| From b5bd95d17102b6719e3531d627875b9690371383 Mon Sep 17 00:00:00 2001 |
| From: Joakim Zhang <qiangqing.zhang@nxp.com> |
| Date: Mon, 6 Dec 2021 21:54:57 +0800 |
| Subject: net: fec: only clear interrupt of handling queue in fec_enet_rx_queue() |
| |
| From: Joakim Zhang <qiangqing.zhang@nxp.com> |
| |
| commit b5bd95d17102b6719e3531d627875b9690371383 upstream. |
| |
| Background: |
| We have a customer is running a Profinet stack on the 8MM which receives and |
| responds PNIO packets every 4ms and PNIO-CM packets every 40ms. However, from |
| time to time the received PNIO-CM package is "stock" and is only handled when |
| receiving a new PNIO-CM or DCERPC-Ping packet (tcpdump shows the PNIO-CM and |
| the DCERPC-Ping packet at the same time but the PNIO-CM HW timestamp is from |
| the expected 40 ms and not the 2s delay of the DCERPC-Ping). |
| |
| After debugging, we noticed PNIO, PNIO-CM and DCERPC-Ping packets would |
| be handled by different RX queues. |
| |
| The root cause should be driver ack all queues' interrupt when handle a |
| specific queue in fec_enet_rx_queue(). The blamed patch is introduced to |
| receive as much packets as possible once to avoid interrupt flooding. |
| But it's unreasonable to clear other queues'interrupt when handling one |
| queue, this patch tries to fix it. |
| |
| Fixes: ed63f1dcd578 (net: fec: clear receive interrupts before processing a packet) |
| Cc: Russell King <rmk+kernel@arm.linux.org.uk> |
| Reported-by: Nicolas Diaz <nicolas.diaz@nxp.com> |
| Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com> |
| Link: https://lore.kernel.org/r/20211206135457.15946-1-qiangqing.zhang@nxp.com |
| Signed-off-by: Jakub Kicinski <kuba@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/net/ethernet/freescale/fec.h | 3 +++ |
| drivers/net/ethernet/freescale/fec_main.c | 2 +- |
| 2 files changed, 4 insertions(+), 1 deletion(-) |
| |
| --- a/drivers/net/ethernet/freescale/fec.h |
| +++ b/drivers/net/ethernet/freescale/fec.h |
| @@ -360,6 +360,9 @@ struct bufdesc_ex { |
| #define FEC_ENET_WAKEUP ((uint)0x00020000) /* Wakeup request */ |
| #define FEC_ENET_TXF (FEC_ENET_TXF_0 | FEC_ENET_TXF_1 | FEC_ENET_TXF_2) |
| #define FEC_ENET_RXF (FEC_ENET_RXF_0 | FEC_ENET_RXF_1 | FEC_ENET_RXF_2) |
| +#define FEC_ENET_RXF_GET(X) (((X) == 0) ? FEC_ENET_RXF_0 : \ |
| + (((X) == 1) ? FEC_ENET_RXF_1 : \ |
| + FEC_ENET_RXF_2)) |
| #define FEC_ENET_TS_AVAIL ((uint)0x00010000) |
| #define FEC_ENET_TS_TIMER ((uint)0x00008000) |
| |
| --- a/drivers/net/ethernet/freescale/fec_main.c |
| +++ b/drivers/net/ethernet/freescale/fec_main.c |
| @@ -1407,7 +1407,7 @@ fec_enet_rx_queue(struct net_device *nde |
| if ((status & BD_ENET_RX_LAST) == 0) |
| netdev_err(ndev, "rcv is not +last\n"); |
| |
| - writel(FEC_ENET_RXF, fep->hwp + FEC_IEVENT); |
| + writel(FEC_ENET_RXF_GET(queue_id), fep->hwp + FEC_IEVENT); |
| |
| /* Check for errors. */ |
| if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO | |