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 */ };