132a734ac4ef63e95da0a7d8d88bf5ca2297fdd6
[openwrt/openwrt.git] /
1 From 55cfeb396965c3906a84d09a9c487d065e37773b Mon Sep 17 00:00:00 2001
2 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
3 Date: Thu, 18 Mar 2021 09:01:42 +0100
4 Subject: [PATCH 1/2] net: dsa: bcm_sf2: add function finding RGMII register
5 MIME-Version: 1.0
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
8
9 Simple macro like REG_RGMII_CNTRL_P() is insufficient as:
10 1. It doesn't validate port argument
11 2. It doesn't support chipsets with non-lineral RGMII regs layout
12
13 Missing port validation could result in getting register offset from out
14 of array. Random memory -> random offset -> random reads/writes. It
15 affected e.g. BCM4908 for REG_RGMII_CNTRL_P(7).
16
17 Fixes: a78e86ed586d ("net: dsa: bcm_sf2: Prepare for different register layouts")
18 Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
19 Acked-by: Florian Fainelli <f.fainelli@gmail.com>
20 Signed-off-by: David S. Miller <davem@davemloft.net>
21 ---
22 drivers/net/dsa/bcm_sf2.c | 49 +++++++++++++++++++++++++++++-----
23 drivers/net/dsa/bcm_sf2_regs.h | 2 --
24 2 files changed, 42 insertions(+), 9 deletions(-)
25
26 --- a/drivers/net/dsa/bcm_sf2.c
27 +++ b/drivers/net/dsa/bcm_sf2.c
28 @@ -75,6 +75,31 @@ static void bcm_sf2_recalc_clock(struct
29 clk_set_rate(priv->clk_mdiv, new_rate);
30 }
31
32 +static u16 bcm_sf2_reg_rgmii_cntrl(struct bcm_sf2_priv *priv, int port)
33 +{
34 + switch (priv->type) {
35 + case BCM4908_DEVICE_ID:
36 + /* TODO */
37 + break;
38 + default:
39 + switch (port) {
40 + case 0:
41 + return REG_RGMII_0_CNTRL;
42 + case 1:
43 + return REG_RGMII_1_CNTRL;
44 + case 2:
45 + return REG_RGMII_2_CNTRL;
46 + default:
47 + break;
48 + }
49 + }
50 +
51 + WARN_ONCE(1, "Unsupported port %d\n", port);
52 +
53 + /* RO fallback reg */
54 + return REG_SWITCH_STATUS;
55 +}
56 +
57 static void bcm_sf2_imp_setup(struct dsa_switch *ds, int port)
58 {
59 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
60 @@ -696,6 +721,7 @@ static void bcm_sf2_sw_mac_config(struct
61 {
62 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
63 u32 id_mode_dis = 0, port_mode;
64 + u32 reg_rgmii_ctrl;
65 u32 reg;
66
67 if (port == core_readl(priv, CORE_IMP0_PRT_ID))
68 @@ -719,10 +745,12 @@ static void bcm_sf2_sw_mac_config(struct
69 return;
70 }
71
72 + reg_rgmii_ctrl = bcm_sf2_reg_rgmii_cntrl(priv, port);
73 +
74 /* Clear id_mode_dis bit, and the existing port mode, let
75 * RGMII_MODE_EN bet set by mac_link_{up,down}
76 */
77 - reg = reg_readl(priv, REG_RGMII_CNTRL_P(port));
78 + reg = reg_readl(priv, reg_rgmii_ctrl);
79 reg &= ~ID_MODE_DIS;
80 reg &= ~(PORT_MODE_MASK << PORT_MODE_SHIFT);
81
82 @@ -730,13 +758,14 @@ static void bcm_sf2_sw_mac_config(struct
83 if (id_mode_dis)
84 reg |= ID_MODE_DIS;
85
86 - reg_writel(priv, reg, REG_RGMII_CNTRL_P(port));
87 + reg_writel(priv, reg, reg_rgmii_ctrl);
88 }
89
90 static void bcm_sf2_sw_mac_link_set(struct dsa_switch *ds, int port,
91 phy_interface_t interface, bool link)
92 {
93 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
94 + u32 reg_rgmii_ctrl;
95 u32 reg;
96
97 if (!phy_interface_mode_is_rgmii(interface) &&
98 @@ -744,13 +773,15 @@ static void bcm_sf2_sw_mac_link_set(stru
99 interface != PHY_INTERFACE_MODE_REVMII)
100 return;
101
102 + reg_rgmii_ctrl = bcm_sf2_reg_rgmii_cntrl(priv, port);
103 +
104 /* If the link is down, just disable the interface to conserve power */
105 - reg = reg_readl(priv, REG_RGMII_CNTRL_P(port));
106 + reg = reg_readl(priv, reg_rgmii_ctrl);
107 if (link)
108 reg |= RGMII_MODE_EN;
109 else
110 reg &= ~RGMII_MODE_EN;
111 - reg_writel(priv, reg, REG_RGMII_CNTRL_P(port));
112 + reg_writel(priv, reg, reg_rgmii_ctrl);
113 }
114
115 static void bcm_sf2_sw_mac_link_down(struct dsa_switch *ds, int port,
116 @@ -784,11 +815,15 @@ static void bcm_sf2_sw_mac_link_up(struc
117 {
118 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
119 struct ethtool_eee *p = &priv->dev->ports[port].eee;
120 - u32 reg, offset;
121
122 bcm_sf2_sw_mac_link_set(ds, port, interface, true);
123
124 if (port != core_readl(priv, CORE_IMP0_PRT_ID)) {
125 + u32 reg_rgmii_ctrl;
126 + u32 reg, offset;
127 +
128 + reg_rgmii_ctrl = bcm_sf2_reg_rgmii_cntrl(priv, port);
129 +
130 if (priv->type == BCM4908_DEVICE_ID ||
131 priv->type == BCM7445_DEVICE_ID)
132 offset = CORE_STS_OVERRIDE_GMIIP_PORT(port);
133 @@ -799,7 +834,7 @@ static void bcm_sf2_sw_mac_link_up(struc
134 interface == PHY_INTERFACE_MODE_RGMII_TXID ||
135 interface == PHY_INTERFACE_MODE_MII ||
136 interface == PHY_INTERFACE_MODE_REVMII) {
137 - reg = reg_readl(priv, REG_RGMII_CNTRL_P(port));
138 + reg = reg_readl(priv, reg_rgmii_ctrl);
139 reg &= ~(RX_PAUSE_EN | TX_PAUSE_EN);
140
141 if (tx_pause)
142 @@ -807,7 +842,7 @@ static void bcm_sf2_sw_mac_link_up(struc
143 if (rx_pause)
144 reg |= RX_PAUSE_EN;
145
146 - reg_writel(priv, reg, REG_RGMII_CNTRL_P(port));
147 + reg_writel(priv, reg, reg_rgmii_ctrl);
148 }
149
150 reg = SW_OVERRIDE | LINK_STS;
151 --- a/drivers/net/dsa/bcm_sf2_regs.h
152 +++ b/drivers/net/dsa/bcm_sf2_regs.h
153 @@ -55,8 +55,6 @@ enum bcm_sf2_reg_offs {
154 #define CROSSBAR_BCM4908_EXT_GPHY4 1
155 #define CROSSBAR_BCM4908_EXT_RGMII 2
156
157 -#define REG_RGMII_CNTRL_P(x) (REG_RGMII_0_CNTRL + (x))
158 -
159 /* Relative to REG_RGMII_CNTRL */
160 #define RGMII_MODE_EN (1 << 0)
161 #define ID_MODE_DIS (1 << 1)