V_01-00-22

1. Single port Suspend/Resume supported
This commit is contained in:
TC956X 2021-11-24 16:03:58 +09:00 committed by jianzhou
parent e0d730ce66
commit eb3a5a9afc
5 changed files with 73 additions and 111 deletions

View File

@ -1,7 +1,7 @@
# Toshiba Electronic Devices & Storage Corporation TC956X PCIe Ethernet Host Driver
Release Date: 08 Nov 2021
Release Date: 24 Nov 2021
Release Version: V_01-00-21 : Limited-tested version
Release Version: V_01-00-22 : Limited-tested version
TC956X PCIe EMAC driver is based on "Fedora 30, kernel-5.4.19".
@ -291,5 +291,9 @@ ethtool -s eth0 wol pg
## TC956X_Host_Driver_20211108_V_01-00-21:
(1) Skip queuing PHY Work during suspend and cancel any phy work if already queued.
(2) Restore Gen 3 Speed after resume.
1. Skip queuing PHY Work during suspend and cancel any phy work if already queued.
2. Restore Gen 3 Speed after resume.
## TC956X_Host_Driver_20211124_V_01-00-22:
1. Single port Suspend/Resume supported

View File

@ -61,6 +61,8 @@
* VERSION : 01-00-20
* 08 Nov 2021 : 1. Added macro for Maximum Port
* VERSION : 01-00-21
* 24 Nov 2021 : 1. Single Port Suspend/Resume supported
* VERSION : 01-00-22
*/
#ifndef __COMMON_H__
@ -89,13 +91,9 @@
/* Indepenedent Suspend/Resume Debug */
#undef TC956X_PM_DEBUG
#define TC956X_MAX_PORT 2
/* 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 */
};
#define TC956X_MAX_PORT 2
#define TC956X_ALL_MAC_PORT_SUSPENDED 0 /* All EMAC Port Suspended. To be used just after suspend and before resume. */
#define TC956X_NO_MAC_DEVICE_IN_USE 0 /* No EMAC Port in use. To be used at probe and remove. */
/* Suspend-Resume Arguments */
enum TC956X_PORT_PM_STATE {

View File

@ -84,6 +84,9 @@
2. Cancel PHY Workqueue before suspend.
3. Restore Gen 3 Speed after resume.
* VERSION : 01-00-21
* 24 Nov 2021 : 1. Version update
2. Single Port Suspend/Resume supported
* VERSION : 01-00-22
*/
#include <linux/clk-provider.h>
@ -116,10 +119,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, 2, 1};
static const struct tc956x_version tc956x_drv_version = {0, 1, 0, 0, 2, 2};
enum TC956X_INDEPENDENT_PORT_PM_SUSPEND tc956xmac_pm_suspend_counter = NO_PORT_SUSPENDED;
struct mutex tc956x_pm_suspend_lock;
static int tc956xmac_pm_usage_counter; /* Device Usage Counter */
struct mutex tc956x_pm_suspend_lock; /* This mutex is shared between all available EMAC ports. */
/*
* This struct is used to associate PCI Function of MAC controller on a board,
@ -2258,12 +2261,19 @@ 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);
/* Initialize only once */
if (tc956xmac_pm_usage_counter == TC956X_NO_MAC_DEVICE_IN_USE)
mutex_init(&tc956x_pm_suspend_lock);
#ifdef DMA_OFFLOAD_ENABLE
if (res.port_num == RM_PF0_ID)
port0_pdev = pdev;
#endif
mutex_lock(&tc956x_pm_suspend_lock);
/* Increment device usage counter */
tc956xmac_pm_usage_counter++;
DBGPR_FUNC(&(pdev->dev), "%s : (Device Usage Count = [%d]) \n", __func__, tc956xmac_pm_usage_counter);
mutex_unlock(&tc956x_pm_suspend_lock);
return ret;
err_out_msi_failed:
@ -2345,61 +2355,19 @@ static void tc956xmac_pci_remove(struct pci_dev *pdev)
pci_release_regions(pdev);
pci_disable_device(pdev);
mutex_destroy(&tc956x_pm_suspend_lock);
mutex_lock(&tc956x_pm_suspend_lock);
/* Decrement device usage counter */
tc956xmac_pm_usage_counter--;
DBGPR_FUNC(&(pdev->dev), "%s : (Device Usage Count = [%d]) \n", __func__, tc956xmac_pm_usage_counter);
mutex_unlock(&tc956x_pm_suspend_lock);
/* Destroy Mutex only once */
if (tc956xmac_pm_usage_counter == TC956X_NO_MAC_DEVICE_IN_USE)
mutex_destroy(&tc956x_pm_suspend_lock);
DBGPR_FUNC(&(pdev->dev), "<--%s\n", __func__);
}
/*!
* \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.
*
@ -2468,10 +2436,10 @@ static int tc956x_pcie_pm_enable_pci(struct pci_dev *pdev)
*/
static int tc956x_pcie_pm_pci(struct pci_dev *pdev, enum TC956X_PORT_PM_STATE state)
{
static struct pci_dev *tc956x_pd = NULL, *tc956x_dsp_ep = NULL, *tc956x_port_pdev[2];
static struct pci_dev *tc956x_pd = NULL, *tc956x_dsp_ep = NULL, *tc956x_port_pdev[2] = {NULL};
struct pci_bus *bus = NULL;
int ret = 0, i = 0;
if (tc956xmac_pm_suspend_counter > SINGLE_PORT_SUSPENDED) {
int ret = 0, i = 0, p = 0;
if (tc956xmac_pm_usage_counter == TC956X_ALL_MAC_PORT_SUSPENDED) {
tc956x_dsp_ep = pci_upstream_bridge(pdev);
bus = tc956x_dsp_ep->subordinate;
@ -2479,21 +2447,17 @@ static int tc956x_pcie_pm_pci(struct pci_dev *pdev, enum TC956X_PORT_PM_STATE st
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;
for (p = 0; ((p < i) && (tc956x_port_pdev[p] != NULL)); p++) {
/* Enter only if at least 1 Port Suspended */
if (state == SUSPEND) {
ret = tc956x_pcie_pm_disable_pci(tc956x_port_pdev[p]);
if (ret < 0)
goto err;
} else if (state == RESUME) {
ret = tc956x_pcie_pm_enable_pci(tc956x_port_pdev[p]);
if (ret < 0)
goto err;
}
}
}
err :
@ -2545,19 +2509,15 @@ static int tc956x_pcie_suspend(struct device *dev)
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);
/* Decrement device usage counter */
tc956xmac_pm_usage_counter--;
DBGPR_FUNC(&(pdev->dev), "%s : (Number of Ports Left to Suspend = [%d]) \n", __func__, tc956xmac_pm_usage_counter);
/* Call tc956xmac_suspend() */
tc956xmac_suspend(&pdev->dev);
#ifdef DMA_OFFLOAD_ENABLE
if (tc956xmac_pm_suspend_counter > SINGLE_PORT_SUSPENDED) {
if (tc956xmac_pm_usage_counter == TC956X_ALL_MAC_PORT_SUSPENDED) {
DBGPR_FUNC(&(pdev->dev), "%s : Port %d - Tamap Configuration", __func__, priv->port_num);
/* Since TAMAP is common for Port0 and Port1,
* Store CM3 TAMAP entries of one Port0*/
@ -2818,7 +2778,7 @@ static int tc956x_pcie_resume(struct device *dev)
goto err;
}
#ifdef TC956X_PCIE_GEN3_SETTING
if (tc956xmac_pm_suspend_counter > SINGLE_PORT_SUSPENDED) {
if (tc956xmac_pm_usage_counter == TC956X_ALL_MAC_PORT_SUSPENDED) {
/* Reset Speed to Gen3 after resume */
DBGPR_FUNC(&(pdev->dev), "%s : Port %d - Set Speed to Gen3", __func__, priv->port_num);
val = readl(priv->ioaddr + TC956X_GLUE_EFUSE_CTRL);
@ -2840,7 +2800,7 @@ static int tc956x_pcie_resume(struct device *dev)
#endif
/* Configure TA map registers */
if (tc956xmac_pm_suspend_counter > SINGLE_PORT_SUSPENDED) {
if (tc956xmac_pm_usage_counter == TC956X_ALL_MAC_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
@ -2864,15 +2824,9 @@ static int tc956x_pcie_resume(struct device *dev)
writel(NEMACIOCTL_DEFAULT, priv->ioaddr + TC9563_CFG_NEMACIOCTL);
}
/* 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;
}
/* Increment device usage counter */
tc956xmac_pm_usage_counter++;
DBGPR_FUNC(&(pdev->dev), "%s : (Number of Ports Resumed = [%d]) \n", __func__, tc956xmac_pm_usage_counter);
priv->tc956x_port_pm_suspend = false;

View File

@ -83,6 +83,9 @@
* VERSION : 01-00-20
* 08 Nov 2021 : 1. Version update
* VERSION : 01-00-21
* 24 Nov 2021 : 1. Version update
2. Private member used instead of global for wol interrupt indication
* VERSION : 01-00-22
*/
#ifndef __TC956XMAC_H__
@ -135,7 +138,7 @@
#ifdef TC956X
#define TC956X_RESOURCE_NAME "tc956x_pci-eth"
#define DRV_MODULE_VERSION "V_01-00-21"
#define DRV_MODULE_VERSION "V_01-00-22"
#define TC956X_FW_MAX_SIZE (64*1024)
#define ATR_AXI4_SLV_BASE 0x0800
@ -588,6 +591,7 @@ struct tc956xmac_priv {
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 */
bool tc956xmac_pm_wol_interrupt; /* Port-wise flag for clearing interrupt after resume. */
#endif
/* set to 1 when ptp offload is enabled, else 0. */

View File

@ -69,7 +69,9 @@
* VERSION : 01-00-20
* 08 Nov 2021 : 1. Skip queuing PHY Work during suspend.
* VERSION : 01-00-21
*/
* 24 Nov 2021 : 1. Private member used instead of global for wol interrupt indication
* VERSION : 01-00-22
*/
#include <linux/clk.h>
#include <linux/kernel.h>
@ -219,7 +221,7 @@ static const struct config_parameter_list config_param_list[] = {
};
static uint16_t mdio_bus_id;
static bool tc956xmac_pm_wol_interrupt[TC956X_MAX_PORT]; /* Port-wise flag for clearing interrupt after resume. */
#define CONFIG_PARAM_NUM ARRAY_SIZE(config_param_list)
int tc956xmac_rx_parser_configuration(struct tc956xmac_priv *);
@ -347,7 +349,7 @@ static irqreturn_t tc956xmac_wol_interrupt(int irq, void *dev_id)
/* Set flag to clear interrupt after resume */
DBGPR_FUNC(priv->device, "%s\n", __func__);
/* Set flag to indicate WOL interrupt trigger */
tc956xmac_pm_wol_interrupt[priv->port_num] = true;
priv->tc956xmac_pm_wol_interrupt = true;
return IRQ_HANDLED;
}
@ -4243,7 +4245,7 @@ static int tc956xmac_open(struct net_device *dev)
}
}
#endif
tc956xmac_pm_wol_interrupt[priv->port_num] = false; /* Initialize flag for PHY Work queue */
priv->tc956xmac_pm_wol_interrupt = false; /* Initialize flag for PHY Work queue */
}
tc956xmac_enable_all_queues(priv);
tc956xmac_start_all_queues(priv);
@ -5809,7 +5811,7 @@ static irqreturn_t tc956xmac_interrupt(int irq, void *dev_id)
/* Queue the work in system_wq */
if (priv->tc956x_port_pm_suspend == true) {
KPRINT_INFO("%s : (Do not queue PHY Work during suspend. Set WOL Interrupt flag) \n", __func__);
tc956xmac_pm_wol_interrupt[priv->port_num] = true;
priv->tc956xmac_pm_wol_interrupt = true;
} else {
KPRINT_INFO("%s : (Queue PHY Work.) \n", __func__);
queue_work(system_wq, &priv->emac_phy_work);
@ -10750,10 +10752,10 @@ int tc956xmac_resume(struct device *dev)
rtnl_unlock();
clean_exit:
if (tc956xmac_pm_wol_interrupt[priv->port_num]) {
if (priv->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[priv->port_num] = false;
priv->tc956xmac_pm_wol_interrupt = false;
/* Queue the work in system_wq */
queue_work(system_wq, &priv->emac_phy_work);
}