Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: mscc: ocelot: switch from {,un}set to {,un}assign for tag_8021q CPU ports

There is a desire for the felix driver to gain support for multiple
tag_8021q CPU ports, but the current model prevents it.

This is because ocelot_apply_bridge_fwd_mask() only takes into
consideration whether a port is a tag_8021q CPU port, but not whose CPU
port it is.

We need a model where we can have a direct affinity between an ocelot
port and a tag_8021q CPU port. This serves as the basis for multiple CPU
ports.

Declare a "dsa_8021q_cpu" backpointer in struct ocelot_port which
encodes that affinity. Repurpose the "ocelot_set_dsa_8021q_cpu" API to
"ocelot_assign_dsa_8021q_cpu" to express the change of paradigm.

Note that this change makes the first practical use of the new
ocelot_port->index field in ocelot_port_unassign_dsa_8021q_cpu(), where
we need to remove the old tag_8021q CPU port from the reserved VLAN range.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Vladimir Oltean and committed by
David S. Miller
c295f983 8c166acb

+93 -69
+9 -18
drivers/net/dsa/ocelot/felix.c
··· 414 414 static int felix_tag_8021q_setup(struct dsa_switch *ds) 415 415 { 416 416 struct ocelot *ocelot = ds->priv; 417 - struct dsa_port *dp, *cpu_dp; 417 + struct dsa_port *dp; 418 418 int err; 419 419 420 420 err = dsa_tag_8021q_register(ds, htons(ETH_P_8021AD)); 421 421 if (err) 422 422 return err; 423 423 424 - dsa_switch_for_each_cpu_port(cpu_dp, ds) { 425 - ocelot_port_set_dsa_8021q_cpu(ocelot, cpu_dp->index); 424 + dsa_switch_for_each_user_port(dp, ds) 425 + ocelot_port_assign_dsa_8021q_cpu(ocelot, dp->index, 426 + dp->cpu_dp->index); 426 427 427 - /* TODO we could support multiple CPU ports in tag_8021q mode */ 428 - break; 429 - } 430 - 431 - dsa_switch_for_each_available_port(dp, ds) { 428 + dsa_switch_for_each_available_port(dp, ds) 432 429 /* This overwrites ocelot_init(): 433 430 * Do not forward BPDU frames to the CPU port module, 434 431 * for 2 reasons: ··· 439 442 ocelot_write_gix(ocelot, 440 443 ANA_PORT_CPU_FWD_BPDU_CFG_BPDU_REDIR_ENA(0), 441 444 ANA_PORT_CPU_FWD_BPDU_CFG, dp->index); 442 - } 443 445 444 446 /* The ownership of the CPU port module's queues might have just been 445 447 * transferred to the tag_8021q tagger from the NPI-based tagger. ··· 455 459 static void felix_tag_8021q_teardown(struct dsa_switch *ds) 456 460 { 457 461 struct ocelot *ocelot = ds->priv; 458 - struct dsa_port *dp, *cpu_dp; 462 + struct dsa_port *dp; 459 463 460 - dsa_switch_for_each_available_port(dp, ds) { 464 + dsa_switch_for_each_available_port(dp, ds) 461 465 /* Restore the logic from ocelot_init: 462 466 * do not forward BPDU frames to the front ports. 463 467 */ ··· 465 469 ANA_PORT_CPU_FWD_BPDU_CFG_BPDU_REDIR_ENA(0xffff), 466 470 ANA_PORT_CPU_FWD_BPDU_CFG, 467 471 dp->index); 468 - } 469 472 470 - dsa_switch_for_each_cpu_port(cpu_dp, ds) { 471 - ocelot_port_unset_dsa_8021q_cpu(ocelot, cpu_dp->index); 472 - 473 - /* TODO we could support multiple CPU ports in tag_8021q mode */ 474 - break; 475 - } 473 + dsa_switch_for_each_user_port(dp, ds) 474 + ocelot_port_unassign_dsa_8021q_cpu(ocelot, dp->index); 476 475 477 476 dsa_tag_8021q_unregister(ds); 478 477 }
+2 -1
drivers/net/dsa/ocelot/felix_vsc9959.c
··· 2162 2162 if (ocelot->npi >= 0) 2163 2163 mask |= BIT(ocelot->npi); 2164 2164 else 2165 - mask |= ocelot_get_dsa_8021q_cpu_mask(ocelot); 2165 + mask |= ocelot_port_assigned_dsa_8021q_cpu_mask(ocelot, 2166 + port); 2166 2167 } 2167 2168 2168 2169 /* Calculate the minimum link speed, among the ports that are
+75 -47
drivers/net/ethernet/mscc/ocelot.c
··· 2046 2046 return __ffs(bond_mask); 2047 2047 } 2048 2048 2049 + static u32 ocelot_dsa_8021q_cpu_assigned_ports(struct ocelot *ocelot, 2050 + struct ocelot_port *cpu) 2051 + { 2052 + u32 mask = 0; 2053 + int port; 2054 + 2055 + for (port = 0; port < ocelot->num_phys_ports; port++) { 2056 + struct ocelot_port *ocelot_port = ocelot->ports[port]; 2057 + 2058 + if (!ocelot_port) 2059 + continue; 2060 + 2061 + if (ocelot_port->dsa_8021q_cpu == cpu) 2062 + mask |= BIT(port); 2063 + } 2064 + 2065 + return mask; 2066 + } 2067 + 2068 + u32 ocelot_port_assigned_dsa_8021q_cpu_mask(struct ocelot *ocelot, int port) 2069 + { 2070 + struct ocelot_port *ocelot_port = ocelot->ports[port]; 2071 + struct ocelot_port *cpu_port = ocelot_port->dsa_8021q_cpu; 2072 + 2073 + if (!cpu_port) 2074 + return 0; 2075 + 2076 + return BIT(cpu_port->index); 2077 + } 2078 + EXPORT_SYMBOL_GPL(ocelot_port_assigned_dsa_8021q_cpu_mask); 2079 + 2049 2080 u32 ocelot_get_bridge_fwd_mask(struct ocelot *ocelot, int src_port) 2050 2081 { 2051 2082 struct ocelot_port *ocelot_port = ocelot->ports[src_port]; ··· 2106 2075 } 2107 2076 EXPORT_SYMBOL_GPL(ocelot_get_bridge_fwd_mask); 2108 2077 2109 - u32 ocelot_get_dsa_8021q_cpu_mask(struct ocelot *ocelot) 2110 - { 2111 - u32 mask = 0; 2112 - int port; 2113 - 2114 - for (port = 0; port < ocelot->num_phys_ports; port++) { 2115 - struct ocelot_port *ocelot_port = ocelot->ports[port]; 2116 - 2117 - if (!ocelot_port) 2118 - continue; 2119 - 2120 - if (ocelot_port->is_dsa_8021q_cpu) 2121 - mask |= BIT(port); 2122 - } 2123 - 2124 - return mask; 2125 - } 2126 - EXPORT_SYMBOL_GPL(ocelot_get_dsa_8021q_cpu_mask); 2127 - 2128 2078 static void ocelot_apply_bridge_fwd_mask(struct ocelot *ocelot, bool joining) 2129 2079 { 2130 - unsigned long cpu_fwd_mask; 2131 2080 int port; 2132 2081 2133 2082 lockdep_assert_held(&ocelot->fwd_domain_lock); ··· 2118 2107 */ 2119 2108 if (joining && ocelot->ops->cut_through_fwd) 2120 2109 ocelot->ops->cut_through_fwd(ocelot); 2121 - 2122 - /* If a DSA tag_8021q CPU exists, it needs to be included in the 2123 - * regular forwarding path of the front ports regardless of whether 2124 - * those are bridged or standalone. 2125 - * If DSA tag_8021q is not used, this returns 0, which is fine because 2126 - * the hardware-based CPU port module can be a destination for packets 2127 - * even if it isn't part of PGID_SRC. 2128 - */ 2129 - cpu_fwd_mask = ocelot_get_dsa_8021q_cpu_mask(ocelot); 2130 2110 2131 2111 /* Apply FWD mask. The loop is needed to add/remove the current port as 2132 2112 * a source for the other ports. ··· 2131 2129 mask = 0; 2132 2130 } else if (ocelot_port->is_dsa_8021q_cpu) { 2133 2131 /* The DSA tag_8021q CPU ports need to be able to 2134 - * forward packets to all other ports except for 2135 - * themselves 2132 + * forward packets to all ports assigned to them. 2136 2133 */ 2137 - mask = GENMASK(ocelot->num_phys_ports - 1, 0); 2138 - mask &= ~cpu_fwd_mask; 2134 + mask = ocelot_dsa_8021q_cpu_assigned_ports(ocelot, 2135 + ocelot_port); 2139 2136 } else if (ocelot_port->bridge) { 2140 2137 struct net_device *bond = ocelot_port->bond; 2141 2138 2142 2139 mask = ocelot_get_bridge_fwd_mask(ocelot, port); 2143 - mask |= cpu_fwd_mask; 2144 2140 mask &= ~BIT(port); 2141 + 2142 + mask |= ocelot_port_assigned_dsa_8021q_cpu_mask(ocelot, 2143 + port); 2144 + 2145 2145 if (bond) 2146 2146 mask &= ~ocelot_get_bond_mask(ocelot, bond); 2147 2147 } else { ··· 2151 2147 * ports (if those exist), or to the hardware CPU port 2152 2148 * module otherwise. 2153 2149 */ 2154 - mask = cpu_fwd_mask; 2150 + mask = ocelot_port_assigned_dsa_8021q_cpu_mask(ocelot, 2151 + port); 2155 2152 } 2156 2153 2157 2154 ocelot_write_rix(ocelot, mask, ANA_PGID_PGID, PGID_SRC + port); ··· 2196 2191 ocelot_write_rix(ocelot, pgid_cpu, ANA_PGID_PGID, PGID_CPU); 2197 2192 } 2198 2193 2199 - void ocelot_port_set_dsa_8021q_cpu(struct ocelot *ocelot, int port) 2194 + void ocelot_port_assign_dsa_8021q_cpu(struct ocelot *ocelot, int port, 2195 + int cpu) 2200 2196 { 2197 + struct ocelot_port *cpu_port = ocelot->ports[cpu]; 2201 2198 u16 vid; 2202 2199 2203 2200 mutex_lock(&ocelot->fwd_domain_lock); 2204 2201 2205 - ocelot->ports[port]->is_dsa_8021q_cpu = true; 2202 + ocelot->ports[port]->dsa_8021q_cpu = cpu_port; 2206 2203 2207 - for (vid = OCELOT_RSV_VLAN_RANGE_START; vid < VLAN_N_VID; vid++) 2208 - ocelot_vlan_member_add(ocelot, port, vid, true); 2204 + if (!cpu_port->is_dsa_8021q_cpu) { 2205 + cpu_port->is_dsa_8021q_cpu = true; 2209 2206 2210 - ocelot_update_pgid_cpu(ocelot); 2207 + for (vid = OCELOT_RSV_VLAN_RANGE_START; vid < VLAN_N_VID; vid++) 2208 + ocelot_vlan_member_add(ocelot, cpu, vid, true); 2209 + 2210 + ocelot_update_pgid_cpu(ocelot); 2211 + } 2211 2212 2212 2213 ocelot_apply_bridge_fwd_mask(ocelot, true); 2213 2214 2214 2215 mutex_unlock(&ocelot->fwd_domain_lock); 2215 2216 } 2216 - EXPORT_SYMBOL_GPL(ocelot_port_set_dsa_8021q_cpu); 2217 + EXPORT_SYMBOL_GPL(ocelot_port_assign_dsa_8021q_cpu); 2217 2218 2218 - void ocelot_port_unset_dsa_8021q_cpu(struct ocelot *ocelot, int port) 2219 + void ocelot_port_unassign_dsa_8021q_cpu(struct ocelot *ocelot, int port) 2219 2220 { 2221 + struct ocelot_port *cpu_port = ocelot->ports[port]->dsa_8021q_cpu; 2222 + bool keep = false; 2220 2223 u16 vid; 2224 + int p; 2221 2225 2222 2226 mutex_lock(&ocelot->fwd_domain_lock); 2223 2227 2224 - ocelot->ports[port]->is_dsa_8021q_cpu = false; 2228 + ocelot->ports[port]->dsa_8021q_cpu = NULL; 2225 2229 2226 - for (vid = OCELOT_RSV_VLAN_RANGE_START; vid < VLAN_N_VID; vid++) 2227 - ocelot_vlan_member_del(ocelot, port, vid); 2230 + for (p = 0; p < ocelot->num_phys_ports; p++) { 2231 + if (!ocelot->ports[p]) 2232 + continue; 2228 2233 2229 - ocelot_update_pgid_cpu(ocelot); 2234 + if (ocelot->ports[p]->dsa_8021q_cpu == cpu_port) { 2235 + keep = true; 2236 + break; 2237 + } 2238 + } 2239 + 2240 + if (!keep) { 2241 + cpu_port->is_dsa_8021q_cpu = false; 2242 + 2243 + for (vid = OCELOT_RSV_VLAN_RANGE_START; vid < VLAN_N_VID; vid++) 2244 + ocelot_vlan_member_del(ocelot, cpu_port->index, vid); 2245 + 2246 + ocelot_update_pgid_cpu(ocelot); 2247 + } 2230 2248 2231 2249 ocelot_apply_bridge_fwd_mask(ocelot, true); 2232 2250 2233 2251 mutex_unlock(&ocelot->fwd_domain_lock); 2234 2252 } 2235 - EXPORT_SYMBOL_GPL(ocelot_port_unset_dsa_8021q_cpu); 2253 + EXPORT_SYMBOL_GPL(ocelot_port_unassign_dsa_8021q_cpu); 2236 2254 2237 2255 void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port, u8 state) 2238 2256 {
+7 -3
include/soc/mscc/ocelot.h
··· 654 654 int to; 655 655 }; 656 656 657 + struct ocelot_port; 658 + 657 659 struct ocelot_port { 658 660 struct ocelot *ocelot; 659 661 ··· 663 661 664 662 struct net_device *bond; 665 663 struct net_device *bridge; 664 + 665 + struct ocelot_port *dsa_8021q_cpu; 666 666 667 667 /* VLAN that untagged frames are classified to, on ingress */ 668 668 const struct ocelot_bridge_vlan *pvid_vlan; ··· 869 865 void ocelot_init_port(struct ocelot *ocelot, int port); 870 866 void ocelot_deinit_port(struct ocelot *ocelot, int port); 871 867 872 - void ocelot_port_set_dsa_8021q_cpu(struct ocelot *ocelot, int port); 873 - void ocelot_port_unset_dsa_8021q_cpu(struct ocelot *ocelot, int port); 868 + void ocelot_port_assign_dsa_8021q_cpu(struct ocelot *ocelot, int port, int cpu); 869 + void ocelot_port_unassign_dsa_8021q_cpu(struct ocelot *ocelot, int port); 870 + u32 ocelot_port_assigned_dsa_8021q_cpu_mask(struct ocelot *ocelot, int port); 874 871 875 872 /* DSA callbacks */ 876 873 void ocelot_get_strings(struct ocelot *ocelot, int port, u32 sset, u8 *data); ··· 883 878 int ocelot_port_vlan_filtering(struct ocelot *ocelot, int port, bool enabled, 884 879 struct netlink_ext_ack *extack); 885 880 void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port, u8 state); 886 - u32 ocelot_get_dsa_8021q_cpu_mask(struct ocelot *ocelot); 887 881 u32 ocelot_get_bridge_fwd_mask(struct ocelot *ocelot, int src_port); 888 882 int ocelot_port_pre_bridge_flags(struct ocelot *ocelot, int port, 889 883 struct switchdev_brport_flags val);