Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 279485
b: refs/heads/master
c: 749ab2c
h: refs/heads/master
i:
  279483: 802bd98
v: v3
  • Loading branch information
Yan, Zheng authored and David S. Miller committed Jan 5, 2012
1 parent 5445377 commit b447274
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 20 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: bdbc063129e811264cd6c311d8c2d9b95de01231
refs/heads/master: 749ab2cd127046df79084b6b9165b23491b1db5f
16 changes: 16 additions & 0 deletions trunk/drivers/net/ethernet/intel/igb/igb_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include <linux/ethtool.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>

#include "igb.h"

Expand Down Expand Up @@ -2161,6 +2162,19 @@ static void igb_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
}
}

static int igb_ethtool_begin(struct net_device *netdev)
{
struct igb_adapter *adapter = netdev_priv(netdev);
pm_runtime_get_sync(&adapter->pdev->dev);
return 0;
}

static void igb_ethtool_complete(struct net_device *netdev)
{
struct igb_adapter *adapter = netdev_priv(netdev);
pm_runtime_put(&adapter->pdev->dev);
}

static const struct ethtool_ops igb_ethtool_ops = {
.get_settings = igb_get_settings,
.set_settings = igb_set_settings,
Expand All @@ -2187,6 +2201,8 @@ static const struct ethtool_ops igb_ethtool_ops = {
.get_ethtool_stats = igb_get_ethtool_stats,
.get_coalesce = igb_get_coalesce,
.set_coalesce = igb_set_coalesce,
.begin = igb_ethtool_begin,
.complete = igb_ethtool_complete,
};

void igb_set_ethtool_ops(struct net_device *netdev)
Expand Down
136 changes: 117 additions & 19 deletions trunk/drivers/net/ethernet/intel/igb/igb_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
#include <linux/if_ether.h>
#include <linux/aer.h>
#include <linux/prefetch.h>
#include <linux/pm_runtime.h>
#ifdef CONFIG_IGB_DCA
#include <linux/dca.h>
#endif
Expand Down Expand Up @@ -172,8 +173,18 @@ static int igb_check_vf_assignment(struct igb_adapter *adapter);
#endif

#ifdef CONFIG_PM
static int igb_suspend(struct pci_dev *, pm_message_t);
static int igb_resume(struct pci_dev *);
static int igb_suspend(struct device *);
static int igb_resume(struct device *);
#ifdef CONFIG_PM_RUNTIME
static int igb_runtime_suspend(struct device *dev);
static int igb_runtime_resume(struct device *dev);
static int igb_runtime_idle(struct device *dev);
#endif
static const struct dev_pm_ops igb_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(igb_suspend, igb_resume)
SET_RUNTIME_PM_OPS(igb_runtime_suspend, igb_runtime_resume,
igb_runtime_idle)
};
#endif
static void igb_shutdown(struct pci_dev *);
#ifdef CONFIG_IGB_DCA
Expand Down Expand Up @@ -214,9 +225,7 @@ static struct pci_driver igb_driver = {
.probe = igb_probe,
.remove = __devexit_p(igb_remove),
#ifdef CONFIG_PM
/* Power Management Hooks */
.suspend = igb_suspend,
.resume = igb_resume,
.driver.pm = &igb_pm_ops,
#endif
.shutdown = igb_shutdown,
.err_handler = &igb_err_handler
Expand Down Expand Up @@ -2111,6 +2120,8 @@ static int __devinit igb_probe(struct pci_dev *pdev,
default:
break;
}

pm_runtime_put_noidle(&pdev->dev);
return 0;

err_register:
Expand Down Expand Up @@ -2150,6 +2161,8 @@ static void __devexit igb_remove(struct pci_dev *pdev)
struct igb_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;

pm_runtime_get_noresume(&pdev->dev);

/*
* The watchdog timer may be rescheduled, so explicitly
* disable watchdog from being rescheduled.
Expand Down Expand Up @@ -2472,16 +2485,22 @@ static int __devinit igb_sw_init(struct igb_adapter *adapter)
* handler is registered with the OS, the watchdog timer is started,
* and the stack is notified that the interface is ready.
**/
static int igb_open(struct net_device *netdev)
static int __igb_open(struct net_device *netdev, bool resuming)
{
struct igb_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
struct pci_dev *pdev = adapter->pdev;
int err;
int i;

/* disallow open during test */
if (test_bit(__IGB_TESTING, &adapter->state))
if (test_bit(__IGB_TESTING, &adapter->state)) {
WARN_ON(resuming);
return -EBUSY;
}

if (!resuming)
pm_runtime_get_sync(&pdev->dev);

netif_carrier_off(netdev);

Expand Down Expand Up @@ -2527,6 +2546,9 @@ static int igb_open(struct net_device *netdev)

netif_tx_start_all_queues(netdev);

if (!resuming)
pm_runtime_put(&pdev->dev);

/* start the watchdog. */
hw->mac.get_link_status = 1;
schedule_work(&adapter->watchdog_task);
Expand All @@ -2541,10 +2563,17 @@ static int igb_open(struct net_device *netdev)
igb_free_all_tx_resources(adapter);
err_setup_tx:
igb_reset(adapter);
if (!resuming)
pm_runtime_put(&pdev->dev);

return err;
}

static int igb_open(struct net_device *netdev)
{
return __igb_open(netdev, false);
}

/**
* igb_close - Disables a network interface
* @netdev: network interface device structure
Expand All @@ -2556,21 +2585,32 @@ static int igb_open(struct net_device *netdev)
* needs to be disabled. A global MAC reset is issued to stop the
* hardware, and all transmit and receive resources are freed.
**/
static int igb_close(struct net_device *netdev)
static int __igb_close(struct net_device *netdev, bool suspending)
{
struct igb_adapter *adapter = netdev_priv(netdev);
struct pci_dev *pdev = adapter->pdev;

WARN_ON(test_bit(__IGB_RESETTING, &adapter->state));
igb_down(adapter);

if (!suspending)
pm_runtime_get_sync(&pdev->dev);

igb_down(adapter);
igb_free_irq(adapter);

igb_free_all_tx_resources(adapter);
igb_free_all_rx_resources(adapter);

if (!suspending)
pm_runtime_put_sync(&pdev->dev);
return 0;
}

static int igb_close(struct net_device *netdev)
{
return __igb_close(netdev, false);
}

/**
* igb_setup_tx_resources - allocate Tx resources (Descriptors)
* @tx_ring: tx descriptor ring (for a specific queue) to setup
Expand Down Expand Up @@ -3631,6 +3671,9 @@ static void igb_watchdog_task(struct work_struct *work)

link = igb_has_link(adapter);
if (link) {
/* Cancel scheduled suspend requests. */
pm_runtime_resume(netdev->dev.parent);

if (!netif_carrier_ok(netdev)) {
u32 ctrl;
hw->mac.ops.get_speed_and_duplex(hw,
Expand Down Expand Up @@ -3702,6 +3745,9 @@ static void igb_watchdog_task(struct work_struct *work)
if (!test_bit(__IGB_DOWN, &adapter->state))
mod_timer(&adapter->phy_info_timer,
round_jiffies(jiffies + 2 * HZ));

pm_schedule_suspend(netdev->dev.parent,
MSEC_PER_SEC * 5);
}
}

Expand Down Expand Up @@ -6588,21 +6634,22 @@ int igb_set_spd_dplx(struct igb_adapter *adapter, u32 spd, u8 dplx)
return -EINVAL;
}

