156051948SVladimir Oltean // SPDX-License-Identifier: (GPL-2.0 OR MIT) 256051948SVladimir Oltean /* Copyright 2017 Microsemi Corporation 33c9cfb52SVladimir Oltean * Copyright 2018-2019 NXP 456051948SVladimir Oltean */ 5bdeced75SVladimir Oltean #include <linux/fsl/enetc_mdio.h> 6de143c0eSXiaoliang Yang #include <soc/mscc/ocelot_qsys.h> 707d985eeSVladimir Oltean #include <soc/mscc/ocelot_vcap.h> 87d4b564dSXiaoliang Yang #include <soc/mscc/ocelot_ana.h> 9de143c0eSXiaoliang Yang #include <soc/mscc/ocelot_ptp.h> 1056051948SVladimir Oltean #include <soc/mscc/ocelot_sys.h> 1123ae3a78SXiaoliang Yang #include <net/tc_act/tc_gate.h> 1256051948SVladimir Oltean #include <soc/mscc/ocelot.h> 1340d3f295SVladimir Oltean #include <linux/dsa/ocelot.h> 14588d0550SIoana Ciornei #include <linux/pcs-lynx.h> 15de143c0eSXiaoliang Yang #include <net/pkt_sched.h> 1656051948SVladimir Oltean #include <linux/iopoll.h> 1716659b81SMichael Walle #include <linux/mdio.h> 1856051948SVladimir Oltean #include <linux/pci.h> 19837ced3aSVladimir Oltean #include <linux/time.h> 2056051948SVladimir Oltean #include "felix.h" 2156051948SVladimir Oltean 22acf242fcSColin Foster #define VSC9959_NUM_PORTS 6 23acf242fcSColin Foster 24de143c0eSXiaoliang Yang #define VSC9959_TAS_GCL_ENTRY_MAX 63 2511afdc65SVladimir Oltean #define VSC9959_TAS_MIN_GATE_LEN_NS 33 2677043c37SXiaoliang Yang #define VSC9959_VCAP_POLICER_BASE 63 2777043c37SXiaoliang Yang #define VSC9959_VCAP_POLICER_MAX 383 28c9910484SColin Foster #define VSC9959_SWITCH_PCI_BAR 4 29c9910484SColin Foster #define VSC9959_IMDIO_PCI_BAR 0 30de143c0eSXiaoliang Yang 31acf242fcSColin Foster #define VSC9959_PORT_MODE_SERDES (OCELOT_PORT_MODE_SGMII | \ 32acf242fcSColin Foster OCELOT_PORT_MODE_QSGMII | \ 3311ecf341SVladimir Oltean OCELOT_PORT_MODE_1000BASEX | \ 34acf242fcSColin Foster OCELOT_PORT_MODE_2500BASEX | \ 35acf242fcSColin Foster OCELOT_PORT_MODE_USXGMII) 36acf242fcSColin Foster 37acf242fcSColin Foster static const u32 vsc9959_port_modes[VSC9959_NUM_PORTS] = { 38acf242fcSColin Foster VSC9959_PORT_MODE_SERDES, 39acf242fcSColin Foster VSC9959_PORT_MODE_SERDES, 40acf242fcSColin Foster VSC9959_PORT_MODE_SERDES, 41acf242fcSColin Foster VSC9959_PORT_MODE_SERDES, 42acf242fcSColin Foster OCELOT_PORT_MODE_INTERNAL, 43a53cbe5dSVladimir Oltean OCELOT_PORT_MODE_INTERNAL, 44acf242fcSColin Foster }; 45acf242fcSColin Foster 4656051948SVladimir Oltean static const u32 vsc9959_ana_regmap[] = { 4756051948SVladimir Oltean REG(ANA_ADVLEARN, 0x0089a0), 4856051948SVladimir Oltean REG(ANA_VLANMASK, 0x0089a4), 4956051948SVladimir Oltean REG_RESERVED(ANA_PORT_B_DOMAIN), 5056051948SVladimir Oltean REG(ANA_ANAGEFIL, 0x0089ac), 5156051948SVladimir Oltean REG(ANA_ANEVENTS, 0x0089b0), 5256051948SVladimir Oltean REG(ANA_STORMLIMIT_BURST, 0x0089b4), 5356051948SVladimir Oltean REG(ANA_STORMLIMIT_CFG, 0x0089b8), 5456051948SVladimir Oltean REG(ANA_ISOLATED_PORTS, 0x0089c8), 5556051948SVladimir Oltean REG(ANA_COMMUNITY_PORTS, 0x0089cc), 5656051948SVladimir Oltean REG(ANA_AUTOAGE, 0x0089d0), 5756051948SVladimir Oltean REG(ANA_MACTOPTIONS, 0x0089d4), 5856051948SVladimir Oltean REG(ANA_LEARNDISC, 0x0089d8), 5956051948SVladimir Oltean REG(ANA_AGENCTRL, 0x0089dc), 6056051948SVladimir Oltean REG(ANA_MIRRORPORTS, 0x0089e0), 6156051948SVladimir Oltean REG(ANA_EMIRRORPORTS, 0x0089e4), 6256051948SVladimir Oltean REG(ANA_FLOODING, 0x0089e8), 6356051948SVladimir Oltean REG(ANA_FLOODING_IPMC, 0x008a08), 6456051948SVladimir Oltean REG(ANA_SFLOW_CFG, 0x008a0c), 6556051948SVladimir Oltean REG(ANA_PORT_MODE, 0x008a28), 6656051948SVladimir Oltean REG(ANA_CUT_THRU_CFG, 0x008a48), 6756051948SVladimir Oltean REG(ANA_PGID_PGID, 0x008400), 6856051948SVladimir Oltean REG(ANA_TABLES_ANMOVED, 0x007f1c), 6956051948SVladimir Oltean REG(ANA_TABLES_MACHDATA, 0x007f20), 7056051948SVladimir Oltean REG(ANA_TABLES_MACLDATA, 0x007f24), 7156051948SVladimir Oltean REG(ANA_TABLES_STREAMDATA, 0x007f28), 7256051948SVladimir Oltean REG(ANA_TABLES_MACACCESS, 0x007f2c), 7356051948SVladimir Oltean REG(ANA_TABLES_MACTINDX, 0x007f30), 7456051948SVladimir Oltean REG(ANA_TABLES_VLANACCESS, 0x007f34), 7556051948SVladimir Oltean REG(ANA_TABLES_VLANTIDX, 0x007f38), 7656051948SVladimir Oltean REG(ANA_TABLES_ISDXACCESS, 0x007f3c), 7756051948SVladimir Oltean REG(ANA_TABLES_ISDXTIDX, 0x007f40), 7856051948SVladimir Oltean REG(ANA_TABLES_ENTRYLIM, 0x007f00), 7956051948SVladimir Oltean REG(ANA_TABLES_PTP_ID_HIGH, 0x007f44), 8056051948SVladimir Oltean REG(ANA_TABLES_PTP_ID_LOW, 0x007f48), 8156051948SVladimir Oltean REG(ANA_TABLES_STREAMACCESS, 0x007f4c), 8256051948SVladimir Oltean REG(ANA_TABLES_STREAMTIDX, 0x007f50), 8356051948SVladimir Oltean REG(ANA_TABLES_SEQ_HISTORY, 0x007f54), 8456051948SVladimir Oltean REG(ANA_TABLES_SEQ_MASK, 0x007f58), 8556051948SVladimir Oltean REG(ANA_TABLES_SFID_MASK, 0x007f5c), 8656051948SVladimir Oltean REG(ANA_TABLES_SFIDACCESS, 0x007f60), 8756051948SVladimir Oltean REG(ANA_TABLES_SFIDTIDX, 0x007f64), 8856051948SVladimir Oltean REG(ANA_MSTI_STATE, 0x008600), 8956051948SVladimir Oltean REG(ANA_OAM_UPM_LM_CNT, 0x008000), 9056051948SVladimir Oltean REG(ANA_SG_ACCESS_CTRL, 0x008a64), 9156051948SVladimir Oltean REG(ANA_SG_CONFIG_REG_1, 0x007fb0), 9256051948SVladimir Oltean REG(ANA_SG_CONFIG_REG_2, 0x007fb4), 9356051948SVladimir Oltean REG(ANA_SG_CONFIG_REG_3, 0x007fb8), 9456051948SVladimir Oltean REG(ANA_SG_CONFIG_REG_4, 0x007fbc), 9556051948SVladimir Oltean REG(ANA_SG_CONFIG_REG_5, 0x007fc0), 9656051948SVladimir Oltean REG(ANA_SG_GCL_GS_CONFIG, 0x007f80), 9756051948SVladimir Oltean REG(ANA_SG_GCL_TI_CONFIG, 0x007f90), 9856051948SVladimir Oltean REG(ANA_SG_STATUS_REG_1, 0x008980), 9956051948SVladimir Oltean REG(ANA_SG_STATUS_REG_2, 0x008984), 10056051948SVladimir Oltean REG(ANA_SG_STATUS_REG_3, 0x008988), 10156051948SVladimir Oltean REG(ANA_PORT_VLAN_CFG, 0x007800), 10256051948SVladimir Oltean REG(ANA_PORT_DROP_CFG, 0x007804), 10356051948SVladimir Oltean REG(ANA_PORT_QOS_CFG, 0x007808), 10456051948SVladimir Oltean REG(ANA_PORT_VCAP_CFG, 0x00780c), 10556051948SVladimir Oltean REG(ANA_PORT_VCAP_S1_KEY_CFG, 0x007810), 10656051948SVladimir Oltean REG(ANA_PORT_VCAP_S2_CFG, 0x00781c), 10756051948SVladimir Oltean REG(ANA_PORT_PCP_DEI_MAP, 0x007820), 10856051948SVladimir Oltean REG(ANA_PORT_CPU_FWD_CFG, 0x007860), 10956051948SVladimir Oltean REG(ANA_PORT_CPU_FWD_BPDU_CFG, 0x007864), 11056051948SVladimir Oltean REG(ANA_PORT_CPU_FWD_GARP_CFG, 0x007868), 11156051948SVladimir Oltean REG(ANA_PORT_CPU_FWD_CCM_CFG, 0x00786c), 11256051948SVladimir Oltean REG(ANA_PORT_PORT_CFG, 0x007870), 11356051948SVladimir Oltean REG(ANA_PORT_POL_CFG, 0x007874), 11456051948SVladimir Oltean REG(ANA_PORT_PTP_CFG, 0x007878), 11556051948SVladimir Oltean REG(ANA_PORT_PTP_DLY1_CFG, 0x00787c), 11656051948SVladimir Oltean REG(ANA_PORT_PTP_DLY2_CFG, 0x007880), 11756051948SVladimir Oltean REG(ANA_PORT_SFID_CFG, 0x007884), 11856051948SVladimir Oltean REG(ANA_PFC_PFC_CFG, 0x008800), 11956051948SVladimir Oltean REG_RESERVED(ANA_PFC_PFC_TIMER), 12056051948SVladimir Oltean REG_RESERVED(ANA_IPT_OAM_MEP_CFG), 12156051948SVladimir Oltean REG_RESERVED(ANA_IPT_IPT), 12256051948SVladimir Oltean REG_RESERVED(ANA_PPT_PPT), 12356051948SVladimir Oltean REG_RESERVED(ANA_FID_MAP_FID_MAP), 12456051948SVladimir Oltean REG(ANA_AGGR_CFG, 0x008a68), 12556051948SVladimir Oltean REG(ANA_CPUQ_CFG, 0x008a6c), 12656051948SVladimir Oltean REG_RESERVED(ANA_CPUQ_CFG2), 12756051948SVladimir Oltean REG(ANA_CPUQ_8021_CFG, 0x008a74), 12856051948SVladimir Oltean REG(ANA_DSCP_CFG, 0x008ab4), 12956051948SVladimir Oltean REG(ANA_DSCP_REWR_CFG, 0x008bb4), 13056051948SVladimir Oltean REG(ANA_VCAP_RNG_TYPE_CFG, 0x008bf4), 13156051948SVladimir Oltean REG(ANA_VCAP_RNG_VAL_CFG, 0x008c14), 13256051948SVladimir Oltean REG_RESERVED(ANA_VRAP_CFG), 13356051948SVladimir Oltean REG_RESERVED(ANA_VRAP_HDR_DATA), 13456051948SVladimir Oltean REG_RESERVED(ANA_VRAP_HDR_MASK), 13556051948SVladimir Oltean REG(ANA_DISCARD_CFG, 0x008c40), 13656051948SVladimir Oltean REG(ANA_FID_CFG, 0x008c44), 13756051948SVladimir Oltean REG(ANA_POL_PIR_CFG, 0x004000), 13856051948SVladimir Oltean REG(ANA_POL_CIR_CFG, 0x004004), 13956051948SVladimir Oltean REG(ANA_POL_MODE_CFG, 0x004008), 14056051948SVladimir Oltean REG(ANA_POL_PIR_STATE, 0x00400c), 14156051948SVladimir Oltean REG(ANA_POL_CIR_STATE, 0x004010), 14256051948SVladimir Oltean REG_RESERVED(ANA_POL_STATE), 14356051948SVladimir Oltean REG(ANA_POL_FLOWC, 0x008c48), 14456051948SVladimir Oltean REG(ANA_POL_HYST, 0x008cb4), 14556051948SVladimir Oltean REG_RESERVED(ANA_POL_MISC_CFG), 14656051948SVladimir Oltean }; 14756051948SVladimir Oltean 14856051948SVladimir Oltean static const u32 vsc9959_qs_regmap[] = { 14956051948SVladimir Oltean REG(QS_XTR_GRP_CFG, 0x000000), 15056051948SVladimir Oltean REG(QS_XTR_RD, 0x000008), 15156051948SVladimir Oltean REG(QS_XTR_FRM_PRUNING, 0x000010), 15256051948SVladimir Oltean REG(QS_XTR_FLUSH, 0x000018), 15356051948SVladimir Oltean REG(QS_XTR_DATA_PRESENT, 0x00001c), 15456051948SVladimir Oltean REG(QS_XTR_CFG, 0x000020), 15556051948SVladimir Oltean REG(QS_INJ_GRP_CFG, 0x000024), 15656051948SVladimir Oltean REG(QS_INJ_WR, 0x00002c), 15756051948SVladimir Oltean REG(QS_INJ_CTRL, 0x000034), 15856051948SVladimir Oltean REG(QS_INJ_STATUS, 0x00003c), 15956051948SVladimir Oltean REG(QS_INJ_ERR, 0x000040), 16056051948SVladimir Oltean REG_RESERVED(QS_INH_DBG), 16156051948SVladimir Oltean }; 16256051948SVladimir Oltean 163c1c3993eSVladimir Oltean static const u32 vsc9959_vcap_regmap[] = { 164c1c3993eSVladimir Oltean /* VCAP_CORE_CFG */ 165c1c3993eSVladimir Oltean REG(VCAP_CORE_UPDATE_CTRL, 0x000000), 166c1c3993eSVladimir Oltean REG(VCAP_CORE_MV_CFG, 0x000004), 167c1c3993eSVladimir Oltean /* VCAP_CORE_CACHE */ 168c1c3993eSVladimir Oltean REG(VCAP_CACHE_ENTRY_DAT, 0x000008), 169c1c3993eSVladimir Oltean REG(VCAP_CACHE_MASK_DAT, 0x000108), 170c1c3993eSVladimir Oltean REG(VCAP_CACHE_ACTION_DAT, 0x000208), 171c1c3993eSVladimir Oltean REG(VCAP_CACHE_CNT_DAT, 0x000308), 172c1c3993eSVladimir Oltean REG(VCAP_CACHE_TG_DAT, 0x000388), 17320968054SVladimir Oltean /* VCAP_CONST */ 17420968054SVladimir Oltean REG(VCAP_CONST_VCAP_VER, 0x000398), 17520968054SVladimir Oltean REG(VCAP_CONST_ENTRY_WIDTH, 0x00039c), 17620968054SVladimir Oltean REG(VCAP_CONST_ENTRY_CNT, 0x0003a0), 17720968054SVladimir Oltean REG(VCAP_CONST_ENTRY_SWCNT, 0x0003a4), 17820968054SVladimir Oltean REG(VCAP_CONST_ENTRY_TG_WIDTH, 0x0003a8), 17920968054SVladimir Oltean REG(VCAP_CONST_ACTION_DEF_CNT, 0x0003ac), 18020968054SVladimir Oltean REG(VCAP_CONST_ACTION_WIDTH, 0x0003b0), 18120968054SVladimir Oltean REG(VCAP_CONST_CNT_WIDTH, 0x0003b4), 18220968054SVladimir Oltean REG(VCAP_CONST_CORE_CNT, 0x0003b8), 18320968054SVladimir Oltean REG(VCAP_CONST_IF_CNT, 0x0003bc), 18456051948SVladimir Oltean }; 18556051948SVladimir Oltean 18656051948SVladimir Oltean static const u32 vsc9959_qsys_regmap[] = { 18756051948SVladimir Oltean REG(QSYS_PORT_MODE, 0x00f460), 18856051948SVladimir Oltean REG(QSYS_SWITCH_PORT_MODE, 0x00f480), 18956051948SVladimir Oltean REG(QSYS_STAT_CNT_CFG, 0x00f49c), 19056051948SVladimir Oltean REG(QSYS_EEE_CFG, 0x00f4a0), 19156051948SVladimir Oltean REG(QSYS_EEE_THRES, 0x00f4b8), 19256051948SVladimir Oltean REG(QSYS_IGR_NO_SHARING, 0x00f4bc), 19356051948SVladimir Oltean REG(QSYS_EGR_NO_SHARING, 0x00f4c0), 19456051948SVladimir Oltean REG(QSYS_SW_STATUS, 0x00f4c4), 19556051948SVladimir Oltean REG(QSYS_EXT_CPU_CFG, 0x00f4e0), 19656051948SVladimir Oltean REG_RESERVED(QSYS_PAD_CFG), 19756051948SVladimir Oltean REG(QSYS_CPU_GROUP_MAP, 0x00f4e8), 19856051948SVladimir Oltean REG_RESERVED(QSYS_QMAP), 19956051948SVladimir Oltean REG_RESERVED(QSYS_ISDX_SGRP), 20056051948SVladimir Oltean REG_RESERVED(QSYS_TIMED_FRAME_ENTRY), 20156051948SVladimir Oltean REG(QSYS_TFRM_MISC, 0x00f50c), 20256051948SVladimir Oltean REG(QSYS_TFRM_PORT_DLY, 0x00f510), 20356051948SVladimir Oltean REG(QSYS_TFRM_TIMER_CFG_1, 0x00f514), 20456051948SVladimir Oltean REG(QSYS_TFRM_TIMER_CFG_2, 0x00f518), 20556051948SVladimir Oltean REG(QSYS_TFRM_TIMER_CFG_3, 0x00f51c), 20656051948SVladimir Oltean REG(QSYS_TFRM_TIMER_CFG_4, 0x00f520), 20756051948SVladimir Oltean REG(QSYS_TFRM_TIMER_CFG_5, 0x00f524), 20856051948SVladimir Oltean REG(QSYS_TFRM_TIMER_CFG_6, 0x00f528), 20956051948SVladimir Oltean REG(QSYS_TFRM_TIMER_CFG_7, 0x00f52c), 21056051948SVladimir Oltean REG(QSYS_TFRM_TIMER_CFG_8, 0x00f530), 21156051948SVladimir Oltean REG(QSYS_RED_PROFILE, 0x00f534), 21256051948SVladimir Oltean REG(QSYS_RES_QOS_MODE, 0x00f574), 21356051948SVladimir Oltean REG(QSYS_RES_CFG, 0x00c000), 21456051948SVladimir Oltean REG(QSYS_RES_STAT, 0x00c004), 21556051948SVladimir Oltean REG(QSYS_EGR_DROP_MODE, 0x00f578), 21656051948SVladimir Oltean REG(QSYS_EQ_CTRL, 0x00f57c), 21756051948SVladimir Oltean REG_RESERVED(QSYS_EVENTS_CORE), 21856051948SVladimir Oltean REG(QSYS_QMAXSDU_CFG_0, 0x00f584), 21956051948SVladimir Oltean REG(QSYS_QMAXSDU_CFG_1, 0x00f5a0), 22056051948SVladimir Oltean REG(QSYS_QMAXSDU_CFG_2, 0x00f5bc), 22156051948SVladimir Oltean REG(QSYS_QMAXSDU_CFG_3, 0x00f5d8), 22256051948SVladimir Oltean REG(QSYS_QMAXSDU_CFG_4, 0x00f5f4), 22356051948SVladimir Oltean REG(QSYS_QMAXSDU_CFG_5, 0x00f610), 22456051948SVladimir Oltean REG(QSYS_QMAXSDU_CFG_6, 0x00f62c), 22556051948SVladimir Oltean REG(QSYS_QMAXSDU_CFG_7, 0x00f648), 22656051948SVladimir Oltean REG(QSYS_PREEMPTION_CFG, 0x00f664), 2270fbabf87SXiaoliang Yang REG(QSYS_CIR_CFG, 0x000000), 22856051948SVladimir Oltean REG(QSYS_EIR_CFG, 0x000004), 22956051948SVladimir Oltean REG(QSYS_SE_CFG, 0x000008), 23056051948SVladimir Oltean REG(QSYS_SE_DWRR_CFG, 0x00000c), 23156051948SVladimir Oltean REG_RESERVED(QSYS_SE_CONNECT), 23256051948SVladimir Oltean REG(QSYS_SE_DLB_SENSE, 0x000040), 23356051948SVladimir Oltean REG(QSYS_CIR_STATE, 0x000044), 23456051948SVladimir Oltean REG(QSYS_EIR_STATE, 0x000048), 23556051948SVladimir Oltean REG_RESERVED(QSYS_SE_STATE), 23656051948SVladimir Oltean REG(QSYS_HSCH_MISC_CFG, 0x00f67c), 23756051948SVladimir Oltean REG(QSYS_TAG_CONFIG, 0x00f680), 23856051948SVladimir Oltean REG(QSYS_TAS_PARAM_CFG_CTRL, 0x00f698), 23956051948SVladimir Oltean REG(QSYS_PORT_MAX_SDU, 0x00f69c), 24056051948SVladimir Oltean REG(QSYS_PARAM_CFG_REG_1, 0x00f440), 24156051948SVladimir Oltean REG(QSYS_PARAM_CFG_REG_2, 0x00f444), 24256051948SVladimir Oltean REG(QSYS_PARAM_CFG_REG_3, 0x00f448), 24356051948SVladimir Oltean REG(QSYS_PARAM_CFG_REG_4, 0x00f44c), 24456051948SVladimir Oltean REG(QSYS_PARAM_CFG_REG_5, 0x00f450), 24556051948SVladimir Oltean REG(QSYS_GCL_CFG_REG_1, 0x00f454), 24656051948SVladimir Oltean REG(QSYS_GCL_CFG_REG_2, 0x00f458), 24756051948SVladimir Oltean REG(QSYS_PARAM_STATUS_REG_1, 0x00f400), 24856051948SVladimir Oltean REG(QSYS_PARAM_STATUS_REG_2, 0x00f404), 24956051948SVladimir Oltean REG(QSYS_PARAM_STATUS_REG_3, 0x00f408), 25056051948SVladimir Oltean REG(QSYS_PARAM_STATUS_REG_4, 0x00f40c), 25156051948SVladimir Oltean REG(QSYS_PARAM_STATUS_REG_5, 0x00f410), 25256051948SVladimir Oltean REG(QSYS_PARAM_STATUS_REG_6, 0x00f414), 25356051948SVladimir Oltean REG(QSYS_PARAM_STATUS_REG_7, 0x00f418), 25456051948SVladimir Oltean REG(QSYS_PARAM_STATUS_REG_8, 0x00f41c), 25556051948SVladimir Oltean REG(QSYS_PARAM_STATUS_REG_9, 0x00f420), 25656051948SVladimir Oltean REG(QSYS_GCL_STATUS_REG_1, 0x00f424), 25756051948SVladimir Oltean REG(QSYS_GCL_STATUS_REG_2, 0x00f428), 25856051948SVladimir Oltean }; 25956051948SVladimir Oltean 26056051948SVladimir Oltean static const u32 vsc9959_rew_regmap[] = { 26156051948SVladimir Oltean REG(REW_PORT_VLAN_CFG, 0x000000), 26256051948SVladimir Oltean REG(REW_TAG_CFG, 0x000004), 26356051948SVladimir Oltean REG(REW_PORT_CFG, 0x000008), 26456051948SVladimir Oltean REG(REW_DSCP_CFG, 0x00000c), 26556051948SVladimir Oltean REG(REW_PCP_DEI_QOS_MAP_CFG, 0x000010), 26656051948SVladimir Oltean REG(REW_PTP_CFG, 0x000050), 26756051948SVladimir Oltean REG(REW_PTP_DLY1_CFG, 0x000054), 26856051948SVladimir Oltean REG(REW_RED_TAG_CFG, 0x000058), 26956051948SVladimir Oltean REG(REW_DSCP_REMAP_DP1_CFG, 0x000410), 27056051948SVladimir Oltean REG(REW_DSCP_REMAP_CFG, 0x000510), 27156051948SVladimir Oltean REG_RESERVED(REW_STAT_CFG), 27256051948SVladimir Oltean REG_RESERVED(REW_REW_STICKY), 27356051948SVladimir Oltean REG_RESERVED(REW_PPT), 27456051948SVladimir Oltean }; 27556051948SVladimir Oltean 27656051948SVladimir Oltean static const u32 vsc9959_sys_regmap[] = { 27756051948SVladimir Oltean REG(SYS_COUNT_RX_OCTETS, 0x000000), 278d4c36765SVladimir Oltean REG(SYS_COUNT_RX_UNICAST, 0x000004), 27956051948SVladimir Oltean REG(SYS_COUNT_RX_MULTICAST, 0x000008), 280d4c36765SVladimir Oltean REG(SYS_COUNT_RX_BROADCAST, 0x00000c), 28156051948SVladimir Oltean REG(SYS_COUNT_RX_SHORTS, 0x000010), 28256051948SVladimir Oltean REG(SYS_COUNT_RX_FRAGMENTS, 0x000014), 28356051948SVladimir Oltean REG(SYS_COUNT_RX_JABBERS, 0x000018), 284d4c36765SVladimir Oltean REG(SYS_COUNT_RX_CRC_ALIGN_ERRS, 0x00001c), 285d4c36765SVladimir Oltean REG(SYS_COUNT_RX_SYM_ERRS, 0x000020), 28656051948SVladimir Oltean REG(SYS_COUNT_RX_64, 0x000024), 28756051948SVladimir Oltean REG(SYS_COUNT_RX_65_127, 0x000028), 28856051948SVladimir Oltean REG(SYS_COUNT_RX_128_255, 0x00002c), 2895152de7bSVladimir Oltean REG(SYS_COUNT_RX_256_511, 0x000030), 2905152de7bSVladimir Oltean REG(SYS_COUNT_RX_512_1023, 0x000034), 2915152de7bSVladimir Oltean REG(SYS_COUNT_RX_1024_1526, 0x000038), 2925152de7bSVladimir Oltean REG(SYS_COUNT_RX_1527_MAX, 0x00003c), 2935152de7bSVladimir Oltean REG(SYS_COUNT_RX_PAUSE, 0x000040), 2945152de7bSVladimir Oltean REG(SYS_COUNT_RX_CONTROL, 0x000044), 2955152de7bSVladimir Oltean REG(SYS_COUNT_RX_LONGS, 0x000048), 296d4c36765SVladimir Oltean REG(SYS_COUNT_RX_CLASSIFIED_DROPS, 0x00004c), 297d4c36765SVladimir Oltean REG(SYS_COUNT_RX_RED_PRIO_0, 0x000050), 298d4c36765SVladimir Oltean REG(SYS_COUNT_RX_RED_PRIO_1, 0x000054), 299d4c36765SVladimir Oltean REG(SYS_COUNT_RX_RED_PRIO_2, 0x000058), 300d4c36765SVladimir Oltean REG(SYS_COUNT_RX_RED_PRIO_3, 0x00005c), 301d4c36765SVladimir Oltean REG(SYS_COUNT_RX_RED_PRIO_4, 0x000060), 302d4c36765SVladimir Oltean REG(SYS_COUNT_RX_RED_PRIO_5, 0x000064), 303d4c36765SVladimir Oltean REG(SYS_COUNT_RX_RED_PRIO_6, 0x000068), 304d4c36765SVladimir Oltean REG(SYS_COUNT_RX_RED_PRIO_7, 0x00006c), 305d4c36765SVladimir Oltean REG(SYS_COUNT_RX_YELLOW_PRIO_0, 0x000070), 306d4c36765SVladimir Oltean REG(SYS_COUNT_RX_YELLOW_PRIO_1, 0x000074), 307d4c36765SVladimir Oltean REG(SYS_COUNT_RX_YELLOW_PRIO_2, 0x000078), 308d4c36765SVladimir Oltean REG(SYS_COUNT_RX_YELLOW_PRIO_3, 0x00007c), 309d4c36765SVladimir Oltean REG(SYS_COUNT_RX_YELLOW_PRIO_4, 0x000080), 310d4c36765SVladimir Oltean REG(SYS_COUNT_RX_YELLOW_PRIO_5, 0x000084), 311d4c36765SVladimir Oltean REG(SYS_COUNT_RX_YELLOW_PRIO_6, 0x000088), 312d4c36765SVladimir Oltean REG(SYS_COUNT_RX_YELLOW_PRIO_7, 0x00008c), 313d4c36765SVladimir Oltean REG(SYS_COUNT_RX_GREEN_PRIO_0, 0x000090), 314d4c36765SVladimir Oltean REG(SYS_COUNT_RX_GREEN_PRIO_1, 0x000094), 315d4c36765SVladimir Oltean REG(SYS_COUNT_RX_GREEN_PRIO_2, 0x000098), 316d4c36765SVladimir Oltean REG(SYS_COUNT_RX_GREEN_PRIO_3, 0x00009c), 317d4c36765SVladimir Oltean REG(SYS_COUNT_RX_GREEN_PRIO_4, 0x0000a0), 318d4c36765SVladimir Oltean REG(SYS_COUNT_RX_GREEN_PRIO_5, 0x0000a4), 319d4c36765SVladimir Oltean REG(SYS_COUNT_RX_GREEN_PRIO_6, 0x0000a8), 320d4c36765SVladimir Oltean REG(SYS_COUNT_RX_GREEN_PRIO_7, 0x0000ac), 321*ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_ASSEMBLY_ERRS, 0x0000b0), 322*ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_SMD_ERRS, 0x0000b4), 323*ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_ASSEMBLY_OK, 0x0000b8), 324*ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_MERGE_FRAGMENTS, 0x0000bc), 325*ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_PMAC_OCTETS, 0x0000c0), 326*ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_PMAC_UNICAST, 0x0000c4), 327*ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_PMAC_MULTICAST, 0x0000c8), 328*ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_PMAC_BROADCAST, 0x0000cc), 329*ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_PMAC_SHORTS, 0x0000d0), 330*ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_PMAC_FRAGMENTS, 0x0000d4), 331*ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_PMAC_JABBERS, 0x0000d8), 332*ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_PMAC_CRC_ALIGN_ERRS, 0x0000dc), 333*ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_PMAC_SYM_ERRS, 0x0000e0), 334*ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_PMAC_64, 0x0000e4), 335*ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_PMAC_65_127, 0x0000e8), 336*ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_PMAC_128_255, 0x0000ec), 337*ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_PMAC_256_511, 0x0000f0), 338*ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_PMAC_512_1023, 0x0000f4), 339*ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_PMAC_1024_1526, 0x0000f8), 340*ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_PMAC_1527_MAX, 0x0000fc), 341*ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_PMAC_PAUSE, 0x000100), 342*ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_PMAC_CONTROL, 0x000104), 343*ab3f97a9SVladimir Oltean REG(SYS_COUNT_RX_PMAC_LONGS, 0x000108), 34456051948SVladimir Oltean REG(SYS_COUNT_TX_OCTETS, 0x000200), 345d4c36765SVladimir Oltean REG(SYS_COUNT_TX_UNICAST, 0x000204), 346d4c36765SVladimir Oltean REG(SYS_COUNT_TX_MULTICAST, 0x000208), 347d4c36765SVladimir Oltean REG(SYS_COUNT_TX_BROADCAST, 0x00020c), 34856051948SVladimir Oltean REG(SYS_COUNT_TX_COLLISION, 0x000210), 34956051948SVladimir Oltean REG(SYS_COUNT_TX_DROPS, 0x000214), 350d4c36765SVladimir Oltean REG(SYS_COUNT_TX_PAUSE, 0x000218), 35156051948SVladimir Oltean REG(SYS_COUNT_TX_64, 0x00021c), 35256051948SVladimir Oltean REG(SYS_COUNT_TX_65_127, 0x000220), 3535152de7bSVladimir Oltean REG(SYS_COUNT_TX_128_255, 0x000224), 3545152de7bSVladimir Oltean REG(SYS_COUNT_TX_256_511, 0x000228), 3555152de7bSVladimir Oltean REG(SYS_COUNT_TX_512_1023, 0x00022c), 3565152de7bSVladimir Oltean REG(SYS_COUNT_TX_1024_1526, 0x000230), 3575152de7bSVladimir Oltean REG(SYS_COUNT_TX_1527_MAX, 0x000234), 358d4c36765SVladimir Oltean REG(SYS_COUNT_TX_YELLOW_PRIO_0, 0x000238), 359d4c36765SVladimir Oltean REG(SYS_COUNT_TX_YELLOW_PRIO_1, 0x00023c), 360d4c36765SVladimir Oltean REG(SYS_COUNT_TX_YELLOW_PRIO_2, 0x000240), 361d4c36765SVladimir Oltean REG(SYS_COUNT_TX_YELLOW_PRIO_3, 0x000244), 362d4c36765SVladimir Oltean REG(SYS_COUNT_TX_YELLOW_PRIO_4, 0x000248), 363d4c36765SVladimir Oltean REG(SYS_COUNT_TX_YELLOW_PRIO_5, 0x00024c), 364d4c36765SVladimir Oltean REG(SYS_COUNT_TX_YELLOW_PRIO_6, 0x000250), 365d4c36765SVladimir Oltean REG(SYS_COUNT_TX_YELLOW_PRIO_7, 0x000254), 366d4c36765SVladimir Oltean REG(SYS_COUNT_TX_GREEN_PRIO_0, 0x000258), 367d4c36765SVladimir Oltean REG(SYS_COUNT_TX_GREEN_PRIO_1, 0x00025c), 368d4c36765SVladimir Oltean REG(SYS_COUNT_TX_GREEN_PRIO_2, 0x000260), 369d4c36765SVladimir Oltean REG(SYS_COUNT_TX_GREEN_PRIO_3, 0x000264), 370d4c36765SVladimir Oltean REG(SYS_COUNT_TX_GREEN_PRIO_4, 0x000268), 371d4c36765SVladimir Oltean REG(SYS_COUNT_TX_GREEN_PRIO_5, 0x00026c), 372d4c36765SVladimir Oltean REG(SYS_COUNT_TX_GREEN_PRIO_6, 0x000270), 373d4c36765SVladimir Oltean REG(SYS_COUNT_TX_GREEN_PRIO_7, 0x000274), 374be5c13f2SVladimir Oltean REG(SYS_COUNT_TX_AGED, 0x000278), 375*ab3f97a9SVladimir Oltean REG(SYS_COUNT_TX_MM_HOLD, 0x00027c), 376*ab3f97a9SVladimir Oltean REG(SYS_COUNT_TX_MERGE_FRAGMENTS, 0x000280), 377*ab3f97a9SVladimir Oltean REG(SYS_COUNT_TX_PMAC_OCTETS, 0x000284), 378*ab3f97a9SVladimir Oltean REG(SYS_COUNT_TX_PMAC_UNICAST, 0x000288), 379*ab3f97a9SVladimir Oltean REG(SYS_COUNT_TX_PMAC_MULTICAST, 0x00028c), 380*ab3f97a9SVladimir Oltean REG(SYS_COUNT_TX_PMAC_BROADCAST, 0x000290), 381*ab3f97a9SVladimir Oltean REG(SYS_COUNT_TX_PMAC_PAUSE, 0x000294), 382*ab3f97a9SVladimir Oltean REG(SYS_COUNT_TX_PMAC_64, 0x000298), 383*ab3f97a9SVladimir Oltean REG(SYS_COUNT_TX_PMAC_65_127, 0x00029c), 384*ab3f97a9SVladimir Oltean REG(SYS_COUNT_TX_PMAC_128_255, 0x0002a0), 385*ab3f97a9SVladimir Oltean REG(SYS_COUNT_TX_PMAC_256_511, 0x0002a4), 386*ab3f97a9SVladimir Oltean REG(SYS_COUNT_TX_PMAC_512_1023, 0x0002a8), 387*ab3f97a9SVladimir Oltean REG(SYS_COUNT_TX_PMAC_1024_1526, 0x0002ac), 388*ab3f97a9SVladimir Oltean REG(SYS_COUNT_TX_PMAC_1527_MAX, 0x0002b0), 389d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_LOCAL, 0x000400), 390d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_TAIL, 0x000404), 391d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_YELLOW_PRIO_0, 0x000408), 392d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_YELLOW_PRIO_1, 0x00040c), 393d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_YELLOW_PRIO_2, 0x000410), 394d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_YELLOW_PRIO_3, 0x000414), 395d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_YELLOW_PRIO_4, 0x000418), 396d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_YELLOW_PRIO_5, 0x00041c), 397d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_YELLOW_PRIO_6, 0x000420), 398d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_YELLOW_PRIO_7, 0x000424), 399d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_GREEN_PRIO_0, 0x000428), 400d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_GREEN_PRIO_1, 0x00042c), 401d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_GREEN_PRIO_2, 0x000430), 402d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_GREEN_PRIO_3, 0x000434), 403d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_GREEN_PRIO_4, 0x000438), 404d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_GREEN_PRIO_5, 0x00043c), 405d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_GREEN_PRIO_6, 0x000440), 406d4c36765SVladimir Oltean REG(SYS_COUNT_DROP_GREEN_PRIO_7, 0x000444), 4070a2360c5SVladimir Oltean REG(SYS_COUNT_SF_MATCHING_FRAMES, 0x000800), 4080a2360c5SVladimir Oltean REG(SYS_COUNT_SF_NOT_PASSING_FRAMES, 0x000804), 4090a2360c5SVladimir Oltean REG(SYS_COUNT_SF_NOT_PASSING_SDU, 0x000808), 4100a2360c5SVladimir Oltean REG(SYS_COUNT_SF_RED_FRAMES, 0x00080c), 41156051948SVladimir Oltean REG(SYS_RESET_CFG, 0x000e00), 41256051948SVladimir Oltean REG(SYS_SR_ETYPE_CFG, 0x000e04), 41356051948SVladimir Oltean REG(SYS_VLAN_ETYPE_CFG, 0x000e08), 41456051948SVladimir Oltean REG(SYS_PORT_MODE, 0x000e0c), 41556051948SVladimir Oltean REG(SYS_FRONT_PORT_MODE, 0x000e2c), 41656051948SVladimir Oltean REG(SYS_FRM_AGING, 0x000e44), 41756051948SVladimir Oltean REG(SYS_STAT_CFG, 0x000e48), 41856051948SVladimir Oltean REG(SYS_SW_STATUS, 0x000e4c), 41956051948SVladimir Oltean REG_RESERVED(SYS_MISC_CFG), 42056051948SVladimir Oltean REG(SYS_REW_MAC_HIGH_CFG, 0x000e6c), 42156051948SVladimir Oltean REG(SYS_REW_MAC_LOW_CFG, 0x000e84), 42256051948SVladimir Oltean REG(SYS_TIMESTAMP_OFFSET, 0x000e9c), 42356051948SVladimir Oltean REG(SYS_PAUSE_CFG, 0x000ea0), 42456051948SVladimir Oltean REG(SYS_PAUSE_TOT_CFG, 0x000ebc), 42556051948SVladimir Oltean REG(SYS_ATOP, 0x000ec0), 42656051948SVladimir Oltean REG(SYS_ATOP_TOT_CFG, 0x000edc), 42756051948SVladimir Oltean REG(SYS_MAC_FC_CFG, 0x000ee0), 42856051948SVladimir Oltean REG(SYS_MMGT, 0x000ef8), 42956051948SVladimir Oltean REG_RESERVED(SYS_MMGT_FAST), 43056051948SVladimir Oltean REG_RESERVED(SYS_EVENTS_DIF), 43156051948SVladimir Oltean REG_RESERVED(SYS_EVENTS_CORE), 43256051948SVladimir Oltean REG(SYS_PTP_STATUS, 0x000f14), 43356051948SVladimir Oltean REG(SYS_PTP_TXSTAMP, 0x000f18), 43456051948SVladimir Oltean REG(SYS_PTP_NXT, 0x000f1c), 43556051948SVladimir Oltean REG(SYS_PTP_CFG, 0x000f20), 43656051948SVladimir Oltean REG(SYS_RAM_INIT, 0x000f24), 43756051948SVladimir Oltean REG_RESERVED(SYS_CM_ADDR), 43856051948SVladimir Oltean REG_RESERVED(SYS_CM_DATA_WR), 43956051948SVladimir Oltean REG_RESERVED(SYS_CM_DATA_RD), 44056051948SVladimir Oltean REG_RESERVED(SYS_CM_OP), 44156051948SVladimir Oltean REG_RESERVED(SYS_CM_DATA), 44256051948SVladimir Oltean }; 44356051948SVladimir Oltean 4445df66c48SYangbo Lu static const u32 vsc9959_ptp_regmap[] = { 4455df66c48SYangbo Lu REG(PTP_PIN_CFG, 0x000000), 4465df66c48SYangbo Lu REG(PTP_PIN_TOD_SEC_MSB, 0x000004), 4475df66c48SYangbo Lu REG(PTP_PIN_TOD_SEC_LSB, 0x000008), 4485df66c48SYangbo Lu REG(PTP_PIN_TOD_NSEC, 0x00000c), 44994aca082SYangbo Lu REG(PTP_PIN_WF_HIGH_PERIOD, 0x000014), 45094aca082SYangbo Lu REG(PTP_PIN_WF_LOW_PERIOD, 0x000018), 4515df66c48SYangbo Lu REG(PTP_CFG_MISC, 0x0000a0), 4525df66c48SYangbo Lu REG(PTP_CLK_CFG_ADJ_CFG, 0x0000a4), 4535df66c48SYangbo Lu REG(PTP_CLK_CFG_ADJ_FREQ, 0x0000a8), 4545df66c48SYangbo Lu }; 4555df66c48SYangbo Lu 45656051948SVladimir Oltean static const u32 vsc9959_gcb_regmap[] = { 45756051948SVladimir Oltean REG(GCB_SOFT_RST, 0x000004), 45856051948SVladimir Oltean }; 45956051948SVladimir Oltean 46091c724cfSVladimir Oltean static const u32 vsc9959_dev_gmii_regmap[] = { 46191c724cfSVladimir Oltean REG(DEV_CLOCK_CFG, 0x0), 46291c724cfSVladimir Oltean REG(DEV_PORT_MISC, 0x4), 46391c724cfSVladimir Oltean REG(DEV_EVENTS, 0x8), 46491c724cfSVladimir Oltean REG(DEV_EEE_CFG, 0xc), 46591c724cfSVladimir Oltean REG(DEV_RX_PATH_DELAY, 0x10), 46691c724cfSVladimir Oltean REG(DEV_TX_PATH_DELAY, 0x14), 46791c724cfSVladimir Oltean REG(DEV_PTP_PREDICT_CFG, 0x18), 46891c724cfSVladimir Oltean REG(DEV_MAC_ENA_CFG, 0x1c), 46991c724cfSVladimir Oltean REG(DEV_MAC_MODE_CFG, 0x20), 47091c724cfSVladimir Oltean REG(DEV_MAC_MAXLEN_CFG, 0x24), 47191c724cfSVladimir Oltean REG(DEV_MAC_TAGS_CFG, 0x28), 47291c724cfSVladimir Oltean REG(DEV_MAC_ADV_CHK_CFG, 0x2c), 47391c724cfSVladimir Oltean REG(DEV_MAC_IFG_CFG, 0x30), 47491c724cfSVladimir Oltean REG(DEV_MAC_HDX_CFG, 0x34), 47591c724cfSVladimir Oltean REG(DEV_MAC_DBG_CFG, 0x38), 47691c724cfSVladimir Oltean REG(DEV_MAC_FC_MAC_LOW_CFG, 0x3c), 47791c724cfSVladimir Oltean REG(DEV_MAC_FC_MAC_HIGH_CFG, 0x40), 47891c724cfSVladimir Oltean REG(DEV_MAC_STICKY, 0x44), 47991c724cfSVladimir Oltean REG_RESERVED(PCS1G_CFG), 48091c724cfSVladimir Oltean REG_RESERVED(PCS1G_MODE_CFG), 48191c724cfSVladimir Oltean REG_RESERVED(PCS1G_SD_CFG), 48291c724cfSVladimir Oltean REG_RESERVED(PCS1G_ANEG_CFG), 48391c724cfSVladimir Oltean REG_RESERVED(PCS1G_ANEG_NP_CFG), 48491c724cfSVladimir Oltean REG_RESERVED(PCS1G_LB_CFG), 48591c724cfSVladimir Oltean REG_RESERVED(PCS1G_DBG_CFG), 48691c724cfSVladimir Oltean REG_RESERVED(PCS1G_CDET_CFG), 48791c724cfSVladimir Oltean REG_RESERVED(PCS1G_ANEG_STATUS), 48891c724cfSVladimir Oltean REG_RESERVED(PCS1G_ANEG_NP_STATUS), 48991c724cfSVladimir Oltean REG_RESERVED(PCS1G_LINK_STATUS), 49091c724cfSVladimir Oltean REG_RESERVED(PCS1G_LINK_DOWN_CNT), 49191c724cfSVladimir Oltean REG_RESERVED(PCS1G_STICKY), 49291c724cfSVladimir Oltean REG_RESERVED(PCS1G_DEBUG_STATUS), 49391c724cfSVladimir Oltean REG_RESERVED(PCS1G_LPI_CFG), 49491c724cfSVladimir Oltean REG_RESERVED(PCS1G_LPI_WAKE_ERROR_CNT), 49591c724cfSVladimir Oltean REG_RESERVED(PCS1G_LPI_STATUS), 49691c724cfSVladimir Oltean REG_RESERVED(PCS1G_TSTPAT_MODE_CFG), 49791c724cfSVladimir Oltean REG_RESERVED(PCS1G_TSTPAT_STATUS), 49891c724cfSVladimir Oltean REG_RESERVED(DEV_PCS_FX100_CFG), 49991c724cfSVladimir Oltean REG_RESERVED(DEV_PCS_FX100_STATUS), 50091c724cfSVladimir Oltean }; 50191c724cfSVladimir Oltean 50291c724cfSVladimir Oltean static const u32 *vsc9959_regmap[TARGET_MAX] = { 50356051948SVladimir Oltean [ANA] = vsc9959_ana_regmap, 50456051948SVladimir Oltean [QS] = vsc9959_qs_regmap, 50556051948SVladimir Oltean [QSYS] = vsc9959_qsys_regmap, 50656051948SVladimir Oltean [REW] = vsc9959_rew_regmap, 50756051948SVladimir Oltean [SYS] = vsc9959_sys_regmap, 508e3aea296SVladimir Oltean [S0] = vsc9959_vcap_regmap, 509a61e365dSVladimir Oltean [S1] = vsc9959_vcap_regmap, 510c1c3993eSVladimir Oltean [S2] = vsc9959_vcap_regmap, 5115df66c48SYangbo Lu [PTP] = vsc9959_ptp_regmap, 51256051948SVladimir Oltean [GCB] = vsc9959_gcb_regmap, 51391c724cfSVladimir Oltean [DEV_GMII] = vsc9959_dev_gmii_regmap, 51456051948SVladimir Oltean }; 51556051948SVladimir Oltean 516b4024c9eSClaudiu Manoil /* Addresses are relative to the PCI device's base address */ 5171109b97bSVladimir Oltean static const struct resource vsc9959_resources[] = { 5181109b97bSVladimir Oltean DEFINE_RES_MEM_NAMED(0x0010000, 0x0010000, "sys"), 5191109b97bSVladimir Oltean DEFINE_RES_MEM_NAMED(0x0030000, 0x0010000, "rew"), 5201109b97bSVladimir Oltean DEFINE_RES_MEM_NAMED(0x0040000, 0x0000400, "s0"), 5211109b97bSVladimir Oltean DEFINE_RES_MEM_NAMED(0x0050000, 0x0000400, "s1"), 5221109b97bSVladimir Oltean DEFINE_RES_MEM_NAMED(0x0060000, 0x0000400, "s2"), 5231109b97bSVladimir Oltean DEFINE_RES_MEM_NAMED(0x0070000, 0x0000200, "devcpu_gcb"), 5241109b97bSVladimir Oltean DEFINE_RES_MEM_NAMED(0x0080000, 0x0000100, "qs"), 5251109b97bSVladimir Oltean DEFINE_RES_MEM_NAMED(0x0090000, 0x00000cc, "ptp"), 526044d447aSVladimir Oltean DEFINE_RES_MEM_NAMED(0x0100000, 0x0010000, "port0"), 527044d447aSVladimir Oltean DEFINE_RES_MEM_NAMED(0x0110000, 0x0010000, "port1"), 528044d447aSVladimir Oltean DEFINE_RES_MEM_NAMED(0x0120000, 0x0010000, "port2"), 529044d447aSVladimir Oltean DEFINE_RES_MEM_NAMED(0x0130000, 0x0010000, "port3"), 530044d447aSVladimir Oltean DEFINE_RES_MEM_NAMED(0x0140000, 0x0010000, "port4"), 531044d447aSVladimir Oltean DEFINE_RES_MEM_NAMED(0x0150000, 0x0010000, "port5"), 5321109b97bSVladimir Oltean DEFINE_RES_MEM_NAMED(0x0200000, 0x0020000, "qsys"), 5331109b97bSVladimir Oltean DEFINE_RES_MEM_NAMED(0x0280000, 0x0010000, "ana"), 5341109b97bSVladimir Oltean }; 5351109b97bSVladimir Oltean 5361109b97bSVladimir Oltean static const char * const vsc9959_resource_names[TARGET_MAX] = { 5371109b97bSVladimir Oltean [SYS] = "sys", 5381109b97bSVladimir Oltean [REW] = "rew", 5391109b97bSVladimir Oltean [S0] = "s0", 5401109b97bSVladimir Oltean [S1] = "s1", 5411109b97bSVladimir Oltean [S2] = "s2", 5421109b97bSVladimir Oltean [GCB] = "devcpu_gcb", 5431109b97bSVladimir Oltean [QS] = "qs", 5441109b97bSVladimir Oltean [PTP] = "ptp", 5451109b97bSVladimir Oltean [QSYS] = "qsys", 5461109b97bSVladimir Oltean [ANA] = "ana", 54756051948SVladimir Oltean }; 54856051948SVladimir Oltean 549bdeced75SVladimir Oltean /* Port MAC 0 Internal MDIO bus through which the SerDes acting as an 550bdeced75SVladimir Oltean * SGMII/QSGMII MAC PCS can be found. 551bdeced75SVladimir Oltean */ 552044d447aSVladimir Oltean static const struct resource vsc9959_imdio_res = 553044d447aSVladimir Oltean DEFINE_RES_MEM_NAMED(0x8030, 0x8040, "imdio"); 554bdeced75SVladimir Oltean 5552789658fSMaxim Kochetkov static const struct reg_field vsc9959_regfields[REGFIELD_MAX] = { 55656051948SVladimir Oltean [ANA_ADVLEARN_VLAN_CHK] = REG_FIELD(ANA_ADVLEARN, 6, 6), 55756051948SVladimir Oltean [ANA_ADVLEARN_LEARN_MIRROR] = REG_FIELD(ANA_ADVLEARN, 0, 5), 55856051948SVladimir Oltean [ANA_ANEVENTS_FLOOD_DISCARD] = REG_FIELD(ANA_ANEVENTS, 30, 30), 55956051948SVladimir Oltean [ANA_ANEVENTS_AUTOAGE] = REG_FIELD(ANA_ANEVENTS, 26, 26), 56056051948SVladimir Oltean [ANA_ANEVENTS_STORM_DROP] = REG_FIELD(ANA_ANEVENTS, 24, 24), 56156051948SVladimir Oltean [ANA_ANEVENTS_LEARN_DROP] = REG_FIELD(ANA_ANEVENTS, 23, 23), 56256051948SVladimir Oltean [ANA_ANEVENTS_AGED_ENTRY] = REG_FIELD(ANA_ANEVENTS, 22, 22), 56356051948SVladimir Oltean [ANA_ANEVENTS_CPU_LEARN_FAILED] = REG_FIELD(ANA_ANEVENTS, 21, 21), 56456051948SVladimir Oltean [ANA_ANEVENTS_AUTO_LEARN_FAILED] = REG_FIELD(ANA_ANEVENTS, 20, 20), 56556051948SVladimir Oltean [ANA_ANEVENTS_LEARN_REMOVE] = REG_FIELD(ANA_ANEVENTS, 19, 19), 56656051948SVladimir Oltean [ANA_ANEVENTS_AUTO_LEARNED] = REG_FIELD(ANA_ANEVENTS, 18, 18), 56756051948SVladimir Oltean [ANA_ANEVENTS_AUTO_MOVED] = REG_FIELD(ANA_ANEVENTS, 17, 17), 56856051948SVladimir Oltean [ANA_ANEVENTS_CLASSIFIED_DROP] = REG_FIELD(ANA_ANEVENTS, 15, 15), 56956051948SVladimir Oltean [ANA_ANEVENTS_CLASSIFIED_COPY] = REG_FIELD(ANA_ANEVENTS, 14, 14), 57056051948SVladimir Oltean [ANA_ANEVENTS_VLAN_DISCARD] = REG_FIELD(ANA_ANEVENTS, 13, 13), 57156051948SVladimir Oltean [ANA_ANEVENTS_FWD_DISCARD] = REG_FIELD(ANA_ANEVENTS, 12, 12), 57256051948SVladimir Oltean [ANA_ANEVENTS_MULTICAST_FLOOD] = REG_FIELD(ANA_ANEVENTS, 11, 11), 57356051948SVladimir Oltean [ANA_ANEVENTS_UNICAST_FLOOD] = REG_FIELD(ANA_ANEVENTS, 10, 10), 57456051948SVladimir Oltean [ANA_ANEVENTS_DEST_KNOWN] = REG_FIELD(ANA_ANEVENTS, 9, 9), 57556051948SVladimir Oltean [ANA_ANEVENTS_BUCKET3_MATCH] = REG_FIELD(ANA_ANEVENTS, 8, 8), 57656051948SVladimir Oltean [ANA_ANEVENTS_BUCKET2_MATCH] = REG_FIELD(ANA_ANEVENTS, 7, 7), 57756051948SVladimir Oltean [ANA_ANEVENTS_BUCKET1_MATCH] = REG_FIELD(ANA_ANEVENTS, 6, 6), 57856051948SVladimir Oltean [ANA_ANEVENTS_BUCKET0_MATCH] = REG_FIELD(ANA_ANEVENTS, 5, 5), 57956051948SVladimir Oltean [ANA_ANEVENTS_CPU_OPERATION] = REG_FIELD(ANA_ANEVENTS, 4, 4), 58056051948SVladimir Oltean [ANA_ANEVENTS_DMAC_LOOKUP] = REG_FIELD(ANA_ANEVENTS, 3, 3), 58156051948SVladimir Oltean [ANA_ANEVENTS_SMAC_LOOKUP] = REG_FIELD(ANA_ANEVENTS, 2, 2), 58256051948SVladimir Oltean [ANA_ANEVENTS_SEQ_GEN_ERR_0] = REG_FIELD(ANA_ANEVENTS, 1, 1), 58356051948SVladimir Oltean [ANA_ANEVENTS_SEQ_GEN_ERR_1] = REG_FIELD(ANA_ANEVENTS, 0, 0), 58456051948SVladimir Oltean [ANA_TABLES_MACACCESS_B_DOM] = REG_FIELD(ANA_TABLES_MACACCESS, 16, 16), 58556051948SVladimir Oltean [ANA_TABLES_MACTINDX_BUCKET] = REG_FIELD(ANA_TABLES_MACTINDX, 11, 12), 58656051948SVladimir Oltean [ANA_TABLES_MACTINDX_M_INDEX] = REG_FIELD(ANA_TABLES_MACTINDX, 0, 10), 58756051948SVladimir Oltean [SYS_RESET_CFG_CORE_ENA] = REG_FIELD(SYS_RESET_CFG, 0, 0), 58856051948SVladimir Oltean [GCB_SOFT_RST_SWC_RST] = REG_FIELD(GCB_SOFT_RST, 0, 0), 589886e1387SVladimir Oltean /* Replicated per number of ports (7), register size 4 per port */ 590886e1387SVladimir Oltean [QSYS_SWITCH_PORT_MODE_PORT_ENA] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 14, 14, 7, 4), 591886e1387SVladimir Oltean [QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 11, 13, 7, 4), 592886e1387SVladimir Oltean [QSYS_SWITCH_PORT_MODE_YEL_RSRVD] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 10, 10, 7, 4), 593886e1387SVladimir Oltean [QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 9, 9, 7, 4), 594886e1387SVladimir Oltean [QSYS_SWITCH_PORT_MODE_TX_PFC_ENA] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 1, 8, 7, 4), 595886e1387SVladimir Oltean [QSYS_SWITCH_PORT_MODE_TX_PFC_MODE] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 0, 0, 7, 4), 596886e1387SVladimir Oltean [SYS_PORT_MODE_DATA_WO_TS] = REG_FIELD_ID(SYS_PORT_MODE, 5, 6, 7, 4), 597886e1387SVladimir Oltean [SYS_PORT_MODE_INCL_INJ_HDR] = REG_FIELD_ID(SYS_PORT_MODE, 3, 4, 7, 4), 598886e1387SVladimir Oltean [SYS_PORT_MODE_INCL_XTR_HDR] = REG_FIELD_ID(SYS_PORT_MODE, 1, 2, 7, 4), 599886e1387SVladimir Oltean [SYS_PORT_MODE_INCL_HDR_ERR] = REG_FIELD_ID(SYS_PORT_MODE, 0, 0, 7, 4), 600541132f0SMaxim Kochetkov [SYS_PAUSE_CFG_PAUSE_START] = REG_FIELD_ID(SYS_PAUSE_CFG, 10, 18, 7, 4), 601541132f0SMaxim Kochetkov [SYS_PAUSE_CFG_PAUSE_STOP] = REG_FIELD_ID(SYS_PAUSE_CFG, 1, 9, 7, 4), 602541132f0SMaxim Kochetkov [SYS_PAUSE_CFG_PAUSE_ENA] = REG_FIELD_ID(SYS_PAUSE_CFG, 0, 1, 7, 4), 60356051948SVladimir Oltean }; 60456051948SVladimir Oltean 605e3aea296SVladimir Oltean static const struct vcap_field vsc9959_vcap_es0_keys[] = { 606e3aea296SVladimir Oltean [VCAP_ES0_EGR_PORT] = { 0, 3}, 607e3aea296SVladimir Oltean [VCAP_ES0_IGR_PORT] = { 3, 3}, 608e3aea296SVladimir Oltean [VCAP_ES0_RSV] = { 6, 2}, 609e3aea296SVladimir Oltean [VCAP_ES0_L2_MC] = { 8, 1}, 610e3aea296SVladimir Oltean [VCAP_ES0_L2_BC] = { 9, 1}, 611e3aea296SVladimir Oltean [VCAP_ES0_VID] = { 10, 12}, 612e3aea296SVladimir Oltean [VCAP_ES0_DP] = { 22, 1}, 613e3aea296SVladimir Oltean [VCAP_ES0_PCP] = { 23, 3}, 614e3aea296SVladimir Oltean }; 615e3aea296SVladimir Oltean 616e3aea296SVladimir Oltean static const struct vcap_field vsc9959_vcap_es0_actions[] = { 617e3aea296SVladimir Oltean [VCAP_ES0_ACT_PUSH_OUTER_TAG] = { 0, 2}, 618e3aea296SVladimir Oltean [VCAP_ES0_ACT_PUSH_INNER_TAG] = { 2, 1}, 619e3aea296SVladimir Oltean [VCAP_ES0_ACT_TAG_A_TPID_SEL] = { 3, 2}, 620e3aea296SVladimir Oltean [VCAP_ES0_ACT_TAG_A_VID_SEL] = { 5, 1}, 621e3aea296SVladimir Oltean [VCAP_ES0_ACT_TAG_A_PCP_SEL] = { 6, 2}, 622e3aea296SVladimir Oltean [VCAP_ES0_ACT_TAG_A_DEI_SEL] = { 8, 2}, 623e3aea296SVladimir Oltean [VCAP_ES0_ACT_TAG_B_TPID_SEL] = { 10, 2}, 624e3aea296SVladimir Oltean [VCAP_ES0_ACT_TAG_B_VID_SEL] = { 12, 1}, 625e3aea296SVladimir Oltean [VCAP_ES0_ACT_TAG_B_PCP_SEL] = { 13, 2}, 626e3aea296SVladimir Oltean [VCAP_ES0_ACT_TAG_B_DEI_SEL] = { 15, 2}, 627e3aea296SVladimir Oltean [VCAP_ES0_ACT_VID_A_VAL] = { 17, 12}, 628e3aea296SVladimir Oltean [VCAP_ES0_ACT_PCP_A_VAL] = { 29, 3}, 629e3aea296SVladimir Oltean [VCAP_ES0_ACT_DEI_A_VAL] = { 32, 1}, 630e3aea296SVladimir Oltean [VCAP_ES0_ACT_VID_B_VAL] = { 33, 12}, 631e3aea296SVladimir Oltean [VCAP_ES0_ACT_PCP_B_VAL] = { 45, 3}, 632e3aea296SVladimir Oltean [VCAP_ES0_ACT_DEI_B_VAL] = { 48, 1}, 633e3aea296SVladimir Oltean [VCAP_ES0_ACT_RSV] = { 49, 23}, 634e3aea296SVladimir Oltean [VCAP_ES0_ACT_HIT_STICKY] = { 72, 1}, 635e3aea296SVladimir Oltean }; 636e3aea296SVladimir Oltean 637a61e365dSVladimir Oltean static const struct vcap_field vsc9959_vcap_is1_keys[] = { 638a61e365dSVladimir Oltean [VCAP_IS1_HK_TYPE] = { 0, 1}, 639a61e365dSVladimir Oltean [VCAP_IS1_HK_LOOKUP] = { 1, 2}, 640a61e365dSVladimir Oltean [VCAP_IS1_HK_IGR_PORT_MASK] = { 3, 7}, 641a61e365dSVladimir Oltean [VCAP_IS1_HK_RSV] = { 10, 9}, 642a61e365dSVladimir Oltean [VCAP_IS1_HK_OAM_Y1731] = { 19, 1}, 643a61e365dSVladimir Oltean [VCAP_IS1_HK_L2_MC] = { 20, 1}, 644a61e365dSVladimir Oltean [VCAP_IS1_HK_L2_BC] = { 21, 1}, 645a61e365dSVladimir Oltean [VCAP_IS1_HK_IP_MC] = { 22, 1}, 646a61e365dSVladimir Oltean [VCAP_IS1_HK_VLAN_TAGGED] = { 23, 1}, 647a61e365dSVladimir Oltean [VCAP_IS1_HK_VLAN_DBL_TAGGED] = { 24, 1}, 648a61e365dSVladimir Oltean [VCAP_IS1_HK_TPID] = { 25, 1}, 649a61e365dSVladimir Oltean [VCAP_IS1_HK_VID] = { 26, 12}, 650a61e365dSVladimir Oltean [VCAP_IS1_HK_DEI] = { 38, 1}, 651a61e365dSVladimir Oltean [VCAP_IS1_HK_PCP] = { 39, 3}, 652a61e365dSVladimir Oltean /* Specific Fields for IS1 Half Key S1_NORMAL */ 653a61e365dSVladimir Oltean [VCAP_IS1_HK_L2_SMAC] = { 42, 48}, 654a61e365dSVladimir Oltean [VCAP_IS1_HK_ETYPE_LEN] = { 90, 1}, 655a61e365dSVladimir Oltean [VCAP_IS1_HK_ETYPE] = { 91, 16}, 656a61e365dSVladimir Oltean [VCAP_IS1_HK_IP_SNAP] = {107, 1}, 657a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4] = {108, 1}, 658a61e365dSVladimir Oltean /* Layer-3 Information */ 659a61e365dSVladimir Oltean [VCAP_IS1_HK_L3_FRAGMENT] = {109, 1}, 660a61e365dSVladimir Oltean [VCAP_IS1_HK_L3_FRAG_OFS_GT0] = {110, 1}, 661a61e365dSVladimir Oltean [VCAP_IS1_HK_L3_OPTIONS] = {111, 1}, 662a61e365dSVladimir Oltean [VCAP_IS1_HK_L3_DSCP] = {112, 6}, 663a61e365dSVladimir Oltean [VCAP_IS1_HK_L3_IP4_SIP] = {118, 32}, 664a61e365dSVladimir Oltean /* Layer-4 Information */ 665a61e365dSVladimir Oltean [VCAP_IS1_HK_TCP_UDP] = {150, 1}, 666a61e365dSVladimir Oltean [VCAP_IS1_HK_TCP] = {151, 1}, 667a61e365dSVladimir Oltean [VCAP_IS1_HK_L4_SPORT] = {152, 16}, 668a61e365dSVladimir Oltean [VCAP_IS1_HK_L4_RNG] = {168, 8}, 669a61e365dSVladimir Oltean /* Specific Fields for IS1 Half Key S1_5TUPLE_IP4 */ 670a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_INNER_TPID] = { 42, 1}, 671a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_INNER_VID] = { 43, 12}, 672a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_INNER_DEI] = { 55, 1}, 673a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_INNER_PCP] = { 56, 3}, 674a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_IP4] = { 59, 1}, 675a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_L3_FRAGMENT] = { 60, 1}, 676a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_L3_FRAG_OFS_GT0] = { 61, 1}, 677a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_L3_OPTIONS] = { 62, 1}, 678a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_L3_DSCP] = { 63, 6}, 679a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_L3_IP4_DIP] = { 69, 32}, 680a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_L3_IP4_SIP] = {101, 32}, 681a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_L3_PROTO] = {133, 8}, 682a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_TCP_UDP] = {141, 1}, 683a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_TCP] = {142, 1}, 684a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_L4_RNG] = {143, 8}, 685a61e365dSVladimir Oltean [VCAP_IS1_HK_IP4_IP_PAYLOAD_S1_5TUPLE] = {151, 32}, 686a61e365dSVladimir Oltean }; 687a61e365dSVladimir Oltean 688a61e365dSVladimir Oltean static const struct vcap_field vsc9959_vcap_is1_actions[] = { 689a61e365dSVladimir Oltean [VCAP_IS1_ACT_DSCP_ENA] = { 0, 1}, 690a61e365dSVladimir Oltean [VCAP_IS1_ACT_DSCP_VAL] = { 1, 6}, 691a61e365dSVladimir Oltean [VCAP_IS1_ACT_QOS_ENA] = { 7, 1}, 692a61e365dSVladimir Oltean [VCAP_IS1_ACT_QOS_VAL] = { 8, 3}, 693a61e365dSVladimir Oltean [VCAP_IS1_ACT_DP_ENA] = { 11, 1}, 694a61e365dSVladimir Oltean [VCAP_IS1_ACT_DP_VAL] = { 12, 1}, 695a61e365dSVladimir Oltean [VCAP_IS1_ACT_PAG_OVERRIDE_MASK] = { 13, 8}, 696a61e365dSVladimir Oltean [VCAP_IS1_ACT_PAG_VAL] = { 21, 8}, 697a61e365dSVladimir Oltean [VCAP_IS1_ACT_RSV] = { 29, 9}, 69875944fdaSXiaoliang Yang /* The fields below are incorrectly shifted by 2 in the manual */ 699a61e365dSVladimir Oltean [VCAP_IS1_ACT_VID_REPLACE_ENA] = { 38, 1}, 700a61e365dSVladimir Oltean [VCAP_IS1_ACT_VID_ADD_VAL] = { 39, 12}, 701a61e365dSVladimir Oltean [VCAP_IS1_ACT_FID_SEL] = { 51, 2}, 702a61e365dSVladimir Oltean [VCAP_IS1_ACT_FID_VAL] = { 53, 13}, 703a61e365dSVladimir Oltean [VCAP_IS1_ACT_PCP_DEI_ENA] = { 66, 1}, 704a61e365dSVladimir Oltean [VCAP_IS1_ACT_PCP_VAL] = { 67, 3}, 705a61e365dSVladimir Oltean [VCAP_IS1_ACT_DEI_VAL] = { 70, 1}, 706a61e365dSVladimir Oltean [VCAP_IS1_ACT_VLAN_POP_CNT_ENA] = { 71, 1}, 707a61e365dSVladimir Oltean [VCAP_IS1_ACT_VLAN_POP_CNT] = { 72, 2}, 708a61e365dSVladimir Oltean [VCAP_IS1_ACT_CUSTOM_ACE_TYPE_ENA] = { 74, 4}, 709a61e365dSVladimir Oltean [VCAP_IS1_ACT_HIT_STICKY] = { 78, 1}, 710a61e365dSVladimir Oltean }; 711a61e365dSVladimir Oltean 7123ab4ceb6SVladimir Oltean static struct vcap_field vsc9959_vcap_is2_keys[] = { 71307d985eeSVladimir Oltean /* Common: 41 bits */ 71407d985eeSVladimir Oltean [VCAP_IS2_TYPE] = { 0, 4}, 71507d985eeSVladimir Oltean [VCAP_IS2_HK_FIRST] = { 4, 1}, 71607d985eeSVladimir Oltean [VCAP_IS2_HK_PAG] = { 5, 8}, 71707d985eeSVladimir Oltean [VCAP_IS2_HK_IGR_PORT_MASK] = { 13, 7}, 71807d985eeSVladimir Oltean [VCAP_IS2_HK_RSV2] = { 20, 1}, 71907d985eeSVladimir Oltean [VCAP_IS2_HK_HOST_MATCH] = { 21, 1}, 72007d985eeSVladimir Oltean [VCAP_IS2_HK_L2_MC] = { 22, 1}, 72107d985eeSVladimir Oltean [VCAP_IS2_HK_L2_BC] = { 23, 1}, 72207d985eeSVladimir Oltean [VCAP_IS2_HK_VLAN_TAGGED] = { 24, 1}, 72307d985eeSVladimir Oltean [VCAP_IS2_HK_VID] = { 25, 12}, 72407d985eeSVladimir Oltean [VCAP_IS2_HK_DEI] = { 37, 1}, 72507d985eeSVladimir Oltean [VCAP_IS2_HK_PCP] = { 38, 3}, 72607d985eeSVladimir Oltean /* MAC_ETYPE / MAC_LLC / MAC_SNAP / OAM common */ 72707d985eeSVladimir Oltean [VCAP_IS2_HK_L2_DMAC] = { 41, 48}, 72807d985eeSVladimir Oltean [VCAP_IS2_HK_L2_SMAC] = { 89, 48}, 72907d985eeSVladimir Oltean /* MAC_ETYPE (TYPE=000) */ 73007d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ETYPE_ETYPE] = {137, 16}, 73107d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD0] = {153, 16}, 73207d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD1] = {169, 8}, 73307d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD2] = {177, 3}, 73407d985eeSVladimir Oltean /* MAC_LLC (TYPE=001) */ 73507d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_LLC_L2_LLC] = {137, 40}, 73607d985eeSVladimir Oltean /* MAC_SNAP (TYPE=010) */ 73707d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_SNAP_L2_SNAP] = {137, 40}, 73807d985eeSVladimir Oltean /* MAC_ARP (TYPE=011) */ 73907d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ARP_SMAC] = { 41, 48}, 74007d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ARP_ADDR_SPACE_OK] = { 89, 1}, 74107d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ARP_PROTO_SPACE_OK] = { 90, 1}, 74207d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ARP_LEN_OK] = { 91, 1}, 74307d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ARP_TARGET_MATCH] = { 92, 1}, 74407d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ARP_SENDER_MATCH] = { 93, 1}, 74507d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ARP_OPCODE_UNKNOWN] = { 94, 1}, 74607d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ARP_OPCODE] = { 95, 2}, 74707d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ARP_L3_IP4_DIP] = { 97, 32}, 74807d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ARP_L3_IP4_SIP] = {129, 32}, 74907d985eeSVladimir Oltean [VCAP_IS2_HK_MAC_ARP_DIP_EQ_SIP] = {161, 1}, 75007d985eeSVladimir Oltean /* IP4_TCP_UDP / IP4_OTHER common */ 75107d985eeSVladimir Oltean [VCAP_IS2_HK_IP4] = { 41, 1}, 75207d985eeSVladimir Oltean [VCAP_IS2_HK_L3_FRAGMENT] = { 42, 1}, 75307d985eeSVladimir Oltean [VCAP_IS2_HK_L3_FRAG_OFS_GT0] = { 43, 1}, 75407d985eeSVladimir Oltean [VCAP_IS2_HK_L3_OPTIONS] = { 44, 1}, 75507d985eeSVladimir Oltean [VCAP_IS2_HK_IP4_L3_TTL_GT0] = { 45, 1}, 75607d985eeSVladimir Oltean [VCAP_IS2_HK_L3_TOS] = { 46, 8}, 75707d985eeSVladimir Oltean [VCAP_IS2_HK_L3_IP4_DIP] = { 54, 32}, 75807d985eeSVladimir Oltean [VCAP_IS2_HK_L3_IP4_SIP] = { 86, 32}, 75907d985eeSVladimir Oltean [VCAP_IS2_HK_DIP_EQ_SIP] = {118, 1}, 76007d985eeSVladimir Oltean /* IP4_TCP_UDP (TYPE=100) */ 76107d985eeSVladimir Oltean [VCAP_IS2_HK_TCP] = {119, 1}, 7628b9e03cdSXiaoliang Yang [VCAP_IS2_HK_L4_DPORT] = {120, 16}, 7638b9e03cdSXiaoliang Yang [VCAP_IS2_HK_L4_SPORT] = {136, 16}, 76407d985eeSVladimir Oltean [VCAP_IS2_HK_L4_RNG] = {152, 8}, 76507d985eeSVladimir Oltean [VCAP_IS2_HK_L4_SPORT_EQ_DPORT] = {160, 1}, 76607d985eeSVladimir Oltean [VCAP_IS2_HK_L4_SEQUENCE_EQ0] = {161, 1}, 7678b9e03cdSXiaoliang Yang [VCAP_IS2_HK_L4_FIN] = {162, 1}, 7688b9e03cdSXiaoliang Yang [VCAP_IS2_HK_L4_SYN] = {163, 1}, 7698b9e03cdSXiaoliang Yang [VCAP_IS2_HK_L4_RST] = {164, 1}, 7708b9e03cdSXiaoliang Yang [VCAP_IS2_HK_L4_PSH] = {165, 1}, 7718b9e03cdSXiaoliang Yang [VCAP_IS2_HK_L4_ACK] = {166, 1}, 7728b9e03cdSXiaoliang Yang [VCAP_IS2_HK_L4_URG] = {167, 1}, 77307d985eeSVladimir Oltean [VCAP_IS2_HK_L4_1588_DOM] = {168, 8}, 77407d985eeSVladimir Oltean [VCAP_IS2_HK_L4_1588_VER] = {176, 4}, 77507d985eeSVladimir Oltean /* IP4_OTHER (TYPE=101) */ 77607d985eeSVladimir Oltean [VCAP_IS2_HK_IP4_L3_PROTO] = {119, 8}, 77707d985eeSVladimir Oltean [VCAP_IS2_HK_L3_PAYLOAD] = {127, 56}, 77807d985eeSVladimir Oltean /* IP6_STD (TYPE=110) */ 77907d985eeSVladimir Oltean [VCAP_IS2_HK_IP6_L3_TTL_GT0] = { 41, 1}, 78007d985eeSVladimir Oltean [VCAP_IS2_HK_L3_IP6_SIP] = { 42, 128}, 78107d985eeSVladimir Oltean [VCAP_IS2_HK_IP6_L3_PROTO] = {170, 8}, 78207d985eeSVladimir Oltean /* OAM (TYPE=111) */ 78307d985eeSVladimir Oltean [VCAP_IS2_HK_OAM_MEL_FLAGS] = {137, 7}, 78407d985eeSVladimir Oltean [VCAP_IS2_HK_OAM_VER] = {144, 5}, 78507d985eeSVladimir Oltean [VCAP_IS2_HK_OAM_OPCODE] = {149, 8}, 78607d985eeSVladimir Oltean [VCAP_IS2_HK_OAM_FLAGS] = {157, 8}, 78707d985eeSVladimir Oltean [VCAP_IS2_HK_OAM_MEPID] = {165, 16}, 78807d985eeSVladimir Oltean [VCAP_IS2_HK_OAM_CCM_CNTS_EQ0] = {181, 1}, 78907d985eeSVladimir Oltean [VCAP_IS2_HK_OAM_IS_Y1731] = {182, 1}, 79007d985eeSVladimir Oltean }; 79107d985eeSVladimir Oltean 7923ab4ceb6SVladimir Oltean static struct vcap_field vsc9959_vcap_is2_actions[] = { 79307d985eeSVladimir Oltean [VCAP_IS2_ACT_HIT_ME_ONCE] = { 0, 1}, 79407d985eeSVladimir Oltean [VCAP_IS2_ACT_CPU_COPY_ENA] = { 1, 1}, 79507d985eeSVladimir Oltean [VCAP_IS2_ACT_CPU_QU_NUM] = { 2, 3}, 79607d985eeSVladimir Oltean [VCAP_IS2_ACT_MASK_MODE] = { 5, 2}, 79707d985eeSVladimir Oltean [VCAP_IS2_ACT_MIRROR_ENA] = { 7, 1}, 79807d985eeSVladimir Oltean [VCAP_IS2_ACT_LRN_DIS] = { 8, 1}, 79907d985eeSVladimir Oltean [VCAP_IS2_ACT_POLICE_ENA] = { 9, 1}, 80007d985eeSVladimir Oltean [VCAP_IS2_ACT_POLICE_IDX] = { 10, 9}, 80107d985eeSVladimir Oltean [VCAP_IS2_ACT_POLICE_VCAP_ONLY] = { 19, 1}, 802460e985eSVladimir Oltean [VCAP_IS2_ACT_PORT_MASK] = { 20, 6}, 803460e985eSVladimir Oltean [VCAP_IS2_ACT_REW_OP] = { 26, 9}, 804460e985eSVladimir Oltean [VCAP_IS2_ACT_SMAC_REPLACE_ENA] = { 35, 1}, 805460e985eSVladimir Oltean [VCAP_IS2_ACT_RSV] = { 36, 2}, 806460e985eSVladimir Oltean [VCAP_IS2_ACT_ACL_ID] = { 38, 6}, 807460e985eSVladimir Oltean [VCAP_IS2_ACT_HIT_CNT] = { 44, 32}, 80807d985eeSVladimir Oltean }; 80907d985eeSVladimir Oltean 81020968054SVladimir Oltean static struct vcap_props vsc9959_vcap_props[] = { 811e3aea296SVladimir Oltean [VCAP_ES0] = { 812e3aea296SVladimir Oltean .action_type_width = 0, 813e3aea296SVladimir Oltean .action_table = { 814e3aea296SVladimir Oltean [ES0_ACTION_TYPE_NORMAL] = { 815e3aea296SVladimir Oltean .width = 72, /* HIT_STICKY not included */ 816e3aea296SVladimir Oltean .count = 1, 817e3aea296SVladimir Oltean }, 818e3aea296SVladimir Oltean }, 819e3aea296SVladimir Oltean .target = S0, 820e3aea296SVladimir Oltean .keys = vsc9959_vcap_es0_keys, 821e3aea296SVladimir Oltean .actions = vsc9959_vcap_es0_actions, 822e3aea296SVladimir Oltean }, 823a61e365dSVladimir Oltean [VCAP_IS1] = { 824a61e365dSVladimir Oltean .action_type_width = 0, 825a61e365dSVladimir Oltean .action_table = { 826a61e365dSVladimir Oltean [IS1_ACTION_TYPE_NORMAL] = { 827a61e365dSVladimir Oltean .width = 78, /* HIT_STICKY not included */ 828a61e365dSVladimir Oltean .count = 4, 829a61e365dSVladimir Oltean }, 830a61e365dSVladimir Oltean }, 831a61e365dSVladimir Oltean .target = S1, 832a61e365dSVladimir Oltean .keys = vsc9959_vcap_is1_keys, 833a61e365dSVladimir Oltean .actions = vsc9959_vcap_is1_actions, 834a61e365dSVladimir Oltean }, 83507d985eeSVladimir Oltean [VCAP_IS2] = { 83607d985eeSVladimir Oltean .action_type_width = 1, 83707d985eeSVladimir Oltean .action_table = { 83807d985eeSVladimir Oltean [IS2_ACTION_TYPE_NORMAL] = { 83907d985eeSVladimir Oltean .width = 44, 84007d985eeSVladimir Oltean .count = 2 84107d985eeSVladimir Oltean }, 84207d985eeSVladimir Oltean [IS2_ACTION_TYPE_SMAC_SIP] = { 84307d985eeSVladimir Oltean .width = 6, 84407d985eeSVladimir Oltean .count = 4 84507d985eeSVladimir Oltean }, 84607d985eeSVladimir Oltean }, 847c1c3993eSVladimir Oltean .target = S2, 848c1c3993eSVladimir Oltean .keys = vsc9959_vcap_is2_keys, 849c1c3993eSVladimir Oltean .actions = vsc9959_vcap_is2_actions, 85007d985eeSVladimir Oltean }, 85107d985eeSVladimir Oltean }; 85207d985eeSVladimir Oltean 8532ac7c6c5SVladimir Oltean static const struct ptp_clock_info vsc9959_ptp_caps = { 8542ac7c6c5SVladimir Oltean .owner = THIS_MODULE, 8552ac7c6c5SVladimir Oltean .name = "felix ptp", 8562ac7c6c5SVladimir Oltean .max_adj = 0x7fffffff, 8572ac7c6c5SVladimir Oltean .n_alarm = 0, 8582ac7c6c5SVladimir Oltean .n_ext_ts = 0, 8592ac7c6c5SVladimir Oltean .n_per_out = OCELOT_PTP_PINS_NUM, 8602ac7c6c5SVladimir Oltean .n_pins = OCELOT_PTP_PINS_NUM, 8612ac7c6c5SVladimir Oltean .pps = 0, 8622ac7c6c5SVladimir Oltean .gettime64 = ocelot_ptp_gettime64, 8632ac7c6c5SVladimir Oltean .settime64 = ocelot_ptp_settime64, 8642ac7c6c5SVladimir Oltean .adjtime = ocelot_ptp_adjtime, 8652ac7c6c5SVladimir Oltean .adjfine = ocelot_ptp_adjfine, 8662ac7c6c5SVladimir Oltean .verify = ocelot_ptp_verify, 8672ac7c6c5SVladimir Oltean .enable = ocelot_ptp_enable, 8682ac7c6c5SVladimir Oltean }; 8692ac7c6c5SVladimir Oltean 87056051948SVladimir Oltean #define VSC9959_INIT_TIMEOUT 50000 87156051948SVladimir Oltean #define VSC9959_GCB_RST_SLEEP 100 87256051948SVladimir Oltean #define VSC9959_SYS_RAMINIT_SLEEP 80 87356051948SVladimir Oltean 87456051948SVladimir Oltean static int vsc9959_gcb_soft_rst_status(struct ocelot *ocelot) 87556051948SVladimir Oltean { 87656051948SVladimir Oltean int val; 87756051948SVladimir Oltean 87875cea9cbSVladimir Oltean ocelot_field_read(ocelot, GCB_SOFT_RST_SWC_RST, &val); 87956051948SVladimir Oltean 88056051948SVladimir Oltean return val; 88156051948SVladimir Oltean } 88256051948SVladimir Oltean 88356051948SVladimir Oltean static int vsc9959_sys_ram_init_status(struct ocelot *ocelot) 88456051948SVladimir Oltean { 88556051948SVladimir Oltean return ocelot_read(ocelot, SYS_RAM_INIT); 88656051948SVladimir Oltean } 88756051948SVladimir Oltean 888c129fc55SVladimir Oltean /* CORE_ENA is in SYS:SYSTEM:RESET_CFG 889c129fc55SVladimir Oltean * RAM_INIT is in SYS:RAM_CTRL:RAM_INIT 890c129fc55SVladimir Oltean */ 89156051948SVladimir Oltean static int vsc9959_reset(struct ocelot *ocelot) 89256051948SVladimir Oltean { 89356051948SVladimir Oltean int val, err; 89456051948SVladimir Oltean 89556051948SVladimir Oltean /* soft-reset the switch core */ 89675cea9cbSVladimir Oltean ocelot_field_write(ocelot, GCB_SOFT_RST_SWC_RST, 1); 89756051948SVladimir Oltean 89856051948SVladimir Oltean err = readx_poll_timeout(vsc9959_gcb_soft_rst_status, ocelot, val, !val, 89956051948SVladimir Oltean VSC9959_GCB_RST_SLEEP, VSC9959_INIT_TIMEOUT); 90056051948SVladimir Oltean if (err) { 90156051948SVladimir Oltean dev_err(ocelot->dev, "timeout: switch core reset\n"); 90256051948SVladimir Oltean return err; 90356051948SVladimir Oltean } 90456051948SVladimir Oltean 90556051948SVladimir Oltean /* initialize switch mem ~40us */ 90656051948SVladimir Oltean ocelot_write(ocelot, SYS_RAM_INIT_RAM_INIT, SYS_RAM_INIT); 90756051948SVladimir Oltean err = readx_poll_timeout(vsc9959_sys_ram_init_status, ocelot, val, !val, 90856051948SVladimir Oltean VSC9959_SYS_RAMINIT_SLEEP, 90956051948SVladimir Oltean VSC9959_INIT_TIMEOUT); 91056051948SVladimir Oltean if (err) { 91156051948SVladimir Oltean dev_err(ocelot->dev, "timeout: switch sram init\n"); 91256051948SVladimir Oltean return err; 91356051948SVladimir Oltean } 91456051948SVladimir Oltean 91556051948SVladimir Oltean /* enable switch core */ 91675cea9cbSVladimir Oltean ocelot_field_write(ocelot, SYS_RESET_CFG_CORE_ENA, 1); 91756051948SVladimir Oltean 91856051948SVladimir Oltean return 0; 91956051948SVladimir Oltean } 92056051948SVladimir Oltean 921aa92d836SMaxim Kochetkov /* Watermark encode 922aa92d836SMaxim Kochetkov * Bit 8: Unit; 0:1, 1:16 923aa92d836SMaxim Kochetkov * Bit 7-0: Value to be multiplied with unit 924aa92d836SMaxim Kochetkov */ 925aa92d836SMaxim Kochetkov static u16 vsc9959_wm_enc(u16 value) 926aa92d836SMaxim Kochetkov { 92701326493SVladimir Oltean WARN_ON(value >= 16 * BIT(8)); 92801326493SVladimir Oltean 929aa92d836SMaxim Kochetkov if (value >= BIT(8)) 930aa92d836SMaxim Kochetkov return BIT(8) | (value / 16); 931aa92d836SMaxim Kochetkov 932aa92d836SMaxim Kochetkov return value; 933aa92d836SMaxim Kochetkov } 934aa92d836SMaxim Kochetkov 935703b7621SVladimir Oltean static u16 vsc9959_wm_dec(u16 wm) 936703b7621SVladimir Oltean { 937703b7621SVladimir Oltean WARN_ON(wm & ~GENMASK(8, 0)); 938703b7621SVladimir Oltean 939703b7621SVladimir Oltean if (wm & BIT(8)) 940703b7621SVladimir Oltean return (wm & GENMASK(7, 0)) * 16; 941703b7621SVladimir Oltean 942703b7621SVladimir Oltean return wm; 943703b7621SVladimir Oltean } 944703b7621SVladimir Oltean 945703b7621SVladimir Oltean static void vsc9959_wm_stat(u32 val, u32 *inuse, u32 *maxuse) 946703b7621SVladimir Oltean { 947703b7621SVladimir Oltean *inuse = (val & GENMASK(23, 12)) >> 12; 948703b7621SVladimir Oltean *maxuse = val & GENMASK(11, 0); 949703b7621SVladimir Oltean } 950703b7621SVladimir Oltean 951bdeced75SVladimir Oltean static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot) 952bdeced75SVladimir Oltean { 9531382ba68SVladimir Oltean struct pci_dev *pdev = to_pci_dev(ocelot->dev); 954bdeced75SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 955bdeced75SVladimir Oltean struct enetc_mdio_priv *mdio_priv; 956bdeced75SVladimir Oltean struct device *dev = ocelot->dev; 9571382ba68SVladimir Oltean resource_size_t imdio_base; 958bdeced75SVladimir Oltean void __iomem *imdio_regs; 959b4024c9eSClaudiu Manoil struct resource res; 960bdeced75SVladimir Oltean struct enetc_hw *hw; 961bdeced75SVladimir Oltean struct mii_bus *bus; 962bdeced75SVladimir Oltean int port; 963bdeced75SVladimir Oltean int rc; 964bdeced75SVladimir Oltean 965bdeced75SVladimir Oltean felix->pcs = devm_kcalloc(dev, felix->info->num_ports, 966e7026f15SColin Foster sizeof(struct phylink_pcs *), 967bdeced75SVladimir Oltean GFP_KERNEL); 968bdeced75SVladimir Oltean if (!felix->pcs) { 969bdeced75SVladimir Oltean dev_err(dev, "failed to allocate array for PCS PHYs\n"); 970bdeced75SVladimir Oltean return -ENOMEM; 971bdeced75SVladimir Oltean } 972bdeced75SVladimir Oltean 9731382ba68SVladimir Oltean imdio_base = pci_resource_start(pdev, VSC9959_IMDIO_PCI_BAR); 9741382ba68SVladimir Oltean 9755fc080deSVladimir Oltean memcpy(&res, &vsc9959_imdio_res, sizeof(res)); 9761382ba68SVladimir Oltean res.start += imdio_base; 9771382ba68SVladimir Oltean res.end += imdio_base; 978bdeced75SVladimir Oltean 979b4024c9eSClaudiu Manoil imdio_regs = devm_ioremap_resource(dev, &res); 980a180be79SGuobin Huang if (IS_ERR(imdio_regs)) 981bdeced75SVladimir Oltean return PTR_ERR(imdio_regs); 982bdeced75SVladimir Oltean 983bdeced75SVladimir Oltean hw = enetc_hw_alloc(dev, imdio_regs); 984bdeced75SVladimir Oltean if (IS_ERR(hw)) { 985bdeced75SVladimir Oltean dev_err(dev, "failed to allocate ENETC HW structure\n"); 986bdeced75SVladimir Oltean return PTR_ERR(hw); 987bdeced75SVladimir Oltean } 988bdeced75SVladimir Oltean 989209bdb7eSVladimir Oltean bus = mdiobus_alloc_size(sizeof(*mdio_priv)); 990bdeced75SVladimir Oltean if (!bus) 991bdeced75SVladimir Oltean return -ENOMEM; 992bdeced75SVladimir Oltean 993bdeced75SVladimir Oltean bus->name = "VSC9959 internal MDIO bus"; 99480e87442SAndrew Lunn bus->read = enetc_mdio_read_c22; 99580e87442SAndrew Lunn bus->write = enetc_mdio_write_c22; 99680e87442SAndrew Lunn bus->read_c45 = enetc_mdio_read_c45; 99780e87442SAndrew Lunn bus->write_c45 = enetc_mdio_write_c45; 998bdeced75SVladimir Oltean bus->parent = dev; 999bdeced75SVladimir Oltean mdio_priv = bus->priv; 1000bdeced75SVladimir Oltean mdio_priv->hw = hw; 1001bdeced75SVladimir Oltean /* This gets added to imdio_regs, which already maps addresses 1002bdeced75SVladimir Oltean * starting with the proper offset. 1003bdeced75SVladimir Oltean */ 1004bdeced75SVladimir Oltean mdio_priv->mdio_base = 0; 1005bdeced75SVladimir Oltean snprintf(bus->id, MII_BUS_ID_SIZE, "%s-imdio", dev_name(dev)); 1006bdeced75SVladimir Oltean 1007bdeced75SVladimir Oltean /* Needed in order to initialize the bus mutex lock */ 1008bdeced75SVladimir Oltean rc = mdiobus_register(bus); 1009bdeced75SVladimir Oltean if (rc < 0) { 1010bdeced75SVladimir Oltean dev_err(dev, "failed to register MDIO bus\n"); 1011209bdb7eSVladimir Oltean mdiobus_free(bus); 1012bdeced75SVladimir Oltean return rc; 1013bdeced75SVladimir Oltean } 1014bdeced75SVladimir Oltean 1015bdeced75SVladimir Oltean felix->imdio = bus; 1016bdeced75SVladimir Oltean 1017bdeced75SVladimir Oltean for (port = 0; port < felix->info->num_ports; port++) { 1018bdeced75SVladimir Oltean struct ocelot_port *ocelot_port = ocelot->ports[port]; 1019e7026f15SColin Foster struct phylink_pcs *phylink_pcs; 102061f0d0c3SColin Foster struct mdio_device *mdio_device; 1021bdeced75SVladimir Oltean 1022588d0550SIoana Ciornei if (dsa_is_unused_port(felix->ds, port)) 1023588d0550SIoana Ciornei continue; 1024bdeced75SVladimir Oltean 1025588d0550SIoana Ciornei if (ocelot_port->phy_mode == PHY_INTERFACE_MODE_INTERNAL) 1026588d0550SIoana Ciornei continue; 1027588d0550SIoana Ciornei 102861f0d0c3SColin Foster mdio_device = mdio_device_create(felix->imdio, port); 102961f0d0c3SColin Foster if (IS_ERR(mdio_device)) 1030bdeced75SVladimir Oltean continue; 1031bdeced75SVladimir Oltean 103261f0d0c3SColin Foster phylink_pcs = lynx_pcs_create(mdio_device); 1033e7026f15SColin Foster if (!phylink_pcs) { 103461f0d0c3SColin Foster mdio_device_free(mdio_device); 1035588d0550SIoana Ciornei continue; 1036588d0550SIoana Ciornei } 1037588d0550SIoana Ciornei 1038e7026f15SColin Foster felix->pcs[port] = phylink_pcs; 1039bdeced75SVladimir Oltean 1040bdeced75SVladimir Oltean dev_info(dev, "Found PCS at internal MDIO address %d\n", port); 1041bdeced75SVladimir Oltean } 1042bdeced75SVladimir Oltean 1043bdeced75SVladimir Oltean return 0; 1044bdeced75SVladimir Oltean } 1045bdeced75SVladimir Oltean 1046ccfdbab5SVladimir Oltean static void vsc9959_mdio_bus_free(struct ocelot *ocelot) 1047bdeced75SVladimir Oltean { 1048bdeced75SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 1049bdeced75SVladimir Oltean int port; 1050bdeced75SVladimir Oltean 1051bdeced75SVladimir Oltean for (port = 0; port < ocelot->num_phys_ports; port++) { 1052e7026f15SColin Foster struct phylink_pcs *phylink_pcs = felix->pcs[port]; 1053e7026f15SColin Foster struct mdio_device *mdio_device; 1054bdeced75SVladimir Oltean 1055e7026f15SColin Foster if (!phylink_pcs) 1056bdeced75SVladimir Oltean continue; 1057bdeced75SVladimir Oltean 1058e7026f15SColin Foster mdio_device = lynx_get_mdio_device(phylink_pcs); 1059e7026f15SColin Foster mdio_device_free(mdio_device); 1060e7026f15SColin Foster lynx_pcs_destroy(phylink_pcs); 1061bdeced75SVladimir Oltean } 1062bdeced75SVladimir Oltean mdiobus_unregister(felix->imdio); 1063209bdb7eSVladimir Oltean mdiobus_free(felix->imdio); 1064bdeced75SVladimir Oltean } 1065bdeced75SVladimir Oltean 106611afdc65SVladimir Oltean /* The switch considers any frame (regardless of size) as eligible for 106711afdc65SVladimir Oltean * transmission if the traffic class gate is open for at least 33 ns. 106811afdc65SVladimir Oltean * Overruns are prevented by cropping an interval at the end of the gate time 106911afdc65SVladimir Oltean * slot for which egress scheduling is blocked, but we need to still keep 33 ns 107011afdc65SVladimir Oltean * available for one packet to be transmitted, otherwise the port tc will hang. 107111afdc65SVladimir Oltean * This function returns the size of a gate interval that remains available for 107211afdc65SVladimir Oltean * setting the guard band, after reserving the space for one egress frame. 107311afdc65SVladimir Oltean */ 107411afdc65SVladimir Oltean static u64 vsc9959_tas_remaining_gate_len_ps(u64 gate_len_ns) 107511afdc65SVladimir Oltean { 107611afdc65SVladimir Oltean /* Gate always open */ 107711afdc65SVladimir Oltean if (gate_len_ns == U64_MAX) 107811afdc65SVladimir Oltean return U64_MAX; 107911afdc65SVladimir Oltean 108011afdc65SVladimir Oltean return (gate_len_ns - VSC9959_TAS_MIN_GATE_LEN_NS) * PSEC_PER_NSEC; 108111afdc65SVladimir Oltean } 108211afdc65SVladimir Oltean 108355a515b1SVladimir Oltean /* Extract shortest continuous gate open intervals in ns for each traffic class 108455a515b1SVladimir Oltean * of a cyclic tc-taprio schedule. If a gate is always open, the duration is 108555a515b1SVladimir Oltean * considered U64_MAX. If the gate is always closed, it is considered 0. 108655a515b1SVladimir Oltean */ 108755a515b1SVladimir Oltean static void vsc9959_tas_min_gate_lengths(struct tc_taprio_qopt_offload *taprio, 108855a515b1SVladimir Oltean u64 min_gate_len[OCELOT_NUM_TC]) 108955a515b1SVladimir Oltean { 109055a515b1SVladimir Oltean struct tc_taprio_sched_entry *entry; 109155a515b1SVladimir Oltean u64 gate_len[OCELOT_NUM_TC]; 10927e4babffSVladimir Oltean u8 gates_ever_opened = 0; 109355a515b1SVladimir Oltean int tc, i, n; 109455a515b1SVladimir Oltean 109555a515b1SVladimir Oltean /* Initialize arrays */ 109655a515b1SVladimir Oltean for (tc = 0; tc < OCELOT_NUM_TC; tc++) { 109755a515b1SVladimir Oltean min_gate_len[tc] = U64_MAX; 109855a515b1SVladimir Oltean gate_len[tc] = 0; 109955a515b1SVladimir Oltean } 110055a515b1SVladimir Oltean 110155a515b1SVladimir Oltean /* If we don't have taprio, consider all gates as permanently open */ 110255a515b1SVladimir Oltean if (!taprio) 110355a515b1SVladimir Oltean return; 110455a515b1SVladimir Oltean 110555a515b1SVladimir Oltean n = taprio->num_entries; 110655a515b1SVladimir Oltean 110755a515b1SVladimir Oltean /* Walk through the gate list twice to determine the length 110855a515b1SVladimir Oltean * of consecutively open gates for a traffic class, including 110955a515b1SVladimir Oltean * open gates that wrap around. We are just interested in the 111055a515b1SVladimir Oltean * minimum window size, and this doesn't change what the 111155a515b1SVladimir Oltean * minimum is (if the gate never closes, min_gate_len will 111255a515b1SVladimir Oltean * remain U64_MAX). 111355a515b1SVladimir Oltean */ 111455a515b1SVladimir Oltean for (i = 0; i < 2 * n; i++) { 111555a515b1SVladimir Oltean entry = &taprio->entries[i % n]; 111655a515b1SVladimir Oltean 111755a515b1SVladimir Oltean for (tc = 0; tc < OCELOT_NUM_TC; tc++) { 111855a515b1SVladimir Oltean if (entry->gate_mask & BIT(tc)) { 111955a515b1SVladimir Oltean gate_len[tc] += entry->interval; 11207e4babffSVladimir Oltean gates_ever_opened |= BIT(tc); 112155a515b1SVladimir Oltean } else { 112255a515b1SVladimir Oltean /* Gate closes now, record a potential new 112355a515b1SVladimir Oltean * minimum and reinitialize length 112455a515b1SVladimir Oltean */ 11257e4babffSVladimir Oltean if (min_gate_len[tc] > gate_len[tc] && 11267e4babffSVladimir Oltean gate_len[tc]) 112755a515b1SVladimir Oltean min_gate_len[tc] = gate_len[tc]; 112855a515b1SVladimir Oltean gate_len[tc] = 0; 112955a515b1SVladimir Oltean } 113055a515b1SVladimir Oltean } 113155a515b1SVladimir Oltean } 11327e4babffSVladimir Oltean 11337e4babffSVladimir Oltean /* min_gate_len[tc] actually tracks minimum *open* gate time, so for 11347e4babffSVladimir Oltean * permanently closed gates, min_gate_len[tc] will still be U64_MAX. 11357e4babffSVladimir Oltean * Therefore they are currently indistinguishable from permanently 11367e4babffSVladimir Oltean * open gates. Overwrite the gate len with 0 when we know they're 11377e4babffSVladimir Oltean * actually permanently closed, i.e. after the loop above. 11387e4babffSVladimir Oltean */ 11397e4babffSVladimir Oltean for (tc = 0; tc < OCELOT_NUM_TC; tc++) 11407e4babffSVladimir Oltean if (!(gates_ever_opened & BIT(tc))) 11417e4babffSVladimir Oltean min_gate_len[tc] = 0; 114255a515b1SVladimir Oltean } 114355a515b1SVladimir Oltean 1144843794bbSVladimir Oltean /* ocelot_write_rix is a macro that concatenates QSYS_MAXSDU_CFG_* with _RSZ, 1145843794bbSVladimir Oltean * so we need to spell out the register access to each traffic class in helper 1146843794bbSVladimir Oltean * functions, to simplify callers 1147843794bbSVladimir Oltean */ 1148843794bbSVladimir Oltean static void vsc9959_port_qmaxsdu_set(struct ocelot *ocelot, int port, int tc, 1149843794bbSVladimir Oltean u32 max_sdu) 1150843794bbSVladimir Oltean { 1151843794bbSVladimir Oltean switch (tc) { 1152843794bbSVladimir Oltean case 0: 1153843794bbSVladimir Oltean ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_0, 1154843794bbSVladimir Oltean port); 1155843794bbSVladimir Oltean break; 1156843794bbSVladimir Oltean case 1: 1157843794bbSVladimir Oltean ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_1, 1158843794bbSVladimir Oltean port); 1159843794bbSVladimir Oltean break; 1160843794bbSVladimir Oltean case 2: 1161843794bbSVladimir Oltean ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_2, 1162843794bbSVladimir Oltean port); 1163843794bbSVladimir Oltean break; 1164843794bbSVladimir Oltean case 3: 1165843794bbSVladimir Oltean ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_3, 1166843794bbSVladimir Oltean port); 1167843794bbSVladimir Oltean break; 1168843794bbSVladimir Oltean case 4: 1169843794bbSVladimir Oltean ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_4, 1170843794bbSVladimir Oltean port); 1171843794bbSVladimir Oltean break; 1172843794bbSVladimir Oltean case 5: 1173843794bbSVladimir Oltean ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_5, 1174843794bbSVladimir Oltean port); 1175843794bbSVladimir Oltean break; 1176843794bbSVladimir Oltean case 6: 1177843794bbSVladimir Oltean ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_6, 1178843794bbSVladimir Oltean port); 1179843794bbSVladimir Oltean break; 1180843794bbSVladimir Oltean case 7: 1181843794bbSVladimir Oltean ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_7, 1182843794bbSVladimir Oltean port); 1183843794bbSVladimir Oltean break; 1184843794bbSVladimir Oltean } 1185843794bbSVladimir Oltean } 1186843794bbSVladimir Oltean 1187843794bbSVladimir Oltean static u32 vsc9959_port_qmaxsdu_get(struct ocelot *ocelot, int port, int tc) 1188843794bbSVladimir Oltean { 1189843794bbSVladimir Oltean switch (tc) { 1190843794bbSVladimir Oltean case 0: return ocelot_read_rix(ocelot, QSYS_QMAXSDU_CFG_0, port); 1191843794bbSVladimir Oltean case 1: return ocelot_read_rix(ocelot, QSYS_QMAXSDU_CFG_1, port); 1192843794bbSVladimir Oltean case 2: return ocelot_read_rix(ocelot, QSYS_QMAXSDU_CFG_2, port); 1193843794bbSVladimir Oltean case 3: return ocelot_read_rix(ocelot, QSYS_QMAXSDU_CFG_3, port); 1194843794bbSVladimir Oltean case 4: return ocelot_read_rix(ocelot, QSYS_QMAXSDU_CFG_4, port); 1195843794bbSVladimir Oltean case 5: return ocelot_read_rix(ocelot, QSYS_QMAXSDU_CFG_5, port); 1196843794bbSVladimir Oltean case 6: return ocelot_read_rix(ocelot, QSYS_QMAXSDU_CFG_6, port); 1197843794bbSVladimir Oltean case 7: return ocelot_read_rix(ocelot, QSYS_QMAXSDU_CFG_7, port); 1198843794bbSVladimir Oltean default: 1199843794bbSVladimir Oltean return 0; 1200843794bbSVladimir Oltean } 1201843794bbSVladimir Oltean } 1202843794bbSVladimir Oltean 12031712be05SVladimir Oltean static u32 vsc9959_tas_tc_max_sdu(struct tc_taprio_qopt_offload *taprio, int tc) 12041712be05SVladimir Oltean { 12051712be05SVladimir Oltean if (!taprio || !taprio->max_sdu[tc]) 12061712be05SVladimir Oltean return 0; 12071712be05SVladimir Oltean 12081712be05SVladimir Oltean return taprio->max_sdu[tc] + ETH_HLEN + 2 * VLAN_HLEN + ETH_FCS_LEN; 12091712be05SVladimir Oltean } 12101712be05SVladimir Oltean 121155a515b1SVladimir Oltean /* Update QSYS_PORT_MAX_SDU to make sure the static guard bands added by the 121255a515b1SVladimir Oltean * switch (see the ALWAYS_GUARD_BAND_SCH_Q comment) are correct at all MTU 121355a515b1SVladimir Oltean * values (the default value is 1518). Also, for traffic class windows smaller 121455a515b1SVladimir Oltean * than one MTU sized frame, update QSYS_QMAXSDU_CFG to enable oversized frame 121555a515b1SVladimir Oltean * dropping, such that these won't hang the port, as they will never be sent. 121655a515b1SVladimir Oltean */ 121755a515b1SVladimir Oltean static void vsc9959_tas_guard_bands_update(struct ocelot *ocelot, int port) 121855a515b1SVladimir Oltean { 121955a515b1SVladimir Oltean struct ocelot_port *ocelot_port = ocelot->ports[port]; 12201712be05SVladimir Oltean struct tc_taprio_qopt_offload *taprio; 122155a515b1SVladimir Oltean u64 min_gate_len[OCELOT_NUM_TC]; 122255a515b1SVladimir Oltean int speed, picos_per_byte; 122355a515b1SVladimir Oltean u64 needed_bit_time_ps; 122455a515b1SVladimir Oltean u32 val, maxlen; 122555a515b1SVladimir Oltean u8 tas_speed; 122655a515b1SVladimir Oltean int tc; 122755a515b1SVladimir Oltean 122855a515b1SVladimir Oltean lockdep_assert_held(&ocelot->tas_lock); 122955a515b1SVladimir Oltean 12301712be05SVladimir Oltean taprio = ocelot_port->taprio; 12311712be05SVladimir Oltean 123255a515b1SVladimir Oltean val = ocelot_read_rix(ocelot, QSYS_TAG_CONFIG, port); 123355a515b1SVladimir Oltean tas_speed = QSYS_TAG_CONFIG_LINK_SPEED_X(val); 123455a515b1SVladimir Oltean 123555a515b1SVladimir Oltean switch (tas_speed) { 123655a515b1SVladimir Oltean case OCELOT_SPEED_10: 123755a515b1SVladimir Oltean speed = SPEED_10; 123855a515b1SVladimir Oltean break; 123955a515b1SVladimir Oltean case OCELOT_SPEED_100: 124055a515b1SVladimir Oltean speed = SPEED_100; 124155a515b1SVladimir Oltean break; 124255a515b1SVladimir Oltean case OCELOT_SPEED_1000: 124355a515b1SVladimir Oltean speed = SPEED_1000; 124455a515b1SVladimir Oltean break; 124555a515b1SVladimir Oltean case OCELOT_SPEED_2500: 124655a515b1SVladimir Oltean speed = SPEED_2500; 124755a515b1SVladimir Oltean break; 124855a515b1SVladimir Oltean default: 124955a515b1SVladimir Oltean return; 125055a515b1SVladimir Oltean } 125155a515b1SVladimir Oltean 125255a515b1SVladimir Oltean picos_per_byte = (USEC_PER_SEC * 8) / speed; 125355a515b1SVladimir Oltean 125455a515b1SVladimir Oltean val = ocelot_port_readl(ocelot_port, DEV_MAC_MAXLEN_CFG); 125555a515b1SVladimir Oltean /* MAXLEN_CFG accounts automatically for VLAN. We need to include it 125655a515b1SVladimir Oltean * manually in the bit time calculation, plus the preamble and SFD. 125755a515b1SVladimir Oltean */ 125855a515b1SVladimir Oltean maxlen = val + 2 * VLAN_HLEN; 125955a515b1SVladimir Oltean /* Consider the standard Ethernet overhead of 8 octets preamble+SFD, 126055a515b1SVladimir Oltean * 4 octets FCS, 12 octets IFG. 126155a515b1SVladimir Oltean */ 126255a515b1SVladimir Oltean needed_bit_time_ps = (maxlen + 24) * picos_per_byte; 126355a515b1SVladimir Oltean 126455a515b1SVladimir Oltean dev_dbg(ocelot->dev, 126555a515b1SVladimir Oltean "port %d: max frame size %d needs %llu ps at speed %d\n", 126655a515b1SVladimir Oltean port, maxlen, needed_bit_time_ps, speed); 126755a515b1SVladimir Oltean 12681712be05SVladimir Oltean vsc9959_tas_min_gate_lengths(taprio, min_gate_len); 126955a515b1SVladimir Oltean 1270843794bbSVladimir Oltean mutex_lock(&ocelot->fwd_domain_lock); 1271843794bbSVladimir Oltean 127255a515b1SVladimir Oltean for (tc = 0; tc < OCELOT_NUM_TC; tc++) { 12731712be05SVladimir Oltean u32 requested_max_sdu = vsc9959_tas_tc_max_sdu(taprio, tc); 127411afdc65SVladimir Oltean u64 remaining_gate_len_ps; 127555a515b1SVladimir Oltean u32 max_sdu; 127655a515b1SVladimir Oltean 127711afdc65SVladimir Oltean remaining_gate_len_ps = 127811afdc65SVladimir Oltean vsc9959_tas_remaining_gate_len_ps(min_gate_len[tc]); 127911afdc65SVladimir Oltean 128011afdc65SVladimir Oltean if (remaining_gate_len_ps > needed_bit_time_ps) { 128155a515b1SVladimir Oltean /* Setting QMAXSDU_CFG to 0 disables oversized frame 128255a515b1SVladimir Oltean * dropping. 128355a515b1SVladimir Oltean */ 12841712be05SVladimir Oltean max_sdu = requested_max_sdu; 128555a515b1SVladimir Oltean dev_dbg(ocelot->dev, 128655a515b1SVladimir Oltean "port %d tc %d min gate len %llu" 128755a515b1SVladimir Oltean ", sending all frames\n", 128855a515b1SVladimir Oltean port, tc, min_gate_len[tc]); 128955a515b1SVladimir Oltean } else { 129055a515b1SVladimir Oltean /* If traffic class doesn't support a full MTU sized 129155a515b1SVladimir Oltean * frame, make sure to enable oversize frame dropping 129255a515b1SVladimir Oltean * for frames larger than the smallest that would fit. 129311afdc65SVladimir Oltean * 129411afdc65SVladimir Oltean * However, the exact same register, QSYS_QMAXSDU_CFG_*, 129511afdc65SVladimir Oltean * controls not only oversized frame dropping, but also 129611afdc65SVladimir Oltean * per-tc static guard band lengths, so it reduces the 129711afdc65SVladimir Oltean * useful gate interval length. Therefore, be careful 129811afdc65SVladimir Oltean * to calculate a guard band (and therefore max_sdu) 129911afdc65SVladimir Oltean * that still leaves 33 ns available in the time slot. 130055a515b1SVladimir Oltean */ 130111afdc65SVladimir Oltean max_sdu = div_u64(remaining_gate_len_ps, picos_per_byte); 130255a515b1SVladimir Oltean /* A TC gate may be completely closed, which is a 130355a515b1SVladimir Oltean * special case where all packets are oversized. 130455a515b1SVladimir Oltean * Any limit smaller than 64 octets accomplishes this 130555a515b1SVladimir Oltean */ 130655a515b1SVladimir Oltean if (!max_sdu) 130755a515b1SVladimir Oltean max_sdu = 1; 130855a515b1SVladimir Oltean /* Take L1 overhead into account, but just don't allow 130955a515b1SVladimir Oltean * max_sdu to go negative or to 0. Here we use 20 131055a515b1SVladimir Oltean * because QSYS_MAXSDU_CFG_* already counts the 4 FCS 131155a515b1SVladimir Oltean * octets as part of packet size. 131255a515b1SVladimir Oltean */ 131355a515b1SVladimir Oltean if (max_sdu > 20) 131455a515b1SVladimir Oltean max_sdu -= 20; 13151712be05SVladimir Oltean 13161712be05SVladimir Oltean if (requested_max_sdu && requested_max_sdu < max_sdu) 13171712be05SVladimir Oltean max_sdu = requested_max_sdu; 13181712be05SVladimir Oltean 131955a515b1SVladimir Oltean dev_info(ocelot->dev, 132055a515b1SVladimir Oltean "port %d tc %d min gate length %llu" 132155a515b1SVladimir Oltean " ns not enough for max frame size %d at %d" 132255a515b1SVladimir Oltean " Mbps, dropping frames over %d" 132355a515b1SVladimir Oltean " octets including FCS\n", 132455a515b1SVladimir Oltean port, tc, min_gate_len[tc], maxlen, speed, 132555a515b1SVladimir Oltean max_sdu); 132655a515b1SVladimir Oltean } 132755a515b1SVladimir Oltean 1328843794bbSVladimir Oltean vsc9959_port_qmaxsdu_set(ocelot, port, tc, max_sdu); 132955a515b1SVladimir Oltean } 133055a515b1SVladimir Oltean 133155a515b1SVladimir Oltean ocelot_write_rix(ocelot, maxlen, QSYS_PORT_MAX_SDU, port); 1332843794bbSVladimir Oltean 1333843794bbSVladimir Oltean ocelot->ops->cut_through_fwd(ocelot); 1334843794bbSVladimir Oltean 1335843794bbSVladimir Oltean mutex_unlock(&ocelot->fwd_domain_lock); 133655a515b1SVladimir Oltean } 133755a515b1SVladimir Oltean 1338de143c0eSXiaoliang Yang static void vsc9959_sched_speed_set(struct ocelot *ocelot, int port, 1339de143c0eSXiaoliang Yang u32 speed) 1340de143c0eSXiaoliang Yang { 134155a515b1SVladimir Oltean struct ocelot_port *ocelot_port = ocelot->ports[port]; 1342dba1e466SXiaoliang Yang u8 tas_speed; 1343dba1e466SXiaoliang Yang 1344dba1e466SXiaoliang Yang switch (speed) { 1345dba1e466SXiaoliang Yang case SPEED_10: 1346dba1e466SXiaoliang Yang tas_speed = OCELOT_SPEED_10; 1347dba1e466SXiaoliang Yang break; 1348dba1e466SXiaoliang Yang case SPEED_100: 1349dba1e466SXiaoliang Yang tas_speed = OCELOT_SPEED_100; 1350dba1e466SXiaoliang Yang break; 1351dba1e466SXiaoliang Yang case SPEED_1000: 1352dba1e466SXiaoliang Yang tas_speed = OCELOT_SPEED_1000; 1353dba1e466SXiaoliang Yang break; 1354dba1e466SXiaoliang Yang case SPEED_2500: 1355dba1e466SXiaoliang Yang tas_speed = OCELOT_SPEED_2500; 1356dba1e466SXiaoliang Yang break; 1357dba1e466SXiaoliang Yang default: 1358dba1e466SXiaoliang Yang tas_speed = OCELOT_SPEED_1000; 1359dba1e466SXiaoliang Yang break; 1360dba1e466SXiaoliang Yang } 1361dba1e466SXiaoliang Yang 1362a4bb481aSVladimir Oltean mutex_lock(&ocelot->tas_lock); 1363a4bb481aSVladimir Oltean 1364de143c0eSXiaoliang Yang ocelot_rmw_rix(ocelot, 1365dba1e466SXiaoliang Yang QSYS_TAG_CONFIG_LINK_SPEED(tas_speed), 1366de143c0eSXiaoliang Yang QSYS_TAG_CONFIG_LINK_SPEED_M, 1367de143c0eSXiaoliang Yang QSYS_TAG_CONFIG, port); 136855a515b1SVladimir Oltean 136955a515b1SVladimir Oltean if (ocelot_port->taprio) 137055a515b1SVladimir Oltean vsc9959_tas_guard_bands_update(ocelot, port); 137155a515b1SVladimir Oltean 137255a515b1SVladimir Oltean mutex_unlock(&ocelot->tas_lock); 1373de143c0eSXiaoliang Yang } 1374de143c0eSXiaoliang Yang 1375de143c0eSXiaoliang Yang static void vsc9959_new_base_time(struct ocelot *ocelot, ktime_t base_time, 1376de143c0eSXiaoliang Yang u64 cycle_time, 1377de143c0eSXiaoliang Yang struct timespec64 *new_base_ts) 1378de143c0eSXiaoliang Yang { 1379de143c0eSXiaoliang Yang struct timespec64 ts; 1380de143c0eSXiaoliang Yang ktime_t new_base_time; 1381de143c0eSXiaoliang Yang ktime_t current_time; 1382de143c0eSXiaoliang Yang 1383de143c0eSXiaoliang Yang ocelot_ptp_gettime64(&ocelot->ptp_info, &ts); 1384de143c0eSXiaoliang Yang current_time = timespec64_to_ktime(ts); 1385de143c0eSXiaoliang Yang new_base_time = base_time; 1386de143c0eSXiaoliang Yang 1387de143c0eSXiaoliang Yang if (base_time < current_time) { 1388de143c0eSXiaoliang Yang u64 nr_of_cycles = current_time - base_time; 1389de143c0eSXiaoliang Yang 1390de143c0eSXiaoliang Yang do_div(nr_of_cycles, cycle_time); 1391de143c0eSXiaoliang Yang new_base_time += cycle_time * (nr_of_cycles + 1); 1392de143c0eSXiaoliang Yang } 1393de143c0eSXiaoliang Yang 1394de143c0eSXiaoliang Yang *new_base_ts = ktime_to_timespec64(new_base_time); 1395de143c0eSXiaoliang Yang } 1396de143c0eSXiaoliang Yang 1397de143c0eSXiaoliang Yang static u32 vsc9959_tas_read_cfg_status(struct ocelot *ocelot) 1398de143c0eSXiaoliang Yang { 1399de143c0eSXiaoliang Yang return ocelot_read(ocelot, QSYS_TAS_PARAM_CFG_CTRL); 1400de143c0eSXiaoliang Yang } 1401de143c0eSXiaoliang Yang 1402de143c0eSXiaoliang Yang static void vsc9959_tas_gcl_set(struct ocelot *ocelot, const u32 gcl_ix, 1403de143c0eSXiaoliang Yang struct tc_taprio_sched_entry *entry) 1404de143c0eSXiaoliang Yang { 1405de143c0eSXiaoliang Yang ocelot_write(ocelot, 1406de143c0eSXiaoliang Yang QSYS_GCL_CFG_REG_1_GCL_ENTRY_NUM(gcl_ix) | 1407de143c0eSXiaoliang Yang QSYS_GCL_CFG_REG_1_GATE_STATE(entry->gate_mask), 1408de143c0eSXiaoliang Yang QSYS_GCL_CFG_REG_1); 1409de143c0eSXiaoliang Yang ocelot_write(ocelot, entry->interval, QSYS_GCL_CFG_REG_2); 1410de143c0eSXiaoliang Yang } 1411de143c0eSXiaoliang Yang 1412de143c0eSXiaoliang Yang static int vsc9959_qos_port_tas_set(struct ocelot *ocelot, int port, 1413de143c0eSXiaoliang Yang struct tc_taprio_qopt_offload *taprio) 1414de143c0eSXiaoliang Yang { 14158670dc33SXiaoliang Yang struct ocelot_port *ocelot_port = ocelot->ports[port]; 1416de143c0eSXiaoliang Yang struct timespec64 base_ts; 1417de143c0eSXiaoliang Yang int ret, i; 1418de143c0eSXiaoliang Yang u32 val; 1419de143c0eSXiaoliang Yang 14208670dc33SXiaoliang Yang mutex_lock(&ocelot->tas_lock); 14218670dc33SXiaoliang Yang 1422de143c0eSXiaoliang Yang if (!taprio->enable) { 1423d68a373bSVladimir Oltean ocelot_rmw_rix(ocelot, 0, QSYS_TAG_CONFIG_ENABLE, 1424de143c0eSXiaoliang Yang QSYS_TAG_CONFIG, port); 1425de143c0eSXiaoliang Yang 14261c9017e4SVladimir Oltean taprio_offload_free(ocelot_port->taprio); 14271c9017e4SVladimir Oltean ocelot_port->taprio = NULL; 14281c9017e4SVladimir Oltean 142955a515b1SVladimir Oltean vsc9959_tas_guard_bands_update(ocelot, port); 143055a515b1SVladimir Oltean 14318670dc33SXiaoliang Yang mutex_unlock(&ocelot->tas_lock); 1432de143c0eSXiaoliang Yang return 0; 1433de143c0eSXiaoliang Yang } 1434de143c0eSXiaoliang Yang 1435de143c0eSXiaoliang Yang if (taprio->cycle_time > NSEC_PER_SEC || 14368670dc33SXiaoliang Yang taprio->cycle_time_extension >= NSEC_PER_SEC) { 14378670dc33SXiaoliang Yang ret = -EINVAL; 14388670dc33SXiaoliang Yang goto err; 14398670dc33SXiaoliang Yang } 1440de143c0eSXiaoliang Yang 14418670dc33SXiaoliang Yang if (taprio->num_entries > VSC9959_TAS_GCL_ENTRY_MAX) { 14428670dc33SXiaoliang Yang ret = -ERANGE; 14438670dc33SXiaoliang Yang goto err; 14448670dc33SXiaoliang Yang } 1445de143c0eSXiaoliang Yang 1446297c4de6SMichael Walle /* Enable guard band. The switch will schedule frames without taking 1447297c4de6SMichael Walle * their length into account. Thus we'll always need to enable the 1448297c4de6SMichael Walle * guard band which reserves the time of a maximum sized frame at the 1449297c4de6SMichael Walle * end of the time window. 1450297c4de6SMichael Walle * 1451297c4de6SMichael Walle * Although the ALWAYS_GUARD_BAND_SCH_Q bit is global for all ports, we 1452297c4de6SMichael Walle * need to set PORT_NUM, because subsequent writes to PARAM_CFG_REG_n 1453297c4de6SMichael Walle * operate on the port number. 1454316bcffeSXiaoliang Yang */ 1455297c4de6SMichael Walle ocelot_rmw(ocelot, QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM(port) | 1456297c4de6SMichael Walle QSYS_TAS_PARAM_CFG_CTRL_ALWAYS_GUARD_BAND_SCH_Q, 1457de143c0eSXiaoliang Yang QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM_M | 1458de143c0eSXiaoliang Yang QSYS_TAS_PARAM_CFG_CTRL_ALWAYS_GUARD_BAND_SCH_Q, 1459de143c0eSXiaoliang Yang QSYS_TAS_PARAM_CFG_CTRL); 1460de143c0eSXiaoliang Yang 1461de143c0eSXiaoliang Yang /* Hardware errata - Admin config could not be overwritten if 1462de143c0eSXiaoliang Yang * config is pending, need reset the TAS module 1463de143c0eSXiaoliang Yang */ 1464de143c0eSXiaoliang Yang val = ocelot_read(ocelot, QSYS_PARAM_STATUS_REG_8); 14658670dc33SXiaoliang Yang if (val & QSYS_PARAM_STATUS_REG_8_CONFIG_PENDING) { 14668670dc33SXiaoliang Yang ret = -EBUSY; 14678670dc33SXiaoliang Yang goto err; 14688670dc33SXiaoliang Yang } 1469de143c0eSXiaoliang Yang 1470de143c0eSXiaoliang Yang ocelot_rmw_rix(ocelot, 1471de143c0eSXiaoliang Yang QSYS_TAG_CONFIG_ENABLE | 1472de143c0eSXiaoliang Yang QSYS_TAG_CONFIG_INIT_GATE_STATE(0xFF) | 1473de143c0eSXiaoliang Yang QSYS_TAG_CONFIG_SCH_TRAFFIC_QUEUES(0xFF), 1474de143c0eSXiaoliang Yang QSYS_TAG_CONFIG_ENABLE | 1475de143c0eSXiaoliang Yang QSYS_TAG_CONFIG_INIT_GATE_STATE_M | 1476de143c0eSXiaoliang Yang QSYS_TAG_CONFIG_SCH_TRAFFIC_QUEUES_M, 1477de143c0eSXiaoliang Yang QSYS_TAG_CONFIG, port); 1478de143c0eSXiaoliang Yang 1479de143c0eSXiaoliang Yang vsc9959_new_base_time(ocelot, taprio->base_time, 1480de143c0eSXiaoliang Yang taprio->cycle_time, &base_ts); 1481de143c0eSXiaoliang Yang ocelot_write(ocelot, base_ts.tv_nsec, QSYS_PARAM_CFG_REG_1); 1482de143c0eSXiaoliang Yang ocelot_write(ocelot, lower_32_bits(base_ts.tv_sec), QSYS_PARAM_CFG_REG_2); 1483de143c0eSXiaoliang Yang val = upper_32_bits(base_ts.tv_sec); 1484de143c0eSXiaoliang Yang ocelot_write(ocelot, 1485de143c0eSXiaoliang Yang QSYS_PARAM_CFG_REG_3_BASE_TIME_SEC_MSB(val) | 1486de143c0eSXiaoliang Yang QSYS_PARAM_CFG_REG_3_LIST_LENGTH(taprio->num_entries), 1487de143c0eSXiaoliang Yang QSYS_PARAM_CFG_REG_3); 1488de143c0eSXiaoliang Yang ocelot_write(ocelot, taprio->cycle_time, QSYS_PARAM_CFG_REG_4); 1489de143c0eSXiaoliang Yang ocelot_write(ocelot, taprio->cycle_time_extension, QSYS_PARAM_CFG_REG_5); 1490de143c0eSXiaoliang Yang 1491de143c0eSXiaoliang Yang for (i = 0; i < taprio->num_entries; i++) 1492de143c0eSXiaoliang Yang vsc9959_tas_gcl_set(ocelot, i, &taprio->entries[i]); 1493de143c0eSXiaoliang Yang 1494de143c0eSXiaoliang Yang ocelot_rmw(ocelot, QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE, 1495de143c0eSXiaoliang Yang QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE, 1496de143c0eSXiaoliang Yang QSYS_TAS_PARAM_CFG_CTRL); 1497de143c0eSXiaoliang Yang 1498de143c0eSXiaoliang Yang ret = readx_poll_timeout(vsc9959_tas_read_cfg_status, ocelot, val, 1499de143c0eSXiaoliang Yang !(val & QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE), 1500de143c0eSXiaoliang Yang 10, 100000); 15011c9017e4SVladimir Oltean if (ret) 15021c9017e4SVladimir Oltean goto err; 15031c9017e4SVladimir Oltean 15041c9017e4SVladimir Oltean ocelot_port->taprio = taprio_offload_get(taprio); 150555a515b1SVladimir Oltean vsc9959_tas_guard_bands_update(ocelot, port); 1506de143c0eSXiaoliang Yang 15078670dc33SXiaoliang Yang err: 15088670dc33SXiaoliang Yang mutex_unlock(&ocelot->tas_lock); 15098670dc33SXiaoliang Yang 1510de143c0eSXiaoliang Yang return ret; 1511de143c0eSXiaoliang Yang } 1512de143c0eSXiaoliang Yang 15138670dc33SXiaoliang Yang static void vsc9959_tas_clock_adjust(struct ocelot *ocelot) 15148670dc33SXiaoliang Yang { 15151c9017e4SVladimir Oltean struct tc_taprio_qopt_offload *taprio; 15168670dc33SXiaoliang Yang struct ocelot_port *ocelot_port; 15178670dc33SXiaoliang Yang struct timespec64 base_ts; 15188670dc33SXiaoliang Yang int port; 15198670dc33SXiaoliang Yang u32 val; 15208670dc33SXiaoliang Yang 15218670dc33SXiaoliang Yang mutex_lock(&ocelot->tas_lock); 15228670dc33SXiaoliang Yang 15238670dc33SXiaoliang Yang for (port = 0; port < ocelot->num_phys_ports; port++) { 15241c9017e4SVladimir Oltean ocelot_port = ocelot->ports[port]; 15251c9017e4SVladimir Oltean taprio = ocelot_port->taprio; 15261c9017e4SVladimir Oltean if (!taprio) 15278670dc33SXiaoliang Yang continue; 15288670dc33SXiaoliang Yang 15298670dc33SXiaoliang Yang ocelot_rmw(ocelot, 15308670dc33SXiaoliang Yang QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM(port), 15318670dc33SXiaoliang Yang QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM_M, 15328670dc33SXiaoliang Yang QSYS_TAS_PARAM_CFG_CTRL); 15338670dc33SXiaoliang Yang 1534d68a373bSVladimir Oltean /* Disable time-aware shaper */ 1535d68a373bSVladimir Oltean ocelot_rmw_rix(ocelot, 0, QSYS_TAG_CONFIG_ENABLE, 15368670dc33SXiaoliang Yang QSYS_TAG_CONFIG, port); 15378670dc33SXiaoliang Yang 15381c9017e4SVladimir Oltean vsc9959_new_base_time(ocelot, taprio->base_time, 15391c9017e4SVladimir Oltean taprio->cycle_time, &base_ts); 15408670dc33SXiaoliang Yang 15418670dc33SXiaoliang Yang ocelot_write(ocelot, base_ts.tv_nsec, QSYS_PARAM_CFG_REG_1); 15428670dc33SXiaoliang Yang ocelot_write(ocelot, lower_32_bits(base_ts.tv_sec), 15438670dc33SXiaoliang Yang QSYS_PARAM_CFG_REG_2); 15448670dc33SXiaoliang Yang val = upper_32_bits(base_ts.tv_sec); 15458670dc33SXiaoliang Yang ocelot_rmw(ocelot, 15468670dc33SXiaoliang Yang QSYS_PARAM_CFG_REG_3_BASE_TIME_SEC_MSB(val), 15478670dc33SXiaoliang Yang QSYS_PARAM_CFG_REG_3_BASE_TIME_SEC_MSB_M, 15488670dc33SXiaoliang Yang QSYS_PARAM_CFG_REG_3); 15498670dc33SXiaoliang Yang 15508670dc33SXiaoliang Yang ocelot_rmw(ocelot, QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE, 15518670dc33SXiaoliang Yang QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE, 15528670dc33SXiaoliang Yang QSYS_TAS_PARAM_CFG_CTRL); 15538670dc33SXiaoliang Yang 1554d68a373bSVladimir Oltean /* Re-enable time-aware shaper */ 1555d68a373bSVladimir Oltean ocelot_rmw_rix(ocelot, QSYS_TAG_CONFIG_ENABLE, 15568670dc33SXiaoliang Yang QSYS_TAG_CONFIG_ENABLE, 15578670dc33SXiaoliang Yang QSYS_TAG_CONFIG, port); 15588670dc33SXiaoliang Yang } 15598670dc33SXiaoliang Yang mutex_unlock(&ocelot->tas_lock); 15608670dc33SXiaoliang Yang } 15618670dc33SXiaoliang Yang 15620fbabf87SXiaoliang Yang static int vsc9959_qos_port_cbs_set(struct dsa_switch *ds, int port, 15630fbabf87SXiaoliang Yang struct tc_cbs_qopt_offload *cbs_qopt) 15640fbabf87SXiaoliang Yang { 15650fbabf87SXiaoliang Yang struct ocelot *ocelot = ds->priv; 15660fbabf87SXiaoliang Yang int port_ix = port * 8 + cbs_qopt->queue; 15670fbabf87SXiaoliang Yang u32 rate, burst; 15680fbabf87SXiaoliang Yang 15690fbabf87SXiaoliang Yang if (cbs_qopt->queue >= ds->num_tx_queues) 15700fbabf87SXiaoliang Yang return -EINVAL; 15710fbabf87SXiaoliang Yang 15720fbabf87SXiaoliang Yang if (!cbs_qopt->enable) { 15730fbabf87SXiaoliang Yang ocelot_write_gix(ocelot, QSYS_CIR_CFG_CIR_RATE(0) | 15740fbabf87SXiaoliang Yang QSYS_CIR_CFG_CIR_BURST(0), 15750fbabf87SXiaoliang Yang QSYS_CIR_CFG, port_ix); 15760fbabf87SXiaoliang Yang 15770fbabf87SXiaoliang Yang ocelot_rmw_gix(ocelot, 0, QSYS_SE_CFG_SE_AVB_ENA, 15780fbabf87SXiaoliang Yang QSYS_SE_CFG, port_ix); 15790fbabf87SXiaoliang Yang 15800fbabf87SXiaoliang Yang return 0; 15810fbabf87SXiaoliang Yang } 15820fbabf87SXiaoliang Yang 15830fbabf87SXiaoliang Yang /* Rate unit is 100 kbps */ 15840fbabf87SXiaoliang Yang rate = DIV_ROUND_UP(cbs_qopt->idleslope, 100); 15850fbabf87SXiaoliang Yang /* Avoid using zero rate */ 15860fbabf87SXiaoliang Yang rate = clamp_t(u32, rate, 1, GENMASK(14, 0)); 15870fbabf87SXiaoliang Yang /* Burst unit is 4kB */ 15880fbabf87SXiaoliang Yang burst = DIV_ROUND_UP(cbs_qopt->hicredit, 4096); 15890fbabf87SXiaoliang Yang /* Avoid using zero burst size */ 1590b014d043SColin Ian King burst = clamp_t(u32, burst, 1, GENMASK(5, 0)); 15910fbabf87SXiaoliang Yang ocelot_write_gix(ocelot, 15920fbabf87SXiaoliang Yang QSYS_CIR_CFG_CIR_RATE(rate) | 15930fbabf87SXiaoliang Yang QSYS_CIR_CFG_CIR_BURST(burst), 15940fbabf87SXiaoliang Yang QSYS_CIR_CFG, 15950fbabf87SXiaoliang Yang port_ix); 15960fbabf87SXiaoliang Yang 15970fbabf87SXiaoliang Yang ocelot_rmw_gix(ocelot, 15980fbabf87SXiaoliang Yang QSYS_SE_CFG_SE_FRM_MODE(0) | 15990fbabf87SXiaoliang Yang QSYS_SE_CFG_SE_AVB_ENA, 16000fbabf87SXiaoliang Yang QSYS_SE_CFG_SE_AVB_ENA | 16010fbabf87SXiaoliang Yang QSYS_SE_CFG_SE_FRM_MODE_M, 16020fbabf87SXiaoliang Yang QSYS_SE_CFG, 16030fbabf87SXiaoliang Yang port_ix); 16040fbabf87SXiaoliang Yang 16050fbabf87SXiaoliang Yang return 0; 16060fbabf87SXiaoliang Yang } 16070fbabf87SXiaoliang Yang 16081712be05SVladimir Oltean static int vsc9959_qos_query_caps(struct tc_query_caps_base *base) 16091712be05SVladimir Oltean { 16101712be05SVladimir Oltean switch (base->type) { 16111712be05SVladimir Oltean case TC_SETUP_QDISC_TAPRIO: { 16121712be05SVladimir Oltean struct tc_taprio_caps *caps = base->caps; 16131712be05SVladimir Oltean 16141712be05SVladimir Oltean caps->supports_queue_max_sdu = true; 16151712be05SVladimir Oltean 16161712be05SVladimir Oltean return 0; 16171712be05SVladimir Oltean } 16181712be05SVladimir Oltean default: 16191712be05SVladimir Oltean return -EOPNOTSUPP; 16201712be05SVladimir Oltean } 16211712be05SVladimir Oltean } 16221712be05SVladimir Oltean 1623de143c0eSXiaoliang Yang static int vsc9959_port_setup_tc(struct dsa_switch *ds, int port, 1624de143c0eSXiaoliang Yang enum tc_setup_type type, 1625de143c0eSXiaoliang Yang void *type_data) 1626de143c0eSXiaoliang Yang { 1627de143c0eSXiaoliang Yang struct ocelot *ocelot = ds->priv; 1628de143c0eSXiaoliang Yang 1629de143c0eSXiaoliang Yang switch (type) { 16301712be05SVladimir Oltean case TC_QUERY_CAPS: 16311712be05SVladimir Oltean return vsc9959_qos_query_caps(type_data); 1632de143c0eSXiaoliang Yang case TC_SETUP_QDISC_TAPRIO: 1633de143c0eSXiaoliang Yang return vsc9959_qos_port_tas_set(ocelot, port, type_data); 16340fbabf87SXiaoliang Yang case TC_SETUP_QDISC_CBS: 16350fbabf87SXiaoliang Yang return vsc9959_qos_port_cbs_set(ds, port, type_data); 1636de143c0eSXiaoliang Yang default: 1637de143c0eSXiaoliang Yang return -EOPNOTSUPP; 1638de143c0eSXiaoliang Yang } 1639de143c0eSXiaoliang Yang } 1640de143c0eSXiaoliang Yang 16417d4b564dSXiaoliang Yang #define VSC9959_PSFP_SFID_MAX 175 16427d4b564dSXiaoliang Yang #define VSC9959_PSFP_GATE_ID_MAX 183 164376c13edeSXiaoliang Yang #define VSC9959_PSFP_POLICER_BASE 63 16447d4b564dSXiaoliang Yang #define VSC9959_PSFP_POLICER_MAX 383 164523ae3a78SXiaoliang Yang #define VSC9959_PSFP_GATE_LIST_NUM 4 164623ae3a78SXiaoliang Yang #define VSC9959_PSFP_GATE_CYCLETIME_MIN 5000 16477d4b564dSXiaoliang Yang 16487d4b564dSXiaoliang Yang struct felix_stream { 16497d4b564dSXiaoliang Yang struct list_head list; 16507d4b564dSXiaoliang Yang unsigned long id; 1651a7e13edfSXiaoliang Yang bool dummy; 1652a7e13edfSXiaoliang Yang int ports; 1653a7e13edfSXiaoliang Yang int port; 16547d4b564dSXiaoliang Yang u8 dmac[ETH_ALEN]; 16557d4b564dSXiaoliang Yang u16 vid; 16567d4b564dSXiaoliang Yang s8 prio; 16577d4b564dSXiaoliang Yang u8 sfid_valid; 16587d4b564dSXiaoliang Yang u8 ssid_valid; 16597d4b564dSXiaoliang Yang u32 sfid; 16607d4b564dSXiaoliang Yang u32 ssid; 16617d4b564dSXiaoliang Yang }; 16627d4b564dSXiaoliang Yang 166325027c84SVladimir Oltean struct felix_stream_filter_counters { 166425027c84SVladimir Oltean u64 match; 166525027c84SVladimir Oltean u64 not_pass_gate; 166625027c84SVladimir Oltean u64 not_pass_sdu; 166725027c84SVladimir Oltean u64 red; 166825027c84SVladimir Oltean }; 166925027c84SVladimir Oltean 16707d4b564dSXiaoliang Yang struct felix_stream_filter { 167125027c84SVladimir Oltean struct felix_stream_filter_counters stats; 16727d4b564dSXiaoliang Yang struct list_head list; 16737d4b564dSXiaoliang Yang refcount_t refcount; 16747d4b564dSXiaoliang Yang u32 index; 16757d4b564dSXiaoliang Yang u8 enable; 1676a7e13edfSXiaoliang Yang int portmask; 16777d4b564dSXiaoliang Yang u8 sg_valid; 16787d4b564dSXiaoliang Yang u32 sgid; 16797d4b564dSXiaoliang Yang u8 fm_valid; 16807d4b564dSXiaoliang Yang u32 fmid; 16817d4b564dSXiaoliang Yang u8 prio_valid; 16827d4b564dSXiaoliang Yang u8 prio; 16837d4b564dSXiaoliang Yang u32 maxsdu; 16847d4b564dSXiaoliang Yang }; 16857d4b564dSXiaoliang Yang 168623ae3a78SXiaoliang Yang struct felix_stream_gate { 168723ae3a78SXiaoliang Yang u32 index; 168823ae3a78SXiaoliang Yang u8 enable; 168923ae3a78SXiaoliang Yang u8 ipv_valid; 169023ae3a78SXiaoliang Yang u8 init_ipv; 169123ae3a78SXiaoliang Yang u64 basetime; 169223ae3a78SXiaoliang Yang u64 cycletime; 169323ae3a78SXiaoliang Yang u64 cycletime_ext; 169423ae3a78SXiaoliang Yang u32 num_entries; 1695dcad856fSkernel test robot struct action_gate_entry entries[]; 169623ae3a78SXiaoliang Yang }; 169723ae3a78SXiaoliang Yang 169823ae3a78SXiaoliang Yang struct felix_stream_gate_entry { 169923ae3a78SXiaoliang Yang struct list_head list; 170023ae3a78SXiaoliang Yang refcount_t refcount; 170123ae3a78SXiaoliang Yang u32 index; 170223ae3a78SXiaoliang Yang }; 170323ae3a78SXiaoliang Yang 17047d4b564dSXiaoliang Yang static int vsc9959_stream_identify(struct flow_cls_offload *f, 17057d4b564dSXiaoliang Yang struct felix_stream *stream) 17067d4b564dSXiaoliang Yang { 17077d4b564dSXiaoliang Yang struct flow_rule *rule = flow_cls_offload_flow_rule(f); 17087d4b564dSXiaoliang Yang struct flow_dissector *dissector = rule->match.dissector; 17097d4b564dSXiaoliang Yang 17107d4b564dSXiaoliang Yang if (dissector->used_keys & 17117d4b564dSXiaoliang Yang ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) | 17127d4b564dSXiaoliang Yang BIT(FLOW_DISSECTOR_KEY_BASIC) | 17137d4b564dSXiaoliang Yang BIT(FLOW_DISSECTOR_KEY_VLAN) | 17147d4b564dSXiaoliang Yang BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS))) 17157d4b564dSXiaoliang Yang return -EOPNOTSUPP; 17167d4b564dSXiaoliang Yang 17177d4b564dSXiaoliang Yang if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) { 17187d4b564dSXiaoliang Yang struct flow_match_eth_addrs match; 17197d4b564dSXiaoliang Yang 17207d4b564dSXiaoliang Yang flow_rule_match_eth_addrs(rule, &match); 17217d4b564dSXiaoliang Yang ether_addr_copy(stream->dmac, match.key->dst); 17227d4b564dSXiaoliang Yang if (!is_zero_ether_addr(match.mask->src)) 17237d4b564dSXiaoliang Yang return -EOPNOTSUPP; 17247d4b564dSXiaoliang Yang } else { 17257d4b564dSXiaoliang Yang return -EOPNOTSUPP; 17267d4b564dSXiaoliang Yang } 17277d4b564dSXiaoliang Yang 17287d4b564dSXiaoliang Yang if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) { 17297d4b564dSXiaoliang Yang struct flow_match_vlan match; 17307d4b564dSXiaoliang Yang 17317d4b564dSXiaoliang Yang flow_rule_match_vlan(rule, &match); 17327d4b564dSXiaoliang Yang if (match.mask->vlan_priority) 17337d4b564dSXiaoliang Yang stream->prio = match.key->vlan_priority; 17347d4b564dSXiaoliang Yang else 17357d4b564dSXiaoliang Yang stream->prio = -1; 17367d4b564dSXiaoliang Yang 17377d4b564dSXiaoliang Yang if (!match.mask->vlan_id) 17387d4b564dSXiaoliang Yang return -EOPNOTSUPP; 17397d4b564dSXiaoliang Yang stream->vid = match.key->vlan_id; 17407d4b564dSXiaoliang Yang } else { 17417d4b564dSXiaoliang Yang return -EOPNOTSUPP; 17427d4b564dSXiaoliang Yang } 17437d4b564dSXiaoliang Yang 17447d4b564dSXiaoliang Yang stream->id = f->cookie; 17457d4b564dSXiaoliang Yang 17467d4b564dSXiaoliang Yang return 0; 17477d4b564dSXiaoliang Yang } 17487d4b564dSXiaoliang Yang 17497d4b564dSXiaoliang Yang static int vsc9959_mact_stream_set(struct ocelot *ocelot, 17507d4b564dSXiaoliang Yang struct felix_stream *stream, 17517d4b564dSXiaoliang Yang struct netlink_ext_ack *extack) 17527d4b564dSXiaoliang Yang { 17537d4b564dSXiaoliang Yang enum macaccess_entry_type type; 17547d4b564dSXiaoliang Yang int ret, sfid, ssid; 17557d4b564dSXiaoliang Yang u32 vid, dst_idx; 17567d4b564dSXiaoliang Yang u8 mac[ETH_ALEN]; 17577d4b564dSXiaoliang Yang 17587d4b564dSXiaoliang Yang ether_addr_copy(mac, stream->dmac); 17597d4b564dSXiaoliang Yang vid = stream->vid; 17607d4b564dSXiaoliang Yang 17617d4b564dSXiaoliang Yang /* Stream identification desn't support to add a stream with non 17627d4b564dSXiaoliang Yang * existent MAC (The MAC entry has not been learned in MAC table). 17637d4b564dSXiaoliang Yang */ 17647d4b564dSXiaoliang Yang ret = ocelot_mact_lookup(ocelot, &dst_idx, mac, vid, &type); 17657d4b564dSXiaoliang Yang if (ret) { 17667d4b564dSXiaoliang Yang if (extack) 17677d4b564dSXiaoliang Yang NL_SET_ERR_MSG_MOD(extack, "Stream is not learned in MAC table"); 17687d4b564dSXiaoliang Yang return -EOPNOTSUPP; 17697d4b564dSXiaoliang Yang } 17707d4b564dSXiaoliang Yang 17717d4b564dSXiaoliang Yang if ((stream->sfid_valid || stream->ssid_valid) && 17727d4b564dSXiaoliang Yang type == ENTRYTYPE_NORMAL) 17737d4b564dSXiaoliang Yang type = ENTRYTYPE_LOCKED; 17747d4b564dSXiaoliang Yang 17757d4b564dSXiaoliang Yang sfid = stream->sfid_valid ? stream->sfid : -1; 17767d4b564dSXiaoliang Yang ssid = stream->ssid_valid ? stream->ssid : -1; 17777d4b564dSXiaoliang Yang 17787d4b564dSXiaoliang Yang ret = ocelot_mact_learn_streamdata(ocelot, dst_idx, mac, vid, type, 17797d4b564dSXiaoliang Yang sfid, ssid); 17807d4b564dSXiaoliang Yang 17817d4b564dSXiaoliang Yang return ret; 17827d4b564dSXiaoliang Yang } 17837d4b564dSXiaoliang Yang 17847d4b564dSXiaoliang Yang static struct felix_stream * 17857d4b564dSXiaoliang Yang vsc9959_stream_table_lookup(struct list_head *stream_list, 17867d4b564dSXiaoliang Yang struct felix_stream *stream) 17877d4b564dSXiaoliang Yang { 17887d4b564dSXiaoliang Yang struct felix_stream *tmp; 17897d4b564dSXiaoliang Yang 17907d4b564dSXiaoliang Yang list_for_each_entry(tmp, stream_list, list) 17917d4b564dSXiaoliang Yang if (ether_addr_equal(tmp->dmac, stream->dmac) && 17927d4b564dSXiaoliang Yang tmp->vid == stream->vid) 17937d4b564dSXiaoliang Yang return tmp; 17947d4b564dSXiaoliang Yang 17957d4b564dSXiaoliang Yang return NULL; 17967d4b564dSXiaoliang Yang } 17977d4b564dSXiaoliang Yang 17987d4b564dSXiaoliang Yang static int vsc9959_stream_table_add(struct ocelot *ocelot, 17997d4b564dSXiaoliang Yang struct list_head *stream_list, 18007d4b564dSXiaoliang Yang struct felix_stream *stream, 18017d4b564dSXiaoliang Yang struct netlink_ext_ack *extack) 18027d4b564dSXiaoliang Yang { 18037d4b564dSXiaoliang Yang struct felix_stream *stream_entry; 18047d4b564dSXiaoliang Yang int ret; 18057d4b564dSXiaoliang Yang 1806e44aecc7SYihao Han stream_entry = kmemdup(stream, sizeof(*stream_entry), GFP_KERNEL); 18077d4b564dSXiaoliang Yang if (!stream_entry) 18087d4b564dSXiaoliang Yang return -ENOMEM; 18097d4b564dSXiaoliang Yang 1810a7e13edfSXiaoliang Yang if (!stream->dummy) { 18117d4b564dSXiaoliang Yang ret = vsc9959_mact_stream_set(ocelot, stream_entry, extack); 18127d4b564dSXiaoliang Yang if (ret) { 18137d4b564dSXiaoliang Yang kfree(stream_entry); 18147d4b564dSXiaoliang Yang return ret; 18157d4b564dSXiaoliang Yang } 1816a7e13edfSXiaoliang Yang } 18177d4b564dSXiaoliang Yang 18187d4b564dSXiaoliang Yang list_add_tail(&stream_entry->list, stream_list); 18197d4b564dSXiaoliang Yang 18207d4b564dSXiaoliang Yang return 0; 18217d4b564dSXiaoliang Yang } 18227d4b564dSXiaoliang Yang 18237d4b564dSXiaoliang Yang static struct felix_stream * 18247d4b564dSXiaoliang Yang vsc9959_stream_table_get(struct list_head *stream_list, unsigned long id) 18257d4b564dSXiaoliang Yang { 18267d4b564dSXiaoliang Yang struct felix_stream *tmp; 18277d4b564dSXiaoliang Yang 18287d4b564dSXiaoliang Yang list_for_each_entry(tmp, stream_list, list) 18297d4b564dSXiaoliang Yang if (tmp->id == id) 18307d4b564dSXiaoliang Yang return tmp; 18317d4b564dSXiaoliang Yang 18327d4b564dSXiaoliang Yang return NULL; 18337d4b564dSXiaoliang Yang } 18347d4b564dSXiaoliang Yang 18357d4b564dSXiaoliang Yang static void vsc9959_stream_table_del(struct ocelot *ocelot, 18367d4b564dSXiaoliang Yang struct felix_stream *stream) 18377d4b564dSXiaoliang Yang { 1838a7e13edfSXiaoliang Yang if (!stream->dummy) 18397d4b564dSXiaoliang Yang vsc9959_mact_stream_set(ocelot, stream, NULL); 18407d4b564dSXiaoliang Yang 18417d4b564dSXiaoliang Yang list_del(&stream->list); 18427d4b564dSXiaoliang Yang kfree(stream); 18437d4b564dSXiaoliang Yang } 18447d4b564dSXiaoliang Yang 18457d4b564dSXiaoliang Yang static u32 vsc9959_sfi_access_status(struct ocelot *ocelot) 18467d4b564dSXiaoliang Yang { 18477d4b564dSXiaoliang Yang return ocelot_read(ocelot, ANA_TABLES_SFIDACCESS); 18487d4b564dSXiaoliang Yang } 18497d4b564dSXiaoliang Yang 18507d4b564dSXiaoliang Yang static int vsc9959_psfp_sfi_set(struct ocelot *ocelot, 18517d4b564dSXiaoliang Yang struct felix_stream_filter *sfi) 18527d4b564dSXiaoliang Yang { 18537d4b564dSXiaoliang Yang u32 val; 18547d4b564dSXiaoliang Yang 18557d4b564dSXiaoliang Yang if (sfi->index > VSC9959_PSFP_SFID_MAX) 18567d4b564dSXiaoliang Yang return -EINVAL; 18577d4b564dSXiaoliang Yang 18587d4b564dSXiaoliang Yang if (!sfi->enable) { 18597d4b564dSXiaoliang Yang ocelot_write(ocelot, ANA_TABLES_SFIDTIDX_SFID_INDEX(sfi->index), 18607d4b564dSXiaoliang Yang ANA_TABLES_SFIDTIDX); 18617d4b564dSXiaoliang Yang 18627d4b564dSXiaoliang Yang val = ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(SFIDACCESS_CMD_WRITE); 18637d4b564dSXiaoliang Yang ocelot_write(ocelot, val, ANA_TABLES_SFIDACCESS); 18647d4b564dSXiaoliang Yang 18657d4b564dSXiaoliang Yang return readx_poll_timeout(vsc9959_sfi_access_status, ocelot, val, 18667d4b564dSXiaoliang Yang (!ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(val)), 18677d4b564dSXiaoliang Yang 10, 100000); 18687d4b564dSXiaoliang Yang } 18697d4b564dSXiaoliang Yang 18707d4b564dSXiaoliang Yang if (sfi->sgid > VSC9959_PSFP_GATE_ID_MAX || 18717d4b564dSXiaoliang Yang sfi->fmid > VSC9959_PSFP_POLICER_MAX) 18727d4b564dSXiaoliang Yang return -EINVAL; 18737d4b564dSXiaoliang Yang 18747d4b564dSXiaoliang Yang ocelot_write(ocelot, 18757d4b564dSXiaoliang Yang (sfi->sg_valid ? ANA_TABLES_SFIDTIDX_SGID_VALID : 0) | 18767d4b564dSXiaoliang Yang ANA_TABLES_SFIDTIDX_SGID(sfi->sgid) | 18777d4b564dSXiaoliang Yang (sfi->fm_valid ? ANA_TABLES_SFIDTIDX_POL_ENA : 0) | 18787d4b564dSXiaoliang Yang ANA_TABLES_SFIDTIDX_POL_IDX(sfi->fmid) | 18797d4b564dSXiaoliang Yang ANA_TABLES_SFIDTIDX_SFID_INDEX(sfi->index), 18807d4b564dSXiaoliang Yang ANA_TABLES_SFIDTIDX); 18817d4b564dSXiaoliang Yang 18827d4b564dSXiaoliang Yang ocelot_write(ocelot, 18837d4b564dSXiaoliang Yang (sfi->prio_valid ? ANA_TABLES_SFIDACCESS_IGR_PRIO_MATCH_ENA : 0) | 18847d4b564dSXiaoliang Yang ANA_TABLES_SFIDACCESS_IGR_PRIO(sfi->prio) | 18857d4b564dSXiaoliang Yang ANA_TABLES_SFIDACCESS_MAX_SDU_LEN(sfi->maxsdu) | 18867d4b564dSXiaoliang Yang ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(SFIDACCESS_CMD_WRITE), 18877d4b564dSXiaoliang Yang ANA_TABLES_SFIDACCESS); 18887d4b564dSXiaoliang Yang 18897d4b564dSXiaoliang Yang return readx_poll_timeout(vsc9959_sfi_access_status, ocelot, val, 18907d4b564dSXiaoliang Yang (!ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(val)), 18917d4b564dSXiaoliang Yang 10, 100000); 18927d4b564dSXiaoliang Yang } 18937d4b564dSXiaoliang Yang 1894a7e13edfSXiaoliang Yang static int vsc9959_psfp_sfidmask_set(struct ocelot *ocelot, u32 sfid, int ports) 18957d4b564dSXiaoliang Yang { 1896a7e13edfSXiaoliang Yang u32 val; 1897a7e13edfSXiaoliang Yang 1898a7e13edfSXiaoliang Yang ocelot_rmw(ocelot, 1899a7e13edfSXiaoliang Yang ANA_TABLES_SFIDTIDX_SFID_INDEX(sfid), 1900a7e13edfSXiaoliang Yang ANA_TABLES_SFIDTIDX_SFID_INDEX_M, 1901a7e13edfSXiaoliang Yang ANA_TABLES_SFIDTIDX); 1902a7e13edfSXiaoliang Yang 1903a7e13edfSXiaoliang Yang ocelot_write(ocelot, 1904a7e13edfSXiaoliang Yang ANA_TABLES_SFID_MASK_IGR_PORT_MASK(ports) | 1905a7e13edfSXiaoliang Yang ANA_TABLES_SFID_MASK_IGR_SRCPORT_MATCH_ENA, 1906a7e13edfSXiaoliang Yang ANA_TABLES_SFID_MASK); 1907a7e13edfSXiaoliang Yang 1908a7e13edfSXiaoliang Yang ocelot_rmw(ocelot, 1909a7e13edfSXiaoliang Yang ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(SFIDACCESS_CMD_WRITE), 1910a7e13edfSXiaoliang Yang ANA_TABLES_SFIDACCESS_SFID_TBL_CMD_M, 1911a7e13edfSXiaoliang Yang ANA_TABLES_SFIDACCESS); 1912a7e13edfSXiaoliang Yang 1913a7e13edfSXiaoliang Yang return readx_poll_timeout(vsc9959_sfi_access_status, ocelot, val, 1914a7e13edfSXiaoliang Yang (!ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(val)), 1915a7e13edfSXiaoliang Yang 10, 100000); 1916a7e13edfSXiaoliang Yang } 1917a7e13edfSXiaoliang Yang 1918a7e13edfSXiaoliang Yang static int vsc9959_psfp_sfi_list_add(struct ocelot *ocelot, 1919a7e13edfSXiaoliang Yang struct felix_stream_filter *sfi, 1920a7e13edfSXiaoliang Yang struct list_head *pos) 1921a7e13edfSXiaoliang Yang { 1922a7e13edfSXiaoliang Yang struct felix_stream_filter *sfi_entry; 19237d4b564dSXiaoliang Yang int ret; 19247d4b564dSXiaoliang Yang 1925e44aecc7SYihao Han sfi_entry = kmemdup(sfi, sizeof(*sfi_entry), GFP_KERNEL); 19267d4b564dSXiaoliang Yang if (!sfi_entry) 19277d4b564dSXiaoliang Yang return -ENOMEM; 19287d4b564dSXiaoliang Yang 19297d4b564dSXiaoliang Yang refcount_set(&sfi_entry->refcount, 1); 19307d4b564dSXiaoliang Yang 19317d4b564dSXiaoliang Yang ret = vsc9959_psfp_sfi_set(ocelot, sfi_entry); 19327d4b564dSXiaoliang Yang if (ret) { 19337d4b564dSXiaoliang Yang kfree(sfi_entry); 19347d4b564dSXiaoliang Yang return ret; 19357d4b564dSXiaoliang Yang } 19367d4b564dSXiaoliang Yang 1937a7e13edfSXiaoliang Yang vsc9959_psfp_sfidmask_set(ocelot, sfi->index, sfi->portmask); 1938a7e13edfSXiaoliang Yang 1939a7e13edfSXiaoliang Yang list_add(&sfi_entry->list, pos); 19407d4b564dSXiaoliang Yang 19417d4b564dSXiaoliang Yang return 0; 19427d4b564dSXiaoliang Yang } 19437d4b564dSXiaoliang Yang 1944a7e13edfSXiaoliang Yang static int vsc9959_psfp_sfi_table_add(struct ocelot *ocelot, 1945a7e13edfSXiaoliang Yang struct felix_stream_filter *sfi) 1946a7e13edfSXiaoliang Yang { 1947a7e13edfSXiaoliang Yang struct list_head *pos, *q, *last; 1948a7e13edfSXiaoliang Yang struct felix_stream_filter *tmp; 1949a7e13edfSXiaoliang Yang struct ocelot_psfp_list *psfp; 1950a7e13edfSXiaoliang Yang u32 insert = 0; 1951a7e13edfSXiaoliang Yang 1952a7e13edfSXiaoliang Yang psfp = &ocelot->psfp; 1953a7e13edfSXiaoliang Yang last = &psfp->sfi_list; 1954a7e13edfSXiaoliang Yang 1955a7e13edfSXiaoliang Yang list_for_each_safe(pos, q, &psfp->sfi_list) { 1956a7e13edfSXiaoliang Yang tmp = list_entry(pos, struct felix_stream_filter, list); 1957a7e13edfSXiaoliang Yang if (sfi->sg_valid == tmp->sg_valid && 1958a7e13edfSXiaoliang Yang sfi->fm_valid == tmp->fm_valid && 1959a7e13edfSXiaoliang Yang sfi->portmask == tmp->portmask && 1960a7e13edfSXiaoliang Yang tmp->sgid == sfi->sgid && 1961a7e13edfSXiaoliang Yang tmp->fmid == sfi->fmid) { 1962a7e13edfSXiaoliang Yang sfi->index = tmp->index; 1963a7e13edfSXiaoliang Yang refcount_inc(&tmp->refcount); 1964a7e13edfSXiaoliang Yang return 0; 1965a7e13edfSXiaoliang Yang } 1966a7e13edfSXiaoliang Yang /* Make sure that the index is increasing in order. */ 1967a7e13edfSXiaoliang Yang if (tmp->index == insert) { 1968a7e13edfSXiaoliang Yang last = pos; 1969a7e13edfSXiaoliang Yang insert++; 1970a7e13edfSXiaoliang Yang } 1971a7e13edfSXiaoliang Yang } 1972a7e13edfSXiaoliang Yang sfi->index = insert; 1973a7e13edfSXiaoliang Yang 1974a7e13edfSXiaoliang Yang return vsc9959_psfp_sfi_list_add(ocelot, sfi, last); 1975a7e13edfSXiaoliang Yang } 1976a7e13edfSXiaoliang Yang 1977a7e13edfSXiaoliang Yang static int vsc9959_psfp_sfi_table_add2(struct ocelot *ocelot, 1978a7e13edfSXiaoliang Yang struct felix_stream_filter *sfi, 1979a7e13edfSXiaoliang Yang struct felix_stream_filter *sfi2) 1980a7e13edfSXiaoliang Yang { 1981a7e13edfSXiaoliang Yang struct felix_stream_filter *tmp; 1982a7e13edfSXiaoliang Yang struct list_head *pos, *q, *last; 1983a7e13edfSXiaoliang Yang struct ocelot_psfp_list *psfp; 1984a7e13edfSXiaoliang Yang u32 insert = 0; 1985a7e13edfSXiaoliang Yang int ret; 1986a7e13edfSXiaoliang Yang 1987a7e13edfSXiaoliang Yang psfp = &ocelot->psfp; 1988a7e13edfSXiaoliang Yang last = &psfp->sfi_list; 1989a7e13edfSXiaoliang Yang 1990a7e13edfSXiaoliang Yang list_for_each_safe(pos, q, &psfp->sfi_list) { 1991a7e13edfSXiaoliang Yang tmp = list_entry(pos, struct felix_stream_filter, list); 1992a7e13edfSXiaoliang Yang /* Make sure that the index is increasing in order. */ 1993a7e13edfSXiaoliang Yang if (tmp->index >= insert + 2) 1994a7e13edfSXiaoliang Yang break; 1995a7e13edfSXiaoliang Yang 1996a7e13edfSXiaoliang Yang insert = tmp->index + 1; 1997a7e13edfSXiaoliang Yang last = pos; 1998a7e13edfSXiaoliang Yang } 1999a7e13edfSXiaoliang Yang sfi->index = insert; 2000a7e13edfSXiaoliang Yang 2001a7e13edfSXiaoliang Yang ret = vsc9959_psfp_sfi_list_add(ocelot, sfi, last); 2002a7e13edfSXiaoliang Yang if (ret) 2003a7e13edfSXiaoliang Yang return ret; 2004a7e13edfSXiaoliang Yang 2005a7e13edfSXiaoliang Yang sfi2->index = insert + 1; 2006a7e13edfSXiaoliang Yang 2007a7e13edfSXiaoliang Yang return vsc9959_psfp_sfi_list_add(ocelot, sfi2, last->next); 2008a7e13edfSXiaoliang Yang } 2009a7e13edfSXiaoliang Yang 201023ae3a78SXiaoliang Yang static struct felix_stream_filter * 201123ae3a78SXiaoliang Yang vsc9959_psfp_sfi_table_get(struct list_head *sfi_list, u32 index) 201223ae3a78SXiaoliang Yang { 201323ae3a78SXiaoliang Yang struct felix_stream_filter *tmp; 201423ae3a78SXiaoliang Yang 201523ae3a78SXiaoliang Yang list_for_each_entry(tmp, sfi_list, list) 201623ae3a78SXiaoliang Yang if (tmp->index == index) 201723ae3a78SXiaoliang Yang return tmp; 201823ae3a78SXiaoliang Yang 201923ae3a78SXiaoliang Yang return NULL; 202023ae3a78SXiaoliang Yang } 202123ae3a78SXiaoliang Yang 20227d4b564dSXiaoliang Yang static void vsc9959_psfp_sfi_table_del(struct ocelot *ocelot, u32 index) 20237d4b564dSXiaoliang Yang { 20247d4b564dSXiaoliang Yang struct felix_stream_filter *tmp, *n; 20257d4b564dSXiaoliang Yang struct ocelot_psfp_list *psfp; 20267d4b564dSXiaoliang Yang u8 z; 20277d4b564dSXiaoliang Yang 20287d4b564dSXiaoliang Yang psfp = &ocelot->psfp; 20297d4b564dSXiaoliang Yang 20307d4b564dSXiaoliang Yang list_for_each_entry_safe(tmp, n, &psfp->sfi_list, list) 20317d4b564dSXiaoliang Yang if (tmp->index == index) { 20327d4b564dSXiaoliang Yang z = refcount_dec_and_test(&tmp->refcount); 20337d4b564dSXiaoliang Yang if (z) { 20347d4b564dSXiaoliang Yang tmp->enable = 0; 20357d4b564dSXiaoliang Yang vsc9959_psfp_sfi_set(ocelot, tmp); 20367d4b564dSXiaoliang Yang list_del(&tmp->list); 20377d4b564dSXiaoliang Yang kfree(tmp); 20387d4b564dSXiaoliang Yang } 20397d4b564dSXiaoliang Yang break; 20407d4b564dSXiaoliang Yang } 20417d4b564dSXiaoliang Yang } 20427d4b564dSXiaoliang Yang 204323ae3a78SXiaoliang Yang static void vsc9959_psfp_parse_gate(const struct flow_action_entry *entry, 204423ae3a78SXiaoliang Yang struct felix_stream_gate *sgi) 204523ae3a78SXiaoliang Yang { 20465a995900SBaowen Zheng sgi->index = entry->hw_index; 204723ae3a78SXiaoliang Yang sgi->ipv_valid = (entry->gate.prio < 0) ? 0 : 1; 204823ae3a78SXiaoliang Yang sgi->init_ipv = (sgi->ipv_valid) ? entry->gate.prio : 0; 204923ae3a78SXiaoliang Yang sgi->basetime = entry->gate.basetime; 205023ae3a78SXiaoliang Yang sgi->cycletime = entry->gate.cycletime; 205123ae3a78SXiaoliang Yang sgi->num_entries = entry->gate.num_entries; 205223ae3a78SXiaoliang Yang sgi->enable = 1; 205323ae3a78SXiaoliang Yang 205423ae3a78SXiaoliang Yang memcpy(sgi->entries, entry->gate.entries, 205523ae3a78SXiaoliang Yang entry->gate.num_entries * sizeof(struct action_gate_entry)); 205623ae3a78SXiaoliang Yang } 205723ae3a78SXiaoliang Yang 205823ae3a78SXiaoliang Yang static u32 vsc9959_sgi_cfg_status(struct ocelot *ocelot) 205923ae3a78SXiaoliang Yang { 206023ae3a78SXiaoliang Yang return ocelot_read(ocelot, ANA_SG_ACCESS_CTRL); 206123ae3a78SXiaoliang Yang } 206223ae3a78SXiaoliang Yang 206323ae3a78SXiaoliang Yang static int vsc9959_psfp_sgi_set(struct ocelot *ocelot, 206423ae3a78SXiaoliang Yang struct felix_stream_gate *sgi) 206523ae3a78SXiaoliang Yang { 206623ae3a78SXiaoliang Yang struct action_gate_entry *e; 206723ae3a78SXiaoliang Yang struct timespec64 base_ts; 206823ae3a78SXiaoliang Yang u32 interval_sum = 0; 206923ae3a78SXiaoliang Yang u32 val; 207023ae3a78SXiaoliang Yang int i; 207123ae3a78SXiaoliang Yang 207223ae3a78SXiaoliang Yang if (sgi->index > VSC9959_PSFP_GATE_ID_MAX) 207323ae3a78SXiaoliang Yang return -EINVAL; 207423ae3a78SXiaoliang Yang 207523ae3a78SXiaoliang Yang ocelot_write(ocelot, ANA_SG_ACCESS_CTRL_SGID(sgi->index), 207623ae3a78SXiaoliang Yang ANA_SG_ACCESS_CTRL); 207723ae3a78SXiaoliang Yang 207823ae3a78SXiaoliang Yang if (!sgi->enable) { 207923ae3a78SXiaoliang Yang ocelot_rmw(ocelot, ANA_SG_CONFIG_REG_3_INIT_GATE_STATE, 208023ae3a78SXiaoliang Yang ANA_SG_CONFIG_REG_3_INIT_GATE_STATE | 208123ae3a78SXiaoliang Yang ANA_SG_CONFIG_REG_3_GATE_ENABLE, 208223ae3a78SXiaoliang Yang ANA_SG_CONFIG_REG_3); 208323ae3a78SXiaoliang Yang 208423ae3a78SXiaoliang Yang return 0; 208523ae3a78SXiaoliang Yang } 208623ae3a78SXiaoliang Yang 208723ae3a78SXiaoliang Yang if (sgi->cycletime < VSC9959_PSFP_GATE_CYCLETIME_MIN || 208823ae3a78SXiaoliang Yang sgi->cycletime > NSEC_PER_SEC) 208923ae3a78SXiaoliang Yang return -EINVAL; 209023ae3a78SXiaoliang Yang 209123ae3a78SXiaoliang Yang if (sgi->num_entries > VSC9959_PSFP_GATE_LIST_NUM) 209223ae3a78SXiaoliang Yang return -EINVAL; 209323ae3a78SXiaoliang Yang 209423ae3a78SXiaoliang Yang vsc9959_new_base_time(ocelot, sgi->basetime, sgi->cycletime, &base_ts); 209523ae3a78SXiaoliang Yang ocelot_write(ocelot, base_ts.tv_nsec, ANA_SG_CONFIG_REG_1); 209623ae3a78SXiaoliang Yang val = lower_32_bits(base_ts.tv_sec); 209723ae3a78SXiaoliang Yang ocelot_write(ocelot, val, ANA_SG_CONFIG_REG_2); 209823ae3a78SXiaoliang Yang 209923ae3a78SXiaoliang Yang val = upper_32_bits(base_ts.tv_sec); 210023ae3a78SXiaoliang Yang ocelot_write(ocelot, 210123ae3a78SXiaoliang Yang (sgi->ipv_valid ? ANA_SG_CONFIG_REG_3_IPV_VALID : 0) | 210223ae3a78SXiaoliang Yang ANA_SG_CONFIG_REG_3_INIT_IPV(sgi->init_ipv) | 210323ae3a78SXiaoliang Yang ANA_SG_CONFIG_REG_3_GATE_ENABLE | 210423ae3a78SXiaoliang Yang ANA_SG_CONFIG_REG_3_LIST_LENGTH(sgi->num_entries) | 210523ae3a78SXiaoliang Yang ANA_SG_CONFIG_REG_3_INIT_GATE_STATE | 210623ae3a78SXiaoliang Yang ANA_SG_CONFIG_REG_3_BASE_TIME_SEC_MSB(val), 210723ae3a78SXiaoliang Yang ANA_SG_CONFIG_REG_3); 210823ae3a78SXiaoliang Yang 210923ae3a78SXiaoliang Yang ocelot_write(ocelot, sgi->cycletime, ANA_SG_CONFIG_REG_4); 211023ae3a78SXiaoliang Yang 211123ae3a78SXiaoliang Yang e = sgi->entries; 211223ae3a78SXiaoliang Yang for (i = 0; i < sgi->num_entries; i++) { 211323ae3a78SXiaoliang Yang u32 ips = (e[i].ipv < 0) ? 0 : (e[i].ipv + 8); 211423ae3a78SXiaoliang Yang 211523ae3a78SXiaoliang Yang ocelot_write_rix(ocelot, ANA_SG_GCL_GS_CONFIG_IPS(ips) | 211623ae3a78SXiaoliang Yang (e[i].gate_state ? 211723ae3a78SXiaoliang Yang ANA_SG_GCL_GS_CONFIG_GATE_STATE : 0), 211823ae3a78SXiaoliang Yang ANA_SG_GCL_GS_CONFIG, i); 211923ae3a78SXiaoliang Yang 212023ae3a78SXiaoliang Yang interval_sum += e[i].interval; 212123ae3a78SXiaoliang Yang ocelot_write_rix(ocelot, interval_sum, ANA_SG_GCL_TI_CONFIG, i); 212223ae3a78SXiaoliang Yang } 212323ae3a78SXiaoliang Yang 212423ae3a78SXiaoliang Yang ocelot_rmw(ocelot, ANA_SG_ACCESS_CTRL_CONFIG_CHANGE, 212523ae3a78SXiaoliang Yang ANA_SG_ACCESS_CTRL_CONFIG_CHANGE, 212623ae3a78SXiaoliang Yang ANA_SG_ACCESS_CTRL); 212723ae3a78SXiaoliang Yang 212823ae3a78SXiaoliang Yang return readx_poll_timeout(vsc9959_sgi_cfg_status, ocelot, val, 212923ae3a78SXiaoliang Yang (!(ANA_SG_ACCESS_CTRL_CONFIG_CHANGE & val)), 213023ae3a78SXiaoliang Yang 10, 100000); 213123ae3a78SXiaoliang Yang } 213223ae3a78SXiaoliang Yang 213323ae3a78SXiaoliang Yang static int vsc9959_psfp_sgi_table_add(struct ocelot *ocelot, 213423ae3a78SXiaoliang Yang struct felix_stream_gate *sgi) 213523ae3a78SXiaoliang Yang { 213623ae3a78SXiaoliang Yang struct felix_stream_gate_entry *tmp; 213723ae3a78SXiaoliang Yang struct ocelot_psfp_list *psfp; 213823ae3a78SXiaoliang Yang int ret; 213923ae3a78SXiaoliang Yang 214023ae3a78SXiaoliang Yang psfp = &ocelot->psfp; 214123ae3a78SXiaoliang Yang 214223ae3a78SXiaoliang Yang list_for_each_entry(tmp, &psfp->sgi_list, list) 214323ae3a78SXiaoliang Yang if (tmp->index == sgi->index) { 214423ae3a78SXiaoliang Yang refcount_inc(&tmp->refcount); 214523ae3a78SXiaoliang Yang return 0; 214623ae3a78SXiaoliang Yang } 214723ae3a78SXiaoliang Yang 214823ae3a78SXiaoliang Yang tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); 214923ae3a78SXiaoliang Yang if (!tmp) 215023ae3a78SXiaoliang Yang return -ENOMEM; 215123ae3a78SXiaoliang Yang 215223ae3a78SXiaoliang Yang ret = vsc9959_psfp_sgi_set(ocelot, sgi); 215323ae3a78SXiaoliang Yang if (ret) { 215423ae3a78SXiaoliang Yang kfree(tmp); 215523ae3a78SXiaoliang Yang return ret; 215623ae3a78SXiaoliang Yang } 215723ae3a78SXiaoliang Yang 215823ae3a78SXiaoliang Yang tmp->index = sgi->index; 215923ae3a78SXiaoliang Yang refcount_set(&tmp->refcount, 1); 216023ae3a78SXiaoliang Yang list_add_tail(&tmp->list, &psfp->sgi_list); 216123ae3a78SXiaoliang Yang 216223ae3a78SXiaoliang Yang return 0; 216323ae3a78SXiaoliang Yang } 216423ae3a78SXiaoliang Yang 216523ae3a78SXiaoliang Yang static void vsc9959_psfp_sgi_table_del(struct ocelot *ocelot, 216623ae3a78SXiaoliang Yang u32 index) 216723ae3a78SXiaoliang Yang { 216823ae3a78SXiaoliang Yang struct felix_stream_gate_entry *tmp, *n; 216923ae3a78SXiaoliang Yang struct felix_stream_gate sgi = {0}; 217023ae3a78SXiaoliang Yang struct ocelot_psfp_list *psfp; 217123ae3a78SXiaoliang Yang u8 z; 217223ae3a78SXiaoliang Yang 217323ae3a78SXiaoliang Yang psfp = &ocelot->psfp; 217423ae3a78SXiaoliang Yang 217523ae3a78SXiaoliang Yang list_for_each_entry_safe(tmp, n, &psfp->sgi_list, list) 217623ae3a78SXiaoliang Yang if (tmp->index == index) { 217723ae3a78SXiaoliang Yang z = refcount_dec_and_test(&tmp->refcount); 217823ae3a78SXiaoliang Yang if (z) { 217923ae3a78SXiaoliang Yang sgi.index = index; 218023ae3a78SXiaoliang Yang sgi.enable = 0; 218123ae3a78SXiaoliang Yang vsc9959_psfp_sgi_set(ocelot, &sgi); 218223ae3a78SXiaoliang Yang list_del(&tmp->list); 218323ae3a78SXiaoliang Yang kfree(tmp); 218423ae3a78SXiaoliang Yang } 218523ae3a78SXiaoliang Yang break; 218623ae3a78SXiaoliang Yang } 218723ae3a78SXiaoliang Yang } 218823ae3a78SXiaoliang Yang 2189a7e13edfSXiaoliang Yang static int vsc9959_psfp_filter_add(struct ocelot *ocelot, int port, 21907d4b564dSXiaoliang Yang struct flow_cls_offload *f) 21917d4b564dSXiaoliang Yang { 21927d4b564dSXiaoliang Yang struct netlink_ext_ack *extack = f->common.extack; 2193a7e13edfSXiaoliang Yang struct felix_stream_filter old_sfi, *sfi_entry; 21947d4b564dSXiaoliang Yang struct felix_stream_filter sfi = {0}; 21957d4b564dSXiaoliang Yang const struct flow_action_entry *a; 21967d4b564dSXiaoliang Yang struct felix_stream *stream_entry; 21977d4b564dSXiaoliang Yang struct felix_stream stream = {0}; 219823ae3a78SXiaoliang Yang struct felix_stream_gate *sgi; 21997d4b564dSXiaoliang Yang struct ocelot_psfp_list *psfp; 220076c13edeSXiaoliang Yang struct ocelot_policer pol; 220123ae3a78SXiaoliang Yang int ret, i, size; 220276c13edeSXiaoliang Yang u64 rate, burst; 220376c13edeSXiaoliang Yang u32 index; 22047d4b564dSXiaoliang Yang 22057d4b564dSXiaoliang Yang psfp = &ocelot->psfp; 22067d4b564dSXiaoliang Yang 22077d4b564dSXiaoliang Yang ret = vsc9959_stream_identify(f, &stream); 22087d4b564dSXiaoliang Yang if (ret) { 22097d4b564dSXiaoliang Yang NL_SET_ERR_MSG_MOD(extack, "Only can match on VID, PCP, and dest MAC"); 22107d4b564dSXiaoliang Yang return ret; 22117d4b564dSXiaoliang Yang } 22127d4b564dSXiaoliang Yang 221325027c84SVladimir Oltean mutex_lock(&psfp->lock); 221425027c84SVladimir Oltean 22157d4b564dSXiaoliang Yang flow_action_for_each(i, a, &f->rule->action) { 22167d4b564dSXiaoliang Yang switch (a->id) { 22177d4b564dSXiaoliang Yang case FLOW_ACTION_GATE: 221823ae3a78SXiaoliang Yang size = struct_size(sgi, entries, a->gate.num_entries); 221923ae3a78SXiaoliang Yang sgi = kzalloc(size, GFP_KERNEL); 2220866b7a27SZheng Yongjun if (!sgi) { 2221866b7a27SZheng Yongjun ret = -ENOMEM; 2222866b7a27SZheng Yongjun goto err; 2223866b7a27SZheng Yongjun } 222423ae3a78SXiaoliang Yang vsc9959_psfp_parse_gate(a, sgi); 222523ae3a78SXiaoliang Yang ret = vsc9959_psfp_sgi_table_add(ocelot, sgi); 222623ae3a78SXiaoliang Yang if (ret) { 222723ae3a78SXiaoliang Yang kfree(sgi); 222876c13edeSXiaoliang Yang goto err; 222923ae3a78SXiaoliang Yang } 223023ae3a78SXiaoliang Yang sfi.sg_valid = 1; 223123ae3a78SXiaoliang Yang sfi.sgid = sgi->index; 223223ae3a78SXiaoliang Yang kfree(sgi); 223323ae3a78SXiaoliang Yang break; 22347d4b564dSXiaoliang Yang case FLOW_ACTION_POLICE: 22355a995900SBaowen Zheng index = a->hw_index + VSC9959_PSFP_POLICER_BASE; 223676c13edeSXiaoliang Yang if (index > VSC9959_PSFP_POLICER_MAX) { 223776c13edeSXiaoliang Yang ret = -EINVAL; 223876c13edeSXiaoliang Yang goto err; 223976c13edeSXiaoliang Yang } 224076c13edeSXiaoliang Yang 224176c13edeSXiaoliang Yang rate = a->police.rate_bytes_ps; 224276c13edeSXiaoliang Yang burst = rate * PSCHED_NS2TICKS(a->police.burst); 224376c13edeSXiaoliang Yang pol = (struct ocelot_policer) { 224476c13edeSXiaoliang Yang .burst = div_u64(burst, PSCHED_TICKS_PER_SEC), 224576c13edeSXiaoliang Yang .rate = div_u64(rate, 1000) * 8, 224676c13edeSXiaoliang Yang }; 224776c13edeSXiaoliang Yang ret = ocelot_vcap_policer_add(ocelot, index, &pol); 224876c13edeSXiaoliang Yang if (ret) 224976c13edeSXiaoliang Yang goto err; 225076c13edeSXiaoliang Yang 225176c13edeSXiaoliang Yang sfi.fm_valid = 1; 225276c13edeSXiaoliang Yang sfi.fmid = index; 225376c13edeSXiaoliang Yang sfi.maxsdu = a->police.mtu; 225476c13edeSXiaoliang Yang break; 22557d4b564dSXiaoliang Yang default: 225625027c84SVladimir Oltean mutex_unlock(&psfp->lock); 22577d4b564dSXiaoliang Yang return -EOPNOTSUPP; 22587d4b564dSXiaoliang Yang } 22597d4b564dSXiaoliang Yang } 22607d4b564dSXiaoliang Yang 2261a7e13edfSXiaoliang Yang stream.ports = BIT(port); 2262a7e13edfSXiaoliang Yang stream.port = port; 22637d4b564dSXiaoliang Yang 2264a7e13edfSXiaoliang Yang sfi.portmask = stream.ports; 22657d4b564dSXiaoliang Yang sfi.prio_valid = (stream.prio < 0 ? 0 : 1); 22667d4b564dSXiaoliang Yang sfi.prio = (sfi.prio_valid ? stream.prio : 0); 22677d4b564dSXiaoliang Yang sfi.enable = 1; 22687d4b564dSXiaoliang Yang 2269a7e13edfSXiaoliang Yang /* Check if stream is set. */ 2270a7e13edfSXiaoliang Yang stream_entry = vsc9959_stream_table_lookup(&psfp->stream_list, &stream); 2271a7e13edfSXiaoliang Yang if (stream_entry) { 2272a7e13edfSXiaoliang Yang if (stream_entry->ports & BIT(port)) { 2273a7e13edfSXiaoliang Yang NL_SET_ERR_MSG_MOD(extack, 2274a7e13edfSXiaoliang Yang "The stream is added on this port"); 2275a7e13edfSXiaoliang Yang ret = -EEXIST; 2276a7e13edfSXiaoliang Yang goto err; 2277a7e13edfSXiaoliang Yang } 2278a7e13edfSXiaoliang Yang 2279a7e13edfSXiaoliang Yang if (stream_entry->ports != BIT(stream_entry->port)) { 2280a7e13edfSXiaoliang Yang NL_SET_ERR_MSG_MOD(extack, 2281a7e13edfSXiaoliang Yang "The stream is added on two ports"); 2282a7e13edfSXiaoliang Yang ret = -EEXIST; 2283a7e13edfSXiaoliang Yang goto err; 2284a7e13edfSXiaoliang Yang } 2285a7e13edfSXiaoliang Yang 2286a7e13edfSXiaoliang Yang stream_entry->ports |= BIT(port); 2287a7e13edfSXiaoliang Yang stream.ports = stream_entry->ports; 2288a7e13edfSXiaoliang Yang 2289a7e13edfSXiaoliang Yang sfi_entry = vsc9959_psfp_sfi_table_get(&psfp->sfi_list, 2290a7e13edfSXiaoliang Yang stream_entry->sfid); 2291a7e13edfSXiaoliang Yang memcpy(&old_sfi, sfi_entry, sizeof(old_sfi)); 2292a7e13edfSXiaoliang Yang 2293a7e13edfSXiaoliang Yang vsc9959_psfp_sfi_table_del(ocelot, stream_entry->sfid); 2294a7e13edfSXiaoliang Yang 2295a7e13edfSXiaoliang Yang old_sfi.portmask = stream_entry->ports; 2296a7e13edfSXiaoliang Yang sfi.portmask = stream.ports; 2297a7e13edfSXiaoliang Yang 2298a7e13edfSXiaoliang Yang if (stream_entry->port > port) { 2299a7e13edfSXiaoliang Yang ret = vsc9959_psfp_sfi_table_add2(ocelot, &sfi, 2300a7e13edfSXiaoliang Yang &old_sfi); 2301a7e13edfSXiaoliang Yang stream_entry->dummy = true; 2302a7e13edfSXiaoliang Yang } else { 2303a7e13edfSXiaoliang Yang ret = vsc9959_psfp_sfi_table_add2(ocelot, &old_sfi, 2304a7e13edfSXiaoliang Yang &sfi); 2305a7e13edfSXiaoliang Yang stream.dummy = true; 2306a7e13edfSXiaoliang Yang } 2307a7e13edfSXiaoliang Yang if (ret) 2308a7e13edfSXiaoliang Yang goto err; 2309a7e13edfSXiaoliang Yang 2310a7e13edfSXiaoliang Yang stream_entry->sfid = old_sfi.index; 2311a7e13edfSXiaoliang Yang } else { 23127d4b564dSXiaoliang Yang ret = vsc9959_psfp_sfi_table_add(ocelot, &sfi); 23137d4b564dSXiaoliang Yang if (ret) 231423ae3a78SXiaoliang Yang goto err; 2315a7e13edfSXiaoliang Yang } 23167d4b564dSXiaoliang Yang 23177d4b564dSXiaoliang Yang stream.sfid = sfi.index; 23187d4b564dSXiaoliang Yang stream.sfid_valid = 1; 23197d4b564dSXiaoliang Yang ret = vsc9959_stream_table_add(ocelot, &psfp->stream_list, 23207d4b564dSXiaoliang Yang &stream, extack); 232123ae3a78SXiaoliang Yang if (ret) { 23227d4b564dSXiaoliang Yang vsc9959_psfp_sfi_table_del(ocelot, stream.sfid); 232323ae3a78SXiaoliang Yang goto err; 232423ae3a78SXiaoliang Yang } 232523ae3a78SXiaoliang Yang 232625027c84SVladimir Oltean mutex_unlock(&psfp->lock); 232725027c84SVladimir Oltean 232823ae3a78SXiaoliang Yang return 0; 232923ae3a78SXiaoliang Yang 233023ae3a78SXiaoliang Yang err: 233123ae3a78SXiaoliang Yang if (sfi.sg_valid) 233223ae3a78SXiaoliang Yang vsc9959_psfp_sgi_table_del(ocelot, sfi.sgid); 23337d4b564dSXiaoliang Yang 233476c13edeSXiaoliang Yang if (sfi.fm_valid) 233576c13edeSXiaoliang Yang ocelot_vcap_policer_del(ocelot, sfi.fmid); 233676c13edeSXiaoliang Yang 233725027c84SVladimir Oltean mutex_unlock(&psfp->lock); 233825027c84SVladimir Oltean 23397d4b564dSXiaoliang Yang return ret; 23407d4b564dSXiaoliang Yang } 23417d4b564dSXiaoliang Yang 23427d4b564dSXiaoliang Yang static int vsc9959_psfp_filter_del(struct ocelot *ocelot, 23437d4b564dSXiaoliang Yang struct flow_cls_offload *f) 23447d4b564dSXiaoliang Yang { 2345a7e13edfSXiaoliang Yang struct felix_stream *stream, tmp, *stream_entry; 234625027c84SVladimir Oltean struct ocelot_psfp_list *psfp = &ocelot->psfp; 234723ae3a78SXiaoliang Yang static struct felix_stream_filter *sfi; 23487d4b564dSXiaoliang Yang 234925027c84SVladimir Oltean mutex_lock(&psfp->lock); 23507d4b564dSXiaoliang Yang 23517d4b564dSXiaoliang Yang stream = vsc9959_stream_table_get(&psfp->stream_list, f->cookie); 235225027c84SVladimir Oltean if (!stream) { 235325027c84SVladimir Oltean mutex_unlock(&psfp->lock); 23547d4b564dSXiaoliang Yang return -ENOMEM; 235525027c84SVladimir Oltean } 23567d4b564dSXiaoliang Yang 235723ae3a78SXiaoliang Yang sfi = vsc9959_psfp_sfi_table_get(&psfp->sfi_list, stream->sfid); 235825027c84SVladimir Oltean if (!sfi) { 235925027c84SVladimir Oltean mutex_unlock(&psfp->lock); 236023ae3a78SXiaoliang Yang return -ENOMEM; 236125027c84SVladimir Oltean } 236223ae3a78SXiaoliang Yang 236323ae3a78SXiaoliang Yang if (sfi->sg_valid) 236423ae3a78SXiaoliang Yang vsc9959_psfp_sgi_table_del(ocelot, sfi->sgid); 236523ae3a78SXiaoliang Yang 236676c13edeSXiaoliang Yang if (sfi->fm_valid) 236776c13edeSXiaoliang Yang ocelot_vcap_policer_del(ocelot, sfi->fmid); 236876c13edeSXiaoliang Yang 23697d4b564dSXiaoliang Yang vsc9959_psfp_sfi_table_del(ocelot, stream->sfid); 23707d4b564dSXiaoliang Yang 2371a7e13edfSXiaoliang Yang memcpy(&tmp, stream, sizeof(tmp)); 2372a7e13edfSXiaoliang Yang 23737d4b564dSXiaoliang Yang stream->sfid_valid = 0; 23747d4b564dSXiaoliang Yang vsc9959_stream_table_del(ocelot, stream); 23757d4b564dSXiaoliang Yang 2376a7e13edfSXiaoliang Yang stream_entry = vsc9959_stream_table_lookup(&psfp->stream_list, &tmp); 2377a7e13edfSXiaoliang Yang if (stream_entry) { 2378a7e13edfSXiaoliang Yang stream_entry->ports = BIT(stream_entry->port); 2379a7e13edfSXiaoliang Yang if (stream_entry->dummy) { 2380a7e13edfSXiaoliang Yang stream_entry->dummy = false; 2381a7e13edfSXiaoliang Yang vsc9959_mact_stream_set(ocelot, stream_entry, NULL); 2382a7e13edfSXiaoliang Yang } 2383a7e13edfSXiaoliang Yang vsc9959_psfp_sfidmask_set(ocelot, stream_entry->sfid, 2384a7e13edfSXiaoliang Yang stream_entry->ports); 2385a7e13edfSXiaoliang Yang } 2386a7e13edfSXiaoliang Yang 238725027c84SVladimir Oltean mutex_unlock(&psfp->lock); 238825027c84SVladimir Oltean 23897d4b564dSXiaoliang Yang return 0; 23907d4b564dSXiaoliang Yang } 23917d4b564dSXiaoliang Yang 239225027c84SVladimir Oltean static void vsc9959_update_sfid_stats(struct ocelot *ocelot, 239325027c84SVladimir Oltean struct felix_stream_filter *sfi) 239425027c84SVladimir Oltean { 239525027c84SVladimir Oltean struct felix_stream_filter_counters *s = &sfi->stats; 239625027c84SVladimir Oltean u32 match, not_pass_gate, not_pass_sdu, red; 239725027c84SVladimir Oltean u32 sfid = sfi->index; 239825027c84SVladimir Oltean 239925027c84SVladimir Oltean lockdep_assert_held(&ocelot->stat_view_lock); 240025027c84SVladimir Oltean 240125027c84SVladimir Oltean ocelot_rmw(ocelot, SYS_STAT_CFG_STAT_VIEW(sfid), 240225027c84SVladimir Oltean SYS_STAT_CFG_STAT_VIEW_M, 240325027c84SVladimir Oltean SYS_STAT_CFG); 240425027c84SVladimir Oltean 240525027c84SVladimir Oltean match = ocelot_read(ocelot, SYS_COUNT_SF_MATCHING_FRAMES); 240625027c84SVladimir Oltean not_pass_gate = ocelot_read(ocelot, SYS_COUNT_SF_NOT_PASSING_FRAMES); 240725027c84SVladimir Oltean not_pass_sdu = ocelot_read(ocelot, SYS_COUNT_SF_NOT_PASSING_SDU); 240825027c84SVladimir Oltean red = ocelot_read(ocelot, SYS_COUNT_SF_RED_FRAMES); 240925027c84SVladimir Oltean 241025027c84SVladimir Oltean /* Clear the PSFP counter. */ 241125027c84SVladimir Oltean ocelot_write(ocelot, 241225027c84SVladimir Oltean SYS_STAT_CFG_STAT_VIEW(sfid) | 241325027c84SVladimir Oltean SYS_STAT_CFG_STAT_CLEAR_SHOT(0x10), 241425027c84SVladimir Oltean SYS_STAT_CFG); 241525027c84SVladimir Oltean 241625027c84SVladimir Oltean s->match += match; 241725027c84SVladimir Oltean s->not_pass_gate += not_pass_gate; 241825027c84SVladimir Oltean s->not_pass_sdu += not_pass_sdu; 241925027c84SVladimir Oltean s->red += red; 242025027c84SVladimir Oltean } 242125027c84SVladimir Oltean 242225027c84SVladimir Oltean /* Caller must hold &ocelot->stat_view_lock */ 242325027c84SVladimir Oltean static void vsc9959_update_stats(struct ocelot *ocelot) 242425027c84SVladimir Oltean { 242525027c84SVladimir Oltean struct ocelot_psfp_list *psfp = &ocelot->psfp; 242625027c84SVladimir Oltean struct felix_stream_filter *sfi; 242725027c84SVladimir Oltean 242825027c84SVladimir Oltean mutex_lock(&psfp->lock); 242925027c84SVladimir Oltean 243025027c84SVladimir Oltean list_for_each_entry(sfi, &psfp->sfi_list, list) 243125027c84SVladimir Oltean vsc9959_update_sfid_stats(ocelot, sfi); 243225027c84SVladimir Oltean 243325027c84SVladimir Oltean mutex_unlock(&psfp->lock); 243425027c84SVladimir Oltean } 243525027c84SVladimir Oltean 24367d4b564dSXiaoliang Yang static int vsc9959_psfp_stats_get(struct ocelot *ocelot, 24377d4b564dSXiaoliang Yang struct flow_cls_offload *f, 24387d4b564dSXiaoliang Yang struct flow_stats *stats) 24397d4b564dSXiaoliang Yang { 244025027c84SVladimir Oltean struct ocelot_psfp_list *psfp = &ocelot->psfp; 244125027c84SVladimir Oltean struct felix_stream_filter_counters *s; 244225027c84SVladimir Oltean static struct felix_stream_filter *sfi; 24437d4b564dSXiaoliang Yang struct felix_stream *stream; 24447d4b564dSXiaoliang Yang 24457d4b564dSXiaoliang Yang stream = vsc9959_stream_table_get(&psfp->stream_list, f->cookie); 24467d4b564dSXiaoliang Yang if (!stream) 24477d4b564dSXiaoliang Yang return -ENOMEM; 24487d4b564dSXiaoliang Yang 244925027c84SVladimir Oltean sfi = vsc9959_psfp_sfi_table_get(&psfp->sfi_list, stream->sfid); 245025027c84SVladimir Oltean if (!sfi) 245125027c84SVladimir Oltean return -EINVAL; 24527d4b564dSXiaoliang Yang 245325027c84SVladimir Oltean mutex_lock(&ocelot->stat_view_lock); 245425027c84SVladimir Oltean 245525027c84SVladimir Oltean vsc9959_update_sfid_stats(ocelot, sfi); 245625027c84SVladimir Oltean 245725027c84SVladimir Oltean s = &sfi->stats; 245825027c84SVladimir Oltean stats->pkts = s->match; 245925027c84SVladimir Oltean stats->drops = s->not_pass_gate + s->not_pass_sdu + s->red; 246025027c84SVladimir Oltean 246125027c84SVladimir Oltean memset(s, 0, sizeof(*s)); 246225027c84SVladimir Oltean 246325027c84SVladimir Oltean mutex_unlock(&ocelot->stat_view_lock); 24647d4b564dSXiaoliang Yang 24657d4b564dSXiaoliang Yang return 0; 24667d4b564dSXiaoliang Yang } 24677d4b564dSXiaoliang Yang 24687d4b564dSXiaoliang Yang static void vsc9959_psfp_init(struct ocelot *ocelot) 24697d4b564dSXiaoliang Yang { 24707d4b564dSXiaoliang Yang struct ocelot_psfp_list *psfp = &ocelot->psfp; 24717d4b564dSXiaoliang Yang 24727d4b564dSXiaoliang Yang INIT_LIST_HEAD(&psfp->stream_list); 24737d4b564dSXiaoliang Yang INIT_LIST_HEAD(&psfp->sfi_list); 24747d4b564dSXiaoliang Yang INIT_LIST_HEAD(&psfp->sgi_list); 247525027c84SVladimir Oltean mutex_init(&psfp->lock); 24767d4b564dSXiaoliang Yang } 24777d4b564dSXiaoliang Yang 24788abe1970SVladimir Oltean /* When using cut-through forwarding and the egress port runs at a higher data 24798abe1970SVladimir Oltean * rate than the ingress port, the packet currently under transmission would 24808abe1970SVladimir Oltean * suffer an underrun since it would be transmitted faster than it is received. 24818abe1970SVladimir Oltean * The Felix switch implementation of cut-through forwarding does not check in 24828abe1970SVladimir Oltean * hardware whether this condition is satisfied or not, so we must restrict the 24838abe1970SVladimir Oltean * list of ports that have cut-through forwarding enabled on egress to only be 24848abe1970SVladimir Oltean * the ports operating at the lowest link speed within their respective 24858abe1970SVladimir Oltean * forwarding domain. 24868abe1970SVladimir Oltean */ 24878abe1970SVladimir Oltean static void vsc9959_cut_through_fwd(struct ocelot *ocelot) 24888abe1970SVladimir Oltean { 24898abe1970SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 24908abe1970SVladimir Oltean struct dsa_switch *ds = felix->ds; 2491843794bbSVladimir Oltean int tc, port, other_port; 24928abe1970SVladimir Oltean 24938abe1970SVladimir Oltean lockdep_assert_held(&ocelot->fwd_domain_lock); 24948abe1970SVladimir Oltean 24958abe1970SVladimir Oltean for (port = 0; port < ocelot->num_phys_ports; port++) { 24968abe1970SVladimir Oltean struct ocelot_port *ocelot_port = ocelot->ports[port]; 24978abe1970SVladimir Oltean int min_speed = ocelot_port->speed; 24988abe1970SVladimir Oltean unsigned long mask = 0; 24998abe1970SVladimir Oltean u32 tmp, val = 0; 25008abe1970SVladimir Oltean 25018abe1970SVladimir Oltean /* Disable cut-through on ports that are down */ 25028abe1970SVladimir Oltean if (ocelot_port->speed <= 0) 25038abe1970SVladimir Oltean goto set; 25048abe1970SVladimir Oltean 25058abe1970SVladimir Oltean if (dsa_is_cpu_port(ds, port)) { 25068abe1970SVladimir Oltean /* Ocelot switches forward from the NPI port towards 25078abe1970SVladimir Oltean * any port, regardless of it being in the NPI port's 25088abe1970SVladimir Oltean * forwarding domain or not. 25098abe1970SVladimir Oltean */ 25108abe1970SVladimir Oltean mask = dsa_user_ports(ds); 25118abe1970SVladimir Oltean } else { 25128abe1970SVladimir Oltean mask = ocelot_get_bridge_fwd_mask(ocelot, port); 25138abe1970SVladimir Oltean mask &= ~BIT(port); 25148abe1970SVladimir Oltean if (ocelot->npi >= 0) 25158abe1970SVladimir Oltean mask |= BIT(ocelot->npi); 25168abe1970SVladimir Oltean else 2517c295f983SVladimir Oltean mask |= ocelot_port_assigned_dsa_8021q_cpu_mask(ocelot, 2518c295f983SVladimir Oltean port); 25198abe1970SVladimir Oltean } 25208abe1970SVladimir Oltean 25218abe1970SVladimir Oltean /* Calculate the minimum link speed, among the ports that are 25228abe1970SVladimir Oltean * up, of this source port's forwarding domain. 25238abe1970SVladimir Oltean */ 25248abe1970SVladimir Oltean for_each_set_bit(other_port, &mask, ocelot->num_phys_ports) { 25258abe1970SVladimir Oltean struct ocelot_port *other_ocelot_port; 25268abe1970SVladimir Oltean 25278abe1970SVladimir Oltean other_ocelot_port = ocelot->ports[other_port]; 25288abe1970SVladimir Oltean if (other_ocelot_port->speed <= 0) 25298abe1970SVladimir Oltean continue; 25308abe1970SVladimir Oltean 25318abe1970SVladimir Oltean if (min_speed > other_ocelot_port->speed) 25328abe1970SVladimir Oltean min_speed = other_ocelot_port->speed; 25338abe1970SVladimir Oltean } 25348abe1970SVladimir Oltean 2535843794bbSVladimir Oltean /* Enable cut-through forwarding for all traffic classes that 2536843794bbSVladimir Oltean * don't have oversized dropping enabled, since this check is 2537843794bbSVladimir Oltean * bypassed in cut-through mode. 2538843794bbSVladimir Oltean */ 2539843794bbSVladimir Oltean if (ocelot_port->speed == min_speed) { 25408abe1970SVladimir Oltean val = GENMASK(7, 0); 25418abe1970SVladimir Oltean 2542843794bbSVladimir Oltean for (tc = 0; tc < OCELOT_NUM_TC; tc++) 2543843794bbSVladimir Oltean if (vsc9959_port_qmaxsdu_get(ocelot, port, tc)) 2544843794bbSVladimir Oltean val &= ~BIT(tc); 2545843794bbSVladimir Oltean } 2546843794bbSVladimir Oltean 25478abe1970SVladimir Oltean set: 25488abe1970SVladimir Oltean tmp = ocelot_read_rix(ocelot, ANA_CUT_THRU_CFG, port); 25498abe1970SVladimir Oltean if (tmp == val) 25508abe1970SVladimir Oltean continue; 25518abe1970SVladimir Oltean 25528abe1970SVladimir Oltean dev_dbg(ocelot->dev, 2553843794bbSVladimir Oltean "port %d fwd mask 0x%lx speed %d min_speed %d, %s cut-through forwarding on TC mask 0x%x\n", 25548abe1970SVladimir Oltean port, mask, ocelot_port->speed, min_speed, 2555843794bbSVladimir Oltean val ? "enabling" : "disabling", val); 25568abe1970SVladimir Oltean 25578abe1970SVladimir Oltean ocelot_write_rix(ocelot, val, ANA_CUT_THRU_CFG, port); 25588abe1970SVladimir Oltean } 25598abe1970SVladimir Oltean } 25608abe1970SVladimir Oltean 25617d4b564dSXiaoliang Yang static const struct ocelot_ops vsc9959_ops = { 25627d4b564dSXiaoliang Yang .reset = vsc9959_reset, 25637d4b564dSXiaoliang Yang .wm_enc = vsc9959_wm_enc, 25647d4b564dSXiaoliang Yang .wm_dec = vsc9959_wm_dec, 25657d4b564dSXiaoliang Yang .wm_stat = vsc9959_wm_stat, 25667d4b564dSXiaoliang Yang .port_to_netdev = felix_port_to_netdev, 25677d4b564dSXiaoliang Yang .netdev_to_port = felix_netdev_to_port, 25687d4b564dSXiaoliang Yang .psfp_init = vsc9959_psfp_init, 25697d4b564dSXiaoliang Yang .psfp_filter_add = vsc9959_psfp_filter_add, 25707d4b564dSXiaoliang Yang .psfp_filter_del = vsc9959_psfp_filter_del, 25717d4b564dSXiaoliang Yang .psfp_stats_get = vsc9959_psfp_stats_get, 25728abe1970SVladimir Oltean .cut_through_fwd = vsc9959_cut_through_fwd, 25738670dc33SXiaoliang Yang .tas_clock_adjust = vsc9959_tas_clock_adjust, 257425027c84SVladimir Oltean .update_stats = vsc9959_update_stats, 25757d4b564dSXiaoliang Yang }; 25767d4b564dSXiaoliang Yang 2577375e1314SVladimir Oltean static const struct felix_info felix_info_vsc9959 = { 25781109b97bSVladimir Oltean .resources = vsc9959_resources, 25791109b97bSVladimir Oltean .num_resources = ARRAY_SIZE(vsc9959_resources), 25801109b97bSVladimir Oltean .resource_names = vsc9959_resource_names, 258156051948SVladimir Oltean .regfields = vsc9959_regfields, 258256051948SVladimir Oltean .map = vsc9959_regmap, 258356051948SVladimir Oltean .ops = &vsc9959_ops, 258407d985eeSVladimir Oltean .vcap = vsc9959_vcap_props, 258577043c37SXiaoliang Yang .vcap_pol_base = VSC9959_VCAP_POLICER_BASE, 258677043c37SXiaoliang Yang .vcap_pol_max = VSC9959_VCAP_POLICER_MAX, 258777043c37SXiaoliang Yang .vcap_pol_base2 = 0, 258877043c37SXiaoliang Yang .vcap_pol_max2 = 0, 258921ce7f3eSVladimir Oltean .num_mact_rows = 2048, 2590acf242fcSColin Foster .num_ports = VSC9959_NUM_PORTS, 259170d39a6eSVladimir Oltean .num_tx_queues = OCELOT_NUM_TC, 2592c8c0ba4fSVladimir Oltean .quirk_no_xtr_irq = true, 25932ac7c6c5SVladimir Oltean .ptp_caps = &vsc9959_ptp_caps, 2594bdeced75SVladimir Oltean .mdio_bus_alloc = vsc9959_mdio_bus_alloc, 2595bdeced75SVladimir Oltean .mdio_bus_free = vsc9959_mdio_bus_free, 2596acf242fcSColin Foster .port_modes = vsc9959_port_modes, 2597de143c0eSXiaoliang Yang .port_setup_tc = vsc9959_port_setup_tc, 2598de143c0eSXiaoliang Yang .port_sched_speed_set = vsc9959_sched_speed_set, 259955a515b1SVladimir Oltean .tas_guard_bands_update = vsc9959_tas_guard_bands_update, 260056051948SVladimir Oltean }; 2601375e1314SVladimir Oltean 2602375e1314SVladimir Oltean static irqreturn_t felix_irq_handler(int irq, void *data) 2603375e1314SVladimir Oltean { 2604375e1314SVladimir Oltean struct ocelot *ocelot = (struct ocelot *)data; 2605375e1314SVladimir Oltean 2606375e1314SVladimir Oltean /* The INTB interrupt is used for both PTP TX timestamp interrupt 2607375e1314SVladimir Oltean * and preemption status change interrupt on each port. 2608375e1314SVladimir Oltean * 2609375e1314SVladimir Oltean * - Get txtstamp if have 2610375e1314SVladimir Oltean * - TODO: handle preemption. Without handling it, driver may get 2611375e1314SVladimir Oltean * interrupt storm. 2612375e1314SVladimir Oltean */ 2613375e1314SVladimir Oltean 2614375e1314SVladimir Oltean ocelot_get_txtstamp(ocelot); 2615375e1314SVladimir Oltean 2616375e1314SVladimir Oltean return IRQ_HANDLED; 2617375e1314SVladimir Oltean } 2618375e1314SVladimir Oltean 2619375e1314SVladimir Oltean static int felix_pci_probe(struct pci_dev *pdev, 2620375e1314SVladimir Oltean const struct pci_device_id *id) 2621375e1314SVladimir Oltean { 2622375e1314SVladimir Oltean struct dsa_switch *ds; 2623375e1314SVladimir Oltean struct ocelot *ocelot; 2624375e1314SVladimir Oltean struct felix *felix; 2625375e1314SVladimir Oltean int err; 2626375e1314SVladimir Oltean 2627375e1314SVladimir Oltean if (pdev->dev.of_node && !of_device_is_available(pdev->dev.of_node)) { 2628375e1314SVladimir Oltean dev_info(&pdev->dev, "device is disabled, skipping\n"); 2629375e1314SVladimir Oltean return -ENODEV; 2630375e1314SVladimir Oltean } 2631375e1314SVladimir Oltean 2632375e1314SVladimir Oltean err = pci_enable_device(pdev); 2633375e1314SVladimir Oltean if (err) { 2634375e1314SVladimir Oltean dev_err(&pdev->dev, "device enable failed\n"); 2635375e1314SVladimir Oltean goto err_pci_enable; 2636375e1314SVladimir Oltean } 2637375e1314SVladimir Oltean 2638375e1314SVladimir Oltean felix = kzalloc(sizeof(struct felix), GFP_KERNEL); 2639375e1314SVladimir Oltean if (!felix) { 2640375e1314SVladimir Oltean err = -ENOMEM; 2641375e1314SVladimir Oltean dev_err(&pdev->dev, "Failed to allocate driver memory\n"); 2642375e1314SVladimir Oltean goto err_alloc_felix; 2643375e1314SVladimir Oltean } 2644375e1314SVladimir Oltean 2645375e1314SVladimir Oltean pci_set_drvdata(pdev, felix); 2646375e1314SVladimir Oltean ocelot = &felix->ocelot; 2647375e1314SVladimir Oltean ocelot->dev = &pdev->dev; 264870d39a6eSVladimir Oltean ocelot->num_flooding_pgids = OCELOT_NUM_TC; 2649375e1314SVladimir Oltean felix->info = &felix_info_vsc9959; 2650c9910484SColin Foster felix->switch_base = pci_resource_start(pdev, VSC9959_SWITCH_PCI_BAR); 2651375e1314SVladimir Oltean 2652375e1314SVladimir Oltean pci_set_master(pdev); 2653375e1314SVladimir Oltean 2654375e1314SVladimir Oltean err = devm_request_threaded_irq(&pdev->dev, pdev->irq, NULL, 2655375e1314SVladimir Oltean &felix_irq_handler, IRQF_ONESHOT, 2656375e1314SVladimir Oltean "felix-intb", ocelot); 2657375e1314SVladimir Oltean if (err) { 2658375e1314SVladimir Oltean dev_err(&pdev->dev, "Failed to request irq\n"); 2659375e1314SVladimir Oltean goto err_alloc_irq; 2660375e1314SVladimir Oltean } 2661375e1314SVladimir Oltean 2662375e1314SVladimir Oltean ocelot->ptp = 1; 2663*ab3f97a9SVladimir Oltean ocelot->mm_supported = true; 2664375e1314SVladimir Oltean 2665375e1314SVladimir Oltean ds = kzalloc(sizeof(struct dsa_switch), GFP_KERNEL); 2666375e1314SVladimir Oltean if (!ds) { 2667375e1314SVladimir Oltean err = -ENOMEM; 2668375e1314SVladimir Oltean dev_err(&pdev->dev, "Failed to allocate DSA switch\n"); 2669375e1314SVladimir Oltean goto err_alloc_ds; 2670375e1314SVladimir Oltean } 2671375e1314SVladimir Oltean 2672375e1314SVladimir Oltean ds->dev = &pdev->dev; 2673375e1314SVladimir Oltean ds->num_ports = felix->info->num_ports; 2674375e1314SVladimir Oltean ds->num_tx_queues = felix->info->num_tx_queues; 2675375e1314SVladimir Oltean ds->ops = &felix_switch_ops; 2676375e1314SVladimir Oltean ds->priv = ocelot; 2677375e1314SVladimir Oltean felix->ds = ds; 2678adb3dccfSVladimir Oltean felix->tag_proto = DSA_TAG_PROTO_OCELOT; 2679375e1314SVladimir Oltean 2680375e1314SVladimir Oltean err = dsa_register_switch(ds); 2681375e1314SVladimir Oltean if (err) { 2682e6934e40SMichael Walle dev_err_probe(&pdev->dev, err, "Failed to register DSA switch\n"); 2683375e1314SVladimir Oltean goto err_register_ds; 2684375e1314SVladimir Oltean } 2685375e1314SVladimir Oltean 2686375e1314SVladimir Oltean return 0; 2687375e1314SVladimir Oltean 2688375e1314SVladimir Oltean err_register_ds: 2689375e1314SVladimir Oltean kfree(ds); 2690375e1314SVladimir Oltean err_alloc_ds: 2691375e1314SVladimir Oltean err_alloc_irq: 2692375e1314SVladimir Oltean kfree(felix); 2693537e2b88SVladimir Oltean err_alloc_felix: 2694375e1314SVladimir Oltean pci_disable_device(pdev); 2695375e1314SVladimir Oltean err_pci_enable: 2696375e1314SVladimir Oltean return err; 2697375e1314SVladimir Oltean } 2698375e1314SVladimir Oltean 2699375e1314SVladimir Oltean static void felix_pci_remove(struct pci_dev *pdev) 2700375e1314SVladimir Oltean { 27010650bf52SVladimir Oltean struct felix *felix = pci_get_drvdata(pdev); 2702375e1314SVladimir Oltean 27030650bf52SVladimir Oltean if (!felix) 27040650bf52SVladimir Oltean return; 2705375e1314SVladimir Oltean 2706375e1314SVladimir Oltean dsa_unregister_switch(felix->ds); 2707375e1314SVladimir Oltean 2708375e1314SVladimir Oltean kfree(felix->ds); 2709375e1314SVladimir Oltean kfree(felix); 2710375e1314SVladimir Oltean 2711375e1314SVladimir Oltean pci_disable_device(pdev); 27120650bf52SVladimir Oltean } 27130650bf52SVladimir Oltean 27140650bf52SVladimir Oltean static void felix_pci_shutdown(struct pci_dev *pdev) 27150650bf52SVladimir Oltean { 27160650bf52SVladimir Oltean struct felix *felix = pci_get_drvdata(pdev); 27170650bf52SVladimir Oltean 27180650bf52SVladimir Oltean if (!felix) 27190650bf52SVladimir Oltean return; 27200650bf52SVladimir Oltean 27210650bf52SVladimir Oltean dsa_switch_shutdown(felix->ds); 27220650bf52SVladimir Oltean 27230650bf52SVladimir Oltean pci_set_drvdata(pdev, NULL); 2724375e1314SVladimir Oltean } 2725375e1314SVladimir Oltean 2726375e1314SVladimir Oltean static struct pci_device_id felix_ids[] = { 2727375e1314SVladimir Oltean { 2728375e1314SVladimir Oltean /* NXP LS1028A */ 2729375e1314SVladimir Oltean PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0xEEF0), 2730375e1314SVladimir Oltean }, 2731375e1314SVladimir Oltean { 0, } 2732375e1314SVladimir Oltean }; 2733375e1314SVladimir Oltean MODULE_DEVICE_TABLE(pci, felix_ids); 2734375e1314SVladimir Oltean 2735d60bc62dSVladimir Oltean static struct pci_driver felix_vsc9959_pci_driver = { 2736375e1314SVladimir Oltean .name = "mscc_felix", 2737375e1314SVladimir Oltean .id_table = felix_ids, 2738375e1314SVladimir Oltean .probe = felix_pci_probe, 2739375e1314SVladimir Oltean .remove = felix_pci_remove, 27400650bf52SVladimir Oltean .shutdown = felix_pci_shutdown, 2741375e1314SVladimir Oltean }; 2742d60bc62dSVladimir Oltean module_pci_driver(felix_vsc9959_pci_driver); 2743d60bc62dSVladimir Oltean 2744d60bc62dSVladimir Oltean MODULE_DESCRIPTION("Felix Switch driver"); 2745d60bc62dSVladimir Oltean MODULE_LICENSE("GPL v2"); 2746