Commit 3f0bf60f authored by David S. Miller's avatar David S. Miller

Merge branch 'dsa-multi-swtich'

Andrew Lunn says:

====================
D in DSA patches

The D in DSA is distributed, meaning multiple switches can be
connected together. Currently no mainline system does this, and so the
code is broken. This patchset contains two fixes, and a small helper.

With three of more switches, the current device tree binding is not
sufficient to express the routing between the switches. The first
patch extends the binding, in a backwards compatible way, to allow a
link between a switch to describe all the switches accessible over the
link, not just the direct neighbor.

The third patch fixes the port configuration on newer devices for
links connecting switches.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 61ed713b 6083ce71
...@@ -44,9 +44,10 @@ Note that a port labelled "dsa" will imply checking for the uplink phandle ...@@ -44,9 +44,10 @@ Note that a port labelled "dsa" will imply checking for the uplink phandle
described below. described below.
Optionnal property: Optionnal property:
- link : Should be a phandle to another switch's DSA port. - link : Should be a list of phandles to another switch's DSA port.
This property is only used when switches are being This property is only used when switches are being
chained/cascaded together. chained/cascaded together. This port is used as outgoing port
towards the phandle port, which can be more than one hop away.
- phy-handle : Phandle to a PHY on an external MDIO bus, not the - phy-handle : Phandle to a PHY on an external MDIO bus, not the
switch internal one. See switch internal one. See
...@@ -100,10 +101,11 @@ Example: ...@@ -100,10 +101,11 @@ Example:
label = "cpu"; label = "cpu";
}; };
switch0uplink: port@6 { switch0port6: port@6 {
reg = <6>; reg = <6>;
label = "dsa"; label = "dsa";
link = <&switch1uplink>; link = <&switch1port0
&switch2port0>;
}; };
}; };
...@@ -113,10 +115,29 @@ Example: ...@@ -113,10 +115,29 @@ Example:
reg = <17 1>; /* MDIO address 17, switch 1 in tree */ reg = <17 1>; /* MDIO address 17, switch 1 in tree */
mii-bus = <&mii_bus1>; mii-bus = <&mii_bus1>;
switch1uplink: port@0 { switch1port0: port@0 {
reg = <0>; reg = <0>;
label = "dsa"; label = "dsa";
link = <&switch0uplink>; link = <&switch0port6>;
};
switch1port1: port@1 {
reg = <1>;
label = "dsa";
link = <&switch2port1>;
};
};
switch@2 {
#address-cells = <1>;
#size-cells = <0>;
reg = <18 2>; /* MDIO address 18, switch 2 in tree */
mii-bus = <&mii_bus1>;
switch2port0: port@0 {
reg = <0>;
label = "dsa";
link = <&switch1port1
&switch0port6>;
}; };
}; };
}; };
...@@ -1926,8 +1926,7 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port) ...@@ -1926,8 +1926,7 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)
* full duplex. * full duplex.
*/ */
reg = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_PCS_CTRL); reg = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_PCS_CTRL);
if (dsa_is_cpu_port(ds, port) || if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) {
ds->dsa_port_mask & (1 << port)) {
reg |= PORT_PCS_CTRL_FORCE_LINK | reg |= PORT_PCS_CTRL_FORCE_LINK |
PORT_PCS_CTRL_LINK_UP | PORT_PCS_CTRL_LINK_UP |
PORT_PCS_CTRL_DUPLEX_FULL | PORT_PCS_CTRL_DUPLEX_FULL |
...@@ -1988,12 +1987,15 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port) ...@@ -1988,12 +1987,15 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)
reg |= PORT_CONTROL_EGRESS_ADD_TAG; reg |= PORT_CONTROL_EGRESS_ADD_TAG;
} }
} }
if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || if (dsa_is_dsa_port(ds, port)) {
mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || if (mv88e6xxx_6095_family(ds) || mv88e6xxx_6185_family(ds))
mv88e6xxx_6095_family(ds) || mv88e6xxx_6065_family(ds) || reg |= PORT_CONTROL_DSA_TAG;
mv88e6xxx_6320_family(ds)) { if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
if (ds->dsa_port_mask & (1 << port)) mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
mv88e6xxx_6320_family(ds)) {
reg |= PORT_CONTROL_FRAME_MODE_DSA; reg |= PORT_CONTROL_FRAME_MODE_DSA;
}
if (port == dsa_upstream_port(ds)) if (port == dsa_upstream_port(ds))
reg |= PORT_CONTROL_FORWARD_UNKNOWN | reg |= PORT_CONTROL_FORWARD_UNKNOWN |
PORT_CONTROL_FORWARD_UNKNOWN_MC; PORT_CONTROL_FORWARD_UNKNOWN_MC;
......
...@@ -171,6 +171,11 @@ static inline bool dsa_is_cpu_port(struct dsa_switch *ds, int p) ...@@ -171,6 +171,11 @@ static inline bool dsa_is_cpu_port(struct dsa_switch *ds, int p)
return !!(ds->index == ds->dst->cpu_switch && p == ds->dst->cpu_port); return !!(ds->index == ds->dst->cpu_switch && p == ds->dst->cpu_port);
} }
static inline bool dsa_is_dsa_port(struct dsa_switch *ds, int p)
{
return !!((ds->dsa_port_mask) & (1 << p));
}
static inline bool dsa_is_port_initialized(struct dsa_switch *ds, int p) static inline bool dsa_is_port_initialized(struct dsa_switch *ds, int p)
{ {
return ds->phys_port_mask & (1 << p) && ds->ports[p]; return ds->phys_port_mask & (1 << p) && ds->ports[p];
......
...@@ -554,6 +554,31 @@ static int dsa_of_setup_routing_table(struct dsa_platform_data *pd, ...@@ -554,6 +554,31 @@ static int dsa_of_setup_routing_table(struct dsa_platform_data *pd,
return 0; return 0;
} }
static int dsa_of_probe_links(struct dsa_platform_data *pd,
struct dsa_chip_data *cd,
int chip_index, int port_index,
struct device_node *port,
const char *port_name)
{
struct device_node *link;
int link_index;
int ret;
for (link_index = 0;; link_index++) {
link = of_parse_phandle(port, "link", link_index);
if (!link)
break;
if (!strcmp(port_name, "dsa") && pd->nr_chips > 1) {
ret = dsa_of_setup_routing_table(pd, cd, chip_index,
port_index, link);
if (ret)
return ret;
}
}
return 0;
}
static void dsa_of_free_platform_data(struct dsa_platform_data *pd) static void dsa_of_free_platform_data(struct dsa_platform_data *pd)
{ {
int i; int i;
...@@ -573,7 +598,7 @@ static void dsa_of_free_platform_data(struct dsa_platform_data *pd) ...@@ -573,7 +598,7 @@ static void dsa_of_free_platform_data(struct dsa_platform_data *pd)
static int dsa_of_probe(struct device *dev) static int dsa_of_probe(struct device *dev)
{ {
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
struct device_node *child, *mdio, *ethernet, *port, *link; struct device_node *child, *mdio, *ethernet, *port;
struct mii_bus *mdio_bus, *mdio_bus_switch; struct mii_bus *mdio_bus, *mdio_bus_switch;
struct net_device *ethernet_dev; struct net_device *ethernet_dev;
struct dsa_platform_data *pd; struct dsa_platform_data *pd;
...@@ -668,15 +693,10 @@ static int dsa_of_probe(struct device *dev) ...@@ -668,15 +693,10 @@ static int dsa_of_probe(struct device *dev)
goto out_free_chip; goto out_free_chip;
} }
link = of_parse_phandle(port, "link", 0); ret = dsa_of_probe_links(pd, cd, chip_index,
port_index, port, port_name);
if (!strcmp(port_name, "dsa") && link && if (ret)
pd->nr_chips > 1) { goto out_free_chip;
ret = dsa_of_setup_routing_table(pd, cd,
chip_index, port_index, link);
if (ret)
goto out_free_chip;
}
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment