diff options
author | Felix Fietkau <nbd@openwrt.org> | 2010-06-12 00:34:01 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-06-14 15:39:32 -0400 |
commit | 9f42c2b667691f6ad29842302c66c864e7eb326c (patch) | |
tree | 10a411c5704e79dae091431b2176764d09951807 | |
parent | 717f6bedcd2d3d39624437e1de7067c90ec931f0 (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.h | 7 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/init.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 116 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/xmit.c | 16 |
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 | ||
428 | void ath_paprd_calibrate(struct work_struct *work); | ||
425 | void ath_ani_calibrate(unsigned long data); | 429 | void 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 | ||
235 | static 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 | |||
255 | void 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 | ||
338 | static void ath_start_ani(struct ath_common *common) | 452 | static 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 |