From: Alexander Sverdlin The FEC/ENET controller can flush frames stuck at the head of the RX FIFO when their destination ring has no empty buffer descriptor, instead of letting them block the FIFO. This is controlled per RX queue through the RX_FLUSHn bits of the QOS Scheme register (FEC_QOS_SCHEME). Parse the new fsl,rx-flush-queues property, build the RX flush mask and program it in fec_enet_enable_ring(). Erratum ERR050395 (e.g. i.MX8QXP) can cause an RX path lock-up when flushing is enabled on more than one queue at a time. Rather than encoding that limitation in the binding, enforce it in the driver: reject a configuration that enables flushing on multiple queues unless the controller advertises FEC_QUIRK_HAS_MULTI_RX_FLUSH, which future parts with the erratum fixed can set. Signed-off-by: Alexander Sverdlin --- drivers/net/ethernet/freescale/fec.h | 14 ++++++++++ drivers/net/ethernet/freescale/fec_main.c | 34 +++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index 7176803146f3d..4af3ae286895f 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h @@ -186,6 +186,7 @@ #define FEC_RCMR_2 0xfff #define FEC_DMA_CFG_1 0xfff #define FEC_DMA_CFG_2 0xfff +#define FEC_QOS_SCHEME 0xfff #define FEC_TXIC0 0xfff #define FEC_TXIC1 0xfff #define FEC_TXIC2 0xfff @@ -322,6 +323,10 @@ struct bufdesc_ex { #define RCMR_CMP(X) (((X) == 1) ? RCMR_CMP_1 : RCMR_CMP_2) #define FEC_TX_BD_FTYPE(X) (((X) & 0xf) << 20) +/* FEC_QOS_SCHEME bits */ +#define QOS_RX_FLUSH(X) (1 << (3 + (X))) /* RX_FLUSHn, n = 0, 1, 2 */ +#define QOS_RX_FLUSH_MASK (QOS_RX_FLUSH(0) | QOS_RX_FLUSH(1) | QOS_RX_FLUSH(2)) + /* The number of Tx and Rx buffers. These are allocated from the page * pool. The code may assume these are power of two, so it is best * to keep them that size. @@ -499,6 +504,12 @@ struct bufdesc_ex { /* Jumbo Frame support */ #define FEC_QUIRK_JUMBO_FRAME BIT(25) +/* Receive flushing (QOS Scheme register RX_FLUSHn) may be enabled on more than + * one RX queue at a time. Parts without this quirk are subject to erratum + * ERR050395 and must limit RX flushing to a single queue. + */ +#define FEC_QUIRK_HAS_MULTI_RX_FLUSH BIT(24) + struct bufdesc_prop { int qid; /* Address of Rx and Tx buffers */ @@ -604,6 +615,9 @@ struct fec_enet_private { unsigned int num_tx_queues; unsigned int num_rx_queues; + /* Bitmask of RX queues with receive flushing enabled */ + u32 rx_flush_mask; + struct fec_enet_priv_tx_q *tx_queue[FEC_ENET_MAX_TX_QS]; struct fec_enet_priv_rx_q *rx_queue[FEC_ENET_MAX_RX_QS]; diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index ced4dbf8cd90f..a4fe8423630b5 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -1090,6 +1090,15 @@ static void fec_enet_enable_ring(struct net_device *ndev) fep->hwp + FEC_RCMR(i)); } + /* Enable receive flushing for the selected queues */ + if (fep->rx_flush_mask) { + u32 val = readl(fep->hwp + FEC_QOS_SCHEME); + + val &= ~QOS_RX_FLUSH_MASK; + val |= fep->rx_flush_mask; + writel(val, fep->hwp + FEC_QOS_SCHEME); + } + for (i = 0; i < fep->num_tx_queues; i++) { txq = fep->tx_queue[i]; writel(txq->bd.dma, fep->hwp + FEC_X_DES_START(i)); @@ -5239,6 +5248,31 @@ fec_probe(struct platform_device *pdev) fep->num_rx_queues = num_rx_qs; fep->num_tx_queues = num_tx_qs; + /* Enable receive flushing on the requested queues. Erratum ERR050395 + * restricts flushing to a single queue; only accept more than one queue + * on controllers known to have the erratum fixed. + */ + for (i = 0; i < of_property_count_u32_elems(np, "fsl,rx-flush-queues"); i++) { + u32 q; + + if (of_property_read_u32_index(np, "fsl,rx-flush-queues", i, &q)) + break; + if (q >= num_rx_qs) { + dev_warn(&pdev->dev, + "fsl,rx-flush-queues: queue %u exceeds num-rx-queues, ignoring\n", + q); + continue; + } + fep->rx_flush_mask |= QOS_RX_FLUSH(q); + } + if (hweight32(fep->rx_flush_mask) > 1 && + !(fep->quirks & FEC_QUIRK_HAS_MULTI_RX_FLUSH)) { + dev_err(&pdev->dev, + "fsl,rx-flush-queues: RX flush on multiple queues not supported\n"); + ret = -EINVAL; + goto failed_ioremap; + } + /* default enable pause frame auto negotiation */ if (fep->quirks & FEC_QUIRK_HAS_GBIT) fep->pause_flag |= FEC_PAUSE_FLAG_AUTONEG; -- 2.55.0