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

net: dsa: felix: tag_8021q preparation for multiple CPU ports

Update the VCAP filters to support multiple tag_8021q CPU ports.

TX works using a filter for VLAN ID on the ingress of the CPU port, with
a redirect and a VLAN pop action. This can be updated trivially by
amending the ingress port mask of this rule to match on all tag_8021q
CPU ports.

RX works using a filter for ingress port on the egress of the CPU port,
with a VLAN push action. Here we need to replicate these filters for
each tag_8021q CPU port, and let them all have the same action.
This means that the OCELOT_VCAP_ES0_TAG_8021Q_RXVLAN() cookie needs to
encode a unique value for every {user port, CPU port} pair it's given.
Do this by encoding the CPU port in the upper 16 bits of the cookie, and
the user port in the lower 16 bits.

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
a4e044dc c295f983

+65 -41
+64 -40
drivers/net/dsa/ocelot/felix.c
··· 45 45 /* Set up VCAP ES0 rules for pushing a tag_8021q VLAN towards the CPU such that 46 46 * the tagger can perform RX source port identification. 47 47 */ 48 - static int felix_tag_8021q_vlan_add_rx(struct felix *felix, int port, u16 vid) 48 + static int felix_tag_8021q_vlan_add_rx(struct dsa_switch *ds, int port, 49 + int upstream, u16 vid) 49 50 { 50 51 struct ocelot_vcap_filter *outer_tagging_rule; 51 - struct ocelot *ocelot = &felix->ocelot; 52 - struct dsa_switch *ds = felix->ds; 53 - int key_length, upstream, err; 52 + struct ocelot *ocelot = ds->priv; 53 + unsigned long cookie; 54 + int key_length, err; 54 55 55 56 key_length = ocelot->vcap[VCAP_ES0].keys[VCAP_ES0_IGR_PORT].length; 56 - upstream = dsa_upstream_port(ds, port); 57 57 58 58 outer_tagging_rule = kzalloc(sizeof(struct ocelot_vcap_filter), 59 59 GFP_KERNEL); 60 60 if (!outer_tagging_rule) 61 61 return -ENOMEM; 62 62 63 + cookie = OCELOT_VCAP_ES0_TAG_8021Q_RXVLAN(ocelot, port, upstream); 64 + 63 65 outer_tagging_rule->key_type = OCELOT_VCAP_KEY_ANY; 64 66 outer_tagging_rule->prio = 1; 65 - outer_tagging_rule->id.cookie = OCELOT_VCAP_ES0_TAG_8021Q_RXVLAN(ocelot, port); 67 + outer_tagging_rule->id.cookie = cookie; 66 68 outer_tagging_rule->id.tc_offload = false; 67 69 outer_tagging_rule->block_id = VCAP_ES0; 68 70 outer_tagging_rule->type = OCELOT_VCAP_FILTER_OFFLOAD; ··· 85 83 return err; 86 84 } 87 85 88 - static int felix_tag_8021q_vlan_del_rx(struct felix *felix, int port, u16 vid) 86 + static int felix_tag_8021q_vlan_del_rx(struct dsa_switch *ds, int port, 87 + int upstream, u16 vid) 89 88 { 90 89 struct ocelot_vcap_filter *outer_tagging_rule; 91 90 struct ocelot_vcap_block *block_vcap_es0; 92 - struct ocelot *ocelot = &felix->ocelot; 91 + struct ocelot *ocelot = ds->priv; 92 + unsigned long cookie; 93 93 94 94 block_vcap_es0 = &ocelot->block[VCAP_ES0]; 95 + cookie = OCELOT_VCAP_ES0_TAG_8021Q_RXVLAN(ocelot, port, upstream); 95 96 96 97 outer_tagging_rule = ocelot_vcap_block_find_filter_by_id(block_vcap_es0, 97 - port, false); 98 + cookie, false); 98 99 if (!outer_tagging_rule) 99 100 return -ENOENT; 100 101 ··· 107 102 /* Set up VCAP IS1 rules for stripping the tag_8021q VLAN on TX and VCAP IS2 108 103 * rules for steering those tagged packets towards the correct destination port 109 104 */ 110 - static int felix_tag_8021q_vlan_add_tx(struct felix *felix, int port, u16 vid) 105 + static int felix_tag_8021q_vlan_add_tx(struct dsa_switch *ds, int port, 106 + u16 vid) 111 107 { 112 108 struct ocelot_vcap_filter *untagging_rule, *redirect_rule; 113 - struct ocelot *ocelot = &felix->ocelot; 114 - struct dsa_switch *ds = felix->ds; 115 - int upstream, err; 109 + unsigned long cpu_ports = dsa_cpu_ports(ds); 110 + struct ocelot *ocelot = ds->priv; 111 + unsigned long cookie; 112 + int err; 116 113 117 114 untagging_rule = kzalloc(sizeof(struct ocelot_vcap_filter), GFP_KERNEL); 118 115 if (!untagging_rule) ··· 126 119 return -ENOMEM; 127 120 } 128 121 129 - upstream = dsa_upstream_port(ds, port); 122 + cookie = OCELOT_VCAP_IS1_TAG_8021Q_TXVLAN(ocelot, port); 130 123 131 124 untagging_rule->key_type = OCELOT_VCAP_KEY_ANY; 132 - untagging_rule->ingress_port_mask = BIT(upstream); 125 + untagging_rule->ingress_port_mask = cpu_ports; 133 126 untagging_rule->vlan.vid.value = vid; 134 127 untagging_rule->vlan.vid.mask = VLAN_VID_MASK; 135 128 untagging_rule->prio = 1; 136 - untagging_rule->id.cookie = OCELOT_VCAP_IS1_TAG_8021Q_TXVLAN(ocelot, port); 129 + untagging_rule->id.cookie = cookie; 137 130 untagging_rule->id.tc_offload = false; 138 131 untagging_rule->block_id = VCAP_IS1; 139 132 untagging_rule->type = OCELOT_VCAP_FILTER_OFFLOAD; ··· 150 143 return err; 151 144 } 152 145 146 + cookie = OCELOT_VCAP_IS2_TAG_8021Q_TXVLAN(ocelot, port); 147 + 153 148 redirect_rule->key_type = OCELOT_VCAP_KEY_ANY; 154 - redirect_rule->ingress_port_mask = BIT(upstream); 149 + redirect_rule->ingress_port_mask = cpu_ports; 155 150 redirect_rule->pag = port; 156 151 redirect_rule->prio = 1; 157 - redirect_rule->id.cookie = OCELOT_VCAP_IS2_TAG_8021Q_TXVLAN(ocelot, port); 152 + redirect_rule->id.cookie = cookie; 158 153 redirect_rule->id.tc_offload = false; 159 154 redirect_rule->block_id = VCAP_IS2; 160 155 redirect_rule->type = OCELOT_VCAP_FILTER_OFFLOAD; ··· 174 165 return 0; 175 166 } 176 167 177 - static int felix_tag_8021q_vlan_del_tx(struct felix *felix, int port, u16 vid) 168 + static int felix_tag_8021q_vlan_del_tx(struct dsa_switch *ds, int port, u16 vid) 178 169 { 179 170 struct ocelot_vcap_filter *untagging_rule, *redirect_rule; 180 171 struct ocelot_vcap_block *block_vcap_is1; 181 172 struct ocelot_vcap_block *block_vcap_is2; 182 - struct ocelot *ocelot = &felix->ocelot; 173 + struct ocelot *ocelot = ds->priv; 174 + unsigned long cookie; 183 175 int err; 184 176 185 177 block_vcap_is1 = &ocelot->block[VCAP_IS1]; 186 178 block_vcap_is2 = &ocelot->block[VCAP_IS2]; 187 179 180 + cookie = OCELOT_VCAP_IS1_TAG_8021Q_TXVLAN(ocelot, port); 188 181 untagging_rule = ocelot_vcap_block_find_filter_by_id(block_vcap_is1, 189 - port, false); 182 + cookie, false); 190 183 if (!untagging_rule) 191 184 return -ENOENT; 192 185 ··· 196 185 if (err) 197 186 return err; 198 187 188 + cookie = OCELOT_VCAP_IS2_TAG_8021Q_TXVLAN(ocelot, port); 199 189 redirect_rule = ocelot_vcap_block_find_filter_by_id(block_vcap_is2, 200 - port, false); 190 + cookie, false); 201 191 if (!redirect_rule) 202 192 return -ENOENT; 203 193 ··· 208 196 static int felix_tag_8021q_vlan_add(struct dsa_switch *ds, int port, u16 vid, 209 197 u16 flags) 210 198 { 211 - struct ocelot *ocelot = ds->priv; 199 + struct dsa_port *cpu_dp; 212 200 int err; 213 201 214 202 /* tag_8021q.c assumes we are implementing this via port VLAN ··· 218 206 if (!dsa_is_user_port(ds, port)) 219 207 return 0; 220 208 221 - err = felix_tag_8021q_vlan_add_rx(ocelot_to_felix(ocelot), port, vid); 222 - if (err) 223 - return err; 224 - 225 - err = felix_tag_8021q_vlan_add_tx(ocelot_to_felix(ocelot), port, vid); 226 - if (err) { 227 - felix_tag_8021q_vlan_del_rx(ocelot_to_felix(ocelot), port, vid); 228 - return err; 209 + dsa_switch_for_each_cpu_port(cpu_dp, ds) { 210 + err = felix_tag_8021q_vlan_add_rx(ds, port, cpu_dp->index, vid); 211 + if (err) 212 + return err; 229 213 } 230 214 215 + err = felix_tag_8021q_vlan_add_tx(ds, port, vid); 216 + if (err) 217 + goto add_tx_failed; 218 + 231 219 return 0; 220 + 221 + add_tx_failed: 222 + dsa_switch_for_each_cpu_port(cpu_dp, ds) 223 + felix_tag_8021q_vlan_del_rx(ds, port, cpu_dp->index, vid); 224 + 225 + return err; 232 226 } 233 227 234 228 static int felix_tag_8021q_vlan_del(struct dsa_switch *ds, int port, u16 vid) 235 229 { 236 - struct ocelot *ocelot = ds->priv; 230 + struct dsa_port *cpu_dp; 237 231 int err; 238 232 239 233 if (!dsa_is_user_port(ds, port)) 240 234 return 0; 241 235 242 - err = felix_tag_8021q_vlan_del_rx(ocelot_to_felix(ocelot), port, vid); 243 - if (err) 244 - return err; 245 - 246 - err = felix_tag_8021q_vlan_del_tx(ocelot_to_felix(ocelot), port, vid); 247 - if (err) { 248 - felix_tag_8021q_vlan_add_rx(ocelot_to_felix(ocelot), port, vid); 249 - return err; 236 + dsa_switch_for_each_cpu_port(cpu_dp, ds) { 237 + err = felix_tag_8021q_vlan_del_rx(ds, port, cpu_dp->index, vid); 238 + if (err) 239 + return err; 250 240 } 251 241 242 + err = felix_tag_8021q_vlan_del_tx(ds, port, vid); 243 + if (err) 244 + goto del_tx_failed; 245 + 252 246 return 0; 247 + 248 + del_tx_failed: 249 + dsa_switch_for_each_cpu_port(cpu_dp, ds) 250 + felix_tag_8021q_vlan_add_rx(ds, port, cpu_dp->index, vid); 251 + 252 + return err; 253 253 } 254 254 255 255 static int felix_trap_get_cpu_port(struct dsa_switch *ds,
+1 -1
include/soc/mscc/ocelot_vcap.h
··· 11 11 /* Cookie definitions for private VCAP filters installed by the driver. 12 12 * Must be unique per VCAP block. 13 13 */ 14 - #define OCELOT_VCAP_ES0_TAG_8021Q_RXVLAN(ocelot, port) (port) 14 + #define OCELOT_VCAP_ES0_TAG_8021Q_RXVLAN(ocelot, port, upstream) ((upstream) << 16 | (port)) 15 15 #define OCELOT_VCAP_IS1_TAG_8021Q_TXVLAN(ocelot, port) (port) 16 16 #define OCELOT_VCAP_IS2_TAG_8021Q_TXVLAN(ocelot, port) (port) 17 17 #define OCELOT_VCAP_IS2_MRP_REDIRECT(ocelot, port) ((ocelot)->num_phys_ports + (port))