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> 18*9de21005SAndrew 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 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; 418eaafff3SAndrew Boyer u_char *bar0_base; 428eaafff3SAndrew Boyer unsigned int i; 438eaafff3SAndrew Boyer 448eaafff3SAndrew Boyer /* BAR0: dev_cmd and interrupts */ 458eaafff3SAndrew Boyer if (num_bars < 1) { 468eaafff3SAndrew Boyer IONIC_PRINT(ERR, "No bars found, aborting\n"); 478eaafff3SAndrew Boyer return -EFAULT; 488eaafff3SAndrew Boyer } 498eaafff3SAndrew Boyer 508eaafff3SAndrew Boyer if (bar->len < IONIC_BAR0_SIZE) { 518eaafff3SAndrew Boyer IONIC_PRINT(ERR, 528eaafff3SAndrew Boyer "Resource bar size %lu too small, aborting\n", 538eaafff3SAndrew Boyer bar->len); 548eaafff3SAndrew Boyer return -EFAULT; 558eaafff3SAndrew Boyer } 568eaafff3SAndrew Boyer 578eaafff3SAndrew Boyer bar0_base = bar->vaddr; 588eaafff3SAndrew Boyer idev->dev_info = (union ionic_dev_info_regs *) 598eaafff3SAndrew Boyer &bar0_base[IONIC_BAR0_DEV_INFO_REGS_OFFSET]; 608eaafff3SAndrew Boyer idev->dev_cmd = (union ionic_dev_cmd_regs *) 618eaafff3SAndrew Boyer &bar0_base[IONIC_BAR0_DEV_CMD_REGS_OFFSET]; 628eaafff3SAndrew Boyer idev->intr_status = (struct ionic_intr_status *) 638eaafff3SAndrew Boyer &bar0_base[IONIC_BAR0_INTR_STATUS_OFFSET]; 648eaafff3SAndrew Boyer idev->intr_ctrl = (struct ionic_intr *) 658eaafff3SAndrew Boyer &bar0_base[IONIC_BAR0_INTR_CTRL_OFFSET]; 668eaafff3SAndrew Boyer 678eaafff3SAndrew Boyer sig = ioread32(&idev->dev_info->signature); 688eaafff3SAndrew Boyer if (sig != IONIC_DEV_INFO_SIGNATURE) { 698eaafff3SAndrew Boyer IONIC_PRINT(ERR, "Incompatible firmware signature %#x", 708eaafff3SAndrew Boyer sig); 718eaafff3SAndrew Boyer return -EFAULT; 728eaafff3SAndrew Boyer } 738eaafff3SAndrew Boyer 748eaafff3SAndrew Boyer for (i = 0; i < IONIC_DEVINFO_FWVERS_BUFLEN; i++) 758eaafff3SAndrew Boyer adapter->fw_version[i] = 768eaafff3SAndrew Boyer ioread8(&idev->dev_info->fw_version[i]); 778eaafff3SAndrew Boyer adapter->fw_version[IONIC_DEVINFO_FWVERS_BUFLEN - 1] = '\0'; 788eaafff3SAndrew Boyer 798eaafff3SAndrew Boyer adapter->name = bus_dev->device.name; 808eaafff3SAndrew Boyer 818eaafff3SAndrew Boyer IONIC_PRINT(DEBUG, "%s firmware version: %s", 828eaafff3SAndrew Boyer adapter->name, adapter->fw_version); 838eaafff3SAndrew Boyer 848eaafff3SAndrew Boyer /* BAR1: doorbells */ 858eaafff3SAndrew Boyer bar++; 868eaafff3SAndrew Boyer if (num_bars < 2) { 878eaafff3SAndrew Boyer IONIC_PRINT(ERR, "Doorbell bar missing, aborting\n"); 888eaafff3SAndrew Boyer return -EFAULT; 898eaafff3SAndrew Boyer } 908eaafff3SAndrew Boyer 918eaafff3SAndrew Boyer idev->db_pages = bar->vaddr; 928eaafff3SAndrew Boyer 938eaafff3SAndrew Boyer return 0; 948eaafff3SAndrew Boyer } 958eaafff3SAndrew Boyer 96*9de21005SAndrew Boyer const char *ionic_pci_devargs_arr[] = { 97*9de21005SAndrew Boyer PMD_IONIC_CMB_KVARG, 98*9de21005SAndrew Boyer NULL, 99*9de21005SAndrew Boyer }; 100*9de21005SAndrew Boyer 101*9de21005SAndrew Boyer static int 102*9de21005SAndrew Boyer ionic_pci_devarg_cmb(const char *key __rte_unused, const char *val, void *arg) 103*9de21005SAndrew Boyer { 104*9de21005SAndrew Boyer struct ionic_adapter *adapter = arg; 105*9de21005SAndrew Boyer 106*9de21005SAndrew Boyer if (!strcmp(val, "1")) { 107*9de21005SAndrew Boyer IONIC_PRINT(NOTICE, "%s enabled", PMD_IONIC_CMB_KVARG); 108*9de21005SAndrew Boyer adapter->q_in_cmb = true; 109*9de21005SAndrew Boyer } else if (!strcmp(val, "0")) { 110*9de21005SAndrew Boyer IONIC_PRINT(DEBUG, "%s disabled (default)", 111*9de21005SAndrew Boyer PMD_IONIC_CMB_KVARG); 112*9de21005SAndrew Boyer } else { 113*9de21005SAndrew Boyer IONIC_PRINT(ERR, "%s=%s invalid, use 1 or 0", 114*9de21005SAndrew Boyer PMD_IONIC_CMB_KVARG, val); 115*9de21005SAndrew Boyer return -ERANGE; 116*9de21005SAndrew Boyer } 117*9de21005SAndrew Boyer 118*9de21005SAndrew Boyer return 0; 119*9de21005SAndrew Boyer } 120*9de21005SAndrew Boyer 121*9de21005SAndrew Boyer static int 122*9de21005SAndrew Boyer ionic_pci_devargs(struct ionic_adapter *adapter, struct rte_devargs *devargs) 123*9de21005SAndrew Boyer { 124*9de21005SAndrew Boyer struct rte_kvargs *kvlist; 125*9de21005SAndrew Boyer int err = 0; 126*9de21005SAndrew Boyer 127*9de21005SAndrew Boyer if (!devargs) 128*9de21005SAndrew Boyer return 0; 129*9de21005SAndrew Boyer 130*9de21005SAndrew Boyer kvlist = rte_kvargs_parse(devargs->args, ionic_pci_devargs_arr); 131*9de21005SAndrew Boyer if (!kvlist) { 132*9de21005SAndrew Boyer IONIC_PRINT(ERR, "Couldn't parse args '%s'", devargs->args); 133*9de21005SAndrew Boyer return -EINVAL; 134*9de21005SAndrew Boyer } 135*9de21005SAndrew Boyer 136*9de21005SAndrew Boyer if (rte_kvargs_count(kvlist, PMD_IONIC_CMB_KVARG) == 1) { 137*9de21005SAndrew Boyer err = rte_kvargs_process(kvlist, PMD_IONIC_CMB_KVARG, 138*9de21005SAndrew Boyer ionic_pci_devarg_cmb, adapter); 139*9de21005SAndrew Boyer if (err < 0) 140*9de21005SAndrew Boyer goto free_kvlist; 141*9de21005SAndrew Boyer } 142*9de21005SAndrew Boyer 143*9de21005SAndrew Boyer free_kvlist: 144*9de21005SAndrew Boyer rte_kvargs_free(kvlist); 145*9de21005SAndrew Boyer return err; 146*9de21005SAndrew Boyer } 147*9de21005SAndrew Boyer 1488eaafff3SAndrew Boyer static void 1498eaafff3SAndrew Boyer ionic_pci_copy_bus_info(struct ionic_adapter *adapter, 1508eaafff3SAndrew Boyer struct rte_eth_dev *eth_dev) 1518eaafff3SAndrew Boyer { 1528eaafff3SAndrew Boyer rte_eth_copy_pci_info(eth_dev, adapter->bus_dev); 1538eaafff3SAndrew Boyer } 1548eaafff3SAndrew Boyer 1558eaafff3SAndrew Boyer static int 1568eaafff3SAndrew Boyer ionic_pci_configure_intr(struct ionic_adapter *adapter) 1578eaafff3SAndrew Boyer { 1588eaafff3SAndrew Boyer struct rte_pci_device *pci_dev = 1598eaafff3SAndrew Boyer (struct rte_pci_device *)(adapter->bus_dev); 1608eaafff3SAndrew Boyer struct rte_intr_handle *intr_handle = pci_dev->intr_handle; 1618eaafff3SAndrew Boyer int err; 1628eaafff3SAndrew Boyer 1638eaafff3SAndrew Boyer IONIC_PRINT(ERR, "Configuring %u intrs", adapter->nintrs); 1648eaafff3SAndrew Boyer 1658eaafff3SAndrew Boyer if (rte_intr_efd_enable(intr_handle, adapter->nintrs)) { 1668eaafff3SAndrew Boyer IONIC_PRINT(ERR, "Fail to create eventfd"); 1678eaafff3SAndrew Boyer return -1; 1688eaafff3SAndrew Boyer } 1698eaafff3SAndrew Boyer 1708eaafff3SAndrew Boyer if (rte_intr_dp_is_en(intr_handle)) { 1718eaafff3SAndrew Boyer IONIC_PRINT(NOTICE, 1728eaafff3SAndrew Boyer "Packet I/O interrupt on datapath is enabled"); 1738eaafff3SAndrew Boyer if (rte_intr_vec_list_alloc(intr_handle, "intr_vec", 1748eaafff3SAndrew Boyer adapter->nintrs)) { 1758eaafff3SAndrew Boyer IONIC_PRINT(ERR, "Failed to allocate %u vectors", 1768eaafff3SAndrew Boyer adapter->nintrs); 1778eaafff3SAndrew Boyer return -ENOMEM; 1788eaafff3SAndrew Boyer } 1798eaafff3SAndrew Boyer } 1808eaafff3SAndrew Boyer 1818eaafff3SAndrew Boyer err = rte_intr_callback_register(intr_handle, 1828eaafff3SAndrew Boyer ionic_dev_interrupt_handler, 1838eaafff3SAndrew Boyer adapter); 1848eaafff3SAndrew Boyer if (err) { 1858eaafff3SAndrew Boyer IONIC_PRINT(ERR, 1868eaafff3SAndrew Boyer "Failure registering interrupts handler (%d)", err); 1878eaafff3SAndrew Boyer return err; 1888eaafff3SAndrew Boyer } 1898eaafff3SAndrew Boyer 1908eaafff3SAndrew Boyer /* enable intr mapping */ 1918eaafff3SAndrew Boyer err = rte_intr_enable(intr_handle); 1928eaafff3SAndrew Boyer if (err) { 1938eaafff3SAndrew Boyer IONIC_PRINT(ERR, "Failure enabling interrupts (%d)", err); 1948eaafff3SAndrew Boyer return err; 1958eaafff3SAndrew Boyer } 1968eaafff3SAndrew Boyer 1978eaafff3SAndrew Boyer return 0; 1988eaafff3SAndrew Boyer } 1998eaafff3SAndrew Boyer 2008eaafff3SAndrew Boyer static void 2018eaafff3SAndrew Boyer ionic_pci_unconfigure_intr(struct ionic_adapter *adapter) 2028eaafff3SAndrew Boyer { 2038eaafff3SAndrew Boyer struct rte_pci_device *pci_dev = 2048eaafff3SAndrew Boyer (struct rte_pci_device *)(adapter->bus_dev); 2058eaafff3SAndrew Boyer struct rte_intr_handle *intr_handle = pci_dev->intr_handle; 2068eaafff3SAndrew Boyer 2078eaafff3SAndrew Boyer rte_intr_disable(intr_handle); 2088eaafff3SAndrew Boyer 2098eaafff3SAndrew Boyer rte_intr_callback_unregister(intr_handle, 2108eaafff3SAndrew Boyer ionic_dev_interrupt_handler, 2118eaafff3SAndrew Boyer adapter); 2128eaafff3SAndrew Boyer } 2138eaafff3SAndrew Boyer 2148eaafff3SAndrew Boyer static const struct ionic_dev_intf ionic_pci_intf = { 2158eaafff3SAndrew Boyer .setup = ionic_pci_setup, 216*9de21005SAndrew Boyer .devargs = ionic_pci_devargs, 2178eaafff3SAndrew Boyer .copy_bus_info = ionic_pci_copy_bus_info, 2188eaafff3SAndrew Boyer .configure_intr = ionic_pci_configure_intr, 2198eaafff3SAndrew Boyer .unconfigure_intr = ionic_pci_unconfigure_intr, 2208eaafff3SAndrew Boyer }; 2218eaafff3SAndrew Boyer 2228eaafff3SAndrew Boyer static int 2238eaafff3SAndrew Boyer eth_ionic_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, 2248eaafff3SAndrew Boyer struct rte_pci_device *pci_dev) 2258eaafff3SAndrew Boyer { 2268eaafff3SAndrew Boyer struct rte_mem_resource *resource; 2278eaafff3SAndrew Boyer struct ionic_bars bars; 2288eaafff3SAndrew Boyer unsigned long i; 2298eaafff3SAndrew Boyer 2308eaafff3SAndrew Boyer IONIC_PRINT(NOTICE, "Initializing device %s %s", 2318eaafff3SAndrew Boyer pci_dev->device.name, 2328eaafff3SAndrew Boyer rte_eal_process_type() == RTE_PROC_SECONDARY ? 2338eaafff3SAndrew Boyer "[SECONDARY]" : ""); 2348eaafff3SAndrew Boyer 2358eaafff3SAndrew Boyer bars.num_bars = 0; 2368eaafff3SAndrew Boyer for (i = 0; i < PCI_MAX_RESOURCE && i < IONIC_BARS_MAX; i++) { 2378eaafff3SAndrew Boyer resource = &pci_dev->mem_resource[i]; 2388eaafff3SAndrew Boyer if (resource->phys_addr == 0 || resource->len == 0) 2398eaafff3SAndrew Boyer continue; 2408eaafff3SAndrew Boyer 2418eaafff3SAndrew Boyer bars.bar[bars.num_bars].vaddr = resource->addr; 2428eaafff3SAndrew Boyer bars.bar[bars.num_bars].bus_addr = resource->phys_addr; 2438eaafff3SAndrew Boyer bars.bar[bars.num_bars].len = resource->len; 2448eaafff3SAndrew Boyer bars.num_bars++; 2458eaafff3SAndrew Boyer } 2468eaafff3SAndrew Boyer 2478eaafff3SAndrew Boyer return eth_ionic_dev_probe((void *)pci_dev, 2488eaafff3SAndrew Boyer &pci_dev->device, 2498eaafff3SAndrew Boyer &bars, 2508eaafff3SAndrew Boyer &ionic_pci_intf, 2518eaafff3SAndrew Boyer pci_dev->id.device_id, 2528eaafff3SAndrew Boyer pci_dev->id.vendor_id); 2538eaafff3SAndrew Boyer } 2548eaafff3SAndrew Boyer 2558eaafff3SAndrew Boyer static int 2568eaafff3SAndrew Boyer eth_ionic_pci_remove(struct rte_pci_device *pci_dev) 2578eaafff3SAndrew Boyer { 2588eaafff3SAndrew Boyer return eth_ionic_dev_remove(&pci_dev->device); 2598eaafff3SAndrew Boyer } 2608eaafff3SAndrew Boyer 2618eaafff3SAndrew Boyer static struct rte_pci_driver rte_pci_ionic_pmd = { 2628eaafff3SAndrew Boyer .id_table = pci_id_ionic_map, 263*9de21005SAndrew Boyer .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC | 264*9de21005SAndrew Boyer RTE_PCI_DRV_WC_ACTIVATE, 2658eaafff3SAndrew Boyer .probe = eth_ionic_pci_probe, 2668eaafff3SAndrew Boyer .remove = eth_ionic_pci_remove, 2678eaafff3SAndrew Boyer }; 2688eaafff3SAndrew Boyer 2698eaafff3SAndrew Boyer RTE_PMD_REGISTER_PCI(net_ionic_pci, rte_pci_ionic_pmd); 2708eaafff3SAndrew Boyer RTE_PMD_REGISTER_PCI_TABLE(net_ionic_pci, pci_id_ionic_map); 2718eaafff3SAndrew Boyer RTE_PMD_REGISTER_KMOD_DEP(net_ionic_pci, "* igb_uio | uio_pci_generic | vfio-pci"); 272*9de21005SAndrew Boyer RTE_PMD_REGISTER_PARAM_STRING(net_ionic_pci, 273*9de21005SAndrew Boyer PMD_IONIC_CMB_KVARG "=<0|1>" 274*9de21005SAndrew Boyer ); 275