mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-25 16:31:13 +00:00
70e81efe93
These patches have partial acceptance upstream and are still a WIP, now there is merge window for kernel v6.10 so these will not be reposted until that is over. In the meantime, let's add the current state to OpenWrt so the ethernet on Gemini is up and working (tested on several devices). Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
74 lines
2.5 KiB
Diff
74 lines
2.5 KiB
Diff
From 81889eb2b37bc21df4ff259441e8fc12d4f27cd9 Mon Sep 17 00:00:00 2001
|
|
From: Linus Walleij <linus.walleij@linaro.org>
|
|
Date: Thu, 9 May 2024 08:48:31 +0200
|
|
Subject: [PATCH] net: ethernet: cortina: Locking fixes
|
|
|
|
This fixes a probably long standing problem in the Cortina
|
|
Gemini ethernet driver: there are some paths in the code
|
|
where the IRQ registers are written without taking the proper
|
|
locks.
|
|
|
|
Fixes: 4d5ae32f5e1e ("net: ethernet: Add a driver for Gemini gigabit ethernet")
|
|
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
|
|
---
|
|
drivers/net/ethernet/cortina/gemini.c | 12 ++++++++++--
|
|
1 file changed, 10 insertions(+), 2 deletions(-)
|
|
|
|
--- a/drivers/net/ethernet/cortina/gemini.c
|
|
+++ b/drivers/net/ethernet/cortina/gemini.c
|
|
@@ -1107,10 +1107,13 @@ static void gmac_tx_irq_enable(struct ne
|
|
{
|
|
struct gemini_ethernet_port *port = netdev_priv(netdev);
|
|
struct gemini_ethernet *geth = port->geth;
|
|
+ unsigned long flags;
|
|
u32 val, mask;
|
|
|
|
netdev_dbg(netdev, "%s device %d\n", __func__, netdev->dev_id);
|
|
|
|
+ spin_lock_irqsave(&geth->irq_lock, flags);
|
|
+
|
|
mask = GMAC0_IRQ0_TXQ0_INTS << (6 * netdev->dev_id + txq);
|
|
|
|
if (en)
|
|
@@ -1119,6 +1122,8 @@ static void gmac_tx_irq_enable(struct ne
|
|
val = readl(geth->base + GLOBAL_INTERRUPT_ENABLE_0_REG);
|
|
val = en ? val | mask : val & ~mask;
|
|
writel(val, geth->base + GLOBAL_INTERRUPT_ENABLE_0_REG);
|
|
+
|
|
+ spin_unlock_irqrestore(&geth->irq_lock, flags);
|
|
}
|
|
|
|
static void gmac_tx_irq(struct net_device *netdev, unsigned int txq_num)
|
|
@@ -1415,15 +1420,19 @@ static unsigned int gmac_rx(struct net_d
|
|
union gmac_rxdesc_3 word3;
|
|
struct page *page = NULL;
|
|
unsigned int page_offs;
|
|
+ unsigned long flags;
|
|
unsigned short r, w;
|
|
union dma_rwptr rw;
|
|
dma_addr_t mapping;
|
|
int frag_nr = 0;
|
|
|
|
+ spin_lock_irqsave(&geth->irq_lock, flags);
|
|
rw.bits32 = readl(ptr_reg);
|
|
/* Reset interrupt as all packages until here are taken into account */
|
|
writel(DEFAULT_Q0_INT_BIT << netdev->dev_id,
|
|
geth->base + GLOBAL_INTERRUPT_STATUS_1_REG);
|
|
+ spin_unlock_irqrestore(&geth->irq_lock, flags);
|
|
+
|
|
r = rw.bits.rptr;
|
|
w = rw.bits.wptr;
|
|
|
|
@@ -1726,10 +1735,9 @@ static irqreturn_t gmac_irq(int irq, voi
|
|
gmac_update_hw_stats(netdev);
|
|
|
|
if (val & (GMAC0_RX_OVERRUN_INT_BIT << (netdev->dev_id * 8))) {
|
|
+ spin_lock(&geth->irq_lock);
|
|
writel(GMAC0_RXDERR_INT_BIT << (netdev->dev_id * 8),
|
|
geth->base + GLOBAL_INTERRUPT_STATUS_4_REG);
|
|
-
|
|
- spin_lock(&geth->irq_lock);
|
|
u64_stats_update_begin(&port->ir_stats_syncp);
|
|
++port->stats.rx_fifo_errors;
|
|
u64_stats_update_end(&port->ir_stats_syncp);
|