From dc822b5db479dc0178d5c04cbb656dad0b6564fb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Dec 2008 12:55:09 +0100 Subject: mac80211: clean up set_key callback The set_key callback now seems rather odd, passing a MAC address instead of a station struct, and a local address instead of a vif struct. Change that. Signed-off-by: Johannes Berg Acked-by: Bob Copeland [ath5k] Acked-by: Ivo van Doorn [rt2x00] Acked-by: Christian Lamparter [p54] Tested-by: Kalle Valo [iwl3945] Tested-by: Samuel Ortiz [iwl3945] Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless/ath5k/base.c') diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 8ef87356e083..88618645a7e4 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -232,7 +232,7 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw, int mc_count, struct dev_mc_list *mclist); static int ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, - const u8 *local_addr, const u8 *addr, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key); static int ath5k_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats); @@ -2991,8 +2991,8 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw, static int ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, - const u8 *local_addr, const u8 *addr, - struct ieee80211_key_conf *key) + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) { struct ath5k_softc *sc = hw->priv; int ret = 0; @@ -3015,7 +3015,8 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, switch (cmd) { case SET_KEY: - ret = ath5k_hw_set_key(sc->ah, key->keyidx, key, addr); + ret = ath5k_hw_set_key(sc->ah, key->keyidx, key, + sta ? sta->addr : NULL); if (ret) { ATH5K_ERR(sc, "can't set the key\n"); goto unlock; -- cgit v1.2.1 From 63649b6cf0a964582af2b4d4734e28ca90ec8f5c Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Thu, 1 Jan 2009 15:01:44 -0500 Subject: ath5k: support LEDs on Acer Aspire One netbook Add vendor ID for Foxconn and use it to set the ath5k LED gpio and polarity for Acer branded laptops. base.c: Changes-licensed-under: 3-Clause-BSD Reported-by: Maxim Levitsky Tested-by: Maxim Levitsky Tested-by: Andreas Mohr Signed-off-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/net/wireless/ath5k/base.c') diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 88618645a7e4..fdf7733e76e1 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -2596,6 +2596,13 @@ ath5k_init_leds(struct ath5k_softc *sc) sc->led_pin = 1; sc->led_on = 1; /* active high */ } + /* Pin 3 on Foxconn chips used in Acer Aspire One (0x105b:e008) */ + if (pdev->subsystem_vendor == PCI_VENDOR_ID_FOXCONN) { + __set_bit(ATH_STAT_LEDSOFT, sc->status); + sc->led_pin = 3; + sc->led_on = 0; /* active low */ + } + if (!test_bit(ATH_STAT_LEDSOFT, sc->status)) goto out; -- cgit v1.2.1 From b6ea03562f04382776ad825624daefe27f5d3f9c Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Sat, 10 Jan 2009 14:42:54 -0500 Subject: ath5k: fix bf->skb==NULL panic in ath5k_tasklet_rx Under memory pressure, we may not be able to allocate a new skb for new packets. If the allocation fails, ath5k_tasklet_rx will exit but will leave a buffer in the list with a NULL skb, eventually triggering a BUG_ON. Extract the skb allocation from ath5k_rxbuf_setup() and change the tasklet to allocate the next skb before accepting a packet. Changes-licensed-under: 3-Clause-BSD Signed-off-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 85 ++++++++++++++++++++++++--------------- 1 file changed, 53 insertions(+), 32 deletions(-) (limited to 'drivers/net/wireless/ath5k/base.c') diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index fdf7733e76e1..d3178731adc6 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -1096,6 +1096,42 @@ ath5k_hw_to_driver_rix(struct ath5k_softc *sc, int hw_rix) * Buffers setup * \***************/ +static +struct sk_buff *ath5k_rx_skb_alloc(struct ath5k_softc *sc, dma_addr_t *skb_addr) +{ + struct sk_buff *skb; + unsigned int off; + + /* + * Allocate buffer with headroom_needed space for the + * fake physical layer header at the start. + */ + skb = dev_alloc_skb(sc->rxbufsize + sc->cachelsz - 1); + + if (!skb) { + ATH5K_ERR(sc, "can't alloc skbuff of size %u\n", + sc->rxbufsize + sc->cachelsz - 1); + return NULL; + } + /* + * Cache-line-align. This is important (for the + * 5210 at least) as not doing so causes bogus data + * in rx'd frames. + */ + off = ((unsigned long)skb->data) % sc->cachelsz; + if (off != 0) + skb_reserve(skb, sc->cachelsz - off); + + *skb_addr = pci_map_single(sc->pdev, + skb->data, sc->rxbufsize, PCI_DMA_FROMDEVICE); + if (unlikely(pci_dma_mapping_error(sc->pdev, *skb_addr))) { + ATH5K_ERR(sc, "%s: DMA mapping failed\n", __func__); + dev_kfree_skb(skb); + return NULL; + } + return skb; +} + static int ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) { @@ -1103,37 +1139,11 @@ ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) struct sk_buff *skb = bf->skb; struct ath5k_desc *ds; - if (likely(skb == NULL)) { - unsigned int off; - - /* - * Allocate buffer with headroom_needed space for the - * fake physical layer header at the start. - */ - skb = dev_alloc_skb(sc->rxbufsize + sc->cachelsz - 1); - if (unlikely(skb == NULL)) { - ATH5K_ERR(sc, "can't alloc skbuff of size %u\n", - sc->rxbufsize + sc->cachelsz - 1); + if (!skb) { + skb = ath5k_rx_skb_alloc(sc, &bf->skbaddr); + if (!skb) return -ENOMEM; - } - /* - * Cache-line-align. This is important (for the - * 5210 at least) as not doing so causes bogus data - * in rx'd frames. - */ - off = ((unsigned long)skb->data) % sc->cachelsz; - if (off != 0) - skb_reserve(skb, sc->cachelsz - off); - bf->skb = skb; - bf->skbaddr = pci_map_single(sc->pdev, - skb->data, sc->rxbufsize, PCI_DMA_FROMDEVICE); - if (unlikely(pci_dma_mapping_error(sc->pdev, bf->skbaddr))) { - ATH5K_ERR(sc, "%s: DMA mapping failed\n", __func__); - dev_kfree_skb(skb); - bf->skb = NULL; - return -ENOMEM; - } } /* @@ -1662,7 +1672,8 @@ ath5k_tasklet_rx(unsigned long data) { struct ieee80211_rx_status rxs = {}; struct ath5k_rx_status rs = {}; - struct sk_buff *skb; + struct sk_buff *skb, *next_skb; + dma_addr_t next_skb_addr; struct ath5k_softc *sc = (void *)data; struct ath5k_buf *bf, *bf_last; struct ath5k_desc *ds; @@ -1747,10 +1758,17 @@ ath5k_tasklet_rx(unsigned long data) goto next; } accept: + next_skb = ath5k_rx_skb_alloc(sc, &next_skb_addr); + + /* + * If we can't replace bf->skb with a new skb under memory + * pressure, just skip this packet + */ + if (!next_skb) + goto next; + pci_unmap_single(sc->pdev, bf->skbaddr, sc->rxbufsize, PCI_DMA_FROMDEVICE); - bf->skb = NULL; - skb_put(skb, rs.rs_datalen); /* The MAC header is padded to have 32-bit boundary if the @@ -1823,6 +1841,9 @@ accept: ath5k_check_ibss_tsf(sc, skb, &rxs); __ieee80211_rx(sc->hw, skb, &rxs); + + bf->skb = next_skb; + bf->skbaddr = next_skb_addr; next: list_move_tail(&bf->list, &sc->rxbuf); } while (ath5k_rxbuf_setup(sc, bf) == 0); -- cgit v1.2.1 From bb2becac91f13e862d4601a8c5364bc758c35b8e Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Mon, 19 Jan 2009 11:20:54 -0500 Subject: ath5k: remove stop/start calls from within suspend/resume mac80211 now takes down interfaces automatically during suspend so doing it in the driver is unnecessary. Signed-off-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 31 +++++++------------------------ 1 file changed, 7 insertions(+), 24 deletions(-) (limited to 'drivers/net/wireless/ath5k/base.c') diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index d3178731adc6..747b49682c5d 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -347,9 +347,9 @@ static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp) } /* Interrupt handling */ -static int ath5k_init(struct ath5k_softc *sc, bool is_resume); +static int ath5k_init(struct ath5k_softc *sc); static int ath5k_stop_locked(struct ath5k_softc *sc); -static int ath5k_stop_hw(struct ath5k_softc *sc, bool is_suspend); +static int ath5k_stop_hw(struct ath5k_softc *sc); static irqreturn_t ath5k_intr(int irq, void *dev_id); static void ath5k_tasklet_reset(unsigned long data); @@ -653,8 +653,6 @@ ath5k_pci_suspend(struct pci_dev *pdev, pm_message_t state) ath5k_led_off(sc); - ath5k_stop_hw(sc, true); - free_irq(pdev->irq, sc); pci_save_state(pdev); pci_disable_device(pdev); @@ -689,14 +687,9 @@ ath5k_pci_resume(struct pci_dev *pdev) goto err_no_irq; } - err = ath5k_init(sc, true); - if (err) - goto err_irq; ath5k_led_enable(sc); - return 0; -err_irq: - free_irq(pdev->irq, sc); + err_no_irq: pci_disable_device(pdev); return err; @@ -2226,18 +2219,13 @@ ath5k_beacon_config(struct ath5k_softc *sc) \********************/ static int -ath5k_init(struct ath5k_softc *sc, bool is_resume) +ath5k_init(struct ath5k_softc *sc) { struct ath5k_hw *ah = sc->ah; int ret, i; mutex_lock(&sc->lock); - if (is_resume && !test_bit(ATH_STAT_STARTED, sc->status)) - goto out_ok; - - __clear_bit(ATH_STAT_STARTED, sc->status); - ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "mode %d\n", sc->opmode); /* @@ -2269,15 +2257,12 @@ ath5k_init(struct ath5k_softc *sc, bool is_resume) for (i = 0; i < AR5K_KEYTABLE_SIZE; i++) ath5k_hw_reset_key(ah, i); - __set_bit(ATH_STAT_STARTED, sc->status); - /* Set ack to be sent at low bit-rates */ ath5k_hw_set_ack_bitrate_high(ah, false); mod_timer(&sc->calib_tim, round_jiffies(jiffies + msecs_to_jiffies(ath5k_calinterval * 1000))); -out_ok: ret = 0; done: mmiowb(); @@ -2332,7 +2317,7 @@ ath5k_stop_locked(struct ath5k_softc *sc) * stop is preempted). */ static int -ath5k_stop_hw(struct ath5k_softc *sc, bool is_suspend) +ath5k_stop_hw(struct ath5k_softc *sc) { int ret; @@ -2363,8 +2348,6 @@ ath5k_stop_hw(struct ath5k_softc *sc, bool is_suspend) } } ath5k_txbuf_free(sc, sc->bbuf); - if (!is_suspend) - __clear_bit(ATH_STAT_STARTED, sc->status); mmiowb(); mutex_unlock(&sc->lock); @@ -2771,12 +2754,12 @@ ath5k_reset_wake(struct ath5k_softc *sc) static int ath5k_start(struct ieee80211_hw *hw) { - return ath5k_init(hw->priv, false); + return ath5k_init(hw->priv); } static void ath5k_stop(struct ieee80211_hw *hw) { - ath5k_stop_hw(hw->priv, false); + ath5k_stop_hw(hw->priv); } static int ath5k_add_interface(struct ieee80211_hw *hw, -- cgit v1.2.1 From 8902ff4e5666c04ca5829c9fd7fc28d73e81ee90 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Thu, 22 Jan 2009 08:44:20 -0500 Subject: ath5k: use short preamble when possible ath5k previously ignored TX_RC_SHORT_PREAMBLE and did not use config->use_short_preamble, so the long preamble was always used for transmitted packets. Changes-licensed-under: 3-Clause-BSD Signed-off-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath5k/base.c') diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 747b49682c5d..fc0ff713401c 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -1179,6 +1179,8 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) struct ieee80211_rate *rate; unsigned int mrr_rate[3], mrr_tries[3]; int i, ret; + u16 hw_rate; + u8 rc_flags; flags = AR5K_TXDESC_INTREQ | AR5K_TXDESC_CLRDMASK; @@ -1186,9 +1188,15 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); + rate = ieee80211_get_tx_rate(sc->hw, info); + if (info->flags & IEEE80211_TX_CTL_NO_ACK) flags |= AR5K_TXDESC_NOACK; + rc_flags = info->control.rates[0].flags; + hw_rate = (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) ? + rate->hw_value_short : rate->hw_value; + pktlen = skb->len; if (info->control.hw_key) { @@ -1198,7 +1206,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) ret = ah->ah_setup_tx_desc(ah, ds, pktlen, ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL, (sc->power_level * 2), - ieee80211_get_tx_rate(sc->hw, info)->hw_value, + hw_rate, info->control.rates[0].count, keyidx, 0, flags, 0, 0); if (ret) goto err_unmap; -- cgit v1.2.1 From 07c1e852514e862e246b9f2962ce8fc0d7ac8ed1 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Thu, 22 Jan 2009 08:44:21 -0500 Subject: ath5k: honor the RTS/CTS bits The ath5k driver didn't use set_rts_threshold or use_cts_prot, and also didn't check the IEEE80211_TX_RC_USE_{RTS_CTS,CTS_PROTECT} RC flags. Tell the hardware about these so RTS/CTS will work, and so the device will work better in mixed b/g environments. Changes-licensed-under: 3-Clause-BSD Signed-off-by: Bob Copeland Acked-by: Nick Kossifidis Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath5k/base.c') diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index fc0ff713401c..fa39f21c36c3 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -1180,6 +1180,8 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) unsigned int mrr_rate[3], mrr_tries[3]; int i, ret; u16 hw_rate; + u16 cts_rate = 0; + u16 duration = 0; u8 rc_flags; flags = AR5K_TXDESC_INTREQ | AR5K_TXDESC_CLRDMASK; @@ -1199,6 +1201,19 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) pktlen = skb->len; + if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) { + flags |= AR5K_TXDESC_RTSENA; + cts_rate = ieee80211_get_rts_cts_rate(sc->hw, info)->hw_value; + duration = le16_to_cpu(ieee80211_rts_duration(sc->hw, + sc->vif, pktlen, info)); + } + if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { + flags |= AR5K_TXDESC_CTSENA; + cts_rate = ieee80211_get_rts_cts_rate(sc->hw, info)->hw_value; + duration = le16_to_cpu(ieee80211_ctstoself_duration(sc->hw, + sc->vif, pktlen, info)); + } + if (info->control.hw_key) { keyidx = info->control.hw_key->hw_key_idx; pktlen += info->control.hw_key->icv_len; @@ -1207,7 +1222,8 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL, (sc->power_level * 2), hw_rate, - info->control.rates[0].count, keyidx, 0, flags, 0, 0); + info->control.rates[0].count, keyidx, 0, flags, + cts_rate, duration); if (ret) goto err_unmap; -- cgit v1.2.1 From 3b5d665b51cda73ef1a774b515afd879a38e3674 Mon Sep 17 00:00:00 2001 From: Alina Friedrichsen Date: Sat, 24 Jan 2009 07:09:59 +0100 Subject: mac80211: Generic TSF debugging This patch enables low-level driver independent debugging of the TSF and remove the driver specific things of ath5k and ath9k from the debugfs. Signed-off-by: Alina Friedrichsen Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/net/wireless/ath5k/base.c') diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index fa39f21c36c3..b3f41acb9065 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -239,6 +239,7 @@ static int ath5k_get_stats(struct ieee80211_hw *hw, static int ath5k_get_tx_stats(struct ieee80211_hw *hw, struct ieee80211_tx_queue_stats *stats); static u64 ath5k_get_tsf(struct ieee80211_hw *hw); +static void ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf); static void ath5k_reset_tsf(struct ieee80211_hw *hw); static int ath5k_beacon_update(struct ath5k_softc *sc, struct sk_buff *skb); @@ -261,6 +262,7 @@ static struct ieee80211_ops ath5k_hw_ops = { .conf_tx = NULL, .get_tx_stats = ath5k_get_tx_stats, .get_tsf = ath5k_get_tsf, + .set_tsf = ath5k_set_tsf, .reset_tsf = ath5k_reset_tsf, .bss_info_changed = ath5k_bss_info_changed, }; @@ -3110,6 +3112,14 @@ ath5k_get_tsf(struct ieee80211_hw *hw) return ath5k_hw_get_tsf64(sc->ah); } +static void +ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf) +{ + struct ath5k_softc *sc = hw->priv; + + ath5k_hw_set_tsf64(sc->ah, tsf); +} + static void ath5k_reset_tsf(struct ieee80211_hw *hw) { -- cgit v1.2.1 From f677d7702d48b7b3dfcce3b2c0db601dbee0aa24 Mon Sep 17 00:00:00 2001 From: Tulio Magno Quites Machado Filho Date: Sun, 25 Jan 2009 23:54:25 +0100 Subject: ath5k: support LED's on emachines E510 notebook Add vendor ID for AMBIT and use it to set the ath5k LED gpio. base.c: Changes-licensed-under: 3-Clause-BSD Signed-off-by: Tulio Magno Quites Machado Filho Acked-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/ath5k/base.c') diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index b3f41acb9065..368db944f11f 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -2626,8 +2626,12 @@ ath5k_init_leds(struct ath5k_softc *sc) sc->led_pin = 1; sc->led_on = 1; /* active high */ } - /* Pin 3 on Foxconn chips used in Acer Aspire One (0x105b:e008) */ - if (pdev->subsystem_vendor == PCI_VENDOR_ID_FOXCONN) { + /* + * Pin 3 on Foxconn chips used in Acer Aspire One (0x105b:e008) and + * in emachines notebooks with AMBIT subsystem. + */ + if (pdev->subsystem_vendor == PCI_VENDOR_ID_FOXCONN || + pdev->subsystem_vendor == PCI_VENDOR_ID_AMBIT) { __set_bit(ATH_STAT_LEDSOFT, sc->status); sc->led_pin = 3; sc->led_on = 0; /* active low */ -- cgit v1.2.1