netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 net-next 00/10] Configuring congestion watermarks on ocelot switch using devlink-sb
@ 2021-01-08 17:59 Vladimir Oltean
  2021-01-08 17:59 ` [PATCH v3 net-next 01/10] net: mscc: ocelot: auto-detect packet buffer size and number of frame references Vladimir Oltean
                   ` (9 more replies)
  0 siblings, 10 replies; 36+ messages in thread
From: Vladimir Oltean @ 2021-01-08 17:59 UTC (permalink / raw)
  To: netdev
  Cc: alexandre.belloni, andrew, f.fainelli, vivien.didelot,
	alexandru.marginean, claudiu.manoil, xiaoliang.yang_1,
	hongbo.wang, kuba, jiri, idosch, UNGLinuxDriver

From: Vladimir Oltean <vladimir.oltean@nxp.com>

In some applications, it is important to create resource reservations in
the Ethernet switches, to prevent background traffic, or deliberate
attacks, from inducing denial of service into the high-priority traffic.

These patches give the user some knobs to turn. The ocelot switches
support per-port and per-port-tc reservations, on ingress and on egress.
The resources that are monitored are packet buffers (in cells of 60
bytes each) and frame references.

The frames that exceed the reservations can optionally consume from
sharing watermarks which are not per-port but global across the switch.
There are 10 sharing watermarks, 8 of them are per traffic class and 2
are per drop priority.

I am configuring the hardware using the best of my knowledge, and mostly
through trial and error. Same goes for devlink-sb integration. Feedback
is welcome.

Vladimir Oltean (10):
  net: mscc: ocelot: auto-detect packet buffer size and number of frame
    references
  net: mscc: ocelot: add ops for decoding watermark threshold and
    occupancy
  net: dsa: add ops for devlink-sb
  net: dsa: felix: reindent struct dsa_switch_ops
  net: dsa: felix: perform teardown in reverse order of setup
  net: mscc: ocelot: export NUM_TC constant from felix to common switch
    lib
  net: mscc: ocelot: delete unused ocelot_set_cpu_port prototype
  net: mscc: ocelot: register devlink ports
  net: mscc: ocelot: initialize watermarks to sane defaults
  net: mscc: ocelot: configure watermarks using devlink-sb

 drivers/net/dsa/ocelot/felix.c             | 210 +++--
 drivers/net/dsa/ocelot/felix.h             |   2 -
 drivers/net/dsa/ocelot/felix_vsc9959.c     |  23 +-
 drivers/net/dsa/ocelot/seville_vsc9953.c   |  20 +-
 drivers/net/ethernet/mscc/Makefile         |   3 +-
 drivers/net/ethernet/mscc/ocelot.c         |  18 +-
 drivers/net/ethernet/mscc/ocelot.h         |   8 +-
 drivers/net/ethernet/mscc/ocelot_devlink.c | 885 +++++++++++++++++++++
 drivers/net/ethernet/mscc/ocelot_net.c     | 282 ++++++-
 drivers/net/ethernet/mscc/ocelot_vsc7514.c |  47 +-
 include/net/dsa.h                          |  34 +
 include/soc/mscc/ocelot.h                  |  54 +-
 include/soc/mscc/ocelot_qsys.h             |   7 +-
 net/dsa/dsa2.c                             | 159 +++-
 14 files changed, 1657 insertions(+), 95 deletions(-)
 create mode 100644 drivers/net/ethernet/mscc/ocelot_devlink.c

-- 
2.25.1


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH v3 net-next 01/10] net: mscc: ocelot: auto-detect packet buffer size and number of frame references
  2021-01-08 17:59 [PATCH v3 net-next 00/10] Configuring congestion watermarks on ocelot switch using devlink-sb Vladimir Oltean
@ 2021-01-08 17:59 ` Vladimir Oltean
  2021-01-08 18:30   ` Florian Fainelli
  2021-01-08 17:59 ` [PATCH v3 net-next 02/10] net: mscc: ocelot: add ops for decoding watermark threshold and occupancy Vladimir Oltean
                   ` (8 subsequent siblings)
  9 siblings, 1 reply; 36+ messages in thread
From: Vladimir Oltean @ 2021-01-08 17:59 UTC (permalink / raw)
  To: netdev
  Cc: alexandre.belloni, andrew, f.fainelli, vivien.didelot,
	alexandru.marginean, claudiu.manoil, xiaoliang.yang_1,
	hongbo.wang, kuba, jiri, idosch, UNGLinuxDriver

From: Vladimir Oltean <vladimir.oltean@nxp.com>

Instead of reading these values from the reference manual and writing
them down into the driver, it appears that the hardware gives us the
option of detecting them dynamically.

The number of frame references corresponds to what the reference manual
notes, however it seems that the frame buffers are reported as slightly
less than the books would indicate. On VSC9959 (Felix), the books say it
should have 128KB of packet buffer, but the registers indicate only
129840 bytes (126.79 KB). Also, the unit of measurement for FREECNT from
the documentation of all these devices is incorrect (taken from an older
generation). This was confirmed by Younes Leroul from Microchip support.

Not having anything better to do with these values at the moment* (this
will change soon), let's just print them.

*The frame buffer size is, in fact, used to calculate the tail dropping
watermarks.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
Changes in v3:
None.

Changes in v2:
- Fixed FREECNT multiplier after consulting with Microchip support.

 drivers/net/dsa/ocelot/felix.c             |  1 -
 drivers/net/dsa/ocelot/felix.h             |  1 -
 drivers/net/dsa/ocelot/felix_vsc9959.c     |  1 -
 drivers/net/dsa/ocelot/seville_vsc9953.c   |  1 -
 drivers/net/ethernet/mscc/ocelot.c         | 22 +++++++++++++++++++++-
 drivers/net/ethernet/mscc/ocelot_vsc7514.c |  1 -
 include/soc/mscc/ocelot.h                  |  3 ++-
 include/soc/mscc/ocelot_qsys.h             |  3 +++
 8 files changed, 26 insertions(+), 7 deletions(-)

diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c
index 90c3c76f21b2..a2e06a0d1509 100644
--- a/drivers/net/dsa/ocelot/felix.c
+++ b/drivers/net/dsa/ocelot/felix.c
@@ -451,7 +451,6 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports)
 	ocelot->map		= felix->info->map;
 	ocelot->stats_layout	= felix->info->stats_layout;
 	ocelot->num_stats	= felix->info->num_stats;
-	ocelot->shared_queue_sz	= felix->info->shared_queue_sz;
 	ocelot->num_mact_rows	= felix->info->num_mact_rows;
 	ocelot->vcap		= felix->info->vcap;
 	ocelot->ops		= felix->info->ops;
diff --git a/drivers/net/dsa/ocelot/felix.h b/drivers/net/dsa/ocelot/felix.h
index 4c717324ac2f..5434fe278d2c 100644
--- a/drivers/net/dsa/ocelot/felix.h
+++ b/drivers/net/dsa/ocelot/felix.h
@@ -15,7 +15,6 @@ struct felix_info {
 	const struct reg_field		*regfields;
 	const u32 *const		*map;
 	const struct ocelot_ops		*ops;
-	int				shared_queue_sz;
 	int				num_mact_rows;
 	const struct ocelot_stat_layout	*stats_layout;
 	unsigned int			num_stats;
diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c
index 2e5bbdca5ea4..9fffbad6ef9b 100644
--- a/drivers/net/dsa/ocelot/felix_vsc9959.c
+++ b/drivers/net/dsa/ocelot/felix_vsc9959.c
@@ -1356,7 +1356,6 @@ static const struct felix_info felix_info_vsc9959 = {
 	.stats_layout		= vsc9959_stats_layout,
 	.num_stats		= ARRAY_SIZE(vsc9959_stats_layout),
 	.vcap			= vsc9959_vcap_props,
-	.shared_queue_sz	= 128 * 1024,
 	.num_mact_rows		= 2048,
 	.num_ports		= 6,
 	.num_tx_queues		= FELIX_NUM_TC,
diff --git a/drivers/net/dsa/ocelot/seville_vsc9953.c b/drivers/net/dsa/ocelot/seville_vsc9953.c
index ebbaf6817ec8..b72813da6d9f 100644
--- a/drivers/net/dsa/ocelot/seville_vsc9953.c
+++ b/drivers/net/dsa/ocelot/seville_vsc9953.c
@@ -1181,7 +1181,6 @@ static const struct felix_info seville_info_vsc9953 = {
 	.stats_layout		= vsc9953_stats_layout,
 	.num_stats		= ARRAY_SIZE(vsc9953_stats_layout),
 	.vcap			= vsc9953_vcap_props,
-	.shared_queue_sz	= 256 * 1024,
 	.num_mact_rows		= 2048,
 	.num_ports		= 10,
 	.mdio_bus_alloc		= vsc9953_mdio_bus_alloc,
diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c
index 0b9992bd6626..876c03e51bdc 100644
--- a/drivers/net/ethernet/mscc/ocelot.c
+++ b/drivers/net/ethernet/mscc/ocelot.c
@@ -1366,7 +1366,7 @@ void ocelot_port_set_maxlen(struct ocelot *ocelot, int port, size_t sdu)
 			    pause_stop);
 
 	/* Tail dropping watermarks */
-	atop_tot = (ocelot->shared_queue_sz - 9 * maxlen) /
+	atop_tot = (ocelot->packet_buffer_size - 9 * maxlen) /
 		   OCELOT_BUFFER_CELL_SZ;
 	atop = (9 * maxlen) / OCELOT_BUFFER_CELL_SZ;
 	ocelot_write_rix(ocelot, ocelot->ops->wm_enc(atop), SYS_ATOP, port);
@@ -1479,6 +1479,25 @@ static void ocelot_cpu_port_init(struct ocelot *ocelot)
 			 ANA_PORT_VLAN_CFG, cpu);
 }
 
+static void ocelot_detect_features(struct ocelot *ocelot)
+{
+	int mmgt, eq_ctrl;
+
+	/* For Ocelot, Felix, Seville, Serval etc, SYS:MMGT:MMGT:FREECNT holds
+	 * the number of 240-byte free memory words (aka 4-cell chunks) and not
+	 * 192 bytes as the documentation incorrectly says.
+	 */
+	mmgt = ocelot_read(ocelot, SYS_MMGT);
+	ocelot->packet_buffer_size = 240 * SYS_MMGT_FREECNT(mmgt);
+
+	eq_ctrl = ocelot_read(ocelot, QSYS_EQ_CTRL);
+	ocelot->num_frame_refs = QSYS_MMGT_EQ_CTRL_FP_FREE_CNT(eq_ctrl);
+
+	dev_info(ocelot->dev,
+		 "Detected %d bytes of packet buffer and %d frame references\n",
+		 ocelot->packet_buffer_size, ocelot->num_frame_refs);
+}
+
 int ocelot_init(struct ocelot *ocelot)
 {
 	char queue_name[32];
@@ -1521,6 +1540,7 @@ int ocelot_init(struct ocelot *ocelot)
 
 	INIT_LIST_HEAD(&ocelot->multicast);
 	INIT_LIST_HEAD(&ocelot->pgids);
+	ocelot_detect_features(ocelot);
 	ocelot_mact_init(ocelot);
 	ocelot_vlan_init(ocelot);
 	ocelot_vcap_init(ocelot);
diff --git a/drivers/net/ethernet/mscc/ocelot_vsc7514.c b/drivers/net/ethernet/mscc/ocelot_vsc7514.c
index 9cf2bc5f4289..7135ad18affe 100644
--- a/drivers/net/ethernet/mscc/ocelot_vsc7514.c
+++ b/drivers/net/ethernet/mscc/ocelot_vsc7514.c
@@ -517,7 +517,6 @@ static int ocelot_chip_init(struct ocelot *ocelot, const struct ocelot_ops *ops)
 	ocelot->map = ocelot_regmap;
 	ocelot->stats_layout = ocelot_stats_layout;
 	ocelot->num_stats = ARRAY_SIZE(ocelot_stats_layout);
-	ocelot->shared_queue_sz = 224 * 1024;
 	ocelot->num_mact_rows = 1024;
 	ocelot->ops = ops;
 
diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h
index 2f4cd3288bcc..c6c131142195 100644
--- a/include/soc/mscc/ocelot.h
+++ b/include/soc/mscc/ocelot.h
@@ -607,7 +607,8 @@ struct ocelot {
 	const struct ocelot_stat_layout	*stats_layout;
 	unsigned int			num_stats;
 
-	int				shared_queue_sz;
+	int				packet_buffer_size;
+	int				num_frame_refs;
 	int				num_mact_rows;
 
 	struct net_device		*hw_bridge_dev;
diff --git a/include/soc/mscc/ocelot_qsys.h b/include/soc/mscc/ocelot_qsys.h
index a814bc2017d8..b7b263a19068 100644
--- a/include/soc/mscc/ocelot_qsys.h
+++ b/include/soc/mscc/ocelot_qsys.h
@@ -77,6 +77,9 @@
 #define QSYS_RES_STAT_MAXUSE(x)                           ((x) & GENMASK(11, 0))
 #define QSYS_RES_STAT_MAXUSE_M                            GENMASK(11, 0)
 
+#define QSYS_MMGT_EQ_CTRL_FP_FREE_CNT(x)                  ((x) & GENMASK(15, 0))
+#define QSYS_MMGT_EQ_CTRL_FP_FREE_CNT_M                   GENMASK(15, 0)
+
 #define QSYS_EVENTS_CORE_EV_FDC(x)                        (((x) << 2) & GENMASK(4, 2))
 #define QSYS_EVENTS_CORE_EV_FDC_M                         GENMASK(4, 2)
 #define QSYS_EVENTS_CORE_EV_FDC_X(x)                      (((x) & GENMASK(4, 2)) >> 2)
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v3 net-next 02/10] net: mscc: ocelot: add ops for decoding watermark threshold and occupancy
  2021-01-08 17:59 [PATCH v3 net-next 00/10] Configuring congestion watermarks on ocelot switch using devlink-sb Vladimir Oltean
  2021-01-08 17:59 ` [PATCH v3 net-next 01/10] net: mscc: ocelot: auto-detect packet buffer size and number of frame references Vladimir Oltean
@ 2021-01-08 17:59 ` Vladimir Oltean
  2021-01-08 18:30   ` Florian Fainelli
  2021-01-10  1:20   ` Jakub Kicinski
  2021-01-08 17:59 ` [PATCH v3 net-next 03/10] net: dsa: add ops for devlink-sb Vladimir Oltean
                   ` (7 subsequent siblings)
  9 siblings, 2 replies; 36+ messages in thread
From: Vladimir Oltean @ 2021-01-08 17:59 UTC (permalink / raw)
  To: netdev
  Cc: alexandre.belloni, andrew, f.fainelli, vivien.didelot,
	alexandru.marginean, claudiu.manoil, xiaoliang.yang_1,
	hongbo.wang, kuba, jiri, idosch, UNGLinuxDriver

From: Vladimir Oltean <vladimir.oltean@nxp.com>

We'll need to read back the watermark thresholds and occupancy from
hardware (for devlink-sb integration), not only to write them as we did
so far in ocelot_port_set_maxlen. So introduce 2 new functions in struct
ocelot_ops, similar to wm_enc, and implement them for the 3 supported
mscc_ocelot switches.

Remove the INUSE and MAXUSE unpacking helpers for the QSYS_RES_STAT
register, because that doesn't scale with the number of switches that
mscc_ocelot supports now. They have different bit widths for the
watermarks, and we need function pointers to abstract that difference
away.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
Changes in v3:
None.

Changes in v2:
None.

 drivers/net/dsa/ocelot/felix_vsc9959.c     | 18 ++++++++++++++++++
 drivers/net/dsa/ocelot/seville_vsc9953.c   | 18 ++++++++++++++++++
 drivers/net/ethernet/mscc/ocelot_vsc7514.c | 16 ++++++++++++++++
 include/soc/mscc/ocelot.h                  |  2 ++
 include/soc/mscc/ocelot_qsys.h             |  6 ------
 5 files changed, 54 insertions(+), 6 deletions(-)

diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c
index 9fffbad6ef9b..540b86edbbb0 100644
--- a/drivers/net/dsa/ocelot/felix_vsc9959.c
+++ b/drivers/net/dsa/ocelot/felix_vsc9959.c
@@ -1006,9 +1006,27 @@ static u16 vsc9959_wm_enc(u16 value)
 	return value;
 }
 
+static u16 vsc9959_wm_dec(u16 wm)
+{
+	WARN_ON(wm & ~GENMASK(8, 0));
+
+	if (wm & BIT(8))
+		return (wm & GENMASK(7, 0)) * 16;
+
+	return wm;
+}
+
+static void vsc9959_wm_stat(u32 val, u32 *inuse, u32 *maxuse)
+{
+	*inuse = (val & GENMASK(23, 12)) >> 12;
+	*maxuse = val & GENMASK(11, 0);
+}
+
 static const struct ocelot_ops vsc9959_ops = {
 	.reset			= vsc9959_reset,
 	.wm_enc			= vsc9959_wm_enc,
+	.wm_dec			= vsc9959_wm_dec,
+	.wm_stat		= vsc9959_wm_stat,
 	.port_to_netdev		= felix_port_to_netdev,
 	.netdev_to_port		= felix_netdev_to_port,
 };
diff --git a/drivers/net/dsa/ocelot/seville_vsc9953.c b/drivers/net/dsa/ocelot/seville_vsc9953.c
index b72813da6d9f..8dad0c894eca 100644
--- a/drivers/net/dsa/ocelot/seville_vsc9953.c
+++ b/drivers/net/dsa/ocelot/seville_vsc9953.c
@@ -1057,9 +1057,27 @@ static u16 vsc9953_wm_enc(u16 value)
 	return value;
 }
 
+static u16 vsc9953_wm_dec(u16 wm)
+{
+	WARN_ON(wm & ~GENMASK(9, 0));
+
+	if (wm & BIT(9))
+		return (wm & GENMASK(8, 0)) * 16;
+
+	return wm;
+}
+
+static void vsc9953_wm_stat(u32 val, u32 *inuse, u32 *maxuse)
+{
+	*inuse = (val & GENMASK(25, 13)) >> 13;
+	*maxuse = val & GENMASK(12, 0);
+}
+
 static const struct ocelot_ops vsc9953_ops = {
 	.reset			= vsc9953_reset,
 	.wm_enc			= vsc9953_wm_enc,
+	.wm_dec			= vsc9953_wm_dec,
+	.wm_stat		= vsc9953_wm_stat,
 	.port_to_netdev		= felix_port_to_netdev,
 	.netdev_to_port		= felix_netdev_to_port,
 };
diff --git a/drivers/net/ethernet/mscc/ocelot_vsc7514.c b/drivers/net/ethernet/mscc/ocelot_vsc7514.c
index 7135ad18affe..ecd474476cc6 100644
--- a/drivers/net/ethernet/mscc/ocelot_vsc7514.c
+++ b/drivers/net/ethernet/mscc/ocelot_vsc7514.c
@@ -763,9 +763,25 @@ static u16 ocelot_wm_enc(u16 value)
 	return value;
 }
 
+static u16 ocelot_wm_dec(u16 wm)
+{
+	if (wm & BIT(8))
+		return (wm & GENMASK(7, 0)) * 16;
+
+	return wm;
+}
+
+static void ocelot_wm_stat(u32 val, u32 *inuse, u32 *maxuse)
+{
+	*inuse = (val & GENMASK(23, 12)) >> 12;
+	*maxuse = val & GENMASK(11, 0);
+}
+
 static const struct ocelot_ops ocelot_ops = {
 	.reset			= ocelot_reset,
 	.wm_enc			= ocelot_wm_enc,
+	.wm_dec			= ocelot_wm_dec,
+	.wm_stat		= ocelot_wm_stat,
 	.port_to_netdev		= ocelot_port_to_netdev,
 	.netdev_to_port		= ocelot_netdev_to_port,
 };
diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h
index c6c131142195..8eb134cd8d9d 100644
--- a/include/soc/mscc/ocelot.h
+++ b/include/soc/mscc/ocelot.h
@@ -563,6 +563,8 @@ struct ocelot_ops {
 	int (*netdev_to_port)(struct net_device *dev);
 	int (*reset)(struct ocelot *ocelot);
 	u16 (*wm_enc)(u16 value);
+	u16 (*wm_dec)(u16 value);
+	void (*wm_stat)(u32 val, u32 *inuse, u32 *maxuse);
 };
 
 struct ocelot_vcap_block {
diff --git a/include/soc/mscc/ocelot_qsys.h b/include/soc/mscc/ocelot_qsys.h
index b7b263a19068..9731895be643 100644
--- a/include/soc/mscc/ocelot_qsys.h
+++ b/include/soc/mscc/ocelot_qsys.h
@@ -71,12 +71,6 @@
 
 #define QSYS_RES_STAT_GSZ                                 0x8
 
-#define QSYS_RES_STAT_INUSE(x)                            (((x) << 12) & GENMASK(23, 12))
-#define QSYS_RES_STAT_INUSE_M                             GENMASK(23, 12)
-#define QSYS_RES_STAT_INUSE_X(x)                          (((x) & GENMASK(23, 12)) >> 12)
-#define QSYS_RES_STAT_MAXUSE(x)                           ((x) & GENMASK(11, 0))
-#define QSYS_RES_STAT_MAXUSE_M                            GENMASK(11, 0)
-
 #define QSYS_MMGT_EQ_CTRL_FP_FREE_CNT(x)                  ((x) & GENMASK(15, 0))
 #define QSYS_MMGT_EQ_CTRL_FP_FREE_CNT_M                   GENMASK(15, 0)
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v3 net-next 03/10] net: dsa: add ops for devlink-sb
  2021-01-08 17:59 [PATCH v3 net-next 00/10] Configuring congestion watermarks on ocelot switch using devlink-sb Vladimir Oltean
  2021-01-08 17:59 ` [PATCH v3 net-next 01/10] net: mscc: ocelot: auto-detect packet buffer size and number of frame references Vladimir Oltean
  2021-01-08 17:59 ` [PATCH v3 net-next 02/10] net: mscc: ocelot: add ops for decoding watermark threshold and occupancy Vladimir Oltean
