Add files via upload

This commit is contained in:
TC956X 2021-07-06 20:30:13 +09:00 committed by jianzhou
parent a899ec8355
commit 4059938c56
13 changed files with 832 additions and 200 deletions

View File

@ -1,26 +1,94 @@
# Toshiba Electronic Devices & Storage Corporation TC956X PCIe Ethernet Host Driver
Release Date: 26 Mar 2021
Release Date: 05 Jul 2021
Release Version: V_01-00
Release Version: V_01-00-01 : Limited-tested version
TC956X PCIe EMAC driver is based on "Fedora 30, kernel-5.4.19".
# Compilation & Run: Need to be root user to execute the following steps.
1. Execute following commands:
#make clean
#make
2. Load phylink module
#modprobe phylink
3. Load the driver
#insmod tc956x_pcie_eth.ko tc956x_speed=X
In the module parameter tc956x_speed, X is the desired PCIe Gen speed. X can be 3 or 2 or 1.
Passing module parameter (tc956x_speed=X) is optional.
If module parameter is not passed, by default Gen3 speed will be selected by the driver.
4. Remove the driver
#rmmod tc956x_pcie_eth
# Release Versions:
## TC956X_Host_Driver_20210326_V_01-00:
1. Initial Version
1. Initial Version
## TC956X_Host_Driver_20210705_V_01-00-01:
1. Used Systick handler instead of Driver kernel timer to process transmitted Tx descriptors.
2. XFI interface supported and added module parameters for selection of Port0 and Port1 interface
3. kernel_read API replaced with kernel_read_file_from_path API
4. sprintf, vsprintf APIs replaced with vcnsprintf or vcnsprintf APIs
5. API to print IPA DMA channel statistics supported
6. Correction of print statement about selection of C45 PHY for Port0 interface
# Note:
1. Use below commands to advertise with Autonegotiation ON for speeds 10Gbps, 5Gbps, 2.5Gbps, 1Gbps, 100Mbps and 10Mbps as ethtool speed command does not support.
ethtool -s <interface> advertise 0x1000 autoneg on --> changes the advertisement to 10Gbps
ethtool -s <interface> advertise 0x1000000000000 autoneg on --> changes the advertisement to 5Gbps
ethtool -s <interface> advertise 0x800000000000 autoneg on --> changes the advertisement to 2.5Gbps
ethtool -s <interface> advertise 0x020 autoneg on --> changes the advertisement to 1Gbps
ethtool -s <interface> advertise 0x008 autoneg on --> changes the advertisement to 100Mbps
ethtool -s <interface> advertise 0x002 autoneg on --> changes the advertisement 10Mbps
2. Use the below command to insert the kernel module with specific modes for interfaces:
#insmod tc956x_pcie_eth.ko tc956x_port0_interface=x tc956x_port1_interface=y
argument info:
tc956x_port0_interface: For PORT0 interface mode setting
tc956x_port1_interface: For PORT1 interface mode setting
x = [0: USXGMII, 1: XFI (default), 2: RGMII (unsupported), 3: SGMII]
y = [0: USXGMII (unsupported), 1: XFI (unsupported), 2: RGMII, 3: SGMII(default)]
If invalid and unsupported modes are passed as kernel module parameter, the default interface mode will be selected.
3. Regarding the performance, use the below command to increase the dynamic byte queue limit
$echo "900000" > /sys/devices/pci0000\:00/0000\:00\:01.0/0000\:01\:00.0/0000\:02\:03.0/0000\:05\:00.0/net/enp5s0f0/queues/tx-0/byte_queue_limits/limit_min
900000 is the random value chosen. It needs to adjust this value on their system and check
"0000\:00/0000\:00\:01.0/0000\:01\:00.0/0000\:02\:03.0/0000\:05\:00.0/" value can be obtained from the "lspci -t" command
4. The debug counters to check the interrupt count is available.
"#ethtool -S <interface>" needs to be executed and sample output is as below
total_interrupts: 120109
lpi_intr_n: 0
pmt_intr_n: 0
event_intr_n: 0
tx_intr_n: 120000
rx_intr_n: 51
xpcs_intr_n: 0
phy_intr_n: 46
sw_msi_n: 12
tx_intr_n = No of. Tx interrupts originating from eMAC
sw_msi_n = No. of SW MSIs triggered by Systick Handler as part of optimized Tx Timer based on Systick approach.
So total number of interrupts for Tx = tx_intr_n + sw_msi_n
Please note that whenever Rx interruts are generated, the Host ISR will process the Tx completed descriptors too.

View File

@ -30,6 +30,10 @@
*
* 15 Mar 2021 : Base lined
* VERSION : 01-00
*
* 05 Jul 2021 : 1. Used Systick handler instead of Driver kernel timer to process transmitted Tx descriptors.
* 2. XFI interface support and module parameters for selection of Port0 and Port1 interface
* VERSION : 01-00-01
*/
#ifndef __COMMON_H__
@ -64,7 +68,7 @@
#define DWXGMAC_CORE_3_01 0x30
//#define DISABLE_EMAC_PORT1
//#define DUMP_REGISTER
/* Note: Multiple macro definitions for TC956X_PCIE_LOGSTAT.
* Please also define/undefine same macro in tc956xmac_ioctl.h, if changing in this file
*/
@ -747,6 +751,11 @@ enum packets_types {
#ifdef TC956X
#define TC956X_EXT_PHY_ETH_INT BIT(20)
#ifdef TC956X_SW_MSI
#define TC956X_SW_MSI_INT BIT(24)
#endif
#define TC956X_SSREG_BRREG_REG_BASE (0x00024000U)
#define TC956X_GLUE_LOGIC_BASE_OFST (0x0002C000U)
@ -901,6 +910,10 @@ enum packets_types {
#define MSI_INT_TX_CH0 3
#define MSI_INT_RX_CH0 11
#define MSI_INT_EXT_PHY 20
#ifdef TC956X_SW_MSI
#define MSI_INT_SW_MSI 24
#endif
#define TC956X_MSI_BASE (0xF000)
#define TC956X_MSI_PF0 (0x000)
@ -936,6 +949,10 @@ enum packets_types {
(pf_id * TC956X_MSI_PF1) + (0x0038))
#define TC956X_MSI_VECT_SET7_OFFSET(pf_id) (TC956X_MSI_BASE +\
(pf_id * TC956X_MSI_PF1) + (0x003C))
#define TC956X_MSI_SW_MSI_SET(pf_id) (TC956X_MSI_BASE +\
(pf_id * TC956X_MSI_PF1) + (0x0050))
#define TC956X_MSI_SW_MSI_CLR(pf_id) (TC956X_MSI_BASE +\
(pf_id * TC956X_MSI_PF1) + (0x0054))
#define TC956X_MSI_EVENT_OFFSET(pf_id) (TC956X_MSI_BASE +\
(pf_id * TC956X_MSI_PF1) + (0x0068))
@ -1126,6 +1143,17 @@ struct tc956xmac_extra_stats {
u64 rxch_sw_cur_rx[TC956XMAC_CH_MAX];
u64 rxch_sw_dirty_rx[TC956XMAC_CH_MAX];
/*debug interrupt counters */
u64 total_interrupts;
u64 lpi_intr_n;
u64 pmt_intr_n;
u64 event_intr_n;
u64 tx_intr_n;
u64 rx_intr_n;
u64 xpcs_intr_n;
u64 phy_intr_n;
u64 sw_msi_n;
};
/* Safety Feature statistics exposed by ethtool */

View File

