V_01-00-19

1. Added PM support for suspend-resume.
2. Added WOL Interrupt Handler and ethtool Support.
3. Updated EEE support for PHY and MAC Control. (EEE macros are not enabled as EEE LPI interrupts disable are still under validation)
This commit is contained in:
TC956X 2021-10-26 19:49:37 +09:00 committed by jianzhou
parent 8d374ba749
commit 8cde5a6522
11 changed files with 807 additions and 319 deletions

View File

@ -1,7 +1,7 @@
# Toshiba Electronic Devices & Storage Corporation TC956X PCIe Ethernet Host Driver
Release Date: 21 Oct 2021
Release Date: 26 Oct 2021
Release Version: V_01-00-18 : Limited-tested version
Release Version: V_01-00-19 : Limited-tested version
TC956X PCIe EMAC driver is based on "Fedora 30, kernel-5.4.19".
@ -122,34 +122,34 @@ TC956X PCIe EMAC driver is based on "Fedora 30, kernel-5.4.19".
#define EP_L0s_ENTRY_DELAY (0x1FU)
#define EP_L1_ENTRY_DELAY (0x3FFU)
Formula:
L0 entry delay = XXX_L0s_ENTRY_DELAY * 256 ns
L1 entry delay = XXX_L1_ENTRY_DELAY * 256 ns
XXX_L0s_ENTRY_DELAY range: 1-31
XXX_L1_ENTRY_DELAY: 1-1023
Formula:
L0 entry delay = XXX_L0s_ENTRY_DELAY * 256 ns
L1 entry delay = XXX_L1_ENTRY_DELAY * 256 ns
XXX_L0s_ENTRY_DELAY range: 1-31
XXX_L1_ENTRY_DELAY: 1-1023
9. To check vlan feature status execute:
ethtool -k <interface> | grep vlan
To enable/disable following vlan features execute:
(a) rx-vlan-filter:
ethtool -K <interface> rx-vlan-filter <on|off>
(b) rx-vlan-offload:
ethtool -K <interface> rxvlan <on|off>
(c) tx-vlan-offload:
ethtool -K <interface> txvlan <on|off>
To enable/disable following vlan features execute:
(a) rx-vlan-filter:
ethtool -K <interface> rx-vlan-filter <on|off>
(b) rx-vlan-offload:
ethtool -K <interface> rxvlan <on|off>
(c) tx-vlan-offload:
ethtool -K <interface> txvlan <on|off>
Use following to configure VLAN:
(a) modprobe 8021q
(b) vconfig add <interface> <vlanid>
(c) vconfig set_flag <interface>.<vlanid> 1 0
(d) ifconfig <interface>.<vlanid> <ip> netmask 255.255.255.0 broadcast <ip mask> up
Use following to configure VLAN:
(a) modprobe 8021q
(b) vconfig add <interface> <vlanid>
(c) vconfig set_flag <interface>.<vlanid> 1 0
(d) ifconfig <interface>.<vlanid> <ip> netmask 255.255.255.0 broadcast <ip mask> up
Default Configuraton:
(a) Rx vlan filter is disabled.
(b) Rx valn offload (vlan stripping) is disabled.
(c) Tx vlan offload is enabled.
Default Configuraton:
(a) Rx vlan filter is disabled.
(b) Rx valn offload (vlan stripping) is disabled.
(c) Tx vlan offload is enabled.
10. Please use the below command to insert the kernel module for passing pause frames to application except pause frames from PHY:
@ -162,6 +162,24 @@ Default Configuraton:
If invalid values are passed as kernel module parameter, the default value will be selected.
11. Use below commands to check WOL support and its type:
#ethtool <interface>
12. WOL command Usage :
#ethtool -s <interface> wol <type - p/g/d>.
Supported WOL options and meaning:
----------------------------------
Option | Meaning
----------------------------------
p | Wake on phy activity
g | Wake on MagicPacket(tm)
d | Disable (wake on nothing). (Default)
----------------------------------
Example - To wake on phy activity and magic packet use :
ethtool -s eth0 wol pg
# Release Versions:
## TC956X_Host_Driver_20210326_V_01-00:
@ -258,3 +276,9 @@ Default Configuraton:
## TC956X_Host_Driver_20211021_V_01-00-18:
1. Added support for GPIO configuration API
## TC956X_Host_Driver_20211025_V_01-00-19:
1. Added PM support for suspend-resume.
2. Added WOL Interrupt Handler and ethtool Support.
3. Updated EEE support for PHY and MAC Control. (EEE macros are not enabled as EEE LPI interrupts disable are still under validation)

View File

@ -53,6 +53,10 @@
* VERSION : 01-00-17
* 21 Oct 2021 : 1. Added support for GPIO configuration API
* VERSION : 01-00-18
* 26 Oct 2021 : 1. Added macro to enable/disable EEE.
: 2. Added enums for PM Suspend-Resume.
: 3. Added macros for EEE, LPI Timer and MAC RST Status.
* VERSION : 01-00-19
*/
#ifndef __COMMON_H__
@ -79,6 +83,21 @@
/* Enable DMA IPA offload */
#define DMA_OFFLOAD_ENABLE
/* Indepenedent Suspend/Resume Debug */
#undef TC956X_PM_DEBUG
/* Suspend-Resume Enum Counter */
enum TC956X_INDEPENDENT_PORT_PM_SUSPEND {
NO_PORT_SUSPENDED = 0, /* Normal State */
SINGLE_PORT_SUSPENDED, /* Only Single Port suspended */
BOTH_PORT_SUSPENDED, /* Both Port suspended */
};
/* Suspend-Resume Arguments */
enum TC956X_PORT_PM_STATE {
SUSPEND = 0,
RESUME,
};
#define TC956X_PCIE_LINK_STATE_LATENCY_CTRL
#define DISABLE 0
@ -95,6 +114,7 @@
#define DWXGMAC_CORE_3_01 0x30
//#define DISABLE_EMAC_PORT1
//#define EEE /* Enable for EEE support */
/* Note: Multiple macro definitions for TC956X_PCIE_LOGSTAT.
* Please also define/undefine same macro in tc956xmac_ioctl.h, if changing in this file
@ -648,6 +668,7 @@ enum packets_types {
#define NCLKCTRL0_MAC0312CLKEN BIT(30)
#define NCLKCTRL0_MAC0ALLCLKEN BIT(31)
#define NRSTCTRL0_OFFSET (0x1008) /* TC956X reset control Register-0 */
#define NRSTCTRL0_MCURST BIT(0)
#define NRSTCTRL0_INTRST BIT(4)
#define NRSTCTRL0_MAC0RST BIT(7)
#define NRSTCTRL0_PCIERST BIT(9)
@ -1526,6 +1547,12 @@ struct dma_features {
/* Default LPI timers */
#define TC956XMAC_DEFAULT_LIT_LS 0x3E8
#define TC956XMAC_DEFAULT_TWT_LS 0x1E
#define TC956XMAC_LIT_LS 0x0011
#define TC956XMAC_TWT_LS 0x0028
#define TC956XMAC_TIC_1US_CNTR 0x7c
#define TC956XMAC_LPIET_600US 0x258
#define TC956X_PHY_SPEED_5G 5000
#define TC956X_PHY_SPEED_2_5G 2500
#define TC956XMAC_CHAIN_MODE 0x1
#define TC956XMAC_RING_MODE 0x2

View File

@ -42,6 +42,8 @@
* 19 Oct 2021 : 1. Adding M3 SRAM Debug counters to ethtool statistics
* 2. Adding MTL RX Overflow/packet miss count, TX underflow counts,Rx Watchdog value to ethtool statistics.
* VERSION : 01-00-17
* 25 Oct 2021 : 1. Added EEE macros for MAC controlled EEE.
* VERSION : 01-00-19
*/
@ -180,6 +182,11 @@
#define XGMAC_LPI_CTRL (MAC_OFFSET + 0x000000d0)
#define XGMAC_TXCGE BIT(21)
#define XGMAC_LPITXA BIT(19)
#ifdef EEE_MAC_CONTROLLED_MODE
#define XGMAC_PLSDIS BIT(18)
#define XGMAC_LPIATE BIT(20)
#endif
#define XGMAC_PLS BIT(17)
#define XGMAC_LPITXEN BIT(16)
#define XGMAC_RLPIEX BIT(3)
@ -187,6 +194,12 @@
#define XGMAC_TLPIEX BIT(1)
#define XGMAC_TLPIEN BIT(0)
#define XGMAC_LPI_TIMER_CTRL (MAC_OFFSET + 0x000000d4)
#ifdef EEE_MAC_CONTROLLED_MODE
#define XGMAC_LPI_1US_Tic_Counter (MAC_OFFSET + 0x000000dc)
#define XGMAC_LPI_Auto_Entry_Timer (MAC_OFFSET + 0x000000d8)
#define XGMAC_LPIET 0xFFFF8
#endif
#define XGMAC_DEBUG (MAC_OFFSET + 0x00000114)
#define XGMAC_HW_FEATURE0 (MAC_OFFSET + 0x0000011c)
#define XGMAC_HW_FEATURE0_BASE (0x0000011c)

View File

@ -50,6 +50,8 @@
* 14 Oct 2021 : 1. Configuring pause frame control using kernel module parameter also forwarding
* only Link partner pause frames to Application and filtering PHY pause frames using FRP
* VERSION : 01-00-16
* 26 Oct 2021 : 1. Added EEE print in host IRQ and updated EEE configuration.
* VERSION : 01-00-19
*/
#include <linux/bitrev.h>
@ -428,6 +430,10 @@ 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
en = readl(ioaddr + XGMAC_INT_EN);
stat = readl(ioaddr + XGMAC_INT_STATUS);
@ -443,17 +449,40 @@ 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");
ret |= CORE_IRQ_TX_PATH_IN_LPI_MODE;
x->irq_tx_path_in_lpi_mode_n++;
}
if (lpi & XGMAC_TLPIEX) {
KPRINT_INFO("Transmit LPI Exit.....\n");
ret |= CORE_IRQ_TX_PATH_EXIT_LPI_MODE;
x->irq_tx_path_exit_lpi_mode_n++;
}
if (lpi & XGMAC_RLPIEN)
if (lpi & XGMAC_RLPIEN) {
KPRINT_INFO("Receive LPI Entry....... \n");
x->irq_rx_path_in_lpi_mode_n++;
if (lpi & XGMAC_RLPIEX)
}
if (lpi & XGMAC_RLPIEX) {
KPRINT_INFO("Receive LPI Exit...... \n");
x->irq_rx_path_exit_lpi_mode_n++;
}
#ifdef EEE
val = tc956x_xpcs_read(priv->xpcsaddr, XGMAC_VR_XS_PCS_DIG_STS);
KPRINT_INFO("XPCS LPI status : %x........\n", val);
if (val & XGMAC_LTX_LRX_STATE) {
if (val & XGMAC_LPI_RECEIVE_STATE)
KPRINT_INFO("XPCS LPI Receive State.........\n");
if (val & XGMAC_LPI_TRANSMIT_STATE)
KPRINT_INFO("XPCS LPI transmit state.....\n");
}
val = tc956x_xpcs_read(priv->xpcsaddr, XGMAC_SR_XS_PCS_STS1);
if ( val & XGMAC_RX_LPI_RECEIVE)
KPRINT_INFO("XPCS RX LPI Received......");
if ( val & XGAMC_TX_LPI_RECEIVE)
KPRINT_INFO("XPCS TX LPI Received......");
#endif
}
return ret;
@ -569,7 +598,9 @@ static void dwxgmac2_set_eee_mode(struct tc956xmac_priv *priv,
value |= XGMAC_LPITXEN | XGMAC_LPITXA;
if (en_tx_lpi_clockgating)
value |= XGMAC_TXCGE;
#ifdef EEE_MAC_CONTROLLED_MODE
value |= XGMAC_PLS | XGMAC_PLSDIS | XGMAC_LPIATE;
#endif
writel(value, ioaddr + XGMAC_LPI_CTRL);
}

