diff options
author | Ivo van Doorn <ivdoorn@gmail.com> | 2008-11-09 17:40:46 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-11-21 11:08:16 -0500 |
commit | 8ff48a8bbe4a1ba29dea2836dfce74660f97c1be (patch) | |
tree | 611c0e996813c59c229694b52d329c24829b80e8 /drivers/net/wireless/rt2x00/rt61pci.c | |
parent | bad13639a30e1557fbe9d440adc1906673c9de4e (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.c | 66 |
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(®, PHY_CSR3_READ_CONTROL, 0); | 94 | rt2x00_set_field32(®, 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 | |||
101 | exit_fail: | ||
102 | mutex_unlock(&rt2x00dev->csr_mutex); | ||
103 | |||
104 | ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n"); | ||
97 | } | 105 | } |
98 | 106 | ||
99 | static void rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev, | 107 | static 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 | |||
143 | exit_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 | ||
136 | static void rt61pci_rf_write(struct rt2x00_dev *rt2x00dev, | 150 | static 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, ®); | 162 | rt2x00pci_register_read(rt2x00dev, PHY_CSR4, ®); |
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, ®); | 199 | rt2x00pci_register_read(rt2x00dev, H2M_MAILBOX_CSR, ®); |
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(®, H2M_MAILBOX_CSR_OWNER, 1); | 204 | rt2x00_set_field32(®, H2M_MAILBOX_CSR_OWNER, 1); |
188 | rt2x00_set_field32(®, H2M_MAILBOX_CSR_CMD_TOKEN, token); | 205 | rt2x00_set_field32(®, H2M_MAILBOX_CSR_CMD_TOKEN, token); |
@@ -194,6 +211,17 @@ static void rt61pci_mcu_request(struct rt2x00_dev *rt2x00dev, | |||
194 | rt2x00_set_field32(®, HOST_CMD_CSR_HOST_COMMAND, command); | 211 | rt2x00_set_field32(®, HOST_CMD_CSR_HOST_COMMAND, command); |
195 | rt2x00_set_field32(®, HOST_CMD_CSR_INTERRUPT_MCU, 1); | 212 | rt2x00_set_field32(®, 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 | |||
219 | exit_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 | ||