Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9f42c2b6 authored by Felix Fietkau's avatar Felix Fietkau Committed by John W. Linville
Browse files

ath9k: implement PA predistortion support

parent 717f6bed
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -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_* */
+1 −0
Original line number Diff line number Diff line
@@ -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);
+116 −0
Original line number Diff line number Diff line
@@ -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);
@@ -1850,6 +1965,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);
}
+13 −3
Original line number Diff line number Diff line
@@ -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);

	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