After writing PUT_TO_SLEEP to the device, wait untill the CURRENT_STATE of the device indicates it is asleep before returning from the suspend function. When suspend fails, call the resume function to bring the device back to live again.
Signed-off-by Ivo van Doorn <[EMAIL PROTECTED]> diff -U 3 -H -w -E -d -r -N -- wireless-2.6/drivers/net/wireless/rt2x00/rt2400pci.c wireless-2.6-rt2x00/drivers/net/wireless/rt2x00/rt2400pci.c --- wireless-2.6/drivers/net/wireless/rt2x00/rt2400pci.c 2006-02-09 20:35:21.000000000 +0100 +++ wireless-2.6-rt2x00/drivers/net/wireless/rt2x00/rt2400pci.c 2006-02-11 22:56:08.000000000 +0100 @@ -2238,11 +2279,15 @@ } #ifdef CONFIG_PM +static int rt2400pci_suspend(struct pci_dev *pci_dev, pm_message_t state); +static int rt2400pci_resume(struct pci_dev *pci_dev); + static int rt2400pci_suspend(struct pci_dev *pci_dev, pm_message_t state) { struct net_device *net_dev = pci_get_drvdata(pci_dev); struct rt2x00_pci *rt2x00pci = ieee80211_dev_hw_data(net_dev); + int counter = 0; u32 reg = 0; NOTICE("Going to sleep.\n"); @@ -2250,21 +2295,42 @@ if(ieee80211_netif_oper(net_dev, NETIF_DETACH)) return -EBUSY; - reg = 0; + rt2x00_register_read(rt2x00pci, PWRCSR1, ®); rt2x00_set_field32(®, PWRCSR1_SET_STATE, 1); rt2x00_set_field32(®, PWRCSR1_BBP_DESIRE_STATE, 1); rt2x00_set_field32(®, PWRCSR1_RF_DESIRE_STATE, 1); rt2x00_set_field32(®, PWRCSR1_PUT_TO_SLEEP, 1); rt2x00_register_write(rt2x00pci, PWRCSR1, reg); + /* + * Device is not guarenteed to be asleep yet. + * We must wait untill the register indicates + * device has been correctly put to sleep. + */ + for(counter = 0; counter < REGISTER_BUSY_COUNT; counter++){ + rt2x00_register_read(rt2x00pci, PWRCSR1, ®); + if((rt2x00_get_field32(reg, PWRCSR1_BBP_CURR_STATE) == 1) + && (rt2x00_get_field32(reg, PWRCSR1_RF_CURR_STATE) == 1)) + break; + NOTICE("Waiting for device to sleep.\n"); + msleep(10); + } + + if(counter == REGISTER_BUSY_COUNT) + goto exit; + if(pci_enable_wake(pci_dev, pci_choose_state(pci_dev, state), 1) || pci_save_state(pci_dev) - || pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))){ - ERROR("Failed to suspend device.\n"); - return -EIO; - } + || pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) + goto exit; return 0; + +exit: + ERROR("Failed to suspend device.\n"); + + rt2400pci_resume(pci_dev); + return -EIO; } static int @@ -2283,6 +2349,7 @@ return -EIO; } + rt2x00_register_read(rt2x00pci, PWRCSR1, ®); rt2x00_set_field32(®, PWRCSR1_SET_STATE, 1); rt2x00_set_field32(®, PWRCSR1_BBP_DESIRE_STATE, 3); rt2x00_set_field32(®, PWRCSR1_RF_DESIRE_STATE, 3); diff -U 3 -H -w -E -d -r -N -- wireless-2.6/drivers/net/wireless/rt2x00/rt2500pci.c wireless-2.6-rt2x00/drivers/net/wireless/rt2x00/rt2500pci.c --- wireless-2.6/drivers/net/wireless/rt2x00/rt2500pci.c 2006-02-09 20:35:21.000000000 +0100 +++ wireless-2.6-rt2x00/drivers/net/wireless/rt2x00/rt2500pci.c 2006-02-11 22:56:28.000000000 +0100 @@ -2513,11 +2541,15 @@ } #ifdef CONFIG_PM +static int rt2500pci_suspend(struct pci_dev *pci_dev, pm_message_t state); +static int rt2500pci_resume(struct pci_dev *pci_dev); + static int rt2500pci_suspend(struct pci_dev *pci_dev, pm_message_t state) { struct net_device *net_dev = pci_get_drvdata(pci_dev); struct rt2x00_pci *rt2x00pci = ieee80211_dev_hw_data(net_dev); + int counter = 0; u32 reg = 0; NOTICE("Going to sleep.\n"); @@ -2525,21 +2557,42 @@ if(ieee80211_netif_oper(net_dev, NETIF_DETACH)) return -EBUSY; - reg = 0; + rt2x00_register_read(rt2x00pci, PWRCSR1, ®); rt2x00_set_field32(®, PWRCSR1_SET_STATE, 1); rt2x00_set_field32(®, PWRCSR1_BBP_DESIRE_STATE, 1); rt2x00_set_field32(®, PWRCSR1_RF_DESIRE_STATE, 1); rt2x00_set_field32(®, PWRCSR1_PUT_TO_SLEEP, 1); rt2x00_register_write(rt2x00pci, PWRCSR1, reg); + /* + * Device is not guarenteed to be asleep yet. + * We must wait untill the register indicates + * device has been correctly put to sleep. + */ + for(counter = 0; counter < REGISTER_BUSY_COUNT; counter++){ + rt2x00_register_read(rt2x00pci, PWRCSR1, ®); + if((rt2x00_get_field32(reg, PWRCSR1_BBP_CURR_STATE) == 1) + && (rt2x00_get_field32(reg, PWRCSR1_RF_CURR_STATE) == 1)) + break; + NOTICE("Waiting for device to sleep.\n"); + msleep(10); + } + + if(counter == REGISTER_BUSY_COUNT) + goto exit; + if(pci_enable_wake(pci_dev, pci_choose_state(pci_dev, state), 1) || pci_save_state(pci_dev) - || pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))){ - ERROR("Failed to suspend device.\n"); - return -EIO; - } + || pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) + goto exit; return 0; + +exit: + ERROR("Failed to suspend device.\n"); + + rt2500pci_resume(pci_dev); + return -EIO; } static int @@ -2558,6 +2611,7 @@ return -EIO; } + rt2x00_register_read(rt2x00pci, PWRCSR1, ®); rt2x00_set_field32(®, PWRCSR1_SET_STATE, 1); rt2x00_set_field32(®, PWRCSR1_BBP_DESIRE_STATE, 3); rt2x00_set_field32(®, PWRCSR1_RF_DESIRE_STATE, 3); diff -U 3 -H -w -E -d -r -N -- wireless-2.6/drivers/net/wireless/rt2x00/rt2500usb.c wireless-2.6-rt2x00/drivers/net/wireless/rt2x00/rt2500usb.c --- wireless-2.6/drivers/net/wireless/rt2x00/rt2500usb.c 2006-02-09 20:35:21.000000000 +0100 +++ wireless-2.6-rt2x00/drivers/net/wireless/rt2x00/rt2500usb.c 2006-02-11 22:56:01.000000000 +0100 @@ -2133,11 +2172,16 @@ } #ifdef CONFIG_PM +static int rt2500usb_suspend( + struct usb_interface *usb_intf, pm_message_t state); +static int rt2500usb_resume(struct usb_interface *usb_intf); + static int rt2500usb_suspend(struct usb_interface *usb_intf, pm_message_t state) { struct net_device *net_dev = usb_get_intfdata(usb_intf); struct rt2x00_usb *rt2x00usb = ieee80211_dev_hw_data(net_dev); + int counter = 0; u16 reg = 0; NOTICE("Going to sleep.\n"); @@ -2145,14 +2189,29 @@ if(ieee80211_netif_oper(net_dev, NETIF_DETACH)) return -EBUSY; - reg = 0; + rt2x00_register_read(rt2x00usb, MAC_CSR17, ®); rt2x00_set_field16_nb(®, MAC_CSR17_SET_STATE, 1); rt2x00_set_field16_nb(®, MAC_CSR17_BBP_DESIRE_STATE, 1); rt2x00_set_field16_nb(®, MAC_CSR17_RF_DESIRE_STATE, 1); rt2x00_set_field16_nb(®, MAC_CSR17_PUT_TO_SLEEP, 1); rt2x00_register_write(rt2x00usb, MAC_CSR17, reg); + /* + * Device is not guarenteed to be asleep yet. + * We must wait untill the register indicates + * device has been correctly put to sleep. + */ + for(counter = 0; counter < REGISTER_BUSY_COUNT; counter++){ + rt2x00_register_read(rt2x00usb, MAC_CSR17, ®); + if((rt2x00_get_field16_nb(reg, MAC_CSR17_BBP_CURR_STATE) == 1) + && (rt2x00_get_field16_nb(reg, MAC_CSR17_RF_CURR_STATE) == 1)) return 0; + NOTICE("Waiting for device to sleep.\n"); + msleep(10); + } + + rt2500usb_resume(usb_intf); + return -EIO; } static int @@ -2164,6 +2223,7 @@ NOTICE("Waking up.\n"); + rt2x00_register_read(rt2x00usb, MAC_CSR17, ®); rt2x00_set_field16_nb(®, MAC_CSR17_SET_STATE, 1); rt2x00_set_field16_nb(®, MAC_CSR17_BBP_DESIRE_STATE, 3); rt2x00_set_field16_nb(®, MAC_CSR17_RF_DESIRE_STATE, 3);
pgpx5QoON7e0y.pgp
Description: PGP signature