aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/rt2x00/rt61pci.c
diff options
context:
space:
mode:
authorIvo van Doorn <ivdoorn@gmail.com>2008-11-09 17:40:46 -0500
committerJohn W. Linville <linville@tuxdriver.com>2008-11-21 11:08:16 -0500
commit8ff48a8bbe4a1ba29dea2836dfce74660f97c1be (patch)
tree611c0e996813c59c229694b52d329c24829b80e8 /drivers/net/wireless/rt2x00/rt61pci.c
parentbad13639a30e1557fbe9d440adc1906673c9de4e (diff)
rt2x00: Fix race condition when using inderect registers
Indirect registers require multiple calls to the CSR register in order to access the indirect registers. This must be protected under a lock to prevent race conditions which could cause invalid data to be returned when reading from the indirect register or silent failures when writing data to the indirect register. USB drivers where already protected under a mutex, so rename the mutex and make PCI drivers use the mutex as well. This now means that BBP and RF registers are no longer accessible in interrupt context. That is not a bad situation since the slow behavior of accessing those registers means we don't _want_ to access them in interrupt context either. Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt61pci.c')
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c66
1 files changed, 47 insertions, 19 deletions
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index abfe33b5712a..89ac34fbadf2 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -75,14 +75,14 @@ static void rt61pci_bbp_write(struct rt2x00_dev *rt2x00dev,
75{ 75{
76 u32 reg; 76 u32 reg;
77 77
78 mutex_lock(&rt2x00dev->csr_mutex);
79
78 /* 80 /*
79 * Wait until the BBP becomes ready. 81 * Wait until the BBP becomes ready.
80 */ 82 */
81 reg = rt61pci_bbp_check(rt2x00dev); 83 reg = rt61pci_bbp_check(rt2x00dev);
82 if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) { 84 if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
83 ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n"); 85 goto exit_fail;
84 return;
85 }
86 86
87 /* 87 /*
88 * Write the data into the BBP. 88 * Write the data into the BBP.
@@ -94,6 +94,14 @@ static void rt61pci_bbp_write(struct rt2x00_dev *rt2x00dev,
94 rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 0); 94 rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 0);
95 95
96 rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg); 96 rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg);
97 mutex_unlock(&rt2x00dev->csr_mutex);
98
99 return;
100
101exit_fail:
102 mutex_unlock(&rt2x00dev->csr_mutex);
103
104 ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n");
97} 105}
98 106
99static void rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev, 107static void rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev,
@@ -101,14 +109,14 @@ static void rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev,
101{ 109{
102 u32 reg; 110 u32 reg;
103 111
112 mutex_lock(&rt2x00dev->csr_mutex);
113
104 /* 114 /*
105 * Wait until the BBP becomes ready. 115 * Wait until the BBP becomes ready.
106 */ 116 */
107 reg = rt61pci_bbp_check(rt2x00dev); 117 reg = rt61pci_bbp_check(rt2x00dev);
108 if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) { 118 if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
109 ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n"); 119 goto exit_fail;
110 return;
111 }
112 120
113 /* 121 /*
114 * Write the request into the BBP. 122 * Write the request into the BBP.
@@ -124,13 +132,19 @@ static void rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev,
124 * Wait until the BBP becomes ready. 132 * Wait until the BBP becomes ready.
125 */ 133 */
126 reg = rt61pci_bbp_check(rt2x00dev); 134 reg = rt61pci_bbp_check(rt2x00dev);
127 if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) { 135 if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
128 ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n"); 136 goto exit_fail;
129 *value = 0xff;
130 return;
131 }
132 137
133 *value = rt2x00_get_field32(reg, PHY_CSR3_VALUE); 138 *value = rt2x00_get_field32(reg, PHY_CSR3_VALUE);
139 mutex_unlock(&rt2x00dev->csr_mutex);
140
141 return;
142
143exit_fail:
144 mutex_unlock(&rt2x00dev->csr_mutex);
145
146 ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n");
147 *value = 0xff;
134} 148}
135 149
136static void rt61pci_rf_write(struct rt2x00_dev *rt2x00dev, 150static void rt61pci_rf_write(struct rt2x00_dev *rt2x00dev,
@@ -142,6 +156,8 @@ static void rt61pci_rf_write(struct rt2x00_dev *rt2x00dev,
142 if (!word) 156 if (!word)
143 return; 157 return;
144 158
159 mutex_lock(&rt2x00dev->csr_mutex);
160
145 for (i = 0; i < REGISTER_BUSY_COUNT; i++) { 161 for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
146 rt2x00pci_register_read(rt2x00dev, PHY_CSR4, &reg); 162 rt2x00pci_register_read(rt2x00dev, PHY_CSR4, &reg);
147 if (!rt2x00_get_field32(reg, PHY_CSR4_BUSY)) 163 if (!rt2x00_get_field32(reg, PHY_CSR4_BUSY))
@@ -149,6 +165,7 @@ static void rt61pci_rf_write(struct rt2x00_dev *rt2x00dev,
149 udelay(REGISTER_BUSY_DELAY); 165 udelay(REGISTER_BUSY_DELAY);
150 } 166 }
151 167
168 mutex_unlock(&rt2x00dev->csr_mutex);
152 ERROR(rt2x00dev, "PHY_CSR4 register busy. Write failed.\n"); 169 ERROR(rt2x00dev, "PHY_CSR4 register busy. Write failed.\n");
153 return; 170 return;
154 171
@@ -161,6 +178,8 @@ rf_write:
161 178
162 rt2x00pci_register_write(rt2x00dev, PHY_CSR4, reg); 179 rt2x00pci_register_write(rt2x00dev, PHY_CSR4, reg);
163 rt2x00_rf_write(rt2x00dev, word, value); 180 rt2x00_rf_write(rt2x00dev, word, value);
181
182 mutex_unlock(&rt2x00dev->csr_mutex);
164} 183}
165 184
166#ifdef CONFIG_RT2X00_LIB_LEDS 185#ifdef CONFIG_RT2X00_LIB_LEDS
@@ -175,14 +194,12 @@ static void rt61pci_mcu_request(struct rt2x00_dev *rt2x00dev,
175{ 194{
176 u32 reg; 195 u32 reg;
177 196
197 mutex_lock(&rt2x00dev->csr_mutex);
198
178 rt2x00pci_register_read(rt2x00dev, H2M_MAILBOX_CSR, &reg); 199 rt2x00pci_register_read(rt2x00dev, H2M_MAILBOX_CSR, &reg);
179 200
180 if (rt2x00_get_field32(reg, H2M_MAILBOX_CSR_OWNER)) { 201 if (rt2x00_get_field32(reg, H2M_MAILBOX_CSR_OWNER))
181 ERROR(rt2x00dev, "mcu request error. " 202 goto exit_fail;
182 "Request 0x%02x failed for token 0x%02x.\n",
183 command, token);
184 return;
185 }
186 203
187 rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_OWNER, 1); 204 rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_OWNER, 1);
188 rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_CMD_TOKEN, token); 205 rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_CMD_TOKEN, token);
@@ -194,6 +211,17 @@ static void rt61pci_mcu_request(struct rt2x00_dev *rt2x00dev,
194 rt2x00_set_field32(&reg, HOST_CMD_CSR_HOST_COMMAND, command); 211 rt2x00_set_field32(&reg, HOST_CMD_CSR_HOST_COMMAND, command);
195 rt2x00_set_field32(&reg, HOST_CMD_CSR_INTERRUPT_MCU, 1); 212 rt2x00_set_field32(&reg, HOST_CMD_CSR_INTERRUPT_MCU, 1);
196 rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, reg); 213 rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, reg);
214
215 mutex_unlock(&rt2x00dev->csr_mutex);
216
217 return;
218
219exit_fail:
220 mutex_unlock(&rt2x00dev->csr_mutex);
221
222 ERROR(rt2x00dev,
223 "mcu request error. Request 0x%02x failed for token 0x%02x.\n",
224 command, token);
197} 225}
198#endif /* CONFIG_RT2X00_LIB_LEDS */ 226#endif /* CONFIG_RT2X00_LIB_LEDS */
199 227