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

net: dsa: felix: create a template for the DSA tags on xmit

With this patch we try to kill 2 birds with 1 stone.

First of all, some switches that use tag_ocelot.c don't have the exact
same bitfield layout for the DSA tags. The destination ports field is
different for Seville VSC9953 for example. So the choices are to either
duplicate tag_ocelot.c into a new tag_seville.c (sub-optimal) or somehow
take into account a supposed ocelot->dest_ports_offset when packing this
field into the DSA injection header (again not ideal).

Secondly, tag_ocelot.c already needs to memset a 128-bit area to zero
and call some packing() functions of dubious performance in the
fastpath. And most of the values it needs to pack are pretty much
constant (BYPASS=1, SRC_PORT=CPU, DEST=port index). So it would be good
if we could improve that.

The proposed solution is to allocate a memory area per port at probe
time, initialize that with the statically defined bits as per chip
hardware revision, and just perform a simpler memcpy in the fastpath.

Other alternatives have been analyzed, such as:
- Create a separate tag_seville.c: too much code duplication for just 1
bit field difference.
- Create a separate DSA_TAG_PROTO_SEVILLE under tag_ocelot.c, just like
tag_brcm.c, which would have a separate .xmit function. Again, too
much code duplication for just 1 bit field difference.
- Allocate the template from the init function of the tag_ocelot.c
module, instead of from the driver: couldn't figure out a method of
accessing the correct port template corresponding to the correct
tagger in the .xmit function.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Vladimir Oltean and committed by
David S. Miller
67c24049 886e1387

+44 -13
+13
drivers/net/dsa/ocelot/felix.c
··· 522 522 for (port = 0; port < num_phys_ports; port++) { 523 523 struct ocelot_port *ocelot_port; 524 524 struct regmap *target; 525 + u8 *template; 525 526 526 527 ocelot_port = devm_kzalloc(ocelot->dev, 527 528 sizeof(struct ocelot_port), ··· 548 547 return PTR_ERR(target); 549 548 } 550 549 550 + template = devm_kzalloc(ocelot->dev, OCELOT_TAG_LEN, 551 + GFP_KERNEL); 552 + if (!template) { 553 + dev_err(ocelot->dev, 554 + "Failed to allocate memory for DSA tag\n"); 555 + kfree(port_phy_modes); 556 + return -ENOMEM; 557 + } 558 + 551 559 ocelot_port->phy_mode = port_phy_modes[port]; 552 560 ocelot_port->ocelot = ocelot; 553 561 ocelot_port->target = target; 562 + ocelot_port->xmit_template = template; 554 563 ocelot->ports[port] = ocelot_port; 564 + 565 + felix->info->xmit_template_populate(ocelot, port); 555 566 } 556 567 557 568 kfree(port_phy_modes);
+1
drivers/net/dsa/ocelot/felix.h
··· 43 43 enum tc_setup_type type, void *type_data); 44 44 void (*port_sched_speed_set)(struct ocelot *ocelot, int port, 45 45 u32 speed); 46 + void (*xmit_template_populate)(struct ocelot *ocelot, int port); 46 47 }; 47 48 48 49 extern struct felix_info felix_info_vsc9959;
+20
drivers/net/dsa/ocelot/felix_vsc9959.c
··· 8 8 #include <soc/mscc/ocelot_ptp.h> 9 9 #include <soc/mscc/ocelot_sys.h> 10 10 #include <soc/mscc/ocelot.h> 11 + #include <linux/packing.h> 11 12 #include <net/pkt_sched.h> 12 13 #include <linux/iopoll.h> 13 14 #include <linux/pci.h> ··· 1433 1432 } 1434 1433 } 1435 1434 1435 + static void vsc9959_xmit_template_populate(struct ocelot *ocelot, int port) 1436 + { 1437 + struct ocelot_port *ocelot_port = ocelot->ports[port]; 1438 + u8 *template = ocelot_port->xmit_template; 1439 + u64 bypass, dest, src; 1440 + 1441 + /* Set the source port as the CPU port module and not the 1442 + * NPI port 1443 + */ 1444 + src = ocelot->num_phys_ports; 1445 + dest = BIT(port); 1446 + bypass = true; 1447 + 1448 + packing(template, &bypass, 127, 127, OCELOT_TAG_LEN, PACK, 0); 1449 + packing(template, &dest, 68, 56, OCELOT_TAG_LEN, PACK, 0); 1450 + packing(template, &src, 46, 43, OCELOT_TAG_LEN, PACK, 0); 1451 + } 1452 + 1436 1453 struct felix_info felix_info_vsc9959 = { 1437 1454 .target_io_res = vsc9959_target_io_res, 1438 1455 .port_io_res = vsc9959_port_io_res, ··· 1477 1458 .prevalidate_phy_mode = vsc9959_prevalidate_phy_mode, 1478 1459 .port_setup_tc = vsc9959_port_setup_tc, 1479 1460 .port_sched_speed_set = vsc9959_sched_speed_set, 1461 + .xmit_template_populate = vsc9959_xmit_template_populate, 1480 1462 };
+2
include/soc/mscc/ocelot.h
··· 564 564 u8 ts_id; 565 565 566 566 phy_interface_t phy_mode; 567 + 568 + u8 *xmit_template; 567 569 }; 568 570 569 571 struct ocelot {
+8 -13
net/dsa/tag_ocelot.c
··· 137 137 struct net_device *netdev) 138 138 { 139 139 struct dsa_port *dp = dsa_slave_to_port(netdev); 140 - u64 bypass, dest, src, qos_class, rew_op; 141 140 struct dsa_switch *ds = dp->ds; 142 - int port = dp->index; 143 141 struct ocelot *ocelot = ds->priv; 144 - struct ocelot_port *ocelot_port = ocelot->ports[port]; 142 + struct ocelot_port *ocelot_port; 143 + u64 qos_class, rew_op; 145 144 u8 *injection; 146 145 147 146 if (unlikely(skb_cow_head(skb, OCELOT_TAG_LEN) < 0)) { ··· 148 149 return NULL; 149 150 } 150 151 152 + ocelot_port = ocelot->ports[dp->index]; 153 + 151 154 injection = skb_push(skb, OCELOT_TAG_LEN); 152 155 153 - memset(injection, 0, OCELOT_TAG_LEN); 154 - 155 - /* Set the source port as the CPU port module and not the NPI port */ 156 - src = ocelot->num_phys_ports; 157 - dest = BIT(port); 158 - bypass = true; 156 + memcpy(injection, ocelot_port->xmit_template, OCELOT_TAG_LEN); 157 + /* Fix up the fields which are not statically determined 158 + * in the template 159 + */ 159 160 qos_class = skb->priority; 160 - 161 - packing(injection, &bypass, 127, 127, OCELOT_TAG_LEN, PACK, 0); 162 - packing(injection, &dest, 68, 56, OCELOT_TAG_LEN, PACK, 0); 163 - packing(injection, &src, 46, 43, OCELOT_TAG_LEN, PACK, 0); 164 161 packing(injection, &qos_class, 19, 17, OCELOT_TAG_LEN, PACK, 0); 165 162 166 163 if (ocelot->ptp && (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {