| From sgruszka@redhat.com Wed Oct 20 10:35:02 2010 |
| From: Stanislaw Gruszka <sgruszka@redhat.com> |
| To: stable@kernel.org |
| Subject: [PATCH -stable 2.6.34 2/2] rt2x00: Fix failed SLEEP->AWAKE and AWAKE->SLEEP transitions. |
| Date: Wed, 20 Oct 2010 16:37:28 +0200 |
| |
| From: Gertjan van Wingerde <gwingerde@gmail.com> |
| |
| commit 9655a6ec19ca656af246fb80817aa337892aefbf upstream. |
| |
| Together with "rt2x00: Disable auto wakeup before waking up device" |
| fix kernel oops/hang reported here: |
| https://bugzilla.redhat.com/show_bug.cgi?id=642031 |
| |
| (Based on a patch created by Ondrej Zary) |
| |
| In some circumstances the Ralink devices do not properly go to sleep |
| or wake up, with timeouts occurring. |
| Fix this by retrying telling the device that it has to wake up or |
| sleep. |
| |
| Signed-off-by: Gertjan van Wingerde <gwingerde@gmail.com> |
| Acked-by: Ivo van Doorn <IvDoorn@gmail.com> |
| Signed-off-by: John W. Linville <linville@tuxdriver.com> |
| |
| drivers/net/wireless/rt2x00/rt2400pci.c | 9 +++++---- |
| drivers/net/wireless/rt2x00/rt2500pci.c | 9 +++++---- |
| drivers/net/wireless/rt2x00/rt61pci.c | 7 ++++--- |
| drivers/net/wireless/rt2x00/rt73usb.c | 7 ++++--- |
| 4 files changed, 18 insertions(+), 14 deletions(-) |
| |
| diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c |
| index 4ba7b038..ad2c98a 100644 |
| |
| |
| @@ -926,7 +926,7 @@ static void rt2400pci_disable_radio(struct rt2x00_dev *rt2x00dev) |
| static int rt2400pci_set_state(struct rt2x00_dev *rt2x00dev, |
| enum dev_state state) |
| { |
| - u32 reg; |
| + u32 reg, reg2; |
| unsigned int i; |
| char put_to_sleep; |
| char bbp_state; |
| @@ -947,11 +947,12 @@ static int rt2400pci_set_state(struct rt2x00_dev *rt2x00dev, |
| * device has entered the correct state. |
| */ |
| for (i = 0; i < REGISTER_BUSY_COUNT; i++) { |
| - rt2x00pci_register_read(rt2x00dev, PWRCSR1, ®); |
| - bbp_state = rt2x00_get_field32(reg, PWRCSR1_BBP_CURR_STATE); |
| - rf_state = rt2x00_get_field32(reg, PWRCSR1_RF_CURR_STATE); |
| + rt2x00pci_register_read(rt2x00dev, PWRCSR1, ®2); |
| + bbp_state = rt2x00_get_field32(reg2, PWRCSR1_BBP_CURR_STATE); |
| + rf_state = rt2x00_get_field32(reg2, PWRCSR1_RF_CURR_STATE); |
| if (bbp_state == state && rf_state == state) |
| return 0; |
| + rt2x00pci_register_write(rt2x00dev, PWRCSR1, reg); |
| msleep(10); |
| } |
| |
| diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c |
| index 89d132d..41da3d2 100644 |
| |
| |
| @@ -1084,7 +1084,7 @@ static void rt2500pci_disable_radio(struct rt2x00_dev *rt2x00dev) |
| static int rt2500pci_set_state(struct rt2x00_dev *rt2x00dev, |
| enum dev_state state) |
| { |
| - u32 reg; |
| + u32 reg, reg2; |
| unsigned int i; |
| char put_to_sleep; |
| char bbp_state; |
| @@ -1105,11 +1105,12 @@ static int rt2500pci_set_state(struct rt2x00_dev *rt2x00dev, |
| * device has entered the correct state. |
| */ |
| for (i = 0; i < REGISTER_BUSY_COUNT; i++) { |
| - rt2x00pci_register_read(rt2x00dev, PWRCSR1, ®); |
| - bbp_state = rt2x00_get_field32(reg, PWRCSR1_BBP_CURR_STATE); |
| - rf_state = rt2x00_get_field32(reg, PWRCSR1_RF_CURR_STATE); |
| + rt2x00pci_register_read(rt2x00dev, PWRCSR1, ®2); |
| + bbp_state = rt2x00_get_field32(reg2, PWRCSR1_BBP_CURR_STATE); |
| + rf_state = rt2x00_get_field32(reg2, PWRCSR1_RF_CURR_STATE); |
| if (bbp_state == state && rf_state == state) |
| return 0; |
| + rt2x00pci_register_write(rt2x00dev, PWRCSR1, reg); |
| msleep(10); |
| } |
| |
| diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c |
| index 2e3076f..6a74baf 100644 |
| |
| |
| @@ -1689,7 +1689,7 @@ static void rt61pci_disable_radio(struct rt2x00_dev *rt2x00dev) |
| |
| static int rt61pci_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) |
| { |
| - u32 reg; |
| + u32 reg, reg2; |
| unsigned int i; |
| char put_to_sleep; |
| |
| @@ -1706,10 +1706,11 @@ static int rt61pci_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) |
| * device has entered the correct state. |
| */ |
| for (i = 0; i < REGISTER_BUSY_COUNT; i++) { |
| - rt2x00pci_register_read(rt2x00dev, MAC_CSR12, ®); |
| - state = rt2x00_get_field32(reg, MAC_CSR12_BBP_CURRENT_STATE); |
| + rt2x00pci_register_read(rt2x00dev, MAC_CSR12, ®2); |
| + state = rt2x00_get_field32(reg2, MAC_CSR12_BBP_CURRENT_STATE); |
| if (state == !put_to_sleep) |
| return 0; |
| + rt2x00pci_register_write(rt2x00dev, MAC_CSR12, reg); |
| msleep(10); |
| } |
| |
| diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c |
| index e35bd19..6e0d82e 100644 |
| |
| |
| @@ -1366,7 +1366,7 @@ static void rt73usb_disable_radio(struct rt2x00_dev *rt2x00dev) |
| |
| static int rt73usb_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) |
| { |
| - u32 reg; |
| + u32 reg, reg2; |
| unsigned int i; |
| char put_to_sleep; |
| |
| @@ -1383,10 +1383,11 @@ static int rt73usb_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) |
| * device has entered the correct state. |
| */ |
| for (i = 0; i < REGISTER_BUSY_COUNT; i++) { |
| - rt2x00usb_register_read(rt2x00dev, MAC_CSR12, ®); |
| - state = rt2x00_get_field32(reg, MAC_CSR12_BBP_CURRENT_STATE); |
| + rt2x00usb_register_read(rt2x00dev, MAC_CSR12, ®2); |
| + state = rt2x00_get_field32(reg2, MAC_CSR12_BBP_CURRENT_STATE); |
| if (state == !put_to_sleep) |
| return 0; |
| + rt2x00usb_register_write(rt2x00dev, MAC_CSR12, reg); |
| msleep(10); |
| } |
| |
| -- |
| 1.7.2.3 |
| |