diff options
Diffstat (limited to 'drivers/net/wireless/ath5k/base.c')
-rw-r--r-- | drivers/net/wireless/ath5k/base.c | 100 |
1 files changed, 64 insertions, 36 deletions
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index d9769c527346..ebf19bc11f5b 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c | |||
@@ -43,7 +43,9 @@ | |||
43 | #include <linux/version.h> | 43 | #include <linux/version.h> |
44 | #include <linux/module.h> | 44 | #include <linux/module.h> |
45 | #include <linux/delay.h> | 45 | #include <linux/delay.h> |
46 | #include <linux/hardirq.h> | ||
46 | #include <linux/if.h> | 47 | #include <linux/if.h> |
48 | #include <linux/io.h> | ||
47 | #include <linux/netdevice.h> | 49 | #include <linux/netdevice.h> |
48 | #include <linux/cache.h> | 50 | #include <linux/cache.h> |
49 | #include <linux/pci.h> | 51 | #include <linux/pci.h> |
@@ -471,9 +473,6 @@ ath5k_pci_probe(struct pci_dev *pdev, | |||
471 | /* Set private data */ | 473 | /* Set private data */ |
472 | pci_set_drvdata(pdev, hw); | 474 | pci_set_drvdata(pdev, hw); |
473 | 475 | ||
474 | /* Enable msi for devices that support it */ | ||
475 | pci_enable_msi(pdev); | ||
476 | |||
477 | /* Setup interrupt handler */ | 476 | /* Setup interrupt handler */ |
478 | ret = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc); | 477 | ret = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc); |
479 | if (ret) { | 478 | if (ret) { |
@@ -551,7 +550,6 @@ err_ah: | |||
551 | err_irq: | 550 | err_irq: |
552 | free_irq(pdev->irq, sc); | 551 | free_irq(pdev->irq, sc); |
553 | err_free: | 552 | err_free: |
554 | pci_disable_msi(pdev); | ||
555 | ieee80211_free_hw(hw); | 553 | ieee80211_free_hw(hw); |
556 | err_map: | 554 | err_map: |
557 | pci_iounmap(pdev, mem); | 555 | pci_iounmap(pdev, mem); |
@@ -573,7 +571,6 @@ ath5k_pci_remove(struct pci_dev *pdev) | |||
573 | ath5k_detach(pdev, hw); | 571 | ath5k_detach(pdev, hw); |
574 | ath5k_hw_detach(sc->ah); | 572 | ath5k_hw_detach(sc->ah); |
575 | free_irq(pdev->irq, sc); | 573 | free_irq(pdev->irq, sc); |
576 | pci_disable_msi(pdev); | ||
577 | pci_iounmap(pdev, sc->iobase); | 574 | pci_iounmap(pdev, sc->iobase); |
578 | pci_release_region(pdev, 0); | 575 | pci_release_region(pdev, 0); |
579 | pci_disable_device(pdev); | 576 | pci_disable_device(pdev); |
@@ -590,6 +587,9 @@ ath5k_pci_suspend(struct pci_dev *pdev, pm_message_t state) | |||
590 | ath5k_led_off(sc); | 587 | ath5k_led_off(sc); |
591 | 588 | ||
592 | ath5k_stop_hw(sc); | 589 | ath5k_stop_hw(sc); |
590 | |||
591 | free_irq(pdev->irq, sc); | ||
592 | pci_disable_msi(pdev); | ||
593 | pci_save_state(pdev); | 593 | pci_save_state(pdev); |
594 | pci_disable_device(pdev); | 594 | pci_disable_device(pdev); |
595 | pci_set_power_state(pdev, PCI_D3hot); | 595 | pci_set_power_state(pdev, PCI_D3hot); |
@@ -605,15 +605,12 @@ ath5k_pci_resume(struct pci_dev *pdev) | |||
605 | struct ath5k_hw *ah = sc->ah; | 605 | struct ath5k_hw *ah = sc->ah; |
606 | int i, err; | 606 | int i, err; |
607 | 607 | ||
608 | err = pci_set_power_state(pdev, PCI_D0); | 608 | pci_restore_state(pdev); |
609 | if (err) | ||
610 | return err; | ||
611 | 609 | ||
612 | err = pci_enable_device(pdev); | 610 | err = pci_enable_device(pdev); |
613 | if (err) | 611 | if (err) |
614 | return err; | 612 | return err; |
615 | 613 | ||
616 | pci_restore_state(pdev); | ||
617 | /* | 614 | /* |
618 | * Suspend/Resume resets the PCI configuration space, so we have to | 615 | * Suspend/Resume resets the PCI configuration space, so we have to |
619 | * re-disable the RETRY_TIMEOUT register (0x41) to keep | 616 | * re-disable the RETRY_TIMEOUT register (0x41) to keep |
@@ -621,7 +618,17 @@ ath5k_pci_resume(struct pci_dev *pdev) | |||
621 | */ | 618 | */ |
622 | pci_write_config_byte(pdev, 0x41, 0); | 619 | pci_write_config_byte(pdev, 0x41, 0); |
623 | 620 | ||
624 | ath5k_init(sc); | 621 | pci_enable_msi(pdev); |
622 | |||
623 | err = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc); | ||
624 | if (err) { | ||
625 | ATH5K_ERR(sc, "request_irq failed\n"); | ||
626 | goto err_msi; | ||
627 | } | ||
628 | |||
629 | err = ath5k_init(sc); | ||
630 | if (err) | ||
631 | goto err_irq; | ||
625 | ath5k_led_enable(sc); | 632 | ath5k_led_enable(sc); |
626 | 633 | ||
627 | /* | 634 | /* |
@@ -635,6 +642,12 @@ ath5k_pci_resume(struct pci_dev *pdev) | |||
635 | ath5k_hw_reset_key(ah, i); | 642 | ath5k_hw_reset_key(ah, i); |
636 | 643 | ||
637 | return 0; | 644 | return 0; |
645 | err_irq: | ||
646 | free_irq(pdev->irq, sc); | ||
647 | err_msi: | ||
648 | pci_disable_msi(pdev); | ||
649 | pci_disable_device(pdev); | ||
650 | return err; | ||
638 | } | 651 | } |
639 | #endif /* CONFIG_PM */ | 652 | #endif /* CONFIG_PM */ |
640 | 653 | ||
@@ -1224,7 +1237,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) | |||
1224 | 1237 | ||
1225 | pktlen = skb->len; | 1238 | pktlen = skb->len; |
1226 | 1239 | ||
1227 | if (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT)) { | 1240 | if (info->control.hw_key) { |
1228 | keyidx = info->control.hw_key->hw_key_idx; | 1241 | keyidx = info->control.hw_key->hw_key_idx; |
1229 | pktlen += info->control.icv_len; | 1242 | pktlen += info->control.icv_len; |
1230 | } | 1243 | } |
@@ -1249,6 +1262,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) | |||
1249 | 1262 | ||
1250 | txq->link = &ds->ds_link; | 1263 | txq->link = &ds->ds_link; |
1251 | ath5k_hw_tx_start(ah, txq->qnum); | 1264 | ath5k_hw_tx_start(ah, txq->qnum); |
1265 | mmiowb(); | ||
1252 | spin_unlock_bh(&txq->lock); | 1266 | spin_unlock_bh(&txq->lock); |
1253 | 1267 | ||
1254 | return 0; | 1268 | return 0; |
@@ -1583,7 +1597,6 @@ ath5k_rx_stop(struct ath5k_softc *sc) | |||
1583 | ath5k_hw_stop_pcu_recv(ah); /* disable PCU */ | 1597 | ath5k_hw_stop_pcu_recv(ah); /* disable PCU */ |
1584 | ath5k_hw_set_rx_filter(ah, 0); /* clear recv filter */ | 1598 | ath5k_hw_set_rx_filter(ah, 0); /* clear recv filter */ |
1585 | ath5k_hw_stop_rx_dma(ah); /* disable DMA engine */ | 1599 | ath5k_hw_stop_rx_dma(ah); /* disable DMA engine */ |
1586 | mdelay(3); /* 3ms is long enough for 1 frame */ | ||
1587 | 1600 | ||
1588 | ath5k_debug_printrxbuffs(sc, ah); | 1601 | ath5k_debug_printrxbuffs(sc, ah); |
1589 | 1602 | ||
@@ -1682,31 +1695,44 @@ ath5k_tasklet_rx(unsigned long data) | |||
1682 | struct ath5k_rx_status rs = {}; | 1695 | struct ath5k_rx_status rs = {}; |
1683 | struct sk_buff *skb; | 1696 | struct sk_buff *skb; |
1684 | struct ath5k_softc *sc = (void *)data; | 1697 | struct ath5k_softc *sc = (void *)data; |
1685 | struct ath5k_buf *bf; | 1698 | struct ath5k_buf *bf, *bf_last; |
1686 | struct ath5k_desc *ds; | 1699 | struct ath5k_desc *ds; |
1687 | int ret; | 1700 | int ret; |
1688 | int hdrlen; | 1701 | int hdrlen; |
1689 | int pad; | 1702 | int pad; |
1690 | 1703 | ||
1691 | spin_lock(&sc->rxbuflock); | 1704 | spin_lock(&sc->rxbuflock); |
1705 | if (list_empty(&sc->rxbuf)) { | ||
1706 | ATH5K_WARN(sc, "empty rx buf pool\n"); | ||
1707 | goto unlock; | ||
1708 | } | ||
1709 | bf_last = list_entry(sc->rxbuf.prev, struct ath5k_buf, list); | ||
1692 | do { | 1710 | do { |
1693 | rxs.flag = 0; | 1711 | rxs.flag = 0; |
1694 | 1712 | ||
1695 | if (unlikely(list_empty(&sc->rxbuf))) { | ||
1696 | ATH5K_WARN(sc, "empty rx buf pool\n"); | ||
1697 | break; | ||
1698 | } | ||
1699 | bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list); | 1713 | bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list); |
1700 | BUG_ON(bf->skb == NULL); | 1714 | BUG_ON(bf->skb == NULL); |
1701 | skb = bf->skb; | 1715 | skb = bf->skb; |
1702 | ds = bf->desc; | 1716 | ds = bf->desc; |
1703 | 1717 | ||
1704 | /* TODO only one segment */ | 1718 | /* |
1705 | pci_dma_sync_single_for_cpu(sc->pdev, sc->desc_daddr, | 1719 | * last buffer must not be freed to ensure proper hardware |
1706 | sc->desc_len, PCI_DMA_FROMDEVICE); | 1720 | * function. When the hardware finishes also a packet next to |
1707 | 1721 | * it, we are sure, it doesn't use it anymore and we can go on. | |
1708 | if (unlikely(ds->ds_link == bf->daddr)) /* this is the end */ | 1722 | */ |
1709 | break; | 1723 | if (bf_last == bf) |
1724 | bf->flags |= 1; | ||
1725 | if (bf->flags) { | ||
1726 | struct ath5k_buf *bf_next = list_entry(bf->list.next, | ||
1727 | struct ath5k_buf, list); | ||
1728 | ret = sc->ah->ah_proc_rx_desc(sc->ah, bf_next->desc, | ||
1729 | &rs); | ||
1730 | if (ret) | ||
1731 | break; | ||
1732 | bf->flags &= ~1; | ||
1733 | /* skip the overwritten one (even status is martian) */ | ||
1734 | goto next; | ||
1735 | } | ||
1710 | 1736 | ||
1711 | ret = sc->ah->ah_proc_rx_desc(sc->ah, ds, &rs); | 1737 | ret = sc->ah->ah_proc_rx_desc(sc->ah, ds, &rs); |
1712 | if (unlikely(ret == -EINPROGRESS)) | 1738 | if (unlikely(ret == -EINPROGRESS)) |
@@ -1752,8 +1778,6 @@ ath5k_tasklet_rx(unsigned long data) | |||
1752 | goto next; | 1778 | goto next; |
1753 | } | 1779 | } |
1754 | accept: | 1780 | accept: |
1755 | pci_dma_sync_single_for_cpu(sc->pdev, bf->skbaddr, | ||
1756 | rs.rs_datalen, PCI_DMA_FROMDEVICE); | ||
1757 | pci_unmap_single(sc->pdev, bf->skbaddr, sc->rxbufsize, | 1781 | pci_unmap_single(sc->pdev, bf->skbaddr, sc->rxbufsize, |
1758 | PCI_DMA_FROMDEVICE); | 1782 | PCI_DMA_FROMDEVICE); |
1759 | bf->skb = NULL; | 1783 | bf->skb = NULL; |
@@ -1816,6 +1840,7 @@ accept: | |||
1816 | next: | 1840 | next: |
1817 | list_move_tail(&bf->list, &sc->rxbuf); | 1841 | list_move_tail(&bf->list, &sc->rxbuf); |
1818 | } while (ath5k_rxbuf_setup(sc, bf) == 0); | 1842 | } while (ath5k_rxbuf_setup(sc, bf) == 0); |
1843 | unlock: | ||
1819 | spin_unlock(&sc->rxbuflock); | 1844 | spin_unlock(&sc->rxbuflock); |
1820 | } | 1845 | } |
1821 | 1846 | ||
@@ -1840,9 +1865,6 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) | |||
1840 | list_for_each_entry_safe(bf, bf0, &txq->q, list) { | 1865 | list_for_each_entry_safe(bf, bf0, &txq->q, list) { |
1841 | ds = bf->desc; | 1866 | ds = bf->desc; |
1842 | 1867 | ||
1843 | /* TODO only one segment */ | ||
1844 | pci_dma_sync_single_for_cpu(sc->pdev, sc->desc_daddr, | ||
1845 | sc->desc_len, PCI_DMA_FROMDEVICE); | ||
1846 | ret = sc->ah->ah_proc_tx_desc(sc->ah, ds, &ts); | 1868 | ret = sc->ah->ah_proc_tx_desc(sc->ah, ds, &ts); |
1847 | if (unlikely(ret == -EINPROGRESS)) | 1869 | if (unlikely(ret == -EINPROGRESS)) |
1848 | break; | 1870 | break; |
@@ -2015,8 +2037,6 @@ ath5k_beacon_send(struct ath5k_softc *sc) | |||
2015 | ATH5K_WARN(sc, "beacon queue %u didn't stop?\n", sc->bhalq); | 2037 | ATH5K_WARN(sc, "beacon queue %u didn't stop?\n", sc->bhalq); |
2016 | /* NB: hw still stops DMA, so proceed */ | 2038 | /* NB: hw still stops DMA, so proceed */ |
2017 | } | 2039 | } |
2018 | pci_dma_sync_single_for_cpu(sc->pdev, bf->skbaddr, bf->skb->len, | ||
2019 | PCI_DMA_TODEVICE); | ||
2020 | 2040 | ||
2021 | ath5k_hw_put_tx_buf(ah, sc->bhalq, bf->daddr); | 2041 | ath5k_hw_put_tx_buf(ah, sc->bhalq, bf->daddr); |
2022 | ath5k_hw_tx_start(ah, sc->bhalq); | 2042 | ath5k_hw_tx_start(ah, sc->bhalq); |
@@ -2150,6 +2170,7 @@ ath5k_beacon_config(struct ath5k_softc *sc) | |||
2150 | 2170 | ||
2151 | ath5k_hw_set_intr(ah, 0); | 2171 | ath5k_hw_set_intr(ah, 0); |
2152 | sc->bmisscount = 0; | 2172 | sc->bmisscount = 0; |
2173 | sc->imask &= ~(AR5K_INT_BMISS | AR5K_INT_SWBA); | ||
2153 | 2174 | ||
2154 | if (sc->opmode == IEEE80211_IF_TYPE_STA) { | 2175 | if (sc->opmode == IEEE80211_IF_TYPE_STA) { |
2155 | sc->imask |= AR5K_INT_BMISS; | 2176 | sc->imask |= AR5K_INT_BMISS; |
@@ -2240,6 +2261,7 @@ ath5k_init(struct ath5k_softc *sc) | |||
2240 | 2261 | ||
2241 | ret = 0; | 2262 | ret = 0; |
2242 | done: | 2263 | done: |
2264 | mmiowb(); | ||
2243 | mutex_unlock(&sc->lock); | 2265 | mutex_unlock(&sc->lock); |
2244 | return ret; | 2266 | return ret; |
2245 | } | 2267 | } |
@@ -2272,6 +2294,7 @@ ath5k_stop_locked(struct ath5k_softc *sc) | |||
2272 | if (!test_bit(ATH_STAT_INVALID, sc->status)) { | 2294 | if (!test_bit(ATH_STAT_INVALID, sc->status)) { |
2273 | ath5k_led_off(sc); | 2295 | ath5k_led_off(sc); |
2274 | ath5k_hw_set_intr(ah, 0); | 2296 | ath5k_hw_set_intr(ah, 0); |
2297 | synchronize_irq(sc->pdev->irq); | ||
2275 | } | 2298 | } |
2276 | ath5k_txq_cleanup(sc); | 2299 | ath5k_txq_cleanup(sc); |
2277 | if (!test_bit(ATH_STAT_INVALID, sc->status)) { | 2300 | if (!test_bit(ATH_STAT_INVALID, sc->status)) { |
@@ -2321,9 +2344,13 @@ ath5k_stop_hw(struct ath5k_softc *sc) | |||
2321 | } | 2344 | } |
2322 | } | 2345 | } |
2323 | ath5k_txbuf_free(sc, sc->bbuf); | 2346 | ath5k_txbuf_free(sc, sc->bbuf); |
2347 | mmiowb(); | ||
2324 | mutex_unlock(&sc->lock); | 2348 | mutex_unlock(&sc->lock); |
2325 | 2349 | ||
2326 | del_timer_sync(&sc->calib_tim); | 2350 | del_timer_sync(&sc->calib_tim); |
2351 | tasklet_kill(&sc->rxtq); | ||
2352 | tasklet_kill(&sc->txtq); | ||
2353 | tasklet_kill(&sc->restq); | ||
2327 | 2354 | ||
2328 | return ret; | 2355 | return ret; |
2329 | } | 2356 | } |
@@ -2550,8 +2577,6 @@ ath5k_init_leds(struct ath5k_softc *sc) | |||
2550 | struct pci_dev *pdev = sc->pdev; | 2577 | struct pci_dev *pdev = sc->pdev; |
2551 | char name[ATH5K_LED_MAX_NAME_LEN + 1]; | 2578 | char name[ATH5K_LED_MAX_NAME_LEN + 1]; |
2552 | 2579 | ||
2553 | sc->led_on = 0; /* active low */ | ||
2554 | |||
2555 | /* | 2580 | /* |
2556 | * Auto-enable soft led processing for IBM cards and for | 2581 | * Auto-enable soft led processing for IBM cards and for |
2557 | * 5211 minipci cards. | 2582 | * 5211 minipci cards. |
@@ -2560,11 +2585,13 @@ ath5k_init_leds(struct ath5k_softc *sc) | |||
2560 | pdev->device == PCI_DEVICE_ID_ATHEROS_AR5211) { | 2585 | pdev->device == PCI_DEVICE_ID_ATHEROS_AR5211) { |
2561 | __set_bit(ATH_STAT_LEDSOFT, sc->status); | 2586 | __set_bit(ATH_STAT_LEDSOFT, sc->status); |
2562 | sc->led_pin = 0; | 2587 | sc->led_pin = 0; |
2588 | sc->led_on = 0; /* active low */ | ||
2563 | } | 2589 | } |
2564 | /* Enable softled on PIN1 on HP Compaq nc6xx, nc4000 & nx5000 laptops */ | 2590 | /* Enable softled on PIN1 on HP Compaq nc6xx, nc4000 & nx5000 laptops */ |
2565 | if (pdev->subsystem_vendor == PCI_VENDOR_ID_COMPAQ) { | 2591 | if (pdev->subsystem_vendor == PCI_VENDOR_ID_COMPAQ) { |
2566 | __set_bit(ATH_STAT_LEDSOFT, sc->status); | 2592 | __set_bit(ATH_STAT_LEDSOFT, sc->status); |
2567 | sc->led_pin = 1; | 2593 | sc->led_pin = 1; |
2594 | sc->led_on = 1; /* active high */ | ||
2568 | } | 2595 | } |
2569 | if (!test_bit(ATH_STAT_LEDSOFT, sc->status)) | 2596 | if (!test_bit(ATH_STAT_LEDSOFT, sc->status)) |
2570 | goto out; | 2597 | goto out; |
@@ -2783,6 +2810,7 @@ ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | |||
2783 | /* XXX: assoc id is set to 0 for now, mac80211 doesn't have | 2810 | /* XXX: assoc id is set to 0 for now, mac80211 doesn't have |
2784 | * a clean way of letting us retrieve this yet. */ | 2811 | * a clean way of letting us retrieve this yet. */ |
2785 | ath5k_hw_set_associd(ah, ah->ah_bssid, 0); | 2812 | ath5k_hw_set_associd(ah, ah->ah_bssid, 0); |
2813 | mmiowb(); | ||
2786 | } | 2814 | } |
2787 | 2815 | ||
2788 | if (conf->changed & IEEE80211_IFCC_BEACON && | 2816 | if (conf->changed & IEEE80211_IFCC_BEACON && |
@@ -2971,6 +2999,7 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
2971 | } | 2999 | } |
2972 | 3000 | ||
2973 | unlock: | 3001 | unlock: |
3002 | mmiowb(); | ||
2974 | mutex_unlock(&sc->lock); | 3003 | mutex_unlock(&sc->lock); |
2975 | return ret; | 3004 | return ret; |
2976 | } | 3005 | } |
@@ -3032,8 +3061,6 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
3032 | 3061 | ||
3033 | ath5k_debug_dump_skb(sc, skb, "BC ", 1); | 3062 | ath5k_debug_dump_skb(sc, skb, "BC ", 1); |
3034 | 3063 | ||
3035 | mutex_lock(&sc->lock); | ||
3036 | |||
3037 | if (sc->opmode != IEEE80211_IF_TYPE_IBSS) { | 3064 | if (sc->opmode != IEEE80211_IF_TYPE_IBSS) { |
3038 | ret = -EIO; | 3065 | ret = -EIO; |
3039 | goto end; | 3066 | goto end; |
@@ -3044,11 +3071,12 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
3044 | ret = ath5k_beacon_setup(sc, sc->bbuf); | 3071 | ret = ath5k_beacon_setup(sc, sc->bbuf); |
3045 | if (ret) | 3072 | if (ret) |
3046 | sc->bbuf->skb = NULL; | 3073 | sc->bbuf->skb = NULL; |
3047 | else | 3074 | else { |
3048 | ath5k_beacon_config(sc); | 3075 | ath5k_beacon_config(sc); |
3076 | mmiowb(); | ||
3077 | } | ||
3049 | 3078 | ||
3050 | end: | 3079 | end: |
3051 | mutex_unlock(&sc->lock); | ||
3052 | return ret; | 3080 | return ret; |
3053 | } | 3081 | } |
3054 | 3082 | ||