From: Markus Stockhausen Date: Fri, 6 Feb 2026 07:43:47 +0000 (+0100) Subject: realtek: eth: introduce global interrupt helpers X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7f67ec0b34a93e2c47be3c653d82e67a0f336180;p=thirdparty%2Fopenwrt.git realtek: eth: introduce global interrupt helpers Global interrupt enabling/disabling is scattered around the code. Provide two helpers to handle this code centrally. Make use of them where needed. This refactoring brings multiple enhancements: 1. Only activate the rx interrupts and ignore the run out (aka rx overflow) interrupts. Overflow was used to spit out log messages to identify driver issues. Nowadays it is stable enough and these messages are not needed any longer. 2. With generic register setting some family checks can be dropped. 3. Last but not least this commit fixes a bug in the probing of the ethernet driver. In rare case (especially during TFTP boot) U-Boot loader leaves a pending rx interrupt that instantly fires when the driver registers its interrupt via devm_request_irq(). To mitigate this, reorder the interrupt disabling from ndo_open() to driver probing. Signed-off-by: Markus Stockhausen Link: https://github.com/openwrt/openwrt/pull/21893 Signed-off-by: Hauke Mehrtens --- diff --git a/target/linux/realtek/files-6.12/drivers/net/ethernet/rtl838x_eth.c b/target/linux/realtek/files-6.12/drivers/net/ethernet/rtl838x_eth.c index 9cd1d259b7c..4aa44fdc554 100644 --- a/target/linux/realtek/files-6.12/drivers/net/ethernet/rtl838x_eth.c +++ b/target/linux/realtek/files-6.12/drivers/net/ethernet/rtl838x_eth.c @@ -199,6 +199,40 @@ struct rteth_ctrl { struct rteth_tx *tx_data; }; +static void rteth_disable_all_irqs(struct rteth_ctrl *ctrl) +{ + int registers = ((ctrl->r->rx_rings * 2 + 7) / 32) + 1; + + for (int reg = 0; reg < registers; reg++) { + sw_w32(0, ctrl->r->dma_if_intr_msk + reg * 4); + sw_w32(GENMASK(31, 0), ctrl->r->dma_if_intr_sts + reg * 4); + } +} + +static void rteth_enable_all_rx_irqs(struct rteth_ctrl *ctrl) +{ + int mask, shift, reg; + + /* + * The hardware has several types of interrupts. Basically for rx/tx completion and + * if hardware queues run out. For now the driver only needs notification about new + * incoming packets. Leave everything else disabled. + */ + mask = GENMASK(ctrl->r->rx_rings - 1, 0); + shift = ctrl->r->rx_rings % 32; + reg = ctrl->r->rx_rings / 32; + sw_w32_mask(0, mask << shift, ctrl->r->dma_if_intr_msk + reg * 4); + + /* + * RTL839x has additional L2 notification interrupts. Simply activate them. All other + * devices that do not have the feature have adequate reserved bit space and ignore it. + */ + mask = GENMASK(2, 0); + shift = (ctrl->r->rx_rings * 2 + 4) % 32; + reg = (ctrl->r->rx_rings * 2 + 4) / 32; + sw_w32_mask(0, mask << shift, ctrl->r->dma_if_intr_msk + reg * 4); +} + /* On the RTL93XX, the RTL93XX_DMA_IF_RX_RING_CNTR track the fill level of * the rings. Writing x into these registers substracts x from its content. * When the content reaches the ring size, the ASIC no longer adds @@ -455,10 +489,6 @@ static void rteth_nic_reset(struct rteth_ctrl *ctrl, int reset_mask) static void rteth_838x_hw_reset(struct rteth_ctrl *ctrl) { - /* Disable and clear interrupts */ - sw_w32(0x00000000, ctrl->r->dma_if_intr_msk); - sw_w32(0xffffffff, ctrl->r->dma_if_intr_sts); - rteth_nic_reset(ctrl, 0xc); /* Free floating rings without space tracking */ @@ -469,10 +499,6 @@ static void rteth_839x_hw_reset(struct rteth_ctrl *ctrl) { u32 int_saved, nbuf; - /* Disable and clear interrupts */ - sw_w32(0x00000000, ctrl->r->dma_if_intr_msk); - sw_w32(0xffffffff, ctrl->r->dma_if_intr_sts); - /* Preserve L2 notification and NBUF settings */ int_saved = sw_r32(ctrl->r->dma_if_intr_msk); nbuf = sw_r32(RTL839X_DMA_IF_NBUF_BASE_DESC_ADDR_CTRL); @@ -499,14 +525,6 @@ static void rteth_839x_hw_reset(struct rteth_ctrl *ctrl) static void rteth_93xx_hw_reset(struct rteth_ctrl *ctrl) { - /* Disable and clear interrupts */ - sw_w32(0x00000000, ctrl->r->dma_if_intr_msk); - sw_w32(0xffffffff, ctrl->r->dma_if_intr_sts); - sw_w32(0x00000000, ctrl->r->dma_if_intr_rx_done_msk); - sw_w32(0xffffffff, ctrl->r->dma_if_intr_rx_done_sts); - sw_w32(0x00000000, ctrl->r->dma_if_intr_tx_done_msk); - sw_w32(0x0000000f, ctrl->r->dma_if_intr_tx_done_sts); - rteth_nic_reset(ctrl, 0x6); /* Setup Head of Line */ @@ -580,8 +598,7 @@ static void rtl838x_hw_en_rxtx(struct rteth_ctrl *ctrl) /* Truncate RX buffer to DEFAULT_MTU bytes, pad TX */ sw_w32((DEFAULT_MTU << 16) | RX_TRUNCATE_EN_83XX | TX_PAD_EN_838X, ctrl->r->dma_if_ctrl); - /* Enable RX done and RX overflow, TX done interrupts not needed */ - sw_w32(0xffff, ctrl->r->dma_if_intr_msk); + rteth_enable_all_rx_irqs(ctrl); /* Enable DMA, engine expects empty FCS field */ sw_w32_mask(0, RX_EN | TX_EN, ctrl->r->dma_if_ctrl); @@ -604,8 +621,7 @@ static void rtl839x_hw_en_rxtx(struct rteth_ctrl *ctrl) /* Setup CPU-Port: RX Buffer */ sw_w32((DEFAULT_MTU << 5) | RX_TRUNCATE_EN_83XX, ctrl->r->dma_if_ctrl); - /* Enable Notify, RX done and RX overflow, TX done interrupts not needed */ - sw_w32(0x0070ffff, ctrl->r->dma_if_intr_msk); /* Notify IRQ! */ + rteth_enable_all_rx_irqs(ctrl); /* Enable DMA */ sw_w32_mask(0, RX_EN | TX_EN, ctrl->r->dma_if_ctrl); @@ -640,10 +656,7 @@ static void rtl93xx_hw_en_rxtx(struct rteth_ctrl *ctrl) sw_w32_mask(0x3ff << pos, v, ctrl->r->dma_if_rx_ring_cntr(i)); } - /* Enable Notify, RX done and RX overflow, TX done interrupts not needed */ - sw_w32(0xffffffff, ctrl->r->dma_if_intr_msk); - sw_w32(0xffffffff, ctrl->r->dma_if_intr_rx_done_msk); - sw_w32(0x00000000, ctrl->r->dma_if_intr_tx_done_msk); + rteth_enable_all_rx_irqs(ctrl); /* Enable DMA */ sw_w32_mask(0, RX_EN_93XX | TX_EN_93XX, ctrl->r->dma_if_ctrl); @@ -789,7 +802,6 @@ static int rteth_open(struct net_device *ndev) static void rtl838x_hw_stop(struct rteth_ctrl *ctrl) { u32 force_mac = ctrl->r->family_id == RTL8380_FAMILY_ID ? 0x6192C : 0x75; - u32 clear_irq = ctrl->r->family_id == RTL8380_FAMILY_ID ? 0x000fffff : 0x007fffff; /* Disable RX/TX from/to CPU-port */ sw_w32_mask(0x3, 0, ctrl->r->mac_l2_port_ctrl); @@ -833,18 +845,7 @@ static void rtl838x_hw_stop(struct rteth_ctrl *ctrl) sw_w32_mask(BIT(0) | BIT(9), 0, ctrl->r->mac_force_mode_ctrl + ctrl->r->cpu_port * 4); mdelay(100); - /* Disable all TX/RX interrupts */ - if (ctrl->r->family_id == RTL9300_FAMILY_ID || ctrl->r->family_id == RTL9310_FAMILY_ID) { - sw_w32(0x00000000, ctrl->r->dma_if_intr_msk); - sw_w32(0xffffffff, ctrl->r->dma_if_intr_sts); - sw_w32(0x00000000, ctrl->r->dma_if_intr_rx_done_msk); - sw_w32(0xffffffff, ctrl->r->dma_if_intr_rx_done_sts); - sw_w32(0x00000000, ctrl->r->dma_if_intr_tx_done_msk); - sw_w32(0x0000000f, ctrl->r->dma_if_intr_tx_done_sts); - } else { - sw_w32(0x00000000, ctrl->r->dma_if_intr_msk); - sw_w32(clear_irq, ctrl->r->dma_if_intr_sts); - } + rteth_disable_all_irqs(ctrl); /* Disable TX/RX DMA */ sw_w32(0x00000000, ctrl->r->dma_if_ctrl); @@ -1702,6 +1703,7 @@ static int rtl838x_eth_probe(struct platform_device *pdev) if (dev->irq < 0) return -ENODEV; + rteth_disable_all_irqs(ctrl); err = devm_request_irq(&pdev->dev, dev->irq, ctrl->r->net_irq, IRQF_SHARED, dev->name, dev); if (err) {