aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2010-06-12 00:34:01 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-06-14 15:39:32 -0400
commit9f42c2b667691f6ad29842302c66c864e7eb326c (patch)
tree10a411c5704e79dae091431b2176764d09951807
parent717f6bedcd2d3d39624437e1de7067c90ec931f0 (diff)
ath9k: implement PA predistortion support
Signed-off-by: Felix Fietkau <nbd@openwrt.org> Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h7
-rw-r--r--drivers/net/wireless/ath/ath9k/init.c1
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c116
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c16
4 files changed, 137 insertions, 3 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 1a19aea8c88c..8d163ae4255e 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -20,6 +20,7 @@
20#include <linux/etherdevice.h> 20#include <linux/etherdevice.h>
21#include <linux/device.h> 21#include <linux/device.h>
22#include <linux/leds.h> 22#include <linux/leds.h>
23#include <linux/completion.h>
23 24
24#include "debug.h" 25#include "debug.h"
25#include "common.h" 26#include "common.h"
@@ -224,6 +225,7 @@ struct ath_buf_state {
224 int bfs_tidno; 225 int bfs_tidno;
225 int bfs_retries; 226 int bfs_retries;
226 u8 bf_type; 227 u8 bf_type;
228 u8 bfs_paprd;
227 u32 bfs_keyix; 229 u32 bfs_keyix;
228 enum ath9k_key_type bfs_keytype; 230 enum ath9k_key_type bfs_keytype;
229}; 231};
@@ -280,6 +282,7 @@ struct ath_tx_control {
280 struct ath_txq *txq; 282 struct ath_txq *txq;
281 int if_id; 283 int if_id;
282 enum ath9k_internal_frame_type frame_type; 284 enum ath9k_internal_frame_type frame_type;
285 u8 paprd;
283}; 286};
284 287
285#define ATH_TX_ERROR 0x01 288#define ATH_TX_ERROR 0x01
@@ -422,6 +425,7 @@ int ath_beaconq_config(struct ath_softc *sc);
422#define ATH_LONG_CALINTERVAL 30000 /* 30 seconds */ 425#define ATH_LONG_CALINTERVAL 30000 /* 30 seconds */
423#define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */ 426#define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */
424 427
428void ath_paprd_calibrate(struct work_struct *work);
425void ath_ani_calibrate(unsigned long data); 429void ath_ani_calibrate(unsigned long data);
426 430
427/**********/ 431/**********/
@@ -553,6 +557,9 @@ struct ath_softc {
553 spinlock_t sc_serial_rw; 557 spinlock_t sc_serial_rw;
554 spinlock_t sc_pm_lock; 558 spinlock_t sc_pm_lock;
555 struct mutex mutex; 559 struct mutex mutex;
560 struct work_struct paprd_work;
561 struct completion paprd_complete;
562 int paprd_txok;
556 563
557 u32 intrstatus; 564 u32 intrstatus;
558 u32 sc_flags; /* SC_OP_* */ 565 u32 sc_flags; /* SC_OP_* */
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 4e078301c887..e1fa26840a53 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -736,6 +736,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
736 goto error_world; 736 goto error_world;
737 } 737 }
738 738
739 INIT_WORK(&sc->paprd_work, ath_paprd_calibrate);
739 INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work); 740 INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work);
740 INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work); 741 INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work);
741 sc->wiphy_scheduler_int = msecs_to_jiffies(500); 742 sc->wiphy_scheduler_int = msecs_to_jiffies(500);
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index b4136100abfb..f38da2920f85 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -232,6 +232,113 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
232 return r; 232 return r;
233} 233}
234 234
235static void ath_paprd_activate(struct ath_softc *sc)
236{
237 struct ath_hw *ah = sc->sc_ah;
238 int chain;
239
240 if (!ah->curchan->paprd_done)
241 return;
242
243 ath9k_ps_wakeup(sc);
244 for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
245 if (!(ah->caps.tx_chainmask & BIT(chain)))
246 continue;
247
248 ar9003_paprd_populate_single_table(ah, ah->curchan, chain);
249 }
250
251 ar9003_paprd_enable(ah, true);
252 ath9k_ps_restore(sc);
253}
254
255void ath_paprd_calibrate(struct work_struct *work)
256{
257 struct ath_softc *sc = container_of(work, struct ath_softc, paprd_work);
258 struct ieee80211_hw *hw = sc->hw;
259 struct ath_hw *ah = sc->sc_ah;
260 struct ieee80211_hdr *hdr;
261 struct sk_buff *skb = NULL;
262 struct ieee80211_tx_info *tx_info;
263 int band = hw->conf.channel->band;
264 struct ieee80211_supported_band *sband = &sc->sbands[band];
265 struct ath_tx_control txctl;
266 int qnum, ftype;
267 int chain_ok = 0;
268 int chain;
269 int len = 1800;
270 int time_left;
271 int i;
272
273 ath9k_ps_wakeup(sc);
274 skb = alloc_skb(len, GFP_KERNEL);
275 if (!skb)
276 return;
277
278 tx_info = IEEE80211_SKB_CB(skb);
279
280 skb_put(skb, len);
281 memset(skb->data, 0, len);
282 hdr = (struct ieee80211_hdr *)skb->data;
283 ftype = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC;
284 hdr->frame_control = cpu_to_le16(ftype);
285 hdr->duration_id = 10;
286 memcpy(hdr->addr1, hw->wiphy->perm_addr, ETH_ALEN);
287 memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN);
288 memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN);
289
290 memset(&txctl, 0, sizeof(txctl));
291 qnum = sc->tx.hwq_map[WME_AC_BE];
292 txctl.txq = &sc->tx.txq[qnum];
293
294 ar9003_paprd_init_table(ah);
295 for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
296 if (!(ah->caps.tx_chainmask & BIT(chain)))
297 continue;
298
299 chain_ok = 0;
300 memset(tx_info, 0, sizeof(*tx_info));
301 tx_info->band = band;
302
303 for (i = 0; i < 4; i++) {
304 tx_info->control.rates[i].idx = sband->n_bitrates - 1;
305 tx_info->control.rates[i].count = 6;
306 }
307
308 init_completion(&sc->paprd_complete);
309 ar9003_paprd_setup_gain_table(ah, chain);
310 txctl.paprd = BIT(chain);
311 if (ath_tx_start(hw, skb, &txctl) != 0)
312 break;
313
314 time_left = wait_for_completion_timeout(&sc->paprd_complete,
315 100);
316 if (!time_left) {
317 ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
318 "Timeout waiting for paprd training on "
319 "TX chain %d\n",
320 chain);
321 break;
322 }
323
324 if (!ar9003_paprd_is_done(ah))
325 break;
326
327 if (ar9003_paprd_create_curve(ah, ah->curchan, chain) != 0)
328 break;
329
330 chain_ok = 1;
331 }
332 kfree_skb(skb);
333
334 if (chain_ok) {
335 ah->curchan->paprd_done = true;
336 ath_paprd_activate(sc);
337 }
338
339 ath9k_ps_restore(sc);
340}
341
235/* 342/*
236 * This routine performs the periodic noise floor calibration function 343 * This routine performs the periodic noise floor calibration function
237 * that is used to adjust and optimize the chip performance. This 344 * that is used to adjust and optimize the chip performance. This
@@ -333,6 +440,13 @@ set_timer:
333 cal_interval = min(cal_interval, (u32)short_cal_interval); 440 cal_interval = min(cal_interval, (u32)short_cal_interval);
334 441
335 mod_timer(&common->ani.timer, jiffies + msecs_to_jiffies(cal_interval)); 442 mod_timer(&common->ani.timer, jiffies + msecs_to_jiffies(cal_interval));
443 if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_PAPRD) &&
444 !(sc->sc_flags & SC_OP_SCANNING)) {
445 if (!sc->sc_ah->curchan->paprd_done)
446 ieee80211_queue_work(sc->hw, &sc->paprd_work);
447 else
448 ath_paprd_activate(sc);
449 }
336} 450}
337 451
338static void ath_start_ani(struct ath_common *common) 452static void ath_start_ani(struct ath_common *common)
@@ -1131,6 +1245,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)
1131 1245
1132 cancel_delayed_work_sync(&sc->ath_led_blink_work); 1246 cancel_delayed_work_sync(&sc->ath_led_blink_work);
1133 cancel_delayed_work_sync(&sc->tx_complete_work); 1247 cancel_delayed_work_sync(&sc->tx_complete_work);
1248 cancel_work_sync(&sc->paprd_work);
1134 1249
1135 if (!sc->num_sec_wiphy) { 1250 if (!sc->num_sec_wiphy) {
1136 cancel_delayed_work_sync(&sc->wiphy_work); 1251 cancel_delayed_work_sync(&sc->wiphy_work);
@@ -1850,6 +1965,7 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
1850 ath9k_wiphy_pause_all_forced(sc, aphy); 1965 ath9k_wiphy_pause_all_forced(sc, aphy);
1851 sc->sc_flags |= SC_OP_SCANNING; 1966 sc->sc_flags |= SC_OP_SCANNING;
1852 del_timer_sync(&common->ani.timer); 1967 del_timer_sync(&common->ani.timer);
1968 cancel_work_sync(&sc->paprd_work);
1853 cancel_delayed_work_sync(&sc->tx_complete_work); 1969 cancel_delayed_work_sync(&sc->tx_complete_work);
1854 mutex_unlock(&sc->mutex); 1970 mutex_unlock(&sc->mutex);
1855} 1971}
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 875b8b47fefe..20221b8c04fd 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -1637,12 +1637,13 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
1637 bf->bf_frmlen -= padsize; 1637 bf->bf_frmlen -= padsize;
1638 } 1638 }
1639 1639
1640 if (conf_is_ht(&hw->conf)) { 1640 if (!txctl->paprd && conf_is_ht(&hw->conf)) {
1641 bf->bf_state.bf_type |= BUF_HT; 1641 bf->bf_state.bf_type |= BUF_HT;
1642 if (tx_info->flags & IEEE80211_TX_CTL_LDPC) 1642 if (tx_info->flags & IEEE80211_TX_CTL_LDPC)
1643 use_ldpc = true; 1643 use_ldpc = true;
1644 } 1644 }
1645 1645
1646 bf->bf_state.bfs_paprd = txctl->paprd;
1646 bf->bf_flags = setup_tx_flags(skb, use_ldpc); 1647 bf->bf_flags = setup_tx_flags(skb, use_ldpc);
1647 1648
1648 bf->bf_keytype = get_hw_crypto_keytype(skb); 1649 bf->bf_keytype = get_hw_crypto_keytype(skb);
@@ -1717,6 +1718,9 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
1717 bf->bf_buf_addr, 1718 bf->bf_buf_addr,
1718 txctl->txq->axq_qnum); 1719 txctl->txq->axq_qnum);
1719 1720
1721 if (bf->bf_state.bfs_paprd)
1722 ar9003_hw_set_paprd_txdesc(ah, ds, bf->bf_state.bfs_paprd);
1723
1720 spin_lock_bh(&txctl->txq->axq_lock); 1724 spin_lock_bh(&txctl->txq->axq_lock);
1721 1725
1722 if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR) && 1726 if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR) &&
@@ -1938,8 +1942,14 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
1938 } 1942 }
1939 1943
1940 dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE); 1944 dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE);
1941 ath_tx_complete(sc, skb, bf->aphy, tx_flags); 1945
1942 ath_debug_stat_tx(sc, txq, bf, ts); 1946 if (bf->bf_state.bfs_paprd) {
1947 sc->paprd_txok = txok;
1948 complete(&sc->paprd_complete);
1949 } else {
1950 ath_tx_complete(sc, skb, bf->aphy, tx_flags);
1951 ath_debug_stat_tx(sc, txq, bf, ts);
1952 }
1943 1953
1944 /* 1954 /*
1945 * Return the list of ath_buf of this mpdu to free queue 1955 * Return the list of ath_buf of this mpdu to free queue