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> 96505b680SVladimir Oltean #include <soc/mscc/ocelot_dev.h> 10de143c0eSXiaoliang Yang #include <soc/mscc/ocelot_ptp.h> 1156051948SVladimir Oltean #include <soc/mscc/ocelot_sys.h> 1223ae3a78SXiaoliang Yang #include <net/tc_act/tc_gate.h> 1356051948SVladimir Oltean #include <soc/mscc/ocelot.h> 1440d3f295SVladimir Oltean #include <linux/dsa/ocelot.h> 15588d0550SIoana Ciornei #include <linux/pcs-lynx.h> 16de143c0eSXiaoliang Yang #include <net/pkt_sched.h> 1756051948SVladimir Oltean #include <linux/iopoll.h> 1816659b81SMichael Walle #include <linux/mdio.h> 1956051948SVladimir Oltean #include <linux/pci.h> 20837ced3aSVladimir Oltean #include <linux/time.h> 2156051948SVladimir Oltean #include "felix.h" 2256051948SVladimir Oltean 23acf242fcSColin Foster #define VSC9959_NUM_PORTS 6 24acf242fcSColin Foster 25de143c0eSXiaoliang Yang #define VSC9959_TAS_GCL_ENTRY_MAX 63 2611afdc65SVladimir Oltean #define VSC9959_TAS_MIN_GATE_LEN_NS 33 2777043c37SXiaoliang Yang #define VSC9959_VCAP_POLICER_BASE 63 2877043c37SXiaoliang Yang #define VSC9959_VCAP_POLICER_MAX 383 29c9910484SColin Foster #define VSC9959_SWITCH_PCI_BAR 4 30c9910484SColin Foster #define VSC9959_IMDIO_PCI_BAR 0 31de143c0eSXiaoliang Yang 32acf242fcSColin Foster #define VSC9959_PORT_MODE_SERDES (OCELOT_PORT_MODE_SGMII | \ 33acf242fcSColin Foster OCELOT_PORT_MODE_QSGMII | \ 3411ecf341SVladimir Oltean OCELOT_PORT_MODE_1000BASEX | \ 35acf242fcSColin Foster OCELOT_PORT_MODE_2500BASEX | \ 36acf242fcSColin Foster OCELOT_PORT_MODE_USXGMII) 37acf242fcSColin Foster 38acf242fcSColin Foster static const u32 vsc9959_port_modes[VSC9959_NUM_PORTS] = { 39acf242fcSColin Foster VSC9959_PORT_MODE_SERDES, 40acf242fcSColin Foster VSC9959_PORT_MODE_SERDES, 41acf242fcSColin Foster VSC9959_PORT_MODE_SERDES, 42acf242fcSColin Foster VSC9959_PORT_MODE_SERDES, 43acf242fcSColin Foster OCELOT_PORT_MODE_INTERNAL, 44a53cbe5dSVladimir Oltean OCELOT_PORT_MODE_INTERNAL, 45acf242fcSColin Foster }; 46acf242fcSColin Foster 4756051948SVladimir Oltean static const u32 vsc9959_ana_regmap[] = { 4856051948SVladimir Oltean REG(ANA_ADVLEARN, 0x0089a0), 4956051948SVladimir Oltean REG(ANA_VLANMASK, 0x0089a4), 5056051948SVladimir Oltean REG_RESERVED(ANA_PORT_B_DOMAIN), 5156051948SVladimir Oltean REG(ANA_ANAGEFIL, 0x0089ac), 5256051948SVladimir Oltean REG(ANA_ANEVENTS, 0x0089b0), 5356051948SVladimir Oltean REG(ANA_STORMLIMIT_BURST, 0x0089b4), 5456051948SVladimir Oltean REG(ANA_STORMLIMIT_CFG, 0x0089b8), 5556051948SVladimir Oltean REG(ANA_ISOLATED_PORTS, 0x0089c8), 5656051948SVladimir Oltean REG(ANA_COMMUNITY_PORTS, 0x0089cc), 5756051948SVladimir Oltean REG(ANA_AUTOAGE, 0x0089d0), 5856051948SVladimir Oltean REG(ANA_MACTOPTIONS, 0x0089d4), 5956051948SVladimir Oltean REG(ANA_LEARNDISC, 0x0089d8), 6056051948SVladimir Oltean REG(ANA_AGENCTRL, 0x0089dc), 6156051948SVladimir Oltean REG(ANA_MIRRORPORTS, 0x0089e0), 6256051948SVladimir Oltean REG(ANA_EMIRRORPORTS, 0x0089e4), 6356051948SVladimir Oltean REG(ANA_FLOODING, 0x0089e8), 6456051948SVladimir Oltean REG(ANA_FLOODING_IPMC, 0x008a08), 6556051948SVladimir Oltean REG(ANA_SFLOW_CFG, 0x008a0c), 6656051948SVladimir Oltean REG(ANA_PORT_MODE, 0x008a28), 6756051948SVladimir Oltean REG(ANA_CUT_THRU_CFG, 0x008a48), 6856051948SVladimir Oltean REG(ANA_PGID_PGID, 0x008400), 6956051948SVladimir Oltean REG(ANA_TABLES_ANMOVED, 0x007f1c), 7056051948SVladimir Oltean REG(ANA_TABLES_MACHDATA, 0x007f20), 7156051948SVladimir Oltean REG(ANA_TABLES_MACLDATA, 0x007f24), 7256051948SVladimir Oltean REG(ANA_TABLES_STREAMDATA, 0x007f28), 7356051948SVladimir Oltean REG(ANA_TABLES_MACACCESS, 0x007f2c), 7456051948SVladimir Oltean REG(ANA_TABLES_MACTINDX, 0x007f30), 7556051948SVladimir Oltean REG(ANA_TABLES_VLANACCESS, 0x007f34), 7656051948SVladimir Oltean REG(ANA_TABLES_VLANTIDX, 0x007f38), 7756051948SVladimir Oltean REG(ANA_TABLES_ISDXACCESS, 0x007f3c), 7856051948SVladimir Oltean REG(ANA_TABLES_ISDXTIDX, 0x007f40), 7956051948SVladimir Oltean REG(ANA_TABLES_ENTRYLIM, 0x007f00), 8056051948SVladimir Oltean REG(ANA_TABLES_PTP_ID_HIGH, 0x007f44), 8156051948SVladimir Oltean REG(ANA_TABLES_PTP_ID_LOW, 0x007f48), 8256051948SVladimir Oltean REG(ANA_TABLES_STREAMACCESS, 0x007f4c), 8356051948SVladimir Oltean REG(ANA_TABLES_STREAMTIDX, 0x007f50), 8456051948SVladimir Oltean REG(ANA_TABLES_SEQ_HISTORY, 0x007f54), 8556051948SVladimir Oltean REG(ANA_TABLES_SEQ_MASK, 0x007f58), 8656051948SVladimir Oltean REG(ANA_TABLES_SFID_MASK, 0x007f5c), 8756051948SVladimir Oltean REG(ANA_TABLES_SFIDACCESS, 0x007f60), 8856051948SVladimir Oltean REG(ANA_TABLES_SFIDTIDX, 0x007f64), 8956051948SVladimir Oltean REG(ANA_MSTI_STATE, 0x008600), 9056051948SVladimir Oltean REG(ANA_OAM_UPM_LM_CNT, 0x008000), 9156051948SVladimir Oltean REG(ANA_SG_ACCESS_CTRL, 0x008a64), 9256051948SVladimir Oltean REG(ANA_SG_CONFIG_REG_1, 0x007fb0), 9356051948SVladimir Oltean REG(ANA_SG_CONFIG_REG_2, 0x007fb4), 9456051948SVladimir Oltean REG(ANA_SG_CONFIG_REG_3, 0x007fb8), 9556051948SVladimir Oltean REG(ANA_SG_CONFIG_REG_4, 0x007fbc), 9656051948SVladimir Oltean REG(ANA_SG_CONFIG_REG_5, 0x007fc0), 9756051948SVladimir Oltean REG(ANA_SG_GCL_GS_CONFIG, 0x007f80), 9856051948SVladimir Oltean REG(ANA_SG_GCL_TI_CONFIG, 0x007f90), 9956051948SVladimir Oltean REG(ANA_SG_STATUS_REG_1, 0x008980), 10056051948SVladimir Oltean REG(ANA_SG_STATUS_REG_2, 0x008984), 10156051948SVladimir Oltean REG(ANA_SG_STATUS_REG_3, 0x008988), 10256051948SVladimir Oltean REG(ANA_PORT_VLAN_CFG, 0x007800), 10356051948SVladimir Oltean REG(ANA_PORT_DROP_CFG, 0x007804), 10456051948SVladimir Oltean REG(ANA_PORT_QOS_CFG, 0x007808), 10556051948SVladimir Oltean REG(ANA_PORT_VCAP_CFG, 0x00780c), 10656051948SVladimir Oltean REG(ANA_PORT_VCAP_S1_KEY_CFG, 0x007810), 10756051948SVladimir Oltean REG(ANA_PORT_VCAP_S2_CFG, 0x00781c), 10856051948SVladimir Oltean REG(ANA_PORT_PCP_DEI_MAP, 0x007820), 10956051948SVladimir Oltean REG(ANA_PORT_CPU_FWD_CFG, 0x007860), 11056051948SVladimir Oltean REG(ANA_PORT_CPU_FWD_BPDU_CFG, 0x007864), 11156051948SVladimir Oltean REG(ANA_PORT_CPU_FWD_GARP_CFG, 0x007868), 11256051948SVladimir Oltean REG(ANA_PORT_CPU_FWD_CCM_CFG, 0x00786c), 11356051948SVladimir Oltean REG(ANA_PORT_PORT_CFG, 0x007870), 11456051948SVladimir Oltean REG(ANA_PORT_POL_CFG, 0x007874), 11556051948SVladimir Oltean REG(ANA_PORT_PTP_CFG, 0x007878), 11656051948SVladimir Oltean REG(ANA_PORT_PTP_DLY1_CFG, 0x00787c), 11756051948SVladimir Oltean REG(ANA_PORT_PTP_DLY2_CFG, 0x007880), 11856051948SVladimir Oltean REG(ANA_PORT_SFID_CFG, 0x007884), 11956051948SVladimir Oltean REG(ANA_PFC_PFC_CFG, 0x008800), 12056051948SVladimir Oltean REG_RESERVED(ANA_PFC_PFC_TIMER), 12156051948SVladimir Oltean REG_RESERVED(ANA_IPT_OAM_MEP_CFG), 12256051948SVladimir Oltean REG_RESERVED(ANA_IPT_IPT), 12356051948SVladimir Oltean REG_RESERVED(ANA_PPT_PPT), 12456051948SVladimir Oltean REG_RESERVED(ANA_FID_MAP_FID_MAP), 12556051948SVladimir Oltean REG(ANA_AGGR_CFG, 0x008a68), 12656051948SVladimir Oltean REG(ANA_CPUQ_CFG, 0x008a6c), 12756051948SVladimir Oltean REG_RESERVED(ANA_CPUQ_CFG2), 12856051948SVladimir Oltean REG(ANA_CPUQ_8021_CFG, 0x008a74), 12956051948SVladimir Oltean REG(ANA_DSCP_CFG, 0x008ab4), 13056051948SVladimir Oltean REG(ANA_DSCP_REWR_CFG, 0x008bb4), 13156051948SVladimir Oltean REG(ANA_VCAP_RNG_TYPE_CFG, 0x008bf4), 13256051948SVladimir Oltean REG(ANA_VCAP_RNG_VAL_CFG, 0x008c14), 13356051948SVladimir Oltean REG_RESERVED(ANA_VRAP_CFG), 13456051948SVladimir Oltean REG_RESERVED(ANA_VRAP_HDR_DATA), 13556051948SVladimir Oltean REG_RESERVED(ANA_VRAP_HDR_MASK), 13656051948SVladimir Oltean REG(ANA_DISCARD_CFG, 0x008c40), 13756051948SVladimir Oltean REG(ANA_FID_CFG, 0x008c44), 13856051948SVladimir Oltean REG(ANA_POL_PIR_CFG, 0x004000), 13956051948SVladimir Oltean REG(ANA_POL_CIR_CFG, 0x004004), 14056051948SVladimir Oltean REG(ANA_POL_MODE_CFG, 0x004008), 14156051948SVladimir Oltean REG(ANA_POL_PIR_STATE, 0x00400c), 14256051948SVladimir Oltean REG(ANA_POL_CIR_STATE, 0x004010), 14356051948SVladimir Oltean REG_RESERVED(ANA_POL_STATE), 14456051948SVladimir Oltean REG(ANA_POL_FLOWC, 0x008c48), 14556051948SVladimir Oltean REG(ANA_POL_HYST, 0x008cb4), 14656051948SVladimir Oltean REG_RESERVED(ANA_POL_MISC_CFG), 14756051948SVladimir Oltean }; 14856051948SVladimir Oltean 14956051948SVladimir Oltean static const u32 vsc9959_qs_regmap[] = { 15056051948SVladimir Oltean REG(QS_XTR_GRP_CFG, 0x000000), 15156051948SVladimir Oltean REG(QS_XTR_RD, 0x000008), 15256051948SVladimir Oltean REG(QS_XTR_FRM_PRUNING, 0x000010), 15356051948SVladimir Oltean REG(QS_XTR_FLUSH, 0x000018), 15456051948SVladimir Oltean REG(QS_XTR_DATA_PRESENT, 0x00001c), 15556051948SVladimir Oltean REG(QS_XTR_CFG, 0x000020), 15656051948SVladimir Oltean REG(QS_INJ_GRP_CFG, 0x000024), 15756051948SVladimir Oltean REG(QS_INJ_WR, 0x00002c), 15856051948SVladimir Oltean REG(QS_INJ_CTRL, 0x000034), 15956051948SVladimir Oltean REG(QS_INJ_STATUS, 0x00003c), 16056051948SVladimir Oltean REG(QS_INJ_ERR, 0x000040), 16156051948SVladimir Oltean REG_RESERVED(QS_INH_DBG), 16256051948SVladimir Oltean }; 16356051948SVladimir Oltean 164c1c3993eSVladimir Oltean static const u32 vsc9959_vcap_regmap[] = { 165c1c3993eSVladimir Oltean /* VCAP_CORE_CFG */ 166c1c3993eSVladimir Oltean REG(VCAP_CORE_UPDATE_CTRL, 0x000000), 167c1c3993eSVladimir Oltean REG(VCAP_CORE_MV_CFG, 0x000004), 168c1c3993eSVladimir Oltean /* VCAP_CORE_CACHE */ 169c1c3993eSVladimir Oltean REG(VCAP_CACHE_ENTRY_DAT, 0x000008), 170c1c3993eSVladimir Oltean REG(VCAP_CACHE_MASK_DAT, 0x000108), 171c1c3993eSVladimir Oltean REG(VCAP_CACHE_ACTION_DAT, 0x000208), 172c1c3993eSVladimir Oltean REG(VCAP_CACHE_CNT_DAT, 0x000308), 173c1c3993eSVladimir Oltean REG(VCAP_CACHE_TG_DAT, 0x000388), 17420968054SVladimir Oltean /* VCAP_CONST */ 17520968054SVladimir Oltean REG(VCAP_CONST_VCAP_VER, 0x000398), 17620968054SVladimir Oltean REG(VCAP_CONST_ENTRY_WIDTH, 0x00039c), 17720968054SVladimir Oltean REG(VCAP_CONST_ENTRY_CNT, 0x0003a0), 17820968054SVladimir Oltean REG(VCAP_CONST_ENTRY_SWCNT, 0x0003a4), 17920968054SVladimir Oltean REG(VCAP_CONST_ENTRY_TG_WIDTH, 0x0003a8), 18020968054SVladimir Oltean REG(VCAP_CONST_ACTION_DEF_CNT, 0x0003ac), 18120968054SVladimir Oltean REG(VCAP_CONST_ACTION_WIDTH, 0x0003b0), 18220968054SVladimir Oltean REG(VCAP_CONST_CNT_WIDTH, 0x0003b4), 18320968054SVladimir Oltean REG(VCAP_CONST_CORE_CNT, 0x0003b8), 18420968054SVladimir Oltean REG(VCAP_CONST_IF_CNT, 0x0003bc), 18556051948SVladimir Oltean }; 18656051948SVladimir Oltean 18756051948SVladimir Oltean static const u32 vsc9959_qsys_regmap[] = { 18856051948SVladimir Oltean REG(QSYS_PORT_MODE, 0x00f460), 18956051948SVladimir Oltean REG(QSYS_SWITCH_PORT_MODE, 0x00f480), 19056051948SVladimir Oltean REG(QSYS_STAT_CNT_CFG, 0x00f49c), 19156051948SVladimir Oltean REG(QSYS_EEE_CFG, 0x00f4a0), 19256051948SVladimir Oltean REG(QSYS_EEE_THRES, 0x00f4b8), 19356051948SVladimir Oltean REG(QSYS_IGR_NO_SHARING, 0x00f4bc), 19456051948SVladimir Oltean REG(QSYS_EGR_NO_SHARING, 0x00f4c0), 19556051948SVladimir Oltean REG(QSYS_SW_STATUS, 0x00f4c4), 19656051948SVladimir Oltean REG(QSYS_EXT_CPU_CFG, 0x00f4e0), 19756051948SVladimir Oltean REG_RESERVED(QSYS_PAD_CFG), 19856051948SVladimir Oltean REG(QSYS_CPU_GROUP_MAP, 0x00f4e8), 19956051948SVladimir Oltean REG_RESERVED(QSYS_QMAP), 20056051948SVladimir Oltean REG_RESERVED(QSYS_ISDX_SGRP), 20156051948SVladimir Oltean REG_RESERVED(QSYS_TIMED_FRAME_ENTRY), 20256051948SVladimir Oltean REG(QSYS_TFRM_MISC, 0x00f50c), 20356051948SVladimir Oltean REG(QSYS_TFRM_PORT_DLY, 0x00f510), 20456051948SVladimir Oltean REG(QSYS_TFRM_TIMER_CFG_1, 0x00f514), 20556051948SVladimir Oltean REG(QSYS_TFRM_TIMER_CFG_2, 0x00f518), 20656051948SVladimir Oltean REG(QSYS_TFRM_TIMER_CFG_3, 0x00f51c), 20756051948SVladimir Oltean REG(QSYS_TFRM_TIMER_CFG_4, 0x00f520), 20856051948SVladimir Oltean REG(QSYS_TFRM_TIMER_CFG_5, 0x00f524), 20956051948SVladimir Oltean REG(QSYS_TFRM_TIMER_CFG_6, 0x00f528), 21056051948SVladimir Oltean REG(QSYS_TFRM_TIMER_CFG_7, 0x00f52c), 21156051948SVladimir Oltean REG(QSYS_TFRM_TIMER_CFG_8, 0x00f530), 21256051948SVladimir Oltean REG(QSYS_RED_PROFILE, 0x00f534), 21356051948SVladimir Oltean REG(QSYS_RES_QOS_MODE, 0x00f574), 21456051948SVladimir Oltean REG(QSYS_RES_CFG, 0x00c000), 21556051948SVladimir Oltean REG(QSYS_RES_STAT, 0x00c004), 21656051948SVladimir Oltean REG(QSYS_EGR_DROP_MODE, 0x00f578), 21756051948SVladimir Oltean REG(QSYS_EQ_CTRL, 0x00f57c), 21856051948SVladimir Oltean REG_RESERVED(QSYS_EVENTS_CORE), 21956051948SVladimir Oltean REG(QSYS_QMAXSDU_CFG_0, 0x00f584), 22056051948SVladimir Oltean REG(QSYS_QMAXSDU_CFG_1, 0x00f5a0), 22156051948SVladimir Oltean REG(QSYS_QMAXSDU_CFG_2, 0x00f5bc), 22256051948SVladimir Oltean REG(QSYS_QMAXSDU_CFG_3, 0x00f5d8), 22356051948SVladimir Oltean REG(QSYS_QMAXSDU_CFG_4, 0x00f5f4), 22456051948SVladimir Oltean REG(QSYS_QMAXSDU_CFG_5, 0x00f610), 22556051948SVladimir Oltean REG(QSYS_QMAXSDU_CFG_6, 0x00f62c), 22656051948SVladimir Oltean REG(QSYS_QMAXSDU_CFG_7, 0x00f648), 22756051948SVladimir Oltean REG(QSYS_PREEMPTION_CFG, 0x00f664), 2280fbabf87SXiaoliang Yang REG(QSYS_CIR_CFG, 0x000000), 22956051948SVladimir Oltean REG(QSYS_EIR_CFG, 0x000004), 23056051948SVladimir Oltean REG(QSYS_SE_CFG, 0x000008), 23156051948SVladimir Oltean REG(QSYS_SE_DWRR_CFG, 0x00000c), 23256051948SVladimir Oltean REG_RESERVED(QSYS_SE_CONNECT), 23356051948SVladimir Oltean REG(QSYS_SE_DLB_SENSE, 0x000040), 23456051948SVladimir Oltean REG(QSYS_CIR_STATE, 0x000044), 23556051948SVladimir Oltean REG(QSYS_EIR_STATE, 0x000048), 23656051948SVladimir Oltean REG_RESERVED(QSYS_SE_STATE), 23756051948SVladimir Oltean REG(QSYS_HSCH_MISC_CFG, 0x00f67c), 23856051948SVladimir Oltean REG(QSYS_TAG_CONFIG, 0x00f680), 23956051948SVladimir Oltean REG(QSYS_TAS_PARAM_CFG_CTRL, 0x00f698), 24056051948SVladimir Oltean REG(QSYS_PORT_MAX_SDU, 0x00f69c), 24156051948SVladimir Oltean REG(QSYS_PARAM_CFG_REG_1, 0x00f440), 24256051948SVladimir Oltean REG(QSYS_PARAM_CFG_REG_2, 0x00f444), 24356051948SVladimir Oltean REG(QSYS_PARAM_CFG_REG_3, 0x00f448), 24456051948SVladimir Oltean REG(QSYS_PARAM_CFG_REG_4, 0x00f44c), 24556051948SVladimir Oltean REG(QSYS_PARAM_CFG_REG_5, 0x00f450), 24656051948SVladimir Oltean REG(QSYS_GCL_CFG_REG_1, 0x00f454), 24756051948SVladimir Oltean REG(QSYS_GCL_CFG_REG_2, 0x00f458), 24856051948SVladimir Oltean REG(QSYS_PARAM_STATUS_REG_1, 0x00f400), 24956051948SVladimir Oltean REG(QSYS_PARAM_STATUS_REG_2, 0x00f404), 25056051948SVladimir Oltean REG(QSYS_PARAM_STATUS_REG_3, 0x00f408), 25156051948SVladimir Oltean REG(QSYS_PARAM_STATUS_REG_4, 0x00f40c), 25256051948SVladimir Oltean REG(QSYS_PARAM_STATUS_REG_5, 0x00f410), 25356051948SVladimir Oltean REG(QSYS_PARAM_STATUS_REG_6, 0x00f414), 25456051948SVladimir Oltean REG(QSYS_PARAM_STATUS_REG_7, 0x00f418), 25556051948SVladimir Oltean REG(QSYS_PARAM_STATUS_REG_8, 0x00f41c), 25656051948SVladimir Oltean REG(QSYS_PARAM_STATUS_REG_9, 0x00f420), 25756051948SVladimir Oltean REG(QSYS_GCL_STATUS_REG_1, 0x00f424), 25856051948SVladimir Oltean REG(QSYS_GCL_STATUS_REG_2, 0x00f428), 25956051948SVladimir Oltean }; 26056051948SVladimir Oltean 26156051948SVladimir Oltean static const u32 vsc9959_rew_regmap[] = { 26256051948SVladimir Oltean REG(REW_PORT_VLAN_CFG, 0x000000), 26356051948SVladimir Oltean REG(REW_TAG_CFG, 0x000004), 26456051948SVladimir Oltean REG(REW_PORT_CFG, 0x000008), 26556051948SVladimir Oltean REG(REW_DSCP_CFG, 0x00000c), 26656051948SVladimir Oltean REG(REW_PCP_DEI_QOS_MAP_CFG, 0x000010), 26756051948SVladimir Oltean REG(REW_PTP_CFG, 0x000050), 26856051948SVladimir Oltean REG(REW_PTP_DLY1_CFG, 0x000054), 26956051948SVladimir Oltean REG(REW_RED_TAG_CFG, 0x000058), 27056051948SVladimir Oltean REG(REW_DSCP_REMAP_DP1_CFG, 0x000410), 27156051948SVladimir Oltean REG(REW_DSCP_REMAP_CFG, 0x000510), 27256051948SVladimir Oltean REG_RESERVED(REW_STAT_CFG), 27356051948SVladimir Oltean REG_RESERVED(REW_REW_STICKY), 27456051948SVladimir Oltean REG_RESERVED(REW_PPT), 27556051948SVladimir Oltean }; 27656051948SVladimir Oltean 27756051948SVladimir Oltean static const u32 vsc9959_sys_regmap[] = { 27856051948SVladimir Oltean REG(SYS_COUNT_RX_OCTETS, 0x000000), 279d4c36765SVladimir Oltean REG(SYS_COUNT_RX_UNICAST, 0x000004), 28056051948SVladimir Oltean REG(SYS_COUNT_RX_MULTICAST, 0x000008), 281d4c36765SVladimir Oltean REG(SYS_COUNT_RX_BROADCAST, 0x00000c), 28256051948SVladimir Oltean REG(SYS_COUNT_RX_SHORTS, 0x000010), 28356051948SVladimir Oltean REG(SYS_COUNT_RX_FRAGMENTS, 0x000014), 28456051948SVladimir Oltean REG(SYS_COUNT_RX_JABBERS, 0x000018), 285d4c36765SVladimir Oltean REG(SYS_COUNT_RX_CRC_ALIGN_ERRS, 0x00001c), 286d4c36765SVladimir Oltean REG(SYS_COUNT_RX_SYM_ERRS, 0x000020), 28756051948SVladimir Oltean REG(SYS_COUNT_RX_64, 0x000024), 28856051948SVladimir Oltean REG(SYS_COUNT_RX_65_127, 0x000028), 28956051948SVladimir Oltean REG(SYS_COUNT_RX_128_255, 0x00002c), 2905152de7bSVladimir Oltean REG(SYS_COUNT_RX_256_511, 0x000030), 2915152de7bSVladimir Oltean REG(SYS_COUNT_RX_512_1023, 0x000034), 2925152de7bSVladimir Oltean REG(SYS_COUNT_RX_1024_1526, 0x000038), 2935152de7bSVladimir Oltean REG(SYS_COUNT_RX_1527_MAX, 0x00003c), 2945152de7bSVladimir Oltean REG(SYS_COUNT_RX_PAUSE, 0x000040), 2955152de7bSVladimir Oltean REG(SYS_COUNT_RX_CONTROL, 0x000044), 2965152de7bSVladimir Oltean REG(SYS_COUNT_RX_LONGS, 0x000048), 297d4c36765SVladimir Oltean REG(SYS_COUNT_RX_CLASSIFIED_DROPS, 0x00004c), 298d4c36765SVladimir Oltean REG(SYS_COUNT_RX_RED_PRIO_0, 0x000050), 299d4c36765SVladimir Oltean REG(SYS_COUNT_RX_RED_PRIO_1, 0x000054), 300d4c36765SVladimir Oltean REG(SYS_COUNT_RX_RED_PRIO_2, 0x000058), 301d4c36765SVladimir Oltean REG(SYS_COUNT_RX_RED_PRIO_3, 0x00005c), 302d4c36765SVladimir Oltean REG(SYS_COUNT_RX_RED_PRIO_4, 0x000060), 303d4c36765SVladimir Oltean REG(SYS_COUNT_RX_RED_PRIO_5, 0x000064), 304d4c36765SVladimir Oltean REG(SYS_COUNT_RX_RED_PRIO_6, 0x000068), 305d4c36765SVladimir Oltean REG(SYS_COUNT_RX_RED_PRIO_7, 0x00006c), 306d4c36765SVladimir Oltean REG(SYS_COUNT_RX_YELLOW_PRIO_0, 0x000070), 307d4c36765SVladimir Oltean REG(SYS_COUNT_RX_YELLOW_PRIO_1, 0x000074), 308d4c36765SVladimir Oltean REG(SYS_COUNT_RX_YELLOW_PRIO_2, 0x000078), 309d4c36765SVladimir Oltean REG(SYS_COUNT_RX_YELLOW_PRIO_3, 0x00007c), 310d4c36765SVladimir Oltean REG(SYS_COUNT_RX_YELLOW_PRIO_4, 0x000080), 311d4c36765SVladimir Oltean REG(SYS_COUNT_RX_YELLOW_PRIO_5, 0x000084), 312d4c36765SVladimir Oltean REG(SYS_COUNT_RX_YELLOW_PRIO_6, 0x000088), 313d4c36765SVladimir Oltean REG(SYS_COUNT_RX_YELLOW_PRIO_7, 0x00008c), 314d4c36765SVladimir Oltean REG(SYS_COUNT_RX_GREEN_PRIO_0, 0x000090), 315d4c36765SVladimir Oltean REG(SYS_COUNT_RX_GREEN_PRIO_1, 0x000094), 316d4c36765SVladimir Oltean REG(SYS_COUNT_RX_GREEN_PRIO_2, 0x000098), 317d4c36765SVladimir Oltean REG(SYS_COUNT_RX_GREEN_PRIO_3, 0x00009c), 318d4c36765SVladimir Oltean REG(SYS_COUNT_RX_GREEN_PRIO_4, 0x0000a0), 319d4c36765SVladimir Oltean REG(SYS_COUNT_RX_GREEN_PRIO_5, 0x0000a4), 320d4c36765SVladimir Oltean REG(SYS_COUNT_RX_GREEN_PRIO_6, 0x0000a8), 321d4c36765SVladimir Oltean REG(SYS_COUNT_RX_GREEN_PRIO_7, 0x0000ac), 322ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_ASSEMBLY_ERRS, 0x0000b0), 323ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_SMD_ERRS, 0x0000b4), 324ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_ASSEMBLY_OK, 0x0000b8), 325ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_MERGE_FRAGMENTS, 0x0000bc), 326ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_PMAC_OCTETS, 0x0000c0), 327ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_PMAC_UNICAST, 0x0000c4), 328ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_PMAC_MULTICAST, 0x0000c8), 329ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_PMAC_BROADCAST, 0x0000cc), 330ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_PMAC_SHORTS, 0x0000d0), 331ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_PMAC_FRAGMENTS, 0x0000d4), 332ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_PMAC_JABBERS, 0x0000d8), 333ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_PMAC_CRC_ALIGN_ERRS, 0x0000dc), 334ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_PMAC_SYM_ERRS, 0x0000e0), 335ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_PMAC_64, 0x0000e4), 336ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_PMAC_65_127, 0x0000e8), 337ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_PMAC_128_255, 0x0000ec), 338ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_PMAC_256_511, 0x0000f0), 339ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_PMAC_512_1023, 0x0000f4), 340ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_PMAC_1024_1526, 0x0000f8), 341ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_PMAC_1527_MAX, 0x0000fc), 342ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_PMAC_PAUSE, 0x000100), 343ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_PMAC_CONTROL, 0x000104), 344ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_PMAC_LONGS, 0x000108), 34556051948SVladimir Oltean REG(SYS_COUNT_TX_OCTETS, 0x000200), 346d4c36765SVladimir Oltean REG(SYS_COUNT_TX_UNICAST, 0x000204), 347d4c36765SVladimir Oltean REG(SYS_COUNT_TX_MULTICAST, 0x000208), 348d4c36765SVladimir Oltean REG(SYS_COUNT_TX_BROADCAST, 0x00020c), 34956051948SVladimir Oltean REG(SYS_COUNT_TX_COLLISION, 0x000210), 35056051948SVladimir Oltean REG(SYS_COUNT_TX_DROPS, 0x000214), 351d4c36765SVladimir Oltean REG(SYS_COUNT_TX_PAUSE, 0x000218), 35256051948SVladimir Oltean REG(SYS_COUNT_TX_64, 0x00021c), 35356051948SVladimir Oltean REG(SYS_COUNT_TX_65_127, 0x000220), 3545152de7bSVladimir Oltean REG(SYS_COUNT_TX_128_255, 0x000224), 3555152de7bSVladimir Oltean REG(SYS_COUNT_TX_256_511, 0x000228), 3565152de7bSVladimir Oltean REG(SYS_COUNT_TX_512_1023, 0x00022c), 3575152de7bSVladimir Oltean REG(SYS_COUNT_TX_1024_1526, 0x000230), 3585152de7bSVladimir Oltean REG(SYS_COUNT_TX_1527_MAX, 0x000234), 359d4c36765SVladimir Oltean REG(SYS_COUNT_TX_YELLOW_PRIO_0, 0x000238), 360d4c36765SVladimir Oltean REG(SYS_COUNT_TX_YELLOW_PRIO_1, 0x00023c), 361d4c36765SVladimir Oltean REG(SYS_COUNT_TX_YELLOW_PRIO_2, 0x000240), 362d4c36765SVladimir Oltean REG(SYS_COUNT_TX_YELLOW_PRIO_3, 0x000244), 363d4c36765SVladimir Oltean REG(SYS_COUNT_TX_YELLOW_PRIO_4, 0x000248), 364d4c36765SVladimir Oltean REG(SYS_COUNT_TX_YELLOW_PRIO_5, 0x00024c), 365d4c36765SVladimir Oltean REG(SYS_COUNT_TX_YELLOW_PRIO_6, 0x000250), 366d4c36765SVladimir Oltean REG(SYS_COUNT_TX_YELLOW_PRIO_7, 0x000254), 367d4c36765SVladimir Oltean REG(SYS_COUNT_TX_GREEN_PRIO_0, 0x000258), 368d4c36765SVladimir Oltean REG(SYS_COUNT_TX_GREEN_PRIO_1, 0x00025c), 369d4c36765SVladimir Oltean REG(SYS_COUNT_TX_GREEN_PRIO_2, 0x000260), 370d4c36765SVladimir Oltean REG(SYS_COUNT_TX_GREEN_PRIO_3, 0x000264), 371d4c36765SVladimir Oltean REG(SYS_COUNT_TX_GREEN_PRIO_4, 0x000268), 372d4c36765SVladimir Oltean REG(SYS_COUNT_TX_GREEN_PRIO_5, 0x00026c), 373d4c36765SVladimir Oltean REG(SYS_COUNT_TX_GREEN_PRIO_6, 0x000270), 374d4c36765SVladimir Oltean REG(SYS_COUNT_TX_GREEN_PRIO_7, 0x000274), 375be5c13f2SVladimir Oltean REG(SYS_COUNT_TX_AGED, 0x000278), 376ab3f97a9SVladimir Oltean REG(SYS_COUNT_TX_MM_HOLD, 0x00027c), 377ab3f97a9SVladimir Oltean REG(SYS_COUNT_TX_MERGE_FRAGMENTS, 0x000280), 378ab3f97a9SVladimir Oltean REG(SYS_COUNT_TX_PMAC_OCTETS, 0x000284), 379ab3f97a9SVladimir Oltean REG(SYS_COUNT_TX_PMAC_UNICAST, 0x000288), 380ab3f97a9SVladimir Oltean REG(SYS_COUNT_TX_PMAC_MULTICAST, 0x00028c), 381ab3f97a9SVladimir Oltean REG(SYS_COUNT_TX_PMAC_BROADCAST, 0x000290), 382ab3f97a9SVladimir Oltean REG(SYS_COUNT_TX_PMAC_PAUSE, 0x000294), 383ab3f97a9SVladimir Oltean REG(SYS_COUNT_TX_PMAC_64, 0x000298), 384ab3f97a9SVladimir Oltean REG(SYS_COUNT_TX_PMAC_65_127, 0x00029c), 385ab3f97a9SVladimir Oltean REG(SYS_COUNT_TX_PMAC_128_255, 0x0002a0), 386ab3f97a9SVladimir Oltean REG(SYS_COUNT_TX_PMAC_256_511, 0x0002a4), 387ab3f97a9SVladimir Oltean REG(SYS_COUNT_TX_PMAC_512_1023, 0x0002a8), 388ab3f97a9SVladimir Oltean REG(SYS_COUNT_TX_PMAC_1024_1526, 0x0002ac), 389ab3f97a9SVladimir Oltean REG(SYS_COUNT_TX_PMAC_1527_MAX, 0x0002b0), 390d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_LOCAL, 0x000400), 391d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_TAIL, 0x000404), 392d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_YELLOW_PRIO_0, 0x000408), 393d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_YELLOW_PRIO_1, 0x00040c), 394d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_YELLOW_PRIO_2, 0x000410), 395d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_YELLOW_PRIO_3, 0x000414), 396d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_YELLOW_PRIO_4, 0x000418), 397d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_YELLOW_PRIO_5, 0x00041c), 398d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_YELLOW_PRIO_6, 0x000420), 399d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_YELLOW_PRIO_7, 0x000424), 400d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_GREEN_PRIO_0, 0x000428), 401d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_GREEN_PRIO_1, 0x00042c), 402d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_GREEN_PRIO_2, 0x000430), 403d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_GREEN_PRIO_3, 0x000434), 404d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_GREEN_PRIO_4, 0x000438), 405d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_GREEN_PRIO_5, 0x00043c), 406d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_GREEN_PRIO_6, 0x000440), 407d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_GREEN_PRIO_7, 0x000444), 4080a2360c5SVladimir Oltean REG(SYS_COUNT_SF_MATCHING_FRAMES, 0x000800), 4090a2360c5SVladimir Oltean REG(SYS_COUNT_SF_NOT_PASSING_FRAMES, 0x000804), 4100a2360c5SVladimir Oltean REG(SYS_COUNT_SF_NOT_PASSING_SDU, 0x000808), 4110a2360c5SVladimir Oltean REG(SYS_COUNT_SF_RED_FRAMES, 0x00080c), 41256051948SVladimir Oltean REG(SYS_RESET_CFG, 0x000e00), 41356051948SVladimir Oltean REG(SYS_SR_ETYPE_CFG, 0x000e04), 41456051948SVladimir Oltean REG(SYS_VLAN_ETYPE_CFG, 0x000e08), 41556051948SVladimir Oltean REG(SYS_PORT_MODE, 0x000e0c), 41656051948SVladimir Oltean REG(SYS_FRONT_PORT_MODE, 0x000e2c), 41756051948SVladimir Oltean REG(SYS_FRM_AGING, 0x000e44), 41856051948SVladimir Oltean REG(SYS_STAT_CFG, 0x000e48), 41956051948SVladimir Oltean REG(SYS_SW_STATUS, 0x000e4c), 42056051948SVladimir Oltean REG_RESERVED(SYS_MISC_CFG), 42156051948SVladimir Oltean REG(SYS_REW_MAC_HIGH_CFG, 0x000e6c), 42256051948SVladimir Oltean REG(SYS_REW_MAC_LOW_CFG, 0x000e84), 42356051948SVladimir Oltean REG(SYS_TIMESTAMP_OFFSET, 0x000e9c), 42456051948SVladimir Oltean REG(SYS_PAUSE_CFG, 0x000ea0), 42556051948SVladimir Oltean REG(SYS_PAUSE_TOT_CFG, 0x000ebc), 42656051948SVladimir Oltean REG(SYS_ATOP, 0x000ec0), 42756051948SVladimir Oltean REG(SYS_ATOP_TOT_CFG, 0x000edc), 42856051948SVladimir Oltean REG(SYS_MAC_FC_CFG, 0x000ee0), 42956051948SVladimir Oltean REG(SYS_MMGT, 0x000ef8), 43056051948SVladimir Oltean REG_RESERVED(SYS_MMGT_FAST), 43156051948SVladimir Oltean REG_RESERVED(SYS_EVENTS_DIF), 43256051948SVladimir Oltean REG_RESERVED(SYS_EVENTS_CORE), 43356051948SVladimir Oltean REG(SYS_PTP_STATUS, 0x000f14), 43456051948SVladimir Oltean REG(SYS_PTP_TXSTAMP, 0x000f18), 43556051948SVladimir Oltean REG(SYS_PTP_NXT, 0x000f1c), 43656051948SVladimir Oltean REG(SYS_PTP_CFG, 0x000f20), 43756051948SVladimir Oltean REG(SYS_RAM_INIT, 0x000f24), 43856051948SVladimir Oltean REG_RESERVED(SYS_CM_ADDR), 43956051948SVladimir Oltean REG_RESERVED(SYS_CM_DATA_WR), 44056051948SVladimir Oltean REG_RESERVED(SYS_CM_DATA_RD), 44156051948SVladimir Oltean REG_RESERVED(SYS_CM_OP), 44256051948SVladimir Oltean REG_RESERVED(SYS_CM_DATA), 44356051948SVladimir Oltean }; 44456051948SVladimir Oltean 4455df66c48SYangbo Lu static const u32 vsc9959_ptp_regmap[] = { 4465df66c48SYangbo Lu REG(PTP_PIN_CFG, 0x000000), 4475df66c48SYangbo Lu REG(PTP_PIN_TOD_SEC_MSB, 0x000004), 4485df66c48SYangbo Lu REG(PTP_PIN_TOD_SEC_LSB, 0x000008), 4495df66c48SYangbo Lu REG(PTP_PIN_TOD_NSEC, 0x00000c), 45094aca082SYangbo Lu REG(PTP_PIN_WF_HIGH_PERIOD, 0x000014), 45194aca082SYangbo Lu REG(PTP_PIN_WF_LOW_PERIOD, 0x000018), 4525df66c48SYangbo Lu REG(PTP_CFG_MISC, 0x0000a0), 4535df66c48SYangbo Lu REG(PTP_CLK_CFG_ADJ_CFG, 0x0000a4), 4545df66c48SYangbo Lu REG(PTP_CLK_CFG_ADJ_FREQ, 0x0000a8), 4555df66c48SYangbo Lu }; 4565df66c48SYangbo Lu 45756051948SVladimir Oltean static const u32 vsc9959_gcb_regmap[] = { 45856051948SVladimir Oltean REG(GCB_SOFT_RST, 0x000004), 45956051948SVladimir Oltean }; 46056051948SVladimir Oltean 46191c724cfSVladimir Oltean static const u32 vsc9959_dev_gmii_regmap[] = { 46291c724cfSVladimir Oltean REG(DEV_CLOCK_CFG, 0x0), 46391c724cfSVladimir Oltean REG(DEV_PORT_MISC, 0x4), 46491c724cfSVladimir Oltean REG(DEV_EVENTS, 0x8), 46591c724cfSVladimir Oltean REG(DEV_EEE_CFG, 0xc), 46691c724cfSVladimir Oltean REG(DEV_RX_PATH_DELAY, 0x10), 46791c724cfSVladimir Oltean REG(DEV_TX_PATH_DELAY, 0x14), 46891c724cfSVladimir Oltean REG(DEV_PTP_PREDICT_CFG, 0x18), 46991c724cfSVladimir Oltean REG(DEV_MAC_ENA_CFG, 0x1c), 47091c724cfSVladimir Oltean REG(DEV_MAC_MODE_CFG, 0x20), 47191c724cfSVladimir Oltean REG(DEV_MAC_MAXLEN_CFG, 0x24), 47291c724cfSVladimir Oltean REG(DEV_MAC_TAGS_CFG, 0x28), 47391c724cfSVladimir Oltean REG(DEV_MAC_ADV_CHK_CFG, 0x2c), 47491c724cfSVladimir Oltean REG(DEV_MAC_IFG_CFG, 0x30), 47591c724cfSVladimir Oltean REG(DEV_MAC_HDX_CFG, 0x34), 47691c724cfSVladimir Oltean REG(DEV_MAC_DBG_CFG, 0x38), 47791c724cfSVladimir Oltean REG(DEV_MAC_FC_MAC_LOW_CFG, 0x3c), 47891c724cfSVladimir Oltean REG(DEV_MAC_FC_MAC_HIGH_CFG, 0x40), 47991c724cfSVladimir Oltean REG(DEV_MAC_STICKY, 0x44), 4806505b680SVladimir Oltean REG(DEV_MM_ENABLE_CONFIG, 0x48), 4816505b680SVladimir Oltean REG(DEV_MM_VERIF_CONFIG, 0x4C), 4826505b680SVladimir Oltean REG(DEV_MM_STATUS, 0x50), 48391c724cfSVladimir Oltean REG_RESERVED(PCS1G_CFG), 48491c724cfSVladimir Oltean REG_RESERVED(PCS1G_MODE_CFG), 48591c724cfSVladimir Oltean REG_RESERVED(PCS1G_SD_CFG), 48691c724cfSVladimir Oltean REG_RESERVED(PCS1G_ANEG_CFG), 48791c724cfSVladimir Oltean REG_RESERVED(PCS1G_ANEG_NP_CFG), 48891c724cfSVladimir Oltean REG_RESERVED(PCS1G_LB_CFG), 48991c724cfSVladimir Oltean REG_RESERVED(PCS1G_DBG_CFG), 49091c724cfSVladimir Oltean REG_RESERVED(PCS1G_CDET_CFG), 49191c724cfSVladimir Oltean REG_RESERVED(PCS1G_ANEG_STATUS), 49291c724cfSVladimir Oltean REG_RESERVED(PCS1G_ANEG_NP_STATUS), 49391c724cfSVladimir Oltean REG_RESERVED(PCS1G_LINK_STATUS), 49491c724cfSVladimir Oltean REG_RESERVED(PCS1G_LINK_DOWN_CNT), 49591c724cfSVladimir Oltean REG_RESERVED(PCS1G_STICKY), 49691c724cfSVladimir Oltean REG_RESERVED(PCS1G_DEBUG_STATUS), 49791c724cfSVladimir Oltean REG_RESERVED(PCS1G_LPI_CFG), 49891c724cfSVladimir Oltean REG_RESERVED(PCS1G_LPI_WAKE_ERROR_CNT), 49991c724cfSVladimir Oltean REG_RESERVED(PCS1G_LPI_STATUS), 50091c724cfSVladimir Oltean REG_RESERVED(PCS1G_TSTPAT_MODE_CFG), 50191c724cfSVladimir Oltean REG_RESERVED(PCS1G_TSTPAT_STATUS), 50291c724cfSVladimir Oltean REG_RESERVED(DEV_PCS_FX100_CFG), 50391c724cfSVladimir Oltean REG_RESERVED(DEV_PCS_FX100_STATUS), 50491c724cfSVladimir Oltean }; 50591c724cfSVladimir Oltean 50691c724cfSVladimir Oltean static const u32 *vsc9959_regmap[TARGET_MAX] = { 50756051948SVladimir Oltean [ANA] = vsc9959_ana_regmap, 50856051948SVladimir Oltean [QS] = vsc9959_qs_regmap, 50956051948SVladimir Oltean [QSYS] = vsc9959_qsys_regmap, 51056051948SVladimir Oltean [REW] = vsc9959_rew_regmap, 51156051948SVladimir Oltean [SYS] = vsc9959_sys_regmap, 512e3aea296SVladimir Oltean [S0] = vsc9959_vcap_regmap, 513a61e365dSVladimir Oltean [S1] = vsc9959_vcap_regmap, 514c1c3993eSVladimir Oltean [S2] = vsc9959_vcap_regmap, 5155df66c48SYangbo Lu [PTP] = vsc9959_ptp_regmap, 51656051948SVladimir Oltean [GCB] = vsc9959_gcb_regmap, 51791c724cfSVladimir Oltean [DEV_GMII] = vsc9959_dev_gmii_regmap, 51856051948SVladimir Oltean }; 51956051948SVladimir Oltean 520b4024c9eSClaudiu Manoil /* Addresses are relative to the PCI device's base address */ 5211109b97bSVladimir Oltean static const struct resource vsc9959_resources[] = { 5221109b97bSVladimir Oltean DEFINE_RES_MEM_NAMED(0x0010000, 0x0010000, "sys"), 5231109b97bSVladimir Oltean DEFINE_RES_MEM_NAMED(0x0030000, 0x0010000, "rew"), 5241109b97bSVladimir Oltean DEFINE_RES_MEM_NAMED(0x0040000, 0x0000400, "s0"), 5251109b97bSVladimir Oltean DEFINE_RES_MEM_NAMED(0x0050000, 0x0000400, "s1"), 5261109b97bSVladimir Oltean DEFINE_RES_MEM_NAMED(0x0060000, 0x0000400, "s2"), 5271109b97bSVladimir Oltean DEFINE_RES_MEM_NAMED(0x0070000, 0x0000200, "devcpu_gcb"), 5281109b97bSVladimir Oltean DEFINE_RES_MEM_NAMED(0x0080000, 0x0000100, "qs"), 5291109b97bSVladimir Oltean DEFINE_RES_MEM_NAMED(0x0090000, 0x00000cc, "ptp"), 530044d447aSVladimir Oltean DEFINE_RES_MEM_NAMED(0x0100000, 0x0010000, "port0"), 531044d447aSVladimir Oltean DEFINE_RES_MEM_NAMED(0x0110000, 0x0010000, "port1"), 532044d447aSVladimir Oltean DEFINE_RES_MEM_NAMED(0x0120000, 0x0010000, "port2"), 533044d447aSVladimir Oltean DEFINE_RES_MEM_NAMED(0x0130000, 0x0010000, "port3"), 534044d447aSVladimir Oltean DEFINE_RES_MEM_NAMED(0x0140000, 0x0010000, "port4"), 535044d447aSVladimir Oltean DEFINE_RES_MEM_NAMED(0x0150000, 0x0010000, "port5"), 5361109b97bSVladimir Oltean DEFINE_RES_MEM_NAMED(0x0200000, 0x0020000, "qsys"), 5371109b97bSVladimir Oltean DEFINE_RES_MEM_NAMED(0x0280000, 0x0010000, "ana"), 5381109b97bSVladimir Oltean }; 5391109b97bSVladimir Oltean 5401109b97bSVladimir Oltean static const char * const vsc9959_resource_names[TARGET_MAX] = { 5411109b97bSVladimir Oltean [SYS] = "sys", 5421109b97bSVladimir Oltean [REW] = "rew", 5431109b97bSVladimir Oltean [S0] = "s0", 5441109b97bSVladimir Oltean [S1] = "s1", 5451109b97bSVladimir Oltean [S2] = "s2", 5461109b97bSVladimir Oltean [GCB] = "devcpu_gcb", 5471109b97bSVladimir Oltean [QS] = "qs", 5481109b97bSVladimir Oltean [PTP] = "ptp", 5491109b97bSVladimir Oltean [QSYS] = "qsys", 5501109b97bSVladimir Oltean [ANA] = "ana", 55156051948SVladimir Oltean }; 55256051948SVladimir Oltean 553bdeced75SVladimir Oltean /* Port MAC 0 Internal MDIO bus through which the SerDes acting as an 554bdeced75SVladimir Oltean * SGMII/QSGMII MAC PCS can be found. 555bdeced75SVladimir Oltean */ 556044d447aSVladimir Oltean static const struct resource vsc9959_imdio_res = 557*940af261SVladimir Oltean DEFINE_RES_MEM_NAMED(0x8030, 0x10, "imdio"); 558bdeced75SVladimir Oltean 5592789658fSMaxim Kochetkov static const struct reg_field vsc9959_regfields[REGFIELD_MAX] = { 56056051948SVladimir Oltean [ANA_ADVLEARN_VLAN_CHK] = REG_FIELD(ANA_ADVLEARN, 6, 6), 56156051948SVladimir Oltean [ANA_ADVLEARN_LEARN_MIRROR] = REG_FIELD(ANA_ADVLEARN, 0, 5), 56256051948SVladimir Oltean [ANA_ANEVENTS_FLOOD_DISCARD] = REG_FIELD(ANA_ANEVENTS, 30, 30), 56356051948SVladimir Oltean [ANA_ANEVENTS_AUTOAGE] = REG_FIELD(ANA_ANEVENTS, 26, 26), 56456051948SVladimir Oltean [ANA_ANEVENTS_STORM_DROP] = REG_FIELD(ANA_ANEVENTS, 24, 24), 56556051948SVladimir Oltean [ANA_ANEVENTS_LEARN_DROP] = REG_FIELD(ANA_ANEVENTS, 23, 23), 56656051948SVladimir Oltean [ANA_ANEVENTS_AGED_ENTRY] = REG_FIELD(ANA_ANEVENTS, 22, 22), 56756051948SVladimir Oltean [ANA_ANEVENTS_CPU_LEARN_FAILED] = REG_FIELD(ANA_ANEVENTS, 21, 21), 56856051948SVladimir Oltean [ANA_ANEVENTS_AUTO_LEARN_FAILED] = REG_FIELD(ANA_ANEVENTS, 20, 20), 56956051948SVladimir Oltean [ANA_ANEVENTS_LEARN_REMOVE] = REG_FIELD(ANA_ANEVENTS, 19, 19), 57056051948SVladimir Oltean [ANA_ANEVENTS_AUTO_LEARNED] = REG_FIELD(ANA_ANEVENTS, 18, 18), 57156051948SVladimir Oltean [ANA_ANEVENTS_AUTO_MOVED] = REG_FIELD(ANA_ANEVENTS, 17, 17), 57256051948SVladimir Oltean [ANA_ANEVENTS_CLASSIFIED_DROP] = REG_FIELD(ANA_ANEVENTS, 15, 15), 57356051948SVladimir Oltean [ANA_ANEVENTS_CLASSIFIED_COPY] = REG_FIELD(ANA_ANEVENTS, 14, 14), 57456051948SVladimir Oltean [ANA_ANEVENTS_VLAN_DISCARD] = REG_FIELD(ANA_ANEVENTS, 13, 13), 57556051948SVladimir Oltean [ANA_ANEVENTS_FWD_DISCARD] = REG_FIELD(ANA_ANEVENTS, 12, 12), 57656051948SVladimir Oltean [ANA_ANEVENTS_MULTICAST_FLOOD] = REG_FIELD(ANA_ANEVENTS, 11, 11), 57756051948SVladimir Oltean [ANA_ANEVENTS_UNICAST_FLOOD] = REG_FIELD(ANA_ANEVENTS, 10, 10), 57856051948SVladimir Oltean [ANA_ANEVENTS_DEST_KNOWN] = REG_FIELD(ANA_ANEVENTS, 9, 9), 57956051948SVladimir Oltean [ANA_ANEVENTS_BUCKET3_MATCH] = REG_FIELD(ANA_ANEVENTS, 8, 8), 58056051948SVladimir Oltean [ANA_ANEVENTS_BUCKET2_MATCH] = REG_FIELD(ANA_ANEVENTS, 7, 7), 58156051948SVladimir Oltean [ANA_ANEVENTS_BUCKET1_MATCH] = REG_FIELD(ANA_ANEVENTS, 6, 6), 58256051948SVladimir Oltean [ANA_ANEVENTS_BUCKET0_MATCH] = REG_FIELD(ANA_ANEVENTS, 5, 5), 58356051948SVladimir Oltean [ANA_ANEVENTS_CPU_OPERATION] = REG_FIELD(ANA_ANEVENTS, 4, 4), 58456051948SVladimir Oltean [ANA_ANEVENTS_DMAC_LOOKUP] = REG_FIELD(ANA_ANEVENTS, 3, 3), 58556051948SVladimir Oltean [ANA_ANEVENTS_SMAC_LOOKUP] = REG_FIELD(ANA_ANEVENTS, 2, 2), 58656051948SVladimir Oltean [ANA_ANEVENTS_SEQ_GEN_ERR_0] = REG_FIELD(ANA_ANEVENTS, 1, 1), 58756051948SVladimir Oltean [ANA_ANEVENTS_SEQ_GEN_ERR_1] = REG_FIELD(ANA_ANEVENTS, 0, 0), 58856051948SVladimir Oltean [ANA_TABLES_MACACCESS_B_DOM] = REG_FIELD(ANA_TABLES_MACACCESS, 16, 16), 58956051948SVladimir Oltean [ANA_TABLES_MACTINDX_BUCKET] = REG_FIELD(ANA_TABLES_MACTINDX, 11, 12), 59056051948SVladimir Oltean [ANA_TABLES_MACTINDX_M_INDEX] = REG_FIELD(ANA_TABLES_MACTINDX, 0, 10), 59156051948SVladimir Oltean [SYS_RESET_CFG_CORE_ENA] = REG_FIELD(SYS_RESET_CFG, 0, 0), 59256051948SVladimir Oltean [GCB_SOFT_RST_SWC_RST] = REG_FIELD(GCB_SOFT_RST, 0, 0), 593886e1387SVladimir Oltean /* Replicated per number of ports (7), register size 4 per port */ 594886e1387SVladimir Oltean [QSYS_SWITCH_PORT_MODE_PORT_ENA] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 14, 14, 7, 4), 595886e1387SVladimir Oltean [QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 11, 13, 7, 4), 596886e1387SVladimir Oltean [QSYS_SWITCH_PORT_MODE_YEL_RSRVD] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 10, 10, 7, 4), 597886e1387SVladimir Oltean [QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 9, 9, 7, 4), 598886e1387SVladimir Oltean [QSYS_SWITCH_PORT_MODE_TX_PFC_ENA] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 1, 8, 7, 4), 599886e1387SVladimir Oltean [QSYS_SWITCH_PORT_MODE_TX_PFC_MODE] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 0, 0, 7, 4), 600886e1387SVladimir Oltean [SYS_PORT_MODE_DATA_WO_TS] = REG_FIELD_ID(SYS_PORT_MODE, 5, 6, 7, 4), 601886e1387SVladimir Oltean [SYS_PORT_MODE_INCL_INJ_HDR] = REG_FIELD_ID(SYS_PORT_MODE, 3, 4, 7, 4), 602886e1387SVladimir Oltean [SYS_PORT_MODE_INCL_XTR_HDR] = REG_FIELD_ID(SYS_PORT_MODE, 1, 2, 7, 4), 603886e1387SVladimir Oltean [SYS_PORT_MODE_INCL_HDR_ERR] = REG_FIELD_ID(SYS_PORT_MODE, 0, 0, 7, 4), 604541132f0SMaxim Kochetkov [SYS_PAUSE_CFG_PAUSE_START] = REG_FIELD_ID(SYS_PAUSE_CFG, 10, 18, 7, 4), 605541132f0SMaxim Kochetkov [SYS_PAUSE_CFG_PAUSE_STOP] = REG_FIELD_ID(SYS_PAUSE_CFG, 1, 9, 7, 4), 606541132f0SMaxim Kochetkov [SYS_PAUSE_CFG_PAUSE_ENA] = REG_FIELD_ID(SYS_PAUSE_CFG, 0, 1, 7, 4), 60756051948SVladimir Oltean }; 60856051948SVladimir Oltean 609e3aea296SVladimir Oltean static const struct vcap_field vsc9959_vcap_es0_keys[] = { 610e3aea296SVladimir Oltean [VCAP_ES0_EGR_PORT] = { 0, 3}, 611e3aea296SVladimir Oltean [VCAP_ES0_IGR_PORT] = { 3, 3}, 612e3aea296SVladimir Oltean [VCAP_ES0_RSV] = { 6, 2}, 613e3aea296SVladimir Oltean [VCAP_ES0_L2_MC] = { 8, 1}, 614e3aea296SVladimir Oltean [VCAP_ES0_L2_BC] = { 9, 1}, 615e3aea296SVladimir Oltean [VCAP_ES0_VID] = { 10, 12}, 616e3aea296SVladimir Oltean [VCAP_ES0_DP] = { 22, 1}, 617e3aea296SVladimir Oltean [VCAP_ES0_PCP] = { 23, 3}, 618e3aea296SVladimir Oltean }; 619e3aea296SVladimir Oltean 620e3aea296SVladimir Oltean static const struct vcap_field vsc9959_vcap_es0_actions[] = { 621e3aea296SVladimir Oltean [VCAP_ES0_ACT_PUSH_OUTER_TAG] = { 0, 2}, 622e3aea296SVladimir Oltean [VCAP_ES0_ACT_PUSH_INNER_TAG] = { 2, 1}, 623e3aea296SVladimir Oltean [VCAP_ES0_ACT_TAG_A_TPID_SEL] = { 3, 2}, 624e3aea296SVladimir Oltean [VCAP_ES0_ACT_TAG_A_VID_SEL] = { 5, 1}, 625e3aea296SVladimir Oltean [VCAP_ES0_ACT_TAG_A_PCP_SEL] = { 6, 2}, 626e3aea296SVladimir Oltean [VCAP_ES0_ACT_TAG_A_DEI_SEL] = { 8, 2}, 627e3aea296SVladimir Oltean [VCAP_ES0_ACT_TAG_B_TPID_SEL] = { 10, 2}, 628e3aea296SVladimir Oltean [VCAP_ES0_ACT_TAG_B_VID_SEL] = { 12, 1}, 629e3aea296SVladimir Oltean [VCAP_ES0_ACT_TAG_B_PCP_SEL] = { 13, 2}, 630e3aea296SVladimir Oltean [VCAP_ES0_ACT_TAG_B_DEI_SEL] = { 15, 2}, 631e3aea296SVladimir Oltean [VCAP_ES0_ACT_VID_A_VAL] = { 17, 12}, 632e3aea296SVladimir Oltean [VCAP_ES0_ACT_PCP_A_VAL] = { 29, 3}, 633e3aea296SVladimir Oltean [VCAP_ES0_ACT_DEI_A_VAL] = { 32, 1}, 634e3aea296SVladimir Oltean [VCAP_ES0_ACT_VID_B_VAL] = { 33, 12}, 635e3aea296SVladimir Oltean [VCAP_ES0_ACT_PCP_B_VAL] = { 45, 3}, 636e3aea296SVladimir Oltean [VCAP_ES0_ACT_DEI_B_VAL] = { 48, 1}, 637e3aea296SVladimir Oltean [VCAP_ES0_ACT_RSV] = { 49, 23}, 638e3aea296SVladimir Oltean [VCAP_ES0_ACT_HIT_STICKY] = { 72, 1}, 639e3aea296SVladimir Oltean }; 640e3aea296SVladimir Oltean 641a61e365dSVladimir Oltean static const struct vcap_field vsc9959_vcap_is1_keys[] = { 642a61e365dSVladimir Oltean [VCAP_IS1_HK_TYPE] = { 0, 1}, 643a61e365dSVladimir Oltean [VCAP_IS1_HK_LOOKUP] = { 1, 2}, 644a61e365dSVladimir Oltean [VCAP_IS1_HK_IGR_PORT_MASK] = { 3, 7}, 645a61e365dSVladimir Oltean [VCAP_IS1_HK_RSV] = { 10, 9}, 646a61e365dSVladimir Oltean [VCAP_IS1_HK_OAM_Y1731] = { 19, 1}, 647a61e365dSVladimir Oltean [VCAP_IS1_HK_L2_MC] = { 20, 1}, 648a61e365dSVladimir Oltean [VCAP_IS1_HK_L2_BC] = { 21, 1}, 649a61e365dSVladimir Oltean [VCAP_IS1_HK_IP_MC] = { 22, 1}, 650a61e365dSVladimir Oltean [VCAP_IS1_HK_VLAN_TAGGED] = { 23, 1}, 651a61e365dSVladimir Oltean [VCAP_IS1_HK_VLAN_DBL_TAGGED] = { 24, 1}, 652a61e365dSVladimir Oltean [VCAP_IS1_HK_TPID] = { 25, 1}, 653a61e365dSVladimir Oltean [VCAP_IS1_HK_VID] = { 26, 12}, 654a61e365dSVladimir Oltean [VCAP_IS1_HK_DEI] = { 38, 1}, 655a61e365dSVladimir Oltean [VCAP_IS1_HK_PCP] = { 39, 3}, 656a61e365dSVladimir Oltean /* Specific Fields for IS1 Half Key S1_NORMAL */ 657a61e365dSVladimir Oltean [VCAP_IS1_HK_L2_SMAC] = { 42, 48}, 658a61e365dSVladimir Oltean [VCAP_IS1_HK_ETYPE_LEN] = { 90, 1}, 659a61e365dSVladimir Oltean [VCAP_IS1_HK_ETYPE] = { 91, 16}, 660a61e365dSVladimir Oltean [VCAP_IS1_HK_IP_SNAP] = {107, 1}, 661a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4] = {108, 1}, 662a61e365dSVladimir Oltean /* Layer-3 Information */ 663a61e365dSVladimir Oltean [VCAP_IS1_HK_L3_FRAGMENT] = {109, 1}, 664a61e365dSVladimir Oltean [VCAP_IS1_HK_L3_FRAG_OFS_GT0] = {110, 1}, 665a61e365dSVladimir Oltean [VCAP_IS1_HK_L3_OPTIONS] = {111, 1}, 666a61e365dSVladimir Oltean [VCAP_IS1_HK_L3_DSCP] = {112, 6}, 667a61e365dSVladimir Oltean [VCAP_IS1_HK_L3_IP4_SIP] = {118, 32}, 668a61e365dSVladimir Oltean /* Layer-4 Information */ 669a61e365dSVladimir Oltean [VCAP_IS1_HK_TCP_UDP] = {150, 1}, 670a61e365dSVladimir Oltean [VCAP_IS1_HK_TCP] = {151, 1}, 671a61e365dSVladimir Oltean [VCAP_IS1_HK_L4_SPORT] = {152, 16}, 672a61e365dSVladimir Oltean [VCAP_IS1_HK_L4_RNG] = {168, 8}, 673a61e365dSVladimir Oltean /* Specific Fields for IS1 Half Key S1_5TUPLE_IP4 */ 674a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_INNER_TPID] = { 42, 1}, 675a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_INNER_VID] = { 43, 12}, 676a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_INNER_DEI] = { 55, 1}, 677a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_INNER_PCP] = { 56, 3}, 678a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_IP4] = { 59, 1}, 679a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_L3_FRAGMENT] = { 60, 1}, 680a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_L3_FRAG_OFS_GT0] = { 61, 1}, 681a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_L3_OPTIONS] = { 62, 1}, 682a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_L3_DSCP] = { 63, 6}, 683a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_L3_IP4_DIP] = { 69, 32}, 684a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_L3_IP4_SIP] = {101, 32}, 685a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_L3_PROTO] = {133, 8}, 686a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_TCP_UDP] = {141, 1}, 687a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_TCP] = {142, 1}, 688a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_L4_RNG] = {143, 8}, 689a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_IP_PAYLOAD_S1_5TUPLE] = {151, 32}, 690a61e365dSVladimir Oltean }; 691a61e365dSVladimir Oltean 692a61e365dSVladimir Oltean static const struct vcap_field vsc9959_vcap_is1_actions[] = { 693a61e365dSVladimir Oltean [VCAP_IS1_ACT_DSCP_ENA] = { 0, 1}, 694a61e365dSVladimir Oltean [VCAP_IS1_ACT_DSCP_VAL] = { 1, 6}, 695a61e365dSVladimir Oltean [VCAP_IS1_ACT_QOS_ENA] = { 7, 1}, 696a61e365dSVladimir Oltean [VCAP_IS1_ACT_QOS_VAL] = { 8, 3}, 697a61e365dSVladimir Oltean [VCAP_IS1_ACT_DP_ENA] = { 11, 1}, 698a61e365dSVladimir Oltean [VCAP_IS1_ACT_DP_VAL] = { 12, 1}, 699a61e365dSVladimir Oltean [VCAP_IS1_ACT_PAG_OVERRIDE_MASK] = { 13, 8}, 700a61e365dSVladimir Oltean [VCAP_IS1_ACT_PAG_VAL] = { 21, 8}, 701a61e365dSVladimir Oltean [VCAP_IS1_ACT_RSV] = { 29, 9}, 70275944fdaSXiaoliang Yang /* The fields below are incorrectly shifted by 2 in the manual */ 703a61e365dSVladimir Oltean [VCAP_IS1_ACT_VID_REPLACE_ENA] = { 38, 1}, 704a61e365dSVladimir Oltean [VCAP_IS1_ACT_VID_ADD_VAL] = { 39, 12}, 705a61e365dSVladimir Oltean [VCAP_IS1_ACT_FID_SEL] = { 51, 2}, 706a61e365dSVladimir Oltean [VCAP_IS1_ACT_FID_VAL] = { 53, 13}, 707a61e365dSVladimir Oltean [VCAP_IS1_ACT_PCP_DEI_ENA] = { 66, 1}, 708a61e365dSVladimir Oltean [VCAP_IS1_ACT_PCP_VAL] = { 67, 3}, 709a61e365dSVladimir Oltean [VCAP_IS1_ACT_DEI_VAL] = { 70, 1}, 710a61e365dSVladimir Oltean [VCAP_IS1_ACT_VLAN_POP_CNT_ENA] = { 71, 1}, 711a61e365dSVladimir Oltean [VCAP_IS1_ACT_VLAN_POP_CNT] = { 72, 2}, 712a61e365dSVladimir Oltean [VCAP_IS1_ACT_CUSTOM_ACE_TYPE_ENA] = { 74, 4}, 713a61e365dSVladimir Oltean [VCAP_IS1_ACT_HIT_STICKY] = { 78, 1}, 714a61e365dSVladimir Oltean }; 715a61e365dSVladimir Oltean 7163ab4ceb6SVladimir Oltean static struct vcap_field vsc9959_vcap_is2_keys[] = { 71707d985eeSVladimir Oltean /* Common: 41 bits */ 71807d985eeSVladimir Oltean [VCAP_IS2_TYPE] = { 0, 4}, 71907d985eeSVladimir Oltean [VCAP_IS2_HK_FIRST] = { 4, 1}, 72007d985eeSVladimir Oltean [VCAP_IS2_HK_PAG] = { 5, 8}, 72107d985eeSVladimir Oltean [VCAP_IS2_HK_IGR_PORT_MASK] = { 13, 7}, 72207d985eeSVladimir Oltean [VCAP_IS2_HK_RSV2] = { 20, 1}, 72307d985eeSVladimir Oltean [VCAP_IS2_HK_HOST_MATCH] = { 21, 1}, 72407d985eeSVladimir Oltean [VCAP_IS2_HK_L2_MC] = { 22, 1}, 72507d985eeSVladimir Oltean [VCAP_IS2_HK_L2_BC] = { 23, 1}, 72607d985eeSVladimir Oltean [VCAP_IS2_HK_VLAN_TAGGED] = { 24, 1}, 72707d985eeSVladimir Oltean [VCAP_IS2_HK_VID] = { 25, 12}, 72807d985eeSVladimir Oltean [VCAP_IS2_HK_DEI] = { 37, 1}, 72907d985eeSVladimir Oltean [VCAP_IS2_HK_PCP] = { 38, 3}, 73007d985eeSVladimir Oltean /* MAC_ETYPE / MAC_LLC / MAC_SNAP / OAM common */ 73107d985eeSVladimir Oltean [VCAP_IS2_HK_L2_DMAC] = { 41, 48}, 73207d985eeSVladimir Oltean [VCAP_IS2_HK_L2_SMAC] = { 89, 48}, 73307d985eeSVladimir Oltean /* MAC_ETYPE (TYPE=000) */ 73407d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ETYPE_ETYPE] = {137, 16}, 73507d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD0] = {153, 16}, 73607d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD1] = {169, 8}, 73707d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD2] = {177, 3}, 73807d985eeSVladimir Oltean /* MAC_LLC (TYPE=001) */ 73907d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_LLC_L2_LLC] = {137, 40}, 74007d985eeSVladimir Oltean /* MAC_SNAP (TYPE=010) */ 74107d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_SNAP_L2_SNAP] = {137, 40}, 74207d985eeSVladimir Oltean /* MAC_ARP (TYPE=011) */ 74307d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ARP_SMAC] = { 41, 48}, 74407d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ARP_ADDR_SPACE_OK] = { 89, 1}, 74507d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ARP_PROTO_SPACE_OK] = { 90, 1}, 74607d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ARP_LEN_OK] = { 91, 1}, 74707d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ARP_TARGET_MATCH] = { 92, 1}, 74807d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ARP_SENDER_MATCH] = { 93, 1}, 74907d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ARP_OPCODE_UNKNOWN] = { 94, 1}, 75007d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ARP_OPCODE] = { 95, 2}, 75107d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ARP_L3_IP4_DIP] = { 97, 32}, 75207d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ARP_L3_IP4_SIP] = {129, 32}, 75307d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ARP_DIP_EQ_SIP] = {161, 1}, 75407d985eeSVladimir Oltean /* IP4_TCP_UDP / IP4_OTHER common */ 75507d985eeSVladimir Oltean [VCAP_IS2_HK_IP4] = { 41, 1}, 75607d985eeSVladimir Oltean [VCAP_IS2_HK_L3_FRAGMENT] = { 42, 1}, 75707d985eeSVladimir Oltean [VCAP_IS2_HK_L3_FRAG_OFS_GT0] = { 43, 1}, 75807d985eeSVladimir Oltean [VCAP_IS2_HK_L3_OPTIONS] = { 44, 1}, 75907d985eeSVladimir Oltean [VCAP_IS2_HK_IP4_L3_TTL_GT0] = { 45, 1}, 76007d985eeSVladimir Oltean [VCAP_IS2_HK_L3_TOS] = { 46, 8}, 76107d985eeSVladimir Oltean [VCAP_IS2_HK_L3_IP4_DIP] = { 54, 32}, 76207d985eeSVladimir Oltean [VCAP_IS2_HK_L3_IP4_SIP] = { 86, 32}, 76307d985eeSVladimir Oltean [VCAP_IS2_HK_DIP_EQ_SIP] = {118, 1}, 76407d985eeSVladimir Oltean /* IP4_TCP_UDP (TYPE=100) */ 76507d985eeSVladimir Oltean [VCAP_IS2_HK_TCP] = {119, 1}, 7668b9e03cdSXiaoliang Yang [VCAP_IS2_HK_L4_DPORT] = {120, 16}, 7678b9e03cdSXiaoliang Yang [VCAP_IS2_HK_L4_SPORT] = {136, 16}, 76807d985eeSVladimir Oltean [VCAP_IS2_HK_L4_RNG] = {152, 8}, 76907d985eeSVladimir Oltean [VCAP_IS2_HK_L4_SPORT_EQ_DPORT] = {160, 1}, 77007d985eeSVladimir Oltean [VCAP_IS2_HK_L4_SEQUENCE_EQ0] = {161, 1}, 7718b9e03cdSXiaoliang Yang [VCAP_IS2_HK_L4_FIN] = {162, 1}, 7728b9e03cdSXiaoliang Yang [VCAP_IS2_HK_L4_SYN] = {163, 1}, 7738b9e03cdSXiaoliang Yang [VCAP_IS2_HK_L4_RST] = {164, 1}, 7748b9e03cdSXiaoliang Yang [VCAP_IS2_HK_L4_PSH] = {165, 1}, 7758b9e03cdSXiaoliang Yang [VCAP_IS2_HK_L4_ACK] = {166, 1}, 7768b9e03cdSXiaoliang Yang [VCAP_IS2_HK_L4_URG] = {167, 1}, 77707d985eeSVladimir Oltean [VCAP_IS2_HK_L4_1588_DOM] = {168, 8}, 77807d985eeSVladimir Oltean [VCAP_IS2_HK_L4_1588_VER] = {176, 4}, 77907d985eeSVladimir Oltean /* IP4_OTHER (TYPE=101) */ 78007d985eeSVladimir Oltean [VCAP_IS2_HK_IP4_L3_PROTO] = {119, 8}, 78107d985eeSVladimir Oltean [VCAP_IS2_HK_L3_PAYLOAD] = {127, 56}, 78207d985eeSVladimir Oltean /* IP6_STD (TYPE=110) */ 78307d985eeSVladimir Oltean [VCAP_IS2_HK_IP6_L3_TTL_GT0] = { 41, 1}, 78407d985eeSVladimir Oltean [VCAP_IS2_HK_L3_IP6_SIP] = { 42, 128}, 78507d985eeSVladimir Oltean [VCAP_IS2_HK_IP6_L3_PROTO] = {170, 8}, 78607d985eeSVladimir Oltean /* OAM (TYPE=111) */ 78707d985eeSVladimir Oltean [VCAP_IS2_HK_OAM_MEL_FLAGS] = {137, 7}, 78807d985eeSVladimir Oltean [VCAP_IS2_HK_OAM_VER] = {144, 5}, 78907d985eeSVladimir Oltean [VCAP_IS2_HK_OAM_OPCODE] = {149, 8}, 79007d985eeSVladimir Oltean [VCAP_IS2_HK_OAM_FLAGS] = {157, 8}, 79107d985eeSVladimir Oltean [VCAP_IS2_HK_OAM_MEPID] = {165, 16}, 79207d985eeSVladimir Oltean [VCAP_IS2_HK_OAM_CCM_CNTS_EQ0] = {181, 1}, 79307d985eeSVladimir Oltean [VCAP_IS2_HK_OAM_IS_Y1731] = {182, 1}, 79407d985eeSVladimir Oltean }; 79507d985eeSVladimir Oltean 7963ab4ceb6SVladimir Oltean static struct vcap_field vsc9959_vcap_is2_actions[] = { 79707d985eeSVladimir Oltean [VCAP_IS2_ACT_HIT_ME_ONCE] = { 0, 1}, 79807d985eeSVladimir Oltean [VCAP_IS2_ACT_CPU_COPY_ENA] = { 1, 1}, 79907d985eeSVladimir Oltean [VCAP_IS2_ACT_CPU_QU_NUM] = { 2, 3}, 80007d985eeSVladimir Oltean [VCAP_IS2_ACT_MASK_MODE] = { 5, 2}, 80107d985eeSVladimir Oltean [VCAP_IS2_ACT_MIRROR_ENA] = { 7, 1}, 80207d985eeSVladimir Oltean [VCAP_IS2_ACT_LRN_DIS] = { 8, 1}, 80307d985eeSVladimir Oltean [VCAP_IS2_ACT_POLICE_ENA] = { 9, 1}, 80407d985eeSVladimir Oltean [VCAP_IS2_ACT_POLICE_IDX] = { 10, 9}, 80507d985eeSVladimir Oltean [VCAP_IS2_ACT_POLICE_VCAP_ONLY] = { 19, 1}, 806460e985eSVladimir Oltean [VCAP_IS2_ACT_PORT_MASK] = { 20, 6}, 807460e985eSVladimir Oltean [VCAP_IS2_ACT_REW_OP] = { 26, 9}, 808460e985eSVladimir Oltean [VCAP_IS2_ACT_SMAC_REPLACE_ENA] = { 35, 1}, 809460e985eSVladimir Oltean [VCAP_IS2_ACT_RSV] = { 36, 2}, 810460e985eSVladimir Oltean [VCAP_IS2_ACT_ACL_ID] = { 38, 6}, 811460e985eSVladimir Oltean [VCAP_IS2_ACT_HIT_CNT] = { 44, 32}, 81207d985eeSVladimir Oltean }; 81307d985eeSVladimir Oltean 81420968054SVladimir Oltean static struct vcap_props vsc9959_vcap_props[] = { 815e3aea296SVladimir Oltean [VCAP_ES0] = { 816e3aea296SVladimir Oltean .action_type_width = 0, 817e3aea296SVladimir Oltean .action_table = { 818e3aea296SVladimir Oltean [ES0_ACTION_TYPE_NORMAL] = { 819e3aea296SVladimir Oltean .width = 72, /* HIT_STICKY not included */ 820e3aea296SVladimir Oltean .count = 1, 821e3aea296SVladimir Oltean }, 822e3aea296SVladimir Oltean }, 823e3aea296SVladimir Oltean .target = S0, 824e3aea296SVladimir Oltean .keys = vsc9959_vcap_es0_keys, 825e3aea296SVladimir Oltean .actions = vsc9959_vcap_es0_actions, 826e3aea296SVladimir Oltean }, 827a61e365dSVladimir Oltean [VCAP_IS1] = { 828a61e365dSVladimir Oltean .action_type_width = 0, 829a61e365dSVladimir Oltean .action_table = { 830a61e365dSVladimir Oltean [IS1_ACTION_TYPE_NORMAL] = { 831a61e365dSVladimir Oltean .width = 78, /* HIT_STICKY not included */ 832a61e365dSVladimir Oltean .count = 4, 833a61e365dSVladimir Oltean }, 834a61e365dSVladimir Oltean }, 835a61e365dSVladimir Oltean .target = S1, 836a61e365dSVladimir Oltean .keys = vsc9959_vcap_is1_keys, 837a61e365dSVladimir Oltean .actions = vsc9959_vcap_is1_actions, 838a61e365dSVladimir Oltean }, 83907d985eeSVladimir Oltean [VCAP_IS2] = { 84007d985eeSVladimir Oltean .action_type_width = 1, 84107d985eeSVladimir Oltean .action_table = { 84207d985eeSVladimir Oltean [IS2_ACTION_TYPE_NORMAL] = { 84307d985eeSVladimir Oltean .width = 44, 84407d985eeSVladimir Oltean .count = 2 84507d985eeSVladimir Oltean }, 84607d985eeSVladimir Oltean [IS2_ACTION_TYPE_SMAC_SIP] = { 84707d985eeSVladimir Oltean .width = 6, 84807d985eeSVladimir Oltean .count = 4 84907d985eeSVladimir Oltean }, 85007d985eeSVladimir Oltean }, 851c1c3993eSVladimir Oltean .target = S2, 852c1c3993eSVladimir Oltean .keys = vsc9959_vcap_is2_keys, 853c1c3993eSVladimir Oltean .actions = vsc9959_vcap_is2_actions, 85407d985eeSVladimir Oltean }, 85507d985eeSVladimir Oltean }; 85607d985eeSVladimir Oltean 8572ac7c6c5SVladimir Oltean static const struct ptp_clock_info vsc9959_ptp_caps = { 8582ac7c6c5SVladimir Oltean .owner = THIS_MODULE, 8592ac7c6c5SVladimir Oltean .name = "felix ptp", 8602ac7c6c5SVladimir Oltean .max_adj = 0x7fffffff, 8612ac7c6c5SVladimir Oltean .n_alarm = 0, 8622ac7c6c5SVladimir Oltean .n_ext_ts = 0, 8632ac7c6c5SVladimir Oltean .n_per_out = OCELOT_PTP_PINS_NUM, 8642ac7c6c5SVladimir Oltean .n_pins = OCELOT_PTP_PINS_NUM, 8652ac7c6c5SVladimir Oltean .pps = 0, 8662ac7c6c5SVladimir Oltean .gettime64 = ocelot_ptp_gettime64, 8672ac7c6c5SVladimir Oltean .settime64 = ocelot_ptp_settime64, 8682ac7c6c5SVladimir Oltean .adjtime = ocelot_ptp_adjtime, 8692ac7c6c5SVladimir Oltean .adjfine = ocelot_ptp_adjfine, 8702ac7c6c5SVladimir Oltean .verify = ocelot_ptp_verify, 8712ac7c6c5SVladimir Oltean .enable = ocelot_ptp_enable, 8722ac7c6c5SVladimir Oltean }; 8732ac7c6c5SVladimir Oltean 87456051948SVladimir Oltean #define VSC9959_INIT_TIMEOUT 50000 87556051948SVladimir Oltean #define VSC9959_GCB_RST_SLEEP 100 87656051948SVladimir Oltean #define VSC9959_SYS_RAMINIT_SLEEP 80 87756051948SVladimir Oltean 87856051948SVladimir Oltean static int vsc9959_gcb_soft_rst_status(struct ocelot *ocelot) 87956051948SVladimir Oltean { 88056051948SVladimir Oltean int val; 88156051948SVladimir Oltean 88275cea9cbSVladimir Oltean ocelot_field_read(ocelot, GCB_SOFT_RST_SWC_RST, &val); 88356051948SVladimir Oltean 88456051948SVladimir Oltean return val; 88556051948SVladimir Oltean } 88656051948SVladimir Oltean 88756051948SVladimir Oltean static int vsc9959_sys_ram_init_status(struct ocelot *ocelot) 88856051948SVladimir Oltean { 88956051948SVladimir Oltean return ocelot_read(ocelot, SYS_RAM_INIT); 89056051948SVladimir Oltean } 89156051948SVladimir Oltean 892c129fc55SVladimir Oltean /* CORE_ENA is in SYS:SYSTEM:RESET_CFG 893c129fc55SVladimir Oltean * RAM_INIT is in SYS:RAM_CTRL:RAM_INIT 894c129fc55SVladimir Oltean */ 89556051948SVladimir Oltean static int vsc9959_reset(struct ocelot *ocelot) 89656051948SVladimir Oltean { 89756051948SVladimir Oltean int val, err; 89856051948SVladimir Oltean 89956051948SVladimir Oltean /* soft-reset the switch core */ 90075cea9cbSVladimir Oltean ocelot_field_write(ocelot, GCB_SOFT_RST_SWC_RST, 1); 90156051948SVladimir Oltean 90256051948SVladimir Oltean err = readx_poll_timeout(vsc9959_gcb_soft_rst_status, ocelot, val, !val, 90356051948SVladimir Oltean VSC9959_GCB_RST_SLEEP, VSC9959_INIT_TIMEOUT); 90456051948SVladimir Oltean if (err) { 90556051948SVladimir Oltean dev_err(ocelot->dev, "timeout: switch core reset\n"); 90656051948SVladimir Oltean return err; 90756051948SVladimir Oltean } 90856051948SVladimir Oltean 90956051948SVladimir Oltean /* initialize switch mem ~40us */ 91056051948SVladimir Oltean ocelot_write(ocelot, SYS_RAM_INIT_RAM_INIT, SYS_RAM_INIT); 91156051948SVladimir Oltean err = readx_poll_timeout(vsc9959_sys_ram_init_status, ocelot, val, !val, 91256051948SVladimir Oltean VSC9959_SYS_RAMINIT_SLEEP, 91356051948SVladimir Oltean VSC9959_INIT_TIMEOUT); 91456051948SVladimir Oltean if (err) { 91556051948SVladimir Oltean dev_err(ocelot->dev, "timeout: switch sram init\n"); 91656051948SVladimir Oltean return err; 91756051948SVladimir Oltean } 91856051948SVladimir Oltean 91956051948SVladimir Oltean /* enable switch core */ 92075cea9cbSVladimir Oltean ocelot_field_write(ocelot, SYS_RESET_CFG_CORE_ENA, 1); 92156051948SVladimir Oltean 92256051948SVladimir Oltean return 0; 92356051948SVladimir Oltean } 92456051948SVladimir Oltean 925aa92d836SMaxim Kochetkov /* Watermark encode 926aa92d836SMaxim Kochetkov * Bit 8: Unit; 0:1, 1:16 927aa92d836SMaxim Kochetkov * Bit 7-0: Value to be multiplied with unit 928aa92d836SMaxim Kochetkov */ 929aa92d836SMaxim Kochetkov static u16 vsc9959_wm_enc(u16 value) 930aa92d836SMaxim Kochetkov { 93101326493SVladimir Oltean WARN_ON(value >= 16 * BIT(8)); 93201326493SVladimir Oltean 933aa92d836SMaxim Kochetkov if (value >= BIT(8)) 934aa92d836SMaxim Kochetkov return BIT(8) | (value / 16); 935aa92d836SMaxim Kochetkov 936aa92d836SMaxim Kochetkov return value; 937aa92d836SMaxim Kochetkov } 938aa92d836SMaxim Kochetkov 939703b7621SVladimir Oltean static u16 vsc9959_wm_dec(u16 wm) 940703b7621SVladimir Oltean { 941703b7621SVladimir Oltean WARN_ON(wm & ~GENMASK(8, 0)); 942703b7621SVladimir Oltean 943703b7621SVladimir Oltean if (wm & BIT(8)) 944703b7621SVladimir Oltean return (wm & GENMASK(7, 0)) * 16; 945703b7621SVladimir Oltean 946703b7621SVladimir Oltean return wm; 947703b7621SVladimir Oltean } 948703b7621SVladimir Oltean 949703b7621SVladimir Oltean static void vsc9959_wm_stat(u32 val, u32 *inuse, u32 *maxuse) 950703b7621SVladimir Oltean { 951703b7621SVladimir Oltean *inuse = (val & GENMASK(23, 12)) >> 12; 952703b7621SVladimir Oltean *maxuse = val & GENMASK(11, 0); 953703b7621SVladimir Oltean } 954703b7621SVladimir Oltean 955bdeced75SVladimir Oltean static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot) 956bdeced75SVladimir Oltean { 9571382ba68SVladimir Oltean struct pci_dev *pdev = to_pci_dev(ocelot->dev); 958bdeced75SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 959bdeced75SVladimir Oltean struct enetc_mdio_priv *mdio_priv; 960bdeced75SVladimir Oltean struct device *dev = ocelot->dev; 9611382ba68SVladimir Oltean resource_size_t imdio_base; 962bdeced75SVladimir Oltean void __iomem *imdio_regs; 963b4024c9eSClaudiu Manoil struct resource res; 964bdeced75SVladimir Oltean struct enetc_hw *hw; 965bdeced75SVladimir Oltean struct mii_bus *bus; 966bdeced75SVladimir Oltean int port; 967bdeced75SVladimir Oltean int rc; 968bdeced75SVladimir Oltean 969bdeced75SVladimir Oltean felix->pcs = devm_kcalloc(dev, felix->info->num_ports, 970e7026f15SColin Foster sizeof(struct phylink_pcs *), 971bdeced75SVladimir Oltean GFP_KERNEL); 972bdeced75SVladimir Oltean if (!felix->pcs) { 973bdeced75SVladimir Oltean dev_err(dev, "failed to allocate array for PCS PHYs\n"); 974bdeced75SVladimir Oltean return -ENOMEM; 975bdeced75SVladimir Oltean } 976bdeced75SVladimir Oltean 9771382ba68SVladimir Oltean imdio_base = pci_resource_start(pdev, VSC9959_IMDIO_PCI_BAR); 9781382ba68SVladimir Oltean 9795fc080deSVladimir Oltean memcpy(&res, &vsc9959_imdio_res, sizeof(res)); 9801382ba68SVladimir Oltean res.start += imdio_base; 9811382ba68SVladimir Oltean res.end += imdio_base; 982bdeced75SVladimir Oltean 983b4024c9eSClaudiu Manoil imdio_regs = devm_ioremap_resource(dev, &res); 984a180be79SGuobin Huang if (IS_ERR(imdio_regs)) 985bdeced75SVladimir Oltean return PTR_ERR(imdio_regs); 986bdeced75SVladimir Oltean 987bdeced75SVladimir Oltean hw = enetc_hw_alloc(dev, imdio_regs); 988bdeced75SVladimir Oltean if (IS_ERR(hw)) { 989bdeced75SVladimir Oltean dev_err(dev, "failed to allocate ENETC HW structure\n"); 990bdeced75SVladimir Oltean return PTR_ERR(hw); 991bdeced75SVladimir Oltean } 992bdeced75SVladimir Oltean 993209bdb7eSVladimir Oltean bus = mdiobus_alloc_size(sizeof(*mdio_priv)); 994bdeced75SVladimir Oltean if (!bus) 995bdeced75SVladimir Oltean return -ENOMEM; 996bdeced75SVladimir Oltean 997bdeced75SVladimir Oltean bus->name = "VSC9959 internal MDIO bus"; 99880e87442SAndrew Lunn bus->read = enetc_mdio_read_c22; 99980e87442SAndrew Lunn bus->write = enetc_mdio_write_c22; 100080e87442SAndrew Lunn bus->read_c45 = enetc_mdio_read_c45; 100180e87442SAndrew Lunn bus->write_c45 = enetc_mdio_write_c45; 1002bdeced75SVladimir Oltean bus->parent = dev; 1003bdeced75SVladimir Oltean mdio_priv = bus->priv; 1004bdeced75SVladimir Oltean mdio_priv->hw = hw; 1005bdeced75SVladimir Oltean /* This gets added to imdio_regs, which already maps addresses 1006bdeced75SVladimir Oltean * starting with the proper offset. 1007bdeced75SVladimir Oltean */ 1008bdeced75SVladimir Oltean mdio_priv->mdio_base = 0; 1009bdeced75SVladimir Oltean snprintf(bus->id, MII_BUS_ID_SIZE, "%s-imdio", dev_name(dev)); 1010bdeced75SVladimir Oltean 1011bdeced75SVladimir Oltean /* Needed in order to initialize the bus mutex lock */ 1012bdeced75SVladimir Oltean rc = mdiobus_register(bus); 1013bdeced75SVladimir Oltean if (rc < 0) { 1014bdeced75SVladimir Oltean dev_err(dev, "failed to register MDIO bus\n"); 1015209bdb7eSVladimir Oltean mdiobus_free(bus); 1016bdeced75SVladimir Oltean return rc; 1017bdeced75SVladimir Oltean } 1018bdeced75SVladimir Oltean 1019bdeced75SVladimir Oltean felix->imdio = bus; 1020bdeced75SVladimir Oltean 1021bdeced75SVladimir Oltean for (port = 0; port < felix->info->num_ports; port++) { 1022bdeced75SVladimir Oltean struct ocelot_port *ocelot_port = ocelot->ports[port]; 1023e7026f15SColin Foster struct phylink_pcs *phylink_pcs; 102461f0d0c3SColin Foster struct mdio_device *mdio_device; 1025bdeced75SVladimir Oltean 1026588d0550SIoana Ciornei if (dsa_is_unused_port(felix->ds, port)) 1027588d0550SIoana Ciornei continue; 1028bdeced75SVladimir Oltean 1029588d0550SIoana Ciornei if (ocelot_port->phy_mode == PHY_INTERFACE_MODE_INTERNAL) 1030588d0550SIoana Ciornei continue; 1031588d0550SIoana Ciornei 103261f0d0c3SColin Foster mdio_device = mdio_device_create(felix->imdio, port); 103361f0d0c3SColin Foster if (IS_ERR(mdio_device)) 1034bdeced75SVladimir Oltean continue; 1035bdeced75SVladimir Oltean 103661f0d0c3SColin Foster phylink_pcs = lynx_pcs_create(mdio_device); 1037e7026f15SColin Foster if (!phylink_pcs) { 103861f0d0c3SColin Foster mdio_device_free(mdio_device); 1039588d0550SIoana Ciornei continue; 1040588d0550SIoana Ciornei } 1041588d0550SIoana Ciornei 1042e7026f15SColin Foster felix->pcs[port] = phylink_pcs; 1043bdeced75SVladimir Oltean 1044bdeced75SVladimir Oltean dev_info(dev, "Found PCS at internal MDIO address %d\n", port); 1045bdeced75SVladimir Oltean } 1046bdeced75SVladimir Oltean 1047bdeced75SVladimir Oltean return 0; 1048bdeced75SVladimir Oltean } 1049bdeced75SVladimir Oltean 1050ccfdbab5SVladimir Oltean static void vsc9959_mdio_bus_free(struct ocelot *ocelot) 1051bdeced75SVladimir Oltean { 1052bdeced75SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 1053bdeced75SVladimir Oltean int port; 1054bdeced75SVladimir Oltean 1055bdeced75SVladimir Oltean for (port = 0; port < ocelot->num_phys_ports; port++) { 1056e7026f15SColin Foster struct phylink_pcs *phylink_pcs = felix->pcs[port]; 1057e7026f15SColin Foster struct mdio_device *mdio_device; 1058bdeced75SVladimir Oltean 1059e7026f15SColin Foster if (!phylink_pcs) 1060bdeced75SVladimir Oltean continue; 1061bdeced75SVladimir Oltean 1062e7026f15SColin Foster mdio_device = lynx_get_mdio_device(phylink_pcs); 1063e7026f15SColin Foster mdio_device_free(mdio_device); 1064e7026f15SColin Foster lynx_pcs_destroy(phylink_pcs); 1065bdeced75SVladimir Oltean } 1066bdeced75SVladimir Oltean mdiobus_unregister(felix->imdio); 1067209bdb7eSVladimir Oltean mdiobus_free(felix->imdio); 1068bdeced75SVladimir Oltean } 1069bdeced75SVladimir Oltean 107011afdc65SVladimir Oltean /* The switch considers any frame (regardless of size) as eligible for 107111afdc65SVladimir Oltean * transmission if the traffic class gate is open for at least 33 ns. 107211afdc65SVladimir Oltean * Overruns are prevented by cropping an interval at the end of the gate time 107311afdc65SVladimir Oltean * slot for which egress scheduling is blocked, but we need to still keep 33 ns 107411afdc65SVladimir Oltean * available for one packet to be transmitted, otherwise the port tc will hang. 107511afdc65SVladimir Oltean * This function returns the size of a gate interval that remains available for 107611afdc65SVladimir Oltean * setting the guard band, after reserving the space for one egress frame. 107711afdc65SVladimir Oltean */ 107811afdc65SVladimir Oltean static u64 vsc9959_tas_remaining_gate_len_ps(u64 gate_len_ns) 107911afdc65SVladimir Oltean { 108011afdc65SVladimir Oltean /* Gate always open */ 108111afdc65SVladimir Oltean if (gate_len_ns == U64_MAX) 108211afdc65SVladimir Oltean return U64_MAX; 108311afdc65SVladimir Oltean 108411afdc65SVladimir Oltean return (gate_len_ns - VSC9959_TAS_MIN_GATE_LEN_NS) * PSEC_PER_NSEC; 108511afdc65SVladimir Oltean } 108611afdc65SVladimir Oltean 108755a515b1SVladimir Oltean /* Extract shortest continuous gate open intervals in ns for each traffic class 108855a515b1SVladimir Oltean * of a cyclic tc-taprio schedule. If a gate is always open, the duration is 108955a515b1SVladimir Oltean * considered U64_MAX. If the gate is always closed, it is considered 0. 109055a515b1SVladimir Oltean */ 109155a515b1SVladimir Oltean static void vsc9959_tas_min_gate_lengths(struct tc_taprio_qopt_offload *taprio, 109255a515b1SVladimir Oltean u64 min_gate_len[OCELOT_NUM_TC]) 109355a515b1SVladimir Oltean { 109455a515b1SVladimir Oltean struct tc_taprio_sched_entry *entry; 109555a515b1SVladimir Oltean u64 gate_len[OCELOT_NUM_TC]; 10967e4babffSVladimir Oltean u8 gates_ever_opened = 0; 109755a515b1SVladimir Oltean int tc, i, n; 109855a515b1SVladimir Oltean 109955a515b1SVladimir Oltean /* Initialize arrays */ 110055a515b1SVladimir Oltean for (tc = 0; tc < OCELOT_NUM_TC; tc++) { 110155a515b1SVladimir Oltean min_gate_len[tc] = U64_MAX; 110255a515b1SVladimir Oltean gate_len[tc] = 0; 110355a515b1SVladimir Oltean } 110455a515b1SVladimir Oltean 110555a515b1SVladimir Oltean /* If we don't have taprio, consider all gates as permanently open */ 110655a515b1SVladimir Oltean if (!taprio) 110755a515b1SVladimir Oltean return; 110855a515b1SVladimir Oltean 110955a515b1SVladimir Oltean n = taprio->num_entries; 111055a515b1SVladimir Oltean 111155a515b1SVladimir Oltean /* Walk through the gate list twice to determine the length 111255a515b1SVladimir Oltean * of consecutively open gates for a traffic class, including 111355a515b1SVladimir Oltean * open gates that wrap around. We are just interested in the 111455a515b1SVladimir Oltean * minimum window size, and this doesn't change what the 111555a515b1SVladimir Oltean * minimum is (if the gate never closes, min_gate_len will 111655a515b1SVladimir Oltean * remain U64_MAX). 111755a515b1SVladimir Oltean */ 111855a515b1SVladimir Oltean for (i = 0; i < 2 * n; i++) { 111955a515b1SVladimir Oltean entry = &taprio->entries[i % n]; 112055a515b1SVladimir Oltean 112155a515b1SVladimir Oltean for (tc = 0; tc < OCELOT_NUM_TC; tc++) { 112255a515b1SVladimir Oltean if (entry->gate_mask & BIT(tc)) { 112355a515b1SVladimir Oltean gate_len[tc] += entry->interval; 11247e4babffSVladimir Oltean gates_ever_opened |= BIT(tc); 112555a515b1SVladimir Oltean } else { 112655a515b1SVladimir Oltean /* Gate closes now, record a potential new 112755a515b1SVladimir Oltean * minimum and reinitialize length 112855a515b1SVladimir Oltean */ 11297e4babffSVladimir Oltean if (min_gate_len[tc] > gate_len[tc] && 11307e4babffSVladimir Oltean gate_len[tc]) 113155a515b1SVladimir Oltean min_gate_len[tc] = gate_len[tc]; 113255a515b1SVladimir Oltean gate_len[tc] = 0; 113355a515b1SVladimir Oltean } 113455a515b1SVladimir Oltean } 113555a515b1SVladimir Oltean } 11367e4babffSVladimir Oltean 11377e4babffSVladimir Oltean /* min_gate_len[tc] actually tracks minimum *open* gate time, so for 11387e4babffSVladimir Oltean * permanently closed gates, min_gate_len[tc] will still be U64_MAX. 11397e4babffSVladimir Oltean * Therefore they are currently indistinguishable from permanently 11407e4babffSVladimir Oltean * open gates. Overwrite the gate len with 0 when we know they're 11417e4babffSVladimir Oltean * actually permanently closed, i.e. after the loop above. 11427e4babffSVladimir Oltean */ 11437e4babffSVladimir Oltean for (tc = 0; tc < OCELOT_NUM_TC; tc++) 11447e4babffSVladimir Oltean if (!(gates_ever_opened & BIT(tc))) 11457e4babffSVladimir Oltean min_gate_len[tc] = 0; 114655a515b1SVladimir Oltean } 114755a515b1SVladimir Oltean 1148843794bbSVladimir Oltean /* ocelot_write_rix is a macro that concatenates QSYS_MAXSDU_CFG_* with _RSZ, 1149843794bbSVladimir Oltean * so we need to spell out the register access to each traffic class in helper 1150843794bbSVladimir Oltean * functions, to simplify callers 1151843794bbSVladimir Oltean */ 1152843794bbSVladimir Oltean static void vsc9959_port_qmaxsdu_set(struct ocelot *ocelot, int port, int tc, 1153843794bbSVladimir Oltean u32 max_sdu) 1154843794bbSVladimir Oltean { 1155843794bbSVladimir Oltean switch (tc) { 1156843794bbSVladimir Oltean case 0: 1157843794bbSVladimir Oltean ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_0, 1158843794bbSVladimir Oltean port); 1159843794bbSVladimir Oltean break; 1160843794bbSVladimir Oltean case 1: 1161843794bbSVladimir Oltean ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_1, 1162843794bbSVladimir Oltean port); 1163843794bbSVladimir Oltean break; 1164843794bbSVladimir Oltean case 2: 1165843794bbSVladimir Oltean ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_2, 1166843794bbSVladimir Oltean port); 1167843794bbSVladimir Oltean break; 1168843794bbSVladimir Oltean case 3: 1169843794bbSVladimir Oltean ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_3, 1170843794bbSVladimir Oltean port); 1171843794bbSVladimir Oltean break; 1172843794bbSVladimir Oltean case 4: 1173843794bbSVladimir Oltean ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_4, 1174843794bbSVladimir Oltean port); 1175843794bbSVladimir Oltean break; 1176843794bbSVladimir Oltean case 5: 1177843794bbSVladimir Oltean ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_5, 1178843794bbSVladimir Oltean port); 1179843794bbSVladimir Oltean break; 1180843794bbSVladimir Oltean case 6: 1181843794bbSVladimir Oltean ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_6, 1182843794bbSVladimir Oltean port); 1183843794bbSVladimir Oltean break; 1184843794bbSVladimir Oltean case 7: 1185843794bbSVladimir Oltean ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_7, 1186843794bbSVladimir Oltean port); 1187843794bbSVladimir Oltean break; 1188843794bbSVladimir Oltean } 1189843794bbSVladimir Oltean } 1190843794bbSVladimir Oltean 1191843794bbSVladimir Oltean static u32 vsc9959_port_qmaxsdu_get(struct ocelot *ocelot, int port, int tc) 1192843794bbSVladimir Oltean { 1193843794bbSVladimir Oltean switch (tc) { 1194843794bbSVladimir Oltean case 0: return ocelot_read_rix(ocelot, QSYS_QMAXSDU_CFG_0, port); 1195843794bbSVladimir Oltean case 1: return ocelot_read_rix(ocelot, QSYS_QMAXSDU_CFG_1, port); 1196843794bbSVladimir Oltean case 2: return ocelot_read_rix(ocelot, QSYS_QMAXSDU_CFG_2, port); 1197843794bbSVladimir Oltean case 3: return ocelot_read_rix(ocelot, QSYS_QMAXSDU_CFG_3, port); 1198843794bbSVladimir Oltean case 4: return ocelot_read_rix(ocelot, QSYS_QMAXSDU_CFG_4, port); 1199843794bbSVladimir Oltean case 5: return ocelot_read_rix(ocelot, QSYS_QMAXSDU_CFG_5, port); 1200843794bbSVladimir Oltean case 6: return ocelot_read_rix(ocelot, QSYS_QMAXSDU_CFG_6, port); 1201843794bbSVladimir Oltean case 7: return ocelot_read_rix(ocelot, QSYS_QMAXSDU_CFG_7, port); 1202843794bbSVladimir Oltean default: 1203843794bbSVladimir Oltean return 0; 1204843794bbSVladimir Oltean } 1205843794bbSVladimir Oltean } 1206843794bbSVladimir Oltean 12071712be05SVladimir Oltean static u32 vsc9959_tas_tc_max_sdu(struct tc_taprio_qopt_offload *taprio, int tc) 12081712be05SVladimir Oltean { 12091712be05SVladimir Oltean if (!taprio || !taprio->max_sdu[tc]) 12101712be05SVladimir Oltean return 0; 12111712be05SVladimir Oltean 12121712be05SVladimir Oltean return taprio->max_sdu[tc] + ETH_HLEN + 2 * VLAN_HLEN + ETH_FCS_LEN; 12131712be05SVladimir Oltean } 12141712be05SVladimir Oltean 121555a515b1SVladimir Oltean /* Update QSYS_PORT_MAX_SDU to make sure the static guard bands added by the 121655a515b1SVladimir Oltean * switch (see the ALWAYS_GUARD_BAND_SCH_Q comment) are correct at all MTU 121755a515b1SVladimir Oltean * values (the default value is 1518). Also, for traffic class windows smaller 121855a515b1SVladimir Oltean * than one MTU sized frame, update QSYS_QMAXSDU_CFG to enable oversized frame 121955a515b1SVladimir Oltean * dropping, such that these won't hang the port, as they will never be sent. 122055a515b1SVladimir Oltean */ 122155a515b1SVladimir Oltean static void vsc9959_tas_guard_bands_update(struct ocelot *ocelot, int port) 122255a515b1SVladimir Oltean { 122355a515b1SVladimir Oltean struct ocelot_port *ocelot_port = ocelot->ports[port]; 12241712be05SVladimir Oltean struct tc_taprio_qopt_offload *taprio; 122555a515b1SVladimir Oltean u64 min_gate_len[OCELOT_NUM_TC]; 122655a515b1SVladimir Oltean int speed, picos_per_byte; 122755a515b1SVladimir Oltean u64 needed_bit_time_ps; 122855a515b1SVladimir Oltean u32 val, maxlen; 122955a515b1SVladimir Oltean u8 tas_speed; 123055a515b1SVladimir Oltean int tc; 123155a515b1SVladimir Oltean 123255a515b1SVladimir Oltean lockdep_assert_held(&ocelot->tas_lock); 123355a515b1SVladimir Oltean 12341712be05SVladimir Oltean taprio = ocelot_port->taprio; 12351712be05SVladimir Oltean 123655a515b1SVladimir Oltean val = ocelot_read_rix(ocelot, QSYS_TAG_CONFIG, port); 123755a515b1SVladimir Oltean tas_speed = QSYS_TAG_CONFIG_LINK_SPEED_X(val); 123855a515b1SVladimir Oltean 123955a515b1SVladimir Oltean switch (tas_speed) { 124055a515b1SVladimir Oltean case OCELOT_SPEED_10: 124155a515b1SVladimir Oltean speed = SPEED_10; 124255a515b1SVladimir Oltean break; 124355a515b1SVladimir Oltean case OCELOT_SPEED_100: 124455a515b1SVladimir Oltean speed = SPEED_100; 124555a515b1SVladimir Oltean break; 124655a515b1SVladimir Oltean case OCELOT_SPEED_1000: 124755a515b1SVladimir Oltean speed = SPEED_1000; 124855a515b1SVladimir Oltean break; 124955a515b1SVladimir Oltean case OCELOT_SPEED_2500: 125055a515b1SVladimir Oltean speed = SPEED_2500; 125155a515b1SVladimir Oltean break; 125255a515b1SVladimir Oltean default: 125355a515b1SVladimir Oltean return; 125455a515b1SVladimir Oltean } 125555a515b1SVladimir Oltean 125655a515b1SVladimir Oltean picos_per_byte = (USEC_PER_SEC * 8) / speed; 125755a515b1SVladimir Oltean 125855a515b1SVladimir Oltean val = ocelot_port_readl(ocelot_port, DEV_MAC_MAXLEN_CFG); 125955a515b1SVladimir Oltean /* MAXLEN_CFG accounts automatically for VLAN. We need to include it 126055a515b1SVladimir Oltean * manually in the bit time calculation, plus the preamble and SFD. 126155a515b1SVladimir Oltean */ 126255a515b1SVladimir Oltean maxlen = val + 2 * VLAN_HLEN; 126355a515b1SVladimir Oltean /* Consider the standard Ethernet overhead of 8 octets preamble+SFD, 126455a515b1SVladimir Oltean * 4 octets FCS, 12 octets IFG. 126555a515b1SVladimir Oltean */ 126655a515b1SVladimir Oltean needed_bit_time_ps = (maxlen + 24) * picos_per_byte; 126755a515b1SVladimir Oltean 126855a515b1SVladimir Oltean dev_dbg(ocelot->dev, 126955a515b1SVladimir Oltean "port %d: max frame size %d needs %llu ps at speed %d\n", 127055a515b1SVladimir Oltean port, maxlen, needed_bit_time_ps, speed); 127155a515b1SVladimir Oltean 12721712be05SVladimir Oltean vsc9959_tas_min_gate_lengths(taprio, min_gate_len); 127355a515b1SVladimir Oltean 1274843794bbSVladimir Oltean mutex_lock(&ocelot->fwd_domain_lock); 1275843794bbSVladimir Oltean 127655a515b1SVladimir Oltean for (tc = 0; tc < OCELOT_NUM_TC; tc++) { 12771712be05SVladimir Oltean u32 requested_max_sdu = vsc9959_tas_tc_max_sdu(taprio, tc); 127811afdc65SVladimir Oltean u64 remaining_gate_len_ps; 127955a515b1SVladimir Oltean u32 max_sdu; 128055a515b1SVladimir Oltean 128111afdc65SVladimir Oltean remaining_gate_len_ps = 128211afdc65SVladimir Oltean vsc9959_tas_remaining_gate_len_ps(min_gate_len[tc]); 128311afdc65SVladimir Oltean 128411afdc65SVladimir Oltean if (remaining_gate_len_ps > needed_bit_time_ps) { 128555a515b1SVladimir Oltean /* Setting QMAXSDU_CFG to 0 disables oversized frame 128655a515b1SVladimir Oltean * dropping. 128755a515b1SVladimir Oltean */ 12881712be05SVladimir Oltean max_sdu = requested_max_sdu; 128955a515b1SVladimir Oltean dev_dbg(ocelot->dev, 129055a515b1SVladimir Oltean "port %d tc %d min gate len %llu" 129155a515b1SVladimir Oltean ", sending all frames\n", 129255a515b1SVladimir Oltean port, tc, min_gate_len[tc]); 129355a515b1SVladimir Oltean } else { 129455a515b1SVladimir Oltean /* If traffic class doesn't support a full MTU sized 129555a515b1SVladimir Oltean * frame, make sure to enable oversize frame dropping 129655a515b1SVladimir Oltean * for frames larger than the smallest that would fit. 129711afdc65SVladimir Oltean * 129811afdc65SVladimir Oltean * However, the exact same register, QSYS_QMAXSDU_CFG_*, 129911afdc65SVladimir Oltean * controls not only oversized frame dropping, but also 130011afdc65SVladimir Oltean * per-tc static guard band lengths, so it reduces the 130111afdc65SVladimir Oltean * useful gate interval length. Therefore, be careful 130211afdc65SVladimir Oltean * to calculate a guard band (and therefore max_sdu) 130311afdc65SVladimir Oltean * that still leaves 33 ns available in the time slot. 130455a515b1SVladimir Oltean */ 130511afdc65SVladimir Oltean max_sdu = div_u64(remaining_gate_len_ps, picos_per_byte); 130655a515b1SVladimir Oltean /* A TC gate may be completely closed, which is a 130755a515b1SVladimir Oltean * special case where all packets are oversized. 130855a515b1SVladimir Oltean * Any limit smaller than 64 octets accomplishes this 130955a515b1SVladimir Oltean */ 131055a515b1SVladimir Oltean if (!max_sdu) 131155a515b1SVladimir Oltean max_sdu = 1; 131255a515b1SVladimir Oltean /* Take L1 overhead into account, but just don't allow 131355a515b1SVladimir Oltean * max_sdu to go negative or to 0. Here we use 20 131455a515b1SVladimir Oltean * because QSYS_MAXSDU_CFG_* already counts the 4 FCS 131555a515b1SVladimir Oltean * octets as part of packet size. 131655a515b1SVladimir Oltean */ 131755a515b1SVladimir Oltean if (max_sdu > 20) 131855a515b1SVladimir Oltean max_sdu -= 20; 13191712be05SVladimir Oltean 13201712be05SVladimir Oltean if (requested_max_sdu && requested_max_sdu < max_sdu) 13211712be05SVladimir Oltean max_sdu = requested_max_sdu; 13221712be05SVladimir Oltean 132355a515b1SVladimir Oltean dev_info(ocelot->dev, 132455a515b1SVladimir Oltean "port %d tc %d min gate length %llu" 132555a515b1SVladimir Oltean " ns not enough for max frame size %d at %d" 132655a515b1SVladimir Oltean " Mbps, dropping frames over %d" 132755a515b1SVladimir Oltean " octets including FCS\n", 132855a515b1SVladimir Oltean port, tc, min_gate_len[tc], maxlen, speed, 132955a515b1SVladimir Oltean max_sdu); 133055a515b1SVladimir Oltean } 133155a515b1SVladimir Oltean 1332843794bbSVladimir Oltean vsc9959_port_qmaxsdu_set(ocelot, port, tc, max_sdu); 133355a515b1SVladimir Oltean } 133455a515b1SVladimir Oltean 133555a515b1SVladimir Oltean ocelot_write_rix(ocelot, maxlen, QSYS_PORT_MAX_SDU, port); 1336843794bbSVladimir Oltean 1337843794bbSVladimir Oltean ocelot->ops->cut_through_fwd(ocelot); 1338843794bbSVladimir Oltean 1339843794bbSVladimir Oltean mutex_unlock(&ocelot->fwd_domain_lock); 134055a515b1SVladimir Oltean } 134155a515b1SVladimir Oltean 1342de143c0eSXiaoliang Yang static void vsc9959_sched_speed_set(struct ocelot *ocelot, int port, 1343de143c0eSXiaoliang Yang u32 speed) 1344de143c0eSXiaoliang Yang { 134555a515b1SVladimir Oltean struct ocelot_port *ocelot_port = ocelot->ports[port]; 1346dba1e466SXiaoliang Yang u8 tas_speed; 1347dba1e466SXiaoliang Yang 1348dba1e466SXiaoliang Yang switch (speed) { 1349dba1e466SXiaoliang Yang case SPEED_10: 1350dba1e466SXiaoliang Yang tas_speed = OCELOT_SPEED_10; 1351dba1e466SXiaoliang Yang break; 1352dba1e466SXiaoliang Yang case SPEED_100: 1353dba1e466SXiaoliang Yang tas_speed = OCELOT_SPEED_100; 1354dba1e466SXiaoliang Yang break; 1355dba1e466SXiaoliang Yang case SPEED_1000: 1356dba1e466SXiaoliang Yang tas_speed = OCELOT_SPEED_1000; 1357dba1e466SXiaoliang Yang break; 1358dba1e466SXiaoliang Yang case SPEED_2500: 1359dba1e466SXiaoliang Yang tas_speed = OCELOT_SPEED_2500; 1360dba1e466SXiaoliang Yang break; 1361dba1e466SXiaoliang Yang default: 1362dba1e466SXiaoliang Yang tas_speed = OCELOT_SPEED_1000; 1363dba1e466SXiaoliang Yang break; 1364dba1e466SXiaoliang Yang } 1365dba1e466SXiaoliang Yang 1366a4bb481aSVladimir Oltean mutex_lock(&ocelot->tas_lock); 1367a4bb481aSVladimir Oltean 1368de143c0eSXiaoliang Yang ocelot_rmw_rix(ocelot, 1369dba1e466SXiaoliang Yang QSYS_TAG_CONFIG_LINK_SPEED(tas_speed), 1370de143c0eSXiaoliang Yang QSYS_TAG_CONFIG_LINK_SPEED_M, 1371de143c0eSXiaoliang Yang QSYS_TAG_CONFIG, port); 137255a515b1SVladimir Oltean 137355a515b1SVladimir Oltean if (ocelot_port->taprio) 137455a515b1SVladimir Oltean vsc9959_tas_guard_bands_update(ocelot, port); 137555a515b1SVladimir Oltean 137655a515b1SVladimir Oltean mutex_unlock(&ocelot->tas_lock); 1377de143c0eSXiaoliang Yang } 1378de143c0eSXiaoliang Yang 1379de143c0eSXiaoliang Yang static void vsc9959_new_base_time(struct ocelot *ocelot, ktime_t base_time, 1380de143c0eSXiaoliang Yang u64 cycle_time, 1381de143c0eSXiaoliang Yang struct timespec64 *new_base_ts) 1382de143c0eSXiaoliang Yang { 1383de143c0eSXiaoliang Yang struct timespec64 ts; 1384de143c0eSXiaoliang Yang ktime_t new_base_time; 1385de143c0eSXiaoliang Yang ktime_t current_time; 1386de143c0eSXiaoliang Yang 1387de143c0eSXiaoliang Yang ocelot_ptp_gettime64(&ocelot->ptp_info, &ts); 1388de143c0eSXiaoliang Yang current_time = timespec64_to_ktime(ts); 1389de143c0eSXiaoliang Yang new_base_time = base_time; 1390de143c0eSXiaoliang Yang 1391de143c0eSXiaoliang Yang if (base_time < current_time) { 1392de143c0eSXiaoliang Yang u64 nr_of_cycles = current_time - base_time; 1393de143c0eSXiaoliang Yang 1394de143c0eSXiaoliang Yang do_div(nr_of_cycles, cycle_time); 1395de143c0eSXiaoliang Yang new_base_time += cycle_time * (nr_of_cycles + 1); 1396de143c0eSXiaoliang Yang } 1397de143c0eSXiaoliang Yang 1398de143c0eSXiaoliang Yang *new_base_ts = ktime_to_timespec64(new_base_time); 1399de143c0eSXiaoliang Yang } 1400de143c0eSXiaoliang Yang 1401de143c0eSXiaoliang Yang static u32 vsc9959_tas_read_cfg_status(struct ocelot *ocelot) 1402de143c0eSXiaoliang Yang { 1403de143c0eSXiaoliang Yang return ocelot_read(ocelot, QSYS_TAS_PARAM_CFG_CTRL); 1404de143c0eSXiaoliang Yang } 1405de143c0eSXiaoliang Yang 1406de143c0eSXiaoliang Yang static void vsc9959_tas_gcl_set(struct ocelot *ocelot, const u32 gcl_ix, 1407de143c0eSXiaoliang Yang struct tc_taprio_sched_entry *entry) 1408de143c0eSXiaoliang Yang { 1409de143c0eSXiaoliang Yang ocelot_write(ocelot, 1410de143c0eSXiaoliang Yang QSYS_GCL_CFG_REG_1_GCL_ENTRY_NUM(gcl_ix) | 1411de143c0eSXiaoliang Yang QSYS_GCL_CFG_REG_1_GATE_STATE(entry->gate_mask), 1412de143c0eSXiaoliang Yang QSYS_GCL_CFG_REG_1); 1413de143c0eSXiaoliang Yang ocelot_write(ocelot, entry->interval, QSYS_GCL_CFG_REG_2); 1414de143c0eSXiaoliang Yang } 1415de143c0eSXiaoliang Yang 1416de143c0eSXiaoliang Yang static int vsc9959_qos_port_tas_set(struct ocelot *ocelot, int port, 1417de143c0eSXiaoliang Yang struct tc_taprio_qopt_offload *taprio) 1418de143c0eSXiaoliang Yang { 14198670dc33SXiaoliang Yang struct ocelot_port *ocelot_port = ocelot->ports[port]; 1420de143c0eSXiaoliang Yang struct timespec64 base_ts; 1421de143c0eSXiaoliang Yang int ret, i; 1422de143c0eSXiaoliang Yang u32 val; 1423de143c0eSXiaoliang Yang 14248670dc33SXiaoliang Yang mutex_lock(&ocelot->tas_lock); 14258670dc33SXiaoliang Yang 1426de143c0eSXiaoliang Yang if (!taprio->enable) { 1427d68a373bSVladimir Oltean ocelot_rmw_rix(ocelot, 0, QSYS_TAG_CONFIG_ENABLE, 1428de143c0eSXiaoliang Yang QSYS_TAG_CONFIG, port); 1429de143c0eSXiaoliang Yang 14301c9017e4SVladimir Oltean taprio_offload_free(ocelot_port->taprio); 14311c9017e4SVladimir Oltean ocelot_port->taprio = NULL; 14321c9017e4SVladimir Oltean 143355a515b1SVladimir Oltean vsc9959_tas_guard_bands_update(ocelot, port); 143455a515b1SVladimir Oltean 14358670dc33SXiaoliang Yang mutex_unlock(&ocelot->tas_lock); 1436de143c0eSXiaoliang Yang return 0; 1437de143c0eSXiaoliang Yang } 1438de143c0eSXiaoliang Yang 1439de143c0eSXiaoliang Yang if (taprio->cycle_time > NSEC_PER_SEC || 14408670dc33SXiaoliang Yang taprio->cycle_time_extension >= NSEC_PER_SEC) { 14418670dc33SXiaoliang Yang ret = -EINVAL; 14428670dc33SXiaoliang Yang goto err; 14438670dc33SXiaoliang Yang } 1444de143c0eSXiaoliang Yang 14458670dc33SXiaoliang Yang if (taprio->num_entries > VSC9959_TAS_GCL_ENTRY_MAX) { 14468670dc33SXiaoliang Yang ret = -ERANGE; 14478670dc33SXiaoliang Yang goto err; 14488670dc33SXiaoliang Yang } 1449de143c0eSXiaoliang Yang 1450297c4de6SMichael Walle /* Enable guard band. The switch will schedule frames without taking 1451297c4de6SMichael Walle * their length into account. Thus we'll always need to enable the 1452297c4de6SMichael Walle * guard band which reserves the time of a maximum sized frame at the 1453297c4de6SMichael Walle * end of the time window. 1454297c4de6SMichael Walle * 1455297c4de6SMichael Walle * Although the ALWAYS_GUARD_BAND_SCH_Q bit is global for all ports, we 1456297c4de6SMichael Walle * need to set PORT_NUM, because subsequent writes to PARAM_CFG_REG_n 1457297c4de6SMichael Walle * operate on the port number. 1458316bcffeSXiaoliang Yang */ 1459297c4de6SMichael Walle ocelot_rmw(ocelot, QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM(port) | 1460297c4de6SMichael Walle QSYS_TAS_PARAM_CFG_CTRL_ALWAYS_GUARD_BAND_SCH_Q, 1461de143c0eSXiaoliang Yang QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM_M | 1462de143c0eSXiaoliang Yang QSYS_TAS_PARAM_CFG_CTRL_ALWAYS_GUARD_BAND_SCH_Q, 1463de143c0eSXiaoliang Yang QSYS_TAS_PARAM_CFG_CTRL); 1464de143c0eSXiaoliang Yang 1465de143c0eSXiaoliang Yang /* Hardware errata - Admin config could not be overwritten if 1466de143c0eSXiaoliang Yang * config is pending, need reset the TAS module 1467de143c0eSXiaoliang Yang */ 1468de143c0eSXiaoliang Yang val = ocelot_read(ocelot, QSYS_PARAM_STATUS_REG_8); 14698670dc33SXiaoliang Yang if (val & QSYS_PARAM_STATUS_REG_8_CONFIG_PENDING) { 14708670dc33SXiaoliang Yang ret = -EBUSY; 14718670dc33SXiaoliang Yang goto err; 14728670dc33SXiaoliang Yang } 1473de143c0eSXiaoliang Yang 1474de143c0eSXiaoliang Yang ocelot_rmw_rix(ocelot, 1475de143c0eSXiaoliang Yang QSYS_TAG_CONFIG_ENABLE | 1476de143c0eSXiaoliang Yang QSYS_TAG_CONFIG_INIT_GATE_STATE(0xFF) | 1477de143c0eSXiaoliang Yang QSYS_TAG_CONFIG_SCH_TRAFFIC_QUEUES(0xFF), 1478de143c0eSXiaoliang Yang QSYS_TAG_CONFIG_ENABLE | 1479de143c0eSXiaoliang Yang QSYS_TAG_CONFIG_INIT_GATE_STATE_M | 1480de143c0eSXiaoliang Yang QSYS_TAG_CONFIG_SCH_TRAFFIC_QUEUES_M, 1481de143c0eSXiaoliang Yang QSYS_TAG_CONFIG, port); 1482de143c0eSXiaoliang Yang 1483de143c0eSXiaoliang Yang vsc9959_new_base_time(ocelot, taprio->base_time, 1484de143c0eSXiaoliang Yang taprio->cycle_time, &base_ts); 1485de143c0eSXiaoliang Yang ocelot_write(ocelot, base_ts.tv_nsec, QSYS_PARAM_CFG_REG_1); 1486de143c0eSXiaoliang Yang ocelot_write(ocelot, lower_32_bits(base_ts.tv_sec), QSYS_PARAM_CFG_REG_2); 1487de143c0eSXiaoliang Yang val = upper_32_bits(base_ts.tv_sec); 1488de143c0eSXiaoliang Yang ocelot_write(ocelot, 1489de143c0eSXiaoliang Yang QSYS_PARAM_CFG_REG_3_BASE_TIME_SEC_MSB(val) | 1490de143c0eSXiaoliang Yang QSYS_PARAM_CFG_REG_3_LIST_LENGTH(taprio->num_entries), 1491de143c0eSXiaoliang Yang QSYS_PARAM_CFG_REG_3); 1492de143c0eSXiaoliang Yang ocelot_write(ocelot, taprio->cycle_time, QSYS_PARAM_CFG_REG_4); 1493de143c0eSXiaoliang Yang ocelot_write(ocelot, taprio->cycle_time_extension, QSYS_PARAM_CFG_REG_5); 1494de143c0eSXiaoliang Yang 1495de143c0eSXiaoliang Yang for (i = 0; i < taprio->num_entries; i++) 1496de143c0eSXiaoliang Yang vsc9959_tas_gcl_set(ocelot, i, &taprio->entries[i]); 1497de143c0eSXiaoliang Yang 1498de143c0eSXiaoliang Yang ocelot_rmw(ocelot, QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE, 1499de143c0eSXiaoliang Yang QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE, 1500de143c0eSXiaoliang Yang QSYS_TAS_PARAM_CFG_CTRL); 1501de143c0eSXiaoliang Yang 1502de143c0eSXiaoliang Yang ret = readx_poll_timeout(vsc9959_tas_read_cfg_status, ocelot, val, 1503de143c0eSXiaoliang Yang !(val & QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE), 1504de143c0eSXiaoliang Yang 10, 100000); 15051c9017e4SVladimir Oltean if (ret) 15061c9017e4SVladimir Oltean goto err; 15071c9017e4SVladimir Oltean 15081c9017e4SVladimir Oltean ocelot_port->taprio = taprio_offload_get(taprio); 150955a515b1SVladimir Oltean vsc9959_tas_guard_bands_update(ocelot, port); 1510de143c0eSXiaoliang Yang 15118670dc33SXiaoliang Yang err: 15128670dc33SXiaoliang Yang mutex_unlock(&ocelot->tas_lock); 15138670dc33SXiaoliang Yang 1514de143c0eSXiaoliang Yang return ret; 1515de143c0eSXiaoliang Yang } 1516de143c0eSXiaoliang Yang 15178670dc33SXiaoliang Yang static void vsc9959_tas_clock_adjust(struct ocelot *ocelot) 15188670dc33SXiaoliang Yang { 15191c9017e4SVladimir Oltean struct tc_taprio_qopt_offload *taprio; 15208670dc33SXiaoliang Yang struct ocelot_port *ocelot_port; 15218670dc33SXiaoliang Yang struct timespec64 base_ts; 15228670dc33SXiaoliang Yang int port; 15238670dc33SXiaoliang Yang u32 val; 15248670dc33SXiaoliang Yang 15258670dc33SXiaoliang Yang mutex_lock(&ocelot->tas_lock); 15268670dc33SXiaoliang Yang 15278670dc33SXiaoliang Yang for (port = 0; port < ocelot->num_phys_ports; port++) { 15281c9017e4SVladimir Oltean ocelot_port = ocelot->ports[port]; 15291c9017e4SVladimir Oltean taprio = ocelot_port->taprio; 15301c9017e4SVladimir Oltean if (!taprio) 15318670dc33SXiaoliang Yang continue; 15328670dc33SXiaoliang Yang 15338670dc33SXiaoliang Yang ocelot_rmw(ocelot, 15348670dc33SXiaoliang Yang QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM(port), 15358670dc33SXiaoliang Yang QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM_M, 15368670dc33SXiaoliang Yang QSYS_TAS_PARAM_CFG_CTRL); 15378670dc33SXiaoliang Yang 1538d68a373bSVladimir Oltean /* Disable time-aware shaper */ 1539d68a373bSVladimir Oltean ocelot_rmw_rix(ocelot, 0, QSYS_TAG_CONFIG_ENABLE, 15408670dc33SXiaoliang Yang QSYS_TAG_CONFIG, port); 15418670dc33SXiaoliang Yang 15421c9017e4SVladimir Oltean vsc9959_new_base_time(ocelot, taprio->base_time, 15431c9017e4SVladimir Oltean taprio->cycle_time, &base_ts); 15448670dc33SXiaoliang Yang 15458670dc33SXiaoliang Yang ocelot_write(ocelot, base_ts.tv_nsec, QSYS_PARAM_CFG_REG_1); 15468670dc33SXiaoliang Yang ocelot_write(ocelot, lower_32_bits(base_ts.tv_sec), 15478670dc33SXiaoliang Yang QSYS_PARAM_CFG_REG_2); 15488670dc33SXiaoliang Yang val = upper_32_bits(base_ts.tv_sec); 15498670dc33SXiaoliang Yang ocelot_rmw(ocelot, 15508670dc33SXiaoliang Yang QSYS_PARAM_CFG_REG_3_BASE_TIME_SEC_MSB(val), 15518670dc33SXiaoliang Yang QSYS_PARAM_CFG_REG_3_BASE_TIME_SEC_MSB_M, 15528670dc33SXiaoliang Yang QSYS_PARAM_CFG_REG_3); 15538670dc33SXiaoliang Yang 15548670dc33SXiaoliang Yang ocelot_rmw(ocelot, QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE, 15558670dc33SXiaoliang Yang QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE, 15568670dc33SXiaoliang Yang QSYS_TAS_PARAM_CFG_CTRL); 15578670dc33SXiaoliang Yang 1558d68a373bSVladimir Oltean /* Re-enable time-aware shaper */ 1559d68a373bSVladimir Oltean ocelot_rmw_rix(ocelot, QSYS_TAG_CONFIG_ENABLE, 15608670dc33SXiaoliang Yang QSYS_TAG_CONFIG_ENABLE, 15618670dc33SXiaoliang Yang QSYS_TAG_CONFIG, port); 15628670dc33SXiaoliang Yang } 15638670dc33SXiaoliang Yang mutex_unlock(&ocelot->tas_lock); 15648670dc33SXiaoliang Yang } 15658670dc33SXiaoliang Yang 15660fbabf87SXiaoliang Yang static int vsc9959_qos_port_cbs_set(struct dsa_switch *ds, int port, 15670fbabf87SXiaoliang Yang struct tc_cbs_qopt_offload *cbs_qopt) 15680fbabf87SXiaoliang Yang { 15690fbabf87SXiaoliang Yang struct ocelot *ocelot = ds->priv; 15700fbabf87SXiaoliang Yang int port_ix = port * 8 + cbs_qopt->queue; 15710fbabf87SXiaoliang Yang u32 rate, burst; 15720fbabf87SXiaoliang Yang 15730fbabf87SXiaoliang Yang if (cbs_qopt->queue >= ds->num_tx_queues) 15740fbabf87SXiaoliang Yang return -EINVAL; 15750fbabf87SXiaoliang Yang 15760fbabf87SXiaoliang Yang if (!cbs_qopt->enable) { 15770fbabf87SXiaoliang Yang ocelot_write_gix(ocelot, QSYS_CIR_CFG_CIR_RATE(0) | 15780fbabf87SXiaoliang Yang QSYS_CIR_CFG_CIR_BURST(0), 15790fbabf87SXiaoliang Yang QSYS_CIR_CFG, port_ix); 15800fbabf87SXiaoliang Yang 15810fbabf87SXiaoliang Yang ocelot_rmw_gix(ocelot, 0, QSYS_SE_CFG_SE_AVB_ENA, 15820fbabf87SXiaoliang Yang QSYS_SE_CFG, port_ix); 15830fbabf87SXiaoliang Yang 15840fbabf87SXiaoliang Yang return 0; 15850fbabf87SXiaoliang Yang } 15860fbabf87SXiaoliang Yang 15870fbabf87SXiaoliang Yang /* Rate unit is 100 kbps */ 15880fbabf87SXiaoliang Yang rate = DIV_ROUND_UP(cbs_qopt->idleslope, 100); 15890fbabf87SXiaoliang Yang /* Avoid using zero rate */ 15900fbabf87SXiaoliang Yang rate = clamp_t(u32, rate, 1, GENMASK(14, 0)); 15910fbabf87SXiaoliang Yang /* Burst unit is 4kB */ 15920fbabf87SXiaoliang Yang burst = DIV_ROUND_UP(cbs_qopt->hicredit, 4096); 15930fbabf87SXiaoliang Yang /* Avoid using zero burst size */ 1594b014d043SColin Ian King burst = clamp_t(u32, burst, 1, GENMASK(5, 0)); 15950fbabf87SXiaoliang Yang ocelot_write_gix(ocelot, 15960fbabf87SXiaoliang Yang QSYS_CIR_CFG_CIR_RATE(rate) | 15970fbabf87SXiaoliang Yang QSYS_CIR_CFG_CIR_BURST(burst), 15980fbabf87SXiaoliang Yang QSYS_CIR_CFG, 15990fbabf87SXiaoliang Yang port_ix); 16000fbabf87SXiaoliang Yang 16010fbabf87SXiaoliang Yang ocelot_rmw_gix(ocelot, 16020fbabf87SXiaoliang Yang QSYS_SE_CFG_SE_FRM_MODE(0) | 16030fbabf87SXiaoliang Yang QSYS_SE_CFG_SE_AVB_ENA, 16040fbabf87SXiaoliang Yang QSYS_SE_CFG_SE_AVB_ENA | 16050fbabf87SXiaoliang Yang QSYS_SE_CFG_SE_FRM_MODE_M, 16060fbabf87SXiaoliang Yang QSYS_SE_CFG, 16070fbabf87SXiaoliang Yang port_ix); 16080fbabf87SXiaoliang Yang 16090fbabf87SXiaoliang Yang return 0; 16100fbabf87SXiaoliang Yang } 16110fbabf87SXiaoliang Yang 16121712be05SVladimir Oltean static int vsc9959_qos_query_caps(struct tc_query_caps_base *base) 16131712be05SVladimir Oltean { 16141712be05SVladimir Oltean switch (base->type) { 16151712be05SVladimir Oltean case TC_SETUP_QDISC_TAPRIO: { 16161712be05SVladimir Oltean struct tc_taprio_caps *caps = base->caps; 16171712be05SVladimir Oltean 16181712be05SVladimir Oltean caps->supports_queue_max_sdu = true; 16191712be05SVladimir Oltean 16201712be05SVladimir Oltean return 0; 16211712be05SVladimir Oltean } 16221712be05SVladimir Oltean default: 16231712be05SVladimir Oltean return -EOPNOTSUPP; 16241712be05SVladimir Oltean } 16251712be05SVladimir Oltean } 16261712be05SVladimir Oltean 1627de143c0eSXiaoliang Yang static int vsc9959_port_setup_tc(struct dsa_switch *ds, int port, 1628de143c0eSXiaoliang Yang enum tc_setup_type type, 1629de143c0eSXiaoliang Yang void *type_data) 1630de143c0eSXiaoliang Yang { 1631de143c0eSXiaoliang Yang struct ocelot *ocelot = ds->priv; 1632de143c0eSXiaoliang Yang 1633de143c0eSXiaoliang Yang switch (type) { 16341712be05SVladimir Oltean case TC_QUERY_CAPS: 16351712be05SVladimir Oltean return vsc9959_qos_query_caps(type_data); 1636de143c0eSXiaoliang Yang case TC_SETUP_QDISC_TAPRIO: 1637de143c0eSXiaoliang Yang return vsc9959_qos_port_tas_set(ocelot, port, type_data); 16380fbabf87SXiaoliang Yang case TC_SETUP_QDISC_CBS: 16390fbabf87SXiaoliang Yang return vsc9959_qos_port_cbs_set(ds, port, type_data); 1640de143c0eSXiaoliang Yang default: 1641de143c0eSXiaoliang Yang return -EOPNOTSUPP; 1642de143c0eSXiaoliang Yang } 1643de143c0eSXiaoliang Yang } 1644de143c0eSXiaoliang Yang 16457d4b564dSXiaoliang Yang #define VSC9959_PSFP_SFID_MAX 175 16467d4b564dSXiaoliang Yang #define VSC9959_PSFP_GATE_ID_MAX 183 164776c13edeSXiaoliang Yang #define VSC9959_PSFP_POLICER_BASE 63 16487d4b564dSXiaoliang Yang #define VSC9959_PSFP_POLICER_MAX 383 164923ae3a78SXiaoliang Yang #define VSC9959_PSFP_GATE_LIST_NUM 4 165023ae3a78SXiaoliang Yang #define VSC9959_PSFP_GATE_CYCLETIME_MIN 5000 16517d4b564dSXiaoliang Yang 16527d4b564dSXiaoliang Yang struct felix_stream { 16537d4b564dSXiaoliang Yang struct list_head list; 16547d4b564dSXiaoliang Yang unsigned long id; 1655a7e13edfSXiaoliang Yang bool dummy; 1656a7e13edfSXiaoliang Yang int ports; 1657a7e13edfSXiaoliang Yang int port; 16587d4b564dSXiaoliang Yang u8 dmac[ETH_ALEN]; 16597d4b564dSXiaoliang Yang u16 vid; 16607d4b564dSXiaoliang Yang s8 prio; 16617d4b564dSXiaoliang Yang u8 sfid_valid; 16627d4b564dSXiaoliang Yang u8 ssid_valid; 16637d4b564dSXiaoliang Yang u32 sfid; 16647d4b564dSXiaoliang Yang u32 ssid; 16657d4b564dSXiaoliang Yang }; 16667d4b564dSXiaoliang Yang 166725027c84SVladimir Oltean struct felix_stream_filter_counters { 166825027c84SVladimir Oltean u64 match; 166925027c84SVladimir Oltean u64 not_pass_gate; 167025027c84SVladimir Oltean u64 not_pass_sdu; 167125027c84SVladimir Oltean u64 red; 167225027c84SVladimir Oltean }; 167325027c84SVladimir Oltean 16747d4b564dSXiaoliang Yang struct felix_stream_filter { 167525027c84SVladimir Oltean struct felix_stream_filter_counters stats; 16767d4b564dSXiaoliang Yang struct list_head list; 16777d4b564dSXiaoliang Yang refcount_t refcount; 16787d4b564dSXiaoliang Yang u32 index; 16797d4b564dSXiaoliang Yang u8 enable; 1680a7e13edfSXiaoliang Yang int portmask; 16817d4b564dSXiaoliang Yang u8 sg_valid; 16827d4b564dSXiaoliang Yang u32 sgid; 16837d4b564dSXiaoliang Yang u8 fm_valid; 16847d4b564dSXiaoliang Yang u32 fmid; 16857d4b564dSXiaoliang Yang u8 prio_valid; 16867d4b564dSXiaoliang Yang u8 prio; 16877d4b564dSXiaoliang Yang u32 maxsdu; 16887d4b564dSXiaoliang Yang }; 16897d4b564dSXiaoliang Yang 169023ae3a78SXiaoliang Yang struct felix_stream_gate { 169123ae3a78SXiaoliang Yang u32 index; 169223ae3a78SXiaoliang Yang u8 enable; 169323ae3a78SXiaoliang Yang u8 ipv_valid; 169423ae3a78SXiaoliang Yang u8 init_ipv; 169523ae3a78SXiaoliang Yang u64 basetime; 169623ae3a78SXiaoliang Yang u64 cycletime; 169723ae3a78SXiaoliang Yang u64 cycletime_ext; 169823ae3a78SXiaoliang Yang u32 num_entries; 1699dcad856fSkernel test robot struct action_gate_entry entries[]; 170023ae3a78SXiaoliang Yang }; 170123ae3a78SXiaoliang Yang 170223ae3a78SXiaoliang Yang struct felix_stream_gate_entry { 170323ae3a78SXiaoliang Yang struct list_head list; 170423ae3a78SXiaoliang Yang refcount_t refcount; 170523ae3a78SXiaoliang Yang u32 index; 170623ae3a78SXiaoliang Yang }; 170723ae3a78SXiaoliang Yang 17087d4b564dSXiaoliang Yang static int vsc9959_stream_identify(struct flow_cls_offload *f, 17097d4b564dSXiaoliang Yang struct felix_stream *stream) 17107d4b564dSXiaoliang Yang { 17117d4b564dSXiaoliang Yang struct flow_rule *rule = flow_cls_offload_flow_rule(f); 17127d4b564dSXiaoliang Yang struct flow_dissector *dissector = rule->match.dissector; 17137d4b564dSXiaoliang Yang 17147d4b564dSXiaoliang Yang if (dissector->used_keys & 17157d4b564dSXiaoliang Yang ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) | 17167d4b564dSXiaoliang Yang BIT(FLOW_DISSECTOR_KEY_BASIC) | 17177d4b564dSXiaoliang Yang BIT(FLOW_DISSECTOR_KEY_VLAN) | 17187d4b564dSXiaoliang Yang BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS))) 17197d4b564dSXiaoliang Yang return -EOPNOTSUPP; 17207d4b564dSXiaoliang Yang 17217d4b564dSXiaoliang Yang if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) { 17227d4b564dSXiaoliang Yang struct flow_match_eth_addrs match; 17237d4b564dSXiaoliang Yang 17247d4b564dSXiaoliang Yang flow_rule_match_eth_addrs(rule, &match); 17257d4b564dSXiaoliang Yang ether_addr_copy(stream->dmac, match.key->dst); 17267d4b564dSXiaoliang Yang if (!is_zero_ether_addr(match.mask->src)) 17277d4b564dSXiaoliang Yang return -EOPNOTSUPP; 17287d4b564dSXiaoliang Yang } else { 17297d4b564dSXiaoliang Yang return -EOPNOTSUPP; 17307d4b564dSXiaoliang Yang } 17317d4b564dSXiaoliang Yang 17327d4b564dSXiaoliang Yang if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) { 17337d4b564dSXiaoliang Yang struct flow_match_vlan match; 17347d4b564dSXiaoliang Yang 17357d4b564dSXiaoliang Yang flow_rule_match_vlan(rule, &match); 17367d4b564dSXiaoliang Yang if (match.mask->vlan_priority) 17377d4b564dSXiaoliang Yang stream->prio = match.key->vlan_priority; 17387d4b564dSXiaoliang Yang else 17397d4b564dSXiaoliang Yang stream->prio = -1; 17407d4b564dSXiaoliang Yang 17417d4b564dSXiaoliang Yang if (!match.mask->vlan_id) 17427d4b564dSXiaoliang Yang return -EOPNOTSUPP; 17437d4b564dSXiaoliang Yang stream->vid = match.key->vlan_id; 17447d4b564dSXiaoliang Yang } else { 17457d4b564dSXiaoliang Yang return -EOPNOTSUPP; 17467d4b564dSXiaoliang Yang } 17477d4b564dSXiaoliang Yang 17487d4b564dSXiaoliang Yang stream->id = f->cookie; 17497d4b564dSXiaoliang Yang 17507d4b564dSXiaoliang Yang return 0; 17517d4b564dSXiaoliang Yang } 17527d4b564dSXiaoliang Yang 17537d4b564dSXiaoliang Yang static int vsc9959_mact_stream_set(struct ocelot *ocelot, 17547d4b564dSXiaoliang Yang struct felix_stream *stream, 17557d4b564dSXiaoliang Yang struct netlink_ext_ack *extack) 17567d4b564dSXiaoliang Yang { 17577d4b564dSXiaoliang Yang enum macaccess_entry_type type; 17587d4b564dSXiaoliang Yang int ret, sfid, ssid; 17597d4b564dSXiaoliang Yang u32 vid, dst_idx; 17607d4b564dSXiaoliang Yang u8 mac[ETH_ALEN]; 17617d4b564dSXiaoliang Yang 17627d4b564dSXiaoliang Yang ether_addr_copy(mac, stream->dmac); 17637d4b564dSXiaoliang Yang vid = stream->vid; 17647d4b564dSXiaoliang Yang 17657d4b564dSXiaoliang Yang /* Stream identification desn't support to add a stream with non 17667d4b564dSXiaoliang Yang * existent MAC (The MAC entry has not been learned in MAC table). 17677d4b564dSXiaoliang Yang */ 17687d4b564dSXiaoliang Yang ret = ocelot_mact_lookup(ocelot, &dst_idx, mac, vid, &type); 17697d4b564dSXiaoliang Yang if (ret) { 17707d4b564dSXiaoliang Yang if (extack) 17717d4b564dSXiaoliang Yang NL_SET_ERR_MSG_MOD(extack, "Stream is not learned in MAC table"); 17727d4b564dSXiaoliang Yang return -EOPNOTSUPP; 17737d4b564dSXiaoliang Yang } 17747d4b564dSXiaoliang Yang 17757d4b564dSXiaoliang Yang if ((stream->sfid_valid || stream->ssid_valid) && 17767d4b564dSXiaoliang Yang type == ENTRYTYPE_NORMAL) 17777d4b564dSXiaoliang Yang type = ENTRYTYPE_LOCKED; 17787d4b564dSXiaoliang Yang 17797d4b564dSXiaoliang Yang sfid = stream->sfid_valid ? stream->sfid : -1; 17807d4b564dSXiaoliang Yang ssid = stream->ssid_valid ? stream->ssid : -1; 17817d4b564dSXiaoliang Yang 17827d4b564dSXiaoliang Yang ret = ocelot_mact_learn_streamdata(ocelot, dst_idx, mac, vid, type, 17837d4b564dSXiaoliang Yang sfid, ssid); 17847d4b564dSXiaoliang Yang 17857d4b564dSXiaoliang Yang return ret; 17867d4b564dSXiaoliang Yang } 17877d4b564dSXiaoliang Yang 17887d4b564dSXiaoliang Yang static struct felix_stream * 17897d4b564dSXiaoliang Yang vsc9959_stream_table_lookup(struct list_head *stream_list, 17907d4b564dSXiaoliang Yang struct felix_stream *stream) 17917d4b564dSXiaoliang Yang { 17927d4b564dSXiaoliang Yang struct felix_stream *tmp; 17937d4b564dSXiaoliang Yang 17947d4b564dSXiaoliang Yang list_for_each_entry(tmp, stream_list, list) 17957d4b564dSXiaoliang Yang if (ether_addr_equal(tmp->dmac, stream->dmac) && 17967d4b564dSXiaoliang Yang tmp->vid == stream->vid) 17977d4b564dSXiaoliang Yang return tmp; 17987d4b564dSXiaoliang Yang 17997d4b564dSXiaoliang Yang return NULL; 18007d4b564dSXiaoliang Yang } 18017d4b564dSXiaoliang Yang 18027d4b564dSXiaoliang Yang static int vsc9959_stream_table_add(struct ocelot *ocelot, 18037d4b564dSXiaoliang Yang struct list_head *stream_list, 18047d4b564dSXiaoliang Yang struct felix_stream *stream, 18057d4b564dSXiaoliang Yang struct netlink_ext_ack *extack) 18067d4b564dSXiaoliang Yang { 18077d4b564dSXiaoliang Yang struct felix_stream *stream_entry; 18087d4b564dSXiaoliang Yang int ret; 18097d4b564dSXiaoliang Yang 1810e44aecc7SYihao Han stream_entry = kmemdup(stream, sizeof(*stream_entry), GFP_KERNEL); 18117d4b564dSXiaoliang Yang if (!stream_entry) 18127d4b564dSXiaoliang Yang return -ENOMEM; 18137d4b564dSXiaoliang Yang 1814a7e13edfSXiaoliang Yang if (!stream->dummy) { 18157d4b564dSXiaoliang Yang ret = vsc9959_mact_stream_set(ocelot, stream_entry, extack); 18167d4b564dSXiaoliang Yang if (ret) { 18177d4b564dSXiaoliang Yang kfree(stream_entry); 18187d4b564dSXiaoliang Yang return ret; 18197d4b564dSXiaoliang Yang } 1820a7e13edfSXiaoliang Yang } 18217d4b564dSXiaoliang Yang 18227d4b564dSXiaoliang Yang list_add_tail(&stream_entry->list, stream_list); 18237d4b564dSXiaoliang Yang 18247d4b564dSXiaoliang Yang return 0; 18257d4b564dSXiaoliang Yang } 18267d4b564dSXiaoliang Yang 18277d4b564dSXiaoliang Yang static struct felix_stream * 18287d4b564dSXiaoliang Yang vsc9959_stream_table_get(struct list_head *stream_list, unsigned long id) 18297d4b564dSXiaoliang Yang { 18307d4b564dSXiaoliang Yang struct felix_stream *tmp; 18317d4b564dSXiaoliang Yang 18327d4b564dSXiaoliang Yang list_for_each_entry(tmp, stream_list, list) 18337d4b564dSXiaoliang Yang if (tmp->id == id) 18347d4b564dSXiaoliang Yang return tmp; 18357d4b564dSXiaoliang Yang 18367d4b564dSXiaoliang Yang return NULL; 18377d4b564dSXiaoliang Yang } 18387d4b564dSXiaoliang Yang 18397d4b564dSXiaoliang Yang static void vsc9959_stream_table_del(struct ocelot *ocelot, 18407d4b564dSXiaoliang Yang struct felix_stream *stream) 18417d4b564dSXiaoliang Yang { 1842a7e13edfSXiaoliang Yang if (!stream->dummy) 18437d4b564dSXiaoliang Yang vsc9959_mact_stream_set(ocelot, stream, NULL); 18447d4b564dSXiaoliang Yang 18457d4b564dSXiaoliang Yang list_del(&stream->list); 18467d4b564dSXiaoliang Yang kfree(stream); 18477d4b564dSXiaoliang Yang } 18487d4b564dSXiaoliang Yang 18497d4b564dSXiaoliang Yang static u32 vsc9959_sfi_access_status(struct ocelot *ocelot) 18507d4b564dSXiaoliang Yang { 18517d4b564dSXiaoliang Yang return ocelot_read(ocelot, ANA_TABLES_SFIDACCESS); 18527d4b564dSXiaoliang Yang } 18537d4b564dSXiaoliang Yang 18547d4b564dSXiaoliang Yang static int vsc9959_psfp_sfi_set(struct ocelot *ocelot, 18557d4b564dSXiaoliang Yang struct felix_stream_filter *sfi) 18567d4b564dSXiaoliang Yang { 18577d4b564dSXiaoliang Yang u32 val; 18587d4b564dSXiaoliang Yang 18597d4b564dSXiaoliang Yang if (sfi->index > VSC9959_PSFP_SFID_MAX) 18607d4b564dSXiaoliang Yang return -EINVAL; 18617d4b564dSXiaoliang Yang 18627d4b564dSXiaoliang Yang if (!sfi->enable) { 18637d4b564dSXiaoliang Yang ocelot_write(ocelot, ANA_TABLES_SFIDTIDX_SFID_INDEX(sfi->index), 18647d4b564dSXiaoliang Yang ANA_TABLES_SFIDTIDX); 18657d4b564dSXiaoliang Yang 18667d4b564dSXiaoliang Yang val = ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(SFIDACCESS_CMD_WRITE); 18677d4b564dSXiaoliang Yang ocelot_write(ocelot, val, ANA_TABLES_SFIDACCESS); 18687d4b564dSXiaoliang Yang 18697d4b564dSXiaoliang Yang return readx_poll_timeout(vsc9959_sfi_access_status, ocelot, val, 18707d4b564dSXiaoliang Yang (!ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(val)), 18717d4b564dSXiaoliang Yang 10, 100000); 18727d4b564dSXiaoliang Yang } 18737d4b564dSXiaoliang Yang 18747d4b564dSXiaoliang Yang if (sfi->sgid > VSC9959_PSFP_GATE_ID_MAX || 18757d4b564dSXiaoliang Yang sfi->fmid > VSC9959_PSFP_POLICER_MAX) 18767d4b564dSXiaoliang Yang return -EINVAL; 18777d4b564dSXiaoliang Yang 18787d4b564dSXiaoliang Yang ocelot_write(ocelot, 18797d4b564dSXiaoliang Yang (sfi->sg_valid ? ANA_TABLES_SFIDTIDX_SGID_VALID : 0) | 18807d4b564dSXiaoliang Yang ANA_TABLES_SFIDTIDX_SGID(sfi->sgid) | 18817d4b564dSXiaoliang Yang (sfi->fm_valid ? ANA_TABLES_SFIDTIDX_POL_ENA : 0) | 18827d4b564dSXiaoliang Yang ANA_TABLES_SFIDTIDX_POL_IDX(sfi->fmid) | 18837d4b564dSXiaoliang Yang ANA_TABLES_SFIDTIDX_SFID_INDEX(sfi->index), 18847d4b564dSXiaoliang Yang ANA_TABLES_SFIDTIDX); 18857d4b564dSXiaoliang Yang 18867d4b564dSXiaoliang Yang ocelot_write(ocelot, 18877d4b564dSXiaoliang Yang (sfi->prio_valid ? ANA_TABLES_SFIDACCESS_IGR_PRIO_MATCH_ENA : 0) | 18887d4b564dSXiaoliang Yang ANA_TABLES_SFIDACCESS_IGR_PRIO(sfi->prio) | 18897d4b564dSXiaoliang Yang ANA_TABLES_SFIDACCESS_MAX_SDU_LEN(sfi->maxsdu) | 18907d4b564dSXiaoliang Yang ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(SFIDACCESS_CMD_WRITE), 18917d4b564dSXiaoliang Yang ANA_TABLES_SFIDACCESS); 18927d4b564dSXiaoliang Yang 18937d4b564dSXiaoliang Yang return readx_poll_timeout(vsc9959_sfi_access_status, ocelot, val, 18947d4b564dSXiaoliang Yang (!ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(val)), 18957d4b564dSXiaoliang Yang 10, 100000); 18967d4b564dSXiaoliang Yang } 18977d4b564dSXiaoliang Yang 1898a7e13edfSXiaoliang Yang static int vsc9959_psfp_sfidmask_set(struct ocelot *ocelot, u32 sfid, int ports) 18997d4b564dSXiaoliang Yang { 1900a7e13edfSXiaoliang Yang u32 val; 1901a7e13edfSXiaoliang Yang 1902a7e13edfSXiaoliang Yang ocelot_rmw(ocelot, 1903a7e13edfSXiaoliang Yang ANA_TABLES_SFIDTIDX_SFID_INDEX(sfid), 1904a7e13edfSXiaoliang Yang ANA_TABLES_SFIDTIDX_SFID_INDEX_M, 1905a7e13edfSXiaoliang Yang ANA_TABLES_SFIDTIDX); 1906a7e13edfSXiaoliang Yang 1907a7e13edfSXiaoliang Yang ocelot_write(ocelot, 1908a7e13edfSXiaoliang Yang ANA_TABLES_SFID_MASK_IGR_PORT_MASK(ports) | 1909a7e13edfSXiaoliang Yang ANA_TABLES_SFID_MASK_IGR_SRCPORT_MATCH_ENA, 1910a7e13edfSXiaoliang Yang ANA_TABLES_SFID_MASK); 1911a7e13edfSXiaoliang Yang 1912a7e13edfSXiaoliang Yang ocelot_rmw(ocelot, 1913a7e13edfSXiaoliang Yang ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(SFIDACCESS_CMD_WRITE), 1914a7e13edfSXiaoliang Yang ANA_TABLES_SFIDACCESS_SFID_TBL_CMD_M, 1915a7e13edfSXiaoliang Yang ANA_TABLES_SFIDACCESS); 1916a7e13edfSXiaoliang Yang 1917a7e13edfSXiaoliang Yang return readx_poll_timeout(vsc9959_sfi_access_status, ocelot, val, 1918a7e13edfSXiaoliang Yang (!ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(val)), 1919a7e13edfSXiaoliang Yang 10, 100000); 1920a7e13edfSXiaoliang Yang } 1921a7e13edfSXiaoliang Yang 1922a7e13edfSXiaoliang Yang static int vsc9959_psfp_sfi_list_add(struct ocelot *ocelot, 1923a7e13edfSXiaoliang Yang struct felix_stream_filter *sfi, 1924a7e13edfSXiaoliang Yang struct list_head *pos) 1925a7e13edfSXiaoliang Yang { 1926a7e13edfSXiaoliang Yang struct felix_stream_filter *sfi_entry; 19277d4b564dSXiaoliang Yang int ret; 19287d4b564dSXiaoliang Yang 1929e44aecc7SYihao Han sfi_entry = kmemdup(sfi, sizeof(*sfi_entry), GFP_KERNEL); 19307d4b564dSXiaoliang Yang if (!sfi_entry) 19317d4b564dSXiaoliang Yang return -ENOMEM; 19327d4b564dSXiaoliang Yang 19337d4b564dSXiaoliang Yang refcount_set(&sfi_entry->refcount, 1); 19347d4b564dSXiaoliang Yang 19357d4b564dSXiaoliang Yang ret = vsc9959_psfp_sfi_set(ocelot, sfi_entry); 19367d4b564dSXiaoliang Yang if (ret) { 19377d4b564dSXiaoliang Yang kfree(sfi_entry); 19387d4b564dSXiaoliang Yang return ret; 19397d4b564dSXiaoliang Yang } 19407d4b564dSXiaoliang Yang 1941a7e13edfSXiaoliang Yang vsc9959_psfp_sfidmask_set(ocelot, sfi->index, sfi->portmask); 1942a7e13edfSXiaoliang Yang 1943a7e13edfSXiaoliang Yang list_add(&sfi_entry->list, pos); 19447d4b564dSXiaoliang Yang 19457d4b564dSXiaoliang Yang return 0; 19467d4b564dSXiaoliang Yang } 19477d4b564dSXiaoliang Yang 1948a7e13edfSXiaoliang Yang static int vsc9959_psfp_sfi_table_add(struct ocelot *ocelot, 1949a7e13edfSXiaoliang Yang struct felix_stream_filter *sfi) 1950a7e13edfSXiaoliang Yang { 1951a7e13edfSXiaoliang Yang struct list_head *pos, *q, *last; 1952a7e13edfSXiaoliang Yang struct felix_stream_filter *tmp; 1953a7e13edfSXiaoliang Yang struct ocelot_psfp_list *psfp; 1954a7e13edfSXiaoliang Yang u32 insert = 0; 1955a7e13edfSXiaoliang Yang 1956a7e13edfSXiaoliang Yang psfp = &ocelot->psfp; 1957a7e13edfSXiaoliang Yang last = &psfp->sfi_list; 1958a7e13edfSXiaoliang Yang 1959a7e13edfSXiaoliang Yang list_for_each_safe(pos, q, &psfp->sfi_list) { 1960a7e13edfSXiaoliang Yang tmp = list_entry(pos, struct felix_stream_filter, list); 1961a7e13edfSXiaoliang Yang if (sfi->sg_valid == tmp->sg_valid && 1962a7e13edfSXiaoliang Yang sfi->fm_valid == tmp->fm_valid && 1963a7e13edfSXiaoliang Yang sfi->portmask == tmp->portmask && 1964a7e13edfSXiaoliang Yang tmp->sgid == sfi->sgid && 1965a7e13edfSXiaoliang Yang tmp->fmid == sfi->fmid) { 1966a7e13edfSXiaoliang Yang sfi->index = tmp->index; 1967a7e13edfSXiaoliang Yang refcount_inc(&tmp->refcount); 1968a7e13edfSXiaoliang Yang return 0; 1969a7e13edfSXiaoliang Yang } 1970a7e13edfSXiaoliang Yang /* Make sure that the index is increasing in order. */ 1971a7e13edfSXiaoliang Yang if (tmp->index == insert) { 1972a7e13edfSXiaoliang Yang last = pos; 1973a7e13edfSXiaoliang Yang insert++; 1974a7e13edfSXiaoliang Yang } 1975a7e13edfSXiaoliang Yang } 1976a7e13edfSXiaoliang Yang sfi->index = insert; 1977a7e13edfSXiaoliang Yang 1978a7e13edfSXiaoliang Yang return vsc9959_psfp_sfi_list_add(ocelot, sfi, last); 1979a7e13edfSXiaoliang Yang } 1980a7e13edfSXiaoliang Yang 1981a7e13edfSXiaoliang Yang static int vsc9959_psfp_sfi_table_add2(struct ocelot *ocelot, 1982a7e13edfSXiaoliang Yang struct felix_stream_filter *sfi, 1983a7e13edfSXiaoliang Yang struct felix_stream_filter *sfi2) 1984a7e13edfSXiaoliang Yang { 1985a7e13edfSXiaoliang Yang struct felix_stream_filter *tmp; 1986a7e13edfSXiaoliang Yang struct list_head *pos, *q, *last; 1987a7e13edfSXiaoliang Yang struct ocelot_psfp_list *psfp; 1988a7e13edfSXiaoliang Yang u32 insert = 0; 1989a7e13edfSXiaoliang Yang int ret; 1990a7e13edfSXiaoliang Yang 1991a7e13edfSXiaoliang Yang psfp = &ocelot->psfp; 1992a7e13edfSXiaoliang Yang last = &psfp->sfi_list; 1993a7e13edfSXiaoliang Yang 1994a7e13edfSXiaoliang Yang list_for_each_safe(pos, q, &psfp->sfi_list) { 1995a7e13edfSXiaoliang Yang tmp = list_entry(pos, struct felix_stream_filter, list); 1996a7e13edfSXiaoliang Yang /* Make sure that the index is increasing in order. */ 1997a7e13edfSXiaoliang Yang if (tmp->index >= insert + 2) 1998a7e13edfSXiaoliang Yang break; 1999a7e13edfSXiaoliang Yang 2000a7e13edfSXiaoliang Yang insert = tmp->index + 1; 2001a7e13edfSXiaoliang Yang last = pos; 2002a7e13edfSXiaoliang Yang } 2003a7e13edfSXiaoliang Yang sfi->index = insert; 2004a7e13edfSXiaoliang Yang 2005a7e13edfSXiaoliang Yang ret = vsc9959_psfp_sfi_list_add(ocelot, sfi, last); 2006a7e13edfSXiaoliang Yang if (ret) 2007a7e13edfSXiaoliang Yang return ret; 2008a7e13edfSXiaoliang Yang 2009a7e13edfSXiaoliang Yang sfi2->index = insert + 1; 2010a7e13edfSXiaoliang Yang 2011a7e13edfSXiaoliang Yang return vsc9959_psfp_sfi_list_add(ocelot, sfi2, last->next); 2012a7e13edfSXiaoliang Yang } 2013a7e13edfSXiaoliang Yang 201423ae3a78SXiaoliang Yang static struct felix_stream_filter * 201523ae3a78SXiaoliang Yang vsc9959_psfp_sfi_table_get(struct list_head *sfi_list, u32 index) 201623ae3a78SXiaoliang Yang { 201723ae3a78SXiaoliang Yang struct felix_stream_filter *tmp; 201823ae3a78SXiaoliang Yang 201923ae3a78SXiaoliang Yang list_for_each_entry(tmp, sfi_list, list) 202023ae3a78SXiaoliang Yang if (tmp->index == index) 202123ae3a78SXiaoliang Yang return tmp; 202223ae3a78SXiaoliang Yang 202323ae3a78SXiaoliang Yang return NULL; 202423ae3a78SXiaoliang Yang } 202523ae3a78SXiaoliang Yang 20267d4b564dSXiaoliang Yang static void vsc9959_psfp_sfi_table_del(struct ocelot *ocelot, u32 index) 20277d4b564dSXiaoliang Yang { 20287d4b564dSXiaoliang Yang struct felix_stream_filter *tmp, *n; 20297d4b564dSXiaoliang Yang struct ocelot_psfp_list *psfp; 20307d4b564dSXiaoliang Yang u8 z; 20317d4b564dSXiaoliang Yang 20327d4b564dSXiaoliang Yang psfp = &ocelot->psfp; 20337d4b564dSXiaoliang Yang 20347d4b564dSXiaoliang Yang list_for_each_entry_safe(tmp, n, &psfp->sfi_list, list) 20357d4b564dSXiaoliang Yang if (tmp->index == index) { 20367d4b564dSXiaoliang Yang z = refcount_dec_and_test(&tmp->refcount); 20377d4b564dSXiaoliang Yang if (z) { 20387d4b564dSXiaoliang Yang tmp->enable = 0; 20397d4b564dSXiaoliang Yang vsc9959_psfp_sfi_set(ocelot, tmp); 20407d4b564dSXiaoliang Yang list_del(&tmp->list); 20417d4b564dSXiaoliang Yang kfree(tmp); 20427d4b564dSXiaoliang Yang } 20437d4b564dSXiaoliang Yang break; 20447d4b564dSXiaoliang Yang } 20457d4b564dSXiaoliang Yang } 20467d4b564dSXiaoliang Yang 204723ae3a78SXiaoliang Yang static void vsc9959_psfp_parse_gate(const struct flow_action_entry *entry, 204823ae3a78SXiaoliang Yang struct felix_stream_gate *sgi) 204923ae3a78SXiaoliang Yang { 20505a995900SBaowen Zheng sgi->index = entry->hw_index; 205123ae3a78SXiaoliang Yang sgi->ipv_valid = (entry->gate.prio < 0) ? 0 : 1; 205223ae3a78SXiaoliang Yang sgi->init_ipv = (sgi->ipv_valid) ? entry->gate.prio : 0; 205323ae3a78SXiaoliang Yang sgi->basetime = entry->gate.basetime; 205423ae3a78SXiaoliang Yang sgi->cycletime = entry->gate.cycletime; 205523ae3a78SXiaoliang Yang sgi->num_entries = entry->gate.num_entries; 205623ae3a78SXiaoliang Yang sgi->enable = 1; 205723ae3a78SXiaoliang Yang 205823ae3a78SXiaoliang Yang memcpy(sgi->entries, entry->gate.entries, 205923ae3a78SXiaoliang Yang entry->gate.num_entries * sizeof(struct action_gate_entry)); 206023ae3a78SXiaoliang Yang } 206123ae3a78SXiaoliang Yang 206223ae3a78SXiaoliang Yang static u32 vsc9959_sgi_cfg_status(struct ocelot *ocelot) 206323ae3a78SXiaoliang Yang { 206423ae3a78SXiaoliang Yang return ocelot_read(ocelot, ANA_SG_ACCESS_CTRL); 206523ae3a78SXiaoliang Yang } 206623ae3a78SXiaoliang Yang 206723ae3a78SXiaoliang Yang static int vsc9959_psfp_sgi_set(struct ocelot *ocelot, 206823ae3a78SXiaoliang Yang struct felix_stream_gate *sgi) 206923ae3a78SXiaoliang Yang { 207023ae3a78SXiaoliang Yang struct action_gate_entry *e; 207123ae3a78SXiaoliang Yang struct timespec64 base_ts; 207223ae3a78SXiaoliang Yang u32 interval_sum = 0; 207323ae3a78SXiaoliang Yang u32 val; 207423ae3a78SXiaoliang Yang int i; 207523ae3a78SXiaoliang Yang 207623ae3a78SXiaoliang Yang if (sgi->index > VSC9959_PSFP_GATE_ID_MAX) 207723ae3a78SXiaoliang Yang return -EINVAL; 207823ae3a78SXiaoliang Yang 207923ae3a78SXiaoliang Yang ocelot_write(ocelot, ANA_SG_ACCESS_CTRL_SGID(sgi->index), 208023ae3a78SXiaoliang Yang ANA_SG_ACCESS_CTRL); 208123ae3a78SXiaoliang Yang 208223ae3a78SXiaoliang Yang if (!sgi->enable) { 208323ae3a78SXiaoliang Yang ocelot_rmw(ocelot, ANA_SG_CONFIG_REG_3_INIT_GATE_STATE, 208423ae3a78SXiaoliang Yang ANA_SG_CONFIG_REG_3_INIT_GATE_STATE | 208523ae3a78SXiaoliang Yang ANA_SG_CONFIG_REG_3_GATE_ENABLE, 208623ae3a78SXiaoliang Yang ANA_SG_CONFIG_REG_3); 208723ae3a78SXiaoliang Yang 208823ae3a78SXiaoliang Yang return 0; 208923ae3a78SXiaoliang Yang } 209023ae3a78SXiaoliang Yang 209123ae3a78SXiaoliang Yang if (sgi->cycletime < VSC9959_PSFP_GATE_CYCLETIME_MIN || 209223ae3a78SXiaoliang Yang sgi->cycletime > NSEC_PER_SEC) 209323ae3a78SXiaoliang Yang return -EINVAL; 209423ae3a78SXiaoliang Yang 209523ae3a78SXiaoliang Yang if (sgi->num_entries > VSC9959_PSFP_GATE_LIST_NUM) 209623ae3a78SXiaoliang Yang return -EINVAL; 209723ae3a78SXiaoliang Yang 209823ae3a78SXiaoliang Yang vsc9959_new_base_time(ocelot, sgi->basetime, sgi->cycletime, &base_ts); 209923ae3a78SXiaoliang Yang ocelot_write(ocelot, base_ts.tv_nsec, ANA_SG_CONFIG_REG_1); 210023ae3a78SXiaoliang Yang val = lower_32_bits(base_ts.tv_sec); 210123ae3a78SXiaoliang Yang ocelot_write(ocelot, val, ANA_SG_CONFIG_REG_2); 210223ae3a78SXiaoliang Yang 210323ae3a78SXiaoliang Yang val = upper_32_bits(base_ts.tv_sec); 210423ae3a78SXiaoliang Yang ocelot_write(ocelot, 210523ae3a78SXiaoliang Yang (sgi->ipv_valid ? ANA_SG_CONFIG_REG_3_IPV_VALID : 0) | 210623ae3a78SXiaoliang Yang ANA_SG_CONFIG_REG_3_INIT_IPV(sgi->init_ipv) | 210723ae3a78SXiaoliang Yang ANA_SG_CONFIG_REG_3_GATE_ENABLE | 210823ae3a78SXiaoliang Yang ANA_SG_CONFIG_REG_3_LIST_LENGTH(sgi->num_entries) | 210923ae3a78SXiaoliang Yang ANA_SG_CONFIG_REG_3_INIT_GATE_STATE | 211023ae3a78SXiaoliang Yang ANA_SG_CONFIG_REG_3_BASE_TIME_SEC_MSB(val), 211123ae3a78SXiaoliang Yang ANA_SG_CONFIG_REG_3); 211223ae3a78SXiaoliang Yang 211323ae3a78SXiaoliang Yang ocelot_write(ocelot, sgi->cycletime, ANA_SG_CONFIG_REG_4); 211423ae3a78SXiaoliang Yang 211523ae3a78SXiaoliang Yang e = sgi->entries; 211623ae3a78SXiaoliang Yang for (i = 0; i < sgi->num_entries; i++) { 211723ae3a78SXiaoliang Yang u32 ips = (e[i].ipv < 0) ? 0 : (e[i].ipv + 8); 211823ae3a78SXiaoliang Yang 211923ae3a78SXiaoliang Yang ocelot_write_rix(ocelot, ANA_SG_GCL_GS_CONFIG_IPS(ips) | 212023ae3a78SXiaoliang Yang (e[i].gate_state ? 212123ae3a78SXiaoliang Yang ANA_SG_GCL_GS_CONFIG_GATE_STATE : 0), 212223ae3a78SXiaoliang Yang ANA_SG_GCL_GS_CONFIG, i); 212323ae3a78SXiaoliang Yang 212423ae3a78SXiaoliang Yang interval_sum += e[i].interval; 212523ae3a78SXiaoliang Yang ocelot_write_rix(ocelot, interval_sum, ANA_SG_GCL_TI_CONFIG, i); 212623ae3a78SXiaoliang Yang } 212723ae3a78SXiaoliang Yang 212823ae3a78SXiaoliang Yang ocelot_rmw(ocelot, ANA_SG_ACCESS_CTRL_CONFIG_CHANGE, 212923ae3a78SXiaoliang Yang ANA_SG_ACCESS_CTRL_CONFIG_CHANGE, 213023ae3a78SXiaoliang Yang ANA_SG_ACCESS_CTRL); 213123ae3a78SXiaoliang Yang 213223ae3a78SXiaoliang Yang return readx_poll_timeout(vsc9959_sgi_cfg_status, ocelot, val, 213323ae3a78SXiaoliang Yang (!(ANA_SG_ACCESS_CTRL_CONFIG_CHANGE & val)), 213423ae3a78SXiaoliang Yang 10, 100000); 213523ae3a78SXiaoliang Yang } 213623ae3a78SXiaoliang Yang 213723ae3a78SXiaoliang Yang static int vsc9959_psfp_sgi_table_add(struct ocelot *ocelot, 213823ae3a78SXiaoliang Yang struct felix_stream_gate *sgi) 213923ae3a78SXiaoliang Yang { 214023ae3a78SXiaoliang Yang struct felix_stream_gate_entry *tmp; 214123ae3a78SXiaoliang Yang struct ocelot_psfp_list *psfp; 214223ae3a78SXiaoliang Yang int ret; 214323ae3a78SXiaoliang Yang 214423ae3a78SXiaoliang Yang psfp = &ocelot->psfp; 214523ae3a78SXiaoliang Yang 214623ae3a78SXiaoliang Yang list_for_each_entry(tmp, &psfp->sgi_list, list) 214723ae3a78SXiaoliang Yang if (tmp->index == sgi->index) { 214823ae3a78SXiaoliang Yang refcount_inc(&tmp->refcount); 214923ae3a78SXiaoliang Yang return 0; 215023ae3a78SXiaoliang Yang } 215123ae3a78SXiaoliang Yang 215223ae3a78SXiaoliang Yang tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); 215323ae3a78SXiaoliang Yang if (!tmp) 215423ae3a78SXiaoliang Yang return -ENOMEM; 215523ae3a78SXiaoliang Yang 215623ae3a78SXiaoliang Yang ret = vsc9959_psfp_sgi_set(ocelot, sgi); 215723ae3a78SXiaoliang Yang if (ret) { 215823ae3a78SXiaoliang Yang kfree(tmp); 215923ae3a78SXiaoliang Yang return ret; 216023ae3a78SXiaoliang Yang } 216123ae3a78SXiaoliang Yang 216223ae3a78SXiaoliang Yang tmp->index = sgi->index; 216323ae3a78SXiaoliang Yang refcount_set(&tmp->refcount, 1); 216423ae3a78SXiaoliang Yang list_add_tail(&tmp->list, &psfp->sgi_list); 216523ae3a78SXiaoliang Yang 216623ae3a78SXiaoliang Yang return 0; 216723ae3a78SXiaoliang Yang } 216823ae3a78SXiaoliang Yang 216923ae3a78SXiaoliang Yang static void vsc9959_psfp_sgi_table_del(struct ocelot *ocelot, 217023ae3a78SXiaoliang Yang u32 index) 217123ae3a78SXiaoliang Yang { 217223ae3a78SXiaoliang Yang struct felix_stream_gate_entry *tmp, *n; 217323ae3a78SXiaoliang Yang struct felix_stream_gate sgi = {0}; 217423ae3a78SXiaoliang Yang struct ocelot_psfp_list *psfp; 217523ae3a78SXiaoliang Yang u8 z; 217623ae3a78SXiaoliang Yang 217723ae3a78SXiaoliang Yang psfp = &ocelot->psfp; 217823ae3a78SXiaoliang Yang 217923ae3a78SXiaoliang Yang list_for_each_entry_safe(tmp, n, &psfp->sgi_list, list) 218023ae3a78SXiaoliang Yang if (tmp->index == index) { 218123ae3a78SXiaoliang Yang z = refcount_dec_and_test(&tmp->refcount); 218223ae3a78SXiaoliang Yang if (z) { 218323ae3a78SXiaoliang Yang sgi.index = index; 218423ae3a78SXiaoliang Yang sgi.enable = 0; 218523ae3a78SXiaoliang Yang vsc9959_psfp_sgi_set(ocelot, &sgi); 218623ae3a78SXiaoliang Yang list_del(&tmp->list); 218723ae3a78SXiaoliang Yang kfree(tmp); 218823ae3a78SXiaoliang Yang } 218923ae3a78SXiaoliang Yang break; 219023ae3a78SXiaoliang Yang } 219123ae3a78SXiaoliang Yang } 219223ae3a78SXiaoliang Yang 2193a7e13edfSXiaoliang Yang static int vsc9959_psfp_filter_add(struct ocelot *ocelot, int port, 21947d4b564dSXiaoliang Yang struct flow_cls_offload *f) 21957d4b564dSXiaoliang Yang { 21967d4b564dSXiaoliang Yang struct netlink_ext_ack *extack = f->common.extack; 2197a7e13edfSXiaoliang Yang struct felix_stream_filter old_sfi, *sfi_entry; 21987d4b564dSXiaoliang Yang struct felix_stream_filter sfi = {0}; 21997d4b564dSXiaoliang Yang const struct flow_action_entry *a; 22007d4b564dSXiaoliang Yang struct felix_stream *stream_entry; 22017d4b564dSXiaoliang Yang struct felix_stream stream = {0}; 220223ae3a78SXiaoliang Yang struct felix_stream_gate *sgi; 22037d4b564dSXiaoliang Yang struct ocelot_psfp_list *psfp; 220476c13edeSXiaoliang Yang struct ocelot_policer pol; 220523ae3a78SXiaoliang Yang int ret, i, size; 220676c13edeSXiaoliang Yang u64 rate, burst; 220776c13edeSXiaoliang Yang u32 index; 22087d4b564dSXiaoliang Yang 22097d4b564dSXiaoliang Yang psfp = &ocelot->psfp; 22107d4b564dSXiaoliang Yang 22117d4b564dSXiaoliang Yang ret = vsc9959_stream_identify(f, &stream); 22127d4b564dSXiaoliang Yang if (ret) { 22137d4b564dSXiaoliang Yang NL_SET_ERR_MSG_MOD(extack, "Only can match on VID, PCP, and dest MAC"); 22147d4b564dSXiaoliang Yang return ret; 22157d4b564dSXiaoliang Yang } 22167d4b564dSXiaoliang Yang 221725027c84SVladimir Oltean mutex_lock(&psfp->lock); 221825027c84SVladimir Oltean 22197d4b564dSXiaoliang Yang flow_action_for_each(i, a, &f->rule->action) { 22207d4b564dSXiaoliang Yang switch (a->id) { 22217d4b564dSXiaoliang Yang case FLOW_ACTION_GATE: 222223ae3a78SXiaoliang Yang size = struct_size(sgi, entries, a->gate.num_entries); 222323ae3a78SXiaoliang Yang sgi = kzalloc(size, GFP_KERNEL); 2224866b7a27SZheng Yongjun if (!sgi) { 2225866b7a27SZheng Yongjun ret = -ENOMEM; 2226866b7a27SZheng Yongjun goto err; 2227866b7a27SZheng Yongjun } 222823ae3a78SXiaoliang Yang vsc9959_psfp_parse_gate(a, sgi); 222923ae3a78SXiaoliang Yang ret = vsc9959_psfp_sgi_table_add(ocelot, sgi); 223023ae3a78SXiaoliang Yang if (ret) { 223123ae3a78SXiaoliang Yang kfree(sgi); 223276c13edeSXiaoliang Yang goto err; 223323ae3a78SXiaoliang Yang } 223423ae3a78SXiaoliang Yang sfi.sg_valid = 1; 223523ae3a78SXiaoliang Yang sfi.sgid = sgi->index; 223623ae3a78SXiaoliang Yang kfree(sgi); 223723ae3a78SXiaoliang Yang break; 22387d4b564dSXiaoliang Yang case FLOW_ACTION_POLICE: 22395a995900SBaowen Zheng index = a->hw_index + VSC9959_PSFP_POLICER_BASE; 224076c13edeSXiaoliang Yang if (index > VSC9959_PSFP_POLICER_MAX) { 224176c13edeSXiaoliang Yang ret = -EINVAL; 224276c13edeSXiaoliang Yang goto err; 224376c13edeSXiaoliang Yang } 224476c13edeSXiaoliang Yang 224576c13edeSXiaoliang Yang rate = a->police.rate_bytes_ps; 224676c13edeSXiaoliang Yang burst = rate * PSCHED_NS2TICKS(a->police.burst); 224776c13edeSXiaoliang Yang pol = (struct ocelot_policer) { 224876c13edeSXiaoliang Yang .burst = div_u64(burst, PSCHED_TICKS_PER_SEC), 224976c13edeSXiaoliang Yang .rate = div_u64(rate, 1000) * 8, 225076c13edeSXiaoliang Yang }; 225176c13edeSXiaoliang Yang ret = ocelot_vcap_policer_add(ocelot, index, &pol); 225276c13edeSXiaoliang Yang if (ret) 225376c13edeSXiaoliang Yang goto err; 225476c13edeSXiaoliang Yang 225576c13edeSXiaoliang Yang sfi.fm_valid = 1; 225676c13edeSXiaoliang Yang sfi.fmid = index; 225776c13edeSXiaoliang Yang sfi.maxsdu = a->police.mtu; 225876c13edeSXiaoliang Yang break; 22597d4b564dSXiaoliang Yang default: 226025027c84SVladimir Oltean mutex_unlock(&psfp->lock); 22617d4b564dSXiaoliang Yang return -EOPNOTSUPP; 22627d4b564dSXiaoliang Yang } 22637d4b564dSXiaoliang Yang } 22647d4b564dSXiaoliang Yang 2265a7e13edfSXiaoliang Yang stream.ports = BIT(port); 2266a7e13edfSXiaoliang Yang stream.port = port; 22677d4b564dSXiaoliang Yang 2268a7e13edfSXiaoliang Yang sfi.portmask = stream.ports; 22697d4b564dSXiaoliang Yang sfi.prio_valid = (stream.prio < 0 ? 0 : 1); 22707d4b564dSXiaoliang Yang sfi.prio = (sfi.prio_valid ? stream.prio : 0); 22717d4b564dSXiaoliang Yang sfi.enable = 1; 22727d4b564dSXiaoliang Yang 2273a7e13edfSXiaoliang Yang /* Check if stream is set. */ 2274a7e13edfSXiaoliang Yang stream_entry = vsc9959_stream_table_lookup(&psfp->stream_list, &stream); 2275a7e13edfSXiaoliang Yang if (stream_entry) { 2276a7e13edfSXiaoliang Yang if (stream_entry->ports & BIT(port)) { 2277a7e13edfSXiaoliang Yang NL_SET_ERR_MSG_MOD(extack, 2278a7e13edfSXiaoliang Yang "The stream is added on this port"); 2279a7e13edfSXiaoliang Yang ret = -EEXIST; 2280a7e13edfSXiaoliang Yang goto err; 2281a7e13edfSXiaoliang Yang } 2282a7e13edfSXiaoliang Yang 2283a7e13edfSXiaoliang Yang if (stream_entry->ports != BIT(stream_entry->port)) { 2284a7e13edfSXiaoliang Yang NL_SET_ERR_MSG_MOD(extack, 2285a7e13edfSXiaoliang Yang "The stream is added on two ports"); 2286a7e13edfSXiaoliang Yang ret = -EEXIST; 2287a7e13edfSXiaoliang Yang goto err; 2288a7e13edfSXiaoliang Yang } 2289a7e13edfSXiaoliang Yang 2290a7e13edfSXiaoliang Yang stream_entry->ports |= BIT(port); 2291a7e13edfSXiaoliang Yang stream.ports = stream_entry->ports; 2292a7e13edfSXiaoliang Yang 2293a7e13edfSXiaoliang Yang sfi_entry = vsc9959_psfp_sfi_table_get(&psfp->sfi_list, 2294a7e13edfSXiaoliang Yang stream_entry->sfid); 2295a7e13edfSXiaoliang Yang memcpy(&old_sfi, sfi_entry, sizeof(old_sfi)); 2296a7e13edfSXiaoliang Yang 2297a7e13edfSXiaoliang Yang vsc9959_psfp_sfi_table_del(ocelot, stream_entry->sfid); 2298a7e13edfSXiaoliang Yang 2299a7e13edfSXiaoliang Yang old_sfi.portmask = stream_entry->ports; 2300a7e13edfSXiaoliang Yang sfi.portmask = stream.ports; 2301a7e13edfSXiaoliang Yang 2302a7e13edfSXiaoliang Yang if (stream_entry->port > port) { 2303a7e13edfSXiaoliang Yang ret = vsc9959_psfp_sfi_table_add2(ocelot, &sfi, 2304a7e13edfSXiaoliang Yang &old_sfi); 2305a7e13edfSXiaoliang Yang stream_entry->dummy = true; 2306a7e13edfSXiaoliang Yang } else { 2307a7e13edfSXiaoliang Yang ret = vsc9959_psfp_sfi_table_add2(ocelot, &old_sfi, 2308a7e13edfSXiaoliang Yang &sfi); 2309a7e13edfSXiaoliang Yang stream.dummy = true; 2310a7e13edfSXiaoliang Yang } 2311a7e13edfSXiaoliang Yang if (ret) 2312a7e13edfSXiaoliang Yang goto err; 2313a7e13edfSXiaoliang Yang 2314a7e13edfSXiaoliang Yang stream_entry->sfid = old_sfi.index; 2315a7e13edfSXiaoliang Yang } else { 23167d4b564dSXiaoliang Yang ret = vsc9959_psfp_sfi_table_add(ocelot, &sfi); 23177d4b564dSXiaoliang Yang if (ret) 231823ae3a78SXiaoliang Yang goto err; 2319a7e13edfSXiaoliang Yang } 23207d4b564dSXiaoliang Yang 23217d4b564dSXiaoliang Yang stream.sfid = sfi.index; 23227d4b564dSXiaoliang Yang stream.sfid_valid = 1; 23237d4b564dSXiaoliang Yang ret = vsc9959_stream_table_add(ocelot, &psfp->stream_list, 23247d4b564dSXiaoliang Yang &stream, extack); 232523ae3a78SXiaoliang Yang if (ret) { 23267d4b564dSXiaoliang Yang vsc9959_psfp_sfi_table_del(ocelot, stream.sfid); 232723ae3a78SXiaoliang Yang goto err; 232823ae3a78SXiaoliang Yang } 232923ae3a78SXiaoliang Yang 233025027c84SVladimir Oltean mutex_unlock(&psfp->lock); 233125027c84SVladimir Oltean 233223ae3a78SXiaoliang Yang return 0; 233323ae3a78SXiaoliang Yang 233423ae3a78SXiaoliang Yang err: 233523ae3a78SXiaoliang Yang if (sfi.sg_valid) 233623ae3a78SXiaoliang Yang vsc9959_psfp_sgi_table_del(ocelot, sfi.sgid); 23377d4b564dSXiaoliang Yang 233876c13edeSXiaoliang Yang if (sfi.fm_valid) 233976c13edeSXiaoliang Yang ocelot_vcap_policer_del(ocelot, sfi.fmid); 234076c13edeSXiaoliang Yang 234125027c84SVladimir Oltean mutex_unlock(&psfp->lock); 234225027c84SVladimir Oltean 23437d4b564dSXiaoliang Yang return ret; 23447d4b564dSXiaoliang Yang } 23457d4b564dSXiaoliang Yang 23467d4b564dSXiaoliang Yang static int vsc9959_psfp_filter_del(struct ocelot *ocelot, 23477d4b564dSXiaoliang Yang struct flow_cls_offload *f) 23487d4b564dSXiaoliang Yang { 2349a7e13edfSXiaoliang Yang struct felix_stream *stream, tmp, *stream_entry; 235025027c84SVladimir Oltean struct ocelot_psfp_list *psfp = &ocelot->psfp; 235123ae3a78SXiaoliang Yang static struct felix_stream_filter *sfi; 23527d4b564dSXiaoliang Yang 235325027c84SVladimir Oltean mutex_lock(&psfp->lock); 23547d4b564dSXiaoliang Yang 23557d4b564dSXiaoliang Yang stream = vsc9959_stream_table_get(&psfp->stream_list, f->cookie); 235625027c84SVladimir Oltean if (!stream) { 235725027c84SVladimir Oltean mutex_unlock(&psfp->lock); 23587d4b564dSXiaoliang Yang return -ENOMEM; 235925027c84SVladimir Oltean } 23607d4b564dSXiaoliang Yang 236123ae3a78SXiaoliang Yang sfi = vsc9959_psfp_sfi_table_get(&psfp->sfi_list, stream->sfid); 236225027c84SVladimir Oltean if (!sfi) { 236325027c84SVladimir Oltean mutex_unlock(&psfp->lock); 236423ae3a78SXiaoliang Yang return -ENOMEM; 236525027c84SVladimir Oltean } 236623ae3a78SXiaoliang Yang 236723ae3a78SXiaoliang Yang if (sfi->sg_valid) 236823ae3a78SXiaoliang Yang vsc9959_psfp_sgi_table_del(ocelot, sfi->sgid); 236923ae3a78SXiaoliang Yang 237076c13edeSXiaoliang Yang if (sfi->fm_valid) 237176c13edeSXiaoliang Yang ocelot_vcap_policer_del(ocelot, sfi->fmid); 237276c13edeSXiaoliang Yang 23737d4b564dSXiaoliang Yang vsc9959_psfp_sfi_table_del(ocelot, stream->sfid); 23747d4b564dSXiaoliang Yang 2375a7e13edfSXiaoliang Yang memcpy(&tmp, stream, sizeof(tmp)); 2376a7e13edfSXiaoliang Yang 23777d4b564dSXiaoliang Yang stream->sfid_valid = 0; 23787d4b564dSXiaoliang Yang vsc9959_stream_table_del(ocelot, stream); 23797d4b564dSXiaoliang Yang 2380a7e13edfSXiaoliang Yang stream_entry = vsc9959_stream_table_lookup(&psfp->stream_list, &tmp); 2381a7e13edfSXiaoliang Yang if (stream_entry) { 2382a7e13edfSXiaoliang Yang stream_entry->ports = BIT(stream_entry->port); 2383a7e13edfSXiaoliang Yang if (stream_entry->dummy) { 2384a7e13edfSXiaoliang Yang stream_entry->dummy = false; 2385a7e13edfSXiaoliang Yang vsc9959_mact_stream_set(ocelot, stream_entry, NULL); 2386a7e13edfSXiaoliang Yang } 2387a7e13edfSXiaoliang Yang vsc9959_psfp_sfidmask_set(ocelot, stream_entry->sfid, 2388a7e13edfSXiaoliang Yang stream_entry->ports); 2389a7e13edfSXiaoliang Yang } 2390a7e13edfSXiaoliang Yang 239125027c84SVladimir Oltean mutex_unlock(&psfp->lock); 239225027c84SVladimir Oltean 23937d4b564dSXiaoliang Yang return 0; 23947d4b564dSXiaoliang Yang } 23957d4b564dSXiaoliang Yang 239625027c84SVladimir Oltean static void vsc9959_update_sfid_stats(struct ocelot *ocelot, 239725027c84SVladimir Oltean struct felix_stream_filter *sfi) 239825027c84SVladimir Oltean { 239925027c84SVladimir Oltean struct felix_stream_filter_counters *s = &sfi->stats; 240025027c84SVladimir Oltean u32 match, not_pass_gate, not_pass_sdu, red; 240125027c84SVladimir Oltean u32 sfid = sfi->index; 240225027c84SVladimir Oltean 240325027c84SVladimir Oltean lockdep_assert_held(&ocelot->stat_view_lock); 240425027c84SVladimir Oltean 240525027c84SVladimir Oltean ocelot_rmw(ocelot, SYS_STAT_CFG_STAT_VIEW(sfid), 240625027c84SVladimir Oltean SYS_STAT_CFG_STAT_VIEW_M, 240725027c84SVladimir Oltean SYS_STAT_CFG); 240825027c84SVladimir Oltean 240925027c84SVladimir Oltean match = ocelot_read(ocelot, SYS_COUNT_SF_MATCHING_FRAMES); 241025027c84SVladimir Oltean not_pass_gate = ocelot_read(ocelot, SYS_COUNT_SF_NOT_PASSING_FRAMES); 241125027c84SVladimir Oltean not_pass_sdu = ocelot_read(ocelot, SYS_COUNT_SF_NOT_PASSING_SDU); 241225027c84SVladimir Oltean red = ocelot_read(ocelot, SYS_COUNT_SF_RED_FRAMES); 241325027c84SVladimir Oltean 241425027c84SVladimir Oltean /* Clear the PSFP counter. */ 241525027c84SVladimir Oltean ocelot_write(ocelot, 241625027c84SVladimir Oltean SYS_STAT_CFG_STAT_VIEW(sfid) | 241725027c84SVladimir Oltean SYS_STAT_CFG_STAT_CLEAR_SHOT(0x10), 241825027c84SVladimir Oltean SYS_STAT_CFG); 241925027c84SVladimir Oltean 242025027c84SVladimir Oltean s->match += match; 242125027c84SVladimir Oltean s->not_pass_gate += not_pass_gate; 242225027c84SVladimir Oltean s->not_pass_sdu += not_pass_sdu; 242325027c84SVladimir Oltean s->red += red; 242425027c84SVladimir Oltean } 242525027c84SVladimir Oltean 242625027c84SVladimir Oltean /* Caller must hold &ocelot->stat_view_lock */ 242725027c84SVladimir Oltean static void vsc9959_update_stats(struct ocelot *ocelot) 242825027c84SVladimir Oltean { 242925027c84SVladimir Oltean struct ocelot_psfp_list *psfp = &ocelot->psfp; 243025027c84SVladimir Oltean struct felix_stream_filter *sfi; 243125027c84SVladimir Oltean 243225027c84SVladimir Oltean mutex_lock(&psfp->lock); 243325027c84SVladimir Oltean 243425027c84SVladimir Oltean list_for_each_entry(sfi, &psfp->sfi_list, list) 243525027c84SVladimir Oltean vsc9959_update_sfid_stats(ocelot, sfi); 243625027c84SVladimir Oltean 243725027c84SVladimir Oltean mutex_unlock(&psfp->lock); 243825027c84SVladimir Oltean } 243925027c84SVladimir Oltean 24407d4b564dSXiaoliang Yang static int vsc9959_psfp_stats_get(struct ocelot *ocelot, 24417d4b564dSXiaoliang Yang struct flow_cls_offload *f, 24427d4b564dSXiaoliang Yang struct flow_stats *stats) 24437d4b564dSXiaoliang Yang { 244425027c84SVladimir Oltean struct ocelot_psfp_list *psfp = &ocelot->psfp; 244525027c84SVladimir Oltean struct felix_stream_filter_counters *s; 244625027c84SVladimir Oltean static struct felix_stream_filter *sfi; 24477d4b564dSXiaoliang Yang struct felix_stream *stream; 24487d4b564dSXiaoliang Yang 24497d4b564dSXiaoliang Yang stream = vsc9959_stream_table_get(&psfp->stream_list, f->cookie); 24507d4b564dSXiaoliang Yang if (!stream) 24517d4b564dSXiaoliang Yang return -ENOMEM; 24527d4b564dSXiaoliang Yang 245325027c84SVladimir Oltean sfi = vsc9959_psfp_sfi_table_get(&psfp->sfi_list, stream->sfid); 245425027c84SVladimir Oltean if (!sfi) 245525027c84SVladimir Oltean return -EINVAL; 24567d4b564dSXiaoliang Yang 245725027c84SVladimir Oltean mutex_lock(&ocelot->stat_view_lock); 245825027c84SVladimir Oltean 245925027c84SVladimir Oltean vsc9959_update_sfid_stats(ocelot, sfi); 246025027c84SVladimir Oltean 246125027c84SVladimir Oltean s = &sfi->stats; 246225027c84SVladimir Oltean stats->pkts = s->match; 246325027c84SVladimir Oltean stats->drops = s->not_pass_gate + s->not_pass_sdu + s->red; 246425027c84SVladimir Oltean 246525027c84SVladimir Oltean memset(s, 0, sizeof(*s)); 246625027c84SVladimir Oltean 246725027c84SVladimir Oltean mutex_unlock(&ocelot->stat_view_lock); 24687d4b564dSXiaoliang Yang 24697d4b564dSXiaoliang Yang return 0; 24707d4b564dSXiaoliang Yang } 24717d4b564dSXiaoliang Yang 24727d4b564dSXiaoliang Yang static void vsc9959_psfp_init(struct ocelot *ocelot) 24737d4b564dSXiaoliang Yang { 24747d4b564dSXiaoliang Yang struct ocelot_psfp_list *psfp = &ocelot->psfp; 24757d4b564dSXiaoliang Yang 24767d4b564dSXiaoliang Yang INIT_LIST_HEAD(&psfp->stream_list); 24777d4b564dSXiaoliang Yang INIT_LIST_HEAD(&psfp->sfi_list); 24787d4b564dSXiaoliang Yang INIT_LIST_HEAD(&psfp->sgi_list); 247925027c84SVladimir Oltean mutex_init(&psfp->lock); 24807d4b564dSXiaoliang Yang } 24817d4b564dSXiaoliang Yang 24828abe1970SVladimir Oltean /* When using cut-through forwarding and the egress port runs at a higher data 24838abe1970SVladimir Oltean * rate than the ingress port, the packet currently under transmission would 24848abe1970SVladimir Oltean * suffer an underrun since it would be transmitted faster than it is received. 24858abe1970SVladimir Oltean * The Felix switch implementation of cut-through forwarding does not check in 24868abe1970SVladimir Oltean * hardware whether this condition is satisfied or not, so we must restrict the 24878abe1970SVladimir Oltean * list of ports that have cut-through forwarding enabled on egress to only be 24888abe1970SVladimir Oltean * the ports operating at the lowest link speed within their respective 24898abe1970SVladimir Oltean * forwarding domain. 24908abe1970SVladimir Oltean */ 24918abe1970SVladimir Oltean static void vsc9959_cut_through_fwd(struct ocelot *ocelot) 24928abe1970SVladimir Oltean { 24938abe1970SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 24948abe1970SVladimir Oltean struct dsa_switch *ds = felix->ds; 2495843794bbSVladimir Oltean int tc, port, other_port; 24968abe1970SVladimir Oltean 24978abe1970SVladimir Oltean lockdep_assert_held(&ocelot->fwd_domain_lock); 24988abe1970SVladimir Oltean 24998abe1970SVladimir Oltean for (port = 0; port < ocelot->num_phys_ports; port++) { 25008abe1970SVladimir Oltean struct ocelot_port *ocelot_port = ocelot->ports[port]; 25018abe1970SVladimir Oltean int min_speed = ocelot_port->speed; 25028abe1970SVladimir Oltean unsigned long mask = 0; 25038abe1970SVladimir Oltean u32 tmp, val = 0; 25048abe1970SVladimir Oltean 25058abe1970SVladimir Oltean /* Disable cut-through on ports that are down */ 25068abe1970SVladimir Oltean if (ocelot_port->speed <= 0) 25078abe1970SVladimir Oltean goto set; 25088abe1970SVladimir Oltean 25098abe1970SVladimir Oltean if (dsa_is_cpu_port(ds, port)) { 25108abe1970SVladimir Oltean /* Ocelot switches forward from the NPI port towards 25118abe1970SVladimir Oltean * any port, regardless of it being in the NPI port's 25128abe1970SVladimir Oltean * forwarding domain or not. 25138abe1970SVladimir Oltean */ 25148abe1970SVladimir Oltean mask = dsa_user_ports(ds); 25158abe1970SVladimir Oltean } else { 25168abe1970SVladimir Oltean mask = ocelot_get_bridge_fwd_mask(ocelot, port); 25178abe1970SVladimir Oltean mask &= ~BIT(port); 25188abe1970SVladimir Oltean if (ocelot->npi >= 0) 25198abe1970SVladimir Oltean mask |= BIT(ocelot->npi); 25208abe1970SVladimir Oltean else 2521c295f983SVladimir Oltean mask |= ocelot_port_assigned_dsa_8021q_cpu_mask(ocelot, 2522c295f983SVladimir Oltean port); 25238abe1970SVladimir Oltean } 25248abe1970SVladimir Oltean 25258abe1970SVladimir Oltean /* Calculate the minimum link speed, among the ports that are 25268abe1970SVladimir Oltean * up, of this source port's forwarding domain. 25278abe1970SVladimir Oltean */ 25288abe1970SVladimir Oltean for_each_set_bit(other_port, &mask, ocelot->num_phys_ports) { 25298abe1970SVladimir Oltean struct ocelot_port *other_ocelot_port; 25308abe1970SVladimir Oltean 25318abe1970SVladimir Oltean other_ocelot_port = ocelot->ports[other_port]; 25328abe1970SVladimir Oltean if (other_ocelot_port->speed <= 0) 25338abe1970SVladimir Oltean continue; 25348abe1970SVladimir Oltean 25358abe1970SVladimir Oltean if (min_speed > other_ocelot_port->speed) 25368abe1970SVladimir Oltean min_speed = other_ocelot_port->speed; 25378abe1970SVladimir Oltean } 25388abe1970SVladimir Oltean 2539843794bbSVladimir Oltean /* Enable cut-through forwarding for all traffic classes that 2540843794bbSVladimir Oltean * don't have oversized dropping enabled, since this check is 2541843794bbSVladimir Oltean * bypassed in cut-through mode. 2542843794bbSVladimir Oltean */ 2543843794bbSVladimir Oltean if (ocelot_port->speed == min_speed) { 25448abe1970SVladimir Oltean val = GENMASK(7, 0); 25458abe1970SVladimir Oltean 2546843794bbSVladimir Oltean for (tc = 0; tc < OCELOT_NUM_TC; tc++) 2547843794bbSVladimir Oltean if (vsc9959_port_qmaxsdu_get(ocelot, port, tc)) 2548843794bbSVladimir Oltean val &= ~BIT(tc); 2549843794bbSVladimir Oltean } 2550843794bbSVladimir Oltean 25518abe1970SVladimir Oltean set: 25528abe1970SVladimir Oltean tmp = ocelot_read_rix(ocelot, ANA_CUT_THRU_CFG, port); 25538abe1970SVladimir Oltean if (tmp == val) 25548abe1970SVladimir Oltean continue; 25558abe1970SVladimir Oltean 25568abe1970SVladimir Oltean dev_dbg(ocelot->dev, 2557843794bbSVladimir Oltean "port %d fwd mask 0x%lx speed %d min_speed %d, %s cut-through forwarding on TC mask 0x%x\n", 25588abe1970SVladimir Oltean port, mask, ocelot_port->speed, min_speed, 2559843794bbSVladimir Oltean val ? "enabling" : "disabling", val); 25608abe1970SVladimir Oltean 25618abe1970SVladimir Oltean ocelot_write_rix(ocelot, val, ANA_CUT_THRU_CFG, port); 25628abe1970SVladimir Oltean } 25638abe1970SVladimir Oltean } 25648abe1970SVladimir Oltean 25657d4b564dSXiaoliang Yang static const struct ocelot_ops vsc9959_ops = { 25667d4b564dSXiaoliang Yang .reset = vsc9959_reset, 25677d4b564dSXiaoliang Yang .wm_enc = vsc9959_wm_enc, 25687d4b564dSXiaoliang Yang .wm_dec = vsc9959_wm_dec, 25697d4b564dSXiaoliang Yang .wm_stat = vsc9959_wm_stat, 25707d4b564dSXiaoliang Yang .port_to_netdev = felix_port_to_netdev, 25717d4b564dSXiaoliang Yang .netdev_to_port = felix_netdev_to_port, 25727d4b564dSXiaoliang Yang .psfp_init = vsc9959_psfp_init, 25737d4b564dSXiaoliang Yang .psfp_filter_add = vsc9959_psfp_filter_add, 25747d4b564dSXiaoliang Yang .psfp_filter_del = vsc9959_psfp_filter_del, 25757d4b564dSXiaoliang Yang .psfp_stats_get = vsc9959_psfp_stats_get, 25768abe1970SVladimir Oltean .cut_through_fwd = vsc9959_cut_through_fwd, 25778670dc33SXiaoliang Yang .tas_clock_adjust = vsc9959_tas_clock_adjust, 257825027c84SVladimir Oltean .update_stats = vsc9959_update_stats, 25797d4b564dSXiaoliang Yang }; 25807d4b564dSXiaoliang Yang 2581375e1314SVladimir Oltean static const struct felix_info felix_info_vsc9959 = { 25821109b97bSVladimir Oltean .resources = vsc9959_resources, 25831109b97bSVladimir Oltean .num_resources = ARRAY_SIZE(vsc9959_resources), 25841109b97bSVladimir Oltean .resource_names = vsc9959_resource_names, 258556051948SVladimir Oltean .regfields = vsc9959_regfields, 258656051948SVladimir Oltean .map = vsc9959_regmap, 258756051948SVladimir Oltean .ops = &vsc9959_ops, 258807d985eeSVladimir Oltean .vcap = vsc9959_vcap_props, 258977043c37SXiaoliang Yang .vcap_pol_base = VSC9959_VCAP_POLICER_BASE, 259077043c37SXiaoliang Yang .vcap_pol_max = VSC9959_VCAP_POLICER_MAX, 259177043c37SXiaoliang Yang .vcap_pol_base2 = 0, 259277043c37SXiaoliang Yang .vcap_pol_max2 = 0, 259321ce7f3eSVladimir Oltean .num_mact_rows = 2048, 2594acf242fcSColin Foster .num_ports = VSC9959_NUM_PORTS, 259570d39a6eSVladimir Oltean .num_tx_queues = OCELOT_NUM_TC, 25961dc6a2a0SColin Foster .quirks = FELIX_MAC_QUIRKS, 2597c8c0ba4fSVladimir Oltean .quirk_no_xtr_irq = true, 25982ac7c6c5SVladimir Oltean .ptp_caps = &vsc9959_ptp_caps, 2599bdeced75SVladimir Oltean .mdio_bus_alloc = vsc9959_mdio_bus_alloc, 2600bdeced75SVladimir Oltean .mdio_bus_free = vsc9959_mdio_bus_free, 2601acf242fcSColin Foster .port_modes = vsc9959_port_modes, 2602de143c0eSXiaoliang Yang .port_setup_tc = vsc9959_port_setup_tc, 2603de143c0eSXiaoliang Yang .port_sched_speed_set = vsc9959_sched_speed_set, 260455a515b1SVladimir Oltean .tas_guard_bands_update = vsc9959_tas_guard_bands_update, 260556051948SVladimir Oltean }; 2606375e1314SVladimir Oltean 26076505b680SVladimir Oltean /* The INTB interrupt is shared between for PTP TX timestamp availability 26086505b680SVladimir Oltean * notification and MAC Merge status change on each port. 26096505b680SVladimir Oltean */ 2610375e1314SVladimir Oltean static irqreturn_t felix_irq_handler(int irq, void *data) 2611375e1314SVladimir Oltean { 2612375e1314SVladimir Oltean struct ocelot *ocelot = (struct ocelot *)data; 26136505b680SVladimir Oltean int port; 2614375e1314SVladimir Oltean 2615375e1314SVladimir Oltean ocelot_get_txtstamp(ocelot); 2616375e1314SVladimir Oltean 26176505b680SVladimir Oltean for (port = 0; port < ocelot->num_phys_ports; port++) 26186505b680SVladimir Oltean ocelot_port_mm_irq(ocelot, port); 26196505b680SVladimir Oltean 2620375e1314SVladimir Oltean return IRQ_HANDLED; 2621375e1314SVladimir Oltean } 2622375e1314SVladimir Oltean 2623375e1314SVladimir Oltean static int felix_pci_probe(struct pci_dev *pdev, 2624375e1314SVladimir Oltean const struct pci_device_id *id) 2625375e1314SVladimir Oltean { 2626375e1314SVladimir Oltean struct dsa_switch *ds; 2627375e1314SVladimir Oltean struct ocelot *ocelot; 2628375e1314SVladimir Oltean struct felix *felix; 2629375e1314SVladimir Oltean int err; 2630375e1314SVladimir Oltean 2631375e1314SVladimir Oltean if (pdev->dev.of_node && !of_device_is_available(pdev->dev.of_node)) { 2632375e1314SVladimir Oltean dev_info(&pdev->dev, "device is disabled, skipping\n"); 2633375e1314SVladimir Oltean return -ENODEV; 2634375e1314SVladimir Oltean } 2635375e1314SVladimir Oltean 2636375e1314SVladimir Oltean err = pci_enable_device(pdev); 2637375e1314SVladimir Oltean if (err) { 2638375e1314SVladimir Oltean dev_err(&pdev->dev, "device enable failed\n"); 2639375e1314SVladimir Oltean goto err_pci_enable; 2640375e1314SVladimir Oltean } 2641375e1314SVladimir Oltean 2642375e1314SVladimir Oltean felix = kzalloc(sizeof(struct felix), GFP_KERNEL); 2643375e1314SVladimir Oltean if (!felix) { 2644375e1314SVladimir Oltean err = -ENOMEM; 2645375e1314SVladimir Oltean dev_err(&pdev->dev, "Failed to allocate driver memory\n"); 2646375e1314SVladimir Oltean goto err_alloc_felix; 2647375e1314SVladimir Oltean } 2648375e1314SVladimir Oltean 2649375e1314SVladimir Oltean pci_set_drvdata(pdev, felix); 2650375e1314SVladimir Oltean ocelot = &felix->ocelot; 2651375e1314SVladimir Oltean ocelot->dev = &pdev->dev; 265270d39a6eSVladimir Oltean ocelot->num_flooding_pgids = OCELOT_NUM_TC; 2653375e1314SVladimir Oltean felix->info = &felix_info_vsc9959; 2654c9910484SColin Foster felix->switch_base = pci_resource_start(pdev, VSC9959_SWITCH_PCI_BAR); 2655375e1314SVladimir Oltean 2656375e1314SVladimir Oltean pci_set_master(pdev); 2657375e1314SVladimir Oltean 2658375e1314SVladimir Oltean err = devm_request_threaded_irq(&pdev->dev, pdev->irq, NULL, 2659375e1314SVladimir Oltean &felix_irq_handler, IRQF_ONESHOT, 2660375e1314SVladimir Oltean "felix-intb", ocelot); 2661375e1314SVladimir Oltean if (err) { 2662375e1314SVladimir Oltean dev_err(&pdev->dev, "Failed to request irq\n"); 2663375e1314SVladimir Oltean goto err_alloc_irq; 2664375e1314SVladimir Oltean } 2665375e1314SVladimir Oltean 2666375e1314SVladimir Oltean ocelot->ptp = 1; 2667ab3f97a9SVladimir Oltean ocelot->mm_supported = true; 2668375e1314SVladimir Oltean 2669375e1314SVladimir Oltean ds = kzalloc(sizeof(struct dsa_switch), GFP_KERNEL); 2670375e1314SVladimir Oltean if (!ds) { 2671375e1314SVladimir Oltean err = -ENOMEM; 2672375e1314SVladimir Oltean dev_err(&pdev->dev, "Failed to allocate DSA switch\n"); 2673375e1314SVladimir Oltean goto err_alloc_ds; 2674375e1314SVladimir Oltean } 2675375e1314SVladimir Oltean 2676375e1314SVladimir Oltean ds->dev = &pdev->dev; 2677375e1314SVladimir Oltean ds->num_ports = felix->info->num_ports; 2678375e1314SVladimir Oltean ds->num_tx_queues = felix->info->num_tx_queues; 2679375e1314SVladimir Oltean ds->ops = &felix_switch_ops; 2680375e1314SVladimir Oltean ds->priv = ocelot; 2681375e1314SVladimir Oltean felix->ds = ds; 2682adb3dccfSVladimir Oltean felix->tag_proto = DSA_TAG_PROTO_OCELOT; 2683375e1314SVladimir Oltean 2684375e1314SVladimir Oltean err = dsa_register_switch(ds); 2685375e1314SVladimir Oltean if (err) { 2686e6934e40SMichael Walle dev_err_probe(&pdev->dev, err, "Failed to register DSA switch\n"); 2687375e1314SVladimir Oltean goto err_register_ds; 2688375e1314SVladimir Oltean } 2689375e1314SVladimir Oltean 2690375e1314SVladimir Oltean return 0; 2691375e1314SVladimir Oltean 2692375e1314SVladimir Oltean err_register_ds: 2693375e1314SVladimir Oltean kfree(ds); 2694375e1314SVladimir Oltean err_alloc_ds: 2695375e1314SVladimir Oltean err_alloc_irq: 2696375e1314SVladimir Oltean kfree(felix); 2697537e2b88SVladimir Oltean err_alloc_felix: 2698375e1314SVladimir Oltean pci_disable_device(pdev); 2699375e1314SVladimir Oltean err_pci_enable: 2700375e1314SVladimir Oltean return err; 2701375e1314SVladimir Oltean } 2702375e1314SVladimir Oltean 2703375e1314SVladimir Oltean static void felix_pci_remove(struct pci_dev *pdev) 2704375e1314SVladimir Oltean { 27050650bf52SVladimir Oltean struct felix *felix = pci_get_drvdata(pdev); 2706375e1314SVladimir Oltean 27070650bf52SVladimir Oltean if (!felix) 27080650bf52SVladimir Oltean return; 2709375e1314SVladimir Oltean 2710375e1314SVladimir Oltean dsa_unregister_switch(felix->ds); 2711375e1314SVladimir Oltean 2712375e1314SVladimir Oltean kfree(felix->ds); 2713375e1314SVladimir Oltean kfree(felix); 2714375e1314SVladimir Oltean 2715375e1314SVladimir Oltean pci_disable_device(pdev); 27160650bf52SVladimir Oltean } 27170650bf52SVladimir Oltean 27180650bf52SVladimir Oltean static void felix_pci_shutdown(struct pci_dev *pdev) 27190650bf52SVladimir Oltean { 27200650bf52SVladimir Oltean struct felix *felix = pci_get_drvdata(pdev); 27210650bf52SVladimir Oltean 27220650bf52SVladimir Oltean if (!felix) 27230650bf52SVladimir Oltean return; 27240650bf52SVladimir Oltean 27250650bf52SVladimir Oltean dsa_switch_shutdown(felix->ds); 27260650bf52SVladimir Oltean 27270650bf52SVladimir Oltean pci_set_drvdata(pdev, NULL); 2728375e1314SVladimir Oltean } 2729375e1314SVladimir Oltean 2730375e1314SVladimir Oltean static struct pci_device_id felix_ids[] = { 2731375e1314SVladimir Oltean { 2732375e1314SVladimir Oltean /* NXP LS1028A */ 2733375e1314SVladimir Oltean PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0xEEF0), 2734375e1314SVladimir Oltean }, 2735375e1314SVladimir Oltean { 0, } 2736375e1314SVladimir Oltean }; 2737375e1314SVladimir Oltean MODULE_DEVICE_TABLE(pci, felix_ids); 2738375e1314SVladimir Oltean 2739d60bc62dSVladimir Oltean static struct pci_driver felix_vsc9959_pci_driver = { 2740375e1314SVladimir Oltean .name = "mscc_felix", 2741375e1314SVladimir Oltean .id_table = felix_ids, 2742375e1314SVladimir Oltean .probe = felix_pci_probe, 2743375e1314SVladimir Oltean .remove = felix_pci_remove, 27440650bf52SVladimir Oltean .shutdown = felix_pci_shutdown, 2745375e1314SVladimir Oltean }; 2746d60bc62dSVladimir Oltean module_pci_driver(felix_vsc9959_pci_driver); 2747d60bc62dSVladimir Oltean 2748d60bc62dSVladimir Oltean MODULE_DESCRIPTION("Felix Switch driver"); 2749d60bc62dSVladimir Oltean MODULE_LICENSE("GPL v2"); 2750