From eea08813f011a3f94bd3e955ba4533105970d5f0 Mon Sep 17 00:00:00 2001 From: TC956X <56059496+TC956X@users.noreply.github.com> Date: Thu, 18 Jan 2024 13:09:01 +0900 Subject: [PATCH] V_01-03-59 This branch is based on V_01-00-59 ## TC956X_Linux_Host_Driver_20230810_V_01-01-59 1. A part of Automotive AVB/TSN support 2. Default Port 0 interface is XFI and Port1 interface is SGMII 3. IPA (macro TC956X_DMA_OFFLOAD_ENABLE) enabled by default 4. Kernel timers are used to process transmitted TX descriptor. Systick timers are not used. 5. Dynamic change of MTU not supported. Max MTU supported is 9000. 6. Port 1 supports USXGMII, XFI and 25000Base-X interface also. ## TC956X_Linux_Host_Driver_20231110_V_01-02-59 1. Kernel 6.1.18 Porting changes 2. TC956x switch to switch connection support (upto 1 level) over DSP ports ## TC956X_Linux_Host_Driver_20231226_V_01-03-59 1. Kernel 6.6.1 Porting changes 2. Added the support for TC commands taprio and flower --- Readme.md | 22 +- common.h | 1239 ++++- config.ini | 8 +- descs.h | 15 + drivers/net/ethernet/toshiba/tc956x/Makefile | 53 +- dwxgmac2.h | 98 + dwxgmac2_core.c | 527 +- dwxgmac2_descs.c | 200 +- dwxgmac2_dma.c | 111 +- hwif.c | 34 +- hwif.h | 370 +- tc956x_ipa_intf.c | 17 +- tc956x_ipa_intf.h | 4 +- tc956x_msigen.c | 286 + tc956x_pci.c | 1065 +++- tc956x_pcie_logstat.c | 919 ++-- tc956x_pcie_logstat.h | 84 +- tc956x_pf_mbx.c | 612 +++ tc956x_pf_mbx.h | 47 + tc956x_pf_mbx_wrapper.c | 1816 +++++++ tc956x_pf_rsc_mng.c | 158 + tc956x_pf_rsc_mng.h | 86 + tc956x_vf_mbx.c | 550 ++ tc956x_vf_mbx.h | 47 + tc956x_vf_mbx_wrapper.c | 2038 ++++++++ tc956x_vf_rsc_mng.c | 119 + tc956x_vf_rsc_mng.h | 87 + tc956x_xpcs.c | 120 +- tc956x_xpcs.h | 50 +- tc956xmac.h | 313 +- tc956xmac_ethtool.c | 588 ++- tc956xmac_hwtstamp.c | 20 +- tc956xmac_inc.h | 458 +- tc956xmac_ioctl.h | 368 +- tc956xmac_main.c | 4899 ++++++++++++++---- tc956xmac_mdio.c | 222 +- tc956xmac_ptp.c | 49 +- tc956xmac_ptp.h | 6 +- tc956xmac_selftests.c | 594 ++- tc956xmac_tc.c | 638 ++- 40 files changed, 16600 insertions(+), 2337 deletions(-) create mode 100644 tc956x_msigen.c create mode 100644 tc956x_pf_mbx.c create mode 100644 tc956x_pf_mbx.h create mode 100644 tc956x_pf_mbx_wrapper.c create mode 100644 tc956x_pf_rsc_mng.c create mode 100644 tc956x_pf_rsc_mng.h create mode 100644 tc956x_vf_mbx.c create mode 100644 tc956x_vf_mbx.h create mode 100644 tc956x_vf_mbx_wrapper.c create mode 100644 tc956x_vf_rsc_mng.c create mode 100644 tc956x_vf_rsc_mng.h diff --git a/Readme.md b/Readme.md index aac10fc00b5b..a882d0581ec0 100644 --- a/Readme.md +++ b/Readme.md @@ -1,9 +1,9 @@ # Toshiba Electronic Devices & Storage Corporation TC956X PCIe Ethernet Host Driver -Release Date: 09 May 2023 +Release Date: 26 Dec 2023 -Release Version: V_01-00-59 : Limited-tested version +Release Version: V_01-03-59 : Limited-tested version -TC956X PCIe EMAC driver is based on "Fedora 30, kernel-5.4.19". +TC956X PCIe EMAC driver is based on "Fedora 39, kernel-6.6.1". # Compilation & Run: Need to be root user to execute the following steps. 1. By default, DMA_OFFLOAD_ENABLE is enabled. Execute following commands: @@ -565,3 +565,19 @@ TC956X PCIe EMAC driver is based on "Fedora 30, kernel-5.4.19". ## TC956X_Host_Driver_20230509_V_01-00-59: 1. Module parameters for SW reset (during link change) enabled by default for Port0. + +## TC956X_Linux_Host_Driver_20230810_V_01-01-59 +1. Automotive AVB/TSN support +2. Default Port 0 interface is XFI and Port1 interface is SGMII +3. IPA (macro TC956X_DMA_OFFLOAD_ENABLE) enabled by default +4. Kernel timers are used to process transmitted TX descriptor. Systick timers are not used. +5. Dynamic change of MTU not supported. Max MTU supported is 9000. +6. Port 1 supports USXGMII, XFI and 25000Base-X interface also. + +## TC956X_Linux_Host_Driver_20231110_V_01-02-59 +1. Kernel 6.1.18 Porting changes +2. TC956x switch to switch connection support (upto 1 level) over DSP ports + +## TC956X_Linux_Host_Driver_20231226_V_01-03-59 +1. Kernel 6.6.1 Porting changes +2. Added the support for TC commands taprio and flower \ No newline at end of file diff --git a/common.h b/common.h index 5fcb5c3bf30a..3682b330811b 100644 --- a/common.h +++ b/common.h @@ -91,6 +91,8 @@ #include "tc956xmac_inc.h" #include #include +#include +#include #if IS_ENABLED(CONFIG_VLAN_8021Q) #define TC956XMAC_VLAN_TAG_USED #include @@ -100,18 +102,21 @@ #include "hwif.h" #include "mmc.h" #ifdef TC956X +#ifndef TC956X_SRIOV_VF #include "tc956x_xpcs.h" +#endif #include "tc956x_pma.h" #endif /* Enable DMA IPA offload */ -#define DMA_OFFLOAD_ENABLE +#define TC956X_DMA_OFFLOAD_ENABLE //#define TC956X_LPI_INTERRUPT /* Indepenedent Suspend/Resume Debug */ #undef TC956X_PM_DEBUG #define TC956X_MAX_PORT 2 -#define TC956X_ALL_MAC_PORT_SUSPENDED 0 /* All EMAC Port Suspended. To be used just after suspend and before resume. */ +#define TC956X_ALL_MAC_PORT_SUSPENDED 0 /* All EMAC Port Suspended. To be used just after suspend and before resume. */ #define TC956X_NO_MAC_DEVICE_IN_USE 0 /* No EMAC Port in use. To be used at probe and remove. */ +#define TC956X_SINGLE_MAC_DEVICE_IN_USE 1 /* One of the EMAC Port in use. To be used at remove. */ #define TC956X_ALL_MAC_PORT_LINK_DOWN 2 /* All ports are Link Down */ /* Suspend-Resume Arguments */ enum TC956X_PORT_PM_STATE { @@ -124,13 +129,14 @@ enum TC956X_PORT_LINK_CHANGE_STATE { LINK_DOWN = 0, LINK_UP, }; - +#if defined(TC956X_SRIOV_PF) //#define TC956X_PCIE_LINK_STATE_LATENCY_CTRL - -#define DISABLE 0 -#define ENABLE 1 -#define SIZE_512B 512 -#define SIZE_1KB 1024 +#define TC956X_PCIE_DSP_CUT_THROUGH +#endif +#define DISABLE 0x0U +#define ENABLE 0x1U +#define SIZE_512B 0x200U +#define SIZE_1KB 0x400U /* Synopsys Core versions */ #define DWMAC_CORE_3_40 0x34 @@ -143,21 +149,79 @@ enum TC956X_PORT_LINK_CHANGE_STATE { #define DWXGMAC_CORE_3_01 0x30 //#define DISABLE_EMAC_PORT1 +#ifndef TC956X_SRIOV_VF #define EEE /* Enable for EEE support */ +#endif -/* Note: Multiple macro definitions for TC956X_PCIE_LOGSTAT. +#define TC956X_MAC_ADDR_CNT 6 +/* Note: Multiple macro definitions for TC956X_PCIE_LOGSTAT and TC956X_PCIE_LOGSTAT_SUMMARY_ENABLE. * Please also define/undefine same macro in tc956xmac_ioctl.h, if changing in this file */ /* #undef TC956X_PCIE_LOGSTAT */ #define TC956X_PCIE_LOGSTAT +#ifdef TC956X_PCIE_LOGSTAT +/* Enable/Disable Logstat Summary Print during probe and resume. */ +#undef TC956X_PCIE_LOGSTAT_SUMMARY_ENABLE +#endif +/* This macro to be enabled for loading cbs based on speed change */ +// #define TC956X_DYNAMIC_LOAD_CBS +/* This macro to be enabled while running TSN demo Application */ +// #define TSN_DEMO_AUTOMOTIVE + +#define TC956X_M3_DMEM_OFFSET 0x40000 +#define MAC2MAC_ETH0_RXDESC_L 0x7800 +#define MAC2MAC_ETH0_RXDESC_H 0x7804 +#define MAC2MAC_ETH1_RXDESC_L 0xB800 +#define MAC2MAC_ETH1_RXDESC_H 0xB804 + +//#define TX_LOGGING_TRACE +//#define RX_LOGGING_TRACE #define TC956XMAC_CHAN0 0 /* Always supported and default for all chips */ +//#define TC956X_SRIOV_PF +#define TC956X_SRIOV_LOCK +//#define TC956X_SRIOV_DEBUG + + #define TC956XMAC_CHA_NO_0 BIT(0) #define TC956XMAC_CHA_NO_1 BIT(1) #define TC956XMAC_CHA_NO_2 BIT(2) #define TC956XMAC_CHA_NO_3 BIT(3) +#ifdef TC956X_SRIOV_PF +/* VF number for each VF Application */ +#define TC956XMAC_VF_IVI 1 +#define TC956XMAC_VF_TCU 2 +#define TC956XMAC_VF_ADAS 3 + +#if defined(TC956X_AUTOMOTIVE_CONFIG) || defined(TC956X_ENABLE_MAC2MAC_BRIDGE) +/* Legacy channel for each VF Application */ +#define TC956XMAC_CHA_IVI TC956XMAC_CHA_NO_0 +#define TC956XMAC_CHA_TCU TC956XMAC_CHA_NO_0 +#define TC956XMAC_CHA_ADAS TC956XMAC_CHA_NO_0 +#define TC956XMAC_CHA_PF TC956XMAC_CHA_NO_0 +#if defined(TC956X_ENABLE_MAC2MAC_BRIDGE) +#define TC956XMAC_CHA_M2M TC956XMAC_CHA_NO_2 +#endif +#else +/* Legacy channel for each VF Application */ +#define TC956XMAC_CHA_IVI TC956XMAC_CHA_NO_0 +#define TC956XMAC_CHA_TCU TC956XMAC_CHA_NO_1 +#define TC956XMAC_CHA_ADAS TC956XMAC_CHA_NO_2 +#define TC956XMAC_CHA_PF TC956XMAC_CHA_NO_3 +#endif +#endif + +#if defined(TC956X_SRIOV_PF) && !defined(TC956X_AUTOMOTIVE_CONFIG) && !defined(TC956X_ENABLE_MAC2MAC_BRIDGE) +#define TC956X_TOT_MSI_VEC 2 +#else +#define TC956X_TOT_MSI_VEC 1 +#endif + +#define TC956X_MSI_VECTOR_0 0 +#define TC956X_MSI_VECTOR_1 1 + #define ETH_DMA_DUMP_OFFSET1 (0x3000 / 4) #define ETH_DMA_DUMP_OFFSET1_END (0x30A0 / 4) #define ETH_DMA_DUMP_OFFSET2 (0x3100 / 4) @@ -193,6 +257,122 @@ void tc956xmac_exit(void); #endif +#ifdef TC956X_SRIOV_PF +/* TC956X Semaphore lock/unlock register */ +#define NSEM(reg) (0x1100 + (reg * 4)) +/* TC956X Semaphore read register */ +#define NSEM_RD(reg) (0x1140 + (reg * 4)) + +#define MBX_MSG_OFST 4 /* First 4 bytes for ACK management */ +#define MBX_MSG_SIZE 60 /* Excluding ACK */ +#define MBX_ACK_SIZE 4 /* ACK management */ +#define MBX_TOT_SIZE (MBX_MSG_SIZE + MBX_ACK_SIZE) + +#define ACK 0x01 +#define NACK 0x02 + +#define MAX_NO_OF_VFS 3 + +/* Mailbox opcode definitions */ +#define OPCODE_MBX_ADD_MAC_ADDR 0x01 +#define OPCODE_MBX_SET_TX_Q_WEIGHT 0x02 +#define OPCODE_MBX_CFG_CBS 0x03 +#define OPCODE_MBX_SET_TX_Q_PRIOR 0x04 +#define OPCODE_MBX_RESET_EEE_MODE 0x05 +#define OPCODE_MBX_VF_IOCTL 0x06 +#define OPCODE_MBX_VF_ETHTOOL 0x07 +#define OPCODE_MBX_VF_ADD_MAC 0x08 +#define OPCODE_MBX_VF_DELETE_MAC 0x09 +#define OPCODE_MBX_VF_ADD_VLAN 0x10 +#define OPCODE_MBX_VF_DELETE_VLAN 0x11 +#define OPCODE_MBX_SET_DMA_TX_MODE 0x12 +#define OPCODE_MBX_VF_GET_LINK_STATUS 0x13 +#define OPCODE_MBX_PHY_LINK 0x14 +#define OPCODE_MBX_SETUP_CBS 0x15 +#define OPCODE_MBX_RX_CRC 0x16 +#define OPCODE_MBX_RX_CSUM 0x17 +#define OPCODE_MBX_DRV_CAP 0x18 +#define OPCODE_MBX_VF_GET_MII_PHY 0x23 +#define TC956XMAC_GET_PAUSE_PARAM_2 0x24 +#define OPCODE_MBX_GET_UMAC_ADDR 0x25 +#define OPCODE_VF_RESET 0x26 +#define OPCODE_MBX_DMA_CH_TLPTR 0x29 +#define OPCODE_MBX_SETUP_ETF 0x30 +#define OPCODE_MBX_FLR 0x33 +#define OPCODE_MBX_DMA_ERR 0x34 +#define OPCODE_MBX_ACK_MSG 0xFF + +#define SIZE_MBX_SET_TX_Q_WEIGHT 8 +#define SIZE_MBX_CFG_CBS 20 +#define SIZE_MBX_SETUP_ETF 5 +#define SIZE_MBX_CFG_EST 540 /* 28 + (4*128) */ +#define SIZE_MBX_CFG_FPE 20 +#define SIZE_MBX_SETUP_CBS 21 +#define SIZE_MBX_SET_TX_Q_PRIOR 8 +#define SIZE_MBX_SET_DMA_TX_MODE 13 +#define SIZE_MBX_VF_GET_LINK_STATUS 0 +#define SIZE_MBX_PHY_LINK 12 +#define SIZE_MBX_RX_CRC 4 +#define SIZE_MBX_RX_CSUM 4 +#define SIZE_MBX_DRV_CAP 4 +#define SIZE_GET_UMAC_ADDR 4 +#define SIZE_SET_UMAC_ADDR 10 +#define SIZE_MBX_VF_MAC 6 +#define SIZE_MBX_VF_VLAN 2 +#define SIZE_MBX_VF_REG_WR 13 +#define SIZE_MBX_VF_SPEED 1 +#define SIZE_MBX_SET_GET_CBS_1 56 +#define SIZE_MBX_SET_GET_RXP_1 56 +#define SIZE_MBX_SET_GET_CBS_2 44 +#define SIZE_MBX_VF_PAUSE_PARAM 1 +#define SIZE_MBX_VF_EEE 1 +#define SIZE_MBX_VF_TS_INFO 1 +#define SIZE_VF_RESET 1 +#define SIZE_MBX_VF_TIMESTAMP 2 +#define SIZE_MBX_SET_GET_EST_1 56 +#define SIZE_MBX_RX_DMA_TL_PTR 4 +#define SIZE_MBX_SET_GET_FPE_1 20 +#define SIZE_MBX_GET_HW_STMP 12 + +#define MAX_SIZE_GCL_MSG 14 +#define EST_FIX_MSG_LEN 28 +#define RXP_FIX_MSG_LEN 16 +#define VF_UP 1 +#define VF_DOWN 0 +#define VF_SUSPEND 2 +#define VF_RELEASE 3 + +#define SCH_WQ_PHY_REG_RD 1 +#define SCH_WQ_RX_DMA_ERR 2 +#define SCH_WQ_GET_PAUSE_PARAM 3 + +#endif /* #ifdef TC956X_SRIOV_PF */ + +#ifdef TC956X_SRIOV_VF +#define TC956X_MIN_MSI_VEC 1 +#define TC956X_MAX_MSI_VEC 1 + +#define TC956X_MSI_VECTOR_0 0 +#define TC956X_MSI_VECTOR_1 1 +#endif + +enum mbx_msg_fns { + mcu = 0, + pf0 = 1, + pf1 = 2, + vf0 = 3, + vf1 = 4, + vf2 = 5 +}; + +struct fn_id { + bool fn_type; /*0 - PF; 1-VF*/ + u8 pf_no; /* PF number [0-1], In case of VF, this gives information + * about associated PF + */ + u8 vf_no; /*VF number [1-3]*/ +}; + /* Packets types */ enum packets_types { @@ -204,6 +384,9 @@ enum packets_types { #ifdef TC956X PACKET_FPE_RESIDUE = 0x6, /* Frame Pre-emption residue packets */ #endif +#if defined(TC956X_SRIOV_PF) && !defined(TC956X_AUTOMOTIVE_CONFIG) && !defined(TC956X_ENABLE_MAC2MAC_BRIDGE) + PACKET_FILTER_FAIL = 0x7, /* Filter Fail packets */ +#endif }; //#define TX_LOGGING_TRACE @@ -211,7 +394,8 @@ enum packets_types { /* Dual Port related Macros */ #define RM_PF0_ID (0) #define RM_PF1_ID (1) - +#define RM_IS_PF (0) +#define RM_IS_VF (1) #define MAC_PORT_NUM_CHECK (priv->port_num == RM_PF0_ID) /* Select the MDC range based on PHY specification. @@ -246,7 +430,12 @@ enum packets_types { */ #define TC956X_MAX_PERFECT_ADDRESSES 32 #define TC956X_MAX_PERFECT_VLAN 16 -#define XGMAC_ADDR_ADD_SKIP_OFST 3 + +#if defined(TC956X_SRIOV_PF) && !defined(TC956X_AUTOMOTIVE_CONFIG) && !defined(TC956X_ENABLE_MAC2MAC_BRIDGE) +#define XGMAC_ADDR_ADD_SKIP_OFST 6 +#else +#define XGMAC_ADDR_ADD_SKIP_OFST 3 +#endif #define TC956X_MAC_STATE_VACANT 0x0 @@ -341,6 +530,455 @@ enum packets_types { #define NFUNCEN4_OFFSET (0x1528) +#define MAX_RX_QUEUE_SIZE 47104 /* 46KB Maximun RX Queue size */ +#define MAX_TX_QUEUE_SIZE 47104 /* 46KB Maximun TX Queue size */ + +#if defined(TC956X_SRIOV_PF) && !defined(TC956X_AUTOMOTIVE_CONFIG) && !defined(TC956X_ENABLE_MAC2MAC_BRIDGE) + +/************************ TC956X_SRIOV_PF Starts ************************/ + +#define TC956X_DMA_RX_AIS BIT(14) +#define TC956X_DMA_RX_FBE BIT(12) +#define TC956X_DMA_RX_RPS BIT(8) +#define MAX_TX_QUEUES_TO_USE 8 +#define MAX_RX_QUEUES_TO_USE 8 + +/* Tx Queue Size*/ +#define TX_QUEUE0_SIZE 4096 +#define TX_QUEUE1_SIZE 4096 +#define TX_QUEUE2_SIZE 18432 +#define TX_QUEUE3_SIZE 4096 +#define TX_QUEUE4_SIZE 1024 +#define TX_QUEUE5_SIZE 4096 +#define TX_QUEUE6_SIZE 4096 +#define TX_QUEUE7_SIZE 4096 + +/* TX Queue 0: Legacy and Jumbo packets */ +#define TX_QUEUE0_MODE MTL_QUEUE_DCB +/* TX Queue 1:Legacy*/ +#define TX_QUEUE1_MODE MTL_QUEUE_DCB +/* TX Queue 2: Legacy */ +#define TX_QUEUE2_MODE MTL_QUEUE_DCB +/* TX Queue 3: Legacy */ +#define TX_QUEUE3_MODE MTL_QUEUE_DCB +/* TX Queue 4: Untagged PTP */ +#define TX_QUEUE4_MODE MTL_QUEUE_DCB +/* TX Queue 5: AVB Class B AVTP packet */ +#define TX_QUEUE5_MODE MTL_QUEUE_AVB +/* TX Queue 6: AVB Class A AVTP packet */ +#define TX_QUEUE6_MODE MTL_QUEUE_AVB +/* TX Queue 7: TSN Class CDT packet */ +#if defined(TSN_DEMO_AUTOMOTIVE) +#define TX_QUEUE7_MODE MTL_QUEUE_DCB +#else +#define TX_QUEUE7_MODE MTL_QUEUE_AVB +#endif + +/* Tx Queue TBS Enable/Disable */ +#define TX_QUEUE0_TBS 0 +#define TX_QUEUE1_TBS 0 +#define TX_QUEUE2_TBS 0 +#define TX_QUEUE3_TBS 0 +#define TX_QUEUE4_TBS 0 +#define TX_QUEUE5_TBS 1 +#define TX_QUEUE6_TBS 1 +#define TX_QUEUE7_TBS 1 + +/* Tx Queue TSO Enable/Disable */ +#define TX_QUEUE0_TSO 1 +#define TX_QUEUE1_TSO 1 +#define TX_QUEUE2_TSO 1 +#define TX_QUEUE3_TSO 1 +#define TX_QUEUE4_TSO 0 +#define TX_QUEUE5_TSO 0 +#define TX_QUEUE6_TSO 0 +#define TX_QUEUE7_TSO 0 + +/* Configure TxQueue - Traffic Class mapping */ +#define TX_QUEUE0_TC 0x0 +#define TX_QUEUE1_TC 0x0 +#define TX_QUEUE2_TC 0x0 +#define TX_QUEUE3_TC 0x0 +#define TX_QUEUE4_TC 0x1 +#define TX_QUEUE5_TC 0x2 +#define TX_QUEUE6_TC 0x3 +#define TX_QUEUE7_TC 0x4 + + +/* + * RX Queue 0: Unicast/Untagged Packets - Packets with + * unique MAC Address of Host/Guest OS DMA channel selection will be based on + * MAC_Address(#i)_High.DCS + */ +#define RX_QUEUE0_MODE MTL_QUEUE_DCB +/* RX Queue 1: VLAN Tagged Legacy packets- Pkt routing will be based on VLAN */ +#define RX_QUEUE1_MODE MTL_QUEUE_DCB +/* RX Queue 2: Untagged gPTP packets */ +#define RX_QUEUE2_MODE MTL_QUEUE_DCB +/* RX Queue 3: Filter Fail packet queue */ +#define RX_QUEUE3_MODE MTL_QUEUE_DCB +/* RX Queue 4: AVB Class B AVTP packets */ +#define RX_QUEUE4_MODE MTL_QUEUE_AVB +/* RX Queue 5: AVB Class A AVTP packets */ +#define RX_QUEUE5_MODE MTL_QUEUE_AVB +/* RX Queue 6:TSN Class CDT packets */ +#define RX_QUEUE6_MODE MTL_QUEUE_AVB +/* RX Queue 7: Broadcast/Multicast packets */ +#define RX_QUEUE7_MODE MTL_QUEUE_DCB + +/* Rx Queue Size */ +#define RX_QUEUE0_SIZE 18432 +#define RX_QUEUE1_SIZE 4096 +#define RX_QUEUE2_SIZE 1024 +#define RX_QUEUE3_SIZE 4096 +#define RX_QUEUE4_SIZE 4096 +#define RX_QUEUE5_SIZE 4096 +#define RX_QUEUE6_SIZE 4096 +#define RX_QUEUE7_SIZE 4096 + +/* Rx Queue Packet Routing */ +#define RX_QUEUE0_PKT_ROUTE PACKET_UPQ +#define RX_QUEUE1_PKT_ROUTE 0 +#define RX_QUEUE2_PKT_ROUTE PACKET_PTPQ +#define RX_QUEUE3_PKT_ROUTE PACKET_FILTER_FAIL +/* Queue 4,5,6 Routed based on Packet Priority Configured in + * MAC_RxQ_Ctrl2/MAC_RxQ_Ctrl3 + */ +#define RX_QUEUE4_PKT_ROUTE 0 +#define RX_QUEUE5_PKT_ROUTE 0 +#define RX_QUEUE6_PKT_ROUTE 0 +#define RX_QUEUE7_PKT_ROUTE PACKET_MCBCQ + + +#define TC956X_DA_MAP 0xF + +/* Unicast/Untagged packet */ +#define LEG_UNTAGGED_PACKET TC956X_DA_MAP +/* VLAN tagged packets */ +#define LEG_TAGGED_PACKET TC956X_DA_MAP +/* Untagged gPTP packet */ +#define UNTAGGED_GPTP_PACKET 4 +/* Filter Failed Unicast, Multicast, Tagged packets. + * Route to PF Best Effort Channel. Used only in SRIOV promiscuous mode + */ +#define FILTER_FAIL_PACKET 3 +/* Class B AVB Packet */ +#define AVB_CLASS_B_PACKET 5 +/* Class A AVB Packet */ +#define AVB_CLASS_A_PACKET 6 +/* TSN Class CDT Packet */ +#define TSN_CLASS_CDT_PACKET 7 +/* Broadcast/Multicast packet */ +#define BC_MC_PACKET TC956X_DA_MAP + +#define TX_QUEUE0_USE_PRIO true +#define TX_QUEUE1_USE_PRIO true +#define TX_QUEUE2_USE_PRIO true +#define TX_QUEUE3_USE_PRIO true +#define TX_QUEUE4_USE_PRIO false +#define TX_QUEUE5_USE_PRIO false +#define TX_QUEUE6_USE_PRIO false +#define TX_QUEUE7_USE_PRIO false + +#define TX_QUEUE0_PRIO 0xFF /* TC0 Priority */ +#define TX_QUEUE1_PRIO 0xFF +#define TX_QUEUE2_PRIO 0xFF +#define TX_QUEUE3_PRIO 0xFF +#define TX_QUEUE4_PRIO 0x00 +#define TX_QUEUE5_PRIO 0x00 +#define TX_QUEUE6_PRIO 0x00 +#define TX_QUEUE7_PRIO 0x00 + +/* Rx Queue Use Priority */ +#define RX_QUEUE0_USE_PRIO false +#define RX_QUEUE1_USE_PRIO true +#define RX_QUEUE2_USE_PRIO false +#define RX_QUEUE3_USE_PRIO false +#define RX_QUEUE4_USE_PRIO true +#define RX_QUEUE5_USE_PRIO true +#define RX_QUEUE6_USE_PRIO true +#define RX_QUEUE7_USE_PRIO false + +/* Rx Queue VLAN tagged Priority mapping */ +#define RX_QUEUE0_PRIO 0 +#define RX_QUEUE1_PRIO 0xFF +#define RX_QUEUE2_PRIO 0 +#define RX_QUEUE3_PRIO 0 +#define RX_QUEUE4_PRIO (1 << TC956X_AVB_PRIORITY_CLASS_B) +#define RX_QUEUE5_PRIO (1 << TC956X_AVB_PRIORITY_CLASS_A) +#define RX_QUEUE6_PRIO (1 << TC956X_PRIORITY_CLASS_CDT) +#define RX_QUEUE7_PRIO 0 + +#define EEPROM_OFFSET 0 +#define EEPROM_MAC_COUNT 8 + +/* DMA Ch allocation in tx-rx pairs for PF & VF */ +#define TC956X_PF_CH_ALLOC 0x18 /* PF - Ch 3, 4 */ +#define TC956X_VF0_CH_ALLOC 0x21 /* VF0 - Ch 0, 5 */ +#define TC956X_VF1_CH_ALLOC 0x02 /* VF1 - Ch 1 */ +#define TC956X_VF2_CH_ALLOC 0xC4 /* VF2 - Ch 2, 6, 7 */ +/************************* TC956X_SRIOV_PF Ends *************************/ + + +#elif defined(TC956X_SRIOV_PF) + +/***************** Automotive and Port Bridge Config Starts *************/ + + +#if defined(TC956X_DMA_OFFLOAD_ENABLE) +#define TX_DMA_CH0_OWNER USE_IN_TC956X_SW +#define TX_DMA_CH1_OWNER NOT_USED +#define TX_DMA_CH2_OWNER USE_IN_TC956X_SW +#define TX_DMA_CH3_OWNER USE_IN_TC956X_SW +#define TX_DMA_CH4_OWNER USE_IN_TC956X_SW +#define TX_DMA_CH5_OWNER USE_IN_TC956X_SW +#define TX_DMA_CH6_OWNER USE_IN_TC956X_SW +#define TX_DMA_CH7_OWNER USE_IN_TC956X_SW + +#define RX_DMA_CH0_OWNER USE_IN_TC956X_SW +#define RX_DMA_CH1_OWNER NOT_USED +#define RX_DMA_CH2_OWNER USE_IN_TC956X_SW +#define RX_DMA_CH3_OWNER USE_IN_TC956X_SW +#define RX_DMA_CH4_OWNER USE_IN_TC956X_SW +#define RX_DMA_CH5_OWNER USE_IN_TC956X_SW +#define RX_DMA_CH6_OWNER USE_IN_TC956X_SW +#define RX_DMA_CH7_OWNER USE_IN_TC956X_SW +#endif +#define TC956X_DMA_RX_AIS BIT(14) +#define TC956X_DMA_RX_FBE BIT(12) +#define TC956X_DMA_RX_RPS BIT(8) +#define MAX_TX_QUEUES_TO_USE 8 +#define MAX_RX_QUEUES_TO_USE 8 + +/* Tx Queue Size*/ +#ifdef TC956X_ENABLE_MAC2MAC_BRIDGE +#define TX_QUEUE0_SIZE 18432 +#define TX_QUEUE1_SIZE 0 +#define TX_QUEUE2_SIZE 18432 +#define TX_QUEUE3_SIZE 0 +#define TX_QUEUE4_SIZE 1024 +#define TX_QUEUE5_SIZE 2048 +#define TX_QUEUE6_SIZE 2048 +#define TX_QUEUE7_SIZE 4096 +#else +#define TX_QUEUE0_SIZE 18432 +#define TX_QUEUE1_SIZE 14336 +#define TX_QUEUE2_SIZE 0 +#define TX_QUEUE3_SIZE 0 +#define TX_QUEUE4_SIZE 1024 +#define TX_QUEUE5_SIZE 4096 +#define TX_QUEUE6_SIZE 4096 +#define TX_QUEUE7_SIZE 4096 +#endif + +/* TX Queue 0: Legacy and Jumbo packets */ +#define TX_QUEUE0_MODE MTL_QUEUE_DCB +/* TX Queue 1: Legacy */ +#define TX_QUEUE1_MODE MTL_QUEUE_DCB +/* TX Queue 2: Legacy */ +#define TX_QUEUE2_MODE MTL_QUEUE_DISABLE +/* TX Queue 3: Legacy */ +#define TX_QUEUE3_MODE MTL_QUEUE_DISABLE +/* TX Queue 4: Untagged PTP */ +#define TX_QUEUE4_MODE MTL_QUEUE_DCB +/* TX Queue 5: AVB Class B AVTP packet */ +#define TX_QUEUE5_MODE MTL_QUEUE_AVB +/* TX Queue 6: AVB Class A AVTP packet */ +#define TX_QUEUE6_MODE MTL_QUEUE_AVB +/* TX Queue 7: TSN Class CDT packet */ +#if defined(TSN_DEMO_AUTOMOTIVE) +#define TX_QUEUE7_MODE MTL_QUEUE_DCB +#else +#define TX_QUEUE7_MODE MTL_QUEUE_AVB +#endif + +/* Tx Queue TBS Enable/Disable */ +#define TX_QUEUE0_TBS 0 +#define TX_QUEUE1_TBS 0 +#define TX_QUEUE2_TBS 0 +#define TX_QUEUE3_TBS 0 +#define TX_QUEUE4_TBS 0 +#define TX_QUEUE5_TBS 1 +#define TX_QUEUE6_TBS 1 +#define TX_QUEUE7_TBS 1 + +/* Tx Queue TSO Enable/Disable */ +#define TX_QUEUE0_TSO 1 +#define TX_QUEUE1_TSO 1 +#define TX_QUEUE2_TSO 0 +#define TX_QUEUE3_TSO 0 +#define TX_QUEUE4_TSO 0 +#define TX_QUEUE5_TSO 0 +#define TX_QUEUE6_TSO 0 +#define TX_QUEUE7_TSO 0 + +/* Configure TxQueue - Traffic Class mapping */ +#define TX_QUEUE0_TC 0x0 +#define TX_QUEUE1_TC 0x0 +#define TX_QUEUE2_TC 0x0 +#define TX_QUEUE3_TC 0x0 +#define TX_QUEUE4_TC 0x1 +#define TX_QUEUE5_TC 0x2 +#define TX_QUEUE6_TC 0x3 +#define TX_QUEUE7_TC 0x4 + + +/* + * RX Queue 0: Unicast/Untagged Packets - Packets with + * unique MAC Address of Host/Guest OS DMA channel selection will be based on + * MAC_Address(#i)_High.DCS + */ +#define RX_QUEUE0_MODE MTL_QUEUE_DCB +/* RX Queue 1: VLAN Tagged Legacy packets- Pkt routing will be based on VLAN */ +/* Queue is used for MAC2MAC Usecase */ +#define RX_QUEUE1_MODE MTL_QUEUE_DCB +/* RX Queue 2: Untagged gPTP packets */ +#define RX_QUEUE2_MODE MTL_QUEUE_DCB +/* RX Queue 3: Untagged AV Control packets */ +#define RX_QUEUE3_MODE MTL_QUEUE_AVB +/* RX Queue 4: AVB Class B AVTP packets */ +#define RX_QUEUE4_MODE MTL_QUEUE_AVB +/* RX Queue 5: AVB Class A AVTP packets */ +#define RX_QUEUE5_MODE MTL_QUEUE_AVB +/* RX Queue 6:TSN Class CDT packets */ +#define RX_QUEUE6_MODE MTL_QUEUE_AVB +/* RX Queue 7: Broadcast/Multicast packets */ +#define RX_QUEUE7_MODE MTL_QUEUE_DCB + +/* Rx Queue Size */ +#ifdef TC956X_ENABLE_MAC2MAC_BRIDGE +#define RX_QUEUE0_SIZE 18432 +#define RX_QUEUE1_SIZE 18432 +#define RX_QUEUE2_SIZE 1024 +#define RX_QUEUE3_SIZE 1024 +#define RX_QUEUE4_SIZE 2048 +#define RX_QUEUE5_SIZE 1024 +#define RX_QUEUE6_SIZE 1024 +#define RX_QUEUE7_SIZE 4096 +#else +#define RX_QUEUE0_SIZE 18432 +#define RX_QUEUE1_SIZE 4096 +#define RX_QUEUE2_SIZE 1024 +#define RX_QUEUE3_SIZE 1024 +#define RX_QUEUE4_SIZE 4096 +#define RX_QUEUE5_SIZE 4096 +#define RX_QUEUE6_SIZE 4096 +#define RX_QUEUE7_SIZE 4096 +#endif +/* Rx Queue Packet Routing */ +#define RX_QUEUE0_PKT_ROUTE PACKET_UPQ +#define RX_QUEUE1_PKT_ROUTE 0 +#define RX_QUEUE2_PKT_ROUTE PACKET_PTPQ +#define RX_QUEUE3_PKT_ROUTE PACKET_AVCPQ +/* Queue 4,5,6 Routed based on Packet Priority Configured in + * MAC_RxQ_Ctrl2/MAC_RxQ_Ctrl3 + */ +#define RX_QUEUE4_PKT_ROUTE 0 +#define RX_QUEUE5_PKT_ROUTE 0 +#define RX_QUEUE6_PKT_ROUTE 0 +#define RX_QUEUE7_PKT_ROUTE PACKET_MCBCQ + + +#define TC956X_DA_MAP 0xF + +/* Unicast/Untagged packet */ +#define LEG_UNTAGGED_PACKET 0 +/* VLAN tagged packets */ +#define LEG_TAGGED_PACKET 0 +/* Untagged gPTP packet */ +#define UNTAGGED_GPTP_PACKET 4 +/* Untagged AV Control Packet */ +#define UNTAGGED_AVCTRL_PACKET 3 +/* Class B AVB Packet */ +#define AVB_CLASS_B_PACKET 5 +/* Class A AVB Packet */ +#define AVB_CLASS_A_PACKET 6 +/* TSN Class CDT Packet */ +#define TSN_CLASS_CDT_PACKET 7 +/* Broadcast/Multicast packet */ +#define BC_MC_PACKET 0 + +#define TX_QUEUE0_USE_PRIO true +#define TX_QUEUE1_USE_PRIO true +#define TX_QUEUE2_USE_PRIO true +#define TX_QUEUE3_USE_PRIO true +#define TX_QUEUE4_USE_PRIO false +#define TX_QUEUE5_USE_PRIO false +#define TX_QUEUE6_USE_PRIO false +#define TX_QUEUE7_USE_PRIO false + +#define TX_QUEUE0_PRIO 0xFF /* TC0 Priority */ +#define TX_QUEUE1_PRIO 0xFF +#define TX_QUEUE2_PRIO 0xFF +#define TX_QUEUE3_PRIO 0xFF +#define TX_QUEUE4_PRIO 0x00 +#define TX_QUEUE5_PRIO 0x00 +#define TX_QUEUE6_PRIO 0x00 +#define TX_QUEUE7_PRIO 0x00 + +/* Rx Queue Use Priority */ +#ifdef TC956X_ENABLE_MAC2MAC_BRIDGE +/* RXQ0 used for Host unicast/untagged and vlan tagged packets +RXQ1 used for MAC2MAC */ +#define RX_QUEUE0_USE_PRIO true +#define RX_QUEUE1_USE_PRIO false +#else +#define RX_QUEUE0_USE_PRIO false +#define RX_QUEUE1_USE_PRIO true +#endif +#define RX_QUEUE2_USE_PRIO false +#define RX_QUEUE3_USE_PRIO false +#define RX_QUEUE4_USE_PRIO true +#define RX_QUEUE5_USE_PRIO true +#define RX_QUEUE6_USE_PRIO true +#define RX_QUEUE7_USE_PRIO false + +/* Rx Queue VLAN tagged Priority mapping */ +#ifdef TC956X_ENABLE_MAC2MAC_BRIDGE +#define RX_QUEUE0_PRIO 0xFF +#define RX_QUEUE1_PRIO 0 +#else +#define RX_QUEUE0_PRIO 0 +#define RX_QUEUE1_PRIO 0xFF +#endif +#define RX_QUEUE2_PRIO 0 +#define RX_QUEUE3_PRIO 0 +#define RX_QUEUE4_PRIO (1 << TC956X_AVB_PRIORITY_CLASS_B) +#define RX_QUEUE5_PRIO (1 << TC956X_AVB_PRIORITY_CLASS_A) +#define RX_QUEUE6_PRIO (1 << TC956X_PRIORITY_CLASS_CDT) +#define RX_QUEUE7_PRIO 0 + +#define EEPROM_OFFSET 0 +#define EEPROM_MAC_COUNT 2 + +/* DMA Ch allocation in tx-rx pairs for PF & VF */ +#define TC956X_PF_CH_ALLOC 0xFF /* PF - All Channels */ +#define TC956X_VF0_CH_ALLOC 0x00 /* VF0 - NA */ +#define TC956X_VF1_CH_ALLOC 0x00 /* VF1 - NA */ +#define TC956X_VF2_CH_ALLOC 0x00 /* VF2 - NA */ + +/***************** Automotive and Port Bridge Config Ends ***************/ + +#elif defined TC956X_SRIOV_VF + +/************************ TC956X_SRIOV_VF Starts ************************/ +#define MAX_TX_QUEUES_TO_USE 8 +#define MAX_RX_QUEUES_TO_USE 8 + +#define MAX_FUNCS_PER_PF 4 +#define TX_TC_ZERO 0x0 +#define TC956X_DMA_CH0_MASK 0x01 + +#define EEPROM_PORT_OFFSET ((MAC_PORT_NUM_CHECK) ? \ + (EEPROM_VF_SLOT_OFST1) : (EEPROM_VF_SLOT_OFST2)) + +#define EEPROM_VF_SLOT_OFST1 2 +#define EEPROM_VF_SLOT_OFST2 3 + +/************************** TC956X_SRIOV_VF Ends ************************/ + +#else /* TC956X_SRIOV_PF */ + #ifdef TC956X /* CPE usecase Configruations */ @@ -415,9 +1053,6 @@ enum packets_types { #define RX_QUEUE6_SIZE 0 #define RX_QUEUE7_SIZE 0 -#define MAX_RX_QUEUE_SIZE 47104 /* 46KB Maximun RX Queue size */ -#define MAX_TX_QUEUE_SIZE 47104 /* 46KB Maximun TX Queue size */ - /* * RX Queue 0: Unicast/Untagged Packets - Packets with * unique MAC Address of Host/Guest OS DMA channel selection will be based on @@ -502,23 +1137,24 @@ enum packets_types { #define TX_DMA_CH0_OWNER USE_IN_TC956X_SW #define TX_DMA_CH1_OWNER NOT_USED -#define TX_DMA_CH2_OWNER NOT_USED -#define TX_DMA_CH3_OWNER NOT_USED -#define TX_DMA_CH4_OWNER NOT_USED -#define TX_DMA_CH5_OWNER NOT_USED -#define TX_DMA_CH6_OWNER NOT_USED -#define TX_DMA_CH7_OWNER NOT_USED +#define TX_DMA_CH2_OWNER USE_IN_TC956X_SW +#define TX_DMA_CH3_OWNER USE_IN_TC956X_SW +#define TX_DMA_CH4_OWNER USE_IN_TC956X_SW +#define TX_DMA_CH5_OWNER USE_IN_TC956X_SW +#define TX_DMA_CH6_OWNER USE_IN_TC956X_SW +#define TX_DMA_CH7_OWNER USE_IN_TC956X_SW #define RX_DMA_CH0_OWNER USE_IN_TC956X_SW #define RX_DMA_CH1_OWNER NOT_USED -#define RX_DMA_CH2_OWNER NOT_USED -#define RX_DMA_CH3_OWNER NOT_USED -#define RX_DMA_CH4_OWNER NOT_USED -#define RX_DMA_CH5_OWNER NOT_USED -#define RX_DMA_CH6_OWNER NOT_USED -#define RX_DMA_CH7_OWNER NOT_USED +#define RX_DMA_CH2_OWNER USE_IN_TC956X_SW +#define RX_DMA_CH3_OWNER USE_IN_TC956X_SW +#define RX_DMA_CH4_OWNER USE_IN_TC956X_SW +#define RX_DMA_CH5_OWNER USE_IN_TC956X_SW +#define RX_DMA_CH6_OWNER USE_IN_TC956X_SW +#define RX_DMA_CH7_OWNER USE_IN_TC956X_SW #endif /* TC956X */ +#endif /* TC956X_SRIOV_PF */ /* PCI new class code */ #define PCI_ETHC_CLASS_CODE 0x020000 @@ -577,6 +1213,13 @@ enum packets_types { #define DBGPR_FUNC_ETHTOOL(x...) do { } while (0) #endif +#ifdef TC956X_SRIOV_VF +/* TC956X Semaphore lock/unlock register */ +#define NSEM(reg) (0x1100 + (reg * 4)) +/* TC956X Semaphore read register */ +#define NSEM_RD(reg) (0x1140 + (reg * 4)) + +#endif #define TC956X_DBG_FUNC #define TC956X_TEST @@ -674,8 +1317,8 @@ enum packets_types { #define SPEED_1GBPS (1000) /* 1Gbps Interms of MBPS */ #define SPEED_10GBPS (10000) /* 10Gbps Interms of MBPS */ -#define RSC_MNG_OFFSET 0x2000 -#define RSCMNG_ID_REG ((RSC_MNG_OFFSET) + 0x00000000) +//#define RSC_MNG_OFFSET 0x2000 +//#define RSCMNG_ID_REG ((RSC_MNG_OFFSET) + 0x00000000) #define RSCMNG_PFN GENMASK(3, 0) #define RSCMNG_PFN_SHIFT 0 @@ -685,6 +1328,17 @@ enum packets_types { #define NFUNCEN0_OFFSET (0x0008) /* TC956X pin mux control */ #define NPCIEBOOT_OFFSET (0x0018) /* TC956X PCIE Boot HW Sequence Status and Control */ +/* Pinmux for PPS Out PPO01 and PPO11*/ +#define NFUNCEN0_JTAGEN_MASK 0x40000000U +#define NFUNCEN0_JTAG_MASK 0x000F0000U +#define NFUNCEN0_JTAG_SHIFT 16U +#define FUNCTION1 0x1U +#define FUNCTION2 0x2U +#define NFUNCEN4_GPIO2_MASK 0x00000F00U +#define NFUNCEN4_GPIO2_SHIFT 8U +#define NFUNCEN4_GPIO4_MASK 0x000F0000 +#define NFUNCEN4_GPIO4_SHIFT 16U + #define NSYSDATA0_OFFSET (0x0100) #define NSYSDATA1_OFFSET (0x0104) @@ -733,13 +1387,24 @@ enum packets_types { NCLKCTRL1_MAC1RMCEN | NCLKCTRL0_MAC0ALLCLKEN) #define NCLKCTRL0_COMMON_EMAC_MASK (NCLKCTRL0_POEPLLCEN | NCLKCTRL0_SGMPCIEN | \ NCLKCTRL0_REFCLKOCEN) - -#define NRSTCTRL0_DEFAULT (NRSTCTRL0_MAC0PONRST| NRSTCTRL0_MAC0PMARST | \ - NRSTCTRL0_MSIGENRST | NRSTCTRL0_UART0RST | \ - NRSTCTRL0_MAC0RST | NRSTCTRL0_INTRST | \ - NRSTCTRL0_MCURST) -#define NCLKCTRL0_DEFAULT (NCLKCTRL0_SRMCEM | NCLKCTRL0_I2SSPIEN | \ +#define NRSTCTRL0_DEFAULT (NRSTCTRL0_MAC0PONRST | NRSTCTRL0_MAC0PMARST | \ + NRSTCTRL0_MAC0RST) +#define NRSTCTRL_COMMON (NRSTCTRL0_MSIGENRST | NRSTCTRL0_UART0RST | \ + NRSTCTRL0_INTRST | NRSTCTRL0_MCURST) +#define NCLKCTRL0_DEFAULT (NCLKCTRL0_SRMCEM | NCLKCTRL0_I2SSPIEN | \ NCLKCTRL0_PCIECEN | NCLKCTRL0_MCUCEN) +#define NCLKCTRL_ENABLE_COMMON_EMAC_MASK (NCLKCTRL0_SRMCEM | NCLKCTRL0_I2SSPIEN | \ + NCLKCTRL0_PCIECEN | NCLKCTRL0_MCUCEN) +#define NCLKCTRL_DISABLE_COMMON_EMAC_MASK (NCLKCTRL0_MAC0ALLCLKEN | NCLKCTRL0_MAC0312CLKEN | \ + NCLKCTRL0_MAC0125CLKEN | NCLKCTRL0_REFCLKOCEN | \ + NCLKCTRL0_SGMPCIEN | NCLKCTRL0_POEPLLCEN | \ + NCLKCTRL0_MSIGENCEN | NCLKCTRL0_UARTOCEN | \ + NCLKCTRL0_MAC0RXCEN | NCLKCTRL0_MAC0TXCEN | \ + NCLKCTRL0_INTCEN) +#define NCLKCTRL_PORT0_EMAC_MASK (NCLKCTRL0_MAC0TXCEN | NCLKCTRL0_MAC0RXCEN | \ + NCLKCTRL0_MAC0125CLKEN | NCLKCTRL0_MAC0312CLKEN | \ + NCLKCTRL0_MAC0ALLCLKEN) + #define NBUSCTRL_OFFSET (0x1014) #define NRSTCTRL_LINK_DOWN (NRSTCTRL0_MAC0PMARST | NRSTCTRL0_MAC0PONRST) @@ -751,6 +1416,12 @@ enum packets_types { #define NRSTCTRL_LINK_DOWN_CMN_SAVE (0x00051213U) /* Save Common Reset Register Bits Between Port 0 and Port 1 */ #define NCLKCTRL_LINK_DOWN_CMN_SAVE (0x07053211U) /* Save Common Clock Register Bits Between Port 0 and Port 1 */ +#define TC956X_MSIGENCEN 18 + +/* Interrupts to CM3 to be enabled in FW */ +#define TC956X_INT_MASK0 0xFFFF1FFF/*0x00000000*/ +#define TC956X_INT_MASK1 0xFFFF1F80/*0x00000000*/ +#define TC956X_INT_MASK2 0x00007740/*0x00000000*/ #endif #define NSPLLPARAM_OFFSET (0x1020) /* TC956X System PLL parameters */ @@ -767,6 +1438,113 @@ enum packets_types { #define NEMAC0CTL_OFFSET (0x1070) /* eMAC Port-0 Control */ #endif +#ifdef TC956X_SRIOV_PF +/* MSIGEN Registers */ + +#define MSI_INT_TX_CH0 3 +#define MSI_INT_RX_CH0 11 + +#define MSI_INT_EXT_PHY 20 + +#define TC956X_MSI_BASE (0xF000) + +#define TC956X_MSI_F_OFFSET (0x0100) +#define TC956X_MSI_OUT_EN_OFFSET(pf_id, vf_id) (TC956X_MSI_BASE +\ + (vf_id * TC956X_MSI_F_OFFSET) + (pf_id * TC956X_MSI_F_OFFSET) + (0x0000)) +#define TC956X_MSI_MASK_SET_OFFSET(pf_id, vf_id) (TC956X_MSI_BASE +\ + (vf_id * TC956X_MSI_F_OFFSET) + (pf_id * TC956X_MSI_F_OFFSET) + (0x0008)) +#define TC956X_MSI_INT_RAW_STS_OFFSET(pf_id, vf_id) (TC956X_MSI_BASE + \ + (vf_id * TC956X_MSI_F_OFFSET) + (pf_id * TC956X_MSI_F_OFFSET) + (0x0014)) +#define TC956X_MSI_STS_OFFSET(pf_id, vf_id) (TC956X_MSI_BASE + \ + (vf_id * TC956X_MSI_F_OFFSET) + (pf_id * TC956X_MSI_F_OFFSET) + (0x0018)) +#define TC956X_MSI_MASK_CLR_OFFSET(pf_id, vf_id) (TC956X_MSI_BASE +\ + (vf_id * TC956X_MSI_F_OFFSET) + (pf_id * TC956X_MSI_F_OFFSET) + (0x000c)) +#define TC956X_MSI_INT_STS_OFFSET(pf_id, vf_id) (TC956X_MSI_BASE +\ + (vf_id * TC956X_MSI_F_OFFSET) + (pf_id * TC956X_MSI_F_OFFSET) + (0x0010)) +#define TC956X_MSI_VECT_SET0_OFFSET(pf_id, vf_id) (TC956X_MSI_BASE +\ + (vf_id * TC956X_MSI_F_OFFSET) + (pf_id * TC956X_MSI_F_OFFSET) + (0x0020)) +#define TC956X_MSI_VECT_SET1_OFFSET(pf_id, vf_id) (TC956X_MSI_BASE +\ + (vf_id * TC956X_MSI_F_OFFSET) + (pf_id * TC956X_MSI_F_OFFSET) + (0x0024)) +#define TC956X_MSI_VECT_SET2_OFFSET(pf_id, vf_id) (TC956X_MSI_BASE +\ + (vf_id * TC956X_MSI_F_OFFSET) + (pf_id * TC956X_MSI_F_OFFSET) + (0x0028)) +#define TC956X_MSI_VECT_SET3_OFFSET(pf_id, vf_id) (TC956X_MSI_BASE +\ + (vf_id * TC956X_MSI_F_OFFSET) + (pf_id * TC956X_MSI_F_OFFSET) + (0x002C)) +#define TC956X_MSI_VECT_SET4_OFFSET(pf_id, vf_id) (TC956X_MSI_BASE +\ + (vf_id * TC956X_MSI_F_OFFSET) + (pf_id * TC956X_MSI_F_OFFSET) + (0x0030)) +#define TC956X_MSI_VECT_SET5_OFFSET(pf_id, vf_id) (TC956X_MSI_BASE +\ + (vf_id * TC956X_MSI_F_OFFSET) + (pf_id * TC956X_MSI_F_OFFSET) + (0x0034)) +#define TC956X_MSI_VECT_SET6_OFFSET(pf_id, vf_id) (TC956X_MSI_BASE +\ + (vf_id * TC956X_MSI_F_OFFSET) + (pf_id * TC956X_MSI_F_OFFSET) + (0x0038)) +#define TC956X_MSI_VECT_SET7_OFFSET(pf_id, vf_id) (TC956X_MSI_BASE +\ + (vf_id * TC956X_MSI_F_OFFSET) + (pf_id * TC956X_MSI_F_OFFSET) + (0x003C)) +#define TC956X_MSI_SW_MSI_CLR(pf_id, vf_id) (TC956X_MSI_BASE +\ + (vf_id * TC956X_MSI_F_OFFSET) + (pf_id * TC956X_MSI_F_OFFSET) + (0x0054)) +#define TC956X_MSI_EVENT_OFFSET(pf_id, vf_id) (TC956X_MSI_BASE +\ + (vf_id * TC956X_MSI_F_OFFSET) + (pf_id * TC956X_MSI_F_OFFSET) + (0x0068)) + +#define TC956X_MSI_CNT0(pf_id, vf_id) (TC956X_MSI_BASE +\ + (vf_id * TC956X_MSI_F_OFFSET) + (pf_id * TC956X_MSI_F_OFFSET) + (0x0080)) +#define TC956X_MSI_CNT1(pf_id, vf_id) (TC956X_MSI_BASE +\ + (vf_id * TC956X_MSI_F_OFFSET) + (pf_id * TC956X_MSI_F_OFFSET) + (0x0084)) +#define TC956X_MSI_CNT2(pf_id, vf_id) (TC956X_MSI_BASE +\ + (vf_id * TC956X_MSI_F_OFFSET) + (pf_id * TC956X_MSI_F_OFFSET) + (0x0088)) +#define TC956X_MSI_CNT3(pf_id, vf_id) (TC956X_MSI_BASE +\ + (vf_id * TC956X_MSI_F_OFFSET) + (pf_id * TC956X_MSI_F_OFFSET) + (0x008C)) +#define TC956X_MSI_CNT4(pf_id, vf_id) (TC956X_MSI_BASE +\ + (vf_id * TC956X_MSI_F_OFFSET) + (pf_id * TC956X_MSI_F_OFFSET) + (0x0090)) +#define TC956X_MSI_CNT11(pf_id, vf_id) (TC956X_MSI_BASE +\ + (vf_id * TC956X_MSI_F_OFFSET) + (pf_id * TC956X_MSI_F_OFFSET) + (0x00AC)) +#define TC956X_MSI_CNT12(pf_id, vf_id) (TC956X_MSI_BASE +\ + (vf_id * TC956X_MSI_F_OFFSET) + (pf_id * TC956X_MSI_F_OFFSET) + (0x00B0)) +#define TC956X_MSI_CNT20(pf_id, vf_id) (TC956X_MSI_BASE +\ + (vf_id * TC956X_MSI_F_OFFSET) + (pf_id * TC956X_MSI_F_OFFSET) + (0x00D0)) +#define TC956X_MSI_CNT24(pf_id, vf_id) (TC956X_MSI_BASE +\ + (vf_id * TC956X_MSI_F_OFFSET) + (pf_id * TC956X_MSI_F_OFFSET) + (0x00E0)) + +#define TC956X_MSI_OUT_EN_CLR (0x00000000) + +/* Enabled LPI_INT, EVENT_INT, TX_INT[3], TX_INT[4], RX_INT[3], RX_INT[4] + * XPCS_INT, PFMAILBOX_INT + * INT 6, 7, 14, 15 is allocated to MSI Vector 1. + * All other enabled INT to Vector 0. + */ + +#if defined(TC956X_AUTOMOTIVE_CONFIG) +#ifdef TC956X_LPI_INTERRUPT +#define TC956X_MSI_OUT_EN (0x0017FFFD) +#else /* #ifdef TC956X_LPI_INTERRUPT */ +#define TC956X_MSI_OUT_EN (0x0017FFFC) +#endif /* #ifdef TC956X_LPI_INTERRUPT */ +#else /* #if defined(TC956X_AUTOMOTIVE_CONFIG) */ +#define TC956X_MSI_OUT_EN (0x0037FFFD) +#endif /* #if defined(TC956X_AUTOMOTIVE_CONFIG) */ + +#if defined(TC956X_AUTOMOTIVE_CONFIG) || defined(TC956X_ENABLE_MAC2MAC_BRIDGE) +#define TC956X_MSI_MASK_SET (0xFFFFFFFE) +#define TC956X_MSI_MASK_CLR (0x00000001) +#define TC956X_MSI_SET0 (0x00000000) +#define TC956X_MSI_SET1 (0x00000000) +#define TC956X_MSI_SET2 (0x00000000) +#define TC956X_MSI_SET3 (0x00000000) +#define TC956X_MSI_SET4 (0x00000000) +#define TC956X_MSI_SET5 (0x00000000) +#define TC956X_MSI_SET6 (0x00000000) +#define TC956X_MSI_SET7 (0x00000000) +#else +#define TC956X_MSI_MASK_SET (0xFFFFFFFC) +#define TC956X_MSI_MASK_CLR (0x00000003) +#define TC956X_MSI_SET0 (0x00010101) +#define TC956X_MSI_SET1 (0x00000000) +#define TC956X_MSI_SET2 (0x00000000) +#define TC956X_MSI_SET3 (0x00000000) +#define TC956X_MSI_SET4 (0x01000000) +#define TC956X_MSI_SET5 (0x01010101) +#define TC956X_MSI_SET6 (0x01010101) +#define TC956X_MSI_SET7 (0x01010101) +#endif + +#endif /* TC956X_SRIOV_PF */ + #define NEMAC1CTL_OFFSET (0x1074) /* eMAC Port-1 Control */ #define NEMACSTS_OFFSET (0x1078) /* eMAC status */ #define NEMACIOCTL_OFFSET (0x107C) /* eMAC IO Control */ @@ -848,6 +1626,12 @@ enum packets_types { #define GPIO_12 (12) #define GPIO_32 (32) +#define TRIG00_SHIFT 4 +#define TRIG10_SHIFT 12 +#define TRIG00_MASK 0xF0 +#define TRIG10_MASK 0xF000 +#define TSIE_SHIFT 12 + /* PCIe registers */ #define PCIE_OFFSET (0x20000) #define PCIE_RANGE_UP_OFFSET_RgOffAddr(no) (PCIE_OFFSET + 0x6200 + (no*0x10)) @@ -896,6 +1680,7 @@ enum packets_types { #ifdef TC956X +#define TC956X_ETH_XPCS_INT BIT(19) #define TC956X_EXT_PHY_ETH_INT BIT(20) #ifdef TC956X_SW_MSI @@ -917,6 +1702,10 @@ enum packets_types { + 0x00000850U) #define TC956X_SSREG_K_PCICONF_031_016 (TC956X_SSREG_BRREG_REG_BASE \ + 0x00000854U) +#define TC956X_SSREG_K_PCICONF_021_021 (TC956X_SSREG_BRREG_REG_BASE \ + + 0x000009E4U) +#define TC956X_SSREG_K_PCICONF_022_022 (TC956X_SSREG_BRREG_REG_BASE \ + + 0x000009E8U) #define TC956X_GLUE_EFUSE_CTRL (TC956X_GLUE_LOGIC_BASE_OFST \ + 0x0000001CU) @@ -930,6 +1719,8 @@ enum packets_types { + 0x0000006CU) #define TC956X_GLUE_SW_DSP2_TEST_IN_31_00 (TC956X_GLUE_LOGIC_BASE_OFST \ + 0x00000074U) +#define TC956X_GLUE_SW_USP_TEST_OUT_127_096 (TC956X_GLUE_LOGIC_BASE_OFST \ + + 0x00000098U) #define TC956X_GLUE_TL_LINK_SPEED_MON (TC956X_GLUE_LOGIC_BASE_OFST \ + 0x00000244U) #define TC956X_GLUE_TL_NUM_LANES_MON (TC956X_GLUE_LOGIC_BASE_OFST \ @@ -1061,10 +1852,18 @@ entry delay = n * 256 ns */ #define TC956X_PHY_CORE1_MISC_RW0_R2 (TC956X_PHY_CORE1_REG_BASE \ + 0x000002C8U) +#define TC956X_GLUE_LTSSM_STATE_MASK (0x0000001FU) +#define TC956X_GLUE_LTSSM_STATE_SHIFT (0) +#define TC956X_GLUE_DLL_MASK (0x00000020U) +#define TC956X_GLUE_DLL_SHIFT (5) +#define TC956X_GLUE_SPEED_MASK(x) (0x0000000FU << (8*x)) +#define TC956X_GLUE_SPEED_SHIFT(x) (8*x) #define USP_LANE_WIDTH_MASK (0x0000003F) #define DSP1_LANE_WIDTH_MASK (0x00003F00) #define DSP1_LANE_WIDTH_SHIFT (8) +#define TC956X_GLUE_LANE_WIDTH_MASK(x) (0x0000003FU << (8*x)) +#define TC956X_GLUE_LANE_WIDTH_SHIFT(x) (8*x) #define USP_LINK_WIDTH_CHANGE_4_TO_1 (0x00000010) #define USP_LINK_WIDTH_CHANGE_4_TO_2 (0x00000011) @@ -1075,6 +1874,7 @@ entry delay = n * 256 ns */ #define DSP1_LINK_WIDTH_CHANGE_1_TO_2 (0x00110000) #define SW_PORT_ENABLE_MASK GENMASK(3, 0) +#define SW_PORT_ENABLE_SHIFT 0U #define SW_USP_ENABLE (0x00000001) #define SW_DSP1_ENABLE (0x00000002) #define SW_DSP2_ENABLE (0x00000004) @@ -1098,7 +1898,10 @@ entry delay = n * 256 ns */ #define POWER_CTL_OVER_ENABLE 0x00000001 #define PC_DEBUG_P1_TOGGLE 0x00000001 +#define ENABLE_CUT_THROUGH_ON_RX_PATH_MASK 0x1U +#define ENABLE_CUT_THROUGH_ON_TX_PATH_MASK 0x1U #endif + /* MSIGEN Registers */ #define MSI_INT_TX_CH0 3 @@ -1109,75 +1912,97 @@ entry delay = n * 256 ns */ #define MSI_INT_SW_MSI 24 #endif -#define TC956X_MSI_BASE (0xF000) -#define TC956X_MSI_PF0 (0x000) -#ifdef TC956X -#define TC956X_MSI_PF1 (0x100) -#else -#define TC956X_MSI_PF1 (0x000) +#ifdef TC956X_SRIOV_VF //VF_DRV related +#define TC956X_MSIGENCEN 18 + +/* MSIGEN Registers */ +#define TC956X_MSI_BASE (0xF000) +#define TC956X_MSI_PF0 (0x0000) +#define TC956X_MSI_PF1 (0x0100) + +#define TC956X_MSI_OUT_EN_OFFSET(pf_id, vf_id) (TC956X_MSI_BASE +\ + TC956X_MSI_PF1 + (vf_id * 0x100) + (pf_id * 0x300) + (0x0000)) +#define TC956X_MSI_MASK_SET_OFFSET(pf_id, vf_id) (TC956X_MSI_BASE +\ + TC956X_MSI_PF1 + (vf_id * 0x100) + (pf_id * 0x300) + (0x0008)) +#define TC956X_MSI_MASK_CLR_OFFSET(pf_id, vf_id) (TC956X_MSI_BASE +\ + TC956X_MSI_PF1 + (vf_id * 0x100) + (pf_id * 0x300) + (0x000c)) +#define TC956X_MSI_VECT_SET0_OFFSET(pf_id, vf_id) (TC956X_MSI_BASE +\ + TC956X_MSI_PF1 + (vf_id * 0x100) + (pf_id * 0x300) + (0x0020)) +#define TC956X_MSI_VECT_SET1_OFFSET(pf_id, vf_id) (TC956X_MSI_BASE +\ + TC956X_MSI_PF1 + (vf_id * 0x100) + (pf_id * 0x300) + (0x0024)) +#define TC956X_MSI_VECT_SET2_OFFSET(pf_id, vf_id) (TC956X_MSI_BASE +\ + TC956X_MSI_PF1 + (vf_id * 0x100) + (pf_id * 0x300) + (0x0028)) +#define TC956X_MSI_VECT_SET3_OFFSET(pf_id, vf_id) (TC956X_MSI_BASE +\ + TC956X_MSI_PF1 + (vf_id * 0x100) + (pf_id * 0x300) + (0x002C)) +#define TC956X_MSI_VECT_SET4_OFFSET(pf_id, vf_id) (TC956X_MSI_BASE +\ + TC956X_MSI_PF1 + (vf_id * 0x100) + (pf_id * 0x300) + (0x0030)) +#define TC956X_MSI_VECT_SET5_OFFSET(pf_id, vf_id) (TC956X_MSI_BASE +\ + TC956X_MSI_PF1 + (vf_id * 0x100) + (pf_id * 0x300) + (0x0034)) +#define TC956X_MSI_VECT_SET6_OFFSET(pf_id, vf_id) (TC956X_MSI_BASE +\ + TC956X_MSI_PF1 + (vf_id * 0x100) + (pf_id * 0x300) + (0x0038)) +#define TC956X_MSI_VECT_SET7_OFFSET(pf_id, vf_id) (TC956X_MSI_BASE +\ + TC956X_MSI_PF1 + (vf_id * 0x100) + (pf_id * 0x300) + (0x003C)) + +#define TC956X_MSI_EVENT_OFFSET(pf_id, vf_id) (TC956X_MSI_BASE +\ + TC956X_MSI_PF1 + (vf_id * 0x100) + (pf_id * 0x300) + (0x0068)) + + +#define TC956X_MSI_OUT_EN_CLR (0x00000000) +/* Enabled LPI_INT, EVENT_INT, TX_INT[3], TX_INT[4], RX_INT[3], RX_INT[4] + * XPCS_INT, PFMAILBOX_INT + */ +//#define TC956X_MSI_OUT_EN (0x0028C0C5) +#define TC956X_MSI_OUT_EN (0x0027FFF8) + + +#define TC956X_MSI_MASK_SET (0xFFFFFFFE) +#define TC956X_MSI_MASK_CLR (0x00000001) +#define TC956X_MSI_SET0 (0x00000000) +#define TC956X_MSI_SET1 (0x00000000) +#define TC956X_MSI_SET2 (0x00000000) +#define TC956X_MSI_SET3 (0x00000000) +#define TC956X_MSI_SET4 (0x00000000) +#define TC956X_MSI_SET5 (0x00000000) +#define TC956X_MSI_SET6 (0x00000000) +#define TC956X_MSI_SET7 (0x00000000) + +#define TC956X_MSI_INT_TXDMA_CH0 (3) +#define TC956X_MSI_INT_RXDMA_CH0 (11) +#define TC956X_MSI_INT_MBX (21) + +#endif // #ifdef TC956X_SRIOV_VF + +#if defined(TC956X_AUTOMOTIVE_CONFIG) +#define CLASS_B_CH 5 /* Class B Queue */ +#define CLASS_CDT_CH 7 /* CDT Queue */ #endif -#ifdef TC956X_LPI_INTERRUPT -#define ENABLE_MSI_INTR (0x17FFFD) +#if defined(TC956X_SRIOV_PF) && !defined(TC956X_AUTOMOTIVE_CONFIG) && !defined(TC956X_ENABLE_MAC2MAC_BRIDGE) +#define HOST_BEST_EFF_CH 3 /* Best effort traffic Queue*/ +#define UNTAGGED_PTP_CH 4 /* Untagged PTP Queue */ +#define CLASS_B_CH 5 /* Class B Queue */ +#define CLASS_A_CH 6 /* Class A Queue */ +#define CLASS_CDT_CH 7 /* CDT Queue */ + +#define TC956X_GPTP_TX_CH UNTAGGED_PTP_CH +/* All data is redirected to Legacy Channel for SRIOV Usecase */ +#define LEGACY_VLAN_TAGGED_CH HOST_BEST_EFF_CH +#define AVB_CLASS_B_TX_CH HOST_BEST_EFF_CH +#define AVB_CLASS_A_TX_CH HOST_BEST_EFF_CH +#define TSN_CLASS_CDT_TX_CH HOST_BEST_EFF_CH + +#elif defined(TC956X_SRIOV_PF) && (defined(TC956X_AUTOMOTIVE_CONFIG) || defined(TC956X_ENABLE_MAC2MAC_BRIDGE)) +#define HOST_BEST_EFF_CH 0 /* Legacy channel is best effort traffic */ +#define LEGACY_VLAN_TAGGED_CH 0 /* Legacy VLAN tagged queue */ +#define TC956X_GPTP_TX_CH 4 /* gPTP Tx Channel */ +#define AVB_CLASS_B_TX_CH 5 /* AVB Class B Qeuue */ +#define AVB_CLASS_A_TX_CH 6 /* AVB Class A Qeuue */ +#define TSN_CLASS_CDT_TX_CH 7 /* Express Control Traffic */ + #else -#define ENABLE_MSI_INTR (0x17FFFC) -#endif - -#define TC956X_MSI_OUT_EN_OFFSET(pf_id) (TC956X_MSI_BASE + \ - (pf_id * TC956X_MSI_PF1) + (0x0000)) -#define TC956X_MSI_INT_STS_OFFSET(pf_id) (TC956X_MSI_BASE + \ - (pf_id * TC956X_MSI_PF1) + (0x0010)) - -#define TC956X_MSI_INT_RAW_STS_OFFSET(pf_id) (TC956X_MSI_BASE + \ - (pf_id * TC956X_MSI_PF1) + (0x0014)) -#define TC956X_MSI_STS_OFFSET(pf_id) (TC956X_MSI_BASE + \ - (pf_id * TC956X_MSI_PF1) + (0x0018)) -#define TC956X_MSI_MASK_SET_OFFSET(pf_id) (TC956X_MSI_BASE +\ - (pf_id * TC956X_MSI_PF1) + (0x0008)) -#define TC956X_MSI_MASK_CLR_OFFSET(pf_id) (TC956X_MSI_BASE +\ - (pf_id * TC956X_MSI_PF1) + (0x000c)) -#define TC956X_MSI_VECT_SET0_OFFSET(pf_id) (TC956X_MSI_BASE +\ - (pf_id * TC956X_MSI_PF1) + (0x0020)) -#define TC956X_MSI_VECT_SET1_OFFSET(pf_id) (TC956X_MSI_BASE +\ - (pf_id * TC956X_MSI_PF1) + (0x0024)) -#define TC956X_MSI_VECT_SET2_OFFSET(pf_id) (TC956X_MSI_BASE +\ - (pf_id * TC956X_MSI_PF1) + (0x0028)) -#define TC956X_MSI_VECT_SET3_OFFSET(pf_id) (TC956X_MSI_BASE +\ - (pf_id * TC956X_MSI_PF1) + (0x002C)) -#define TC956X_MSI_VECT_SET4_OFFSET(pf_id) (TC956X_MSI_BASE +\ - (pf_id * TC956X_MSI_PF1) + (0x0030)) -#define TC956X_MSI_VECT_SET5_OFFSET(pf_id) (TC956X_MSI_BASE +\ - (pf_id * TC956X_MSI_PF1) + (0x0034)) -#define TC956X_MSI_VECT_SET6_OFFSET(pf_id) (TC956X_MSI_BASE +\ - (pf_id * TC956X_MSI_PF1) + (0x0038)) -#define TC956X_MSI_VECT_SET7_OFFSET(pf_id) (TC956X_MSI_BASE +\ - (pf_id * TC956X_MSI_PF1) + (0x003C)) -#define TC956X_MSI_SW_MSI_SET(pf_id) (TC956X_MSI_BASE +\ - (pf_id * TC956X_MSI_PF1) + (0x0050)) -#define TC956X_MSI_SW_MSI_CLR(pf_id) (TC956X_MSI_BASE +\ - (pf_id * TC956X_MSI_PF1) + (0x0054)) -#define TC956X_MSI_EVENT_OFFSET(pf_id) (TC956X_MSI_BASE +\ - (pf_id * TC956X_MSI_PF1) + (0x0068)) -#define TC956X_MSI_CNT0(pf_id) (TC956X_MSI_BASE +\ - (pf_id * TC956X_MSI_PF1) + (0x0080)) -#define TC956X_MSI_CNT1(pf_id) (TC956X_MSI_BASE +\ - (pf_id * TC956X_MSI_PF1) + (0x0084)) -#define TC956X_MSI_CNT2(pf_id) (TC956X_MSI_BASE +\ - (pf_id * TC956X_MSI_PF1) + (0x0088)) -#define TC956X_MSI_CNT3(pf_id) (TC956X_MSI_BASE +\ - (pf_id * TC956X_MSI_PF1) + (0x008C)) -#define TC956X_MSI_CNT4(pf_id) (TC956X_MSI_BASE +\ - (pf_id * TC956X_MSI_PF1) + (0x0090)) -#define TC956X_MSI_CNT11(pf_id) (TC956X_MSI_BASE +\ - (pf_id * TC956X_MSI_PF1) + (0x00AC)) -#define TC956X_MSI_CNT12(pf_id) (TC956X_MSI_BASE +\ - (pf_id * TC956X_MSI_PF1) + (0x00B0)) -#define TC956X_MSI_CNT20(pf_id) (TC956X_MSI_BASE +\ - (pf_id * TC956X_MSI_PF1) + (0x00D0)) -#define TC956X_MSI_CNT24(pf_id) (TC956X_MSI_BASE +\ - (pf_id * TC956X_MSI_PF1) + (0x00E0)) - #ifdef TC956X + +#ifndef TC956X_SRIOV_VF /* CPE usecase only TxCH 0 is applicable */ #define HOST_BEST_EFF_CH 0 /* Legacy channel is best effort traffic */ #define LEGACY_VLAN_TAGGED_CH 0 /* Legacy VLAN tagged queue */ @@ -1186,6 +2011,8 @@ entry delay = n * 256 ns */ #define AVB_CLASS_A_TX_CH 0 /* AVB Class A Qeuue */ #define TSN_CLASS_CDT_TX_CH 0 /* Express Control Traffic */ #endif +#endif +#endif /* Scale factor for the CBS calculus */ #define AVB_CBS_SCALE 1024 @@ -1193,11 +2020,11 @@ entry delay = n * 256 ns */ #define TC956X_HOST_PHYSICAL_ADRS_MASK (0x10) /* bit no 37: (1<<36) */ #define ETHNORMAL_LEN 1500 -/*Max supported MTU limited to 2000, not 'ETH_FRAME_LEN + ETH_FCS_LEN + VLAN_HLEN' */ -#define MAX_SUPPORTED_MTU 2000 /*(ETH_FRAME_LEN + ETH_FCS_LEN + VLAN_HLEN)*/ +#define MAX_SUPPORTED_MTU (ETH_FRAME_LEN + ETH_FCS_LEN + VLAN_HLEN) #define MIN_SUPPORTED_MTU (ETH_ZLEN + ETH_FCS_LEN + VLAN_HLEN) #define HOST_MAC_ADDR_OFFSET 2 +#define HOST_BC_ADDR_OFFSET 0 #endif /* End of TC956X Define */ @@ -1206,9 +2033,17 @@ entry delay = n * 256 ns */ #define DMA_RX_SIZE 512 #define TC956XMAC_GET_ENTRY(x, size) ((x + 1) & (size - 1)) +/* default DMA channel for TC */ +#if defined(TC956X_SRIOV_PF) && !defined(TC956X_AUTOMOTIVE_CONFIG) && !defined(TC956X_ENABLE_MAC2MAC_BRIDGE) +#define TC956X_TC_DEFAULT_DMA_CH (0x1 << 3) +#else +#define TC956X_TC_DEFAULT_DMA_CH (0x1 << 0) +#endif + #undef FRAME_FILTER_DEBUG /* #define FRAME_FILTER_DEBUG */ +#define TOTAL_VF 3 /* Extra statistic and debug information exposed by ethtool */ struct tc956xmac_extra_stats { /* Transmit errors */ @@ -1364,6 +2199,13 @@ struct tc956xmac_extra_stats { u64 rxch_desc_buf_laddr[TC956XMAC_CH_MAX]; u64 rxch_sw_cur_rx[TC956XMAC_CH_MAX]; u64 rxch_sw_dirty_rx[TC956XMAC_CH_MAX]; +#ifdef TC956X_SRIOV_PF + u64 mbx_pf_sent_vf[TOTAL_VF]; + u64 mbx_pf_rcvd_vf[TOTAL_VF]; +#else + u64 mbx_vf_sent_pf; + u64 mbx_vf_rcvd_pf; +#endif /*debug interrupt counters */ u64 total_interrupts; @@ -1417,6 +2259,72 @@ struct tc956xmac_safety_stats { unsigned long dma_errors[32]; }; +#ifdef TC956X_SRIOV_VF +struct tc956x_sw_counters { + u64 tx_frame_count_good_bad; + u64 rx_frame_count_good_bad; + u64 rx_frame_count_good; + u64 rx_fame_count_bad; + u64 rx_packet_good_octets; + u64 rx_header_good_octets; + u64 rx_av_tagged_datapacket_count; + u64 rx_av_tagged_controlpacket_count; + u64 rx_nonav_packet_count; + u64 rx_tunnel_packet_count; + u64 rx_non_ip_pkt_count; + u64 rx_ipv4_tcp_pkt_count; + u64 rx_ipv4_udp_pkt_count; + u64 rx_ipv4_icmp_pkt_count; + u64 rx_ipv4_igmp_pkt_count; + u64 rx_ipv4_unkown_pkt_count; + u64 rx_ipv6_tcp_pkt_count; + u64 rx_ipv6_udp_pkt_count; + u64 rx_ipv6_icmp_pkt_count; + u64 rx_ipv6_unkown_pkt_count; + u64 rx_err_wd_timeout_count; + u64 rx_err_gmii_inv_count; + u64 rx_err_crc_count; + u64 rx_err_giant_count; + u64 rx_err_checksum_count; + u64 rx_err_overflow_count; + u64 rx_err_bus_count; + u64 rx_err_pkt_len_count; + u64 rx_err_runt_pkt_count; + u64 rx_err_dribble_count; + u64 rx_err_t_out_ip_header_count; + u64 rx_err_t_out_ip_pl_l4_csum_count; + u64 rx_err_t_in_ip_header_count; + u64 rx_err_t_in_ip_pl_l4_csum_count; + u64 rx_err_t_invalid_vlan_header; + u64 rx_l2_len_pkt_count; + u64 rx_l2_mac_control_pkt_count; + u64 rx_l2_dcb_control_pkt_count; + u64 rx_l2_arp_pkt_count; + u64 rx_l2_oam_type_pkt_count; + u64 rx_l2_untg_typ_match_pkt_count; + u64 rx_l2_other_type_pkt_count; + u64 rx_l2_single_svlan_pkt_count; + u64 rx_l2_single_cvlan_pkt_count; + u64 rx_l2_d_cvlan_cvlan_pkt_count; + u64 rx_l2_d_svlan_svlan_pkt_count; + u64 rx_l2_d_svlan_cvlan_pkt_count; + u64 rx_l2_d_cvlan_svlan_pkt_count; + u64 rx_l2_untg_av_control_pkt_count; + u64 rx_ptp_no_msg; + u64 rx_ptp_msg_type_sync; + u64 rx_ptp_msg_type_follow_up; + u64 rx_ptp_msg_type_delay_req; + u64 rx_ptp_msg_type_delay_resp; + u64 rx_ptp_msg_type_pdelay_req; + u64 rx_ptp_msg_type_pdelay_resp; + u64 rx_ptp_msg_type_pdelay_follow_up; + u64 rx_ptp_msg_type_announce; + u64 rx_ptp_msg_type_management; + u64 rx_ptp_msg_pkt_signaling; + u64 rx_ptp_msg_pkt_reserved_type; +}; +#endif //#ifdef TC956X_SRIOV_VF + struct tc956x_mac_addr { u8 mac_address[6]; u8 status; @@ -1542,6 +2450,98 @@ enum dma_irq_status { handle_tx = 0x8, }; +#ifdef TC956X_SRIOV_VF + +#define MBX_MSG_OFST 4 /* First 4 bytes for ACK management */ +#define MBX_MSG_SIZE 60 /* Excluding ACK */ +#define MBX_ACK_SIZE 4 /* ACK management */ +#define MBX_TOT_SIZE (MBX_MSG_SIZE + MBX_ACK_SIZE) + +#define ACK 0x01 +#define NACK 0x02 + +/* Mailbox opcode definitions */ +#define OPCODE_MBX_ADD_MAC_ADDR 0x01 +#define OPCODE_MBX_SET_TX_Q_WEIGHT 0x02 +#define OPCODE_MBX_CFG_CBS 0x03 +#define OPCODE_MBX_SET_TX_Q_PRIOR 0x04 +#define OPCODE_MBX_RESET_EEE_MODE 0x05 +#define OPCODE_MBX_VF_IOCTL 0x06 +#define OPCODE_MBX_VF_ETHTOOL 0x07 +#define OPCODE_MBX_VF_ADD_MAC 0x08 +#define OPCODE_MBX_VF_DELETE_MAC 0x09 +#define OPCODE_MBX_VF_ADD_VLAN 0x10 +#define OPCODE_MBX_VF_DELETE_VLAN 0x11 +#define OPCODE_MBX_SET_DMA_TX_MODE 0x12 +#define OPCODE_MBX_VF_GET_LINK_STATUS 0x13 +#define OPCODE_MBX_PHY_LINK 0x14 +#define OPCODE_MBX_SETUP_CBS 0x15 +#define OPCODE_MBX_RX_CRC 0x16 +#define OPCODE_MBX_RX_CSUM 0x17 +#define OPCODE_MBX_DRV_CAP 0x18 +#define OPCODE_MBX_VF_GET_PAUSE_PARAM 0x19 +#define OPCODE_MBX_VF_GET_EEE 0x20 +#define OPCODE_MBX_VF_GET_TS_INFO 0x22 +#define OPCODE_MBX_VF_GET_MII_PHY 0x23 +#define OPCODE_MBX_VF_GET_PAUSE_PARAM_2 0x24 +#define OPCODE_MBX_GET_UMAC_ADDR 0x25 +#define OPCODE_VF_RESET 0x26 +#define OPCODE_MBX_DMA_CH_TLPTR 0x29 +#define OPCODE_MBX_SETUP_ETF 0x30 +#define OPCODE_MBX_FLR 0x33 +#define OPCODE_MBX_DMA_ERR 0x34 +#define OPCODE_MBX_ACK_MSG 0xFF + +#define SIZE_MBX_SET_TX_Q_WEIGHT 8 +#define SIZE_MBX_CFG_CBS 20 +#define SIZE_MBX_SETUP_ETF 5 +#define SIZE_MBX_SETUP_CBS 21 +#define SIZE_MBX_CFG_EST 56 +#define SIZE_MBX_CFG_FPE 20 +#define SIZE_MBX_SET_TX_Q_PRIOR 8 +#define SIZE_MBX_SET_DMA_TX_MODE 13 +#define SIZE_MBX_VF_GET_LINK_STATUS 0 +#define SIZE_MBX_PHY_LINK 12 +#define SIZE_MBX_RX_CRC 4 +#define SIZE_MBX_RX_CSUM 4 +#define SIZE_MBX_DRV_CAP 4 +#define SIZE_SET_UMAC_ADDR 10 +#define SIZE_GET_UMAC_ADDR 4 +#define SIZE_MBX_VF_MAC 6 +#define SIZE_MBX_VF_VLAN 2 +#define SIZE_MBX_VF_REG_WR 13 +#define SIZE_MBX_VF_SPEED 1 +#define SIZE_MBX_SET_GET_CBS_1 56 +#define SIZE_MBX_SET_GET_CBS_2 44 +#define SIZE_MBX_SET_GET_EST_1 56 +#define SIZE_MBX_SET_GET_RXP_1 56 +#define SIZE_MBX_SET_GET_FPE_1 20 +#define SIZE_MBX_VF_GET_CBS 2 +#define SIZE_MBX_VF_PAUSE_PARAM 1 +#define SIZE_MBX_VF_EEE 1 +#define SIZE_MBX_VF_TS_INFO 1 +#define SIZE_VF_RESET 1 +#define SIZE_MBX_VF_TIMESTAMP 2 +#define SIZE_MBX_VF_GET_EST 1 +#define SIZE_MBX_VF_GET_RXP 1 +#define SIZE_MBX_VF_GET_FPE 1 +#define SIZE_MBX_VF_GET_MII_REG 23 +#define SIZE_MBX_RX_DMA_TL_PTR 4 +#define SIZE_MBX_GET_HW_STMP 12 + +#define MAX_SIZE_GCL_MSG 14 +#define EST_FIX_MSG_LEN 28 +#define RXP_FIX_MSG_LEN 16 +#define VF_UP 1 +#define VF_DOWN 0 +#define VF_SUSPEND 2 +#define VF_RELEASE 3 + +#define SCH_WQ_PF_FLR 1 +#define SCH_WQ_RX_DMA_ERR 2 +#define SCH_WQ_LINK_STATE_UP 3 +#endif /* #ifdef TC956X_SRIOV_VF */ + /* EEE and LPI defines */ #define CORE_IRQ_TX_PATH_IN_LPI_MODE (1 << 0) #define CORE_IRQ_TX_PATH_EXIT_LPI_MODE (1 << 1) @@ -1676,9 +2676,22 @@ struct dma_features { #define TC956X_TWO 2 #define TC956X_THREE 3 #define TC956X_FOUR 4 +#define TC956X_FIVE 5 +#define TC956X_SIX 6 +#define TC956X_SEVEN 7 #define TC956X_EIGHT 8 +#define TC956X_NINE 9 +#define TC956X_TEN 10 #define TC956X_SIXTEEN 16 #define TC956X_TWENTY_FOUR 24 +#define TC956X_FORTY_EIGHT 48 +#define TC956X_FORTY_NINE 49 + +/* EEPROM Mac address mask values */ +#define EEPROM_MAC_ADDR_MASK1 0x000000FF +#define EEPROM_MAC_ADDR_MASK2 0x0000FF00 +#define EEPROM_MAC_ADDR_MASK3 0x00FF0000 +#define EEPROM_MAC_ADDR_MASK4 0xFF000000 #define TC956X_MIN_LPI_AUTO_ENTRY_TIMER 0 #define TC956X_MAX_LPI_AUTO_ENTRY_TIMER 0xFFFF8 /* LPI Entry timer is in the units of 8 micro second granularity. So mask the last 3 bits. */ @@ -1723,6 +2736,17 @@ struct mac_device_info { const struct tc956xmac_mode_ops *mode; const struct tc956xmac_hwtimestamp *ptp; const struct tc956xmac_tc_ops *tc; + const struct tc956x_msi_ops *msi; +#ifdef TC956X_SRIOV_PF + const struct mac_rsc_mng_ops *rsc; + const struct mac_mbx_ops *mbx; + const struct tc956x_mbx_wrapper_ops *mbx_wrapper; +#endif +#ifdef TC956X_SRIOV_VF + const struct mac_rsc_mng_ops *rsc; + const struct mac_mbx_ops *mbx; + const struct tc956xmac_mbx_wrapper_ops *mbx_wrapper; +#endif const struct tc956xmac_mmc_ops *mmc; const struct tc956xmac_pma_ops *pma; struct mii_regs mii; /* MII register Addresses */ @@ -1750,12 +2774,20 @@ int dwmac1000_setup(struct tc956xmac_priv *priv); int dwmac4_setup(struct tc956xmac_priv *priv); int dwxgmac2_setup(struct tc956xmac_priv *priv); +#ifdef TC956X_SRIOV_PF void tc956xmac_set_mac_addr(void __iomem *ioaddr, u8 addr[6], unsigned int high, unsigned int low); void tc956xmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr, unsigned int high, unsigned int low); void tc956xmac_set_mac(struct tc956xmac_priv *priv, void __iomem *ioaddr, bool enable); - +int tc956x_add_mac_addr(struct net_device *dev, const unsigned char *mac); +#elif defined TC956X_SRIOV_VF +void tc956xmac_vf_set_mac_addr(void __iomem *ioaddr, u8 addr[6], + unsigned int high, unsigned int low); +void tc956xmac_vf_get_mac_addr(void __iomem *ioaddr, unsigned char *addr, + unsigned int high, unsigned int low); +void tc956xmac_set_mac(struct tc956xmac_priv *priv, void __iomem *ioaddr, bool enable); +#endif void tc956xmac_dwmac4_set_mac_addr(void __iomem *ioaddr, u8 addr[6], unsigned int high, unsigned int low); void tc956xmac_dwmac4_get_mac_addr(void __iomem *ioaddr, unsigned char *addr, @@ -1768,4 +2800,7 @@ extern const struct tc956xmac_mode_ops ring_mode_ops; extern const struct tc956xmac_mode_ops chain_mode_ops; extern const struct tc956xmac_desc_ops dwmac4_desc_ops; +#ifdef TC956X_SRIOV_VF +void tc956xmac_mailbox_service_event_schedule(struct tc956xmac_priv *priv); +#endif #endif /* __COMMON_H__ */ diff --git a/config.ini b/config.ini index d8d63f556ad6..896868add496 100644 --- a/config.ini +++ b/config.ini @@ -1,4 +1,8 @@ #MAC ID configuration, For Test purpose only -MDIOBUSID1: 1: MAC_ID1: EC:21:E5:10:4F:EA -MDIOBUSID2: 1: MAC_ID1: EC:21:E5:11:4F:EA +MDIOBUSID1: 1: MAC_ID01: EC:21:E5:10:4F:EA +MDIOBUSID2: 1: MAC_ID02: EC:21:E5:11:4F:EA +MDIOBUSID3: 1: MAC_ID03: EC:21:E5:12:4F:EA +MDIOBUSID4: 1: MAC_ID04: EC:21:E5:13:4F:EA +MDIOBUSID5: 1: MAC_ID05: EC:21:E5:14:4F:EA +MDIOBUSID6: 1: MAC_ID06: EC:21:E5:15:4F:EA #End of file (New line) diff --git a/descs.h b/descs.h index 97334a85f847..48cc17eb71bb 100644 --- a/descs.h +++ b/descs.h @@ -180,6 +180,21 @@ #define RDES_PTP_SIGNALING 0xa #define RDES_PTP_PKT_RESERVED_TYPE 0xf +#ifdef TC956X_SRIOV_VF /* MMC SW counter related */ +/* RDES3 PMT message type definitions */ +#define RDES_PMT_NO_PTP 0x0 +#define RDES_PMT_SYNC 0x1 +#define RDES_PMT_FOLLOW_UP 0x2 +#define RDES_PMT_DELAY_REQ 0x3 +#define RDES_PMT_DELAY_RESP 0x4 +#define RDES_PMT_PDELAY_REQ 0x5 +#define RDES_PMT_PDELAY_RESP 0x6 +#define RDES_PMT_PDELAY_FOLLOW_UP 0x7 +#define RDES_PMT_PTP_ANNOUNCE 0x8 +#define RDES_PMT_PTP_MANAGEMENT 0x9 +#define RDES_PMT_PTP_SIGNALING 0xa +#define RDES_PMT_PTP_PKT_RESERVED_TYPE 0xf +#endif /* Basic descriptor structure for normal and alternate descriptors */ struct dma_desc { __le32 des0; diff --git a/drivers/net/ethernet/toshiba/tc956x/Makefile b/drivers/net/ethernet/toshiba/tc956x/Makefile index 1210ce0a570c..634751ffda24 100644 --- a/drivers/net/ethernet/toshiba/tc956x/Makefile +++ b/drivers/net/ethernet/toshiba/tc956x/Makefile @@ -9,6 +9,8 @@ else CCFLAGS += -m32 endif +EXTRA_CFLAGS+=-DTC956X + ifeq ($(TC956X_PCIE_GEN3_SETTING),1) EXTRA_CFLAGS+=-DTC956X_PCIE_GEN3_SETTING endif @@ -17,23 +19,64 @@ ifeq ($(TC956X_LOAD_FW_HEADER),1) EXTRA_CFLAGS+=-DTC956X_LOAD_FW_HEADER endif +ifeq ($(TC956X_IOCTL_REG_RD_WR_ENABLE),1) +EXTRA_CFLAGS+=-DTC956X_IOCTL_REG_RD_WR_ENABLE +endif + +ifeq ($(TC956X_MAGIC_PACKET_WOL_GPIO),1) +EXTRA_CFLAGS+=-DTC956X_MAGIC_PACKET_WOL_GPIO +endif + +ifeq ($(TC956X_MAGIC_PACKET_WOL_CONF),1) +EXTRA_CFLAGS+=-DTC956X_MAGIC_PACKET_WOL_CONF +endif + +ifeq ($(TC956X_DMA_OFFLOAD_ENABLE),1) +EXTRA_CFLAGS+=-DTC956X_DMA_OFFLOAD_ENABLE DMA_OFFLOAD = 1 +endif + +ifeq ($(vf), 1) +EXTRA_CFLAGS+=-DTC956X_SRIOV_VF + +obj-m := tc956x_vf_pcie_eth.o +tc956x_vf_pcie_eth-y := tc956xmac_main.o tc956xmac_ethtool.o \ + mmc_core.o tc956xmac_hwtstamp.o tc956xmac_ptp.o \ + hwif.o tc956xmac_tc.o dwxgmac2_core.o \ + dwxgmac2_descs.o dwxgmac2_dma.o tc956x_pci.o \ + tc956x_vf_mbx_wrapper.o tc956x_msigen.o \ + tc956x_vf_rsc_mng.o tc956x_vf_mbx.o \ + tc956x_pcie_logstat.o + +else + +EXTRA_CFLAGS+=-DTC956X_SRIOV_PF obj-m := tc956x_pcie_eth.o tc956x_pcie_eth-y := tc956xmac_main.o tc956xmac_ethtool.o tc956xmac_mdio.o \ mmc_core.o tc956xmac_hwtstamp.o tc956xmac_ptp.o tc956x_xpcs.o tc956x_pma.o \ hwif.o tc956xmac_tc.o dwxgmac2_core.o \ dwxgmac2_descs.o dwxgmac2_dma.o tc956x_pci.o \ - tc956x_pcie_logstat.o + tc956x_msigen.o \ + tc956x_pcie_logstat.o tc956x_pf_rsc_mng.o \ -ifeq ($(TC956XMAC_SELFTESTS), 1) - tc956x_pcie_eth-y += tc956xmac_selftests.o -endif +ifeq ($(pf), 1) + tc956x_pcie_eth-y += tc956x_pf_mbx_wrapper.o tc956x_pf_rsc_mng.o tc956x_pf_mbx.o +else ifeq ($(port_bridge), 1) +EXTRA_CFLAGS+=-DTC956X_ENABLE_MAC2MAC_BRIDGE +else +EXTRA_CFLAGS+=-DTC956X_AUTOMOTIVE_CONFIG +endif ifeq ($(DMA_OFFLOAD), 1) tc956x_pcie_eth-y += tc956x_ipa_intf.o -endif +endif +ifeq ($(TC956XMAC_SELFTESTS), 1) + tc956x_pcie_eth-y += tc956xmac_selftests.o +endif + +endif all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules diff --git a/dwxgmac2.h b/dwxgmac2.h index 571e8a20ac91..1c8d35c45ce7 100644 --- a/dwxgmac2.h +++ b/dwxgmac2.h @@ -142,6 +142,7 @@ #define XGMAC_VLAN_ERSVLM BIT(19) #define XGMAC_VLAN_ESVL BIT(18) #define XGMAC_VLAN_ETV BIT(16) +#define XGMAC_VLAN_ETV_DATA BIT(17) #define XGMAC_VLAN_VID GENMASK(15, 0) #define XGMAC_VLAN_VL_LPOS (0) #define XGMAC_VLAN_HASH_TABLE (MAC_OFFSET + 0x00000058) @@ -158,15 +159,27 @@ #define XGMAC_RQ_SHIFT 4 #define XGMAC_RXQ_CTRL2 (MAC_OFFSET + 0x000000a8) #define XGMAC_RXQ_CTRL3 (MAC_OFFSET + 0x000000ac) +#define XGMAC_RXQ_CTRL4 (MAC_OFFSET + 0x00000094) +#define XGMAC_VFFQ_MASK GENMASK(20, 17) +#define XGMAC_VFFQ_SHIFT 17 +#define XGMAC_MFFQ_MASK GENMASK(12, 9) +#define XGMAC_MFFQ_SHIFT 9 +#define XGMAC_UFFQ_MASK GENMASK(4, 1) +#define XGMAC_UFFQ_SHIFT 1 +#define XGMAC_VFFQE BIT(16) +#define XGMAC_MFFQE BIT(8) +#define XGMAC_UFFQE BIT(0) #define XGMAC_PSRQ(x) GENMASK((x) * 8 + 7, (x) * 8) #define XGMAC_PSRQ_SHIFT(x) ((x) * 8) #define XGMAC_INT_STATUS (MAC_OFFSET + 0x000000b0) +#define XGMAC_TSIS BIT(12) #define XGMAC_LPIIS BIT(5) #define XGMAC_PMTIS BIT(4) #define XGMAC_INT_EN (MAC_OFFSET + 0x000000b4) #define XGMAC_TSIE BIT(12) #define XGMAC_LPIIE BIT(5) #define XGMAC_PMTIE BIT(4) +#define XGMAC_AUXTSTRIG BIT(2) /* MAC_Timestamp_Status register */ #ifndef TC956X #define XGMAC_INT_DEFAULT_EN (XGMAC_LPIIE | XGMAC_PMTIE) #else @@ -179,6 +192,7 @@ #define XGMAC_PT_SHIFT 16 #define XGMAC_TFE BIT(1) #define XGMAC_RX_FLOW_CTRL (MAC_OFFSET + 0x00000090) +#define XGMAC_PFCE BIT(8) #define XGMAC_RFE BIT(0) #define XGMAC_PMT (MAC_OFFSET + 0x000000c0) #define XGMAC_GLBLUCAST BIT(9) @@ -278,6 +292,22 @@ #define XGMAC_VLAN_EN BIT(16) #define TC956X_VLAN_DMACH BIT(25) /* DMA CHANNEL = 1*/ #define XGMAC_DMA_In(x) (MAC_OFFSET + (0x00000704 + (x) * 0x4)) +#define XGMAC_INDR_ACC_CTRL (MAC_OFFSET + 0x00000700) +#define XGMAC_INDR_ACC_CTRL_RSVD BIT(31) +#define XGMAC_INDR_ACC_CTRL_MSEL GENMASK(19, 16) +#define XGMAC_INDR_ACC_CTRL_MSEL_SHIFT (16) +#define XGMAC_INDR_ACC_CTRL_AOFF GENMASK(15, 8) +#define XGMAC_INDR_ACC_CTRL_AOFF_SHIFT (8) +#define XGMAC_INDR_ACC_CTRL_AUTO BIT(5) +#define XGMAC_INDR_ACC_CTRL_COM BIT(1) +#define XGMAC_INDR_ACC_CTRL_COM_SHIFT (1) +#define XGMAC_INDR_ACC_CTRL_OB BIT(0) +#define XGMAC_INDR_ACC_CTRL_OB_SHIFT (0) +#define XGMAC_DCHSEL (0) +#define XGMAC_INDR_ACC_DATA (MAC_OFFSET + 0x00000704) +#define XGMAC_MSEL_DCHSEL (0) +#define XGMAC_COM_READ (1) +#define XGMAC_COM_WRITE (0) #define XGMAC_ADDR_MAX 32 #define XGMAC_AE BIT(31) #define XGMAC_AE_SHIFT 31 @@ -381,6 +411,7 @@ #define XGMAC_MTL_INT_STATUS (MAC_OFFSET + 0x00001020) #define XGMAC_MTL_RXQ_DMA_MAP0 (MAC_OFFSET + 0x00001030) #define XGMAC_MTL_RXQ_DMA_MAP1 (MAC_OFFSET + 0x00001034) +#define XGMAC_QxDDMACH_SHIFT(x) ((x * 8) + 7) #define XGMAC_QxMDMACH(x) GENMASK((x) * 8 + 7, (x) * 8) #define XGMAC_QxMDMACH_SHIFT(x) ((x) * 8) #define XGMAC_QDDMACH BIT(7) @@ -426,6 +457,7 @@ #define XGMAC_NVE GENMASK(7, 0) #define XGMAC_MTL_RXP_IACC_CTRL_ST (MAC_OFFSET + 0x000010b0) #define XGMAC_STARTBUSY BIT(31) +#define XGMAC_ACCSEL BIT(24) #define XGMAC_WRRDN BIT(16) #define XGMAC_ADDR GENMASK(9, 0) #define XGMAC_MTL_RXP_IACC_DATA (MAC_OFFSET + 0x000010b4) @@ -487,7 +519,11 @@ #define XGMAC_MISPKTCNT_MASK GENMASK(26, 16) #define XGMAC_MISPKTCNT_SHIFT 16 +#ifdef TC956X_SRIOV_PF +#define XGMAC_MTL_RXQ_Debug(x) (MAC_OFFSET + (0x00001148 + (0x80 * (x)))) +#elif defined TC956X_SRIOV_VF #define XGMAC_MTL_RXQ_Debug(x) (0x00001148 + (0x80 * (x))) +#endif #define XGMAC_MTL_DEBUG_RXQSTS_MASK GENMASK(5, 4) #define XGMAC_MTL_DEBUG_RXQSTS_SHIFT 4 #define XGMAC_MTL_DEBUG_RXQSTS_EMPTY 0 @@ -727,6 +763,10 @@ #define XGMAC_TDES3_VT GENMASK(15, 0) #define XGMAC_TDES3_FL GENMASK(14, 0) #define XGMAC_RDES2_HL GENMASK(9, 0) +#ifdef TC956X_SRIOV_VF +#define XGMAC_RDES2_TNP BIT(11) +#define XGMAC_RDES2_TNP_SHIFT 11 +#endif #define XGMAC_RDES3_OWN BIT(31) #define XGMAC_RDES3_CTXT BIT(30) #define XGMAC_RDES3_IOC BIT(30) @@ -735,11 +775,18 @@ #define XGMAC_RDES3_RSV BIT(26) #define XGMAC_RDES3_L34T GENMASK(23, 20) #define XGMAC_RDES3_L34T_SHIFT 20 +#ifdef TC956X_SRIOV_VF +#define XGMAC_RDES3_ETLT GENMASK(19, 16) +#define XGMAC_RDES3_ETLT_SHIFT 16 +#endif #define XGMAC_L34T_IP4TCP 0x1 #define XGMAC_L34T_IP4UDP 0x2 #define XGMAC_L34T_IP6TCP 0x9 #define XGMAC_L34T_IP6UDP 0xA #define XGMAC_RDES3_ES BIT(15) +#ifdef TC956X_SRIOV_VF +#define XGMAC_RDES3_ES_SHIFT 15 +#endif #define XGMAC_RDES3_PL GENMASK(13, 0) #define XGMAC_RDES3_TSD BIT(6) #define XGMAC_RDES3_TSA BIT(4) @@ -764,4 +811,55 @@ _prefix##_##_field##_WIDTH) #endif +#ifdef TC956X_SRIOV_VF +#define XGMAC_RDES3_PMT GENMASK(3, 0) + +#define XGMAC_RDES2_AVTDP BIT(1) +#define XGMAC_RDES2_AVTCP BIT(0) + +#define XGMAC_L34T_NON_IP 0 +#define XGMAC_L34T_IPV4_TCP 1 +#define XGMAC_L34T_IPV4_UDP 2 +#define XGMAC_L34T_IPV4_ICMP 3 +#define XGMAC_L34T_IPV4_IGMP 4 +#define XGMAC_L34T_IPV4_UNKNOWN 7 +#define XGMAC_L34T_IPV6_TCP 9 +#define XGMAC_L34T_IPV6_UDP 10 +#define XGMAC_L34T_IPV6_ICMP 11 +#define XGMAC_L34T_IPV6_UNKNOWN 15 + + +#define XGMAC_ET_WD_TIMEOUT 1 +#define XGMAC_ET_INV_GMII 2 +#define XGMAC_ET_CRC 3 +#define XGMAC_ET_GIANT_PKT 4 +#define XGMAC_ET_IP_HEADER 5 +#define XGMAC_ET_L4_CSUM 6 +#define XGMAC_ET_OVERFLOW 7 +#define XGMAC_ET_BUS 8 +#define XGMAC_ET_LENGTH 9 +#define XGMAC_ET_GOOD_RUNT 10 +#define XGMAC_ET_DRIBBLE 12 + +#define XGMAC_ET_T_OUTER_IP_HEADER 5 +#define XGMAC_ET_T_OUTER_HEADER_PAYLOAD_L4_CSUM 6 +#define XGMAC_ET_T_INNER_IP_HEADER 9 +#define XGMAC_ET_T_INNER_L4_PAYLOAD 10 +#define XGMAC_ET_T_INV_VXLAN_HEADER 11 + +#define XGMAC_LT_LENGTH 0 +#define XGMAC_LT_MAC_CONTROL 1 +#define XGMAC_LT_DCB_CONTROL 2 +#define XGMAC_LT_ARP_REQ 3 +#define XGMAC_LT_OAM 4 +#define XGMAC_LT_MAC_RX_ETH_TYPE_MATCH 5 +#define XGMAC_LT_OTH_TYPE 7 +#define XGMAC_LT_SVLAN 8 +#define XGMAC_LT_CVLAN 9 +#define XGMAC_LT_D_CVLAN_CVLAN 10 +#define XGMAC_LT_D_SVLAN_SVLAN 11 +#define XGMAC_LT_D_SVLAN_CVLAN 12 +#define XGMAC_LT_D_CVLAN_SVLAN 13 +#define XGMAC_LT_UNTAG_AV_CONTROL 6 +#endif /* #ifdef TC956X_SRIOV_VF */ #endif /* __TC956XMAC_DWXGMAC2_H__ */ diff --git a/dwxgmac2_core.c b/dwxgmac2_core.c index 5125ad537afd..159de808d897 100644 --- a/dwxgmac2_core.c +++ b/dwxgmac2_core.c @@ -4,7 +4,7 @@ * dwxgmac2_core.c * * Copyright (C) 2018 Synopsys, Inc. and/or its affiliates. - * Copyright (C) 2021 Toshiba Electronic Devices & Storage Corporation + * Copyright (C) 2023 Toshiba Electronic Devices & Storage Corporation * * This file has been derived from the STMicro and Synopsys Linux driver, * and developed or modified for TC956X. @@ -59,6 +59,8 @@ * VERSION : 01-00-24 * 08 Dec 2021 : 1. Renamed pause frames module parameter * VERSION : 01-00-30 + * 10 Nov 2023 : 1. Kernel 6.1 Porting changes + * VERSION : 01-02-59 */ #include @@ -68,8 +70,21 @@ #include "tc956xmac_ptp.h" #include "dwxgmac2.h" +#ifndef TC956X_SRIOV_VF extern unsigned int mac0_filter_phy_pause; extern unsigned int mac1_filter_phy_pause; +#endif + +#ifdef TC956X_SRIOV_DEBUG +void tc956x_filter_debug(struct tc956xmac_priv *priv); +#endif +#ifdef TC956X_SRIOV_PF +int tc956x_pf_set_mac_filter(struct net_device *dev, int vf, const u8 *mac); +void tc956x_pf_del_mac_filter(struct net_device *dev, int vf, const u8 *mac); +void tc956x_pf_del_umac_addr(struct tc956xmac_priv *priv, int index, int vf); +void tc956x_pf_set_vlan_filter(struct net_device *dev, u16 vf, u16 vid); +void tc956x_pf_del_vlan_filter(struct net_device *dev, u16 vf, u16 vid); +#endif static void tc956x_set_mac_addr(struct tc956xmac_priv *priv, struct mac_device_info *hw, const u8 *mac, int index, int vf); @@ -278,7 +293,24 @@ static void tc956x_rx_queue_routing(struct tc956xmac_priv *priv, { XGMAC_RXQCTRL_MCBCQ_MASK, XGMAC_RXQCTRL_MCBCQ_SHIFT }, { XGMAC_RXQCTRL_FPRQ_MASK, XGMAC_RXQCTRL_FPRQ_SHIFT }, }; +#if defined(TC956X_SRIOV_PF) && !defined(TC956X_AUTOMOTIVE_CONFIG) && !defined(TC956X_ENABLE_MAC2MAC_BRIDGE) + /* Fail packet routing for UC, MC, VLAN */ + if (packet == PACKET_FILTER_FAIL) { + value = readl(ioaddr + XGMAC_RXQ_CTRL4); + value &= (~(XGMAC_VFFQ_MASK | XGMAC_MFFQ_MASK | XGMAC_UFFQ_MASK)); + + value |= ((queue << XGMAC_UFFQ_SHIFT) | \ + (queue << XGMAC_MFFQ_SHIFT) | \ + (queue << XGMAC_VFFQ_SHIFT)); + + value |= XGMAC_UFFQE | XGMAC_MFFQE | XGMAC_VFFQE; + + writel(value, ioaddr + XGMAC_RXQ_CTRL4); + + return; + } +#endif value = readl(ioaddr + XGMAC_RXQ_CTRL1); /* routing configuration */ @@ -352,7 +384,7 @@ static void dwxgmac2_prog_mtl_tx_algorithms(struct tc956xmac_priv *priv, writel(value, ioaddr + XGMAC_MTL_OPMODE); /* Set ETS if desired */ - for (i = 0; i < MTL_MAX_TX_QUEUES; i++) { + for (i = 0; i < MTL_MAX_TX_TC; i++) { value = readl(ioaddr + XGMAC_MTL_TCx_ETS_CONTROL(i)); value &= ~XGMAC_TSA; if (ets) @@ -363,13 +395,13 @@ static void dwxgmac2_prog_mtl_tx_algorithms(struct tc956xmac_priv *priv, static void dwxgmac2_set_mtl_tx_queue_weight(struct tc956xmac_priv *priv, struct mac_device_info *hw, - u32 weight, u32 queue) + u32 weight, u32 tc) { void __iomem *ioaddr = hw->pcsr; - writel(weight, ioaddr + XGMAC_MTL_TCx_QUANTUM_WEIGHT(queue)); + writel(weight, ioaddr + XGMAC_MTL_TCx_QUANTUM_WEIGHT(tc)); - netdev_dbg(priv->dev, "%s: MTLQ%d weight = %d", __func__, queue, weight); + netdev_dbg(priv->dev, "%s: MTL_TC%d weight = %d", __func__, tc, weight); } static void dwxgmac2_map_mtl_to_dma(struct tc956xmac_priv *priv, @@ -377,15 +409,25 @@ static void dwxgmac2_map_mtl_to_dma(struct tc956xmac_priv *priv, u32 chan) { void __iomem *ioaddr = hw->pcsr; - u32 value, reg; + u32 value, reg, rx_q; + rx_q = queue; reg = (queue < 4) ? XGMAC_MTL_RXQ_DMA_MAP0 : XGMAC_MTL_RXQ_DMA_MAP1; if (queue >= 4) queue -= 4; value = readl(ioaddr + reg); - value &= ~XGMAC_QxMDMACH(queue); - value |= (chan << XGMAC_QxMDMACH_SHIFT(queue)) & XGMAC_QxMDMACH(queue); +#ifdef TC956X_SRIOV_PF + /* Set QxDDMACH to enable Rx Q-ch mapping based on DA Filter Value */ + if (priv->plat->rx_queues_cfg[rx_q].chan == TC956X_DA_MAP) { + value |= 1 << XGMAC_QxDDMACH_SHIFT(queue); + } else { +#endif + value &= ~XGMAC_QxMDMACH(queue); + value |= (chan << XGMAC_QxMDMACH_SHIFT(queue)) & XGMAC_QxMDMACH(queue); +#ifdef TC956X_SRIOV_PF + } +#endif writel(value, ioaddr + reg); @@ -393,7 +435,6 @@ static void dwxgmac2_map_mtl_to_dma(struct tc956xmac_priv *priv, readl(ioaddr + reg)); } -#ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE static void dwxgmac2_config_cbs(struct tc956xmac_priv *priv, struct mac_device_info *hw, u32 send_slope, u32 idle_slope, @@ -416,17 +457,16 @@ static void dwxgmac2_config_cbs(struct tc956xmac_priv *priv, value |= XGMAC_CBS; writel(value, ioaddr + XGMAC_MTL_TCx_ETS_CONTROL(traffic_class)); - netdev_dbg(priv->dev, "%s: MTLQ%d Send Slope Register = 0x%x", __func__, traffic_class, + netdev_dbg(priv->dev, "%s: MTL_TC%d Send Slope Register = 0x%x", __func__, traffic_class, readl(ioaddr + XGMAC_MTL_TCx_SENDSLOPE(traffic_class))); - netdev_dbg(priv->dev, "%s: MTLQ%d Idle Slope Register = 0x%x", __func__, traffic_class, + netdev_dbg(priv->dev, "%s: MTL_TC%d Idle Slope Register = 0x%x", __func__, traffic_class, readl(ioaddr + XGMAC_MTL_TCx_QUANTUM_WEIGHT(traffic_class))); - netdev_dbg(priv->dev, "%s: MTLQ%d High Credit Register = 0x%x", __func__, traffic_class, + netdev_dbg(priv->dev, "%s: MTL_TC%d High Credit Register = 0x%x", __func__, traffic_class, readl(ioaddr + XGMAC_MTL_TCx_HICREDIT(traffic_class))); - netdev_dbg(priv->dev, "%s: MTLQ%d Lo Credit Register = 0x%x", __func__, traffic_class, + netdev_dbg(priv->dev, "%s: MTL_TC%d Lo Credit Register = 0x%x", __func__, traffic_class, readl(ioaddr + XGMAC_MTL_TCx_LOCREDIT(traffic_class))); } -#endif /* TC956X_UNSUPPORTED_UNTESTED_FEATURE */ static void dwxgmac2_dump_regs(struct tc956xmac_priv *priv, struct mac_device_info *hw, u32 *reg_space) @@ -434,19 +474,27 @@ static void dwxgmac2_dump_regs(struct tc956xmac_priv *priv, void __iomem *ioaddr = hw->pcsr; int i, ch, tc, k; - for (i = ETH_CORE_DUMP_OFFSET1; i <= ETH_CORE_DUMP_OFFSET1_END; i++)/*MAC reg*/ + KPRINT_DEBUG1("************************************EMAC Dump***********************************************"); + for (i = ETH_CORE_DUMP_OFFSET1; i <= ETH_CORE_DUMP_OFFSET1_END; i++) {/*MAC reg*/ reg_space[i] = readl(ioaddr + MAC_OFFSET + (i * 4)); + KPRINT_DEBUG1("%04x : %08x\n", i*4, reg_space[i]); + } - for (i = ETH_CORE_DUMP_OFFSET2; i <= ETH_CORE_DUMP_OFFSET2_END; i++)/*MAC reg*/ + for (i = ETH_CORE_DUMP_OFFSET2; i <= ETH_CORE_DUMP_OFFSET2_END; i++) { /*MAC reg*/ reg_space[i] = readl(ioaddr + MAC_OFFSET + (i * 4)); + KPRINT_DEBUG1("%04x : %08x\n", i*4, reg_space[i]); + } - for (i = ETH_CORE_DUMP_OFFSET3; i <= ETH_CORE_DUMP_OFFSET3_END; i++)/*MTL reg*/ + for (i = ETH_CORE_DUMP_OFFSET3; i <= ETH_CORE_DUMP_OFFSET3_END; i++) {/*MTL reg*/ reg_space[i] = readl(ioaddr + MAC_OFFSET + (i * 4)); + KPRINT_DEBUG1("%04x : %08x\n", i*4, reg_space[i]); + } for (i = ETH_CORE_DUMP_OFFSET4; i <= ETH_CORE_DUMP_OFFSET4_END; i++) {/*MTL TX reg*/ for (ch = 0; ch < 8; ch++) { k = i + (0x20 * ch); reg_space[k] = readl(ioaddr + MAC_OFFSET + ((0x0080 * ch) + (i * 4))); + KPRINT_DEBUG1("%04x : %08x\n", (0x0080 * ch) + (i * 4), reg_space[k]); } } @@ -454,6 +502,7 @@ static void dwxgmac2_dump_regs(struct tc956xmac_priv *priv, for (tc = 0; tc < 5; tc++) { k = i + (0x20 * tc); reg_space[k] = readl(ioaddr + MAC_OFFSET + ((0x0080 * tc) + (i * 4))); + KPRINT_DEBUG1("%04x : %08x\n", (0x0080 * tc) + (i * 4), reg_space[k]); } } @@ -461,6 +510,7 @@ static void dwxgmac2_dump_regs(struct tc956xmac_priv *priv, for (ch = 0; ch < 8; ch++) { k = i + (0x20 * ch); reg_space[k] = readl(ioaddr + MAC_OFFSET + (0x0080*ch) + (i * 4)); + KPRINT_DEBUG1("%04x : %08x\n", (0x0080 * ch) + (i * 4), reg_space[k]); } } } @@ -472,10 +522,7 @@ static int dwxgmac2_host_irq_status(struct tc956xmac_priv *priv, void __iomem *ioaddr = hw->pcsr; u32 stat, en; int ret = 0; -#ifdef EEE - int val; -#endif - + int val = 0; en = readl(ioaddr + XGMAC_INT_EN); stat = readl(ioaddr + XGMAC_INT_STATUS); @@ -491,7 +538,7 @@ static int dwxgmac2_host_irq_status(struct tc956xmac_priv *priv, u32 lpi = readl(ioaddr + XGMAC_LPI_CTRL); if (lpi & XGMAC_TLPIEN) { - KPRINT_INFO("Transmit LPI Entry..... \n"); + KPRINT_INFO("Transmit LPI Entry.....\n"); ret |= CORE_IRQ_TX_PATH_IN_LPI_MODE; x->irq_tx_path_in_lpi_mode_n++; } @@ -501,11 +548,11 @@ static int dwxgmac2_host_irq_status(struct tc956xmac_priv *priv, x->irq_tx_path_exit_lpi_mode_n++; } if (lpi & XGMAC_RLPIEN) { - KPRINT_INFO("Receive LPI Entry....... \n"); + KPRINT_INFO("Receive LPI Entry.......\n"); x->irq_rx_path_in_lpi_mode_n++; } if (lpi & XGMAC_RLPIEX) { - KPRINT_INFO("Receive LPI Exit...... \n"); + KPRINT_INFO("Receive LPI Exit......\n"); x->irq_rx_path_exit_lpi_mode_n++; } @@ -520,12 +567,20 @@ static int dwxgmac2_host_irq_status(struct tc956xmac_priv *priv, } val = tc956x_xpcs_read(priv->xpcsaddr, XGMAC_SR_XS_PCS_STS1); - if ( val & XGMAC_RX_LPI_RECEIVE) + if (val & XGMAC_RX_LPI_RECEIVE) KPRINT_INFO("XPCS RX LPI Received......"); - if ( val & XGAMC_TX_LPI_RECEIVE) + if (val & XGAMC_TX_LPI_RECEIVE) KPRINT_INFO("XPCS TX LPI Received......"); #endif } + if (stat & XGMAC_TSIS) { + val = readl(ioaddr + PTP_XGMAC_OFFSET + PTP_TS_STATUS); + if (val & XGMAC_AUXTSTRIG) { + KPRINT_INFO("\n"); + KPRINT_INFO("second: %x\n", readl(ioaddr + PTP_XGMAC_OFFSET + PTP_ATS_SEC)); + KPRINT_INFO("subsec(ns): %x\n", readl(ioaddr + PTP_XGMAC_OFFSET + PTP_ATS_NSEC)); + } + } return ret; } @@ -560,8 +615,11 @@ static void dwxgmac2_flow_ctrl(struct tc956xmac_priv *priv, flow = 0; if (fc & FLOW_RX) +#ifdef TC956X_SRIOV_PF flow |= XGMAC_RFE; - +#elif defined TC956X_SRIOV_VF + flow |= XGMAC_RFE; +#endif writel(flow, ioaddr + XGMAC_RX_FLOW_CTRL); flow = 0; @@ -712,56 +770,179 @@ static void dwxgmac2_set_mchash(struct tc956xmac_priv *priv, void __iomem *ioadd } } -static void tc956x_set_dma_ch(struct tc956xmac_priv *priv, struct mac_device_info *hw, int index, int vf) +#ifdef TC956X_SRIOV_PF +static s32 tc956x_mac_ind_acc_wr_rd(struct tc956xmac_priv *priv, u8 wr_rd, u32 msel, u32 offset, u32 *val) +{ + u32 reg_data, limit; + void __iomem *ioaddr = priv->ioaddr; + + /* Wait till previous operation is complete */ + limit = 1000; + while (limit--) { + if (!(readl(ioaddr + XGMAC_INDR_ACC_CTRL) & XGMAC_INDR_ACC_CTRL_OB)) + break; + udelay(1); + } + if (limit < 0) + return -EBUSY; + + /* Clear previous values */ + reg_data = readl(ioaddr + XGMAC_INDR_ACC_CTRL); + reg_data &= (~(XGMAC_INDR_ACC_CTRL_RSVD | XGMAC_INDR_ACC_CTRL_MSEL | \ + XGMAC_INDR_ACC_CTRL_AOFF | XGMAC_INDR_ACC_CTRL_COM | \ + XGMAC_INDR_ACC_CTRL_AUTO)); + + if (wr_rd) { + /* Indirect Read sequence */ + + /* Set read params */ + reg_data |= (msel << XGMAC_INDR_ACC_CTRL_MSEL_SHIFT) | \ + (wr_rd << XGMAC_INDR_ACC_CTRL_COM_SHIFT) | \ + (offset << XGMAC_INDR_ACC_CTRL_AOFF_SHIFT); + + writel(reg_data, ioaddr + XGMAC_INDR_ACC_CTRL); + + + /* Start Operation */ + reg_data |= XGMAC_INDR_ACC_CTRL_OB; + + writel(reg_data, ioaddr + XGMAC_INDR_ACC_CTRL); + + /* Wait for completion */ + limit = 1000; + while (limit--) { + if (!(readl(ioaddr + XGMAC_INDR_ACC_CTRL) & XGMAC_INDR_ACC_CTRL_OB)) + break; + udelay(1); + } + if (limit < 0) + return -EBUSY; + + /* Read value */ + *val = readl(ioaddr + XGMAC_INDR_ACC_DATA); + + + } else { + /* Indirect Write sequence */ + + /* Set write value and params */ + writel(*val, ioaddr + XGMAC_INDR_ACC_DATA); + + reg_data |= (msel << XGMAC_INDR_ACC_CTRL_MSEL_SHIFT) | \ + (offset << XGMAC_INDR_ACC_CTRL_AOFF_SHIFT); + + writel(reg_data, ioaddr + XGMAC_INDR_ACC_CTRL); + + /* Start Operation */ + reg_data |= XGMAC_INDR_ACC_CTRL_OB; + + writel(reg_data, ioaddr + XGMAC_INDR_ACC_CTRL); + + /* Wait for completion */ + limit = 1000;//10000; + while (limit--) { + if (!(readl(ioaddr + XGMAC_INDR_ACC_CTRL) & XGMAC_INDR_ACC_CTRL_OB)) + break; + udelay(1); + } + if (limit < 0) + return -EBUSY; + + } + + return 0; + +} + +#ifdef TC956X_SRIOV_DEBUG +void tc956x_filter_debug(struct tc956xmac_priv *priv) +{ + u32 reg_data = 0, offset; + void __iomem *ioaddr = priv->ioaddr; + + for (offset = 0; offset < 32; offset++) { + if (tc956x_mac_ind_acc_wr_rd(priv, XGMAC_COM_READ, XGMAC_MSEL_DCHSEL, offset, ®_data)) { + netdev_err(priv->dev, "Setting XDCS Failed\n"); + return; + } + KPRINT_INFO("%d %08x %08x %01x\n", offset, readl(ioaddr + XGMAC_ADDRx_HIGH(offset)), readl(ioaddr + XGMAC_ADDRx_LOW(offset)), reg_data); + } +} +#endif +#ifdef TC956X_ENABLE_MAC2MAC_BRIDGE +static void tc956x_set_dma_ch(struct tc956xmac_priv *priv, struct mac_device_info *hw, int index, int vf, bool mc_addr) +#else +static void tc956x_set_dma_ch(struct tc956xmac_priv *priv, struct mac_device_info *hw, int index, int vf) +#endif { - void __iomem *ioaddr = hw->pcsr; u32 data = 0, reg_data = 0; reg_data = 0; - reg_data = readl(ioaddr + XGMAC_DMA_In(index)); - if (vf == 1) /* IVI */ - data |= TC956XMAC_CHA_NO_0; - else if (vf == 2) /* TCU */ - data |= TC956XMAC_CHA_NO_1; - else if (vf == 3) /* ADAS */ - data |= TC956XMAC_CHA_NO_2; - else if (vf == PF_DRIVER) /* PF */ - data |= TC956XMAC_CHA_NO_3; - else + if (tc956x_mac_ind_acc_wr_rd(priv, XGMAC_COM_READ, XGMAC_MSEL_DCHSEL, index, ®_data)) { + netdev_err(priv->dev, "Setting XDCS Failed\n"); + return; + } + + if (vf == TC956XMAC_VF_IVI) /* IVI */ + data |= TC956XMAC_CHA_IVI; + else if (vf == TC956XMAC_VF_TCU) /* TCU */ + data |= TC956XMAC_CHA_TCU; + else if (vf == TC956XMAC_VF_ADAS) /* ADAS */ + data |= TC956XMAC_CHA_ADAS; + else if (vf == PF_DRIVER) {/* PF */ +#if defined(TC956X_ENABLE_MAC2MAC_BRIDGE) + if (mc_addr) + data |= TC956XMAC_CHA_M2M; + data |= TC956XMAC_CHA_PF; + +#else + data |= TC956XMAC_CHA_PF; +#endif + } else data |= TC956XMAC_CHA_NO_0; reg_data |= data; - writel(reg_data, ioaddr + XGMAC_DMA_In(index)); + if (tc956x_mac_ind_acc_wr_rd(priv, XGMAC_COM_WRITE, XGMAC_MSEL_DCHSEL, index, ®_data)) { + netdev_err(priv->dev, "Setting XDCS Failed\n"); + return; + } } static void tc956x_del_dma_ch(struct tc956xmac_priv *priv, struct mac_device_info *hw, int index, int vf) { - void __iomem *ioaddr = hw->pcsr; u32 data = 0, reg_data = 0; - reg_data = readl(ioaddr + XGMAC_DMA_In(index)); - if (vf == 1) /* IVI */ - data |= TC956XMAC_CHA_NO_0; - else if (vf == 2) /* TCU */ - data |= TC956XMAC_CHA_NO_1; - else if (vf == 3) /* ADAS */ - data |= TC956XMAC_CHA_NO_2; + if (tc956x_mac_ind_acc_wr_rd(priv, XGMAC_COM_READ, XGMAC_MSEL_DCHSEL, index, ®_data)) { + netdev_err(priv->dev, "Setting XDCS Failed\n"); + return; + } + + if (vf == TC956XMAC_VF_IVI) /* IVI */ + data |= TC956XMAC_CHA_IVI; + else if (vf == TC956XMAC_VF_TCU) /* TCU */ + data |= TC956XMAC_CHA_TCU; + else if (vf == TC956XMAC_VF_ADAS) /* ADAS */ + data |= TC956XMAC_CHA_ADAS; else if (vf == PF_DRIVER) /* PF */ - data |= TC956XMAC_CHA_NO_3; + data |= TC956XMAC_CHA_PF; else data |= TC956XMAC_CHA_NO_0; reg_data &= ~data; - writel(reg_data, ioaddr + XGMAC_DMA_In(index)); + + if (tc956x_mac_ind_acc_wr_rd(priv, XGMAC_COM_WRITE, XGMAC_MSEL_DCHSEL, index, ®_data)) { + netdev_err(priv->dev, "Setting XDCS Failed\n"); + return; + } } - +#endif static void tc956x_set_mac_addr(struct tc956xmac_priv *priv, struct mac_device_info *hw, const u8 *mac, int index, int vf) @@ -769,6 +950,10 @@ static void tc956x_set_mac_addr(struct tc956xmac_priv *priv, struct mac_device_i void __iomem *ioaddr = hw->pcsr; unsigned long data = 0; u32 value; +#ifdef TC956X_ENABLE_MAC2MAC_BRIDGE + u8 flow_ctrl_addr[6] = {0x01, 0x80, 0xC2, 0x00, 0x00, 0x01}; + bool multicast_addr = false; +#endif data = (mac[5] << 8) | mac[4]; /* For MAC Addr registers se have to set the Address Enable (AE) @@ -785,6 +970,20 @@ static void tc956x_set_mac_addr(struct tc956xmac_priv *priv, struct mac_device_i data = (mac[3] << 24) | (mac[2] << 16) | (mac[1] << 8) | mac[0]; writel(data, ioaddr + XGMAC_ADDRx_LOW(index)); +#ifdef TC956X_SRIOV_PF +#ifdef TC956X_ENABLE_MAC2MAC_BRIDGE + if (is_multicast_ether_addr(mac)) + multicast_addr = true; + + /* Route all multicast Flow control packets to PCI path */ + if (!memcmp(&flow_ctrl_addr[0], &mac[0], TC956X_SIX)) + multicast_addr = false; + + tc956x_set_dma_ch(priv, hw, index, vf, multicast_addr); +#else + tc956x_set_dma_ch(priv, hw, index, vf); +#endif +#endif } static void tc956x_del_mac_addr(struct tc956xmac_priv *priv, struct mac_device_info *hw, @@ -795,6 +994,18 @@ static void tc956x_del_mac_addr(struct tc956xmac_priv *priv, struct mac_device_i writel(data, ioaddr + XGMAC_ADDRx_HIGH(index)); writel(data, ioaddr + XGMAC_ADDRx_LOW(index)); + +#ifdef TC956X_SRIOV_PF + /*clearing the dma indirect XDCS register + * when the mac address is completely deleted from the sw table + */ + + if (tc956x_mac_ind_acc_wr_rd(priv, XGMAC_COM_WRITE, XGMAC_MSEL_DCHSEL, index, (u32 *)&data)) { + netdev_err(priv->dev, "Setting XDCS Failed\n"); + return; + } +#endif + } static void tc956x_del_sw_mac_helper(struct tc956x_mac_addr *mac_table, int vf) @@ -857,9 +1068,10 @@ static void tc956x_del_sw_mac_table(struct net_device *dev, writel(data2, ioaddr + XGMAC_HASH_TAB_32_63); } tc956x_del_mac_addr(priv, hw, i, vf); - +#ifdef TC956X_SRIOV_PF } else { tc956x_del_dma_ch(priv, hw, i, vf); +#endif } } @@ -906,7 +1118,11 @@ static int tc956x_add_actual_mac_table(struct net_device *dev, KPRINT_INFO("Space is not available in MAC_Table\n"); KPRINT_INFO("Enabling the promisc mode\n"); value = readl(ioaddr + XGMAC_PACKET_FILTER); +#if defined(TC956X_SRIOV_PF) || defined(TC956X_SRIOV_VF) || defined(TC956X_AUTOMOTIVE_CONFIG) || defined(TC956X_ENABLE_MAC2MAC_BRIDGE) + value |= XGMAC_FILTER_RA; +#else value |= XGMAC_FILTER_PR; +#endif writel(value, ioaddr + XGMAC_PACKET_FILTER); } return ret_value; @@ -925,6 +1141,10 @@ static int tc956x_mac_duplication(struct tc956xmac_priv *priv, i++, mac_table++) { if (mac_table->status == TC956X_MAC_STATE_OCCUPIED) { if (ether_addr_equal(mac, mac_table->mac_address)) { + if (is_unicast_ether_addr(mac)) { + KPRINT_DEBUG1("%pM mac is unicast address and it cannot be duplicated\n", mac); + return -1; + } for (vf_no = 0; vf_no < 4; vf_no++) { if (mac_table->vf[vf_no] == 0) { free_index = vf_no; @@ -933,15 +1153,31 @@ static int tc956x_mac_duplication(struct tc956xmac_priv *priv, return -1; } } +#ifdef TC956X_SRIOV_PF + /*if vf is not found in vf[], + *than add vf no, in free index + *of vf[] + */ + KPRINT_DEBUG1(KERN_DEBUG "%d offset %pM mac duplication\n", i, mac); + mac_table->vf[free_index] = vf; + mac_table->counter++; +#ifdef TC956X_ENABLE_MAC2MAC_BRIDGE + tc956x_set_dma_ch(priv, hw, i, vf, false); +#else + tc956x_set_dma_ch(priv, hw, i, vf); +#endif + ret_value = TC956X_MAC_STATE_MODIFIED; + return ret_value; +#elif defined TC956X_SRIOV_VF /*if vf is not found in vf[], *than add vf no, in free index *of vf[] */ mac_table->vf[free_index] = vf; mac_table->counter++; - tc956x_set_dma_ch(priv, hw, i, vf); ret_value = TC956X_MAC_STATE_MODIFIED; return ret_value; +#endif } } } @@ -974,9 +1210,14 @@ static int tc956x_add_sw_mac_table(struct net_device *dev, const u8 *mac, int vf u32 value = readl(ioaddr + XGMAC_PACKET_FILTER); unsigned int reg_value; int ret_value = 0; +#ifdef TC956X_SRIOV_PF + /*u32 value_extended = readl(ioaddr + XGMAC_EXTENDED_REG);*/ +#endif +#ifndef TC956X_ENABLE_MAC2MAC_BRIDGE value &= ~(XGMAC_FILTER_PR | XGMAC_FILTER_HMC | XGMAC_FILTER_PM | XGMAC_FILTER_RA); +#endif value |= XGMAC_FILTER_HPF; writel(value, ioaddr + XGMAC_PACKET_FILTER); @@ -1002,21 +1243,72 @@ static int tc956x_add_sw_mac_table(struct net_device *dev, const u8 *mac, int vf return ret_value; } +#ifdef TC956X_SRIOV_PF +int tc956x_pf_set_mac_filter(struct net_device *dev, + int vf, const u8 *mac) +{ + + if (tc956x_add_sw_mac_table(dev, mac, vf) >= 0) + return 0; + else + return -EPERM; +} + +void tc956x_pf_del_mac_filter(struct net_device *dev, + int vf, const u8 *mac) +{ + tc956x_del_sw_mac_table(dev, mac, vf); +} + +void tc956x_pf_del_umac_addr(struct tc956xmac_priv *priv, + int index, int vf) +{ + struct mac_device_info *hw = priv->hw; + + tc956x_del_mac_addr(priv, hw, index, vf); + tc956x_del_dma_ch(priv, hw, 0, vf); +} +#endif + +#ifdef TC956X_SRIOV_PF +int tc956x_add_mac_addr(struct net_device *dev, const unsigned char *mac) +#elif defined TC956X_SRIOV_VF static int tc956x_add_mac_addr(struct net_device *dev, const unsigned char *mac) +#endif { int ret_value; +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + struct tc956xmac_priv *priv = netdev_priv(dev); + unsigned long flags; + spin_lock_irqsave(&priv->spn_lock.mac_filter, flags); +#endif ret_value = tc956x_add_sw_mac_table(dev, mac, PF_DRIVER); +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_unlock_irqrestore(&priv->spn_lock.mac_filter, flags); +#endif + return ret_value; } static int tc956x_delete_mac_addr(struct net_device *dev, const unsigned char *mac) { +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + unsigned long flags; + struct tc956xmac_priv *priv = netdev_priv(dev); + + spin_lock_irqsave(&priv->spn_lock.mac_filter, flags); +#endif tc956x_del_sw_mac_table(dev, mac, PF_DRIVER); +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_unlock_irqrestore(&priv->spn_lock.mac_filter, flags); +#endif + + return 0; } static void dwxgmac2_set_filter(struct tc956xmac_priv *priv, struct mac_device_info *hw, @@ -1026,18 +1318,26 @@ static void dwxgmac2_set_filter(struct tc956xmac_priv *priv, struct mac_device_i u32 value = readl(ioaddr + XGMAC_PACKET_FILTER); u32 i; +#ifndef TC956X_ENABLE_MAC2MAC_BRIDGE value &= ~(XGMAC_FILTER_PR | XGMAC_FILTER_HMC | XGMAC_FILTER_PM | XGMAC_FILTER_RA); +#endif value |= XGMAC_FILTER_HPF; +#ifndef TC956X_SRIOV_VF /* Configuring to Pass all pause frames to application, PHY pause frames will be filtered by FRP */ if ((mac0_filter_phy_pause == ENABLE && priv->port_num == RM_PF0_ID) || (mac1_filter_phy_pause == ENABLE && priv->port_num == RM_PF1_ID)) { /* setting pcf to 0b10 i.e. pass pause frames of address filter fail to Application */ value |= 0x80; } +#endif writel(value, ioaddr + XGMAC_PACKET_FILTER); if (dev->flags & IFF_PROMISC) { +#if defined(TC956X_SRIOV_PF) || defined(TC956X_SRIOV_VF) || defined(TC956X_AUTOMOTIVE_CONFIG) || defined(TC956X_ENABLE_MAC2MAC_BRIDGE) + value |= XGMAC_FILTER_RA; +#else value |= XGMAC_FILTER_PR; +#endif writel(value, ioaddr + XGMAC_PACKET_FILTER); } else if (dev->flags & IFF_ALLMULTI) { value |= XGMAC_FILTER_PM; @@ -1160,6 +1460,30 @@ static void tc956x_vlan_addr_reg(struct tc956xmac_priv *priv, struct mac_device_ void __iomem *ioaddr = hw->pcsr; unsigned long data = 0; +#if defined(TC956X_SRIOV_PF) | defined(TC956X_SRIOV_VF) + data = 0; + data |= VLAN; + data |= XGMAC_VLAN_EN; + data |= XGMAC_VLAN_ETV_DATA; + data &= ~XGMAC_VLAN_DMACHE; + writel(data, ioaddr + XGMAC_VLAN_TAG_DATA); + + data = 0; +#ifdef TC956X_SRIOV_PF + data = readl(ioaddr + XGMAC_VLAN_TAG_CTRL); +#endif + data &= ~XGMAC_ADDR_OFFSET; + data |= (count << XGMAC_ADDR_OFFSET_LPOS); + data &= ~XGMAC_VLAN_CT;/*write command*/ + data |= XGMAC_VLAN_OB; + + writel(data, ioaddr + XGMAC_VLAN_TAG_CTRL); + + do { + data = readl(ioaddr + XGMAC_VLAN_TAG_CTRL) & XGMAC_VLAN_OB; + } while (data); + +#else data = readl(ioaddr + XGMAC_VLAN_TAG_DATA); data |= VLAN; data |= XGMAC_VLAN_EN; @@ -1180,6 +1504,7 @@ static void tc956x_vlan_addr_reg(struct tc956xmac_priv *priv, struct mac_device_ data = readl(ioaddr + XGMAC_VLAN_TAG_CTRL) & XGMAC_VLAN_OB; } while (data); +#endif } @@ -1441,6 +1766,23 @@ static void dwxgmac2_update_vlan_hash(struct tc956xmac_priv *priv, } +#ifdef TC956X_SRIOV_PF + +void tc956x_pf_set_vlan_filter(struct net_device *dev, u16 vf, u16 vid) +{ + struct tc956xmac_priv *priv = netdev_priv(dev); + + dwxgmac2_update_vlan_hash(priv, dev, 0, vid, vf); +} + +void tc956x_pf_del_vlan_filter(struct net_device *dev, u16 vf, u16 vid) +{ + struct tc956xmac_priv *priv = netdev_priv(dev); + + tc956x_del_sw_vlan_table(priv, dev, vid, vf); +} +#endif + struct dwxgmac3_error_desc { bool valid; const char *desc; @@ -1732,14 +2074,25 @@ static int dwxgmac3_safety_feat_dump(struct tc956xmac_priv *priv, *desc = dwxgmac3_all_errors[module].desc[offset].desc; return 0; } - +#endif /* TC956X_UNSUPPORTED_UNTESTED_FEATURE */ static int dwxgmac3_rxp_disable(struct tc956xmac_priv *priv, void __iomem *ioaddr) { + int limit; u32 val = readl(ioaddr + XGMAC_MTL_OPMODE); val &= ~XGMAC_FRPE; writel(val, ioaddr + XGMAC_MTL_OPMODE); + limit = 10000; + while (limit--) { + if (!(readl(ioaddr + XGMAC_MTL_RXP_CONTROL_STATUS) & XGMAC_RXPI)) + break; + udelay(1); + } + + if (limit < 0) + return -EBUSY; + return 0; } @@ -1833,7 +2186,6 @@ dwxgmac3_rxp_get_next_entry(struct tc956xmac_tc_entry *entries, return &entries[min_prio_idx]; return NULL; } -#endif /* TC956X_UNSUPPORTED_UNTESTED_FEATURE */ static int dwxgmac2_rx_parser_write_entry(struct tc956xmac_priv *priv, struct mac_device_info *hw, struct tc956xmac_rx_parser_entry *entry, int entry_pos) @@ -1883,39 +2235,6 @@ static int dwxgmac2_rx_parser_write_entry(struct tc956xmac_priv *priv, struct ma return 0; } -static void dwxgmac2_rx_parser_enable(struct tc956xmac_priv *priv, struct mac_device_info *hw) -{ - void __iomem *ioaddr = hw->pcsr; - u32 value; - - value = readl(ioaddr + XGMAC_MTL_OPMODE); - value |= XGMAC_FRPE; - writel(value, ioaddr + XGMAC_MTL_OPMODE); -} - -static int dwxgmac2_rx_parser_disable(struct tc956xmac_priv *priv, struct mac_device_info *hw) -{ - void __iomem *ioaddr = hw->pcsr; - u32 value; - int limit; - - value = readl(ioaddr + XGMAC_MTL_OPMODE); - value &= ~XGMAC_FRPE; - writel(value, ioaddr + XGMAC_MTL_OPMODE); - - limit = 10000; - while (limit--) { - if (!(readl(ioaddr + XGMAC_MTL_RXP_CONTROL_STATUS) & XGMAC_RXPI)) - break; - udelay(1); - } - - if (limit < 0) - return -EBUSY; - - return 0; -} - static int dwxgmac2_rx_parser_config(struct tc956xmac_priv *priv, struct mac_device_info *hw, struct tc956xmac_rx_parser_cfg *cfg) { @@ -1960,7 +2279,7 @@ static int dwxgmac2_rx_parser_init(struct tc956xmac_priv *priv, writel(value, ioaddr + XGMAC_RX_CONFIG); /* Disable RX Parser */ - ret = dwxgmac2_rx_parser_disable(priv, hw); + ret = dwxgmac3_rxp_disable(priv, ioaddr); if (ret) { netdev_err(ndev, "Failed to disable RX Parser\n"); return ret; @@ -1981,7 +2300,7 @@ static int dwxgmac2_rx_parser_init(struct tc956xmac_priv *priv, } /* Enable RX Parser */ - dwxgmac2_rx_parser_enable(priv, hw); + dwxgmac3_rxp_enable(priv, ioaddr); /* Restore RX to previous state */ writel(old_value, ioaddr + XGMAC_RX_CONFIG); @@ -1989,7 +2308,6 @@ static int dwxgmac2_rx_parser_init(struct tc956xmac_priv *priv, netdev_info(ndev, "Enabling RX Parser\n"); return 0; } -#ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE static int dwxgmac3_rxp_config(struct tc956xmac_priv *priv, void __iomem *ioaddr, struct tc956xmac_tc_entry *entries, unsigned int count) @@ -2093,6 +2411,7 @@ static int dwxgmac2_get_mac_tx_timestamp(struct tc956xmac_priv *priv, return 0; } +#ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE static int dwxgmac2_flex_pps_config(struct tc956xmac_priv *priv, void __iomem *ioaddr, int index, struct tc956xmac_pps_cfg *cfg, bool enable, @@ -2377,6 +2696,10 @@ static void dwxgmac2_debug(struct tc956xmac_priv *priv, void __iomem *ioaddr, u32 queue; for (queue = 0; queue < tx_queues; queue++) { +#ifdef TC956X_SRIOV_VF + if (priv->plat->tx_q_in_use[queue] == 0) + continue; +#endif value = readl(ioaddr + XGMAC_MTL_TXQ_Debug(queue)); if (value & XGMAC_MTL_DEBUG_TXQSTS) @@ -2400,6 +2723,10 @@ static void dwxgmac2_debug(struct tc956xmac_priv *priv, void __iomem *ioaddr, } for (queue = 0; queue < rx_queues; queue++) { +#ifdef TC956X_SRIOV_VF + if (priv->plat->rx_q_in_use[queue] == 0) + continue; +#endif value = readl(ioaddr + XGMAC_MTL_RXQ_Debug(queue)); if (value & XGMAC_MTL_DEBUG_RXQSTS_MASK) { @@ -2530,6 +2857,7 @@ static void dwxgmac2_set_arp_offload(struct tc956xmac_priv *priv, value &= ~XGMAC_CONFIG_ARPEN; writel(value, ioaddr + XGMAC_RX_CONFIG); } +#endif /* TC956X_UNSUPPORTED_UNTESTED_FEATURE */ #ifdef DEBUG_TSN static int dwxgmac3_est_read(struct tc956xmac_priv *priv, void __iomem *ioaddr, u32 reg, u32 *val, bool gcl) @@ -2537,7 +2865,7 @@ static int dwxgmac3_est_read(struct tc956xmac_priv *priv, void __iomem *ioaddr, u32 ctrl = 0x0; #ifdef GCL_PRINT - static unsigned int count = 0; + static unsigned int count; if (count % 8000 == 0) { if (readl(ioaddr + XGMAC_MTL_EST_STATUS) & XGMAC_SWOL) @@ -2599,7 +2927,7 @@ static int dwxgmac3_est_configure(struct tc956xmac_priv *priv, #if defined(TX_LOGGING_TRACE) int j; u64 read_btr = 0, read_ctr = 0; - static u32 switch_cnt = 0; + static u32 switch_cnt; char *qptr = NULL, *pptr = NULL; int char_buff_size = 100*100; @@ -2651,8 +2979,8 @@ static int dwxgmac3_est_configure(struct tc956xmac_priv *priv, PACKET_IPG, PACKET_CDT_IPG); for (i = 0; i < cfg->gcl_size; i++) { scnprintf((pptr+(i*11)), char_buff_size - (i*11), ",%010d", (cfg->gcl[i]&0xffffff)); - for (j = 0; j < 6; j++) { - scnprintf((qptr+(i*6*2)+(j*2)), char_buff_size - (i*6*2) + (j*2), ",%d", + for (j = 0; j < MTL_MAX_TX_TC; j++) { + scnprintf((qptr+(i*5*2)+(j*2)), char_buff_size - (i*5*2) + (j*2), ",%d", ((cfg->gcl[i]>>(24+j))&0x1)); } } @@ -2706,6 +3034,7 @@ static int dwxgmac3_est_configure(struct tc956xmac_priv *priv, return 0; } +#ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE static void dwxgmac3_fpe_configure(struct tc956xmac_priv *priv, void __iomem *ioaddr, u32 num_txq, u32 num_rxq, bool enable) @@ -2792,9 +3121,7 @@ const struct tc956xmac_ops dwxgmac210_ops = { .prog_mtl_tx_algorithms = dwxgmac2_prog_mtl_tx_algorithms, .set_mtl_tx_queue_weight = dwxgmac2_set_mtl_tx_queue_weight, .map_mtl_to_dma = dwxgmac2_map_mtl_to_dma, -#ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE .config_cbs = dwxgmac2_config_cbs, -#endif /* TC956X_UNSUPPORTED_UNTESTED_FEATURE */ .dump_regs = dwxgmac2_dump_regs, .host_irq_status = dwxgmac2_host_irq_status, .host_mtl_irq_status = dwxgmac2_host_mtl_irq_status, @@ -2811,9 +3138,11 @@ const struct tc956xmac_ops dwxgmac210_ops = { .pcs_ctrl_ane = NULL, .pcs_rane = NULL, .pcs_get_adv_lp = NULL, +#ifndef TC956X_SRIOV_VF #ifdef TC956X .xpcs_init = tc956x_xpcs_init, .xpcs_ctrl_ane = tc956x_xpcs_ctrl_ane, +#endif #endif .debug = dwxgmac2_debug, .set_filter = dwxgmac2_set_filter, @@ -2831,9 +3160,9 @@ const struct tc956xmac_ops dwxgmac210_ops = { .update_vlan_hash = dwxgmac2_update_vlan_hash, .delete_vlan = tc956x_del_sw_vlan_table, .rx_parser_init = dwxgmac2_rx_parser_init, -#ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE .rxp_config = dwxgmac3_rxp_config, .get_mac_tx_timestamp = dwxgmac2_get_mac_tx_timestamp, +#ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE .flex_pps_config = dwxgmac2_flex_pps_config, .sarc_configure = dwxgmac2_sarc_configure, #endif /* TC956X_UNSUPPORTED_UNTESTED_FEATURE */ @@ -2849,7 +3178,9 @@ const struct tc956xmac_ops dwxgmac210_ops = { .config_l3_filter = dwxgmac2_config_l3_filter, .config_l4_filter = dwxgmac2_config_l4_filter, .set_arp_offload = dwxgmac2_set_arp_offload, +#endif /* TC956X_UNSUPPORTED_UNTESTED_FEATURE */ .est_configure = dwxgmac3_est_configure, +#ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE .fpe_configure = dwxgmac3_fpe_configure, .set_ptp_offload = dwxgmac3_set_ptp_offload, #endif /* TC956X_UNSUPPORTED_UNTESTED_FEATURE */ diff --git a/dwxgmac2_descs.c b/dwxgmac2_descs.c index 6e75b943ea56..7075a50ade70 100644 --- a/dwxgmac2_descs.c +++ b/dwxgmac2_descs.c @@ -52,7 +52,9 @@ static int dwxgmac2_get_tx_status(struct tc956xmac_priv *priv, void *data, return tx_dma_own; if (likely(!(tdes3 & XGMAC_TDES3_LD))) return tx_not_ls; - +#ifdef TC956X_SRIOV_VF + priv->sw_stats.tx_frame_count_good_bad++; +#endif return ret; } @@ -61,6 +63,10 @@ static int dwxgmac2_get_rx_status(struct tc956xmac_priv *priv, void *data, struct dma_desc *p) { unsigned int rdes3 = le32_to_cpu(p->des3); +#ifdef TC956X_SRIOV_VF + u32 rdes2 = le32_to_cpu(p->des2), l34t_type = 0; + u32 error_summary = 0, etlt = 0, tnp = 0; +#endif if (unlikely(rdes3 & XGMAC_RDES3_OWN)) return dma_own; @@ -71,6 +77,120 @@ static int dwxgmac2_get_rx_status(struct tc956xmac_priv *priv, void *data, if (unlikely((rdes3 & XGMAC_RDES3_ES) && (rdes3 & XGMAC_RDES3_LD))) return discard_frame; +#ifdef TC956X_SRIOV_VF + l34t_type = (rdes3 & XGMAC_RDES3_L34T) >> XGMAC_RDES3_L34T_SHIFT; + error_summary = (rdes3 & XGMAC_RDES3_ES) >> XGMAC_RDES3_ES_SHIFT; + etlt = (rdes3 & XGMAC_RDES3_ETLT) >> XGMAC_RDES3_ETLT_SHIFT; + tnp = (rdes2 & XGMAC_RDES2_TNP) >> XGMAC_RDES2_TNP_SHIFT; + + + if (!(rdes3 & XGMAC_RDES3_OWN)) { + priv->sw_stats.rx_frame_count_good_bad++; + if (l34t_type == XGMAC_L34T_NON_IP) { + /* Non IP Packet */ + priv->sw_stats.rx_non_ip_pkt_count++; + if (rdes2 & XGMAC_RDES2_AVTDP) + priv->sw_stats.rx_av_tagged_datapacket_count++; + else if (rdes2 & XGMAC_RDES2_AVTCP) + priv->sw_stats.rx_av_tagged_controlpacket_count++; + } else { + /* IP Packet */ + priv->sw_stats.rx_nonav_packet_count++; + priv->sw_stats.rx_header_good_octets += + le32_to_cpu(p->des2) & XGMAC_RDES2_HL; + if (l34t_type == XGMAC_L34T_IPV4_TCP) + priv->sw_stats.rx_ipv4_tcp_pkt_count++; + if (l34t_type == XGMAC_L34T_IPV4_UDP) + priv->sw_stats.rx_ipv4_udp_pkt_count++; + if (l34t_type == XGMAC_L34T_IPV4_ICMP) + priv->sw_stats.rx_ipv4_icmp_pkt_count++; + if (l34t_type == XGMAC_L34T_IPV4_IGMP) + priv->sw_stats.rx_ipv4_igmp_pkt_count++; + if (l34t_type == XGMAC_L34T_IPV4_UNKNOWN) + priv->sw_stats.rx_ipv4_unkown_pkt_count++; + if (l34t_type == XGMAC_L34T_IPV6_TCP) + priv->sw_stats.rx_ipv6_tcp_pkt_count++; + if (l34t_type == XGMAC_L34T_IPV6_UDP) + priv->sw_stats.rx_ipv6_udp_pkt_count++; + if (l34t_type == XGMAC_L34T_IPV6_ICMP) + priv->sw_stats.rx_ipv6_icmp_pkt_count++; + if (l34t_type == XGMAC_L34T_IPV6_UNKNOWN) + priv->sw_stats.rx_ipv6_unkown_pkt_count++; + } + if (error_summary) { + priv->sw_stats.rx_fame_count_bad++; + if (etlt == XGMAC_ET_WD_TIMEOUT) + priv->sw_stats.rx_err_wd_timeout_count++; + if (etlt == XGMAC_ET_INV_GMII) + priv->sw_stats.rx_err_gmii_inv_count++; + if (etlt == XGMAC_ET_CRC) + priv->sw_stats.rx_err_crc_count++; + if (etlt == XGMAC_ET_GIANT_PKT) + priv->sw_stats.rx_err_giant_count++; + if (etlt == XGMAC_ET_IP_HEADER) + priv->sw_stats.rx_err_giant_count++; + if (etlt == XGMAC_ET_L4_CSUM) + priv->sw_stats.rx_err_checksum_count++; + if (etlt == XGMAC_ET_OVERFLOW) + priv->sw_stats.rx_err_overflow_count++; + if (etlt == XGMAC_ET_BUS) + priv->sw_stats.rx_err_bus_count++; + if (etlt == XGMAC_ET_LENGTH) + priv->sw_stats.rx_err_pkt_len_count++; + if (etlt == XGMAC_ET_GOOD_RUNT) + priv->sw_stats.rx_err_runt_pkt_count++; + if (etlt == XGMAC_ET_DRIBBLE) + priv->sw_stats.rx_err_dribble_count++; + if (tnp) { + priv->sw_stats.rx_tunnel_packet_count++; + if (etlt == XGMAC_ET_T_OUTER_IP_HEADER) + priv->sw_stats.rx_err_t_out_ip_header_count++; + if (etlt == XGMAC_ET_T_OUTER_HEADER_PAYLOAD_L4_CSUM) + priv->sw_stats.rx_err_t_out_ip_pl_l4_csum_count++; + if (etlt == XGMAC_ET_T_INNER_IP_HEADER) + priv->sw_stats.rx_err_t_in_ip_header_count++; + if (etlt == XGMAC_ET_T_INNER_L4_PAYLOAD) + priv->sw_stats.rx_err_t_in_ip_pl_l4_csum_count++; + if (etlt == XGMAC_ET_T_INV_VXLAN_HEADER) + priv->sw_stats.rx_err_t_invalid_vlan_header++; + } + } else { + priv->sw_stats.rx_frame_count_good++; + priv->sw_stats.rx_packet_good_octets += + (rdes3 & XGMAC_RDES3_PL); + priv->sw_stats.rx_header_good_octets += + le32_to_cpu(p->des2) & XGMAC_RDES2_HL; + if (etlt == XGMAC_LT_LENGTH) + priv->sw_stats.rx_l2_len_pkt_count++; + if (etlt == XGMAC_LT_MAC_CONTROL) + priv->sw_stats.rx_l2_mac_control_pkt_count++; + if (etlt == XGMAC_LT_DCB_CONTROL) + priv->sw_stats.rx_l2_dcb_control_pkt_count++; + if (etlt == XGMAC_LT_ARP_REQ) + priv->sw_stats.rx_l2_arp_pkt_count++; + if (etlt == XGMAC_LT_OAM) + priv->sw_stats.rx_l2_oam_type_pkt_count++; + if (etlt == XGMAC_LT_MAC_RX_ETH_TYPE_MATCH) + priv->sw_stats.rx_l2_untg_typ_match_pkt_count++; + if (etlt == XGMAC_LT_OTH_TYPE) + priv->sw_stats.rx_l2_other_type_pkt_count++; + if (etlt == XGMAC_LT_SVLAN) + priv->sw_stats.rx_l2_single_svlan_pkt_count++; + if (etlt == XGMAC_LT_CVLAN) + priv->sw_stats.rx_l2_single_cvlan_pkt_count++; + if (etlt == XGMAC_LT_D_CVLAN_CVLAN) + priv->sw_stats.rx_l2_d_cvlan_cvlan_pkt_count++; + if (etlt == XGMAC_LT_D_SVLAN_SVLAN) + priv->sw_stats.rx_l2_d_svlan_svlan_pkt_count++; + if (etlt == XGMAC_LT_D_SVLAN_CVLAN) + priv->sw_stats.rx_l2_d_svlan_cvlan_pkt_count++; + if (etlt == XGMAC_LT_D_CVLAN_SVLAN) + priv->sw_stats.rx_l2_d_cvlan_svlan_pkt_count++; + if (etlt == XGMAC_LT_UNTAG_AV_CONTROL) + priv->sw_stats.rx_l2_untg_av_control_pkt_count++; + } + } +#endif /* #ifdef TC956X_SRIOV_VF */ return good_frame; } @@ -112,7 +232,6 @@ static int dwxgmac2_get_rx_frame_len(struct tc956xmac_priv *priv, return (le32_to_cpu(p->des3) & XGMAC_RDES3_PL); } -#ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE static void dwxgmac2_enable_tx_timestamp(struct tc956xmac_priv *priv, struct dma_desc *p) { @@ -162,25 +281,70 @@ static int dwxgmac2_rx_check_timestamp(struct tc956xmac_priv *priv, void *desc) return 0; } - return -EINVAL; + /* Timestamp not ready */ + return 1; } -#endif /* TC956X_UNSUPPORTED_UNTESTED_FEATURE */ static int dwxgmac2_get_rx_timestamp_status(struct tc956xmac_priv *priv, void *desc, void *next_desc, u32 ats) { -#ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE struct dma_desc *p = (struct dma_desc *)desc; unsigned int rdes3 = le32_to_cpu(p->des3); -#endif /* TC956X_UNSUPPORTED_UNTESTED_FEATURE */ int ret = -EBUSY; + unsigned int i = 0; +#ifdef TC956X_SRIOV_VF + u32 message_type; +#endif + if (likely(rdes3 & XGMAC_RDES3_CDA)) { + do { + ret = dwxgmac2_rx_check_timestamp(priv, next_desc); + if (ret < 0) + goto exit; -#ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE - if (likely(rdes3 & XGMAC_RDES3_CDA)) - ret = dwxgmac2_rx_check_timestamp(priv, next_desc); -#endif /* TC956X_UNSUPPORTED_UNTESTED_FEATURE */ + i++; + if (ret == 1) + udelay(1); + + } while ((ret == 1) && (i < 25)); + + if (i == 25) + ret = -EBUSY; + } + +#ifdef TC956X_SRIOV_VF + /* Read frame type to SW MMC counters from PMT bits in RDES3 */ + if ((rdes3 & XGMAC_RDES3_OWN) && (rdes3 & XGMAC_RDES3_CTXT)) { + + message_type = (rdes3 & XGMAC_RDES3_PMT); + if (message_type == RDES_PMT_NO_PTP) + priv->sw_stats.rx_ptp_no_msg++; + else if (message_type == RDES_PMT_SYNC) + priv->sw_stats.rx_ptp_msg_type_sync++; + else if (message_type == RDES_PMT_FOLLOW_UP) + priv->sw_stats.rx_ptp_msg_type_follow_up++; + else if (message_type == RDES_PMT_DELAY_REQ) + priv->sw_stats.rx_ptp_msg_type_delay_req++; + else if (message_type == RDES_PMT_DELAY_RESP) + priv->sw_stats.rx_ptp_msg_type_delay_resp++; + else if (message_type == RDES_PMT_PDELAY_REQ) + priv->sw_stats.rx_ptp_msg_type_pdelay_req++; + else if (message_type == RDES_PMT_PDELAY_RESP) + priv->sw_stats.rx_ptp_msg_type_pdelay_resp++; + else if (message_type == RDES_PMT_PDELAY_FOLLOW_UP) + priv->sw_stats.rx_ptp_msg_type_pdelay_follow_up++; + else if (message_type == RDES_PMT_PTP_ANNOUNCE) + priv->sw_stats.rx_ptp_msg_type_announce++; + else if (message_type == RDES_PMT_PTP_MANAGEMENT) + priv->sw_stats.rx_ptp_msg_type_management++; + else if (message_type == RDES_PMT_PTP_SIGNALING) + priv->sw_stats.rx_ptp_msg_pkt_signaling++; + else if (message_type == RDES_PMT_PTP_PKT_RESERVED_TYPE) + priv->sw_stats.rx_ptp_msg_pkt_reserved_type++; + } +#endif +exit: return !ret; } @@ -334,7 +498,6 @@ static void dwxgmac2_get_addr(struct tc956xmac_priv *priv, static void dwxgmac2_set_addr(struct tc956xmac_priv *priv, struct dma_desc *p, dma_addr_t addr) { - //printk("%s, buff addr = 0x%llx\n",__func__, addr); p->des0 = cpu_to_le32(lower_32_bits(addr)); #ifdef TC956X /* Set the mask for physical address access */ @@ -344,7 +507,6 @@ static void dwxgmac2_set_addr(struct tc956xmac_priv *priv, p->des1 = cpu_to_le32(upper_32_bits(addr)); #endif - //printk(" pdes0 = 0x%x. pdes1 = 0x%x\n", p->des0, p->des1); } static void dwxgmac2_clear(struct tc956xmac_priv *priv, struct dma_desc *p) @@ -442,14 +604,15 @@ static void dwxgmac2_set_vlan(struct tc956xmac_priv *priv, struct dma_desc *p, p->des2 |= cpu_to_le32(type & XGMAC_TDES2_VTIR); } -#ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE static void dwxgmac2_set_tbs(struct tc956xmac_priv *priv, struct dma_edesc *p, u32 sec, u32 nsec, bool lt_valid) { p->des4 = 0; - if (lt_valid) + p->des5 = 0; + if (lt_valid) { p->des4 = cpu_to_le32((sec & XGMAC_TDES0_LT) | XGMAC_TDES0_LTV); - p->des5 = cpu_to_le32(nsec & XGMAC_TDES1_LT); + p->des5 = cpu_to_le32(nsec & XGMAC_TDES1_LT); + } p->des6 = 0; p->des7 = 0; } @@ -469,7 +632,6 @@ static void dwxgmac2_set_ostc(struct tc956xmac_priv *priv, /* Set Context Type for Context descriptor */ p->des3 |= cpu_to_le32(XGMAC_TDES3_CTXT); } -#endif /* TC956X_UNSUPPORTED_UNTESTED_FEATURE */ const struct tc956xmac_desc_ops dwxgmac210_desc_ops = { .tx_status = dwxgmac2_get_tx_status, @@ -484,14 +646,10 @@ const struct tc956xmac_desc_ops dwxgmac210_desc_ops = { .get_tx_ls = dwxgmac2_get_tx_ls, #endif /* TC956X_UNSUPPORTED_UNTESTED_FEATURE */ .get_rx_frame_len = dwxgmac2_get_rx_frame_len, -#ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE .enable_tx_timestamp = dwxgmac2_enable_tx_timestamp, .get_tx_timestamp_status = dwxgmac2_get_tx_timestamp_status, -#endif /* TC956X_UNSUPPORTED_UNTESTED_FEATURE */ .get_rx_timestamp_status = dwxgmac2_get_rx_timestamp_status, -#ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE .get_timestamp = dwxgmac2_get_timestamp, -#endif /* TC956X_UNSUPPORTED_UNTESTED_FEATURE */ .set_tx_ic = dwxgmac2_set_tx_ic, .prepare_tx_desc = dwxgmac2_prepare_tx_desc, .prepare_tso_tx_desc = dwxgmac2_prepare_tso_tx_desc, @@ -510,8 +668,6 @@ const struct tc956xmac_desc_ops dwxgmac210_desc_ops = { .set_sarc = dwxgmac2_set_sarc, .set_vlan_tag = dwxgmac2_set_vlan_tag, .set_vlan = dwxgmac2_set_vlan, -#ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE .set_tbs = dwxgmac2_set_tbs, .set_ostc = dwxgmac2_set_ostc, -#endif /* TC956X_UNSUPPORTED_UNTESTED_FEATURE */ }; diff --git a/dwxgmac2_dma.c b/dwxgmac2_dma.c index 050780da6b4f..6bed14992a47 100644 --- a/dwxgmac2_dma.c +++ b/dwxgmac2_dma.c @@ -45,6 +45,9 @@ * 29 Apr 2022 : 1. Checking for DMA status update as stop after TX DMA stop * 2. Checking for Tx MTL Queue Read/Write contollers in idle state after TX DMA stop * VERSION : 01-00-51 + * 26 Dec 2023 : 1. Kernel 6.6 Porting changes + * VERSION : 01-03-59 + * */ #include @@ -211,11 +214,17 @@ static void dwxgmac2_dma_dump_regs(struct tc956xmac_priv *priv, { int i; - for (i = ETH_DMA_DUMP_OFFSET1; i <= ETH_DMA_DUMP_OFFSET1_END; i++) + for (i = ETH_DMA_DUMP_OFFSET1; i <= ETH_DMA_DUMP_OFFSET1_END; i++) { reg_space[i] = readl(ioaddr + MAC_OFFSET + (4 * i)); + KPRINT_DEBUG1("%04x : %08x\n", i*4, reg_space[i]); + } - for (i = ETH_DMA_DUMP_OFFSET2; i < XGMAC_REGSIZE; i++) + for (i = ETH_DMA_DUMP_OFFSET2; i < XGMAC_REGSIZE; i++) { reg_space[i] = readl(ioaddr + MAC_OFFSET + (4 * i)); + KPRINT_DEBUG1("%04x : %08x\n", i*4, reg_space[i]); + } + + KPRINT_DEBUG1("**********************************************************************************"); } /** @@ -365,22 +374,32 @@ static void dwxgmac2_dma_start_tx(struct tc956xmac_priv *priv, value |= XGMAC_TXST; writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan)); -#ifndef DMA_OFFLOAD_ENABLE + /* TE set will enable all the MAC transmisster, PF to configure when + * starting its channel for tranmission + */ +#ifndef TC956X_SRIOV_VF +#ifndef TC956X_DMA_OFFLOAD_ENABLE value = readl(ioaddr + XGMAC_TX_CONFIG); value |= XGMAC_CONFIG_TE; writel(value, ioaddr + XGMAC_TX_CONFIG); #endif +#endif } static void dwxgmac2_dma_stop_tx(struct tc956xmac_priv *priv, void __iomem *ioaddr, u32 chan) { - u32 value, limit; + u32 value; + int limit; value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan)); value &= ~XGMAC_TXST; writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan)); + /* TE reset will disable the MAC transmisster, it is possible that + * other MAC channels are used by other VF/PF. So donot configure this + */ + /*Check whether Tx DMA is in stop state */ limit = 10000; while (limit--) { @@ -423,11 +442,13 @@ static void dwxgmac2_dma_stop_tx(struct tc956xmac_priv *priv, DBGPR_FUNC(priv->device, "%s MTL TXQ status after flush: 0x%x, limit [%d]\n", __func__, readl(ioaddr + XGMAC_MTL_TXQ_Debug(chan)), limit); -#ifndef DMA_OFFLOAD_ENABLE +#ifndef TC956X_SRIOV_VF +#ifndef TC956X_DMA_OFFLOAD_ENABLE value = readl(ioaddr + XGMAC_TX_CONFIG); value &= ~XGMAC_CONFIG_TE; writel(value, ioaddr + XGMAC_TX_CONFIG); #endif +#endif } static void dwxgmac2_dma_start_rx(struct tc956xmac_priv *priv, @@ -439,11 +460,16 @@ static void dwxgmac2_dma_start_rx(struct tc956xmac_priv *priv, value |= XGMAC_RXST; writel(value, ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan)); -#ifndef DMA_OFFLOAD_ENABLE + /* RE set will enable all the MAC receiver, PF to configure when + * starting its channel for reception + */ +#ifndef TC956X_SRIOV_VF +#ifndef TC956X_DMA_OFFLOAD_ENABLE value = readl(ioaddr + XGMAC_RX_CONFIG); value |= XGMAC_CONFIG_RE; writel(value, ioaddr + XGMAC_RX_CONFIG); #endif +#endif } static void dwxgmac2_dma_stop_rx(struct tc956xmac_priv *priv, @@ -455,11 +481,13 @@ static void dwxgmac2_dma_stop_rx(struct tc956xmac_priv *priv, value &= ~XGMAC_RXST; writel(value, ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan)); -#ifndef DMA_OFFLOAD_ENABLE +#ifndef TC956X_SRIOV_VF +#ifndef TC956X_DMA_OFFLOAD_ENABLE value = readl(ioaddr + XGMAC_RX_CONFIG); value &= ~XGMAC_CONFIG_RE; writel(value, ioaddr + XGMAC_RX_CONFIG); #endif +#endif } static int dwxgmac2_dma_interrupt(struct tc956xmac_priv *priv, void __iomem *ioaddr, @@ -485,8 +513,6 @@ static int dwxgmac2_dma_interrupt(struct tc956xmac_priv *priv, void __iomem *ioa } } - //printk("%s 1 status = 0x%x\n", __func__, intr_status); - /* TX/RX NORMAL interrupts */ // if (likely(intr_status & XGMAC_NIS)) { if (1) { @@ -594,7 +620,11 @@ static void dwxgmac2_get_hw_feature(struct tc956xmac_priv *priv, dma_cap->dvlan = (hw_cap & XGMAC_HWFEAT_DVLAN) >> 13; dma_cap->frpes = (hw_cap & XGMAC_HWFEAT_FRPES) >> 11; dma_cap->frpbs = (hw_cap & XGMAC_HWFEAT_FRPPB) >> 9; +#ifndef TC956X_SRIOV_VF dma_cap->frpsel = (hw_cap & XGMAC_HWFEAT_FRPSEL) >> 3; +#elif (defined TC956X_SRIOV_VF) + dma_cap->frpsel = 0; /* VF to not support FRP */ +#endif switch (dma_cap->frpes) { default: dma_cap->frpes = 0; @@ -618,14 +648,36 @@ static void dwxgmac2_get_hw_feature(struct tc956xmac_priv *priv, static void dwxgmac2_rx_watchdog(struct tc956xmac_priv *priv, void __iomem *ioaddr, u32 riwt, u32 nchan) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 13, 0)) +#ifdef TC956X_SRIOV_PF + if (priv->plat->rx_ch_in_use[nchan] == TC956X_DISABLE_CHNL) + return; +#elif (defined TC956X_SRIOV_VF) + if (priv->plat->ch_in_use[nchan] == NOT_USED) + return; +#else + if (priv->plat->rx_dma_ch_owner[nchan] != USE_IN_TC956X_SW) + return; +#endif + + writel(riwt & XGMAC_RWT, ioaddr + XGMAC_DMA_CH_Rx_WATCHDOG(nchan)); +#else u32 i; for (i = 0; i < nchan; i++) { +#ifdef TC956X_SRIOV_PF + if (priv->plat->rx_ch_in_use[i] == TC956X_DISABLE_CHNL) + continue; +#elif (defined TC956X_SRIOV_VF) + if (priv->plat->ch_in_use[i] == NOT_USED) + continue; +#else if (priv->plat->rx_dma_ch_owner[i] != USE_IN_TC956X_SW) continue; - +#endif writel(riwt & XGMAC_RWT, ioaddr + XGMAC_DMA_CH_Rx_WATCHDOG(i)); } +#endif } static void dwxgmac2_set_rx_ring_len(struct tc956xmac_priv *priv, @@ -649,9 +701,6 @@ static void dwxgmac2_set_rx_tail_ptr(struct tc956xmac_priv *priv, void __iomem *ioaddr, u32 ptr, u32 chan) { writel(ptr, ioaddr + XGMAC_DMA_CH_RxDESC_TAIL_LPTR(chan)); - //printk("%s, reg 0x%x = 0x%x, input = 0x%x\n", __func__, XGMAC_DMA_CH_RxDESC_TAIL_LPTR(chan), - // readl(ioaddr + XGMAC_DMA_CH_RxDESC_TAIL_LPTR(chan)), ptr); - } @@ -659,7 +708,6 @@ static void dwxgmac2_set_tx_tail_ptr(struct tc956xmac_priv *priv, void __iomem *ioaddr, u32 ptr, u32 chan) { writel(ptr, ioaddr + XGMAC_DMA_CH_TxDESC_TAIL_LPTR(chan)); - //printk("%s\n", __func__); } static void dwxgmac2_enable_tso(struct tc956xmac_priv *priv, @@ -680,22 +728,25 @@ static void dwxgmac2_qmode(struct tc956xmac_priv *priv, void __iomem *ioaddr, u32 channel, u8 qmode) { u32 value = readl(ioaddr + XGMAC_MTL_TXQ_OPMODE(channel)); +#ifndef TC956X_SRIOV_VF u32 flow = readl(ioaddr + XGMAC_RX_FLOW_CTRL); - +#endif value &= ~XGMAC_TXQEN; if (qmode != MTL_QUEUE_AVB) { value |= 0x2 << XGMAC_TXQEN_SHIFT; //writel(0, ioaddr + XGMAC_MTL_TCx_ETS_CONTROL(channel)); } else { value |= 0x1 << XGMAC_TXQEN_SHIFT; + /* RFE configuration is handled in PF driver */ +#ifndef TC956X_SRIOV_VF writel(flow & (~XGMAC_RFE), ioaddr + XGMAC_RX_FLOW_CTRL); +#endif } writel(value, ioaddr + XGMAC_MTL_TXQ_OPMODE(channel)); } #endif /* TC956X_UNSUPPORTED_UNTESTED_FEATURE */ - static void dwxgmac2_set_bfsize(struct tc956xmac_priv *priv, void __iomem *ioaddr, int bfsize, u32 chan) { @@ -712,10 +763,12 @@ static void dwxgmac2_enable_sph(struct tc956xmac_priv *priv, { u32 value = readl(ioaddr + XGMAC_RX_CONFIG); + /* Common register configuration only done in PF driver */ +#ifndef TC956X_SRIOV_VF value &= ~XGMAC_CONFIG_HDSMS; value |= XGMAC_CONFIG_HDSMS_256; /* Segment max 256 bytes */ writel(value, ioaddr + XGMAC_RX_CONFIG); - +#endif value = readl(ioaddr + XGMAC_DMA_CH_CONTROL(chan)); if (en) value |= XGMAC_SPH; @@ -742,24 +795,29 @@ static int dwxgmac2_enable_tbs(struct tc956xmac_priv *priv, void __iomem *ioaddr if (en && !value) return -EIO; - writel((100 < XGMAC_FTOS_SHIFT) | (1 << XGMAC_FGOS_SHIFT) | XGMAC_FTOV, + /* Below configuration done on common DMA registers + * so PF driver can configure this. + */ + writel((100 << XGMAC_FTOS_SHIFT) | (1 << XGMAC_FGOS_SHIFT) | XGMAC_FTOV, ioaddr + XGMAC_DMA_TBS_CTRL0); - writel((100 < XGMAC_FTOS_SHIFT) | (1 << XGMAC_FGOS_SHIFT) | XGMAC_FTOV, + writel((100 << XGMAC_FTOS_SHIFT) | (1 << XGMAC_FGOS_SHIFT) | XGMAC_FTOV, ioaddr + XGMAC_DMA_TBS_CTRL1); - writel((100 < XGMAC_FTOS_SHIFT) | (1 << XGMAC_FGOS_SHIFT) | XGMAC_FTOV, + writel((100 << XGMAC_FTOS_SHIFT) | (1 << XGMAC_FGOS_SHIFT) | XGMAC_FTOV, ioaddr + XGMAC_DMA_TBS_CTRL2); - writel((100 < XGMAC_FTOS_SHIFT) | (1 << XGMAC_FGOS_SHIFT) | XGMAC_FTOV, + writel((100 << XGMAC_FTOS_SHIFT) | (1 << XGMAC_FGOS_SHIFT) | XGMAC_FTOV, ioaddr + XGMAC_DMA_TBS_CTRL3); - return 0; } static void dwxgmac2_desc_stats(struct tc956xmac_priv *priv, void __iomem *ioaddr) { u32 chno; -//printk("%s\n", __func__); - for (chno = 0; chno < priv->plat->tx_queues_to_use; chno++) { + for (chno = 0; chno < priv->plat->tx_queues_to_use; chno++) { +#ifdef TC956X_SRIOV_VF + if (priv->plat->ch_in_use[chno] == 0) + continue; +#endif priv->xstats.txch_status[chno] = readl(ioaddr + XGMAC_DMA_CH_STATUS(chno)); priv->xstats.txch_control[chno] = @@ -785,7 +843,10 @@ static void dwxgmac2_desc_stats(struct tc956xmac_priv *priv, void __iomem *ioadd } for (chno = 0; chno < priv->plat->rx_queues_to_use; chno++) { - +#ifdef TC956X_SRIOV_VF + if (priv->plat->ch_in_use[chno] == 0) + continue; +#endif priv->xstats.rxch_status[chno] = readl(ioaddr + XGMAC_DMA_CH_STATUS(chno)); priv->xstats.rxch_control[chno] = diff --git a/hwif.c b/hwif.c index f0183fa4eee2..59ecac43f87c 100644 --- a/hwif.c +++ b/hwif.c @@ -35,10 +35,12 @@ #include "common.h" #include "tc956xmac.h" #include "tc956xmac_ptp.h" +#ifndef TC956X_SRIOV_VF #ifdef TC956X #include "tc956x_xpcs.h" #include "tc956x_pma.h" #endif +#endif static u32 tc956xmac_get_id(struct tc956xmac_priv *priv, u32 id_reg) { @@ -117,6 +119,12 @@ static const struct tc956xmac_hwif_entry { const void *tc; const void *mmc; const void *pma; +#if defined(TC956X_SRIOV_PF) | defined(TC956X_SRIOV_VF) + const void *msi; + const void *rsc; + const void *mbx; + const void *mbx_wrapper; +#endif int (*setup)(struct tc956xmac_priv *priv); int (*quirks)(struct tc956xmac_priv *priv); } tc956xmac_hw[] = { @@ -240,9 +248,11 @@ static const struct tc956xmac_hwif_entry { .regs = { .ptp_off = PTP_XGMAC_OFFSET_BASE, .mmc_off = MMC_XGMAC_OFFSET_BASE, +#ifndef TC956X_SRIOV_VF #ifdef TC956X .xpcs_off = XPCS_XGMAC_OFFSET, .pma_off = PMA_XGMAC_OFFSET, +#endif #endif }, .desc = &dwxgmac210_desc_ops, @@ -252,8 +262,19 @@ static const struct tc956xmac_hwif_entry { .mode = NULL, .tc = &dwmac510_tc_ops, .mmc = &dwxgmac_mmc_ops, +#ifndef TC956X_SRIOV_VF #ifdef TC956X .pma = &tc956x_pma_ops, +#endif +#endif +#if defined(TC956X_SRIOV_PF) | defined(TC956X_SRIOV_VF) + .msi = &tc956x_msigen_ops, + .rsc = &tc956xmac_rsc_mng_ops, +#endif + +#if (defined(TC956X_SRIOV_PF) && !defined(TC956X_AUTOMOTIVE_CONFIG) && !defined(TC956X_ENABLE_MAC2MAC_BRIDGE)) | defined(TC956X_SRIOV_VF) + .mbx = &tc956xmac_mbx_ops, + .mbx_wrapper = &tc956xmac_mbx_wrapper_ops, #endif .setup = dwxgmac2_setup, .quirks = NULL, @@ -288,9 +309,11 @@ int tc956xmac_hwif_init(struct tc956xmac_priv *priv) (needs_gmac4 ? PTP_GMAC4_OFFSET : PTP_GMAC3_X_OFFSET); priv->mmcaddr = priv->ioaddr + (needs_gmac4 ? MMC_GMAC4_OFFSET : MMC_GMAC3_X_OFFSET); +#ifndef TC956X_SRIOV_VF #ifdef TC956X priv->xpcsaddr = priv->ioaddr + XPCS_XGMAC_OFFSET; priv->pmaaddr = priv->ioaddr + PMA_XGMAC_OFFSET; +#endif #endif /* Check for HW specific setup first */ @@ -326,14 +349,23 @@ int tc956xmac_hwif_init(struct tc956xmac_priv *priv) mac->mode = mac->mode ? : entry->mode; mac->tc = mac->tc ? : entry->tc; mac->mmc = mac->mmc ? : entry->mmc; +#ifndef TC956X_SRIOV_VF mac->pma = mac->pma ? : entry->pma; - +#endif +#if defined(TC956X_SRIOV_PF) | defined(TC956X_SRIOV_VF) + mac->msi = mac->msi ? : entry->msi; + mac->rsc = mac->rsc ? : entry->rsc; + mac->mbx = mac->mbx ? : entry->mbx; + mac->mbx_wrapper = mac->mbx_wrapper ? : entry->mbx_wrapper; +#endif priv->hw = mac; priv->ptpaddr = priv->ioaddr + mac_offset_base + entry->regs.ptp_off; priv->mmcaddr = priv->ioaddr + mac_offset_base + entry->regs.mmc_off; +#ifndef TC956X_SRIOV_VF #ifdef TC956X priv->xpcsaddr = priv->ioaddr + mac_offset_base + entry->regs.xpcs_off; priv->pmaaddr = priv->ioaddr + mac_offset_base + entry->regs.pma_off; +#endif #endif /* Entry found */ if (needs_setup) { diff --git a/hwif.h b/hwif.h index 073d193954c1..a375c6fb3a7e 100644 --- a/hwif.h +++ b/hwif.h @@ -39,6 +39,8 @@ * VERSION : 01-00-13 * 04 Nov 2021 : 1. Added separate control functons for MAC TX and RX start/stop * VERSION : 01-00-20 + * 26 Dec 2023 : 1. Added the support for TC commands taprio and flower + * VERSION : 01-03-59 */ #ifndef __TC956XMAC_HWIF_H__ @@ -46,6 +48,7 @@ #include #include "tc956xmac_inc.h" +#include #define tc956xmac_do_void_callback(__priv, __module, __cname, __arg0, __args...) \ ({ \ @@ -63,6 +66,15 @@ __result = (__priv)->hw->__module->__cname(__priv, (__arg0), ##__args); \ __result; \ }) +#define tc956xmac_do_void_no_param_callback(__priv, __module, __cname) \ +({ \ + int __result = -EINVAL; \ + if ((__priv)->hw->__module && (__priv)->hw->__module->__cname) { \ + (__priv)->hw->__module->__cname(__priv); \ + __result = 0; \ + } \ + __result; \ +}) struct tc956xmac_priv; struct tc956xmac_extra_stats; @@ -71,6 +83,11 @@ struct dma_desc; struct dma_extended_desc; struct dma_edesc; +#if defined(TC956X_SRIOV_PF) | defined(TC956X_SRIOV_VF) +struct fn_id; +enum mbx_msg_fns; +#endif + /* Descriptors helpers */ struct tc956xmac_desc_ops { /* DMA RX descriptor ring initialization */ @@ -279,8 +296,13 @@ struct tc956xmac_dma_ops { tc956xmac_do_void_callback(__priv, dma, dump_regs, __args) #define tc956xmac_dma_rx_mode(__priv, __args...) \ tc956xmac_do_void_callback(__priv, dma, dma_rx_mode, __args) +#ifdef TC956X_SRIOV_PF #define tc956xmac_dma_tx_mode(__priv, __args...) \ tc956xmac_do_void_callback(__priv, dma, dma_tx_mode, __args) +#elif (defined TC956X_SRIOV_VF) +#define tc956xmac_dma_tx_mode(__priv, __args...) \ + tc956xmac_do_void_callback(__priv, mbx_wrapper, dma_tx_mode, __args) +#endif #define tc956xmac_dma_diagnostic_fr(__priv, __args...) \ tc956xmac_do_void_callback(__priv, dma, dma_diagnostic_fr, __args) #define tc956xmac_enable_dma_transmission(__priv, __args...) \ @@ -361,7 +383,7 @@ struct tc956xmac_ops { void (*prog_mtl_tx_algorithms)(struct tc956xmac_priv *priv, struct mac_device_info *hw, u32 tx_alg); /* Set MTL TX queues weight */ void (*set_mtl_tx_queue_weight)(struct tc956xmac_priv *priv, struct mac_device_info *hw, - u32 weight, u32 queue); + u32 weight, u32 tc); /* RX MTL queue to RX dma mapping */ void (*map_mtl_to_dma)(struct tc956xmac_priv *priv, struct mac_device_info *hw, u32 queue, u32 chan); /* Configure AV Algorithm */ @@ -474,20 +496,56 @@ struct tc956xmac_ops { tc956xmac_do_void_callback(__priv, mac, rx_queue_enable, __args) #define tc956xmac_rx_queue_prio(__priv, __args...) \ tc956xmac_do_void_callback(__priv, mac, rx_queue_prio, __args) +#ifdef TC956X_SRIOV_PF #define tc956xmac_tx_queue_prio(__priv, __args...) \ tc956xmac_do_void_callback(__priv, mac, tx_queue_prio, __args) +#elif (defined TC956X_SRIOV_VF) +#define tc956xmac_tx_queue_prio(__priv, __args...) \ + tc956xmac_do_void_callback(__priv, mbx_wrapper, tx_queue_prio, __args) +#endif #define tc956xmac_rx_queue_routing(__priv, __args...) \ tc956xmac_do_void_callback(__priv, mac, rx_queue_routing, __args) #define tc956xmac_prog_mtl_rx_algorithms(__priv, __args...) \ tc956xmac_do_void_callback(__priv, mac, prog_mtl_rx_algorithms, __args) #define tc956xmac_prog_mtl_tx_algorithms(__priv, __args...) \ tc956xmac_do_void_callback(__priv, mac, prog_mtl_tx_algorithms, __args) +#ifdef TC956X_SRIOV_PF #define tc956xmac_set_mtl_tx_queue_weight(__priv, __args...) \ tc956xmac_do_void_callback(__priv, mac, set_mtl_tx_queue_weight, __args) +#elif (defined TC956X_SRIOV_VF) +#define tc956xmac_set_mtl_tx_queue_weight(__priv, __args...) \ + tc956xmac_do_void_callback(__priv, mbx_wrapper, set_mtl_tx_queue_weight, __args) +#endif + #define tc956xmac_map_mtl_to_dma(__priv, __args...) \ tc956xmac_do_void_callback(__priv, mac, map_mtl_to_dma, __args) +#ifdef TC956X_SRIOV_PF #define tc956xmac_config_cbs(__priv, __args...) \ tc956xmac_do_void_callback(__priv, mac, config_cbs, __args) +#elif defined TC956X_SRIOV_VF +#define tc956xmac_config_cbs(__priv, __args...) \ + tc956xmac_do_void_callback(__priv, mbx_wrapper, config_cbs, __args) +#endif + +#ifdef TC956X_SRIOV_VF +#define tc956x_phy_link(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, phy_link, __args) +#define tc956x_setup_mbx_etf(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, setup_mbx_etf, __args) +#define tc956x_get_drv_cap(__priv, __args...) \ + tc956xmac_do_void_callback(__priv, mbx_wrapper, get_drv_cap, __args) +#define tc956x_rx_crc(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, rx_crc, __args) +#define tc956x_rx_dma_ch_tlptr(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, rx_dma_ch_tlptr, __args) +#define tc956x_rx_dma_err(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, rx_dma_err, __args) +#define tc956x_rx_csum(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, rx_csum, __args) +#define tc956x_mbx_flr(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, pf_flr, __args) +#endif + #define tc956xmac_dump_mac_regs(__priv, __args...) \ tc956xmac_do_void_callback(__priv, mac, dump_regs, __args) #define tc956xmac_host_irq_status(__priv, __args...) \ @@ -500,14 +558,29 @@ struct tc956xmac_ops { tc956xmac_do_void_callback(__priv, mac, flow_ctrl, __args) #define tc956xmac_pmt(__priv, __args...) \ tc956xmac_do_void_callback(__priv, mac, pmt, __args) +#ifdef TC956X_SRIOV_PF #define tc956xmac_set_umac_addr(__priv, __args...) \ tc956xmac_do_void_callback(__priv, mac, set_umac_addr, __args) +#elif (defined TC956X_SRIOV_VF) +#define tc956xmac_set_umac_addr(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, set_umac_addr, __args) +#endif +#ifdef TC956X_SRIOV_PF #define tc956xmac_get_umac_addr(__priv, __args...) \ tc956xmac_do_void_callback(__priv, mac, get_umac_addr, __args) +#elif (defined TC956X_SRIOV_VF) +#define tc956xmac_get_umac_addr(__priv, __args...) \ + tc956xmac_do_void_callback(__priv, mbx_wrapper, get_umac_addr, __args) +#endif #define tc956xmac_set_eee_mode(__priv, __args...) \ tc956xmac_do_void_callback(__priv, mac, set_eee_mode, __args) +#ifdef TC956X_SRIOV_VF +#define tc956xmac_reset_eee_mode(__priv, __args...) \ + tc956xmac_do_void_callback(__priv, mbx_wrapper, reset_eee_mode, __args) +#else #define tc956xmac_reset_eee_mode(__priv, __args...) \ tc956xmac_do_void_callback(__priv, mac, reset_eee_mode, __args) +#endif #define tc956xmac_set_eee_timer(__priv, __args...) \ tc956xmac_do_void_callback(__priv, mac, set_eee_timer, __args) #define tc956xmac_set_eee_pls(__priv, __args...) \ @@ -544,8 +617,13 @@ struct tc956xmac_ops { tc956xmac_do_callback(__priv, mac, rss_configure, __args) #define tc956xmac_update_vlan_hash(__priv, __args...) \ tc956xmac_do_void_callback(__priv, mac, update_vlan_hash, __args) +#ifdef TC956X_SRIOV_PF #define tc956xmac_delete_vlan(__priv, __args...) \ tc956xmac_do_void_callback(__priv, mac, delete_vlan, __args) +#else //TC956X_SRIOV_PF +#define tc956xmac_delete_vlan(__priv, __args...) \ + tc956xmac_do_void_callback(__priv, mbx_wrapper, delete_vlan, __args) +#endif #define tc956xmac_enable_vlan(__priv, __args...) \ tc956xmac_do_void_callback(__priv, mac, enable_vlan, __args) #ifdef TC956X @@ -578,7 +656,53 @@ struct tc956xmac_ops { tc956xmac_do_void_callback(__priv, mac, set_ptp_offload, __args) #define tc956xmac_jumbo_en(__priv, __args...) \ tc956xmac_do_void_callback(__priv, mac, jumbo_en, __args) +#ifdef TC956X_SRIOV_VF +#define tc956xmac_get_speed(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, get_speed, __args) +#define tc956xmac_get_est(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, get_est, __args) +#define tc956xmac_set_est(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, set_est, __args) +#define tc956xmac_get_rxp(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, get_rxp, __args) +#define tc956xmac_set_rxp(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, set_rxp, __args) +#define tc956xmac_get_fpe(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, get_fpe, __args) +#define tc956xmac_set_fpe(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, set_fpe, __args) +#define tc956xmac_reg_wr(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, reg_wr, __args) +#define tc956xmac_get_cbs(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, get_cbs, __args) + +#define tc956xmac_set_cbs(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, set_cbs, __args) + +#define tc956xmac_ethtool_get_pauseparam(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, get_pause_param, __args) + +#define tc956xmac_ethtool_get_eee(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, get_eee, __args) + + +#define tc956xmac_add_mac(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, add_mac, __args) + +#define tc956xmac_delete_mac(__priv, __args...) \ + tc956xmac_do_void_callback(__priv, mbx_wrapper, delete_mac, __args) + +#define tc956xmac_add_vlan(__priv, __args...) \ + tc956xmac_do_void_callback(__priv, mbx_wrapper, add_vlan, __args) +#endif +#ifdef TC956X_SRIOV_VF +#define tc956xmac_get_link_status(__priv, __args...) \ + tc956xmac_do_void_callback(__priv, mbx_wrapper, get_link_status, __args) + +#define tc956xmac_vf_reset(__priv, __args...) \ + tc956xmac_do_void_callback(__priv, mbx_wrapper, vf_reset, __args) +#endif /* PTP and HW Timer helpers */ struct tc956xmac_hwtimestamp { void (*config_hw_tstamping)(struct tc956xmac_priv *priv, void __iomem *ioaddr, u32 data); @@ -631,11 +755,15 @@ struct tc956xmac_mode_ops { #define tc956xmac_clean_desc3(__priv, __args...) \ tc956xmac_do_void_callback(__priv, mode, clean_desc3, __args) +#ifdef TC956X_SRIOV_PF +struct tc956xmac_priv; +#endif struct tc_cls_u32_offload; struct tc_cbs_qopt_offload; struct flow_cls_offload; struct tc_taprio_qopt_offload; struct tc_etf_qopt_offload; +struct tc_query_caps_base; struct tc956xmac_tc_ops { int (*init)(struct tc956xmac_priv *priv, void *data); @@ -649,20 +777,31 @@ struct tc956xmac_tc_ops { struct tc_taprio_qopt_offload *qopt); int (*setup_etf)(struct tc956xmac_priv *priv, struct tc_etf_qopt_offload *qopt); + int (*query_caps)(struct tc956xmac_priv *priv, + struct tc_query_caps_base *base); }; #define tc956xmac_tc_init(__priv, __args...) \ tc956xmac_do_callback(__priv, tc, init, __args) #define tc956xmac_tc_setup_cls_u32(__priv, __args...) \ tc956xmac_do_callback(__priv, tc, setup_cls_u32, __args) +#ifdef TC956X_SRIOV_PF #define tc956xmac_tc_setup_cbs(__priv, __args...) \ tc956xmac_do_callback(__priv, tc, setup_cbs, __args) +#elif (defined TC956X_SRIOV_VF) +#define tc956xmac_tc_setup_cbs(__priv, __args...) \ + tc956xmac_do_void_callback(__priv, mbx_wrapper, setup_cbs, __args) +#endif #define tc956xmac_tc_setup_cls(__priv, __args...) \ tc956xmac_do_callback(__priv, tc, setup_cls, __args) #define tc956xmac_tc_setup_taprio(__priv, __args...) \ tc956xmac_do_callback(__priv, tc, setup_taprio, __args) #define tc956xmac_tc_setup_etf(__priv, __args...) \ tc956xmac_do_callback(__priv, tc, setup_etf, __args) +#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 2, 16)) +#define tc956xmac_tc_setup_query_cap(__priv, __args...) \ + tc956xmac_do_callback(__priv, tc, query_caps, __args) +#endif struct tc956xmac_counters; @@ -679,9 +818,210 @@ struct tc956xmac_mmc_ops { #define tc956xmac_mmc_read(__priv, __args...) \ tc956xmac_do_void_callback(__priv, mmc, read, __args) +#if defined(TC956X_SRIOV_PF) | defined(TC956X_SRIOV_VF) +struct mac_rsc_mng_ops { +#ifdef TC956X_SRIOV_VF + int (*init)(struct tc956xmac_priv *priv, struct net_device *dev); +#endif + int (*get_fn_id)(struct tc956xmac_priv *priv, void __iomem *reg_pci_bridge_config_addr, struct fn_id *fn_id_info); + /*rscs[4] = {PFx_DMA_bit_pattern, VF0_DMA_bit_pattern, VF1_DMA_bit_pattern, VF2_DMA_bit_pattern}*/ + void (*set_rscs)(struct tc956xmac_priv *priv, struct net_device *dev, u8 *rscs); + /*resource allocated rscs - bit pattern [DMA7 bit-7] ... ... ... [DMA0 bit-0]*/ + void (*get_rscs)(struct tc956xmac_priv *priv, struct net_device *dev, u8 *rscs); +}; +#endif + +#ifdef TC956X_SRIOV_VF +#define tc956xmac_rsc_mng_init(__priv, __args...) \ + tc956xmac_do_callback(__priv, rsc, init, __args) +#endif +#define tc956xmac_rsc_mng_get_fn_id(__priv, __args...) \ + tc956xmac_do_callback(__priv, rsc, get_fn_id, __args) +#define tc956xmac_rsc_mng_set_rscs(__priv, __args...) \ + tc956xmac_do_void_callback(__priv, rsc, set_rscs, __args) +#define tc956xmac_rsc_mng_get_rscs(__priv, __args...) \ + tc956xmac_do_void_callback(__priv, rsc, get_rscs, __args) + +#ifdef TC956X_SRIOV_VF +/* Specific mailbox helpers */ +struct tc956xmac_mbx_wrapper_ops { + void (*dma_tx_mode)(struct tc956xmac_priv *priv, int mode, u32 channel, + int fifosz, u8 qmode); + void (*get_umac_addr)(struct tc956xmac_priv *priv, unsigned char *addr, + unsigned int reg_n); + int (*set_umac_addr)(struct tc956xmac_priv *priv, unsigned char *addr, + unsigned int reg_n); + /* Set MTL TX queues weight */ + void (*set_mtl_tx_queue_weight)(struct tc956xmac_priv *priv, + u32 weight, u32 traffic_class); + /* Configure AV Algorithm */ + void (*config_cbs)(struct tc956xmac_priv *priv, u32 send_slope, + u32 idle_slope, u32 high_credit, u32 low_credit, + u32 queue); + int (*setup_cbs)(struct tc956xmac_priv *priv, struct tc_cbs_qopt_offload *qopt); + /* TX Queues Priority */ + void (*tx_queue_prio)(struct tc956xmac_priv *priv, u32 prio, u32 queue); + /* Get PF link status */ + void (*get_link_status)(struct tc956xmac_priv *priv, u32 *link_status, + u32 *speed, u32 *duplex); + /* PHY Link state change from PF */ + int (*phy_link)(struct tc956xmac_priv *priv, u8 *msg_buf, u8 *ack_msg); + int (*setup_mbx_etf)(struct tc956xmac_priv *priv, u8 *msg_buf, u8 *ack_msg); + /* Get driver Capabilities from PF */ + void (*get_drv_cap)(struct tc956xmac_priv *priv, struct tc956xmac_priv *priv1); + void (*reset_eee_mode)(struct tc956xmac_priv *priv, struct mac_device_info *hw); + void (*vf_reset)(struct tc956xmac_priv *priv, u8 vf_status); + /* Rx CRC state update from PF */ + int (*rx_crc)(struct tc956xmac_priv *priv, u8 *msg_buf, u8 *ack_msg); + int (*rx_dma_ch_tlptr)(struct tc956xmac_priv *priv, u8 *msg_buf, u8 *ack_msg); + int (*rx_dma_err)(struct tc956xmac_priv *priv, u8 *msg_buf, u8 *ack_msg); + /* Rx checksum state update from PF */ + int (*rx_csum)(struct tc956xmac_priv *priv, u8 *msg_buf, u8 *ack_msg); + int (*pf_flr)(struct tc956xmac_priv *priv, u8 *msg_buf, u8 *ack_msg); + int (*get_cbs)(struct tc956xmac_priv *priv, void __user *data); + int (*set_cbs)(struct tc956xmac_priv *priv, void __user *data); + int (*get_est)(struct tc956xmac_priv *priv, void __user *data); + int (*set_est)(struct tc956xmac_priv *priv, void __user *data); + int (*get_rxp)(struct tc956xmac_priv *priv, void __user *data); + int (*set_rxp)(struct tc956xmac_priv *priv, void __user *data); + int (*get_fpe)(struct tc956xmac_priv *priv, void __user *data); + int (*set_fpe)(struct tc956xmac_priv *priv, void __user *data); + int (*get_speed)(struct tc956xmac_priv *priv, void __user *data); + int (*reg_wr)(struct tc956xmac_priv *priv, void __user *data); + int (*get_pause_param)(struct tc956xmac_priv *priv, struct ethtool_pauseparam *pause); + int (*get_eee)(struct tc956xmac_priv *priv, struct ethtool_eee *edata); + int (*get_ts_info)(struct tc956xmac_priv *priv, struct ethtool_ts_info *info); + int (*add_mac)(struct tc956xmac_priv *priv, const u8 *mac); + void (*delete_mac)(struct tc956xmac_priv *priv, const u8 *mac); + void (*delete_vlan)(struct tc956xmac_priv *priv, u16 vid); + void (*add_vlan)(struct tc956xmac_priv *priv, u16 vid); +}; +#endif + +#if defined(TC956X_SRIOV_PF) | defined(TC956X_SRIOV_VF) +struct mac_mbx_ops { + void (*init)(struct tc956xmac_priv *priv, void *data); + int (*read)(struct tc956xmac_priv *priv, u8 *msg_buff, + enum mbx_msg_fns msg_src, struct fn_id *fn_id_info); + int (*write)(struct tc956xmac_priv *priv, u8 *msg_buff, + enum mbx_msg_fns msg_dst, struct fn_id *fn_id_info); + void (*send_ack)(struct tc956xmac_priv *priv, u8 *msg_buff, + enum mbx_msg_fns msg_dst, struct fn_id *fn_id_info); + /* normally interrupt method is used. + * But for ACK/NACK checking this can be used. + */ + int (*poll_for_ack)(struct tc956xmac_priv *priv, enum mbx_msg_fns msg_src); +}; + +#define tc956xmac_mbx_init(__priv, __args...) \ + tc956xmac_do_void_callback(__priv, mbx, init, __args) +#define tc956xmac_mbx_read(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx, read, __args) +#define tc956xmac_mbx_write(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx, write, __args) +#define tc956xmac_mbx_send_ack(__priv, __args...) \ + tc956xmac_do_void_callback(__priv, mbx, send_ack, __args) +#define tc956xmac_mbx_poll_for_ack(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx, poll_for_ack, __args) +#endif /* #ifdef TC956X_SRIOV_PF/VF */ + +#ifdef TC956X_SRIOV_PF + +struct tc956x_msi_ops { + void (*init)(struct tc956xmac_priv *priv, struct net_device *dev); + void (*interrupt_en)(struct tc956xmac_priv *priv, struct net_device *dev, u32 en); + void (*interrupt_clr)(struct tc956xmac_priv *priv, struct net_device *dev, u32 vector); +}; + +#define tc956x_msi_init(__priv, __args...) \ + tc956xmac_do_void_callback(__priv, msi, init, __args) +#define tc956x_msi_intr_en(__priv, __args...) \ + tc956xmac_do_void_callback(__priv, msi, interrupt_en, __args) +#define tc956x_msi_intr_clr(__priv, __args...) \ + tc956xmac_do_void_callback(__priv, msi, interrupt_clr, __args) + +/* Specific mailbox helpers */ +struct tc956x_mbx_wrapper_ops { + void (*phy_link)(struct tc956xmac_priv *priv); + int (*set_dma_tx_mode)(struct tc956xmac_priv *priv, u8 *mbx_buff, u8 *ack_buff); + int (*set_mtl_tx_queue_weight)(struct tc956xmac_priv *priv, u8 *mbx_buff, u8 *ack_buff); + int (*config_cbs)(struct tc956xmac_priv *priv, u8 *mbx_buff, u8 *ack_buff); + int (*setup_cbs)(struct tc956xmac_priv *priv, u8 *mbx_buff, u8 *ack_buff); + int (*setup_mbx_etf)(struct tc956xmac_priv *priv, u32 ch, u8 vf); + int (*tx_queue_prio)(struct tc956xmac_priv *priv, u8 *mbx_buff, u8 *ack_buff); + int (*vf_get_link_status)(struct tc956xmac_priv *priv, u8 *mbx_buff, u8 *ack_buff); + void (*rx_crc)(struct tc956xmac_priv *priv); + void (*rx_csum)(struct tc956xmac_priv *priv); + void (*pf_flr)(struct tc956xmac_priv *priv); + int (*reset_eee_mode)(struct tc956xmac_priv *priv, u8 *mbx_buff, u8 *ack_buff); + int (*get_umac_addr)(struct tc956xmac_priv *priv, u8 *mbx_buff, u8 *ack_buff); + int (*set_umac_addr)(struct tc956xmac_priv *priv, u8 *mbx_buff, u8 *ack_buff, u8 vf_no); + int (*vf_reset)(struct tc956xmac_priv *priv, u8 *mbx_buff, u8 *ack_buff, u8 vf_no); + int (*get_drv_cap)(struct tc956xmac_priv *priv, u8 *mbx_buff, u8 *ack_buff); + int (*vf_ioctl)(struct tc956xmac_priv *priv, u8 *mbx_buff, u8 *ack_buff, u8 vf_no); + int (*vf_ethtool)(struct tc956xmac_priv *priv, struct net_device *dev, u8 *mbx_buff, u8 *ack_buff); + int (*add_mac)(struct tc956xmac_priv *priv, struct net_device *dev, u8 *mbx_buff, u8 *ack_buff, u8 vf_no); + int (*delete_mac)(struct tc956xmac_priv *priv, struct net_device *dev, u8 *mbx_buff, u8 *ack_buff, u8 vf_no); + int (*add_vlan)(struct tc956xmac_priv *priv, struct net_device *dev, u8 *mbx_buff, u8 *ack_buff, u8 vf_no); + int (*delete_vlan)(struct tc956xmac_priv *priv, struct net_device *dev, u8 *mbx_buff, u8 *ack_buff, u8 vf_no); + int (*rx_dma_ch_tlptr)(struct tc956xmac_priv *priv, u32 ch, u8 vf_no); + int (*rx_dma_err)(struct tc956xmac_priv *priv, u8 vf_no); +}; + +#define tc956x_mbx_wrap_phy_link(__priv) \ + tc956xmac_do_void_no_param_callback(__priv, mbx_wrapper, phy_link) +#define tc956x_mbx_wrap_set_dma_tx_mode(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, set_dma_tx_mode, __args) +#define tc956x_mbx_wrap_set_mtl_tx_queue_weight(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, set_mtl_tx_queue_weight, __args) +#define tc956x_mbx_wrap_config_cbs(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, config_cbs, __args) +#define tc956x_mbx_wrap_setup_cbs(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, setup_cbs, __args) +#define tc956x_mbx_wrap_setup_etf(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, setup_mbx_etf, __args) +#define tc956x_mbx_wrap_tx_queue_prior(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, tx_queue_prio, __args) +#define tc956x_mbx_wrap_get_link_status(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, vf_get_link_status, __args) +#define tc956x_mbx_wrap_set_rx_crc(__priv, __args...) \ + tc956xmac_do_void_no_param_callback(__priv, mbx_wrapper, rx_crc) +#define tc956x_mbx_wrap_set_rx_csum(__priv, __args...) \ + tc956xmac_do_void_no_param_callback(__priv, mbx_wrapper, rx_csum) +#define tc956x_mbx_wrap_pf_flr(__priv, __args...) \ + tc956xmac_do_void_no_param_callback(__priv, mbx_wrapper, pf_flr) +#define tc956x_mbx_wrap_rx_dma_ch_tlptr(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, rx_dma_ch_tlptr, __args) +#define tc956x_mbx_wrap_rx_dma_err(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, rx_dma_err, __args) +#define tc956x_mbx_wrap_reset_eee_mode(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, reset_eee_mode, __args) +#define tc956x_mbx_wrap_get_umac_addr(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, get_umac_addr, __args) +#define tc956x_mbx_wrap_set_umac_addr(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, set_umac_addr, __args) +#define tc956x_mbx_wrap_get_drv_cap(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, get_drv_cap, __args) +#define tc956x_mbx_wrap_vf_reset(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, vf_reset, __args) +#define tc956xmac_mbx_ioctl_interface(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, vf_ioctl, __args) +#define tc956xmac_mbx_ethtool_interface(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, vf_ethtool, __args) + +#define tc956xmac_mbx_add_mac(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, add_mac, __args) +#define tc956xmac_mbx_delete_mac(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, delete_mac, __args) +#define tc956xmac_mbx_add_vlan(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, add_vlan, __args) +#define tc956xmac_mbx_delete_vlan(__priv, __args...) \ + tc956xmac_do_callback(__priv, mbx_wrapper, delete_vlan, __args) + +#endif /* TC956X_SRIOV_PF */ + #ifdef TC956X /*PMA module*/ - struct tc956xmac_pma_ops { int (*init)(struct tc956xmac_priv *priv, void __iomem *pmaaddr); }; @@ -700,6 +1040,21 @@ struct tc956xmac_regs_off { #endif }; +#ifdef TC956X_SRIOV_VF +struct tc956x_msi_ops { + void (*init)(struct tc956xmac_priv *priv, struct net_device *dev, struct fn_id *fn_id_info); + void (*interrupt_en)(struct tc956xmac_priv *priv, struct net_device *dev, u32 en, struct fn_id *fn_id_info); + void (*interrupt_clr)(struct tc956xmac_priv *priv, struct net_device *dev, u32 vector, struct fn_id *fn_id_info); +}; + +#define tc956x_msi_init(__priv, __args...) \ + tc956xmac_do_void_callback(__priv, msi, init, __args) +#define tc956x_msi_intr_en(__priv, __args...) \ + tc956xmac_do_void_callback(__priv, msi, interrupt_en, __args) +#define tc956x_msi_intr_clr(__priv, __args...) \ + tc956xmac_do_void_callback(__priv, msi, interrupt_clr, __args) +#endif + extern const struct tc956xmac_ops dwmac100_ops; extern const struct tc956xmac_dma_ops dwmac100_dma_ops; extern const struct tc956xmac_ops dwmac1000_ops; @@ -718,6 +1073,17 @@ extern const struct tc956xmac_mmc_ops dwxgmac_mmc_ops; #ifdef TC956X extern const struct tc956xmac_pma_ops tc956x_pma_ops; #endif +#if defined(TC956X_SRIOV_PF) | defined(TC956X_SRIOV_VF) +extern const struct tc956x_msi_ops tc956x_msigen_ops; +extern const struct mac_rsc_mng_ops tc956xmac_rsc_mng_ops; +extern const struct mac_mbx_ops tc956xmac_mbx_ops; +#endif + +#ifdef TC956X_SRIOV_PF +extern const struct tc956x_mbx_wrapper_ops tc956xmac_mbx_wrapper_ops; +#elif defined TC956X_SRIOV_VF +extern const struct tc956xmac_mbx_wrapper_ops tc956xmac_mbx_wrapper_ops; +#endif #define GMAC_VERSION (MAC_OFFSET + 0x00000020) /* GMAC CORE Version */ #define GMAC4_VERSION (MAC_OFFSET + 0x00000110) /* GMAC4+ CORE Version */ diff --git a/tc956x_ipa_intf.c b/tc956x_ipa_intf.c index 077de26c8689..97b13cec4812 100644 --- a/tc956x_ipa_intf.c +++ b/tc956x_ipa_intf.c @@ -79,8 +79,6 @@ #define MAC_ADDR_DCS 0x1 static u8 mac_addr_default[6] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; -extern struct pci_dev* port0_pdev; - static DEFINE_SPINLOCK(cm3_tamap_lock); extern int tc956xmac_rx_parser_configuration(struct tc956xmac_priv *priv); @@ -599,6 +597,11 @@ struct channel_info* request_channel(struct request_channel_input *channel_input struct tc956xmac_tx_queue *tx_q; struct tc956xmac_rx_queue *rx_q; + if (!channel_input) { + pr_err("%s: ERROR: Invalid channel_input pointer\n", __func__); + return NULL; + } + if (!channel_input->ndev) { pr_err("%s: ERROR: Invalid netdevice pointer\n", __func__); return NULL; @@ -651,7 +654,7 @@ struct channel_info* request_channel(struct request_channel_input *channel_input goto err_buff_dma_mem_alloc; } - channel->dma_pdev = (struct pci_dev*)priv->device; + channel->dma_pdev = (struct pci_dev *)priv->device; if (channel->mem_ops) { /*if mem_ops is a valid, memory resrouces will be allocated by IPA */ @@ -939,7 +942,7 @@ EXPORT_SYMBOL_GPL(release_channel); * \remarks : * If this API is invoked for a channel without calling release_event(), * then the PCIe address and value for that channel will be overwritten - * Mask = 2 ^ (CM3_TAMAP_ATR_SIZE + 1) - 1 + * Mask = 2 ^ (CM3_TAMAP_ATR_SIZE + 1) - 1 * TRSL_ADDR = DMA_PCIe_ADDR & ~((2 ^ (ATR_SIZE + 1) - 1) = TRSL_ADDR = DMA_PCIe_ADDR & ~Mask * CM3 Target Address = DMA_PCIe_ADDR & Mask | SRC_ADDR */ @@ -1676,6 +1679,12 @@ int set_mac_addr(struct net_device *ndev, struct mac_addr_list *mac_addr, u8 ind return -EPERM; } + if (index >= TC956X_MAX_PERFECT_ADDRESSES) { + netdev_err(priv->dev, + "%s: ERROR: Index out of range\n", __func__); + return -EPERM; + } + data = (mac_addr->addr[5] << 8) | (mac_addr->addr[4]) | (mac_addr->ae << XGMAC_AE_SHIFT) | (mac_addr->mbc << XGMAC_MBC_SHIFT); writel(data, priv->ioaddr + XGMAC_ADDRx_HIGH(index)); diff --git a/tc956x_ipa_intf.h b/tc956x_ipa_intf.h index 8986d05bdb71..968846a94fa0 100644 --- a/tc956x_ipa_intf.h +++ b/tc956x_ipa_intf.h @@ -94,7 +94,7 @@ struct rxp_filter_entry { u16 res4; }; -struct rx_filter_info{ +struct rx_filter_info { u32 nve; /* Max block entries user want to write */ u32 npe; /* number of parsable entries in the Instruction Table. */ struct rxp_filter_entry entries[128]; /* FRP table entries */ @@ -259,7 +259,7 @@ int release_channel(struct net_device *ndev, struct channel_info *channel); * \remarks : * If this API is invoked for a channel without calling release_event(), * then the PCIe address and value for that channel will be overwritten - * Mask = 2 ^ (CM3_TAMAP_ATR_SIZE + 1) - 1 + * Mask = 2 ^ (CM3_TAMAP_ATR_SIZE + 1) - 1 * TRSL_ADDR = DMA_PCIe_ADDR & ~((2 ^ (ATR_SIZE + 1) - 1) = TRSL_ADDR = DMA_PCIe_ADDR & ~Mask * CM3 Target Address = DMA_PCIe_ADDR & Mask | SRC_ADDR */ diff --git a/tc956x_msigen.c b/tc956x_msigen.c new file mode 100644 index 000000000000..c3a338d5c596 --- /dev/null +++ b/tc956x_msigen.c @@ -0,0 +1,286 @@ +/* + * TC956X ethernet driver. + * + * tc956x_msigen.c + * + * Copyright (C) 2022 Toshiba Electronic Devices & Storage Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/*! History: + * 14 SEP 2020 : Initial Version + * VERSION : 00-01 + * + * 30 Nov 2021 : Base lined for SRIOV + * VERSION : 01-02 + * + * 20 May 2022 : 1. Automotive Driver, CPE fixes merged and IPA Features supported + * 2. Base lined version + * VERSION : 03-00 + */ + +#include +#include +#include "hwif.h" +#include "common.h" +#include "tc956xmac.h" + +#ifdef TC956X_SRIOV_PF +/** + * tc956x_msigen_init + * + * \brief API to Initialize and configure MSIGEN module + * + * \details This function is used to configures clock, reset, sets mask and + * interrupt source to MSI vector mapping. + * + * \param[in] dev - Pointer to net device structure + * + * \return None + */ +static void tc956x_msigen_init(struct tc956xmac_priv *priv, struct net_device *dev) +{ + u32 rd_val; + + /* Enable MSIGEN Module */ +#ifdef TC956X + rd_val = readl(priv->ioaddr + NCLKCTRL0_OFFSET); + rd_val |= (1 << TC956X_MSIGENCEN); + writel(rd_val, priv->ioaddr + NCLKCTRL0_OFFSET); + rd_val = readl(priv->ioaddr + NRSTCTRL0_OFFSET); + rd_val &= ~(1 << TC956X_MSIGENCEN); + writel(rd_val, priv->ioaddr + NRSTCTRL0_OFFSET); +#else + rd_val = readl(priv->ioaddr + NCLKCTRL_OFFSET); + rd_val |= (1 << TC956X_MSIGENCEN); + writel(rd_val, priv->ioaddr + NCLKCTRL_OFFSET); + rd_val = readl(priv->ioaddr + NRSTCTRL_OFFSET); + rd_val &= ~(1 << TC956X_MSIGENCEN); + writel(rd_val, priv->ioaddr + NRSTCTRL_OFFSET); +#endif + /* Initialize MSIGEN */ + + writel(TC956X_MSI_OUT_EN_CLR, priv->ioaddr + TC956X_MSI_OUT_EN_OFFSET(priv->fn_id_info.pf_no, priv->fn_id_info.vf_no)); + writel(TC956X_MSI_MASK_SET, priv->ioaddr + TC956X_MSI_MASK_SET_OFFSET(priv->fn_id_info.pf_no, priv->fn_id_info.vf_no)); + writel(TC956X_MSI_MASK_CLR, priv->ioaddr + TC956X_MSI_MASK_CLR_OFFSET(priv->fn_id_info.pf_no, priv->fn_id_info.vf_no)); + /* DMA Ch Tx-Rx Interrupt sources are assigned to Vector 0, + * All other Interrupt sources are assigned to Vector 1 */ + writel(TC956X_MSI_SET0, priv->ioaddr + TC956X_MSI_VECT_SET0_OFFSET(priv->fn_id_info.pf_no, priv->fn_id_info.vf_no)); + writel(TC956X_MSI_SET1, priv->ioaddr + TC956X_MSI_VECT_SET1_OFFSET(priv->fn_id_info.pf_no, priv->fn_id_info.vf_no)); + writel(TC956X_MSI_SET2, priv->ioaddr + TC956X_MSI_VECT_SET2_OFFSET(priv->fn_id_info.pf_no, priv->fn_id_info.vf_no)); + writel(TC956X_MSI_SET3, priv->ioaddr + TC956X_MSI_VECT_SET3_OFFSET(priv->fn_id_info.pf_no, priv->fn_id_info.vf_no)); + writel(TC956X_MSI_SET4, priv->ioaddr + TC956X_MSI_VECT_SET4_OFFSET(priv->fn_id_info.pf_no, priv->fn_id_info.vf_no)); + writel(TC956X_MSI_SET5, priv->ioaddr + TC956X_MSI_VECT_SET5_OFFSET(priv->fn_id_info.pf_no, priv->fn_id_info.vf_no)); + writel(TC956X_MSI_SET6, priv->ioaddr + TC956X_MSI_VECT_SET6_OFFSET(priv->fn_id_info.pf_no, priv->fn_id_info.vf_no)); + writel(TC956X_MSI_SET7, priv->ioaddr + TC956X_MSI_VECT_SET7_OFFSET(priv->fn_id_info.pf_no, priv->fn_id_info.vf_no)); +} + +/** + * tc956x_interrupt_en + * + * \brief API to enable disable MSI interrupts + * + * \details This function is used to set/clear interrupts + * + * \param[in] dev - Pointer to net device structure + * \param[in] en - 1 - Enable interrupts + * 0 - Disable interrupts + * \return None + */ +static void tc956x_interrupt_en(struct tc956xmac_priv *priv, struct net_device *dev, u32 en) +{ + u32 chan, mask_val = 0; + + if (en) { + + /* Disable MSI for Tx/Rx channels that is not enabled in the Function */ + + for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) { +#ifdef TC956X_SRIOV_PF + if (priv->plat->tx_ch_in_use[chan] != TC956X_ENABLE_CHNL) +#endif + mask_val |= (1 << (MSI_INT_TX_CH0 + chan)); + } + + for (chan = 0; chan < priv->plat->rx_queues_to_use; chan++) { +#ifdef TC956X_SRIOV_PF + if (priv->plat->rx_ch_in_use[chan] != TC956X_ENABLE_CHNL) +#endif + mask_val |= (1 << (MSI_INT_RX_CH0 + chan)); + } +#ifdef TC956X_SRIOV_PF + /* PHY MSI interrupt enabled */ + mask_val &= ~(1 << MSI_INT_EXT_PHY); +#else + /* PHY MSI interrupt diabled */ + mask_val |= (1 << MSI_INT_EXT_PHY); +#endif + mask_val = TC956X_MSI_OUT_EN & (~mask_val); + +#ifdef TC956X_SW_MSI + /* Enable SW MSI interrupt */ + KPRINT_INFO("%s Enable SW MSI", __func__); + mask_val |= (1 << MSI_INT_SW_MSI); + + /*Clear SW MSI*/ + writel(1, priv->ioaddr + TC956X_MSI_SW_MSI_CLR(priv->fn_id_info.pf_no, priv->fn_id_info.vf_no)); + +#endif + writel(mask_val, priv->ioaddr + TC956X_MSI_OUT_EN_OFFSET(priv->fn_id_info.pf_no, priv->fn_id_info.vf_no)); + } else + writel(TC956X_MSI_OUT_EN_CLR, priv->ioaddr + TC956X_MSI_OUT_EN_OFFSET(priv->fn_id_info.pf_no, priv->fn_id_info.vf_no)); + + netdev_dbg(priv->dev, "%s mask_val : %x\n", __func__, mask_val); +} + +/** + * tc956x_interrupt_clr + * + * \brief API to enable clear MSI vector + * + * \details This function is used to clear MSI vector. To be called + * after handling the interrupts. + * + * \param[in] dev - Pointer to net device structure + * \param[in] vector - Supported values TC956X_MSI_VECTOR_0, TC956X_MSI_VECTOR_1 + * + * \return None + */ +static void tc956x_interrupt_clr(struct tc956xmac_priv *priv, struct net_device *dev, u32 vector) +{ + writel((1<ioaddr + TC956X_MSI_MASK_CLR_OFFSET(priv->fn_id_info.pf_no, priv->fn_id_info.vf_no)); + + netdev_dbg(priv->dev, "%s %d\n", __func__, vector); +} +#elif defined TC956X_SRIOV_VF +/** + * tc956x_msigen_init + * + * \brief API to Initialize and configure MSIGEN module + * + * \details This function is used to configures clock, reset, sets mask and + * interrupt source to MSI vector mapping. + * + * \param[in] dev - Pointer to net device structure + * + * \return None + */ +static void tc956x_msigen_init(struct tc956xmac_priv *priv, struct net_device *dev, + struct fn_id *fn_id_info) +{ + //struct tc956xmac_priv *priv = netdev_priv(dev); + u8 pf_id = fn_id_info->pf_no; + u8 vf_id = fn_id_info->vf_no; + +#ifndef TC956X_SRIOV_VF + /* Enable MSIGEN Module */ + rd_val = readl(priv->ioaddr + NCLKCTRL0_OFFSET); + rd_val |= (1 << TC956X_MSIGENCEN); + writel(rd_val, priv->ioaddr + NCLKCTRL0_OFFSET); + rd_val = readl(priv->ioaddr + NRSTCTRL0_OFFSET); + rd_val &= ~(1 << TC956X_MSIGENCEN); + writel(rd_val, priv->ioaddr + NRSTCTRL0_OFFSET); +#endif + + /* Initialize MSIGEN */ + writel(TC956X_MSI_OUT_EN_CLR, priv->ioaddr + TC956X_MSI_OUT_EN_OFFSET(pf_id, vf_id)); + writel(TC956X_MSI_MASK_SET, priv->ioaddr + TC956X_MSI_MASK_SET_OFFSET(pf_id, vf_id)); + writel(TC956X_MSI_MASK_CLR, priv->ioaddr + TC956X_MSI_MASK_CLR_OFFSET(pf_id, vf_id)); + writel(TC956X_MSI_SET0, priv->ioaddr + TC956X_MSI_VECT_SET0_OFFSET(pf_id, vf_id)); + writel(TC956X_MSI_SET1, priv->ioaddr + TC956X_MSI_VECT_SET1_OFFSET(pf_id, vf_id)); + writel(TC956X_MSI_SET2, priv->ioaddr + TC956X_MSI_VECT_SET2_OFFSET(pf_id, vf_id)); + writel(TC956X_MSI_SET3, priv->ioaddr + TC956X_MSI_VECT_SET3_OFFSET(pf_id, vf_id)); + writel(TC956X_MSI_SET4, priv->ioaddr + TC956X_MSI_VECT_SET4_OFFSET(pf_id, vf_id)); + writel(TC956X_MSI_SET5, priv->ioaddr + TC956X_MSI_VECT_SET5_OFFSET(pf_id, vf_id)); + writel(TC956X_MSI_SET6, priv->ioaddr + TC956X_MSI_VECT_SET6_OFFSET(pf_id, vf_id)); + writel(TC956X_MSI_SET7, priv->ioaddr + TC956X_MSI_VECT_SET7_OFFSET(pf_id, vf_id)); + + +} + +/** + * tc956x_interrupt_en + * + * \brief API to enable disable MSI interrupts + * + * \details This function is used to set/clear interrupts + * + * \param[in] dev - Pointer to net device structure + * \param[in] en - 1 - Enable interrupts + * 0 - Disable interrupts + * \return None + */ +static void tc956x_interrupt_en(struct tc956xmac_priv *priv, struct net_device *dev, u32 en, + struct fn_id *fn_id_info) +{ + //struct tc956xmac_priv *priv = netdev_priv(dev); + u8 pf_id = fn_id_info->pf_no; + u8 vf_id = fn_id_info->vf_no; + + u32 tx_queues_cnt = priv->plat->tx_queues_to_use; + u32 ch; + u32 msi_out_en = 0; + + for (ch = 0; ch < tx_queues_cnt; ch++) { +#ifdef TC956X_SRIOV_VF + /* skip configuring for unallocated channel */ + if (priv->plat->ch_in_use[ch] == 0) + continue; +#endif + msi_out_en |= (1 << (ch + TC956X_MSI_INT_TXDMA_CH0)); /* tx dma channel setting */ + msi_out_en |= (1 << (ch + TC956X_MSI_INT_RXDMA_CH0)); /* rx dma channel setting */ + } + +#ifdef TC956X_SRIOV_VF + msi_out_en |= (1 << TC956X_MSI_INT_MBX); /* Mailbox interrupt setting */ +#endif + + msi_out_en = TC956X_MSI_OUT_EN & (msi_out_en); + + if (en) + writel(msi_out_en, priv->ioaddr + TC956X_MSI_OUT_EN_OFFSET(pf_id, vf_id)); + else + writel(TC956X_MSI_OUT_EN_CLR, priv->ioaddr + TC956X_MSI_OUT_EN_OFFSET(pf_id, vf_id)); +} + +/** + * tc956x_interrupt_clr + * + * \brief API to enable clear MSI vector + * + * \details This function is used to clear MSI vector. To be called + * after handling the interrupts. + * + * \param[in] dev - Pointer to net device structure + * \param[in] vector - Supported values TC956X_MSI_VECTOR_0, TC956X_MSI_VECTOR_1 + * + * \return None + */ +static void tc956x_interrupt_clr(struct tc956xmac_priv *priv, struct net_device *dev, u32 vector, + struct fn_id *fn_id_info) +{ + u8 pf_id = fn_id_info->pf_no; + u8 vf_id = fn_id_info->vf_no; + + writel((1 << vector), priv->ioaddr + TC956X_MSI_MASK_CLR_OFFSET(pf_id, vf_id)); + +} +#endif +const struct tc956x_msi_ops tc956x_msigen_ops = { + .init = tc956x_msigen_init, + .interrupt_en = tc956x_interrupt_en, + .interrupt_clr = tc956x_interrupt_clr, +}; diff --git a/tc956x_pci.c b/tc956x_pci.c index a846b24d16b2..19b745cddacb 100644 --- a/tc956x_pci.c +++ b/tc956x_pci.c @@ -4,7 +4,7 @@ * tc956x_pci.c * * Copyright (C) 2011-2012 Vayavya Labs Pvt Ltd - * Copyright (C) 2021 Toshiba Electronic Devices & Storage Corporation + * Copyright (C) 2023 Toshiba Electronic Devices & Storage Corporation * * This file has been derived from the STMicro and Synopsys Linux driver, * and developed or modified for TC956X. @@ -182,6 +182,15 @@ * 09 May 2023 : 1. Version update * 2. Module parameters to control SW reset (during link change) enabled by default for Port0. * VERSION : 01-00-59 + * 10 Nov 2023 : 1. Kernel 6.1 Porting changes + * 2. DSP Cascade related modifications. + * 3. Version update + * VERSION : 01-02-59 + * + * 26 Dec 2023 : 1. Kernel 6.6 Porting changes + * 2. Added the support for TC commands taprio and flower + * 3. Version update + * VERSION : 01-03-59 */ #include @@ -200,20 +209,29 @@ #ifdef TC956X_LOAD_FW_HEADER #include "fw.h" #endif +#ifdef TC956X_SRIOV_VF +#include "tc956x_vf_rsc_mng.h" +#endif #ifdef TC956X_PCIE_LOGSTAT #include "tc956x_pcie_logstat.h" #endif /* #ifdef TC956X_PCIE_LOGSTAT */ +#ifndef TC956X_SRIOV_VF +#ifdef CONFIG_PCI_IOV +static int tc956x_no_of_vf; +#endif #ifdef TC956X_PCIE_GEN3_SETTING static unsigned int pcie_link_speed = 3; #endif +#endif unsigned int mac0_force_speed_mode = DISABLE; unsigned int mac1_force_speed_mode = DISABLE; unsigned int mac0_force_config_speed = 3; /* 1Gbps */ unsigned int mac1_force_config_speed = 3; /* 1Gbps */ +#if defined(TC956X_SRIOV_PF) || defined(TC956X_AUTOMOTIVE_CONFIG) static unsigned int mac0_interface = ENABLE_XFI_INTERFACE; static unsigned int mac1_interface = ENABLE_SGMII_INTERFACE; @@ -233,7 +251,7 @@ static unsigned int mac0_rxq1_rfd = 24; static unsigned int mac0_rxq1_rfa = 24; static unsigned int mac0_txq0_size = TX_QUEUE0_SIZE; static unsigned int mac0_txq1_size = TX_QUEUE1_SIZE; - + static unsigned int mac1_rxq0_size = RX_QUEUE0_SIZE; static unsigned int mac1_rxq1_size = RX_QUEUE1_SIZE; static unsigned int mac1_rxq0_rfd = 24; @@ -242,19 +260,32 @@ static unsigned int mac1_rxq1_rfd = 24; static unsigned int mac1_rxq1_rfa = 24; static unsigned int mac1_txq0_size = TX_QUEUE0_SIZE; static unsigned int mac1_txq1_size = TX_QUEUE1_SIZE; + +static unsigned int port0_mdc = TC956XMAC_XGMAC_MDC_CSR_12; +static int port0_c45_state = 1; /* C45 selected by default */ + +static unsigned int port1_mdc = TC956XMAC_XGMAC_MDC_CSR_62; +static int port1_c45_state; /* C22 selected by default */ + +static unsigned int port0_phyaddr; +static unsigned int port1_phyaddr; unsigned int mac0_link_down_macrst = ENABLE; unsigned int mac1_link_down_macrst = DISABLE; +#endif + unsigned int mac0_en_lp_pause_frame_cnt = DISABLE; unsigned int mac1_en_lp_pause_frame_cnt = DISABLE; unsigned int mac_power_save_at_link_down = DISABLE; - -static const struct tc956x_version tc956x_drv_version = {0, 1, 0, 0, 5, 9}; - -static int tc956xmac_pm_usage_counter; /* Device Usage Counter */ +static const struct tc956x_version tc956x_drv_version = {0, 1, 0, 3, 5, 9}; +int tc956xmac_pm_usage_counter; /* Device Usage Counter */ struct mutex tc956x_pm_suspend_lock; /* This mutex is shared between all available EMAC ports. */ - +#ifdef TC956X_SRIOV_PF +#ifdef TC956X_MAGIC_PACKET_WOL_GPIO +static void tc956x_wol_gpio_trigger(void __iomem *reg_base_addr, bool mode); +#endif +#endif /* * This struct is used to associate PCI Function of MAC controller on a board, * discovered via DMI, with the address of PHY connected to the MAC. The @@ -275,16 +306,22 @@ struct tc956xmac_pci_info { int (*setup)(struct pci_dev *pdev, struct plat_tc956xmacenet_data *plat); }; -/*By default, route all packets to RxCh0 */ +/* By default, Bypass FRP routing */ +/* User to configure routing for FRP usecase */ static struct tc956xmac_rx_parser_entry snps_rxp_entries[] = { #ifdef TC956X { +#ifdef TC956X_SRIOV_PF + .match_data = 0x00000000, .match_en = 0x00000000, .af = 1, .rf = 1, .im = 0, .nc = 0, .res1 = 0, .frame_offset = 0, .res2 = 0, .ok_index = 0, .res3 = 0, .dma_ch_no = 0x0, .res4 = 0, /* FRP Bypass */ +#elif defined TC956X_SRIOV_VF .match_data = 0x00000000, .match_en = 0x00000000, .af = 1, .rf = 0, .im = 0, .nc = 0, .res1 = 0, .frame_offset = 0, .res2 = 0, .ok_index = 0, .res3 = 0, .dma_ch_no = 1, .res4 = 0, +#endif }, #endif }; +#ifndef TC956X_SRIOV_VF static struct tc956xmac_rx_parser_entry snps_rxp_entries_filter_phy_pause_frames[] = { /* 0th entry */{.match_data = 0x00000888, .match_en = 0x0000FFFF, .af = 0, .rf = 0, .im = 0, .nc = 1, .res1 = 0, .frame_offset = 3, .res2 = 0, .ok_index = 3, .res3 = 0, .dma_ch_no = 1, .res4 = 0,}, /* Checking SA Address 00:01:02:03:04:05 AQR PHYs SA Address as Ether type Match*/ @@ -294,6 +331,7 @@ static struct tc956xmac_rx_parser_entry snps_rxp_entries_filter_phy_pause_frames /* 3rd entry */{.match_data = 0x00000000, .match_en = 0x00000000, .af = 1, .rf = 0, .im = 0, .nc = 0, .res1 = 0, .frame_offset = 0, .res2 = 0, .ok_index = 0, .res3 = 0, .dma_ch_no = 1, .res4 = 0,}, /* 4th entry */{.match_data = 0x00000000, .match_en = 0x00000000, .af = 1, .rf = 0, .im = 0, .nc = 0, .res1 = 0, .frame_offset = 0, .res2 = 0, .ok_index = 0, .res3 = 0, .dma_ch_no = 1, .res4 = 0,}, }; +#endif /*! * \brief API to save and restore clock and reset during suspend-resume. @@ -310,6 +348,7 @@ static void tc956xmac_pm_set_power(struct tc956xmac_priv *priv, enum TC956X_PORT { void *nrst_reg = NULL, *nclk_reg = NULL, *commonclk_reg = NULL; u32 nrst_val = 0, nclk_val = 0, commonclk_val = 0; + KPRINT_INFO("-->%s : Port %d", __func__, priv->port_num); /* Select register address by port */ if (priv->port_num == 0) { @@ -325,7 +364,7 @@ static void tc956xmac_pm_set_power(struct tc956xmac_priv *priv, enum TC956X_PORT /* Modify register for reset, clock and MSI_OUTEN */ nrst_val = readl(nrst_reg); nclk_val = readl(nclk_reg); - KPRINT_INFO("%s : Port %d Rd RST Reg:%x, CLK Reg:%x", __func__, priv->port_num, + KPRINT_INFO("%s : Port %d Rd RST Reg:%x, CLK Reg:%x", __func__, priv->port_num, nrst_val, nclk_val); /* Save values before Asserting reset and Clock Disable */ priv->pm_saved_emac_rst = nrst_val & NRSTCTRL_EMAC_MASK; @@ -337,12 +376,12 @@ static void tc956xmac_pm_set_power(struct tc956xmac_priv *priv, enum TC956X_PORT if (tc956xmac_pm_usage_counter == TC956X_ALL_MAC_PORT_SUSPENDED) { commonclk_reg = priv->tc956x_SFR_pci_base_addr + NCLKCTRL0_OFFSET; commonclk_val = readl(commonclk_reg); - KPRINT_INFO("%s : Port %d Common CLK Rd Reg:%x", __func__, priv->port_num, + KPRINT_INFO("%s : Port %d Common CLK Rd Reg:%x", __func__, priv->port_num, commonclk_val); /* Clear Common Clocks only when both port suspends */ commonclk_val = commonclk_val & ~NCLKCTRL0_COMMON_EMAC_MASK; writel(commonclk_val, commonclk_reg); - KPRINT_INFO("%s : Port %d Common CLK Wr Reg:%x", __func__, priv->port_num, + KPRINT_INFO("%s : Port %d Common CLK Wr Reg:%x", __func__, priv->port_num, commonclk_val); } } else if (state == RESUME) { @@ -350,17 +389,17 @@ static void tc956xmac_pm_set_power(struct tc956xmac_priv *priv, enum TC956X_PORT if (tc956xmac_pm_usage_counter == TC956X_ALL_MAC_PORT_SUSPENDED) { commonclk_reg = priv->tc956x_SFR_pci_base_addr + NCLKCTRL0_OFFSET; commonclk_val = readl(commonclk_reg); - KPRINT_INFO("%s : Port %d Common CLK Rd Reg:%x", __func__, priv->port_num, + KPRINT_INFO("%s : Port %d Common CLK Rd Reg:%x", __func__, priv->port_num, commonclk_val); /* Clear Common Clocks only when both port suspends */ commonclk_val = commonclk_val | NCLKCTRL0_COMMON_EMAC_MASK; writel(commonclk_val, commonclk_reg); - KPRINT_INFO("%s : Port %d Common CLK WR Reg:%x", __func__, priv->port_num, + KPRINT_INFO("%s : Port %d Common CLK WR Reg:%x", __func__, priv->port_num, commonclk_val); } nrst_val = readl(nrst_reg); nclk_val = readl(nclk_reg); - KPRINT_INFO("%s : Port %d Rd RST Reg:%x, CLK Reg:%x", __func__, priv->port_num, + KPRINT_INFO("%s : Port %d Rd RST Reg:%x, CLK Reg:%x", __func__, priv->port_num, nrst_val, nclk_val); /* Restore values same as before suspend */ nrst_val = (nrst_val & ~NRSTCTRL_EMAC_MASK) | priv->pm_saved_emac_rst; @@ -368,15 +407,12 @@ static void tc956xmac_pm_set_power(struct tc956xmac_priv *priv, enum TC956X_PORT writel(nclk_val, nclk_reg); writel(nrst_val, nrst_reg); } - KPRINT_INFO("%s : Port %d priv->pm_saved_emac_rst %x priv->pm_saved_emac_clk %x", __func__, + KPRINT_INFO("%s : Port %d priv->pm_saved_emac_rst %x priv->pm_saved_emac_clk %x", __func__, priv->port_num, priv->pm_saved_emac_rst, priv->pm_saved_emac_clk); - KPRINT_INFO("%s : Port %d Wr RST Reg:%x, CLK Reg:%x", __func__, priv->port_num, + KPRINT_INFO("%s : Port %d Wr RST Reg:%x, CLK Reg:%x", __func__, priv->port_num, readl(nrst_reg), readl(nclk_reg)); KPRINT_INFO("<--%s : Port %d", __func__, priv->port_num); } -#ifdef DMA_OFFLOAD_ENABLE -struct pci_dev* port0_pdev; -#endif #ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE static int tc956xmac_pci_find_phy_addr(struct pci_dev *pdev, @@ -451,6 +487,7 @@ static int tc956xmac_default_data(struct pci_dev *pdev, plat->dma_cfg->pblx8 = true; /* TODO: AXI */ +#if !defined(TC956X_SRIOV_PF) && !defined(TC956X_SRIOV_VF) plat->tx_dma_ch_owner[0] = TX_DMA_CH0_OWNER; plat->tx_dma_ch_owner[1] = TX_DMA_CH1_OWNER; plat->tx_dma_ch_owner[2] = TX_DMA_CH2_OWNER; @@ -468,7 +505,7 @@ static int tc956xmac_default_data(struct pci_dev *pdev, plat->rx_dma_ch_owner[5] = RX_DMA_CH5_OWNER; plat->rx_dma_ch_owner[6] = RX_DMA_CH6_OWNER; plat->rx_dma_ch_owner[7] = RX_DMA_CH7_OWNER; - +#endif KPRINT_INFO("%s <", __func__); return 0; } @@ -826,9 +863,11 @@ static int snps_gmac5_default_data(struct pci_dev *pdev, plat->est->gcl_size = plat->tx_queues_to_use; for (i = 0; i < plat->tx_queues_to_use; i++) { +#ifndef TC956X u32 value = BIT(24 + i) + 100000; plat->est->gcl_unaligned[i] = value; +#endif } return 0; @@ -845,11 +884,12 @@ static int xgmac3_phy_read(void *priv, int phyaddr, int phyreg) { struct tc956xmac_priv *spriv = priv; u32 off, ret; - +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 3, 0)) if (!(phyreg & MII_ADDR_C45)) return -ENODEV; phyreg &= ~MII_ADDR_C45; +#endif off = (phyreg & GENMASK(7, 0)) << 4; writel(phyreg >> 8, spriv->ioaddr + XGMAC3_PHY_ADDR); @@ -867,10 +907,12 @@ static int xgmac3_phy_write(void *priv, int phyaddr, int phyreg, u16 phydata) struct tc956xmac_priv *spriv = priv; u32 off; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 3, 0)) if (!(phyreg & MII_ADDR_C45)) return -ENODEV; phyreg &= ~MII_ADDR_C45; +#endif off = (phyreg & GENMASK(7, 0)) << 4; writel(phyreg >> 8, spriv->ioaddr + XGMAC3_PHY_ADDR); @@ -991,7 +1033,7 @@ static void xgmac_default_data(struct plat_tc956xmacenet_data *plat) memcpy(plat->rxp_cfg.entries, snps_rxp_entries, ARRAY_SIZE(snps_rxp_entries) * sizeof(struct tc956xmac_rx_parser_entry)); - +#ifndef TC956X_SRIOV_VF /* Over writing the Default FRP table with FRP Table for Filtering PHY pause frames */ if ((mac0_filter_phy_pause == ENABLE && plat->port_num == RM_PF0_ID) || (mac1_filter_phy_pause == ENABLE && plat->port_num == RM_PF1_ID)) { @@ -1001,19 +1043,77 @@ static void xgmac_default_data(struct plat_tc956xmacenet_data *plat) ARRAY_SIZE(snps_rxp_entries_filter_phy_pause_frames) * sizeof(struct tc956xmac_rx_parser_entry)); } - +#endif } +#ifdef TC956X_SRIOV_VF +#ifdef TC956X_SRIOV_DEBUG +static void tc956x_print_vf_mac_config(struct pci_dev *pdev, + struct plat_tc956xmacenet_data *plat) +{ + u8 ch, k; + + dev_info(&pdev->dev, "******************************************************************\n"); + dev_info(&pdev->dev, "VF %d - MAC Config Params:\n", (plat->vf_id + 1)); + dev_info(&pdev->dev, "rx_queues_to_use_actual : %d\n", plat->rx_queues_to_use_actual); + dev_info(&pdev->dev, "tx_queues_to_use_actual : %d\n", plat->tx_queues_to_use_actual); + dev_info(&pdev->dev, "Ch enabled : \t"); + for (ch = 0; ch < MTL_MAX_RX_QUEUES; ch++) { + + if (plat->ch_in_use[ch] == 1) + dev_info(&pdev->dev, " %d\t", ch); + } + dev_info(&pdev->dev, "Tx Q in use : \t"); + for (ch = 0; ch < MTL_MAX_RX_QUEUES; ch++) { + + if (plat->tx_q_in_use[ch] == 1) + dev_info(&pdev->dev, "Q: %d Size: %d\t", ch, plat->tx_q_size[ch]); + } + dev_info(&pdev->dev, "Rx Q in use : \t"); + for (ch = 0; ch < MTL_MAX_RX_QUEUES; ch++) { + + if (plat->rx_q_in_use[ch] == 1) + dev_info(&pdev->dev, " %d\t", ch); + } + dev_info(&pdev->dev, "Best Ef Ch : %d\n", plat->best_effort_ch_no); + dev_info(&pdev->dev, "AVB A Ch : %d\n", plat->avb_class_a_ch_no); + dev_info(&pdev->dev, "AVB B Ch : %d\n", plat->avb_class_b_ch_no); + dev_info(&pdev->dev, "TSN Ch : %d\n", plat->tsn_ch_no); + + + + dev_info(&pdev->dev, "Tx Q config :\n"); + for (k = 0; k < MTL_MAX_RX_QUEUES; k++) { + dev_info(&pdev->dev, "Q%d : weight %d\n", k, plat->tx_queues_cfg[k].weight); + dev_info(&pdev->dev, "Q%d : mode_to_use %d\n", k, plat->tx_queues_cfg[k].mode_to_use); + dev_info(&pdev->dev, "Q%d : send_slope %d\n", k, plat->tx_queues_cfg[k].send_slope); + dev_info(&pdev->dev, "Q%d : idle_slope %d\n", k, plat->tx_queues_cfg[k].idle_slope); + dev_info(&pdev->dev, "Q%d : high_credit %d\n", k, plat->tx_queues_cfg[k].high_credit); + dev_info(&pdev->dev, "Q%d : low_credit %d\n", k, plat->tx_queues_cfg[k].low_credit); + dev_info(&pdev->dev, "Q%d : use_prio %d\n", k, plat->tx_queues_cfg[k].use_prio); + dev_info(&pdev->dev, "Q%d : prio %d\n", k, plat->tx_queues_cfg[k].prio); + dev_info(&pdev->dev, "Q%d : tbs_en %d\n", k, plat->tx_queues_cfg[k].tbs_en); + dev_info(&pdev->dev, "Q%d : tso_en %d\n", k, plat->tx_queues_cfg[k].tso_en); + dev_info(&pdev->dev, "\n"); + } + dev_info(&pdev->dev, "******************************************************************\n"); +} +#endif +#endif /* TC956X_SRIOV_VF */ + static int tc956xmac_xgmac3_default_data(struct pci_dev *pdev, struct plat_tc956xmacenet_data *plat) { +#ifndef TC956X_SRIOV_VF unsigned int queue0_rfd = 0, queue1_rfd = 0, queue0_rfa = 0, queue1_rfa = 0, temp_var = 0; unsigned int rxqueue0_size = 0, rxqueue1_size = 0, txqueue0_size = 0, txqueue1_size = 0; +#endif unsigned int forced_speed = 3; /* default 1Gbps */ /* Set common default data first */ xgmac_default_data(plat); + plat->gate_mask = 1; /* 1: tc_to_txq gate mask enabled by default. Traffic control gate event mapped to respective queues in kernel and sent to Driver */ plat->bus_id = 1; #ifdef TC956X plat->phy_addr = -1; @@ -1021,6 +1121,7 @@ static int tc956xmac_xgmac3_default_data(struct pci_dev *pdev, plat->phy_addr = 0; #endif plat->pdev = pdev; + plat->pse = 0; #ifdef TC956X if (plat->port_interface == ENABLE_USXGMII_INTERFACE) { @@ -1098,12 +1199,27 @@ static int tc956xmac_xgmac3_default_data(struct pci_dev *pdev, #endif - plat->maxmtu = MAX_SUPPORTED_MTU/*XGMAC_JUMBO_LEN*/; + plat->maxmtu = XGMAC_JUMBO_LEN; /* Set default number of RX and TX queues to use */ #ifdef TC956X plat->tx_queues_to_use = MAX_TX_QUEUES_TO_USE; plat->rx_queues_to_use = MAX_RX_QUEUES_TO_USE; +#ifdef TC956X_SRIOV_VF + plat->rx_queues_to_use_actual = tc956xmac_vf[plat->vf_id].rx_queues_to_use_actual; + plat->tx_queues_to_use_actual = tc956xmac_vf[plat->vf_id].tx_queues_to_use_actual; + memcpy(plat->ch_in_use, tc956xmac_vf[plat->vf_id].ch_in_use, sizeof(plat->ch_in_use)); + memcpy(plat->tx_q_in_use, tc956xmac_vf[plat->vf_id].tx_q_in_use, sizeof(plat->tx_q_in_use)); + memcpy(plat->rx_q_in_use, tc956xmac_vf[plat->vf_id].rx_q_in_use, sizeof(plat->rx_q_in_use)); + memcpy(plat->tx_q_size, tc956xmac_vf[plat->vf_id].tx_q_size, sizeof(plat->tx_q_size)); + plat->best_effort_ch_no = tc956xmac_vf[plat->vf_id].best_effort_ch_no; + plat->gptp_ch_no = tc956xmac_vf[plat->vf_id].gptp_ch_no; + plat->avb_class_a_ch_no = tc956xmac_vf[plat->vf_id].avb_class_a_ch_no; + plat->avb_class_b_ch_no = tc956xmac_vf[plat->vf_id].avb_class_b_ch_no; + plat->tsn_ch_no = tc956xmac_vf[plat->vf_id].tsn_ch_no; + plat->tsn_application = tc956xmac_vf[plat->vf_id].tsn_application; + plat->avb_application = tc956xmac_vf[plat->vf_id].avb_application; +#endif #else plat->tx_queues_to_use = 1; plat->rx_queues_to_use = 1; @@ -1111,15 +1227,28 @@ static int tc956xmac_xgmac3_default_data(struct pci_dev *pdev, #ifdef TC956X /* MTL Configuration */ + + /*Rx queue configuration for VFs are done in PF driver, so skip setting it here*/ +#ifndef TC956X_SRIOV_VF /* Static Mapping */ + /* Note : Best Effort, Broadcast/Multicast packet routing based + * on DA filter Channel Mapping + */ /* Unicast/Untagged Packets : Consider Jumbo packets */ plat->rx_queues_cfg[0].chan = LEG_UNTAGGED_PACKET; /* VLAN Tagged Legacy packets */ plat->rx_queues_cfg[1].chan = LEG_TAGGED_PACKET; /* Untagged gPTP packets */ plat->rx_queues_cfg[2].chan = UNTAGGED_GPTP_PACKET; + +#if defined(TC956X_AUTOMOTIVE_CONFIG) || defined(TC956X_ENABLE_MAC2MAC_BRIDGE) /* Tagged/Untagged AV control pkts */ plat->rx_queues_cfg[3].chan = UNTAGGED_AVCTRL_PACKET; +#else + /* Filter Failed Unicast, Multicast, Tagged packets */ + plat->rx_queues_cfg[3].chan = FILTER_FAIL_PACKET; +#endif + /* AVB Class B */ plat->rx_queues_cfg[4].chan = AVB_CLASS_B_PACKET; /* AVB Class A */ @@ -1142,20 +1271,33 @@ static int tc956xmac_xgmac3_default_data(struct pci_dev *pdev, plat->rx_sched_algorithm = MTL_RX_ALGORITHM_SP; plat->tx_sched_algorithm = MTL_TX_ALGORITHM_WRR; +#endif +#ifndef TC956X_SRIOV_VF /* Due to the erratum in XGMAC 3.01a, WRR weights not considered in * TX DMA read data arbitration. Workaround is at set all weights for Tx Queues with * WRR arbitration logic to 1 */ - plat->tx_queues_cfg[0].weight = 1; - plat->tx_queues_cfg[1].weight = 1; - plat->tx_queues_cfg[2].weight = 1; - plat->tx_queues_cfg[3].weight = 1; - plat->tx_queues_cfg[4].weight = 1; - plat->tx_queues_cfg[5].weight = 1; - plat->tx_queues_cfg[6].weight = 1; - plat->tx_queues_cfg[7].weight = 1; + /* Best Effort weitghts are same as its mapped to TC0 */ + plat->tx_queues_cfg[0].weight = 0x11; + plat->tx_queues_cfg[1].weight = 0x11; + plat->tx_queues_cfg[2].weight = 0x11; + plat->tx_queues_cfg[3].weight = 0x11; + plat->tx_queues_cfg[4].weight = 0x12; + plat->tx_queues_cfg[5].weight = 0x13; + plat->tx_queues_cfg[6].weight = 0x14; + plat->tx_queues_cfg[7].weight = 0x15; +#else + /* Each VF will have different configuration which is initialised in the + * tc956xmac_vf table. Copy all the tx queue configuration for this vf_id + * here + */ + memcpy(plat->tx_queues_cfg, tc956xmac_vf[plat->vf_id].tx_queues_cfg, sizeof(plat->tx_queues_cfg)); +#endif + + /*Rx queue configuration for VFs are done in PF driver, so skip setting it here*/ +#ifndef TC956X_SRIOV_VF plat->rx_queues_cfg[0].mode_to_use = RX_QUEUE0_MODE; plat->rx_queues_cfg[1].mode_to_use = RX_QUEUE1_MODE; plat->rx_queues_cfg[2].mode_to_use = RX_QUEUE2_MODE; @@ -1164,7 +1306,9 @@ static int tc956xmac_xgmac3_default_data(struct pci_dev *pdev, plat->rx_queues_cfg[5].mode_to_use = RX_QUEUE5_MODE; plat->rx_queues_cfg[6].mode_to_use = RX_QUEUE6_MODE; plat->rx_queues_cfg[7].mode_to_use = RX_QUEUE7_MODE; +#endif +#ifndef TC956X_SRIOV_VF plat->tx_queues_cfg[0].mode_to_use = TX_QUEUE0_MODE; plat->tx_queues_cfg[1].mode_to_use = TX_QUEUE1_MODE; plat->tx_queues_cfg[2].mode_to_use = TX_QUEUE2_MODE; @@ -1173,10 +1317,16 @@ static int tc956xmac_xgmac3_default_data(struct pci_dev *pdev, plat->tx_queues_cfg[5].mode_to_use = TX_QUEUE5_MODE; plat->tx_queues_cfg[6].mode_to_use = TX_QUEUE6_MODE; plat->tx_queues_cfg[7].mode_to_use = TX_QUEUE7_MODE; +#else + /*Already all configurations are copied through mem_cpy above*/ +#endif + +#ifndef TC956X_SRIOV_VF + /* CBS are per TC basis in TC956X (total TC = 5) */ + /* CBS: queue 5 -> Class B traffic (25% BW) */ + /* plat->tx_queues_cfg[3].idle_slope = plat->est_cfg.enable ? 0x8e4 : 0x800; */ /* CBS: queue 5 -> Class B traffic (25% BW) */ - /* plat->tx_queues_cfg[3].idle_slope = plat->est_cfg.enable ? 0x8e4 : 0x800; - */ plat->tx_queues_cfg[5].idle_slope = 0x800; plat->tx_queues_cfg[5].send_slope = 0x1800; plat->tx_queues_cfg[5].high_credit = 0x320000; @@ -1196,15 +1346,26 @@ static int tc956xmac_xgmac3_default_data(struct pci_dev *pdev, plat->tx_queues_cfg[7].high_credit = 0x500000; plat->tx_queues_cfg[7].low_credit = 0xff880000; - /* Disable Priority config by default */ - plat->tx_queues_cfg[0].use_prio = false; - plat->tx_queues_cfg[1].use_prio = false; - plat->tx_queues_cfg[2].use_prio = false; - plat->tx_queues_cfg[3].use_prio = false; - plat->tx_queues_cfg[4].use_prio = false; - plat->tx_queues_cfg[5].use_prio = false; - plat->tx_queues_cfg[6].use_prio = false; - plat->tx_queues_cfg[7].use_prio = false; +#endif +#ifndef TC956X_SRIOV_VF + /* Tx TC priority */ + plat->tx_queues_cfg[0].use_prio = TX_QUEUE0_USE_PRIO; + plat->tx_queues_cfg[1].use_prio = TX_QUEUE1_USE_PRIO; + plat->tx_queues_cfg[2].use_prio = TX_QUEUE2_USE_PRIO; + plat->tx_queues_cfg[3].use_prio = TX_QUEUE3_USE_PRIO; + plat->tx_queues_cfg[4].use_prio = TX_QUEUE4_USE_PRIO; + plat->tx_queues_cfg[5].use_prio = TX_QUEUE5_USE_PRIO; + plat->tx_queues_cfg[6].use_prio = TX_QUEUE6_USE_PRIO; + plat->tx_queues_cfg[7].use_prio = TX_QUEUE7_USE_PRIO; + + plat->tx_queues_cfg[0].prio = TX_QUEUE0_PRIO; + plat->tx_queues_cfg[1].prio = TX_QUEUE1_PRIO; + plat->tx_queues_cfg[2].prio = TX_QUEUE2_PRIO; + plat->tx_queues_cfg[3].prio = TX_QUEUE3_PRIO; + plat->tx_queues_cfg[4].prio = TX_QUEUE4_PRIO; + plat->tx_queues_cfg[5].prio = TX_QUEUE5_PRIO; + plat->tx_queues_cfg[6].prio = TX_QUEUE6_PRIO; + plat->tx_queues_cfg[7].prio = TX_QUEUE7_PRIO; /* Enable/Disable TBS */ plat->tx_queues_cfg[0].tbs_en = TX_QUEUE0_TBS; @@ -1259,8 +1420,8 @@ static int tc956xmac_xgmac3_default_data(struct pci_dev *pdev, plat->rx_queues_cfg[7].use_prio = RX_QUEUE7_USE_PRIO; plat->rx_queues_cfg[7].prio = RX_QUEUE7_PRIO; - -#else +#endif +#else /* TC956X */ /* Disable Priority config by default */ plat->tx_queues_cfg[0].use_prio = false; plat->tx_queues_cfg[0].mode_to_use = MTL_QUEUE_DCB; @@ -1314,6 +1475,13 @@ static int tc956xmac_xgmac3_default_data(struct pci_dev *pdev, memset(plat->est, 0, sizeof(*plat->est)); } +#ifdef TC956X_SRIOV_VF +#ifdef TC956X_SRIOV_DEBUG + tc956x_print_vf_mac_config(pdev, plat); +#endif +#endif + +#if defined(TC956X_SRIOV_PF) && defined(TC956X_DMA_OFFLOAD_ENABLE) plat->tx_dma_ch_owner[0] = TX_DMA_CH0_OWNER; plat->tx_dma_ch_owner[1] = TX_DMA_CH1_OWNER; plat->tx_dma_ch_owner[2] = TX_DMA_CH2_OWNER; @@ -1331,6 +1499,7 @@ static int tc956xmac_xgmac3_default_data(struct pci_dev *pdev, plat->rx_dma_ch_owner[5] = RX_DMA_CH5_OWNER; plat->rx_dma_ch_owner[6] = RX_DMA_CH6_OWNER; plat->rx_dma_ch_owner[7] = RX_DMA_CH7_OWNER; +#endif /* Configuration of PHY operating mode 1(true): for interrupt mode, 0(false): for polling mode */ if (plat->port_num == RM_PF0_ID) { @@ -1349,6 +1518,7 @@ static int tc956xmac_xgmac3_default_data(struct pci_dev *pdev, #endif } +#ifndef TC956X_SRIOV_VF /* Rx Queue size and flow control thresholds configuration */ if (plat->port_num == RM_PF0_ID) { rxqueue0_size = mac0_rxq0_size; @@ -1379,7 +1549,7 @@ static int tc956xmac_xgmac3_default_data(struct pci_dev *pdev, } /* Validation of Queue size and Flow control thresholds and configuring local parameters to update registers*/ - if((rxqueue0_size + rxqueue1_size) <= MAX_RX_QUEUE_SIZE) { + if ((rxqueue0_size + rxqueue1_size) <= MAX_RX_QUEUE_SIZE) { plat->rx_queues_cfg[0].size = rxqueue0_size; plat->rx_queues_cfg[1].size = rxqueue1_size; } else { @@ -1390,13 +1560,13 @@ static int tc956xmac_xgmac3_default_data(struct pci_dev *pdev, } - if((((queue0_rfd * SIZE_512B) + SIZE_1KB) < plat->rx_queues_cfg[0].size) && + if ((((queue0_rfd * SIZE_512B) + SIZE_1KB) < plat->rx_queues_cfg[0].size) && (((queue0_rfa * SIZE_512B) + SIZE_1KB) < plat->rx_queues_cfg[0].size)) { plat->rx_queues_cfg[0].rfd = queue0_rfd; plat->rx_queues_cfg[0].rfa = queue0_rfa; } else { temp_var = ((plat->rx_queues_cfg[0].size - (((plat->rx_queues_cfg[0].size)*8)/10))/SIZE_512B); /* configuration to 20% of FIFO Size */ - if(temp_var >= 2) { + if (temp_var >= 2) { temp_var = (temp_var - 2); } else { temp_var = 0; @@ -1407,13 +1577,13 @@ static int tc956xmac_xgmac3_default_data(struct pci_dev *pdev, __func__, queue0_rfd, queue0_rfa, plat->rx_queues_cfg[0].rfd, plat->rx_queues_cfg[0].rfa, plat->port_num); } - if((((queue1_rfd * SIZE_512B) + SIZE_1KB) < plat->rx_queues_cfg[1].size) && + if ((((queue1_rfd * SIZE_512B) + SIZE_1KB) < plat->rx_queues_cfg[1].size) && (((queue1_rfa * SIZE_512B) + SIZE_1KB) < plat->rx_queues_cfg[1].size)) { plat->rx_queues_cfg[1].rfd = queue1_rfd; plat->rx_queues_cfg[1].rfa = queue1_rfa; } else { temp_var = ((plat->rx_queues_cfg[1].size - (((plat->rx_queues_cfg[1].size)*8)/10))/SIZE_512B); /* configuration to 20% of FIFO Size */ - if(temp_var >= 2){ + if (temp_var >= 2) { temp_var = (temp_var - 2); } else { temp_var = 0; @@ -1424,16 +1594,16 @@ static int tc956xmac_xgmac3_default_data(struct pci_dev *pdev, __func__, queue1_rfd, queue1_rfa, plat->rx_queues_cfg[1].rfd, plat->rx_queues_cfg[1].rfa, plat->port_num); } - if((txqueue0_size + txqueue1_size) <= MAX_TX_QUEUE_SIZE) { + if ((txqueue0_size + txqueue1_size) <= MAX_TX_QUEUE_SIZE) { plat->tx_queues_cfg[0].size = txqueue0_size; plat->tx_queues_cfg[1].size = txqueue1_size; } else { plat->tx_queues_cfg[0].size = TX_QUEUE0_SIZE; /* Default configuration when invalid input given */ plat->tx_queues_cfg[1].size = TX_QUEUE1_SIZE; NMSGPR_INFO(&(pdev->dev), "%s: ERROR Invalid Rx Queue sizes passed txq0_size=%d, txq1_size=%d, Restoring default to txq0_size=%d, txq1_size=%d of port=%d\n", - __func__, rxqueue0_size, rxqueue1_size, TX_QUEUE0_SIZE, TX_QUEUE1_SIZE,plat->port_num); + __func__, rxqueue0_size, rxqueue1_size, TX_QUEUE0_SIZE, TX_QUEUE1_SIZE, plat->port_num); } - +#endif return 0; } @@ -1566,9 +1736,11 @@ static int tc956xmac_xgmac3_2_5g_default_data(struct pci_dev *pdev, plat->est->gcl_size = plat->tx_queues_to_use; for (i = 0; i < plat->tx_queues_to_use; i++) { +#ifndef TC956X u32 value = BIT(24 + i) + 100000; plat->est->gcl_unaligned[i] = value; +#endif } tc956xmac_config_data(plat); @@ -1602,6 +1774,7 @@ static const struct tc956xmac_pci_info tc956xmac_xgmac3_2_5g_mdio_pci_info = { }; #endif /* TC956X_UNSUPPORTED_UNTESTED_FEATURE */ +#ifndef TC956X_SRIOV_VF /*! * \brief API to Reset SRAM Region. * @@ -1621,7 +1794,7 @@ static void tc956x_reset_SRAM(struct device *dev, struct tc956xmac_resources *re memset_io((res->tc956x_SRAM_pci_base_addr + 0x40000), 0x0, 0x10000); NMSGPR_INFO(dev, "Resetting SRAM Region end\n"); } - + /*! * \brief API to load firmware for CM3. * @@ -1712,7 +1885,7 @@ s32 tc956x_load_firmware(struct device *dev, struct tc956xmac_resources *res) } NMSGPR_INFO(dev, "FW Loading Start...\n"); - NMSGPR_INFO(dev, "FW Size = %ld\n", (long int)(pfw->size)); + NMSGPR_INFO(dev, "FW Size = %ld\n", (long)(pfw->size)); /* Assert M3 reset */ #ifdef TC956X @@ -1763,8 +1936,8 @@ s32 tc956x_load_firmware(struct device *dev, struct tc956xmac_resources *res) return 0; } - -#ifdef DMA_OFFLOAD_ENABLE +#endif /*TC956X_SRIOV_VF*/ +#ifdef TC956X_DMA_OFFLOAD_ENABLE /* * brief API to populate the table address map registers. * @@ -1815,6 +1988,7 @@ void tc956x_config_CM3_tamap(struct device *dev, } #endif +#ifndef TC956X_SRIOV_VF /* * brief API to populate the table address map registers. * @@ -1828,8 +2002,28 @@ static void tc956x_config_tamap(struct device *dev, void __iomem *reg_pci_base_addr) { #ifdef TC956X + u32 table_entry; + DBGPR_FUNC(dev, "-->%s\n", __func__); + /* Set all entries to default */ + for (table_entry = 0; table_entry <= MAX_CM3_TAMAP_ENTRIES; table_entry++) { + + writel(TC956X_AXI4_SLV00_TRSL_PARAM_VAL, reg_pci_base_addr + + TC956X_AXI4_SLV_TRSL_PARAM(0, table_entry)); + writel(0x0, reg_pci_base_addr + + TC956X_AXI4_SLV_TRSL_ADDR_HI(0, table_entry)); + writel(0x0, reg_pci_base_addr + + TC956X_AXI4_SLV_TRSL_ADDR_LO(0, table_entry)); + writel(0x0, reg_pci_base_addr + + TC956X_AXI4_SLV_SRC_ADDR_HI(0, table_entry)); + writel(TC956X_AXI4_SLV00_SRC_ADDR_LO_VAL_DEFAULT, reg_pci_base_addr + + TC956X_AXI4_SLV_SRC_ADDR_LO(0, table_entry)); + + } + + + /* AXI4 Slave 0 - Table 0 Entry */ /* EDMA address region 0x10 0000 0000 - 0x1F FFFF FFFF is * translated to 0x0 0000 0000 - 0xF FFFF FFFF @@ -1865,6 +2059,48 @@ static void tc956x_config_tamap(struct device *dev, #endif DBGPR_FUNC(dev, "<--%s\n", __func__); } +#endif + +#ifdef TC956X_SRIOV_VF +static int tc956x_vf_get_fn_id(void __iomem *reg_pci_bridge_config_addr, + struct fn_id *fn_id_info) +{ + void __iomem *ioaddr = reg_pci_bridge_config_addr; + u32 rsc_mng_id = readl(ioaddr + RSCMNG_ID_REG); + + fn_id_info->fn_type = (rsc_mng_id & RSC_MNG_FN_TYPE) >> 16; + fn_id_info->pf_no = (rsc_mng_id & RSC_MNG_PF_FN_NUM); + fn_id_info->vf_no = ((rsc_mng_id & RSC_MNG_VF_FN_NUM) >> 8); + + /** Below error check for VF driver. + * In case of VF driver, function type to be 1 + */ + if (fn_id_info->fn_type == 0) + return -1; + + /* VF1,2,3 are supported */ + if (fn_id_info->vf_no > 3) + return -1; + + /* PF 0 and 1 are supported */ + if (fn_id_info->pf_no > 1) + return -1; + + return 0; +} + +static int get_vf_id(struct plat_tc956xmacenet_data *plat_dat, + struct tc956xmac_resources *res) +{ + struct fn_id fn_id_info; + + tc956x_vf_get_fn_id(res->tc956x_BRIDGE_CFG_pci_base_addr, &fn_id_info); + + plat_dat->vf_id = fn_id_info.vf_no - 1; + return 0; + +} +#endif #ifdef TC956X @@ -2173,28 +2409,38 @@ static int tc956xmac_pci_probe(struct pci_dev *pdev, struct tc956xmac_pci_info *info = (struct tc956xmac_pci_info *)id->driver_data; struct plat_tc956xmacenet_data *plat; struct tc956xmac_resources res; -#ifdef TC956X_PCIE_LINK_STATE_LATENCY_CTRL +#if (defined(TC956X_PCIE_DSP_CUT_THROUGH) || defined(TC956X_PCIE_GEN3_SETTING)) && defined(TC956X_SRIOV_PF) + u32 val; +#endif +#if defined(TC956X_PCIE_LINK_STATE_LATENCY_CTRL) && defined(TC956X_SRIOV_PF) u32 reg_val; #endif /* end of TC956X_PCIE_LINK_STATE_LATENCY_CTRL */ #ifdef TC956X - /* use signal from MSPHY */ +#ifndef TC956X_SRIOV_VF + /* use signal from EMSPHY */ uint8_t SgmSigPol = 0; -#ifdef TC956X_PCIE_GEN3_SETTING - u32 val; #endif #endif - int ret; char version_str[32]; -#ifdef TC956X_PCIE_LOGSTAT - struct tc956x_ltssm_log ltssm_data; -#endif/*TC956X_PCIE_LOGSTAT*/ +#if defined(TC956X_PCIE_DSP_CUT_THROUGH) && defined(TC956X_SRIOV_PF) + u32 pcie_mode; /* Read Setting A/B */ +#endif + KPRINT_INFO("%s >", __func__); +#ifndef TC956X_SRIOV_VF scnprintf(version_str, sizeof(version_str), "Host Driver Version %d%d-%d%d-%d%d", tc956x_drv_version.rel_dbg, tc956x_drv_version.major, tc956x_drv_version.minor, tc956x_drv_version.sub_minor, tc956x_drv_version.patch_rel_major, tc956x_drv_version.patch_rel_minor); +#else + scnprintf(version_str, sizeof(version_str), "Virtual Function Driver Version %d%d-%d%d-%d%d", + tc956x_drv_version.rel_dbg, + tc956x_drv_version.major, tc956x_drv_version.minor, + tc956x_drv_version.sub_minor, + tc956x_drv_version.patch_rel_major, tc956x_drv_version.patch_rel_minor); +#endif NMSGPR_INFO(&pdev->dev, "%s\n", version_str); plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL); @@ -2228,14 +2474,71 @@ static int tc956xmac_pci_probe(struct pci_dev *pdev, DBGPR_FUNC(&(pdev->dev), "<--%s : ret: %d\n", __func__, ret); goto err_out_req_reg_failed; } + memset(&res, 0, sizeof(res)); +#if defined(TC956X_SRIOV_PF) && (defined(TC956X_AUTOMOTIVE_CONFIG) || defined(TC956X_ENABLE_MAC2MAC_BRIDGE)) + if (tc956x_no_of_vf > 0) { + tc956x_no_of_vf = 0; + NMSGPR_INFO(&(pdev->dev), + "Enabling SRIOV not allowed in Automotive configuration\n"); + } +#endif +#ifdef TC956X_SRIOV_PF +#ifdef CONFIG_PCI_IOV + + + /* Enable SRIOV with the requested no of VFs */ + if ((tc956x_no_of_vf != 0) && (pdev->is_physfn)) { + + s32 pos = 0; + + pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV); + if (pos) { + NDBGPR_L1(&(pdev->dev), "SR-IOV capability found\n"); + + /* Validate and Enable the requested No. of VFs value */ + if (tc956x_no_of_vf <= TC956X_TOTAL_VFS) { + + ret = pci_enable_sriov(pdev, tc956x_no_of_vf); + if (ret) { + + NMSGPR_ERR(&(pdev->dev), + "%s : SRIOV enable failed.\n", + TC956X_RESOURCE_NAME); + DBGPR_FUNC(&(pdev->dev), + "<--%s: ret: %d\n", __func__, ret); + goto err_sriov_vf_en_failed; + } + + res.sriov_enabled = 1; + + NMSGPR_INFO(&(pdev->dev), + "Total SR-IOV VFs Enabled: %d\n", + tc956x_no_of_vf); + } else { + NMSGPR_ALERT(&(pdev->dev), + "%s : VFs Value Out of Range.\n", + TC956X_RESOURCE_NAME); + } + } else { + NDBGPR_L1(&(pdev->dev), + "SR-IOV capability not found\n"); + } + } +#endif +#endif + /* From the Kernel version 6.4.0, AER Error reporting is enabled by default. + * It is enabled in pci_device_add() Kernel Space API. + * So not required to enable from EMAC Driver. + */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0)) /* Enable AER Error reporting, if device capability is detected */ if (pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR)) { pci_enable_pcie_error_reporting(pdev); NMSGPR_INFO(&(pdev->dev), "AER Capability Enabled\n"); } - +#endif /* Enable the bus mastering */ pci_set_master(pdev); @@ -2252,22 +2555,27 @@ static int tc956xmac_pci_probe(struct pci_dev *pdev, dev_info(&(pdev->dev), "BAR4 physical address = 0x%llx\n", (u64)pci_resource_start(pdev, 4)); - memset(&res, 0, sizeof(res)); #ifdef TC956X - +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)) + res.tc956x_BRIDGE_CFG_pci_base_addr = ioremap + (pci_resource_start(pdev, TC956X_BAR0), pci_resource_len(pdev, TC956X_BAR0)); +#else res.tc956x_BRIDGE_CFG_pci_base_addr = ioremap_nocache (pci_resource_start(pdev, TC956X_BAR0), pci_resource_len(pdev, TC956X_BAR0)); - +#endif if (((void __iomem *)res.tc956x_BRIDGE_CFG_pci_base_addr == NULL)) { NMSGPR_ERR(&(pdev->dev), "%s: cannot map TC956X BAR0, aborting", pci_name(pdev)); ret = -EIO; DBGPR_FUNC(&(pdev->dev), "<--%s : ret: %d\n", __func__, ret); goto err_out_map_failed; } - +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)) + res.tc956x_SRAM_pci_base_addr = ioremap + (pci_resource_start(pdev, TC956X_BAR2), pci_resource_len(pdev, TC956X_BAR2)); +#else res.tc956x_SRAM_pci_base_addr = ioremap_nocache (pci_resource_start(pdev, TC956X_BAR2), pci_resource_len(pdev, TC956X_BAR2)); - +#endif if (((void __iomem *)res.tc956x_SRAM_pci_base_addr == NULL)) { pci_iounmap(pdev, (void __iomem *)res.tc956x_BRIDGE_CFG_pci_base_addr); NMSGPR_ERR(&(pdev->dev), "%s: cannot map TC956X BAR2, aborting", pci_name(pdev)); @@ -2275,10 +2583,13 @@ static int tc956xmac_pci_probe(struct pci_dev *pdev, DBGPR_FUNC(&(pdev->dev), "<--%s : ret: %d\n", __func__, ret); goto err_out_map_failed; } - +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)) + res.tc956x_SFR_pci_base_addr = ioremap + (pci_resource_start(pdev, TC956X_BAR4), pci_resource_len(pdev, TC956X_BAR4)); +#else res.tc956x_SFR_pci_base_addr = ioremap_nocache (pci_resource_start(pdev, TC956X_BAR4), pci_resource_len(pdev, TC956X_BAR4)); - +#endif if (((void __iomem *)res.tc956x_SFR_pci_base_addr == NULL)) { pci_iounmap(pdev, (void __iomem *)res.tc956x_BRIDGE_CFG_pci_base_addr); pci_iounmap(pdev, (void __iomem *)res.tc956x_SRAM_pci_base_addr); @@ -2293,6 +2604,37 @@ static int tc956xmac_pci_probe(struct pci_dev *pdev, NDBGPR_L1(&(pdev->dev), "BAR4 virtual address = %p\n", res.tc956x_SFR_pci_base_addr); res.addr = res.tc956x_SFR_pci_base_addr; + +#ifdef TC956X + res.port_num = readl(res.tc956x_BRIDGE_CFG_pci_base_addr + RSCMNG_ID_REG); /* Resource Manager ID */ + res.port_num &= RSCMNG_PFN; +#endif + +#ifndef TC956X_SRIOV_VF +#ifdef TC956X_PCIE_LOGSTAT + if (res.port_num == RM_PF0_ID) { +#ifdef TC956X_PCIE_LOGSTAT_SUMMARY_ENABLE + if ((tc956x_logstat_state_log_summary((void __iomem *)res.addr, UPSTREAM_PORT) < 0) + || (tc956x_logstat_state_log_summary((void __iomem *)res.addr, DOWNSTREAM_PORT1) < 0) + || (tc956x_logstat_state_log_summary((void __iomem *)res.addr, DOWNSTREAM_PORT2) < 0) + || (tc956x_logstat_state_log_summary((void __iomem *)res.addr, INTERNAL_ENDPOINT) < 0)) { + ret = -EFAULT; /* The returns returned by above functions are -EFAULT only */ + DBGPR_FUNC(&(pdev->dev), "<--%s : Error ret: %d\n", __func__, ret); + goto err_dvr_logstat; + } +#endif /* #ifdef TC956X_PCIE_LOGSTAT_SUMMARY_ENABLE */ + + if ((tc956x_logstat_set_state_log_enable((void __iomem *)res.addr, UPSTREAM_PORT, STATE_LOG_ENABLE) < 0) + || (tc956x_logstat_set_state_log_enable((void __iomem *)res.addr, DOWNSTREAM_PORT1, STATE_LOG_ENABLE) < 0) + || (tc956x_logstat_set_state_log_enable((void __iomem *)res.addr, DOWNSTREAM_PORT2, STATE_LOG_ENABLE) < 0) + || (tc956x_logstat_set_state_log_enable((void __iomem *)res.addr, INTERNAL_ENDPOINT, STATE_LOG_ENABLE) < 0)) { + ret = -EFAULT; /* The returns returned by above functions are -EFAULT only */ + DBGPR_FUNC(&(pdev->dev), "<--%s : Error ret: %d\n", __func__, ret); + goto err_dvr_logstat; + } + } +#endif /* TC956X_PCIE_LOGSTAT */ + #ifdef TC956X_PCIE_GEN3_SETTING val = readl(res.addr + TC956X_GLUE_EFUSE_CTRL); if ((val & 0x10) == 0) { @@ -2310,7 +2652,9 @@ static int tc956xmac_pci_probe(struct pci_dev *pdev, if ((pcie_link_speed >= 1) && (pcie_link_speed <= 3)) tc956x_set_pci_speed(pdev, pcie_link_speed); #endif +#endif /*#ifdef TC956X_SRIOV_VF*/ +#if defined(TC956X_SRIOV_PF) #ifdef TC956X_PCIE_LINK_STATE_LATENCY_CTRL /* 0x4002_C02C SSREG_GLUE_SW_REG_ACCESS_CTRL.sw_port_reg_access_enable for USP Access enable */ writel(SW_USP_ENABLE, res.addr + TC956X_GLUE_SW_REG_ACCESS_CTRL); @@ -2333,7 +2677,7 @@ static int tc956xmac_pci_probe(struct pci_dev *pdev, /* 0x4002_4970 K_PEXCONF_210_219.aspm_L1_entry_delay in terms of 256ns */ writel(DSP2_L1_ENTRY_DELAY, res.addr + TC956X_PCIE_S_L1_ENTRY_LATENCY); - /* 0x4002_C02C SSREG_GLUE_SW_REG_ACCESS_CTRL.sw_port_reg_access_enable + /* 0x4002_C02C SSREG_GLUE_SW_REG_ACCESS_CTRL.sw_port_reg_access_enable for VDSP Access enable */ writel(SW_VDSP_ENABLE, res.addr + TC956X_GLUE_SW_REG_ACCESS_CTRL); /* 0x4002_496C K_PEXCONF_209_205.aspm_l0s_entry_delay in terms of 256ns */ @@ -2349,18 +2693,24 @@ static int tc956xmac_pci_probe(struct pci_dev *pdev, /* Updating PCIE EP Capability setting of L0s & L1 entry delays */ reg_val |= (((EP_L0s_ENTRY_DELAY << TC956X_PCIE_EP_L0s_ENTRY_SHIFT) & - TC956X_PCIE_EP_L0s_ENTRY_MASK) | + TC956X_PCIE_EP_L0s_ENTRY_MASK) | ((EP_L1_ENTRY_DELAY << TC956X_PCIE_EP_L1_ENTRY_SHIFT) & TC956X_PCIE_EP_L1_ENTRY_MASK)); /* 0x4002_00D8 PCIE EP Capability setting L0S & L1 entry delay in terms of 256ns */ writel(reg_val, res.addr + TC956X_PCIE_EP_CAPB_SET); - /* 0x4002_C02C SSREG_GLUE_SW_REG_ACCESS_CTRL.sw_port_reg_access_enable + /* 0x4002_C02C SSREG_GLUE_SW_REG_ACCESS_CTRL.sw_port_reg_access_enable for All Switch Ports Access enable */ writel(TC956X_PCIE_S_EN_ALL_PORTS_ACCESS, res.addr + TC956X_GLUE_SW_REG_ACCESS_CTRL); #endif /* end of TC956X_PCIE_LINK_STATE_LATENCY_CTRL */ +#endif /* TC956X_SRIOV_PF*/ +#ifdef TC956X_SRIOV_VF + get_vf_id(plat, &res); +#endif /*#ifdef TC956X_SRIOV_VF*/ + +#ifndef TC956X_SRIOV_VF #ifdef TC956X_PCIE_DISABLE_DSP1 tc956x_pcie_disable_dsp1_port(&pdev->dev, res.tc956x_SFR_pci_base_addr); #endif @@ -2376,7 +2726,14 @@ static int tc956xmac_pci_probe(struct pci_dev *pdev, res.port_num = readl(res.tc956x_BRIDGE_CFG_pci_base_addr + RSCMNG_ID_REG); /* Resource Manager ID */ res.port_num &= RSCMNG_PFN; #endif - +#ifdef TC956X_SRIOV_PF +#ifdef TC956X_MAGIC_PACKET_WOL_GPIO + if (res.port_num == RM_PF0_ID) { + KPRINT_INFO("%s: Port %d - Configuring GPIO for WOL", __func__, res.port_num); + tc956x_wol_gpio_trigger(res.addr, false); /* Set to LOW */ + } +#endif +#endif /* TC956X_SRIOV_PF */ #ifdef DISABLE_EMAC_PORT1 #ifdef TC956X if (res.port_num == RM_PF1_ID) { @@ -2394,59 +2751,65 @@ static int tc956xmac_pci_probe(struct pci_dev *pdev, } #endif #endif +#endif /*#ifdef TC956X_SRIOV_VF*/ plat->port_num = res.port_num; +#ifndef TC956X_SRIOV_VF /* User configured/Default Module parameters of TC956x*/ - NMSGPR_INFO(&pdev->dev, "User Configured/Default Module parameters of TC956x of Port-%d\n",plat->port_num); + NMSGPR_INFO(&pdev->dev, "User Configured/Default Module parameters of TC956x of Port-%d\n", plat->port_num); if (plat->port_num == RM_PF0_ID) { #ifdef TC956X_PCIE_GEN3_SETTING - NMSGPR_INFO(&pdev->dev, "pcie_link_speed = %d \n", pcie_link_speed); + NMSGPR_INFO(&pdev->dev, "pcie_link_speed = %d\n", pcie_link_speed); #endif - NMSGPR_INFO(&pdev->dev, "mac0_force_speed_mode = %d \n", mac0_force_speed_mode); - NMSGPR_INFO(&pdev->dev, "mac0_force_config_speed = %d \n", mac0_force_config_speed); - NMSGPR_INFO(&pdev->dev, "mac0_interface = %d \n", mac0_interface); - NMSGPR_INFO(&pdev->dev, "mac0_eee_enable = %d \n", mac0_eee_enable); - NMSGPR_INFO(&pdev->dev, "mac0_lpi_timer = %d \n", mac0_lpi_timer); - NMSGPR_INFO(&pdev->dev, "mac0_filter_phy_pause = %d \n", mac0_filter_phy_pause); - NMSGPR_INFO(&pdev->dev, "mac0_rxq0_size = %d \n", mac0_rxq0_size); - NMSGPR_INFO(&pdev->dev, "mac0_rxq1_size = %d \n", mac0_rxq1_size); - NMSGPR_INFO(&pdev->dev, "mac0_rxq0_rfd = %d \n", mac0_rxq0_rfd); - NMSGPR_INFO(&pdev->dev, "mac0_rxq0_rfa = %d \n", mac0_rxq0_rfa); - NMSGPR_INFO(&pdev->dev, "mac0_rxq1_rfd = %d \n", mac0_rxq1_rfd); - NMSGPR_INFO(&pdev->dev, "mac0_rxq1_rfa = %d \n", mac0_rxq1_rfa); - NMSGPR_INFO(&pdev->dev, "mac0_txq0_size = %d \n", mac0_txq0_size); - NMSGPR_INFO(&pdev->dev, "mac0_txq1_size = %d \n", mac0_txq1_size); - NMSGPR_INFO(&pdev->dev, "mac0_en_lp_pause_frame_cnt = %d \n", mac0_en_lp_pause_frame_cnt); + NMSGPR_INFO(&pdev->dev, "mac0_force_speed_mode = %d\n", mac0_force_speed_mode); + NMSGPR_INFO(&pdev->dev, "mac0_force_config_speed = %d\n", mac0_force_config_speed); + NMSGPR_INFO(&pdev->dev, "mac0_interface = %d\n", mac0_interface); + NMSGPR_INFO(&pdev->dev, "mac0_eee_enable = %d\n", mac0_eee_enable); + NMSGPR_INFO(&pdev->dev, "mac0_lpi_timer = %d\n", mac0_lpi_timer); + NMSGPR_INFO(&pdev->dev, "mac0_filter_phy_pause = %d\n", mac0_filter_phy_pause); + NMSGPR_INFO(&pdev->dev, "mac0_rxq0_size = %d\n", mac0_rxq0_size); + NMSGPR_INFO(&pdev->dev, "mac0_rxq1_size = %d\n", mac0_rxq1_size); + NMSGPR_INFO(&pdev->dev, "mac0_rxq0_rfd = %d\n", mac0_rxq0_rfd); + NMSGPR_INFO(&pdev->dev, "mac0_rxq0_rfa = %d\n", mac0_rxq0_rfa); + NMSGPR_INFO(&pdev->dev, "mac0_rxq1_rfd = %d\n", mac0_rxq1_rfd); + NMSGPR_INFO(&pdev->dev, "mac0_rxq1_rfa = %d\n", mac0_rxq1_rfa); + NMSGPR_INFO(&pdev->dev, "mac0_txq0_size = %d\n", mac0_txq0_size); + NMSGPR_INFO(&pdev->dev, "mac0_txq1_size = %d\n", mac0_txq1_size); + NMSGPR_INFO(&pdev->dev, "mac0_en_lp_pause_frame_cnt = %d\n", mac0_en_lp_pause_frame_cnt); NMSGPR_INFO(&pdev->dev, "mac_power_save_at_link_down = %d \n", mac_power_save_at_link_down); NMSGPR_INFO(&pdev->dev, "mac0_link_down_macrst = %d \n", mac0_link_down_macrst); } else if (plat->port_num == RM_PF1_ID) { - NMSGPR_INFO(&pdev->dev, "mac1_force_speed_mode = %d \n", mac1_force_speed_mode); - NMSGPR_INFO(&pdev->dev, "mac1_force_config_speed = %d \n", mac1_force_config_speed); - NMSGPR_INFO(&pdev->dev, "mac1_interface = %d \n", mac1_interface); - NMSGPR_INFO(&pdev->dev, "mac1_eee_enable = %d \n", mac1_eee_enable); - NMSGPR_INFO(&pdev->dev, "mac1_filter_phy_pause = %d \n", mac1_filter_phy_pause); - NMSGPR_INFO(&pdev->dev, "mac1_lpi_timer = %d \n", mac1_lpi_timer); - NMSGPR_INFO(&pdev->dev, "mac1_rxq0_size = %d \n", mac1_rxq0_size); - NMSGPR_INFO(&pdev->dev, "mac1_rxq1_size = %d \n", mac1_rxq1_size); - NMSGPR_INFO(&pdev->dev, "mac1_rxq0_rfd = %d \n", mac1_rxq0_rfd); - NMSGPR_INFO(&pdev->dev, "mac1_rxq0_rfa = %d \n", mac1_rxq0_rfa); - NMSGPR_INFO(&pdev->dev, "mac1_rxq1_rfd = %d \n", mac1_rxq1_rfd); - NMSGPR_INFO(&pdev->dev, "mac1_rxq1_rfa = %d \n", mac1_rxq1_rfa); - NMSGPR_INFO(&pdev->dev, "mac1_txq0_size = %d \n", mac1_txq0_size); - NMSGPR_INFO(&pdev->dev, "mac1_txq1_size = %d \n", mac1_txq1_size); - NMSGPR_INFO(&pdev->dev, "mac1_en_lp_pause_frame_cnt = %d \n", mac1_en_lp_pause_frame_cnt); + NMSGPR_INFO(&pdev->dev, "mac1_force_speed_mode = %d\n", mac1_force_speed_mode); + NMSGPR_INFO(&pdev->dev, "mac1_force_config_speed = %d\n", mac1_force_config_speed); + NMSGPR_INFO(&pdev->dev, "mac1_interface = %d\n", mac1_interface); + NMSGPR_INFO(&pdev->dev, "mac1_eee_enable = %d\n", mac1_eee_enable); + NMSGPR_INFO(&pdev->dev, "mac1_filter_phy_pause = %d\n", mac1_filter_phy_pause); + NMSGPR_INFO(&pdev->dev, "mac1_lpi_timer = %d\n", mac1_lpi_timer); + NMSGPR_INFO(&pdev->dev, "mac1_rxq0_size = %d\n", mac1_rxq0_size); + NMSGPR_INFO(&pdev->dev, "mac1_rxq1_size = %d\n", mac1_rxq1_size); + NMSGPR_INFO(&pdev->dev, "mac1_rxq0_rfd = %d\n", mac1_rxq0_rfd); + NMSGPR_INFO(&pdev->dev, "mac1_rxq0_rfa = %d\n", mac1_rxq0_rfa); + NMSGPR_INFO(&pdev->dev, "mac1_rxq1_rfd = %d\n", mac1_rxq1_rfd); + NMSGPR_INFO(&pdev->dev, "mac1_rxq1_rfa = %d\n", mac1_rxq1_rfa); + NMSGPR_INFO(&pdev->dev, "mac1_txq0_size = %d\n", mac1_txq0_size); + NMSGPR_INFO(&pdev->dev, "mac1_txq1_size = %d\n", mac1_txq1_size); + NMSGPR_INFO(&pdev->dev, "mac1_en_lp_pause_frame_cnt = %d\n", mac1_en_lp_pause_frame_cnt); NMSGPR_INFO(&pdev->dev, "mac1_link_down_macrst = %d \n", mac1_link_down_macrst); } +#endif +#if defined(TC956X_SRIOV_PF) || defined(TC956X_AUTOMOTIVE_CONFIG) if (res.port_num == RM_PF0_ID) { - plat->mdc_clk = PORT0_MDC; - plat->c45_needed = PORT0_C45_STATE; + plat->mdc_clk = port0_mdc; + plat->c45_needed = port0_c45_state == 1 ? true : false; + plat->start_phy_addr = port0_phyaddr; } if (res.port_num == RM_PF1_ID) { - plat->mdc_clk = PORT1_MDC; - plat->c45_needed = PORT1_C45_STATE; + plat->mdc_clk = port1_mdc; + plat->c45_needed = port1_c45_state == 1 ? true : false; + plat->start_phy_addr = port1_phyaddr; } if (res.port_num == RM_PF0_ID) { @@ -2460,10 +2823,9 @@ static int tc956xmac_pci_probe(struct pci_dev *pdev, if (res.port_num == RM_PF1_ID) { /* Set the PORT1 interface mode to default, in case of invalid input */ - if ((mac1_interface < ENABLE_RGMII_INTERFACE) || + if ((mac1_interface < ENABLE_USXGMII_INTERFACE) || (mac1_interface > ENABLE_2500BASE_X_INTERFACE)) mac1_interface = ENABLE_SGMII_INTERFACE; - res.port_interface = mac1_interface; } @@ -2483,18 +2845,18 @@ static int tc956xmac_pci_probe(struct pci_dev *pdev, __func__, mac0_force_config_speed); } } - if ((mac0_eee_enable != DISABLE) && + if ((mac0_eee_enable != DISABLE) && (mac0_eee_enable != ENABLE)) { mac0_eee_enable = DISABLE; - NMSGPR_INFO(&(pdev->dev), "%s: ERROR Invalid mac0_eee_enable parameter passed. Restoring default to %d. Supported Values are 0 and 1.\n", - __func__, mac1_eee_enable); + NMSGPR_INFO(&(pdev->dev), "%s: ERROR Invalid mac0_eee_enable parameter passed. Restoring default to %d. Supported Values are 0 and 1.\n", + __func__, mac0_eee_enable); } - if ((mac0_eee_enable == ENABLE) && + if ((mac0_eee_enable == ENABLE) && (mac0_lpi_timer > TC956X_MAX_LPI_AUTO_ENTRY_TIMER)) { mac0_lpi_timer = TC956XMAC_LPIET_600US; - NMSGPR_INFO(&(pdev->dev), "%s: ERROR Invalid mac0_lpi_timer parameter passed. Restoring default to %d. Supported Values between %d and %d.\n", - __func__, mac1_lpi_timer, + NMSGPR_INFO(&(pdev->dev), "%s: ERROR Invalid mac0_lpi_timer parameter passed. Restoring default to %d. Supported Values between %d and %d.\n", + __func__, mac1_lpi_timer, TC956X_MIN_LPI_AUTO_ENTRY_TIMER, TC956X_MAX_LPI_AUTO_ENTRY_TIMER); } res.eee_enabled = mac0_eee_enable; @@ -2516,30 +2878,31 @@ static int tc956xmac_pci_probe(struct pci_dev *pdev, } } - if ((mac1_eee_enable != DISABLE) && + if ((mac1_eee_enable != DISABLE) && (mac1_eee_enable != ENABLE)) { mac1_eee_enable = DISABLE; - NMSGPR_INFO(&(pdev->dev), "%s: ERROR Invalid mac1_eee_enable parameter passed. Restoring default to %d. Supported Values are 0 and 1.\n", + NMSGPR_INFO(&(pdev->dev), "%s: ERROR Invalid mac1_eee_enable parameter passed. Restoring default to %d. Supported Values are 0 and 1.\n", __func__, mac1_eee_enable); } - if ((mac0_eee_enable == ENABLE) && + if ((mac0_eee_enable == ENABLE) && (mac1_lpi_timer > TC956X_MAX_LPI_AUTO_ENTRY_TIMER)) { mac1_lpi_timer = TC956XMAC_LPIET_600US; - NMSGPR_INFO(&(pdev->dev), "%s: ERROR Invalid mac1_lpi_timer parameter passed. Restoring default to %d. Supported Values between %d and %d.\n", - __func__, mac1_lpi_timer, + NMSGPR_INFO(&(pdev->dev), "%s: ERROR Invalid mac1_lpi_timer parameter passed. Restoring default to %d. Supported Values between %d and %d.\n", + __func__, mac1_lpi_timer, TC956X_MIN_LPI_AUTO_ENTRY_TIMER, TC956X_MAX_LPI_AUTO_ENTRY_TIMER); } res.eee_enabled = mac1_eee_enable; res.tx_lpi_timer = mac1_lpi_timer; } - +#endif ret = info->setup(pdev, plat); if (ret) return ret; #ifdef TC956X +#ifndef TC956X_SRIOV_VF if (res.port_num == RM_PF0_ID) { ret = readl(res.addr + NRSTCTRL0_OFFSET); ret |= (NRSTCTRL0_INTRST); @@ -2558,10 +2921,37 @@ static int tc956xmac_pci_probe(struct pci_dev *pdev, */ tc956x_config_tamap(&pdev->dev, res.tc956x_BRIDGE_CFG_pci_base_addr); } - +#endif /*#ifdef TC956X_SRIOV_VF*/ #endif - +#ifdef TC956X_SRIOV_PF NMSGPR_INFO(&(pdev->dev), "Initialising eMAC Port %d\n", res.port_num); + /* Enable MSI and Allocate Vectors */ + ret = pci_alloc_irq_vectors(pdev, TC956X_TOT_MSI_VEC, + TC956X_TOT_MSI_VEC, PCI_IRQ_MSI); + + if (ret < TC956X_TOT_MSI_VEC) { + dev_err(&(pdev->dev), + "%s:Enable MSI error\n", TC956X_RESOURCE_NAME); + DBGPR_FUNC(&(pdev->dev), "<--%s : ret: %d\n", __func__, ret); + goto err_out_msi_failed; + } + + DBGPR_FUNC(&(pdev->dev), "%s : Allocated MSI Vectors : %d", + __func__, ret); +#elif defined TC956X_SRIOV_VF + /* Enable MSI and Allocate Vectors */ + ret = pci_alloc_irq_vectors(pdev, TC956X_MIN_MSI_VEC, + TC956X_MAX_MSI_VEC, PCI_IRQ_MSI); + + if (ret < TC956X_MIN_MSI_VEC) { + dev_err(&(pdev->dev), + "%s:Enable MSI error\n", TC956X_RESOURCE_NAME); + DBGPR_FUNC(&(pdev->dev), "<--%s : ret: %d\n", __func__, ret); + goto err_out_msi_failed; + } + + DBGPR_FUNC(&(pdev->dev), "<--%s : Allocated MSI Vectors : %d", __func__, ret); +#else /* Enable MSI Operation */ ret = pci_enable_msi(pdev); if (ret) { @@ -2571,9 +2961,10 @@ static int tc956xmac_pci_probe(struct pci_dev *pdev, goto err_out_msi_failed; } +#endif /*#ifdef TC956X_SRIOV_VF*/ pci_write_config_dword(pdev, pdev->msi_cap + PCI_MSI_MASK_64, 0); - +#ifndef TC956X_SRIOV_VF #ifdef EEPROM_MAC_ADDR #ifdef TC956X @@ -2581,7 +2972,6 @@ static int tc956xmac_pci_probe(struct pci_dev *pdev, TC956X_M3_SRAM_EEPROM_OFFSET_ADDR)); iowrite8(EEPROM_MAC_COUNT, (void __iomem *)(res.tc956x_SRAM_pci_base_addr + TC956X_M3_SRAM_EEPROM_MAC_COUNT)); - #endif #endif @@ -2689,13 +3079,19 @@ static int tc956xmac_pci_probe(struct pci_dev *pdev, } #endif +#endif /*#ifdef TC956X_SRIOV_VF*/ + res.wol_irq = pdev->irq; res.irq = pdev->irq; res.lpi_irq = pdev->irq; - plat->bus_id = res.port_num; + plat->bus_id = ((pdev->bus->number<<4) | res.port_num); +#ifdef TC956X_SRIOV_PF ret = tc956xmac_dvr_probe(&pdev->dev, plat, &res); +#elif defined TC956X_SRIOV_VF + ret = tc956xmac_vf_dvr_probe(&pdev->dev, plat, &res); +#endif if (ret) { if (ret == -ENODEV) { dev_info(&(pdev->dev), "Port%d will be registered as PCIe device only", res.port_num); @@ -2706,46 +3102,82 @@ static int tc956xmac_pci_probe(struct pci_dev *pdev, goto err_dvr_probe; } } + +#ifndef TC956X_SRIOV_VF #ifdef TC956X if ((res.port_num == RM_PF1_ID) && (res.port_interface == ENABLE_RGMII_INTERFACE)) { writel(0x00000000, res.addr + 0x1050); writel(0xF300F300, res.addr + 0x107C); } #endif +#endif /*#ifdef TC956X_SRIOV_VF*/ -#ifdef TC956X_PCIE_LOGSTAT - memset(<ssm_data, 0, sizeof(ltssm_data)); - ret = tc956x_logstat_GetLTSSMLogData((void __iomem *)res.addr, UPSTREAM_PORT, <ssm_data); - if (ret == 0) { - dev_dbg(&(pdev->dev), "%s : ltssm_data.eq_phase = %d\n", __func__, ltssm_data.eq_phase); - dev_dbg(&(pdev->dev), "%s : ltssm_data.rxL0s = %d\n", __func__, ltssm_data.rxL0s); - dev_dbg(&(pdev->dev), "%s : ltssm_data.txL0s = %d\n", __func__, ltssm_data.txL0s); - dev_dbg(&(pdev->dev), "%s : ltssm_data.substate_L1 = %d\n", __func__, ltssm_data.substate_L1); - dev_dbg(&(pdev->dev), "%s : ltssm_data.active_lane; = %d\n", __func__, ltssm_data.active_lane); - dev_dbg(&(pdev->dev), "%s : ltssm_data.link_speed = %d\n", __func__, ltssm_data.link_speed); - dev_dbg(&(pdev->dev), "%s : ltssm_data.dl_active = %d\n", __func__, ltssm_data.dl_active); - dev_dbg(&(pdev->dev), "%s : ltssm_data.ltssm_timeout = %d\n", __func__, ltssm_data.ltssm_timeout); - dev_dbg(&(pdev->dev), "%s : ltssm_data.ltssm_stop_status = %d\n", __func__, ltssm_data.ltssm_stop_status); +#ifdef TC956X_SRIOV_PF +#ifdef TC956X_PCIE_DSP_CUT_THROUGH + DBGPR_FUNC(&(pdev->dev), "<--%s : Adding DSP Cut Through Settings", __func__); + /* Read mode setting register + * Mode settings values 0:Setting A: x4x1x1, 1:Setting B: x2x2x1 + */ + val = readl(res.addr + NMODESTS_OFFSET); + pcie_mode = (val & NMODESTS_MODE2) >> NMODESTS_MODE2_SHIFT; + + switch (pcie_mode) { + case TC956X_PCIE_SETTING_A: /* 0:Setting A: x4x1x1 mode */ + DBGPR_FUNC(&(pdev->dev), "%s : Setting A : Adding DSP Cut Through Settings for DSP1 & DSP2", __func__); + /*DSP1 & DSP2 is selected*/ + val = readl(res.addr + TC956X_GLUE_SW_REG_ACCESS_CTRL); + val &= ~(SW_DSP1_ENABLE|SW_DSP2_ENABLE); + val |= (SW_DSP1_ENABLE|SW_DSP2_ENABLE); + writel(val, res.addr + TC956X_GLUE_SW_REG_ACCESS_CTRL); + /*Set 0x0 to Rx Bit enable_cut_through_on_receive_path*/ + val = readl(res.addr + TC956X_SSREG_K_PCICONF_021_021); + val &= ~(ENABLE_CUT_THROUGH_ON_RX_PATH_MASK); + writel(val, res.addr + TC956X_SSREG_K_PCICONF_021_021); + /*Set 0x00000000 to Tx Bit enable_cut_through_on_transmit_path*/ + val = readl(res.addr + TC956X_SSREG_K_PCICONF_022_022); + val &= ~(ENABLE_CUT_THROUGH_ON_TX_PATH_MASK); + writel(val, res.addr + TC956X_SSREG_K_PCICONF_022_022); + break; + case TC956X_PCIE_SETTING_B: /* 1:Setting B: x2x2x1 mode */ + DBGPR_FUNC(&(pdev->dev), "%s : Setting B : Adding DSP Cut Through Settings for DSP2", __func__); + /*DSP2 is selected*/ + val = readl(res.addr + TC956X_GLUE_SW_REG_ACCESS_CTRL); + val &= ~(SW_DSP2_ENABLE); + val |= (SW_DSP2_ENABLE); + writel(val, res.addr + TC956X_GLUE_SW_REG_ACCESS_CTRL); + /*Set 0x0 to Rx Bit enable_cut_through_on_receive_path*/ + val = readl(res.addr + TC956X_SSREG_K_PCICONF_021_021); + val &= ~(ENABLE_CUT_THROUGH_ON_RX_PATH_MASK); + writel(val, res.addr + TC956X_SSREG_K_PCICONF_021_021); + /*Set 0x0 to Tx Bit enable_cut_through_on_transmit_path*/ + val = readl(res.addr + TC956X_SSREG_K_PCICONF_022_022); + val &= ~(ENABLE_CUT_THROUGH_ON_TX_PATH_MASK); + writel(val, res.addr + TC956X_SSREG_K_PCICONF_022_022); + break; } -#endif /* TC956X_PCIE_LOGSTAT */ +#endif /* #ifdef TC956X_PCIE_DSP_CUT_THROUGH */ +#endif /* #ifdef TC956X_SRIOV_PF */ + /* Initialize only once */ if (tc956xmac_pm_usage_counter == TC956X_NO_MAC_DEVICE_IN_USE) mutex_init(&tc956x_pm_suspend_lock); -#ifdef DMA_OFFLOAD_ENABLE - if (res.port_num == RM_PF0_ID) - port0_pdev = pdev; -#endif mutex_lock(&tc956x_pm_suspend_lock); /* Increment device usage counter */ tc956xmac_pm_usage_counter++; - DBGPR_FUNC(&(pdev->dev), "%s : (Device Usage Count = [%d]) \n", __func__, tc956xmac_pm_usage_counter); + DBGPR_FUNC(&(pdev->dev), "%s : (Device Usage Count = [%d])\n", __func__, tc956xmac_pm_usage_counter); mutex_unlock(&tc956x_pm_suspend_lock); + return ret; -err_out_msi_failed: + err_dvr_probe: +err_out_msi_failed: +#if defined(TC956X_SRIOV_PF) | defined(TC956X_SRIOV_VF) + pci_free_irq_vectors(pdev); +#else pci_disable_msi(pdev); +#endif #ifdef DISABLE_EMAC_PORT1 disable_emac_port: #endif @@ -2757,7 +3189,30 @@ static int tc956xmac_pci_probe(struct pci_dev *pdev, if (((void __iomem *)res.tc956x_BRIDGE_CFG_pci_base_addr != NULL)) pci_iounmap(pdev, (void __iomem *)res.tc956x_BRIDGE_CFG_pci_base_addr); #endif +#ifndef TC956X_SRIOV_VF +#ifdef TC956X_PCIE_LOGSTAT +err_dvr_logstat: +#endif +#endif err_out_map_failed: +#ifdef TC956X_SRIOV_PF +#ifdef TC956X +#ifdef CONFIG_PCI_IOV + /* Disable SR-IOV */ + + if ((res.sriov_enabled != 0) && pdev->is_physfn) { + NMSGPR_INFO(&(pdev->dev), "Disabling sriov\n"); + res.sriov_enabled = 0; + pci_disable_sriov(pdev); + } +#endif +#endif +#ifdef TC956X +#ifdef CONFIG_PCI_IOV +err_sriov_vf_en_failed: +#endif +#endif +#endif pci_release_regions(pdev); err_out_req_reg_failed: pci_disable_device(pdev); @@ -2785,14 +3240,20 @@ static void tc956xmac_pci_remove(struct pci_dev *pdev) { struct net_device *ndev = dev_get_drvdata(&pdev->dev); struct tc956xmac_priv *priv = netdev_priv(ndev); +#ifdef TC956X_SRIOV_PF void *nrst_reg, *nclk_reg; u32 nrst_val, nclk_val; - +#endif DBGPR_FUNC(&(pdev->dev), "-->%s\n", __func__); -#ifdef DMA_OFFLOAD_ENABLE - if (priv->port_num == RM_PF0_ID) - port0_pdev = NULL; +#ifdef TC956X_SRIOV_PF +#ifdef CONFIG_PCI_IOV + /* Disable SR-IOV */ + if ((priv->sriov_enabled != 0) && pdev->is_physfn) { + NMSGPR_INFO(&(pdev->dev), "Disabling sriov\n"); + priv->sriov_enabled = 0; + pci_disable_sriov(pdev); + } #endif /* phy_addr == -1 indicates that PHY was not found and * device is registered as only PCIe device. So skip any @@ -2805,23 +3266,45 @@ static void tc956xmac_pci_remove(struct pci_dev *pdev) if (priv->port_num == 0) { nrst_reg = priv->tc956x_SFR_pci_base_addr + NRSTCTRL0_OFFSET; nclk_reg = priv->tc956x_SFR_pci_base_addr + NCLKCTRL0_OFFSET; - nrst_val = NRSTCTRL0_DEFAULT; - nclk_val = NCLKCTRL0_DEFAULT; + nrst_val = readl(nrst_reg); + nclk_val = readl(nclk_reg); + nrst_val |= NRSTCTRL0_DEFAULT; + nclk_val &= ~NCLKCTRL_PORT0_EMAC_MASK; } else { nrst_reg = priv->tc956x_SFR_pci_base_addr + NRSTCTRL1_OFFSET; nclk_reg = priv->tc956x_SFR_pci_base_addr + NCLKCTRL1_OFFSET; nrst_val = NRSTCTRL_EMAC_MASK; - nclk_val = 0; + nclk_val = 0; } writel(nrst_val, nrst_reg); writel(nclk_val, nclk_reg); + if (tc956xmac_pm_usage_counter == TC956X_SINGLE_MAC_DEVICE_IN_USE) { + /* Set reset value for Common CLK control and Common RESET Control registers */ + nrst_reg = priv->tc956x_SFR_pci_base_addr + NRSTCTRL0_OFFSET; + nclk_reg = priv->tc956x_SFR_pci_base_addr + NCLKCTRL0_OFFSET; + nrst_val = readl(nrst_reg); + nclk_val = readl(nclk_reg); + nrst_val |= NRSTCTRL_COMMON; + nclk_val |= NCLKCTRL_ENABLE_COMMON_EMAC_MASK; + nclk_val &= ~NCLKCTRL_DISABLE_COMMON_EMAC_MASK; + writel(nrst_val, nrst_reg); + writel(nclk_val, nclk_reg); + } KPRINT_INFO("%s : Port %d Wr RST Reg:%x, CLK Reg:%x", __func__, priv->port_num, readl(nrst_reg), readl(nclk_reg)); +#elif defined TC956X_SRIOV_VF + tc956xmac_vf_dvr_remove(&pdev->dev); +#endif pdev->irq = 0; - /* Enable MSI Operation */ +#if defined(TC956X_SRIOV_PF) | defined(TC956X_SRIOV_VF) + /* Free allocated interrupt vectors for device */ + pci_free_irq_vectors(pdev); +#else + /* Disable MSI Operation */ pci_disable_msi(pdev); +#endif if (priv->plat->tc956xmac_clk) clk_unregister_fixed_rate(priv->plat->tc956xmac_clk); @@ -2845,12 +3328,11 @@ static void tc956xmac_pci_remove(struct pci_dev *pdev) mutex_lock(&tc956x_pm_suspend_lock); /* Decrement device usage counter */ tc956xmac_pm_usage_counter--; - DBGPR_FUNC(&(pdev->dev), "%s : (Device Usage Count = [%d]) \n", __func__, tc956xmac_pm_usage_counter); + DBGPR_FUNC(&(pdev->dev), "%s : (Device Usage Count = [%d])\n", __func__, tc956xmac_pm_usage_counter); mutex_unlock(&tc956x_pm_suspend_lock); /* Destroy Mutex only once */ if (tc956xmac_pm_usage_counter == TC956X_NO_MAC_DEVICE_IN_USE) mutex_destroy(&tc956x_pm_suspend_lock); - DBGPR_FUNC(&(pdev->dev), "<--%s\n", __func__); } @@ -2922,9 +3404,10 @@ static int tc956x_pcie_pm_enable_pci(struct pci_dev *pdev) */ static int tc956x_pcie_pm_pci(struct pci_dev *pdev, enum TC956X_PORT_PM_STATE state) { - static struct pci_dev *tc956x_pd = NULL, *tc956x_dsp_ep = NULL, *tc956x_port_pdev[2] = {NULL}; + static struct pci_dev *tc956x_pd = NULL, *tc956x_dsp_ep = NULL, *tc956x_port_pdev[2] = {NULL}; struct pci_bus *bus = NULL; int ret = 0, i = 0, p = 0; + if (tc956xmac_pm_usage_counter == TC956X_ALL_MAC_PORT_SUSPENDED) { tc956x_dsp_ep = pci_upstream_bridge(pdev); bus = tc956x_dsp_ep->subordinate; @@ -2946,16 +3429,16 @@ static int tc956x_pcie_pm_pci(struct pci_dev *pdev, enum TC956X_PORT_PM_STATE st } } } -err : +err: return ret; } /*! * \brief Routine to put the device in suspend mode * - * \details This function is called whenever pm_generic_suspend() gets invoked. - * This function invokes tc956xmac_suspend() to process MAC related suspend - * operations during PORT_WIDE suspend. + * \details This function is called whenever pm_generic_suspend() gets invoked. + * This function invokes tc956xmac_suspend() to process MAC related suspend + * operations during PORT_WIDE suspend. * This function handles PCI state during SYSTEM_WIDE suspend. * * \param[in] dev \96 pointer to device structure. @@ -2970,14 +3453,14 @@ static int tc956x_pcie_suspend(struct device *dev) struct net_device *ndev = dev_get_drvdata(&pdev->dev); struct tc956xmac_priv *priv = netdev_priv(ndev); int ret = 0; -#ifdef DMA_OFFLOAD_ENABLE +#ifdef TC956X_DMA_OFFLOAD_ENABLE u8 i; u32 val; #endif DBGPR_FUNC(&(pdev->dev), "-->%s\n", __func__); if (priv->tc956x_port_pm_suspend == true) { - DBGPR_FUNC(&(pdev->dev), "<--%s : Port %d already Suspended \n", __func__, priv->port_num); + DBGPR_FUNC(&(pdev->dev), "<--%s : Port %d already Suspended\n", __func__, priv->port_num); return -1; } /* Set flag to avoid queuing any more work */ @@ -2987,12 +3470,12 @@ static int tc956x_pcie_suspend(struct device *dev) /* Decrement device usage counter */ tc956xmac_pm_usage_counter--; - DBGPR_FUNC(&(pdev->dev), "%s : (Number of Ports Left to Suspend = [%d]) \n", __func__, tc956xmac_pm_usage_counter); + DBGPR_FUNC(&(pdev->dev), "%s : (Number of Ports Left to Suspend = [%d])\n", __func__, tc956xmac_pm_usage_counter); /* Call tc956xmac_suspend() */ +#ifdef TC956X_SRIOV_PF tc956xmac_suspend(&pdev->dev); - -#ifdef DMA_OFFLOAD_ENABLE +#ifdef TC956X_DMA_OFFLOAD_ENABLE if (tc956xmac_pm_usage_counter == TC956X_ALL_MAC_PORT_SUSPENDED) { DBGPR_FUNC(&(pdev->dev), "%s : Port %d - Tamap Configuration", __func__, priv->port_num); /* Since TAMAP is common for Port0 and Port1, @@ -3016,27 +3499,47 @@ static int tc956x_pcie_suspend(struct device *dev) } } } +#endif +#elif defined TC956X_SRIOV_VF + tc956xmac_vf_suspend(&pdev->dev); #endif DBGPR_FUNC(&(pdev->dev), "%s : Port %d - Platform Suspend", __func__, priv->port_num); - +#ifdef TC956X_SRIOV_PF ret = tc956x_platform_suspend(priv); if (ret) { NMSGPR_ERR(&(pdev->dev), "%s: error in calling tc956x_platform_suspend", pci_name(pdev)); goto err; } +#endif tc956xmac_pm_set_power(priv, SUSPEND); - +#ifdef TC956X_SRIOV_PF +#ifdef TC956X_MAGIC_PACKET_WOL_GPIO + if (priv->port_num == RM_PF0_ID) { + KPRINT_INFO("%s: Port %d - Configuring GPIO for WOL", __func__, priv->port_num); + tc956x_wol_gpio_trigger(priv->ioaddr, true); /* Set to HIGH */ + } +#endif +#endif ret = tc956x_pcie_pm_pci(pdev, SUSPEND); if (ret < 0) goto err; - -err : +#ifdef TC956X_SRIOV_PF +#ifdef TC956X_MAGIC_PACKET_WOL_CONF + if (priv->wol_config_enabled == true) { + /* Set Flag to configure original interface and speed after resume. */ + priv->wol_config_enabled = false; /* Note: QC can place this either at end of suspend or beginning of resume */ + KPRINT_INFO("%s Port %d : Updated flag priv->wol_config_enabled to %d", __func__, priv->port_num, priv->wol_config_enabled); + } +#endif /* #ifdef TC956X_MAGIC_PACKET_WOL_CONF */ +#endif +err: mutex_unlock(&tc956x_pm_suspend_lock); DBGPR_FUNC(&(pdev->dev), "<--%s\n", __func__); return ret; } +#ifndef TC956X_SRIOV_VF /*! * \brief Routine to configure device during resume * @@ -3060,7 +3563,7 @@ static int tc956x_pcie_resume_config(struct pci_dev *pdev) uint8_t SgmSigPol = 0; int ret = 0; - DBGPR_FUNC(&(pdev->dev), "---> %s", __func__); + DBGPR_FUNC(&(pdev->dev), "---> %s", __func__); /* Skip Config when Port unavailable */ if ((priv->plat->phy_addr == -1) || (priv->mii == NULL)) { DBGPR_FUNC(&(pdev->dev), "%s : Invalid PHY Address (%d)\n", __func__, priv->plat->phy_addr); @@ -3209,7 +3712,9 @@ static int tc956x_pcie_resume_config(struct pci_dev *pdev) ret = readl(priv->ioaddr + NEMAC1CTL_OFFSET); } while ((NEMACCTL_INIT_DONE & ret) != NEMACCTL_INIT_DONE); } +#ifndef TC956X_SRIOV_VF ret = tc956x_xpcs_init(priv, priv->xpcsaddr); +#endif if (ret < 0) KPRINT_INFO("XPCS initialization error\n"); } @@ -3219,7 +3724,7 @@ static int tc956x_pcie_resume_config(struct pci_dev *pdev) return ret; } #endif - +#endif /*! * \brief Routine to resume device operation * @@ -3239,24 +3744,28 @@ static int tc956x_pcie_resume_config(struct pci_dev *pdev) static int tc956x_pcie_resume(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); +#ifndef TC956X_SRIOV_VF struct net_device *ndev = dev_get_drvdata(&pdev->dev); struct tc956xmac_priv *priv = netdev_priv(ndev); - int ret = 0; - -#ifdef DMA_OFFLOAD_ENABLE +#ifdef TC956X_DMA_OFFLOAD_ENABLE u8 i; #endif #ifdef TC956X_PCIE_GEN3_SETTING u32 val; #endif +#endif + int ret = 0; +#ifndef TC956X_SRIOV_VF DBGPR_FUNC(&(pdev->dev), "-->%s\n", __func__); if (priv->tc956x_port_pm_suspend == false) { - DBGPR_FUNC(&(pdev->dev), "%s : Port %d already Resumed \n", __func__, priv->port_num); + DBGPR_FUNC(&(pdev->dev), "%s : Port %d already Resumed\n", __func__, priv->port_num); return -1; } +#endif mutex_lock(&tc956x_pm_suspend_lock); +#ifndef TC956X_SRIOV_VF ret = tc956x_pcie_pm_enable_pci(pdev); if (ret < 0) goto err; @@ -3275,6 +3784,7 @@ static int tc956x_pcie_resume(struct device *dev) pci_disable_device(pdev); goto err; } + #ifdef TC956X_PCIE_GEN3_SETTING if (tc956xmac_pm_usage_counter == TC956X_ALL_MAC_PORT_SUSPENDED) { /* Reset Speed to Gen3 after resume */ @@ -3287,21 +3797,22 @@ static int tc956x_pcie_resume(struct device *dev) /* 0x4002C030 All PHY_COREs are selected */ writel(0x0f, priv->ioaddr + TC956X_GLUE_PHY_REG_ACCESS_CTRL); /* 0x40028000 All Lanes are selected */ - writel(0x0f , priv->ioaddr + TC956X_PHY_CORE0_GL_LANE_ACCESS); + writel(0x0f, priv->ioaddr + TC956X_PHY_CORE0_GL_LANE_ACCESS); /* 0x4002B268 PMA_LN_PCS2PMA_PHYMODE_R2.pcs2pma_phymode */ writel(0x02, priv->ioaddr + TC956X_PMA_LN_PCS2PMA_PHYMODE_R2); } - + if ((pcie_link_speed >= 1) && (pcie_link_speed <= 3)) tc956x_set_pci_speed(pdev, pcie_link_speed); } #endif - +#endif +#ifndef TC956X_SRIOV_VF /* Configure TA map registers */ if (tc956xmac_pm_usage_counter == TC956X_ALL_MAC_PORT_SUSPENDED) { - DBGPR_FUNC(&(pdev->dev),"%s : Tamap Re-configuration", __func__); + DBGPR_FUNC(&(pdev->dev), "%s : Tamap Re-configuration", __func__); tc956x_config_tamap(&pdev->dev, priv->tc956x_BRIDGE_CFG_pci_base_addr); -#ifdef DMA_OFFLOAD_ENABLE +#ifdef TC956X_DMA_OFFLOAD_ENABLE for (i = 1; i <= MAX_CM3_TAMAP_ENTRIES; i++) { if (priv->cm3_tamap[i-1].valid) tc956x_config_CM3_tamap(&pdev->dev, priv->tc956x_BRIDGE_CFG_pci_base_addr, @@ -3311,20 +3822,27 @@ static int tc956x_pcie_resume(struct device *dev) #endif } +#ifdef TC956X /* Configure EMAC Port */ tc956x_pcie_resume_config(pdev); +#endif +#endif /* Call tc956xmac_resume() */ +#ifdef TC956X_SRIOV_PF tc956xmac_resume(&pdev->dev); - if ((priv->port_num == RM_PF1_ID) && (priv->port_interface == ENABLE_RGMII_INTERFACE)) { writel(NEMACTXCDLY_DEFAULT, priv->ioaddr + TC9563_CFG_NEMACTXCDLY); writel(NEMACIOCTL_DEFAULT, priv->ioaddr + TC9563_CFG_NEMACIOCTL); } +#elif defined TC956X_SRIOV_VF + tc956xmac_vf_resume(&pdev->dev); +#endif +#ifndef TC956X_SRIOV_VF /* Increment device usage counter */ tc956xmac_pm_usage_counter++; - DBGPR_FUNC(&(pdev->dev), "%s : (Number of Ports Resumed = [%d]) \n", __func__, tc956xmac_pm_usage_counter); + DBGPR_FUNC(&(pdev->dev), "%s : (Number of Ports Resumed = [%d])\n", __func__, tc956xmac_pm_usage_counter); priv->tc956x_port_pm_suspend = false; @@ -3337,12 +3855,99 @@ static int tc956x_pcie_resume(struct device *dev) queue_work(system_wq, &priv->emac_phy_work); } +#ifdef TC956X_MAGIC_PACKET_WOL_GPIO + if (priv->port_num == RM_PF0_ID) { + KPRINT_INFO("%s: Port %d - Configuring GPIO for WOL", __func__, priv->port_num); + tc956x_wol_gpio_trigger(priv->ioaddr, false); /* Set to LOW */ + } +#endif +#ifdef TC956X_PCIE_LOGSTAT + if (priv->port_num == RM_PF0_ID) { +#ifdef TC956X_PCIE_LOGSTAT_SUMMARY_ENABLE + if ((tc956x_logstat_state_log_summary((void __iomem *)priv->ioaddr, UPSTREAM_PORT) < 0) + || (tc956x_logstat_state_log_summary((void __iomem *)priv->ioaddr, DOWNSTREAM_PORT1) < 0) + || (tc956x_logstat_state_log_summary((void __iomem *)priv->ioaddr, DOWNSTREAM_PORT2) < 0) + || (tc956x_logstat_state_log_summary((void __iomem *)priv->ioaddr, INTERNAL_ENDPOINT) < 0)) { + ret = -EFAULT; /* The returns returned by above function are -EFAULT only */ + NMSGPR_ERR(&(pdev->dev), + "%s: error in calling tc956x_logstat_state_log_summary", pci_name(pdev)); + DBGPR_FUNC(&(pdev->dev), "<--%s : Error ret: %d\n", __func__, ret); + goto err_resume_logstat; + } +#endif /* #ifdef TC956X_PCIE_LOGSTAT_SUMMARY_ENABLE */ + if ((tc956x_logstat_set_state_log_enable((void __iomem *)priv->ioaddr, UPSTREAM_PORT, STATE_LOG_ENABLE) < 0) + || (tc956x_logstat_set_state_log_enable((void __iomem *)priv->ioaddr, DOWNSTREAM_PORT1, STATE_LOG_ENABLE) < 0) + || (tc956x_logstat_set_state_log_enable((void __iomem *)priv->ioaddr, DOWNSTREAM_PORT2, STATE_LOG_ENABLE) < 0) + || (tc956x_logstat_set_state_log_enable((void __iomem *)priv->ioaddr, INTERNAL_ENDPOINT, STATE_LOG_ENABLE) < 0)) { + ret = -EFAULT; /* The returns returned by above function are -EFAULT only */ + NMSGPR_ERR(&(pdev->dev), + "%s: error in calling tc956x_logstat_set_state_log_enable", pci_name(pdev)); + DBGPR_FUNC(&(pdev->dev), "<--%s : Error ret: %d\n", __func__, ret); + goto err_resume_logstat; + } + } +#endif /* TC956X_PCIE_LOGSTAT */ +#endif + DBGPR_FUNC(&(pdev->dev), "<--%s\n", __func__); +#ifndef TC956X_SRIOV_VF +#ifdef TC956X_PCIE_LOGSTAT +err_resume_logstat: +#endif /* TC956X_PCIE_LOGSTAT */ +#endif /* TC956X_SRIOV_VF */ +#ifndef TC956X_SRIOV_VF err: +#endif mutex_unlock(&tc956x_pm_suspend_lock); DBGPR_FUNC(&(pdev->dev), "<--%s\n", __func__); + return ret; } +#ifdef TC956X_SRIOV_PF +#ifdef TC956X_MAGIC_PACKET_WOL_GPIO +/*! + * \brief API to signal SUSPEND/RESUME to external Host Triggering Device. + * + * \details This is a api to configure GPIO04 and set its output value + * based on mode to (HIGH/LOW) passed as argument. + * + * \param[in] reg_base_addr - pointer to BAR 4 base address. + * \param[in] mode - true or false + */ +static void tc956x_wol_gpio_trigger(void __iomem *reg_base_addr, bool mode) +{ + u32 reg; + + KPRINT_INFO("-->%s\n", __func__); + /* Set GPIO to Function.0*/ + reg = readl(reg_base_addr + NFUNCEN4_OFFSET); + reg &= (~(BIT(4))); + writel(reg, reg_base_addr + NFUNCEN4_OFFSET); + KPRINT_INFO("%s: Setting GPIO04 to Function 0 (%x:%x)\n", __func__, + NFUNCEN4_OFFSET, readl(reg_base_addr + NFUNCEN4_OFFSET)); + + /* GPIO04:OUT Enable*/ + reg = readl(reg_base_addr + GPIOE0_OFFSET); + reg = (reg & ~(BIT(4))); + writel(reg, reg_base_addr + GPIOE0_OFFSET); + KPRINT_INFO("%s: Setting GPIO04 Direction to Out Enable (%x:%x)\n", __func__, + GPIOE0_OFFSET, readl(reg_base_addr + GPIOE0_OFFSET)); + + reg = readl(reg_base_addr + GPIOO0_OFFSET); + if (!mode) { /* Set GPIO04 to LOW */ + KPRINT_INFO("%s: Setting GPIO04 to LOW\n", __func__); + reg &= (~(BIT(4))); + } else { /* Set GPIO04 to HIGH */ + KPRINT_INFO("%s: Setting GPIO04 to HIGH\n", __func__); + reg |= (BIT(4)); + } + writel(reg, reg_base_addr + GPIOO0_OFFSET); + KPRINT_INFO("%s: Setting GPIO04 Value (%x:%x)\n", __func__, + GPIOO0_OFFSET, readl(reg_base_addr + GPIOO0_OFFSET)); + KPRINT_INFO("<--%s\n", __func__); +} +#endif /* #ifdef TC956X_MAGIC_PACKET_WOL_GPIO */ +#endif /* TC956X_SRIOV_PF */ /*! * \brief API to shutdown the device. * @@ -3353,6 +3958,10 @@ static int tc956x_pcie_resume(struct device *dev) */ static void tc956x_pcie_shutdown(struct pci_dev *pdev) { +#ifdef TC956X_SRIOV_VF + tc956xmac_vf_dvr_remove(&pdev->dev); +#endif + DBGPR_FUNC(&(pdev->dev), "-->%s\n", __func__); NMSGPR_ALERT(&(pdev->dev), "Handle the shutdown\n"); DBGPR_FUNC(&(pdev->dev), "<--%s\n", __func__); @@ -3539,13 +4148,22 @@ module_init(tc956x_init_module); * that the entry function registered. */ module_exit(tc956x_exit_module); +#ifndef TC956X_SRIOV_VF +#ifdef CONFIG_PCI_IOV +/* Input parameter for No of virtural functions to Enable per VF. + * tc956x_no_of_vf - Valid vlaues are 0 to 3. + */ +module_param(tc956x_no_of_vf, int, MOD_PARAM_ACCESS); +#endif #ifdef TC956X_PCIE_GEN3_SETTING module_param(pcie_link_speed, uint, 0444); MODULE_PARM_DESC(pcie_link_speed, "PCIe speed Gen TC956X - default is 3, [1..3]"); #endif +#endif +#if defined(TC956X_SRIOV_PF) || defined(TC956X_AUTOMOTIVE_CONFIG) module_param(mac0_interface, uint, 0444); MODULE_PARM_DESC(mac0_interface, "PORT0 interface mode TC956X - default is 1,\ @@ -3554,7 +4172,7 @@ MODULE_PARM_DESC(mac0_interface, module_param(mac1_interface, uint, 0444); MODULE_PARM_DESC(mac1_interface, "PORT1 interface mode TC956X - default is 3,\ - [0: USXGMII(not supported), 1: XFI(not supported), 2: RGMII, 3: SGMII, 4: 2500Base-X]"); + [0: USXGMII, 1: XFI, 2: RGMII, 3: SGMII, 4: 2500Base-X]"); module_param(mac0_filter_phy_pause, uint, 0444); MODULE_PARM_DESC(mac0_filter_phy_pause, @@ -3593,7 +4211,7 @@ MODULE_PARM_DESC(mac0_rxq0_size, module_param(mac0_rxq1_size, uint, 0444); MODULE_PARM_DESC(mac0_rxq1_size, - "Rx Queue-1 size of Port 0 - default is 18432 (bytes),\ + "Rx Queue-1 size of Port 0 - default is 4096 (bytes),\ [Range Supported : 3072..44032 (bytes)]"); module_param(mac0_rxq0_rfd, uint, 0444); @@ -3623,7 +4241,7 @@ MODULE_PARM_DESC(mac0_txq0_size, module_param(mac0_txq1_size, uint, 0444); MODULE_PARM_DESC(mac0_txq1_size, - "Tx Queue-1 size of Port 0 - default is 18432 (bytes),\ + "Tx Queue-1 size of Port 0 - default is 14336 (bytes),\ [Range Supported : 3072..44032 (bytes)]"); module_param(mac1_rxq0_size, uint, 0444); @@ -3633,7 +4251,7 @@ MODULE_PARM_DESC(mac1_rxq0_size, module_param(mac1_rxq1_size, uint, 0444); MODULE_PARM_DESC(mac1_rxq1_size, - "Rx Queue-1 size of Port 1 - default is 18432 (bytes),\ + "Rx Queue-1 size of Port 1 - default is 4096 (bytes),\ [Range Supported : 3072..44032 (bytes)]"); module_param(mac1_rxq0_rfd, uint, 0444); @@ -3663,7 +4281,7 @@ MODULE_PARM_DESC(mac1_txq0_size, module_param(mac1_txq1_size, uint, 0444); MODULE_PARM_DESC(mac1_txq1_size, - "Tx Queue-1 size of Port 1 - default is 18432 (bytes),\ + "Tx Queue-1 size of Port 1 - default is 14336 (bytes),\ [Range Supported : 3072..44032 (bytes)]"); module_param(mac0_en_lp_pause_frame_cnt, uint, 0444); @@ -3701,6 +4319,64 @@ MODULE_PARM_DESC(mac_power_save_at_link_down, "Enable Power saving during Link down - default is 0,\ [0: DISABLE, 1: ENABLE]"); +module_param(port0_mdc, uint, 0444); +MODULE_PARM_DESC(port0_mdc, + "PORT0 MDC clock setting - default is 0x4,\ + select the value based on the following MDIO clock settings:\ + [0x0 - clk_csr_i/4,\ + 0x1 - clk_csr_i/6,\ + 0x2 - clk_csr_i/8,\ + 0x3 - clk_csr_i/10,\ + 0x4 - clk_csr_i/12,\ + 0x5 - clk_csr_i/14,\ + 0x6 - clk_csr_i/16,\ + 0x7 - clk_csr_i/18,\ + 0x8 - clk_csr_i/62,\ + 0x9 - clk_csr_i/102,\ + 0xA - clk_csr_i/122,\ + 0xB - clk_csr_i/142,\ + 0xC - clk_csr_i/162,\ + 0xD - clk_csr_i/202]"); + +module_param(port0_c45_state, int, 0444); +MODULE_PARM_DESC(port0_c45_state, + "PORT0 phy driver clause setting - default is 1 (true),\ + [1 - true, 0 - false]"); + +module_param(port1_mdc, uint, 0444); +MODULE_PARM_DESC(port1_mdc, + "PORT1 MDC clock setting - default is 0x8,\ + select the value based on the following MDIO clock settings:\ + [0x0 - clk_csr_i/4,\ + 0x1 - clk_csr_i/6,\ + 0x2 - clk_csr_i/8,\ + 0x3 - clk_csr_i/10,\ + 0x4 - clk_csr_i/12,\ + 0x5 - clk_csr_i/14,\ + 0x6 - clk_csr_i/16,\ + 0x7 - clk_csr_i/18,\ + 0x8 - clk_csr_i/62,\ + 0x9 - clk_csr_i/102,\ + 0xA - clk_csr_i/122,\ + 0xB - clk_csr_i/142,\ + 0xC - clk_csr_i/162,\ + 0xD - clk_csr_i/202]"); + +module_param(port1_c45_state, int, 0444); +MODULE_PARM_DESC(port1_c45_state, + "PORT1 phy driver clause setting - default is 0 (false),\ + [1 - true, 0 - false]"); + +module_param(port0_phyaddr, uint, 0444); +MODULE_PARM_DESC(port0_phyaddr, + "PORT0 Phy device addr for phy detection, default is 0,\ + [0 to 31]"); + +module_param(port1_phyaddr, uint, 0444); +MODULE_PARM_DESC(port1_phyaddr, + "PORT1 Phy device addr for phy detection, default is 0,\ + [0 to 31]"); + module_param(mac0_link_down_macrst, uint, 0444); MODULE_PARM_DESC(mac0_link_down_macrst, "MAC0 reset for PHY Clock loss during Link Down - default is 1,\ @@ -3711,6 +4387,7 @@ MODULE_PARM_DESC(mac1_link_down_macrst, "MAC1 reset for PHY Clock loss during Link Down - default is 0,\ [0: DISABLE, 1: ENABLE]"); +#endif MODULE_DESCRIPTION("TC956X PCI Express Ethernet Network Driver"); MODULE_AUTHOR("Toshiba Electronic Devices & Storage Corporation"); MODULE_LICENSE("GPL v2"); diff --git a/tc956x_pcie_logstat.c b/tc956x_pcie_logstat.c index eebf8b064f50..fff0a426befb 100644 --- a/tc956x_pcie_logstat.c +++ b/tc956x_pcie_logstat.c @@ -52,15 +52,6 @@ static uint8_t pcie_port[4][20] = { "Endpoint Port", }; -/* - * Array containing Enable and Disable Modes. - */ -static uint8_t pcie_conf_mode[2][10] = { - "Disable", - "Enable", -}; - - /* * Array containing different LTSSM states. */ @@ -94,17 +85,6 @@ static uint8_t ltssm_states[COUNT_LTSSM_REG_STATES][25] = { "Hot Reset", }; - -/* - * Array containing different Equalization Phases. - */ -static uint8_t eq_phase[4][8] = { - "Phase 0", - "Phase 1", - "Phase 2", - "Phase 3", -}; - /* * Array containing different Receive L0s sub-states. */ @@ -139,24 +119,6 @@ static uint8_t state_L1[8][20] = { "Exit", }; -/* - * Array containing Lane Status. - */ -static uint8_t active_lanes[2][20] = { - "Inactive Lane", - "Active Lane", -}; - -/* - * Array containing different Link Speed. - */ -static uint8_t link_speed[4][15] = { - "None", - "2.5 GT/s", - "5.0 GT/s", - "8.0 GT/s", -}; - /* * Array containing Data Layer Status. */ @@ -165,465 +127,632 @@ static uint8_t dl_state[2][20] = { "DL_Active", }; -/* - * Array containing LTSSM Timeout Status. - */ -static uint8_t ltssm_timeout_status[2][31] = { - "LTSSM Timeout is not occurred.", - "LTSSM Timeout is occurred.", -}; -/* - * Array containing LTSSM Logging Stop Status. - */ -static uint8_t ltssm_stop_status[2][25] = { - "State Logging NotStop", - "State Logging Stop", -}; +/* Static Variables for Analysis */ +static uint8_t DlActive_Pre = LOGSTAT_DUMMY_VALUE, LinkSpeed_Pre = LOGSTAT_DUMMY_VALUE; +static uint8_t LinkWidth_Pre = LOGSTAT_DUMMY_VALUE; +static uint8_t DlActive = LOGSTAT_DUMMY_VALUE, LinkSpeed = LOGSTAT_DUMMY_VALUE, LinkWidth = LOGSTAT_DUMMY_VALUE; /* =================================== * Function Definition * =================================== */ + /** - * tc956x_logstat_SetConf + * tc956x_pcie_ioctl_state_log_summary * - * \brief Function to set and print debug configuration register. + * \brief IOCTL Function to read and print State Log summary. * - * \details This is an internal function called by tc956x_pcie_ioctl_SetConf - * whenever IOCTL TC956X_PCIE_SET_LOGSTAT_CONF is invoked by user. - * This function - * configures LTSSM State Logging Configuration, Control, Fifo Read pointer - * Control register. In addition it also configures LTSSM enable - * registers. + * \details This function is called whenever IOCTL TC956X_PCIE_STATE_LOG_SUMMARY + * is invoked by user. This function prints a summary of State Log for particular + * port after PCIE State Transition, example PCIe Lane change, speed change, etc. + * State Log will contain following: + * 1. LTSSM Timeout Occured(or not). + * 2. DLL Active(or not). + * 3. Link Speed Transition. + * 4. Link Width Transition. + * 4. L1 PM Substate Transition. + * 5. TxL0s State Transition. + * 6. RxL0s State Transition. + * 7. Equalization Phase. + * 8. LTSSM State Transition. * - * \param[in] pconf_base_addr - pointer to TC956X Configuration base address. - * \param[in] ppcie_base_addr - pointer to TC956X PCIE SFR base address. - * \param[in] nport - port such Upstream, Downstream 1, Downstream 2 and - * Endpoint Ports. - * \param[in] plogstat_conf - pointer to tc956x_ltssm_conf structure - * containing user configuration. + * \param[in] priv - pointer to pcie private data. + * \param[in] data - data passed from user space. * - * \return 0 if OK, otherwise -1 + * \return -EFAULT in case of copy failure, otherwise 0 */ -int tc956x_logstat_SetConf(void __iomem *pconf_base_addr, - enum ports nport, - struct tc956x_ltssm_conf *plogstat_conf) +int tc956x_pcie_ioctl_state_log_summary(const struct tc956xmac_priv *priv, void __user *data) { int ret = 0; - uint32_t regval; + struct tc956x_ioctl_state_log_summary ioctl_data; + + DBGPR_FUNC(priv->device, "--> %s\n", __func__); + + if ((priv == NULL) || (data == NULL)) + return -EFAULT; + + if (copy_from_user(&ioctl_data, data, sizeof(ioctl_data))) + ret = -EFAULT; + + if (ret == 0) + ret = tc956x_logstat_state_log_summary(priv->ioaddr, ioctl_data.port); + + return ret; +} + +/** + * tc956x_pcie_ioctl_state_log_summary + * + * \brief IOCTL Function to read and print State Log summary. + * + * \details This function performs following : + * 1. Reads current PCIe Link Parameters + * 2. Stop State Logging. + * 3. Get current State Log Status. + * 4. Set FIFO Pointer from 0 to 31 and Get Sate Log Data for each FIFO pointer. + * 5. Analyze all 32 State Log Data. + * 6. Print LTSSM state transition, if valid values are observed. + * + * NOTE: The function doesn't enable back the State Logging after Stop. + * + * \param[in] priv - pointer to pcie private data. + * \param[in] data - data passed from user space. + * + * \return -EFAULT in case of copy failure, otherwise 0 + */ +int tc956x_logstat_state_log_summary(void __iomem *pbase_addr, enum ports nport) +{ + int ret = 0; + uint8_t state = 0, dll = 0, speed = 0, width = 0, status = 0; + uint8_t count = 0; /* count for invalid State Log Data */ + int8_t fptr = 0; /* signed state log fifo pointer. can become negative. */ + char cur_ltssm[25]; + uint32_t val = 0, cur_state = 0; + uint32_t fifo_array[MAX_FIFO_READ_POINTER + 1]; /* Array of State Log Read Value for each FIFO Read Ptr */ + + if (pbase_addr == NULL) { + ret = -EFAULT; + KPRINT_INFO("%s : NULL Pointer Arguments\n", __func__); + } + + if (ret == 0) { + KPRINT_INFO("State Transition Log Summary : %s\n", pcie_port[nport]); + /* Get PCIe LTSSM, DLL, Speed, Width, State Log Status & Disable Stop State Logging */ + if ((tc956x_logstat_get_pcie_cur_ltssm(pbase_addr, nport, &state) < 0) + || (tc956x_logstat_get_pcie_cur_dll(pbase_addr, nport, &dll) < 0) + || (tc956x_logstat_get_pcie_cur_speed(pbase_addr, nport, &speed) < 0) + || (tc956x_logstat_get_pcie_cur_width(pbase_addr, nport, &width) < 0) + || (tc956x_logstat_set_state_log_enable(pbase_addr, nport, STATE_LOG_DISABLE) < 0) + || (tc956x_logstat_get_state_log_stop_status(pbase_addr, nport, &status) < 0)) { + ret = -1; + goto end; + } + + strcpy(cur_ltssm, ltssm_states[state]); + /* State Logging Should Stop after Disabling State Log */ + /* Read State Log Data for each fifo pointer */ + for (fptr = 0; fptr <= MAX_FIFO_READ_POINTER; fptr++) { + if ((tc956x_logstat_set_state_log_fifo_ptr(pbase_addr, nport, fptr) < 0) + || (tc956x_logstat_get_state_log_data(pbase_addr, nport, &val) < 0)) { + ret = -1; + goto end; + } + fifo_array[fptr] = val; + } + /* Reset all values */ + DlActive_Pre = LOGSTAT_DUMMY_VALUE; + LinkSpeed_Pre = LOGSTAT_DUMMY_VALUE; + LinkWidth_Pre = LOGSTAT_DUMMY_VALUE; + DlActive = LOGSTAT_DUMMY_VALUE; + LinkSpeed = LOGSTAT_DUMMY_VALUE; + LinkWidth = LOGSTAT_DUMMY_VALUE; + + /* Analyze State Log Data using state log of each fifo pointer */ + for (fptr = MAX_FIFO_READ_POINTER; fptr >= 0; fptr--) { + if (fifo_array[fptr] != INVALID_STATE_LOG) { + cur_state = fifo_array[fptr]; + /* Start analyzing only after prev_state is set */ + ret = tc956x_logstat_state_log_analyze(cur_state); + if (ret < 0) + goto end; + + count++; + } else { + continue; + } + } + + if (count == 0) { + KPRINT_INFO("==> LTSSM is not changed\n"); + KPRINT_INFO("Speed:Gen%d, Width:x%d, LTSSM:%s, DLL:%d\n", speed, width, cur_ltssm, dll); + ret = 0; + } + + if (status == STATE_LOG_STOP) + KPRINT_INFO("STATE LOGGING is stopped\n"); + } +end: + return ret; +} + +/** + * tc956x_logstat_get_state_log_stop_status + * + * \brief Function to get State Log Stop Status. + * + * \details This function reads the State Logging Status from register. + * PCIe State Loggging is running if value returned by function is set, + * otherwise stopped. + * + * \param[in] pbase_addr - pointer to Bar4 base address. + * \param[in] nport - log start/stop for port passed. + * \param[out] pstop_status - state logging status (1 : stopped, 0 : still running). + * + * \return -EFAULT in case of copy failure, otherwise 0 + */ +int tc956x_logstat_get_state_log_stop_status(void __iomem *pbase_addr, enum ports nport, uint8_t *pstop_status) +{ + int ret = 0; + uint32_t regval = 0; uint32_t port_offset; /* Port Address Register Offset */ - if ((pconf_base_addr == NULL) - || (plogstat_conf == NULL)) { - ret = -1; + if ((pbase_addr == NULL) || (pstop_status == NULL)) { + ret = -EFAULT; + KPRINT_INFO("%s : Invalid Arguments\n", __func__); + } + + if (ret == 0) { + port_offset = nport * STATE_LOG_REG_OFFSET; + /* Get State Logging Stop Status */ + regval = readl(pbase_addr + TC956X_CONF_REG_NPCIEUSPLOGST + port_offset); + *pstop_status = (regval & STOP_STATUS_MASK) >> STOP_STATUS_SHIFT; + /* KPRINT_INFO("RD: Addr= 0x%08X, Val= 0x%08X\n", TC956X_CONF_REG_NPCIEUSPLOGST + port_offset, regval); */ + } + return ret; +} + + +/** + * tc956x_logstat_set_state_log_fifo_ptr + * + * \brief Function to set State Log FIFO Read Pointer. + * + * \details This function write the FIFO Pointer. State Logging Data will be read as per + * FIFO Pointer set in register. + * + * \param[in] pbase_addr - pointer to Bar4 base address. + * \param[in] nport - log start/stop for port passed. + * \param[in] fifo_pointer - fifo pointer (0 to 31) for which state log to be read. + * + * \return -EFAULT in case of copy failure, otherwise 0 + */ +int tc956x_logstat_set_state_log_fifo_ptr(void __iomem *pbase_addr, enum ports nport, uint8_t fifo_pointer) +{ + int ret = 0; + uint32_t regval = 0; + uint32_t port_offset; /* Port Address Register Offset */ + + if ((pbase_addr == NULL) || (fifo_pointer > MAX_FIFO_READ_POINTER)) { + ret = -EFAULT; + KPRINT_INFO("%s : Invalid Arguments\n", __func__); + } + + if (ret == 0) { + port_offset = nport * STATE_LOG_REG_OFFSET; + /* Set FIFO Read Pointer Register */ + regval = (((uint32_t)(fifo_pointer) & FIFO_READ_POINTER_MASK) >> FIFO_READ_POINTER_SHIFT); + writel(regval, pbase_addr + TC956X_CONF_REG_NPCIEUSPLOGRDCTRL + port_offset); + /* KPRINT_INFO("WR: Addr= 0x%08X, Val= 0x%08X\n", TC956X_CONF_REG_NPCIEUSPLOGRDCTRL + port_offset, regval); */ + } + return ret; +} + +/** + * tc956x_logstat_get_state_log_data + * + * \brief Function to read State Log Data. + * + * \details This function reads the State Logging Data from register. + * + * \param[in] pbase_addr - pointer to Bar4 base address. + * \param[in] nport - log start/stop for port passed. + * \param[out] pstate_log_data - pointer to state log data read. + * + * \return -EFAULT in case of copy failure, otherwise 0 + */ +int tc956x_logstat_get_state_log_data(void __iomem *pbase_addr, enum ports nport, uint32_t *pstate_log_data) +{ + int ret = 0; + uint32_t port_offset; /* Port Address Register Offset */ + + if ((pbase_addr == NULL) || (pstate_log_data == NULL)) { + ret = -EFAULT; KPRINT_INFO("%s : NULL Pointer Arguments\n", __func__); - } else { - if ((plogstat_conf->logging_stop_cnt_val > MAX_STOP_CNT) - || (plogstat_conf->logging_stop_linkwdth_en > ENABLE) - || (plogstat_conf->logging_stop_linkspeed_en > ENABLE) - || (plogstat_conf->logging_stop_timeout_en > ENABLE) - || (plogstat_conf->logging_accept_txrxL0s_en > ENABLE) - || (plogstat_conf->logging_post_stop_enable > ENABLE) - || (plogstat_conf->ltssm_fifo_pointer > MAX_FIFO_POINTER)) { - ret = -1; - KPRINT_INFO("%s : Invalid Arguments\n", __func__); + } + + if (ret == 0) { + port_offset = nport * STATE_LOG_REG_OFFSET; + /* Read LTSSM Log Data Register */ + *pstate_log_data = readl(pbase_addr + TC956X_CONF_REG_NPCIEUSPLOGD + port_offset); + /* KPRINT_INFO("RD: Addr= 0x%08X, Val= 0x%08X\n", TC956X_CONF_REG_NPCIEUSPLOGD + port_offset, *pstate_log_data); */ + } + return ret; +} + +/** + * tc956x_logstat_state_log_analyze + * + * \brief Function to analyze State Log Data. + * + * \details This function analyze the State Logging Data as per current value passed. + * + * \param[in] cur_state - FIFO register data containing current state of pcie. + * + * \return always 0. + */ +int tc956x_logstat_state_log_analyze(uint32_t cur_state) +{ + union tc956x_logstat_State_Log_Data curr_state_log_data; + uint8_t timeout = 0, activelane = 0, l1_substate = 0, tx_l0s = 0, rx_l0s = 0, eqphase = 0, ltssm = 0; + uint8_t l1ss[20], txl0s_dec[20], rxl0s_dec[20], ltssm_dec[30]; + uint8_t append_str[150]; + + /* Assign Previous and Current State Log Data */ + curr_state_log_data.reg_val = cur_state; + + /* Decoding State Log */ + /* LTSSM Timeout Decoding */ + if (curr_state_log_data.bitfield.fifo_read_value8 == LTSSM_TIMEOUT_OCCURRED) + timeout = LTSSM_TIMEOUT_OCCURRED; + else + timeout = LTSSM_TIMEOUT_NOT_OCCURRED; + + /* DL_Active Decoding */ + DlActive_Pre = DlActive; + + if (curr_state_log_data.bitfield.fifo_read_value7 == DL_ACTIVE) + DlActive = DL_ACTIVE; + else + DlActive = DL_NOT_ACTIVE; + + /* Link Speed Decoding */ + LinkSpeed_Pre = LinkSpeed; + LinkSpeed = curr_state_log_data.bitfield.fifo_read_value6; + + /* Link Width Decoding */ + LinkWidth_Pre = LinkWidth; + activelane = curr_state_log_data.bitfield.fifo_read_value5; + LinkWidth = 0; + while (activelane) { + LinkWidth += activelane & ACTIVE_SINGLE_LANE_MASK; + activelane = (activelane >> ACTIVE_SINGLE_LANE_SHIFT) & ACTIVE_ALL_LANE_MASK; + } + + /* L1 PM Substate Decoding */ + l1_substate = curr_state_log_data.bitfield.fifo_read_value4; + strcpy(l1ss, state_L1[l1_substate]); + + /* TxL0s Decoding */ + tx_l0s = curr_state_log_data.bitfield.fifo_read_value3; + strcpy(txl0s_dec, tx_L0s_state[tx_l0s]); + + /* RxL0s Decoding */ + rx_l0s = curr_state_log_data.bitfield.fifo_read_value2; + strcpy(rxl0s_dec, rx_L0s_state[rx_l0s]); + + /* EQ Phase Decoding */ + eqphase = curr_state_log_data.bitfield.fifo_read_value1; + + /* LTSSM Decoding */ + ltssm = curr_state_log_data.bitfield.fifo_read_value0; + if (ltssm <= LTSSM_MAX_VALUE) + strcpy(ltssm_dec, ltssm_states[ltssm]); + + /* Print State Log Summary */ + if (timeout == LTSSM_TIMEOUT_OCCURRED) + KPRINT_INFO("==> LTSSM Timeout occurred!\n"); + else { + if ((DlActive_Pre == DL_NOT_ACTIVE) && (DlActive == DL_ACTIVE)) + KPRINT_INFO("==> Linkup!\n"); + else if ((DlActive_Pre == DL_ACTIVE) && (DlActive == DL_NOT_ACTIVE)) + KPRINT_INFO("==> Link is down!\n"); + + if (LinkSpeed_Pre != LOGSTAT_DUMMY_VALUE) { + if (LinkSpeed < LinkSpeed_Pre) + KPRINT_INFO("==> Speed down occurred! (Gen%d --> Gen%d)\n", LinkSpeed_Pre, LinkSpeed); + else if (LinkSpeed > LinkSpeed_Pre) + KPRINT_INFO("==> Speed up occurred! (Gen%d --> Gen%d)\n", LinkSpeed_Pre, LinkSpeed); + } + + if ((LinkWidth_Pre != LOGSTAT_DUMMY_VALUE) && (LinkWidth_Pre != ALL_LANES_INACTIVE)) { + if (LinkWidth < LinkWidth_Pre) { + if (strcmp(ltssm_dec, "Detect.Active") == 0) { + if (LinkWidth > 1) + KPRINT_INFO("==> Receiver Detection is occurred! (Only %d Lanes is detected)\n", LinkWidth); + else + KPRINT_INFO("==> Receiver Detection is occurred! (Only 1 Lane is detected)\n"); + } else + KPRINT_INFO("==> Link Width down configure occurred! (x%d --> x%d)\n", LinkWidth_Pre, LinkWidth); + } else if (LinkWidth > LinkWidth_Pre) + KPRINT_INFO("==> Link Width upconfigure occurred! (x%d --> x%d)\n", LinkWidth_Pre, LinkWidth); + } + + sprintf(append_str, "--> DL_Active:%d, Speed:Gen%d, Width:x%d, LTSSM:%s", DlActive, LinkSpeed, LinkWidth, ltssm_dec); + + if ((tx_l0s != INACTIVE_L0s) && (rx_l0s != INACTIVE_L0s)) + KPRINT_INFO("%s (%d:%s, %d:%s)\n", append_str, tx_l0s, txl0s_dec, rx_l0s, rxl0s_dec); + else if ((tx_l0s != INACTIVE_L0s) && (rx_l0s == INACTIVE_L0s)) + KPRINT_INFO("%s (%s)\n", append_str, txl0s_dec); + else if ((tx_l0s == INACTIVE_L0s) && (rx_l0s != INACTIVE_L0s)) + KPRINT_INFO("%s (%s)\n", append_str, rxl0s_dec); + else if (strcmp(ltssm_dec, "Recovery.Equalization")) + KPRINT_INFO("%s (Phase %d)\n", append_str, eqphase); + else if (l1_substate != INACTIVE_L1) + KPRINT_INFO("%s (%s)\n", append_str, l1ss); + } + return 0; +} + +/** + * tc956x_pcie_ioctl_get_pcie_link_params + * + * \brief IOCTL Function to read PCIe Link LTSSM, DL State, Speed and Width. + * + * \details This function is called whenever IOCTL TC956X_PCIE_GET_PCIE_LINK_PARAMS + * is invoked by user. This function reads and print Current LTSSM State, DL Link State, + * Link Speed and Link Width. + * + * \param[in] priv - pointer to pcie private data. + * \param[in] data - data passed from user space. + * + * \return -EFAULT in case of copy failure, otherwise 0 + */ +int tc956x_pcie_ioctl_get_pcie_link_params(const struct tc956xmac_priv *priv, void __user *data) +{ + int ret = 0; + struct tc956x_ioctl_pcie_link_params ioctl_data; + struct tc956x_pcie_link_params link_param; + + DBGPR_FUNC(priv->device, "--> %s\n", __func__); + + if ((priv == NULL) || (data == NULL)) + return -EFAULT; + + memset(&link_param, 0, sizeof(link_param)); + + if (copy_from_user(&ioctl_data, data, sizeof(ioctl_data))) + ret = -EFAULT; + + if (ret == 0) { + if ((tc956x_logstat_get_pcie_cur_ltssm(priv->ioaddr, ioctl_data.port, &(link_param.ltssm)) < 0) + || (tc956x_logstat_get_pcie_cur_dll(priv->ioaddr, ioctl_data.port, &(link_param.dll)) < 0) + || (tc956x_logstat_get_pcie_cur_speed(priv->ioaddr, ioctl_data.port, &(link_param.speed)) < 0) + || (tc956x_logstat_get_pcie_cur_width(priv->ioaddr, ioctl_data.port, &(link_param.width)) < 0)) { + ret = -EFAULT; } } if (ret == 0) { - /* LTSSM Register Offsets */ - port_offset = (LTSSM_CONF_REG_OFFSET * nport); - - KPRINT_INFO("%s : %s State Logging Configuration\n", __func__, pcie_port[nport]); - regval = 0; /* Always overwritten */ - /* Set LTSSM State Logging Configuration Register */ - regval |= (((uint32_t)(plogstat_conf->logging_stop_cnt_val) - << STOP_COUNT_VALUE_SHIFT) - & STOP_COUNT_VALUE_MASK); - KPRINT_INFO("%s : Set Stop Count Value %d\n", - __func__, plogstat_conf->logging_stop_cnt_val); - regval |= (((uint32_t)(plogstat_conf->logging_stop_linkwdth_en) - << LINKWIDTH_DOWN_ST_SHIFT) & LINKWIDTH_DOWN_ST_MASK); - KPRINT_INFO("%s : Set Small Link Width Stop : %d %s\n", __func__, - plogstat_conf->logging_stop_linkwdth_en, - pcie_conf_mode[plogstat_conf->logging_stop_linkwdth_en]); - regval |= (((uint32_t)(plogstat_conf->logging_stop_linkspeed_en) - << LINKSPEED_DOWN_ST_SHIFT) & LINKSPEED_DOWN_ST_MASK); - KPRINT_INFO("%s : Set Late Link Speed Stop : %d %s\n", - __func__, plogstat_conf->logging_stop_linkspeed_en, - pcie_conf_mode[plogstat_conf->logging_stop_linkspeed_en]); - regval |= (((uint32_t)(plogstat_conf->logging_stop_timeout_en) - << TIMEOUT_STOP_SHIFT) & TIMEOUT_STOP_MASK); - KPRINT_INFO("%s : Set LTSSM Timeout Stop : %d %s\n", __func__, - plogstat_conf->logging_stop_timeout_en, - pcie_conf_mode[plogstat_conf->logging_stop_timeout_en]); - regval |= (((uint32_t)(plogstat_conf->logging_accept_txrxL0s_en) - << L0S_MASK_SHIFT) & L0S_MASK_MASK); - KPRINT_INFO("%s : Set Accept TxL0s/RxL0s : %d %s\n", __func__, - plogstat_conf->logging_accept_txrxL0s_en, - pcie_conf_mode[plogstat_conf->logging_accept_txrxL0s_en]); - writel(regval, (pconf_base_addr + TC956X_CONF_REG_NPCIEUSPLOGCFG + port_offset)); - - /* Set LTSSM State Logging Control Register */ - regval = 0; - regval |= (((uint32_t)(plogstat_conf->logging_post_stop_enable) - << STATE_LOGGING_ENABLE_SHIFT) & STATE_LOGGING_ENABLE_MASK); - KPRINT_INFO("%s : Precedent Condition Logging Stop : %d %s\n", __func__, - plogstat_conf->logging_post_stop_enable, - pcie_conf_mode[plogstat_conf->logging_post_stop_enable]); - writel(regval, pconf_base_addr + TC956X_CONF_REG_NPCIEUSPLOGCTRL + port_offset); - - /* Read LTSSM State Logging Read Control Register */ - regval = 0; /* Always overwritten */ - regval |= (((uint32_t)(plogstat_conf->ltssm_fifo_pointer) - << FIFO_READ_POINTER_SHIFT) & (FIFO_READ_POINTER_MASK)); - KPRINT_INFO("%s : Set FIFO Read Pointer : %d\n", __func__, - plogstat_conf->ltssm_fifo_pointer); - writel(regval, pconf_base_addr + TC956X_CONF_REG_NPCIEUSPLOGRDCTRL + port_offset); + if (copy_to_user((void __user *)ioctl_data.link_param, &link_param, sizeof(link_param))) + ret = -EFAULT; } + + DBGPR_FUNC(priv->device, "<-- %s\n", __func__); return ret; } /** - * tc956x_logstat_GetConf + * tc956x_logstat_get_pcie_cur_ltssm * - * \brief Function to read and print debug configuration register. + * \brief Function to read current PCIe Link LTSSM State. * - * \details This is an internal function called by tc956x_pcie_ioctl_GetConf - * whenever IOCTL TC956X_PCIE_GET_LOGSTAT_CONF is invoked by user. - * This function - * reads LTSSM State Logging Configuration, Control, Fifo Read pointer - * Control register. In addition it also reads LTSSM enable - * registers. + * \details This function reads current Link Training and Status State Machine + * State from register. * - * \param[in] pconf_base_addr - pointer to TC956X Configuration base address. - * \param[in] ppcie_base_addr - pointer to TC956X PCIE SFR base address. - * \param[in] nport - port such Upstream, Downstream 1, Downstream 2 and - * Endpoint Ports. - * \param[in] plogstat_conf - pointer to empty tc956x_ltssm_conf structure. - * Function will fill register configuration - * information into the structure. + * \param[in] pbase_addr - pointer to BAR4 base address. + * \param[in] nport - port for which to get current ltssm value. + * \param[out] pltssm - pointer to ltssm value from register. * - * \return 0 if OK, otherwise -1 + * \return -EFAULT in case of bad address, otherwise 0 */ -int tc956x_logstat_GetConf(void __iomem *pconf_base_addr, - enum ports nport, - struct tc956x_ltssm_conf *plogstat_conf) +int tc956x_logstat_get_pcie_cur_ltssm(void __iomem *pbase_addr, enum ports nport, uint8_t *pltssm) { int ret = 0; uint32_t regval; - uint32_t port_offset; /* Port Address Register Offset */ + uint32_t reg_offset; /* Port Address Register Offset */ - if ((pconf_base_addr == NULL) - || (plogstat_conf == NULL)) { - ret = -1; + if ((pbase_addr == NULL) || (pltssm == NULL)) { + ret = -EFAULT; KPRINT_INFO("%s : NULL Pointer Arguments\n", __func__); } if (ret == 0) { - /* LTSSM Register Offsets */ - port_offset = (LTSSM_CONF_REG_OFFSET * nport); - - KPRINT_INFO("%s : %s State Logging Configuration\n", __func__, pcie_port[nport]); - - /* Read LTSSM State Logging Configuration Register */ - regval = readl(pconf_base_addr + TC956X_CONF_REG_NPCIEUSPLOGCFG + port_offset); - - plogstat_conf->logging_stop_cnt_val = ((regval & STOP_COUNT_VALUE_MASK) - >> STOP_COUNT_VALUE_SHIFT); - KPRINT_INFO("%s : Get Stop Count Value %d\n", - __func__, plogstat_conf->logging_stop_cnt_val); - plogstat_conf->logging_stop_linkwdth_en = ((regval & LINKWIDTH_DOWN_ST_MASK) - >> LINKWIDTH_DOWN_ST_SHIFT); - KPRINT_INFO("%s : Get Small Link Width Stop : %d %s\n", __func__, - plogstat_conf->logging_stop_linkwdth_en, - pcie_conf_mode[plogstat_conf->logging_stop_linkwdth_en]); - plogstat_conf->logging_stop_linkspeed_en = ((regval & LINKSPEED_DOWN_ST_MASK) - >> LINKSPEED_DOWN_ST_SHIFT); - KPRINT_INFO("%s : Get Late Link Speed Stop : %d %s\n", __func__, - plogstat_conf->logging_stop_linkspeed_en, - pcie_conf_mode[plogstat_conf->logging_stop_linkspeed_en]); - plogstat_conf->logging_stop_timeout_en = ((regval - & TIMEOUT_STOP_MASK) >> TIMEOUT_STOP_SHIFT); - KPRINT_INFO("%s : Get LTSSM Timeout Stop : %d %s\n", __func__, - plogstat_conf->logging_stop_timeout_en, - pcie_conf_mode[plogstat_conf->logging_stop_timeout_en]); - plogstat_conf->logging_accept_txrxL0s_en = ((regval & L0S_MASK_MASK) - >> L0S_MASK_SHIFT); - KPRINT_INFO("%s : Get Accept TxL0s/RxL0s : %d %s\n", __func__, - plogstat_conf->logging_accept_txrxL0s_en, - pcie_conf_mode[plogstat_conf->logging_accept_txrxL0s_en]); - - /* Read LTSSM State Logging Control Register */ - regval = readl(pconf_base_addr + TC956X_CONF_REG_NPCIEUSPLOGCTRL + port_offset); - - plogstat_conf->logging_post_stop_enable = ((regval & STATE_LOGGING_ENABLE_MASK) - >> STATE_LOGGING_ENABLE_SHIFT); - KPRINT_INFO("%s : Get Precedent Condition Logging Stop : %d %s\n", __func__, - plogstat_conf->logging_post_stop_enable, - pcie_conf_mode[plogstat_conf->logging_post_stop_enable]); - - /* Read LTSSM State Logging Read Control Register */ - regval = readl(pconf_base_addr + TC956X_CONF_REG_NPCIEUSPLOGRDCTRL + port_offset); - - plogstat_conf->ltssm_fifo_pointer = ((regval & FIFO_READ_POINTER_MASK) - >> FIFO_READ_POINTER_SHIFT); - KPRINT_INFO("%s : Get FIFO Read Pointer : %d\n", __func__, - plogstat_conf->ltssm_fifo_pointer); + reg_offset = nport * GLUE_REG_LTSSM_OFFSET; + /* Read Current LTSSM State */ + regval = readl(pbase_addr + TC956X_GLUE_SW_USP_TEST_OUT_127_096 + reg_offset); + *pltssm = (regval & TC956X_GLUE_LTSSM_STATE_MASK) >> TC956X_GLUE_LTSSM_STATE_SHIFT; + KPRINT_INFO("%s : LTSSM State %s for port %s\n", __func__, ltssm_states[(*pltssm)], pcie_port[nport]); + if ((*pltssm) > LTSSM_MAX_VALUE) + ret = -1; } return ret; } /** - * tc956x_logstat_GetLTSSMLogData + * tc956x_logstat_get_pcie_cur_dll * - * \brief Function to read and print LTSSM Logging Data register. + * \brief Function to read current PCIe Link DLL Active State. * - * \details This is an internal function called by - * tc956x_pcie_ioctl_GetLTSSMLogData - * whenever IOCTL TC956X_PCIE_GET_LTSSM_LOG is invoked by user. - * This function - * read and print LTSSM Logging Data, State Logging Status Register - * Information. + * \details This function reads current Data Link Layer Active State from register. * - * \param[in] pbase_addr - pointer to base address. - * \param[in] nport - port such Upstream, Downstream 1, Downstream 2 and - * Endpoint Ports. - * \param[in] plogstat_conf - pointer to empty tc956x_ltssm_log structure. - * Function will fill register configuration - * information into the structure. + * \param[in] pbase_addr - pointer to BAR4 base address. + * \param[in] nport - port for which to get current ltssm value. + * \param[out] pdll - pointer to dll active state value from register. * - * \return 0 if OK, otherwise -1 + * \return -EFAULT in case of bad address, otherwise 0 */ -int tc956x_logstat_GetLTSSMLogData(void __iomem *pbase_addr, - enum ports nport, - struct tc956x_ltssm_log *ltssm_logd) +int tc956x_logstat_get_pcie_cur_dll(void __iomem *pbase_addr, enum ports nport, uint8_t *pdll) { int ret = 0; uint32_t regval; - uint32_t port_offset; /* Port Address Register Offset */ + uint32_t reg_offset; /* Port Address Register Offset */ - if ((pbase_addr == NULL) - || (ltssm_logd == NULL)) { - ret = -1; + if ((pbase_addr == NULL) || (pdll == NULL)) { + ret = -EFAULT; KPRINT_INFO("%s : NULL Pointer Arguments\n", __func__); } if (ret == 0) { - /* LTSSM Register Offsets */ - port_offset = (LTSSM_CONF_REG_OFFSET * nport); + reg_offset = nport * GLUE_REG_LTSSM_OFFSET; + /* Read DLL State */ + regval = readl(pbase_addr + TC956X_GLUE_SW_USP_TEST_OUT_127_096 + reg_offset); + *pdll = (regval & TC956X_GLUE_DLL_MASK) >> TC956X_GLUE_DLL_SHIFT; + KPRINT_INFO("%s : DLL State %s for port %s\n", __func__, dl_state[(*pdll)], pcie_port[nport]); + } + return ret; +} - KPRINT_INFO("%s : %s State Logging Configuration\n", __func__, pcie_port[nport]); +/** + * tc956x_logstat_get_pcie_cur_speed + * + * \brief Function to read current PCIe Link Speed. + * + * \details This function reads current PCIe Link Speed from register. + * + * \param[in] pbase_addr - pointer to BAR4 base address. + * \param[in] nport - port for which to get current ltssm value. + * \param[out] pspeed_val - pointer to current link speed value from register. + * + * \return -EFAULT in case of bad address, otherwise 0 + */ +int tc956x_logstat_get_pcie_cur_speed(void __iomem *pbase_addr, enum ports nport, uint8_t *pspeed_val) +{ + int ret = 0; + uint32_t regval; - /* Read LTSSM Log Data Register */ - regval = readl(pbase_addr + TC956X_CONF_REG_NPCIEUSPLOGD + port_offset); - ltssm_logd->ltssm_state = ((regval & FIFO_READ_VALUE0_MASK) - >> FIFO_READ_VALUE0_SHIFT); - KPRINT_INFO("%s : LTSSM State: 0x%x %s\n", __func__, ltssm_logd->ltssm_state, - ltssm_states[ltssm_logd->ltssm_state]); - ltssm_logd->eq_phase = ((regval & FIFO_READ_VALUE1_MASK) - >> FIFO_READ_VALUE1_SHIFT); - KPRINT_INFO("%s : Equalization Phase: 0x%x %s\n", __func__, ltssm_logd->eq_phase, - eq_phase[ltssm_logd->eq_phase]); - ltssm_logd->rxL0s = ((regval & FIFO_READ_VALUE2_MASK) - >> FIFO_READ_VALUE2_SHIFT); - KPRINT_INFO("%s : Receive L0s: 0x%x %s\n", __func__, ltssm_logd->rxL0s, - rx_L0s_state[ltssm_logd->rxL0s]); - ltssm_logd->txL0s = ((regval & FIFO_READ_VALUE3_MASK) - >> FIFO_READ_VALUE3_SHIFT); - KPRINT_INFO("%s : Transmit L0s: 0x%x %s\n", __func__, ltssm_logd->txL0s, - tx_L0s_state[ltssm_logd->txL0s]); - ltssm_logd->substate_L1 = ((regval & FIFO_READ_VALUE4_MASK) - >> FIFO_READ_VALUE4_SHIFT); - KPRINT_INFO("%s : L1 Power Management Substate: 0x%x %s\n", __func__, - ltssm_logd->substate_L1, state_L1[ltssm_logd->substate_L1]); - ltssm_logd->active_lane = ((regval & FIFO_READ_VALUE5_MASK) - >> FIFO_READ_VALUE5_SHIFT); - KPRINT_INFO("%s : Active Lanes Lane0: 0x%x %s\n", __func__, - ((ltssm_logd->active_lane & LANE0_MASK) >> LANE0_SHIFT), - active_lanes[(ltssm_logd->active_lane & LANE0_MASK)]); - KPRINT_INFO("%s : Active Lanes Lane1: 0x%x %s\n", __func__, - ((ltssm_logd->active_lane & LANE1_MASK) >> LANE1_SHIFT), - active_lanes[(ltssm_logd->active_lane & LANE1_MASK)]); - KPRINT_INFO("%s : Active Lanes Lane2: 0x%x %s\n", __func__, - ((ltssm_logd->active_lane & LANE2_MASK) >> LANE2_SHIFT), - active_lanes[(ltssm_logd->active_lane & LANE2_MASK)]); - KPRINT_INFO("%s : Active Lanes Lane3: 0x%x %s\n", __func__, - ((ltssm_logd->active_lane & LANE3_MASK) >> LANE3_SHIFT), - active_lanes[(ltssm_logd->active_lane & LANE3_MASK)]); - ltssm_logd->link_speed = ((regval & FIFO_READ_VALUE6_MASK) - >> FIFO_READ_VALUE6_SHIFT); - KPRINT_INFO("%s : Link Speed: 0x%x %s\n", __func__, ltssm_logd->link_speed, - link_speed[ltssm_logd->link_speed]); - ltssm_logd->dl_active = ((regval & FIFO_READ_VALUE7_MASK) - >> FIFO_READ_VALUE7_SHIFT); - KPRINT_INFO("%s : Data Link Active: 0x%x %s\n", __func__, - ltssm_logd->dl_active, dl_state[ltssm_logd->dl_active]); - ltssm_logd->ltssm_timeout = ((regval & FIFO_READ_VALUE8_MASK) - >> FIFO_READ_VALUE8_SHIFT); - KPRINT_INFO("%s : LTSSM Timeout: 0x%x %s\n", __func__, ltssm_logd->ltssm_timeout, - ltssm_timeout_status[ltssm_logd->ltssm_timeout]); + if ((pbase_addr == NULL) || (pspeed_val == NULL)) { + ret = -EFAULT; + KPRINT_INFO("%s : NULL Pointer Arguments\n", __func__); + } - regval = readl(pbase_addr + TC956X_CONF_REG_NPCIEUSPLOGST + port_offset); - ltssm_logd->ltssm_stop_status = ((regval & STOP_STATUS_MASK) >> STOP_STATUS_SHIFT); - KPRINT_INFO("%s : LTSSM Stop Status: 0x%x %s\n", __func__, - ltssm_logd->ltssm_stop_status, - ltssm_stop_status[ltssm_logd->ltssm_stop_status]); + if (ret == 0) { + /* Read Speed */ + regval = readl(pbase_addr + TC956X_GLUE_TL_LINK_SPEED_MON); + *pspeed_val = (regval & TC956X_GLUE_SPEED_MASK(nport)) >> TC956X_GLUE_SPEED_SHIFT(nport); + KPRINT_INFO("%s : Link Speed Gen%d for port %s\n", __func__, (*pspeed_val), pcie_port[nport]); + } + return ret; +} + +/** + * tc956x_logstat_get_pcie_cur_width + * + * \brief Function to read current PCIe Link Width. + * + * \details This function reads current PCIe Link Width from register. + * + * \param[in] pbase_addr - pointer to BAR4 base address. + * \param[in] nport - port for which to get current ltssm value. + * \param[out] plane_width_val - pointer to current lane width value from register. + * + * \return -EFAULT in case of bad address, otherwise 0 + */ +int tc956x_logstat_get_pcie_cur_width(void __iomem *pbase_addr, enum ports nport, uint8_t *plane_width_val) +{ + int ret = 0; + uint32_t regval; + + if ((pbase_addr == NULL) || (plane_width_val == NULL)) { + ret = -EFAULT; + KPRINT_INFO("%s : NULL Pointer Arguments\n", __func__); + } + + if (ret == 0) { + /* Read Lane Width */ + regval = readl(pbase_addr + TC956X_GLUE_TL_NUM_LANES_MON); + *plane_width_val = (regval & TC956X_GLUE_LANE_WIDTH_MASK(nport)) >> TC956X_GLUE_LANE_WIDTH_SHIFT(nport); + KPRINT_INFO("%s : Lane Width x%d for port %s\n", __func__, (*plane_width_val), pcie_port[nport]); } return ret; } /** - * tc956x_pcie_ioctl_SetDbgConf + * tc956x_pcie_ioctl_StateLogStop * - * \brief IOCTL Function to set and print debug configuration register. + * \brief IOCTL Function to Enable and Disable State Logging. * - * \details This function is called whenever IOCTL - * TC956X_PCIE_SET_LOGSTAT_CONF - * is invoked by user. This function - * configures LTSSM State Logging Configuration, Control, Fifo Read pointer - * Control register. In addition it also configures LTSSM enable - * registers. + * \details This function is called whenever IOCTL TC956X_PCIE_STATE_LOG_ENABLE + * is invoked by user. This function set register to enable/disable state logging. * * \param[in] priv - pointer to pcie private data. * \param[in] data - data passed from user space. * - * \return -EFAULT in case of copy failure, otherwise 0 + * \return -EFAULT in case of bad address, otherwise 0. */ -int tc956x_pcie_ioctl_SetDbgConf(const struct tc956xmac_priv *priv, - void __user *data) +int tc956x_pcie_ioctl_state_log_enable(const struct tc956xmac_priv *priv, void __user *data) { int ret = 0; - struct tc956x_ioctl_logstatconf ioctl_data; - struct tc956x_ltssm_conf logstat_conf; + struct tc956x_ioctl_state_log_enable ioctl_data; + + DBGPR_FUNC(priv->device, "--> %s\n", __func__); if ((priv == NULL) || (data == NULL)) return -EFAULT; - DBGPR_FUNC(priv->device, "--> %s\n", __func__); - - memset(&logstat_conf, 0, sizeof(logstat_conf)); if (copy_from_user(&ioctl_data, data, sizeof(ioctl_data))) ret = -EFAULT; - if (copy_from_user(&logstat_conf, - (const void __user *)ioctl_data.logstat_conf, - sizeof(logstat_conf))) - ret = -EFAULT; + if (ret == 0) + ret = tc956x_logstat_set_state_log_enable(priv->ioaddr, ioctl_data.port, ioctl_data.enable); - if (ioctl_data.port > INTERNAL_ENDPOINT) { - KPRINT_INFO("%s : Argument Port %d invalid", __func__, ioctl_data.port); - ret = -EFAULT; - } - - if (ret == 0) { -#ifdef TC956X - ret = tc956x_logstat_SetConf(priv->ioaddr, ioctl_data.port, &logstat_conf); -#endif - } + DBGPR_FUNC(priv->device, "<-- %s\n", __func__); return ret; } /** - * tc956x_pcie_ioctl_GetDbgConf + * tc956x_logstat_set_state_log_enable * - * \brief IOCTL Function to read and print debug configuration register. + * \brief Function to Enable and Disable State Log. * - * \details This function is called whenever IOCTL - * TC956X_PCIE_GET_LOGSTAT_CONF - * is invoked by user. This function - * reads LTSSM State Logging Configuration, Control, Fifo Read pointer - * Control register. In addition it also reads LTSSM enable - * registers. + * \details This function enable or disable State Logging based on mode passed. * - * \param[in] priv - pointer to pcie private data. - * \param[in] data - data passed from user space. + * \param[in] pbase_addr - pointer to Bar4 base address. + * \param[in] nport - log start/stop for port passed. + * \param[in] mode - start or stop state logging. * - * \return -EFAULT in case of copy failure, otherwise 0 + * \return -EFAULT in case of bad address, otherwise 0 */ -int tc956x_pcie_ioctl_GetDbgConf(const struct tc956xmac_priv *priv, - void __user *data) +int tc956x_logstat_set_state_log_enable(void __iomem *pbase_addr, enum ports nport, enum state_log_enable enable) { int ret = 0; - struct tc956x_ioctl_logstatconf ioctl_data; - struct tc956x_ltssm_conf logstat_conf; + uint32_t port_offset; /* Port Address Register Offset */ - if ((priv == NULL) || (data == NULL)) - return -EFAULT; - - DBGPR_FUNC(priv->device, "--> %s\n", __func__); - - memset(&logstat_conf, 0, sizeof(logstat_conf)); - if (copy_from_user(&ioctl_data, data, sizeof(ioctl_data))) - ret = -EFAULT; - - if (ioctl_data.port > INTERNAL_ENDPOINT) { - KPRINT_INFO("%s : Argument Port %d invalid", __func__, ioctl_data.port); + if (pbase_addr == NULL) { ret = -EFAULT; + KPRINT_INFO("%s : Invalid Arguments\n", __func__); } if (ret == 0) { -#ifdef TC956X - ret = tc956x_logstat_GetConf(priv->ioaddr, ioctl_data.port, &logstat_conf); -#endif + port_offset = nport * STATE_LOG_REG_OFFSET; + + if (enable == STATE_LOG_ENABLE) { + /* Stop State Log */ + writel(STATE_LOG_DISABLE, pbase_addr + TC956X_CONF_REG_NPCIEUSPLOGCTRL + port_offset); + /* Start State Log */ + writel(STATE_LOG_ENABLE, pbase_addr + TC956X_CONF_REG_NPCIEUSPLOGCTRL + port_offset); + /* Verify Sate Log Enable */ + if (readl(pbase_addr + TC956X_CONF_REG_NPCIEUSPLOGCTRL + port_offset) == STATE_LOG_ENABLE) + KPRINT_INFO("%s : Enabling State Logging for port %s\n", __func__, pcie_port[nport]); + } else { + /* Stop State Log */ + writel(STATE_LOG_DISABLE, pbase_addr + TC956X_CONF_REG_NPCIEUSPLOGCTRL + port_offset); + } + /* KPRINT_INFO("WR: Addr= 0x%08X, Val= 0x%08X\n", TC956X_CONF_REG_NPCIEUSPLOGCTRL + port_offset, enable); */ } - if (ret == 0) { - if (copy_to_user((void __user *)ioctl_data.logstat_conf, &logstat_conf, sizeof(logstat_conf))) - ret = -EFAULT; - } - return ret; -} - -/** - * tc956x_pcie_ioctl_GetLTSSMLogD - * - * \brief IOCTL Function to read and print LTSSM logging register. - * - * \details This function is called whenever IOCTL TC956X_PCIE_GET_LTSSM_LOG - * is invoked by user. This function - * read and print LTSSM Logging Data, State Logging Status Register - * Information. - * - * \param[in] priv - pointer to pcie private data. - * \param[in] data - data passed from user space. - * - * \return -EFAULT in case of copy failure, otherwise 0 - */ -int tc956x_pcie_ioctl_GetLTSSMLogD(const struct tc956xmac_priv *priv, - void __user *data) -{ - int ret = 0; - struct tc956x_ioctl_ltssm ioctl_data; - struct tc956x_ltssm_log ltssm_log; - - if ((priv == NULL) || (data == NULL)) - return -EFAULT; - DBGPR_FUNC(priv->device, "--> %s\n", __func__); - - memset(<ssm_log, 0, sizeof(ltssm_log)); - if (copy_from_user(&ioctl_data, data, sizeof(ioctl_data))) - ret = -EFAULT; - - if (ioctl_data.port > INTERNAL_ENDPOINT) { - KPRINT_INFO("%s : Argument Port %d invalid", __func__, ioctl_data.port); - ret = -EFAULT; - } - - if (ret == 0) { -#ifdef TC956X - tc956x_logstat_GetLTSSMLogData(priv->ioaddr, ioctl_data.port, &(ltssm_log)); -#endif - - } - - if (ret == 0) { - if (copy_to_user((void __user *)ioctl_data.ltssm_logd, <ssm_log, sizeof(ltssm_log))) - ret = -EFAULT; - } return ret; } diff --git a/tc956x_pcie_logstat.h b/tc956x_pcie_logstat.h index 7b0f0436cbd8..187bd71b33fb 100644 --- a/tc956x_pcie_logstat.h +++ b/tc956x_pcie_logstat.h @@ -79,7 +79,8 @@ #define STATE_LOGGING_ENABLE_SHIFT (0U) #define FIFO_READ_POINTER_MASK (0x0000001FU) #define FIFO_READ_POINTER_SHIFT (0U) - +#define STOP_STATUS_MASK (0x00000001U) +#define STOP_STATUS_SHIFT (0U) #define COUNT_LTSSM_REG_STATES (28U) @@ -121,27 +122,72 @@ #define MAX_STOP_CNT (0xFFU) #define MAX_FIFO_POINTER (31U) +#define STATE_LOG_REG_OFFSET (0x20U) +#define GLUE_REG_LTSSM_OFFSET (0x40U) + +#define STATE_LOG_STOP (1U) +#define MAX_FIFO_READ_POINTER (0x1F) +#define INVALID_STATE_LOG (0x33F7F31FU) + +#define LTSSM_TIMEOUT_NOT_OCCURRED (0U) +#define LTSSM_TIMEOUT_OCCURRED (1U) +#define DL_ACTIVE (1U) +#define DL_NOT_ACTIVE (0U) +#define ALL_LANES_INACTIVE (0U) +#define INACTIVE_L0s (0U) +#define EQ_PHASE0 (0U) +#define INACTIVE_L1 (0U) + +#define LTSSM_MAX_VALUE (0x1A) +#define LOGSTAT_DUMMY_VALUE (0xFF) +#define ACTIVE_SINGLE_LANE_MASK (1) +#define ACTIVE_SINGLE_LANE_SHIFT (1) +#define ACTIVE_ALL_LANE_MASK (0xF) +/* =================================== + * Enumeration + * =================================== + */ + +/* =================================== + * Structure/Union + * =================================== + */ +union tc956x_logstat_State_Log_Data { + struct { + unsigned char fifo_read_value0 :5; + unsigned char reserved1 :3; + unsigned char fifo_read_value1 :2; + unsigned char reserved2 :2; + unsigned char fifo_read_value2 :2; + unsigned char fifo_read_value3 :2; + unsigned char fifo_read_value4 :3; + unsigned char reserved3 :1; + unsigned char fifo_read_value5 :4; + unsigned char fifo_read_value6 :2; + unsigned char reserved4 :2; + unsigned char fifo_read_value7 :1; + unsigned char fifo_read_value8 :1; + unsigned char reserved5 :2; + } bitfield; + unsigned int reg_val; +}; + /* =================================== * Function Declaration * =================================== */ - -int tc956x_logstat_SetConf(void __iomem *pconf_base_addr, - enum ports nport, - struct tc956x_ltssm_conf *plogstat_conf); -int tc956x_logstat_GetConf(void __iomem *pconf_base_addr, - enum ports nport, - struct tc956x_ltssm_conf *plogstat_conf); -int tc956x_logstat_GetLTSSMLogData(void __iomem *pbase_addr, - enum ports nport, - struct tc956x_ltssm_log *plogstat_conf); - -int tc956x_pcie_ioctl_SetDbgConf(const struct tc956xmac_priv *priv, - void __user *data); -int tc956x_pcie_ioctl_GetDbgConf(const struct tc956xmac_priv *priv, - void __user *data); -int tc956x_pcie_ioctl_GetLTSSMLogD(const struct tc956xmac_priv *priv, - void __user *data); - +int tc956x_pcie_ioctl_state_log_summary(const struct tc956xmac_priv *priv, void __user *data); +int tc956x_pcie_ioctl_get_pcie_link_params(const struct tc956xmac_priv *priv, void __user *data); +int tc956x_pcie_ioctl_state_log_enable(const struct tc956xmac_priv *priv, void __user *data); +int tc956x_logstat_state_log_summary(void __iomem *pbase_addr, enum ports nport); +int tc956x_logstat_get_state_log_stop_status(void __iomem *pbase_addr, enum ports nport, uint8_t *pstop_status); +int tc956x_logstat_set_state_log_fifo_ptr(void __iomem *pbase_addr, enum ports nport, uint8_t fifo_pointer); +int tc956x_logstat_get_state_log_data(void __iomem *pbase_addr, enum ports nport, uint32_t *pstate_log_data); +int tc956x_logstat_state_log_analyze(unsigned int cur_state); +int tc956x_logstat_get_pcie_cur_ltssm(void __iomem *pbase_addr, enum ports nport, uint8_t *pltssm); +int tc956x_logstat_get_pcie_cur_dll(void __iomem *pbase_addr, enum ports nport, uint8_t *pdll); +int tc956x_logstat_get_pcie_cur_speed(void __iomem *pbase_addr, enum ports nport, uint8_t *pspeed_val); +int tc956x_logstat_get_pcie_cur_width(void __iomem *pbase_addr, enum ports nport, uint8_t *plane_width_val); +int tc956x_logstat_set_state_log_enable(void __iomem *pbase_addr, enum ports nport, enum state_log_enable enable); #endif /* #ifdef TC956X_PCIE_LOGSTAT */ #endif /* __TC956X_PCIE_LOGSTAT_H__ */ diff --git a/tc956x_pf_mbx.c b/tc956x_pf_mbx.c new file mode 100644 index 000000000000..e8bdcdccf928 --- /dev/null +++ b/tc956x_pf_mbx.c @@ -0,0 +1,612 @@ +/* + * TC956X ethernet driver. + * + * tc956x_pf_mbx.c + * + * Copyright (C) 2021 Toshiba Electronic Devices & Storage Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/*! History: + * 10 July 2020 : Initial Version + * VERSION : 00-01 + * + * 30 Nov 2021 : Base lined for SRIOV + * VERSION : 01-02 + */ + +#include "tc956x_pf_mbx.h" +#include "tc956xmac.h" +#include "tc956x_pf_rsc_mng.h" + +#ifdef TC956X_SRIOV_PF + +/** + * This table maintains the SRAM mapping for PF0->VF0s, VF0s->PF0, PF1->VF1s, + * VF1s->PF1, PF0->PF1, PF1->PF0, MCU->PF0, PF0->MCU, PF1->MCU, MCU->PF1 + * Each communication SRAM size is of 64 bytes. In total 30 such SRAMs are + * required for above mentioned communication path. + * In general, in Design of HW semaphore: PF uses one SRAM location for + * any request and ACK message to a particular VF and VF uses other + * SRAM location for requestand ACK. In Design of No semaphore: PF use one + * SRAM location to send request, VF to use same location (overwrite) to send + * the ACK, similarly VF uses other SRAM to send request, PF to use same location + * (overwrite) to send the ACK. + */ +static u8 PF_VF_mbx_idx[PFS_MAX][FNS_MAX][2] = { + { + {1, 2}, /* PF0 <--> MCU [PF0 RQST Msg/PF0 ACK Msg, + * MCU ACK Msg/MCU RQST Msg] + */ + {0, 0}, /* PF0 <--> PF0 [Not a valid, + * just to maintain index it is used] + */ + {3, 4}, /* PF0 <--> PF1 [PF0 RQST Msg/PF0 ACK Msg, + * PF1 ACK Msg/PF1 RQST Msg] + */ + {5, 6}, /* PF0 <--> VF00 [PF0 RQST Msg/PF0 ACK Msg, + * VF0 ACK Msg/VF0 RQST Msg] + */ + {7, 8}, /* PF0 <--> VF01 [PF0 RQST Msg/PF0 ACK Msg, + * VF1 ACK Msg/VF1 RQST Msg] + */ + {9, 10} /* PF0 <--> VF02 [PF0 RQST Msg/PF0 ACK Msg, + * VF2 ACK Msg/VF2 RQST Msg] + */ + }, + + { + {11, 12}, /* PF1 <--> MCU [PF1 RQST Msg/PF1 ACK Msg, + * MCU ACK Msg/MCU RQST Msg] + */ + {0, 0}, /* PF1 <--> PF1 [Not a valid, + * just to maintain index it is used] + */ + {3, 4}, /* PF1 <--> PF0 [PF1 RQST Msg/PF1 ACK Msg, + * PF0 ACK Msg/PF0 RQST Msg] + */ + {13, 14}, /* PF1 <--> VF10 [PF1 RQST Msg/PF1 ACK Msg, + * VF0 ACK Msg/VF0 RQST Msg] + */ + {15, 16}, /* PF1 <--> VF11 [PF1 RQST Msg/PF1 ACK Msg, + * VF1 ACK Msg/VF1 RQST Msg] + */ + {17, 18} /* PF1 <--> VF12 [PF1 RQST Msg/PF1 ACK Msg, + * VF2 ACK Msg/VF2 RQST Msg] + */ + }, + + { + {19, 20}, /* MCU <--> VF00 [MCU RQST Msg/MCU ACK Msg, + * VF00 ACK Msg/VF00 RQST Msg] + */ + {21, 22}, /* MCU <--> VF01 [MCU RQST Msg/MCU ACK Msg, + * VF01 ACK Msg/VF01 RQST Msg] + */ + {23, 24}, /* MCU <--> VF02 [MCU RQST Msg/MCU ACK Msg, + * VF02 ACK Msg/VF02 RQST Msg] + */ + {25, 26}, /* MCU <--> VF10 [MCU RQST Msg/MCU ACK Msg, + * VF10 ACK Msg/VF10 RQST Msg] + */ + {27, 28}, /* MCU <--> VF11 [MCU RQST Msg/MCU ACK Msg, + * VF11 ACK Msg/VF11 RQST Msg] + */ + {29, 30} /* MCU <--> VF12 [MCU RQST Msg/MCU ACK Msg, + * VF12 ACK Msg/VF12 RQST Msg] + */ + }, +}; + +/** + * pf_get_mbx_mem_idx + * + * \brief API to return pointer pointing to SRAM index + * + * \details This function to return the pointer to the 1D array of + * PF_VF_mbx_idx where it points to SRAM location of specific PF->Fn + * + * \param[in] msg_src - Function to/from where PF needs to write/read + * \param[in] fn_id_info - Pointer to this function id information + * + * \return pointer to the SRAM index + */ + +static u8 *pf_get_mbx_mem_idx(enum mbx_msg_fns msg_src, + struct fn_id *fn_id_info) +{ + return *(*(PF_VF_mbx_idx + fn_id_info->pf_no) + msg_src); +} + +/** + * tc956x_pf_get_fn_idx_from_int_sts + * + * \brief Helper function to get function that raised the mailbox interrupt + * + * \details This function is called to get the function which raised the + * mailbox interrupt. Interrupt source can be MCU, VFs or other PF + * + * \param[in] msg_dst - Function to which interrupt should be set + * \param[in] fn_id_info - Pointer to Function info structure + * + * \return function type or error + */ +int tc956x_pf_get_fn_idx_from_int_sts(struct tc956xmac_priv *priv, + struct fn_id *fn_id_info) +{ + void __iomem *ioaddr = priv->tc956x_BRIDGE_CFG_pci_base_addr; + u32 rsc_mng_int_sts = readl(ioaddr + RSCMNG_INT_ST_REG); + + if ((rsc_mng_int_sts & RSC_MNG_INT_MCU_MASK) == RSC_MNG_INT_MCU_MASK) { + writel(RSC_MNG_INT_MCU_MASK, ioaddr + RSCMNG_INT_ST_REG); + return mcu; + } else if ((rsc_mng_int_sts & RSC_MNG_INT_VF2_MASK) == + RSC_MNG_INT_VF2_MASK) { + writel(RSC_MNG_INT_VF2_MASK, ioaddr + RSCMNG_INT_ST_REG); + return vf2; + } else if ((rsc_mng_int_sts & RSC_MNG_INT_VF1_MASK) == + RSC_MNG_INT_VF1_MASK) { + writel(RSC_MNG_INT_VF1_MASK, ioaddr + RSCMNG_INT_ST_REG); + return vf1; + } else if ((rsc_mng_int_sts & RSC_MNG_INT_VF0_MASK) == + RSC_MNG_INT_VF0_MASK) { + writel(RSC_MNG_INT_VF0_MASK, ioaddr + RSCMNG_INT_ST_REG); + return vf0; + } else if ((rsc_mng_int_sts & RSC_MNG_INT_OTHR_PF_MASK) == + RSC_MNG_INT_OTHR_PF_MASK) { + if (fn_id_info->pf_no == 0) { + writel(RSC_MNG_INT_OTHR_PF_MASK, ioaddr + RSCMNG_INT_ST_REG); + return pf1; + } else if (fn_id_info->pf_no == 1) { + writel(RSC_MNG_INT_OTHR_PF_MASK, ioaddr + RSCMNG_INT_ST_REG); + return pf0; + } else + return -1; + } else + return -1; +} + +static int trylock_semaphore(void __iomem *ioaddr, u8 idx) +{ + u32 rd_val = 0; + + /* Read 0 for lock. Else already semaphore is locked + * curr value : action : next value + * 0 : read 0 : 1 + * 1 : read 1 : 1 + */ + + rd_val = readl(ioaddr + NSEM(idx)); + if (rd_val == 0) + return 0; + else + return -EBUSY; +} + +static int unlock_semaphore(void __iomem *ioaddr, u8 idx) +{ + u32 wr_val = 1; + + /* Write 1 to unlock + * curr value : action : next value + * 0 : write 0 : 0 + * 0 : write 1 : 0 + * 1 : write 0 : 1 + * 1 : write 1 : 0 + */ + writel(wr_val, ioaddr + NSEM(idx)); + return 0; +} + +/** + * tc956x_pf_parse_mbx + * + * \brief API to read and process the PF mailbox + * + * \details This function should be called from ISR to parse the mailbox for + * the mail received from particular function. Message will be processed and + * ACK/NACK will be sent in this function + * + * \param[in] priv - Pointer to device private structure + * \param[in] msg_src - Function to which ACK should be posted + * + * \return None + */ +void tc956x_pf_parse_mbx(struct tc956xmac_priv *priv, + enum mbx_msg_fns msg_src) +{ + u8 msg_buff[MBX_TOT_SIZE]; + + /* Get the function id information and read the mailbox. + * Function id can be get earlier too + */ + if (!tc956xmac_rsc_mng_get_fn_id(priv, + priv->tc956x_BRIDGE_CFG_pci_base_addr, &priv->fn_id_info)) { + /* Read and acknowledge the mailbox */ + tc956xmac_mbx_read(priv, msg_buff, msg_src, + &priv->fn_id_info); + } +} + + +/** + * tc956x_pf_check_for_ack + * + * \brief Helper function to check for ACK + * + * \details This function is called from polling function to check if + * any ACK or NACK is received after writing in the mailbox + * + * \param[in] dev - Pointer to device structure + * \param[in] msg_dst - Function from which ACK/NACK should be read + * \param[in] fn_id_info - Pointer to Function info structure + * + * \return ACK/NACK or error + */ +static int tc956x_pf_check_for_ack(struct tc956xmac_priv *priv, + enum mbx_msg_fns msg_dst, + struct fn_id *fn_id_info) +{ + u8 *ptr_mail_box_idx; + u8 ack_buff[MBX_ACK_SIZE]; + + /* Read the correct mailbox access index as per + * the destination function + */ + ptr_mail_box_idx = pf_get_mbx_mem_idx(msg_dst, fn_id_info); + + /* Copy the ACK inidication data (first 4 bytes) from VF->PF mailbox */ + memcpy_fromio(ack_buff, + (priv->tc956x_SRAM_mailbox_base_addr + + ((*ptr_mail_box_idx + PF_READ_ACK_OFST) * MBX_TOT_SIZE)), + MBX_ACK_SIZE); + + if ((ack_buff[0] & RSC_MNG_ACK_MASK) == RSC_MNG_ACK_MASK) + return ACK; + else if ((ack_buff[0] & RSC_MNG_NACK_MASK) == RSC_MNG_NACK_MASK) + return NACK; + else + return -1; +} + +/** + * tc956x_pf_mbx_init + * + * \brief API to initialise mailbox memory and parameters + * + * \details This function initialise mailbox memory used by this function. + * Also to initialise parameters used for mailbox control. + * + * \param[in] ndev - Pointer to device structure + * + * \return None + */ +static void tc956x_pf_mbx_init(struct tc956xmac_priv *priv, void *data) +{ + priv->tc956x_SRAM_mailbox_base_addr = priv->tc956x_SRAM_pci_base_addr + PF_MBX_SRAM_ADDR; + memset_io(priv->tc956x_SRAM_mailbox_base_addr, 0, 1920); +} + +/** + * tc956x_pf_mbx_poll_for_ack + * + * \brief API to poll for acknowledgement + * + * \details This function will poll for acknowledgement after writing to the + * mailbox memory. Polling is done by means of reading a + * resource manager register + * + * \param[in] priv - Pointer to device private structure + * \param[in] msg_dst - Function from which ACK should be polled + * + * \return None + */ +static int tc956x_pf_mbx_poll_for_ack(struct tc956xmac_priv *priv, + enum mbx_msg_fns msg_dst) +{ + + int countdown = MBX_TIMEOUT; + int ack_status; + + ack_status = + tc956x_pf_check_for_ack(priv, msg_dst, &priv->fn_id_info); + + while (countdown && (ack_status < 0)) { + countdown--; + udelay(1000); + ack_status = tc956x_pf_check_for_ack(priv, msg_dst, + &priv->fn_id_info); + } + + return ack_status; +} + +/** + * tc956x_pf_mbx_send_ack + * + * \brief API to send acknowledgement + * + * \details This function will post the acknowledgement message + * to the mailbox memory. + * Basically this should be called after every read + * + * \param[in] priv - Pointer to device private structure + * \param[in] msg_buff - Pointer to buffer having the acknowledgement message + * \param[in] msg_dst - Function to which ACK should be posted + * \param[in] fn_id_info - Pointer to function id information + * + * \return None + */ +static void tc956x_pf_mbx_send_ack(struct tc956xmac_priv *priv, u8 *msg_buff, + enum mbx_msg_fns msg_dst, + struct fn_id *fn_id_info) +{ + u8 *ptr_mail_box_idx; + + /* Read the correct mailbox access index as per + * the destination function + */ + ptr_mail_box_idx = pf_get_mbx_mem_idx(msg_dst, fn_id_info); + + /* Copy the ACK message data to PF->VF SRAM area. + * Also first 4 bytes of ACK indications also copied here + */ + memcpy_toio((priv->tc956x_SRAM_mailbox_base_addr + + ((*ptr_mail_box_idx + PF_SEND_ACK_OFST) * MBX_TOT_SIZE)), + msg_buff, MBX_TOT_SIZE); + + if (msg_dst >= 3) + priv->xstats.mbx_pf_sent_vf[msg_dst - 3]++; +} + +/** + * tc956x_pf_trigger_interrupt + * + * \brief Helper function to set mailbox interrupt bit + * + * \details This function is called to set the mailbox interrupt bits while + * writing the mailbox. Interrupt targets can be MCU, VFs or other PF + * + * \param[in] msg_dst - Function to which interrupt should be set + * + * \return None + */ +static void tc956x_pf_trigger_interrupt(struct tc956xmac_priv *priv, + enum mbx_msg_fns msg_dst) +{ + void __iomem *ioaddr = priv->tc956x_BRIDGE_CFG_pci_base_addr; + u32 rsc_mng_interrupt_ctl = readl(ioaddr + RSCMNG_INT_CTRL_REG); + + if (mcu == msg_dst) + rsc_mng_interrupt_ctl |= MBX_MCU_INTERRUPT; + else if (vf2 == msg_dst) + rsc_mng_interrupt_ctl |= MBX_VF3_INTERRUPT; + else if (vf1 == msg_dst) + rsc_mng_interrupt_ctl |= MBX_VF2_INTERRUPT; + else if (vf0 == msg_dst) + rsc_mng_interrupt_ctl |= MBX_VF1_INTERRUPT; + else if ((pf0 == msg_dst) || (pf1 == msg_dst)) + rsc_mng_interrupt_ctl |= MBX_PF_INTERRUPT; + + writel(rsc_mng_interrupt_ctl, ioaddr + RSCMNG_INT_CTRL_REG); +} + +/** + * tc956x_pf_mbx_write + * + * \brief API to write a message to particular mailbox (sram) + * + * \details This function will post the request message to the mailbox memory. + * + * \param[in] priv - Pointer to device private structure + * \param[in] msg_buff - Pointer to buffer having the request message + * Skip the first 4 bytes while preparing data in this buffer + * \param[in] msg_dst - Function to which message should be posted + * \param[in] fn_id_info - Pointer to function id information + * + * \return success or error code + */ +static int tc956x_pf_mbx_write(struct tc956xmac_priv *priv, u8 *msg_buff, + enum mbx_msg_fns msg_dst, + struct fn_id *fn_id_info) +{ + u8 *ptr_mail_box_idx; + int ret; + + /* Read the correct mailbox access index as per + * the destination function + */ + ptr_mail_box_idx = pf_get_mbx_mem_idx(msg_dst, fn_id_info); + + /* Get the semaphore lock before udpating mailbox */ + ret = trylock_semaphore(priv->ioaddr, ((*ptr_mail_box_idx + 1) >> 1)); + if (ret != 0) + return ret; + + + /* Clear the mailbox including ACK area (first 4 bytes) */ + memset_io((priv->tc956x_SRAM_mailbox_base_addr + + ((*ptr_mail_box_idx + PF_SEND_RQST_OFST) * MBX_TOT_SIZE)), + 0, MBX_TOT_SIZE); + + /* Copy the mailbox data from local buffer to PF->VF or other + * destination mailbox SRAM memory + */ + memcpy_toio((priv->tc956x_SRAM_mailbox_base_addr + + ((*ptr_mail_box_idx + PF_SEND_RQST_OFST)*MBX_TOT_SIZE) + MBX_MSG_OFST), + msg_buff, MBX_MSG_SIZE); + + if (msg_dst >= 3) + priv->xstats.mbx_pf_sent_vf[msg_dst - 3]++; + + /*Set the interrupt bit in resource manager interrupt register*/ + tc956x_pf_trigger_interrupt(priv, msg_dst); + + /*poll for ack/nack from the VF/MCU/Other PF*/ + ret = tc956xmac_mbx_poll_for_ack(priv, msg_dst); + + /* Read for ACK message */ + if (ret > 0) { + tc956xmac_mbx_read(priv, msg_buff, msg_dst, + &priv->fn_id_info); + } + + unlock_semaphore(priv->ioaddr, ((*ptr_mail_box_idx + 1) >> 1)); + + return ret; +} + +/** + * tc956x_pf_mbx_read + * + * \brief API to read a message from particular mailbox (sram) + * + * \details This function will read request message from the mailbox + * memory. This function to be called from mailbox interrupt routine. + * This API can be used in case of ACK message read as well. + * + * \param[in] priv - Pointer to device private structure + * \param[in] msg_buff - Pointer to read the mailbox message of max size + * 64 bytes + * \param[in] msg_src - Function from which mailbox message should be read + * \param[in] fn_id_info - Pointer to function id information + * + * \return success or error code + */ +static int tc956x_pf_mbx_read(struct tc956xmac_priv *priv, u8 *msg_buff, + enum mbx_msg_fns msg_src, + struct fn_id *fn_id_info) +{ + u8 *ptr_mail_box_idx; + enum mbx_msg_fns msg_dst; + u8 ack_msg[MBX_MSG_SIZE]; + u8 ret_val = 0; + u8 vf_no = 0; + + /* Read the correct mailbox access index as per + * the destination function + */ + ptr_mail_box_idx = pf_get_mbx_mem_idx(msg_src, fn_id_info); + + /* Copy the mailbox data from VF->PF mailbox */ + memcpy_fromio(msg_buff, + (priv->tc956x_SRAM_mailbox_base_addr + + ((*ptr_mail_box_idx + PF_READ_RQST_OFST) * MBX_TOT_SIZE)), + MBX_TOT_SIZE); + + if (msg_src >= 3) + vf_no = msg_src - 2; + + priv->xstats.mbx_pf_rcvd_vf[vf_no - 1]++; + + switch (msg_buff[MBX_MSG_OFST]) { + case OPCODE_MBX_ADD_MAC_ADDR: + /* Call specific function for the type and get the return + * as ACK,NACK and associated data + */ + ret_val = tc956x_mbx_wrap_set_umac_addr(priv, &msg_buff[MBX_MSG_OFST], &ack_msg[0], vf_no); + break; + + case OPCODE_MBX_SET_TX_Q_WEIGHT: /* set mtl tx queue weight */ + ret_val = tc956x_mbx_wrap_set_mtl_tx_queue_weight(priv, &msg_buff[MBX_MSG_OFST], &ack_msg[0]); + break; + case OPCODE_MBX_CFG_CBS: /* config cbs */ + ret_val = tc956x_mbx_wrap_config_cbs(priv, &msg_buff[MBX_MSG_OFST], &ack_msg[0]); + break; + case OPCODE_MBX_SETUP_CBS: /* setup cbs */ + ret_val = tc956x_mbx_wrap_setup_cbs(priv, &msg_buff[MBX_MSG_OFST], &ack_msg[0]); + break; + case OPCODE_MBX_SET_TX_Q_PRIOR: /* tx queue prior */ + ret_val = tc956x_mbx_wrap_tx_queue_prior(priv, &msg_buff[MBX_MSG_OFST], &ack_msg[0]); + break; + case OPCODE_MBX_SET_DMA_TX_MODE: /* set dma tx mode */ + ret_val = tc956x_mbx_wrap_set_dma_tx_mode(priv, &msg_buff[MBX_MSG_OFST], &ack_msg[0]); + break; + case OPCODE_MBX_VF_GET_LINK_STATUS: /* vf get link status */ + ret_val = tc956x_mbx_wrap_get_link_status(priv, &msg_buff[MBX_MSG_OFST], &ack_msg[0]); + break; + case OPCODE_MBX_VF_IOCTL: + ret_val = tc956xmac_mbx_ioctl_interface(priv, &msg_buff[MBX_MSG_OFST], &ack_msg[0], vf_no); + break; + case OPCODE_MBX_VF_ETHTOOL: + ret_val = tc956xmac_mbx_ethtool_interface(priv, priv->dev, &msg_buff[MBX_MSG_OFST], &ack_msg[0]); + break; + case OPCODE_MBX_VF_ADD_MAC: + ret_val = tc956xmac_mbx_add_mac(priv, priv->dev, &msg_buff[MBX_MSG_OFST], &ack_msg[0], vf_no); + break; + case OPCODE_MBX_VF_DELETE_MAC: + ret_val = tc956xmac_mbx_delete_mac(priv, priv->dev, &msg_buff[MBX_MSG_OFST], &ack_msg[0], vf_no); + break; + case OPCODE_MBX_VF_ADD_VLAN: + ret_val = tc956xmac_mbx_add_vlan(priv, priv->dev, &msg_buff[MBX_MSG_OFST], &ack_msg[0], vf_no); + break; + case OPCODE_MBX_VF_DELETE_VLAN: + ret_val = tc956xmac_mbx_delete_vlan(priv, priv->dev, &msg_buff[MBX_MSG_OFST], &ack_msg[0], vf_no); + break; + case OPCODE_MBX_DRV_CAP: + ret_val = tc956x_mbx_wrap_get_drv_cap(priv, &msg_buff[MBX_MSG_OFST], &ack_msg[0]); + break; + case OPCODE_MBX_GET_UMAC_ADDR: + ret_val = tc956x_mbx_wrap_get_umac_addr(priv, &msg_buff[MBX_MSG_OFST], &ack_msg[0]); + break; + case OPCODE_MBX_RESET_EEE_MODE: + ret_val = tc956x_mbx_wrap_reset_eee_mode(priv, &msg_buff[MBX_MSG_OFST], &ack_msg[0]); + break; + case OPCODE_VF_RESET: + ret_val = tc956x_mbx_wrap_vf_reset(priv, &msg_buff[MBX_MSG_OFST], &ack_msg[0], vf_no); + break; + case OPCODE_MBX_ACK_MSG: + /* ACK message */ + memset_io((priv->tc956x_SRAM_mailbox_base_addr + + ((*ptr_mail_box_idx + PF_READ_RQST_OFST) * MBX_TOT_SIZE)), 0, + MBX_TOT_SIZE); + break; + default: + break; + } + + /* Send the Acknowldegment if message read is not ACK message */ + if (msg_buff[MBX_MSG_OFST] != OPCODE_MBX_ACK_MSG) { + /* For sending ACK, source of request message becomes + * the destination + */ + msg_dst = msg_src; + + /* Prepare first 4 bytes of ACK inidication data */ + msg_buff[0] = ret_val; + msg_buff[1] = 0x0; + msg_buff[2] = 0x0; + msg_buff[3] = 0x0; + + memcpy(&msg_buff[MBX_MSG_OFST], ack_msg, MBX_MSG_SIZE); + + /* After successful parsing, ACK/NACK the functions which + * originated the message + */ + tc956xmac_mbx_send_ack(priv, msg_buff, msg_dst, + fn_id_info); + } + return 0; +} + +const struct mac_mbx_ops tc956xmac_mbx_ops = { + .init = tc956x_pf_mbx_init, + .read = tc956x_pf_mbx_read, + .write = tc956x_pf_mbx_write, + .send_ack = tc956x_pf_mbx_send_ack, + .poll_for_ack = tc956x_pf_mbx_poll_for_ack, +}; +#endif /* #ifdef TC956X_SRIOV_PF */ diff --git a/tc956x_pf_mbx.h b/tc956x_pf_mbx.h new file mode 100644 index 000000000000..eb7f9cfcc020 --- /dev/null +++ b/tc956x_pf_mbx.h @@ -0,0 +1,47 @@ +/* + * TC956X ethernet driver. + * + * tc956x_pf_mbx.h + * + * Copyright (C) 2021 Toshiba Electronic Devices & Storage Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/*! History: + * 10 July 2020 : Initial Version + * VERSION : 00-01 + * + * 30 Nov 2021 : Base lined for SRIOV + * VERSION : 01-02 + */ + +#ifndef __TC956X_PF_MBX_H__ +#define __TC956X_PF_MBX_H__ + +#include "common.h" +#include + +#define PF_READ_RQST_OFST 1 +#define PF_SEND_ACK_OFST 0 + +#define PF_SEND_RQST_OFST 0 +#define PF_READ_ACK_OFST 1 + +#define PFS_MAX 3 /* 2 PF + 1 MCU */ +#define FNS_MAX 6 /* actually 5 communication paths */ +#define PF_MBX_SRAM_ADDR 0x47060 /*0x20007060*/ + +#endif /* __TC956X_PF_MBX_H__ */ diff --git a/tc956x_pf_mbx_wrapper.c b/tc956x_pf_mbx_wrapper.c new file mode 100644 index 000000000000..b74c8417bd47 --- /dev/null +++ b/tc956x_pf_mbx_wrapper.c @@ -0,0 +1,1816 @@ +/* + * TC956X ethernet driver. + * + * tc956x_mbx_wrapper.c + * + * Copyright (C) 2022 Toshiba Electronic Devices & Storage Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/*! History: + * 15 Sep 2020 : Initial Version + * VERSION : 00-01 + * + * 30 Nov 2021 : Base lined for SRIOV + * VERSION : 01-02 + * + * 20 May 2022 : 1. Automotive Driver, CPE fixes merged and IPA Features supported + * 2. Base lined version + * VERSION : 03-00 + */ + +#include "tc956x_pf_mbx.h" +#include "tc956xmac.h" +#include "common.h" + +extern int tc956xmac_ioctl_get_cbs(struct tc956xmac_priv *priv, void *data); +extern int tc956xmac_ioctl_set_cbs(struct tc956xmac_priv *priv, void *data); +extern int tc956xmac_ioctl_set_rxp(struct tc956xmac_priv *priv, void *data); +extern int tc956xmac_ioctl_get_rxp(struct tc956xmac_priv *priv, void *data); +extern int tc956xmac_ioctl_set_est(struct tc956xmac_priv *priv, void *data); +extern int tc956xmac_ioctl_get_est(struct tc956xmac_priv *priv, void *data); +extern int tc956xmac_ioctl_set_fpe(struct tc956xmac_priv *priv, void *data); +extern int tc956xmac_ioctl_get_fpe(struct tc956xmac_priv *priv, void *data); +extern int tc956xmac_ethtool_op_get_eee(struct net_device *dev, + struct ethtool_eee *edata); + + +extern int tc956x_pf_set_mac_filter(struct net_device *dev, int vf, + const u8 *mac); + +extern void tc956x_pf_del_mac_filter(struct net_device *dev, int vf, const u8 *mac); + +extern void tc956x_pf_set_vlan_filter(struct net_device *dev, u16 vf, u16 vid); + +extern void tc956x_pf_del_vlan_filter(struct net_device *dev, u16 vf, u16 vid); + +extern void tc956x_pf_del_umac_addr(struct tc956xmac_priv *priv, int index, int vf); + +extern void tc956xmac_service_mbx_event_schedule(struct tc956xmac_priv *priv); + +#ifdef TC956X_SRIOV_PF +/** + * tc956x_mbx_mac_link + * + * \brief API to send link state and params to VFs + * + * \details This function is used to send PHY link parameters to VF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * + * \return None + */ +static void tc956x_mbx_phy_link(struct tc956xmac_priv *priv) +{ + /* Prepare mailbox message and call mailbox API for posting + * and getting the ACK + */ + u8 mbx[MAX_NO_OF_VFS][MBX_TOT_SIZE]; + int ret, i; + enum mbx_msg_fns msg_dst; + + if (priv == NULL) { + KPRINT_DEBUG1("NULL pointer error"); + return; + } + + for (i = 0; i < MAX_NO_OF_VFS; i++) { + + mbx[i][0] = OPCODE_MBX_PHY_LINK; /* opcode */ + mbx[i][1] = SIZE_MBX_PHY_LINK; /* size */ + + /* Copy link, speed and duplex values */ + memcpy(&mbx[i][2], &priv->link, SIZE_MBX_PHY_LINK); + } + + /* Send data to all VFs */ + for (i = vf0; i <= vf2; i++) { + + if (priv->clear_to_send[i-vf0] == VF_UP) { + msg_dst = (enum mbx_msg_fns) i; + + ret = tc956xmac_mbx_write(priv, &mbx[i-vf0][0], msg_dst, + &priv->fn_id_info); + + /* Validation of successfull message posting can be done + * by reading the mbx buffer for ACK opcode (0xFE) + */ + + if (ret > 0) + KPRINT_DEBUG1( + "mailbox write with ACK or NACK %d msgbuff %x %x\n", + ret, mbx[i-vf0][0], mbx[i-vf0][4]); + else + KPRINT_DEBUG1("mailbox write failed"); + } else + KPRINT_DEBUG1("VF %d not up", i-vf0); + } +} + +/** + * tc956x_mbx_rx_dma_ch_tlptr + * + * \brief API to send ch numer to VF where overflow detected + * + * \details This function is used to send DMA channel no to VF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] ch - DMA channel no + * \param[in] vf - VF no of DMA channel + * + * \return 0 or error + */ +static int tc956x_mbx_rx_dma_ch_tlptr(struct tc956xmac_priv *priv, u32 ch, u8 vf) +{ + + /* Prepare mailbox message and call mailbox API for posting + * and getting the ACK + */ + u8 mbx[MBX_TOT_SIZE]; + int ret = 0; + enum mbx_msg_fns msg_dst; + + if (priv == NULL) { + KPRINT_DEBUG1("NULL pointer error"); + return -EFAULT; + } + + mbx[0] = OPCODE_MBX_DMA_CH_TLPTR; /* opcode */ + mbx[1] = SIZE_MBX_RX_DMA_TL_PTR; /* size */ + + memcpy(&mbx[2], &ch, SIZE_MBX_RX_DMA_TL_PTR); + + if (priv->clear_to_send[vf] == VF_UP) { + msg_dst = (enum mbx_msg_fns)(vf + 3); + + ret = tc956xmac_mbx_write(priv, &mbx[0], msg_dst, + &priv->fn_id_info); + + /* Validation of successfull message posting can be done + * by reading the mbx buffer for ACK opcode (0xFF) + */ + if (ret > 0) + KPRINT_DEBUG1( + "mailbox write with ACK or NACK %d msgbuff %x %x\n", + ret, mbx[0], mbx[4]); + else + KPRINT_DEBUG1("mailbox write failed"); + } else + KPRINT_DEBUG1("VF %d is not UP", vf); + + return ret; +} + +/** + * tc956x_mbx_set_dma_tx_mode + * + * \brief API to set dma tx mode + * + * \details This function is used to set dma tx mode on VF request using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] mbx_buff - Pointer to message + * \param[out] ack_msg - Pointer to output ack + * + * \return ACK/NACK + */ +static int tc956x_mbx_set_dma_tx_mode(struct tc956xmac_priv *priv, u8 *mbx_buff, u8 *ack_buff) +{ + u32 txmode = 0; + u32 chan = 0; + u8 qmode = 0; + int txfifosz; + + if (priv == NULL || mbx_buff == NULL || ack_buff == NULL) { + KPRINT_DEBUG1("NULL pointer error\n"); + return NACK; + } + + if (mbx_buff[0] != OPCODE_MBX_SET_DMA_TX_MODE) + return NACK; + + if (mbx_buff[1] != SIZE_MBX_SET_DMA_TX_MODE) + return NACK; + + memcpy(&txmode, &mbx_buff[2], sizeof(txmode)); + memcpy(&chan, &mbx_buff[6], sizeof(chan)); + memcpy(&txfifosz, &mbx_buff[10], sizeof(txfifosz)); + qmode = mbx_buff[14]; + + /* Call core API to set the register */ + tc956xmac_dma_tx_mode(priv, priv->ioaddr, txmode, chan, + txfifosz, qmode); + + /* Clear the ACK buffer as there is no ACK message */ + ack_buff[0] = OPCODE_MBX_ACK_MSG; /* set ACK opcode */ + memset(&ack_buff[1], 0, MBX_MSG_SIZE-1); + + /* return ACK as all steps are successfull */ + return ACK; +} + +/** + * tc956x_mbx_set_mtl_tx_queue_weight + * + * \brief API to set tx mtl queue weight + * + * \details This function is used to set tx mtl queue weight on VF request using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] mbx_buff - Pointer to message + * \param[out] ack_msg - Pointer to output ack + * + * \return ACK/NACK + */ +static int tc956x_mbx_set_mtl_tx_queue_weight(struct tc956xmac_priv *priv, u8 *mbx_buff, + u8 *ack_buff) +{ + u32 weight, traffic_class; + + if (priv == NULL || mbx_buff == NULL || ack_buff == NULL) { + KPRINT_DEBUG1("NULL pointer error\n"); + return NACK; + } + + if (mbx_buff[0] != OPCODE_MBX_SET_TX_Q_WEIGHT) + return NACK; + + if (mbx_buff[1] != SIZE_MBX_SET_TX_Q_WEIGHT) + return NACK; + + memcpy(&weight, &mbx_buff[2], sizeof(weight)); + memcpy(&traffic_class, &mbx_buff[6], sizeof(traffic_class)); + + /* Call core API to set the register */ + tc956xmac_set_mtl_tx_queue_weight(priv, priv->hw, weight, traffic_class); + + /* Clear the ACK buffer as there is no ACK message */ + ack_buff[0] = OPCODE_MBX_ACK_MSG; /* set ACK opcode */ + memset(&ack_buff[1], 0, MBX_MSG_SIZE-1); + + /* return ACK as all steps are successfull */ + return ACK; +} + +/** + * tc956x_mbx_config_cbs + * + * \brief API to configure te cbs param + * + * \details This function is used to configure te cbs param on VF request using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] mbx_buff - Pointer to message + * \param[out] ack_msg - Pointer to output ack + * + * \return ACK/NACK + */ +static int tc956x_mbx_config_cbs(struct tc956xmac_priv *priv, + u8 *mbx_buff, u8 *ack_buff) +{ + u32 send_slope, idle_slope, high_credit; + u32 low_credit, queue; +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + unsigned long flags; +#endif + if (priv == NULL || mbx_buff == NULL || ack_buff == NULL) { + KPRINT_DEBUG1("NULL pointer error\n"); + return NACK; + } + + if (mbx_buff[0] != OPCODE_MBX_CFG_CBS) + return NACK; + + if (mbx_buff[1] != SIZE_MBX_CFG_CBS) + return NACK; +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_lock_irqsave(&priv->spn_lock.cbs, flags); +#endif + memcpy(&send_slope, &mbx_buff[2], sizeof(send_slope)); + memcpy(&idle_slope, &mbx_buff[6], sizeof(idle_slope)); + memcpy(&high_credit, &mbx_buff[10], sizeof(high_credit)); + memcpy(&low_credit, &mbx_buff[14], sizeof(low_credit)); + memcpy(&queue, &mbx_buff[18], sizeof(queue)); + + /* Call core API to set the register */ + tc956xmac_config_cbs(priv, priv->hw, send_slope, + idle_slope, high_credit, low_credit, queue); + + if (priv->speed == SPEED_100) { + priv->cbs_speed100_cfg[queue].send_slope = send_slope; + priv->cbs_speed100_cfg[queue].idle_slope = idle_slope; + priv->cbs_speed100_cfg[queue].high_credit = high_credit; + priv->cbs_speed100_cfg[queue].low_credit = low_credit; + } else if (priv->speed == SPEED_1000) { + priv->cbs_speed1000_cfg[queue].send_slope = send_slope; + priv->cbs_speed1000_cfg[queue].idle_slope = idle_slope; + priv->cbs_speed1000_cfg[queue].high_credit = high_credit; + priv->cbs_speed1000_cfg[queue].low_credit = low_credit; + } else if (priv->speed == SPEED_10000) { + priv->cbs_speed10000_cfg[queue].send_slope = send_slope; + priv->cbs_speed10000_cfg[queue].idle_slope = idle_slope; + priv->cbs_speed10000_cfg[queue].high_credit = high_credit; + priv->cbs_speed10000_cfg[queue].low_credit = low_credit; + } else if (priv->speed == SPEED_2500) { + priv->cbs_speed2500_cfg[queue].send_slope = send_slope; + priv->cbs_speed2500_cfg[queue].idle_slope = idle_slope; + priv->cbs_speed2500_cfg[queue].high_credit = high_credit; + priv->cbs_speed2500_cfg[queue].low_credit = low_credit; + } else if (priv->speed == SPEED_5000) { + priv->cbs_speed5000_cfg[queue].send_slope = send_slope; + priv->cbs_speed5000_cfg[queue].idle_slope = idle_slope; + priv->cbs_speed5000_cfg[queue].high_credit = high_credit; + priv->cbs_speed5000_cfg[queue].low_credit = low_credit; + } +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_unlock_irqrestore(&priv->spn_lock.cbs, flags); +#endif + /* Clear the ACK buffer as there is no ACK message */ + ack_buff[0] = OPCODE_MBX_ACK_MSG; + memset(&ack_buff[1], 0, MBX_MSG_SIZE-1); + + /* return ACK as all steps are successfull */ + return ACK; + +} + +/** + * tc956x_mbx_setup_cbs + * + * \brief API to configure te cbs param using tc command + * + * \details This function is used to configure te cbs param using tc command + * on VF request using mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] mbx_buff - Pointer to message + * \param[out] ack_msg - Pointer to output ack + * + * \return ACK/NACK + */ +static int tc956x_mbx_setup_cbs(struct tc956xmac_priv *priv, + u8 *mbx_buff, u8 *ack_buff) +{ + struct tc_cbs_qopt_offload qopt; + + if (priv == NULL || mbx_buff == NULL || ack_buff == NULL) { + KPRINT_DEBUG1("NULL pointer error\n"); + return NACK; + } + + if (mbx_buff[0] != OPCODE_MBX_SETUP_CBS) + return NACK; + + if (mbx_buff[1] != SIZE_MBX_SETUP_CBS) + return NACK; + + memcpy(&qopt.enable, &mbx_buff[2], sizeof(qopt.enable)); + memcpy(&qopt.idleslope, &mbx_buff[3], sizeof(qopt.idleslope)); + memcpy(&qopt.sendslope, &mbx_buff[7], sizeof(qopt.sendslope)); + memcpy(&qopt.hicredit, &mbx_buff[11], sizeof(qopt.hicredit)); + memcpy(&qopt.locredit, &mbx_buff[15], sizeof(qopt.locredit)); + memcpy(&qopt.queue, &mbx_buff[19], sizeof(qopt.queue)); + + tc956xmac_tc_setup_cbs(priv, &qopt); + /* Clear the ACK buffer as there is no ACK message */ + ack_buff[0] = OPCODE_MBX_ACK_MSG; + memset(&ack_buff[1], 0, MBX_MSG_SIZE-1); + + /* return ACK as all steps are successfull */ + return ACK; +} + +/** + * tc956x_mbx_tx_queue_prio + * + * \brief API to set tx queue priority + * + * \details This function is used to set tx queue priority + * on VF request using mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] mbx_buff - Pointer to message + * \param[out] ack_msg - Pointer to output ack + * + * \return ACK/NACK + */ +static int tc956x_mbx_tx_queue_prio(struct tc956xmac_priv *priv, + u8 *mbx_buff, u8 *ack_buff) +{ + u32 queue; + u32 prio; + + if (priv == NULL || mbx_buff == NULL || ack_buff == NULL) { + KPRINT_DEBUG1("NULL pointer error\n"); + return NACK; + } + + if (mbx_buff[0] != OPCODE_MBX_SET_TX_Q_PRIOR) + return NACK; + + if (mbx_buff[1] != SIZE_MBX_SET_TX_Q_PRIOR) + return NACK; + + memcpy(&prio, &mbx_buff[2], sizeof(prio)); + memcpy(&queue, &mbx_buff[6], sizeof(queue)); + + /* Call core API to set the register */ + tc956xmac_tx_queue_prio(priv, priv->hw, prio, queue); + + + /* Clear the ACK buffer as there is no ACK message */ + ack_buff[0] = OPCODE_MBX_ACK_MSG; /* set ACK opcode */ + memset(&ack_buff[1], 0, MBX_MSG_SIZE-1); + + /* return ACK as all steps are successfull */ + return ACK; + +} + +/** + * tc956x_mbx_vf_get_link_status + * + * \brief API to send the pf link status + * + * \details This function is used to send the pf link status + * on VF request using mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] mbx_buff - Pointer to message + * \param[out] ack_msg - Pointer to output ack + * + * \return ACK/NACK + */ +static int tc956x_mbx_vf_get_link_status(struct tc956xmac_priv *priv, + u8 *mbx_buff, u8 *ack_buff) +{ + if (priv == NULL || mbx_buff == NULL || ack_buff == NULL) { + KPRINT_DEBUG1("NULL pointer error\n"); + return NACK; + } + + if (mbx_buff[0] != OPCODE_MBX_VF_GET_LINK_STATUS) + return NACK; + + if (mbx_buff[1] != 0) + return NACK; + + ack_buff[0] = OPCODE_MBX_ACK_MSG; /* set ACK opcode */ + ack_buff[1] = SIZE_MBX_PHY_LINK; /* set size */ + + /* Copy link, speed and duplex values */ + memcpy(&ack_buff[2], &priv->link, SIZE_MBX_PHY_LINK); + + /* return ACK as all steps are successfull */ + return ACK; +} + +/** + * tc956xmac_pf_ioctl_interface + * + * \brief API to process ioctl requests + * + * \details This function is used to process ioctl requests + * on VF request using mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] mbx_buff - Pointer to message + * \param[out] ack_msg - Pointer to output ack + * + * \return ACK/NACK + */ +static int tc956xmac_pf_ioctl_interface(struct tc956xmac_priv *priv, + u8 *mbx, u8 *ack_buff, u8 vf_no) +{ + u32 val; + u32 addr; + u32 bar_num; + unsigned long flags; + struct hwtstamp_config *config = &priv->tstamp_config; + + DBGPR_FUNC(priv->device, "-->%s\n", __func__); + + if (priv == NULL || mbx == NULL || ack_buff == NULL) { + KPRINT_DEBUG1("NULL pointer error\n"); + return NACK; + } + + switch (mbx[2]) { + case TC956XMAC_SET_CBS_1: + case TC956XMAC_SET_CBS_2: + { + static u8 msg_seq[TC956X_TOTAL_VFS], mbx_loc[TC956X_TOTAL_VFS][MBX_TOT_SIZE * TC956X_TWO]; + static struct tc956xmac_ioctl_cbs_cfg cbs; + + vf_no -= TC956X_ONE; + if (mbx[2] == TC956XMAC_SET_CBS_1) { + + memset(&mbx_loc[vf_no][0], 0, MBX_TOT_SIZE * TC956X_TWO); + + memcpy(&mbx_loc[vf_no][0], &mbx[4], SIZE_MBX_SET_GET_CBS_1); + msg_seq[vf_no] = TC956X_ONE << TC956X_ZERO; + + } else if (mbx[2] == TC956XMAC_SET_CBS_2) { + memcpy(&mbx_loc[vf_no][SIZE_MBX_SET_GET_CBS_1], &mbx[4], SIZE_MBX_SET_GET_CBS_2); + msg_seq[vf_no] |= TC956X_ONE << TC956X_ONE; + + if (msg_seq[vf_no] == TC956X_THREE) { + + msg_seq[vf_no] = TC956X_ZERO; + + memset(&cbs, 0, sizeof(cbs)); + + cbs.queue_idx = mbx[3]; + + memcpy(&cbs.speed100cfg.send_slope, &mbx_loc[vf_no][0], sizeof(cbs.speed100cfg.send_slope)); + memcpy(&cbs.speed100cfg.idle_slope, &mbx_loc[vf_no][4], sizeof(cbs.speed100cfg.idle_slope)); + memcpy(&cbs.speed100cfg.high_credit, &mbx_loc[vf_no][8], sizeof(cbs.speed100cfg.high_credit)); + memcpy(&cbs.speed100cfg.low_credit, &mbx_loc[vf_no][12], sizeof(cbs.speed100cfg.low_credit)); + memcpy(&cbs.speed100cfg.percentage, &mbx_loc[vf_no][16], sizeof(cbs.speed100cfg.percentage)); + + memcpy(&cbs.speed1000cfg.send_slope, &mbx_loc[vf_no][20], sizeof(cbs.speed1000cfg.send_slope)); + memcpy(&cbs.speed1000cfg.idle_slope, &mbx_loc[vf_no][24], sizeof(cbs.speed1000cfg.idle_slope)); + memcpy(&cbs.speed1000cfg.high_credit, &mbx_loc[vf_no][28], sizeof(cbs.speed1000cfg.high_credit)); + memcpy(&cbs.speed1000cfg.low_credit, &mbx_loc[vf_no][32], sizeof(cbs.speed1000cfg.low_credit)); + memcpy(&cbs.speed1000cfg.percentage, &mbx_loc[vf_no][36], sizeof(cbs.speed1000cfg.percentage)); + + memcpy(&cbs.speed10000cfg.send_slope, &mbx_loc[vf_no][40], sizeof(cbs.speed10000cfg.send_slope)); + memcpy(&cbs.speed10000cfg.idle_slope, &mbx_loc[vf_no][44], sizeof(cbs.speed10000cfg.idle_slope)); + memcpy(&cbs.speed10000cfg.high_credit, &mbx_loc[vf_no][48], sizeof(cbs.speed10000cfg.high_credit)); + memcpy(&cbs.speed10000cfg.low_credit, &mbx_loc[vf_no][52], sizeof(cbs.speed10000cfg.low_credit)); + memcpy(&cbs.speed10000cfg.percentage, &mbx_loc[vf_no][56], sizeof(cbs.speed10000cfg.percentage)); + + memcpy(&cbs.speed5000cfg.send_slope, &mbx_loc[vf_no][60], sizeof(cbs.speed5000cfg.send_slope)); + memcpy(&cbs.speed5000cfg.idle_slope, &mbx_loc[vf_no][64], sizeof(cbs.speed5000cfg.idle_slope)); + memcpy(&cbs.speed5000cfg.high_credit, &mbx_loc[vf_no][68], sizeof(cbs.speed5000cfg.high_credit)); + memcpy(&cbs.speed5000cfg.low_credit, &mbx_loc[vf_no][72], sizeof(cbs.speed5000cfg.low_credit)); + memcpy(&cbs.speed5000cfg.percentage, &mbx_loc[vf_no][76], sizeof(cbs.speed5000cfg.percentage)); + + memcpy(&cbs.speed2500cfg.send_slope, &mbx_loc[vf_no][80], sizeof(cbs.speed2500cfg.send_slope)); + memcpy(&cbs.speed2500cfg.idle_slope, &mbx_loc[vf_no][84], sizeof(cbs.speed2500cfg.idle_slope)); + memcpy(&cbs.speed2500cfg.high_credit, &mbx_loc[vf_no][88], sizeof(cbs.speed2500cfg.high_credit)); + memcpy(&cbs.speed2500cfg.low_credit, &mbx_loc[vf_no][92], sizeof(cbs.speed2500cfg.low_credit)); + memcpy(&cbs.speed2500cfg.percentage, &mbx_loc[vf_no][96], sizeof(cbs.speed2500cfg.percentage)); + + tc956xmac_ioctl_set_cbs(priv, &cbs); + } + } + + /* Clear the ACK buffer as there is no ACK message */ + ack_buff[0] = OPCODE_MBX_ACK_MSG; /* set ACK opcode */ + memset(&ack_buff[1], 0, MBX_MSG_SIZE-1); + break; + } + case TC956XMAC_GET_CBS_1: + case TC956XMAC_GET_CBS_2: + { + static u8 mbx_loc[TC956X_TOTAL_VFS][MBX_TOT_SIZE * TC956X_TWO]; + struct tc956xmac_ioctl_cbs_cfg cbs; + int ret = 0; + + vf_no -= TC956X_ONE; + if (mbx[2] == TC956XMAC_GET_CBS_1) { + memset(&mbx_loc[vf_no][0], 0, sizeof(struct tc956xmac_ioctl_cbs_cfg)); + cbs.queue_idx = mbx[3]; + ret = tc956xmac_ioctl_get_cbs(priv, &cbs); + memcpy(&mbx_loc[vf_no][0], (u8 *)&cbs.speed100cfg, sizeof(cbs) - TC956X_EIGHT); + + ack_buff[0] = OPCODE_MBX_ACK_MSG; /* set ACK opcode */ + ack_buff[1] = SIZE_MBX_SET_GET_CBS_1; /* set size */ + + memcpy(&ack_buff[2], &mbx_loc[vf_no][0], SIZE_MBX_SET_GET_CBS_1); + + } else if (mbx[2] == TC956XMAC_GET_CBS_2) { + + ack_buff[0] = OPCODE_MBX_ACK_MSG; /* set ACK opcode */ + ack_buff[1] = SIZE_MBX_SET_GET_CBS_2; /* set size */ + memcpy(&ack_buff[2], &mbx_loc[vf_no][SIZE_MBX_SET_GET_CBS_1], SIZE_MBX_SET_GET_CBS_2); + + } + + break; + } + case TC956XMAC_SET_EST_1: + case TC956XMAC_SET_EST_2: + case TC956XMAC_SET_EST_3: + case TC956XMAC_SET_EST_4: + case TC956XMAC_SET_EST_5: + case TC956XMAC_SET_EST_6: + case TC956XMAC_SET_EST_7: + case TC956XMAC_SET_EST_8: + case TC956XMAC_SET_EST_9: + case TC956XMAC_SET_EST_10: + { + static u16 total_size, msg_size, offset = 1; + static u8 mbx_loc[MBX_TOT_SIZE * TC956X_TEN]; + static struct tc956xmac_ioctl_est_cfg *est; + + if (vf_no != TC956XMAC_VF_ADAS) + return NACK; + + vf_no -= TC956X_ONE; + + if (mbx[2] == TC956XMAC_SET_EST_1) { + est = kzalloc(sizeof(*est), GFP_ATOMIC); + if (!est) + return -ENOMEM; + + memset(&mbx_loc[0], 0, MBX_TOT_SIZE * TC956X_TEN); + memcpy(&mbx_loc[0], &mbx[3], SIZE_MBX_SET_GET_EST_1); + + memset(est, 0, sizeof(struct tc956xmac_est)); + memcpy(&est->enabled, &mbx_loc[0], sizeof(est->enabled)); + memcpy(&est->btr_offset[0], &mbx_loc[4], sizeof(est->btr_offset)); + memcpy(&est->ctr[0], &mbx_loc[12], sizeof(est->ctr)); + memcpy(&est->ter, &mbx_loc[20], sizeof(est->ter)); + memcpy(&est->gcl_size, &mbx_loc[24], sizeof(est->gcl_size)); + + total_size = est->gcl_size * sizeof(*est->gcl); + msg_size = mbx[1] - EST_FIX_MSG_LEN; + } else { + memcpy(&mbx_loc[offset * SIZE_MBX_SET_GET_EST_1], &mbx[3], SIZE_MBX_SET_GET_EST_1); + msg_size += mbx[1]; + offset++; + } + if (msg_size == total_size) { + memcpy(&est->gcl[0], &mbx_loc[28], est->gcl_size * sizeof(*est->gcl)); + tc956xmac_ioctl_set_est(priv, est); + msg_size = 0; + total_size = 0; + offset = 1; + } + /* Clear the ACK buffer as there is no ACK message */ + ack_buff[0] = OPCODE_MBX_ACK_MSG; /* set ACK opcode */ + memset(&ack_buff[1], 0, MBX_MSG_SIZE-1); + break; + } + case TC956XMAC_GET_EST_1: + case TC956XMAC_GET_EST_2: + case TC956XMAC_GET_EST_3: + case TC956XMAC_GET_EST_4: + case TC956XMAC_GET_EST_5: + case TC956XMAC_GET_EST_6: + case TC956XMAC_GET_EST_7: + case TC956XMAC_GET_EST_8: + case TC956XMAC_GET_EST_9: + case TC956XMAC_GET_EST_10: + { + static u16 gcl_size, msg_size, toatl_msg_size, offset; + static u8 mbx_loc[MBX_TOT_SIZE * TC956X_TEN]; + static struct tc956xmac_ioctl_est_cfg *est; + + if (vf_no != TC956XMAC_VF_ADAS) + return NACK; + + vf_no -= TC956X_ONE; + + if (mbx[2] == TC956XMAC_GET_EST_1) { + est = kzalloc(sizeof(*est), GFP_ATOMIC); + if (!est) + return -ENOMEM; + tc956xmac_ioctl_get_est(priv, est); + + memcpy(&mbx_loc[0], (u8 *)&est->enabled, sizeof(est->enabled)); + memcpy(&mbx_loc[4], (u8 *)&est->estwid, sizeof(est->estwid)); + memcpy(&mbx_loc[8], (u8 *)&est->estdep, sizeof(est->estdep)); + memcpy(&mbx_loc[12], (u8 *)&est->btr_offset[0], sizeof(est->btr_offset)); + memcpy(&mbx_loc[20], (u8 *)&est->ctr[0], sizeof(est->ctr)); + memcpy(&mbx_loc[28], (u8 *)&est->ter, sizeof(est->ter)); + memcpy(&mbx_loc[32], (u8 *)&est->gcl_size, sizeof(est->gcl_size)); + memcpy(&mbx_loc[36], (u8 *)&est->gcl, (est->gcl_size * sizeof(*est->gcl))); + + gcl_size = est->gcl_size * sizeof(*est->gcl); + toatl_msg_size = gcl_size + EST_FIX_MSG_LEN + 8; + msg_size = toatl_msg_size >= SIZE_MBX_SET_GET_EST_1 ? SIZE_MBX_SET_GET_EST_1 : toatl_msg_size; + offset = 0; + } else { + offset += msg_size; + msg_size = (toatl_msg_size - offset) >= SIZE_MBX_SET_GET_EST_1 ? SIZE_MBX_SET_GET_EST_1 : (toatl_msg_size - offset); + } + + if (toatl_msg_size == (offset + msg_size)) { + kfree(est); + } + + ack_buff[0] = OPCODE_MBX_ACK_MSG; /* set ACK opcode */ + ack_buff[1] = msg_size; /* set ACK size */ + memcpy(&ack_buff[2], &mbx_loc[offset], msg_size); + + break; + } + case TC956XMAC_SET_RXP_1: + case TC956XMAC_SET_RXP_2: + case TC956XMAC_SET_RXP_3: + case TC956XMAC_SET_RXP_4: + case TC956XMAC_SET_RXP_5: + case TC956XMAC_SET_RXP_6: + case TC956XMAC_SET_RXP_7: + case TC956XMAC_SET_RXP_8: + case TC956XMAC_SET_RXP_9: + case TC956XMAC_SET_RXP_10: + case TC956XMAC_SET_RXP_11: + case TC956XMAC_SET_RXP_12: + case TC956XMAC_SET_RXP_13: + case TC956XMAC_SET_RXP_14: + case TC956XMAC_SET_RXP_15: + case TC956XMAC_SET_RXP_16: + case TC956XMAC_SET_RXP_17: + case TC956XMAC_SET_RXP_18: + case TC956XMAC_SET_RXP_19: + case TC956XMAC_SET_RXP_20: + case TC956XMAC_SET_RXP_21: + case TC956XMAC_SET_RXP_22: + case TC956XMAC_SET_RXP_23: + case TC956XMAC_SET_RXP_24: + case TC956XMAC_SET_RXP_25: + case TC956XMAC_SET_RXP_26: + case TC956XMAC_SET_RXP_27: + case TC956XMAC_SET_RXP_28: + case TC956XMAC_SET_RXP_29: + case TC956XMAC_SET_RXP_30: + case TC956XMAC_SET_RXP_31: + case TC956XMAC_SET_RXP_32: + case TC956XMAC_SET_RXP_33: + case TC956XMAC_SET_RXP_34: + case TC956XMAC_SET_RXP_35: + case TC956XMAC_SET_RXP_36: + case TC956XMAC_SET_RXP_37: + { + static u16 total_size, msg_size, offset = 1; + static u8 *mbx_loc; + static struct tc956xmac_ioctl_rxp_cfg *rxp; + + if (mbx[2] == TC956XMAC_SET_RXP_1) { + rxp = kzalloc(sizeof(*rxp), GFP_ATOMIC); + if (!rxp) + return -ENOMEM; + + mbx_loc = kzalloc(sizeof(*rxp), GFP_ATOMIC); + if (!mbx_loc) { + kfree(rxp); + return -ENOMEM; + } + + memset(&mbx_loc[0], 0, sizeof(*rxp)); + memcpy(&mbx_loc[0], &mbx[3], SIZE_MBX_SET_GET_RXP_1); + + memset(rxp, 0, sizeof(struct tc956xmac_ioctl_rxp_cfg)); + memcpy(&rxp->frpes, &mbx_loc[0], sizeof(rxp->frpes)); + memcpy(&rxp->enabled, &mbx_loc[4], sizeof(rxp->enabled)); + memcpy(&rxp->nve, &mbx_loc[8], sizeof(rxp->nve)); + memcpy(&rxp->npe, &mbx_loc[12], sizeof(rxp->npe)); + + total_size = rxp->nve * sizeof(*rxp->entries); + msg_size = mbx[1] - RXP_FIX_MSG_LEN; + } else { + memcpy(&mbx_loc[offset*SIZE_MBX_SET_GET_RXP_1], &mbx[3], SIZE_MBX_SET_GET_RXP_1); + msg_size += mbx[1]; + offset++; + } + + if (msg_size == total_size) { + memcpy(&rxp->entries[0], &mbx_loc[16], total_size); + tc956xmac_ioctl_set_rxp(priv, rxp); + msg_size = 0; + total_size = 0; + offset = 1; + kfree(mbx_loc); + } + /* Clear the ACK buffer as there is no ACK message */ + ack_buff[0] = OPCODE_MBX_ACK_MSG; /* set ACK opcode */ + memset(&ack_buff[1], 0, MBX_MSG_SIZE-1); + break; + } + case TC956XMAC_GET_RXP_1: + case TC956XMAC_GET_RXP_2: + case TC956XMAC_GET_RXP_3: + case TC956XMAC_GET_RXP_4: + case TC956XMAC_GET_RXP_5: + case TC956XMAC_GET_RXP_6: + case TC956XMAC_GET_RXP_7: + case TC956XMAC_GET_RXP_8: + case TC956XMAC_GET_RXP_9: + case TC956XMAC_GET_RXP_10: + case TC956XMAC_GET_RXP_11: + case TC956XMAC_GET_RXP_12: + case TC956XMAC_GET_RXP_13: + case TC956XMAC_GET_RXP_14: + case TC956XMAC_GET_RXP_15: + case TC956XMAC_GET_RXP_16: + case TC956XMAC_GET_RXP_17: + case TC956XMAC_GET_RXP_18: + case TC956XMAC_GET_RXP_19: + case TC956XMAC_GET_RXP_20: + case TC956XMAC_GET_RXP_21: + case TC956XMAC_GET_RXP_22: + case TC956XMAC_GET_RXP_23: + case TC956XMAC_GET_RXP_24: + case TC956XMAC_GET_RXP_25: + case TC956XMAC_GET_RXP_26: + case TC956XMAC_GET_RXP_27: + case TC956XMAC_GET_RXP_28: + case TC956XMAC_GET_RXP_29: + case TC956XMAC_GET_RXP_30: + case TC956XMAC_GET_RXP_31: + case TC956XMAC_GET_RXP_32: + case TC956XMAC_GET_RXP_33: + case TC956XMAC_GET_RXP_34: + case TC956XMAC_GET_RXP_35: + case TC956XMAC_GET_RXP_36: + case TC956XMAC_GET_RXP_37: + { + static u16 rxp_size, msg_size, toatl_msg_size, offset; + static u8 *mbx_loc; + static struct tc956xmac_ioctl_rxp_cfg *rxp; + + if (mbx[2] == TC956XMAC_GET_RXP_1) { + rxp = kzalloc(sizeof(*rxp), GFP_ATOMIC); + if (!rxp) + return -ENOMEM; + + mbx_loc = kzalloc(sizeof(*rxp), GFP_ATOMIC); + if (!mbx_loc) { + kfree(rxp); + return -ENOMEM; + } + tc956xmac_ioctl_get_rxp(priv, rxp); + + memcpy(&mbx_loc[0], (u8 *)&rxp->frpes, sizeof(rxp->frpes)); + memcpy(&mbx_loc[4], (u8 *)&rxp->enabled, sizeof(rxp->enabled)); + memcpy(&mbx_loc[8], (u8 *)&rxp->nve, sizeof(rxp->nve)); + memcpy(&mbx_loc[12], (u8 *)&rxp->npe, sizeof(rxp->npe)); + memcpy(&mbx_loc[16], (u8 *)&rxp->entries[0], (rxp->nve * sizeof(*rxp->entries))); + + rxp_size = rxp->nve * sizeof(*rxp->entries); + toatl_msg_size = rxp_size + RXP_FIX_MSG_LEN; + msg_size = toatl_msg_size >= SIZE_MBX_SET_GET_RXP_1 ? SIZE_MBX_SET_GET_RXP_1 : toatl_msg_size; + + offset = 0; + } else { + offset += msg_size; + msg_size = (toatl_msg_size - offset) >= SIZE_MBX_SET_GET_RXP_1 ? SIZE_MBX_SET_GET_RXP_1 : (toatl_msg_size - offset); + } + + ack_buff[0] = OPCODE_MBX_ACK_MSG; /* set ACK opcode */ + ack_buff[1] = msg_size; /* set ACK size */ + memcpy(&ack_buff[2], &mbx_loc[offset], msg_size); + + if (toatl_msg_size == (offset + msg_size)) { + kfree(rxp); + kfree(mbx_loc); + } + + break; + } + case TC956XMAC_SET_FPE_1: + { + struct tc956xmac_ioctl_fpe_cfg fpe; + + if (vf_no != TC956XMAC_VF_ADAS) + return NACK; + + vf_no -= TC956X_ONE; + + memcpy(&fpe.enabled, &mbx[3], sizeof(fpe.enabled)); + memcpy(&fpe.pec, &mbx[7], sizeof(fpe.pec)); + memcpy(&fpe.afsz, &mbx[11], sizeof(fpe.afsz)); + memcpy(&fpe.RA_time, &mbx[15], sizeof(fpe.RA_time)); + memcpy(&fpe.HA_time, &mbx[19], sizeof(fpe.HA_time)); + + tc956xmac_ioctl_set_fpe(priv, &fpe); + + /* Clear the ACK buffer as there is no ACK message */ + ack_buff[0] = OPCODE_MBX_ACK_MSG; /* set ACK opcode */ + memset(&ack_buff[1], 0, MBX_MSG_SIZE-1); + break; + } + case TC956XMAC_GET_FPE_1: + { + struct tc956xmac_ioctl_fpe_cfg fpe; + + if (vf_no != TC956XMAC_VF_ADAS) + return NACK; + + vf_no -= TC956X_ONE; + + tc956xmac_ioctl_get_fpe(priv, &fpe); + + /* Clear the ACK buffer as there is no ACK message */ + ack_buff[0] = OPCODE_MBX_ACK_MSG; /* set ACK opcode */ + ack_buff[1] = SIZE_MBX_SET_GET_FPE_1; + memcpy(&ack_buff[2], (u8 *)&fpe.enabled, sizeof(fpe.enabled)); + memcpy(&ack_buff[6], (u8 *)&fpe.pec, sizeof(fpe.pec)); + memcpy(&ack_buff[10], (u8 *)&fpe.afsz, sizeof(fpe.afsz)); + memcpy(&ack_buff[14], (u8 *)&fpe.RA_time, sizeof(fpe.RA_time)); + memcpy(&ack_buff[18], (u8 *)&fpe.HA_time, sizeof(fpe.HA_time)); + break; + } + case TC956XMAC_GET_SPEED: + ack_buff[0] = OPCODE_MBX_ACK_MSG; /* set ACK opcode */ + ack_buff[1] = sizeof(priv->speed); /* set size */ + memcpy(&ack_buff[2], (u8 *)&priv->speed, + sizeof(priv->speed)); + break; + + case TC956XMAC_REG_WR: + memcpy(&bar_num, &mbx[3], sizeof(bar_num)); + memcpy(&addr, &mbx[7], sizeof(addr)); + memcpy(&val, &mbx[11], sizeof(val)); + + if (bar_num == 4) + writel(val, (void __iomem *)(priv->dev->base_addr + addr)); + else if (bar_num == 2)/*SRAM bar number 2*/ + writel(val, (void __iomem *)(priv->tc956x_SRAM_pci_base_addr + addr)); + ack_buff[0] = OPCODE_MBX_ACK_MSG; /* set ACK opcode */ + memset(&ack_buff[1], 0, MBX_MSG_SIZE-1); + break; + case OPCODE_MBX_VF_GET_MII_PHY: + ack_buff[0] = OPCODE_MBX_ACK_MSG; + ack_buff[1] = sizeof(priv->plat->phy_addr); + memcpy(&ack_buff[2], (u8 *)&priv->plat->phy_addr, + sizeof(priv->plat->phy_addr)); + break; + case OPCODE_MBX_VF_GET_MII_REG_1: + vf_no -= TC956X_ONE; + memcpy(&priv->mbx_wq_param.rq.ifr_ifru.ifru_data, &mbx[3], 6); + memcpy(&priv->mbx_wq_param.rq.ifr_ifrn.ifrn_name, &mbx[9], 16); + + spin_lock_irqsave(&priv->wq_lock, flags); + priv->mbx_wq_param.fn_id = SCH_WQ_PHY_REG_RD; + priv->mbx_wq_param.val_out[vf_no] = 0; + priv->mbx_wq_param.vf_no = vf_no; + + tc956xmac_service_mbx_event_schedule(priv); + spin_unlock_irqrestore(&priv->wq_lock, flags); + + ack_buff[0] = OPCODE_MBX_ACK_MSG; /* set ACK opcode */ + memset(&ack_buff[1], 0, MBX_MSG_SIZE-1); + break; + case OPCODE_MBX_VF_GET_MII_REG_2: + vf_no -= TC956X_ONE; + ack_buff[0] = OPCODE_MBX_ACK_MSG; + ack_buff[1] = sizeof(priv->mbx_wq_param.val_out[vf_no]); + memcpy(&ack_buff[2], (u8 *)&priv->mbx_wq_param.val_out[vf_no], sizeof(priv->mbx_wq_param.val_out[vf_no])); + break; + case OPCODE_MBX_VF_GET_HW_STMP: + ack_buff[0] = OPCODE_MBX_ACK_MSG; + ack_buff[1] = sizeof(*config); + memcpy(&ack_buff[2], (u8 *)config, sizeof(*config)); + break; + } + return ACK; +} + +/** + * tc956xmac_pf_ethtool_interface + * + * \brief API to process ethtool requests + * + * \details This function is used to process ethtool requests + * on VF request using mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] mbx_buff - Pointer to message + * \param[out] ack_msg - Pointer to output ack + * + * \return ACK/NACK + */ +static int tc956xmac_pf_ethtool_interface(struct tc956xmac_priv *priv, struct net_device *netdev, + u8 *mbx, u8 *ack_buff) +{ + struct ethtool_eee edata; + unsigned long flags; + + if (priv == NULL || mbx == NULL || netdev == NULL || ack_buff == NULL) { + KPRINT_DEBUG1("NULL pointer error\n"); + return NACK; + } + + switch (mbx[2]) { + case TC956XMAC_GET_PAUSE_PARAM: + spin_lock_irqsave(&priv->wq_lock, flags); + priv->mbx_wq_param.fn_id = SCH_WQ_GET_PAUSE_PARAM; + tc956xmac_service_mbx_event_schedule(priv); + spin_unlock_irqrestore(&priv->wq_lock, flags); + + ack_buff[0] = OPCODE_MBX_ACK_MSG; /* set ACK opcode */ + memset(&ack_buff[1], 0, MBX_MSG_SIZE-1); + break; + case TC956XMAC_GET_PAUSE_PARAM_2: + ack_buff[0] = OPCODE_MBX_ACK_MSG; + ack_buff[1] = sizeof(struct ethtool_pauseparam); + memcpy(&ack_buff[2], (u8 *)&priv->mbx_wq_param.pause, + sizeof(struct ethtool_pauseparam)); + break; + case TC956XMAC_GET_EEE: + tc956xmac_ethtool_op_get_eee(netdev, &edata); + ack_buff[0] = OPCODE_MBX_ACK_MSG; /* set ACK opcode */ + ack_buff[1] = sizeof(struct ethtool_eee); /* set size */ + memcpy(&ack_buff[2], (u8 *)&edata, + sizeof(struct ethtool_eee)); + break; + + default: + break; + } + + return ACK; +} + +/** + * tc956xmac_pf_set_mac_filter + * + * \brief API to add the mac address filter value + * + * \details This function is used to add the mac address filter value + * on VF request using mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] dev - Pointer to device + * \param[in] mbx_buff - Pointer to message + * \param[in] vf - VF no + * \param[out] ack_msg - Pointer to output ack + * + * \return ACK/NACK + */ +static int tc956xmac_pf_set_mac_filter(struct tc956xmac_priv *priv, struct net_device *dev, + u8 *mbx_buff, u8 *ack_buff, u8 vf) +{ + u8 mac[SIZE_MBX_VF_MAC]; + int ret; +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + unsigned long flags; +#endif + + if (priv == NULL || mbx_buff == NULL || dev == NULL || ack_buff == NULL) { + KPRINT_DEBUG1("NULL pointer error\n"); + return NACK; + } + + if (mbx_buff[0] != OPCODE_MBX_VF_ADD_MAC) + return NACK; + + if (mbx_buff[1] != SIZE_MBX_VF_MAC) + return NACK; + + memcpy(&mac[0], &mbx_buff[2], SIZE_MBX_VF_MAC); + /* Call core API to set the register */ +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_lock_irqsave(&priv->spn_lock.mac_filter, flags); +#endif + ret = tc956x_pf_set_mac_filter(dev, vf, &mac[0]); + +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_unlock_irqrestore(&priv->spn_lock.mac_filter, flags); +#endif + + if (ret) + return NACK; + + /* Clear the ACK buffer as there is no ACK message */ + ack_buff[0] = OPCODE_MBX_ACK_MSG; /* set ACK opcode */ + memset(&ack_buff[1], 0, MBX_MSG_SIZE-1); + + /* return ACK as all steps are successfull */ + return ACK; +} + +/** + * tc956xmac_pf_del_mac_filter + * + * \brief API to delete the mac address filter value + * + * \details This function is used to delete the mac address filter value + * on VF request using mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] dev - Pointer to device + * \param[in] mbx_buff - Pointer to message + * \param[in] vf - VF no + * \param[out] ack_msg - Pointer to output ack + * + * \return ACK/NACK + */ +static int tc956xmac_pf_del_mac_filter(struct tc956xmac_priv *priv, struct net_device *dev, + u8 *mbx_buff, u8 *ack_buff, u8 vf) +{ + + u8 mac[SIZE_MBX_VF_MAC]; +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + unsigned long flags; +#endif + + if (priv == NULL || mbx_buff == NULL || dev == NULL || ack_buff == NULL) { + KPRINT_DEBUG1("NULL pointer error\n"); + return NACK; + } + + if (mbx_buff[0] != OPCODE_MBX_VF_DELETE_MAC) + return NACK; + + if (mbx_buff[1] != SIZE_MBX_VF_MAC) + return NACK; + + memcpy(&mac[0], &mbx_buff[2], SIZE_MBX_VF_MAC); +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_lock_irqsave(&priv->spn_lock.mac_filter, flags); +#endif + /* Call core API to set the register */ + tc956x_pf_del_mac_filter(dev, vf, &mac[0]); + +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_unlock_irqrestore(&priv->spn_lock.mac_filter, flags); +#endif + + /* Clear the ACK buffer as there is no ACK message */ + ack_buff[0] = OPCODE_MBX_ACK_MSG; /* set ACK opcode */ + memset(&ack_buff[1], 0, MBX_MSG_SIZE-1); + + /* return ACK as all steps are successfull */ + return ACK; +} + +/** + * tc956xmac_pf_set_vlan_filter + * + * \brief API to add the vlan ids filter value + * + * \details This function is used to add the vlan filter value + * on VF request using mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] dev - Pointer to device + * \param[in] mbx_buff - Pointer to message + * \param[in] vf - VF no + * \param[out] ack_msg - Pointer to output ack + * + * \return ACK/NACK + */ +static int tc956xmac_pf_set_vlan_filter(struct tc956xmac_priv *priv, struct net_device *dev, + u8 *mbx_buff, u8 *ack_buff, u8 vf) +{ + u16 vid; +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + unsigned long flags; +#endif + if (priv == NULL || mbx_buff == NULL || dev == NULL || ack_buff == NULL) { + KPRINT_DEBUG1("NULL pointer error\n"); + return NACK; + } + + if (mbx_buff[0] != OPCODE_MBX_VF_ADD_VLAN) + return NACK; + + if (mbx_buff[1] != SIZE_MBX_VF_VLAN) + return NACK; + + memcpy(&vid, &mbx_buff[2], SIZE_MBX_VF_VLAN); +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_lock_irqsave(&priv->spn_lock.vlan_filter, flags); +#endif + + /* Call core API to set the register */ + tc956x_pf_set_vlan_filter(dev, vf, vid); + +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_unlock_irqrestore(&priv->spn_lock.vlan_filter, flags); +#endif + + /* Clear the ACK buffer as there is no ACK message */ + ack_buff[0] = OPCODE_MBX_ACK_MSG; /* set ACK opcode */ + memset(&ack_buff[1], 0, MBX_MSG_SIZE-1); + + /* return ACK as all steps are successfull */ + return ACK; + +} + +/** + * tc956xmac_pf_set_vlan_filter + * + * \brief API to add the vlan ids filter value + * + * \details This function is used to add the vlan filter value + * on VF request using mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] dev - Pointer to device + * \param[in] mbx_buff - Pointer to message + * \param[in] vf - VF no + * \param[out] ack_msg - Pointer to output ack + * + * \return ACK/NACK + */ +static int tc956xmac_pf_del_vlan_filter(struct tc956xmac_priv *priv, struct net_device *dev, + u8 *mbx_buff, u8 *ack_buff, u8 vf) +{ + u16 vid; +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + unsigned long flags; +#endif + + if (priv == NULL || mbx_buff == NULL || dev == NULL || ack_buff == NULL) { + KPRINT_DEBUG1("NULL pointer error\n"); + return NACK; + } + + if (mbx_buff[0] != OPCODE_MBX_VF_DELETE_VLAN) + return NACK; + + if (mbx_buff[1] != SIZE_MBX_VF_VLAN) + return NACK; + + memcpy(&vid, &mbx_buff[2], SIZE_MBX_VF_VLAN); +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_lock_irqsave(&priv->spn_lock.vlan_filter, flags); +#endif + /* Call core API to set the register */ + tc956x_pf_del_vlan_filter(dev, vf, vid); + +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_unlock_irqrestore(&priv->spn_lock.vlan_filter, flags); +#endif + /* Clear the ACK buffer as there is no ACK message */ + ack_buff[0] = OPCODE_MBX_ACK_MSG; /* set ACK opcode */ + memset(&ack_buff[1], 0, MBX_MSG_SIZE-1); + + /* return ACK as all steps are successfull */ + return ACK; + +} +/** + * tc956x_mbx_rx_crc + * + * \brief API to send Rx CRC state to VFs + * + * \details This function is used to send Rx CRC states to VF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * + * \return None + */ +static void tc956x_mbx_rx_crc(struct tc956xmac_priv *priv) +{ + /* Prepare mailbox message and call mailbox API for posting + * and getting the ACK + */ + u8 mbx[MAX_NO_OF_VFS][MBX_TOT_SIZE]; + int ret, i; + enum mbx_msg_fns msg_dst; + + if (priv == NULL) { + KPRINT_DEBUG1("NULL pointer error"); + return; + } + + for (i = 0; i < MAX_NO_OF_VFS; i++) { + + mbx[i][0] = OPCODE_MBX_RX_CRC; /* opcode */ + mbx[i][1] = SIZE_MBX_RX_CRC; /* size */ + + /* Copy Rx crc pad values */ + memcpy(&mbx[i][2], &priv->rx_crc_pad_state, SIZE_MBX_RX_CRC); + } + + /* Send data to all VFs */ + for (i = vf0; i <= vf2; i++) { + if (priv->clear_to_send[i-vf0] == VF_UP) { + + msg_dst = (enum mbx_msg_fns) i; + ret = tc956xmac_mbx_write(priv, &mbx[i-vf0][0], msg_dst, + &priv->fn_id_info); + + /* Validation of successfull message posting can be done + * by reading the mbx buffer for ACK opcode (0xFE) + */ + + if (ret > 0) + KPRINT_DEBUG1( + "mailbox write with ACK or NACK %d msgbuff %x %x", ret, mbx[i-vf0][0], mbx[i-vf0][4]); + else + KPRINT_DEBUG1("mailbox write failed"); + } else + KPRINT_DEBUG1("VF %d not up", i-vf0); + } +} + +/** + * tc956x_mbx_rx_csum + * + * \brief API to send Rx checksum state to VFs + * + * \details This function is used to send Rx Checksum states to VF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * + * \return None + */ +static void tc956x_mbx_rx_csum(struct tc956xmac_priv *priv) +{ + /* Prepare mailbox message and call mailbox API for posting + * and getting the ACK + */ + u8 mbx[MAX_NO_OF_VFS][MBX_TOT_SIZE]; + int ret, i; + enum mbx_msg_fns msg_dst; + + if (priv == NULL) { + KPRINT_DEBUG1("NULL pointer error"); + return; + } + + for (i = 0; i < MAX_NO_OF_VFS; i++) { + mbx[i][0] = OPCODE_MBX_RX_CSUM; /* opcode */ + mbx[i][1] = SIZE_MBX_RX_CSUM; /* size */ + + /* Copy link, speed and duplex values */ + memcpy(&mbx[i][2], &priv->rx_csum_state, SIZE_MBX_RX_CSUM); + } + + /* Send data to all VFs */ + for (i = vf0; i <= vf2; i++) { + if (priv->clear_to_send[i-vf0] == VF_UP) { + msg_dst = (enum mbx_msg_fns) i; + ret = tc956xmac_mbx_write(priv, &mbx[i-vf0][0], msg_dst, + &priv->fn_id_info); + + /* Validation of successfull message posting can be done + * by reading the mbx buffer for ACK opcode (0xFE) + */ + if (ret > 0) + KPRINT_DEBUG1( + "mailbox write with ACK or NACK %d msgbuff %x %x\n", ret, mbx[i-vf0][0], mbx[i-vf0][4]); + else + KPRINT_DEBUG1("mailbox write failed"); + } else + KPRINT_DEBUG1("VF %d not up", i-vf0); + } +} + +/** + * tc956x_mbx_get_drv_cap + * + * \brief API to send PF driver featues state to VFs + * + * \details This function is used to send PF driver feature states to VF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] mbx_buff - Pointer to message + * \param[out] ack_msg - Pointer to output ack + * + * \return ACK/NACK + */ +static int tc956x_mbx_get_drv_cap(struct tc956xmac_priv *priv, u8 *mbx_buff, u8 *ack_buff) +{ + if (priv == NULL || mbx_buff == NULL || ack_buff == NULL) { + KPRINT_DEBUG1("NULL pointer error\n"); + return NACK; + } + + if (mbx_buff[0] != OPCODE_MBX_DRV_CAP) + return NACK; + + if (mbx_buff[1] != 0) + return NACK; + + priv->pf_drv_cap.crc_en = priv->rx_crc_pad_state; + priv->pf_drv_cap.csum_en = priv->rx_csum_state; + + ack_buff[0] = OPCODE_MBX_ACK_MSG; + ack_buff[1] = SIZE_MBX_DRV_CAP; + /* Copy driver capability to ack buffer */ + memcpy(&ack_buff[2], &priv->pf_drv_cap, SIZE_MBX_DRV_CAP); + + return ACK; +} + +/** + * tc956x_mbx_get_umac_addr + * + * \brief API to send PF unicast mac addr to VFs + * + * \details This function is used to send PF unicast mac addr to VF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] mbx_buff - Pointer to message + * \param[out] ack_msg - Pointer to output ack + * + * \return ACK/NACK + */ +static int tc956x_mbx_get_umac_addr(struct tc956xmac_priv *priv, u8 *mbx_buff, u8 *ack_buff) +{ + unsigned char addr[SIZE_MBX_VF_MAC]; + unsigned int reg_n; +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + unsigned long flags; +#endif + + if (priv == NULL || mbx_buff == NULL || ack_buff == NULL) { + KPRINT_DEBUG1("NULL pointer error\n"); + return NACK; + } + + if (mbx_buff[0] != OPCODE_MBX_GET_UMAC_ADDR) + return NACK; + + if (mbx_buff[1] != SIZE_GET_UMAC_ADDR) + return NACK; + + memcpy(®_n, &mbx_buff[2], SIZE_GET_UMAC_ADDR); + +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_lock_irqsave(&priv->spn_lock.mac_filter, flags); +#endif + + tc956xmac_get_umac_addr(priv, priv->hw, addr, reg_n); + +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_unlock_irqrestore(&priv->spn_lock.mac_filter, flags); +#endif + + ack_buff[0] = OPCODE_MBX_ACK_MSG; + ack_buff[1] = SIZE_MBX_VF_MAC; + + memcpy(&ack_buff[2], addr, SIZE_MBX_VF_MAC); + + return ACK; +} + +/** + * tc956x_mbx_set_umac_addr + * + * \brief API to set unicast mac addr of VFs + * + * \details This function is used to send PF unicast mac addr to VF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] mbx_buff - Pointer to message + * \param[out] ack_msg - Pointer to output ack + * + * \return ACK/NACK + */ +static int tc956x_mbx_set_umac_addr(struct tc956xmac_priv *priv, u8 *mbx_buff, u8 *ack_buff, u8 vf) +{ + unsigned char addr[SIZE_MBX_VF_MAC]; + unsigned int reg_n; +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + unsigned long flags; +#endif + + if (priv == NULL || mbx_buff == NULL || ack_buff == NULL) { + KPRINT_DEBUG1("NULL pointer error\n"); + return NACK; + } + + if (mbx_buff[0] != OPCODE_MBX_ADD_MAC_ADDR) + return NACK; + + if (mbx_buff[1] != SIZE_SET_UMAC_ADDR) + return NACK; + + memcpy(addr, &mbx_buff[2], SIZE_MBX_VF_MAC); + memcpy(®_n, &mbx_buff[8], 4); + +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_lock_irqsave(&priv->spn_lock.mac_filter, flags); +#endif + + tc956xmac_set_umac_addr(priv, priv->hw, addr, reg_n, vf); + +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_unlock_irqrestore(&priv->spn_lock.mac_filter, flags); +#endif + + ack_buff[0] = OPCODE_MBX_ACK_MSG; + memset(&ack_buff[1], 0, MBX_MSG_SIZE-1); + + return ACK; +} + +/** + * tc956x_mbx_reset_eee + * + * \brief API to reset eee + * + * \details This function is used to reset eee mode on VF request using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] mbx_buff - Pointer to message + * \param[out] ack_msg - Pointer to output ack + * + * \return ACK/NACK + */ +static int tc956x_mbx_reset_eee_mode(struct tc956xmac_priv *priv, u8 *mbx_buff, u8 *ack_msg) +{ + if (priv == NULL || mbx_buff == NULL || ack_msg == NULL) { + KPRINT_DEBUG1("NULL pointer error\n"); + return NACK; + } + + if (mbx_buff[0] != OPCODE_MBX_RESET_EEE_MODE) + return NACK; + + if (mbx_buff[1] != 0) + return NACK; + + tc956xmac_reset_eee_mode(priv, priv->hw); + + ack_msg[0] = OPCODE_MBX_ACK_MSG; + memset(&ack_msg[1], 0, MBX_MSG_SIZE-1); + + return ACK; +} + +/** + * tc956xmac_mbx_vf_reset + * + * \brief API to send tbs sate change to VF + * + * \details This function is used to send TBS state change to VF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] ch - DMA channel no + * \param[in] vf - VF of DMA channel + * + * \return 0 or error + */ +static int tc956xmac_mbx_vf_reset(struct tc956xmac_priv *priv, u8 *mbx_buff, + u8 *ack_msg, u8 vf) +{ + struct tc956x_mac_addr *mac_table = &priv->mac_table[0]; + struct tc956x_vlan_id *vlan_table = &priv->vlan_table[0]; + u8 i, vf_number; +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + unsigned long flags; +#endif + + if (priv == NULL || mbx_buff == NULL || ack_msg == NULL) { + KPRINT_DEBUG1("NULL pointer error\n"); + return NACK; + } + + if (mbx_buff[0] != OPCODE_VF_RESET) + return NACK; + + if (mbx_buff[1] != SIZE_VF_RESET) + return NACK; + + if (mbx_buff[2] == VF_UP) { + priv->clear_to_send[vf-1] = VF_UP; + KPRINT_DEBUG1("P%d VF%d MBX State : UP\n", priv->port_num, vf-1); + } else if (mbx_buff[2] == VF_DOWN) { + priv->clear_to_send[vf-1] = VF_DOWN; + +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_lock_irqsave(&priv->spn_lock.mac_filter, flags); +#endif + tc956x_pf_del_umac_addr(priv, HOST_MAC_ADDR_OFFSET + vf, vf); //VF device address + for (i = XGMAC_ADDR_ADD_SKIP_OFST; i < (TC956X_MAX_PERFECT_ADDRESSES); + i++, mac_table++) { + for (vf_number = 0; vf_number < 4; vf_number++) { + if (mac_table->vf[vf_number] == vf) + tc956x_pf_del_mac_filter(priv->dev, vf, (u8 *)&mac_table->mac_address); + } + } + +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_unlock_irqrestore(&priv->spn_lock.mac_filter, flags); +#endif + +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_lock_irqsave(&priv->spn_lock.vlan_filter, flags); +#endif + for (i = 0; i < TC956X_MAX_PERFECT_VLAN; i++, vlan_table++) { + for (vf_number = 0; vf_number < 4; vf_number++) { + if (vlan_table->vf[vf_number].vf_number == vf) + tc956x_pf_del_vlan_filter(priv->dev, vf, vlan_table->vid); + } + } +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_unlock_irqrestore(&priv->spn_lock.vlan_filter, flags); +#endif + KPRINT_DEBUG1("P%d VF%d MBX State : DOWN\n", priv->port_num, vf-1); + } else if (mbx_buff[2] == VF_SUSPEND || mbx_buff[2] == VF_RELEASE) { + priv->clear_to_send[vf-1] = mbx_buff[2]; + + if (mbx_buff[2] == VF_SUSPEND) + KPRINT_DEBUG1("P%d VF%d MBX State : SUSPEND\n", priv->port_num, vf-1); + else + KPRINT_DEBUG1("P%d VF%d MBX State : RELEASE\n", priv->port_num, vf-1); + } + + ack_msg[0] = OPCODE_MBX_ACK_MSG; + memset(&ack_msg[1], 0, MBX_MSG_SIZE-1); + + return ACK; +} + +/** + * tc956x_mbx_setup_etf + * + * \brief API to send tbs sate change to VF + * + * \details This function is used to send TBS state change to VF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] ch - DMA channel no + * \param[in] vf - VF of DMA channel + * + * \return 0 or error + */ +static int tc956x_mbx_setup_etf(struct tc956xmac_priv *priv, u32 ch, u8 vf) +{ + /* Prepare mailbox message and call mailbox API for posting + * and getting the ACK + */ + u8 mbx[MBX_TOT_SIZE]; + int ret = 0; + enum mbx_msg_fns msg_dst; + + if (priv == NULL) { + KPRINT_DEBUG1("NULL pointer error"); + return -EFAULT; + } + + mbx[0] = OPCODE_MBX_SETUP_ETF; /* opcode */ + mbx[1] = SIZE_MBX_SETUP_ETF; /* size */ + + memcpy(&mbx[2], &ch, 4); + memcpy(&mbx[6], &priv->tx_queue[ch].tbs, 1); + + if (priv->clear_to_send[vf] == VF_UP) { + msg_dst = (enum mbx_msg_fns)(vf + 3); + + ret = tc956xmac_mbx_write(priv, &mbx[0], msg_dst, + &priv->fn_id_info); + + /* Validation of successfull message posting can be done + * by reading the mbx buffer for ACK opcode (0xFF) + */ + if (ret > 0) + KPRINT_DEBUG1( + "mailbox write with ACK or NACK %d msgbuff %x %x\n", + ret, mbx[0], mbx[4]); + else + KPRINT_DEBUG1("mailbox write failed"); + } else + KPRINT_DEBUG1("VF %d is not UP", vf); + return ret; +} + +/** + * tc956x_mbx_flr + * + * \brief API to infor VF of PF FLR + * + * \details This function is used to inform VF about PF FLR using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * + * \return none + */ +static void tc956x_mbx_flr(struct tc956xmac_priv *priv) +{ + /* Prepare mailbox message and call mailbox API for posting + * and getting the ACK + */ + u8 mbx[MAX_NO_OF_VFS][MBX_TOT_SIZE]; + int ret, i; + enum mbx_msg_fns msg_dst; + + if (priv == NULL) { + KPRINT_DEBUG1("NULL pointer error"); + return; + } + + for (i = 0; i < MAX_NO_OF_VFS; i++) { + mbx[i][0] = OPCODE_MBX_FLR; /* opcode */ + mbx[i][1] = 0; /* size */ + } + + /* Send data to all VFs */ + for (i = vf0; i <= vf2; i++) { + if (priv->clear_to_send[i-vf0] == VF_UP) { + msg_dst = (enum mbx_msg_fns) i; + ret = tc956xmac_mbx_write(priv, &mbx[i-vf0][0], msg_dst, + &priv->fn_id_info); + + /* Validation of successfull message posting can be done + * by reading the mbx buffer for ACK opcode (0xFF) + */ + if (ret > 0) { + priv->clear_to_send[i-vf0] = VF_DOWN; + KPRINT_DEBUG1( + "mailbox write with ACK or NACK %d msgbuff %x %x\n", ret, mbx[i-vf0][0], mbx[i-vf0][4]); + } else + KPRINT_DEBUG1("mailbox write failed"); + } else + KPRINT_DEBUG1("VF %d not up", i-vf0); + } +} + +/** + * tc956x_mbx_rx_dma_ch_tlptr + * + * \brief API to send DMA err information to VF + * + * \details This function is used to send DMA error info to VF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] vf - VF no of DMA channel + * + * \return 0 or error + */ +static int tc956x_mbx_rx_dma_err(struct tc956xmac_priv *priv, u8 vf) +{ + /* Prepare mailbox message and call mailbox API for posting + * and getting the ACK + */ + u8 mbx[MBX_TOT_SIZE]; + int ret = 0; + enum mbx_msg_fns msg_dst; + + if (priv == NULL) { + KPRINT_DEBUG1("NULL pointer error"); + return -EFAULT; + } + + mbx[0] = OPCODE_MBX_DMA_ERR; /* opcode */ + mbx[1] = 0; /* size */ + + if (priv->clear_to_send[vf] == VF_UP) { + msg_dst = (enum mbx_msg_fns)(vf + 3); + ret = tc956xmac_mbx_write(priv, &mbx[0], msg_dst, + &priv->fn_id_info); + + /* Validation of successfull message posting can be done + * by reading the mbx buffer for ACK opcode (0xFF) + */ + + if (ret > 0) + KPRINT_DEBUG1( + "mailbox write with ACK or NACK %d msgbuff %x %x\n", + ret, mbx[0], mbx[4]); + else + KPRINT_DEBUG1("mailbox write failed\n"); + } else + KPRINT_DEBUG1("VF %d is not UP", vf); + + return ret; +} + +const struct tc956x_mbx_wrapper_ops tc956xmac_mbx_wrapper_ops = { + .phy_link = tc956x_mbx_phy_link, + .set_dma_tx_mode = tc956x_mbx_set_dma_tx_mode, + .set_mtl_tx_queue_weight = tc956x_mbx_set_mtl_tx_queue_weight, + .config_cbs = tc956x_mbx_config_cbs, + .setup_cbs = tc956x_mbx_setup_cbs, + .setup_mbx_etf = tc956x_mbx_setup_etf, + .tx_queue_prio = tc956x_mbx_tx_queue_prio, + .vf_get_link_status = tc956x_mbx_vf_get_link_status, + .rx_crc = tc956x_mbx_rx_crc, + .rx_csum = tc956x_mbx_rx_csum, + .reset_eee_mode = tc956x_mbx_reset_eee_mode, + .get_umac_addr = tc956x_mbx_get_umac_addr, + .set_umac_addr = tc956x_mbx_set_umac_addr, + .get_drv_cap = tc956x_mbx_get_drv_cap, + .vf_ioctl = tc956xmac_pf_ioctl_interface, + .vf_ethtool = tc956xmac_pf_ethtool_interface, + .add_mac = tc956xmac_pf_set_mac_filter, + .delete_mac = tc956xmac_pf_del_mac_filter, + .add_vlan = tc956xmac_pf_set_vlan_filter, + .delete_vlan = tc956xmac_pf_del_vlan_filter, + .vf_reset = tc956xmac_mbx_vf_reset, + .rx_dma_ch_tlptr = tc956x_mbx_rx_dma_ch_tlptr, + .pf_flr = tc956x_mbx_flr, + .rx_dma_err = tc956x_mbx_rx_dma_err, +}; +#endif diff --git a/tc956x_pf_rsc_mng.c b/tc956x_pf_rsc_mng.c new file mode 100644 index 000000000000..cc99b1669fea --- /dev/null +++ b/tc956x_pf_rsc_mng.c @@ -0,0 +1,158 @@ +/* + * TC956X ethernet driver. + * + * tc956x_pf_rsc_mng.c + * + * Copyright (C) 2021 Toshiba Electronic Devices & Storage Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/*! History: + * 04 June 2020 : Initial Version + * VERSION : 00-01 + * + * 30 Nov 2021 : Base lined for SRIOV + * VERSION : 01-02 + */ + +#include "tc956xmac.h" +#include "tc956x_pf_rsc_mng.h" + +/** + * tc956x_pf_rsc_mng_get_fn_id + * + * \brief API to get function ID of this function + * + * \details This function is called to get the function ID from + * the resource manager function ID register + * + * \param[in] dev - Pointer to device structure + * \param[in] fn_id_info - Pointer to function id info structure + * + * \return success or error + */ + +static int tc956x_pf_rsc_mng_get_fn_id(struct tc956xmac_priv *priv, void __iomem *reg_pci_bridge_config_addr, + struct fn_id *fn_id_info) +{ + void __iomem *ioaddr = reg_pci_bridge_config_addr; + u32 rsc_mng_id = readl(ioaddr + RSCMNG_ID_REG); + + fn_id_info->fn_type = (rsc_mng_id & RSC_MNG_FN_TYPE) >> 16; + fn_id_info->pf_no = (rsc_mng_id & RSC_MNG_PF_FN_NUM); + fn_id_info->vf_no = ((rsc_mng_id & RSC_MNG_VF_FN_NUM) >> 8); + + /** Below error check for PF driver. + * In case of PF driver, vf_no should be 0 and function type to be 0 + */ + if ((fn_id_info->vf_no != 0) || (fn_id_info->fn_type != 0)) + return -1; + + /* PF 0 and 1 are supported */ + if (fn_id_info->pf_no > 1) + return -1; + + return 0; + +} + +/** + * tc956x_pf_rsc_mng_set_rscs + * + * \brief API to set the DMA channel resources for the functions + * + * \details This function is used to set the resources (DMA channels) + * for PF and it's associated VFs + * + * \param[in] dev - Pointer to device structure + * \param[in] rscs - Pointer to array of PF0, VF0, VF1, VF2 having + * DMA channel bit pattern <7,6,5,4,3,2,1,0> + * Example: for case 0-1 following is the array + * rscs[4] = { 0x18, --> PF0 DMACH 3, 4 + * 0x21, --> VF00 DMACH 0, 5 + * 0x02, --> VF01 DMACH 1 + * 0xc4, --> VF02 DMACH 2, 6, 7 + * } + * \return None + */ +static void tc956x_pf_rsc_mng_set_rscs(struct tc956xmac_priv *priv, struct net_device *dev, u8 *rscs) +{ + void __iomem *ioaddr = priv->tc956x_BRIDGE_CFG_pci_base_addr; + u32 rsc_mng_rsc_ctl = 0; + u8 i, buffer_value; + + for (i = 0; i < MAX_FUNCTIONS_PER_PF; i++) { + buffer_value = rscs[i]; + if ((buffer_value & RSC_MNG_DMA_CH7_MASK) == + RSC_MNG_DMA_CH7_MASK) /*DMA ch7 bit*/ + rsc_mng_rsc_ctl |= (i << RSC_MNG_DMA_CH7_BIT_POS); + + if ((buffer_value & RSC_MNG_DMA_CH6_MASK) == + RSC_MNG_DMA_CH6_MASK) /*DMA ch6 bit*/ + rsc_mng_rsc_ctl |= (i << RSC_MNG_DMA_CH6_BIT_POS); + + if ((buffer_value & RSC_MNG_DMA_CH5_MASK) == + RSC_MNG_DMA_CH5_MASK) /*DMA ch5 bit*/ + rsc_mng_rsc_ctl |= (i << RSC_MNG_DMA_CH5_BIT_POS); + + if ((buffer_value & RSC_MNG_DMA_CH4_MASK) == + RSC_MNG_DMA_CH4_MASK) /*DMA ch4 bit*/ + rsc_mng_rsc_ctl |= (i << RSC_MNG_DMA_CH4_BIT_POS); + + if ((buffer_value & RSC_MNG_DMA_CH3_MASK) == + RSC_MNG_DMA_CH3_MASK) /*DMA ch3 bit*/ + rsc_mng_rsc_ctl |= (i << RSC_MNG_DMA_CH3_BIT_POS); + + if ((buffer_value & RSC_MNG_DMA_CH2_MASK) == + RSC_MNG_DMA_CH2_MASK) /*DMA ch2 bit*/ + rsc_mng_rsc_ctl |= (i << RSC_MNG_DMA_CH2_BIT_POS); + + if ((buffer_value & RSC_MNG_DMA_CH1_MASK) == + RSC_MNG_DMA_CH1_MASK) /*DMA ch1 bit*/ + rsc_mng_rsc_ctl |= (i << RSC_MNG_DMA_CH1_BIT_POS); + + if ((buffer_value & RSC_MNG_DMA_CH0_MASK) == + RSC_MNG_DMA_CH0_MASK) /*DMA ch0 bit*/ + rsc_mng_rsc_ctl |= (i << RSC_MNG_DMA_CH0_BIT_POS); + } + writel(rsc_mng_rsc_ctl, ioaddr + RSCMNG_RSC_CTRL_REG); +} + +/** + * tc956x_pf_rsc_mng_get_rscs + * + * \brief API to get the DMA channel resources allocated + * + * \details This function is used to get the resources (DMA channels) + * allocated for this function + * + * \param[in] dev - Pointer to device structure + * \param[in] rscs - Pointer to return DMA channel bit pattern in + * order <7,6,5,4,3,2,1,0> + * \return None + */ + +static void tc956x_pf_rsc_mng_get_rscs(struct tc956xmac_priv *priv, struct net_device *dev, u8 *rscs) +{ + void __iomem *ioaddr = priv->tc956x_BRIDGE_CFG_pci_base_addr; + *rscs = ((readl(ioaddr + RSCMNG_RSC_ST_REG)) & RSC_MNG_RSC_STATUS_MASK); +} + +const struct mac_rsc_mng_ops tc956xmac_rsc_mng_ops = { + .get_fn_id = tc956x_pf_rsc_mng_get_fn_id, + .set_rscs = tc956x_pf_rsc_mng_set_rscs, + .get_rscs = tc956x_pf_rsc_mng_get_rscs, +}; diff --git a/tc956x_pf_rsc_mng.h b/tc956x_pf_rsc_mng.h new file mode 100644 index 000000000000..3cb97c4a4b26 --- /dev/null +++ b/tc956x_pf_rsc_mng.h @@ -0,0 +1,86 @@ +/* + * TC956X ethernet driver. + * + * tc956x_pf_rsc_mng.h + * + * Copyright (C) 2021 Toshiba Electronic Devices & Storage Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/*! History: + * 10 July 2020 : Initial Version + * VERSION : 00-01 + * + * 30 Nov 2021 : Base lined for SRIOV + * VERSION : 01-02 + */ +#ifndef __TC956X_PF_RSC_MNG_H__ +#define __TC956X_PF_RSC_MNG_H__ + +#include "common.h" +#include + +#define MAX_FUNCTIONS_PER_PF 4 /*Max functions per pf including pf, vfs*/ +#define RSC_MNG_OFFSET 0x2000 +#define RSCMNG_ID_REG ((RSC_MNG_OFFSET) + 0x00000000) +#define RSCMNG_RSC_CTRL_REG ((RSC_MNG_OFFSET) + 0x00000004) +#define RSCMNG_RSC_ST_REG ((RSC_MNG_OFFSET) + 0x00000008) +#define RSCMNG_INT_CTRL_REG ((RSC_MNG_OFFSET) + 0x0000000c) +#define RSCMNG_INT_ST_REG ((RSC_MNG_OFFSET) + 0x00000010) + +#define RSC_MNG_FN_TYPE BIT(16) +#define RSC_MNG_VF_FN_NUM GENMASK(11, 8) +#define RSC_MNG_PF_FN_NUM GENMASK(3, 0) + +#define RSC_MNG_DMA_CH7_MASK 0x80 +#define RSC_MNG_DMA_CH6_MASK 0x40 +#define RSC_MNG_DMA_CH5_MASK 0x20 +#define RSC_MNG_DMA_CH4_MASK 0x10 +#define RSC_MNG_DMA_CH3_MASK 0x08 +#define RSC_MNG_DMA_CH2_MASK 0x04 +#define RSC_MNG_DMA_CH1_MASK 0x02 +#define RSC_MNG_DMA_CH0_MASK 0x01 + +#define RSC_MNG_DMA_CH7_BIT_POS 28 +#define RSC_MNG_DMA_CH6_BIT_POS 24 +#define RSC_MNG_DMA_CH5_BIT_POS 20 +#define RSC_MNG_DMA_CH4_BIT_POS 16 +#define RSC_MNG_DMA_CH3_BIT_POS 12 +#define RSC_MNG_DMA_CH2_BIT_POS 8 +#define RSC_MNG_DMA_CH1_BIT_POS 4 +#define RSC_MNG_DMA_CH0_BIT_POS 0 + +#define RSC_MNG_RSC_STATUS_MASK 0xff + +#define RSC_MNG_INT_STATUS_MASK 0x1f +#define RSC_MNG_INT_MCU_MASK 0x10 +#define RSC_MNG_INT_VF2_MASK 0x08 +#define RSC_MNG_INT_VF1_MASK 0x04 +#define RSC_MNG_INT_VF0_MASK 0x02 +#define RSC_MNG_INT_OTHR_PF_MASK 0x01 + +#define MBX_MCU_INTERRUPT BIT(4) +#define MBX_VF3_INTERRUPT BIT(3) +#define MBX_VF2_INTERRUPT BIT(2) +#define MBX_VF1_INTERRUPT BIT(1) +#define MBX_PF_INTERRUPT BIT(0) + +#define RSC_MNG_ACK_MASK 0x01 +#define RSC_MNG_NACK_MASK 0x02 + +#define MBX_TIMEOUT 1000 + +#endif /* __TC956X_PF_RSC_MNG_H__ */ diff --git a/tc956x_vf_mbx.c b/tc956x_vf_mbx.c new file mode 100644 index 000000000000..aee1c2b7cb62 --- /dev/null +++ b/tc956x_vf_mbx.c @@ -0,0 +1,550 @@ +/* + * TC956X ethernet driver. + * + * tc956x_vf_mbx.c + * + * Copyright (C) 2021 Toshiba Electronic Devices & Storage Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/*! History: + * 06 Nov 2020 : Initial Version + * VERSION : 00-01 + * + * 30 Nov 2021 : Base lined for SRIOV + * VERSION : 01-02 + */ + +#include "tc956x_vf_mbx.h" +#include "tc956xmac.h" +#include "tc956x_vf_rsc_mng.h" + +#ifdef TC956X_SRIOV_VF + +/** + * This table maintains the SRAM mapping for PF0->VF0s, VF0s->PF0, PF1->VF1s, + * VF1s->PF1, PF0->PF1, PF1->PF0, MCU->PF0, PF0->MCU, PF1->MCU, MCU->PF1 + * Each communication SRAM size is of 64 bytes. In total 30 such SRAMs are + * required for above mentioned communication path. + * In general, in Design of HW semaphore: PF uses one SRAM location for + * any request and ACK message to a particular VF and VF uses other + * SRAM location for requestand ACK. In Design of No semaphore: PF use one + * SRAM location to send request, VF to use same location (overwrite) to send + * the ACK, similarly VF uses other SRAM to send request, PF to use same location + * (overwrite) to send the ACK. + */ +static u8 PF_VF_mbx_idx[PFS_MAX][VFNS_MAX][2] = { + { + {19, 20}, /* MCU <--> VF00 [MCU RQST Msg/MCU ACK Msg, + * VF00 ACK Msg/VF00 RQST Msg] + */ + {21, 22}, /* MCU <--> VF01 [MCU RQST Msg/MCU ACK Msg, + * VF01 ACK Msg/VF01 RQST Msg] + */ + {23, 24}, /* MCU <--> VF02 [MCU RQST Msg/MCU ACK Msg, + * VF02 ACK Msg/VF02 RQST Msg] + */ + }, + { + {5, 6}, /* PF0 <--> VF00 [PF0 RQST Msg/PF0 ACK Msg, + * VF0 ACK Msg/VF0 RQST Msg] + */ + {7, 8}, /* PF0 <--> VF01 [PF0 RQST Msg/PF0 ACK Msg, + * VF1 ACK Msg/VF1 RQST Msg] + */ + {9, 10} /* PF0 <--> VF02 [PF0 RQST Msg/PF0 ACK Msg, + * VF2 ACK Msg/VF2 RQST Msg] + */ + }, + { + {25, 26}, /* MCU <--> VF10 [MCU RQST Msg/MCU ACK Msg, + * VF10 ACK Msg/VF10 RQST Msg] + */ + {27, 28}, /* MCU <--> VF11 [MCU RQST Msg/MCU ACK Msg, + * VF11 ACK Msg/VF11 RQST Msg] + */ + {29, 30} /* MCU <--> VF12 [MCU RQST Msg/MCU ACK Msg, + * MCU VF12 Msg/VF12 RQST Msg] + */ + }, + { + {13, 14}, /* PF1 <--> VF10 [PF1 RQST Msg/PF1 ACK Msg, + * VF0 ACK Msg/VF0 RQST Msg] + */ + {15, 16}, /* PF2 <--> VF11 [PF1 RQST Msg/PF1 ACK Msg, + * VF1 ACK Msg/VF1 RQST Msg] + */ + {17, 18} /* PF3 <--> VF12 [PF1 RQST Msg/PF1 ACK Msg, + * VF2 ACK Msg/VF2 RQST Msg] + */ + }, + +}; + +/** + * vf_get_mbx_mem_idx + * + * \brief API to return pointer pointing to SRAM index + * + * \details This function to return the pointer to the 1D array of + * PF_VF_mbx_idx where it points to SRAM location of specific PF->Fn + * + * \param[in] msg_src - Function to/from where PF needs to write/read + * \param[in] fn_id_info - Pointer to this function id information + * + * \return pointer to the SRAM index + */ + +static u8 *vf_get_mbx_mem_idx(enum mbx_msg_fns msg_src, + struct fn_id *fn_id_info) +{ + /* for MCU interrupt for VFs associated with pf1, below handling + * is required as it is not possible to get correct offset from + * the array with the other approach + */ + if ((msg_src == mcu) && (fn_id_info->pf_no == 1)) + return *(*(PF_VF_mbx_idx + 2) + (fn_id_info->vf_no - 1)); + else + return *(*(PF_VF_mbx_idx + (msg_src + fn_id_info->pf_no)) + + (fn_id_info->vf_no - 1)); +} + +/** + * tc956x_vf_get_fn_idx_from_int_sts + * + * \brief Helper function to get function that raised the mailbox interrupt + * + * \details This function is called to get the function which raised the + * mailbox interrupt. Interrupt source can be MCU or associated PF + * + * \param[in] msg_dst - Function to which interrupt should be set + * \param[in] fn_id_info - Pointer to Function info structure + * + * \return function type or error + */ +int tc956x_vf_get_fn_idx_from_int_sts(struct tc956xmac_priv *priv, + struct fn_id *fn_id_info) +{ + void __iomem *ioaddr = priv->tc956x_BRIDGE_CFG_pci_base_addr; + u32 rsc_mng_int_sts = readl(ioaddr + RSCMNG_INT_ST_REG); + + if ((rsc_mng_int_sts & RSC_MNG_INT_MCU_MASK) == RSC_MNG_INT_MCU_MASK) { + writel(RSC_MNG_INT_MCU_MASK, ioaddr + RSCMNG_INT_ST_REG); + return mcu; + } else if ((rsc_mng_int_sts & RSC_MNG_INT_OTHR_PF_MASK) == + RSC_MNG_INT_OTHR_PF_MASK) { + if (fn_id_info->pf_no == 0) { + writel(RSC_MNG_INT_OTHR_PF_MASK, ioaddr + RSCMNG_INT_ST_REG); + return pf0; + } else if (fn_id_info->pf_no == 1) { + writel(RSC_MNG_INT_OTHR_PF_MASK, ioaddr + RSCMNG_INT_ST_REG); + return pf1; + } else + return -1; + } else /* Other interrupts are not supported */ + return -1; +} + +static int trylock_semaphore(void __iomem *ioaddr, u8 idx) +{ + u32 rd_val = 0; + + /* Read 0 for lock. Else already semaphore is locked + * curr value : action : next value + * 0 : read 0 : 1 + * 1 : read 1 : 1 + */ + + rd_val = readl(ioaddr + NSEM(idx)); + if (rd_val == 0) + return 0; + else + return -EBUSY; +} + +static int unlock_semaphore(void __iomem *ioaddr, u8 idx) +{ + u32 wr_val = 1; + + /* Write 1 to unlock + * curr value : action : next value + * 0 : write 0 : 0 + * 0 : write 1 : 0 + * 1 : write 0 : 1 + * 1 : write 1 : 0 + */ + writel(wr_val, ioaddr + NSEM(idx)); + return 0; +} + +/** + * tc956x_vf_parse_mbx + * + * \brief API to read and process the VF mailbox + * + * \details This function should be called from ISR to parse the mailbox for + * the mail received from particular function. Message will be processed and + * ACK/NACK will be sent in this function + * + * \param[in] priv - Pointer to device private structure + * \param[in] msg_src - Function to which ACK should be posted + * + * \return None + */ +void tc956x_vf_parse_mbx(struct tc956xmac_priv *priv, + enum mbx_msg_fns msg_src) +{ + u8 msg_buff[MBX_TOT_SIZE]; + + /* Get the function id information and read the mailbox. + * Function id can be get earlier too + */ + if (!tc956xmac_rsc_mng_get_fn_id(priv, + priv->tc956x_BRIDGE_CFG_pci_base_addr, &priv->fn_id_info)) { + /* Read and acknowledge the mailbox */ + tc956xmac_mbx_read(priv, msg_buff, msg_src, + &priv->fn_id_info); + } +} + +/** + * tc956x_vf_check_for_ack + * + * \brief Helper function to check for ACK + * + * \details This function is called from polling function to check if + * any ACK or NACK is received after writing in the mailbox + * + * \param[in] dev - Pointer to device structure + * \param[in] msg_dst - Function from which ACK/NACK should be read + * \param[in] fn_id_info - Pointer to Function info structure + * + * \return ACK/NACK or error + */ +static int tc956x_vf_check_for_ack(struct tc956xmac_priv *priv, + enum mbx_msg_fns msg_dst, + struct fn_id *fn_id_info) +{ + u8 *ptr_mail_box_idx; + u8 ack_buff[MBX_ACK_SIZE]; + + /* Read the correct mailbox access index as per + * the destination function + */ + ptr_mail_box_idx = vf_get_mbx_mem_idx(msg_dst, fn_id_info); + + /* Copy the ACK inidication data (first 4 bytes) from PF->VF mailbox */ + memcpy_fromio(ack_buff, + (priv->tc956x_SRAM_mailbox_base_addr + + ((*ptr_mail_box_idx + VF_READ_ACK_OFST) * MBX_TOT_SIZE)), + MBX_ACK_SIZE); + + if ((ack_buff[0] & RSC_MNG_ACK_MASK) == RSC_MNG_ACK_MASK) + return ACK; + else if ((ack_buff[0] & RSC_MNG_NACK_MASK) == RSC_MNG_NACK_MASK) + return NACK; + else + return -1; +} + +/** + * tc956x_vf_mbx_init + * + * \brief API to initialise mailbox memory and parameters + * + * \details This function initialise mailbox memory used by this function. + * Also to initialise parameters used for mailbox control. + * + * \param[in] ndev - Pointer to device structure + * + * \return None + */ + +static void tc956x_vf_mbx_init(struct tc956xmac_priv *priv, void *data) +{ + priv->tc956x_SRAM_mailbox_base_addr = priv->tc956x_SRAM_pci_base_addr + VF_MBX_SRAM_ADDR; +} + +/** + * tc956x_vf_mbx_poll_for_ack + * + * \brief API to poll for acknowledgement + * + * \details This function will poll for acknowledgement after writing to the + * mailbox memory. Polling is done by means of reading a + * resource manager register + * + * \param[in] priv - Pointer to device private structure + * \param[in] msg_dst - Function from which ACK should be polled + * + * \return None + */ +static int tc956x_vf_mbx_poll_for_ack(struct tc956xmac_priv *priv, + enum mbx_msg_fns msg_dst) +{ + + int countdown = MBX_TIMEOUT; + int ack_status; + + ack_status = + tc956x_vf_check_for_ack(priv, msg_dst, &priv->fn_id_info); + + while (countdown && (ack_status < 0)) { + countdown--; + udelay(1000); + ack_status = tc956x_vf_check_for_ack(priv, msg_dst, + &priv->fn_id_info); + } + + return ack_status; +} + +/** + * tc956x_vf_mbx_send_ack + * + * \brief API to send acknowledgement + * + * \details This function will post the acknowledgement message + * to the mailbox memory. + * Basically this should be called after every read + * + * \param[in] priv - Pointer to device private structure + * \param[in] msg_buff - Pointer to buffer having the acknowledgement message + * \param[in] msg_dst - Function to which ACK should be posted + * \param[in] fn_id_info - Pointer to function id information + * + * \return None + */ +static void tc956x_vf_mbx_send_ack(struct tc956xmac_priv *priv, u8 *msg_buff, + enum mbx_msg_fns msg_dst, + struct fn_id *fn_id_info) +{ + u8 *ptr_mail_box_idx; + + /* Read the correct mailbox access index as per + * the destination function + */ + ptr_mail_box_idx = vf_get_mbx_mem_idx(msg_dst, fn_id_info); + + /* Copy the ACK message data to PF->VF SRAM area. + * Also first 4 bytes of ACK indications also copied here + */ + memcpy_toio((priv->tc956x_SRAM_mailbox_base_addr + + ((*ptr_mail_box_idx + VF_SEND_ACK_OFST) * MBX_TOT_SIZE)), + msg_buff, MBX_TOT_SIZE); + + priv->xstats.mbx_vf_sent_pf++; +} + +/** + * tc956x_vf_trigger_interrupt + * + * \brief Helper function to set mailbox interrupt bit + * + * \details This function is called to set the mailbox interrupt bits while + * writing the mailbox. Interrupt targets can be MCU, VFs or other PF + * + * \param[in] msg_dst - Function to which interrupt should be set + * + * \return None + */ +static void tc956x_vf_trigger_interrupt(struct tc956xmac_priv *priv, + enum mbx_msg_fns msg_dst) +{ + void __iomem *ioaddr = priv->tc956x_BRIDGE_CFG_pci_base_addr; + u32 rsc_mng_interrupt_ctl = readl(ioaddr + RSCMNG_INT_CTRL_REG); + + if (mcu == msg_dst) + rsc_mng_interrupt_ctl |= MBX_MCU_INTERRUPT; + else if ((pf0 == msg_dst) || (pf1 == msg_dst)) + rsc_mng_interrupt_ctl |= MBX_PF_INTERRUPT; + + writel(rsc_mng_interrupt_ctl, ioaddr + RSCMNG_INT_CTRL_REG); +} + +/** + * tc956x_vf_mbx_write + * + * \brief API to write a message to particular mailbox (sram) + * + * \details This function will post the request message to the mailbox memory. + * + * \param[in] priv - Pointer to device private structure + * \param[in] msg_buff - Pointer to buffer having the request message + * Skip the first 4 bytes while preparing data in this buffer + * \param[in] msg_dst - Function to which message should be posted + * \param[in] fn_id_info - Pointer to function id information + * + * \return success or error code + */ +static int tc956x_vf_mbx_write(struct tc956xmac_priv *priv, u8 *msg_buff, + enum mbx_msg_fns msg_dst, + struct fn_id *fn_id_info) +{ + u8 *ptr_mail_box_idx; + int ret; + + + /* Read the correct mailbox access index as per + * the destination function + */ + ptr_mail_box_idx = vf_get_mbx_mem_idx(msg_dst, fn_id_info); + + /* Get the semaphore lock before udpating mailbox */ + ret = trylock_semaphore(priv->ioaddr, ((*ptr_mail_box_idx + 1) >> 1)); + if (ret != 0) + return ret; + + /* Clear the mailbox including ACK area (first 4 bytes) */ + memset_io((priv->tc956x_SRAM_mailbox_base_addr + + ((*ptr_mail_box_idx + VF_SEND_RQST_OFST) * MBX_TOT_SIZE)), + 0, MBX_TOT_SIZE); + + /* Copy the mailbox data from local buffer to VF->PF or VF->MCU + * destination mailbox SRAM memory + */ + memcpy_toio((priv->tc956x_SRAM_mailbox_base_addr + + ((*ptr_mail_box_idx + VF_SEND_RQST_OFST) * MBX_TOT_SIZE) + MBX_MSG_OFST), + msg_buff, MBX_MSG_SIZE); + + priv->xstats.mbx_vf_sent_pf++; + + /*Set the interrupt bit in resource manager interrupt register*/ + tc956x_vf_trigger_interrupt(priv, msg_dst); + + /*poll for ack/nack from the VF/MCU/Other PF*/ + ret = tc956xmac_mbx_poll_for_ack(priv, msg_dst); + + /* Read for ACK message */ + if (ret > 0) { + /* msg_buff to be overwritten here with ACK notification data + * and ACK message data + */ + tc956xmac_mbx_read(priv, msg_buff, msg_dst, + &priv->fn_id_info); + } + + unlock_semaphore(priv->ioaddr, ((*ptr_mail_box_idx + 1) >> 1)); + + return ret; +} + +/** + * tc956x_vf_mbx_read + * + * \brief API to read a message from particular mailbox (sram) + * + * \details This function will read request message from the mailbox + * memory. This function to be called from mailbox interrupt routine. + * This API can be used in case of ACK message read as well. + * + * \param[in] priv - Pointer to device private structure + * \param[in] msg_buff - Pointer to read the mailbox message of max size + * 64 bytes + * \param[in] msg_src - Function from which mailbox message should be read + * \param[in] fn_id_info - Pointer to function id information + * + * \return success or error code + */ +static int tc956x_vf_mbx_read(struct tc956xmac_priv *priv, u8 *msg_buff, + enum mbx_msg_fns msg_src, + struct fn_id *fn_id_info) +{ + u8 *ptr_mail_box_idx; + enum mbx_msg_fns msg_dst; + u8 ack_msg[MBX_MSG_SIZE]; + u8 ret_val = 0; + + /* Read the correct mailbox access index as per + * the destination function + */ + ptr_mail_box_idx = vf_get_mbx_mem_idx(msg_src, fn_id_info); + + /* Copy the mailbox data from PF->VF mailbox*/ + memcpy_fromio(msg_buff, + (priv->tc956x_SRAM_mailbox_base_addr + + ((*ptr_mail_box_idx + VF_READ_RQST_OFST) * MBX_TOT_SIZE)), + MBX_TOT_SIZE); + + priv->xstats.mbx_vf_rcvd_pf++; + + switch (msg_buff[MBX_MSG_OFST]) { + case OPCODE_MBX_PHY_LINK: + ret_val = tc956x_phy_link(priv, &msg_buff[MBX_MSG_OFST], &ack_msg[0]); + break; + case OPCODE_MBX_RX_CSUM: + ret_val = tc956x_rx_csum(priv, &msg_buff[MBX_MSG_OFST], &ack_msg[0]); + break; + case OPCODE_MBX_RX_CRC: + ret_val = tc956x_rx_crc(priv, &msg_buff[MBX_MSG_OFST], &ack_msg[0]); + break; + case OPCODE_MBX_DMA_CH_TLPTR: + ret_val = tc956x_rx_dma_ch_tlptr(priv, &msg_buff[MBX_MSG_OFST], &ack_msg[0]); + break; + case OPCODE_MBX_SETUP_ETF: + ret_val = tc956x_setup_mbx_etf(priv, &msg_buff[MBX_MSG_OFST], &ack_msg[0]); + break; + case OPCODE_MBX_FLR: + ret_val = tc956x_mbx_flr(priv, &msg_buff[MBX_MSG_OFST], &ack_msg[0]); + break; + case OPCODE_MBX_DMA_ERR: + ret_val = tc956x_rx_dma_err(priv, &msg_buff[MBX_MSG_OFST], &ack_msg[0]); + break; + case OPCODE_MBX_ACK_MSG: + /* ACK message */ + memset_io((priv->tc956x_SRAM_mailbox_base_addr + + ((*ptr_mail_box_idx + VF_READ_RQST_OFST) * MBX_TOT_SIZE)), 0, + MBX_TOT_SIZE); + break; + default: + break; + } + + /* Send the Acknowldegment if message read is not ACK message */ + if (msg_buff[MBX_MSG_OFST] != OPCODE_MBX_ACK_MSG) { + /* For sending ACK, source of request message becomes + * the destination + */ + msg_dst = msg_src; + + /* Prepare first 4 bytes of ACK inidication data */ + msg_buff[0] = ret_val; + msg_buff[1] = 0x0; + msg_buff[2] = 0x0; + msg_buff[3] = 0x0; + + /* Prepare 60 bytes of acknowledgment message */ + memcpy(&msg_buff[MBX_MSG_OFST], ack_msg, + MBX_MSG_SIZE); + + /* After successful parsing, ACK/NACK the functions which + * originated the message + */ + tc956xmac_mbx_send_ack(priv, msg_buff, msg_dst, + fn_id_info); + } + return 0; +} + +const struct mac_mbx_ops tc956xmac_mbx_ops = { + .init = tc956x_vf_mbx_init, + .read = tc956x_vf_mbx_read, + .write = tc956x_vf_mbx_write, + .send_ack = tc956x_vf_mbx_send_ack, + .poll_for_ack = tc956x_vf_mbx_poll_for_ack, + +}; +#endif /* #ifdef TC956X_SRIOV_VF */ diff --git a/tc956x_vf_mbx.h b/tc956x_vf_mbx.h new file mode 100644 index 000000000000..64736f00e410 --- /dev/null +++ b/tc956x_vf_mbx.h @@ -0,0 +1,47 @@ +/* + * TC956X ethernet driver. + * + * tc956x_vf_mbx.h + * + * Copyright (C) 2021 Toshiba Electronic Devices & Storage Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/*! History: + * 10 Jul 2020 : Initial Version + * VERSION : 00-01 + * + * 30 Nov 2021 : Base lined for SRIOV + * VERSION : 01-02 + */ + +#ifndef __TC956X_VF_MBX_H__ +#define __TC956X_VF_MBX_H__ + +#include "common.h" +#include + +#define VF_READ_RQST_OFST 0 /* VF to read request of PF */ +#define VF_SEND_ACK_OFST 1 /* VF to send ACK to PF */ + +#define VF_SEND_RQST_OFST 1 /* VF to send request to PF */ +#define VF_READ_ACK_OFST 0 /* VF to read ACK from PF */ + +#define PFS_MAX 4 /* 2 PF + 2 MCU->VF0x, MCU->VF1x */ +#define VFNS_MAX 3 /* 3 VFs */ + +#define VF_MBX_SRAM_ADDR 0x47060 /*0x20007060*/ +#endif /* __TC956X_VF_MBX_H__ */ diff --git a/tc956x_vf_mbx_wrapper.c b/tc956x_vf_mbx_wrapper.c new file mode 100644 index 000000000000..3da29d4400bd --- /dev/null +++ b/tc956x_vf_mbx_wrapper.c @@ -0,0 +1,2038 @@ +/* + * TC956X ethernet driver. + * + * tc956x_mbx_wrapper.c + * + * Copyright (C) 2022 Toshiba Electronic Devices & Storage Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/*! History: + * 06 Nov 2020 : Initial Version + * VERSION : 00-01 + * + * 30 Nov 2021 : Base lined for SRIOV + * VERSION : 01-02 + * + * 20 May 2022 : 1. Automotive Driver, CPE fixes merged and IPA Features supported + * 2. Base lined version + * VERSION : 03-00 + */ + +#include "tc956xmac.h" +#include "dwxgmac2.h" + +#ifdef TC956X_SRIOV_VF + +/** + * tc956xmac_mbx_dma_tx_mode + * + * \brief API to set dma tx mode + * + * \details This function is used to send parameters of set dma tx mode to PF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] mode - mode + * \param[in] channel - DMA channel no + * \param[in] fifosz - fifo size + * \param[in] qmode - queue mode + * + * \return None + */ +static void tc956xmac_mbx_dma_tx_mode(struct tc956xmac_priv *priv, int mode, + u32 channel, int fifosz, u8 qmode) +{ + + /* Prepare mailbox message and call mailbox API for posting + * and getting the ACK + */ + u8 mbx[MBX_TOT_SIZE]; + int ret; + enum mbx_msg_fns msg_dst = priv->fn_id_info.pf_no + 1; + + if (priv == NULL) { + KPRINT_DEBUG2("NULL pointer error\n"); + return; + } + + mbx[0] = OPCODE_MBX_SET_DMA_TX_MODE; //opcode + mbx[1] = SIZE_MBX_SET_DMA_TX_MODE; //size + + memcpy(&mbx[2], (u8 *)&mode, sizeof(mode)); + memcpy(&mbx[6], (u8 *)&channel, sizeof(channel)); + memcpy(&mbx[10], (u8 *)&fifosz, sizeof(fifosz)); + mbx[14] = qmode; + + ret = tc956xmac_mbx_write(priv, mbx, msg_dst, &priv->fn_id_info); + + /* Validation of successfull message posting can be done + * by reading the mbx buffer for ACK opcode (0xFF) + */ + + if (ret > 0) + KPRINT_DEBUG2("mailbox write with ACK or NACK %d msgbuff %x %x\n", ret, + mbx[0], mbx[4]); + else + KPRINT_DEBUG2("mailbox write failed"); +} + +/** + * tc956xmac_mbx_set_mtl_tx_queue_weight + * + * \brief API to set mtl tx queue weight + * + * \details This function is used to send parameters of mtl queue weight to PF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] weight - weight + * \param[in] traffic_class - traffic_class no + * + * \return None + */ +static void tc956xmac_mbx_set_mtl_tx_queue_weight(struct tc956xmac_priv *priv, + u32 weight, u32 traffic_class) +{ + /* Prepare mailbox message and call mailbox API for posting + * and getting the ACK + */ + u8 mbx[MBX_TOT_SIZE]; + int ret; + enum mbx_msg_fns msg_dst = priv->fn_id_info.pf_no + 1; + + if (priv == NULL) { + KPRINT_DEBUG2("NULL pointer error\n"); + return; + } + + mbx[0] = OPCODE_MBX_SET_TX_Q_WEIGHT; //opcode + mbx[1] = SIZE_MBX_SET_TX_Q_WEIGHT; //size + + memcpy(&mbx[2], (u8 *)&weight, sizeof(weight)); + memcpy(&mbx[6], (u8 *)&traffic_class, sizeof(traffic_class)); + + ret = tc956xmac_mbx_write(priv, mbx, msg_dst, &priv->fn_id_info); + + /* Validation of successfull message posting can be done + * by reading the mbx buffer for ACK opcode (0xFE) + */ + + if (ret > 0) + KPRINT_DEBUG2("mailbox write with ACK or NACK %d msgbuff %x %x\n", ret, + mbx[0], mbx[4]); + else + KPRINT_DEBUG2("mailbox write failed"); +} + +/** + * tc956xmac_mbx_config_cbs + * + * \brief API to configure the cbs parameters for queue + * + * \details This function is used to send cbs parameters to PF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] send_slope - send_slope + * \param[in] idle_slope - idle_slope + * \param[in] high_credit - high_credit + * \param[in] low_credit - low_credit + * \param[in] queue - queue + * + * \return None + */ +static void tc956xmac_mbx_config_cbs(struct tc956xmac_priv *priv, + u32 send_slope, u32 idle_slope, + u32 high_credit, u32 low_credit, u32 queue) +{ + /* Prepare mailbox message and call mailbox API for posting + * and getting the ACK + */ + u8 mbx[MBX_TOT_SIZE]; + int ret; + enum mbx_msg_fns msg_dst = priv->fn_id_info.pf_no + 1; + + if (priv == NULL) { + KPRINT_DEBUG2("NULL pointer error\n"); + return; + } + + mbx[0] = OPCODE_MBX_CFG_CBS; //opcode + mbx[1] = SIZE_MBX_CFG_CBS; //size + + memcpy(&mbx[2], (u8 *)&send_slope, sizeof(send_slope)); + memcpy(&mbx[6], (u8 *)&idle_slope, sizeof(idle_slope)); + memcpy(&mbx[10], (u8 *)&high_credit, sizeof(high_credit)); + memcpy(&mbx[14], (u8 *)&low_credit, sizeof(low_credit)); + memcpy(&mbx[18], (u8 *)&queue, sizeof(queue)); + + ret = tc956xmac_mbx_write(priv, mbx, msg_dst, &priv->fn_id_info); + /* Validation of successfull message posting can be done + * by reading the mbx buffer for ACK opcode (0xFE) + */ + + if (ret > 0) + KPRINT_DEBUG2("mailbox write with ACK or NACK %d msgbuff %x %x\n", ret, + mbx[0], mbx[4]); + else + KPRINT_DEBUG2("mailbox write failed"); +} + +/** + * tc956xmac_mbx_tx_queue_prio + * + * \brief API to set tx queue priority + * + * \details This function is used to send tx queue priority values to PF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] prio - priority + * \param[in] queue - queue + * + * \return None + */ +static void tc956xmac_mbx_tx_queue_prio(struct tc956xmac_priv *priv, + u32 prio, u32 queue) +{ + /* Prepare mailbox message and call mailbox API for posting + * and getting the ACK + */ + u8 mbx[MBX_TOT_SIZE]; + int ret; + enum mbx_msg_fns msg_dst = priv->fn_id_info.pf_no + 1; + + if (priv == NULL) { + KPRINT_DEBUG2("NULL pointer error\n"); + return; + } + + mbx[0] = OPCODE_MBX_SET_TX_Q_PRIOR; //opcode + mbx[1] = SIZE_MBX_SET_TX_Q_PRIOR; //size + + memcpy(&mbx[2], (u8 *)&prio, sizeof(prio)); + memcpy(&mbx[6], (u8 *)&queue, sizeof(queue)); + + ret = tc956xmac_mbx_write(priv, mbx, msg_dst, &priv->fn_id_info); + + /* Validation of successfull message posting can be done + * by reading the mbx buffer for ACK opcode (0xFE) + */ + + if (ret > 0) + KPRINT_DEBUG2("mailbox write with ACK or NACK %d msgbuff %x %x\n", + ret, mbx[0], mbx[4]); + else + KPRINT_DEBUG2("mailbox write failed"); +} + +/** + * tc956xmac_mbx_get_link_status + * + * \brief API to get pf link status parametrs + * + * \details This function is used to get link status from PF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[out] link_status - link_status + * \param[out] speed - speed + * \param[out] duplex - duplex + * + * \return None + */ +static void tc956xmac_mbx_get_link_status(struct tc956xmac_priv *priv, + u32 *link_status, u32 *speed, u32 *duplex) +{ + /* Prepare mailbox message and call mailbox API for posting + * and getting the ACK + */ + u8 mbx[MBX_TOT_SIZE]; + int ret; + enum mbx_msg_fns msg_dst = priv->fn_id_info.pf_no + 1; + + if (priv == NULL || link_status == NULL || speed == NULL || duplex == NULL) { + KPRINT_DEBUG2("NULL pointer error\n"); + return; + } + + mbx[0] = OPCODE_MBX_VF_GET_LINK_STATUS; //opcode + mbx[1] = 0; //size + + ret = tc956xmac_mbx_write(priv, mbx, msg_dst, &priv->fn_id_info); + + /* Validation of successfull message posting can be done + * by reading the mbx buffer for ACK opcode (0xFF) + */ + + if (ret > 0) { + if (ret == ACK) { + /* Check the acknowledgement message for opcode and size, + * then read the data from the ACK message + */ + if ((mbx[4] == OPCODE_MBX_ACK_MSG) && (mbx[5] == SIZE_MBX_PHY_LINK)) { + memcpy(link_status, &mbx[6], 4); + memcpy(speed, &mbx[10], 4); + memcpy(duplex, &mbx[14], 4); + } + } + KPRINT_DEBUG2("mailbox write with ACK or NACK %d msgbuff %x %x\n", ret, mbx[0], mbx[4]); + } else { + KPRINT_DEBUG2("mailbox write failed"); + } +} + +/** + * tc956xmac_mbx_get_umac_addr + * + * \brief API to get mac address + * + * \details This function is used to get mac address from PF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] reg_n - register index + * \param[out] addr - mac address + * + * \return None + */ +static void tc956xmac_mbx_get_umac_addr(struct tc956xmac_priv *priv, + unsigned char *addr, unsigned int reg_n) +{ + u8 mbx[MBX_TOT_SIZE]; + int ret; + enum mbx_msg_fns msg_dst = priv->fn_id_info.pf_no + 1; + + if (priv == NULL || addr == NULL) { + KPRINT_DEBUG2("NULL pointer error\n"); + return; + } + + mbx[0] = OPCODE_MBX_GET_UMAC_ADDR; + mbx[1] = SIZE_GET_UMAC_ADDR; + + memcpy(&mbx[2], ®_n, SIZE_GET_UMAC_ADDR); + ret = tc956xmac_mbx_write(priv, mbx, msg_dst, &priv->fn_id_info); + if (ret > 0) { + if (ret == ACK) { + if ((mbx[4] == OPCODE_MBX_ACK_MSG) && (mbx[5] == SIZE_MBX_VF_MAC)) { + memcpy(addr, &mbx[6], SIZE_MBX_VF_MAC); + } + } + KPRINT_DEBUG2("mailbox write with ACK or NACK %d msgbuff %x %x\n" + , ret, mbx[0], mbx[4]); + } else + KPRINT_DEBUG2("mailbox write failed"); +} + +/** + * tc956xmac_mbx_set_umac_addr + * + * \brief API to add mac address to register + * + * \details This function is used to send mac address to PF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] reg_n - register index + * \param[in] addr - mac address + * + * \return error/success + */ +static int tc956xmac_mbx_set_umac_addr(struct tc956xmac_priv *priv, unsigned char *addr, unsigned int reg_n) +{ + u8 mbx[MBX_TOT_SIZE]; + int ret = 0; + enum mbx_msg_fns msg_dst = priv->fn_id_info.pf_no + 1; + + if (priv == NULL || addr == NULL) { + KPRINT_DEBUG2("NULL pointer error\n"); + return -EFAULT; + } + + mbx[0] = OPCODE_MBX_ADD_MAC_ADDR; + mbx[1] = SIZE_SET_UMAC_ADDR; + + memcpy(&mbx[2], addr, SIZE_MBX_VF_MAC); + memcpy(&mbx[8], ®_n, 4); + + ret = tc956xmac_mbx_write(priv, mbx, msg_dst, &priv->fn_id_info); + if (ret > 0) { + KPRINT_DEBUG2("mailbox write with ACK or NACK %d msgbuff %x, %x\n" + , ret, mbx[0], mbx[4]); + } else + KPRINT_DEBUG2("mailbox write failed"); + + return ret; +} + +/** + * tc956xmac_vf_ioctl_reg_wr + * + * \brief API to write value to register + * + * \details This function is used to send register value to set in PF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] data - input adata from ioctl call + * + * \return success/error + */ +static int tc956xmac_vf_ioctl_reg_wr(struct tc956xmac_priv *priv, + void __user *data) +{ + struct tc956xmac_ioctl_reg_rd_wr ioctl_data; + u32 val; + u8 mbx[MBX_TOT_SIZE]; + enum mbx_msg_fns msg_dst = priv->fn_id_info.pf_no + 1; + int ret; + + DBGPR_FUNC(priv->device, "-->%s\n", __func__); + + if (priv == NULL || data == NULL) { + KPRINT_DEBUG2("NULL pointer error\n"); + return -EFAULT; + } + + if (copy_from_user(&ioctl_data, data, sizeof(ioctl_data))) + return -EFAULT; + + if (copy_from_user(&val, ioctl_data.ptr, sizeof(unsigned int))) + return -EFAULT; + + mbx[0] = OPCODE_MBX_VF_IOCTL; /*opcode for ioctl*/ + mbx[1] = SIZE_MBX_VF_REG_WR; /*size*/ + mbx[2] = ioctl_data.cmd; + memcpy(&mbx[3], (u8 *)&ioctl_data.bar_num, sizeof(ioctl_data.bar_num)); + memcpy(&mbx[7], (u8 *)&ioctl_data.addr, sizeof(ioctl_data.addr)); + memcpy(&mbx[11], (u8 *)&val, sizeof(val)); + + ret = tc956xmac_mbx_write(priv, mbx, msg_dst, &priv->fn_id_info); + if (ret > 0) + KPRINT_DEBUG2("mailbox write with ACK or NACK %d msgbuff %x %x\n", + ret, mbx[0], mbx[4]); + else { + KPRINT_DEBUG2("mailbox write failed"); + return ret; + } + + return 0; +} + +/** + * tc956xmac_vf_ioctl_get_connected_speed + * + * \brief API to get link speed + * + * \details This function is used to get link speed from PF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[out] data - data to ioctl call + * + * \return success/error + */ +static int tc956xmac_vf_ioctl_get_connected_speed(struct tc956xmac_priv *priv, + void __user *data) +{ + struct tc956xmac_ioctl_speed ioctl_data; + u8 mbx[MBX_TOT_SIZE]; + enum mbx_msg_fns msg_dst = priv->fn_id_info.pf_no + 1; + int ret; + + memset(&ioctl_data, 0, sizeof(ioctl_data)); + + DBGPR_FUNC(priv->device, "-->%s\n", __func__); + + if (priv == NULL || data == NULL) { + KPRINT_DEBUG2("NULL pointer error\n"); + return -EFAULT; + } + + if (copy_from_user(&ioctl_data, data, sizeof(ioctl_data))) + return -EFAULT; + + mbx[0] = OPCODE_MBX_VF_IOCTL; /*opcode for ioctl*/ + mbx[1] = SIZE_MBX_VF_SPEED; /*size*/ + mbx[2] = ioctl_data.cmd;/*cmd for get_speed*/ + + + ret = tc956xmac_mbx_write(priv, mbx, msg_dst, &priv->fn_id_info); + + /* Validation of successfull message posting can be done + * by reading the mbx buffer for ACK opcode (0xFE) + */ + if (ret > 0) { + if (ret == ACK) { + if ((mbx[4] == OPCODE_MBX_ACK_MSG) && (mbx[5] == sizeof(ioctl_data.connected_speed))) + memcpy(&ioctl_data.connected_speed, &mbx[6], sizeof(ioctl_data.connected_speed)); + } + KPRINT_DEBUG2("mailbox write with ACK or NACK %d msgbuff %x %x\n", ret, mbx[0], mbx[4]); + } else { + KPRINT_DEBUG2("mailbox write failed"); + return ret; + } + + if (copy_to_user(data, &ioctl_data, sizeof(ioctl_data))) + return -EFAULT; + + DBGPR_FUNC(priv->device, "<--%s\n", __func__); + return 0; +} + +/** + * tc956xmac_vf_ioctl_set_cbs + * + * \brief API to set cbs values for queue + * + * \details This function is used to set cbs values for queue to PF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] data - input data from ioctl call + * + * \return success/error + */ +static int tc956xmac_vf_ioctl_set_cbs(struct tc956xmac_priv *priv, + void __user *data) +{ + u8 mbx[MBX_TOT_SIZE]; + u8 mbx_loc[MBX_TOT_SIZE * 2], seq = 0, ack = 0; + int ret; + enum mbx_msg_fns msg_dst = priv->fn_id_info.pf_no + 1; + + u32 tx_qcount = priv->plat->tx_queues_to_use; + struct tc956xmac_ioctl_cbs_cfg cbs; + u8 qmode; + + DBGPR_FUNC(priv->device, "-->%s\n", __func__); + + if (priv == NULL || data == NULL) { + KPRINT_DEBUG2("NULL pointer error\n"); + return -EFAULT; + } + + if (copy_from_user(&cbs, data, sizeof(cbs))) + return -EFAULT; + + if ((cbs.queue_idx >= tx_qcount) || (cbs.queue_idx == 0)) + return -EINVAL; + + if (!priv->hw->mac->config_cbs) + return -EINVAL; + + qmode = priv->plat->tx_queues_cfg[cbs.queue_idx].mode_to_use; + + if (qmode != MTL_QUEUE_AVB) + return -EINVAL; + + memcpy(&mbx_loc[0], (u8 *)&cbs.speed100cfg.send_slope, sizeof(cbs.speed100cfg.send_slope)); + memcpy(&mbx_loc[4], (u8 *)&cbs.speed100cfg.idle_slope, sizeof(cbs.speed100cfg.idle_slope)); + memcpy(&mbx_loc[8], (u8 *)&cbs.speed100cfg.high_credit, sizeof(cbs.speed100cfg.high_credit)); + memcpy(&mbx_loc[12], (u8 *)&cbs.speed100cfg.low_credit, sizeof(cbs.speed100cfg.low_credit)); + memcpy(&mbx_loc[16], (u8 *)&cbs.speed100cfg.percentage, sizeof(cbs.speed100cfg.percentage)); + + memcpy(&mbx_loc[20], (u8 *)&cbs.speed1000cfg.send_slope, sizeof(cbs.speed1000cfg.send_slope)); + memcpy(&mbx_loc[24], (u8 *)&cbs.speed1000cfg.idle_slope, sizeof(cbs.speed1000cfg.idle_slope)); + memcpy(&mbx_loc[28], (u8 *)&cbs.speed1000cfg.high_credit, sizeof(cbs.speed1000cfg.high_credit)); + memcpy(&mbx_loc[32], (u8 *)&cbs.speed1000cfg.low_credit, sizeof(cbs.speed1000cfg.low_credit)); + memcpy(&mbx_loc[36], (u8 *)&cbs.speed1000cfg.percentage, sizeof(cbs.speed1000cfg.percentage)); + + memcpy(&mbx_loc[40], (u8 *)&cbs.speed10000cfg.send_slope, sizeof(cbs.speed10000cfg.send_slope)); + memcpy(&mbx_loc[44], (u8 *)&cbs.speed10000cfg.idle_slope, sizeof(cbs.speed10000cfg.idle_slope)); + memcpy(&mbx_loc[48], (u8 *)&cbs.speed10000cfg.high_credit, sizeof(cbs.speed10000cfg.high_credit)); + memcpy(&mbx_loc[52], (u8 *)&cbs.speed10000cfg.low_credit, sizeof(cbs.speed10000cfg.low_credit)); + memcpy(&mbx_loc[56], (u8 *)&cbs.speed10000cfg.percentage, sizeof(cbs.speed10000cfg.percentage)); + + memcpy(&mbx_loc[60], (u8 *)&cbs.speed5000cfg.send_slope, sizeof(cbs.speed5000cfg.send_slope)); + memcpy(&mbx_loc[64], (u8 *)&cbs.speed5000cfg.idle_slope, sizeof(cbs.speed5000cfg.idle_slope)); + memcpy(&mbx_loc[68], (u8 *)&cbs.speed5000cfg.high_credit, sizeof(cbs.speed5000cfg.high_credit)); + memcpy(&mbx_loc[72], (u8 *)&cbs.speed5000cfg.low_credit, sizeof(cbs.speed5000cfg.low_credit)); + memcpy(&mbx_loc[76], (u8 *)&cbs.speed5000cfg.percentage, sizeof(cbs.speed5000cfg.percentage)); + + memcpy(&mbx_loc[80], (u8 *)&cbs.speed2500cfg.send_slope, sizeof(cbs.speed2500cfg.send_slope)); + memcpy(&mbx_loc[84], (u8 *)&cbs.speed2500cfg.idle_slope, sizeof(cbs.speed2500cfg.idle_slope)); + memcpy(&mbx_loc[88], (u8 *)&cbs.speed2500cfg.high_credit, sizeof(cbs.speed2500cfg.high_credit)); + memcpy(&mbx_loc[92], (u8 *)&cbs.speed2500cfg.low_credit, sizeof(cbs.speed2500cfg.low_credit)); + memcpy(&mbx_loc[96], (u8 *)&cbs.speed2500cfg.percentage, sizeof(cbs.speed2500cfg.percentage)); + + mbx[0] = OPCODE_MBX_VF_IOCTL; + mbx[1] = SIZE_MBX_SET_GET_CBS_1; + mbx[2] = TC956XMAC_SET_CBS_1; + mbx[3] = cbs.queue_idx; + + memcpy(&mbx[4], &mbx_loc[0], SIZE_MBX_SET_GET_CBS_1); + ret = tc956xmac_mbx_write(priv, mbx, msg_dst, &priv->fn_id_info); + if (ret > 0) { + ack |= 1 << seq++; + KPRINT_DEBUG2("mailbox write with ACK or NACK %d msgbuff %x %x\n", + ret, mbx[0], mbx[4]); + } else + KPRINT_DEBUG2("mailbox write failed"); + + mbx[0] = OPCODE_MBX_VF_IOCTL; + mbx[1] = SIZE_MBX_SET_GET_CBS_2; + mbx[2] = TC956XMAC_SET_CBS_2; + mbx[3] = cbs.queue_idx; + + memcpy(&mbx[4], &mbx_loc[SIZE_MBX_SET_GET_CBS_1], SIZE_MBX_SET_GET_CBS_2); + ret = tc956xmac_mbx_write(priv, mbx, msg_dst, &priv->fn_id_info); + if (ret > 0) { + ack |= 1 << seq; + KPRINT_DEBUG2("mailbox write with ACK or NACK %d msgbuff %x %x\n", + ret, mbx[0], mbx[4]); + } else + KPRINT_DEBUG2("mailbox write failed"); + + if (ack == 0x3) { + return 0; + } else + return -EFAULT; +} + +/** + * tc956xmac_vf_ioctl_get_cbs + * + * \brief API to get cbs values for queue + * + * \details This function is used to get cbs values for queue from PF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[out] data - data to ioctl call + * + * \return success/error + */ +static int tc956xmac_vf_ioctl_get_cbs(struct tc956xmac_priv *priv, + void __user *data) +{ + /* Prepare mailbox message and call mailbox API for posting + * and getting the ACK + */ + u8 mbx[MBX_TOT_SIZE]; + u8 mbx_loc[MBX_TOT_SIZE * 2], seq = 0, ack = 0; + + int ret; + enum mbx_msg_fns msg_dst = priv->fn_id_info.pf_no + 1; + + u32 tx_qcount = priv->plat->tx_queues_to_use; + struct tc956xmac_ioctl_cbs_cfg cbs; + + DBGPR_FUNC(priv->device, "-->%s\n", __func__); + + if (priv == NULL || data == NULL) { + KPRINT_DEBUG2("NULL pointer error\n"); + return -EFAULT; + } + + if (copy_from_user(&cbs, data, sizeof(cbs))) + return -EFAULT; + if (cbs.queue_idx >= tx_qcount) + return -EINVAL; + + mbx[0] = OPCODE_MBX_VF_IOCTL; + mbx[1] = SIZE_MBX_VF_GET_CBS; + mbx[2] = TC956XMAC_GET_CBS_1; + mbx[3] = cbs.queue_idx; + + ret = tc956xmac_mbx_write(priv, mbx, msg_dst, &priv->fn_id_info); + if (ret > 0) { + if (ret == ACK) { + if ((mbx[4] == OPCODE_MBX_ACK_MSG) && (mbx[5] == SIZE_MBX_SET_GET_CBS_1)) { + ack |= 1 << seq++; + memcpy(&mbx_loc[0], &mbx[6], SIZE_MBX_SET_GET_CBS_1); + } + } + KPRINT_DEBUG2("mailbox write with ACK or NACK %d msgbuff %x %x\n", ret, mbx[0], mbx[4]); + } else + KPRINT_DEBUG2("mailbox write failed"); + + mbx[0] = OPCODE_MBX_VF_IOCTL; + mbx[1] = SIZE_MBX_VF_GET_CBS; + mbx[2] = TC956XMAC_GET_CBS_2; + mbx[3] = cbs.queue_idx; + + ret = tc956xmac_mbx_write(priv, mbx, msg_dst, &priv->fn_id_info); + if (ret > 0) { + if (ret == ACK) { + if ((mbx[4] == OPCODE_MBX_ACK_MSG) && (mbx[5] == SIZE_MBX_SET_GET_CBS_2)) { + ack |= 1 << seq; + memcpy(&mbx_loc[SIZE_MBX_SET_GET_CBS_1], &mbx[6], SIZE_MBX_SET_GET_CBS_2); + } + } + KPRINT_DEBUG2("mailbox write with ACK or NACK %d msgbuff %x %x\n", ret, mbx[0], mbx[4]); + } else + KPRINT_DEBUG2("mailbox write failed"); + + if (ack == 0x3) { + memcpy(&cbs.speed100cfg.send_slope, &mbx_loc[0], sizeof(cbs.speed100cfg.send_slope)); + memcpy(&cbs.speed100cfg.idle_slope, &mbx_loc[4], sizeof(cbs.speed100cfg.idle_slope)); + memcpy(&cbs.speed100cfg.high_credit, &mbx_loc[8], sizeof(cbs.speed100cfg.high_credit)); + memcpy(&cbs.speed100cfg.low_credit, &mbx_loc[12], sizeof(cbs.speed100cfg.low_credit)); + memcpy(&cbs.speed100cfg.percentage, &mbx_loc[16], sizeof(cbs.speed100cfg.percentage)); + + memcpy(&cbs.speed1000cfg.send_slope, &mbx_loc[20], sizeof(cbs.speed1000cfg.send_slope)); + memcpy(&cbs.speed1000cfg.idle_slope, &mbx_loc[24], sizeof(cbs.speed1000cfg.idle_slope)); + memcpy(&cbs.speed1000cfg.high_credit, &mbx_loc[28], sizeof(cbs.speed1000cfg.high_credit)); + memcpy(&cbs.speed1000cfg.low_credit, &mbx_loc[32], sizeof(cbs.speed1000cfg.low_credit)); + memcpy(&cbs.speed1000cfg.percentage, &mbx_loc[36], sizeof(cbs.speed1000cfg.percentage)); + + memcpy(&cbs.speed10000cfg.send_slope, &mbx_loc[40], sizeof(cbs.speed10000cfg.send_slope)); + memcpy(&cbs.speed10000cfg.idle_slope, &mbx_loc[44], sizeof(cbs.speed10000cfg.idle_slope)); + memcpy(&cbs.speed10000cfg.high_credit, &mbx_loc[48], sizeof(cbs.speed10000cfg.high_credit)); + memcpy(&cbs.speed10000cfg.low_credit, &mbx_loc[52], sizeof(cbs.speed10000cfg.low_credit)); + memcpy(&cbs.speed10000cfg.percentage, &mbx_loc[56], sizeof(cbs.speed10000cfg.percentage)); + + memcpy(&cbs.speed5000cfg.send_slope, &mbx_loc[60], sizeof(cbs.speed5000cfg.send_slope)); + memcpy(&cbs.speed5000cfg.idle_slope, &mbx_loc[64], sizeof(cbs.speed5000cfg.idle_slope)); + memcpy(&cbs.speed5000cfg.high_credit, &mbx_loc[68], sizeof(cbs.speed5000cfg.high_credit)); + memcpy(&cbs.speed5000cfg.low_credit, &mbx_loc[72], sizeof(cbs.speed5000cfg.low_credit)); + memcpy(&cbs.speed5000cfg.percentage, &mbx_loc[76], sizeof(cbs.speed5000cfg.percentage)); + + memcpy(&cbs.speed2500cfg.send_slope, &mbx_loc[80], sizeof(cbs.speed2500cfg.send_slope)); + memcpy(&cbs.speed2500cfg.idle_slope, &mbx_loc[84], sizeof(cbs.speed2500cfg.idle_slope)); + memcpy(&cbs.speed2500cfg.high_credit, &mbx_loc[88], sizeof(cbs.speed2500cfg.high_credit)); + memcpy(&cbs.speed2500cfg.low_credit, &mbx_loc[92], sizeof(cbs.speed2500cfg.low_credit)); + memcpy(&cbs.speed2500cfg.percentage, &mbx_loc[96], sizeof(cbs.speed2500cfg.percentage)); + } else + return -EFAULT; + + if (copy_to_user(data, &cbs, sizeof(cbs))) + return -EFAULT; + + DBGPR_FUNC(priv->device, "<--%s\n", __func__); + + return 0; +} + +/** + * tc956xmac_vf_ioctl_set_est + * + * \brief API to add est entries + * + * \details This function is used to send add est entries to PF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] data - input data from ioctl call + * + * \return success/error + */ +static int tc956xmac_vf_ioctl_set_est(struct tc956xmac_priv *priv, + void __user *data) +{ + u8 mbx[MBX_TOT_SIZE]; + u8 mbx_loc[MBX_MSG_SIZE * 10]; + int ret = 0, offset = 1, total_size; + enum mbx_msg_fns msg_dst = priv->fn_id_info.pf_no + 1; + u32 opcode, rem_gcl_cnt, msg_size; + struct tc956xmac_ioctl_est_cfg *est; + + if (!priv->plat->tsn_application) + return -EFAULT; + + DBGPR_FUNC(priv->device, "-->%s\n", __func__); + + if (priv == NULL || data == NULL) { + KPRINT_DEBUG2("NULL pointer error\n"); + return -EFAULT; + } + + est = kzalloc(sizeof(*est), GFP_KERNEL); + if (!est) + return -ENOMEM; + + if (copy_from_user(est, data, sizeof(struct tc956xmac_ioctl_est_cfg))) { + ret = -EINVAL; + goto out_free; + } + + if (est->gcl_size > TC956XMAC_IOCTL_EST_GCL_MAX_ENTRIES) { + ret = -EINVAL; + goto out_free; + } + + if (est->enabled) { + memcpy(&mbx_loc[0], (u8 *)&est->enabled, sizeof(est->enabled)); + memcpy(&mbx_loc[4], (u8 *)&est->btr_offset[0], sizeof(est->btr_offset)); + memcpy(&mbx_loc[12], (u8 *)&est->ctr[0], sizeof(est->ctr)); + memcpy(&mbx_loc[20], (u8 *)&est->ter, sizeof(est->ter)); + memcpy(&mbx_loc[24], (u8 *)&est->gcl_size, sizeof(est->gcl_size)); + memcpy(&mbx_loc[28], (u8 *)&est->gcl, (est->gcl_size * sizeof(*est->gcl))); + + total_size = (est->gcl_size * sizeof(*est->gcl)) + EST_FIX_MSG_LEN; + msg_size = est->gcl_size >= ((SIZE_MBX_SET_GET_EST_1 - EST_FIX_MSG_LEN) / sizeof(est->gcl_size)) ? + SIZE_MBX_SET_GET_EST_1 : ((est->gcl_size * sizeof(*est->gcl)) + EST_FIX_MSG_LEN); + + mbx[0] = OPCODE_MBX_VF_IOCTL; + mbx[1] = msg_size; + mbx[2] = TC956XMAC_SET_EST_1; + memcpy(&mbx[3], &mbx_loc[0], mbx[1]); + + ret = tc956xmac_mbx_write(priv, mbx, msg_dst, &priv->fn_id_info); + if (ret > 0) { + KPRINT_DEBUG2("mailbox write with ACK or NACK %d msgbuff %x %x\n", + ret, mbx[0], mbx[4]); + } else { + KPRINT_DEBUG2("mailbox write failed"); + goto out_free; + } + + opcode = TC956XMAC_SET_EST_1; + total_size -= msg_size; + rem_gcl_cnt = est->gcl_size > ((SIZE_MBX_SET_GET_EST_1 - EST_FIX_MSG_LEN) / sizeof(est->gcl_size)) ? + (est->gcl_size - ((SIZE_MBX_SET_GET_EST_1 - EST_FIX_MSG_LEN) / sizeof(est->gcl_size))) : 0; + + while (total_size > 0) { + msg_size = rem_gcl_cnt >= MAX_SIZE_GCL_MSG ? SIZE_MBX_SET_GET_EST_1 : (rem_gcl_cnt * sizeof(*est->gcl)); + opcode += 1; + mbx[0] = OPCODE_MBX_VF_IOCTL; + mbx[1] = msg_size; + mbx[2] = opcode; + + memcpy(&mbx[3], &mbx_loc[offset * SIZE_MBX_SET_GET_EST_1], msg_size); + ret = tc956xmac_mbx_write(priv, mbx, msg_dst, &priv->fn_id_info); + if (ret > 0) { + KPRINT_DEBUG2("mailbox write with ACK or NACK %d msgbuff %x %x\n", + ret, mbx[0], mbx[4]); + } else { + KPRINT_DEBUG2("mailbox write failed"); + goto out_free; + } + + total_size -= msg_size; + rem_gcl_cnt = rem_gcl_cnt > MAX_SIZE_GCL_MSG ? (rem_gcl_cnt - MAX_SIZE_GCL_MSG) : 0; + offset++; + } + ret = 0; + } + +out_free: + kfree(est); + + return ret; +} + +/** + * tc956xmac_vf_ioctl_get_est + * + * \brief API to get est entries + * + * \details This function is used to get est entries from PF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[out] data - data to ioctl call + * + * \return success/error + */ +static int tc956xmac_vf_ioctl_get_est(struct tc956xmac_priv *priv, void __user *data) +{ + u8 mbx[MBX_TOT_SIZE]; + u8 mbx_loc[MBX_MSG_SIZE * 10]; + u16 msg_size, total_msg_size = 0; + int ret, offset = 0; + enum mbx_msg_fns msg_dst = priv->fn_id_info.pf_no + 1; + u32 gcl_size = 0, opcode; + struct tc956xmac_ioctl_est_cfg *est; + + if (!priv->plat->tsn_application) + return -EFAULT; + + DBGPR_FUNC(priv->device, "-->%s\n", __func__); + + if (priv == NULL || data == NULL) { + KPRINT_DEBUG2("NULL pointer error\n"); + return -EFAULT; + } + + est = kzalloc(sizeof(*est), GFP_KERNEL); + if (!est) + return -ENOMEM; + + opcode = TC956XMAC_GET_EST_1; + + do { + mbx[0] = OPCODE_MBX_VF_IOCTL; + mbx[1] = SIZE_MBX_VF_GET_EST; + mbx[2] = opcode++; + + ret = tc956xmac_mbx_write(priv, mbx, msg_dst, &priv->fn_id_info); + if (ret > 0) { + if (ret == ACK) { + if (mbx[4] == OPCODE_MBX_ACK_MSG) { + msg_size = mbx[5]; + memcpy(&mbx_loc[offset], &mbx[6], msg_size); + offset += msg_size; + if ((opcode - 1) == TC956XMAC_GET_EST_1) { + memcpy(&est->enabled, &mbx_loc[0], sizeof(est->enabled)); + memcpy(&est->estwid, &mbx_loc[4], sizeof(est->estwid)); + memcpy(&est->estdep, &mbx_loc[8], sizeof(est->estdep)); + memcpy(&est->btr_offset[0], &mbx_loc[12], sizeof(est->btr_offset)); + memcpy(&est->ctr[0], &mbx_loc[20], sizeof(est->ctr)); + memcpy(&est->ter, &mbx_loc[28], sizeof(est->ter)); + memcpy(&est->gcl_size, &mbx_loc[32], sizeof(est->gcl_size)); + + gcl_size = est->gcl_size * sizeof(*est->gcl); + total_msg_size = gcl_size + EST_FIX_MSG_LEN + 8; //8 due to estwid and estdep + } + } + } + KPRINT_DEBUG2("mailbox write with ACK or NACK %d msgbuff %x %x\n", ret, mbx[0], mbx[4]); + } else { + KPRINT_DEBUG2("mailbox write failed"); + goto out_free; + } + } while (offset != total_msg_size); + + memcpy(&est->gcl, &mbx_loc[36], est->gcl_size * sizeof(*est->gcl)); + ret = 0; + + if (copy_to_user(data, est, sizeof(struct tc956xmac_ioctl_est_cfg))) { + goto out_free; + ret = -EFAULT; + } + +out_free: + kfree(est); + + return ret; +} + +/** + * tc956xmac_vf_ioctl_set_fpe + * + * \brief API to set fpe param + * + * \details This function is used to send fpe param to PF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] data - input data from ioctl call + * + * \return success/error + */ +static int tc956xmac_vf_ioctl_set_fpe(struct tc956xmac_priv *priv, void __user *data) +{ + u8 mbx[MBX_TOT_SIZE]; + int ret; + enum mbx_msg_fns msg_dst = priv->fn_id_info.pf_no + 1; + + struct tc956xmac_ioctl_fpe_cfg fpe; + + DBGPR_FUNC(priv->device, "-->%s\n", __func__); + + if (priv == NULL || data == NULL) { + KPRINT_DEBUG2("NULL pointer error\n"); + return -EFAULT; + } + + if (copy_from_user(&fpe, data, sizeof(struct tc956xmac_ioctl_fpe_cfg))) + return -EFAULT; + + mbx[0] = OPCODE_MBX_VF_IOCTL; + mbx[1] = SIZE_MBX_SET_GET_FPE_1; + mbx[2] = TC956XMAC_SET_FPE_1; + + memcpy(&mbx[3], (u8 *)&fpe.enabled, sizeof(fpe.enabled)); + memcpy(&mbx[7], (u8 *)&fpe.pec, sizeof(fpe.pec)); + memcpy(&mbx[11], (u8 *)&fpe.afsz, sizeof(fpe.afsz)); + memcpy(&mbx[15], (u8 *)&fpe.RA_time, sizeof(fpe.RA_time)); + memcpy(&mbx[19], (u8 *)&fpe.HA_time, sizeof(fpe.RA_time)); + + ret = tc956xmac_mbx_write(priv, mbx, msg_dst, &priv->fn_id_info); + if (ret > 0) { + KPRINT_DEBUG2("mailbox write with ACK or NACK %d msgbuff %x %x\n", + ret, mbx[0], mbx[4]); + } else { + KPRINT_DEBUG2("mailbox write failed"); + return -EFAULT; + } + + return 0; +} + +/** + * tc956xmac_vf_ioctl_get_fpe + * + * \brief API to get fpe parametrs + * + * \details This function is used to get fpe param from PF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[out] data - data to ioctl call + * + * \return success/error + */ +static int tc956xmac_vf_ioctl_get_fpe(struct tc956xmac_priv *priv, void __user *data) +{ + /* Prepare mailbox message and call mailbox API for posting + * and getting the ACK + */ + u8 mbx[MBX_TOT_SIZE]; + int ret; + enum mbx_msg_fns msg_dst = priv->fn_id_info.pf_no + 1; + struct tc956xmac_ioctl_fpe_cfg fpe; + + DBGPR_FUNC(priv->device, "-->%s\n", __func__); + + if (priv == NULL || data == NULL) { + KPRINT_DEBUG2("NULL pointer error\n"); + return -EFAULT; + } + + mbx[0] = OPCODE_MBX_VF_IOCTL; + mbx[1] = SIZE_MBX_VF_GET_FPE; + mbx[2] = TC956XMAC_GET_FPE_1; + + ret = tc956xmac_mbx_write(priv, mbx, msg_dst, &priv->fn_id_info); + if (ret > 0) { + if (ret == ACK) { + if ((mbx[4] == OPCODE_MBX_ACK_MSG) && (mbx[5] == SIZE_MBX_SET_GET_FPE_1)) { + memcpy(&fpe.enabled, &mbx[6], sizeof(fpe.enabled)); + memcpy(&fpe.pec, &mbx[10], sizeof(fpe.pec)); + memcpy(&fpe.afsz, &mbx[14], sizeof(fpe.afsz)); + memcpy(&fpe.RA_time, &mbx[18], sizeof(fpe.RA_time)); + memcpy(&fpe.HA_time, &mbx[22], sizeof(fpe.HA_time)); + } + } + KPRINT_DEBUG2("mailbox write with ACK or NACK %d msgbuff %x %x\n", ret, mbx[0], mbx[4]); + } else { + KPRINT_DEBUG2("mailbox write failed"); + return -EFAULT; + } + + if (copy_to_user(data, &fpe, sizeof(struct tc956xmac_ioctl_fpe_cfg))) + return -EFAULT; + + DBGPR_FUNC(priv->device, "<--%s\n", __func__); + + return 0; +} + +/** + * tc956xmac_vf_ioctl_set_rxp + * + * \brief API to set frp entries + * + * \details This function is used to send frp entries to PF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] data - input data from ioctl call + * + * \return success/error + */ +static int tc956xmac_vf_ioctl_set_rxp(struct tc956xmac_priv *priv, void __user *data) +{ + u8 mbx[MBX_TOT_SIZE]; + u8 *mbx_loc; //sizeof(struct tc956xmac_ioctl_rxp_cfg) + int ret = 0, offset = 1, total_size; + enum mbx_msg_fns msg_dst = priv->fn_id_info.pf_no + 1; + u32 opcode, msg_size; + struct tc956xmac_ioctl_rxp_cfg *rxp; + + DBGPR_FUNC(priv->device, "-->%s\n", __func__); + + if (priv == NULL || data == NULL) { + KPRINT_DEBUG2("NULL pointer error\n"); + return -EFAULT; + } + + rxp = kzalloc(sizeof(*rxp), GFP_KERNEL); + if (!rxp) + return -ENOMEM; + + mbx_loc = kzalloc(sizeof(*rxp), GFP_KERNEL); + if (!mbx_loc) { + ret = -ENOMEM; + goto out_free; + } + + if (copy_from_user(rxp, data, sizeof(struct tc956xmac_ioctl_rxp_cfg))) { + return -EINVAL; + } + + if (rxp->nve > TC956XMAC_RX_PARSER_MAX_ENTRIES) { + return -EINVAL; + } + + if (rxp->enabled) { + memcpy(&mbx_loc[0], (u8 *)&rxp->frpes, sizeof(rxp->frpes)); + memcpy(&mbx_loc[4], (u8 *)&rxp->enabled, sizeof(rxp->enabled)); + memcpy(&mbx_loc[8], (u8 *)&rxp->nve, sizeof(rxp->nve)); + memcpy(&mbx_loc[12], (u8 *)&rxp->npe, sizeof(rxp->npe)); + memcpy(&mbx_loc[16], (u8 *)&rxp->entries, (rxp->nve * sizeof(*rxp->entries))); + + total_size = (rxp->nve * sizeof(*rxp->entries)) + RXP_FIX_MSG_LEN; + msg_size = total_size >= SIZE_MBX_SET_GET_RXP_1 ? SIZE_MBX_SET_GET_RXP_1 : total_size; + + mbx[0] = OPCODE_MBX_VF_IOCTL; + mbx[1] = msg_size; + mbx[2] = TC956XMAC_SET_RXP_1; + + memcpy(&mbx[3], &mbx_loc[0], mbx[1]); + + ret = tc956xmac_mbx_write(priv, mbx, msg_dst, &priv->fn_id_info); + if (ret > 0) { + KPRINT_DEBUG2("mailbox write with ACK or NACK %d msgbuff %x %x\n", + ret, mbx[0], mbx[4]); + } else { + KPRINT_DEBUG2("mailbox write failed"); + goto out_free; + } + + opcode = TC956XMAC_SET_RXP_1; + total_size -= msg_size; + + while (total_size > 0) { + msg_size = total_size >= SIZE_MBX_SET_GET_RXP_1 ? SIZE_MBX_SET_GET_RXP_1 : total_size; + opcode += 1; + mbx[0] = OPCODE_MBX_VF_IOCTL; + mbx[1] = msg_size; + mbx[2] = opcode; + + memcpy(&mbx[3], &mbx_loc[offset * SIZE_MBX_SET_GET_RXP_1], msg_size); + ret = tc956xmac_mbx_write(priv, mbx, msg_dst, &priv->fn_id_info); + if (ret > 0) { + KPRINT_DEBUG2("mailbox write with ACK or NACK %d msgbuff %x %x\n", + ret, mbx[0], mbx[4]); + } else { + KPRINT_DEBUG2("mailbox write failed"); + goto out_free; + } + + total_size -= msg_size; + offset++; + } + ret = 0; + } + +out_free: + kfree(rxp); + kfree(mbx_loc); + return ret; +} + +/** + * tc956xmac_vf_ioctl_get_rxp + * + * \brief API to get frp entries + * + * \details This function is used to get frp entries from PF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[out] data - data to ioctl call + * + * \return success/error + */ +static int tc956xmac_vf_ioctl_get_rxp(struct tc956xmac_priv *priv, void __user *data) +{ + u8 mbx[MBX_TOT_SIZE]; + u8 *mbx_loc; + u16 msg_size, total_msg_size = 0; + int ret, offset = 0; + enum mbx_msg_fns msg_dst = priv->fn_id_info.pf_no + 1; + u32 rxp_size = 0, opcode; + struct tc956xmac_ioctl_rxp_cfg *rxp; + + DBGPR_FUNC(priv->device, "-->%s\n", __func__); + + if (priv == NULL || data == NULL) { + KPRINT_DEBUG2("NULL pointer error\n"); + return -EFAULT; + } + + rxp = kzalloc(sizeof(*rxp), GFP_KERNEL); + if (!rxp) + return -ENOMEM; + + mbx_loc = kzalloc(sizeof(*rxp), GFP_KERNEL); + if (!mbx_loc) { + ret = -ENOMEM; + goto out_free; + } + opcode = TC956XMAC_GET_RXP_1; + + do { + mbx[0] = OPCODE_MBX_VF_IOCTL; + mbx[1] = SIZE_MBX_VF_GET_RXP; + mbx[2] = opcode++; + + ret = tc956xmac_mbx_write(priv, mbx, msg_dst, &priv->fn_id_info); + if (ret > 0) { + if (ret == ACK) { + if (mbx[4] == OPCODE_MBX_ACK_MSG) { + msg_size = mbx[5]; + memcpy(&mbx_loc[offset], &mbx[6], msg_size); + offset += msg_size; + if ((opcode - 1) == TC956XMAC_GET_RXP_1) { + memcpy(&rxp->frpes, &mbx_loc[0], sizeof(rxp->frpes)); + memcpy(&rxp->enabled, &mbx_loc[4], sizeof(rxp->enabled)); + memcpy(&rxp->nve, &mbx_loc[8], sizeof(rxp->nve)); + memcpy(&rxp->npe, &mbx_loc[12], sizeof(rxp->npe)); + rxp_size = rxp->nve * sizeof(*rxp->entries); + total_msg_size = rxp_size + RXP_FIX_MSG_LEN; + } + } + } + KPRINT_DEBUG2("mailbox write with ACK or NACK %d msgbuff %x %x\n", ret, mbx[0], mbx[4]); + } else { + KPRINT_DEBUG2("mailbox write failed"); + goto out_free; + } + } while (offset != total_msg_size); + + memcpy(&rxp->entries[0], &mbx_loc[16], rxp->nve * sizeof(*rxp->entries)); + ret = 0; + + if (copy_to_user(data, rxp, sizeof(struct tc956xmac_ioctl_rxp_cfg))) { + goto out_free; + ret = -EFAULT; + } + +out_free: + kfree(rxp); + kfree(mbx_loc); + return ret; +} + +/** + * tc956xmac_vf_ethtool_get_pauseparam + * + * \brief API to get pauseparameters + * + * \details This function is used to get ethtool pauseparam from PF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[out] pause - pause parameters + * + * \return success/error + */ +static int tc956xmac_vf_ethtool_get_pauseparam(struct tc956xmac_priv *priv, + struct ethtool_pauseparam *pause) +{ + u8 mbx[MBX_TOT_SIZE]; + int ret; + enum mbx_msg_fns msg_dst = priv->fn_id_info.pf_no + 1; + + DBGPR_FUNC(priv->device, "-->%s\n", __func__); + + if (priv == NULL || pause == NULL) { + KPRINT_DEBUG2("NULL pointer error\n"); + return -EFAULT; + } + + mbx[0] = OPCODE_MBX_VF_ETHTOOL; + mbx[1] = SIZE_MBX_VF_PAUSE_PARAM; + mbx[2] = OPCODE_MBX_VF_GET_PAUSE_PARAM; + + ret = tc956xmac_mbx_write(priv, mbx, msg_dst, &priv->fn_id_info); + if (ret > 0) { + if (ret == ACK) { + mbx[0] = OPCODE_MBX_VF_ETHTOOL; + mbx[1] = SIZE_MBX_VF_PAUSE_PARAM; + mbx[2] = OPCODE_MBX_VF_GET_PAUSE_PARAM_2; + + ret = tc956xmac_mbx_write(priv, mbx, msg_dst, &priv->fn_id_info); + if (ret > 0) { + if (ret == ACK) { + if ((mbx[4] == OPCODE_MBX_ACK_MSG) && + (mbx[5] == sizeof(struct ethtool_pauseparam))) { + memcpy(pause, &mbx[6], sizeof(struct ethtool_pauseparam)); + } + } + } else { + KPRINT_DEBUG2("mailbox write failed"); + return ret; + } + } + KPRINT_DEBUG2("mailbox write with ACK or NACK %d msgbuff %x %x\n", ret, mbx[0], mbx[4]); + } else { + KPRINT_DEBUG2("mailbox write failed"); + return ret; + } + + return 0; +} + +/** + * tc956xmac_vf_ethtool_get_eee + * + * \brief API to get eee parametrs + * + * \details This function is used to get ethtool eee param from PF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[out] edata - edata parameters + * + * \return success/error + */ +static int tc956xmac_vf_ethtool_get_eee(struct tc956xmac_priv *priv, + struct ethtool_eee *edata) +{ + u8 mbx[MBX_TOT_SIZE]; + int ret; + enum mbx_msg_fns msg_dst = priv->fn_id_info.pf_no + 1; + + DBGPR_FUNC(priv->device, "-->%s\n", __func__); + + if (priv == NULL || edata == NULL) { + KPRINT_DEBUG2("NULL pointer error\n"); + return -EFAULT; + } + + mbx[0] = OPCODE_MBX_VF_ETHTOOL; + mbx[1] = SIZE_MBX_VF_EEE; + mbx[2] = OPCODE_MBX_VF_GET_EEE; + + ret = tc956xmac_mbx_write(priv, mbx, msg_dst, &priv->fn_id_info); + if (ret > 0) { + if (ret == ACK) { + if ((mbx[4] == OPCODE_MBX_ACK_MSG) && + (mbx[5] == sizeof(struct ethtool_eee))) { + memcpy(edata, &mbx[6], sizeof(struct ethtool_eee)); + } + } + KPRINT_DEBUG2("mailbox write with ACK or NACK %d msgbuff %x %x\n", ret, mbx[0], mbx[4]); + } else { + KPRINT_DEBUG2("mailbox write failed"); + return ret; + } + + return 0; +} + +/** + * tc956xmac_vf_add_mac + * + * \brief API to add mac address + * + * \details This function is used to send mac address to PF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] mac - mac address + * + * \return success/error + */ +static int tc956xmac_vf_add_mac(struct tc956xmac_priv *priv, const u8 *mac) +{ + /* Prepare mailbox message and call mailbox API for posting + * and getting the ACK + */ + u8 mbx[MBX_TOT_SIZE]; + int ret; + + enum mbx_msg_fns msg_dst = priv->fn_id_info.pf_no + 1; + + if (priv == NULL || mac == NULL) { + KPRINT_DEBUG2("NULL pointer error\n"); + return -EFAULT; + } + + mbx[0] = OPCODE_MBX_VF_ADD_MAC; + mbx[1] = SIZE_MBX_VF_MAC; + + memcpy(&mbx[2], mac, SIZE_MBX_VF_MAC); + + ret = tc956xmac_mbx_write(priv, mbx, msg_dst, &priv->fn_id_info); + if (ret > 0) + KPRINT_DEBUG2("mailbox write with ACK or NACK %d msgbuff %x %x\n", + ret, mbx[0], mbx[4]); + else { + KPRINT_DEBUG2("mailbox write failed"); + return ret; + } + + return 0; +} + +/** + * tc956xmac_vf_delete_mac + * + * \brief API to delete mac address + * + * \details This function is used to send mac address to delete to PF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] mac - mac address + * + * \return None + */ +static void tc956xmac_vf_delete_mac(struct tc956xmac_priv *priv, const u8 *mac) +{ + /* Prepare mailbox message and call mailbox API for posting + * and getting the ACK + */ + u8 mbx[MBX_TOT_SIZE]; + int ret; + + enum mbx_msg_fns msg_dst = priv->fn_id_info.pf_no + 1; + + if (priv == NULL || mac == NULL) { + KPRINT_DEBUG2("NULL pointer error\n"); + return; + } + + mbx[0] = OPCODE_MBX_VF_DELETE_MAC; + mbx[1] = SIZE_MBX_VF_MAC; + + memcpy(&mbx[2], mac, SIZE_MBX_VF_MAC); + + ret = tc956xmac_mbx_write(priv, mbx, msg_dst, &priv->fn_id_info); + if (ret > 0) + KPRINT_DEBUG2("mailbox write with ACK or NACK %d msgbuff %x %x\n", + ret, mbx[0], mbx[4]); + else + KPRINT_DEBUG2("mailbox write failed"); +} + +/** + * tc956xmac_vf_add_vlan + * + * \brief API to add vlan id + * + * \details This function is used to send vlan id to PF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] vid - vlan id + * + * \return None + */ +static void tc956xmac_vf_add_vlan(struct tc956xmac_priv *priv, u16 vid) +{ + /* Prepare mailbox message and call mailbox API for posting + * and getting the ACK + */ + u8 mbx[MBX_TOT_SIZE]; + int ret; + + enum mbx_msg_fns msg_dst = priv->fn_id_info.pf_no + 1; + + if (priv == NULL) { + KPRINT_DEBUG2("NULL pointer error\n"); + return; + } + + mbx[0] = OPCODE_MBX_VF_ADD_VLAN; + mbx[1] = SIZE_MBX_VF_VLAN; + + memcpy(&mbx[2], (u8 *)&vid, SIZE_MBX_VF_VLAN); + + ret = tc956xmac_mbx_write(priv, mbx, msg_dst, &priv->fn_id_info); + if (ret > 0) + KPRINT_DEBUG2("mailbox write with ACK or NACK %d msgbuff %x %x\n", + ret, mbx[0], mbx[4]); + else + KPRINT_DEBUG2("mailbox write failed"); +} + +/** + * tc956xmac_vf_delete_vlan + * + * \brief API to delete vlan id + * + * \details This function is used to send vlan id to delete to PF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] vid - vlan id + * + * \return None + */ +static void tc956xmac_vf_delete_vlan(struct tc956xmac_priv *priv, u16 vid) +{ + /* Prepare mailbox message and call mailbox API for posting + * and getting the ACK + */ + u8 mbx[MBX_TOT_SIZE]; + int ret; + + enum mbx_msg_fns msg_dst = priv->fn_id_info.pf_no + 1; + + if (priv == NULL) { + KPRINT_DEBUG2("NULL pointer error\n"); + return; + } + + mbx[0] = OPCODE_MBX_VF_DELETE_VLAN; + mbx[1] = SIZE_MBX_VF_VLAN; + + memcpy(&mbx[2], (u8 *)&vid, SIZE_MBX_VF_VLAN); + + ret = tc956xmac_mbx_write(priv, mbx, msg_dst, &priv->fn_id_info); + if (ret > 0) + KPRINT_DEBUG2("mailbox write with ACK or NACK %d msgbuff %x %x\n", + ret, mbx[0], mbx[4]); + else + KPRINT_DEBUG2("mailbox write failed"); +} + +/** + * tc956x_mbx_get_drv_cap + * + * \brief API to receive EMAC features state from PF + * + * \details This function is used to receive states for Jumbo frames, TSO, + * RX CRC and RC Checksum from PF using mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * + * \return None + */ +static void tc956x_mbx_get_drv_cap(struct tc956xmac_priv *priv, struct tc956xmac_priv *priv1) +{ + /* Prepare mailbox message and call mailbox API for posting + * and getting the ACK + */ + u8 mbx[MBX_TOT_SIZE]; + int ret; + enum mbx_msg_fns msg_dst = priv->fn_id_info.pf_no + 1; + + if (priv == NULL) { + KPRINT_DEBUG2("NULL pointer error\n"); + return; + } + + mbx[0] = OPCODE_MBX_DRV_CAP; + mbx[1] = 0; + + ret = tc956xmac_mbx_write(priv, mbx, msg_dst, &priv->fn_id_info); + + /* If ACK received, copy data*/ + if (ret > 0) { + if (ret == ACK) { + if ((mbx[4] == OPCODE_MBX_ACK_MSG) && (mbx[5] == SIZE_MBX_DRV_CAP)) { + + /* Copy PF drv capabiliites to priv*/ + memcpy((u8 *)&priv->pf_drv_cap, &mbx[6], + SIZE_MBX_DRV_CAP); + } + } + KPRINT_DEBUG2("mailbox write with ACK or NACK %d msgbuff %x %x\n" + , ret, mbx[0], mbx[4]); + } else { + priv->pf_drv_cap.jumbo_en = false; + priv->pf_drv_cap.tso_en = false; + priv->pf_drv_cap.crc_en = false; + priv->pf_drv_cap.csum_en = false; + KPRINT_DEBUG2("mailbox write failed"); + } +} + +/** + * tc956xmac_vf_mbx_reset_eee_mode + * + * \brief API to reset eee mode + * + * \details This function is used to param of eee reset to PF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] hw - pointer to device information structure + * + * \return None + */ +static void tc956xmac_vf_mbx_reset_eee_mode(struct tc956xmac_priv *priv, struct mac_device_info *hw) +{ + u8 mbx[MBX_TOT_SIZE]; + int ret; + enum mbx_msg_fns msg_dst = priv->fn_id_info.pf_no + 1; + + if (priv == NULL || hw == NULL) { + KPRINT_DEBUG2("NULL pointer error\n"); + return; + } + + mbx[0] = OPCODE_MBX_RESET_EEE_MODE; + mbx[1] = 0; + + ret = tc956xmac_mbx_write(priv, mbx, msg_dst, &priv->fn_id_info); + + if (ret > 0) + KPRINT_DEBUG2("mailbox write with ACK or NACK %d msgbuff %x %x\n", ret, + mbx[0], mbx[4]); + else + KPRINT_DEBUG2("mailbox write failed"); +} + +/** + * tc956xmac_vf_mbx_reset + * + * \brief API to send VF status to PF + * + * \details This function is used to send VF status to PF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] vf_status - vf_status + * + * \return None + */ +static void tc956xmac_vf_mbx_reset(struct tc956xmac_priv *priv, u8 vf_status) +{ + u8 mbx[MBX_TOT_SIZE]; + int ret; + enum mbx_msg_fns msg_dst = priv->fn_id_info.pf_no + 1; + + if (priv == NULL) { + KPRINT_DEBUG2("NULL pointer error\n"); + return; + } + + mbx[0] = OPCODE_VF_RESET; + mbx[1] = SIZE_VF_RESET; + mbx[2] = vf_status; + + ret = tc956xmac_mbx_write(priv, mbx, msg_dst, &priv->fn_id_info); + + if (ret > 0) + KPRINT_DEBUG2("mailbox write with ACK or NACK %d msgbuff %x %x\n", ret, + mbx[0], mbx[4]); + else + KPRINT_DEBUG2("mailbox write failed"); +} + +/** + * tc956x_mbx_setup_cbs + * + * \brief API to setup cbs param for queue using TC command + * + * \details This function is used to send VF status to PF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] qopt - pointer to tc_cbs_qopt_offload structure + * + * \return success/error + */ +static int tc956x_mbx_setup_cbs(struct tc956xmac_priv *priv, struct tc_cbs_qopt_offload *qopt) +{ + u8 mbx[MBX_TOT_SIZE]; + int ret; + enum mbx_msg_fns msg_dst = priv->fn_id_info.pf_no + 1; + + if (priv == NULL || qopt == NULL) { + KPRINT_DEBUG2("NULL pointer error\n"); + return -EFAULT; + } + + mbx[0] = OPCODE_MBX_SETUP_CBS; //opcode + mbx[1] = SIZE_MBX_SETUP_CBS; //size + + memcpy(&mbx[2], (u8 *)&qopt->enable, sizeof(qopt->enable)); + memcpy(&mbx[3], (u8 *)&qopt->idleslope, sizeof(qopt->idleslope)); + memcpy(&mbx[7], (u8 *)&qopt->sendslope, sizeof(qopt->sendslope)); + memcpy(&mbx[11], (u8 *)&qopt->hicredit, sizeof(qopt->hicredit)); + memcpy(&mbx[15], (u8 *)&qopt->locredit, sizeof(qopt->locredit)); + memcpy(&mbx[19], (u8 *)&qopt->queue, sizeof(qopt->queue)); + + if (priv->plat->ch_in_use[qopt->queue] == 0) + return -EFAULT; + + ret = tc956xmac_mbx_write(priv, mbx, msg_dst, &priv->fn_id_info); + if (ret > 0) + KPRINT_DEBUG2("mailbox write with ACK or NACK %d msgbuff %x %x\n", ret, + mbx[0], mbx[4]); + else { + KPRINT_DEBUG2("mailbox write failed"); + return ret; + } + + return 0; +} + +/* Parsing PF->VF Message */ +/** + * tc956x_mbx_phy_link + * + * \brief API to receive link state and params from PF + * + * \details This function is used to receive PHY link parameters from PF using + * mailbox interface during state change. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] msg_buf - Pointer to mailboc message buffer + * \param[out] ack_msg - Pointer to output ack + * + * \return ACK/NACK + */ +static int tc956x_mbx_phy_link(struct tc956xmac_priv *priv, u8 *msg_buf, u8 *ack_msg) +{ + u32 datal = 0, datah = 0; + u8 vf_mac_addr[6]; + u8 comp_addr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + unsigned long flags; + + if (priv == NULL || msg_buf == NULL || ack_msg == NULL) { + KPRINT_DEBUG2("NULL pointer error\n"); + return NACK; + } + + if (msg_buf[0] != OPCODE_MBX_PHY_LINK) + return NACK; + + if (msg_buf[1] != SIZE_MBX_PHY_LINK) + return NACK; + + /* Copy link, speed and duplex values from mailbox */ + + memcpy((u8 *)&priv->link, &msg_buf[2], SIZE_MBX_PHY_LINK); + + /* Indicate state change to NW layer */ + if (priv->link) { + netif_carrier_on(priv->dev); + NMSGPR_INFO(priv->device, "PHY Link : UP\n"); + + datal = readl(priv->ioaddr + XGMAC_ADDRx_LOW(HOST_MAC_ADDR_OFFSET + priv->fn_id_info.vf_no)); + datah = readl(priv->ioaddr + XGMAC_ADDRx_HIGH(HOST_MAC_ADDR_OFFSET + priv->fn_id_info.vf_no)); + + vf_mac_addr[0] = datal & 0xff; + vf_mac_addr[1] = (datal >> 8) & 0xff; + vf_mac_addr[2] = (datal >> 16) & 0xff; + vf_mac_addr[3] = (datal >> 24) & 0xff; + vf_mac_addr[4] = datah & 0xff; + vf_mac_addr[5] = (datah >> 8) & 0xff; + + if (!(memcmp(vf_mac_addr, comp_addr, 6))) { + spin_lock_irqsave(&priv->wq_lock, flags); + priv->flag = SCH_WQ_LINK_STATE_UP; + tc956xmac_mailbox_service_event_schedule(priv); + spin_unlock_irqrestore(&priv->wq_lock, flags); + + } + } else { + netif_carrier_off(priv->dev); + NMSGPR_INFO(priv->device, "PHY Link : DOWN\n"); + } + + KPRINT_DEBUG2("Link state change update received from PF\n"); + + ack_msg[0] = OPCODE_MBX_ACK_MSG; + memset(&ack_msg[1], 0, MBX_MSG_SIZE-1); + + return ACK; +} + +/** + * tc956x_mbx_rx_crc + * + * \brief API to receive Rx CRC state from PF + * + * \details This function is used to receive Rx CRC state from PF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] msg_buf - Pointer to mailbox message buffer + * \param[out] ack_msg - Pointer to output ack + * + * \return ACK/NACK + */ +static int tc956x_mbx_rx_crc(struct tc956xmac_priv *priv, u8 *msg_buf, u8 *ack_msg) +{ + unsigned long flags; + + if (priv == NULL || msg_buf == NULL || ack_msg == NULL) { + KPRINT_DEBUG2("NULL pointer error\n"); + return NACK; + } + + if (msg_buf[0] != OPCODE_MBX_RX_CRC) + return NACK; + + if (msg_buf[1] != SIZE_MBX_RX_CRC) + return NACK; + + /* Copy RX CRC state values from mailbox */ + memcpy(&priv->rx_crc_pad_state, &msg_buf[2], + SIZE_MBX_RX_CRC); + priv->pf_drv_cap.crc_en = priv->rx_crc_pad_state; + + spin_lock_irqsave(&priv->wq_lock, flags); + tc956xmac_mailbox_service_event_schedule(priv); + spin_unlock_irqrestore(&priv->wq_lock, flags); + + KPRINT_DEBUG2("Rx CRC state received from PF"); + ack_msg[0] = OPCODE_MBX_ACK_MSG; + memset(&ack_msg[1], 0, MBX_MSG_SIZE-1); + + return ACK; +} + +/** + * tc956x_mbx_rx_csum + * + * \brief API to receive Rx Checksum state from PF + * + * \details This function is used to receive Rx Checksum state from PF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] msg_buf - Pointer to mailbox message buffer + * \param[out] ack_msg - Pointer to output ack + * + * \return ACK/NACK + */ +static int tc956x_mbx_rx_csum(struct tc956xmac_priv *priv, u8 *msg_buf, u8 *ack_msg) +{ + unsigned long flags; + + if (priv == NULL || msg_buf == NULL || ack_msg == NULL) { + KPRINT_DEBUG2("NULL pointer error\n"); + return NACK; + } + + if (msg_buf[0] != OPCODE_MBX_RX_CSUM) + return NACK; + + if (msg_buf[1] != SIZE_MBX_RX_CSUM) + return NACK; + + /* Copy RX checksum state from mailbox */ + memcpy(&priv->rx_csum_state, &msg_buf[2], SIZE_MBX_RX_CSUM); + priv->pf_drv_cap.csum_en = priv->rx_csum_state; + + spin_lock_irqsave(&priv->wq_lock, flags); + tc956xmac_mailbox_service_event_schedule(priv); + spin_unlock_irqrestore(&priv->wq_lock, flags); + + KPRINT_DEBUG2("Rx CSum state received from PF"); + + ack_msg[0] = OPCODE_MBX_ACK_MSG; + memset(&ack_msg[1], 0, MBX_MSG_SIZE-1); + + return ACK; +} + +/** + * tc956x_mbx_rx_dma_ch_tlptr + * + * \brief API to receive dma ch no from PF to update tail pointer + * + * \details This function is used to receive dma ch no from PF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] msg_buf - Pointer to mailbox message buffer + * \param[out] ack_msg - Pointer to output ack + * + * \return ACK/NACK + */ +static int tc956x_mbx_rx_dma_ch_tlptr(struct tc956xmac_priv *priv, u8 *msg_buf, u8 *ack_msg) +{ + u32 ch; + struct tc956xmac_rx_queue *rx_q; + + if (priv == NULL || msg_buf == NULL || ack_msg == NULL) { + KPRINT_DEBUG2("NULL pointer error\n"); + return NACK; + } + + if (msg_buf[0] != OPCODE_MBX_DMA_CH_TLPTR) + return NACK; + + if (msg_buf[1] != SIZE_MBX_RX_DMA_TL_PTR) + return NACK; + + memcpy(&ch, &msg_buf[2], SIZE_MBX_RX_DMA_TL_PTR); + + if (priv->plat->ch_in_use[ch] == 0) + return NACK; + + rx_q = &priv->rx_queue[ch]; + tc956xmac_set_rx_tail_ptr(priv, priv->ioaddr, rx_q->rx_tail_addr, ch); + + ack_msg[0] = OPCODE_MBX_ACK_MSG; + memset(&ack_msg[1], 0, MBX_MSG_SIZE-1); + + return ACK; +} + +/** + * tc956x_mbx_setup_etf + * + * \brief API to receive tbs status from PF to update tail pointer + * + * \details This function is used to receive tbs status from PF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] msg_buf - Pointer to mailbox message buffer + * \param[out] ack_msg - Pointer to output ack + * + * \return ACK/NACK + */ +static int tc956x_mbx_setup_etf(struct tc956xmac_priv *priv, u8 *msg_buf, u8 *ack_msg) +{ + u32 ch; + u8 tbs_status; + + if (priv == NULL || msg_buf == NULL || ack_msg == NULL) { + KPRINT_DEBUG2("NULL pointer error\n"); + return NACK; + } + + if (msg_buf[0] != OPCODE_MBX_SETUP_ETF) + return NACK; + + if (msg_buf[1] != SIZE_MBX_SETUP_ETF) + return NACK; + + memcpy(&ch, &msg_buf[2], 4); + memcpy(&tbs_status, &msg_buf[6], 1); + + if (priv->plat->tx_queues_cfg[ch].mode_to_use != MTL_QUEUE_DISABLE) { + if (priv->tx_queue[ch].tbs & TC956XMAC_TBS_AVAIL) { + if (tbs_status) + priv->tx_queue[ch].tbs |= TC956XMAC_TBS_EN; + else + priv->tx_queue[ch].tbs &= ~TC956XMAC_TBS_EN; + } + } + + ack_msg[0] = OPCODE_MBX_ACK_MSG; + memset(&ack_msg[1], 0, MBX_MSG_SIZE-1); + + return ACK; +} + +/** + * tc956x_mbx_pf_flr + * + * \brief API to receive PF FLR trigger from PF + * + * \details This function is used to receive PF FLR trigger from PF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] msg_buf - Pointer to mailbox message buffer + * \param[out] ack_msg - Pointer to output ack + * + * \return ACK/NACK + */ +static int tc956x_mbx_pf_flr(struct tc956xmac_priv *priv, u8 *msg_buf, u8 *ack_msg) +{ + unsigned long flags; + + if (priv == NULL || msg_buf == NULL || ack_msg == NULL) { + KPRINT_DEBUG2("NULL pointer error\n"); + return NACK; + } + + if (msg_buf[0] != OPCODE_MBX_FLR) + return NACK; + + if (msg_buf[1] != 0) + return NACK; + + spin_lock_irqsave(&priv->wq_lock, flags); + priv->flag = SCH_WQ_PF_FLR; + tc956xmac_mailbox_service_event_schedule(priv); + spin_unlock_irqrestore(&priv->wq_lock, flags); + + ack_msg[0] = OPCODE_MBX_ACK_MSG; + memset(&ack_msg[1], 0, MBX_MSG_SIZE-1); + + return ACK; +} + +/** + * tc956x_mbx_rx_dma_err + * + * \brief API to receive DMA err state from PF + * + * \details This function is used to receive DMA err state from PF using + * mailbox interface. + * + * \param[in] priv - Pointer to device's private structure + * \param[in] msg_buf - Pointer to mailbox message buffer + * \param[out] ack_msg - Pointer to output ack + * + * \return ACK/NACK + */ +static int tc956x_mbx_rx_dma_err(struct tc956xmac_priv *priv, u8 *msg_buf, u8 *ack_msg) +{ + unsigned long flags; + + if (priv == NULL || msg_buf == NULL || ack_msg == NULL) { + KPRINT_DEBUG2("NULL pointer error\n"); + return NACK; + } + + if (msg_buf[0] != OPCODE_MBX_DMA_ERR) + return NACK; + + if (msg_buf[1] != 0) + return NACK; + + spin_lock_irqsave(&priv->wq_lock, flags); + priv->flag = SCH_WQ_RX_DMA_ERR; + tc956xmac_mailbox_service_event_schedule(priv); + spin_unlock_irqrestore(&priv->wq_lock, flags); + + ack_msg[0] = OPCODE_MBX_ACK_MSG; + memset(&ack_msg[1], 0, MBX_MSG_SIZE-1); + + return ACK; +} + +const struct tc956xmac_mbx_wrapper_ops tc956xmac_mbx_wrapper_ops = { + .dma_tx_mode = tc956xmac_mbx_dma_tx_mode, + .get_umac_addr = tc956xmac_mbx_get_umac_addr, + .set_umac_addr = tc956xmac_mbx_set_umac_addr, + .set_mtl_tx_queue_weight = tc956xmac_mbx_set_mtl_tx_queue_weight, + .config_cbs = tc956xmac_mbx_config_cbs, + .tx_queue_prio = tc956xmac_mbx_tx_queue_prio, + .get_link_status = tc956xmac_mbx_get_link_status, + .phy_link = tc956x_mbx_phy_link, + .get_drv_cap = tc956x_mbx_get_drv_cap, + .rx_crc = tc956x_mbx_rx_crc, + .rx_csum = tc956x_mbx_rx_csum, + .get_cbs = tc956xmac_vf_ioctl_get_cbs, + .set_cbs = tc956xmac_vf_ioctl_set_cbs, + .set_est = tc956xmac_vf_ioctl_set_est, + .get_est = tc956xmac_vf_ioctl_get_est, + .set_rxp = tc956xmac_vf_ioctl_set_rxp, + .get_rxp = tc956xmac_vf_ioctl_get_rxp, + .get_fpe = tc956xmac_vf_ioctl_get_fpe, + .set_fpe = tc956xmac_vf_ioctl_set_fpe, + .get_speed = tc956xmac_vf_ioctl_get_connected_speed, + .reg_wr = tc956xmac_vf_ioctl_reg_wr, + .get_pause_param = tc956xmac_vf_ethtool_get_pauseparam, + .get_eee = tc956xmac_vf_ethtool_get_eee, + .add_mac = tc956xmac_vf_add_mac, + .delete_mac = tc956xmac_vf_delete_mac, + .add_vlan = tc956xmac_vf_add_vlan, + .delete_vlan = tc956xmac_vf_delete_vlan, + .reset_eee_mode = tc956xmac_vf_mbx_reset_eee_mode, + .vf_reset = tc956xmac_vf_mbx_reset, + .rx_dma_ch_tlptr = tc956x_mbx_rx_dma_ch_tlptr, + .setup_cbs = tc956x_mbx_setup_cbs, + .setup_mbx_etf = tc956x_mbx_setup_etf, + .pf_flr = tc956x_mbx_pf_flr, + .rx_dma_err = tc956x_mbx_rx_dma_err, +}; + +#endif diff --git a/tc956x_vf_rsc_mng.c b/tc956x_vf_rsc_mng.c new file mode 100644 index 000000000000..e0733f204c4c --- /dev/null +++ b/tc956x_vf_rsc_mng.c @@ -0,0 +1,119 @@ +/* + * TC956X ethernet driver. + * + * tc956x_vf_rsc_mng.c + * + * Copyright (C) 2021 Toshiba Electronic Devices & Storage Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/*! History: + * 04 Jun 2020 : Initial Version + * VERSION : 00-01 + * + * 30 Nov 2021 : Base lined for SRIOV + * VERSION : 01-02 + */ + +#include "tc956x_vf_rsc_mng.h" +#include "tc956xmac.h" + + +/** + * tc956x_vf_rsc_mng_init + * + * \brief API to initialise resource manager parameters + * + * \details This function initialise parameters used for resource manager + * control. + * + * \param[in] ndev - Pointer to device structure + * + * \return None + */ + +static int tc956x_vf_rsc_mng_init(struct tc956xmac_priv *priv, struct net_device *ndev) +{ + return 0; +} + +/** + * tc956x_vf_rsc_mng_get_fn_id + * + * \brief API to get function ID of this function + * + * \details This function is called to get the function ID from + * the resource manager function ID register + * + * \param[in] dev - Pointer to device structure + * \param[in] fn_id_info - Pointer to function id info structure + * + * \return success or error + */ + +int tc956x_vf_rsc_mng_get_fn_id(struct tc956xmac_priv *priv, void __iomem *reg_pci_bridge_config_addr, + struct fn_id *fn_id_info) +{ + void __iomem *ioaddr = reg_pci_bridge_config_addr; + u32 rsc_mng_id = readl(ioaddr + RSCMNG_ID_REG); + + fn_id_info->fn_type = (rsc_mng_id & RSC_MNG_FN_TYPE) >> 16; + fn_id_info->pf_no = (rsc_mng_id & RSC_MNG_PF_FN_NUM); + fn_id_info->vf_no = ((rsc_mng_id & RSC_MNG_VF_FN_NUM) >> 8); + + /** Below error check for VF driver. + * In case of VF driver, function type to be 1 + */ + if (fn_id_info->fn_type == 0) + return -1; + + /* VF1,2,3 are supported */ + if (fn_id_info->vf_no > 3) + return -1; + + /* PF 0 and 1 are supported */ + if (fn_id_info->pf_no > 1) + return -1; + + return 0; +} + +/** + * tc956x_vf_rsc_mng_get_rscs + * + * \brief API to get the DMA channel resources allocated + * + * \details This function is used to get the resources (DMA channels) + * allocated for this function + * + * \param[in] dev - Pointer to device structure + * \param[in] rscs - Pointer to return DMA channel bit pattern in + * order <7,6,5,4,3,2,1,0> + * \return None + */ + +static void tc956x_vf_rsc_mng_get_rscs(struct tc956xmac_priv *priv, struct net_device *dev, u8 *rscs) +{ + void __iomem *ioaddr = (void __iomem *)priv->tc956x_BRIDGE_CFG_pci_base_addr; + *rscs = ((readl(ioaddr + RSCMNG_RSC_ST_REG)) & RSC_MNG_RSC_STATUS_MASK); +} + +const struct mac_rsc_mng_ops tc956xmac_rsc_mng_ops = { + .init = tc956x_vf_rsc_mng_init, + .get_fn_id = tc956x_vf_rsc_mng_get_fn_id, + .set_rscs = NULL, /* Not applicable for VF */ + .get_rscs = tc956x_vf_rsc_mng_get_rscs, +}; diff --git a/tc956x_vf_rsc_mng.h b/tc956x_vf_rsc_mng.h new file mode 100644 index 000000000000..f9f16e923ca2 --- /dev/null +++ b/tc956x_vf_rsc_mng.h @@ -0,0 +1,87 @@ +/* + * TC956X ethernet driver. + * + * tc956x_vf_rsc_mng.h + * + * Copyright (C) 2021 Toshiba Electronic Devices & Storage Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/*! History: + * 10 Jul 2020 : Initial Version + * VERSION : 00-01 + * + * 30 Nov 2021 : Base lined for SRIOV + * VERSION : 01-02 + */ + +#ifndef __TC956X_VF_RSC_MNG_H__ +#define __TC956X_VF_RSC_MNG_H__ + +#include "common.h" +#include + +#define MAX_FUNCTIONS_PER_PF 4 /*Max functions per pf including pf, vfs*/ +#define RSC_MNG_OFFSET 0x2000 +#define RSCMNG_ID_REG ((RSC_MNG_OFFSET) + 0x00000000) +#define RSCMNG_RSC_CTRL_REG ((RSC_MNG_OFFSET) + 0x00000004) +#define RSCMNG_RSC_ST_REG ((RSC_MNG_OFFSET) + 0x00000008) +#define RSCMNG_INT_CTRL_REG ((RSC_MNG_OFFSET) + 0x0000000c) +#define RSCMNG_INT_ST_REG ((RSC_MNG_OFFSET) + 0x00000010) + +#define RSC_MNG_FN_TYPE BIT(16) +#define RSC_MNG_VF_FN_NUM GENMASK(11, 8) +#define RSC_MNG_PF_FN_NUM GENMASK(3, 0) + +#define RSC_MNG_DMA_CH7_MASK 0x80 +#define RSC_MNG_DMA_CH6_MASK 0x40 +#define RSC_MNG_DMA_CH5_MASK 0x20 +#define RSC_MNG_DMA_CH4_MASK 0x10 +#define RSC_MNG_DMA_CH3_MASK 0x08 +#define RSC_MNG_DMA_CH2_MASK 0x04 +#define RSC_MNG_DMA_CH1_MASK 0x02 +#define RSC_MNG_DMA_CH0_MASK 0x01 + +#define RSC_MNG_DMA_CH7_BIT_POS 28 +#define RSC_MNG_DMA_CH6_BIT_POS 24 +#define RSC_MNG_DMA_CH5_BIT_POS 20 +#define RSC_MNG_DMA_CH4_BIT_POS 16 +#define RSC_MNG_DMA_CH3_BIT_POS 12 +#define RSC_MNG_DMA_CH2_BIT_POS 8 +#define RSC_MNG_DMA_CH1_BIT_POS 4 +#define RSC_MNG_DMA_CH0_BIT_POS 0 + +#define RSC_MNG_RSC_STATUS_MASK 0xff + +#define RSC_MNG_INT_STATUS_MASK 0x1f +#define RSC_MNG_INT_MCU_MASK 0x10 +#define RSC_MNG_INT_VF2_MASK 0x08 +#define RSC_MNG_INT_VF1_MASK 0x04 +#define RSC_MNG_INT_VF0_MASK 0x02 +#define RSC_MNG_INT_OTHR_PF_MASK 0x01 + +#define MBX_MCU_INTERRUPT BIT(4) +#define MBX_VF3_INTERRUPT BIT(3) +#define MBX_VF2_INTERRUPT BIT(2) +#define MBX_VF1_INTERRUPT BIT(1) +#define MBX_PF_INTERRUPT BIT(0) + +#define RSC_MNG_ACK_MASK 0x01 +#define RSC_MNG_NACK_MASK 0x02 + +#define MBX_TIMEOUT 1000 + +#endif /* __TC956X_VF_RSC_MNG_H__ */ diff --git a/tc956x_xpcs.c b/tc956x_xpcs.c index fadcc6cacdd4..595aa244588c 100644 --- a/tc956x_xpcs.c +++ b/tc956x_xpcs.c @@ -91,57 +91,74 @@ int tc956x_xpcs_init(struct tc956xmac_priv *priv, void __iomem *xpcsaddr) if (reg_value & XGMAC_SOFT_RST) return -1; - /*Clause 37 autoneg related settings*/ - if (priv->plat->interface == PHY_INTERFACE_MODE_SGMII) { - //DK2 - //PCS Type Select SR_XS_PCS_CTRL2 PCS_TYPE_SEL -> 1 - reg_value = tc956x_xpcs_read(xpcsaddr, XGMAC_SR_XS_PCS_CTRL2); - reg_value &= XGMAC_PCS_TYPE_SEL; - reg_value |= 0x1; - tc956x_xpcs_write(xpcsaddr, XGMAC_SR_XS_PCS_CTRL2, reg_value); +#ifdef TC956X_MAGIC_PACKET_WOL_CONF + if (priv->wol_config_enabled != true) { +#endif /* #ifdef TC956X_MAGIC_PACKET_WOL_CONF */ + /*Clause 37 autoneg related settings*/ + if (priv->plat->interface == PHY_INTERFACE_MODE_SGMII) { + //DK2 + //PCS Type Select SR_XS_PCS_CTRL2 PCS_TYPE_SEL -> 1 + reg_value = tc956x_xpcs_read(xpcsaddr, XGMAC_SR_XS_PCS_CTRL2); + reg_value &= XGMAC_PCS_TYPE_SEL; + reg_value |= 0x1; + tc956x_xpcs_write(xpcsaddr, XGMAC_SR_XS_PCS_CTRL2, reg_value); - reg_value = tc956x_xpcs_read(xpcsaddr, XGMAC_VR_MII_AN_CTRL); - reg_value &= XGMAC_PCS_MODE_MASK; - reg_value |= XGMAC_SGMII_MODE;/*SGMII PCS MODE*/ - tc956x_xpcs_write(xpcsaddr, XGMAC_VR_MII_AN_CTRL, reg_value); + reg_value = tc956x_xpcs_read(xpcsaddr, XGMAC_VR_MII_AN_CTRL); + reg_value &= XGMAC_PCS_MODE_MASK; + reg_value |= XGMAC_SGMII_MODE;/*SGMII PCS MODE*/ + tc956x_xpcs_write(xpcsaddr, XGMAC_VR_MII_AN_CTRL, reg_value); + + if (priv->is_sgmii_2p5g == true) { + reg_value = tc956x_xpcs_read(xpcsaddr, XGMAC_VR_XS_PCS_DIG_CTRL1); + reg_value &= ~(0x4); + /* Enable only if SGMII 2.5G is enabled */ + reg_value |= 0x4; /*EN_2_5G_MODE*/ + tc956x_xpcs_write(xpcsaddr, XGMAC_VR_XS_PCS_DIG_CTRL1, reg_value); + } + } + if ((priv->plat->interface == PHY_INTERFACE_MODE_USXGMII) || + (priv->plat->interface == PHY_INTERFACE_MODE_10GKR)) { + reg_value = tc956x_xpcs_read(xpcsaddr, XGMAC_SR_XS_PCS_CTRL2); + reg_value &= XGMAC_PCS_TYPE_SEL;/*PCS_TYPE_SEL as 10GBASE-R PCS */ + tc956x_xpcs_write(xpcsaddr, XGMAC_SR_XS_PCS_CTRL2, reg_value); - if (priv->is_sgmii_2p5g == true) { reg_value = tc956x_xpcs_read(xpcsaddr, XGMAC_VR_XS_PCS_DIG_CTRL1); - reg_value &= ~(0x4); - /* Enable only if SGMII 2.5G is enabled */ - reg_value |= 0x4; /*EN_2_5G_MODE*/ + if (priv->plat->interface == PHY_INTERFACE_MODE_10GKR) { + reg_value &= (~XGMAC_USXG_EN); /*Disable USXG_EN*/ + } else { + reg_value |= XGMAC_USXG_EN; /*set USXG_EN*/ + } + tc956x_xpcs_write(xpcsaddr, XGMAC_VR_XS_PCS_DIG_CTRL1, reg_value); - } - } - if ((priv->plat->interface == PHY_INTERFACE_MODE_USXGMII) || - (priv->plat->interface == PHY_INTERFACE_MODE_10GKR)) { - reg_value = tc956x_xpcs_read(xpcsaddr, XGMAC_SR_XS_PCS_CTRL2); - reg_value &= XGMAC_PCS_TYPE_SEL;/*PCS_TYPE_SEL as 10GBASE-R PCS */ - tc956x_xpcs_write(xpcsaddr, XGMAC_SR_XS_PCS_CTRL2, reg_value); - reg_value = tc956x_xpcs_read(xpcsaddr, XGMAC_VR_XS_PCS_DIG_CTRL1); - if (priv->plat->interface == PHY_INTERFACE_MODE_10GKR) { - reg_value &= (~XGMAC_USXG_EN); /*Disable USXG_EN*/ - } else { - reg_value |= XGMAC_USXG_EN; /*set USXG_EN*/ - } + reg_value = tc956x_xpcs_read(xpcsaddr, XGMAC_VR_XS_PCS_KR_CTRL); + reg_value &= ~XGMAC_USXG_MODE;/*USXG_MODE : 0x000*/ + tc956x_xpcs_write(xpcsaddr, XGMAC_VR_XS_PCS_KR_CTRL, reg_value); - tc956x_xpcs_write(xpcsaddr, XGMAC_VR_XS_PCS_DIG_CTRL1, reg_value); - - reg_value = tc956x_xpcs_read(xpcsaddr, XGMAC_VR_XS_PCS_KR_CTRL); - reg_value &= ~XGMAC_USXG_MODE;/*USXG_MODE : 0x000*/ - tc956x_xpcs_write(xpcsaddr, XGMAC_VR_XS_PCS_KR_CTRL, reg_value); - - reg_value = tc956x_xpcs_read(xpcsaddr, XGMAC_VR_XS_PCS_DIG_CTRL1); - reg_value |= XGMAC_VR_RST;/*set VR_RST*/ - tc956x_xpcs_write(xpcsaddr, XGMAC_VR_XS_PCS_DIG_CTRL1, reg_value); - - /*Wait for Reset to clear*/ - do { reg_value = tc956x_xpcs_read(xpcsaddr, XGMAC_VR_XS_PCS_DIG_CTRL1); - } while ((XGMAC_VR_RST & reg_value) == XGMAC_VR_RST); + reg_value |= XGMAC_VR_RST;/*set VR_RST*/ + tc956x_xpcs_write(xpcsaddr, XGMAC_VR_XS_PCS_DIG_CTRL1, reg_value); + /*Wait for Reset to clear*/ + do { + reg_value = tc956x_xpcs_read(xpcsaddr, XGMAC_VR_XS_PCS_DIG_CTRL1); + } while ((XGMAC_VR_RST & reg_value) == XGMAC_VR_RST); + + } +#ifdef TC956X_MAGIC_PACKET_WOL_CONF + } else { /* SerDES Configuration for WOL SGMII 1G when native interface other than SGMII. */ + KPRINT_INFO("%s Port %d : Entered with flag priv->wol_config_enabled %d", __func__, priv->port_num, priv->wol_config_enabled); + reg_value = tc956x_xpcs_read(xpcsaddr, XGMAC_SR_XS_PCS_CTRL2); + reg_value &= XGMAC_PCS_TYPE_SEL; + reg_value |= 0x1; + tc956x_xpcs_write(xpcsaddr, XGMAC_SR_XS_PCS_CTRL2, reg_value); + + reg_value = tc956x_xpcs_read(xpcsaddr, XGMAC_VR_MII_AN_CTRL); + reg_value &= XGMAC_PCS_MODE_MASK; + reg_value |= XGMAC_SGMII_MODE;/*SGMII PCS MODE*/ + tc956x_xpcs_write(xpcsaddr, XGMAC_VR_MII_AN_CTRL, reg_value); } +#endif /* #ifdef TC956X_MAGIC_PACKET_WOL_CONF */ #ifdef EEE reg_value = tc956x_xpcs_read(xpcsaddr, XGMAC_SR_XS_PCS_CTRL1); reg_value |= XGMAC_LPI_ENABLE;/* LPM : power down */ @@ -220,13 +237,24 @@ void tc956x_xpcs_ctrl_ane(struct tc956xmac_priv *priv, bool ane) u32 reg_value; reg_value = tc956x_xpcs_read(priv->xpcsaddr, XGMAC_SR_MII_CTRL); - if (ane) { +#ifdef TC956X_MAGIC_PACKET_WOL_CONF + if (priv->wol_config_enabled != true) { +#endif /* #ifdef TC956X_MAGIC_PACKET_WOL_CONF */ + if (ane) { + reg_value |= XGMAC_AN_37_ENABLE; + KPRINT_INFO("%s Enable AN", __func__); + } else { + reg_value &= (~XGMAC_AN_37_ENABLE); + KPRINT_INFO("%s Disable AN", __func__); + } +#ifdef TC956X_MAGIC_PACKET_WOL_CONF + } else { + /* Configure SGMII 1Gbps when WOL flag is enabled and native interface is other than SGMII. */ + KPRINT_INFO("%s Port %d : Entered with flag priv->wol_config_enabled %d", __func__, priv->port_num, priv->wol_config_enabled); reg_value |= XGMAC_AN_37_ENABLE; KPRINT_INFO("%s Enable AN", __func__); - } else { - reg_value &= (~XGMAC_AN_37_ENABLE); - KPRINT_INFO("%s Disable AN", __func__); } +#endif /* #ifdef TC956X_MAGIC_PACKET_WOL_CONF */ tc956x_xpcs_write(priv->xpcsaddr, XGMAC_SR_MII_CTRL, reg_value); } diff --git a/tc956x_xpcs.h b/tc956x_xpcs.h index ec15c2cfc97e..54d6eab97fb2 100644 --- a/tc956x_xpcs.h +++ b/tc956x_xpcs.h @@ -48,13 +48,14 @@ #endif /*XPCS registers*/ -#define XGMAC_SR_MII_CTRL 0x7C0000 +#define XGMAC_SR_MII_CTRL 0x7C0000 #define XGMAC_VR_MII_AN_CTRL 0x7e0004 #define XGMAC_VR_MII_DIG_CTRL1 0x7e0000 #define XGMAC_SR_XS_PCS_CTRL1 0xC0000 #define XGMAC_SR_XS_PCS_STS1 0xC0004 #define XGMAC_SR_XS_PCS_CTRL2 0xC001C #define XGMAC_SR_XS_PCS_EEE_ABL 0xC0050 +#define XGMAC_SR_XS_PCS_STS2 0xC0020 #define XGMAC_VR_XS_PCS_DIG_CTRL1 0xe0000 #define XGMAC_VR_XS_PCS_EEE_MCTRL0 0xe0018 #define XGMAC_VR_XS_PCS_EEE_MCTRL1 0xe002c @@ -88,32 +89,33 @@ #define XGMAC_TRN_LPI 0x1 /*XPCS Register value*/ -#define XGMAC_PCS_MODE_MASK 0xFFFFFFF9 -#define XGMAC_SGMII_MODE 0x00000004 -#define XGMAC_TX_CFIG_INTR_EN_MASK 0xFFFFFFF6 /*Mask TX_CONFIG & MII_AN_INTR_EN*/ -#define XGMAC_MII_AN_INTR_EN 0x00000001 /*MII_AN_INTR_EN*/ -#define XGMAC_MAC_AUTO_SW_EN 0x00000200 /*MAC_AUTO_SW*/ -#define XGMAC_AN_37_ENABLE 0x00001000 /*AN_EN*/ -#define XGMAC_PCS_TYPE_SEL 0xFFFFFFF0 /*PCS_TYPE_SEL: 0x0000*/ -#define XGMAC_USXG_EN 0x00000200 /*USXG_EN enable*/ -#define XGMAC_USXG_MODE 0x00001c00 /*USXG_MODE: 0x000*/ -#define XGMAC_VR_RST 0x00008000 /*set VR_RST*/ -#define XGMAC_USXG_AN_STS_SPEED_MASK 0x00001c00 /*USXGMII autonegotiated speed*/ -#define XGMAC_USXG_AN_STS_DUPLEX_MASK 0x00002000 /*USXGMII autonegtiated duplex*/ -#define XGMAC_USXG_AN_STS_LINK_MASK 0x00004000 /*USXGMII link status*/ -#define XGMAC_SGM_STS_LINK_MASK 0x00000010 /*SGMII link status*/ -#define XGMAC_SGM_STS_DUPLEX 0x00000002 /*SGMII autonegotiated duplex*/ -#define XGMAC_SGM_STS_SPEED_MASK 0x0000000c /*SGMII autonegotiated speed*/ -#define XGMAC_SOFT_RST 0x00008000 /*SOFT RST*/ -#define XGMAC_C37_AN_COMPL 0x00000001 /*C37 Autoneg complete*/ -#define XGMAC_SR_MII_CTRL_SPEED 0x00002060 /* SR_MII_CTRL Reg SPEED SS13, SS6, SS5 */ -#define XGMAC_SR_MII_CTRL_SPEED_10G 0x00002040 /* SR_MII_CTRL SPEED: 10G */ -#define XGMAC_SR_MII_CTRL_SPEED_5G 0x00002020 /* SR_MII_CTRL SPEED: 5G */ -#define XGMAC_SR_MII_CTRL_SPEED_2_5G 0x00000020 /* SR_MII_CTRL SPEED: 5G */ -#define XGMAC_USRA_RST 0x400 /* USRA_RST */ +#define XGMAC_PCS_MODE_MASK 0xFFFFFFF9 +#define XGMAC_SGMII_MODE 0x00000004 +#define XGMAC_TX_CFIG_INTR_EN_MASK 0xFFFFFFF6/*Mask TX_CONFIG & MII_AN_INTR_EN*/ +#define XGMAC_MII_AN_INTR_EN 0x00000001/*MII_AN_INTR_EN*/ +#define XGMAC_MAC_AUTO_SW_EN 0x00000200/*MAC_AUTO_SW*/ +#define XGMAC_AN_37_ENABLE 0x00001000/*AN_EN*/ +#define XGMAC_PCS_TYPE_SEL 0xFFFFFFF0/*PCS_TYPE_SEL: 0x0000*/ +#define XGMAC_USXG_EN 0x00000200/*USXG_EN enable*/ +#define XGMAC_USXG_MODE 0x00001c00/*USXG_MODE: 0x000*/ +#define XGMAC_VR_RST 0x00008000/*set VR_RST*/ +#define XGMAC_USXG_AN_STS_SPEED_MASK 0x00001c00/*USXGMII autonegotiated speed*/ +#define XGMAC_USXG_AN_STS_DUPLEX_MASK 0x00002000/*USXGMII autonegtiated duplex*/ +#define XGMAC_USXG_AN_STS_LINK_MASK 0x00004000/*USXGMII link status*/ +#define XGMAC_SGM_STS_LINK_MASK 0x00000010/*SGMII link status*/ +#define XGMAC_SGM_STS_DUPLEX 0x00000002/*SGMII autonegotiated duplex*/ +#define XGMAC_SGM_STS_SPEED_MASK 0x0000000c/*SGMII autonegotiated speed*/ +#define XGMAC_SOFT_RST 0x00008000/*SOFT RST*/ +#define XGMAC_C37_AN_COMPL 0x00000001/*C37 Autoneg complete*/ +#define XGMAC_SR_MII_CTRL_SPEED 0x00002060/* SR_MII_CTRL Reg SPEED SS13, SS6, SS5 */ +#define XGMAC_SR_MII_CTRL_SPEED_10G 0x00002040/* SR_MII_CTRL SPEED: 10G */ +#define XGMAC_SR_MII_CTRL_SPEED_5G 0x00002020/* SR_MII_CTRL SPEED: 5G */ +#define XGMAC_SR_MII_CTRL_SPEED_2_5G 0x00000020/* SR_MII_CTRL SPEED: 5G */ +#define XGMAC_USRA_RST 0x400/* USRA_RST */ #define XGMAC_EEE_LRX_EN BIT(1) /* LPI Rx Enable */ + #define XPCS_REG_BASE_ADDR 10 #define XPCS_REG_OFFSET 0x0003FF #define XPCS_IND_ACCESS 0x3FC diff --git a/tc956xmac.h b/tc956xmac.h index 123c92cb8eec..df92497ff536 100644 --- a/tc956xmac.h +++ b/tc956xmac.h @@ -4,7 +4,7 @@ * tc956xmac.h * * Copyright (C) 2007-2009 STMicroelectronics Ltd - * Copyright (C) 2021 Toshiba Electronic Devices & Storage Corporation + * Copyright (C) 2023 Toshiba Electronic Devices & Storage Corporation * * This file has been derived from the STMicro Linux driver, * and developed or modified for TC956X. @@ -172,6 +172,15 @@ * VERSION : 01-00-58 * 09 May 2023 : 1. Version update * VERSION : 01-00-59 + * 10 Nov 2023 : 1. DSP Cascade related modifications + * 2. Kernel 6.1 Porting changes + * 3. Version update + * VERSION : 01-02-59 + * + * 26 Dec 2023 : 1. Kernel 6.6 Porting changes + * 2. Added the support for TC commands taprio and flower + * 3. Version update + * VERSION : 01-03-59 */ #ifndef __TC956XMAC_H__ @@ -181,16 +190,26 @@ #include #include #include "tc956xmac_inc.h" +#ifndef TC956X_SRIOV_VF #include +#endif #include #include "common.h" #include #include #include -#include #include - +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0)) +#include +#else +#include +#endif +#ifdef TC956X_SRIOV_PF +#include "tc956x_pf_rsc_mng.h" +#endif +#ifndef TC956X_SRIOV_VF //#define TC956X_LOAD_FW_HEADER +#endif #define PF_DRIVER 4 /* Uncomment EEE_MAC_CONTROLLED_MODE macro for MAC controlled EEE Mode & comment for PHY controlled EEE mode */ @@ -201,7 +220,11 @@ #ifdef TC956X #define VENDOR_ID 0x1179 +#ifndef TC956X_SRIOV_VF #define DEVICE_ID 0x0220 /* PF - 0x0220, VF - 0x0221 */ +#elif (defined TC956X_SRIOV_VF) +#define DEVICE_ID 0x0221 /* PF - 0x0220, VF - 0x0221 */ +#endif #endif #define SUB_SYS_VENDOR_ID 0x1179 @@ -221,15 +244,21 @@ #define FIRMWARE_NAME "TC956X_Firmware_PCIeBridge.bin" #endif +#define TC956X_TOTAL_VFS 3 + #ifdef TC956X +#ifndef TC956X_SRIOV_VF #define TC956X_RESOURCE_NAME "tc956x_pci-eth" #define IRQ_DEV_NAME(x) (((x) == RM_PF0_ID) ? ("eth0") : ("eth1")) #define WOL_IRQ_DEV_NAME(x) (((x) == RM_PF0_ID) ? ("eth0_wol") : ("eth1_wol")) -#define DRV_MODULE_VERSION "V_01-00-59" +#define DRV_MODULE_VERSION "V_01-03-59" #define TC956X_FW_MAX_SIZE (64*1024) - +#elif (defined TC956X_SRIOV_VF) +#define TC956X_RESOURCE_NAME "tc956x_vf_pci-eth" +#define DRV_MODULE_VERSION "V_01-01-59" +#endif #define ATR_AXI4_SLV_BASE 0x0800 #define ATR_AXI4_SLAVE_OFFSET 0x0100 #define ATR_AXI4_TABLE_OFFSET 0x20 @@ -260,7 +289,7 @@ TRSL_MASK_OFFSET2) #define TC956X_ATR_IMPL 1U -#define TC956X_ATR_SIZE(size) ((size - 1U) << 1U) +#define TC956X_ATR_SIZE(size) ((size - 1U) << 1U) #define TC956X_ATR_SIZE_MASK GENMASK(6, 1) #define TC956x_ATR_SIZE_SHIFT 1 #define TC956X_SRC_LO_MASK GENMASK(31, 12) @@ -272,9 +301,10 @@ #define TC956X_AXI4_SLV00_TRSL_ADDR_LO_VAL (0x00000000U) #define TC956X_AXI4_SLV00_TRSL_ADDR_HI_VAL (0x00000000U) #define TC956X_AXI4_SLV00_TRSL_PARAM_VAL (0x00000000U) +#define TC956X_AXI4_SLV00_SRC_ADDR_LO_VAL_DEFAULT (0x0000007FU) -#ifdef DMA_OFFLOAD_ENABLE -#define TC956X_AXI4_SLV01_ATR_SIZE 28U /* 28 bit DMA Mask */ +#ifdef TC956X_DMA_OFFLOAD_ENABLE +#define TC956X_AXI4_SLV01_ATR_SIZE 28U /* 28 bit DMA Mask */ #define TC956X_AXI4_SLV01_SRC_ADDR_LO_VAL (0x60000000U) #define TC956X_AXI4_SLV01_SRC_ADDR_HI_VAL (0x00000000U) #define TC956X_AXI4_SLV01_TRSL_ADDR_LO_VAL (0x00000000U) @@ -308,6 +338,21 @@ #define DB_CNT18 18 /* m3 transmission timeout indication for port1 */ #define DB_CNT19 19 /* reserved19 */ +#define SIXTEEN 16 +#define TWENTY 20 +#define TWENTY_FOUR 24 +#define SIXTY_FOUR 64 +#define ONE_TWENTY_EIGHT 128 +#define TWO_FIFTY_SIX 256 +#define FIVE_HUNDRED_TWELVE 512 +#define THOUSAND_TWENTY_FOUR 1024 + +#define SPD_DIV_10G 10000000 +#define SPD_DIV_5G 5000000 +#define SPD_DIV_2_5G 2500000 +#define SPD_DIV_1G 1000000 +#define SPD_DIV_100M 100000 + #define NRSTCTRL0_RST_ASRT 0x1 #define NRSTCTRL0_RST_DE_ASRT 0x3 @@ -362,6 +407,18 @@ #define MTL_FPE_AFSZ_128 1 #define MTL_FPE_AFSZ_192 2 #define MTL_FPE_AFSZ_256 3 +#ifdef TC956X_SRIOV_PF +#define TC956X_DISABLE_CHNL 0 +#define TC956X_ENABLE_CHNL 1 + +#define TC956X_DISABLE_QUEUE 0 +#define TC956X_ENABLE_QUEUE 1 +#endif + +#define MMC_XGMAC_TX_FPE_FRAG 0x208 +#define MMC_XGMAC_RX_PKT_ASSEMBLY_OK 0x230 +#define MMC_XGMAC_RX_FPE_FRAG 0x234 + #endif #define MAX_CM3_TAMAP_ENTRIES 3 @@ -374,7 +431,10 @@ #define TC956X_MAX_LINK_DELAY 800 -#ifdef DMA_OFFLOAD_ENABLE +#define XDP_PACKET_HEADROOM 256 +#define TC956X_MAX_RX_BUF_SIZE(num) (((num) * PAGE_SIZE) - XDP_PACKET_HEADROOM) + +#ifdef TC956X_DMA_OFFLOAD_ENABLE struct tc956xmac_cm3_tamap { u32 trsl_addr_hi; u32 trsl_addr_low; @@ -388,11 +448,15 @@ struct tc956xmac_cm3_tamap { struct tc956xmac_resources { void __iomem *addr; -#ifdef TC956X +#ifdef TC956X_SRIOV_PF +#ifdef CONFIG_PCI_IOV + u32 sriov_enabled; +#endif +#endif void __iomem *tc956x_BRIDGE_CFG_pci_base_addr; void __iomem *tc956x_SRAM_pci_base_addr; void __iomem *tc956x_SFR_pci_base_addr; -#endif + const char *mac; int wol_irq; int lpi_irq; @@ -421,7 +485,11 @@ struct tc956xmac_tx_info { struct tc956xmac_tx_queue { u32 tx_count_frames; int tbs; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)) + struct hrtimer txtimer; +#else struct timer_list txtimer; +#endif u32 queue_index; struct tc956xmac_priv *priv_data; struct dma_extended_desc *dma_etx ____cacheline_aligned_in_smp; @@ -434,7 +502,7 @@ struct tc956xmac_tx_queue { dma_addr_t dma_tx_phy; u32 tx_tail_addr; u32 mss; -#ifdef DMA_OFFLOAD_ENABLE +#ifdef TC956X_DMA_OFFLOAD_ENABLE struct sk_buff **tx_offload_skbuff; dma_addr_t *tx_offload_skbuff_dma; dma_addr_t buff_tx_phy; @@ -468,7 +536,7 @@ struct tc956xmac_rx_queue { unsigned int len; unsigned int error; } state; -#ifdef DMA_OFFLOAD_ENABLE +#ifdef TC956X_DMA_OFFLOAD_ENABLE struct sk_buff **rx_offload_skbuff; dma_addr_t *rx_offload_skbuff_dma; dma_addr_t buff_rx_phy; @@ -501,10 +569,12 @@ struct tc956xmac_tc_entry { u8 im:1; u8 nc:1; u8 res1:4; - u8 frame_offset; + u8 frame_offset:6; + u8 res2:2; u8 ok_index; - u8 dma_ch_no; - u32 res2; + u8 res3; + u16 dma_ch_no; + u16 res4; } __packed val; }; @@ -535,6 +605,14 @@ struct tc956xmac_flow_entry { int is_l4; }; +struct tc956xmac_rfs_entry { + unsigned long cookie; + u16 etype; + int in_use; + int type; + int tc; +}; + struct tc956x_cbs_params { u32 send_slope; u32 idle_slope; @@ -548,12 +626,54 @@ struct tc956x_gpio_config { u8 out_val; /* 0 or 1 */ }; +struct drv_cap { + u8 csum_en; + u8 crc_en; + u8 tso_en; + u8 jumbo_en; +}; + +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) +struct sync_locks { + spinlock_t mac_filter; + spinlock_t vlan_filter; + spinlock_t est; + spinlock_t fpe; + spinlock_t frp; + spinlock_t cbs; +}; +#endif + +#ifdef TC956X_SRIOV_PF +struct work_queue_param { + struct ethtool_pauseparam pause; + struct ifreq rq; + u16 val_out[MAX_NO_OF_VFS]; + u32 queue_no; + u8 fn_id; + u8 vf_no; +}; +#endif + +/* Rx Frame Steering */ +enum tc956x_rfs_type { + TC956X_RFS_T_VLAN, + TC956X_RFS_T_LLDP, + TC956X_RFS_T_1588, + TC956X_RFS_T_MAX, +}; + struct tc956xmac_priv { /* Frequently used values are kept adjacent for cache effect */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 13, 0)) + u32 tx_coal_frames[MTL_MAX_TX_QUEUES]; + u32 tx_coal_timer[MTL_MAX_TX_QUEUES]; + u32 rx_coal_frames[MTL_MAX_TX_QUEUES]; +#else u32 tx_coal_frames; u32 tx_coal_timer; u32 rx_coal_frames; - +#endif int tx_coalesce; int hwts_tx_en; bool tx_path_in_lpi_mode; @@ -563,14 +683,27 @@ struct tc956xmac_priv { unsigned int dma_buf_sz; unsigned int rx_copybreak; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 13, 0)) + u32 rx_riwt[MTL_MAX_RX_QUEUES]; +#else u32 rx_riwt; +#endif int hwts_rx_en; void __iomem *ioaddr; -#ifdef TC956X +#ifdef TC956X_SRIOV_PF +#ifdef CONFIG_PCI_IOV + s32 sriov_enabled; +#endif +#endif void __iomem *tc956x_BRIDGE_CFG_pci_base_addr; void __iomem *tc956x_SRAM_pci_base_addr; void __iomem *tc956x_SFR_pci_base_addr; +#if defined(TC956X_SRIOV_PF) | defined(TC956X_SRIOV_VF) + void __iomem *tc956x_SRAM_mailbox_base_addr; +#endif +#ifdef TC956X_SRIOV_PF + unsigned char clear_to_send[MAX_NO_OF_VFS]; #endif struct net_device *dev; struct device *device; @@ -597,8 +730,10 @@ struct tc956xmac_priv { /* RX Parser */ bool rxp_enabled; - /* PHY state */ + /* Phy Link State */ + u32 link; int speed; + u32 duplex; bool oldlink; int oldduplex; @@ -606,15 +741,18 @@ struct tc956xmac_priv { unsigned int pause; struct mii_bus *mii; int mii_irq[PHY_MAX_ADDR]; - +#ifndef TC956X_SRIOV_VF struct phylink_config phylink_config; struct phylink *phylink; - +#endif struct tc956xmac_extra_stats xstats ____cacheline_aligned_in_smp; struct tc956xmac_safety_stats sstats; struct plat_tc956xmacenet_data *plat; struct dma_features dma_cap; struct tc956xmac_counters mmc; +#ifdef TC956X_SRIOV_VF + struct tc956x_sw_counters sw_stats; +#endif int hw_cap_support; int synopsys_id; u32 msg_enable; @@ -653,7 +791,17 @@ struct tc956xmac_priv { unsigned long state; struct workqueue_struct *wq; struct work_struct service_task; - +#ifdef TC956X_SRIOV_PF + struct workqueue_struct *mbx_wq; + struct work_struct service_mbx_task; + struct work_queue_param mbx_wq_param; +#endif + spinlock_t wq_lock; +#ifdef TC956X_SRIOV_VF + struct workqueue_struct *mbx_wq; + struct work_struct mbx_service_task; + unsigned char flag; +#endif /* CBS configurations */ struct tc956x_cbs_params cbs_speed100_cfg[8]; struct tc956x_cbs_params cbs_speed1000_cfg[8]; @@ -667,19 +815,39 @@ struct tc956xmac_priv { unsigned int flow_entries_max; struct tc956xmac_flow_entry *flow_entries; + unsigned int rfs_entries_max[TC956X_RFS_T_MAX]; + unsigned int rfs_entries_cnt[TC956X_RFS_T_MAX]; + unsigned int rfs_entries_total; + struct tc956xmac_rfs_entry *rfs_entries; + /* Pulse Per Second output */ struct tc956xmac_pps_cfg pps[TC956XMAC_PPS_MAX]; /* Receive Side Scaling */ struct tc956xmac_rss rss; - +#ifdef TC956X_SRIOV_PF + u8 dma_vf_map[TC956XMAC_CH_MAX]; + u8 pf_queue_dma_map[MTL_MAX_TX_QUEUES]; + /* Features enabled in PF */ + struct drv_cap pf_drv_cap; +#endif + /* Function ID information */ + struct fn_id fn_id_info; +#ifdef TC956X_SRIOV_VF + /* Features enabled in PF */ + struct drv_cap pf_drv_cap; +#endif /* Tx Checksum Insertion */ u32 csum_insertion; - +#if defined(TC956X_SRIOV_PF) | defined(TC956X_SRIOV_VF) + u32 rx_csum_state; +#endif /* CRC Tx Rx Configuraion */ u32 tx_crc_pad_state; u32 rx_crc_pad_state; - +#ifdef TC956X_SRIOV_PF + u8 rsc_dma_ch_alloc[MAX_FUNCTIONS_PER_PF]; +#endif /* eMAC port number */ #ifdef TC956X u32 port_num; @@ -704,7 +872,7 @@ struct tc956xmac_priv { /* Private data store for platform layer */ void *plat_priv; -#ifdef DMA_OFFLOAD_ENABLE +#ifdef TC956X_DMA_OFFLOAD_ENABLE void *client_priv; struct tc956xmac_cm3_tamap cm3_tamap[MAX_CM3_TAMAP_ENTRIES]; #endif @@ -712,16 +880,31 @@ struct tc956xmac_priv { struct work_struct emac_phy_work; u32 pm_saved_emac_rst; /* Save and restore EMAC Resets during suspend-resume sequence */ u32 pm_saved_emac_clk; /* Save and restore EMAC Clocks during suspend-resume sequence */ +#ifdef TC956X_SRIOV_PF +#ifdef TC956X_MAGIC_PACKET_WOL_CONF + bool wol_config_enabled; /* Flag to indicate SerDes configuration for SGMII, 1Gbps for WOL */ +#endif /* #ifdef TC956X_MAGIC_PACKET_WOL_CONF */ u32 pm_saved_linkdown_rst; /* Save and restore Resets during link-down sequence */ u32 pm_saved_linkdown_clk; /* Save and restore Clocks during link-down sequence */ bool port_link_down; /* Flag to save per port link down state */ bool port_release; /* Flag to notify appropriate sequence of link down & up */ struct mutex port_ld_release_lock; /* Mutex lock to handle (set and clear) flag to notify appropriate sequence of link down & up */ + +#endif struct tc956x_gpio_config saved_gpio_config[GPIO_12 + 1]; /* Only GPIO0- GPIO06, GPI010-GPIO12 are used */ #ifdef CONFIG_DEBUG_FS struct dentry *debugfs_dir; /* debugfs structure pointer for port specific */ #endif + +#ifdef TC956X_ENABLE_MAC2MAC_BRIDGE + void *pbridge_buffaddr; + dma_addr_t pbridge_handle; + size_t pbridge_buffsize; +#endif +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + struct sync_locks spn_lock; +#endif unsigned long link_state; bool link_down_rst; /* For light-weight release and open during link-down */ }; @@ -797,11 +980,10 @@ struct tc956x_regs_dma_ch { u32 buf_laddr; }; -struct tx956x_tx_desc_buf_addrs -{ +struct tx956x_tx_desc_buf_addrs { dma_addr_t desc_phy_addr; struct dma_desc *desc_va_addr; -#ifdef DMA_OFFLOAD_ENABLE +#ifdef TC956X_DMA_OFFLOAD_ENABLE dma_addr_t buff_phy_addr; void *buff_va_addr; #endif @@ -809,11 +991,10 @@ struct tx956x_tx_desc_buf_addrs struct tc956xmac_tx_info *tx_skbuff_dma; }; -struct tx956x_rx_desc_buf_addrs -{ +struct tx956x_rx_desc_buf_addrs { dma_addr_t desc_phy_addr; struct dma_desc *desc_va_addr; -#ifdef DMA_OFFLOAD_ENABLE +#ifdef TC956X_DMA_OFFLOAD_ENABLE dma_addr_t buff_phy_addr; void *buff_va_addr; #endif @@ -995,42 +1176,6 @@ struct tc956x_regs { int tc956x_dump_regs(struct net_device *net_device, struct tc956x_regs *regs); int tc956x_print_debug_regs(struct net_device *net_device, struct tc956x_regs *regs); - -/* for PTP offloading configuration */ -#define TC956X_PTP_OFFLOADING_DISABLE 0 -#define TC956X_PTP_OFFLOADING_ENABLE 1 - -#define TC956X_PTP_ORDINARY_SLAVE 1 -#define TC956X_PTP_ORDINARY_MASTER 2 -#define TC956X_PTP_TRASPARENT_SLAVE 3 -#define TC956X_PTP_TRASPARENT_MASTER 4 -#define TC956X_PTP_PEER_TO_PEER_TRANSPARENT 5 - -#define TC956X_AUX_SNAPSHOT_0 1 -#define TC956X_AUX_SNAPSHOT_1 2 -#define TC956X_AUX_SNAPSHOT_2 4 -#define TC956X_AUX_SNAPSHOT_3 8 - - -struct tc956x_ioctl_aux_snapshot { - __u32 cmd; - __u32 aux_snapshot_ctrl; -}; - -struct tc956x_config_ptpoffloading { - __u32 cmd; - int en_dis; - int mode; - int domain_num; - int mc_uc; - unsigned char mc_uc_addr[ETH_ALEN]; -}; - -struct tc956x_config_ost { - __u32 cmd; - int en_dis; -}; - int tc956xmac_mdio_unregister(struct net_device *ndev); int tc956xmac_mdio_register(struct net_device *ndev); int tc956xmac_mdio_reset(struct mii_bus *mii); @@ -1038,12 +1183,21 @@ void tc956xmac_set_ethtool_ops(struct net_device *netdev); void tc956xmac_ptp_register(struct tc956xmac_priv *priv); void tc956xmac_ptp_unregister(struct tc956xmac_priv *priv); +#ifdef TC956X_SRIOV_PF int tc956xmac_resume(struct device *dev); int tc956xmac_suspend(struct device *dev); int tc956xmac_dvr_remove(struct device *dev); int tc956xmac_dvr_probe(struct device *device, struct plat_tc956xmacenet_data *plat_dat, struct tc956xmac_resources *res); +#elif defined TC956X_SRIOV_VF +int tc956xmac_vf_resume(struct device *dev); +int tc956xmac_vf_suspend(struct device *dev); +int tc956xmac_vf_dvr_remove(struct device *dev); +int tc956xmac_vf_dvr_probe(struct device *device, + struct plat_tc956xmacenet_data *plat_dat, + struct tc956xmac_resources *res); +#endif void tc956xmac_disable_eee_mode(struct tc956xmac_priv *priv); bool tc956xmac_eee_init(struct tc956xmac_priv *priv); @@ -1071,9 +1225,16 @@ static inline int tc956xmac_selftest_get_count(struct tc956xmac_priv *priv) /* Function Prototypes */ +#ifndef TC956X_SRIOV_VF s32 tc956x_load_firmware(struct device *dev, struct tc956xmac_resources *res); - -int tc956x_set_pci_speed(struct pci_dev *pdev, u32 speed); +#endif +extern int tc956xmac_pm_usage_counter; +#if defined(TC956X_SRIOV_PF) && !defined(TC956X_AUTOMOTIVE_CONFIG) && !defined(TC956X_ENABLE_MAC2MAC_BRIDGE) +int tc956x_pf_get_fn_idx_from_int_sts(struct tc956xmac_priv *priv, + struct fn_id *fn_id_info); +void tc956x_pf_parse_mbx(struct tc956xmac_priv *priv, + enum mbx_msg_fns msg_src); +#endif #ifdef CONFIG_TC956X_PLATFORM_SUPPORT int tc956x_platform_probe(struct tc956xmac_priv *priv, struct tc956xmac_resources *res); @@ -1089,5 +1250,17 @@ static inline int tc956x_platform_resume(struct tc956xmac_priv *priv) { return 0 int tc956x_GPIO_OutputConfigPin(struct tc956xmac_priv *priv, u32 gpio_pin, u8 out_value); int tc956x_gpio_restore_configuration(struct tc956xmac_priv *priv); + +#ifdef TC956X_SRIOV_VF +int tc956x_vf_get_fn_idx_from_int_sts(struct tc956xmac_priv *priv, + struct fn_id *fn_id_info); +void tc956x_vf_parse_mbx(struct tc956xmac_priv *priv, + enum mbx_msg_fns msg_src); +int tc956x_vf_rsc_mng_get_fn_id(struct tc956xmac_priv *priv, void __iomem *reg_pci_bridge_config_addr, + struct fn_id *fn_id_info); + +#endif +int tc956x_set_pci_speed(struct pci_dev *pdev, u32 speed); void tc956xmac_link_change_set_power(struct tc956xmac_priv *priv, enum TC956X_PORT_LINK_CHANGE_STATE state); + #endif /* __TC956XMAC_H__ */ diff --git a/tc956xmac_ethtool.c b/tc956xmac_ethtool.c index ca7d25947315..d99f38253523 100644 --- a/tc956xmac_ethtool.c +++ b/tc956xmac_ethtool.c @@ -4,7 +4,7 @@ * tc956xmac_ethtool.c - Ethtool support * * Copyright (C) 2007-2009 STMicroelectronics Ltd - * Copyright (C) 2021 Toshiba Electronic Devices & Storage Corporation + * Copyright (C) 2023 Toshiba Electronic Devices & Storage Corporation * * This file has been derived from the STMicro Linux driver, * and developed or modified for TC956X. @@ -52,15 +52,20 @@ * VERSION : 01-00-41 * 22 Mar 2022 : 1. PCI bus info updated for ethtool get driver version * VERSION : 01-00-46 + * 10 Nov 2023 : 1. Kernel 6.1 Porting changes + * VERSION : 01-02-59 */ #include #include #include #include +#ifndef TC956X_SRIOV_VF #include +#endif /* TC956X_SRIOV_VF */ #include #include +#include #include "tc956xmac.h" #include "dwxgmac2.h" @@ -68,10 +73,23 @@ #define REG_SPACE_SIZE 11512/*Total Reg Len*/ #define MAC100_ETHTOOL_NAME "tc956x_mac100" #define GMAC_ETHTOOL_NAME "tc956x_gmac" +#ifdef TC956X_SRIOV_PF #define XGMAC_ETHTOOL_NAME TC956X_RESOURCE_NAME - +#elif defined TC956X_SRIOV_VF +#define XGMAC_ETHTOOL_NAME "tc956x_vf_pcie_eth" +#endif #define ETHTOOL_DMA_OFFSET 55 - +#ifdef TC956X_SRIOV_DEBUG +extern void tc956x_filter_debug(struct tc956xmac_priv *priv); +#endif +#ifndef TC956X_SRIOV_VF +void tc956xmac_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause); +int tc956xmac_ethtool_op_get_eee(struct net_device *dev, struct ethtool_eee *edata); +#endif +#ifdef TC956X_5_G_2_5_G_EEE_SUPPORT +#define TC956X_ADVERTISED_2500baseT_Full ETHTOOL_LINK_MODE_2500baseT_Full_BIT +#define TC956X_ADVERTISED_5000baseT_Full ETHTOOL_LINK_MODE_5000baseT_Full_BIT +#endif struct tc956xmac_stats { char stat_string[ETH_GSTRING_LEN]; int sizeof_stat; @@ -706,6 +724,18 @@ static const struct tc956xmac_stats tc956xmac_gstrings_stats[] = { TC956XMAC_STAT(m3_rx_pcie_addr_loc_port1[6]), TC956XMAC_STAT(m3_rx_pcie_addr_loc_port1[7]), +#ifdef TC956X_SRIOV_PF + TC956XMAC_STAT(mbx_pf_sent_vf[0]), + TC956XMAC_STAT(mbx_pf_sent_vf[1]), + TC956XMAC_STAT(mbx_pf_sent_vf[2]), + TC956XMAC_STAT(mbx_pf_rcvd_vf[0]), + TC956XMAC_STAT(mbx_pf_rcvd_vf[1]), + TC956XMAC_STAT(mbx_pf_rcvd_vf[2]), +#else + TC956XMAC_STAT(mbx_vf_sent_pf), + TC956XMAC_STAT(mbx_vf_rcvd_pf), +#endif + }; #define TC956XMAC_STATS_LEN ARRAY_SIZE(tc956xmac_gstrings_stats) @@ -805,6 +835,77 @@ static const struct tc956xmac_stats tc956xmac_mmc[] = { }; #define TC956XMAC_MMC_STATS_LEN ARRAY_SIZE(tc956xmac_mmc) +#ifdef TC956X_SRIOV_VF +/* SW counters */ +#define TC956X_SW_STAT(m) \ + { #m, sizeof_field(struct tc956x_sw_counters, m), \ + offsetof(struct tc956xmac_priv, sw_stats.m)} + +static const struct tc956xmac_stats tc956x_sw[] = { + TC956X_SW_STAT(tx_frame_count_good_bad), + TC956X_SW_STAT(rx_frame_count_good_bad), + TC956X_SW_STAT(rx_frame_count_good), + TC956X_SW_STAT(rx_fame_count_bad), + TC956X_SW_STAT(rx_packet_good_octets), + TC956X_SW_STAT(rx_header_good_octets), + TC956X_SW_STAT(rx_av_tagged_datapacket_count), + TC956X_SW_STAT(rx_av_tagged_controlpacket_count), + TC956X_SW_STAT(rx_nonav_packet_count), + TC956X_SW_STAT(rx_tunnel_packet_count), + TC956X_SW_STAT(rx_non_ip_pkt_count), + TC956X_SW_STAT(rx_ipv4_tcp_pkt_count), + TC956X_SW_STAT(rx_ipv4_udp_pkt_count), + TC956X_SW_STAT(rx_ipv4_icmp_pkt_count), + TC956X_SW_STAT(rx_ipv4_igmp_pkt_count), + TC956X_SW_STAT(rx_ipv4_unkown_pkt_count), + TC956X_SW_STAT(rx_ipv6_tcp_pkt_count), + TC956X_SW_STAT(rx_ipv6_udp_pkt_count), + TC956X_SW_STAT(rx_ipv6_icmp_pkt_count), + TC956X_SW_STAT(rx_ipv6_unkown_pkt_count), + TC956X_SW_STAT(rx_err_wd_timeout_count), + TC956X_SW_STAT(rx_err_gmii_inv_count), + TC956X_SW_STAT(rx_err_crc_count), + TC956X_SW_STAT(rx_err_giant_count), + TC956X_SW_STAT(rx_err_checksum_count), + TC956X_SW_STAT(rx_err_overflow_count), + TC956X_SW_STAT(rx_err_bus_count), + TC956X_SW_STAT(rx_err_pkt_len_count), + TC956X_SW_STAT(rx_err_runt_pkt_count), + TC956X_SW_STAT(rx_err_dribble_count), + TC956X_SW_STAT(rx_err_t_out_ip_header_count), + TC956X_SW_STAT(rx_err_t_out_ip_pl_l4_csum_count), + TC956X_SW_STAT(rx_err_t_in_ip_header_count), + TC956X_SW_STAT(rx_err_t_in_ip_pl_l4_csum_count), + TC956X_SW_STAT(rx_err_t_invalid_vlan_header), + TC956X_SW_STAT(rx_l2_len_pkt_count), + TC956X_SW_STAT(rx_l2_mac_control_pkt_count), + TC956X_SW_STAT(rx_l2_dcb_control_pkt_count), + TC956X_SW_STAT(rx_l2_arp_pkt_count), + TC956X_SW_STAT(rx_l2_oam_type_pkt_count), + TC956X_SW_STAT(rx_l2_untg_typ_match_pkt_count), + TC956X_SW_STAT(rx_l2_other_type_pkt_count), + TC956X_SW_STAT(rx_l2_single_svlan_pkt_count), + TC956X_SW_STAT(rx_l2_single_cvlan_pkt_count), + TC956X_SW_STAT(rx_l2_d_cvlan_cvlan_pkt_count), + TC956X_SW_STAT(rx_l2_d_svlan_svlan_pkt_count), + TC956X_SW_STAT(rx_l2_d_svlan_cvlan_pkt_count), + TC956X_SW_STAT(rx_l2_d_cvlan_svlan_pkt_count), + TC956X_SW_STAT(rx_l2_untg_av_control_pkt_count), + TC956X_SW_STAT(rx_ptp_no_msg), + TC956X_SW_STAT(rx_ptp_msg_type_sync), + TC956X_SW_STAT(rx_ptp_msg_type_follow_up), + TC956X_SW_STAT(rx_ptp_msg_type_delay_req), + TC956X_SW_STAT(rx_ptp_msg_type_delay_resp), + TC956X_SW_STAT(rx_ptp_msg_type_pdelay_req), + TC956X_SW_STAT(rx_ptp_msg_type_pdelay_resp), + TC956X_SW_STAT(rx_ptp_msg_type_pdelay_follow_up), + TC956X_SW_STAT(rx_ptp_msg_type_announce), + TC956X_SW_STAT(rx_ptp_msg_type_management), + TC956X_SW_STAT(rx_ptp_msg_pkt_signaling), + TC956X_SW_STAT(rx_ptp_msg_pkt_reserved_type), +}; +#define TC956X_SW_STATS_LEN ARRAY_SIZE(tc956x_sw) +#endif static const char tc956x_priv_flags_strings[][ETH_GSTRING_LEN] = { #define TC956XMAC_TX_FCS BIT(0) "tx-fcs", @@ -845,7 +946,7 @@ static void tc956xmac_ethtool_getdrvinfo(struct net_device *dev, info->n_priv_flags = TC956X_PRIV_FLAGS_STR_LEN; } - +#ifndef TC956X_SRIOV_VF static int tc956xmac_ethtool_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *cmd) { @@ -961,11 +1062,13 @@ tc956xmac_ethtool_set_link_ksettings(struct net_device *dev, ADVERTISED_10baseT_Full); mutex_lock(&priv->lock); +#ifndef TC956X_SRIOV_VF #ifdef TC956X tc956x_xpcs_ctrl_ane(priv, 1); #else tc956xmac_pcs_ctrl_ane(priv, priv->ioaddr, 1, priv->hw->ps, 0); #endif +#endif /* TC956X_SRIOV_VF */ mutex_unlock(&priv->lock); return 0; @@ -980,7 +1083,7 @@ tc956xmac_ethtool_set_link_ksettings(struct net_device *dev, return -ENODEV; return phylink_ethtool_ksettings_set(priv->phylink, cmd); } - +#endif /* TC956X_SRIOV_VF */ static u32 tc956xmac_ethtool_getmsglevel(struct net_device *dev) { struct tc956xmac_priv *priv = netdev_priv(dev); @@ -1012,6 +1115,58 @@ static int tc956xmac_ethtool_get_regs_len(struct net_device *dev) return REG_SPACE_SIZE * sizeof(u32); } +#ifdef TC956X_SRIOV_PF +#ifdef TC956X_SRIOV_DEBUG +static u32 rxp_read_frp_stat(struct tc956xmac_priv *priv, void __iomem *ioaddr, + int pos) +{ + int ret; + + u32 val; + + /* Wait for ready */ + ret = readl_poll_timeout(ioaddr + XGMAC_MTL_RXP_IACC_CTRL_ST, + val, !(val & XGMAC_STARTBUSY), 1, 10000); + if (ret) + return ret; + + /* Write pos */ + val = pos & XGMAC_ADDR; + val |= XGMAC_ACCSEL; + writel(val, ioaddr + XGMAC_MTL_RXP_IACC_CTRL_ST); + + /* Start Read */ + val |= XGMAC_STARTBUSY; + writel(val, ioaddr + XGMAC_MTL_RXP_IACC_CTRL_ST); + + /* Wait for done */ + ret = readl_poll_timeout(ioaddr + XGMAC_MTL_RXP_IACC_CTRL_ST, + val, !(val & XGMAC_STARTBUSY), 1, 10000); + if (ret) { + netdev_err(priv->dev, "timeout error\n"); + return ret; + } else + return readl(ioaddr + XGMAC_MTL_RXP_IACC_DATA); + +} + +static void tc956x_read_frp_stats(struct tc956xmac_priv *priv) +{ + u32 ch; + + netdev_info(priv->dev, "For MTL_RXP_Drop_Cnt %d", (0x7FFFFFFF & rxp_read_frp_stat(priv, priv->ioaddr, 0))); + netdev_info(priv->dev, "For MTL_RXP_Error_Cnt %d", (0x7FFFFFFF & rxp_read_frp_stat(priv, priv->ioaddr, 1))); + netdev_info(priv->dev, "For MTL_RXP_Bypass_Cnt %d", (0x7FFFFFFF & rxp_read_frp_stat(priv, priv->ioaddr, 2))); + + for (ch = 0; ch < TC956XMAC_CH_MAX; ch++) { + u32 read_pos = (0x40 + (0x10*ch)); + + netdev_info(priv->dev, "For DMA_CH%d_RXP_Accept_Cnt %d", ch, (0x7FFFFFFF & rxp_read_frp_stat(priv, priv->ioaddr, read_pos))); + } +} +#endif /* TC956X_SRIOV_DEBUG */ +#endif /* TC956X_SRIOV_PF */ + static void tc956xmac_ethtool_gregs(struct net_device *dev, struct ethtool_regs *regs, void *space) { @@ -1020,7 +1175,12 @@ static void tc956xmac_ethtool_gregs(struct net_device *dev, tc956xmac_dump_mac_regs(priv, priv->hw, reg_space); tc956xmac_dump_dma_regs(priv, priv->ioaddr, reg_space); - +#ifdef TC956X_SRIOV_PF +#ifdef TC956X_SRIOV_DEBUG + tc956x_read_frp_stats(priv); + tc956x_filter_debug(priv); +#endif +#endif #ifndef TC956X if (!priv->plat->has_xgmac && !priv->plat->has_gmac4) { /* Copy DMA registers to where ethtool expects them */ @@ -1032,15 +1192,28 @@ static void tc956xmac_ethtool_gregs(struct net_device *dev, } #ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE +#ifndef TC956X_SRIOV_VF static int tc956xmac_nway_reset(struct net_device *dev) { struct tc956xmac_priv *priv = netdev_priv(dev); return phylink_ethtool_nway_reset(priv->phylink); } +#endif /* TC956X_SRIOV_VF */ #endif +#ifdef TC956X_SRIOV_VF static void +tc956xmac_get_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct tc956xmac_priv *priv = netdev_priv(netdev); + + tc956xmac_ethtool_get_pauseparam(priv, pause); +} +#endif +#ifndef TC956X_SRIOV_VF +void tc956xmac_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) { @@ -1058,6 +1231,7 @@ tc956xmac_get_pauseparam(struct net_device *netdev, pause->tx_pause = (priv->flow_ctrl & FLOW_TX); } } +#endif static int tc956xmac_set_pauseparam(struct net_device *netdev, @@ -1081,7 +1255,9 @@ tc956xmac_set_pauseparam(struct net_device *netdev, return -EOPNOTSUPP; return 0; } else { +#ifndef TC956X_SRIOV_VF phylink_ethtool_set_pauseparam(priv->phylink, pause); +#endif /* TC956X_SRIOV_VF */ } if (pause->rx_pause) new_pause |= FLOW_RX; @@ -1093,11 +1269,13 @@ tc956xmac_set_pauseparam(struct net_device *netdev, priv->pause, tx_cnt); return 0; } + +#ifndef TC956X_SRIOV_VF static void tc956xmac_m3fw_stats_read(struct tc956xmac_priv *priv) { u32 rx_queues_count = priv->plat->rx_queues_to_use; u32 tx_queues_count = priv->plat->tx_queues_to_use; - u32 chno, reg_val=0; + u32 chno, reg_val = 0; for (chno = 0; chno < tx_queues_count; chno++) { /* Tx Underflow count may not match with actual value, as it is 11bit value @@ -1119,74 +1297,110 @@ static void tc956xmac_m3fw_stats_read(struct tc956xmac_priv *priv) readl(priv->ioaddr + XGMAC_DMA_CH_Rx_WATCHDOG(chno)); } /* Reading M3 Debug Counters*/ - priv->xstats.m3_debug_cnt0 = readl(priv->tc956x_SRAM_pci_base_addr + - (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT0 ))); - priv->xstats.m3_debug_cnt1 = readl(priv->tc956x_SRAM_pci_base_addr + - (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT1 ))); - priv->xstats.m3_debug_cnt2 = readl(priv->tc956x_SRAM_pci_base_addr + - (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT2 ))); - priv->xstats.m3_debug_cnt3 = readl(priv->tc956x_SRAM_pci_base_addr + - (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT3 ))); - priv->xstats.m3_debug_cnt4 = readl(priv->tc956x_SRAM_pci_base_addr + - (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT4 ))); - priv->xstats.m3_debug_cnt5 = readl(priv->tc956x_SRAM_pci_base_addr + - (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT5 ))); - priv->xstats.m3_debug_cnt6 = readl(priv->tc956x_SRAM_pci_base_addr + - (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT6 ))); - priv->xstats.m3_debug_cnt7 = readl(priv->tc956x_SRAM_pci_base_addr + - (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT7 ))); - priv->xstats.m3_debug_cnt8 = readl(priv->tc956x_SRAM_pci_base_addr + - (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT8 ))); - priv->xstats.m3_debug_cnt9 = readl(priv->tc956x_SRAM_pci_base_addr + - (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT9 ))); - priv->xstats.m3_debug_cnt10 = readl(priv->tc956x_SRAM_pci_base_addr + - (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT10 ))); - priv->xstats.m3_watchdog_exp_cnt = readl(priv->tc956x_SRAM_pci_base_addr + - (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT11 ))); - priv->xstats.m3_watchdog_monitor_cnt = readl(priv->tc956x_SRAM_pci_base_addr + - (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT12 ))); - priv->xstats.m3_debug_cnt13 = readl(priv->tc956x_SRAM_pci_base_addr + - (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT13 ))); - priv->xstats.m3_debug_cnt14 = readl(priv->tc956x_SRAM_pci_base_addr + - (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT14 ))); - priv->xstats.m3_systick_cnt_upper_value = readl(priv->tc956x_SRAM_pci_base_addr + - (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT16 ))); - priv->xstats.m3_systick_cnt_lower_value = readl(priv->tc956x_SRAM_pci_base_addr + - (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT15 ))); - priv->xstats.m3_tx_timeout_port0 = readl(priv->tc956x_SRAM_pci_base_addr + - (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT17 ))); - priv->xstats.m3_tx_timeout_port1 = readl(priv->tc956x_SRAM_pci_base_addr + - (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT18 ))); - priv->xstats.m3_debug_cnt19 = readl(priv->tc956x_SRAM_pci_base_addr + - (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT19 ))); + priv->xstats.m3_debug_cnt0 = readl(priv->tc956x_SRAM_pci_base_addr + + (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT0))); + priv->xstats.m3_debug_cnt1 = readl(priv->tc956x_SRAM_pci_base_addr + + (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT1))); + priv->xstats.m3_debug_cnt2 = readl(priv->tc956x_SRAM_pci_base_addr + + (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT2))); + priv->xstats.m3_debug_cnt3 = readl(priv->tc956x_SRAM_pci_base_addr + + (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT3))); + priv->xstats.m3_debug_cnt4 = readl(priv->tc956x_SRAM_pci_base_addr + + (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT4))); + priv->xstats.m3_debug_cnt5 = readl(priv->tc956x_SRAM_pci_base_addr + + (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT5))); + priv->xstats.m3_debug_cnt6 = readl(priv->tc956x_SRAM_pci_base_addr + + (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT6))); + priv->xstats.m3_debug_cnt7 = readl(priv->tc956x_SRAM_pci_base_addr + + (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT7))); + priv->xstats.m3_debug_cnt8 = readl(priv->tc956x_SRAM_pci_base_addr + + (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT8))); + priv->xstats.m3_debug_cnt9 = readl(priv->tc956x_SRAM_pci_base_addr + + (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT9))); + priv->xstats.m3_debug_cnt10 = readl(priv->tc956x_SRAM_pci_base_addr + + (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT10))); + priv->xstats.m3_watchdog_exp_cnt = readl(priv->tc956x_SRAM_pci_base_addr + + (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT11))); + priv->xstats.m3_watchdog_monitor_cnt = readl(priv->tc956x_SRAM_pci_base_addr + + (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT12))); + priv->xstats.m3_debug_cnt13 = readl(priv->tc956x_SRAM_pci_base_addr + + (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT13))); + priv->xstats.m3_debug_cnt14 = readl(priv->tc956x_SRAM_pci_base_addr + + (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT14))); + priv->xstats.m3_systick_cnt_upper_value = readl(priv->tc956x_SRAM_pci_base_addr + + (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT16))); + priv->xstats.m3_systick_cnt_lower_value = readl(priv->tc956x_SRAM_pci_base_addr + + (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT15))); + priv->xstats.m3_tx_timeout_port0 = readl(priv->tc956x_SRAM_pci_base_addr + + (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT17))); + priv->xstats.m3_tx_timeout_port1 = readl(priv->tc956x_SRAM_pci_base_addr + + (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT18))); + priv->xstats.m3_debug_cnt19 = readl(priv->tc956x_SRAM_pci_base_addr + + (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT19))); for (chno = 0; chno < tx_queues_count; chno++) { - priv->xstats.m3_tx_pcie_addr_loc_port0[chno] = readl(priv->tc956x_SRAM_pci_base_addr + - (SRAM_TX_PCIE_ADDR_LOC + (chno * 4 ))); + priv->xstats.m3_tx_pcie_addr_loc_port0[chno] = readl(priv->tc956x_SRAM_pci_base_addr + + (SRAM_TX_PCIE_ADDR_LOC + (chno * 4))); } for (chno = 0; chno < tx_queues_count; chno++) { - priv->xstats.m3_tx_pcie_addr_loc_port1[chno] = readl(priv->tc956x_SRAM_pci_base_addr + - (SRAM_TX_PCIE_ADDR_LOC + (TC956XMAC_CH_MAX * 4) + (chno * 4 ))); + priv->xstats.m3_tx_pcie_addr_loc_port1[chno] = readl(priv->tc956x_SRAM_pci_base_addr + + (SRAM_TX_PCIE_ADDR_LOC + (TC956XMAC_CH_MAX * 4) + (chno * 4))); } for (chno = 0; chno < rx_queues_count; chno++) { - priv->xstats.m3_rx_pcie_addr_loc_port0[chno] = readl(priv->tc956x_SRAM_pci_base_addr + - (SRAM_RX_PCIE_ADDR_LOC + (chno * 4 ))); + priv->xstats.m3_rx_pcie_addr_loc_port0[chno] = readl(priv->tc956x_SRAM_pci_base_addr + + (SRAM_RX_PCIE_ADDR_LOC + (chno * 4))); } for (chno = 0; chno < rx_queues_count; chno++) { - priv->xstats.m3_rx_pcie_addr_loc_port1[chno] = readl(priv->tc956x_SRAM_pci_base_addr + - (SRAM_RX_PCIE_ADDR_LOC + (TC956XMAC_CH_MAX * 4) + (chno * 4 ))); + priv->xstats.m3_rx_pcie_addr_loc_port1[chno] = readl(priv->tc956x_SRAM_pci_base_addr + + (SRAM_RX_PCIE_ADDR_LOC + (TC956XMAC_CH_MAX * 4) + (chno * 4))); } } +#endif static void tc956xmac_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *dummy, u64 *data) { struct tc956xmac_priv *priv = netdev_priv(dev); + u32 rx_queues_count = priv->plat->rx_queues_to_use; u32 tx_queues_count = priv->plat->tx_queues_to_use; +#ifndef TC956X_SRIOV_VF unsigned long count; - int i, j = 0, ret; +#endif + int i, j = 0; +#ifndef TC956X_SRIOV_VF + int ret; +#endif +#ifdef TC956X_SRIOV_VF + + /* Copy only the SW stats for VF driver */ + for (i = 0; i < TC956X_SW_STATS_LEN; i++) { + char *p; + + p = (char *)priv + tc956x_sw[i].stat_offset; + + data[j++] = (tc956x_sw[i].sizeof_stat == + sizeof(u64)) ? (*(u64 *)p) : + (*(u32 *)p); + } + + if (priv->synopsys_id >= DWMAC_CORE_3_50 || + priv->synopsys_id == DWXGMAC_CORE_3_01) { + tc956xmac_mac_debug(priv, priv->ioaddr, + (void *)&priv->xstats, + rx_queues_count, tx_queues_count); + + tc956xmac_dma_desc_stats(priv, priv->ioaddr); + } + + for (i = 0; i < TC956XMAC_STATS_LEN; i++) { + char *p = (char *)priv + tc956xmac_gstrings_stats[i].stat_offset; + + data[j++] = (tc956xmac_gstrings_stats[i].sizeof_stat == + sizeof(u64)) ? (*(u64 *)p) : (*(u32 *)p); + } +#else if (priv->dma_cap.asp) { for (i = 0; i < TC956XMAC_SAFETY_FEAT_SIZE; i++) { if (!tc956xmac_safety_feat_dump(priv, &priv->sstats, i, @@ -1213,13 +1427,14 @@ static void tc956xmac_get_ethtool_stats(struct net_device *dev, (*(u32 *)p); } } +#ifndef TC956X_SRIOV_VF if (priv->eee_enabled) { int val = phylink_get_eee_err(priv->phylink); if (val) priv->xstats.phy_eee_wakeup_error_n = val; } - +#endif /* TC956X_SRIOV_VF */ if (priv->synopsys_id >= DWMAC_CORE_3_50 || priv->synopsys_id == DWXGMAC_CORE_3_01) { tc956xmac_mac_debug(priv, priv->ioaddr, @@ -1236,15 +1451,23 @@ static void tc956xmac_get_ethtool_stats(struct net_device *dev, data[j++] = (tc956xmac_gstrings_stats[i].sizeof_stat == sizeof(u64)) ? (*(u64 *)p) : (*(u32 *)p); } +#endif } static int tc956xmac_get_sset_count(struct net_device *netdev, int sset) { struct tc956xmac_priv *priv = netdev_priv(netdev); +#ifdef TC956X_SRIOV_VF + int len; +#else int i, len, safety_len = 0; +#endif switch (sset) { case ETH_SS_STATS: +#ifdef TC956X_SRIOV_VF + len = TC956X_SW_STATS_LEN + TC956XMAC_STATS_LEN; +#else len = TC956XMAC_STATS_LEN; if (priv->dma_cap.rmon) @@ -1259,13 +1482,12 @@ static int tc956xmac_get_sset_count(struct net_device *netdev, int sset) len += safety_len; } - +#endif return len; case ETH_SS_TEST: return tc956xmac_selftest_get_count(priv); case ETH_SS_PRIV_FLAGS: return TC956X_PRIV_FLAGS_STR_LEN; - break; default: return -EOPNOTSUPP; } @@ -1279,6 +1501,13 @@ static void tc956xmac_get_strings(struct net_device *dev, u32 stringset, u8 *dat switch (stringset) { case ETH_SS_STATS: +#ifdef TC956X_SRIOV_VF + for (i = 0; i < TC956X_SW_STATS_LEN; i++) { + memcpy(p, tc956x_sw[i].stat_string, + ETH_GSTRING_LEN); + p += ETH_GSTRING_LEN; + } +#else if (priv->dma_cap.asp) { for (i = 0; i < TC956XMAC_SAFETY_FEAT_SIZE; i++) { const char *desc; @@ -1297,11 +1526,13 @@ static void tc956xmac_get_strings(struct net_device *dev, u32 stringset, u8 *dat ETH_GSTRING_LEN); p += ETH_GSTRING_LEN; } +#endif for (i = 0; i < TC956XMAC_STATS_LEN; i++) { memcpy(p, tc956xmac_gstrings_stats[i].stat_string, ETH_GSTRING_LEN); p += ETH_GSTRING_LEN; } + break; case ETH_SS_TEST: tc956xmac_selftest_get_strings(priv, p); @@ -1316,6 +1547,8 @@ static void tc956xmac_get_strings(struct net_device *dev, u32 stringset, u8 *dat } } +#ifndef TC956X_SRIOV_VF + static void tc956xmac_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { struct tc956xmac_priv *priv = netdev_priv(dev); @@ -1359,7 +1592,7 @@ int phy_ethtool_get_eee_local(struct phy_device *phydev, struct ethtool_eee *dat /* Get Supported EEE */ val = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_EEE_ABLE); - KPRINT_INFO("%s --- cap: 0x%x\n",__func__,val); + KPRINT_INFO("%s --- cap: 0x%x\n", __func__, val); if (val < 0) return val; data->supported = mmd_eee_cap_to_ethtool_sup_t(val); @@ -1369,8 +1602,8 @@ int phy_ethtool_get_eee_local(struct phy_device *phydev, struct ethtool_eee *dat if (val < 0) return val; - KPRINT_INFO("%s --- adv: 0x%x\n",__func__,val); - + KPRINT_INFO("%s --- adv: 0x%x\n", __func__, val); + data->advertised = mmd_eee_adv_to_ethtool_adv_t(val); data->eee_enabled = !!data->advertised; @@ -1378,18 +1611,18 @@ int phy_ethtool_get_eee_local(struct phy_device *phydev, struct ethtool_eee *dat val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_LPABLE); if (val < 0) return val; - KPRINT_INFO("%s --- lp_adv: 0x%x\n",__func__,val); - + KPRINT_INFO("%s --- lp_adv: 0x%x\n", __func__, val); + data->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(val); - KPRINT_INFO("%s --- data->advertised: 0x%x\n",__func__,data->advertised); - KPRINT_INFO("%s --- data->lp_advertised: 0x%x\n",__func__,data->lp_advertised); + KPRINT_INFO("%s --- data->advertised: 0x%x\n", __func__, data->advertised); + KPRINT_INFO("%s --- data->lp_advertised: 0x%x\n", __func__, data->lp_advertised); data->eee_active = !!(data->advertised & data->lp_advertised); - KPRINT_INFO("%s --- data->eee_enabled: 0x%x\n",__func__,data->eee_enabled); - KPRINT_INFO("%s --- data->eee_active: 0x%x\n",__func__,data->eee_active); + KPRINT_INFO("%s --- data->eee_enabled: 0x%x\n", __func__, data->eee_enabled); + KPRINT_INFO("%s --- data->eee_active: 0x%x\n", __func__, data->eee_active); return 0; } @@ -1404,13 +1637,13 @@ int phy_ethtool_set_eee_local(struct phy_device *phydev, struct ethtool_eee *dat /* Get Supported EEE */ cap = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_EEE_ABLE); - KPRINT_INFO("%s --- cap: 0x%x\n",__func__,cap); + KPRINT_INFO("%s --- cap: 0x%x\n", __func__, cap); if (cap < 0) return cap; old_adv = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV); - KPRINT_INFO("%s --- old_adv:0x%x\n",__func__,old_adv); + KPRINT_INFO("%s --- old_adv:0x%x\n", __func__, old_adv); if (old_adv < 0) return old_adv; @@ -1421,7 +1654,7 @@ int phy_ethtool_set_eee_local(struct phy_device *phydev, struct ethtool_eee *dat /* Mask prohibited EEE modes */ adv &= ~phydev->eee_broken_modes; } - KPRINT_INFO("%s --- adv:0x%x\n",__func__,adv); + KPRINT_INFO("%s --- adv:0x%x\n", __func__, adv); if (old_adv != adv) { ret = phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, adv); @@ -1429,7 +1662,7 @@ int phy_ethtool_set_eee_local(struct phy_device *phydev, struct ethtool_eee *dat return ret; ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV); - KPRINT_INFO("%s --- readback adv:0x%x\n",__func__,ret); + KPRINT_INFO("%s --- readback adv:0x%x\n", __func__, ret); if (ret < 0) return ret; @@ -1445,12 +1678,12 @@ int phy_ethtool_set_eee_local(struct phy_device *phydev, struct ethtool_eee *dat } #ifdef TC956X_5_G_2_5_G_EEE_SUPPORT cap2p5 = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_EEE_ABLE2); - KPRINT_INFO("%s --- cap2p5: 0x%x\n",__func__,cap2p5); + KPRINT_INFO("%s --- cap2p5: 0x%x\n", __func__, cap2p5); if (cap < 0) return cap; old_adv_2p5 = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV2); - KPRINT_INFO("%s --- old_adv_2p5:0x%x\n",__func__,old_adv_2p5); + KPRINT_INFO("%s --- old_adv_2p5:0x%x\n", __func__, old_adv_2p5); if (old_adv_2p5 < 0) return old_adv_2p5; @@ -1460,7 +1693,7 @@ int phy_ethtool_set_eee_local(struct phy_device *phydev, struct ethtool_eee *dat /* Mask prohibited EEE modes */ adv_2p5 &= ~phydev->eee_broken_modes; } - KPRINT_INFO("%s --- adv_2p5:0x%x\n",__func__,adv_2p5); + KPRINT_INFO("%s --- adv_2p5:0x%x\n", __func__, adv_2p5); if (old_adv_2p5 != adv_2p5) { ret = phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV2, adv_2p5); @@ -1483,30 +1716,44 @@ int phy_ethtool_set_eee_local(struct phy_device *phydev, struct ethtool_eee *dat #endif #ifdef TC956X_5_G_2_5_G_EEE_SUPPORT + +static inline u16 tc956x_ethtool_adv_to_mmd_eee_adv2_t(u32 adv) +{ + u16 reg = 0; + + if (adv & TC956X_ADVERTISED_2500baseT_Full) + reg |= MDIO_EEE_2_5GT; + if (adv & TC956X_ADVERTISED_5000baseT_Full) + reg |= MDIO_EEE_5GT; + + return reg; +} + int phy_ethtool_set_eee_2p5(struct phy_device *phydev, struct ethtool_eee *data) { int ret; int cap2p5, old_adv_2p5, adv_2p5 = 0; + if (!phydev->drv) return -EIO; cap2p5 = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_EEE_ABLE2); - KPRINT_INFO("%s --- cap2p5: 0x%x\n",__func__,cap2p5); + KPRINT_INFO("%s --- cap2p5: 0x%x\n", __func__, cap2p5); if (cap2p5 < 0) return cap2p5; old_adv_2p5 = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV2); - KPRINT_INFO("%s --- old_adv_2p5:0x%x\n",__func__,old_adv_2p5); + KPRINT_INFO("%s --- old_adv_2p5:0x%x\n", __func__, old_adv_2p5); if (old_adv_2p5 < 0) return old_adv_2p5; - + /* EEE advertise checking API corrected for 2.5G and 5G speeds. */ if (data->eee_enabled) { adv_2p5 = !data->advertised ? cap2p5 : - ethtool_adv_to_mmd_eee_adv_t(data->advertised) & cap2p5; + tc956x_ethtool_adv_to_mmd_eee_adv2_t(data->advertised) & cap2p5; /* Mask prohibited EEE modes */ adv_2p5 &= ~phydev->eee_broken_modes; } - KPRINT_INFO("%s --- adv_2p5:0x%x\n",__func__,adv_2p5); + KPRINT_INFO("%s --- adv_2p5:0x%x\n", __func__, adv_2p5); if (old_adv_2p5 != adv_2p5) { ret = phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV2, adv_2p5); @@ -1526,7 +1773,7 @@ int phy_ethtool_set_eee_2p5(struct phy_device *phydev, struct ethtool_eee *data) } #endif -static int tc956xmac_ethtool_op_get_eee(struct net_device *dev, +int tc956xmac_ethtool_op_get_eee(struct net_device *dev, struct ethtool_eee *edata) { struct tc956xmac_priv *priv = netdev_priv(dev); @@ -1542,7 +1789,7 @@ static int tc956xmac_ethtool_op_get_eee(struct net_device *dev, DBGPR_FUNC(priv->device, "1--> %s edata->eee_active: %d\n", __func__, edata->eee_active); #ifndef DEBUG_EEE ret = phylink_ethtool_get_eee(priv->phylink, edata); -#else +#else ret = phy_ethtool_get_eee_local(priv->dev->phydev, edata); #endif @@ -1555,13 +1802,25 @@ static int tc956xmac_ethtool_op_get_eee(struct net_device *dev, return ret; } +#endif +#ifdef TC956X_SRIOV_VF +static int tc956xmac_ethtool_op_get_eee(struct net_device *dev, + struct ethtool_eee *edata) +{ + struct tc956xmac_priv *priv = netdev_priv(dev); + tc956xmac_ethtool_get_eee(priv, edata); + + return 0; +} +#endif static int tc956xmac_ethtool_op_set_eee(struct net_device *dev, struct ethtool_eee *edata) { struct tc956xmac_priv *priv = netdev_priv(dev); +#ifndef TC956X_SRIOV_VF int ret; - +#endif if (!edata->eee_enabled) { DBGPR_FUNC(priv->device, "%s Disable EEE\n", __func__); tc956xmac_disable_eee_mode(priv); @@ -1584,7 +1843,7 @@ static int tc956xmac_ethtool_op_set_eee(struct net_device *dev, if (!edata->eee_enabled) return -EOPNOTSUPP; } - +#ifndef TC956X_SRIOV_VF #ifndef DEBUG_EEE ret = phylink_ethtool_set_eee(priv->phylink, edata); @@ -1594,7 +1853,7 @@ static int tc956xmac_ethtool_op_set_eee(struct net_device *dev, #endif if (ret) return ret; - +#endif /* TC956X_SRIOV_VF */ priv->eee_enabled = edata->eee_enabled; priv->tx_lpi_timer = edata->tx_lpi_timer; @@ -1645,7 +1904,133 @@ static u32 tc956xmac_riwt2usec(u32 riwt, struct tc956xmac_priv *priv) return (riwt * mult) / (clk / 1000000); } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 13, 0)) +static int __tc956xmac_get_coalesce(struct net_device *dev, + struct ethtool_coalesce *ec, + int queue) +{ + struct tc956xmac_priv *priv = netdev_priv(dev); + u32 max_cnt; + u32 rx_cnt; + u32 tx_cnt; + rx_cnt = priv->plat->rx_queues_to_use; + tx_cnt = priv->plat->tx_queues_to_use; + max_cnt = max(rx_cnt, tx_cnt); + + if (queue < 0) + queue = 0; + else if (queue >= max_cnt) + return -EINVAL; + + if (queue < tx_cnt) { + ec->tx_coalesce_usecs = priv->tx_coal_timer[queue]; + ec->tx_max_coalesced_frames = priv->tx_coal_frames[queue]; + } else { + ec->tx_coalesce_usecs = 0; + ec->tx_max_coalesced_frames = 0; + } + + if (priv->use_riwt && queue < rx_cnt) { + ec->rx_max_coalesced_frames = priv->rx_coal_frames[queue]; + ec->rx_coalesce_usecs = tc956xmac_riwt2usec(priv->rx_riwt[queue], + priv); + } else { + ec->rx_max_coalesced_frames = 0; + ec->rx_coalesce_usecs = 0; + } + + return 0; +} + +static int tc956xmac_get_coalesce(struct net_device *dev, + struct ethtool_coalesce *ec, + struct kernel_ethtool_coalesce *kernel_coal, + struct netlink_ext_ack *extack) +{ + return __tc956xmac_get_coalesce(dev, ec, -1); +} + +static int __tc956xmac_set_coalesce(struct net_device *dev, + struct ethtool_coalesce *ec, + int queue) +{ + struct tc956xmac_priv *priv = netdev_priv(dev); + bool all_queues = false; + unsigned int rx_riwt; + u32 max_cnt; + u32 rx_cnt; + u32 tx_cnt; + + rx_cnt = priv->plat->rx_queues_to_use; + tx_cnt = priv->plat->tx_queues_to_use; + max_cnt = max(rx_cnt, tx_cnt); + + if (queue < 0) + all_queues = true; + else if (queue >= max_cnt) + return -EINVAL; + + if (priv->use_riwt && (ec->rx_coalesce_usecs > 0)) { + rx_riwt = tc956xmac_usec2riwt(ec->rx_coalesce_usecs, priv); + + if ((rx_riwt > MAX_DMA_RIWT) || (rx_riwt < MIN_DMA_RIWT)) + return -EINVAL; + + if (all_queues) { + int i; + + for (i = 0; i < rx_cnt; i++) { + priv->rx_riwt[i] = rx_riwt; + tc956xmac_rx_watchdog(priv, priv->ioaddr, + rx_riwt, i); + priv->rx_coal_frames[i] = + ec->rx_max_coalesced_frames; + } + } else if (queue < rx_cnt) { + priv->rx_riwt[queue] = rx_riwt; + tc956xmac_rx_watchdog(priv, priv->ioaddr, + rx_riwt, queue); + priv->rx_coal_frames[queue] = + ec->rx_max_coalesced_frames; + } + } + + if ((ec->tx_coalesce_usecs == 0) && + (ec->tx_max_coalesced_frames == 0)) + return -EINVAL; + + if ((ec->tx_coalesce_usecs > TC956XMAC_MAX_COAL_TX_TICK) || + (ec->tx_max_coalesced_frames > TC956XMAC_TX_MAX_FRAMES)) + return -EINVAL; + + if (all_queues) { + int i; + + for (i = 0; i < tx_cnt; i++) { + priv->tx_coal_frames[i] = + ec->tx_max_coalesced_frames; + priv->tx_coal_timer[i] = + ec->tx_coalesce_usecs; + } + } else if (queue < tx_cnt) { + priv->tx_coal_frames[queue] = + ec->tx_max_coalesced_frames; + priv->tx_coal_timer[queue] = + ec->tx_coalesce_usecs; + } + + return 0; +} + +static int tc956xmac_set_coalesce(struct net_device *dev, + struct ethtool_coalesce *ec, + struct kernel_ethtool_coalesce *kernel_coal, + struct netlink_ext_ack *extack) +{ + return __tc956xmac_set_coalesce(dev, ec, -1); +} +#else static int tc956xmac_get_coalesce(struct net_device *dev, struct ethtool_coalesce *ec) { @@ -1669,6 +2054,7 @@ static int tc956xmac_set_coalesce(struct net_device *dev, u32 rx_cnt = priv->plat->rx_queues_to_use; unsigned int rx_riwt; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 7, 0)) /* Check not supported parameters */ if ((ec->rx_coalesce_usecs_irq) || (ec->rx_max_coalesced_frames_irq) || (ec->tx_coalesce_usecs_irq) || @@ -1682,6 +2068,7 @@ static int tc956xmac_set_coalesce(struct net_device *dev, (ec->stats_block_coalesce_usecs) || (ec->tx_max_coalesced_frames_high) || (ec->rate_sample_interval)) return -EOPNOTSUPP; +#endif if (priv->use_riwt && (ec->rx_coalesce_usecs > 0)) { rx_riwt = tc956xmac_usec2riwt(ec->rx_coalesce_usecs, priv); @@ -1714,7 +2101,7 @@ static int tc956xmac_set_coalesce(struct net_device *dev, priv->rx_coal_frames = ec->rx_max_coalesced_frames; return 0; } - +#endif #ifndef TC956X static int tc956xmac_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *rxnfc, u32 *rule_locs) @@ -1793,19 +2180,30 @@ static int tc956xmac_get_ts_info(struct net_device *dev, struct tc956xmac_priv *priv = netdev_priv(dev); if ((priv->dma_cap.time_stamp || priv->dma_cap.atime_stamp)) { - +#ifdef TC956X_SRIOV_PF info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | SOF_TIMESTAMPING_TX_HARDWARE | SOF_TIMESTAMPING_RX_SOFTWARE | SOF_TIMESTAMPING_RX_HARDWARE | SOF_TIMESTAMPING_SOFTWARE | SOF_TIMESTAMPING_RAW_HARDWARE; +#else + info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | + SOF_TIMESTAMPING_RX_SOFTWARE | + SOF_TIMESTAMPING_RX_HARDWARE | + SOF_TIMESTAMPING_SOFTWARE | + SOF_TIMESTAMPING_RAW_HARDWARE; +#endif if (priv->ptp_clock) info->phc_index = ptp_clock_index(priv->ptp_clock); - +#ifdef TC956X_SRIOV_PF info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON); +#else + info->tx_types = (1 << HWTSTAMP_TX_OFF); +#endif +#ifdef TC956X_SRIOV_PF info->rx_filters = ((1 << HWTSTAMP_FILTER_NONE) | (1 << HWTSTAMP_FILTER_PTP_V1_L4_EVENT) | (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) | @@ -1817,6 +2215,10 @@ static int tc956xmac_get_ts_info(struct net_device *dev, (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) | (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) | (1 << HWTSTAMP_FILTER_ALL)); +#else + info->rx_filters = (1 << HWTSTAMP_FILTER_ALL); +#endif + return 0; } else return ethtool_op_get_ts_info(dev, info); @@ -1890,6 +2292,10 @@ static u32 tc956x_get_priv_flag(struct net_device *dev) #endif static const struct ethtool_ops tc956xmac_ethtool_ops = { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) + .supported_coalesce_params = ETHTOOL_COALESCE_USECS | + ETHTOOL_COALESCE_MAX_FRAMES, +#endif .begin = tc956xmac_check_if_running, .get_drvinfo = tc956xmac_ethtool_getdrvinfo, .get_msglevel = tc956xmac_ethtool_getmsglevel, @@ -1897,16 +2303,20 @@ static const struct ethtool_ops tc956xmac_ethtool_ops = { .get_regs = tc956xmac_ethtool_gregs, .get_regs_len = tc956xmac_ethtool_get_regs_len, .get_link = ethtool_op_get_link, +#ifndef TC956X_SRIOV_VF #ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE .nway_reset = tc956xmac_nway_reset, #endif +#endif /* TC956X_SRIOV_VF */ .get_pauseparam = tc956xmac_get_pauseparam, .set_pauseparam = tc956xmac_set_pauseparam, .self_test = tc956xmac_selftest_run, .get_ethtool_stats = tc956xmac_get_ethtool_stats, .get_strings = tc956xmac_get_strings, +#ifndef TC956X_SRIOV_VF .get_wol = tc956xmac_get_wol, .set_wol = tc956xmac_set_wol, +#endif .get_eee = tc956xmac_ethtool_op_get_eee, .set_eee = tc956xmac_ethtool_op_set_eee, .get_sset_count = tc956xmac_get_sset_count, @@ -1924,8 +2334,10 @@ static const struct ethtool_ops tc956xmac_ethtool_ops = { .get_tunable = tc956xmac_get_tunable, .set_tunable = tc956xmac_set_tunable, #endif +#ifndef TC956X_SRIOV_VF .get_link_ksettings = tc956xmac_ethtool_get_link_ksettings, .set_link_ksettings = tc956xmac_ethtool_set_link_ksettings, +#endif /* TC956X_SRIOV_VF */ #ifdef TC956X .set_priv_flags = tc956x_set_priv_flag, .get_priv_flags = tc956x_get_priv_flag, diff --git a/tc956xmac_hwtstamp.c b/tc956xmac_hwtstamp.c index d9ee910317f5..834f4cb94a03 100644 --- a/tc956xmac_hwtstamp.c +++ b/tc956xmac_hwtstamp.c @@ -38,6 +38,7 @@ #include "common.h" #include "tc956xmac_ptp.h" +#ifdef TC956X_SRIOV_PF static u32 tc956xmac_get_ptp_subperiod(struct tc956xmac_priv *priv, void __iomem *ioaddr, u32 ptp_clock); static u32 tc956xmac_get_ptp_period(struct tc956xmac_priv *priv, void __iomem *ioaddr, u32 ptp_clock); @@ -153,7 +154,6 @@ static int config_addend(struct tc956xmac_priv *priv, void __iomem *ioaddr, u32 return 0; } -#ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE static int adjust_systime(struct tc956xmac_priv *priv, void __iomem *ioaddr, u32 sec, u32 nsec, int add_sub, int gmac4) { @@ -196,7 +196,7 @@ static int adjust_systime(struct tc956xmac_priv *priv, void __iomem *ioaddr, return 0; } - +#endif static void get_systime(struct tc956xmac_priv *priv, void __iomem *ioaddr, u64 *systime) { @@ -224,8 +224,7 @@ static void get_systime(struct tc956xmac_priv *priv, void __iomem *ioaddr, u64 * *systime = ns; } -#endif /* TC956X_UNSUPPORTED_UNTESTED_FEATURE */ - +#ifdef TC956X_SRIOV_PF static u32 tc956xmac_get_ptp_period(struct tc956xmac_priv *priv, void __iomem *ioaddr, u32 ptp_clock) { u32 value = readl(ioaddr + PTP_TCR); @@ -294,8 +293,17 @@ const struct tc956xmac_hwtimestamp tc956xmac_ptp = { .init_systime = init_systime, .config_sub_second_increment = config_sub_second_increment, .config_addend = config_addend, -#ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE .adjust_systime = adjust_systime, .get_systime = get_systime, -#endif /* TC956X_UNSUPPORTED_UNTESTED_FEATURE */ }; +#else +const struct tc956xmac_hwtimestamp tc956xmac_ptp = { + .config_hw_tstamping = NULL, + .init_systime = NULL, + .config_sub_second_increment = NULL, + .config_addend = NULL, + .adjust_systime = NULL, + .get_systime = get_systime, +}; +#endif + diff --git a/tc956xmac_inc.h b/tc956xmac_inc.h index 1783bc630d6d..fb454937553a 100644 --- a/tc956xmac_inc.h +++ b/tc956xmac_inc.h @@ -46,6 +46,8 @@ * VERSION : 01-00-30 * 11 Jan 2022 : 1. Forced speed mode parameter added for fixed phy mode. * VERSION : 01-00-35 + * 26 Dec 2023 : 1. Added the support for TC commands taprio and flower + * VERSION : 01-03-59 */ #ifndef __TC956XMAC_PLATFORM_DATA @@ -55,7 +57,7 @@ #include #include "tc956xmac_ioctl.h" -#define TC956X +//#define TC956X //#define TC956X_IOCTL_REG_RD_WR_ENABLE //#define TC956X_WITHOUT_MDIO //#define TC956X_PCIE_GEN3_SETTING @@ -66,20 +68,33 @@ /* Enable for PORT1 interrupt mode, if commented polling mode */ #define TC956X_PHY_INTERRUPT_MODE_EMAC1 +#ifdef TC956X +//#define TC956X_SRIOV_PF /* Enable TC956X SRIOV Configuration */ +//#define TC956X_MBX_DESIGN_HW_SEMAPHORE +#endif /* Enable this macro to use Systick timer instead of Kernel timers * for handling Tx completion periodically */ -#define TX_COMPLETION_WITHOUT_TIMERS -#define TC956X_SW_MSI /*Enable this macro to process SW MSI when CM3 Systick Handler sends SW MSI*/ -//#define ENABLE_TX_TIMER /*Enable this macro to use Kernel timer. TC956X_SW_MSI can be disabled in this case */ +#ifdef TC956X_AUTOMOTIVE_CONFIG +//#define TX_COMPLETION_WITHOUT_TIMERS +//#define TC956X_SW_MSI /*Enable this macro to process SW MSI when CM3 Systick Handler sends SW MSI*/ +#define ENABLE_TX_TIMER /*Enable this macro to use Kernel timer. TC956X_SW_MSI can be disabled in this case */ +#else +//#define TX_COMPLETION_WITHOUT_TIMERS +//#define TC956X_SW_MSI /*Enable this macro to process SW MSI when CM3 Systick Handler sends SW MSI*/ +#define ENABLE_TX_TIMER /*Enable this macro to use Kernel timer. TC956X_SW_MSI can be disabled in this case */ +#endif -/* By default macro is defined and code coverage this macro to be disabled */ +/* By default macro is defined and for code coverage this macro has to be disabled */ #define TC956X_UNSUPPORTED_UNTESTED_FEATURE //#define EEPROM_MAC_ADDR +//#define TC956X_MBX_DESIGN_HW_SEMAPHORE +//#define TC956X_SRIOV_VF /* This macro mentions applicable changes for VF driver from CPE driver. It should be enabled along with TC956X macro */ #define MTL_MAX_RX_QUEUES 8 #define MTL_MAX_TX_QUEUES 8 +#define MTL_MAX_TX_TC 5 #define TC956XMAC_CH_MAX 8 #define TC956XMAC_RX_COE_NONE 0 @@ -113,6 +128,11 @@ #define MTL_QUEUE_DCB 0x1 #define MTL_QUEUE_DISABLE 0x2 +#ifdef TC956X_SRIOV_VF +#define TC956X_ENABLE 1 +#define TC956X_DISABLE 0 +#endif + /* The MDC clock could be set higher than the IEEE 802.3 * specified frequency limit 0f 2.5 MHz, by programming a clock divider * of value different than the above defined values. The resultant MDIO @@ -192,16 +212,18 @@ struct tc956xmac_axi { bool axi_rb; }; -#define EST_GCL 1024 +#define EST_GCL 128 struct tc956xmac_est { int enable; u32 btr_offset[2]; u32 btr[2]; u32 ctr[2]; u32 ter; - u32 gcl_unaligned[EST_GCL]; u32 gcl[EST_GCL]; u32 gcl_size; +#ifndef TC956X + u32 gcl_unaligned[EST_GCL]; +#endif }; struct tc956xmac_rxq_cfg { @@ -249,12 +271,14 @@ struct plat_tc956xmacenet_data { int bus_id; int phy_addr; int interface; - tc956xmac_rx_parser_cfg rxp_cfg; + struct tc956xmac_rx_parser_cfg rxp_cfg; struct pci_dev *pdev; phy_interface_t phy_interface; struct tc956xmac_mdio_bus_data *mdio_bus_data; struct device_node *phy_node; +#ifndef TC956X_SRIOV_VF struct device_node *phylink_node; +#endif struct device_node *mdio_node; struct tc956xmac_dma_cfg *dma_cfg; struct tc956xmac_est *est; @@ -279,6 +303,28 @@ struct plat_tc956xmacenet_data { int rx_fifo_size; u32 rx_queues_to_use; u32 tx_queues_to_use; + /* Variable for queues and channels used in current driver instance */ +#ifdef TC956X_SRIOV_PF + u32 tx_ch_in_use[TC956XMAC_CH_MAX]; + u32 rx_ch_in_use[TC956XMAC_CH_MAX]; + u32 tx_q_in_use[MTL_MAX_TX_QUEUES]; + u32 rx_q_in_use[MTL_MAX_RX_QUEUES]; +#elif defined TC956X_SRIOV_VF + u32 vf_id; /*0 or 1 or 2*/ + u32 rx_queues_to_use_actual; + u32 tx_queues_to_use_actual; + u32 ch_in_use[TC956XMAC_CH_MAX]; + u32 tx_q_in_use[MTL_MAX_TX_QUEUES]; + u32 rx_q_in_use[MTL_MAX_TX_QUEUES]; + u32 tx_q_size[MTL_MAX_TX_QUEUES]; + u32 best_effort_ch_no; + u32 gptp_ch_no; + u32 avb_class_a_ch_no; + u32 avb_class_b_ch_no; + u32 tsn_ch_no; + u32 tsn_application; + u32 avb_application; +#endif u8 rx_sched_algorithm; u8 tx_sched_algorithm; struct tc956xmac_rxq_cfg rx_queues_cfg[MTL_MAX_RX_QUEUES]; @@ -307,11 +353,407 @@ struct plat_tc956xmacenet_data { int has_xgmac; int (*cphy_read)(void *priv, int phyaddr, int phyreg); int (*cphy_write)(void *priv, int phyaddr, int phyreg, u16 phydata); +#ifndef TC956X_SRIOV_VF enum ch_owner tx_dma_ch_owner[MTL_MAX_TX_QUEUES]; enum ch_owner rx_dma_ch_owner[MTL_MAX_RX_QUEUES]; +#endif u32 port_num; u32 port_interface; /* Kernel module parameter variable for interface */ bool phy_interrupt_mode; /* For Handling of PHY Operating mode */ int forced_speed; /* applicable only in case of fixed phy mode */ + /*Preamble*/ + bool pse; + int start_phy_addr; + bool gate_mask; +}; +#ifdef TC956X_SRIOV_VF +static const struct tc956xmac_vf_entry { + u32 rx_queues_to_use_actual; + u32 tx_queues_to_use_actual; + /* No of and name of Rx and Tx channel will be always same */ + u32 ch_in_use[TC956XMAC_CH_MAX]; + u32 tx_q_in_use[MTL_MAX_TX_QUEUES]; + u32 rx_q_in_use[MTL_MAX_TX_QUEUES]; + u32 tx_q_size[MTL_MAX_TX_QUEUES]; + u32 best_effort_ch_no; + u32 gptp_ch_no; + u32 avb_class_a_ch_no; + u32 avb_class_b_ch_no; + u32 tsn_ch_no; + u32 tsn_application; /* Set if VF supports TSN application */ + u32 avb_application; /* Set if VF supports AVB app */ + struct tc956xmac_txq_cfg tx_queues_cfg[MTL_MAX_TX_QUEUES]; +} tc956xmac_vf[] = { + /* VF[0] configurations */ + { + .rx_queues_to_use_actual = 8, + .tx_queues_to_use_actual = 8, + .ch_in_use = {1, 0, 0, 0, 0, 1, 0, 0}, + .tx_q_in_use = {1, 0, 0, 0, 0, 1, 0, 0}, + .rx_q_in_use = {0, 0, 0, 0, 0, 0, 0, 0}, + .tx_q_size = {4096, 0, 0, 0, 0, 4096, 0, 0}, + .best_effort_ch_no = 0, + .gptp_ch_no = 0, + .avb_class_a_ch_no = 0, /* Not used - redirect to BE Ch */ + .avb_class_b_ch_no = 5, + .tsn_ch_no = 0, /* Not used - redirect to BE Ch */ + .tsn_application = 0, + .avb_application = 1, + .tx_queues_cfg = { + { /*Tx queue 0 configuration */ + .weight = 0x1, + .mode_to_use = MTL_QUEUE_DCB, + .send_slope = 0x0, + .idle_slope = 0x0, + .high_credit = 0x0, + .low_credit = 0x0, + .use_prio = false, + .prio = 0x0, + .tbs_en = 0x0, + .tso_en = TC956X_ENABLE, + .traffic_class = 0 + }, + { /*Tx queue 1 configuration */ + .weight = 0x1, + .mode_to_use = MTL_QUEUE_DISABLE, + .send_slope = 0x0, + .idle_slope = 0x0, + .high_credit = 0x0, + .low_credit = 0x0, + .use_prio = false, + .prio = 0x0, + .tbs_en = 0x0, + .tso_en = 0x0, + .traffic_class = 0 + }, + { /*Tx queue 2 configuration */ + .weight = 0x1, + .mode_to_use = MTL_QUEUE_DISABLE, + .send_slope = 0x0, + .idle_slope = 0x0, + .high_credit = 0x0, + .low_credit = 0x0, + .use_prio = false, + .prio = 0x0, + .tbs_en = 0x0, + .tso_en = 0x0, + .traffic_class = 0 + }, + { /*Tx queue 3 configuration */ + .weight = 0x1, + .mode_to_use = MTL_QUEUE_DISABLE, + .send_slope = 0x0, + .idle_slope = 0x0, + .high_credit = 0x0, + .low_credit = 0x0, + .use_prio = false, + .prio = 0x0, + .tbs_en = 0x0, + .tso_en = 0x0, + .traffic_class = 0 + }, + { /*Tx queue 4 configuration */ + .weight = 0x1, + .mode_to_use = MTL_QUEUE_DISABLE, + .send_slope = 0x0, + .idle_slope = 0x0, + .high_credit = 0x0, + .low_credit = 0x0, + .use_prio = false, + .prio = 0x0, + .tbs_en = 0x0, + .tso_en = 0x0, + .traffic_class = 0 + }, + { /*Tx queue 5 configuration */ + /* CBS: queue 5 -> Class B traffic (25% BW) */ + .weight = 0x1, + .mode_to_use = MTL_QUEUE_AVB, + .send_slope = 0x1800, + .idle_slope = 0x800, + .high_credit = 0x320000, + .low_credit = 0xff6a0000, + .use_prio = false, + .prio = 0x0, + .tbs_en = TC956X_ENABLE, + .tso_en = 0x0, + .traffic_class = 2 + }, + { /*Tx queue 6 configuration */ + .weight = 0x1, + .mode_to_use = MTL_QUEUE_DISABLE, + .send_slope = 0x0, + .idle_slope = 0x0, + .high_credit = 0x0, + .low_credit = 0x0, + .use_prio = false, + .prio = 0x0, + .tbs_en = 0x0, + .tso_en = 0x0, + .traffic_class = 0 + }, + { /*Tx queue 7 configuration */ + .weight = 0x1, + .mode_to_use = MTL_QUEUE_DISABLE, + .send_slope = 0x0, + .idle_slope = 0x0, + .high_credit = 0x0, + .low_credit = 0x0, + .use_prio = false, + .prio = 0x0, + .tbs_en = 0x0, + .tso_en = 0x0, + .traffic_class = 0 + }, + }, + }, + /* VF[1] configurations */ + { + .rx_queues_to_use_actual = 8, + .tx_queues_to_use_actual = 8, + .ch_in_use = {0, 1, 0, 0, 0, 0, 0, 0}, + .tx_q_in_use = {0, 1, 0, 0, 0, 0, 0, 0}, + .rx_q_in_use = {0, 0, 0, 0, 0, 0, 0, 0}, + .tx_q_size = {0, 4096, 0, 0, 0, 0, 0, 0}, + .best_effort_ch_no = 1, + .gptp_ch_no = 1, + .avb_class_a_ch_no = 1, /* Not used - redirect to BE Ch */ + .avb_class_b_ch_no = 1, /* Not used - redirect to BE Ch */ + .tsn_ch_no = 1, /* Not used - redirect to BE Ch */ + .tsn_application = 0, + .avb_application = 0, + .tx_queues_cfg = { + { /*Tx queue 0 configuration */ + .weight = 0x1, + .mode_to_use = MTL_QUEUE_DISABLE, + .send_slope = 0x0, + .idle_slope = 0x0, + .high_credit = 0x0, + .low_credit = 0x0, + .use_prio = false, + .prio = 0x0, + .tbs_en = 0x0, + .tso_en = 0x0, + .traffic_class = 0 + }, + { /*Tx queue 1 configuration */ + .weight = 0x1, + .mode_to_use = MTL_QUEUE_DCB, + .send_slope = 0x0, + .idle_slope = 0x0, + .high_credit = 0x0, + .low_credit = 0x0, + .use_prio = false, + .prio = 0x0, + .tbs_en = 0x0, + .tso_en = TC956X_ENABLE, + .traffic_class = 0 + }, + { /*Tx queue 2 configuration */ + .weight = 0x1, + .mode_to_use = MTL_QUEUE_DISABLE, + .send_slope = 0x0, + .idle_slope = 0x0, + .high_credit = 0x0, + .low_credit = 0x0, + .use_prio = false, + .prio = 0x0, + .tbs_en = 0x0, + .tso_en = 0x0, + .traffic_class = 0 + }, + { /*Tx queue 3 configuration */ + .weight = 0x1, + .mode_to_use = MTL_QUEUE_DISABLE, + .send_slope = 0x0, + .idle_slope = 0x0, + .high_credit = 0x0, + .low_credit = 0x0, + .use_prio = false, + .prio = 0x0, + .tbs_en = 0x0, + .tso_en = 0x0, + .traffic_class = 0 + }, + { /*Tx queue 4 configuration */ + .weight = 0x1, + .mode_to_use = MTL_QUEUE_DISABLE, + .send_slope = 0x0, + .idle_slope = 0x0, + .high_credit = 0x0, + .low_credit = 0x0, + .use_prio = false, + .prio = 0x0, + .tbs_en = 0x0, + .tso_en = 0x0, + .traffic_class = 0 + }, + { /*Tx queue 5 configuration */ + .weight = 0x1, + .mode_to_use = MTL_QUEUE_DISABLE, + .send_slope = 0x0, + .idle_slope = 0x0, + .high_credit = 0x0, + .low_credit = 0x0, + .use_prio = false, + .prio = 0x0, + .tbs_en = 0x0, + .tso_en = 0x0, + .traffic_class = 0 + }, + { /*Tx queue 6 configuration */ + .weight = 0x1, + .mode_to_use = MTL_QUEUE_DISABLE, + .send_slope = 0x0, + .idle_slope = 0x0, + .high_credit = 0x0, + .low_credit = 0x0, + .use_prio = false, + .prio = 0x0, + .tbs_en = 0x0, + .tso_en = 0x0, + .traffic_class = 0 + }, + { /*Tx queue 7 configuration */ + .weight = 0x1, + .mode_to_use = MTL_QUEUE_DISABLE, + .send_slope = 0x0, + .idle_slope = 0x0, + .high_credit = 0x0, + .low_credit = 0x0, + .use_prio = false, + .prio = 0x0, + .tbs_en = 0x0, + .tso_en = 0x0, + .traffic_class = 0 + }, + }, + }, + /* VF[2] configurations */ + { + .rx_queues_to_use_actual = 8, + .tx_queues_to_use_actual = 8, + .ch_in_use = {0, 0, 1, 0, 0, 0, 1, 1}, + .tx_q_in_use = {0, 0, 1, 0, 0, 0, 1, 1}, + .rx_q_in_use = {0, 0, 0, 0, 0, 0, 0, 0}, + .tx_q_size = {0, 0, 18432, 0, 0, 0, 4096, 4096}, + .best_effort_ch_no = 2, + .gptp_ch_no = 2, + .avb_class_a_ch_no = 6, + .avb_class_b_ch_no = 2, /* Not used - redirect to BE Ch */ + .tsn_ch_no = 7, + .tsn_application = 1, + .avb_application = 1, + .tx_queues_cfg = { + { /*Tx queue 0 configuration */ + .weight = 0x1, + .mode_to_use = MTL_QUEUE_DISABLE, + .send_slope = 0x0, + .idle_slope = 0x0, + .high_credit = 0x0, + .low_credit = 0x0, + .use_prio = false, + .prio = 0x0, + .tbs_en = 0x0, + .tso_en = 0x0, + .traffic_class = 0 + }, + { /*Tx queue 1 configuration */ + .weight = 0x1, + .mode_to_use = MTL_QUEUE_DISABLE, + .send_slope = 0x0, + .idle_slope = 0x0, + .high_credit = 0x0, + .low_credit = 0x0, + .use_prio = false, + .prio = 0x0, + .tbs_en = 0x0, + .tso_en = 0x0, + .traffic_class = 0 + }, + { /*Tx queue 2 configuration */ + .weight = 0x1, + .mode_to_use = MTL_QUEUE_DCB, + .send_slope = 0x0, + .idle_slope = 0x0, + .high_credit = 0x0, + .low_credit = 0x0, + .use_prio = false, + .prio = 0x0, + .tbs_en = 0x0, + .tso_en = TC956X_ENABLE, + .traffic_class = 0 + }, + { /*Tx queue 3 configuration */ + .weight = 0x1, + .mode_to_use = MTL_QUEUE_DISABLE, + .send_slope = 0x0, + .idle_slope = 0x0, + .high_credit = 0x0, + .low_credit = 0x0, + .use_prio = false, + .prio = 0x0, + .tbs_en = 0x0, + .tso_en = 0x0, + .traffic_class = 0 + }, + { /*Tx queue 4 configuration */ + .weight = 0x1, + .mode_to_use = MTL_QUEUE_DISABLE, + .send_slope = 0x0, + .idle_slope = 0x0, + .high_credit = 0x0, + .low_credit = 0x0, + .use_prio = false, + .prio = 0x0, + .tbs_en = 0x0, + .tso_en = 0x0, + .traffic_class = 0 + }, + { /*Tx queue 5 configuration */ + .weight = 0x1, + .mode_to_use = MTL_QUEUE_DISABLE, + .send_slope = 0x0, + .idle_slope = 0x0, + .high_credit = 0x0, + .low_credit = 0x0, + .use_prio = false, + .prio = 0x0, + .tbs_en = 0x0, + .tso_en = 0x0, + .traffic_class = 0 + }, + { /*Tx queue 6 configuration */ + /* CBS: queue 6 -> Class A traffic (25% BW) */ + .weight = 0x1, + .mode_to_use = MTL_QUEUE_AVB, + .send_slope = 0x1800, + .idle_slope = 0x800, + .high_credit = 0x320000, + .low_credit = 0xff6a0000, + .use_prio = false, + .prio = 0x0, + .tbs_en = TC956X_ENABLE, + .tso_en = 0x0, + .traffic_class = 3 + }, + { /*Tx queue 7 configuration */ + /* CBS: queue 7 -> Class CDT traffic (40%) BW */ + .weight = 0x1, + .mode_to_use = MTL_QUEUE_AVB, + .send_slope = 0x1333, + .idle_slope = 0xccc, + .high_credit = 0x500000, + .low_credit = 0xff880000, + .use_prio = false, + .prio = 0x0, + .tbs_en = TC956X_ENABLE, + .tso_en = 0x0, + .traffic_class = 4 + }, + }, + }, + }; #endif +#endif diff --git a/tc956xmac_ioctl.h b/tc956xmac_ioctl.h index 55e190b353c8..a1e9bd54cb46 100644 --- a/tc956xmac_ioctl.h +++ b/tc956xmac_ioctl.h @@ -42,19 +42,25 @@ #ifndef _IOCTL_H__ #define _IOCTL_H__ -/* Note: Multiple macro definitions for TC956X_PCIE_LOGSTAT. +/* Note: Multiple macro definitions for TC956X_PCIE_LOGSTAT and TC956X_PCIE_LOGSTAT_SUMMARY_ENABLE. * Please also define/undefine same macro in common.h, if changing in this file */ /* #undef TC956X_PCIE_LOGSTAT */ #define TC956X_PCIE_LOGSTAT +#ifdef TC956X_PCIE_LOGSTAT +/* Enable/Disable Logstat Summary Print during probe and resume. */ +#undef TC956X_PCIE_LOGSTAT_SUMMARY_ENABLE +#endif enum ioctl_commands { TC956XMAC_GET_CBS = 0x1, TC956XMAC_SET_CBS = 0x2, TC956XMAC_GET_EST = 0x3, TC956XMAC_SET_EST = 0x4, +#ifdef TC956X_UNSUPPORTED_UNTESTED TC956XMAC_GET_FPE = 0x5, TC956XMAC_SET_FPE = 0x6, +#endif TC956XMAC_GET_RXP = 0x7, TC956XMAC_SET_RXP = 0x8, TC956XMAC_GET_SPEED = 0x9, @@ -78,20 +84,145 @@ enum ioctl_commands { TC956XMAC_ENABLE_AUX_TIMESTAMP = 0x1b, TC956XMAC_ENABLE_ONESTEP_TIMESTAMP = 0x1c, #ifdef TC956X_PCIE_LOGSTAT - TC956X_PCIE_SET_LOGSTAT_CONF = 0x1d, /* LOGSTAT : Sets and Prints LTSSM and AER Configuration */ - TC956X_PCIE_GET_LOGSTAT_CONF = 0x1e, /* LOGSTAT : Read, Print and return LTSSM and AER Configuration */ - TC956X_PCIE_GET_LTSSM_LOG = 0x1f, /* LOGSTAT : Read, Print and return LTSSM Looging Data */ + TC956X_PCIE_STATE_LOG_SUMMARY = 0x1d, /* LOGSTAT : Prints State Log Summary */ + TC956X_PCIE_GET_PCIE_LINK_PARAMS = 0x1e, /* LOGSTAT : Return and Print PCIe LTSSM, DLL, Speed and Lane Width */ + TC956X_PCIE_STATE_LOG_ENABLE = 0x1f, /* LOGSTAT : Set State Log Enable/Disable */ #endif /* #ifdef TC956X_PCIE_LOGSTAT */ -#ifndef TC956X + TC956XMAC_VLAN_STRIP_CONFIG = 0x22, -#endif TC956XMAC_PCIE_LANE_CHANGE = 0x23, TC956XMAC_PCIE_SET_TX_MARGIN = 0x24, TC956XMAC_PCIE_SET_TX_DEEMPHASIS = 0x25, /*Enable or disable Tx de-emphasis*/ TC956XMAC_PCIE_SET_DFE = 0x26, TC956XMAC_PCIE_SET_CTLE = 0x27, TC956XMAC_PCIE_SPEED_CHANGE = 0x28, +#ifdef TC956X_SRIOV_PF + TC956XMAC_GET_QMODE = 0x29, + TC956XMAC_SET_QMODE = 0x2a, + TC956XMAC_GET_CBS100 = 0x2b, + TC956XMAC_GET_CBS1000 = 0x2c, + TC956XMAC_GET_CBS2500 = 0x2d, + TC956XMAC_GET_CBS5000 = 0x2e, + TC956XMAC_GET_CBS10000 = 0x2f, + TC956XMAC_SET_CBS100 = 0x30, + TC956XMAC_SET_CBS1000 = 0x31, + TC956XMAC_SET_CBS2500 = 0x32, + TC956XMAC_SET_CBS5000 = 0x33, + TC956XMAC_SET_CBS10000 = 0x34, +#endif }; + +#define TC956XMAC_GET_CBS_1 0x29 /* Sub commands - CBS */ +#define TC956XMAC_GET_CBS_2 0x2a +#define TC956XMAC_SET_CBS_1 0x2b +#define TC956XMAC_SET_CBS_2 0x2c +#define TC956XMAC_SET_EST_1 0x2d +#define TC956XMAC_SET_EST_2 0x2e +#define TC956XMAC_SET_EST_3 0x2f +#define TC956XMAC_SET_EST_4 0x30 +#define TC956XMAC_SET_EST_5 0x31 +#define TC956XMAC_SET_EST_6 0x32 +#define TC956XMAC_SET_EST_7 0x33 +#define TC956XMAC_SET_EST_8 0x34 +#define TC956XMAC_SET_EST_9 0x35 +#define TC956XMAC_SET_EST_10 0x36 +#define TC956XMAC_SET_FPE_1 0x37 +#define TC956XMAC_GET_FPE_1 0x38 +#define TC956XMAC_GET_EST_1 0x39 +#define TC956XMAC_GET_EST_2 0x3a +#define TC956XMAC_GET_EST_3 0x3b +#define TC956XMAC_GET_EST_4 0x3c +#define TC956XMAC_GET_EST_5 0x3d +#define TC956XMAC_GET_EST_6 0x3e +#define TC956XMAC_GET_EST_7 0x3f +#define TC956XMAC_GET_EST_8 0x40 +#define TC956XMAC_GET_EST_9 0x41 +#define TC956XMAC_GET_EST_10 0x42 +#define TC956XMAC_SET_RXP_1 0x43 +#define TC956XMAC_SET_RXP_2 0x44 +#define TC956XMAC_SET_RXP_3 0x45 +#define TC956XMAC_SET_RXP_4 0x46 +#define TC956XMAC_SET_RXP_5 0x47 +#define TC956XMAC_SET_RXP_6 0x48 +#define TC956XMAC_SET_RXP_7 0x49 +#define TC956XMAC_SET_RXP_8 0x4a +#define TC956XMAC_SET_RXP_9 0x4b +#define TC956XMAC_SET_RXP_10 0x4c +#define TC956XMAC_SET_RXP_11 0x4d +#define TC956XMAC_SET_RXP_12 0x4e +#define TC956XMAC_SET_RXP_13 0x4f +#define TC956XMAC_SET_RXP_14 0x50 +#define TC956XMAC_SET_RXP_15 0x51 +#define TC956XMAC_SET_RXP_16 0x52 +#define TC956XMAC_SET_RXP_17 0x53 +#define TC956XMAC_SET_RXP_18 0x54 +#define TC956XMAC_SET_RXP_19 0x55 +#define TC956XMAC_SET_RXP_20 0x56 +#define TC956XMAC_SET_RXP_21 0x57 +#define TC956XMAC_SET_RXP_22 0x58 +#define TC956XMAC_SET_RXP_23 0x59 +#define TC956XMAC_SET_RXP_24 0x5a +#define TC956XMAC_SET_RXP_25 0x5b +#define TC956XMAC_SET_RXP_26 0x5c +#define TC956XMAC_SET_RXP_27 0x5d +#define TC956XMAC_SET_RXP_28 0x5e +#define TC956XMAC_SET_RXP_29 0x5f +#define TC956XMAC_SET_RXP_30 0x60 +#define TC956XMAC_SET_RXP_31 0x61 +#define TC956XMAC_SET_RXP_32 0x62 +#define TC956XMAC_SET_RXP_33 0x63 +#define TC956XMAC_SET_RXP_34 0x64 +#define TC956XMAC_SET_RXP_35 0x65 +#define TC956XMAC_SET_RXP_36 0x66 +#define TC956XMAC_SET_RXP_37 0x67 +#define TC956XMAC_GET_RXP_1 0x68 +#define TC956XMAC_GET_RXP_2 0x69 +#define TC956XMAC_GET_RXP_3 0x6a +#define TC956XMAC_GET_RXP_4 0x6b +#define TC956XMAC_GET_RXP_5 0x6c +#define TC956XMAC_GET_RXP_6 0x6d +#define TC956XMAC_GET_RXP_7 0x6e +#define TC956XMAC_GET_RXP_8 0x6f +#define TC956XMAC_GET_RXP_9 0x70 +#define TC956XMAC_GET_RXP_10 0x71 +#define TC956XMAC_GET_RXP_11 0x72 +#define TC956XMAC_GET_RXP_12 0x73 +#define TC956XMAC_GET_RXP_13 0x74 +#define TC956XMAC_GET_RXP_14 0x75 +#define TC956XMAC_GET_RXP_15 0x76 +#define TC956XMAC_GET_RXP_16 0x77 +#define TC956XMAC_GET_RXP_17 0x78 +#define TC956XMAC_GET_RXP_18 0x79 +#define TC956XMAC_GET_RXP_19 0x7a +#define TC956XMAC_GET_RXP_20 0x7b +#define TC956XMAC_GET_RXP_21 0x7c +#define TC956XMAC_GET_RXP_22 0x7d +#define TC956XMAC_GET_RXP_23 0x7e +#define TC956XMAC_GET_RXP_24 0x7f +#define TC956XMAC_GET_RXP_25 0x80 +#define TC956XMAC_GET_RXP_26 0x81 +#define TC956XMAC_GET_RXP_27 0x82 +#define TC956XMAC_GET_RXP_28 0x83 +#define TC956XMAC_GET_RXP_29 0x84 +#define TC956XMAC_GET_RXP_30 0x85 +#define TC956XMAC_GET_RXP_31 0x86 +#define TC956XMAC_GET_RXP_32 0x87 +#define TC956XMAC_GET_RXP_33 0x88 +#define TC956XMAC_GET_RXP_34 0x89 +#define TC956XMAC_GET_RXP_35 0x8a +#define TC956XMAC_GET_RXP_36 0x8b +#define TC956XMAC_GET_RXP_37 0x8c +#define OPCODE_MBX_VF_GET_HW_STMP 0x8d +#define OPCODE_MBX_VF_GET_MII_REG_1 0x8e +#define OPCODE_MBX_VF_GET_MII_REG_2 0x8f + +enum ethtool_command { + TC956XMAC_GET_PAUSE_PARAM = 0x19, + TC956XMAC_GET_EEE = 0x20, + TC956XMAC_GET_COALESCE = 0x21, + TC956XMAC_GET_TS_INFO = 0x22, +}; + #define SIOCSTIOCTL SIOCDEVPRIVATE #define TC956XMAC_IOCTL_QMODE_DCB 0x0 @@ -123,7 +254,57 @@ enum ioctl_commands { /* Replace the SA with the value given in MAC Addr 1 Reg */ #define TC956XMAC_SA1_REG_REPLACE ((TC956XMAC1_REG << 2) | 3) +/* for PTP offloading configuration */ +#define TC956X_PTP_OFFLOADING_DISABLE 0 +#define TC956X_PTP_OFFLOADING_ENABLE 1 +#define TC956X_PTP_ORDINARY_SLAVE 1 +#define TC956X_PTP_ORDINARY_MASTER 2 +#define TC956X_PTP_TRASPARENT_SLAVE 3 +#define TC956X_PTP_TRASPARENT_MASTER 4 +#define TC956X_PTP_PEER_TO_PEER_TRANSPARENT 5 + +#define TC956X_AUX_SNAPSHOT_0 1 + +struct tc956x_ioctl_aux_snapshot { + __u32 cmd; + __u32 aux_snapshot_ctrl; +}; +#ifdef TC956X_SRIOV_PF +struct tc956x_config_ptpoffloading { + __u32 cmd; + bool en_dis; /* Enable/Disable */ + int mode; /* PTP Ordinary/Transparent Slave, Ordinary/Transparent Master, Peer to Peer Transparent */ + int domain_num; /* Domain Number between 0 and 0xFF */ + bool mc_uc; /* Enable/Disable */ + unsigned char mc_uc_addr[ETH_ALEN]; /* Mac Address */ +}; + +struct tc956x_config_ost { + __u32 cmd; + bool en_dis; /* Enable/Disable OST */ +}; + +struct tc956xmac_ioctl_qmode_cfg { + __u32 cmd; + __u32 queue_idx; + __u32 queue_mode; +}; +#elif defined TC956X_SRIOV_VF +struct tc956x_config_ptpoffloading { + __u32 cmd; + int en_dis; + int mode; + int domain_num; + int mc_uc; + unsigned char mc_uc_addr[ETH_ALEN]; +}; + +struct tc956x_config_ost { + __u32 cmd; + int en_dis; +}; +#endif struct tc956xmac_ioctl_cbs_params { __u32 send_slope; /* Send Slope value supported 15 bits */ __u32 idle_slope; /* Idle Slope value supported 20 bits */ @@ -177,12 +358,12 @@ struct tc956xmac_ioctl_free_desc { struct tc956xmac_PPS_Config { __u32 cmd; - unsigned int ptpclk_freq; - unsigned int ppsout_freq; - unsigned int ppsout_duty; - unsigned int ppsout_align_ns; /* first output align to ppsout_align_ns in ns */ - unsigned short ppsout_ch; - bool ppsout_align; /* first output align */ + unsigned int ptpclk_freq; /* Maximum 250MHz */ + unsigned int ppsout_freq; /* PPS Output Frequency */ + unsigned int ppsout_duty; /* Duty Cycle between 0 and 100 */ + unsigned int ppsout_align_ns; /* first output align to ppsout_align_ns in ns. */ + unsigned short ppsout_ch; /* Ch0 and Ch1 */ + bool ppsout_align; /* first output align */ }; struct tc956xmac_ioctl_reg_rd_wr { @@ -238,12 +419,12 @@ struct tc956xmac_ioctl_rxp_entry { #define TC956XMAC_RX_PARSER_MAX_ENTRIES 128 -typedef struct tc956xmac_rx_parser_cfg { +struct tc956xmac_rx_parser_cfg { bool enable; __u32 nve; __u32 npe; struct tc956xmac_rx_parser_entry entries[TC956XMAC_RX_PARSER_MAX_ENTRIES]; -} tc956xmac_rx_parser_cfg; +}; struct tc956xmac_ioctl_rxp_cfg { __u32 cmd; @@ -254,13 +435,13 @@ struct tc956xmac_ioctl_rxp_cfg { struct tc956xmac_ioctl_rxp_entry entries[TC956XMAC_RX_PARSER_MAX_ENTRIES]; }; -#define TC956XMAC_IOCTL_EST_GCL_MAX_ENTRIES 1024 +#define TC956XMAC_IOCTL_EST_GCL_MAX_ENTRIES 128 struct tc956xmac_ioctl_est_cfg { __u32 cmd; __u32 enabled; - __u32 estwid; - __u32 estdep; + __u32 estwid; /* parameter used to get the value and not used in set */ + __u32 estdep; /* parameter used to get the value and not used in set */ __u32 btr_offset[2]; __u32 ctr[2]; __u32 ter; @@ -309,12 +490,11 @@ struct tc956x_ioctl_fwstatus { __u32 fw_status; }; -#ifndef TC956X struct tc956xmac_ioctl_vlan_strip_cfg { __u32 cmd; __u32 enabled; /* 1 to enable stripping, 0 to disable stripping */ }; -#endif + enum lane_width { LANE_1 = 1, LANE_2 = 2, @@ -327,7 +507,6 @@ enum pcie_speed { GEN_3 = 3, /*8 GT/s*/ }; -#ifdef TC956X_PCIE_LOGSTAT /** * enum port - Enumeration for ports available */ @@ -338,100 +517,32 @@ enum ports { INTERNAL_ENDPOINT = 3U, }; +#ifdef TC956X_PCIE_LOGSTAT /** - * enum tx_debug_monitor - Enumeration for Tx Debug Monitor + * enum state_log_enable - Enumeration for State Log Enable */ -enum tx_debug_monitor { - TX_DEBUG_MONITOR0 = 0U, - TX_DEBUG_MONITOR1 = 1U, - TX_DEBUG_MONITOR2 = 2U, - TX_DEBUG_MONITOR3 = 3U, - TX_DEBUG_MONITOR4 = 4U, - TX_DEBUG_MONITOR5 = 5U, - TX_DEBUG_MONITOR6 = 6U, - TX_DEBUG_MONITOR7 = 7U, - TX_DEBUG_MONITOR8 = 8U, - TX_DEBUG_MONITOR9 = 9U, - TX_DEBUG_MONITOR10 = 10U, +enum state_log_enable { + STATE_LOG_DISABLE = 0U, + STATE_LOG_ENABLE = 1U, }; /** - * enum rx_debug_monitor - Enumeration for Rx Debug Monitor - */ -enum rx_debug_monitor { - RX_DEBUG_MONITOR0 = 0U, - RX_DEBUG_MONITOR1 = 1U, -}; - -/** - * struct tc956x_ltssm_conf - Configuration Parameters + * struct tc956x_pcie_link_params - PCIe Link Parameters * - * State Logging Configuration Parameters. + * PCIe Link Parameters + * ltssm : Link Training and Status State Machine(LTSSM) Value(0 to 0x1F). + * dll : Data Link Layer Active/Inactive State Value(0, 1). + * speed : Link Speed (Gen1 : 2.5GT/s, Gen2 : 5 GT/s, Gen3 : 8GT/s). + * width : Number of Active Lanes(0, 1, 2, 3, 4). */ -struct tc956x_ltssm_conf { - __u8 logging_stop_cnt_val; - __u8 logging_stop_linkwdth_en; - __u8 logging_stop_linkspeed_en; - __u8 logging_stop_timeout_en; - __u8 logging_accept_txrxL0s_en; - __u8 logging_post_stop_enable; - __u8 ltssm_fifo_pointer; +struct tc956x_pcie_link_params { + __u8 ltssm; /* Current Link Training and Status State Machine(LTSSM) Value */ + __u8 dll; /* Current Data Link Layer State */ + __u8 speed; /* Current Link Speed */ + __u8 width; /* Current Link Width */ }; - -/** - * struct tc956x_ltssm_log - Logging Parameters - * - * State Logging Data parameters. - */ -struct tc956x_ltssm_log { - __u8 ltssm_state; - __u8 eq_phase; - __u8 rxL0s; - __u8 txL0s; - __u8 substate_L1; - __u8 active_lane; - __u8 link_speed; - __u8 dl_active; - __u8 ltssm_timeout; - __u8 ltssm_stop_status; -}; - -/** - * struct tc956x_tx_dbg_mon - Tx Debug Monitor Parameters - * - * Covers all Tx Debug Monitor Parameters from 0 to 10. - */ -struct tc956x_tx_dbg_mon { - __u8 gen3_tx_preset_override_en; - __u8 gen3_pcoeff_tx_post_cur; - __u8 gen3_pcoeff_tx_main_cur; - __u8 gen3_pcoeff_tx_pre_cur; - __u8 gen12_txmargin_override_en; - __u16 gen12_txswing1_txmargin0; - __u16 gen12_txswing0_txmargin0; -}; - -/** - * struct tc956x_rx_dbg_mon - Rx Debug Monitor Parameters - * - * Covers all Rx Debug Monitor Parameters both 0 and 1. - */ -struct tc956x_rx_dbg_mon { - __u8 gen3_rx_param_override_en; - __u8 gen3_rx_param00_dfe_dlev; - __u8 gen3_rx_param00_ctle_c; - __u8 gen3_rx_param00_ctle_r; - __u8 gen3_rx_param00_vga; - __u8 gen3_rx_param00_dfe_h5; - __u8 gen3_rx_param00_dfe_h4; - __u8 gen3_rx_param00_dfe_h3; - __u8 gen3_rx_param00_dfe_h2; - __u8 gen3_rx_param00_dfe_h1; -}; - - - +#endif /* #ifdef TC956X_PCIE_LOGSTAT */ /** * struct tc956x_ioctl_pcie_lane_change - IOCTL arguments for * PCIe USP and DSPs lane change for power reduction @@ -479,7 +590,7 @@ struct tc956x_ioctl_pcie_set_tx_deemphasis { * enable - enable or disable DFE * port - USP/DSP1/DSP2 on which DFE should be enabled/disabled */ -struct tc956x_ioctl_pcie_set_dfe{ +struct tc956x_ioctl_pcie_set_dfe { __u32 cmd; __u8 enable; /* 1: enable, 0: disable*/ enum ports port; /* USP, DSP1, DSP2*/ @@ -494,7 +605,7 @@ struct tc956x_ioctl_pcie_set_dfe{ * port - USP/DSP1/DSP2 on which CTLE fixed mode setting to be done */ -struct tc956x_ioctl_pcie_set_ctle_fixed_mode{ +struct tc956x_ioctl_pcie_set_ctle_fixed_mode { __u32 cmd; __u8 eqc_force; __u8 eq_res; @@ -511,33 +622,44 @@ struct tc956x_ioctl_pcie_set_speed { __u32 cmd; enum pcie_speed speed; /*1 or 2 or 3*/ }; - +#ifdef TC956X_PCIE_LOGSTAT /** - * struct tc956x_ioctl_logstat - IOCTL arguments for Log - * and Statistics configuration + * struct tc956x_ioctl_state_log_summary - IOCTL arguments for + * State Logging Summary. * - * If TC956X_PCIE_SET_LOGSTAT_CONF IOCTL used, user will - * set tc956x_ltssm_conf for the specified port. - * Otherwise, if TC956X_PCIE_GET_LOGSTAT_CONF IOCTL used, - * the driver will return tc956x_ltssm_conf - * for the port passed as IOCTL arguments. + * cmd - TC956X_PCIE_STATE_LOG_SUMMARY IOCTL. + * port - USP/DSP1/DSP2/EP for which state logging enable/disbale to be done. */ -struct tc956x_ioctl_logstatconf { +struct tc956x_ioctl_state_log_summary { __u32 cmd; - struct tc956x_ltssm_conf *logstat_conf; - enum ports port; + enum ports port; /* USP, DSP1, DSP2, EP*/ }; /** - * struct tc956x_ioctl_ltssm - IOCTL arguments for State log data + * struct tc956x_ioctl_state_log_enable - IOCTL arguments for + * Enabling/Disabling State Logging. * - * Driver will return tc956x_ltssm_log - * for the port passed as IOCTL arguments. + * cmd - TC956X_PCIE_STATE_LOG_ENABLE IOCTL. + * enable - enable/disable state log. + * port - USP/DSP1/DSP2/EP for which state logging enable/disbale to be done. */ -struct tc956x_ioctl_ltssm { +struct tc956x_ioctl_state_log_enable { __u32 cmd; - struct tc956x_ltssm_log *ltssm_logd; + enum state_log_enable enable; /* Enable/Disable */ + enum ports port; /* USP, DSP1, DSP2, EP*/ +}; + +/** + * struct tc956x_ioctl_pcie_link_params - IOCTL arguments for State log data + * + * cmd - TC956X_PCIE_GET_PCIE_LINK_PARAMS IOCTL. + * link_param - structure for pcie link parameters to read. + * port - USP/DSP1/DSP2/EP for which state link parameters to be read. + */ +struct tc956x_ioctl_pcie_link_params { + __u32 cmd; + struct tc956x_pcie_link_params *link_param; enum ports port; }; diff --git a/tc956xmac_main.c b/tc956xmac_main.c index 22abda5d31bc..5c26f192305d 100644 --- a/tc956xmac_main.c +++ b/tc956xmac_main.c @@ -4,7 +4,7 @@ * tc956xmac_main.c * * Copyright(C) 2007-2011 STMicroelectronics Ltd - * Copyright (C) 2021 Toshiba Electronic Devices & Storage Corporation + * Copyright (C) 2023 Toshiba Electronic Devices & Storage Corporation * * This file has been derived from the STMicro Linux driver, * and developed or modified for TC956X. @@ -140,6 +140,13 @@ * 22 Dec 2022 : 1. Support for SW reset during link down. 2. Module parameters introduced for the control of SW reset and by default SW reset is disabled. * VERSION : 01-00-58 + * 10 Nov 2023 : 1. Kernel 6.1 Porting changes. + 2. DSP Cascade related modifications. + * VERSION : 01-02-59 + * + * 26 Dec 2023 : 1. Kernel 6.6 Porting changes + * 2. Added the support for TC commands taprio and flower + * VERSION : 01-03-59 */ #include @@ -164,7 +171,9 @@ #include #endif /* CONFIG_DEBUG_FS */ #include +#ifdef TC956X_SRIOV_PF #include +#endif #include #include #include "tc956xmac_ptp.h" @@ -181,7 +190,15 @@ #include #include #endif +#ifdef TC956X_SRIOV_PF +#include "tc956x_pf_rsc_mng.h" +#include "tc956x_pf_mbx.h" +#include "tc956x_pf_rsc_mng.h" +#endif +#ifdef TC956X_SRIOV_VF +#include "tc956x_vf_mbx.h" +#endif #ifdef TC956X_PCIE_LOGSTAT #include "tc956x_pcie_logstat.h" #endif /* #ifdef TC956X_PCIE_LOGSTAT */ @@ -189,6 +206,9 @@ #define TSO_MAX_BUFF_SIZE (SZ_16K - 1) #define PPS_START_DELAY 100000000 /* 100 ms, in unit of ns */ +#ifdef TC956X_DYNAMIC_LOAD_CBS +int prev_speed; +#endif /* Module parameters */ #define TX_TIMEO 5000 static int watchdog = TX_TIMEO; @@ -230,7 +250,9 @@ static const u32 default_msg_level = (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN | NETIF_MSG_TIMER); +#ifdef TC956X_SRIOV_PF static void tc956x_ptp_configuration(struct tc956xmac_priv *priv, u32 tcr_config); +#endif #define TC956XMAC_DEFAULT_LPI_TIMER 1000 static int eee_timer = TC956XMAC_DEFAULT_LPI_TIMER; @@ -238,30 +260,87 @@ module_param(eee_timer, int, 0644); MODULE_PARM_DESC(eee_timer, "LPI tx expiration time in msec"); #define TC956XMAC_LPI_T(x) (jiffies + msecs_to_jiffies(x)) +#if defined(TC956X_SRIOV_PF) && defined(TC956X_ENABLE_MAC2MAC_BRIDGE) +static bool port_brige_state; +static DEFINE_MUTEX(tc956x_port_bridge_lock); +#endif /* By default the driver will use the ring mode to manage tx and rx descriptors, * but allow user to force to use the chain instead of the ring */ static unsigned int chain_mode; module_param(chain_mode, int, 0444); MODULE_PARM_DESC(chain_mode, "To use chain instead of ring mode"); - -static irqreturn_t tc956xmac_interrupt(int irq, void *dev_id); - +#if defined(TC956X_SRIOV_PF) +static irqreturn_t tc956xmac_interrupt_v0(int irq, void *dev_id); +static irqreturn_t tc956xmac_interrupt_v1(int irq, void *dev_id); +#elif defined(TC956X_SRIOV_VF) +static irqreturn_t tc956xmac_interrupt_v0(int irq, void *dev_id); +#endif #ifdef CONFIG_DEBUG_FS static const struct net_device_ops tc956xmac_netdev_ops; static void tc956xmac_init_fs(struct net_device *dev); static void tc956xmac_exit_fs(struct net_device *dev); #endif - +#ifdef TC956X_5_G_2_5_G_EEE_SUPPORT +extern int phy_ethtool_set_eee_2p5(struct phy_device *phydev, struct ethtool_eee *data); +#endif +#ifdef TC956X_SRIOV_PF static u32 tc956xmac_link_down_counter = 0; /* Counter to count Link Down/Up for both port */ +extern void tc956x_pf_del_umac_addr(struct tc956xmac_priv *priv, int index, int vf); +extern void tc956x_pf_del_mac_filter(struct net_device *dev, int vf, const u8 *mac); +extern void tc956x_pf_del_vlan_filter(struct net_device *dev, u16 vf, u16 vid); +extern void tc956xmac_get_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause); + +int tc956xmac_ioctl_set_cbs(struct tc956xmac_priv *priv, void *data); +int tc956xmac_ioctl_get_cbs(struct tc956xmac_priv *priv, void *data); +int tc956xmac_ioctl_get_est(struct tc956xmac_priv *priv, void *data); +int tc956xmac_ioctl_set_est(struct tc956xmac_priv *priv, void *data); +int tc956xmac_ioctl_get_fpe(struct tc956xmac_priv *priv, void *data); +int tc956xmac_ioctl_set_fpe(struct tc956xmac_priv *priv, void *data); +int tc956xmac_ioctl_get_rxp(struct tc956xmac_priv *priv, void *data); +int tc956xmac_ioctl_set_rxp(struct tc956xmac_priv *priv, void *data); +void tc956xmac_service_mbx_event_schedule(struct tc956xmac_priv *priv); +#ifdef TC956X_ENABLE_MAC2MAC_BRIDGE +extern int tc956x_pf_set_mac_filter(struct net_device *dev, int vf, const u8 *mac); +#endif + +#endif /* TC956X_SRIOV_PF */ #define TC956XMAC_COAL_TIMER(x) (jiffies + usecs_to_jiffies(x)) /* MAC address */ +#ifdef TC956X_SRIOV_PF +static u8 dev_addr[6][6] = { + {0xEC, 0x21, 0xE5, 0x10, 0x4F, 0xEA}, + {0xEC, 0x21, 0xE5, 0x11, 0x4F, 0xEA}, + {0xEC, 0x21, 0xE5, 0x12, 0x4F, 0xEA}, + {0xEC, 0x21, 0xE5, 0x13, 0x4F, 0xEA}, + {0xEC, 0x21, 0xE5, 0x14, 0x4F, 0xEA}, + {0xEC, 0x21, 0xE5, 0x15, 0x4F, 0xEA}, + }; + +#ifdef TC956X_ENABLE_MAC2MAC_BRIDGE +u8 flow_ctrl_addr[6] = {0x01, 0x80, 0xC2, 0x00, 0x00, 0x01}; +#endif + +#elif defined(TC956X_SRIOV_VF) /* Defining different MAC address for VF */ +static u8 dev_addr[2][3][6] = { + { /* PF-0 */ + {0xEC, 0x21, 0xE5, 0x12, 0x4F, 0xEA}, /* VF-0 */ + {0xEC, 0x21, 0xE5, 0x13, 0x4F, 0xEA}, /* VF-1 */ + {0xEC, 0x21, 0xE5, 0x14, 0x4F, 0xEA}, /* VF-2 */ + }, + { /* PF-1 */ + {0xEC, 0x21, 0xE5, 0x15, 0x4F, 0xEA}, /* VF-0 */ + {0xEC, 0x21, 0xE5, 0x16, 0x4F, 0xEA}, /* VF-1 */ + {0xEC, 0x21, 0xE5, 0x17, 0x4F, 0xEA}, /* VF-2 */ + }, + }; +#endif -static u8 dev_addr[2][6] = {{0xEC, 0x21, 0xE5, 0x10, 0x4F, 0xEA}, - {0xEC, 0x21, 0xE5, 0x11, 0x4F, 0xEA}}; #ifdef TC956X +#ifndef TC956X_SRIOV_VF #define TX_PRESET_MAX 11 static u8 tx_demphasis_setting[TX_PRESET_MAX][2] = { {0x00, 0x14}, /*Preshoot: 0 dB, De-emphasis: -6 dB*/ @@ -276,6 +355,7 @@ static u8 tx_demphasis_setting[TX_PRESET_MAX][2] = { {0x0E, 0x00}, /*Preshoot: 3.5 dB, De-emphasis: 0 dB*/ {0x00, 0x1B}, /*Preshoot: 0 dB, De-emphasis: -9.1 dB*/ }; +#endif /* TC956X_SRIOV_VF */ #endif struct config_parameter_list { @@ -292,7 +372,6 @@ static const struct config_parameter_list config_param_list[] = { }; static uint16_t mdio_bus_id; - #define CONFIG_PARAM_NUM ARRAY_SIZE(config_param_list) int tc956xmac_rx_parser_configuration(struct tc956xmac_priv *); @@ -303,6 +382,8 @@ static u8 phy_sa_addr[2][6] = { }; extern unsigned int mac0_en_lp_pause_frame_cnt; extern unsigned int mac1_en_lp_pause_frame_cnt; +#ifndef TC956X_SRIOV_VF + extern unsigned int mac_power_save_at_link_down; extern unsigned int mac0_force_speed_mode; @@ -311,8 +392,6 @@ extern unsigned int mac1_force_speed_mode; extern unsigned int mac0_link_down_macrst; extern unsigned int mac1_link_down_macrst; -extern int phy_ethtool_set_eee_2p5(struct phy_device *phydev, struct ethtool_eee *data); - static int dwxgmac2_rx_parser_read_entry(struct tc956xmac_priv *priv, struct tc956xmac_rx_parser_entry *entry, int entry_pos) { @@ -329,7 +408,7 @@ static int dwxgmac2_rx_parser_read_entry(struct tc956xmac_priv *priv, reg_val = reg_val & (~XGMAC_ADDR); reg_val |= (real_pos & XGMAC_ADDR); writel(reg_val, ioaddr + XGMAC_MTL_RXP_IACC_CTRL_ST); - + /* Set Read op */ reg_val = readl(ioaddr + XGMAC_MTL_RXP_IACC_CTRL_ST); reg_val &= ~XGMAC_WRRDN; @@ -391,29 +470,29 @@ int tc956x_dump_regs(struct net_device *net_device, struct tc956x_regs *regs) regs->config_reg.gpioe1 = readl(priv->ioaddr + GPIOE1_OFFSET); /* MSI register dump */ - regs->msi_reg.msi_out_en = readl(priv->ioaddr + TC956X_MSI_OUT_EN_OFFSET(priv->port_num)); - regs->msi_reg.msi_mask_set = readl(priv->ioaddr + TC956X_MSI_MASK_SET_OFFSET(priv->port_num)); - regs->msi_reg.msi_mask_clr = readl(priv->ioaddr + TC956X_MSI_MASK_CLR_OFFSET(priv->port_num)); - regs->msi_reg.int_sts = readl(priv->ioaddr + TC956X_MSI_INT_STS_OFFSET(priv->port_num)); - regs->msi_reg.int_raw_sts = readl(priv->ioaddr + TC956X_MSI_INT_RAW_STS_OFFSET(priv->port_num)); - regs->msi_reg.msi_sts = readl(priv->ioaddr + TC956X_MSI_STS_OFFSET(priv->port_num)); - regs->msi_reg.cnt_int0 = readl(priv->ioaddr + TC956X_MSI_CNT0(priv->port_num)); - regs->msi_reg.cnt_int1 = readl(priv->ioaddr + TC956X_MSI_CNT1(priv->port_num)); - regs->msi_reg.cnt_int2 = readl(priv->ioaddr + TC956X_MSI_CNT2(priv->port_num)); - regs->msi_reg.cnt_int3 = readl(priv->ioaddr + TC956X_MSI_CNT3(priv->port_num)); - regs->msi_reg.cnt_int4 = readl(priv->ioaddr + TC956X_MSI_CNT4(priv->port_num)); - regs->msi_reg.cnt_int11 = readl(priv->ioaddr + TC956X_MSI_CNT11(priv->port_num)); - regs->msi_reg.cnt_int12 = readl(priv->ioaddr + TC956X_MSI_CNT12(priv->port_num)); - regs->msi_reg.cnt_int20 = readl(priv->ioaddr + TC956X_MSI_CNT20(priv->port_num)); - regs->msi_reg.cnt_int24 = readl(priv->ioaddr + TC956X_MSI_CNT24(priv->port_num)); + regs->msi_reg.msi_out_en = readl(priv->ioaddr + TC956X_MSI_OUT_EN_OFFSET(priv->port_num, 0)); + regs->msi_reg.msi_mask_set = readl(priv->ioaddr + TC956X_MSI_MASK_SET_OFFSET(priv->port_num, 0)); + regs->msi_reg.msi_mask_clr = readl(priv->ioaddr + TC956X_MSI_MASK_CLR_OFFSET(priv->port_num, 0)); + regs->msi_reg.int_sts = readl(priv->ioaddr + TC956X_MSI_INT_STS_OFFSET(priv->port_num, 0)); + regs->msi_reg.int_raw_sts = readl(priv->ioaddr + TC956X_MSI_INT_RAW_STS_OFFSET(priv->port_num, 0)); + regs->msi_reg.msi_sts = readl(priv->ioaddr + TC956X_MSI_STS_OFFSET(priv->port_num, 0)); + regs->msi_reg.cnt_int0 = readl(priv->ioaddr + TC956X_MSI_CNT0(priv->port_num, 0)); + regs->msi_reg.cnt_int1 = readl(priv->ioaddr + TC956X_MSI_CNT1(priv->port_num, 0)); + regs->msi_reg.cnt_int2 = readl(priv->ioaddr + TC956X_MSI_CNT2(priv->port_num, 0)); + regs->msi_reg.cnt_int3 = readl(priv->ioaddr + TC956X_MSI_CNT3(priv->port_num, 0)); + regs->msi_reg.cnt_int4 = readl(priv->ioaddr + TC956X_MSI_CNT4(priv->port_num, 0)); + regs->msi_reg.cnt_int11 = readl(priv->ioaddr + TC956X_MSI_CNT11(priv->port_num, 0)); + regs->msi_reg.cnt_int12 = readl(priv->ioaddr + TC956X_MSI_CNT12(priv->port_num, 0)); + regs->msi_reg.cnt_int20 = readl(priv->ioaddr + TC956X_MSI_CNT20(priv->port_num, 0)); + regs->msi_reg.cnt_int24 = readl(priv->ioaddr + TC956X_MSI_CNT24(priv->port_num, 0)); /* INTC register dump */ - regs->intc_reg.intmcumask0 = readl(priv->ioaddr + INTMCUMASK0); - regs->intc_reg.intmcumask1 = readl(priv->ioaddr + INTMCUMASK1); - regs->intc_reg.intmcumask2 = readl(priv->ioaddr + INTMCUMASK2); + regs->intc_reg.intmcumask0 = readl(priv->ioaddr + INTMCUMASK0); + regs->intc_reg.intmcumask1 = readl(priv->ioaddr + INTMCUMASK1); + regs->intc_reg.intmcumask2 = readl(priv->ioaddr + INTMCUMASK2); /* DMA channel register dump */ - regs->dma_reg.debug_sts0 = readl(priv->ioaddr + XGMAC_DMA_DEBUG_STATUS0); + regs->dma_reg.debug_sts0 = readl(priv->ioaddr + XGMAC_DMA_DEBUG_STATUS0); for (ch = 0; ch < maxq; ch++) { regs->dma_reg.ch_control[ch] = readl(priv->ioaddr + XGMAC_DMA_CH_CONTROL(ch)); @@ -451,10 +530,10 @@ int tc956x_dump_regs(struct net_device *net_device, struct tc956x_regs *regs) tx_q = &priv->tx_queue[ch]; regs->dma_reg.tx_queue[ch].desc_phy_addr = tx_q->dma_tx_phy; regs->dma_reg.tx_queue[ch].desc_va_addr = tx_q->dma_tx; - #ifdef DMA_OFFLOAD_ENABLE +#ifdef TC956X_DMA_OFFLOAD_ENABLE regs->dma_reg.tx_queue[ch].buff_phy_addr = tx_q->buff_tx_phy; regs->dma_reg.tx_queue[ch].buff_va_addr = (void *)tx_q->buffer_tx_va_addr; - #endif +#endif regs->dma_reg.tx_queue[ch].tx_skbuff = tx_q->tx_skbuff; regs->dma_reg.tx_queue[ch].tx_skbuff_dma = tx_q->tx_skbuff_dma; } @@ -463,10 +542,10 @@ int tc956x_dump_regs(struct net_device *net_device, struct tc956x_regs *regs) rx_q = &priv->rx_queue[ch]; regs->dma_reg.rx_queue[ch].desc_phy_addr = rx_q->dma_rx_phy; regs->dma_reg.rx_queue[ch].desc_va_addr = rx_q->dma_rx; - #ifdef DMA_OFFLOAD_ENABLE +#ifdef TC956X_DMA_OFFLOAD_ENABLE regs->dma_reg.rx_queue[ch].buff_phy_addr = rx_q->buff_rx_phy; regs->dma_reg.rx_queue[ch].buff_va_addr = (void *)rx_q->buffer_rx_va_addr; - #endif +#endif regs->dma_reg.rx_queue[ch].buf_pool = rx_q->buf_pool; } @@ -497,71 +576,71 @@ int tc956x_dump_regs(struct net_device *net_device, struct tc956x_regs *regs) /* M3 SRAM dump */ for (ch = 0; ch < maxq; ch++) { - regs->m3_reg.sram_tx_pcie_addr[ch] = readl(priv->tc956x_SRAM_pci_base_addr + SRAM_TX_PCIE_ADDR_LOC + + regs->m3_reg.sram_tx_pcie_addr[ch] = readl(priv->tc956x_SRAM_pci_base_addr + SRAM_TX_PCIE_ADDR_LOC + (priv->port_num * TC956XMAC_CH_MAX * 4) + (ch * 4)); - regs->m3_reg.sram_rx_pcie_addr[ch] = readl(priv->tc956x_SRAM_pci_base_addr + SRAM_RX_PCIE_ADDR_LOC + + regs->m3_reg.sram_rx_pcie_addr[ch] = readl(priv->tc956x_SRAM_pci_base_addr + SRAM_RX_PCIE_ADDR_LOC + (priv->port_num * TC956XMAC_CH_MAX * 4) + (ch * 4)); - } + } regs->m3_reg.m3_fw_init_done = readl(priv->tc956x_SRAM_pci_base_addr + TC956X_M3_INIT_DONE); regs->m3_reg.m3_fw_exit = readl(priv->tc956x_SRAM_pci_base_addr + TC956X_M3_FW_EXIT); - regs->m3_reg.m3_debug_cnt0 = readl(priv->tc956x_SRAM_pci_base_addr + - (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT0 ))); - regs->m3_reg.m3_debug_cnt1 = readl(priv->tc956x_SRAM_pci_base_addr + - (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT1 ))); - regs->m3_reg.m3_debug_cnt2 = readl(priv->tc956x_SRAM_pci_base_addr + - (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT2 ))); - regs->m3_reg.m3_debug_cnt3 = readl(priv->tc956x_SRAM_pci_base_addr + - (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT3 ))); - regs->m3_reg.m3_debug_cnt4 = readl(priv->tc956x_SRAM_pci_base_addr + - (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT4 ))); - regs->m3_reg.m3_debug_cnt5 = readl(priv->tc956x_SRAM_pci_base_addr + - (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT5 ))); - regs->m3_reg.m3_debug_cnt6 = readl(priv->tc956x_SRAM_pci_base_addr + - (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT6 ))); - regs->m3_reg.m3_debug_cnt7 = readl(priv->tc956x_SRAM_pci_base_addr + - (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT7 ))); - regs->m3_reg.m3_debug_cnt8 = readl(priv->tc956x_SRAM_pci_base_addr + - (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT8 ))); - regs->m3_reg.m3_debug_cnt9 = readl(priv->tc956x_SRAM_pci_base_addr + - (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT9 ))); - regs->m3_reg.m3_debug_cnt10 = readl(priv->tc956x_SRAM_pci_base_addr + - (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT10 ))); - regs->m3_reg.m3_watchdog_exp_cnt = readl(priv->tc956x_SRAM_pci_base_addr + - (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT11 ))); - regs->m3_reg.m3_watchdog_monitor_cnt = readl(priv->tc956x_SRAM_pci_base_addr + - (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT12 ))); - regs->m3_reg.m3_debug_cnt13 = readl(priv->tc956x_SRAM_pci_base_addr + - (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT13 ))); - regs->m3_reg.m3_debug_cnt14 = readl(priv->tc956x_SRAM_pci_base_addr + - (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT14 ))); - regs->m3_reg.m3_systick_cnt_upper_value = readl(priv->tc956x_SRAM_pci_base_addr + - (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT16 ))); - regs->m3_reg.m3_systick_cnt_lower_value = readl(priv->tc956x_SRAM_pci_base_addr + - (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT15 ))); - regs->m3_reg.m3_tx_timeout_port0 = readl(priv->tc956x_SRAM_pci_base_addr + - (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT17 ))); - regs->m3_reg.m3_tx_timeout_port1 = readl(priv->tc956x_SRAM_pci_base_addr + - (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT18 ))); - regs->m3_reg.m3_debug_cnt19 = readl(priv->tc956x_SRAM_pci_base_addr + - (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT19 ))); + regs->m3_reg.m3_debug_cnt0 = readl(priv->tc956x_SRAM_pci_base_addr + + (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT0))); + regs->m3_reg.m3_debug_cnt1 = readl(priv->tc956x_SRAM_pci_base_addr + + (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT1))); + regs->m3_reg.m3_debug_cnt2 = readl(priv->tc956x_SRAM_pci_base_addr + + (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT2))); + regs->m3_reg.m3_debug_cnt3 = readl(priv->tc956x_SRAM_pci_base_addr + + (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT3))); + regs->m3_reg.m3_debug_cnt4 = readl(priv->tc956x_SRAM_pci_base_addr + + (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT4))); + regs->m3_reg.m3_debug_cnt5 = readl(priv->tc956x_SRAM_pci_base_addr + + (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT5))); + regs->m3_reg.m3_debug_cnt6 = readl(priv->tc956x_SRAM_pci_base_addr + + (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT6))); + regs->m3_reg.m3_debug_cnt7 = readl(priv->tc956x_SRAM_pci_base_addr + + (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT7))); + regs->m3_reg.m3_debug_cnt8 = readl(priv->tc956x_SRAM_pci_base_addr + + (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT8))); + regs->m3_reg.m3_debug_cnt9 = readl(priv->tc956x_SRAM_pci_base_addr + + (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT9))); + regs->m3_reg.m3_debug_cnt10 = readl(priv->tc956x_SRAM_pci_base_addr + + (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT10))); + regs->m3_reg.m3_watchdog_exp_cnt = readl(priv->tc956x_SRAM_pci_base_addr + + (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT11))); + regs->m3_reg.m3_watchdog_monitor_cnt = readl(priv->tc956x_SRAM_pci_base_addr + + (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT12))); + regs->m3_reg.m3_debug_cnt13 = readl(priv->tc956x_SRAM_pci_base_addr + + (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT13))); + regs->m3_reg.m3_debug_cnt14 = readl(priv->tc956x_SRAM_pci_base_addr + + (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT14))); + regs->m3_reg.m3_systick_cnt_upper_value = readl(priv->tc956x_SRAM_pci_base_addr + + (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT16))); + regs->m3_reg.m3_systick_cnt_lower_value = readl(priv->tc956x_SRAM_pci_base_addr + + (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT15))); + regs->m3_reg.m3_tx_timeout_port0 = readl(priv->tc956x_SRAM_pci_base_addr + + (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT17))); + regs->m3_reg.m3_tx_timeout_port1 = readl(priv->tc956x_SRAM_pci_base_addr + + (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT18))); + regs->m3_reg.m3_debug_cnt19 = readl(priv->tc956x_SRAM_pci_base_addr + + (TC956X_M3_SRAM_DEBUG_CNTS_OFFSET + (DB_CNT_LEN * DB_CNT19))); regs->rxp_cfg = (struct tc956xmac_rx_parser_cfg *)&priv->plat->rxp_cfg; /* TAMAP Information */ - for(table_entry = 0; table_entry <= MAX_CM3_TAMAP_ENTRIES; table_entry++) { - regs->tamap[table_entry].trsl_addr_hi = readl(priv->tc956x_BRIDGE_CFG_pci_base_addr + + for (table_entry = 0; table_entry <= MAX_CM3_TAMAP_ENTRIES; table_entry++) { + regs->tamap[table_entry].trsl_addr_hi = readl(priv->tc956x_BRIDGE_CFG_pci_base_addr + TC956X_AXI4_SLV_TRSL_ADDR_HI(0, table_entry)); - regs->tamap[table_entry].trsl_addr_low = readl(priv->tc956x_BRIDGE_CFG_pci_base_addr + + regs->tamap[table_entry].trsl_addr_low = readl(priv->tc956x_BRIDGE_CFG_pci_base_addr + TC956X_AXI4_SLV_TRSL_ADDR_LO(0, table_entry)); - regs->tamap[table_entry].src_addr_hi = readl(priv->tc956x_BRIDGE_CFG_pci_base_addr + + regs->tamap[table_entry].src_addr_hi = readl(priv->tc956x_BRIDGE_CFG_pci_base_addr + TC956X_AXI4_SLV_SRC_ADDR_HI(0, table_entry)); - regs->tamap[table_entry].src_addr_low = (readl(priv->tc956x_BRIDGE_CFG_pci_base_addr + + regs->tamap[table_entry].src_addr_low = (readl(priv->tc956x_BRIDGE_CFG_pci_base_addr + TC956X_AXI4_SLV_SRC_ADDR_LO(0, table_entry)) & TC956X_SRC_LO_MASK); - regs->tamap[table_entry].atr_size = ((readl(priv->tc956x_BRIDGE_CFG_pci_base_addr + + regs->tamap[table_entry].atr_size = ((readl(priv->tc956x_BRIDGE_CFG_pci_base_addr + TC956X_AXI4_SLV_SRC_ADDR_LO(0, table_entry)) & TC956X_ATR_SIZE_MASK) >> 1); - regs->tamap[table_entry].atr_impl = (readl(priv->tc956x_BRIDGE_CFG_pci_base_addr + + regs->tamap[table_entry].atr_impl = (readl(priv->tc956x_BRIDGE_CFG_pci_base_addr + TC956X_AXI4_SLV_SRC_ADDR_LO(0, table_entry)) & TC956X_ATR_IMPL); } @@ -623,7 +702,7 @@ int tc956x_dump_regs(struct net_device *net_device, struct tc956x_regs *regs) /* Reading FRP Table information from Registers */ regs->rxp_cfg->nve = (readl(priv->ioaddr + XGMAC_MTL_RXP_CONTROL_STATUS) & 0xFF); regs->rxp_cfg->npe = ((readl(priv->ioaddr + XGMAC_MTL_RXP_CONTROL_STATUS) >> 16) & 0xFF); - for(table_entry = 0; table_entry <= (regs->rxp_cfg->nve); table_entry++) { + for (table_entry = 0; table_entry <= (regs->rxp_cfg->nve); table_entry++) { dwxgmac2_rx_parser_read_entry(priv, &(regs->rxp_cfg->entries[table_entry]), table_entry); } @@ -631,6 +710,7 @@ int tc956x_dump_regs(struct net_device *net_device, struct tc956x_regs *regs) return 0; } EXPORT_SYMBOL_GPL(tc956x_dump_regs); +#endif int tc956x_print_debug_regs(struct net_device *net_device, struct tc956x_regs *regs) { @@ -643,231 +723,234 @@ int tc956x_print_debug_regs(struct net_device *net_device, struct tc956x_regs *r DBGPR_FUNC(priv->device, "-->%s\n", __func__); - printk("regs->pcie_reg.rsc_mng_id = 0x%x\n",regs->pcie_reg.rsc_mng_id); + KPRINT_DEBUG1("regs->pcie_reg.rsc_mng_id = 0x%x\n", regs->pcie_reg.rsc_mng_id); /* Configuration register dump */ - printk("regs->config_reg.ncid = 0x%x\n", regs->config_reg.ncid); - printk("regs->config_reg.nclkctrl0 = 0x%x\n", regs->config_reg.nclkctrl0); - printk("regs->config_reg.nrstctrl0 = 0x%x\n", regs->config_reg.nrstctrl0); - printk("regs->config_reg.nclkctrl1 = 0x%x\n", regs->config_reg.nclkctrl1); - printk("regs->config_reg.nrstctrl1 = 0x%x\n", regs->config_reg.nrstctrl1); - printk("regs->config_reg.nemac0ctl = 0x%x\n", regs->config_reg.nemac0ctl); - printk("regs->config_reg.nemac1ctl = 0x%x\n", regs->config_reg.nemac1ctl); - printk("regs->config_reg.nemacsts = 0x%x\n", regs->config_reg.nemacsts); - printk("regs->config_reg.gpioi0 = 0x%x\n", regs->config_reg.gpioi0); - printk("regs->config_reg.gpioi1 = 0x%x\n", regs->config_reg.gpioi1); - printk("regs->config_reg.gpioe0 = 0x%x\n", regs->config_reg.gpioe0); - printk("regs->config_reg.gpioe1 = 0x%x\n", regs->config_reg.gpioe1); + KPRINT_DEBUG1("regs->config_reg.ncid = 0x%x\n", regs->config_reg.ncid); + KPRINT_DEBUG1("regs->config_reg.nclkctrl0 = 0x%x\n", regs->config_reg.nclkctrl0); + KPRINT_DEBUG1("regs->config_reg.nrstctrl0 = 0x%x\n", regs->config_reg.nrstctrl0); + KPRINT_DEBUG1("regs->config_reg.nclkctrl1 = 0x%x\n", regs->config_reg.nclkctrl1); + KPRINT_DEBUG1("regs->config_reg.nrstctrl1 = 0x%x\n", regs->config_reg.nrstctrl1); + KPRINT_DEBUG1("regs->config_reg.nemac0ctl = 0x%x\n", regs->config_reg.nemac0ctl); + KPRINT_DEBUG1("regs->config_reg.nemac1ctl = 0x%x\n", regs->config_reg.nemac1ctl); + KPRINT_DEBUG1("regs->config_reg.nemacsts = 0x%x\n", regs->config_reg.nemacsts); + KPRINT_DEBUG1("regs->config_reg.gpioi0 = 0x%x\n", regs->config_reg.gpioi0); + KPRINT_DEBUG1("regs->config_reg.gpioi1 = 0x%x\n", regs->config_reg.gpioi1); + KPRINT_DEBUG1("regs->config_reg.gpioe0 = 0x%x\n", regs->config_reg.gpioe0); + KPRINT_DEBUG1("regs->config_reg.gpioe1 = 0x%x\n", regs->config_reg.gpioe1); /* MSI register dump */ - printk("regs->msi_reg.msi_out_en = 0x%x\n", regs->msi_reg.msi_out_en); - printk("regs->msi_reg.msi_mask_set = 0x%x\n", regs->msi_reg.msi_mask_set); - printk("regs->msi_reg.msi_mask_clr = 0x%x\n", regs->msi_reg.msi_mask_clr); - printk("regs->msi_reg.int_sts = 0x%x\n", regs->msi_reg.int_sts); - printk("regs->msi_reg.int_raw_sts = 0x%x\n", regs->msi_reg.int_raw_sts); - printk("regs->msi_reg.msi_sts = 0x%x\n", regs->msi_reg.msi_sts); - printk("regs->msi_reg.cnt_int0 = 0x%x\n", regs->msi_reg.cnt_int0); - printk("regs->msi_reg.cnt_int1 = 0x%x\n", regs->msi_reg.cnt_int1); - printk("regs->msi_reg.cnt_int2 = 0x%x\n", regs->msi_reg.cnt_int2); - printk("regs->msi_reg.cnt_int3 = 0x%x\n", regs->msi_reg.cnt_int3); - printk("regs->msi_reg.cnt_int4 = 0x%x\n", regs->msi_reg.cnt_int4); - printk("regs->msi_reg.cnt_int11 = 0x%x\n", regs->msi_reg.cnt_int11); - printk("regs->msi_reg.cnt_int12 = 0x%x\n", regs->msi_reg.cnt_int12); - printk("regs->msi_reg.cnt_int20 = 0x%x\n", regs->msi_reg.cnt_int20); - printk("regs->msi_reg.cnt_int24 = 0x%x\n", regs->msi_reg.cnt_int24); + KPRINT_DEBUG1("regs->msi_reg.msi_out_en = 0x%x\n", regs->msi_reg.msi_out_en); + KPRINT_DEBUG1("regs->msi_reg.msi_mask_set = 0x%x\n", regs->msi_reg.msi_mask_set); + KPRINT_DEBUG1("regs->msi_reg.msi_mask_clr = 0x%x\n", regs->msi_reg.msi_mask_clr); + KPRINT_DEBUG1("regs->msi_reg.int_sts = 0x%x\n", regs->msi_reg.int_sts); + KPRINT_DEBUG1("regs->msi_reg.int_raw_sts = 0x%x\n", regs->msi_reg.int_raw_sts); + KPRINT_DEBUG1("regs->msi_reg.msi_sts = 0x%x\n", regs->msi_reg.msi_sts); + KPRINT_DEBUG1("regs->msi_reg.cnt_int0 = 0x%x\n", regs->msi_reg.cnt_int0); + KPRINT_DEBUG1("regs->msi_reg.cnt_int1 = 0x%x\n", regs->msi_reg.cnt_int1); + KPRINT_DEBUG1("regs->msi_reg.cnt_int2 = 0x%x\n", regs->msi_reg.cnt_int2); + KPRINT_DEBUG1("regs->msi_reg.cnt_int3 = 0x%x\n", regs->msi_reg.cnt_int3); + KPRINT_DEBUG1("regs->msi_reg.cnt_int4 = 0x%x\n", regs->msi_reg.cnt_int4); + KPRINT_DEBUG1("regs->msi_reg.cnt_int11 = 0x%x\n", regs->msi_reg.cnt_int11); + KPRINT_DEBUG1("regs->msi_reg.cnt_int12 = 0x%x\n", regs->msi_reg.cnt_int12); + KPRINT_DEBUG1("regs->msi_reg.cnt_int20 = 0x%x\n", regs->msi_reg.cnt_int20); + KPRINT_DEBUG1("regs->msi_reg.cnt_int24 = 0x%x\n", regs->msi_reg.cnt_int24); /* INTC register dump */ - printk("regs->intc_reg.intmcumask0 = 0x%x\n", regs->intc_reg.intmcumask0); - printk("regs->intc_reg.intmcumask1 = 0x%x\n", regs->intc_reg.intmcumask1); - printk("regs->intc_reg.intmcumask2 = 0x%x\n", regs->intc_reg.intmcumask2); + KPRINT_DEBUG1("regs->intc_reg.intmcumask0 = 0x%x\n", regs->intc_reg.intmcumask0); + KPRINT_DEBUG1("regs->intc_reg.intmcumask1 = 0x%x\n", regs->intc_reg.intmcumask1); + KPRINT_DEBUG1("regs->intc_reg.intmcumask2 = 0x%x\n", regs->intc_reg.intmcumask2); /* DMA channel register dump */ - printk("regs->dma_reg.debug_sts0 = 0x%x\n", regs->dma_reg.debug_sts0); + KPRINT_DEBUG1("regs->dma_reg.debug_sts0 = 0x%x\n", regs->dma_reg.debug_sts0); for (ch = 0; ch < maxq; ch++) { - printk("regs->dma_reg.ch_control[%d] = 0x%x\n", ch, regs->dma_reg.ch_control[ch]); - printk("regs->dma_reg.interrupt_enable[%d] = 0x%x\n", ch, regs->dma_reg.interrupt_enable[ch]); - printk("regs->dma_reg.ch_status[%d] = 0x%x\n", ch, regs->dma_reg.ch_status[ch]); - printk("regs->dma_reg.debug_status[%d] = 0x%x\n", ch, regs->dma_reg.debug_status[ch]); - printk("regs->dma_reg.rxch_watchdog_timer[%d] = 0x%x\n", ch, regs->dma_reg.rxch_watchdog_timer[ch]); + KPRINT_DEBUG1("regs->dma_reg.ch_control[%d] = 0x%x\n", ch, regs->dma_reg.ch_control[ch]); + KPRINT_DEBUG1("regs->dma_reg.interrupt_enable[%d] = 0x%x\n", ch, regs->dma_reg.interrupt_enable[ch]); + KPRINT_DEBUG1("regs->dma_reg.ch_status[%d] = 0x%x\n", ch, regs->dma_reg.ch_status[ch]); + KPRINT_DEBUG1("regs->dma_reg.debug_status[%d] = 0x%x\n", ch, regs->dma_reg.debug_status[ch]); + KPRINT_DEBUG1("regs->dma_reg.rxch_watchdog_timer[%d] = 0x%x\n", ch, regs->dma_reg.rxch_watchdog_timer[ch]); } for (ch = 0; ch < tx_queues_cnt; ch++) { - printk("regs->dma_reg.tx_ch[%d].control = 0x%x\n", ch, regs->dma_reg.tx_ch[ch].control); - printk("regs->dma_reg.tx_ch[%d].list_haddr = 0x%x\n", ch, regs->dma_reg.tx_ch[ch].list_haddr); - printk("regs->dma_reg.tx_ch[%d].list_laddr = 0x%x\n", ch, regs->dma_reg.tx_ch[ch].list_laddr); - printk("regs->dma_reg.tx_ch[%d].ring_len = 0x%x\n", ch, regs->dma_reg.tx_ch[ch].ring_len); - printk("regs->dma_reg.tx_ch[%d].curr_haddr = 0x%x\n", ch, regs->dma_reg.tx_ch[ch].curr_haddr); - printk("regs->dma_reg.tx_ch[%d].curr_laddr = 0x%x\n", ch, regs->dma_reg.tx_ch[ch].curr_laddr); - printk("regs->dma_reg.tx_ch[%d].tail_ptr = 0x%x\n", ch, regs->dma_reg.tx_ch[ch].tail_ptr); - printk("regs->dma_reg.tx_ch[%d].buf_haddr = 0x%x\n", ch, regs->dma_reg.tx_ch[ch].buf_haddr); - printk("regs->dma_reg.tx_ch[%d].buf_laddr = 0x%x\n", ch, regs->dma_reg.tx_ch[ch].buf_laddr); + KPRINT_DEBUG1("regs->dma_reg.tx_ch[%d].control = 0x%x\n", ch, regs->dma_reg.tx_ch[ch].control); + KPRINT_DEBUG1("regs->dma_reg.tx_ch[%d].list_haddr = 0x%x\n", ch, regs->dma_reg.tx_ch[ch].list_haddr); + KPRINT_DEBUG1("regs->dma_reg.tx_ch[%d].list_laddr = 0x%x\n", ch, regs->dma_reg.tx_ch[ch].list_laddr); + KPRINT_DEBUG1("regs->dma_reg.tx_ch[%d].ring_len = 0x%x\n", ch, regs->dma_reg.tx_ch[ch].ring_len); + KPRINT_DEBUG1("regs->dma_reg.tx_ch[%d].curr_haddr = 0x%x\n", ch, regs->dma_reg.tx_ch[ch].curr_haddr); + KPRINT_DEBUG1("regs->dma_reg.tx_ch[%d].curr_laddr = 0x%x\n", ch, regs->dma_reg.tx_ch[ch].curr_laddr); + KPRINT_DEBUG1("regs->dma_reg.tx_ch[%d].tail_ptr = 0x%x\n", ch, regs->dma_reg.tx_ch[ch].tail_ptr); + KPRINT_DEBUG1("regs->dma_reg.tx_ch[%d].buf_haddr = 0x%x\n", ch, regs->dma_reg.tx_ch[ch].buf_haddr); + KPRINT_DEBUG1("regs->dma_reg.tx_ch[%d].buf_laddr = 0x%x\n", ch, regs->dma_reg.tx_ch[ch].buf_laddr); } for (ch = 0; ch < rx_queues_cnt; ch++) { - printk("regs->dma_reg.rx_ch[%d].control = 0x%x\n", ch, regs->dma_reg.rx_ch[ch].control); - printk("regs->dma_reg.rx_ch[%d].list_haddr = 0x%x\n", ch, regs->dma_reg.rx_ch[ch].list_haddr); - printk("regs->dma_reg.rx_ch[%d].list_laddr = 0x%x\n", ch, regs->dma_reg.rx_ch[ch].list_laddr); - printk("regs->dma_reg.rx_ch[%d].ring_len = 0x%x\n", ch, regs->dma_reg.rx_ch[ch].ring_len); - printk("regs->dma_reg.rx_ch[%d].curr_haddr = 0x%x\n", ch, regs->dma_reg.rx_ch[ch].curr_haddr); - printk("regs->dma_reg.rx_ch[%d].curr_laddr = 0x%x\n", ch, regs->dma_reg.rx_ch[ch].curr_laddr); - printk("regs->dma_reg.rx_ch[%d].tail_ptr = 0x%x\n", ch, regs->dma_reg.rx_ch[ch].tail_ptr); - printk("regs->dma_reg.rx_ch[%d].buf_haddr = 0x%x\n", ch, regs->dma_reg.rx_ch[ch].buf_haddr); - printk("regs->dma_reg.rx_ch[%d].buf_laddr = 0x%x\n", ch, regs->dma_reg.rx_ch[ch].buf_laddr); + KPRINT_DEBUG1("regs->dma_reg.rx_ch[%d].control = 0x%x\n", ch, regs->dma_reg.rx_ch[ch].control); + KPRINT_DEBUG1("regs->dma_reg.rx_ch[%d].list_haddr = 0x%x\n", ch, regs->dma_reg.rx_ch[ch].list_haddr); + KPRINT_DEBUG1("regs->dma_reg.rx_ch[%d].list_laddr = 0x%x\n", ch, regs->dma_reg.rx_ch[ch].list_laddr); + KPRINT_DEBUG1("regs->dma_reg.rx_ch[%d].ring_len = 0x%x\n", ch, regs->dma_reg.rx_ch[ch].ring_len); + KPRINT_DEBUG1("regs->dma_reg.rx_ch[%d].curr_haddr = 0x%x\n", ch, regs->dma_reg.rx_ch[ch].curr_haddr); + KPRINT_DEBUG1("regs->dma_reg.rx_ch[%d].curr_laddr = 0x%x\n", ch, regs->dma_reg.rx_ch[ch].curr_laddr); + KPRINT_DEBUG1("regs->dma_reg.rx_ch[%d].tail_ptr = 0x%x\n", ch, regs->dma_reg.rx_ch[ch].tail_ptr); + KPRINT_DEBUG1("regs->dma_reg.rx_ch[%d].buf_haddr = 0x%x\n", ch, regs->dma_reg.rx_ch[ch].buf_haddr); + KPRINT_DEBUG1("regs->dma_reg.rx_ch[%d].buf_laddr = 0x%x\n", ch, regs->dma_reg.rx_ch[ch].buf_laddr); } for (ch = 0; ch < tx_queues_cnt; ch++) { - printk("regs->dma_reg.tx_queue[%d].desc_phy_addr = 0x%x\n", ch, regs->dma_reg.tx_queue[ch].desc_phy_addr); - printk("regs->dma_reg.tx_queue[%d].desc_va_addr = 0x%x\n", ch, (u32)(regs->dma_reg.tx_queue[ch].desc_va_addr)); - #ifdef DMA_OFFLOAD_ENABLE - printk("regs->dma_reg.tx_queue[%d].buff_phy_addr = 0x%x\n", ch, regs->dma_reg.tx_queue[ch].buff_phy_addr); - printk("regs->dma_reg.tx_queue[%d].buff_va_addr = 0x%x\n", ch, (u32)(regs->dma_reg.tx_queue[ch].buff_va_addr)); - #endif - printk("regs->dma_reg.tx_queue[%d].tx_skbuff = 0x%x\n", ch, (u32)(regs->dma_reg.tx_queue[ch].tx_skbuff)); - printk("regs->dma_reg.tx_queue[%d].tx_skbuff_dma = 0x%x\n", ch, (u32)(regs->dma_reg.tx_queue[ch].tx_skbuff_dma)); + KPRINT_DEBUG1("regs->dma_reg.tx_queue[%d].desc_phy_addr = 0x%llx\n", ch, regs->dma_reg.tx_queue[ch].desc_phy_addr); + KPRINT_DEBUG1("regs->dma_reg.tx_queue[%d].desc_va_addr = 0x%zx\n", ch, (size_t)(regs->dma_reg.tx_queue[ch].desc_va_addr)); +#ifdef TC956X_DMA_OFFLOAD_ENABLE + KPRINT_DEBUG1("regs->dma_reg.tx_queue[%d].buff_phy_addr = 0x%llx\n", ch, regs->dma_reg.tx_queue[ch].buff_phy_addr); + KPRINT_DEBUG1("regs->dma_reg.tx_queue[%d].buff_va_addr = 0x%zx\n", ch, (size_t)(regs->dma_reg.tx_queue[ch].buff_va_addr)); +#endif + KPRINT_DEBUG1("regs->dma_reg.tx_queue[%d].tx_skbuff = 0x%zx\n", ch, (size_t)(regs->dma_reg.tx_queue[ch].tx_skbuff)); + KPRINT_DEBUG1("regs->dma_reg.tx_queue[%d].tx_skbuff_dma = 0x%zx\n", ch, (size_t)(regs->dma_reg.tx_queue[ch].tx_skbuff_dma)); } for (ch = 0; ch < rx_queues_cnt; ch++) { - printk("regs->dma_reg.rx_queue[%d].desc_phy_addr = 0x%x\n", ch, regs->dma_reg.rx_queue[ch].desc_phy_addr); - printk("regs->dma_reg.rx_queue[%d].desc_va_addr = 0x%x\n", ch, (u32)(regs->dma_reg.rx_queue[ch].desc_va_addr)); - #ifdef DMA_OFFLOAD_ENABLE - printk("regs->dma_reg.rx_queue[%d].buff_phy_addr = 0x%x\n", ch, regs->dma_reg.rx_queue[ch].buff_phy_addr); - printk("regs->dma_reg.rx_queue[%d].buff_va_addr = 0x%x\n", ch, (u32)(regs->dma_reg.rx_queue[ch].buff_va_addr)); - #endif - printk("regs->dma_reg.rx_queue[%d].buf_pool = 0x%x\n", ch, (u32)(regs->dma_reg.rx_queue[ch].buf_pool)); + KPRINT_DEBUG1("regs->dma_reg.rx_queue[%d].desc_phy_addr = 0x%llx\n", ch, regs->dma_reg.rx_queue[ch].desc_phy_addr); + KPRINT_DEBUG1("regs->dma_reg.rx_queue[%d].desc_va_addr = 0x%zx\n", ch, (size_t)(regs->dma_reg.rx_queue[ch].desc_va_addr)); +#ifdef TC956X_DMA_OFFLOAD_ENABLE + KPRINT_DEBUG1("regs->dma_reg.rx_queue[%d].buff_phy_addr = 0x%llx\n", ch, regs->dma_reg.rx_queue[ch].buff_phy_addr); + KPRINT_DEBUG1("regs->dma_reg.rx_queue[%d].buff_va_addr = 0x%zx\n", ch, (size_t)(regs->dma_reg.rx_queue[ch].buff_va_addr)); +#endif + KPRINT_DEBUG1("regs->dma_reg.rx_queue[%d].buf_pool = 0x%zx\n", ch, (size_t)(regs->dma_reg.rx_queue[ch].buf_pool)); } /* MAC register dump */ - printk("regs->mac_reg.mac_tx_config = 0x%x\n", regs->mac_reg.mac_tx_config); - printk("regs->mac_reg.mac_rx_config = 0x%x\n", regs->mac_reg.mac_rx_config); - printk("regs->mac_reg.mac_pkt_filter = 0x%x\n", regs->mac_reg.mac_pkt_filter); - printk("regs->mac_reg.mac_tx_rx_status = 0x%x\n", regs->mac_reg.mac_tx_rx_status); - printk("regs->mac_reg.mac_debug = 0x%x\n", regs->mac_reg.mac_debug); + KPRINT_DEBUG1("regs->mac_reg.mac_tx_config = 0x%x\n", regs->mac_reg.mac_tx_config); + KPRINT_DEBUG1("regs->mac_reg.mac_rx_config = 0x%x\n", regs->mac_reg.mac_rx_config); + KPRINT_DEBUG1("regs->mac_reg.mac_pkt_filter = 0x%x\n", regs->mac_reg.mac_pkt_filter); + KPRINT_DEBUG1("regs->mac_reg.mac_tx_rx_status = 0x%x\n", regs->mac_reg.mac_tx_rx_status); + KPRINT_DEBUG1("regs->mac_reg.mac_debug = 0x%x\n", regs->mac_reg.mac_debug); /* MTL register dump */ - printk("regs->mtl_reg.op_mode = 0x%x\n", regs->mtl_reg.op_mode); - printk("regs->mtl_reg.mtl_rxq_dma_map0 = 0x%x\n", regs->mtl_reg.mtl_rxq_dma_map0 ); - printk("regs->mtl_reg.mtl_rxq_dma_map1 = 0x%x\n", regs->mtl_reg.mtl_rxq_dma_map1); + KPRINT_DEBUG1("regs->mtl_reg.op_mode = 0x%x\n", regs->mtl_reg.op_mode); + KPRINT_DEBUG1("regs->mtl_reg.mtl_rxq_dma_map0 = 0x%x\n", regs->mtl_reg.mtl_rxq_dma_map0); + KPRINT_DEBUG1("regs->mtl_reg.mtl_rxq_dma_map1 = 0x%x\n", regs->mtl_reg.mtl_rxq_dma_map1); for (queue = 0; queue < MTL_MAX_TX_QUEUES; queue++) { - printk("regs->mtl_reg.tx_info[%d].op_mode = 0x%x\n", queue, regs->mtl_reg.tx_info[queue].op_mode); - printk("regs->mtl_reg.tx_info[%d].underflow = 0x%x\n", queue, regs->mtl_reg.tx_info[queue].underflow); - printk("regs->mtl_reg.tx_info[%d].debug = 0x%x\n", queue, regs->mtl_reg.tx_info[queue].debug); + KPRINT_DEBUG1("regs->mtl_reg.tx_info[%d].op_mode = 0x%x\n", queue, regs->mtl_reg.tx_info[queue].op_mode); + KPRINT_DEBUG1("regs->mtl_reg.tx_info[%d].underflow = 0x%x\n", queue, regs->mtl_reg.tx_info[queue].underflow); + KPRINT_DEBUG1("regs->mtl_reg.tx_info[%d].debug = 0x%x\n", queue, regs->mtl_reg.tx_info[queue].debug); } for (queue = 0; queue < MTL_MAX_RX_QUEUES; queue++) { - printk("regs->mtl_reg.rx_info[%d].op_mode = 0x%x\n", queue, regs->mtl_reg.rx_info[queue].op_mode); - printk("regs->mtl_reg.rx_info[%d].miss_pkt_overflow = 0x%x\n", queue, regs->mtl_reg.rx_info[queue].miss_pkt_overflow); - printk("regs->mtl_reg.rx_info[%d].debug = 0x%x\n", queue, regs->mtl_reg.rx_info[queue].debug); - printk("regs->mtl_reg.rx_info[%d].flow_control = 0x%x\n", queue, regs->mtl_reg.rx_info[queue].flow_control ); + KPRINT_DEBUG1("regs->mtl_reg.rx_info[%d].op_mode = 0x%x\n", queue, regs->mtl_reg.rx_info[queue].op_mode); + KPRINT_DEBUG1("regs->mtl_reg.rx_info[%d].miss_pkt_overflow = 0x%x\n", queue, regs->mtl_reg.rx_info[queue].miss_pkt_overflow); + KPRINT_DEBUG1("regs->mtl_reg.rx_info[%d].debug = 0x%x\n", queue, regs->mtl_reg.rx_info[queue].debug); + KPRINT_DEBUG1("regs->mtl_reg.rx_info[%d].flow_control = 0x%x\n", queue, regs->mtl_reg.rx_info[queue].flow_control); } /* M3 SRAM dump */ for (ch = 0; ch < maxq; ch++) { - printk("regs->m3_reg.sram_tx_pcie_addr[%d] = 0x%x\n", ch, regs->m3_reg.sram_tx_pcie_addr[ch]); - printk("regs->m3_reg.sram_rx_pcie_addr[%d] = 0x%x\n", ch, regs->m3_reg.sram_rx_pcie_addr[ch]); + KPRINT_DEBUG1("regs->m3_reg.sram_tx_pcie_addr[%d] = 0x%x\n", ch, regs->m3_reg.sram_tx_pcie_addr[ch]); + KPRINT_DEBUG1("regs->m3_reg.sram_rx_pcie_addr[%d] = 0x%x\n", ch, regs->m3_reg.sram_rx_pcie_addr[ch]); } - printk("regs->m3_reg.m3_fw_init_done = 0x%x\n", regs->m3_reg.m3_fw_init_done); - printk("regs->m3_reg.m3_fw_exit = 0x%x\n", regs->m3_reg.m3_fw_exit); - printk("regs->m3_reg.m3_debug_cnt0 = 0x%x\n", regs->m3_reg.m3_debug_cnt0); - printk("regs->m3_reg.m3_debug_cnt1 = 0x%x\n", regs->m3_reg.m3_debug_cnt1); - printk("regs->m3_reg.m3_debug_cnt2 = 0x%x\n", regs->m3_reg.m3_debug_cnt2); - printk("regs->m3_reg.m3_debug_cnt3 = 0x%x\n", regs->m3_reg.m3_debug_cnt3); - printk("regs->m3_reg.m3_debug_cnt4 = 0x%x\n", regs->m3_reg.m3_debug_cnt4); - printk("regs->m3_reg.m3_debug_cnt5 = 0x%x\n", regs->m3_reg.m3_debug_cnt5); - printk("regs->m3_reg.m3_debug_cnt6 = 0x%x\n", regs->m3_reg.m3_debug_cnt6); - printk("regs->m3_reg.m3_debug_cnt7 = 0x%x\n", regs->m3_reg.m3_debug_cnt7); - printk("regs->m3_reg.m3_debug_cnt8 = 0x%x\n", regs->m3_reg.m3_debug_cnt8); - printk("regs->m3_reg.m3_debug_cnt9 = 0x%x\n", regs->m3_reg.m3_debug_cnt9); - printk("regs->m3_reg.m3_debug_cnt10 = 0x%x\n", regs->m3_reg.m3_debug_cnt10); - printk("regs->m3_reg.m3_watchdog_exp_cnt = 0x%x\n", regs->m3_reg.m3_watchdog_exp_cnt); - printk("regs->m3_reg.m3_watchdog_monitor_cnt = 0x%x\n", regs->m3_reg.m3_watchdog_monitor_cnt); - printk("regs->m3_reg.m3_debug_cnt13 = 0x%x\n", regs->m3_reg.m3_debug_cnt13); - printk("regs->m3_reg.m3_debug_cnt14 = 0x%x\n", regs->m3_reg.m3_debug_cnt14); - printk("regs->m3_reg.m3_systick_cnt_upper_value = 0x%x\n", regs->m3_reg.m3_systick_cnt_upper_value); - printk("regs->m3_reg.m3_systick_cnt_lower_value = 0x%x\n", regs->m3_reg.m3_systick_cnt_lower_value); - printk("regs->m3_reg.m3_tx_timeout_port0 = 0x%x\n", regs->m3_reg.m3_tx_timeout_port0); - printk("regs->m3_reg.m3_tx_timeout_port1 = 0x%x\n", regs->m3_reg.m3_tx_timeout_port1); - printk("regs->m3_reg.m3_debug_cnt19 = 0x%x\n", regs->m3_reg.m3_debug_cnt19); - + KPRINT_DEBUG1("regs->m3_reg.m3_fw_init_done = 0x%x\n", regs->m3_reg.m3_fw_init_done); + KPRINT_DEBUG1("regs->m3_reg.m3_fw_exit = 0x%x\n", regs->m3_reg.m3_fw_exit); + KPRINT_DEBUG1("regs->m3_reg.m3_debug_cnt0 = 0x%x\n", regs->m3_reg.m3_debug_cnt0); + KPRINT_DEBUG1("regs->m3_reg.m3_debug_cnt1 = 0x%x\n", regs->m3_reg.m3_debug_cnt1); + KPRINT_DEBUG1("regs->m3_reg.m3_debug_cnt2 = 0x%x\n", regs->m3_reg.m3_debug_cnt2); + KPRINT_DEBUG1("regs->m3_reg.m3_debug_cnt3 = 0x%x\n", regs->m3_reg.m3_debug_cnt3); + KPRINT_DEBUG1("regs->m3_reg.m3_debug_cnt4 = 0x%x\n", regs->m3_reg.m3_debug_cnt4); + KPRINT_DEBUG1("regs->m3_reg.m3_debug_cnt5 = 0x%x\n", regs->m3_reg.m3_debug_cnt5); + KPRINT_DEBUG1("regs->m3_reg.m3_debug_cnt6 = 0x%x\n", regs->m3_reg.m3_debug_cnt6); + KPRINT_DEBUG1("regs->m3_reg.m3_debug_cnt7 = 0x%x\n", regs->m3_reg.m3_debug_cnt7); + KPRINT_DEBUG1("regs->m3_reg.m3_debug_cnt8 = 0x%x\n", regs->m3_reg.m3_debug_cnt8); + KPRINT_DEBUG1("regs->m3_reg.m3_debug_cnt9 = 0x%x\n", regs->m3_reg.m3_debug_cnt9); + KPRINT_DEBUG1("regs->m3_reg.m3_debug_cnt10 = 0x%x\n", regs->m3_reg.m3_debug_cnt10); + KPRINT_DEBUG1("regs->m3_reg.m3_watchdog_exp_cnt = 0x%x\n", regs->m3_reg.m3_watchdog_exp_cnt); + KPRINT_DEBUG1("regs->m3_reg.m3_watchdog_monitor_cnt = 0x%x\n", regs->m3_reg.m3_watchdog_monitor_cnt); + KPRINT_DEBUG1("regs->m3_reg.m3_debug_cnt13 = 0x%x\n", regs->m3_reg.m3_debug_cnt13); + KPRINT_DEBUG1("regs->m3_reg.m3_debug_cnt14 = 0x%x\n", regs->m3_reg.m3_debug_cnt14); + KPRINT_DEBUG1("regs->m3_reg.m3_systick_cnt_upper_value = 0x%x\n", regs->m3_reg.m3_systick_cnt_upper_value); + KPRINT_DEBUG1("regs->m3_reg.m3_systick_cnt_lower_value = 0x%x\n", regs->m3_reg.m3_systick_cnt_lower_value); + KPRINT_DEBUG1("regs->m3_reg.m3_tx_timeout_port0 = 0x%x\n", regs->m3_reg.m3_tx_timeout_port0); + KPRINT_DEBUG1("regs->m3_reg.m3_tx_timeout_port1 = 0x%x\n", regs->m3_reg.m3_tx_timeout_port1); + KPRINT_DEBUG1("regs->m3_reg.m3_debug_cnt19 = 0x%x\n", regs->m3_reg.m3_debug_cnt19); + /* FRP Table Dump */ - printk("regs->rxp_cfg->npe = %d\n", regs->rxp_cfg->npe); - printk("regs->rxp_cfg->nve = %d\n", regs->rxp_cfg->nve); + KPRINT_DEBUG1("regs->rxp_cfg->npe = %d\n", regs->rxp_cfg->npe); + KPRINT_DEBUG1("regs->rxp_cfg->nve = %d\n", regs->rxp_cfg->nve); for (index = 0; index <= (regs->rxp_cfg->nve); index++) { - printk("regs->rxp_cfg->entries[%d].match_data = 0x%x\n", index, regs->rxp_cfg->entries[index].match_data); - printk("regs->rxp_cfg->entries[%d].match_en = 0x%x\n", index, regs->rxp_cfg->entries[index].match_en); - printk("regs->rxp_cfg->entries[%d].af = 0x%x\n", index, regs->rxp_cfg->entries[index].af); - printk("regs->rxp_cfg->entries[%d].rf = 0x%x\n", index, regs->rxp_cfg->entries[index].rf); - printk("regs->rxp_cfg->entries[%d].im = 0x%x\n", index, regs->rxp_cfg->entries[index].im); - printk("regs->rxp_cfg->entries[%d].nc = 0x%x\n", index, regs->rxp_cfg->entries[index].nc); - printk("regs->rxp_cfg->entries[%d].frame_offset = 0x%x\n", index, regs->rxp_cfg->entries[index].frame_offset); - printk("regs->rxp_cfg->entries[%d].ok_index = 0x%x\n", index, regs->rxp_cfg->entries[index].ok_index); - printk("regs->rxp_cfg->entries[%d].dma_ch_no = 0x%x\n", index, regs->rxp_cfg->entries[index].dma_ch_no); + KPRINT_DEBUG1("regs->rxp_cfg->entries[%d].match_data = 0x%x\n", index, regs->rxp_cfg->entries[index].match_data); + KPRINT_DEBUG1("regs->rxp_cfg->entries[%d].match_en = 0x%x\n", index, regs->rxp_cfg->entries[index].match_en); + KPRINT_DEBUG1("regs->rxp_cfg->entries[%d].af = 0x%x\n", index, regs->rxp_cfg->entries[index].af); + KPRINT_DEBUG1("regs->rxp_cfg->entries[%d].rf = 0x%x\n", index, regs->rxp_cfg->entries[index].rf); + KPRINT_DEBUG1("regs->rxp_cfg->entries[%d].im = 0x%x\n", index, regs->rxp_cfg->entries[index].im); + KPRINT_DEBUG1("regs->rxp_cfg->entries[%d].nc = 0x%x\n", index, regs->rxp_cfg->entries[index].nc); + KPRINT_DEBUG1("regs->rxp_cfg->entries[%d].frame_offset = 0x%x\n", index, regs->rxp_cfg->entries[index].frame_offset); + KPRINT_DEBUG1("regs->rxp_cfg->entries[%d].ok_index = 0x%x\n", index, regs->rxp_cfg->entries[index].ok_index); + KPRINT_DEBUG1("regs->rxp_cfg->entries[%d].dma_ch_no = 0x%x\n", index, regs->rxp_cfg->entries[index].dma_ch_no); } /* TAMAP entries */ - for(index = 0; index <= MAX_CM3_TAMAP_ENTRIES; index++) { - printk("regs->tamap[%d].trsl_addr_hi = 0x%x\n", index, regs->tamap[index].trsl_addr_hi); - printk("regs->tamap[%d].trsl_addr_low = 0x%x\n", index, regs->tamap[index].trsl_addr_low); - printk("regs->tamap[%d].src_addr_hi = 0x%x\n", index, regs->tamap[index].src_addr_hi); - printk("regs->tamap[%d].src_addr_low = 0x%x\n", index, regs->tamap[index].src_addr_low); - printk("regs->tamap[%d].atr_size = 0x%x\n", index, regs->tamap[index].atr_size); - printk("regs->tamap[%d].atr_impl = 0x%x\n", index, regs->tamap[index].atr_impl); + for (index = 0; index <= MAX_CM3_TAMAP_ENTRIES; index++) { + KPRINT_DEBUG1("regs->tamap[%d].trsl_addr_hi = 0x%x\n", index, regs->tamap[index].trsl_addr_hi); + KPRINT_DEBUG1("regs->tamap[%d].trsl_addr_low = 0x%x\n", index, regs->tamap[index].trsl_addr_low); + KPRINT_DEBUG1("regs->tamap[%d].src_addr_hi = 0x%x\n", index, regs->tamap[index].src_addr_hi); + KPRINT_DEBUG1("regs->tamap[%d].src_addr_low = 0x%x\n", index, regs->tamap[index].src_addr_low); + KPRINT_DEBUG1("regs->tamap[%d].atr_size = 0x%x\n", index, regs->tamap[index].atr_size); + KPRINT_DEBUG1("regs->tamap[%d].atr_impl = 0x%x\n", index, regs->tamap[index].atr_impl); } - + /* Driver & FW Information */ - printk("regs->info.driver = %s\n", regs->info.driver); - printk("regs->info.version = %s\n", regs->info.version); - printk("regs->info.fw_version = %s\n", regs->info.fw_version); + KPRINT_DEBUG1("regs->info.driver = %s\n", regs->info.driver); + KPRINT_DEBUG1("regs->info.version = %s\n", regs->info.version); + KPRINT_DEBUG1("regs->info.fw_version = %s\n", regs->info.fw_version); /* statistics */ for (ch = 0; ch < tx_queues_cnt; ch++) { - printk("regs->stats.rx_buf_unav_irq[%d] = 0x%llx\n", ch, regs->stats.rx_buf_unav_irq[ch]); - printk("regs->stats.tx_pkt_n[%d] = 0x%llx\n", ch, regs->stats.tx_pkt_n[ch]); - printk("regs->stats.tx_pkt_errors_n[%d] = 0x%llx\n", ch, regs->stats.tx_pkt_errors_n[ch]); - printk("regs->stats.rx_pkt_n[%d] = 0x%llx\n", ch, regs->stats.rx_pkt_n[ch]); + KPRINT_DEBUG1("regs->stats.rx_buf_unav_irq[%d] = 0x%llx\n", ch, regs->stats.rx_buf_unav_irq[ch]); + KPRINT_DEBUG1("regs->stats.tx_pkt_n[%d] = 0x%llx\n", ch, regs->stats.tx_pkt_n[ch]); + KPRINT_DEBUG1("regs->stats.tx_pkt_errors_n[%d] = 0x%llx\n", ch, regs->stats.tx_pkt_errors_n[ch]); + KPRINT_DEBUG1("regs->stats.rx_pkt_n[%d] = 0x%llx\n", ch, regs->stats.rx_pkt_n[ch]); } - printk("regs->stats.mmc_tx_broadcastframe_g = 0x%llx\n", regs->stats.mmc_tx_broadcastframe_g); - printk("regs->stats.mmc_tx_multicastframe_g = 0x%llx\n", regs->stats.mmc_tx_multicastframe_g); - printk("regs->stats.mmc_tx_64_octets_gb = 0x%llx\n", regs->stats.mmc_tx_64_octets_gb); - printk("regs->stats.mmc_tx_framecount_gb = 0x%llx\n", regs->stats.mmc_tx_framecount_gb); - printk("regs->stats.mmc_tx_65_to_127_octets_gb = 0x%llx\n", regs->stats.mmc_tx_65_to_127_octets_gb); - printk("regs->stats.mmc_tx_128_to_255_octets_gb = 0x%llx\n", regs->stats.mmc_tx_128_to_255_octets_gb); - printk("regs->stats.mmc_tx_256_to_511_octets_gb = 0x%llx\n", regs->stats.mmc_tx_256_to_511_octets_gb); - printk("regs->stats.mmc_tx_512_to_1023_octets_gb = 0x%llx\n", regs->stats.mmc_tx_512_to_1023_octets_gb); - printk("regs->stats.mmc_tx_1024_to_max_octets_gb = 0x%llx\n", regs->stats.mmc_tx_1024_to_max_octets_gb); - printk("regs->stats.mmc_tx_unicast_gb = 0x%llx\n", regs->stats.mmc_tx_unicast_gb); - printk("regs->stats.mmc_tx_underflow_error = 0x%llx\n", regs->stats.mmc_tx_underflow_error); - printk("regs->stats.mmc_tx_framecount_g = 0x%llx\n", regs->stats.mmc_tx_framecount_g); - printk("regs->stats.mmc_tx_pause_frame = 0x%llx\n", regs->stats.mmc_tx_pause_frame); - printk("regs->stats.mmc_tx_vlan_frame_g = 0x%llx\n", regs->stats.mmc_tx_vlan_frame_g); - printk("regs->stats.mmc_tx_lpi_us_cntr = 0x%llx\n", regs->stats.mmc_tx_lpi_us_cntr); - printk("regs->stats.mmc_tx_lpi_tran_cntr = 0x%llx\n", regs->stats.mmc_tx_lpi_tran_cntr); + KPRINT_DEBUG1("regs->stats.mmc_tx_broadcastframe_g = 0x%llx\n", regs->stats.mmc_tx_broadcastframe_g); + KPRINT_DEBUG1("regs->stats.mmc_tx_multicastframe_g = 0x%llx\n", regs->stats.mmc_tx_multicastframe_g); + KPRINT_DEBUG1("regs->stats.mmc_tx_64_octets_gb = 0x%llx\n", regs->stats.mmc_tx_64_octets_gb); + KPRINT_DEBUG1("regs->stats.mmc_tx_framecount_gb = 0x%llx\n", regs->stats.mmc_tx_framecount_gb); + KPRINT_DEBUG1("regs->stats.mmc_tx_65_to_127_octets_gb = 0x%llx\n", regs->stats.mmc_tx_65_to_127_octets_gb); + KPRINT_DEBUG1("regs->stats.mmc_tx_128_to_255_octets_gb = 0x%llx\n", regs->stats.mmc_tx_128_to_255_octets_gb); + KPRINT_DEBUG1("regs->stats.mmc_tx_256_to_511_octets_gb = 0x%llx\n", regs->stats.mmc_tx_256_to_511_octets_gb); + KPRINT_DEBUG1("regs->stats.mmc_tx_512_to_1023_octets_gb = 0x%llx\n", regs->stats.mmc_tx_512_to_1023_octets_gb); + KPRINT_DEBUG1("regs->stats.mmc_tx_1024_to_max_octets_gb = 0x%llx\n", regs->stats.mmc_tx_1024_to_max_octets_gb); + KPRINT_DEBUG1("regs->stats.mmc_tx_unicast_gb = 0x%llx\n", regs->stats.mmc_tx_unicast_gb); + KPRINT_DEBUG1("regs->stats.mmc_tx_underflow_error = 0x%llx\n", regs->stats.mmc_tx_underflow_error); + KPRINT_DEBUG1("regs->stats.mmc_tx_framecount_g = 0x%llx\n", regs->stats.mmc_tx_framecount_g); + KPRINT_DEBUG1("regs->stats.mmc_tx_pause_frame = 0x%llx\n", regs->stats.mmc_tx_pause_frame); + KPRINT_DEBUG1("regs->stats.mmc_tx_vlan_frame_g = 0x%llx\n", regs->stats.mmc_tx_vlan_frame_g); + KPRINT_DEBUG1("regs->stats.mmc_tx_lpi_us_cntr = 0x%llx\n", regs->stats.mmc_tx_lpi_us_cntr); + KPRINT_DEBUG1("regs->stats.mmc_tx_lpi_tran_cntr = 0x%llx\n", regs->stats.mmc_tx_lpi_tran_cntr); - printk("regs->stats.mmc_rx_framecount_gb = 0x%llx\n", regs->stats.mmc_rx_framecount_gb); - printk("regs->stats.mmc_rx_broadcastframe_g = 0x%llx\n", regs->stats.mmc_rx_broadcastframe_g); - printk("regs->stats.mmc_rx_multicastframe_g = 0x%llx\n", regs->stats.mmc_rx_multicastframe_g); - printk("regs->stats.mmc_rx_crc_error = 0x%llx\n", regs->stats.mmc_rx_crc_error); - printk("regs->stats.mmc_rx_jabber_error = 0x%llx\n", regs->stats.mmc_rx_jabber_error); - printk("regs->stats.mmc_rx_undersize_g = 0x%llx\n", regs->stats.mmc_rx_undersize_g); - printk("regs->stats.mmc_rx_oversize_g = 0x%llx\n", regs->stats.mmc_rx_oversize_g); - printk("regs->stats.mmc_rx_64_octets_gb = 0x%llx\n", regs->stats.mmc_rx_64_octets_gb); - printk("regs->stats.mmc_rx_65_to_127_octets_gb = 0x%llx\n", regs->stats.mmc_rx_65_to_127_octets_gb); - printk("regs->stats.mmc_rx_128_to_255_octets_gb = 0x%llx\n", regs->stats.mmc_rx_128_to_255_octets_gb); - printk("regs->stats.mmc_rx_256_to_511_octets_gb = 0x%llx\n", regs->stats.mmc_rx_256_to_511_octets_gb); - printk("regs->stats.mmc_rx_512_to_1023_octets_gb = 0x%llx\n", regs->stats.mmc_rx_512_to_1023_octets_gb); - printk("regs->stats.mmc_rx_1024_to_max_octets_gb = 0x%llx\n", regs->stats.mmc_rx_1024_to_max_octets_gb); - printk("regs->stats.mmc_rx_unicast_g = 0x%llx\n", regs->stats.mmc_rx_unicast_g); - printk("regs->stats.mmc_rx_length_error = 0x%llx\n", regs->stats.mmc_rx_length_error); - printk("regs->stats.mmc_rx_pause_frames = 0x%llx\n", regs->stats.mmc_rx_pause_frames); - printk("regs->stats.mmc_rx_fifo_overflow = 0x%llx\n", regs->stats.mmc_rx_fifo_overflow); - printk("regs->stats.mmc_rx_lpi_us_cntr = 0x%llx\n", regs->stats.mmc_rx_lpi_us_cntr); - printk("regs->stats.mmc_rx_lpi_tran_cntr = 0x%llx\n", regs->stats.mmc_rx_lpi_tran_cntr); + KPRINT_DEBUG1("regs->stats.mmc_rx_framecount_gb = 0x%llx\n", regs->stats.mmc_rx_framecount_gb); + KPRINT_DEBUG1("regs->stats.mmc_rx_broadcastframe_g = 0x%llx\n", regs->stats.mmc_rx_broadcastframe_g); + KPRINT_DEBUG1("regs->stats.mmc_rx_multicastframe_g = 0x%llx\n", regs->stats.mmc_rx_multicastframe_g); + KPRINT_DEBUG1("regs->stats.mmc_rx_crc_error = 0x%llx\n", regs->stats.mmc_rx_crc_error); + KPRINT_DEBUG1("regs->stats.mmc_rx_jabber_error = 0x%llx\n", regs->stats.mmc_rx_jabber_error); + KPRINT_DEBUG1("regs->stats.mmc_rx_undersize_g = 0x%llx\n", regs->stats.mmc_rx_undersize_g); + KPRINT_DEBUG1("regs->stats.mmc_rx_oversize_g = 0x%llx\n", regs->stats.mmc_rx_oversize_g); + KPRINT_DEBUG1("regs->stats.mmc_rx_64_octets_gb = 0x%llx\n", regs->stats.mmc_rx_64_octets_gb); + KPRINT_DEBUG1("regs->stats.mmc_rx_65_to_127_octets_gb = 0x%llx\n", regs->stats.mmc_rx_65_to_127_octets_gb); + KPRINT_DEBUG1("regs->stats.mmc_rx_128_to_255_octets_gb = 0x%llx\n", regs->stats.mmc_rx_128_to_255_octets_gb); + KPRINT_DEBUG1("regs->stats.mmc_rx_256_to_511_octets_gb = 0x%llx\n", regs->stats.mmc_rx_256_to_511_octets_gb); + KPRINT_DEBUG1("regs->stats.mmc_rx_512_to_1023_octets_gb = 0x%llx\n", regs->stats.mmc_rx_512_to_1023_octets_gb); + KPRINT_DEBUG1("regs->stats.mmc_rx_1024_to_max_octets_gb = 0x%llx\n", regs->stats.mmc_rx_1024_to_max_octets_gb); + KPRINT_DEBUG1("regs->stats.mmc_rx_unicast_g = 0x%llx\n", regs->stats.mmc_rx_unicast_g); + KPRINT_DEBUG1("regs->stats.mmc_rx_length_error = 0x%llx\n", regs->stats.mmc_rx_length_error); + KPRINT_DEBUG1("regs->stats.mmc_rx_pause_frames = 0x%llx\n", regs->stats.mmc_rx_pause_frames); + KPRINT_DEBUG1("regs->stats.mmc_rx_fifo_overflow = 0x%llx\n", regs->stats.mmc_rx_fifo_overflow); + KPRINT_DEBUG1("regs->stats.mmc_rx_lpi_us_cntr = 0x%llx\n", regs->stats.mmc_rx_lpi_us_cntr); + KPRINT_DEBUG1("regs->stats.mmc_rx_lpi_tran_cntr = 0x%llx\n", regs->stats.mmc_rx_lpi_tran_cntr); return 0; } +extern unsigned int mac0_force_speed_mode; +extern unsigned int mac1_force_speed_mode; + static DEFINE_SPINLOCK(reg_dump_lock); static void dump_all_reg(struct tc956xmac_priv *priv) { @@ -1164,25 +1247,25 @@ static ssize_t read_tc956x_dma_status(struct file *file, for (ch = 0; ch < tx_queues_cnt; ch++) { tx_q = &priv->tx_queue[ch]; - printk("dma_reg.tx_queue[%d].desc_phy_addr = 0x%x \n", ch, tx_q->dma_tx_phy); - printk("dma_reg.tx_queue[%d].desc_va_addr = 0x%x \n", ch, (u32)tx_q->dma_tx); - #ifdef DMA_OFFLOAD_ENABLE - printk("dma_reg.tx_queue[%d].buff_phy_addr = 0x%x \n", ch, tx_q->buff_tx_phy); - printk("dma_reg.tx_queue[%d].buff_va_addr = 0x%x \n", ch, (u32)tx_q->buffer_tx_va_addr); + printk("dma_reg.tx_queue[%d].desc_phy_addr = 0x%lx \n", ch, (unsigned long)tx_q->dma_tx_phy); + printk("dma_reg.tx_queue[%d].desc_va_addr = 0x%lx \n", ch, (unsigned long)tx_q->dma_tx); + #ifdef TC956X_DMA_OFFLOAD_ENABLE + printk("dma_reg.tx_queue[%d].buff_phy_addr = 0x%lx \n", ch, (unsigned long)tx_q->buff_tx_phy); + printk("dma_reg.tx_queue[%d].buff_va_addr = 0x%lx \n", ch, (unsigned long)tx_q->buffer_tx_va_addr); #endif - printk("dma_reg.tx_queue[%d].tx_skbuff = 0x%x \n", ch, (u32)tx_q->tx_skbuff); - printk("dma_reg.tx_queue[%d].tx_skbuff_dma = 0x%x \n", ch, (u32)tx_q->tx_skbuff_dma); + printk("dma_reg.tx_queue[%d].tx_skbuff = 0x%lx \n", ch, (unsigned long)tx_q->tx_skbuff); + printk("dma_reg.tx_queue[%d].tx_skbuff_dma = 0x%lx \n", ch, (unsigned long)tx_q->tx_skbuff_dma); } for (ch = 0; ch < rx_queues_cnt; ch++) { rx_q = &priv->rx_queue[ch]; - printk("dma_reg.rx_queue[%d].desc_phy_addr = 0x%x \n", ch, rx_q->dma_rx_phy); - printk("dma_reg.rx_queue[%d].desc_va_addr = 0x%x \n", ch, (u32)rx_q->dma_rx); - #ifdef DMA_OFFLOAD_ENABLE - printk("dma_reg.rx_queue[%d].buff_phy_addr = 0x%x \n", ch, rx_q->buff_rx_phy); - printk("dma_reg.rx_queue[%d].buff_va_addr = 0x%x \n", ch, (u32)(void *)rx_q->buffer_rx_va_addr); + printk("dma_reg.rx_queue[%d].desc_phy_addr = 0x%lx \n", ch, (unsigned long)rx_q->dma_rx_phy); + printk("dma_reg.rx_queue[%d].desc_va_addr = 0x%lx \n", ch, (unsigned long)rx_q->dma_rx); + #ifdef TC956X_DMA_OFFLOAD_ENABLE + printk("dma_reg.rx_queue[%d].buff_phy_addr = 0x%lx \n", ch, (unsigned long)rx_q->buff_rx_phy); + printk("dma_reg.rx_queue[%d].buff_va_addr = 0x%lx \n", ch, (unsigned long)(void *)rx_q->buffer_rx_va_addr); #endif - printk("dma_reg.rx_queue[%d].buf_pool = 0x%x \n", ch, (u32)rx_q->buf_pool); + printk("dma_reg.rx_queue[%d].buf_pool = 0x%lx \n", ch, (unsigned long)rx_q->buf_pool); } return 0; @@ -1195,7 +1278,6 @@ static const struct file_operations fops_dma_stats = { .llseek = default_llseek, }; - /** * read_tc956x_status() - Debugfs read command for interrupt status info * @@ -1214,21 +1296,21 @@ static ssize_t read_tc956x_intr_status(struct file *file, printk("pcie_reg.rsc_mng_id = 0x%x \n",readl(priv->tc956x_BRIDGE_CFG_pci_base_addr + RSCMNG_ID_REG)); /* MSI register dump */ - printk("msi_reg.msi_out_en = 0x%x \n", readl(priv->ioaddr + TC956X_MSI_OUT_EN_OFFSET(priv->port_num))); - printk("msi_reg.msi_mask_set = 0x%x \n", readl(priv->ioaddr + TC956X_MSI_MASK_SET_OFFSET(priv->port_num))); - printk("msi_reg.msi_mask_clr = 0x%x \n", readl(priv->ioaddr + TC956X_MSI_MASK_CLR_OFFSET(priv->port_num))); - printk("msi_reg.int_sts = 0x%x \n", readl(priv->ioaddr + TC956X_MSI_INT_STS_OFFSET(priv->port_num))); - printk("msi_reg.int_raw_sts = 0x%x \n", readl(priv->ioaddr + TC956X_MSI_INT_RAW_STS_OFFSET(priv->port_num))); - printk("msi_reg.msi_sts = 0x%x \n", readl(priv->ioaddr + TC956X_MSI_STS_OFFSET(priv->port_num))); - printk("msi_reg.cnt_int0 = 0x%x \n", readl(priv->ioaddr + TC956X_MSI_CNT0(priv->port_num))); - printk("msi_reg.cnt_int1 = 0x%x \n", readl(priv->ioaddr + TC956X_MSI_CNT1(priv->port_num))); - printk("msi_reg.cnt_int2 = 0x%x \n", readl(priv->ioaddr + TC956X_MSI_CNT2(priv->port_num))); - printk("msi_reg.cnt_int3 = 0x%x \n", readl(priv->ioaddr + TC956X_MSI_CNT3(priv->port_num))); - printk("msi_reg.cnt_int4 = 0x%x \n", readl(priv->ioaddr + TC956X_MSI_CNT4(priv->port_num))); - printk("msi_reg.cnt_int11 = 0x%x \n", readl(priv->ioaddr + TC956X_MSI_CNT11(priv->port_num))); - printk("msi_reg.cnt_int12 = 0x%x \n", readl(priv->ioaddr + TC956X_MSI_CNT12(priv->port_num))); - printk("msi_reg.cnt_int20 = 0x%x \n", readl(priv->ioaddr + TC956X_MSI_CNT20(priv->port_num))); - printk("msi_reg.cnt_int24 = 0x%x \n", readl(priv->ioaddr + TC956X_MSI_CNT24(priv->port_num))); + printk("msi_reg.msi_out_en = 0x%x \n", readl(priv->ioaddr + TC956X_MSI_OUT_EN_OFFSET(priv->port_num, 0))); + printk("msi_reg.msi_mask_set = 0x%x \n", readl(priv->ioaddr + TC956X_MSI_MASK_SET_OFFSET(priv->port_num, 0))); + printk("msi_reg.msi_mask_clr = 0x%x \n", readl(priv->ioaddr + TC956X_MSI_MASK_CLR_OFFSET(priv->port_num, 0))); + printk("msi_reg.int_sts = 0x%x \n", readl(priv->ioaddr + TC956X_MSI_INT_STS_OFFSET(priv->port_num, 0))); + printk("msi_reg.int_raw_sts = 0x%x \n", readl(priv->ioaddr + TC956X_MSI_INT_RAW_STS_OFFSET(priv->port_num, 0))); + printk("msi_reg.msi_sts = 0x%x \n", readl(priv->ioaddr + TC956X_MSI_STS_OFFSET(priv->port_num, 0))); + printk("msi_reg.cnt_int0 = 0x%x \n", readl(priv->ioaddr + TC956X_MSI_CNT0(priv->port_num, 0))); + printk("msi_reg.cnt_int1 = 0x%x \n", readl(priv->ioaddr + TC956X_MSI_CNT1(priv->port_num, 0))); + printk("msi_reg.cnt_int2 = 0x%x \n", readl(priv->ioaddr + TC956X_MSI_CNT2(priv->port_num, 0))); + printk("msi_reg.cnt_int3 = 0x%x \n", readl(priv->ioaddr + TC956X_MSI_CNT3(priv->port_num, 0))); + printk("msi_reg.cnt_int4 = 0x%x \n", readl(priv->ioaddr + TC956X_MSI_CNT4(priv->port_num, 0))); + printk("msi_reg.cnt_int11 = 0x%x \n", readl(priv->ioaddr + TC956X_MSI_CNT11(priv->port_num, 0))); + printk("msi_reg.cnt_int12 = 0x%x \n", readl(priv->ioaddr + TC956X_MSI_CNT12(priv->port_num, 0))); + printk("msi_reg.cnt_int20 = 0x%x \n", readl(priv->ioaddr + TC956X_MSI_CNT20(priv->port_num, 0))); + printk("msi_reg.cnt_int24 = 0x%x \n", readl(priv->ioaddr + TC956X_MSI_CNT24(priv->port_num, 0))); /* INTC register dump */ printk("intc_reg.intmcumask0 = 0x%x \n", readl(priv->ioaddr + INTMCUMASK0)); @@ -1408,7 +1490,6 @@ static const struct file_operations fops_other_stats = { .llseek = default_llseek, }; - /** * read_tc956x_status() - Debugfs read command for dumping all registers of MAC, MTL, DMA... * @@ -1434,7 +1515,6 @@ static const struct file_operations fops_reg_dump_stats = { .llseek = default_llseek, }; - /** * tc956xmac_create_debugfs() - API to create debugfs node * for debugging. @@ -1583,7 +1663,7 @@ int tc956x_GPIO_OutputConfigPin(struct tc956xmac_priv *priv, u32 gpio_pin, u8 ou { u32 config, val; - /* Only GPIO0- GPIO06, GPI010-GPIO12 are allowed */ + /* Only GPIO0- GPIO06, GPI010-GPIO12 are allowed */ switch (gpio_pin) { case GPIO_00: val = readl(priv->ioaddr + NFUNCEN4_OFFSET); @@ -1645,7 +1725,7 @@ int tc956x_GPIO_OutputConfigPin(struct tc956xmac_priv *priv, u32 gpio_pin, u8 ou val |= (NFUNCEN_FUNC0 << NFUNCEN6_GPIO_12_SHIFT); writel(val, priv->ioaddr + NFUNCEN6_OFFSET); break; - default : + default: netdev_err(priv->dev, "Invalid GPIO pin - %d\n", gpio_pin); return -EPERM; } @@ -1653,11 +1733,11 @@ int tc956x_GPIO_OutputConfigPin(struct tc956xmac_priv *priv, u32 gpio_pin, u8 ou priv->saved_gpio_config[gpio_pin].config = 1; /* Write data to GPIO pin */ - if(gpio_pin < GPIO_32) { - config = 1 << gpio_pin; + if (gpio_pin < GPIO_32) { + config = 1 << gpio_pin; val = readl(priv->ioaddr + GPIOO0_OFFSET); val &= ~config; - if(out_value) + if (out_value) val |= config; writel(val, priv->ioaddr + GPIOO0_OFFSET); @@ -1665,7 +1745,7 @@ int tc956x_GPIO_OutputConfigPin(struct tc956xmac_priv *priv, u32 gpio_pin, u8 ou config = 1 << (gpio_pin - GPIO_32); val = readl(priv->ioaddr + GPIOO1_OFFSET); val &= ~config; - if(out_value) + if (out_value) val |= config; writel(val, priv->ioaddr + GPIOO1_OFFSET); @@ -1674,12 +1754,12 @@ int tc956x_GPIO_OutputConfigPin(struct tc956xmac_priv *priv, u32 gpio_pin, u8 ou priv->saved_gpio_config[gpio_pin].out_val = out_value; /* Configure the GPIO pin in output direction */ - if(gpio_pin < GPIO_32) { - config = ~(1 << gpio_pin) ; + if (gpio_pin < GPIO_32) { + config = ~(1 << gpio_pin); val = readl(priv->ioaddr + GPIOE0_OFFSET); writel(val & config, priv->ioaddr + GPIOE0_OFFSET); } else { - config = ~(1 << (gpio_pin - GPIO_32)) ; + config = ~(1 << (gpio_pin - GPIO_32)); val = readl(priv->ioaddr + GPIOE1_OFFSET); writel(val & config, priv->ioaddr + GPIOE1_OFFSET); } @@ -1769,7 +1849,7 @@ int tc956x_gpio_restore_configuration(struct tc956xmac_priv *priv) val |= (NFUNCEN_FUNC0 << NFUNCEN6_GPIO_12_SHIFT); writel(val, priv->ioaddr + NFUNCEN6_OFFSET); break; - default : + default : netdev_err(priv->dev, "Invalid GPIO pin - %d\n", gpio_pin); return -EPERM; } @@ -1778,7 +1858,7 @@ int tc956x_gpio_restore_configuration(struct tc956xmac_priv *priv) /* Write data to GPIO pin */ if(gpio_pin < GPIO_32) { - config = 1 << gpio_pin; + config = 1 << gpio_pin; val = readl(priv->ioaddr + GPIOO0_OFFSET); val &= ~config; if(out_value) @@ -1809,6 +1889,7 @@ int tc956x_gpio_restore_configuration(struct tc956xmac_priv *priv) return 0; } +#ifdef TC956X_SRIOV_PF /** * tc956xmac_wol_interrupt - ISR to handle WoL PHY interrupt * @irq: interrupt number. @@ -1825,6 +1906,7 @@ static irqreturn_t tc956xmac_wol_interrupt(int irq, void *dev_id) priv->tc956xmac_pm_wol_interrupt = true; return IRQ_HANDLED; } +#endif /** * tc956xmac_verify_args - verify the driver parameters. @@ -1847,6 +1929,79 @@ static void tc956xmac_verify_args(void) eee_timer = TC956XMAC_DEFAULT_LPI_TIMER; } +#ifdef TC956X_SRIOV_PF +#ifdef TC956X_DYNAMIC_LOAD_CBS +static void tc956xmac_set_cbs_speed(struct tc956xmac_priv *priv) +{ + u32 queue_idx; +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + unsigned long flags; +#endif + for (queue_idx = CLASS_B_CH ; queue_idx <= CLASS_CDT_CH; queue_idx++) { + if (priv->plat->tx_queues_cfg[queue_idx].mode_to_use == MTL_QUEUE_AVB) + { + if (priv->speed == SPEED_100) { + priv->plat->tx_queues_cfg[queue_idx].send_slope = + priv->cbs_speed100_cfg[queue_idx].send_slope; + priv->plat->tx_queues_cfg[queue_idx].idle_slope = + priv->cbs_speed100_cfg[queue_idx].idle_slope; + priv->plat->tx_queues_cfg[queue_idx].high_credit = + priv->cbs_speed100_cfg[queue_idx].high_credit; + priv->plat->tx_queues_cfg[queue_idx].low_credit = + priv->cbs_speed100_cfg[queue_idx].low_credit; + } else if (priv->speed == SPEED_1000) { + priv->plat->tx_queues_cfg[queue_idx].send_slope = + priv->cbs_speed1000_cfg[queue_idx].send_slope; + priv->plat->tx_queues_cfg[queue_idx].idle_slope = + priv->cbs_speed1000_cfg[queue_idx].idle_slope; + priv->plat->tx_queues_cfg[queue_idx].high_credit = + priv->cbs_speed1000_cfg[queue_idx].high_credit; + priv->plat->tx_queues_cfg[queue_idx].low_credit = + priv->cbs_speed1000_cfg[queue_idx].low_credit; + } else if (priv->speed == SPEED_10000) { + priv->plat->tx_queues_cfg[queue_idx].send_slope = + priv->cbs_speed10000_cfg[queue_idx].send_slope; + priv->plat->tx_queues_cfg[queue_idx].idle_slope = + priv->cbs_speed10000_cfg[queue_idx].idle_slope; + priv->plat->tx_queues_cfg[queue_idx].high_credit = + priv->cbs_speed10000_cfg[queue_idx].high_credit; + priv->plat->tx_queues_cfg[queue_idx].low_credit = + priv->cbs_speed10000_cfg[queue_idx].low_credit; + } else if (priv->speed == SPEED_2500) { + priv->plat->tx_queues_cfg[queue_idx].send_slope = + priv->cbs_speed2500_cfg[queue_idx].send_slope; + priv->plat->tx_queues_cfg[queue_idx].idle_slope = + priv->cbs_speed2500_cfg[queue_idx].idle_slope; + priv->plat->tx_queues_cfg[queue_idx].high_credit = + priv->cbs_speed2500_cfg[queue_idx].high_credit; + priv->plat->tx_queues_cfg[queue_idx].low_credit = + priv->cbs_speed2500_cfg[queue_idx].low_credit; + } else if (priv->speed == SPEED_5000) { + priv->plat->tx_queues_cfg[queue_idx].send_slope = + priv->cbs_speed5000_cfg[queue_idx].send_slope; + priv->plat->tx_queues_cfg[queue_idx].idle_slope = + priv->cbs_speed5000_cfg[queue_idx].idle_slope; + priv->plat->tx_queues_cfg[queue_idx].high_credit = + priv->cbs_speed5000_cfg[queue_idx].high_credit; + priv->plat->tx_queues_cfg[queue_idx].low_credit = + priv->cbs_speed5000_cfg[queue_idx].low_credit; + } +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_lock_irqsave(&priv->spn_lock.cbs, flags); +#endif + tc956xmac_config_cbs(priv, priv->hw, priv->plat->tx_queues_cfg[queue_idx].send_slope, + priv->plat->tx_queues_cfg[queue_idx].idle_slope, + priv->plat->tx_queues_cfg[queue_idx].high_credit, + priv->plat->tx_queues_cfg[queue_idx].low_credit, + queue_idx); +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_unlock_irqrestore(&priv->spn_lock.cbs, flags); +#endif + } + } +} +#endif /* DYNAMIC_LOAD_CBS */ +#endif /** * tc956xmac_disable_all_queues - Disable all queues * @priv: driver private structure @@ -1863,11 +2018,31 @@ static void tc956xmac_disable_all_queues(struct tc956xmac_priv *priv) for (queue = 0; queue < maxq; queue++) { struct tc956xmac_channel *ch = &priv->channel[queue]; +#ifdef TC956X_SRIOV_PF + if (priv->plat->rx_ch_in_use[queue] == TC956X_DISABLE_CHNL) + continue; +#elif defined TC956X_SRIOV_VF + /* skip configuring for unallocated channel */ + if (priv->plat->ch_in_use[queue] == 0) + continue; + if (queue < rx_queues_cnt) +#else if (queue < rx_queues_cnt && priv->plat->rx_dma_ch_owner[queue] == USE_IN_TC956X_SW) +#endif napi_disable(&ch->rx_napi); +#ifdef TC956X_SRIOV_PF + if (priv->plat->tx_ch_in_use[queue] == TC956X_DISABLE_CHNL) + continue; +#elif defined TC956X_SRIOV_VF + /* skip configuring for unallocated channel */ + if (priv->plat->ch_in_use[queue] == 0) + continue; + if (queue < tx_queues_cnt) +#else if (queue < tx_queues_cnt && priv->plat->tx_dma_ch_owner[queue] == USE_IN_TC956X_SW) +#endif napi_disable(&ch->tx_napi); } } @@ -1889,10 +2064,39 @@ static void tc956xmac_enable_all_queues(struct tc956xmac_priv *priv) for (queue = 0; queue < maxq; queue++) { struct tc956xmac_channel *ch = &priv->channel[queue]; - if (queue < rx_queues_cnt && priv->plat->rx_dma_ch_owner[queue] == USE_IN_TC956X_SW) +#ifdef TC956X_SRIOV_PF + if (queue < rx_queues_cnt) { + + if (priv->plat->rx_ch_in_use[queue] == + TC956X_DISABLE_CHNL) + continue; +#elif defined TC956X_SRIOV_VF + /* skip configuring for unallocated channel */ + if (priv->plat->ch_in_use[queue] == 0) + continue; + + if (queue < rx_queues_cnt) { +#else + if (queue < rx_queues_cnt && priv->plat->rx_dma_ch_owner[queue] == USE_IN_TC956X_SW) { +#endif napi_enable(&ch->rx_napi); - if (queue < tx_queues_cnt && priv->plat->tx_dma_ch_owner[queue] == USE_IN_TC956X_SW) + } +#ifdef TC956X_SRIOV_PF + if (queue < tx_queues_cnt) { + if (priv->plat->tx_ch_in_use[queue] == + TC956X_DISABLE_CHNL) + continue; +#elif defined TC956X_SRIOV_VF + /* skip configuring for unallocated channel */ + if (priv->plat->ch_in_use[queue] == 0) + continue; + + if (queue < tx_queues_cnt) { +#else + if (queue < tx_queues_cnt && priv->plat->tx_dma_ch_owner[queue] == USE_IN_TC956X_SW) { +#endif napi_enable(&ch->tx_napi); + } } } @@ -1906,9 +2110,17 @@ static void tc956xmac_stop_all_queues(struct tc956xmac_priv *priv) u32 queue; for (queue = 0; queue < tx_queues_cnt; queue++) { +#ifdef TC956X_SRIOV_PF + if (priv->plat->tx_ch_in_use[queue] == TC956X_DISABLE_CHNL) + continue; +#elif defined TC956X_SRIOV_VF + /* skip configuring for unallocated channel */ + if (priv->plat->ch_in_use[queue] == 0) + continue; +#else if (priv->plat->tx_dma_ch_owner[queue] != USE_IN_TC956X_SW) continue; - +#endif netif_tx_stop_queue(netdev_get_tx_queue(priv->dev, queue)); } } @@ -1923,9 +2135,17 @@ static void tc956xmac_start_all_queues(struct tc956xmac_priv *priv) u32 queue; for (queue = 0; queue < tx_queues_cnt; queue++) { +#ifdef TC956X_SRIOV_PF + if (priv->plat->tx_ch_in_use[queue] == TC956X_DISABLE_CHNL) + continue; +#elif defined TC956X_SRIOV_VF + /* skip configuring for unallocated channel */ + if (priv->plat->ch_in_use[queue] == 0) + continue; +#else if (priv->plat->tx_dma_ch_owner[queue] != USE_IN_TC956X_SW) continue; - +#endif netif_tx_start_queue(netdev_get_tx_queue(priv->dev, queue)); } } @@ -1939,8 +2159,35 @@ static void tc956xmac_service_event_schedule(struct tc956xmac_priv *priv) } #endif +#if defined(TC956X_SRIOV_PF) && !defined(TC956X_AUTOMOTIVE_CONFIG) && !defined(TC956X_ENABLE_MAC2MAC_BRIDGE) +/** + * tc956xmac_service_mbx_event_schedule - Schedule work queue + * @priv: driver private structure + */ +void tc956xmac_service_mbx_event_schedule(struct tc956xmac_priv *priv) +{ + if (!test_bit(TC956XMAC_DOWN, &priv->state) && + !test_and_set_bit(TC956XMAC_SERVICE_SCHED, &priv->state)) + queue_work(priv->mbx_wq, &priv->service_mbx_task); +} +#endif +#ifdef TC956X_SRIOV_VF +/** + * tc956xmac_mailbox_service_event_schedule - Schedule work queue + * @priv: driver private structure + */ +void tc956xmac_mailbox_service_event_schedule(struct tc956xmac_priv *priv) +{ + if (!test_bit(TC956XMAC_DOWN, &priv->state) && + !test_and_set_bit(TC956XMAC_SERVICE_SCHED, &priv->state)) + queue_work(priv->mbx_wq, &priv->mbx_service_task); +} +#endif static void tc956xmac_global_err(struct tc956xmac_priv *priv) { +#ifdef TC956X_SRIOV_VF + netdev_alert(priv->dev, "%s PF %d VF %d disabling carrier\n", __func__, priv->fn_id_info.pf_no, priv->fn_id_info.vf_no); +#endif netif_carrier_off(priv->dev); set_bit(TC956XMAC_RESET_REQUESTED, &priv->state); #ifdef TC956X_UNSUPPORTED_UNTESTED @@ -1949,6 +2196,7 @@ static void tc956xmac_global_err(struct tc956xmac_priv *priv) } #ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE +#ifndef TC956X_SRIOV_VF /** * tc956xmac_clk_csr_set - dynamically set the MDC clock * @priv: driver private structure @@ -2015,6 +2263,7 @@ static void tc956xmac_clk_csr_set(struct tc956xmac_priv *priv) priv->clk_csr = 0x0; } } +#endif /* TC956X_SRIOV_VF */ #endif /* TC956X_UNSUPPORTED_UNTESTED_FEATURE */ static void print_pkt(unsigned char *buf, int len) { @@ -2061,8 +2310,10 @@ static inline u32 tc956xmac_rx_dirty(struct tc956xmac_priv *priv, u32 queue) */ static void tc956xmac_enable_eee_mode(struct tc956xmac_priv *priv) { +#ifdef TC956X_SRIOV_PF tc956xmac_set_eee_mode(priv, priv->hw, priv->plat->en_tx_lpi_clockgating); +#endif } /** @@ -2112,7 +2363,7 @@ bool tc956xmac_eee_init(struct tc956xmac_priv *priv) value = readl(priv->ioaddr + XGMAC_LPI_Auto_Entry_Timer); /* Setting LPIET bit [19...3] */ value &= ~(XGMAC_LPIET); - /* LPI Entry timer is in the units of 8 micro second granularity considering last reserved 2:0 bits as zero + /* LPI Entry timer is in the units of 8 micro second granularity considering last reserved 2:0 bits as zero * So mask the last 3 bits */ value |= (priv->tx_lpi_timer & XGMAC_LPIET); @@ -2139,14 +2390,13 @@ static void tc956xmac_get_tx_hwtstamp(struct tc956xmac_priv *priv, bool found = false; u64 ns = 0; #if defined(TX_LOGGING_TRACE) - static unsigned int ccnt1 = 0, ccnt2 = 0, ccnt3 = 0; - static unsigned int ccnt4 = 0, ccnt5 = 0, ccnt6 = 0; + static unsigned int ccnt1, ccnt2, ccnt3; u32 qno = skb_get_queue_mapping(skb); #endif #ifdef PKT_RATE_DBG - static unsigned int count = 0; - static u64 prev_ns = 0; + static unsigned int count; + static u64 prev_ns; u64 rate; #endif @@ -2190,11 +2440,14 @@ static void tc956xmac_get_tx_hwtstamp(struct tc956xmac_priv *priv, #endif #ifdef FPE - priv->mmc.mmc_tx_fpe_fragments += readl(priv->mmcaddr + MMC_TX_FPE_FRAG); + priv->mmc.mmc_tx_fpe_fragment_cntr += readl(priv->mmcaddr + MMC_XGMAC_TX_FPE_FRAG); #endif - +#ifdef TC956X_SRIOV_VF + if ((qno == priv->plat->avb_class_a_ch_no) + && (priv->plat->best_effort_ch_no != priv->plat->avb_class_a_ch_no)) {/* For AVB */ +#else if (qno == AVB_CLASS_A_TX_CH) {/* For AVB */ - +#endif if (skb->data[20] == 0) ccnt1++; @@ -2205,16 +2458,24 @@ static void tc956xmac_get_tx_hwtstamp(struct tc956xmac_priv *priv, trace_printk("[AVB]TS,%llu,%d,%03d,%02d, ,\n", ns, ccnt1, skb->data[20], qno); #endif - +#ifdef TC956X_SRIOV_VF + } else if ((qno == priv->plat->avb_class_b_ch_no) + && (priv->plat->best_effort_ch_no != priv->plat->avb_class_b_ch_no)) { +#else } else if (qno == AVB_CLASS_B_TX_CH) { +#endif if (skb->data[20] == 0) ccnt2++; - trace_printk("[AVB_B]TS,%llu,%d,%03d,%02d, ,\n", + trace_printk("[CLASS_B]TS,%llu,%d,%03d,%02d, ,\n", ns, ccnt2, skb->data[20], qno); - +#ifdef TC956X_SRIOV_VF + } else if ((qno == priv->plat->tsn_ch_no) + && (priv->plat->best_effort_ch_no != priv->plat->tsn_ch_no)) {/* For CDT */ +#else } else if (qno == TSN_CLASS_CDT_TX_CH) {/* For CDT */ +#endif if (skb->data[20] == 0) ccnt3++; @@ -2226,36 +2487,13 @@ static void tc956xmac_get_tx_hwtstamp(struct tc956xmac_priv *priv, trace_printk("[CDT]TS,%llu,%d,%03d,%02d, ,\n", ns, ccnt3, skb->data[20], qno); #endif - } else if (qno == 4) { /* For queue 3 */ - if (skb->data[20] == 0) - /*trace_printk("[CDT]CYCLE = %d\n",ccnt3);*/ - ccnt4++; - - /* [CDT]TS,,,," */ -#ifdef FPE - trace_printk("[DUM4]TS,%llu,%d,%03d,%02d,\n", - ns, ccnt4, skb->data[20], qno); +#ifdef TC956X_SRIOV_VF + } else if ((qno == priv->plat->gptp_ch_no) + && (priv->plat->best_effort_ch_no != priv->plat->gptp_ch_no)) { #else - trace_printk("[DUM4]TS,%llu,%d,%03d,%02d, ,\n", - ns, ccnt4, skb->data[20], qno); -#endif - } else if (qno == 3) { /* For queue 3 */ - - if (skb->data[20] == 0) - /*trace_printk("[CDT]CYCLE = %d\n",ccnt3);*/ - ccnt5++; - - /* [CDT]TS,,,," */ -#ifdef FPE - trace_printk("[DUM3]TS,%llu,%d,%03d,%02d,\n", - ns, ccnt5, skb->data[20], qno); -#else - trace_printk("[DUM3]TS,%llu,%d,%03d,%02d, ,\n", - ns, ccnt5, skb->data[20], qno); -#endif - } else if (qno == TC956X_GPTP_TX_CH) { +#endif u16 gPTP_ID = 0; u16 MsgType = 0; @@ -2267,22 +2505,11 @@ static void tc956xmac_get_tx_hwtstamp(struct tc956xmac_priv *priv, trace_printk("[gPTP]TS,%019llu,%04d,0x%x,%02d\n", ns, gPTP_ID, MsgType, qno); - } else if (qno == 1) { /* For queue 1 dummy packet */ - - if (skb->data[20] == 0) - /*trace_printk("[CDT]CYCLE = %d\n",ccnt3);*/ - ccnt6++; - - /* [CDT]TS,,,," */ -#ifdef FPE - trace_printk("[DUM1]TS,%llu,%d,%03d,%02d,\n", - ns, ccnt6, skb->data[20], qno); +#ifdef TC956X_SRIOV_VF + } else if (qno == priv->plat->best_effort_ch_no) { #else - trace_printk("[DUM1]TS,%llu,%d,%03d,%02d, ,\n", - ns, ccnt6, skb->data[20], qno); -#endif - } else if (qno == HOST_BEST_EFF_CH) { +#endif #ifdef FPE trace_printk("[LE]TS,%llu,00,000,%02d,\n", ns, qno); #else @@ -2325,8 +2552,8 @@ static void tc956xmac_get_rx_hwtstamp(struct tc956xmac_priv *priv, struct dma_de #ifdef FPE #if defined(RX_LOGGING_TRACE) - priv->mmc.mmc_rx_pkt_assembly_ok += readl(priv->mmcaddr + MMC_RX_PKT_ASSEMBLY_OK); - priv->mmc.mmc_rx_fpe_fragment += readl(priv->mmcaddr + MMC_RX_FPE_FRAG); + priv->mmc.mmc_rx_packet_assembly_ok_cntr += readl(priv->mmcaddr + MMC_XGMAC_RX_PKT_ASSEMBLY_OK); + priv->mmc.mmc_rx_fpe_fragment_cntr += readl(priv->mmcaddr + MMC_XGMAC_RX_FPE_FRAG); #endif #endif @@ -2342,12 +2569,12 @@ static void tc956xmac_get_rx_hwtstamp(struct tc956xmac_priv *priv, struct dma_de if (tc956xmac_get_rx_timestamp_status(priv, p, np, priv->adv_ts)) { #ifdef FPE #if defined(RX_LOGGING_TRACE) - static unsigned int count = 0; + static unsigned int count; if (count % 8000 == 0) { - KPRINT_INFO("Rx FPE asmbly_ok_cnt:%d,frag_cnt:%d\n", - priv->mmc.mmc_rx_pkt_assembly_ok, - priv->mmc.mmc_rx_fpe_fragment); + KPRINT_INFO("Rx FPE asmbly_ok_cnt:%lld,frag_cnt:%lld\n", + priv->mmc.mmc_rx_packet_assembly_ok_cntr, + priv->mmc.mmc_rx_fpe_fragment_cntr); } count++; #endif @@ -2367,18 +2594,14 @@ static void tc956xmac_get_rx_hwtstamp(struct tc956xmac_priv *priv, struct dma_de /* Differentiated by stream IDs 2 for CDT */ if ((unsigned char)skb->data[16] == 0) ccnt1++; - - trace_printk("[CDT]TS,%llu,%d,%03d,%02d \n", + trace_printk("[CDT]TS,%llu,%d,%03d,%02d\n", ns, ccnt1, skb->data[16], qno); } else if (skb->data[24] == 0 && skb->data[25] == 1) { /* Differentiated by stream IDs 1 for AVB */ - if ((unsigned char)skb->data[16] == 0) ccnt2++; - - trace_printk("[AVB]TS,%llu,%d,%03d,\ - %02d \n", ns, ccnt2, - skb->data[16], qno); + trace_printk("[AVB]TS,%llu,%d,%03d,%02d\n", + ns, ccnt2, skb->data[16], qno); } } } else if (proto == ETH_P_1588) { @@ -2397,7 +2620,6 @@ static void tc956xmac_get_rx_hwtstamp(struct tc956xmac_priv *priv, struct dma_de } } -#ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE /** * tc956xmac_hwtstamp_set - control hardware timestamping. * @dev: device pointer. @@ -2409,6 +2631,7 @@ static void tc956xmac_get_rx_hwtstamp(struct tc956xmac_priv *priv, struct dma_de * Return Value: * 0 on success and an appropriate -ve integer on failure. */ +#ifndef TC956X_SRIOV_VF static int tc956xmac_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) { struct tc956xmac_priv *priv = netdev_priv(dev); @@ -2595,11 +2818,11 @@ static int tc956xmac_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) ts_master_en | snap_type_sel | PTP_TCR_ASMEN); value = readl(priv->ptpaddr + PTP_TCR); - /* Note : Values will never be set. The IOCTL will - *not set any bits + /* Note : Values will never be set. "tc956x_ptp_configuration" function + * call should be same as during probe. */ if (!(value & 0x00000001)) { - tc956x_ptp_configuration(priv, tcr_config); + tc956x_ptp_configuration(priv, 0); DBGPR_FUNC(priv->device, "--> %s\n", __func__); } @@ -2631,7 +2854,6 @@ static int tc956xmac_hwtstamp_get(struct net_device *dev, struct ifreq *ifr) return copy_to_user(ifr->ifr_data, config, sizeof(*config)) ? -EFAULT : 0; } -#endif /* TC956X_UNSUPPORTED_UNTESTED_FEATURE */ /** * tc956xmac_init_ptp - init PTP @@ -2669,6 +2891,7 @@ static int tc956xmac_init_ptp(struct tc956xmac_priv *priv) return 0; } +#endif /* TC956X_SRIOV_VF */ static void tc956xmac_release_ptp(struct tc956xmac_priv *priv) { @@ -2676,7 +2899,7 @@ static void tc956xmac_release_ptp(struct tc956xmac_priv *priv) clk_disable_unprepare(priv->plat->clk_ptp_ref); tc956xmac_ptp_unregister(priv); } - +#ifndef TC956X_SRIOV_VF /** * tc956xmac_mac_flow_ctrl - Configure flow control in all queues * @priv: driver private structure @@ -2770,8 +2993,11 @@ static void tc956xmac_validate(struct phylink_config *config, bitmap_andnot(state->advertising, state->advertising, mask, __ETHTOOL_LINK_MODE_MASK_NBITS); } +#endif /* TC956X_SRIOV_VF */ +#ifndef TC956X_SRIOV_VF #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0)) +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0)) static void tc956xmac_mac_pcs_get_state(struct phylink_config *config, struct phylink_link_state *state) { @@ -2831,6 +3057,7 @@ static void tc956xmac_mac_pcs_get_state(struct phylink_config *config, } #endif } +#endif #else /* Required when using with Kernel v5.4 */ static int tc956xmac_mac_link_state(struct phylink_config *config, struct phylink_link_state *state) @@ -2906,7 +3133,7 @@ static int tc956xmac_mac_link_state(struct phylink_config *config, * Description: It is used for initializing MAC during speed change of * USXGMII and SGMII. */ -void tc956xmac_speed_change_init_mac(struct tc956xmac_priv *priv, +static void tc956xmac_speed_change_init_mac(struct tc956xmac_priv *priv, const struct phylink_link_state *state) { /* use signal from MSPHY */ @@ -2968,6 +3195,13 @@ void tc956xmac_speed_change_init_mac(struct tc956xmac_priv *priv, ret |= NEMACCTL_SP_SEL_SGMII_2500M; else ret |= NEMACCTL_SP_SEL_SGMII_1000M; + } else { + if (state->speed == SPEED_10000) + ret |= NEMACCTL_SP_SEL_USXGMII_10G_10G; + else if (state->speed == SPEED_5000) + ret |= NEMACCTL_SP_SEL_USXGMII_5G_10G; + else if (state->speed == SPEED_2500) + ret |= NEMACCTL_SP_SEL_USXGMII_2_5G_10G; } ret &= ~(0x00000040); /* Mask Polarity */ @@ -2978,7 +3212,7 @@ void tc956xmac_speed_change_init_mac(struct tc956xmac_priv *priv, } /*PMA module init*/ - if (priv->hw->xpcs) { + if (priv->hw->xpcs && (state->interface == PHY_INTERFACE_MODE_SGMII)) { if (priv->port_num == RM_PF0_ID) { /* Assertion of PMA & XPCS reset software Reset*/ ret = readl(priv->ioaddr + NRSTCTRL0_OFFSET); @@ -3045,6 +3279,9 @@ static void tc956xmac_mac_config(struct phylink_config *config, unsigned int mod u32 ctrl, emac_ctrl; u32 val; bool config_done = false; +#ifdef TC956X_MAGIC_PACKET_WOL_CONF + int ret = 0; +#endif #ifdef TC956X u32 reg_value; @@ -3064,50 +3301,104 @@ static void tc956xmac_mac_config(struct phylink_config *config, unsigned int mod KPRINT_INFO("AN clause 37 complete bit cleared"); } - if (state->interface == PHY_INTERFACE_MODE_USXGMII) { - /* Invoke this only during speed change */ - if ((state->speed != SPEED_UNKNOWN) && (state->speed != 0)) { - if (state->speed != priv->speed) { - tc956xmac_speed_change_init_mac(priv, state); +#ifdef TC956X_MAGIC_PACKET_WOL_CONF + if (priv->wol_config_enabled != true) { +#endif + if (state->interface == PHY_INTERFACE_MODE_USXGMII) { + /* Invoke this only during speed change */ + if ((state->speed != SPEED_UNKNOWN) && (state->speed != 0)) { + if (state->speed != priv->speed) { + tc956xmac_speed_change_init_mac(priv, state); + } + } else { + return; } - } else { - return; + + /* Program autonegotiated speed to SR_MII_CTRL */ + val = tc956x_xpcs_read(priv->xpcsaddr, XGMAC_SR_MII_CTRL); + val &= ~XGMAC_SR_MII_CTRL_SPEED; /* Mask speed ss13, ss6, ss5 */ + + switch (state->speed) { + case SPEED_10000: + ctrl |= priv->hw->link.xgmii.speed10000; + emac_ctrl |= NEMACCTL_SP_SEL_USXGMII_10G_10G; + val |= XGMAC_SR_MII_CTRL_SPEED_10G; + break; + case SPEED_5000: + ctrl |= priv->hw->link.xgmii.speed5000; + emac_ctrl |= NEMACCTL_SP_SEL_USXGMII_5G_10G; + val |= XGMAC_SR_MII_CTRL_SPEED_5G; + break; + case SPEED_2500: + ctrl |= priv->hw->link.xgmii.speed2500; + emac_ctrl |= NEMACCTL_SP_SEL_USXGMII_2_5G_10G; + val |= XGMAC_SR_MII_CTRL_SPEED_2_5G; + break; + default: + return; + } + + tc956x_xpcs_write(priv->xpcsaddr, XGMAC_SR_MII_CTRL, val); + + /* USRA_RST set to 1 */ + val = tc956x_xpcs_read(priv->xpcsaddr, XGMAC_VR_XS_PCS_DIG_CTRL1); + val |= XGMAC_USRA_RST; + tc956x_xpcs_write(priv->xpcsaddr, XGMAC_VR_XS_PCS_DIG_CTRL1, val); + config_done = true; } - - /* Program autonegotiated speed to SR_MII_CTRL */ - val = tc956x_xpcs_read(priv->xpcsaddr, XGMAC_SR_MII_CTRL); - val &= ~XGMAC_SR_MII_CTRL_SPEED; /* Mask speed ss13, ss6, ss5 */ - - switch (state->speed) { - case SPEED_10000: - ctrl |= priv->hw->link.xgmii.speed10000; - emac_ctrl |= NEMACCTL_SP_SEL_USXGMII_10G_10G; - val |= XGMAC_SR_MII_CTRL_SPEED_10G; - break; - case SPEED_5000: - ctrl |= priv->hw->link.xgmii.speed5000; - emac_ctrl |= NEMACCTL_SP_SEL_USXGMII_5G_10G; - val |= XGMAC_SR_MII_CTRL_SPEED_5G; - break; - case SPEED_2500: - ctrl |= priv->hw->link.xgmii.speed2500; - emac_ctrl |= NEMACCTL_SP_SEL_USXGMII_2_5G_10G; - val |= XGMAC_SR_MII_CTRL_SPEED_2_5G; - break; - default: - return; + if ((state->interface == PHY_INTERFACE_MODE_SGMII) + && (priv->port_interface != ENABLE_2500BASE_X_INTERFACE)) { /* Autonegotiation not supported for SGMII */ + reg_value = tc956x_xpcs_read(priv->xpcsaddr, XGMAC_VR_MII_AN_INTR_STS); + /* Clear autonegotiation only if completed. As for XPCS, 2.5G autonegotiation is not supported */ + /* Switching from SGMII 2.5G to any speed doesn't cause AN completion */ + if (reg_value & XGMAC_C37_AN_COMPL) {/*check if AN 37 is complete CL37_ANCMPLT_INTR*/ + KPRINT_INFO("AN clause 37 completed"); + reg_value &= ~(XGMAC_C37_AN_COMPL); + tc956x_xpcs_write(priv->xpcsaddr, XGMAC_VR_MII_AN_INTR_STS, reg_value); + KPRINT_INFO("AN clause 37 complete bit cleared"); + } + /* Invoke this only during speed change */ + if ((state->speed != SPEED_UNKNOWN) && (state->speed != 0)) { + if (state->speed != priv->speed) + tc956xmac_speed_change_init_mac(priv, state); + } else { + return; + } + val = tc956x_xpcs_read(priv->xpcsaddr, XGMAC_SR_MII_CTRL); + val &= ~XGMAC_SR_MII_CTRL_SPEED; /* Mask speed ss13, ss6, ss5 */ + switch (state->speed) { + case SPEED_2500: + ctrl |= priv->hw->link.speed2500; + /* Program autonegotiated speed to SR_MII_CTRL */ + val |= XPCS_SS_SGMII_1G; /*1000 Mbps setting only available, so set the same*/ + emac_ctrl |= NEMACCTL_SP_SEL_SGMII_2500M; + break; + case SPEED_1000: + ctrl |= priv->hw->link.speed1000; + val |= XPCS_SS_SGMII_1G; /*1000 Mbps setting only available, so set the same*/ + emac_ctrl |= NEMACCTL_SP_SEL_SGMII_1000M; + break; + case SPEED_100: + ctrl |= priv->hw->link.speed100; + val |= XPCS_SS_SGMII_100M; /*100 Mbps setting */ + emac_ctrl |= NEMACCTL_SP_SEL_SGMII_100M; + break; + case SPEED_10: + ctrl |= priv->hw->link.speed10; + val |= XPCS_SS_SGMII_10M; /*10 Mbps setting */ + emac_ctrl |= NEMACCTL_SP_SEL_SGMII_10M; + break; + default: + return; + } + tc956x_xpcs_write(priv->xpcsaddr, XGMAC_SR_MII_CTRL, val); + config_done = true; } - - tc956x_xpcs_write(priv->xpcsaddr, XGMAC_SR_MII_CTRL, val); - - /* USRA_RST set to 1 */ - val = tc956x_xpcs_read(priv->xpcsaddr, XGMAC_VR_XS_PCS_DIG_CTRL1); - val |= XGMAC_USRA_RST; - tc956x_xpcs_write(priv->xpcsaddr, XGMAC_VR_XS_PCS_DIG_CTRL1, val); - config_done = true; - } - if( (state->interface == PHY_INTERFACE_MODE_SGMII) - && (priv->port_interface != ENABLE_2500BASE_X_INTERFACE) ) { /* Autonegotiation not supported for SGMII */ +#ifdef TC956X_MAGIC_PACKET_WOL_CONF + } else { + /* Configure Speed for WOL SGMII 1Gbps */ + KPRINT_INFO("%s Port %d : Entered with flag priv->wol_config_enabled %d", __func__, priv->port_num, priv->wol_config_enabled); + KPRINT_INFO("%s Port %d : Speed to configure %d", __func__, priv->port_num, state->speed); reg_value = tc956x_xpcs_read(priv->xpcsaddr, XGMAC_VR_MII_AN_INTR_STS); /* Clear autonegotiation only if completed. As for XPCS, 2.5G autonegotiation is not supported */ /* Switching from SGMII 2.5G to any speed doesn't cause AN completion */ @@ -3117,22 +3408,13 @@ static void tc956xmac_mac_config(struct phylink_config *config, unsigned int mod tc956x_xpcs_write(priv->xpcsaddr, XGMAC_VR_MII_AN_INTR_STS, reg_value); KPRINT_INFO("AN clause 37 complete bit cleared"); } - /* Invoke this only during speed change */ - if ((state->speed != SPEED_UNKNOWN) && (state->speed != 0)) { - if (state->speed != priv->speed) - tc956xmac_speed_change_init_mac(priv, state); - } else { - return; - } + ret = tc956x_xpcs_init(priv, priv->xpcsaddr); + if (ret < 0) + KPRINT_INFO("XPCS initialization error\n"); + tc956x_xpcs_ctrl_ane(priv, true); val = tc956x_xpcs_read(priv->xpcsaddr, XGMAC_SR_MII_CTRL); val &= ~XGMAC_SR_MII_CTRL_SPEED; /* Mask speed ss13, ss6, ss5 */ switch (state->speed) { - case SPEED_2500: - ctrl |= priv->hw->link.speed2500; - /* Program autonegotiated speed to SR_MII_CTRL */ - val |= XPCS_SS_SGMII_1G; /*1000 Mbps setting only available, so set the same*/ - emac_ctrl |= NEMACCTL_SP_SEL_SGMII_2500M; - break; case SPEED_1000: ctrl |= priv->hw->link.speed1000; val |= XPCS_SS_SGMII_1G; /*1000 Mbps setting only available, so set the same*/ @@ -3143,17 +3425,13 @@ static void tc956xmac_mac_config(struct phylink_config *config, unsigned int mod val |= XPCS_SS_SGMII_100M; /*100 Mbps setting */ emac_ctrl |= NEMACCTL_SP_SEL_SGMII_100M; break; - case SPEED_10: - ctrl |= priv->hw->link.speed10; - val |= XPCS_SS_SGMII_10M; /*10 Mbps setting */ - emac_ctrl |= NEMACCTL_SP_SEL_SGMII_10M; - break; default: return; } tc956x_xpcs_write(priv->xpcsaddr, XGMAC_SR_MII_CTRL, val); config_done = true; - } + } /* End of if (priv->wol_config_enabled != true) */ +#endif /* #ifdef TC956X_MAGIC_PACKET_WOL_CONF */ } else if (state->interface == PHY_INTERFACE_MODE_RGMII) { switch (state->speed) { case SPEED_1000: @@ -3193,7 +3471,9 @@ static void tc956xmac_mac_config(struct phylink_config *config, unsigned int mod } priv->speed = state->speed; - +#ifdef TC956X_SRIOV_PF + priv->duplex = state->duplex; +#endif if (priv->plat->fix_mac_speed) priv->plat->fix_mac_speed(priv->plat->bsp_priv, state->speed); @@ -3212,7 +3492,7 @@ static void tc956xmac_mac_config(struct phylink_config *config, unsigned int mod } #endif } - +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0)) static void tc956xmac_mac_an_restart(struct phylink_config *config) { #ifdef TC956X @@ -3243,6 +3523,7 @@ static void tc956xmac_mac_an_restart(struct phylink_config *config) /*Not supported*/ #endif } +#endif static int tc956xmac_open(struct net_device *dev); static int tc956xmac_release(struct net_device *dev); @@ -3254,6 +3535,9 @@ static void tc956xmac_mac_link_down(struct phylink_config *config, struct tc956xmac_priv *priv = netdev_priv(to_net_dev(config->dev)); struct net_device *ndev = to_net_dev(config->dev); tc956xmac_mac_set_rx(priv, priv->ioaddr, false); + + /* In SRIOV code, EEE is handled by PF driver */ +#ifndef TC956X_SRIOV_VF #ifdef EEE priv->eee_active = false; DBGPR_FUNC(priv->device, "%s Disable EEE\n", __func__); @@ -3299,10 +3583,12 @@ static void tc956xmac_mac_link_down(struct phylink_config *config, /* If all channels are freed, call API for power saving*/ if(priv->port_link_down == false && offload_release_sts == true) { - tc956xmac_link_change_set_power(priv, LINK_DOWN); /* Save, Assert and Disable Reset and Clock */ + tc956xmac_link_change_set_power(priv, LINK_DOWN); /* Save, Assert and Disable Reset and Clock */ } priv->port_release = true; /* setting port release to true as link-down invoked, and clear from open or link-up */ mutex_unlock(&priv->port_ld_release_lock); + +#endif } #ifdef TC956X_5_G_2_5_G_EEE_SUPPORT @@ -3324,7 +3610,7 @@ static void tc956x_mmd_eee_adv_to_linkmode_5G_2_5G(unsigned long *advertising, u advertising); } -int tc956x_phy_init_eee(struct phy_device *phydev, bool clk_stop_enable) +static int tc956x_phy_init_eee(struct phy_device *phydev, bool clk_stop_enable) { if (!phydev->drv) return -EIO; @@ -3483,7 +3769,7 @@ int phy_init_eee_local(struct phy_device *phydev, bool clk_stop_enable) KPRINT_INFO("%s adv: 0x%x\n", __func__, adv); KPRINT_INFO("%s eee_lp: 0x%x\n", __func__, lp); - + linkmode_and(common, adv, lp); KPRINT_INFO("%s common: 0x%x\n", __func__, common); @@ -3507,25 +3793,265 @@ int phy_init_eee_local(struct phy_device *phydev, bool clk_stop_enable) } #endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) +static void tc956xmac_mac_link_up(struct phylink_config *config, + struct phy_device *phy, + unsigned int mode, phy_interface_t interface, + int speed, int duplex, bool tx_pause, bool rx_pause) +#else static void tc956xmac_mac_link_up(struct phylink_config *config, unsigned int mode, phy_interface_t interface, struct phy_device *phy) +#endif { struct tc956xmac_priv *priv = netdev_priv(to_net_dev(config->dev)); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) + u32 ctrl, emac_ctrl; + bool config_done = false; + u32 reg_value; + u32 val; + struct phylink_link_state state; + state.interface = interface; + state.speed = speed; + state.duplex = duplex; + + ctrl = readl(priv->ioaddr + MAC_CTRL_REG); + ctrl &= ~priv->hw->link.speed_mask; + + emac_ctrl = readl(priv->ioaddr + NEMACCTL_OFFSET); + emac_ctrl &= ~NEMACCTL_SP_SEL_MASK; + + if (priv->hw->xpcs) { + reg_value = tc956x_xpcs_read(priv->xpcsaddr, XGMAC_VR_MII_AN_INTR_STS); + if (reg_value & XGMAC_C37_AN_COMPL) {/*check if AN 37 is complete CL37_ANCMPLT_INTR*/ + KPRINT_INFO("AN clause 37 completed"); + reg_value &= ~(XGMAC_C37_AN_COMPL); + tc956x_xpcs_write(priv->xpcsaddr, XGMAC_VR_MII_AN_INTR_STS, reg_value); + KPRINT_INFO("AN clause 37 complete bit cleared"); + } + +#ifdef TC956X_MAGIC_PACKET_WOL_CONF + if (priv->wol_config_enabled != true) { +#endif + if (interface == PHY_INTERFACE_MODE_USXGMII) { + /* Invoke this only during speed change */ + if ((speed != SPEED_UNKNOWN) && (speed != 0)) { + if (speed != priv->speed) + tc956xmac_speed_change_init_mac(priv, &state); + } else { + return; + } + /* Program autonegotiated speed to SR_MII_CTRL */ + val = tc956x_xpcs_read(priv->xpcsaddr, XGMAC_SR_MII_CTRL); + val &= ~XGMAC_SR_MII_CTRL_SPEED; /* Mask speed ss13, ss6, ss5 */ + + switch (speed) { + case SPEED_10000: + ctrl |= priv->hw->link.xgmii.speed10000; + emac_ctrl |= NEMACCTL_SP_SEL_USXGMII_10G_10G; + val |= XGMAC_SR_MII_CTRL_SPEED_10G; + break; + case SPEED_5000: + ctrl |= priv->hw->link.xgmii.speed5000; + emac_ctrl |= NEMACCTL_SP_SEL_USXGMII_5G_10G; + val |= XGMAC_SR_MII_CTRL_SPEED_5G; + break; + case SPEED_2500: + ctrl |= priv->hw->link.xgmii.speed2500; + emac_ctrl |= NEMACCTL_SP_SEL_USXGMII_2_5G_10G; + val |= XGMAC_SR_MII_CTRL_SPEED_2_5G; + break; + default: + return; + } + tc956x_xpcs_write(priv->xpcsaddr, XGMAC_SR_MII_CTRL, val); + + /* USRA_RST set to 1 */ + val = tc956x_xpcs_read(priv->xpcsaddr, XGMAC_VR_XS_PCS_DIG_CTRL1); + val |= XGMAC_USRA_RST; + tc956x_xpcs_write(priv->xpcsaddr, XGMAC_VR_XS_PCS_DIG_CTRL1, val); + config_done = true; + } + if ((interface == PHY_INTERFACE_MODE_SGMII) && + (priv->port_interface != ENABLE_2500BASE_X_INTERFACE)) { + reg_value = tc956x_xpcs_read(priv->xpcsaddr, XGMAC_VR_MII_AN_INTR_STS); + /* Clear autonegotiation only if completed. As for XPCS, 2.5G autonegotiation is not supported */ + /* Switching from SGMII 2.5G to any speed doesn't cause AN completion */ + + if (reg_value & XGMAC_C37_AN_COMPL) {/*check if AN 37 is complete CL37_ANCMPLT_INTR*/ + KPRINT_INFO("AN clause 37 completed"); + reg_value &= ~(XGMAC_C37_AN_COMPL); + tc956x_xpcs_write(priv->xpcsaddr, XGMAC_VR_MII_AN_INTR_STS, reg_value); + KPRINT_INFO("AN clause 37 complete bit cleared"); + } + + /* Invoke this only during speed change */ + if ((speed != SPEED_UNKNOWN) && (speed != 0)) { + if (speed != priv->speed) + tc956xmac_speed_change_init_mac(priv, &state); + } else { + return; + } + + val = tc956x_xpcs_read(priv->xpcsaddr, XGMAC_SR_MII_CTRL); + val &= ~XGMAC_SR_MII_CTRL_SPEED; /* Mask speed ss13, ss6, ss5 */ + + switch (speed) { + case SPEED_2500: + ctrl |= priv->hw->link.speed2500; + /* Program autonegotiated speed to SR_MII_CTRL */ + val |= XPCS_SS_SGMII_1G; /*1000 Mbps setting only available, so set the same*/ + emac_ctrl |= NEMACCTL_SP_SEL_SGMII_2500M; + break; + case SPEED_1000: + ctrl |= priv->hw->link.speed1000; + val |= XPCS_SS_SGMII_1G; /*1000 Mbps setting only available, so set the same*/ + emac_ctrl |= NEMACCTL_SP_SEL_SGMII_1000M; + break; + case SPEED_100: + ctrl |= priv->hw->link.speed100; + val |= XPCS_SS_SGMII_100M; /*100 Mbps setting */ + emac_ctrl |= NEMACCTL_SP_SEL_SGMII_100M; + break; + case SPEED_10: + ctrl |= priv->hw->link.speed10; + val |= XPCS_SS_SGMII_10M; /*10 Mbps setting */ + emac_ctrl |= NEMACCTL_SP_SEL_SGMII_10M; + break; + default: + return; + } + tc956x_xpcs_write(priv->xpcsaddr, XGMAC_SR_MII_CTRL, val); + config_done = true; + } +#ifdef TC956X_MAGIC_PACKET_WOL_CONF + } else { + /* Configure Speed for WOL SGMII 1Gbps */ + KPRINT_INFO("%s Port %d : Entered with flag priv->wol_config_enabled %d", __func__, priv->port_num, priv->wol_config_enabled); + KPRINT_INFO("%s Port %d : Speed to configure %d", __func__, priv->port_num, speed); + reg_value = tc956x_xpcs_read(priv->xpcsaddr, XGMAC_VR_MII_AN_INTR_STS); + + /* Clear autonegotiation only if completed. As for XPCS, 2.5G autonegotiation is not supported */ + /* Switching from SGMII 2.5G to any speed doesn't cause AN completion */ + if (reg_value & XGMAC_C37_AN_COMPL) {/*check if AN 37 is complete CL37_ANCMPLT_INTR*/ + KPRINT_INFO("AN clause 37 completed"); + reg_value &= ~(XGMAC_C37_AN_COMPL); + tc956x_xpcs_write(priv->xpcsaddr, XGMAC_VR_MII_AN_INTR_STS, reg_value); + KPRINT_INFO("AN clause 37 complete bit cleared"); + } + + ret = tc956x_xpcs_init(priv, priv->xpcsaddr); + if (ret < 0) + KPRINT_INFO("XPCS initialization error\n"); + tc956x_xpcs_ctrl_ane(priv, true); + val = tc956x_xpcs_read(priv->xpcsaddr, XGMAC_SR_MII_CTRL); + val &= ~XGMAC_SR_MII_CTRL_SPEED; /* Mask speed ss13, ss6, ss5 */ + switch (speed) { + case SPEED_1000: + ctrl |= priv->hw->link.speed1000; + val |= XPCS_SS_SGMII_1G; /*1000 Mbps setting only available, so set the same*/ + emac_ctrl |= NEMACCTL_SP_SEL_SGMII_1000M; + break; + case SPEED_100: + ctrl |= priv->hw->link.speed100; + val |= XPCS_SS_SGMII_100M; /*100 Mbps setting */ + emac_ctrl |= NEMACCTL_SP_SEL_SGMII_100M; + break; + default: + return; + } + tc956x_xpcs_write(priv->xpcsaddr, XGMAC_SR_MII_CTRL, val); + config_done = true; + } /* End of if (priv->wol_config_enabled != true) */ +#endif /* #ifdef TC956X_MAGIC_PACKET_WOL_CONF */ + } else if (interface == PHY_INTERFACE_MODE_RGMII) { + switch (speed) { + case SPEED_1000: + ctrl |= priv->hw->link.speed1000; + emac_ctrl |= NEMACCTL_SP_SEL_RGMII_1000M; + break; + case SPEED_100: + ctrl |= priv->hw->link.speed100; + emac_ctrl |= NEMACCTL_SP_SEL_RGMII_100M; + break; + case SPEED_10: + ctrl |= priv->hw->link.speed10; + emac_ctrl |= NEMACCTL_SP_SEL_RGMII_10M; + break; + default: + return; + } + config_done = true; + } else { + switch (speed) { + case SPEED_2500: + ctrl |= priv->hw->link.speed2500; + break; + case SPEED_1000: + ctrl |= priv->hw->link.speed1000; + break; + case SPEED_100: + ctrl |= priv->hw->link.speed100; + break; + case SPEED_10: + ctrl |= priv->hw->link.speed10; + break; + default: + return; + } + config_done = true; + } + priv->speed = speed; + +#ifdef TC956X_SRIOV_PF + priv->duplex = duplex; +#endif + + if (priv->plat->fix_mac_speed) + priv->plat->fix_mac_speed(priv->plat->bsp_priv, speed); + + if (!duplex) + ctrl &= ~priv->hw->link.duplex; + else + ctrl |= priv->hw->link.duplex; + + /* Flow Control operation */ + if (rx_pause && tx_pause) + priv->flow_ctrl = FLOW_AUTO; + else if (rx_pause && !tx_pause) + priv->flow_ctrl = FLOW_RX; + else if (!rx_pause && tx_pause) + priv->flow_ctrl = FLOW_TX; + else + priv->flow_ctrl = FLOW_OFF; + + tc956xmac_mac_flow_ctrl(priv, duplex); + + if (config_done) { + writel(ctrl, priv->ioaddr + MAC_CTRL_REG); + writel(emac_ctrl, priv->ioaddr + NEMACCTL_OFFSET); + } + + tc956xmac_mac_set(priv, priv->ioaddr, true); +#endif +#ifndef TC956X_SRIOV_VF mutex_lock(&priv->port_ld_release_lock); priv->port_release = false; /* setting port release to false as link-up invoked, and set to true from release or link down */ if (priv->port_link_down == true) { tc956xmac_link_change_set_power(priv, LINK_UP); /* Restore, De-assert and Enable Reset and Clock */ } mutex_unlock(&priv->port_ld_release_lock); - +#endif tc956xmac_mac_set_rx(priv, priv->ioaddr, true); + + /* In SRIOV code, EEE is handled by PF driver */ +#ifndef TC956X_SRIOV_VF #ifdef EEE if (phy && priv->dma_cap.eee && priv->eee_enabled) { DBGPR_FUNC(priv->device, "%s EEE Enable, checking to enable acive\n", __func__); #ifdef TC956X_5_G_2_5_G_EEE_SUPPORT - if(phy->speed == TC956X_PHY_SPEED_5G || phy->speed == TC956X_PHY_SPEED_2_5G) { + if (phy->speed == TC956X_PHY_SPEED_5G || phy->speed == TC956X_PHY_SPEED_2_5G) { priv->eee_active = tc956x_phy_init_eee(phy, 1) >= 0; } else { #ifndef DEBUG_EEE @@ -3546,11 +4072,23 @@ static void tc956xmac_mac_link_up(struct phylink_config *config, tc956xmac_set_eee_pls(priv, priv->hw, true); } } +#endif + /* Send Link parameters to all VFs */ + priv->link = true; #endif DBGPR_FUNC(priv->device, "%s priv->eee_enabled: %d priv->eee_active: %d\n", __func__, priv->eee_enabled, priv->eee_active); - clear_bit(TC956XMAC_DOWN, &priv->link_state); +#ifdef TC956X_SRIOV_PF +#ifdef TC956X_DYNAMIC_LOAD_CBS + if (prev_speed != priv->speed) + { + tc956xmac_set_cbs_speed(priv); + } + prev_speed = priv->speed; +#endif + tc956x_mbx_wrap_phy_link(priv); +#endif #ifdef TC956X_PM_DEBUG pm_generic_resume(priv->device); #endif @@ -3559,16 +4097,21 @@ static void tc956xmac_mac_link_up(struct phylink_config *config, static const struct phylink_mac_ops tc956xmac_phylink_mac_ops = { .validate = tc956xmac_validate, #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0)) +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0)) .mac_pcs_get_state = tc956xmac_mac_pcs_get_state, +#endif #else /* Required when using with Kernel v5.4 */ .mac_link_state = tc956xmac_mac_link_state, #endif .mac_config = tc956xmac_mac_config, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0)) .mac_an_restart = tc956xmac_mac_an_restart, +#endif .mac_link_down = tc956xmac_mac_link_down, .mac_link_up = tc956xmac_mac_link_up, }; - +#endif /* TC956X_SRIOV_VF */ +#ifndef TC956X_SRIOV_VF /** * tc956xmac_check_pcs_mode - verify if RGMII/SGMII is supported * @priv: driver private structure @@ -3630,7 +4173,7 @@ static void tc956xmac_defer_phy_isr_work(struct work_struct *work) struct tc956xmac_priv *priv = container_of(work, struct tc956xmac_priv, emac_phy_work); int addr = priv->plat->phy_addr; - + DBGPR_FUNC(priv->device, "Entry: tc956xmac_defer_phy_isr_work\n"); phydev = mdiobus_get_phy(priv->mii, addr); @@ -3640,23 +4183,27 @@ static void tc956xmac_defer_phy_isr_work(struct work_struct *work) return; } - if(!phydev->drv) { + if (!phydev->drv) { netdev_err(priv->dev, "no phy driver\n"); return; } /* Call ack interrupt to clear the WOL interrupt status fields */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)) + if (phydev->drv->handle_interrupt) + phydev->drv->handle_interrupt(phydev); +#else if (phydev->drv->ack_interrupt) phydev->drv->ack_interrupt(phydev); - +#endif phy_mac_interrupt(phydev); - - /* PHY MSI interrupt Enable */ - rd_val = readl(priv->ioaddr + TC956X_MSI_OUT_EN_OFFSET(priv->port_num)); /* MSI_OUT_EN: Reading */ - rd_val |= (1 << MSI_INT_EXT_PHY); - writel(rd_val, priv->ioaddr + TC956X_MSI_OUT_EN_OFFSET(priv->port_num)); /* MSI_OUT_EN: Enable MAC Ext Interrupt */ - DBGPR_FUNC(priv->device, "Exit: tc956xmac_defer_phy_isr_work \n"); + /* PHY MSI interrupt Enable */ + rd_val = readl(priv->ioaddr + TC956X_MSI_OUT_EN_OFFSET(priv->port_num, 0)); /* MSI_OUT_EN: Reading */ + rd_val |= (1 << MSI_INT_EXT_PHY); + writel(rd_val, priv->ioaddr + TC956X_MSI_OUT_EN_OFFSET(priv->port_num, 0)); /* MSI_OUT_EN: Enable MAC Ext Interrupt */ + + DBGPR_FUNC(priv->device, "Exit: tc956xmac_defer_phy_isr_work\n"); } /** @@ -3679,30 +4226,31 @@ static int tc956xmac_init_phy(struct net_device *dev) node = priv->plat->phylink_node; phydev = mdiobus_get_phy(priv->mii, addr); - + if (!phydev) { netdev_err(priv->dev, "no phy at addr %d\n", addr); return -ENODEV; } - if(phydev->drv != NULL) { + if (phydev->drv != NULL) { if (true == priv->plat->phy_interrupt_mode && (phydev->drv->config_intr)) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) + phydev->irq = PHY_MAC_INTERRUPT; +#else phydev->irq = PHY_IGNORE_INTERRUPT; - phydev->interrupts = PHY_INTERRUPT_ENABLED; - KPRINT_INFO("PHY configured in interrupt mode \n"); +#endif + KPRINT_INFO("PHY configured in interrupt mode\n"); DBGPR_FUNC(priv->device, "%s PHY configured in interrupt mode\n", __func__); - + INIT_WORK(&priv->emac_phy_work, tc956xmac_defer_phy_isr_work); } else { phydev->irq = PHY_POLL; - phydev->interrupts = PHY_INTERRUPT_DISABLED; DBGPR_FUNC(priv->device, "%s [1] PHY configured in polling mode\n", __func__); - } + } } else { phydev->irq = PHY_POLL; phydev->interrupts = PHY_INTERRUPT_DISABLED; DBGPR_FUNC(priv->device, "%s [2] PHY configured in polling mode\n", __func__); } - if (node) ret = phylink_of_phy_connect(priv->phylink, node, 0); @@ -3733,9 +4281,17 @@ static int tc956xmac_init_phy(struct net_device *dev) phy_attached_info(phydev); } + + if (phydev->drv != NULL) { + if (true == priv->plat->phy_interrupt_mode && (phydev->drv->config_intr)) + phydev->interrupts = PHY_INTERRUPT_ENABLED; + else + phydev->interrupts = PHY_INTERRUPT_DISABLED; + } + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { if (!(phydev->drv->config_intr && - !phydev->drv->config_intr(phydev))){ + !phydev->drv->config_intr(phydev))) { KPRINT_ERR("Failed to configure PHY interrupt port number is %d", priv->port_num); } } @@ -3744,7 +4300,15 @@ static int tc956xmac_init_phy(struct net_device *dev) edata.advertised = 0; if (priv->phylink) { - phylink_ethtool_set_eee(priv->phylink, &edata); + if (priv->plat->interface != PHY_INTERFACE_MODE_RGMII) { + netdev_info(priv->dev, "Ethtool EEE Setting\n"); + phylink_ethtool_set_eee(priv->phylink, &edata); +#ifdef TC956X_5_G_2_5_G_EEE_SUPPORT + /* Enable EEE for 2.5G and 5G speeds, when driver is loaded with EEE ON module param. */ + netdev_info(priv->dev, "Ethtool EEE Setting for 5G/2.5G\n"); + ret |= phy_ethtool_set_eee_2p5(phydev, &edata); +#endif + } } /* In forced speed mode, donot return error here */ if (((priv->port_num == RM_PF1_ID) && (mac1_force_speed_mode == ENABLE)) || @@ -3753,9 +4317,15 @@ static int tc956xmac_init_phy(struct net_device *dev) return ret; } - +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) +static void tc956xmac_phylink_fixed_state(struct phylink_config *config, struct phylink_link_state *state) +#else static void tc956xmac_phylink_fixed_state(struct net_device *dev, struct phylink_link_state *state) +#endif { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) + struct net_device *dev = to_net_dev(config->dev); +#endif struct tc956xmac_priv *priv = netdev_priv(dev); state->link = 1; @@ -3776,6 +4346,11 @@ static int tc956xmac_phy_setup(struct tc956xmac_priv *priv) priv->phylink_config.dev = &priv->dev->dev; priv->phylink_config.type = PHYLINK_NETDEV; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0)) + /* Set the platform/firmware specified interface mode */ + __set_bit(mode, priv->phylink_config.supported_interfaces); +#endif + phylink = phylink_create(&priv->phylink_config, fwnode, mode, &tc956xmac_phylink_mac_ops); if (IS_ERR(phylink)) @@ -3784,12 +4359,15 @@ static int tc956xmac_phy_setup(struct tc956xmac_priv *priv) /* Fixed phy mode should be set using device tree, driver just registers callback here */ if (((priv->port_num == RM_PF1_ID) && (mac1_force_speed_mode == ENABLE)) || ((priv->port_num == RM_PF0_ID) && (mac0_force_speed_mode == ENABLE))) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) + priv->phylink_config.get_fixed_state=tc956xmac_phylink_fixed_state; +#else phylink_fixed_state_cb(phylink, tc956xmac_phylink_fixed_state); - +#endif priv->phylink = phylink; return 0; } - +#endif /*#ifdef TC956X_SRIOV_VF*/ static void tc956xmac_display_rx_rings(struct tc956xmac_priv *priv) { u32 rx_cnt = priv->plat->rx_queues_to_use; @@ -3800,9 +4378,17 @@ static void tc956xmac_display_rx_rings(struct tc956xmac_priv *priv) for (queue = 0; queue < rx_cnt; queue++) { struct tc956xmac_rx_queue *rx_q = &priv->rx_queue[queue]; +#ifdef TC956X_SRIOV_PF + if (priv->plat->rx_ch_in_use[queue] == TC956X_DISABLE_CHNL) + continue; +#elif defined TC956X_SRIOV_VF + /* skip configuring for unallocated channel */ + if (priv->plat->ch_in_use[queue] == 0) + continue; +#else if (priv->plat->rx_dma_ch_owner[queue] != USE_IN_TC956X_SW) continue; - +#endif pr_info("\tRX Queue %u rings\n", queue); if (priv->extend_desc) @@ -3825,9 +4411,17 @@ static void tc956xmac_display_tx_rings(struct tc956xmac_priv *priv) for (queue = 0; queue < tx_cnt; queue++) { struct tc956xmac_tx_queue *tx_q = &priv->tx_queue[queue]; +#ifdef TC956X_SRIOV_PF + if (priv->plat->tx_ch_in_use[queue] == TC956X_DISABLE_CHNL) + continue; +#elif defined TC956X_SRIOV_VF + /* skip configuring for unallocated channel */ + if (priv->plat->ch_in_use[queue] == 0) + continue; +#else if (priv->plat->tx_dma_ch_owner[queue] != USE_IN_TC956X_SW) continue; - +#endif pr_info("\tTX Queue %d rings\n", queue); if (priv->extend_desc) @@ -3939,17 +4533,33 @@ static void tc956xmac_clear_descriptors(struct tc956xmac_priv *priv) /* Clear the RX descriptors */ for (queue = 0; queue < rx_queue_cnt; queue++) { +#ifdef TC956X_SRIOV_PF + if (priv->plat->rx_ch_in_use[queue] == TC956X_DISABLE_CHNL) + continue; +#elif defined TC956X_SRIOV_VF + /* skip configuring for unallocated channel */ + if (priv->plat->ch_in_use[queue] == 0) + continue; +#else if (priv->plat->rx_dma_ch_owner[queue] != USE_IN_TC956X_SW) continue; - +#endif tc956xmac_clear_rx_descriptors(priv, queue); } /* Clear the TX descriptors */ for (queue = 0; queue < tx_queue_cnt; queue++) { +#ifdef TC956X_SRIOV_PF + if (priv->plat->tx_ch_in_use[queue] == TC956X_DISABLE_CHNL) + continue; +#elif defined TC956X_SRIOV_VF + /* skip configuring for unallocated channel */ + if (priv->plat->ch_in_use[queue] == 0) + continue; +#else if (priv->plat->tx_dma_ch_owner[queue] != USE_IN_TC956X_SW) continue; - +#endif tc956xmac_clear_tx_descriptors(priv, queue); } } @@ -4005,11 +4615,19 @@ static void tc956xmac_free_rx_buffer(struct tc956xmac_priv *priv, u32 queue, int struct tc956xmac_rx_buffer *buf = &rx_q->buf_pool[i]; if (buf->page) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) + page_pool_put_full_page(rx_q->page_pool, buf->page, false); +#else page_pool_put_page(rx_q->page_pool, buf->page, false); +#endif buf->page = NULL; if (buf->sec_page) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) + page_pool_put_full_page(rx_q->page_pool, buf->sec_page, false); +#else page_pool_put_page(rx_q->page_pool, buf->sec_page, false); +#endif buf->sec_page = NULL; } @@ -4074,9 +4692,17 @@ static int init_dma_rx_desc_rings(struct net_device *dev, gfp_t flags) for (queue = 0; queue < rx_count; queue++) { struct tc956xmac_rx_queue *rx_q = &priv->rx_queue[queue]; +#ifdef TC956X_SRIOV_PF + if (priv->plat->rx_ch_in_use[queue] == TC956X_DISABLE_CHNL) + continue; +#elif defined TC956X_SRIOV_VF + /* skip configuring for unallocated channel */ + if (priv->plat->ch_in_use[queue] == 0) + continue; +#else if (priv->plat->rx_dma_ch_owner[queue] != USE_IN_TC956X_SW) continue; - +#endif netif_dbg(priv, probe, priv->dev, "(%s) dma_rx_phy=0x%08x\n", __func__, (u32)rx_q->dma_rx_phy); @@ -4115,6 +4741,14 @@ static int init_dma_rx_desc_rings(struct net_device *dev, gfp_t flags) err_init_rx_buffers: while (queue >= 0) { +#ifdef TC956X_SRIOV_VF + /* skip configuring for unallocated channel */ + if (priv->plat->ch_in_use[queue] == 0) { + i = DMA_RX_SIZE; + queue--; + continue; + } +#endif while (--i >= 0) tc956xmac_free_rx_buffer(priv, queue, i); @@ -4145,9 +4779,18 @@ static int init_dma_tx_desc_rings(struct net_device *dev) for (queue = 0; queue < tx_queue_cnt; queue++) { struct tc956xmac_tx_queue *tx_q = &priv->tx_queue[queue]; +#ifdef TC956X_SRIOV_PF + if (priv->plat->tx_ch_in_use[queue] == TC956X_DISABLE_CHNL) + continue; +#elif defined TC956X_SRIOV_VF + /* skip configuring for unallocated channel */ + if (priv->plat->ch_in_use[queue] == 0) + continue; +#else + /* skip configuring for unallocated channel */ if (priv->plat->tx_dma_ch_owner[queue] != USE_IN_TC956X_SW) continue; - +#endif netif_dbg(priv, probe, priv->dev, "(%s) dma_tx_phy=0x%08x\n", __func__, (u32)tx_q->dma_tx_phy); @@ -4259,10 +4902,17 @@ static void free_dma_rx_desc_resources(struct tc956xmac_priv *priv) /* Free RX queue resources */ for (queue = 0; queue < rx_count; queue++) { struct tc956xmac_rx_queue *rx_q = &priv->rx_queue[queue]; - +#ifdef TC956X_SRIOV_PF + if (priv->plat->rx_ch_in_use[queue] == TC956X_DISABLE_CHNL) + continue; +#elif defined TC956X_SRIOV_VF + /* skip configuring for unallocated channel */ + if (priv->plat->ch_in_use[queue] == 0) + continue; +#else if (priv->plat->rx_dma_ch_owner[queue] != USE_IN_TC956X_SW) continue; - +#endif /* Release the DMA RX socket buffers */ dma_free_rx_skbufs(priv, queue); @@ -4297,9 +4947,17 @@ static void free_dma_tx_desc_resources(struct tc956xmac_priv *priv) size_t size; void *addr; +#ifdef TC956X_SRIOV_PF + if (priv->plat->tx_ch_in_use[queue] == TC956X_DISABLE_CHNL) + continue; +#elif defined TC956X_SRIOV_VF + /* skip configuring for unallocated channel */ + if (priv->plat->ch_in_use[queue] == 0) + continue; +#else if (priv->plat->tx_dma_ch_owner[queue] != USE_IN_TC956X_SW) continue; - +#endif /* Release the DMA TX socket buffers */ dma_free_tx_skbufs(priv, queue); @@ -4350,10 +5008,18 @@ static int alloc_dma_rx_desc_resources(struct tc956xmac_priv *priv) struct page_pool_params pp_params = { 0 }; unsigned int num_pages; +#ifdef TC956X_SRIOV_PF + if (priv->plat->rx_ch_in_use[queue] == TC956X_DISABLE_CHNL) + continue; +#elif defined TC956X_SRIOV_VF + /* skip configuring for unallocated channel */ + if (priv->plat->ch_in_use[queue] == 0) + continue; +#else /* Create Rx DMA resources for Host owned channels only */ if (priv->plat->rx_dma_ch_owner[queue] != USE_IN_TC956X_SW) continue; - +#endif rx_q->queue_index = queue; rx_q->priv_data = priv; @@ -4364,7 +5030,10 @@ static int alloc_dma_rx_desc_resources(struct tc956xmac_priv *priv) pp_params.nid = dev_to_node(priv->device); pp_params.dev = priv->device; pp_params.dma_dir = DMA_FROM_DEVICE; - +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0)) + pp_params.offset = 0; + pp_params.max_len = TC956X_MAX_RX_BUF_SIZE(num_pages); +#endif rx_q->page_pool = page_pool_create(&pp_params); if (IS_ERR(rx_q->page_pool)) { ret = PTR_ERR(rx_q->page_pool); @@ -4423,9 +5092,17 @@ static int alloc_dma_tx_desc_resources(struct tc956xmac_priv *priv) size_t size; void *addr; +#ifdef TC956X_SRIOV_PF + if (priv->plat->tx_ch_in_use[queue] == TC956X_DISABLE_CHNL) + continue; +#elif defined TC956X_SRIOV_VF + /* skip configuring for unallocated channel */ + if (priv->plat->ch_in_use[queue] == 0) + continue; +#else if (priv->plat->tx_dma_ch_owner[queue] != USE_IN_TC956X_SW) continue; - +#endif tx_q->queue_index = queue; tx_q->priv_data = priv; @@ -4504,6 +5181,7 @@ static void free_dma_desc_resources(struct tc956xmac_priv *priv) free_dma_tx_desc_resources(priv); } +#ifndef TC956X_SRIOV_VF /** * tc956xmac_mac_enable_rx_queues - Enable MAC rx queues * @priv: driver private structure @@ -4516,11 +5194,15 @@ static void tc956xmac_mac_enable_rx_queues(struct tc956xmac_priv *priv) u8 mode; for (queue = 0; queue < rx_queues_count; queue++) { +#ifdef TC956X_SRIOV_PF + if (priv->plat->rx_q_in_use[queue] == TC956X_DISABLE_QUEUE) + continue; +#endif mode = priv->plat->rx_queues_cfg[queue].mode_to_use; tc956xmac_rx_queue_enable(priv, priv->hw, mode, queue); } } - +#endif /* TC956X_SRIOV_VF */ /** * tc956xmac_start_rx_dma - start RX DMA channel * @priv: driver private structure @@ -4589,14 +5271,30 @@ static void tc956xmac_start_all_dma(struct tc956xmac_priv *priv) u32 chan = 0; for (chan = 0; chan < rx_channels_count; chan++) { +#ifdef TC956X_SRIOV_PF + if (priv->plat->rx_ch_in_use[chan] == TC956X_DISABLE_CHNL) + continue; +#elif defined TC956X_SRIOV_VF + if (priv->plat->ch_in_use[chan] == 0) + continue; +#else if (priv->plat->rx_dma_ch_owner[chan] != USE_IN_TC956X_SW) continue; +#endif tc956xmac_start_rx_dma(priv, chan); } for (chan = 0; chan < tx_channels_count; chan++) { +#ifdef TC956X_SRIOV_PF + if (priv->plat->tx_ch_in_use[chan] == TC956X_DISABLE_CHNL) + continue; +#elif defined TC956X_SRIOV_VF + if (priv->plat->ch_in_use[chan] == 0) + continue; +#else if (priv->plat->tx_dma_ch_owner[chan] != USE_IN_TC956X_SW) continue; +#endif tc956xmac_start_tx_dma(priv, chan); } } @@ -4617,14 +5315,32 @@ static void tc956xmac_stop_all_dma(struct tc956xmac_priv *priv) u32 chan = 0; for (chan = 0; chan < rx_channels_count; chan++) { +#ifdef TC956X_SRIOV_PF + if (priv->plat->rx_ch_in_use[chan] == TC956X_DISABLE_CHNL) + continue; +#elif defined TC956X_SRIOV_VF + /* skip configuring for unallocated channel */ + if (priv->plat->ch_in_use[chan] == 0) + continue; +#else if (priv->plat->rx_dma_ch_owner[chan] != USE_IN_TC956X_SW) continue; +#endif tc956xmac_stop_rx_dma(priv, chan); } for (chan = 0; chan < tx_channels_count; chan++) { +#ifdef TC956X_SRIOV_PF + if (priv->plat->tx_ch_in_use[chan] == TC956X_DISABLE_CHNL) + continue; +#elif defined TC956X_SRIOV_VF + /* skip configuring for unallocated channel */ + if (priv->plat->ch_in_use[chan] == 0) + continue; +#else if (priv->plat->tx_dma_ch_owner[chan] != USE_IN_TC956X_SW) continue; +#endif tc956xmac_stop_tx_dma(priv, chan); } } @@ -4674,15 +5390,28 @@ static void tc956xmac_dma_operation_mode(struct tc956xmac_priv *priv) rxmode = SF_DMA_MODE; } +#ifndef TC956X_SRIOV_VF /* configure all channels */ for (chan = 0; chan < rx_channels_count; chan++) { #ifdef TC956X +#ifdef TC956X_SRIOV_PF + if (priv->plat->rx_q_in_use[chan] == TC956X_DISABLE_QUEUE) + continue; +#endif switch (chan) { case 0: +#if defined(TC956X_AUTOMOTIVE_CONFIG) rxfifosz = priv->plat->rx_queues_cfg[0].size; +#else + rxfifosz = RX_QUEUE0_SIZE; +#endif break; case 1: +#if defined(TC956X_AUTOMOTIVE_CONFIG) rxfifosz = priv->plat->rx_queues_cfg[1].size; +#else + rxfifosz = RX_QUEUE1_SIZE; +#endif break; case 2: rxfifosz = RX_QUEUE2_SIZE; @@ -4712,22 +5441,49 @@ static void tc956xmac_dma_operation_mode(struct tc956xmac_priv *priv) tc956xmac_dma_rx_mode(priv, priv->ioaddr, rxmode, chan, rxfifosz, qmode); + } +#endif + + for (chan = 0; chan < rx_channels_count; chan++) { #ifdef TC956X +#ifdef TC956X_SRIOV_PF + if (priv->plat->rx_ch_in_use[chan] == TC956X_DISABLE_CHNL) + continue; +#elif defined TC956X_SRIOV_VF + /* configure only size in DMA register for the + * channels used by VF, other channels skip + */ + if (priv->plat->ch_in_use[chan] == 0) + continue; +#else if (priv->plat->rx_dma_ch_owner[chan] == USE_IN_TC956X_SW) +#endif tc956xmac_set_dma_bfsize(priv, priv->ioaddr, priv->dma_buf_sz, chan); #endif - } + for (chan = 0; chan < tx_channels_count; chan++) { #ifdef TC956X +#ifdef TC956X_SRIOV_PF + if (priv->plat->tx_q_in_use[chan] == TC956X_DISABLE_QUEUE) + continue; + switch (chan) { case 0: +#if defined(TC956X_AUTOMOTIVE_CONFIG) txfifosz = priv->plat->tx_queues_cfg[0].size; +#else + txfifosz = TX_QUEUE0_SIZE; +#endif break; case 1: +#if defined(TC956X_AUTOMOTIVE_CONFIG) txfifosz = priv->plat->tx_queues_cfg[1].size; +#else + txfifosz = TX_QUEUE1_SIZE; +#endif break; case 2: txfifosz = TX_QUEUE2_SIZE; @@ -4751,12 +5507,28 @@ static void tc956xmac_dma_operation_mode(struct tc956xmac_priv *priv) txfifosz = TX_QUEUE0_SIZE; break; } +#elif defined TC956X_SRIOV_VF + /* configure only size in DMA register for the + * channels used by VF, other channels skip + */ + if (priv->plat->ch_in_use[chan] == 0) + continue; + + txfifosz = priv->plat->tx_q_size[chan]; +#endif /* TC956X_SRIOV_VF */ #endif qmode = priv->plat->tx_queues_cfg[chan].mode_to_use; + /* Use mailbox to set tx mode */ +#ifdef TC956X_SRIOV_PF tc956xmac_dma_tx_mode(priv, priv->ioaddr, txmode, chan, txfifosz, qmode); +#elif defined TC956X_SRIOV_VF + tc956xmac_dma_tx_mode(priv, txmode, chan, + txfifosz, qmode); +#endif + } } @@ -4865,8 +5637,14 @@ static int tc956xmac_tx_clean(struct tc956xmac_priv *priv, int budget, u32 queue } #ifdef ENABLE_TX_TIMER /* We still have pending packets, let's call for a new scheduling */ - if (tx_q->dirty_tx != tx_q->cur_tx) + if (tx_q->dirty_tx != tx_q->cur_tx) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)) + hrtimer_start(&tx_q->txtimer, + TC956XMAC_COAL_TIMER(priv->tx_coal_timer[queue]), HRTIMER_MODE_REL); +#else mod_timer(&tx_q->txtimer, TC956XMAC_COAL_TIMER(priv->tx_coal_timer)); +#endif + } #endif __netif_tx_unlock_bh(netdev_get_tx_queue(priv->dev, queue)); @@ -4901,6 +5679,7 @@ static void tc956xmac_tx_err(struct tc956xmac_priv *priv, u32 chan) netif_tx_wake_queue(netdev_get_tx_queue(priv->dev, chan)); } +#ifndef TC956X_SRIOV_VF /** * tc956xmac_set_dma_operation_mode - Set DMA operation mode by channel * @priv: driver private structure @@ -4930,15 +5709,26 @@ static void tc956xmac_set_dma_operation_mode(struct tc956xmac_priv *priv, u32 tx rxfifosz /= rx_channels_count; txfifosz /= tx_channels_count; +#ifndef TC956X_SRIOV_VF #ifdef TC956X switch (chan) { case 0: +#if defined(TC956X_AUTOMOTIVE_CONFIG) rxfifosz = priv->plat->rx_queues_cfg[0].size; txfifosz = priv->plat->tx_queues_cfg[0].size; +#else + rxfifosz = RX_QUEUE0_SIZE; + txfifosz = TX_QUEUE0_SIZE; +#endif break; case 1: +#if defined(TC956X_AUTOMOTIVE_CONFIG) rxfifosz = priv->plat->rx_queues_cfg[1].size; txfifosz = priv->plat->tx_queues_cfg[1].size; +#else + rxfifosz = RX_QUEUE1_SIZE; + txfifosz = TX_QUEUE1_SIZE; +#endif break; case 2: rxfifosz = RX_QUEUE2_SIZE; @@ -4972,9 +5762,18 @@ static void tc956xmac_set_dma_operation_mode(struct tc956xmac_priv *priv, u32 tx #endif tc956xmac_dma_rx_mode(priv, priv->ioaddr, rxmode, chan, rxfifosz, rxqmode); - tc956xmac_dma_tx_mode(priv, priv->ioaddr, txmode, chan, txfifosz, txqmode); -} +#endif /* TC956X_SRIOV_VF */ + /* Use mailbox to set tx mode */ +#ifndef TC956X_SRIOV_VF + tc956xmac_dma_tx_mode(priv, priv->ioaddr, txmode, chan, txfifosz, txqmode); +#elif (defined TC956X_SRIOV_VF) + tc956xmac_dma_tx_mode(priv, priv, txmode, chan, txfifosz, txqmode); +#endif +} +#endif /*#ifdef TC956X_SRIOV_VF*/ + +#ifndef TC956X_SRIOV_VF static bool tc956xmac_safety_feat_interrupt(struct tc956xmac_priv *priv) { int ret; @@ -4988,6 +5787,7 @@ static bool tc956xmac_safety_feat_interrupt(struct tc956xmac_priv *priv) return false; } +#endif static int tc956xmac_napi_check(struct tc956xmac_priv *priv, u32 chan) { @@ -4997,8 +5797,15 @@ static int tc956xmac_napi_check(struct tc956xmac_priv *priv, u32 chan) unsigned long flags; #ifdef TC956X +#ifdef TC956X_SRIOV_PF + if ((status & handle_rx) && (chan < priv->plat->rx_queues_to_use) && (priv->plat->rx_ch_in_use[chan] == TC956X_ENABLE_CHNL)) { +#elif defined TC956X_SRIOV_VF + if ((status & handle_rx) && (chan < priv->plat->rx_queues_to_use) && + (priv->plat->ch_in_use[chan] == 1)) { +#else if ((status & handle_rx) && (chan < priv->plat->rx_queues_to_use) && (priv->plat->rx_dma_ch_owner[chan] == USE_IN_TC956X_SW)) { +#endif #endif if (napi_schedule_prep(&ch->rx_napi)) { @@ -5009,9 +5816,15 @@ static int tc956xmac_napi_check(struct tc956xmac_priv *priv, u32 chan) } } +#ifdef TC956X_SRIOV_PF + if ((status & handle_tx) && (chan < priv->plat->tx_queues_to_use) && (priv->plat->tx_ch_in_use[chan] == TC956X_ENABLE_CHNL)) { +#elif defined TC956X_SRIOV_VF + if ((status & handle_tx) && (chan < priv->plat->tx_queues_to_use) && + (priv->plat->ch_in_use[chan] == 1)) { +#else if ((status & handle_tx) && (chan < priv->plat->tx_queues_to_use) && (priv->plat->tx_dma_ch_owner[chan] == USE_IN_TC956X_SW)) { - +#endif #ifdef TX_COMPLETION_WITHOUT_TIMERS writel(0, priv->tc956x_SRAM_pci_base_addr + TX_TIMER_SRAM_OFFSET(priv->port_num)); @@ -5052,23 +5865,36 @@ static void tc956xmac_dma_interrupt(struct tc956xmac_priv *priv) channels_to_check = ARRAY_SIZE(status); for (chan = 0; chan < channels_to_check; chan++) { - /* Assuming DMA Tx and Rx channels are used as pairs */ - if ((priv->plat->tx_dma_ch_owner[chan] != USE_IN_TC956X_SW) || - (priv->plat->rx_dma_ch_owner[chan] != USE_IN_TC956X_SW)) +#ifdef TC956X_SRIOV_PF + if ((priv->plat->tx_ch_in_use[chan] == TC956X_DISABLE_CHNL) && (priv->plat->rx_ch_in_use[chan] == TC956X_DISABLE_CHNL)) continue; - +#elif defined TC956X_SRIOV_VF + /* skip configuring for unallocated channel */ + if (priv->plat->ch_in_use[chan] == 0) + continue; +#endif status[chan] = tc956xmac_napi_check(priv, chan); } for (chan = 0; chan < tx_channel_count; chan++) { - if (priv->plat->tx_dma_ch_owner[chan] != USE_IN_TC956X_SW) +#ifdef TC956X_SRIOV_PF + if (priv->plat->tx_ch_in_use[chan] == TC956X_DISABLE_CHNL) continue; - +#elif defined TC956X_SRIOV_VF + /* skip configuring for unallocated channel */ + if (priv->plat->ch_in_use[chan] == 0) + continue; +#endif if (unlikely(status[chan] & tx_hard_error_bump_tc)) { /* Try to bump up the dma threshold on this failure */ if (unlikely(priv->xstats.threshold != SF_DMA_MODE) && (tc <= 256)) { tc += 64; + + // Note: Threshold mode is not used as per configuration. And setting of Rx DMA operation mode will be + // tricky as Rx queue is shared among more than on VF, this operation may affect other VF/PF + // So as of now this code is not used in VF driver +#ifndef TC956X_SRIOV_VF if (priv->plat->force_thresh_dma_mode) tc956xmac_set_dma_operation_mode(priv, tc, @@ -5079,6 +5905,7 @@ static void tc956xmac_dma_interrupt(struct tc956xmac_priv *priv) tc, SF_DMA_MODE, chan); +#endif priv->xstats.threshold = tc; } } else if (unlikely(status[chan] == tx_hard_error)) { @@ -5094,6 +5921,7 @@ static void tc956xmac_dma_interrupt(struct tc956xmac_priv *priv) */ static void tc956xmac_mmc_setup(struct tc956xmac_priv *priv) { +#ifndef TC956X_SRIOV_VF //CPE_DRV unsigned int mode = MMC_CNTRL_RESET_ON_READ | MMC_CNTRL_COUNTER_RESET | MMC_CNTRL_PRESET | MMC_CNTRL_FULL_HALF_PRESET; @@ -5104,6 +5932,9 @@ static void tc956xmac_mmc_setup(struct tc956xmac_priv *priv) memset(&priv->mmc, 0, sizeof(struct tc956xmac_counters)); } else netdev_info(priv->dev, "No MAC Management Counters available\n"); +#else + memset(&priv->sw_stats, 0, sizeof(struct tc956x_sw_counters)); +#endif } /** @@ -5120,6 +5951,7 @@ static int tc956xmac_get_hw_features(struct tc956xmac_priv *priv) return tc956xmac_get_hw_feature(priv, priv->ioaddr, &priv->dma_cap) == 0; } +#ifdef TC956X_SRIOV_VF /** * tc956xmac_check_ether_addr - check if the MAC addr is valid * @priv: driver private structure @@ -5129,14 +5961,45 @@ static int tc956xmac_get_hw_features(struct tc956xmac_priv *priv) */ static void tc956xmac_check_ether_addr(struct tc956xmac_priv *priv) { +#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)) + u8 addr[ETH_ALEN]; +#endif +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + unsigned long flags; +#endif + +#ifndef TC956X_SRIOV_VF if (!is_valid_ether_addr(priv->dev->dev_addr)) { + +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_lock_irqsave(&priv->spn_lock.mac_filter, flags); +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)) + tc956xmac_get_umac_addr(priv, priv->hw, addr, 0); +#else tc956xmac_get_umac_addr(priv, priv->hw, priv->dev->dev_addr, 0); +#endif + +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_unlock_irqrestore(&priv->spn_lock.mac_filter, flags); +#endif + +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)) + if (is_valid_ether_addr(addr)) + eth_hw_addr_set(priv->dev, addr); + else +#else if (!is_valid_ether_addr(priv->dev->dev_addr)) +#endif eth_hw_addr_random(priv->dev); dev_info(priv->device, "device MAC address %pM\n", priv->dev->dev_addr); +#ifndef TC956X_SRIOV_VF } +#endif } +#endif /** * tc956xmac_init_dma_engine - DMA init. @@ -5169,6 +6032,7 @@ static int tc956xmac_init_dma_engine(struct tc956xmac_priv *priv) if (priv->extend_desc && (priv->mode == TC956XMAC_RING_MODE)) atds = 1; +#ifndef TC956X_SRIOV_VF ret = tc956xmac_reset(priv, priv->ioaddr); if (ret) { dev_err(priv->device, "Failed to reset the dma\n"); @@ -5180,16 +6044,35 @@ static int tc956xmac_init_dma_engine(struct tc956xmac_priv *priv) if (priv->plat->axi) tc956xmac_axi(priv, priv->ioaddr, priv->plat->axi); +#endif /* DMA CSR Channel configuration */ - for (chan = 0; chan < dma_csr_ch; chan++) + for (chan = 0; chan < dma_csr_ch; chan++) { +#ifdef TC956X_SRIOV_PF + if ((priv->plat->tx_ch_in_use[chan] == TC956X_DISABLE_CHNL) && + (priv->plat->rx_ch_in_use[chan] == TC956X_DISABLE_CHNL)) + continue; +#elif defined TC956X_SRIOV_VF + /* skip configuring for unallocated channel */ + if (priv->plat->ch_in_use[chan] == 0) + continue; +#endif tc956xmac_init_chan(priv, priv->ioaddr, priv->plat->dma_cfg, chan); + } /* DMA RX Channel Configuration */ for (chan = 0; chan < rx_channels_count; chan++) { +#ifdef TC956X_SRIOV_PF + if (priv->plat->rx_ch_in_use[chan] == TC956X_DISABLE_CHNL) + continue; +#elif defined TC956X_SRIOV_VF + /* skip configuring for unallocated channel */ + if (priv->plat->ch_in_use[chan] == 0) + continue; +#else if (priv->plat->rx_dma_ch_owner[chan] != USE_IN_TC956X_SW) continue; - +#endif rx_q = &priv->rx_queue[chan]; tc956xmac_init_rx_chan(priv, priv->ioaddr, priv->plat->dma_cfg, rx_q->dma_rx_phy, chan); @@ -5201,9 +6084,17 @@ static int tc956xmac_init_dma_engine(struct tc956xmac_priv *priv) /* DMA TX Channel Configuration */ for (chan = 0; chan < tx_channels_count; chan++) { +#ifdef TC956X_SRIOV_PF + if (priv->plat->tx_ch_in_use[chan] == TC956X_DISABLE_CHNL) + continue; +#elif defined TC956X_SRIOV_VF + /* skip configuring for unallocated channel */ + if (priv->plat->ch_in_use[chan] == 0) + continue; +#else if (priv->plat->tx_dma_ch_owner[chan] != USE_IN_TC956X_SW) continue; - +#endif tx_q = &priv->tx_queue[chan]; tc956xmac_init_tx_chan(priv, priv->ioaddr, priv->plat->dma_cfg, @@ -5221,8 +6112,12 @@ static int tc956xmac_init_dma_engine(struct tc956xmac_priv *priv) static void tc956xmac_tx_timer_arm(struct tc956xmac_priv *priv, u32 queue) { struct tc956xmac_tx_queue *tx_q = &priv->tx_queue[queue]; - +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)) + hrtimer_start(&tx_q->txtimer, + TC956XMAC_COAL_TIMER(priv->tx_coal_timer[queue]), HRTIMER_MODE_REL); +#else mod_timer(&tx_q->txtimer, TC956XMAC_COAL_TIMER(priv->tx_coal_timer)); +#endif } /** @@ -5231,17 +6126,44 @@ static void tc956xmac_tx_timer_arm(struct tc956xmac_priv *priv, u32 queue) * Description: * This is the timer handler to directly invoke the tc956xmac_tx_clean. */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)) +static enum hrtimer_restart tc956xmac_tx_timer(struct hrtimer *t) +#else static void tc956xmac_tx_timer(struct timer_list *t) +#endif { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)) + struct tc956xmac_tx_queue *tx_q = container_of(t, struct tc956xmac_tx_queue, txtimer); +#else struct tc956xmac_tx_queue *tx_q = from_timer(tx_q, t, txtimer); +#endif struct tc956xmac_priv *priv = tx_q->priv_data; struct tc956xmac_channel *ch; ch = &priv->channel[tx_q->queue_index]; - if (priv->plat->tx_dma_ch_owner[tx_q->queue_index] != USE_IN_TC956X_SW) +#ifdef TC956X_SRIOV_PF + if (priv->plat->tx_ch_in_use[tx_q->queue_index] == TC956X_DISABLE_CHNL) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)) + return HRTIMER_NORESTART; +#else return; - +#endif +#elif defined TC956X_SRIOV_VF + if (priv->plat->ch_in_use[tx_q->queue_index] == 0) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)) + return HRTIMER_NORESTART; +#else + return; +#endif +#else + if (priv->plat->tx_dma_ch_owner[tx_q->queue_index] != USE_IN_TC956X_SW) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)) + return HRTIMER_NORESTART; +#else + return; +#endif +#endif /* * If NAPI is already running we can miss some events. Let's rearm * the timer and try again. @@ -5254,6 +6176,11 @@ static void tc956xmac_tx_timer(struct timer_list *t) spin_unlock_irqrestore(&ch->lock, flags); __napi_schedule(&ch->tx_napi); } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)) + return HRTIMER_NORESTART; +#else + return; +#endif } #endif @@ -5271,19 +6198,46 @@ static void tc956xmac_init_coalesce(struct tc956xmac_priv *priv) #ifdef ENABLE_TX_TIMER u32 tx_channel_count = priv->plat->tx_queues_to_use; u32 chan; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 13, 0)) + u32 rx_channel_count = priv->plat->rx_queues_to_use; #endif +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 13, 0)) priv->tx_coal_frames = TC956XMAC_TX_FRAMES; priv->tx_coal_timer = TC956XMAC_COAL_TX_TIMER; priv->rx_coal_frames = TC956XMAC_RX_FRAMES; +#endif #ifdef ENABLE_TX_TIMER for (chan = 0; chan < tx_channel_count; chan++) { struct tc956xmac_tx_queue *tx_q = &priv->tx_queue[chan]; - +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 13, 0)) + priv->tx_coal_frames[chan] = TC956XMAC_TX_FRAMES; + priv->tx_coal_timer[chan] = TC956XMAC_COAL_TX_TIMER; +#endif +#ifdef TC956X_SRIOV_PF + if (priv->plat->tx_ch_in_use[chan] == TC956X_DISABLE_CHNL) + continue; +#elif defined TC956X_SRIOV_VF + /* skip configuring for unallocated channel */ + if (priv->plat->ch_in_use[chan] == 0) + continue; +#else if (priv->plat->tx_dma_ch_owner[chan] != USE_IN_TC956X_SW) continue; +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)) + hrtimer_init(&tx_q->txtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + tx_q->txtimer.function = tc956xmac_tx_timer; +#else timer_setup(&tx_q->txtimer, tc956xmac_tx_timer, 0); +#endif } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 13, 0)) + for (chan = 0; chan < rx_channel_count; chan++) + priv->rx_coal_frames[chan] = TC956XMAC_RX_FRAMES; +#endif #endif } @@ -5298,18 +6252,32 @@ static void tc956xmac_set_rings_length(struct tc956xmac_priv *priv) /* set TX ring length */ for (chan = 0; chan < tx_channels_count; chan++) { +#ifdef TC956X_SRIOV_PF + if (priv->plat->tx_ch_in_use[chan] == TC956X_DISABLE_CHNL) + continue; +#elif defined TC956X_SRIOV_VF + if (priv->plat->ch_in_use[chan] == 0) + continue; +#else if (priv->plat->tx_dma_ch_owner[chan] != USE_IN_TC956X_SW) continue; - +#endif tc956xmac_set_tx_ring_len(priv, priv->ioaddr, (DMA_TX_SIZE - 1), chan); } /* set RX ring length */ for (chan = 0; chan < rx_channels_count; chan++) { +#ifdef TC956X_SRIOV_PF + if (priv->plat->rx_ch_in_use[chan] == TC956X_DISABLE_CHNL) + continue; +#elif defined TC956X_SRIOV_VF + if (priv->plat->ch_in_use[chan] == 0) + continue; +#else if (priv->plat->rx_dma_ch_owner[chan] != USE_IN_TC956X_SW) continue; - +#endif tc956xmac_set_rx_ring_len(priv, priv->ioaddr, (DMA_RX_SIZE - 1), chan); } @@ -5324,11 +6292,35 @@ static void tc956xmac_set_tx_queue_weight(struct tc956xmac_priv *priv) { u32 tx_queues_count = priv->plat->tx_queues_to_use; u32 weight; - u32 queue; + u32 queue, traffic_class; + + /* Set weights for Traffic class based on Queue enable state */ for (queue = 0; queue < tx_queues_count; queue++) { +#ifdef TC956X_SRIOV_PF + if (priv->plat->tx_q_in_use[queue] == TC956X_DISABLE_QUEUE) + continue; +#elif defined TC956X_SRIOV_VF + /* skip configuring for unallocated queue */ + if (priv->plat->tx_q_in_use[queue] == 0) + continue; +#endif + + traffic_class = priv->plat->tx_queues_cfg[queue].traffic_class; +#ifdef TC956X_SRIOV_VF + /* TC0 related configuration is done in PF only */ + if (traffic_class == TX_TC_ZERO) + continue; +#endif weight = priv->plat->tx_queues_cfg[queue].weight; - tc956xmac_set_mtl_tx_queue_weight(priv, priv->hw, weight, queue); + + /* Use mailbox wrapper API to pass to PF for updation */ +#ifdef TC956X_SRIOV_PF + tc956xmac_set_mtl_tx_queue_weight(priv, priv->hw, weight, traffic_class); +#elif (defined TC956X_SRIOV_VF) + tc956xmac_set_mtl_tx_queue_weight(priv, weight, traffic_class); +#endif + } } @@ -5342,24 +6334,51 @@ static void tc956xmac_configure_cbs(struct tc956xmac_priv *priv) u32 tx_queues_count = priv->plat->tx_queues_to_use; u32 mode_to_use; u32 queue; +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + unsigned long flags; +#endif /* queue 0 is reserved for legacy traffic */ for (queue = 1; queue < tx_queues_count; queue++) { +#ifdef TC956X_SRIOV_PF + if (priv->plat->tx_q_in_use[queue] == TC956X_DISABLE_QUEUE) + continue; +#elif defined TC956X_SRIOV_VF + /* skip configuring for unallocated queue */ + if (priv->plat->tx_q_in_use[queue] == 0) + continue; +#endif mode_to_use = priv->plat->tx_queues_cfg[queue].mode_to_use; if (mode_to_use != MTL_QUEUE_AVB) continue; -#ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE +/* Mailbox to be used for CBS configuration */ +#ifdef TC956X_SRIOV_PF +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_lock_irqsave(&priv->spn_lock.cbs, flags); +#endif tc956xmac_config_cbs(priv, priv->hw, priv->plat->tx_queues_cfg[queue].send_slope, priv->plat->tx_queues_cfg[queue].idle_slope, priv->plat->tx_queues_cfg[queue].high_credit, priv->plat->tx_queues_cfg[queue].low_credit, queue); -#endif /* TC956X_UNSUPPORTED_UNTESTED_FEATURE */ +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_unlock_irqrestore(&priv->spn_lock.cbs, flags); +#endif +#elif (defined TC956X_SRIOV_VF) + tc956xmac_config_cbs(priv, + priv->plat->tx_queues_cfg[queue].send_slope, + priv->plat->tx_queues_cfg[queue].idle_slope, + priv->plat->tx_queues_cfg[queue].high_credit, + priv->plat->tx_queues_cfg[queue].low_credit, + queue); +#endif + } } +#ifndef TC956X_SRIOV_VF /** * tc956xmac_rx_queue_dma_chan_map - Map RX queue to RX dma channel * @priv: driver private structure @@ -5372,6 +6391,11 @@ static void tc956xmac_rx_queue_dma_chan_map(struct tc956xmac_priv *priv) u32 chan; for (queue = 0; queue < rx_queues_count; queue++) { +#ifdef TC956X_SRIOV_PF + if (priv->plat->rx_q_in_use[queue] == TC956X_DISABLE_QUEUE) + continue; +#endif + /* Enable DA based Queue-Ch mapping for elabled Queues */ chan = priv->plat->rx_queues_cfg[queue].chan; tc956xmac_map_mtl_to_dma(priv, priv->hw, queue, chan); } @@ -5396,7 +6420,7 @@ static void tc956xmac_mac_config_rx_queues_prio(struct tc956xmac_priv *priv) tc956xmac_rx_queue_prio(priv, priv->hw, prio, queue); } } - +#endif /** * tc956xmac_mac_config_tx_queues_prio - Configure TX Queue priority * @priv: driver private structure @@ -5407,16 +6431,33 @@ static void tc956xmac_mac_config_tx_queues_prio(struct tc956xmac_priv *priv) u32 tx_queues_count = priv->plat->tx_queues_to_use; u32 queue; u32 prio; + u32 traffic_class; for (queue = 0; queue < tx_queues_count; queue++) { +#ifdef TC956X_SRIOV_VF + /* skip configuring for unallocated queue */ + if (priv->plat->tx_q_in_use[queue] == 0) + continue; +#endif if (!priv->plat->tx_queues_cfg[queue].use_prio) continue; prio = priv->plat->tx_queues_cfg[queue].prio; + + traffic_class = priv->plat->tx_queues_cfg[queue].traffic_class; + +#ifdef TC956X_SRIOV_PF + tc956xmac_tx_queue_prio(priv, priv->hw, prio, traffic_class); +#elif defined TC956X_SRIOV_VF + tc956xmac_tx_queue_prio(priv, prio, traffic_class); +#else tc956xmac_tx_queue_prio(priv, priv->hw, prio, queue); +#endif } } +#ifndef TC956X_SRIOV_VF + /** * tc956xmac_mac_config_rx_queues_routing - Configure RX Queue Routing * @priv: driver private structure @@ -5454,7 +6495,7 @@ static void tc956xmac_mac_config_rss(struct tc956xmac_priv *priv) priv->plat->rx_queues_to_use); #endif /* TC956X_UNSUPPORTED_UNTESTED_FEATURE */ } - +#endif /* TC956X_SRIOV_VF */ /** * tc956xmac_mtl_configuration - Configure MTL * @priv: driver private structure @@ -5462,12 +6503,15 @@ static void tc956xmac_mac_config_rss(struct tc956xmac_priv *priv) */ static void tc956xmac_mtl_configuration(struct tc956xmac_priv *priv) { +#ifndef TC956X_SRIOV_VF u32 rx_queues_count = priv->plat->rx_queues_to_use; +#endif u32 tx_queues_count = priv->plat->tx_queues_to_use; if (tx_queues_count > 1) tc956xmac_set_tx_queue_weight(priv); +#ifndef TC956X_SRIOV_VF /* Configure MTL RX algorithms */ if (rx_queues_count > 1) tc956xmac_prog_mtl_rx_algorithms(priv, priv->hw, @@ -5477,11 +6521,16 @@ static void tc956xmac_mtl_configuration(struct tc956xmac_priv *priv) if (tx_queues_count > 1) tc956xmac_prog_mtl_tx_algorithms(priv, priv->hw, priv->plat->tx_sched_algorithm); +#endif /* Configure CBS in AVB TX queues */ if (tx_queues_count > 1) tc956xmac_configure_cbs(priv); +/* Some of Rx queue are shared among more than one VF (DMA channels), + * so Rx queue configuration will be done by PF commonly + */ +#ifndef TC956X_SRIOV_VF /* Map RX MTL to DMA channels */ tc956xmac_rx_queue_dma_chan_map(priv); @@ -5503,8 +6552,15 @@ static void tc956xmac_mtl_configuration(struct tc956xmac_priv *priv) /* Receive Side Scaling */ if (rx_queues_count > 1) tc956xmac_mac_config_rss(priv); +#else + /* Set TX priorities */ + if (tx_queues_count > 1) + tc956xmac_mac_config_tx_queues_prio(priv); +#endif } +#ifndef TC956X_SRIOV_VF + static void tc956xmac_safety_feat_configuration(struct tc956xmac_priv *priv) { if (priv->dma_cap.asp) { @@ -5542,7 +6598,7 @@ static void tc956x_rx_crc_pad_config(struct tc956xmac_priv *priv, u32 crc_pad) writel(value, priv->ioaddr + XGMAC_RX_CONFIG); #endif } - +#endif /** * tc956xmac_hw_setup - setup mac in a usable state. * @dev : pointer to the device structure. @@ -5560,13 +6616,22 @@ static int tc956xmac_hw_setup(struct net_device *dev, bool init_ptp) struct tc956xmac_priv *priv = netdev_priv(dev); #ifdef TC956X u32 rx_cnt = priv->plat->rx_queues_to_use; +#ifndef TC956X_SRIOV_VF bool enable_en = true; #endif - +#endif + u8 dev_addr[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 13, 0)) + u32 queue; +#endif u32 tx_cnt = priv->plat->tx_queues_to_use; u32 chan; int ret; +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + unsigned long flags; +#endif + /* Back up MMC registers into internal SW MMC counters */ if (priv->link_down_rst == true) tc956xmac_mmc_read(priv, priv->mmcaddr, &priv->mmc); @@ -5580,9 +6645,30 @@ static int tc956xmac_hw_setup(struct net_device *dev, bool init_ptp) return ret; } +#ifdef TC956X_SRIOV_PF +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_lock_irqsave(&priv->spn_lock.mac_filter, flags); +#endif /* Copy the MAC addr into the HW */ - tc956xmac_set_umac_addr(priv, priv->hw, dev->dev_addr, HOST_MAC_ADDR_OFFSET, PF_DRIVER); + tc956xmac_set_umac_addr(priv, priv->hw, (unsigned char *)dev->dev_addr, HOST_MAC_ADDR_OFFSET, PF_DRIVER); + /* Adding Broadcast address to offset 0 to divert Rx packet to PF Legacy Channel */ + tc956xmac_set_umac_addr(priv, priv->hw, &dev_addr[0], HOST_BC_ADDR_OFFSET, PF_DRIVER); + +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_unlock_irqrestore(&priv->spn_lock.mac_filter, flags); +#endif + +#elif defined TC956X_SRIOV_VF + ret = -EBUSY; + while (ret == -EBUSY) + ret = tc956xmac_set_umac_addr(priv, dev_addr, 0); + ret = -EBUSY; + while (ret == -EBUSY) + ret = tc956xmac_set_umac_addr(priv, dev->dev_addr, HOST_MAC_ADDR_OFFSET + priv->fn_id_info.vf_no); +#endif + +#ifndef TC956X_SRIOV_VF /* No speed related and core init in VF */ /* PS and related bits will be programmed according to the speed */ #ifdef TC956X if (priv->hw->pcs || priv->hw->xpcs) { @@ -5603,27 +6689,63 @@ static int tc956xmac_hw_setup(struct net_device *dev, bool init_ptp) /* Initialize the MAC Core */ tc956xmac_core_init(priv, priv->hw, dev); - +#endif +#ifndef TC956X_SRIOV_VF /* Enable Jumbo Frame Support */ tc956xmac_jumbo_en(priv, dev, TC956X_ENABLE); +#ifdef TC956X_SRIOV_PF + /* Update driver cap to let VF know about feature enable/disable */ + priv->pf_drv_cap.jumbo_en = true; +#elif (defined TC956X_SRIOV_VF) + /* Check if Jumbo frames Initialized in PF */ + if (priv->pf_drv_cap.jumbo_en) + NMSGPR_INFO(priv->device, "Jumbo Frames supported\n"); +#endif +#endif /* Initialize MTL*/ tc956xmac_mtl_configuration(priv); + /* Safety feature not supported aswell not configured by VF*/ +#ifndef TC956X_SRIOV_VF /* Initialize Safety Features */ tc956xmac_safety_feat_configuration(priv); +#endif +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_lock_irqsave(&priv->spn_lock.frp, flags); +#endif ret = tc956xmac_rx_parser_configuration(priv); +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_unlock_irqrestore(&priv->spn_lock.frp, flags); +#endif + /* Rx checksum offload configuration is done by PF + * VF driver should know the status of core register configuration + */ +#ifndef TC956X_SRIOV_VF ret = tc956xmac_rx_ipc(priv, priv->hw); if (!ret) { +#else + if (!priv->pf_drv_cap.csum_en) { +#endif netdev_warn(priv->dev, "RX IPC Checksum Offload disabled\n"); priv->plat->rx_coe = TC956XMAC_RX_COE_NONE; priv->hw->rx_csum = 0; +#ifdef TC956X_SRIOV_PF + /* Update driver cap to let VF know about feature enable/disable + */ + priv->pf_drv_cap.csum_en = false; + } else { + /* Update driver cap to let VF know about feature enable/disable */ + priv->pf_drv_cap.csum_en = true; + priv->rx_csum_state = priv->hw->rx_csum; +#endif } +#ifndef TC956X_SRIOV_VF /* Enable the MAC Rx/Tx */ tc956xmac_mac_set(priv, priv->ioaddr, true); - +#endif /* Set the HW DMA mode and the COE */ tc956xmac_dma_operation_mode(priv); @@ -5635,8 +6757,16 @@ static int tc956xmac_hw_setup(struct net_device *dev, bool init_ptp) priv->tx_crc_pad_state = TC956X_TX_CRC_PAD_INSERT; priv->rx_crc_pad_state = TC956X_RX_CRC_DEFAULT; + /* In SRIOV case the RX CRC configuration is handled by PF as it + * impacts all drivers + */ +#ifndef TC956X_SRIOV_VF tc956x_rx_crc_pad_config(priv, priv->rx_crc_pad_state); +#ifdef TC956X_SRIOV_PF + /* Update driver cap to let VF know about feature enable/disable */ + priv->pf_drv_cap.crc_en = priv->rx_crc_pad_state; +#endif if (init_ptp) { ret = clk_prepare_enable(priv->plat->clk_ptp_ref); @@ -5649,14 +6779,28 @@ static int tc956xmac_hw_setup(struct net_device *dev, bool init_ptp) else if (ret) netdev_warn(priv->dev, "PTP init failed\n"); } - +#endif if (priv->use_riwt) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 13, 0)) + for (queue = 0; queue < rx_cnt; queue++) { + if (!priv->rx_riwt[queue]) + priv->rx_riwt[queue] = DEF_DMA_RIWT; + + ret = tc956xmac_rx_watchdog(priv, priv->ioaddr, priv->rx_riwt[queue], queue); + } +#else if (!priv->rx_riwt) priv->rx_riwt = DEF_DMA_RIWT; ret = tc956xmac_rx_watchdog(priv, priv->ioaddr, priv->rx_riwt, rx_cnt); + +#endif } + /* Auto negotiation not applicable for VF + * PTP configuration not applicable for VF + */ +#ifndef TC956X_SRIOV_VF #ifdef TC956X if (priv->hw->xpcs) { /*C37 AN enable*/ @@ -5677,6 +6821,10 @@ static int tc956xmac_hw_setup(struct net_device *dev, bool init_ptp) tc956xmac_pcs_ctrl_ane(priv, priv->ioaddr, 1, priv->hw->ps, 0); #endif tc956x_ptp_configuration(priv, 0); +#else + /* PTP init should have been done in PF */ + priv->hwts_rx_en = 1; +#endif /*#ifdef TC956X_SRIOV_VF*/ /* set TX and RX rings length */ tc956xmac_set_rings_length(priv); @@ -5684,17 +6832,32 @@ static int tc956xmac_hw_setup(struct net_device *dev, bool init_ptp) /* Enable TSO */ if (priv->tso) { for (chan = 0; chan < tx_cnt; chan++) { +#ifdef TC956X_SRIOV_VF + if (priv->plat->ch_in_use[chan] == 0) + continue; + if (priv->plat->tx_queues_cfg[chan].tso_en && priv->tso) +#else if (priv->plat->tx_queues_cfg[chan].tso_en) +#endif + tc956xmac_enable_tso(priv, priv->ioaddr, 1, chan); } } /* Enable Split Header */ if (priv->sph && priv->hw->rx_csum) { - for (chan = 0; chan < rx_cnt; chan++) - tc956xmac_enable_sph(priv, priv->ioaddr, 1, chan); + for (chan = 0; chan < rx_cnt; chan++) { +#ifdef TC956X_SRIOV_PF + if (priv->plat->tx_queues_cfg[chan].tso_en) +#elif defined TC956X_SRIOV_VF + if (priv->plat->ch_in_use[chan] == 0) + continue; +#endif + tc956xmac_enable_sph(priv, priv->ioaddr, 1, chan); + } } +#ifndef TC956X_SRIOV_VF /* VLAN Tag Insertion */ #ifndef TC956X if (priv->dma_cap.vlins) @@ -5702,18 +6865,38 @@ static int tc956xmac_hw_setup(struct net_device *dev, bool init_ptp) if ((priv->dma_cap.vlins) && (dev->features & NETIF_F_HW_VLAN_CTAG_TX)) #endif tc956xmac_enable_vlan(priv, priv->hw, TC956XMAC_VLAN_INSERT); +#endif /* TBS */ for (chan = 0; chan < tx_cnt; chan++) { struct tc956xmac_tx_queue *tx_q = &priv->tx_queue[chan]; int enable = tx_q->tbs & TC956XMAC_TBS_AVAIL; +#ifdef TC956X_SRIOV_PF + if (priv->plat->tx_ch_in_use[chan] == TC956X_DISABLE_CHNL) + continue; + + if (priv->plat->tx_queues_cfg[chan].tbs_en == TC956X_DISABLE) + continue; +#elif defined TC956X_SRIOV_VF + if (priv->plat->ch_in_use[chan] == 0) + continue; +#endif tc956xmac_enable_tbs(priv, priv->ioaddr, enable, chan); } + /* PF driver to configure EST for all functions */ +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_lock_irqsave(&priv->spn_lock.est, flags); +#endif +#ifndef TC956X_SRIOV_VF if (priv->plat->est->enable) tc956xmac_est_configure(priv, priv->ioaddr, priv->plat->est, priv->plat->clk_ptp_rate); +#endif +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_unlock_irqrestore(&priv->spn_lock.est, flags); +#endif /* Start the ball rolling... */ tc956xmac_start_all_dma(priv); @@ -5721,6 +6904,7 @@ static int tc956xmac_hw_setup(struct net_device *dev, bool init_ptp) return 0; } +#ifndef TC956X_SRIOV_VF static void tc956xmac_hw_teardown(struct net_device *dev) { struct tc956xmac_priv *priv = netdev_priv(dev); @@ -5728,6 +6912,67 @@ static void tc956xmac_hw_teardown(struct net_device *dev) clk_disable_unprepare(priv->plat->clk_ptp_ref); } + +static void tc956xmac_set_cbs_default(struct tc956xmac_priv *priv) +{ + u32 queue_idx; + u32 tx_queue_cnt = priv->plat->tx_queues_to_use; + + for (queue_idx = 0 ; queue_idx < tx_queue_cnt; queue_idx++) { + if (priv->plat->tx_queues_cfg[queue_idx].mode_to_use == MTL_QUEUE_AVB) { + /* CBS: queue 5/6/7 -> Class A/B/CDT traffic (25% BW) */ + priv->cbs_speed100_cfg[queue_idx].idle_slope = 0x400; + priv->cbs_speed100_cfg[queue_idx].send_slope = 0xc00; + priv->cbs_speed100_cfg[queue_idx].high_credit = 0x320000; + priv->cbs_speed100_cfg[queue_idx].low_credit = 0xFF6A0000; + + priv->cbs_speed1000_cfg[queue_idx].idle_slope = 0x800; + priv->cbs_speed1000_cfg[queue_idx].send_slope = 0x1800; + priv->cbs_speed1000_cfg[queue_idx].high_credit = 0x320000; + priv->cbs_speed1000_cfg[queue_idx].low_credit = 0xFF6A0000; + + priv->cbs_speed2500_cfg[queue_idx].idle_slope = 0x800; + priv->cbs_speed2500_cfg[queue_idx].send_slope = 0x1800; + priv->cbs_speed2500_cfg[queue_idx].high_credit = 0x320000; + priv->cbs_speed2500_cfg[queue_idx].low_credit = 0xFF6A0000; + + priv->cbs_speed5000_cfg[queue_idx].idle_slope = 0x2000; + priv->cbs_speed5000_cfg[queue_idx].send_slope = 0x6000; + priv->cbs_speed5000_cfg[queue_idx].high_credit = 0x320000; + priv->cbs_speed5000_cfg[queue_idx].low_credit = 0xFF6A0000; + + priv->cbs_speed10000_cfg[queue_idx].idle_slope = 0x2000; + priv->cbs_speed10000_cfg[queue_idx].send_slope = 0x6000; + priv->cbs_speed10000_cfg[queue_idx].high_credit = 0x320000; + priv->cbs_speed10000_cfg[queue_idx].low_credit = 0xFF6A0000; + } + } + +} + +#ifdef TC956X_SRIOV_PF +/** + * tc956x_pf_vf_ch_alloc - Configure Resource Manager Module to allocate + * EMAC DMA channel for PF and VF. + * @ndev : pointer to the device structure. + * Description: + * Configure Resource Manager Module to allocate EMAC DMA channel for + * PF and VF. + * Return value: + * 0 on success and (-)ve integer on failure. + */ +static int tc956x_pf_vf_ch_alloc(struct net_device *ndev) +{ + struct tc956xmac_priv *priv = netdev_priv(ndev); + + tc956xmac_rsc_mng_set_rscs(priv, ndev, &priv->rsc_dma_ch_alloc[0]); + + return 0; +} + +#endif +#endif + /** * tc956xmac_open - open entry point of the driver * @dev : pointer to the device structure. @@ -5740,9 +6985,19 @@ static void tc956xmac_hw_teardown(struct net_device *dev) static int tc956xmac_open(struct net_device *dev) { struct tc956xmac_priv *priv = netdev_priv(dev); + struct pci_dev *pdev = container_of(priv->device, struct pci_dev, dev); + int bfsize = 0; u32 chan, rd_val; - int ret; + int ret, irq_no; +#ifdef TC956X_SRIOV_VF + u32 link_status = 0; + u32 speed; + u32 duplex; + int state_count = 0; +#endif + +#ifndef TC956X_SRIOV_VF struct phy_device *phydev; int addr = priv->plat->phy_addr; @@ -5754,6 +7009,8 @@ static int tc956xmac_open(struct net_device *dev) tc956xmac_create_debugfs(priv->dev);/*Creating Debugfs*/ #endif + +#ifndef TC956X_SRIOV_VF mutex_lock(&priv->port_ld_release_lock); priv->port_release = false; /* setting port release to false as Open invoked, and set to true from release or link down */ if (priv->port_link_down == true) { @@ -5761,6 +7018,8 @@ static int tc956xmac_open(struct net_device *dev) } mutex_unlock(&priv->port_ld_release_lock); +#endif + if (!phydev) { netdev_err(priv->dev, "no phy at addr %d\n", addr); return -ENODEV; @@ -5780,7 +7039,7 @@ static int tc956xmac_open(struct net_device *dev) } } } - +#ifdef TC956X_AUTOMOTIVE_CONFIG /* Do not re-allocate host resources during resume sequence. Only re-initialize resources */ if (priv->tc956x_port_pm_suspend == false) { /* Extra statistics */ @@ -5794,11 +7053,6 @@ static int tc956xmac_open(struct net_device *dev) if (bfsize < BUF_SIZE_16KiB) bfsize = tc956xmac_set_bfsize(dev->mtu, priv->dma_buf_sz); - /* Overwrite buff size allocated to 2K, to accomodate max mtu supported of 2000 bytes, - * so that no buffer reconfiguration required during MTU change - */ - bfsize = BUF_SIZE_2KiB; - priv->dma_buf_sz = bfsize; buf_sz = bfsize; @@ -5818,6 +7072,108 @@ static int tc956xmac_open(struct net_device *dev) tx_q->tbs &= ~TC956XMAC_TBS_AVAIL; } } +#endif +#ifdef TC956X_SRIOV_PF + /* Retrieve Function ID */ + ret = tc956xmac_rsc_mng_get_fn_id(priv, priv->tc956x_BRIDGE_CFG_pci_base_addr, &priv->fn_id_info); + if (ret < 0) { + netdev_err(priv->dev, "%s: Invalid SRIOV Function ID\n", + __func__); + return ret; + } + + priv->port_num = priv->fn_id_info.pf_no; + + if (priv->fn_id_info.fn_type == RM_IS_PF) { + /* Allocate DMA channels for PF & VF. + * To be called from both PFs + */ + KPRINT_INFO("%s: SRIOV Rsc Mgr Channel Allocation\n", __func__); + ret = tc956x_pf_vf_ch_alloc(dev); + if (ret < 0) { + netdev_err(priv->dev, "%s: SRIOV CH Alloc failed\n", + __func__); + return ret; + } + } +#endif +#ifdef TC956X_SRIOV_PF + priv->dma_vf_map[0] = 0; //vf1 + priv->dma_vf_map[1] = 1; //vf2 + priv->dma_vf_map[2] = 2; //vf3 + priv->dma_vf_map[3] = 3; //pf + priv->dma_vf_map[4] = 3; + priv->dma_vf_map[5] = 0; + priv->dma_vf_map[6] = 2; + priv->dma_vf_map[7] = 2; + + priv->pf_queue_dma_map[0] = 3; + priv->pf_queue_dma_map[1] = 3; + priv->pf_queue_dma_map[2] = 4; + priv->pf_queue_dma_map[3] = 3; + priv->pf_queue_dma_map[4] = 8; //NA to PF + priv->pf_queue_dma_map[5] = 8; //NA to PF + priv->pf_queue_dma_map[6] = 8; //NA to PF + priv->pf_queue_dma_map[7] = 3; +#endif +#ifdef TC956X_SRIOV_PF + tc956xmac_mbx_init(priv, NULL); +#endif + + /* Extra statistics */ + memset(&priv->xstats, 0, sizeof(struct tc956xmac_extra_stats)); + priv->xstats.threshold = tc; +#elif defined TC956X_SRIOV_VF + memset(&priv->sw_stats, 0, sizeof(struct tc956x_sw_counters)); +#endif + +#ifdef TC956X_SRIOV_VF + tc956xmac_get_link_status(priv, &link_status, &speed, &duplex); + + while (link_status != true && state_count < 10) { + tc956xmac_get_link_status(priv, &link_status, &speed, &duplex); + state_count++; + udelay(100); + } +#endif + bfsize = tc956xmac_set_16kib_bfsize(priv, dev->mtu); + if (bfsize < 0) + bfsize = 0; + + if (bfsize < BUF_SIZE_16KiB) + bfsize = tc956xmac_set_bfsize(dev->mtu, priv->dma_buf_sz); + + priv->dma_buf_sz = bfsize; + buf_sz = bfsize; + +#ifdef TC956X_SRIOV_PF + tc956xmac_set_cbs_default(priv); +#endif + + priv->rx_copybreak = TC956XMAC_RX_COPYBREAK; + + /* Earlier check for TBS */ + for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) { + struct tc956xmac_tx_queue *tx_q = &priv->tx_queue[chan]; + int tbs_en = priv->plat->tx_queues_cfg[chan].tbs_en; +#ifdef TC956X_SRIOV_PF + if (priv->plat->tx_ch_in_use[chan] == + TC956X_DISABLE_CHNL) + continue; +#elif defined TC956X_SRIOV_VF + /* skip configuring for unallocated channel */ + if (priv->plat->ch_in_use[chan] == 0) + continue; +#endif + /* Set TC956XMAC_TBS_EN by default. Later allow tc command to + *enable/disable + */ + tx_q->tbs |= tbs_en ? TC956XMAC_TBS_AVAIL | TC956XMAC_TBS_EN : 0; + + if (tc956xmac_enable_tbs(priv, priv->ioaddr, tbs_en, chan)) + tx_q->tbs &= ~TC956XMAC_TBS_AVAIL; + } + ret = alloc_dma_desc_resources(priv); if (ret < 0) { netdev_err(priv->dev, "%s: DMA descriptors allocation failed\n", @@ -5838,120 +7194,68 @@ static int tc956xmac_open(struct net_device *dev) /*goto init_error;*/ } + #ifdef TC956X - if (priv->port_num == RM_PF0_ID) { - /* mask all eMAC interrupts for MCU */ + +#ifdef TC956X_SRIOV_PF + + /* Masked all interrupts. + * Interrupts to CM3 to be enabled in FW + */ + if ((priv->fn_id_info.fn_type == RM_IS_PF) && (priv->fn_id_info.pf_no == RM_PF0_ID)) { rd_val = readl(priv->ioaddr + INTMCUMASK0); - rd_val |= 0xFFFF1FFF; + rd_val |= TC956X_INT_MASK0; writel(rd_val, priv->ioaddr + INTMCUMASK0); } - - if (priv->port_num == RM_PF1_ID) { - /* mask all eMAC interrupts for MCU */ + if ((priv->fn_id_info.fn_type == RM_IS_PF) && (priv->fn_id_info.pf_no == RM_PF1_ID)) { rd_val = readl(priv->ioaddr + INTMCUMASK1); - rd_val |= 0xFFFF1F80; + rd_val |= TC956X_INT_MASK1; writel(rd_val, priv->ioaddr + INTMCUMASK1); } - - /* MSIGEN block is common for Port0 and Port1 */ - rd_val = readl(priv->ioaddr + NCLKCTRL0_OFFSET); - rd_val |= (1 << 18); /* MSIGENCEN=1 */ #ifdef EEE_MAC_CONTROLLED_MODE if (priv->port_num == RM_PF0_ID) { rd_val |= (NCLKCTRL0_MAC0312CLKEN | NCLKCTRL0_MAC0125CLKEN); } rd_val |= (NCLKCTRL0_POEPLLCEN | NCLKCTRL0_SGMPCIEN | NCLKCTRL0_REFCLKOCEN); #endif - writel(rd_val, priv->ioaddr + NCLKCTRL0_OFFSET); - rd_val = readl(priv->ioaddr + NRSTCTRL0_OFFSET); - rd_val &= ~(1 << 18); /* MSIGENSRST=0 */ -#ifdef EEE_MAC_CONTROLLED_MODE - //rd_val &= ~(NRSTCTRL0_MAC0RST | NRSTCTRL0_MAC0RST); -#endif - writel(rd_val, priv->ioaddr + NRSTCTRL0_OFFSET); - - /* Initialize MSIGEN */ + tc956x_msi_init(priv, dev); - /* MSI_OUT_EN: Disable all first */ - writel(0x00000000, priv->ioaddr + TC956X_MSI_OUT_EN_OFFSET(priv->port_num)); - /* MSI_MASK_SET: mask all vectors other than vector 0 */ - writel(0xfffffffe, priv->ioaddr + TC956X_MSI_MASK_SET_OFFSET(priv->port_num)); - /* MSI_MASK_CLR: unmask vector 0 */ - writel(0x00000001, priv->ioaddr + TC956X_MSI_MASK_CLR_OFFSET(priv->port_num)); - /* MSI_VECT_SET0: All INTs mapped to vector 0 */ - writel(0x00000000, priv->ioaddr + TC956X_MSI_VECT_SET0_OFFSET(priv->port_num)); - /* MSI_VECT_SET1: All INTs mapped to vector 0 */ - writel(0x00000000, priv->ioaddr + TC956X_MSI_VECT_SET1_OFFSET(priv->port_num)); - /* MSI_VECT_SET2: All INTs mapped to vector 0 */ - writel(0x00000000, priv->ioaddr + TC956X_MSI_VECT_SET2_OFFSET(priv->port_num)); - /* MSI_VECT_SET3: All INTs mapped to vector 0 */ - writel(0x00000000, priv->ioaddr + TC956X_MSI_VECT_SET3_OFFSET(priv->port_num)); - /* MSI_VECT_SET4: All INTs mapped to vector 0 */ - writel(0x00000000, priv->ioaddr + TC956X_MSI_VECT_SET4_OFFSET(priv->port_num)); - /* MSI_VECT_SET5: All INTs mapped to vector 0 */ - writel(0x00000000, priv->ioaddr + TC956X_MSI_VECT_SET5_OFFSET(priv->port_num)); - /* MSI_VECT_SET6: All INTs mapped to vector 0 */ - writel(0x00000000, priv->ioaddr + TC956X_MSI_VECT_SET6_OFFSET(priv->port_num)); - /* MSI_VECT_SET7: All INTs mapped to vector 0 */ - writel(0x00000000, priv->ioaddr + TC956X_MSI_VECT_SET7_OFFSET(priv->port_num)); - - /* Disable MSI for Tx/Rx channels that do not belong to Host */ - rd_val = 0; - for (chan = 0; chan < MTL_MAX_TX_QUEUES; chan++) { - if (priv->plat->tx_dma_ch_owner[chan] != USE_IN_TC956X_SW) - rd_val |= (1 << (MSI_INT_TX_CH0 + chan)); - } - - for (chan = 0; chan < MTL_MAX_RX_QUEUES; chan++) { - if (priv->plat->rx_dma_ch_owner[chan] != USE_IN_TC956X_SW) - rd_val |= (1 << (MSI_INT_RX_CH0 + chan)); - } - - if (phydev->interrupts == PHY_INTERRUPT_DISABLED) { - /* PHY MSI interrupt diabled */ - rd_val |= (1 << MSI_INT_EXT_PHY); - } - - /* rd_val |= (1 << 2); *//* Disable MSI for MAC EVENT Interrupt */ - /* Disable MAC Event and XPCS interrupt */ - rd_val = ENABLE_MSI_INTR & (~rd_val); - -#ifdef TC956X_SW_MSI - /* Enable SW MSI interrupt */ - KPRINT_INFO("%s Enable SW MSI", __func__); - rd_val |= (1 << MSI_INT_SW_MSI); - - /*Clear SW MSI*/ - writel(1, priv->ioaddr + TC956X_MSI_SW_MSI_CLR(priv->port_num)); - -#endif - writel(rd_val, priv->ioaddr + TC956X_MSI_OUT_EN_OFFSET(priv->port_num)); /* MSI_OUT_EN: Enable All mac int */ +#elif defined TC956X_SRIOV_VF + /* Initialize MSIGEN */ + tc956x_msi_init(priv, dev, &priv->fn_id_info); #endif +#endif /* TC956X */ tc956xmac_init_coalesce(priv); + +#ifndef TC956X_SRIOV_VF if (priv->link_down_rst == false) { if (priv->phylink) phylink_start(priv->phylink); } KPRINT_INFO("%s phylink started", __func__); +#endif +#if defined(TC956X_SRIOV_PF) | defined(TC956X_SRIOV_VF) + irq_no = pci_irq_vector(pdev, TC956X_MSI_VECTOR_0); if (priv->link_down_rst == false) { + /* Request the IRQ lines */ - ret = request_irq(dev->irq, tc956xmac_interrupt, - IRQF_NO_SUSPEND, IRQ_DEV_NAME(priv->port_num), dev); + ret = request_irq(irq_no, tc956xmac_interrupt_v0, + IRQF_NO_SUSPEND, dev->name, dev); if (unlikely(ret < 0)) { netdev_err(priv->dev, - "%s: ERROR: allocating the IRQ %d (error: %d)\n", + "%s: ERROR: allocating the IRQ 0 : %d (error: %d)\n", __func__, dev->irq, ret); goto irq_error; } - +#ifdef TC956X_SRIOV_PF /* Do not re-request WOL irq resources during resume sequence. */ if (priv->tc956x_port_pm_suspend == false) { /* Request the Wake IRQ in case of another line is used for WoL */ @@ -5981,29 +7285,111 @@ static int tc956xmac_open(struct net_device *dev) priv->tc956xmac_pm_wol_interrupt = false; /* Initialize flag for PHY Work queue */ } } +#endif /* TC956X_SRIOV_PF */ + +#if defined(TC956X_SRIOV_PF) && !defined(TC956X_AUTOMOTIVE_CONFIG) && !defined(TC956X_ENABLE_MAC2MAC_BRIDGE) + irq_no = pci_irq_vector(pdev, TC956X_MSI_VECTOR_1); + + ret = request_irq(irq_no, tc956xmac_interrupt_v1, + IRQF_SHARED, dev->name, dev); + if (unlikely(ret < 0)) { + netdev_err(priv->dev, + "%s: ERROR: allocating the IRQ 1 : %d (error: %d)\n", + __func__, dev->irq, ret); + goto irq_error; + } +#else + netdev_info(priv->dev, "%s: Only one interrupt handler registered\n", + __func__); +#endif +#endif + +#ifdef TC956X_SRIOV_PF + /* Enable MSIGEN interrupt */ + tc956x_msi_intr_en(priv, dev, TC956X_ENABLE); + +#elif defined TC956X_SRIOV_VF + /* Enable MSIGEN interrupt */ + tc956x_msi_intr_en(priv, dev, TC956X_ENABLE, &priv->fn_id_info); +#endif tc956xmac_enable_all_queues(priv); + tc956xmac_start_all_queues(priv); -#ifdef TC956X - if (readl_poll_timeout_atomic(priv->ioaddr + TC956X_MSI_EVENT_OFFSET(priv->port_num), +#ifdef TC956X_SRIOV_PF + if (readl_poll_timeout_atomic(priv->ioaddr + TC956X_MSI_EVENT_OFFSET(priv->fn_id_info.pf_no, priv->fn_id_info.vf_no), rd_val, !(rd_val & 0x1), 100, 10000)) { netdev_warn(priv->dev, "MSI Vector not clear. MSI_MASK_CLR = 0x0%x\n", - readl(priv->ioaddr + TC956X_MSI_MASK_CLR_OFFSET(priv->port_num))); + readl(priv->ioaddr + TC956X_MSI_MASK_CLR_OFFSET(priv->fn_id_info.pf_no, priv->fn_id_info.vf_no))); } - /* MSI_MASK_CLR: unmask vector 0 */ - writel(0x00000001, priv->ioaddr + TC956X_MSI_MASK_CLR_OFFSET(priv->port_num)); + /* MSI_MASK_CLR: unmask vector 0 & 1*/ + tc956x_msi_intr_clr(priv, dev, TC956X_MSI_VECTOR_0); +#if !defined(TC956X_AUTOMOTIVE_CONFIG) + tc956x_msi_intr_clr(priv, dev, TC956X_MSI_VECTOR_1); +#endif #ifdef TX_COMPLETION_WITHOUT_TIMERS writel(0, priv->tc956x_SRAM_pci_base_addr + TX_TIMER_SRAM_OFFSET(priv->port_num)); #endif +#ifdef TC956X_ENABLE_MAC2MAC_BRIDGE + + /* Route all multicast Flow control packets to PCI path */ + tc956x_pf_set_mac_filter(dev, PF_DRIVER, (const u8*) &flow_ctrl_addr[0]); + + if (priv->port_num == RM_PF0_ID) { + /* Write Eth0 RxBuffer Head address to DMEM */ + writel(priv->pbridge_handle, priv->tc956x_SRAM_pci_base_addr + + TC956X_M3_DMEM_OFFSET + (MAC2MAC_ETH0_RXDESC_L)); + writel(upper_32_bits(priv->pbridge_handle), + priv->tc956x_SRAM_pci_base_addr + TC956X_M3_DMEM_OFFSET + (MAC2MAC_ETH0_RXDESC_H)); + writel(0x1 << 0, priv->ioaddr + INTC_MCUFLG); + } else if (priv->port_num == RM_PF1_ID) { + /* Write Eth1 RxBuffer Head address to DMEM */ + writel(priv->pbridge_handle, priv->tc956x_SRAM_pci_base_addr + + TC956X_M3_DMEM_OFFSET + (MAC2MAC_ETH1_RXDESC_L)); + writel(upper_32_bits(priv->pbridge_handle), priv->tc956x_SRAM_pci_base_addr + + TC956X_M3_DMEM_OFFSET + (MAC2MAC_ETH1_RXDESC_H)); + writel(0x1 << 1, priv->ioaddr + INTC_MCUFLG); + } + mutex_lock(&tc956x_port_bridge_lock); + port_brige_state = 1; + mutex_unlock(&tc956x_port_bridge_lock); + netdev_info(priv->dev, "%s: Port bridge Feature enabled\n", __func__); +#endif + +#elif defined TC956X_SRIOV_VF + if (readl_poll_timeout_atomic(priv->ioaddr + TC956X_MSI_EVENT_OFFSET(priv->fn_id_info.pf_no, priv->fn_id_info.vf_no), + rd_val, !(rd_val & 0x1), 100, 10000)) { + + netdev_warn(priv->dev, "MSI Vector not clear. MSI_MASK_CLR = 0x0%x\n", + readl(priv->ioaddr + TC956X_MSI_MASK_CLR_OFFSET(priv->fn_id_info.pf_no, priv->fn_id_info.vf_no))); + } + + /* MSI_MASK_CLR: unmask vector 0 */ + writel(0x00000001, priv->ioaddr + TC956X_MSI_MASK_CLR_OFFSET(priv->fn_id_info.pf_no, priv->fn_id_info.vf_no)); + + if (link_status == true) { + netif_carrier_on(dev); + NMSGPR_INFO(priv->device, "PHY Link : UP\n"); + } else { + netif_carrier_off(dev); + NMSGPR_INFO(priv->device, "PHY Link : DOWN\n"); + } + + tc956xmac_vf_reset(priv, VF_UP); +#endif +#ifdef TX_COMPLETION_WITHOUT_TIMERS + writel(0, priv->tc956x_SRAM_pci_base_addr + + TX_TIMER_SRAM_OFFSET(priv->port_num)); #endif KPRINT_INFO("<--- light weight = %d %s(2) : Port %d", priv->link_down_rst,__func__, priv->port_num); return 0; +#ifdef TC956X_SRIOV_PF #ifndef TC956X lpiirq_error: if (priv->wol_irq != dev->irq) @@ -6011,21 +7397,41 @@ static int tc956xmac_open(struct net_device *dev) #endif wolirq_error: free_irq(dev->irq, dev); +#endif irq_error: +#ifndef TC956X_SRIOV_VF phylink_stop(priv->phylink); +#endif #ifdef ENABLE_TX_TIMER for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) { +#ifdef TC956X_SRIOV_PF + if (priv->plat->tx_ch_in_use[chan] == TC956X_DISABLE_CHNL) + continue; +#elif defined TC956X_SRIOV_VF + /* skip configuring for unallocated channel */ + if (priv->plat->ch_in_use[chan] == 0) + continue; +#else if (priv->plat->tx_dma_ch_owner[chan] == USE_IN_TC956X_SW) +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)) + hrtimer_cancel(&priv->tx_queue[chan].txtimer); +#else del_timer_sync(&priv->tx_queue[chan].txtimer); +#endif } #endif +#ifndef TC956X_SRIOV_VF tc956xmac_hw_teardown(dev); +#endif + init_error: free_dma_desc_resources(priv); dma_desc_error: +#ifndef TC956X_SRIOV_VF phylink_disconnect_phy(priv->phylink); KPRINT_INFO("<--- light weight = %d %s(3) : Port %d", priv->link_down_rst,__func__, priv->port_num); - +#endif return ret; } @@ -6038,24 +7444,67 @@ static int tc956xmac_open(struct net_device *dev) static int tc956xmac_release(struct net_device *dev) { struct tc956xmac_priv *priv = netdev_priv(dev); + struct pci_dev *pdev = container_of(priv->device, struct pci_dev, dev); +#ifdef TC956X_SRIOV_PF +#if defined(TC956X_AUTOMOTIVE_CONFIG) || defined(TC956X_ENABLE_MAC2MAC_BRIDGE) struct phy_device *phydev; int addr = priv->plat->phy_addr; +#endif + struct tc956x_mac_addr *mac_table = &priv->mac_table[0]; + struct tc956x_vlan_id *vlan_table = &priv->vlan_table[0]; + int i, vf_number; +#endif u32 ch; u32 offload_release_sts = true; + + int irq_no; #ifdef ENABLE_TX_TIMER u32 chan; #endif +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + unsigned long flags; +#endif + KPRINT_INFO(" ---> light weight = %d %s : Port %d", priv->link_down_rst, __func__, priv->port_num); #ifdef TX_COMPLETION_WITHOUT_TIMERS - writel(0, priv->tc956x_SRAM_pci_base_addr - + TX_TIMER_SRAM_OFFSET(priv->port_num)); + writel(0, priv->tc956x_SRAM_pci_base_addr + + TX_TIMER_SRAM_OFFSET(priv->port_num)); #endif KPRINT_INFO("Release priv->link_down_rst = %d priv->tc956x_port_pm_suspend = %d\n", priv->link_down_rst, priv->tc956x_port_pm_suspend); +#ifdef TC956X_SRIOV_VF + tc956xmac_vf_reset(priv, VF_RELEASE); +#endif + +#ifdef TC956X_SRIOV_PF + /* Disable all interrupt sources */ + tc956x_msi_intr_en(priv, dev, TC956X_DISABLE); + +#if defined(TC956X_ENABLE_MAC2MAC_BRIDGE) + mutex_lock(&tc956x_port_bridge_lock); + if (port_brige_state) { + port_brige_state = 0; + writel(0x1 << 2, priv->ioaddr + INTC_MCUFLG); + KPRINT_INFO("Sending MCU Flag Port bridge exit signal\n"); + } + mutex_unlock(&tc956x_port_bridge_lock); +#endif + +#elif defined TC956X_SRIOV_VF + /* Disable all interrupt sources */ + tc956x_msi_intr_en(priv, dev, 0, &priv->fn_id_info); +#endif + +#ifndef TC956X_SRIOV_VF + /*if (priv->eee_enabled) + del_timer_sync(&priv->eee_ctrl_timer);*/ + #ifdef CONFIG_DEBUG_FS if (priv->link_down_rst == false) - tc956xmac_cleanup_debugfs(priv->dev); + tc956xmac_cleanup_debugfs(priv->dev); #endif + + /* Stop and disconnect the PHY */ if (priv->link_down_rst == false) { if (priv->phylink) { @@ -6069,23 +7518,41 @@ static int tc956xmac_release(struct net_device *dev) KPRINT_INFO("Link down happened before %s, restoring clocks to stop DMA\n",__func__); tc956xmac_link_change_set_power(priv, LINK_UP); /* Restore, De-assert and Enable Reset and Clock */ } + +#endif tc956xmac_stop_all_queues(priv); tc956xmac_disable_all_queues(priv); /* MSI_OUT_EN: Disable all MSI*/ if (priv->link_down_rst == false) - writel(0x00000000, priv->ioaddr + TC956X_MSI_OUT_EN_OFFSET(priv->port_num)); + writel(0x00000000, priv->ioaddr + TC956X_MSI_OUT_EN_OFFSET(priv->port_num, 0)); #ifdef ENABLE_TX_TIMER for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) { +#ifdef TC956X_SRIOV_PF + if (priv->plat->tx_ch_in_use[chan] == TC956X_DISABLE_CHNL) + continue; +#elif defined TC956X_SRIOV_VF + /* skip configuring for unallocated channel */ + if (priv->plat->ch_in_use[chan] == 0) + continue; +#else if (priv->plat->tx_dma_ch_owner[chan] == USE_IN_TC956X_SW) +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)) + hrtimer_cancel(&priv->tx_queue[chan].txtimer); +#else del_timer_sync(&priv->tx_queue[chan].txtimer); +#endif } #endif +#ifdef TC956X_SRIOV_PF /* Free the IRQ lines */ if (priv->link_down_rst == false) { - free_irq(dev->irq, dev); + irq_no = pci_irq_vector(pdev, TC956X_MSI_VECTOR_0); + free_irq(irq_no, dev); + /* Do not Free Host Irq resources during suspend sequence */ if (priv->tc956x_port_pm_suspend == false) { if (priv->wol_irq != dev->irq) @@ -6096,6 +7563,8 @@ static int tc956xmac_release(struct net_device *dev) #endif } } + +#if defined(TC956X_AUTOMOTIVE_CONFIG) || defined(TC956X_ENABLE_MAC2MAC_BRIDGE) phydev = mdiobus_get_phy(priv->mii, addr); if(phydev->drv != NULL) { @@ -6104,18 +7573,34 @@ static int tc956xmac_release(struct net_device *dev) flush_work(&priv->emac_phy_work); } } +#endif +#if !defined(TC956X_AUTOMOTIVE_CONFIG) && !defined(TC956X_ENABLE_MAC2MAC_BRIDGE) + irq_no = pci_irq_vector(pdev, TC956X_MSI_VECTOR_1); + free_irq(irq_no, dev); +#endif +#elif defined TC956X_SRIOV_VF + irq_no = pci_irq_vector(pdev, TC956X_MSI_VECTOR_0); + free_irq(irq_no, dev); +#endif + +#ifndef TC956X + if (priv->lpi_irq > 0) + free_irq(priv->lpi_irq, dev); +#endif /* Stop TX/RX DMA and clear the descriptors */ tc956xmac_stop_all_dma(priv); /* Release and free the Rx/Tx resources */ free_dma_desc_resources(priv); +#ifndef TC956X_SRIOV_VF /* Disable the MAC Rx/Tx */ tc956xmac_mac_set(priv, priv->ioaddr, false); - +#endif if (priv->link_down_rst == false) netif_carrier_off(dev); + NMSGPR_INFO(priv->device, "PHY Link : DOWN\n"); tc956xmac_release_ptp(priv); @@ -6143,8 +7628,36 @@ static int tc956xmac_release(struct net_device *dev) } priv->port_release = true; /* setting port release to true as release invoked, and clear from open or link-up */ mutex_unlock(&priv->port_ld_release_lock); - KPRINT_INFO("<--- light weight = %d %s : Port %d", priv->link_down_rst, __func__, priv->port_num); +#ifdef TC956X_SRIOV_PF +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_lock_irqsave(&priv->spn_lock.mac_filter, flags); +#endif + for (i = XGMAC_ADDR_ADD_SKIP_OFST; i < (TC956X_MAX_PERFECT_ADDRESSES); + i++, mac_table++) { + for (vf_number = 0; vf_number < 4; vf_number++) { + if (mac_table->vf[vf_number] != 0) + tc956x_pf_del_mac_filter(priv->dev, mac_table->vf[vf_number], (u8 *)&mac_table->mac_address); + } + } +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_unlock_irqrestore(&priv->spn_lock.mac_filter, flags); +#endif + +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_lock_irqsave(&priv->spn_lock.vlan_filter, flags); +#endif + for (i = 0; i < TC956X_MAX_PERFECT_VLAN; i++, vlan_table++) { + for (vf_number = 0; vf_number < 4; vf_number++) { + if (vlan_table->vf[vf_number].vf_number != 0) + tc956x_pf_del_vlan_filter(priv->dev, vlan_table->vf[vf_number].vf_number, vlan_table->vid); + } + } +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_unlock_irqrestore(&priv->spn_lock.vlan_filter, flags); +#endif +#endif + KPRINT_INFO("<--- light weight = %d %s : Port %d", priv->link_down_rst, __func__, priv->port_num); return 0; } @@ -6397,7 +7910,18 @@ static netdev_tx_t tc956xmac_tso_xmit(struct sk_buff *skb, struct net_device *de /* Manage tx mitigation */ tx_packets = (tx_q->cur_tx + 1) - first_tx; tx_q->tx_count_frames += tx_packets; - +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 13, 0)) + if ((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && priv->hwts_tx_en) + set_ic = true; + else if (!priv->tx_coal_frames[queue]) + set_ic = false; + else if (tx_packets > priv->tx_coal_frames[queue]) + set_ic = true; + else if ((tx_q->tx_count_frames % priv->tx_coal_frames[queue]) < tx_packets) + set_ic = true; + else + set_ic = false; +#else if ((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && priv->hwts_tx_en) set_ic = true; else if (!priv->tx_coal_frames) @@ -6408,7 +7932,7 @@ static netdev_tx_t tc956xmac_tso_xmit(struct sk_buff *skb, struct net_device *de set_ic = true; else set_ic = false; - +#endif if (set_ic) { if (tx_q->tbs & TC956XMAC_TBS_AVAIL) desc = &tx_q->dma_entx[tx_q->cur_tx].basic; @@ -6539,6 +8063,8 @@ static netdev_tx_t tc956xmac_xmit(struct sk_buff *skb, struct net_device *dev) KPRINT_DEBUG1("tso en = %d\n", priv->tso); KPRINT_DEBUG1("skb tso en = %d\n", skb_is_gso(skb)); /* Manage oversized TCP frames for GMAC4 device */ + + /* TSO feature is supported based on configuration in PF */ if (skb_is_gso(skb) && priv->tso) { KPRINT_DEBUG1("XMIT TSO IF\n"); if (gso & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) @@ -6561,7 +8087,12 @@ static netdev_tx_t tc956xmac_xmit(struct sk_buff *skb, struct net_device *dev) } /* Prepare context descriptor for one-step timestamp correction */ +#ifdef TC956X_SRIOV_VF + if ((tx_q->queue_index == priv->plat->gptp_ch_no) && (priv->ost_en == 1) + && (priv->plat->best_effort_ch_no != priv->plat->gptp_ch_no)) { +#else if ((tx_q->queue_index == TC956X_GPTP_TX_CH) && (priv->ost_en == 1)) { +#endif if (tx_q->tbs & TC956XMAC_TBS_AVAIL) desc = &tx_q->dma_entx[tx_q->cur_tx].basic; else @@ -6582,12 +8113,19 @@ static netdev_tx_t tc956xmac_xmit(struct sk_buff *skb, struct net_device *dev) WARN_ON(tx_q->tx_skbuff[first_entry]); /* Update checksum value as per Ethtool configuration */ - /*csum_insertion = (skb->ip_summed == CHECKSUM_PARTIAL);*/ +#ifdef TC956X_SRIOV_PF + if (queue == HOST_BEST_EFF_CH) + csum_insertion = priv->csum_insertion; +#elif defined TC956X_SRIOV_VF + if (queue == priv->plat->best_effort_ch_no) csum_insertion = priv->csum_insertion; +#endif + else + csum_insertion = 0; + KPRINT_DEBUG1("csum_insertion = %d\n", csum_insertion); KPRINT_DEBUG1("priv->tx_crc_pad_state = %d\n", priv->tx_crc_pad_state); - if (likely(priv->extend_desc)) desc = (struct dma_desc *)(tx_q->dma_etx + entry); else if (tx_q->tbs & TC956XMAC_TBS_AVAIL) @@ -6655,7 +8193,18 @@ static netdev_tx_t tc956xmac_xmit(struct sk_buff *skb, struct net_device *dev) */ tx_packets = (entry + 1) - first_tx; tx_q->tx_count_frames += tx_packets; - +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 13, 0)) + if ((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && priv->hwts_tx_en) + set_ic = true; + else if (!priv->tx_coal_frames[queue]) + set_ic = false; + else if (tx_packets > priv->tx_coal_frames[queue]) + set_ic = true; + else if ((tx_q->tx_count_frames % priv->tx_coal_frames[queue]) < tx_packets) + set_ic = true; + else + set_ic = false; +#else if ((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && priv->hwts_tx_en) set_ic = true; else if (!priv->tx_coal_frames) @@ -6666,7 +8215,7 @@ static netdev_tx_t tc956xmac_xmit(struct sk_buff *skb, struct net_device *dev) set_ic = true; else set_ic = false; - +#endif if (set_ic) { if (likely(priv->extend_desc)) desc = &tx_q->dma_etx[entry].basic; @@ -6765,10 +8314,19 @@ static netdev_tx_t tc956xmac_xmit(struct sk_buff *skb, struct net_device *dev) skb->data[32]; Presentation_time = (Presentation_time<<8) | skb->data[33]; - - if (AVB_CLASS_B_TX_CH == queue) +#ifdef TC956X_SRIOV_VF + if ((priv->plat->avb_class_b_ch_no == queue) + && (priv->plat->best_effort_ch_no != priv->plat->avb_class_b_ch_no)) +#else + if (queue == AVB_CLASS_B_TX_CH) +#endif Traverse_time = 50000000; /* Class B - 50ms */ - else if (AVB_CLASS_A_TX_CH == queue) +#ifdef TC956X_SRIOV_VF + else if ((priv->plat->avb_class_a_ch_no == queue) + && (priv->plat->best_effort_ch_no != priv->plat->avb_class_a_ch_no)) +#else + else if (queue == AVB_CLASS_A_TX_CH) +#endif Traverse_time = 2000000; /* Class A- 2ms */ else Traverse_time = 0; /* default */ @@ -6886,7 +8444,7 @@ static void tc956xmac_rx_vlan(struct net_device *dev, struct sk_buff *skb) * Description : this function extracts vlan id from the descriptor * stripped by MAC VLAN filter. */ -static void tc956xmac_rx_vlan(struct net_device *dev, +static void tc956xmac_rx_vlan(struct net_device *dev, struct dma_desc *rdesc, struct sk_buff *skb) { @@ -6899,7 +8457,7 @@ static void tc956xmac_rx_vlan(struct net_device *dev, etlt = XGMAC_GET_BITS_LE(rdesc->des3, XGMAC_RDES3, ETLT); if (!err) { /* No error if err is 0 or etlt is 0 */ - /* Check packet type is Single CVLAN tag and + /* Check packet type is Single CVLAN tag and netdev supports VLAN CTAG*/ if ((etlt == PKT_TYPE_SINGLE_CVLAN) && (dev->features & NETIF_F_HW_VLAN_CTAG_RX)) { @@ -6978,11 +8536,19 @@ static inline void tc956xmac_rx_refill(struct tc956xmac_priv *priv, u32 queue) tc956xmac_refill_desc3(priv, rx_q, p); rx_q->rx_count_frames++; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 13, 0)) + rx_q->rx_count_frames += priv->rx_coal_frames[queue]; + if (rx_q->rx_count_frames > priv->rx_coal_frames[queue]) + rx_q->rx_count_frames = 0; + + use_rx_wd = !priv->rx_coal_frames[queue]; +#else rx_q->rx_count_frames += priv->rx_coal_frames; if (rx_q->rx_count_frames > priv->rx_coal_frames) rx_q->rx_count_frames = 0; use_rx_wd = !priv->rx_coal_frames; +#endif use_rx_wd |= rx_q->rx_count_frames > 0; if (!priv->use_riwt) use_rx_wd = false; @@ -7183,7 +8749,11 @@ static int tc956xmac_rx(struct tc956xmac_priv *priv, int limit, u32 queue) priv->dma_buf_sz); /* Data payload appended into SKB */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0)) page_pool_release_page(rx_q->page_pool, buf->page); +#else + skb_mark_for_recycle(skb); +#endif buf->page = NULL; } @@ -7195,7 +8765,12 @@ static int tc956xmac_rx(struct tc956xmac_priv *priv, int limit, u32 queue) priv->dma_buf_sz); /* Data payload appended into SKB */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0)) page_pool_release_page(rx_q->page_pool, buf->sec_page); +#else + skb_mark_for_recycle(skb); +#endif + buf->sec_page = NULL; } @@ -7206,12 +8781,15 @@ static int tc956xmac_rx(struct tc956xmac_priv *priv, int limit, u32 queue) continue; /* Got entire packet into SKB. Finish it. */ +#ifdef RX_LOGGING_TRACE + tc956xmac_get_rx_hwtstamp(priv, p, np, skb, queue); +#else /* Pause frame counter to count link partner pause frames */ if ((mac0_en_lp_pause_frame_cnt == ENABLE && priv->port_num == RM_PF0_ID) || (mac1_en_lp_pause_frame_cnt == ENABLE && priv->port_num == RM_PF1_ID)) { proto = htons(((skb->data[13]<<8) | skb->data[12])); if (proto == ETH_P_PAUSE) { - if(!(skb->data[6] == phy_sa_addr[priv->port_num][0] && skb->data[7] == phy_sa_addr[priv->port_num][1] + if (!(skb->data[6] == phy_sa_addr[priv->port_num][0] && skb->data[7] == phy_sa_addr[priv->port_num][1] && skb->data[8] == phy_sa_addr[priv->port_num][2] && skb->data[9] == phy_sa_addr[priv->port_num][3] && skb->data[10] == phy_sa_addr[priv->port_num][4] && skb->data[11] == phy_sa_addr[priv->port_num][5])) { priv->xstats.link_partner_pause_frame_cnt++; @@ -7220,6 +8798,7 @@ static int tc956xmac_rx(struct tc956xmac_priv *priv, int limit, u32 queue) } tc956xmac_get_rx_hwtstamp(priv, p, np, skb); +#endif #ifndef TC956X tc956xmac_rx_vlan(priv->dev, skb); #else @@ -7316,13 +8895,45 @@ static int tc956xmac_napi_poll_tx(struct napi_struct *napi, int budget) * netdev structure and arrange for the device to be reset to a sane state * in order to transmit a new packet. */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)) +static void tc956xmac_tx_timeout(struct net_device *dev, unsigned int txqueue) +#else static void tc956xmac_tx_timeout(struct net_device *dev) +#endif { struct tc956xmac_priv *priv = netdev_priv(dev); tc956xmac_global_err(priv); } +#ifdef TC956X_SRIOV_VF +static int tc956x_vf_add_mac_addr(struct net_device *dev, const unsigned char *mac) +{ + int ret_value; + struct tc956xmac_priv *priv = netdev_priv(dev); + + ret_value = tc956xmac_add_mac(priv, mac); + + return ret_value; +} + +static int tc956x_vf_delete_mac_addr(struct net_device *dev, + const unsigned char *mac) +{ + struct tc956xmac_priv *priv = netdev_priv(dev); + + tc956xmac_delete_mac(priv, mac); + return 0; +} +static void tc956x_vf_set_filter(struct mac_device_info *hw, + struct net_device *dev) +{ + __dev_uc_sync(dev, tc956x_vf_add_mac_addr, tc956x_vf_delete_mac_addr); + + __dev_mc_sync(dev, tc956x_vf_add_mac_addr, tc956x_vf_delete_mac_addr); +} +#endif + /** * tc956xmac_set_rx_mode - entry point for multicast addressing * @dev : pointer to the device structure @@ -7335,8 +8946,11 @@ static void tc956xmac_tx_timeout(struct net_device *dev) static void tc956xmac_set_rx_mode(struct net_device *dev) { struct tc956xmac_priv *priv = netdev_priv(dev); - +#ifndef TC956X_SRIOV_VF tc956xmac_set_filter(priv, priv->hw, dev); +#else + tc956x_vf_set_filter(priv->hw, dev); +#endif } /** @@ -7361,20 +8975,18 @@ static int tc956xmac_change_mtu(struct net_device *dev, int new_mtu) txfifosz /= priv->plat->tx_queues_to_use; - /* Dynamic MTU change is supported, so below condition is commented */ - /*if (netif_running(dev)) { + if (netif_running(dev)) { netdev_err(priv->dev, "must be stopped to change its MTU\n"); return -EBUSY; - }*/ + } - /* Alignment of MTU reported to upper layers is not required */ - /*new_mtu = TC956XMAC_ALIGN(new_mtu);*/ + new_mtu = TC956XMAC_ALIGN(new_mtu); #ifdef TC956X /* Supported frame sizes */ - if ((new_mtu < MIN_SUPPORTED_MTU) || (new_mtu > MAX_SUPPORTED_MTU)) { + if ((new_mtu < MIN_SUPPORTED_MTU) || (new_mtu > JUMBO_LEN)) { NMSGPR_ALERT(priv->device, "%s: invalid MTU, min %d and max %d MTU are supported\n", - dev->name, MIN_SUPPORTED_MTU, MAX_SUPPORTED_MTU); + dev->name, MIN_SUPPORTED_MTU, JUMBO_LEN); return -EINVAL; } @@ -7395,6 +9007,21 @@ static netdev_features_t tc956xmac_fix_features(struct net_device *dev, { struct tc956xmac_priv *priv = netdev_priv(dev); + +#ifdef TC956X_SRIOV_VF + /* Update dev->feature RX Checksum and RX FCS flags based on states + * received from PF via mailbox. + */ + if (priv->rx_csum_state) + features |= NETIF_F_RXCSUM; + else + features &= ~NETIF_F_RXCSUM; + + if (priv->rx_crc_pad_state) + features &= ~NETIF_F_RXFCS; + else + features |= NETIF_F_RXFCS; +#endif if (priv->plat->rx_coe == TC956XMAC_RX_COE_NONE) features &= ~NETIF_F_RXCSUM; @@ -7409,13 +9036,34 @@ static netdev_features_t tc956xmac_fix_features(struct net_device *dev, if (priv->plat->bugged_jumbo && (dev->mtu > ETH_DATA_LEN)) features &= ~NETIF_F_CSUM_MASK; +#ifdef TC956X_SRIOV_PF /* Disable tso if asked by ethtool */ if ((priv->plat->tso_en) && (priv->dma_cap.tsoen)) { - if (features & NETIF_F_TSO) + if (features & NETIF_F_TSO) { priv->tso = true; - else + /* Update driver cap to let VF know about + * feature enable/disable + */ + priv->pf_drv_cap.tso_en = true; + } else { priv->tso = false; + /* Update driver cap to let VF know about + * feature enable/disable + */ + priv->pf_drv_cap.tso_en = false; + } } +#elif defined TC956X_SRIOV_VF + if (priv->pf_drv_cap.tso_en) { + /* Disable tso if asked by ethtool */ + if ((priv->plat->tso_en) && (priv->dma_cap.tsoen)) { + if (features & NETIF_F_TSO) + priv->tso = true; + else + priv->tso = false; + } + } +#endif return features; } @@ -7433,16 +9081,38 @@ static int tc956xmac_set_features(struct net_device *netdev, txvlan = (netdev->features & NETIF_F_HW_VLAN_CTAG_TX); rxvlan_filter = (netdev->features & NETIF_F_HW_VLAN_CTAG_FILTER); #endif - /* Keep the COE Type in case of csum is supporting */ - if (features & NETIF_F_RXCSUM) + +#ifdef TC956X_SRIOV_VF + /* RX CSUM is handled in PF as it impacts all drivers */ + if (priv->pf_drv_cap.csum_en) priv->hw->rx_csum = priv->plat->rx_coe; else priv->hw->rx_csum = 0; +#else + /* Keep the COE Type in case of csum is supporting */ + if (features & NETIF_F_RXCSUM) { + if (priv->hw->rx_csum != priv->plat->rx_coe) { + priv->hw->rx_csum = priv->plat->rx_coe; + priv->rx_csum_state = priv->hw->rx_csum; +#ifdef TC956X_SRIOV_PF + tc956x_mbx_wrap_set_rx_csum(priv); +#endif + } + } else { + if (priv->hw->rx_csum != 0) { + priv->hw->rx_csum = 0; + priv->rx_csum_state = priv->hw->rx_csum; +#ifdef TC956X_SRIOV_PF + tc956x_mbx_wrap_set_rx_csum(priv); +#endif + } + } + /* No check needed because rx_coe has been set before and it will be * fixed in case of issue. */ tc956xmac_rx_ipc(priv, priv->hw); - +#endif /* Tx Checksum Configuration via Ethtool */ if ((features & NETIF_F_IP_CSUM) || (features & NETIF_F_IPV6_CSUM)) priv->csum_insertion = 1; @@ -7450,13 +9120,18 @@ static int tc956xmac_set_features(struct net_device *netdev, priv->csum_insertion = 0; KPRINT_DEBUG1("priv->csum_insertion = %d\n", priv->csum_insertion); +#ifdef TC956X_SRIOV_PF /* Clean up needed */ /* Rx fcs Configuration via Ethtool */ if (features & NETIF_F_RXFCS) { - priv->rx_crc_pad_state &= (~TC956X_RX_CRC_DEFAULT); + if (priv->rx_crc_pad_state != (priv->rx_crc_pad_state & (~TC956X_RX_CRC_DEFAULT))) { + priv->rx_crc_pad_state &= (~TC956X_RX_CRC_DEFAULT); + tc956x_mbx_wrap_set_rx_crc(priv); + } } else { -#ifdef TC956X - priv->rx_crc_pad_state = TC956X_RX_CRC_DEFAULT; -#endif + if (priv->rx_crc_pad_state != TC956X_RX_CRC_DEFAULT) { + priv->rx_crc_pad_state = TC956X_RX_CRC_DEFAULT; + tc956x_mbx_wrap_set_rx_crc(priv); + } } tc956x_rx_crc_pad_config(priv, priv->rx_crc_pad_state); @@ -7466,6 +9141,23 @@ static int tc956xmac_set_features(struct net_device *netdev, for (chan = 0; chan < priv->plat->rx_queues_to_use; chan++) tc956xmac_enable_sph(priv, priv->ioaddr, sph_en, chan); +#elif defined TC956X_SRIOV_VF + /* Rx fcs Configuration via Ethtool */ + if (features & NETIF_F_RXFCS) { + priv->rx_crc_pad_state &= (~TC956X_RX_CRC_DEFAULT); + } else { +#ifdef TC956X + priv->rx_crc_pad_state = TC956X_RX_CRC_DEFAULT; +#endif + } + + sph_en = (priv->hw->rx_csum > 0) && priv->sph; + for (chan = 0; chan < priv->plat->rx_queues_to_use; chan++) { + if (priv->plat->ch_in_use[chan] == 0) + continue; + tc956xmac_enable_sph(priv, priv->ioaddr, sph_en, chan); + } +#endif #ifdef TC956X if ((features & NETIF_F_HW_VLAN_CTAG_RX) && !rxvlan) tc956xmac_enable_rx_vlan_stripping(priv, priv->hw); @@ -7485,8 +9177,50 @@ static int tc956xmac_set_features(struct net_device *netdev, return 0; } +#ifdef TC956X_SRIOV_PF /** - * tc956xmac_interrupt - main ISR + * tc956xmac_rx_dma_error_recovery + * + * \brief API to handle and recover from the dma err + * + * \details This function is used to handle and recover from the dma error + * + * \param[in] priv - Pointer to device's private structure + * + * \return None + */ +static void tc956xmac_rx_dma_error_recovery(struct tc956xmac_priv *priv) +{ + u8 ch; + u32 intr_status = 0; + u32 reg_val = 0; +#if !defined(TC956X_AUTOMOTIVE_CONFIG) && !defined(TC956X_ENABLE_MAC2MAC_BRIDGE) + unsigned long flags; +#endif + for (ch = 0; ch < TC956XMAC_CH_MAX; ch++) { + intr_status = 0; + reg_val = 0; + + intr_status = readl(priv->ioaddr + XGMAC_DMA_CH_STATUS(ch)); + + if ((intr_status & TC956X_DMA_RX_FBE) && (intr_status & TC956X_DMA_RX_RPS)) { + reg_val = readl(priv->ioaddr + XGMAC_DMA_CH_RX_CONTROL(ch)); + reg_val |= 0x80000000; //set bit 31 to flush ch + writel(reg_val, priv->ioaddr + XGMAC_DMA_CH_RX_CONTROL(ch)); + writel(intr_status, priv->ioaddr + XGMAC_DMA_CH_STATUS(ch)); +#if !defined(TC956X_AUTOMOTIVE_CONFIG) && !defined(TC956X_ENABLE_MAC2MAC_BRIDGE) + spin_lock_irqsave(&priv->wq_lock, flags); + priv->mbx_wq_param.fn_id = SCH_WQ_RX_DMA_ERR; + tc956xmac_service_mbx_event_schedule(priv); + spin_unlock_irqrestore(&priv->wq_lock, flags); +#endif + } + } +} +#endif + +/** + * tc956xmac_interrupt_v0 - main ISR * @irq: interrupt number. * @dev_id: to pass the net device pointer. * Description: this is the main driver interrupt service routine. @@ -7496,19 +9230,135 @@ static int tc956xmac_set_features(struct net_device *netdev, * o Core interrupts to manage: remote wake-up, management counter, LPI * interrupts. */ -static irqreturn_t tc956xmac_interrupt(int irq, void *dev_id) +static irqreturn_t tc956xmac_interrupt_v0(int irq, void *dev_id) { struct net_device *dev = (struct net_device *)dev_id; struct tc956xmac_priv *priv = netdev_priv(dev); +#ifndef TC956X_SRIOV_VF + u32 val = 0; +#endif +#if defined(TC956X_SRIOV_PF) && defined(TC956X_AUTOMOTIVE_CONFIG) + u32 queue, value; + uint32_t uiIntSts, uiIntclr = 0; +#endif + u32 queues_count; +#ifdef TC956X_SRIOV_VF + enum mbx_msg_fns msg_src; + u8 i; +#endif +#ifdef TC956X + u32 rx_cnt = priv->plat->rx_queues_to_use; + u32 tx_cnt = priv->plat->tx_queues_to_use; + + queues_count = (rx_cnt > tx_cnt) ? rx_cnt : tx_cnt; +#endif +#ifndef TC956X_SRIOV_VF + val = readl(priv->ioaddr + TC956X_MSI_INT_STS_OFFSET(priv->fn_id_info.pf_no, priv->fn_id_info.vf_no)); + + priv->xstats.total_interrupts++; + + if (val & (0xFF << 3)) + priv->xstats.tx_intr_n++; + + if (val & (0xFF << 11)) + priv->xstats.rx_intr_n++; + /* Checking if any RBUs occurred and updating the statistics corresponding to channel */ +#endif + +#if defined(TC956X_SRIOV_PF) && defined(TC956X_AUTOMOTIVE_CONFIG) + for (queue = 0; queue < queues_count; queue++) { + uiIntSts = readl(priv->ioaddr + XGMAC_DMA_CH_STATUS(queue)); + + /* Assuming DMA Tx and Rx channels are used as pairs */ + if ((priv->plat->tx_dma_ch_owner[queue] != USE_IN_TC956X_SW) || + (priv->plat->rx_dma_ch_owner[queue] != USE_IN_TC956X_SW)) { + uiIntSts = readl(priv->ioaddr + XGMAC_DMA_CH_STATUS(queue)); + /* Handling Abnormal interrupts of NON S/W path, TI & RI are handled in FW */ + if (unlikely(uiIntSts & XGMAC_AIS)) { + if (unlikely(uiIntSts & XGMAC_RBU)) { + priv->xstats.rx_buf_unav_irq[queue]++; + uiIntclr |= XGMAC_RBU; + } + if (unlikely(uiIntSts & XGMAC_TPS)) { + priv->xstats.tx_process_stopped_irq[queue]++; + uiIntclr |= XGMAC_TPS; + } + if (unlikely(uiIntSts & XGMAC_FBE)) { + priv->xstats.fatal_bus_error_irq[queue]++; + uiIntclr |= XGMAC_FBE; + } + if (unlikely(uiIntSts & XGMAC_RPS)) { + uiIntclr |= XGMAC_RPS; + } + uiIntclr |= XGMAC_AIS; + writel(uiIntclr, (priv->ioaddr + XGMAC_DMA_CH_STATUS(queue))); + } + + /* Disable RBU interrupt on RBU interrupt occurance. IPA SW should enable it back */ + value = readl(priv->ioaddr + XGMAC_DMA_CH_INT_EN(queue)); + if ( ((uiIntclr & XGMAC_RBU) == XGMAC_RBU) && (value & XGMAC_RBUE)) { + value = readl(priv->ioaddr + XGMAC_DMA_CH_INT_EN(queue)); + value &= ~XGMAC_RBUE; + writel(value, priv->ioaddr + XGMAC_DMA_CH_INT_EN(queue)); + printk("***RBU INT disabled***XGMAC_DMA_CH_INT_EN[%d]***** :0x%x\n", queue, readl(priv->ioaddr + XGMAC_DMA_CH_INT_EN(queue))); + } + } + } +#endif + /* To handle DMA interrupts */ + tc956xmac_dma_interrupt(priv); /* TODO: To be compared sequence with Beta-2 */ + + +#ifdef TC956X_SRIOV_PF +#if defined(TC956X_SRIOV_PF) && (defined(TC956X_AUTOMOTIVE_CONFIG) || defined(TC956X_ENABLE_MAC2MAC_BRIDGE)) + tc956xmac_interrupt_v1(irq, dev_id); +#endif + /* unmask MSI vector 0 */ + tc956x_msi_intr_clr(priv, dev, TC956X_MSI_VECTOR_0); +#elif defined TC956X_SRIOV_VF + /* Run the through the loop PF and MCU */ + + for (i = 0; i < PFS_MAX; i++) { + msg_src = tc956x_vf_get_fn_idx_from_int_sts(priv, + &priv->fn_id_info); + if (msg_src >= 0 && msg_src <= 2) { + /* Read and ack the mail and call respective + * message type functions to perform the action + */ + tc956x_vf_parse_mbx(priv, msg_src); + } else { + /* No valid Interrupt*/ + } + } + + /* unmask MSI vector 0 */ + tc956x_msi_intr_clr(priv, dev, TC956X_MSI_VECTOR_0, &priv->fn_id_info); +#endif + return IRQ_HANDLED; +} + +#ifdef TC956X_SRIOV_PF +static irqreturn_t tc956xmac_interrupt_v1(int irq, void *dev_id) +{ + struct net_device *dev = (struct net_device *)dev_id; + struct tc956xmac_priv *priv = netdev_priv(dev); + #ifdef TC956X u32 rx_cnt = priv->plat->rx_queues_to_use; u32 tx_cnt = priv->plat->tx_queues_to_use; #endif + +#if !defined(TC956X_AUTOMOTIVE_CONFIG) && !defined(TC956X_ENABLE_MAC2MAC_BRIDGE) + u32 i; + enum mbx_msg_fns msg_src; + unsigned long flags; +#endif + u32 queues_count; u32 queue; bool xmac; - u32 val = 0, value = 0; - uint32_t uiIntSts, uiIntclr = 0; + u32 val = 0; + //uint32_t uiIntSts, uiIntclr = 0; xmac = priv->plat->has_gmac4 || priv->plat->has_xgmac; #ifdef TC956X @@ -7529,7 +9379,7 @@ static irqreturn_t tc956xmac_interrupt(int irq, void *dev_id) if (tc956xmac_safety_feat_interrupt(priv)) return IRQ_HANDLED; - val = readl(priv->ioaddr + TC956X_MSI_INT_STS_OFFSET(priv->port_num)); + val = readl(priv->ioaddr + TC956X_MSI_INT_STS_OFFSET(priv->fn_id_info.pf_no, priv->fn_id_info.vf_no)); priv->xstats.total_interrupts++; @@ -7542,12 +9392,6 @@ static irqreturn_t tc956xmac_interrupt(int irq, void *dev_id) if (val & (1 << 2)) priv->xstats.event_intr_n++; - if (val & (0xFF << 3)) - priv->xstats.tx_intr_n++; - - if (val & (0xFF << 11)) - priv->xstats.rx_intr_n++; - if (val & (1 << 19)) priv->xstats.xpcs_intr_n++; @@ -7557,41 +9401,9 @@ static irqreturn_t tc956xmac_interrupt(int irq, void *dev_id) if (val & (1 << 24)) priv->xstats.sw_msi_n++; - /* Checking if any RBUs occurred and updating the statistics corresponding to channel */ - - for (queue = 0; queue < queues_count; queue++) { - /* Assuming DMA Tx and Rx channels are used as pairs */ - if ((priv->plat->tx_dma_ch_owner[queue] != USE_IN_TC956X_SW) || - (priv->plat->rx_dma_ch_owner[queue] != USE_IN_TC956X_SW)) { - uiIntSts = readl(priv->ioaddr + XGMAC_DMA_CH_STATUS(queue)); - /* Handling Abnormal interrupts of NON S/W path, TI & RI are handled in FW */ - if (unlikely(uiIntSts & XGMAC_AIS)) { - if (unlikely(uiIntSts & XGMAC_RBU)) { - priv->xstats.rx_buf_unav_irq[queue]++; - uiIntclr |= XGMAC_RBU; - } - if (unlikely(uiIntSts & XGMAC_TPS)) { - priv->xstats.tx_process_stopped_irq[queue]++; - uiIntclr |= XGMAC_TPS; - } - if (unlikely(uiIntSts & XGMAC_FBE)) { - priv->xstats.fatal_bus_error_irq[queue]++; - uiIntclr |= XGMAC_FBE; - } - uiIntclr |= XGMAC_AIS; - } - writel(uiIntclr, (priv->ioaddr + XGMAC_DMA_CH_STATUS(queue))); - - /* Disable RBU interrupt on RBU interrupt occurance. IPA SW should enable it back */ - value = readl(priv->ioaddr + XGMAC_DMA_CH_INT_EN(queue)); - if ( ((uiIntclr & XGMAC_RBU) == XGMAC_RBU) && (value & XGMAC_RBUE)) { - value = readl(priv->ioaddr + XGMAC_DMA_CH_INT_EN(queue)); - value &= ~XGMAC_RBUE; - writel(value, priv->ioaddr + XGMAC_DMA_CH_INT_EN(queue)); - printk("***RBU INT disabled***XGMAC_DMA_CH_INT_EN[%d]***** :0x%x\n", queue, readl(priv->ioaddr + XGMAC_DMA_CH_INT_EN(queue))); - } - } - } +#ifdef TC956X_SRIOV_PF + tc956xmac_rx_dma_error_recovery(priv); +#endif /* To handle GMAC own interrupts */ if ((priv->plat->has_gmac) || xmac) { @@ -7607,17 +9419,53 @@ static irqreturn_t tc956xmac_interrupt(int irq, void *dev_id) } for (queue = 0; queue < queues_count; queue++) { - struct tc956xmac_rx_queue *rx_q = &priv->rx_queue[queue]; + struct tc956xmac_rx_queue *rx_q; + +#ifdef TC956X_SRIOV_PF + if (priv->plat->rx_q_in_use[queue] == TC956X_DISABLE_QUEUE) + continue; + +#endif +#ifdef TC956X_ENABLE_MAC2MAC_BRIDGE + if ((queue == TC956X_ONE) || (queue == TC956X_TWO)) + continue; +#endif mtl_status = tc956xmac_host_mtl_irq_status(priv, priv->hw, queue); + if (mtl_status != -EINVAL) status |= mtl_status; - if (status & CORE_IRQ_MTL_RX_OVERFLOW) - tc956xmac_set_rx_tail_ptr(priv, priv->ioaddr, - rx_q->rx_tail_addr, - queue); + if (status & CORE_IRQ_MTL_RX_OVERFLOW) { + u8 pf_dma_ch; + + status = status & (~CORE_IRQ_MTL_RX_OVERFLOW); + priv->mbx_wq_param.queue_no = queue; + KPRINT_INFO("CORE_IRQ_MTL_RX_OVERFLOW for queue = %d\n", queue); + if (queue == 0 || queue == 1 || queue == 7) { + pf_dma_ch = priv->pf_queue_dma_map[queue]; + rx_q = &priv->rx_queue[pf_dma_ch]; +#if !defined(TC956X_AUTOMOTIVE_CONFIG) && !defined(TC956X_ENABLE_MAC2MAC_BRIDGE) + spin_lock_irqsave(&priv->wq_lock, flags); + tc956xmac_service_mbx_event_schedule(priv); + spin_unlock_irqrestore(&priv->wq_lock, flags); +#endif + tc956xmac_set_rx_tail_ptr(priv, priv->ioaddr, + rx_q->rx_tail_addr, pf_dma_ch); + } else if (queue == 2 || queue == 3) { + pf_dma_ch = priv->pf_queue_dma_map[queue]; + rx_q = &priv->rx_queue[pf_dma_ch]; + tc956xmac_set_rx_tail_ptr(priv, priv->ioaddr, + rx_q->rx_tail_addr, pf_dma_ch); +#if !defined(TC956X_AUTOMOTIVE_CONFIG) && !defined(TC956X_ENABLE_MAC2MAC_BRIDGE) + } else { + spin_lock_irqsave(&priv->wq_lock, flags); + tc956xmac_service_mbx_event_schedule(priv); + spin_unlock_irqrestore(&priv->wq_lock, flags); +#endif + } + } } /* PCS link status */ @@ -7629,51 +9477,69 @@ static irqreturn_t tc956xmac_interrupt(int irq, void *dev_id) } } - /* To handle DMA interrupts */ - tc956xmac_dma_interrupt(priv); - val = readl(priv->ioaddr + TC956X_MSI_INT_STS_OFFSET(priv->port_num)); +#if defined(TC956X_SRIOV_PF) && !defined(TC956X_AUTOMOTIVE_CONFIG) && !defined(TC956X_ENABLE_MAC2MAC_BRIDGE) + /* Mailbox Events */ + /* Run the through the loop of VF, PF (other PF) and MCU */ + for (i = 0; i < FNS_MAX; i++) { + msg_src = tc956x_pf_get_fn_idx_from_int_sts(priv, + &priv->fn_id_info); + + if (msg_src >= 0 && msg_src <= 5) { + /* Read and ack the mail and call respective + * message type functions to perform the action + */ + tc956x_pf_parse_mbx(priv, msg_src); + } else { + /* No valid Interrupt*/ + } + } +#endif + + val = readl(priv->ioaddr + TC956X_MSI_INT_STS_OFFSET(priv->fn_id_info.pf_no, priv->fn_id_info.vf_no)); + if (val & TC956X_EXT_PHY_ETH_INT) { - KPRINT_INFO("PHY Interrupt %s \n", __func__); - + KPRINT_INFO("PHY Interrupt %s\n", __func__); +#ifndef TC956X_SRIOV_VF if (priv->port_link_down == true) tc956xmac_link_change_set_power(priv, LINK_UP); /* Restore, De-assert and Enable Reset and Clock */ - +#endif /* Queue the work in system_wq */ if (priv->tc956x_port_pm_suspend == true) { - KPRINT_INFO("%s : (Do not queue PHY Work during suspend. Set WOL Interrupt flag) \n", __func__); + KPRINT_INFO("%s : (Do not queue PHY Work during suspend. Set WOL Interrupt flag)\n", __func__); priv->tc956xmac_pm_wol_interrupt = true; } else { - KPRINT_INFO("%s : (Queue PHY Work.) \n", __func__); + KPRINT_INFO("%s : (Queue PHY Work.)\n", __func__); queue_work(system_wq, &priv->emac_phy_work); } /* phy_mac_interrupt(priv->dev->phydev); */ - val = readl(priv->ioaddr + TC956X_MSI_OUT_EN_OFFSET(priv->port_num)); /* MSI_OUT_EN: Reading */ + /* MSI_OUT_EN: Reading */ + val = readl(priv->ioaddr + TC956X_MSI_OUT_EN_OFFSET(priv->fn_id_info.pf_no, priv->fn_id_info.vf_no)); val &= (~(1 << MSI_INT_EXT_PHY)); - writel(val, priv->ioaddr + TC956X_MSI_OUT_EN_OFFSET(priv->port_num)); /* MSI_OUT_EN: Writing to disable MAC Ext Interrupt*/ + /* MSI_OUT_EN: Writing to disable MAC Ext Interrupt*/ + writel(val, priv->ioaddr + TC956X_MSI_OUT_EN_OFFSET(priv->fn_id_info.pf_no, priv->fn_id_info.vf_no)); } + #ifdef TC956X_SW_MSI val = readl(priv->ioaddr + TC956X_MSI_INT_STS_OFFSET(priv->port_num)); if (val & TC956X_SW_MSI_INT) { - //DBGPR_FUNC(priv->device, "%s SW MSI INT STS[%08x]\n", __func__, val); - /*Clear SW MSI*/ - writel(1, priv->ioaddr + TC956X_MSI_SW_MSI_CLR(priv->port_num)); - - val = readl(priv->ioaddr + TC956X_MSI_SW_MSI_CLR(priv->port_num)); - - //DBGPR_FUNC(priv->device, "%s SW MSI INT CLR[%08x]\n", __func__, val); + writel(1, priv->ioaddr + TC956X_MSI_SW_MSI_CLR(priv->fn_id_info.pf_no, priv->fn_id_info.vf_no)); + val = readl(priv->ioaddr + TC956X_MSI_SW_MSI_CLR(priv->fn_id_info.pf_no, priv->fn_id_info.vf_no)); } #endif #ifdef TC956X - /* MSI_MSK_CLR, unmask vector 0 */ - writel(0x1, priv->ioaddr + TC956X_MSI_MASK_CLR_OFFSET(priv->port_num)); +#if defined(TC956X_SRIOV_PF) && !defined(TC956X_AUTOMOTIVE_CONFIG) && !defined(TC956X_ENABLE_MAC2MAC_BRIDGE) + /* unmask MSI vector 1 */ + tc956x_msi_intr_clr(priv, dev, TC956X_MSI_VECTOR_1); +#endif #endif return IRQ_HANDLED; } +#endif #ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE #ifdef CONFIG_NET_POLL_CONTROLLER @@ -7683,7 +9549,13 @@ static irqreturn_t tc956xmac_interrupt(int irq, void *dev_id) static void tc956xmac_poll_controller(struct net_device *dev) { disable_irq(dev->irq); - tc956xmac_interrupt(dev->irq, dev); +#ifdef TC956X_SRIOV_PF + tc956xmac_interrupt_v0(dev->irq, dev); + tc956xmac_interrupt_v1(dev->irq, dev); +#elif defined TC956X_SRIOV_VF + tc956xmac_interrupt_v0(dev->irq, dev); + //tc956xmac_interrupt_v1(dev->irq, dev); +#endif enable_irq(dev->irq); } #endif @@ -7694,9 +9566,9 @@ int tc956xmac_rx_parser_configuration(struct tc956xmac_priv *priv) int ret = -EINVAL, re_init_eee = 0, dly_cnt = 0, ret_val; struct ethtool_eee edata; +#ifndef TC956X_SRIOV_VF /* Disable EEE before configuring FRP */ if (priv->eee_enabled) { - if (priv->hw->xpcs) { tc956x_xpcs_ctrl0_lrx(priv, false); re_init_eee = 1; @@ -7735,17 +9607,17 @@ int tc956xmac_rx_parser_configuration(struct tc956xmac_priv *priv) re_init_eee = 1; } } - +#endif if (priv->hw->mac->rx_parser_init && priv->plat->rxp_cfg.enable) ret = tc956xmac_rx_parser_init(priv, priv->dev, priv->hw, priv->dma_cap.spram, priv->dma_cap.frpsel, priv->dma_cap.frpes, &priv->plat->rxp_cfg); +#ifndef TC956X_SRIOV_VF /* Restore EEE state */ if (re_init_eee) { re_init_eee = 0; - if (priv->hw->xpcs) tc956x_xpcs_ctrl0_lrx(priv, true); else { @@ -7784,7 +9656,8 @@ int tc956xmac_rx_parser_configuration(struct tc956xmac_priv *priv) } } - /* spram feautre is not present in TC956X */ +#endif + /* spram feautre is not present in TC956X */ if (ret) priv->rxp_enabled = false; else @@ -7792,7 +9665,8 @@ int tc956xmac_rx_parser_configuration(struct tc956xmac_priv *priv) return ret; } -#ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE + +#ifndef TC956X_SRIOV_VF static int tc956xmac_est_configuration_ioctl(struct tc956xmac_priv *priv) { int ret = -EINVAL; @@ -7819,16 +9693,26 @@ static int tc956xmac_est_configuration_ioctl(struct tc956xmac_priv *priv) * As pre-requisite for calling this function, CBS Set must be done before get. * */ +#ifdef TC956X_SRIOV_PF +int tc956xmac_ioctl_get_cbs(struct tc956xmac_priv *priv, void *data) +#else static int tc956xmac_ioctl_get_cbs(struct tc956xmac_priv *priv, void __user *data) +#endif { u32 tx_qcount = priv->plat->tx_queues_to_use; struct tc956xmac_ioctl_cbs_cfg cbs; u8 qmode; - +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + unsigned long flags; +#endif DBGPR_FUNC(priv->device, "-->%s\n", __func__); +#ifdef TC956X_SRIOV_PF + memcpy(&cbs, data, sizeof(cbs)); +#else if (copy_from_user(&cbs, data, sizeof(cbs))) return -EFAULT; +#endif /* queue 0 is reserved for legacy traffic; cbs configuration not allowed (registers also not available for Q0)*/ if ((cbs.queue_idx >= tx_qcount) || (cbs.queue_idx == 0)) @@ -7839,7 +9723,9 @@ static int tc956xmac_ioctl_get_cbs(struct tc956xmac_priv *priv, void __user *dat /* Only AVB queue supported for cbs */ if (qmode != MTL_QUEUE_AVB) return -EINVAL; - +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_lock_irqsave(&priv->spn_lock.cbs, flags); +#endif cbs.speed100cfg.send_slope = priv->cbs_speed100_cfg[cbs.queue_idx].send_slope; cbs.speed100cfg.idle_slope = priv->cbs_speed100_cfg[cbs.queue_idx].idle_slope; cbs.speed100cfg.high_credit = priv->cbs_speed100_cfg[cbs.queue_idx].high_credit; @@ -7864,24 +9750,41 @@ static int tc956xmac_ioctl_get_cbs(struct tc956xmac_priv *priv, void __user *dat cbs.speed2500cfg.idle_slope = priv->cbs_speed2500_cfg[cbs.queue_idx].idle_slope; cbs.speed2500cfg.high_credit = priv->cbs_speed2500_cfg[cbs.queue_idx].high_credit; cbs.speed2500cfg.low_credit = priv->cbs_speed2500_cfg[cbs.queue_idx].low_credit; +#ifdef TC956X_SRIOV_PF + memcpy(data, &cbs, sizeof(cbs)); +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_unlock_irqrestore(&priv->spn_lock.cbs, flags); +#endif +#else if (copy_to_user(data, &cbs, sizeof(cbs))) return -EFAULT; +#endif DBGPR_FUNC(priv->device, "<--%s\n", __func__); return 0; } +#ifdef TC956X_SRIOV_PF +int tc956xmac_ioctl_set_cbs(struct tc956xmac_priv *priv, void *data) +#else static int tc956xmac_ioctl_set_cbs(struct tc956xmac_priv *priv, void __user *data) +#endif { u32 tx_qcount = priv->plat->tx_queues_to_use; struct tc956xmac_ioctl_cbs_cfg cbs; u8 qmode; - +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + unsigned long flags; +#endif DBGPR_FUNC(priv->device, "-->%s\n", __func__); +#ifdef TC956X_SRIOV_PF + memcpy(&cbs, data, sizeof(cbs)); +#else if (copy_from_user(&cbs, data, sizeof(cbs))) return -EFAULT; +#endif /* queue 0 is reserved for legacy traffic; cbs configuration not allowed (registers also not available for Q0)*/ if ((cbs.queue_idx >= tx_qcount) || (cbs.queue_idx == 0)) @@ -7890,11 +9793,19 @@ static int tc956xmac_ioctl_set_cbs(struct tc956xmac_priv *priv, void __user *dat if (!priv->hw->mac->config_cbs) return -EINVAL; +#ifdef TC956X_SRIOV_VF + /* skip configuring for unallocated queue */ + if (priv->plat->tx_q_in_use[cbs.queue_idx] == 0) + return -EINVAL; +#endif + qmode = priv->plat->tx_queues_cfg[cbs.queue_idx].mode_to_use; if (qmode != MTL_QUEUE_AVB) return -EINVAL; - +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_lock_irqsave(&priv->spn_lock.cbs, flags); +#endif priv->cbs_speed100_cfg[cbs.queue_idx].send_slope = cbs.speed100cfg.send_slope; priv->cbs_speed100_cfg[cbs.queue_idx].idle_slope = cbs.speed100cfg.idle_slope; priv->cbs_speed100_cfg[cbs.queue_idx].high_credit = cbs.speed100cfg.high_credit; @@ -7967,29 +9878,50 @@ static int tc956xmac_ioctl_set_cbs(struct tc956xmac_priv *priv, void __user *dat priv->plat->tx_queues_cfg[cbs.queue_idx].low_credit = priv->cbs_speed5000_cfg[cbs.queue_idx].low_credit; } - +#ifdef TC956X_SRIOV_PF tc956xmac_config_cbs(priv, priv->hw, priv->plat->tx_queues_cfg[cbs.queue_idx].send_slope, priv->plat->tx_queues_cfg[cbs.queue_idx].idle_slope, priv->plat->tx_queues_cfg[cbs.queue_idx].high_credit, priv->plat->tx_queues_cfg[cbs.queue_idx].low_credit, cbs.queue_idx); - +#elif defined TC956X_SRIOV_VF + tc956xmac_config_cbs(priv, + priv->plat->tx_queues_cfg[cbs.queue_idx].send_slope, + priv->plat->tx_queues_cfg[cbs.queue_idx].idle_slope, + priv->plat->tx_queues_cfg[cbs.queue_idx].high_credit, + priv->plat->tx_queues_cfg[cbs.queue_idx].low_credit, + cbs.queue_idx); +#endif +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_unlock_irqrestore(&priv->spn_lock.cbs, flags); +#endif DBGPR_FUNC(priv->device, "<--%s\n", __func__); return 0; } +#ifdef TC956X_SRIOV_PF +int tc956xmac_ioctl_get_est(struct tc956xmac_priv *priv, void *data) +#else static int tc956xmac_ioctl_get_est(struct tc956xmac_priv *priv, void __user *data) +#endif { struct tc956xmac_ioctl_est_cfg *est; int ret = 0; - +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + unsigned long flags; +#endif DBGPR_FUNC(priv->device, "-->%s\n", __func__); - +#ifdef TC956X_SRIOV_PF + est = data; +#else est = kzalloc(sizeof(*est), GFP_KERNEL); if (!est) return -ENOMEM; - +#endif +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_lock_irqsave(&priv->spn_lock.est, flags); +#endif est->enabled = priv->plat->est->enable; est->estwid = priv->dma_cap.estwid; est->estdep = priv->dma_cap.estdep; @@ -8000,37 +9932,51 @@ static int tc956xmac_ioctl_get_est(struct tc956xmac_priv *priv, void __user *dat est->ter = priv->plat->est->ter; est->gcl_size = priv->plat->est->gcl_size; memcpy(est->gcl, priv->plat->est->gcl, est->gcl_size * sizeof(*est->gcl)); + +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_unlock_irqrestore(&priv->spn_lock.est, flags); +#endif + +#ifndef TC956X_SRIOV_PF if (copy_to_user(data, est, sizeof(*est))) { ret = -EFAULT; goto out_free; } +#endif DBGPR_FUNC(priv->device, "<--%s\n", __func__); - +#ifndef TC956X_SRIOV_PF out_free: kfree(est); - +#endif return ret; } +#ifdef TC956X_SRIOV_PF +int tc956xmac_ioctl_set_est(struct tc956xmac_priv *priv, void *data) +#else static int tc956xmac_ioctl_set_est(struct tc956xmac_priv *priv, void __user *data) +#endif { struct tc956xmac_est *cfg = priv->plat->est; struct tc956xmac_ioctl_est_cfg *est; int ret = 0; -#ifdef TC956X u64 system_time; u32 system_time_s; u32 system_time_ns; #ifndef CONFIG_ARCH_DMA_ADDR_T_64BIT u64 quotient; u32 reminder; -#endif #endif - +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + unsigned long flags; +#endif DBGPR_FUNC(priv->device, "-->%s\n", __func__); +#ifdef TC956X_SRIOV_PF + est = data; +#else est = kzalloc(sizeof(*est), GFP_KERNEL); if (!est) return -ENOMEM; @@ -8039,11 +9985,18 @@ static int tc956xmac_ioctl_set_est(struct tc956xmac_priv *priv, void __user *dat ret = -EFAULT; goto out_free; } -#ifdef TC956X +#endif if (est->gcl_size > TC956XMAC_IOCTL_EST_GCL_MAX_ENTRIES) { ret = -EINVAL; goto out_free; } + + if (cfg->gcl_size > priv->dma_cap.estdep) { + ret = -EINVAL; + goto out_free; + } +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_lock_irqsave(&priv->spn_lock.est, flags); #endif if (est->enabled) { cfg->btr_offset[0] = est->btr_offset[0]; @@ -8052,7 +10005,7 @@ static int tc956xmac_ioctl_set_est(struct tc956xmac_priv *priv, void __user *dat cfg->ctr[1] = est->ctr[1]; cfg->ter = est->ter; cfg->gcl_size = est->gcl_size; -#ifdef TC956X + /* BTR Offset */ tc956xmac_get_systime(priv, priv->ptpaddr, &system_time); #ifndef CONFIG_ARCH_DMA_ADDR_T_64BIT @@ -8065,7 +10018,6 @@ static int tc956xmac_ioctl_set_est(struct tc956xmac_priv *priv, void __user *dat #endif cfg->btr[0] = cfg->btr_offset[0] + (u32)system_time_ns; cfg->btr[1] = cfg->btr_offset[1] + (u32)system_time_s; -#endif memcpy(cfg->gcl, est->gcl, cfg->gcl_size * sizeof(*cfg->gcl)); } else { cfg->btr_offset[0] = 0; @@ -8082,7 +10034,9 @@ static int tc956xmac_ioctl_set_est(struct tc956xmac_priv *priv, void __user *dat if (!est->enabled) ret = 0; - +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_unlock_irqrestore(&priv->spn_lock.est, flags); +#endif DBGPR_FUNC(priv->device, "<--%s\n", __func__); out_free: @@ -8090,16 +10044,31 @@ static int tc956xmac_ioctl_set_est(struct tc956xmac_priv *priv, void __user *dat return ret; } +#ifdef TC956X_SRIOV_PF +int tc956xmac_ioctl_get_fpe(struct tc956xmac_priv *priv, void *data) +#else static int tc956xmac_ioctl_get_fpe(struct tc956xmac_priv *priv, void __user *data) +#endif { struct tc956xmac_ioctl_fpe_cfg *fpe; int ret = 0; unsigned int control = 0; +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + unsigned long flags; +#endif + DBGPR_FUNC(priv->device, "-->%s\n", __func__); +#ifdef TC956X_SRIOV_PF + fpe = data; +#else fpe = kzalloc(sizeof(*fpe), GFP_KERNEL); if (!fpe) return -ENOMEM; +#endif +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_lock_irqsave(&priv->spn_lock.fpe, flags); +#endif #ifdef TC956X control = readl(priv->ioaddr + XGMAC_FPE_CTRL_STS); #endif @@ -8121,21 +10090,37 @@ static int tc956xmac_ioctl_get_fpe(struct tc956xmac_priv *priv, void __user *dat fpe->HA_time = 0; fpe->RA_time = 0; } +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_unlock_irqrestore(&priv->spn_lock.fpe, flags); +#endif +#ifndef TC956X_SRIOV_PF if (copy_to_user(data, fpe, sizeof(*fpe))) { ret = -EFAULT; goto out_free; } out_free: kfree(fpe); +#endif return ret; } +#ifdef TC956X_SRIOV_PF +int tc956xmac_ioctl_set_fpe(struct tc956xmac_priv *priv, void *data) +#else static int tc956xmac_ioctl_set_fpe(struct tc956xmac_priv *priv, void __user *data) +#endif { struct tc956xmac_ioctl_fpe_cfg *fpe; int ret = 0; unsigned int control = 0; +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + unsigned long flags; +#endif + DBGPR_FUNC(priv->device, "-->%s\n", __func__); +#ifdef TC956X_SRIOV_PF + fpe = data; +#else fpe = kzalloc(sizeof(*fpe), GFP_KERNEL); if (!fpe) return -ENOMEM; @@ -8143,6 +10128,10 @@ static int tc956xmac_ioctl_set_fpe(struct tc956xmac_priv *priv, void __user *dat ret = -EFAULT; goto out_free; } +#endif +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_lock_irqsave(&priv->spn_lock.fpe, flags); +#endif #ifdef TC956X if (fpe->enabled) { control = readl(priv->ioaddr + XGMAC_MTL_FPE_CTRL_STS); @@ -8174,27 +10163,54 @@ static int tc956xmac_ioctl_set_fpe(struct tc956xmac_priv *priv, void __user *dat writel(control, priv->ioaddr + XGMAC_MTL_FPE_CTRL_STS); } #endif - +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_unlock_irqrestore(&priv->spn_lock.fpe, flags); +#endif +#ifndef TC956X_SRIOV_PF out_free: kfree(fpe); +#endif return ret; } -#endif /* TC956X_UNSUPPORTED_UNTESTED_FEATURE */ + +#ifdef TC956X_SRIOV_PF +int tc956xmac_ioctl_get_rxp(struct tc956xmac_priv *priv, void *data) +#else static int tc956xmac_ioctl_get_rxp(struct tc956xmac_priv *priv, void __user *data) +#endif { struct tc956xmac_rx_parser_cfg *cfg = &priv->plat->rxp_cfg; struct tc956xmac_ioctl_rxp_cfg *rxp; int ret = 0; +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + unsigned long flags; +#endif + + DBGPR_FUNC(priv->device, "-->%s\n", __func__); + +#ifdef TC956X_SRIOV_PF + rxp = data; +#else rxp = kzalloc(sizeof(*rxp), GFP_KERNEL); if (!rxp) return -ENOMEM; +#endif +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_lock_irqsave(&priv->spn_lock.frp, flags); +#endif rxp->enabled = priv->rxp_enabled; rxp->frpes = priv->dma_cap.frpes; rxp->nve = cfg->nve; rxp->npe = cfg->npe; memcpy(rxp->entries, cfg->entries, rxp->nve * sizeof(*cfg->entries)); + +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_unlock_irqrestore(&priv->spn_lock.frp, flags); +#endif + +#ifndef TC956X_SRIOV_PF if (copy_to_user(data, rxp, sizeof(*rxp))) { ret = -EFAULT; goto out_free; @@ -8202,15 +10218,28 @@ static int tc956xmac_ioctl_get_rxp(struct tc956xmac_priv *priv, void __user *dat out_free: kfree(rxp); +#endif return ret; } +#ifdef TC956X_SRIOV_PF +int tc956xmac_ioctl_set_rxp(struct tc956xmac_priv *priv, void *data) +#else static int tc956xmac_ioctl_set_rxp(struct tc956xmac_priv *priv, void __user *data) +#endif { struct tc956xmac_rx_parser_cfg *cfg = &priv->plat->rxp_cfg; struct tc956xmac_ioctl_rxp_cfg *rxp; int ret = 0; +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + unsigned long flags; +#endif + DBGPR_FUNC(priv->device, "-->%s\n", __func__); + +#ifdef TC956X_SRIOV_PF + rxp = data; +#else rxp = kzalloc(sizeof(*rxp), GFP_KERNEL); if (!rxp) return -ENOMEM; @@ -8219,11 +10248,14 @@ static int tc956xmac_ioctl_set_rxp(struct tc956xmac_priv *priv, void __user *dat ret = -EFAULT; goto out_free; } +#endif if (rxp->nve > TC956XMAC_RX_PARSER_MAX_ENTRIES) { ret = -EINVAL; goto out_free; } - +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_lock_irqsave(&priv->spn_lock.frp, flags); +#endif if (rxp->enabled) { cfg->nve = rxp->nve; cfg->npe = rxp->npe; @@ -8238,12 +10270,14 @@ static int tc956xmac_ioctl_set_rxp(struct tc956xmac_priv *priv, void __user *dat ret = tc956xmac_rx_parser_configuration(priv); if (!rxp->enabled) ret = 0; - +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_unlock_irqrestore(&priv->spn_lock.frp, flags); +#endif out_free: kfree(rxp); return ret; } - +#endif static int tc956xmac_ioctl_get_tx_free_desc(struct tc956xmac_priv *priv, void __user *data) { @@ -8255,9 +10289,13 @@ static int tc956xmac_ioctl_get_tx_free_desc(struct tc956xmac_priv *priv, void __ if (copy_from_user(&ioctl_data, data, sizeof(ioctl_data))) return -EFAULT; - if ((ioctl_data.queue_idx < priv->plat->tx_queues_to_use) && (ioctl_data.queue_idx != 1) && - (priv->plat->tx_dma_ch_owner[ioctl_data.queue_idx] == USE_IN_TC956X_SW)) { - +#ifdef TC956X_SRIOV_PF + if ((ioctl_data.queue_idx < priv->plat->tx_queues_to_use) && + (priv->plat->tx_ch_in_use[ioctl_data.queue_idx] == TC956X_ENABLE_CHNL)) { +#else + if ((ioctl_data.queue_idx < priv->plat->tx_queues_to_use) && + (priv->plat->ch_in_use[ioctl_data.queue_idx] == 1)) { +#endif tx_free_desc = tc956xmac_tx_avail(priv, ioctl_data.queue_idx); if (copy_to_user((void __user *)ioctl_data.ptr, &tx_free_desc, sizeof(unsigned int))) return -EFAULT; @@ -8270,6 +10308,7 @@ static int tc956xmac_ioctl_get_tx_free_desc(struct tc956xmac_priv *priv, void __ return 0; } +#ifndef TC956X_SRIOV_VF static int tc956xmac_ioctl_get_connected_speed(struct tc956xmac_priv *priv, void __user *data) { struct tc956xmac_ioctl_speed ioctl_data; @@ -8289,6 +10328,7 @@ static int tc956xmac_ioctl_get_connected_speed(struct tc956xmac_priv *priv, void DBGPR_FUNC(priv->device, "<--%s\n", __func__); return 0; } +#endif /* TC956X_SRIOV_VF */ #ifdef TC956X_IOCTL_REG_RD_WR_ENABLE /*! @@ -8323,6 +10363,7 @@ static int tc956xmac_reg_rd(struct tc956xmac_priv *priv, void __user *data) } +#ifndef TC956X_SRIOV_VF /*! * \brief API to write register * \param[in] address offset as per tc956x data-sheet @@ -8354,7 +10395,9 @@ static int tc956xmac_reg_wr(struct tc956xmac_priv *priv, void __user *data) return 0; } #endif +#endif +#ifndef TC956X_SRIOV_VF static int tc956xmac_ioctl_set_mac_loopback(struct tc956xmac_priv *priv, void __user *data) { struct tc956xmac_ioctl_loopback ioctl_data; @@ -8448,17 +10491,20 @@ static int tc956xmac_config_vlan_filter(struct tc956xmac_priv *priv, void __user { struct tc956xmac_ioctl_vlan_filter ioctl_data; u32 reg_val; - +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + unsigned long flags; +#endif if (!(priv->dev->features & NETIF_F_HW_VLAN_CTAG_FILTER)) return -EPERM; - if (copy_from_user(&ioctl_data, data, sizeof(ioctl_data))) return -EFAULT; - /* Disabling VLAN is not supported */ if (ioctl_data.filter_enb_dis == 0) return -EINVAL; +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_lock_irqsave(&priv->spn_lock.vlan_filter, flags); +#endif #ifndef TC956X /* configure the vlan filter */ reg_val = readl(priv->ioaddr + XGMAC_PACKET_FILTER); @@ -8490,6 +10536,9 @@ static int tc956xmac_config_vlan_filter(struct tc956xmac_priv *priv, void __user writel(reg_val, priv->ioaddr + XGMAC_VLAN_TAG); priv->vlan_hash_filtering = ioctl_data.perfect_hash; +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_unlock_irqrestore(&priv->spn_lock.vlan_filter, flags); +#endif KPRINT_INFO("Successfully %s VLAN %s filtering and %s matching\n", (ioctl_data.filter_enb_dis ? "ENABLED" : "DISABLED"), (ioctl_data.perfect_hash ? "HASH" : "PERFECT"), @@ -8586,7 +10635,7 @@ static void tc956x_ptp_configuration(struct tc956xmac_priv *priv, u32 tcr_config if (tcr_config == 0) { control = PTP_TCR_TSENA | PTP_TCR_TSCTRLSSR - | PTP_TCR_TSCFUPDT; + | PTP_TCR_TSCFUPDT | PTP_TCR_TSENALL; control |= PTP_TCR_PTGE; control |= 0x10013e03; } else { @@ -8618,15 +10667,11 @@ static void tc956x_ptp_configuration(struct tc956xmac_priv *priv, u32 tcr_config ktime_get_real_ts64(&now); tc956xmac_init_systime(priv, priv->ptpaddr, (u32)now.tv_sec, now.tv_nsec); - control |= PTP_TCR_TSINIT; - tc956xmac_config_hw_tstamping(priv, priv->ptpaddr, control); - priv->hwts_tx_en = 1; priv->hwts_rx_en = 1; } -#ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE static int pps_configuration(struct tc956xmac_priv *priv, struct tc956xmac_PPS_Config *tc956x_pps_cfg) { @@ -8639,7 +10684,6 @@ static int pps_configuration(struct tc956xmac_priv *priv, DBGPR_FUNC(priv->device, "--> %s\n", __func__); } - interval = (tc956x_pps_cfg->ptpclk_freq + tc956x_pps_cfg->ppsout_freq/2) / tc956x_pps_cfg->ppsout_freq; @@ -8685,16 +10729,32 @@ static int pps_configuration(struct tc956xmac_priv *priv, writel(width, priv->ioaddr + XGMAC_PPSx_WIDTH(tc956x_pps_cfg->ppsout_ch)); #endif - if (tc956x_pps_cfg->ppsout_ch == 0) { - val = readl(priv->ioaddr + NFUNCEN4_OFFSET); - val &= (~0x00000F00); /* GPIO2 */ - val |= 0x00000100; - writel(val, priv->ioaddr + NFUNCEN4_OFFSET); - } else if (tc956x_pps_cfg->ppsout_ch == 1) { - val = readl(priv->ioaddr + NFUNCEN4_OFFSET); - val &= (~0x000F0000); /* GPIO4 */ - val |= 0x00010000; - writel(val, priv->ioaddr + NFUNCEN4_OFFSET); + if (priv->port_num == RM_PF0_ID) { + if (tc956x_pps_cfg->ppsout_ch == 0) { /* PPO00 */ + val = readl(priv->ioaddr + NFUNCEN4_OFFSET); + val &= (~NFUNCEN4_GPIO2_MASK); /* GPIO2 */ + val |= ((FUNCTION1 << NFUNCEN4_GPIO2_SHIFT) & NFUNCEN4_GPIO2_MASK); + writel(val, priv->ioaddr + NFUNCEN4_OFFSET); + } else if (tc956x_pps_cfg->ppsout_ch == 1) { /* PPO01 */ + val = readl(priv->ioaddr + NFUNCEN0_OFFSET); + val &= (~NFUNCEN0_JTAGEN_MASK); /* Disable JTAGEN */ + val &= (~NFUNCEN0_JTAG_MASK); /* Clear JTAG Function */ + val |= ((FUNCTION2 << NFUNCEN0_JTAG_SHIFT) & NFUNCEN0_JTAG_MASK); + writel(val, priv->ioaddr + NFUNCEN0_OFFSET); + } + } else if (priv->port_num == RM_PF1_ID) { + if (tc956x_pps_cfg->ppsout_ch == 0) { /* PPO10 */ + val = readl(priv->ioaddr + NFUNCEN4_OFFSET); + val &= (~NFUNCEN4_GPIO4_MASK); /* GPIO4 */ + val |= ((FUNCTION1 << NFUNCEN4_GPIO4_SHIFT) & NFUNCEN4_GPIO4_MASK); + writel(val, priv->ioaddr + NFUNCEN4_OFFSET); + } else if (tc956x_pps_cfg->ppsout_ch == 1) { /* PPO11 */ + val = readl(priv->ioaddr + NFUNCEN0_OFFSET); + val &= (~NFUNCEN0_JTAGEN_MASK); /* Disable JTAGEN */ + val &= (~NFUNCEN0_JTAG_MASK); /* Clear JTAG Function */ + val |= ((FUNCTION2 << NFUNCEN0_JTAG_SHIFT) & NFUNCEN0_JTAG_MASK); + writel(val, priv->ioaddr + NFUNCEN0_OFFSET); + } } #ifdef TC956X @@ -8885,6 +10945,11 @@ static int tc956xmac_config_ptpoffload(struct tc956xmac_priv *priv, void __user if (copy_from_user(&ioctl_data, data, sizeof(ioctl_data))) return -EFAULT; + if ((ioctl_data.domain_num < 0U) + || (ioctl_data.domain_num > 0xFFU)) { + return -EINVAL; + } + pto_cntrl = XGMAC_PTOEN; /* enable ptp offloading */ varMAC_TCR = readl(priv->ptpaddr + PTP_TCR); @@ -8915,21 +10980,23 @@ static int tc956xmac_config_ptpoffload(struct tc956xmac_priv *priv, void __user pto_cntrl |= XGMAC_APDREQEN; varMAC_TCR |= (3 << PTP_TCR_SNAPTYPSEL_1_LPOS); priv->ptp_offloading_mode = TC956X_PTP_PEER_TO_PEER_TRANSPARENT; - } + } else + return -EINVAL; priv->ptp_offload = 1; + pto_cntrl |= (ioctl_data.domain_num << 8); + + if ((ioctl_data.en_dis != TC956X_PTP_OFFLOADING_DISABLE) && (ioctl_data.mc_uc == 1)) + tc956x_add_mac_addr(priv->dev, ioctl_data.mc_uc_addr); + if (ioctl_data.en_dis == TC956X_PTP_OFFLOADING_DISABLE) { pto_cntrl = 0; varMAC_TCR = readl(priv->ptpaddr + PTP_TCR); priv->ptp_offload = 0; } - pto_cntrl |= (ioctl_data.domain_num << 8); writel(varMAC_TCR, priv->ptpaddr + PTP_TCR); - /* Since time registers are already initialized by default, no need to initialize time. */ - if (ioctl_data.mc_uc == 1) - tc956xmac_set_umac_addr(priv, priv->hw, ioctl_data.mc_uc_addr, 0, PF_DRIVER); #ifdef TC956X writel(pto_cntrl, priv->ioaddr + XGMAC_PTO_CTRL); @@ -8943,52 +11010,58 @@ static int tc956xmac_config_ptpoffload(struct tc956xmac_priv *priv, void __user return 0; } +#endif + +#ifndef TC956X_SRIOV_VF /*! * \brief API to configure to enable auxiliary timestamp feature * \param[in] tc956xmac priv structure - * \param[in] An IOCTL specefic structure, that can contain a data pointer + * \param[in] An IOCTL specific structure, that can contain a data pointer * \return 0 (success) or Error value (fail) */ static int tc956xmac_aux_timestamp_enable(struct tc956xmac_priv *priv, void __user *data) { struct tc956x_ioctl_aux_snapshot ioctl_data; - u32 aux_cntrl_en; + u32 aux_cntrl_en, val; DBGPR_FUNC(priv->device, "--> %s\n", __func__); -#ifdef TC956X aux_cntrl_en = readl(priv->ioaddr + XGMAC_MAC_AUX_CTRL); -#endif + if (copy_from_user(&ioctl_data, data, sizeof(ioctl_data))) return -EFAULT; + if (ioctl_data.aux_snapshot_ctrl > 1) + return -EFAULT; + if ((ioctl_data.aux_snapshot_ctrl & TC956X_AUX_SNAPSHOT_0)) aux_cntrl_en |= XGMAC_ATSEN0; else aux_cntrl_en &= ~XGMAC_ATSEN0; - if ((ioctl_data.aux_snapshot_ctrl & TC956X_AUX_SNAPSHOT_1)) - aux_cntrl_en |= XGMAC_ATSEN1; - else - aux_cntrl_en &= ~XGMAC_ATSEN1; - - if ((ioctl_data.aux_snapshot_ctrl & TC956X_AUX_SNAPSHOT_2)) - aux_cntrl_en |= XGMAC_ATSEN2; - else - aux_cntrl_en &= ~XGMAC_ATSEN2; - - if ((ioctl_data.aux_snapshot_ctrl & TC956X_AUX_SNAPSHOT_3)) - aux_cntrl_en |= XGMAC_ATSEN3; - else - aux_cntrl_en &= ~XGMAC_ATSEN3; - /* Auxiliary timestamp FIFO clear */ aux_cntrl_en |= XGMAC_ATSFC; -#ifdef TC956X writel(aux_cntrl_en, priv->ioaddr + XGMAC_MAC_AUX_CTRL); -#endif + + if (priv->port_num == RM_PF0_ID) { + val = readl(priv->ioaddr + NFUNCEN4_OFFSET); + val &= ~TRIG00_MASK; + val |= (0x1 << TRIG00_SHIFT); /* set bit 4 GPIO1 TRIG00 */ + writel(val, priv->ioaddr + NFUNCEN4_OFFSET); + } + if (priv->port_num == RM_PF1_ID) { + val = readl(priv->ioaddr + NFUNCEN4_OFFSET); + val &= ~TRIG10_MASK; + val |= (0x1 << TRIG10_SHIFT); /* set bit 12 GPIO3 TRIG10 */ + writel(val, priv->ioaddr + NFUNCEN4_OFFSET); + } + + /* Enable the Trig interrupt */ + val = readl(priv->ioaddr + XGMAC_INT_EN); + val |= (0x1 << TSIE_SHIFT); /* set bit 12req=50000000Hz */ + writel(val, priv->ioaddr + XGMAC_INT_EN); DBGPR_FUNC(priv->device, "--> %s\n", __func__); @@ -9019,13 +11092,14 @@ static int tc956xmac_config_onestep_timestamp(struct tc956xmac_priv *priv, void return 0; } -#endif /* TC956X_UNSUPPORTED_UNTESTED_FEATURE */ static int tc956xmac_sa_vlan_ins_config(struct tc956xmac_priv *priv, void __user *data) { struct tc956xmac_ioctl_sa_ins_cfg ioctl_data; u32 reg_data; - +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + unsigned long flags; +#endif DBGPR_FUNC(priv->device, "-->%s\n", __func__); if (copy_from_user(&ioctl_data, data, sizeof(ioctl_data))) return -EFAULT; @@ -9040,7 +11114,16 @@ static int tc956xmac_sa_vlan_ins_config(struct tc956xmac_priv *priv, void __user memcpy(priv->ins_mac_addr, ioctl_data.mac_addr, ETH_ALEN); #ifdef TC956X +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_lock_irqsave(&priv->spn_lock.mac_filter, flags); +#endif + tc956xmac_set_umac_addr(priv, priv->hw, priv->ins_mac_addr, 0, PF_DRIVER); + +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_unlock_irqrestore(&priv->spn_lock.mac_filter, flags); +#endif + reg_data = readl(priv->ioaddr + XGMAC_TX_CONFIG); reg_data = (reg_data & (~XGMAC_CONFIG_SARC)) | (priv->sa_vlan_ins_via_reg << XGMAC_CONFIG_SARC_SHIFT); @@ -9057,7 +11140,15 @@ static int tc956xmac_sa_vlan_ins_config(struct tc956xmac_priv *priv, void __user memcpy(priv->ins_mac_addr, ioctl_data.mac_addr, ETH_ALEN); #ifdef TC956X +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_lock_irqsave(&priv->spn_lock.mac_filter, flags); +#endif tc956xmac_set_umac_addr(priv, priv->hw, priv->ins_mac_addr, 1, PF_DRIVER); + +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_unlock_irqrestore(&priv->spn_lock.mac_filter, flags); +#endif + reg_data = readl(priv->ioaddr + XGMAC_TX_CONFIG); reg_data = (reg_data & (~XGMAC_CONFIG_SARC)) | (priv->sa_vlan_ins_via_reg << XGMAC_CONFIG_SARC_SHIFT); @@ -9077,6 +11168,7 @@ static int tc956xmac_sa_vlan_ins_config(struct tc956xmac_priv *priv, void __user return 0; } +#endif /* TC956X_SRIOV_VF */ static int tc956xmac_get_tx_qcnt(struct tc956xmac_priv *priv, void __user *data) { u32 tx_qcnt = 0; @@ -9167,7 +11259,7 @@ static int tc956xmac_pcie_config_reg_wr(struct tc956xmac_priv *priv, void __user return 0; } -#ifndef TC956X +#ifndef TC956X_SRIOV_VF /*! * \brief IOCTL to enable/disable VLAN Rx Stripping * \param[in] priv driver private structure @@ -9180,6 +11272,7 @@ static int tc956xmac_vlan_strip_config(struct tc956xmac_priv *priv, void __user { struct tc956xmac_ioctl_vlan_strip_cfg ioctl_data; u32 reg_data; + struct net_device *dev = priv->dev; DBGPR_FUNC(priv->device, "-->%s\n", __func__); if (copy_from_user(&ioctl_data, data, sizeof(ioctl_data))) @@ -9191,7 +11284,7 @@ static int tc956xmac_vlan_strip_config(struct tc956xmac_priv *priv, void __user reg_data = readl(priv->ioaddr + XGMAC_VLAN_TAG); reg_data &= ~XGMAC_VLAN_EVLS; reg_data |= 0x3 << XGMAC_VLAN_EVLS_SHIFT; - + dev->features |= NETIF_F_HW_VLAN_CTAG_RX; writel(reg_data, priv->ioaddr + XGMAC_VLAN_TAG); #endif } else { @@ -9199,13 +11292,13 @@ static int tc956xmac_vlan_strip_config(struct tc956xmac_priv *priv, void __user #ifdef TC956X reg_data = readl(priv->ioaddr + XGMAC_VLAN_TAG); reg_data &= ~XGMAC_VLAN_EVLS; - + dev->features &= ~NETIF_F_HW_VLAN_CTAG_RX; writel(reg_data, priv->ioaddr + XGMAC_VLAN_TAG); #endif } + netdev_features_change(dev); return 0; } -#endif #ifdef TC956X #ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE @@ -10982,11 +13075,20 @@ static int tc956xmac_pcie_speed_change(struct tc956xmac_priv *priv, void __user } #endif /*#define TC956X*/ +#endif /*#ifdef TC956X_SRIOV_VF*/ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)) +static int tc956xmac_siocdevprivate(struct net_device *dev, struct ifreq *rq, + void __user *data, int cmd) +#else static int tc956xmac_extension_ioctl(struct tc956xmac_priv *priv, void __user *data) +#endif { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)) + struct tc956xmac_priv *priv = netdev_priv(dev); +#else u32 cmd; - +#endif DBGPR_FUNC(priv->device, "-->%s\n", __func__); if (!capable(CAP_NET_ADMIN)) return -EPERM; @@ -10994,54 +13096,207 @@ static int tc956xmac_extension_ioctl(struct tc956xmac_priv *priv, return -EFAULT; switch (cmd) { -#ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE case TC956XMAC_GET_CBS: - return tc956xmac_ioctl_get_cbs(priv, data); +#ifdef TC956X_SRIOV_PF + { + int ret; + struct tc956xmac_ioctl_cbs_cfg cbs; + + if (copy_from_user(&cbs, data, sizeof(cbs))) + return -EFAULT; + + ret = tc956xmac_ioctl_get_cbs(priv, &cbs); + + if (ret == 0) { + if (copy_to_user(data, &cbs, sizeof(cbs))) + return -EFAULT; + } + + return ret; + } +#elif (defined TC956X_SRIOV_VF) + return tc956xmac_get_cbs(priv, data); +#endif case TC956XMAC_SET_CBS: - return tc956xmac_ioctl_set_cbs(priv, data); +#ifdef TC956X_SRIOV_PF + { + struct tc956xmac_ioctl_cbs_cfg cbs; + + if (copy_from_user(&cbs, data, sizeof(cbs))) + return -EFAULT; + + return tc956xmac_ioctl_set_cbs(priv, &cbs); + } +#elif (defined TC956X_SRIOV_VF) + return tc956xmac_set_cbs(priv, data); +#endif case TC956XMAC_GET_EST: - return tc956xmac_ioctl_get_est(priv, data); +#ifdef TC956X_SRIOV_PF + { + int ret; + struct tc956xmac_ioctl_est_cfg *est; + + est = kzalloc(sizeof(*est), GFP_KERNEL); + if (!est) + return -ENOMEM; + + ret = tc956xmac_ioctl_get_est(priv, est); + if (ret == 0) { + if (copy_to_user(data, est, sizeof(*est))) { + kfree(est); + return -EFAULT; + } + } + kfree(est); + return ret; + } +#elif (defined TC956X_SRIOV_VF) + return tc956xmac_get_est(priv, data); +#endif case TC956XMAC_SET_EST: - return tc956xmac_ioctl_set_est(priv, data); +#ifdef TC956X_SRIOV_PF + { + struct tc956xmac_ioctl_est_cfg *est; + + est = kzalloc(sizeof(*est), GFP_KERNEL); + if (!est) + return -ENOMEM; + + if (copy_from_user(est, data, sizeof(*est))) { + kfree(est); + return -EFAULT; + } + return tc956xmac_ioctl_set_est(priv, est); + } +#elif (defined TC956X_SRIOV_VF) + return tc956xmac_set_est(priv, data); +#endif + +#ifdef TC956X_UNSUPPORTED_UNTESTED case TC956XMAC_GET_FPE: /*Function to Get FPE related configurations*/ - return tc956xmac_ioctl_get_fpe(priv, data); +#ifdef TC956X_SRIOV_PF + { + int ret; + struct tc956xmac_ioctl_fpe_cfg *fpe; + + fpe = kzalloc(sizeof(*fpe), GFP_KERNEL); + if (!fpe) + return -ENOMEM; + + ret = tc956xmac_ioctl_get_fpe(priv, fpe); + if (ret == 0) { + if (copy_to_user(data, fpe, sizeof(*fpe))) { + kfree(fpe); + return -EFAULT; + } + } + kfree(fpe); + return ret; + } +#elif (defined TC956X_SRIOV_VF) + return tc956xmac_get_fpe(priv, data); +#endif case TC956XMAC_SET_FPE: /*Function to Set FPE related configurations*/ - return tc956xmac_ioctl_set_fpe(priv, data); -#endif /* TC956X_UNSUPPORTED_UNTESTED_FEATURE */ +#ifdef TC956X_SRIOV_PF + { + struct tc956xmac_ioctl_fpe_cfg *fpe; + + fpe = kzalloc(sizeof(*fpe), GFP_KERNEL); + if (!fpe) + return -ENOMEM; + + if (copy_from_user(fpe, data, sizeof(*fpe))) { + kfree(fpe); + return -EFAULT; + } + return tc956xmac_ioctl_set_fpe(priv, fpe); + } +#elif (defined TC956X_SRIOV_VF) + return tc956xmac_set_fpe(priv, data); +#endif +#endif /* TC956X_UNSUPPORTED_UNTESTED */ + +#ifdef TC956X_SRIOV_PF case TC956X_GET_FW_STATUS: return tc956x_xgmac_get_fw_status(priv, data); case TC956XMAC_VLAN_FILTERING: return tc956xmac_config_vlan_filter(priv, data); +#endif case TC956XMAC_GET_RXP: - return tc956xmac_ioctl_get_rxp(priv, data); +#ifdef TC956X_SRIOV_PF + { + int ret; + struct tc956xmac_ioctl_rxp_cfg *rxp; + + rxp = kzalloc(sizeof(*rxp), GFP_KERNEL); + if (!rxp) + return -ENOMEM; + + ret = tc956xmac_ioctl_get_rxp(priv, rxp); + if (ret == 0) { + if (copy_to_user(data, rxp, sizeof(*rxp))) { + kfree(rxp); + return -EFAULT; + } + } + kfree(rxp); + return ret; + } +#elif (defined TC956X_SRIOV_VF) + return tc956xmac_get_rxp(priv, data); +#endif case TC956XMAC_SET_RXP: - return tc956xmac_ioctl_set_rxp(priv, data); +#ifdef TC956X_SRIOV_PF + { + struct tc956xmac_ioctl_rxp_cfg *rxp; + + rxp = kzalloc(sizeof(*rxp), GFP_KERNEL); + if (!rxp) + return -ENOMEM; + + if (copy_from_user(rxp, data, sizeof(*rxp))) { + kfree(rxp); + return -EFAULT; + } + return tc956xmac_ioctl_set_rxp(priv, rxp); + } +#elif (defined TC956X_SRIOV_VF) + return tc956xmac_set_rxp(priv, data); +#endif case TC956XMAC_GET_SPEED: +#ifdef TC956X_SRIOV_PF return tc956xmac_ioctl_get_connected_speed(priv, data); +#elif defined TC956X_SRIOV_VF + return tc956xmac_get_speed(priv, data); +#endif case TC956XMAC_GET_TX_FREE_DESC: return tc956xmac_ioctl_get_tx_free_desc(priv, data); #ifdef TC956X_IOCTL_REG_RD_WR_ENABLE case TC956XMAC_REG_RD: return tc956xmac_reg_rd(priv, data); case TC956XMAC_REG_WR: +#ifdef TC956X_SRIOV_PF + return tc956xmac_reg_wr(priv, data); +#elif defined TC956X_SRIOV_VF return tc956xmac_reg_wr(priv, data); #endif +#endif /* TC956X_IOCTL_REG_RD_WR_ENABLE */ +#ifndef TC956X_SRIOV_VF case TC956XMAC_SET_MAC_LOOPBACK: return tc956xmac_ioctl_set_mac_loopback(priv, data); case TC956XMAC_SET_PHY_LOOPBACK: return tc956xmac_ioctl_set_phy_loopback(priv, data); case TC956XMAC_L2_DA_FILTERING_CMD: return tc956xmac_config_l2_da_filter(priv, data); -#ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE case TC956XMAC_SET_PPS_OUT: return tc956xmac_set_ppsout(priv, data); case TC956XMAC_PTPCLK_CONFIG: return tc956xmac_ptp_clk_config(priv, data); -#endif /* TC956X_UNSUPPORTED_UNTESTED_FEATURE */ case TC956XMAC_SA0_VLAN_INS_REP_REG: return tc956xmac_sa_vlan_ins_config(priv, data); case TC956XMAC_SA1_VLAN_INS_REP_REG: return tc956xmac_sa_vlan_ins_config(priv, data); +#endif /* TC956X_SRIOV_VF */ case TC956XMAC_GET_TX_QCNT: return tc956xmac_get_tx_qcnt(priv, data); case TC956XMAC_GET_RX_QCNT: @@ -11050,26 +13305,30 @@ static int tc956xmac_extension_ioctl(struct tc956xmac_priv *priv, return tc956xmac_pcie_config_reg_rd(priv, data); case TC956XMAC_PCIE_CONFIG_REG_WR: return tc956xmac_pcie_config_reg_wr(priv, data); -#ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE +#ifdef TC956X_SRIOV_PF case TC956XMAC_PTPOFFLOADING: return tc956xmac_config_ptpoffload(priv, data); +#endif /* TC956X_SRIOV_PF */ case TC956XMAC_ENABLE_AUX_TIMESTAMP: +#ifdef TC956X_SRIOV_PF return tc956xmac_aux_timestamp_enable(priv, data); +#endif +#ifdef TC956X_SRIOV_PF case TC956XMAC_ENABLE_ONESTEP_TIMESTAMP: return tc956xmac_config_onestep_timestamp(priv, data); -#endif /* TC956X_UNSUPPORTED_UNTESTED_FEATURE */ +#endif /* TC956X_SRIOV_PF */ + +#ifndef TC956X_SRIOV_VF #ifdef TC956X_PCIE_LOGSTAT - case TC956X_PCIE_SET_LOGSTAT_CONF: - return tc956x_pcie_ioctl_SetDbgConf(priv, data); - case TC956X_PCIE_GET_LOGSTAT_CONF: - return tc956x_pcie_ioctl_GetDbgConf(priv, data); - case TC956X_PCIE_GET_LTSSM_LOG: - return tc956x_pcie_ioctl_GetLTSSMLogD(priv, data); + case TC956X_PCIE_STATE_LOG_SUMMARY: + return tc956x_pcie_ioctl_state_log_summary(priv, data); + case TC956X_PCIE_GET_PCIE_LINK_PARAMS: + return tc956x_pcie_ioctl_get_pcie_link_params(priv, data); + case TC956X_PCIE_STATE_LOG_ENABLE: + return tc956x_pcie_ioctl_state_log_enable(priv, data); #endif /* #ifdef TC956X_PCIE_LOGSTAT */ -#ifndef TC956X case TC956XMAC_VLAN_STRIP_CONFIG: return tc956xmac_vlan_strip_config(priv, data); -#endif #ifdef TC956X case TC956XMAC_PCIE_LANE_CHANGE: return tc956xmac_pcie_lane_change(priv, data); @@ -11083,6 +13342,7 @@ static int tc956xmac_extension_ioctl(struct tc956xmac_priv *priv, return tc956xmac_pcie_set_ctle_fixed(priv, data); case TC956XMAC_PCIE_SPEED_CHANGE: return tc956xmac_pcie_speed_change(priv, data); +#endif /* TC956X */ #endif default: @@ -11092,6 +13352,7 @@ static int tc956xmac_extension_ioctl(struct tc956xmac_priv *priv, return 0; } +#ifndef TC956X_SRIOV_VF static int tc956xmac_phy_fw_flash_mdio_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd) { @@ -11099,6 +13360,7 @@ static int tc956xmac_phy_fw_flash_mdio_ioctl(struct net_device *ndev, struct tc956xmac_priv *priv = netdev_priv(ndev); int ret = -EINVAL; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 3, 0)) int prtad, devad; if (mdio_phy_id_is_c45(mii->phy_id)) { @@ -11109,14 +13371,18 @@ static int tc956xmac_phy_fw_flash_mdio_ioctl(struct net_device *ndev, prtad = mii->phy_id; devad = mii->reg_num; } - +#endif switch (cmd) { case SIOCGMIIPHY: mii->phy_id = 0; - /* fall through */ + fallthrough; case SIOCGMIIREG: +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 3, 0)) ret = priv->mii->read(priv->mii, prtad, devad); +#else + ret = phylink_mii_ioctl(priv->phylink, ifr, cmd); +#endif if (ret >= 0) { mii->val_out = ret; ret = 0; @@ -11124,8 +13390,12 @@ static int tc956xmac_phy_fw_flash_mdio_ioctl(struct net_device *ndev, break; case SIOCSMIIREG: +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 3, 0)) ret = priv->mii->write(priv->mii, prtad, devad, mii->val_in); +#else + ret = phylink_mii_ioctl(priv->phylink, ifr, cmd); +#endif break; default: @@ -11134,6 +13404,7 @@ static int tc956xmac_phy_fw_flash_mdio_ioctl(struct net_device *ndev, return ret; } +#endif /** * tc956xmac_ioctl - Entry point for the Ioctl @@ -11148,34 +13419,144 @@ static int tc956xmac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct tc956xmac_priv *priv = netdev_priv(dev); int ret = -EOPNOTSUPP; + +#ifdef TC956X_SRIOV_VF + u8 mbx[MBX_TOT_SIZE]; + + enum mbx_msg_fns msg_dst = priv->fn_id_info.pf_no + 1; +#endif struct mii_ioctl_data *data = if_mii(rq); if (!netif_running(dev)) +#ifndef TC956X_SRIOV_VF return tc956xmac_phy_fw_flash_mdio_ioctl(dev, rq, cmd); +#else + return -EINVAL; +#endif switch (cmd) { case SIOCGMIIPHY: +#ifndef TC956X_SRIOV_VF data->phy_id = priv->plat->phy_addr; NMSGPR_ALERT(priv->device, "PHY ID: SIOCGMIIPHY\n"); +#elif (defined TC956X_SRIOV_VF) + mbx[0] = OPCODE_MBX_VF_IOCTL; //opcode for ioctl + mbx[1] = 1; //size + mbx[2] = OPCODE_MBX_VF_GET_MII_PHY;//cmd for SIOCGMIIPHY + + ret = tc956xmac_mbx_write(priv, mbx, msg_dst, &priv->fn_id_info); + + /* Validation of successfull message posting can be done + * by reading the mbx buffer for ACK opcode (0xFE) + */ + if (ret > 0) { + if (ret == ACK) { + /* Check the acknowledgement message for opcode and size, + * then read the data from the ACK message + */ + if ((mbx[4] == OPCODE_MBX_ACK_MSG && mbx[5] == 4)) { + memcpy(&data->phy_id, &mbx[6], 4); + NMSGPR_ALERT(priv->device, "PHY ID: SIOCGMIIPHY\n"); + } + } + KPRINT_DEBUG2("mailbox write with ACK or NACK %d %x %x", ret, mbx[4], mbx[5]); + } else { + KPRINT_DEBUG2("mailbox write failed"); + } +#endif ret = 0; break; +#ifndef TC956X_SRIOV_VF case SIOCGMIIREG: case SIOCSMIIREG: ret = phylink_mii_ioctl(priv->phylink, rq, cmd); break; -#ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE +#elif defined TC956X_SRIOV_VF + case SIOCGMIIREG: + mbx[0] = OPCODE_MBX_VF_IOCTL; //opcode for ioctl + mbx[1] = SIZE_MBX_VF_GET_MII_REG; //size + mbx[2] = OPCODE_MBX_VF_GET_MII_REG_1;//cmd for SIOCGMIIREG + + memcpy(&mbx[3], &(data->phy_id), 2); + memcpy(&mbx[5], &(data->reg_num), 2); + memcpy(&mbx[7], &(data->val_in), 2); + + memset(&mbx[9], 0, sizeof(rq->ifr_ifrn.ifrn_name)); + memcpy(&mbx[9], &rq->ifr_ifrn.ifrn_name, sizeof(rq->ifr_ifrn.ifrn_name)); + ret = tc956xmac_mbx_write(priv, mbx, msg_dst, &priv->fn_id_info); + + /* Validation of successfull message posting can be done + * by reading the mbx buffer for ACK opcode (0xFF) + */ + if (ret > 0) { + if (ret == ACK) { + KPRINT_DEBUG2("mailbox write with ACK or NACK %d %x %x", ret, mbx[4], mbx[5]); + + mbx[0] = OPCODE_MBX_VF_IOCTL; //opcode for ioctl + mbx[1] = 1; //size + mbx[2] = OPCODE_MBX_VF_GET_MII_REG_2; + + ret = tc956xmac_mbx_write(priv, mbx, msg_dst, &priv->fn_id_info); + if (ret > 0) { + KPRINT_DEBUG2("mailbox write with ACK or NACK %d %x %x", ret, mbx[4], mbx[5]); + + if (ret == ACK) { + /* Check the acknowledgement message for opcode and size, + * then read the data from the ACK message + */ + if ((mbx[4] == OPCODE_MBX_ACK_MSG && mbx[5] == 2)) + memcpy(&(data->val_out), &mbx[6], 2); + } + } else + KPRINT_DEBUG2("mailbox write failed"); + } + } else { + KPRINT_DEBUG2("mailbox write failed"); + } + ret = 0; + break; +#endif +#ifndef TC956X_SRIOV_VF case SIOCSHWTSTAMP: ret = tc956xmac_hwtstamp_set(dev, rq); break; +#endif case SIOCGHWTSTAMP: +#ifndef TC956X_SRIOV_VF ret = tc956xmac_hwtstamp_get(dev, rq); +#else + mbx[0] = OPCODE_MBX_VF_IOCTL; //opcode for ioctl + mbx[1] = 1; //size + mbx[2] = OPCODE_MBX_VF_GET_HW_STMP;//cmd for SIOCGHWTSTAMP + + ret = tc956xmac_mbx_write(priv, mbx, msg_dst, &priv->fn_id_info); + + /* Validation of successfull message posting can be done + * by reading the mbx buffer for ACK opcode (0xFF) + */ + if (ret > 0) { + if (ret == ACK) { + /* Check the acknowledgement message for opcode and size, + * then read the data from the ACK message + */ + if ((mbx[4] == OPCODE_MBX_ACK_MSG && mbx[5] == SIZE_MBX_GET_HW_STMP)) { + if (copy_to_user(rq->ifr_data, &mbx[6], SIZE_MBX_GET_HW_STMP)) + ret = -EFAULT; + } + } + KPRINT_DEBUG2("mailbox write with ACK or NACK %d %x %x", ret, mbx[4], mbx[5]); + } else { + KPRINT_DEBUG2("mailbox write failed"); + } +#endif break; -#endif /* TC956X_UNSUPPORTED_UNTESTED_FEATURE */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0)) case SIOCSTIOCTL: if (!priv || !rq) return -EINVAL; ret = tc956xmac_extension_ioctl(priv, rq->ifr_data); break; +#endif default: break; } @@ -11186,7 +13567,6 @@ static int tc956xmac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) static int tc956xmac_setup_tc_block_cb(enum tc_setup_type type, void *type_data, void *cb_priv) { -#ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE struct tc956xmac_priv *priv = cb_priv; int ret = -EOPNOTSUPP; @@ -11208,10 +13588,6 @@ static int tc956xmac_setup_tc_block_cb(enum tc_setup_type type, void *type_data, tc956xmac_enable_all_queues(priv); return ret; -#else - return 0; -#endif /* TC956X_UNSUPPORTED_UNTESTED_FEATURE */ - } static LIST_HEAD(tc956xmac_block_cb_list); @@ -11233,6 +13609,10 @@ static int tc956xmac_setup_tc(struct net_device *ndev, enum tc_setup_type type, return tc956xmac_tc_setup_taprio(priv, type_data); case TC_SETUP_QDISC_ETF: return tc956xmac_tc_setup_etf(priv, type_data); +#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 2, 16)) + case TC_QUERY_CAPS: + return tc956xmac_tc_setup_query_cap(priv, type_data); +#endif default: return -EOPNOTSUPP; } @@ -11257,6 +13637,7 @@ static u16 tc956xmac_select_queue(struct net_device *dev, struct sk_buff *skb, avb_priority = htons((skb->data[15]<<8) | skb->data[14]); avb_priority >>= 13; +#ifndef TC956X_SRIOV_VF if (avb_priority == TC956X_AVB_PRIORITY_CLASS_A) txqueue_select = AVB_CLASS_A_TX_CH; else if (avb_priority == TC956X_AVB_PRIORITY_CLASS_B) @@ -11265,10 +13646,25 @@ static u16 tc956xmac_select_queue(struct net_device *dev, struct sk_buff *skb, txqueue_select = TSN_CLASS_CDT_TX_CH; else txqueue_select = HOST_BEST_EFF_CH; +#elif (defined TC956X_SRIOV_VF) + if (avb_priority == TC956X_AVB_PRIORITY_CLASS_A) + txqueue_select = priv->plat->avb_class_a_ch_no; + else if (avb_priority == TC956X_AVB_PRIORITY_CLASS_B) + txqueue_select = priv->plat->avb_class_b_ch_no; + else if (avb_priority == TC956X_PRIORITY_CLASS_CDT) + txqueue_select = priv->plat->tsn_ch_no; + else + txqueue_select = priv->plat->best_effort_ch_no; +#endif } else { +#ifndef TC956X_SRIOV_VF txqueue_select = LEGACY_VLAN_TAGGED_CH; +#elif (defined TC956X_SRIOV_VF) + txqueue_select = priv->plat->best_effort_ch_no; +#endif } } else { +#ifndef TC956X_SRIOV_VF switch (eth_or_vlan_tag) { case ETH_P_1588: txqueue_select = TC956X_GPTP_TX_CH; @@ -11277,6 +13673,16 @@ static u16 tc956xmac_select_queue(struct net_device *dev, struct sk_buff *skb, txqueue_select = HOST_BEST_EFF_CH; break; } +#elif (defined TC956X_SRIOV_VF) + switch (eth_or_vlan_tag) { + case ETH_P_1588: + txqueue_select = priv->plat->gptp_ch_no; + break; + default: + txqueue_select = priv->plat->best_effort_ch_no; + break; + } +#endif } netdev_dbg(priv->dev, "%s: Tx Queue select = %d", __func__, txqueue_select); return txqueue_select; @@ -11301,12 +13707,28 @@ static int tc956xmac_set_mac_address(struct net_device *ndev, void *addr) { struct tc956xmac_priv *priv = netdev_priv(ndev); int ret = 0; +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + unsigned long flags; +#endif ret = eth_mac_addr(ndev, addr); if (ret) return ret; - tc956xmac_set_umac_addr(priv, priv->hw, ndev->dev_addr, HOST_MAC_ADDR_OFFSET, PF_DRIVER); +#ifdef TC956X_SRIOV_VF + tc956xmac_set_umac_addr(priv, ndev->dev_addr, HOST_MAC_ADDR_OFFSET + priv->fn_id_info.vf_no); +#else +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_lock_irqsave(&priv->spn_lock.mac_filter, flags); +#endif + + tc956xmac_set_umac_addr(priv, priv->hw, (unsigned char *)ndev->dev_addr, HOST_MAC_ADDR_OFFSET, PF_DRIVER); + +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_unlock_irqrestore(&priv->spn_lock.mac_filter, flags); +#endif + +#endif return ret; } @@ -11503,7 +13925,11 @@ static int tc956xmac_device_event(struct notifier_block *unused, struct net_device *dev = netdev_notifier_info_to_dev(ptr); struct tc956xmac_priv *priv = netdev_priv(dev); +#ifndef TC956X_SRIOV_VF if (dev->netdev_ops != &tc956xmac_netdev_ops) +#else + if (dev->netdev_ops != &tc956xmac_vf_netdev_ops) +#endif goto done; switch (event) { @@ -11583,28 +14009,58 @@ static int tc956xmac_vlan_rx_add_vid(struct net_device *ndev, __be16 proto, u16 vid) { struct tc956xmac_priv *priv = netdev_priv(ndev); +#ifndef TC956X_SRIOV_VF bool is_double = false; int ret = 0; - +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + unsigned long flags; +#endif if (be16_to_cpu(proto) == ETH_P_8021AD) is_double = true; +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_lock_irqsave(&priv->spn_lock.vlan_filter, flags); +#endif + tc956xmac_update_vlan_hash(priv, ndev, is_double, vid, PF_DRIVER); +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_unlock_irqrestore(&priv->spn_lock.vlan_filter, flags); +#endif return ret; +#elif (defined TC956X_SRIOV_VF) + tc956xmac_add_vlan(priv, vid); + return 0; +#endif } static int tc956xmac_vlan_rx_kill_vid(struct net_device *ndev, __be16 proto, u16 vid) { struct tc956xmac_priv *priv = netdev_priv(ndev); +#ifndef TC956X_SRIOV_VF int ret = 0; +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + unsigned long flags; + spin_lock_irqsave(&priv->spn_lock.vlan_filter, flags); +#endif tc956xmac_delete_vlan(priv, ndev, vid, PF_DRIVER); +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_unlock_irqrestore(&priv->spn_lock.vlan_filter, flags); +#endif return ret; +#elif (defined TC956X_SRIOV_VF) + tc956xmac_delete_vlan(priv, vid); + return 0; +#endif } +#ifndef TC956X_SRIOV_VF static const struct net_device_ops tc956xmac_netdev_ops = { +#elif defined TC956X_SRIOV_VF +static const struct net_device_ops tc956xmac_vf_netdev_ops = { +#endif .ndo_open = tc956xmac_open, .ndo_start_xmit = tc956xmac_xmit, .ndo_stop = tc956xmac_release, @@ -11613,7 +14069,12 @@ static const struct net_device_ops tc956xmac_netdev_ops = { .ndo_set_features = tc956xmac_set_features, .ndo_set_rx_mode = tc956xmac_set_rx_mode, .ndo_tx_timeout = tc956xmac_tx_timeout, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)) + .ndo_eth_ioctl = tc956xmac_ioctl, + .ndo_siocdevprivate = tc956xmac_siocdevprivate, +#else .ndo_do_ioctl = tc956xmac_ioctl, +#endif .ndo_setup_tc = tc956xmac_setup_tc, .ndo_select_queue = tc956xmac_select_queue, #ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE @@ -11658,6 +14119,115 @@ static void tc956xmac_service_task(struct work_struct *work) clear_bit(TC956XMAC_SERVICE_SCHED, &priv->state); } #endif +#if defined(TC956X_SRIOV_PF) && !defined(TC956X_AUTOMOTIVE_CONFIG) && !defined(TC956X_ENABLE_MAC2MAC_BRIDGE) +/** + * tc956xmac_service_mbx_task - Service mailbox task + * @work: work structure + */ +static void tc956xmac_service_mbx_task(struct work_struct *work) +{ + struct tc956xmac_priv *priv = container_of(work, struct tc956xmac_priv, + service_mbx_task); + u32 dma_ch = 0; + u8 vf; + int ret = -EBUSY; + struct mii_ioctl_data *mii_ptr; + + if (priv->mbx_wq_param.fn_id == SCH_WQ_PHY_REG_RD) { + mii_ptr = if_mii(&priv->mbx_wq_param.rq); + rtnl_lock(); + ret = phylink_mii_ioctl(priv->phylink, &priv->mbx_wq_param.rq, SIOCGMIIREG); + rtnl_unlock(); + priv->mbx_wq_param.val_out[priv->mbx_wq_param.vf_no] = mii_ptr->val_out; + priv->mbx_wq_param.fn_id = 0; + } else if (priv->mbx_wq_param.fn_id == SCH_WQ_RX_DMA_ERR) { + for (vf = 0; vf < MAX_NO_OF_VFS; vf++) { + while (ret == -EBUSY) + ret = tc956x_mbx_wrap_rx_dma_err(priv, vf); + + if (ret == -1) { + priv->clear_to_send[vf] = VF_DOWN; + for (dma_ch = 0; dma_ch < TC956XMAC_CH_MAX; dma_ch++) { + if (priv->dma_vf_map[dma_ch] == vf) + tc956xmac_stop_rx_dma(priv, dma_ch); + } + } + ret = -EBUSY; //to continue with next vf + } + /* Invoke device driver close */ + if (netif_running(priv->dev)) { + rtnl_lock(); + dev_close(priv->dev); + rtnl_unlock(); + } + /* Invoke device driver open */ + if (!netif_running(priv->dev)) { + rtnl_lock(); + dev_open(priv->dev, NULL); + rtnl_unlock(); + } + priv->mbx_wq_param.fn_id = 0; + } else if (priv->mbx_wq_param.fn_id == SCH_WQ_GET_PAUSE_PARAM) { + rtnl_lock(); + tc956xmac_get_pauseparam(priv->dev, &priv->mbx_wq_param.pause); + rtnl_unlock(); + priv->mbx_wq_param.fn_id = 0; + } else { + if (priv->mbx_wq_param.queue_no == 0 || priv->mbx_wq_param.queue_no == 1 || priv->mbx_wq_param.queue_no == 7) { + for (dma_ch = 0; dma_ch < 3; dma_ch++) { + vf = priv->dma_vf_map[dma_ch]; + while (ret == -EBUSY) + ret = tc956x_mbx_wrap_rx_dma_ch_tlptr(priv, dma_ch, vf); + ret = -EBUSY; //to continue with next vf + } + } else { + dma_ch = priv->plat->rx_queues_cfg[priv->mbx_wq_param.queue_no].chan; + vf = priv->dma_vf_map[dma_ch]; + while (ret == -EBUSY) + ret = tc956x_mbx_wrap_rx_dma_ch_tlptr(priv, dma_ch, vf); + } + } + clear_bit(TC956XMAC_SERVICE_SCHED, &priv->state); +} +#endif + +#ifdef TC956X_SRIOV_VF +static void tc956xmac_mailbox_service_task(struct work_struct *work) +{ + struct tc956xmac_priv *priv = container_of(work, struct tc956xmac_priv, mbx_service_task); + struct pci_dev *pdev = to_pci_dev(priv->device); + + if (priv->flag == SCH_WQ_PF_FLR) { + pci_reset_function(pdev); + priv->flag = 0; + } else if (priv->flag == SCH_WQ_RX_DMA_ERR) { + tc956xmac_stop_all_dma(priv); + priv->flag = 0; + } else if (priv->flag == SCH_WQ_LINK_STATE_UP) { + int ret = 0; + + ret = init_dma_desc_rings(priv->dev, GFP_KERNEL); + if (ret < 0) { + netdev_err(priv->dev, "%s: DMA descriptors initialization failed\n", + __func__); + } + + ret = tc956xmac_hw_setup(priv->dev, true); + if (ret < 0) + netdev_err(priv->dev, "%s: Hw setup failed\n", __func__); + priv->flag = 0; + } else { + /* Indicate change of features required, which invokes ndo_fix_features + * where dev->features are updated. + */ + rtnl_lock(); + netdev_change_features(priv->dev); + rtnl_unlock(); + } + + clear_bit(TC956XMAC_SERVICE_SCHED, &priv->state); +} +#endif /** * tc956xmac_hw_init - Init the MAC device @@ -11844,11 +14414,13 @@ static bool isMAC(char *s) * * \return None */ -static void extract_macid(char *string) +static void extract_macid(char *string, uint8_t vf_id) { char *token_m = NULL; int j = 0; int mac_id = 0; + +#ifdef TC956X_SRIOV_PF static int addr_found; /* Extract MAC ID byte by byte */ @@ -11856,13 +14428,33 @@ static void extract_macid(char *string) while (token_m != NULL) { sscanf(token_m, "%x", &mac_id); - if (addr_found < 2) { + if (addr_found < TC956X_MAC_ADDR_CNT) { dev_addr[addr_found][j++] = mac_id; token_m = strsep(&string, ":"); } else break; } KPRINT_DEBUG1("MAC Addr : %pM\n", &dev_addr[addr_found][0]); +#elif defined TC956X_SRIOV_VF + static int k; + int addr_found = 0; + + /* Extract MAC ID byte by byte */ + token_m = strsep(&string, ":"); + + while (token_m != NULL) { + sscanf(token_m, "%x", &mac_id); + + if (addr_found < 2) { + dev_addr[k][addr_found + vf_id][j++] = mac_id; + token_m = strsep(&string, ":"); + } else + break; + } + KPRINT_INFO("MAC Addr : %pM\n", &dev_addr[k][addr_found + vf_id][0]); + + k++; +#endif addr_found++; } @@ -11875,9 +14467,10 @@ static void extract_macid(char *string) * * \return - True on Success and False in failure */ -static bool lookfor_macid(char *file_buf) +static bool lookfor_macid(char *file_buf, uint8_t port_id, uint8_t dev_id) { char *string = NULL, *token_n = NULL, *token_s = NULL, *token_m = NULL; + char *dev_no = NULL, *port_no = NULL; bool status = false; int tc956x_device_no = 0; int total_valid_addr = 0; @@ -11887,7 +14480,6 @@ static bool lookfor_macid(char *file_buf) /* Parse Line-0 */ token_n = strsep(&string, "\n"); while (token_n != NULL) { - /* Check if line is enabled */ if (token_n[0] != '#') { /* Extract the token based space character */ @@ -11896,10 +14488,20 @@ static bool lookfor_macid(char *file_buf) if (strncmp(token_s, config_param_list[0] .mdio_key, 9) == 0) { token_s = strsep(&token_n, " "); + dev_no = &token_n[6]; + port_no = &token_n[7]; token_m = strsep(&token_s, ":"); sscanf(token_m, "%d", &tc956x_device_no); - if (tc956x_device_no != mdio_bus_id) { +#ifdef TC956X_SRIOV_VF + if (((tc956x_device_no != mdio_bus_id) && + (*port_no != (char)(port_id + 49))) || + (*dev_no != (char)(dev_id + 49))) { +#else + if (((tc956x_device_no != mdio_bus_id) && + (*port_no != (char)(port_id + 49))) || + (*dev_no != (char)(dev_id + 48))) { +#endif token_n = strsep(&string, "\n"); if (token_n == NULL) break; @@ -11933,7 +14535,7 @@ static bool lookfor_macid(char *file_buf) * MAC ID is valid, * assign default MAC ID */ - extract_macid(token_s); + extract_macid(token_s, dev_id); total_valid_addr++; if (total_valid_addr @@ -11954,7 +14556,6 @@ static bool lookfor_macid(char *file_buf) break; } - return status; } @@ -11966,15 +14567,17 @@ static bool lookfor_macid(char *file_buf) * \return None * */ -static void parse_config_file(void) +static void parse_config_file(uint8_t port_id, uint8_t dev_id) { - void *data; + void *data = NULL; char *cdata; int ret, i; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) + ret = kernel_read_file_from_path("config.ini", 0, &data, INT_MAX, NULL, READING_POLICY); +#else loff_t size; - ret = kernel_read_file_from_path("config.ini", &data, &size, 1000, READING_POLICY); - +#endif if (ret < 0) { KPRINT_ERR("Mac configuration file not found\n"); KPRINT_INFO("Using Default MAC Address\n"); @@ -11989,7 +14592,7 @@ static void parse_config_file(void) if (strncmp(config_param_list[i].mdio_key, "MDIOBUSID", 9) == 0) { /* MAC ID Configuration */ KPRINT_DEBUG1("MAC_ID Configuration\n"); - lookfor_macid(data); + lookfor_macid(data, port_id, dev_id); } } } @@ -11998,8 +14601,30 @@ static void parse_config_file(void) vfree(data); KPRINT_INFO("<--%s", __func__); } +#endif +#ifdef TC956X_SRIOV_VF +static int validate_rsc_mgr_alloc(struct tc956xmac_priv *priv, struct net_device *ndev) +{ + u8 rsc, i; + u8 ch_cnt = priv->plat->tx_queues_to_use; + u8 ret = 0; + + /* Validate Resource allocation for VF */ + + tc956xmac_rsc_mng_get_rscs(priv, ndev, &rsc); + + dev_info(priv->device, "VF %d Resource allocation %x\n", priv->plat->vf_id+1, rsc); + + for (i = 0; i < ch_cnt; i++) { + if (priv->plat->ch_in_use[i]) + if (!((rsc >> i) & TC956X_DMA_CH0_MASK)) + ret = -1; + } + + return ret; +} #endif /** @@ -12012,7 +14637,11 @@ static void parse_config_file(void) * Return: * returns 0 on success, otherwise errno. */ +#ifdef TC956X_SRIOV_PF int tc956xmac_dvr_probe(struct device *device, +#elif defined TC956X_SRIOV_VF +int tc956xmac_vf_dvr_probe(struct device *device, +#endif struct plat_tc956xmacenet_data *plat_dat, struct tc956xmac_resources *res) { @@ -12080,6 +14709,9 @@ int tc956xmac_dvr_probe(struct device *device, tc956xmac_set_ethtool_ops(ndev); priv->pause = pause; priv->plat = plat_dat; +#ifdef TC956X_SRIOV_PF + priv->sriov_enabled = res->sriov_enabled; +#endif #ifdef TC956X priv->tc956x_SFR_pci_base_addr = res->tc956x_SFR_pci_base_addr; priv->tc956x_SRAM_pci_base_addr = res->tc956x_SRAM_pci_base_addr; @@ -12091,21 +14723,145 @@ int tc956xmac_dvr_probe(struct device *device, priv->is_sgmii_2p5g = true; else priv->is_sgmii_2p5g = false; +#ifdef TC956X_SRIOV_PF +#ifdef TC956X_MAGIC_PACKET_WOL_CONF + priv->wol_config_enabled = false; /* Disable WOL SGMII 1G, configuration by default */ +#endif /* #ifdef TC956X_MAGIC_PACKET_WOL_CONF */ +#endif priv->dev->irq = res->irq; priv->wol_irq = res->wol_irq; priv->lpi_irq = res->lpi_irq; priv->port_interface = res->port_interface; priv->eee_enabled = res->eee_enabled; priv->tx_lpi_timer = res->tx_lpi_timer; + +#ifdef TC956X_SRIOV_PF priv->pm_saved_linkdown_rst = 0; priv->pm_saved_linkdown_clk = 0; priv->port_link_down = false; priv->port_release = false; -#ifdef DMA_OFFLOAD_ENABLE + + + /* DMA Ch allocation for PF & VF */ + priv->rsc_dma_ch_alloc[0] = TC956X_PF_CH_ALLOC; + priv->rsc_dma_ch_alloc[1] = TC956X_VF0_CH_ALLOC; + priv->rsc_dma_ch_alloc[2] = TC956X_VF1_CH_ALLOC; + priv->rsc_dma_ch_alloc[3] = TC956X_VF2_CH_ALLOC; + +#if !defined(TC956X_AUTOMOTIVE_CONFIG) && !defined(TC956X_ENABLE_MAC2MAC_BRIDGE) + /* SRIOV PF 0/1 Queue configuration + * Note: + * 1. Channels used in PF/VF configurations are enabled + * in respective drivers. + * 2. Rx Queues are configured in PF only. + * 3. Tx Queues are configured in respective devices. In case of + * VF, the Queue configuraion happens via mailbox. + * 4. Traffic class configuraions are done in respective drivers except for TC0. + * TC0 is configured in PF only as its common for Tx 0,1,2,3 + * as per current design. + */ + + /* Tx & Rx Channel Configuration */ + priv->plat->tx_ch_in_use[0] = TC956X_DISABLE_CHNL; + priv->plat->tx_ch_in_use[1] = TC956X_DISABLE_CHNL; + priv->plat->tx_ch_in_use[2] = TC956X_DISABLE_CHNL; + priv->plat->tx_ch_in_use[3] = TC956X_ENABLE_CHNL; + priv->plat->tx_ch_in_use[4] = TC956X_ENABLE_CHNL; + priv->plat->tx_ch_in_use[5] = TC956X_DISABLE_CHNL; + priv->plat->tx_ch_in_use[6] = TC956X_DISABLE_CHNL; + priv->plat->tx_ch_in_use[7] = TC956X_DISABLE_CHNL; + + priv->plat->rx_ch_in_use[0] = TC956X_DISABLE_CHNL; + priv->plat->rx_ch_in_use[1] = TC956X_DISABLE_CHNL; + priv->plat->rx_ch_in_use[2] = TC956X_DISABLE_CHNL; + priv->plat->rx_ch_in_use[3] = TC956X_ENABLE_CHNL; + priv->plat->rx_ch_in_use[4] = TC956X_ENABLE_CHNL; + priv->plat->rx_ch_in_use[5] = TC956X_DISABLE_CHNL; + priv->plat->rx_ch_in_use[6] = TC956X_DISABLE_CHNL; + priv->plat->rx_ch_in_use[7] = TC956X_DISABLE_CHNL; + + /* Tx & Rx Queue Configuration */ + priv->plat->tx_q_in_use[0] = TC956X_DISABLE_QUEUE; + priv->plat->tx_q_in_use[1] = TC956X_DISABLE_QUEUE; + priv->plat->tx_q_in_use[2] = TC956X_DISABLE_QUEUE; + priv->plat->tx_q_in_use[3] = TC956X_ENABLE_QUEUE; + priv->plat->tx_q_in_use[4] = TC956X_ENABLE_QUEUE; + priv->plat->tx_q_in_use[5] = TC956X_DISABLE_QUEUE; + priv->plat->tx_q_in_use[6] = TC956X_DISABLE_QUEUE; + priv->plat->tx_q_in_use[7] = TC956X_DISABLE_QUEUE; + + priv->plat->rx_q_in_use[0] = TC956X_ENABLE_QUEUE; + priv->plat->rx_q_in_use[1] = TC956X_ENABLE_QUEUE; + priv->plat->rx_q_in_use[2] = TC956X_ENABLE_QUEUE; + priv->plat->rx_q_in_use[3] = TC956X_ENABLE_QUEUE; + priv->plat->rx_q_in_use[4] = TC956X_ENABLE_QUEUE; + priv->plat->rx_q_in_use[5] = TC956X_ENABLE_QUEUE; + priv->plat->rx_q_in_use[6] = TC956X_ENABLE_QUEUE; + priv->plat->rx_q_in_use[7] = TC956X_ENABLE_QUEUE; +#else + /* Tx & Rx Channel Configuration */ + priv->plat->tx_ch_in_use[0] = TC956X_ENABLE_CHNL; + priv->plat->tx_ch_in_use[1] = TC956X_DISABLE_CHNL; + priv->plat->tx_ch_in_use[2] = TC956X_DISABLE_CHNL; + priv->plat->tx_ch_in_use[3] = TC956X_DISABLE_CHNL; + priv->plat->tx_ch_in_use[4] = TC956X_ENABLE_CHNL; + priv->plat->tx_ch_in_use[5] = TC956X_ENABLE_CHNL; + priv->plat->tx_ch_in_use[6] = TC956X_ENABLE_CHNL; + priv->plat->tx_ch_in_use[7] = TC956X_ENABLE_CHNL; + + priv->plat->rx_ch_in_use[0] = TC956X_ENABLE_CHNL; + priv->plat->rx_ch_in_use[1] = TC956X_DISABLE_CHNL; + priv->plat->rx_ch_in_use[2] = TC956X_DISABLE_CHNL; + priv->plat->rx_ch_in_use[3] = TC956X_ENABLE_CHNL; + priv->plat->rx_ch_in_use[4] = TC956X_ENABLE_CHNL; + priv->plat->rx_ch_in_use[5] = TC956X_ENABLE_CHNL; + priv->plat->rx_ch_in_use[6] = TC956X_ENABLE_CHNL; + priv->plat->rx_ch_in_use[7] = TC956X_ENABLE_CHNL; + + /* Tx & Rx Queue Configuration */ + priv->plat->tx_q_in_use[0] = TC956X_ENABLE_QUEUE; +#ifdef TC956X_DMA_OFFLOAD_ENABLE + priv->plat->tx_q_in_use[1] = TC956X_ENABLE_QUEUE; +#else + priv->plat->tx_q_in_use[1] = TC956X_DISABLE_QUEUE; +#endif +#if defined(TC956X_ENABLE_MAC2MAC_BRIDGE) + priv->plat->tx_q_in_use[2] = TC956X_ENABLE_QUEUE; +#else + priv->plat->tx_q_in_use[2] = TC956X_DISABLE_QUEUE; +#endif + priv->plat->tx_q_in_use[3] = TC956X_DISABLE_QUEUE; + priv->plat->tx_q_in_use[4] = TC956X_ENABLE_QUEUE; + priv->plat->tx_q_in_use[5] = TC956X_ENABLE_QUEUE; + priv->plat->tx_q_in_use[6] = TC956X_ENABLE_QUEUE; + priv->plat->tx_q_in_use[7] = TC956X_ENABLE_QUEUE; + + priv->plat->rx_q_in_use[0] = TC956X_ENABLE_QUEUE; + priv->plat->rx_q_in_use[1] = TC956X_ENABLE_QUEUE; + priv->plat->rx_q_in_use[2] = TC956X_ENABLE_QUEUE; + priv->plat->rx_q_in_use[3] = TC956X_ENABLE_QUEUE; + priv->plat->rx_q_in_use[4] = TC956X_ENABLE_QUEUE; + priv->plat->rx_q_in_use[5] = TC956X_ENABLE_QUEUE; + priv->plat->rx_q_in_use[6] = TC956X_ENABLE_QUEUE; + priv->plat->rx_q_in_use[7] = TC956X_ENABLE_QUEUE; +#endif /* TC956X_AUTOMOTIVE_CONFIG */ +#endif /* TC956X_SRIOV_PF */ + +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + dev_info(priv->device, "Locks enabled for shared resources\n"); + spin_lock_init(&priv->spn_lock.mac_filter); + spin_lock_init(&priv->spn_lock.vlan_filter); + spin_lock_init(&priv->spn_lock.est); + spin_lock_init(&priv->spn_lock.fpe); + spin_lock_init(&priv->spn_lock.frp); + spin_lock_init(&priv->spn_lock.cbs); +#endif +#ifndef TC956X_SRIOV_PF +#ifdef TC956X_DMA_OFFLOAD_ENABLE priv->client_priv = NULL; memset(priv->cm3_tamap, 0, sizeof(struct tc956xmac_cm3_tamap) * MAX_CM3_TAMAP_ENTRIES); #endif - +#endif #ifdef TC956X /* Read mac address from config.ini file */ ++mdio_bus_id; @@ -12113,39 +14869,83 @@ int tc956xmac_dvr_probe(struct device *device, #ifdef EEPROM_MAC_ADDR #ifdef TC956X +#ifdef TC956X_SRIOV_VF + mac_addr = readl(priv->tc956x_SRAM_pci_base_addr + - TC956X_M3_SRAM_EEPROM_MAC_ADDR + (priv->port_num * 8)); + TC956X_M3_SRAM_EEPROM_MAC_ADDR + (EEPROM_PORT_OFFSET * TC956X_EIGHT) + + (priv->plat->vf_id * TC956X_SIXTEEN)); if (mac_addr != 0) { - dev_addr[priv->port_num][0] = (mac_addr & 0x000000FF); - dev_addr[priv->port_num][1] = (mac_addr & 0x0000FF00) >> 8; - dev_addr[priv->port_num][2] = (mac_addr & 0x00FF0000) >> 16; - dev_addr[priv->port_num][3] = (mac_addr & 0xFF000000) >> 24; + + dev_addr[priv->port_num][priv->plat->vf_id][0] = (mac_addr & EEPROM_MAC_ADDR_MASK1); + dev_addr[priv->port_num][priv->plat->vf_id][1] = + (mac_addr & EEPROM_MAC_ADDR_MASK2) >> TC956X_EIGHT; + dev_addr[priv->port_num][priv->plat->vf_id][2] = + (mac_addr & EEPROM_MAC_ADDR_MASK3) >> TC956X_SIXTEEN; + dev_addr[priv->port_num][priv->plat->vf_id][3] = + (mac_addr & EEPROM_MAC_ADDR_MASK4) >> TC956X_TWENTY_FOUR; mac_addr = readl(priv->tc956x_SRAM_pci_base_addr + - TC956X_M3_SRAM_EEPROM_MAC_ADDR + 0x4 + (priv->port_num * 8)); - dev_addr[priv->port_num][4] = (mac_addr & 0x000000FF); - dev_addr[priv->port_num][5] = (mac_addr & 0x0000FF00) >> 8; + TC956X_M3_SRAM_EEPROM_MAC_ADDR + (EEPROM_PORT_OFFSET * TC956X_EIGHT) + + (priv->plat->vf_id * TC956X_SIXTEEN) + TC956X_FOUR); + + dev_addr[priv->port_num][priv->plat->vf_id][4] = (mac_addr & EEPROM_MAC_ADDR_MASK1); + dev_addr[priv->port_num][priv->plat->vf_id][5] = + (mac_addr & EEPROM_MAC_ADDR_MASK2) >> TC956X_EIGHT; } -#endif #else + mac_addr = readl(priv->tc956x_SRAM_pci_base_addr + + TC956X_M3_SRAM_EEPROM_MAC_ADDR + (priv->port_num * TC956X_EIGHT)); + + if (mac_addr != 0) { + dev_addr[priv->port_num][0] = (mac_addr & EEPROM_MAC_ADDR_MASK1); + dev_addr[priv->port_num][1] = (mac_addr & EEPROM_MAC_ADDR_MASK2) >> TC956X_EIGHT; + dev_addr[priv->port_num][2] = (mac_addr & EEPROM_MAC_ADDR_MASK3) >> TC956X_SIXTEEN; + dev_addr[priv->port_num][3] = (mac_addr & EEPROM_MAC_ADDR_MASK4) >> TC956X_TWENTY_FOUR; + + mac_addr = readl(priv->tc956x_SRAM_pci_base_addr + + TC956X_M3_SRAM_EEPROM_MAC_ADDR + TC956X_FOUR + (priv->port_num * TC956X_EIGHT)); + dev_addr[priv->port_num][4] = (mac_addr & EEPROM_MAC_ADDR_MASK1); + dev_addr[priv->port_num][5] = (mac_addr & EEPROM_MAC_ADDR_MASK2) >> TC956X_EIGHT; + } +#endif /* TC956X_SRIOV_VF */ +#endif /* TC956X */ + +#else +#ifdef TC956X_SRIOV_VF /* To be enabled for config.ini parsing */ - parse_config_file(); + parse_config_file(priv->port_num, priv->plat->vf_id); +#else + /* To be enabled for config.ini parsing */ + parse_config_file(priv->port_num, 0); +#endif #endif /* EEPROM_MAC_ADDR */ - - res->mac = &dev_addr[priv->port_num][0]; +#ifndef TC956X_SRIOV_VF + res->mac = &dev_addr[tc956xmac_pm_usage_counter][0]; NMSGPR_INFO(device, "MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n", - dev_addr[priv->port_num][0], dev_addr[priv->port_num][1], - dev_addr[priv->port_num][2], dev_addr[priv->port_num][3], - dev_addr[priv->port_num][4], dev_addr[priv->port_num][5]); + dev_addr[tc956xmac_pm_usage_counter][0], dev_addr[tc956xmac_pm_usage_counter][1], + dev_addr[tc956xmac_pm_usage_counter][2], dev_addr[tc956xmac_pm_usage_counter][3], + dev_addr[tc956xmac_pm_usage_counter][4], dev_addr[tc956xmac_pm_usage_counter][5]); + +#elif (defined TC956X_SRIOV_VF) + + res->mac = &dev_addr[priv->port_num][priv->plat->vf_id][0]; + NMSGPR_INFO(device, "MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n", + dev_addr[priv->port_num][priv->plat->vf_id][0], dev_addr[priv->port_num][priv->plat->vf_id][1], + dev_addr[priv->port_num][priv->plat->vf_id][2], dev_addr[priv->port_num][priv->plat->vf_id][3], + dev_addr[priv->port_num][priv->plat->vf_id][4], dev_addr[priv->port_num][priv->plat->vf_id][5]); +#endif #endif if (!IS_ERR_OR_NULL(res->mac)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 13, 0)) + eth_hw_addr_set(priv->dev, res->mac); +#else memcpy(priv->dev->dev_addr, res->mac, ETH_ALEN); - +#endif dev_set_drvdata(device, priv->dev); /* Verify driver arguments */ @@ -12162,6 +14962,26 @@ int tc956xmac_dvr_probe(struct device *device, INIT_WORK(&priv->service_task, tc956xmac_service_task); #endif +#if defined(TC956X_SRIOV_PF) && !defined(TC956X_AUTOMOTIVE_CONFIG) && !defined(TC956X_ENABLE_MAC2MAC_BRIDGE) + /* Allocate workqueue */ + priv->mbx_wq = create_singlethread_workqueue("tc956xmac_mbx_wq"); + if (!priv->mbx_wq) { + dev_err(priv->device, "failed to create workqueue\n"); + return -ENOMEM; + } + + INIT_WORK(&priv->service_mbx_task, tc956xmac_service_mbx_task); +#endif +#ifdef TC956X_SRIOV_VF + /* Allocate workqueue */ + priv->mbx_wq = create_singlethread_workqueue("tc956xmac_mailbox_wq"); + if (!priv->mbx_wq) { + dev_err(priv->device, "failed to create workqueue\n"); + return -ENOMEM; + } + + INIT_WORK(&priv->mbx_service_task, tc956xmac_mailbox_service_task); +#endif /* Override with kernel parameters if supplied XXX CRS XXX * this needs to have multiple instances */ @@ -12182,17 +15002,33 @@ int tc956xmac_dvr_probe(struct device *device, ret = tc956xmac_hw_init(priv); if (ret) goto error_hw_init; +#ifdef TC956X_SRIOV_VF + ret = validate_rsc_mgr_alloc(priv, ndev); + + if (ret) { + dev_err(priv->device, "VF %d Channel Resource allocation mismatch\n", priv->plat->vf_id + 1); + goto error_hw_init; + } tc956xmac_check_ether_addr(priv); - +#endif /* Configure real RX and TX queues */ +#ifndef TC956X_SRIOV_VF netif_set_real_num_rx_queues(ndev, priv->plat->rx_queues_to_use); netif_set_real_num_tx_queues(ndev, priv->plat->tx_queues_to_use); - ndev->netdev_ops = &tc956xmac_netdev_ops; +#elif (defined TC956X_SRIOV_VF) + netif_set_real_num_rx_queues(ndev, priv->plat->rx_queues_to_use_actual); + netif_set_real_num_tx_queues(ndev, priv->plat->tx_queues_to_use_actual); + ndev->netdev_ops = &tc956xmac_vf_netdev_ops; +#endif +#ifdef TC956X_SRIOV_VF + ndev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; +#else //CPE_DRV ndev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM; +#endif ret = tc956xmac_tc_init(priv, NULL); if (!ret) @@ -12200,19 +15036,34 @@ int tc956xmac_dvr_probe(struct device *device, /* Enable TSO module if any Queue TSO is Enabled */ for (queue = 0; queue < MTL_MAX_TX_QUEUES; queue++) { +#ifdef TC956X_SRIOV_VF + if (priv->plat->tx_queues_cfg[0].tso_en == TC956X_ENABLE && + priv->tso) +#else if (priv->plat->tx_queues_cfg[0].tso_en == TC956X_ENABLE) +#endif priv->plat->tso_en = 1; } +#ifndef TC956X_SRIOV_VF if ((priv->plat->tso_en) && (priv->dma_cap.tsoen)) { ndev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6; if (priv->plat->has_gmac4) ndev->hw_features |= NETIF_F_GSO_UDP_L4; priv->tso = true; + /* Update driver cap to let VF know about feature + * enable/disable + */ + priv->pf_drv_cap.tso_en = true; dev_info(priv->device, "TSO feature enabled\n"); } else { priv->tso = false; + /* Update driver cap to let VF know about feature + * enable/disable + */ + priv->pf_drv_cap.tso_en = false; } +#endif if (priv->dma_cap.sphen && priv->plat->sph_en) { ndev->hw_features |= NETIF_F_GRO; @@ -12226,7 +15077,6 @@ int tc956xmac_dvr_probe(struct device *device, if (!ret) { dev_info(priv->device, "Using %d bits DMA width\n", priv->dma_cap.addr64); - } else { ret = dma_set_mask_and_coherent(device, DMA_BIT_MASK(32)); @@ -12246,22 +15096,65 @@ int tc956xmac_dvr_probe(struct device *device, priv->plat->dma_cfg->eame = true; ndev->features |= ndev->hw_features | NETIF_F_HIGHDMA; +#ifdef TC956X_SRIOV_VF + /* Get the VF function id information */ + if (tc956xmac_rsc_mng_get_fn_id(priv, priv->tc956x_BRIDGE_CFG_pci_base_addr, + &priv->fn_id_info)) { + netdev_err(priv->dev, + "%s: Wrong function id for the driver (error: %d)\n", + __func__, -ENODEV); + return -ENODEV; + } + + tc956xmac_mbx_init(priv, NULL); + + /* Get PF driver capabilities */ + tc956x_get_drv_cap(priv, priv); + KPRINT_DEBUG1("priv->pf_drv_cap.jumbo_en = %d\n", priv->pf_drv_cap.jumbo_en); + + /* These features will be modified based on PF configuration and mailbox + * request from PF */ + if (priv->pf_drv_cap.csum_en) { + ndev->features |= NETIF_F_RXCSUM; + ndev->hw_features |= NETIF_F_RXCSUM; + } + + if (priv->pf_drv_cap.crc_en) { + ndev->features |= NETIF_F_RXFCS; + ndev->hw_features |= NETIF_F_RXFCS; + } + + if (priv->pf_drv_cap.tso_en) { + if ((priv->plat->tso_en) && (priv->dma_cap.tsoen)) { + ndev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6; + ndev->features |= NETIF_F_TSO | NETIF_F_TSO6; + if (priv->plat->has_gmac4) { + ndev->hw_features |= NETIF_F_GSO_UDP_L4; + ndev->features |= NETIF_F_GSO_UDP_L4; + } + priv->tso = true; + dev_info(priv->device, "TSO feature enabled\n"); + } else { + priv->tso = false; + } + } +#else /* Ethtool rx-fcs state is Off by default */ ndev->hw_features |= NETIF_F_RXFCS; - +#endif ndev->watchdog_timeo = msecs_to_jiffies(watchdog); #ifdef TC956XMAC_VLAN_TAG_USED /* Both mac100 and gmac support receive VLAN tag detection */ /* Driver only supports CTAG */ - ndev->features &= ~NETIF_F_HW_VLAN_CTAG_RX; /* Disable rx-vlan-filter by default */ + ndev->features &= ~NETIF_F_HW_VLAN_CTAG_RX; /* Disable rx-vlan-offload by default */ ndev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX; /* Support as User-changeable features */ #ifndef TC956X ndev->features |= NETIF_F_HW_VLAN_STAG_RX; #endif if (priv->dma_cap.vlhash) { /* Driver only supports CTAG */ - ndev->features &= ~NETIF_F_HW_VLAN_CTAG_FILTER; /* Disable rx-vlan-offload by default */ + ndev->features &= ~NETIF_F_HW_VLAN_CTAG_FILTER; /* Disable rx-vlan-filter by default */ ndev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER; /* Support as User-changeable features */ #ifndef TC956X ndev->features |= NETIF_F_HW_VLAN_STAG_FILTER; @@ -12303,12 +15196,20 @@ int tc956xmac_dvr_probe(struct device *device, /* MTU range: 46 - hw-specific max */ ndev->min_mtu = ETH_ZLEN - ETH_HLEN; +#ifdef TC956X_SRIOV_VF + /* Set MTU size based on Jumbo Frame feature enable */ + if (priv->pf_drv_cap.jumbo_en) { +#endif if (priv->plat->has_xgmac) - ndev->max_mtu = MAX_SUPPORTED_MTU/*XGMAC_JUMBO_LEN*/; + ndev->max_mtu = XGMAC_JUMBO_LEN; else if ((priv->plat->enh_desc) || (priv->synopsys_id >= DWMAC_CORE_4_00)) ndev->max_mtu = JUMBO_LEN; else ndev->max_mtu = SKB_MAX_HEAD(NET_SKB_PAD + NET_IP_ALIGN); +#ifdef TC956X_SRIOV_VF + } else + ndev->max_mtu = SKB_MAX_HEAD(NET_SKB_PAD + NET_IP_ALIGN); +#endif /* Will not overwrite ndev->max_mtu if plat->maxmtu > ndev->max_mtu * as well as plat->maxmtu < ndev->min_mtu which is a invalid range. */ @@ -12335,8 +15236,59 @@ int tc956xmac_dvr_probe(struct device *device, ch->priv_data = priv; ch->index = queue; +#ifdef TC956X_SRIOV_PF + + if (queue < priv->plat->rx_queues_to_use) { + + if (priv->plat->rx_ch_in_use[queue] == + TC956X_DISABLE_CHNL) + continue; + + /* Add napi only for applicable channels */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)) + netif_napi_add(ndev, &ch->rx_napi, tc956xmac_napi_poll_rx); +#else + netif_napi_add(ndev, &ch->rx_napi, tc956xmac_napi_poll_rx, + NAPI_POLL_WEIGHT); +#endif + } + if (queue < priv->plat->tx_queues_to_use) { + + + if (priv->plat->tx_ch_in_use[queue] == + TC956X_DISABLE_CHNL) + continue; + + /* Add napi only for applicable channels */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 0)) + netif_napi_add_tx(ndev, &ch->tx_napi, + tc956xmac_napi_poll_tx); +#else + netif_tx_napi_add(ndev, &ch->tx_napi, + tc956xmac_napi_poll_tx, + NAPI_POLL_WEIGHT); +#endif + } +#elif defined TC956X_SRIOV_VF + /* DMA Tx or Rx channel number and counts are same for VF, so + * use any one variable to skip the non-used channel + */ + + if ((queue < priv->plat->rx_queues_to_use) && + (priv->plat->ch_in_use[queue] == 1)) { + netif_napi_add(ndev, &ch->rx_napi, tc956xmac_napi_poll_rx, + NAPI_POLL_WEIGHT); + } + if ((queue < priv->plat->tx_queues_to_use) && + (priv->plat->ch_in_use[queue] == 1)) { + netif_tx_napi_add(ndev, &ch->tx_napi, + tc956xmac_napi_poll_tx, + NAPI_POLL_WEIGHT); + } +#else /* TC956X_SRIOV_PF */ if ((queue < priv->plat->rx_queues_to_use) && (priv->plat->rx_dma_ch_owner[queue] == USE_IN_TC956X_SW)) { + netif_napi_add(ndev, &ch->rx_napi, tc956xmac_napi_poll_rx, NAPI_POLL_WEIGHT); } @@ -12346,11 +15298,14 @@ int tc956xmac_dvr_probe(struct device *device, tc956xmac_napi_poll_tx, NAPI_POLL_WEIGHT); } +#endif /* TC956X_SRIOV_PF */ } mutex_init(&priv->lock); mutex_init(&priv->port_ld_release_lock); +#ifndef TC956X_SRIOV_VF + /* If a specific clk_csr value is passed from the platform * this means that the CSR Clock Range selection cannot be * changed at run-time and it is fixed. Viceversa the driver'll try to @@ -12419,7 +15374,7 @@ int tc956xmac_dvr_probe(struct device *device, KPRINT_INFO("XPCS initialization error\n"); } -#endif +#endif /* TC956X */ if (priv->hw->pcs != TC956XMAC_PCS_RGMII && priv->hw->pcs != TC956XMAC_PCS_TBI && priv->hw->pcs != TC956XMAC_PCS_RTBI) { @@ -12449,7 +15404,7 @@ int tc956xmac_dvr_probe(struct device *device, netdev_err(ndev, "failed to setup phy (%d)\n", ret); goto error_phy_setup; } - +#endif /* TC956X_SRIOV_VF */ ret = register_netdev(ndev); if (ret) { dev_err(priv->device, "%s: ERROR %i registering the device\n", @@ -12461,9 +15416,17 @@ int tc956xmac_dvr_probe(struct device *device, tc956xmac_init_fs(ndev); #endif +#ifdef TC956X_ENABLE_MAC2MAC_BRIDGE + priv->pbridge_buffsize = DEFAULT_BUFSIZE * DMA_RX_SIZE; + priv->pbridge_buffaddr = dma_alloc_coherent(priv->device, + priv->pbridge_buffsize, &priv->pbridge_handle, GFP_DMA); + if (priv->pbridge_buffaddr == NULL) + ret = -ENOSPC; +#endif return ret; error_netdev_register: +#ifndef TC956X_SRIOV_VF phylink_destroy(priv->phylink); error_phy_setup: if (priv->hw->pcs != TC956XMAC_PCS_RGMII && @@ -12473,14 +15436,30 @@ int tc956xmac_dvr_probe(struct device *device, error_mdio_register: for (queue = 0; queue < maxq; queue++) { struct tc956xmac_channel *ch = &priv->channel[queue]; - +#ifdef TC956X_SRIOV_PF + if (queue < priv->plat->rx_queues_to_use) { + if (priv->plat->rx_ch_in_use[queue] == + TC956X_DISABLE_CHNL) + continue; +#else if (queue < priv->plat->rx_queues_to_use && priv->plat->rx_dma_ch_owner[queue] == USE_IN_TC956X_SW) +#endif netif_napi_del(&ch->rx_napi); +} +#ifdef TC956X_SRIOV_PF + if (queue < priv->plat->tx_queues_to_use) { + if (priv->plat->tx_ch_in_use[queue] == + TC956X_DISABLE_CHNL) + continue; +#else if (queue < priv->plat->tx_queues_to_use && priv->plat->tx_dma_ch_owner[queue] == USE_IN_TC956X_SW) +#endif netif_napi_del(&ch->tx_napi); + } } +#endif /* TC956X_SRIOV_VF */ #ifndef TC956X_WITHOUT_MDIO if (priv->port_num == 0) { nrst_reg = priv->tc956x_SFR_pci_base_addr + NRSTCTRL0_OFFSET; @@ -12505,49 +15484,72 @@ int tc956xmac_dvr_probe(struct device *device, #ifndef TC956X destroy_workqueue(priv->wq); #endif +#if (defined(TC956X_SRIOV_PF) && !defined(TC956X_AUTOMOTIVE_CONFIG) && !defined(TC956X_ENABLE_MAC2MAC_BRIDGE)) | defined(TC956X_SRIOV_VF) + destroy_workqueue(priv->mbx_wq); +#endif return ret; } +#ifdef TC956X_SRIOV_PF EXPORT_SYMBOL_GPL(tc956xmac_dvr_probe); - +#elif defined TC956X_SRIOV_VF +EXPORT_SYMBOL_GPL(tc956xmac_vf_dvr_probe); +#endif /** * tc956xmac_dvr_remove * @dev: device pointer * Description: this function resets the TX/RX processes, disables the MAC RX/TX * changes the link status, releases the DMA descriptor rings. */ +#ifdef TC956X_SRIOV_PF int tc956xmac_dvr_remove(struct device *dev) +#elif defined TC956X_SRIOV_VF +int tc956xmac_vf_dvr_remove(struct device *dev) +#endif { struct net_device *ndev = dev_get_drvdata(dev); struct tc956xmac_priv *priv = netdev_priv(ndev); +#ifndef TC956X_SRIOV_VF u32 val; struct phy_device *phydev; int addr = priv->plat->phy_addr; - netdev_info(priv->dev, "%s: removing driver", __func__); - phydev = mdiobus_get_phy(priv->mii, addr); - if(phydev->drv != NULL) { +#endif + + netdev_info(priv->dev, "%s: removing driver", __func__); + +#ifdef TC956X_SRIOV_VF + tc956xmac_vf_reset(priv, VF_DOWN); +#else + if (phydev->drv != NULL) { if ((true == priv->plat->phy_interrupt_mode) && (phydev->drv->config_intr)) cancel_work_sync(&priv->emac_phy_work); } +#endif + #ifdef CONFIG_DEBUG_FS tc956xmac_exit_fs(ndev); #endif tc956xmac_stop_all_dma(priv); +#ifndef TC956X_SRIOV_VF tc956xmac_mac_set(priv, priv->ioaddr, false); +#endif + netif_carrier_off(ndev); unregister_netdev(ndev); +#ifndef TC956X_SRIOV_VF phylink_destroy(priv->phylink); - +#endif kfree(priv->mac_table); kfree(priv->vlan_table); if (priv->plat->tc956xmac_rst) reset_control_assert(priv->plat->tc956xmac_rst); +#ifndef TC956X_SRIOV_VF clk_disable_unprepare(priv->plat->pclk); clk_disable_unprepare(priv->plat->tc956xmac_clk); if (priv->hw->pcs != TC956XMAC_PCS_RGMII && @@ -12559,11 +15561,17 @@ int tc956xmac_dvr_remove(struct device *dev) dev_err(priv->device, "Platform remove error\n"); } +#endif #ifndef TC956X destroy_workqueue(priv->wq); +#endif +#if (defined(TC956X_SRIOV_PF) && !defined(TC956X_AUTOMOTIVE_CONFIG) && !defined(TC956X_ENABLE_MAC2MAC_BRIDGE)) | defined(TC956X_SRIOV_VF) + destroy_workqueue(priv->mbx_wq); #endif mutex_destroy(&priv->lock); mutex_destroy(&priv->port_ld_release_lock); + +#ifndef TC956X_SRIOV_VF #ifdef TC956X val = ioread32((void __iomem *)(priv->tc956x_SRAM_pci_base_addr + TC956X_M3_FW_EXIT)); val += 1; @@ -12573,9 +15581,20 @@ int tc956xmac_dvr_remove(struct device *dev) iowrite32(val, (void __iomem *)(priv->tc956x_SRAM_pci_base_addr + TC956X_M3_FW_EXIT)); #endif +#ifdef TC956X_ENABLE_MAC2MAC_BRIDGE + dma_free_coherent(priv->device, priv->pbridge_buffsize, priv->pbridge_buffaddr, + priv->pbridge_handle); +#endif +#endif + return 0; } + +#ifdef TC956X_SRIOV_PF EXPORT_SYMBOL_GPL(tc956xmac_dvr_remove); +#elif defined TC956X_SRIOV_VF +EXPORT_SYMBOL_GPL(tc956xmac_vf_dvr_remove); +#endif /** * tc956xmac_suspend - suspend callback @@ -12584,26 +15603,38 @@ EXPORT_SYMBOL_GPL(tc956xmac_dvr_remove); * by the platform driver to stop the network queue, release the resources, * program the PMT register (for WoL), clean and release driver resources. */ +#ifdef TC956X_SRIOV_PF int tc956xmac_suspend(struct device *dev) +#elif defined TC956X_SRIOV_VF +int tc956xmac_vf_suspend(struct device *dev) +#endif { struct net_device *ndev = dev_get_drvdata(dev); struct tc956xmac_priv *priv = netdev_priv(ndev); +#ifndef TC956X_SRIOV_VF struct phy_device *phydev = NULL; /* For cancelling Work queue */ int addr = priv->plat->phy_addr; - +#endif KPRINT_INFO("---> %s : Port %d", __func__, priv->port_num); +#ifndef TC956X_SRIOV_VF if ((priv->plat->phy_addr != -1) && (priv->mii != NULL)) phydev = mdiobus_get_phy(priv->mii, addr); - +#endif if (!ndev) return 0; - +#ifndef TC956X_SRIOV_VF if (!phydev) { - DBGPR_FUNC(priv->device, "%s Error : No phy at Addr %d or MDIO Unavailable \n", + DBGPR_FUNC(priv->device, "%s Error : No phy at Addr %d or MDIO Unavailable\n", __func__, addr); return 0; } +#endif +#ifdef TC956X_SRIOV_VF + tc956xmac_vf_reset(priv, VF_SUSPEND); +#endif + +#ifndef TC956X_SRIOV_VF /* Disabling EEE for issue in TC9560/62, to be tested for TC956X */ if (priv->eee_enabled) tc956xmac_disable_eee_mode(priv); @@ -12612,19 +15643,21 @@ int tc956xmac_suspend(struct device *dev) // KPRINT_INFO("%s : Port %d - Phy Speed Down", __func__, priv->port_num); // phy_speed_down(phydev, true); //} +#endif if (!netif_running(ndev)) goto clean_exit; +#ifndef TC956X_SRIOV_VF /* Cancel all work-queues before suspend start only when net interface is up and running */ if (phydev->drv != NULL) { - if ((true == priv->plat->phy_interrupt_mode) && + if ((true == priv->plat->phy_interrupt_mode) && (phydev->drv->config_intr)) { - DBGPR_FUNC(priv->device, "%s : (Flush All PHY work-queues) \n", __func__); + DBGPR_FUNC(priv->device, "%s : (Flush All PHY work-queues)\n", __func__); cancel_work_sync(&priv->emac_phy_work); } } - +#endif /* Invoke device driver close only when net inteface is up and running. */ rtnl_lock(); tc956xmac_release(ndev); @@ -12641,7 +15674,11 @@ int tc956xmac_suspend(struct device *dev) KPRINT_INFO("<--- %s : Port %d", __func__, priv->port_num); return 0; } +#ifdef TC956X_SRIOV_PF EXPORT_SYMBOL_GPL(tc956xmac_suspend); +#elif defined TC956X_SRIOV_VF +EXPORT_SYMBOL_GPL(tc956xmac_vf_suspend); +#endif #ifndef TC956X /** * tc956xmac_reset_queues_param - reset queue parameters @@ -12655,53 +15692,76 @@ static void tc956xmac_reset_queues_param(struct tc956xmac_priv *priv) for (queue = 0; queue < rx_cnt; queue++) { struct tc956xmac_rx_queue *rx_q = &priv->rx_queue[queue]; - +#ifdef TC956X_SRIOV_PF + if (priv->plat->rx_ch_in_use[queue] == + TC956X_DISABLE_CHNL) + continue; +#elif defined TC956X_SRIOV_VF + /* skip configuring for unallocated channel */ + if (priv->plat->ch_in_use[queue] == 0) + continue; +#else if (priv->plat->rx_dma_ch_owner[queue] != USE_IN_TC956X_SW) continue; - +#endif rx_q->cur_rx = 0; rx_q->dirty_rx = 0; } for (queue = 0; queue < tx_cnt; queue++) { struct tc956xmac_tx_queue *tx_q = &priv->tx_queue[queue]; - +#ifdef TC956X_SRIOV_PF + if (priv->plat->tx_ch_in_use[queue] == + TC956X_DISABLE_CHNL) + continue; +#elif defined TC956X_SRIOV_VF + /* skip configuring for unallocated channel */ + if (priv->plat->ch_in_use[queue] == 0) + continue; +#else if (priv->plat->tx_dma_ch_owner[queue] != USE_IN_TC956X_SW) continue; - +#endif tx_q->cur_tx = 0; tx_q->dirty_tx = 0; tx_q->mss = 0; } } -#endif - +#endif /* TC956X */ /** * tc956xmac_resume - resume callback * @dev: device pointer * Description: when resume this function is invoked to setup the DMA and CORE * in a usable state. */ +#ifdef TC956X_SRIOV_PF int tc956xmac_resume(struct device *dev) +#elif defined TC956X_SRIOV_VF +int tc956xmac_vf_resume(struct device *dev) +#endif { struct net_device *ndev = dev_get_drvdata(dev); struct tc956xmac_priv *priv = netdev_priv(ndev); struct tc956xmac_resources res; +#ifndef TC956X_SRIOV_VF u32 cm3_reset_status = 0; s32 fw_load_status = 0; #ifndef TC956X_WITHOUT_MDIO void *nrst_reg = NULL, *nclk_reg = NULL; u32 nrst_val = 0, nclk_val = 0; #endif - KPRINT_INFO("---> %s : Port %d", __func__, priv->port_num); +#endif /* TC956X_SRIOV_VF */ + KPRINT_INFO("---> %s : Port %d", __func__, priv->port_num); +#ifdef TC956X memset(&res, 0, sizeof(res)); +#ifndef TC956X_SRIOV_VF cm3_reset_status = readl((priv->ioaddr + NRSTCTRL0_OFFSET)); if ((cm3_reset_status & NRSTCTRL0_MCURST) == NRSTCTRL0_MCURST) { - res.tc956x_SFR_pci_base_addr = priv->tc956x_SFR_pci_base_addr; - res.addr = priv->ioaddr; - res.tc956x_SRAM_pci_base_addr = priv->tc956x_SRAM_pci_base_addr; - res.irq = priv->dev->irq; + res.tc956x_SFR_pci_base_addr = priv->tc956x_SFR_pci_base_addr; + res.addr = priv->ioaddr; + res.tc956x_SRAM_pci_base_addr = priv->tc956x_SRAM_pci_base_addr; + res.irq = priv->dev->irq; fw_load_status = tc956x_load_firmware(dev, &res); if (fw_load_status < 0) { KPRINT_ERR("Firmware load failed\n"); @@ -12713,24 +15773,41 @@ int tc956xmac_resume(struct device *dev) // KPRINT_INFO("%s : Port %d - Phy Speed Up", __func__, priv->port_num); // phy_speed_up(phydev); //} +#elif defined(TC956X_SRIOV_VF) + res.tc956x_SFR_pci_base_addr = priv->tc956x_SFR_pci_base_addr; + res.addr = priv->ioaddr; + res.tc956x_SRAM_pci_base_addr = priv->tc956x_SRAM_pci_base_addr; + res.irq = priv->dev->irq; +#endif +#endif /* TC956X */ + + #ifndef TC956X /* Reset Parameters. */ tc956xmac_reset_queues_param(priv); #endif if (!netif_running(ndev)) goto clean_exit; + /* Invoke device driver open */ rtnl_lock(); tc956xmac_open(ndev); rtnl_unlock(); +clean_exit: /* Attach network device */ netif_device_attach(ndev); -clean_exit: + + +#ifdef TC956X_SRIOV_VF + tc956xmac_vf_reset(priv, VF_UP); +#endif /* TC956X_SRIOV_VF */ + +#ifndef TC956X_SRIOV_VF /* Reset eMAC when Port unavailable */ if ((priv->plat->phy_addr == -1) || (priv->mii == NULL)) { - KPRINT_ERR("%s : Port %d : Invalid PHY Address (%d)\n", __func__, priv->port_num, + KPRINT_ERR("%s : Port %d : Invalid PHY Address (%d)\n", __func__, priv->port_num, priv->plat->phy_addr); #ifndef TC956X_WITHOUT_MDIO /* Set Clocks same as before suspend */ @@ -12754,11 +15831,17 @@ int tc956xmac_resume(struct device *dev) readl(nrst_reg), readl(nclk_reg)); #endif } +#endif KPRINT_INFO("<--- %s : Port %d", __func__, priv->port_num); return 0; } +#ifdef TC956X_SRIOV_PF EXPORT_SYMBOL_GPL(tc956xmac_resume); +#elif defined TC956X_SRIOV_VF +EXPORT_SYMBOL_GPL(tc956xmac_vf_resume); +#endif +#ifndef TC956X_SRIOV_VF /*! * \brief API to save and restore clock and reset during link down and link up. * @@ -12792,17 +15875,17 @@ void tc956xmac_link_change_set_power(struct tc956xmac_priv *priv, enum TC956X_PO KPRINT_INFO("%s : Port %d Set Power for Link Down", __func__, priv->port_num); nrst_val = readl(nrst_reg); nclk_val = readl(nclk_reg); - KPRINT_INFO("%s : Port %d Rd RST Reg:%x, CLK Reg:%x", __func__, priv->port_num, + KPRINT_INFO("%s : Port %d Rd RST Reg:%x, CLK Reg:%x", __func__, priv->port_num, nrst_val, nclk_val); /* Save register values before Asserting reset and Clock Disable */ priv->pm_saved_linkdown_rst = ((~nrst_val) & NRSTCTRL_LINK_DOWN_SAVE); /* Save Non-Common De-Asserted Resets */ priv->pm_saved_linkdown_clk = (nclk_val & NCLKCTRL_LINK_DOWN_SAVE); /* Save Non-Common Enabled Clocks */ - KPRINT_INFO("%s : Port %d priv->pm_saved_linkdown_rst %x priv->pm_saved_linkdown_clk %x", __func__, + KPRINT_INFO("%s : Port %d priv->pm_saved_linkdown_rst %x priv->pm_saved_linkdown_clk %x", __func__, priv->port_num, priv->pm_saved_linkdown_rst, priv->pm_saved_linkdown_clk); /* Assert Reset and Disable Clock */ nrst_val = nrst_val | NRSTCTRL_LINK_DOWN; nclk_val = nclk_val & ~NCLKCTRL_LINK_DOWN; - KPRINT_INFO("%s : Port %d Wr RST Reg:%x, CLK Reg:%x", __func__, priv->port_num, + KPRINT_INFO("%s : Port %d Wr RST Reg:%x, CLK Reg:%x", __func__, priv->port_num, nrst_val, nclk_val); writel(nrst_val, nrst_reg); writel(nclk_val, nclk_reg); @@ -12813,11 +15896,11 @@ void tc956xmac_link_change_set_power(struct tc956xmac_priv *priv, enum TC956X_PO commonclk_reg = priv->tc956x_SFR_pci_base_addr + NCLKCTRL0_OFFSET; commonrst_val = readl(commonrst_reg); commonclk_val = readl(commonclk_reg); - KPRINT_INFO("%s : Port %d Common Rd RST Reg:%x, CLK Reg:%x", __func__, priv->port_num, + KPRINT_INFO("%s : Port %d Common Rd RST Reg:%x, CLK Reg:%x", __func__, priv->port_num, commonrst_val, commonclk_val); pm_saved_cmn_linkdown_rst = ((~commonrst_val) & NRSTCTRL_LINK_DOWN_CMN_SAVE); /* Save Common De-Asserted Resets */ pm_saved_cmn_linkdown_clk = commonclk_val & NCLKCTRL_LINK_DOWN_CMN_SAVE; /* Save Common Enabled Clocks */ - KPRINT_INFO("%s : Port %d pm_saved_cmn_linkdown_rst %x pm_saved_cmn_linkdown_clk %x", __func__, + KPRINT_INFO("%s : Port %d pm_saved_cmn_linkdown_rst %x pm_saved_cmn_linkdown_clk %x", __func__, priv->port_num, pm_saved_cmn_linkdown_rst, pm_saved_cmn_linkdown_clk); } priv->port_link_down = true; /* Set per port flag to true */ @@ -12825,38 +15908,38 @@ void tc956xmac_link_change_set_power(struct tc956xmac_priv *priv, enum TC956X_PO KPRINT_INFO("%s : Port %d Set Power for Link Up", __func__, priv->port_num); if (tc956xmac_link_down_counter == TC956X_ALL_MAC_PORT_LINK_DOWN) { /* Restore Common register values */ - KPRINT_INFO("%s : Port %d pm_saved_cmn_linkdown_clk %x, pm_saved_cmn_linkdown_rst %x", __func__, + KPRINT_INFO("%s : Port %d pm_saved_cmn_linkdown_clk %x, pm_saved_cmn_linkdown_rst %x", __func__, priv->port_num, pm_saved_cmn_linkdown_clk, pm_saved_cmn_linkdown_rst); /* Enable Common Clock and De-Assert Common Resets */ commonclk_reg = priv->tc956x_SFR_pci_base_addr + NCLKCTRL0_OFFSET; commonrst_reg = priv->tc956x_SFR_pci_base_addr + NRSTCTRL0_OFFSET; commonclk_val = readl(commonclk_reg); commonrst_val = readl(commonrst_reg); - KPRINT_INFO("%s : Port %d Common Rd CLK Reg:%x, RST Reg:%x ", __func__, priv->port_num, + KPRINT_INFO("%s : Port %d Common Rd CLK Reg:%x, RST Reg:%x ", __func__, priv->port_num, commonclk_val, commonrst_val); /* Clear Common Clocks only when both port suspends */ commonclk_val = (commonclk_val | pm_saved_cmn_linkdown_clk); /* Enable Common Saved Clock */ commonrst_val = (commonrst_val & (~pm_saved_cmn_linkdown_rst)); /* De-assert Common Saved Reset */ writel(commonclk_val, commonclk_reg); writel(commonrst_val, commonrst_reg); - KPRINT_INFO("%s : Port %d Common Wr CLK Reg:%x, RST Reg:%x ", __func__, priv->port_num, + KPRINT_INFO("%s : Port %d Common Wr CLK Reg:%x, RST Reg:%x ", __func__, priv->port_num, commonclk_val, commonrst_val); - KPRINT_INFO("%s : Port %d Common Rd CLK Reg:%x, RST Reg:%x", __func__, priv->port_num, + KPRINT_INFO("%s : Port %d Common Rd CLK Reg:%x, RST Reg:%x", __func__, priv->port_num, readl(commonclk_reg), readl(commonrst_reg)); } /* Restore register values */ - KPRINT_INFO("%s : Port %d pm_saved_linkdown_clk %x, pm_saved_linkdown_rst %x", __func__, + KPRINT_INFO("%s : Port %d pm_saved_linkdown_clk %x, pm_saved_linkdown_rst %x", __func__, priv->port_num, priv->pm_saved_linkdown_clk, priv->pm_saved_linkdown_rst); nclk_val = readl(nclk_reg); nrst_val = readl(nrst_reg); - KPRINT_INFO("%s : Port %d Rd CLK Reg:%x, RST Reg:%x", __func__, priv->port_num, + KPRINT_INFO("%s : Port %d Rd CLK Reg:%x, RST Reg:%x", __func__, priv->port_num, nrst_val, nclk_val); /* Restore values same as before link down */ nclk_val = (nclk_val | priv->pm_saved_linkdown_clk); /* Enable Saved Clock */ nrst_val = (nrst_val & (~(priv->pm_saved_linkdown_rst))); /* De-assert Saved Reset */ writel(nclk_val, nclk_reg); writel(nrst_val, nrst_reg); - KPRINT_INFO("%s : Port %d Wr CLK Reg:%x, RST Reg:%x ", __func__, priv->port_num, + KPRINT_INFO("%s : Port %d Wr CLK Reg:%x, RST Reg:%x ", __func__, priv->port_num, nclk_val, nrst_val); tc956xmac_link_down_counter--; /* Decrement Counter Only when this api called */ @@ -12868,8 +15951,8 @@ void tc956xmac_link_change_set_power(struct tc956xmac_priv *priv, enum TC956X_PO KPRINT_INFO("XPCS initialization error\n"); /*C37 AN enable*/ - if ((priv->plat->interface == PHY_INTERFACE_MODE_10GKR) || - (priv->plat->interface == ENABLE_2500BASE_X_INTERFACE)) + if ((priv->plat->interface == PHY_INTERFACE_MODE_10GKR) || + (priv->plat->interface == ENABLE_2500BASE_X_INTERFACE)) enable_en = false; else if (priv->plat->interface == PHY_INTERFACE_MODE_SGMII) { if (priv->is_sgmii_2p5g == true) @@ -12881,13 +15964,15 @@ void tc956xmac_link_change_set_power(struct tc956xmac_priv *priv, enum TC956X_PO tc956x_xpcs_ctrl_ane(priv, enable_en); } - KPRINT_INFO("%s : Port %d Rd RST Reg:%x, CLK Reg:%x", __func__, priv->port_num, + KPRINT_INFO("%s : Port %d Rd RST Reg:%x, CLK Reg:%x", __func__, priv->port_num, readl(nrst_reg), readl(nclk_reg)); KPRINT_INFO("<--%s : Port %d", __func__, priv->port_num); } else { KPRINT_INFO("-->%s : status of Power saving at Link down %d", __func__, mac_power_save_at_link_down); } + } +#endif #ifndef MODULE static int __init tc956xmac_cmdline_opt(char *str) diff --git a/tc956xmac_mdio.c b/tc956xmac_mdio.c index f61fdff25a87..e779e356ebf4 100644 --- a/tc956xmac_mdio.c +++ b/tc956xmac_mdio.c @@ -45,6 +45,9 @@ * VERSION : 01-00-32 * 21 Oct 2022 : 1. MDIO registration failures treated as error -ENODEV * VERSION : 01-00-56 + * + * 26 Dec 2023 : 1. Kernel 6.6 Porting changes + * VERSION : 01-03-59 */ #include @@ -83,6 +86,25 @@ #define MII_XGMAC_CRS BIT(31) #define MII_XGMAC_CRS_SHIFT 31 +/*Preamble support*/ +#define MII_XGMAC_PSE_SHIFT 30 +#define MII_XGMAC_PSE BIT(30) +#define MII_XGMAC_DISABLE_PSE 0xBFFFFFFF + +#ifdef TC956X_MAGIC_PACKET_WOL_CONF +#define MII_XGMAC_DA_MASK 0x1F +#define MII_XGMAC_PHYREG_MASK 0xFFFF +#define MII_AQR113C_PHY_GLOBAL_DEV 0x1E +#define MII_AQR113C_PHY_GLBL_100M_REG_ADDR 0x31B +#define MII_AQR113C_PHY_GLBL_1G_REG_ADDR 0x31C +#define MII_AQR113C_AN_EN_SGMII_MODE_MASK 0xB +#define MII_AQR113C_AN_DIS_SGMII_DIS 0x0 +#endif /* #ifdef TC956X_MAGIC_PACKET_WOL_CONF */ + +#define TC956X_MII_ADDR_C45 (1<<30) +#define TC956X_MII_DEVADDR_C45_SHIFT 16 +#define TC956X_MII_REGADDR_C45_MASK GENMASK(15, 0) + static int tc956xmac_xgmac2_c45_format(struct tc956xmac_priv *priv, int phyaddr, int phyreg, u32 *hw_addr) { @@ -94,7 +116,7 @@ static int tc956xmac_xgmac2_c45_format(struct tc956xmac_priv *priv, int phyaddr, writel(tmp, priv->ioaddr + XGMAC_MDIO_C22P); *hw_addr = (phyaddr << MII_XGMAC_PA_SHIFT) | (phyreg & 0xffff); - *hw_addr |= (phyreg >> MII_DEVADDR_C45_SHIFT) << MII_XGMAC_DA_SHIFT; + *hw_addr |= (phyreg >> TC956X_MII_DEVADDR_C45_SHIFT) << MII_XGMAC_DA_SHIFT; return 0; } @@ -103,13 +125,8 @@ static int tc956xmac_xgmac2_c22_format(struct tc956xmac_priv *priv, int phyaddr, { u32 tmp; - /* HW does not support C22 addr >= 4 */ - //if (phyaddr > MII_XGMAC_MAX_C22ADDR) - //return -ENODEV; - /* Set port as Clause 22 */ tmp = readl(priv->ioaddr + XGMAC_MDIO_C22P); - //tmp &= ~MII_XGMAC_C22P_MASK; tmp |= BIT(phyaddr); writel(tmp, priv->ioaddr + XGMAC_MDIO_C22P); @@ -134,6 +151,7 @@ static int __tc956xmac_xgmac2_mdio_read(struct mii_bus *bus, int phyaddr, int ph !(tmp & MII_XGMAC_BUSY), /*100*/1, 10000)) return -EBUSY; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 3, 0)) if ((priv->plat->c45_needed == true) && (phyreg < 0x1F)) { if (phyreg == 0) phyreg = (MII_ADDR_C45 | ((PHY_CL45_CTRL_REG_MMD_BANK) << 16) | (PHY_CL45_CTRL_REG_ADDR)); @@ -147,10 +165,10 @@ static int __tc956xmac_xgmac2_mdio_read(struct mii_bus *bus, int phyaddr, int ph netdev_dbg(priv->dev, "%s Clause 45 register not defined for PHY register 0x%x\n", __func__, phyreg); } +#endif - - if (phyreg & MII_ADDR_C45) { - phyreg &= ~MII_ADDR_C45; + if (phyreg & TC956X_MII_ADDR_C45) { + phyreg &= ~TC956X_MII_ADDR_C45; ret = tc956xmac_xgmac2_c45_format(priv, phyaddr, phyreg, &addr); if (ret) @@ -171,6 +189,12 @@ static int __tc956xmac_xgmac2_mdio_read(struct mii_bus *bus, int phyaddr, int ph value |= MII_XGMAC_READ; + /*Preamble support*/ + if (priv->plat->pse == 1) + value |= MII_XGMAC_PSE; /*Set PSE for preamble supperssion*/ + else + value &= MII_XGMAC_DISABLE_PSE; /* Reset PSE for preamble supperssion disable*/ + /* Wait until any existing MII operation is complete */ if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, !(tmp & MII_XGMAC_BUSY), /*100*/1, 10000)) @@ -189,7 +213,7 @@ static int __tc956xmac_xgmac2_mdio_read(struct mii_bus *bus, int phyaddr, int ph return readl(priv->ioaddr + mii_data) & GENMASK(15, 0); } /** - * __tc956xmac_xgmac2_mdio_read + * tc956xmac_xgmac2_mdio_read * @bus: points to the mii_bus structure * @phyaddr: MII addr * @phyreg: MII reg @@ -201,6 +225,23 @@ static int tc956xmac_xgmac2_mdio_read(struct mii_bus *bus, int phyaddr, int phyr return bus->priv ? __tc956xmac_xgmac2_mdio_read(bus, phyaddr, phyreg) : -EIO; } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)) +/** + * tc956xmac_xgmac2_mdio_read_c45 + * @bus: points to the mii_bus structure + * @phyaddr: MII addr + * @devad: device (MMD) address + * @phyreg: MII reg + * Description: Check whether MDIO bus is registered successfully or not + * if registered then access MDIO for C45 Read operation + */ +static int tc956xmac_xgmac2_mdio_read_c45(struct mii_bus *bus, int phyaddr, + int devad, int phyreg) +{ + return bus->priv ? __tc956xmac_xgmac2_mdio_read(bus, phyaddr, + TC956X_MII_ADDR_C45 | (devad << TC956X_MII_DEVADDR_C45_SHIFT) | phyreg) : -EIO; +} +#endif /* KERNEL_VERSION(6, 3, 0) */ static int __tc956xmac_xgmac2_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg, u16 phydata) @@ -211,6 +252,9 @@ static int __tc956xmac_xgmac2_mdio_write(struct mii_bus *bus, int phyaddr, unsigned int mii_data = priv->hw->mii.data; u32 addr, tmp, value = MII_XGMAC_BUSY; int ret; +#ifdef TC956X_MAGIC_PACKET_WOL_CONF + u32 devtype = 0, datareg = 0, dataval = 0; +#endif if (priv->plat->cphy_write) return priv->plat->cphy_write(priv, phyaddr, phyreg, phydata); @@ -220,8 +264,8 @@ static int __tc956xmac_xgmac2_mdio_write(struct mii_bus *bus, int phyaddr, !(tmp & MII_XGMAC_BUSY), /*100*/1, 10000)) return -EBUSY; - if (phyreg & MII_ADDR_C45) { - phyreg &= ~MII_ADDR_C45; + if (phyreg & TC956X_MII_ADDR_C45) { + phyreg &= ~TC956X_MII_ADDR_C45; ret = tc956xmac_xgmac2_c45_format(priv, phyaddr, phyreg, &addr); if (ret) @@ -243,21 +287,63 @@ static int __tc956xmac_xgmac2_mdio_write(struct mii_bus *bus, int phyaddr, value |= phydata; value |= MII_XGMAC_WRITE; + /*Preamble support*/ + if (priv->plat->pse == 1) + value |= MII_XGMAC_PSE; /*Set PSE for preamble supperssion*/ + else + value &= MII_XGMAC_DISABLE_PSE; /* Reset PSE for preamble supperssion disable*/ + /* Wait until any existing MII operation is complete */ if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, !(tmp & MII_XGMAC_BUSY), /*100*/1, 10000)) return -EBUSY; +#ifdef TC956X_MAGIC_PACKET_WOL_CONF + /* NOTE: Following changes specific to AQR PHY while configuring WOL. */ + if (priv->plat->interface != PHY_INTERFACE_MODE_SGMII) { + /* If we are updating SGMII configurtaion in Non-SGMII interface mode */ + devtype = ((addr >> MII_XGMAC_DA_SHIFT) & MII_XGMAC_DA_MASK); + datareg = (addr & MII_XGMAC_PHYREG_MASK); + dataval = (value); + if (priv->wol_config_enabled == false) { + /* Check for 1e.31b = 0x0b and 1e.31c = 0x0b */ + if (((devtype == MII_AQR113C_PHY_GLOBAL_DEV) && + (datareg == MII_AQR113C_PHY_GLBL_100M_REG_ADDR) && + ((dataval & MII_AQR113C_AN_EN_SGMII_MODE_MASK) == MII_AQR113C_AN_EN_SGMII_MODE_MASK)) || + ((devtype == MII_AQR113C_PHY_GLOBAL_DEV) && + (datareg == MII_AQR113C_PHY_GLBL_1G_REG_ADDR) && + ((dataval & MII_AQR113C_AN_EN_SGMII_MODE_MASK) == MII_AQR113C_AN_EN_SGMII_MODE_MASK))) { + priv->wol_config_enabled = true; /* Enable SGMII SERDES Flag */ + KPRINT_INFO("%s Port %d : Changing flag priv->wol_config_enabled to %d\n", __func__, priv->port_num, priv->wol_config_enabled); + } + } else if (((devtype == MII_AQR113C_PHY_GLOBAL_DEV) && /* Check for 1e.31b = 0x00 and 1e.31c = 0x00 */ + (datareg == MII_AQR113C_PHY_GLBL_100M_REG_ADDR) && + ((dataval & MII_AQR113C_AN_EN_SGMII_MODE_MASK) == MII_AQR113C_AN_DIS_SGMII_DIS)) || + ((devtype == MII_AQR113C_PHY_GLOBAL_DEV) && + (datareg == MII_AQR113C_PHY_GLBL_1G_REG_ADDR) && + ((dataval & MII_AQR113C_AN_EN_SGMII_MODE_MASK) == MII_AQR113C_AN_DIS_SGMII_DIS))) { + priv->wol_config_enabled = false; /* Disable SGMII SERDES Flag */ + KPRINT_INFO("%s Port %d : Changing flag priv->wol_config_enabled to %d\n", __func__, priv->port_num, priv->wol_config_enabled); + } + } +#endif /* Set the MII address register to write */ writel(addr, priv->ioaddr + mii_address); writel(value, priv->ioaddr + mii_data); + /*Preamble support*/ + if ((priv->dev->phydev) && (priv->dev->phydev->priv != NULL)) { + if (*((int *)priv->dev->phydev->priv) == 1) + priv->plat->pse = 1; + else + priv->plat->pse = 0; + } /* Wait until any existing MII operation is complete */ return readl_poll_timeout(priv->ioaddr + mii_data, tmp, !(tmp & MII_XGMAC_BUSY), /*100*/10, 10000); } /** - * __tc956xmac_xgmac2_mdio_write + * tc956xmac_xgmac2_mdio_write * @bus: points to the mii_bus structure * @phyaddr: MII addr * @phyreg: MII reg @@ -272,7 +358,27 @@ static int tc956xmac_xgmac2_mdio_write(struct mii_bus *bus, int phyaddr, __tc956xmac_xgmac2_mdio_write(bus, phyaddr, phyreg, phydata) : -EIO; } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)) +/** + * tc956xmac_xgmac2_mdio_write_c45 + * @bus: points to the mii_bus structure + * @phyaddr: MII addr + * @devad: device (MMD) address + * @phyreg: MII reg + * @phydata: data to write into PHY reg + * Description: Check whether MDIO bus is registered successfully or not + * if registered then access MDIO for C45 Write operation + */ +static int tc956xmac_xgmac2_mdio_write_c45(struct mii_bus *bus, int phyaddr, + int devad, int phyreg, u16 phydata) +{ + return bus->priv ? __tc956xmac_xgmac2_mdio_write(bus, phyaddr, + TC956X_MII_ADDR_C45 | (devad << TC956X_MII_DEVADDR_C45_SHIFT) | phyreg, phydata) : -EIO; +} +#endif /* KERNEL_VERSION(6, 3, 0) */ + #ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE + /** * tc956xmac_mdio_read * @bus: points to the mii_bus structure @@ -292,7 +398,7 @@ static int tc956xmac_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg) u32 value = MII_BUSY; int data = 0; u32 v; - +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 3, 0)) if ((priv->plat->c45_needed == true) && (phyreg < 0x1F)) { if (phyreg == 0) phyreg = (MII_ADDR_C45 | (PHY_CL45_CTRL_REG_MMD_BANK << 16) | PHY_CL45_CTRL_REG_ADDR); @@ -306,6 +412,7 @@ static int tc956xmac_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg) netdev_dbg(priv->dev, "%s Clause 45 register not defined for PHY register 0x%x\n", __func__, phyreg); } +#endif value |= (phyaddr << priv->hw->mii.addr_shift) & priv->hw->mii.addr_mask; @@ -314,14 +421,14 @@ static int tc956xmac_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg) & priv->hw->mii.clk_csr_mask; if (priv->plat->has_gmac4) { value |= MII_GMAC4_READ; - if (phyreg & MII_ADDR_C45) { + if (phyreg & TC956X_MII_ADDR_C45) { value |= MII_GMAC4_C45E; value &= ~priv->hw->mii.reg_mask; - value |= ((phyreg >> MII_DEVADDR_C45_SHIFT) << + value |= ((phyreg >> TC956X_MII_DEVADDR_C45_SHIFT) << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask; - data |= (phyreg & MII_REGADDR_C45_MASK) << + data |= (phyreg & TC956X_MII_REGADDR_C45_MASK) << MII_GMAC4_REG_ADDR_SHIFT; } } @@ -343,6 +450,26 @@ static int tc956xmac_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg) return data; } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)) +/** + * tc956xmac_mdio_read_c45 + * @bus: points to the mii_bus structure + * @phyaddr: MII addr + * @devad: device (MMD) address + * @phyreg: MII reg + * Description: it reads data from the MII register from within the phy device. + * For the 7111 GMAC, we must set the bit 0 in the MII address register while + * accessing the PHY registers. + * Fortunately, it seems this has no drawback for the 7109 MAC. + */ +static int tc956xmac_mdio_read_c45(struct mii_bus *bus, int phyaddr, int devad, + int phyreg) +{ + return tc956xmac_mdio_read(bus, phyaddr, + TC956X_MII_ADDR_C45 | (devad << TC956X_MII_DEVADDR_C45_SHIFT) | phyreg); +} +#endif /* KERNEL_VERSION(6, 3, 0) */ + /** * tc956xmac_mdio_write * @bus: points to the mii_bus structure @@ -370,14 +497,14 @@ static int tc956xmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg, & priv->hw->mii.clk_csr_mask; if (priv->plat->has_gmac4) { value |= MII_GMAC4_WRITE; - if (phyreg & MII_ADDR_C45) { + if (phyreg & TC956X_MII_ADDR_C45) { value |= MII_GMAC4_C45E; value &= ~priv->hw->mii.reg_mask; - value |= ((phyreg >> MII_DEVADDR_C45_SHIFT) << + value |= ((phyreg >> TC956X_MII_DEVADDR_C45_SHIFT) << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask; - data |= (phyreg & MII_REGADDR_C45_MASK) << + data |= (phyreg & TC956X_MII_REGADDR_C45_MASK) << MII_GMAC4_REG_ADDR_SHIFT; } } else { @@ -397,6 +524,24 @@ static int tc956xmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg, return readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY), 100, 10000); } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)) +/** + * tc956xmac_mdio_write_c45 + * @bus: points to the mii_bus structure + * @phyaddr: MII addr + * @phyreg: MII reg + * @devad: device address to read + * @phydata: phy data + * Description: it writes the data into the MII register from within the device. + */ +static int tc956xmac_mdio_write_c45(struct mii_bus *bus, int phyaddr, + int devad, int phyreg, u16 phydata) +{ + return tc956xmac_mdio_write(bus, phyaddr, + TC956X_MII_ADDR_C45 | (devad << TC956X_MII_DEVADDR_C45_SHIFT) | phyreg, phydata); +} +#endif /* KERNEL_VERSION(6, 3, 0) */ #endif /* TC956X_UNSUPPORTED_UNTESTED_FEATURE */ /** @@ -463,7 +608,7 @@ int tc956xmac_mdio_register(struct net_device *ndev) struct tc956xmac_mdio_bus_data *mdio_bus_data = priv->plat->mdio_bus_data; struct device_node *mdio_node = priv->plat->mdio_node; struct device *dev = ndev->dev.parent; - int addr, found; + int addr, found, start_addr; if (!mdio_bus_data) return 0; @@ -480,6 +625,10 @@ int tc956xmac_mdio_register(struct net_device *ndev) if (priv->plat->has_xgmac) { new_bus->read = &tc956xmac_xgmac2_mdio_read; new_bus->write = &tc956xmac_xgmac2_mdio_write; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)) + new_bus->read_c45 = &tc956xmac_xgmac2_mdio_read_c45; + new_bus->write_c45 = &tc956xmac_xgmac2_mdio_write_c45; +#endif #ifndef TC956X /* Check if DT specified an unsupported phy addr */ if (priv->plat->phy_addr > MII_XGMAC_MAX_C22ADDR) @@ -491,6 +640,12 @@ int tc956xmac_mdio_register(struct net_device *ndev) else { new_bus->read = &tc956xmac_mdio_read; new_bus->write = &tc956xmac_mdio_write; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)) + if (priv->plat->has_gmac4) { + new_bus->read_c45 = &tc956xmac_mdio_read_c45; + new_bus->write_c45 = &tc956xmac_mdio_write_c45; + } +#endif } #endif /* TC956X_UNSUPPORTED_UNTESTED_FEATURE */ @@ -515,14 +670,22 @@ int tc956xmac_mdio_register(struct net_device *ndev) /* Looks like we need a dummy read for XGMAC only and C45 PHYs */ if (priv->plat->has_xgmac) +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 3, 0)) tc956xmac_xgmac2_mdio_read(new_bus, 0, MII_ADDR_C45); +#else + tc956xmac_xgmac2_mdio_read_c45(new_bus, 0, 0, 0); +#endif #ifndef TC956X if (priv->plat->phy_node || mdio_node || priv->plat->has_xgmac) goto bus_register_done; #endif found = 0; - for (addr = 0; addr < PHY_MAX_ADDR; addr++) { + + /* Select the PHY address to be detected as specififed by user */ + start_addr = priv->plat->start_phy_addr; + + for (addr = start_addr; addr < PHY_MAX_ADDR; addr++) { #ifdef TC956X int phy_reg_read; @@ -534,10 +697,10 @@ int tc956xmac_mdio_register(struct net_device *ndev) if (phy_reg_read != -EBUSY && phy_reg_read != -ENODEV) { if (phy_reg_read != 0x0000 && phy_reg_read != 0xffff) { - if (priv->plat->c45_needed == true) + if (priv->plat->c45_needed == true) NMSGPR_ALERT(priv->device, "TC956X: [1] Phy detected C45 at ID/ADDR %d\n", addr); - else + else NMSGPR_ALERT(priv->device, "TC956X: [1] Phy detected C22 at ID/ADDR %d\n", addr); #else @@ -574,22 +737,29 @@ int tc956xmac_mdio_register(struct net_device *ndev) } } else { NMSGPR_ALERT(priv->device, "TC956X: Error reading the phy register"\ - " MII_BMSR for phy ID/ADDR %d\n", addr); + " MII_BMSR for phy ID/ADDR %d\n", addr); } #endif } /* If C22 PHY is not found, probe for C45 based PHY*/ if (!found) { - for (addr = 0; addr < PHY_MAX_ADDR; addr++) { + for (addr = start_addr; addr < PHY_MAX_ADDR; addr++) { #ifdef TC956X int phy_reg_read1, phy_reg_read2, phy_id; /* For C45 based PHYs, check for PHY ID to detect PHY */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 3, 0)) phy_reg_read1 = tc956xmac_xgmac2_mdio_read(new_bus, addr, ((PHY_CL45_PHYID1_REG) | MII_ADDR_C45)); phy_reg_read2 = tc956xmac_xgmac2_mdio_read(new_bus, addr, ((PHY_CL45_PHYID2_REG) | MII_ADDR_C45)); +#else + phy_reg_read1 = tc956xmac_xgmac2_mdio_read_c45(new_bus, addr, + PHY_CL45_PHYID1_MMD_BANK, PHY_CL45_PHYID1_ADDR); + phy_reg_read2 = tc956xmac_xgmac2_mdio_read_c45(new_bus, addr, + PHY_CL45_PHYID2_MMD_BANK, PHY_CL45_PHYID2_ADDR); +#endif if (phy_reg_read1 != -EBUSY && phy_reg_read2 != -EBUSY) { phy_id = ((phy_reg_read1 << 16) | phy_reg_read2); diff --git a/tc956xmac_ptp.c b/tc956xmac_ptp.c index 725be8e81d42..69d90964e721 100644 --- a/tc956xmac_ptp.c +++ b/tc956xmac_ptp.c @@ -30,12 +30,14 @@ * * 15 Mar 2021 : Base lined * VERSION : 01-00 + * + * 26 Dec 2023 : 1. Kernel 6.6 Porting changes + * VERSION : 01-03-59 */ #include "tc956xmac.h" #include "tc956xmac_ptp.h" -#ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE /** * tc956xmac_adjust_freq * @@ -44,12 +46,19 @@ * * Description: this function will adjust the frequency of hardware clock. */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0)) static int tc956xmac_adjust_freq(struct ptp_clock_info *ptp, s32 ppb) +#else +static int tc956xmac_adjust_freq(struct ptp_clock_info *ptp, long scaled_ppm) +#endif { +#ifdef TC956X_SRIOV_PF struct tc956xmac_priv *priv = container_of(ptp, struct tc956xmac_priv, ptp_clock_ops); unsigned long flags; - u32 diff, addend; + u32 addend; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0)) + u32 diff; int neg_adj = 0; u64 adj; @@ -63,12 +72,17 @@ static int tc956xmac_adjust_freq(struct ptp_clock_info *ptp, s32 ppb) adj *= ppb; diff = div_u64(adj, 1000000000ULL); addend = neg_adj ? (addend - diff) : (addend + diff); - +#else + addend = adjust_by_scaled_ppm(priv->default_addend, scaled_ppm); +#endif spin_lock_irqsave(&priv->ptp_lock, flags); tc956xmac_config_addend(priv, priv->ptpaddr, addend); spin_unlock_irqrestore(&priv->ptp_lock, flags); return 0; +#else + return -ENOTSUPP; +#endif } /** @@ -81,6 +95,7 @@ static int tc956xmac_adjust_freq(struct ptp_clock_info *ptp, s32 ppb) */ static int tc956xmac_adjust_time(struct ptp_clock_info *ptp, s64 delta) { +#ifdef TC956X_SRIOV_PF struct tc956xmac_priv *priv = container_of(ptp, struct tc956xmac_priv, ptp_clock_ops); unsigned long flags; @@ -105,6 +120,9 @@ static int tc956xmac_adjust_time(struct ptp_clock_info *ptp, s64 delta) spin_unlock_irqrestore(&priv->ptp_lock, flags); return 0; +#else + return -ENOTSUPP; +#endif } /** @@ -144,6 +162,7 @@ static int tc956xmac_get_time(struct ptp_clock_info *ptp, struct timespec64 *ts) static int tc956xmac_set_time(struct ptp_clock_info *ptp, const struct timespec64 *ts) { +#ifdef TC956X_SRIOV_PF struct tc956xmac_priv *priv = container_of(ptp, struct tc956xmac_priv, ptp_clock_ops); unsigned long flags; @@ -153,15 +172,21 @@ static int tc956xmac_set_time(struct ptp_clock_info *ptp, spin_unlock_irqrestore(&priv->ptp_lock, flags); return 0; +#else + return -ENOTSUPP; +#endif } +#ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE static int tc956xmac_enable(struct ptp_clock_info *ptp, struct ptp_clock_request *rq, int on) { + int ret = -EOPNOTSUPP; + +#ifdef TC956X_SRIOV_PF struct tc956xmac_priv *priv = container_of(ptp, struct tc956xmac_priv, ptp_clock_ops); struct tc956xmac_pps_cfg *cfg; - int ret = -EOPNOTSUPP; unsigned long flags; switch (rq->type) { @@ -187,7 +212,7 @@ static int tc956xmac_enable(struct ptp_clock_info *ptp, default: break; } - +#endif return ret; } #endif /* TC956X_UNSUPPORTED_UNTESTED_FEATURE */ @@ -195,18 +220,26 @@ static int tc956xmac_enable(struct ptp_clock_info *ptp, /* structure describing a PTP hardware clock */ static struct ptp_clock_info tc956xmac_ptp_clock_ops = { .owner = THIS_MODULE, +#ifdef TC956X_SRIOV_PF .name = "tc956xmac ptp", +#else + .name = "tc956xmac vf ptp", +#endif .max_adj = 62500000, .n_alarm = 0, .n_ext_ts = 0, .n_per_out = 0, /* will be overwritten in tc956xmac_ptp_register */ .n_pins = 0, .pps = 0, -#ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0)) .adjfreq = tc956xmac_adjust_freq, +#else + .adjfine = tc956xmac_adjust_freq, +#endif .adjtime = tc956xmac_adjust_time, .gettime64 = tc956xmac_get_time, .settime64 = tc956xmac_set_time, +#ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE .enable = tc956xmac_enable, #endif /* TC956X_UNSUPPORTED_UNTESTED_FEATURE */ }; @@ -229,9 +262,9 @@ void tc956xmac_ptp_register(struct tc956xmac_priv *priv) if (priv->plat->ptp_max_adj) tc956xmac_ptp_clock_ops.max_adj = priv->plat->ptp_max_adj; - +#ifdef TC956X_SRIOV_PF tc956xmac_ptp_clock_ops.n_per_out = priv->dma_cap.pps_out_num; - +#endif spin_lock_init(&priv->ptp_lock); priv->ptp_clock_ops = tc956xmac_ptp_clock_ops; diff --git a/tc956xmac_ptp.h b/tc956xmac_ptp.h index 8696df02aacf..d82fda5fece2 100644 --- a/tc956xmac_ptp.h +++ b/tc956xmac_ptp.h @@ -51,10 +51,10 @@ #define PTP_STSUR 0x10 /* System Time – Seconds Update Reg */ #define PTP_STNSUR 0x14 /* System Time – Nanoseconds Update Reg */ #define PTP_TAR 0x18 /* Timestamp Addend Reg */ -#ifdef TC956X -#define PTP_TS_STATUS 0x20 /* Timestamp status Reg */ -#endif +#define PTP_TS_STATUS 0x20 /* Timestamp status Reg */ +#define PTP_ATS_NSEC 0x48 /* MAC_Auxiliary_Timestamp_Seconds */ +#define PTP_ATS_SEC 0x4C /* MAC_Auxiliary_Timestamp_Nanoseconds */ #define PTP_STNSUR_ADDSUB_SHIFT 31 #define PTP_DIGITAL_ROLLOVER_MODE 0x3B9ACA00 /* 10e9-1 ns */ diff --git a/tc956xmac_selftests.c b/tc956xmac_selftests.c index 73cb065123fd..db62cdc8f4b3 100644 --- a/tc956xmac_selftests.c +++ b/tc956xmac_selftests.c @@ -58,6 +58,7 @@ struct tc956xmachdr { #define TC956XMAC_LB_TIMEOUT msecs_to_jiffies(200) #define TC956XMAC_PTP_TIMEOUT msecs_to_jiffies(2000) #define MMC_COUNTER_INITIAL_VALUE 0 +/*#define SELFTEST_NOT_SUPPORTED*/ struct tc956xmac_packet_attrs { int vlan; @@ -244,8 +245,6 @@ static struct sk_buff *tc956xmac_test_get_udp_skb(struct tc956xmac_priv *priv, return skb; } - - struct tc956xmac_test_priv { struct tc956xmac_packet_attrs *packet; struct packet_type pt; @@ -358,6 +357,7 @@ static int __tc956xmac_test_loopback(struct tc956xmac_priv *priv, goto cleanup; } + attr->queue_mapping = HOST_BEST_EFF_CH; ret = dev_direct_xmit(skb, attr->queue_mapping); if (ret) goto cleanup; @@ -438,7 +438,66 @@ static int tc956xmac_test_mmc(struct tc956xmac_priv *priv) return 0; } +#ifdef SELFTEST_NOT_SUPPORTED +static int tc956xmac_test_eee(struct tc956xmac_priv *priv) +{ + struct tc956xmac_extra_stats *initial, *final; + int retries = 10; + int ret; + if (!priv->dma_cap.eee || !priv->eee_active) + return -EOPNOTSUPP; + + initial = kzalloc(sizeof(*initial), GFP_KERNEL); + if (!initial) + return -ENOMEM; + + final = kzalloc(sizeof(*final), GFP_KERNEL); + if (!final) { + ret = -ENOMEM; + goto out_free_initial; + } + + memcpy(initial, &priv->xstats, sizeof(*initial)); + + ret = tc956xmac_test_mac_loopback(priv); + if (ret) + goto out_free_final; + + /* We have no traffic in the line so, sooner or later it will go LPI */ + while (--retries) { + memcpy(final, &priv->xstats, sizeof(*final)); + + if (final->irq_tx_path_in_lpi_mode_n > + initial->irq_tx_path_in_lpi_mode_n) + break; + msleep(100); + } + + if (!retries) { + ret = -ETIMEDOUT; + goto out_free_final; + } + + if (final->irq_tx_path_in_lpi_mode_n <= + initial->irq_tx_path_in_lpi_mode_n) { + ret = -EINVAL; + goto out_free_final; + } + + if (final->irq_tx_path_exit_lpi_mode_n <= + initial->irq_tx_path_exit_lpi_mode_n) { + ret = -EINVAL; + goto out_free_final; + } + +out_free_final: + kfree(final); +out_free_initial: + kfree(initial); + return ret; +} +#endif static int tc956xmac_filter_check(struct tc956xmac_priv *priv) { @@ -668,7 +727,114 @@ static int tc956xmac_test_ucfilt(struct tc956xmac_priv *priv) return ret; } +#ifdef SELFTEST_NOT_SUPPORTED +static int tc956xmac_test_flowctrl_validate(struct sk_buff *skb, + struct net_device *ndev, + struct packet_type *pt, + struct net_device *orig_ndev) +{ + struct tc956xmac_test_priv *tpriv = pt->af_packet_priv; + struct ethhdr *ehdr; + ehdr = (struct ethhdr *)skb_mac_header(skb); + if (!ether_addr_equal_unaligned(ehdr->h_source, orig_ndev->dev_addr)) + goto out; + if (ehdr->h_proto != htons(ETH_P_PAUSE)) + goto out; + + tpriv->ok = true; + complete(&tpriv->comp); +out: + kfree_skb(skb); + return 0; +} + +static int tc956xmac_test_flowctrl(struct tc956xmac_priv *priv) +{ + unsigned char paddr[ETH_ALEN] = {0x01, 0x80, 0xC2, 0x00, 0x00, 0x01}; + struct phy_device *phydev = priv->dev->phydev; + u32 rx_cnt = priv->plat->rx_queues_to_use; + struct tc956xmac_test_priv *tpriv; + unsigned int pkt_count; + int i, ret = 0; + + if (!phydev || (!phydev->pause && !phydev->asym_pause)) + return -EOPNOTSUPP; + + tpriv = kzalloc(sizeof(*tpriv), GFP_KERNEL); + if (!tpriv) + return -ENOMEM; + + tpriv->ok = false; + init_completion(&tpriv->comp); + tpriv->pt.type = htons(ETH_P_PAUSE); + tpriv->pt.func = tc956xmac_test_flowctrl_validate; + tpriv->pt.dev = priv->dev; + tpriv->pt.af_packet_priv = tpriv; + dev_add_pack(&tpriv->pt); + + /* Compute minimum number of packets to make FIFO full */ + pkt_count = priv->plat->rx_fifo_size; + if (!pkt_count) + pkt_count = priv->dma_cap.rx_fifo_size; + pkt_count /= 1400; + pkt_count *= 2; + + for (i = 0; i < rx_cnt; i++) + tc956xmac_stop_rx(priv, priv->ioaddr, i); + + ret = dev_set_promiscuity(priv->dev, 1); + if (ret) + goto cleanup; + + ret = dev_mc_add(priv->dev, paddr); + if (ret) + goto cleanup; + + for (i = 0; i < pkt_count; i++) { + struct tc956xmac_packet_attrs attr = { }; + + attr.dst = priv->dev->dev_addr; + attr.dont_wait = true; + attr.size = 1400; + + ret = __tc956xmac_test_loopback(priv, &attr); + if (ret) + goto cleanup; + if (tpriv->ok) + break; + } + + /* Wait for some time in case RX Watchdog is enabled */ + msleep(200); + + for (i = 0; i < rx_cnt; i++) { + struct tc956xmac_channel *ch = &priv->channel[i]; + u32 tail; + + tail = priv->rx_queue[i].dma_rx_phy + + (DMA_RX_SIZE * sizeof(struct dma_desc)); + + tc956xmac_set_rx_tail_ptr(priv, priv->ioaddr, tail, i); + tc956xmac_start_rx(priv, priv->ioaddr, i); + + local_bh_disable(); + napi_reschedule(&ch->rx_napi); + local_bh_enable(); + } + + wait_for_completion_timeout(&tpriv->comp, TC956XMAC_LB_TIMEOUT); + ret = tpriv->ok ? 0 : -ETIMEDOUT; + +cleanup: + dev_mc_del(priv->dev, paddr); + dev_set_promiscuity(priv->dev, -1); + dev_remove_pack(&tpriv->pt); + kfree(tpriv); + return ret; +} + +#endif static int tc956xmac_test_vlan_validate(struct sk_buff *skb, struct net_device *ndev, @@ -774,7 +940,7 @@ static int __tc956xmac_test_vlanfilt(struct tc956xmac_priv *priv) goto vlan_del; } - ret = dev_direct_xmit(skb, 0); + ret = dev_direct_xmit(skb, HOST_BEST_EFF_CH); if (ret) goto vlan_del; @@ -868,7 +1034,7 @@ static int __tc956xmac_test_dvlanfilt(struct tc956xmac_priv *priv) goto vlan_del; } - ret = dev_direct_xmit(skb, 0); + ret = dev_direct_xmit(skb, HOST_BEST_EFF_CH); if (ret) goto vlan_del; @@ -916,7 +1082,158 @@ static int tc956xmac_test_dvlanfilt_perfect(struct tc956xmac_priv *priv) return ret; } +#ifdef TC956X_FRP_ENABLE +static int tc956xmac_test_rxp(struct tc956xmac_priv *priv) +{ + unsigned char addr[ETH_ALEN] = {0xde, 0xad, 0xbe, 0xef, 0x00, 0x00}; + struct tc_cls_u32_offload cls_u32 = { }; + struct tc956xmac_packet_attrs attr = { }; + struct tc_action **actions, *act; + struct tc_u32_sel *sel; + struct tcf_exts *exts; + int ret, i, nk = 1; + if (!tc_can_offload(priv->dev)) + return -EOPNOTSUPP; + if (!priv->dma_cap.frpsel) + return -EOPNOTSUPP; + + sel = kzalloc(sizeof(*sel) + nk * sizeof(struct tc_u32_key), GFP_KERNEL); + if (!sel) + return -ENOMEM; + + exts = kzalloc(sizeof(*exts), GFP_KERNEL); + if (!exts) { + ret = -ENOMEM; + goto cleanup_sel; + } + + actions = kzalloc(nk * sizeof(*actions), GFP_KERNEL); + if (!actions) { + ret = -ENOMEM; + goto cleanup_exts; + } + + act = kzalloc(nk * sizeof(*act), GFP_KERNEL); + if (!act) { + ret = -ENOMEM; + goto cleanup_actions; + } + + cls_u32.command = TC_CLSU32_NEW_KNODE; + cls_u32.common.chain_index = 0; + cls_u32.common.protocol = htons(ETH_P_ALL); + cls_u32.knode.exts = exts; + cls_u32.knode.sel = sel; + cls_u32.knode.handle = 0x123; + + exts->nr_actions = nk; + exts->actions = actions; + for (i = 0; i < nk; i++) { + struct tcf_gact *gact = to_gact(&act[i]); + + actions[i] = &act[i]; + gact->tcf_action = TC_ACT_SHOT; + } + + sel->nkeys = nk; + sel->offshift = 0; + sel->keys[0].off = 6; + sel->keys[0].val = htonl(0xdeadbeef); + sel->keys[0].mask = ~0x0; + + ret = tc956xmac_tc_setup_cls_u32(priv, &cls_u32); + if (ret) + goto cleanup_act; + + attr.dst = priv->dev->dev_addr; + attr.src = addr; + + ret = __tc956xmac_test_loopback(priv, &attr); + ret = ret ? 0 : -EINVAL; /* Shall NOT receive packet */ + + cls_u32.command = TC_CLSU32_DELETE_KNODE; + tc956xmac_tc_setup_cls_u32(priv, &cls_u32); + +cleanup_act: + kfree(act); +cleanup_actions: + kfree(actions); +cleanup_exts: + kfree(exts); +cleanup_sel: + kfree(sel); + return ret; +} +#endif + +static int tc956xmac_test_reg_sai(struct tc956xmac_priv *priv) +{ + unsigned char src[ETH_ALEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + struct tc956xmac_packet_attrs attr = { }; + int ret; +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + unsigned long flags; +#endif + + if (!priv->dma_cap.vlins) + return -EOPNOTSUPP; + + attr.remove_sa = true; + attr.sarc = true; + attr.src = src; + attr.dst = priv->dev->dev_addr; +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_lock_irqsave(&priv->spn_lock.mac_filter, flags); +#endif + + tc956xmac_set_umac_addr(priv, priv->hw, priv->dev->dev_addr, 0, PF_DRIVER); + +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_unlock_irqrestore(&priv->spn_lock.mac_filter, flags); +#endif + + if (tc956xmac_sarc_configure(priv, priv->ioaddr, 0x2)) + return -EOPNOTSUPP; + + ret = __tc956xmac_test_loopback(priv, &attr); + + tc956xmac_sarc_configure(priv, priv->ioaddr, 0x0); + return ret; +} + +static int tc956xmac_test_reg_sar(struct tc956xmac_priv *priv) +{ + unsigned char src[ETH_ALEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + struct tc956xmac_packet_attrs attr = { }; + int ret; +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + unsigned long flags; +#endif + if (!priv->dma_cap.vlins) + return -EOPNOTSUPP; + + attr.sarc = true; + attr.src = src; + attr.dst = priv->dev->dev_addr; +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_lock_irqsave(&priv->spn_lock.mac_filter, flags); +#endif + + tc956xmac_set_umac_addr(priv, priv->hw, priv->dev->dev_addr, 0, PF_DRIVER); + +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_unlock_irqrestore(&priv->spn_lock.mac_filter, flags); +#endif + + if (tc956xmac_sarc_configure(priv, priv->ioaddr, 0x3)) + return -EOPNOTSUPP; + + ret = __tc956xmac_test_loopback(priv, &attr); + + tc956xmac_sarc_configure(priv, priv->ioaddr, 0x0); + return ret; +} static int tc956xmac_test_vlanoff_common(struct tc956xmac_priv *priv, bool svlan) @@ -963,7 +1280,7 @@ static int tc956xmac_test_vlanoff_common(struct tc956xmac_priv *priv, bool svlan __vlan_hwaccel_put_tag(skb, htons(proto), tpriv->vlan_id); skb->protocol = htons(proto); - ret = dev_direct_xmit(skb, 0); + ret = dev_direct_xmit(skb, HOST_BEST_EFF_CH); if (ret) goto vlan_del; @@ -1001,8 +1318,139 @@ static int tc956xmac_test_jumbo(struct tc956xmac_priv *priv) return __tc956xmac_test_jumbo(priv, 0); } +#ifdef SELFTEST_NOT_SUPPORTED +static int tc956xmac_test_tbs(struct tc956xmac_priv *priv) +{ +#define TC956XMAC_TBS_LT_OFFSET (500 * 1000 * 1000) /* 500 ms*/ + struct tc956xmac_packet_attrs attr = { }; + struct tc_etf_qopt_offload qopt; + u64 start_time, curr_time = 0; + unsigned long flags; + int ret, i; + if (!priv->hwts_tx_en) + return -EOPNOTSUPP; + + /* Find first TBS enabled Queue, if any */ + for (i = 0; i < priv->plat->tx_queues_to_use; i++) + if (priv->tx_queue[i].tbs & TC956XMAC_TBS_AVAIL) + break; + + if (i >= priv->plat->tx_queues_to_use) + return -EOPNOTSUPP; + + qopt.enable = true; + qopt.queue = i; + + ret = tc956xmac_tc_setup_etf(priv, &qopt); + if (ret) + return ret; + + spin_lock_irqsave(&priv->ptp_lock, flags); + tc956xmac_get_systime(priv, priv->ptpaddr, &curr_time); + spin_unlock_irqrestore(&priv->ptp_lock, flags); + + if (!curr_time) { + ret = -EOPNOTSUPP; + goto fail_disable; + } + + start_time = curr_time; + curr_time += TC956XMAC_TBS_LT_OFFSET; + + attr.dst = priv->dev->dev_addr; + attr.timestamp = curr_time; + attr.timeout = nsecs_to_jiffies(2 * TC956XMAC_TBS_LT_OFFSET); + attr.queue_mapping = i; + + ret = __tc956xmac_test_loopback(priv, &attr); + if (ret) + goto fail_disable; + + /* Check if expected time has elapsed */ + spin_lock_irqsave(&priv->ptp_lock, flags); + tc956xmac_get_systime(priv, priv->ptpaddr, &curr_time); + spin_unlock_irqrestore(&priv->ptp_lock, flags); + + if ((curr_time - start_time) < TC956XMAC_TBS_LT_OFFSET) + ret = -EINVAL; + +fail_disable: + qopt.enable = false; + tc956xmac_tc_setup_etf(priv, &qopt); + return ret; +} + +static int tc956xmac_test_ptp_validate(struct sk_buff *skb, + struct net_device *ndev, + struct packet_type *pt, + struct net_device *orig_ndev) +{ + unsigned char dst[ETH_ALEN] = { 0x01, 0x1b, 0x19, 0x00, 0x00, 0x00 }; + struct tc956xmac_test_priv *tpriv = pt->af_packet_priv; + struct ethhdr *ehdr; + + ehdr = (struct ethhdr *)skb_mac_header(skb); + if (!ether_addr_equal(ehdr->h_source, orig_ndev->dev_addr)) + goto out; + if (!ether_addr_equal(ehdr->h_dest, dst)) + goto out; + + tpriv->ok = true; + complete(&tpriv->comp); +out: + kfree_skb(skb); + return 0; +} + +static int tc956xmac_test_ptp_offload(struct tc956xmac_priv *priv) +{ +#define TC956XMAC_PTP_CNT 10 + struct tc956xmac_test_priv *tpriv; + int ret, i; + + if (!priv->dma_cap.ptoen) + return -EOPNOTSUPP; + if (!priv->hwts_tx_en) + return -EOPNOTSUPP; + + tpriv = kzalloc(sizeof(*tpriv), GFP_KERNEL); + if (!tpriv) + return -ENOMEM; + + tpriv->ok = false; + init_completion(&tpriv->comp); + + tpriv->pt.type = htons(ETH_P_1588); + tpriv->pt.func = tc956xmac_test_ptp_validate; + tpriv->pt.dev = priv->dev; + tpriv->pt.af_packet_priv = tpriv; + dev_add_pack(&tpriv->pt); + + ret = dev_set_promiscuity(priv->dev, 1); + if (ret) + goto cleanup; + + ret = tc956xmac_set_ptp_offload(priv, priv->ioaddr, true); + if (ret) + goto cleanup; + + for (i = 0; i < TC956XMAC_PTP_CNT; i++) { + wait_for_completion_timeout(&tpriv->comp, TC956XMAC_PTP_TIMEOUT); + ret = tpriv->ok ? 0 : -ETIMEDOUT; + if (ret) + goto cleanup; + } + +cleanup: + tc956xmac_set_ptp_offload(priv, priv->ioaddr, false); + dev_set_promiscuity(priv->dev, -1); + dev_remove_pack(&tpriv->pt); + kfree(tpriv); + return ret; +} +#endif #define TC956XMAC_LOOPBACK_NONE 0 #define TC956XMAC_LOOPBACK_MAC 1 @@ -1025,12 +1473,15 @@ static const struct tc956xmac_test { .name = "MMC Counters ", .lb = TC956XMAC_LOOPBACK_PHY, .fn = tc956xmac_test_mmc, - },/* { - *.name = "EEE ", //NOt supported - *.lb = TC956XMAC_LOOPBACK_PHY, - *.fn = tc956xmac_test_eee, - }, */ - { + }, +#ifdef SELFTEST_NOT_SUPPORTED + { + .name = "EEE ", + .lb = TC956XMAC_LOOPBACK_PHY, + .fn = tc956xmac_test_eee, + }, +#endif + { .name = "Hash Filter MC ", .lb = TC956XMAC_LOOPBACK_PHY, .fn = tc956xmac_test_hfilt, @@ -1046,16 +1497,14 @@ static const struct tc956xmac_test { .name = "UC Filter ", .lb = TC956XMAC_LOOPBACK_PHY, .fn = tc956xmac_test_ucfilt, - }, /* { - * .name = "Flow Control ", NOt Validated correctly - * .lb = TC956XMAC_LOOPBACK_PHY, - * .fn = tc956xmac_test_flowctrl, - * }, { - * .name = "RSS ", not supported - * .lb = TC956XMAC_LOOPBACK_PHY, - * .fn = tc956xmac_test_rss, - * }, - */ + }, +#ifdef SELFTEST_NOT_SUPPORTED + { + .name = "Flow Control ", + .lb = TC956XMAC_LOOPBACK_PHY, + .fn = tc956xmac_test_flowctrl, + }, +#endif { .name = "VLAN Filtering ", .lb = TC956XMAC_LOOPBACK_PHY, @@ -1072,87 +1521,42 @@ static const struct tc956xmac_test { .name = "Double VLAN Filter (perf) ", .lb = TC956XMAC_LOOPBACK_PHY, .fn = tc956xmac_test_dvlanfilt_perfect, - }, /* { - * .name = "Flexible RX Parser ", //Not supported - * .lb = TC956XMAC_LOOPBACK_PHY, - * .fn = tc956xmac_test_rxp, - * }, { - * .name = "SA Insertion (desc) ", //Not validated correctly , This test is covered in IT testing - * .lb = TC956XMAC_LOOPBACK_PHY, - * .fn = tc956xmac_test_desc_sai, - * }, { - * .name = "SA Replacement (desc) ", //Not validated correctly , This test is covered in IT testing - * .lb = TC956XMAC_LOOPBACK_PHY, - * .fn = tc956xmac_test_desc_sar, - * }, { - * .name = "SA Insertion (reg) ", //Not validated correctly , This test is covered in IT testing - * .lb = TC956XMAC_LOOPBACK_PHY, - * .fn = tc956xmac_test_reg_sai, - * }, { - * .name = "SA Replacement (reg) ", //Not validated correctly , This test is covered in IT testing - * .lb = TC956XMAC_LOOPBACK_PHY, - * .fn = tc956xmac_test_reg_sar, - }, */ + }, +#ifdef TC956X_FRP_ENABLE { + .name = "Flexible RX Parser ", + .lb = TC956XMAC_LOOPBACK_PHY, + .fn = tc956xmac_test_rxp, + }, +#endif + { + .name = "SA Insertion (reg) ", + .lb = TC956XMAC_LOOPBACK_PHY, + .fn = tc956xmac_test_reg_sai, + }, { + .name = "SA Replacement (reg) ", + .lb = TC956XMAC_LOOPBACK_PHY, + .fn = tc956xmac_test_reg_sar, + }, { .name = "VLAN TX Insertion ", .lb = TC956XMAC_LOOPBACK_PHY, .fn = tc956xmac_test_vlanoff, - }, /* { - * .name = "SVLAN TX Insertion ", //Not supported - * .lb = TC956XMAC_LOOPBACK_PHY, - * .fn = tc956xmac_test_svlanoff, - * }, { - * .name = "L3 DA Filtering ", //Not supported - * .lb = TC956XMAC_LOOPBACK_PHY, - * .fn = tc956xmac_test_l3filt_da, - * }, { - * .name = "L3 SA Filtering ", //Not supported - * .lb = TC956XMAC_LOOPBACK_PHY, - * .fn = tc956xmac_test_l3filt_sa, - * }, { - * .name = "L4 DA TCP Filtering ", //Not supported - * .lb = TC956XMAC_LOOPBACK_PHY, - * .fn = tc956xmac_test_l4filt_da_tcp, - * }, { - * .name = "L4 SA TCP Filtering ", //Not supported - * .lb = TC956XMAC_LOOPBACK_PHY, - * .fn = tc956xmac_test_l4filt_sa_tcp, - * }, { - * .name = "L4 DA UDP Filtering ", //Not supported - * .lb = TC956XMAC_LOOPBACK_PHY, - * .fn = tc956xmac_test_l4filt_da_udp, - * }, { - * .name = "L4 SA UDP Filtering ", //Not supported - * .lb = TC956XMAC_LOOPBACK_PHY, - * .fn = tc956xmac_test_l4filt_sa_udp, - * }, { - * .name = "ARP Offload ", //Not supported - * .lb = TC956XMAC_LOOPBACK_PHY, - * .fn = tc956xmac_test_arpoffload, - * }, - */ - { + }, { .name = "Jumbo Frame ", .lb = TC956XMAC_LOOPBACK_PHY, .fn = tc956xmac_test_jumbo, - }, /* { - *.name = "Multichannel Jumbo ", //Not supprted - *.lb = TC956XMAC_LOOPBACK_PHY, - *.fn = tc956xmac_test_mjumbo, - *}, { - *.name = "Split Header ", //not supoorted - *.lb = TC956XMAC_LOOPBACK_PHY, - *.fn = tc956xmac_test_sph, - *}, { - *.name = "TBS (ETF Scheduler) ", //Validation not done correctly, Tested During IT - *.lb = TC956XMAC_LOOPBACK_PHY, - *.fn = tc956xmac_test_tbs, - *}, { - *.name = "PTP Offload ", //Validation not done correctly - *.lb = TC956XMAC_LOOPBACK_PHY, - *.fn = tc956xmac_test_ptp_offload, - *}, - */ + }, +#ifdef SELFTEST_NOT_SUPPORTED + { + .name = "TBS (ETF Scheduler) ", + .lb = TC956XMAC_LOOPBACK_PHY, + .fn = tc956xmac_test_tbs, + }, { + .name = "PTP Offload ", + .lb = TC956XMAC_LOOPBACK_PHY, + .fn = tc956xmac_test_ptp_offload, + }, +#endif }; void tc956xmac_selftest_run(struct net_device *dev, diff --git a/tc956xmac_tc.c b/tc956xmac_tc.c index 32b209d1dff4..71fccf7e77ca 100644 --- a/tc956xmac_tc.c +++ b/tc956xmac_tc.c @@ -4,7 +4,7 @@ * tc956xmac_tc.c * * Copyright (C) 2018 Synopsys, Inc. and/or its affiliates. - * Copyright (C) 2021 Toshiba Electronic Devices & Storage Corporation + * Copyright (C) 2023 Toshiba Electronic Devices & Storage Corporation * * This file has been derived from the STMicro and Synopsys Linux driver, * and developed or modified for TC956X. @@ -30,15 +30,25 @@ * * 15 Mar 2021 : Base lined * VERSION : 01-00 + * 10 Nov 2023 : 1. Kernel 6.1 Porting changes + * VERSION : 01-02-59 + * + * 26 Dec 2023 : 1. Kernel 6.6 Porting changes + * : 2. Added the support for TC commands taprio and flower + * VERSION : 01-03-59 */ #include #include #include "common.h" #include "tc956xmac.h" +#include "dwxgmac2.h" -#ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE +#ifdef TC956X_SRIOV_PF static void tc_fill_all_pass_entry(struct tc956xmac_tc_entry *entry) +#elif defined TC956X_SRIOV_VF +static void tc_fill_all_pass_entry(struct tc956xmac_tc_entry *entry, struct tc956xmac_priv *priv) +#endif { memset(entry, 0, sizeof(*entry)); entry->in_use = true; @@ -49,7 +59,11 @@ static void tc_fill_all_pass_entry(struct tc956xmac_tc_entry *entry) entry->val.match_data = 0x0; entry->val.match_en = 0x0; entry->val.af = 1; - entry->val.dma_ch_no = 0x0; +#ifdef TC956X_SRIOV_PF + entry->val.dma_ch_no = TC956X_TC_DEFAULT_DMA_CH; +#elif defined TC956X_SRIOV_VF + entry->val.dma_ch_no = (1 << priv->plat->best_effort_ch_no); +#endif } static struct tc956xmac_tc_entry *tc_find_entry(struct tc956xmac_priv *priv, @@ -109,7 +123,7 @@ static int tc_fill_actions(struct tc956xmac_tc_entry *entry, } /* Unsupported */ - return -EINVAL; + /* return -EINVAL; */ } return 0; @@ -181,7 +195,11 @@ static int tc_fill_entry(struct tc956xmac_priv *priv, entry->val.frame_offset = real_off; entry->prio = prio; } - +#ifdef TC956X_SRIOV_PF + entry->val.dma_ch_no = TC956X_TC_DEFAULT_DMA_CH; +#elif defined TC956X_SRIOV_VF + entry->val.dma_ch_no = (1 << priv->plat->best_effort_ch_no); +#endif ret = tc_fill_actions(entry, frag, cls); if (ret) goto err_unuse; @@ -216,19 +234,39 @@ static int tc_config_knode(struct tc956xmac_priv *priv, struct tc_cls_u32_offload *cls) { int ret; + u32 val, i = 0; + void __iomem *ioaddr = priv->hw->pcsr; + struct tc956xmac_rx_parser_cfg *cfg = &priv->plat->rxp_cfg; +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + unsigned long flags; +#endif ret = tc_fill_entry(priv, cls); if (ret) return ret; - +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_lock_irqsave(&priv->spn_lock.frp, flags); +#endif ret = tc956xmac_rxp_config(priv, priv->hw->pcsr, priv->tc_entries, priv->tc_entries_max); if (ret) goto err_unfill; + val = readl(ioaddr + XGMAC_MTL_RXP_CONTROL_STATUS); + cfg->nve = val & XGMAC_NVE; + cfg->npe = val & XGMAC_NVE; + for (i = 0 ; i < cfg->nve ; i++) + memcpy(&cfg->entries[i], &priv->tc_entries[i].val, sizeof(*cfg->entries)); + +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_unlock_irqrestore(&priv->spn_lock.frp, flags); +#endif return 0; err_unfill: +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_unlock_irqrestore(&priv->spn_lock.frp, flags); +#endif tc_unfill_entry(priv, cls); return ret; } @@ -237,12 +275,22 @@ static int tc_delete_knode(struct tc956xmac_priv *priv, struct tc_cls_u32_offload *cls) { int ret; - +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + unsigned long flags; +#endif /* Set entry and fragments as not used */ tc_unfill_entry(priv, cls); +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_lock_irqsave(&priv->spn_lock.frp, flags); +#endif + ret = tc956xmac_rxp_config(priv, priv->hw->pcsr, priv->tc_entries, priv->tc_entries_max); + +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_unlock_irqrestore(&priv->spn_lock.frp, flags); +#endif if (ret) return ret; @@ -252,10 +300,16 @@ static int tc_delete_knode(struct tc956xmac_priv *priv, static int tc_setup_cls_u32(struct tc956xmac_priv *priv, struct tc_cls_u32_offload *cls) { +#ifdef TC956X_SRIOV_VF + /* This is feature not supported from VF as this will impact + * the entire MAC + * */ + return -EOPNOTSUPP; +#endif switch (cls->command) { case TC_CLSU32_REPLACE_KNODE: tc_unfill_entry(priv, cls); - /* Fall through */ + fallthrough; case TC_CLSU32_NEW_KNODE: return tc_config_knode(priv, cls); case TC_CLSU32_DELETE_KNODE: @@ -264,13 +318,36 @@ static int tc_setup_cls_u32(struct tc956xmac_priv *priv, return -EOPNOTSUPP; } } -#endif /* TC956X_UNSUPPORTED_UNTESTED_FEATURE */ + +static int tc_rfs_init(struct tc956xmac_priv *priv) +{ + int i; + + priv->rfs_entries_max[TC956X_RFS_T_VLAN] = 8; + priv->rfs_entries_max[TC956X_RFS_T_LLDP] = 1; + priv->rfs_entries_max[TC956X_RFS_T_1588] = 1; + + for (i = 0; i < TC956X_RFS_T_MAX; i++) + priv->rfs_entries_total += priv->rfs_entries_max[i]; + + priv->rfs_entries = devm_kcalloc(priv->device, + priv->rfs_entries_total, + sizeof(*priv->rfs_entries), + GFP_KERNEL); + if (!priv->rfs_entries) + return -ENOMEM; + + dev_info(priv->device, "Enabled RFS Flow TC (entries=%d)\n", + priv->rfs_entries_total); + + return 0; +} static int tc_init(struct tc956xmac_priv *priv, void *data) { struct dma_features *dma_cap = &priv->dma_cap; unsigned int count; - int i; + int ret, i; if (dma_cap->l3l4fnum) { priv->flow_entries_max = dma_cap->l3l4fnum; @@ -288,37 +365,29 @@ static int tc_init(struct tc956xmac_priv *priv, void *data) priv->flow_entries_max); } + ret = tc_rfs_init(priv); + if (ret) + return -ENOMEM; + /* Fail silently as we can still use remaining features, e.g. CBS */ if (!dma_cap->frpsel) return 0; switch (dma_cap->frpbs) { case 0x0: - priv->tc_off_max = 64; + priv->tc_off_max = SIXTY_FOUR; break; case 0x1: - priv->tc_off_max = 128; + priv->tc_off_max = ONE_TWENTY_EIGHT; break; case 0x2: - priv->tc_off_max = 256; + priv->tc_off_max = TWO_FIFTY_SIX; break; default: return -EINVAL; } - switch (dma_cap->frpes) { - case 0x0: - count = 64; - break; - case 0x1: - count = 128; - break; - case 0x2: - count = 256; - break; - default: - return -EINVAL; - } + count = dma_cap->frpes; /* Reserve one last filter which lets all pass */ priv->tc_entries_max = count; @@ -327,16 +396,17 @@ static int tc_init(struct tc956xmac_priv *priv, void *data) if (!priv->tc_entries) return -ENOMEM; -#ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE +#ifdef TC956X_SRIOV_PF tc_fill_all_pass_entry(&priv->tc_entries[count - 1]); -#endif /* TC956X_UNSUPPORTED_UNTESTED_FEATURE */ +#elif defined TC956X_SRIOV_VF + tc_fill_all_pass_entry(&priv->tc_entries[count - 1], priv); +#endif dev_info(priv->device, "Enabling HW TC (entries=%d, max_off=%d)\n", priv->tc_entries_max, priv->tc_off_max); return 0; } -#ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE static int tc_setup_cbs(struct tc956xmac_priv *priv, struct tc_cbs_qopt_offload *qopt) { @@ -346,10 +416,18 @@ static int tc_setup_cbs(struct tc956xmac_priv *priv, u32 mode_to_use; u64 value; int ret; - +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + unsigned long flags; +#endif /* Queue 0 is not AVB capable */ if (queue <= 0 || queue >= tx_queues_count) return -EINVAL; +#if defined(TC956X_SRIOV_PF) | defined(TC956X_SRIOV_VF) + /* Only allows if Queue is allocated to PF */ + if (priv->plat->tx_queues_cfg[qopt->queue].mode_to_use == + MTL_QUEUE_DISABLE) + return -EINVAL; +#endif if (!priv->dma_cap.av) return -EOPNOTSUPP; @@ -359,6 +437,8 @@ static int tc_setup_cbs(struct tc956xmac_priv *priv, DBGPR_FUNC(priv->device, "--> %s (mode_to_use != MTL_QUEUE_AVB) mode_to_use %d\n", __func__, mode_to_use); return -EINVAL; } + +#ifndef TC956X if (mode_to_use == MTL_QUEUE_DCB && qopt->enable) { ret = tc956xmac_dma_qmode(priv, priv->ioaddr, queue, MTL_QUEUE_AVB); if (ret) @@ -369,21 +449,46 @@ static int tc_setup_cbs(struct tc956xmac_priv *priv, /* Removed : when called "tc del" code Changing property * such as mode from AVB to DCB and reset register values */ -#ifndef TC956X + ret = tc956xmac_dma_qmode(priv, priv->ioaddr, queue, MTL_QUEUE_DCB); if (ret) return ret; priv->plat->tx_queues_cfg[queue].mode_to_use = MTL_QUEUE_DCB; -#endif + return 0; } - /* TODO : 1. Handle 2.5G,5G,10G Speeds */ - /* 2. IOCTL Output different than TC command */ - /* Port Transmit Rate and Speed Divider */ - ptr = (priv->speed == SPEED_100) ? 4 : 8; - speed_div = (priv->speed == SPEED_100) ? 100000 : 1000000; +#endif + /* Port Transmit Rate and Speed Divider */ + switch (priv->speed) { + case SPEED_10000: + ptr = 32; + speed_div = SPD_DIV_10G; + break; + case SPEED_5000: + ptr = 32; + speed_div = SPD_DIV_5G; + break; + case SPEED_2500: + ptr = 8; + speed_div = SPD_DIV_2_5G; + break; + case SPEED_1000: + ptr = 8; + speed_div = SPD_DIV_1G; + break; + case SPEED_100: + ptr = 4; + speed_div = SPD_DIV_100M; + break; + default: + return -EOPNOTSUPP; + } + +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_lock_irqsave(&priv->spn_lock.cbs, flags); +#endif /* Final adjustments for HW */ value = div_s64(qopt->idleslope * 1024ll * ptr, speed_div); priv->plat->tx_queues_cfg[queue].idle_slope = value & GENMASK(20, 0); @@ -397,15 +502,80 @@ static int tc_setup_cbs(struct tc956xmac_priv *priv, value = qopt->locredit * 1024ll * 8; priv->plat->tx_queues_cfg[queue].low_credit = value & GENMASK(28, 0); +#ifndef TC956X_SRIOV_VF ret = tc956xmac_config_cbs(priv, priv->hw, priv->plat->tx_queues_cfg[queue].send_slope, priv->plat->tx_queues_cfg[queue].idle_slope, priv->plat->tx_queues_cfg[queue].high_credit, priv->plat->tx_queues_cfg[queue].low_credit, queue); - if (ret) - return ret; +#elif (defined TC956X_SRIOV_VF) + ret = tc956xmac_config_cbs(priv, + priv->plat->tx_queues_cfg[queue].send_slope, + priv->plat->tx_queues_cfg[queue].idle_slope, + priv->plat->tx_queues_cfg[queue].high_credit, + priv->plat->tx_queues_cfg[queue].low_credit, + queue); +#endif + if (ret) { +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_unlock_irqrestore(&priv->spn_lock.cbs, flags); +#endif + return ret; + } + + if (priv->speed == SPEED_100) { + priv->cbs_speed100_cfg[queue].send_slope = + priv->plat->tx_queues_cfg[queue].send_slope; + priv->cbs_speed100_cfg[queue].idle_slope = + priv->plat->tx_queues_cfg[queue].idle_slope; + priv->cbs_speed100_cfg[queue].high_credit = + priv->plat->tx_queues_cfg[queue].high_credit; + priv->cbs_speed100_cfg[queue].low_credit = + priv->plat->tx_queues_cfg[queue].low_credit; + } else if (priv->speed == SPEED_1000) { + priv->cbs_speed1000_cfg[queue].send_slope = + priv->plat->tx_queues_cfg[queue].send_slope; + priv->cbs_speed1000_cfg[queue].idle_slope = + priv->plat->tx_queues_cfg[queue].idle_slope; + priv->cbs_speed1000_cfg[queue].high_credit = + priv->plat->tx_queues_cfg[queue].high_credit; + priv->cbs_speed1000_cfg[queue].low_credit = + priv->plat->tx_queues_cfg[queue].low_credit; + } else if (priv->speed == SPEED_10000) { + priv->cbs_speed10000_cfg[queue].send_slope = + priv->plat->tx_queues_cfg[queue].send_slope; + priv->cbs_speed10000_cfg[queue].idle_slope = + priv->plat->tx_queues_cfg[queue].idle_slope; + priv->cbs_speed10000_cfg[queue].high_credit = + priv->plat->tx_queues_cfg[queue].high_credit; + priv->cbs_speed10000_cfg[queue].low_credit = + priv->plat->tx_queues_cfg[queue].low_credit; + } else if (priv->speed == SPEED_2500) { + priv->cbs_speed2500_cfg[queue].send_slope = + priv->plat->tx_queues_cfg[queue].send_slope; + priv->cbs_speed2500_cfg[queue].idle_slope = + priv->plat->tx_queues_cfg[queue].idle_slope; + priv->cbs_speed2500_cfg[queue].high_credit = + priv->plat->tx_queues_cfg[queue].high_credit; + priv->cbs_speed2500_cfg[queue].low_credit = + priv->plat->tx_queues_cfg[queue].low_credit; + } else if (priv->speed == SPEED_5000) { + priv->cbs_speed5000_cfg[queue].send_slope = + priv->plat->tx_queues_cfg[queue].send_slope; + priv->cbs_speed5000_cfg[queue].idle_slope = + priv->plat->tx_queues_cfg[queue].idle_slope; + priv->cbs_speed5000_cfg[queue].high_credit = + priv->plat->tx_queues_cfg[queue].high_credit; + priv->cbs_speed5000_cfg[queue].low_credit = + priv->plat->tx_queues_cfg[queue].low_credit; + } else { + } + +#if defined(TC956X_SRIOV_PF) && defined(TC956X_SRIOV_LOCK) + spin_unlock_irqrestore(&priv->spn_lock.cbs, flags); +#endif dev_info(priv->device, "CBS queue %d: send %d, idle %d, hi %d, lo %d\n", queue, qopt->sendslope, qopt->idleslope, qopt->hicredit, qopt->locredit); @@ -564,6 +734,148 @@ static struct { { .fn = tc_add_ports_flow }, }; +static struct tc956xmac_rfs_entry *tc_find_rfs(struct tc956xmac_priv *priv, + struct flow_cls_offload *cls, + bool get_free) +{ + int i; + + for (i = 0; i < priv->rfs_entries_total; i++) { + struct tc956xmac_rfs_entry *entry = &priv->rfs_entries[i]; + + if (entry->cookie == cls->cookie) + return entry; + if (get_free && entry->in_use == false) + return entry; + } + + return NULL; +} + +#define ETHER_TYPE_FULL_MASK cpu_to_be16(~0) + +static int tc_add_ethtype_flow(struct tc956xmac_priv *priv, + struct flow_cls_offload *cls) +{ + struct tc956xmac_rfs_entry *entry = tc_find_rfs(priv, cls, false); + struct flow_rule *rule = flow_cls_offload_flow_rule(cls); + struct flow_dissector *dissector = rule->match.dissector; + int tc = tc_classid_to_hwtc(priv->dev, cls->classid); + struct flow_match_basic match; + + if (!entry) { + entry = tc_find_rfs(priv, cls, true); + if (!entry) + return -ENOENT; + } + + /* Nothing to do here */ + if (!dissector_uses_key(dissector, FLOW_DISSECTOR_KEY_BASIC)) + return -EINVAL; + + if (tc < 0) { + netdev_err(priv->dev, "Invalid traffic class\n"); + return -EINVAL; + } + + flow_rule_match_basic(rule, &match); + + if (match.mask->n_proto) { + u16 etype = ntohs(match.key->n_proto); + + if (match.mask->n_proto != ETHER_TYPE_FULL_MASK) { + netdev_err(priv->dev, "Only full mask is supported for EthType filter"); + return -EINVAL; + } + switch (etype) { + case ETH_P_LLDP: + if (priv->rfs_entries_cnt[TC956X_RFS_T_LLDP] >= + priv->rfs_entries_max[TC956X_RFS_T_LLDP]) + return -ENOENT; + + entry->type = TC956X_RFS_T_LLDP; + priv->rfs_entries_cnt[TC956X_RFS_T_LLDP]++; + + tc956xmac_rx_queue_routing(priv, priv->hw, + PACKET_DCBCPQ, tc); + break; + case ETH_P_1588: + if (priv->rfs_entries_cnt[TC956X_RFS_T_1588] >= + priv->rfs_entries_max[TC956X_RFS_T_1588]) + return -ENOENT; + + entry->type = TC956X_RFS_T_1588; + priv->rfs_entries_cnt[TC956X_RFS_T_1588]++; + + tc956xmac_rx_queue_routing(priv, priv->hw, + PACKET_PTPQ, tc); + break; + default: + netdev_err(priv->dev, "EthType(0x%x) is not supported", etype); + return -EINVAL; + } + + entry->in_use = true; + entry->cookie = cls->cookie; + entry->tc = tc; + entry->etype = etype; + + return 0; + } + return -EINVAL; +} + +#define VLAN_PRIO_FULL_MASK (0x07) + +static int tc_add_vlan_flow(struct tc956xmac_priv *priv, + struct flow_cls_offload *cls) +{ + struct tc956xmac_rfs_entry *entry = tc_find_rfs(priv, cls, false); + struct flow_rule *rule = flow_cls_offload_flow_rule(cls); + struct flow_dissector *dissector = rule->match.dissector; + int tc = tc_classid_to_hwtc(priv->dev, cls->classid); + struct flow_match_vlan match; + + if (!entry) { + entry = tc_find_rfs(priv, cls, true); + if (!entry) + return -ENOENT; + } + + if (priv->rfs_entries_cnt[TC956X_RFS_T_VLAN] >= + priv->rfs_entries_max[TC956X_RFS_T_VLAN]) + return -ENOENT; + + /* Nothing to do here */ + if (!dissector_uses_key(dissector, FLOW_DISSECTOR_KEY_VLAN)) + return -EINVAL; + + if (tc < 0) { + netdev_err(priv->dev, "Invalid traffic class\n"); + return -EINVAL; + } + + flow_rule_match_vlan(rule, &match); + if (match.mask->vlan_priority) { + u32 prio; + + if (match.mask->vlan_priority != VLAN_PRIO_FULL_MASK) { + netdev_err(priv->dev, "Only full mask is supported for VLAN priority"); + return -EINVAL; + } + + prio = BIT(match.key->vlan_priority); + tc956xmac_rx_queue_prio(priv, priv->hw, prio, tc); + + entry->in_use = true; + entry->cookie = cls->cookie; + entry->tc = tc; + entry->type = TC956X_RFS_T_VLAN; + priv->rfs_entries_cnt[TC956X_RFS_T_VLAN]++; + } + return 0; +} + static int tc_add_flow(struct tc956xmac_priv *priv, struct flow_cls_offload *cls) { @@ -619,6 +931,93 @@ static int tc_del_flow(struct tc956xmac_priv *priv, return ret; } +static int tc_del_ethtype_flow(struct tc956xmac_priv *priv, + struct flow_cls_offload *cls) +{ + struct tc956xmac_rfs_entry *entry = tc_find_rfs(priv, cls, false); + + if (!entry || !entry->in_use || + entry->type < TC956X_RFS_T_LLDP || + entry->type > TC956X_RFS_T_1588) + return -ENOENT; + + switch (entry->etype) { + case ETH_P_LLDP: + tc956xmac_rx_queue_routing(priv, priv->hw, + PACKET_DCBCPQ, 0); + priv->rfs_entries_cnt[TC956X_RFS_T_LLDP]--; + break; + case ETH_P_1588: + tc956xmac_rx_queue_routing(priv, priv->hw, + PACKET_PTPQ, 0); + priv->rfs_entries_cnt[TC956X_RFS_T_1588]--; + break; + default: + netdev_err(priv->dev, "EthType(0x%x) is not supported", + entry->etype); + return -EINVAL; + } + + entry->in_use = false; + entry->cookie = 0; + entry->tc = 0; + entry->etype = 0; + entry->type = 0; + + return 0; +} + +static int tc_del_vlan_flow(struct tc956xmac_priv *priv, + struct flow_cls_offload *cls) +{ + struct tc956xmac_rfs_entry *entry = tc_find_rfs(priv, cls, false); + + if (!entry || !entry->in_use || entry->type != TC956X_RFS_T_VLAN) + return -ENOENT; + + tc956xmac_rx_queue_prio(priv, priv->hw, 0, entry->tc); + + entry->in_use = false; + entry->cookie = 0; + entry->tc = 0; + entry->type = 0; + + priv->rfs_entries_cnt[TC956X_RFS_T_VLAN]--; + + return 0; +} + +static int tc_add_flow_cls(struct tc956xmac_priv *priv, + struct flow_cls_offload *cls) +{ + int ret; + + ret = tc_add_flow(priv, cls); + if (!ret) + return ret; + ret = tc_add_ethtype_flow(priv, cls); + if (!ret) + return ret; + + return tc_add_vlan_flow(priv, cls); +} + +static int tc_del_flow_cls(struct tc956xmac_priv *priv, + struct flow_cls_offload *cls) +{ + int ret; + + ret = tc_del_flow(priv, cls); + if (!ret) + return ret; + + ret = tc_del_ethtype_flow(priv, cls); + if (!ret) + return ret; + + return tc_del_vlan_flow(priv, cls); +} + static int tc_setup_cls(struct tc956xmac_priv *priv, struct flow_cls_offload *cls) { @@ -630,10 +1029,10 @@ static int tc_setup_cls(struct tc956xmac_priv *priv, switch (cls->command) { case FLOW_CLS_REPLACE: - ret = tc_add_flow(priv, cls); + ret = tc_add_flow_cls(priv, cls); break; case FLOW_CLS_DESTROY: - ret = tc_del_flow(priv, cls); + ret = tc_del_flow_cls(priv, cls); break; default: return -EOPNOTSUPP; @@ -642,6 +1041,30 @@ static int tc_setup_cls(struct tc956xmac_priv *priv, return ret; } +#if (LINUX_VERSION_CODE > KERNEL_VERSION(5, 5, 0)) +struct timespec64 tc956x_calc_basetime(ktime_t old_base_time, + ktime_t current_time, + u64 cycle_time) +{ + struct timespec64 time; + + if (ktime_after(old_base_time, current_time)) { + time = ktime_to_timespec64(old_base_time); + } else { + s64 n; + ktime_t base_time; + + n = div64_s64(ktime_sub_ns(current_time, old_base_time), + cycle_time); + base_time = ktime_add_ns(old_base_time, + (n + 1) * cycle_time); + + time = ktime_to_timespec64(base_time); + } + + return time; +} + static int tc_setup_taprio(struct tc956xmac_priv *priv, struct tc_taprio_qopt_offload *qopt) { @@ -655,18 +1078,25 @@ static int tc_setup_taprio(struct tc956xmac_priv *priv, bool fpe = false; int i, ret = 0; + u64 system_time; + ktime_t current_time_ns; + + u32 tx_channels_count = priv->plat->tx_queues_to_use; + u32 chan = 0; + unsigned long gates; + if (!priv->dma_cap.estsel) return -EOPNOTSUPP; switch (wid) { case 0x1: - wid = 16; + wid = SIXTEEN; break; case 0x2: - wid = 20; + wid = TWENTY; break; case 0x3: - wid = 24; + wid = TWENTY_FOUR; break; default: return -EOPNOTSUPP; @@ -674,26 +1104,32 @@ static int tc_setup_taprio(struct tc956xmac_priv *priv, switch (dep) { case 0x1: - dep = 64; + dep = SIXTY_FOUR; break; case 0x2: - dep = 128; + dep = ONE_TWENTY_EIGHT; break; case 0x3: - dep = 256; + dep = TWO_FIFTY_SIX; break; case 0x4: - dep = 512; + dep = FIVE_HUNDRED_TWELVE; break; case 0x5: - dep = 1024; + dep = THOUSAND_TWENTY_FOUR; break; default: return -EOPNOTSUPP; } - +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 5)) if (!qopt->enable) goto disable; +#else + if (qopt->cmd == TAPRIO_CMD_DESTROY) + goto disable; + else if (qopt->cmd != TAPRIO_CMD_REPLACE) + return -EOPNOTSUPP; +#endif if (qopt->num_entries >= dep) return -EINVAL; if (!qopt->base_time) @@ -713,11 +1149,30 @@ static int tc_setup_taprio(struct tc956xmac_priv *priv, size = qopt->num_entries; priv->plat->est->gcl_size = size; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 5)) priv->plat->est->enable = qopt->enable; - +#else + priv->plat->est->enable = qopt->cmd == TAPRIO_CMD_REPLACE; +#endif for (i = 0; i < size; i++) { s64 delta_ns = qopt->entries[i].interval; - u32 gates = qopt->entries[i].gate_mask; + unsigned long gate_list = qopt->entries[i].gate_mask; + + gates = 0; + for (chan = 0; chan < tx_channels_count; chan++) { +#ifdef TC956X_SRIOV_PF + if (priv->plat->tx_q_in_use[chan] == TC956X_DISABLE_QUEUE) + continue; +#endif + + if (priv->plat->gate_mask == 1) { /* kernel returns gate_mask with tc_map_to_queue_mask. so queue mask to tc map to be done */ + if (test_bit(chan, &gate_list)) + set_bit(priv->plat->tx_queues_cfg[chan].traffic_class, &gates); + } + } + + if (priv->plat->gate_mask == 0) /* If tc_map_to_queue_mask disabled, then no need of queue mask to tc map */ + gates = gate_list; if (delta_ns > GENMASK(wid, 0)) return -ERANGE; @@ -745,7 +1200,13 @@ static int tc_setup_taprio(struct tc956xmac_priv *priv, } /* Adjust for real system time */ - time = ktime_to_timespec64(qopt->base_time); + + tc956xmac_get_systime(priv, priv->ptpaddr, &system_time); + current_time_ns = ns_to_ktime(system_time); + time = tc956x_calc_basetime(qopt->base_time, current_time_ns, qopt->cycle_time); + + tc956xmac_get_systime(priv, priv->ptpaddr, &system_time); + priv->plat->est->btr[0] = (u32)time.tv_nsec; priv->plat->est->btr[1] = (u32)time.tv_sec; #ifndef CONFIG_ARCH_DMA_ADDR_T_64BIT @@ -759,7 +1220,7 @@ static int tc_setup_taprio(struct tc956xmac_priv *priv, if (fpe && !priv->dma_cap.fpesel) return -EOPNOTSUPP; - +#ifdef TC956X_UNSUPPORTED_UNTESTED ret = tc956xmac_fpe_configure(priv, priv->ioaddr, priv->plat->tx_queues_to_use, priv->plat->rx_queues_to_use, fpe); @@ -767,7 +1228,7 @@ static int tc_setup_taprio(struct tc956xmac_priv *priv, netdev_err(priv->dev, "failed to enable Frame Preemption\n"); return ret; } - +#endif ret = tc956xmac_est_configure(priv, priv->ioaddr, priv->plat->est, priv->plat->clk_ptp_rate); if (ret) { @@ -785,34 +1246,93 @@ static int tc_setup_taprio(struct tc956xmac_priv *priv, return ret; } +#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 2, 16)) +static int tc_query_caps(struct tc956xmac_priv *priv, + struct tc_query_caps_base *base) +{ + switch (base->type) { + case TC_SETUP_QDISC_TAPRIO: { + struct tc_taprio_caps *caps = base->caps; + + if (!priv->dma_cap.estsel) + return -EOPNOTSUPP; + + caps->gate_mask_per_txq = true; + if (caps->gate_mask_per_txq) + priv->plat->gate_mask = 1; + else + priv->plat->gate_mask = 0; + + return 0; + } + default: + return -EOPNOTSUPP; + } +} +#endif +#endif + static int tc_setup_etf(struct tc956xmac_priv *priv, struct tc_etf_qopt_offload *qopt) { +#ifndef TC956X_SRIOV_VF + u8 vf; +#endif + bool is_pf_ch = false; + if (!priv->dma_cap.tbssel) return -EOPNOTSUPP; if (qopt->queue >= priv->plat->tx_queues_to_use) return -EINVAL; - if (!(priv->tx_queue[qopt->queue].tbs & TC956XMAC_TBS_AVAIL)) +#ifdef TC956X_SRIOV_VF + /* Only allows if Queue is allocated to VF */ + if (priv->plat->tx_queues_cfg[qopt->queue].mode_to_use == + MTL_QUEUE_DISABLE) return -EINVAL; +#else +#ifdef TC956X_AUTOMOTIVE_CONFIG + vf = priv->dma_vf_map[qopt->queue]; + if (vf == 0) + is_pf_ch = true; + +#else + vf = priv->dma_vf_map[qopt->queue]; + if (vf == 3) + is_pf_ch = true; +#endif +#endif + if (!(priv->tx_queue[qopt->queue].tbs & TC956XMAC_TBS_AVAIL)) { + if (is_pf_ch == false && priv->fn_id_info.vf_no != 0) + return -EINVAL; + else if (is_pf_ch == true) + return -EINVAL; + } if (qopt->enable) priv->tx_queue[qopt->queue].tbs |= TC956XMAC_TBS_EN; else priv->tx_queue[qopt->queue].tbs &= ~TC956XMAC_TBS_EN; +#ifndef TC956X_SRIOV_VF + if (is_pf_ch == false && priv->fn_id_info.vf_no == 0) + tc956x_mbx_wrap_setup_etf(priv, qopt->queue, vf); +#endif + netdev_info(priv->dev, "%s ETF for Queue %d\n", qopt->enable ? "enabled" : "disabled", qopt->queue); return 0; } -#endif /* TC956X_UNSUPPORTED_UNTESTED_FEATURE */ const struct tc956xmac_tc_ops dwmac510_tc_ops = { .init = tc_init, -#ifdef TC956X_UNSUPPORTED_UNTESTED_FEATURE .setup_cls_u32 = tc_setup_cls_u32, .setup_cbs = tc_setup_cbs, .setup_cls = tc_setup_cls, +#if (LINUX_VERSION_CODE > KERNEL_VERSION(5, 5, 0)) .setup_taprio = tc_setup_taprio, +#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 2, 16)) + .query_caps = tc_query_caps, +#endif +#endif .setup_etf = tc_setup_etf, -#endif /* TC956X_UNSUPPORTED_UNTESTED_FEATURE */ };