linux/drivers/net/ethernet/intel/ixd/ixd_main.c
Amritha Nambiar f290d48f02 ixd: add devlink support
Enable initial support for the devlink interface with the ixd driver. The
ixd hardware is a single function PCIe device. So, the PCIe adapter gets
its own devlink instance to manage device-wide resources or configuration.

$ devlink dev show
pci/0000:83:00.6

$ devlink dev info pci/0000:83:00.6
pci/0000:83:00.6:
  driver ixd
  serial_number 00-a0-c9-ff-ff-23-45-67
  versions:
      fixed:
        device.type MEV
      running:
        fw.mgmt.api 2.0

Signed-off-by: Amritha Nambiar <amritha.nambiar@intel.com>
Reviewed-by: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>
Reviewed-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
Tested-by: Bharath R <Bharath.r@intel.com>
Signed-off-by: Larysa Zaremba <larysa.zaremba@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
2026-08-12 13:56:51 -07:00

145 lines
3.2 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (C) 2025 Intel Corporation */
#include "ixd.h"
#include "ixd_ctlq.h"
#include "ixd_lan_regs.h"
#include "ixd_devlink.h"
MODULE_DESCRIPTION("Intel(R) Control Plane Function Device Driver");
MODULE_IMPORT_NS("LIBIE_CP");
MODULE_IMPORT_NS("LIBIE_PCI");
MODULE_LICENSE("GPL");
/**
* ixd_remove - remove a CPF PCI device
* @pdev: PCI device being removed
*/
static void ixd_remove(struct pci_dev *pdev)
{
struct ixd_adapter *adapter = pci_get_drvdata(pdev);
/* Do not mix removal with (re)initialization */
cancel_delayed_work_sync(&adapter->init_task.init_work);
ixd_devlink_unregister(adapter);
/* Leave the device clean on exit */
if (adapter->xnm)
libie_ctlq_xn_shutdown(adapter->xnm);
ixd_trigger_reset(adapter);
ixd_deinit_dflt_mbx(adapter);
libie_pci_unmap_all_mmio_regions(&adapter->cp_ctx.mmio_info);
ixd_devlink_free(adapter);
}
/**
* ixd_shutdown - shut down a CPF PCI device
* @pdev: PCI device being shut down
*/
static void ixd_shutdown(struct pci_dev *pdev)
{
ixd_remove(pdev);
if (system_state == SYSTEM_POWER_OFF)
pci_set_power_state(pdev, PCI_D3hot);
}
/**
* ixd_iomap_regions - iomap PCI BARs
* @adapter: adapter to map memory regions for
*
* Returns: %0 on success, negative on failure
*/
static int ixd_iomap_regions(struct ixd_adapter *adapter)
{
const struct ixd_bar_region regions[] = {
{
.offset = PFGEN_RTRIG,
.size = PFGEN_RTRIG_REG_LEN,
},
{
.offset = PF_FW_MBX,
.size = PF_FW_MBX_REG_LEN,
},
};
for (int i = 0; i < ARRAY_SIZE(regions); i++) {
struct libie_mmio_info *mmio_info = &adapter->cp_ctx.mmio_info;
bool map_ok;
map_ok = libie_pci_map_mmio_region(mmio_info,
regions[i].offset,
regions[i].size);
if (!map_ok) {
dev_err(ixd_to_dev(adapter),
"Failed to map PCI device MMIO region\n");
libie_pci_unmap_all_mmio_regions(mmio_info);
return -EIO;
}
}
return 0;
}
/**
* ixd_probe - probe a CPF PCI device
* @pdev: corresponding PCI device
* @ent: entry in ixd_pci_tbl
*
* Returns: %0 on success, negative errno code on failure
*/
static int ixd_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct ixd_adapter *adapter;
int err;
adapter = ixd_adapter_alloc(&pdev->dev);
if (!adapter)
return -ENOMEM;
adapter->cp_ctx.mmio_info.pdev = pdev;
INIT_LIST_HEAD(&adapter->cp_ctx.mmio_info.mmio_list);
err = libie_pci_init_dev(pdev);
if (err)
goto free_adapter;
pci_set_drvdata(pdev, adapter);
err = ixd_iomap_regions(adapter);
if (err)
goto free_adapter;
INIT_DELAYED_WORK(&adapter->init_task.init_work,
ixd_init_task);
INIT_DELAYED_WORK(&adapter->mbx_task, ixd_ctlq_rx_task);
ixd_trigger_reset(adapter);
queue_delayed_work(system_dfl_wq, &adapter->init_task.init_work,
IXD_INIT_TASK_DELAY_JIFFIES);
return 0;
free_adapter:
ixd_devlink_free(adapter);
return err;
}
static const struct pci_device_id ixd_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, IXD_DEV_ID_CPF) },
{ }
};
MODULE_DEVICE_TABLE(pci, ixd_pci_tbl);
static struct pci_driver ixd_driver = {
.name = KBUILD_MODNAME,
.id_table = ixd_pci_tbl,
.probe = ixd_probe,
.remove = ixd_remove,
.shutdown = ixd_shutdown,
};
module_pci_driver(ixd_driver);