Skip to content

Commit

Permalink
Merge branch 'Generic-adjustment-for-flow-dissector-in-DSA'
Browse files Browse the repository at this point in the history
Vladimir Oltean says:

====================
Generic adjustment for flow dissector in DSA

This is the v2 of a series initially submitted in May:
https://www.spinics.net/lists/netdev/msg651866.html

The end goal is to get rid of the unintuitive code for the flow
dissector that currently exists in the taggers. It can all be replaced
by a single, common function.

Some background work needs to be done for that. Especially the ocelot
driver poses some problems, since it has a different tag length between
RX and TX, and I didn't want to make DSA aware of that, since I could
instead make the tag lengths equal.

Changes in v3:
- Added an optimization (08/15) that makes the generic case not need to
  call the .flow_dissect function pointer. Basically .flow_dissect now
  currently only exists for sja1105.
- Moved the .promisc_on_master property to the tagger structure.
- Added the .tail_tag property to the tagger structure.
- Disabled "suppresscc = all" from my .gitconfig.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Sep 26, 2020
2 parents 435be28 + 300fd57 commit dfa6692
Show file tree
Hide file tree
Showing 19 changed files with 158 additions and 135 deletions.
31 changes: 26 additions & 5 deletions drivers/net/dsa/ocelot/felix.c
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,8 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports)
ocelot->vcap_is2_actions= felix->info->vcap_is2_actions;
ocelot->vcap = felix->info->vcap;
ocelot->ops = felix->info->ops;
ocelot->inj_prefix = OCELOT_TAG_PREFIX_SHORT;
ocelot->xtr_prefix = OCELOT_TAG_PREFIX_SHORT;

port_phy_modes = kcalloc(num_phys_ports, sizeof(phy_interface_t),
GFP_KERNEL);
Expand Down Expand Up @@ -509,7 +511,7 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports)
return PTR_ERR(target);
}

