summaryrefslogtreecommitdiffstats
path: root/rt2x00_fix_MCU_request_failures.patch
diff options
context:
space:
mode:
authorJosh Boyer <jwboyer@redhat.com>2012-02-03 09:44:46 -0500
committerJosh Boyer <jwboyer@redhat.com>2012-02-03 09:44:46 -0500
commitd2b0178f32e66158b10664953c20a32fcff69655 (patch)
treed5605e54069a6160862ac5acc9c2e1e1c3432b9f /rt2x00_fix_MCU_request_failures.patch
parenta492600e58537402007adb67458144ecf9876cc3 (diff)
downloadkernel-d2b0178f32e66158b10664953c20a32fcff69655.tar.gz
kernel-d2b0178f32e66158b10664953c20a32fcff69655.tar.xz
kernel-d2b0178f32e66158b10664953c20a32fcff69655.zip
Patch from Jakub Kicinski to fix rt2x00 MCU requests (rhbz 772772)
Diffstat (limited to 'rt2x00_fix_MCU_request_failures.patch')
-rw-r--r--rt2x00_fix_MCU_request_failures.patch136
1 files changed, 136 insertions, 0 deletions
diff --git a/rt2x00_fix_MCU_request_failures.patch b/rt2x00_fix_MCU_request_failures.patch
new file mode 100644
index 000000000..f7b8a6a4c
--- /dev/null
+++ b/rt2x00_fix_MCU_request_failures.patch
@@ -0,0 +1,136 @@
+diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h
+index 2571a2f..822f9e5 100644
+--- a/drivers/net/wireless/rt2x00/rt2800.h
++++ b/drivers/net/wireless/rt2x00/rt2800.h
+@@ -1627,6 +1627,7 @@ struct mac_iveiv_entry {
+
+ /*
+ * H2M_MAILBOX_CSR: Host-to-MCU Mailbox.
++ * CMD_TOKEN: Command id, 0xff disable status reporting
+ */
+ #define H2M_MAILBOX_CSR 0x7010
+ #define H2M_MAILBOX_CSR_ARG0 FIELD32(0x000000ff)
+@@ -1636,6 +1637,8 @@ struct mac_iveiv_entry {
+
+ /*
+ * H2M_MAILBOX_CID:
++ * Free slots contain 0xff. MCU will store command's token to lowest free slot.
++ * If all slots are occupied status will be dropped.
+ */
+ #define H2M_MAILBOX_CID 0x7014
+ #define H2M_MAILBOX_CID_CMD0 FIELD32(0x000000ff)
+@@ -1645,6 +1648,7 @@ struct mac_iveiv_entry {
+
+ /*
+ * H2M_MAILBOX_STATUS:
++ * Command status will be saved to same slot as command id.
+ */
+ #define H2M_MAILBOX_STATUS 0x701c
+
+@@ -2259,6 +2263,12 @@ struct mac_iveiv_entry {
+
+ /*
+ * MCU mailbox commands.
++ * MCU_SLEEP - go to power-save mode.
++ * arg1: 1: save as much power as possible, 0: save less power
++ * status: 1: success, 2: already asleep,
++ * 3: maybe MAC is busy so can't finish this task
++ * MCU_RADIO_OFF
++ * arg0: 0: do power-saving, NOT turn off radio
+ */
+ #define MCU_SLEEP 0x30
+ #define MCU_WAKEUP 0x31
+@@ -2279,7 +2289,9 @@ struct mac_iveiv_entry {
+ /*
+ * MCU mailbox tokens
+ */
+-#define TOKEN_WAKUP 3
++#define TOKEN_SLEEP 1
++#define TOKEN_RADIO_OFF 2
++#define TOKEN_WAKEUP 3
+
+ /*
+ * DMA descriptor defines.
+diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
+index dc88bae..9ac3017 100644
+--- a/drivers/net/wireless/rt2x00/rt2800pci.c
++++ b/drivers/net/wireless/rt2x00/rt2800pci.c
+@@ -517,23 +517,6 @@ static void rt2800pci_disable_radio(struct rt2x00_dev *rt2x00dev)
+ }
+ }
+
+-static int rt2800pci_set_state(struct rt2x00_dev *rt2x00dev,
+- enum dev_state state)
+-{
+- if (state == STATE_AWAKE) {
+- rt2800_mcu_request(rt2x00dev, MCU_WAKEUP, TOKEN_WAKUP, 0, 0x02);
+- rt2800pci_mcu_status(rt2x00dev, TOKEN_WAKUP);
+- } else if (state == STATE_SLEEP) {
+- rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_STATUS,
+- 0xffffffff);
+- rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID,
+- 0xffffffff);
+- rt2800_mcu_request(rt2x00dev, MCU_SLEEP, 0x01, 0xff, 0x01);
+- }
+-
+- return 0;
+-}
+-
+ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+ {
+@@ -541,14 +524,20 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev,
+
+ switch (state) {
+ case STATE_RADIO_ON:
+- /*
+- * Before the radio can be enabled, the device first has
+- * to be woken up. After that it needs a bit of time
+- * to be fully awake and then the radio can be enabled.
+- */
+- rt2800pci_set_state(rt2x00dev, STATE_AWAKE);
+- msleep(1);
++ /* Initialise all registers and send MCU_BOOT_SIGNAL. */
+ retval = rt2800pci_enable_radio(rt2x00dev);
++
++ /* After resume MCU_BOOT_SIGNAL will trash those. */
++ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0);
++ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
++
++ /* Finish initialization procedure. */
++ rt2800_mcu_request(rt2x00dev, MCU_SLEEP, TOKEN_RADIO_OFF,
++ 0xff, 0x02);
++ rt2800pci_mcu_status(rt2x00dev, TOKEN_RADIO_OFF);
++
++ rt2800_mcu_request(rt2x00dev, MCU_WAKEUP, TOKEN_WAKEUP, 0, 0);
++ rt2800pci_mcu_status(rt2x00dev, TOKEN_WAKEUP);
+ break;
+ case STATE_RADIO_OFF:
+ /*
+@@ -556,7 +545,7 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev,
+ * be put to sleep for powersaving.
+ */
+ rt2800pci_disable_radio(rt2x00dev);
+- rt2800pci_set_state(rt2x00dev, STATE_SLEEP);
++ rt2800pci_set_device_state(rt2x00dev, STATE_SLEEP);
+ break;
+ case STATE_RADIO_IRQ_ON:
+ case STATE_RADIO_IRQ_OFF:
+@@ -565,8 +554,16 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev,
+ case STATE_DEEP_SLEEP:
+ case STATE_SLEEP:
+ case STATE_STANDBY:
++ /* PCIe devices won't report status after SLEEP request. */
++ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0);
++ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
++ rt2800_mcu_request(rt2x00dev, MCU_SLEEP, TOKEN_SLEEP,
++ 0xff, 0x01);
++ break;
+ case STATE_AWAKE:
+- retval = rt2800pci_set_state(rt2x00dev, state);
++ rt2800_mcu_request(rt2x00dev, MCU_WAKEUP, TOKEN_WAKEUP,
++ 0, 0x02);
++ rt2800pci_mcu_status(rt2x00dev, TOKEN_WAKEUP);
+ break;
+ default:
+ retval = -ENOTSUPP;