>From a4897d6d64d5e880dd3a6f30b17c3cb1c02a244e Mon Sep 17 00:00:00 2001 Message-Id: In-Reply-To: <3f5bcfcc93ecc8634e5da95cc58a751e39a1ec9f.1439418772.git.romieu@fr.zoreil.com> References: <3f5bcfcc93ecc8634e5da95cc58a751e39a1ec9f.1439418772.git.romieu@fr.zoreil.com> From: Francois Romieu 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 --- 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