@ 2021-01-08 17:59 ` Vladimir Oltean
  2021-01-08 18:20   ` Andrew Lunn
  2021-01-08 18:31   ` Florian Fainelli
  2021-01-08 17:59 ` [PATCH v3 net-next 04/10] net: dsa: felix: reindent struct dsa_switch_ops Vladimir Oltean
                   ` (6 subsequent siblings)
  9 siblings, 2 replies; 36+ messages in thread
From: Vladimir Oltean @ 2021-01-08 17:59 UTC (permalink / raw)
  To: netdev
  Cc: alexandre.belloni, andrew, f.fainelli, vivien.didelot,
	alexandru.marginean, claudiu.manoil, xiaoliang.yang_1,
	hongbo.wang, kuba, jiri, idosch, UNGLinuxDriver

From: Vladimir Oltean <vladimir.oltean@nxp.com>

Switches that care about QoS might have hardware support for reserving
buffer pools for individual ports or traffic classes, and configuring
their sizes and thresholds. Through devlink-sb (shared buffers), this is
all configurable, as well as their occupancy being viewable.

Add the plumbing in DSA for these operations.

Individual drivers still need to call devlink_sb_register() with the
shared buffers they want to expose. A helper was not created in DSA for
this purpose (unlike, say, dsa_devlink_params_register), since in my
opinion it does not bring any benefit over plainly calling
devlink_sb_register() directly.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
Changes in v3:
Use the helpers added by Andrew to convert from devlink and devlink_port
to DSA structures rather than open-coding them.

Changes in v2:
None.

 include/net/dsa.h |  34 ++++++++++
 net/dsa/dsa2.c    | 159 +++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 192 insertions(+), 1 deletion(-)

diff --git a/include/net/dsa.h b/include/net/dsa.h
index 9a0cab5fb7c4..b64fd53d7fce 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -650,6 +650,40 @@ struct dsa_switch_ops {
 	int	(*devlink_info_get)(struct dsa_switch *ds,
 				    struct devlink_info_req *req,
 				    struct netlink_ext_ack *extack);
+	int	(*devlink_sb_pool_get)(struct dsa_switch *ds,
+				       unsigned int sb_index, u16 pool_index,
+				       struct devlink_sb_pool_info *pool_info);
+	int	(*devlink_sb_pool_set)(struct dsa_switch *ds, unsigned int sb_index,
+				       u16 pool_index, u32 size,
+				       enum devlink_sb_threshold_type threshold_type,
+				       struct netlink_ext_ack *extack);
+	int	(*devlink_sb_port_pool_get)(struct dsa_switch *ds, int port,
+					    unsigned int sb_index, u16 pool_index,
+					    u32 *p_threshold);
+	int	(*devlink_sb_port_pool_set)(struct dsa_switch *ds, int port,
+					    unsigned int sb_index, u16 pool_index,
+					    u32 threshold,
+					    struct netlink_ext_ack *extack);
+	int	(*devlink_sb_tc_pool_bind_get)(struct dsa_switch *ds, int port,
+					       unsigned int sb_index, u16 tc_index,
+					       enum devlink_sb_pool_type pool_type,
+					       u16 *p_pool_index, u32 *p_threshold);
+	int	(*devlink_sb_tc_pool_bind_set)(struct dsa_switch *ds, int port,
+					       unsigned int sb_index, u16 tc_index,
+					       enum devlink_sb_pool_type pool_type,
+					       u16 pool_index, u32 threshold,
+					       struct netlink_ext_ack *extack);
+	int	(*devlink_sb_occ_snapshot)(struct dsa_switch *ds,
+					   unsigned int sb_index);
+	int	(*devlink_sb_occ_max_clear)(struct dsa_switch *ds,
+					    unsigned int sb_index);
+	int	(*devlink_sb_occ_port_pool_get)(struct dsa_switch *ds, int port,
+						unsigned int sb_index, u16 pool_index,
+						u32 *p_cur, u32 *p_max);
+	int	(*devlink_sb_occ_tc_port_bind_get)(struct dsa_switch *ds, int port,
+						   unsigned int sb_index, u16 tc_index,
+						   enum devlink_sb_pool_type pool_type,
+						   u32 *p_cur, u32 *p_max);
 
 	/*
 	 * MTU change functionality. Switches can also adjust their MRU through
diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c
index 01f21b0b379a..c05b1b54c4f7 100644
--- a/net/dsa/dsa2.c
+++ b/net/dsa/dsa2.c
@@ -400,8 +400,165 @@ static int dsa_devlink_info_get(struct devlink *dl,
 	return -EOPNOTSUPP;
 }
 
+static int dsa_devlink_sb_pool_get(struct devlink *dl,
+				   unsigned int sb_index, u16 pool_index,
+				   struct devlink_sb_pool_info *pool_info)
+{
+	struct dsa_switch *ds = dsa_devlink_to_ds(dl);
+
+	if (!ds->ops->devlink_sb_pool_get)
+		return -EOPNOTSUPP;
+
+	return ds->ops->devlink_sb_pool_get(ds, sb_index, pool_index,
+					    pool_info);
+}
+
+static int dsa_devlink_sb_pool_set(struct devlink *dl, unsigned int sb_index,
+				   u16 pool_index, u32 size,
+				   enum devlink_sb_threshold_type threshold_type,
+				   struct netlink_ext_ack *extack)
+{
+	struct dsa_switch *ds = dsa_devlink_to_ds(dl);
+
+	if (!ds->ops->devlink_sb_pool_set)
+		return -EOPNOTSUPP;
+
+	return ds->ops->devlink_sb_pool_set(ds, sb_index, pool_index, size,
+					    threshold_type, extack);
+}
+
+static int dsa_devlink_sb_port_pool_get(struct devlink_port *dlp,
+					unsigned int sb_index, u16 pool_index,
+					u32 *p_threshold)
+{
+	struct dsa_switch *ds = dsa_devlink_port_to_ds(dlp);
+	int port = dsa_devlink_port_to_port(dlp);
+
+	if (!ds->ops->devlink_sb_port_pool_get)
+		return -EOPNOTSUPP;
+
+	return ds->ops->devlink_sb_port_pool_get(ds, port, sb_index,
+						 pool_index, p_threshold);
+}
+
+static int dsa_devlink_sb_port_pool_set(struct devlink_port *dlp,
+					unsigned int sb_index, u16 pool_index,
+					u32 threshold,
+					struct netlink_ext_ack *extack)
+{
+	struct dsa_switch *ds = dsa_devlink_port_to_ds(dlp);
+	int port = dsa_devlink_port_to_port(dlp);
+
+	if (!ds->ops->devlink_sb_port_pool_set)
+		return -EOPNOTSUPP;
+
+	return ds->ops->devlink_sb_port_pool_set(ds, port, sb_index,
+						 pool_index, threshold, extack);
+}
+
+static int
+dsa_devlink_sb_tc_pool_bind_get(struct devlink_port *dlp,
+				unsigned int sb_index, u16 tc_index,
+				enum devlink_sb_pool_type pool_type,
+				u16 *p_pool_index, u32 *p_threshold)
+{
+	struct dsa_switch *ds = dsa_devlink_port_to_ds(dlp);
+	int port = dsa_devlink_port_to_port(dlp);
+
+	if (!ds->ops->devlink_sb_tc_pool_bind_get)
+		return -EOPNOTSUPP;
+
+	return ds->ops->devlink_sb_tc_pool_bind_get(ds, port, sb_index,
+						    tc_index, pool_type,
+						    p_pool_index, p_threshold);
+}
+
+static int
+dsa_devlink_sb_tc_pool_bind_set(struct devlink_port *dlp,
+				unsigned int sb_index, u16 tc_index,
+				enum devlink_sb_pool_type pool_type,
+				u16 pool_index, u32 threshold,
+				struct netlink_ext_ack *extack)
+{
+	struct dsa_switch *ds = dsa_devlink_port_to_ds(dlp);
+	int port = dsa_devlink_port_to_port(dlp);
+
+	if (!ds->ops->devlink_sb_tc_pool_bind_set)
+		return -EOPNOTSUPP;
+
+	return ds->ops->devlink_sb_tc_pool_bind_set(ds, port, sb_index,
+						    tc_index, pool_type,
+						    pool_index, threshold,
+						    extack);
+}
+
+static int dsa_devlink_sb_occ_snapshot(struct devlink *dl,
+				       unsigned int sb_index)
+{
+	struct dsa_switch *ds = dsa_devlink_to_ds(dl);
+
+	if (!ds->ops->devlink_sb_occ_snapshot)
+		return -EOPNOTSUPP;
+
+	return ds->ops->devlink_sb_occ_snapshot(ds, sb_index);
+}
+
+static int dsa_devlink_sb_occ_max_clear(struct devlink *dl,
+					unsigned int sb_index)
+{
+	struct dsa_switch *ds = dsa_devlink_to_ds(dl);
+
+	if (!ds->ops->devlink_sb_occ_max_clear)
+		return -EOPNOTSUPP;
+
+	return ds->ops->devlink_sb_occ_max_clear(ds, sb_index);
+}
+
+static int dsa_devlink_sb_occ_port_pool_get(struct devlink_port *dlp,
+					    unsigned int sb_index,
+					    u16 pool_index, u32 *p_cur,
+					    u32 *p_max)
+{
+	struct dsa_switch *ds = dsa_devlink_port_to_ds(dlp);
+	int port = dsa_devlink_port_to_port(dlp);
+
+	if (!ds->ops->devlink_sb_occ_port_pool_get)
+		return -EOPNOTSUPP;
+
+	return ds->ops->devlink_sb_occ_port_pool_get(ds, port, sb_index,
+						     pool_index, p_cur, p_max);
+}
+
+static int
+dsa_devlink_sb_occ_tc_port_bind_get(struct devlink_port *dlp,
+				    unsigned int sb_index, u16 tc_index,
+				    enum devlink_sb_pool_type pool_type,
+				    u32 *p_cur, u32 *p_max)
+{
+	struct dsa_switch *ds = dsa_devlink_port_to_ds(dlp);
+	int port = dsa_devlink_port_to_port(dlp);
+
+	if (!ds->ops->devlink_sb_occ_tc_port_bind_get)
+		return -EOPNOTSUPP;
+
+	return ds->ops->devlink_sb_occ_tc_port_bind_get(ds, port,
+							sb_index, tc_index,
+							pool_type, p_cur,
+							p_max);
+}
+
 static const struct devlink_ops dsa_devlink_ops = {
-	.info_get = dsa_devlink_info_get,
+	.info_get			= dsa_devlink_info_get,
+	.sb_pool_get			= dsa_devlink_sb_pool_get,
+	.sb_pool_set			= dsa_devlink_sb_pool_set,
+	.sb_port_pool_get		= dsa_devlink_sb_port_pool_get,
+	.sb_port_pool_set		= dsa_devlink_sb_port_pool_set,
+	.sb_tc_pool_bind_get		= dsa_devlink_sb_tc_pool_bind_get,
+	.sb_tc_pool_bind_set		= dsa_devlink_sb_tc_pool_bind_set,
+	.sb_occ_snapshot		= dsa_devlink_sb_occ_snapshot,
+	.sb_occ_max_clear		= dsa_devlink_sb_occ_max_clear,
+	.sb_occ_port_pool_get		= dsa_devlink_sb_occ_port_pool_get,
+	.sb_occ_tc_port_bind_get	= dsa_devlink_sb_occ_tc_port_bind_get,
 };
 
 static int dsa_switch_setup(struct dsa_switch *ds)
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v3 net-next 04/10] net: dsa: felix: reindent struct dsa_switch_ops
  2021-01-08 17:59 [PATCH v3 net-next 00/10] Configuring congestion watermarks on ocelot switch using devlink-sb Vladimir Oltean
                   ` (2 preceding siblings ...)
  2021-01-08 17:59 ` [PATCH v3 net-next 03/10] net: dsa: add ops for devlink-sb Vladimir Oltean
@ 2021-01-08 17:59 ` Vladimir Oltean
  2021-01-08 18:33   ` Florian Fainelli
  2021-01-10  1:24   ` Jakub Kicinski
  2021-01-08 17:59 ` [PATCH v3 net-next 05/10] net: dsa: felix: perform teardown in reverse order of setup Vladimir Oltean
                   ` (5 subsequent siblings)
  9 siblings, 2 replies; 36+ messages in thread
From: Vladimir Oltean @ 2021-01-08 17:59 UTC (permalink / raw)
  To: netdev
  Cc: alexandre.belloni, andrew, f.fainelli, vivien.didelot,
	alexandru.marginean, claudiu.manoil, xiaoliang.yang_1,
	hongbo.wang, kuba, jiri, idosch, UNGLinuxDriver

From: Vladimir Oltean <vladimir.oltean@nxp.com>

The devlink function pointer names are super long, and they would break
the alignment. So reindent the existing ops now by adding one tab.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
Changes in v3:
None.

Changes in v2:
None.

 drivers/net/dsa/ocelot/felix.c | 78 +++++++++++++++++-----------------
 1 file changed, 39 insertions(+), 39 deletions(-)

diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c
index a2e06a0d1509..79d0508e5910 100644
--- a/drivers/net/dsa/ocelot/felix.c
+++ b/drivers/net/dsa/ocelot/felix.c
@@ -781,45 +781,45 @@ static int felix_port_setup_tc(struct dsa_switch *ds, int port,
 }
 
 const struct dsa_switch_ops felix_switch_ops = {
-	.get_tag_protocol	= felix_get_tag_protocol,
-	.setup			= felix_setup,
-	.teardown		= felix_teardown,
-	.set_ageing_time	= felix_set_ageing_time,
-	.get_strings		= felix_get_strings,
-	.get_ethtool_stats	= felix_get_ethtool_stats,
-	.get_sset_count		= felix_get_sset_count,
-	.get_ts_info		= felix_get_ts_info,
-	.phylink_validate	= felix_phylink_validate,
-	.phylink_mac_config	= felix_phylink_mac_config,
-	.phylink_mac_link_down	= felix_phylink_mac_link_down,
-	.phylink_mac_link_up	= felix_phylink_mac_link_up,
-	.port_enable		= felix_port_enable,
-	.port_disable		= felix_port_disable,
-	.port_fdb_dump		= felix_fdb_dump,
-	.port_fdb_add		= felix_fdb_add,
-	.port_fdb_del		= felix_fdb_del,
-	.port_mdb_prepare	= felix_mdb_prepare,
-	.port_mdb_add		= felix_mdb_add,
-	.port_mdb_del		= felix_mdb_del,
-	.port_bridge_join	= felix_bridge_join,
-	.port_bridge_leave	= felix_bridge_leave,
-	.port_stp_state_set	= felix_bridge_stp_state_set,
-	.port_vlan_prepare	= felix_vlan_prepare,
-	.port_vlan_filtering	= felix_vlan_filtering,
-	.port_vlan_add		= felix_vlan_add,
-	.port_vlan_del		= felix_vlan_del,
-	.port_hwtstamp_get	= felix_hwtstamp_get,
-	.port_hwtstamp_set	= felix_hwtstamp_set,
-	.port_rxtstamp		= felix_rxtstamp,
-	.port_txtstamp		= felix_txtstamp,
-	.port_change_mtu	= felix_change_mtu,
-	.port_max_mtu		= felix_get_max_mtu,
-	.port_policer_add	= felix_port_policer_add,
-	.port_policer_del	= felix_port_policer_del,
-	.cls_flower_add		= felix_cls_flower_add,
-	.cls_flower_del		= felix_cls_flower_del,
-	.cls_flower_stats	= felix_cls_flower_stats,
-	.port_setup_tc		= felix_port_setup_tc,
+	.get_tag_protocol		= felix_get_tag_protocol,
+	.setup				= felix_setup,
+	.teardown			= felix_teardown,
+	.set_ageing_time		= felix_set_ageing_time,
+	.get_strings			= felix_get_strings,
+	.get_ethtool_stats		= felix_get_ethtool_stats,
+	.get_sset_count			= felix_get_sset_count,
+	.get_ts_info			= felix_get_ts_info,
+	.phylink_validate		= felix_phylink_validate,
+	.phylink_mac_config		= felix_phylink_mac_config,
+	.phylink_mac_link_down		= felix_phylink_mac_link_down,
+	.phylink_mac_link_up		= felix_phylink_mac_link_up,
+	.port_enable			= felix_port_enable,
+	.port_disable			= felix_port_disable,
+	.port_fdb_dump			= felix_fdb_dump,
+	.port_fdb_add			= felix_fdb_add,
+	.port_fdb_del			= felix_fdb_del,
+	.port_mdb_prepare		= felix_mdb_prepare,
+	.port_mdb_add			= felix_mdb_add,
+	.port_mdb_del			= felix_mdb_del,
+	.port_bridge_join		= felix_bridge_join,
+	.port_bridge_leave		= felix_bridge_leave,
+	.port_stp_state_set		= felix_bridge_stp_state_set,
+	.port_vlan_prepare		= felix_vlan_prepare,
+	.port_vlan_filtering		= felix_vlan_filtering,
+	.port_vlan_add			= felix_vlan_add,
+	.port_vlan_del			= felix_vlan_del,
+	.port_hwtstamp_get		= felix_hwtstamp_get,
+	.port_hwtstamp_set		= felix_hwtstamp_set,
+	.port_rxtstamp			= felix_rxtstamp,
+	.port_txtstamp			= felix_txtstamp,
+	.port_change_mtu		= felix_change_mtu,
+	.port_max_mtu			= felix_get_max_mtu,
+	.port_policer_add		= felix_port_policer_add,
+	.port_policer_del		= felix_port_policer_del,
+	.cls_flower_add			= felix_cls_flower_add,
+	.cls_flower_del			= felix_cls_flower_del,
+	.cls_flower_stats		= felix_cls_flower_stats,
+	.port_setup_tc			= felix_port_setup_tc,
 };
 
 struct net_device *felix_port_to_netdev(struct ocelot *ocelot, int port)
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v3 net-next 05/10] net: dsa: felix: perform teardown in reverse order of setup
  2021-01-08 17:59 [PATCH v3 net-next 00/10] Configuring congestion watermarks on ocelot switch using devlink-sb Vladimir Oltean
                   ` (3 preceding siblings ...)
  2021-01-08 17:59 ` [PATCH v3 net-next 04/10] net: dsa: felix: reindent struct dsa_switch_ops Vladimir Oltean
@ 2021-01-08 17:59 ` Vladimir Oltean
  2021-01-08 18:34   ` Florian Fainelli
  2021-01-08 17:59 ` [PATCH v3 net-next 06/10] net: mscc: ocelot: export NUM_TC constant from felix to common switch lib Vladimir Oltean
                   ` (4 subsequent siblings)
  9 siblings, 1 reply; 36+ messages in thread
From: Vladimir Oltean @ 2021-01-08 17:59 UTC (permalink / raw)
  To: netdev
  Cc: alexandre.belloni, andrew, f.fainelli, vivien.didelot,
	alexandru.marginean, claudiu.manoil, xiaoliang.yang_1,
	hongbo.wang, kuba, jiri, idosch, UNGLinuxDriver

From: Vladimir Oltean <vladimir.oltean@nxp.com>

In general it is desirable that cleanup is the reverse process of setup.
In this case I am not seeing any particular issue, but with the
introduction of devlink-sb for felix, a non-obvious decision had to be
made as to where to put its cleanup method. When there's a convention in
place, that decision becomes obvious.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
Changes in v3:
None.

Changes in v2:
None.

 drivers/net/dsa/ocelot/felix.c | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c
index 79d0508e5910..42770a86e871 100644
--- a/drivers/net/dsa/ocelot/felix.c
+++ b/drivers/net/dsa/ocelot/felix.c
@@ -639,14 +639,13 @@ static void felix_teardown(struct dsa_switch *ds)
 	struct felix *felix = ocelot_to_felix(ocelot);
 	int port;
 
-	if (felix->info->mdio_bus_free)
-		felix->info->mdio_bus_free(ocelot);
-
+	if (ocelot->ptp)
+		ocelot_deinit_timestamp(ocelot);
+	ocelot_deinit(ocelot);
 	for (port = 0; port < ocelot->num_phys_ports; port++)
 		ocelot_deinit_port(ocelot, port);
-	ocelot_deinit_timestamp(ocelot);
-	/* stop workqueue thread */
-	ocelot_deinit(ocelot);
+	if (felix->info->mdio_bus_free)
+		felix->info->mdio_bus_free(ocelot);
 }
 
 static int felix_hwtstamp_get(struct dsa_switch *ds, int port,
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v3 net-next 06/10] net: mscc: ocelot: export NUM_TC constant from felix to common switch lib
  2021-01-08 17:59 [PATCH v3 net-next 00/10] Configuring congestion watermarks on ocelot switch using devlink-sb Vladimir Oltean
                   ` (4 preceding siblings ...)
  2021-01-08 17:59 ` [PATCH v3 net-next 05/10] net: dsa: felix: perform teardown in reverse order of setup Vladimir Oltean
@ 2021-01-08 17:59 ` Vladimir Oltean
  2021-01-08 18:34   ` Florian Fainelli
  2021-01-08 17:59 ` [PATCH v3 net-next 07/10] net: mscc: ocelot: delete unused ocelot_set_cpu_port prototype Vladimir Oltean
                   ` (3 subsequent siblings)
  9 siblings, 1 reply; 36+ messages in thread
From: Vladimir Oltean @ 2021-01-08 17:59 UTC (permalink / raw)
  To: netdev
  Cc: alexandre.belloni, andrew, f.fainelli, vivien.didelot,
	alexandru.marginean, claudiu.manoil, xiaoliang.yang_1,
	hongbo.wang, kuba, jiri, idosch, UNGLinuxDriver

From: Vladimir Oltean <vladimir.oltean@nxp.com>

We should be moving anything that isn't DSA-specific or SoC-specific out
of the felix DSA driver, and into the common mscc_ocelot switch library.

The number of traffic classes is one of the aspects that is common
between all ocelot switches, so it belongs in the library.

This patch also makes seville use 8 TX queues, and therefore enables
prioritization via the QOS_CLASS field in the NPI injection header.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
Changes in v3:
None.

Changes in v2:
Rebased on top of commit edd2410b165e ("net: mscc: ocelot: fix dropping
of unknown IPv4 multicast on Seville").

 drivers/net/dsa/ocelot/felix.c           | 2 +-
 drivers/net/dsa/ocelot/felix.h           | 1 -
 drivers/net/dsa/ocelot/felix_vsc9959.c   | 4 ++--
 drivers/net/dsa/ocelot/seville_vsc9953.c | 1 +
 include/soc/mscc/ocelot.h                | 1 +
 5 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c
index 42770a86e871..f41f3476ae06 100644
--- a/drivers/net/dsa/ocelot/felix.c
+++ b/drivers/net/dsa/ocelot/felix.c
@@ -328,7 +328,7 @@ static void felix_port_qos_map_init(struct ocelot *ocelot, int port)
 		       ANA_PORT_QOS_CFG,
 		       port);
 