@ -30,7 +30,11 @@
*
* 15 Mar 2021 : Base lined
* VERSION : 01-00
*/
*
* 05 Jul 2021 : 1. Used Systick handler instead of Driver kernel timer to process transmitted Tx descriptors.
* 2. XFI interface support and module parameters for selection of Port0 and Port1 interface
* VERSION : 01-00-01
*/
#include <linux/bitrev.h>
#include <linux/crc32.h>
@ -64,7 +68,8 @@ static void dwxgmac2_core_init(struct tc956xmac_priv *priv,
tx |= hw->link.xgmii.speed10000;
break;
case SPEED_2500:
tx |= hw->link.speed2500;
if (priv->plat->interface == PHY_INTERFACE_MODE_SGMII)
tx |= hw->link.speed2500;
break;
case SPEED_1000:
default:
@ -77,7 +82,8 @@ static void dwxgmac2_core_init(struct tc956xmac_priv *priv,
tx |= hw->link.speed1000;
else if (priv->plat->interface == PHY_INTERFACE_MODE_SGMII)
tx |= hw->link.speed2500;
else if (priv->plat->interface == PHY_INTERFACE_MODE_USXGMII)
else if ((priv->plat->interface == PHY_INTERFACE_MODE_USXGMII) ||
(priv->plat->interface == PHY_INTERFACE_MODE_10GKR))
tx |= hw->link.xgmii.speed10000;
#endif
writel(tx, ioaddr + XGMAC_TX_CONFIG);
@ -2394,6 +2400,7 @@ static int dwxgmac3_est_configure(struct tc956xmac_priv *priv,
u64 read_btr = 0, read_ctr = 0;
static u32 switch_cnt = 0;
char *qptr = NULL, *pptr = NULL;
int char_buff_size = 100*100;
pptr = (char *)kzalloc(100*100, GFP_KERNEL);
if (!pptr) {
@ -2442,9 +2449,9 @@ static int dwxgmac3_est_configure(struct tc956xmac_priv *priv,
switch_cnt, read_btr, read_ctr,
PACKET_IPG, PACKET_CDT_IPG);
for (i = 0; i < cfg->gcl_size; i++) {
sprintf((pptr+(i*11)), ", %010d", (cfg->gcl[i]&0xffffff));
scnprintf((pptr+(i*11)), char_buff_size - (i*11), ",%010d", (cfg->gcl[i]&0xffffff));
for (j = 0; j < 6; j++) {
sprintf((qptr+(i*6*2)+(j*2)), ",%d",
scnprintf((qptr+(i*6*2)+(j*2)), char_buff_size - (i*6*2) + (j*2), ",%d",
((cfg->gcl[i]>>(24+j))&0x1));
}
}

View File

@ -27,6 +27,10 @@
*
* 15 Mar 2021 : Base lined
* VERSION : 01-00
*
* 05 Jul 2021 : 1. Used Systick handler instead of Driver kernel timer to process transmitted Tx descriptors.
* 2. XFI interface support and module parameters for selection of Port0 and Port1 interface
* VERSION : 01-00-01
*/
#include <linux/dma-mapping.h>
@ -1446,5 +1450,71 @@ int stop_channel(struct net_device *ndev, struct channel_info *channel)
}
EXPORT_SYMBOL_GPL(stop_channel);
/*!
* \brief This API will print EMAC-IPA offload DMA channel stats
*
* \details This function will read and prints DMA Descriptor stats
* used by IPA.
*
* \param[in] ndev : TC956x netdev data structure.
*
* \return : Return 0 on success, -ve value on error
* -ENODEV if ndev is NULL, tc956xmac_priv extracted from ndev is NULL
*/
int read_ipa_desc_stats(struct net_device *ndev)
{
int chno = 0;
struct tc956xmac_priv *priv;
if (!ndev) {
pr_err("%s: ERROR: Invalid netdevice pointer\n", __func__);
return -ENODEV;
}
priv = netdev_priv(ndev);
if (!priv) {
pr_err("%s: ERROR: Invalid private data pointer\n", __func__);
return -ENODEV;
}
/* TX DMA Descriptors Status for all channels */
for (chno = 0; chno < priv->plat->tx_queues_to_use; chno++) {
if (priv->plat->tx_dma_ch_owner[chno] != USE_IN_OFFLOADER)
continue;
netdev_info(priv->dev, "%s : txch_status[%d] : 0x%08x", __func__, chno, readl(priv->ioaddr + XGMAC_DMA_CH_STATUS(chno)));
netdev_info(priv->dev, "%s : txch_control[%d] : 0x%08x", __func__, chno, readl(priv->ioaddr + XGMAC_DMA_CH_TX_CONTROL(chno)));
netdev_info(priv->dev, "%s : txch_desc_list_haddr[%d] : 0x%08x", __func__, chno, readl(priv->ioaddr + XGMAC_DMA_CH_TxDESC_HADDR(chno)));
netdev_info(priv->dev, "%s : txch_desc_list_laddr[%d] : 0x%08x", __func__, chno, readl(priv->ioaddr + XGMAC_DMA_CH_TxDESC_LADDR(chno)));
netdev_info(priv->dev, "%s : txch_desc_ring_len[%d] : 0x%08x", __func__, chno, readl(priv->ioaddr + XGMAC_DMA_CH_TX_CONTROL2(chno)));
netdev_info(priv->dev, "%s : txch_desc_curr_haddr[%d] : 0x%08x", __func__, chno, readl(priv->ioaddr + XGMAC_DMA_CH_Cur_TxDESC_HADDR(chno)));
netdev_info(priv->dev, "%s : txch_desc_curr_laddr[%d] : 0x%08x", __func__, chno, readl(priv->ioaddr + XGMAC_DMA_CH_Cur_TxDESC_LADDR(chno)));
netdev_info(priv->dev, "%s : txch_desc_tail[%d] : 0x%08x", __func__, chno, readl(priv->ioaddr + XGMAC_DMA_CH_TxDESC_TAIL_LPTR(chno)));
netdev_info(priv->dev, "%s : txch_desc_buf_haddr[%d] : 0x%08x", __func__, chno, readl(priv->ioaddr + XGMAC_DMA_CH_Cur_TxBuff_HADDR(chno)));
netdev_info(priv->dev, "%s : txch_desc_buf_laddr[%d] : 0x%08x", __func__, chno, readl(priv->ioaddr + XGMAC_DMA_CH_Cur_TxBuff_LADDR(chno)));
netdev_info(priv->dev, "%s : txch_dma_interrupt_en[%d] : 0x%08x", __func__, chno, readl(priv->ioaddr + XGMAC_DMA_CH_INT_EN(chno)));
}
/* RX DMA Descriptors Status for all channels */
for (chno = 0; chno < TC956XMAC_CH_MAX; chno++) {
if (priv->plat->rx_dma_ch_owner[chno] != USE_IN_OFFLOADER)
continue;
netdev_info(priv->dev, "%s : rxch_status[%d] : 0x%08x", __func__, chno, readl(priv->ioaddr + XGMAC_DMA_CH_STATUS(chno)));
netdev_info(priv->dev, "%s : rxch_control[%d] : 0x%08x", __func__, chno, readl(priv->ioaddr + XGMAC_DMA_CH_RX_CONTROL(chno)));
netdev_info(priv->dev, "%s : rxch_desc_list_haddr[%d] : 0x%08x", __func__, chno, readl(priv->ioaddr + XGMAC_DMA_CH_RxDESC_HADDR(chno)));
netdev_info(priv->dev, "%s : rxch_desc_list_laddr[%d] : 0x%08x", __func__, chno, readl(priv->ioaddr + XGMAC_DMA_CH_RxDESC_LADDR(chno)));
netdev_info(priv->dev, "%s : rxch_desc_ring_len[%d] : 0x%08x", __func__, chno, readl(priv->ioaddr + XGMAC_DMA_CH_RX_CONTROL2(chno)));
netdev_info(priv->dev, "%s : rxch_desc_curr_haddr[%d] : 0x%08x", __func__, chno, readl(priv->ioaddr + XGMAC_DMA_CH_Cur_RxDESC_HADDR(chno)));
netdev_info(priv->dev, "%s : rxch_desc_curr_laddr[%d] : 0x%08x", __func__, chno, readl(priv->ioaddr + XGMAC_DMA_CH_Cur_RxDESC_LADDR(chno)));
netdev_info(priv->dev, "%s : rxch_desc_tail[%d] : 0x%08x", __func__, chno, readl(priv->ioaddr + XGMAC_DMA_CH_RxDESC_TAIL_LPTR(chno)));
netdev_info(priv->dev, "%s : rxch_desc_buf_haddr[%d] : 0x%08x", __func__, chno, readl(priv->ioaddr + XGMAC_DMA_CH_Cur_RxBuff_HADDR(chno)));
netdev_info(priv->dev, "%s : rxch_desc_buf_laddr[%d] : 0x%08x", __func__, chno, readl(priv->ioaddr + XGMAC_DMA_CH_Cur_RxBuff_LADDR(chno)));
netdev_info(priv->dev, "%s : rxch_dma_interrupt_en[%d] : 0x%08x", __func__, chno, readl(priv->ioaddr + XGMAC_DMA_CH_INT_EN(chno)));
}
return 0;
}
EXPORT_SYMBOL_GPL(read_ipa_desc_stats);

View File

@ -29,6 +29,10 @@
*
* 15 Mar 2021 : Base lined
* VERSION : 01-00
*
* 05 Jul 2021 : 1. Used Systick handler instead of Driver kernel timer to process transmitted Tx descriptors.
* 2. XFI interface support and module parameters for selection of Port0 and Port1 interface
* VERSION : 01-00-01
*/
#ifndef __TC956x_IPA_INTF_H
@ -363,6 +367,19 @@ int start_channel(struct net_device *ndev, struct channel_info *channel);
*/
int stop_channel(struct net_device *ndev, struct channel_info *channel);
/*!
* \brief This API will print EMAC-IPA offload DMA channel stats
*
* \details This function will read and prints DMA Descriptor stats
* used by IPA.
*
* \param[i] ndev : TC956x netdev data structure.
*
* \return : Return 0 on success, -ve value on error
* -ENODEV if ndev is NULL, tc956xmac_priv extracted from ndev is NULL
*
*/
int read_ipa_desc_stats(struct net_device *ndev);
#endif /* __TC956x_IPA_INTF_H */

View File

@ -30,6 +30,10 @@
*
* 15 Mar 2021 : Base lined
* VERSION : 01-00
*
* 05 Jul 2021 : 1. Used Systick handler instead of Driver kernel timer to process transmitted Tx descriptors.
* 2. XFI interface support and module parameters for selection of Port0 and Port1 interface
* VERSION : 01-00-01
*/
#include <linux/clk-provider.h>
@ -56,9 +60,10 @@
#ifdef TC956X_PCIE_GEN3_SETTING
static unsigned int tc956x_speed = 3;
#endif
static unsigned int tc956x_port0_interface = ENABLE_XFI_INTERFACE;
static unsigned int tc956x_port1_interface = ENABLE_SGMII_INTERFACE;
static const struct tc956x_version tc956x_drv_version = {0, 1, 0, 0};
static const struct tc956x_version tc956x_drv_version = {0, 1, 0, 0, 0, 1};
/*
* This struct is used to associate PCI Function of MAC controller on a board,
@ -674,21 +679,15 @@ static void xgmac_default_data(struct plat_tc956xmacenet_data *plat)
plat->has_gmac4 = 0;
plat->force_thresh_dma_mode = 0;
plat->mdio_bus_data->needs_reset = false;
if (INTERFACE_SELECTED(plat->port_num) == ENABLE_USXGMII_INTERFACE)
if ((plat->port_interface == ENABLE_USXGMII_INTERFACE) ||
(plat->port_interface == ENABLE_XFI_INTERFACE))
plat->mac_port_sel_speed = 10000;
if (INTERFACE_SELECTED(plat->port_num) == ENABLE_RGMII_INTERFACE)
if (plat->port_interface == ENABLE_RGMII_INTERFACE)
plat->mac_port_sel_speed = 1000;
if (INTERFACE_SELECTED(plat->port_num) == ENABLE_SGMII_INTERFACE) {
#ifndef TC956X_SGMII_2P5_GBPS_TEST
plat->mac_port_sel_speed = 1000;
#else
if (plat->port_interface == ENABLE_SGMII_INTERFACE)
plat->mac_port_sel_speed = 2500;
#endif
}
plat->riwt_off = 0;
plat->rss_en = 0;
@ -724,23 +723,21 @@ static int tc956xmac_xgmac3_default_data(struct pci_dev *pdev,
plat->pdev = pdev;
#ifdef TC956X
if (INTERFACE_SELECTED(plat->port_num) == ENABLE_USXGMII_INTERFACE) {
if (plat->port_interface == ENABLE_USXGMII_INTERFACE) {
plat->interface = PHY_INTERFACE_MODE_USXGMII;
plat->max_speed = 10000;
}
if (INTERFACE_SELECTED(plat->port_num) == ENABLE_RGMII_INTERFACE) {
if (plat->port_interface == ENABLE_XFI_INTERFACE) {
plat->interface = PHY_INTERFACE_MODE_10GKR;
plat->max_speed = 10000;
}
if (plat->port_interface == ENABLE_RGMII_INTERFACE) {
plat->interface = PHY_INTERFACE_MODE_RGMII;
plat->max_speed = 1000;
}
if (INTERFACE_SELECTED(plat->port_num) == ENABLE_SGMII_INTERFACE) {
if (plat->port_interface == ENABLE_SGMII_INTERFACE) {
plat->interface = PHY_INTERFACE_MODE_SGMII;
#ifndef TC956X_SGMII_2P5_GBPS_TEST
plat->max_speed = 1000;
#else
plat->max_speed = 2500;
#endif
}
#else
plat->interface = PHY_INTERFACE_MODE_USXGMII;
@ -1729,10 +1726,11 @@ static int tc956xmac_pci_probe(struct pci_dev *pdev,
struct tc956x_ltssm_log ltssm_data;
#endif/*TC956X_PCIE_LOGSTAT*/
KPRINT_INFO("%s >", __func__);
sprintf(version_str, "Host Driver Version %d%d-%d%d",
scnprintf(version_str, sizeof(version_str), "Host Driver Version %d%d-%d%d-%d%d",
tc956x_drv_version.rel_dbg,
tc956x_drv_version.major, tc956x_drv_version.minor,
tc956x_drv_version.sub_minor);
tc956x_drv_version.sub_minor,
tc956x_drv_version.patch_rel_major, tc956x_drv_version.patch_rel_minor);
NMSGPR_INFO(&pdev->dev, "%s\n", version_str);
plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL);
@ -1896,6 +1894,26 @@ static int tc956xmac_pci_probe(struct pci_dev *pdev,
plat->c45_needed = PORT1_C45_STATE;
}
if (res.port_num == RM_PF0_ID) {
/* Set the PORT0 interface mode to default, in case of invalid input */
if ((tc956x_port0_interface == ENABLE_RGMII_INTERFACE) ||
(tc956x_port0_interface > ENABLE_SGMII_INTERFACE))
tc956x_port0_interface = ENABLE_XFI_INTERFACE;
res.port_interface = tc956x_port0_interface;
}
if (res.port_num == RM_PF1_ID) {
/* Set the PORT1 interface mode to default, in case of invalid input */
if ((tc956x_port1_interface < ENABLE_RGMII_INTERFACE) ||
(tc956x_port1_interface > ENABLE_SGMII_INTERFACE))
tc956x_port1_interface = ENABLE_SGMII_INTERFACE;
res.port_interface = tc956x_port1_interface;
}
plat->port_interface = res.port_interface;
ret = info->setup(pdev, plat);
if (ret)
@ -1974,25 +1992,23 @@ static int tc956xmac_pci_probe(struct pci_dev *pdev,
ret = readl(res.addr + NCLKCTRL0_OFFSET);
ret |= ((NCLKCTRL0_MAC0TXCEN | NCLKCTRL0_MAC0ALLCLKEN | NCLKCTRL0_MAC0RXCEN));
#ifdef TC956X_SGMII_2P5_GBPS_TEST
ret &= ~NCLKCTRL0_POEPLLCEN;
ret &= ~NCLKCTRL0_SGMPCIEN;
ret &= ~NCLKCTRL0_REFCLKOCEN;
ret &= ~NCLKCTRL0_MAC0125CLKEN;
ret &= ~NCLKCTRL0_MAC0312CLKEN;
#endif
/* Only if "current" port is SGMII 2.5G, configure below clocks. */
if (res.port_interface == ENABLE_SGMII_INTERFACE) {
ret &= ~NCLKCTRL0_POEPLLCEN;
ret &= ~NCLKCTRL0_SGMPCIEN;
ret &= ~NCLKCTRL0_REFCLKOCEN;
ret &= ~NCLKCTRL0_MAC0125CLKEN;
ret &= ~NCLKCTRL0_MAC0312CLKEN;
}
writel(ret, res.addr + NCLKCTRL0_OFFSET);
/* Interface configuration for port0*/
ret = readl(res.addr + NEMAC0CTL_OFFSET);
ret &= ~(NEMACCTL_SP_SEL_MASK | NEMACCTL_PHY_INF_SEL_MASK);
if (PORT0_INTERFACE == ENABLE_SGMII_INTERFACE)
#ifndef TC956X_SGMII_2P5_GBPS_TEST
ret |= NEMACCTL_SP_SEL_SGMII_1000M;
#else
if (res.port_interface == ENABLE_SGMII_INTERFACE)
ret |= NEMACCTL_SP_SEL_SGMII_2500M;
#endif
else if (PORT0_INTERFACE == ENABLE_USXGMII_INTERFACE)
else if ((res.port_interface == ENABLE_USXGMII_INTERFACE) ||
(res.port_interface == ENABLE_XFI_INTERFACE))
ret |= NEMACCTL_SP_SEL_USXGMII_10G_10G;
ret &= ~(0x00000040); /* Mask Polarity */
@ -2021,16 +2037,21 @@ static int tc956xmac_pci_probe(struct pci_dev *pdev,
ret |= ((NCLKCTRL1_MAC1TXCEN | NCLKCTRL1_MAC1RXCEN |
NCLKCTRL1_MAC1ALLCLKEN1 | 1 << 15));
if (res.port_interface == ENABLE_SGMII_INTERFACE) {
ret &= ~NCLKCTRL1_MAC1125CLKEN1;
ret &= ~NCLKCTRL1_MAC1312CLKEN1;
}
writel(ret, res.addr + NCLKCTRL1_OFFSET);
/* Interface configuration for port1*/
ret = readl(res.addr + NEMAC1CTL_OFFSET);
ret &= ~(NEMACCTL_SP_SEL_MASK | NEMACCTL_PHY_INF_SEL_MASK);
if (PORT1_INTERFACE == ENABLE_RGMII_INTERFACE)
if (res.port_interface == ENABLE_RGMII_INTERFACE)
ret |= NEMACCTL_SP_SEL_RGMII_1000M;
else if (PORT1_INTERFACE == ENABLE_SGMII_INTERFACE)
else if (res.port_interface == ENABLE_SGMII_INTERFACE)
ret |= NEMACCTL_SP_SEL_SGMII_2500M;
else if (PORT1_INTERFACE == ENABLE_USXGMII_INTERFACE)
else if ((res.port_interface == ENABLE_USXGMII_INTERFACE) ||
(res.port_interface == ENABLE_XFI_INTERFACE))
ret |= NEMACCTL_SP_SEL_USXGMII_10G_10G;
ret &= ~(0x00000040); /* Mask Polarity */
@ -2059,8 +2080,10 @@ static int tc956xmac_pci_probe(struct pci_dev *pdev,
goto err_dvr_probe;
}
#ifdef TC956X
writel(0x00000000, res.addr + 0x1050);
writel(0xF300F300, res.addr + 0x107C);
if ((res.port_num == RM_PF1_ID) && (res.port_interface == ENABLE_RGMII_INTERFACE)) {
writel(0x00000000, res.addr + 0x1050);
writel(0xF300F300, res.addr + 0x107C);
}
#endif
#ifdef TC956X_PCIE_LOGSTAT
@ -2240,14 +2263,23 @@ static int tc956x_pcie_resume_config(struct pci_dev *pdev)
ret = readl(priv->tc956x_SFR_pci_base_addr + NCLKCTRL0_OFFSET);
ret |= ((NCLKCTRL0_MAC0TXCEN | NCLKCTRL0_MAC0ALLCLKEN | NCLKCTRL0_MAC0RXCEN));
if (priv->port_interface == ENABLE_SGMII_INTERFACE) {
/* Disable Clocks for 2.5Gbps SGMII */
ret &= ~NCLKCTRL0_POEPLLCEN;
ret &= ~NCLKCTRL0_SGMPCIEN;
ret &= ~NCLKCTRL0_REFCLKOCEN;
ret &= ~NCLKCTRL0_MAC0125CLKEN;
ret &= ~NCLKCTRL0_MAC0312CLKEN;
}
writel(ret, priv->tc956x_SFR_pci_base_addr + NCLKCTRL0_OFFSET);
/* Interface configuration for port0*/
ret = readl(priv->tc956x_SFR_pci_base_addr + NEMAC0CTL_OFFSET);
ret &= ~(NEMACCTL_SP_SEL_MASK | NEMACCTL_PHY_INF_SEL_MASK);
if (PORT0_INTERFACE == ENABLE_SGMII_INTERFACE)
ret |= NEMACCTL_SP_SEL_SGMII_1000M; //ret |= NEMACCTL_SP_SEL_SGMII_2500M;
else if (PORT0_INTERFACE == ENABLE_USXGMII_INTERFACE)
if (priv->port_interface == ENABLE_SGMII_INTERFACE)
ret |= NEMACCTL_SP_SEL_SGMII_2500M;
else if ((priv->port_interface == ENABLE_USXGMII_INTERFACE) ||
(priv->port_interface == ENABLE_XFI_INTERFACE))
ret |= NEMACCTL_SP_SEL_USXGMII_10G_10G;
ret &= ~(0x00000040); /* Mask Polarity */
@ -2276,16 +2308,21 @@ static int tc956x_pcie_resume_config(struct pci_dev *pdev)
ret |= ((NCLKCTRL1_MAC1TXCEN | NCLKCTRL1_MAC1RXCEN |
NCLKCTRL1_MAC1ALLCLKEN1 | 1 << 15));
if (priv->port_interface == ENABLE_SGMII_INTERFACE) {
ret &= ~NCLKCTRL1_MAC1125CLKEN1;
ret &= ~NCLKCTRL1_MAC1312CLKEN1;
}
writel(ret, priv->tc956x_SFR_pci_base_addr + NCLKCTRL1_OFFSET);
/* Interface configuration for port1*/
ret = readl(priv->tc956x_SFR_pci_base_addr + NEMAC1CTL_OFFSET);
ret &= ~(NEMACCTL_SP_SEL_MASK | NEMACCTL_PHY_INF_SEL_MASK);
if (PORT1_INTERFACE == ENABLE_RGMII_INTERFACE)
if (priv->port_interface == ENABLE_RGMII_INTERFACE)
ret |= NEMACCTL_SP_SEL_RGMII_1000M;
else if (PORT1_INTERFACE == ENABLE_SGMII_INTERFACE)
else if (priv->port_interface == ENABLE_SGMII_INTERFACE)
ret |= NEMACCTL_SP_SEL_SGMII_2500M;
else if (PORT1_INTERFACE == ENABLE_USXGMII_INTERFACE)
else if ((priv->port_interface == ENABLE_USXGMII_INTERFACE) ||
(priv->port_interface == ENABLE_XFI_INTERFACE))
ret |= NEMACCTL_SP_SEL_USXGMII_10G_10G;
ret &= ~(0x00000040); /* Mask Polarity */
@ -2410,8 +2447,10 @@ static s32 tc956x_pcie_resume(struct pci_dev *pdev)
/* Call tc956xmac_resume() */
tc956xmac_resume(&pdev->dev);
#ifdef TC956X
writel(NEMACTXCDLY_DEFAULT, priv->ioaddr + TC9563_CFG_NEMACTXCDLY);
writel(NEMACIOCTL_DEFAULT, priv->ioaddr + TC9563_CFG_NEMACIOCTL);
if ((priv->port_num == RM_PF1_ID) && (priv->port_interface == ENABLE_RGMII_INTERFACE)) {
writel(NEMACTXCDLY_DEFAULT, priv->ioaddr + TC9563_CFG_NEMACTXCDLY);
writel(NEMACIOCTL_DEFAULT, priv->ioaddr + TC9563_CFG_NEMACIOCTL);
}
#endif
DBGPR_FUNC(&(pdev->dev), "<--%s\n", __func__);
@ -2638,6 +2677,16 @@ MODULE_PARM_DESC(tc956x_speed,
"PCIe speed Gen TC9563_64 - default is 3, [1..3]");
#endif
module_param(tc956x_port0_interface, uint, 0444);
MODULE_PARM_DESC(tc956x_port0_interface,
"PORT0 interface mode TC9563_64 - default is 1,\
[0: USXGMII, 1: XFI, 2: RGMII(not supported), 3: SGMII]");
module_param(tc956x_port1_interface, uint, 0444);
MODULE_PARM_DESC(tc956x_port1_interface,
"PORT1 interface mode TC9563_64 - default is 3,\
[0: USXGMII(not supported), 1: XFI(not supported), 2: RGMII, 3: SGMII]");
MODULE_DESCRIPTION("TC956X PCI Express Ethernet Network Driver");
MODULE_AUTHOR("Toshiba Electronic Devices & Storage Corporation");
MODULE_LICENSE("GPL v2");

View File

@ -27,6 +27,10 @@
*
* 15 Mar 2021 : Base lined
* VERSION : 01-00
*
* 05 Jul 2021 : 1. Used Systick handler instead of Driver kernel timer to process transmitted Tx descriptors.
* 2. XFI interface support and module parameters for selection of Port0 and Port1 interface
* VERSION : 01-00-01
*/
#include "common.h"
@ -93,21 +97,26 @@ int tc956x_xpcs_init(struct tc956xmac_priv *priv, void __iomem *xpcsaddr)
reg_value |= XGMAC_SGMII_MODE;/*SGMII PCS MODE*/
tc956x_xpcs_write(xpcsaddr, XGMAC_VR_MII_AN_CTRL, reg_value);
#ifdef TC956X_SGMII_2P5_GBPS_TEST
reg_value = tc956x_xpcs_read(xpcsaddr, XGMAC_VR_XS_PCS_DIG_CTRL1);
reg_value &= ~(0x4);
reg_value |= 0x4; /*EN_2_5G_MODE*/
tc956x_xpcs_write(xpcsaddr, XGMAC_VR_XS_PCS_DIG_CTRL1, reg_value);
#endif
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) {
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);
reg_value |= XGMAC_USXG_EN;/*set USXG_EN*/
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);
reg_value = tc956x_xpcs_read(xpcsaddr, XGMAC_VR_XS_PCS_KR_CTRL);
@ -132,9 +141,9 @@ int tc956x_xpcs_init(struct tc956xmac_priv *priv, void __iomem *xpcsaddr)
reg_value = tc956x_xpcs_read(xpcsaddr, XGMAC_VR_MII_DIG_CTRL1);
reg_value &= ~XGMAC_MAC_AUTO_SW_EN;/*MAC_AUTO_SW enable*/
#ifndef TC956X_SGMII_2P5_GBPS_TEST
reg_value |= XGMAC_MAC_AUTO_SW_EN;
#endif
if (priv->is_sgmii_2p5g != true)
/* Enable only if SGMII 2.5G is not enabled. */
reg_value |= XGMAC_MAC_AUTO_SW_EN;
tc956x_xpcs_write(xpcsaddr, XGMAC_VR_MII_DIG_CTRL1, reg_value);
return 0;
@ -144,15 +153,14 @@ 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) {
reg_value = tc956x_xpcs_read(priv->xpcsaddr, XGMAC_SR_MII_CTRL);
#ifndef TC956X_SGMII_2P5_GBPS_TEST
reg_value |= XGMAC_AN_37_ENABLE;
#else
KPRINT_INFO("%s Enable AN", __func__);
} else {
reg_value &= (~XGMAC_AN_37_ENABLE);
#endif
tc956x_xpcs_write(priv->xpcsaddr, XGMAC_SR_MII_CTRL, reg_value);
KPRINT_INFO("%s Disable AN", __func__);
}
tc956x_xpcs_write(priv->xpcsaddr, XGMAC_SR_MII_CTRL, reg_value);
}
#endif

View File

@ -27,6 +27,10 @@
*
* 15 Mar 2021 : Base lined
* VERSION : 01-00
*
* 05 Jul 2021 : 1. Used Systick handler instead of Driver kernel timer to process transmitted Tx descriptors.
* 2. XFI interface support and module parameters for selection of Port0 and Port1 interface
* VERSION : 01-00-01
*/
#ifndef __TC956X_XPCS_H__
@ -77,7 +81,9 @@
#define XPCS_REG_BASE_ADDR 10
#define XPCS_REG_OFFSET 0x0003FF
#define XPCS_IND_ACCESS 0x3FC
#define XPCS_SS_SGMII_1G 0x40
#define XPCS_SS_SGMII_100M 0x2000
#define XPCS_SS_SGMII_10M 0x0
u32 tc956x_xpcs_read(void __iomem *xpcsaddr, u32 pcs_reg_num);
u32 tc956x_xpcs_write(void __iomem *xpcsaddr, u32 pcs_reg_num, u32 value);

View File

@ -30,6 +30,10 @@
*
* 15 Mar 2021 : Base lined
* VERSION : 01-00
*
* 05 Jul 2021 : 1. Used Systick handler instead of Driver kernel timer to process transmitted Tx descriptors.
* 2. XFI interface support and module parameters for selection of Port0 and Port1 interface
* VERSION : 01-00-01
*/
#ifndef __TC956XMAC_H__
@ -48,7 +52,7 @@
#include <net/page_pool.h>
#include <linux/version.h>
//#define TC956X_LOAD_FW_HEADER
#define TC956X_LOAD_FW_HEADER
#define PF_DRIVER 4
//#define DMA_OFFLOAD_ENABLE
@ -77,7 +81,7 @@
#ifdef TC956X
#define TC956X_RESOURCE_NAME "tc956x_pci-eth"
#define DRV_MODULE_VERSION "V_01-00"
#define DRV_MODULE_VERSION "V_01-00-01"
#define TC956X_FW_MAX_SIZE (64*1024)
#define ATR_AXI4_SLV_BASE 0x0800
@ -159,6 +163,14 @@
/* Systick count SRAM address DMEM addrs 0x2000F83C, Check this value for any change */
#define SYSTCIK_SRAM_OFFSET 0x4F83C
/* Tx Timer count SRAM address DMEM addrs 0x2000F844, Check this value for any change */
#define TX_TIMER_SRAM_OFFSET_0 0x4F844
/* Tx Timer count SRAM address DMEM addrs 0x2000F848, Check this value for any change */
#define TX_TIMER_SRAM_OFFSET_1 0x4F848
#define TX_TIMER_SRAM_OFFSET(t) (((t) == RM_PF0_ID) ? (TX_TIMER_SRAM_OFFSET_0) : (TX_TIMER_SRAM_OFFSET_1))
#define TC956X_M3_SRAM_EEPROM_MAC_ADDR 0x47000 /* DMEM addrs 0x20007000U */
#define TC956X_M3_SRAM_EEPROM_OFFSET_ADDR 0x47050 /* DMEM addrs 0x20007050U */
#define TC956X_M3_SRAM_EEPROM_MAC_COUNT 0x47051 /* DMEM addrs 0x20007051U */
@ -168,15 +180,9 @@
#define TC956X_M3_DBG_VER_START 0x4F900
#define ENABLE_USXGMII_INTERFACE 0
#define ENABLE_RGMII_INTERFACE 1
#define ENABLE_SGMII_INTERFACE 2
/* Only SGMII and USXGMII allowed for Port0 */
#define PORT0_INTERFACE ENABLE_USXGMII_INTERFACE
//#define PORT0_INTERFACE ENABLE_SGMII_INTERFACE
#define PORT1_INTERFACE ENABLE_RGMII_INTERFACE
#define INTERFACE_SELECTED(p) (((p) == RM_PF0_ID) ? (PORT0_INTERFACE) : (PORT1_INTERFACE))
#define ENABLE_XFI_INTERFACE 1 /* XFI/SFI, this is same as USXGMII, except XPCS autoneg disabled */
#define ENABLE_RGMII_INTERFACE 2
#define ENABLE_SGMII_INTERFACE 3
#define MTL_FPE_AFSZ_64 0
#define MTL_FPE_AFSZ_128 1
@ -200,6 +206,7 @@ struct tc956xmac_resources {
int irq;
#ifdef TC956X
unsigned int port_num;
unsigned int port_interface; /* Kernel module parameter variable for interface */
#endif
};
@ -475,6 +482,8 @@ struct tc956xmac_priv {
u32 port_num;
u32 mac_loopback_mode;
u32 phy_loopback_mode;
bool is_sgmii_2p5g; /* For 2.5G SGMI, XPCS doesn't support AN. This flag is to identify 2.5G Speed for SGMII interface. */
u32 port_interface; /* Kernel module parameter variable for interface */
#endif
/* set to 1 when ptp offload is enabled, else 0. */
@ -498,6 +507,8 @@ struct tc956x_version {
unsigned char major;
unsigned char minor;
unsigned char sub_minor;
unsigned char patch_rel_major;
unsigned char patch_rel_minor;
};
enum tc956xmac_state {

View File

@ -30,6 +30,10 @@
*
* 15 Mar 2021 : Base lined
* VERSION : 01-00
*
* 05 Jul 2021 : 1. Used Systick handler instead of Driver kernel timer to process transmitted Tx descriptors.
* 2. XFI interface support and module parameters for selection of Port0 and Port1 interface
* VERSION : 01-00-01
*/
#include <linux/etherdevice.h>
@ -588,7 +592,15 @@ static const struct tc956xmac_stats tc956xmac_gstrings_stats[] = {
TC956XMAC_STAT(rxch_sw_dirty_rx[5]),
TC956XMAC_STAT(rxch_sw_dirty_rx[6]),
TC956XMAC_STAT(rxch_sw_dirty_rx[7]),
TC956XMAC_STAT(total_interrupts),
TC956XMAC_STAT(lpi_intr_n),
TC956XMAC_STAT(pmt_intr_n),
TC956XMAC_STAT(event_intr_n),
TC956XMAC_STAT(tx_intr_n),
TC956XMAC_STAT(rx_intr_n),
TC956XMAC_STAT(xpcs_intr_n),
TC956XMAC_STAT(phy_intr_n),
TC956XMAC_STAT(sw_msi_n),
};
#define TC956XMAC_STATS_LEN ARRAY_SIZE(tc956xmac_gstrings_stats)
@ -706,7 +718,7 @@ static void tc956xmac_ethtool_getdrvinfo(struct net_device *dev,
#endif
fw_version = (struct tc956x_version *)(&reg);
sprintf(fw_version_str, "Firmware Version %s_%d.%d-%d", (fw_version->rel_dbg == 'D')?"DBG":"REL",
scnprintf(fw_version_str, sizeof(fw_version_str), "Firmware Version %s_%d.%d-%d", (fw_version->rel_dbg == 'D')?"DBG":"REL",
fw_version->major, fw_version->minor,
fw_version->sub_minor);
@ -849,7 +861,11 @@ tc956xmac_ethtool_set_link_ksettings(struct net_device *dev,
return 0;
}
/* Temporary fix (phy dependent code): In case of AQR phy, auto negotiation OFF is not supported, return error for it */
if (priv->port_num == RM_PF0_ID) {
if (cmd->base.autoneg != AUTONEG_ENABLE)
return -EINVAL;
}
if (!dev->phydev)
return -ENODEV;
return phylink_ethtool_ksettings_set(priv->phylink, cmd);

View File

@ -30,6 +30,10 @@
*
* 15 Mar 2021 : Base lined
* VERSION : 01-00
*
* 05 Jul 2021 : 1. Used Systick handler instead of Driver kernel timer to process transmitted Tx descriptors.
* 2. XFI interface support and module parameters for selection of Port0 and Port1 interface
* VERSION : 01-00-01
*/
#ifndef __TC956XMAC_PLATFORM_DATA
@ -43,10 +47,16 @@
//#define TC956X_IOCTL_REG_RD_WR_ENABLE
//#define TC956X_WITHOUT_MDIO
#define TC956X_PCIE_GEN3_SETTING
//#define TC956X_SGMII_2P5_GBPS_TEST /*Enable this macro to test SGMII 2.5Gbps*/
//#define TC956X_PCIE_DISABLE_DSP1 /*Enable this macro to disable DSP1 port*/
//#define TC956X_PCIE_DISABLE_DSP2 /*Enable this macro to disable DSP2 port*/
/* 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 */
/* By default macro is defined and code coverage this macro to be disabled */
#define TC956X_UNSUPPORTED_UNTESTED_FEATURE
@ -280,5 +290,6 @@ struct plat_tc956xmacenet_data {
enum ch_owner tx_dma_ch_owner[MTL_MAX_TX_QUEUES];
enum ch_owner rx_dma_ch_owner[MTL_MAX_RX_QUEUES];
u32 port_num;
u32 port_interface; /* Kernel module parameter variable for interface */
};
#endif

View File

@ -30,6 +30,10 @@
*
* 15 Mar 2021 : Base lined
* VERSION : 01-00
*
* 05 Jul 2021 : 1. Used Systick handler instead of Driver kernel timer to process transmitted Tx descriptors.
* 2. XFI interface support and module parameters for selection of Port0 and Port1 interface
* VERSION : 01-00-01
*/
#include <linux/clk.h>
@ -179,6 +183,98 @@ static uint16_t mdio_bus_id;
#define CONFIG_PARAM_NUM ARRAY_SIZE(config_param_list)
int tc956xmac_rx_parser_configuration(struct tc956xmac_priv *);
#ifdef DUMP_REGISTER
void dump_registers(struct tc956xmac_priv *priv)
{
u32 i, j;
/* Register dump */
printk("CNFREG dump\n");
for (i = 0; i <= 0x1800; i = i+4)
printk("CNFREG 0x4000_%.4x = 0x%x\n", i, readl(priv->ioaddr + i));
printk("--------------------------------------------------------\n");
printk("PMATOP register dump\n");
printk("PMATOP Reg 0x%x = 0x%x\n", 0x441b8, readl(priv->ioaddr + 0x441b8));
printk("PMATOP Reg 0x%x = 0x%x\n", 0x45888, readl(priv->ioaddr + 0x45888));
printk("PMATOP Reg 0x%x = 0x%x\n", 0x45890, readl(priv->ioaddr + 0x45890));
printk("PMATOP Reg 0x%x = 0x%x\n", 0x45898, readl(priv->ioaddr + 0x45898));
printk("PMATOP Reg 0x%x = 0x%x\n", 0x458a0, readl(priv->ioaddr + 0x458a0));
printk("PMATOP Reg 0x%x = 0x%x\n", 0x458a8, readl(priv->ioaddr + 0x458a8));
printk("PMATOP Reg 0x%x = 0x%x\n", 0x45080, readl(priv->ioaddr + 0x45080));
printk("PMATOP Reg 0x%x = 0x%x\n", 0x45090, readl(priv->ioaddr + 0x45090));
printk("PMATOP Reg 0x%x = 0x%x\n", 0x45094, readl(priv->ioaddr + 0x45094));
printk("PMATOP Reg 0x%x = 0x%x\n", 0x450a4, readl(priv->ioaddr + 0x450a4));
printk("PMATOP Reg 0x%x = 0x%x\n", 0x450a8, readl(priv->ioaddr + 0x450a8));
printk("PMATOP Reg 0x%x = 0x%x\n", 0x450b8, readl(priv->ioaddr + 0x450b8));
printk("PMATOP Reg 0x%x = 0x%x\n", 0x450bc, readl(priv->ioaddr + 0x450bc));
printk("PMATOP Reg 0x%x = 0x%x\n", 0x450cc, readl(priv->ioaddr + 0x450cc));
printk("PMATOP Reg 0x%x = 0x%x\n", 0x450d0, readl(priv->ioaddr + 0x450d0));
printk("PMATOP Reg 0x%x = 0x%x\n", 0x450e0, readl(priv->ioaddr + 0x450e0));
printk("PMATOP Reg 0x%x = 0x%x\n", XGMAC_PMA_GL_PM_CFG0, readl(priv->pmaaddr + XGMAC_PMA_GL_PM_CFG0));
printk("PMATOP Reg 0x%x = 0x%x\n", XGMAC_PMA_CFG_0_1_R0, readl(priv->pmaaddr + XGMAC_PMA_CFG_0_1_R0));
printk("PMATOP Reg 0x%x = 0x%x\n", XGMAC_PMA_CFG_0_1_R1, readl(priv->pmaaddr + XGMAC_PMA_CFG_0_1_R1));
printk("PMATOP Reg 0x%x = 0x%x\n", XGMAC_PMA_CFG_0_1_R2, readl(priv->pmaaddr + XGMAC_PMA_CFG_0_1_R2));
printk("PMATOP Reg 0x%x = 0x%x\n", XGMAC_PMA_CFG_0_1_R3, readl(priv->pmaaddr + XGMAC_PMA_CFG_0_1_R3));
printk("PMATOP Reg 0x%x = 0x%x\n", XGMAC_PMA_CFG_0_1_R4, readl(priv->pmaaddr + XGMAC_PMA_CFG_0_1_R4));
printk("PMATOP Reg 0x%x = 0x%x\n", XGMAC_PMA_HWT_REFCK_EN_R0, readl(priv->pmaaddr + XGMAC_PMA_HWT_REFCK_EN_R0));
printk("PMATOP Reg 0x%x = 0x%x\n", XGMAC_PMA_HWT_REFCK_TERM_EN_R0, readl(priv->pmaaddr + XGMAC_PMA_HWT_REFCK_TERM_EN_R0));
printk("PMATOP Reg 0x%x = 0x%x\n", XGMAC_PMA_HWT_REFCK_R_EN_R1, readl(priv->pmaaddr + XGMAC_PMA_HWT_REFCK_R_EN_R1));
printk("PMATOP Reg 0x%x = 0x%x\n", XGMAC_PMA_HWT_REFCK_TERM_EN_R1, readl(priv->pmaaddr + XGMAC_PMA_HWT_REFCK_TERM_EN_R1));
printk("PMATOP Reg 0x%x = 0x%x\n", XGMAC_PMA_HWT_REFCK_R_EN_R2, readl(priv->pmaaddr + XGMAC_PMA_HWT_REFCK_R_EN_R2));
printk("PMATOP Reg 0x%x = 0x%x\n", XGMAC_PMA_HWT_REFCK_TERM_EN_R2, readl(priv->pmaaddr + XGMAC_PMA_HWT_REFCK_TERM_EN_R2));
printk("PMATOP Reg 0x%x = 0x%x\n", XGMAC_PMA_HWT_REFCK_R_EN_R3, readl(priv->pmaaddr + XGMAC_PMA_HWT_REFCK_R_EN_R3));
printk("PMATOP Reg 0x%x = 0x%x\n", XGMAC_PMA_HWT_REFCK_TERM_EN_R3, readl(priv->pmaaddr + XGMAC_PMA_HWT_REFCK_TERM_EN_R3));
printk("PMATOP Reg 0x%x = 0x%x\n", XGMAC_PMA_HWT_REFCK_R_EN_R4, readl(priv->pmaaddr + XGMAC_PMA_HWT_REFCK_R_EN_R4));
printk("PMATOP Reg 0x%x = 0x%x\n", XGMAC_PMA_HWT_REFCK_TERM_EN_R4, readl(priv->pmaaddr + XGMAC_PMA_HWT_REFCK_TERM_EN_R4));
printk("--------------------------------------------------------\n");
printk("XPCS register dump\n");
printk("XPCS Reg 0x%x = 0x%x\n", XGMAC_SR_MII_CTRL, tc956x_xpcs_read(priv->xpcsaddr, XGMAC_SR_MII_CTRL));
printk("XPCS Reg 0x%x = 0x%x\n", XGMAC_VR_MII_AN_CTRL, tc956x_xpcs_read(priv->xpcsaddr, XGMAC_VR_MII_AN_CTRL));
printk("XPCS Reg 0x%x = 0x%x\n", XGMAC_VR_MII_DIG_CTRL1, tc956x_xpcs_read(priv->xpcsaddr, XGMAC_VR_MII_DIG_CTRL1));
printk("XPCS Reg 0x%x = 0x%x\n", XGMAC_SR_XS_PCS_CTRL2, tc956x_xpcs_read(priv->xpcsaddr, XGMAC_SR_XS_PCS_CTRL2));
printk("XPCS Reg 0x%x = 0x%x\n", XGMAC_VR_XS_PCS_DIG_CTRL1, tc956x_xpcs_read(priv->xpcsaddr, XGMAC_VR_XS_PCS_DIG_CTRL1));
printk("XPCS Reg 0x%x = 0x%x\n", XGMAC_VR_XS_PCS_KR_CTRL, tc956x_xpcs_read(priv->xpcsaddr, XGMAC_VR_XS_PCS_KR_CTRL));
printk("XPCS Reg 0x%x = 0x%x\n", XGMAC_VR_MII_AN_INTR_STS, tc956x_xpcs_read(priv->xpcsaddr, XGMAC_VR_MII_AN_INTR_STS));
printk("--------------------------------------------------------\n");
printk("XGMAC-MAC register dump\n");
for (i = 0; i <= 0x810; i = i+4)
printk("XGMAC MAC Reg 0x400%.5x = 0x%x\n", MAC_OFFSET + i, readl(priv->ioaddr + MAC_OFFSET + i));
printk("--------------------------------------------------------\n");
printk("XGMAC-MTL register dump\n");
for (i = 0x1000; i <= 0x10B4; i = i+4)
printk("XGMAC MTL Reg 0x400%.5x = 0x%x\n", MAC_OFFSET + i, readl(priv->ioaddr + MAC_OFFSET + i));
for (i = 0x1100; i <= 0x1174; i = i+4) {
for (j = 0; j < 2; j++)
printk("XGMAC MTL Reg 0x400%.5x = 0x%x\n", MAC_OFFSET + i + (j*0x80), readl(priv->ioaddr + MAC_OFFSET + i + (j*0x80) ));
}
printk("--------------------------------------------------------\n");
printk("XGMAC-DMA register dump\n");
for (i = 0x3000; i <= 0x3084; i = i+4)
printk("XGMAC DMA Reg 0x400%.5x = 0x%x\n", MAC_OFFSET + i, readl(priv->ioaddr + MAC_OFFSET + i));
for (i = 0x3100; i <= 0x317c; i = i+4) {
for (j = 0; j < 2; j++)
printk("XGMAC DMA Reg 0x400%.5x = 0x%x\n", MAC_OFFSET + i + (j*0x80), readl(priv->ioaddr + MAC_OFFSET + i + (j*0x80) ));
}
printk("--------------------------------------------------------\n");
}
#endif
/**
* tc956xmac_verify_args - verify the driver parameters.
* Description: it checks the driver parameters and set a default in case of
@ -1156,7 +1252,8 @@ static void tc956xmac_mac_pcs_get_state(struct phylink_config *config,
reg_value = tc956x_xpcs_read(priv->xpcsaddr, XGMAC_VR_MII_AN_INTR_STS);
if (reg_value & XGMAC_C37_AN_COMPL) {/*check if AN 37 is complete CL37_ANCMPLT_INTR*/
KPRINT_INFO("AN clause 37 completed");
if (priv->plat->interface == PHY_INTERFACE_MODE_USXGMII) {
if ((priv->plat->interface == PHY_INTERFACE_MODE_USXGMII) ||
(priv->plat->interface == PHY_INTERFACE_MODE_10GKR)) {
if (reg_value & XGMAC_USXG_AN_STS_LINK_MASK) {/*check link status*/
state->link = 1;
KPRINT_INFO("XPCS USXGMII link up");
@ -1187,13 +1284,12 @@ static void tc956xmac_mac_pcs_get_state(struct phylink_config *config,
else
state->duplex = DUPLEX_HALF;
if (((reg_value & XGMAC_SGM_STS_SPEED_MASK) >> 2) == 0x2)/*SGMII autonegotiated speed */
#ifndef TC956X_SGMII_2P5_GBPS_TEST
state->speed = SPEED_1000;
#else
state->speed = SPEED_2500; /*There is no seperate bit check for 2.5Gbps, so set here */
#endif
else if (((reg_value & XGMAC_SGM_STS_SPEED_MASK) >> 2) == 0x1)
if (((reg_value & XGMAC_SGM_STS_SPEED_MASK) >> 2) == 0x2) {/*SGMII autonegotiated speed */
if (priv->is_sgmii_2p5g == true)
state->speed = SPEED_2500; /*There is no seperate bit check for 2.5Gbps, so set here */
else
state->speed = SPEED_1000;
} else if (((reg_value & XGMAC_SGM_STS_SPEED_MASK) >> 2) == 0x1)
state->speed = SPEED_100;
} else {
state->link = 0;
@ -1216,7 +1312,8 @@ static int tc956xmac_mac_link_state(struct phylink_config *config,
reg_value = tc956x_xpcs_read(priv->xpcsaddr, XGMAC_VR_MII_AN_INTR_STS);
if (reg_value & XGMAC_C37_AN_COMPL) {/*check if AN 37 is complete CL37_ANCMPLT_INTR*/
KPRINT_INFO("AN clause 37 completed");
if (priv->plat->interface == PHY_INTERFACE_MODE_USXGMII) {
if ((priv->plat->interface == PHY_INTERFACE_MODE_USXGMII) ||
(priv->plat->interface == PHY_INTERFACE_MODE_10GKR)) {
if (reg_value & XGMAC_USXG_AN_STS_LINK_MASK) {/*check link status*/
state->link = 1;
KPRINT_INFO("XPCS USXGMII link up");
@ -1251,15 +1348,12 @@ static int tc956xmac_mac_link_state(struct phylink_config *config,
else
state->duplex = DUPLEX_HALF;
/*SGMII autonegotiated speed */
if (((reg_value & XGMAC_SGM_STS_SPEED_MASK) >> 2) == 0x2)
#ifndef TC956X_SGMII_2P5_GBPS_TEST
state->speed = SPEED_1000;
#else
/*There is no seperate bit check for 2.5Gbps, so set here */
state->speed = SPEED_2500;
#endif
else if (((reg_value & XGMAC_SGM_STS_SPEED_MASK) >> 2) == 0x1)
if (((reg_value & XGMAC_SGM_STS_SPEED_MASK) >> 2) == 0x2) {
if (priv->is_sgmii_2p5g == true)
state->speed = SPEED_2500; /*There is no seperate bit check for 2.5Gbps, so set here */
else
state->speed = SPEED_1000;
} else if (((reg_value & XGMAC_SGM_STS_SPEED_MASK) >> 2) == 0x1)
state->speed = SPEED_100;
} else {
state->link = 0;
@ -1273,6 +1367,137 @@ static int tc956xmac_mac_link_state(struct phylink_config *config,
}
#endif
/**
* tc956xmac_speed_change_init_mac - Initialize MAC during speed change.
* @priv: driver private structure
* @state : phy state structure
* Description: It is used for initializing MAC during speed change of
* USXGMII and SGMII.
*/
void tc956xmac_speed_change_init_mac(struct tc956xmac_priv *priv,
const struct phylink_link_state *state)
{
/* use signal from EMSPHY */
uint8_t SgmSigPol = 0;
int ret = 0;
bool enable_an = true;
if (priv->port_num == RM_PF0_ID) {
/* Enable all clocks to eMAC Port0 */
ret = readl(priv->tc956x_SFR_pci_base_addr + NCLKCTRL0_OFFSET);
if ((state->interface == PHY_INTERFACE_MODE_SGMII) &&
(state->speed == SPEED_2500)) {
ret &= ~NCLKCTRL0_MAC0125CLKEN;
ret &= ~NCLKCTRL0_MAC0312CLKEN;
}
writel(ret, priv->tc956x_SFR_pci_base_addr + NCLKCTRL0_OFFSET);
/* Interface configuration for port0*/
ret = readl(priv->tc956x_SFR_pci_base_addr + NEMAC0CTL_OFFSET);
ret &= ~(NEMACCTL_SP_SEL_MASK | NEMACCTL_PHY_INF_SEL_MASK);
if (state->interface == PHY_INTERFACE_MODE_SGMII) {
if (state->speed == SPEED_2500)
ret |= NEMACCTL_SP_SEL_SGMII_2500M;
else
ret |= NEMACCTL_SP_SEL_SGMII_1000M;
}
ret &= ~(0x00000040); /* Mask Polarity */
if (SgmSigPol == 1)
ret |= 0x00000040; /* Set Active low */
ret |= (NEMACCTL_PHY_INF_SEL | NEMACCTL_LPIHWCLKEN);
writel(ret, priv->tc956x_SFR_pci_base_addr + NEMAC0CTL_OFFSET);
}
if (priv->port_num == RM_PF1_ID) {
/* Enable all clocks to eMAC Port1 */
ret = readl(priv->tc956x_SFR_pci_base_addr + NCLKCTRL1_OFFSET);
if ((state->interface == PHY_INTERFACE_MODE_SGMII) &&
(state->speed == SPEED_2500)) {
ret &= ~NCLKCTRL1_MAC1125CLKEN1;
ret &= ~NCLKCTRL1_MAC1312CLKEN1;
} else {
ret &= ~NCLKCTRL1_MAC1312CLKEN1;
ret |= NCLKCTRL1_MAC1125CLKEN1;
}
writel(ret, priv->tc956x_SFR_pci_base_addr + NCLKCTRL1_OFFSET);
/* Interface configuration for port1*/
ret = readl(priv->tc956x_SFR_pci_base_addr + NEMAC1CTL_OFFSET);
ret &= ~(NEMACCTL_SP_SEL_MASK | NEMACCTL_PHY_INF_SEL_MASK);
if (state->interface == PHY_INTERFACE_MODE_SGMII) {
if (state->speed == SPEED_2500)
ret |= NEMACCTL_SP_SEL_SGMII_2500M;
else
ret |= NEMACCTL_SP_SEL_SGMII_1000M;
}
ret &= ~(0x00000040); /* Mask Polarity */
if (SgmSigPol == 1)
ret |= 0x00000040; /* Set Active low */
ret |= (NEMACCTL_PHY_INF_SEL | NEMACCTL_LPIHWCLKEN);
writel(ret, priv->tc956x_SFR_pci_base_addr + NEMAC1CTL_OFFSET);
}
/*PMA module init*/
if (priv->hw->xpcs) {
if (priv->port_num == RM_PF0_ID) {
/* Assertion of PMA & XPCS reset software Reset*/
ret = readl(priv->ioaddr + NRSTCTRL0_OFFSET);
ret |= (NRSTCTRL0_MAC0PMARST | NRSTCTRL0_MAC0PONRST);
writel(ret, priv->ioaddr + NRSTCTRL0_OFFSET);
}
if (priv->port_num == RM_PF1_ID) {
/* Assertion of PMA & XPCS reset software Reset*/
ret = readl(priv->ioaddr + NRSTCTRL1_OFFSET);
ret |= (NRSTCTRL1_MAC1PMARST1 | NRSTCTRL1_MAC1PONRST1);
writel(ret, priv->ioaddr + NRSTCTRL1_OFFSET);
}
ret = tc956x_pma_setup(priv, priv->pmaaddr);
if (ret < 0)
KPRINT_ERR("PMA switching to internal clock Failed\n");
if (priv->port_num == RM_PF0_ID) {
/* De-assertion of PMA & XPCS reset software Reset*/
ret = readl(priv->ioaddr + NRSTCTRL0_OFFSET);
ret &= ~(NRSTCTRL0_MAC0PMARST | NRSTCTRL0_MAC0PONRST);
writel(ret, priv->ioaddr + NRSTCTRL0_OFFSET);
}
if (priv->port_num == RM_PF1_ID) {
/* De-assertion of PMA & XPCS reset software Reset*/
ret = readl(priv->ioaddr + NRSTCTRL1_OFFSET);
ret &= ~(NRSTCTRL1_MAC1PMARST1 | NRSTCTRL1_MAC1PONRST1);
writel(ret, priv->ioaddr + NRSTCTRL1_OFFSET);
}
if (priv->port_num == RM_PF0_ID) {
do {
ret = readl(priv->ioaddr + NEMAC0CTL_OFFSET);
} while ((NEMACCTL_INIT_DONE & ret) != NEMACCTL_INIT_DONE);
}
if (priv->port_num == RM_PF1_ID) {
do {
ret = readl(priv->ioaddr + NEMAC1CTL_OFFSET);
} while ((NEMACCTL_INIT_DONE & ret) != NEMACCTL_INIT_DONE);
}
if ((state->interface == PHY_INTERFACE_MODE_SGMII)
&& (state->speed == SPEED_2500)) {
/* XPCS doesn't support AN for 2.5G SGMII.
* Disable AN only if SGMII 2.5G is Enabled.
*/
priv->is_sgmii_2p5g = true;
enable_an = false;
} else {
priv->is_sgmii_2p5g = false;
enable_an = true;
}
ret = tc956x_xpcs_init(priv, priv->xpcsaddr);
if (ret < 0)
KPRINT_INFO("XPCS initialization error\n");
tc956x_xpcs_ctrl_ane(priv, enable_an);
}
}
static void tc956xmac_mac_config(struct phylink_config *config, unsigned int mode,
const struct phylink_link_state *state)
{
@ -1330,34 +1555,53 @@ static void tc956xmac_mac_config(struct phylink_config *config, unsigned int mod
val = tc956x_xpcs_read(priv->xpcsaddr, XGMAC_VR_XS_PCS_DIG_CTRL1);
val |= XGMAC_USRA_RST;
tc956x_xpcs_write(priv->xpcsaddr, XGMAC_VR_XS_PCS_DIG_CTRL1, val);
} else if (state->interface == PHY_INTERFACE_MODE_SGMII) {
#if defined(TC956X) && defined(TC956X_SGMII_2P5_GBPS_TEST)
/* Program autonegotiated speed to SR_MII_CTRL */
val = tc956x_xpcs_read(priv->xpcsaddr, XGMAC_SR_MII_CTRL);
val &= ~XGMAC_SR_MII_CTRL_SPEED; /* Mask speed ss13, ss6, ss5 */
#endif
switch (state->speed) {
case SPEED_2500:
ctrl |= priv->hw->link.speed2500;
#if defined(TC956X) && defined(TC956X_SGMII_2P5_GBPS_TEST)
val |= 0x40; /*1000 Mbps setting only available, so set the same*/
#endif
emac_ctrl |= NEMACCTL_SP_SEL_SGMII_2500M;
break;
case SPEED_1000:
ctrl |= priv->hw->link.speed1000;
emac_ctrl |= NEMACCTL_SP_SEL_SGMII_1000M;
break;
default:
return;
}
#if defined(TC956X) && defined(TC956X_SGMII_2P5_GBPS_TEST)
tc956x_xpcs_write(priv->xpcsaddr, XGMAC_SR_MII_CTRL, val);
#endif
config_done = true;
}
}
if (state->interface == PHY_INTERFACE_MODE_SGMII) { /* Autonegotiation not supported for SGMII */
reg_value = tc956x_xpcs_read(priv->xpcsaddr, XGMAC_VR_MII_AN_INTR_STS);
/* Clear autonegotiation only if completed. As for XPCS, 2.5G autonegotiation is not supported */
/* Switching from SGMII 2.5G to any speed doesn't cause AN completion */
if (reg_value & XGMAC_C37_AN_COMPL) {/*check if AN 37 is complete CL37_ANCMPLT_INTR*/
KPRINT_INFO("AN clause 37 completed");
reg_value &= ~(XGMAC_C37_AN_COMPL);
tc956x_xpcs_write(priv->xpcsaddr, XGMAC_VR_MII_AN_INTR_STS, reg_value);
KPRINT_INFO("AN clause 37 complete bit cleared");
}
/* Invoke this only during speed change */
if ((state->speed != SPEED_UNKNOWN) || (state->speed != 0)) {
if (state->speed != priv->speed) {
tc956xmac_speed_change_init_mac(priv, state);
}
}
val = tc956x_xpcs_read(priv->xpcsaddr, XGMAC_SR_MII_CTRL);
val &= ~XGMAC_SR_MII_CTRL_SPEED; /* Mask speed ss13, ss6, ss5 */
switch (state->speed) {
case SPEED_2500:
ctrl |= priv->hw->link.speed2500;
/* Program autonegotiated speed to SR_MII_CTRL */
val |= XPCS_SS_SGMII_1G; /*1000 Mbps setting only available, so set the same*/
emac_ctrl |= NEMACCTL_SP_SEL_SGMII_2500M;
break;
case SPEED_1000:
ctrl |= priv->hw->link.speed1000;
val |= XPCS_SS_SGMII_1G; /*1000 Mbps setting only available, so set the same*/
emac_ctrl |= NEMACCTL_SP_SEL_SGMII_1000M;
break;
case SPEED_100:
ctrl |= priv->hw->link.speed100;
val |= XPCS_SS_SGMII_100M; /*100 Mbps setting */
emac_ctrl |= NEMACCTL_SP_SEL_SGMII_100M;
break;
case SPEED_10:
ctrl |= priv->hw->link.speed10;
val |= XPCS_SS_SGMII_10M; /*10 Mbps setting */
emac_ctrl |= NEMACCTL_SP_SEL_SGMII_10M;
break;
default:
return;
}
tc956x_xpcs_write(priv->xpcsaddr, XGMAC_SR_MII_CTRL, val);
config_done = true;
}
} else if (state->interface == PHY_INTERFACE_MODE_RGMII) {
@ -1423,10 +1667,26 @@ static void tc956xmac_mac_an_restart(struct phylink_config *config)
{
#ifdef TC956X
struct tc956xmac_priv *priv = netdev_priv(to_net_dev(config->dev));
bool enable_en = true;
if (priv->hw->xpcs) {
/*Enable XPCS Autoneg*/
tc956x_xpcs_ctrl_ane(priv, 1);
if (priv->plat->interface == PHY_INTERFACE_MODE_10GKR) {
enable_en = false;
KPRINT_INFO("%s :Port %d AN Enable:%d", __func__, priv->port_num, enable_en);
} else if (priv->plat->interface == PHY_INTERFACE_MODE_SGMII) {
if (priv->is_sgmii_2p5g == true) {
enable_en = false;
KPRINT_INFO("%s : Port %d AN Enable:%d", __func__, priv->port_num, enable_en);
} else {
enable_en = true;
KPRINT_INFO("%s : Port %d AN Enable:%d", __func__, priv->port_num, enable_en);
}
} else {
enable_en = true;
KPRINT_INFO("%s : Port %d AN Enable:%d", __func__, priv->port_num, enable_en);
}
tc956x_xpcs_ctrl_ane(priv, enable_en);
}
#else
/*Not supported*/
@ -1498,8 +1758,9 @@ static void tc956xmac_check_pcs_mode(struct tc956xmac_priv *priv)
#ifdef TC956X
priv->hw->pcs = TC956XMAC_PCS_SGMII;
#endif
} else if (interface == PHY_INTERFACE_MODE_USXGMII) {
netdev_dbg(priv->dev, "PCS USXGMII support enabled\n");
} else if ((interface == PHY_INTERFACE_MODE_USXGMII) ||
(interface == PHY_INTERFACE_MODE_10GKR)) {
netdev_dbg(priv->dev, "PCS USXGMII/XFI support enabled\n");
#ifdef TC956X
priv->hw->pcs = TC956XMAC_PCS_USXGMII;
#endif
@ -1512,7 +1773,8 @@ static void tc956xmac_check_pcs_mode(struct tc956xmac_priv *priv)
} else if (interface == PHY_INTERFACE_MODE_SGMII) {
netdev_dbg(priv->dev, "PCS SGMII support enabled\n");
priv->hw->xpcs = TC956XMAC_PCS_SGMII;
} else if (interface == PHY_INTERFACE_MODE_USXGMII) {
} else if ((interface == PHY_INTERFACE_MODE_USXGMII) ||
(interface == PHY_INTERFACE_MODE_10GKR)) {
netdev_dbg(priv->dev, "PCS USXGMII support enabled\n");
priv->hw->xpcs = TC956XMAC_PCS_USXGMII;
}
@ -2661,10 +2923,11 @@ static int tc956xmac_tx_clean(struct tc956xmac_priv *priv, int budget, u32 queue
mod_timer(&priv->eee_ctrl_timer, TC956XMAC_LPI_T(eee_timer));
}
#ifdef ENABLE_TX_TIMER
/* We still have pending packets, let's call for a new scheduling */
if (tx_q->dirty_tx != tx_q->cur_tx)
mod_timer(&tx_q->txtimer, TC956XMAC_COAL_TIMER(priv->tx_coal_timer));
#endif
__netif_tx_unlock_bh(netdev_get_tx_queue(priv->dev, queue));
return count;
@ -2808,6 +3071,11 @@ static int tc956xmac_napi_check(struct tc956xmac_priv *priv, u32 chan)
if ((status & handle_tx) && (chan < priv->plat->tx_queues_to_use) &&
(priv->plat->tx_dma_ch_owner[chan] == USE_IN_TC956X_SW)) {
#ifdef TX_COMPLETION_WITHOUT_TIMERS
writel(0, priv->tc956x_SRAM_pci_base_addr
+ TX_TIMER_SRAM_OFFSET(priv->port_num));
#endif
if (napi_schedule_prep(&ch->tx_napi)) {
spin_lock_irqsave(&ch->lock, flags);
tc956xmac_disable_dma_irq(priv, priv->ioaddr, chan, 0, 1);
@ -2999,6 +3267,7 @@ static int tc956xmac_init_dma_engine(struct tc956xmac_priv *priv)
return ret;
}
#ifdef ENABLE_TX_TIMER
static void tc956xmac_tx_timer_arm(struct tc956xmac_priv *priv, u32 queue)
{
struct tc956xmac_tx_queue *tx_q = &priv->tx_queue[queue];
@ -3037,6 +3306,8 @@ static void tc956xmac_tx_timer(struct timer_list *t)
}
}
#endif
/**
* tc956xmac_init_coalesce - init mitigation options.
* @priv: driver private structure
@ -3047,13 +3318,15 @@ static void tc956xmac_tx_timer(struct timer_list *t)
*/
static void tc956xmac_init_coalesce(struct tc956xmac_priv *priv)
{
#ifdef ENABLE_TX_TIMER
u32 tx_channel_count = priv->plat->tx_queues_to_use;
u32 chan;
#endif
priv->tx_coal_frames = TC956XMAC_TX_FRAMES;
priv->tx_coal_timer = TC956XMAC_COAL_TX_TIMER;
priv->rx_coal_frames = TC956XMAC_RX_FRAMES;
#ifdef ENABLE_TX_TIMER
for (chan = 0; chan < tx_channel_count; chan++) {
struct tc956xmac_tx_queue *tx_q = &priv->tx_queue[chan];
@ -3061,6 +3334,7 @@ static void tc956xmac_init_coalesce(struct tc956xmac_priv *priv)
continue;
timer_setup(&tx_q->txtimer, tc956xmac_tx_timer, 0);
}
#endif
}
static void tc956xmac_set_rings_length(struct tc956xmac_priv *priv)
@ -3336,6 +3610,7 @@ static int tc956xmac_hw_setup(struct net_device *dev, bool init_ptp)
struct tc956xmac_priv *priv = netdev_priv(dev);
#ifdef TC956X
u32 rx_cnt = priv->plat->rx_queues_to_use;
bool enable_en = true;
#endif
u32 tx_cnt = priv->plat->tx_queues_to_use;
@ -3428,9 +3703,19 @@ static int tc956xmac_hw_setup(struct net_device *dev, bool init_ptp)
}
#ifdef TC956X
if (priv->hw->xpcs)
if (priv->hw->xpcs) {
/*C37 AN enable*/
tc956x_xpcs_ctrl_ane(priv, 1);
if (priv->plat->interface == PHY_INTERFACE_MODE_10GKR)
enable_en = false;
else if (priv->plat->interface == PHY_INTERFACE_MODE_SGMII) {
if (priv->is_sgmii_2p5g == true)
enable_en = false;
else
enable_en = true;
} else
enable_en = true;
tc956x_xpcs_ctrl_ane(priv, enable_en);
}
#else
if (priv->hw->pcs)
tc956xmac_pcs_ctrl_ane(priv, priv->ioaddr, 1, priv->hw->ps, 0);
@ -3625,8 +3910,21 @@ static int tc956xmac_open(struct net_device *dev)
rd_val |= (1 << (MSI_INT_RX_CH0 + chan));
}
/* PHY MSI interrupt diabled */
rd_val |= (1 << MSI_INT_EXT_PHY);
/* Disable MAC Event and XPCS interrupt */
rd_val = ENABLE_MSI_INTR & (~rd_val);
#ifdef TC956X_SW_MSI
/* Enable SW MSI interrupt */
KPRINT_INFO("%s Enable SW MSI", __func__);
rd_val |= (1 << MSI_INT_SW_MSI);
/*Clear SW MSI*/
writel(1, priv->ioaddr + TC956X_MSI_SW_MSI_CLR(priv->port_num));
#endif
writel(rd_val, priv->ioaddr + TC956X_MSI_OUT_EN_OFFSET(priv->port_num)); /* MSI_OUT_EN: Enable All mac int */
#endif
@ -3688,8 +3986,13 @@ static int tc956xmac_open(struct net_device *dev)
/* MSI_MASK_CLR: unmask vector 0 */
writel(0x00000001, priv->ioaddr + TC956X_MSI_MASK_CLR_OFFSET(priv->port_num));
#ifdef TX_COMPLETION_WITHOUT_TIMERS
writel(0, priv->tc956x_SRAM_pci_base_addr
+ TX_TIMER_SRAM_OFFSET(priv->port_num));
#endif
#endif
return 0;
#ifndef TC956X
lpiirq_error:
@ -3700,12 +4003,12 @@ static int tc956xmac_open(struct net_device *dev)
#endif
irq_error:
phylink_stop(priv->phylink);
#ifdef ENABLE_TX_TIMER
for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) {
if (priv->plat->tx_dma_ch_owner[chan] == USE_IN_TC956X_SW)
del_timer_sync(&priv->tx_queue[chan].txtimer);
}
#endif
tc956xmac_hw_teardown(dev);
init_error:
free_dma_desc_resources(priv);
@ -3723,8 +4026,14 @@ static int tc956xmac_open(struct net_device *dev)
static int tc956xmac_release(struct net_device *dev)
{
struct tc956xmac_priv *priv = netdev_priv(dev);
#ifdef ENABLE_TX_TIMER
u32 chan;
#endif
#ifdef TX_COMPLETION_WITHOUT_TIMERS
writel(0, priv->tc956x_SRAM_pci_base_addr
+ TX_TIMER_SRAM_OFFSET(priv->port_num));
#endif
if (priv->eee_enabled)
del_timer_sync(&priv->eee_ctrl_timer);
@ -3736,12 +4045,12 @@ static int tc956xmac_release(struct net_device *dev)
tc956xmac_stop_all_queues(priv);
tc956xmac_disable_all_queues(priv);
#ifdef ENABLE_TX_TIMER
for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) {
if (priv->plat->tx_dma_ch_owner[chan] == USE_IN_TC956X_SW)
del_timer_sync(&priv->tx_queue[chan].txtimer);
}
#endif
/* Free the IRQ lines */
free_irq(dev->irq, dev);
@ -4109,8 +4418,14 @@ static netdev_tx_t tc956xmac_tso_xmit(struct sk_buff *skb, struct net_device *de
tx_q->tx_tail_addr = tx_q->dma_tx_phy + (tx_q->cur_tx * desc_size);
tc956xmac_set_tx_tail_ptr(priv, priv->ioaddr, tx_q->tx_tail_addr, queue);
#ifdef ENABLE_TX_TIMER
tc956xmac_tx_timer_arm(priv, queue);
#endif
#ifdef TX_COMPLETION_WITHOUT_TIMERS
writel(1, priv->tc956x_SRAM_pci_base_addr
+ TX_TIMER_SRAM_OFFSET(priv->port_num));
#endif
return NETDEV_TX_OK;
dma_map_err:
@ -4446,7 +4761,15 @@ static netdev_tx_t tc956xmac_xmit(struct sk_buff *skb, struct net_device *dev)
tx_q->tx_tail_addr = tx_q->dma_tx_phy + (tx_q->cur_tx * desc_size);
tc956xmac_set_tx_tail_ptr(priv, priv->ioaddr, tx_q->tx_tail_addr, queue);
#ifdef ENABLE_TX_TIMER
tc956xmac_tx_timer_arm(priv, queue);
#endif
#ifdef TX_COMPLETION_WITHOUT_TIMERS
writel(1, priv->tc956x_SRAM_pci_base_addr
+ TX_TIMER_SRAM_OFFSET(priv->port_num));
#endif
return NETDEV_TX_OK;
@ -5052,6 +5375,34 @@ static irqreturn_t tc956xmac_interrupt(int irq, void *dev_id)
if (tc956xmac_safety_feat_interrupt(priv))
return IRQ_HANDLED;
val = readl(priv->ioaddr + TC956X_MSI_INT_STS_OFFSET(priv->port_num));
priv->xstats.total_interrupts++;
if (val & (1 << 0))
priv->xstats.lpi_intr_n++;
if (val & (1 << 1))
priv->xstats.pmt_intr_n++;
if (val & (1 << 2))
priv->xstats.event_intr_n++;
if (val & (0xFF << 3))
priv->xstats.tx_intr_n++;
if (val & (0xFF << 11))
priv->xstats.rx_intr_n++;
if (val & (1 << 19))
priv->xstats.xpcs_intr_n++;
if (val & (1 << 20))
priv->xstats.phy_intr_n++;
if (val & (1 << 24))
priv->xstats.sw_msi_n++;
/* To handle GMAC own interrupts */
if ((priv->plat->has_gmac) || xmac) {
int status = tc956xmac_host_irq_status(priv, priv->hw, &priv->xstats);
@ -5094,6 +5445,19 @@ static irqreturn_t tc956xmac_interrupt(int irq, void *dev_id)
val = readl(priv->ioaddr + TC956X_MSI_INT_STS_OFFSET(priv->port_num));
if (val & TC956X_EXT_PHY_ETH_INT)
phy_mac_interrupt(priv->dev->phydev);
#ifdef TC956X_SW_MSI
if (val & TC956X_SW_MSI_INT) {
//DBGPR_FUNC(priv->device, "%s SW MSI INT STS[%08x]\n", __func__, val);
/*Clear SW MSI*/
writel(1, priv->ioaddr + TC956X_MSI_SW_MSI_CLR(priv->port_num));
val = readl(priv->ioaddr + TC956X_MSI_SW_MSI_CLR(priv->port_num));
//DBGPR_FUNC(priv->device, "%s SW MSI INT CLR[%08x]\n", __func__, val);
}
#endif
#ifdef TC956X
/* MSI_MSK_CLR, unmask vector 0 */
@ -9092,30 +9456,6 @@ static unsigned char tc956x_get_rx_channel_count(struct tc956xmac_resources *res
#endif
#ifndef EEPROM_MAC_ADDR
/*!
* \brief API to kernel read from file
*
* \param[in] file - pointer to file descriptor
* \param[in] offset - Offset of file to start read
* \param[in] size - Size of the buffer to be read
*
* \param[out] data - File data buffer
*
*
* \return integer
*
* \retval 0 on success & -ve number on failure.
*/
static int file_read(struct file *file, unsigned long long offset,
unsigned char *data, unsigned int size)
{
int ret;
ret = kernel_read(file, (void *)data, size, &offset);
return ret;
}
/*!
* \brief API to validate MAC ID
*
@ -9273,29 +9613,24 @@ static bool lookfor_macid(char *file_buf)
*/
static void parse_config_file(void)
{
struct file *filep = NULL;
char *data = kmalloc(1000, GFP_KERNEL);
int ret, flags = O_RDONLY, i = 0;
mm_segment_t oldfs;
void *data;
char *cdata;
int ret, i;
loff_t size;
KPRINT_INFO("-->%s", __func__);
oldfs = get_fs();
set_fs(KERNEL_DS);
filep = filp_open("config.ini", flags, 0600);
set_fs(oldfs);
if (IS_ERR(filep)) {
ret = kernel_read_file_from_path("config.ini", &data, &size, 1000, READING_POLICY);
if (ret < 0) {
KPRINT_ERR("Mac configuration file not found\n");
KPRINT_INFO("Using Default MAC Address\n");
return;
} else {
cdata = data;
/* Parse the file */
ret = file_read(filep, 0, data, 1000);
for (i = 0; i < CONFIG_PARAM_NUM; i++) {
if (strstr((const char *)data, config_param_list[i]
.mdio_key)) {
if (strstr((const char *)cdata, config_param_list[i].mdio_key)) {
KPRINT_DEBUG1("Pattern Match\n");
if (strncmp(config_param_list[i].mdio_key,
"MDIOBUSID", 9) == 0) {
if (strncmp(config_param_list[i].mdio_key, "MDIOBUSID", 9) == 0) {
/* MAC ID Configuration */
KPRINT_DEBUG1("MAC_ID Configuration\n");
lookfor_macid(data);
@ -9304,10 +9639,11 @@ static void parse_config_file(void)
}
}
kfree(data);
filp_close(filep, NULL);
vfree(data);
KPRINT_INFO("<--%s", __func__);
}
#endif
/**
@ -9383,11 +9719,14 @@ int tc956xmac_dvr_probe(struct device *device,
#endif
priv->port_num = res->port_num;
priv->dev->base_addr = (unsigned long)res->addr;
if (priv->plat->interface == PHY_INTERFACE_MODE_SGMII)
priv->is_sgmii_2p5g = true;
else
priv->is_sgmii_2p5g = false;
priv->dev->irq = res->irq;
priv->wol_irq = res->wol_irq;
priv->lpi_irq = res->lpi_irq;
priv->port_interface = res->port_interface;
#ifdef DMA_OFFLOAD_ENABLE
priv->client_priv = NULL;
#endif

View File

@ -30,6 +30,10 @@
*
* 15 Mar 2021 : Base lined
* VERSION : 01-00
*
* 05 Jul 2021 : 1. Used Systick handler instead of Driver kernel timer to process transmitted Tx descriptors.
* 2. XFI interface support and module parameters for selection of Port0 and Port1 interface
* VERSION : 01-00-01
*/
#include <linux/gpio/consumer.h>
@ -61,7 +65,7 @@
#define MII_XGMAC_WRITE (1 << MII_XGMAC_CMD_SHIFT)
#define MII_XGMAC_READ (3 << MII_XGMAC_CMD_SHIFT)
#define MII_XGMAC_BUSY BIT(22)
#define MII_XGMAC_MAX_C22ADDR 3
#define MII_XGMAC_MAX_C22ADDR 31
#define MII_XGMAC_C22P_MASK GENMASK(MII_XGMAC_MAX_C22ADDR, 0)
#define MII_XGMAC_PA_SHIFT 16
#define MII_XGMAC_DA_SHIFT 21
@ -88,13 +92,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);
@ -494,9 +493,12 @@ int tc956xmac_mdio_register(struct net_device *ndev)
if (phy_reg_read != -EBUSY) {
if (phy_reg_read != 0x0000 && phy_reg_read != 0xffff) {
NMSGPR_ALERT(priv->device,
if (priv->plat->c45_needed == true)
NMSGPR_ALERT(priv->device,
"TC956X: Phy detected C45 at ID/ADDR %d\n", addr);
else
NMSGPR_ALERT(priv->device,
"TC956X: Phy detected C22 at ID/ADDR %d\n", addr);
#else
struct phy_device *phydev = mdiobus_get_phy(new_bus, addr);