 2c35899d81
			
		
	
	2c35899d81
	
	
	
		
			
			All modification made by update_kernel.sh in a fresh clone without
existing toolchains.
Build system:       x86_64
Build-tested:       ipq806x/R7800, bcm27xx/bcm2711
Run-tested:         ipq806x/R7800
Compile-tested [*]: ath79/{tiny,generic}, ipq40xx, octeon,
                    ramips/mt7621, realtek, x86/64
Run-tested [*]:     ath79/generic, ipq40xx, octeon, ramips/mt7621
No dmesg regressions, everything functional
Signed-off-by: John Audia <graysky@archlinux.us>
Tested-by: Stijn Segers <foss@volatilesystems.org> [*]
		
	
		
			
				
	
	
		
			1987 lines
		
	
	
		
			61 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			1987 lines
		
	
	
		
			61 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From eb5556db4c4fb8dff9a7b716c66a1ea3d3e696ce Mon Sep 17 00:00:00 2001
 | |
| From: Xiaoliang Yang <xiaoliang.yang_1@nxp.com>
 | |
| Date: Fri, 29 Nov 2019 11:02:43 +0800
 | |
| Subject: [PATCH] net: mscc: ocelot: tsn configuration support
 | |
| 
 | |
| Support TSN configuration for ocelot switch. The TSN configuration
 | |
| fucntions are based on tsn netlink interface, it can support Qbv,
 | |
| Qbu, Qci, 802.1CB, and Qav configuration now.
 | |
| 
 | |
| Signed-off-by: Xiaoliang Yang <xiaoliang.yang_1@nxp.com>
 | |
| ---
 | |
|  drivers/net/ethernet/mscc/Makefile          |    1 +
 | |
|  drivers/net/ethernet/mscc/ocelot.c          |   11 +-
 | |
|  drivers/net/ethernet/mscc/ocelot.h          |    2 +
 | |
|  drivers/net/ethernet/mscc/ocelot_ana.h      |   25 +-
 | |
|  drivers/net/ethernet/mscc/ocelot_dev_gmii.h |  153 +++
 | |
|  drivers/net/ethernet/mscc/ocelot_tsn.c      | 1572 +++++++++++++++++++++++++++
 | |
|  drivers/net/ethernet/mscc/ocelot_tsn.h      |   51 +
 | |
|  include/soc/mscc/ocelot.h                   |   52 +-
 | |
|  8 files changed, 1857 insertions(+), 10 deletions(-)
 | |
|  create mode 100644 drivers/net/ethernet/mscc/ocelot_dev_gmii.h
 | |
|  create mode 100644 drivers/net/ethernet/mscc/ocelot_tsn.c
 | |
|  create mode 100644 drivers/net/ethernet/mscc/ocelot_tsn.h
 | |
| 
 | |
| --- a/drivers/net/ethernet/mscc/Makefile
 | |
| +++ b/drivers/net/ethernet/mscc/Makefile
 | |
| @@ -2,4 +2,5 @@
 | |
|  obj-$(CONFIG_MSCC_OCELOT_SWITCH) += mscc_ocelot_common.o
 | |
|  mscc_ocelot_common-y := ocelot.o ocelot_io.o
 | |
|  mscc_ocelot_common-y += ocelot_regs.o ocelot_tc.o ocelot_police.o ocelot_ace.o ocelot_flower.o
 | |
| +mscc_ocelot_common-y += ocelot_tsn.o
 | |
|  obj-$(CONFIG_MSCC_OCELOT_SWITCH_OCELOT) += ocelot_board.o
 | |
| --- a/drivers/net/ethernet/mscc/ocelot.c
 | |
| +++ b/drivers/net/ethernet/mscc/ocelot.c
 | |
| @@ -780,7 +780,7 @@ static void ocelot_set_rx_mode(struct ne
 | |
|  	 * forwarded to the CPU port.
 | |
|  	 */
 | |
|  	val = GENMASK(ocelot->num_phys_ports - 1, 0);
 | |
| -	for (i = ocelot->num_phys_ports + 1; i < PGID_CPU; i++)
 | |
| +	for (i = ocelot->num_phys_ports + 1; i < PGID_MCRED; i++)
 | |
|  		ocelot_write_rix(ocelot, val, ANA_PGID_PGID, i);
 | |
|  
 | |
|  	__dev_mc_sync(dev, ocelot_mc_sync, ocelot_mc_unsync);
 | |
| @@ -2410,10 +2410,11 @@ int ocelot_init(struct ocelot *ocelot)
 | |
|  		     SYS_FRM_AGING_MAX_AGE(307692), SYS_FRM_AGING);
 | |
|  
 | |
|  	/* Setup flooding PGIDs */
 | |
| -	ocelot_write_rix(ocelot, ANA_FLOODING_FLD_MULTICAST(PGID_MC) |
 | |
| -			 ANA_FLOODING_FLD_BROADCAST(PGID_MC) |
 | |
| -			 ANA_FLOODING_FLD_UNICAST(PGID_UC),
 | |
| -			 ANA_FLOODING, 0);
 | |
| +	for (i = 0; i < 8; i++)
 | |
| +		ocelot_write_rix(ocelot, ANA_FLOODING_FLD_MULTICAST(PGID_MC) |
 | |
| +				 ANA_FLOODING_FLD_BROADCAST(PGID_MC) |
 | |
| +				 ANA_FLOODING_FLD_UNICAST(PGID_UC),
 | |
| +				 ANA_FLOODING, i);
 | |