-	for (i = 0; i < FELIX_NUM_TC * 2; i++) {
+	for (i = 0; i < OCELOT_NUM_TC * 2; i++) {
 		ocelot_rmw_ix(ocelot,
 			      (ANA_PORT_PCP_DEI_MAP_DP_PCP_DEI_VAL & i) |
 			      ANA_PORT_PCP_DEI_MAP_QOS_PCP_DEI_VAL(i),
diff --git a/drivers/net/dsa/ocelot/felix.h b/drivers/net/dsa/ocelot/felix.h
index 5434fe278d2c..994835cb9307 100644
--- a/drivers/net/dsa/ocelot/felix.h
+++ b/drivers/net/dsa/ocelot/felix.h
@@ -5,7 +5,6 @@
 #define _MSCC_FELIX_H
 
 #define ocelot_to_felix(o)		container_of((o), struct felix, ocelot)
-#define FELIX_NUM_TC			8
 
 /* Platform-specific information */
 struct felix_info {
diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c
index 540b86edbbb0..57d1d6767867 100644
--- a/drivers/net/dsa/ocelot/felix_vsc9959.c
+++ b/drivers/net/dsa/ocelot/felix_vsc9959.c
@@ -1376,7 +1376,7 @@ static const struct felix_info felix_info_vsc9959 = {
 	.vcap			= vsc9959_vcap_props,
 	.num_mact_rows		= 2048,
 	.num_ports		= 6,
-	.num_tx_queues		= FELIX_NUM_TC,
+	.num_tx_queues		= OCELOT_NUM_TC,
 	.switch_pci_bar		= 4,
 	.imdio_pci_bar		= 0,
 	.ptp_caps		= &vsc9959_ptp_caps,
@@ -1446,7 +1446,7 @@ static int felix_pci_probe(struct pci_dev *pdev,
 	pci_set_drvdata(pdev, felix);
 	ocelot = &felix->ocelot;
 	ocelot->dev = &pdev->dev;
-	ocelot->num_flooding_pgids = FELIX_NUM_TC;
+	ocelot->num_flooding_pgids = OCELOT_NUM_TC;
 	felix->info = &felix_info_vsc9959;
 	felix->switch_base = pci_resource_start(pdev,
 						felix->info->switch_pci_bar);
diff --git a/drivers/net/dsa/ocelot/seville_vsc9953.c b/drivers/net/dsa/ocelot/seville_vsc9953.c
index 8dad0c894eca..5e9bfdea50be 100644
--- a/drivers/net/dsa/ocelot/seville_vsc9953.c
+++ b/drivers/net/dsa/ocelot/seville_vsc9953.c
@@ -1201,6 +1201,7 @@ static const struct felix_info seville_info_vsc9953 = {
 	.vcap			= vsc9953_vcap_props,
 	.num_mact_rows		= 2048,
 	.num_ports		= 10,
+	.num_tx_queues		= OCELOT_NUM_TC,
 	.mdio_bus_alloc		= vsc9953_mdio_bus_alloc,
 	.mdio_bus_free		= vsc9953_mdio_bus_free,
 	.phylink_validate	= vsc9953_phylink_validate,
diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h
index 8eb134cd8d9d..9a46787c679b 100644
--- a/include/soc/mscc/ocelot.h
+++ b/include/soc/mscc/ocelot.h
@@ -98,6 +98,7 @@
 #define IFH_REW_OP_TWO_STEP_PTP		0x3
 #define IFH_REW_OP_ORIGIN_PTP		0x5
 
+#define OCELOT_NUM_TC			8
 #define OCELOT_TAG_LEN			16
 #define OCELOT_SHORT_PREFIX_LEN		4
 #define OCELOT_LONG_PREFIX_LEN		16
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v3 net-next 07/10] net: mscc: ocelot: delete unused ocelot_set_cpu_port prototype
  2021-01-08 17:59 [PATCH v3 net-next 00/10] Configuring congestion watermarks on ocelot switch using devlink-sb Vladimir Oltean
                   ` (5 preceding siblings ...)
  2021-01-08 17:59 ` [PATCH v3 net-next 06/10] net: mscc: ocelot: export NUM_TC constant from felix to common switch lib Vladimir Oltean
@ 2021-01-08 17:59 ` Vladimir Oltean
  2021-01-08 18:35   ` Florian Fainelli
  2021-01-08 17:59 ` [PATCH v3 net-next 08/10] net: mscc: ocelot: register devlink ports Vladimir Oltean
                   ` (2 subsequent siblings)
  9 siblings, 1 reply; 36+ messages in thread
From: Vladimir Oltean @ 2021-01-08 17:59 UTC (permalink / raw)
  To: netdev
  Cc: alexandre.belloni, andrew, f.fainelli, vivien.didelot,
	alexandru.marginean, claudiu.manoil, xiaoliang.yang_1,
	hongbo.wang, kuba, jiri, idosch, UNGLinuxDriver

From: Vladimir Oltean <vladimir.oltean@nxp.com>

This is a leftover of commit 69df578c5f4b ("net: mscc: ocelot: eliminate
confusion between CPU and NPI port") which renamed that function.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
Changes in v3:
None.

Changes in v2:
None.

 drivers/net/ethernet/mscc/ocelot.h | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h
index 291d39d49c4e..519335676c24 100644
--- a/drivers/net/ethernet/mscc/ocelot.h
+++ b/drivers/net/ethernet/mscc/ocelot.h
@@ -122,10 +122,6 @@ void ocelot_port_writel(struct ocelot_port *port, u32 val, u32 reg);
 int ocelot_probe_port(struct ocelot *ocelot, int port, struct regmap *target,
 		      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;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v3 net-next 08/10] net: mscc: ocelot: register devlink ports
  2021-01-08 17:59 [PATCH v3 net-next 00/10] Configuring congestion watermarks on ocelot switch using devlink-sb Vladimir Oltean
                   ` (6 preceding siblings ...)
  2021-01-08 17:59 ` [PATCH v3 net-next 07/10] net: mscc: ocelot: delete unused ocelot_set_cpu_port prototype Vladimir Oltean
@ 2021-01-08 17:59 ` Vladimir Oltean
  2021-01-08 18:36   ` Florian Fainelli
                     ` (2 more replies)
  2021-01-08 17:59 ` [PATCH v3 net-next 09/10] net: mscc: ocelot: initialize watermarks to sane defaults Vladimir Oltean
  2021-01-08 17:59 ` [PATCH v3 net-next 10/10] net: mscc: ocelot: configure watermarks using devlink-sb Vladimir Oltean
  9 siblings, 3 replies; 36+ messages in thread
From: Vladimir Oltean @ 2021-01-08 17:59 UTC (permalink / raw)
  To: netdev
  Cc: alexandre.belloni, andrew, f.fainelli, vivien.didelot,
	alexandru.marginean, claudiu.manoil, xiaoliang.yang_1,
	hongbo.wang, kuba, jiri, idosch, UNGLinuxDriver

From: Vladimir Oltean <vladimir.oltean@nxp.com>

Add devlink integration into the mscc_ocelot switchdev driver. Only the
probed interfaces are registered with devlink, because for convenience,
struct devlink_port was included into struct ocelot_port_private, which
is only initialized for the ports that are used.

Since we use devlink_port_type_eth_set to link the devlink port to the
net_device, we can as well remove the .ndo_get_phys_port_name and
.ndo_get_port_parent_id implementations, since devlink takes care of
retrieving the port name and number automatically, once
.ndo_get_devlink_port is implemented.

Note that the felix DSA driver is already integrated with devlink by
default, since that is a thing that the DSA core takes care of. This is
the reason why these devlink stubs were put in ocelot_net.c and not in
the common library.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
Changes in v3:
None.

Changes in v2:
Using devlink_port_type_eth_set as per Jiri's suggestion.

 drivers/net/ethernet/mscc/ocelot.h         |   4 +
 drivers/net/ethernet/mscc/ocelot_net.c     | 139 ++++++++++++++++-----
 drivers/net/ethernet/mscc/ocelot_vsc7514.c |   7 ++
 include/soc/mscc/ocelot.h                  |   1 +
 4 files changed, 123 insertions(+), 28 deletions(-)

diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h
index 519335676c24..2e9a3c4697c8 100644
--- a/drivers/net/ethernet/mscc/ocelot.h
+++ b/drivers/net/ethernet/mscc/ocelot.h
@@ -57,6 +57,8 @@ struct ocelot_port_private {
 	struct phy *serdes;
 
 	struct ocelot_port_tc tc;
+
+	struct devlink_port devlink_port;
 };
 
 struct ocelot_dump_ctx {
@@ -121,6 +123,8 @@ void ocelot_port_writel(struct ocelot_port *port, u32 val, u32 reg);
 
 int ocelot_probe_port(struct ocelot *ocelot, int port, struct regmap *target,
 		      struct phy_device *phy);
+int ocelot_devlink_init(struct ocelot *ocelot);
+void ocelot_devlink_teardown(struct ocelot *ocelot);
 
 extern struct notifier_block ocelot_netdevice_nb;
 extern struct notifier_block ocelot_switchdev_nb;
diff --git a/drivers/net/ethernet/mscc/ocelot_net.c b/drivers/net/ethernet/mscc/ocelot_net.c
index 2bd2840d88bd..d0d98c6adea8 100644
--- a/drivers/net/ethernet/mscc/ocelot_net.c
+++ b/drivers/net/ethernet/mscc/ocelot_net.c
@@ -8,6 +8,116 @@
 #include "ocelot.h"
 #include "ocelot_vcap.h"
 
+struct ocelot_devlink_private {
+	struct ocelot *ocelot;
+};
+
+static const struct devlink_ops ocelot_devlink_ops = {
+};
+
+static int ocelot_port_devlink_init(struct ocelot *ocelot, int port)
+{
+	struct ocelot_port *ocelot_port = ocelot->ports[port];
+	int id_len = sizeof(ocelot->base_mac);
+	struct devlink *dl = ocelot->devlink;
+	struct devlink_port_attrs attrs = {};
+	struct ocelot_port_private *priv;
+	struct devlink_port *dlp;
+	int err;
+
+	if (!ocelot_port)
+		return 0;
+
+	priv = container_of(ocelot_port, struct ocelot_port_private, port);
+	dlp = &priv->devlink_port;
+
+	memcpy(attrs.switch_id.id, &ocelot->base_mac, id_len);
+	attrs.switch_id.id_len = id_len;
+	attrs.phys.port_number = port;
+
+	if (priv->dev)
+		attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
+	else
+		attrs.flavour = DEVLINK_PORT_FLAVOUR_UNUSED;
+
+	devlink_port_attrs_set(dlp, &attrs);
+
+	err = devlink_port_register(dl, dlp, port);
+	if (err)
+		return err;
+
+	if (priv->dev)
+		devlink_port_type_eth_set(dlp, priv->dev);
+
+	return 0;
+}
+
+static void ocelot_port_devlink_teardown(struct ocelot *ocelot, int port)
+{
+	struct ocelot_port *ocelot_port = ocelot->ports[port];
+	struct ocelot_port_private *priv;
+	struct devlink_port *dlp;
+
+	if (!ocelot_port)
+		return;
+
+	priv = container_of(ocelot_port, struct ocelot_port_private, port);
+	dlp = &priv->devlink_port;
+
+	devlink_port_unregister(dlp);
+}
+
+int ocelot_devlink_init(struct ocelot *ocelot)
+{
+	struct ocelot_devlink_private *dl_priv;
+	int port, err;
+
+	ocelot->devlink = devlink_alloc(&ocelot_devlink_ops, sizeof(*dl_priv));
+	if (!ocelot->devlink)
+		return -ENOMEM;
+	dl_priv = devlink_priv(ocelot->devlink);
+	dl_priv->ocelot = ocelot;
+
+	err = devlink_register(ocelot->devlink, ocelot->dev);
+	if (err)
+		goto free_devlink;
+
+	for (port = 0; port < ocelot->num_phys_ports; port++) {
+		err = ocelot_port_devlink_init(ocelot, port);
+		if (err) {
+			while (port-- > 0)
+				ocelot_port_devlink_teardown(ocelot, port);
+			goto unregister_devlink;
+		}
+	}
+
+	return 0;
+
+unregister_devlink:
+	devlink_unregister(ocelot->devlink);
+free_devlink:
+	devlink_free(ocelot->devlink);
+	return err;
+}
+
+void ocelot_devlink_teardown(struct ocelot *ocelot)
+{
+	int port;
+
+	for (port = 0; port < ocelot->num_phys_ports; port++)
+		ocelot_port_devlink_teardown(ocelot, port);
+
+	devlink_unregister(ocelot->devlink);
+	devlink_free(ocelot->devlink);
+}
+
+static struct devlink_port *ocelot_get_devlink_port(struct net_device *dev)
+{
+	struct ocelot_port_private *priv = netdev_priv(dev);
+
+	return &priv->devlink_port;
+}
+
 int ocelot_setup_tc_cls_flower(struct ocelot_port_private *priv,
 			       struct flow_cls_offload *f,
 			       bool ingress)
@@ -525,20 +635,6 @@ static void ocelot_set_rx_mode(struct net_device *dev)
 	__dev_mc_sync(dev, ocelot_mc_sync, ocelot_mc_unsync);
 }
 
-static int ocelot_port_get_phys_port_name(struct net_device *dev,
-					  char *buf, size_t len)
-{
-	struct ocelot_port_private *priv = netdev_priv(dev);
-	int port = priv->chip_port;
-	int ret;
-
-	ret = snprintf(buf, len, "p%d", port);
-	if (ret >= len)
-		return -EINVAL;
-
-	return 0;
-}
-
 static int ocelot_port_set_mac_address(struct net_device *dev, void *p)
 {
 	struct ocelot_port_private *priv = netdev_priv(dev);
@@ -689,18 +785,6 @@ static int ocelot_set_features(struct net_device *dev,
 	return 0;
 }
 
-static int ocelot_get_port_parent_id(struct net_device *dev,
-				     struct netdev_phys_item_id *ppid)
-{
-	struct ocelot_port_private *priv = netdev_priv(dev);
-	struct ocelot *ocelot = priv->port.ocelot;
-
-	ppid->id_len = sizeof(ocelot->base_mac);
-	memcpy(&ppid->id, &ocelot->base_mac, ppid->id_len);
-
-	return 0;
-}
-
 static int ocelot_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
 	struct ocelot_port_private *priv = netdev_priv(dev);
@@ -727,7 +811,6 @@ static const struct net_device_ops ocelot_port_netdev_ops = {
 	.ndo_stop			= ocelot_port_stop,
 	.ndo_start_xmit			= ocelot_port_xmit,
 	.ndo_set_rx_mode		= ocelot_set_rx_mode,
-	.ndo_get_phys_port_name		= ocelot_port_get_phys_port_name,
 	.ndo_set_mac_address		= ocelot_port_set_mac_address,
 	.ndo_get_stats64		= ocelot_get_stats64,
 	.ndo_fdb_add			= ocelot_port_fdb_add,
@@ -736,9 +819,9 @@ static const struct net_device_ops ocelot_port_netdev_ops = {
 	.ndo_vlan_rx_add_vid		= ocelot_vlan_rx_add_vid,
 	.ndo_vlan_rx_kill_vid		= ocelot_vlan_rx_kill_vid,
 	.ndo_set_features		= ocelot_set_features,
-	.ndo_get_port_parent_id		= ocelot_get_port_parent_id,
 	.ndo_setup_tc			= ocelot_setup_tc,
 	.ndo_do_ioctl			= ocelot_ioctl,
+	.ndo_get_devlink_port		= ocelot_get_devlink_port,
 };
 
 struct net_device *ocelot_port_to_netdev(struct ocelot *ocelot, int port)
diff --git a/drivers/net/ethernet/mscc/ocelot_vsc7514.c b/drivers/net/ethernet/mscc/ocelot_vsc7514.c
index ecd474476cc6..80fdf971d573 100644
--- a/drivers/net/ethernet/mscc/ocelot_vsc7514.c
+++ b/drivers/net/ethernet/mscc/ocelot_vsc7514.c
@@ -1293,6 +1293,12 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
 		}
 	}
 
+	err = ocelot_devlink_init(ocelot);
+	if (err) {
+		mscc_ocelot_release_ports(ocelot);
+		goto out_ocelot_deinit;
+	}
+
 	register_netdevice_notifier(&ocelot_netdevice_nb);
 	register_switchdev_notifier(&ocelot_switchdev_nb);
 	register_switchdev_blocking_notifier(&ocelot_switchdev_blocking_nb);
@@ -1314,6 +1320,7 @@ static int mscc_ocelot_remove(struct platform_device *pdev)
 {
 	struct ocelot *ocelot = platform_get_drvdata(pdev);
 
+	ocelot_devlink_teardown(ocelot);
 	ocelot_deinit_timestamp(ocelot);
 	mscc_ocelot_release_ports(ocelot);
 	ocelot_deinit(ocelot);
diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h
index 9a46787c679b..75cd457b99b9 100644
--- a/include/soc/mscc/ocelot.h
+++ b/include/soc/mscc/ocelot.h
@@ -602,6 +602,7 @@ struct ocelot_port {
 
 struct ocelot {
 	struct device			*dev;
+	struct devlink			*devlink;
 
 	const struct ocelot_ops		*ops;
 	struct regmap			*targets[TARGET_MAX];
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v3 net-next 09/10] net: mscc: ocelot: initialize watermarks to sane defaults
  2021-01-08 17:59 [PATCH v3 net-next 00/10] Configuring congestion watermarks on ocelot switch using devlink-sb Vladimir Oltean
                   ` (7 preceding siblings ...)
  2021-01-08 17:59 ` [PATCH v3 net-next 08/10] net: mscc: ocelot: register devlink ports Vladimir Oltean
@ 2021-01-08 17:59 ` Vladimir Oltean
  2021-01-09  3:59   ` Florian Fainelli
  2021-01-08 17:59 ` [PATCH v3 net-next 10/10] net: mscc: ocelot: configure watermarks using devlink-sb Vladimir Oltean
  9 siblings, 1 reply; 36+ messages in thread
From: Vladimir Oltean @ 2021-01-08 17:59 UTC (permalink / raw)
  To: netdev
  Cc: alexandre.belloni, andrew, f.fainelli, vivien.didelot,
	alexandru.marginean, claudiu.manoil, xiaoliang.yang_1,
	hongbo.wang, kuba, jiri, idosch, UNGLinuxDriver

From: Vladimir Oltean <vladimir.oltean@nxp.com>

This is meant to be a gentle introduction into the world of watermarks
on ocelot. The code is placed in ocelot_devlink.c because it will be
integrated with devlink, even if it isn't right now.

My first step was intended to be to replicate the default configuration
of the congestion watermarks programatically, since they are now going
to be tuned by the user.

But after studying and understanding through trial and error how they
work, I now believe that the configuration used out of reset does not do
justice to the word "reservation", since the sum of all reservations
exceeds the total amount of resources (otherwise said, all reservations
cannot be fulfilled at the same time, which means that, contrary to the
reference manual, they don't guarantee anything).

As an example, here's a dump of the reservation watermarks for frame
buffers, for port 0 (for brevity, the ports 1-6 were omitted, but they
have the same configuration):

BUF_Q_RSRV_I(port 0, prio 0) = max 3000 bytes
BUF_Q_RSRV_I(port 0, prio 1) = max 3000 bytes
BUF_Q_RSRV_I(port 0, prio 2) = max 3000 bytes
BUF_Q_RSRV_I(port 0, prio 3) = max 3000 bytes
BUF_Q_RSRV_I(port 0, prio 4) = max 3000 bytes
BUF_Q_RSRV_I(port 0, prio 5) = max 3000 bytes
BUF_Q_RSRV_I(port 0, prio 6) = max 3000 bytes
BUF_Q_RSRV_I(port 0, prio 7) = max 3000 bytes

Otherwise said, every port-tc has an ingress reservation of 3000 bytes,
and there are 7 ports in VSC9959 Felix (6 user ports and 1 CPU port).
Concentrating only on the ingress reservations, there are, in total,
8 [traffic classes] x 7 [ports] x 3000 [bytes] = 168,000 bytes of memory
reserved on ingress.
But, surprise, Felix only has 128 KB of packet buffer in total...
A similar thing happens with Seville, which has a larger packet buffer,
but also more ports, and the default configuration is also overcommitted.

This patch disables the (apparently) bogus reservations and moves all
resources to the shared area. This way, real reservations can be set up
by the user, using devlink-sb.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
Changes in v3:
None.

Changes in v2:
None.

 drivers/net/ethernet/mscc/Makefile         |   3 +-
 drivers/net/ethernet/mscc/ocelot.c         |   1 +
 drivers/net/ethernet/mscc/ocelot.h         |   1 +
 drivers/net/ethernet/mscc/ocelot_devlink.c | 442 +++++++++++++++++++++
 4 files changed, 446 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/ethernet/mscc/ocelot_devlink.c

diff --git a/drivers/net/ethernet/mscc/Makefile b/drivers/net/ethernet/mscc/Makefile
index 58f94c3d80f9..346bba2730ad 100644
--- a/drivers/net/ethernet/mscc/Makefile
+++ b/drivers/net/ethernet/mscc/Makefile
@@ -6,7 +6,8 @@ mscc_ocelot_switch_lib-y := \
 	ocelot_police.o \
 	ocelot_vcap.o \
 	ocelot_flower.o \
-	ocelot_ptp.o
+	ocelot_ptp.o \
+	ocelot_devlink.o
 obj-$(CONFIG_MSCC_OCELOT_SWITCH) += mscc_ocelot.o
 mscc_ocelot-y := \
 	ocelot_vsc7514.o \
diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c
index 876c03e51bdc..f547728c6718 100644
--- a/drivers/net/ethernet/mscc/ocelot.c
+++ b/drivers/net/ethernet/mscc/ocelot.c
@@ -1636,6 +1636,7 @@ int ocelot_init(struct ocelot *ocelot)
 	INIT_DELAYED_WORK(&ocelot->stats_work, ocelot_check_stats_work);
 	queue_delayed_work(ocelot->stats_queue, &ocelot->stats_work,
 			   OCELOT_STATS_CHECK_DELAY);
+	ocelot_watermark_init(ocelot);
 
 	return 0;
 }
diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h
index 2e9a3c4697c8..a9d60ef30344 100644
--- a/drivers/net/ethernet/mscc/ocelot.h
+++ b/drivers/net/ethernet/mscc/ocelot.h
@@ -125,6 +125,7 @@ int ocelot_probe_port(struct ocelot *ocelot, int port, struct regmap *target,
 		      struct phy_device *phy);
 int ocelot_devlink_init(struct ocelot *ocelot);
 void ocelot_devlink_teardown(struct ocelot *ocelot);
+void ocelot_watermark_init(struct ocelot *ocelot);
 
 extern struct notifier_block ocelot_netdevice_nb;
 extern struct notifier_block ocelot_switchdev_nb;
diff --git a/drivers/net/ethernet/mscc/ocelot_devlink.c b/drivers/net/ethernet/mscc/ocelot_devlink.c
new file mode 100644
index 000000000000..c96309cde82d
--- /dev/null
+++ b/drivers/net/ethernet/mscc/ocelot_devlink.c
@@ -0,0 +1,442 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/* Copyright 2020 NXP Semiconductors
+ */
+#include <net/devlink.h>
+#include "ocelot.h"
+
+/* The queue system tracks four resource consumptions:
+ * Resource 0: Memory tracked per source port
+ * Resource 1: Frame references tracked per source port
+ * Resource 2: Memory tracked per destination port
+ * Resource 3: Frame references tracked per destination port
+ */
+#define OCELOT_RESOURCE_SZ		256
+#define OCELOT_NUM_RESOURCES		4
+
+#define BUF_xxxx_I			(0 * OCELOT_RESOURCE_SZ)
+#define REF_xxxx_I			(1 * OCELOT_RESOURCE_SZ)
+#define BUF_xxxx_E			(2 * OCELOT_RESOURCE_SZ)
+#define REF_xxxx_E			(3 * OCELOT_RESOURCE_SZ)
+
+/* For each resource type there are 4 types of watermarks:
+ * Q_RSRV: reservation per QoS class per port
+ * PRIO_SHR: sharing watermark per QoS class across all ports
+ * P_RSRV: reservation per port
+ * COL_SHR: sharing watermark per color (drop precedence) across all ports
+ */
+#define xxx_Q_RSRV_x			0
+#define xxx_PRIO_SHR_x			216
+#define xxx_P_RSRV_x			224
+#define xxx_COL_SHR_x			254
+
+/* Reservation Watermarks
+ * ----------------------
+ *
+ * For setting up the reserved areas, egress watermarks exist per port and per
+ * QoS class for both ingress and egress.
+ */
+
+/*  Amount of packet buffer
+ *  |  per QoS class
+ *  |  |  reserved
+ *  |  |  |   per egress port
+ *  |  |  |   |
+ *  V  V  v   v
+ * BUF_Q_RSRV_E
+ */
+#define BUF_Q_RSRV_E(port, prio) \
+	(BUF_xxxx_E + xxx_Q_RSRV_x + OCELOT_NUM_TC * (port) + (prio))
+
+/*  Amount of packet buffer
+ *  |  for all port's traffic classes
+ *  |  |  reserved
+ *  |  |  |   per egress port
+ *  |  |  |   |
+ *  V  V  v   v
+ * BUF_P_RSRV_E
+ */
+#define BUF_P_RSRV_E(port) \
+	(BUF_xxxx_E + xxx_P_RSRV_x + (port))
+
+/*  Amount of packet buffer
+ *  |  per QoS class
+ *  |  |  reserved
+ *  |  |  |   per ingress port
+ *  |  |  |   |
+ *  V  V  v   v
+ * BUF_Q_RSRV_I
+ */
+#define BUF_Q_RSRV_I(port, prio) \
+	(BUF_xxxx_I + xxx_Q_RSRV_x + OCELOT_NUM_TC * (port) + (prio))
+
+/*  Amount of packet buffer
+ *  |  for all port's traffic classes
+ *  |  |  reserved
+ *  |  |  |   per ingress port
+ *  |  |  |   |
+ *  V  V  v   v
+ * BUF_P_RSRV_I
+ */
+#define BUF_P_RSRV_I(port) \
+	(BUF_xxxx_I + xxx_P_RSRV_x + (port))
+
+/*  Amount of frame references
+ *  |  per QoS class
+ *  |  |  reserved
+ *  |  |  |   per egress port
+ *  |  |  |   |
+ *  V  V  v   v
+ * REF_Q_RSRV_E
+ */
+#define REF_Q_RSRV_E(port, prio) \
+	(REF_xxxx_E + xxx_Q_RSRV_x + OCELOT_NUM_TC * (port) + (prio))
+
+/*  Amount of frame references
+ *  |  for all port's traffic classes
+ *  |  |  reserved
+ *  |  |  |   per egress port
+ *  |  |  |   |
+ *  V  V  v   v
+ * REF_P_RSRV_E
+ */
+#define REF_P_RSRV_E(port) \
+	(REF_xxxx_E + xxx_P_RSRV_x + (port))
+
+/*  Amount of frame references
+ *  |  per QoS class
+ *  |  |  reserved
+ *  |  |  |   per ingress port
+ *  |  |  |   |
+ *  V  V  v   v
+ * REF_Q_RSRV_I
+ */
+#define REF_Q_RSRV_I(port, prio) \
+	(REF_xxxx_I + xxx_Q_RSRV_x + OCELOT_NUM_TC * (port) + (prio))
+
+/*  Amount of frame references
+ *  |  for all port's traffic classes
+ *  |  |  reserved
+ *  |  |  |   per ingress port
+ *  |  |  |   |
+ *  V  V  v   v
+ * REF_P_RSRV_I
+ */
+#define REF_P_RSRV_I(port) \
+	(REF_xxxx_I + xxx_P_RSRV_x + (port))
+
+/* Sharing Watermarks
+ * ------------------
+ *
+ * The shared memory area is shared between all ports.
+ */
+
+/* Amount of buffer
+ *  |   per QoS class
+ *  |   |    from the shared memory area
+ *  |   |    |  for egress traffic
+ *  |   |    |  |
+ *  V   V    v  v
+ * BUF_PRIO_SHR_E
+ */
+#define BUF_PRIO_SHR_E(prio) \
+	(BUF_xxxx_E + xxx_PRIO_SHR_x + (prio))
+
+/* Amount of buffer
+ *  |   per color (drop precedence level)
+ *  |   |   from the shared memory area
+ *  |   |   |  for egress traffic
+ *  |   |   |  |
+ *  V   V   v  v
+ * BUF_COL_SHR_E
+ */
+#define BUF_COL_SHR_E(dp) \
+	(BUF_xxxx_E + xxx_COL_SHR_x + (1 - (dp)))
+
+/* Amount of buffer
+ *  |   per QoS class
+ *  |   |    from the shared memory area
+ *  |   |    |  for ingress traffic
+ *  |   |    |  |
+ *  V   V    v  v
+ * BUF_PRIO_SHR_I
+ */
+#define BUF_PRIO_SHR_I(prio) \
+	(BUF_xxxx_I + xxx_PRIO_SHR_x + (prio))
+
+/* Amount of buffer
+ *  |   per color (drop precedence level)
+ *  |   |   from the shared memory area
+ *  |   |   |  for ingress traffic
+ *  |   |   |  |
+ *  V   V   v  v
+ * BUF_COL_SHR_I
+ */
+#define BUF_COL_SHR_I(dp) \
+	(BUF_xxxx_I + xxx_COL_SHR_x + (1 - (dp)))
+
+/* Amount of frame references
+ *  |   per QoS class
+ *  |   |    from the shared area
+ *  |   |    |  for egress traffic
+ *  |   |    |  |
+ *  V   V    v  v
+ * REF_PRIO_SHR_E
+ */
+#define REF_PRIO_SHR_E(prio) \
+	(REF_xxxx_E + xxx_PRIO_SHR_x + (prio))
+
+/* Amount of frame references
+ *  |   per color (drop precedence level)
+ *  |   |   from the shared area
+ *  |   |   |  for egress traffic
+ *  |   |   |  |
+ *  V   V   v  v
+ * REF_COL_SHR_E
+ */
+#define REF_COL_SHR_E(dp) \
+	(REF_xxxx_E + xxx_COL_SHR_x + (1 - (dp)))
+
+/* Amount of frame references
+ *  |   per QoS class
+ *  |   |    from the shared area
+ *  |   |    |  for ingress traffic
+ *  |   |    |  |
+ *  V   V    v  v
+ * REF_PRIO_SHR_I
+ */
+#define REF_PRIO_SHR_I(prio) \
+	(REF_xxxx_I + xxx_PRIO_SHR_x + (prio))
+
+/* Amount of frame references
+ *  |   per color (drop precedence level)
+ *  |   |   from the shared area
+ *  |   |   |  for ingress traffic
+ *  |   |   |  |
+ *  V   V   v  v
+ * REF_COL_SHR_I
+ */
+#define REF_COL_SHR_I(dp) \
+	(REF_xxxx_I + xxx_COL_SHR_x + (1 - (dp)))
+
+static u32 ocelot_wm_read(struct ocelot *ocelot, int index)
+{
+	int wm = ocelot_read_gix(ocelot, QSYS_RES_CFG, index);
+
+	return ocelot->ops->wm_dec(wm);
+}
+
+static void ocelot_wm_write(struct ocelot *ocelot, int index, u32 val)
+{
+	u32 wm = ocelot->ops->wm_enc(val);
+
+	ocelot_write_gix(ocelot, wm, QSYS_RES_CFG, index);
+}
+
+/* The hardware comes out of reset with strange defaults: the sum of all
+ * reservations for frame memory is larger than the total buffer size.
+ * One has to wonder how can the reservation watermarks still guarantee
+ * anything under congestion.
+ * Bring some sense into the hardware by changing the defaults to disable all
+ * reservations and rely only on the sharing watermark for frames with drop
+ * precedence 0. The user can still explicitly request reservations per port
+ * and per port-tc through devlink-sb.
+ */
+static void ocelot_disable_reservation_watermarks(struct ocelot *ocelot,
+						  int port)
+{
+	int prio;
+
+	for (prio = 0; prio < OCELOT_NUM_TC; prio++) {
+		ocelot_wm_write(ocelot, BUF_Q_RSRV_I(port, prio), 0);
+		ocelot_wm_write(ocelot, BUF_Q_RSRV_E(port, prio), 0);
+		ocelot_wm_write(ocelot, REF_Q_RSRV_I(port, prio), 0);
+		ocelot_wm_write(ocelot, REF_Q_RSRV_E(port, prio), 0);
+	}
+
+	ocelot_wm_write(ocelot, BUF_P_RSRV_I(port), 0);
+	ocelot_wm_write(ocelot, BUF_P_RSRV_E(port), 0);
+	ocelot_wm_write(ocelot, REF_P_RSRV_I(port), 0);
+	ocelot_wm_write(ocelot, REF_P_RSRV_E(port), 0);
+}
+
+/* We want the sharing watermarks to consume all nonreserved resources, for
+ * efficient resource utilization (a single traffic flow should be able to use
+ * up the entire buffer space and frame resources as long as there's no
+ * interference).
+ * The switch has 10 sharing watermarks per lookup: 8 per traffic class and 2
+ * per color (drop precedence).
+ * The trouble with configuring these sharing watermarks is that:
+ * (1) There's a risk that we overcommit the resources if we configure
+ *     (a) all 8 per-TC sharing watermarks to the max
+ *     (b) all 2 per-color sharing watermarks to the max
+ * (2) There's a risk that we undercommit the resources if we configure
+ *     (a) all 8 per-TC sharing watermarks to "max / 8"
+ *     (b) all 2 per-color sharing watermarks to "max / 2"
+ * So for Linux, let's just disable the sharing watermarks per traffic class
+ * (setting them to 0 will make them always exceeded), and rely only on the
+ * sharing watermark for drop priority 0. So frames with drop priority set to 1
+ * by QoS classification or policing will still be allowed, but only as long as
+ * the port and port-TC reservations are not exceeded.
+ */
+static void ocelot_disable_tc_sharing_watermarks(struct ocelot *ocelot)
+{
+	int prio;
+
+	for (prio = 0; prio < OCELOT_NUM_TC; prio++) {
+		ocelot_wm_write(ocelot, BUF_PRIO_SHR_I(prio), 0);
+		ocelot_wm_write(ocelot, BUF_PRIO_SHR_E(prio), 0);
+		ocelot_wm_write(ocelot, REF_PRIO_SHR_I(prio), 0);
+		ocelot_wm_write(ocelot, REF_PRIO_SHR_E(prio), 0);
+	}
+}
+
+static void ocelot_get_buf_rsrv(struct ocelot *ocelot, u32 *buf_rsrv_i,
+				u32 *buf_rsrv_e)
+{
+	int port, prio;
+
+	*buf_rsrv_i = 0;
+	*buf_rsrv_e = 0;
+
+	for (port = 0; port <= ocelot->num_phys_ports; port++) {
+		for (prio = 0; prio < OCELOT_NUM_TC; prio++) {
+			*buf_rsrv_i += ocelot_wm_read(ocelot,
+						      BUF_Q_RSRV_I(port, prio));
+			*buf_rsrv_e += ocelot_wm_read(ocelot,
+						      BUF_Q_RSRV_E(port, prio));
+		}
+
+		*buf_rsrv_i += ocelot_wm_read(ocelot, BUF_P_RSRV_I(port));
+		*buf_rsrv_e += ocelot_wm_read(ocelot, BUF_P_RSRV_E(port));
+	}
+
+	*buf_rsrv_i *= OCELOT_BUFFER_CELL_SZ;
+	*buf_rsrv_e *= OCELOT_BUFFER_CELL_SZ;
+}
+
+static void ocelot_get_ref_rsrv(struct ocelot *ocelot, u32 *ref_rsrv_i,
+				u32 *ref_rsrv_e)
+{
+	int port, prio;
+
+	*ref_rsrv_i = 0;
+	*ref_rsrv_e = 0;
+
+	for (port = 0; port <= ocelot->num_phys_ports; port++) {
+		for (prio = 0; prio < OCELOT_NUM_TC; prio++) {
+			*ref_rsrv_i += ocelot_wm_read(ocelot,
+						      REF_Q_RSRV_I(port, prio));
+			*ref_rsrv_e += ocelot_wm_read(ocelot,
+						      REF_Q_RSRV_E(port, prio));
+		}
+
+		*ref_rsrv_i += ocelot_wm_read(ocelot, REF_P_RSRV_I(port));
+		*ref_rsrv_e += ocelot_wm_read(ocelot, REF_P_RSRV_E(port));
+	}
+}
+
+/* Calculate all reservations, then set up the sharing watermark for DP=0 to
+ * consume the remaining resources up to the pool's configured size.
+ */
+static void ocelot_setup_sharing_watermarks(struct ocelot *ocelot)
+{
+	u32 buf_rsrv_i, buf_rsrv_e;
+	u32 ref_rsrv_i, ref_rsrv_e;
+	u32 buf_shr_i, buf_shr_e;
+	u32 ref_shr_i, ref_shr_e;
+
+	ocelot_get_buf_rsrv(ocelot, &buf_rsrv_i, &buf_rsrv_e);
+	ocelot_get_ref_rsrv(ocelot, &ref_rsrv_i, &ref_rsrv_e);
+
+	buf_shr_i = ocelot->packet_buffer_size - buf_rsrv_i;
+	buf_shr_e = ocelot->packet_buffer_size - buf_rsrv_e;
+	ref_shr_i = ocelot->num_frame_refs - ref_rsrv_i;
+	ref_shr_e = ocelot->num_frame_refs - ref_rsrv_e;
+
+	buf_shr_i /= OCELOT_BUFFER_CELL_SZ;
+	buf_shr_e /= OCELOT_BUFFER_CELL_SZ;
+
+	ocelot_wm_write(ocelot, BUF_COL_SHR_I(0), buf_shr_i);
+	ocelot_wm_write(ocelot, BUF_COL_SHR_E(0), buf_shr_e);
+	ocelot_wm_write(ocelot, REF_COL_SHR_E(0), ref_shr_e);
+	ocelot_wm_write(ocelot, REF_COL_SHR_I(0), ref_shr_i);
+	ocelot_wm_write(ocelot, BUF_COL_SHR_I(1), 0);
+	ocelot_wm_write(ocelot, BUF_COL_SHR_E(1), 0);
+	ocelot_wm_write(ocelot, REF_COL_SHR_E(1), 0);
+	ocelot_wm_write(ocelot, REF_COL_SHR_I(1), 0);
+}
+
+/* The hardware works like this:
+ *
+ *                         Frame forwarding decision taken
+ *                                       |
+ *                                       v
+ *       +--------------------+--------------------+--------------------+
+ *       |                    |                    |                    |
+ *       v                    v                    v                    v
+ * Ingress memory       Egress memory        Ingress frame        Egress frame
+ *     check                check           reference check      reference check
+ *       |                    |                    |                    |
+ *       v                    v                    v                    v
+ *  BUF_Q_RSRV_I   ok    BUF_Q_RSRV_E   ok    REF_Q_RSRV_I   ok     REF_Q_RSRV_E   ok
+ *(src port, prio) -+  (dst port, prio) -+  (src port, prio) -+   (dst port, prio) -+
+ *       |          |         |          |         |          |         |           |
+ *       |exceeded  |         |exceeded  |         |exceeded  |         |exceeded   |
+ *       v          |         v          |         v          |         v           |
+ *  BUF_P_RSRV_I  ok|    BUF_P_RSRV_E  ok|    REF_P_RSRV_I  ok|    REF_P_RSRV_E   ok|
+ *   (src port) ----+     (dst port) ----+     (src port) ----+     (dst port) -----+
+ *       |          |         |          |         |          |         |           |
+ *       |exceeded  |         |exceeded  |         |exceeded  |         |exceeded   |
+ *       v          |         v          |         v          |         v           |
+ * BUF_PRIO_SHR_I ok|   BUF_PRIO_SHR_E ok|   REF_PRIO_SHR_I ok|   REF_PRIO_SHR_E  ok|
+ *     (prio) ------+       (prio) ------+       (prio) ------+       (prio) -------+
+ *       |          |         |          |         |          |         |           |
+ *       |exceeded  |         |exceeded  |         |exceeded  |         |exceeded   |
+ *       v          |         v          |         v          |         v           |
+ * BUF_COL_SHR_I  ok|   BUF_COL_SHR_E  ok|   REF_COL_SHR_I  ok|   REF_COL_SHR_E   ok|
+ *      (dp) -------+        (dp) -------+        (dp) -------+        (dp) --------+
+ *       |          |         |          |         |          |         |           |
+ *       |exceeded  |         |exceeded  |         |exceeded  |         |exceeded   |
+ *       v          v         v          v         v          v         v           v
+ *      fail     success     fail     success     fail     success     fail      success
+ *       |          |         |          |         |          |         |           |
+ *       v          v         v          v         v          v         v           v
+ *       +-----+----+         +-----+----+         +-----+----+         +-----+-----+
+ *             |                    |                    |                    |
+ *             +-------> OR <-------+                    +-------> OR <-------+
+ *                        |                                        |
+ *                        v                                        v
+ *                        +----------------> AND <-----------------+
+ *                                            |
+ *                                            v
+ *                                    FIFO drop / accept
+ *
+ * We are modeling each of the 4 parallel lookups as a devlink-sb pool.
+ * At least one (ingress or egress) memory pool and one (ingress or egress)
+ * frame reference pool need to have resources for frame acceptance to succeed.
+ *
+ * The following watermarks are controlled explicitly through devlink-sb:
+ * BUF_Q_RSRV_I, BUF_Q_RSRV_E, REF_Q_RSRV_I, REF_Q_RSRV_E
+ * BUF_P_RSRV_I, BUF_P_RSRV_E, REF_P_RSRV_I, REF_P_RSRV_E
+ * The following watermarks are controlled implicitly through devlink-sb:
+ * BUF_COL_SHR_I, BUF_COL_SHR_E, REF_COL_SHR_I, REF_COL_SHR_E
+ * The following watermarks are unused and disabled:
+ * BUF_PRIO_SHR_I, BUF_PRIO_SHR_E, REF_PRIO_SHR_I, REF_PRIO_SHR_E
+ *
+ * This function overrides the hardware defaults with more sane ones (no
+ * reservations by default, let sharing use all resources) and disables the
+ * unused watermarks.
+ */
+void ocelot_watermark_init(struct ocelot *ocelot)
+{
+	int all_tcs = GENMASK(OCELOT_NUM_TC - 1, 0);
+	int port;
+
+	ocelot_write(ocelot, all_tcs, QSYS_RES_QOS_MODE);
+
+	for (port = 0; port <= ocelot->num_phys_ports; port++)
+		ocelot_disable_reservation_watermarks(ocelot, port);
+
+	ocelot_disable_tc_sharing_watermarks(ocelot);
+	ocelot_setup_sharing_watermarks(ocelot);
+}
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v3 net-next 10/10] net: mscc: ocelot: configure watermarks using devlink-sb
  2021-01-08 17:59 [PATCH v3 net-next 00/10] Configuring congestion watermarks on ocelot switch using devlink-sb Vladimir Oltean
                   ` (8 preceding siblings ...)
  2021-01-08 17:59 ` [PATCH v3 net-next 09/10] net: mscc: ocelot: initialize watermarks to sane defaults Vladimir Oltean
@ 2021-01-08 17:59 ` Vladimir Oltean
  2021-01-09  4:03   ` Florian Fainelli
  9 siblings, 1 reply; 36+ messages in thread
From: Vladimir Oltean @ 2021-01-08 17:59 UTC (permalink / raw)
  To: netdev
  Cc: alexandre.belloni, andrew, f.fainelli, vivien.didelot,
	alexandru.marginean, claudiu.manoil, xiaoliang.yang_1,
	hongbo.wang, kuba, jiri, idosch, UNGLinuxDriver

From: Vladimir Oltean <vladimir.oltean@nxp.com>

Using devlink-sb, we can configure 12/16 (the important 75%) of the
switch's controlling watermarks for congestion drops, and we can monitor
50% of the watermark occupancies (we can monitor the reservation
watermarks, but not the sharing watermarks, which are exposed as pool
sizes).

The following definitions can be made:

SB_BUF=0 # The devlink-sb for frame buffers
SB_REF=1 # The devlink-sb for frame references
POOL_ING=0 # The pool for ingress traffic. Both devlink-sb instances
           # have one of these.
POOL_EGR=1 # The pool for egress traffic. Both devlink-sb instances
           # have one of these.

Editing the hardware watermarks is done in the following way:
BUF_xxxx_I is accessed when sb=$SB_BUF and pool=$POOL_ING
REF_xxxx_I is accessed when sb=$SB_REF and pool=$POOL_ING
BUF_xxxx_E is accessed when sb=$SB_BUF and pool=$POOL_EGR
REF_xxxx_E is accessed when sb=$SB_REF and pool=$POOL_EGR

Configuring the sharing watermarks for COL_SHR(dp=0) is done implicitly
by modifying the corresponding pool size. By default, the pool size has
maximum size, so this can be skipped.

devlink sb pool set pci/0000:00:00.5 sb $SB_BUF pool $POOL_ING \
	size 103872 thtype static

Since by default there is no buffer reservation, the above command has
maxed out BUF_COL_SHR_I(dp=0).

Configuring the per-port reservation watermark (P_RSRV) is done in the
following way:

devlink sb port pool set pci/0000:00:00.5/0 sb $SB_BUF \
	pool $POOL_ING th 1000

The above command sets BUF_P_RSRV_I(port 0) to 1000 bytes. After this
command, the sharing watermarks are internally reconfigured with 1000
bytes less, i.e. from 103872 bytes to 102872 bytes.

Configuring the per-port-tc reservation watermarks (Q_RSRV) is done in
the following way:

for tc in {0..7}; do
	devlink sb tc bind set pci/0000:00:00.5/0 sb 0 tc $tc \
		type ingress pool $POOL_ING \
		th 3000
done

The above command sets BUF_Q_RSRV_I(port 0, tc 0..7) to 3000 bytes.
The sharing watermarks are again reconfigured with 24000 bytes less.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
Changes in v3:
None.

Changes in v2:
- Calling ocelot_watermark_init from ocelot_devlink_sb_register, since
  there was a bug in v1 where ocelot_watermark_init would use an
  uninitialized value from ocelot->pool_size, so we need to ensure that
  ocelot_watermark_init is called after ocelot_devlink_sb_register
  actually initializes the pool sizes.
- Deleted the "detected N bytes and M frame references" message since
  that information is now available through devlink-sb.

 drivers/net/dsa/ocelot/felix.c             | 118 ++++++
 drivers/net/ethernet/mscc/ocelot.c         |   5 -
 drivers/net/ethernet/mscc/ocelot.h         |   1 -
 drivers/net/ethernet/mscc/ocelot_devlink.c | 453 ++++++++++++++++++++-
 drivers/net/ethernet/mscc/ocelot_net.c     | 143 +++++++
 drivers/net/ethernet/mscc/ocelot_vsc7514.c |  27 +-
 include/soc/mscc/ocelot.h                  |  47 +++
 7 files changed, 781 insertions(+), 13 deletions(-)

diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c
index f41f3476ae06..8c421165213a 100644
--- a/drivers/net/dsa/ocelot/felix.c
+++ b/drivers/net/dsa/ocelot/felix.c
@@ -456,6 +456,7 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports)
 	ocelot->ops		= felix->info->ops;
 	ocelot->inj_prefix	= OCELOT_TAG_PREFIX_SHORT;
 	ocelot->xtr_prefix	= OCELOT_TAG_PREFIX_SHORT;
+	ocelot->devlink		= felix->ds->devlink;
 
 	port_phy_modes = kcalloc(num_phys_ports, sizeof(phy_interface_t),
 				 GFP_KERNEL);
@@ -617,6 +618,10 @@ static int felix_setup(struct dsa_switch *ds)
 		felix_port_qos_map_init(ocelot, port);
 	}
 
+	err = ocelot_devlink_sb_register(ocelot);
+	if (err)
+		return err;
+
 	/* Include the CPU port module in the forwarding mask for unknown
 	 * unicast - the hardware default value for ANA_FLOODING_FLD_UNICAST
 	 * excludes BIT(ocelot->num_phys_ports), and so does ocelot_init, since
@@ -639,6 +644,7 @@ static void felix_teardown(struct dsa_switch *ds)
 	struct felix *felix = ocelot_to_felix(ocelot);
 	int port;
 
+	ocelot_devlink_sb_unregister(ocelot);
 	if (ocelot->ptp)
 		ocelot_deinit_timestamp(ocelot);
 	ocelot_deinit(ocelot);
@@ -779,6 +785,108 @@ static int felix_port_setup_tc(struct dsa_switch *ds, int port,
 		return -EOPNOTSUPP;
 }
 
+static int felix_sb_pool_get(struct dsa_switch *ds, unsigned int sb_index,
+			     u16 pool_index,
+			     struct devlink_sb_pool_info *pool_info)
+{
+	struct ocelot *ocelot = ds->priv;
+
+	return ocelot_sb_pool_get(ocelot, sb_index, pool_index, pool_info);
+}
+
+static int felix_sb_pool_set(struct dsa_switch *ds, unsigned int sb_index,
+			     u16 pool_index, u32 size,
+			     enum devlink_sb_threshold_type threshold_type,
+			     struct netlink_ext_ack *extack)
+{
+	struct ocelot *ocelot = ds->priv;
+
+	return ocelot_sb_pool_set(ocelot, sb_index, pool_index, size,
+				  threshold_type, extack);
+}
+
+static int felix_sb_port_pool_get(struct dsa_switch *ds, int port,
+				  unsigned int sb_index, u16 pool_index,
+				  u32 *p_threshold)
+{
+	struct ocelot *ocelot = ds->priv;
+
+	return ocelot_sb_port_pool_get(ocelot, port, sb_index, pool_index,
+				       p_threshold);
+}
+
+static int felix_sb_port_pool_set(struct dsa_switch *ds, int port,
+				  unsigned int sb_index, u16 pool_index,
+				  u32 threshold, struct netlink_ext_ack *extack)
+{
+	struct ocelot *ocelot = ds->priv;
+
+	return ocelot_sb_port_pool_set(ocelot, port, sb_index, pool_index,
+				       threshold, extack);
+}
+
+static int felix_sb_tc_pool_bind_get(struct dsa_switch *ds, int port,
+				     unsigned int sb_index, u16 tc_index,
+				     enum devlink_sb_pool_type pool_type,
+				     u16 *p_pool_index, u32 *p_threshold)
+{
+	struct ocelot *ocelot = ds->priv;
+
+	return ocelot_sb_tc_pool_bind_get(ocelot, port, sb_index, tc_index,
+					  pool_type, p_pool_index,
+					  p_threshold);
+}
+
+static int felix_sb_tc_pool_bind_set(struct dsa_switch *ds, int port,
+				     unsigned int sb_index, u16 tc_index,
+				     enum devlink_sb_pool_type pool_type,
+				     u16 pool_index, u32 threshold,
+				     struct netlink_ext_ack *extack)
+{
+	struct ocelot *ocelot = ds->priv;
+
+	return ocelot_sb_tc_pool_bind_set(ocelot, port, sb_index, tc_index,
+					  pool_type, pool_index, threshold,
+					  extack);
+}
+
+static int felix_sb_occ_snapshot(struct dsa_switch *ds,
+				 unsigned int sb_index)
+{
+	struct ocelot *ocelot = ds->priv;
+
+	return ocelot_sb_occ_snapshot(ocelot, sb_index);
+}
+
+static int felix_sb_occ_max_clear(struct dsa_switch *ds,
+				  unsigned int sb_index)
+{
+	struct ocelot *ocelot = ds->priv;
+
+	return ocelot_sb_occ_max_clear(ocelot, sb_index);
+}
+
+static int felix_sb_occ_port_pool_get(struct dsa_switch *ds, int port,
+				      unsigned int sb_index, u16 pool_index,
+				      u32 *p_cur, u32 *p_max)
+{
+	struct ocelot *ocelot = ds->priv;
+
+	return ocelot_sb_occ_port_pool_get(ocelot, port, sb_index, pool_index,
+					   p_cur, p_max);
+}
+
+static int felix_sb_occ_tc_port_bind_get(struct dsa_switch *ds, int port,
+					 unsigned int sb_index, u16 tc_index,
+					 enum devlink_sb_pool_type pool_type,
+					 u32 *p_cur, u32 *p_max)
+{
+	struct ocelot *ocelot = ds->priv;
+
+	return ocelot_sb_occ_tc_port_bind_get(ocelot, port, sb_index, tc_index,
+					      pool_type, p_cur, p_max);
+}
+
 const struct dsa_switch_ops felix_switch_ops = {
 	.get_tag_protocol		= felix_get_tag_protocol,
 	.setup				= felix_setup,
@@ -819,6 +927,16 @@ const struct dsa_switch_ops felix_switch_ops = {
 	.cls_flower_del			= felix_cls_flower_del,
 	.cls_flower_stats		= felix_cls_flower_stats,
 	.port_setup_tc			= felix_port_setup_tc,
+	.devlink_sb_pool_get		= felix_sb_pool_get,
+	.devlink_sb_pool_set		= felix_sb_pool_set,
+	.devlink_sb_port_pool_get	= felix_sb_port_pool_get,
+	.devlink_sb_port_pool_set	= felix_sb_port_pool_set,
+	.devlink_sb_tc_pool_bind_get	= felix_sb_tc_pool_bind_get,
+	.devlink_sb_tc_pool_bind_set	= felix_sb_tc_pool_bind_set,
+	.devlink_sb_occ_snapshot	= felix_sb_occ_snapshot,
+	.devlink_sb_occ_max_clear	= felix_sb_occ_max_clear,
+	.devlink_sb_occ_port_pool_get	= felix_sb_occ_port_pool_get,
+	.devlink_sb_occ_tc_port_bind_get= felix_sb_occ_tc_port_bind_get,
 };
 
 struct net_device *felix_port_to_netdev(struct ocelot *ocelot, int port)
diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c
index f547728c6718..02fa86c72eb5 100644
--- a/drivers/net/ethernet/mscc/ocelot.c
+++ b/drivers/net/ethernet/mscc/ocelot.c
@@ -1492,10 +1492,6 @@ static void ocelot_detect_features(struct ocelot *ocelot)
 
 	eq_ctrl = ocelot_read(ocelot, QSYS_EQ_CTRL);
 	ocelot->num_frame_refs = QSYS_MMGT_EQ_CTRL_FP_FREE_CNT(eq_ctrl);
-
-	dev_info(ocelot->dev,
-		 "Detected %d bytes of packet buffer and %d frame references\n",
-		 ocelot->packet_buffer_size, ocelot->num_frame_refs);
 }
 
 int ocelot_init(struct ocelot *ocelot)
@@ -1636,7 +1632,6 @@ int ocelot_init(struct ocelot *ocelot)
 	INIT_DELAYED_WORK(&ocelot->stats_work, ocelot_check_stats_work);
 	queue_delayed_work(ocelot->stats_queue, &ocelot->stats_work,
 			   OCELOT_STATS_CHECK_DELAY);
-	ocelot_watermark_init(ocelot);
 
 	return 0;
 }
diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h
index a9d60ef30344..2e9a3c4697c8 100644
--- a/drivers/net/ethernet/mscc/ocelot.h
+++ b/drivers/net/ethernet/mscc/ocelot.h
@@ -125,7 +125,6 @@ int ocelot_probe_port(struct ocelot *ocelot, int port, struct regmap *target,
 		      struct phy_device *phy);
 int ocelot_devlink_init(struct ocelot *ocelot);
 void ocelot_devlink_teardown(struct ocelot *ocelot);
-void ocelot_watermark_init(struct ocelot *ocelot);
 
 extern struct notifier_block ocelot_netdevice_nb;
 extern struct notifier_block ocelot_switchdev_nb;
diff --git a/drivers/net/ethernet/mscc/ocelot_devlink.c b/drivers/net/ethernet/mscc/ocelot_devlink.c
index c96309cde82d..d441ab8dcfb8 100644
--- a/drivers/net/ethernet/mscc/ocelot_devlink.c
+++ b/drivers/net/ethernet/mscc/ocelot_devlink.c
@@ -232,6 +232,14 @@ static void ocelot_wm_write(struct ocelot *ocelot, int index, u32 val)
 	ocelot_write_gix(ocelot, wm, QSYS_RES_CFG, index);
 }
 
+static void ocelot_wm_status(struct ocelot *ocelot, int index, u32 *inuse,
+			     u32 *maxuse)
+{
+	int res_stat = ocelot_read_gix(ocelot, QSYS_RES_STAT, index);
+
+	return ocelot->ops->wm_stat(res_stat, inuse, maxuse);
+}
+
 /* The hardware comes out of reset with strange defaults: the sum of all
  * reservations for frame memory is larger than the total buffer size.
  * One has to wonder how can the reservation watermarks still guarantee
@@ -348,10 +356,14 @@ static void ocelot_setup_sharing_watermarks(struct ocelot *ocelot)
 	ocelot_get_buf_rsrv(ocelot, &buf_rsrv_i, &buf_rsrv_e);
 	ocelot_get_ref_rsrv(ocelot, &ref_rsrv_i, &ref_rsrv_e);
 
-	buf_shr_i = ocelot->packet_buffer_size - buf_rsrv_i;
-	buf_shr_e = ocelot->packet_buffer_size - buf_rsrv_e;
-	ref_shr_i = ocelot->num_frame_refs - ref_rsrv_i;
-	ref_shr_e = ocelot->num_frame_refs - ref_rsrv_e;
+	buf_shr_i = ocelot->pool_size[OCELOT_SB_BUF][OCELOT_SB_POOL_ING] -
+		    buf_rsrv_i;
+	buf_shr_e = ocelot->pool_size[OCELOT_SB_BUF][OCELOT_SB_POOL_EGR] -
+		    buf_rsrv_e;
+	ref_shr_i = ocelot->pool_size[OCELOT_SB_REF][OCELOT_SB_POOL_ING] -
+		    ref_rsrv_i;
+	ref_shr_e = ocelot->pool_size[OCELOT_SB_REF][OCELOT_SB_POOL_EGR] -
+		    ref_rsrv_e;
 
 	buf_shr_i /= OCELOT_BUFFER_CELL_SZ;
 	buf_shr_e /= OCELOT_BUFFER_CELL_SZ;
@@ -366,6 +378,40 @@ static void ocelot_setup_sharing_watermarks(struct ocelot *ocelot)
 	ocelot_wm_write(ocelot, REF_COL_SHR_I(1), 0);
 }
 
+/* Ensure that all reservations can be enforced */
+static int ocelot_watermark_validate(struct ocelot *ocelot,
+				     struct netlink_ext_ack *extack)
+{
+	u32 buf_rsrv_i, buf_rsrv_e;
+	u32 ref_rsrv_i, ref_rsrv_e;
+
+	ocelot_get_buf_rsrv(ocelot, &buf_rsrv_i, &buf_rsrv_e);
+	ocelot_get_ref_rsrv(ocelot, &ref_rsrv_i, &ref_rsrv_e);
+
+	if (buf_rsrv_i > ocelot->pool_size[OCELOT_SB_BUF][OCELOT_SB_POOL_ING]) {
+		NL_SET_ERR_MSG_MOD(extack,
+				   "Ingress frame reservations exceed pool size");
+		return -ERANGE;
+	}
+	if (buf_rsrv_e > ocelot->pool_size[OCELOT_SB_BUF][OCELOT_SB_POOL_EGR]) {
+		NL_SET_ERR_MSG_MOD(extack,
+				   "Egress frame reservations exceed pool size");
+		return -ERANGE;
+	}
+	if (ref_rsrv_i > ocelot->pool_size[OCELOT_SB_REF][OCELOT_SB_POOL_ING]) {
+		NL_SET_ERR_MSG_MOD(extack,
+				   "Ingress reference reservations exceed pool size");
+		return -ERANGE;
+	}
+	if (ref_rsrv_e > ocelot->pool_size[OCELOT_SB_REF][OCELOT_SB_POOL_EGR]) {
+		NL_SET_ERR_MSG_MOD(extack,
+				   "Egress reference reservations exceed pool size");
+		return -ERANGE;
+	}
+
+	return 0;
+}
+
 /* The hardware works like this:
  *
  *                         Frame forwarding decision taken
@@ -427,7 +473,7 @@ static void ocelot_setup_sharing_watermarks(struct ocelot *ocelot)
  * reservations by default, let sharing use all resources) and disables the
  * unused watermarks.
  */
-void ocelot_watermark_init(struct ocelot *ocelot)
+static void ocelot_watermark_init(struct ocelot *ocelot)
 {
 	int all_tcs = GENMASK(OCELOT_NUM_TC - 1, 0);
 	int port;
@@ -440,3 +486,400 @@ void ocelot_watermark_init(struct ocelot *ocelot)
 	ocelot_disable_tc_sharing_watermarks(ocelot);
 	ocelot_setup_sharing_watermarks(ocelot);
 }
+
+/* Pool size and type are fixed up at runtime. Keeping this structure to
+ * look up the cell size multipliers.
+ */
+static const struct devlink_sb_pool_info ocelot_sb_pool[] = {
+	[OCELOT_SB_BUF] = {
+		.cell_size = OCELOT_BUFFER_CELL_SZ,
+		.threshold_type = DEVLINK_SB_THRESHOLD_TYPE_STATIC,
+	},
+	[OCELOT_SB_REF] = {
+		.cell_size = 1,
+		.threshold_type = DEVLINK_SB_THRESHOLD_TYPE_STATIC,
+	},
+};
+
+/* Returns the pool size configured through ocelot_sb_pool_set */
+int ocelot_sb_pool_get(struct ocelot *ocelot, unsigned int sb_index,
+		       u16 pool_index,
+		       struct devlink_sb_pool_info *pool_info)
+{
+	if (sb_index >= OCELOT_SB_NUM)
+		return -ENODEV;
+	if (pool_index >= OCELOT_SB_POOL_NUM)
+		return -ENODEV;
+
+	*pool_info = ocelot_sb_pool[sb_index];
+	pool_info->size = ocelot->pool_size[sb_index][pool_index];
+	if (pool_index)
+		pool_info->pool_type = DEVLINK_SB_POOL_TYPE_INGRESS;
+	else
+		pool_info->pool_type = DEVLINK_SB_POOL_TYPE_EGRESS;
+
+	return 0;
+}
+EXPORT_SYMBOL(ocelot_sb_pool_get);
+
+/* The pool size received here configures the total amount of resources used on
+ * ingress (or on egress, depending upon the pool index). The pool size, minus
+ * the values for the port and port-tc reservations, is written into the
+ * COL_SHR(dp=0) sharing watermark.
+ */
+int ocelot_sb_pool_set(struct ocelot *ocelot, unsigned int sb_index,
+		       u16 pool_index, u32 size,
+		       enum devlink_sb_threshold_type threshold_type,
+		       struct netlink_ext_ack *extack)
+{
+	u32 old_pool_size;
+	int err;
+
+	if (sb_index >= OCELOT_SB_NUM) {
+		NL_SET_ERR_MSG_MOD(extack,
+				   "Invalid sb, use 0 for buffers and 1 for frame references");
+		return -ENODEV;
+	}
+	if (pool_index >= OCELOT_SB_POOL_NUM) {
+		NL_SET_ERR_MSG_MOD(extack,
+				   "Invalid pool, use 0 for ingress and 1 for egress");
+		return -ENODEV;
+	}
+	if (threshold_type != DEVLINK_SB_THRESHOLD_TYPE_STATIC) {
+		NL_SET_ERR_MSG_MOD(extack,
+				   "Only static threshold supported");
+		return -EOPNOTSUPP;
+	}
+
+	old_pool_size = ocelot->pool_size[sb_index][pool_index];
+	ocelot->pool_size[sb_index][pool_index] = size;
+
+	err = ocelot_watermark_validate(ocelot, extack);
+	if (err) {
+		ocelot->pool_size[sb_index][pool_index] = old_pool_size;
+		return err;
+	}
+
+	ocelot_setup_sharing_watermarks(ocelot);
+
+	return 0;
+}
+EXPORT_SYMBOL(ocelot_sb_pool_set);
+
+/* This retrieves the configuration made with ocelot_sb_port_pool_set */
+int ocelot_sb_port_pool_get(struct ocelot *ocelot, int port,
+			    unsigned int sb_index, u16 pool_index,
+			    u32 *p_threshold)
+{
+	int wm_index;
+
+	switch (sb_index) {
+	case OCELOT_SB_BUF:
+		if (pool_index == OCELOT_SB_POOL_ING)
+			wm_index = BUF_P_RSRV_I(port);
+		else
+			wm_index = BUF_P_RSRV_E(port);
+		break;
+	case OCELOT_SB_REF:
+		if (pool_index == OCELOT_SB_POOL_ING)
+			wm_index = REF_P_RSRV_I(port);
+		else
+			wm_index = REF_P_RSRV_E(port);
+		break;
+	default:
+		return -ENODEV;
+	}
+
+	*p_threshold = ocelot_wm_read(ocelot, wm_index);
+	*p_threshold *= ocelot_sb_pool[sb_index].cell_size;
+
+	return 0;
+}
+EXPORT_SYMBOL(ocelot_sb_port_pool_get);
+
+/* This configures the P_RSRV per-port reserved resource watermark */
+int ocelot_sb_port_pool_set(struct ocelot *ocelot, int port,
+			    unsigned int sb_index, u16 pool_index,
+			    u32 threshold, struct netlink_ext_ack *extack)
+{
+	int wm_index, err;
+	u32 old_thr;
+
+	switch (sb_index) {
+	case OCELOT_SB_BUF:
+		if (pool_index == OCELOT_SB_POOL_ING)
+			wm_index = BUF_P_RSRV_I(port);
+		else
+			wm_index = BUF_P_RSRV_E(port);
+		break;
+	case OCELOT_SB_REF:
+		if (pool_index == OCELOT_SB_POOL_ING)
+			wm_index = REF_P_RSRV_I(port);
+		else
+			wm_index = REF_P_RSRV_E(port);
+		break;
+	default:
+		NL_SET_ERR_MSG_MOD(extack, "Invalid shared buffer");
+		return -ENODEV;
+	}
+
+	threshold /= ocelot_sb_pool[sb_index].cell_size;
+
+	old_thr = ocelot_wm_read(ocelot, wm_index);
+	ocelot_wm_write(ocelot, wm_index, threshold);
+
+	err = ocelot_watermark_validate(ocelot, extack);
+	if (err) {
+		ocelot_wm_write(ocelot, wm_index, old_thr);
+		return err;
+	}
+
+	ocelot_setup_sharing_watermarks(ocelot);
+
+	return 0;
+}
+EXPORT_SYMBOL(ocelot_sb_port_pool_set);
+
+/* This retrieves the configuration done by ocelot_sb_tc_pool_bind_set */
+int ocelot_sb_tc_pool_bind_get(struct ocelot *ocelot, int port,
+			       unsigned int sb_index, u16 tc_index,
+			       enum devlink_sb_pool_type pool_type,
+			       u16 *p_pool_index, u32 *p_threshold)
+{
+	int wm_index;
+
+	switch (sb_index) {
+	case OCELOT_SB_BUF:
+		if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS)
+			wm_index = BUF_Q_RSRV_I(port, tc_index);
+		else
+			wm_index = BUF_Q_RSRV_E(port, tc_index);
+		break;
+	case OCELOT_SB_REF:
+		if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS)
+			wm_index = REF_Q_RSRV_I(port, tc_index);
+		else
+			wm_index = REF_Q_RSRV_E(port, tc_index);
+		break;
+	default:
+		return -ENODEV;
+	}
+
+	*p_threshold = ocelot_wm_read(ocelot, wm_index);
+	*p_threshold *= ocelot_sb_pool[sb_index].cell_size;
+
+	if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS)
+		*p_pool_index = 0;
+	else
+		*p_pool_index = 1;
+
+	return 0;
+}
+EXPORT_SYMBOL(ocelot_sb_tc_pool_bind_get);
+
+/* This configures the Q_RSRV per-port-tc reserved resource watermark */
+int ocelot_sb_tc_pool_bind_set(struct ocelot *ocelot, int port,
+			       unsigned int sb_index, u16 tc_index,
+			       enum devlink_sb_pool_type pool_type,
+			       u16 pool_index, u32 threshold,
+			       struct netlink_ext_ack *extack)
+{
+	int wm_index, err;
+	u32 old_thr;
+
+	/* Paranoid check? */
+	if (pool_index == OCELOT_SB_POOL_ING &&
+	    pool_type != DEVLINK_SB_POOL_TYPE_INGRESS)
+		return -EINVAL;
+	if (pool_index == OCELOT_SB_POOL_EGR &&
+	    pool_type != DEVLINK_SB_POOL_TYPE_EGRESS)
+		return -EINVAL;
+
+	switch (sb_index) {
+	case OCELOT_SB_BUF:
+		if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS)
+			wm_index = BUF_Q_RSRV_I(port, tc_index);
+		else
+			wm_index = BUF_Q_RSRV_E(port, tc_index);
+		break;
+	case OCELOT_SB_REF:
+		if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS)
+			wm_index = REF_Q_RSRV_I(port, tc_index);
+		else
+			wm_index = REF_Q_RSRV_E(port, tc_index);
+		break;
+	default:
+		NL_SET_ERR_MSG_MOD(extack, "Invalid shared buffer");
+		return -ENODEV;
+	}
+
+	threshold /= ocelot_sb_pool[sb_index].cell_size;
+
+	old_thr = ocelot_wm_read(ocelot, wm_index);
+	ocelot_wm_write(ocelot, wm_index, threshold);
+	err = ocelot_watermark_validate(ocelot, extack);
+	if (err) {
+		ocelot_wm_write(ocelot, wm_index, old_thr);
+		return err;
+	}
+
+	ocelot_setup_sharing_watermarks(ocelot);
+
+	return 0;
+}
+EXPORT_SYMBOL(ocelot_sb_tc_pool_bind_set);
+
+/* The hardware does not support atomic snapshots, we'll read out the
+ * occupancy registers individually and have this as just a stub.
+ */
+int ocelot_sb_occ_snapshot(struct ocelot *ocelot, unsigned int sb_index)
+{
+	return 0;
+}
+EXPORT_SYMBOL(ocelot_sb_occ_snapshot);
+
+/* The watermark occupancy registers are cleared upon read,
+ * so let's read them.
+ */
+int ocelot_sb_occ_max_clear(struct ocelot *ocelot, unsigned int sb_index)
+{
+	u32 inuse, maxuse;
+	int port, prio;
+
+	switch (sb_index) {
+	case OCELOT_SB_BUF:
+		for (port = 0; port <= ocelot->num_phys_ports; port++) {
+			for (prio = 0; prio < OCELOT_NUM_TC; prio++) {
+				ocelot_wm_status(ocelot, BUF_Q_RSRV_I(port, prio),
+						 &inuse, &maxuse);
+				ocelot_wm_status(ocelot, BUF_Q_RSRV_E(port, prio),
+						 &inuse, &maxuse);
+			}
+			ocelot_wm_status(ocelot, BUF_P_RSRV_I(port),
+					 &inuse, &maxuse);
+			ocelot_wm_status(ocelot, BUF_P_RSRV_E(port),
+					 &inuse, &maxuse);
+		}
+		break;
+	case OCELOT_SB_REF:
+		for (port = 0; port <= ocelot->num_phys_ports; port++) {
+			for (prio = 0; prio < OCELOT_NUM_TC; prio++) {
+				ocelot_wm_status(ocelot, REF_Q_RSRV_I(port, prio),
+						 &inuse, &maxuse);
+				ocelot_wm_status(ocelot, REF_Q_RSRV_E(port, prio),
+						 &inuse, &maxuse);
+			}
+			ocelot_wm_status(ocelot, REF_P_RSRV_I(port),
+					 &inuse, &maxuse);
+			ocelot_wm_status(ocelot, REF_P_RSRV_E(port),
+					 &inuse, &maxuse);
+		}
+		break;
+	default:
+		return -ENODEV;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(ocelot_sb_occ_max_clear);
+
+/* This retrieves the watermark occupancy for per-port P_RSRV watermarks */
+int ocelot_sb_occ_port_pool_get(struct ocelot *ocelot, int port,
+				unsigned int sb_index, u16 pool_index,
+				u32 *p_cur, u32 *p_max)
+{
+	int wm_index;
+
+	switch (sb_index) {
+	case OCELOT_SB_BUF:
+		if (pool_index == OCELOT_SB_POOL_ING)
+			wm_index = BUF_P_RSRV_I(port);
+		else
+			wm_index = BUF_P_RSRV_E(port);
+		break;
+	case OCELOT_SB_REF:
+		if (pool_index == OCELOT_SB_POOL_ING)
+			wm_index = REF_P_RSRV_I(port);
+		else
+			wm_index = REF_P_RSRV_E(port);
+		break;
+	default:
+		return -ENODEV;
+	}
+
+	ocelot_wm_status(ocelot, wm_index, p_cur, p_max);
+	*p_cur *= ocelot_sb_pool[sb_index].cell_size;
+	*p_max *= ocelot_sb_pool[sb_index].cell_size;
+
+	return 0;
+}
+EXPORT_SYMBOL(ocelot_sb_occ_port_pool_get);
+
+/* This retrieves the watermark occupancy for per-port-tc Q_RSRV watermarks */
+int ocelot_sb_occ_tc_port_bind_get(struct ocelot *ocelot, int port,
+				   unsigned int sb_index, u16 tc_index,
+				   enum devlink_sb_pool_type pool_type,
+				   u32 *p_cur, u32 *p_max)
+{
+	int wm_index;
+
+	switch (sb_index) {
+	case OCELOT_SB_BUF:
+		if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS)
+			wm_index = BUF_Q_RSRV_I(port, tc_index);
+		else
+			wm_index = BUF_Q_RSRV_E(port, tc_index);
+		break;
+	case OCELOT_SB_REF:
+		if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS)
+			wm_index = REF_Q_RSRV_I(port, tc_index);
+		else
+			wm_index = REF_Q_RSRV_E(port, tc_index);
+		break;
+	default:
+		return -ENODEV;
+	}
+
+	ocelot_wm_status(ocelot, wm_index, p_cur, p_max);
+	*p_cur *= ocelot_sb_pool[sb_index].cell_size;
+	*p_max *= ocelot_sb_pool[sb_index].cell_size;
+
+	return 0;
+}
+EXPORT_SYMBOL(ocelot_sb_occ_tc_port_bind_get);
+
+int ocelot_devlink_sb_register(struct ocelot *ocelot)
+{
+	int err;
+
+	err = devlink_sb_register(ocelot->devlink, OCELOT_SB_BUF,
+				  ocelot->packet_buffer_size, 1, 1,
+				  OCELOT_NUM_TC, OCELOT_NUM_TC);
+	if (err)
+		return err;
+
+	err = devlink_sb_register(ocelot->devlink, OCELOT_SB_REF,
+				  ocelot->num_frame_refs, 1, 1,
+				  OCELOT_NUM_TC, OCELOT_NUM_TC);
+	if (err) {
+		devlink_sb_unregister(ocelot->devlink, OCELOT_SB_BUF);
+		return err;
+	}
+
+	ocelot->pool_size[OCELOT_SB_BUF][OCELOT_SB_POOL_ING] = ocelot->packet_buffer_size;
+	ocelot->pool_size[OCELOT_SB_BUF][OCELOT_SB_POOL_EGR] = ocelot->packet_buffer_size;
+	ocelot->pool_size[OCELOT_SB_REF][OCELOT_SB_POOL_ING] = ocelot->num_frame_refs;
+	ocelot->pool_size[OCELOT_SB_REF][OCELOT_SB_POOL_EGR] = ocelot->num_frame_refs;
+
+	ocelot_watermark_init(ocelot);
+
+	return 0;
+}
+EXPORT_SYMBOL(ocelot_devlink_sb_register);
+
+void ocelot_devlink_sb_unregister(struct ocelot *ocelot)
+{
+	devlink_sb_unregister(ocelot->devlink, OCELOT_SB_BUF);
+	devlink_sb_unregister(ocelot->devlink, OCELOT_SB_REF);
+}
+EXPORT_SYMBOL(ocelot_devlink_sb_unregister);
diff --git a/drivers/net/ethernet/mscc/ocelot_net.c b/drivers/net/ethernet/mscc/ocelot_net.c
index d0d98c6adea8..ae1f9d6cf7f2 100644
--- a/drivers/net/ethernet/mscc/ocelot_net.c
+++ b/drivers/net/ethernet/mscc/ocelot_net.c
@@ -1,7 +1,11 @@
 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
 /* Microsemi Ocelot Switch driver
+ *
+ * This contains glue logic between the switchdev driver operations and the
+ * mscc_ocelot_switch_lib.
  *
  * Copyright (c) 2017, 2019 Microsemi Corporation
+ * Copyright 2020 NXP Semiconductors
  */
 
 #include <linux/if_bridge.h>
