Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7a05dc64 authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller
Browse files

alx: fix alx_poll()



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>
parent 12d80ac4
Loading
Loading
Loading
Loading
+13 −11
Original line number Diff line number Diff line
@@ -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)