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

Commit 406f353c authored by Matheos Worku's avatar Matheos Worku Committed by David S. Miller
Browse files

[NIU]: Fix slowpath interrupt handling.



niu_slowpath_interrupt() expects values to be setup in lp->{v0,v1,v2}
but they aren't.  That's only done by niu_schedule_napi() which is
done later in the interrupt path.

If niu_rx_error() returns zero, and v0 is clear, hit the
RX_DMA_CTL_STATE register with a RX_DMA_CTL_STAT_MEX.

Only emit verbose RX error logs if a fatal channel or port error is
signalled.  Other cases will be recorded into statistics by
niu_log_rxchan_errors().

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent cdf71a10
Loading
Loading
Loading
Loading
+23 −11
Original line number Diff line number Diff line
@@ -2508,15 +2508,19 @@ static int niu_rx_error(struct niu *np, struct rx_ring_info *rp)
	u64 stat = nr64(RX_DMA_CTL_STAT(rp->rx_channel));
	int err = 0;

	dev_err(np->device, PFX "%s: RX channel %u error, stat[%llx]\n",
		np->dev->name, rp->rx_channel, (unsigned long long) stat);

	niu_log_rxchan_errors(np, rp, stat);

	if (stat & (RX_DMA_CTL_STAT_CHAN_FATAL |
		    RX_DMA_CTL_STAT_PORT_FATAL))
		err = -EINVAL;

	if (err) {
		dev_err(np->device, PFX "%s: RX channel %u error, stat[%llx]\n",
			np->dev->name, rp->rx_channel,
			(unsigned long long) stat);

		niu_log_rxchan_errors(np, rp, stat);
	}

	nw64(RX_DMA_CTL_STAT(rp->rx_channel),
	     stat & RX_DMA_CTL_WRITE_CLEAR_ERRS);

@@ -2749,13 +2753,16 @@ static int niu_device_error(struct niu *np)
	return -ENODEV;
}

static int niu_slowpath_interrupt(struct niu *np, struct niu_ldg *lp)
static int niu_slowpath_interrupt(struct niu *np, struct niu_ldg *lp,
			      u64 v0, u64 v1, u64 v2)
{
	u64 v0 = lp->v0;
	u64 v1 = lp->v1;
	u64 v2 = lp->v2;

	int i, err = 0;

	lp->v0 = v0;
	lp->v1 = v1;
	lp->v2 = v2;

	if (v1 & 0x00000000ffffffffULL) {
		u32 rx_vec = (v1 & 0xffffffff);

@@ -2764,8 +2771,13 @@ static int niu_slowpath_interrupt(struct niu *np, struct niu_ldg *lp)

			if (rx_vec & (1 << rp->rx_channel)) {
				int r = niu_rx_error(np, rp);
				if (r)
				if (r) {
					err = r;
				} else {
					if (!v0)
						nw64(RX_DMA_CTL_STAT(rp->rx_channel),
						     RX_DMA_CTL_STAT_MEX);
				}
			}
		}
	}
@@ -2803,7 +2815,7 @@ static int niu_slowpath_interrupt(struct niu *np, struct niu_ldg *lp)
	if (err)
		niu_enable_interrupts(np, 0);

	return -EINVAL;
	return err;
}

static void niu_rxchan_intr(struct niu *np, struct rx_ring_info *rp,
@@ -2905,7 +2917,7 @@ static irqreturn_t niu_interrupt(int irq, void *dev_id)
	}

	if (unlikely((v0 & ((u64)1 << LDN_MIF)) || v1 || v2)) {
		int err = niu_slowpath_interrupt(np, lp);
		int err = niu_slowpath_interrupt(np, lp, v0, v1, v2);
		if (err)
			goto out;
	}