@@ -12,7 +16,146 @@ struct ocelot_devlink_private {
 	struct ocelot *ocelot;
 };
 
+static struct ocelot_port_private *
+devlink_to_ocelot_port_priv(struct devlink_port *dlp)
+{
+	return container_of(dlp, struct ocelot_port_private, devlink_port);
+}
+
+static int ocelot_devlink_sb_pool_get(struct devlink *dl,
+				      unsigned int sb_index, u16 pool_index,
+				      struct devlink_sb_pool_info *pool_info)
+{
+	struct ocelot_devlink_private *dl_priv = devlink_priv(dl);
+	struct ocelot *ocelot = dl_priv->ocelot;
+
+	return ocelot_sb_pool_get(ocelot, sb_index, pool_index, pool_info);
+}
+
+static int ocelot_devlink_sb_pool_set(struct devlink *dl, unsigned int sb_index,
+				      u16 pool_index, u32 size,
+				      enum devlink_sb_threshold_type threshold_type,
+				      struct netlink_ext_ack *extack)
+{
+	struct ocelot_devlink_private *dl_priv = devlink_priv(dl);
+	struct ocelot *ocelot = dl_priv->ocelot;
+
+	return ocelot_sb_pool_set(ocelot, sb_index, pool_index, size,
+				  threshold_type, extack);
+}
+
+static int ocelot_devlink_sb_port_pool_get(struct devlink_port *dlp,
+					   unsigned int sb_index, u16 pool_index,
+					   u32 *p_threshold)
+{
+	struct ocelot_devlink_private *dl_priv = devlink_priv(dlp->devlink);
+	struct ocelot_port_private *priv = devlink_to_ocelot_port_priv(dlp);
+	struct ocelot *ocelot = dl_priv->ocelot;
+
+	return ocelot_sb_port_pool_get(ocelot, priv->chip_port, sb_index,
+				       pool_index, p_threshold);
+}
+
+static int ocelot_devlink_sb_port_pool_set(struct devlink_port *dlp,
+					   unsigned int sb_index, u16 pool_index,
+					   u32 threshold,
+					   struct netlink_ext_ack *extack)
+{
+	struct ocelot_devlink_private *dl_priv = devlink_priv(dlp->devlink);
+	struct ocelot_port_private *priv = devlink_to_ocelot_port_priv(dlp);
+	struct ocelot *ocelot = dl_priv->ocelot;
+
+	return ocelot_sb_port_pool_set(ocelot, priv->chip_port, sb_index,
+				       pool_index, threshold, extack);
+}
+
+static int
+ocelot_devlink_sb_tc_pool_bind_get(struct devlink_port *dlp,
+				   unsigned int sb_index, u16 tc_index,
+				   enum devlink_sb_pool_type pool_type,
+				   u16 *p_pool_index, u32 *p_threshold)
+{
+	struct ocelot_devlink_private *dl_priv = devlink_priv(dlp->devlink);
+	struct ocelot_port_private *priv = devlink_to_ocelot_port_priv(dlp);
+	struct ocelot *ocelot = dl_priv->ocelot;
+
+	return ocelot_sb_tc_pool_bind_get(ocelot, priv->chip_port, sb_index,
+					  tc_index, pool_type, p_pool_index,
+					  p_threshold);
+}
+
+static int
+ocelot_devlink_sb_tc_pool_bind_set(struct devlink_port *dlp,
+				   unsigned int sb_index, u16 tc_index,
+				   enum devlink_sb_pool_type pool_type,
+				   u16 pool_index, u32 threshold,
+				   struct netlink_ext_ack *extack)
+{
+	struct ocelot_devlink_private *dl_priv = devlink_priv(dlp->devlink);
+	struct ocelot_port_private *priv = devlink_to_ocelot_port_priv(dlp);
+	struct ocelot *ocelot = dl_priv->ocelot;
+
+	return ocelot_sb_tc_pool_bind_set(ocelot, priv->chip_port, sb_index,
+					  tc_index, pool_type, pool_index,
+					  threshold, extack);
+}
+
+static int ocelot_devlink_sb_occ_snapshot(struct devlink *dl,
+					  unsigned int sb_index)
+{
+	struct ocelot_devlink_private *dl_priv = devlink_priv(dl);
+	struct ocelot *ocelot = dl_priv->ocelot;
+
+	return ocelot_sb_occ_snapshot(ocelot, sb_index);
+}
+
+static int ocelot_devlink_sb_occ_max_clear(struct devlink *dl,
+					   unsigned int sb_index)
+{
+	struct ocelot_devlink_private *dl_priv = devlink_priv(dl);
+	struct ocelot *ocelot = dl_priv->ocelot;
+
+	return ocelot_sb_occ_max_clear(ocelot, sb_index);
+}
+
+static int ocelot_devlink_sb_occ_port_pool_get(struct devlink_port *dlp,
+					       unsigned int sb_index,
+					       u16 pool_index, u32 *p_cur,
+					       u32 *p_max)
+{
+	struct ocelot_devlink_private *dl_priv = devlink_priv(dlp->devlink);
+	struct ocelot_port_private *priv = devlink_to_ocelot_port_priv(dlp);
+	struct ocelot *ocelot = dl_priv->ocelot;
+
+	return ocelot_sb_occ_port_pool_get(ocelot, priv->chip_port, sb_index,
+						     pool_index, p_cur, p_max);
+}
+
+static int
+ocelot_devlink_sb_occ_tc_port_bind_get(struct devlink_port *dlp,
+				       unsigned int sb_index, u16 tc_index,
+				       enum devlink_sb_pool_type pool_type,
+				       u32 *p_cur, u32 *p_max)
+{
+	struct ocelot_devlink_private *dl_priv = devlink_priv(dlp->devlink);
+	struct ocelot_port_private *priv = devlink_to_ocelot_port_priv(dlp);
+	struct ocelot *ocelot = dl_priv->ocelot;
+
+	return ocelot_sb_occ_tc_port_bind_get(ocelot, priv->chip_port, sb_index,
+					      tc_index, pool_type, p_cur, p_max);
+}
+
 static const struct devlink_ops ocelot_devlink_ops = {
+	.sb_pool_get			= ocelot_devlink_sb_pool_get,
+	.sb_pool_set			= ocelot_devlink_sb_pool_set,
+	.sb_port_pool_get		= ocelot_devlink_sb_port_pool_get,
+	.sb_port_pool_set		= ocelot_devlink_sb_port_pool_set,
+	.sb_tc_pool_bind_get		= ocelot_devlink_sb_tc_pool_bind_get,
+	.sb_tc_pool_bind_set		= ocelot_devlink_sb_tc_pool_bind_set,
+	.sb_occ_snapshot		= ocelot_devlink_sb_occ_snapshot,
+	.sb_occ_max_clear		= ocelot_devlink_sb_occ_max_clear,
+	.sb_occ_port_pool_get		= ocelot_devlink_sb_occ_port_pool_get,
+	.sb_occ_tc_port_bind_get	= ocelot_devlink_sb_occ_tc_port_bind_get,
 };
 
 static int ocelot_port_devlink_init(struct ocelot *ocelot, int port)
