I think I found the issue.

I diffed the macb driver in mainline 6.18.18 with the raspberry pi fork
and patched what was missing into the mainline. The network still hung.
Then I realised I was missing some parameters that the patched in code
referenced in the DT, so I added those in to my DT. A couple of hours
later my test node is still running. I may be being premature but it
usually hangs after around half an hour

The specific parameters are these for the DT ethernet node:
        cdns,ar2r-max-pipe = [08];
        cdns,aw2w-max-pipe = [08];
        cdns,use-aw2b-fill;

What follows is the entire patch - I'll keep the test node going and
report if it fails:

diff --git arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts 
arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
index 02a0eaff0..370e84bdf 100644
--- arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
+++ arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
@@ -164,6 +164,9 @@ &rp1_eth {
        status = "okay";
        phy-mode = "rgmii-id";
        phy-handle = <&phy1>;
+       cdns,ar2r-max-pipe = [08];
+       cdns,aw2w-max-pipe = [08];
+       cdns,use-aw2b-fill;
 
        mdio {
                reg = <0x1>;
@@ -173,8 +176,8 @@ mdio {
                #size-cells = <0>;
 
                phy1: ethernet-phy@1 {
-       /*              brcm,powerdown-enable;
-                       eee-broken-100tx;
+           brcm,powerdown-enable;
+                       /* eee-broken-100tx;
                        eee-broken-1000t;  */
                        reg = <0x1>;
                };
diff --git drivers/net/ethernet/cadence/macb.h 
drivers/net/ethernet/cadence/macb.h
index 0830c4897..2c814a2d0 100644
--- drivers/net/ethernet/cadence/macb.h
+++ drivers/net/ethernet/cadence/macb.h
@@ -86,6 +86,8 @@
 #define GEM_PBUFRXCUT          0x0044 /* RX Partial Store and Forward */
 #define GEM_JML                        0x0048 /* Jumbo Max Length */
 #define GEM_HS_MAC_CONFIG      0x0050 /* GEM high speed config */
+#define GEM_AMP                        0x0054 /* AXI Max Pipeline */
+#define GEM_INTMOD             0x005c /* Interrupt moderation */
 #define GEM_HRB                        0x0080 /* Hash Bottom */
 #define GEM_HRT                        0x0084 /* Hash Top */
 #define GEM_SA1B               0x0088 /* Specific1 Bottom */
@@ -360,6 +362,21 @@
 #define GEM_ADDR64_OFFSET      30 /* Address bus width - 64b or 32b */
 #define GEM_ADDR64_SIZE                1
 
+/* Bitfields in AMP */
+#define GEM_AR2R_MAX_PIPE_OFFSET       0  /* Maximum number of outstanding AXI 
read requests */
+#define GEM_AR2R_MAX_PIPE_SIZE         8
+#define GEM_AW2W_MAX_PIPE_OFFSET       8  /* Maximum number of outstanding AXI 
write requests */
+#define GEM_AW2W_MAX_PIPE_SIZE         8
+#define GEM_AW2B_FILL_OFFSET           16 /* Select wether the max AW2W 
transactions operates between: */
+#define GEM_AW2B_FILL_AW2W             0  /*   0: the AW to W AXI channel */
+#define GEM_AW2B_FILL_AW2B             1  /*   1: AW to B channel */
+#define GEM_AW2B_FILL_SIZE              1
+
+/* Bitfields in INTMOD */
+#define GEM_RX_MODERATION_OFFSET       0  /* RX interrupt moderation */
+#define GEM_RX_MODERATION_SIZE         8
+#define GEM_TX_MODERATION_OFFSET       16 /* TX interrupt moderation */
+#define GEM_TX_MODERATION_SIZE         8
 
 /* Bitfields in PBUFRXCUT */
 #define GEM_ENCUTTHRU_OFFSET   31 /* Enable RX partial store and forward */
@@ -843,6 +860,7 @@
        })
 
 #define MACB_READ_NSR(bp)      macb_readl(bp, NSR)
+#define MACB_READ_TSR(bp)      macb_readl(bp, TSR)
 
 /* struct macb_dma_desc - Hardware DMA descriptor
  * @addr: DMA address of data buffer
@@ -1260,6 +1278,7 @@ struct macb_queue {
        dma_addr_t              tx_ring_dma;
        struct work_struct      tx_error_task;
        bool                    txubr_pending;
+       bool                    tx_pending;
        struct napi_struct      napi_tx;
 
        dma_addr_t              rx_ring_dma;
@@ -1327,9 +1346,15 @@ struct macb {
 
        u32                     caps;
        unsigned int            dma_burst_length;
+       u8                      aw2w_max_pipe;
+       u8                      ar2r_max_pipe;
+       bool                    use_aw2b_fill;
 
        phy_interface_t         phy_interface;
 
+       struct gpio_desc        *phy_reset_gpio;
+       int                     phy_reset_ms;
+
        /* AT91RM9200 transmit queue (1 on wire + 1 queued) */
        struct macb_tx_skb      rm9200_txq[2];
        unsigned int            max_tx_length;
diff --git drivers/net/ethernet/cadence/macb_main.c 
drivers/net/ethernet/cadence/macb_main.c
index 90550055c..65d5ddf48 100644
--- drivers/net/ethernet/cadence/macb_main.c
+++ drivers/net/ethernet/cadence/macb_main.c
@@ -21,6 +21,7 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/dma-mapping.h>
+#include <linux/gpio/consumer.h>
 #include <linux/platform_device.h>
 #include <linux/phylink.h>
 #include <linux/of.h>
@@ -328,7 +329,7 @@ static int macb_mdio_wait_for_idle(struct macb *bp)
        u32 val;
 
        return readx_poll_timeout(MACB_READ_NSR, bp, val, val & MACB_BIT(IDLE),
-                                 1, MACB_MDIO_TIMEOUT);
+                                 100, MACB_MDIO_TIMEOUT);
 }
 
 static int macb_mdio_read_c22(struct mii_bus *bus, int mii_id, int regnum)
