|
@@ -78,19 +78,28 @@ static void dsa_dst_del_ds(struct dsa_switch_tree *dst,
|
|
|
kref_put(&dst->refcount, dsa_free_dst);
|
|
|
}
|
|
|
|
|
|
+/* For platform data configurations, we need to have a valid name argument to
|
|
|
+ * differentiate a disabled port from an enabled one
|
|
|
+ */
|
|
|
static bool dsa_port_is_valid(struct dsa_port *port)
|
|
|
{
|
|
|
- return !!port->dn;
|
|
|
+ return !!(port->dn || port->name);
|
|
|
}
|
|
|
|
|
|
static bool dsa_port_is_dsa(struct dsa_port *port)
|
|
|
{
|
|
|
- return !!of_parse_phandle(port->dn, "link", 0);
|
|
|
+ if (port->name && !strcmp(port->name, "dsa"))
|
|
|
+ return true;
|
|
|
+ else
|
|
|
+ return !!of_parse_phandle(port->dn, "link", 0);
|
|
|
}
|
|
|
|
|
|
static bool dsa_port_is_cpu(struct dsa_port *port)
|
|
|
{
|
|
|
- return !!of_parse_phandle(port->dn, "ethernet", 0);
|
|
|
+ if (port->name && !strcmp(port->name, "cpu"))
|
|
|
+ return true;
|
|
|
+ else
|
|
|
+ return !!of_parse_phandle(port->dn, "ethernet", 0);
|
|
|
}
|
|
|
|
|
|
static bool dsa_ds_find_port_dn(struct dsa_switch *ds,
|
|
@@ -250,10 +259,11 @@ static void dsa_cpu_port_unapply(struct dsa_port *port, u32 index,
|
|
|
static int dsa_user_port_apply(struct dsa_port *port, u32 index,
|
|
|
struct dsa_switch *ds)
|
|
|
{
|
|
|
- const char *name;
|
|
|
+ const char *name = port->name;
|
|
|
int err;
|
|
|
|
|
|
- name = of_get_property(port->dn, "label", NULL);
|
|
|
+ if (port->dn)
|
|
|
+ name = of_get_property(port->dn, "label", NULL);
|
|
|
if (!name)
|
|
|
name = "eth%d";
|
|
|
|
|
@@ -444,11 +454,16 @@ static int dsa_cpu_parse(struct dsa_port *port, u32 index,
|
|
|
struct net_device *ethernet_dev;
|
|
|
struct device_node *ethernet;
|
|
|
|
|
|
- ethernet = of_parse_phandle(port->dn, "ethernet", 0);
|
|
|
- if (!ethernet)
|
|
|
- return -EINVAL;
|
|
|
+ if (port->dn) {
|
|
|
+ ethernet = of_parse_phandle(port->dn, "ethernet", 0);
|
|
|
+ if (!ethernet)
|
|
|
+ return -EINVAL;
|
|
|
+ ethernet_dev = of_find_net_device_by_node(ethernet);
|
|
|
+ } else {
|
|
|
+ ethernet_dev = dsa_dev_to_net_device(ds->cd->netdev[index]);
|
|
|
+ dev_put(ethernet_dev);
|
|
|
+ }
|
|
|
|
|
|
- ethernet_dev = of_find_net_device_by_node(ethernet);
|
|
|
if (!ethernet_dev)
|
|
|
return -EPROBE_DEFER;
|
|
|
|
|
@@ -551,6 +566,33 @@ static int dsa_parse_ports_dn(struct device_node *ports, struct dsa_switch *ds)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int dsa_parse_ports(struct dsa_chip_data *cd, struct dsa_switch *ds)
|
|
|
+{
|
|
|
+ bool valid_name_found = false;
|
|
|
+ unsigned int i;
|
|
|
+
|
|
|
+ for (i = 0; i < DSA_MAX_PORTS; i++) {
|
|
|
+ if (!cd->port_names[i])
|
|
|
+ continue;
|
|
|
+
|
|
|
+ ds->ports[i].name = cd->port_names[i];
|
|
|
+
|
|
|
+ /* Initialize enabled_port_mask now for drv->setup()
|
|
|
+ * to have access to a correct value, just like what
|
|
|
+ * net/dsa/dsa.c::dsa_switch_setup_one does.
|
|
|
+ */
|
|
|
+ if (!dsa_port_is_cpu(&ds->ports[i]))
|
|
|
+ ds->enabled_port_mask |= 1 << i;
|
|
|
+
|
|
|
+ valid_name_found = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!valid_name_found && i == DSA_MAX_PORTS)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int dsa_parse_member_dn(struct device_node *np, u32 *tree, u32 *index)
|
|
|
{
|
|
|
int err;
|
|
@@ -575,6 +617,18 @@ static int dsa_parse_member_dn(struct device_node *np, u32 *tree, u32 *index)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int dsa_parse_member(struct dsa_chip_data *pd, u32 *tree, u32 *index)
|
|
|
+{
|
|
|
+ if (!pd)
|
|
|
+ return -ENODEV;
|
|
|
+
|
|
|
+ /* We do not support complex trees with dsa_chip_data */
|
|
|
+ *tree = 0;
|
|
|
+ *index = 0;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static struct device_node *dsa_get_ports(struct dsa_switch *ds,
|
|
|
struct device_node *np)
|
|
|
{
|
|
@@ -591,23 +645,34 @@ static struct device_node *dsa_get_ports(struct dsa_switch *ds,
|
|
|
|
|
|
static int _dsa_register_switch(struct dsa_switch *ds, struct device *dev)
|
|
|
{
|
|
|
+ struct dsa_chip_data *pdata = dev->platform_data;
|
|
|
struct device_node *np = dev->of_node;
|
|
|
struct dsa_switch_tree *dst;
|
|
|
struct device_node *ports;
|
|
|
u32 tree, index;
|
|
|
int i, err;
|
|
|
|
|
|
- err = dsa_parse_member_dn(np, &tree, &index);
|
|
|
- if (err)
|
|
|
- return err;
|
|
|
+ if (np) {
|
|
|
+ err = dsa_parse_member_dn(np, &tree, &index);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
|
|
|
- ports = dsa_get_ports(ds, np);
|
|
|
- if (IS_ERR(ports))
|
|
|
- return PTR_ERR(ports);
|
|
|
+ ports = dsa_get_ports(ds, np);
|
|
|
+ if (IS_ERR(ports))
|
|
|
+ return PTR_ERR(ports);
|
|
|
|
|
|
- err = dsa_parse_ports_dn(ports, ds);
|
|
|
- if (err)
|
|
|
- return err;
|
|
|
+ err = dsa_parse_ports_dn(ports, ds);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+ } else {
|
|
|
+ err = dsa_parse_member(pdata, &tree, &index);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ err = dsa_parse_ports(pdata, ds);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+ }
|
|
|
|
|
|
dst = dsa_get_dst(tree);
|
|
|
if (!dst) {
|
|
@@ -623,6 +688,7 @@ static int _dsa_register_switch(struct dsa_switch *ds, struct device *dev)
|
|
|
|
|
|
ds->dst = dst;
|
|
|
ds->index = index;
|
|
|
+ ds->cd = pdata;
|
|
|
|
|
|
/* Initialize the routing table */
|
|
|
for (i = 0; i < DSA_MAX_SWITCHES; ++i)
|