diff --git a/drivers/net/ethernet/mscc/ocelot_vsc7514.c b/drivers/net/ethernet/mscc/ocelot_vsc7514.c
index 80fdf971d573..7bb80144dd1d 100644
--- a/drivers/net/ethernet/mscc/ocelot_vsc7514.c
+++ b/drivers/net/ethernet/mscc/ocelot_vsc7514.c
@@ -1173,6 +1173,29 @@ static int mscc_ocelot_init_ports(struct platform_device *pdev,
 	return 0;
 }
 
+static int mscc_ocelot_devlink_setup(struct ocelot *ocelot)
+{
+	int err;
+
+	err = ocelot_devlink_init(ocelot);
+	if (err)
+		return err;
+
+	err = ocelot_devlink_sb_register(ocelot);
+	if (err) {
+		ocelot_devlink_teardown(ocelot);
+		return err;
+	}
+
+	return 0;
+}
+
+static void mscc_ocelot_devlink_cleanup(struct ocelot *ocelot)
+{
+	ocelot_devlink_sb_unregister(ocelot);
+	ocelot_devlink_teardown(ocelot);
+}
+
 static int mscc_ocelot_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
@@ -1293,7 +1316,7 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
 		}
 	}
 
-	err = ocelot_devlink_init(ocelot);
+	err = mscc_ocelot_devlink_setup(ocelot);
 	if (err) {
 		mscc_ocelot_release_ports(ocelot);
 		goto out_ocelot_deinit;
@@ -1320,7 +1343,7 @@ static int mscc_ocelot_remove(struct platform_device *pdev)
 {
 	struct ocelot *ocelot = platform_get_drvdata(pdev);
 
-	ocelot_devlink_teardown(ocelot);
+	mscc_ocelot_devlink_cleanup(ocelot);
 	ocelot_deinit_timestamp(ocelot);
 	mscc_ocelot_release_ports(ocelot);
 	ocelot_deinit(ocelot);
diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h
index 75cd457b99b9..762b827784b8 100644
--- a/include/soc/mscc/ocelot.h
+++ b/include/soc/mscc/ocelot.h
@@ -579,6 +579,18 @@ struct ocelot_vlan {
 	u16 vid;
 };
 
+enum ocelot_sb {
+	OCELOT_SB_BUF,
+	OCELOT_SB_REF,
+	OCELOT_SB_NUM,
+};
+
+enum ocelot_sb_pool {
+	OCELOT_SB_POOL_ING,
+	OCELOT_SB_POOL_EGR,
+	OCELOT_SB_POOL_NUM,
+};
+
 struct ocelot_port {
 	struct ocelot			*ocelot;
 
@@ -611,6 +623,7 @@ struct ocelot {
 	const struct ocelot_stat_layout	*stats_layout;
 	unsigned int			num_stats;
 
+	u32				pool_size[OCELOT_SB_NUM][OCELOT_SB_POOL_NUM];
 	int				packet_buffer_size;
 	int				num_frame_refs;
 	int				num_mact_rows;
@@ -783,4 +796,38 @@ int ocelot_port_mdb_add(struct ocelot *ocelot, int port,
 int ocelot_port_mdb_del(struct ocelot *ocelot, int port,
 			const struct switchdev_obj_port_mdb *mdb);
 
+int ocelot_devlink_sb_register(struct ocelot *ocelot);
+void ocelot_devlink_sb_unregister(struct ocelot *ocelot);
+int ocelot_sb_pool_get(struct ocelot *ocelot, unsigned int sb_index,
+		       u16 pool_index,
+		       struct devlink_sb_pool_info *pool_info);
+int ocelot_sb_pool_set(struct ocelot *ocelot, unsigned int sb_index,
+		       u16 pool_index, u32 size,
+		       enum devlink_sb_threshold_type threshold_type,
+		       struct netlink_ext_ack *extack);
+int ocelot_sb_port_pool_get(struct ocelot *ocelot, int port,
+			    unsigned int sb_index, u16 pool_index,
+			    u32 *p_threshold);
+int ocelot_sb_port_pool_set(struct ocelot *ocelot, int port,
+			    unsigned int sb_index, u16 pool_index,
+			    u32 threshold, struct netlink_ext_ack *extack);
+int ocelot_sb_tc_pool_bind_get(struct ocelot *ocelot, int port,
+			       unsigned int sb_index, u16 tc_index,
+			       enum devlink_sb_pool_type pool_type,
+			       u16 *p_pool_index, u32 *p_threshold);
+int ocelot_sb_tc_pool_bind_set(struct ocelot *ocelot, int port,
+			       unsigned int sb_index, u16 tc_index,
+			       enum devlink_sb_pool_type pool_type,
+			       u16 pool_index, u32 threshold,
+			       struct netlink_ext_ack *extack);
+int ocelot_sb_occ_snapshot(struct ocelot *ocelot, unsigned int sb_index);
+int ocelot_sb_occ_max_clear(struct ocelot *ocelot, unsigned int sb_index);
+int ocelot_sb_occ_port_pool_get(struct ocelot *ocelot, int port,
+				unsigned int sb_index, u16 pool_index,
+				u32 *p_cur, u32 *p_max);
+int ocelot_sb_occ_tc_port_bind_get(struct ocelot *ocelot, int port,
+				   unsigned int sb_index, u16 tc_index,
+				   enum devlink_sb_pool_type pool_type,
+				   u32 *p_cur, u32 *p_max);
+
 #endif
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [PATCH v3 net-next 03/10] net: dsa: add ops for devlink-sb
  2021-01-08 17:59 ` [PATCH v3 net-next 03/10] net: dsa: add ops for devlink-sb Vladimir Oltean
@ 2021-01-08 18:20   ` Andrew Lunn
  2021-01-08 18:31   ` Florian Fainelli
  1 sibling, 0 replies; 36+ messages in thread
From: Andrew Lunn @ 2021-01-08 18:20 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: netdev, alexandre.belloni, f.fainelli, vivien.didelot,
	alexandru.marginean, claudiu.manoil, xiaoliang.yang_1,
	hongbo.wang, kuba, jiri, idosch, UNGLinuxDriver

On Fri, Jan 08, 2021 at 07:59:43PM +0200, Vladimir Oltean wrote:
> From: Vladimir Oltean <vladimir.oltean@nxp.com>
> 
> Switches that care about QoS might have hardware support for reserving
> buffer pools for individual ports or traffic classes, and configuring
> their sizes and thresholds. Through devlink-sb (shared buffers), this is
> all configurable, as well as their occupancy being viewable.
> 
> Add the plumbing in DSA for these operations.
> 
> Individual drivers still need to call devlink_sb_register() with the
> shared buffers they want to expose. A helper was not created in DSA for
> this purpose (unlike, say, dsa_devlink_params_register), since in my
> opinion it does not bring any benefit over plainly calling
> devlink_sb_register() directly.
> 
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>

Reviewed-by: Andrew Lunn <andrew@lunn.ch>

    Andrew

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v3 net-next 01/10] net: mscc: ocelot: auto-detect packet buffer size and number of frame references
  2021-01-08 17:59 ` [PATCH v3 net-next 01/10] net: mscc: ocelot: auto-detect packet buffer size and number of frame references Vladimir Oltean
@ 2021-01-08 18:30   ` Florian Fainelli
  0 siblings, 0 replies; 36+ messages in thread
From: Florian Fainelli @ 2021-01-08 18:30 UTC (permalink / raw)
  To: Vladimir Oltean, netdev
  Cc: alexandre.belloni, andrew, vivien.didelot, alexandru.marginean,
	claudiu.manoil, xiaoliang.yang_1, hongbo.wang, kuba, jiri,
	idosch, UNGLinuxDriver



On 1/8/2021 9:59 AM, Vladimir Oltean wrote:
> From: Vladimir Oltean <vladimir.oltean@nxp.com>
> 
> Instead of reading these values from the reference manual and writing
> them down into the driver, it appears that the hardware gives us the
> option of detecting them dynamically.
> 
> The number of frame references corresponds to what the reference manual
> notes, however it seems that the frame buffers are reported as slightly
> less than the books would indicate. On VSC9959 (Felix), the books say it
> should have 128KB of packet buffer, but the registers indicate only
> 129840 bytes (126.79 KB). Also, the unit of measurement for FREECNT from
> the documentation of all these devices is incorrect (taken from an older
> generation). This was confirmed by Younes Leroul from Microchip support.
> 
> Not having anything better to do with these values at the moment* (this
> will change soon), let's just print them.
> 
> *The frame buffer size is, in fact, used to calculate the tail dropping
> watermarks.
> 
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>

Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
-- 
Florian

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v3 net-next 02/10] net: mscc: ocelot: add ops for decoding watermark threshold and occupancy
  2021-01-08 17:59 ` [PATCH v3 net-next 02/10] net: mscc: ocelot: add ops for decoding watermark threshold and occupancy Vladimir Oltean
@ 2021-01-08 18:30   ` Florian Fainelli
  2021-01-10  1:20   ` Jakub Kicinski
  1 sibling, 0 replies; 36+ messages in thread
From: Florian Fainelli @ 2021-01-08 18:30 UTC (permalink / raw)
  To: Vladimir Oltean, netdev
  Cc: alexandre.belloni, andrew, vivien.didelot, alexandru.marginean,
	claudiu.manoil, xiaoliang.yang_1, hongbo.wang, kuba, jiri,
	idosch, UNGLinuxDriver



On 1/8/2021 9:59 AM, Vladimir Oltean wrote:
> From: Vladimir Oltean <vladimir.oltean@nxp.com>
> 
> We'll need to read back the watermark thresholds and occupancy from
> hardware (for devlink-sb integration), not only to write them as we did
> so far in ocelot_port_set_maxlen. So introduce 2 new functions in struct
> ocelot_ops, similar to wm_enc, and implement them for the 3 supported
> mscc_ocelot switches.
> 
> Remove the INUSE and MAXUSE unpacking helpers for the QSYS_RES_STAT
> register, because that doesn't scale with the number of switches that
> mscc_ocelot supports now. They have different bit widths for the
> watermarks, and we need function pointers to abstract that difference
> away.
> 
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>

Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
-- 
Florian

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v3 net-next 03/10] net: dsa: add ops for devlink-sb
  2021-01-08 17:59 ` [PATCH v3 net-next 03/10] net: dsa: add ops for devlink-sb Vladimir Oltean
  2021-01-08 18:20   ` Andrew Lunn
@ 2021-01-08 18:31   ` Florian Fainelli
  1 sibling, 0 replies; 36+ messages in thread
From: Florian Fainelli @ 2021-01-08 18:31 UTC (permalink / raw)
  To: Vladimir Oltean, netdev
  Cc: alexandre.belloni, andrew, vivien.didelot, alexandru.marginean,
	claudiu.manoil, xiaoliang.yang_1, hongbo.wang, kuba, jiri,
	idosch, UNGLinuxDriver



On 1/8/2021 9:59 AM, Vladimir Oltean wrote:
> From: Vladimir Oltean <vladimir.oltean@nxp.com>
> 
> Switches that care about QoS might have hardware support for reserving
> buffer pools for individual ports or traffic classes, and configuring
> their sizes and thresholds. Through devlink-sb (shared buffers), this is
> all configurable, as well as their occupancy being viewable.
> 
> Add the plumbing in DSA for these operations.
> 
> Individual drivers still need to call devlink_sb_register() with the
> shared buffers they want to expose. A helper was not created in DSA for
> this purpose (unlike, say, dsa_devlink_params_register), since in my
> opinion it does not bring any benefit over plainly calling
> devlink_sb_register() directly.
> 
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>

Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
-- 
Florian

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v3 net-next 04/10] net: dsa: felix: reindent struct dsa_switch_ops
  2021-01-08 17:59 ` [PATCH v3 net-next 04/10] net: dsa: felix: reindent struct dsa_switch_ops Vladimir Oltean
@ 2021-01-08 18:33   ` Florian Fainelli
  2021-01-10  1:24   ` Jakub Kicinski
  1 sibling, 0 replies; 36+ messages in thread
From: Florian Fainelli @ 2021-01-08 18:33 UTC (permalink / raw)
  To: Vladimir Oltean, netdev
  Cc: alexandre.belloni, andrew, vivien.didelot, alexandru.marginean,
	claudiu.manoil, xiaoliang.yang_1, hongbo.wang, kuba, jiri,
	idosch, UNGLinuxDriver



On 1/8/2021 9:59 AM, Vladimir Oltean wrote:
> From: Vladimir Oltean <vladimir.oltean@nxp.com>
> 
> The devlink function pointer names are super long, and they would break
> the alignment. So reindent the existing ops now by adding one tab.
> 
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>

Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
-- 
Florian

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v3 net-next 05/10] net: dsa: felix: perform teardown in reverse order of setup
  2021-01-08 17:59 ` [PATCH v3 net-next 05/10] net: dsa: felix: perform teardown in reverse order of setup Vladimir Oltean
@ 2021-01-08 18:34   ` Florian Fainelli
  0 siblings, 0 replies; 36+ messages in thread
From: Florian Fainelli @ 2021-01-08 18:34 UTC (permalink / raw)
  To: Vladimir Oltean, netdev
  Cc: alexandre.belloni, andrew, vivien.didelot, alexandru.marginean,
	claudiu.manoil, xiaoliang.yang_1, hongbo.wang, kuba, jiri,
	idosch, UNGLinuxDriver



On 1/8/2021 9:59 AM, Vladimir Oltean wrote:
> From: Vladimir Oltean <vladimir.oltean@nxp.com>
> 
> In general it is desirable that cleanup is the reverse process of setup.
> In this case I am not seeing any particular issue, but with the
> introduction of devlink-sb for felix, a non-obvious decision had to be
> made as to where to put its cleanup method. When there's a convention in
> place, that decision becomes obvious.
> 
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>

Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
-- 
Florian

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v3 net-next 06/10] net: mscc: ocelot: export NUM_TC constant from felix to common switch lib
  2021-01-08 17:59 ` [PATCH v3 net-next 06/10] net: mscc: ocelot: export NUM_TC constant from felix to common switch lib Vladimir Oltean
@ 2021-01-08 18:34   ` Florian Fainelli
  0 siblings, 0 replies; 36+ messages in thread
From: Florian Fainelli @ 2021-01-08 18:34 UTC (permalink / raw)
  To: Vladimir Oltean, netdev
  Cc: alexandre.belloni, andrew, vivien.didelot, alexandru.marginean,
	claudiu.manoil, xiaoliang.yang_1, hongbo.wang, kuba, jiri,
	idosch, UNGLinuxDriver



On 1/8/2021 9:59 AM, Vladimir Oltean wrote:
> From: Vladimir Oltean <vladimir.oltean@nxp.com>
> 
> We should be moving anything that isn't DSA-specific or SoC-specific out
> of the felix DSA driver, and into the common mscc_ocelot switch library.
> 
> The number of traffic classes is one of the aspects that is common
> between all ocelot switches, so it belongs in the library.
> 
> This patch also makes seville use 8 TX queues, and therefore enables
> prioritization via the QOS_CLASS field in the NPI injection header.
> 
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>

Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
-- 
Florian

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v3 net-next 07/10] net: mscc: ocelot: delete unused ocelot_set_cpu_port prototype
  2021-01-08 17:59 ` [PATCH v3 net-next 07/10] net: mscc: ocelot: delete unused ocelot_set_cpu_port prototype Vladimir Oltean
@ 2021-01-08 18:35   ` Florian Fainelli
  0 siblings, 0 replies; 36+ messages in thread
From: Florian Fainelli @ 2021-01-08 18:35 UTC (permalink / raw)
  To: Vladimir Oltean, netdev
  Cc: alexandre.belloni, andrew, vivien.didelot, alexandru.marginean,
	claudiu.manoil, xiaoliang.yang_1, hongbo.wang, kuba, jiri,
	idosch, UNGLinuxDriver



On 1/8/2021 9:59 AM, Vladimir Oltean wrote:
> From: Vladimir Oltean <vladimir.oltean@nxp.com>
> 
> This is a leftover of commit 69df578c5f4b ("net: mscc: ocelot: eliminate
> confusion between CPU and NPI port") which renamed that function.
> 
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>

Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
-- 
Florian

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v3 net-next 08/10] net: mscc: ocelot: register devlink ports
  2021-01-08 17:59 ` [PATCH v3 net-next 08/10] net: mscc: ocelot: register devlink ports Vladimir Oltean
@ 2021-01-08 18:36   ` Florian Fainelli
  2021-01-10  1:44   ` Jakub Kicinski
  2021-01-10  2:01   ` [PATCH v3 net-next 08/10] net: mscc: ocelot: register devlink ports Jakub Kicinski
  2 siblings, 0 replies; 36+ messages in thread
From: Florian Fainelli @ 2021-01-08 18:36 UTC (permalink / raw)
  To: Vladimir Oltean, netdev
  Cc: alexandre.belloni, andrew, vivien.didelot, alexandru.marginean,
	claudiu.manoil, xiaoliang.yang_1, hongbo.wang, kuba, jiri,
	idosch, UNGLinuxDriver



On 1/8/2021 9:59 AM, Vladimir Oltean wrote:
> From: Vladimir Oltean <vladimir.oltean@nxp.com>
> 
> Add devlink integration into the mscc_ocelot switchdev driver. Only the
> probed interfaces are registered with devlink, because for convenience,
> struct devlink_port was included into struct ocelot_port_private, which
> is only initialized for the ports that are used.
> 
> Since we use devlink_port_type_eth_set to link the devlink port to the
> net_device, we can as well remove the .ndo_get_phys_port_name and
> .ndo_get_port_parent_id implementations, since devlink takes care of
> retrieving the port name and number automatically, once
> .ndo_get_devlink_port is implemented.
> 
> Note that the felix DSA driver is already integrated with devlink by
> default, since that is a thing that the DSA core takes care of. This is
> the reason why these devlink stubs were put in ocelot_net.c and not in
> the common library.
> 
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>

Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
-- 
Florian

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v3 net-next 09/10] net: mscc: ocelot: initialize watermarks to sane defaults
  2021-01-08 17:59 ` [PATCH v3 net-next 09/10] net: mscc: ocelot: initialize watermarks to sane defaults Vladimir Oltean
@ 2021-01-09  3:59   ` Florian Fainelli
  0 siblings, 0 replies; 36+ messages in thread