@@ -487,6 +488,19 @@ static int macb_mdio_write_c45(struct mii_bus *bus, int 
mii_id,
        return status;
 }
 
+static int macb_mdio_reset(struct mii_bus *bus)
+{
+       struct macb *bp = bus->priv;
+
+       if (bp->phy_reset_gpio) {
+               gpiod_set_value_cansleep(bp->phy_reset_gpio, 1);
+               msleep(bp->phy_reset_ms);
+               gpiod_set_value_cansleep(bp->phy_reset_gpio, 0);
+       }
+
+       return 0;
+}
+
 static void macb_init_buffers(struct macb *bp)
 {
        struct macb_queue *queue;
@@ -950,6 +964,7 @@ static int macb_mii_init(struct macb *bp)
        bp->mii_bus->write = &macb_mdio_write_c22;
        bp->mii_bus->read_c45 = &macb_mdio_read_c45;
        bp->mii_bus->write_c45 = &macb_mdio_write_c45;
+       bp->mii_bus->reset = &macb_mdio_reset;
        snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
                 bp->pdev->name, bp->pdev->id);
        bp->mii_bus->priv = bp;
@@ -1626,6 +1641,11 @@ static int macb_rx(struct macb_queue *queue, struct 
napi_struct *napi,
 
                macb_init_rx_ring(queue);
                queue_writel(queue, RBQP, queue->rx_ring_dma);
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+               if (bp->hw_dma_cap & HW_DMA_CAP_64B)
+                       macb_writel(bp, RBQPH,
+                                   upper_32_bits(queue->rx_ring_dma));
+#endif
 
                macb_writel(bp, NCR, ctrl | MACB_BIT(RE));
 
@@ -1928,8 +1948,9 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
                                queue_writel(queue, ISR, MACB_BIT(TCOMP) |
                                                         MACB_BIT(TXUBR));
 
-                       if (status & MACB_BIT(TXUBR)) {
+                       if (status & MACB_BIT(TXUBR) || queue->tx_pending) {
                                queue->txubr_pending = true;
+                               queue->tx_pending = 0;
                                wmb(); // ensure softirq can see update
                        }
 
@@ -2387,6 +2408,11 @@ static netdev_tx_t macb_start_xmit(struct sk_buff *skb, 
struct net_device *dev)
                             skb->len);
 
        spin_lock(&bp->lock);
+
+       /* TSTART write might get dropped, so make the IRQ retrigger a buffer 
read */
+       if (macb_readl(bp, TSR) & MACB_BIT(TGO))
+               queue->tx_pending = 1;
+
        macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART));
        spin_unlock(&bp->lock);
 
