diff options
-rw-r--r-- | drivers/net/wireless/p54/p54pci.c | 242 | ||||
-rw-r--r-- | drivers/net/wireless/p54/p54pci.h | 10 |
2 files changed, 168 insertions, 84 deletions
diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index ea2dc3d93c4..e9db4495c62 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c | |||
@@ -3,6 +3,7 @@ | |||
3 | * Linux device driver for PCI based Prism54 | 3 | * Linux device driver for PCI based Prism54 |
4 | * | 4 | * |
5 | * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net> | 5 | * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net> |
6 | * Copyright (c) 2008, Christian Lamparter <chunkeey@web.de> | ||
6 | * | 7 | * |
7 | * Based on the islsm (softmac prism54) driver, which is: | 8 | * Based on the islsm (softmac prism54) driver, which is: |
8 | * Copyright 2004-2006 Jean-Baptiste Note <jean-baptiste.note@m4x.org>, et al. | 9 | * Copyright 2004-2006 Jean-Baptiste Note <jean-baptiste.note@m4x.org>, et al. |
@@ -237,20 +238,22 @@ static int p54p_read_eeprom(struct ieee80211_hw *dev) | |||
237 | return err; | 238 | return err; |
238 | } | 239 | } |
239 | 240 | ||
240 | static void p54p_refill_rx_ring(struct ieee80211_hw *dev) | 241 | static void p54p_refill_rx_ring(struct ieee80211_hw *dev, |
242 | int ring_index, struct p54p_desc *ring, u32 ring_limit, | ||
243 | struct sk_buff **rx_buf) | ||
241 | { | 244 | { |
242 | struct p54p_priv *priv = dev->priv; | 245 | struct p54p_priv *priv = dev->priv; |
243 | struct p54p_ring_control *ring_control = priv->ring_control; | 246 | struct p54p_ring_control *ring_control = priv->ring_control; |
244 | u32 limit, host_idx, idx; | 247 | u32 limit, idx, i; |
245 | 248 | ||
246 | host_idx = le32_to_cpu(ring_control->host_idx[0]); | 249 | idx = le32_to_cpu(ring_control->host_idx[ring_index]); |
247 | limit = host_idx; | 250 | limit = idx; |
248 | limit -= le32_to_cpu(ring_control->device_idx[0]); | 251 | limit -= le32_to_cpu(ring_control->device_idx[ring_index]); |
249 | limit = ARRAY_SIZE(ring_control->rx_data) - limit; | 252 | limit = ring_limit - limit; |
250 | 253 | ||
251 | idx = host_idx % ARRAY_SIZE(ring_control->rx_data); | 254 | i = idx % ring_limit; |
252 | while (limit-- > 1) { | 255 | while (limit-- > 1) { |
253 | struct p54p_desc *desc = &ring_control->rx_data[idx]; | 256 | struct p54p_desc *desc = &ring[i]; |
254 | 257 | ||
255 | if (!desc->host_addr) { | 258 | if (!desc->host_addr) { |
256 | struct sk_buff *skb; | 259 | struct sk_buff *skb; |
@@ -267,16 +270,106 @@ static void p54p_refill_rx_ring(struct ieee80211_hw *dev) | |||
267 | desc->device_addr = 0; // FIXME: necessary? | 270 | desc->device_addr = 0; // FIXME: necessary? |
268 | desc->len = cpu_to_le16(MAX_RX_SIZE); | 271 | desc->len = cpu_to_le16(MAX_RX_SIZE); |
269 | desc->flags = 0; | 272 | desc->flags = 0; |
270 | priv->rx_buf[idx] = skb; | 273 | rx_buf[i] = skb; |
271 | } | 274 | } |
272 | 275 | ||
276 | i++; | ||
273 | idx++; | 277 | idx++; |
274 | host_idx++; | 278 | i %= ring_limit; |
275 | idx %= ARRAY_SIZE(ring_control->rx_data); | ||
276 | } | 279 | } |
277 | 280 | ||
278 | wmb(); | 281 | wmb(); |
279 | ring_control->host_idx[0] = cpu_to_le32(host_idx); | 282 | ring_control->host_idx[ring_index] = cpu_to_le32(idx); |
283 | } | ||
284 | |||
285 | static void p54p_check_rx_ring(struct ieee80211_hw *dev, u32 *index, | ||
286 | int ring_index, struct p54p_desc *ring, u32 ring_limit, | ||
287 | struct sk_buff **rx_buf) | ||
288 | { | ||
289 | struct p54p_priv *priv = dev->priv; | ||
290 | struct p54p_ring_control *ring_control = priv->ring_control; | ||
291 | struct p54p_desc *desc; | ||
292 | u32 idx, i; | ||
293 | |||
294 | i = (*index) % ring_limit; | ||
295 | (*index) = idx = le32_to_cpu(ring_control->device_idx[ring_index]); | ||
296 | idx %= ring_limit; | ||
297 | while (i != idx) { | ||
298 | u16 len; | ||
299 | struct sk_buff *skb; | ||
300 | desc = &ring[i]; | ||
301 | len = le16_to_cpu(desc->len); | ||
302 | skb = rx_buf[i]; | ||
303 | |||
304 | if (!skb) | ||
305 | continue; | ||
306 | |||
307 | skb_put(skb, len); | ||
308 | |||
309 | if (p54_rx(dev, skb)) { | ||
310 | pci_unmap_single(priv->pdev, | ||
311 | le32_to_cpu(desc->host_addr), | ||
312 | MAX_RX_SIZE, PCI_DMA_FROMDEVICE); | ||
313 | rx_buf[i] = NULL; | ||
314 | desc->host_addr = 0; | ||
315 | } else { | ||
316 | skb_trim(skb, 0); | ||
317 | desc->len = cpu_to_le16(MAX_RX_SIZE); | ||
318 | } | ||
319 | |||
320 | i++; | ||
321 | i %= ring_limit; | ||
322 | } | ||
323 | |||
324 | p54p_refill_rx_ring(dev, ring_index, ring, ring_limit, rx_buf); | ||
325 | } | ||
326 | |||
327 | /* caller must hold priv->lock */ | ||
328 | static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index, | ||
329 | int ring_index, struct p54p_desc *ring, u32 ring_limit, | ||
330 | void **tx_buf) | ||
331 | { | ||
332 | struct p54p_priv *priv = dev->priv; | ||
333 | struct p54p_ring_control *ring_control = priv->ring_control; | ||
334 | struct p54p_desc *desc; | ||
335 | u32 idx, i; | ||
336 | |||
337 | i = (*index) % ring_limit; | ||
338 | (*index) = idx = le32_to_cpu(ring_control->device_idx[1]); | ||
339 | idx %= ring_limit; | ||
340 | |||
341 | while (i != idx) { | ||
342 | desc = &ring[i]; | ||
343 | kfree(tx_buf[i]); | ||
344 | tx_buf[i] = NULL; | ||
345 | |||
346 | pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), | ||
347 | le16_to_cpu(desc->len), PCI_DMA_TODEVICE); | ||
348 | |||
349 | desc->host_addr = 0; | ||
350 | desc->device_addr = 0; | ||
351 | desc->len = 0; | ||
352 | desc->flags = 0; | ||
353 | |||
354 | i++; | ||
355 | i %= ring_limit; | ||
356 | } | ||
357 | } | ||
358 | |||
359 | static void p54p_rx_tasklet(unsigned long dev_id) | ||
360 | { | ||
361 | struct ieee80211_hw *dev = (struct ieee80211_hw *)dev_id; | ||
362 | struct p54p_priv *priv = dev->priv; | ||
363 | struct p54p_ring_control *ring_control = priv->ring_control; | ||
364 | |||
365 | p54p_check_rx_ring(dev, &priv->rx_idx_mgmt, 2, ring_control->rx_mgmt, | ||
366 | ARRAY_SIZE(ring_control->rx_mgmt), priv->rx_buf_mgmt); | ||
367 | |||
368 | p54p_check_rx_ring(dev, &priv->rx_idx_data, 0, ring_control->rx_data, | ||
369 | ARRAY_SIZE(ring_control->rx_data), priv->rx_buf_data); | ||
370 | |||
371 | wmb(); | ||
372 | P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE)); | ||
280 | } | 373 | } |
281 | 374 | ||
282 | static irqreturn_t p54p_interrupt(int irq, void *dev_id) | 375 | static irqreturn_t p54p_interrupt(int irq, void *dev_id) |
@@ -298,65 +391,18 @@ static irqreturn_t p54p_interrupt(int irq, void *dev_id) | |||
298 | reg &= P54P_READ(int_enable); | 391 | reg &= P54P_READ(int_enable); |
299 | 392 | ||
300 | if (reg & cpu_to_le32(ISL38XX_INT_IDENT_UPDATE)) { | 393 | if (reg & cpu_to_le32(ISL38XX_INT_IDENT_UPDATE)) { |
301 | struct p54p_desc *desc; | 394 | p54p_check_tx_ring(dev, &priv->tx_idx_mgmt, |
302 | u32 idx, i; | 395 | 3, ring_control->tx_mgmt, |
303 | i = priv->tx_idx; | 396 | ARRAY_SIZE(ring_control->tx_mgmt), |
304 | i %= ARRAY_SIZE(ring_control->tx_data); | 397 | priv->tx_buf_mgmt); |
305 | priv->tx_idx = idx = le32_to_cpu(ring_control->device_idx[1]); | ||
306 | idx %= ARRAY_SIZE(ring_control->tx_data); | ||
307 | |||
308 | while (i != idx) { | ||
309 | desc = &ring_control->tx_data[i]; | ||
310 | if (priv->tx_buf[i]) { | ||
311 | kfree(priv->tx_buf[i]); | ||
312 | priv->tx_buf[i] = NULL; | ||
313 | } | ||
314 | |||
315 | pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), | ||
316 | le16_to_cpu(desc->len), PCI_DMA_TODEVICE); | ||
317 | 398 | ||
318 | desc->host_addr = 0; | 399 | p54p_check_tx_ring(dev, &priv->tx_idx_data, |
319 | desc->device_addr = 0; | 400 | 1, ring_control->tx_data, |
320 | desc->len = 0; | 401 | ARRAY_SIZE(ring_control->tx_data), |
321 | desc->flags = 0; | 402 | priv->tx_buf_data); |
322 | 403 | ||
323 | i++; | 404 | tasklet_schedule(&priv->rx_tasklet); |
324 | i %= ARRAY_SIZE(ring_control->tx_data); | ||
325 | } | ||
326 | |||
327 | i = priv->rx_idx; | ||
328 | i %= ARRAY_SIZE(ring_control->rx_data); | ||
329 | priv->rx_idx = idx = le32_to_cpu(ring_control->device_idx[0]); | ||
330 | idx %= ARRAY_SIZE(ring_control->rx_data); | ||
331 | while (i != idx) { | ||
332 | u16 len; | ||
333 | struct sk_buff *skb; | ||
334 | desc = &ring_control->rx_data[i]; | ||
335 | len = le16_to_cpu(desc->len); | ||
336 | skb = priv->rx_buf[i]; | ||
337 | |||
338 | skb_put(skb, len); | ||
339 | |||
340 | if (p54_rx(dev, skb)) { | ||
341 | pci_unmap_single(priv->pdev, | ||
342 | le32_to_cpu(desc->host_addr), | ||
343 | MAX_RX_SIZE, PCI_DMA_FROMDEVICE); | ||
344 | |||
345 | priv->rx_buf[i] = NULL; | ||
346 | desc->host_addr = 0; | ||
347 | } else { | ||
348 | skb_trim(skb, 0); | ||
349 | desc->len = cpu_to_le16(MAX_RX_SIZE); | ||
350 | } | ||
351 | |||
352 | i++; | ||
353 | i %= ARRAY_SIZE(ring_control->rx_data); | ||
354 | } | ||
355 | 405 | ||
356 | p54p_refill_rx_ring(dev); | ||
357 | |||
358 | wmb(); | ||
359 | P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE)); | ||
360 | } else if (reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)) | 406 | } else if (reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)) |
361 | complete(&priv->boot_comp); | 407 | complete(&priv->boot_comp); |
362 | 408 | ||
@@ -392,7 +438,7 @@ static void p54p_tx(struct ieee80211_hw *dev, struct p54_control_hdr *data, | |||
392 | ring_control->host_idx[1] = cpu_to_le32(idx + 1); | 438 | ring_control->host_idx[1] = cpu_to_le32(idx + 1); |
393 | 439 | ||
394 | if (free_on_tx) | 440 | if (free_on_tx) |
395 | priv->tx_buf[i] = data; | 441 | priv->tx_buf_data[i] = data; |
396 | 442 | ||
397 | spin_unlock_irqrestore(&priv->lock, flags); | 443 | spin_unlock_irqrestore(&priv->lock, flags); |
398 | 444 | ||
@@ -420,8 +466,14 @@ static int p54p_open(struct ieee80211_hw *dev) | |||
420 | } | 466 | } |
421 | 467 | ||
422 | memset(priv->ring_control, 0, sizeof(*priv->ring_control)); | 468 | memset(priv->ring_control, 0, sizeof(*priv->ring_control)); |
423 | priv->rx_idx = priv->tx_idx = 0; | 469 | priv->rx_idx_data = priv->tx_idx_data = 0; |
424 | p54p_refill_rx_ring(dev); | 470 | priv->rx_idx_mgmt = priv->tx_idx_mgmt = 0; |
471 | |||
472 | p54p_refill_rx_ring(dev, 0, priv->ring_control->rx_data, | ||
473 | ARRAY_SIZE(priv->ring_control->rx_data), priv->rx_buf_data); | ||
474 | |||
475 | p54p_refill_rx_ring(dev, 2, priv->ring_control->rx_mgmt, | ||
476 | ARRAY_SIZE(priv->ring_control->rx_mgmt), priv->rx_buf_mgmt); | ||
425 | 477 | ||
426 | p54p_upload_firmware(dev); | 478 | p54p_upload_firmware(dev); |
427 | 479 | ||
@@ -465,6 +517,8 @@ static void p54p_stop(struct ieee80211_hw *dev) | |||
465 | unsigned int i; | 517 | unsigned int i; |
466 | struct p54p_desc *desc; | 518 | struct p54p_desc *desc; |
467 | 519 | ||
520 | tasklet_kill(&priv->rx_tasklet); | ||
521 | |||
468 | P54P_WRITE(int_enable, cpu_to_le32(0)); | 522 | P54P_WRITE(int_enable, cpu_to_le32(0)); |
469 | P54P_READ(int_enable); | 523 | P54P_READ(int_enable); |
470 | udelay(10); | 524 | udelay(10); |
@@ -473,26 +527,51 @@ static void p54p_stop(struct ieee80211_hw *dev) | |||
473 | 527 | ||
474 | P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET)); | 528 | P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET)); |
475 | 529 | ||
476 | for (i = 0; i < ARRAY_SIZE(priv->rx_buf); i++) { | 530 | for (i = 0; i < ARRAY_SIZE(priv->rx_buf_data); i++) { |
477 | desc = &ring_control->rx_data[i]; | 531 | desc = &ring_control->rx_data[i]; |
478 | if (desc->host_addr) | 532 | if (desc->host_addr) |
479 | pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), | 533 | pci_unmap_single(priv->pdev, |
534 | le32_to_cpu(desc->host_addr), | ||
480 | MAX_RX_SIZE, PCI_DMA_FROMDEVICE); | 535 | MAX_RX_SIZE, PCI_DMA_FROMDEVICE); |
481 | kfree_skb(priv->rx_buf[i]); | 536 | kfree_skb(priv->rx_buf_data[i]); |
482 | priv->rx_buf[i] = NULL; | 537 | priv->rx_buf_data[i] = NULL; |
483 | } | 538 | } |
484 | 539 | ||
485 | for (i = 0; i < ARRAY_SIZE(priv->tx_buf); i++) { | 540 | for (i = 0; i < ARRAY_SIZE(priv->rx_buf_mgmt); i++) { |
541 | desc = &ring_control->rx_mgmt[i]; | ||
542 | if (desc->host_addr) | ||
543 | pci_unmap_single(priv->pdev, | ||
544 | le32_to_cpu(desc->host_addr), | ||
545 | MAX_RX_SIZE, PCI_DMA_FROMDEVICE); | ||
546 | kfree_skb(priv->rx_buf_mgmt[i]); | ||
547 | priv->rx_buf_mgmt[i] = NULL; | ||
548 | } | ||
549 | |||
550 | for (i = 0; i < ARRAY_SIZE(priv->tx_buf_data); i++) { | ||
486 | desc = &ring_control->tx_data[i]; | 551 | desc = &ring_control->tx_data[i]; |
487 | if (desc->host_addr) | 552 | if (desc->host_addr) |
488 | pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), | 553 | pci_unmap_single(priv->pdev, |
489 | le16_to_cpu(desc->len), PCI_DMA_TODEVICE); | 554 | le32_to_cpu(desc->host_addr), |
555 | le16_to_cpu(desc->len), | ||
556 | PCI_DMA_TODEVICE); | ||
557 | |||
558 | kfree(priv->tx_buf_data[i]); | ||
559 | priv->tx_buf_data[i] = NULL; | ||
560 | } | ||
561 | |||
562 | for (i = 0; i < ARRAY_SIZE(priv->tx_buf_mgmt); i++) { | ||
563 | desc = &ring_control->tx_mgmt[i]; | ||
564 | if (desc->host_addr) | ||
565 | pci_unmap_single(priv->pdev, | ||
566 | le32_to_cpu(desc->host_addr), | ||
567 | le16_to_cpu(desc->len), | ||
568 | PCI_DMA_TODEVICE); | ||
490 | 569 | ||
491 | kfree(priv->tx_buf[i]); | 570 | kfree(priv->tx_buf_mgmt[i]); |
492 | priv->tx_buf[i] = NULL; | 571 | priv->tx_buf_mgmt[i] = NULL; |
493 | } | 572 | } |
494 | 573 | ||
495 | memset(ring_control, 0, sizeof(ring_control)); | 574 | memset(ring_control, 0, sizeof(*ring_control)); |
496 | } | 575 | } |
497 | 576 | ||
498 | static int __devinit p54p_probe(struct pci_dev *pdev, | 577 | static int __devinit p54p_probe(struct pci_dev *pdev, |
@@ -585,6 +664,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev, | |||
585 | priv->common.tx = p54p_tx; | 664 | priv->common.tx = p54p_tx; |
586 | 665 | ||
587 | spin_lock_init(&priv->lock); | 666 | spin_lock_init(&priv->lock); |
667 | tasklet_init(&priv->rx_tasklet, p54p_rx_tasklet, (unsigned long)dev); | ||
588 | 668 | ||
589 | err = ieee80211_register_hw(dev); | 669 | err = ieee80211_register_hw(dev); |
590 | if (err) { | 670 | if (err) { |
diff --git a/drivers/net/wireless/p54/p54pci.h b/drivers/net/wireless/p54/p54pci.h index 07678ef5ddc..4a6778070af 100644 --- a/drivers/net/wireless/p54/p54pci.h +++ b/drivers/net/wireless/p54/p54pci.h | |||
@@ -92,13 +92,17 @@ struct p54p_priv { | |||
92 | struct p54_common common; | 92 | struct p54_common common; |
93 | struct pci_dev *pdev; | 93 | struct pci_dev *pdev; |
94 | struct p54p_csr __iomem *map; | 94 | struct p54p_csr __iomem *map; |
95 | struct tasklet_struct rx_tasklet; | ||
95 | 96 | ||
96 | spinlock_t lock; | 97 | spinlock_t lock; |
97 | struct p54p_ring_control *ring_control; | 98 | struct p54p_ring_control *ring_control; |
98 | dma_addr_t ring_control_dma; | 99 | dma_addr_t ring_control_dma; |
99 | u32 rx_idx, tx_idx; | 100 | u32 rx_idx_data, tx_idx_data; |
100 | struct sk_buff *rx_buf[8]; | 101 | u32 rx_idx_mgmt, tx_idx_mgmt; |
101 | void *tx_buf[32]; | 102 | struct sk_buff *rx_buf_data[8]; |
103 | struct sk_buff *rx_buf_mgmt[4]; | ||
104 | void *tx_buf_data[32]; | ||
105 | void *tx_buf_mgmt[4]; | ||
102 | struct completion boot_comp; | 106 | struct completion boot_comp; |
103 | }; | 107 | }; |
104 | 108 | ||