aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath5k/base.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath5k/base.c')
-rw-r--r--drivers/net/wireless/ath5k/base.c100
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:
551err_irq: 550err_irq:
552 free_irq(pdev->irq, sc); 551 free_irq(pdev->irq, sc);
553err_free: 552err_free:
554 pci_disable_msi(pdev);
555 ieee80211_free_hw(hw); 553 ieee80211_free_hw(hw);
556err_map: 554err_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;
645err_irq:
646 free_irq(pdev->irq, sc);
647err_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 }
1754accept: 1780accept:
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:
1816next: 1840next:
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);
1843unlock:
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;
2242done: 2263done:
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
2973unlock: 3001unlock:
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
3050end: 3079end:
3051 mutex_unlock(&sc->lock);
3052 return ret; 3080 return ret;
3053} 3081}
3054 3082