V_01-03-59

This branch is based on V_01-00-59
## TC956X_Linux_Host_Driver_20230810_V_01-01-59
1. A part of Automotive AVB/TSN support
2. Default Port 0 interface is XFI and Port1 interface is SGMII
3. IPA (macro TC956X_DMA_OFFLOAD_ENABLE) enabled by default
4. Kernel timers are used to process transmitted TX descriptor. Systick timers are not used.
5. Dynamic change of MTU not supported. Max MTU supported is 9000.
6. Port 1 supports USXGMII, XFI and 25000Base-X interface also.

## TC956X_Linux_Host_Driver_20231110_V_01-02-59
1. Kernel 6.1.18 Porting changes
2. TC956x switch to switch connection support (upto 1 level) over DSP ports

## TC956X_Linux_Host_Driver_20231226_V_01-03-59
1. Kernel 6.6.1 Porting changes
2. Added the support for TC commands taprio and flower
This commit is contained in:
TC956X 2024-01-18 13:09:01 +09:00 committed by jianzhou
parent 688a75f02c
commit eea08813f0
40 changed files with 16600 additions and 2337 deletions

View File

@ -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

1239
common.h

File diff suppressed because it is too large Load Diff

View File

@ -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)

15
descs.h
View File

@ -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;

View File

@ -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
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
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

View File

@ -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__ */

View File

@ -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 <linux/bitrev.h>
@ -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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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 */

View File

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

View File

@ -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 <linux/iopoll.h>
@ -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] =

34
hwif.c
View File

@ -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) {

370
hwif.h
View File

@ -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 <linux/netdevice.h>
#include "tc956xmac_inc.h"
#include <linux/version.h>
#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 */

View File

@ -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));

View File

@ -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
*/

286
tc956x_msigen.c Normal file
View File

@ -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 <linux/kernel.h>
#include <linux/io.h>
#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<<vector), priv->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,
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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__ */

612
tc956x_pf_mbx.c Normal file
View File

@ -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 */

47
tc956x_pf_mbx.h Normal file
View File

@ -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 <linux/netdevice.h>
#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__ */

1816
tc956x_pf_mbx_wrapper.c Normal file

File diff suppressed because it is too large Load Diff

158
tc956x_pf_rsc_mng.c Normal file
View File

@ -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,
};

86
tc956x_pf_rsc_mng.h Normal file
View File

@ -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 <linux/netdevice.h>
#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__ */

550
tc956x_vf_mbx.c Normal file
View File

@ -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 */

47
tc956x_vf_mbx.h Normal file
View File

@ -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 <linux/netdevice.h>
#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__ */

2038
tc956x_vf_mbx_wrapper.c Normal file

File diff suppressed because it is too large Load Diff

119
tc956x_vf_rsc_mng.c Normal file
View File

@ -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,
};

87
tc956x_vf_rsc_mng.h Normal file
View File

@ -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 <linux/netdevice.h>
#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__ */

View File

@ -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);
}

View File

@ -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

View File

@ -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 <linux/clk.h>
#include <linux/if_vlan.h>
#include "tc956xmac_inc.h"
#ifndef TC956X_SRIOV_VF
#include <linux/phylink.h>
#endif
#include <linux/pci.h>
#include "common.h"
#include <linux/ptp_clock_kernel.h>
#include <linux/net_tstamp.h>
#include <linux/reset.h>
#include <net/page_pool.h>
#include <linux/version.h>
#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0))
#include <net/page_pool.h>
#else
#include <net/page_pool/helpers.h>
#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__ */

View File

@ -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 <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/interrupt.h>
#include <linux/mii.h>
#ifndef TC956X_SRIOV_VF
#include <linux/phylink.h>
#endif /* TC956X_SRIOV_VF */
#include <linux/net_tstamp.h>
#include <asm/io.h>
#include <linux/iopoll.h>
#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
@ -1120,73 +1298,109 @@ static void tc956xmac_m3fw_stats_read(struct tc956xmac_priv *priv)
}
/* 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 )));
(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 )));
(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 )));
(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 )));
(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 )));
(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 )));
(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 )));
(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 )));
(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 )));
(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 )));
(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 )));
(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 )));
(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 )));
(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 )));
(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 )));
(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 )));
(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 )));
(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 )));
(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 )));
(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 )));
(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 )));
(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 )));
(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 )));
(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 )));
(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,7 +1602,7 @@ 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);
@ -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,

View File

@ -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

View File

@ -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 <linux/phy.h>
#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

View File

@ -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;
};

File diff suppressed because it is too large Load Diff

View File

@ -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 <linux/gpio/consumer.h>
@ -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;
@ -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);

View File

@ -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;

View File

@ -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 */

View File

@ -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,

View File

@ -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 <net/pkt_cls.h>
#include <net/tc_act/tc_gact.h>
#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 */
};