summaryrefslogtreecommitdiffstats
path: root/rt2x00_fix_MCU_request_failures.patch
blob: f7b8a6a4c59d47efe22278e1a90331b228bbe364 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
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;