mirror of
https://github.com/torvalds/linux
synced 2024-11-05 18:23:50 +00:00
alx: fix alx_poll()
Commitd75b1ade56
("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: Eric Dumazet <edumazet@google.com> Fixes:d75b1ade56
("net: less interrupt masking in NAPI") Reported-by: Oded Gabbay <oded.gabbay@amd.com> Bisected-by: Oded Gabbay <oded.gabbay@amd.com> Tested-by: Oded Gabbay <oded.gabbay@amd.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
12d80ac4e7
commit
7a05dc64e2
1 changed files with 13 additions and 11 deletions
|
@ -184,15 +184,16 @@ static void alx_schedule_reset(struct alx_priv *alx)
|
|||
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_rrd *rrd;
|
||||
struct alx_buffer *rxb;
|
||||
struct sk_buff *skb;
|
||||
u16 length, rfd_cleaned = 0;
|
||||
int work = 0;
|
||||
|
||||
while (budget > 0) {
|
||||
while (work < budget) {
|
||||
rrd = &rxq->rrd[rxq->rrd_read_idx];
|
||||
if (!(rrd->word3 & cpu_to_le32(1 << RRD_UPDATED_SHIFT)))
|
||||
break;
|
||||
|
@ -203,7 +204,7 @@ static bool alx_clean_rx_irq(struct alx_priv *alx, int budget)
|
|||
ALX_GET_FIELD(le32_to_cpu(rrd->word0),
|
||||
RRD_NOR) != 1) {
|
||||
alx_schedule_reset(alx);
|
||||
return 0;
|
||||
return work;
|
||||
}
|
||||
|
||||
rxb = &rxq->bufs[rxq->read_idx];
|
||||
|
@ -243,7 +244,7 @@ static bool alx_clean_rx_irq(struct alx_priv *alx, int budget)
|
|||
}
|
||||
|
||||
napi_gro_receive(&alx->napi, skb);
|
||||
budget--;
|
||||
work++;
|
||||
|
||||
next_pkt:
|
||||
if (++rxq->read_idx == alx->rx_ringsz)
|
||||
|
@ -258,21 +259,22 @@ static bool alx_clean_rx_irq(struct alx_priv *alx, int budget)
|
|||
if (rfd_cleaned)
|
||||
alx_refill_rx_ring(alx, GFP_ATOMIC);
|
||||
|
||||
return budget > 0;
|
||||
return work;
|
||||
}
|
||||
|
||||
static int alx_poll(struct napi_struct *napi, int budget)
|
||||
{
|
||||
struct alx_priv *alx = container_of(napi, struct alx_priv, napi);
|
||||
struct alx_hw *hw = &alx->hw;
|
||||
bool complete = true;
|
||||
unsigned long flags;
|
||||
bool tx_complete;
|
||||
int work;
|
||||
|
||||
complete = alx_clean_tx_irq(alx) &&
|
||||
alx_clean_rx_irq(alx, budget);
|
||||
tx_complete = alx_clean_tx_irq(alx);
|
||||
work = alx_clean_rx_irq(alx, budget);
|
||||
|
||||
if (!complete)
|
||||
return 1;
|
||||
if (!tx_complete || work == budget)
|
||||
return budget;
|
||||
|
||||
napi_complete(&alx->napi);
|
||||
|
||||
|
@ -284,7 +286,7 @@ static int alx_poll(struct napi_struct *napi, int budget)
|
|||
|
||||
alx_post_write(hw);
|
||||
|
||||
return 0;
|
||||
return work;
|
||||
}
|
||||
|
||||
static irqreturn_t alx_intr_handle(struct alx_priv *alx, u32 intr)
|
||||
|
|
Loading…
Reference in a new issue