template = devm_kzalloc(ocelot->dev, OCELOT_TAG_LEN,
template = devm_kzalloc(ocelot->dev, OCELOT_TOTAL_TAG_LEN,
GFP_KERNEL);
if (!template) {
dev_err(ocelot->dev,
Expand Down Expand Up @@ -538,6 +540,28 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports)
return 0;
}

/* The CPU port module is connected to the Node Processor Interface (NPI). This
* is the mode through which frames can be injected from and extracted to an
* external CPU, over Ethernet.
*/
static void felix_npi_port_init(struct ocelot *ocelot, int port)
{
ocelot->npi = port;

ocelot_write(ocelot, QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK_M |
QSYS_EXT_CPU_CFG_EXT_CPU_PORT(port),
QSYS_EXT_CPU_CFG);

/* NPI port Injection/Extraction configuration */
ocelot_fields_write(ocelot, port, SYS_PORT_MODE_INCL_XTR_HDR,
ocelot->xtr_prefix);
ocelot_fields_write(ocelot, port, SYS_PORT_MODE_INCL_INJ_HDR,
ocelot->inj_prefix);

/* Disable transmission of pause frames */
ocelot_fields_write(ocelot, port, SYS_PAUSE_CFG_PAUSE_ENA, 0);
}

/* Hardware initialization done here so that we can allocate structures with
* devm without fear of dsa_register_switch returning -EPROBE_DEFER and causing
* us to allocate structures twice (leak memory) and map PCI memory twice
Expand Down Expand Up @@ -570,11 +594,8 @@ static int felix_setup(struct dsa_switch *ds)
for (port = 0; port < ds->num_ports; port++) {
ocelot_init_port(ocelot, port);

/* Bring up the CPU port module and configure the NPI port */
if (dsa_is_cpu_port(ds, port))
ocelot_configure_cpu(ocelot, port,
OCELOT_TAG_PREFIX_NONE,
OCELOT_TAG_PREFIX_LONG);
felix_npi_port_init(ocelot, port);

/* Set the default QoS Classification based on PCP and DEI
* bits of vlan tag.
Expand Down
13 changes: 10 additions & 3 deletions drivers/net/dsa/ocelot/felix_vsc9959.c
Original file line number Diff line number Diff line change
Expand Up @@ -1155,6 +1155,8 @@ static void vsc9959_xmit_template_populate(struct ocelot *ocelot, int port)
struct ocelot_port *ocelot_port = ocelot->ports[port];
u8 *template = ocelot_port->xmit_template;
u64 bypass, dest, src;
__be32 *prefix;
u8 *injection;

/* Set the source port as the CPU port module and not the
* NPI port
Expand All @@ -1163,9 +1165,14 @@ static void vsc9959_xmit_template_populate(struct ocelot *ocelot, int port)
dest = BIT(port);
bypass = true;

packing(template, &bypass, 127, 127, OCELOT_TAG_LEN, PACK, 0);
packing(template, &dest, 68, 56, OCELOT_TAG_LEN, PACK, 0);
packing(template, &src, 46, 43, OCELOT_TAG_LEN, PACK, 0);
injection = template + OCELOT_SHORT_PREFIX_LEN;
prefix = (__be32 *)template;

packing(injection, &bypass, 127, 127, OCELOT_TAG_LEN, PACK, 0);
packing(injection, &dest, 68, 56, OCELOT_TAG_LEN, PACK, 0);
packing(injection, &src, 46, 43, OCELOT_TAG_LEN, PACK, 0);

*prefix = cpu_to_be32(0x8880000a);
}

static const struct felix_info felix_info_vsc9959 = {
Expand Down
13 changes: 10 additions & 3 deletions drivers/net/dsa/ocelot/seville_vsc9953.c
Original file line number Diff line number Diff line change
Expand Up @@ -1003,6 +1003,8 @@ static void vsc9953_xmit_template_populate(struct ocelot *ocelot, int port)
struct ocelot_port *ocelot_port = ocelot->ports[port];
u8 *template = ocelot_port->xmit_template;
u64 bypass, dest, src;
__be32 *prefix;
u8 *injection;

/* Set the source port as the CPU port module and not the
* NPI port
Expand All @@ -1011,9 +1013,14 @@ static void vsc9953_xmit_template_populate(struct ocelot *ocelot, int port)
dest = BIT(port);
bypass = true;

packing(template, &bypass, 127, 127, OCELOT_TAG_LEN, PACK, 0);
packing(template, &dest, 67, 57, OCELOT_TAG_LEN, PACK, 0);
packing(template, &src, 46, 43, OCELOT_TAG_LEN, PACK, 0);
injection = template + OCELOT_SHORT_PREFIX_LEN;
prefix = (__be32 *)template;

packing(injection, &bypass, 127, 127, OCELOT_TAG_LEN, PACK, 0);
packing(injection, &dest, 67, 57, OCELOT_TAG_LEN, PACK, 0);
packing(injection, &src, 46, 43, OCELOT_TAG_LEN, PACK, 0);

*prefix = cpu_to_be32(0x88800005);
}

static const struct felix_info seville_info_vsc9953 = {
Expand Down
40 changes: 7 additions & 33 deletions drivers/net/ethernet/mscc/ocelot.c
Original file line number Diff line number Diff line change
Expand Up @@ -1346,22 +1346,14 @@ void ocelot_init_port(struct ocelot *ocelot, int port)
}
EXPORT_SYMBOL(ocelot_init_port);

/* Configure and enable the CPU port module, which is a set of queues.
* If @npi contains a valid port index, the CPU port module is connected
* to the Node Processor Interface (NPI). This is the mode through which
* frames can be injected from and extracted to an external CPU,
* over Ethernet.
/* Configure and enable the CPU port module, which is a set of queues
* accessible through register MMIO, frame DMA or Ethernet (in case
* NPI mode is used).
*/
void ocelot_configure_cpu(struct ocelot *ocelot, int npi,
enum ocelot_tag_prefix injection,
enum ocelot_tag_prefix extraction)
static void ocelot_cpu_port_init(struct ocelot *ocelot)
{
int cpu = ocelot->num_phys_ports;

ocelot->npi = npi;
ocelot->inj_prefix = injection;
ocelot->xtr_prefix = extraction;

/* The unicast destination PGID for the CPU port module is unused */
ocelot_write_rix(ocelot, 0, ANA_PGID_PGID, cpu);
/* Instead set up a multicast destination PGID for traffic copied to
Expand All @@ -1373,39 +1365,20 @@ void ocelot_configure_cpu(struct ocelot *ocelot, int npi,
ANA_PORT_PORT_CFG_PORTID_VAL(cpu),
ANA_PORT_PORT_CFG, cpu);

if (npi >= 0 && npi < ocelot->num_phys_ports) {
ocelot_write(ocelot, QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK_M |
QSYS_EXT_CPU_CFG_EXT_CPU_PORT(npi),
QSYS_EXT_CPU_CFG);

/* Enable NPI port */
ocelot_fields_write(ocelot, npi,
QSYS_SWITCH_PORT_MODE_PORT_ENA, 1);
/* NPI port Injection/Extraction configuration */
ocelot_fields_write(ocelot, npi, SYS_PORT_MODE_INCL_XTR_HDR,
extraction);
ocelot_fields_write(ocelot, npi, SYS_PORT_MODE_INCL_INJ_HDR,
injection);

/* Disable transmission of pause frames */
ocelot_fields_write(ocelot, npi, SYS_PAUSE_CFG_PAUSE_ENA, 0);
}

/* Enable CPU port module */
ocelot_fields_write(ocelot, cpu, QSYS_SWITCH_PORT_MODE_PORT_ENA, 1);
/* CPU port Injection/Extraction configuration */
ocelot_fields_write(ocelot, cpu, SYS_PORT_MODE_INCL_XTR_HDR,
extraction);
ocelot->xtr_prefix);
ocelot_fields_write(ocelot, cpu, SYS_PORT_MODE_INCL_INJ_HDR,
injection);
ocelot->inj_prefix);

