cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

link.c (14315B)


      1/*
      2 * Copyright (c) 2012 Qualcomm Atheros, Inc.
      3 *
      4 * Permission to use, copy, modify, and/or distribute this software for any
      5 * purpose with or without fee is hereby granted, provided that the above
      6 * copyright notice and this permission notice appear in all copies.
      7 *
      8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     15 */
     16
     17#include "ath9k.h"
     18
     19/*
     20 * TX polling - checks if the TX engine is stuck somewhere
     21 * and issues a chip reset if so.
     22 */
     23static bool ath_tx_complete_check(struct ath_softc *sc)
     24{
     25	struct ath_txq *txq;
     26	int i;
     27
     28	if (sc->tx99_state)
     29		return true;
     30
     31	for (i = 0; i < IEEE80211_NUM_ACS; i++) {
     32		txq = sc->tx.txq_map[i];
     33
     34		ath_txq_lock(sc, txq);
     35		if (txq->axq_depth) {
     36			if (txq->axq_tx_inprogress) {
     37				ath_txq_unlock(sc, txq);
     38				goto reset;
     39			}
     40
     41			txq->axq_tx_inprogress = true;
     42		}
     43		ath_txq_unlock(sc, txq);
     44	}
     45
     46	return true;
     47
     48reset:
     49	ath_dbg(ath9k_hw_common(sc->sc_ah), RESET,
     50		"tx hung, resetting the chip\n");
     51	ath9k_queue_reset(sc, RESET_TYPE_TX_HANG);
     52	return false;
     53
     54}
     55
     56void ath_hw_check_work(struct work_struct *work)
     57{
     58	struct ath_softc *sc = container_of(work, struct ath_softc,
     59					    hw_check_work.work);
     60
     61	if (!ath_hw_check(sc) ||
     62	    !ath_tx_complete_check(sc))
     63		return;
     64
     65	ieee80211_queue_delayed_work(sc->hw, &sc->hw_check_work,
     66				     msecs_to_jiffies(ATH_HW_CHECK_POLL_INT));
     67}
     68
     69/*
     70 * Checks if the BB/MAC is hung.
     71 */
     72bool ath_hw_check(struct ath_softc *sc)
     73{
     74	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
     75	enum ath_reset_type type;
     76	bool is_alive;
     77
     78	ath9k_ps_wakeup(sc);
     79
     80	is_alive = ath9k_hw_check_alive(sc->sc_ah);
     81
     82	if (!is_alive) {
     83		ath_dbg(common, RESET,
     84			"HW hang detected, schedule chip reset\n");
     85		type = RESET_TYPE_MAC_HANG;
     86		ath9k_queue_reset(sc, type);
     87	}
     88
     89	ath9k_ps_restore(sc);
     90
     91	return is_alive;
     92}
     93
     94/*
     95 * PLL-WAR for AR9485/AR9340
     96 */
     97static bool ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum)
     98{
     99	static int count;
    100	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
    101
    102	if (pll_sqsum >= 0x40000) {
    103		count++;
    104		if (count == 3) {
    105			ath_dbg(common, RESET, "PLL WAR, resetting the chip\n");
    106			ath9k_queue_reset(sc, RESET_TYPE_PLL_HANG);
    107			count = 0;
    108			return true;
    109		}
    110	} else {
    111		count = 0;
    112	}
    113
    114	return false;
    115}
    116
    117void ath_hw_pll_work(struct work_struct *work)
    118{
    119	u32 pll_sqsum;
    120	struct ath_softc *sc = container_of(work, struct ath_softc,
    121					    hw_pll_work.work);
    122	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
    123	/*
    124	 * ensure that the PLL WAR is executed only
    125	 * after the STA is associated (or) if the
    126	 * beaconing had started in interfaces that
    127	 * uses beacons.
    128	 */
    129	if (!test_bit(ATH_OP_BEACONS, &common->op_flags))
    130		return;
    131
    132	if (sc->tx99_state)
    133		return;
    134
    135	ath9k_ps_wakeup(sc);
    136	pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah);
    137	ath9k_ps_restore(sc);
    138	if (ath_hw_pll_rx_hang_check(sc, pll_sqsum))
    139		return;
    140
    141	ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work,
    142				     msecs_to_jiffies(ATH_PLL_WORK_INTERVAL));
    143}
    144
    145/*
    146 * PA Pre-distortion.
    147 */
    148static void ath_paprd_activate(struct ath_softc *sc)
    149{
    150	struct ath_hw *ah = sc->sc_ah;
    151	struct ath_common *common = ath9k_hw_common(ah);
    152	struct ath9k_hw_cal_data *caldata = ah->caldata;
    153	int chain;
    154
    155	if (!caldata || !test_bit(PAPRD_DONE, &caldata->cal_flags)) {
    156		ath_dbg(common, CALIBRATE, "Failed to activate PAPRD\n");
    157		return;
    158	}
    159
    160	ar9003_paprd_enable(ah, false);
    161	for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
    162		if (!(ah->txchainmask & BIT(chain)))
    163			continue;
    164
    165		ar9003_paprd_populate_single_table(ah, caldata, chain);
    166	}
    167
    168	ath_dbg(common, CALIBRATE, "Activating PAPRD\n");
    169	ar9003_paprd_enable(ah, true);
    170}
    171
    172static bool ath_paprd_send_frame(struct ath_softc *sc, struct sk_buff *skb, int chain)
    173{
    174	struct ieee80211_hw *hw = sc->hw;
    175	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
    176	struct ath_hw *ah = sc->sc_ah;
    177	struct ath_common *common = ath9k_hw_common(ah);
    178	struct ath_tx_control txctl;
    179	unsigned long time_left;
    180
    181	memset(&txctl, 0, sizeof(txctl));
    182	txctl.txq = sc->tx.txq_map[IEEE80211_AC_BE];
    183
    184	memset(tx_info, 0, sizeof(*tx_info));
    185	tx_info->band = sc->cur_chandef.chan->band;
    186	tx_info->flags |= IEEE80211_TX_CTL_NO_ACK;
    187	tx_info->control.rates[0].idx = 0;
    188	tx_info->control.rates[0].count = 1;
    189	tx_info->control.rates[0].flags = IEEE80211_TX_RC_MCS;
    190	tx_info->control.rates[1].idx = -1;
    191
    192	init_completion(&sc->paprd_complete);
    193	txctl.paprd = BIT(chain);
    194
    195	if (ath_tx_start(hw, skb, &txctl) != 0) {
    196		ath_dbg(common, CALIBRATE, "PAPRD TX failed\n");
    197		dev_kfree_skb_any(skb);
    198		return false;
    199	}
    200
    201	time_left = wait_for_completion_timeout(&sc->paprd_complete,
    202			msecs_to_jiffies(ATH_PAPRD_TIMEOUT));
    203
    204	if (!time_left)
    205		ath_dbg(common, CALIBRATE,
    206			"Timeout waiting for paprd training on TX chain %d\n",
    207			chain);
    208
    209	return !!time_left;
    210}
    211
    212void ath_paprd_calibrate(struct work_struct *work)
    213{
    214	struct ath_softc *sc = container_of(work, struct ath_softc, paprd_work);
    215	struct ieee80211_hw *hw = sc->hw;
    216	struct ath_hw *ah = sc->sc_ah;
    217	struct ieee80211_hdr *hdr;
    218	struct sk_buff *skb = NULL;
    219	struct ath9k_hw_cal_data *caldata = ah->caldata;
    220	struct ath_common *common = ath9k_hw_common(ah);
    221	int ftype;
    222	int chain_ok = 0;
    223	int chain;
    224	int len = 1800;
    225	int ret;
    226
    227	if (!caldata ||
    228	    !test_bit(PAPRD_PACKET_SENT, &caldata->cal_flags) ||
    229	    test_bit(PAPRD_DONE, &caldata->cal_flags)) {
    230		ath_dbg(common, CALIBRATE, "Skipping PAPRD calibration\n");
    231		return;
    232	}
    233
    234	ath9k_ps_wakeup(sc);
    235
    236	if (ar9003_paprd_init_table(ah) < 0)
    237		goto fail_paprd;
    238
    239	skb = alloc_skb(len, GFP_KERNEL);
    240	if (!skb)
    241		goto fail_paprd;
    242
    243	skb_put(skb, len);
    244	memset(skb->data, 0, len);
    245	hdr = (struct ieee80211_hdr *)skb->data;
    246	ftype = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC;
    247	hdr->frame_control = cpu_to_le16(ftype);
    248	hdr->duration_id = cpu_to_le16(10);
    249	memcpy(hdr->addr1, hw->wiphy->perm_addr, ETH_ALEN);
    250	memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN);
    251	memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN);
    252
    253	for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
    254		if (!(ah->txchainmask & BIT(chain)))
    255			continue;
    256
    257		chain_ok = 0;
    258		ar9003_paprd_setup_gain_table(ah, chain);
    259
    260		ath_dbg(common, CALIBRATE,
    261			"Sending PAPRD training frame on chain %d\n", chain);
    262		if (!ath_paprd_send_frame(sc, skb, chain))
    263			goto fail_paprd;
    264
    265		if (!ar9003_paprd_is_done(ah)) {
    266			ath_dbg(common, CALIBRATE,
    267				"PAPRD not yet done on chain %d\n", chain);
    268			break;
    269		}
    270
    271		ret = ar9003_paprd_create_curve(ah, caldata, chain);
    272		if (ret == -EINPROGRESS) {
    273			ath_dbg(common, CALIBRATE,
    274				"PAPRD curve on chain %d needs to be re-trained\n",
    275				chain);
    276			break;
    277		} else if (ret) {
    278			ath_dbg(common, CALIBRATE,
    279				"PAPRD create curve failed on chain %d\n",
    280				chain);
    281			break;
    282		}
    283
    284		chain_ok = 1;
    285	}
    286	kfree_skb(skb);
    287
    288	if (chain_ok) {
    289		set_bit(PAPRD_DONE, &caldata->cal_flags);
    290		ath_paprd_activate(sc);
    291	}
    292
    293fail_paprd:
    294	ath9k_ps_restore(sc);
    295}
    296
    297/*
    298 *  ANI performs periodic noise floor calibration
    299 *  that is used to adjust and optimize the chip performance.  This
    300 *  takes environmental changes (location, temperature) into account.
    301 *  When the task is complete, it reschedules itself depending on the
    302 *  appropriate interval that was calculated.
    303 */
    304void ath_ani_calibrate(struct timer_list *t)
    305{
    306	struct ath_common *common = from_timer(common, t, ani.timer);
    307	struct ath_softc *sc = (struct ath_softc *)common->priv;
    308	struct ath_hw *ah = sc->sc_ah;
    309	bool longcal = false;
    310	bool shortcal = false;
    311	bool aniflag = false;
    312	unsigned int timestamp = jiffies_to_msecs(jiffies);
    313	u32 cal_interval, short_cal_interval, long_cal_interval;
    314	unsigned long flags;
    315
    316	if (ah->caldata && test_bit(NFCAL_INTF, &ah->caldata->cal_flags))
    317		long_cal_interval = ATH_LONG_CALINTERVAL_INT;
    318	else
    319		long_cal_interval = ATH_LONG_CALINTERVAL;
    320
    321	short_cal_interval = (ah->opmode == NL80211_IFTYPE_AP) ?
    322		ATH_AP_SHORT_CALINTERVAL : ATH_STA_SHORT_CALINTERVAL;
    323
    324	/* Only calibrate if awake */
    325	if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) {
    326		if (++ah->ani_skip_count >= ATH_ANI_MAX_SKIP_COUNT) {
    327			spin_lock_irqsave(&sc->sc_pm_lock, flags);
    328			sc->ps_flags |= PS_WAIT_FOR_ANI;
    329			spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
    330		}
    331		goto set_timer;
    332	}
    333	ah->ani_skip_count = 0;
    334	spin_lock_irqsave(&sc->sc_pm_lock, flags);
    335	sc->ps_flags &= ~PS_WAIT_FOR_ANI;
    336	spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
    337
    338	ath9k_ps_wakeup(sc);
    339
    340	/* Long calibration runs independently of short calibration. */
    341	if ((timestamp - common->ani.longcal_timer) >= long_cal_interval) {
    342		longcal = true;
    343		common->ani.longcal_timer = timestamp;
    344	}
    345
    346	/* Short calibration applies only while caldone is false */
    347	if (!common->ani.caldone) {
    348		if ((timestamp - common->ani.shortcal_timer) >= short_cal_interval) {
    349			shortcal = true;
    350			common->ani.shortcal_timer = timestamp;
    351			common->ani.resetcal_timer = timestamp;
    352		}
    353	} else {
    354		if ((timestamp - common->ani.resetcal_timer) >=
    355		    ATH_RESTART_CALINTERVAL) {
    356			common->ani.caldone = ath9k_hw_reset_calvalid(ah);
    357			if (common->ani.caldone)
    358				common->ani.resetcal_timer = timestamp;
    359		}
    360	}
    361
    362	/* Verify whether we must check ANI */
    363	if ((timestamp - common->ani.checkani_timer) >= ah->config.ani_poll_interval) {
    364		aniflag = true;
    365		common->ani.checkani_timer = timestamp;
    366	}
    367
    368	/* Call ANI routine if necessary */
    369	if (aniflag) {
    370		spin_lock_irqsave(&common->cc_lock, flags);
    371		ath9k_hw_ani_monitor(ah, ah->curchan);
    372		ath_update_survey_stats(sc);
    373		spin_unlock_irqrestore(&common->cc_lock, flags);
    374	}
    375
    376	/* Perform calibration if necessary */
    377	if (longcal || shortcal) {
    378		int ret = ath9k_hw_calibrate(ah, ah->curchan, ah->rxchainmask,
    379					     longcal);
    380		if (ret < 0) {
    381			common->ani.caldone = 0;
    382			ath9k_queue_reset(sc, RESET_TYPE_CALIBRATION);
    383			return;
    384		}
    385
    386		common->ani.caldone = ret;
    387	}
    388
    389	ath_dbg(common, ANI,
    390		"Calibration @%lu finished: %s %s %s, caldone: %s\n",
    391		jiffies,
    392		longcal ? "long" : "", shortcal ? "short" : "",
    393		aniflag ? "ani" : "", common->ani.caldone ? "true" : "false");
    394
    395	ath9k_ps_restore(sc);
    396
    397set_timer:
    398	/*
    399	* Set timer interval based on previous results.
    400	* The interval must be the shortest necessary to satisfy ANI,
    401	* short calibration and long calibration.
    402	*/
    403	cal_interval = ATH_LONG_CALINTERVAL;
    404	cal_interval = min(cal_interval, (u32)ah->config.ani_poll_interval);
    405	if (!common->ani.caldone)
    406		cal_interval = min(cal_interval, (u32)short_cal_interval);
    407
    408	mod_timer(&common->ani.timer, jiffies + msecs_to_jiffies(cal_interval));
    409
    410	if (ar9003_is_paprd_enabled(ah) && ah->caldata) {
    411		if (!test_bit(PAPRD_DONE, &ah->caldata->cal_flags)) {
    412			ieee80211_queue_work(sc->hw, &sc->paprd_work);
    413		} else if (!ah->paprd_table_write_done) {
    414			ath9k_ps_wakeup(sc);
    415			ath_paprd_activate(sc);
    416			ath9k_ps_restore(sc);
    417		}
    418	}
    419}
    420
    421void ath_start_ani(struct ath_softc *sc)
    422{
    423	struct ath_hw *ah = sc->sc_ah;
    424	struct ath_common *common = ath9k_hw_common(ah);
    425	unsigned long timestamp = jiffies_to_msecs(jiffies);
    426
    427	if (common->disable_ani ||
    428	    !test_bit(ATH_OP_ANI_RUN, &common->op_flags) ||
    429	    sc->cur_chan->offchannel)
    430		return;
    431
    432	common->ani.longcal_timer = timestamp;
    433	common->ani.shortcal_timer = timestamp;
    434	common->ani.checkani_timer = timestamp;
    435
    436	ath_dbg(common, ANI, "Starting ANI\n");
    437	mod_timer(&common->ani.timer,
    438		  jiffies + msecs_to_jiffies((u32)ah->config.ani_poll_interval));
    439}
    440
    441void ath_stop_ani(struct ath_softc *sc)
    442{
    443	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
    444
    445	ath_dbg(common, ANI, "Stopping ANI\n");
    446	del_timer_sync(&common->ani.timer);
    447}
    448
    449void ath_check_ani(struct ath_softc *sc)
    450{
    451	struct ath_hw *ah = sc->sc_ah;
    452	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
    453	struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon;
    454
    455	/*
    456	 * Check for the various conditions in which ANI has to
    457	 * be stopped.
    458	 */
    459	if (ah->opmode == NL80211_IFTYPE_ADHOC) {
    460		if (!cur_conf->enable_beacon)
    461			goto stop_ani;
    462	} else if (ah->opmode == NL80211_IFTYPE_AP) {
    463		if (!cur_conf->enable_beacon) {
    464			/*
    465			 * Disable ANI only when there are no
    466			 * associated stations.
    467			 */
    468			if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags))
    469				goto stop_ani;
    470		}
    471	} else if (ah->opmode == NL80211_IFTYPE_STATION) {
    472		if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags))
    473			goto stop_ani;
    474	}
    475
    476	if (!test_bit(ATH_OP_ANI_RUN, &common->op_flags)) {
    477		set_bit(ATH_OP_ANI_RUN, &common->op_flags);
    478		ath_start_ani(sc);
    479	}
    480
    481	return;
    482
    483stop_ani:
    484	clear_bit(ATH_OP_ANI_RUN, &common->op_flags);
    485	ath_stop_ani(sc);
    486}
    487
    488void ath_update_survey_nf(struct ath_softc *sc, int channel)
    489{
    490	struct ath_hw *ah = sc->sc_ah;
    491	struct ath9k_channel *chan = &ah->channels[channel];
    492	struct survey_info *survey = &sc->survey[channel];
    493
    494	if (chan->noisefloor) {
    495		survey->filled |= SURVEY_INFO_NOISE_DBM;
    496		survey->noise = ath9k_hw_getchan_noise(ah, chan,
    497						       chan->noisefloor);
    498	}
    499}
    500
    501/*
    502 * Updates the survey statistics and returns the busy time since last
    503 * update in %, if the measurement duration was long enough for the
    504 * result to be useful, -1 otherwise.
    505 */
    506int ath_update_survey_stats(struct ath_softc *sc)
    507{
    508	struct ath_hw *ah = sc->sc_ah;
    509	struct ath_common *common = ath9k_hw_common(ah);
    510	int pos = ah->curchan - &ah->channels[0];
    511	struct survey_info *survey = &sc->survey[pos];
    512	struct ath_cycle_counters *cc = &common->cc_survey;
    513	unsigned int div = common->clockrate * 1000;
    514	int ret = 0;
    515
    516	if (!ah->curchan)
    517		return -1;
    518
    519	if (ah->power_mode == ATH9K_PM_AWAKE)
    520		ath_hw_cycle_counters_update(common);
    521
    522	if (cc->cycles > 0) {
    523		survey->filled |= SURVEY_INFO_TIME |
    524			SURVEY_INFO_TIME_BUSY |
    525			SURVEY_INFO_TIME_RX |
    526			SURVEY_INFO_TIME_TX;
    527		survey->time += cc->cycles / div;
    528		survey->time_busy += cc->rx_busy / div;
    529		survey->time_rx += cc->rx_frame / div;
    530		survey->time_tx += cc->tx_frame / div;
    531	}
    532
    533	if (cc->cycles < div)
    534		return -1;
    535
    536	if (cc->cycles > 0)
    537		ret = cc->rx_busy * 100 / cc->cycles;
    538
    539	memset(cc, 0, sizeof(*cc));
    540
    541	ath_update_survey_nf(sc, pos);
    542
    543	return ret;
    544}