aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFlorian Fainelli <f.fainelli@gmail.com>2015-10-23 15:11:08 -0400
committerDavid S. Miller <davem@davemloft.net>2015-10-26 21:23:59 -0400
commit8b7c94e3478dbb0296293b43a974c3561d01e9fb (patch)
tree7d3c6de2409ac496165853b236a9ba6b757a6b68
parent680060d3e02d175516832e9af058ffe96ecc4cdc (diff)
net: dsa: bcm_sf2: Unhardcode port numbers
While the current driver mostly supports BCM7445 which has a hardcoded location for its MoCA port on port 7 and port 0 for its internal PHY, this is not necessarily true for all other chips out there such as BCM3390 for instance. Walk the list of ports from Device Tree, get their port number ("reg" property), and then parse the "phy-mode" property and initialize two internal variables: moca_port and a bitmask of internal PHYs. Since we use interrupts for the MoCA port, we introduce two helper functions to enable/disable interrupts and do this at the appropriate bank (INTRL2_0 or INTRL2_1). Signed-off-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/dsa/bcm_sf2.c102
-rw-r--r--drivers/net/dsa/bcm_sf2.h6
2 files changed, 97 insertions, 11 deletions
diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c
index 4f32b8a530bf..6f946fedbb77 100644
--- a/drivers/net/dsa/bcm_sf2.c
+++ b/drivers/net/dsa/bcm_sf2.c
@@ -21,6 +21,7 @@
21#include <linux/of.h> 21#include <linux/of.h>
22#include <linux/of_irq.h> 22#include <linux/of_irq.h>
23#include <linux/of_address.h> 23#include <linux/of_address.h>
24#include <linux/of_net.h>
24#include <net/dsa.h> 25#include <net/dsa.h>
25#include <linux/ethtool.h> 26#include <linux/ethtool.h>
26#include <linux/if_bridge.h> 27#include <linux/if_bridge.h>
@@ -266,6 +267,50 @@ static void bcm_sf2_gphy_enable_set(struct dsa_switch *ds, bool enable)
266 } 267 }
267} 268}
268 269
270static inline void bcm_sf2_port_intr_enable(struct bcm_sf2_priv *priv,
271 int port)
272{
273 unsigned int off;
274
275 switch (port) {
276 case 7:
277 off = P7_IRQ_OFF;
278 break;
279 case 0:
280 /* Port 0 interrupts are located on the first bank */
281 intrl2_0_mask_clear(priv, P_IRQ_MASK(P0_IRQ_OFF));
282 return;
283 default:
284 off = P_IRQ_OFF(port);
285 break;
286 }
287
288 intrl2_1_mask_clear(priv, P_IRQ_MASK(off));
289}
290
291static inline void bcm_sf2_port_intr_disable(struct bcm_sf2_priv *priv,
292 int port)
293{
294 unsigned int off;
295
296 switch (port) {
297 case 7:
298 off = P7_IRQ_OFF;
299 break;
300 case 0:
301 /* Port 0 interrupts are located on the first bank */
302 intrl2_0_mask_set(priv, P_IRQ_MASK(P0_IRQ_OFF));
303 intrl2_0_writel(priv, P_IRQ_MASK(P0_IRQ_OFF), INTRL2_CPU_CLEAR);
304 return;
305 default:
306 off = P_IRQ_OFF(port);
307 break;
308 }
309
310 intrl2_1_mask_set(priv, P_IRQ_MASK(off));
311 intrl2_1_writel(priv, P_IRQ_MASK(off), INTRL2_CPU_CLEAR);
312}
313
269static int bcm_sf2_port_setup(struct dsa_switch *ds, int port, 314static int bcm_sf2_port_setup(struct dsa_switch *ds, int port,
270 struct phy_device *phy) 315 struct phy_device *phy)
271{ 316{
@@ -282,7 +327,7 @@ static int bcm_sf2_port_setup(struct dsa_switch *ds, int port,
282 core_writel(priv, 0, CORE_G_PCTL_PORT(port)); 327 core_writel(priv, 0, CORE_G_PCTL_PORT(port));
283 328
284 /* Re-enable the GPHY and re-apply workarounds */ 329 /* Re-enable the GPHY and re-apply workarounds */
285 if (port == 0 && priv->hw_params.num_gphy == 1) { 330 if (priv->int_phy_mask & 1 << port && priv->hw_params.num_gphy == 1) {
286 bcm_sf2_gphy_enable_set(ds, true); 331 bcm_sf2_gphy_enable_set(ds, true);
287 if (phy) { 332 if (phy) {
288 /* if phy_stop() has been called before, phy 333 /* if phy_stop() has been called before, phy
@@ -299,9 +344,9 @@ static int bcm_sf2_port_setup(struct dsa_switch *ds, int port,
299 } 344 }
300 } 345 }
301 346
302 /* Enable port 7 interrupts to get notified */ 347 /* Enable MoCA port interrupts to get notified */
303 if (port == 7) 348 if (port == priv->moca_port)
304 intrl2_1_mask_clear(priv, P_IRQ_MASK(P7_IRQ_OFF)); 349 bcm_sf2_port_intr_enable(priv, port);
305 350
306 /* Set this port, and only this one to be in the default VLAN, 351 /* Set this port, and only this one to be in the default VLAN,
307 * if member of a bridge, restore its membership prior to 352 * if member of a bridge, restore its membership prior to
@@ -331,12 +376,10 @@ static void bcm_sf2_port_disable(struct dsa_switch *ds, int port,
331 if (priv->wol_ports_mask & (1 << port)) 376 if (priv->wol_ports_mask & (1 << port))
332 return; 377 return;
333 378
334 if (port == 7) { 379 if (port == priv->moca_port)
335 intrl2_1_mask_set(priv, P_IRQ_MASK(P7_IRQ_OFF)); 380 bcm_sf2_port_intr_disable(priv, port);
336 intrl2_1_writel(priv, P_IRQ_MASK(P7_IRQ_OFF), INTRL2_CPU_CLEAR);
337 }
338 381
339 if (port == 0 && priv->hw_params.num_gphy == 1) 382 if (priv->int_phy_mask & 1 << port && priv->hw_params.num_gphy == 1)
340 bcm_sf2_gphy_enable_set(ds, false); 383 bcm_sf2_gphy_enable_set(ds, false);
341 384
342 if (dsa_is_cpu_port(ds, port)) 385 if (dsa_is_cpu_port(ds, port))
@@ -847,6 +890,42 @@ static void bcm_sf2_intr_disable(struct bcm_sf2_priv *priv)
847 intrl2_1_writel(priv, 0, INTRL2_CPU_MASK_CLEAR); 890 intrl2_1_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
848} 891}
849 892
893static void bcm_sf2_identify_ports(struct bcm_sf2_priv *priv,
894 struct device_node *dn)
895{
896 struct device_node *port;
897 const char *phy_mode_str;
898 int mode;
899 unsigned int port_num;
900 int ret;
901
902 priv->moca_port = -1;
903
904 for_each_available_child_of_node(dn, port) {
905 if (of_property_read_u32(port, "reg", &port_num))
906 continue;
907
908 /* Internal PHYs get assigned a specific 'phy-mode' property
909 * value: "internal" to help flag them before MDIO probing
910 * has completed, since they might be turned off at that
911 * time
912 */
913 mode = of_get_phy_mode(port);
914 if (mode < 0) {
915 ret = of_property_read_string(port, "phy-mode",
916 &phy_mode_str);
917 if (ret < 0)
918 continue;
919
920 if (!strcasecmp(phy_mode_str, "internal"))
921 priv->int_phy_mask |= 1 << port_num;
922 }
923
924 if (mode == PHY_INTERFACE_MODE_MOCA)
925 priv->moca_port = port_num;
926 }
927}
928
850static int bcm_sf2_sw_setup(struct dsa_switch *ds) 929static int bcm_sf2_sw_setup(struct dsa_switch *ds)
851{ 930{
852 const char *reg_names[BCM_SF2_REGS_NUM] = BCM_SF2_REGS_NAME; 931 const char *reg_names[BCM_SF2_REGS_NUM] = BCM_SF2_REGS_NAME;
@@ -865,6 +944,7 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds)
865 * level 944 * level
866 */ 945 */
867 dn = ds->pd->of_node->parent; 946 dn = ds->pd->of_node->parent;
947 bcm_sf2_identify_ports(priv, ds->pd->of_node);
868 948
869 priv->irq0 = irq_of_parse_and_map(dn, 0); 949 priv->irq0 = irq_of_parse_and_map(dn, 0);
870 priv->irq1 = irq_of_parse_and_map(dn, 1); 950 priv->irq1 = irq_of_parse_and_map(dn, 1);
@@ -1145,7 +1225,7 @@ static void bcm_sf2_sw_fixed_link_update(struct dsa_switch *ds, int port,
1145 1225
1146 status->link = 0; 1226 status->link = 0;
1147 1227
1148 /* Port 7 is special as we do not get link status from CORE_LNKSTS, 1228 /* MoCA port is special as we do not get link status from CORE_LNKSTS,
1149 * which means that we need to force the link at the port override 1229 * which means that we need to force the link at the port override
1150 * level to get the data to flow. We do use what the interrupt handler 1230 * level to get the data to flow. We do use what the interrupt handler
1151 * did determine before. 1231 * did determine before.
@@ -1153,7 +1233,7 @@ static void bcm_sf2_sw_fixed_link_update(struct dsa_switch *ds, int port,
1153 * For the other ports, we just force the link status, since this is 1233 * For the other ports, we just force the link status, since this is
1154 * a fixed PHY device. 1234 * a fixed PHY device.
1155 */ 1235 */
1156 if (port == 7) { 1236 if (port == priv->moca_port) {
1157 status->link = priv->port_sts[port].link; 1237 status->link = priv->port_sts[port].link;
1158 /* For MoCA interfaces, also force a link down notification 1238 /* For MoCA interfaces, also force a link down notification
1159 * since some version of the user-space daemon (mocad) use 1239 * since some version of the user-space daemon (mocad) use
diff --git a/drivers/net/dsa/bcm_sf2.h b/drivers/net/dsa/bcm_sf2.h
index cc98abc0aaf3..6bba1c98d764 100644
--- a/drivers/net/dsa/bcm_sf2.h
+++ b/drivers/net/dsa/bcm_sf2.h
@@ -134,6 +134,12 @@ struct bcm_sf2_priv {
134 134
135 /* Mask of ports enabled for Wake-on-LAN */ 135 /* Mask of ports enabled for Wake-on-LAN */
136 u32 wol_ports_mask; 136 u32 wol_ports_mask;
137
138 /* MoCA port location */
139 int moca_port;
140
141 /* Bitmask of ports having an integrated PHY */
142 unsigned int int_phy_mask;
137}; 143};
138 144
139struct bcm_sf2_hw_stats { 145struct bcm_sf2_hw_stats {