diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2009-11-28 22:43:07 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-11-29 19:46:29 -0500 |
commit | 89c758fa47b54d8ce10d2b39ed09de6da0ba4324 (patch) | |
tree | 3ad41c34f54f071ea986597295623775fbd19dc9 /drivers | |
parent | 78c1f0a06551f6ff61bfd7c1a9302115a8135a62 (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.c | 96 | ||||
-rw-r--r-- | drivers/net/sfc/ethtool.c | 17 | ||||
-rw-r--r-- | drivers/net/sfc/falcon.c | 27 | ||||
-rw-r--r-- | drivers/net/sfc/net_driver.h | 6 |
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 | ||
2246 | static 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 | |||
2260 | static 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 | |||
2283 | static 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 */ | ||
2297 | static 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 | |||
2321 | static 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 | |||
2332 | static 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 | |||
2246 | static struct pci_driver efx_pci_driver = { | 2341 | static 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 | ||
742 | static 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 | |||
750 | static 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 | |||
742 | const struct ethtool_ops efx_ethtool_ops = { | 757 | const 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 | |||
3253 | static 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 | |||
3260 | static 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; |