8
mmc.h
View File

@ -30,6 +30,8 @@
*
* 15 Mar 2021 : Base lined
* VERSION : 01-00
* 26 Oct 2021 : 1. Added EEE mmc counters for MAC COntrolled mode.
* VERSION : 01-00-19
*/
#ifndef __MMC_H__
@ -81,6 +83,12 @@ struct tc956xmac_counters {
u64 mmc_tx_excessdef;
u64 mmc_tx_pause_frame;
u64 mmc_tx_vlan_frame_g;
#ifdef EEE_MAC_CONTROLLED_MODE
u64 mmc_tx_lpi_us_cntr;
u64 mmc_tx_lpi_tran_cntr;
u64 mmc_rx_lpi_us_cntr;
u64 mmc_rx_lpi_tran_cntr;
#endif
u64 mmc_tx_per_priority_pkt;
u64 mmc_tx_per_priority_pfc_pkt;
u64 mmc_tx_per_priority_gpfc_pkt;

View File

@ -73,6 +73,11 @@
* VERSION : 01-00-17
* 21 Oct 2021 : 1. Version update
* VERSION : 01-00-18
* 26 Oct 2021 : 1. Added support for EEE PHY and MAC Control Mode support.
2. Added PM support for suspend-resume.
3. Added platform api calls.
4. Version update
* VERSION : 01-00-19
*/
#include <linux/clk-provider.h>
@ -105,7 +110,10 @@ static unsigned int tc956x_port1_interface = ENABLE_SGMII_INTERFACE;
unsigned int tc956x_port0_filter_phy_pause_frames = DISABLE;
unsigned int tc956x_port1_filter_phy_pause_frames = DISABLE;
static const struct tc956x_version tc956x_drv_version = {0, 1, 0, 0, 1, 8};
static const struct tc956x_version tc956x_drv_version = {0, 1, 0, 0, 1, 9};
enum TC956X_INDEPENDENT_PORT_PM_SUSPEND tc956xmac_pm_suspend_counter = NO_PORT_SUSPENDED;
struct mutex tc956x_pm_suspend_lock;
/*
* This struct is used to associate PCI Function of MAC controller on a board,
@ -1019,8 +1027,11 @@ static int tc956xmac_xgmac3_default_data(struct pci_dev *pdev,
return -ENOMEM;
#ifdef TC956X
plat->axi->axi_lpi_en = 0;
#ifdef EEE_MAC_CONTROLLED_MODE
plat->axi->axi_lpi_en = 1;
plat->axi->axi_xit_frm = 0;
plat->en_tx_lpi_clockgating = 1;
#endif
plat->axi->axi_wr_osr_lmt = 31;
plat->axi->axi_rd_osr_lmt = 31;
#else
@ -2241,6 +2252,7 @@ static int tc956xmac_pci_probe(struct pci_dev *pdev,
dev_dbg(&(pdev->dev), "%s : ltssm_data.ltssm_stop_status = %d\n", __func__, ltssm_data.ltssm_stop_status);
}
#endif /* TC956X_PCIE_LOGSTAT */
mutex_init(&tc956x_pm_suspend_lock);
#ifdef DMA_OFFLOAD_ENABLE
if (res.port_num == RM_PF0_ID)
@ -2306,10 +2318,6 @@ static void tc956xmac_pci_remove(struct pci_dev *pdev)
pdev->irq = 0;
if (tc956x_platform_remove(priv)) {
dev_err(priv->device, "Platform remove error\n");
}
/* Enable MSI Operation */
pci_disable_msi(pdev);
@ -2331,44 +2339,210 @@ static void tc956xmac_pci_remove(struct pci_dev *pdev)
pci_release_regions(pdev);
pci_disable_device(pdev);
mutex_destroy(&tc956x_pm_suspend_lock);
DBGPR_FUNC(&(pdev->dev), "<--%s\n", __func__);
}
/*!
* \brief API to increment port-wise suspend counter.
*
* \details This api will be called during suspend operation.
* This will set(increase) the tc956xmac_pm_set_counter based on
* number of times tc956x_pcie_suspend() is called as per following :
* If no port suspended - the api will set to Single Port Supended,
* If one port already suspended - the api will set to Single Port Supended,
* If both port suspended - the api will return error.
*
* \param[in] pdev - pointer to pci_dev structure.
*
* \return int
*/
static inline int tc956xmac_pm_set_counter(struct tc956xmac_priv *priv)
{
if (tc956xmac_pm_suspend_counter == NO_PORT_SUSPENDED)
tc956xmac_pm_suspend_counter = SINGLE_PORT_SUSPENDED;
else if (tc956xmac_pm_suspend_counter == SINGLE_PORT_SUSPENDED)
tc956xmac_pm_suspend_counter = BOTH_PORT_SUSPENDED;
else /* if (tc956xmac_pm_suspend_counter == BOTH_PORT_SUSPENDED)*/
return -1;
return tc956xmac_pm_suspend_counter;
}
/*!
* \brief API to decrement port-wise suspend counter.
*
* \details This api will be called during resume operation.
* This will set(decrease) the tc956xmac_pm_set_counter based on
* number of times tc956x_pcie_resume() is called as per following :
* If both port suspended - the api will set to Single Port Supended,
* If one port is already suspended - the api will set to No Port Supended,
* If no port is suspended - on calling the api will return error.
*
* \param[in] pdev - pointer to pci_dev structure.
*
* \return int
*/
static inline int tc956xmac_pm_get_counter(struct tc956xmac_priv *priv)
{
if (tc956xmac_pm_suspend_counter == BOTH_PORT_SUSPENDED)
tc956xmac_pm_suspend_counter = SINGLE_PORT_SUSPENDED;
else if (tc956xmac_pm_suspend_counter == SINGLE_PORT_SUSPENDED)
tc956xmac_pm_suspend_counter = NO_PORT_SUSPENDED;
else /* if (tc956xmac_pm_suspend_counter == NO_PORT_SUSPENDED) */
return -1;
return tc956xmac_pm_suspend_counter;
}
/*!
* \brief API to disable pci device.
*
* \details This api will be called during suspend operation.
* This will disable pci device passed as argument.
*
* \param[in] pdev - pointer to pci_dev structure.
*
* \return int
*/
static int tc956x_pcie_pm_disable_pci(struct pci_dev *pdev)
{
struct net_device *ndev = dev_get_drvdata(&pdev->dev);
struct tc956xmac_priv *priv = netdev_priv(ndev);
int ret = 0;
DBGPR_FUNC(&(pdev->dev), "---->%s : Port %d - PCI Save State, Disable Device, Prepare to sleep", __func__, priv->port_num);
pci_save_state(pdev);
pci_disable_device(pdev);
pci_prepare_to_sleep(pdev);
DBGPR_FUNC(&(pdev->dev), "<----%s : Port %d - PCI Save State, Disable Device, Prepare to sleep", __func__, priv->port_num);
return ret;
}
/*!
* \brief API to enable pci device.
*
* \details This api will be called during resume operation.
* This will enable pci device passed as argument.
*
* \param[in] pdev - pointer to pci_dev structure.
*
* \return int
*/
static int tc956x_pcie_pm_enable_pci(struct pci_dev *pdev)
{
struct net_device *ndev = dev_get_drvdata(&pdev->dev);
struct tc956xmac_priv *priv = netdev_priv(ndev);
int ret = 0;
DBGPR_FUNC(&(pdev->dev), "---->%s : Port %d - PCI Set Power, Enable Device, Restore State & Set Master", __func__, priv->port_num);
pci_set_power_state(pdev, PCI_D0);
ret = pci_enable_device_mem(pdev);
if (ret) {
NMSGPR_ERR(&(pdev->dev),
"%s: error in calling pci_enable_device_mem", pci_name(pdev));
DBGPR_FUNC(&(pdev->dev), "<--%s\n", __func__);
return ret;
}
pci_restore_state(pdev);
pci_set_master(pdev);
DBGPR_FUNC(&(pdev->dev), "<----%s : Port %d - PCI Set Power, Enable Device, Restore State & Set Master", __func__, priv->port_num);
return ret;
}
/*!
* \brief API to extract child pci devices.
*
* \details This api will be called during suspend and resume operation.
* This will find pci child devices by getting parent device of argument pci device.
*
* \param[in] pdev - pointer to pci_dev structure.
* \param[in] state - identify SUSPEND and RESUME operation.
*
* \return int
*/
static int tc956x_pcie_pm_pci(struct pci_dev *pdev, enum TC956X_PORT_PM_STATE state)
{
static struct pci_dev *tc956x_pd = NULL, *tc956x_dsp_ep = NULL, *tc956x_port_pdev[2];
struct pci_bus *bus = NULL;
int ret = 0, i = 0;
if (tc956xmac_pm_suspend_counter > SINGLE_PORT_SUSPENDED) {
tc956x_dsp_ep = pci_upstream_bridge(pdev);
bus = tc956x_dsp_ep->subordinate;
if (bus)
list_for_each_entry(tc956x_pd, &bus->devices, bus_list)
tc956x_port_pdev[i++] = tc956x_pd;
/* Enter only if at least 1 Port Suspended */
if (state == SUSPEND) {
ret = tc956x_pcie_pm_disable_pci(tc956x_port_pdev[0]);
if (ret < 0)
goto err;
ret = tc956x_pcie_pm_disable_pci(tc956x_port_pdev[1]);
if (ret < 0)
goto err;
} else if (state == RESUME) {
ret = tc956x_pcie_pm_enable_pci(tc956x_port_pdev[0]);
if (ret < 0)
goto err;
ret = tc956x_pcie_pm_enable_pci(tc956x_port_pdev[1]);
if (ret < 0)
goto err;
}
}
err :
return ret;
}
/*!
* \brief Routine to put the device in suspend mode
*
* \details This function gets called by PCI core when the device is being
* suspended. The suspended state is passed as input argument to it. This
* function saves the configuration space of the device and puts the device
* in the requested suspend state apart from invoking tc956xmac_suspend() to
* process MAC related suspend operations.
* \details This function is called whenever pm_generic_suspend() gets invoked.
* This function invokes tc956xmac_suspend() to process MAC related suspend
* operations during PORT_WIDE suspend.
* This function handles PCI state during SYSTEM_WIDE suspend.
*
* \param[in] pdev \96 pointer to pci device structure.
* \param[in] state \96 suspend state of device.
* \param[in] dev \96 pointer to device structure.
*
* \return s32
* \return int
*
* \retval 0
*/
static s32 tc956x_pcie_suspend(struct pci_dev *pdev, pm_message_t state)
static int tc956x_pcie_suspend(struct device *dev)
{
s32 ret = 0;
struct pci_dev *pdev = to_pci_dev(dev);
struct net_device *ndev = dev_get_drvdata(&pdev->dev);
struct tc956xmac_priv *priv = netdev_priv(ndev);
int ret = 0;
#ifdef DMA_OFFLOAD_ENABLE
u8 i;
u32 val;
#endif
DBGPR_FUNC(&(pdev->dev), "-->%s\n", __func__);
if (priv->tc956x_port_pm_suspend == true) {
DBGPR_FUNC(&(pdev->dev), "<--%s : Port %d already Suspended \n", __func__, priv->port_num);
return -1;
}
mutex_lock(&tc956x_pm_suspend_lock);
/* Increment Suspend counter */
ret = tc956xmac_pm_set_counter(priv);
if (ret < 0) {
DBGPR_FUNC(&(pdev->dev), "%s : (Both Ports Already Suspended ) \n", __func__);
goto err;
} else
DBGPR_FUNC(&(pdev->dev), "%s : (Number of Ports Suspended = [%d]) \n", __func__, ret);
priv->tc956x_port_pm_suspend = true;
/* Call tc956xmac_suspend() */
tc956xmac_suspend(&pdev->dev);
#ifdef DMA_OFFLOAD_ENABLE
if (priv->port_num == RM_PF0_ID) {
if (tc956xmac_pm_suspend_counter > SINGLE_PORT_SUSPENDED) {
DBGPR_FUNC(&(pdev->dev), "%s : Port %d - Tamap Configuration", __func__, priv->port_num);
/* Since TAMAP is common for Port0 and Port1,
* Store CM3 TAMAP entries of one Port0*/
for (i = 1; i <= MAX_CM3_TAMAP_ENTRIES; i++) {
@ -2392,35 +2566,22 @@ static s32 tc956x_pcie_suspend(struct pci_dev *pdev, pm_message_t state)
}
#endif
DBGPR_FUNC(&(pdev->dev), "%s : Port %d - Platform Suspend", __func__, priv->port_num);
ret = tc956x_platform_suspend(priv);
if (ret) {
NMSGPR_ERR(&(pdev->dev), "%s: error in calling tc956x_platform_suspend", pci_name(pdev));
return ret;
goto err;
}
/* Save the PCI Config Space of the device */
ret = pci_save_state(pdev);
if (ret) {
NMSGPR_ERR(&(pdev->dev),
"%s: error in calling pci_save_state", pci_name(pdev));
DBGPR_FUNC(&(pdev->dev), "<--%s\n", __func__);
return ret;
}
/* Set the device into the requested power state */
ret = pci_set_power_state(pdev, pci_choose_state(pdev, state));
if (ret) {
NMSGPR_ERR(&(pdev->dev),
"%s: error in calling pci_set_power_state", pci_name(pdev));
DBGPR_FUNC(&(pdev->dev), "<--%s\n", __func__);
return ret;
}
ret = tc956x_pcie_pm_pci(pdev, SUSPEND);
if (ret < 0)
goto err;
err :
mutex_unlock(&tc956x_pm_suspend_lock);
DBGPR_FUNC(&(pdev->dev), "<--%s\n", __func__);
return 0;
return ret;
}
/*!
@ -2559,6 +2720,9 @@ static int tc956x_pcie_resume_config(struct pci_dev *pdev)
/* De-assertion of PMA & XPCS reset software Reset*/
ret = readl(priv->ioaddr + NRSTCTRL0_OFFSET);
ret &= ~(NRSTCTRL0_MAC0PMARST | NRSTCTRL0_MAC0PONRST);
#ifdef EEE_MAC_CONTROLLED_MODE
ret &= ~(NRSTCTRL0_MAC0RST | NRSTCTRL0_MAC0RST);
#endif
writel(ret, priv->ioaddr + NRSTCTRL0_OFFSET);
}
@ -2588,58 +2752,56 @@ static int tc956x_pcie_resume_config(struct pci_dev *pdev)
return ret;
}
#endif
/*!
* \brief Routine to resume device operation
*
* \details This function gets called by PCI core when the device is being
* resumed. It is always called after suspend has been called. These function
* reverse operations performed at suspend time. This function restores the
* power state of the device and restores the PCI config space apart from
* invoking tc956xmac_resume() to perform MAC realted resume operations.
* \details This function gets called whenever pm_generic_resume() gets invoked.
* This function reverse operations performed at suspend time. This function restores the
* power state of the device and restores the PCI config space for SYSTEM_WIDE resume.
* And it invokes tc956xmac_resume() to perform MAC realted resume operations
* for PORT_WIDE resume.
*
* \param[in] pdev pointer to pci device structure.
* \param[in] dev pointer to device structure.
*
* \return s32
* \return int
*
* \retval 0
*/
static s32 tc956x_pcie_resume(struct pci_dev *pdev)
static int tc956x_pcie_resume(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct net_device *ndev = dev_get_drvdata(&pdev->dev);
struct tc956xmac_priv *priv = netdev_priv(ndev);
s32 ret = 0;
int ret = 0;
#ifdef DMA_OFFLOAD_ENABLE
u8 i;
#endif
#ifdef TC956X_PCIE_LOGSTAT
struct tc956x_ltssm_log ltssm_data;
#endif /* TC956X_PCIE_LOGSTAT */
DBGPR_FUNC(&(pdev->dev), "-->%s\n", __func__);
/* Set requested power state */
ret = pci_set_power_state(pdev, PCI_D0);
if (ret) {
NMSGPR_ERR(&(pdev->dev),
"%s: error in calling pci_set_power_state", pci_name(pdev));
DBGPR_FUNC(&(pdev->dev), "<--%s\n", __func__);
return ret;
if (priv->tc956x_port_pm_suspend == false) {
DBGPR_FUNC(&(pdev->dev), "%s : Port %d already Resumed \n", __func__, priv->port_num);
return -1;
}
mutex_lock(&tc956x_pm_suspend_lock);
/* Restore PCI config space of device */
pci_restore_state(pdev);
ret = tc956x_pcie_pm_enable_pci(pdev);
if (ret < 0)
goto err;
DBGPR_FUNC(&(pdev->dev), "%s : Port %d - Platform Resume", __func__, priv->port_num);
ret = tc956x_platform_resume(priv);
if (ret) {
NMSGPR_ERR(&(pdev->dev), "%s: error in calling tc956x_platform_resume", pci_name(pdev));
pci_disable_device(pdev);
return ret;
goto err;
}
/* Configure TA map registers */
#ifdef TC956X
if (priv->port_num == RM_PF0_ID) {
if (tc956xmac_pm_suspend_counter > SINGLE_PORT_SUSPENDED) {
DBGPR_FUNC(&(pdev->dev),"%s : Tamap Re-configuration", __func__);
tc956x_config_tamap(&pdev->dev, priv->tc956x_BRIDGE_CFG_pci_base_addr);
#ifdef DMA_OFFLOAD_ENABLE
for (i = 1; i <= MAX_CM3_TAMAP_ENTRIES; i++) {
@ -2650,36 +2812,33 @@ static s32 tc956x_pcie_resume(struct pci_dev *pdev)
#endif
}
#endif
#ifdef TC956X
/* Configure EMAC Port */
tc956x_pcie_resume_config(pdev);
#endif
/* Call tc956xmac_resume() */
tc956xmac_resume(&pdev->dev);
#ifdef TC956X
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__);
#ifdef TC956X_PCIE_LOGSTAT
memset(&ltssm_data, 0, sizeof(ltssm_data));
ret = tc956x_logstat_GetLTSSMLogData((void __iomem *)priv->ioaddr, UPSTREAM_PORT, &ltssm_data);
if (ret == 0) {
dev_dbg(&(pdev->dev), "%s : ltssm_data.eq_phase = %d\n", __func__, ltssm_data.eq_phase);
dev_dbg(&(pdev->dev), "%s : ltssm_data.rxL0s = %d\n", __func__, ltssm_data.rxL0s);
dev_dbg(&(pdev->dev), "%s : ltssm_data.txL0s = %d\n", __func__, ltssm_data.txL0s);
dev_dbg(&(pdev->dev), "%s : ltssm_data.substate_L1 = %d\n", __func__, ltssm_data.substate_L1);
dev_dbg(&(pdev->dev), "%s : ltssm_data.active_lane; = %d\n", __func__, ltssm_data.active_lane);
dev_dbg(&(pdev->dev), "%s : ltssm_data.link_speed = %d\n", __func__, ltssm_data.link_speed);
dev_dbg(&(pdev->dev), "%s : ltssm_data.dl_active = %d\n", __func__, ltssm_data.dl_active);
dev_dbg(&(pdev->dev), "%s : ltssm_data.ltssm_timeout = %d\n", __func__, ltssm_data.ltssm_timeout);
dev_dbg(&(pdev->dev), "%s : ltssm_data.ltssm_stop_status = %d\n", __func__, ltssm_data.ltssm_stop_status);
/* Decrement Suspend counter */
ret = tc956xmac_pm_get_counter(priv);
if (ret < 0) {
DBGPR_FUNC(&(pdev->dev), "%s : (Both Ports Already in Resume State ) \n", __func__);
goto err;
} else {
DBGPR_FUNC(&(pdev->dev), "%s : (Number of Ports left to Resume = [%d]) \n", __func__, ret);
ret = 0;
}
#endif /* TC956X_PCIE_LOGSTAT */
priv->tc956x_port_pm_suspend = false;
err:
mutex_unlock(&tc956x_pm_suspend_lock);
DBGPR_FUNC(&(pdev->dev), "<--%s\n", __func__);
return ret;
}
@ -2801,6 +2960,7 @@ static const struct pci_device_id tc956xmac_id_table[] = {
{}
};
static SIMPLE_DEV_PM_OPS(tc956xmac_pm_ops, tc956x_pcie_suspend, tc956x_pcie_resume);
static struct pci_driver tc956xmac_pci_driver = {
.name = TC956X_RESOURCE_NAME,
@ -2808,13 +2968,10 @@ static struct pci_driver tc956xmac_pci_driver = {
.probe = tc956xmac_pci_probe,
.remove = tc956xmac_pci_remove,
.shutdown = tc956x_pcie_shutdown,
#ifdef CONFIG_PM
.suspend = tc956x_pcie_suspend,
.resume = tc956x_pcie_resume,
#endif
.driver = {
.name = TC956X_RESOURCE_NAME,
.owner = THIS_MODULE,
.pm = &tc956xmac_pm_ops,
},
.err_handler = &tc956x_err_handler
};

View File

@ -35,6 +35,8 @@
* VERSION : 01-00-02
* 22 Jul 2021 : 1. USXGMII/XFI/SGMII/RGMII interface supported with module parameters
* VERSION : 01-00-04
* 26 Oct 2021 : 1. Added EEE configration for PHY and MAC Controlled Mode.
* VERSION : 01-00-19
*/
#include "common.h"
@ -138,6 +140,63 @@ int tc956x_xpcs_init(struct tc956xmac_priv *priv, void __iomem *xpcsaddr)
} while ((XGMAC_VR_RST & reg_value) == XGMAC_VR_RST);
}
#ifdef EEE
reg_value = tc956x_xpcs_read(xpcsaddr, XGMAC_SR_XS_PCS_CTRL1);
reg_value |= XGMAC_LPI_ENABLE;/* LPM : power down */
tc956x_xpcs_write(xpcsaddr, XGMAC_SR_XS_PCS_CTRL1, reg_value);
reg_value = tc956x_xpcs_read(xpcsaddr, XGMAC_VR_XS_PCS_DIG_STS);
reg_value &= ~(XGMAC_PSEQ_STATE);/* PSEQ_STATE(B4:2)=3'b000 */
tc956x_xpcs_write(xpcsaddr, XGMAC_VR_XS_PCS_DIG_STS, reg_value);
reg_value = tc956x_xpcs_read(xpcsaddr, XGMAC_SR_XS_PCS_CTRL1);
reg_value &= ~(XGMAC_LPI_ENABLE);/* LPM : Normal Operation */
tc956x_xpcs_write(xpcsaddr, XGMAC_SR_XS_PCS_CTRL1, reg_value);
reg_value = tc956x_xpcs_read(xpcsaddr, XGMAC_SR_XS_PCS_EEE_ABL);
reg_value |= XGMAC_KXEEE;/* KXEEE */
tc956x_xpcs_write(xpcsaddr, XGMAC_SR_XS_PCS_EEE_ABL, reg_value);
reg_value = tc956x_xpcs_read(xpcsaddr, XGMAC_VR_XS_PCS_EEE_MCTRL0);
reg_value &= ~(XGMAC_MULT_FACT_100NS);
#ifdef EEE_MAC_CONTROLLED_MODE
reg_value |= XGMAC_MULT_FACT_100NS_MAC; /* MULT_FACT_100NS */
#else
reg_value |= XGMAC_MULT_FACT_100NS_PHY; /* MULT_FACT_100NS */
#endif
reg_value |= XGMAC_SIGN_BIT;/* SIGN_BIT */
reg_value |= XGMAC_TX_RX_EN;/* TX_EN_CTRL, RX_EN_CTRL */
tc956x_xpcs_write(xpcsaddr, XGMAC_VR_XS_PCS_EEE_MCTRL0, reg_value);
reg_value = tc956x_xpcs_read(xpcsaddr, XGMAC_VR_XS_PCS_EEE_TXTIMER);
reg_value &= ~(XGMAC_EEE_TX_TIMER);
#ifdef EEE_MAC_CONTROLLED_MODE
reg_value |= XGMAC_EEE_TX_TIMER_MAC_CONT; /* TWL_RES=0x5, T1U_RES=0x1, TSL_RES=0x3 */
#else
reg_value |= XGMAC_EEE_TX_TIMER_PHY_CONT; /* TWL_RES=0xe, T1U_RES=0x8, TSL_RES=0x1c */
#endif
tc956x_xpcs_write(xpcsaddr, XGMAC_VR_XS_PCS_EEE_TXTIMER, reg_value);
reg_value = tc956x_xpcs_read(xpcsaddr, XGMAC_VR_XS_PCS_EEE_RXTIMER);
reg_value &= ~(XGMAC_EEE_RX_TIMER);
#ifdef EEE_MAC_CONTROLLED_MODE
reg_value |= XGMAC_EEE_RX_TIMER_MAC_CONT; /* TWR_RES=0x6, RES_100U=0x42 */
#else
reg_value |= XGMAC_EEE_RX_TIMER_PHY_CONT; /* TWR_RES=0x88, RES_100U=0x28 */
#endif
tc956x_xpcs_write(xpcsaddr, XGMAC_VR_XS_PCS_EEE_RXTIMER, reg_value);
reg_value = tc956x_xpcs_read(xpcsaddr, XGMAC_VR_XS_PCS_EEE_MCTRL1);
reg_value |= XGMAC_TRN_LPI;
tc956x_xpcs_write(xpcsaddr, XGMAC_VR_XS_PCS_EEE_MCTRL1, reg_value);
reg_value = tc956x_xpcs_read(xpcsaddr, XGMAC_VR_XS_PCS_EEE_MCTRL0);
reg_value &= ~XGMAC_TX_RX_QUIET_EN;
reg_value |= XGMAC_TX_RX_QUIET_EN; /* RX_QUIET_EN, TX_QUIET_EN, LRX_EN, LTX_EN */
tc956x_xpcs_write(xpcsaddr, XGMAC_VR_XS_PCS_EEE_MCTRL0, reg_value);
#endif
reg_value = tc956x_xpcs_read(xpcsaddr, XGMAC_VR_MII_AN_CTRL);
reg_value &= XGMAC_TX_CFIG_INTR_EN_MASK;/*TX_CONFIG MAC SIDE*/

View File

@ -33,6 +33,8 @@
* VERSION : 01-00-01
* 15 Jul 2021 : 1. USXGMII/XFI/SGMII/RGMII interface supported without module parameter
* VERSION : 01-00-02
* 26 Oct 2021 : 1. Added EEE macros for PHY and MAC Controlled Mode.
* VERSION : 01-00-19
*/
#ifndef __TC956X_XPCS_H__
@ -44,39 +46,69 @@
#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_VR_XS_PCS_DIG_CTRL1 0xe0000
#define XGMAC_VR_XS_PCS_EEE_MCTRL0 0xe0018
#define XGMAC_VR_XS_PCS_EEE_MCTRL1 0xe002c
#define XGMAC_VR_XS_PCS_KR_CTRL 0xe001c
#define XGMAC_VR_XS_PCS_EEE_TXTIMER 0xe0020
#define XGMAC_VR_XS_PCS_EEE_RXTIMER 0xe0024
#define XGMAC_VR_XS_PCS_DIG_STS 0xe0040
#define XGMAC_VR_MII_AN_INTR_STS 0x7e0008
#define XGMAC_SR_XS_PCS_STS2 0xC0020
#define XGMAC_LTX_LRX_STATE 0xFC00
#define XGMAC_LPI_RECEIVE_STATE 0x1C00
#define XGMAC_LPI_TRANSMIT_STATE 0xE000
#define XGMAC_RX_LPI_RECEIVE 0x400
#define XGAMC_TX_LPI_RECEIVE 0x800
#define XGMAC_LPI_ENABLE 0x0800
#define XGMAC_PSEQ_STATE 0x001C
#define XGMAC_KXEEE 0x0010
#define XGMAC_MULT_FACT_100NS 0x0F00
#define XGMAC_SIGN_BIT 0x40
#define XGMAC_TX_RX_EN 0x90
#define XGMAC_EEE_RX_TIMER 0x3FFF
#define XGMAC_EEE_TX_TIMER 0x1FFF
#define XGMAC_TX_RX_QUIET_EN 0x000F
#define XGMAC_MULT_FACT_100NS_MAC 0xB00
#define XGMAC_MULT_FACT_100NS_PHY 0xA00
#define XGMAC_EEE_TX_TIMER_MAC_CONT 0x0543
#define XGMAC_EEE_TX_TIMER_PHY_CONT 0x0E9C
#define XGMAC_EEE_RX_TIMER_MAC_CONT 0x062A
#define XGMAC_EEE_RX_TIMER_PHY_CONT 0x2888
#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 */

View File

@ -75,6 +75,10 @@
* 21 Oct 2021 : 1. Added support for GPIO configuration API
* : 2. Version update
* VERSION : 01-00-18
* 26 Oct 2021 : 1. Updated Driver Module Version.
: 2. Added variable for port-wise suspend status.
: 3. Added macro to control EEE MAC Control.
* VERSION : 01-00-19
*/
#ifndef __TC956XMAC_H__
@ -96,6 +100,10 @@
//#define TC956X_LOAD_FW_HEADER
#define PF_DRIVER 4
/* Uncomment EEE_MAC_CONTROLLED_MODE macro for MAC controlled EEE Mode & comment for PHY controlled EEE mode */
//#define EEE_MAC_CONTROLLED_MODE
/* Uncomment TC956X_5_G_2_5_G_EEE_SUPPORT macro for enabling EEE support for 5G and 2.5G */
//#define TC956X_5_G_2_5_G_EEE_SUPPORT
// #define CONFIG_TC956XMAC_SELFTESTS /*Enable this macro to test Feature selftest*/
#ifdef TC956X
@ -123,7 +131,7 @@
#ifdef TC956X
#define TC956X_RESOURCE_NAME "tc956x_pci-eth"
#define DRV_MODULE_VERSION "V_01-00-18"
#define DRV_MODULE_VERSION "V_01-00-19"
#define TC956X_FW_MAX_SIZE (64*1024)
#define ATR_AXI4_SLV_BASE 0x0800
@ -575,6 +583,7 @@ struct tc956xmac_priv {
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 */
bool tc956x_port_pm_suspend; /* Port Suspend Status; True : port suspended, False : port resume */
#endif
/* set to 1 when ptp offload is enabled, else 0. */

View File

@ -41,6 +41,8 @@
* 19 Oct 2021 : 1. Adding M3 SRAM Debug counters to ethtool statistics
* 2. Adding MTL RX Overflow/packet miss count, TX underflow counts,Rx Watchdog value to ethtool statistics.
* VERSION : 01-00-17
* 26 Oct 2021 : 1. Added set_wol and get_wol support using ethtool.
* VERSION : 01-00-19
*/
#include <linux/etherdevice.h>
@ -1251,6 +1253,39 @@ static void tc956xmac_get_strings(struct net_device *dev, u32 stringset, u8 *dat
}
}
static void tc956xmac_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
struct tc956xmac_priv *priv = netdev_priv(dev);
if (device_can_wakeup(priv->device))
phylink_ethtool_get_wol(priv->phylink, wol);
}
static int tc956xmac_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
struct tc956xmac_priv *priv = netdev_priv(dev);
u32 support = (WAKE_MAGIC | WAKE_PHY);
int ret;
if (!device_can_wakeup(priv->device))
return -EINVAL;
if (wol->wolopts & ~support)
return -EINVAL;
ret = phylink_ethtool_set_wol(priv->phylink, wol);
if (!ret)
device_set_wakeup_enable(priv->device, wol->wolopts);
else
return ret;
mutex_lock(&priv->lock);
priv->wolopts = wol->wolopts;
mutex_unlock(&priv->lock);
return ret;
}
static int tc956xmac_ethtool_op_get_eee(struct net_device *dev,
struct ethtool_eee *edata)
{
@ -1598,6 +1633,8 @@ static const struct ethtool_ops tc956xmac_ethtool_ops = {
.self_test = tc956xmac_selftest_run,
.get_ethtool_stats = tc956xmac_get_ethtool_stats,
.get_strings = tc956xmac_get_strings,
.get_wol = tc956xmac_get_wol,
.set_wol = tc956xmac_set_wol,
.get_eee = tc956xmac_ethtool_op_get_eee,
.set_eee = tc956xmac_ethtool_op_set_eee,
.get_sset_count = tc956xmac_get_sset_count,

View File

@ -60,6 +60,11 @@
* VERSION : 01-00-14
* 21 Oct 2021 : 1. Added support for GPIO configuration API
* VERSION : 01-00-18
* 26 Oct 2021 : 1. Added support for EEE PHY and MAC Control Mode.
2. Added dev_pm_ops interface support for suspend-resume.
3. Changed IRQF_SHARED to IRQF_NO_SUSPEND and added WOL Interrupt Handler support.
4. Added Platform Apis.
* VERSION : 01-00-19
*/
#include <linux/clk.h>
@ -97,6 +102,10 @@
#include "hwif.h"
#include "common.h"
#include "tc956xmac_ioctl.h"
#ifdef TC956X_5_G_2_5_G_EEE_SUPPORT
#include <linux/phy.h>
#include <linux/linkmode.h>
#endif
#ifdef TC956X_PCIE_LOGSTAT
#include "tc956x_pcie_logstat.h"
@ -206,6 +215,8 @@ static const struct config_parameter_list config_param_list[] = {
};
static uint16_t mdio_bus_id;
extern enum TC956X_INDEPENDENT_PORT_PM_SUSPEND tc956xmac_pm_suspend_counter;
static bool tc956xmac_pm_wol_interrupt = false; /* Flag for clearing interrupt after resume. */
#define CONFIG_PARAM_NUM ARRAY_SIZE(config_param_list)
int tc956xmac_rx_parser_configuration(struct tc956xmac_priv *);
@ -320,6 +331,22 @@ int tc956x_GPIO_OutputConfigPin(struct tc956xmac_priv *priv, u32 gpio_pin, u8 ou
return 0;
}
/**
* tc956xmac_wol_interrupt - ISR to handle WoL PHY interrupt
* @irq: interrupt number.
* @dev_id: to pass the net device pointer.
*/
static irqreturn_t tc956xmac_wol_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *)dev_id;
struct tc956xmac_priv *priv = netdev_priv(dev);
/* Set flag to clear interrupt after resume */
DBGPR_FUNC(priv->device, "%s\n", __func__);
tc956xmac_pm_wol_interrupt = true;
return IRQ_HANDLED;
}
/**
* tc956xmac_verify_args - verify the driver parameters.
* Description: it checks the driver parameters and set a default in case of
@ -610,7 +637,10 @@ static void tc956xmac_eee_ctrl_timer(struct timer_list *t)
*/
bool tc956xmac_eee_init(struct tc956xmac_priv *priv)
{
#ifdef EEE_MAC_CONTROLLED_MODE
int tx_lpi_timer = priv->tx_lpi_timer;
int value;
#endif
/* Using PCS we cannot dial with the phy registers at this stage
* so we do not support extra feature like EEE.
@ -631,7 +661,9 @@ bool tc956xmac_eee_init(struct tc956xmac_priv *priv)
if (priv->eee_enabled) {
netdev_dbg(priv->dev, "disable EEE\n");
del_timer_sync(&priv->eee_ctrl_timer);
#ifdef EEE_MAC_CONTROLLED_MODE
tc956xmac_set_eee_timer(priv, priv->hw, 0, tx_lpi_timer);
#endif
}
mutex_unlock(&priv->lock);
return false;
@ -640,8 +672,16 @@ bool tc956xmac_eee_init(struct tc956xmac_priv *priv)
if (priv->eee_active && !priv->eee_enabled) {
timer_setup(&priv->eee_ctrl_timer, tc956xmac_eee_ctrl_timer, 0);
mod_timer(&priv->eee_ctrl_timer, TC956XMAC_LPI_T(eee_timer));
tc956xmac_set_eee_timer(priv, priv->hw, TC956XMAC_DEFAULT_LIT_LS,
tx_lpi_timer);
#ifdef EEE_MAC_CONTROLLED_MODE
tc956xmac_set_eee_timer(priv, priv->hw, TC956XMAC_LIT_LS, TC956XMAC_TWT_LS);
value = TC956XMAC_TIC_1US_CNTR;
writel(value, priv->ioaddr + XGMAC_LPI_1US_Tic_Counter);
value = readl(priv->ioaddr + XGMAC_LPI_Auto_Entry_Timer);
/* Setting LPIET bit [19...3] */
value &= ~(XGMAC_LPIET);
value |= (TC956XMAC_LPIET_600US << 3);
writel(value, priv->ioaddr + XGMAC_LPI_Auto_Entry_Timer);
#endif
}
mutex_unlock(&priv->lock);
@ -1742,11 +1782,93 @@ static void tc956xmac_mac_link_down(struct phylink_config *config,
struct tc956xmac_priv *priv = netdev_priv(to_net_dev(config->dev));
tc956xmac_mac_set(priv, priv->ioaddr, false);
#ifdef EEE
priv->eee_active = false;
priv->eee_enabled = tc956xmac_eee_init(priv);
tc956xmac_set_eee_pls(priv, priv->hw, false);
#endif
#ifdef TC956X_PM_DEBUG
pm_generic_suspend(priv->device);
#endif
}
#ifdef TC956X_5_G_2_5_G_EEE_SUPPORT
static inline bool tc956x_phy_check_valid(int speed, int duplex,
unsigned long *features)
{
return !!phy_lookup_setting(speed, duplex, features, true);
}
static void tc956x_mmd_eee_adv_to_linkmode_5G_2_5G(unsigned long *advertising, u16 eee_adv)
{
linkmode_zero(advertising);
if (eee_adv & MDIO_EEE_5GT)
linkmode_set_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
advertising);
if (eee_adv & MDIO_EEE_2_5GT)
linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
advertising);
}
int tc956x_phy_init_eee(struct phy_device *phydev, bool clk_stop_enable)
{
if (!phydev->drv)
return -EIO;
/* According to 802.3az,the EEE is supported only in full duplex-mode.
*/
if (phydev->duplex == DUPLEX_FULL) {
__ETHTOOL_DECLARE_LINK_MODE_MASK(common);
__ETHTOOL_DECLARE_LINK_MODE_MASK(lp);
__ETHTOOL_DECLARE_LINK_MODE_MASK(adv);
int eee_lp, eee_cap, eee_adv;
int status;
u32 cap;
/* Read phy status to properly get the right settings */
status = phy_read_status(phydev);
if (status)
return status;
/* First check if the EEE ability is supported */
eee_cap = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_EEE_ABLE);
if (eee_cap <= 0)
goto eee_exit_err;
cap = mmd_eee_cap_to_ethtool_sup_t(eee_cap);
if (!cap)
goto eee_exit_err;
/* Check which link settings negotiated and verify it in
* the EEE advertising registers.
*/
eee_lp = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_LPABLE2);
if (eee_lp <= 0)
goto eee_exit_err;
eee_adv = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV2);
if (eee_adv <= 0)
goto eee_exit_err;
tc956x_mmd_eee_adv_to_linkmode_5G_2_5G(adv, eee_adv);
tc956x_mmd_eee_adv_to_linkmode_5G_2_5G(lp, eee_lp);
linkmode_and(common, adv, lp);
if (!tc956x_phy_check_valid(phydev->speed, phydev->duplex, common))
goto eee_exit_err;
if (clk_stop_enable)
phy_set_bits_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1,
MDIO_PCS_CTRL1_CLKSTOP_EN);
return 0;
}
eee_exit_err:
return -EPROTONOSUPPORT;
}
#endif
static void tc956xmac_mac_link_up(struct phylink_config *config,
unsigned int mode, phy_interface_t interface,
struct phy_device *phy)
@ -1754,11 +1876,24 @@ static void tc956xmac_mac_link_up(struct phylink_config *config,
struct tc956xmac_priv *priv = netdev_priv(to_net_dev(config->dev));
tc956xmac_mac_set(priv, priv->ioaddr, true);
#ifdef EEE
if (phy && priv->dma_cap.eee) {
#ifdef TC956X_5_G_2_5_G_EEE_SUPPORT
if(phy->speed == TC956X_PHY_SPEED_5G || phy->speed == TC956X_PHY_SPEED_2_5G) {
priv->eee_active = tc956x_phy_init_eee(phy, 1) >= 0;
} else {
priv->eee_active = phy_init_eee(phy, 1) >= 0;
}
#else
priv->eee_active = phy_init_eee(phy, 1) >= 0;
#endif
priv->eee_enabled = tc956xmac_eee_init(priv);
tc956xmac_set_eee_pls(priv, priv->hw, true);
}
#endif
#ifdef TC956X_PM_DEBUG
pm_generic_resume(priv->device);
#endif
}
static const struct phylink_mac_ops tc956xmac_phylink_mac_ops = {
@ -3896,7 +4031,8 @@ static int tc956xmac_open(struct net_device *dev)
int ret;
struct phy_device *phydev;
int addr = priv->plat->phy_addr;
KPRINT_INFO("---> %s : Port %d", __func__, priv->port_num);
phydev = mdiobus_get_phy(priv->mii, addr);
if (!phydev) {
@ -3912,41 +4048,43 @@ static int tc956xmac_open(struct net_device *dev)
netdev_err(priv->dev,
"%s: Cannot attach to PHY (error: %d)\n",
__func__, ret);
KPRINT_INFO("<--- %s(1) : Port %d", __func__, priv->port_num);
return ret;
}
}
/* Do not re-allocate host resources during resume sequence. Only re-initialize resources */
if (priv->tc956x_port_pm_suspend == false) {
/* Extra statistics */
memset(&priv->xstats, 0, sizeof(struct tc956xmac_extra_stats));
priv->xstats.threshold = tc;
/* Extra statistics */
memset(&priv->xstats, 0, sizeof(struct tc956xmac_extra_stats));
priv->xstats.threshold = tc;
bfsize = tc956xmac_set_16kib_bfsize(priv, dev->mtu);
if (bfsize < 0)
bfsize = 0;
bfsize = tc956xmac_set_16kib_bfsize(priv, dev->mtu);
if (bfsize < 0)
bfsize = 0;
if (bfsize < BUF_SIZE_16KiB)
bfsize = tc956xmac_set_bfsize(dev->mtu, priv->dma_buf_sz);
if (bfsize < BUF_SIZE_16KiB)
bfsize = tc956xmac_set_bfsize(dev->mtu, priv->dma_buf_sz);
priv->dma_buf_sz = bfsize;
buf_sz = bfsize;
priv->dma_buf_sz = bfsize;
buf_sz = bfsize;
priv->rx_copybreak = TC956XMAC_RX_COPYBREAK;
priv->rx_copybreak = TC956XMAC_RX_COPYBREAK;
/* Earlier check for TBS */
for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) {
struct tc956xmac_tx_queue *tx_q = &priv->tx_queue[chan];
int tbs_en = priv->plat->tx_queues_cfg[chan].tbs_en;
/* Earlier check for TBS */
for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) {
struct tc956xmac_tx_queue *tx_q = &priv->tx_queue[chan];
int tbs_en = priv->plat->tx_queues_cfg[chan].tbs_en;
/* Set TC956XMAC_TBS_EN by default. Later allow tc command to
*enable/disable
*/
tx_q->tbs |= tbs_en ? TC956XMAC_TBS_AVAIL | TC956XMAC_TBS_EN : 0;
/* Set TC956XMAC_TBS_EN by default. Later allow tc command to
*enable/disable
*/
tx_q->tbs |= tbs_en ? TC956XMAC_TBS_AVAIL | TC956XMAC_TBS_EN : 0;
if (tc956xmac_enable_tbs(priv, priv->ioaddr, tbs_en, chan))
tx_q->tbs &= ~TC956XMAC_TBS_AVAIL;
if (tc956xmac_enable_tbs(priv, priv->ioaddr, tbs_en, chan))
tx_q->tbs &= ~TC956XMAC_TBS_AVAIL;
}
}
ret = alloc_dma_desc_resources(priv);
if (ret < 0) {
netdev_err(priv->dev, "%s: DMA descriptors allocation failed\n",
@ -3987,9 +4125,15 @@ static int tc956xmac_open(struct net_device *dev)
/* MSIGEN block is common for Port0 and Port1 */
rd_val = readl(priv->ioaddr + NCLKCTRL0_OFFSET);
rd_val |= (1 << 18); /* MSIGENCEN=1 */
#ifdef EEE_MAC_CONTROLLED_MODE
rd_val |= 0x67000000;
#endif
writel(rd_val, priv->ioaddr + NCLKCTRL0_OFFSET);
rd_val = readl(priv->ioaddr + NRSTCTRL0_OFFSET);
rd_val &= ~(1 << 18); /* MSIGENSRST=0 */
#ifdef EEE_MAC_CONTROLLED_MODE
rd_val &= ~(NRSTCTRL0_MAC0RST | NRSTCTRL0_MAC0RST);
#endif
writel(rd_val, priv->ioaddr + NRSTCTRL0_OFFSET);
@ -4059,42 +4203,43 @@ static int tc956xmac_open(struct net_device *dev)
KPRINT_INFO("%s phylink started", __func__);
/* Request the IRQ lines */
ret = request_irq(dev->irq, tc956xmac_interrupt,
IRQF_SHARED, dev->name, dev);
if (unlikely(ret < 0)) {
netdev_err(priv->dev,
"%s: ERROR: allocating the IRQ %d (error: %d)\n",
__func__, dev->irq, ret);
goto irq_error;
}
/* Do not re-request host irq resources during resume sequence. */
if (priv->tc956x_port_pm_suspend == false) {
/* Request the IRQ lines */
ret = request_irq(dev->irq, tc956xmac_interrupt,
IRQF_NO_SUSPEND, dev->name, dev);
if (unlikely(ret < 0)) {
netdev_err(priv->dev,
"%s: ERROR: allocating the IRQ %d (error: %d)\n",
__func__, dev->irq, ret);
goto irq_error;
}
/* Request the Wake IRQ in case of another line is used for WoL */
if (priv->wol_irq != dev->irq) {
ret = request_irq(priv->wol_irq, tc956xmac_wol_interrupt,
IRQF_NO_SUSPEND, dev->name, dev);
if (unlikely(ret < 0)) {
netdev_err(priv->dev,
"%s: ERROR: allocating the WoL IRQ %d (%d)\n",
__func__, priv->wol_irq, ret);
goto wolirq_error;
}
}
#ifndef TC956X
/* Request the Wake IRQ in case of another line is used for WoL */
if (priv->wol_irq != dev->irq) {
ret = request_irq(priv->wol_irq, tc956xmac_interrupt,
IRQF_SHARED, dev->name, dev);
if (unlikely(ret < 0)) {
netdev_err(priv->dev,
"%s: ERROR: allocating the WoL IRQ %d (%d)\n",
__func__, priv->wol_irq, ret);
goto wolirq_error;
/* Request the IRQ lines */
if (priv->lpi_irq > 0) {
ret = request_irq(priv->lpi_irq, tc956xmac_interrupt, IRQF_SHARED,
dev->name, dev);
if (unlikely(ret < 0)) {
netdev_err(priv->dev,
"%s: ERROR: allocating the LPI IRQ %d (%d)\n",
__func__, priv->lpi_irq, ret);
goto lpiirq_error;
}
}
}
/* Request the IRQ lines */
if (priv->lpi_irq > 0) {
ret = request_irq(priv->lpi_irq, tc956xmac_interrupt, IRQF_SHARED,
dev->name, dev);
if (unlikely(ret < 0)) {
netdev_err(priv->dev,
"%s: ERROR: allocating the LPI IRQ %d (%d)\n",
__func__, priv->lpi_irq, ret);
goto lpiirq_error;
}
}
#endif
}
tc956xmac_enable_all_queues(priv);
tc956xmac_start_all_queues(priv);
@ -4116,14 +4261,15 @@ static int tc956xmac_open(struct net_device *dev)
#endif
#endif
KPRINT_INFO("<--- %s(2) : Port %d", __func__, priv->port_num);
return 0;
#ifndef TC956X
lpiirq_error:
if (priv->wol_irq != dev->irq)
free_irq(priv->wol_irq, dev);
#endif
wolirq_error:
free_irq(dev->irq, dev);
#endif
irq_error:
phylink_stop(priv->phylink);
#ifdef ENABLE_TX_TIMER
@ -4137,6 +4283,7 @@ static int tc956xmac_open(struct net_device *dev)
free_dma_desc_resources(priv);
dma_desc_error:
phylink_disconnect_phy(priv->phylink);
KPRINT_INFO("<--- %s(3) : Port %d", __func__, priv->port_num);
return ret;
}
@ -4152,7 +4299,7 @@ static int tc956xmac_release(struct net_device *dev)
#ifdef ENABLE_TX_TIMER
u32 chan;
#endif
KPRINT_INFO("---> %s : Port %d", __func__, priv->port_num);
#ifdef TX_COMPLETION_WITHOUT_TIMERS
writel(0, priv->tc956x_SRAM_pci_base_addr
+ TX_TIMER_SRAM_OFFSET(priv->port_num));
@ -4175,15 +4322,18 @@ static int tc956xmac_release(struct net_device *dev)
del_timer_sync(&priv->tx_queue[chan].txtimer);
}
#endif
/* Free the IRQ lines */
free_irq(dev->irq, dev);
/* Do not Free Host Irq resources during suspend sequence */
if (priv->tc956x_port_pm_suspend == false) {
/* Free the IRQ lines */
free_irq(dev->irq, dev);
if (priv->wol_irq != dev->irq)
free_irq(priv->wol_irq, dev);
#ifndef TC956X
if (priv->wol_irq != dev->irq)
free_irq(priv->wol_irq, dev);
if (priv->lpi_irq > 0)
free_irq(priv->lpi_irq, dev);
if (priv->lpi_irq > 0)
free_irq(priv->lpi_irq, dev);
#endif
}
/* Stop TX/RX DMA and clear the descriptors */
tc956xmac_stop_all_dma(priv);
@ -4197,6 +4347,7 @@ static int tc956xmac_release(struct net_device *dev)
tc956xmac_release_ptp(priv);
KPRINT_INFO("<--- %s : Port %d", __func__, priv->port_num);
return 0;
}
@ -9986,6 +10137,7 @@ int tc956xmac_dvr_probe(struct device *device,
#ifdef TC956X
priv->mac_loopback_mode = 0; /* Disable MAC loopback by default */
priv->phy_loopback_mode = 0; /* Disable PHY loopback by default */
priv->tc956x_port_pm_suspend = false; /* By Default Port suspend state set to false */
#endif
/* ToDo : Firwmware load code here */
@ -10423,6 +10575,9 @@ int tc956xmac_dvr_remove(struct device *dev)
#endif
tc956xmac_stop_all_dma(priv);
if (tc956x_platform_remove(priv)) {
dev_err(priv->device, "Platform remove error\n");
}
tc956xmac_mac_set(priv, priv->ioaddr, false);
netif_carrier_off(ndev);
unregister_netdev(ndev);
@ -10471,70 +10626,38 @@ int tc956xmac_suspend(struct device *dev)
if (!ndev)
return 0;
KPRINT_INFO("---> %s : Port %d", __func__, priv->port_num);
/* Disabling EEE for issue in TC9560/62, to be tested for TC956X */
if (priv->eee_enabled)
tc956xmac_disable_eee_mode(priv);
/* Intimate MAC state change to phylink */
phylink_mac_change(priv->phylink, false);
//if (priv->wolopts) {
// KPRINT_INFO("%s : Port %d - Phy Speed Down", __func__, priv->port_num);
// phy_speed_down(phydev, true);
//}
/* Invoke device driver close */
if (netif_running(ndev)) {
rtnl_lock();
dev_close(ndev);
rtnl_unlock();
}
if (priv->phylink) {
rtnl_lock();
phylink_stop(priv->phylink);
rtnl_unlock();
}
if (!netif_running(ndev))
goto clean_exit;
mutex_lock(&priv->lock);
/* Invoke device driver close only when net inteface is up and running. */
rtnl_lock();
tc956xmac_release(ndev);
rtnl_unlock();
clean_exit:
/* Detach network device */
netif_device_detach(ndev);
/* Stop and disable Queues */
tc956xmac_stop_all_queues(priv);
#ifndef TC956X
tc956xmac_disable_all_queues(priv);
#endif
/* Stop TX/RX DMA */
tc956xmac_stop_all_dma(priv);
/* Power management Not Applicable for TC956X */
#ifndef TC956X
/* Enable Power down mode by programming the PMT regs */
if (device_may_wakeup(priv->device)) {
tc956xmac_pmt(priv, priv->hw, priv->wolopts);
priv->irq_wake = 1;
} else {
mutex_unlock(&priv->lock);
rtnl_lock();
phylink_stop(priv->phylink);
rtnl_unlock();
mutex_lock(&priv->lock);
tc956xmac_mac_set(priv, priv->ioaddr, false);
pinctrl_pm_select_sleep_state(priv->device);
/* Disable clock in case of PWM is off */
if (priv->plat->clk_ptp_ref)
clk_disable_unprepare(priv->plat->clk_ptp_ref);
clk_disable_unprepare(priv->plat->pclk);
clk_disable_unprepare(priv->plat->tc956xmac_clk);
}
#endif
mutex_unlock(&priv->lock);
priv->oldlink = false;
priv->speed = SPEED_UNKNOWN;
priv->oldduplex = DUPLEX_UNKNOWN;
KPRINT_INFO("<--- %s : Port %d", __func__, priv->port_num);
return 0;
}
EXPORT_SYMBOL_GPL(tc956xmac_suspend);
#ifndef TC956X
/**
* tc956xmac_reset_queues_param - reset queue parameters
* @dev: device pointer
@ -10566,6 +10689,7 @@ static void tc956xmac_reset_queues_param(struct tc956xmac_priv *priv)
tx_q->mss = 0;
}
}
#endif
/**
* tc956xmac_resume - resume callback
@ -10578,85 +10702,52 @@ int tc956xmac_resume(struct device *dev)
struct net_device *ndev = dev_get_drvdata(dev);
struct tc956xmac_priv *priv = netdev_priv(ndev);
struct tc956xmac_resources res;
s32 ret;
u32 cm3_reset_status = 0;
s32 fw_load_status = 0;
#ifdef TC956X
res.tc956x_SFR_pci_base_addr = priv->tc956x_SFR_pci_base_addr;
res.addr = priv->ioaddr;
res.tc956x_SRAM_pci_base_addr = priv->tc956x_SRAM_pci_base_addr;
res.irq = priv->dev->irq;
#endif
/* Load Firmare for CM3 */
if (priv->port_num == RM_PF0_ID) {
ret = tc956x_load_firmware(dev, &res);
if (ret < 0) {
KPRINT_INFO("---> %s : Port %d", __func__, priv->port_num);
memset(&res, 0, sizeof(res));
cm3_reset_status = readl((priv->ioaddr + NRSTCTRL0_OFFSET));
if ((cm3_reset_status & NRSTCTRL0_MCURST) == NRSTCTRL0_MCURST) {
res.tc956x_SFR_pci_base_addr = priv->tc956x_SFR_pci_base_addr;
res.addr = priv->ioaddr;
res.tc956x_SRAM_pci_base_addr = priv->tc956x_SRAM_pci_base_addr;
res.irq = priv->dev->irq;
fw_load_status = tc956x_load_firmware(dev, &res);
if (fw_load_status < 0) {
KPRINT_ERR("Firmware load failed\n");
return -EINVAL;
}
}
/* Power Down bit, into the PM register, is cleared
* automatically as soon as a magic packet or a Wake-up frame
* is received. Anyway, it's better to manually clear
* this bit because it can generate problems while resuming
* from another devices (e.g. serial console).
*/
/* Power management not applicable for TC956X */
#ifndef TC956X
if (device_may_wakeup(priv->device)) {
mutex_lock(&priv->lock);
tc956xmac_pmt(priv, priv->hw, 0);
mutex_unlock(&priv->lock);
priv->irq_wake = 0;
} else {
pinctrl_pm_select_default_state(priv->device);
/* enable the clk previously disabled */
clk_prepare_enable(priv->plat->tc956xmac_clk);
clk_prepare_enable(priv->plat->pclk);
if (priv->plat->clk_ptp_ref)
clk_prepare_enable(priv->plat->clk_ptp_ref);
/* reset the phy so that it's ready */
if (priv->mii)
tc956xmac_mdio_reset(priv->mii);
}
#endif
//if (priv->wolopts) {
// KPRINT_INFO("%s : Port %d - Phy Speed Up", __func__, priv->port_num);
// phy_speed_up(phydev);
//}
/* Attach network device */
netif_device_attach(ndev);
mutex_lock(&priv->lock);
/* Reset Tx/Rx Queues */
tc956xmac_reset_queues_param(priv);
#ifndef TC956X
/* Clear Descriptors */
tc956xmac_clear_descriptors(priv);
tc956xmac_hw_setup(ndev, false);
tc956xmac_init_coalesce(priv);
tc956xmac_set_rx_mode(ndev);
/* Enable and Start all queues */
tc956xmac_enable_all_queues(priv);
/* Reset Parameters. */
tc956xmac_reset_queues_param(priv);
#endif
tc956xmac_start_all_queues(priv);
mutex_unlock(&priv->lock);
if (!device_may_wakeup(priv->device)) {
rtnl_lock();
phylink_start(priv->phylink);
rtnl_unlock();
}
if (!netif_running(ndev))
goto clean_exit;
/* Invoke device driver open */
if (!netif_running(ndev)) {
rtnl_lock();
dev_open(ndev, NULL);
rtnl_unlock();
rtnl_lock();
tc956xmac_open(ndev);
rtnl_unlock();
clean_exit:
if ((priv->wolopts) && (tc956xmac_pm_wol_interrupt)) {
KPRINT_INFO("%s : Port %d Clearing WOL and queuing phy work", __func__, priv->port_num);
/* Clear WOL Interrupt after resume, if WOL enabled */
tc956xmac_pm_wol_interrupt = false;
/* Queue the work in system_wq */
queue_work(system_wq, &priv->emac_phy_work);
}
/* Intimate phylink about state change */
phylink_mac_change(priv->phylink, true);
KPRINT_INFO("<--- %s : Port %d", __func__, priv->port_num);
return 0;
}
EXPORT_SYMBOL_GPL(tc956xmac_resume);