From: Frank Sae <Frank.Sae@motor-comm.com>
To: davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
pabeni@redhat.com
Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
xiaogang.fan@motor-comm.com, fei.zhang@motor-comm.com,
hua.sun@motor-comm.com, Frank.Sae@motor-comm.com
Subject: [PATCH net-next v2 15/21] motorcomm:yt6801: Implement pci_driver suspend and resume
Date: Wed, 20 Nov 2024 18:56:19 +0800 [thread overview]
Message-ID: <20241120105625.22508-16-Frank.Sae@motor-comm.com> (raw)
In-Reply-To: <20241120105625.22508-1-Frank.Sae@motor-comm.com>
Implement the pci_driver suspend function to enable the device to sleep,
and implement the resume function to enable the device to resume operation.
Signed-off-by: Frank Sae <Frank.Sae@motor-comm.com>
---
.../net/ethernet/motorcomm/yt6801/yt6801_hw.c | 118 ++++++++++++++++++
.../ethernet/motorcomm/yt6801/yt6801_net.c | 28 +++++
.../ethernet/motorcomm/yt6801/yt6801_pci.c | 61 +++++++++
3 files changed, 207 insertions(+)
diff --git a/drivers/net/ethernet/motorcomm/yt6801/yt6801_hw.c b/drivers/net/ethernet/motorcomm/yt6801/yt6801_hw.c
index bd3036625..25411f2dd 100644
--- a/drivers/net/ethernet/motorcomm/yt6801/yt6801_hw.c
+++ b/drivers/net/ethernet/motorcomm/yt6801/yt6801_hw.c
@@ -2424,6 +2424,56 @@ static void fxgmac_config_dma_bus(struct fxgmac_pdata *pdata)
wr32_mac(pdata, val, DMA_SBMR);
}
+static int fxgmac_pre_powerdown(struct fxgmac_pdata *pdata)
+{
+ u32 val = 0;
+ int ret;
+
+ fxgmac_disable_rx(pdata);
+
+ yt_dbg(pdata, "%s, phy and mac status update\n", __func__);
+
+ if (device_may_wakeup(pdata->dev)) {
+ val = rd32_mem(pdata, EPHY_CTRL);
+ if (val & EPHY_CTRL_STA_LINKUP) {
+ ret = phy_speed_down(pdata->phydev, true);
+ if (ret < 0) {
+ yt_err(pdata, "%s, phy_speed_down err:%d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = phy_read_status(pdata->phydev);
+ if (ret < 0) {
+ yt_err(pdata, "%s, phy_read_status err:%d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ pdata->phy_speed = pdata->phydev->speed;
+ pdata->phy_duplex = pdata->phydev->duplex;
+ yt_dbg(pdata, "%s, speed :%d, duplex :%d\n", __func__,
+ pdata->phy_speed, pdata->phy_duplex);
+
+ fxgmac_config_mac_speed(pdata);
+ } else {
+ yt_dbg(pdata, "%s link down, do nothing\n", __func__);
+ }
+ }
+
+ /* After enable OOB_WOL from efuse, mac will loopcheck phy status,
+ * and lead to panic sometimes. So we should disable it from powerup,
+ * enable it from power down.
+ */
+ val = rd32_mem(pdata, OOB_WOL_CTRL);
+ fxgmac_set_bits(&val, OOB_WOL_CTRL_DIS_POS, OOB_WOL_CTRL_DIS_LEN, 0);
+ wr32_mem(pdata, val, OOB_WOL_CTRL);
+ fsleep(2000);
+
+ fxgmac_set_mac_address(pdata, pdata->mac_addr);
+
+ return 0;
+}
+
static int fxgmac_phy_clear_interrupt(struct fxgmac_pdata *pdata)
{
u32 stats_pre, stats;
@@ -2458,6 +2508,70 @@ static int fxgmac_phy_clear_interrupt(struct fxgmac_pdata *pdata)
return -ETIMEDOUT;
}
+static void fxgmac_config_powerdown(struct fxgmac_pdata *pdata,
+ bool wol)
+{
+ u32 val = 0;
+
+ /* Use default arp offloading feature */
+ fxgmac_update_aoe_ipv4addr(pdata, (u8 *)NULL);
+ fxgmac_enable_arp_offload(pdata);
+ fxgmac_update_ns_offload_ipv6addr(pdata, FXGMAC_NS_IFA_GLOBAL_UNICAST);
+ fxgmac_update_ns_offload_ipv6addr(pdata, FXGMAC_NS_IFA_LOCAL_LINK);
+ fxgmac_enable_ns_offload(pdata);
+ fxgmac_enable_wake_packet_indication(pdata, 1);
+
+ /* Enable MAC Rx TX */
+ val = rd32_mac(pdata, MAC_CR);
+ fxgmac_set_bits(&val, MAC_CR_RE_POS, MAC_CR_RE_LEN, 1);
+ fxgmac_set_bits(&val, MAC_CR_TE_POS, MAC_CR_TE_LEN, 1);
+ wr32_mac(pdata, val, MAC_CR);
+
+ val = rd32_mem(pdata, LPW_CTRL);
+ fxgmac_set_bits(&val, LPW_CTRL_ASPM_LPW_EN_POS,
+ LPW_CTRL_ASPM_LPW_EN_LEN, 1);
+ wr32_mem(pdata, val, LPW_CTRL);
+
+ /* Set gmac power down */
+ val = rd32_mac(pdata, MAC_PMT_STA);
+ fxgmac_set_bits(&val, MAC_PMT_STA_PWRDWN_POS, MAC_PMT_STA_PWRDWN_LEN,
+ 1);
+ wr32_mac(pdata, val, MAC_PMT_STA);
+
+ val = rd32_mem(pdata, MGMT_SIGDET);
+ fxgmac_set_bits(&val, MGMT_SIGDET_POS, MGMT_SIGDET_LEN,
+ MGMT_SIGDET_55MV);
+ wr32_mem(pdata, val, MGMT_SIGDET);
+ fxgmac_phy_clear_interrupt(pdata);
+}
+
+static void fxgmac_config_powerup(struct fxgmac_pdata *pdata)
+{
+ u32 val = 0;
+
+ /* After enable OOB_WOL from efuse, mac will loopcheck phy status,
+ * and lead to panic sometimes.
+ * So we should disable it from powerup, enable it from power down.
+ */
+ val = rd32_mem(pdata, OOB_WOL_CTRL);
+ fxgmac_set_bits(&val, OOB_WOL_CTRL_DIS_POS, OOB_WOL_CTRL_DIS_LEN, 1);
+ wr32_mem(pdata, val, OOB_WOL_CTRL);
+
+ /* Clear wpi mode whether or not waked by WOL, write reset value */
+ val = rd32_mem(pdata, MGMT_WPI_CTRL0);
+ fxgmac_set_bits(&val, MGMT_WPI_CTRL0_WPI_MODE_POS,
+ MGMT_WPI_CTRL0_WPI_MODE_LEN, 0);
+ wr32_mem(pdata, val, MGMT_WPI_CTRL0);
+
+ /* Read pmt_status register to De-assert the pmt_intr_o */
+ val = rd32_mac(pdata, MAC_PMT_STA);
+ /* whether or not waked up by WOL, write reset value */
+ fxgmac_set_bits(&val, MAC_PMT_STA_PWRDWN_POS, MAC_PMT_STA_PWRDWN_LEN,
+ 0);
+ /* Write register to synchronized always-on block */
+ wr32_mac(pdata, val, MAC_PMT_STA);
+}
+
#define FXGMAC_WOL_WAIT_2_MS 2
static void fxgmac_config_wol_wait_time(struct fxgmac_pdata *pdata)
@@ -3262,4 +3376,8 @@ void fxgmac_hw_ops_init(struct fxgmac_hw_ops *hw_ops)
hw_ops->enable_wake_pattern = fxgmac_enable_wake_pattern;
hw_ops->disable_wake_pattern = fxgmac_disable_wake_pattern;
+ /* Power Management */
+ hw_ops->pre_power_down = fxgmac_pre_powerdown;
+ hw_ops->config_power_down = fxgmac_config_powerdown;
+ hw_ops->config_power_up = fxgmac_config_powerup;
}
diff --git a/drivers/net/ethernet/motorcomm/yt6801/yt6801_net.c b/drivers/net/ethernet/motorcomm/yt6801/yt6801_net.c
index 6a3d1073c..10c103e95 100644
--- a/drivers/net/ethernet/motorcomm/yt6801/yt6801_net.c
+++ b/drivers/net/ethernet/motorcomm/yt6801/yt6801_net.c
@@ -986,6 +986,34 @@ static void fxgmac_restart_work(struct work_struct *work)
rtnl_unlock();
}
+int fxgmac_net_powerup(struct fxgmac_pdata *pdata)
+{
+ struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops;
+ int ret;
+
+ /* Signal that we are up now */
+ pdata->powerstate = 0;
+ if (__test_and_set_bit(FXGMAC_POWER_STATE_UP, &pdata->powerstate))
+ return 0; /* do nothing if already up */
+
+ ret = fxgmac_start(pdata);
+ if (ret < 0) {
+ yt_err(pdata, "%s: fxgmac_start err: %d\n", __func__, ret);
+ return ret;
+ }
+
+ /* Must call it after fxgmac_start,because it will be
+ * enable in fxgmac_start
+ */
+ hw_ops->disable_arp_offload(pdata);
+
+ if (netif_msg_drv(pdata))
+ yt_dbg(pdata, "%s, powerstate :%ld.\n", __func__,
+ pdata->powerstate);
+
+ return 0;
+}
+
int fxgmac_config_wol(struct fxgmac_pdata *pdata, bool en)
{
struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops;
diff --git a/drivers/net/ethernet/motorcomm/yt6801/yt6801_pci.c b/drivers/net/ethernet/motorcomm/yt6801/yt6801_pci.c
index b2cd75b5c..860b79d13 100644
--- a/drivers/net/ethernet/motorcomm/yt6801/yt6801_pci.c
+++ b/drivers/net/ethernet/motorcomm/yt6801/yt6801_pci.c
@@ -104,6 +104,62 @@ static void fxgmac_shutdown(struct pci_dev *pcidev)
(system_state == SYSTEM_POWER_OFF) ? 1 : 0);
}
+static int fxgmac_suspend(struct device *device)
+{
+ struct fxgmac_pdata *pdata = dev_get_drvdata(device);
+ struct net_device *netdev = pdata->netdev;
+ int ret = 0;
+
+ mutex_lock(&pdata->mutex);
+ if (pdata->dev_state != FXGMAC_DEV_START)
+ goto unlock;
+
+ if (netif_running(netdev)) {
+ ret = __fxgmac_shutdown(to_pci_dev(device), NULL);
+ if (ret < 0)
+ goto unlock;
+ }
+
+ pdata->dev_state = FXGMAC_DEV_SUSPEND;
+unlock:
+ mutex_unlock(&pdata->mutex);
+
+ return ret;
+}
+
+static int fxgmac_resume(struct device *device)
+{
+ struct fxgmac_pdata *pdata = dev_get_drvdata(device);
+ struct net_device *netdev = pdata->netdev;
+ int ret = 0;
+
+ mutex_lock(&pdata->mutex);
+ if (pdata->dev_state != FXGMAC_DEV_SUSPEND)
+ goto unlock;
+
+ pdata->dev_state = FXGMAC_DEV_RESUME;
+ __clear_bit(FXGMAC_POWER_STATE_DOWN, &pdata->powerstate);
+
+ rtnl_lock();
+ if (netif_running(netdev)) {
+ ret = fxgmac_net_powerup(pdata);
+ if (ret < 0) {
+ dev_err(device, "%s, fxgmac_net_powerup err:%d\n",
+ __func__, ret);
+ goto unlock;
+ }
+ }
+
+ netif_device_attach(netdev);
+ rtnl_unlock();
+
+ dev_dbg(device, "%s ok\n", __func__);
+unlock:
+ mutex_unlock(&pdata->mutex);
+
+ return ret;
+}
+
#define MOTORCOMM_PCI_ID 0x1f0a
#define YT6801_PCI_DEVICE_ID 0x6801
@@ -114,11 +170,16 @@ static const struct pci_device_id fxgmac_pci_tbl[] = {
MODULE_DEVICE_TABLE(pci, fxgmac_pci_tbl);
+static const struct dev_pm_ops fxgmac_pm_ops = {
+ SYSTEM_SLEEP_PM_OPS(fxgmac_suspend, fxgmac_resume)
+};
+
static struct pci_driver fxgmac_pci_driver = {
.name = FXGMAC_DRV_NAME,
.id_table = fxgmac_pci_tbl,
.probe = fxgmac_probe,
.remove = fxgmac_remove,
+ .driver.pm = pm_ptr(&fxgmac_pm_ops),
.shutdown = fxgmac_shutdown,
};
--
2.34.1
next prev parent reply other threads:[~2024-11-20 11:02 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-11-20 10:56 [PATCH net-next v2 00/21] net:yt6801: Add Motorcomm yt6801 PCIe driver Frank Sae
2024-11-20 10:56 ` [PATCH net-next v2 03/21] motorcomm:yt6801: Implement the fxgmac_drv_probe function Frank Sae
2024-11-20 10:56 ` [PATCH net-next v2 04/21] motorcomm:yt6801: Implement the .ndo_open function Frank Sae
2024-11-20 10:56 ` [PATCH net-next v2 05/21] motorcomm:yt6801: Implement the fxgmac_start function Frank Sae
2024-11-20 10:56 ` [PATCH net-next v2 08/21] motorcomm:yt6801: Implement the fxgmac_read_mac_addr function Frank Sae
2024-11-20 10:56 ` [PATCH net-next v2 12/21] motorcomm:yt6801: Implement .ndo_tx_timeout and .ndo_change_mtu functions Frank Sae
2024-11-20 10:56 ` [PATCH net-next v2 13/21] motorcomm:yt6801: Implement some ethtool_ops function Frank Sae
2024-11-20 10:56 ` [PATCH net-next v2 14/21] motorcomm:yt6801: Implement the WOL function of ethtool_ops Frank Sae
2024-11-20 10:56 ` Frank Sae [this message]
2024-11-20 10:56 ` [PATCH net-next v2 16/21] motorcomm:yt6801: Add a Makefile in the motorcomm folder Frank Sae
2024-11-20 10:56 ` [PATCH net-next v2 17/21] motorcomm:yt6801: Update the Makefile and Kconfig in the motorcomm Frank Sae
2024-11-20 10:56 ` [PATCH net-next v2 18/21] motorcomm:yt6801: Update the Makefile and Kconfig in the ethernet Frank Sae
2024-11-20 10:56 ` [PATCH net-next v2 19/21] ethernet: Update the index.rst in the ethernet documentation folder Frank Sae
2024-11-20 10:56 ` [PATCH net-next v2 20/21] motorcomm:yt6801: Add a yt6801.rst " Frank Sae
2024-11-20 10:56 ` [PATCH net-next v2 21/21] MAINTAINERS:Add the motorcomm ethernet driver entry Frank Sae
2024-11-20 11:14 ` [PATCH net-next v2 11/21] motorcomm:yt6801: Implement some net_device_ops function Frank Sae
2024-11-20 11:14 ` [PATCH net-next v2 09/21] motorcomm:yt6801: Implement some hw_ops function Frank Sae
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20241120105625.22508-16-Frank.Sae@motor-comm.com \
--to=frank.sae@motor-comm.com \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=fei.zhang@motor-comm.com \
--cc=hua.sun@motor-comm.com \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=xiaogang.fan@motor-comm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox