Add proper PCI power management operations to support modern standby (S0i3) on AMD platforms. The existing suspend/resume implementation did not properly handle PCI device state transitions, which prevented the system from reaching the deepest sleep states. The amd_pmc driver was reporting "Last suspend didn't reach deepest state" when the XGBE driver was enabled. The implementation follows the standard PCI PM model: Suspend path: - Powerdown the network interface - Set PHY to low-power mode - Disable bus mastering to prevent DMA activity - Save PCI configuration state - Disable the PCI device - Disable wake from D3 (required for S0i3 - no Wake-on-LAN needed) - Set device to D3hot power state Resume path: - Restore PCI power state to D0 - Restore PCI configuration state - Enable the PCI device - Re-enable bus mastering - Re-enable device interrupts - Clear PHY low-power mode - Power up the network interface Signed-off-by: Raju Rangoju --- drivers/net/ethernet/amd/xgbe/xgbe-pci.c | 39 ++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-pci.c b/drivers/net/ethernet/amd/xgbe/xgbe-pci.c index 112d7697174c..8e392cccd065 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-pci.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-pci.c @@ -356,15 +356,34 @@ static int xgbe_pci_suspend(struct device *dev) { struct xgbe_prv_data *pdata = dev_get_drvdata(dev); struct net_device *netdev = pdata->netdev; + struct pci_dev *pdev = to_pci_dev(dev); int ret = 0; + if (!netdev) + return 0; + if (netif_running(netdev)) ret = xgbe_powerdown(netdev); + /* Disable all device interrupts to prevent spurious wakeups */ + XP_IOWRITE(pdata, XP_INT_EN, 0x0); + + /* Set PHY to low-power mode */ pdata->lpm_ctrl = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1); pdata->lpm_ctrl |= MDIO_CTRL1_LPOWER; XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, pdata->lpm_ctrl); + /* Disable bus mastering to prevent DMA activity */ + pci_clear_master(pdev); + + /* Save PCI configuration state and disable device */ + pci_save_state(pdev); + pci_disable_device(pdev); + + /* Disable wake from D3 - required for S0i3 deep sleep */ + pci_wake_from_d3(pdev, false); + pci_set_power_state(pdev, PCI_D3hot); + return ret; } @@ -372,13 +391,33 @@ static int xgbe_pci_resume(struct device *dev) { struct xgbe_prv_data *pdata = dev_get_drvdata(dev); struct net_device *netdev = pdata->netdev; + struct pci_dev *pdev = to_pci_dev(dev); int ret = 0; + /* Restore PCI power state */ + pci_set_power_state(pdev, PCI_D0); + + /* Restore PCI configuration state */ + pci_restore_state(pdev); + + /* Enable PCI device */ + ret = pci_enable_device(pdev); + if (ret) + return ret; + + /* Re-enable bus mastering */ + pci_set_master(pdev); + + /* Re-enable all device interrupts */ XP_IOWRITE(pdata, XP_INT_EN, 0x1fffff); + /* Clear PHY low-power mode */ pdata->lpm_ctrl &= ~MDIO_CTRL1_LPOWER; XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, pdata->lpm_ctrl); + if (!netdev) + return 0; + if (netif_running(netdev)) { ret = xgbe_powerup(netdev); -- 2.34.1