aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJanne Ylalehto <janne.ylalehto@nokia.com>2009-11-17 11:49:31 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-11-18 17:09:22 -0500
commitdcea4dbe54f5bbea2ef0bb265072754ccd934a1e (patch)
treef0e9a50fe025ac0f57d85e90c4c50582241a7aca /drivers
parent33d51facad8360cb9c55fd696431e2a477f16cc1 (diff)
wl1251: Add IRQ looping support
Add support for IRQ looping. Helps in the case that we have e.g. multiple packets coming from the network when we wake up from the ELP. Signed-off-by: Janne Ylalehto <janne.ylalehto@nokia.com> Reviewed-by: Juuso Oikarinen <juuso.oikarinen@nokia.com> Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com> Signed-off-by: Kalle Valo <kalle.valo@nokia.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_main.c127
1 files changed, 67 insertions, 60 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c
index cc32ba67909..dad010d114f 100644
--- a/drivers/net/wireless/wl12xx/wl1251_main.c
+++ b/drivers/net/wireless/wl12xx/wl1251_main.c
@@ -212,9 +212,10 @@ out:
212 return ret; 212 return ret;
213} 213}
214 214
215#define WL1251_IRQ_LOOP_COUNT 10
215static void wl1251_irq_work(struct work_struct *work) 216static void wl1251_irq_work(struct work_struct *work)
216{ 217{
217 u32 intr; 218 u32 intr, ctr = WL1251_IRQ_LOOP_COUNT;
218 struct wl1251 *wl = 219 struct wl1251 *wl =
219 container_of(work, struct wl1251, irq_work); 220 container_of(work, struct wl1251, irq_work);
220 int ret; 221 int ret;
@@ -235,78 +236,84 @@ static void wl1251_irq_work(struct work_struct *work)
235 intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); 236 intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR);
236 wl1251_debug(DEBUG_IRQ, "intr: 0x%x", intr); 237 wl1251_debug(DEBUG_IRQ, "intr: 0x%x", intr);
237 238
238 if (wl->data_path) { 239 do {
239 wl->rx_counter = 240 if (wl->data_path) {
240 wl1251_mem_read32(wl, wl->data_path->rx_control_addr); 241 wl->rx_counter = wl1251_mem_read32(
241 242 wl, wl->data_path->rx_control_addr);
242 /* We handle a frmware bug here */ 243
243 switch ((wl->rx_counter - wl->rx_handled) & 0xf) { 244 /* We handle a frmware bug here */
244 case 0: 245 switch ((wl->rx_counter - wl->rx_handled) & 0xf) {
245 wl1251_debug(DEBUG_IRQ, "RX: FW and host in sync"); 246 case 0:
246 intr &= ~WL1251_ACX_INTR_RX0_DATA; 247 wl1251_debug(DEBUG_IRQ,
247 intr &= ~WL1251_ACX_INTR_RX1_DATA; 248 "RX: FW and host in sync");
248 break; 249 intr &= ~WL1251_ACX_INTR_RX0_DATA;
249 case 1: 250 intr &= ~WL1251_ACX_INTR_RX1_DATA;
250 wl1251_debug(DEBUG_IRQ, "RX: FW +1"); 251 break;
251 intr |= WL1251_ACX_INTR_RX0_DATA; 252 case 1:
252 intr &= ~WL1251_ACX_INTR_RX1_DATA; 253 wl1251_debug(DEBUG_IRQ, "RX: FW +1");
253 break; 254 intr |= WL1251_ACX_INTR_RX0_DATA;
254 case 2: 255 intr &= ~WL1251_ACX_INTR_RX1_DATA;
255 wl1251_debug(DEBUG_IRQ, "RX: FW +2"); 256 break;
256 intr |= WL1251_ACX_INTR_RX0_DATA; 257 case 2:
257 intr |= WL1251_ACX_INTR_RX1_DATA; 258 wl1251_debug(DEBUG_IRQ, "RX: FW +2");
258 break; 259 intr |= WL1251_ACX_INTR_RX0_DATA;
259 default: 260 intr |= WL1251_ACX_INTR_RX1_DATA;
260 wl1251_warning("RX: FW and host out of sync: %d", 261 break;
261 wl->rx_counter - wl->rx_handled); 262 default:
262 break; 263 wl1251_warning(
263 } 264 "RX: FW and host out of sync: %d",
264 265 wl->rx_counter - wl->rx_handled);
265 wl->rx_handled = wl->rx_counter; 266 break;
267 }
266 268
269 wl->rx_handled = wl->rx_counter;
267 270
268 wl1251_debug(DEBUG_IRQ, "RX counter: %d", wl->rx_counter); 271 wl1251_debug(DEBUG_IRQ, "RX counter: %d",
269 } 272 wl->rx_counter);
273 }
270 274
271 intr &= wl->intr_mask; 275 intr &= wl->intr_mask;
272 276
273 if (intr == 0) { 277 if (intr == 0) {
274 wl1251_debug(DEBUG_IRQ, "INTR is 0"); 278 wl1251_debug(DEBUG_IRQ, "INTR is 0");
275 wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, 279 goto out_sleep;
276 ~(wl->intr_mask)); 280 }
277 281
278 goto out_sleep; 282 if (intr & WL1251_ACX_INTR_RX0_DATA) {
279 } 283 wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA");
284 wl1251_rx(wl);
285 }
280 286
281 if (intr & WL1251_ACX_INTR_RX0_DATA) { 287 if (intr & WL1251_ACX_INTR_RX1_DATA) {
282 wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA"); 288 wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA");
283 wl1251_rx(wl); 289 wl1251_rx(wl);
284 } 290 }
285 291
286 if (intr & WL1251_ACX_INTR_RX1_DATA) { 292 if (intr & WL1251_ACX_INTR_TX_RESULT) {
287 wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA"); 293 wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT");
288 wl1251_rx(wl); 294 wl1251_tx_complete(wl);
289 } 295 }
290 296
291 if (intr & WL1251_ACX_INTR_TX_RESULT) { 297 if (intr & (WL1251_ACX_INTR_EVENT_A |
292 wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT"); 298 WL1251_ACX_INTR_EVENT_B)) {
293 wl1251_tx_complete(wl); 299 wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)",
294 } 300 intr);
301 if (intr & WL1251_ACX_INTR_EVENT_A)
302 wl1251_event_handle(wl, 0);
303 else
304 wl1251_event_handle(wl, 1);
305 }
295 306
296 if (intr & (WL1251_ACX_INTR_EVENT_A | WL1251_ACX_INTR_EVENT_B)) { 307 if (intr & WL1251_ACX_INTR_INIT_COMPLETE)
297 wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)", intr); 308 wl1251_debug(DEBUG_IRQ,
298 if (intr & WL1251_ACX_INTR_EVENT_A) 309 "WL1251_ACX_INTR_INIT_COMPLETE");
299 wl1251_event_handle(wl, 0);
300 else
301 wl1251_event_handle(wl, 1);
302 }
303 310
304 if (intr & WL1251_ACX_INTR_INIT_COMPLETE) 311 intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR);
305 wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_INIT_COMPLETE");
306 312
307 wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); 313 } while (intr && --ctr);
308 314
309out_sleep: 315out_sleep:
316 wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask));
310 wl1251_ps_elp_sleep(wl); 317 wl1251_ps_elp_sleep(wl);
311 318
312out: 319out: