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

Commit 194828a2 authored by Nick Kossifidis's avatar Nick Kossifidis Committed by John W. Linville
Browse files

ath5k: Misc fixes/cleanups



*Handle MIB interrupts and pass low level stats to mac80211
*Add Power On Self Test function
*Update to match recent dumps
*Let RF2425 attach so we can further test it
*Remove unused files regdom.c and regdom.h

base.c
Changes-licensed-under: 3-clause-BSD

rest
Changes-licensed-under: ISC

Signed-off-by: default avatarNick Kossifidis <mickflemm@gmail.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 136bfc79
Loading
Loading
Loading
Loading
+1 −9
Original line number Original line Diff line number Diff line
@@ -450,14 +450,6 @@ struct ath5k_rx_status {
#define AR5K_RXKEYIX_INVALID	((u8) - 1)
#define AR5K_RXKEYIX_INVALID	((u8) - 1)
#define AR5K_TXKEYIX_INVALID	((u32) - 1)
#define AR5K_TXKEYIX_INVALID	((u32) - 1)


struct ath5k_mib_stats {
	u32	ackrcv_bad;
	u32	rts_bad;
	u32	rts_good;
	u32	fcs_bad;
	u32	beacons;
};



/**************************\
/**************************\
 BEACON TIMERS DEFINITIONS
 BEACON TIMERS DEFINITIONS
@@ -1070,6 +1062,7 @@ extern int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase);
extern bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah);
extern bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah);
extern int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask);
extern int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask);
extern enum ath5k_int ath5k_hw_set_intr(struct ath5k_hw *ah, enum ath5k_int new_mask);
extern enum ath5k_int ath5k_hw_set_intr(struct ath5k_hw *ah, enum ath5k_int new_mask);
extern void ath5k_hw_update_mib_counters(struct ath5k_hw *ah, struct ieee80211_low_level_stats *stats);
/* EEPROM access functions */
/* EEPROM access functions */
extern int ath5k_hw_set_regdomain(struct ath5k_hw *ah, u16 regdomain);
extern int ath5k_hw_set_regdomain(struct ath5k_hw *ah, u16 regdomain);
/* Protocol Control Unit Functions */
/* Protocol Control Unit Functions */
@@ -1098,7 +1091,6 @@ extern int ath5k_hw_set_beacon_timers(struct ath5k_hw *ah, const struct ath5k_be
extern void ath5k_hw_reset_beacon(struct ath5k_hw *ah);
extern void ath5k_hw_reset_beacon(struct ath5k_hw *ah);
extern int ath5k_hw_beaconq_finish(struct ath5k_hw *ah, unsigned long phys_addr);
extern int ath5k_hw_beaconq_finish(struct ath5k_hw *ah, unsigned long phys_addr);
#endif
#endif
extern void ath5k_hw_update_mib_counters(struct ath5k_hw *ah, struct ath5k_mib_stats *statistics);
/* ACK bit rate */
/* ACK bit rate */
void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high);
void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high);
/* ACK/CTS Timeouts */
/* ACK/CTS Timeouts */
+11 −2
Original line number Original line Diff line number Diff line
@@ -2342,7 +2342,8 @@ ath5k_init(struct ath5k_softc *sc)
	 * Enable interrupts.
	 * Enable interrupts.
	 */
	 */
	sc->imask = AR5K_INT_RX | AR5K_INT_TX | AR5K_INT_RXEOL |
	sc->imask = AR5K_INT_RX | AR5K_INT_TX | AR5K_INT_RXEOL |
		AR5K_INT_RXORN | AR5K_INT_FATAL | AR5K_INT_GLOBAL;
		AR5K_INT_RXORN | AR5K_INT_FATAL | AR5K_INT_GLOBAL |
		AR5K_INT_MIB;


	ath5k_hw_set_intr(sc->ah, sc->imask);
	ath5k_hw_set_intr(sc->ah, sc->imask);
	/* Set ack to be sent at low bit-rates */
	/* Set ack to be sent at low bit-rates */
