diff --git a/kernel.spec b/kernel.spec index c53aa5d..d67e19b 100644 --- a/kernel.spec +++ b/kernel.spec @@ -744,6 +744,8 @@ Patch21091: kmemleak.patch Patch21092: udlfb-remove-sysfs-framebuffer-device-with-USB-disconnect.patch +Patch21093: rt2x00_fix_MCU_request_failures.patch + # compat-wireless patches Patch50000: compat-wireless-config-fixups.patch Patch50001: compat-wireless-pr_fmt-warning-avoidance.patch @@ -1440,6 +1442,9 @@ ApplyPatch udlfb-remove-sysfs-framebuffer-device-with-USB-disconnect.patch #rhbz 783211 ApplyPatch fs-Inval-cache-for-parent-block-device-if-fsync-called-on-part.patch +#rhbz 772772 +ApplyPatch rt2x00_fix_MCU_request_failures.patch + # END OF PATCH APPLICATIONS %endif @@ -1510,6 +1515,7 @@ ApplyPatch compat-move-br_port_exists-to-compat-2_6_36_h.patch ApplyPatch compat-wireless-fix-some-config-options.patch ApplyPatch ath9k-use-WARN_ON_ONCE-in-ath_rc_get_highest_rix.patch +ApplyPatch rt2x00_fix_MCU_request_failures.patch cd .. @@ -2286,6 +2292,9 @@ fi # ||----w | # || || %changelog +* Fri Feb 03 2012 Josh Boyer +- Patch from Jakub Kicinski to fix rt2x00 MCU requests (rhbz 772772) + * Thu Feb 02 2012 Dennis Gilmore - disable TOUCHSCREEN_EGALAX on arm arches - build in CACHE_L2X0 on the imx kernel diff --git a/rt2x00_fix_MCU_request_failures.patch b/rt2x00_fix_MCU_request_failures.patch new file mode 100644 index 0000000..f7b8a6a --- /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;