Commit ff9df482 authored by Eric Dumazet's avatar Eric Dumazet Committed by Greg Kroah-Hartman

alx: fix alx_poll()

[ Upstream commit 7a05dc64 ]

Commit d75b1ade ("net: less interrupt masking in NAPI") uncovered
wrong alx_poll() behavior.

A NAPI poll() handler is supposed to return exactly the budget when/if
napi_complete() has not been called.

It is also supposed to return number of frames that were received, so
that netdev_budget can have a meaning.

Also, in case of TX pressure, we still have to dequeue received
packets : alx_clean_rx_irq() has to be called even if
alx_clean_tx_irq(alx) returns false, otherwise device is half duplex.
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Fixes: d75b1ade ("net: less interrupt masking in NAPI")
Reported-by: default avatarOded Gabbay <oded.gabbay@amd.com>
Bisected-by: default avatarOded Gabbay <oded.gabbay@amd.com>
Tested-by: default avatarOded Gabbay <oded.gabbay@amd.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 2aab9536
...@@ -184,15 +184,16 @@ static void alx_schedule_reset(struct alx_priv *alx) ...@@ -184,15 +184,16 @@ static void alx_schedule_reset(struct alx_priv *alx)
schedule_work(&alx->reset_wk); schedule_work(&alx->reset_wk);
} }
static bool alx_clean_rx_irq(struct alx_priv *alx, int budget) static int alx_clean_rx_irq(struct alx_priv *alx, int budget)
{ {
struct alx_rx_queue *rxq = &alx->rxq; struct alx_rx_queue *rxq = &alx->rxq;
struct alx_rrd *rrd; struct alx_rrd *rrd;
struct alx_buffer *rxb; struct alx_buffer *rxb;
struct sk_buff *skb; struct sk_buff *skb;
u16 length, rfd_cleaned = 0; u16 length, rfd_cleaned = 0;
int work = 0;
while (budget > 0) { while (work < budget) {
rrd = &rxq->rrd[rxq->rrd_read_idx]; rrd = &rxq->rrd[rxq->rrd_read_idx];
if (!(rrd->word3 & cpu_to_le32(1 << RRD_UPDATED_SHIFT))) if (!(rrd->word3 & cpu_to_le32(1 << RRD_UPDATED_SHIFT)))
break; break;
...@@ -203,7 +204,7 @@ static bool alx_clean_rx_irq(struct alx_priv *alx, int budget) ...@@ -203,7 +204,7 @@ static bool alx_clean_rx_irq(struct alx_priv *alx, int budget)
ALX_GET_FIELD(le32_to_cpu(rrd->word0), ALX_GET_FIELD(le32_to_cpu(rrd->word0),
RRD_NOR) != 1) { RRD_NOR) != 1) {
alx_schedule_reset(alx); alx_schedule_reset(alx);
return 0; return work;
} }
rxb = &rxq->bufs[rxq->read_idx]; rxb = &rxq->bufs[rxq->read_idx];
...@@ -243,7 +244,7 @@ static bool alx_clean_rx_irq(struct alx_priv *alx, int budget) ...@@ -243,7 +244,7 @@ static bool alx_clean_rx_irq(struct alx_priv *alx, int budget)
} }
napi_gro_receive(&alx->napi, skb); napi_gro_receive(&alx->napi, skb);
budget--; work++;
next_pkt: next_pkt:
if (++rxq->read_idx == alx->rx_ringsz) if (++rxq->read_idx == alx->rx_ringsz)
...@@ -258,21 +259,22 @@ static bool alx_clean_rx_irq(struct alx_priv *alx, int budget) ...@@ -258,21 +259,22 @@ static bool alx_clean_rx_irq(struct alx_priv *alx, int budget)
if (rfd_cleaned) if (rfd_cleaned)
alx_refill_rx_ring(alx, GFP_ATOMIC); alx_refill_rx_ring(alx, GFP_ATOMIC);
return budget > 0; return work;
} }
static int alx_poll(struct napi_struct *napi, int budget) static int alx_poll(struct napi_struct *napi, int budget)
{ {
struct alx_priv *alx = container_of(napi, struct alx_priv, napi); struct alx_priv *alx = container_of(napi, struct alx_priv, napi);
struct alx_hw *hw = &alx->hw; struct alx_hw *hw = &alx->hw;
bool complete = true;
unsigned long flags; unsigned long flags;
bool tx_complete;
int work;
complete = alx_clean_tx_irq(alx) && tx_complete = alx_clean_tx_irq(alx);
alx_clean_rx_irq(alx, budget); work = alx_clean_rx_irq(alx, budget);
if (!complete) if (!tx_complete || work == budget)
return 1; return budget;
napi_complete(&alx->napi); napi_complete(&alx->napi);
...@@ -284,7 +286,7 @@ static int alx_poll(struct napi_struct *napi, int budget) ...@@ -284,7 +286,7 @@ static int alx_poll(struct napi_struct *napi, int budget)
alx_post_write(hw); alx_post_write(hw);
return 0; return work;
} }
static irqreturn_t alx_intr_handle(struct alx_priv *alx, u32 intr) static irqreturn_t alx_intr_handle(struct alx_priv *alx, u32 intr)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment