[net-next,14/15] net: mscc: ocelot: split assignment of the cpu port into a separate function
diff mbox series

Message ID 20191109130301.13716-15-olteanv@gmail.com
State Accepted
Delegated to: David Miller
Headers show
Series
  • Accomodate DSA front-end into Ocelot
Related show

Commit Message

Vladimir Oltean Nov. 9, 2019, 1:03 p.m. UTC
From: Vladimir Oltean <vladimir.oltean@nxp.com>

Now that the places that configure routing destinations for the CPU port
have been marked as such, allow callers to specify their own CPU port
that is different than ocelot->num_phys_ports. A user will be the Felix
DSA driver, where the CPU port is one of the physical ports (NPI mode).

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
 drivers/net/ethernet/mscc/ocelot.c       | 65 ++++++++++++++++--------
 drivers/net/ethernet/mscc/ocelot.h       | 12 +++++
 drivers/net/ethernet/mscc/ocelot_board.c |  2 +
 3 files changed, 57 insertions(+), 22 deletions(-)

Comments

Andrew Lunn Nov. 10, 2019, 4:32 p.m. UTC | #1
> +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
Vladimir Oltean Nov. 10, 2019, 4:40 p.m. UTC | #2
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.
Vladimir Oltean Nov. 10, 2019, 4:50 p.m. UTC | #3
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.

Patch
diff mbox series

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;