net: dsa: bcm_sf2: add function finding RGMII register
authorRafał Miłecki <rafal@milecki.pl>
Thu, 18 Mar 2021 08:01:42 +0000 (09:01 +0100)
committerDavid S. Miller <davem@davemloft.net>
Thu, 18 Mar 2021 21:44:05 +0000 (14:44 -0700)
Simple macro like REG_RGMII_CNTRL_P() is insufficient as:
1. It doesn't validate port argument
2. It doesn't support chipsets with non-lineral RGMII regs layout

Missing port validation could result in getting register offset from out
of array. Random memory -> random offset -> random reads/writes. It
affected e.g. BCM4908 for REG_RGMII_CNTRL_P(7).

Fixes: a78e86ed586d ("net: dsa: bcm_sf2: Prepare for different register layouts")
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
Acked-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/dsa/bcm_sf2.c
drivers/net/dsa/bcm_sf2_regs.h

index d8e6dd371468c4069ca1094bf057e7a60972519a..044972b7d1189d8aef40bac840f888939494e799 100644 (file)
 #include "b53/b53_priv.h"
 #include "b53/b53_regs.h"
 
+static u16 bcm_sf2_reg_rgmii_cntrl(struct bcm_sf2_priv *priv, int port)
+{
+       switch (priv->type) {
+       case BCM4908_DEVICE_ID:
+               /* TODO */
+               break;
+       default:
+               switch (port) {
+               case 0:
+                       return REG_RGMII_0_CNTRL;
+               case 1:
+                       return REG_RGMII_1_CNTRL;
+               case 2:
+                       return REG_RGMII_2_CNTRL;
+               default:
+                       break;
+               }
+       }
+
+       WARN_ONCE(1, "Unsupported port %d\n", port);
+
+       /* RO fallback reg */
+       return REG_SWITCH_STATUS;
+}
+
 /* Return the number of active ports, not counting the IMP (CPU) port */
 static unsigned int bcm_sf2_num_active_ports(struct dsa_switch *ds)
 {
@@ -688,6 +713,7 @@ static void bcm_sf2_sw_mac_config(struct dsa_switch *ds, int port,
 {
        struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
        u32 id_mode_dis = 0, port_mode;
+       u32 reg_rgmii_ctrl;
        u32 reg;
 
        if (port == core_readl(priv, CORE_IMP0_PRT_ID))
@@ -711,10 +737,12 @@ static void bcm_sf2_sw_mac_config(struct dsa_switch *ds, int port,
                return;
        }
 
+       reg_rgmii_ctrl = bcm_sf2_reg_rgmii_cntrl(priv, port);
+
        /* Clear id_mode_dis bit, and the existing port mode, let
         * RGMII_MODE_EN bet set by mac_link_{up,down}
         */
-       reg = reg_readl(priv, REG_RGMII_CNTRL_P(port));
+       reg = reg_readl(priv, reg_rgmii_ctrl);
        reg &= ~ID_MODE_DIS;
        reg &= ~(PORT_MODE_MASK << PORT_MODE_SHIFT);
 
@@ -722,13 +750,14 @@ static void bcm_sf2_sw_mac_config(struct dsa_switch *ds, int port,
        if (id_mode_dis)
                reg |= ID_MODE_DIS;
 
-       reg_writel(priv, reg, REG_RGMII_CNTRL_P(port));
+       reg_writel(priv, reg, reg_rgmii_ctrl);
 }
 
 static void bcm_sf2_sw_mac_link_set(struct dsa_switch *ds, int port,
                                    phy_interface_t interface, bool link)
 {
        struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
+       u32 reg_rgmii_ctrl;
        u32 reg;
 
        if (!phy_interface_mode_is_rgmii(interface) &&
@@ -736,13 +765,15 @@ static void bcm_sf2_sw_mac_link_set(struct dsa_switch *ds, int port,
            interface != PHY_INTERFACE_MODE_REVMII)
                return;
 
+       reg_rgmii_ctrl = bcm_sf2_reg_rgmii_cntrl(priv, port);
+
        /* If the link is down, just disable the interface to conserve power */
-       reg = reg_readl(priv, REG_RGMII_CNTRL_P(port));
+       reg = reg_readl(priv, reg_rgmii_ctrl);
        if (link)
                reg |= RGMII_MODE_EN;
        else
                reg &= ~RGMII_MODE_EN;
-       reg_writel(priv, reg, REG_RGMII_CNTRL_P(port));
+       reg_writel(priv, reg, reg_rgmii_ctrl);
 }
 
 static void bcm_sf2_sw_mac_link_down(struct dsa_switch *ds, int port,
@@ -776,11 +807,15 @@ static void bcm_sf2_sw_mac_link_up(struct dsa_switch *ds, int port,
 {
        struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
        struct ethtool_eee *p = &priv->dev->ports[port].eee;
-       u32 reg, offset;
 
        bcm_sf2_sw_mac_link_set(ds, port, interface, true);
 
        if (port != core_readl(priv, CORE_IMP0_PRT_ID)) {
+               u32 reg_rgmii_ctrl;
+               u32 reg, offset;
+
+               reg_rgmii_ctrl = bcm_sf2_reg_rgmii_cntrl(priv, port);
+
                if (priv->type == BCM4908_DEVICE_ID ||
                    priv->type == BCM7445_DEVICE_ID)
                        offset = CORE_STS_OVERRIDE_GMIIP_PORT(port);
@@ -791,7 +826,7 @@ static void bcm_sf2_sw_mac_link_up(struct dsa_switch *ds, int port,
                    interface == PHY_INTERFACE_MODE_RGMII_TXID ||
                    interface == PHY_INTERFACE_MODE_MII ||
                    interface == PHY_INTERFACE_MODE_REVMII) {
-                       reg = reg_readl(priv, REG_RGMII_CNTRL_P(port));
+                       reg = reg_readl(priv, reg_rgmii_ctrl);
                        reg &= ~(RX_PAUSE_EN | TX_PAUSE_EN);
 
                        if (tx_pause)
@@ -799,7 +834,7 @@ static void bcm_sf2_sw_mac_link_up(struct dsa_switch *ds, int port,
                        if (rx_pause)
                                reg |= RX_PAUSE_EN;
 
-                       reg_writel(priv, reg, REG_RGMII_CNTRL_P(port));
+                       reg_writel(priv, reg, reg_rgmii_ctrl);
                }
 
                reg = SW_OVERRIDE | LINK_STS;
index e297b09411f37bdbcb1a6d86f6f28fc59419faaa..3d5515fe43cb633f4336b88da213595058ab78aa 100644 (file)
@@ -55,8 +55,6 @@ enum bcm_sf2_reg_offs {
 #define CROSSBAR_BCM4908_EXT_GPHY4     1
 #define CROSSBAR_BCM4908_EXT_RGMII     2
 
-#define REG_RGMII_CNTRL_P(x)           (REG_RGMII_0_CNTRL + (x))
-
 /* Relative to REG_RGMII_CNTRL */
 #define  RGMII_MODE_EN                 (1 << 0)
 #define  ID_MODE_DIS                   (1 << 1)