@@ -2810,6 +2836,37 @@ static void macb_configure_dma(struct macb *bp)
        }
 }
 
+static void gem_init_axi(struct macb *bp)
+{
+       u32 amp;
+
+       /* AXI pipeline setup - don't touch values unless specified in device
+        * tree. Some hardware could have reset values > 1.
+        */
+       amp = gem_readl(bp, AMP);
+
+       if (bp->use_aw2b_fill)
+               amp = GEM_BFINS(AW2B_FILL, bp->use_aw2b_fill, amp);
+       if (bp->aw2w_max_pipe)
+               amp = GEM_BFINS(AW2W_MAX_PIPE, bp->aw2w_max_pipe, amp);
+       if (bp->ar2r_max_pipe)
+               amp = GEM_BFINS(AR2R_MAX_PIPE, bp->ar2r_max_pipe, amp);
+
+       gem_writel(bp, AMP, amp);
+}
+
+static void gem_init_intmod(struct macb *bp)
+{
+       unsigned int throttle;
+       u32 intmod = 0;
+
+       /* Use sensible interrupt moderation thresholds (50us rx and tx) */
+       throttle = (1000 * 50) / 800;
+       intmod = GEM_BFINS(TX_MODERATION, throttle, intmod);
+       intmod = GEM_BFINS(RX_MODERATION, throttle, intmod);
+       gem_writel(bp, INTMOD, intmod);
+}
+
 static void macb_init_hw(struct macb *bp)
 {
        u32 config;
@@ -2838,6 +2895,11 @@ static void macb_init_hw(struct macb *bp)
        if (bp->caps & MACB_CAPS_JUMBO)
                bp->rx_frm_len_mask = MACB_RX_JFRMLEN_MASK;
 
+       if (macb_is_gem(bp)) {
+               gem_init_axi(bp);
+               gem_init_intmod(bp);
+       }
+
        macb_configure_dma(bp);
 
        /* Enable RX partial store and forward and set watermark */
@@ -3201,6 +3263,52 @@ static void gem_get_ethtool_strings(struct net_device 
*dev, u32 sset, u8 *p)
        }
 }
 
