diff --git a/package/network/config/swconfig/src/cli.c b/package/network/config/swconfig/src/cli.c index 28b7ed8625..eab6c64742 100644 --- a/package/network/config/swconfig/src/cli.c +++ b/package/network/config/swconfig/src/cli.c @@ -41,6 +41,7 @@ enum { CMD_LOAD, CMD_HELP, CMD_SHOW, + CMD_PORTMAP, }; static void @@ -284,6 +285,10 @@ int main(int argc, char **argv) print_usage(); cmd = CMD_LOAD; ckey = argv[++i]; + } else if (!strcmp(arg, "portmap")) { + if (i + 1 < argc) + csegment = argv[++i]; + cmd = CMD_PORTMAP; } else if (!strcmp(arg, "show")) { cmd = CMD_SHOW; } else { @@ -357,6 +362,9 @@ int main(int argc, char **argv) case CMD_HELP: list_attributes(dev); break; + case CMD_PORTMAP: + swlib_print_portmap(dev, csegment); + break; case CMD_SHOW: if (cport >= 0 || cvlan >= 0) { if (cport >= 0) diff --git a/package/network/config/swconfig/src/swlib.c b/package/network/config/swconfig/src/swlib.c index 440a45aef7..e6e9aead47 100644 --- a/package/network/config/swconfig/src/swlib.c +++ b/package/network/config/swconfig/src/swlib.c @@ -46,6 +46,11 @@ static struct nla_policy port_policy[SWITCH_ATTR_MAX] = { [SWITCH_PORT_FLAG_TAGGED] = { .type = NLA_FLAG }, }; +static struct nla_policy portmap_policy[SWITCH_PORTMAP_MAX] = { + [SWITCH_PORTMAP_SEGMENT] = { .type = NLA_STRING }, + [SWITCH_PORTMAP_VIRT] = { .type = NLA_U32 }, +}; + static struct nla_policy link_policy[SWITCH_LINK_ATTR_MAX] = { [SWITCH_LINK_FLAG_LINK] = { .type = NLA_FLAG }, [SWITCH_LINK_FLAG_DUPLEX] = { .type = NLA_FLAG }, @@ -696,6 +701,41 @@ struct swlib_scan_arg { struct switch_dev *ptr; }; +static int +add_port_map(struct switch_dev *dev, struct nlattr *nla) +{ + struct nlattr *p; + int err = 0, idx = 0; + int remaining; + + dev->maps = malloc(sizeof(struct switch_portmap) * dev->ports); + if (!dev->maps) + return -1; + memset(dev->maps, 0, sizeof(struct switch_portmap) * dev->ports); + + nla_for_each_nested(p, nla, remaining) { + struct nlattr *tb[SWITCH_PORTMAP_MAX+1]; + + if (idx >= dev->ports) + continue; + + err = nla_parse_nested(tb, SWITCH_PORTMAP_MAX, p, portmap_policy); + if (err < 0) + continue; + + + if (tb[SWITCH_PORTMAP_SEGMENT] && tb[SWITCH_PORTMAP_VIRT]) { + dev->maps[idx].segment = strdup(nla_get_string(tb[SWITCH_PORTMAP_SEGMENT])); + dev->maps[idx].virt = nla_get_u32(tb[SWITCH_PORTMAP_VIRT]); + } + idx++; + } + +out: + return err; +} + + static int add_switch(struct nl_msg *msg, void *arg) { @@ -733,6 +773,8 @@ add_switch(struct nl_msg *msg, void *arg) dev->vlans = nla_get_u32(tb[SWITCH_ATTR_VLANS]); if (tb[SWITCH_ATTR_CPU_PORT]) dev->cpu_port = nla_get_u32(tb[SWITCH_ATTR_CPU_PORT]); + if (tb[SWITCH_ATTR_PORTMAP]) + add_port_map(dev, tb[SWITCH_ATTR_PORTMAP]); if (!sa->head) { sa->head = dev; @@ -774,6 +816,34 @@ swlib_list(void) swlib_priv_free(); } +void +swlib_print_portmap(struct switch_dev *dev, char *segment) +{ + int i; + + if (segment) { + if (!strcmp(segment, "cpu")) { + printf("%d ", dev->cpu_port); + } else if (!strcmp(segment, "disabled")) { + for (i = 0; i < dev->ports; i++) + if (!dev->maps[i].segment) + printf("%d ", i); + } else for (i = 0; i < dev->ports; i++) { + if (dev->maps[i].segment && !strcmp(dev->maps[i].segment, segment)) + printf("%d ", i); + } + } else { + printf("%s - %s\n", dev->dev_name, dev->name); + for (i = 0; i < dev->ports; i++) + if (i == dev->cpu_port) + printf("port%d:\tcpu\n", i); + else if (dev->maps[i].segment) + printf("port%d:\t%s.%d\n", i, dev->maps[i].segment, dev->maps[i].virt); + else + printf("port%d:\tdisabled\n", i); + } +} + struct switch_dev * swlib_connect(const char *name) { @@ -811,12 +881,26 @@ swlib_free_attributes(struct switch_attr **head) *head = NULL; } +static void +swlib_free_port_map(struct switch_dev *dev) +{ + int i; + + if (!dev || !dev->maps) + return; + + for (i = 0; i < dev->ports; i++) + free(dev->maps[i].segment); + free(dev->maps); +} + void swlib_free(struct switch_dev *dev) { swlib_free_attributes(&dev->ops); swlib_free_attributes(&dev->port_ops); swlib_free_attributes(&dev->vlan_ops); + swlib_free_port_map(dev); free(dev->name); free(dev->alias); free(dev); diff --git a/package/network/config/swconfig/src/swlib.h b/package/network/config/swconfig/src/swlib.h index 89dbba748d..3826a5e340 100644 --- a/package/network/config/swconfig/src/swlib.h +++ b/package/network/config/swconfig/src/swlib.h @@ -129,6 +129,7 @@ struct switch_dev { struct switch_attr *ops; struct switch_attr *port_ops; struct switch_attr *vlan_ops; + struct switch_portmap *maps; struct switch_dev *next; void *priv; }; @@ -161,6 +162,11 @@ struct switch_port { unsigned int flags; }; +struct switch_portmap { + unsigned int virt; + char *segment; +}; + struct switch_port_link { int link:1; int duplex:1; @@ -177,6 +183,12 @@ struct switch_port_link { */ void swlib_list(void); +/** + * swlib_print_portmap: get portmap + * @dev: switch device struct + */ +void swlib_print_portmap(struct switch_dev *dev, char *segment); + /** * swlib_connect: connect to the switch through netlink * @name: name of the ethernet interface, diff --git a/target/linux/generic/files/drivers/net/phy/swconfig.c b/target/linux/generic/files/drivers/net/phy/swconfig.c index 8dfcb1aa3b..c70ca74cad 100644 --- a/target/linux/generic/files/drivers/net/phy/swconfig.c +++ b/target/linux/generic/files/drivers/net/phy/swconfig.c @@ -915,7 +915,9 @@ static int swconfig_send_switch(struct sk_buff *msg, u32 pid, u32 seq, int flags, const struct switch_dev *dev) { + struct nlattr *p = NULL, *m = NULL; void *hdr; + int i; hdr = genlmsg_put(msg, pid, seq, &switch_fam, flags, SWITCH_CMD_NEW_ATTR); @@ -937,6 +939,24 @@ swconfig_send_switch(struct sk_buff *msg, u32 pid, u32 seq, int flags, if (nla_put_u32(msg, SWITCH_ATTR_CPU_PORT, dev->cpu_port)) goto nla_put_failure; + m = nla_nest_start(msg, SWITCH_ATTR_PORTMAP); + if (!m) + goto nla_put_failure; + for (i = 0; i < dev->ports; i++) { + p = nla_nest_start(msg, SWITCH_ATTR_PORTS); + if (!p) + continue; + if (dev->portmap[i].s) { + if (nla_put_string(msg, SWITCH_PORTMAP_SEGMENT, + dev->portmap[i].s)) + goto nla_put_failure; + if (nla_put_u32(msg, SWITCH_PORTMAP_VIRT, + dev->portmap[i].virt)) + goto nla_put_failure; + } + nla_nest_end(msg, p); + } + nla_nest_end(msg, m); genlmsg_end(msg, hdr); return msg->len; nla_put_failure: @@ -1029,6 +1049,51 @@ static struct genl_ops swconfig_ops[] = { } }; +#ifdef CONFIG_OF +void +of_switch_load_portmap(struct switch_dev *dev) +{ + struct device_node *port; + + if (!dev->of_node) + return; + + for_each_child_of_node(dev->of_node, port) { + const __be32 *prop; + const char *segment; + int size, phys; + + if (!of_device_is_compatible(port, "swconfig,port")) + continue; + + if (of_property_read_string(port, "swconfig,segment", &segment)) + continue; + + prop = of_get_property(port, "swconfig,portmap", &size); + if (!prop) + continue; + + if (size != (2 * sizeof(*prop))) { + pr_err("%s: failed to parse port mapping\n", + port->name); + continue; + } + + phys = be32_to_cpup(prop++); + if ((phys < 0) | (phys >= dev->ports)) { + pr_err("%s: physical port index out of range\n", + port->name); + continue; + } + + dev->portmap[phys].s = kstrdup(segment, GFP_KERNEL); + dev->portmap[phys].virt = be32_to_cpup(prop); + pr_debug("Found port: %s, physical: %d, virtual: %d\n", + segment, phys, dev->portmap[phys].virt); + } +} +#endif + int register_switch(struct switch_dev *dev, struct net_device *netdev) { @@ -1051,6 +1116,12 @@ register_switch(struct switch_dev *dev, struct net_device *netdev) dev->ports, GFP_KERNEL); if (!dev->portbuf) return -ENOMEM; + dev->portmap = kzalloc(sizeof(struct switch_portmap) * + dev->ports, GFP_KERNEL); + if (!dev->portmap) { + kfree(dev->portbuf); + return -ENOMEM; + } } swconfig_defaults_init(dev); mutex_init(&dev->sw_mutex); @@ -1072,6 +1143,11 @@ register_switch(struct switch_dev *dev, struct net_device *netdev) return -ENFILE; } +#ifdef CONFIG_OF + if (dev->ports) + of_switch_load_portmap(dev); +#endif + /* fill device name */ snprintf(dev->devname, IFNAMSIZ, SWCONFIG_DEVNAME, i); diff --git a/target/linux/generic/files/include/linux/switch.h b/target/linux/generic/files/include/linux/switch.h index a381fd006c..dda4820a7a 100644 --- a/target/linux/generic/files/include/linux/switch.h +++ b/target/linux/generic/files/include/linux/switch.h @@ -105,6 +105,7 @@ struct switch_dev_ops { }; struct switch_dev { + struct device_node *of_node; const struct switch_dev_ops *ops; /* will be automatically filled */ char devname[IFNAMSIZ]; @@ -125,6 +126,7 @@ struct switch_dev { struct mutex sw_mutex; struct switch_port *portbuf; + struct switch_portmap *portmap; struct switch_port_link linkbuf; char buf[128]; @@ -139,6 +141,11 @@ struct switch_port { u32 flags; }; +struct switch_portmap { + u32 virt; + const char *s; +}; + struct switch_val { const struct switch_attr *attr; int port_vlan; diff --git a/target/linux/generic/files/include/uapi/linux/switch.h b/target/linux/generic/files/include/uapi/linux/switch.h index 2a67da2e9d..ea449653fa 100644 --- a/target/linux/generic/files/include/uapi/linux/switch.h +++ b/target/linux/generic/files/include/uapi/linux/switch.h @@ -39,6 +39,7 @@ enum { SWITCH_ATTR_NAME, SWITCH_ATTR_VLANS, SWITCH_ATTR_PORTS, + SWITCH_ATTR_PORTMAP, SWITCH_ATTR_CPU_PORT, /* attributes */ SWITCH_ATTR_OP_ID, @@ -56,6 +57,14 @@ enum { SWITCH_ATTR_MAX }; +enum { + /* port map */ + SWITCH_PORTMAP_PORTS, + SWITCH_PORTMAP_SEGMENT, + SWITCH_PORTMAP_VIRT, + SWITCH_PORTMAP_MAX +}; + /* commands */ enum { SWITCH_CMD_UNSPEC, diff --git a/target/linux/ramips/dts/FONERA20N.dts b/target/linux/ramips/dts/FONERA20N.dts index 004a2c0889..b7eb91ea7b 100644 --- a/target/linux/ramips/dts/FONERA20N.dts +++ b/target/linux/ramips/dts/FONERA20N.dts @@ -93,6 +93,36 @@ &esw { mediatek,portmap = <0x2f>; + + port@0 { + compatible = "swconfig,port"; + swconfig,segment = "lan"; + swconfig,portmap = <0 4>; + }; + + port@1 { + compatible = "swconfig,port"; + swconfig,segment = "lan"; + swconfig,portmap = <1 3>; + }; + + port@2 { + compatible = "swconfig,port"; + swconfig,segment = "lan"; + swconfig,portmap = <2 2>; + }; + + port@3 { + compatible = "swconfig,port"; + swconfig,segment = "lan"; + swconfig,portmap = <3 1>; + }; + + port@4 { + compatible = "swconfig,port"; + swconfig,segment = "wan"; + swconfig,portmap = <4 0>; + }; }; &wmac { diff --git a/target/linux/ramips/patches-4.4/0512-net-mediatek-add-swconfig-driver-for-esw_rt3050.patch b/target/linux/ramips/patches-4.4/0512-net-mediatek-add-swconfig-driver-for-esw_rt3050.patch index b647d889f9..5d0072fe1e 100644 --- a/target/linux/ramips/patches-4.4/0512-net-mediatek-add-swconfig-driver-for-esw_rt3050.patch +++ b/target/linux/ramips/patches-4.4/0512-net-mediatek-add-swconfig-driver-for-esw_rt3050.patch @@ -865,11 +865,12 @@ Signed-off-by: John Crispin struct rt305x_esw *esw; struct resource *irq; int ret; -@@ -568,6 +1353,20 @@ static int esw_probe(struct platform_dev +@@ -568,6 +1353,21 @@ static int esw_probe(struct platform_dev if (reg_init) esw->reg_led_polarity = be32_to_cpu(*reg_init); + swdev = &esw->swdev; ++ swdev->of_node = pdev->dev.of_node; + swdev->name = "rt305x-esw"; + swdev->alias = "rt305x"; + swdev->cpu_port = RT305X_ESW_PORT6;