X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fnfp%2Fnfp_net.c;h=5d35ce13487fa0b3dd21ec0d7f70f666050bb801;hb=24c14430cdc4556a30a1e608f67230e881718f7f;hp=5b4108a4b23990e8545b8fa75f07a8f3c067f25b;hpb=a75b4086aaaf06a36b19a185adaf516dde43d47d;p=dpdk.git diff --git a/drivers/net/nfp/nfp_net.c b/drivers/net/nfp/nfp_net.c index 5b4108a4b2..5d35ce1348 100644 --- a/drivers/net/nfp/nfp_net.c +++ b/drivers/net/nfp/nfp_net.c @@ -593,7 +593,55 @@ nfp_net_cfg_queue_setup(struct nfp_net_hw *hw) hw->qcp_cfg = hw->tx_bar + NFP_QCP_QUEUE_ADDR_SZ; } -static void nfp_net_read_mac(struct nfp_net_hw *hw) +#define ETH_ADDR_LEN 6 + +static void +nfp_eth_copy_mac_reverse(uint8_t *dst, const uint8_t *src) +{ + int i; + + for (i = 0; i < ETH_ADDR_LEN; i++) + dst[ETH_ADDR_LEN - i - 1] = src[i]; +} + +static int +nfp_net_pf_read_mac(struct nfp_net_hw *hw, int port) +{ + union eth_table_entry *entry; + int idx, i; + + idx = port; + entry = hw->eth_table; + + /* Reading NFP ethernet table obtained before */ + for (i = 0; i < NSP_ETH_MAX_COUNT; i++) { + if (!(entry->port & NSP_ETH_PORT_LANES_MASK)) { + /* port not in use */ + entry++; + continue; + } + if (idx == 0) + break; + idx--; + entry++; + } + + if (i == NSP_ETH_MAX_COUNT) + return -EINVAL; + + /* + * hw points to port0 private data. We need hw now pointing to + * right port. + */ + hw += port; + nfp_eth_copy_mac_reverse((uint8_t *)&hw->mac_addr, + (uint8_t *)&entry->mac_addr); + + return 0; +} + +static void +nfp_net_vf_read_mac(struct nfp_net_hw *hw) { uint32_t tmp; @@ -687,6 +735,11 @@ nfp_net_start(struct rte_eth_dev *dev) /* check and configure queue intr-vector mapping */ if (dev->data->dev_conf.intr_conf.rxq != 0) { + if (hw->pf_multiport_enabled) { + PMD_INIT_LOG(ERR, "PMD rx interrupt is not supported " + "with NFP multiport PF"); + return -EINVAL; + } if (intr_handle->type == RTE_INTR_HANDLE_UIO) { /* * Better not to share LSC with RX interrupts. @@ -732,6 +785,10 @@ nfp_net_start(struct rte_eth_dev *dev) goto error; } + if (hw->is_pf) + /* Configure the physical port up */ + nfp_nsp_eth_config(hw->nspu_desc, hw->pf_port_idx, 1); + hw->ctrl = new_ctrl; return 0; @@ -760,9 +817,12 @@ static void nfp_net_stop(struct rte_eth_dev *dev) { int i; + struct nfp_net_hw *hw; PMD_INIT_LOG(DEBUG, "Stop"); + hw = NFP_NET_DEV_PRIVATE_TO_HW(dev->data->dev_private); + nfp_net_disable_queues(dev); /* Clear queues */ @@ -775,6 +835,10 @@ nfp_net_stop(struct rte_eth_dev *dev) nfp_net_reset_rx_queue( (struct nfp_net_rxq *)dev->data->rx_queues[i]); } + + if (hw->is_pf) + /* Configure the physical port down */ + nfp_nsp_eth_config(hw->nspu_desc, hw->pf_port_idx, 0); } /* Reset and stop device. The device can not be restarted. */ @@ -783,6 +847,7 @@ nfp_net_close(struct rte_eth_dev *dev) { struct nfp_net_hw *hw; struct rte_pci_device *pci_dev; + int i; PMD_INIT_LOG(DEBUG, "Close"); @@ -794,7 +859,18 @@ nfp_net_close(struct rte_eth_dev *dev) * threads/queues before calling the device close function. */ - nfp_net_stop(dev); + nfp_net_disable_queues(dev); + + /* Clear queues */ + for (i = 0; i < dev->data->nb_tx_queues; i++) { + nfp_net_reset_tx_queue( + (struct nfp_net_txq *)dev->data->tx_queues[i]); + } + + for (i = 0; i < dev->data->nb_rx_queues; i++) { + nfp_net_reset_rx_queue( + (struct nfp_net_rxq *)dev->data->rx_queues[i]); + } rte_intr_disable(&pci_dev->intr_handle); nn_cfg_writeb(hw, NFP_NET_CFG_LSC, 0xff); @@ -2489,11 +2565,43 @@ static const struct eth_dev_ops nfp_net_eth_dev_ops = { .rx_queue_intr_disable = nfp_rx_queue_intr_disable, }; +/* + * All eth_dev created got its private data, but before nfp_net_init, that + * private data is referencing private data for all the PF ports. This is due + * to how the vNIC bars are mapped based on first port, so all ports need info + * about port 0 private data. Inside nfp_net_init the private data pointer is + * changed to the right address for each port once the bars have been mapped. + * + * This functions helps to find out which port and therefore which offset + * inside the private data array to use. + */ +static int +get_pf_port_number(char *name) +{ + char *pf_str = name; + int size = 0; + + while ((*pf_str != '_') && (*pf_str != '\0') && (size++ < 30)) + pf_str++; + + if (size == 30) + /* + * This should not happen at all and it would mean major + * implementation fault. + */ + rte_panic("nfp_net: problem with pf device name\n"); + + /* Expecting _portX with X within [0,7] */ + pf_str += 5; + + return (int)strtol(pf_str, NULL, 10); +} + static int nfp_net_init(struct rte_eth_dev *eth_dev) { struct rte_pci_device *pci_dev; - struct nfp_net_hw *hw; + struct nfp_net_hw *hw, *hwport0; uint64_t tx_bar_off = 0, rx_bar_off = 0; uint32_t start_q; @@ -2501,10 +2609,32 @@ nfp_net_init(struct rte_eth_dev *eth_dev) nspu_desc_t *nspu_desc = NULL; uint64_t bar_offset; + int port = 0; PMD_INIT_FUNC_TRACE(); - hw = NFP_NET_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private); + pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev); + + if ((pci_dev->id.device_id == PCI_DEVICE_ID_NFP4000_PF_NIC) || + (pci_dev->id.device_id == PCI_DEVICE_ID_NFP6000_PF_NIC)) { + port = get_pf_port_number(eth_dev->data->name); + if (port < 0 || port > 7) { + RTE_LOG(ERR, PMD, "Port value is wrong\n"); + return -ENODEV; + } + + PMD_INIT_LOG(DEBUG, "Working with PF port value %d\n", port); + + /* This points to port 0 private data */ + hwport0 = NFP_NET_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private); + + /* This points to the specific port private data */ + hw = &hwport0[port]; + hw->pf_port_idx = port; + } else { + hw = NFP_NET_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private); + hwport0 = 0; + } eth_dev->dev_ops = &nfp_net_eth_dev_ops; eth_dev->rx_pkt_burst = &nfp_net_recv_pkts; @@ -2514,9 +2644,10 @@ nfp_net_init(struct rte_eth_dev *eth_dev) if (rte_eal_process_type() != RTE_PROC_PRIMARY) return 0; - pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev); rte_eth_copy_pci_info(eth_dev, pci_dev); - eth_dev->data->dev_flags |= RTE_ETH_DEV_DETACHABLE; + /* hotplug is not possible with multiport PF */ + if (!hw->pf_multiport_enabled) + eth_dev->data->dev_flags |= RTE_ETH_DEV_DETACHABLE; hw->device_id = pci_dev->id.device_id; hw->vendor_id = pci_dev->id.vendor_id; @@ -2535,9 +2666,7 @@ nfp_net_init(struct rte_eth_dev *eth_dev) return -ENODEV; } - /* Is this a PF device? */ - if ((pci_dev->id.device_id == PCI_DEVICE_ID_NFP4000_PF_NIC) || - (pci_dev->id.device_id == PCI_DEVICE_ID_NFP6000_PF_NIC)) { + if (hw->is_pf && port == 0) { nspu_desc = hw->nspu_desc; if (nfp_nsp_map_ctrl_bar(nspu_desc, &bar_offset) != 0) { @@ -2554,6 +2683,17 @@ nfp_net_init(struct rte_eth_dev *eth_dev) PMD_INIT_LOG(DEBUG, "ctrl bar: %p\n", hw->ctrl_bar); } + if (port > 0) { + if (!hwport0->ctrl_bar) + return -ENODEV; + + /* address based on port0 offset */ + hw->ctrl_bar = hwport0->ctrl_bar + + (port * NFP_PF_CSR_SLICE_SIZE); + } + + PMD_INIT_LOG(DEBUG, "ctrl bar: %p\n", hw->ctrl_bar); + hw->max_rx_queues = nn_cfg_readl(hw, NFP_NET_CFG_MAX_RXRINGS); hw->max_tx_queues = nn_cfg_readl(hw, NFP_NET_CFG_MAX_TXRINGS); @@ -2575,18 +2715,25 @@ nfp_net_init(struct rte_eth_dev *eth_dev) PMD_INIT_LOG(DEBUG, "tx_bar_off: 0x%" PRIx64 "\n", tx_bar_off); PMD_INIT_LOG(DEBUG, "rx_bar_off: 0x%" PRIx64 "\n", rx_bar_off); - if ((pci_dev->id.device_id == PCI_DEVICE_ID_NFP4000_PF_NIC) || - (pci_dev->id.device_id == PCI_DEVICE_ID_NFP6000_PF_NIC)) { + if (hw->is_pf && port == 0) { /* configure access to tx/rx vNIC BARs */ nfp_nsp_map_queues_bar(nspu_desc, &bar_offset); PMD_INIT_LOG(DEBUG, "tx/rx bar_offset: %" PRIx64 "\n", bar_offset); - hw->hw_queues = (uint8_t *)pci_dev->mem_resource[0].addr; + hwport0->hw_queues = (uint8_t *)pci_dev->mem_resource[0].addr; /* vNIC PF tx/rx BARs are a subset of PF PCI device */ - hw->hw_queues += bar_offset; - hw->tx_bar = hw->hw_queues + tx_bar_off; - hw->rx_bar = hw->hw_queues + rx_bar_off; + hwport0->hw_queues += bar_offset; + + /* Lets seize the chance to read eth table from hw */ + if (nfp_nsp_eth_read_table(nspu_desc, &hw->eth_table)) + return -ENODEV; + } + + if (hw->is_pf) { + hw->tx_bar = hwport0->hw_queues + tx_bar_off; + hw->rx_bar = hwport0->hw_queues + rx_bar_off; + eth_dev->data->dev_private = hw; } else { hw->tx_bar = (uint8_t *)pci_dev->mem_resource[2].addr + tx_bar_off; @@ -2641,7 +2788,10 @@ nfp_net_init(struct rte_eth_dev *eth_dev) return -ENOMEM; } - nfp_net_read_mac(hw); + if (hw->is_pf) + nfp_net_pf_read_mac(hwport0, port); + else + nfp_net_vf_read_mac(hw); if (!is_valid_assigned_ether_addr((struct ether_addr *)&hw->mac_addr)) { /* Using random mac addresses for VFs */ @@ -2674,16 +2824,77 @@ nfp_net_init(struct rte_eth_dev *eth_dev) return 0; } -static int nfp_pf_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, - struct rte_pci_device *dev) +static int +nfp_pf_create_dev(struct rte_pci_device *dev, int port, int ports, + nfpu_desc_t *nfpu_desc, void **priv) { struct rte_eth_dev *eth_dev; struct nfp_net_hw *hw; + char *port_name; + int ret; + + port_name = rte_zmalloc("nfp_pf_port_name", 100, 0); + if (!port_name) + return -ENOMEM; + + if (ports > 1) + sprintf(port_name, "%s_port%d", dev->device.name, port); + else + sprintf(port_name, "%s", dev->device.name); + + eth_dev = rte_eth_dev_allocate(port_name); + if (!eth_dev) + return -ENOMEM; + + if (port == 0) { + *priv = rte_zmalloc(port_name, + sizeof(struct nfp_net_adapter) * ports, + RTE_CACHE_LINE_SIZE); + if (!*priv) { + rte_eth_dev_release_port(eth_dev); + return -ENOMEM; + } + } + + eth_dev->data->dev_private = *priv; + + /* + * dev_private pointing to port0 dev_private because we need + * to configure vNIC bars based on port0 at nfp_net_init. + * Then dev_private is adjusted per port. + */ + hw = (struct nfp_net_hw *)(eth_dev->data->dev_private) + port; + hw->nspu_desc = nfpu_desc->nspu; + hw->nfpu_desc = nfpu_desc; + hw->is_pf = 1; + if (ports > 1) + hw->pf_multiport_enabled = 1; + + eth_dev->device = &dev->device; + rte_eth_copy_pci_info(eth_dev, dev); + + ret = nfp_net_init(eth_dev); + + if (ret) + rte_eth_dev_release_port(eth_dev); + + rte_free(port_name); + + return ret; +} + +static int nfp_pf_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, + struct rte_pci_device *dev) +{ nfpu_desc_t *nfpu_desc; nspu_desc_t *nspu_desc; uint64_t offset_symbol; + uint8_t *bar_offset; int major, minor; + int total_ports; + void *priv = 0; int ret = -ENODEV; + int i; if (!dev) return ret; @@ -2718,36 +2929,24 @@ static int nfp_pf_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, if (ret) goto error; - eth_dev = rte_eth_dev_allocate(dev->device.name); - if (!eth_dev) { - ret = -ENODEV; - goto error; - } + bar_offset = (uint8_t *)dev->mem_resource[0].addr; + bar_offset += offset_symbol; + total_ports = (uint32_t)*bar_offset; + PMD_INIT_LOG(INFO, "Total pf ports: %d\n", total_ports); - eth_dev->data->dev_private = rte_zmalloc("nfp_pf_port", - sizeof(struct nfp_net_adapter), - RTE_CACHE_LINE_SIZE); - if (!eth_dev->data->dev_private) { - rte_eth_dev_release_port(eth_dev); + if (total_ports <= 0 || total_ports > 8) { + RTE_LOG(ERR, PMD, "nfd_cfg_pf0_num_ports symbol with wrong value"); ret = -ENODEV; goto error; } - hw = (struct nfp_net_hw *)(eth_dev->data->dev_private); - hw->nspu_desc = nspu_desc; - hw->nfpu_desc = nfpu_desc; - hw->is_pf = 1; - - eth_dev->device = &dev->device; - rte_eth_copy_pci_info(eth_dev, dev); - - ret = nfp_net_init(eth_dev); - - if (!ret) - return 0; + for (i = 0; i < total_ports; i++) { + ret = nfp_pf_create_dev(dev, i, total_ports, nfpu_desc, &priv); + if (ret) + goto error; + } - /* something went wrong */ - rte_eth_dev_release_port(eth_dev); + return 0; error: nfpu_close(nfpu_desc);