mirror of
https://github.com/openwrt/openwrt.git
synced 2026-10-13 00:17:02 +04:00
qualcommax: add PPE driver
PPE switch driver for Qualcomm IPQ platforms, depends on EDMA and UNIPHY PCS. Signed-off-by: John Crispin <john@phrozen.org> [ rework Makefile for external repository, dependency ] Signed-off-by: Christian Marangi <ansuelsmth@gmail.com> [ bring PPE in-tree ] Link: https://github.com/openwrt/openwrt/pull/22381 Signed-off-by: Robert Marko <robimarko@gmail.com>
This commit is contained in:
1 parent
05c180511d
commit
142104bb90
7 files changed
+3549
No files matched your search
@@ -402,6 +402,7 @@ CONFIG_QCA807X_PHY=y
|
||||
CONFIG_QCA808X_PHY=y
|
||||
# CONFIG_QCM_DISPCC_2290 is not set
|
||||
# CONFIG_QCM_GCC_2290 is not set
|
||||
# CONFIG_QCOM_80211AX_PPE is not set
|
||||
# CONFIG_QCOM_A53PLL is not set
|
||||
# CONFIG_QCOM_AOSS_QMP is not set
|
||||
CONFIG_QCOM_APCS_IPC=y
|
||||
|
||||
@@ -0,0 +1,545 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later OR MIT */
|
||||
|
||||
#ifndef __QCA_PPE_H
|
||||
#define __QCA_PPE_H
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/io.h>
|
||||
#include <net/dsa.h>
|
||||
|
||||
#define QCA_PPE_MAX_PORTS 8
|
||||
#define QCA_PPE_CPU_PORT 0
|
||||
#define QCA_PPE_MAX_BRIDGES 8
|
||||
|
||||
|
||||
/* --- Global --- */
|
||||
#define PPE_PORT_MUX_CTRL 0x10
|
||||
|
||||
/* CPPE (IPQ60xx) PORT_MUX_CTRL bit layout */
|
||||
#define CPPE_PORT3_PCS_SEL GENMASK(1, 0)
|
||||
#define CPPE_PORT5_PCS_SEL GENMASK(5, 4)
|
||||
#define CPPE_PORT5_GMAC_SEL BIT(6)
|
||||
#define CPPE_PCS0_CH4_SEL BIT(7)
|
||||
#define CPPE_PORT3_PCS0_CH4 1
|
||||
#define CPPE_PORT5_PCS1_CH0 1
|
||||
|
||||
/* HPPE (IPQ807x) PORT_MUX_CTRL bit layout */
|
||||
#define HPPE_PORT4_PCS_SEL BIT(0)
|
||||
#define HPPE_PORT5_PCS_SEL GENMASK(2, 1)
|
||||
#define HPPE_PORT5_GMAC_SEL BIT(3)
|
||||
#define HPPE_PORT6_PCS_SEL BIT(4)
|
||||
#define HPPE_PORT6_GMAC_SEL BIT(5)
|
||||
#define HPPE_PORT4_PCS0 1
|
||||
#define HPPE_PORT5_PCS0 1
|
||||
#define HPPE_PORT5_PCS1 2
|
||||
#define HPPE_PORT6_PCS2 1
|
||||
#define HPPE_PORT5_GMAC_SEL_GMAC 1
|
||||
#define HPPE_PORT6_GMAC_SEL_GMAC 1
|
||||
|
||||
/* --- MAC CSR (base 0x001000) --- */
|
||||
#define PPE_MAC_CSR_BASE 0x001000
|
||||
|
||||
#define PPE_GMAC_ENABLE(gmac) (PPE_MAC_CSR_BASE + (gmac) * 0x200)
|
||||
#define PPE_MAC_ENABLE_RXMAC_EN BIT(0)
|
||||
#define PPE_MAC_ENABLE_TXMAC_EN BIT(1)
|
||||
#define PPE_MAC_ENABLE_DUPLEX BIT(4)
|
||||
#define PPE_MAC_ENABLE_RX_FLOW_EN BIT(5)
|
||||
#define PPE_MAC_ENABLE_TX_FLOW_EN BIT(6)
|
||||
|
||||
#define PPE_LPBK_ENABLE(gmac) (PPE_MAC_CSR_BASE + (gmac) * 0x200)
|
||||
#define PPE_LPBK_EN BIT(0)
|
||||
#define PPE_LPBK_CRC_STRIP_EN BIT(3)
|
||||
|
||||
#define PPE_GMAC_SPEED(gmac) (PPE_MAC_CSR_BASE + (gmac) * 0x200 + 0x4)
|
||||
#define PPE_GMAC_SPEED_MASK GENMASK(1, 0)
|
||||
|
||||
#define PPE_LPBK_PPS_CTRL(gmac) (PPE_MAC_CSR_BASE + (gmac) * 0x200 + 0x0c)
|
||||
#define PPE_LPBK_PPS_THRESHOLD GENMASK(8, 0)
|
||||
|
||||
#define PPE_GMAC_CTRL2(gmac) (PPE_MAC_CSR_BASE + (gmac) * 0x200 + 0x18)
|
||||
#define PPE_GMAC_CTRL2_MAXFR GENMASK(21, 8)
|
||||
#define PPE_GMAC_CTRL2_CRS_SEL BIT(6)
|
||||
#define PPE_GMAC_CTRL2_TX_THD GENMASK(27, 24)
|
||||
|
||||
#define PPE_GMAC_DBG_CTRL(gmac) (PPE_MAC_CSR_BASE + (gmac) * 0x200 + 0x1c)
|
||||
#define PPE_GMAC_DBG_CTRL_HIHG_IPG GENMASK(15, 8)
|
||||
|
||||
#define PPE_GMAC_JUMBO_SIZE(gmac) (PPE_MAC_CSR_BASE + (gmac) * 0x200 + 0x30)
|
||||
|
||||
#define PPE_GMAC_MIB_CTRL(gmac) (PPE_MAC_CSR_BASE + (gmac) * 0x200 + 0x34)
|
||||
#define PPE_MIB_EN BIT(0)
|
||||
#define PPE_MIB_RD_CLR BIT(2)
|
||||
|
||||
#define PPE_GMAC_MIB(gmac, off) (PPE_MAC_CSR_BASE + (gmac) * 0x200 + (off))
|
||||
#define PPE_MIB_RXBROAD 0x40
|
||||
#define PPE_MIB_RXPAUSE 0x44
|
||||
#define PPE_MIB_RXMULTI 0x48
|
||||
#define PPE_MIB_RXFCSERR 0x4c
|
||||
#define PPE_MIB_RXALIGNERR 0x50
|
||||
#define PPE_MIB_RXRUNT 0x54
|
||||
#define PPE_MIB_RXFRAG 0x58
|
||||
#define PPE_MIB_RXJUMBOFCSERR 0x5c
|
||||
#define PPE_MIB_RXJUMBOALIGNERR 0x60
|
||||
#define PPE_MIB_RXPKT64 0x64
|
||||
#define PPE_MIB_RXPKT65TO127 0x68
|
||||
#define PPE_MIB_RXPKT128TO255 0x6c
|
||||
#define PPE_MIB_RXPKT256TO511 0x70
|
||||
#define PPE_MIB_RXPKT512TO1023 0x74
|
||||
#define PPE_MIB_RXPKT1024TO1518 0x78
|
||||
#define PPE_MIB_RXPKT1519TOX 0x7c
|
||||
#define PPE_MIB_RXTOOLONG 0x80
|
||||
#define PPE_MIB_RXGOODBYTE_L 0x84
|
||||
#define PPE_MIB_RXGOODBYTE_H 0x88
|
||||
#define PPE_MIB_RXBADBYTE_L 0x8c
|
||||
#define PPE_MIB_RXBADBYTE_H 0x90
|
||||
#define PPE_MIB_RXUNI 0x94
|
||||
#define PPE_MIB_TXBROAD 0xa0
|
||||
#define PPE_MIB_TXPAUSE 0xa4
|
||||
#define PPE_MIB_TXMULTI 0xa8
|
||||
#define PPE_MIB_TXUNDERRUN 0xac
|
||||
#define PPE_MIB_TXPKT64 0xb0
|
||||
#define PPE_MIB_TXPKT65TO127 0xb4
|
||||
#define PPE_MIB_TXPKT128TO255 0xb8
|
||||
#define PPE_MIB_TXPKT256TO511 0xbc
|
||||
#define PPE_MIB_TXPKT512TO1023 0xc0
|
||||
#define PPE_MIB_TXPKT1024TO1518 0xc4
|
||||
#define PPE_MIB_TXPKT1519TOX 0xc8
|
||||
#define PPE_MIB_TXBYTE_L 0xcc
|
||||
#define PPE_MIB_TXBYTE_H 0xd0
|
||||
#define PPE_MIB_TXCOLLISIONS 0xd4
|
||||
#define PPE_MIB_TXABORTCOL 0xd8
|
||||
#define PPE_MIB_TXMULTICOL 0xdc
|
||||
#define PPE_MIB_TXSINGLECOL 0xe0
|
||||
#define PPE_MIB_TXEXCESSIVEDEFER 0xe4
|
||||
#define PPE_MIB_TXDEFER 0xe8
|
||||
#define PPE_MIB_TXLATECOL 0xec
|
||||
#define PPE_MIB_TXUNI 0xf0
|
||||
|
||||
/* --- XGMAC (base 0x003000) --- */
|
||||
#define PPE_MAC_XGMAC_CSR_BASE 0x003000
|
||||
|
||||
#define PPE_XGMAC_TX_CONF(xgmac) (PPE_MAC_XGMAC_CSR_BASE + (xgmac) * 0x4000)
|
||||
#define PPE_XGMAC_TX_ENABLE BIT(0)
|
||||
#define PPE_XGMAC_JABBER_DISABLE BIT(16) /* Called JD */
|
||||
#define PPE_XGMAC_SPEED_SELECT GENMASK(30, 29)
|
||||
#define PPE_XGMAC_SPEED_SELECT_10000 FIELD_PREP_CONST(PPE_XGMAC_SPEED_SELECT, 0x0)
|
||||
#define PPE_XGMAC_SPEED_SELECT_5000 FIELD_PREP_CONST(PPE_XGMAC_SPEED_SELECT, 0x1)
|
||||
#define PPE_XGMAC_SPEED_SELECT_2500 FIELD_PREP_CONST(PPE_XGMAC_SPEED_SELECT, 0x2)
|
||||
#define PPE_XGMAC_SPEED_SELECT_1000 FIELD_PREP_CONST(PPE_XGMAC_SPEED_SELECT, 0x3)
|
||||
#define PPE_XGMAC_USXGMII_SELECT BIT(31)
|
||||
|
||||
#define PPE_XGMAC_RX_CONF(xgmac) (PPE_MAC_XGMAC_CSR_BASE + (xgmac) * 0x4000 + 0x4)
|
||||
#define PPE_XGMAC_RX_ENABLE BIT(0)
|
||||
#define PPE_XGMAC_AUTO_CRC_STRIP BIT(1) /* Called ACS */
|
||||
#define PPE_XGMAC_CRC_STRIP_TYPE BIT(2) /* Called CST */
|
||||
#define PPE_XGMAC_GMII_MPLS_LAYER_CK BIT(6) /* Called GMPSLCE */
|
||||
#define PPE_XGMAC_WATCHDOG_DISABLE BIT(7) /* Called WD */
|
||||
|
||||
#define PPE_XGMAC_PACKET_FILTER(xgmac) (PPE_MAC_XGMAC_CSR_BASE + (xgmac) * 0x4000 + 0x8)
|
||||
#define PPE_XGMAC_PROMISCUOUS BIT(0) /* Called PR */
|
||||
#define PPE_XGMAC_PASS_CONTROL_FRAME GENMASK(7, 6) /* Called PCF */
|
||||
#define PPE_XGMAC_RATE_ADAPTATION BIT(31) /* Called RA */
|
||||
|
||||
#define PPE_XGMAC_WATCHDOG_TIMEOUT(xgmac) (PPE_MAC_XGMAC_CSR_BASE + (xgmac) * 0x4000 + 0xc)
|
||||
#define PPE_XGMAC_WATCHDOG_THRESHOLD GENMASK(3, 0)
|
||||
#define PPE_XGMAC_WATCHDOG_ENABLE BIT(8)
|
||||
|
||||
#define PPE_XGMAC_TX_FLOW_CTRL(xgmac) (PPE_MAC_XGMAC_CSR_BASE + (xgmac) * 0x4000 + 0x70)
|
||||
#define PPE_XGMAC_TX_FLOW_ENABLE BIT(1)
|
||||
#define PPE_XGMAC_PAUSE_TIME GENMASK(31, 16)
|
||||
|
||||
#define PPE_XGMAC_RX_FLOW_CTRL(xgmac) (PPE_MAC_XGMAC_CSR_BASE + (xgmac) * 0x4000 + 0x90)
|
||||
#define PPE_XGMAC_RX_FLOW_ENABLE BIT(0)
|
||||
|
||||
/* --- PRX (base 0x00b000) --- */
|
||||
#define PPE_PRX_BASE 0x00b000
|
||||
|
||||
#define PPE_PRX_TDM_CTRL (PPE_PRX_BASE + 0x0)
|
||||
#define PPE_TDM_DEPTH GENMASK(7, 0)
|
||||
#define PPE_TDM_EN BIT(31)
|
||||
|
||||
#define PPE_PRX_TDM_CFG(i) (PPE_PRX_BASE + 0x1000 + (i) * 0x10)
|
||||
#define PPE_TDM_PORT_NUM GENMASK(3, 0)
|
||||
#define PPE_TDM_DIR BIT(4)
|
||||
#define PPE_TDM_VALID BIT(5)
|
||||
|
||||
#define PPE_PRX_MRU_MTU_W1(p) (PPE_PRX_BASE + 0x3000 + (p) * 0x10 + 0x4)
|
||||
#define PPE_QOS_PCP_GRP BIT(4)
|
||||
#define PPE_QOS_DSCP_GRP BIT(5)
|
||||
#define PPE_QOS_PREHEADER_PREC GENMASK(10, 8)
|
||||
#define PPE_QOS_PCP_PREC GENMASK(13, 11)
|
||||
#define PPE_QOS_DSCP_PREC GENMASK(16, 14)
|
||||
#define PPE_QOS_FLOW_PREC GENMASK(19, 17)
|
||||
#define PPE_QOS_ACL_PREC GENMASK(22, 20)
|
||||
|
||||
/* --- Ingress VLAN (base 0x00f000) --- */
|
||||
#define PPE_IVLAN_BASE 0x00f000
|
||||
|
||||
#define PPE_PORT_DEF_VID(port) (PPE_IVLAN_BASE + 0x10 + (port) * 0x4)
|
||||
#define PPE_PORT_DEF_CVID GENMASK(27, 16)
|
||||
#define PPE_PORT_DEF_CVID_EN BIT(28)
|
||||
|
||||
#define PPE_PORT_VLAN_CFG(port) (PPE_IVLAN_BASE + 0x50 + (port) * 0x4)
|
||||
#define PPE_VLAN_XLT_MISS_FWD GENMASK(6, 5)
|
||||
|
||||
#define PPE_XLT_RULE_TBL(idx) (PPE_IVLAN_BASE + 0x2000 + (idx) * 0x10)
|
||||
#define PPE_XLT_VALID BIT(0)
|
||||
#define PPE_XLT_PORT_BMP GENMASK(8, 1)
|
||||
#define PPE_XLT_CKEY_FMT_0 BIT(31)
|
||||
|
||||
#define PPE_XLT_RULE_W1(idx) (PPE_IVLAN_BASE + 0x2000 + (idx) * 0x10 + 0x4)
|
||||
#define PPE_XLT_CKEY_FMT_1 GENMASK(1, 0)
|
||||
#define PPE_XLT_CKEY_VID_INCL BIT(2)
|
||||
#define PPE_XLT_CKEY_VID GENMASK(14, 3)
|
||||
|
||||
#define PPE_XLT_ACTION_TBL(idx) (PPE_IVLAN_BASE + 0x4000 + (idx) * 0x10)
|
||||
#define PPE_XLT_CVID_CMD GENMASK(16, 15)
|
||||
|
||||
#define PPE_XLT_ACTION_W1(idx) (PPE_IVLAN_BASE + 0x4000 + (idx) * 0x10 + 0x4)
|
||||
#define PPE_XLT_VSI_CMD BIT(11)
|
||||
#define PPE_XLT_VSI GENMASK(16, 12)
|
||||
|
||||
/* --- PTX (base 0x020000) --- */
|
||||
#define PPE_PTX_BASE 0x020000
|
||||
|
||||
#define PPE_EG_VSI_TAG(vsi) (PPE_PTX_BASE + (vsi) * 0x4)
|
||||
#define PPE_EG_VSI_TAG_UNMODIFIED 0xaaaa
|
||||
|
||||
#define PPE_EG_BRIDGE_CONFIG (PPE_PTX_BASE + 0x6000)
|
||||
#define PPE_EG_L2_EDIT_EN BIT(1)
|
||||
#define PPE_EG_QUEUE_CNT_EN BIT(2)
|
||||
|
||||
#define PPE_PORT_EG_VLAN(port) (PPE_PTX_BASE + 0x420 + (port) * 0x4)
|
||||
#define PPE_PORT_EG_VLAN_CTAG_MODE GENMASK(2, 1)
|
||||
#define PPE_PORT_EG_VLAN_STAG_MODE GENMASK(4, 3)
|
||||
#define PPE_PORT_EG_VSI_TAG_EN BIT(5)
|
||||
#define PPE_PORT_EG_VLAN_TX_CNT_EN BIT(8)
|
||||
|
||||
#define PPE_EG_UNTOUCHED 3
|
||||
|
||||
/* --- L2 (base 0x060000) --- */
|
||||
#define PPE_L2_BASE 0x060000
|
||||
|
||||
#define PPE_FDB_OP (PPE_L2_BASE + 0x8)
|
||||
#define PPE_FDB_RD_OP (PPE_L2_BASE + 0x10)
|
||||
#define PPE_FDB_OP_RSLT (PPE_L2_BASE + 0x20)
|
||||
#define PPE_FDB_RD_OP_RSLT (PPE_L2_BASE + 0x30)
|
||||
|
||||
#define PPE_AGE_TIMER (PPE_L2_BASE + 0x34)
|
||||
#define PPE_AGE_TIMER_MASK GENMASK(19, 0)
|
||||
|
||||
#define PPE_L2_GLOBAL_CONF (PPE_L2_BASE + 0x38)
|
||||
#define PPE_L2_LRN_EN BIT(6)
|
||||
#define PPE_L2_AGE_EN BIT(7)
|
||||
|
||||
#define PPE_CST_STATE(port) (PPE_L2_BASE + 0x100 + (port) * 0x4)
|
||||
#define PPE_STP_DISABLED 0
|
||||
#define PPE_STP_BLOCKING 1
|
||||
#define PPE_STP_LEARNING 2
|
||||
#define PPE_STP_FORWARDING 3
|
||||
#define PPE_STP_STATE_MASK GENMASK(1, 0)
|
||||
|
||||
#define PPE_FDB_RD_RSLT_DATA0 (PPE_L2_BASE + 0x200)
|
||||
#define PPE_FDB_RD_RSLT_DATA1 (PPE_L2_BASE + 0x204)
|
||||
#define PPE_FDB_RD_RSLT_DATA2 (PPE_L2_BASE + 0x208)
|
||||
|
||||
#define PPE_FDB_OP_DATA0 (PPE_L2_BASE + 0x230)
|
||||
#define PPE_FDB_OP_DATA1 (PPE_L2_BASE + 0x234)
|
||||
#define PPE_FDB_OP_DATA2 (PPE_L2_BASE + 0x238)
|
||||
|
||||
#define PPE_FDB_RD_OP_DATA0 (PPE_L2_BASE + 0x260)
|
||||
#define PPE_FDB_RD_OP_DATA1 (PPE_L2_BASE + 0x264)
|
||||
#define PPE_FDB_RD_OP_DATA2 (PPE_L2_BASE + 0x268)
|
||||
|
||||
#define PPE_PORT_BRIDGE_CTRL(port) (PPE_L2_BASE + 0x300 + (port) * 0x4)
|
||||
#define PPE_BRIDGE_NEW_LRN_EN BIT(0)
|
||||
#define PPE_BRIDGE_STA_MOVE_EN BIT(3)
|
||||
#define PPE_BRIDGE_PORT_ISOL GENMASK(15, 8)
|
||||
#define PPE_PORT_BRIDGE_CTRL_TXMAC_EN BIT(16)
|
||||
|
||||
#define PPE_MC_MTU_CTRL(port) (PPE_L2_BASE + 0xa00 + (port) * 0x4)
|
||||
#define PPE_MC_MTU_CTRL_TX_CNT_EN BIT(16)
|
||||
|
||||
#define PPE_RFDB_TBL(idx) (PPE_L2_BASE + 0x1000 + (idx) * 0x8)
|
||||
|
||||
#define PPE_APP_CTRL(idx) (PPE_L2_BASE + 0x1400 + (idx) * 0x10)
|
||||
|
||||
#define PPE_VSI_TBL(vsi) (PPE_L2_BASE + 0x1800 + (vsi) * 0x10)
|
||||
#define PPE_VSI_TBL_MEMBER GENMASK(7, 0)
|
||||
#define PPE_VSI_TBL_UUC GENMASK(15, 8)
|
||||
#define PPE_VSI_TBL_UMC GENMASK(23, 16)
|
||||
#define PPE_VSI_TBL_BC GENMASK(31, 24)
|
||||
#define PPE_VSI_TBL_NEW_ADDR_LRN_EN BIT(0)
|
||||
#define PPE_VSI_TBL_STA_MOVE_LRN_EN BIT(3)
|
||||
|
||||
#define PPE_MRU_MTU_CTRL(port) (PPE_L2_BASE + 0x3000 + (port) * 0x10)
|
||||
#define PPE_MRU_MTU_CTRL_RX_CNT_EN BIT(0)
|
||||
#define PPE_MRU_MTU_CTRL_TX_CNT_EN BIT(1)
|
||||
|
||||
/* --- L3 (base 0x200000) --- */
|
||||
#define PPE_L3_BASE 0x200000
|
||||
|
||||
#define PPE_L3_VP_PORT_TBL(port) (PPE_L3_BASE + 0x1000 + (port) * 0x10)
|
||||
#define PPE_L3_VP_VSI_VALID BIT(9)
|
||||
#define PPE_L3_VP_VSI GENMASK(14, 10)
|
||||
|
||||
/* --- Traffic Manager (base 0x400000) --- */
|
||||
#define PPE_TM_BASE 0x400000
|
||||
|
||||
#define PPE_TM_TDM_DEPTH (PPE_TM_BASE + 0x0)
|
||||
#define PPE_TM_TDM_DEPTH_MASK GENMASK(7, 0)
|
||||
|
||||
#define PPE_TM_L0_FLOW_MAP(i) (PPE_TM_BASE + 0x2000 + (i) * 0x10)
|
||||
#define PPE_L0_SP_ID GENMASK(5, 0)
|
||||
#define PPE_L0_C_PRI GENMASK(8, 6)
|
||||
#define PPE_L0_E_PRI GENMASK(11, 9)
|
||||
#define PPE_L0_C_DRR_WT GENMASK(21, 12)
|
||||
#define PPE_L0_E_DRR_WT GENMASK(31, 22)
|
||||
|
||||
#define PPE_TM_L0_C_SP(i) (PPE_TM_BASE + 0x4000 + (i) * 0x10)
|
||||
#define PPE_TM_L0_E_SP(i) (PPE_TM_BASE + 0x6000 + (i) * 0x10)
|
||||
#define PPE_L0_SP_DRR_ID GENMASK(7, 0)
|
||||
|
||||
#define PPE_TM_L0_PORT_MAP(i) (PPE_TM_BASE + 0x8000 + (i) * 0x10)
|
||||
#define PPE_L0_PORT_NUM GENMASK(3, 0)
|
||||
|
||||
#define PPE_TM_RING_Q_MAP(r) (PPE_TM_BASE + 0x2a000 + (r) * 0x40)
|
||||
|
||||
#define PPE_TM_L1_FLOW_MAP(i) (PPE_TM_BASE + 0x40000 + (i) * 0x10)
|
||||
#define PPE_L1_SP_ID GENMASK(3, 0)
|
||||
#define PPE_L1_C_PRI GENMASK(6, 4)
|
||||
#define PPE_L1_E_PRI GENMASK(9, 7)
|
||||
#define PPE_L1_C_DRR_WT GENMASK(19, 10)
|
||||
#define PPE_L1_E_DRR_WT GENMASK(29, 20)
|
||||
|
||||
#define PPE_TM_L1_C_SP(i) (PPE_TM_BASE + 0x42000 + (i) * 0x10)
|
||||
#define PPE_TM_L1_E_SP(i) (PPE_TM_BASE + 0x44000 + (i) * 0x10)
|
||||
#define PPE_L1_SP_DRR_ID GENMASK(5, 0)
|
||||
|
||||
#define PPE_TM_L1_PORT_MAP(i) (PPE_TM_BASE + 0x46000 + (i) * 0x10)
|
||||
#define PPE_L1_PORT_NUM GENMASK(3, 0)
|
||||
|
||||
#define PPE_TM_PSCH_TDM(i) (PPE_TM_BASE + 0x7a000 + (i) * 0x10)
|
||||
#define PPE_PSCH_DES_PORT GENMASK(3, 0)
|
||||
#define PPE_PSCH_ENS_PORT GENMASK(7, 4)
|
||||
#define PPE_PSCH_ENS_PORT_BMP GENMASK(15, 8)
|
||||
|
||||
/* --- Buffer Manager (base 0x600000) --- */
|
||||
#define PPE_BM_BASE 0x600000
|
||||
|
||||
#define PPE_BM_FC_MODE(i) (PPE_BM_BASE + 0x100 + (i) * 0x4)
|
||||
#define PPE_BM_FC_EN BIT(0)
|
||||
|
||||
#define PPE_BM_GROUP_ID(i) (PPE_BM_BASE + 0x180 + (i) * 0x4)
|
||||
|
||||
#define PPE_BM_SHARED_GRP(g) (PPE_BM_BASE + 0x290 + (g) * 0x4)
|
||||
#define PPE_BM_SHARED_LIMIT GENMASK(10, 0)
|
||||
|
||||
#define PPE_BM_PORT_FC_W0(i) (PPE_BM_BASE + 0x1000 + (i) * 0x10)
|
||||
#define PPE_BM_PORT_FC_W1(i) (PPE_BM_BASE + 0x1000 + (i) * 0x10 + 0x4)
|
||||
#define PPE_BM_REACT_LIMIT GENMASK(8, 0)
|
||||
#define PPE_BM_RESUME_FLOOR GENMASK(17, 9)
|
||||
#define PPE_BM_RESUME_OFF GENMASK(28, 18)
|
||||
#define PPE_BM_CEILING_LO GENMASK(31, 29)
|
||||
#define PPE_BM_CEILING_HI GENMASK(7, 0)
|
||||
#define PPE_BM_WEIGHT GENMASK(10, 8)
|
||||
#define PPE_BM_DYNAMIC BIT(11)
|
||||
#define PPE_BM_PREALLOC GENMASK(22, 12)
|
||||
|
||||
/* --- Queue Manager (base 0x800000) --- */
|
||||
#define PPE_QM_BASE 0x800000
|
||||
|
||||
#define PPE_QM_UCAST_MAP(i) (PPE_QM_BASE + 0x10000 + (i) * 0x10)
|
||||
#define PPE_QM_PROFILE_ID GENMASK(3, 0)
|
||||
#define PPE_QM_QUEUE_ID GENMASK(11, 4)
|
||||
|
||||
#define PPE_QM_UCAST_HASH_MAP(i) (PPE_QM_BASE + 0x30000 + (i) * 0x10)
|
||||
#define PPE_QM_HASH_CLASS GENMASK(3, 0)
|
||||
|
||||
#define PPE_QM_UCAST_PRI_MAP(i) (PPE_QM_BASE + 0x42000 + (i) * 0x10)
|
||||
#define PPE_QM_PRI_CLASS GENMASK(3, 0)
|
||||
|
||||
#define PPE_QM_AC_UNI_W0(i) (PPE_QM_BASE + 0x48000 + (i) * 0x10)
|
||||
#define PPE_QM_AC_UNI_W1(i) (PPE_QM_BASE + 0x48000 + (i) * 0x10 + 0x4)
|
||||
#define PPE_QM_AC_UNI_W2(i) (PPE_QM_BASE + 0x48000 + (i) * 0x10 + 0x8)
|
||||
#define PPE_QM_AC_UNI_W3(i) (PPE_QM_BASE + 0x48000 + (i) * 0x10 + 0xc)
|
||||
#define PPE_AC_EN BIT(0)
|
||||
#define PPE_AC_GRP_ID GENMASK(5, 4)
|
||||
#define PPE_AC_SHARED_DYNAMIC BIT(17)
|
||||
#define PPE_AC_SHARED_WEIGHT GENMASK(20, 18)
|
||||
#define PPE_AC_SHARED_CEILING GENMASK(31, 21)
|
||||
#define PPE_AC_GRN_RESUME_OFF GENMASK(23, 13)
|
||||
|
||||
#define PPE_QM_AC_MUL_W0(i) (PPE_QM_BASE + 0x4a000 + (i) * 0x10)
|
||||
#define PPE_QM_AC_MUL_W1(i) (PPE_QM_BASE + 0x4a000 + (i) * 0x10 + 0x4)
|
||||
#define PPE_QM_AC_MUL_W2(i) (PPE_QM_BASE + 0x4a000 + (i) * 0x10 + 0x8)
|
||||
#define PPE_AC_MUL_EN BIT(0)
|
||||
#define PPE_AC_MUL_CEILING GENMASK(26, 16)
|
||||
#define PPE_AC_MUL_GRN_MAX_LO GENMASK(31, 27)
|
||||
#define PPE_AC_MUL_GRN_MAX_HI GENMASK(5, 0)
|
||||
#define PPE_AC_MUL_GRN_RESUME_HI GENMASK(17, 11)
|
||||
|
||||
#define PPE_QM_AC_GRP_W0(g) (PPE_QM_BASE + 0x4c000 + (g) * 0x10)
|
||||
#define PPE_QM_AC_GRP_W1(g) (PPE_QM_BASE + 0x4c000 + (g) * 0x10 + 0x4)
|
||||
#define PPE_QM_AC_GRP_W2(g) (PPE_QM_BASE + 0x4c000 + (g) * 0x10 + 0x8)
|
||||
#define PPE_AC_GRP_LIMIT GENMASK(14, 4)
|
||||
#define PPE_AC_GRP_PALLOC GENMASK(26, 16)
|
||||
|
||||
/* --- FDB fields --- */
|
||||
#define PPE_FDB_OP_CMD_ID GENMASK(3, 0)
|
||||
#define PPE_FDB_OP_TYPE GENMASK(7, 5)
|
||||
#define PPE_FDB_OP_HASH_BLOCK GENMASK(9, 8)
|
||||
#define PPE_FDB_OP_MODE BIT(10)
|
||||
#define PPE_FDB_OP_ENTRY_IDX GENMASK(21, 11)
|
||||
|
||||
#define PPE_FDB_RSLT_CMD_ID GENMASK(3, 0)
|
||||
|
||||
#define PPE_FDB_DATA1_VALID BIT(16)
|
||||
#define PPE_FDB_DATA1_LKP_VALID BIT(17)
|
||||
#define PPE_FDB_DATA1_VSI GENMASK(22, 18)
|
||||
#define PPE_FDB_DATA1_DST_LO GENMASK(31, 23)
|
||||
|
||||
#define PPE_FDB_DATA2_DST_HI GENMASK(2, 0)
|
||||
#define PPE_FDB_DATA2_DST_TYPE GENMASK(4, 3)
|
||||
#define PPE_FDB_DATA2_HIT_AGE GENMASK(10, 9)
|
||||
|
||||
/* --- Constants --- */
|
||||
#define PPE_NUM_PORTS 8
|
||||
#define PPE_MAX_SP_PRI 8
|
||||
#define PPE_L0_QUEUES 300
|
||||
#define PPE_L0_UCAST_QUEUES 256
|
||||
|
||||
#define PPE_BM_PORTS 15
|
||||
#define PPE_BM_PHY_START 8
|
||||
|
||||
#define PPE_VSI_MAX 32
|
||||
#define PPE_VSI_INVALID U32_MAX
|
||||
#define PPE_DEFAULT_MTU 1514
|
||||
#define PPE_MTU_SHIFT 16
|
||||
#define PPE_MAX_FRAME_SIZE 0x3000
|
||||
#define PPE_AGE_UNIT_MS 8000
|
||||
|
||||
#define PPE_FDB_TBL_NUM 2048
|
||||
#define PPE_FDB_OP_ADD 0
|
||||
#define PPE_FDB_OP_DEL 1
|
||||
#define PPE_FDB_OP_GET 2
|
||||
#define PPE_FDB_DST_PORT 2
|
||||
#define PPE_FDB_DST_PORTMAP 3
|
||||
#define PPE_FDB_AGE_STATIC 3
|
||||
#define PPE_FDB_OP_FLUSH 4
|
||||
|
||||
#define PPE_XLT_TBL_NUM 64
|
||||
#define PPE_XLT_MISS_FWD_DROP 3
|
||||
#define PPE_XLT_CVID_DEL 2
|
||||
#define PPE_XLT_CKEY_TAGGED 4
|
||||
|
||||
#define PPE_EG_UNTAGGED 0
|
||||
#define PPE_EG_TAGGED 1
|
||||
#define PPE_EG_UNMODIFIED 2
|
||||
|
||||
#define PPE_MAX_SERVICE_CODES 256
|
||||
#define PPE_MAX_CPU_CODES 256
|
||||
#define PPE_MAX_VPORT 256
|
||||
|
||||
#define QM_VP_PORT_OFFSET 0
|
||||
#define QM_CPU_CODE_OFFSET 1024
|
||||
#define QM_SERVICE_CODE_OFFSET 2048
|
||||
|
||||
struct psch_tdm_data {
|
||||
const struct psch_tdm_entry *entries;
|
||||
int num;
|
||||
};
|
||||
|
||||
struct bm_tdm_data {
|
||||
const struct bm_tdm_entry *entries;
|
||||
int num;
|
||||
};
|
||||
|
||||
enum ppe_type {
|
||||
PPE_TYPE_IPQ6018,
|
||||
PPE_TYPE_IPQ8074,
|
||||
};
|
||||
|
||||
struct ppe_data {
|
||||
enum ppe_type type;
|
||||
u8 num_ports;
|
||||
u8 num_gmacs;
|
||||
u8 loopback_port;
|
||||
u8 bm_phy_end;
|
||||
u8 bm_internal_start;
|
||||
u16 bm_group_buf;
|
||||
u16 bm_ceiling;
|
||||
u16 qm_total_buf;
|
||||
u16 qm_ceiling;
|
||||
u16 qm_green_max;
|
||||
const struct psch_tdm_data *psch_tdm;
|
||||
const struct bm_tdm_data *bm_tdm;
|
||||
};
|
||||
|
||||
struct qca_ppe_bridge_vsi {
|
||||
struct net_device *br_dev;
|
||||
u32 vsi;
|
||||
int refcount;
|
||||
};
|
||||
|
||||
struct qca_ppe_vlan_entry {
|
||||
struct net_device *br_dev;
|
||||
u16 vid;
|
||||
u32 vsi;
|
||||
u8 ports;
|
||||
u8 pvid_ports;
|
||||
int xlt_idx;
|
||||
int xlt_pvid_idx;
|
||||
};
|
||||
|
||||
struct qca_ppe_priv {
|
||||
struct dsa_switch ds;
|
||||
struct regmap *regmap;
|
||||
const struct ppe_data *data;
|
||||
struct clk_bulk_data *clks;
|
||||
int num_clks;
|
||||
spinlock_t fdb_lock;
|
||||
DECLARE_BITMAP(vsi_bitmap, PPE_VSI_MAX);
|
||||
DECLARE_BITMAP(xlt_bitmap, PPE_XLT_TBL_NUM);
|
||||
u32 port_vsi[QCA_PPE_MAX_PORTS];
|
||||
struct qca_ppe_bridge_vsi bridges[QCA_PPE_MAX_BRIDGES];
|
||||
struct qca_ppe_vlan_entry vlans[PPE_VSI_MAX];
|
||||
struct net_device *port_br_dev[QCA_PPE_MAX_PORTS];
|
||||
u16 port_pvid[QCA_PPE_MAX_PORTS];
|
||||
struct clk *port_rx_clk[QCA_PPE_MAX_PORTS];
|
||||
struct clk *port_tx_clk[QCA_PPE_MAX_PORTS];
|
||||
struct reset_control *port_rst[QCA_PPE_MAX_PORTS];
|
||||
};
|
||||
|
||||
extern const struct psch_tdm_data cppe_psch_tdm_data;
|
||||
extern const struct psch_tdm_data hppe_psch_tdm_data;
|
||||
|
||||
extern const struct bm_tdm_data cppe_bm_tdm_data;
|
||||
extern const struct bm_tdm_data hppe_bm_tdm_data;
|
||||
|
||||
static inline struct qca_ppe_priv *ds_to_priv(struct dsa_switch *ds)
|
||||
{
|
||||
return container_of(ds, struct qca_ppe_priv, ds);
|
||||
}
|
||||
|
||||
void ppe_scheduler_init(struct qca_ppe_priv *priv);
|
||||
|
||||
int ppe_vsi_alloc(struct qca_ppe_priv *priv);
|
||||
void ppe_vsi_free(struct qca_ppe_priv *priv, u32 vsi);
|
||||
void ppe_vsi_member_set(struct qca_ppe_priv *priv, u32 vsi, u32 portmask);
|
||||
|
||||
int qca_ppe_vlan_setup(struct dsa_switch *ds);
|
||||
int qca_ppe_port_vlan_filtering(struct dsa_switch *ds, int port,
|
||||
bool vlan_filtering,
|
||||
struct netlink_ext_ack *extack);
|
||||
int qca_ppe_port_vlan_add(struct dsa_switch *ds, int port,
|
||||
const struct switchdev_obj_port_vlan *vlan,
|
||||
struct netlink_ext_ack *extack);
|
||||
int qca_ppe_port_vlan_del(struct dsa_switch *ds, int port,
|
||||
const struct switchdev_obj_port_vlan *vlan);
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,781 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
|
||||
|
||||
#include "qca_ppe.h"
|
||||
|
||||
struct psch_tdm_entry {
|
||||
u8 en_port;
|
||||
u8 de_port;
|
||||
};
|
||||
|
||||
struct bm_tdm_entry {
|
||||
u8 port;
|
||||
u8 dir;
|
||||
};
|
||||
|
||||
enum psch_tdm_port {
|
||||
TDM_PORT_CPU = 0,
|
||||
TDM_PORT_PHY_1,
|
||||
TDM_PORT_PHY_2,
|
||||
TDM_PORT_PHY_3,
|
||||
TDM_PORT_PHY_4,
|
||||
TDM_PORT_FAB_0,
|
||||
TDM_PORT_FAB_1,
|
||||
TDM_PORT_PHY_7,
|
||||
};
|
||||
|
||||
enum bm_tdm_dir {
|
||||
TDM_DIR_INGRESS = 0,
|
||||
TDM_DIR_EGRESS,
|
||||
};
|
||||
|
||||
/* CPPE (IPQ60xx) port scheduler TDM -- 50 entries */
|
||||
const struct psch_tdm_entry cppe_psch_tdm[] = {
|
||||
{ TDM_PORT_CPU, TDM_PORT_FAB_1 },
|
||||
{ TDM_PORT_PHY_3, TDM_PORT_CPU },
|
||||
{ TDM_PORT_FAB_1, TDM_PORT_FAB_0 },
|
||||
{ TDM_PORT_CPU, TDM_PORT_PHY_1 },
|
||||
{ TDM_PORT_FAB_0, TDM_PORT_FAB_1 },
|
||||
{ TDM_PORT_PHY_1, TDM_PORT_CPU },
|
||||
{ TDM_PORT_FAB_1, TDM_PORT_PHY_4 },
|
||||
{ TDM_PORT_CPU, TDM_PORT_FAB_0 },
|
||||
{ TDM_PORT_PHY_4, TDM_PORT_FAB_1 },
|
||||
{ TDM_PORT_FAB_0, TDM_PORT_CPU },
|
||||
{ TDM_PORT_FAB_1, TDM_PORT_PHY_7 },
|
||||
{ TDM_PORT_CPU, TDM_PORT_FAB_0 },
|
||||
{ TDM_PORT_PHY_7, TDM_PORT_FAB_1 },
|
||||
{ TDM_PORT_FAB_0, TDM_PORT_CPU },
|
||||
{ TDM_PORT_FAB_1, TDM_PORT_PHY_2 },
|
||||
{ TDM_PORT_CPU, TDM_PORT_FAB_1 },
|
||||
{ TDM_PORT_PHY_2, TDM_PORT_FAB_0 },
|
||||
{ TDM_PORT_FAB_1, TDM_PORT_PHY_4 },
|
||||
{ TDM_PORT_FAB_0, TDM_PORT_CPU },
|
||||
{ TDM_PORT_PHY_4, TDM_PORT_FAB_1 },
|
||||
{ TDM_PORT_CPU, TDM_PORT_PHY_7 },
|
||||
{ TDM_PORT_FAB_1, TDM_PORT_FAB_0 },
|
||||
{ TDM_PORT_PHY_7, TDM_PORT_CPU },
|
||||
{ TDM_PORT_FAB_0, TDM_PORT_FAB_1 },
|
||||
{ TDM_PORT_CPU, TDM_PORT_PHY_3 },
|
||||
{ TDM_PORT_FAB_1, TDM_PORT_PHY_4 },
|
||||
{ TDM_PORT_PHY_3, TDM_PORT_CPU },
|
||||
{ TDM_PORT_PHY_4, TDM_PORT_FAB_1 },
|
||||
{ TDM_PORT_CPU, TDM_PORT_FAB_0 },
|
||||
{ TDM_PORT_FAB_1, TDM_PORT_PHY_1 },
|
||||
{ TDM_PORT_FAB_0, TDM_PORT_CPU },
|
||||
{ TDM_PORT_PHY_1, TDM_PORT_FAB_1 },
|
||||
{ TDM_PORT_CPU, TDM_PORT_FAB_0 },
|
||||
{ TDM_PORT_FAB_1, TDM_PORT_PHY_7 },
|
||||
{ TDM_PORT_FAB_0, TDM_PORT_CPU },
|
||||
{ TDM_PORT_PHY_7, TDM_PORT_FAB_1 },
|
||||
{ TDM_PORT_CPU, TDM_PORT_PHY_4 },
|
||||
{ TDM_PORT_FAB_1, TDM_PORT_FAB_0 },
|
||||
{ TDM_PORT_PHY_4, TDM_PORT_FAB_1 },
|
||||
{ TDM_PORT_FAB_0, TDM_PORT_CPU },
|
||||
{ TDM_PORT_FAB_1, TDM_PORT_PHY_2 },
|
||||
{ TDM_PORT_CPU, TDM_PORT_FAB_0 },
|
||||
{ TDM_PORT_PHY_2, TDM_PORT_FAB_1 },
|
||||
{ TDM_PORT_FAB_0, TDM_PORT_CPU },
|
||||
{ TDM_PORT_FAB_1, TDM_PORT_PHY_7 },
|
||||
{ TDM_PORT_CPU, TDM_PORT_PHY_4 },
|
||||
{ TDM_PORT_PHY_7, TDM_PORT_FAB_1 },
|
||||
{ TDM_PORT_PHY_4, TDM_PORT_FAB_0 },
|
||||
{ TDM_PORT_FAB_1, TDM_PORT_CPU },
|
||||
{ TDM_PORT_FAB_0, TDM_PORT_PHY_3 },
|
||||
};
|
||||
|
||||
/* HPPE (IPQ807x) port scheduler TDM -- 50 entries
|
||||
* Source: ssdk_hppe.c port_schedulerTDM_PORT_CPU_tbl[] */
|
||||
const struct psch_tdm_entry hppe_psch_tdm[] = {
|
||||
{ TDM_PORT_FAB_1, TDM_PORT_CPU },
|
||||
{ TDM_PORT_PHY_4, TDM_PORT_FAB_0 },
|
||||
{ TDM_PORT_CPU, TDM_PORT_FAB_1 },
|
||||
{ TDM_PORT_FAB_0, TDM_PORT_CPU },
|
||||
{ TDM_PORT_FAB_1, TDM_PORT_PHY_7 },
|
||||
{ TDM_PORT_CPU, TDM_PORT_FAB_0 },
|
||||
{ TDM_PORT_PHY_7, TDM_PORT_FAB_1 },
|
||||
{ TDM_PORT_FAB_0, TDM_PORT_CPU },
|
||||
{ TDM_PORT_FAB_1, TDM_PORT_PHY_1 },
|
||||
{ TDM_PORT_CPU, TDM_PORT_FAB_0 },
|
||||
{ TDM_PORT_PHY_1, TDM_PORT_CPU },
|
||||
{ TDM_PORT_FAB_0, TDM_PORT_FAB_1 },
|
||||
{ TDM_PORT_CPU, TDM_PORT_PHY_2 },
|
||||
{ TDM_PORT_FAB_1, TDM_PORT_FAB_0 },
|
||||
{ TDM_PORT_PHY_2, TDM_PORT_CPU },
|
||||
{ TDM_PORT_FAB_0, TDM_PORT_FAB_1 },
|
||||
{ TDM_PORT_CPU, TDM_PORT_PHY_7 },
|
||||
{ TDM_PORT_FAB_1, TDM_PORT_CPU },
|
||||
{ TDM_PORT_PHY_7, TDM_PORT_FAB_0 },
|
||||
{ TDM_PORT_CPU, TDM_PORT_FAB_1 },
|
||||
{ TDM_PORT_FAB_0, TDM_PORT_PHY_3 },
|
||||
{ TDM_PORT_FAB_1, TDM_PORT_CPU },
|
||||
{ TDM_PORT_PHY_3, TDM_PORT_FAB_0 },
|
||||
{ TDM_PORT_CPU, TDM_PORT_FAB_1 },
|
||||
{ TDM_PORT_FAB_0, TDM_PORT_CPU },
|
||||
{ TDM_PORT_FAB_1, TDM_PORT_PHY_4 },
|
||||
{ TDM_PORT_CPU, TDM_PORT_FAB_0 },
|
||||
{ TDM_PORT_PHY_4, TDM_PORT_FAB_1 },
|
||||
{ TDM_PORT_FAB_0, TDM_PORT_CPU },
|
||||
{ TDM_PORT_FAB_1, TDM_PORT_PHY_7 },
|
||||
{ TDM_PORT_CPU, TDM_PORT_FAB_0 },
|
||||
{ TDM_PORT_PHY_7, TDM_PORT_CPU },
|
||||
{ TDM_PORT_FAB_0, TDM_PORT_FAB_1 },
|
||||
{ TDM_PORT_CPU, TDM_PORT_PHY_1 },
|
||||
{ TDM_PORT_FAB_1, TDM_PORT_FAB_0 },
|
||||
{ TDM_PORT_PHY_1, TDM_PORT_CPU },
|
||||
{ TDM_PORT_FAB_0, TDM_PORT_FAB_1 },
|
||||
{ TDM_PORT_CPU, TDM_PORT_PHY_2 },
|
||||
{ TDM_PORT_FAB_1, TDM_PORT_CPU },
|
||||
{ TDM_PORT_PHY_2, TDM_PORT_FAB_0 },
|
||||
{ TDM_PORT_CPU, TDM_PORT_FAB_1 },
|
||||
{ TDM_PORT_FAB_0, TDM_PORT_PHY_7 },
|
||||
{ TDM_PORT_FAB_1, TDM_PORT_CPU },
|
||||
{ TDM_PORT_PHY_7, TDM_PORT_FAB_0 },
|
||||
{ TDM_PORT_CPU, TDM_PORT_FAB_1 },
|
||||
{ TDM_PORT_FAB_0, TDM_PORT_PHY_3 },
|
||||
{ TDM_PORT_FAB_1, TDM_PORT_CPU },
|
||||
{ TDM_PORT_PHY_3, TDM_PORT_FAB_0 },
|
||||
{ TDM_PORT_CPU, TDM_PORT_FAB_1 },
|
||||
{ TDM_PORT_FAB_0, TDM_PORT_PHY_4 },
|
||||
};
|
||||
|
||||
/* CPPE buffer manager TDM -- 98 entries */
|
||||
const struct bm_tdm_entry cppe_bm_tdm[] = {
|
||||
{ TDM_PORT_CPU, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_FAB_0, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_PHY_4, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_PHY_1, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_FAB_0, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_FAB_1, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_FAB_1, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_PHY_7, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_PHY_7, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_PHY_4, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_FAB_1, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_FAB_0, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_PHY_2, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_FAB_1, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_PHY_7, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_PHY_7, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_FAB_0, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_FAB_0, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_FAB_1, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_FAB_1, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_PHY_7, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_PHY_3, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_FAB_0, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_PHY_7, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_FAB_1, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_FAB_0, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_FAB_1, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_PHY_7, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_PHY_7, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_FAB_0, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_PHY_4, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_FAB_1, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_FAB_1, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_PHY_7, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_PHY_7, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_PHY_4, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_FAB_0, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_FAB_0, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_PHY_1, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_FAB_1, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_FAB_1, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_PHY_7, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_PHY_7, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_PHY_4, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_FAB_0, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_FAB_1, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_FAB_1, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_PHY_2, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_PHY_7, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_PHY_7, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_FAB_0, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_FAB_0, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_FAB_1, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_FAB_1, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_PHY_3, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_PHY_7, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_PHY_7, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_FAB_0, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_FAB_0, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_FAB_1, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_FAB_1, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_PHY_7, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_PHY_7, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_PHY_4, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_FAB_0, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_FAB_1, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_FAB_1, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_PHY_7, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_PHY_7, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_EGRESS },
|
||||
};
|
||||
|
||||
/* HPPE buffer manager TDM -- 96 entries
|
||||
* Source: ssdk_hppe.c port_tdmTDM_PORT_CPU_tbl[] */
|
||||
const struct bm_tdm_entry hppe_bm_tdm[] = {
|
||||
{ TDM_PORT_CPU, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_FAB_0, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_FAB_0, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_PHY_7, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_PHY_1, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_FAB_1, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_FAB_1, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_PHY_7, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_PHY_7, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_FAB_0, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_FAB_0, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_FAB_1, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_FAB_1, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_PHY_3, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_PHY_2, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_PHY_7, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_PHY_7, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_FAB_0, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_FAB_0, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_FAB_1, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_FAB_1, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_PHY_7, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_PHY_7, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_FAB_0, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_FAB_0, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_FAB_1, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_FAB_1, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_PHY_7, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_PHY_7, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_FAB_0, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_FAB_0, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_PHY_4, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_FAB_1, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_FAB_1, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_PHY_7, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_PHY_7, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_PHY_4, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_FAB_0, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_FAB_0, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_FAB_1, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_FAB_1, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_PHY_1, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_PHY_7, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_PHY_7, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_FAB_0, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_FAB_0, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_FAB_1, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_FAB_1, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_PHY_7, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_PHY_7, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_FAB_0, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_FAB_0, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_FAB_1, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_FAB_1, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_PHY_3, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_PHY_7, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_PHY_7, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_FAB_0, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_FAB_0, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_FAB_1, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_FAB_1, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_PHY_7, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_PHY_2, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_PHY_7, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_FAB_0, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_FAB_0, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_FAB_1, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_CPU, TDM_DIR_EGRESS },
|
||||
{ TDM_PORT_PHY_7, TDM_DIR_INGRESS },
|
||||
{ TDM_PORT_FAB_1, TDM_DIR_EGRESS },
|
||||
};
|
||||
|
||||
static void ppe_tdm_init(struct qca_ppe_priv *priv)
|
||||
{
|
||||
const struct ppe_data *data = priv->data;
|
||||
const struct psch_tdm_entry *psch;
|
||||
const struct bm_tdm_entry *bm;
|
||||
int psch_num, bm_num;
|
||||
u8 prev_de_port;
|
||||
int i;
|
||||
|
||||
psch = data->psch_tdm->entries;
|
||||
psch_num = data->psch_tdm->num;
|
||||
|
||||
bm = data->bm_tdm->entries;
|
||||
bm_num = data->bm_tdm->num;
|
||||
|
||||
/*
|
||||
* The port scheduler TDM is circular with the bitmap
|
||||
* composed of the
|
||||
* NOT (dequeue port (de_port) OR the previous dequeue port)
|
||||
* Each bit correspond to a port from 0 to 7.
|
||||
*
|
||||
* For the first element, we refer to the last dequeue port
|
||||
* (since it's circular).
|
||||
*
|
||||
* Taking an example for the first element:
|
||||
* We dequeue port 6 and the last element dequeue port 3
|
||||
* So the bitmap will be ~(BIT(6) | BIT(3)) = 0xb7
|
||||
*
|
||||
* Example for the second element:
|
||||
* We dequeque port 0 and previously we dequeued port 6
|
||||
* So the bitmap will be ~(BIT(0) | BIT(6)) = 0xbe
|
||||
*/
|
||||
prev_de_port = psch[psch_num - 1].de_port;
|
||||
for (i = 0; i < psch_num; i++) {
|
||||
u8 bmp = ~(BIT(prev_de_port) | BIT(psch[i].de_port));
|
||||
|
||||
regmap_write(priv->regmap, PPE_TM_PSCH_TDM(i),
|
||||
FIELD_PREP(PPE_PSCH_ENS_PORT_BMP, bmp) |
|
||||
FIELD_PREP(PPE_PSCH_ENS_PORT, psch[i].en_port) |
|
||||
FIELD_PREP(PPE_PSCH_DES_PORT, psch[i].de_port));
|
||||
|
||||
prev_de_port = BIT(psch[i].de_port);
|
||||
}
|
||||
|
||||
regmap_write(priv->regmap, PPE_TM_TDM_DEPTH,
|
||||
FIELD_PREP(PPE_TM_TDM_DEPTH_MASK, psch_num));
|
||||
|
||||
for (i = 0; i < bm_num; i++)
|
||||
regmap_write(priv->regmap, PPE_PRX_TDM_CFG(i),
|
||||
FIELD_PREP(PPE_TDM_PORT_NUM, bm[i].port) |
|
||||
FIELD_PREP(PPE_TDM_DIR, bm[i].dir) |
|
||||
PPE_TDM_VALID);
|
||||
|
||||
regmap_write(priv->regmap, PPE_PRX_TDM_CTRL,
|
||||
FIELD_PREP(PPE_TDM_DEPTH, bm_num) |
|
||||
PPE_TDM_EN);
|
||||
}
|
||||
|
||||
static void ppe_bm_init(struct qca_ppe_priv *priv)
|
||||
{
|
||||
const struct ppe_data *d = priv->data;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < PPE_BM_PORTS; i++) {
|
||||
bool fc_en = (i < PPE_BM_PHY_START || i > d->bm_phy_end);
|
||||
|
||||
regmap_write(priv->regmap, PPE_BM_FC_MODE(i),
|
||||
fc_en ? PPE_BM_FC_EN : 0);
|
||||
regmap_write(priv->regmap, PPE_BM_GROUP_ID(i), 0);
|
||||
}
|
||||
|
||||
regmap_write(priv->regmap, PPE_BM_SHARED_GRP(0),
|
||||
FIELD_PREP(PPE_BM_SHARED_LIMIT, d->bm_group_buf));
|
||||
|
||||
for (i = 0; i < PPE_BM_PORTS; i++) {
|
||||
u16 react;
|
||||
u32 w0, w1;
|
||||
|
||||
if (i < PPE_BM_PHY_START)
|
||||
react = 100;
|
||||
else if (i >= d->bm_internal_start)
|
||||
react = 40;
|
||||
else
|
||||
react = 128;
|
||||
|
||||
w0 = FIELD_PREP(PPE_BM_REACT_LIMIT, react) |
|
||||
FIELD_PREP(PPE_BM_RESUME_OFF, 36) |
|
||||
FIELD_PREP(PPE_BM_CEILING_LO, d->bm_ceiling & 0x7);
|
||||
w1 = FIELD_PREP(PPE_BM_CEILING_HI, d->bm_ceiling >> 3) |
|
||||
FIELD_PREP(PPE_BM_WEIGHT, 4) |
|
||||
PPE_BM_DYNAMIC;
|
||||
|
||||
regmap_write(priv->regmap, PPE_BM_PORT_FC_W0(i), w0);
|
||||
regmap_write(priv->regmap, PPE_BM_PORT_FC_W1(i), w1);
|
||||
}
|
||||
}
|
||||
|
||||
static void ppe_qm_map_set(struct qca_ppe_priv *priv, u32 index,
|
||||
u8 queue_base, u8 profile)
|
||||
{
|
||||
regmap_write(priv->regmap, PPE_QM_UCAST_MAP(index),
|
||||
FIELD_PREP(PPE_QM_PROFILE_ID, profile) |
|
||||
FIELD_PREP(PPE_QM_QUEUE_ID, queue_base));
|
||||
}
|
||||
|
||||
static const u8 port_queue_base[PPE_NUM_PORTS] = {
|
||||
0, 144, 160, 176, 192, 208, 224, 240,
|
||||
};
|
||||
|
||||
static const u8 port_l0_cdrr_num[PPE_NUM_PORTS] = {
|
||||
48, 16, 16, 16, 16, 16, 16, 16,
|
||||
};
|
||||
|
||||
static void ppe_qm_init(struct qca_ppe_priv *priv)
|
||||
{
|
||||
const struct ppe_data *d = priv->data;
|
||||
int i, pri;
|
||||
|
||||
ppe_qm_map_set(priv, QM_SERVICE_CODE_OFFSET + 2, 8, 0);
|
||||
ppe_qm_map_set(priv, QM_SERVICE_CODE_OFFSET + 3, 128, 8);
|
||||
ppe_qm_map_set(priv, QM_SERVICE_CODE_OFFSET + 4, 128, 8);
|
||||
ppe_qm_map_set(priv, QM_SERVICE_CODE_OFFSET + 5, 0, 0);
|
||||
ppe_qm_map_set(priv, QM_SERVICE_CODE_OFFSET + 6, 8, 0);
|
||||
ppe_qm_map_set(priv, QM_SERVICE_CODE_OFFSET + 7, 240, 0);
|
||||
|
||||
for (i = 0; i < PPE_NUM_PORTS; i++)
|
||||
ppe_qm_map_set(priv, QM_VP_PORT_OFFSET + i,
|
||||
port_queue_base[i], i);
|
||||
|
||||
for (i = 0; i < PPE_NUM_PORTS; i++) {
|
||||
u8 max_pri = port_l0_cdrr_num[i];
|
||||
u8 profile;
|
||||
|
||||
if (max_pri > 16)
|
||||
max_pri = 1;
|
||||
|
||||
for (pri = 0; pri < 16; pri++) {
|
||||
u8 cls = (pri >= max_pri) ? max_pri - 1 : pri;
|
||||
|
||||
if (i == 0) {
|
||||
profile = 0;
|
||||
regmap_write(priv->regmap,
|
||||
PPE_QM_UCAST_PRI_MAP(profile * 16 + pri),
|
||||
FIELD_PREP(PPE_QM_PRI_CLASS, cls));
|
||||
profile = 15;
|
||||
regmap_write(priv->regmap,
|
||||
PPE_QM_UCAST_PRI_MAP(profile * 16 + pri),
|
||||
FIELD_PREP(PPE_QM_PRI_CLASS, cls));
|
||||
} else {
|
||||
regmap_write(priv->regmap,
|
||||
PPE_QM_UCAST_PRI_MAP(i * 16 + pri),
|
||||
FIELD_PREP(PPE_QM_PRI_CLASS, cls));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
regmap_write(priv->regmap, PPE_QM_UCAST_HASH_MAP(15 * 256 + i), 0);
|
||||
regmap_write(priv->regmap, PPE_QM_UCAST_HASH_MAP(14 * 256 + i), 0);
|
||||
}
|
||||
|
||||
ppe_qm_map_set(priv, QM_CPU_CODE_OFFSET + 101,
|
||||
port_queue_base[0] + 0, 0);
|
||||
|
||||
for (i = 0; i < PPE_MAX_SERVICE_CODES; i++) {
|
||||
u32 idx = QM_SERVICE_CODE_OFFSET + (1 << 8) + i;
|
||||
|
||||
if (i == 2 || i == 6)
|
||||
ppe_qm_map_set(priv, idx, 8, 0);
|
||||
else if (i == 3 || i == 4)
|
||||
ppe_qm_map_set(priv, idx, 128, 8);
|
||||
else
|
||||
ppe_qm_map_set(priv, idx, 4, 0);
|
||||
}
|
||||
|
||||
for (i = 0; i < PPE_MAX_CPU_CODES; i++)
|
||||
ppe_qm_map_set(priv, QM_CPU_CODE_OFFSET + (1 << 8) + i, 4, 0);
|
||||
|
||||
for (i = 0; i < PPE_NUM_PORTS; i++)
|
||||
ppe_qm_map_set(priv, QM_VP_PORT_OFFSET + (1 << 8) + i,
|
||||
port_queue_base[i], i);
|
||||
|
||||
for (i = PPE_NUM_PORTS; i < PPE_MAX_VPORT; i++)
|
||||
ppe_qm_map_set(priv, QM_VP_PORT_OFFSET + (1 << 8) + i, 4, 0);
|
||||
|
||||
for (i = 0; i < PPE_L0_UCAST_QUEUES; i++) {
|
||||
regmap_write(priv->regmap, PPE_QM_AC_UNI_W0(i),
|
||||
PPE_AC_EN |
|
||||
PPE_AC_SHARED_DYNAMIC |
|
||||
FIELD_PREP(PPE_AC_SHARED_WEIGHT, 4) |
|
||||
FIELD_PREP(PPE_AC_SHARED_CEILING, d->qm_ceiling));
|
||||
regmap_write(priv->regmap, PPE_QM_AC_UNI_W1(i), 0);
|
||||
regmap_write(priv->regmap, PPE_QM_AC_UNI_W2(i), 0);
|
||||
regmap_write(priv->regmap, PPE_QM_AC_UNI_W3(i),
|
||||
FIELD_PREP(PPE_AC_GRN_RESUME_OFF, 36));
|
||||
}
|
||||
|
||||
for (i = 0; i < PPE_L0_QUEUES - PPE_L0_UCAST_QUEUES; i++) {
|
||||
regmap_write(priv->regmap, PPE_QM_AC_MUL_W0(i),
|
||||
PPE_AC_MUL_EN |
|
||||
FIELD_PREP(PPE_AC_MUL_CEILING, d->qm_ceiling) |
|
||||
FIELD_PREP(PPE_AC_MUL_GRN_MAX_LO, d->qm_green_max & 0x1f));
|
||||
regmap_write(priv->regmap, PPE_QM_AC_MUL_W1(i),
|
||||
FIELD_PREP(PPE_AC_MUL_GRN_MAX_HI, d->qm_green_max >> 5));
|
||||
regmap_write(priv->regmap, PPE_QM_AC_MUL_W2(i),
|
||||
FIELD_PREP(PPE_AC_MUL_GRN_RESUME_HI, 36));
|
||||
}
|
||||
|
||||
regmap_write(priv->regmap, PPE_QM_AC_GRP_W0(0), 0);
|
||||
regmap_write(priv->regmap, PPE_QM_AC_GRP_W1(0),
|
||||
FIELD_PREP(PPE_AC_GRP_LIMIT, d->qm_total_buf));
|
||||
regmap_write(priv->regmap, PPE_QM_AC_GRP_W2(0), 0);
|
||||
|
||||
regmap_update_bits(priv->regmap, PPE_EG_BRIDGE_CONFIG,
|
||||
PPE_EG_QUEUE_CNT_EN, PPE_EG_QUEUE_CNT_EN);
|
||||
}
|
||||
|
||||
struct l1_cfg {
|
||||
u8 index;
|
||||
u8 port;
|
||||
u8 pri;
|
||||
u8 drr;
|
||||
};
|
||||
|
||||
static const struct l1_cfg l1_cfg[] = {
|
||||
{ 0, 0, 0, 0 },
|
||||
{ 1, 0, 0, 0 },
|
||||
{ 36, 1, 0, 8 },
|
||||
{ 37, 1, 1, 9 },
|
||||
{ 40, 2, 0, 12 },
|
||||
{ 41, 2, 1, 13 },
|
||||
{ 44, 3, 0, 16 },
|
||||
{ 45, 3, 1, 17 },
|
||||
{ 48, 4, 0, 20 },
|
||||
{ 49, 4, 1, 21 },
|
||||
{ 52, 5, 0, 24 },
|
||||
{ 53, 5, 1, 25 },
|
||||
{ 56, 6, 0, 28 },
|
||||
{ 57, 6, 1, 29 },
|
||||
{ 60, 7, 0, 32 },
|
||||
{ 61, 7, 1, 33 },
|
||||
};
|
||||
|
||||
static void ppe_l1_scheduler_init(struct qca_ppe_priv *priv)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(l1_cfg); i++) {
|
||||
const struct l1_cfg *c = &l1_cfg[i];
|
||||
u32 sp_idx;
|
||||
|
||||
regmap_write(priv->regmap, PPE_TM_L1_FLOW_MAP(c->index),
|
||||
FIELD_PREP(PPE_L1_SP_ID, c->port) |
|
||||
FIELD_PREP(PPE_L1_C_PRI, c->pri) |
|
||||
FIELD_PREP(PPE_L1_E_PRI, c->pri) |
|
||||
FIELD_PREP(PPE_L1_C_DRR_WT, 1) |
|
||||
FIELD_PREP(PPE_L1_E_DRR_WT, 1));
|
||||
|
||||
sp_idx = c->port * 8 + c->pri;
|
||||
regmap_write(priv->regmap, PPE_TM_L1_C_SP(sp_idx),
|
||||
FIELD_PREP(PPE_L1_SP_DRR_ID, c->drr));
|
||||
|
||||
regmap_write(priv->regmap, PPE_TM_L1_E_SP(sp_idx),
|
||||
FIELD_PREP(PPE_L1_SP_DRR_ID, c->drr));
|
||||
|
||||
regmap_write(priv->regmap, PPE_TM_L1_PORT_MAP(c->index),
|
||||
FIELD_PREP(PPE_L1_PORT_NUM, c->port));
|
||||
}
|
||||
}
|
||||
|
||||
struct l0_cfg {
|
||||
u16 queue;
|
||||
u8 port;
|
||||
u8 sp;
|
||||
u8 cpri;
|
||||
u8 cdrr;
|
||||
u8 epri;
|
||||
u8 edrr;
|
||||
};
|
||||
|
||||
static const struct l0_cfg l0_port0[] = {
|
||||
{ 0, 0, 0, 0, 0, 0, 0 }, { 4, 0, 0, 0, 0, 0, 0 },
|
||||
{ 8, 0, 0, 0, 0, 0, 0 }, { 256, 0, 0, 0, 0, 0, 0 },
|
||||
{ 260, 0, 0, 0, 0, 0, 0 },
|
||||
{ 1, 0, 0, 1, 1, 1, 1 }, { 5, 0, 0, 1, 1, 1, 1 },
|
||||
{ 9, 0, 0, 1, 1, 1, 1 }, { 257, 0, 0, 1, 1, 1, 1 },
|
||||
{ 261, 0, 0, 1, 1, 1, 1 },
|
||||
{ 2, 0, 0, 2, 2, 2, 2 }, { 6, 0, 0, 2, 2, 2, 2 },
|
||||
{ 10, 0, 0, 2, 2, 2, 2 }, { 258, 0, 0, 2, 2, 2, 2 },
|
||||
{ 262, 0, 0, 2, 2, 2, 2 },
|
||||
{ 3, 0, 0, 3, 3, 3, 3 }, { 7, 0, 0, 3, 3, 3, 3 },
|
||||
{ 11, 0, 0, 3, 3, 3, 3 }, { 259, 0, 0, 3, 3, 3, 3 },
|
||||
{ 263, 0, 0, 3, 3, 3, 3 },
|
||||
};
|
||||
|
||||
static void ppe_l0_entry_write(struct qca_ppe_priv *priv, const struct l0_cfg *c)
|
||||
{
|
||||
u32 sp_idx;
|
||||
|
||||
regmap_write(priv->regmap, PPE_TM_L0_FLOW_MAP(c->queue),
|
||||
FIELD_PREP(PPE_L0_SP_ID, c->sp) |
|
||||
FIELD_PREP(PPE_L0_C_PRI, c->cpri) |
|
||||
FIELD_PREP(PPE_L0_E_PRI, c->epri) |
|
||||
FIELD_PREP(PPE_L0_C_DRR_WT, 1) |
|
||||
FIELD_PREP(PPE_L0_E_DRR_WT, 1));
|
||||
|
||||
sp_idx = c->sp * 8 + c->cpri;
|
||||
regmap_write(priv->regmap, PPE_TM_L0_C_SP(sp_idx),
|
||||
FIELD_PREP(PPE_L0_SP_DRR_ID, c->cdrr));
|
||||
|
||||
sp_idx = c->sp * 8 + c->epri;
|
||||
regmap_write(priv->regmap, PPE_TM_L0_E_SP(sp_idx),
|
||||
FIELD_PREP(PPE_L0_SP_DRR_ID, c->edrr));
|
||||
|
||||
regmap_write(priv->regmap, PPE_TM_L0_PORT_MAP(c->queue),
|
||||
FIELD_PREP(PPE_L0_PORT_NUM, c->port));
|
||||
}
|
||||
|
||||
struct port_l0_params {
|
||||
u16 ucast_base;
|
||||
u8 ucast_count;
|
||||
u16 mcast_base;
|
||||
u8 mcast_count;
|
||||
u8 sp_base;
|
||||
u8 cdrr_base;
|
||||
u8 port;
|
||||
};
|
||||
|
||||
static const struct port_l0_params port_l0[] = {
|
||||
{ 144, 16, 272, 4, 36, 48, 1 },
|
||||
{ 160, 16, 276, 4, 40, 64, 2 },
|
||||
{ 176, 16, 280, 4, 44, 80, 3 },
|
||||
{ 192, 16, 284, 4, 48, 96, 4 },
|
||||
{ 208, 16, 288, 4, 52, 112, 5 },
|
||||
{ 224, 16, 292, 4, 56, 128, 6 },
|
||||
{ 240, 16, 296, 1, 60, 144, 7 },
|
||||
};
|
||||
|
||||
static void ppe_l0_scheduler_init(struct qca_ppe_priv *priv)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(l0_port0); i++)
|
||||
ppe_l0_entry_write(priv, &l0_port0[i]);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(port_l0); i++) {
|
||||
const struct port_l0_params *p = &port_l0[i];
|
||||
u16 bases[] = { p->ucast_base, p->mcast_base };
|
||||
u8 counts[] = { p->ucast_count, p->mcast_count };
|
||||
int k;
|
||||
|
||||
for (k = 0; k < 2; k++) {
|
||||
for (j = 0; j < counts[k]; j++) {
|
||||
struct l0_cfg c = {
|
||||
.queue = bases[k] + j,
|
||||
.port = p->port,
|
||||
.sp = p->sp_base + j / PPE_MAX_SP_PRI,
|
||||
.cpri = j % PPE_MAX_SP_PRI,
|
||||
.cdrr = p->cdrr_base + j,
|
||||
.epri = j % PPE_MAX_SP_PRI,
|
||||
.edrr = p->cdrr_base + j,
|
||||
};
|
||||
|
||||
ppe_l0_entry_write(priv, &c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ppe_edma_ring_map_init(struct qca_ppe_priv *priv)
|
||||
{
|
||||
int i;
|
||||
|
||||
regmap_write(priv->regmap, PPE_TM_RING_Q_MAP(0), 0xf);
|
||||
for (i = 1; i < 10; i++)
|
||||
regmap_write(priv->regmap, PPE_TM_RING_Q_MAP(0) + i * 4, 0);
|
||||
|
||||
regmap_write(priv->regmap, PPE_TM_RING_Q_MAP(3), 0xf0);
|
||||
for (i = 1; i < 10; i++)
|
||||
regmap_write(priv->regmap, PPE_TM_RING_Q_MAP(3) + i * 4, 0);
|
||||
|
||||
regmap_write(priv->regmap, PPE_TM_RING_Q_MAP(1), 0xf00);
|
||||
for (i = 1; i < 10; i++)
|
||||
regmap_write(priv->regmap, PPE_TM_RING_Q_MAP(1) + i * 4, 0);
|
||||
|
||||
for (i = 0; i < 10; i++)
|
||||
regmap_write(priv->regmap, PPE_TM_RING_Q_MAP(2) + i * 4, 0);
|
||||
regmap_write(priv->regmap, PPE_TM_RING_Q_MAP(2) + 4 * 4, 0xffff);
|
||||
}
|
||||
|
||||
static void ppe_qos_init(struct qca_ppe_priv *priv)
|
||||
{
|
||||
int i;
|
||||
u32 qos_bits;
|
||||
|
||||
qos_bits = FIELD_PREP(PPE_QOS_PREHEADER_PREC, 3) |
|
||||
FIELD_PREP(PPE_QOS_DSCP_PREC, 1) |
|
||||
FIELD_PREP(PPE_QOS_FLOW_PREC, 4) |
|
||||
FIELD_PREP(PPE_QOS_ACL_PREC, 2);
|
||||
|
||||
for (i = 0; i < PPE_NUM_PORTS; i++)
|
||||
regmap_update_bits(priv->regmap, PPE_PRX_MRU_MTU_W1(i),
|
||||
PPE_QOS_PCP_GRP | PPE_QOS_DSCP_GRP |
|
||||
PPE_QOS_PREHEADER_PREC | PPE_QOS_PCP_PREC |
|
||||
PPE_QOS_DSCP_PREC | PPE_QOS_FLOW_PREC |
|
||||
PPE_QOS_ACL_PREC,
|
||||
qos_bits);
|
||||
}
|
||||
|
||||
const struct psch_tdm_data cppe_psch_tdm_data = {
|
||||
.entries = cppe_psch_tdm,
|
||||
.num = ARRAY_SIZE(cppe_psch_tdm),
|
||||
};
|
||||
|
||||
const struct psch_tdm_data hppe_psch_tdm_data = {
|
||||
.entries = hppe_psch_tdm,
|
||||
.num = ARRAY_SIZE(hppe_psch_tdm),
|
||||
};
|
||||
|
||||
const struct bm_tdm_data cppe_bm_tdm_data = {
|
||||
.entries = cppe_bm_tdm,
|
||||
.num = ARRAY_SIZE(cppe_bm_tdm),
|
||||
};
|
||||
|
||||
const struct bm_tdm_data hppe_bm_tdm_data = {
|
||||
.entries = hppe_bm_tdm,
|
||||
.num = ARRAY_SIZE(hppe_bm_tdm),
|
||||
};
|
||||
|
||||
void ppe_scheduler_init(struct qca_ppe_priv *priv)
|
||||
{
|
||||
ppe_tdm_init(priv);
|
||||
ppe_bm_init(priv);
|
||||
ppe_qm_init(priv);
|
||||
ppe_l1_scheduler_init(priv);
|
||||
ppe_l0_scheduler_init(priv);
|
||||
ppe_edma_ring_map_init(priv);
|
||||
ppe_qos_init(priv);
|
||||
}
|
||||
@@ -0,0 +1,319 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
|
||||
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/if_bridge.h>
|
||||
|
||||
#include "qca_ppe.h"
|
||||
|
||||
static int ppe_xlt_idx_alloc(struct qca_ppe_priv *priv)
|
||||
{
|
||||
int idx;
|
||||
|
||||
idx = find_first_zero_bit(priv->xlt_bitmap, PPE_XLT_TBL_NUM);
|
||||
if (idx >= PPE_XLT_TBL_NUM)
|
||||
return -ENOSPC;
|
||||
|
||||
set_bit(idx, priv->xlt_bitmap);
|
||||
return idx;
|
||||
}
|
||||
|
||||
static void ppe_xlt_rule_set(struct qca_ppe_priv *priv, int idx,
|
||||
u8 port_bmp, u16 vid, bool untagged)
|
||||
{
|
||||
u32 w0, w1;
|
||||
|
||||
w0 = PPE_XLT_VALID | FIELD_PREP(PPE_XLT_PORT_BMP, port_bmp);
|
||||
w1 = 0;
|
||||
|
||||
if (untagged) {
|
||||
w0 |= PPE_XLT_CKEY_FMT_0;
|
||||
} else {
|
||||
w1 |= FIELD_PREP(PPE_XLT_CKEY_FMT_1,
|
||||
PPE_XLT_CKEY_TAGGED >> 1);
|
||||
w1 |= PPE_XLT_CKEY_VID_INCL;
|
||||
w1 |= FIELD_PREP(PPE_XLT_CKEY_VID, vid);
|
||||
}
|
||||
|
||||
regmap_write(priv->regmap, PPE_XLT_RULE_TBL(idx), w0);
|
||||
regmap_write(priv->regmap, PPE_XLT_RULE_W1(idx), w1);
|
||||
regmap_write(priv->regmap, PPE_XLT_RULE_TBL(idx) + 8, 0);
|
||||
}
|
||||
|
||||
static void ppe_xlt_action_set(struct qca_ppe_priv *priv, int idx,
|
||||
u32 vsi, bool strip_ctag)
|
||||
{
|
||||
u32 w0 = 0, w1;
|
||||
|
||||
if (strip_ctag)
|
||||
w0 = FIELD_PREP(PPE_XLT_CVID_CMD, PPE_XLT_CVID_DEL);
|
||||
|
||||
w1 = PPE_XLT_VSI_CMD | FIELD_PREP(PPE_XLT_VSI, vsi);
|
||||
|
||||
regmap_write(priv->regmap, PPE_XLT_ACTION_TBL(idx), w0);
|
||||
regmap_write(priv->regmap, PPE_XLT_ACTION_W1(idx), w1);
|
||||
}
|
||||
|
||||
static void ppe_xlt_clear(struct qca_ppe_priv *priv, int idx)
|
||||
{
|
||||
regmap_write(priv->regmap, PPE_XLT_RULE_TBL(idx), 0);
|
||||
regmap_write(priv->regmap, PPE_XLT_RULE_W1(idx), 0);
|
||||
regmap_write(priv->regmap, PPE_XLT_RULE_TBL(idx) + 8, 0);
|
||||
regmap_write(priv->regmap, PPE_XLT_ACTION_TBL(idx), 0);
|
||||
regmap_write(priv->regmap, PPE_XLT_ACTION_W1(idx), 0);
|
||||
}
|
||||
|
||||
static void ppe_xlt_idx_free(struct qca_ppe_priv *priv, int *idx)
|
||||
{
|
||||
ppe_xlt_clear(priv, *idx);
|
||||
clear_bit(*idx, priv->xlt_bitmap);
|
||||
*idx = -1;
|
||||
}
|
||||
|
||||
static void ppe_eg_vsi_tag_port_set(struct qca_ppe_priv *priv,
|
||||
u32 vsi, int port, u32 mode)
|
||||
{
|
||||
regmap_update_bits(priv->regmap, PPE_EG_VSI_TAG(vsi),
|
||||
0x3 << (port * 2), (mode & 0x3) << (port * 2));
|
||||
}
|
||||
|
||||
static void ppe_port_def_cvid_set(struct qca_ppe_priv *priv,
|
||||
int port, u16 vid, bool enable)
|
||||
{
|
||||
regmap_update_bits(priv->regmap, PPE_PORT_DEF_VID(port),
|
||||
PPE_PORT_DEF_CVID | PPE_PORT_DEF_CVID_EN,
|
||||
enable ? FIELD_PREP(PPE_PORT_DEF_CVID, vid) |
|
||||
PPE_PORT_DEF_CVID_EN : 0);
|
||||
}
|
||||
|
||||
static struct qca_ppe_vlan_entry *
|
||||
ppe_vlan_find(struct qca_ppe_priv *priv, struct net_device *br_dev,
|
||||
u16 vid)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < PPE_VSI_MAX; i++)
|
||||
if (priv->vlans[i].br_dev == br_dev &&
|
||||
priv->vlans[i].vid == vid)
|
||||
return &priv->vlans[i];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct qca_ppe_vlan_entry *
|
||||
ppe_vlan_alloc(struct qca_ppe_priv *priv, struct net_device *br_dev,
|
||||
u16 vid)
|
||||
{
|
||||
struct qca_ppe_vlan_entry *entry;
|
||||
int vsi, i;
|
||||
|
||||
vsi = ppe_vsi_alloc(priv);
|
||||
if (vsi < 0)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < PPE_VSI_MAX; i++) {
|
||||
if (priv->vlans[i].br_dev)
|
||||
continue;
|
||||
|
||||
entry = &priv->vlans[i];
|
||||
entry->br_dev = br_dev;
|
||||
entry->vid = vid;
|
||||
entry->vsi = vsi;
|
||||
entry->ports = 0;
|
||||
entry->pvid_ports = 0;
|
||||
entry->xlt_idx = -1;
|
||||
entry->xlt_pvid_idx = -1;
|
||||
return entry;
|
||||
}
|
||||
|
||||
ppe_vsi_free(priv, vsi);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void ppe_vlan_free(struct qca_ppe_priv *priv,
|
||||
struct qca_ppe_vlan_entry *entry)
|
||||
{
|
||||
if (entry->xlt_idx >= 0)
|
||||
ppe_xlt_idx_free(priv, &entry->xlt_idx);
|
||||
if (entry->xlt_pvid_idx >= 0)
|
||||
ppe_xlt_idx_free(priv, &entry->xlt_pvid_idx);
|
||||
ppe_vsi_free(priv, entry->vsi);
|
||||
entry->br_dev = NULL;
|
||||
}
|
||||
|
||||
static void ppe_vlan_members_update(struct qca_ppe_priv *priv,
|
||||
struct qca_ppe_vlan_entry *entry)
|
||||
{
|
||||
ppe_vsi_member_set(priv, entry->vsi,
|
||||
entry->ports | BIT(QCA_PPE_CPU_PORT));
|
||||
}
|
||||
|
||||
static void ppe_vlan_pvid_update(struct qca_ppe_priv *priv,
|
||||
struct qca_ppe_vlan_entry *entry)
|
||||
{
|
||||
if (!entry->pvid_ports && entry->xlt_pvid_idx >= 0) {
|
||||
ppe_xlt_idx_free(priv, &entry->xlt_pvid_idx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (entry->pvid_ports)
|
||||
ppe_xlt_rule_set(priv, entry->xlt_pvid_idx,
|
||||
entry->pvid_ports, 0, true);
|
||||
}
|
||||
|
||||
int qca_ppe_vlan_setup(struct dsa_switch *ds)
|
||||
{
|
||||
struct qca_ppe_priv *priv = ds_to_priv(ds);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ds->num_ports; i++) {
|
||||
u32 mode = dsa_is_user_port(ds, i) ?
|
||||
PPE_EG_UNMODIFIED : PPE_EG_UNTOUCHED;
|
||||
|
||||
regmap_update_bits(priv->regmap, PPE_PORT_EG_VLAN(i),
|
||||
PPE_PORT_EG_VLAN_CTAG_MODE |
|
||||
PPE_PORT_EG_VLAN_STAG_MODE,
|
||||
FIELD_PREP(PPE_PORT_EG_VLAN_CTAG_MODE, mode) |
|
||||
FIELD_PREP(PPE_PORT_EG_VLAN_STAG_MODE, mode));
|
||||
}
|
||||
|
||||
for (i = 0; i < PPE_VSI_MAX; i++) {
|
||||
regmap_write(priv->regmap, PPE_EG_VSI_TAG(i),
|
||||
PPE_EG_VSI_TAG_UNMODIFIED);
|
||||
priv->vlans[i].xlt_idx = -1;
|
||||
priv->vlans[i].xlt_pvid_idx = -1;
|
||||
}
|
||||
|
||||
regmap_update_bits(priv->regmap, PPE_EG_BRIDGE_CONFIG,
|
||||
PPE_EG_L2_EDIT_EN, PPE_EG_L2_EDIT_EN);
|
||||
|
||||
ds->configure_vlan_while_not_filtering = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qca_ppe_port_vlan_filtering(struct dsa_switch *ds, int port,
|
||||
bool vlan_filtering,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct qca_ppe_priv *priv = ds_to_priv(ds);
|
||||
|
||||
regmap_update_bits(priv->regmap, PPE_PORT_EG_VLAN(port),
|
||||
PPE_PORT_EG_VSI_TAG_EN,
|
||||
vlan_filtering ? PPE_PORT_EG_VSI_TAG_EN : 0);
|
||||
|
||||
regmap_update_bits(priv->regmap, PPE_PORT_VLAN_CFG(port),
|
||||
PPE_VLAN_XLT_MISS_FWD,
|
||||
vlan_filtering ?
|
||||
FIELD_PREP(PPE_VLAN_XLT_MISS_FWD, PPE_XLT_MISS_FWD_DROP) : 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qca_ppe_port_vlan_add(struct dsa_switch *ds, int port,
|
||||
const struct switchdev_obj_port_vlan *vlan,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct qca_ppe_priv *priv = ds_to_priv(ds);
|
||||
struct net_device *br_dev = priv->port_br_dev[port];
|
||||
bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
|
||||
bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
|
||||
struct qca_ppe_vlan_entry *entry;
|
||||
u16 vid = vlan->vid;
|
||||
int idx;
|
||||
|
||||
if (!br_dev)
|
||||
return 0;
|
||||
|
||||
entry = ppe_vlan_find(priv, br_dev, vid);
|
||||
if (!entry) {
|
||||
entry = ppe_vlan_alloc(priv, br_dev, vid);
|
||||
if (!entry)
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
entry->ports |= BIT(port);
|
||||
|
||||
if (entry->xlt_idx < 0) {
|
||||
idx = ppe_xlt_idx_alloc(priv);
|
||||
if (idx < 0) {
|
||||
entry->ports &= ~BIT(port);
|
||||
if (!entry->ports)
|
||||
ppe_vlan_free(priv, entry);
|
||||
return -ENOSPC;
|
||||
}
|
||||
entry->xlt_idx = idx;
|
||||
}
|
||||
|
||||
ppe_xlt_rule_set(priv, entry->xlt_idx,
|
||||
entry->ports | BIT(QCA_PPE_CPU_PORT), vid, false);
|
||||
ppe_xlt_action_set(priv, entry->xlt_idx, entry->vsi, true);
|
||||
|
||||
ppe_eg_vsi_tag_port_set(priv, entry->vsi, port,
|
||||
untagged ? PPE_EG_UNTAGGED : PPE_EG_TAGGED);
|
||||
|
||||
if (pvid) {
|
||||
ppe_port_def_cvid_set(priv, port, vid, true);
|
||||
priv->port_pvid[port] = vid;
|
||||
entry->pvid_ports |= BIT(port);
|
||||
|
||||
if (entry->xlt_pvid_idx < 0) {
|
||||
idx = ppe_xlt_idx_alloc(priv);
|
||||
if (idx < 0)
|
||||
return -ENOSPC;
|
||||
entry->xlt_pvid_idx = idx;
|
||||
}
|
||||
ppe_xlt_rule_set(priv, entry->xlt_pvid_idx,
|
||||
entry->pvid_ports, 0, true);
|
||||
ppe_xlt_action_set(priv, entry->xlt_pvid_idx, entry->vsi,
|
||||
false);
|
||||
} else if (priv->port_pvid[port] == vid) {
|
||||
ppe_port_def_cvid_set(priv, port, 0, false);
|
||||
priv->port_pvid[port] = 0;
|
||||
entry->pvid_ports &= ~BIT(port);
|
||||
|
||||
ppe_vlan_pvid_update(priv, entry);
|
||||
}
|
||||
|
||||
ppe_vlan_members_update(priv, entry);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qca_ppe_port_vlan_del(struct dsa_switch *ds, int port,
|
||||
const struct switchdev_obj_port_vlan *vlan)
|
||||
{
|
||||
struct qca_ppe_priv *priv = ds_to_priv(ds);
|
||||
struct net_device *br_dev = priv->port_br_dev[port];
|
||||
struct qca_ppe_vlan_entry *entry;
|
||||
u16 vid = vlan->vid;
|
||||
|
||||
if (!br_dev)
|
||||
return 0;
|
||||
|
||||
entry = ppe_vlan_find(priv, br_dev, vid);
|
||||
if (!entry)
|
||||
return 0;
|
||||
|
||||
entry->ports &= ~BIT(port);
|
||||
ppe_eg_vsi_tag_port_set(priv, entry->vsi, port, PPE_EG_UNMODIFIED);
|
||||
|
||||
if (priv->port_pvid[port] == vid) {
|
||||
ppe_port_def_cvid_set(priv, port, 0, false);
|
||||
priv->port_pvid[port] = 0;
|
||||
entry->pvid_ports &= ~BIT(port);
|
||||
}
|
||||
|
||||
if (!entry->ports) {
|
||||
ppe_vlan_free(priv, entry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ppe_xlt_rule_set(priv, entry->xlt_idx,
|
||||
entry->ports | BIT(QCA_PPE_CPU_PORT), vid, false);
|
||||
|
||||
ppe_vlan_pvid_update(priv, entry);
|
||||
|
||||
ppe_vlan_members_update(priv, entry);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,309 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/net/dsa/qualcomm,ipq-ppe.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm IPQ PPE Ethernet Switch
|
||||
|
||||
maintainers:
|
||||
- John Crispin <john@phrozen.org>
|
||||
|
||||
description: |
|
||||
The Packet Processing Engine (PPE) in Qualcomm IPQ6018 and IPQ8074 SoCs is a
|
||||
hardware Ethernet switch with integrated MAC, L2 forwarding, FDB, and QoS
|
||||
scheduling. It is driven as a DSA switch, using an EDMA network device as the
|
||||
CPU port conduit and UNIPHY PCS instances for SerDes link management.
|
||||
|
||||
IPQ6018 provides 7 ports (CPU port 0, user ports 1-4 via QSGMII/PSGMII on uniphy0,
|
||||
and port 5 via uniphy1). IPQ8074 provides 8 ports (CPU port 0, user ports
|
||||
1-4 via QSGMII/PSGMII on uniphy0, and ports 5-6 via uniphy1/uniphy2).
|
||||
|
||||
$ref: dsa.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qualcomm,ipq6018-ppe
|
||||
- qualcomm,ipq8074-ppe
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
minItems: 21
|
||||
maxItems: 33
|
||||
description: |
|
||||
PPE common clocks, per-port MAC clocks, NSS infrastructure clocks, and
|
||||
per-port RX/TX clocks. The exact set depends on the SoC variant and
|
||||
the number of active ports.
|
||||
|
||||
clock-names:
|
||||
minItems: 21
|
||||
maxItems: 33
|
||||
items:
|
||||
enum:
|
||||
- cmn_ahb_clk
|
||||
- cmn_sys_clk
|
||||
- port1_mac_clk
|
||||
- port2_mac_clk
|
||||
- port3_mac_clk
|
||||
- port4_mac_clk
|
||||
- port5_mac_clk
|
||||
- port6_mac_clk
|
||||
- nss_ppe_clk
|
||||
- nss_ppe_cfg_clk
|
||||
- nssnoc_ppe_clk
|
||||
- nssnoc_ppe_cfg_clk
|
||||
- nss_ppe_ipe_clk
|
||||
- nss_ppe_btq_clk
|
||||
- gcc_mdio_ahb_clk
|
||||
- gcc_nss_noc_clk
|
||||
- gcc_nssnoc_snoc_clk
|
||||
- gcc_mem_noc_nss_axi_clk
|
||||
- gcc_nss_crypto_clk
|
||||
- gcc_nss_imem_clk
|
||||
- gcc_nss_ptp_ref_clk
|
||||
- gcc_snoc_nssnoc_clk
|
||||
- port1_rx
|
||||
- port1_tx
|
||||
- port2_rx
|
||||
- port2_tx
|
||||
- port3_rx
|
||||
- port3_tx
|
||||
- port4_rx
|
||||
- port4_tx
|
||||
- port5_rx
|
||||
- port5_tx
|
||||
- port6_rx
|
||||
- port6_tx
|
||||
|
||||
resets:
|
||||
minItems: 2
|
||||
maxItems: 7
|
||||
description: |
|
||||
PPE full reset followed by per-port NSS resets. IPQ6018 has 6 resets
|
||||
(PPE + 5 ports), IPQ8074 has 7 (PPE + 6 ports).
|
||||
|
||||
reset-names:
|
||||
minItems: 2
|
||||
maxItems: 7
|
||||
items:
|
||||
enum:
|
||||
- ppe_rst
|
||||
- nss_port1_rst
|
||||
- nss_port2_rst
|
||||
- nss_port3_rst
|
||||
- nss_port4_rst
|
||||
- nss_port5_rst
|
||||
- nss_port6_rst
|
||||
|
||||
patternProperties:
|
||||
"^(ethernet-)?ports$":
|
||||
type: object
|
||||
additionalProperties: true
|
||||
patternProperties:
|
||||
"^(ethernet-)?port@[0-7]$":
|
||||
type: object
|
||||
description: PPE switch ports
|
||||
|
||||
$ref: dsa-port.yaml#
|
||||
|
||||
properties:
|
||||
pcs-handle:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
items:
|
||||
- items:
|
||||
- description: Phandle to a UNIPHY PCS instance
|
||||
- description: Channel index within the UNIPHY
|
||||
description:
|
||||
Reference to the UNIPHY PCS instance and channel that provides
|
||||
SerDes link control for this port. Not used on the CPU port or
|
||||
ports with RGMII PHY connections.
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
oneOf:
|
||||
- required:
|
||||
- ports
|
||||
- required:
|
||||
- ethernet-ports
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- resets
|
||||
- reset-names
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/qcom,gcc-ipq8074.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
edma: edma@3ab00000 {
|
||||
compatible = "qualcomm,ipq8074-edma";
|
||||
reg = <0x3ab00000 0xb0000>;
|
||||
|
||||
interrupts = <GIC_SPI 345 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 353 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 361 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 344 IRQ_TYPE_LEVEL_HIGH>;
|
||||
|
||||
clocks = <&gcc GCC_NSS_EDMA_CLK>,
|
||||
<&gcc GCC_NSS_EDMA_CFG_CLK>,
|
||||
<&gcc GCC_NSS_PPE_CLK>,
|
||||
<&gcc GCC_NSS_PPE_CFG_CLK>,
|
||||
<&gcc GCC_NSSNOC_PPE_CLK>,
|
||||
<&gcc GCC_NSSNOC_PPE_CFG_CLK>,
|
||||
<&gcc GCC_NSS_NOC_CLK>,
|
||||
<&gcc GCC_NSSNOC_SNOC_CLK>,
|
||||
<&gcc GCC_MEM_NOC_NSS_AXI_CLK>;
|
||||
clock-names = "nss_edma_clk", "nss_edma_cfg_clk",
|
||||
"nss_ppe_clk", "nss_ppe_cfg_clk",
|
||||
"nssnoc_ppe_clk", "nssnoc_ppe_cfg_clk",
|
||||
"gcc_nss_noc_clk", "gcc_nssnoc_snoc_clk",
|
||||
"gcc_mem_noc_nss_axi_clk";
|
||||
|
||||
resets = <&gcc GCC_EDMA_HW_RESET>;
|
||||
reset-names = "edma_rst";
|
||||
};
|
||||
|
||||
uniphy1: ethernet-pcs@7a10000 {
|
||||
compatible = "qualcomm,ipq8074-uniphy";
|
||||
reg = <0x07a10000 0x10000>;
|
||||
#pcs-cells = <1>;
|
||||
|
||||
clocks = <&gcc GCC_UNIPHY1_AHB_CLK>,
|
||||
<&gcc GCC_UNIPHY1_SYS_CLK>,
|
||||
<&gcc GCC_UNIPHY1_PORT5_RX_CLK>,
|
||||
<&gcc GCC_UNIPHY1_PORT5_TX_CLK>;
|
||||
clock-names = "ahb", "sys",
|
||||
"port5_rx", "port5_tx";
|
||||
|
||||
resets = <&gcc GCC_UNIPHY1_SOFT_RESET>,
|
||||
<&gcc GCC_UNIPHY1_XPCS_RESET>;
|
||||
reset-names = "soft", "xpcs";
|
||||
};
|
||||
|
||||
uniphy2: ethernet-pcs@7a20000 {
|
||||
compatible = "qualcomm,ipq8074-uniphy";
|
||||
reg = <0x07a20000 0x10000>;
|
||||
#pcs-cells = <1>;
|
||||
|
||||
clocks = <&gcc GCC_UNIPHY2_AHB_CLK>,
|
||||
<&gcc GCC_UNIPHY2_SYS_CLK>,
|
||||
<&gcc GCC_UNIPHY2_PORT6_RX_CLK>,
|
||||
<&gcc GCC_UNIPHY2_PORT6_TX_CLK>;
|
||||
clock-names = "ahb", "sys",
|
||||
"port6_rx", "port6_tx";
|
||||
|
||||
resets = <&gcc GCC_UNIPHY2_SOFT_RESET>,
|
||||
<&gcc GCC_UNIPHY2_XPCS_RESET>;
|
||||
reset-names = "soft", "xpcs";
|
||||
};
|
||||
|
||||
ppe@3a000000 {
|
||||
compatible = "qualcomm,ipq8074-ppe";
|
||||
reg = <0x3a000000 0x900000>;
|
||||
|
||||
clocks = <&gcc GCC_CMN_12GPLL_AHB_CLK>,
|
||||
<&gcc GCC_CMN_12GPLL_SYS_CLK>,
|
||||
<&gcc GCC_PORT1_MAC_CLK>,
|
||||
<&gcc GCC_PORT2_MAC_CLK>,
|
||||
<&gcc GCC_PORT3_MAC_CLK>,
|
||||
<&gcc GCC_PORT4_MAC_CLK>,
|
||||
<&gcc GCC_PORT5_MAC_CLK>,
|
||||
<&gcc GCC_PORT6_MAC_CLK>,
|
||||
<&gcc GCC_NSS_PPE_CLK>,
|
||||
<&gcc GCC_NSS_PPE_CFG_CLK>,
|
||||
<&gcc GCC_NSSNOC_PPE_CLK>,
|
||||
<&gcc GCC_NSSNOC_PPE_CFG_CLK>,
|
||||
<&gcc GCC_NSS_PPE_IPE_CLK>,
|
||||
<&gcc GCC_NSS_PPE_BTQ_CLK>,
|
||||
<&gcc GCC_MDIO_AHB_CLK>,
|
||||
<&gcc GCC_NSS_NOC_CLK>,
|
||||
<&gcc GCC_NSSNOC_SNOC_CLK>,
|
||||
<&gcc GCC_MEM_NOC_NSS_AXI_CLK>,
|
||||
<&gcc GCC_NSS_CRYPTO_CLK>,
|
||||
<&gcc GCC_NSS_IMEM_CLK>,
|
||||
<&gcc GCC_NSS_PTP_REF_CLK>,
|
||||
<&gcc GCC_NSS_PORT1_RX_CLK>,
|
||||
<&gcc GCC_NSS_PORT1_TX_CLK>,
|
||||
<&gcc GCC_NSS_PORT2_RX_CLK>,
|
||||
<&gcc GCC_NSS_PORT2_TX_CLK>,
|
||||
<&gcc GCC_NSS_PORT3_RX_CLK>,
|
||||
<&gcc GCC_NSS_PORT3_TX_CLK>,
|
||||
<&gcc GCC_NSS_PORT4_RX_CLK>,
|
||||
<&gcc GCC_NSS_PORT4_TX_CLK>,
|
||||
<&gcc GCC_NSS_PORT5_RX_CLK>,
|
||||
<&gcc GCC_NSS_PORT5_TX_CLK>,
|
||||
<&gcc GCC_NSS_PORT6_RX_CLK>,
|
||||
<&gcc GCC_NSS_PORT6_TX_CLK>;
|
||||
clock-names = "cmn_ahb_clk", "cmn_sys_clk",
|
||||
"port1_mac_clk", "port2_mac_clk",
|
||||
"port3_mac_clk", "port4_mac_clk",
|
||||
"port5_mac_clk", "port6_mac_clk",
|
||||
"nss_ppe_clk", "nss_ppe_cfg_clk",
|
||||
"nssnoc_ppe_clk", "nssnoc_ppe_cfg_clk",
|
||||
"nss_ppe_ipe_clk", "nss_ppe_btq_clk",
|
||||
"gcc_mdio_ahb_clk", "gcc_nss_noc_clk",
|
||||
"gcc_nssnoc_snoc_clk",
|
||||
"gcc_mem_noc_nss_axi_clk",
|
||||
"gcc_nss_crypto_clk",
|
||||
"gcc_nss_imem_clk",
|
||||
"gcc_nss_ptp_ref_clk",
|
||||
"port1_rx", "port1_tx",
|
||||
"port2_rx", "port2_tx",
|
||||
"port3_rx", "port3_tx",
|
||||
"port4_rx", "port4_tx",
|
||||
"port5_rx", "port5_tx",
|
||||
"port6_rx", "port6_tx";
|
||||
|
||||
resets = <&gcc GCC_PPE_FULL_RESET>,
|
||||
<&gcc GCC_NSSPORT1_RESET>,
|
||||
<&gcc GCC_NSSPORT2_RESET>,
|
||||
<&gcc GCC_NSSPORT3_RESET>,
|
||||
<&gcc GCC_NSSPORT4_RESET>,
|
||||
<&gcc GCC_NSSPORT5_RESET>,
|
||||
<&gcc GCC_NSSPORT6_RESET>;
|
||||
reset-names = "ppe_rst", "nss_port1_rst",
|
||||
"nss_port2_rst", "nss_port3_rst",
|
||||
"nss_port4_rst", "nss_port5_rst",
|
||||
"nss_port6_rst";
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
ethernet = <&edma>;
|
||||
phy-mode = "internal";
|
||||
|
||||
fixed-link {
|
||||
speed = <10000>;
|
||||
full-duplex;
|
||||
};
|
||||
};
|
||||
|
||||
port@5 {
|
||||
reg = <5>;
|
||||
label = "lan";
|
||||
phy-handle = <&phy1>;
|
||||
phy-mode = "sgmii";
|
||||
pcs-handle = <&uniphy1 0>;
|
||||
};
|
||||
|
||||
port@6 {
|
||||
reg = <6>;
|
||||
label = "wan";
|
||||
phy-handle = <&phy2>;
|
||||
phy-mode = "sgmii";
|
||||
pcs-handle = <&uniphy2 0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
--- a/drivers/net/ethernet/qualcomm/Kconfig
|
||||
+++ b/drivers/net/ethernet/qualcomm/Kconfig
|
||||
@@ -61,6 +61,13 @@ config QCOM_EMAC
|
||||
low power, Receive-Side Scaling (RSS), and IEEE 1588-2008
|
||||
Precision Clock Synchronization Protocol.
|
||||
|
||||
+config QCOM_80211AX_PPE
|
||||
+ tristate "Qualcomm 802.11ax PPE switch driver"
|
||||
+ select PHYLINK
|
||||
+ help
|
||||
+ Driver for Qualcomm 802.11ax PPE (Packet Processing Engine) switches.
|
||||
+
|
||||
+
|
||||
source "drivers/net/ethernet/qualcomm/rmnet/Kconfig"
|
||||
|
||||
endif # NET_VENDOR_QUALCOMM
|
||||
--- a/drivers/net/ethernet/qualcomm/Makefile
|
||||
+++ b/drivers/net/ethernet/qualcomm/Makefile
|
||||
@@ -8,6 +8,8 @@ obj-$(CONFIG_QCA7000_SPI) += qcaspi.o
|
||||
qcaspi-objs := qca_7k.o qca_debug.o qca_spi.o
|
||||
obj-$(CONFIG_QCA7000_UART) += qcauart.o
|
||||
qcauart-objs := qca_uart.o
|
||||
+obj-$(CONFIG_QCOM_80211AX_PPE) += qca_ppe.o
|
||||
+qca_ppe-objs := qca_ppe_main.o qca_ppe_vlan.o qca_ppe_scheduler.o
|
||||
|
||||
obj-y += emac/
|
||||
|
||||
Reference in new issue
Block a user