Ron Angeles <ronange...@gmail.com> : > This BQL implementation is mostly derived from its related driver, alx. > Tested on AR8131 (rev c0) [1969:1063]. Saturated a 100mbps link with 5 > concurrent runs of netperf. Ping latency dropped from 14ms to 3ms.
Could you use some time to test the attached experimental stuff as well ? -- Ueimor
>From 3f5bcfcc93ecc8634e5da95cc58a751e39a1ec9f Mon Sep 17 00:00:00 2001 Message-Id: <3f5bcfcc93ecc8634e5da95cc58a751e39a1ec9f.1439418772.git.rom...@fr.zoreil.com> From: Francois Romieu <rom...@fr.zoreil.com> Date: Sun, 19 Apr 2015 00:23:51 +0200 Subject: [PATCH 1/5] atl1c: use return value where argument pointer makes no sense. X-Organisation: Land of Sunshine Inc. Signed-off-by: Francois Romieu <rom...@fr.zoreil.com> --- drivers/net/ethernet/atheros/atl1c/atl1c_main.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c index 932bd18..282ec17 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c @@ -56,8 +56,7 @@ static int atl1c_stop_mac(struct atl1c_hw *hw); static void atl1c_disable_l0s_l1(struct atl1c_hw *hw); static void atl1c_set_aspm(struct atl1c_hw *hw, u16 link_speed); static void atl1c_start_mac(struct atl1c_adapter *adapter); -static void atl1c_clean_rx_irq(struct atl1c_adapter *adapter, - int *work_done, int work_to_do); +static int atl1c_clean_rx_irq(struct atl1c_adapter *adapter, int budget); static int atl1c_up(struct atl1c_adapter *adapter); static void atl1c_down(struct atl1c_adapter *adapter); static int atl1c_reset_mac(struct atl1c_hw *hw); @@ -1787,11 +1786,10 @@ static void atl1c_clean_rfd(struct atl1c_rfd_ring *rfd_ring, rfd_ring->next_to_clean = rfd_index; } -static void atl1c_clean_rx_irq(struct atl1c_adapter *adapter, - int *work_done, int work_to_do) +static int atl1c_clean_rx_irq(struct atl1c_adapter *adapter, int budget) { u16 rfd_num, rfd_index; - u16 count = 0; + u16 count; u16 length; struct pci_dev *pdev = adapter->pdev; struct net_device *netdev = adapter->netdev; @@ -1801,9 +1799,7 @@ static void atl1c_clean_rx_irq(struct atl1c_adapter *adapter, struct atl1c_recv_ret_status *rrs; struct atl1c_buffer *buffer_info; - while (1) { - if (*work_done >= work_to_do) - break; + for (count = 0; count < budget; count++) { rrs = ATL1C_RRD_DESC(rrd_ring, rrd_ring->next_to_clean); if (likely(RRS_RXD_IS_VALID(rrs->word3))) { rfd_num = (rrs->word0 >> RRS_RX_RFD_CNT_SHIFT) & @@ -1857,12 +1853,11 @@ rrs_checked: __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan); } netif_receive_skb(skb); - - (*work_done)++; - count++; } if (count) atl1c_alloc_rx_buffer(adapter); + + return count; } /** @@ -1875,10 +1870,10 @@ static int atl1c_clean(struct napi_struct *napi, int budget) int work_done = 0; /* Keep link state information with original netdev */ - if (!netif_carrier_ok(adapter->netdev)) + if (unlikely(!netif_carrier_ok(adapter->netdev))) goto quit_polling; /* just enable one RXQ */ - atl1c_clean_rx_irq(adapter, &work_done, budget); + work_done = atl1c_clean_rx_irq(adapter, budget); if (work_done < budget) { quit_polling: -- 2.4.3
>From c1eb6bb4817ed04155e829df435264be675aeab4 Mon Sep 17 00:00:00 2001 Message-Id: <c1eb6bb4817ed04155e829df435264be675aeab4.1439418772.git.rom...@fr.zoreil.com> In-Reply-To: <3f5bcfcc93ecc8634e5da95cc58a751e39a1ec9f.1439418772.git.rom...@fr.zoreil.com> References: <3f5bcfcc93ecc8634e5da95cc58a751e39a1ec9f.1439418772.git.rom...@fr.zoreil.com> From: Francois Romieu <rom...@fr.zoreil.com> Date: Sun, 19 Apr 2015 00:45:09 +0200 Subject: [PATCH 2/5] atl1c: highlight normal code path in receive poller atl1c_clean_rx_irq. X-Organisation: Land of Sunshine Inc. Signed-off-by: Francois Romieu <rom...@fr.zoreil.com> --- drivers/net/ethernet/atheros/atl1c/atl1c_main.c | 46 +++++++++++-------------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c index 282ec17..35ea3ec 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c @@ -1801,46 +1801,40 @@ static int atl1c_clean_rx_irq(struct atl1c_adapter *adapter, int budget) for (count = 0; count < budget; count++) { rrs = ATL1C_RRD_DESC(rrd_ring, rrd_ring->next_to_clean); - if (likely(RRS_RXD_IS_VALID(rrs->word3))) { - rfd_num = (rrs->word0 >> RRS_RX_RFD_CNT_SHIFT) & - RRS_RX_RFD_CNT_MASK; - if (unlikely(rfd_num != 1)) - /* TODO support mul rfd*/ - if (netif_msg_rx_err(adapter)) - dev_warn(&pdev->dev, - "Multi rfd not support yet!\n"); - goto rrs_checked; - } else { + if (unlikely(!RRS_RXD_IS_VALID(rrs->word3))) break; + + rfd_num = (rrs->word0 >> RRS_RX_RFD_CNT_SHIFT) & + RRS_RX_RFD_CNT_MASK; + if (unlikely(rfd_num != 1)) { + /* TODO support mul rfd*/ + netif_warn(adapter, rx_err, netdev, + "Multi rfd not support yet!\n"); } -rrs_checked: + atl1c_clean_rrd(rrd_ring, rrs, rfd_num); if (rrs->word3 & (RRS_RX_ERR_SUM | RRS_802_3_LEN_ERR)) { atl1c_clean_rfd(rfd_ring, rrs, rfd_num); - if (netif_msg_rx_err(adapter)) - dev_warn(&pdev->dev, - "wrong packet! rrs word3 is %x\n", - rrs->word3); + netif_warn(adapter, rx_err, netdev, + "wrong packet! rrs word3: %x\n", rrs->word3); continue; } length = le16_to_cpu((rrs->word3 >> RRS_PKT_SIZE_SHIFT) & RRS_PKT_SIZE_MASK); /* Good Receive */ - if (likely(rfd_num == 1)) { - rfd_index = (rrs->word0 >> RRS_RX_RFD_INDEX_SHIFT) & - RRS_RX_RFD_INDEX_MASK; - buffer_info = &rfd_ring->buffer_info[rfd_index]; - pci_unmap_single(pdev, buffer_info->dma, - buffer_info->length, PCI_DMA_FROMDEVICE); - skb = buffer_info->skb; - } else { + if (unlikely(rfd_num != 1)) { /* TODO */ - if (netif_msg_rx_err(adapter)) - dev_warn(&pdev->dev, - "Multi rfd not support yet!\n"); break; } + + rfd_index = (rrs->word0 >> RRS_RX_RFD_INDEX_SHIFT) & + RRS_RX_RFD_INDEX_MASK; + buffer_info = &rfd_ring->buffer_info[rfd_index]; + pci_unmap_single(pdev, buffer_info->dma, buffer_info->length, + PCI_DMA_FROMDEVICE); + skb = buffer_info->skb; + atl1c_clean_rfd(rfd_ring, rrs, rfd_num); skb_put(skb, length - ETH_FCS_LEN); skb->protocol = eth_type_trans(skb, netdev); -- 2.4.3
>From 60b6eef77b3256e67c1ba1970df8d8488d76164a Mon Sep 17 00:00:00 2001 Message-Id: <60b6eef77b3256e67c1ba1970df8d8488d76164a.1439418772.git.rom...@fr.zoreil.com> In-Reply-To: <3f5bcfcc93ecc8634e5da95cc58a751e39a1ec9f.1439418772.git.rom...@fr.zoreil.com> References: <3f5bcfcc93ecc8634e5da95cc58a751e39a1ec9f.1439418772.git.rom...@fr.zoreil.com> From: Francois Romieu <rom...@fr.zoreil.com> Date: Sat, 2 May 2015 22:33:09 +0200 Subject: [PATCH 3/5] atl1c: remove useless forward declaration and useless variable. X-Organisation: Land of Sunshine Inc. Signed-off-by: Francois Romieu <rom...@fr.zoreil.com> --- drivers/net/ethernet/atheros/atl1c/atl1c_main.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c index 35ea3ec..4150118 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c @@ -56,7 +56,6 @@ static int atl1c_stop_mac(struct atl1c_hw *hw); static void atl1c_disable_l0s_l1(struct atl1c_hw *hw); static void atl1c_set_aspm(struct atl1c_hw *hw, u16 link_speed); static void atl1c_start_mac(struct atl1c_adapter *adapter); -static int atl1c_clean_rx_irq(struct atl1c_adapter *adapter, int budget); static int atl1c_up(struct atl1c_adapter *adapter); static void atl1c_down(struct atl1c_adapter *adapter); static int atl1c_reset_mac(struct atl1c_hw *hw); @@ -1689,7 +1688,6 @@ static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter) struct pci_dev *pdev = adapter->pdev; struct atl1c_buffer *buffer_info, *next_info; struct sk_buff *skb; - void *vir_addr = NULL; u16 num_alloc = 0; u16 rfd_next_to_use, next_next; struct atl1c_rx_free_desc *rfd_desc; @@ -1716,13 +1714,11 @@ static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter) * this will result in a 16 byte aligned IP header after * the 14 byte MAC header is removed */ - vir_addr = skb->data; ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_BUSY); buffer_info->skb = skb; buffer_info->length = adapter->rx_buffer_len; - mapping = pci_map_single(pdev, vir_addr, - buffer_info->length, - PCI_DMA_FROMDEVICE); + mapping = pci_map_single(pdev, skb->data, buffer_info->length, + PCI_DMA_FROMDEVICE); if (unlikely(pci_dma_mapping_error(pdev, mapping))) { dev_kfree_skb(skb); buffer_info->skb = NULL; -- 2.4.3
>From a4897d6d64d5e880dd3a6f30b17c3cb1c02a244e Mon Sep 17 00:00:00 2001 Message-Id: <a4897d6d64d5e880dd3a6f30b17c3cb1c02a244e.1439418772.git.rom...@fr.zoreil.com> In-Reply-To: <3f5bcfcc93ecc8634e5da95cc58a751e39a1ec9f.1439418772.git.rom...@fr.zoreil.com> References: <3f5bcfcc93ecc8634e5da95cc58a751e39a1ec9f.1439418772.git.rom...@fr.zoreil.com> From: Francois Romieu <rom...@fr.zoreil.com> Date: Thu, 13 Aug 2015 00:15:48 +0200 Subject: [PATCH 4/5] atl1c: move tx packet completion to NAPI context. X-Organisation: Land of Sunshine Inc. Signed-off-by: Francois Romieu <rom...@fr.zoreil.com> --- drivers/net/ethernet/atheros/atl1c/atl1c_main.c | 57 +++++++++++++++++++++---- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c index 4150118..5624b58 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c @@ -1570,6 +1570,8 @@ static bool atl1c_clean_tx_irq(struct atl1c_adapter *adapter, return true; } +#define ISR_NAPI (ISR_RX_PKT | ISR_TX_PKT) + /** * atl1c_intr - Interrupt Handler * @irq: interrupt number @@ -1583,6 +1585,7 @@ static irqreturn_t atl1c_intr(int irq, void *data) struct atl1c_hw *hw = &adapter->hw; int max_ints = AT_MAX_INT_WORK; int handled = IRQ_NONE; + u32 intr_mask = 0; u32 status; u32 reg_data; @@ -1598,17 +1601,22 @@ static irqreturn_t atl1c_intr(int irq, void *data) /* link event */ if (status & ISR_GPHY) atl1c_clear_phy_int(adapter); - /* Ack ISR */ + + if (status & ISR_NAPI) + intr_mask = ~ISR_NAPI; + + status &= intr_mask; + + /* Ack non-NAPI events. */ AT_WRITE_REG(hw, REG_ISR, status | ISR_DIS_INT); - if (status & ISR_RX_PKT) { + + if (intr_mask) { if (likely(napi_schedule_prep(&adapter->napi))) { - hw->intr_mask &= ~ISR_RX_PKT; + hw->intr_mask &= intr_mask; AT_WRITE_REG(hw, REG_IMR, hw->intr_mask); __napi_schedule(&adapter->napi); } } - if (status & ISR_TX_PKT) - atl1c_clean_tx_irq(adapter, atl1c_trans_normal); handled = IRQ_HANDLED; /* check if PCIE PHY Link down */ @@ -1850,6 +1858,15 @@ static int atl1c_clean_rx_irq(struct atl1c_adapter *adapter, int budget) return count; } +static u32 atl1c_read_napi_events(struct atl1c_hw *hw) +{ + u32 data; + + AT_READ_REG(hw, REG_ISR, &data); + + return data & ISR_NAPI; +} + /** * atl1c_clean - NAPI Rx polling callback */ @@ -1857,19 +1874,43 @@ static int atl1c_clean(struct napi_struct *napi, int budget) { struct atl1c_adapter *adapter = container_of(napi, struct atl1c_adapter, napi); + struct atl1c_hw *hw = &adapter->hw; + u32 *intr_mask = &hw->intr_mask; int work_done = 0; + u32 status; /* Keep link state information with original netdev */ if (unlikely(!netif_carrier_ok(adapter->netdev))) goto quit_polling; + +work: + status = atl1c_read_napi_events(hw); + /* Ack NAPI events. */ + AT_WRITE_REG(hw, REG_ISR, status); + + if (status & ISR_TX_PKT) + atl1c_clean_tx_irq(adapter, atl1c_trans_normal); + /* just enable one RXQ */ - work_done = atl1c_clean_rx_irq(adapter, budget); + if (status & ISR_RX_PKT) + work_done = atl1c_clean_rx_irq(adapter, budget - work_done); if (work_done < budget) { quit_polling: napi_complete(napi); - adapter->hw.intr_mask |= ISR_RX_PKT; - AT_WRITE_REG(&adapter->hw, REG_IMR, adapter->hw.intr_mask); + + *intr_mask |= ISR_NAPI; + AT_WRITE_REG(&adapter->hw, REG_IMR, *intr_mask); + + /* Play safe if the chipset doesn't honor level triggered irq. */ + status = atl1c_read_napi_events(hw); + if (status) { + *intr_mask &= ~ISR_NAPI; + AT_WRITE_REG(&adapter->hw, REG_IMR, *intr_mask); + + if (likely(napi_schedule_prep(&adapter->napi))) + goto work; + } } return work_done; } -- 2.4.3
>From defdd6f990b188a819902d4f3f36b956c2e63d9b Mon Sep 17 00:00:00 2001 Message-Id: <defdd6f990b188a819902d4f3f36b956c2e63d9b.1439418772.git.rom...@fr.zoreil.com> In-Reply-To: <3f5bcfcc93ecc8634e5da95cc58a751e39a1ec9f.1439418772.git.rom...@fr.zoreil.com> References: <3f5bcfcc93ecc8634e5da95cc58a751e39a1ec9f.1439418772.git.rom...@fr.zoreil.com> From: Francois Romieu <rom...@fr.zoreil.com> Date: Thu, 13 Aug 2015 00:21:04 +0200 Subject: [PATCH 5/5] atl1c: remove tx_lock. X-Organisation: Land of Sunshine Inc. Being only used in atl1c_xmit_frame makes it a good candidate for removal, especially as tx completion now happens in softirq context. TODO: check the details / elaborate... Signed-off-by: Francois Romieu <rom...@fr.zoreil.com> --- drivers/net/ethernet/atheros/atl1c/atl1c.h | 3 +-- drivers/net/ethernet/atheros/atl1c/atl1c_main.c | 11 ----------- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c.h b/drivers/net/ethernet/atheros/atl1c/atl1c.h index b9203d9..c46b489 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c.h +++ b/drivers/net/ethernet/atheros/atl1c/atl1c.h @@ -488,7 +488,7 @@ struct atl1c_tpd_ring { dma_addr_t dma; /* descriptor ring physical address */ u16 size; /* descriptor ring length in bytes */ u16 count; /* number of descriptors in the ring */ - u16 next_to_use; /* this is protectd by adapter->tx_lock */ + u16 next_to_use; atomic_t next_to_clean; struct atl1c_buffer *buffer_info; }; @@ -542,7 +542,6 @@ struct atl1c_adapter { u16 link_duplex; spinlock_t mdio_lock; - spinlock_t tx_lock; atomic_t irq_sem; struct work_struct common_task; diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c index 5624b58..63b65e3 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c @@ -823,7 +823,6 @@ static int atl1c_sw_init(struct atl1c_adapter *adapter) atl1c_set_rxbufsize(adapter, adapter->netdev); atomic_set(&adapter->irq_sem, 1); spin_lock_init(&adapter->mdio_lock); - spin_lock_init(&adapter->tx_lock); set_bit(__AT_DOWN, &adapter->flags); return 0; @@ -2228,7 +2227,6 @@ static netdev_tx_t atl1c_xmit_frame(struct sk_buff *skb, struct net_device *netdev) { struct atl1c_adapter *adapter = netdev_priv(netdev); - unsigned long flags; u16 tpd_req = 1; struct atl1c_tpd_desc *tpd; enum atl1c_trans_queue type = atl1c_trans_normal; @@ -2239,16 +2237,10 @@ static netdev_tx_t atl1c_xmit_frame(struct sk_buff *skb, } tpd_req = atl1c_cal_tpd_req(skb); - if (!spin_trylock_irqsave(&adapter->tx_lock, flags)) { - if (netif_msg_pktdata(adapter)) - dev_info(&adapter->pdev->dev, "tx locked\n"); - return NETDEV_TX_LOCKED; - } if (atl1c_tpd_avail(adapter, type) < tpd_req) { /* no enough descriptor, just stop queue */ netif_stop_queue(netdev); - spin_unlock_irqrestore(&adapter->tx_lock, flags); return NETDEV_TX_BUSY; } @@ -2256,7 +2248,6 @@ static netdev_tx_t atl1c_xmit_frame(struct sk_buff *skb, /* do TSO and check sum */ if (atl1c_tso_csum(adapter, skb, &tpd, type) != 0) { - spin_unlock_irqrestore(&adapter->tx_lock, flags); dev_kfree_skb_any(skb); return NETDEV_TX_OK; } @@ -2279,11 +2270,9 @@ static netdev_tx_t atl1c_xmit_frame(struct sk_buff *skb, "tx-skb droppted due to dma error\n"); /* roll back tpd/buffer */ atl1c_tx_rollback(adapter, tpd, type); - spin_unlock_irqrestore(&adapter->tx_lock, flags); dev_kfree_skb_any(skb); } else { atl1c_tx_queue(adapter, skb, tpd, type); - spin_unlock_irqrestore(&adapter->tx_lock, flags); } return NETDEV_TX_OK; -- 2.4.3