aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2009-11-28 22:43:07 -0500
committerDavid S. Miller <davem@davemloft.net>2009-11-29 19:46:29 -0500
commit89c758fa47b54d8ce10d2b39ed09de6da0ba4324 (patch)
tree3ad41c34f54f071ea986597295623775fbd19dc9 /drivers
parent78c1f0a06551f6ff61bfd7c1a9302115a8135a62 (diff)
sfc: Add power-management and wake-on-LAN support
Wake-on-LAN is a stub for Falcon, but will be implemented fully for new NICs. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/sfc/efx.c96
-rw-r--r--drivers/net/sfc/ethtool.c17
-rw-r--r--drivers/net/sfc/falcon.c27
-rw-r--r--drivers/net/sfc/net_driver.h6
4 files changed, 146 insertions, 0 deletions
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 14ef27fa8416..b016719d8f67 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -2243,11 +2243,107 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev,
2243 return rc; 2243 return rc;
2244} 2244}
2245 2245
2246static int efx_pm_freeze(struct device *dev)
2247{
2248 struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev));
2249
2250 efx->state = STATE_FINI;
2251
2252 netif_device_detach(efx->net_dev);
2253
2254 efx_stop_all(efx);
2255 efx_fini_channels(efx);
2256
2257 return 0;
2258}
2259
2260static int efx_pm_thaw(struct device *dev)
2261{
2262 struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev));
2263
2264 efx->state = STATE_INIT;
2265
2266 efx_init_channels(efx);
2267
2268 mutex_lock(&efx->mac_lock);
2269 efx->phy_op->reconfigure(efx);
2270 mutex_unlock(&efx->mac_lock);
2271
2272 efx_start_all(efx);
2273
2274 netif_device_attach(efx->net_dev);
2275
2276 efx->state = STATE_RUNNING;
2277
2278 efx->type->resume_wol(efx);
2279
2280 return 0;
2281}
2282
2283static int efx_pm_poweroff(struct device *dev)
2284{
2285 struct pci_dev *pci_dev = to_pci_dev(dev);
2286 struct efx_nic *efx = pci_get_drvdata(pci_dev);
2287
2288 efx->type->fini(efx);
2289
2290 efx->reset_pending = RESET_TYPE_NONE;
2291
2292 pci_save_state(pci_dev);
2293 return pci_set_power_state(pci_dev, PCI_D3hot);
2294}
2295
2296/* Used for both resume and restore */
2297static int efx_pm_resume(struct device *dev)
2298{
2299 struct pci_dev *pci_dev = to_pci_dev(dev);
2300 struct efx_nic *efx = pci_get_drvdata(pci_dev);
2301 int rc;
2302
2303 rc = pci_set_power_state(pci_dev, PCI_D0);
2304 if (rc)
2305 return rc;
2306 pci_restore_state(pci_dev);
2307 rc = pci_enable_device(pci_dev);
2308 if (rc)
2309 return rc;
2310 pci_set_master(efx->pci_dev);
2311 rc = efx->type->reset(efx, RESET_TYPE_ALL);
2312 if (rc)
2313 return rc;
2314 rc = efx->type->init(efx);
2315 if (rc)
2316 return rc;
2317 efx_pm_thaw(dev);
2318 return 0;
2319}
2320
2321static int efx_pm_suspend(struct device *dev)
2322{
2323 int rc;
2324
2325 efx_pm_freeze(dev);
2326 rc = efx_pm_poweroff(dev);
2327 if (rc)
2328 efx_pm_resume(dev);
2329 return rc;
2330}
2331
2332static struct dev_pm_ops efx_pm_ops = {
2333 .suspend = efx_pm_suspend,
2334 .resume = efx_pm_resume,
2335 .freeze = efx_pm_freeze,
2336 .thaw = efx_pm_thaw,
2337 .poweroff = efx_pm_poweroff,
2338 .restore = efx_pm_resume,
2339};
2340
2246static struct pci_driver efx_pci_driver = { 2341static struct pci_driver efx_pci_driver = {
2247 .name = EFX_DRIVER_NAME, 2342 .name = EFX_DRIVER_NAME,
2248 .id_table = efx_pci_table, 2343 .id_table = efx_pci_table,
2249 .probe = efx_pci_probe, 2344 .probe = efx_pci_probe,
2250 .remove = efx_pci_remove, 2345 .remove = efx_pci_remove,
2346 .driver.pm = &efx_pm_ops,
2251}; 2347};
2252 2348
2253/************************************************************************** 2349/**************************************************************************
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c
index d95d0fa399ff..b4c6ea1b9c07 100644
--- a/drivers/net/sfc/ethtool.c
+++ b/drivers/net/sfc/ethtool.c
@@ -739,6 +739,21 @@ static void efx_ethtool_get_pauseparam(struct net_device *net_dev,
739} 739}
740 740
741 741
742static void efx_ethtool_get_wol(struct net_device *net_dev,
743 struct ethtool_wolinfo *wol)
744{
745 struct efx_nic *efx = netdev_priv(net_dev);
746 return efx->type->get_wol(efx, wol);
747}
748
749
750static int efx_ethtool_set_wol(struct net_device *net_dev,
751 struct ethtool_wolinfo *wol)
752{
753 struct efx_nic *efx = netdev_priv(net_dev);
754 return efx->type->set_wol(efx, wol->wolopts);
755}
756
742const struct ethtool_ops efx_ethtool_ops = { 757const struct ethtool_ops efx_ethtool_ops = {
743 .get_settings = efx_ethtool_get_settings, 758 .get_settings = efx_ethtool_get_settings,
744 .set_settings = efx_ethtool_set_settings, 759 .set_settings = efx_ethtool_set_settings,
@@ -767,4 +782,6 @@ const struct ethtool_ops efx_ethtool_ops = {
767 .get_strings = efx_ethtool_get_strings, 782 .get_strings = efx_ethtool_get_strings,
768 .phys_id = efx_ethtool_phys_id, 783 .phys_id = efx_ethtool_phys_id,
769 .get_ethtool_stats = efx_ethtool_get_stats, 784 .get_ethtool_stats = efx_ethtool_get_stats,
785 .get_wol = efx_ethtool_get_wol,
786 .set_wol = efx_ethtool_set_wol,
770}; 787};
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 3466616c01c0..8f2c58305538 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -3245,6 +3245,27 @@ void falcon_stop_nic_stats(struct efx_nic *efx)
3245 3245
3246/************************************************************************** 3246/**************************************************************************
3247 * 3247 *
3248 * Wake on LAN
3249 *
3250 **************************************************************************
3251 */
3252
3253static void falcon_get_wol(struct efx_nic *efx, struct ethtool_wolinfo *wol)
3254{
3255 wol->supported = 0;
3256 wol->wolopts = 0;
3257 memset(&wol->sopass, 0, sizeof(wol->sopass));
3258}
3259
3260static int falcon_set_wol(struct efx_nic *efx, u32 type)
3261{
3262 if (type != 0)
3263 return -EINVAL;
3264 return 0;
3265}
3266
3267/**************************************************************************
3268 *
3248 * Revision-dependent attributes used by efx.c 3269 * Revision-dependent attributes used by efx.c
3249 * 3270 *
3250 ************************************************************************** 3271 **************************************************************************
@@ -3266,6 +3287,9 @@ struct efx_nic_type falcon_a1_nic_type = {
3266 .push_irq_moderation = falcon_push_irq_moderation, 3287 .push_irq_moderation = falcon_push_irq_moderation,
3267 .push_multicast_hash = falcon_push_multicast_hash, 3288 .push_multicast_hash = falcon_push_multicast_hash,
3268 .reconfigure_port = falcon_reconfigure_port, 3289 .reconfigure_port = falcon_reconfigure_port,
3290 .get_wol = falcon_get_wol,
3291 .set_wol = falcon_set_wol,
3292 .resume_wol = efx_port_dummy_op_void,
3269 .default_mac_ops = &falcon_xmac_operations, 3293 .default_mac_ops = &falcon_xmac_operations,
3270 3294
3271 .revision = EFX_REV_FALCON_A1, 3295 .revision = EFX_REV_FALCON_A1,
@@ -3299,6 +3323,9 @@ struct efx_nic_type falcon_b0_nic_type = {
3299 .push_irq_moderation = falcon_push_irq_moderation, 3323 .push_irq_moderation = falcon_push_irq_moderation,
3300 .push_multicast_hash = falcon_push_multicast_hash, 3324 .push_multicast_hash = falcon_push_multicast_hash,
3301 .reconfigure_port = falcon_reconfigure_port, 3325 .reconfigure_port = falcon_reconfigure_port,
3326 .get_wol = falcon_get_wol,
3327 .set_wol = falcon_set_wol,
3328 .resume_wol = efx_port_dummy_op_void,
3302 .default_mac_ops = &falcon_xmac_operations, 3329 .default_mac_ops = &falcon_xmac_operations,
3303 3330
3304 .revision = EFX_REV_FALCON_B0, 3331 .revision = EFX_REV_FALCON_B0,
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index f63a05c4e38b..a9fde82aeeae 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -861,6 +861,9 @@ static inline const char *efx_dev_name(struct efx_nic *efx)
861 * @push_irq_moderation: Apply interrupt moderation value 861 * @push_irq_moderation: Apply interrupt moderation value
862 * @push_multicast_hash: Apply multicast hash table 862 * @push_multicast_hash: Apply multicast hash table
863 * @reconfigure_port: Push loopback/power/txdis changes to the MAC and PHY 863 * @reconfigure_port: Push loopback/power/txdis changes to the MAC and PHY
864 * @get_wol: Get WoL configuration from driver state
865 * @set_wol: Push WoL configuration to the NIC
866 * @resume_wol: Synchronise WoL state between driver and MC (e.g. after resume)
864 * @default_mac_ops: efx_mac_operations to set at startup 867 * @default_mac_ops: efx_mac_operations to set at startup
865 * @revision: Hardware architecture revision 868 * @revision: Hardware architecture revision
866 * @mem_map_size: Memory BAR mapped size 869 * @mem_map_size: Memory BAR mapped size
@@ -894,6 +897,9 @@ struct efx_nic_type {
894 void (*push_irq_moderation)(struct efx_channel *channel); 897 void (*push_irq_moderation)(struct efx_channel *channel);
895 void (*push_multicast_hash)(struct efx_nic *efx); 898 void (*push_multicast_hash)(struct efx_nic *efx);
896 int (*reconfigure_port)(struct efx_nic *efx); 899 int (*reconfigure_port)(struct efx_nic *efx);
900 void (*get_wol)(struct efx_nic *efx, struct ethtool_wolinfo *wol);
901 int (*set_wol)(struct efx_nic *efx, u32 type);
902 void (*resume_wol)(struct efx_nic *efx);
897 struct efx_mac_operations *default_mac_ops; 903 struct efx_mac_operations *default_mac_ops;
898 904
899 int revision; 905 int revision;