Message ID | 20191109130301.13716-15-olteanv@gmail.com |
---|---|
State | Accepted |
Delegated to: | David Miller |
Headers | show |
Series | Accomodate DSA front-end into Ocelot | expand |
> +void ocelot_set_cpu_port(struct ocelot *ocelot, int cpu, > + enum ocelot_tag_prefix injection, > + enum ocelot_tag_prefix extraction) > +{ > + /* Configure and enable the CPU port. */ > + ocelot_write_rix(ocelot, 0, ANA_PGID_PGID, cpu); > + ocelot_write_rix(ocelot, BIT(cpu), ANA_PGID_PGID, PGID_CPU); > + ocelot_write_gix(ocelot, ANA_PORT_PORT_CFG_RECV_ENA | > + ANA_PORT_PORT_CFG_PORTID_VAL(cpu), > + ANA_PORT_PORT_CFG, cpu); > + > + /* If the CPU port is a physical port, set up the port in Node > + * Processor Interface (NPI) mode. This is the mode through which > + * frames can be injected from and extracted to an external CPU. > + * Only one port can be an NPI at the same time. > + */ > + if (cpu < ocelot->num_phys_ports) { > + ocelot_write(ocelot, QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK_M | > + QSYS_EXT_CPU_CFG_EXT_CPU_PORT(cpu), > + QSYS_EXT_CPU_CFG); > + } If a port is not a physical port, what is it? Is it actually an error if the CPU port is not physical? Should we be returning -EINVAL here, indicating the device tree is bad? Andrew
On Sun, 10 Nov 2019 at 18:32, Andrew Lunn <andrew@lunn.ch> wrote: > > > +void ocelot_set_cpu_port(struct ocelot *ocelot, int cpu, > > + enum ocelot_tag_prefix injection, > > + enum ocelot_tag_prefix extraction) > > +{ > > + /* Configure and enable the CPU port. */ > > + ocelot_write_rix(ocelot, 0, ANA_PGID_PGID, cpu); > > + ocelot_write_rix(ocelot, BIT(cpu), ANA_PGID_PGID, PGID_CPU); > > + ocelot_write_gix(ocelot, ANA_PORT_PORT_CFG_RECV_ENA | > > + ANA_PORT_PORT_CFG_PORTID_VAL(cpu), > > + ANA_PORT_PORT_CFG, cpu); > > + > > + /* If the CPU port is a physical port, set up the port in Node > > + * Processor Interface (NPI) mode. This is the mode through which > > + * frames can be injected from and extracted to an external CPU. > > + * Only one port can be an NPI at the same time. > > + */ > > + if (cpu < ocelot->num_phys_ports) { > > + ocelot_write(ocelot, QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK_M | > > + QSYS_EXT_CPU_CFG_EXT_CPU_PORT(cpu), > > + QSYS_EXT_CPU_CFG); > > + } > > If a port is not a physical port, what is it? Is it actually an error > if the CPU port is not physical? Should we be returning -EINVAL here, > indicating the device tree is bad? > > Andrew The Vitesse switches have a number of "physical" ports and a number of "CPU" ports. By "port", one understands a target in the queuing subsystem, with learning, flooding, forwarding, etc. The CPU ports that are not physical don't have an 802.3 MAC. Then frame transfer happens over DMA from its queues, PIO, etc (depending on SoC integration). In the LS1028A SoC instantiation of the Felix switch (which is an instantiation of the Ocelot core with less ports and support for TSN), the CPU port _is_ physical (aka is a MAC connected back-to-back to an ENETC DSA master), and that is what is being understood by NPI mode.
On Sun, 10 Nov 2019 at 18:40, Vladimir Oltean <olteanv@gmail.com> wrote: > > On Sun, 10 Nov 2019 at 18:32, Andrew Lunn <andrew@lunn.ch> wrote: > > > > > +void ocelot_set_cpu_port(struct ocelot *ocelot, int cpu, > > > + enum ocelot_tag_prefix injection, > > > + enum ocelot_tag_prefix extraction) > > > +{ > > > + /* Configure and enable the CPU port. */ > > > + ocelot_write_rix(ocelot, 0, ANA_PGID_PGID, cpu); > > > + ocelot_write_rix(ocelot, BIT(cpu), ANA_PGID_PGID, PGID_CPU); > > > + ocelot_write_gix(ocelot, ANA_PORT_PORT_CFG_RECV_ENA | > > > + ANA_PORT_PORT_CFG_PORTID_VAL(cpu), > > > + ANA_PORT_PORT_CFG, cpu); > > > + > > > + /* If the CPU port is a physical port, set up the port in Node > > > + * Processor Interface (NPI) mode. This is the mode through which > > > + * frames can be injected from and extracted to an external CPU. > > > + * Only one port can be an NPI at the same time. > > > + */ > > > + if (cpu < ocelot->num_phys_ports) { > > > + ocelot_write(ocelot, QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK_M | > > > + QSYS_EXT_CPU_CFG_EXT_CPU_PORT(cpu), > > > + QSYS_EXT_CPU_CFG); > > > + } > > > > If a port is not a physical port, what is it? Is it actually an error > > if the CPU port is not physical? Should we be returning -EINVAL here, > > indicating the device tree is bad? > > > > Andrew > > The Vitesse switches have a number of "physical" ports and a number of > "CPU" ports. By "port", one understands a target in the queuing > subsystem, with learning, flooding, forwarding, etc. The CPU ports > that are not physical don't have an 802.3 MAC. Then frame transfer > happens over DMA from its queues, PIO, etc (depending on SoC > integration). In the LS1028A SoC instantiation of the Felix switch > (which is an instantiation of the Ocelot core with less ports and > support for TSN), the CPU port _is_ physical (aka is a MAC connected > back-to-back to an ENETC DSA master), and that is what is being > understood by NPI mode. If this is still confusing, take for example Ocelot (http://ww1.microchip.com/downloads/en/DeviceDoc/VMDS-10491.pdf). The physical ports are 0-9, and the CPU ports are 10 and 11. So the ocelot driver was hardcoding the CPU port to 10, which is the first port outside the num_phys_ports range. I don't expect any caller to specify an invalid CPU port, so returning -EINVAL would just be overhead here. Neither of the 2 entry points of this function (one in mainline, one as a currently downstream patch) can. The Ocelot SoC driver (ocelot_board.c) always sets port #10 as CPU port, which is legit, and the Felix driver always sets one of the physical ports as CPU port, which again is legit.
diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 7f0bd89fc363..bba6d60dc5a8 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -380,12 +380,6 @@ static void ocelot_vlan_init(struct ocelot *ocelot) ocelot->vlan_mask[0] = GENMASK(ocelot->num_phys_ports - 1, 0); ocelot_vlant_set_mask(ocelot, 0, ocelot->vlan_mask[0]); - /* 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, ocelot->num_phys_ports); - /* Set vlan ingress filter mask to all ports but the CPU port by * default. */ @@ -2224,11 +2218,52 @@ int ocelot_probe_port(struct ocelot *ocelot, u8 port, } EXPORT_SYMBOL(ocelot_probe_port); +void ocelot_set_cpu_port(struct ocelot *ocelot, int cpu, + enum ocelot_tag_prefix injection, + enum ocelot_tag_prefix extraction) +{ + /* Configure and enable the CPU port. */ + ocelot_write_rix(ocelot, 0, ANA_PGID_PGID, cpu); + ocelot_write_rix(ocelot, BIT(cpu), ANA_PGID_PGID, PGID_CPU); + ocelot_write_gix(ocelot, ANA_PORT_PORT_CFG_RECV_ENA | + ANA_PORT_PORT_CFG_PORTID_VAL(cpu), + ANA_PORT_PORT_CFG, cpu); + + /* If the CPU port is a physical port, set up the port in Node + * Processor Interface (NPI) mode. This is the mode through which + * frames can be injected from and extracted to an external CPU. + * Only one port can be an NPI at the same time. + */ + if (cpu < ocelot->num_phys_ports) { + ocelot_write(ocelot, QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK_M | + QSYS_EXT_CPU_CFG_EXT_CPU_PORT(cpu), + QSYS_EXT_CPU_CFG); + } + + /* CPU port Injection/Extraction configuration */ + ocelot_write_rix(ocelot, QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE | + QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG(1) | + QSYS_SWITCH_PORT_MODE_PORT_ENA, + QSYS_SWITCH_PORT_MODE, cpu); + ocelot_write_rix(ocelot, SYS_PORT_MODE_INCL_XTR_HDR(extraction) | + SYS_PORT_MODE_INCL_INJ_HDR(injection), + SYS_PORT_MODE, cpu); + + /* 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); + + ocelot->cpu = cpu; +} +EXPORT_SYMBOL(ocelot_set_cpu_port); + int ocelot_init(struct ocelot *ocelot) { - u32 port; - int i, ret, cpu = ocelot->num_phys_ports; char queue_name[32]; + int i, ret; + u32 port; ocelot->lags = devm_kcalloc(ocelot->dev, ocelot->num_phys_ports, sizeof(u32), GFP_KERNEL); @@ -2308,13 +2343,6 @@ int ocelot_init(struct ocelot *ocelot) ocelot_write_rix(ocelot, 0, ANA_PGID_PGID, PGID_SRC + port); } - /* Configure and enable the CPU port. */ - ocelot_write_rix(ocelot, 0, ANA_PGID_PGID, cpu); - ocelot_write_rix(ocelot, BIT(cpu), ANA_PGID_PGID, PGID_CPU); - ocelot_write_gix(ocelot, ANA_PORT_PORT_CFG_RECV_ENA | - ANA_PORT_PORT_CFG_PORTID_VAL(cpu), - ANA_PORT_PORT_CFG, cpu); - /* Allow broadcast MAC frames. */ for (i = ocelot->num_phys_ports + 1; i < PGID_CPU; i++) { u32 val = ANA_PGID_PGID_PGID(GENMASK(ocelot->num_phys_ports - 1, 0)); @@ -2327,13 +2355,6 @@ int ocelot_init(struct ocelot *ocelot) ocelot_write_rix(ocelot, 0, ANA_PGID_PGID, PGID_MCIPV4); ocelot_write_rix(ocelot, 0, ANA_PGID_PGID, PGID_MCIPV6); - /* CPU port Injection/Extraction configuration */ - ocelot_write_rix(ocelot, QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE | - QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG(1) | - QSYS_SWITCH_PORT_MODE_PORT_ENA, - QSYS_SWITCH_PORT_MODE, cpu); - ocelot_write_rix(ocelot, SYS_PORT_MODE_INCL_XTR_HDR(1) | - SYS_PORT_MODE_INCL_INJ_HDR(1), SYS_PORT_MODE, cpu); /* Allow manual injection via DEVCPU_QS registers, and byte swap these * registers endianness. */ diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h index 7f3526151fa9..4d8e769ccad9 100644 --- a/drivers/net/ethernet/mscc/ocelot.h +++ b/drivers/net/ethernet/mscc/ocelot.h @@ -427,6 +427,13 @@ struct ocelot_multicast { u16 ports; }; +enum ocelot_tag_prefix { + OCELOT_TAG_PREFIX_DISABLED = 0, + OCELOT_TAG_PREFIX_NONE, + OCELOT_TAG_PREFIX_SHORT, + OCELOT_TAG_PREFIX_LONG, +}; + struct ocelot_port; struct ocelot_stat_layout { @@ -455,6 +462,7 @@ struct ocelot { u8 num_phys_ports; u8 num_cpu_ports; + u8 cpu; struct ocelot_port **ports; u32 *lags; @@ -552,6 +560,10 @@ int ocelot_probe_port(struct ocelot *ocelot, u8 port, void __iomem *regs, struct phy_device *phy); +void ocelot_set_cpu_port(struct ocelot *ocelot, int cpu, + enum ocelot_tag_prefix injection, + enum ocelot_tag_prefix extraction); + extern struct notifier_block ocelot_netdevice_nb; extern struct notifier_block ocelot_switchdev_nb; extern struct notifier_block ocelot_switchdev_blocking_nb; diff --git a/drivers/net/ethernet/mscc/ocelot_board.c b/drivers/net/ethernet/mscc/ocelot_board.c index 9985fb334aac..811599f32910 100644 --- a/drivers/net/ethernet/mscc/ocelot_board.c +++ b/drivers/net/ethernet/mscc/ocelot_board.c @@ -365,6 +365,8 @@ static int mscc_ocelot_probe(struct platform_device *pdev) sizeof(struct ocelot_port *), GFP_KERNEL); ocelot_init(ocelot); + ocelot_set_cpu_port(ocelot, ocelot->num_phys_ports, + OCELOT_TAG_PREFIX_NONE, OCELOT_TAG_PREFIX_NONE); for_each_available_child_of_node(ports, portnp) { struct ocelot_port_private *priv;