+static int gem_set_coalesce(struct net_device *dev,
+                           struct ethtool_coalesce *ec,
+                           struct kernel_ethtool_coalesce *kernel_coal,
+                           struct netlink_ext_ack *extack)
+{
+       struct macb *bp = netdev_priv(dev);
+       unsigned int tx_throttle;
+       unsigned int rx_throttle;
+       u32 intmod = 0;
+
+       /* GEM has simple IRQ throttling support. RX and TX interrupts
+        * are separately moderated on 800ns quantums, with no support
+        * for frame coalescing.
+        */
+
+       /* Max is 255 * 0.8us = 204us. Zero implies no moderation. */
+       if (ec->rx_coalesce_usecs > 204 || ec->tx_coalesce_usecs > 204)
+               return -EINVAL;
+
+       tx_throttle = (1000 * ec->tx_coalesce_usecs) / 800;
+       rx_throttle = (1000 * ec->rx_coalesce_usecs) / 800;
+
+       intmod = GEM_BFINS(TX_MODERATION, tx_throttle, intmod);
+       intmod = GEM_BFINS(RX_MODERATION, rx_throttle, intmod);
+
+       gem_writel(bp, INTMOD, intmod);
+
+       return 0;
+}
+
+static int gem_get_coalesce(struct net_device *dev,
+                           struct ethtool_coalesce *ec,
+                           struct kernel_ethtool_coalesce *kernel_coal,
+                           struct netlink_ext_ack *extack)
+{
+       struct macb *bp = netdev_priv(dev);
+       u32 intmod;
+
+       intmod = gem_readl(bp, INTMOD);
+
+       ec->tx_coalesce_usecs = (GEM_BFEXT(TX_MODERATION, intmod) * 800) / 1000;
+       ec->rx_coalesce_usecs = (GEM_BFEXT(RX_MODERATION, intmod) * 800) / 1000;
+
+       return 0;
+}
+
 static void macb_get_stats(struct net_device *dev,
                           struct rtnl_link_stats64 *nstat)
 {
@@ -3954,6 +4062,8 @@ static const struct ethtool_ops macb_ethtool_ops = {
 };
 
 static const struct ethtool_ops gem_ethtool_ops = {
+       .supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS |
+                                    ETHTOOL_COALESCE_TX_USECS,
        .get_regs_len           = macb_get_regs_len,
        .get_regs               = macb_get_regs,
        .get_wol                = macb_get_wol,
@@ -3967,6 +4077,8 @@ static const struct ethtool_ops gem_ethtool_ops = {
        .get_eth_mac_stats      = gem_get_eth_mac_stats,
        .get_eth_phy_stats      = gem_get_eth_phy_stats,
        .get_rmon_stats         = gem_get_rmon_stats,
+       .get_coalesce           = gem_get_coalesce,
+       .set_coalesce           = gem_set_coalesce,
        .get_link_ksettings     = macb_get_link_ksettings,
        .set_link_ksettings     = macb_set_link_ksettings,
        .get_ringparam          = macb_get_ringparam,
@@ -5533,6 +5645,11 @@ static int macb_probe(struct platform_device *pdev)
                        }
                }
        }
+
+       device_property_read_u8(&pdev->dev, "cdns,aw2w-max-pipe", 
&bp->aw2w_max_pipe);
+       device_property_read_u8(&pdev->dev, "cdns,ar2r-max-pipe", 
&bp->ar2r_max_pipe);
+       bp->use_aw2b_fill = device_property_read_bool(&pdev->dev, 
"cdns,use-aw2b-fill");
+
        spin_lock_init(&bp->lock);
        spin_lock_init(&bp->stats_lock);
 
@@ -5593,6 +5710,21 @@ static int macb_probe(struct platform_device *pdev)
        else
                bp->phy_interface = interface;
 
+       /* optional PHY reset-related properties */
+       bp->phy_reset_gpio = devm_gpiod_get_optional(&pdev->dev, "phy-reset",
+                                                    GPIOD_OUT_LOW);
+       if (IS_ERR(bp->phy_reset_gpio)) {
+               dev_err(&pdev->dev, "Failed to obtain phy-reset gpio\n");
+               err = PTR_ERR(bp->phy_reset_gpio);
+               goto err_out_free_netdev;
+       }
+
+       bp->phy_reset_ms = 10;
+       of_property_read_u32(np, "phy-reset-duration", &bp->phy_reset_ms);
+       /* A sane reset duration should not be longer than 1s */
+       if (bp->phy_reset_ms > 1000)
+               bp->phy_reset_ms = 1000;
+
        /* IP specific init */
        err = init(pdev);
        if (err)

-- 
You received this bug notification because you are a member of Ubuntu
Bugs, which is subscribed to Ubuntu.
https://bugs.launchpad.net/bugs/2133877

Title:
  Complete network hang on Raspberry Pi 5 with kernel 6.17 under load -
  possibly related to CPU frequency scaling

To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/linux-raspi/+bug/2133877/+subscriptions


-- 
ubuntu-bugs mailing list
[email protected]
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs

Reply via email to