/* Configure the CPU port to be VLAN aware */
ocelot_write_gix(ocelot, ANA_PORT_VLAN_CFG_VLAN_VID(0) |
ANA_PORT_VLAN_CFG_VLAN_AWARE_ENA |
ANA_PORT_VLAN_CFG_VLAN_POP_CNT(1),
ANA_PORT_VLAN_CFG, cpu);
}
EXPORT_SYMBOL(ocelot_configure_cpu);

int ocelot_init(struct ocelot *ocelot)
{
Expand Down Expand Up @@ -1445,6 +1418,7 @@ int ocelot_init(struct ocelot *ocelot)
ocelot_mact_init(ocelot);
ocelot_vlan_init(ocelot);
ocelot_vcap_init(ocelot);
ocelot_cpu_port_init(ocelot);

for (port = 0; port < ocelot->num_phys_ports; port++) {
/* Clear all counters (5 groups) */
Expand Down
7 changes: 3 additions & 4 deletions drivers/net/ethernet/mscc/ocelot_vsc7514.c
Original file line number Diff line number Diff line change
Expand Up @@ -930,10 +930,6 @@ static int mscc_ocelot_init_ports(struct platform_device *pdev,
if (!ocelot->ports)
return -ENOMEM;

/* No NPI port */
ocelot_configure_cpu(ocelot, -1, OCELOT_TAG_PREFIX_NONE,
OCELOT_TAG_PREFIX_NONE);

for_each_available_child_of_node(ports, portnp) {
struct ocelot_port_private *priv;
struct ocelot_port *ocelot_port;
Expand Down Expand Up @@ -1120,6 +1116,9 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
ocelot->vcap_is2_keys = vsc7514_vcap_is2_keys;
ocelot->vcap_is2_actions = vsc7514_vcap_is2_actions;
ocelot->vcap = vsc7514_vcap_props;
ocelot->inj_prefix = OCELOT_TAG_PREFIX_NONE;
ocelot->xtr_prefix = OCELOT_TAG_PREFIX_NONE;
ocelot->npi = -1;

err = ocelot_init(ocelot);
if (err)
Expand Down
37 changes: 35 additions & 2 deletions include/net/dsa.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ struct dsa_device_ops {
struct sk_buff *(*xmit)(struct sk_buff *skb, struct net_device *dev);
struct sk_buff *(*rcv)(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pt);
int (*flow_dissect)(const struct sk_buff *skb, __be16 *proto,
int *offset);
void (*flow_dissect)(const struct sk_buff *skb, __be16 *proto,
int *offset);
/* Used to determine which traffic should match the DSA filter in
* eth_type_trans, and which, if any, should bypass it and be processed
* as regular on the master net device.
Expand All @@ -84,6 +84,13 @@ struct dsa_device_ops {
unsigned int overhead;
const char *name;
enum dsa_tag_protocol proto;
/* Some tagging protocols either mangle or shift the destination MAC
* address, in which case the DSA master would drop packets on ingress
* if what it understands out of the destination MAC address is not in
* its RX filter.
*/
bool promisc_on_master;
bool tail_tag;
};

/* This structure defines the control interfaces that are overlayed by the
Expand Down Expand Up @@ -705,6 +712,32 @@ static inline bool dsa_can_decode(const struct sk_buff *skb,
return false;
}

/* All DSA tags that push the EtherType to the right (basically all except tail
* tags, which don't break dissection) can be treated the same from the
* perspective of the flow dissector.
*
* We need to return:
* - offset: the (B - A) difference between:
* A. the position of the real EtherType and
* B. the current skb->data (aka ETH_HLEN bytes into the frame, aka 2 bytes
* after the normal EtherType was supposed to be)
* The offset in bytes is exactly equal to the tagger overhead (and half of
* that, in __be16 shorts).
*
* - proto: the value of the real EtherType.
*/
static inline void dsa_tag_generic_flow_dissect(const struct sk_buff *skb,
__be16 *proto, int *offset)
{
#if IS_ENABLED(CONFIG_NET_DSA)
const struct dsa_device_ops *ops = skb->dev->dsa_ptr->tag_ops;
int tag_len = ops->overhead;

*offset = tag_len;
*proto = ((__be16 *)skb->data)[(tag_len / 2) - 1];
#endif
}

#if IS_ENABLED(CONFIG_NET_DSA)
static inline int __dsa_netdevice_ops_check(struct net_device *dev)
{
Expand Down
4 changes: 1 addition & 3 deletions include/soc/mscc/ocelot.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
#define OCELOT_TAG_LEN 16
#define OCELOT_SHORT_PREFIX_LEN 4
#define OCELOT_LONG_PREFIX_LEN 16
#define OCELOT_TOTAL_TAG_LEN (OCELOT_SHORT_PREFIX_LEN + OCELOT_TAG_LEN)

#define OCELOT_SPEED_2500 0
#define OCELOT_SPEED_1000 1
Expand Down Expand Up @@ -672,9 +673,6 @@ void __ocelot_rmw_ix(struct ocelot *ocelot, u32 val, u32 mask, u32 reg,
int ocelot_regfields_init(struct ocelot *ocelot,
const struct reg_field *const regfields);
struct regmap *ocelot_regmap_init(struct ocelot *ocelot, struct resource *res);
void ocelot_configure_cpu(struct ocelot *ocelot, int npi,
enum ocelot_tag_prefix injection,
enum ocelot_tag_prefix extraction);
int ocelot_init(struct ocelot *ocelot);
void ocelot_deinit(struct ocelot *ocelot);
void ocelot_init_port(struct ocelot *ocelot, int port);
Expand Down
10 changes: 8 additions & 2 deletions net/core/flow_dissector.c
Original file line number Diff line number Diff line change
Expand Up @@ -932,8 +932,14 @@ bool __skb_flow_dissect(const struct net *net,
int offset = 0;

ops = skb->dev->dsa_ptr->tag_ops;
if (ops->flow_dissect &&
!ops->flow_dissect(skb, &proto, &offset)) {
/* Tail taggers don't break flow dissection */
if (!ops->tail_tag) {
if (ops->flow_dissect)
ops->flow_dissect(skb, &proto, &offset);
else
dsa_tag_generic_flow_dissect(skb,
&proto,
&offset);
hlen -= offset;
nhoff += offset;
}
Expand Down
20 changes: 19 additions & 1 deletion net/dsa/master.c
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,18 @@ static void dsa_netdev_ops_set(struct net_device *dev,
dev->dsa_ptr->netdev_ops = ops;
}

static void dsa_master_set_promiscuity(struct net_device *dev, int inc)
{
const struct dsa_device_ops *ops = dev->dsa_ptr->tag_ops;

if (!ops->promisc_on_master)
return;

rtnl_lock();
dev_set_promiscuity(dev, inc);
rtnl_unlock();
}

static ssize_t tagging_show(struct device *d, struct device_attribute *attr,
char *buf)
{
Expand Down Expand Up @@ -314,9 +326,12 @@ int dsa_master_setup(struct net_device *dev, struct dsa_port *cpu_dp)
dev->dsa_ptr = cpu_dp;
lockdep_set_class(&dev->addr_list_lock,
&dsa_master_addr_list_lock_key);

dsa_master_set_promiscuity(dev, 1);

ret = dsa_master_ethtool_setup(dev);
if (ret)
return ret;
goto out_err_reset_promisc;

dsa_netdev_ops_set(dev, &dsa_netdev_ops);

Expand All @@ -329,6 +344,8 @@ int dsa_master_setup(struct net_device *dev, struct dsa_port *cpu_dp)
out_err_ndo_teardown:
dsa_netdev_ops_set(dev, NULL);
dsa_master_ethtool_teardown(dev);
out_err_reset_promisc:
dsa_master_set_promiscuity(dev, -1);
return ret;
}

Expand All @@ -338,6 +355,7 @@ void dsa_master_teardown(struct net_device *dev)
dsa_netdev_ops_set(dev, NULL);
dsa_master_ethtool_teardown(dev);
dsa_master_reset_mtu(dev);
dsa_master_set_promiscuity(dev, -1);

dev->dsa_ptr = NULL;

Expand Down
Loading

0 comments on commit dfa6692

Please sign in to comment.