From: Florian Fainelli @ 2021-01-09  3:59 UTC (permalink / raw)
  To: Vladimir Oltean, netdev
  Cc: alexandre.belloni, andrew, vivien.didelot, alexandru.marginean,
	claudiu.manoil, xiaoliang.yang_1, hongbo.wang, kuba, jiri,
	idosch, UNGLinuxDriver



On 1/8/2021 9:59 AM, Vladimir Oltean wrote:
> From: Vladimir Oltean <vladimir.oltean@nxp.com>
> 
> This is meant to be a gentle introduction into the world of watermarks
> on ocelot. The code is placed in ocelot_devlink.c because it will be
> integrated with devlink, even if it isn't right now.
> 
> My first step was intended to be to replicate the default configuration
> of the congestion watermarks programatically, since they are now going
> to be tuned by the user.
> 
> But after studying and understanding through trial and error how they
> work, I now believe that the configuration used out of reset does not do
> justice to the word "reservation", since the sum of all reservations
> exceeds the total amount of resources (otherwise said, all reservations
> cannot be fulfilled at the same time, which means that, contrary to the
> reference manual, they don't guarantee anything).
> 
> As an example, here's a dump of the reservation watermarks for frame
> buffers, for port 0 (for brevity, the ports 1-6 were omitted, but they
> have the same configuration):
> 
> BUF_Q_RSRV_I(port 0, prio 0) = max 3000 bytes
> BUF_Q_RSRV_I(port 0, prio 1) = max 3000 bytes
> BUF_Q_RSRV_I(port 0, prio 2) = max 3000 bytes
> BUF_Q_RSRV_I(port 0, prio 3) = max 3000 bytes
> BUF_Q_RSRV_I(port 0, prio 4) = max 3000 bytes
> BUF_Q_RSRV_I(port 0, prio 5) = max 3000 bytes
> BUF_Q_RSRV_I(port 0, prio 6) = max 3000 bytes
> BUF_Q_RSRV_I(port 0, prio 7) = max 3000 bytes
> 
> Otherwise said, every port-tc has an ingress reservation of 3000 bytes,
> and there are 7 ports in VSC9959 Felix (6 user ports and 1 CPU port).
> Concentrating only on the ingress reservations, there are, in total,
> 8 [traffic classes] x 7 [ports] x 3000 [bytes] = 168,000 bytes of memory
> reserved on ingress.
> But, surprise, Felix only has 128 KB of packet buffer in total...
> A similar thing happens with Seville, which has a larger packet buffer,
> but also more ports, and the default configuration is also overcommitted.
> 
> This patch disables the (apparently) bogus reservations and moves all
> resources to the shared area. This way, real reservations can be set up
> by the user, using devlink-sb.
> 
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>

Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
-- 
Florian

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v3 net-next 10/10] net: mscc: ocelot: configure watermarks using devlink-sb
  2021-01-08 17:59 ` [PATCH v3 net-next 10/10] net: mscc: ocelot: configure watermarks using devlink-sb Vladimir Oltean
@ 2021-01-09  4:03   ` Florian Fainelli
  0 siblings, 0 replies; 36+ messages in thread