static int __igb_shutdown(struct pci_dev *pdev, bool *enable_wake)
static int __igb_shutdown(struct pci_dev *pdev, bool *enable_wake,
bool runtime)
{
struct net_device *netdev = pci_get_drvdata(pdev);
struct igb_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
u32 ctrl, rctl, status;
u32 wufc = adapter->wol;
u32 wufc = runtime ? E1000_WUFC_LNKC : adapter->wol;
#ifdef CONFIG_PM
int retval = 0;
#endif

netif_device_detach(netdev);

if (netif_running(netdev))
igb_close(netdev);
__igb_close(netdev, true);

igb_clear_interrupt_scheme(adapter);

Expand Down Expand Up @@ -6661,12 +6708,13 @@ static int __igb_shutdown(struct pci_dev *pdev, bool *enable_wake)
}

#ifdef CONFIG_PM
static int igb_suspend(struct pci_dev *pdev, pm_message_t state)
static int igb_suspend(struct device *dev)
{
int retval;
bool wake;
struct pci_dev *pdev = to_pci_dev(dev);

retval = __igb_shutdown(pdev, &wake);
retval = __igb_shutdown(pdev, &wake, 0);
if (retval)
return retval;

Expand All @@ -6680,8 +6728,9 @@ static int igb_suspend(struct pci_dev *pdev, pm_message_t state)
return 0;
}

static int igb_resume(struct pci_dev *pdev)
static int igb_resume(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct net_device *netdev = pci_get_drvdata(pdev);
struct igb_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
Expand All @@ -6702,7 +6751,18 @@ static int igb_resume(struct pci_dev *pdev)
pci_enable_wake(pdev, PCI_D3hot, 0);
pci_enable_wake(pdev, PCI_D3cold, 0);

if (igb_init_interrupt_scheme(adapter)) {
if (!rtnl_is_locked()) {
/*
* shut up ASSERT_RTNL() warning in
* netif_set_real_num_tx/rx_queues.
*/
rtnl_lock();
err = igb_init_interrupt_scheme(adapter);
rtnl_unlock();
} else {
err = igb_init_interrupt_scheme(adapter);
}
if (err) {
dev_err(&pdev->dev, "Unable to allocate memory for queues\n");
return -ENOMEM;
}
Expand All @@ -6715,23 +6775,61 @@ static int igb_resume(struct pci_dev *pdev)

wr32(E1000_WUS, ~0);

if (netif_running(netdev)) {
err = igb_open(netdev);
if (netdev->flags & IFF_UP) {
err = __igb_open(netdev, true);
if (err)
return err;
}

netif_device_attach(netdev);
return 0;
}

#ifdef CONFIG_PM_RUNTIME
static int igb_runtime_idle(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct net_device *netdev = pci_get_drvdata(pdev);
struct igb_adapter *adapter = netdev_priv(netdev);

if (!igb_has_link(adapter))
pm_schedule_suspend(dev, MSEC_PER_SEC * 5);

return -EBUSY;
}

static int igb_runtime_suspend(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
int retval;
bool wake;

retval = __igb_shutdown(pdev, &wake, 1);
if (retval)
return retval;

if (wake) {
pci_prepare_to_sleep(pdev);
} else {
pci_wake_from_d3(pdev, false);
pci_set_power_state(pdev, PCI_D3hot);
}

return 0;
}

static int igb_runtime_resume(struct device *dev)
{
return igb_resume(dev);
}
#endif /* CONFIG_PM_RUNTIME */
#endif

static void igb_shutdown(struct pci_dev *pdev)
{
bool wake;

__igb_shutdown(pdev, &wake);
__igb_shutdown(pdev, &wake, 0);

if (system_state == SYSTEM_POWER_OFF) {
pci_wake_from_d3(pdev, wake);
Expand Down

0 comments on commit b447274

Please sign in to comment.