156051948SVladimir Oltean // SPDX-License-Identifier: (GPL-2.0 OR MIT) 256051948SVladimir Oltean /* Copyright 2017 Microsemi Corporation 33c9cfb52SVladimir Oltean * Copyright 2018-2019 NXP 456051948SVladimir Oltean */ 5bdeced75SVladimir Oltean #include <linux/fsl/enetc_mdio.h> 6de143c0eSXiaoliang Yang #include <soc/mscc/ocelot_qsys.h> 707d985eeSVladimir Oltean #include <soc/mscc/ocelot_vcap.h> 87d4b564dSXiaoliang Yang #include <soc/mscc/ocelot_ana.h> 9de143c0eSXiaoliang Yang #include <soc/mscc/ocelot_ptp.h> 1056051948SVladimir Oltean #include <soc/mscc/ocelot_sys.h> 1123ae3a78SXiaoliang Yang #include <net/tc_act/tc_gate.h> 1256051948SVladimir Oltean #include <soc/mscc/ocelot.h> 1340d3f295SVladimir Oltean #include <linux/dsa/ocelot.h> 14588d0550SIoana Ciornei #include <linux/pcs-lynx.h> 15de143c0eSXiaoliang Yang #include <net/pkt_sched.h> 1656051948SVladimir Oltean #include <linux/iopoll.h> 1716659b81SMichael Walle #include <linux/mdio.h> 1856051948SVladimir Oltean #include <linux/pci.h> 19837ced3aSVladimir Oltean #include <linux/time.h> 2056051948SVladimir Oltean #include "felix.h" 2156051948SVladimir Oltean 22acf242fcSColin Foster #define VSC9959_NUM_PORTS 6 23acf242fcSColin Foster 24de143c0eSXiaoliang Yang #define VSC9959_TAS_GCL_ENTRY_MAX 63 25*11afdc65SVladimir Oltean #define VSC9959_TAS_MIN_GATE_LEN_NS 33 2677043c37SXiaoliang Yang #define VSC9959_VCAP_POLICER_BASE 63 2777043c37SXiaoliang Yang #define VSC9959_VCAP_POLICER_MAX 383 28c9910484SColin Foster #define VSC9959_SWITCH_PCI_BAR 4 29c9910484SColin Foster #define VSC9959_IMDIO_PCI_BAR 0 30de143c0eSXiaoliang Yang 31acf242fcSColin Foster #define VSC9959_PORT_MODE_SERDES (OCELOT_PORT_MODE_SGMII | \ 32acf242fcSColin Foster OCELOT_PORT_MODE_QSGMII | \ 3311ecf341SVladimir Oltean OCELOT_PORT_MODE_1000BASEX | \ 34acf242fcSColin Foster OCELOT_PORT_MODE_2500BASEX | \ 35acf242fcSColin Foster OCELOT_PORT_MODE_USXGMII) 36acf242fcSColin Foster 37acf242fcSColin Foster static const u32 vsc9959_port_modes[VSC9959_NUM_PORTS] = { 38acf242fcSColin Foster VSC9959_PORT_MODE_SERDES, 39acf242fcSColin Foster VSC9959_PORT_MODE_SERDES, 40acf242fcSColin Foster VSC9959_PORT_MODE_SERDES, 41acf242fcSColin Foster VSC9959_PORT_MODE_SERDES, 42acf242fcSColin Foster OCELOT_PORT_MODE_INTERNAL, 43a53cbe5dSVladimir Oltean OCELOT_PORT_MODE_INTERNAL, 44acf242fcSColin Foster }; 45acf242fcSColin Foster 4656051948SVladimir Oltean static const u32 vsc9959_ana_regmap[] = { 4756051948SVladimir Oltean REG(ANA_ADVLEARN, 0x0089a0), 4856051948SVladimir Oltean REG(ANA_VLANMASK, 0x0089a4), 4956051948SVladimir Oltean REG_RESERVED(ANA_PORT_B_DOMAIN), 5056051948SVladimir Oltean REG(ANA_ANAGEFIL, 0x0089ac), 5156051948SVladimir Oltean REG(ANA_ANEVENTS, 0x0089b0), 5256051948SVladimir Oltean REG(ANA_STORMLIMIT_BURST, 0x0089b4), 5356051948SVladimir Oltean REG(ANA_STORMLIMIT_CFG, 0x0089b8), 5456051948SVladimir Oltean REG(ANA_ISOLATED_PORTS, 0x0089c8), 5556051948SVladimir Oltean REG(ANA_COMMUNITY_PORTS, 0x0089cc), 5656051948SVladimir Oltean REG(ANA_AUTOAGE, 0x0089d0), 5756051948SVladimir Oltean REG(ANA_MACTOPTIONS, 0x0089d4), 5856051948SVladimir Oltean REG(ANA_LEARNDISC, 0x0089d8), 5956051948SVladimir Oltean REG(ANA_AGENCTRL, 0x0089dc), 6056051948SVladimir Oltean REG(ANA_MIRRORPORTS, 0x0089e0), 6156051948SVladimir Oltean REG(ANA_EMIRRORPORTS, 0x0089e4), 6256051948SVladimir Oltean REG(ANA_FLOODING, 0x0089e8), 6356051948SVladimir Oltean REG(ANA_FLOODING_IPMC, 0x008a08), 6456051948SVladimir Oltean REG(ANA_SFLOW_CFG, 0x008a0c), 6556051948SVladimir Oltean REG(ANA_PORT_MODE, 0x008a28), 6656051948SVladimir Oltean REG(ANA_CUT_THRU_CFG, 0x008a48), 6756051948SVladimir Oltean REG(ANA_PGID_PGID, 0x008400), 6856051948SVladimir Oltean REG(ANA_TABLES_ANMOVED, 0x007f1c), 6956051948SVladimir Oltean REG(ANA_TABLES_MACHDATA, 0x007f20), 7056051948SVladimir Oltean REG(ANA_TABLES_MACLDATA, 0x007f24), 7156051948SVladimir Oltean REG(ANA_TABLES_STREAMDATA, 0x007f28), 7256051948SVladimir Oltean REG(ANA_TABLES_MACACCESS, 0x007f2c), 7356051948SVladimir Oltean REG(ANA_TABLES_MACTINDX, 0x007f30), 7456051948SVladimir Oltean REG(ANA_TABLES_VLANACCESS, 0x007f34), 7556051948SVladimir Oltean REG(ANA_TABLES_VLANTIDX, 0x007f38), 7656051948SVladimir Oltean REG(ANA_TABLES_ISDXACCESS, 0x007f3c), 7756051948SVladimir Oltean REG(ANA_TABLES_ISDXTIDX, 0x007f40), 7856051948SVladimir Oltean REG(ANA_TABLES_ENTRYLIM, 0x007f00), 7956051948SVladimir Oltean REG(ANA_TABLES_PTP_ID_HIGH, 0x007f44), 8056051948SVladimir Oltean REG(ANA_TABLES_PTP_ID_LOW, 0x007f48), 8156051948SVladimir Oltean REG(ANA_TABLES_STREAMACCESS, 0x007f4c), 8256051948SVladimir Oltean REG(ANA_TABLES_STREAMTIDX, 0x007f50), 8356051948SVladimir Oltean REG(ANA_TABLES_SEQ_HISTORY, 0x007f54), 8456051948SVladimir Oltean REG(ANA_TABLES_SEQ_MASK, 0x007f58), 8556051948SVladimir Oltean REG(ANA_TABLES_SFID_MASK, 0x007f5c), 8656051948SVladimir Oltean REG(ANA_TABLES_SFIDACCESS, 0x007f60), 8756051948SVladimir Oltean REG(ANA_TABLES_SFIDTIDX, 0x007f64), 8856051948SVladimir Oltean REG(ANA_MSTI_STATE, 0x008600), 8956051948SVladimir Oltean REG(ANA_OAM_UPM_LM_CNT, 0x008000), 9056051948SVladimir Oltean REG(ANA_SG_ACCESS_CTRL, 0x008a64), 9156051948SVladimir Oltean REG(ANA_SG_CONFIG_REG_1, 0x007fb0), 9256051948SVladimir Oltean REG(ANA_SG_CONFIG_REG_2, 0x007fb4), 9356051948SVladimir Oltean REG(ANA_SG_CONFIG_REG_3, 0x007fb8), 9456051948SVladimir Oltean REG(ANA_SG_CONFIG_REG_4, 0x007fbc), 9556051948SVladimir Oltean REG(ANA_SG_CONFIG_REG_5, 0x007fc0), 9656051948SVladimir Oltean REG(ANA_SG_GCL_GS_CONFIG, 0x007f80), 9756051948SVladimir Oltean REG(ANA_SG_GCL_TI_CONFIG, 0x007f90), 9856051948SVladimir Oltean REG(ANA_SG_STATUS_REG_1, 0x008980), 9956051948SVladimir Oltean REG(ANA_SG_STATUS_REG_2, 0x008984), 10056051948SVladimir Oltean REG(ANA_SG_STATUS_REG_3, 0x008988), 10156051948SVladimir Oltean REG(ANA_PORT_VLAN_CFG, 0x007800), 10256051948SVladimir Oltean REG(ANA_PORT_DROP_CFG, 0x007804), 10356051948SVladimir Oltean REG(ANA_PORT_QOS_CFG, 0x007808), 10456051948SVladimir Oltean REG(ANA_PORT_VCAP_CFG, 0x00780c), 10556051948SVladimir Oltean REG(ANA_PORT_VCAP_S1_KEY_CFG, 0x007810), 10656051948SVladimir Oltean REG(ANA_PORT_VCAP_S2_CFG, 0x00781c), 10756051948SVladimir Oltean REG(ANA_PORT_PCP_DEI_MAP, 0x007820), 10856051948SVladimir Oltean REG(ANA_PORT_CPU_FWD_CFG, 0x007860), 10956051948SVladimir Oltean REG(ANA_PORT_CPU_FWD_BPDU_CFG, 0x007864), 11056051948SVladimir Oltean REG(ANA_PORT_CPU_FWD_GARP_CFG, 0x007868), 11156051948SVladimir Oltean REG(ANA_PORT_CPU_FWD_CCM_CFG, 0x00786c), 11256051948SVladimir Oltean REG(ANA_PORT_PORT_CFG, 0x007870), 11356051948SVladimir Oltean REG(ANA_PORT_POL_CFG, 0x007874), 11456051948SVladimir Oltean REG(ANA_PORT_PTP_CFG, 0x007878), 11556051948SVladimir Oltean REG(ANA_PORT_PTP_DLY1_CFG, 0x00787c), 11656051948SVladimir Oltean REG(ANA_PORT_PTP_DLY2_CFG, 0x007880), 11756051948SVladimir Oltean REG(ANA_PORT_SFID_CFG, 0x007884), 11856051948SVladimir Oltean REG(ANA_PFC_PFC_CFG, 0x008800), 11956051948SVladimir Oltean REG_RESERVED(ANA_PFC_PFC_TIMER), 12056051948SVladimir Oltean REG_RESERVED(ANA_IPT_OAM_MEP_CFG), 12156051948SVladimir Oltean REG_RESERVED(ANA_IPT_IPT), 12256051948SVladimir Oltean REG_RESERVED(ANA_PPT_PPT), 12356051948SVladimir Oltean REG_RESERVED(ANA_FID_MAP_FID_MAP), 12456051948SVladimir Oltean REG(ANA_AGGR_CFG, 0x008a68), 12556051948SVladimir Oltean REG(ANA_CPUQ_CFG, 0x008a6c), 12656051948SVladimir Oltean REG_RESERVED(ANA_CPUQ_CFG2), 12756051948SVladimir Oltean REG(ANA_CPUQ_8021_CFG, 0x008a74), 12856051948SVladimir Oltean REG(ANA_DSCP_CFG, 0x008ab4), 12956051948SVladimir Oltean REG(ANA_DSCP_REWR_CFG, 0x008bb4), 13056051948SVladimir Oltean REG(ANA_VCAP_RNG_TYPE_CFG, 0x008bf4), 13156051948SVladimir Oltean REG(ANA_VCAP_RNG_VAL_CFG, 0x008c14), 13256051948SVladimir Oltean REG_RESERVED(ANA_VRAP_CFG), 13356051948SVladimir Oltean REG_RESERVED(ANA_VRAP_HDR_DATA), 13456051948SVladimir Oltean REG_RESERVED(ANA_VRAP_HDR_MASK), 13556051948SVladimir Oltean REG(ANA_DISCARD_CFG, 0x008c40), 13656051948SVladimir Oltean REG(ANA_FID_CFG, 0x008c44), 13756051948SVladimir Oltean REG(ANA_POL_PIR_CFG, 0x004000), 13856051948SVladimir Oltean REG(ANA_POL_CIR_CFG, 0x004004), 13956051948SVladimir Oltean REG(ANA_POL_MODE_CFG, 0x004008), 14056051948SVladimir Oltean REG(ANA_POL_PIR_STATE, 0x00400c), 14156051948SVladimir Oltean REG(ANA_POL_CIR_STATE, 0x004010), 14256051948SVladimir Oltean REG_RESERVED(ANA_POL_STATE), 14356051948SVladimir Oltean REG(ANA_POL_FLOWC, 0x008c48), 14456051948SVladimir Oltean REG(ANA_POL_HYST, 0x008cb4), 14556051948SVladimir Oltean REG_RESERVED(ANA_POL_MISC_CFG), 14656051948SVladimir Oltean }; 14756051948SVladimir Oltean 14856051948SVladimir Oltean static const u32 vsc9959_qs_regmap[] = { 14956051948SVladimir Oltean REG(QS_XTR_GRP_CFG, 0x000000), 15056051948SVladimir Oltean REG(QS_XTR_RD, 0x000008), 15156051948SVladimir Oltean REG(QS_XTR_FRM_PRUNING, 0x000010), 15256051948SVladimir Oltean REG(QS_XTR_FLUSH, 0x000018), 15356051948SVladimir Oltean REG(QS_XTR_DATA_PRESENT, 0x00001c), 15456051948SVladimir Oltean REG(QS_XTR_CFG, 0x000020), 15556051948SVladimir Oltean REG(QS_INJ_GRP_CFG, 0x000024), 15656051948SVladimir Oltean REG(QS_INJ_WR, 0x00002c), 15756051948SVladimir Oltean REG(QS_INJ_CTRL, 0x000034), 15856051948SVladimir Oltean REG(QS_INJ_STATUS, 0x00003c), 15956051948SVladimir Oltean REG(QS_INJ_ERR, 0x000040), 16056051948SVladimir Oltean REG_RESERVED(QS_INH_DBG), 16156051948SVladimir Oltean }; 16256051948SVladimir Oltean 163c1c3993eSVladimir Oltean static const u32 vsc9959_vcap_regmap[] = { 164c1c3993eSVladimir Oltean /* VCAP_CORE_CFG */ 165c1c3993eSVladimir Oltean REG(VCAP_CORE_UPDATE_CTRL, 0x000000), 166c1c3993eSVladimir Oltean REG(VCAP_CORE_MV_CFG, 0x000004), 167c1c3993eSVladimir Oltean /* VCAP_CORE_CACHE */ 168c1c3993eSVladimir Oltean REG(VCAP_CACHE_ENTRY_DAT, 0x000008), 169c1c3993eSVladimir Oltean REG(VCAP_CACHE_MASK_DAT, 0x000108), 170c1c3993eSVladimir Oltean REG(VCAP_CACHE_ACTION_DAT, 0x000208), 171c1c3993eSVladimir Oltean REG(VCAP_CACHE_CNT_DAT, 0x000308), 172c1c3993eSVladimir Oltean REG(VCAP_CACHE_TG_DAT, 0x000388), 17320968054SVladimir Oltean /* VCAP_CONST */ 17420968054SVladimir Oltean REG(VCAP_CONST_VCAP_VER, 0x000398), 17520968054SVladimir Oltean REG(VCAP_CONST_ENTRY_WIDTH, 0x00039c), 17620968054SVladimir Oltean REG(VCAP_CONST_ENTRY_CNT, 0x0003a0), 17720968054SVladimir Oltean REG(VCAP_CONST_ENTRY_SWCNT, 0x0003a4), 17820968054SVladimir Oltean REG(VCAP_CONST_ENTRY_TG_WIDTH, 0x0003a8), 17920968054SVladimir Oltean REG(VCAP_CONST_ACTION_DEF_CNT, 0x0003ac), 18020968054SVladimir Oltean REG(VCAP_CONST_ACTION_WIDTH, 0x0003b0), 18120968054SVladimir Oltean REG(VCAP_CONST_CNT_WIDTH, 0x0003b4), 18220968054SVladimir Oltean REG(VCAP_CONST_CORE_CNT, 0x0003b8), 18320968054SVladimir Oltean REG(VCAP_CONST_IF_CNT, 0x0003bc), 18456051948SVladimir Oltean }; 18556051948SVladimir Oltean 18656051948SVladimir Oltean static const u32 vsc9959_qsys_regmap[] = { 18756051948SVladimir Oltean REG(QSYS_PORT_MODE, 0x00f460), 18856051948SVladimir Oltean REG(QSYS_SWITCH_PORT_MODE, 0x00f480), 18956051948SVladimir Oltean REG(QSYS_STAT_CNT_CFG, 0x00f49c), 19056051948SVladimir Oltean REG(QSYS_EEE_CFG, 0x00f4a0), 19156051948SVladimir Oltean REG(QSYS_EEE_THRES, 0x00f4b8), 19256051948SVladimir Oltean REG(QSYS_IGR_NO_SHARING, 0x00f4bc), 19356051948SVladimir Oltean REG(QSYS_EGR_NO_SHARING, 0x00f4c0), 19456051948SVladimir Oltean REG(QSYS_SW_STATUS, 0x00f4c4), 19556051948SVladimir Oltean REG(QSYS_EXT_CPU_CFG, 0x00f4e0), 19656051948SVladimir Oltean REG_RESERVED(QSYS_PAD_CFG), 19756051948SVladimir Oltean REG(QSYS_CPU_GROUP_MAP, 0x00f4e8), 19856051948SVladimir Oltean REG_RESERVED(QSYS_QMAP), 19956051948SVladimir Oltean REG_RESERVED(QSYS_ISDX_SGRP), 20056051948SVladimir Oltean REG_RESERVED(QSYS_TIMED_FRAME_ENTRY), 20156051948SVladimir Oltean REG(QSYS_TFRM_MISC, 0x00f50c), 20256051948SVladimir Oltean REG(QSYS_TFRM_PORT_DLY, 0x00f510), 20356051948SVladimir Oltean REG(QSYS_TFRM_TIMER_CFG_1, 0x00f514), 20456051948SVladimir Oltean REG(QSYS_TFRM_TIMER_CFG_2, 0x00f518), 20556051948SVladimir Oltean REG(QSYS_TFRM_TIMER_CFG_3, 0x00f51c), 20656051948SVladimir Oltean REG(QSYS_TFRM_TIMER_CFG_4, 0x00f520), 20756051948SVladimir Oltean REG(QSYS_TFRM_TIMER_CFG_5, 0x00f524), 20856051948SVladimir Oltean REG(QSYS_TFRM_TIMER_CFG_6, 0x00f528), 20956051948SVladimir Oltean REG(QSYS_TFRM_TIMER_CFG_7, 0x00f52c), 21056051948SVladimir Oltean REG(QSYS_TFRM_TIMER_CFG_8, 0x00f530), 21156051948SVladimir Oltean REG(QSYS_RED_PROFILE, 0x00f534), 21256051948SVladimir Oltean REG(QSYS_RES_QOS_MODE, 0x00f574), 21356051948SVladimir Oltean REG(QSYS_RES_CFG, 0x00c000), 21456051948SVladimir Oltean REG(QSYS_RES_STAT, 0x00c004), 21556051948SVladimir Oltean REG(QSYS_EGR_DROP_MODE, 0x00f578), 21656051948SVladimir Oltean REG(QSYS_EQ_CTRL, 0x00f57c), 21756051948SVladimir Oltean REG_RESERVED(QSYS_EVENTS_CORE), 21856051948SVladimir Oltean REG(QSYS_QMAXSDU_CFG_0, 0x00f584), 21956051948SVladimir Oltean REG(QSYS_QMAXSDU_CFG_1, 0x00f5a0), 22056051948SVladimir Oltean REG(QSYS_QMAXSDU_CFG_2, 0x00f5bc), 22156051948SVladimir Oltean REG(QSYS_QMAXSDU_CFG_3, 0x00f5d8), 22256051948SVladimir Oltean REG(QSYS_QMAXSDU_CFG_4, 0x00f5f4), 22356051948SVladimir Oltean REG(QSYS_QMAXSDU_CFG_5, 0x00f610), 22456051948SVladimir Oltean REG(QSYS_QMAXSDU_CFG_6, 0x00f62c), 22556051948SVladimir Oltean REG(QSYS_QMAXSDU_CFG_7, 0x00f648), 22656051948SVladimir Oltean REG(QSYS_PREEMPTION_CFG, 0x00f664), 2270fbabf87SXiaoliang Yang REG(QSYS_CIR_CFG, 0x000000), 22856051948SVladimir Oltean REG(QSYS_EIR_CFG, 0x000004), 22956051948SVladimir Oltean REG(QSYS_SE_CFG, 0x000008), 23056051948SVladimir Oltean REG(QSYS_SE_DWRR_CFG, 0x00000c), 23156051948SVladimir Oltean REG_RESERVED(QSYS_SE_CONNECT), 23256051948SVladimir Oltean REG(QSYS_SE_DLB_SENSE, 0x000040), 23356051948SVladimir Oltean REG(QSYS_CIR_STATE, 0x000044), 23456051948SVladimir Oltean REG(QSYS_EIR_STATE, 0x000048), 23556051948SVladimir Oltean REG_RESERVED(QSYS_SE_STATE), 23656051948SVladimir Oltean REG(QSYS_HSCH_MISC_CFG, 0x00f67c), 23756051948SVladimir Oltean REG(QSYS_TAG_CONFIG, 0x00f680), 23856051948SVladimir Oltean REG(QSYS_TAS_PARAM_CFG_CTRL, 0x00f698), 23956051948SVladimir Oltean REG(QSYS_PORT_MAX_SDU, 0x00f69c), 24056051948SVladimir Oltean REG(QSYS_PARAM_CFG_REG_1, 0x00f440), 24156051948SVladimir Oltean REG(QSYS_PARAM_CFG_REG_2, 0x00f444), 24256051948SVladimir Oltean REG(QSYS_PARAM_CFG_REG_3, 0x00f448), 24356051948SVladimir Oltean REG(QSYS_PARAM_CFG_REG_4, 0x00f44c), 24456051948SVladimir Oltean REG(QSYS_PARAM_CFG_REG_5, 0x00f450), 24556051948SVladimir Oltean REG(QSYS_GCL_CFG_REG_1, 0x00f454), 24656051948SVladimir Oltean REG(QSYS_GCL_CFG_REG_2, 0x00f458), 24756051948SVladimir Oltean REG(QSYS_PARAM_STATUS_REG_1, 0x00f400), 24856051948SVladimir Oltean REG(QSYS_PARAM_STATUS_REG_2, 0x00f404), 24956051948SVladimir Oltean REG(QSYS_PARAM_STATUS_REG_3, 0x00f408), 25056051948SVladimir Oltean REG(QSYS_PARAM_STATUS_REG_4, 0x00f40c), 25156051948SVladimir Oltean REG(QSYS_PARAM_STATUS_REG_5, 0x00f410), 25256051948SVladimir Oltean REG(QSYS_PARAM_STATUS_REG_6, 0x00f414), 25356051948SVladimir Oltean REG(QSYS_PARAM_STATUS_REG_7, 0x00f418), 25456051948SVladimir Oltean REG(QSYS_PARAM_STATUS_REG_8, 0x00f41c), 25556051948SVladimir Oltean REG(QSYS_PARAM_STATUS_REG_9, 0x00f420), 25656051948SVladimir Oltean REG(QSYS_GCL_STATUS_REG_1, 0x00f424), 25756051948SVladimir Oltean REG(QSYS_GCL_STATUS_REG_2, 0x00f428), 25856051948SVladimir Oltean }; 25956051948SVladimir Oltean 26056051948SVladimir Oltean static const u32 vsc9959_rew_regmap[] = { 26156051948SVladimir Oltean REG(REW_PORT_VLAN_CFG, 0x000000), 26256051948SVladimir Oltean REG(REW_TAG_CFG, 0x000004), 26356051948SVladimir Oltean REG(REW_PORT_CFG, 0x000008), 26456051948SVladimir Oltean REG(REW_DSCP_CFG, 0x00000c), 26556051948SVladimir Oltean REG(REW_PCP_DEI_QOS_MAP_CFG, 0x000010), 26656051948SVladimir Oltean REG(REW_PTP_CFG, 0x000050), 26756051948SVladimir Oltean REG(REW_PTP_DLY1_CFG, 0x000054), 26856051948SVladimir Oltean REG(REW_RED_TAG_CFG, 0x000058), 26956051948SVladimir Oltean REG(REW_DSCP_REMAP_DP1_CFG, 0x000410), 27056051948SVladimir Oltean REG(REW_DSCP_REMAP_CFG, 0x000510), 27156051948SVladimir Oltean REG_RESERVED(REW_STAT_CFG), 27256051948SVladimir Oltean REG_RESERVED(REW_REW_STICKY), 27356051948SVladimir Oltean REG_RESERVED(REW_PPT), 27456051948SVladimir Oltean }; 27556051948SVladimir Oltean 27656051948SVladimir Oltean static const u32 vsc9959_sys_regmap[] = { 27756051948SVladimir Oltean REG(SYS_COUNT_RX_OCTETS, 0x000000), 278d4c36765SVladimir Oltean REG(SYS_COUNT_RX_UNICAST, 0x000004), 27956051948SVladimir Oltean REG(SYS_COUNT_RX_MULTICAST, 0x000008), 280d4c36765SVladimir Oltean REG(SYS_COUNT_RX_BROADCAST, 0x00000c), 28156051948SVladimir Oltean REG(SYS_COUNT_RX_SHORTS, 0x000010), 28256051948SVladimir Oltean REG(SYS_COUNT_RX_FRAGMENTS, 0x000014), 28356051948SVladimir Oltean REG(SYS_COUNT_RX_JABBERS, 0x000018), 284d4c36765SVladimir Oltean REG(SYS_COUNT_RX_CRC_ALIGN_ERRS, 0x00001c), 285d4c36765SVladimir Oltean REG(SYS_COUNT_RX_SYM_ERRS, 0x000020), 28656051948SVladimir Oltean REG(SYS_COUNT_RX_64, 0x000024), 28756051948SVladimir Oltean REG(SYS_COUNT_RX_65_127, 0x000028), 28856051948SVladimir Oltean REG(SYS_COUNT_RX_128_255, 0x00002c), 2895152de7bSVladimir Oltean REG(SYS_COUNT_RX_256_511, 0x000030), 2905152de7bSVladimir Oltean REG(SYS_COUNT_RX_512_1023, 0x000034), 2915152de7bSVladimir Oltean REG(SYS_COUNT_RX_1024_1526, 0x000038), 2925152de7bSVladimir Oltean REG(SYS_COUNT_RX_1527_MAX, 0x00003c), 2935152de7bSVladimir Oltean REG(SYS_COUNT_RX_PAUSE, 0x000040), 2945152de7bSVladimir Oltean REG(SYS_COUNT_RX_CONTROL, 0x000044), 2955152de7bSVladimir Oltean REG(SYS_COUNT_RX_LONGS, 0x000048), 296d4c36765SVladimir Oltean REG(SYS_COUNT_RX_CLASSIFIED_DROPS, 0x00004c), 297d4c36765SVladimir Oltean REG(SYS_COUNT_RX_RED_PRIO_0, 0x000050), 298d4c36765SVladimir Oltean REG(SYS_COUNT_RX_RED_PRIO_1, 0x000054), 299d4c36765SVladimir Oltean REG(SYS_COUNT_RX_RED_PRIO_2, 0x000058), 300d4c36765SVladimir Oltean REG(SYS_COUNT_RX_RED_PRIO_3, 0x00005c), 301d4c36765SVladimir Oltean REG(SYS_COUNT_RX_RED_PRIO_4, 0x000060), 302d4c36765SVladimir Oltean REG(SYS_COUNT_RX_RED_PRIO_5, 0x000064), 303d4c36765SVladimir Oltean REG(SYS_COUNT_RX_RED_PRIO_6, 0x000068), 304d4c36765SVladimir Oltean REG(SYS_COUNT_RX_RED_PRIO_7, 0x00006c), 305d4c36765SVladimir Oltean REG(SYS_COUNT_RX_YELLOW_PRIO_0, 0x000070), 306d4c36765SVladimir Oltean REG(SYS_COUNT_RX_YELLOW_PRIO_1, 0x000074), 307d4c36765SVladimir Oltean REG(SYS_COUNT_RX_YELLOW_PRIO_2, 0x000078), 308d4c36765SVladimir Oltean REG(SYS_COUNT_RX_YELLOW_PRIO_3, 0x00007c), 309d4c36765SVladimir Oltean REG(SYS_COUNT_RX_YELLOW_PRIO_4, 0x000080), 310d4c36765SVladimir Oltean REG(SYS_COUNT_RX_YELLOW_PRIO_5, 0x000084), 311d4c36765SVladimir Oltean REG(SYS_COUNT_RX_YELLOW_PRIO_6, 0x000088), 312d4c36765SVladimir Oltean REG(SYS_COUNT_RX_YELLOW_PRIO_7, 0x00008c), 313d4c36765SVladimir Oltean REG(SYS_COUNT_RX_GREEN_PRIO_0, 0x000090), 314d4c36765SVladimir Oltean REG(SYS_COUNT_RX_GREEN_PRIO_1, 0x000094), 315d4c36765SVladimir Oltean REG(SYS_COUNT_RX_GREEN_PRIO_2, 0x000098), 316d4c36765SVladimir Oltean REG(SYS_COUNT_RX_GREEN_PRIO_3, 0x00009c), 317d4c36765SVladimir Oltean REG(SYS_COUNT_RX_GREEN_PRIO_4, 0x0000a0), 318d4c36765SVladimir Oltean REG(SYS_COUNT_RX_GREEN_PRIO_5, 0x0000a4), 319d4c36765SVladimir Oltean REG(SYS_COUNT_RX_GREEN_PRIO_6, 0x0000a8), 320d4c36765SVladimir Oltean REG(SYS_COUNT_RX_GREEN_PRIO_7, 0x0000ac), 32156051948SVladimir Oltean REG(SYS_COUNT_TX_OCTETS, 0x000200), 322d4c36765SVladimir Oltean REG(SYS_COUNT_TX_UNICAST, 0x000204), 323d4c36765SVladimir Oltean REG(SYS_COUNT_TX_MULTICAST, 0x000208), 324d4c36765SVladimir Oltean REG(SYS_COUNT_TX_BROADCAST, 0x00020c), 32556051948SVladimir Oltean REG(SYS_COUNT_TX_COLLISION, 0x000210), 32656051948SVladimir Oltean REG(SYS_COUNT_TX_DROPS, 0x000214), 327d4c36765SVladimir Oltean REG(SYS_COUNT_TX_PAUSE, 0x000218), 32856051948SVladimir Oltean REG(SYS_COUNT_TX_64, 0x00021c), 32956051948SVladimir Oltean REG(SYS_COUNT_TX_65_127, 0x000220), 3305152de7bSVladimir Oltean REG(SYS_COUNT_TX_128_255, 0x000224), 3315152de7bSVladimir Oltean REG(SYS_COUNT_TX_256_511, 0x000228), 3325152de7bSVladimir Oltean REG(SYS_COUNT_TX_512_1023, 0x00022c), 3335152de7bSVladimir Oltean REG(SYS_COUNT_TX_1024_1526, 0x000230), 3345152de7bSVladimir Oltean REG(SYS_COUNT_TX_1527_MAX, 0x000234), 335d4c36765SVladimir Oltean REG(SYS_COUNT_TX_YELLOW_PRIO_0, 0x000238), 336d4c36765SVladimir Oltean REG(SYS_COUNT_TX_YELLOW_PRIO_1, 0x00023c), 337d4c36765SVladimir Oltean REG(SYS_COUNT_TX_YELLOW_PRIO_2, 0x000240), 338d4c36765SVladimir Oltean REG(SYS_COUNT_TX_YELLOW_PRIO_3, 0x000244), 339d4c36765SVladimir Oltean REG(SYS_COUNT_TX_YELLOW_PRIO_4, 0x000248), 340d4c36765SVladimir Oltean REG(SYS_COUNT_TX_YELLOW_PRIO_5, 0x00024c), 341d4c36765SVladimir Oltean REG(SYS_COUNT_TX_YELLOW_PRIO_6, 0x000250), 342d4c36765SVladimir Oltean REG(SYS_COUNT_TX_YELLOW_PRIO_7, 0x000254), 343d4c36765SVladimir Oltean REG(SYS_COUNT_TX_GREEN_PRIO_0, 0x000258), 344d4c36765SVladimir Oltean REG(SYS_COUNT_TX_GREEN_PRIO_1, 0x00025c), 345d4c36765SVladimir Oltean REG(SYS_COUNT_TX_GREEN_PRIO_2, 0x000260), 346d4c36765SVladimir Oltean REG(SYS_COUNT_TX_GREEN_PRIO_3, 0x000264), 347d4c36765SVladimir Oltean REG(SYS_COUNT_TX_GREEN_PRIO_4, 0x000268), 348d4c36765SVladimir Oltean REG(SYS_COUNT_TX_GREEN_PRIO_5, 0x00026c), 349d4c36765SVladimir Oltean REG(SYS_COUNT_TX_GREEN_PRIO_6, 0x000270), 350d4c36765SVladimir Oltean REG(SYS_COUNT_TX_GREEN_PRIO_7, 0x000274), 35156051948SVladimir Oltean REG(SYS_COUNT_TX_AGING, 0x000278), 352d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_LOCAL, 0x000400), 353d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_TAIL, 0x000404), 354d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_YELLOW_PRIO_0, 0x000408), 355d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_YELLOW_PRIO_1, 0x00040c), 356d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_YELLOW_PRIO_2, 0x000410), 357d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_YELLOW_PRIO_3, 0x000414), 358d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_YELLOW_PRIO_4, 0x000418), 359d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_YELLOW_PRIO_5, 0x00041c), 360d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_YELLOW_PRIO_6, 0x000420), 361d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_YELLOW_PRIO_7, 0x000424), 362d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_GREEN_PRIO_0, 0x000428), 363d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_GREEN_PRIO_1, 0x00042c), 364d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_GREEN_PRIO_2, 0x000430), 365d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_GREEN_PRIO_3, 0x000434), 366d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_GREEN_PRIO_4, 0x000438), 367d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_GREEN_PRIO_5, 0x00043c), 368d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_GREEN_PRIO_6, 0x000440), 369d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_GREEN_PRIO_7, 0x000444), 37056051948SVladimir Oltean REG(SYS_RESET_CFG, 0x000e00), 37156051948SVladimir Oltean REG(SYS_SR_ETYPE_CFG, 0x000e04), 37256051948SVladimir Oltean REG(SYS_VLAN_ETYPE_CFG, 0x000e08), 37356051948SVladimir Oltean REG(SYS_PORT_MODE, 0x000e0c), 37456051948SVladimir Oltean REG(SYS_FRONT_PORT_MODE, 0x000e2c), 37556051948SVladimir Oltean REG(SYS_FRM_AGING, 0x000e44), 37656051948SVladimir Oltean REG(SYS_STAT_CFG, 0x000e48), 37756051948SVladimir Oltean REG(SYS_SW_STATUS, 0x000e4c), 37856051948SVladimir Oltean REG_RESERVED(SYS_MISC_CFG), 37956051948SVladimir Oltean REG(SYS_REW_MAC_HIGH_CFG, 0x000e6c), 38056051948SVladimir Oltean REG(SYS_REW_MAC_LOW_CFG, 0x000e84), 38156051948SVladimir Oltean REG(SYS_TIMESTAMP_OFFSET, 0x000e9c), 38256051948SVladimir Oltean REG(SYS_PAUSE_CFG, 0x000ea0), 38356051948SVladimir Oltean REG(SYS_PAUSE_TOT_CFG, 0x000ebc), 38456051948SVladimir Oltean REG(SYS_ATOP, 0x000ec0), 38556051948SVladimir Oltean REG(SYS_ATOP_TOT_CFG, 0x000edc), 38656051948SVladimir Oltean REG(SYS_MAC_FC_CFG, 0x000ee0), 38756051948SVladimir Oltean REG(SYS_MMGT, 0x000ef8), 38856051948SVladimir Oltean REG_RESERVED(SYS_MMGT_FAST), 38956051948SVladimir Oltean REG_RESERVED(SYS_EVENTS_DIF), 39056051948SVladimir Oltean REG_RESERVED(SYS_EVENTS_CORE), 3917d4b564dSXiaoliang Yang REG(SYS_CNT, 0x000000), 39256051948SVladimir Oltean REG(SYS_PTP_STATUS, 0x000f14), 39356051948SVladimir Oltean REG(SYS_PTP_TXSTAMP, 0x000f18), 39456051948SVladimir Oltean REG(SYS_PTP_NXT, 0x000f1c), 39556051948SVladimir Oltean REG(SYS_PTP_CFG, 0x000f20), 39656051948SVladimir Oltean REG(SYS_RAM_INIT, 0x000f24), 39756051948SVladimir Oltean REG_RESERVED(SYS_CM_ADDR), 39856051948SVladimir Oltean REG_RESERVED(SYS_CM_DATA_WR), 39956051948SVladimir Oltean REG_RESERVED(SYS_CM_DATA_RD), 40056051948SVladimir Oltean REG_RESERVED(SYS_CM_OP), 40156051948SVladimir Oltean REG_RESERVED(SYS_CM_DATA), 40256051948SVladimir Oltean }; 40356051948SVladimir Oltean 4045df66c48SYangbo Lu static const u32 vsc9959_ptp_regmap[] = { 4055df66c48SYangbo Lu REG(PTP_PIN_CFG, 0x000000), 4065df66c48SYangbo Lu REG(PTP_PIN_TOD_SEC_MSB, 0x000004), 4075df66c48SYangbo Lu REG(PTP_PIN_TOD_SEC_LSB, 0x000008), 4085df66c48SYangbo Lu REG(PTP_PIN_TOD_NSEC, 0x00000c), 40994aca082SYangbo Lu REG(PTP_PIN_WF_HIGH_PERIOD, 0x000014), 41094aca082SYangbo Lu REG(PTP_PIN_WF_LOW_PERIOD, 0x000018), 4115df66c48SYangbo Lu REG(PTP_CFG_MISC, 0x0000a0), 4125df66c48SYangbo Lu REG(PTP_CLK_CFG_ADJ_CFG, 0x0000a4), 4135df66c48SYangbo Lu REG(PTP_CLK_CFG_ADJ_FREQ, 0x0000a8), 4145df66c48SYangbo Lu }; 4155df66c48SYangbo Lu 41656051948SVladimir Oltean static const u32 vsc9959_gcb_regmap[] = { 41756051948SVladimir Oltean REG(GCB_SOFT_RST, 0x000004), 41856051948SVladimir Oltean }; 41956051948SVladimir Oltean 42091c724cfSVladimir Oltean static const u32 vsc9959_dev_gmii_regmap[] = { 42191c724cfSVladimir Oltean REG(DEV_CLOCK_CFG, 0x0), 42291c724cfSVladimir Oltean REG(DEV_PORT_MISC, 0x4), 42391c724cfSVladimir Oltean REG(DEV_EVENTS, 0x8), 42491c724cfSVladimir Oltean REG(DEV_EEE_CFG, 0xc), 42591c724cfSVladimir Oltean REG(DEV_RX_PATH_DELAY, 0x10), 42691c724cfSVladimir Oltean REG(DEV_TX_PATH_DELAY, 0x14), 42791c724cfSVladimir Oltean REG(DEV_PTP_PREDICT_CFG, 0x18), 42891c724cfSVladimir Oltean REG(DEV_MAC_ENA_CFG, 0x1c), 42991c724cfSVladimir Oltean REG(DEV_MAC_MODE_CFG, 0x20), 43091c724cfSVladimir Oltean REG(DEV_MAC_MAXLEN_CFG, 0x24), 43191c724cfSVladimir Oltean REG(DEV_MAC_TAGS_CFG, 0x28), 43291c724cfSVladimir Oltean REG(DEV_MAC_ADV_CHK_CFG, 0x2c), 43391c724cfSVladimir Oltean REG(DEV_MAC_IFG_CFG, 0x30), 43491c724cfSVladimir Oltean REG(DEV_MAC_HDX_CFG, 0x34), 43591c724cfSVladimir Oltean REG(DEV_MAC_DBG_CFG, 0x38), 43691c724cfSVladimir Oltean REG(DEV_MAC_FC_MAC_LOW_CFG, 0x3c), 43791c724cfSVladimir Oltean REG(DEV_MAC_FC_MAC_HIGH_CFG, 0x40), 43891c724cfSVladimir Oltean REG(DEV_MAC_STICKY, 0x44), 43991c724cfSVladimir Oltean REG_RESERVED(PCS1G_CFG), 44091c724cfSVladimir Oltean REG_RESERVED(PCS1G_MODE_CFG), 44191c724cfSVladimir Oltean REG_RESERVED(PCS1G_SD_CFG), 44291c724cfSVladimir Oltean REG_RESERVED(PCS1G_ANEG_CFG), 44391c724cfSVladimir Oltean REG_RESERVED(PCS1G_ANEG_NP_CFG), 44491c724cfSVladimir Oltean REG_RESERVED(PCS1G_LB_CFG), 44591c724cfSVladimir Oltean REG_RESERVED(PCS1G_DBG_CFG), 44691c724cfSVladimir Oltean REG_RESERVED(PCS1G_CDET_CFG), 44791c724cfSVladimir Oltean REG_RESERVED(PCS1G_ANEG_STATUS), 44891c724cfSVladimir Oltean REG_RESERVED(PCS1G_ANEG_NP_STATUS), 44991c724cfSVladimir Oltean REG_RESERVED(PCS1G_LINK_STATUS), 45091c724cfSVladimir Oltean REG_RESERVED(PCS1G_LINK_DOWN_CNT), 45191c724cfSVladimir Oltean REG_RESERVED(PCS1G_STICKY), 45291c724cfSVladimir Oltean REG_RESERVED(PCS1G_DEBUG_STATUS), 45391c724cfSVladimir Oltean REG_RESERVED(PCS1G_LPI_CFG), 45491c724cfSVladimir Oltean REG_RESERVED(PCS1G_LPI_WAKE_ERROR_CNT), 45591c724cfSVladimir Oltean REG_RESERVED(PCS1G_LPI_STATUS), 45691c724cfSVladimir Oltean REG_RESERVED(PCS1G_TSTPAT_MODE_CFG), 45791c724cfSVladimir Oltean REG_RESERVED(PCS1G_TSTPAT_STATUS), 45891c724cfSVladimir Oltean REG_RESERVED(DEV_PCS_FX100_CFG), 45991c724cfSVladimir Oltean REG_RESERVED(DEV_PCS_FX100_STATUS), 46091c724cfSVladimir Oltean }; 46191c724cfSVladimir Oltean 46291c724cfSVladimir Oltean static const u32 *vsc9959_regmap[TARGET_MAX] = { 46356051948SVladimir Oltean [ANA] = vsc9959_ana_regmap, 46456051948SVladimir Oltean [QS] = vsc9959_qs_regmap, 46556051948SVladimir Oltean [QSYS] = vsc9959_qsys_regmap, 46656051948SVladimir Oltean [REW] = vsc9959_rew_regmap, 46756051948SVladimir Oltean [SYS] = vsc9959_sys_regmap, 468e3aea296SVladimir Oltean [S0] = vsc9959_vcap_regmap, 469a61e365dSVladimir Oltean [S1] = vsc9959_vcap_regmap, 470c1c3993eSVladimir Oltean [S2] = vsc9959_vcap_regmap, 4715df66c48SYangbo Lu [PTP] = vsc9959_ptp_regmap, 47256051948SVladimir Oltean [GCB] = vsc9959_gcb_regmap, 47391c724cfSVladimir Oltean [DEV_GMII] = vsc9959_dev_gmii_regmap, 47456051948SVladimir Oltean }; 47556051948SVladimir Oltean 476b4024c9eSClaudiu Manoil /* Addresses are relative to the PCI device's base address */ 47791c724cfSVladimir Oltean static const struct resource vsc9959_target_io_res[TARGET_MAX] = { 47856051948SVladimir Oltean [ANA] = { 47956051948SVladimir Oltean .start = 0x0280000, 48056051948SVladimir Oltean .end = 0x028ffff, 48156051948SVladimir Oltean .name = "ana", 48256051948SVladimir Oltean }, 48356051948SVladimir Oltean [QS] = { 48456051948SVladimir Oltean .start = 0x0080000, 48556051948SVladimir Oltean .end = 0x00800ff, 48656051948SVladimir Oltean .name = "qs", 48756051948SVladimir Oltean }, 48856051948SVladimir Oltean [QSYS] = { 48956051948SVladimir Oltean .start = 0x0200000, 49056051948SVladimir Oltean .end = 0x021ffff, 49156051948SVladimir Oltean .name = "qsys", 49256051948SVladimir Oltean }, 49356051948SVladimir Oltean [REW] = { 49456051948SVladimir Oltean .start = 0x0030000, 49556051948SVladimir Oltean .end = 0x003ffff, 49656051948SVladimir Oltean .name = "rew", 49756051948SVladimir Oltean }, 49856051948SVladimir Oltean [SYS] = { 49956051948SVladimir Oltean .start = 0x0010000, 50056051948SVladimir Oltean .end = 0x001ffff, 50156051948SVladimir Oltean .name = "sys", 50256051948SVladimir Oltean }, 503e3aea296SVladimir Oltean [S0] = { 504e3aea296SVladimir Oltean .start = 0x0040000, 505e3aea296SVladimir Oltean .end = 0x00403ff, 506e3aea296SVladimir Oltean .name = "s0", 507e3aea296SVladimir Oltean }, 508a61e365dSVladimir Oltean [S1] = { 509a61e365dSVladimir Oltean .start = 0x0050000, 510a61e365dSVladimir Oltean .end = 0x00503ff, 511a61e365dSVladimir Oltean .name = "s1", 512a61e365dSVladimir Oltean }, 51356051948SVladimir Oltean [S2] = { 51456051948SVladimir Oltean .start = 0x0060000, 51556051948SVladimir Oltean .end = 0x00603ff, 51656051948SVladimir Oltean .name = "s2", 51756051948SVladimir Oltean }, 5185df66c48SYangbo Lu [PTP] = { 5195df66c48SYangbo Lu .start = 0x0090000, 5205df66c48SYangbo Lu .end = 0x00900cb, 5215df66c48SYangbo Lu .name = "ptp", 5225df66c48SYangbo Lu }, 52356051948SVladimir Oltean [GCB] = { 52456051948SVladimir Oltean .start = 0x0070000, 52556051948SVladimir Oltean .end = 0x00701ff, 52656051948SVladimir Oltean .name = "devcpu_gcb", 52756051948SVladimir Oltean }, 52856051948SVladimir Oltean }; 52956051948SVladimir Oltean 530b4024c9eSClaudiu Manoil static const struct resource vsc9959_port_io_res[] = { 53156051948SVladimir Oltean { 53256051948SVladimir Oltean .start = 0x0100000, 53356051948SVladimir Oltean .end = 0x010ffff, 53456051948SVladimir Oltean .name = "port0", 53556051948SVladimir Oltean }, 53656051948SVladimir Oltean { 53756051948SVladimir Oltean .start = 0x0110000, 53856051948SVladimir Oltean .end = 0x011ffff, 53956051948SVladimir Oltean .name = "port1", 54056051948SVladimir Oltean }, 54156051948SVladimir Oltean { 54256051948SVladimir Oltean .start = 0x0120000, 54356051948SVladimir Oltean .end = 0x012ffff, 54456051948SVladimir Oltean .name = "port2", 54556051948SVladimir Oltean }, 54656051948SVladimir Oltean { 54756051948SVladimir Oltean .start = 0x0130000, 54856051948SVladimir Oltean .end = 0x013ffff, 54956051948SVladimir Oltean .name = "port3", 55056051948SVladimir Oltean }, 55156051948SVladimir Oltean { 55256051948SVladimir Oltean .start = 0x0140000, 55356051948SVladimir Oltean .end = 0x014ffff, 55456051948SVladimir Oltean .name = "port4", 55556051948SVladimir Oltean }, 55656051948SVladimir Oltean { 55756051948SVladimir Oltean .start = 0x0150000, 55856051948SVladimir Oltean .end = 0x015ffff, 55956051948SVladimir Oltean .name = "port5", 56056051948SVladimir Oltean }, 56156051948SVladimir Oltean }; 56256051948SVladimir Oltean 563bdeced75SVladimir Oltean /* Port MAC 0 Internal MDIO bus through which the SerDes acting as an 564bdeced75SVladimir Oltean * SGMII/QSGMII MAC PCS can be found. 565bdeced75SVladimir Oltean */ 566b4024c9eSClaudiu Manoil static const struct resource vsc9959_imdio_res = { 567bdeced75SVladimir Oltean .start = 0x8030, 568bdeced75SVladimir Oltean .end = 0x8040, 569bdeced75SVladimir Oltean .name = "imdio", 570bdeced75SVladimir Oltean }; 571bdeced75SVladimir Oltean 5722789658fSMaxim Kochetkov static const struct reg_field vsc9959_regfields[REGFIELD_MAX] = { 57356051948SVladimir Oltean [ANA_ADVLEARN_VLAN_CHK] = REG_FIELD(ANA_ADVLEARN, 6, 6), 57456051948SVladimir Oltean [ANA_ADVLEARN_LEARN_MIRROR] = REG_FIELD(ANA_ADVLEARN, 0, 5), 57556051948SVladimir Oltean [ANA_ANEVENTS_FLOOD_DISCARD] = REG_FIELD(ANA_ANEVENTS, 30, 30), 57656051948SVladimir Oltean [ANA_ANEVENTS_AUTOAGE] = REG_FIELD(ANA_ANEVENTS, 26, 26), 57756051948SVladimir Oltean [ANA_ANEVENTS_STORM_DROP] = REG_FIELD(ANA_ANEVENTS, 24, 24), 57856051948SVladimir Oltean [ANA_ANEVENTS_LEARN_DROP] = REG_FIELD(ANA_ANEVENTS, 23, 23), 57956051948SVladimir Oltean [ANA_ANEVENTS_AGED_ENTRY] = REG_FIELD(ANA_ANEVENTS, 22, 22), 58056051948SVladimir Oltean [ANA_ANEVENTS_CPU_LEARN_FAILED] = REG_FIELD(ANA_ANEVENTS, 21, 21), 58156051948SVladimir Oltean [ANA_ANEVENTS_AUTO_LEARN_FAILED] = REG_FIELD(ANA_ANEVENTS, 20, 20), 58256051948SVladimir Oltean [ANA_ANEVENTS_LEARN_REMOVE] = REG_FIELD(ANA_ANEVENTS, 19, 19), 58356051948SVladimir Oltean [ANA_ANEVENTS_AUTO_LEARNED] = REG_FIELD(ANA_ANEVENTS, 18, 18), 58456051948SVladimir Oltean [ANA_ANEVENTS_AUTO_MOVED] = REG_FIELD(ANA_ANEVENTS, 17, 17), 58556051948SVladimir Oltean [ANA_ANEVENTS_CLASSIFIED_DROP] = REG_FIELD(ANA_ANEVENTS, 15, 15), 58656051948SVladimir Oltean [ANA_ANEVENTS_CLASSIFIED_COPY] = REG_FIELD(ANA_ANEVENTS, 14, 14), 58756051948SVladimir Oltean [ANA_ANEVENTS_VLAN_DISCARD] = REG_FIELD(ANA_ANEVENTS, 13, 13), 58856051948SVladimir Oltean [ANA_ANEVENTS_FWD_DISCARD] = REG_FIELD(ANA_ANEVENTS, 12, 12), 58956051948SVladimir Oltean [ANA_ANEVENTS_MULTICAST_FLOOD] = REG_FIELD(ANA_ANEVENTS, 11, 11), 59056051948SVladimir Oltean [ANA_ANEVENTS_UNICAST_FLOOD] = REG_FIELD(ANA_ANEVENTS, 10, 10), 59156051948SVladimir Oltean [ANA_ANEVENTS_DEST_KNOWN] = REG_FIELD(ANA_ANEVENTS, 9, 9), 59256051948SVladimir Oltean [ANA_ANEVENTS_BUCKET3_MATCH] = REG_FIELD(ANA_ANEVENTS, 8, 8), 59356051948SVladimir Oltean [ANA_ANEVENTS_BUCKET2_MATCH] = REG_FIELD(ANA_ANEVENTS, 7, 7), 59456051948SVladimir Oltean [ANA_ANEVENTS_BUCKET1_MATCH] = REG_FIELD(ANA_ANEVENTS, 6, 6), 59556051948SVladimir Oltean [ANA_ANEVENTS_BUCKET0_MATCH] = REG_FIELD(ANA_ANEVENTS, 5, 5), 59656051948SVladimir Oltean [ANA_ANEVENTS_CPU_OPERATION] = REG_FIELD(ANA_ANEVENTS, 4, 4), 59756051948SVladimir Oltean [ANA_ANEVENTS_DMAC_LOOKUP] = REG_FIELD(ANA_ANEVENTS, 3, 3), 59856051948SVladimir Oltean [ANA_ANEVENTS_SMAC_LOOKUP] = REG_FIELD(ANA_ANEVENTS, 2, 2), 59956051948SVladimir Oltean [ANA_ANEVENTS_SEQ_GEN_ERR_0] = REG_FIELD(ANA_ANEVENTS, 1, 1), 60056051948SVladimir Oltean [ANA_ANEVENTS_SEQ_GEN_ERR_1] = REG_FIELD(ANA_ANEVENTS, 0, 0), 60156051948SVladimir Oltean [ANA_TABLES_MACACCESS_B_DOM] = REG_FIELD(ANA_TABLES_MACACCESS, 16, 16), 60256051948SVladimir Oltean [ANA_TABLES_MACTINDX_BUCKET] = REG_FIELD(ANA_TABLES_MACTINDX, 11, 12), 60356051948SVladimir Oltean [ANA_TABLES_MACTINDX_M_INDEX] = REG_FIELD(ANA_TABLES_MACTINDX, 0, 10), 60456051948SVladimir Oltean [SYS_RESET_CFG_CORE_ENA] = REG_FIELD(SYS_RESET_CFG, 0, 0), 60556051948SVladimir Oltean [GCB_SOFT_RST_SWC_RST] = REG_FIELD(GCB_SOFT_RST, 0, 0), 606886e1387SVladimir Oltean /* Replicated per number of ports (7), register size 4 per port */ 607886e1387SVladimir Oltean [QSYS_SWITCH_PORT_MODE_PORT_ENA] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 14, 14, 7, 4), 608886e1387SVladimir Oltean [QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 11, 13, 7, 4), 609886e1387SVladimir Oltean [QSYS_SWITCH_PORT_MODE_YEL_RSRVD] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 10, 10, 7, 4), 610886e1387SVladimir Oltean [QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 9, 9, 7, 4), 611886e1387SVladimir Oltean [QSYS_SWITCH_PORT_MODE_TX_PFC_ENA] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 1, 8, 7, 4), 612886e1387SVladimir Oltean [QSYS_SWITCH_PORT_MODE_TX_PFC_MODE] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 0, 0, 7, 4), 613886e1387SVladimir Oltean [SYS_PORT_MODE_DATA_WO_TS] = REG_FIELD_ID(SYS_PORT_MODE, 5, 6, 7, 4), 614886e1387SVladimir Oltean [SYS_PORT_MODE_INCL_INJ_HDR] = REG_FIELD_ID(SYS_PORT_MODE, 3, 4, 7, 4), 615886e1387SVladimir Oltean [SYS_PORT_MODE_INCL_XTR_HDR] = REG_FIELD_ID(SYS_PORT_MODE, 1, 2, 7, 4), 616886e1387SVladimir Oltean [SYS_PORT_MODE_INCL_HDR_ERR] = REG_FIELD_ID(SYS_PORT_MODE, 0, 0, 7, 4), 617541132f0SMaxim Kochetkov [SYS_PAUSE_CFG_PAUSE_START] = REG_FIELD_ID(SYS_PAUSE_CFG, 10, 18, 7, 4), 618541132f0SMaxim Kochetkov [SYS_PAUSE_CFG_PAUSE_STOP] = REG_FIELD_ID(SYS_PAUSE_CFG, 1, 9, 7, 4), 619541132f0SMaxim Kochetkov [SYS_PAUSE_CFG_PAUSE_ENA] = REG_FIELD_ID(SYS_PAUSE_CFG, 0, 1, 7, 4), 62056051948SVladimir Oltean }; 62156051948SVladimir Oltean 62291904600SVladimir Oltean static const struct ocelot_stat_layout vsc9959_stats_layout[OCELOT_NUM_STATS] = { 62391904600SVladimir Oltean [OCELOT_STAT_RX_OCTETS] = { 62491904600SVladimir Oltean .name = "rx_octets", 625d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_OCTETS, 62691904600SVladimir Oltean }, 62791904600SVladimir Oltean [OCELOT_STAT_RX_UNICAST] = { 62891904600SVladimir Oltean .name = "rx_unicast", 629d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_UNICAST, 63091904600SVladimir Oltean }, 63191904600SVladimir Oltean [OCELOT_STAT_RX_MULTICAST] = { 63291904600SVladimir Oltean .name = "rx_multicast", 633d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_MULTICAST, 63491904600SVladimir Oltean }, 63591904600SVladimir Oltean [OCELOT_STAT_RX_BROADCAST] = { 63691904600SVladimir Oltean .name = "rx_broadcast", 637d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_BROADCAST, 63891904600SVladimir Oltean }, 63991904600SVladimir Oltean [OCELOT_STAT_RX_SHORTS] = { 64091904600SVladimir Oltean .name = "rx_shorts", 641d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_SHORTS, 64291904600SVladimir Oltean }, 64391904600SVladimir Oltean [OCELOT_STAT_RX_FRAGMENTS] = { 64491904600SVladimir Oltean .name = "rx_fragments", 645d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_FRAGMENTS, 64691904600SVladimir Oltean }, 64791904600SVladimir Oltean [OCELOT_STAT_RX_JABBERS] = { 64891904600SVladimir Oltean .name = "rx_jabbers", 649d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_JABBERS, 65091904600SVladimir Oltean }, 65191904600SVladimir Oltean [OCELOT_STAT_RX_CRC_ALIGN_ERRS] = { 65291904600SVladimir Oltean .name = "rx_crc_align_errs", 653d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_CRC_ALIGN_ERRS, 65491904600SVladimir Oltean }, 65591904600SVladimir Oltean [OCELOT_STAT_RX_SYM_ERRS] = { 65691904600SVladimir Oltean .name = "rx_sym_errs", 657d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_SYM_ERRS, 65891904600SVladimir Oltean }, 65991904600SVladimir Oltean [OCELOT_STAT_RX_64] = { 66091904600SVladimir Oltean .name = "rx_frames_below_65_octets", 661d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_64, 66291904600SVladimir Oltean }, 66391904600SVladimir Oltean [OCELOT_STAT_RX_65_127] = { 66491904600SVladimir Oltean .name = "rx_frames_65_to_127_octets", 665d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_65_127, 66691904600SVladimir Oltean }, 66791904600SVladimir Oltean [OCELOT_STAT_RX_128_255] = { 66891904600SVladimir Oltean .name = "rx_frames_128_to_255_octets", 669d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_128_255, 67091904600SVladimir Oltean }, 67191904600SVladimir Oltean [OCELOT_STAT_RX_256_511] = { 67291904600SVladimir Oltean .name = "rx_frames_256_to_511_octets", 673d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_256_511, 67491904600SVladimir Oltean }, 67591904600SVladimir Oltean [OCELOT_STAT_RX_512_1023] = { 67691904600SVladimir Oltean .name = "rx_frames_512_to_1023_octets", 677d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_512_1023, 67891904600SVladimir Oltean }, 67991904600SVladimir Oltean [OCELOT_STAT_RX_1024_1526] = { 68091904600SVladimir Oltean .name = "rx_frames_1024_to_1526_octets", 681d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_1024_1526, 68291904600SVladimir Oltean }, 68391904600SVladimir Oltean [OCELOT_STAT_RX_1527_MAX] = { 68491904600SVladimir Oltean .name = "rx_frames_over_1526_octets", 685d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_1527_MAX, 68691904600SVladimir Oltean }, 68791904600SVladimir Oltean [OCELOT_STAT_RX_PAUSE] = { 68891904600SVladimir Oltean .name = "rx_pause", 689d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_PAUSE, 69091904600SVladimir Oltean }, 69191904600SVladimir Oltean [OCELOT_STAT_RX_CONTROL] = { 69291904600SVladimir Oltean .name = "rx_control", 693d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_CONTROL, 69491904600SVladimir Oltean }, 69591904600SVladimir Oltean [OCELOT_STAT_RX_LONGS] = { 69691904600SVladimir Oltean .name = "rx_longs", 697d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_LONGS, 69891904600SVladimir Oltean }, 69991904600SVladimir Oltean [OCELOT_STAT_RX_CLASSIFIED_DROPS] = { 70091904600SVladimir Oltean .name = "rx_classified_drops", 701d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_CLASSIFIED_DROPS, 70291904600SVladimir Oltean }, 70391904600SVladimir Oltean [OCELOT_STAT_RX_RED_PRIO_0] = { 70491904600SVladimir Oltean .name = "rx_red_prio_0", 705d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_RED_PRIO_0, 70691904600SVladimir Oltean }, 70791904600SVladimir Oltean [OCELOT_STAT_RX_RED_PRIO_1] = { 70891904600SVladimir Oltean .name = "rx_red_prio_1", 709d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_RED_PRIO_1, 71091904600SVladimir Oltean }, 71191904600SVladimir Oltean [OCELOT_STAT_RX_RED_PRIO_2] = { 71291904600SVladimir Oltean .name = "rx_red_prio_2", 713d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_RED_PRIO_2, 71491904600SVladimir Oltean }, 71591904600SVladimir Oltean [OCELOT_STAT_RX_RED_PRIO_3] = { 71691904600SVladimir Oltean .name = "rx_red_prio_3", 717d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_RED_PRIO_3, 71891904600SVladimir Oltean }, 71991904600SVladimir Oltean [OCELOT_STAT_RX_RED_PRIO_4] = { 72091904600SVladimir Oltean .name = "rx_red_prio_4", 721d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_RED_PRIO_4, 72291904600SVladimir Oltean }, 72391904600SVladimir Oltean [OCELOT_STAT_RX_RED_PRIO_5] = { 72491904600SVladimir Oltean .name = "rx_red_prio_5", 725d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_RED_PRIO_5, 72691904600SVladimir Oltean }, 72791904600SVladimir Oltean [OCELOT_STAT_RX_RED_PRIO_6] = { 72891904600SVladimir Oltean .name = "rx_red_prio_6", 729d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_RED_PRIO_6, 73091904600SVladimir Oltean }, 73191904600SVladimir Oltean [OCELOT_STAT_RX_RED_PRIO_7] = { 73291904600SVladimir Oltean .name = "rx_red_prio_7", 733d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_RED_PRIO_7, 73491904600SVladimir Oltean }, 73591904600SVladimir Oltean [OCELOT_STAT_RX_YELLOW_PRIO_0] = { 73691904600SVladimir Oltean .name = "rx_yellow_prio_0", 737d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_YELLOW_PRIO_0, 73891904600SVladimir Oltean }, 73991904600SVladimir Oltean [OCELOT_STAT_RX_YELLOW_PRIO_1] = { 74091904600SVladimir Oltean .name = "rx_yellow_prio_1", 741d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_YELLOW_PRIO_1, 74291904600SVladimir Oltean }, 74391904600SVladimir Oltean [OCELOT_STAT_RX_YELLOW_PRIO_2] = { 74491904600SVladimir Oltean .name = "rx_yellow_prio_2", 745d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_YELLOW_PRIO_2, 74691904600SVladimir Oltean }, 74791904600SVladimir Oltean [OCELOT_STAT_RX_YELLOW_PRIO_3] = { 74891904600SVladimir Oltean .name = "rx_yellow_prio_3", 749d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_YELLOW_PRIO_3, 75091904600SVladimir Oltean }, 75191904600SVladimir Oltean [OCELOT_STAT_RX_YELLOW_PRIO_4] = { 75291904600SVladimir Oltean .name = "rx_yellow_prio_4", 753d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_YELLOW_PRIO_4, 75491904600SVladimir Oltean }, 75591904600SVladimir Oltean [OCELOT_STAT_RX_YELLOW_PRIO_5] = { 75691904600SVladimir Oltean .name = "rx_yellow_prio_5", 757d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_YELLOW_PRIO_5, 75891904600SVladimir Oltean }, 75991904600SVladimir Oltean [OCELOT_STAT_RX_YELLOW_PRIO_6] = { 76091904600SVladimir Oltean .name = "rx_yellow_prio_6", 761d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_YELLOW_PRIO_6, 76291904600SVladimir Oltean }, 76391904600SVladimir Oltean [OCELOT_STAT_RX_YELLOW_PRIO_7] = { 76491904600SVladimir Oltean .name = "rx_yellow_prio_7", 765d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_YELLOW_PRIO_7, 76691904600SVladimir Oltean }, 76791904600SVladimir Oltean [OCELOT_STAT_RX_GREEN_PRIO_0] = { 76891904600SVladimir Oltean .name = "rx_green_prio_0", 769d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_GREEN_PRIO_0, 77091904600SVladimir Oltean }, 77191904600SVladimir Oltean [OCELOT_STAT_RX_GREEN_PRIO_1] = { 77291904600SVladimir Oltean .name = "rx_green_prio_1", 773d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_GREEN_PRIO_1, 77491904600SVladimir Oltean }, 77591904600SVladimir Oltean [OCELOT_STAT_RX_GREEN_PRIO_2] = { 77691904600SVladimir Oltean .name = "rx_green_prio_2", 777d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_GREEN_PRIO_2, 77891904600SVladimir Oltean }, 77991904600SVladimir Oltean [OCELOT_STAT_RX_GREEN_PRIO_3] = { 78091904600SVladimir Oltean .name = "rx_green_prio_3", 781d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_GREEN_PRIO_3, 78291904600SVladimir Oltean }, 78391904600SVladimir Oltean [OCELOT_STAT_RX_GREEN_PRIO_4] = { 78491904600SVladimir Oltean .name = "rx_green_prio_4", 785d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_GREEN_PRIO_4, 78691904600SVladimir Oltean }, 78791904600SVladimir Oltean [OCELOT_STAT_RX_GREEN_PRIO_5] = { 78891904600SVladimir Oltean .name = "rx_green_prio_5", 789d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_GREEN_PRIO_5, 79091904600SVladimir Oltean }, 79191904600SVladimir Oltean [OCELOT_STAT_RX_GREEN_PRIO_6] = { 79291904600SVladimir Oltean .name = "rx_green_prio_6", 793d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_GREEN_PRIO_6, 79491904600SVladimir Oltean }, 79591904600SVladimir Oltean [OCELOT_STAT_RX_GREEN_PRIO_7] = { 79691904600SVladimir Oltean .name = "rx_green_prio_7", 797d4c36765SVladimir Oltean .reg = SYS_COUNT_RX_GREEN_PRIO_7, 79891904600SVladimir Oltean }, 79991904600SVladimir Oltean [OCELOT_STAT_TX_OCTETS] = { 80091904600SVladimir Oltean .name = "tx_octets", 801d4c36765SVladimir Oltean .reg = SYS_COUNT_TX_OCTETS, 80291904600SVladimir Oltean }, 80391904600SVladimir Oltean [OCELOT_STAT_TX_UNICAST] = { 80491904600SVladimir Oltean .name = "tx_unicast", 805d4c36765SVladimir Oltean .reg = SYS_COUNT_TX_UNICAST, 80691904600SVladimir Oltean }, 80791904600SVladimir Oltean [OCELOT_STAT_TX_MULTICAST] = { 80891904600SVladimir Oltean .name = "tx_multicast", 809d4c36765SVladimir Oltean .reg = SYS_COUNT_TX_MULTICAST, 81091904600SVladimir Oltean }, 81191904600SVladimir Oltean [OCELOT_STAT_TX_BROADCAST] = { 81291904600SVladimir Oltean .name = "tx_broadcast", 813d4c36765SVladimir Oltean .reg = SYS_COUNT_TX_BROADCAST, 81491904600SVladimir Oltean }, 81591904600SVladimir Oltean [OCELOT_STAT_TX_COLLISION] = { 81691904600SVladimir Oltean .name = "tx_collision", 817d4c36765SVladimir Oltean .reg = SYS_COUNT_TX_COLLISION, 81891904600SVladimir Oltean }, 81991904600SVladimir Oltean [OCELOT_STAT_TX_DROPS] = { 82091904600SVladimir Oltean .name = "tx_drops", 821d4c36765SVladimir Oltean .reg = SYS_COUNT_TX_DROPS, 82291904600SVladimir Oltean }, 82391904600SVladimir Oltean [OCELOT_STAT_TX_PAUSE] = { 82491904600SVladimir Oltean .name = "tx_pause", 825d4c36765SVladimir Oltean .reg = SYS_COUNT_TX_PAUSE, 82691904600SVladimir Oltean }, 82791904600SVladimir Oltean [OCELOT_STAT_TX_64] = { 82891904600SVladimir Oltean .name = "tx_frames_below_65_octets", 829d4c36765SVladimir Oltean .reg = SYS_COUNT_TX_64, 83091904600SVladimir Oltean }, 83191904600SVladimir Oltean [OCELOT_STAT_TX_65_127] = { 83291904600SVladimir Oltean .name = "tx_frames_65_to_127_octets", 833d4c36765SVladimir Oltean .reg = SYS_COUNT_TX_65_127, 83491904600SVladimir Oltean }, 83591904600SVladimir Oltean [OCELOT_STAT_TX_128_255] = { 83691904600SVladimir Oltean .name = "tx_frames_128_255_octets", 837d4c36765SVladimir Oltean .reg = SYS_COUNT_TX_128_255, 83891904600SVladimir Oltean }, 83991904600SVladimir Oltean [OCELOT_STAT_TX_256_511] = { 84091904600SVladimir Oltean .name = "tx_frames_256_511_octets", 841d4c36765SVladimir Oltean .reg = SYS_COUNT_TX_256_511, 84291904600SVladimir Oltean }, 84391904600SVladimir Oltean [OCELOT_STAT_TX_512_1023] = { 84491904600SVladimir Oltean .name = "tx_frames_512_1023_octets", 845d4c36765SVladimir Oltean .reg = SYS_COUNT_TX_512_1023, 84691904600SVladimir Oltean }, 84791904600SVladimir Oltean [OCELOT_STAT_TX_1024_1526] = { 84891904600SVladimir Oltean .name = "tx_frames_1024_1526_octets", 849d4c36765SVladimir Oltean .reg = SYS_COUNT_TX_1024_1526, 85091904600SVladimir Oltean }, 85191904600SVladimir Oltean [OCELOT_STAT_TX_1527_MAX] = { 85291904600SVladimir Oltean .name = "tx_frames_over_1526_octets", 853d4c36765SVladimir Oltean .reg = SYS_COUNT_TX_1527_MAX, 85491904600SVladimir Oltean }, 85591904600SVladimir Oltean [OCELOT_STAT_TX_YELLOW_PRIO_0] = { 85691904600SVladimir Oltean .name = "tx_yellow_prio_0", 857d4c36765SVladimir Oltean .reg = SYS_COUNT_TX_YELLOW_PRIO_0, 85891904600SVladimir Oltean }, 85991904600SVladimir Oltean [OCELOT_STAT_TX_YELLOW_PRIO_1] = { 86091904600SVladimir Oltean .name = "tx_yellow_prio_1", 861d4c36765SVladimir Oltean .reg = SYS_COUNT_TX_YELLOW_PRIO_1, 86291904600SVladimir Oltean }, 86391904600SVladimir Oltean [OCELOT_STAT_TX_YELLOW_PRIO_2] = { 86491904600SVladimir Oltean .name = "tx_yellow_prio_2", 865d4c36765SVladimir Oltean .reg = SYS_COUNT_TX_YELLOW_PRIO_2, 86691904600SVladimir Oltean }, 86791904600SVladimir Oltean [OCELOT_STAT_TX_YELLOW_PRIO_3] = { 86891904600SVladimir Oltean .name = "tx_yellow_prio_3", 869d4c36765SVladimir Oltean .reg = SYS_COUNT_TX_YELLOW_PRIO_3, 87091904600SVladimir Oltean }, 87191904600SVladimir Oltean [OCELOT_STAT_TX_YELLOW_PRIO_4] = { 87291904600SVladimir Oltean .name = "tx_yellow_prio_4", 873d4c36765SVladimir Oltean .reg = SYS_COUNT_TX_YELLOW_PRIO_4, 87491904600SVladimir Oltean }, 87591904600SVladimir Oltean [OCELOT_STAT_TX_YELLOW_PRIO_5] = { 87691904600SVladimir Oltean .name = "tx_yellow_prio_5", 877d4c36765SVladimir Oltean .reg = SYS_COUNT_TX_YELLOW_PRIO_5, 87891904600SVladimir Oltean }, 87991904600SVladimir Oltean [OCELOT_STAT_TX_YELLOW_PRIO_6] = { 88091904600SVladimir Oltean .name = "tx_yellow_prio_6", 881d4c36765SVladimir Oltean .reg = SYS_COUNT_TX_YELLOW_PRIO_6, 88291904600SVladimir Oltean }, 88391904600SVladimir Oltean [OCELOT_STAT_TX_YELLOW_PRIO_7] = { 88491904600SVladimir Oltean .name = "tx_yellow_prio_7", 885d4c36765SVladimir Oltean .reg = SYS_COUNT_TX_YELLOW_PRIO_7, 88691904600SVladimir Oltean }, 88791904600SVladimir Oltean [OCELOT_STAT_TX_GREEN_PRIO_0] = { 88891904600SVladimir Oltean .name = "tx_green_prio_0", 889d4c36765SVladimir Oltean .reg = SYS_COUNT_TX_GREEN_PRIO_0, 89091904600SVladimir Oltean }, 89191904600SVladimir Oltean [OCELOT_STAT_TX_GREEN_PRIO_1] = { 89291904600SVladimir Oltean .name = "tx_green_prio_1", 893d4c36765SVladimir Oltean .reg = SYS_COUNT_TX_GREEN_PRIO_1, 89491904600SVladimir Oltean }, 89591904600SVladimir Oltean [OCELOT_STAT_TX_GREEN_PRIO_2] = { 89691904600SVladimir Oltean .name = "tx_green_prio_2", 897d4c36765SVladimir Oltean .reg = SYS_COUNT_TX_GREEN_PRIO_2, 89891904600SVladimir Oltean }, 89991904600SVladimir Oltean [OCELOT_STAT_TX_GREEN_PRIO_3] = { 90091904600SVladimir Oltean .name = "tx_green_prio_3", 901d4c36765SVladimir Oltean .reg = SYS_COUNT_TX_GREEN_PRIO_3, 90291904600SVladimir Oltean }, 90391904600SVladimir Oltean [OCELOT_STAT_TX_GREEN_PRIO_4] = { 90491904600SVladimir Oltean .name = "tx_green_prio_4", 905d4c36765SVladimir Oltean .reg = SYS_COUNT_TX_GREEN_PRIO_4, 90691904600SVladimir Oltean }, 90791904600SVladimir Oltean [OCELOT_STAT_TX_GREEN_PRIO_5] = { 90891904600SVladimir Oltean .name = "tx_green_prio_5", 909d4c36765SVladimir Oltean .reg = SYS_COUNT_TX_GREEN_PRIO_5, 91091904600SVladimir Oltean }, 91191904600SVladimir Oltean [OCELOT_STAT_TX_GREEN_PRIO_6] = { 91291904600SVladimir Oltean .name = "tx_green_prio_6", 913d4c36765SVladimir Oltean .reg = SYS_COUNT_TX_GREEN_PRIO_6, 91491904600SVladimir Oltean }, 91591904600SVladimir Oltean [OCELOT_STAT_TX_GREEN_PRIO_7] = { 91691904600SVladimir Oltean .name = "tx_green_prio_7", 917d4c36765SVladimir Oltean .reg = SYS_COUNT_TX_GREEN_PRIO_7, 91891904600SVladimir Oltean }, 91991904600SVladimir Oltean [OCELOT_STAT_TX_AGED] = { 92091904600SVladimir Oltean .name = "tx_aged", 921d4c36765SVladimir Oltean .reg = SYS_COUNT_TX_AGING, 92291904600SVladimir Oltean }, 92391904600SVladimir Oltean [OCELOT_STAT_DROP_LOCAL] = { 92491904600SVladimir Oltean .name = "drop_local", 925d4c36765SVladimir Oltean .reg = SYS_COUNT_DROP_LOCAL, 92691904600SVladimir Oltean }, 92791904600SVladimir Oltean [OCELOT_STAT_DROP_TAIL] = { 92891904600SVladimir Oltean .name = "drop_tail", 929d4c36765SVladimir Oltean .reg = SYS_COUNT_DROP_TAIL, 93091904600SVladimir Oltean }, 93191904600SVladimir Oltean [OCELOT_STAT_DROP_YELLOW_PRIO_0] = { 93291904600SVladimir Oltean .name = "drop_yellow_prio_0", 933d4c36765SVladimir Oltean .reg = SYS_COUNT_DROP_YELLOW_PRIO_0, 93491904600SVladimir Oltean }, 93591904600SVladimir Oltean [OCELOT_STAT_DROP_YELLOW_PRIO_1] = { 93691904600SVladimir Oltean .name = "drop_yellow_prio_1", 937d4c36765SVladimir Oltean .reg = SYS_COUNT_DROP_YELLOW_PRIO_1, 93891904600SVladimir Oltean }, 93991904600SVladimir Oltean [OCELOT_STAT_DROP_YELLOW_PRIO_2] = { 94091904600SVladimir Oltean .name = "drop_yellow_prio_2", 941d4c36765SVladimir Oltean .reg = SYS_COUNT_DROP_YELLOW_PRIO_2, 94291904600SVladimir Oltean }, 94391904600SVladimir Oltean [OCELOT_STAT_DROP_YELLOW_PRIO_3] = { 94491904600SVladimir Oltean .name = "drop_yellow_prio_3", 945d4c36765SVladimir Oltean .reg = SYS_COUNT_DROP_YELLOW_PRIO_3, 94691904600SVladimir Oltean }, 94791904600SVladimir Oltean [OCELOT_STAT_DROP_YELLOW_PRIO_4] = { 94891904600SVladimir Oltean .name = "drop_yellow_prio_4", 949d4c36765SVladimir Oltean .reg = SYS_COUNT_DROP_YELLOW_PRIO_4, 95091904600SVladimir Oltean }, 95191904600SVladimir Oltean [OCELOT_STAT_DROP_YELLOW_PRIO_5] = { 95291904600SVladimir Oltean .name = "drop_yellow_prio_5", 953d4c36765SVladimir Oltean .reg = SYS_COUNT_DROP_YELLOW_PRIO_5, 95491904600SVladimir Oltean }, 95591904600SVladimir Oltean [OCELOT_STAT_DROP_YELLOW_PRIO_6] = { 95691904600SVladimir Oltean .name = "drop_yellow_prio_6", 957d4c36765SVladimir Oltean .reg = SYS_COUNT_DROP_YELLOW_PRIO_6, 95891904600SVladimir Oltean }, 95991904600SVladimir Oltean [OCELOT_STAT_DROP_YELLOW_PRIO_7] = { 96091904600SVladimir Oltean .name = "drop_yellow_prio_7", 961d4c36765SVladimir Oltean .reg = SYS_COUNT_DROP_YELLOW_PRIO_7, 96291904600SVladimir Oltean }, 96391904600SVladimir Oltean [OCELOT_STAT_DROP_GREEN_PRIO_0] = { 96491904600SVladimir Oltean .name = "drop_green_prio_0", 965d4c36765SVladimir Oltean .reg = SYS_COUNT_DROP_GREEN_PRIO_0, 96691904600SVladimir Oltean }, 96791904600SVladimir Oltean [OCELOT_STAT_DROP_GREEN_PRIO_1] = { 96891904600SVladimir Oltean .name = "drop_green_prio_1", 969d4c36765SVladimir Oltean .reg = SYS_COUNT_DROP_GREEN_PRIO_1, 97091904600SVladimir Oltean }, 97191904600SVladimir Oltean [OCELOT_STAT_DROP_GREEN_PRIO_2] = { 97291904600SVladimir Oltean .name = "drop_green_prio_2", 973d4c36765SVladimir Oltean .reg = SYS_COUNT_DROP_GREEN_PRIO_2, 97491904600SVladimir Oltean }, 97591904600SVladimir Oltean [OCELOT_STAT_DROP_GREEN_PRIO_3] = { 97691904600SVladimir Oltean .name = "drop_green_prio_3", 977d4c36765SVladimir Oltean .reg = SYS_COUNT_DROP_GREEN_PRIO_3, 97891904600SVladimir Oltean }, 97991904600SVladimir Oltean [OCELOT_STAT_DROP_GREEN_PRIO_4] = { 98091904600SVladimir Oltean .name = "drop_green_prio_4", 981d4c36765SVladimir Oltean .reg = SYS_COUNT_DROP_GREEN_PRIO_4, 98291904600SVladimir Oltean }, 98391904600SVladimir Oltean [OCELOT_STAT_DROP_GREEN_PRIO_5] = { 98491904600SVladimir Oltean .name = "drop_green_prio_5", 985d4c36765SVladimir Oltean .reg = SYS_COUNT_DROP_GREEN_PRIO_5, 98691904600SVladimir Oltean }, 98791904600SVladimir Oltean [OCELOT_STAT_DROP_GREEN_PRIO_6] = { 98891904600SVladimir Oltean .name = "drop_green_prio_6", 989d4c36765SVladimir Oltean .reg = SYS_COUNT_DROP_GREEN_PRIO_6, 99091904600SVladimir Oltean }, 99191904600SVladimir Oltean [OCELOT_STAT_DROP_GREEN_PRIO_7] = { 99291904600SVladimir Oltean .name = "drop_green_prio_7", 993d4c36765SVladimir Oltean .reg = SYS_COUNT_DROP_GREEN_PRIO_7, 99491904600SVladimir Oltean }, 99556051948SVladimir Oltean }; 99656051948SVladimir Oltean 997e3aea296SVladimir Oltean static const struct vcap_field vsc9959_vcap_es0_keys[] = { 998e3aea296SVladimir Oltean [VCAP_ES0_EGR_PORT] = { 0, 3}, 999e3aea296SVladimir Oltean [VCAP_ES0_IGR_PORT] = { 3, 3}, 1000e3aea296SVladimir Oltean [VCAP_ES0_RSV] = { 6, 2}, 1001e3aea296SVladimir Oltean [VCAP_ES0_L2_MC] = { 8, 1}, 1002e3aea296SVladimir Oltean [VCAP_ES0_L2_BC] = { 9, 1}, 1003e3aea296SVladimir Oltean [VCAP_ES0_VID] = { 10, 12}, 1004e3aea296SVladimir Oltean [VCAP_ES0_DP] = { 22, 1}, 1005e3aea296SVladimir Oltean [VCAP_ES0_PCP] = { 23, 3}, 1006e3aea296SVladimir Oltean }; 1007e3aea296SVladimir Oltean 1008e3aea296SVladimir Oltean static const struct vcap_field vsc9959_vcap_es0_actions[] = { 1009e3aea296SVladimir Oltean [VCAP_ES0_ACT_PUSH_OUTER_TAG] = { 0, 2}, 1010e3aea296SVladimir Oltean [VCAP_ES0_ACT_PUSH_INNER_TAG] = { 2, 1}, 1011e3aea296SVladimir Oltean [VCAP_ES0_ACT_TAG_A_TPID_SEL] = { 3, 2}, 1012e3aea296SVladimir Oltean [VCAP_ES0_ACT_TAG_A_VID_SEL] = { 5, 1}, 1013e3aea296SVladimir Oltean [VCAP_ES0_ACT_TAG_A_PCP_SEL] = { 6, 2}, 1014e3aea296SVladimir Oltean [VCAP_ES0_ACT_TAG_A_DEI_SEL] = { 8, 2}, 1015e3aea296SVladimir Oltean [VCAP_ES0_ACT_TAG_B_TPID_SEL] = { 10, 2}, 1016e3aea296SVladimir Oltean [VCAP_ES0_ACT_TAG_B_VID_SEL] = { 12, 1}, 1017e3aea296SVladimir Oltean [VCAP_ES0_ACT_TAG_B_PCP_SEL] = { 13, 2}, 1018e3aea296SVladimir Oltean [VCAP_ES0_ACT_TAG_B_DEI_SEL] = { 15, 2}, 1019e3aea296SVladimir Oltean [VCAP_ES0_ACT_VID_A_VAL] = { 17, 12}, 1020e3aea296SVladimir Oltean [VCAP_ES0_ACT_PCP_A_VAL] = { 29, 3}, 1021e3aea296SVladimir Oltean [VCAP_ES0_ACT_DEI_A_VAL] = { 32, 1}, 1022e3aea296SVladimir Oltean [VCAP_ES0_ACT_VID_B_VAL] = { 33, 12}, 1023e3aea296SVladimir Oltean [VCAP_ES0_ACT_PCP_B_VAL] = { 45, 3}, 1024e3aea296SVladimir Oltean [VCAP_ES0_ACT_DEI_B_VAL] = { 48, 1}, 1025e3aea296SVladimir Oltean [VCAP_ES0_ACT_RSV] = { 49, 23}, 1026e3aea296SVladimir Oltean [VCAP_ES0_ACT_HIT_STICKY] = { 72, 1}, 1027e3aea296SVladimir Oltean }; 1028e3aea296SVladimir Oltean 1029a61e365dSVladimir Oltean static const struct vcap_field vsc9959_vcap_is1_keys[] = { 1030a61e365dSVladimir Oltean [VCAP_IS1_HK_TYPE] = { 0, 1}, 1031a61e365dSVladimir Oltean [VCAP_IS1_HK_LOOKUP] = { 1, 2}, 1032a61e365dSVladimir Oltean [VCAP_IS1_HK_IGR_PORT_MASK] = { 3, 7}, 1033a61e365dSVladimir Oltean [VCAP_IS1_HK_RSV] = { 10, 9}, 1034a61e365dSVladimir Oltean [VCAP_IS1_HK_OAM_Y1731] = { 19, 1}, 1035a61e365dSVladimir Oltean [VCAP_IS1_HK_L2_MC] = { 20, 1}, 1036a61e365dSVladimir Oltean [VCAP_IS1_HK_L2_BC] = { 21, 1}, 1037a61e365dSVladimir Oltean [VCAP_IS1_HK_IP_MC] = { 22, 1}, 1038a61e365dSVladimir Oltean [VCAP_IS1_HK_VLAN_TAGGED] = { 23, 1}, 1039a61e365dSVladimir Oltean [VCAP_IS1_HK_VLAN_DBL_TAGGED] = { 24, 1}, 1040a61e365dSVladimir Oltean [VCAP_IS1_HK_TPID] = { 25, 1}, 1041a61e365dSVladimir Oltean [VCAP_IS1_HK_VID] = { 26, 12}, 1042a61e365dSVladimir Oltean [VCAP_IS1_HK_DEI] = { 38, 1}, 1043a61e365dSVladimir Oltean [VCAP_IS1_HK_PCP] = { 39, 3}, 1044a61e365dSVladimir Oltean /* Specific Fields for IS1 Half Key S1_NORMAL */ 1045a61e365dSVladimir Oltean [VCAP_IS1_HK_L2_SMAC] = { 42, 48}, 1046a61e365dSVladimir Oltean [VCAP_IS1_HK_ETYPE_LEN] = { 90, 1}, 1047a61e365dSVladimir Oltean [VCAP_IS1_HK_ETYPE] = { 91, 16}, 1048a61e365dSVladimir Oltean [VCAP_IS1_HK_IP_SNAP] = {107, 1}, 1049a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4] = {108, 1}, 1050a61e365dSVladimir Oltean /* Layer-3 Information */ 1051a61e365dSVladimir Oltean [VCAP_IS1_HK_L3_FRAGMENT] = {109, 1}, 1052a61e365dSVladimir Oltean [VCAP_IS1_HK_L3_FRAG_OFS_GT0] = {110, 1}, 1053a61e365dSVladimir Oltean [VCAP_IS1_HK_L3_OPTIONS] = {111, 1}, 1054a61e365dSVladimir Oltean [VCAP_IS1_HK_L3_DSCP] = {112, 6}, 1055a61e365dSVladimir Oltean [VCAP_IS1_HK_L3_IP4_SIP] = {118, 32}, 1056a61e365dSVladimir Oltean /* Layer-4 Information */ 1057a61e365dSVladimir Oltean [VCAP_IS1_HK_TCP_UDP] = {150, 1}, 1058a61e365dSVladimir Oltean [VCAP_IS1_HK_TCP] = {151, 1}, 1059a61e365dSVladimir Oltean [VCAP_IS1_HK_L4_SPORT] = {152, 16}, 1060a61e365dSVladimir Oltean [VCAP_IS1_HK_L4_RNG] = {168, 8}, 1061a61e365dSVladimir Oltean /* Specific Fields for IS1 Half Key S1_5TUPLE_IP4 */ 1062a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_INNER_TPID] = { 42, 1}, 1063a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_INNER_VID] = { 43, 12}, 1064a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_INNER_DEI] = { 55, 1}, 1065a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_INNER_PCP] = { 56, 3}, 1066a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_IP4] = { 59, 1}, 1067a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_L3_FRAGMENT] = { 60, 1}, 1068a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_L3_FRAG_OFS_GT0] = { 61, 1}, 1069a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_L3_OPTIONS] = { 62, 1}, 1070a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_L3_DSCP] = { 63, 6}, 1071a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_L3_IP4_DIP] = { 69, 32}, 1072a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_L3_IP4_SIP] = {101, 32}, 1073a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_L3_PROTO] = {133, 8}, 1074a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_TCP_UDP] = {141, 1}, 1075a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_TCP] = {142, 1}, 1076a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_L4_RNG] = {143, 8}, 1077a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_IP_PAYLOAD_S1_5TUPLE] = {151, 32}, 1078a61e365dSVladimir Oltean }; 1079a61e365dSVladimir Oltean 1080a61e365dSVladimir Oltean static const struct vcap_field vsc9959_vcap_is1_actions[] = { 1081a61e365dSVladimir Oltean [VCAP_IS1_ACT_DSCP_ENA] = { 0, 1}, 1082a61e365dSVladimir Oltean [VCAP_IS1_ACT_DSCP_VAL] = { 1, 6}, 1083a61e365dSVladimir Oltean [VCAP_IS1_ACT_QOS_ENA] = { 7, 1}, 1084a61e365dSVladimir Oltean [VCAP_IS1_ACT_QOS_VAL] = { 8, 3}, 1085a61e365dSVladimir Oltean [VCAP_IS1_ACT_DP_ENA] = { 11, 1}, 1086a61e365dSVladimir Oltean [VCAP_IS1_ACT_DP_VAL] = { 12, 1}, 1087a61e365dSVladimir Oltean [VCAP_IS1_ACT_PAG_OVERRIDE_MASK] = { 13, 8}, 1088a61e365dSVladimir Oltean [VCAP_IS1_ACT_PAG_VAL] = { 21, 8}, 1089a61e365dSVladimir Oltean [VCAP_IS1_ACT_RSV] = { 29, 9}, 109075944fdaSXiaoliang Yang /* The fields below are incorrectly shifted by 2 in the manual */ 1091a61e365dSVladimir Oltean [VCAP_IS1_ACT_VID_REPLACE_ENA] = { 38, 1}, 1092a61e365dSVladimir Oltean [VCAP_IS1_ACT_VID_ADD_VAL] = { 39, 12}, 1093a61e365dSVladimir Oltean [VCAP_IS1_ACT_FID_SEL] = { 51, 2}, 1094a61e365dSVladimir Oltean [VCAP_IS1_ACT_FID_VAL] = { 53, 13}, 1095a61e365dSVladimir Oltean [VCAP_IS1_ACT_PCP_DEI_ENA] = { 66, 1}, 1096a61e365dSVladimir Oltean [VCAP_IS1_ACT_PCP_VAL] = { 67, 3}, 1097a61e365dSVladimir Oltean [VCAP_IS1_ACT_DEI_VAL] = { 70, 1}, 1098a61e365dSVladimir Oltean [VCAP_IS1_ACT_VLAN_POP_CNT_ENA] = { 71, 1}, 1099a61e365dSVladimir Oltean [VCAP_IS1_ACT_VLAN_POP_CNT] = { 72, 2}, 1100a61e365dSVladimir Oltean [VCAP_IS1_ACT_CUSTOM_ACE_TYPE_ENA] = { 74, 4}, 1101a61e365dSVladimir Oltean [VCAP_IS1_ACT_HIT_STICKY] = { 78, 1}, 1102a61e365dSVladimir Oltean }; 1103a61e365dSVladimir Oltean 11043ab4ceb6SVladimir Oltean static struct vcap_field vsc9959_vcap_is2_keys[] = { 110507d985eeSVladimir Oltean /* Common: 41 bits */ 110607d985eeSVladimir Oltean [VCAP_IS2_TYPE] = { 0, 4}, 110707d985eeSVladimir Oltean [VCAP_IS2_HK_FIRST] = { 4, 1}, 110807d985eeSVladimir Oltean [VCAP_IS2_HK_PAG] = { 5, 8}, 110907d985eeSVladimir Oltean [VCAP_IS2_HK_IGR_PORT_MASK] = { 13, 7}, 111007d985eeSVladimir Oltean [VCAP_IS2_HK_RSV2] = { 20, 1}, 111107d985eeSVladimir Oltean [VCAP_IS2_HK_HOST_MATCH] = { 21, 1}, 111207d985eeSVladimir Oltean [VCAP_IS2_HK_L2_MC] = { 22, 1}, 111307d985eeSVladimir Oltean [VCAP_IS2_HK_L2_BC] = { 23, 1}, 111407d985eeSVladimir Oltean [VCAP_IS2_HK_VLAN_TAGGED] = { 24, 1}, 111507d985eeSVladimir Oltean [VCAP_IS2_HK_VID] = { 25, 12}, 111607d985eeSVladimir Oltean [VCAP_IS2_HK_DEI] = { 37, 1}, 111707d985eeSVladimir Oltean [VCAP_IS2_HK_PCP] = { 38, 3}, 111807d985eeSVladimir Oltean /* MAC_ETYPE / MAC_LLC / MAC_SNAP / OAM common */ 111907d985eeSVladimir Oltean [VCAP_IS2_HK_L2_DMAC] = { 41, 48}, 112007d985eeSVladimir Oltean [VCAP_IS2_HK_L2_SMAC] = { 89, 48}, 112107d985eeSVladimir Oltean /* MAC_ETYPE (TYPE=000) */ 112207d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ETYPE_ETYPE] = {137, 16}, 112307d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD0] = {153, 16}, 112407d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD1] = {169, 8}, 112507d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD2] = {177, 3}, 112607d985eeSVladimir Oltean /* MAC_LLC (TYPE=001) */ 112707d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_LLC_L2_LLC] = {137, 40}, 112807d985eeSVladimir Oltean /* MAC_SNAP (TYPE=010) */ 112907d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_SNAP_L2_SNAP] = {137, 40}, 113007d985eeSVladimir Oltean /* MAC_ARP (TYPE=011) */ 113107d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ARP_SMAC] = { 41, 48}, 113207d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ARP_ADDR_SPACE_OK] = { 89, 1}, 113307d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ARP_PROTO_SPACE_OK] = { 90, 1}, 113407d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ARP_LEN_OK] = { 91, 1}, 113507d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ARP_TARGET_MATCH] = { 92, 1}, 113607d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ARP_SENDER_MATCH] = { 93, 1}, 113707d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ARP_OPCODE_UNKNOWN] = { 94, 1}, 113807d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ARP_OPCODE] = { 95, 2}, 113907d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ARP_L3_IP4_DIP] = { 97, 32}, 114007d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ARP_L3_IP4_SIP] = {129, 32}, 114107d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ARP_DIP_EQ_SIP] = {161, 1}, 114207d985eeSVladimir Oltean /* IP4_TCP_UDP / IP4_OTHER common */ 114307d985eeSVladimir Oltean [VCAP_IS2_HK_IP4] = { 41, 1}, 114407d985eeSVladimir Oltean [VCAP_IS2_HK_L3_FRAGMENT] = { 42, 1}, 114507d985eeSVladimir Oltean [VCAP_IS2_HK_L3_FRAG_OFS_GT0] = { 43, 1}, 114607d985eeSVladimir Oltean [VCAP_IS2_HK_L3_OPTIONS] = { 44, 1}, 114707d985eeSVladimir Oltean [VCAP_IS2_HK_IP4_L3_TTL_GT0] = { 45, 1}, 114807d985eeSVladimir Oltean [VCAP_IS2_HK_L3_TOS] = { 46, 8}, 114907d985eeSVladimir Oltean [VCAP_IS2_HK_L3_IP4_DIP] = { 54, 32}, 115007d985eeSVladimir Oltean [VCAP_IS2_HK_L3_IP4_SIP] = { 86, 32}, 115107d985eeSVladimir Oltean [VCAP_IS2_HK_DIP_EQ_SIP] = {118, 1}, 115207d985eeSVladimir Oltean /* IP4_TCP_UDP (TYPE=100) */ 115307d985eeSVladimir Oltean [VCAP_IS2_HK_TCP] = {119, 1}, 11548b9e03cdSXiaoliang Yang [VCAP_IS2_HK_L4_DPORT] = {120, 16}, 11558b9e03cdSXiaoliang Yang [VCAP_IS2_HK_L4_SPORT] = {136, 16}, 115607d985eeSVladimir Oltean [VCAP_IS2_HK_L4_RNG] = {152, 8}, 115707d985eeSVladimir Oltean [VCAP_IS2_HK_L4_SPORT_EQ_DPORT] = {160, 1}, 115807d985eeSVladimir Oltean [VCAP_IS2_HK_L4_SEQUENCE_EQ0] = {161, 1}, 11598b9e03cdSXiaoliang Yang [VCAP_IS2_HK_L4_FIN] = {162, 1}, 11608b9e03cdSXiaoliang Yang [VCAP_IS2_HK_L4_SYN] = {163, 1}, 11618b9e03cdSXiaoliang Yang [VCAP_IS2_HK_L4_RST] = {164, 1}, 11628b9e03cdSXiaoliang Yang [VCAP_IS2_HK_L4_PSH] = {165, 1}, 11638b9e03cdSXiaoliang Yang [VCAP_IS2_HK_L4_ACK] = {166, 1}, 11648b9e03cdSXiaoliang Yang [VCAP_IS2_HK_L4_URG] = {167, 1}, 116507d985eeSVladimir Oltean [VCAP_IS2_HK_L4_1588_DOM] = {168, 8}, 116607d985eeSVladimir Oltean [VCAP_IS2_HK_L4_1588_VER] = {176, 4}, 116707d985eeSVladimir Oltean /* IP4_OTHER (TYPE=101) */ 116807d985eeSVladimir Oltean [VCAP_IS2_HK_IP4_L3_PROTO] = {119, 8}, 116907d985eeSVladimir Oltean [VCAP_IS2_HK_L3_PAYLOAD] = {127, 56}, 117007d985eeSVladimir Oltean /* IP6_STD (TYPE=110) */ 117107d985eeSVladimir Oltean [VCAP_IS2_HK_IP6_L3_TTL_GT0] = { 41, 1}, 117207d985eeSVladimir Oltean [VCAP_IS2_HK_L3_IP6_SIP] = { 42, 128}, 117307d985eeSVladimir Oltean [VCAP_IS2_HK_IP6_L3_PROTO] = {170, 8}, 117407d985eeSVladimir Oltean /* OAM (TYPE=111) */ 117507d985eeSVladimir Oltean [VCAP_IS2_HK_OAM_MEL_FLAGS] = {137, 7}, 117607d985eeSVladimir Oltean [VCAP_IS2_HK_OAM_VER] = {144, 5}, 117707d985eeSVladimir Oltean [VCAP_IS2_HK_OAM_OPCODE] = {149, 8}, 117807d985eeSVladimir Oltean [VCAP_IS2_HK_OAM_FLAGS] = {157, 8}, 117907d985eeSVladimir Oltean [VCAP_IS2_HK_OAM_MEPID] = {165, 16}, 118007d985eeSVladimir Oltean [VCAP_IS2_HK_OAM_CCM_CNTS_EQ0] = {181, 1}, 118107d985eeSVladimir Oltean [VCAP_IS2_HK_OAM_IS_Y1731] = {182, 1}, 118207d985eeSVladimir Oltean }; 118307d985eeSVladimir Oltean 11843ab4ceb6SVladimir Oltean static struct vcap_field vsc9959_vcap_is2_actions[] = { 118507d985eeSVladimir Oltean [VCAP_IS2_ACT_HIT_ME_ONCE] = { 0, 1}, 118607d985eeSVladimir Oltean [VCAP_IS2_ACT_CPU_COPY_ENA] = { 1, 1}, 118707d985eeSVladimir Oltean [VCAP_IS2_ACT_CPU_QU_NUM] = { 2, 3}, 118807d985eeSVladimir Oltean [VCAP_IS2_ACT_MASK_MODE] = { 5, 2}, 118907d985eeSVladimir Oltean [VCAP_IS2_ACT_MIRROR_ENA] = { 7, 1}, 119007d985eeSVladimir Oltean [VCAP_IS2_ACT_LRN_DIS] = { 8, 1}, 119107d985eeSVladimir Oltean [VCAP_IS2_ACT_POLICE_ENA] = { 9, 1}, 119207d985eeSVladimir Oltean [VCAP_IS2_ACT_POLICE_IDX] = { 10, 9}, 119307d985eeSVladimir Oltean [VCAP_IS2_ACT_POLICE_VCAP_ONLY] = { 19, 1}, 1194460e985eSVladimir Oltean [VCAP_IS2_ACT_PORT_MASK] = { 20, 6}, 1195460e985eSVladimir Oltean [VCAP_IS2_ACT_REW_OP] = { 26, 9}, 1196460e985eSVladimir Oltean [VCAP_IS2_ACT_SMAC_REPLACE_ENA] = { 35, 1}, 1197460e985eSVladimir Oltean [VCAP_IS2_ACT_RSV] = { 36, 2}, 1198460e985eSVladimir Oltean [VCAP_IS2_ACT_ACL_ID] = { 38, 6}, 1199460e985eSVladimir Oltean [VCAP_IS2_ACT_HIT_CNT] = { 44, 32}, 120007d985eeSVladimir Oltean }; 120107d985eeSVladimir Oltean 120220968054SVladimir Oltean static struct vcap_props vsc9959_vcap_props[] = { 1203e3aea296SVladimir Oltean [VCAP_ES0] = { 1204e3aea296SVladimir Oltean .action_type_width = 0, 1205e3aea296SVladimir Oltean .action_table = { 1206e3aea296SVladimir Oltean [ES0_ACTION_TYPE_NORMAL] = { 1207e3aea296SVladimir Oltean .width = 72, /* HIT_STICKY not included */ 1208e3aea296SVladimir Oltean .count = 1, 1209e3aea296SVladimir Oltean }, 1210e3aea296SVladimir Oltean }, 1211e3aea296SVladimir Oltean .target = S0, 1212e3aea296SVladimir Oltean .keys = vsc9959_vcap_es0_keys, 1213e3aea296SVladimir Oltean .actions = vsc9959_vcap_es0_actions, 1214e3aea296SVladimir Oltean }, 1215a61e365dSVladimir Oltean [VCAP_IS1] = { 1216a61e365dSVladimir Oltean .action_type_width = 0, 1217a61e365dSVladimir Oltean .action_table = { 1218a61e365dSVladimir Oltean [IS1_ACTION_TYPE_NORMAL] = { 1219a61e365dSVladimir Oltean .width = 78, /* HIT_STICKY not included */ 1220a61e365dSVladimir Oltean .count = 4, 1221a61e365dSVladimir Oltean }, 1222a61e365dSVladimir Oltean }, 1223a61e365dSVladimir Oltean .target = S1, 1224a61e365dSVladimir Oltean .keys = vsc9959_vcap_is1_keys, 1225a61e365dSVladimir Oltean .actions = vsc9959_vcap_is1_actions, 1226a61e365dSVladimir Oltean }, 122707d985eeSVladimir Oltean [VCAP_IS2] = { 122807d985eeSVladimir Oltean .action_type_width = 1, 122907d985eeSVladimir Oltean .action_table = { 123007d985eeSVladimir Oltean [IS2_ACTION_TYPE_NORMAL] = { 123107d985eeSVladimir Oltean .width = 44, 123207d985eeSVladimir Oltean .count = 2 123307d985eeSVladimir Oltean }, 123407d985eeSVladimir Oltean [IS2_ACTION_TYPE_SMAC_SIP] = { 123507d985eeSVladimir Oltean .width = 6, 123607d985eeSVladimir Oltean .count = 4 123707d985eeSVladimir Oltean }, 123807d985eeSVladimir Oltean }, 1239c1c3993eSVladimir Oltean .target = S2, 1240c1c3993eSVladimir Oltean .keys = vsc9959_vcap_is2_keys, 1241c1c3993eSVladimir Oltean .actions = vsc9959_vcap_is2_actions, 124207d985eeSVladimir Oltean }, 124307d985eeSVladimir Oltean }; 124407d985eeSVladimir Oltean 12452ac7c6c5SVladimir Oltean static const struct ptp_clock_info vsc9959_ptp_caps = { 12462ac7c6c5SVladimir Oltean .owner = THIS_MODULE, 12472ac7c6c5SVladimir Oltean .name = "felix ptp", 12482ac7c6c5SVladimir Oltean .max_adj = 0x7fffffff, 12492ac7c6c5SVladimir Oltean .n_alarm = 0, 12502ac7c6c5SVladimir Oltean .n_ext_ts = 0, 12512ac7c6c5SVladimir Oltean .n_per_out = OCELOT_PTP_PINS_NUM, 12522ac7c6c5SVladimir Oltean .n_pins = OCELOT_PTP_PINS_NUM, 12532ac7c6c5SVladimir Oltean .pps = 0, 12542ac7c6c5SVladimir Oltean .gettime64 = ocelot_ptp_gettime64, 12552ac7c6c5SVladimir Oltean .settime64 = ocelot_ptp_settime64, 12562ac7c6c5SVladimir Oltean .adjtime = ocelot_ptp_adjtime, 12572ac7c6c5SVladimir Oltean .adjfine = ocelot_ptp_adjfine, 12582ac7c6c5SVladimir Oltean .verify = ocelot_ptp_verify, 12592ac7c6c5SVladimir Oltean .enable = ocelot_ptp_enable, 12602ac7c6c5SVladimir Oltean }; 12612ac7c6c5SVladimir Oltean 126256051948SVladimir Oltean #define VSC9959_INIT_TIMEOUT 50000 126356051948SVladimir Oltean #define VSC9959_GCB_RST_SLEEP 100 126456051948SVladimir Oltean #define VSC9959_SYS_RAMINIT_SLEEP 80 126556051948SVladimir Oltean 126656051948SVladimir Oltean static int vsc9959_gcb_soft_rst_status(struct ocelot *ocelot) 126756051948SVladimir Oltean { 126856051948SVladimir Oltean int val; 126956051948SVladimir Oltean 127075cea9cbSVladimir Oltean ocelot_field_read(ocelot, GCB_SOFT_RST_SWC_RST, &val); 127156051948SVladimir Oltean 127256051948SVladimir Oltean return val; 127356051948SVladimir Oltean } 127456051948SVladimir Oltean 127556051948SVladimir Oltean static int vsc9959_sys_ram_init_status(struct ocelot *ocelot) 127656051948SVladimir Oltean { 127756051948SVladimir Oltean return ocelot_read(ocelot, SYS_RAM_INIT); 127856051948SVladimir Oltean } 127956051948SVladimir Oltean 1280c129fc55SVladimir Oltean /* CORE_ENA is in SYS:SYSTEM:RESET_CFG 1281c129fc55SVladimir Oltean * RAM_INIT is in SYS:RAM_CTRL:RAM_INIT 1282c129fc55SVladimir Oltean */ 128356051948SVladimir Oltean static int vsc9959_reset(struct ocelot *ocelot) 128456051948SVladimir Oltean { 128556051948SVladimir Oltean int val, err; 128656051948SVladimir Oltean 128756051948SVladimir Oltean /* soft-reset the switch core */ 128875cea9cbSVladimir Oltean ocelot_field_write(ocelot, GCB_SOFT_RST_SWC_RST, 1); 128956051948SVladimir Oltean 129056051948SVladimir Oltean err = readx_poll_timeout(vsc9959_gcb_soft_rst_status, ocelot, val, !val, 129156051948SVladimir Oltean VSC9959_GCB_RST_SLEEP, VSC9959_INIT_TIMEOUT); 129256051948SVladimir Oltean if (err) { 129356051948SVladimir Oltean dev_err(ocelot->dev, "timeout: switch core reset\n"); 129456051948SVladimir Oltean return err; 129556051948SVladimir Oltean } 129656051948SVladimir Oltean 129756051948SVladimir Oltean /* initialize switch mem ~40us */ 129856051948SVladimir Oltean ocelot_write(ocelot, SYS_RAM_INIT_RAM_INIT, SYS_RAM_INIT); 129956051948SVladimir Oltean err = readx_poll_timeout(vsc9959_sys_ram_init_status, ocelot, val, !val, 130056051948SVladimir Oltean VSC9959_SYS_RAMINIT_SLEEP, 130156051948SVladimir Oltean VSC9959_INIT_TIMEOUT); 130256051948SVladimir Oltean if (err) { 130356051948SVladimir Oltean dev_err(ocelot->dev, "timeout: switch sram init\n"); 130456051948SVladimir Oltean return err; 130556051948SVladimir Oltean } 130656051948SVladimir Oltean 130756051948SVladimir Oltean /* enable switch core */ 130875cea9cbSVladimir Oltean ocelot_field_write(ocelot, SYS_RESET_CFG_CORE_ENA, 1); 130956051948SVladimir Oltean 131056051948SVladimir Oltean return 0; 131156051948SVladimir Oltean } 131256051948SVladimir Oltean 1313375e1314SVladimir Oltean static void vsc9959_phylink_validate(struct ocelot *ocelot, int port, 1314375e1314SVladimir Oltean unsigned long *supported, 1315375e1314SVladimir Oltean struct phylink_link_state *state) 1316375e1314SVladimir Oltean { 1317375e1314SVladimir Oltean __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; 1318375e1314SVladimir Oltean 1319375e1314SVladimir Oltean phylink_set_port_modes(mask); 1320375e1314SVladimir Oltean phylink_set(mask, Autoneg); 1321375e1314SVladimir Oltean phylink_set(mask, Pause); 1322375e1314SVladimir Oltean phylink_set(mask, Asym_Pause); 1323375e1314SVladimir Oltean phylink_set(mask, 10baseT_Half); 1324375e1314SVladimir Oltean phylink_set(mask, 10baseT_Full); 1325375e1314SVladimir Oltean phylink_set(mask, 100baseT_Half); 1326375e1314SVladimir Oltean phylink_set(mask, 100baseT_Full); 1327375e1314SVladimir Oltean phylink_set(mask, 1000baseT_Half); 1328375e1314SVladimir Oltean phylink_set(mask, 1000baseT_Full); 132911ecf341SVladimir Oltean phylink_set(mask, 1000baseX_Full); 1330375e1314SVladimir Oltean 1331375e1314SVladimir Oltean if (state->interface == PHY_INTERFACE_MODE_INTERNAL || 1332375e1314SVladimir Oltean state->interface == PHY_INTERFACE_MODE_2500BASEX || 1333375e1314SVladimir Oltean state->interface == PHY_INTERFACE_MODE_USXGMII) { 1334375e1314SVladimir Oltean phylink_set(mask, 2500baseT_Full); 1335375e1314SVladimir Oltean phylink_set(mask, 2500baseX_Full); 1336375e1314SVladimir Oltean } 1337375e1314SVladimir Oltean 13384973056cSSean Anderson linkmode_and(supported, supported, mask); 13394973056cSSean Anderson linkmode_and(state->advertising, state->advertising, mask); 1340375e1314SVladimir Oltean } 1341375e1314SVladimir Oltean 1342aa92d836SMaxim Kochetkov /* Watermark encode 1343aa92d836SMaxim Kochetkov * Bit 8: Unit; 0:1, 1:16 1344aa92d836SMaxim Kochetkov * Bit 7-0: Value to be multiplied with unit 1345aa92d836SMaxim Kochetkov */ 1346aa92d836SMaxim Kochetkov static u16 vsc9959_wm_enc(u16 value) 1347aa92d836SMaxim Kochetkov { 134801326493SVladimir Oltean WARN_ON(value >= 16 * BIT(8)); 134901326493SVladimir Oltean 1350aa92d836SMaxim Kochetkov if (value >= BIT(8)) 1351aa92d836SMaxim Kochetkov return BIT(8) | (value / 16); 1352aa92d836SMaxim Kochetkov 1353aa92d836SMaxim Kochetkov return value; 1354aa92d836SMaxim Kochetkov } 1355aa92d836SMaxim Kochetkov 1356703b7621SVladimir Oltean static u16 vsc9959_wm_dec(u16 wm) 1357703b7621SVladimir Oltean { 1358703b7621SVladimir Oltean WARN_ON(wm & ~GENMASK(8, 0)); 1359703b7621SVladimir Oltean 1360703b7621SVladimir Oltean if (wm & BIT(8)) 1361703b7621SVladimir Oltean return (wm & GENMASK(7, 0)) * 16; 1362703b7621SVladimir Oltean 1363703b7621SVladimir Oltean return wm; 1364703b7621SVladimir Oltean } 1365703b7621SVladimir Oltean 1366703b7621SVladimir Oltean static void vsc9959_wm_stat(u32 val, u32 *inuse, u32 *maxuse) 1367703b7621SVladimir Oltean { 1368703b7621SVladimir Oltean *inuse = (val & GENMASK(23, 12)) >> 12; 1369703b7621SVladimir Oltean *maxuse = val & GENMASK(11, 0); 1370703b7621SVladimir Oltean } 1371703b7621SVladimir Oltean 1372bdeced75SVladimir Oltean static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot) 1373bdeced75SVladimir Oltean { 1374bdeced75SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 1375bdeced75SVladimir Oltean struct enetc_mdio_priv *mdio_priv; 1376bdeced75SVladimir Oltean struct device *dev = ocelot->dev; 1377bdeced75SVladimir Oltean void __iomem *imdio_regs; 1378b4024c9eSClaudiu Manoil struct resource res; 1379bdeced75SVladimir Oltean struct enetc_hw *hw; 1380bdeced75SVladimir Oltean struct mii_bus *bus; 1381bdeced75SVladimir Oltean int port; 1382bdeced75SVladimir Oltean int rc; 1383bdeced75SVladimir Oltean 1384bdeced75SVladimir Oltean felix->pcs = devm_kcalloc(dev, felix->info->num_ports, 1385e7026f15SColin Foster sizeof(struct phylink_pcs *), 1386bdeced75SVladimir Oltean GFP_KERNEL); 1387bdeced75SVladimir Oltean if (!felix->pcs) { 1388bdeced75SVladimir Oltean dev_err(dev, "failed to allocate array for PCS PHYs\n"); 1389bdeced75SVladimir Oltean return -ENOMEM; 1390bdeced75SVladimir Oltean } 1391bdeced75SVladimir Oltean 1392b4024c9eSClaudiu Manoil memcpy(&res, felix->info->imdio_res, sizeof(res)); 1393b4024c9eSClaudiu Manoil res.flags = IORESOURCE_MEM; 1394375e1314SVladimir Oltean res.start += felix->imdio_base; 1395375e1314SVladimir Oltean res.end += felix->imdio_base; 1396bdeced75SVladimir Oltean 1397b4024c9eSClaudiu Manoil imdio_regs = devm_ioremap_resource(dev, &res); 1398a180be79SGuobin Huang if (IS_ERR(imdio_regs)) 1399bdeced75SVladimir Oltean return PTR_ERR(imdio_regs); 1400bdeced75SVladimir Oltean 1401bdeced75SVladimir Oltean hw = enetc_hw_alloc(dev, imdio_regs); 1402bdeced75SVladimir Oltean if (IS_ERR(hw)) { 1403bdeced75SVladimir Oltean dev_err(dev, "failed to allocate ENETC HW structure\n"); 1404bdeced75SVladimir Oltean return PTR_ERR(hw); 1405bdeced75SVladimir Oltean } 1406bdeced75SVladimir Oltean 1407209bdb7eSVladimir Oltean bus = mdiobus_alloc_size(sizeof(*mdio_priv)); 1408bdeced75SVladimir Oltean if (!bus) 1409bdeced75SVladimir Oltean return -ENOMEM; 1410bdeced75SVladimir Oltean 1411bdeced75SVladimir Oltean bus->name = "VSC9959 internal MDIO bus"; 1412bdeced75SVladimir Oltean bus->read = enetc_mdio_read; 1413bdeced75SVladimir Oltean bus->write = enetc_mdio_write; 1414bdeced75SVladimir Oltean bus->parent = dev; 1415bdeced75SVladimir Oltean mdio_priv = bus->priv; 1416bdeced75SVladimir Oltean mdio_priv->hw = hw; 1417bdeced75SVladimir Oltean /* This gets added to imdio_regs, which already maps addresses 1418bdeced75SVladimir Oltean * starting with the proper offset. 1419bdeced75SVladimir Oltean */ 1420bdeced75SVladimir Oltean mdio_priv->mdio_base = 0; 1421bdeced75SVladimir Oltean snprintf(bus->id, MII_BUS_ID_SIZE, "%s-imdio", dev_name(dev)); 1422bdeced75SVladimir Oltean 1423bdeced75SVladimir Oltean /* Needed in order to initialize the bus mutex lock */ 1424bdeced75SVladimir Oltean rc = mdiobus_register(bus); 1425bdeced75SVladimir Oltean if (rc < 0) { 1426bdeced75SVladimir Oltean dev_err(dev, "failed to register MDIO bus\n"); 1427209bdb7eSVladimir Oltean mdiobus_free(bus); 1428bdeced75SVladimir Oltean return rc; 1429bdeced75SVladimir Oltean } 1430bdeced75SVladimir Oltean 1431bdeced75SVladimir Oltean felix->imdio = bus; 1432bdeced75SVladimir Oltean 1433bdeced75SVladimir Oltean for (port = 0; port < felix->info->num_ports; port++) { 1434bdeced75SVladimir Oltean struct ocelot_port *ocelot_port = ocelot->ports[port]; 1435e7026f15SColin Foster struct phylink_pcs *phylink_pcs; 143661f0d0c3SColin Foster struct mdio_device *mdio_device; 1437bdeced75SVladimir Oltean 1438588d0550SIoana Ciornei if (dsa_is_unused_port(felix->ds, port)) 1439588d0550SIoana Ciornei continue; 1440bdeced75SVladimir Oltean 1441588d0550SIoana Ciornei if (ocelot_port->phy_mode == PHY_INTERFACE_MODE_INTERNAL) 1442588d0550SIoana Ciornei continue; 1443588d0550SIoana Ciornei 144461f0d0c3SColin Foster mdio_device = mdio_device_create(felix->imdio, port); 144561f0d0c3SColin Foster if (IS_ERR(mdio_device)) 1446bdeced75SVladimir Oltean continue; 1447bdeced75SVladimir Oltean 144861f0d0c3SColin Foster phylink_pcs = lynx_pcs_create(mdio_device); 1449e7026f15SColin Foster if (!phylink_pcs) { 145061f0d0c3SColin Foster mdio_device_free(mdio_device); 1451588d0550SIoana Ciornei continue; 1452588d0550SIoana Ciornei } 1453588d0550SIoana Ciornei 1454e7026f15SColin Foster felix->pcs[port] = phylink_pcs; 1455bdeced75SVladimir Oltean 1456bdeced75SVladimir Oltean dev_info(dev, "Found PCS at internal MDIO address %d\n", port); 1457bdeced75SVladimir Oltean } 1458bdeced75SVladimir Oltean 1459bdeced75SVladimir Oltean return 0; 1460bdeced75SVladimir Oltean } 1461bdeced75SVladimir Oltean 1462ccfdbab5SVladimir Oltean static void vsc9959_mdio_bus_free(struct ocelot *ocelot) 1463bdeced75SVladimir Oltean { 1464bdeced75SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 1465bdeced75SVladimir Oltean int port; 1466bdeced75SVladimir Oltean 1467bdeced75SVladimir Oltean for (port = 0; port < ocelot->num_phys_ports; port++) { 1468e7026f15SColin Foster struct phylink_pcs *phylink_pcs = felix->pcs[port]; 1469e7026f15SColin Foster struct mdio_device *mdio_device; 1470bdeced75SVladimir Oltean 1471e7026f15SColin Foster if (!phylink_pcs) 1472bdeced75SVladimir Oltean continue; 1473bdeced75SVladimir Oltean 1474e7026f15SColin Foster mdio_device = lynx_get_mdio_device(phylink_pcs); 1475e7026f15SColin Foster mdio_device_free(mdio_device); 1476e7026f15SColin Foster lynx_pcs_destroy(phylink_pcs); 1477bdeced75SVladimir Oltean } 1478bdeced75SVladimir Oltean mdiobus_unregister(felix->imdio); 1479209bdb7eSVladimir Oltean mdiobus_free(felix->imdio); 1480bdeced75SVladimir Oltean } 1481bdeced75SVladimir Oltean 1482*11afdc65SVladimir Oltean /* The switch considers any frame (regardless of size) as eligible for 1483*11afdc65SVladimir Oltean * transmission if the traffic class gate is open for at least 33 ns. 1484*11afdc65SVladimir Oltean * Overruns are prevented by cropping an interval at the end of the gate time 1485*11afdc65SVladimir Oltean * slot for which egress scheduling is blocked, but we need to still keep 33 ns 1486*11afdc65SVladimir Oltean * available for one packet to be transmitted, otherwise the port tc will hang. 1487*11afdc65SVladimir Oltean * This function returns the size of a gate interval that remains available for 1488*11afdc65SVladimir Oltean * setting the guard band, after reserving the space for one egress frame. 1489*11afdc65SVladimir Oltean */ 1490*11afdc65SVladimir Oltean static u64 vsc9959_tas_remaining_gate_len_ps(u64 gate_len_ns) 1491*11afdc65SVladimir Oltean { 1492*11afdc65SVladimir Oltean /* Gate always open */ 1493*11afdc65SVladimir Oltean if (gate_len_ns == U64_MAX) 1494*11afdc65SVladimir Oltean return U64_MAX; 1495*11afdc65SVladimir Oltean 1496*11afdc65SVladimir Oltean return (gate_len_ns - VSC9959_TAS_MIN_GATE_LEN_NS) * PSEC_PER_NSEC; 1497*11afdc65SVladimir Oltean } 1498*11afdc65SVladimir Oltean 149955a515b1SVladimir Oltean /* Extract shortest continuous gate open intervals in ns for each traffic class 150055a515b1SVladimir Oltean * of a cyclic tc-taprio schedule. If a gate is always open, the duration is 150155a515b1SVladimir Oltean * considered U64_MAX. If the gate is always closed, it is considered 0. 150255a515b1SVladimir Oltean */ 150355a515b1SVladimir Oltean static void vsc9959_tas_min_gate_lengths(struct tc_taprio_qopt_offload *taprio, 150455a515b1SVladimir Oltean u64 min_gate_len[OCELOT_NUM_TC]) 150555a515b1SVladimir Oltean { 150655a515b1SVladimir Oltean struct tc_taprio_sched_entry *entry; 150755a515b1SVladimir Oltean u64 gate_len[OCELOT_NUM_TC]; 15087e4babffSVladimir Oltean u8 gates_ever_opened = 0; 150955a515b1SVladimir Oltean int tc, i, n; 151055a515b1SVladimir Oltean 151155a515b1SVladimir Oltean /* Initialize arrays */ 151255a515b1SVladimir Oltean for (tc = 0; tc < OCELOT_NUM_TC; tc++) { 151355a515b1SVladimir Oltean min_gate_len[tc] = U64_MAX; 151455a515b1SVladimir Oltean gate_len[tc] = 0; 151555a515b1SVladimir Oltean } 151655a515b1SVladimir Oltean 151755a515b1SVladimir Oltean /* If we don't have taprio, consider all gates as permanently open */ 151855a515b1SVladimir Oltean if (!taprio) 151955a515b1SVladimir Oltean return; 152055a515b1SVladimir Oltean 152155a515b1SVladimir Oltean n = taprio->num_entries; 152255a515b1SVladimir Oltean 152355a515b1SVladimir Oltean /* Walk through the gate list twice to determine the length 152455a515b1SVladimir Oltean * of consecutively open gates for a traffic class, including 152555a515b1SVladimir Oltean * open gates that wrap around. We are just interested in the 152655a515b1SVladimir Oltean * minimum window size, and this doesn't change what the 152755a515b1SVladimir Oltean * minimum is (if the gate never closes, min_gate_len will 152855a515b1SVladimir Oltean * remain U64_MAX). 152955a515b1SVladimir Oltean */ 153055a515b1SVladimir Oltean for (i = 0; i < 2 * n; i++) { 153155a515b1SVladimir Oltean entry = &taprio->entries[i % n]; 153255a515b1SVladimir Oltean 153355a515b1SVladimir Oltean for (tc = 0; tc < OCELOT_NUM_TC; tc++) { 153455a515b1SVladimir Oltean if (entry->gate_mask & BIT(tc)) { 153555a515b1SVladimir Oltean gate_len[tc] += entry->interval; 15367e4babffSVladimir Oltean gates_ever_opened |= BIT(tc); 153755a515b1SVladimir Oltean } else { 153855a515b1SVladimir Oltean /* Gate closes now, record a potential new 153955a515b1SVladimir Oltean * minimum and reinitialize length 154055a515b1SVladimir Oltean */ 15417e4babffSVladimir Oltean if (min_gate_len[tc] > gate_len[tc] && 15427e4babffSVladimir Oltean gate_len[tc]) 154355a515b1SVladimir Oltean min_gate_len[tc] = gate_len[tc]; 154455a515b1SVladimir Oltean gate_len[tc] = 0; 154555a515b1SVladimir Oltean } 154655a515b1SVladimir Oltean } 154755a515b1SVladimir Oltean } 15487e4babffSVladimir Oltean 15497e4babffSVladimir Oltean /* min_gate_len[tc] actually tracks minimum *open* gate time, so for 15507e4babffSVladimir Oltean * permanently closed gates, min_gate_len[tc] will still be U64_MAX. 15517e4babffSVladimir Oltean * Therefore they are currently indistinguishable from permanently 15527e4babffSVladimir Oltean * open gates. Overwrite the gate len with 0 when we know they're 15537e4babffSVladimir Oltean * actually permanently closed, i.e. after the loop above. 15547e4babffSVladimir Oltean */ 15557e4babffSVladimir Oltean for (tc = 0; tc < OCELOT_NUM_TC; tc++) 15567e4babffSVladimir Oltean if (!(gates_ever_opened & BIT(tc))) 15577e4babffSVladimir Oltean min_gate_len[tc] = 0; 155855a515b1SVladimir Oltean } 155955a515b1SVladimir Oltean 156055a515b1SVladimir Oltean /* Update QSYS_PORT_MAX_SDU to make sure the static guard bands added by the 156155a515b1SVladimir Oltean * switch (see the ALWAYS_GUARD_BAND_SCH_Q comment) are correct at all MTU 156255a515b1SVladimir Oltean * values (the default value is 1518). Also, for traffic class windows smaller 156355a515b1SVladimir Oltean * than one MTU sized frame, update QSYS_QMAXSDU_CFG to enable oversized frame 156455a515b1SVladimir Oltean * dropping, such that these won't hang the port, as they will never be sent. 156555a515b1SVladimir Oltean */ 156655a515b1SVladimir Oltean static void vsc9959_tas_guard_bands_update(struct ocelot *ocelot, int port) 156755a515b1SVladimir Oltean { 156855a515b1SVladimir Oltean struct ocelot_port *ocelot_port = ocelot->ports[port]; 156955a515b1SVladimir Oltean u64 min_gate_len[OCELOT_NUM_TC]; 157055a515b1SVladimir Oltean int speed, picos_per_byte; 157155a515b1SVladimir Oltean u64 needed_bit_time_ps; 157255a515b1SVladimir Oltean u32 val, maxlen; 157355a515b1SVladimir Oltean u8 tas_speed; 157455a515b1SVladimir Oltean int tc; 157555a515b1SVladimir Oltean 157655a515b1SVladimir Oltean lockdep_assert_held(&ocelot->tas_lock); 157755a515b1SVladimir Oltean 157855a515b1SVladimir Oltean val = ocelot_read_rix(ocelot, QSYS_TAG_CONFIG, port); 157955a515b1SVladimir Oltean tas_speed = QSYS_TAG_CONFIG_LINK_SPEED_X(val); 158055a515b1SVladimir Oltean 158155a515b1SVladimir Oltean switch (tas_speed) { 158255a515b1SVladimir Oltean case OCELOT_SPEED_10: 158355a515b1SVladimir Oltean speed = SPEED_10; 158455a515b1SVladimir Oltean break; 158555a515b1SVladimir Oltean case OCELOT_SPEED_100: 158655a515b1SVladimir Oltean speed = SPEED_100; 158755a515b1SVladimir Oltean break; 158855a515b1SVladimir Oltean case OCELOT_SPEED_1000: 158955a515b1SVladimir Oltean speed = SPEED_1000; 159055a515b1SVladimir Oltean break; 159155a515b1SVladimir Oltean case OCELOT_SPEED_2500: 159255a515b1SVladimir Oltean speed = SPEED_2500; 159355a515b1SVladimir Oltean break; 159455a515b1SVladimir Oltean default: 159555a515b1SVladimir Oltean return; 159655a515b1SVladimir Oltean } 159755a515b1SVladimir Oltean 159855a515b1SVladimir Oltean picos_per_byte = (USEC_PER_SEC * 8) / speed; 159955a515b1SVladimir Oltean 160055a515b1SVladimir Oltean val = ocelot_port_readl(ocelot_port, DEV_MAC_MAXLEN_CFG); 160155a515b1SVladimir Oltean /* MAXLEN_CFG accounts automatically for VLAN. We need to include it 160255a515b1SVladimir Oltean * manually in the bit time calculation, plus the preamble and SFD. 160355a515b1SVladimir Oltean */ 160455a515b1SVladimir Oltean maxlen = val + 2 * VLAN_HLEN; 160555a515b1SVladimir Oltean /* Consider the standard Ethernet overhead of 8 octets preamble+SFD, 160655a515b1SVladimir Oltean * 4 octets FCS, 12 octets IFG. 160755a515b1SVladimir Oltean */ 160855a515b1SVladimir Oltean needed_bit_time_ps = (maxlen + 24) * picos_per_byte; 160955a515b1SVladimir Oltean 161055a515b1SVladimir Oltean dev_dbg(ocelot->dev, 161155a515b1SVladimir Oltean "port %d: max frame size %d needs %llu ps at speed %d\n", 161255a515b1SVladimir Oltean port, maxlen, needed_bit_time_ps, speed); 161355a515b1SVladimir Oltean 161455a515b1SVladimir Oltean vsc9959_tas_min_gate_lengths(ocelot_port->taprio, min_gate_len); 161555a515b1SVladimir Oltean 161655a515b1SVladimir Oltean for (tc = 0; tc < OCELOT_NUM_TC; tc++) { 1617*11afdc65SVladimir Oltean u64 remaining_gate_len_ps; 161855a515b1SVladimir Oltean u32 max_sdu; 161955a515b1SVladimir Oltean 1620*11afdc65SVladimir Oltean remaining_gate_len_ps = 1621*11afdc65SVladimir Oltean vsc9959_tas_remaining_gate_len_ps(min_gate_len[tc]); 1622*11afdc65SVladimir Oltean 1623*11afdc65SVladimir Oltean if (remaining_gate_len_ps > needed_bit_time_ps) { 162455a515b1SVladimir Oltean /* Setting QMAXSDU_CFG to 0 disables oversized frame 162555a515b1SVladimir Oltean * dropping. 162655a515b1SVladimir Oltean */ 162755a515b1SVladimir Oltean max_sdu = 0; 162855a515b1SVladimir Oltean dev_dbg(ocelot->dev, 162955a515b1SVladimir Oltean "port %d tc %d min gate len %llu" 163055a515b1SVladimir Oltean ", sending all frames\n", 163155a515b1SVladimir Oltean port, tc, min_gate_len[tc]); 163255a515b1SVladimir Oltean } else { 163355a515b1SVladimir Oltean /* If traffic class doesn't support a full MTU sized 163455a515b1SVladimir Oltean * frame, make sure to enable oversize frame dropping 163555a515b1SVladimir Oltean * for frames larger than the smallest that would fit. 1636*11afdc65SVladimir Oltean * 1637*11afdc65SVladimir Oltean * However, the exact same register, QSYS_QMAXSDU_CFG_*, 1638*11afdc65SVladimir Oltean * controls not only oversized frame dropping, but also 1639*11afdc65SVladimir Oltean * per-tc static guard band lengths, so it reduces the 1640*11afdc65SVladimir Oltean * useful gate interval length. Therefore, be careful 1641*11afdc65SVladimir Oltean * to calculate a guard band (and therefore max_sdu) 1642*11afdc65SVladimir Oltean * that still leaves 33 ns available in the time slot. 164355a515b1SVladimir Oltean */ 1644*11afdc65SVladimir Oltean max_sdu = div_u64(remaining_gate_len_ps, picos_per_byte); 164555a515b1SVladimir Oltean /* A TC gate may be completely closed, which is a 164655a515b1SVladimir Oltean * special case where all packets are oversized. 164755a515b1SVladimir Oltean * Any limit smaller than 64 octets accomplishes this 164855a515b1SVladimir Oltean */ 164955a515b1SVladimir Oltean if (!max_sdu) 165055a515b1SVladimir Oltean max_sdu = 1; 165155a515b1SVladimir Oltean /* Take L1 overhead into account, but just don't allow 165255a515b1SVladimir Oltean * max_sdu to go negative or to 0. Here we use 20 165355a515b1SVladimir Oltean * because QSYS_MAXSDU_CFG_* already counts the 4 FCS 165455a515b1SVladimir Oltean * octets as part of packet size. 165555a515b1SVladimir Oltean */ 165655a515b1SVladimir Oltean if (max_sdu > 20) 165755a515b1SVladimir Oltean max_sdu -= 20; 165855a515b1SVladimir Oltean dev_info(ocelot->dev, 165955a515b1SVladimir Oltean "port %d tc %d min gate length %llu" 166055a515b1SVladimir Oltean " ns not enough for max frame size %d at %d" 166155a515b1SVladimir Oltean " Mbps, dropping frames over %d" 166255a515b1SVladimir Oltean " octets including FCS\n", 166355a515b1SVladimir Oltean port, tc, min_gate_len[tc], maxlen, speed, 166455a515b1SVladimir Oltean max_sdu); 166555a515b1SVladimir Oltean } 166655a515b1SVladimir Oltean 166755a515b1SVladimir Oltean /* ocelot_write_rix is a macro that concatenates 166855a515b1SVladimir Oltean * QSYS_MAXSDU_CFG_* with _RSZ, so we need to spell out 166955a515b1SVladimir Oltean * the writes to each traffic class 167055a515b1SVladimir Oltean */ 167155a515b1SVladimir Oltean switch (tc) { 167255a515b1SVladimir Oltean case 0: 167355a515b1SVladimir Oltean ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_0, 167455a515b1SVladimir Oltean port); 167555a515b1SVladimir Oltean break; 167655a515b1SVladimir Oltean case 1: 167755a515b1SVladimir Oltean ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_1, 167855a515b1SVladimir Oltean port); 167955a515b1SVladimir Oltean break; 168055a515b1SVladimir Oltean case 2: 168155a515b1SVladimir Oltean ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_2, 168255a515b1SVladimir Oltean port); 168355a515b1SVladimir Oltean break; 168455a515b1SVladimir Oltean case 3: 168555a515b1SVladimir Oltean ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_3, 168655a515b1SVladimir Oltean port); 168755a515b1SVladimir Oltean break; 168855a515b1SVladimir Oltean case 4: 168955a515b1SVladimir Oltean ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_4, 169055a515b1SVladimir Oltean port); 169155a515b1SVladimir Oltean break; 169255a515b1SVladimir Oltean case 5: 169355a515b1SVladimir Oltean ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_5, 169455a515b1SVladimir Oltean port); 169555a515b1SVladimir Oltean break; 169655a515b1SVladimir Oltean case 6: 169755a515b1SVladimir Oltean ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_6, 169855a515b1SVladimir Oltean port); 169955a515b1SVladimir Oltean break; 170055a515b1SVladimir Oltean case 7: 170155a515b1SVladimir Oltean ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_7, 170255a515b1SVladimir Oltean port); 170355a515b1SVladimir Oltean break; 170455a515b1SVladimir Oltean } 170555a515b1SVladimir Oltean } 170655a515b1SVladimir Oltean 170755a515b1SVladimir Oltean ocelot_write_rix(ocelot, maxlen, QSYS_PORT_MAX_SDU, port); 170855a515b1SVladimir Oltean } 170955a515b1SVladimir Oltean 1710de143c0eSXiaoliang Yang static void vsc9959_sched_speed_set(struct ocelot *ocelot, int port, 1711de143c0eSXiaoliang Yang u32 speed) 1712de143c0eSXiaoliang Yang { 171355a515b1SVladimir Oltean struct ocelot_port *ocelot_port = ocelot->ports[port]; 1714dba1e466SXiaoliang Yang u8 tas_speed; 1715dba1e466SXiaoliang Yang 1716dba1e466SXiaoliang Yang switch (speed) { 1717dba1e466SXiaoliang Yang case SPEED_10: 1718dba1e466SXiaoliang Yang tas_speed = OCELOT_SPEED_10; 1719dba1e466SXiaoliang Yang break; 1720dba1e466SXiaoliang Yang case SPEED_100: 1721dba1e466SXiaoliang Yang tas_speed = OCELOT_SPEED_100; 1722dba1e466SXiaoliang Yang break; 1723dba1e466SXiaoliang Yang case SPEED_1000: 1724dba1e466SXiaoliang Yang tas_speed = OCELOT_SPEED_1000; 1725dba1e466SXiaoliang Yang break; 1726dba1e466SXiaoliang Yang case SPEED_2500: 1727dba1e466SXiaoliang Yang tas_speed = OCELOT_SPEED_2500; 1728dba1e466SXiaoliang Yang break; 1729dba1e466SXiaoliang Yang default: 1730dba1e466SXiaoliang Yang tas_speed = OCELOT_SPEED_1000; 1731dba1e466SXiaoliang Yang break; 1732dba1e466SXiaoliang Yang } 1733dba1e466SXiaoliang Yang 1734de143c0eSXiaoliang Yang ocelot_rmw_rix(ocelot, 1735dba1e466SXiaoliang Yang QSYS_TAG_CONFIG_LINK_SPEED(tas_speed), 1736de143c0eSXiaoliang Yang QSYS_TAG_CONFIG_LINK_SPEED_M, 1737de143c0eSXiaoliang Yang QSYS_TAG_CONFIG, port); 173855a515b1SVladimir Oltean 173955a515b1SVladimir Oltean mutex_lock(&ocelot->tas_lock); 174055a515b1SVladimir Oltean 174155a515b1SVladimir Oltean if (ocelot_port->taprio) 174255a515b1SVladimir Oltean vsc9959_tas_guard_bands_update(ocelot, port); 174355a515b1SVladimir Oltean 174455a515b1SVladimir Oltean mutex_unlock(&ocelot->tas_lock); 1745de143c0eSXiaoliang Yang } 1746de143c0eSXiaoliang Yang 1747de143c0eSXiaoliang Yang static void vsc9959_new_base_time(struct ocelot *ocelot, ktime_t base_time, 1748de143c0eSXiaoliang Yang u64 cycle_time, 1749de143c0eSXiaoliang Yang struct timespec64 *new_base_ts) 1750de143c0eSXiaoliang Yang { 1751de143c0eSXiaoliang Yang struct timespec64 ts; 1752de143c0eSXiaoliang Yang ktime_t new_base_time; 1753de143c0eSXiaoliang Yang ktime_t current_time; 1754de143c0eSXiaoliang Yang 1755de143c0eSXiaoliang Yang ocelot_ptp_gettime64(&ocelot->ptp_info, &ts); 1756de143c0eSXiaoliang Yang current_time = timespec64_to_ktime(ts); 1757de143c0eSXiaoliang Yang new_base_time = base_time; 1758de143c0eSXiaoliang Yang 1759de143c0eSXiaoliang Yang if (base_time < current_time) { 1760de143c0eSXiaoliang Yang u64 nr_of_cycles = current_time - base_time; 1761de143c0eSXiaoliang Yang 1762de143c0eSXiaoliang Yang do_div(nr_of_cycles, cycle_time); 1763de143c0eSXiaoliang Yang new_base_time += cycle_time * (nr_of_cycles + 1); 1764de143c0eSXiaoliang Yang } 1765de143c0eSXiaoliang Yang 1766de143c0eSXiaoliang Yang *new_base_ts = ktime_to_timespec64(new_base_time); 1767de143c0eSXiaoliang Yang } 1768de143c0eSXiaoliang Yang 1769de143c0eSXiaoliang Yang static u32 vsc9959_tas_read_cfg_status(struct ocelot *ocelot) 1770de143c0eSXiaoliang Yang { 1771de143c0eSXiaoliang Yang return ocelot_read(ocelot, QSYS_TAS_PARAM_CFG_CTRL); 1772de143c0eSXiaoliang Yang } 1773de143c0eSXiaoliang Yang 1774de143c0eSXiaoliang Yang static void vsc9959_tas_gcl_set(struct ocelot *ocelot, const u32 gcl_ix, 1775de143c0eSXiaoliang Yang struct tc_taprio_sched_entry *entry) 1776de143c0eSXiaoliang Yang { 1777de143c0eSXiaoliang Yang ocelot_write(ocelot, 1778de143c0eSXiaoliang Yang QSYS_GCL_CFG_REG_1_GCL_ENTRY_NUM(gcl_ix) | 1779de143c0eSXiaoliang Yang QSYS_GCL_CFG_REG_1_GATE_STATE(entry->gate_mask), 1780de143c0eSXiaoliang Yang QSYS_GCL_CFG_REG_1); 1781de143c0eSXiaoliang Yang ocelot_write(ocelot, entry->interval, QSYS_GCL_CFG_REG_2); 1782de143c0eSXiaoliang Yang } 1783de143c0eSXiaoliang Yang 1784de143c0eSXiaoliang Yang static int vsc9959_qos_port_tas_set(struct ocelot *ocelot, int port, 1785de143c0eSXiaoliang Yang struct tc_taprio_qopt_offload *taprio) 1786de143c0eSXiaoliang Yang { 17878670dc33SXiaoliang Yang struct ocelot_port *ocelot_port = ocelot->ports[port]; 1788de143c0eSXiaoliang Yang struct timespec64 base_ts; 1789de143c0eSXiaoliang Yang int ret, i; 1790de143c0eSXiaoliang Yang u32 val; 1791de143c0eSXiaoliang Yang 17928670dc33SXiaoliang Yang mutex_lock(&ocelot->tas_lock); 17938670dc33SXiaoliang Yang 1794de143c0eSXiaoliang Yang if (!taprio->enable) { 1795d68a373bSVladimir Oltean ocelot_rmw_rix(ocelot, 0, QSYS_TAG_CONFIG_ENABLE, 1796de143c0eSXiaoliang Yang QSYS_TAG_CONFIG, port); 1797de143c0eSXiaoliang Yang 17981c9017e4SVladimir Oltean taprio_offload_free(ocelot_port->taprio); 17991c9017e4SVladimir Oltean ocelot_port->taprio = NULL; 18001c9017e4SVladimir Oltean 180155a515b1SVladimir Oltean vsc9959_tas_guard_bands_update(ocelot, port); 180255a515b1SVladimir Oltean 18038670dc33SXiaoliang Yang mutex_unlock(&ocelot->tas_lock); 1804de143c0eSXiaoliang Yang return 0; 1805de143c0eSXiaoliang Yang } 1806de143c0eSXiaoliang Yang 1807de143c0eSXiaoliang Yang if (taprio->cycle_time > NSEC_PER_SEC || 18088670dc33SXiaoliang Yang taprio->cycle_time_extension >= NSEC_PER_SEC) { 18098670dc33SXiaoliang Yang ret = -EINVAL; 18108670dc33SXiaoliang Yang goto err; 18118670dc33SXiaoliang Yang } 1812de143c0eSXiaoliang Yang 18138670dc33SXiaoliang Yang if (taprio->num_entries > VSC9959_TAS_GCL_ENTRY_MAX) { 18148670dc33SXiaoliang Yang ret = -ERANGE; 18158670dc33SXiaoliang Yang goto err; 18168670dc33SXiaoliang Yang } 1817de143c0eSXiaoliang Yang 1818297c4de6SMichael Walle /* Enable guard band. The switch will schedule frames without taking 1819297c4de6SMichael Walle * their length into account. Thus we'll always need to enable the 1820297c4de6SMichael Walle * guard band which reserves the time of a maximum sized frame at the 1821297c4de6SMichael Walle * end of the time window. 1822297c4de6SMichael Walle * 1823297c4de6SMichael Walle * Although the ALWAYS_GUARD_BAND_SCH_Q bit is global for all ports, we 1824297c4de6SMichael Walle * need to set PORT_NUM, because subsequent writes to PARAM_CFG_REG_n 1825297c4de6SMichael Walle * operate on the port number. 1826316bcffeSXiaoliang Yang */ 1827297c4de6SMichael Walle ocelot_rmw(ocelot, QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM(port) | 1828297c4de6SMichael Walle QSYS_TAS_PARAM_CFG_CTRL_ALWAYS_GUARD_BAND_SCH_Q, 1829de143c0eSXiaoliang Yang QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM_M | 1830de143c0eSXiaoliang Yang QSYS_TAS_PARAM_CFG_CTRL_ALWAYS_GUARD_BAND_SCH_Q, 1831de143c0eSXiaoliang Yang QSYS_TAS_PARAM_CFG_CTRL); 1832de143c0eSXiaoliang Yang 1833de143c0eSXiaoliang Yang /* Hardware errata - Admin config could not be overwritten if 1834de143c0eSXiaoliang Yang * config is pending, need reset the TAS module 1835de143c0eSXiaoliang Yang */ 1836de143c0eSXiaoliang Yang val = ocelot_read(ocelot, QSYS_PARAM_STATUS_REG_8); 18378670dc33SXiaoliang Yang if (val & QSYS_PARAM_STATUS_REG_8_CONFIG_PENDING) { 18388670dc33SXiaoliang Yang ret = -EBUSY; 18398670dc33SXiaoliang Yang goto err; 18408670dc33SXiaoliang Yang } 1841de143c0eSXiaoliang Yang 1842de143c0eSXiaoliang Yang ocelot_rmw_rix(ocelot, 1843de143c0eSXiaoliang Yang QSYS_TAG_CONFIG_ENABLE | 1844de143c0eSXiaoliang Yang QSYS_TAG_CONFIG_INIT_GATE_STATE(0xFF) | 1845de143c0eSXiaoliang Yang QSYS_TAG_CONFIG_SCH_TRAFFIC_QUEUES(0xFF), 1846de143c0eSXiaoliang Yang QSYS_TAG_CONFIG_ENABLE | 1847de143c0eSXiaoliang Yang QSYS_TAG_CONFIG_INIT_GATE_STATE_M | 1848de143c0eSXiaoliang Yang QSYS_TAG_CONFIG_SCH_TRAFFIC_QUEUES_M, 1849de143c0eSXiaoliang Yang QSYS_TAG_CONFIG, port); 1850de143c0eSXiaoliang Yang 1851de143c0eSXiaoliang Yang vsc9959_new_base_time(ocelot, taprio->base_time, 1852de143c0eSXiaoliang Yang taprio->cycle_time, &base_ts); 1853de143c0eSXiaoliang Yang ocelot_write(ocelot, base_ts.tv_nsec, QSYS_PARAM_CFG_REG_1); 1854de143c0eSXiaoliang Yang ocelot_write(ocelot, lower_32_bits(base_ts.tv_sec), QSYS_PARAM_CFG_REG_2); 1855de143c0eSXiaoliang Yang val = upper_32_bits(base_ts.tv_sec); 1856de143c0eSXiaoliang Yang ocelot_write(ocelot, 1857de143c0eSXiaoliang Yang QSYS_PARAM_CFG_REG_3_BASE_TIME_SEC_MSB(val) | 1858de143c0eSXiaoliang Yang QSYS_PARAM_CFG_REG_3_LIST_LENGTH(taprio->num_entries), 1859de143c0eSXiaoliang Yang QSYS_PARAM_CFG_REG_3); 1860de143c0eSXiaoliang Yang ocelot_write(ocelot, taprio->cycle_time, QSYS_PARAM_CFG_REG_4); 1861de143c0eSXiaoliang Yang ocelot_write(ocelot, taprio->cycle_time_extension, QSYS_PARAM_CFG_REG_5); 1862de143c0eSXiaoliang Yang 1863de143c0eSXiaoliang Yang for (i = 0; i < taprio->num_entries; i++) 1864de143c0eSXiaoliang Yang vsc9959_tas_gcl_set(ocelot, i, &taprio->entries[i]); 1865de143c0eSXiaoliang Yang 1866de143c0eSXiaoliang Yang ocelot_rmw(ocelot, QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE, 1867de143c0eSXiaoliang Yang QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE, 1868de143c0eSXiaoliang Yang QSYS_TAS_PARAM_CFG_CTRL); 1869de143c0eSXiaoliang Yang 1870de143c0eSXiaoliang Yang ret = readx_poll_timeout(vsc9959_tas_read_cfg_status, ocelot, val, 1871de143c0eSXiaoliang Yang !(val & QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE), 1872de143c0eSXiaoliang Yang 10, 100000); 18731c9017e4SVladimir Oltean if (ret) 18741c9017e4SVladimir Oltean goto err; 18751c9017e4SVladimir Oltean 18761c9017e4SVladimir Oltean ocelot_port->taprio = taprio_offload_get(taprio); 187755a515b1SVladimir Oltean vsc9959_tas_guard_bands_update(ocelot, port); 1878de143c0eSXiaoliang Yang 18798670dc33SXiaoliang Yang err: 18808670dc33SXiaoliang Yang mutex_unlock(&ocelot->tas_lock); 18818670dc33SXiaoliang Yang 1882de143c0eSXiaoliang Yang return ret; 1883de143c0eSXiaoliang Yang } 1884de143c0eSXiaoliang Yang 18858670dc33SXiaoliang Yang static void vsc9959_tas_clock_adjust(struct ocelot *ocelot) 18868670dc33SXiaoliang Yang { 18871c9017e4SVladimir Oltean struct tc_taprio_qopt_offload *taprio; 18888670dc33SXiaoliang Yang struct ocelot_port *ocelot_port; 18898670dc33SXiaoliang Yang struct timespec64 base_ts; 18908670dc33SXiaoliang Yang int port; 18918670dc33SXiaoliang Yang u32 val; 18928670dc33SXiaoliang Yang 18938670dc33SXiaoliang Yang mutex_lock(&ocelot->tas_lock); 18948670dc33SXiaoliang Yang 18958670dc33SXiaoliang Yang for (port = 0; port < ocelot->num_phys_ports; port++) { 18961c9017e4SVladimir Oltean ocelot_port = ocelot->ports[port]; 18971c9017e4SVladimir Oltean taprio = ocelot_port->taprio; 18981c9017e4SVladimir Oltean if (!taprio) 18998670dc33SXiaoliang Yang continue; 19008670dc33SXiaoliang Yang 19018670dc33SXiaoliang Yang ocelot_rmw(ocelot, 19028670dc33SXiaoliang Yang QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM(port), 19038670dc33SXiaoliang Yang QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM_M, 19048670dc33SXiaoliang Yang QSYS_TAS_PARAM_CFG_CTRL); 19058670dc33SXiaoliang Yang 1906d68a373bSVladimir Oltean /* Disable time-aware shaper */ 1907d68a373bSVladimir Oltean ocelot_rmw_rix(ocelot, 0, QSYS_TAG_CONFIG_ENABLE, 19088670dc33SXiaoliang Yang QSYS_TAG_CONFIG, port); 19098670dc33SXiaoliang Yang 19101c9017e4SVladimir Oltean vsc9959_new_base_time(ocelot, taprio->base_time, 19111c9017e4SVladimir Oltean taprio->cycle_time, &base_ts); 19128670dc33SXiaoliang Yang 19138670dc33SXiaoliang Yang ocelot_write(ocelot, base_ts.tv_nsec, QSYS_PARAM_CFG_REG_1); 19148670dc33SXiaoliang Yang ocelot_write(ocelot, lower_32_bits(base_ts.tv_sec), 19158670dc33SXiaoliang Yang QSYS_PARAM_CFG_REG_2); 19168670dc33SXiaoliang Yang val = upper_32_bits(base_ts.tv_sec); 19178670dc33SXiaoliang Yang ocelot_rmw(ocelot, 19188670dc33SXiaoliang Yang QSYS_PARAM_CFG_REG_3_BASE_TIME_SEC_MSB(val), 19198670dc33SXiaoliang Yang QSYS_PARAM_CFG_REG_3_BASE_TIME_SEC_MSB_M, 19208670dc33SXiaoliang Yang QSYS_PARAM_CFG_REG_3); 19218670dc33SXiaoliang Yang 19228670dc33SXiaoliang Yang ocelot_rmw(ocelot, QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE, 19238670dc33SXiaoliang Yang QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE, 19248670dc33SXiaoliang Yang QSYS_TAS_PARAM_CFG_CTRL); 19258670dc33SXiaoliang Yang 1926d68a373bSVladimir Oltean /* Re-enable time-aware shaper */ 1927d68a373bSVladimir Oltean ocelot_rmw_rix(ocelot, QSYS_TAG_CONFIG_ENABLE, 19288670dc33SXiaoliang Yang QSYS_TAG_CONFIG_ENABLE, 19298670dc33SXiaoliang Yang QSYS_TAG_CONFIG, port); 19308670dc33SXiaoliang Yang } 19318670dc33SXiaoliang Yang mutex_unlock(&ocelot->tas_lock); 19328670dc33SXiaoliang Yang } 19338670dc33SXiaoliang Yang 19340fbabf87SXiaoliang Yang static int vsc9959_qos_port_cbs_set(struct dsa_switch *ds, int port, 19350fbabf87SXiaoliang Yang struct tc_cbs_qopt_offload *cbs_qopt) 19360fbabf87SXiaoliang Yang { 19370fbabf87SXiaoliang Yang struct ocelot *ocelot = ds->priv; 19380fbabf87SXiaoliang Yang int port_ix = port * 8 + cbs_qopt->queue; 19390fbabf87SXiaoliang Yang u32 rate, burst; 19400fbabf87SXiaoliang Yang 19410fbabf87SXiaoliang Yang if (cbs_qopt->queue >= ds->num_tx_queues) 19420fbabf87SXiaoliang Yang return -EINVAL; 19430fbabf87SXiaoliang Yang 19440fbabf87SXiaoliang Yang if (!cbs_qopt->enable) { 19450fbabf87SXiaoliang Yang ocelot_write_gix(ocelot, QSYS_CIR_CFG_CIR_RATE(0) | 19460fbabf87SXiaoliang Yang QSYS_CIR_CFG_CIR_BURST(0), 19470fbabf87SXiaoliang Yang QSYS_CIR_CFG, port_ix); 19480fbabf87SXiaoliang Yang 19490fbabf87SXiaoliang Yang ocelot_rmw_gix(ocelot, 0, QSYS_SE_CFG_SE_AVB_ENA, 19500fbabf87SXiaoliang Yang QSYS_SE_CFG, port_ix); 19510fbabf87SXiaoliang Yang 19520fbabf87SXiaoliang Yang return 0; 19530fbabf87SXiaoliang Yang } 19540fbabf87SXiaoliang Yang 19550fbabf87SXiaoliang Yang /* Rate unit is 100 kbps */ 19560fbabf87SXiaoliang Yang rate = DIV_ROUND_UP(cbs_qopt->idleslope, 100); 19570fbabf87SXiaoliang Yang /* Avoid using zero rate */ 19580fbabf87SXiaoliang Yang rate = clamp_t(u32, rate, 1, GENMASK(14, 0)); 19590fbabf87SXiaoliang Yang /* Burst unit is 4kB */ 19600fbabf87SXiaoliang Yang burst = DIV_ROUND_UP(cbs_qopt->hicredit, 4096); 19610fbabf87SXiaoliang Yang /* Avoid using zero burst size */ 1962b014d043SColin Ian King burst = clamp_t(u32, burst, 1, GENMASK(5, 0)); 19630fbabf87SXiaoliang Yang ocelot_write_gix(ocelot, 19640fbabf87SXiaoliang Yang QSYS_CIR_CFG_CIR_RATE(rate) | 19650fbabf87SXiaoliang Yang QSYS_CIR_CFG_CIR_BURST(burst), 19660fbabf87SXiaoliang Yang QSYS_CIR_CFG, 19670fbabf87SXiaoliang Yang port_ix); 19680fbabf87SXiaoliang Yang 19690fbabf87SXiaoliang Yang ocelot_rmw_gix(ocelot, 19700fbabf87SXiaoliang Yang QSYS_SE_CFG_SE_FRM_MODE(0) | 19710fbabf87SXiaoliang Yang QSYS_SE_CFG_SE_AVB_ENA, 19720fbabf87SXiaoliang Yang QSYS_SE_CFG_SE_AVB_ENA | 19730fbabf87SXiaoliang Yang QSYS_SE_CFG_SE_FRM_MODE_M, 19740fbabf87SXiaoliang Yang QSYS_SE_CFG, 19750fbabf87SXiaoliang Yang port_ix); 19760fbabf87SXiaoliang Yang 19770fbabf87SXiaoliang Yang return 0; 19780fbabf87SXiaoliang Yang } 19790fbabf87SXiaoliang Yang 1980de143c0eSXiaoliang Yang static int vsc9959_port_setup_tc(struct dsa_switch *ds, int port, 1981de143c0eSXiaoliang Yang enum tc_setup_type type, 1982de143c0eSXiaoliang Yang void *type_data) 1983de143c0eSXiaoliang Yang { 1984de143c0eSXiaoliang Yang struct ocelot *ocelot = ds->priv; 1985de143c0eSXiaoliang Yang 1986de143c0eSXiaoliang Yang switch (type) { 1987de143c0eSXiaoliang Yang case TC_SETUP_QDISC_TAPRIO: 1988de143c0eSXiaoliang Yang return vsc9959_qos_port_tas_set(ocelot, port, type_data); 19890fbabf87SXiaoliang Yang case TC_SETUP_QDISC_CBS: 19900fbabf87SXiaoliang Yang return vsc9959_qos_port_cbs_set(ds, port, type_data); 1991de143c0eSXiaoliang Yang default: 1992de143c0eSXiaoliang Yang return -EOPNOTSUPP; 1993de143c0eSXiaoliang Yang } 1994de143c0eSXiaoliang Yang } 1995de143c0eSXiaoliang Yang 19967d4b564dSXiaoliang Yang #define VSC9959_PSFP_SFID_MAX 175 19977d4b564dSXiaoliang Yang #define VSC9959_PSFP_GATE_ID_MAX 183 199876c13edeSXiaoliang Yang #define VSC9959_PSFP_POLICER_BASE 63 19997d4b564dSXiaoliang Yang #define VSC9959_PSFP_POLICER_MAX 383 200023ae3a78SXiaoliang Yang #define VSC9959_PSFP_GATE_LIST_NUM 4 200123ae3a78SXiaoliang Yang #define VSC9959_PSFP_GATE_CYCLETIME_MIN 5000 20027d4b564dSXiaoliang Yang 20037d4b564dSXiaoliang Yang struct felix_stream { 20047d4b564dSXiaoliang Yang struct list_head list; 20057d4b564dSXiaoliang Yang unsigned long id; 2006a7e13edfSXiaoliang Yang bool dummy; 2007a7e13edfSXiaoliang Yang int ports; 2008a7e13edfSXiaoliang Yang int port; 20097d4b564dSXiaoliang Yang u8 dmac[ETH_ALEN]; 20107d4b564dSXiaoliang Yang u16 vid; 20117d4b564dSXiaoliang Yang s8 prio; 20127d4b564dSXiaoliang Yang u8 sfid_valid; 20137d4b564dSXiaoliang Yang u8 ssid_valid; 20147d4b564dSXiaoliang Yang u32 sfid; 20157d4b564dSXiaoliang Yang u32 ssid; 20167d4b564dSXiaoliang Yang }; 20177d4b564dSXiaoliang Yang 20187d4b564dSXiaoliang Yang struct felix_stream_filter { 20197d4b564dSXiaoliang Yang struct list_head list; 20207d4b564dSXiaoliang Yang refcount_t refcount; 20217d4b564dSXiaoliang Yang u32 index; 20227d4b564dSXiaoliang Yang u8 enable; 2023a7e13edfSXiaoliang Yang int portmask; 20247d4b564dSXiaoliang Yang u8 sg_valid; 20257d4b564dSXiaoliang Yang u32 sgid; 20267d4b564dSXiaoliang Yang u8 fm_valid; 20277d4b564dSXiaoliang Yang u32 fmid; 20287d4b564dSXiaoliang Yang u8 prio_valid; 20297d4b564dSXiaoliang Yang u8 prio; 20307d4b564dSXiaoliang Yang u32 maxsdu; 20317d4b564dSXiaoliang Yang }; 20327d4b564dSXiaoliang Yang 20337d4b564dSXiaoliang Yang struct felix_stream_filter_counters { 20347d4b564dSXiaoliang Yang u32 match; 20357d4b564dSXiaoliang Yang u32 not_pass_gate; 20367d4b564dSXiaoliang Yang u32 not_pass_sdu; 20377d4b564dSXiaoliang Yang u32 red; 20387d4b564dSXiaoliang Yang }; 20397d4b564dSXiaoliang Yang 204023ae3a78SXiaoliang Yang struct felix_stream_gate { 204123ae3a78SXiaoliang Yang u32 index; 204223ae3a78SXiaoliang Yang u8 enable; 204323ae3a78SXiaoliang Yang u8 ipv_valid; 204423ae3a78SXiaoliang Yang u8 init_ipv; 204523ae3a78SXiaoliang Yang u64 basetime; 204623ae3a78SXiaoliang Yang u64 cycletime; 204723ae3a78SXiaoliang Yang u64 cycletime_ext; 204823ae3a78SXiaoliang Yang u32 num_entries; 2049dcad856fSkernel test robot struct action_gate_entry entries[]; 205023ae3a78SXiaoliang Yang }; 205123ae3a78SXiaoliang Yang 205223ae3a78SXiaoliang Yang struct felix_stream_gate_entry { 205323ae3a78SXiaoliang Yang struct list_head list; 205423ae3a78SXiaoliang Yang refcount_t refcount; 205523ae3a78SXiaoliang Yang u32 index; 205623ae3a78SXiaoliang Yang }; 205723ae3a78SXiaoliang Yang 20587d4b564dSXiaoliang Yang static int vsc9959_stream_identify(struct flow_cls_offload *f, 20597d4b564dSXiaoliang Yang struct felix_stream *stream) 20607d4b564dSXiaoliang Yang { 20617d4b564dSXiaoliang Yang struct flow_rule *rule = flow_cls_offload_flow_rule(f); 20627d4b564dSXiaoliang Yang struct flow_dissector *dissector = rule->match.dissector; 20637d4b564dSXiaoliang Yang 20647d4b564dSXiaoliang Yang if (dissector->used_keys & 20657d4b564dSXiaoliang Yang ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) | 20667d4b564dSXiaoliang Yang BIT(FLOW_DISSECTOR_KEY_BASIC) | 20677d4b564dSXiaoliang Yang BIT(FLOW_DISSECTOR_KEY_VLAN) | 20687d4b564dSXiaoliang Yang BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS))) 20697d4b564dSXiaoliang Yang return -EOPNOTSUPP; 20707d4b564dSXiaoliang Yang 20717d4b564dSXiaoliang Yang if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) { 20727d4b564dSXiaoliang Yang struct flow_match_eth_addrs match; 20737d4b564dSXiaoliang Yang 20747d4b564dSXiaoliang Yang flow_rule_match_eth_addrs(rule, &match); 20757d4b564dSXiaoliang Yang ether_addr_copy(stream->dmac, match.key->dst); 20767d4b564dSXiaoliang Yang if (!is_zero_ether_addr(match.mask->src)) 20777d4b564dSXiaoliang Yang return -EOPNOTSUPP; 20787d4b564dSXiaoliang Yang } else { 20797d4b564dSXiaoliang Yang return -EOPNOTSUPP; 20807d4b564dSXiaoliang Yang } 20817d4b564dSXiaoliang Yang 20827d4b564dSXiaoliang Yang if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) { 20837d4b564dSXiaoliang Yang struct flow_match_vlan match; 20847d4b564dSXiaoliang Yang 20857d4b564dSXiaoliang Yang flow_rule_match_vlan(rule, &match); 20867d4b564dSXiaoliang Yang if (match.mask->vlan_priority) 20877d4b564dSXiaoliang Yang stream->prio = match.key->vlan_priority; 20887d4b564dSXiaoliang Yang else 20897d4b564dSXiaoliang Yang stream->prio = -1; 20907d4b564dSXiaoliang Yang 20917d4b564dSXiaoliang Yang if (!match.mask->vlan_id) 20927d4b564dSXiaoliang Yang return -EOPNOTSUPP; 20937d4b564dSXiaoliang Yang stream->vid = match.key->vlan_id; 20947d4b564dSXiaoliang Yang } else { 20957d4b564dSXiaoliang Yang return -EOPNOTSUPP; 20967d4b564dSXiaoliang Yang } 20977d4b564dSXiaoliang Yang 20987d4b564dSXiaoliang Yang stream->id = f->cookie; 20997d4b564dSXiaoliang Yang 21007d4b564dSXiaoliang Yang return 0; 21017d4b564dSXiaoliang Yang } 21027d4b564dSXiaoliang Yang 21037d4b564dSXiaoliang Yang static int vsc9959_mact_stream_set(struct ocelot *ocelot, 21047d4b564dSXiaoliang Yang struct felix_stream *stream, 21057d4b564dSXiaoliang Yang struct netlink_ext_ack *extack) 21067d4b564dSXiaoliang Yang { 21077d4b564dSXiaoliang Yang enum macaccess_entry_type type; 21087d4b564dSXiaoliang Yang int ret, sfid, ssid; 21097d4b564dSXiaoliang Yang u32 vid, dst_idx; 21107d4b564dSXiaoliang Yang u8 mac[ETH_ALEN]; 21117d4b564dSXiaoliang Yang 21127d4b564dSXiaoliang Yang ether_addr_copy(mac, stream->dmac); 21137d4b564dSXiaoliang Yang vid = stream->vid; 21147d4b564dSXiaoliang Yang 21157d4b564dSXiaoliang Yang /* Stream identification desn't support to add a stream with non 21167d4b564dSXiaoliang Yang * existent MAC (The MAC entry has not been learned in MAC table). 21177d4b564dSXiaoliang Yang */ 21187d4b564dSXiaoliang Yang ret = ocelot_mact_lookup(ocelot, &dst_idx, mac, vid, &type); 21197d4b564dSXiaoliang Yang if (ret) { 21207d4b564dSXiaoliang Yang if (extack) 21217d4b564dSXiaoliang Yang NL_SET_ERR_MSG_MOD(extack, "Stream is not learned in MAC table"); 21227d4b564dSXiaoliang Yang return -EOPNOTSUPP; 21237d4b564dSXiaoliang Yang } 21247d4b564dSXiaoliang Yang 21257d4b564dSXiaoliang Yang if ((stream->sfid_valid || stream->ssid_valid) && 21267d4b564dSXiaoliang Yang type == ENTRYTYPE_NORMAL) 21277d4b564dSXiaoliang Yang type = ENTRYTYPE_LOCKED; 21287d4b564dSXiaoliang Yang 21297d4b564dSXiaoliang Yang sfid = stream->sfid_valid ? stream->sfid : -1; 21307d4b564dSXiaoliang Yang ssid = stream->ssid_valid ? stream->ssid : -1; 21317d4b564dSXiaoliang Yang 21327d4b564dSXiaoliang Yang ret = ocelot_mact_learn_streamdata(ocelot, dst_idx, mac, vid, type, 21337d4b564dSXiaoliang Yang sfid, ssid); 21347d4b564dSXiaoliang Yang 21357d4b564dSXiaoliang Yang return ret; 21367d4b564dSXiaoliang Yang } 21377d4b564dSXiaoliang Yang 21387d4b564dSXiaoliang Yang static struct felix_stream * 21397d4b564dSXiaoliang Yang vsc9959_stream_table_lookup(struct list_head *stream_list, 21407d4b564dSXiaoliang Yang struct felix_stream *stream) 21417d4b564dSXiaoliang Yang { 21427d4b564dSXiaoliang Yang struct felix_stream *tmp; 21437d4b564dSXiaoliang Yang 21447d4b564dSXiaoliang Yang list_for_each_entry(tmp, stream_list, list) 21457d4b564dSXiaoliang Yang if (ether_addr_equal(tmp->dmac, stream->dmac) && 21467d4b564dSXiaoliang Yang tmp->vid == stream->vid) 21477d4b564dSXiaoliang Yang return tmp; 21487d4b564dSXiaoliang Yang 21497d4b564dSXiaoliang Yang return NULL; 21507d4b564dSXiaoliang Yang } 21517d4b564dSXiaoliang Yang 21527d4b564dSXiaoliang Yang static int vsc9959_stream_table_add(struct ocelot *ocelot, 21537d4b564dSXiaoliang Yang struct list_head *stream_list, 21547d4b564dSXiaoliang Yang struct felix_stream *stream, 21557d4b564dSXiaoliang Yang struct netlink_ext_ack *extack) 21567d4b564dSXiaoliang Yang { 21577d4b564dSXiaoliang Yang struct felix_stream *stream_entry; 21587d4b564dSXiaoliang Yang int ret; 21597d4b564dSXiaoliang Yang 2160e44aecc7SYihao Han stream_entry = kmemdup(stream, sizeof(*stream_entry), GFP_KERNEL); 21617d4b564dSXiaoliang Yang if (!stream_entry) 21627d4b564dSXiaoliang Yang return -ENOMEM; 21637d4b564dSXiaoliang Yang 2164a7e13edfSXiaoliang Yang if (!stream->dummy) { 21657d4b564dSXiaoliang Yang ret = vsc9959_mact_stream_set(ocelot, stream_entry, extack); 21667d4b564dSXiaoliang Yang if (ret) { 21677d4b564dSXiaoliang Yang kfree(stream_entry); 21687d4b564dSXiaoliang Yang return ret; 21697d4b564dSXiaoliang Yang } 2170a7e13edfSXiaoliang Yang } 21717d4b564dSXiaoliang Yang 21727d4b564dSXiaoliang Yang list_add_tail(&stream_entry->list, stream_list); 21737d4b564dSXiaoliang Yang 21747d4b564dSXiaoliang Yang return 0; 21757d4b564dSXiaoliang Yang } 21767d4b564dSXiaoliang Yang 21777d4b564dSXiaoliang Yang static struct felix_stream * 21787d4b564dSXiaoliang Yang vsc9959_stream_table_get(struct list_head *stream_list, unsigned long id) 21797d4b564dSXiaoliang Yang { 21807d4b564dSXiaoliang Yang struct felix_stream *tmp; 21817d4b564dSXiaoliang Yang 21827d4b564dSXiaoliang Yang list_for_each_entry(tmp, stream_list, list) 21837d4b564dSXiaoliang Yang if (tmp->id == id) 21847d4b564dSXiaoliang Yang return tmp; 21857d4b564dSXiaoliang Yang 21867d4b564dSXiaoliang Yang return NULL; 21877d4b564dSXiaoliang Yang } 21887d4b564dSXiaoliang Yang 21897d4b564dSXiaoliang Yang static void vsc9959_stream_table_del(struct ocelot *ocelot, 21907d4b564dSXiaoliang Yang struct felix_stream *stream) 21917d4b564dSXiaoliang Yang { 2192a7e13edfSXiaoliang Yang if (!stream->dummy) 21937d4b564dSXiaoliang Yang vsc9959_mact_stream_set(ocelot, stream, NULL); 21947d4b564dSXiaoliang Yang 21957d4b564dSXiaoliang Yang list_del(&stream->list); 21967d4b564dSXiaoliang Yang kfree(stream); 21977d4b564dSXiaoliang Yang } 21987d4b564dSXiaoliang Yang 21997d4b564dSXiaoliang Yang static u32 vsc9959_sfi_access_status(struct ocelot *ocelot) 22007d4b564dSXiaoliang Yang { 22017d4b564dSXiaoliang Yang return ocelot_read(ocelot, ANA_TABLES_SFIDACCESS); 22027d4b564dSXiaoliang Yang } 22037d4b564dSXiaoliang Yang 22047d4b564dSXiaoliang Yang static int vsc9959_psfp_sfi_set(struct ocelot *ocelot, 22057d4b564dSXiaoliang Yang struct felix_stream_filter *sfi) 22067d4b564dSXiaoliang Yang { 22077d4b564dSXiaoliang Yang u32 val; 22087d4b564dSXiaoliang Yang 22097d4b564dSXiaoliang Yang if (sfi->index > VSC9959_PSFP_SFID_MAX) 22107d4b564dSXiaoliang Yang return -EINVAL; 22117d4b564dSXiaoliang Yang 22127d4b564dSXiaoliang Yang if (!sfi->enable) { 22137d4b564dSXiaoliang Yang ocelot_write(ocelot, ANA_TABLES_SFIDTIDX_SFID_INDEX(sfi->index), 22147d4b564dSXiaoliang Yang ANA_TABLES_SFIDTIDX); 22157d4b564dSXiaoliang Yang 22167d4b564dSXiaoliang Yang val = ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(SFIDACCESS_CMD_WRITE); 22177d4b564dSXiaoliang Yang ocelot_write(ocelot, val, ANA_TABLES_SFIDACCESS); 22187d4b564dSXiaoliang Yang 22197d4b564dSXiaoliang Yang return readx_poll_timeout(vsc9959_sfi_access_status, ocelot, val, 22207d4b564dSXiaoliang Yang (!ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(val)), 22217d4b564dSXiaoliang Yang 10, 100000); 22227d4b564dSXiaoliang Yang } 22237d4b564dSXiaoliang Yang 22247d4b564dSXiaoliang Yang if (sfi->sgid > VSC9959_PSFP_GATE_ID_MAX || 22257d4b564dSXiaoliang Yang sfi->fmid > VSC9959_PSFP_POLICER_MAX) 22267d4b564dSXiaoliang Yang return -EINVAL; 22277d4b564dSXiaoliang Yang 22287d4b564dSXiaoliang Yang ocelot_write(ocelot, 22297d4b564dSXiaoliang Yang (sfi->sg_valid ? ANA_TABLES_SFIDTIDX_SGID_VALID : 0) | 22307d4b564dSXiaoliang Yang ANA_TABLES_SFIDTIDX_SGID(sfi->sgid) | 22317d4b564dSXiaoliang Yang (sfi->fm_valid ? ANA_TABLES_SFIDTIDX_POL_ENA : 0) | 22327d4b564dSXiaoliang Yang ANA_TABLES_SFIDTIDX_POL_IDX(sfi->fmid) | 22337d4b564dSXiaoliang Yang ANA_TABLES_SFIDTIDX_SFID_INDEX(sfi->index), 22347d4b564dSXiaoliang Yang ANA_TABLES_SFIDTIDX); 22357d4b564dSXiaoliang Yang 22367d4b564dSXiaoliang Yang ocelot_write(ocelot, 22377d4b564dSXiaoliang Yang (sfi->prio_valid ? ANA_TABLES_SFIDACCESS_IGR_PRIO_MATCH_ENA : 0) | 22387d4b564dSXiaoliang Yang ANA_TABLES_SFIDACCESS_IGR_PRIO(sfi->prio) | 22397d4b564dSXiaoliang Yang ANA_TABLES_SFIDACCESS_MAX_SDU_LEN(sfi->maxsdu) | 22407d4b564dSXiaoliang Yang ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(SFIDACCESS_CMD_WRITE), 22417d4b564dSXiaoliang Yang ANA_TABLES_SFIDACCESS); 22427d4b564dSXiaoliang Yang 22437d4b564dSXiaoliang Yang return readx_poll_timeout(vsc9959_sfi_access_status, ocelot, val, 22447d4b564dSXiaoliang Yang (!ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(val)), 22457d4b564dSXiaoliang Yang 10, 100000); 22467d4b564dSXiaoliang Yang } 22477d4b564dSXiaoliang Yang 2248a7e13edfSXiaoliang Yang static int vsc9959_psfp_sfidmask_set(struct ocelot *ocelot, u32 sfid, int ports) 22497d4b564dSXiaoliang Yang { 2250a7e13edfSXiaoliang Yang u32 val; 2251a7e13edfSXiaoliang Yang 2252a7e13edfSXiaoliang Yang ocelot_rmw(ocelot, 2253a7e13edfSXiaoliang Yang ANA_TABLES_SFIDTIDX_SFID_INDEX(sfid), 2254a7e13edfSXiaoliang Yang ANA_TABLES_SFIDTIDX_SFID_INDEX_M, 2255a7e13edfSXiaoliang Yang ANA_TABLES_SFIDTIDX); 2256a7e13edfSXiaoliang Yang 2257a7e13edfSXiaoliang Yang ocelot_write(ocelot, 2258a7e13edfSXiaoliang Yang ANA_TABLES_SFID_MASK_IGR_PORT_MASK(ports) | 2259a7e13edfSXiaoliang Yang ANA_TABLES_SFID_MASK_IGR_SRCPORT_MATCH_ENA, 2260a7e13edfSXiaoliang Yang ANA_TABLES_SFID_MASK); 2261a7e13edfSXiaoliang Yang 2262a7e13edfSXiaoliang Yang ocelot_rmw(ocelot, 2263a7e13edfSXiaoliang Yang ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(SFIDACCESS_CMD_WRITE), 2264a7e13edfSXiaoliang Yang ANA_TABLES_SFIDACCESS_SFID_TBL_CMD_M, 2265a7e13edfSXiaoliang Yang ANA_TABLES_SFIDACCESS); 2266a7e13edfSXiaoliang Yang 2267a7e13edfSXiaoliang Yang return readx_poll_timeout(vsc9959_sfi_access_status, ocelot, val, 2268a7e13edfSXiaoliang Yang (!ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(val)), 2269a7e13edfSXiaoliang Yang 10, 100000); 2270a7e13edfSXiaoliang Yang } 2271a7e13edfSXiaoliang Yang 2272a7e13edfSXiaoliang Yang static int vsc9959_psfp_sfi_list_add(struct ocelot *ocelot, 2273a7e13edfSXiaoliang Yang struct felix_stream_filter *sfi, 2274a7e13edfSXiaoliang Yang struct list_head *pos) 2275a7e13edfSXiaoliang Yang { 2276a7e13edfSXiaoliang Yang struct felix_stream_filter *sfi_entry; 22777d4b564dSXiaoliang Yang int ret; 22787d4b564dSXiaoliang Yang 2279e44aecc7SYihao Han sfi_entry = kmemdup(sfi, sizeof(*sfi_entry), GFP_KERNEL); 22807d4b564dSXiaoliang Yang if (!sfi_entry) 22817d4b564dSXiaoliang Yang return -ENOMEM; 22827d4b564dSXiaoliang Yang 22837d4b564dSXiaoliang Yang refcount_set(&sfi_entry->refcount, 1); 22847d4b564dSXiaoliang Yang 22857d4b564dSXiaoliang Yang ret = vsc9959_psfp_sfi_set(ocelot, sfi_entry); 22867d4b564dSXiaoliang Yang if (ret) { 22877d4b564dSXiaoliang Yang kfree(sfi_entry); 22887d4b564dSXiaoliang Yang return ret; 22897d4b564dSXiaoliang Yang } 22907d4b564dSXiaoliang Yang 2291a7e13edfSXiaoliang Yang vsc9959_psfp_sfidmask_set(ocelot, sfi->index, sfi->portmask); 2292a7e13edfSXiaoliang Yang 2293a7e13edfSXiaoliang Yang list_add(&sfi_entry->list, pos); 22947d4b564dSXiaoliang Yang 22957d4b564dSXiaoliang Yang return 0; 22967d4b564dSXiaoliang Yang } 22977d4b564dSXiaoliang Yang 2298a7e13edfSXiaoliang Yang static int vsc9959_psfp_sfi_table_add(struct ocelot *ocelot, 2299a7e13edfSXiaoliang Yang struct felix_stream_filter *sfi) 2300a7e13edfSXiaoliang Yang { 2301a7e13edfSXiaoliang Yang struct list_head *pos, *q, *last; 2302a7e13edfSXiaoliang Yang struct felix_stream_filter *tmp; 2303a7e13edfSXiaoliang Yang struct ocelot_psfp_list *psfp; 2304a7e13edfSXiaoliang Yang u32 insert = 0; 2305a7e13edfSXiaoliang Yang 2306a7e13edfSXiaoliang Yang psfp = &ocelot->psfp; 2307a7e13edfSXiaoliang Yang last = &psfp->sfi_list; 2308a7e13edfSXiaoliang Yang 2309a7e13edfSXiaoliang Yang list_for_each_safe(pos, q, &psfp->sfi_list) { 2310a7e13edfSXiaoliang Yang tmp = list_entry(pos, struct felix_stream_filter, list); 2311a7e13edfSXiaoliang Yang if (sfi->sg_valid == tmp->sg_valid && 2312a7e13edfSXiaoliang Yang sfi->fm_valid == tmp->fm_valid && 2313a7e13edfSXiaoliang Yang sfi->portmask == tmp->portmask && 2314a7e13edfSXiaoliang Yang tmp->sgid == sfi->sgid && 2315a7e13edfSXiaoliang Yang tmp->fmid == sfi->fmid) { 2316a7e13edfSXiaoliang Yang sfi->index = tmp->index; 2317a7e13edfSXiaoliang Yang refcount_inc(&tmp->refcount); 2318a7e13edfSXiaoliang Yang return 0; 2319a7e13edfSXiaoliang Yang } 2320a7e13edfSXiaoliang Yang /* Make sure that the index is increasing in order. */ 2321a7e13edfSXiaoliang Yang if (tmp->index == insert) { 2322a7e13edfSXiaoliang Yang last = pos; 2323a7e13edfSXiaoliang Yang insert++; 2324a7e13edfSXiaoliang Yang } 2325a7e13edfSXiaoliang Yang } 2326a7e13edfSXiaoliang Yang sfi->index = insert; 2327a7e13edfSXiaoliang Yang 2328a7e13edfSXiaoliang Yang return vsc9959_psfp_sfi_list_add(ocelot, sfi, last); 2329a7e13edfSXiaoliang Yang } 2330a7e13edfSXiaoliang Yang 2331a7e13edfSXiaoliang Yang static int vsc9959_psfp_sfi_table_add2(struct ocelot *ocelot, 2332a7e13edfSXiaoliang Yang struct felix_stream_filter *sfi, 2333a7e13edfSXiaoliang Yang struct felix_stream_filter *sfi2) 2334a7e13edfSXiaoliang Yang { 2335a7e13edfSXiaoliang Yang struct felix_stream_filter *tmp; 2336a7e13edfSXiaoliang Yang struct list_head *pos, *q, *last; 2337a7e13edfSXiaoliang Yang struct ocelot_psfp_list *psfp; 2338a7e13edfSXiaoliang Yang u32 insert = 0; 2339a7e13edfSXiaoliang Yang int ret; 2340a7e13edfSXiaoliang Yang 2341a7e13edfSXiaoliang Yang psfp = &ocelot->psfp; 2342a7e13edfSXiaoliang Yang last = &psfp->sfi_list; 2343a7e13edfSXiaoliang Yang 2344a7e13edfSXiaoliang Yang list_for_each_safe(pos, q, &psfp->sfi_list) { 2345a7e13edfSXiaoliang Yang tmp = list_entry(pos, struct felix_stream_filter, list); 2346a7e13edfSXiaoliang Yang /* Make sure that the index is increasing in order. */ 2347a7e13edfSXiaoliang Yang if (tmp->index >= insert + 2) 2348a7e13edfSXiaoliang Yang break; 2349a7e13edfSXiaoliang Yang 2350a7e13edfSXiaoliang Yang insert = tmp->index + 1; 2351a7e13edfSXiaoliang Yang last = pos; 2352a7e13edfSXiaoliang Yang } 2353a7e13edfSXiaoliang Yang sfi->index = insert; 2354a7e13edfSXiaoliang Yang 2355a7e13edfSXiaoliang Yang ret = vsc9959_psfp_sfi_list_add(ocelot, sfi, last); 2356a7e13edfSXiaoliang Yang if (ret) 2357a7e13edfSXiaoliang Yang return ret; 2358a7e13edfSXiaoliang Yang 2359a7e13edfSXiaoliang Yang sfi2->index = insert + 1; 2360a7e13edfSXiaoliang Yang 2361a7e13edfSXiaoliang Yang return vsc9959_psfp_sfi_list_add(ocelot, sfi2, last->next); 2362a7e13edfSXiaoliang Yang } 2363a7e13edfSXiaoliang Yang 236423ae3a78SXiaoliang Yang static struct felix_stream_filter * 236523ae3a78SXiaoliang Yang vsc9959_psfp_sfi_table_get(struct list_head *sfi_list, u32 index) 236623ae3a78SXiaoliang Yang { 236723ae3a78SXiaoliang Yang struct felix_stream_filter *tmp; 236823ae3a78SXiaoliang Yang 236923ae3a78SXiaoliang Yang list_for_each_entry(tmp, sfi_list, list) 237023ae3a78SXiaoliang Yang if (tmp->index == index) 237123ae3a78SXiaoliang Yang return tmp; 237223ae3a78SXiaoliang Yang 237323ae3a78SXiaoliang Yang return NULL; 237423ae3a78SXiaoliang Yang } 237523ae3a78SXiaoliang Yang 23767d4b564dSXiaoliang Yang static void vsc9959_psfp_sfi_table_del(struct ocelot *ocelot, u32 index) 23777d4b564dSXiaoliang Yang { 23787d4b564dSXiaoliang Yang struct felix_stream_filter *tmp, *n; 23797d4b564dSXiaoliang Yang struct ocelot_psfp_list *psfp; 23807d4b564dSXiaoliang Yang u8 z; 23817d4b564dSXiaoliang Yang 23827d4b564dSXiaoliang Yang psfp = &ocelot->psfp; 23837d4b564dSXiaoliang Yang 23847d4b564dSXiaoliang Yang list_for_each_entry_safe(tmp, n, &psfp->sfi_list, list) 23857d4b564dSXiaoliang Yang if (tmp->index == index) { 23867d4b564dSXiaoliang Yang z = refcount_dec_and_test(&tmp->refcount); 23877d4b564dSXiaoliang Yang if (z) { 23887d4b564dSXiaoliang Yang tmp->enable = 0; 23897d4b564dSXiaoliang Yang vsc9959_psfp_sfi_set(ocelot, tmp); 23907d4b564dSXiaoliang Yang list_del(&tmp->list); 23917d4b564dSXiaoliang Yang kfree(tmp); 23927d4b564dSXiaoliang Yang } 23937d4b564dSXiaoliang Yang break; 23947d4b564dSXiaoliang Yang } 23957d4b564dSXiaoliang Yang } 23967d4b564dSXiaoliang Yang 239723ae3a78SXiaoliang Yang static void vsc9959_psfp_parse_gate(const struct flow_action_entry *entry, 239823ae3a78SXiaoliang Yang struct felix_stream_gate *sgi) 239923ae3a78SXiaoliang Yang { 24005a995900SBaowen Zheng sgi->index = entry->hw_index; 240123ae3a78SXiaoliang Yang sgi->ipv_valid = (entry->gate.prio < 0) ? 0 : 1; 240223ae3a78SXiaoliang Yang sgi->init_ipv = (sgi->ipv_valid) ? entry->gate.prio : 0; 240323ae3a78SXiaoliang Yang sgi->basetime = entry->gate.basetime; 240423ae3a78SXiaoliang Yang sgi->cycletime = entry->gate.cycletime; 240523ae3a78SXiaoliang Yang sgi->num_entries = entry->gate.num_entries; 240623ae3a78SXiaoliang Yang sgi->enable = 1; 240723ae3a78SXiaoliang Yang 240823ae3a78SXiaoliang Yang memcpy(sgi->entries, entry->gate.entries, 240923ae3a78SXiaoliang Yang entry->gate.num_entries * sizeof(struct action_gate_entry)); 241023ae3a78SXiaoliang Yang } 241123ae3a78SXiaoliang Yang 241223ae3a78SXiaoliang Yang static u32 vsc9959_sgi_cfg_status(struct ocelot *ocelot) 241323ae3a78SXiaoliang Yang { 241423ae3a78SXiaoliang Yang return ocelot_read(ocelot, ANA_SG_ACCESS_CTRL); 241523ae3a78SXiaoliang Yang } 241623ae3a78SXiaoliang Yang 241723ae3a78SXiaoliang Yang static int vsc9959_psfp_sgi_set(struct ocelot *ocelot, 241823ae3a78SXiaoliang Yang struct felix_stream_gate *sgi) 241923ae3a78SXiaoliang Yang { 242023ae3a78SXiaoliang Yang struct action_gate_entry *e; 242123ae3a78SXiaoliang Yang struct timespec64 base_ts; 242223ae3a78SXiaoliang Yang u32 interval_sum = 0; 242323ae3a78SXiaoliang Yang u32 val; 242423ae3a78SXiaoliang Yang int i; 242523ae3a78SXiaoliang Yang 242623ae3a78SXiaoliang Yang if (sgi->index > VSC9959_PSFP_GATE_ID_MAX) 242723ae3a78SXiaoliang Yang return -EINVAL; 242823ae3a78SXiaoliang Yang 242923ae3a78SXiaoliang Yang ocelot_write(ocelot, ANA_SG_ACCESS_CTRL_SGID(sgi->index), 243023ae3a78SXiaoliang Yang ANA_SG_ACCESS_CTRL); 243123ae3a78SXiaoliang Yang 243223ae3a78SXiaoliang Yang if (!sgi->enable) { 243323ae3a78SXiaoliang Yang ocelot_rmw(ocelot, ANA_SG_CONFIG_REG_3_INIT_GATE_STATE, 243423ae3a78SXiaoliang Yang ANA_SG_CONFIG_REG_3_INIT_GATE_STATE | 243523ae3a78SXiaoliang Yang ANA_SG_CONFIG_REG_3_GATE_ENABLE, 243623ae3a78SXiaoliang Yang ANA_SG_CONFIG_REG_3); 243723ae3a78SXiaoliang Yang 243823ae3a78SXiaoliang Yang return 0; 243923ae3a78SXiaoliang Yang } 244023ae3a78SXiaoliang Yang 244123ae3a78SXiaoliang Yang if (sgi->cycletime < VSC9959_PSFP_GATE_CYCLETIME_MIN || 244223ae3a78SXiaoliang Yang sgi->cycletime > NSEC_PER_SEC) 244323ae3a78SXiaoliang Yang return -EINVAL; 244423ae3a78SXiaoliang Yang 244523ae3a78SXiaoliang Yang if (sgi->num_entries > VSC9959_PSFP_GATE_LIST_NUM) 244623ae3a78SXiaoliang Yang return -EINVAL; 244723ae3a78SXiaoliang Yang 244823ae3a78SXiaoliang Yang vsc9959_new_base_time(ocelot, sgi->basetime, sgi->cycletime, &base_ts); 244923ae3a78SXiaoliang Yang ocelot_write(ocelot, base_ts.tv_nsec, ANA_SG_CONFIG_REG_1); 245023ae3a78SXiaoliang Yang val = lower_32_bits(base_ts.tv_sec); 245123ae3a78SXiaoliang Yang ocelot_write(ocelot, val, ANA_SG_CONFIG_REG_2); 245223ae3a78SXiaoliang Yang 245323ae3a78SXiaoliang Yang val = upper_32_bits(base_ts.tv_sec); 245423ae3a78SXiaoliang Yang ocelot_write(ocelot, 245523ae3a78SXiaoliang Yang (sgi->ipv_valid ? ANA_SG_CONFIG_REG_3_IPV_VALID : 0) | 245623ae3a78SXiaoliang Yang ANA_SG_CONFIG_REG_3_INIT_IPV(sgi->init_ipv) | 245723ae3a78SXiaoliang Yang ANA_SG_CONFIG_REG_3_GATE_ENABLE | 245823ae3a78SXiaoliang Yang ANA_SG_CONFIG_REG_3_LIST_LENGTH(sgi->num_entries) | 245923ae3a78SXiaoliang Yang ANA_SG_CONFIG_REG_3_INIT_GATE_STATE | 246023ae3a78SXiaoliang Yang ANA_SG_CONFIG_REG_3_BASE_TIME_SEC_MSB(val), 246123ae3a78SXiaoliang Yang ANA_SG_CONFIG_REG_3); 246223ae3a78SXiaoliang Yang 246323ae3a78SXiaoliang Yang ocelot_write(ocelot, sgi->cycletime, ANA_SG_CONFIG_REG_4); 246423ae3a78SXiaoliang Yang 246523ae3a78SXiaoliang Yang e = sgi->entries; 246623ae3a78SXiaoliang Yang for (i = 0; i < sgi->num_entries; i++) { 246723ae3a78SXiaoliang Yang u32 ips = (e[i].ipv < 0) ? 0 : (e[i].ipv + 8); 246823ae3a78SXiaoliang Yang 246923ae3a78SXiaoliang Yang ocelot_write_rix(ocelot, ANA_SG_GCL_GS_CONFIG_IPS(ips) | 247023ae3a78SXiaoliang Yang (e[i].gate_state ? 247123ae3a78SXiaoliang Yang ANA_SG_GCL_GS_CONFIG_GATE_STATE : 0), 247223ae3a78SXiaoliang Yang ANA_SG_GCL_GS_CONFIG, i); 247323ae3a78SXiaoliang Yang 247423ae3a78SXiaoliang Yang interval_sum += e[i].interval; 247523ae3a78SXiaoliang Yang ocelot_write_rix(ocelot, interval_sum, ANA_SG_GCL_TI_CONFIG, i); 247623ae3a78SXiaoliang Yang } 247723ae3a78SXiaoliang Yang 247823ae3a78SXiaoliang Yang ocelot_rmw(ocelot, ANA_SG_ACCESS_CTRL_CONFIG_CHANGE, 247923ae3a78SXiaoliang Yang ANA_SG_ACCESS_CTRL_CONFIG_CHANGE, 248023ae3a78SXiaoliang Yang ANA_SG_ACCESS_CTRL); 248123ae3a78SXiaoliang Yang 248223ae3a78SXiaoliang Yang return readx_poll_timeout(vsc9959_sgi_cfg_status, ocelot, val, 248323ae3a78SXiaoliang Yang (!(ANA_SG_ACCESS_CTRL_CONFIG_CHANGE & val)), 248423ae3a78SXiaoliang Yang 10, 100000); 248523ae3a78SXiaoliang Yang } 248623ae3a78SXiaoliang Yang 248723ae3a78SXiaoliang Yang static int vsc9959_psfp_sgi_table_add(struct ocelot *ocelot, 248823ae3a78SXiaoliang Yang struct felix_stream_gate *sgi) 248923ae3a78SXiaoliang Yang { 249023ae3a78SXiaoliang Yang struct felix_stream_gate_entry *tmp; 249123ae3a78SXiaoliang Yang struct ocelot_psfp_list *psfp; 249223ae3a78SXiaoliang Yang int ret; 249323ae3a78SXiaoliang Yang 249423ae3a78SXiaoliang Yang psfp = &ocelot->psfp; 249523ae3a78SXiaoliang Yang 249623ae3a78SXiaoliang Yang list_for_each_entry(tmp, &psfp->sgi_list, list) 249723ae3a78SXiaoliang Yang if (tmp->index == sgi->index) { 249823ae3a78SXiaoliang Yang refcount_inc(&tmp->refcount); 249923ae3a78SXiaoliang Yang return 0; 250023ae3a78SXiaoliang Yang } 250123ae3a78SXiaoliang Yang 250223ae3a78SXiaoliang Yang tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); 250323ae3a78SXiaoliang Yang if (!tmp) 250423ae3a78SXiaoliang Yang return -ENOMEM; 250523ae3a78SXiaoliang Yang 250623ae3a78SXiaoliang Yang ret = vsc9959_psfp_sgi_set(ocelot, sgi); 250723ae3a78SXiaoliang Yang if (ret) { 250823ae3a78SXiaoliang Yang kfree(tmp); 250923ae3a78SXiaoliang Yang return ret; 251023ae3a78SXiaoliang Yang } 251123ae3a78SXiaoliang Yang 251223ae3a78SXiaoliang Yang tmp->index = sgi->index; 251323ae3a78SXiaoliang Yang refcount_set(&tmp->refcount, 1); 251423ae3a78SXiaoliang Yang list_add_tail(&tmp->list, &psfp->sgi_list); 251523ae3a78SXiaoliang Yang 251623ae3a78SXiaoliang Yang return 0; 251723ae3a78SXiaoliang Yang } 251823ae3a78SXiaoliang Yang 251923ae3a78SXiaoliang Yang static void vsc9959_psfp_sgi_table_del(struct ocelot *ocelot, 252023ae3a78SXiaoliang Yang u32 index) 252123ae3a78SXiaoliang Yang { 252223ae3a78SXiaoliang Yang struct felix_stream_gate_entry *tmp, *n; 252323ae3a78SXiaoliang Yang struct felix_stream_gate sgi = {0}; 252423ae3a78SXiaoliang Yang struct ocelot_psfp_list *psfp; 252523ae3a78SXiaoliang Yang u8 z; 252623ae3a78SXiaoliang Yang 252723ae3a78SXiaoliang Yang psfp = &ocelot->psfp; 252823ae3a78SXiaoliang Yang 252923ae3a78SXiaoliang Yang list_for_each_entry_safe(tmp, n, &psfp->sgi_list, list) 253023ae3a78SXiaoliang Yang if (tmp->index == index) { 253123ae3a78SXiaoliang Yang z = refcount_dec_and_test(&tmp->refcount); 253223ae3a78SXiaoliang Yang if (z) { 253323ae3a78SXiaoliang Yang sgi.index = index; 253423ae3a78SXiaoliang Yang sgi.enable = 0; 253523ae3a78SXiaoliang Yang vsc9959_psfp_sgi_set(ocelot, &sgi); 253623ae3a78SXiaoliang Yang list_del(&tmp->list); 253723ae3a78SXiaoliang Yang kfree(tmp); 253823ae3a78SXiaoliang Yang } 253923ae3a78SXiaoliang Yang break; 254023ae3a78SXiaoliang Yang } 254123ae3a78SXiaoliang Yang } 254223ae3a78SXiaoliang Yang 25437d4b564dSXiaoliang Yang static void vsc9959_psfp_counters_get(struct ocelot *ocelot, u32 index, 25447d4b564dSXiaoliang Yang struct felix_stream_filter_counters *counters) 25457d4b564dSXiaoliang Yang { 254622d842e3SVladimir Oltean spin_lock(&ocelot->stats_lock); 254758bf4db6SVladimir Oltean 25487d4b564dSXiaoliang Yang ocelot_rmw(ocelot, SYS_STAT_CFG_STAT_VIEW(index), 25497d4b564dSXiaoliang Yang SYS_STAT_CFG_STAT_VIEW_M, 25507d4b564dSXiaoliang Yang SYS_STAT_CFG); 25517d4b564dSXiaoliang Yang 25527d4b564dSXiaoliang Yang counters->match = ocelot_read_gix(ocelot, SYS_CNT, 0x200); 25537d4b564dSXiaoliang Yang counters->not_pass_gate = ocelot_read_gix(ocelot, SYS_CNT, 0x201); 25547d4b564dSXiaoliang Yang counters->not_pass_sdu = ocelot_read_gix(ocelot, SYS_CNT, 0x202); 25557d4b564dSXiaoliang Yang counters->red = ocelot_read_gix(ocelot, SYS_CNT, 0x203); 25567d4b564dSXiaoliang Yang 25577d4b564dSXiaoliang Yang /* Clear the PSFP counter. */ 25587d4b564dSXiaoliang Yang ocelot_write(ocelot, 25597d4b564dSXiaoliang Yang SYS_STAT_CFG_STAT_VIEW(index) | 25607d4b564dSXiaoliang Yang SYS_STAT_CFG_STAT_CLEAR_SHOT(0x10), 25617d4b564dSXiaoliang Yang SYS_STAT_CFG); 256258bf4db6SVladimir Oltean 256322d842e3SVladimir Oltean spin_unlock(&ocelot->stats_lock); 25647d4b564dSXiaoliang Yang } 25657d4b564dSXiaoliang Yang 2566a7e13edfSXiaoliang Yang static int vsc9959_psfp_filter_add(struct ocelot *ocelot, int port, 25677d4b564dSXiaoliang Yang struct flow_cls_offload *f) 25687d4b564dSXiaoliang Yang { 25697d4b564dSXiaoliang Yang struct netlink_ext_ack *extack = f->common.extack; 2570a7e13edfSXiaoliang Yang struct felix_stream_filter old_sfi, *sfi_entry; 25717d4b564dSXiaoliang Yang struct felix_stream_filter sfi = {0}; 25727d4b564dSXiaoliang Yang const struct flow_action_entry *a; 25737d4b564dSXiaoliang Yang struct felix_stream *stream_entry; 25747d4b564dSXiaoliang Yang struct felix_stream stream = {0}; 257523ae3a78SXiaoliang Yang struct felix_stream_gate *sgi; 25767d4b564dSXiaoliang Yang struct ocelot_psfp_list *psfp; 257776c13edeSXiaoliang Yang struct ocelot_policer pol; 257823ae3a78SXiaoliang Yang int ret, i, size; 257976c13edeSXiaoliang Yang u64 rate, burst; 258076c13edeSXiaoliang Yang u32 index; 25817d4b564dSXiaoliang Yang 25827d4b564dSXiaoliang Yang psfp = &ocelot->psfp; 25837d4b564dSXiaoliang Yang 25847d4b564dSXiaoliang Yang ret = vsc9959_stream_identify(f, &stream); 25857d4b564dSXiaoliang Yang if (ret) { 25867d4b564dSXiaoliang Yang NL_SET_ERR_MSG_MOD(extack, "Only can match on VID, PCP, and dest MAC"); 25877d4b564dSXiaoliang Yang return ret; 25887d4b564dSXiaoliang Yang } 25897d4b564dSXiaoliang Yang 25907d4b564dSXiaoliang Yang flow_action_for_each(i, a, &f->rule->action) { 25917d4b564dSXiaoliang Yang switch (a->id) { 25927d4b564dSXiaoliang Yang case FLOW_ACTION_GATE: 259323ae3a78SXiaoliang Yang size = struct_size(sgi, entries, a->gate.num_entries); 259423ae3a78SXiaoliang Yang sgi = kzalloc(size, GFP_KERNEL); 2595866b7a27SZheng Yongjun if (!sgi) { 2596866b7a27SZheng Yongjun ret = -ENOMEM; 2597866b7a27SZheng Yongjun goto err; 2598866b7a27SZheng Yongjun } 259923ae3a78SXiaoliang Yang vsc9959_psfp_parse_gate(a, sgi); 260023ae3a78SXiaoliang Yang ret = vsc9959_psfp_sgi_table_add(ocelot, sgi); 260123ae3a78SXiaoliang Yang if (ret) { 260223ae3a78SXiaoliang Yang kfree(sgi); 260376c13edeSXiaoliang Yang goto err; 260423ae3a78SXiaoliang Yang } 260523ae3a78SXiaoliang Yang sfi.sg_valid = 1; 260623ae3a78SXiaoliang Yang sfi.sgid = sgi->index; 260723ae3a78SXiaoliang Yang kfree(sgi); 260823ae3a78SXiaoliang Yang break; 26097d4b564dSXiaoliang Yang case FLOW_ACTION_POLICE: 26105a995900SBaowen Zheng index = a->hw_index + VSC9959_PSFP_POLICER_BASE; 261176c13edeSXiaoliang Yang if (index > VSC9959_PSFP_POLICER_MAX) { 261276c13edeSXiaoliang Yang ret = -EINVAL; 261376c13edeSXiaoliang Yang goto err; 261476c13edeSXiaoliang Yang } 261576c13edeSXiaoliang Yang 261676c13edeSXiaoliang Yang rate = a->police.rate_bytes_ps; 261776c13edeSXiaoliang Yang burst = rate * PSCHED_NS2TICKS(a->police.burst); 261876c13edeSXiaoliang Yang pol = (struct ocelot_policer) { 261976c13edeSXiaoliang Yang .burst = div_u64(burst, PSCHED_TICKS_PER_SEC), 262076c13edeSXiaoliang Yang .rate = div_u64(rate, 1000) * 8, 262176c13edeSXiaoliang Yang }; 262276c13edeSXiaoliang Yang ret = ocelot_vcap_policer_add(ocelot, index, &pol); 262376c13edeSXiaoliang Yang if (ret) 262476c13edeSXiaoliang Yang goto err; 262576c13edeSXiaoliang Yang 262676c13edeSXiaoliang Yang sfi.fm_valid = 1; 262776c13edeSXiaoliang Yang sfi.fmid = index; 262876c13edeSXiaoliang Yang sfi.maxsdu = a->police.mtu; 262976c13edeSXiaoliang Yang break; 26307d4b564dSXiaoliang Yang default: 26317d4b564dSXiaoliang Yang return -EOPNOTSUPP; 26327d4b564dSXiaoliang Yang } 26337d4b564dSXiaoliang Yang } 26347d4b564dSXiaoliang Yang 2635a7e13edfSXiaoliang Yang stream.ports = BIT(port); 2636a7e13edfSXiaoliang Yang stream.port = port; 26377d4b564dSXiaoliang Yang 2638a7e13edfSXiaoliang Yang sfi.portmask = stream.ports; 26397d4b564dSXiaoliang Yang sfi.prio_valid = (stream.prio < 0 ? 0 : 1); 26407d4b564dSXiaoliang Yang sfi.prio = (sfi.prio_valid ? stream.prio : 0); 26417d4b564dSXiaoliang Yang sfi.enable = 1; 26427d4b564dSXiaoliang Yang 2643a7e13edfSXiaoliang Yang /* Check if stream is set. */ 2644a7e13edfSXiaoliang Yang stream_entry = vsc9959_stream_table_lookup(&psfp->stream_list, &stream); 2645a7e13edfSXiaoliang Yang if (stream_entry) { 2646a7e13edfSXiaoliang Yang if (stream_entry->ports & BIT(port)) { 2647a7e13edfSXiaoliang Yang NL_SET_ERR_MSG_MOD(extack, 2648a7e13edfSXiaoliang Yang "The stream is added on this port"); 2649a7e13edfSXiaoliang Yang ret = -EEXIST; 2650a7e13edfSXiaoliang Yang goto err; 2651a7e13edfSXiaoliang Yang } 2652a7e13edfSXiaoliang Yang 2653a7e13edfSXiaoliang Yang if (stream_entry->ports != BIT(stream_entry->port)) { 2654a7e13edfSXiaoliang Yang NL_SET_ERR_MSG_MOD(extack, 2655a7e13edfSXiaoliang Yang "The stream is added on two ports"); 2656a7e13edfSXiaoliang Yang ret = -EEXIST; 2657a7e13edfSXiaoliang Yang goto err; 2658a7e13edfSXiaoliang Yang } 2659a7e13edfSXiaoliang Yang 2660a7e13edfSXiaoliang Yang stream_entry->ports |= BIT(port); 2661a7e13edfSXiaoliang Yang stream.ports = stream_entry->ports; 2662a7e13edfSXiaoliang Yang 2663a7e13edfSXiaoliang Yang sfi_entry = vsc9959_psfp_sfi_table_get(&psfp->sfi_list, 2664a7e13edfSXiaoliang Yang stream_entry->sfid); 2665a7e13edfSXiaoliang Yang memcpy(&old_sfi, sfi_entry, sizeof(old_sfi)); 2666a7e13edfSXiaoliang Yang 2667a7e13edfSXiaoliang Yang vsc9959_psfp_sfi_table_del(ocelot, stream_entry->sfid); 2668a7e13edfSXiaoliang Yang 2669a7e13edfSXiaoliang Yang old_sfi.portmask = stream_entry->ports; 2670a7e13edfSXiaoliang Yang sfi.portmask = stream.ports; 2671a7e13edfSXiaoliang Yang 2672a7e13edfSXiaoliang Yang if (stream_entry->port > port) { 2673a7e13edfSXiaoliang Yang ret = vsc9959_psfp_sfi_table_add2(ocelot, &sfi, 2674a7e13edfSXiaoliang Yang &old_sfi); 2675a7e13edfSXiaoliang Yang stream_entry->dummy = true; 2676a7e13edfSXiaoliang Yang } else { 2677a7e13edfSXiaoliang Yang ret = vsc9959_psfp_sfi_table_add2(ocelot, &old_sfi, 2678a7e13edfSXiaoliang Yang &sfi); 2679a7e13edfSXiaoliang Yang stream.dummy = true; 2680a7e13edfSXiaoliang Yang } 2681a7e13edfSXiaoliang Yang if (ret) 2682a7e13edfSXiaoliang Yang goto err; 2683a7e13edfSXiaoliang Yang 2684a7e13edfSXiaoliang Yang stream_entry->sfid = old_sfi.index; 2685a7e13edfSXiaoliang Yang } else { 26867d4b564dSXiaoliang Yang ret = vsc9959_psfp_sfi_table_add(ocelot, &sfi); 26877d4b564dSXiaoliang Yang if (ret) 268823ae3a78SXiaoliang Yang goto err; 2689a7e13edfSXiaoliang Yang } 26907d4b564dSXiaoliang Yang 26917d4b564dSXiaoliang Yang stream.sfid = sfi.index; 26927d4b564dSXiaoliang Yang stream.sfid_valid = 1; 26937d4b564dSXiaoliang Yang ret = vsc9959_stream_table_add(ocelot, &psfp->stream_list, 26947d4b564dSXiaoliang Yang &stream, extack); 269523ae3a78SXiaoliang Yang if (ret) { 26967d4b564dSXiaoliang Yang vsc9959_psfp_sfi_table_del(ocelot, stream.sfid); 269723ae3a78SXiaoliang Yang goto err; 269823ae3a78SXiaoliang Yang } 269923ae3a78SXiaoliang Yang 270023ae3a78SXiaoliang Yang return 0; 270123ae3a78SXiaoliang Yang 270223ae3a78SXiaoliang Yang err: 270323ae3a78SXiaoliang Yang if (sfi.sg_valid) 270423ae3a78SXiaoliang Yang vsc9959_psfp_sgi_table_del(ocelot, sfi.sgid); 27057d4b564dSXiaoliang Yang 270676c13edeSXiaoliang Yang if (sfi.fm_valid) 270776c13edeSXiaoliang Yang ocelot_vcap_policer_del(ocelot, sfi.fmid); 270876c13edeSXiaoliang Yang 27097d4b564dSXiaoliang Yang return ret; 27107d4b564dSXiaoliang Yang } 27117d4b564dSXiaoliang Yang 27127d4b564dSXiaoliang Yang static int vsc9959_psfp_filter_del(struct ocelot *ocelot, 27137d4b564dSXiaoliang Yang struct flow_cls_offload *f) 27147d4b564dSXiaoliang Yang { 2715a7e13edfSXiaoliang Yang struct felix_stream *stream, tmp, *stream_entry; 271623ae3a78SXiaoliang Yang static struct felix_stream_filter *sfi; 27177d4b564dSXiaoliang Yang struct ocelot_psfp_list *psfp; 27187d4b564dSXiaoliang Yang 27197d4b564dSXiaoliang Yang psfp = &ocelot->psfp; 27207d4b564dSXiaoliang Yang 27217d4b564dSXiaoliang Yang stream = vsc9959_stream_table_get(&psfp->stream_list, f->cookie); 27227d4b564dSXiaoliang Yang if (!stream) 27237d4b564dSXiaoliang Yang return -ENOMEM; 27247d4b564dSXiaoliang Yang 272523ae3a78SXiaoliang Yang sfi = vsc9959_psfp_sfi_table_get(&psfp->sfi_list, stream->sfid); 272623ae3a78SXiaoliang Yang if (!sfi) 272723ae3a78SXiaoliang Yang return -ENOMEM; 272823ae3a78SXiaoliang Yang 272923ae3a78SXiaoliang Yang if (sfi->sg_valid) 273023ae3a78SXiaoliang Yang vsc9959_psfp_sgi_table_del(ocelot, sfi->sgid); 273123ae3a78SXiaoliang Yang 273276c13edeSXiaoliang Yang if (sfi->fm_valid) 273376c13edeSXiaoliang Yang ocelot_vcap_policer_del(ocelot, sfi->fmid); 273476c13edeSXiaoliang Yang 27357d4b564dSXiaoliang Yang vsc9959_psfp_sfi_table_del(ocelot, stream->sfid); 27367d4b564dSXiaoliang Yang 2737a7e13edfSXiaoliang Yang memcpy(&tmp, stream, sizeof(tmp)); 2738a7e13edfSXiaoliang Yang 27397d4b564dSXiaoliang Yang stream->sfid_valid = 0; 27407d4b564dSXiaoliang Yang vsc9959_stream_table_del(ocelot, stream); 27417d4b564dSXiaoliang Yang 2742a7e13edfSXiaoliang Yang stream_entry = vsc9959_stream_table_lookup(&psfp->stream_list, &tmp); 2743a7e13edfSXiaoliang Yang if (stream_entry) { 2744a7e13edfSXiaoliang Yang stream_entry->ports = BIT(stream_entry->port); 2745a7e13edfSXiaoliang Yang if (stream_entry->dummy) { 2746a7e13edfSXiaoliang Yang stream_entry->dummy = false; 2747a7e13edfSXiaoliang Yang vsc9959_mact_stream_set(ocelot, stream_entry, NULL); 2748a7e13edfSXiaoliang Yang } 2749a7e13edfSXiaoliang Yang vsc9959_psfp_sfidmask_set(ocelot, stream_entry->sfid, 2750a7e13edfSXiaoliang Yang stream_entry->ports); 2751a7e13edfSXiaoliang Yang } 2752a7e13edfSXiaoliang Yang 27537d4b564dSXiaoliang Yang return 0; 27547d4b564dSXiaoliang Yang } 27557d4b564dSXiaoliang Yang 27567d4b564dSXiaoliang Yang static int vsc9959_psfp_stats_get(struct ocelot *ocelot, 27577d4b564dSXiaoliang Yang struct flow_cls_offload *f, 27587d4b564dSXiaoliang Yang struct flow_stats *stats) 27597d4b564dSXiaoliang Yang { 27607d4b564dSXiaoliang Yang struct felix_stream_filter_counters counters; 27617d4b564dSXiaoliang Yang struct ocelot_psfp_list *psfp; 27627d4b564dSXiaoliang Yang struct felix_stream *stream; 27637d4b564dSXiaoliang Yang 27647d4b564dSXiaoliang Yang psfp = &ocelot->psfp; 27657d4b564dSXiaoliang Yang stream = vsc9959_stream_table_get(&psfp->stream_list, f->cookie); 27667d4b564dSXiaoliang Yang if (!stream) 27677d4b564dSXiaoliang Yang return -ENOMEM; 27687d4b564dSXiaoliang Yang 27697d4b564dSXiaoliang Yang vsc9959_psfp_counters_get(ocelot, stream->sfid, &counters); 27707d4b564dSXiaoliang Yang 27717d4b564dSXiaoliang Yang stats->pkts = counters.match; 27727d4b564dSXiaoliang Yang stats->drops = counters.not_pass_gate + counters.not_pass_sdu + 27737d4b564dSXiaoliang Yang counters.red; 27747d4b564dSXiaoliang Yang 27757d4b564dSXiaoliang Yang return 0; 27767d4b564dSXiaoliang Yang } 27777d4b564dSXiaoliang Yang 27787d4b564dSXiaoliang Yang static void vsc9959_psfp_init(struct ocelot *ocelot) 27797d4b564dSXiaoliang Yang { 27807d4b564dSXiaoliang Yang struct ocelot_psfp_list *psfp = &ocelot->psfp; 27817d4b564dSXiaoliang Yang 27827d4b564dSXiaoliang Yang INIT_LIST_HEAD(&psfp->stream_list); 27837d4b564dSXiaoliang Yang INIT_LIST_HEAD(&psfp->sfi_list); 27847d4b564dSXiaoliang Yang INIT_LIST_HEAD(&psfp->sgi_list); 27857d4b564dSXiaoliang Yang } 27867d4b564dSXiaoliang Yang 27878abe1970SVladimir Oltean /* When using cut-through forwarding and the egress port runs at a higher data 27888abe1970SVladimir Oltean * rate than the ingress port, the packet currently under transmission would 27898abe1970SVladimir Oltean * suffer an underrun since it would be transmitted faster than it is received. 27908abe1970SVladimir Oltean * The Felix switch implementation of cut-through forwarding does not check in 27918abe1970SVladimir Oltean * hardware whether this condition is satisfied or not, so we must restrict the 27928abe1970SVladimir Oltean * list of ports that have cut-through forwarding enabled on egress to only be 27938abe1970SVladimir Oltean * the ports operating at the lowest link speed within their respective 27948abe1970SVladimir Oltean * forwarding domain. 27958abe1970SVladimir Oltean */ 27968abe1970SVladimir Oltean static void vsc9959_cut_through_fwd(struct ocelot *ocelot) 27978abe1970SVladimir Oltean { 27988abe1970SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 27998abe1970SVladimir Oltean struct dsa_switch *ds = felix->ds; 28008abe1970SVladimir Oltean int port, other_port; 28018abe1970SVladimir Oltean 28028abe1970SVladimir Oltean lockdep_assert_held(&ocelot->fwd_domain_lock); 28038abe1970SVladimir Oltean 28048abe1970SVladimir Oltean for (port = 0; port < ocelot->num_phys_ports; port++) { 28058abe1970SVladimir Oltean struct ocelot_port *ocelot_port = ocelot->ports[port]; 28068abe1970SVladimir Oltean int min_speed = ocelot_port->speed; 28078abe1970SVladimir Oltean unsigned long mask = 0; 28088abe1970SVladimir Oltean u32 tmp, val = 0; 28098abe1970SVladimir Oltean 28108abe1970SVladimir Oltean /* Disable cut-through on ports that are down */ 28118abe1970SVladimir Oltean if (ocelot_port->speed <= 0) 28128abe1970SVladimir Oltean goto set; 28138abe1970SVladimir Oltean 28148abe1970SVladimir Oltean if (dsa_is_cpu_port(ds, port)) { 28158abe1970SVladimir Oltean /* Ocelot switches forward from the NPI port towards 28168abe1970SVladimir Oltean * any port, regardless of it being in the NPI port's 28178abe1970SVladimir Oltean * forwarding domain or not. 28188abe1970SVladimir Oltean */ 28198abe1970SVladimir Oltean mask = dsa_user_ports(ds); 28208abe1970SVladimir Oltean } else { 28218abe1970SVladimir Oltean mask = ocelot_get_bridge_fwd_mask(ocelot, port); 28228abe1970SVladimir Oltean mask &= ~BIT(port); 28238abe1970SVladimir Oltean if (ocelot->npi >= 0) 28248abe1970SVladimir Oltean mask |= BIT(ocelot->npi); 28258abe1970SVladimir Oltean else 2826c295f983SVladimir Oltean mask |= ocelot_port_assigned_dsa_8021q_cpu_mask(ocelot, 2827c295f983SVladimir Oltean port); 28288abe1970SVladimir Oltean } 28298abe1970SVladimir Oltean 28308abe1970SVladimir Oltean /* Calculate the minimum link speed, among the ports that are 28318abe1970SVladimir Oltean * up, of this source port's forwarding domain. 28328abe1970SVladimir Oltean */ 28338abe1970SVladimir Oltean for_each_set_bit(other_port, &mask, ocelot->num_phys_ports) { 28348abe1970SVladimir Oltean struct ocelot_port *other_ocelot_port; 28358abe1970SVladimir Oltean 28368abe1970SVladimir Oltean other_ocelot_port = ocelot->ports[other_port]; 28378abe1970SVladimir Oltean if (other_ocelot_port->speed <= 0) 28388abe1970SVladimir Oltean continue; 28398abe1970SVladimir Oltean 28408abe1970SVladimir Oltean if (min_speed > other_ocelot_port->speed) 28418abe1970SVladimir Oltean min_speed = other_ocelot_port->speed; 28428abe1970SVladimir Oltean } 28438abe1970SVladimir Oltean 28448abe1970SVladimir Oltean /* Enable cut-through forwarding for all traffic classes. */ 28458abe1970SVladimir Oltean if (ocelot_port->speed == min_speed) 28468abe1970SVladimir Oltean val = GENMASK(7, 0); 28478abe1970SVladimir Oltean 28488abe1970SVladimir Oltean set: 28498abe1970SVladimir Oltean tmp = ocelot_read_rix(ocelot, ANA_CUT_THRU_CFG, port); 28508abe1970SVladimir Oltean if (tmp == val) 28518abe1970SVladimir Oltean continue; 28528abe1970SVladimir Oltean 28538abe1970SVladimir Oltean dev_dbg(ocelot->dev, 28548abe1970SVladimir Oltean "port %d fwd mask 0x%lx speed %d min_speed %d, %s cut-through forwarding\n", 28558abe1970SVladimir Oltean port, mask, ocelot_port->speed, min_speed, 28568abe1970SVladimir Oltean val ? "enabling" : "disabling"); 28578abe1970SVladimir Oltean 28588abe1970SVladimir Oltean ocelot_write_rix(ocelot, val, ANA_CUT_THRU_CFG, port); 28598abe1970SVladimir Oltean } 28608abe1970SVladimir Oltean } 28618abe1970SVladimir Oltean 28627d4b564dSXiaoliang Yang static const struct ocelot_ops vsc9959_ops = { 28637d4b564dSXiaoliang Yang .reset = vsc9959_reset, 28647d4b564dSXiaoliang Yang .wm_enc = vsc9959_wm_enc, 28657d4b564dSXiaoliang Yang .wm_dec = vsc9959_wm_dec, 28667d4b564dSXiaoliang Yang .wm_stat = vsc9959_wm_stat, 28677d4b564dSXiaoliang Yang .port_to_netdev = felix_port_to_netdev, 28687d4b564dSXiaoliang Yang .netdev_to_port = felix_netdev_to_port, 28697d4b564dSXiaoliang Yang .psfp_init = vsc9959_psfp_init, 28707d4b564dSXiaoliang Yang .psfp_filter_add = vsc9959_psfp_filter_add, 28717d4b564dSXiaoliang Yang .psfp_filter_del = vsc9959_psfp_filter_del, 28727d4b564dSXiaoliang Yang .psfp_stats_get = vsc9959_psfp_stats_get, 28738abe1970SVladimir Oltean .cut_through_fwd = vsc9959_cut_through_fwd, 28748670dc33SXiaoliang Yang .tas_clock_adjust = vsc9959_tas_clock_adjust, 28757d4b564dSXiaoliang Yang }; 28767d4b564dSXiaoliang Yang 2877375e1314SVladimir Oltean static const struct felix_info felix_info_vsc9959 = { 287856051948SVladimir Oltean .target_io_res = vsc9959_target_io_res, 287956051948SVladimir Oltean .port_io_res = vsc9959_port_io_res, 2880bdeced75SVladimir Oltean .imdio_res = &vsc9959_imdio_res, 288156051948SVladimir Oltean .regfields = vsc9959_regfields, 288256051948SVladimir Oltean .map = vsc9959_regmap, 288356051948SVladimir Oltean .ops = &vsc9959_ops, 288456051948SVladimir Oltean .stats_layout = vsc9959_stats_layout, 288507d985eeSVladimir Oltean .vcap = vsc9959_vcap_props, 288677043c37SXiaoliang Yang .vcap_pol_base = VSC9959_VCAP_POLICER_BASE, 288777043c37SXiaoliang Yang .vcap_pol_max = VSC9959_VCAP_POLICER_MAX, 288877043c37SXiaoliang Yang .vcap_pol_base2 = 0, 288977043c37SXiaoliang Yang .vcap_pol_max2 = 0, 289021ce7f3eSVladimir Oltean .num_mact_rows = 2048, 2891acf242fcSColin Foster .num_ports = VSC9959_NUM_PORTS, 289270d39a6eSVladimir Oltean .num_tx_queues = OCELOT_NUM_TC, 2893c8c0ba4fSVladimir Oltean .quirk_no_xtr_irq = true, 28942ac7c6c5SVladimir Oltean .ptp_caps = &vsc9959_ptp_caps, 2895bdeced75SVladimir Oltean .mdio_bus_alloc = vsc9959_mdio_bus_alloc, 2896bdeced75SVladimir Oltean .mdio_bus_free = vsc9959_mdio_bus_free, 2897375e1314SVladimir Oltean .phylink_validate = vsc9959_phylink_validate, 2898acf242fcSColin Foster .port_modes = vsc9959_port_modes, 2899de143c0eSXiaoliang Yang .port_setup_tc = vsc9959_port_setup_tc, 2900de143c0eSXiaoliang Yang .port_sched_speed_set = vsc9959_sched_speed_set, 290155a515b1SVladimir Oltean .tas_guard_bands_update = vsc9959_tas_guard_bands_update, 2902242bd0c1SColin Foster .init_regmap = ocelot_regmap_init, 290356051948SVladimir Oltean }; 2904375e1314SVladimir Oltean 2905375e1314SVladimir Oltean static irqreturn_t felix_irq_handler(int irq, void *data) 2906375e1314SVladimir Oltean { 2907375e1314SVladimir Oltean struct ocelot *ocelot = (struct ocelot *)data; 2908375e1314SVladimir Oltean 2909375e1314SVladimir Oltean /* The INTB interrupt is used for both PTP TX timestamp interrupt 2910375e1314SVladimir Oltean * and preemption status change interrupt on each port. 2911375e1314SVladimir Oltean * 2912375e1314SVladimir Oltean * - Get txtstamp if have 2913375e1314SVladimir Oltean * - TODO: handle preemption. Without handling it, driver may get 2914375e1314SVladimir Oltean * interrupt storm. 2915375e1314SVladimir Oltean */ 2916375e1314SVladimir Oltean 2917375e1314SVladimir Oltean ocelot_get_txtstamp(ocelot); 2918375e1314SVladimir Oltean 2919375e1314SVladimir Oltean return IRQ_HANDLED; 2920375e1314SVladimir Oltean } 2921375e1314SVladimir Oltean 2922375e1314SVladimir Oltean static int felix_pci_probe(struct pci_dev *pdev, 2923375e1314SVladimir Oltean const struct pci_device_id *id) 2924375e1314SVladimir Oltean { 2925375e1314SVladimir Oltean struct dsa_switch *ds; 2926375e1314SVladimir Oltean struct ocelot *ocelot; 2927375e1314SVladimir Oltean struct felix *felix; 2928375e1314SVladimir Oltean int err; 2929375e1314SVladimir Oltean 2930375e1314SVladimir Oltean if (pdev->dev.of_node && !of_device_is_available(pdev->dev.of_node)) { 2931375e1314SVladimir Oltean dev_info(&pdev->dev, "device is disabled, skipping\n"); 2932375e1314SVladimir Oltean return -ENODEV; 2933375e1314SVladimir Oltean } 2934375e1314SVladimir Oltean 2935375e1314SVladimir Oltean err = pci_enable_device(pdev); 2936375e1314SVladimir Oltean if (err) { 2937375e1314SVladimir Oltean dev_err(&pdev->dev, "device enable failed\n"); 2938375e1314SVladimir Oltean goto err_pci_enable; 2939375e1314SVladimir Oltean } 2940375e1314SVladimir Oltean 2941375e1314SVladimir Oltean felix = kzalloc(sizeof(struct felix), GFP_KERNEL); 2942375e1314SVladimir Oltean if (!felix) { 2943375e1314SVladimir Oltean err = -ENOMEM; 2944375e1314SVladimir Oltean dev_err(&pdev->dev, "Failed to allocate driver memory\n"); 2945375e1314SVladimir Oltean goto err_alloc_felix; 2946375e1314SVladimir Oltean } 2947375e1314SVladimir Oltean 2948375e1314SVladimir Oltean pci_set_drvdata(pdev, felix); 2949375e1314SVladimir Oltean ocelot = &felix->ocelot; 2950375e1314SVladimir Oltean ocelot->dev = &pdev->dev; 295170d39a6eSVladimir Oltean ocelot->num_flooding_pgids = OCELOT_NUM_TC; 2952375e1314SVladimir Oltean felix->info = &felix_info_vsc9959; 2953c9910484SColin Foster felix->switch_base = pci_resource_start(pdev, VSC9959_SWITCH_PCI_BAR); 2954c9910484SColin Foster felix->imdio_base = pci_resource_start(pdev, VSC9959_IMDIO_PCI_BAR); 2955375e1314SVladimir Oltean 2956375e1314SVladimir Oltean pci_set_master(pdev); 2957375e1314SVladimir Oltean 2958375e1314SVladimir Oltean err = devm_request_threaded_irq(&pdev->dev, pdev->irq, NULL, 2959375e1314SVladimir Oltean &felix_irq_handler, IRQF_ONESHOT, 2960375e1314SVladimir Oltean "felix-intb", ocelot); 2961375e1314SVladimir Oltean if (err) { 2962375e1314SVladimir Oltean dev_err(&pdev->dev, "Failed to request irq\n"); 2963375e1314SVladimir Oltean goto err_alloc_irq; 2964375e1314SVladimir Oltean } 2965375e1314SVladimir Oltean 2966375e1314SVladimir Oltean ocelot->ptp = 1; 2967375e1314SVladimir Oltean 2968375e1314SVladimir Oltean ds = kzalloc(sizeof(struct dsa_switch), GFP_KERNEL); 2969375e1314SVladimir Oltean if (!ds) { 2970375e1314SVladimir Oltean err = -ENOMEM; 2971375e1314SVladimir Oltean dev_err(&pdev->dev, "Failed to allocate DSA switch\n"); 2972375e1314SVladimir Oltean goto err_alloc_ds; 2973375e1314SVladimir Oltean } 2974375e1314SVladimir Oltean 2975375e1314SVladimir Oltean ds->dev = &pdev->dev; 2976375e1314SVladimir Oltean ds->num_ports = felix->info->num_ports; 2977375e1314SVladimir Oltean ds->num_tx_queues = felix->info->num_tx_queues; 2978375e1314SVladimir Oltean ds->ops = &felix_switch_ops; 2979375e1314SVladimir Oltean ds->priv = ocelot; 2980375e1314SVladimir Oltean felix->ds = ds; 2981adb3dccfSVladimir Oltean felix->tag_proto = DSA_TAG_PROTO_OCELOT; 2982375e1314SVladimir Oltean 2983375e1314SVladimir Oltean err = dsa_register_switch(ds); 2984375e1314SVladimir Oltean if (err) { 2985e6934e40SMichael Walle dev_err_probe(&pdev->dev, err, "Failed to register DSA switch\n"); 2986375e1314SVladimir Oltean goto err_register_ds; 2987375e1314SVladimir Oltean } 2988375e1314SVladimir Oltean 2989375e1314SVladimir Oltean return 0; 2990375e1314SVladimir Oltean 2991375e1314SVladimir Oltean err_register_ds: 2992375e1314SVladimir Oltean kfree(ds); 2993375e1314SVladimir Oltean err_alloc_ds: 2994375e1314SVladimir Oltean err_alloc_irq: 2995375e1314SVladimir Oltean kfree(felix); 2996537e2b88SVladimir Oltean err_alloc_felix: 2997375e1314SVladimir Oltean pci_disable_device(pdev); 2998375e1314SVladimir Oltean err_pci_enable: 2999375e1314SVladimir Oltean return err; 3000375e1314SVladimir Oltean } 3001375e1314SVladimir Oltean 3002375e1314SVladimir Oltean static void felix_pci_remove(struct pci_dev *pdev) 3003375e1314SVladimir Oltean { 30040650bf52SVladimir Oltean struct felix *felix = pci_get_drvdata(pdev); 3005375e1314SVladimir Oltean 30060650bf52SVladimir Oltean if (!felix) 30070650bf52SVladimir Oltean return; 3008375e1314SVladimir Oltean 3009375e1314SVladimir Oltean dsa_unregister_switch(felix->ds); 3010375e1314SVladimir Oltean 3011375e1314SVladimir Oltean kfree(felix->ds); 3012375e1314SVladimir Oltean kfree(felix); 3013375e1314SVladimir Oltean 3014375e1314SVladimir Oltean pci_disable_device(pdev); 30150650bf52SVladimir Oltean 30160650bf52SVladimir Oltean pci_set_drvdata(pdev, NULL); 30170650bf52SVladimir Oltean } 30180650bf52SVladimir Oltean 30190650bf52SVladimir Oltean static void felix_pci_shutdown(struct pci_dev *pdev) 30200650bf52SVladimir Oltean { 30210650bf52SVladimir Oltean struct felix *felix = pci_get_drvdata(pdev); 30220650bf52SVladimir Oltean 30230650bf52SVladimir Oltean if (!felix) 30240650bf52SVladimir Oltean return; 30250650bf52SVladimir Oltean 30260650bf52SVladimir Oltean dsa_switch_shutdown(felix->ds); 30270650bf52SVladimir Oltean 30280650bf52SVladimir Oltean pci_set_drvdata(pdev, NULL); 3029375e1314SVladimir Oltean } 3030375e1314SVladimir Oltean 3031375e1314SVladimir Oltean static struct pci_device_id felix_ids[] = { 3032375e1314SVladimir Oltean { 3033375e1314SVladimir Oltean /* NXP LS1028A */ 3034375e1314SVladimir Oltean PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0xEEF0), 3035375e1314SVladimir Oltean }, 3036375e1314SVladimir Oltean { 0, } 3037375e1314SVladimir Oltean }; 3038375e1314SVladimir Oltean MODULE_DEVICE_TABLE(pci, felix_ids); 3039375e1314SVladimir Oltean 3040d60bc62dSVladimir Oltean static struct pci_driver felix_vsc9959_pci_driver = { 3041375e1314SVladimir Oltean .name = "mscc_felix", 3042375e1314SVladimir Oltean .id_table = felix_ids, 3043375e1314SVladimir Oltean .probe = felix_pci_probe, 3044375e1314SVladimir Oltean .remove = felix_pci_remove, 30450650bf52SVladimir Oltean .shutdown = felix_pci_shutdown, 3046375e1314SVladimir Oltean }; 3047d60bc62dSVladimir Oltean module_pci_driver(felix_vsc9959_pci_driver); 3048d60bc62dSVladimir Oltean 3049d60bc62dSVladimir Oltean MODULE_DESCRIPTION("Felix Switch driver"); 3050d60bc62dSVladimir Oltean MODULE_LICENSE("GPL v2"); 3051