From: Florian Fainelli @ 2021-01-09  4:03 UTC (permalink / raw)
  To: Vladimir Oltean, netdev
  Cc: alexandre.belloni, andrew, vivien.didelot, alexandru.marginean,
	claudiu.manoil, xiaoliang.yang_1, hongbo.wang, kuba, jiri,
	idosch, UNGLinuxDriver



On 1/8/2021 9:59 AM, Vladimir Oltean wrote:
> From: Vladimir Oltean <vladimir.oltean@nxp.com>
> 
> Using devlink-sb, we can configure 12/16 (the important 75%) of the
> switch's controlling watermarks for congestion drops, and we can monitor
> 50% of the watermark occupancies (we can monitor the reservation
> watermarks, but not the sharing watermarks, which are exposed as pool
> sizes).
> 
> The following definitions can be made:
> 
> SB_BUF=0 # The devlink-sb for frame buffers
> SB_REF=1 # The devlink-sb for frame references
> POOL_ING=0 # The pool for ingress traffic. Both devlink-sb instances
>            # have one of these.
> POOL_EGR=1 # The pool for egress traffic. Both devlink-sb instances
>            # have one of these.
> 
> Editing the hardware watermarks is done in the following way:
> BUF_xxxx_I is accessed when sb=$SB_BUF and pool=$POOL_ING
> REF_xxxx_I is accessed when sb=$SB_REF and pool=$POOL_ING
> BUF_xxxx_E is accessed when sb=$SB_BUF and pool=$POOL_EGR
> REF_xxxx_E is accessed when sb=$SB_REF and pool=$POOL_EGR
> 
> Configuring the sharing watermarks for COL_SHR(dp=0) is done implicitly
> by modifying the corresponding pool size. By default, the pool size has
> maximum size, so this can be skipped.
> 
> devlink sb pool set pci/0000:00:00.5 sb $SB_BUF pool $POOL_ING \
> 	size 103872 thtype static
> 
> Since by default there is no buffer reservation, the above command has
> maxed out BUF_COL_SHR_I(dp=0).
> 
> Configuring the per-port reservation watermark (P_RSRV) is done in the
> following way:
> 
> devlink sb port pool set pci/0000:00:00.5/0 sb $SB_BUF \
> 	pool $POOL_ING th 1000
> 
> The above command sets BUF_P_RSRV_I(port 0) to 1000 bytes. After this
> command, the sharing watermarks are internally reconfigured with 1000
> bytes less, i.e. from 103872 bytes to 102872 bytes.
> 
> Configuring the per-port-tc reservation watermarks (Q_RSRV) is done in
> the following way:
> 
> for tc in {0..7}; do
> 	devlink sb tc bind set pci/0000:00:00.5/0 sb 0 tc $tc \
> 		type ingress pool $POOL_ING \
> 		th 3000
> done
> 
> The above command sets BUF_Q_RSRV_I(port 0, tc 0..7) to 3000 bytes.
> The sharing watermarks are again reconfigured with 24000 bytes less.
> 
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>

Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
-- 
Florian

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v3 net-next 02/10] net: mscc: ocelot: add ops for decoding watermark threshold and occupancy
  2021-01-08 17:59 ` [PATCH v3 net-next 02/10] net: mscc: ocelot: add ops for decoding watermark threshold and occupancy Vladimir Oltean
  2021-01-08 18:30   ` Florian Fainelli
@ 2021-01-10  1:20   ` Jakub Kicinski
  2021-01-11 16:53     ` Vladimir Oltean
  1 sibling, 1 reply; 36+ messages in thread
From: Jakub Kicinski @ 2021-01-10  1:20 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: netdev, alexandre.belloni, andrew, f.fainelli, vivien.didelot,
	alexandru.marginean, claudiu.manoil, xiaoliang.yang_1,
	hongbo.wang, jiri, idosch, UNGLinuxDriver

On Fri,  8 Jan 2021 19:59:42 +0200 Vladimir Oltean wrote:
> +	*inuse = (val & GENMASK(23, 12)) >> 12;

FWIW FIELD_GET()

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v3 net-next 04/10] net: dsa: felix: reindent struct dsa_switch_ops
  2021-01-08 17:59 ` [PATCH v3 net-next 04/10] net: dsa: felix: reindent struct dsa_switch_ops Vladimir Oltean
  2021-01-08 18:33   ` Florian Fainelli
@ 2021-01-10  1:24   ` Jakub Kicinski
  2021-01-11 17:01     ` Vladimir Oltean
  1 sibling, 1 reply; 36+ messages in thread
From: Jakub Kicinski @ 2021-01-10  1:24 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: netdev, alexandre.belloni, andrew, f.fainelli, vivien.didelot,
	alexandru.marginean, claudiu.manoil, xiaoliang.yang_1,
	hongbo.wang, jiri, idosch, UNGLinuxDriver

On Fri,  8 Jan 2021 19:59:44 +0200 Vladimir Oltean wrote:
> From: Vladimir Oltean <vladimir.oltean@nxp.com>
> 
> The devlink function pointer names are super long, and they would break
> the alignment. So reindent the existing ops now by adding one tab.

Therefore it'd be tempting to prefix them with dl_ rather than full
devlink_

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v3 net-next 08/10] net: mscc: ocelot: register devlink ports
  2021-01-08 17:59 ` [PATCH v3 net-next 08/10] net: mscc: ocelot: register devlink ports Vladimir Oltean
  2021-01-08 18:36   ` Florian Fainelli
@ 2021-01-10  1:44   ` Jakub Kicinski
  2021-01-11 17:13     ` Vladimir Oltean
  2021-01-10  2:01   ` [PATCH v3 net-next 08/10] net: mscc: ocelot: register devlink ports Jakub Kicinski
  2 siblings, 1 reply; 36+ messages in thread
From: Jakub Kicinski @ 2021-01-10  1:44 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: netdev, alexandre.belloni, andrew, f.fainelli, vivien.didelot,
	alexandru.marginean, claudiu.manoil, xiaoliang.yang_1,
	hongbo.wang, jiri, idosch, UNGLinuxDriver

On Fri,  8 Jan 2021 19:59:48 +0200 Vladimir Oltean wrote:
> From: Vladimir Oltean <vladimir.oltean@nxp.com>
> 
> Add devlink integration into the mscc_ocelot switchdev driver. Only the
> probed interfaces are registered with devlink, because for convenience,
> struct devlink_port was included into struct ocelot_port_private, which
> is only initialized for the ports that are used.
> 
> Since we use devlink_port_type_eth_set to link the devlink port to the
> net_device, we can as well remove the .ndo_get_phys_port_name and
> .ndo_get_port_parent_id implementations, since devlink takes care of
> retrieving the port name and number automatically, once
> .ndo_get_devlink_port is implemented.
> 
> Note that the felix DSA driver is already integrated with devlink by
> default, since that is a thing that the DSA core takes care of. This is
> the reason why these devlink stubs were put in ocelot_net.c and not in
> the common library.
> 
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>

> diff --git a/drivers/net/ethernet/mscc/ocelot_net.c b/drivers/net/ethernet/mscc/ocelot_net.c
> index 2bd2840d88bd..d0d98c6adea8 100644
> --- a/drivers/net/ethernet/mscc/ocelot_net.c
> +++ b/drivers/net/ethernet/mscc/ocelot_net.c
> @@ -8,6 +8,116 @@
>  #include "ocelot.h"
>  #include "ocelot_vcap.h"
>  
> +struct ocelot_devlink_private {
> +	struct ocelot *ocelot;
> +};

Why not make struct ocelot part of devlink_priv?

> +static const struct devlink_ops ocelot_devlink_ops = {
> +};
> +
> +static int ocelot_port_devlink_init(struct ocelot *ocelot, int port)
> +{
> +	struct ocelot_port *ocelot_port = ocelot->ports[port];
> +	int id_len = sizeof(ocelot->base_mac);
> +	struct devlink *dl = ocelot->devlink;
> +	struct devlink_port_attrs attrs = {};
> +	struct ocelot_port_private *priv;
> +	struct devlink_port *dlp;
> +	int err;
> +
> +	if (!ocelot_port)
> +		return 0;
> +
> +	priv = container_of(ocelot_port, struct ocelot_port_private, port);
> +	dlp = &priv->devlink_port;
> +
> +	memcpy(attrs.switch_id.id, &ocelot->base_mac, id_len);
> +	attrs.switch_id.id_len = id_len;
> +	attrs.phys.port_number = port;
> +
> +	if (priv->dev)
> +		attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
> +	else
> +		attrs.flavour = DEVLINK_PORT_FLAVOUR_UNUSED;
> +
> +	devlink_port_attrs_set(dlp, &attrs);
> +
> +	err = devlink_port_register(dl, dlp, port);
> +	if (err)
> +		return err;
> +
> +	if (priv->dev)
> +		devlink_port_type_eth_set(dlp, priv->dev);

devlink_port_attrs_set() should be called before netdev is registered,
and devlink_port_type_eth_set() after. So this sequence makes me a tad
suspicious.

In particular IIRC devlink's .ndo_get_phys_port_name depends on it,
because udev event needs to carry the right info for interface renaming
to work reliably. No?

> +	return 0;
> +}
> +
> +static void ocelot_port_devlink_teardown(struct ocelot *ocelot, int port)
> +{
> +	struct ocelot_port *ocelot_port = ocelot->ports[port];
> +	struct ocelot_port_private *priv;
> +	struct devlink_port *dlp;
> +
> +	if (!ocelot_port)
> +		return;
> +
> +	priv = container_of(ocelot_port, struct ocelot_port_private, port);
> +	dlp = &priv->devlink_port;
> +
> +	devlink_port_unregister(dlp);
> +}
> +
> +int ocelot_devlink_init(struct ocelot *ocelot)
> +{
> +	struct ocelot_devlink_private *dl_priv;
> +	int port, err;
> +
> +	ocelot->devlink = devlink_alloc(&ocelot_devlink_ops, sizeof(*dl_priv));
> +	if (!ocelot->devlink)
> +		return -ENOMEM;
> +	dl_priv = devlink_priv(ocelot->devlink);
> +	dl_priv->ocelot = ocelot;
> +
> +	err = devlink_register(ocelot->devlink, ocelot->dev);
> +	if (err)
> +		goto free_devlink;
> +
> +	for (port = 0; port < ocelot->num_phys_ports; port++) {
> +		err = ocelot_port_devlink_init(ocelot, port);
> +		if (err) {
> +			while (port-- > 0)
> +				ocelot_port_devlink_teardown(ocelot, port);
> +			goto unregister_devlink;

nit: should this also be on the error path below?

> +		}
> +	}
> +
> +	return 0;
> +
> +unregister_devlink:
> +	devlink_unregister(ocelot->devlink);
> +free_devlink:
> +	devlink_free(ocelot->devlink);
> +	return err;
> +}

> --- a/drivers/net/ethernet/mscc/ocelot_vsc7514.c
> +++ b/drivers/net/ethernet/mscc/ocelot_vsc7514.c
> @@ -1293,6 +1293,12 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
>  		}
>  	}
>  
> +	err = ocelot_devlink_init(ocelot);
> +	if (err) {
> +		mscc_ocelot_release_ports(ocelot);
> +		goto out_ocelot_deinit;

No need to add ocelot_deinit_timestamp(ocelot); to the error path?

> +	}
> +
>  	register_netdevice_notifier(&ocelot_netdevice_nb);
>  	register_switchdev_notifier(&ocelot_switchdev_nb);
>  	register_switchdev_blocking_notifier(&ocelot_switchdev_blocking_nb);


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v3 net-next 08/10] net: mscc: ocelot: register devlink ports
  2021-01-08 17:59 ` [PATCH v3 net-next 08/10] net: mscc: ocelot: register devlink ports Vladimir Oltean
  2021-01-08 18:36   ` Florian Fainelli
  2021-01-10  1:44   ` Jakub Kicinski
@ 2021-01-10  2:01   ` Jakub Kicinski
  2 siblings, 0 replies; 36+ messages in thread
From: Jakub Kicinski @ 2021-01-10  2:01 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: netdev, alexandre.belloni, andrew, f.fainelli, vivien.didelot,
	alexandru.marginean, claudiu.manoil, xiaoliang.yang_1,
	hongbo.wang, jiri, idosch, UNGLinuxDriver

On Fri,  8 Jan 2021 19:59:48 +0200 Vladimir Oltean wrote:
> From: Vladimir Oltean <vladimir.oltean@nxp.com>
> 
> Add devlink integration into the mscc_ocelot switchdev driver. Only the
> probed interfaces are registered with devlink, because for convenience,
> struct devlink_port was included into struct ocelot_port_private, which
> is only initialized for the ports that are used.

This sounds like something that DSA should have a general policy on.
I actually feel like it was discussed in the past.. Do you know what
other drivers do?


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v3 net-next 02/10] net: mscc: ocelot: add ops for decoding watermark threshold and occupancy
  2021-01-10  1:20   ` Jakub Kicinski
@ 2021-01-11 16:53     ` Vladimir Oltean
  2021-01-11 19:10       ` Jakub Kicinski
  0 siblings, 1 reply; 36+ messages in thread
From: Vladimir Oltean @ 2021-01-11 16:53 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: netdev, alexandre.belloni, andrew, f.fainelli, vivien.didelot,
	alexandru.marginean, claudiu.manoil, xiaoliang.yang_1,
	hongbo.wang, jiri, idosch, UNGLinuxDriver

On Sat, Jan 09, 2021 at 05:20:46PM -0800, Jakub Kicinski wrote:
> On Fri,  8 Jan 2021 19:59:42 +0200 Vladimir Oltean wrote:
> > +	*inuse = (val & GENMASK(23, 12)) >> 12;
> 
> FWIW FIELD_GET()

Do you mind if I don't use it? I don't feel that:
	*inuse = FIELD_GET(GENMASK(23, 12), val);
looks any better.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v3 net-next 04/10] net: dsa: felix: reindent struct dsa_switch_ops
  2021-01-10  1:24   ` Jakub Kicinski
@ 2021-01-11 17:01     ` Vladimir Oltean
  2021-01-11 19:12       ` Jakub Kicinski
  0 siblings, 1 reply; 36+ messages in thread
From: Vladimir Oltean @ 2021-01-11 17:01 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: netdev, alexandre.belloni, andrew, f.fainelli, vivien.didelot,
	alexandru.marginean, claudiu.manoil, xiaoliang.yang_1,
	hongbo.wang, jiri, idosch, UNGLinuxDriver

On Sat, Jan 09, 2021 at 05:24:19PM -0800, Jakub Kicinski wrote:
> On Fri,  8 Jan 2021 19:59:44 +0200 Vladimir Oltean wrote:
> > From: Vladimir Oltean <vladimir.oltean@nxp.com>
> >
> > The devlink function pointer names are super long, and they would break
> > the alignment. So reindent the existing ops now by adding one tab.
>
> Therefore it'd be tempting to prefix them with dl_ rather than full
> devlink_

Indentation is broken even with devlink_sb_occ_tc_port_bind_get reduced
to dl_sb_occ_tc_port_bind_get.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v3 net-next 08/10] net: mscc: ocelot: register devlink ports
  2021-01-10  1:44   ` Jakub Kicinski
@ 2021-01-11 17:13     ` Vladimir Oltean
  2021-01-11 19:19       ` Jakub Kicinski
  0 siblings, 1 reply; 36+ messages in thread
From: Vladimir Oltean @ 2021-01-11 17:13 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: netdev, alexandre.belloni, andrew, f.fainelli, vivien.didelot,
	alexandru.marginean, claudiu.manoil, xiaoliang.yang_1,
	hongbo.wang, jiri, idosch, UNGLinuxDriver

On Sat, Jan 09, 2021 at 05:44:39PM -0800, Jakub Kicinski wrote:
> On Fri,  8 Jan 2021 19:59:48 +0200 Vladimir Oltean wrote:
> > From: Vladimir Oltean <vladimir.oltean@nxp.com>
> > 
> > Add devlink integration into the mscc_ocelot switchdev driver. Only the
> > probed interfaces are registered with devlink, because for convenience,
> > struct devlink_port was included into struct ocelot_port_private, which
> > is only initialized for the ports that are used.
> > 
> > Since we use devlink_port_type_eth_set to link the devlink port to the
> > net_device, we can as well remove the .ndo_get_phys_port_name and
> > .ndo_get_port_parent_id implementations, since devlink takes care of
> > retrieving the port name and number automatically, once
> > .ndo_get_devlink_port is implemented.
> > 
> > Note that the felix DSA driver is already integrated with devlink by
> > default, since that is a thing that the DSA core takes care of. This is
> > the reason why these devlink stubs were put in ocelot_net.c and not in
> > the common library.
> > 
> > Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
> 
> > diff --git a/drivers/net/ethernet/mscc/ocelot_net.c b/drivers/net/ethernet/mscc/ocelot_net.c
> > index 2bd2840d88bd..d0d98c6adea8 100644
> > --- a/drivers/net/ethernet/mscc/ocelot_net.c
> > +++ b/drivers/net/ethernet/mscc/ocelot_net.c
> > @@ -8,6 +8,116 @@
> >  #include "ocelot.h"
> >  #include "ocelot_vcap.h"
> >  
> > +struct ocelot_devlink_private {
> > +	struct ocelot *ocelot;
> > +};
> 
> Why not make struct ocelot part of devlink_priv?

I am not sure what you mean.

