diff options
Diffstat (limited to 'drivers/net/wireless/b43/main.c')
-rw-r--r-- | drivers/net/wireless/b43/main.c | 460 |
1 files changed, 229 insertions, 231 deletions
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index ae05f6671149..7a9a3fa55425 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c | |||
@@ -291,7 +291,7 @@ static struct ieee80211_supported_band b43_band_2GHz = { | |||
291 | 291 | ||
292 | static void b43_wireless_core_exit(struct b43_wldev *dev); | 292 | static void b43_wireless_core_exit(struct b43_wldev *dev); |
293 | static int b43_wireless_core_init(struct b43_wldev *dev); | 293 | static int b43_wireless_core_init(struct b43_wldev *dev); |
294 | static void b43_wireless_core_stop(struct b43_wldev *dev); | 294 | static struct b43_wldev * b43_wireless_core_stop(struct b43_wldev *dev); |
295 | static int b43_wireless_core_start(struct b43_wldev *dev); | 295 | static int b43_wireless_core_start(struct b43_wldev *dev); |
296 | 296 | ||
297 | static int b43_ratelimit(struct b43_wl *wl) | 297 | static int b43_ratelimit(struct b43_wl *wl) |
@@ -390,7 +390,7 @@ static inline void b43_shm_control_word(struct b43_wldev *dev, | |||
390 | b43_write32(dev, B43_MMIO_SHM_CONTROL, control); | 390 | b43_write32(dev, B43_MMIO_SHM_CONTROL, control); |
391 | } | 391 | } |
392 | 392 | ||
393 | u32 __b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset) | 393 | u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset) |
394 | { | 394 | { |
395 | u32 ret; | 395 | u32 ret; |
396 | 396 | ||
@@ -413,20 +413,7 @@ out: | |||
413 | return ret; | 413 | return ret; |
414 | } | 414 | } |
415 | 415 | ||
416 | u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset) | 416 | u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset) |
417 | { | ||
418 | struct b43_wl *wl = dev->wl; | ||
419 | unsigned long flags; | ||
420 | u32 ret; | ||
421 | |||
422 | spin_lock_irqsave(&wl->shm_lock, flags); | ||
423 | ret = __b43_shm_read32(dev, routing, offset); | ||
424 | spin_unlock_irqrestore(&wl->shm_lock, flags); | ||
425 | |||
426 | return ret; | ||
427 | } | ||
428 | |||
429 | u16 __b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset) | ||
430 | { | 417 | { |
431 | u16 ret; | 418 | u16 ret; |
432 | 419 | ||
@@ -447,20 +434,7 @@ out: | |||
447 | return ret; | 434 | return ret; |
448 | } | 435 | } |
449 | 436 | ||
450 | u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset) | 437 | void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value) |
451 | { | ||
452 | struct b43_wl *wl = dev->wl; | ||
453 | unsigned long flags; | ||
454 | u16 ret; | ||
455 | |||
456 | spin_lock_irqsave(&wl->shm_lock, flags); | ||
457 | ret = __b43_shm_read16(dev, routing, offset); | ||
458 | spin_unlock_irqrestore(&wl->shm_lock, flags); | ||
459 | |||
460 | return ret; | ||
461 | } | ||
462 | |||
463 | void __b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value) | ||
464 | { | 438 | { |
465 | if (routing == B43_SHM_SHARED) { | 439 | if (routing == B43_SHM_SHARED) { |
466 | B43_WARN_ON(offset & 0x0001); | 440 | B43_WARN_ON(offset & 0x0001); |
@@ -480,17 +454,7 @@ void __b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value | |||
480 | b43_write32(dev, B43_MMIO_SHM_DATA, value); | 454 | b43_write32(dev, B43_MMIO_SHM_DATA, value); |
481 | } | 455 | } |
482 | 456 | ||
483 | void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value) | 457 | void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value) |
484 | { | ||
485 | struct b43_wl *wl = dev->wl; | ||
486 | unsigned long flags; | ||
487 | |||
488 | spin_lock_irqsave(&wl->shm_lock, flags); | ||
489 | __b43_shm_write32(dev, routing, offset, value); | ||
490 | spin_unlock_irqrestore(&wl->shm_lock, flags); | ||
491 | } | ||
492 | |||
493 | void __b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value) | ||
494 | { | 458 | { |
495 | if (routing == B43_SHM_SHARED) { | 459 | if (routing == B43_SHM_SHARED) { |
496 | B43_WARN_ON(offset & 0x0001); | 460 | B43_WARN_ON(offset & 0x0001); |
@@ -506,16 +470,6 @@ void __b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value | |||
506 | b43_write16(dev, B43_MMIO_SHM_DATA, value); | 470 | b43_write16(dev, B43_MMIO_SHM_DATA, value); |
507 | } | 471 | } |
508 | 472 | ||
509 | void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value) | ||
510 | { | ||
511 | struct b43_wl *wl = dev->wl; | ||
512 | unsigned long flags; | ||
513 | |||
514 | spin_lock_irqsave(&wl->shm_lock, flags); | ||
515 | __b43_shm_write16(dev, routing, offset, value); | ||
516 | spin_unlock_irqrestore(&wl->shm_lock, flags); | ||
517 | } | ||
518 | |||
519 | /* Read HostFlags */ | 473 | /* Read HostFlags */ |
520 | u64 b43_hf_read(struct b43_wldev *dev) | 474 | u64 b43_hf_read(struct b43_wldev *dev) |
521 | { | 475 | { |
@@ -685,22 +639,11 @@ static void b43_short_slot_timing_disable(struct b43_wldev *dev) | |||
685 | b43_set_slot_time(dev, 20); | 639 | b43_set_slot_time(dev, 20); |
686 | } | 640 | } |
687 | 641 | ||
688 | /* Synchronize IRQ top- and bottom-half. | ||
689 | * IRQs must be masked before calling this. | ||
690 | * This must not be called with the irq_lock held. | ||
691 | */ | ||
692 | static void b43_synchronize_irq(struct b43_wldev *dev) | ||
693 | { | ||
694 | synchronize_irq(dev->dev->irq); | ||
695 | tasklet_kill(&dev->isr_tasklet); | ||
696 | } | ||
697 | |||
698 | /* DummyTransmission function, as documented on | 642 | /* DummyTransmission function, as documented on |
699 | * http://bcm-v4.sipsolutions.net/802.11/DummyTransmission | 643 | * http://bcm-v4.sipsolutions.net/802.11/DummyTransmission |
700 | */ | 644 | */ |
701 | void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on) | 645 | void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on) |
702 | { | 646 | { |
703 | struct b43_wl *wl = dev->wl; | ||
704 | struct b43_phy *phy = &dev->phy; | 647 | struct b43_phy *phy = &dev->phy; |
705 | unsigned int i, max_loop; | 648 | unsigned int i, max_loop; |
706 | u16 value; | 649 | u16 value; |
@@ -720,9 +663,6 @@ void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on) | |||
720 | buffer[0] = 0x000B846E; | 663 | buffer[0] = 0x000B846E; |
721 | } | 664 | } |
722 | 665 | ||
723 | spin_lock_irq(&wl->irq_lock); | ||
724 | write_lock(&wl->tx_lock); | ||
725 | |||
726 | for (i = 0; i < 5; i++) | 666 | for (i = 0; i < 5; i++) |
727 | b43_ram_write(dev, i * 4, buffer[i]); | 667 | b43_ram_write(dev, i * 4, buffer[i]); |
728 | 668 | ||
@@ -778,9 +718,6 @@ void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on) | |||
778 | } | 718 | } |
779 | if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5) | 719 | if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5) |
780 | b43_radio_write16(dev, 0x0051, 0x0037); | 720 | b43_radio_write16(dev, 0x0051, 0x0037); |
781 | |||
782 | write_unlock(&wl->tx_lock); | ||
783 | spin_unlock_irq(&wl->irq_lock); | ||
784 | } | 721 | } |
785 | 722 | ||
786 | static void key_write(struct b43_wldev *dev, | 723 | static void key_write(struct b43_wldev *dev, |
@@ -1620,6 +1557,27 @@ static void handle_irq_beacon(struct b43_wldev *dev) | |||
1620 | } | 1557 | } |
1621 | } | 1558 | } |
1622 | 1559 | ||
1560 | static void b43_do_beacon_update_trigger_work(struct b43_wldev *dev) | ||
1561 | { | ||
1562 | u32 old_irq_mask = dev->irq_mask; | ||
1563 | |||
1564 | /* update beacon right away or defer to irq */ | ||
1565 | handle_irq_beacon(dev); | ||
1566 | if (old_irq_mask != dev->irq_mask) { | ||
1567 | /* The handler updated the IRQ mask. */ | ||
1568 | B43_WARN_ON(!dev->irq_mask); | ||
1569 | if (b43_read32(dev, B43_MMIO_GEN_IRQ_MASK)) { | ||
1570 | b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask); | ||
1571 | } else { | ||
1572 | /* Device interrupts are currently disabled. That means | ||
1573 | * we just ran the hardirq handler and scheduled the | ||
1574 | * IRQ thread. The thread will write the IRQ mask when | ||
1575 | * it finished, so there's nothing to do here. Writing | ||
1576 | * the mask _here_ would incorrectly re-enable IRQs. */ | ||
1577 | } | ||
1578 | } | ||
1579 | } | ||
1580 | |||
1623 | static void b43_beacon_update_trigger_work(struct work_struct *work) | 1581 | static void b43_beacon_update_trigger_work(struct work_struct *work) |
1624 | { | 1582 | { |
1625 | struct b43_wl *wl = container_of(work, struct b43_wl, | 1583 | struct b43_wl *wl = container_of(work, struct b43_wl, |
@@ -1629,19 +1587,22 @@ static void b43_beacon_update_trigger_work(struct work_struct *work) | |||
1629 | mutex_lock(&wl->mutex); | 1587 | mutex_lock(&wl->mutex); |
1630 | dev = wl->current_dev; | 1588 | dev = wl->current_dev; |
1631 | if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED))) { | 1589 | if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED))) { |
1632 | spin_lock_irq(&wl->irq_lock); | 1590 | if (0 /*FIXME dev->dev->bus->bustype == SSB_BUSTYPE_SDIO*/) { |
1633 | /* update beacon right away or defer to irq */ | 1591 | /* wl->mutex is enough. */ |
1634 | handle_irq_beacon(dev); | 1592 | b43_do_beacon_update_trigger_work(dev); |
1635 | /* The handler might have updated the IRQ mask. */ | 1593 | mmiowb(); |
1636 | b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask); | 1594 | } else { |
1637 | mmiowb(); | 1595 | spin_lock_irq(&wl->hardirq_lock); |
1638 | spin_unlock_irq(&wl->irq_lock); | 1596 | b43_do_beacon_update_trigger_work(dev); |
1597 | mmiowb(); | ||
1598 | spin_unlock_irq(&wl->hardirq_lock); | ||
1599 | } | ||
1639 | } | 1600 | } |
1640 | mutex_unlock(&wl->mutex); | 1601 | mutex_unlock(&wl->mutex); |
1641 | } | 1602 | } |
1642 | 1603 | ||
1643 | /* Asynchronously update the packet templates in template RAM. | 1604 | /* Asynchronously update the packet templates in template RAM. |
1644 | * Locking: Requires wl->irq_lock to be locked. */ | 1605 | * Locking: Requires wl->mutex to be locked. */ |
1645 | static void b43_update_templates(struct b43_wl *wl) | 1606 | static void b43_update_templates(struct b43_wl *wl) |
1646 | { | 1607 | { |
1647 | struct sk_buff *beacon; | 1608 | struct sk_buff *beacon; |
@@ -1778,18 +1739,15 @@ out: | |||
1778 | B43_DEBUGIRQ_REASON_REG, B43_DEBUGIRQ_ACK); | 1739 | B43_DEBUGIRQ_REASON_REG, B43_DEBUGIRQ_ACK); |
1779 | } | 1740 | } |
1780 | 1741 | ||
1781 | /* Interrupt handler bottom-half */ | 1742 | static void b43_do_interrupt_thread(struct b43_wldev *dev) |
1782 | static void b43_interrupt_tasklet(struct b43_wldev *dev) | ||
1783 | { | 1743 | { |
1784 | u32 reason; | 1744 | u32 reason; |
1785 | u32 dma_reason[ARRAY_SIZE(dev->dma_reason)]; | 1745 | u32 dma_reason[ARRAY_SIZE(dev->dma_reason)]; |
1786 | u32 merged_dma_reason = 0; | 1746 | u32 merged_dma_reason = 0; |
1787 | int i; | 1747 | int i; |
1788 | unsigned long flags; | ||
1789 | |||
1790 | spin_lock_irqsave(&dev->wl->irq_lock, flags); | ||
1791 | 1748 | ||
1792 | B43_WARN_ON(b43_status(dev) != B43_STAT_STARTED); | 1749 | if (unlikely(b43_status(dev) != B43_STAT_STARTED)) |
1750 | return; | ||
1793 | 1751 | ||
1794 | reason = dev->irq_reason; | 1752 | reason = dev->irq_reason; |
1795 | for (i = 0; i < ARRAY_SIZE(dma_reason); i++) { | 1753 | for (i = 0; i < ARRAY_SIZE(dma_reason); i++) { |
@@ -1822,8 +1780,6 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev) | |||
1822 | dma_reason[2], dma_reason[3], | 1780 | dma_reason[2], dma_reason[3], |
1823 | dma_reason[4], dma_reason[5]); | 1781 | dma_reason[4], dma_reason[5]); |
1824 | b43_controller_restart(dev, "DMA error"); | 1782 | b43_controller_restart(dev, "DMA error"); |
1825 | mmiowb(); | ||
1826 | spin_unlock_irqrestore(&dev->wl->irq_lock, flags); | ||
1827 | return; | 1783 | return; |
1828 | } | 1784 | } |
1829 | if (merged_dma_reason & B43_DMAIRQ_NONFATALMASK) { | 1785 | if (merged_dma_reason & B43_DMAIRQ_NONFATALMASK) { |
@@ -1867,47 +1823,36 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev) | |||
1867 | if (reason & B43_IRQ_TX_OK) | 1823 | if (reason & B43_IRQ_TX_OK) |
1868 | handle_irq_transmit_status(dev); | 1824 | handle_irq_transmit_status(dev); |
1869 | 1825 | ||
1826 | /* Re-enable interrupts on the device by restoring the current interrupt mask. */ | ||
1870 | b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask); | 1827 | b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask); |
1871 | mmiowb(); | ||
1872 | spin_unlock_irqrestore(&dev->wl->irq_lock, flags); | ||
1873 | } | 1828 | } |
1874 | 1829 | ||
1875 | static void b43_interrupt_ack(struct b43_wldev *dev, u32 reason) | 1830 | /* Interrupt thread handler. Handles device interrupts in thread context. */ |
1831 | static irqreturn_t b43_interrupt_thread_handler(int irq, void *dev_id) | ||
1876 | { | 1832 | { |
1877 | b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, reason); | 1833 | struct b43_wldev *dev = dev_id; |
1878 | 1834 | ||
1879 | b43_write32(dev, B43_MMIO_DMA0_REASON, dev->dma_reason[0]); | 1835 | mutex_lock(&dev->wl->mutex); |
1880 | b43_write32(dev, B43_MMIO_DMA1_REASON, dev->dma_reason[1]); | 1836 | b43_do_interrupt_thread(dev); |
1881 | b43_write32(dev, B43_MMIO_DMA2_REASON, dev->dma_reason[2]); | 1837 | mmiowb(); |
1882 | b43_write32(dev, B43_MMIO_DMA3_REASON, dev->dma_reason[3]); | 1838 | mutex_unlock(&dev->wl->mutex); |
1883 | b43_write32(dev, B43_MMIO_DMA4_REASON, dev->dma_reason[4]); | 1839 | |
1884 | /* Unused ring | 1840 | return IRQ_HANDLED; |
1885 | b43_write32(dev, B43_MMIO_DMA5_REASON, dev->dma_reason[5]); | ||
1886 | */ | ||
1887 | } | 1841 | } |
1888 | 1842 | ||
1889 | /* Interrupt handler top-half */ | 1843 | static irqreturn_t b43_do_interrupt(struct b43_wldev *dev) |
1890 | static irqreturn_t b43_interrupt_handler(int irq, void *dev_id) | ||
1891 | { | 1844 | { |
1892 | irqreturn_t ret = IRQ_NONE; | ||
1893 | struct b43_wldev *dev = dev_id; | ||
1894 | u32 reason; | 1845 | u32 reason; |
1895 | 1846 | ||
1896 | B43_WARN_ON(!dev); | 1847 | /* This code runs under wl->hardirq_lock, but _only_ on non-SDIO busses. |
1848 | * On SDIO, this runs under wl->mutex. */ | ||
1897 | 1849 | ||
1898 | spin_lock(&dev->wl->irq_lock); | ||
1899 | |||
1900 | if (unlikely(b43_status(dev) < B43_STAT_STARTED)) { | ||
1901 | /* This can only happen on shared IRQ lines. */ | ||
1902 | goto out; | ||
1903 | } | ||
1904 | reason = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); | 1850 | reason = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); |
1905 | if (reason == 0xffffffff) /* shared IRQ */ | 1851 | if (reason == 0xffffffff) /* shared IRQ */ |
1906 | goto out; | 1852 | return IRQ_NONE; |
1907 | ret = IRQ_HANDLED; | ||
1908 | reason &= dev->irq_mask; | 1853 | reason &= dev->irq_mask; |
1909 | if (!reason) | 1854 | if (!reason) |
1910 | goto out; | 1855 | return IRQ_HANDLED; |
1911 | 1856 | ||
1912 | dev->dma_reason[0] = b43_read32(dev, B43_MMIO_DMA0_REASON) | 1857 | dev->dma_reason[0] = b43_read32(dev, B43_MMIO_DMA0_REASON) |
1913 | & 0x0001DC00; | 1858 | & 0x0001DC00; |
@@ -1924,15 +1869,38 @@ static irqreturn_t b43_interrupt_handler(int irq, void *dev_id) | |||
1924 | & 0x0000DC00; | 1869 | & 0x0000DC00; |
1925 | */ | 1870 | */ |
1926 | 1871 | ||
1927 | b43_interrupt_ack(dev, reason); | 1872 | /* ACK the interrupt. */ |
1928 | /* disable all IRQs. They are enabled again in the bottom half. */ | 1873 | b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, reason); |
1874 | b43_write32(dev, B43_MMIO_DMA0_REASON, dev->dma_reason[0]); | ||
1875 | b43_write32(dev, B43_MMIO_DMA1_REASON, dev->dma_reason[1]); | ||
1876 | b43_write32(dev, B43_MMIO_DMA2_REASON, dev->dma_reason[2]); | ||
1877 | b43_write32(dev, B43_MMIO_DMA3_REASON, dev->dma_reason[3]); | ||
1878 | b43_write32(dev, B43_MMIO_DMA4_REASON, dev->dma_reason[4]); | ||
1879 | /* Unused ring | ||
1880 | b43_write32(dev, B43_MMIO_DMA5_REASON, dev->dma_reason[5]); | ||
1881 | */ | ||
1882 | |||
1883 | /* Disable IRQs on the device. The IRQ thread handler will re-enable them. */ | ||
1929 | b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0); | 1884 | b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0); |
1930 | /* save the reason code and call our bottom half. */ | 1885 | /* Save the reason bitmasks for the IRQ thread handler. */ |
1931 | dev->irq_reason = reason; | 1886 | dev->irq_reason = reason; |
1932 | tasklet_schedule(&dev->isr_tasklet); | 1887 | |
1933 | out: | 1888 | return IRQ_WAKE_THREAD; |
1889 | } | ||
1890 | |||
1891 | /* Interrupt handler top-half. This runs with interrupts disabled. */ | ||
1892 | static irqreturn_t b43_interrupt_handler(int irq, void *dev_id) | ||
1893 | { | ||
1894 | struct b43_wldev *dev = dev_id; | ||
1895 | irqreturn_t ret; | ||
1896 | |||
1897 | if (unlikely(b43_status(dev) < B43_STAT_STARTED)) | ||
1898 | return IRQ_NONE; | ||
1899 | |||
1900 | spin_lock(&dev->wl->hardirq_lock); | ||
1901 | ret = b43_do_interrupt(dev); | ||
1934 | mmiowb(); | 1902 | mmiowb(); |
1935 | spin_unlock(&dev->wl->irq_lock); | 1903 | spin_unlock(&dev->wl->hardirq_lock); |
1936 | 1904 | ||
1937 | return ret; | 1905 | return ret; |
1938 | } | 1906 | } |
@@ -3038,15 +3006,12 @@ static void b43_security_init(struct b43_wldev *dev) | |||
3038 | static int b43_rng_read(struct hwrng *rng, u32 *data) | 3006 | static int b43_rng_read(struct hwrng *rng, u32 *data) |
3039 | { | 3007 | { |
3040 | struct b43_wl *wl = (struct b43_wl *)rng->priv; | 3008 | struct b43_wl *wl = (struct b43_wl *)rng->priv; |
3041 | unsigned long flags; | ||
3042 | 3009 | ||
3043 | /* Don't take wl->mutex here, as it could deadlock with | 3010 | /* FIXME: We need to take wl->mutex here to make sure the device |
3044 | * hwrng internal locking. It's not needed to take | 3011 | * is not going away from under our ass. However it could deadlock |
3045 | * wl->mutex here, anyway. */ | 3012 | * with hwrng internal locking. */ |
3046 | 3013 | ||
3047 | spin_lock_irqsave(&wl->irq_lock, flags); | ||
3048 | *data = b43_read16(wl->current_dev, B43_MMIO_RNG); | 3014 | *data = b43_read16(wl->current_dev, B43_MMIO_RNG); |
3049 | spin_unlock_irqrestore(&wl->irq_lock, flags); | ||
3050 | 3015 | ||
3051 | return (sizeof(u16)); | 3016 | return (sizeof(u16)); |
3052 | } | 3017 | } |
@@ -3082,46 +3047,52 @@ static int b43_rng_init(struct b43_wl *wl) | |||
3082 | return err; | 3047 | return err; |
3083 | } | 3048 | } |
3084 | 3049 | ||
3085 | static int b43_op_tx(struct ieee80211_hw *hw, | 3050 | static void b43_tx_work(struct work_struct *work) |
3086 | struct sk_buff *skb) | ||
3087 | { | 3051 | { |
3088 | struct b43_wl *wl = hw_to_b43_wl(hw); | 3052 | struct b43_wl *wl = container_of(work, struct b43_wl, tx_work); |
3089 | struct b43_wldev *dev = wl->current_dev; | 3053 | struct b43_wldev *dev; |
3090 | unsigned long flags; | 3054 | struct sk_buff *skb; |
3091 | int err; | 3055 | int err = 0; |
3092 | 3056 | ||
3093 | if (unlikely(skb->len < 2 + 2 + 6)) { | 3057 | mutex_lock(&wl->mutex); |
3094 | /* Too short, this can't be a valid frame. */ | 3058 | dev = wl->current_dev; |
3095 | goto drop_packet; | 3059 | if (unlikely(!dev || b43_status(dev) < B43_STAT_STARTED)) { |
3060 | mutex_unlock(&wl->mutex); | ||
3061 | return; | ||
3096 | } | 3062 | } |
3097 | B43_WARN_ON(skb_shinfo(skb)->nr_frags); | ||
3098 | if (unlikely(!dev)) | ||
3099 | goto drop_packet; | ||
3100 | 3063 | ||
3101 | /* Transmissions on seperate queues can run concurrently. */ | 3064 | while (skb_queue_len(&wl->tx_queue)) { |
3102 | read_lock_irqsave(&wl->tx_lock, flags); | 3065 | skb = skb_dequeue(&wl->tx_queue); |
3103 | 3066 | ||
3104 | err = -ENODEV; | ||
3105 | if (likely(b43_status(dev) >= B43_STAT_STARTED)) { | ||
3106 | if (b43_using_pio_transfers(dev)) | 3067 | if (b43_using_pio_transfers(dev)) |
3107 | err = b43_pio_tx(dev, skb); | 3068 | err = b43_pio_tx(dev, skb); |
3108 | else | 3069 | else |
3109 | err = b43_dma_tx(dev, skb); | 3070 | err = b43_dma_tx(dev, skb); |
3071 | if (unlikely(err)) | ||
3072 | dev_kfree_skb(skb); /* Drop it */ | ||
3110 | } | 3073 | } |
3111 | 3074 | ||
3112 | read_unlock_irqrestore(&wl->tx_lock, flags); | 3075 | mutex_unlock(&wl->mutex); |
3076 | } | ||
3113 | 3077 | ||
3114 | if (unlikely(err)) | 3078 | static int b43_op_tx(struct ieee80211_hw *hw, |
3115 | goto drop_packet; | 3079 | struct sk_buff *skb) |
3116 | return NETDEV_TX_OK; | 3080 | { |
3081 | struct b43_wl *wl = hw_to_b43_wl(hw); | ||
3082 | |||
3083 | if (unlikely(skb->len < 2 + 2 + 6)) { | ||
3084 | /* Too short, this can't be a valid frame. */ | ||
3085 | dev_kfree_skb_any(skb); | ||
3086 | return NETDEV_TX_OK; | ||
3087 | } | ||
3088 | B43_WARN_ON(skb_shinfo(skb)->nr_frags); | ||
3089 | |||
3090 | skb_queue_tail(&wl->tx_queue, skb); | ||
3091 | ieee80211_queue_work(wl->hw, &wl->tx_work); | ||
3117 | 3092 | ||
3118 | drop_packet: | ||
3119 | /* We can not transmit this packet. Drop it. */ | ||
3120 | dev_kfree_skb_any(skb); | ||
3121 | return NETDEV_TX_OK; | 3093 | return NETDEV_TX_OK; |
3122 | } | 3094 | } |
3123 | 3095 | ||
3124 | /* Locking: wl->irq_lock */ | ||
3125 | static void b43_qos_params_upload(struct b43_wldev *dev, | 3096 | static void b43_qos_params_upload(struct b43_wldev *dev, |
3126 | const struct ieee80211_tx_queue_params *p, | 3097 | const struct ieee80211_tx_queue_params *p, |
3127 | u16 shm_offset) | 3098 | u16 shm_offset) |
@@ -3130,6 +3101,9 @@ static void b43_qos_params_upload(struct b43_wldev *dev, | |||
3130 | int bslots, tmp; | 3101 | int bslots, tmp; |
3131 | unsigned int i; | 3102 | unsigned int i; |
3132 | 3103 | ||
3104 | if (!dev->qos_enabled) | ||
3105 | return; | ||
3106 | |||
3133 | bslots = b43_read16(dev, B43_MMIO_RNG) & p->cw_min; | 3107 | bslots = b43_read16(dev, B43_MMIO_RNG) & p->cw_min; |
3134 | 3108 | ||
3135 | memset(¶ms, 0, sizeof(params)); | 3109 | memset(¶ms, 0, sizeof(params)); |
@@ -3175,6 +3149,9 @@ static void b43_qos_upload_all(struct b43_wldev *dev) | |||
3175 | struct b43_qos_params *params; | 3149 | struct b43_qos_params *params; |
3176 | unsigned int i; | 3150 | unsigned int i; |
3177 | 3151 | ||
3152 | if (!dev->qos_enabled) | ||
3153 | return; | ||
3154 | |||
3178 | BUILD_BUG_ON(ARRAY_SIZE(b43_qos_shm_offsets) != | 3155 | BUILD_BUG_ON(ARRAY_SIZE(b43_qos_shm_offsets) != |
3179 | ARRAY_SIZE(wl->qos_params)); | 3156 | ARRAY_SIZE(wl->qos_params)); |
3180 | 3157 | ||
@@ -3234,6 +3211,16 @@ static void b43_qos_clear(struct b43_wl *wl) | |||
3234 | /* Initialize the core's QOS capabilities */ | 3211 | /* Initialize the core's QOS capabilities */ |
3235 | static void b43_qos_init(struct b43_wldev *dev) | 3212 | static void b43_qos_init(struct b43_wldev *dev) |
3236 | { | 3213 | { |
3214 | if (!dev->qos_enabled) { | ||
3215 | /* Disable QOS support. */ | ||
3216 | b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_EDCF); | ||
3217 | b43_write16(dev, B43_MMIO_IFSCTL, | ||
3218 | b43_read16(dev, B43_MMIO_IFSCTL) | ||
3219 | & ~B43_MMIO_IFSCTL_USE_EDCF); | ||
3220 | b43dbg(dev->wl, "QoS disabled\n"); | ||
3221 | return; | ||
3222 | } | ||
3223 | |||
3237 | /* Upload the current QOS parameters. */ | 3224 | /* Upload the current QOS parameters. */ |
3238 | b43_qos_upload_all(dev); | 3225 | b43_qos_upload_all(dev); |
3239 | 3226 | ||
@@ -3242,6 +3229,7 @@ static void b43_qos_init(struct b43_wldev *dev) | |||
3242 | b43_write16(dev, B43_MMIO_IFSCTL, | 3229 | b43_write16(dev, B43_MMIO_IFSCTL, |
3243 | b43_read16(dev, B43_MMIO_IFSCTL) | 3230 | b43_read16(dev, B43_MMIO_IFSCTL) |
3244 | | B43_MMIO_IFSCTL_USE_EDCF); | 3231 | | B43_MMIO_IFSCTL_USE_EDCF); |
3232 | b43dbg(dev->wl, "QoS enabled\n"); | ||
3245 | } | 3233 | } |
3246 | 3234 | ||
3247 | static int b43_op_conf_tx(struct ieee80211_hw *hw, u16 _queue, | 3235 | static int b43_op_conf_tx(struct ieee80211_hw *hw, u16 _queue, |
@@ -3283,22 +3271,20 @@ static int b43_op_get_tx_stats(struct ieee80211_hw *hw, | |||
3283 | struct ieee80211_tx_queue_stats *stats) | 3271 | struct ieee80211_tx_queue_stats *stats) |
3284 | { | 3272 | { |
3285 | struct b43_wl *wl = hw_to_b43_wl(hw); | 3273 | struct b43_wl *wl = hw_to_b43_wl(hw); |
3286 | struct b43_wldev *dev = wl->current_dev; | 3274 | struct b43_wldev *dev; |
3287 | unsigned long flags; | ||
3288 | int err = -ENODEV; | 3275 | int err = -ENODEV; |
3289 | 3276 | ||
3290 | if (!dev) | 3277 | mutex_lock(&wl->mutex); |
3291 | goto out; | 3278 | dev = wl->current_dev; |
3292 | spin_lock_irqsave(&wl->irq_lock, flags); | 3279 | if (dev && b43_status(dev) >= B43_STAT_STARTED) { |
3293 | if (likely(b43_status(dev) >= B43_STAT_STARTED)) { | ||
3294 | if (b43_using_pio_transfers(dev)) | 3280 | if (b43_using_pio_transfers(dev)) |
3295 | b43_pio_get_tx_stats(dev, stats); | 3281 | b43_pio_get_tx_stats(dev, stats); |
3296 | else | 3282 | else |
3297 | b43_dma_get_tx_stats(dev, stats); | 3283 | b43_dma_get_tx_stats(dev, stats); |
3298 | err = 0; | 3284 | err = 0; |
3299 | } | 3285 | } |
3300 | spin_unlock_irqrestore(&wl->irq_lock, flags); | 3286 | mutex_unlock(&wl->mutex); |
3301 | out: | 3287 | |
3302 | return err; | 3288 | return err; |
3303 | } | 3289 | } |
3304 | 3290 | ||
@@ -3306,11 +3292,10 @@ static int b43_op_get_stats(struct ieee80211_hw *hw, | |||
3306 | struct ieee80211_low_level_stats *stats) | 3292 | struct ieee80211_low_level_stats *stats) |
3307 | { | 3293 | { |
3308 | struct b43_wl *wl = hw_to_b43_wl(hw); | 3294 | struct b43_wl *wl = hw_to_b43_wl(hw); |
3309 | unsigned long flags; | ||
3310 | 3295 | ||
3311 | spin_lock_irqsave(&wl->irq_lock, flags); | 3296 | mutex_lock(&wl->mutex); |
3312 | memcpy(stats, &wl->ieee_stats, sizeof(*stats)); | 3297 | memcpy(stats, &wl->ieee_stats, sizeof(*stats)); |
3313 | spin_unlock_irqrestore(&wl->irq_lock, flags); | 3298 | mutex_unlock(&wl->mutex); |
3314 | 3299 | ||
3315 | return 0; | 3300 | return 0; |
3316 | } | 3301 | } |
@@ -3322,7 +3307,6 @@ static u64 b43_op_get_tsf(struct ieee80211_hw *hw) | |||
3322 | u64 tsf; | 3307 | u64 tsf; |
3323 | 3308 | ||
3324 | mutex_lock(&wl->mutex); | 3309 | mutex_lock(&wl->mutex); |
3325 | spin_lock_irq(&wl->irq_lock); | ||
3326 | dev = wl->current_dev; | 3310 | dev = wl->current_dev; |
3327 | 3311 | ||
3328 | if (dev && (b43_status(dev) >= B43_STAT_INITIALIZED)) | 3312 | if (dev && (b43_status(dev) >= B43_STAT_INITIALIZED)) |
@@ -3330,7 +3314,6 @@ static u64 b43_op_get_tsf(struct ieee80211_hw *hw) | |||
3330 | else | 3314 | else |
3331 | tsf = 0; | 3315 | tsf = 0; |
3332 | 3316 | ||
3333 | spin_unlock_irq(&wl->irq_lock); | ||
3334 | mutex_unlock(&wl->mutex); | 3317 | mutex_unlock(&wl->mutex); |
3335 | 3318 | ||
3336 | return tsf; | 3319 | return tsf; |
@@ -3342,13 +3325,11 @@ static void b43_op_set_tsf(struct ieee80211_hw *hw, u64 tsf) | |||
3342 | struct b43_wldev *dev; | 3325 | struct b43_wldev *dev; |
3343 | 3326 | ||
3344 | mutex_lock(&wl->mutex); | 3327 | mutex_lock(&wl->mutex); |
3345 | spin_lock_irq(&wl->irq_lock); | ||
3346 | dev = wl->current_dev; | 3328 | dev = wl->current_dev; |
3347 | 3329 | ||
3348 | if (dev && (b43_status(dev) >= B43_STAT_INITIALIZED)) | 3330 | if (dev && (b43_status(dev) >= B43_STAT_INITIALIZED)) |
3349 | b43_tsf_write(dev, tsf); | 3331 | b43_tsf_write(dev, tsf); |
3350 | 3332 | ||
3351 | spin_unlock_irq(&wl->irq_lock); | ||
3352 | mutex_unlock(&wl->mutex); | 3333 | mutex_unlock(&wl->mutex); |
3353 | } | 3334 | } |
3354 | 3335 | ||
@@ -3434,7 +3415,7 @@ static int b43_switch_band(struct b43_wl *wl, struct ieee80211_channel *chan) | |||
3434 | prev_status = b43_status(down_dev); | 3415 | prev_status = b43_status(down_dev); |
3435 | /* Shutdown the currently running core. */ | 3416 | /* Shutdown the currently running core. */ |
3436 | if (prev_status >= B43_STAT_STARTED) | 3417 | if (prev_status >= B43_STAT_STARTED) |
3437 | b43_wireless_core_stop(down_dev); | 3418 | down_dev = b43_wireless_core_stop(down_dev); |
3438 | if (prev_status >= B43_STAT_INITIALIZED) | 3419 | if (prev_status >= B43_STAT_INITIALIZED) |
3439 | b43_wireless_core_exit(down_dev); | 3420 | b43_wireless_core_exit(down_dev); |
3440 | 3421 | ||
@@ -3498,7 +3479,6 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) | |||
3498 | struct b43_wldev *dev; | 3479 | struct b43_wldev *dev; |
3499 | struct b43_phy *phy; | 3480 | struct b43_phy *phy; |
3500 | struct ieee80211_conf *conf = &hw->conf; | 3481 | struct ieee80211_conf *conf = &hw->conf; |
3501 | unsigned long flags; | ||
3502 | int antenna; | 3482 | int antenna; |
3503 | int err = 0; | 3483 | int err = 0; |
3504 | 3484 | ||
@@ -3529,13 +3509,11 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) | |||
3529 | 3509 | ||
3530 | /* Adjust the desired TX power level. */ | 3510 | /* Adjust the desired TX power level. */ |
3531 | if (conf->power_level != 0) { | 3511 | if (conf->power_level != 0) { |
3532 | spin_lock_irqsave(&wl->irq_lock, flags); | ||
3533 | if (conf->power_level != phy->desired_txpower) { | 3512 | if (conf->power_level != phy->desired_txpower) { |
3534 | phy->desired_txpower = conf->power_level; | 3513 | phy->desired_txpower = conf->power_level; |
3535 | b43_phy_txpower_check(dev, B43_TXPWR_IGNORE_TIME | | 3514 | b43_phy_txpower_check(dev, B43_TXPWR_IGNORE_TIME | |
3536 | B43_TXPWR_IGNORE_TSSI); | 3515 | B43_TXPWR_IGNORE_TSSI); |
3537 | } | 3516 | } |
3538 | spin_unlock_irqrestore(&wl->irq_lock, flags); | ||
3539 | } | 3517 | } |
3540 | 3518 | ||
3541 | /* Antennas for RX and management frame TX. */ | 3519 | /* Antennas for RX and management frame TX. */ |
@@ -3620,7 +3598,6 @@ static void b43_op_bss_info_changed(struct ieee80211_hw *hw, | |||
3620 | { | 3598 | { |
3621 | struct b43_wl *wl = hw_to_b43_wl(hw); | 3599 | struct b43_wl *wl = hw_to_b43_wl(hw); |
3622 | struct b43_wldev *dev; | 3600 | struct b43_wldev *dev; |
3623 | unsigned long flags; | ||
3624 | 3601 | ||
3625 | mutex_lock(&wl->mutex); | 3602 | mutex_lock(&wl->mutex); |
3626 | 3603 | ||
@@ -3630,7 +3607,6 @@ static void b43_op_bss_info_changed(struct ieee80211_hw *hw, | |||
3630 | 3607 | ||
3631 | B43_WARN_ON(wl->vif != vif); | 3608 | B43_WARN_ON(wl->vif != vif); |
3632 | 3609 | ||
3633 | spin_lock_irqsave(&wl->irq_lock, flags); | ||
3634 | if (changed & BSS_CHANGED_BSSID) { | 3610 | if (changed & BSS_CHANGED_BSSID) { |
3635 | if (conf->bssid) | 3611 | if (conf->bssid) |
3636 | memcpy(wl->bssid, conf->bssid, ETH_ALEN); | 3612 | memcpy(wl->bssid, conf->bssid, ETH_ALEN); |
@@ -3648,7 +3624,6 @@ static void b43_op_bss_info_changed(struct ieee80211_hw *hw, | |||
3648 | if (changed & BSS_CHANGED_BSSID) | 3624 | if (changed & BSS_CHANGED_BSSID) |
3649 | b43_write_mac_bssid_templates(dev); | 3625 | b43_write_mac_bssid_templates(dev); |
3650 | } | 3626 | } |
3651 | spin_unlock_irqrestore(&wl->irq_lock, flags); | ||
3652 | 3627 | ||
3653 | b43_mac_suspend(dev); | 3628 | b43_mac_suspend(dev); |
3654 | 3629 | ||
@@ -3689,15 +3664,6 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
3689 | return -ENOSPC; /* User disabled HW-crypto */ | 3664 | return -ENOSPC; /* User disabled HW-crypto */ |
3690 | 3665 | ||
3691 | mutex_lock(&wl->mutex); | 3666 | mutex_lock(&wl->mutex); |
3692 | spin_lock_irq(&wl->irq_lock); | ||
3693 | write_lock(&wl->tx_lock); | ||
3694 | /* Why do we need all this locking here? | ||
3695 | * mutex -> Every config operation must take it. | ||
3696 | * irq_lock -> We modify the dev->key array, which is accessed | ||
3697 | * in the IRQ handlers. | ||
3698 | * tx_lock -> We modify the dev->key array, which is accessed | ||
3699 | * in the TX handler. | ||
3700 | */ | ||
3701 | 3667 | ||
3702 | dev = wl->current_dev; | 3668 | dev = wl->current_dev; |
3703 | err = -ENODEV; | 3669 | err = -ENODEV; |
@@ -3789,8 +3755,6 @@ out_unlock: | |||
3789 | sta ? sta->addr : bcast_addr); | 3755 | sta ? sta->addr : bcast_addr); |
3790 | b43_dump_keymemory(dev); | 3756 | b43_dump_keymemory(dev); |
3791 | } | 3757 | } |
3792 | write_unlock(&wl->tx_lock); | ||
3793 | spin_unlock_irq(&wl->irq_lock); | ||
3794 | mutex_unlock(&wl->mutex); | 3758 | mutex_unlock(&wl->mutex); |
3795 | 3759 | ||
3796 | return err; | 3760 | return err; |
@@ -3801,15 +3765,15 @@ static void b43_op_configure_filter(struct ieee80211_hw *hw, | |||
3801 | u64 multicast) | 3765 | u64 multicast) |
3802 | { | 3766 | { |
3803 | struct b43_wl *wl = hw_to_b43_wl(hw); | 3767 | struct b43_wl *wl = hw_to_b43_wl(hw); |
3804 | struct b43_wldev *dev = wl->current_dev; | 3768 | struct b43_wldev *dev; |
3805 | unsigned long flags; | ||
3806 | 3769 | ||
3770 | mutex_lock(&wl->mutex); | ||
3771 | dev = wl->current_dev; | ||
3807 | if (!dev) { | 3772 | if (!dev) { |
3808 | *fflags = 0; | 3773 | *fflags = 0; |
3809 | return; | 3774 | goto out_unlock; |
3810 | } | 3775 | } |
3811 | 3776 | ||
3812 | spin_lock_irqsave(&wl->irq_lock, flags); | ||
3813 | *fflags &= FIF_PROMISC_IN_BSS | | 3777 | *fflags &= FIF_PROMISC_IN_BSS | |
3814 | FIF_ALLMULTI | | 3778 | FIF_ALLMULTI | |
3815 | FIF_FCSFAIL | | 3779 | FIF_FCSFAIL | |
@@ -3830,41 +3794,70 @@ static void b43_op_configure_filter(struct ieee80211_hw *hw, | |||
3830 | 3794 | ||
3831 | if (changed && b43_status(dev) >= B43_STAT_INITIALIZED) | 3795 | if (changed && b43_status(dev) >= B43_STAT_INITIALIZED) |
3832 | b43_adjust_opmode(dev); | 3796 | b43_adjust_opmode(dev); |
3833 | spin_unlock_irqrestore(&wl->irq_lock, flags); | 3797 | |
3798 | out_unlock: | ||
3799 | mutex_unlock(&wl->mutex); | ||
3834 | } | 3800 | } |
3835 | 3801 | ||
3836 | /* Locking: wl->mutex */ | 3802 | /* Locking: wl->mutex |
3837 | static void b43_wireless_core_stop(struct b43_wldev *dev) | 3803 | * Returns the current dev. This might be different from the passed in dev, |
3804 | * because the core might be gone away while we unlocked the mutex. */ | ||
3805 | static struct b43_wldev * b43_wireless_core_stop(struct b43_wldev *dev) | ||
3838 | { | 3806 | { |
3839 | struct b43_wl *wl = dev->wl; | 3807 | struct b43_wl *wl = dev->wl; |
3840 | unsigned long flags; | 3808 | struct b43_wldev *orig_dev; |
3841 | 3809 | ||
3842 | if (b43_status(dev) < B43_STAT_STARTED) | 3810 | redo: |
3843 | return; | 3811 | if (!dev || b43_status(dev) < B43_STAT_STARTED) |
3812 | return dev; | ||
3844 | 3813 | ||
3845 | /* Disable and sync interrupts. We must do this before than | 3814 | /* Cancel work. Unlock to avoid deadlocks. */ |
3846 | * setting the status to INITIALIZED, as the interrupt handler | 3815 | mutex_unlock(&wl->mutex); |
3847 | * won't care about IRQs then. */ | 3816 | cancel_delayed_work_sync(&dev->periodic_work); |
3848 | spin_lock_irqsave(&wl->irq_lock, flags); | 3817 | cancel_work_sync(&wl->tx_work); |
3849 | b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0); | 3818 | mutex_lock(&wl->mutex); |
3850 | b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* flush */ | 3819 | dev = wl->current_dev; |
3851 | spin_unlock_irqrestore(&wl->irq_lock, flags); | 3820 | if (!dev || b43_status(dev) < B43_STAT_STARTED) { |
3852 | b43_synchronize_irq(dev); | 3821 | /* Whoops, aliens ate up the device while we were unlocked. */ |
3822 | return dev; | ||
3823 | } | ||
3853 | 3824 | ||
3854 | write_lock_irqsave(&wl->tx_lock, flags); | 3825 | /* Disable interrupts on the device. */ |
3855 | b43_set_status(dev, B43_STAT_INITIALIZED); | 3826 | b43_set_status(dev, B43_STAT_INITIALIZED); |
3856 | write_unlock_irqrestore(&wl->tx_lock, flags); | 3827 | if (0 /*FIXME dev->dev->bus->bustype == SSB_BUSTYPE_SDIO*/) { |
3857 | 3828 | /* wl->mutex is locked. That is enough. */ | |
3858 | b43_pio_stop(dev); | 3829 | b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0); |
3830 | b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* Flush */ | ||
3831 | } else { | ||
3832 | spin_lock_irq(&wl->hardirq_lock); | ||
3833 | b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0); | ||
3834 | b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* Flush */ | ||
3835 | spin_unlock_irq(&wl->hardirq_lock); | ||
3836 | } | ||
3837 | /* Synchronize the interrupt handlers. Unlock to avoid deadlocks. */ | ||
3838 | orig_dev = dev; | ||
3859 | mutex_unlock(&wl->mutex); | 3839 | mutex_unlock(&wl->mutex); |
3860 | /* Must unlock as it would otherwise deadlock. No races here. | 3840 | synchronize_irq(dev->dev->irq); |
3861 | * Cancel the possibly running self-rearming periodic work. */ | ||
3862 | cancel_delayed_work_sync(&dev->periodic_work); | ||
3863 | mutex_lock(&wl->mutex); | 3841 | mutex_lock(&wl->mutex); |
3842 | dev = wl->current_dev; | ||
3843 | if (!dev) | ||
3844 | return dev; | ||
3845 | if (dev != orig_dev) { | ||
3846 | if (b43_status(dev) >= B43_STAT_STARTED) | ||
3847 | goto redo; | ||
3848 | return dev; | ||
3849 | } | ||
3850 | B43_WARN_ON(b43_read32(dev, B43_MMIO_GEN_IRQ_MASK)); | ||
3851 | |||
3852 | /* Drain the TX queue */ | ||
3853 | while (skb_queue_len(&wl->tx_queue)) | ||
3854 | dev_kfree_skb(skb_dequeue(&wl->tx_queue)); | ||
3864 | 3855 | ||
3865 | b43_mac_suspend(dev); | 3856 | b43_mac_suspend(dev); |
3866 | free_irq(dev->dev->irq, dev); | 3857 | free_irq(dev->dev->irq, dev); |
3867 | b43dbg(wl, "Wireless interface stopped\n"); | 3858 | b43dbg(wl, "Wireless interface stopped\n"); |
3859 | |||
3860 | return dev; | ||
3868 | } | 3861 | } |
3869 | 3862 | ||
3870 | /* Locking: wl->mutex */ | 3863 | /* Locking: wl->mutex */ |
@@ -3875,8 +3868,9 @@ static int b43_wireless_core_start(struct b43_wldev *dev) | |||
3875 | B43_WARN_ON(b43_status(dev) != B43_STAT_INITIALIZED); | 3868 | B43_WARN_ON(b43_status(dev) != B43_STAT_INITIALIZED); |
3876 | 3869 | ||
3877 | drain_txstatus_queue(dev); | 3870 | drain_txstatus_queue(dev); |
3878 | err = request_irq(dev->dev->irq, b43_interrupt_handler, | 3871 | err = request_threaded_irq(dev->dev->irq, b43_interrupt_handler, |
3879 | IRQF_SHARED, KBUILD_MODNAME, dev); | 3872 | b43_interrupt_thread_handler, |
3873 | IRQF_SHARED, KBUILD_MODNAME, dev); | ||
3880 | if (err) { | 3874 | if (err) { |
3881 | b43err(dev->wl, "Cannot request IRQ-%d\n", dev->dev->irq); | 3875 | b43err(dev->wl, "Cannot request IRQ-%d\n", dev->dev->irq); |
3882 | goto out; | 3876 | goto out; |
@@ -4098,16 +4092,20 @@ static void b43_imcfglo_timeouts_workaround(struct b43_wldev *dev) | |||
4098 | bus->pcicore.dev->id.revision <= 5) { | 4092 | bus->pcicore.dev->id.revision <= 5) { |
4099 | /* IMCFGLO timeouts workaround. */ | 4093 | /* IMCFGLO timeouts workaround. */ |
4100 | tmp = ssb_read32(dev->dev, SSB_IMCFGLO); | 4094 | tmp = ssb_read32(dev->dev, SSB_IMCFGLO); |
4101 | tmp &= ~SSB_IMCFGLO_REQTO; | ||
4102 | tmp &= ~SSB_IMCFGLO_SERTO; | ||
4103 | switch (bus->bustype) { | 4095 | switch (bus->bustype) { |
4104 | case SSB_BUSTYPE_PCI: | 4096 | case SSB_BUSTYPE_PCI: |
4105 | case SSB_BUSTYPE_PCMCIA: | 4097 | case SSB_BUSTYPE_PCMCIA: |
4098 | tmp &= ~SSB_IMCFGLO_REQTO; | ||
4099 | tmp &= ~SSB_IMCFGLO_SERTO; | ||
4106 | tmp |= 0x32; | 4100 | tmp |= 0x32; |
4107 | break; | 4101 | break; |
4108 | case SSB_BUSTYPE_SSB: | 4102 | case SSB_BUSTYPE_SSB: |
4103 | tmp &= ~SSB_IMCFGLO_REQTO; | ||
4104 | tmp &= ~SSB_IMCFGLO_SERTO; | ||
4109 | tmp |= 0x53; | 4105 | tmp |= 0x53; |
4110 | break; | 4106 | break; |
4107 | default: | ||
4108 | break; | ||
4111 | } | 4109 | } |
4112 | ssb_write32(dev->dev, SSB_IMCFGLO, tmp); | 4110 | ssb_write32(dev->dev, SSB_IMCFGLO, tmp); |
4113 | } | 4111 | } |
@@ -4155,8 +4153,8 @@ static void b43_wireless_core_exit(struct b43_wldev *dev) | |||
4155 | { | 4153 | { |
4156 | u32 macctl; | 4154 | u32 macctl; |
4157 | 4155 | ||
4158 | B43_WARN_ON(b43_status(dev) > B43_STAT_INITIALIZED); | 4156 | B43_WARN_ON(dev && b43_status(dev) > B43_STAT_INITIALIZED); |
4159 | if (b43_status(dev) != B43_STAT_INITIALIZED) | 4157 | if (!dev || b43_status(dev) != B43_STAT_INITIALIZED) |
4160 | return; | 4158 | return; |
4161 | b43_set_status(dev, B43_STAT_UNINIT); | 4159 | b43_set_status(dev, B43_STAT_UNINIT); |
4162 | 4160 | ||
@@ -4309,7 +4307,6 @@ static int b43_op_add_interface(struct ieee80211_hw *hw, | |||
4309 | { | 4307 | { |
4310 | struct b43_wl *wl = hw_to_b43_wl(hw); | 4308 | struct b43_wl *wl = hw_to_b43_wl(hw); |
4311 | struct b43_wldev *dev; | 4309 | struct b43_wldev *dev; |
4312 | unsigned long flags; | ||
4313 | int err = -EOPNOTSUPP; | 4310 | int err = -EOPNOTSUPP; |
4314 | 4311 | ||
4315 | /* TODO: allow WDS/AP devices to coexist */ | 4312 | /* TODO: allow WDS/AP devices to coexist */ |
@@ -4333,12 +4330,10 @@ static int b43_op_add_interface(struct ieee80211_hw *hw, | |||
4333 | wl->if_type = conf->type; | 4330 | wl->if_type = conf->type; |
4334 | memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN); | 4331 | memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN); |
4335 | 4332 | ||
4336 | spin_lock_irqsave(&wl->irq_lock, flags); | ||
4337 | b43_adjust_opmode(dev); | 4333 | b43_adjust_opmode(dev); |
4338 | b43_set_pretbtt(dev); | 4334 | b43_set_pretbtt(dev); |
4339 | b43_set_synth_pu_delay(dev, 0); | 4335 | b43_set_synth_pu_delay(dev, 0); |
4340 | b43_upload_card_macaddress(dev); | 4336 | b43_upload_card_macaddress(dev); |
4341 | spin_unlock_irqrestore(&wl->irq_lock, flags); | ||
4342 | 4337 | ||
4343 | err = 0; | 4338 | err = 0; |
4344 | out_mutex_unlock: | 4339 | out_mutex_unlock: |
@@ -4352,7 +4347,6 @@ static void b43_op_remove_interface(struct ieee80211_hw *hw, | |||
4352 | { | 4347 | { |
4353 | struct b43_wl *wl = hw_to_b43_wl(hw); | 4348 | struct b43_wl *wl = hw_to_b43_wl(hw); |
4354 | struct b43_wldev *dev = wl->current_dev; | 4349 | struct b43_wldev *dev = wl->current_dev; |
4355 | unsigned long flags; | ||
4356 | 4350 | ||
4357 | b43dbg(wl, "Removing Interface type %d\n", conf->type); | 4351 | b43dbg(wl, "Removing Interface type %d\n", conf->type); |
4358 | 4352 | ||
@@ -4364,11 +4358,9 @@ static void b43_op_remove_interface(struct ieee80211_hw *hw, | |||
4364 | 4358 | ||
4365 | wl->operating = 0; | 4359 | wl->operating = 0; |
4366 | 4360 | ||
4367 | spin_lock_irqsave(&wl->irq_lock, flags); | ||
4368 | b43_adjust_opmode(dev); | 4361 | b43_adjust_opmode(dev); |
4369 | memset(wl->mac_addr, 0, ETH_ALEN); | 4362 | memset(wl->mac_addr, 0, ETH_ALEN); |
4370 | b43_upload_card_macaddress(dev); | 4363 | b43_upload_card_macaddress(dev); |
4371 | spin_unlock_irqrestore(&wl->irq_lock, flags); | ||
4372 | 4364 | ||
4373 | mutex_unlock(&wl->mutex); | 4365 | mutex_unlock(&wl->mutex); |
4374 | } | 4366 | } |
@@ -4428,10 +4420,15 @@ static void b43_op_stop(struct ieee80211_hw *hw) | |||
4428 | cancel_work_sync(&(wl->beacon_update_trigger)); | 4420 | cancel_work_sync(&(wl->beacon_update_trigger)); |
4429 | 4421 | ||
4430 | mutex_lock(&wl->mutex); | 4422 | mutex_lock(&wl->mutex); |
4431 | if (b43_status(dev) >= B43_STAT_STARTED) | 4423 | if (b43_status(dev) >= B43_STAT_STARTED) { |
4432 | b43_wireless_core_stop(dev); | 4424 | dev = b43_wireless_core_stop(dev); |
4425 | if (!dev) | ||
4426 | goto out_unlock; | ||
4427 | } | ||
4433 | b43_wireless_core_exit(dev); | 4428 | b43_wireless_core_exit(dev); |
4434 | wl->radio_enabled = 0; | 4429 | wl->radio_enabled = 0; |
4430 | |||
4431 | out_unlock: | ||
4435 | mutex_unlock(&wl->mutex); | 4432 | mutex_unlock(&wl->mutex); |
4436 | 4433 | ||
4437 | cancel_work_sync(&(wl->txpower_adjust_work)); | 4434 | cancel_work_sync(&(wl->txpower_adjust_work)); |
@@ -4441,11 +4438,10 @@ static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, | |||
4441 | struct ieee80211_sta *sta, bool set) | 4438 | struct ieee80211_sta *sta, bool set) |
4442 | { | 4439 | { |
4443 | struct b43_wl *wl = hw_to_b43_wl(hw); | 4440 | struct b43_wl *wl = hw_to_b43_wl(hw); |
4444 | unsigned long flags; | ||
4445 | 4441 | ||
4446 | spin_lock_irqsave(&wl->irq_lock, flags); | 4442 | mutex_lock(&wl->mutex); |
4447 | b43_update_templates(wl); | 4443 | b43_update_templates(wl); |
4448 | spin_unlock_irqrestore(&wl->irq_lock, flags); | 4444 | mutex_unlock(&wl->mutex); |
4449 | 4445 | ||
4450 | return 0; | 4446 | return 0; |
4451 | } | 4447 | } |
@@ -4526,8 +4522,13 @@ static void b43_chip_reset(struct work_struct *work) | |||
4526 | 4522 | ||
4527 | prev_status = b43_status(dev); | 4523 | prev_status = b43_status(dev); |
4528 | /* Bring the device down... */ | 4524 | /* Bring the device down... */ |
4529 | if (prev_status >= B43_STAT_STARTED) | 4525 | if (prev_status >= B43_STAT_STARTED) { |
4530 | b43_wireless_core_stop(dev); | 4526 | dev = b43_wireless_core_stop(dev); |
4527 | if (!dev) { | ||
4528 | err = -ENODEV; | ||
4529 | goto out; | ||
4530 | } | ||
4531 | } | ||
4531 | if (prev_status >= B43_STAT_INITIALIZED) | 4532 | if (prev_status >= B43_STAT_INITIALIZED) |
4532 | b43_wireless_core_exit(dev); | 4533 | b43_wireless_core_exit(dev); |
4533 | 4534 | ||
@@ -4742,9 +4743,6 @@ static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl) | |||
4742 | wldev->wl = wl; | 4743 | wldev->wl = wl; |
4743 | b43_set_status(wldev, B43_STAT_UNINIT); | 4744 | b43_set_status(wldev, B43_STAT_UNINIT); |
4744 | wldev->bad_frames_preempt = modparam_bad_frames_preempt; | 4745 | wldev->bad_frames_preempt = modparam_bad_frames_preempt; |
4745 | tasklet_init(&wldev->isr_tasklet, | ||
4746 | (void (*)(unsigned long))b43_interrupt_tasklet, | ||
4747 | (unsigned long)wldev); | ||
4748 | INIT_LIST_HEAD(&wldev->list); | 4746 | INIT_LIST_HEAD(&wldev->list); |
4749 | 4747 | ||
4750 | err = b43_wireless_core_attach(wldev); | 4748 | err = b43_wireless_core_attach(wldev); |
@@ -4841,14 +4839,14 @@ static int b43_wireless_init(struct ssb_device *dev) | |||
4841 | 4839 | ||
4842 | /* Initialize struct b43_wl */ | 4840 | /* Initialize struct b43_wl */ |
4843 | wl->hw = hw; | 4841 | wl->hw = hw; |
4844 | spin_lock_init(&wl->irq_lock); | ||
4845 | rwlock_init(&wl->tx_lock); | ||
4846 | spin_lock_init(&wl->leds_lock); | 4842 | spin_lock_init(&wl->leds_lock); |
4847 | spin_lock_init(&wl->shm_lock); | ||
4848 | mutex_init(&wl->mutex); | 4843 | mutex_init(&wl->mutex); |
4844 | spin_lock_init(&wl->hardirq_lock); | ||
4849 | INIT_LIST_HEAD(&wl->devlist); | 4845 | INIT_LIST_HEAD(&wl->devlist); |
4850 | INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work); | 4846 | INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work); |
4851 | INIT_WORK(&wl->txpower_adjust_work, b43_phy_txpower_adjust_work); | 4847 | INIT_WORK(&wl->txpower_adjust_work, b43_phy_txpower_adjust_work); |
4848 | INIT_WORK(&wl->tx_work, b43_tx_work); | ||
4849 | skb_queue_head_init(&wl->tx_queue); | ||
4852 | 4850 | ||
4853 | ssb_set_devtypedata(dev, wl); | 4851 | ssb_set_devtypedata(dev, wl); |
4854 | b43info(wl, "Broadcom %04X WLAN found (core revision %u)\n", | 4852 | b43info(wl, "Broadcom %04X WLAN found (core revision %u)\n", |
@@ -4946,8 +4944,8 @@ static int b43_suspend(struct ssb_device *dev, pm_message_t state) | |||
4946 | wldev->suspend_in_progress = true; | 4944 | wldev->suspend_in_progress = true; |
4947 | wldev->suspend_init_status = b43_status(wldev); | 4945 | wldev->suspend_init_status = b43_status(wldev); |
4948 | if (wldev->suspend_init_status >= B43_STAT_STARTED) | 4946 | if (wldev->suspend_init_status >= B43_STAT_STARTED) |
4949 | b43_wireless_core_stop(wldev); | 4947 | wldev = b43_wireless_core_stop(wldev); |
4950 | if (wldev->suspend_init_status >= B43_STAT_INITIALIZED) | 4948 | if (wldev && wldev->suspend_init_status >= B43_STAT_INITIALIZED) |
4951 | b43_wireless_core_exit(wldev); | 4949 | b43_wireless_core_exit(wldev); |
4952 | mutex_unlock(&wl->mutex); | 4950 | mutex_unlock(&wl->mutex); |
4953 | 4951 | ||