Commit d56f9ddf authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'sparx5-qos'

Daniel Machon says:

====================
net: Add QoS offload support for sparx5

This patch series adds support for offloading QoS features with the tc
command suite, to the sparx5 switch. The new offloadable QoS features
introduced in this patch series are:

  - tc-mqprio for mapping traffic class to hardware queue. Queues are by
    default mapped 1:1  in hardware, as such the mqprio qdisc is used as
    an attachment point for qdiscs tbf and ets.

    $ tc qdisc add dev eth0 root handle 1:0 mqprio

  - tc-tbf for setting up shaping on scheduler elements of the HSCH
    (Hierarchical Scheduler) block. Shaping on either port output or
    queue output is supported.

    Port shaper: $ tc qdisc add dev eth0 root handle 1:0 tbf rate \
    10000000 burst 8192 limit 1m

    Queue shaper: $ tc qdisc replace dev eth0 parent 1:5 handle 2:0 tbf \
    rate 10000000 burst 8192 limit 1m

  - tc-ets for setting up strict and or bandwidth-sharing bands on one
    through eight priority queues.

    Configure a mix of strict and bw-sharing bands:
    $ tc qdisc add dev eth0 handle 1: root ets bands 8 strict 5 \
    quanta 1000 1000 1000 priomap 7 6 5 4 3 2 1 0

Patch #1 Sets up the tc hook.
Patch #2 Adds support for offloading the tc-mqprio qdisc.
Patch #3 Adds support for offloading the tc-tbf qdisc.
Patch #4 Adds support for offloading the tc-ets qdisc.
Patch #5 Updates the maintainers of the sparx5 driver.

========================================================================

v1:
https://lore.kernel.org/netdev/20220919120215.3815696-1-daniel.machon@microchip.com/



v1 -> v2:
  - Fix compiler warning in patch #2
  - Fix comment style in patch #4
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents d05d9eb7 d91a6d04
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -2401,6 +2401,7 @@ N: atmel
ARM/Microchip Sparx5 SoC support
M:	Lars Povlsen <lars.povlsen@microchip.com>
M:	Steen Hegelund <Steen.Hegelund@microchip.com>
M:	Daniel Machon <daniel.machon@microchip.com>
M:	UNGLinuxDriver@microchip.com
L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S:	Supported
+1 −1
Original line number Diff line number Diff line
@@ -8,4 +8,4 @@ obj-$(CONFIG_SPARX5_SWITCH) += sparx5-switch.o
sparx5-switch-objs  := sparx5_main.o sparx5_packet.o \
 sparx5_netdev.o sparx5_phylink.o sparx5_port.o sparx5_mactable.o sparx5_vlan.o \
 sparx5_switchdev.o sparx5_calendar.o sparx5_ethtool.o sparx5_fdma.o \
 sparx5_ptp.o sparx5_pgid.o
 sparx5_ptp.o sparx5_pgid.o sparx5_tc.o sparx5_qos.o
+7 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@
#include "sparx5_main_regs.h"
#include "sparx5_main.h"
#include "sparx5_port.h"
#include "sparx5_qos.h"

#define QLIM_WM(fraction) \
	((SPX5_BUFFER_MEMORY / SPX5_BUFFER_CELL_SZ - 100) * (fraction) / 100)
@@ -868,6 +869,12 @@ static int mchp_sparx5_probe(struct platform_device *pdev)
		goto cleanup_ports;
	}

	err = sparx5_qos_init(sparx5);
	if (err) {
		dev_err(sparx5->dev, "Failed to initialize QoS\n");
		goto cleanup_ports;
	}

	err = sparx5_ptp_init(sparx5);
	if (err) {
		dev_err(sparx5->dev, "PTP failed\n");
+165 −0
Original line number Diff line number Diff line
@@ -2993,6 +2993,147 @@ enum sparx5_target {
#define GCB_SIO_CLOCK_SYS_CLK_PERIOD_GET(x)\
	FIELD_GET(GCB_SIO_CLOCK_SYS_CLK_PERIOD, x)

/*      HSCH:HSCH_CFG:CIR_CFG */
#define HSCH_CIR_CFG(g)           __REG(TARGET_HSCH, 0, 1, 0, g, 5040, 32, 0, 0, 1, 4)

#define HSCH_CIR_CFG_CIR_RATE                    GENMASK(22, 6)
#define HSCH_CIR_CFG_CIR_RATE_SET(x)\
	FIELD_PREP(HSCH_CIR_CFG_CIR_RATE, x)
#define HSCH_CIR_CFG_CIR_RATE_GET(x)\
	FIELD_GET(HSCH_CIR_CFG_CIR_RATE, x)

#define HSCH_CIR_CFG_CIR_BURST                   GENMASK(5, 0)
#define HSCH_CIR_CFG_CIR_BURST_SET(x)\
	FIELD_PREP(HSCH_CIR_CFG_CIR_BURST, x)
#define HSCH_CIR_CFG_CIR_BURST_GET(x)\
	FIELD_GET(HSCH_CIR_CFG_CIR_BURST, x)

/*      HSCH:HSCH_CFG:EIR_CFG */
#define HSCH_EIR_CFG(g)           __REG(TARGET_HSCH, 0, 1, 0, g, 5040, 32, 4, 0, 1, 4)

#define HSCH_EIR_CFG_EIR_RATE                    GENMASK(22, 6)
#define HSCH_EIR_CFG_EIR_RATE_SET(x)\
	FIELD_PREP(HSCH_EIR_CFG_EIR_RATE, x)
#define HSCH_EIR_CFG_EIR_RATE_GET(x)\
	FIELD_GET(HSCH_EIR_CFG_EIR_RATE, x)

#define HSCH_EIR_CFG_EIR_BURST                   GENMASK(5, 0)
#define HSCH_EIR_CFG_EIR_BURST_SET(x)\
	FIELD_PREP(HSCH_EIR_CFG_EIR_BURST, x)
#define HSCH_EIR_CFG_EIR_BURST_GET(x)\
	FIELD_GET(HSCH_EIR_CFG_EIR_BURST, x)

/*      HSCH:HSCH_CFG:SE_CFG */
#define HSCH_SE_CFG(g)            __REG(TARGET_HSCH, 0, 1, 0, g, 5040, 32, 8, 0, 1, 4)

#define HSCH_SE_CFG_SE_DWRR_CNT                  GENMASK(12, 6)
#define HSCH_SE_CFG_SE_DWRR_CNT_SET(x)\
	FIELD_PREP(HSCH_SE_CFG_SE_DWRR_CNT, x)
#define HSCH_SE_CFG_SE_DWRR_CNT_GET(x)\
	FIELD_GET(HSCH_SE_CFG_SE_DWRR_CNT, x)

#define HSCH_SE_CFG_SE_AVB_ENA                   BIT(5)
#define HSCH_SE_CFG_SE_AVB_ENA_SET(x)\
	FIELD_PREP(HSCH_SE_CFG_SE_AVB_ENA, x)
#define HSCH_SE_CFG_SE_AVB_ENA_GET(x)\
	FIELD_GET(HSCH_SE_CFG_SE_AVB_ENA, x)

#define HSCH_SE_CFG_SE_FRM_MODE                  GENMASK(4, 3)
#define HSCH_SE_CFG_SE_FRM_MODE_SET(x)\
	FIELD_PREP(HSCH_SE_CFG_SE_FRM_MODE, x)
#define HSCH_SE_CFG_SE_FRM_MODE_GET(x)\
	FIELD_GET(HSCH_SE_CFG_SE_FRM_MODE, x)

#define HSCH_SE_CFG_SE_DWRR_FRM_MODE             GENMASK(2, 1)
#define HSCH_SE_CFG_SE_DWRR_FRM_MODE_SET(x)\
	FIELD_PREP(HSCH_SE_CFG_SE_DWRR_FRM_MODE, x)
#define HSCH_SE_CFG_SE_DWRR_FRM_MODE_GET(x)\
	FIELD_GET(HSCH_SE_CFG_SE_DWRR_FRM_MODE, x)

#define HSCH_SE_CFG_SE_STOP                      BIT(0)
#define HSCH_SE_CFG_SE_STOP_SET(x)\
	FIELD_PREP(HSCH_SE_CFG_SE_STOP, x)
#define HSCH_SE_CFG_SE_STOP_GET(x)\
	FIELD_GET(HSCH_SE_CFG_SE_STOP, x)

/*      HSCH:HSCH_CFG:SE_CONNECT */
#define HSCH_SE_CONNECT(g)        __REG(TARGET_HSCH, 0, 1, 0, g, 5040, 32, 12, 0, 1, 4)

#define HSCH_SE_CONNECT_SE_LEAK_LINK             GENMASK(15, 0)
#define HSCH_SE_CONNECT_SE_LEAK_LINK_SET(x)\
	FIELD_PREP(HSCH_SE_CONNECT_SE_LEAK_LINK, x)
#define HSCH_SE_CONNECT_SE_LEAK_LINK_GET(x)\
	FIELD_GET(HSCH_SE_CONNECT_SE_LEAK_LINK, x)

/*      HSCH:HSCH_CFG:SE_DLB_SENSE */
#define HSCH_SE_DLB_SENSE(g)      __REG(TARGET_HSCH, 0, 1, 0, g, 5040, 32, 16, 0, 1, 4)

#define HSCH_SE_DLB_SENSE_SE_DLB_PRIO            GENMASK(12, 10)
#define HSCH_SE_DLB_SENSE_SE_DLB_PRIO_SET(x)\
	FIELD_PREP(HSCH_SE_DLB_SENSE_SE_DLB_PRIO, x)
#define HSCH_SE_DLB_SENSE_SE_DLB_PRIO_GET(x)\
	FIELD_GET(HSCH_SE_DLB_SENSE_SE_DLB_PRIO, x)

#define HSCH_SE_DLB_SENSE_SE_DLB_DPORT           GENMASK(9, 3)
#define HSCH_SE_DLB_SENSE_SE_DLB_DPORT_SET(x)\
	FIELD_PREP(HSCH_SE_DLB_SENSE_SE_DLB_DPORT, x)
#define HSCH_SE_DLB_SENSE_SE_DLB_DPORT_GET(x)\
	FIELD_GET(HSCH_SE_DLB_SENSE_SE_DLB_DPORT, x)

#define HSCH_SE_DLB_SENSE_SE_DLB_SE_ENA          BIT(2)
#define HSCH_SE_DLB_SENSE_SE_DLB_SE_ENA_SET(x)\
	FIELD_PREP(HSCH_SE_DLB_SENSE_SE_DLB_SE_ENA, x)
#define HSCH_SE_DLB_SENSE_SE_DLB_SE_ENA_GET(x)\
	FIELD_GET(HSCH_SE_DLB_SENSE_SE_DLB_SE_ENA, x)

#define HSCH_SE_DLB_SENSE_SE_DLB_PRIO_ENA        BIT(1)
#define HSCH_SE_DLB_SENSE_SE_DLB_PRIO_ENA_SET(x)\
	FIELD_PREP(HSCH_SE_DLB_SENSE_SE_DLB_PRIO_ENA, x)
#define HSCH_SE_DLB_SENSE_SE_DLB_PRIO_ENA_GET(x)\
	FIELD_GET(HSCH_SE_DLB_SENSE_SE_DLB_PRIO_ENA, x)

#define HSCH_SE_DLB_SENSE_SE_DLB_DPORT_ENA       BIT(0)
#define HSCH_SE_DLB_SENSE_SE_DLB_DPORT_ENA_SET(x)\
	FIELD_PREP(HSCH_SE_DLB_SENSE_SE_DLB_DPORT_ENA, x)
#define HSCH_SE_DLB_SENSE_SE_DLB_DPORT_ENA_GET(x)\
	FIELD_GET(HSCH_SE_DLB_SENSE_SE_DLB_DPORT_ENA, x)

/*      HSCH:HSCH_DWRR:DWRR_ENTRY */
#define HSCH_DWRR_ENTRY(g)        __REG(TARGET_HSCH, 0, 1, 162816, g, 72, 4, 0, 0, 1, 4)

#define HSCH_DWRR_ENTRY_DWRR_COST                GENMASK(24, 20)
#define HSCH_DWRR_ENTRY_DWRR_COST_SET(x)\
	FIELD_PREP(HSCH_DWRR_ENTRY_DWRR_COST, x)
#define HSCH_DWRR_ENTRY_DWRR_COST_GET(x)\
	FIELD_GET(HSCH_DWRR_ENTRY_DWRR_COST, x)

#define HSCH_DWRR_ENTRY_DWRR_BALANCE             GENMASK(19, 0)
#define HSCH_DWRR_ENTRY_DWRR_BALANCE_SET(x)\
	FIELD_PREP(HSCH_DWRR_ENTRY_DWRR_BALANCE, x)
#define HSCH_DWRR_ENTRY_DWRR_BALANCE_GET(x)\
	FIELD_GET(HSCH_DWRR_ENTRY_DWRR_BALANCE, x)

/*      HSCH:HSCH_MISC:HSCH_CFG_CFG */
#define HSCH_HSCH_CFG_CFG         __REG(TARGET_HSCH, 0, 1, 163104, 0, 1, 648, 284, 0, 1, 4)

#define HSCH_HSCH_CFG_CFG_CFG_SE_IDX             GENMASK(26, 14)
#define HSCH_HSCH_CFG_CFG_CFG_SE_IDX_SET(x)\
	FIELD_PREP(HSCH_HSCH_CFG_CFG_CFG_SE_IDX, x)
#define HSCH_HSCH_CFG_CFG_CFG_SE_IDX_GET(x)\
	FIELD_GET(HSCH_HSCH_CFG_CFG_CFG_SE_IDX, x)

#define HSCH_HSCH_CFG_CFG_HSCH_LAYER             GENMASK(13, 12)
#define HSCH_HSCH_CFG_CFG_HSCH_LAYER_SET(x)\
	FIELD_PREP(HSCH_HSCH_CFG_CFG_HSCH_LAYER, x)
#define HSCH_HSCH_CFG_CFG_HSCH_LAYER_GET(x)\
	FIELD_GET(HSCH_HSCH_CFG_CFG_HSCH_LAYER, x)

#define HSCH_HSCH_CFG_CFG_CSR_GRANT              GENMASK(11, 0)
#define HSCH_HSCH_CFG_CFG_CSR_GRANT_SET(x)\
	FIELD_PREP(HSCH_HSCH_CFG_CFG_CSR_GRANT, x)
#define HSCH_HSCH_CFG_CFG_CSR_GRANT_GET(x)\
	FIELD_GET(HSCH_HSCH_CFG_CFG_CSR_GRANT, x)

/*      HSCH:HSCH_MISC:SYS_CLK_PER */
#define HSCH_SYS_CLK_PER          __REG(TARGET_HSCH, 0, 1, 163104, 0, 1, 648, 640, 0, 1, 4)

@@ -3002,6 +3143,30 @@ enum sparx5_target {
#define HSCH_SYS_CLK_PER_SYS_CLK_PER_100PS_GET(x)\
	FIELD_GET(HSCH_SYS_CLK_PER_SYS_CLK_PER_100PS, x)

/*      HSCH:HSCH_LEAK_LISTS:HSCH_TIMER_CFG */
#define HSCH_HSCH_TIMER_CFG(g, r) __REG(TARGET_HSCH, 0, 1, 161664, g, 4, 32, 0, r, 4, 4)

#define HSCH_HSCH_TIMER_CFG_LEAK_TIME            GENMASK(17, 0)
#define HSCH_HSCH_TIMER_CFG_LEAK_TIME_SET(x)\
	FIELD_PREP(HSCH_HSCH_TIMER_CFG_LEAK_TIME, x)
#define HSCH_HSCH_TIMER_CFG_LEAK_TIME_GET(x)\
	FIELD_GET(HSCH_HSCH_TIMER_CFG_LEAK_TIME, x)

/*      HSCH:HSCH_LEAK_LISTS:HSCH_LEAK_CFG */
#define HSCH_HSCH_LEAK_CFG(g, r)  __REG(TARGET_HSCH, 0, 1, 161664, g, 4, 32, 16, r, 4, 4)

#define HSCH_HSCH_LEAK_CFG_LEAK_FIRST            GENMASK(16, 1)
#define HSCH_HSCH_LEAK_CFG_LEAK_FIRST_SET(x)\
	FIELD_PREP(HSCH_HSCH_LEAK_CFG_LEAK_FIRST, x)
#define HSCH_HSCH_LEAK_CFG_LEAK_FIRST_GET(x)\
	FIELD_GET(HSCH_HSCH_LEAK_CFG_LEAK_FIRST, x)

#define HSCH_HSCH_LEAK_CFG_LEAK_ERR              BIT(0)
#define HSCH_HSCH_LEAK_CFG_LEAK_ERR_SET(x)\
	FIELD_PREP(HSCH_HSCH_LEAK_CFG_LEAK_ERR, x)
#define HSCH_HSCH_LEAK_CFG_LEAK_ERR_GET(x)\
	FIELD_GET(HSCH_HSCH_LEAK_CFG_LEAK_ERR, x)

/*      HSCH:SYSTEM:FLUSH_CTRL */
#define HSCH_FLUSH_CTRL           __REG(TARGET_HSCH, 0, 1, 184000, 0, 1, 312, 4, 0, 1, 4)

+7 −1
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@
#include "sparx5_main_regs.h"
#include "sparx5_main.h"
#include "sparx5_port.h"
#include "sparx5_tc.h"

/* The IFH bit position of the first VSTAX bit. This is because the
 * VSTAX bit positions in Data sheet is starting from zero.
@@ -228,6 +229,7 @@ static const struct net_device_ops sparx5_port_netdev_ops = {
	.ndo_get_stats64        = sparx5_get_stats64,
	.ndo_get_port_parent_id = sparx5_get_port_parent_id,
	.ndo_eth_ioctl          = sparx5_port_ioctl,
	.ndo_setup_tc           = sparx5_port_setup_tc,
};

bool sparx5_netdevice_check(const struct net_device *dev)
@@ -240,10 +242,14 @@ struct net_device *sparx5_create_netdev(struct sparx5 *sparx5, u32 portno)
	struct sparx5_port *spx5_port;
	struct net_device *ndev;

	ndev = devm_alloc_etherdev(sparx5->dev, sizeof(struct sparx5_port));
	ndev = devm_alloc_etherdev_mqs(sparx5->dev, sizeof(struct sparx5_port),
				       SPX5_PRIOS, 1);
	if (!ndev)
		return ERR_PTR(-ENOMEM);

	ndev->hw_features |= NETIF_F_HW_TC;
	ndev->features |= NETIF_F_HW_TC;

	SET_NETDEV_DEV(ndev, sparx5->dev);
	spx5_port = netdev_priv(ndev);
	spx5_port->ndev = ndev;
Loading