> > +static const struct devlink_ops ocelot_devlink_ops = {
> > +};
> > +
> > +static int ocelot_port_devlink_init(struct ocelot *ocelot, int port)
> > +{
> > +	struct ocelot_port *ocelot_port = ocelot->ports[port];
> > +	int id_len = sizeof(ocelot->base_mac);
> > +	struct devlink *dl = ocelot->devlink;
> > +	struct devlink_port_attrs attrs = {};
> > +	struct ocelot_port_private *priv;
> > +	struct devlink_port *dlp;
> > +	int err;
> > +
> > +	if (!ocelot_port)
> > +		return 0;
> > +
> > +	priv = container_of(ocelot_port, struct ocelot_port_private, port);
> > +	dlp = &priv->devlink_port;
> > +
> > +	memcpy(attrs.switch_id.id, &ocelot->base_mac, id_len);
> > +	attrs.switch_id.id_len = id_len;
> > +	attrs.phys.port_number = port;
> > +
> > +	if (priv->dev)
> > +		attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
> > +	else
> > +		attrs.flavour = DEVLINK_PORT_FLAVOUR_UNUSED;
> > +
> > +	devlink_port_attrs_set(dlp, &attrs);
> > +
> > +	err = devlink_port_register(dl, dlp, port);
> > +	if (err)
> > +		return err;
> > +
> > +	if (priv->dev)
> > +		devlink_port_type_eth_set(dlp, priv->dev);
> 
> devlink_port_attrs_set() should be called before netdev is registered,
> and devlink_port_type_eth_set() after. So this sequence makes me a tad
> suspicious.
> 
> In particular IIRC devlink's .ndo_get_phys_port_name depends on it,
> because udev event needs to carry the right info for interface renaming
> to work reliably. No?
> 

If I change the driver's Kconfig from tristate to bool, all is fine,
isn't it?

> > +	return 0;
> > +}
> > +
> > +static void ocelot_port_devlink_teardown(struct ocelot *ocelot, int port)
> > +{
> > +	struct ocelot_port *ocelot_port = ocelot->ports[port];
> > +	struct ocelot_port_private *priv;
> > +	struct devlink_port *dlp;
> > +
> > +	if (!ocelot_port)
> > +		return;
> > +
> > +	priv = container_of(ocelot_port, struct ocelot_port_private, port);
> > +	dlp = &priv->devlink_port;
> > +
> > +	devlink_port_unregister(dlp);
> > +}
> > +
> > +int ocelot_devlink_init(struct ocelot *ocelot)
> > +{
> > +	struct ocelot_devlink_private *dl_priv;
> > +	int port, err;
> > +
> > +	ocelot->devlink = devlink_alloc(&ocelot_devlink_ops, sizeof(*dl_priv));
> > +	if (!ocelot->devlink)
> > +		return -ENOMEM;
> > +	dl_priv = devlink_priv(ocelot->devlink);
> > +	dl_priv->ocelot = ocelot;
> > +
> > +	err = devlink_register(ocelot->devlink, ocelot->dev);
> > +	if (err)
> > +		goto free_devlink;
> > +
> > +	for (port = 0; port < ocelot->num_phys_ports; port++) {
> > +		err = ocelot_port_devlink_init(ocelot, port);
> > +		if (err) {
> > +			while (port-- > 0)
> > +				ocelot_port_devlink_teardown(ocelot, port);
> > +			goto unregister_devlink;
> 
> nit: should this also be on the error path below?
> 
> > +		}
> > +	}
> > +
> > +	return 0;
> > +
> > +unregister_devlink:
> > +	devlink_unregister(ocelot->devlink);
> > +free_devlink:
> > +	devlink_free(ocelot->devlink);
> > +	return err;
> > +}
> 
> > --- a/drivers/net/ethernet/mscc/ocelot_vsc7514.c
> > +++ b/drivers/net/ethernet/mscc/ocelot_vsc7514.c
> > @@ -1293,6 +1293,12 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
> >  		}
> >  	}
> >  
> > +	err = ocelot_devlink_init(ocelot);
> > +	if (err) {
> > +		mscc_ocelot_release_ports(ocelot);
> > +		goto out_ocelot_deinit;
> 
> No need to add ocelot_deinit_timestamp(ocelot); to the error path?

Yes, the error handling could be better.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v3 net-next 02/10] net: mscc: ocelot: add ops for decoding watermark threshold and occupancy
  2021-01-11 16:53     ` Vladimir Oltean
@ 2021-01-11 19:10       ` Jakub Kicinski
  0 siblings, 0 replies; 36+ messages in thread
From: Jakub Kicinski @ 2021-01-11 19:10 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: netdev, alexandre.belloni, andrew, f.fainelli, vivien.didelot,
	alexandru.marginean, claudiu.manoil, xiaoliang.yang_1,
	hongbo.wang, jiri, idosch, UNGLinuxDriver

On Mon, 11 Jan 2021 18:53:21 +0200 Vladimir Oltean wrote:
> On Sat, Jan 09, 2021 at 05:20:46PM -0800, Jakub Kicinski wrote:
> > On Fri,  8 Jan 2021 19:59:42 +0200 Vladimir Oltean wrote:  
> > > +	*inuse = (val & GENMASK(23, 12)) >> 12;  
> > 
> > FWIW FIELD_GET()  
> 
> Do you mind if I don't use it? I don't feel that:
> 	*inuse = FIELD_GET(GENMASK(23, 12), val);
> looks any better.

Not at all, your call.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v3 net-next 04/10] net: dsa: felix: reindent struct dsa_switch_ops
  2021-01-11 17:01     ` Vladimir Oltean
@ 2021-01-11 19:12       ` Jakub Kicinski
  0 siblings, 0 replies; 36+ messages in thread
From: Jakub Kicinski @ 2021-01-11 19:12 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: netdev, alexandre.belloni, andrew, f.fainelli, vivien.didelot,
	alexandru.marginean, claudiu.manoil, xiaoliang.yang_1,
	hongbo.wang, jiri, idosch, UNGLinuxDriver

On Mon, 11 Jan 2021 19:01:58 +0200 Vladimir Oltean wrote:
> On Sat, Jan 09, 2021 at 05:24:19PM -0800, Jakub Kicinski wrote:
> > On Fri,  8 Jan 2021 19:59:44 +0200 Vladimir Oltean wrote:  
> > > From: Vladimir Oltean <vladimir.oltean@nxp.com>
> > >
> > > The devlink function pointer names are super long, and they would break
> > > the alignment. So reindent the existing ops now by adding one tab.  
> >
> > Therefore it'd be tempting to prefix them with dl_ rather than full
> > devlink_  
> 
> Indentation is broken even with devlink_sb_occ_tc_port_bind_get reduced
> to dl_sb_occ_tc_port_bind_get.

Ack, still, shorter is better IMHO.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v3 net-next 08/10] net: mscc: ocelot: register devlink ports
  2021-01-11 17:13     ` Vladimir Oltean
@ 2021-01-11 19:19       ` Jakub Kicinski
  2021-01-14 10:34         ` Vladimir Oltean
  0 siblings, 1 reply; 36+ messages in thread
From: Jakub Kicinski @ 2021-01-11 19:19 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: netdev, alexandre.belloni, andrew, f.fainelli, vivien.didelot,
	alexandru.marginean, claudiu.manoil, xiaoliang.yang_1,
	hongbo.wang, jiri, idosch, UNGLinuxDriver

On Mon, 11 Jan 2021 19:13:44 +0200 Vladimir Oltean wrote:
> On Sat, Jan 09, 2021 at 05:44:39PM -0800, Jakub Kicinski wrote:
> > On Fri,  8 Jan 2021 19:59:48 +0200 Vladimir Oltean wrote:  
> > > From: Vladimir Oltean <vladimir.oltean@nxp.com>
> > > 
> > > Add devlink integration into the mscc_ocelot switchdev driver. Only the
> > > probed interfaces are registered with devlink, because for convenience,
> > > struct devlink_port was included into struct ocelot_port_private, which
> > > is only initialized for the ports that are used.
> > > 
> > > Since we use devlink_port_type_eth_set to link the devlink port to the
> > > net_device, we can as well remove the .ndo_get_phys_port_name and
> > > .ndo_get_port_parent_id implementations, since devlink takes care of
> > > retrieving the port name and number automatically, once
> > > .ndo_get_devlink_port is implemented.
> > > 
> > > Note that the felix DSA driver is already integrated with devlink by
> > > default, since that is a thing that the DSA core takes care of. This is
> > > the reason why these devlink stubs were put in ocelot_net.c and not in
> > > the common library.
> > > 
> > > Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>  
> >   
> > > diff --git a/drivers/net/ethernet/mscc/ocelot_net.c b/drivers/net/ethernet/mscc/ocelot_net.c
> > > index 2bd2840d88bd..d0d98c6adea8 100644
> > > --- a/drivers/net/ethernet/mscc/ocelot_net.c
> > > +++ b/drivers/net/ethernet/mscc/ocelot_net.c
> > > @@ -8,6 +8,116 @@
> > >  #include "ocelot.h"
> > >  #include "ocelot_vcap.h"
> > >  
> > > +struct ocelot_devlink_private {
> > > +	struct ocelot *ocelot;
> > > +};  
> > 
> > Why not make struct ocelot part of devlink_priv?  
> 
> I am not sure what you mean.

You put a pointer to struct ocelot inside devlink->priv, why not put
the actual struct ocelot there?

> > > +static const struct devlink_ops ocelot_devlink_ops = {
> > > +};
> > > +
> > > +static int ocelot_port_devlink_init(struct ocelot *ocelot, int port)
> > > +{
> > > +	struct ocelot_port *ocelot_port = ocelot->ports[port];
> > > +	int id_len = sizeof(ocelot->base_mac);
> > > +	struct devlink *dl = ocelot->devlink;
> > > +	struct devlink_port_attrs attrs = {};
> > > +	struct ocelot_port_private *priv;
> > > +	struct devlink_port *dlp;
> > > +	int err;
> > > +
> > > +	if (!ocelot_port)
> > > +		return 0;
> > > +
> > > +	priv = container_of(ocelot_port, struct ocelot_port_private, port);
> > > +	dlp = &priv->devlink_port;
> > > +
> > > +	memcpy(attrs.switch_id.id, &ocelot->base_mac, id_len);
> > > +	attrs.switch_id.id_len = id_len;
> > > +	attrs.phys.port_number = port;
> > > +
> > > +	if (priv->dev)
> > > +		attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
> > > +	else
> > > +		attrs.flavour = DEVLINK_PORT_FLAVOUR_UNUSED;
> > > +
> > > +	devlink_port_attrs_set(dlp, &attrs);
> > > +
> > > +	err = devlink_port_register(dl, dlp, port);
> > > +	if (err)
> > > +		return err;
> > > +
> > > +	if (priv->dev)
> > > +		devlink_port_type_eth_set(dlp, priv->dev);  
> > 
> > devlink_port_attrs_set() should be called before netdev is registered,
> > and devlink_port_type_eth_set() after. So this sequence makes me a tad
> > suspicious.
> > 
> > In particular IIRC devlink's .ndo_get_phys_port_name depends on it,
> > because udev event needs to carry the right info for interface renaming
> > to work reliably. No?
> 
> If I change the driver's Kconfig from tristate to bool, all is fine,
> isn't it?

How does Kconfig change the order of registration of objects to
subsystems _within_ the driver?

Can you unbind and bind the driver back and see if phys_port_name
always gets the correct value? (replay/udevadm test is not sufficient)

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v3 net-next 08/10] net: mscc: ocelot: register devlink ports
  2021-01-11 19:19       ` Jakub Kicinski
@ 2021-01-14 10:34         ` Vladimir Oltean
  2021-01-14 16:44           ` Jakub Kicinski
  0 siblings, 1 reply; 36+ messages in thread
From: Vladimir Oltean @ 2021-01-14 10:34 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: netdev, alexandre.belloni, andrew, f.fainelli, vivien.didelot,
	alexandru.marginean, claudiu.manoil, xiaoliang.yang_1,
	hongbo.wang, jiri, idosch, UNGLinuxDriver

On Mon, Jan 11, 2021 at 11:19:09AM -0800, Jakub Kicinski wrote:
> > > devlink_port_attrs_set() should be called before netdev is registered,
> > > and devlink_port_type_eth_set() after. So this sequence makes me a tad
> > > suspicious.
> > >
> > > In particular IIRC devlink's .ndo_get_phys_port_name depends on it,
> > > because udev event needs to carry the right info for interface renaming
> > > to work reliably. No?
> >
> > If I change the driver's Kconfig from tristate to bool, all is fine,
> > isn't it?
>
> How does Kconfig change the order of registration of objects to
> subsystems _within_ the driver?

The registration order within the driver is not what matters. What
matters is that the devlink_port and net_device are both registered
_before_ udev is up.

> Can you unbind and bind the driver back and see if phys_port_name
> always gets the correct value? (replay/udevadm test is not sufficient)

Yes, and that udev renaming test failed miserably still.

I have dhcpcd in my system, and it races with my udev script by
auto-upping the interfaces when they probe. Then, dev_change_name()
returns -EBUSY because the interfaces are up but its priv_flags do not
declare IFF_LIVE_RENAME_OK.

How is that one solved?

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v3 net-next 08/10] net: mscc: ocelot: register devlink ports
  2021-01-14 10:34         ` Vladimir Oltean
@ 2021-01-14 16:44           ` Jakub Kicinski
  2021-01-15 17:11             ` Renaming interfaces that are up (Was "Re: [PATCH v3 net-next 08/10] net: mscc: ocelot: register devlink") ports Vladimir Oltean
  0 siblings, 1 reply; 36+ messages in thread
From: Jakub Kicinski @ 2021-01-14 16:44 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: netdev, alexandre.belloni, andrew, f.fainelli, vivien.didelot,
	alexandru.marginean, claudiu.manoil, xiaoliang.yang_1,
	hongbo.wang, jiri, idosch, UNGLinuxDriver

On Thu, 14 Jan 2021 12:34:05 +0200 Vladimir Oltean wrote:
> On Mon, Jan 11, 2021 at 11:19:09AM -0800, Jakub Kicinski wrote:
> > > > devlink_port_attrs_set() should be called before netdev is registered,
> > > > and devlink_port_type_eth_set() after. So this sequence makes me a tad
> > > > suspicious.
> > > >
> > > > In particular IIRC devlink's .ndo_get_phys_port_name depends on it,
> > > > because udev event needs to carry the right info for interface renaming
> > > > to work reliably. No?  
> > >
> > > If I change the driver's Kconfig from tristate to bool, all is fine,
> > > isn't it?  
> >
> > How does Kconfig change the order of registration of objects to
> > subsystems _within_ the driver?  
> 
> The registration order within the driver is not what matters. What
> matters is that the devlink_port and net_device are both registered
> _before_ udev is up.

I see.

> > Can you unbind and bind the driver back and see if phys_port_name
> > always gets the correct value? (replay/udevadm test is not sufficient)  
> 
> Yes, and that udev renaming test failed miserably still.
> 
> I have dhcpcd in my system, and it races with my udev script by
> auto-upping the interfaces when they probe. Then, dev_change_name()
> returns -EBUSY because the interfaces are up but its priv_flags do not
> declare IFF_LIVE_RENAME_OK.
> 
> How is that one solved?

Yeah, that's one of those perennial problems we never found a strong
answer to. IIRC IFF_LIVE_RENAME_OK was more of a dirty hack than a
serious answer. I think we should allow renaming interfaces while
they're up, and see if anything breaks. We'd just need to add the right
netlink notifications to dev_change_name(), maybe?

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Renaming interfaces that are up (Was "Re: [PATCH v3 net-next 08/10] net: mscc: ocelot: register devlink") ports
  2021-01-14 16:44           ` Jakub Kicinski
@ 2021-01-15 17:11             ` Vladimir Oltean
  2021-01-15 19:54               ` Vladimir Oltean
  0 siblings, 1 reply; 36+ messages in thread
From: Vladimir Oltean @ 2021-01-15 17:11 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: netdev, alexandre.belloni, andrew, f.fainelli, vivien.didelot,
	alexandru.marginean, claudiu.manoil, xiaoliang.yang_1,
	hongbo.wang, jiri, idosch, UNGLinuxDriver

On Thu, Jan 14, 2021 at 08:44:35AM -0800, Jakub Kicinski wrote:
> > > Can you unbind and bind the driver back and see if phys_port_name
> > > always gets the correct value? (replay/udevadm test is not sufficient)
> >
> > Yes, and that udev renaming test failed miserably still.
> >
> > I have dhcpcd in my system, and it races with my udev script by
> > auto-upping the interfaces when they probe. Then, dev_change_name()
> > returns -EBUSY because the interfaces are up but its priv_flags do not
> > declare IFF_LIVE_RENAME_OK.
> >
> > How is that one solved?
>
> Yeah, that's one of those perennial problems we never found a strong
> answer to. IIRC IFF_LIVE_RENAME_OK was more of a dirty hack than a
> serious answer. I think we should allow renaming interfaces while
> they're up, and see if anything breaks. We'd just need to add the right
> netlink notifications to dev_change_name(), maybe?

I'm probably crazy for even indulging in this, since it is likely going
to just be a huge time sink. But I need to ask anyway: what netlink
notification are you thinking of adding? Do you want me to call
dev_close and then dev_open, like what was discussed in the
"[virtio-dev] Re: net_failover slave udev renaming (was Re: [RFC PATCH
net-next v6 4/4] netvsc: refactor notifier/event handling code to use
the bypass framework)" thread and then in the "failover: allow name
change on IFF_UP slave interfaces" email threads?

By the way I removed the if condition and added nothing in its place,
just to see what would happen. I see a lot of these messages, I did not
investigate where they are coming from and why they are emitted. They go
away when I rename the interface back to swp0.

# ip monitor &
[1] 26931
# ip link set swp0 name random
[ 2857.570246] mscc_felix 0000:00:00.5 random: renamed from swp0
32: random: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default
    link/ether 7a:1e:87:48:79:c0 brd ff:ff:ff:ff:ff:ff
Deleted inet swp0
inet swp0 forwarding off rp_filter off mc_forwarding off proxy_neigh off ignore_routes_with_linkdown off
Deleted inet6 swp0
inet6 swp0 forwarding off mc_forwarding off proxy_neigh off ignore_routes_with_linkdown off
32: random: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default
    link/ether 7a:1e:87:48:79:c0 brd ff:ff:ff:ff:ff:ff
fe80::/64 dev swp0 proto kernel metric 256 pref medium
32: swp0    inet6 fe80::e4fb:6ac5:7211:7981/64 scope link tentative
       valid_lft forever preferred_lft forever
Deleted 32: swp0    inet6 fe80::e4fb:6ac5:7211:7981/64 scope link tentative
       valid_lft forever preferred_lft forever
Deleted fe80::/64 dev swp0 proto kernel metric 256 pref medium
32: random: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default
    link/ether 7a:1e:87:48:79:c0 brd ff:ff:ff:ff:ff:ff
fe80::/64 dev swp0 proto kernel metric 256 pref medium
32: swp0    inet6 fe80::e4fb:6ac5:7211:7981/64 scope link tentative
       valid_lft forever preferred_lft forever
Deleted 32: swp0    inet6 fe80::e4fb:6ac5:7211:7981/64 scope link tentative
       valid_lft forever preferred_lft forever
Deleted fe80::/64 dev swp0 proto kernel metric 256 pref medium
32: random: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default
    link/ether 7a:1e:87:48:79:c0 brd ff:ff:ff:ff:ff:ff
fe80::/64 dev swp0 proto kernel metric 256 pref medium
32: swp0    inet6 fe80::e4fb:6ac5:7211:7981/64 scope link tentative
       valid_lft forever preferred_lft forever
Deleted 32: swp0    inet6 fe80::e4fb:6ac5:7211:7981/64 scope link tentative
       valid_lft forever preferred_lft forever
Deleted fe80::/64 dev swp0 proto kernel metric 256 pref medium
^C32: random: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default
    link/ether 7a:1e:87:48:79:c0 brd ff:ff:ff:ff:ff:ff
fe80::/64 dev swp0 proto kernel metric 256 pref medium
32: swp0    inet6 fe80::e4fb:6ac5:7211:7981/64 scope link tentative
       valid_lft forever preferred_lft forever
Deleted 32: swp0    inet6 fe80::e4fb:6ac5:7211:7981/64 scope link tentative
       valid_lft forever preferred_lft forever
Deleted fe80::/64 dev swp0 proto kernel metric 256 pref medium
32: random: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default
    link/ether 7a:1e:87:48:79:c0 brd ff:ff:ff:ff:ff:ff
fe80::/64 dev swp0 proto kernel metric 256 pref medium
32: swp0    inet6 fe80::e4fb:6ac5:7211:7981/64 scope link tentative
       valid_lft forever preferred_lft forever
Deleted 32: swp0    inet6 fe80::e4fb:6ac5:7211:7981/64 scope link tentative
       valid_lft forever preferred_lft forever
Deleted fe80::/64 dev swp0 proto kernel metric 256 pref medium

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: Renaming interfaces that are up (Was "Re: [PATCH v3 net-next 08/10] net: mscc: ocelot: register devlink") ports
  2021-01-15 17:11             ` Renaming interfaces that are up (Was "Re: [PATCH v3 net-next 08/10] net: mscc: ocelot: register devlink") ports Vladimir Oltean
@ 2021-01-15 19:54               ` Vladimir Oltean
  0 siblings, 0 replies; 36+ messages in thread
From: Vladimir Oltean @ 2021-01-15 19:54 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: netdev, alexandre.belloni, andrew, f.fainelli, vivien.didelot,
	alexandru.marginean, claudiu.manoil, xiaoliang.yang_1,
	hongbo.wang, jiri, idosch, UNGLinuxDriver

On Fri, Jan 15, 2021 at 07:11:42PM +0200, Vladimir Oltean wrote:
> By the way I removed the if condition and added nothing in its place,
> just to see what would happen. I see a lot of these messages, I did not
> investigate where they are coming from and why they are emitted. They go
> away when I rename the interface back to swp0.

Looks like it's again related to dhcpcd. If I rename the interface while
it's down, the link-local IPv6 addresses don't get endlessly deleted as
they do if I rename it while it's up. Also, if I live-rename the interface
while dhcpcd isn't up, that behavior disappears too.

Still not sure why it happens.

^ permalink raw reply	[flat|nested] 36+ messages in thread

end of thread, other threads:[~2021-01-15 19:54 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-01-08 17:59 [PATCH v3 net-next 00/10] Configuring congestion watermarks on ocelot switch using devlink-sb Vladimir Oltean
2021-01-08 17:59 ` [PATCH v3 net-next 01/10] net: mscc: ocelot: auto-detect packet buffer size and number of frame references Vladimir Oltean
2021-01-08 18:30   ` Florian Fainelli
2021-01-08 17:59 ` [PATCH v3 net-next 02/10] net: mscc: ocelot: add ops for decoding watermark threshold and occupancy Vladimir Oltean
2021-01-08 18:30   ` Florian Fainelli
2021-01-10  1:20   ` Jakub Kicinski
2021-01-11 16:53     ` Vladimir Oltean
2021-01-11 19:10       ` Jakub Kicinski
2021-01-08 17:59 ` [PATCH v3 net-next 03/10] net: dsa: add ops for devlink-sb Vladimir Oltean
2021-01-08 18:20   ` Andrew Lunn
2021-01-08 18:31   ` Florian Fainelli
2021-01-08 17:59 ` [PATCH v3 net-next 04/10] net: dsa: felix: reindent struct dsa_switch_ops Vladimir Oltean
2021-01-08 18:33   ` Florian Fainelli
2021-01-10  1:24   ` Jakub Kicinski
2021-01-11 17:01     ` Vladimir Oltean
2021-01-11 19:12       ` Jakub Kicinski
2021-01-08 17:59 ` [PATCH v3 net-next 05/10] net: dsa: felix: perform teardown in reverse order of setup Vladimir Oltean
2021-01-08 18:34   ` Florian Fainelli
2021-01-08 17:59 ` [PATCH v3 net-next 06/10] net: mscc: ocelot: export NUM_TC constant from felix to common switch lib Vladimir Oltean
2021-01-08 18:34   ` Florian Fainelli
2021-01-08 17:59 ` [PATCH v3 net-next 07/10] net: mscc: ocelot: delete unused ocelot_set_cpu_port prototype Vladimir Oltean
2021-01-08 18:35   ` Florian Fainelli
2021-01-08 17:59 ` [PATCH v3 net-next 08/10] net: mscc: ocelot: register devlink ports Vladimir Oltean
2021-01-08 18:36   ` Florian Fainelli
2021-01-10  1:44   ` Jakub Kicinski
2021-01-11 17:13     ` Vladimir Oltean
2021-01-11 19:19       ` Jakub Kicinski
2021-01-14 10:34         ` Vladimir Oltean
2021-01-14 16:44           ` Jakub Kicinski
2021-01-15 17:11             ` Renaming interfaces that are up (Was "Re: [PATCH v3 net-next 08/10] net: mscc: ocelot: register devlink") ports Vladimir Oltean
2021-01-15 19:54               ` Vladimir Oltean
2021-01-10  2:01   ` [PATCH v3 net-next 08/10] net: mscc: ocelot: register devlink ports Jakub Kicinski
2021-01-08 17:59 ` [PATCH v3 net-next 09/10] net: mscc: ocelot: initialize watermarks to sane defaults Vladimir Oltean
2021-01-09  3:59   ` Florian Fainelli
2021-01-08 17:59 ` [PATCH v3 net-next 10/10] net: mscc: ocelot: configure watermarks using devlink-sb Vladimir Oltean
2021-01-09  4:03   ` Florian Fainelli

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).