|  	ocelot_write(ocelot, ANA_FLOODING_IPMC_FLD_MC6_DATA(PGID_MCIPV6) |
 | |
|  		     ANA_FLOODING_IPMC_FLD_MC6_CTRL(PGID_MC) |
 | |
|  		     ANA_FLOODING_IPMC_FLD_MC4_DATA(PGID_MCIPV4) |
 | |
| --- a/drivers/net/ethernet/mscc/ocelot.h
 | |
| +++ b/drivers/net/ethernet/mscc/ocelot.h
 | |
| @@ -27,11 +27,13 @@
 | |
|  #include "ocelot_qs.h"
 | |
|  #include "ocelot_tc.h"
 | |
|  #include "ocelot_ptp.h"
 | |
| +#include "ocelot_dev_gmii.h"
 | |
|  
 | |
|  #define PGID_AGGR    64
 | |
|  #define PGID_SRC     80
 | |
|  
 | |
|  /* Reserved PGIDs */
 | |
| +#define PGID_MCRED   (PGID_AGGR - 25)
 | |
|  #define PGID_CPU     (PGID_AGGR - 5)
 | |
|  #define PGID_UC      (PGID_AGGR - 4)
 | |
|  #define PGID_MC      (PGID_AGGR - 3)
 | |
| --- a/drivers/net/ethernet/mscc/ocelot_ana.h
 | |
| +++ b/drivers/net/ethernet/mscc/ocelot_ana.h
 | |
| @@ -227,6 +227,11 @@
 | |
|  #define ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(x)             ((x) & GENMASK(1, 0))
 | |
|  #define ANA_TABLES_SFIDACCESS_SFID_TBL_CMD_M              GENMASK(1, 0)
 | |
|  
 | |
| +#define SFIDACCESS_CMD_IDLE                             0
 | |
| +#define SFIDACCESS_CMD_READ                             1
 | |
| +#define SFIDACCESS_CMD_WRITE                            2
 | |
| +#define SFIDACCESS_CMD_INIT				3
 | |
| +
 | |
|  #define ANA_TABLES_SFIDTIDX_SGID_VALID                    BIT(26)
 | |
|  #define ANA_TABLES_SFIDTIDX_SGID(x)                       (((x) << 18) & GENMASK(25, 18))
 | |
|  #define ANA_TABLES_SFIDTIDX_SGID_M                        GENMASK(25, 18)
 | |
| @@ -252,15 +257,23 @@
 | |
|  #define ANA_SG_CONFIG_REG_3_LIST_LENGTH_M                 GENMASK(18, 16)
 | |
|  #define ANA_SG_CONFIG_REG_3_LIST_LENGTH_X(x)              (((x) & GENMASK(18, 16)) >> 16)
 | |
|  #define ANA_SG_CONFIG_REG_3_GATE_ENABLE                   BIT(20)
 | |
| -#define ANA_SG_CONFIG_REG_3_INIT_IPS(x)                   (((x) << 24) & GENMASK(27, 24))
 | |
| -#define ANA_SG_CONFIG_REG_3_INIT_IPS_M                    GENMASK(27, 24)
 | |
| -#define ANA_SG_CONFIG_REG_3_INIT_IPS_X(x)                 (((x) & GENMASK(27, 24)) >> 24)
 | |
| -#define ANA_SG_CONFIG_REG_3_INIT_GATE_STATE               BIT(28)
 | |
| +#define ANA_SG_CONFIG_REG_3_INIT_IPS(x)                   (((x) << 21) & GENMASK(24, 21))
 | |
| +#define ANA_SG_CONFIG_REG_3_INIT_IPS_M                    GENMASK(24, 21)
 | |
| +#define ANA_SG_CONFIG_REG_3_INIT_IPS_X(x)                 (((x) & GENMASK(24, 21)) >> 21)
 | |
| +#define ANA_SG_CONFIG_REG_3_IPV_VALID                     BIT(24)
 | |
| +#define ANA_SG_CONFIG_REG_3_IPV_INVALID(x)		  (((x) << 24) & GENMASK(24, 24))
 | |
| +#define ANA_SG_CONFIG_REG_3_INIT_IPV(x)                   (((x) << 21) & GENMASK(23, 21))
 | |
| +#define ANA_SG_CONFIG_REG_3_INIT_IPV_M                    GENMASK(23, 21)
 | |
| +#define ANA_SG_CONFIG_REG_3_INIT_IPV_X(x)                 (((x) & GENMASK(23, 21)) >> 21)
 | |
| +#define ANA_SG_CONFIG_REG_3_INIT_GATE_STATE               BIT(25)
 | |
|  
 | |
|  #define ANA_SG_GCL_GS_CONFIG_RSZ                          0x4
 | |
|  
 | |
|  #define ANA_SG_GCL_GS_CONFIG_IPS(x)                       ((x) & GENMASK(3, 0))
 | |
|  #define ANA_SG_GCL_GS_CONFIG_IPS_M                        GENMASK(3, 0)
 | |
| +#define ANA_SG_GCL_GS_CONFIG_IPV_VALID                    BIT(3)
 | |
| +#define ANA_SG_GCL_GS_CONFIG_IPV(x)                       ((x) & GENMASK(2, 0))
 | |
| +#define ANA_SG_GCL_GS_CONFIG_IPV_M                        GENMASK(2, 0)
 | |
|  #define ANA_SG_GCL_GS_CONFIG_GATE_STATE                   BIT(4)
 | |
|  
 | |
|  #define ANA_SG_GCL_TI_CONFIG_RSZ                          0x4
 | |
| @@ -271,6 +284,10 @@
 | |
|  #define ANA_SG_STATUS_REG_3_IPS(x)                        (((x) << 20) & GENMASK(23, 20))
 | |
|  #define ANA_SG_STATUS_REG_3_IPS_M                         GENMASK(23, 20)
 | |
|  #define ANA_SG_STATUS_REG_3_IPS_X(x)                      (((x) & GENMASK(23, 20)) >> 20)
 | |
| +#define ANA_SG_STATUS_REG_3_IPV_VALID                     BIT(23)
 | |
| +#define ANA_SG_STATUS_REG_3_IPV(x)                        (((x) << 20) & GENMASK(22, 20))
 | |
| +#define ANA_SG_STATUS_REG_3_IPV_M                         GENMASK(22, 20)
 | |
| +#define ANA_SG_STATUS_REG_3_IPV_X(x)                      (((x) & GENMASK(22, 20)) >> 20)
 | |
|  #define ANA_SG_STATUS_REG_3_CONFIG_PENDING                BIT(24)
 | |
|  
 | |
|  #define ANA_PORT_VLAN_CFG_GSZ                             0x100
 | |
| --- /dev/null
 | |
| +++ b/drivers/net/ethernet/mscc/ocelot_dev_gmii.h
 | |
| @@ -0,0 +1,153 @@
 | |
| +/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
 | |
| +/* Microsemi Ocelot Switch driver
 | |
| + *
 | |
| + * Copyright (c) 2017 Microsemi Corporation
 | |
| + */
 | |
| +
 | |
| +#ifndef _MSCC_OCELOT_DEV_GMII_H_
 | |
| +#define _MSCC_OCELOT_DEV_GMII_H_
 | |
| +
 | |
| +#define DEV_GMII_PORT_MODE_CLOCK_CFG                      0x0
 | |
| +
 | |
| +#define DEV_GMII_PORT_MODE_CLOCK_CFG_MAC_TX_RST           BIT(5)
 | |
| +#define DEV_GMII_PORT_MODE_CLOCK_CFG_MAC_RX_RST           BIT(4)
 | |
| +#define DEV_GMII_PORT_MODE_CLOCK_CFG_PORT_RST             BIT(3)
 | |
| +#define DEV_GMII_PORT_MODE_CLOCK_CFG_PHY_RST              BIT(2)
 | |
| +#define DEV_GMII_PORT_MODE_CLOCK_CFG_LINK_SPEED(x)        ((x) & GENMASK(1, 0))
 | |
| +#define DEV_GMII_PORT_MODE_CLOCK_CFG_LINK_SPEED_M         GENMASK(1, 0)
 | |
| +
 | |
| +#define DEV_GMII_PORT_MODE_PORT_MISC                      0x4
 | |
| +
 | |
| +#define DEV_GMII_PORT_MODE_PORT_MISC_MPLS_RX_ENA          BIT(5)
 | |
| +#define DEV_GMII_PORT_MODE_PORT_MISC_FWD_ERROR_ENA        BIT(4)
 | |
| +#define DEV_GMII_PORT_MODE_PORT_MISC_FWD_PAUSE_ENA        BIT(3)
 | |
| +#define DEV_GMII_PORT_MODE_PORT_MISC_FWD_CTRL_ENA         BIT(2)
 | |
| +#define DEV_GMII_PORT_MODE_PORT_MISC_GMII_LOOP_ENA        BIT(1)
 | |
| +#define DEV_GMII_PORT_MODE_PORT_MISC_DEV_LOOP_ENA         BIT(0)
 | |
| +
 | |
| +#define DEV_GMII_PORT_MODE_EVENTS                         0x8
 | |
| +
 | |
| +#define DEV_GMII_PORT_MODE_EEE_CFG                        0xc
 | |
| +
 | |
| +#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_ENA                BIT(22)
 | |
| +#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_AGE(x)       (((x) << 15) & GENMASK(21, 15))
 | |
| +#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_AGE_M        GENMASK(21, 15)
 | |
| +#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_AGE_X(x)     (((x) & GENMASK(21, 15)) >> 15)
 | |
| +#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_WAKEUP(x)    (((x) << 8) & GENMASK(14, 8))
 | |
| +#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_WAKEUP_M     GENMASK(14, 8)
 | |
| +#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_WAKEUP_X(x)  (((x) & GENMASK(14, 8)) >> 8)
 | |
| +#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_HOLDOFF(x)   (((x) << 1) & GENMASK(7, 1))
 | |
| +#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_HOLDOFF_M    GENMASK(7, 1)
 | |
| +#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_HOLDOFF_X(x) (((x) & GENMASK(7, 1)) >> 1)
 | |
| +#define DEV_GMII_PORT_MODE_EEE_CFG_PORT_LPI               BIT(0)
 | |
| +
 | |
| +#define DEV_GMII_PORT_MODE_RX_PATH_DELAY                  0x10
 | |
| +
 | |
| +#define DEV_GMII_PORT_MODE_TX_PATH_DELAY                  0x14
 | |
| +
 | |
| +#define DEV_GMII_PORT_MODE_PTP_PREDICT_CFG                0x18
 | |
| +
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_ENA_CFG               0x1c
 | |
| +
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_ENA_CFG_RX_ENA        BIT(4)
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_ENA_CFG_TX_ENA        BIT(0)
 | |
| +
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_MODE_CFG              0x20
 | |
| +
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_MODE_CFG_FC_WORD_SYNC_ENA BIT(8)
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_MODE_CFG_GIGA_MODE_ENA BIT(4)
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_MODE_CFG_FDX_ENA      BIT(0)
 | |
| +
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_MAXLEN_CFG            0x24
 | |
| +
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_TAGS_CFG              0x28
 | |
| +
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_TAGS_CFG_TAG_ID(x)    (((x) << 16) & GENMASK(31, 16))
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_TAGS_CFG_TAG_ID_M     GENMASK(31, 16)
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_TAGS_CFG_TAG_ID_X(x)  (((x) & GENMASK(31, 16)) >> 16)
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_TAGS_CFG_PB_ENA       BIT(1)
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_TAGS_CFG_VLAN_AWR_ENA BIT(0)
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA BIT(2)
 | |
| +
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_ADV_CHK_CFG           0x2c
 | |
| +
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_ADV_CHK_CFG_LEN_DROP_ENA BIT(0)
 | |
| +
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG               0x30
 | |
| +
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_RESTORE_OLD_IPG_CHECK BIT(17)
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_REDUCED_TX_IFG BIT(16)
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_TX_IFG(x)     (((x) << 8) & GENMASK(12, 8))
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_TX_IFG_M      GENMASK(12, 8)
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_TX_IFG_X(x)   (((x) & GENMASK(12, 8)) >> 8)
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_RX_IFG2(x)    (((x) << 4) & GENMASK(7, 4))
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_RX_IFG2_M     GENMASK(7, 4)
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_RX_IFG2_X(x)  (((x) & GENMASK(7, 4)) >> 4)
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_RX_IFG1(x)    ((x) & GENMASK(3, 0))
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_RX_IFG1_M     GENMASK(3, 0)
 | |
| +
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG               0x34
 | |
| +
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_BYPASS_COL_SYNC BIT(26)
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_OB_ENA        BIT(25)
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_WEXC_DIS      BIT(24)
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_SEED(x)       (((x) << 16) & GENMASK(23, 16))
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_SEED_M        GENMASK(23, 16)
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_SEED_X(x)     (((x) & GENMASK(23, 16)) >> 16)
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_SEED_LOAD     BIT(12)
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_RETRY_AFTER_EXC_COL_ENA BIT(8)
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_LATE_COL_POS(x) ((x) & GENMASK(6, 0))
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_LATE_COL_POS_M GENMASK(6, 0)
 | |
| +
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_DBG_CFG               0x38
 | |
| +
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_DBG_CFG_TBI_MODE      BIT(4)
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_DBG_CFG_IFG_CRS_EXT_CHK_ENA BIT(0)
 | |
| +
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_FC_MAC_LOW_CFG        0x3c
 | |
| +
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_FC_MAC_HIGH_CFG       0x40
 | |
| +
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY                0x44
 | |
| +
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_RX_IPG_SHRINK_STICKY BIT(9)
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_RX_PREAM_SHRINK_STICKY BIT(8)
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_RX_CARRIER_EXT_STICKY BIT(7)
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_RX_CARRIER_EXT_ERR_STICKY BIT(6)
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_RX_JUNK_STICKY BIT(5)
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_TX_RETRANSMIT_STICKY BIT(4)
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_TX_JAM_STICKY  BIT(3)
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_TX_FIFO_OFLW_STICKY BIT(2)
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_TX_FRM_LEN_OVR_STICKY BIT(1)
 | |
| +#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_TX_ABORT_STICKY BIT(0)
 | |
| +
 | |
| +#define DEV_GMII_MM_CONFIG_ENABLE_CONFIG                  0x48
 | |
| +
 | |
| +#define DEV_GMII_MM_CONFIG_ENABLE_CONFIG_MM_RX_ENA        BIT(0)
 | |
| +#define DEV_GMII_MM_CONFIG_ENABLE_CONFIG_MM_TX_ENA        BIT(4)
 | |
| +#define DEV_GMII_MM_CONFIG_ENABLE_CONFIG_KEEP_S_AFTER_D   BIT(8)
 | |
| +
 | |
| +#define DEV_GMII_MM_CONFIG_VERIF_CONFIG                   0x4c
 | |
| +
 | |
| +#define DEV_GMII_MM_CONFIG_VERIF_CONFIG_PRM_VERIFY_DIS    BIT(0)
 | |
| +#define DEV_GMII_MM_CONFIG_VERIF_CONFIG_PRM_VERIFY_TIME(x) (((x) << 4) & GENMASK(11, 4))
 | |
| +#define DEV_GMII_MM_CONFIG_VERIF_CONFIG_PRM_VERIFY_TIME_M GENMASK(11, 4)
 | |
| +#define DEV_GMII_MM_CONFIG_VERIF_CONFIG_PRM_VERIFY_TIME_X(x) (((x) & GENMASK(11, 4)) >> 4)
 | |
| +#define DEV_GMII_MM_CONFIG_VERIF_CONFIG_VERIF_TIMER_UNITS(x) (((x) << 12) & GENMASK(13, 12))
 | |
| +#define DEV_GMII_MM_CONFIG_VERIF_CONFIG_VERIF_TIMER_UNITS_M GENMASK(13, 12)
 | |
| +#define DEV_GMII_MM_CONFIG_VERIF_CONFIG_VERIF_TIMER_UNITS_X(x) (((x) & GENMASK(13, 12)) >> 12)
 | |
| +
 | |
| +#define DEV_GMII_MM_STATISTICS_MM_STATUS                  0x50
 | |
| +
 | |
| +#define DEV_GMII_MM_STATISTICS_MM_STATUS_PRMPT_ACTIVE_STATUS BIT(0)
 | |
| +#define DEV_GMII_MM_STATISTICS_MM_STATUS_PRMPT_ACTIVE_STICKY BIT(4)
 | |
| +#define DEV_GMII_MM_STATISTICS_MM_STATUS_PRMPT_VERIFY_STATE(x) (((x) << 8) & GENMASK(10, 8))
 | |
| +#define DEV_GMII_MM_STATISTICS_MM_STATUS_PRMPT_VERIFY_STATE_M GENMASK(10, 8)
 | |
| +#define DEV_GMII_MM_STATISTICS_MM_STATUS_PRMPT_VERIFY_STATE_X(x) (((x) & GENMASK(10, 8)) >> 8)
 | |
| +#define DEV_GMII_MM_STATISTICS_MM_STATUS_UNEXP_RX_PFRM_STICKY BIT(12)
 | |
| +#define DEV_GMII_MM_STATISTICS_MM_STATUS_UNEXP_TX_PFRM_STICKY BIT(16)
 | |
| +#define DEV_GMII_MM_STATISTICS_MM_STATUS_MM_RX_FRAME_STATUS BIT(20)
 | |
| +#define DEV_GMII_MM_STATISTICS_MM_STATUS_MM_TX_FRAME_STATUS BIT(24)
 | |
| +#define DEV_GMII_MM_STATISTICS_MM_STATUS_MM_TX_PRMPT_STATUS BIT(28)
 | |
| +
 | |
| +#endif
 | |
| --- /dev/null
 | |
| +++ b/drivers/net/ethernet/mscc/ocelot_tsn.c
 | |
| @@ -0,0 +1,1572 @@
 | |
| +// SPDX-License-Identifier: (GPL-2.0 OR MIT)
 | |
| +/* Felix Switch TSN driver
 | |
| + *
 | |
| + * Copyright (c) 2018 Microsemi Corporation
 | |
| + * Copyright 2018-2019 NXP
 | |
| + */
 | |
| +
 | |
| +#include <linux/io.h>
 | |
| +#include <linux/kernel.h>
 | |
| +#include <linux/pci.h>
 | |
| +#include <linux/iopoll.h>
 | |
| +#include "ocelot.h"
 | |
| +#include <soc/mscc/ocelot_sys.h>
 | |
| +#include "ocelot_ana.h"
 | |
| +#include "ocelot_qsys.h"
 | |
| +#include "ocelot_rew.h"
 | |
| +#include "ocelot_dev_gmii.h"
 | |
| +#include "ocelot_tsn.h"
 | |
| +
 | |
| +#define MSCC_NUM_OUT_PORT 4 /* Number of physical output ports */
 | |
| +#define SE_IX_PORT 64
 | |
| +
 | |
| +/* MSCC TSN parameters limited */
 | |
| +#define NUM_MSCC_QOS_PRIO 8
 | |
| +#define MSCC_PSFP_SFID_NUM 176
 | |
| +#define MSCC_FRER_SSID_NUM 128
 | |
| +
 | |
| +/* Using the max number of MSCC_PSFP_SFID_NUM and MSCC_FRER_SSID_NUM */
 | |
| +#define MSCC_STREAM_HANDLE_NUM	MSCC_PSFP_SFID_NUM
 | |
| +
 | |
| +int streamhandle_map[MSCC_STREAM_HANDLE_NUM] = {0};
 | |
| +static struct mscc_switch_capa capa __ro_after_init = {
 | |
| +	.num_tas_gcl	= 64,
 | |
| +	.tas_ct_min	= 100,
 | |
| +	.tas_ct_max	= 1000000000,
 | |
| +	.tas_cte_max	= 999999999,
 | |
| +	.tas_it_max	= 999999999,
 | |
| +	.tas_it_min	= 1000,
 | |
| +	.num_hsch	= 72,
 | |
| +	.num_psfp_sfid	= MSCC_PSFP_SFID_NUM,
 | |
| +	.num_psfp_sgid	= 184,
 | |
| +	.psfp_fmi_max	= 246,
 | |
| +	.psfp_fmi_min	= 63,
 | |
| +	.num_sgi_gcl	= 4,
 | |
| +	.sgi_ct_min	= 5000,
 | |
| +	.sgi_ct_max	= 1000000000,
 | |
| +	.sgi_cte_max	= 999999999,
 | |
| +	.qos_pol_max	= 383,
 | |
| +	/* Maximum allowed value of committed burst size(CBS) is 240 KB */
 | |
| +	.pol_cbs_max	= 60,
 | |
| +	/* Maximum allowed value of excess burst size(EBS) is 240 KB */
 | |
| +	.pol_pbs_max	= 60,
 | |
| +	.num_frer_ssid  = MSCC_FRER_SSID_NUM,
 | |
| +	.frer_seq_len_min = 1,
 | |
| +	.frer_seq_len_max = 28,
 | |
| +	.frer_his_len_min = 1,
 | |
| +	.frer_his_len_max = 32,
 | |
| +	.qos_dscp_max	= 63,
 | |
| +	.qos_cos_max	= NUM_MSCC_QOS_PRIO - 1,
 | |
| +	.qos_dp_max	= 1,
 | |
| +};
 | |
| +
 | |
| +static int qos_port_tas_gcl_set(struct ocelot *ocelot, const u8 gcl_ix,
 | |
| +				struct tsn_qbv_entry *control_list)
 | |
| +{
 | |
| +	if (gcl_ix >= capa.num_tas_gcl) {
 | |
| +		dev_err(ocelot->dev, "Invalid gcl ix %u\n", gcl_ix);
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +	if (control_list->time_interval < capa.tas_it_min ||
 | |
| +	    control_list->time_interval > capa.tas_it_max) {
 | |
| +		dev_err(ocelot->dev, "Invalid time_interval %u\n",
 | |
| +			control_list->time_interval);
 | |
| +
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +
 | |
| +	ocelot_write(ocelot,
 | |
| +		     QSYS_GCL_CFG_REG_1_GCL_ENTRY_NUM(gcl_ix) |
 | |
| +		     QSYS_GCL_CFG_REG_1_GATE_STATE(control_list->gate_state),
 | |
| +		     QSYS_GCL_CFG_REG_1);
 | |
| +
 | |
| +	ocelot_write(ocelot,
 | |
| +		     control_list->time_interval,
 | |
| +		     QSYS_GCL_CFG_REG_2);
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +static u32 tas_read_status(struct ocelot *ocelot)
 | |
| +{
 | |
| +	u32 val;
 | |
| +
 | |
| +	val = ocelot_read(ocelot, QSYS_TAS_PARAM_CFG_CTRL);
 | |
| +
 | |
| +	return val;
 | |
| +}
 | |
| +
 | |
| +int ocelot_qbv_set(struct ocelot *ocelot, int port_id,
 | |
| +		   struct tsn_qbv_conf *shaper_config)
 | |
| +{
 | |
| +	struct tsn_qbv_basic *admin_basic = &shaper_config->admin;
 | |
| +	struct tsn_qbv_entry *control_list = admin_basic->control_list;
 | |
| +	u32 base_time_nsec = admin_basic->base_time % 1000000000;
 | |
| +	u64 base_time_sec = admin_basic->base_time / 1000000000;
 | |
| +	u64 cur_time;
 | |
| +	u32 val;
 | |
| +	u8 speed;
 | |
| +	int i;
 | |
| +	int ret;
 | |
| +
 | |
| +	if (admin_basic->control_list_length > capa.num_tas_gcl) {
 | |
| +		dev_err(ocelot->dev,
 | |
| +			"Invalid admin_control_list_length %u\n",
 | |
| +			admin_basic->control_list_length);
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +
 | |
| +	if ((admin_basic->cycle_time < capa.tas_ct_min ||
 | |
| +	     admin_basic->cycle_time > capa.tas_ct_max) &&
 | |
| +	    shaper_config->gate_enabled) {
 | |
| +		dev_err(ocelot->dev, "Invalid admin_cycle_time %u ns\n",
 | |
| +			admin_basic->cycle_time);
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +	if (admin_basic->cycle_time_extension > capa.tas_cte_max) {
 | |
| +		dev_err(ocelot->dev,
 | |
| +			"Invalid admin_cycle_time_extension %u\n",
 | |
| +			admin_basic->cycle_time_extension);
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +
 | |
| +	cur_time = ocelot_read(ocelot, PTP_CUR_SEC_MSB);
 | |
| +	cur_time = cur_time << 32;
 | |
| +	cur_time += ocelot_read(ocelot, PTP_CUR_SEC_LSB);
 | |
| +
 | |
| +	if (base_time_sec < cur_time) {
 | |
| +		base_time_sec = cur_time;
 | |
| +		base_time_nsec = ocelot_read(ocelot, PTP_CUR_NSEC);
 | |
| +	}
 | |
| +
 | |
| +	/* Select port */
 | |
| +	ocelot_rmw(ocelot,
 | |
| +		   QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM(port_id),
 | |
| +		   QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM_M,
 | |
| +		   QSYS_TAS_PARAM_CFG_CTRL);
 | |
| +
 | |
| +	val = ocelot_read(ocelot, QSYS_PARAM_STATUS_REG_8);
 | |
| +	if (val & QSYS_PARAM_STATUS_REG_8_CONFIG_PENDING) {
 | |
| +		ocelot_rmw_rix(ocelot, 0, QSYS_TAG_CONFIG_ENABLE,
 | |
| +			       QSYS_TAG_CONFIG, port_id);
 | |
| +	}
 | |
| +
 | |
| +	if (!shaper_config->gate_enabled)
 | |
| +		admin_basic->gate_states = 0xff;
 | |
| +
 | |
| +	val = ocelot_read_gix(ocelot, ANA_PFC_PFC_CFG, port_id);
 | |
| +	speed = ANA_PFC_PFC_CFG_FC_LINK_SPEED(val);
 | |
| +
 | |
| +	ocelot_rmw_rix(ocelot,
 | |
| +		       (shaper_config->gate_enabled ?
 | |
| +			QSYS_TAG_CONFIG_ENABLE : 0) |
 | |
| +		       QSYS_TAG_CONFIG_INIT_GATE_STATE(admin_basic->gate_states) |
 | |
| +		       QSYS_TAG_CONFIG_SCH_TRAFFIC_QUEUES(0xff) |
 | |
| +		       QSYS_TAG_CONFIG_LINK_SPEED(speed),
 | |
| +		       QSYS_TAG_CONFIG_ENABLE |
 | |
| +		       QSYS_TAG_CONFIG_INIT_GATE_STATE_M |
 | |
| +		       QSYS_TAG_CONFIG_SCH_TRAFFIC_QUEUES_M |
 | |
| +		       QSYS_TAG_CONFIG_LINK_SPEED_M,
 | |
| +		       QSYS_TAG_CONFIG,
 | |
| +		       port_id);
 | |
| +
 | |
| +	ocelot_write_rix(ocelot, shaper_config->maxsdu,
 | |
| +			 QSYS_PORT_MAX_SDU, port_id);
 | |
| +	/* TODO: add queue max SDU set */
 | |
| +
 | |
| +	if (shaper_config->gate_enabled) {
 | |
| +		ocelot_write(ocelot, base_time_nsec,
 | |
| +			     QSYS_PARAM_CFG_REG_1);
 | |
| +
 | |
| +		ocelot_write(ocelot, base_time_sec & GENMASK(31, 0),
 | |
| +			     QSYS_PARAM_CFG_REG_2);
 | |
| +
 | |
| +		ocelot_write(ocelot,
 | |
| +			     QSYS_PARAM_CFG_REG_3_BASE_TIME_SEC_MSB(base_time_sec >> 32) |
 | |
| +			     QSYS_PARAM_CFG_REG_3_LIST_LENGTH(admin_basic->control_list_length),
 | |
| +			     QSYS_PARAM_CFG_REG_3);
 | |
| +
 | |
| +		ocelot_write(ocelot, admin_basic->cycle_time,
 | |
| +			     QSYS_PARAM_CFG_REG_4);
 | |
| +
 | |
| +		ocelot_write(ocelot, admin_basic->cycle_time_extension,
 | |
| +			     QSYS_PARAM_CFG_REG_5);
 | |
| +
 | |
| +		for (i = 0; i < admin_basic->control_list_length; i++) {
 | |
| +			qos_port_tas_gcl_set(ocelot, i, control_list);
 | |
| +			control_list++;
 | |
| +		}
 | |
| +
 | |
| +		/* Start configuration change */
 | |
| +		ocelot_rmw(ocelot,
 | |
| +			   QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE,
 | |
| +			   QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE,
 | |
| +			   QSYS_TAS_PARAM_CFG_CTRL);
 | |
| +
 | |
| +		ret = readx_poll_timeout(tas_read_status, ocelot, val,
 | |
| +					 !(QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE
 | |
| +					 & val), 10, 100000);
 | |
| +		return ret;
 | |
| +	}
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +int ocelot_qbv_get(struct ocelot *ocelot, int port_id,
 | |
| +		   struct tsn_qbv_conf *shaper_config)
 | |
| +{
 | |
| +	u32 val, reg;
 | |
| +	int i;
 | |
| +	u32 base_timel;
 | |
| +	u32 base_timeh;
 | |
| +	struct tsn_qbv_basic *admin = &shaper_config->admin;
 | |
| +	struct tsn_qbv_entry *list;
 | |
| +
 | |
| +	ocelot_rmw(ocelot,
 | |
| +		   QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM(port_id),
 | |
| +		   QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM_M,
 | |
| +		   QSYS_TAS_PARAM_CFG_CTRL);
 | |
| +
 | |
| +	val = ocelot_read_rix(ocelot, QSYS_TAG_CONFIG, port_id);
 | |
| +	shaper_config->gate_enabled = (val & QSYS_TAG_CONFIG_ENABLE);
 | |
| +	admin->gate_states = QSYS_TAG_CONFIG_INIT_GATE_STATE_X(val);
 | |
| +
 | |
| +	base_timel = ocelot_read(ocelot, QSYS_PARAM_CFG_REG_1);
 | |
| +	base_timeh = ocelot_read(ocelot, QSYS_PARAM_CFG_REG_2);
 | |
| +	reg = ocelot_read(ocelot, QSYS_PARAM_CFG_REG_3);
 | |
| +	admin->base_time = base_timeh |
 | |
| +		(((u64)QSYS_PARAM_CFG_REG_3_BASE_TIME_SEC_MSB(reg)) << 32);
 | |
| +
 | |
| +	admin->base_time = (admin->base_time * 1000000000) + base_timel;
 | |
| +
 | |
| +	admin->control_list_length =
 | |
| +		QSYS_PARAM_CFG_REG_3_LIST_LENGTH_X(reg);
 | |
| +
 | |
| +	admin->cycle_time = ocelot_read(ocelot, QSYS_PARAM_CFG_REG_4);
 | |
| +	admin->cycle_time_extension =
 | |
| +		ocelot_read(ocelot, QSYS_PARAM_CFG_REG_5);
 | |
| +
 | |
| +	list = kmalloc_array(admin->control_list_length,
 | |
| +			     sizeof(struct tsn_qbv_entry), GFP_KERNEL);
 | |
| +	admin->control_list = list;
 | |
| +
 | |
| +	for (i = 0; i < admin->control_list_length; i++) {
 | |
| +		ocelot_rmw(ocelot,
 | |
| +			   QSYS_GCL_CFG_REG_1_GCL_ENTRY_NUM(i),
 | |
| +			   QSYS_GCL_CFG_REG_1_GCL_ENTRY_NUM_M,
 | |
| +			   QSYS_GCL_CFG_REG_1);
 | |
| +
 | |
| +		list->time_interval =
 | |
| +			ocelot_read(ocelot, QSYS_GCL_CFG_REG_2);
 | |
| +
 | |
| +		reg = ocelot_read(ocelot, QSYS_GCL_CFG_REG_1);
 | |
| +		list->gate_state = QSYS_GCL_CFG_REG_1_GATE_STATE_X(reg);
 | |
| +
 | |
| +		list++;
 | |
| +	}
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +static int qbv_get_gatelist(struct ocelot *ocelot,
 | |
| +			    struct tsn_qbv_basic *oper)
 | |
| +{
 | |
| +	u32 base_timel;
 | |
| +	u32 base_timeh;
 | |
| +	u32 val;
 | |
| +	struct tsn_qbv_entry *glist;
 | |
| +	int i;
 | |
| +
 | |
| +	base_timel = ocelot_read(ocelot, QSYS_PARAM_STATUS_REG_1);
 | |
| +	base_timeh = ocelot_read(ocelot, QSYS_PARAM_STATUS_REG_2);
 | |
| +	val = ocelot_read(ocelot, QSYS_PARAM_STATUS_REG_3);
 | |
| +	oper->base_time = base_timeh;
 | |
| +	oper->base_time +=
 | |
| +		((u64)QSYS_PARAM_STATUS_REG_3_BASE_TIME_SEC_MSB(val)) <<
 | |
| +		32;
 | |
| +	oper->base_time = (oper->base_time * 1000000000) + base_timel;
 | |
| +
 | |
| +	oper->control_list_length =
 | |
| +		QSYS_PARAM_STATUS_REG_3_LIST_LENGTH_X(val);
 | |
| +
 | |
| +	oper->cycle_time = ocelot_read(ocelot, QSYS_PARAM_STATUS_REG_4);
 | |
| +	oper->cycle_time_extension = ocelot_read(ocelot,
 | |
| +						 QSYS_PARAM_STATUS_REG_5);
 | |
| +
 | |
| +	val = ocelot_read(ocelot, QSYS_PARAM_STATUS_REG_8);
 | |
| +	oper->gate_states = QSYS_PARAM_STATUS_REG_8_OPER_GATE_STATE_X(val);
 | |
| +
 | |
| +	glist = kmalloc_array(oper->control_list_length,
 | |
| +			      sizeof(struct tsn_qbv_entry), GFP_KERNEL);
 | |
| +
 | |
| +	oper->control_list = glist;
 | |
| +
 | |
| +	for (i = 0; i < oper->control_list_length; i++) {
 | |
| +		ocelot_rmw(ocelot,
 | |
| +			   QSYS_GCL_STATUS_REG_1_GCL_ENTRY_NUM(i),
 | |
| +			   QSYS_GCL_STATUS_REG_1_GCL_ENTRY_NUM_M,
 | |
| +			   QSYS_GCL_STATUS_REG_1);
 | |
| +
 | |
| +		val = ocelot_read(ocelot, QSYS_GCL_STATUS_REG_2);
 | |
| +		glist->time_interval = val;
 | |
| +		val = ocelot_read(ocelot, QSYS_GCL_STATUS_REG_1);
 | |
| +		glist->gate_state =
 | |
| +			QSYS_GCL_STATUS_REG_1_GATE_STATE_X(val);
 | |
| +
 | |
| +		glist++;
 | |
| +	}
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +int ocelot_qbv_get_status(struct ocelot *ocelot, int port_id,
 | |
| +			  struct tsn_qbv_status *qbvstatus)
 | |
| +{
 | |
| +	struct tsn_qbv_basic *oper = &qbvstatus->oper;
 | |
| +	u32 val;
 | |
| +	ptptime_t cur_time;
 | |
| +
 | |
| +	ocelot_rmw(ocelot,
 | |
| +		   QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM(port_id),
 | |
| +		   QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM_M,
 | |
| +		   QSYS_TAS_PARAM_CFG_CTRL);
 | |
| +
 | |
| +	qbvstatus->supported_list_max = capa.num_tas_gcl;
 | |
| +
 | |
| +	val = ocelot_read(ocelot, QSYS_PARAM_STATUS_REG_8);
 | |
| +	qbvstatus->config_pending =
 | |
| +		(val & QSYS_PARAM_STATUS_REG_8_CONFIG_PENDING) ? 1 : 0;
 | |
| +
 | |
| +	qbvstatus->config_change_time =
 | |
| +		ocelot_read(ocelot, QSYS_PARAM_STATUS_REG_7);
 | |
| +
 | |
| +	qbvstatus->config_change_time +=
 | |
| +		((u64)QSYS_PARAM_STATUS_REG_8_CFG_CHG_TIME_SEC_MSB(val)) <<
 | |
| +		32;
 | |
| +
 | |
| +	qbvstatus->config_change_time =
 | |
| +		(qbvstatus->config_change_time * 1000000000) +
 | |
| +		ocelot_read(ocelot, QSYS_PARAM_STATUS_REG_6);
 | |
| +
 | |
| +	qbvstatus->config_change_error =
 | |
| +		ocelot_read(ocelot, QSYS_PARAM_STATUS_REG_9);
 | |
| +
 | |
| +	cur_time = ocelot_read(ocelot, PTP_CUR_SEC_MSB);
 | |
| +	cur_time = cur_time << 32;
 | |
| +	cur_time += ocelot_read(ocelot, PTP_CUR_SEC_LSB);
 | |
| +	cur_time = (cur_time * 1000000000) +
 | |
| +		   ocelot_read(ocelot, PTP_CUR_NSEC);
 | |
| +
 | |
| +	qbvstatus->current_time = cur_time;
 | |
| +	qbv_get_gatelist(ocelot, oper);
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +int ocelot_cut_thru_set(struct ocelot *ocelot, int port_id, u8 cut_thru)
 | |
| +{
 | |
| +	ocelot_write_rix(ocelot, cut_thru, ANA_CUT_THRU_CFG, port_id);
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +static int qos_shaper_conf_set(struct ocelot *ocelot, int port,
 | |
| +			       u32 port_ix, u8 percent)
 | |
| +{
 | |
| +	u32 val;
 | |
| +	int speed;
 | |
| +	u32 cbs = 0;
 | |
| +	u32 cir = 0;
 | |
| +
 | |
| +	if (percent > 100) {
 | |
| +		dev_err(ocelot->dev, "percentage %d larger than 100\n",
 | |
| +			percent);
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +	if (port_ix >= capa.num_hsch) {
 | |
| +		dev_err(ocelot->dev,
 | |
| +			"CIR_CFG: id %d is exceed num of HSCH instance\n",
 | |
| +			port_ix);
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +
 | |
| +	val = ocelot_read_gix(ocelot, ANA_PFC_PFC_CFG, port);
 | |
| +	speed = ANA_PFC_PFC_CFG_FC_LINK_SPEED(val);
 | |
| +	switch (speed) {
 | |
| +	case OCELOT_SPEED_10:
 | |
| +		cir = 10000;
 | |
| +		break;
 | |
| +	case OCELOT_SPEED_100:
 | |
| +		cir = 100000;
 | |
| +		break;
 | |
| +	case OCELOT_SPEED_1000:
 | |
| +		cir = 1000000;
 | |
| +		break;
 | |
| +	case OCELOT_SPEED_2500:
 | |
| +		cir = 2500000;
 | |
| +		break;
 | |
| +	}
 | |
| +
 | |
| +	cir = cir * percent / 100;
 | |
| +	cir = DIV_ROUND_UP(cir, 100);  /* Rate unit is 100 kbps */
 | |
| +	cir = (cir ? cir : 1);              /* Avoid using zero rate */
 | |
| +	cbs = DIV_ROUND_UP(cbs, 4096); /* Burst unit is 4kB */
 | |
| +	cbs = (cbs ? cbs : 1);		/* Avoid using zero burst size */
 | |
| +	cir = min_t(u32, GENMASK(15, 0), cir);
 | |
| +	cbs = min_t(u32, GENMASK(6, 0), cbs);
 | |
| +	ocelot_write_gix(ocelot,
 | |
| +			 QSYS_CIR_CFG_CIR_RATE(cir) |
 | |
| +			 QSYS_CIR_CFG_CIR_BURST(cbs),
 | |
| +			 QSYS_CIR_CFG,
 | |
| +			 port_ix);
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +static int qos_shaper_conf_get(struct ocelot *ocelot, int port,
 | |
| +			       u32 port_ix)
 | |
| +{
 | |
| +	u32 val;
 | |
| +	u32 bandwidth = 0;
 | |
| +	u32 cir = 0;
 | |
| +	int percentage;
 | |
| +	int speed;
 | |
| +
 | |
| +	if (port_ix >= capa.num_hsch) {
 | |
| +		dev_err(ocelot->dev,
 | |
| +			"CIR_CFG: id %d is exceed num of HSCH instance\n",
 | |
| +			port_ix);
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +
 | |
| +	val = ocelot_read_gix(ocelot, ANA_PFC_PFC_CFG, port);
 | |
| +	speed = ANA_PFC_PFC_CFG_FC_LINK_SPEED(val);
 | |
| +	switch (speed) {
 | |
| +	case OCELOT_SPEED_10:
 | |
| +		bandwidth = 10000;
 | |
| +		break;
 | |
| +	case OCELOT_SPEED_100:
 | |
| +		bandwidth = 100000;
 | |
| +		break;
 | |
| +	case OCELOT_SPEED_1000:
 | |
| +		bandwidth = 1000000;
 | |
| +		break;
 | |
| +	case OCELOT_SPEED_2500:
 | |
| +		bandwidth = 2500000;
 | |
| +		break;
 | |
| +	}
 | |
| +
 | |
| +	val = ocelot_read_gix(ocelot, QSYS_CIR_CFG, port_ix);
 | |
| +
 | |
| +	cir = QSYS_CIR_CFG_CIR_RATE_X(val);
 | |
| +	cir *= 100;
 | |
| +	percentage = cir * 100 / bandwidth;
 | |
| +
 | |
| +	return percentage;
 | |
| +}
 | |
| +
 | |
| +int ocelot_cbs_set(struct ocelot *ocelot, int port, u8 tc, u8 bw)
 | |
| +{
 | |
| +	if (tc > capa.qos_cos_max) {
 | |
| +		dev_err(ocelot->dev, "Invalid tc: %u\n", tc);
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +
 | |
| +	qos_shaper_conf_set(ocelot, port, port * 8 + tc, bw);
 | |
| +
 | |
| +	ocelot_rmw_gix(ocelot,
 | |
| +		       QSYS_SE_CFG_SE_AVB_ENA,
 | |
| +		       QSYS_SE_CFG_SE_AVB_ENA,
 | |
| +		       QSYS_SE_CFG,
 | |
| +		       port * 8 + tc);
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +int ocelot_cbs_get(struct ocelot *ocelot, int port, u8 tc)
 | |
| +{
 | |
| +	int ret;
 | |
| +
 | |
| +	if (tc > capa.qos_cos_max) {
 | |
| +		dev_err(ocelot->dev, "Invalid tc: %u\n", tc);
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +
 | |
| +	ret = qos_shaper_conf_get(ocelot, port, port * 8 + tc);
 | |
| +
 | |
| +	return ret;
 | |
| +}
 | |
| +
 | |
| +int ocelot_qbu_set(struct ocelot *ocelot, int port, u8 preemptible)
 | |
| +{
 | |
| +	struct ocelot_port *ocelot_port = ocelot->ports[port];
 | |
| +
 | |
| +	ocelot_port_rmwl(ocelot_port,
 | |
| +			 DEV_GMII_MM_CONFIG_ENABLE_CONFIG_MM_RX_ENA |
 | |
| +			 DEV_GMII_MM_CONFIG_ENABLE_CONFIG_MM_TX_ENA,
 | |
| +			 DEV_GMII_MM_CONFIG_ENABLE_CONFIG_MM_RX_ENA |
 | |
| +			 DEV_GMII_MM_CONFIG_ENABLE_CONFIG_MM_TX_ENA,
 | |
| +			 DEV_GMII_MM_CONFIG_ENABLE_CONFIG);
 | |
| +
 | |
| +	ocelot_rmw_rix(ocelot,
 | |
| +		       QSYS_PREEMPTION_CFG_P_QUEUES(preemptible),
 | |
| +		       QSYS_PREEMPTION_CFG_P_QUEUES_M,
 | |
| +		       QSYS_PREEMPTION_CFG,
 | |
| +		       port);
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +int ocelot_qbu_get(struct ocelot *ocelot, int port,
 | |
| +		   struct tsn_preempt_status *c)
 | |
| +{
 | |
| +	struct ocelot_port *ocelot_port = ocelot->ports[port];
 | |
| +	u32 val;
 | |
| +
 | |
| +	val = ocelot_read_rix(ocelot,
 | |
| +			      QSYS_PREEMPTION_CFG,
 | |
| +			      port);
 | |
| +
 | |
| +	c->admin_state = QSYS_PREEMPTION_CFG_P_QUEUES(val);
 | |
| +	c->hold_advance = QSYS_PREEMPTION_CFG_HOLD_ADVANCE_X(val);
 | |
| +
 | |
| +	val = ocelot_port_readl(ocelot_port,
 | |
| +				DEV_GMII_MM_STATISTICS_MM_STATUS);
 | |
| +	c->preemption_active =
 | |
| +		DEV_GMII_MM_STATISTICS_MM_STATUS_PRMPT_ACTIVE_STATUS & val;
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +int ocelot_cb_streamid_get(struct ocelot *ocelot, int port, u32 index,
 | |
| +			   struct tsn_cb_streamid *streamid)
 | |
| +{
 | |
| +	u32 m_index;
 | |
| +	u32 bucket;
 | |
| +	u32 val, dst, reg;
 | |
| +	u64 dmac;
 | |
| +	u32 ldmac, hdmac;
 | |
| +
 | |
| +	if (index >= MSCC_STREAM_HANDLE_NUM) {
 | |
| +		dev_err(ocelot->dev,
 | |
| +			"Invalid stream handle %u, maximum:%u\n",
 | |
| +			index, MSCC_STREAM_HANDLE_NUM - 1);
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +
 | |
| +	index = streamhandle_map[index];
 | |
| +	m_index = index / 4;
 | |
| +	bucket =  index % 4;
 | |
| +	streamid->type = 1;
 | |
| +	regmap_field_write(ocelot->regfields[ANA_TABLES_MACTINDX_BUCKET],
 | |
| +			   bucket);
 | |
| +	regmap_field_write(ocelot->regfields[ANA_TABLES_MACTINDX_M_INDEX],
 | |
| +			   m_index);
 | |
| +
 | |
| +	/*READ command MACACCESS.VALID(11 bit) must be 0 */
 | |
| +	ocelot_write(ocelot,
 | |
| +		     ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_READ),
 | |
| +		     ANA_TABLES_MACACCESS);
 | |
| +
 | |
| +	val = ocelot_read(ocelot, ANA_TABLES_MACACCESS);
 | |
| +	dst = ANA_TABLES_MACACCESS_DEST_IDX_X(val);
 | |
| +	reg = ocelot_read_rix(ocelot, ANA_PGID_PGID, dst);
 | |
| +	streamid->ofac_oport = ANA_PGID_PGID_PGID(reg);
 | |
| +
 | |
| +	/*Get the entry's MAC address and VLAN id*/
 | |
| +	ldmac = ocelot_read(ocelot, ANA_TABLES_MACLDATA);
 | |
| +	val = ocelot_read(ocelot, ANA_TABLES_MACHDATA);
 | |
| +	val &= 0x1fffffff;
 | |
| +	hdmac = val & 0xffff;
 | |
| +	dmac = hdmac;
 | |
| +	dmac = (dmac << 32) | ldmac;
 | |
| +	streamid->para.nid.dmac = dmac;
 | |
| +
 | |
| +	streamid->para.nid.vid = ANA_TABLES_MACHDATA_VID_X(val);
 | |
| +
 | |
| +	val = ocelot_read(ocelot, ANA_TABLES_STREAMDATA);
 | |
| +	if (!(val & ANA_TABLES_STREAMDATA_SFID_VALID))
 | |
| +		return -EINVAL;
 | |
| +
 | |
| +	streamid->handle = ANA_TABLES_STREAMDATA_SFID(val);
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +static int lookup_mactable(struct ocelot *ocelot, u16 vid, u64 mac)
 | |
| +{
 | |
| +	u32 mach, macl;
 | |
| +	u32 reg1, reg2;
 | |
| +	u32 index, bucket;
 | |
| +
 | |
| +	macl = mac & 0xffffffff;
 | |
| +	mach = (mac >> 32) & 0xffff;
 | |
| +	ocelot_write(ocelot, macl, ANA_TABLES_MACLDATA);
 | |
| +	ocelot_write(ocelot, ANA_TABLES_MACHDATA_VID(vid) |
 | |
| +		     ANA_TABLES_MACHDATA_MACHDATA(mach),
 | |
| +		     ANA_TABLES_MACHDATA);
 | |
| +
 | |
| +	ocelot_write(ocelot, ANA_TABLES_MACACCESS_VALID |
 | |
| +		     ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_READ),
 | |
| +		     ANA_TABLES_MACACCESS);
 | |
| +
 | |
| +	reg1 = ocelot_read(ocelot, ANA_TABLES_MACLDATA);
 | |
| +	reg2 = ocelot_read(ocelot, ANA_TABLES_MACHDATA);
 | |
| +	if (reg1 == 0 && reg2 == 0)
 | |
| +		return -1;
 | |
| +
 | |
| +	regmap_field_read(ocelot->regfields[ANA_TABLES_MACTINDX_BUCKET],
 | |
| +			  &bucket);
 | |
| +	regmap_field_read(ocelot->regfields[ANA_TABLES_MACTINDX_M_INDEX],
 | |
| +			  &index);
 | |
| +
 | |
| +	index = index * 4 + bucket;
 | |
| +
 | |
| +	return index;
 | |
| +}
 | |
| +
 | |
| +int ocelot_cb_streamid_set(struct ocelot *ocelot, int port,
 | |
| +			   u32 index, bool enable,
 | |
| +			   struct tsn_cb_streamid *streamid)
 | |
| +{
 | |
| +	struct regmap_field *rf;
 | |
| +	u16 vid;
 | |
| +	u64 mac;
 | |
| +	u32 macl, mach;
 | |
| +	u32 dst_idx;
 | |
| +	int idx;
 | |
| +	u32 reg;
 | |
| +	int sfid, ssid;
 | |
| +	u32 m_index, bucket;
 | |
| +
 | |
| +	if (!enable) {
 | |
| +		if (index >= MSCC_STREAM_HANDLE_NUM) {
 | |
| +			dev_err(ocelot->dev,
 | |
| +				"Invalid index %u, maximum:%u\n",
 | |
| +				index, MSCC_STREAM_HANDLE_NUM - 1);
 | |
| +			return -EINVAL;
 | |
| +		}
 | |
| +		m_index = streamhandle_map[index] / 4;
 | |
| +		bucket =  streamhandle_map[index] % 4;
 | |
| +		rf = ocelot->regfields[ANA_TABLES_MACTINDX_BUCKET];
 | |
| +		regmap_field_write(rf, bucket);
 | |
| +		rf = ocelot->regfields[ANA_TABLES_MACTINDX_M_INDEX];
 | |
| +		regmap_field_write(rf, m_index);
 | |
| +
 | |
| +		/*READ command MACACCESS.VALID(11 bit) must be 0 */
 | |
| +		ocelot_write(ocelot,
 | |
| +			     ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_READ),
 | |
| +			     ANA_TABLES_MACACCESS);
 | |
| +
 | |
| +		ocelot_write(ocelot,
 | |
| +			     ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_FORGET),
 | |
| +			     ANA_TABLES_MACACCESS);
 | |
| +
 | |
| +		streamhandle_map[index] = 0;
 | |
| +
 | |
| +		return 0;
 | |
| +	}
 | |
| +
 | |
| +	if (streamid->type != 1) {
 | |
| +		dev_err(ocelot->dev, "Invalid stream type\n");
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +
 | |
| +	if (streamid->handle >= MSCC_STREAM_HANDLE_NUM) {
 | |
| +		dev_err(ocelot->dev,
 | |
| +			"Invalid stream handle %u, maximum:%u\n",
 | |
| +			streamid->handle, MSCC_STREAM_HANDLE_NUM - 1);
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +
 | |
| +	sfid = streamid->handle;
 | |
| +	ssid = (streamid->handle < MSCC_FRER_SSID_NUM ?
 | |
| +		streamid->handle : (MSCC_FRER_SSID_NUM - 1));
 | |
| +
 | |
| +	mac = streamid->para.nid.dmac;
 | |
| +	macl = mac & 0xffffffff;
 | |
| +	mach = (mac >> 32) & 0xffff;
 | |
| +	vid = streamid->para.nid.vid;
 | |
| +
 | |
| +	idx = lookup_mactable(ocelot, vid, mac);
 | |
| +
 | |
| +	if (idx < 0) {
 | |
| +		ocelot_write(ocelot, macl, ANA_TABLES_MACLDATA);
 | |
| +		ocelot_write(ocelot, ANA_TABLES_MACHDATA_VID(vid) |
 | |
| +			     ANA_TABLES_MACHDATA_MACHDATA(mach),
 | |
| +			     ANA_TABLES_MACHDATA);
 | |
| +
 | |
| +		ocelot_write(ocelot,
 | |
| +			     ANA_TABLES_STREAMDATA_SFID_VALID |
 | |
| +			     ANA_TABLES_STREAMDATA_SFID(sfid) |
 | |
| +			     ANA_TABLES_STREAMDATA_SSID_VALID |
 | |
| +			     ANA_TABLES_STREAMDATA_SSID(ssid),
 | |
| +			     ANA_TABLES_STREAMDATA);
 | |
| +
 | |
| +		dst_idx = port;
 | |
| +		ocelot_write(ocelot, ANA_TABLES_MACACCESS_VALID |
 | |
| +			     ANA_TABLES_MACACCESS_ENTRYTYPE(1) |
 | |
| +			     ANA_TABLES_MACACCESS_DEST_IDX(dst_idx) |
 | |
| +			     ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_LEARN),
 | |
| +			     ANA_TABLES_MACACCESS);
 | |
| +
 | |
| +		ocelot_write(ocelot, ANA_TABLES_MACACCESS_VALID |
 | |
| +			     ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_READ),
 | |
| +			     ANA_TABLES_MACACCESS);
 | |
| +
 | |
| +		regmap_field_read(ocelot->regfields[ANA_TABLES_MACTINDX_BUCKET],
 | |
| +				  &bucket);
 | |
| +		regmap_field_read(ocelot->regfields[ANA_TABLES_MACTINDX_M_INDEX],
 | |
| +				  &m_index);
 | |
| +
 | |
| +		m_index = m_index * 4 + bucket;
 | |
| +		streamhandle_map[streamid->handle] = m_index;
 | |
| +
 | |
| +		return 0;
 | |
| +	}
 | |
| +
 | |
| +	ocelot_write(ocelot,
 | |
| +		     ANA_TABLES_STREAMDATA_SFID_VALID |
 | |
| +		     ANA_TABLES_STREAMDATA_SFID(sfid) |
 | |
| +		     ANA_TABLES_STREAMDATA_SSID_VALID |
 | |
| +		     ANA_TABLES_STREAMDATA_SSID(ssid),
 | |
| +		     ANA_TABLES_STREAMDATA);
 | |
| +
 | |
| +	reg = ocelot_read(ocelot, ANA_TABLES_MACACCESS);
 | |
| +	dst_idx = ANA_TABLES_MACACCESS_DEST_IDX_X(reg);
 | |
| +	ocelot_write(ocelot, ANA_TABLES_MACACCESS_VALID |
 | |
| +		     ANA_TABLES_MACACCESS_ENTRYTYPE(1) |
 | |
| +		     ANA_TABLES_MACACCESS_DEST_IDX(dst_idx) |
 | |
| +		     ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_WRITE),
 | |
| +		     ANA_TABLES_MACACCESS);
 | |
| +
 | |
| +	streamhandle_map[streamid->handle] = idx;
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +static int streamid_multi_forward_set(struct ocelot *ocelot, u32 index,
 | |
| +				      u8 fwdmask)
 | |
| +{
 | |
| +	u32 m_index;
 | |
| +	u32 bucket;
 | |
| +	u32 val;
 | |
| +	int m, n, i;
 | |
| +	u8 pgid_val, fwdport;
 | |
| +	u32 dst_idx;
 | |
| +
 | |
| +	m_index = index / 4;
 | |
| +	bucket =  index % 4;
 | |
| +
 | |
| +	regmap_field_write(ocelot->regfields[ANA_TABLES_MACTINDX_BUCKET],
 | |
| +			   bucket);
 | |
| +	regmap_field_write(ocelot->regfields[ANA_TABLES_MACTINDX_M_INDEX],
 | |
| +			   m_index);
 | |
| +
 | |
| +	/*READ command MACACCESS.VALID(11 bit) must be 0 */
 | |
| +	ocelot_write(ocelot,
 | |
| +		     ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_READ),
 | |
| +		     ANA_TABLES_MACACCESS);
 | |
| +
 | |
| +	val = ocelot_read(ocelot, ANA_TABLES_MACACCESS);
 | |
| +	fwdport = ANA_TABLES_MACACCESS_DEST_IDX_X(val);
 | |
| +
 | |
| +	if (fwdport >= MSCC_NUM_OUT_PORT) {
 | |
| +		dst_idx = fwdport;
 | |
| +		return 0;
 | |
| +	}
 | |
| +
 | |
| +	fwdmask |= (1 << fwdport);
 | |
| +
 | |
| +	m = ocelot->num_phys_ports - 1;
 | |
| +	for (i = m; i >= MSCC_NUM_OUT_PORT; i--) {
 | |
| +		if (fwdmask & (1 << i)) {
 | |
| +			dst_idx = PGID_MCRED +
 | |
| +				  (m - i) * MSCC_NUM_OUT_PORT +
 | |
| +				  fwdport;
 | |
| +
 | |
| +			pgid_val = (1 << i) | (1 << fwdport);
 | |
| +			break;
 | |
| +		}
 | |
| +	}
 | |
| +
 | |
| +	if (i < MSCC_NUM_OUT_PORT) {
 | |
| +		m = PGID_MCRED +
 | |
| +		    (ocelot->num_phys_ports - MSCC_NUM_OUT_PORT) *
 | |
| +		    MSCC_NUM_OUT_PORT;
 | |
| +
 | |
| +		for (; i > 0; i--) {
 | |
| +			if (fwdmask & (1 << i))
 | |
| +				break;
 | |
| +
 | |
| +			m = m + (1 << i) - 1;
 | |
| +		}
 | |
| +		n = fwdmask & ((1 << i) - 1);
 | |
| +		if (n) {
 | |
| +			dst_idx = m + n;
 | |
| +			pgid_val = fwdmask & ((1 << MSCC_NUM_OUT_PORT) - 1);
 | |
| +		} else {
 | |
| +			dst_idx = fwdport;
 | |
| +		}
 | |
| +	}
 | |
| +
 | |
| +	if (dst_idx < PGID_MCRED)
 | |
| +		return 0;
 | |
| +
 | |
| +	ocelot_write(ocelot, ANA_TABLES_MACACCESS_VALID |
 | |
| +		     ANA_TABLES_MACACCESS_ENTRYTYPE(1) |
 | |
| +		     ANA_TABLES_MACACCESS_DEST_IDX(dst_idx) |
 | |
| +		     ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_WRITE),
 | |
| +		     ANA_TABLES_MACACCESS);
 | |
| +
 | |
| +	ocelot_write_rix(ocelot, pgid_val, ANA_PGID_PGID, dst_idx);
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +int ocelot_qci_sfi_get(struct ocelot *ocelot, int port, u32 index,
 | |
| +		       struct tsn_qci_psfp_sfi_conf *sfi)
 | |
| +{
 | |
| +	u32 val, reg, fmeter_id, max_sdu;
 | |
| +	u32 sfid = index;
 | |
| +
 | |
| +	if (sfid >= capa.num_psfp_sfid) {
 | |
| +		dev_err(ocelot->dev, "Invalid index %u, maximum:%u\n",
 | |
| +			sfid, capa.num_psfp_sfid);
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +
 | |
| +	ocelot_rmw(ocelot,
 | |
| +		   ANA_TABLES_SFIDTIDX_SFID_INDEX(sfid),
 | |
| +		   ANA_TABLES_SFIDTIDX_SFID_INDEX_M,
 | |
| +		   ANA_TABLES_SFIDTIDX);
 | |
| +
 | |
| +	ocelot_write(ocelot,
 | |
| +		     ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(SFIDACCESS_CMD_READ),
 | |
| +		     ANA_TABLES_SFIDACCESS);
 | |
| +
 | |
| +	val = ocelot_read(ocelot, ANA_TABLES_SFIDTIDX);
 | |
| +	if (!(val & ANA_TABLES_SFIDTIDX_SGID_VALID))
 | |
| +		return -EINVAL;
 | |
| +
 | |
| +	sfi->stream_gate_instance_id = ANA_TABLES_SFIDTIDX_SGID_X(val);
 | |
| +	fmeter_id = ANA_TABLES_SFIDTIDX_POL_IDX_X(val);
 | |
| +	sfi->stream_filter.flow_meter_instance_id = fmeter_id;
 | |
| +
 | |
| +	reg = ocelot_read(ocelot, ANA_TABLES_SFIDACCESS);
 | |
| +	max_sdu = ANA_TABLES_SFIDACCESS_MAX_SDU_LEN_X(reg);
 | |
| +	sfi->stream_filter.maximum_sdu_size  = max_sdu;
 | |
| +
 | |
| +	if (reg & ANA_TABLES_SFIDACCESS_IGR_PRIO_MATCH_ENA)
 | |
| +		sfi->priority_spec = ANA_TABLES_SFIDACCESS_IGR_PRIO_X(reg);
 | |
| +	else
 | |
| +		dev_err(ocelot->dev, "priority not enable\n");
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +int ocelot_qci_sfi_set(struct ocelot *ocelot, int port,
 | |
| +		       u32 index, bool enable,
 | |
| +		       struct tsn_qci_psfp_sfi_conf *sfi)
 | |
| +{
 | |
| +	int igr_prio = sfi->priority_spec;
 | |
| +	u16 sgid  = sfi->stream_gate_instance_id;
 | |
| +	u16 pol_idx;
 | |
| +	int fmid = sfi->stream_filter.flow_meter_instance_id;
 | |
| +	u16 max_sdu_len = sfi->stream_filter.maximum_sdu_size;
 | |
| +	int sfid = index;
 | |
| +	u32 val;
 | |
| +
 | |
| +	if (fmid == -1)
 | |
| +		pol_idx = capa.psfp_fmi_max;
 | |
| +	else
 | |
| +		pol_idx = (u16)fmid;
 | |
| +
 | |
| +	if (sfid >= capa.num_psfp_sfid) {
 | |
| +		dev_err(ocelot->dev, "Invalid index %u, maximum:%u\n",
 | |
| +			sfid, capa.num_psfp_sfid);
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +
 | |
| +	if (!enable) {
 | |
| +		val = ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(SFIDACCESS_CMD_WRITE);
 | |
| +		ocelot_write(ocelot,
 | |
| +			     ANA_TABLES_SFIDTIDX_SFID_INDEX(sfid),
 | |
| +			     ANA_TABLES_SFIDTIDX);
 | |
| +		ocelot_write(ocelot, val, ANA_TABLES_SFIDACCESS);
 | |
| +		return 0;
 | |
| +	}
 | |
| +
 | |
| +	if (sgid >= capa.num_psfp_sgid) {
 | |
| +		dev_err(ocelot->dev, "Invalid sgid %u, maximum:%u\n",
 | |
| +			sgid, capa.num_psfp_sgid);
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +	if (pol_idx > capa.psfp_fmi_max || pol_idx < capa.psfp_fmi_min) {
 | |
| +		dev_err(ocelot->dev, "Invalid pol_idx %u, range:%d~%d\n",
 | |
| +			pol_idx, capa.psfp_fmi_min, capa.psfp_fmi_max);
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +
 | |
| +	ocelot_write(ocelot, ANA_TABLES_SFIDTIDX_SGID_VALID |
 | |
| +		     ANA_TABLES_SFIDTIDX_SGID(sgid) |
 | |
| +		     ((fmid != -1) ? ANA_TABLES_SFIDTIDX_POL_ENA : 0) |
 | |
| +		     ANA_TABLES_SFIDTIDX_POL_IDX(pol_idx) |
 | |
| +		     ANA_TABLES_SFIDTIDX_SFID_INDEX(sfid),
 | |
| +		     ANA_TABLES_SFIDTIDX);
 | |
| +
 | |
| +	ocelot_write(ocelot,
 | |
| +		     ((igr_prio >= 0) ?
 | |
| +		      ANA_TABLES_SFIDACCESS_IGR_PRIO_MATCH_ENA : 0) |
 | |
| +		     ANA_TABLES_SFIDACCESS_IGR_PRIO(igr_prio) |
 | |
| +		     ANA_TABLES_SFIDACCESS_MAX_SDU_LEN(max_sdu_len) |
 | |
| +		     ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(SFIDACCESS_CMD_WRITE),
 | |
| +		     ANA_TABLES_SFIDACCESS);
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +int ocelot_qci_sfi_counters_get(struct ocelot *ocelot, int port,
 | |
| +				u32 index,
 | |
| +				struct tsn_qci_psfp_sfi_counters *sfi_cnt)
 | |
| +{
 | |
| +	u32 sfid = index;
 | |
| +	u32 match, not_pass, not_pass_sdu, red;
 | |
| +
 | |
| +	if (sfid >= capa.num_psfp_sfid) {
 | |
| +		dev_err(ocelot->dev, "Invalid index %u, maximum:%u\n",
 | |
| +			sfid, capa.num_psfp_sfid);
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +
 | |
| +	ocelot_rmw(ocelot,
 | |
| +		   SYS_STAT_CFG_STAT_VIEW(sfid),
 | |
| +		   SYS_STAT_CFG_STAT_VIEW_M,
 | |
| +		   SYS_STAT_CFG);
 | |
| +
 | |
| +	match = ocelot_read_gix(ocelot, SYS_CNT, 0x200);
 | |
| +	not_pass = ocelot_read_gix(ocelot, SYS_CNT, 0x201);
 | |
| +	not_pass_sdu = ocelot_read_gix(ocelot, SYS_CNT, 0x202);
 | |
| +	red = ocelot_read_gix(ocelot, SYS_CNT, 0x203);
 | |
| +
 | |
| +	sfi_cnt->matching_frames_count = match;
 | |
| +	sfi_cnt->not_passing_frames_count = not_pass;
 | |
| +	sfi_cnt->not_passing_sdu_count = not_pass_sdu;
 | |
| +	sfi_cnt->red_frames_count  =  red;
 | |
| +
 | |
| +	sfi_cnt->passing_frames_count = match - not_pass;
 | |
| +	sfi_cnt->passing_sdu_count = match - not_pass - not_pass_sdu;
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +int ocelot_qci_max_cap_get(struct ocelot *ocelot,
 | |
| +			   struct tsn_qci_psfp_stream_param *stream_para)
 | |
| +{
 | |
| +	/* MaxStreamFilterInstances */
 | |
| +	stream_para->max_sf_instance = capa.num_psfp_sfid;
 | |
| +	/* MaxStreamGateInstances */
 | |
| +	stream_para->max_sg_instance = capa.num_psfp_sgid;
 | |
| +	/* MaxFlowMeterInstances */
 | |
| +	stream_para->max_fm_instance = capa.psfp_fmi_max -
 | |
| +				       capa.psfp_fmi_min + 1;
 | |
| +	/* SupportedListMax */
 | |
| +	stream_para->supported_list_max = capa.num_sgi_gcl;
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +static int sgi_set_glist(struct ocelot *ocelot,
 | |
| +			 struct tsn_qci_psfp_gcl *gcl, uint32_t num)
 | |
| +{
 | |
| +	u32 time_sum = 0;
 | |
| +	int i;
 | |
| +
 | |
| +	if (num > capa.num_sgi_gcl)
 | |
| +		return -EINVAL;
 | |
| +
 | |
| +	for (i = 0; i < num; i++) {
 | |
| +		u32 val = ANA_SG_GCL_GS_CONFIG_IPS((gcl->ipv < 0) ?
 | |
| +						   0 : gcl->ipv + 8);
 | |
| +		val |= (gcl->gate_state ? ANA_SG_GCL_GS_CONFIG_GATE_STATE : 0);
 | |
| +		ocelot_write_rix(ocelot, val, ANA_SG_GCL_GS_CONFIG, i);
 | |
| +
 | |
| +		time_sum += gcl->time_interval;
 | |
| +		ocelot_write_rix(ocelot, time_sum, ANA_SG_GCL_TI_CONFIG, i);
 | |
| +
 | |
| +		gcl++;
 | |
| +	}
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +static u32 sgi_read_status(struct ocelot *ocelot)
 | |
| +{
 | |
| +	u32 val;
 | |
| +
 | |
| +	val = ocelot_read(ocelot, ANA_SG_ACCESS_CTRL);
 | |
| +
 | |
| +	return val;
 | |
| +}
 | |
| +
 | |
| +int ocelot_qci_sgi_set(struct ocelot *ocelot, int port, u32 index,
 | |
| +		       struct tsn_qci_psfp_sgi_conf *sgi_conf)
 | |
| +{
 | |
| +	struct tsn_qci_sg_control *admin_list = &sgi_conf->admin;
 | |
| +	u32 sgid = index;
 | |
| +	u32 list_length = sgi_conf->admin.control_list_length;
 | |
| +	u32 cycle_time = sgi_conf->admin.cycle_time;
 | |
| +	u32 cycle_time_ex = sgi_conf->admin.cycle_time_extension;
 | |
| +	u32 l_basetime = sgi_conf->admin.base_time % 1000000000;
 | |
| +	u64 h_basetime = sgi_conf->admin.base_time / 1000000000;
 | |
| +	u64 cur_time;
 | |
| +	u32 val;
 | |
| +	int ret;
 | |
| +
 | |
| +	if (sgid >= capa.num_psfp_sgid) {
 | |
| +		dev_err(ocelot->dev, "Invalid sgid %u, maximum:%u\n",
 | |
| +			sgid, capa.num_psfp_sgid);
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +	if ((cycle_time < capa.sgi_ct_min ||
 | |
| +	     cycle_time > capa.sgi_ct_max) &&
 | |
| +	     sgi_conf->gate_enabled) {
 | |
| +		dev_err(ocelot->dev, "Invalid cycle_time %u ns\n",
 | |
| +			cycle_time);
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +	if (cycle_time_ex > capa.sgi_cte_max) {
 | |
| +		dev_err(ocelot->dev,
 | |
| +			"Invalid cycle_time_extension %u\n",
 | |
| +			cycle_time_ex);
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +	if (list_length > capa.num_sgi_gcl) {
 | |
| +		dev_err(ocelot->dev,
 | |
| +			"Invalid sgi_gcl len %u, maximum:%u\n",
 | |
| +			list_length, capa.num_sgi_gcl);
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +
 | |
| +	/*configure SGID*/
 | |
| +	ocelot_rmw(ocelot,
 | |
| +		   ANA_SG_ACCESS_CTRL_SGID(sgid),
 | |
| +		   ANA_SG_ACCESS_CTRL_SGID_M,
 | |
| +		   ANA_SG_ACCESS_CTRL);
 | |
| +
 | |
| +	/*Disable SG*/
 | |
| +	if (!sgi_conf->gate_enabled) {
 | |
| +		ocelot_rmw(ocelot,
 | |
| +			   ANA_SG_CONFIG_REG_3_INIT_GATE_STATE,
 | |
| +			   ANA_SG_CONFIG_REG_3_INIT_GATE_STATE |
 | |
| +			   ANA_SG_CONFIG_REG_3_GATE_ENABLE,
 | |
| +			   ANA_SG_CONFIG_REG_3);
 | |
| +		return 0;
 | |
| +	}
 | |
| +
 | |
| +	/*admin parameters*/
 | |
| +	cur_time = ocelot_read(ocelot, PTP_CUR_SEC_MSB);
 | |
| +	cur_time = cur_time << 32;
 | |
| +	cur_time += ocelot_read(ocelot, PTP_CUR_SEC_LSB);
 | |
| +	if (h_basetime < cur_time) {
 | |
| +		h_basetime = cur_time;
 | |
| +		l_basetime = ocelot_read(ocelot, PTP_CUR_NSEC);
 | |
| +	}
 | |
| +
 | |
| +	ocelot_write(ocelot, l_basetime, ANA_SG_CONFIG_REG_1);
 | |
| +	ocelot_write(ocelot, h_basetime, ANA_SG_CONFIG_REG_2);
 | |
| +
 | |
| +	ocelot_write(ocelot,
 | |
| +		     (sgi_conf->admin.init_ipv < 0 ?
 | |
| +		      0 : ANA_SG_CONFIG_REG_3_IPV_VALID) |
 | |
| +		     ANA_SG_CONFIG_REG_3_INIT_IPV(sgi_conf->admin.init_ipv) |
 | |
| +		     ANA_SG_CONFIG_REG_3_GATE_ENABLE |
 | |
| +		     ANA_SG_CONFIG_REG_3_LIST_LENGTH(list_length) |
 | |
| +		     (sgi_conf->admin.gate_states > 0 ?
 | |
| +		      ANA_SG_CONFIG_REG_3_INIT_GATE_STATE : 0) |
 | |
| +		     ANA_SG_CONFIG_REG_3_BASE_TIME_SEC_MSB(h_basetime >> 32),
 | |
| +		     ANA_SG_CONFIG_REG_3);
 | |
| +
 | |
| +	ocelot_write(ocelot, cycle_time, ANA_SG_CONFIG_REG_4);
 | |
| +	ocelot_write(ocelot, cycle_time_ex, ANA_SG_CONFIG_REG_5);
 | |
| +
 | |
| +	ret = sgi_set_glist(ocelot, admin_list->gcl, list_length);
 | |
| +	if (ret < 0)
 | |
| +		return ret;
 | |
| +
 | |
| +	/* Start configuration change */
 | |
| +	ocelot_rmw(ocelot,
 | |
| +		   ANA_SG_ACCESS_CTRL_CONFIG_CHANGE,
 | |
| +		   ANA_SG_ACCESS_CTRL_CONFIG_CHANGE,
 | |
| +		   ANA_SG_ACCESS_CTRL);
 | |
| +
 | |
| +	ret = readx_poll_timeout(sgi_read_status, ocelot, val,
 | |
| +				 (!(ANA_SG_ACCESS_CTRL_CONFIG_CHANGE & val)),
 | |
| +				 10, 100000);
 | |
| +
 | |
| +	return ret;
 | |
| +}
 | |
| +
 | |
| +static int sgi_get_glist(struct ocelot *ocelot,
 | |
| +			 struct tsn_qci_psfp_gcl *gcl,
 | |
| +			 uint32_t num)
 | |
| +{
 | |
| +	int i;
 | |
| +	u16 val;
 | |
| +	u32 time = 0;
 | |
| +	u32 reg;
 | |
| +
 | |
| +	if (num > capa.num_sgi_gcl)
 | |
| +		return -EINVAL;
 | |
| +
 | |
| +	for (i = 0; i < num; i++) {
 | |
| +		val = ocelot_read_rix(ocelot, ANA_SG_GCL_GS_CONFIG, i);
 | |
| +		gcl->gate_state = (val & ANA_SG_GCL_GS_CONFIG_GATE_STATE);
 | |
| +
 | |
| +		if (val & ANA_SG_GCL_GS_CONFIG_IPV_VALID)
 | |
| +			gcl->ipv = ANA_SG_GCL_GS_CONFIG_IPV(val);
 | |
| +		else
 | |
| +			gcl->ipv = -1;
 | |
| +
 | |
| +		reg = ocelot_read_rix(ocelot, ANA_SG_GCL_TI_CONFIG, i);
 | |
| +		gcl->time_interval = (reg - time);
 | |
| +		time = reg;
 | |
| +
 | |
| +		gcl++;
 | |
| +	}
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +int ocelot_qci_sgi_get(struct ocelot *ocelot, int port, u32 index,
 | |
| +		       struct tsn_qci_psfp_sgi_conf *sgi_conf)
 | |
| +{
 | |
| +	struct tsn_qci_sg_control *admin  = &sgi_conf->admin;
 | |
| +	struct tsn_qci_psfp_gcl *glist;
 | |
| +	u32 val, reg;
 | |
| +	u32 list_num;
 | |
| +	int ret;
 | |
| +
 | |
| +	if (index >= capa.num_psfp_sgid) {
 | |
| +		dev_err(ocelot->dev, "Invalid sgid %u, maximum:%u\n",
 | |
| +			index, capa.num_psfp_sgid);
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +
 | |
| +	ocelot_rmw(ocelot,
 | |
| +		   ANA_SG_ACCESS_CTRL_SGID(index),
 | |
| +		   ANA_SG_ACCESS_CTRL_SGID_M,
 | |
| +		   ANA_SG_ACCESS_CTRL);
 | |
| +
 | |
| +	admin->cycle_time = ocelot_read(ocelot, ANA_SG_CONFIG_REG_4);
 | |
| +	admin->cycle_time_extension =
 | |
| +		ocelot_read(ocelot, ANA_SG_CONFIG_REG_5);
 | |
| +
 | |
| +	val = ocelot_read(ocelot, ANA_SG_CONFIG_REG_2);
 | |
| +	admin->base_time = val;
 | |
| +
 | |
| +	reg = ocelot_read(ocelot, ANA_SG_CONFIG_REG_1);
 | |
| +	val = ocelot_read(ocelot, ANA_SG_CONFIG_REG_3);
 | |
| +
 | |
| +	admin->base_time +=
 | |
| +		ANA_SG_CONFIG_REG_3_BASE_TIME_SEC_MSB(val) << 32;
 | |
| +
 | |
| +	admin->base_time = admin->base_time * 1000000000 + reg;
 | |
| +
 | |
| +	if (val & ANA_SG_CONFIG_REG_3_IPV_VALID)
 | |
| +		admin->init_ipv = ANA_SG_CONFIG_REG_3_INIT_IPV_X(val);
 | |
| +	else
 | |
| +		admin->init_ipv = -1;
 | |
| +
 | |
| +	if (val & ANA_SG_CONFIG_REG_3_GATE_ENABLE)
 | |
| +		sgi_conf->gate_enabled = TRUE;
 | |
| +
 | |
| +	admin->control_list_length = ANA_SG_CONFIG_REG_3_LIST_LENGTH_X(val);
 | |
| +
 | |
| +	list_num = admin->control_list_length;
 | |
| +
 | |
| +	glist = kmalloc_array(list_num, sizeof(struct tsn_qci_psfp_gcl),
 | |
| +			      GFP_KERNEL);
 | |
| +	admin->gcl = glist;
 | |
| +
 | |
| +	ret = sgi_get_glist(ocelot, glist, list_num);
 | |
| +
 | |
| +	return ret;
 | |
| +}
 | |
| +
 | |
| +int ocelot_qci_sgi_status_get(struct ocelot *ocelot, int port, u32 index,
 | |
| +			      struct tsn_psfp_sgi_status *sgi_status)
 | |
| +{
 | |
| +	u32 val, reg;
 | |
| +
 | |
| +	if (index >= capa.num_psfp_sgid) {
 | |
| +		dev_err(ocelot->dev, "Invalid sgid %u, maximum:%u\n",
 | |
| +			index, capa.num_psfp_sgid);
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +
 | |
| +	ocelot_rmw(ocelot,
 | |
| +		   ANA_SG_ACCESS_CTRL_SGID(index),
 | |
| +		   ANA_SG_ACCESS_CTRL_SGID_M,
 | |
| +		   ANA_SG_ACCESS_CTRL);
 | |
| +
 | |
| +	val = ocelot_read(ocelot, ANA_SG_STATUS_REG_2);
 | |
| +	sgi_status->config_change_time = val;
 | |
| +
 | |
| +	reg = ocelot_read(ocelot, ANA_SG_STATUS_REG_1);
 | |
| +	val = ocelot_read(ocelot, ANA_SG_STATUS_REG_3);
 | |
| +	sgi_status->config_change_time +=
 | |
| +		ANA_SG_STATUS_REG_3_CFG_CHG_TIME_SEC_MSB(val) << 32;
 | |
| +	sgi_status->config_change_time =
 | |
| +		sgi_status->config_change_time * 1000000000 + reg;
 | |
| +
 | |
| +	if (val & ANA_SG_STATUS_REG_3_CONFIG_PENDING)
 | |
| +		sgi_status->config_pending  = TRUE;
 | |
| +	else
 | |
| +		sgi_status->config_pending = FALSE;
 | |
| +
 | |
| +	if (val & ANA_SG_STATUS_REG_3_GATE_STATE)
 | |
| +		sgi_status->oper.gate_states  =  TRUE;
 | |
| +	else
 | |
| +		sgi_status->oper.gate_states  =  FALSE;
 | |
| +	/*bit 3 encoding 0:IPV [0:2]is invalid . 1:IPV[0:2] is valid*/
 | |
| +	if (val & ANA_SG_STATUS_REG_3_IPV_VALID)
 | |
| +		sgi_status->oper.init_ipv = ANA_SG_STATUS_REG_3_IPV_X(val);
 | |
| +	else
 | |
| +		sgi_status->oper.init_ipv = -1;
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +int ocelot_qci_fmi_set(struct ocelot *ocelot, int port, u32 index,
 | |
| +		       bool enable, struct tsn_qci_psfp_fmi *fmi)
 | |
| +{
 | |
| +	u32 cir = 0, cbs = 0, pir = 0, pbs = 0;
 | |
| +	u32 cir_ena = 0;
 | |
| +	u32 pbs_max = 0, cbs_max = 0;
 | |
| +	bool cir_discard = 0, pir_discard = 0;
 | |
| +
 | |
| +	if (index > capa.qos_pol_max) {
 | |
| +		dev_err(ocelot->dev, "Invalid pol_idx %u, maximum: %u\n",
 | |
| +			index, capa.qos_pol_max);
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +
 | |
| +	if (fmi->mark_red_enable && fmi->mark_red) {
 | |
| +		fmi->eir = 0;
 | |
| +		fmi->ebs = 0;
 | |
| +		fmi->cir = 0;
 | |
| +		fmi->cbs = 0;
 | |
| +	}
 | |
| +
 | |
| +	pir = fmi->eir;
 | |
| +	pbs = fmi->ebs;
 | |
| +
 | |
| +	if (!fmi->drop_on_yellow)
 | |
| +		cir_ena = 1;
 | |
| +
 | |
| +	if (cir_ena) {
 | |
| +		cir = fmi->cir;
 | |
| +		cbs = fmi->cbs;
 | |
| +		if (cir == 0 && cbs == 0) {
 | |
| +			cir_discard = 1;
 | |
| +		} else {
 | |
| +			cir = DIV_ROUND_UP(cir, 100);
 | |
| +			cir *= 3;  /* Rate unit is 33 1/3 kbps */
 | |
| +			cbs = DIV_ROUND_UP(cbs, 4096);
 | |
| +			cbs = (cbs ? cbs : 1);
 | |
| +			cbs_max = capa.pol_cbs_max;
 | |
| +			if (fmi->cf)
 | |
| +				pir += fmi->cir;
 | |
| +		}
 | |
| +	}
 | |
| +
 | |
| +	if (pir == 0 && pbs == 0) {
 | |
| +		pir_discard = 1;
 | |
| +	} else {
 | |
| +		pir = DIV_ROUND_UP(pir, 100);
 | |
| +		pir *= 3;  /* Rate unit is 33 1/3 kbps */
 | |
| +		pbs = DIV_ROUND_UP(pbs, 4096);
 | |
| +		pbs = (pbs ? pbs : 1);
 | |
| +		pbs_max = capa.pol_pbs_max;
 | |
| +	}
 | |
| +	pir = min_t(u32, GENMASK(15, 0), pir);
 | |
| +	cir = min_t(u32, GENMASK(15, 0), cir);
 | |
| +	pbs = min(pbs_max, pbs);
 | |
| +	cbs = min(cbs_max, cbs);
 | |
| +
 | |
| +	ocelot_write_gix(ocelot, (ANA_POL_MODE_CFG_IPG_SIZE(20) |
 | |
| +			 ANA_POL_MODE_CFG_FRM_MODE(1) |
 | |
| +			 (fmi->cf ? ANA_POL_MODE_CFG_DLB_COUPLED : 0) |
 | |
| +			 (cir_ena ? ANA_POL_MODE_CFG_CIR_ENA : 0) |
 | |
| +			 ANA_POL_MODE_CFG_OVERSHOOT_ENA),
 | |
| +			 ANA_POL_MODE_CFG, index);
 | |
| +
 | |
| +	ocelot_write_gix(ocelot, ANA_POL_PIR_CFG_PIR_RATE(pir) |
 | |
| +			 ANA_POL_PIR_CFG_PIR_BURST(pbs),
 | |
| +			 ANA_POL_PIR_CFG, index);
 | |
| +
 | |
| +	ocelot_write_gix(ocelot,
 | |
| +			 (pir_discard ? GENMASK(22, 0) : 0),
 | |
| +			 ANA_POL_PIR_STATE, index);
 | |
| +
 | |
| +	ocelot_write_gix(ocelot, ANA_POL_CIR_CFG_CIR_RATE(cir) |
 | |
| +			 ANA_POL_CIR_CFG_CIR_BURST(cbs),
 | |
| +			 ANA_POL_CIR_CFG, index);
 | |
| +
 | |
| +	ocelot_write_gix(ocelot,
 | |
| +			 (cir_discard ? GENMASK(22, 0) : 0),
 | |
| +			 ANA_POL_CIR_STATE, index);
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +int ocelot_qci_fmi_get(struct ocelot *ocelot, int port, u32 index,
 | |
| +		       struct tsn_qci_psfp_fmi *fmi,
 | |
| +		       struct tsn_qci_psfp_fmi_counters *counters)
 | |
| +{
 | |
| +	u32 val, reg;
 | |
| +
 | |
| +	if (index > capa.qos_pol_max) {
 | |
| +		dev_err(ocelot->dev, "Invalid pol_idx %u, maximum: %u\n",
 | |
| +			index, capa.qos_pol_max);
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +
 | |
| +	val = ocelot_read_gix(ocelot, ANA_POL_PIR_CFG, index);
 | |
| +	reg = ocelot_read_gix(ocelot, ANA_POL_CIR_CFG, index);
 | |
| +
 | |
| +	fmi->eir = ANA_POL_PIR_CFG_PIR_RATE_X(val);
 | |
| +	fmi->eir = fmi->eir * 100 / 3;
 | |
| +	fmi->ebs = ANA_POL_PIR_CFG_PIR_BURST(val);
 | |
| +	fmi->ebs *= 4096;
 | |
| +	fmi->cir = ANA_POL_CIR_CFG_CIR_RATE_X(reg);
 | |
| +	fmi->cir = fmi->cir * 100 / 3;
 | |
| +	fmi->cbs = ANA_POL_CIR_CFG_CIR_BURST(reg);
 | |
| +	fmi->cbs *= 4096;
 | |
| +	if (!(fmi->eir | fmi->ebs | fmi->cir | fmi->cbs))
 | |
| +		fmi->mark_red = TRUE;
 | |
| +	else
 | |
| +		fmi->mark_red = FALSE;
 | |
| +
 | |
| +	val = ocelot_read_gix(ocelot, ANA_POL_MODE_CFG, index);
 | |
| +	if (val & ANA_POL_MODE_CFG_DLB_COUPLED)
 | |
| +		fmi->cf = TRUE;
 | |
| +	else
 | |
| +		fmi->cf = FALSE;
 | |
| +	if (val & ANA_POL_MODE_CFG_CIR_ENA)
 | |
| +		fmi->drop_on_yellow = FALSE;
 | |
| +	else
 | |
| +		fmi->drop_on_yellow = TRUE;
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +int ocelot_seq_gen_set(struct ocelot *ocelot, int port, u32 index,
 | |
| +		       struct tsn_seq_gen_conf *sg_conf)
 | |
| +{
 | |
| +	u8 iport_mask = sg_conf->iport_mask;
 | |
| +	u8 split_mask = sg_conf->split_mask;
 | |
| +	u8 seq_len = sg_conf->seq_len;
 | |
| +	u32 seq_num = sg_conf->seq_num;
 | |
| +
 | |
| +	if (index >= capa.num_frer_ssid) {
 | |
| +		dev_err(ocelot->dev, "Invalid SSID %u, maximum:%u\n",
 | |
| +			index, capa.num_frer_ssid - 1);
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +	if (seq_len < capa.frer_seq_len_min ||
 | |
| +	    seq_len > capa.frer_seq_len_max) {
 | |
| +		dev_err(ocelot->dev,
 | |
| +			"Invalid seq_space_bits num %u,range:%d~%d\n",
 | |
| +			seq_len,
 | |
| +			capa.frer_seq_len_min,
 | |
| +			capa.frer_seq_len_max);
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +
 | |
| +	streamid_multi_forward_set(ocelot,
 | |
| +				   streamhandle_map[index],
 | |
| +				   split_mask);
 | |
| +
 | |
| +	ocelot_write(ocelot,
 | |
| +		     ANA_TABLES_SEQ_MASK_SPLIT_MASK(split_mask) |
 | |
| +		     ANA_TABLES_SEQ_MASK_INPUT_PORT_MASK(iport_mask),
 | |
| +		     ANA_TABLES_SEQ_MASK);
 | |
| +
 | |
| +	ocelot_write(ocelot,
 | |
| +		     ANA_TABLES_STREAMTIDX_S_INDEX(index) |
 | |
| +		     ANA_TABLES_STREAMTIDX_STREAM_SPLIT |
 | |
| +		     ANA_TABLES_STREAMTIDX_SEQ_SPACE_LOG2(seq_len),
 | |
| +		     ANA_TABLES_STREAMTIDX);
 | |
| +
 | |
| +	ocelot_write(ocelot,
 | |
| +		     ANA_TABLES_STREAMACCESS_GEN_REC_SEQ_NUM(seq_num) |
 | |
| +		     ANA_TABLES_STREAMACCESS_SEQ_GEN_REC_ENA |
 | |
| +		     ANA_TABLES_STREAMACCESS_STREAM_TBL_CMD(SFIDACCESS_CMD_WRITE),
 | |
| +		     ANA_TABLES_STREAMACCESS);
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +int ocelot_seq_rec_set(struct ocelot *ocelot, int port, u32 index,
 | |
| +		       struct tsn_seq_rec_conf *sr_conf)
 | |
| +{
 | |
| +	u8 seq_len = sr_conf->seq_len;
 | |
| +	u8 hislen = sr_conf->his_len;
 | |
| +
 | |
| +	if (index >= capa.num_frer_ssid) {
 | |
| +		dev_err(ocelot->dev, "Invalid SSID %u, maximum:%u\n",
 | |
| +			index, capa.num_frer_ssid - 1);
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +	if (seq_len < capa.frer_seq_len_min ||
 | |
| +	    seq_len > capa.frer_seq_len_max) {
 | |
| +		dev_err(ocelot->dev,
 | |
| +			"Invalid seq_space_bits num %u,range:%d~%d\n",
 | |
| +			seq_len,
 | |
| +			capa.frer_seq_len_min,
 | |
| +			capa.frer_seq_len_max);
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +	if (hislen < capa.frer_his_len_min ||
 | |
| +	    hislen > capa.frer_his_len_max) {
 | |
| +		dev_err(ocelot->dev,
 | |
| +			"Invalid history_bits num %u,range:%d~%d\n",
 | |
| +			hislen,
 | |
| +			capa.frer_his_len_min,
 | |
| +			capa.frer_his_len_max);
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +
 | |
| +	ocelot_write(ocelot,
 | |
| +		     ANA_TABLES_STREAMTIDX_S_INDEX(index) |
 | |
| +		     ANA_TABLES_STREAMTIDX_FORCE_SF_BEHAVIOUR |
 | |
| +		     ANA_TABLES_STREAMTIDX_SEQ_HISTORY_LEN(hislen) |
 | |
| +		     ANA_TABLES_STREAMTIDX_RESET_ON_ROGUE |
 | |
| +		     (sr_conf->rtag_pop_en ?
 | |
| +		      ANA_TABLES_STREAMTIDX_REDTAG_POP : 0) |
 | |
| +		     ANA_TABLES_STREAMTIDX_SEQ_SPACE_LOG2(seq_len),
 | |
| +		     ANA_TABLES_STREAMTIDX);
 | |
| +
 | |
| +	ocelot_write(ocelot,
 | |
| +		     ANA_TABLES_STREAMACCESS_SEQ_GEN_REC_ENA |
 | |
| +		     ANA_TABLES_STREAMACCESS_GEN_REC_TYPE |
 | |
| +		     ANA_TABLES_STREAMACCESS_STREAM_TBL_CMD(SFIDACCESS_CMD_WRITE),
 | |
| +		     ANA_TABLES_STREAMACCESS);
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +int ocelot_cb_get(struct ocelot *ocelot, int port, u32 index,
 | |
| +		  struct tsn_cb_status *c)
 | |
| +{
 | |
| +	u32 val;
 | |
| +
 | |
| +	if (index >= capa.num_frer_ssid) {
 | |
| +		dev_err(ocelot->dev, "Invalid SSID %u, maximum:%u\n",
 | |
| +			index, capa.num_frer_ssid - 1);
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +
 | |
| +	ocelot_write(ocelot,
 | |
| +		     ANA_TABLES_STREAMTIDX_S_INDEX(index),
 | |
| +		     ANA_TABLES_STREAMTIDX);
 | |
| +
 | |
| +	ocelot_write(ocelot,
 | |
| +		     ANA_TABLES_STREAMACCESS_STREAM_TBL_CMD(SFIDACCESS_CMD_READ),
 | |
| +		     ANA_TABLES_STREAMACCESS);
 | |
| +
 | |
| +	val = ocelot_read(ocelot, ANA_TABLES_STREAMACCESS);
 | |
| +	c->gen_rec = (ANA_TABLES_STREAMACCESS_GEN_REC_TYPE & val) >> 2;
 | |
| +	c->seq_num = ANA_TABLES_STREAMACCESS_GEN_REC_SEQ_NUM_X(val);
 | |
| +
 | |
| +	val = ocelot_read(ocelot, ANA_TABLES_STREAMTIDX);
 | |
| +	c->err = ANA_TABLES_STREAMTIDX_SEQ_GEN_ERR_STATUS_X(val);
 | |
| +	c->his_len = ANA_TABLES_STREAMTIDX_SEQ_HISTORY_LEN_X(val);
 | |
| +	c->seq_len = ANA_TABLES_STREAMTIDX_SEQ_SPACE_LOG2(val);
 | |
| +
 | |
| +	val = ocelot_read(ocelot, ANA_TABLES_SEQ_MASK);
 | |
| +	c->split_mask = ANA_TABLES_SEQ_MASK_SPLIT_MASK_X(val);
 | |
| +	c->iport_mask = ANA_TABLES_SEQ_MASK_INPUT_PORT_MASK(val);
 | |
| +
 | |
| +	c->seq_his = ocelot_read(ocelot, ANA_TABLES_SEQ_HISTORY);
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +int ocelot_pcp_map_enable(struct ocelot *ocelot, u8 port)
 | |
| +{
 | |
| +	int i;
 | |
| +
 | |
| +	ocelot_rmw_gix(ocelot,
 | |
| +		       ANA_PORT_QOS_CFG_QOS_PCP_ENA,
 | |
| +		       ANA_PORT_QOS_CFG_QOS_PCP_ENA,
 | |
| +		       ANA_PORT_QOS_CFG,
 | |
| +		       port);
 | |
| +
 | |
| +	for (i = 0; i < NUM_MSCC_QOS_PRIO * 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),
 | |
| +			      ANA_PORT_PCP_DEI_MAP_DP_PCP_DEI_VAL |
 | |
| +			      ANA_PORT_PCP_DEI_MAP_QOS_PCP_DEI_VAL_M,
 | |
| +			      ANA_PORT_PCP_DEI_MAP,
 | |
| +			      port, i);
 | |
| +	}
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +int ocelot_rtag_parse_enable(struct ocelot *ocelot, u8 port)
 | |
| +{
 | |
| +	ocelot_rmw_rix(ocelot,
 | |
| +		       ANA_PORT_MODE_REDTAG_PARSE_CFG,
 | |
| +		       ANA_PORT_MODE_REDTAG_PARSE_CFG,
 | |
| +		       ANA_PORT_MODE,
 | |
| +		       port);
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +int ocelot_dscp_set(struct ocelot *ocelot, int port,
 | |
| +		    bool enable, const u8 dscp_ix,
 | |
| +		    struct tsn_qos_switch_dscp_conf *c)
 | |
| +{
 | |
| +	u32 val, ri = dscp_ix;
 | |
| +
 | |
| +	c->dscp = 0;
 | |
| +	c->trust = 1;
 | |
| +	c->remark = 0;
 | |
| +
 | |
| +	if (dscp_ix > capa.qos_dscp_max) {
 | |
| +		dev_err(ocelot->dev, "Invalid dscp_ix %u\n", dscp_ix);
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +	if (c->cos > capa.qos_cos_max) {
 | |
| +		dev_err(ocelot->dev, "Invalid cos %d\n", c->cos);
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +	if (c->dpl > capa.qos_dp_max) {
 | |
| +		dev_err(ocelot->dev, "Invalid dpl %d\n", c->dpl);
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +
 | |
| +	ocelot_rmw_gix(ocelot,
 | |
| +		       (enable ? ANA_PORT_QOS_CFG_QOS_DSCP_ENA : 0) |
 | |
| +		       (c->dscp ? ANA_PORT_QOS_CFG_DSCP_TRANSLATE_ENA : 0),
 | |
| +		       ANA_PORT_QOS_CFG_QOS_DSCP_ENA |
 | |
| +		       ANA_PORT_QOS_CFG_DSCP_TRANSLATE_ENA,
 | |
| +		       ANA_PORT_QOS_CFG,
 | |
| +		       port);
 | |
| +
 | |
| +	val = (c->dpl ? ANA_DSCP_CFG_DP_DSCP_VAL : 0) |
 | |
| +	       ANA_DSCP_CFG_QOS_DSCP_VAL(c->cos) |
 | |
| +	       ANA_DSCP_CFG_DSCP_TRANSLATE_VAL(c->dscp) |
 | |
| +	       (c->trust ? ANA_DSCP_CFG_DSCP_TRUST_ENA : 0) |
 | |
| +	       (c->remark ? ANA_DSCP_CFG_DSCP_REWR_ENA : 0);
 | |
| +
 | |
| +	ocelot_write_rix(ocelot, val, ANA_DSCP_CFG, ri);
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| --- /dev/null
 | |
| +++ b/drivers/net/ethernet/mscc/ocelot_tsn.h
 | |
| @@ -0,0 +1,51 @@
 | |
| +/* SPDX-License-Identifier: (GPL-2.0 OR MIT)
 | |
| + *
 | |
| + * TSN_SWITCH driver
 | |
| + *
 | |
| + * Copyright 2018-2019 NXP
 | |
| + */
 | |
| +
 | |
| +#ifndef _MSCC_OCELOT_SWITCH_TSN_H_
 | |
| +#define _MSCC_OCELOT_SWITCH_TSN_H_
 | |
| +
 | |
| +#define TRUE 1
 | |
| +#define FALSE 0
 | |
| +
 | |
| +struct mscc_switch_capa {
 | |
| +	u8 num_tas_gcl; /* Number of TAS Gate Control Lists */
 | |
| +	u32 tas_ct_min; /* Minimum supported TAS CycleTime in nS */
 | |
| +	u32 tas_ct_max; /* Maximum supported TAS CycleTime in nS */
 | |
| +	u32 tas_cte_max; /* Maximum supported TAS CycleTimeExtension in nS
 | |
| +			  */
 | |
| +	u32 tas_it_max;
 | |
| +	u32 tas_it_min;
 | |
| +	u8 num_hsch;
 | |
| +	u8 num_psfp_sfid;
 | |
| +	u8 num_frer_ssid;
 | |
| +	u8 num_psfp_sgid;
 | |
| +	u16 psfp_fmi_max;
 | |
| +	u16 psfp_fmi_min;
 | |
| +	u8 num_sgi_gcl;
 | |
| +	u32 sgi_ct_min;
 | |
| +	u32 sgi_ct_max;
 | |
| +	u32 sgi_cte_max;
 | |
| +	u16 qos_pol_max;
 | |
| +	u8 pol_cbs_max;
 | |
| +	u8 pol_pbs_max;
 | |
| +	u8 frer_seq_len_min;
 | |
| +	u8 frer_seq_len_max;
 | |
| +	u8 frer_his_len_min;
 | |
| +	u8 frer_his_len_max;
 | |
| +	u8 qos_dscp_max;
 | |
| +	u8 qos_cos_max;
 | |
| +	u8 qos_dp_max;
 | |
| +};
 | |
| +
 | |
| +static inline void ocelot_port_rmwl(struct ocelot_port *port, u32 val,
 | |
| +				    u32 mask, u32 reg)
 | |
| +{
 | |
| +	u32 cur = ocelot_port_readl(port, reg);
 | |
| +
 | |
| +	ocelot_port_writel(port, (cur & (~mask)) | val, reg);
 | |
| +}
 | |
| +#endif
 | |
| --- a/include/soc/mscc/ocelot.h
 | |
| +++ b/include/soc/mscc/ocelot.h
 | |
| @@ -10,6 +10,7 @@
 | |
|  #include <linux/if_vlan.h>
 | |
|  #include <linux/regmap.h>
 | |
|  #include <net/dsa.h>
 | |
| +#include <net/tsn.h>
 | |
|  
 | |
|  #define IFH_INJ_BYPASS			BIT(31)
 | |
|  #define IFH_INJ_POP_CNT_DISABLE		(3 << 28)
 | |
| @@ -328,6 +329,10 @@ enum ocelot_reg {
 | |
|  	PTP_CFG_MISC,
 | |
|  	PTP_CLK_CFG_ADJ_CFG,
 | |
|  	PTP_CLK_CFG_ADJ_FREQ,
 | |
| +	PTP_CUR_NSF,
 | |
| +	PTP_CUR_NSEC,
 | |
| +	PTP_CUR_SEC_LSB,
 | |
| +	PTP_CUR_SEC_MSB,
 | |
|  	GCB_SOFT_RST = GCB << TARGET_OFFSET,
 | |
|  };
 | |
|  
 | |
| @@ -539,5 +544,50 @@ int ocelot_ptp_gettime64(struct ptp_cloc
 | |
|  int ocelot_port_add_txtstamp_skb(struct ocelot_port *ocelot_port,
 | |
|  				 struct sk_buff *skb);
 | |
|  void ocelot_get_txtstamp(struct ocelot *ocelot);
 | |
| -
 | |
| +int ocelot_qbv_set(struct ocelot *ocelot, int port_id,
 | |
| +		   struct tsn_qbv_conf *shaper_config);
 | |
| +int ocelot_qbv_get(struct ocelot *ocelot, int port_id,
 | |
| +		   struct tsn_qbv_conf *shaper_config);
 | |
| +int ocelot_qbv_get_status(struct ocelot *ocelot, int port_id,
 | |
| +			  struct tsn_qbv_status *qbvstatus);
 | |
| +int ocelot_cut_thru_set(struct ocelot *ocelot, int port_id, u8 cut_thru);
 | |
| +int ocelot_cbs_set(struct ocelot *ocelot, int port, u8 tc, u8 bw);
 | |
| +int ocelot_cbs_get(struct ocelot *ocelot, int port, u8 tc);
 | |
| +int ocelot_qbu_set(struct ocelot *ocelot, int port, u8 preemptible);
 | |
| +int ocelot_qbu_get(struct ocelot *ocelot, int port,
 | |
| +		   struct tsn_preempt_status *c);
 | |
| +int ocelot_cb_streamid_get(struct ocelot *ocelot, int port, u32 index,
 | |
| +			   struct tsn_cb_streamid *streamid);
 | |
| +int ocelot_cb_streamid_set(struct ocelot *ocelot, int port, u32 index,
 | |
| +			   bool enable, struct tsn_cb_streamid *streamid);
 | |
| +int ocelot_qci_sfi_get(struct ocelot *ocelot, int port, u32 index,
 | |
| +		       struct tsn_qci_psfp_sfi_conf *sfi);
 | |
| +int ocelot_qci_sfi_set(struct ocelot *ocelot, int port, u32 index,
 | |
| +		       bool enable, struct tsn_qci_psfp_sfi_conf *sfi);
 | |
| +int ocelot_qci_sfi_counters_get(struct ocelot *ocelot, int port, u32 index,
 | |
| +			struct tsn_qci_psfp_sfi_counters *sfi_counters);
 | |
| +int ocelot_qci_max_cap_get(struct ocelot *ocelot,
 | |
| +			   struct tsn_qci_psfp_stream_param *stream_para);
 | |
| +int ocelot_qci_sgi_set(struct ocelot *ocelot, int port, u32 index,
 | |
| +		       struct tsn_qci_psfp_sgi_conf *sgi_conf);
 | |
| +int ocelot_qci_sgi_get(struct ocelot *ocelot, int port, u32 index,
 | |
| +		       struct tsn_qci_psfp_sgi_conf *sgi_conf);
 | |
| +int ocelot_qci_sgi_status_get(struct ocelot *ocelot, int port, u32 index,
 | |
| +			      struct tsn_psfp_sgi_status *sgi_status);
 | |
| +int ocelot_qci_fmi_set(struct ocelot *ocelot, int port, u32 index,
 | |
| +		       bool enable, struct tsn_qci_psfp_fmi *fmi);
 | |
| +int ocelot_qci_fmi_get(struct ocelot *ocelot, int port, u32 index,
 | |
| +		       struct tsn_qci_psfp_fmi *fmi,
 | |
| +		       struct tsn_qci_psfp_fmi_counters *counters);
 | |
| +int ocelot_seq_gen_set(struct ocelot *ocelot, int port, u32 index,
 | |
| +		       struct tsn_seq_gen_conf *sg_conf);
 | |
| +int ocelot_seq_rec_set(struct ocelot *ocelot, int port, u32 index,
 | |
| +		       struct tsn_seq_rec_conf *sr_conf);
 | |
| +int ocelot_cb_get(struct ocelot *ocelot, int port, u32 index,
 | |
| +		  struct tsn_cb_status *c);
 | |
| +int ocelot_pcp_map_enable(struct ocelot *ocelot, u8 port);
 | |
| +int ocelot_rtag_parse_enable(struct ocelot *ocelot, u8 port);
 | |
| +int ocelot_dscp_set(struct ocelot *ocelot, int port,
 | |
| +		    bool enable, const u8 dscp_ix,
 | |
| +		    struct tsn_qos_switch_dscp_conf *c);
 | |
|  #endif
 |