@@ -2522,7 +2523,11 @@ ath5k_intr(int irq, void *dev_id)
			if (status & AR5K_INT_BMISS) {
			if (status & AR5K_INT_BMISS) {
			}
			}
			if (status & AR5K_INT_MIB) {
			if (status & AR5K_INT_MIB) {
				/* TODO */
				/*
				 * These stats are also used for ANI i think
				 * so how about updating them more often ?
				 */
				ath5k_hw_update_mib_counters(ah, &sc->ll_stats);
			}
			}
		}
		}
	} while (ath5k_hw_is_intr_pending(ah) && counter-- > 0);
	} while (ath5k_hw_is_intr_pending(ah) && counter-- > 0);
@@ -3015,6 +3020,10 @@ ath5k_get_stats(struct ieee80211_hw *hw,
		struct ieee80211_low_level_stats *stats)
		struct ieee80211_low_level_stats *stats)
{
{
	struct ath5k_softc *sc = hw->priv;
	struct ath5k_softc *sc = hw->priv;
	struct ath5k_hw *ah = sc->ah;

	/* Force update */
	ath5k_hw_update_mib_counters(ah, &sc->ll_stats);


	memcpy(stats, &sc->ll_stats, sizeof(sc->ll_stats));
	memcpy(stats, &sc->ll_stats, sizeof(sc->ll_stats));


+127 −11
Original line number Original line Diff line number Diff line
@@ -119,12 +119,70 @@ int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val,
	Attach/Detach Functions
	Attach/Detach Functions
\***************************************/
\***************************************/


/*
 * Power On Self Test helper function
 */
static int ath5k_hw_post(struct ath5k_hw *ah)
{

	int i, c;
	u16 cur_reg;
	u16 regs[2] = {AR5K_STA_ID0, AR5K_PHY(8)};
	u32 var_pattern;
	u32 static_pattern[4] = {
		0x55555555,	0xaaaaaaaa,
		0x66666666,	0x99999999
	};
	u32 init_val;
	u32 cur_val;

	for (c = 0; c < 2; c++) {

		cur_reg = regs[c];
		init_val = ath5k_hw_reg_read(ah, cur_reg);

		for (i = 0; i < 256; i++) {
			var_pattern = i << 16 | i;
			ath5k_hw_reg_write(ah, var_pattern, cur_reg);
			cur_val = ath5k_hw_reg_read(ah, cur_reg);

			if (cur_val != var_pattern) {
				ATH5K_ERR(ah->ah_sc, "POST Failed !!!\n");
				return -EAGAIN;
			}

			/* Found on ndiswrapper dumps */
			var_pattern = 0x0039080f;
			ath5k_hw_reg_write(ah, var_pattern, cur_reg);
		}

		for (i = 0; i < 4; i++) {
			var_pattern = static_pattern[i];
			ath5k_hw_reg_write(ah, var_pattern, cur_reg);
			cur_val = ath5k_hw_reg_read(ah, cur_reg);

			if (cur_val != var_pattern) {
				ATH5K_ERR(ah->ah_sc, "POST Failed !!!\n");
				return -EAGAIN;
			}

			/* Found on ndiswrapper dumps */
			var_pattern = 0x003b080f;
			ath5k_hw_reg_write(ah, var_pattern, cur_reg);
		}
	}

	return 0;

}

/*
/*
 * Check if the device is supported and initialize the needed structs
 * Check if the device is supported and initialize the needed structs
 */
 */
struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
{
{
	struct ath5k_hw *ah;
	struct ath5k_hw *ah;
	struct pci_dev *pdev = sc->pdev;
	u8 mac[ETH_ALEN];
	u8 mac[ETH_ALEN];
	int ret;
	int ret;
	u32 srev;
	u32 srev;
@@ -204,10 +262,13 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
				CHANNEL_2GHZ);
				CHANNEL_2GHZ);


	/* Return on unsuported chips (unsupported eeprom etc) */
	/* Return on unsuported chips (unsupported eeprom etc) */
	if (srev >= AR5K_SREV_VER_AR5416) {
	if ((srev >= AR5K_SREV_VER_AR5416) &&
	(srev < AR5K_SREV_VER_AR2425)) {
		ATH5K_ERR(sc, "Device not yet supported.\n");
		ATH5K_ERR(sc, "Device not yet supported.\n");
		ret = -ENODEV;
		ret = -ENODEV;
		goto err_free;
		goto err_free;
	} else if (srev == AR5K_SREV_VER_AR2425) {
		ATH5K_WARN(sc, "Support for RF2425 is under development.\n");
	}
	}


	/* Identify single chip solutions */
	/* Identify single chip solutions */
@@ -251,14 +312,57 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
			ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5424;
			ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5424;
		else
		else
			ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112A;
			ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112A;

	/*
	} else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5133) {
	 * Register returns 0x4 for radio revision
	 * so ath5k_hw_radio_revision doesn't parse the value
	 * correctly. For now we are based on mac's srev to
	 * identify RF2425 radio.
	 */
	} else if (srev == AR5K_SREV_VER_AR2425) {
		ah->ah_radio = AR5K_RF2425;
		ah->ah_radio = AR5K_RF2425;
		ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112;
		ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112;
	}
	}


	ah->ah_phy = AR5K_PHY(0);
	ah->ah_phy = AR5K_PHY(0);


	/*
	 * Identify AR5212-based PCI-E cards
	 * And write some initial settings.
	 *
	 * (doing a "strings" on ndis driver
	 * -ar5211.sys- reveals the following
	 * pci-e related functions:
	 *
	 * pcieClockReq
	 * pcieRxErrNotify
	 * pcieL1SKPEnable
	 * pcieAspm
	 * pcieDisableAspmOnRfWake
	 * pciePowerSaveEnable
	 *
	 * I guess these point to ClockReq but
	 * i'm not sure.)
	 */
	if ((ah->ah_version == AR5K_AR5212) && (pdev->is_pcie)) {
		ath5k_hw_reg_write(ah, 0x9248fc00, 0x4080);
		ath5k_hw_reg_write(ah, 0x24924924, 0x4080);
		ath5k_hw_reg_write(ah, 0x28000039, 0x4080);
		ath5k_hw_reg_write(ah, 0x53160824, 0x4080);
		ath5k_hw_reg_write(ah, 0xe5980579, 0x4080);
		ath5k_hw_reg_write(ah, 0x001defff, 0x4080);
		ath5k_hw_reg_write(ah, 0x1aaabe40, 0x4080);
		ath5k_hw_reg_write(ah, 0xbe105554, 0x4080);
		ath5k_hw_reg_write(ah, 0x000e3007, 0x4080);
		ath5k_hw_reg_write(ah, 0x00000000, 0x4084);
	}

	/*
	 * POST
	 */
	ret = ath5k_hw_post(ah);
	if (ret)
		goto err_free;

	/*
	/*
	 * Get card capabilities, values, ...
	 * Get card capabilities, values, ...
	 */
	 */
@@ -2851,15 +2955,19 @@ int ath5k_hw_beaconq_finish(struct ath5k_hw *ah, unsigned long phys_addr)
 * Update mib counters (statistics)
 * Update mib counters (statistics)
 */
 */
void ath5k_hw_update_mib_counters(struct ath5k_hw *ah,
void ath5k_hw_update_mib_counters(struct ath5k_hw *ah,
		struct ath5k_mib_stats *statistics)
		struct ieee80211_low_level_stats  *stats)
{
{
	ATH5K_TRACE(ah->ah_sc);
	ATH5K_TRACE(ah->ah_sc);

	/* Read-And-Clear */
	/* Read-And-Clear */
	statistics->ackrcv_bad += ath5k_hw_reg_read(ah, AR5K_ACK_FAIL);
	stats->dot11ACKFailureCount += ath5k_hw_reg_read(ah, AR5K_ACK_FAIL);
	statistics->rts_bad += ath5k_hw_reg_read(ah, AR5K_RTS_FAIL);
	stats->dot11RTSFailureCount += ath5k_hw_reg_read(ah, AR5K_RTS_FAIL);
	statistics->rts_good += ath5k_hw_reg_read(ah, AR5K_RTS_OK);
	stats->dot11RTSSuccessCount += ath5k_hw_reg_read(ah, AR5K_RTS_OK);
	statistics->fcs_bad += ath5k_hw_reg_read(ah, AR5K_FCS_FAIL);
	stats->dot11FCSErrorCount += ath5k_hw_reg_read(ah, AR5K_FCS_FAIL);
	statistics->beacons += ath5k_hw_reg_read(ah, AR5K_BEACON_CNT);

	/* XXX: Should we use this to track beacon count ?
	 * -we read it anyway to clear the register */
	ath5k_hw_reg_read(ah, AR5K_BEACON_CNT);


	/* Reset profile count registers on 5212*/
	/* Reset profile count registers on 5212*/
	if (ah->ah_version == AR5K_AR5212) {
	if (ah->ah_version == AR5K_AR5212) {
@@ -2960,8 +3068,16 @@ int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry)
	for (i = 0; i < AR5K_KEYCACHE_SIZE; i++)
	for (i = 0; i < AR5K_KEYCACHE_SIZE; i++)
		ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i));
		ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i));


	/* Set NULL encryption on non-5210*/
	/*
	if (ah->ah_version != AR5K_AR5210)
	 * Set NULL encryption on AR5212+
	 *
	 * Note: AR5K_KEYTABLE_TYPE -> AR5K_KEYTABLE_OFF(entry, 5)
	 *       AR5K_KEYTABLE_TYPE_NULL -> 0x00000007
	 *
	 * Note2: Windows driver (ndiswrapper) sets this to
	 *        0x00000714 instead of 0x00000007
	 */
	if (ah->ah_version > AR5K_AR5211)
		ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
		ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
				AR5K_KEYTABLE_TYPE(entry));
				AR5K_KEYTABLE_TYPE(entry));


+0 −121
Original line number Original line Diff line number Diff line
/*
 * Copyright (c) 2004, 2005 Reyk Floeter <reyk@vantronix.net>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * Basic regulation domain extensions for the IEEE 802.11 stack
 */

#include <linux/kernel.h>
#include <linux/string.h>

#include "regdom.h"

static const struct ath5k_regdommap {
	enum ath5k_regdom dmn;
	enum ath5k_regdom dmn5;
	enum ath5k_regdom dmn2;
} r_map[] = {
	{ DMN_DEFAULT,		DMN_DEBUG,	DMN_DEBUG },
	{ DMN_NULL_WORLD,	DMN_NULL,	DMN_WORLD },
	{ DMN_NULL_ETSIB,	DMN_NULL,	DMN_ETSIB },
	{ DMN_NULL_ETSIC,	DMN_NULL,	DMN_ETSIC },
	{ DMN_FCC1_FCCA,	DMN_FCC1,	DMN_FCCA },
	{ DMN_FCC1_WORLD,	DMN_FCC1,	DMN_WORLD },
	{ DMN_FCC2_FCCA,	DMN_FCC2,	DMN_FCCA },
	{ DMN_FCC2_WORLD,	DMN_FCC2,	DMN_WORLD },
	{ DMN_FCC2_ETSIC,	DMN_FCC2,	DMN_ETSIC },
	{ DMN_FRANCE_NULL,	DMN_ETSI3,	DMN_ETSI3 },
	{ DMN_FCC3_FCCA,	DMN_FCC3,	DMN_WORLD },
	{ DMN_ETSI1_WORLD,	DMN_ETSI1,	DMN_WORLD },
	{ DMN_ETSI3_ETSIA,	DMN_ETSI3,	DMN_WORLD },
	{ DMN_ETSI2_WORLD,	DMN_ETSI2,	DMN_WORLD },
	{ DMN_ETSI3_WORLD,	DMN_ETSI3,	DMN_WORLD },
	{ DMN_ETSI4_WORLD,	DMN_ETSI4,	DMN_WORLD },
	{ DMN_ETSI4_ETSIC,	DMN_ETSI4,	DMN_ETSIC },
	{ DMN_ETSI5_WORLD,	DMN_ETSI5,	DMN_WORLD },
	{ DMN_ETSI6_WORLD,	DMN_ETSI6,	DMN_WORLD },
	{ DMN_ETSI_NULL,	DMN_ETSI1,	DMN_ETSI1 },
	{ DMN_MKK1_MKKA,	DMN_MKK1,	DMN_MKKA },
	{ DMN_MKK1_MKKB,	DMN_MKK1,	DMN_MKKA },
	{ DMN_APL4_WORLD,	DMN_APL4,	DMN_WORLD },
	{ DMN_MKK2_MKKA,	DMN_MKK2,	DMN_MKKA },
	{ DMN_APL_NULL,		DMN_APL1,	DMN_NULL },
	{ DMN_APL2_WORLD,	DMN_APL2,	DMN_WORLD },
	{ DMN_APL2_APLC,	DMN_APL2,	DMN_WORLD },
	{ DMN_APL3_WORLD,	DMN_APL3,	DMN_WORLD },
	{ DMN_MKK1_FCCA,	DMN_MKK1,	DMN_FCCA },
	{ DMN_APL2_APLD,	DMN_APL2,	DMN_APLD },
	{ DMN_MKK1_MKKA1,	DMN_MKK1,	DMN_MKKA },
	{ DMN_MKK1_MKKA2,	DMN_MKK1,	DMN_MKKA },
	{ DMN_APL1_WORLD,	DMN_APL1,	DMN_WORLD },
	{ DMN_APL1_FCCA,	DMN_APL1,	DMN_FCCA },
	{ DMN_APL1_APLA,	DMN_APL1,	DMN_WORLD },
	{ DMN_APL1_ETSIC,	DMN_APL1,	DMN_ETSIC },
	{ DMN_APL2_ETSIC,	DMN_APL2,	DMN_ETSIC },
	{ DMN_APL5_WORLD,	DMN_APL5,	DMN_WORLD },
	{ DMN_WOR0_WORLD,	DMN_WORLD,	DMN_WORLD },
	{ DMN_WOR1_WORLD,	DMN_WORLD,	DMN_WORLD },
	{ DMN_WOR2_WORLD,	DMN_WORLD,	DMN_WORLD },
	{ DMN_WOR3_WORLD,	DMN_WORLD,	DMN_WORLD },
	{ DMN_WOR4_WORLD,	DMN_WORLD,	DMN_WORLD },
	{ DMN_WOR5_ETSIC,	DMN_WORLD,	DMN_WORLD },
	{ DMN_WOR01_WORLD,	DMN_WORLD,	DMN_WORLD },
	{ DMN_WOR02_WORLD,	DMN_WORLD,	DMN_WORLD },
	{ DMN_EU1_WORLD,	DMN_ETSI1,	DMN_WORLD },
	{ DMN_WOR9_WORLD,	DMN_WORLD,	DMN_WORLD },
	{ DMN_WORA_WORLD,	DMN_WORLD,	DMN_WORLD },
};

enum ath5k_regdom ath5k_regdom2flag(enum ath5k_regdom dmn, u16 mhz)
{
	unsigned int i;

	for (i = 0; i < ARRAY_SIZE(r_map); i++) {
		if (r_map[i].dmn == dmn) {
			if (mhz >= 2000 && mhz <= 3000)
				return r_map[i].dmn2;
			if (mhz >= IEEE80211_CHANNELS_5GHZ_MIN &&
					mhz <= IEEE80211_CHANNELS_5GHZ_MAX)
				return r_map[i].dmn5;
		}
	}

	return DMN_DEBUG;
}

u16 ath5k_regdom_from_ieee(enum ath5k_regdom ieee)
{
	u32 regdomain = (u32)ieee;

	/*
	 * Use the default regulation domain if the value is empty
	 * or not supported by the net80211 regulation code.
	 */
	if (ath5k_regdom2flag(regdomain, IEEE80211_CHANNELS_5GHZ_MIN) ==
			DMN_DEBUG)
		return (u16)AR5K_TUNE_REGDOMAIN;

	/* It is supported, just return the value */
	return regdomain;
}

enum ath5k_regdom ath5k_regdom_to_ieee(u16 regdomain)
{
	enum ath5k_regdom ieee = (enum ath5k_regdom)regdomain;

	return ieee;
}
+0 −500

File deleted.

Preview size limit exceeded, changes collapsed.