From: Javen Xu RSS uses multi rx queues to receive packets, and each rx queue needs one irq and napi. So this patch adds support for multi irqs and napi here. Signed-off-by: Javen Xu --- Changes in v2: - remove some unused definitions, such as index, name in rtl8169_irq - remove array imr and isr - remove min_irq_nvecs and max_irq_nvecs, replaced with help function get_min_irq_nvecs and get_max_irq_nvecs - alloc irq by flags, instead of PCI_IRQ_ALL_TYPES Changes in v3: - add enum rtl_isr_version to replace macro definition - remove struct rtl8169_napi, use napi_struct array instead and alloc memory for this array dynamically - remove struct rtl8169_irq Changes in v4: - change retval to ret in rtl8169_set_real_num_queue() - reverse xmas tree in rtl8169_poll() and rtl8169_interrupt() - remove tp->hw_supp_isr_ver Changes in v5: - rtl8169_request_irq(), when failed, only free irqs which are allocated - remove rss_support, simplied napi init, call r8169_init_napi() directly - remove rtl_isr_version, INTR_VEC_MAP_MASK, INTR_VEC_MAP_STATUS, R8169_MAX_MSIX_VEC, rss_enable, recheck_desc_ownbit - rtl_software_parameter_initialize() this function will be expanded in next patch, so i want to remain it here. Changes in v6: - Fix netpoll crash - Fix use-after-free during driver unload by registering a devm action for netif_napi_del() - remove tp->irq Changes in v7: - pass NAPI as arg to rtl_rx() - use netif_set_real_num_queues to replace rtl8169_set_real_num_queues - replace rtl_software_parameter_initialize with rtl_setup_rx_params Changes in v8: - no changes --- drivers/net/ethernet/realtek/r8169_main.c | 150 +++++++++++++++++----- 1 file changed, 121 insertions(+), 29 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index ec4fc21fa21f..8f3a5c50299f 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -733,7 +733,6 @@ struct rtl8169_private { struct pci_dev *pci_dev; struct net_device *dev; struct phy_device *phydev; - struct napi_struct napi; enum mac_version mac_version; enum rtl_dash_type dash_type; u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */ @@ -745,10 +744,12 @@ struct rtl8169_private { dma_addr_t RxPhyAddr; struct page *Rx_databuff[NUM_RX_DESC]; /* Rx data buffers */ struct ring_info tx_skb[NUM_TX_DESC]; /* Tx data buffers */ + struct napi_struct *rtl8169_napi; + unsigned int num_rx_rings; u16 cp_cmd; u16 tx_lpi_timer; u32 irq_mask; - int irq; + unsigned int irq_nvecs; struct clk *clk; struct { @@ -2680,6 +2681,11 @@ static void rtl_hw_reset(struct rtl8169_private *tp) rtl_loop_wait_low(tp, &rtl_chipcmd_cond, 100, 100); } +static void rtl_setup_rx_params(struct rtl8169_private *tp) +{ + tp->num_rx_rings = 1; +} + static void rtl_request_firmware(struct rtl8169_private *tp) { struct rtl_fw *rtl_fw; @@ -4266,9 +4272,21 @@ static void rtl8169_tx_clear(struct rtl8169_private *tp) netdev_reset_queue(tp->dev); } +static void rtl8169_napi_disable(struct rtl8169_private *tp) +{ + for (int i = 0; i < tp->irq_nvecs; i++) + napi_disable(&tp->rtl8169_napi[i]); +} + +static void rtl8169_napi_enable(struct rtl8169_private *tp) +{ + for (int i = 0; i < tp->irq_nvecs; i++) + napi_enable(&tp->rtl8169_napi[i]); +} + static void rtl8169_cleanup(struct rtl8169_private *tp) { - napi_disable(&tp->napi); + rtl8169_napi_disable(tp); /* Give a racing hard_start_xmit a few cycles to complete. */ synchronize_net(); @@ -4314,7 +4332,7 @@ static void rtl_reset_work(struct rtl8169_private *tp) for (i = 0; i < NUM_RX_DESC; i++) rtl8169_mark_to_asic(tp->RxDescArray + i); - napi_enable(&tp->napi); + rtl8169_napi_enable(tp); rtl_hw_start(tp); } @@ -4768,7 +4786,8 @@ static inline void rtl8169_rx_csum(struct sk_buff *skb, u32 opts1) skb_checksum_none_assert(skb); } -static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, int budget) +static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, + int budget, struct napi_struct *napi) { struct device *d = tp_to_dev(tp); int count; @@ -4820,7 +4839,7 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, int budget goto release_descriptor; } - skb = napi_alloc_skb(&tp->napi, pkt_size); + skb = napi_alloc_skb(napi, pkt_size); if (unlikely(!skb)) { dev->stats.rx_dropped++; goto release_descriptor; @@ -4844,7 +4863,7 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, int budget if (skb->pkt_type == PACKET_MULTICAST) dev->stats.multicast++; - napi_gro_receive(&tp->napi, skb); + napi_gro_receive(napi, skb); dev_sw_netstats_rx_add(dev, pkt_size); release_descriptor: @@ -4856,8 +4875,12 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, int budget static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance) { - struct rtl8169_private *tp = dev_instance; - u32 status = rtl_get_events(tp); + struct napi_struct *napi = dev_instance; + struct rtl8169_private *tp; + u32 status; + + tp = netdev_priv(napi->dev); + status = rtl_get_events(tp); if ((status & 0xffff) == 0xffff || !(status & tp->irq_mask)) return IRQ_NONE; @@ -4873,13 +4896,43 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance) phy_mac_interrupt(tp->phydev); rtl_irq_disable(tp); - napi_schedule(&tp->napi); + napi_schedule(napi); out: rtl_ack_events(tp, status); return IRQ_HANDLED; } +static void rtl8169_free_irq(struct rtl8169_private *tp) +{ + for (int i = 0; i < tp->irq_nvecs; i++) { + struct napi_struct *napi = &tp->rtl8169_napi[i]; + + pci_free_irq(tp->pci_dev, i, napi); + } +} + +static int rtl8169_request_irq(struct rtl8169_private *tp) +{ + struct net_device *dev = tp->dev; + struct napi_struct *napi; + int i, rc; + + for (i = 0; i < tp->irq_nvecs; i++) { + napi = &tp->rtl8169_napi[i]; + rc = pci_request_irq(tp->pci_dev, i, rtl8169_interrupt, + NULL, napi, "%s-%d", dev->name, i); + if (rc) + goto free_irq; + } + return 0; + +free_irq: + while (--i >= 0) + pci_free_irq(tp->pci_dev, i, &tp->rtl8169_napi[i]); + return rc; +} + static void rtl_task(struct work_struct *work) { struct rtl8169_private *tp = @@ -4914,13 +4967,13 @@ static void rtl_task(struct work_struct *work) static int rtl8169_poll(struct napi_struct *napi, int budget) { - struct rtl8169_private *tp = container_of(napi, struct rtl8169_private, napi); - struct net_device *dev = tp->dev; - int work_done; + struct rtl8169_private *tp = netdev_priv(napi->dev); + struct net_device *dev = napi->dev; + int work_done = 0; rtl_tx(dev, tp, budget); - work_done = rtl_rx(dev, tp, budget); + work_done = rtl_rx(dev, tp, budget, napi); if (work_done < budget && napi_complete_done(napi, work_done)) rtl_irq_enable(tp); @@ -5035,7 +5088,7 @@ static void rtl8169_up(struct rtl8169_private *tp) phy_init_hw(tp->phydev); phy_resume(tp->phydev); rtl8169_init_phy(tp); - napi_enable(&tp->napi); + rtl8169_napi_enable(tp); enable_work(&tp->wk.work); rtl_reset_work(tp); @@ -5053,7 +5106,7 @@ static int rtl8169_close(struct net_device *dev) rtl8169_down(tp); rtl8169_rx_clear(tp); - free_irq(tp->irq, tp); + rtl8169_free_irq(tp); phy_disconnect(tp->phydev); @@ -5074,7 +5127,10 @@ static void rtl8169_netpoll(struct net_device *dev) { struct rtl8169_private *tp = netdev_priv(dev); - rtl8169_interrupt(tp->irq, tp); + for (int i = 0; i < tp->irq_nvecs; i++) { + rtl8169_interrupt(pci_irq_vector(tp->pci_dev, i), + &tp->rtl8169_napi[i]); + } } #endif @@ -5082,7 +5138,6 @@ static int rtl_open(struct net_device *dev) { struct rtl8169_private *tp = netdev_priv(dev); struct pci_dev *pdev = tp->pci_dev; - unsigned long irqflags; int retval = -ENOMEM; pm_runtime_get_sync(&pdev->dev); @@ -5107,8 +5162,7 @@ static int rtl_open(struct net_device *dev) rtl_request_firmware(tp); - irqflags = pci_dev_msi_enabled(pdev) ? IRQF_NO_THREAD : IRQF_SHARED; - retval = request_irq(tp->irq, rtl8169_interrupt, irqflags, dev->name, tp); + retval = rtl8169_request_irq(tp); if (retval < 0) goto err_release_fw_2; @@ -5125,7 +5179,7 @@ static int rtl_open(struct net_device *dev) return retval; err_free_irq: - free_irq(tp->irq, tp); + rtl8169_free_irq(tp); err_release_fw_2: rtl_release_firmware(tp); rtl8169_rx_clear(tp); @@ -5275,6 +5329,14 @@ static void rtl_shutdown(struct pci_dev *pdev) pci_prepare_to_sleep(pdev); } +static void r8169_free_napi(struct rtl8169_private *tp) +{ + for (int i = 0; i < tp->irq_nvecs; i++) + netif_napi_del(&tp->rtl8169_napi[i]); + + kfree(tp->rtl8169_napi); +} + static void rtl_remove_one(struct pci_dev *pdev) { struct rtl8169_private *tp = pci_get_drvdata(pdev); @@ -5289,6 +5351,8 @@ static void rtl_remove_one(struct pci_dev *pdev) unregister_netdev(tp->dev); + r8169_free_napi(tp); + if (tp->dash_type != RTL_DASH_NONE) rtl8168_driver_stop(tp); @@ -5328,7 +5392,9 @@ static void rtl_set_irq_mask(struct rtl8169_private *tp) static int rtl_alloc_irq(struct rtl8169_private *tp) { + struct pci_dev *pdev = tp->pci_dev; unsigned int flags; + int nvecs; switch (tp->mac_version) { case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06: @@ -5344,7 +5410,14 @@ static int rtl_alloc_irq(struct rtl8169_private *tp) break; } - return pci_alloc_irq_vectors(tp->pci_dev, 1, 1, flags); + nvecs = pci_alloc_irq_vectors(pdev, 1, 1, flags); + + if (nvecs < 0) + return nvecs; + + tp->irq_nvecs = nvecs; + + return 0; } static void rtl_read_mac_address(struct rtl8169_private *tp, @@ -5599,6 +5672,12 @@ static bool rtl_aspm_is_safe(struct rtl8169_private *tp) return false; } +static void r8169_init_napi(struct rtl8169_private *tp) +{ + for (int i = 0; i < tp->irq_nvecs; i++) + netif_napi_add(tp->dev, &tp->rtl8169_napi[i], rtl8169_poll); +} + static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { const struct rtl_chip_info *chip; @@ -5703,12 +5782,12 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) rtl_hw_reset(tp); + rtl_setup_rx_params(tp); + rc = rtl_alloc_irq(tp); if (rc < 0) return dev_err_probe(&pdev->dev, rc, "Can't allocate interrupt\n"); - tp->irq = pci_irq_vector(pdev, 0); - INIT_WORK(&tp->wk.work, rtl_task); disable_work(&tp->wk.work); @@ -5716,8 +5795,6 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev->ethtool_ops = &rtl8169_ethtool_ops; - netif_napi_add(dev, &tp->napi, rtl8169_poll); - dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM | NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX; dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO; @@ -5778,6 +5855,10 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (jumbo_max) dev->max_mtu = jumbo_max; + rc = netif_set_real_num_queues(tp->dev, 1, tp->num_rx_rings); + if (rc < 0) + return dev_err_probe(&pdev->dev, rc, "set tx/rx num failure\n"); + rtl_set_irq_mask(tp); tp->counters = dmam_alloc_coherent (&pdev->dev, sizeof(*tp->counters), @@ -5792,9 +5873,15 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) return rc; + tp->rtl8169_napi = kcalloc(tp->irq_nvecs, sizeof(struct napi_struct), GFP_KERNEL); + if (!tp->rtl8169_napi) + return -ENOMEM; + + r8169_init_napi(tp); + rc = register_netdev(dev); if (rc) - return rc; + goto err_free_napi; if (IS_ENABLED(CONFIG_R8169_LEDS)) { if (rtl_is_8125(tp)) @@ -5803,8 +5890,9 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) tp->leds = rtl8168_init_leds(dev); } - netdev_info(dev, "%s, %pM, %sXID %x, IRQ %d\n", - chip->name, dev->dev_addr, ext_xid_str, xid, tp->irq); + netdev_info(dev, "%s, %pM, %sXID %x, IRQ %d (%d total)\n", + chip->name, dev->dev_addr, ext_xid_str, xid, + pci_irq_vector(pdev, 0), tp->irq_nvecs); if (jumbo_max) netdev_info(dev, "jumbo features [frames: %d bytes, tx checksumming: %s]\n", @@ -5821,6 +5909,10 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) pm_runtime_put_sync(&pdev->dev); return 0; + +err_free_napi: + r8169_free_napi(tp); + return rc; } static struct pci_driver rtl8169_pci_driver = { -- 2.43.0