18eaafff3SAndrew Boyer /* SPDX-License-Identifier: BSD-3-Clause
28eaafff3SAndrew Boyer * Copyright 2018-2022 Advanced Micro Devices, Inc.
38eaafff3SAndrew Boyer */
48eaafff3SAndrew Boyer
58eaafff3SAndrew Boyer #include <stdio.h>
68eaafff3SAndrew Boyer #include <errno.h>
78eaafff3SAndrew Boyer #include <string.h>
88eaafff3SAndrew Boyer #include <stdint.h>
98eaafff3SAndrew Boyer
108eaafff3SAndrew Boyer #include <rte_common.h>
118eaafff3SAndrew Boyer #include <rte_interrupts.h>
128eaafff3SAndrew Boyer #include <rte_log.h>
138eaafff3SAndrew Boyer #include <rte_pci.h>
148eaafff3SAndrew Boyer #include <bus_pci_driver.h>
158eaafff3SAndrew Boyer #include <rte_eal.h>
168eaafff3SAndrew Boyer #include <ethdev_pci.h>
178eaafff3SAndrew Boyer #include <rte_dev.h>
189de21005SAndrew Boyer #include <rte_kvargs.h>
198eaafff3SAndrew Boyer
208eaafff3SAndrew Boyer #include "ionic.h"
218eaafff3SAndrew Boyer #include "ionic_if.h"
228eaafff3SAndrew Boyer #include "ionic_dev.h"
238eaafff3SAndrew Boyer #include "ionic_ethdev.h"
248eaafff3SAndrew Boyer #include "ionic_logs.h"
258eaafff3SAndrew Boyer
268eaafff3SAndrew Boyer static const struct rte_pci_id pci_id_ionic_map[] = {
278eaafff3SAndrew Boyer { RTE_PCI_DEVICE(IONIC_PENSANDO_VENDOR_ID, IONIC_DEV_ID_ETH_PF) },
288eaafff3SAndrew Boyer { RTE_PCI_DEVICE(IONIC_PENSANDO_VENDOR_ID, IONIC_DEV_ID_ETH_VF) },
298eaafff3SAndrew Boyer { RTE_PCI_DEVICE(IONIC_PENSANDO_VENDOR_ID, IONIC_DEV_ID_ETH_MGMT) },
308eaafff3SAndrew Boyer { .vendor_id = 0, /* sentinel */ },
318eaafff3SAndrew Boyer };
328eaafff3SAndrew Boyer
338eaafff3SAndrew Boyer static int
ionic_pci_setup(struct ionic_adapter * adapter)348eaafff3SAndrew Boyer ionic_pci_setup(struct ionic_adapter *adapter)
358eaafff3SAndrew Boyer {
368eaafff3SAndrew Boyer struct ionic_dev_bar *bar = adapter->bars.bar;
378eaafff3SAndrew Boyer unsigned int num_bars = adapter->bars.num_bars;
388eaafff3SAndrew Boyer struct ionic_dev *idev = &adapter->idev;
398eaafff3SAndrew Boyer struct rte_pci_device *bus_dev = adapter->bus_dev;
408eaafff3SAndrew Boyer uint32_t sig;
419d6f108cSAndrew Boyer uint8_t *bar0_base;
428eaafff3SAndrew Boyer unsigned int i;
438eaafff3SAndrew Boyer
448eaafff3SAndrew Boyer /* BAR0: dev_cmd and interrupts */
458eaafff3SAndrew Boyer if (num_bars < 1) {
46*d026a6b0SAndrew Boyer IONIC_PRINT(ERR, "No bars found, aborting");
478eaafff3SAndrew Boyer return -EFAULT;
488eaafff3SAndrew Boyer }
498eaafff3SAndrew Boyer
508eaafff3SAndrew Boyer if (bar->len < IONIC_BAR0_SIZE) {
51*d026a6b0SAndrew Boyer IONIC_PRINT(ERR, "Resource bar size %lu too small, aborting",
528eaafff3SAndrew Boyer bar->len);
538eaafff3SAndrew Boyer return -EFAULT;
548eaafff3SAndrew Boyer }
558eaafff3SAndrew Boyer
568eaafff3SAndrew Boyer bar0_base = bar->vaddr;
578eaafff3SAndrew Boyer idev->dev_info = (union ionic_dev_info_regs *)
588eaafff3SAndrew Boyer &bar0_base[IONIC_BAR0_DEV_INFO_REGS_OFFSET];
598eaafff3SAndrew Boyer idev->dev_cmd = (union ionic_dev_cmd_regs *)
608eaafff3SAndrew Boyer &bar0_base[IONIC_BAR0_DEV_CMD_REGS_OFFSET];
618eaafff3SAndrew Boyer idev->intr_status = (struct ionic_intr_status *)
628eaafff3SAndrew Boyer &bar0_base[IONIC_BAR0_INTR_STATUS_OFFSET];
638eaafff3SAndrew Boyer idev->intr_ctrl = (struct ionic_intr *)
648eaafff3SAndrew Boyer &bar0_base[IONIC_BAR0_INTR_CTRL_OFFSET];
658eaafff3SAndrew Boyer
668eaafff3SAndrew Boyer sig = ioread32(&idev->dev_info->signature);
678eaafff3SAndrew Boyer if (sig != IONIC_DEV_INFO_SIGNATURE) {
688eaafff3SAndrew Boyer IONIC_PRINT(ERR, "Incompatible firmware signature %#x",
698eaafff3SAndrew Boyer sig);
708eaafff3SAndrew Boyer return -EFAULT;
718eaafff3SAndrew Boyer }
728eaafff3SAndrew Boyer
738eaafff3SAndrew Boyer for (i = 0; i < IONIC_DEVINFO_FWVERS_BUFLEN; i++)
748eaafff3SAndrew Boyer adapter->fw_version[i] =
758eaafff3SAndrew Boyer ioread8(&idev->dev_info->fw_version[i]);
768eaafff3SAndrew Boyer adapter->fw_version[IONIC_DEVINFO_FWVERS_BUFLEN - 1] = '\0';
778eaafff3SAndrew Boyer
788eaafff3SAndrew Boyer adapter->name = bus_dev->device.name;
798eaafff3SAndrew Boyer
808eaafff3SAndrew Boyer IONIC_PRINT(DEBUG, "%s firmware version: %s",
818eaafff3SAndrew Boyer adapter->name, adapter->fw_version);
828eaafff3SAndrew Boyer
838eaafff3SAndrew Boyer /* BAR1: doorbells */
848eaafff3SAndrew Boyer bar++;
85484027bfSAndrew Boyer if (num_bars < IONIC_BARS_MIN) {
86*d026a6b0SAndrew Boyer IONIC_PRINT(ERR, "Doorbell bar missing, aborting");
878eaafff3SAndrew Boyer return -EFAULT;
888eaafff3SAndrew Boyer }
898eaafff3SAndrew Boyer
908eaafff3SAndrew Boyer idev->db_pages = bar->vaddr;
918eaafff3SAndrew Boyer
928eaafff3SAndrew Boyer return 0;
938eaafff3SAndrew Boyer }
948eaafff3SAndrew Boyer
959de21005SAndrew Boyer const char *ionic_pci_devargs_arr[] = {
969de21005SAndrew Boyer PMD_IONIC_CMB_KVARG,
979de21005SAndrew Boyer NULL,
989de21005SAndrew Boyer };
999de21005SAndrew Boyer
1009de21005SAndrew Boyer static int
ionic_pci_devarg_cmb(const char * key __rte_unused,const char * val,void * arg)1019de21005SAndrew Boyer ionic_pci_devarg_cmb(const char *key __rte_unused, const char *val, void *arg)
1029de21005SAndrew Boyer {
1039de21005SAndrew Boyer struct ionic_adapter *adapter = arg;
1049de21005SAndrew Boyer
1059de21005SAndrew Boyer if (!strcmp(val, "1")) {
1069de21005SAndrew Boyer IONIC_PRINT(NOTICE, "%s enabled", PMD_IONIC_CMB_KVARG);
1079de21005SAndrew Boyer adapter->q_in_cmb = true;
1089de21005SAndrew Boyer } else if (!strcmp(val, "0")) {
1099de21005SAndrew Boyer IONIC_PRINT(DEBUG, "%s disabled (default)",
1109de21005SAndrew Boyer PMD_IONIC_CMB_KVARG);
1119de21005SAndrew Boyer } else {
1129de21005SAndrew Boyer IONIC_PRINT(ERR, "%s=%s invalid, use 1 or 0",
1139de21005SAndrew Boyer PMD_IONIC_CMB_KVARG, val);
1149de21005SAndrew Boyer return -ERANGE;
1159de21005SAndrew Boyer }
1169de21005SAndrew Boyer
1179de21005SAndrew Boyer return 0;
1189de21005SAndrew Boyer }
1199de21005SAndrew Boyer
1209de21005SAndrew Boyer static int
ionic_pci_devargs(struct ionic_adapter * adapter,struct rte_devargs * devargs)1219de21005SAndrew Boyer ionic_pci_devargs(struct ionic_adapter *adapter, struct rte_devargs *devargs)
1229de21005SAndrew Boyer {
1239de21005SAndrew Boyer struct rte_kvargs *kvlist;
1249de21005SAndrew Boyer int err = 0;
1259de21005SAndrew Boyer
1269de21005SAndrew Boyer if (!devargs)
1279de21005SAndrew Boyer return 0;
1289de21005SAndrew Boyer
1299de21005SAndrew Boyer kvlist = rte_kvargs_parse(devargs->args, ionic_pci_devargs_arr);
1309de21005SAndrew Boyer if (!kvlist) {
1319de21005SAndrew Boyer IONIC_PRINT(ERR, "Couldn't parse args '%s'", devargs->args);
1329de21005SAndrew Boyer return -EINVAL;
1339de21005SAndrew Boyer }
1349de21005SAndrew Boyer
1359de21005SAndrew Boyer if (rte_kvargs_count(kvlist, PMD_IONIC_CMB_KVARG) == 1) {
1369de21005SAndrew Boyer err = rte_kvargs_process(kvlist, PMD_IONIC_CMB_KVARG,
1379de21005SAndrew Boyer ionic_pci_devarg_cmb, adapter);
1389de21005SAndrew Boyer if (err < 0)
1399de21005SAndrew Boyer goto free_kvlist;
1409de21005SAndrew Boyer }
1419de21005SAndrew Boyer
1429de21005SAndrew Boyer free_kvlist:
1439de21005SAndrew Boyer rte_kvargs_free(kvlist);
1449de21005SAndrew Boyer return err;
1459de21005SAndrew Boyer }
1469de21005SAndrew Boyer
1478eaafff3SAndrew Boyer static void
ionic_pci_copy_bus_info(struct ionic_adapter * adapter,struct rte_eth_dev * eth_dev)1488eaafff3SAndrew Boyer ionic_pci_copy_bus_info(struct ionic_adapter *adapter,
1498eaafff3SAndrew Boyer struct rte_eth_dev *eth_dev)
1508eaafff3SAndrew Boyer {
1518eaafff3SAndrew Boyer rte_eth_copy_pci_info(eth_dev, adapter->bus_dev);
1528eaafff3SAndrew Boyer }
1538eaafff3SAndrew Boyer
1548eaafff3SAndrew Boyer static int
ionic_pci_configure_intr(struct ionic_adapter * adapter)1558eaafff3SAndrew Boyer ionic_pci_configure_intr(struct ionic_adapter *adapter)
1568eaafff3SAndrew Boyer {
1578eaafff3SAndrew Boyer struct rte_pci_device *pci_dev =
1588eaafff3SAndrew Boyer (struct rte_pci_device *)(adapter->bus_dev);
1598eaafff3SAndrew Boyer struct rte_intr_handle *intr_handle = pci_dev->intr_handle;
1608eaafff3SAndrew Boyer int err;
1618eaafff3SAndrew Boyer
1628eaafff3SAndrew Boyer IONIC_PRINT(ERR, "Configuring %u intrs", adapter->nintrs);
1638eaafff3SAndrew Boyer
1648eaafff3SAndrew Boyer if (rte_intr_efd_enable(intr_handle, adapter->nintrs)) {
1658eaafff3SAndrew Boyer IONIC_PRINT(ERR, "Fail to create eventfd");
1668eaafff3SAndrew Boyer return -1;
1678eaafff3SAndrew Boyer }
1688eaafff3SAndrew Boyer
1698eaafff3SAndrew Boyer if (rte_intr_dp_is_en(intr_handle)) {
1708eaafff3SAndrew Boyer IONIC_PRINT(NOTICE,
1718eaafff3SAndrew Boyer "Packet I/O interrupt on datapath is enabled");
1728eaafff3SAndrew Boyer if (rte_intr_vec_list_alloc(intr_handle, "intr_vec",
1738eaafff3SAndrew Boyer adapter->nintrs)) {
1748eaafff3SAndrew Boyer IONIC_PRINT(ERR, "Failed to allocate %u vectors",
1758eaafff3SAndrew Boyer adapter->nintrs);
1768eaafff3SAndrew Boyer return -ENOMEM;
1778eaafff3SAndrew Boyer }
1788eaafff3SAndrew Boyer }
1798eaafff3SAndrew Boyer
1808eaafff3SAndrew Boyer err = rte_intr_callback_register(intr_handle,
1818eaafff3SAndrew Boyer ionic_dev_interrupt_handler,
1828eaafff3SAndrew Boyer adapter);
1838eaafff3SAndrew Boyer if (err) {
1848eaafff3SAndrew Boyer IONIC_PRINT(ERR,
1858eaafff3SAndrew Boyer "Failure registering interrupts handler (%d)", err);
1868eaafff3SAndrew Boyer return err;
1878eaafff3SAndrew Boyer }
1888eaafff3SAndrew Boyer
1898eaafff3SAndrew Boyer /* enable intr mapping */
1908eaafff3SAndrew Boyer err = rte_intr_enable(intr_handle);
1918eaafff3SAndrew Boyer if (err) {
1928eaafff3SAndrew Boyer IONIC_PRINT(ERR, "Failure enabling interrupts (%d)", err);
1938eaafff3SAndrew Boyer return err;
1948eaafff3SAndrew Boyer }
1958eaafff3SAndrew Boyer
1968eaafff3SAndrew Boyer return 0;
1978eaafff3SAndrew Boyer }
1988eaafff3SAndrew Boyer
1998eaafff3SAndrew Boyer static void
ionic_pci_unconfigure_intr(struct ionic_adapter * adapter)2008eaafff3SAndrew Boyer ionic_pci_unconfigure_intr(struct ionic_adapter *adapter)
2018eaafff3SAndrew Boyer {
2028eaafff3SAndrew Boyer struct rte_pci_device *pci_dev =
2038eaafff3SAndrew Boyer (struct rte_pci_device *)(adapter->bus_dev);
2048eaafff3SAndrew Boyer struct rte_intr_handle *intr_handle = pci_dev->intr_handle;
2058eaafff3SAndrew Boyer
2068eaafff3SAndrew Boyer rte_intr_disable(intr_handle);
2078eaafff3SAndrew Boyer
2088eaafff3SAndrew Boyer rte_intr_callback_unregister(intr_handle,
2098eaafff3SAndrew Boyer ionic_dev_interrupt_handler,
2108eaafff3SAndrew Boyer adapter);
2118eaafff3SAndrew Boyer }
2128eaafff3SAndrew Boyer
2138eaafff3SAndrew Boyer static const struct ionic_dev_intf ionic_pci_intf = {
2148eaafff3SAndrew Boyer .setup = ionic_pci_setup,
2159de21005SAndrew Boyer .devargs = ionic_pci_devargs,
2168eaafff3SAndrew Boyer .copy_bus_info = ionic_pci_copy_bus_info,
2178eaafff3SAndrew Boyer .configure_intr = ionic_pci_configure_intr,
2188eaafff3SAndrew Boyer .unconfigure_intr = ionic_pci_unconfigure_intr,
2198eaafff3SAndrew Boyer };
2208eaafff3SAndrew Boyer
2218eaafff3SAndrew Boyer static int
eth_ionic_pci_probe(struct rte_pci_driver * pci_drv __rte_unused,struct rte_pci_device * pci_dev)2228eaafff3SAndrew Boyer eth_ionic_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
2238eaafff3SAndrew Boyer struct rte_pci_device *pci_dev)
2248eaafff3SAndrew Boyer {
2258eaafff3SAndrew Boyer struct rte_mem_resource *resource;
2268eaafff3SAndrew Boyer struct ionic_bars bars;
2278eaafff3SAndrew Boyer unsigned long i;
2288eaafff3SAndrew Boyer
2298eaafff3SAndrew Boyer IONIC_PRINT(NOTICE, "Initializing device %s %s",
2308eaafff3SAndrew Boyer pci_dev->device.name,
2318eaafff3SAndrew Boyer rte_eal_process_type() == RTE_PROC_SECONDARY ?
2328eaafff3SAndrew Boyer "[SECONDARY]" : "");
2338eaafff3SAndrew Boyer
2348eaafff3SAndrew Boyer bars.num_bars = 0;
2358eaafff3SAndrew Boyer for (i = 0; i < PCI_MAX_RESOURCE && i < IONIC_BARS_MAX; i++) {
2368eaafff3SAndrew Boyer resource = &pci_dev->mem_resource[i];
2378eaafff3SAndrew Boyer if (resource->phys_addr == 0 || resource->len == 0)
2388eaafff3SAndrew Boyer continue;
2398eaafff3SAndrew Boyer
2408eaafff3SAndrew Boyer bars.bar[bars.num_bars].vaddr = resource->addr;
2418eaafff3SAndrew Boyer bars.bar[bars.num_bars].bus_addr = resource->phys_addr;
2428eaafff3SAndrew Boyer bars.bar[bars.num_bars].len = resource->len;
2438eaafff3SAndrew Boyer bars.num_bars++;
2448eaafff3SAndrew Boyer }
2458eaafff3SAndrew Boyer
2468eaafff3SAndrew Boyer return eth_ionic_dev_probe((void *)pci_dev,
2478eaafff3SAndrew Boyer &pci_dev->device,
2488eaafff3SAndrew Boyer &bars,
2498eaafff3SAndrew Boyer &ionic_pci_intf,
2508eaafff3SAndrew Boyer pci_dev->id.device_id,
2518eaafff3SAndrew Boyer pci_dev->id.vendor_id);
2528eaafff3SAndrew Boyer }
2538eaafff3SAndrew Boyer
2548eaafff3SAndrew Boyer static int
eth_ionic_pci_remove(struct rte_pci_device * pci_dev)2558eaafff3SAndrew Boyer eth_ionic_pci_remove(struct rte_pci_device *pci_dev)
2568eaafff3SAndrew Boyer {
2578eaafff3SAndrew Boyer return eth_ionic_dev_remove(&pci_dev->device);
2588eaafff3SAndrew Boyer }
2598eaafff3SAndrew Boyer
2608eaafff3SAndrew Boyer static struct rte_pci_driver rte_pci_ionic_pmd = {
2618eaafff3SAndrew Boyer .id_table = pci_id_ionic_map,
2629de21005SAndrew Boyer .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC |
2639de21005SAndrew Boyer RTE_PCI_DRV_WC_ACTIVATE,
2648eaafff3SAndrew Boyer .probe = eth_ionic_pci_probe,
2658eaafff3SAndrew Boyer .remove = eth_ionic_pci_remove,
2668eaafff3SAndrew Boyer };
2678eaafff3SAndrew Boyer
2688eaafff3SAndrew Boyer RTE_PMD_REGISTER_PCI(net_ionic_pci, rte_pci_ionic_pmd);
2698eaafff3SAndrew Boyer RTE_PMD_REGISTER_PCI_TABLE(net_ionic_pci, pci_id_ionic_map);
2708eaafff3SAndrew Boyer RTE_PMD_REGISTER_KMOD_DEP(net_ionic_pci, "* igb_uio | uio_pci_generic | vfio-pci");
2719de21005SAndrew Boyer RTE_PMD_REGISTER_PARAM_STRING(net_ionic_pci,
2729de21005SAndrew Boyer PMD_IONIC_CMB_KVARG "=<0|1>"
2739de21005SAndrew Boyer );
274