From: "Luis R. Rodriguez" <lrodriguez@atheros.com>
To: linville@tuxdriver.com
Cc: linux-wireless@vger.kernel.org, Felix Fietkau <nbd@openwrt.org>,
"Luis R. Rodriguez" <lrodriguez@atheros.com>
Subject: [PATCH 23/24] ath9k: implement PA predistortion support
Date: Sat, 12 Jun 2010 00:34:01 -0400 [thread overview]
Message-ID: <1276317242-15540-24-git-send-email-lrodriguez@atheros.com> (raw)
In-Reply-To: <1276317242-15540-1-git-send-email-lrodriguez@atheros.com>
From: Felix Fietkau <nbd@openwrt.org>
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
drivers/net/wireless/ath/ath9k/ath9k.h | 7 ++
drivers/net/wireless/ath/ath9k/init.c | 1 +
drivers/net/wireless/ath/ath9k/main.c | 116 ++++++++++++++++++++++++++++++++
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 1a19aea..8d163ae 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -20,6 +20,7 @@
#include <linux/etherdevice.h>
#include <linux/device.h>
#include <linux/leds.h>
+#include <linux/completion.h>
#include "debug.h"
#include "common.h"
@@ -224,6 +225,7 @@ struct ath_buf_state {
int bfs_tidno;
int bfs_retries;
u8 bf_type;
+ u8 bfs_paprd;
u32 bfs_keyix;
enum ath9k_key_type bfs_keytype;
};
@@ -280,6 +282,7 @@ struct ath_tx_control {
struct ath_txq *txq;
int if_id;
enum ath9k_internal_frame_type frame_type;
+ u8 paprd;
};
#define ATH_TX_ERROR 0x01
@@ -422,6 +425,7 @@ int ath_beaconq_config(struct ath_softc *sc);
#define ATH_LONG_CALINTERVAL 30000 /* 30 seconds */
#define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */
+void ath_paprd_calibrate(struct work_struct *work);
void ath_ani_calibrate(unsigned long data);
/**********/
@@ -553,6 +557,9 @@ struct ath_softc {
spinlock_t sc_serial_rw;
spinlock_t sc_pm_lock;
struct mutex mutex;
+ struct work_struct paprd_work;
+ struct completion paprd_complete;
+ int paprd_txok;
u32 intrstatus;
u32 sc_flags; /* SC_OP_* */
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 4e07830..e1fa268 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,
goto error_world;
}
+ INIT_WORK(&sc->paprd_work, ath_paprd_calibrate);
INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work);
INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work);
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 52ed4c8..7b2f4a7 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,
return r;
}
+static void ath_paprd_activate(struct ath_softc *sc)
+{
+ struct ath_hw *ah = sc->sc_ah;
+ int chain;
+
+ if (!ah->curchan->paprd_done)
+ return;
+
+ ath9k_ps_wakeup(sc);
+ for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
+ if (!(ah->caps.tx_chainmask & BIT(chain)))
+ continue;
+
+ ar9003_paprd_populate_single_table(ah, ah->curchan, chain);
+ }
+
+ ar9003_paprd_enable(ah, true);
+ ath9k_ps_restore(sc);
+}
+
+void ath_paprd_calibrate(struct work_struct *work)
+{
+ struct ath_softc *sc = container_of(work, struct ath_softc, paprd_work);
+ struct ieee80211_hw *hw = sc->hw;
+ struct ath_hw *ah = sc->sc_ah;
+ struct ieee80211_hdr *hdr;
+ struct sk_buff *skb = NULL;
+ struct ieee80211_tx_info *tx_info;
+ int band = hw->conf.channel->band;
+ struct ieee80211_supported_band *sband = &sc->sbands[band];
+ struct ath_tx_control txctl;
+ int qnum, ftype;
+ int chain_ok = 0;
+ int chain;
+ int len = 1800;
+ int time_left;
+ int i;
+
+ ath9k_ps_wakeup(sc);
+ skb = alloc_skb(len, GFP_KERNEL);
+ if (!skb)
+ return;
+
+ tx_info = IEEE80211_SKB_CB(skb);
+
+ skb_put(skb, len);
+ memset(skb->data, 0, len);
+ hdr = (struct ieee80211_hdr *)skb->data;
+ ftype = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC;
+ hdr->frame_control = cpu_to_le16(ftype);
+ hdr->duration_id = 10;
+ memcpy(hdr->addr1, hw->wiphy->perm_addr, ETH_ALEN);
+ memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN);
+ memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN);
+
+ memset(&txctl, 0, sizeof(txctl));
+ qnum = sc->tx.hwq_map[WME_AC_BE];
+ txctl.txq = &sc->tx.txq[qnum];
+
+ ar9003_paprd_init_table(ah);
+ for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
+ if (!(ah->caps.tx_chainmask & BIT(chain)))
+ continue;
+
+ chain_ok = 0;
+ memset(tx_info, 0, sizeof(*tx_info));
+ tx_info->band = band;
+
+ for (i = 0; i < 4; i++) {
+ tx_info->control.rates[i].idx = sband->n_bitrates - 1;
+ tx_info->control.rates[i].count = 6;
+ }
+
+ init_completion(&sc->paprd_complete);
+ ar9003_paprd_setup_gain_table(ah, chain);
+ txctl.paprd = BIT(chain);
+ if (ath_tx_start(hw, skb, &txctl) != 0)
+ break;
+
+ time_left = wait_for_completion_timeout(&sc->paprd_complete,
+ 100);
+ if (!time_left) {
+ ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
+ "Timeout waiting for paprd training on "
+ "TX chain %d\n",
+ chain);
+ break;
+ }
+
+ if (!ar9003_paprd_is_done(ah))
+ break;
+
+ if (ar9003_paprd_create_curve(ah, ah->curchan, chain) != 0)
+ break;
+
+ chain_ok = 1;
+ }
+ kfree_skb(skb);
+
+ if (chain_ok) {
+ ah->curchan->paprd_done = true;
+ ath_paprd_activate(sc);
+ }
+
+ ath9k_ps_restore(sc);
+}
+
/*
* This routine performs the periodic noise floor calibration function
* that is used to adjust and optimize the chip performance. This
@@ -333,6 +440,13 @@ set_timer:
cal_interval = min(cal_interval, (u32)short_cal_interval);
mod_timer(&common->ani.timer, jiffies + msecs_to_jiffies(cal_interval));
+ if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_PAPRD) &&
+ !(sc->sc_flags & SC_OP_SCANNING)) {
+ if (!sc->sc_ah->curchan->paprd_done)
+ ieee80211_queue_work(sc->hw, &sc->paprd_work);
+ else
+ ath_paprd_activate(sc);
+ }
}
static void ath_start_ani(struct ath_common *common)
@@ -1131,6 +1245,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)
cancel_delayed_work_sync(&sc->ath_led_blink_work);
cancel_delayed_work_sync(&sc->tx_complete_work);
+ cancel_work_sync(&sc->paprd_work);
if (!sc->num_sec_wiphy) {
cancel_delayed_work_sync(&sc->wiphy_work);
@@ -1846,6 +1961,7 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
ath9k_wiphy_pause_all_forced(sc, aphy);
sc->sc_flags |= SC_OP_SCANNING;
del_timer_sync(&common->ani.timer);
+ cancel_work_sync(&sc->paprd_work);
cancel_delayed_work_sync(&sc->tx_complete_work);
mutex_unlock(&sc->mutex);
}
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 875b8b4..20221b8 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,
bf->bf_frmlen -= padsize;
}
- if (conf_is_ht(&hw->conf)) {
+ if (!txctl->paprd && conf_is_ht(&hw->conf)) {
bf->bf_state.bf_type |= BUF_HT;
if (tx_info->flags & IEEE80211_TX_CTL_LDPC)
use_ldpc = true;
}
+ bf->bf_state.bfs_paprd = txctl->paprd;
bf->bf_flags = setup_tx_flags(skb, use_ldpc);
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,
bf->bf_buf_addr,
txctl->txq->axq_qnum);
+ if (bf->bf_state.bfs_paprd)
+ ar9003_hw_set_paprd_txdesc(ah, ds, bf->bf_state.bfs_paprd);
+
spin_lock_bh(&txctl->txq->axq_lock);
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,
}
dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE);
- ath_tx_complete(sc, skb, bf->aphy, tx_flags);
- ath_debug_stat_tx(sc, txq, bf, ts);
+
+ if (bf->bf_state.bfs_paprd) {
+ sc->paprd_txok = txok;
+ complete(&sc->paprd_complete);
+ } else {
+ ath_tx_complete(sc, skb, bf->aphy, tx_flags);
+ ath_debug_stat_tx(sc, txq, bf, ts);
+ }
/*
* Return the list of ath_buf of this mpdu to free queue
--
1.6.3.3
next prev parent reply other threads:[~2010-06-12 4:34 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-06-12 4:33 [PATCH 00/24] ath9k: new ANI, PAPrD and few fixes and cleanups Luis R. Rodriguez
2010-06-12 4:33 ` [PATCH 01/24] ath9k_hw: move clock definitions from hw.c to hw.h Luis R. Rodriguez
2010-06-12 4:33 ` [PATCH 02/24] ath9k_hw: fix clock rate calculations for ANI Luis R. Rodriguez
2010-06-12 4:33 ` [PATCH 03/24] ath9k_hw: clear MIB interrupt causes when skipping ANI adjustments Luis R. Rodriguez
2010-06-12 4:33 ` [PATCH 04/24] ath9k_hw: allow for spliting up ANI operations by family Luis R. Rodriguez
2010-06-12 4:33 ` [PATCH 05/24] ath9k_hw: add register definitions for the new ANI Luis R. Rodriguez
2010-06-12 4:33 ` [PATCH 06/24] ath9k_hw: inform ANI calibration when scanning Luis R. Rodriguez
2010-06-12 4:33 ` [PATCH 07/24] ath9k: add new ANI implementation for AR9003 Luis R. Rodriguez
2010-06-12 4:33 ` [PATCH 08/24] ath9k_hw: enable ANI " Luis R. Rodriguez
2010-06-12 4:33 ` [PATCH 09/24] ath9k_hw: reduce delay on programming INI on AR9003 Luis R. Rodriguez
2010-06-12 4:33 ` [PATCH 10/24] ath9k_hw: update 5 GHz tx gain tables for femless and high power PA Luis R. Rodriguez
2010-06-12 4:33 ` [PATCH 11/24] ath9k: fix mac80211 queue lookup for waking up queues Luis R. Rodriguez
2010-06-12 4:33 ` [PATCH 12/24] ath9k_htc: use common WMM AC definitions instead of ath9k ones Luis R. Rodriguez
2010-06-12 4:33 ` [PATCH 13/24] ath9k: remove duplicate WMM AC definitions Luis R. Rodriguez
2010-06-12 4:33 ` [PATCH 14/24] ath9k: remove declarations of some nonexistant functions Luis R. Rodriguez
2010-06-12 4:33 ` [PATCH 15/24] ath9k: make ath_get_hal_qnum static Luis R. Rodriguez
2010-06-12 4:33 ` [PATCH 16/24] ath9k: fix extending the rx timestamp with the hardware TSF Luis R. Rodriguez
2010-06-12 4:33 ` [PATCH 17/24] ath9k: fix queue stopping threshold Luis R. Rodriguez
2010-06-12 4:33 ` [PATCH 18/24] ath9k: add a debugfs entry for ignoring CCA on the extension channel in HT40 Luis R. Rodriguez
2010-06-12 4:33 ` [PATCH 19/24] ath9k_hw: remove a useless function for setting the mac address Luis R. Rodriguez
2010-06-12 4:33 ` [PATCH 20/24] ath9k_hw: add register definitions related to PA predistortion Luis R. Rodriguez
2010-06-12 4:33 ` [PATCH 21/24] ath9k_hw: add support for parsing PA predistortion related EEPROM fields Luis R. Rodriguez
2010-06-12 4:34 ` [PATCH 22/24] ath9k_hw: add functions for controlling PA predistortion calibration Luis R. Rodriguez
2010-06-12 4:34 ` Luis R. Rodriguez [this message]
2010-06-12 4:34 ` [PATCH 24/24] ath9k: enable AR9003 PCI IDs Luis R. Rodriguez
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1276317242-15540-24-git-send-email-lrodriguez@atheros.com \
--to=lrodriguez@atheros.com \
--cc=linux-wireless@vger.kernel.org \
--cc=linville@tuxdriver.com \
--cc=nbd@openwrt.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox