Update to later code from my repository:

o many bug fixes
o add new periodic calibration api
o break up 5416 periodic calibration code in preparation for 928x
o move get noise floor to rf backends
o 5416-specific ani (still disabled)
o modularize 5210 eeprom format a la other eeprom formats
o start cleaning up regdomain code
o prepare for proper 1/2 and 1/4 width channel support
o bring back 900MHz card support
o clean up 5212 rf version handling
o add 1/2 and 1/4 width channel support for 5212 parts
o split 5212 rfgain handling out
o improve ani debugging
o add AH_USE_INIPDGAIN compile option
o purge a bunch of dead 5212 state
o add 1/2 and 1/4 rate modes
o remove HAL_CAP_CHAN_HALFRATE and HAL_CAP_CHAN_QUARTERRATE; the
  same info can now be deduced from the set of supported modes
This commit is contained in:
Sam Leffler 2008-11-28 00:48:05 +00:00
parent 89eac01a28
commit d143488650
63 changed files with 4795 additions and 2913 deletions

71
ah.c
View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ah.c,v 1.13 2008/11/10 04:08:00 sam Exp $
* $Id: ah.c,v 1.15 2008/11/15 22:15:44 sam Exp $
*/
#include "opt_ah.h"
@ -46,6 +46,14 @@ extern struct ath_hal *ar5416Attach(uint16_t, HAL_SOFTC,
extern struct ath_hal *ar9160Attach(uint16_t, HAL_SOFTC,
HAL_BUS_TAG, HAL_BUS_HANDLE, HAL_STATUS*);
#endif
#ifdef AH_SUPPORT_AR9280
extern struct ath_hal *ar9280Attach(uint16_t, HAL_SOFTC,
HAL_BUS_TAG, HAL_BUS_HANDLE, HAL_STATUS*);
#endif
#ifdef AH_SUPPORT_AR9285
extern struct ath_hal *ar9285Attach(uint16_t, HAL_SOFTC,
HAL_BUS_TAG, HAL_BUS_HANDLE, HAL_STATUS*);
#endif
#include "version.h"
char ath_hal_version[] = ATH_HAL_VERSION;
@ -68,6 +76,12 @@ const char* ath_hal_buildopts[] = {
#ifdef AH_SUPPORT_AR9180
"AR9180",
#endif
#ifdef AH_SUPPORT_AR9280
"AR9280",
#endif
#ifdef AH_SUPPORT_AR9285
"AR9285",
#endif
#ifdef AH_SUPPORT_5111
"RF5111",
#endif
@ -110,12 +124,21 @@ const char* ath_hal_buildopts[] = {
#ifdef AH_PRIVATE_DIAG
"PRIVATE_DIAG",
#endif
#ifdef AH_SUPPORT_WRITE_EEPROM
"WRITE_EEPROM",
#endif
#ifdef AH_SUPPORT_WRITE_REGDOMAIN
"WRITE_REGDOMAIN",
#endif
#ifdef AH_DEBUG_COUNTRY
"DEBUG_COUNTRY",
#endif
#ifdef AH_NEED_DESC_SWAP
"TX_DESC_SWAP",
#endif
#ifdef AH_USE_INIPDGAIN
"INIPDGAIN",
#endif
#ifdef AH_DISABLE_WME
"DISABLE_WME",
#endif
@ -169,6 +192,11 @@ ath_hal_devname(uint16_t devid)
return "Atheros 5416";
case AR9160_DEVID_PCI:
return "Atheros 9160";
case AR9280_DEVID_PCI:
case AR9280_DEVID_PCIE:
return "Atheros 9280";
case AR9285_DEVID_PCIE:
return "Atheros 9285";
}
return AH_NULL;
}
@ -246,6 +274,17 @@ ath_hal_attach(uint16_t devid, HAL_SOFTC sc,
case AR9160_DEVID_PCI:
ah = ar9160Attach(devid, sc, st, sh, error);
break;
#endif
#ifdef AH_SUPPORT_AR9280
case AR9280_DEVID_PCI:
case AR9280_DEVID_PCIE:
ah = ar9280Attach(devid, sc, st, sh, error);
break;
#endif
#ifdef AH_SUPPORT_AR9285
case AR9285_DEVID_PCIE:
ah = ar9285Attach(devid, sc, st, sh, error);
break;
#endif
default:
ah = AH_NULL;
@ -418,6 +457,19 @@ ath_hal_computetxtime(struct ath_hal *ah,
return txTime;
}
static __inline int
mapgsm(u_int freq, u_int flags)
{
freq *= 10;
if (flags & CHANNEL_QUARTER)
freq += 5;
else if (flags & CHANNEL_HALF)
freq += 10;
else
freq += 20;
return (freq - 24220) / 5;
}
static __inline int
mappsb(u_int freq, u_int flags)
{
@ -434,6 +486,8 @@ ath_hal_mhz2ieee(struct ath_hal *ah, u_int freq, u_int flags)
if (freq == 2484)
return 14;
if (freq < 2484) {
if (ath_hal_isgsmsku(ah))
return mapgsm(freq, flags);
return ((int)freq - 2407) / 5;
} else
return 15 + ((freq - 2512) / 20);
@ -450,6 +504,8 @@ ath_hal_mhz2ieee(struct ath_hal *ah, u_int freq, u_int flags)
if (freq == 2484)
return 14;
if (freq < 2484) {
if (ath_hal_isgsmsku(ah))
return mapgsm(freq, flags);
return ((int)freq - 2407) / 5;
}
if (freq < 5000) {
@ -641,10 +697,6 @@ ath_hal_getcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
return pCap->halMcastKeySrchSupport ? HAL_OK : HAL_ENOTSUPP;
case HAL_CAP_TSF_ADJUST: /* hardware has beacon tsf adjust */
return HAL_ENOTSUPP;
case HAL_CAP_CHAN_HALFRATE:
return pCap->halChanHalfRate ? HAL_OK : HAL_ENOTSUPP;
case HAL_CAP_CHAN_QUARTERRATE:
return pCap->halChanQuarterRate ? HAL_OK : HAL_ENOTSUPP;
case HAL_CAP_RFSILENT: /* rfsilent support */
switch (capability) {
case 0: /* facility is supported */
@ -789,6 +841,15 @@ ath_hal_getdiagstate(struct ath_hal *ah, int request,
if (argsize != sizeof(uint16_t))
return AH_FALSE;
return ah->ah_resetKeyCacheEntry(ah, *(const uint16_t *)args);
#ifdef AH_SUPPORT_WRITE_EEPROM
case HAL_DIAG_EEWRITE: {
const HAL_DIAG_EEVAL *ee;
if (argsize != sizeof(HAL_DIAG_EEVAL))
return AH_FALSE;
ee = (const HAL_DIAG_EEVAL *)args;
return ath_hal_eepromWrite(ah, ee->ee_off, ee->ee_data);
}
#endif /* AH_SUPPORT_WRITE_EEPROM */
#endif /* AH_PRIVATE_DIAG */
case HAL_DIAG_11NCOMPAT:
if (argsize == 0) {

20
ah.h
View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ah.h,v 1.13 2008/11/10 04:08:00 sam Exp $
* $Id: ah.h,v 1.15 2008/11/15 03:43:50 sam Exp $
*/
#ifndef _ATH_AH_H_
@ -105,8 +105,8 @@ typedef enum {
HAL_CAP_TSF_ADJUST = 20, /* hardware has beacon tsf adjust */
/* 21 was HAL_CAP_XR */
HAL_CAP_WME_TKIPMIC = 22, /* hardware can support TKIP MIC when WMM is turned on */
HAL_CAP_CHAN_HALFRATE = 23, /* hardware can support half rate channels */
HAL_CAP_CHAN_QUARTERRATE = 24, /* hardware can support quarter rate channels */
/* 23 was HAL_CAP_CHAN_HALFRATE */
/* 24 was HAL_CAP_CHAN_QUARTERRATE */
HAL_CAP_RFSILENT = 25, /* hardware has rfsilent support */
HAL_CAP_TPC_ACK = 26, /* ack txpower with per-packet tpc */
HAL_CAP_TPC_CTS = 27, /* cts txpower with per-packet tpc */
@ -466,8 +466,10 @@ enum {
#endif
HAL_MODE_108G = 0x020, /* 11g+Turbo channels */
HAL_MODE_108A = 0x040, /* 11a+Turbo channels */
HAL_MODE_11A_HALF_RATE = 0x200, /* 11A half rate channels */
HAL_MODE_11A_QUARTER_RATE = 0x400, /* 11A quarter rate channels */
HAL_MODE_11A_HALF_RATE = 0x200, /* 11a half width channels */
HAL_MODE_11A_QUARTER_RATE = 0x400, /* 11a quarter width channels */
HAL_MODE_11G_HALF_RATE = 0x800, /* 11g half width channels */
HAL_MODE_11G_QUARTER_RATE = 0x1000, /* 11g quarter width channels */
HAL_MODE_11NG_HT20 = 0x008000,
HAL_MODE_11NA_HT20 = 0x010000,
HAL_MODE_11NG_HT40PLUS = 0x020000,
@ -654,7 +656,7 @@ struct ath_rx_status;
struct ath_hal {
uint32_t ah_magic; /* consistency check magic number */
uint32_t ah_abi; /* HAL ABI version */
#define HAL_ABI_VERSION 0x08110600 /* YYMMDDnn */
#define HAL_ABI_VERSION 0x08111400 /* YYMMDDnn */
uint16_t ah_devid; /* PCI device ID */
uint16_t ah_subvendorid; /* PCI subvendor ID */
HAL_SOFTC ah_sc; /* back pointer to driver/os state */
@ -680,7 +682,11 @@ struct ath_hal {
HAL_BOOL __ahdecl(*ah_phyDisable)(struct ath_hal *);
HAL_BOOL __ahdecl(*ah_disable)(struct ath_hal *);
void __ahdecl(*ah_setPCUConfig)(struct ath_hal *);
HAL_BOOL __ahdecl(*ah_perCalibration)(struct ath_hal*, HAL_CHANNEL *, HAL_BOOL *);
HAL_BOOL __ahdecl(*ah_perCalibration)(struct ath_hal*, HAL_CHANNEL *,
HAL_BOOL *);
HAL_BOOL __ahdecl(*ah_perCalibrationN)(struct ath_hal *, HAL_CHANNEL *,
u_int chainMask, HAL_BOOL longCal, HAL_BOOL *isCalDone);
HAL_BOOL __ahdecl(*ah_resetCalValid)(struct ath_hal *, HAL_CHANNEL *);
HAL_BOOL __ahdecl(*ah_setTxPowerLimit)(struct ath_hal *, uint32_t);
/* Transmit functions */

View File

@ -167,7 +167,8 @@ enum {
/*
* Definitions for the software frame/packet descriptors used by
* the Atheros HAL. Drivers are expected to fillin the
* the Atheros HAL. This definition obscures hardware-specific
* details from the driver. Drivers are expected to fillin the
* portions of a descriptor that are not opaque then use HAL calls
* to complete the work. Status for completed frames is returned
* in a device-independent format.

View File

@ -23,8 +23,8 @@
#define ATHEROS_VENDOR_ID 0x168c /* Atheros PCI vendor ID */
/*
* NB: all Atheros-based devices should have a PCI vendor ID
* of 0x168c, but some vendors do not follow this so we
* must handle them specially.
* of 0x168c, but some vendors, in their infinite wisdom
* do not follow this so we must handle them specially.
*/
#define ATHEROS_3COM_VENDOR_ID 0xa727 /* 3Com 3CRPAG175 vendor ID */
#define ATHEROS_3COM2_VENDOR_ID 0x10b7 /* 3Com 3CRDAG675 vendor ID */

View File

@ -14,11 +14,12 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ah_eeprom.h,v 1.6 2008/11/10 04:08:00 sam Exp $
* $Id: ah_eeprom.h,v 1.11 2008/11/27 22:32:48 sam Exp $
*/
#ifndef _ATH_AH_EEPROM_H_
#define _ATH_AH_EEPROM_H_
#define AR_EEPROM_VER1 0x1000 /* Version 1.0; 5210 only */
/*
* Version 3 EEPROMs are all 16K.
* 3.1 adds turbo limit, antenna gain, 16 CTL's, 11g info,
@ -34,15 +35,17 @@
#define AR_EEPROM_VER3_2 0x3002 /* Version 3.2 */
#define AR_EEPROM_VER3_3 0x3003 /* Version 3.3 */
#define AR_EEPROM_VER3_4 0x3004 /* Version 3.4 */
#define AR_EEPROM_VER4 0x4000 /* Version 4.x */
#define AR_EEPROM_VER4_0 0x4000 /* Version 4.0 */
#define AR_EEPROM_VER4_1 0x4001 /* Version 4.0 */
#define AR_EEPROM_VER4_2 0x4002 /* Version 4.0 */
#define AR_EEPROM_VER4_3 0x4003 /* Version 4.0 */
#define AR_EEPROM_VER4_6 0x4006 /* Version 4.0 */
#define AR_EEPROM_VER4_7 0x3007 /* Version 4.7 */
#define AR_EEPROM_VER4_9 0x4009 /* EEPROM EAR futureproofing */
#define AR_EEPROM_VER5_0 0x5000 /* Adds new 2413 cal powers and added params */
#define AR_EEPROM_VER5_1 0x5001 /* Adds capability values */
#define AR_EEPROM_VER4_9 0x4009 /* EEPROM EAR futureproofing */
#define AR_EEPROM_VER5 0x5000 /* Version 5.x */
#define AR_EEPROM_VER5_0 0x5000 /* Adds new 2413 cal powers and added params */
#define AR_EEPROM_VER5_1 0x5001 /* Adds capability values */
#define AR_EEPROM_VER5_3 0x5003 /* Adds spur mitigation table */
#define AR_EEPROM_VER5_4 0x5004
/*
@ -50,7 +53,8 @@
* 14.2 adds txFrameToPaOn, txFrameToDataStart, ht40PowerInc
* 14.3 adds bswAtten, bswMargin, swSettle, and base OpFlags for HT20/40
*/
#define AR_EEPROM_VER14_1 0xE001 /* 11n support */
#define AR_EEPROM_VER14 0xE000 /* Version 14.x */
#define AR_EEPROM_VER14_1 0xE001 /* Adds 11n support */
#define AR_EEPROM_VER14_2 0xE002
#define AR_EEPROM_VER14_3 0xE003
#define AR_EEPROM_VER14_7 0xE007
@ -75,8 +79,8 @@ enum {
AR_EEP_BURST, /* use ath_hal_eepromGetFlag */
AR_EEP_MAXQCU, /* uint16_t* */
AR_EEP_KCENTRIES, /* uint16_t* */
AR_EEP_NFTHRESH_5, /* uint8_t* */
AR_EEP_NFTHRESH_2, /* uint8_t* */
AR_EEP_NFTHRESH_5, /* int16_t* */
AR_EEP_NFTHRESH_2, /* int16_t* */
AR_EEP_REGDMN_0, /* uint16_t* */
AR_EEP_REGDMN_1, /* uint16_t* */
AR_EEP_OPCAP, /* uint16_t* */
@ -122,6 +126,8 @@ typedef struct {
/* XXX exposed to chip code */
#define MAX_RATE_POWER 63
HAL_STATUS ath_hal_v1EepromAttach(struct ath_hal *ah);
HAL_STATUS ath_hal_legacyEepromAttach(struct ath_hal *ah);
HAL_STATUS ath_hal_v14EepromAttach(struct ath_hal *ah);
HAL_STATUS ath_hal_v4kEepromAttach(struct ath_hal *ah);
#endif /* _ATH_AH_EEPROM_H_ */

253
ah_eeprom_v1.c Normal file
View File

@ -0,0 +1,253 @@
/*
* Copyright (c) 2008 Sam Leffler, Errno Consulting
* Copyright (c) 2008 Atheros Communications, Inc.
*
* Permission to use, copy, modify, and/or 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.
*
* $Id: ah_eeprom_v1.c,v 1.1 2008/11/11 02:40:11 sam Exp $
*/
#include "opt_ah.h"
#include "ah.h"
#include "ah_internal.h"
#include "ah_eeprom_v1.h"
static HAL_STATUS
v1EepromGet(struct ath_hal *ah, int param, void *val)
{
HAL_EEPROM_v1 *ee = AH_PRIVATE(ah)->ah_eeprom;
uint32_t sum;
uint16_t eeval;
uint8_t *macaddr;
int i;
switch (param) {
case AR_EEP_MACADDR: /* Get MAC Address */
sum = 0;
macaddr = val;
for (i = 0; i < 3; i++) {
if (!ath_hal_eepromRead(ah, AR_EEPROM_MAC(i), &eeval)) {
HALDEBUG(ah, HAL_DEBUG_ANY,
"%s: cannot read EEPROM location %u\n",
__func__, i);
return HAL_EEREAD;
}
sum += eeval;
macaddr[2*i + 0] = eeval >> 8;
macaddr[2*i + 1] = eeval & 0xff;
}
if (sum == 0 || sum == 0xffff*3) {
HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad mac address %s\n",
__func__, ath_hal_ether_sprintf(macaddr));
return HAL_EEBADMAC;
}
return HAL_OK;
case AR_EEP_REGDMN_0:
*(uint16_t *) val = ee->ee_regDomain[0];
return HAL_OK;
case AR_EEP_RFKILL:
HALASSERT(val == AH_NULL);
return ee->ee_rfKill ? HAL_OK : HAL_EIO;
case AR_EEP_WRITEPROTECT:
HALASSERT(val == AH_NULL);
return (ee->ee_protect & AR_EEPROM_PROTOTECT_WP_128_191) ?
HAL_OK : HAL_EIO;
default:
HALASSERT(0);
return HAL_EINVAL;
}
}
static HAL_BOOL
v1EepromSet(struct ath_hal *ah, int param, int v)
{
return HAL_EINVAL;
}
static HAL_BOOL
v1EepromDiag(struct ath_hal *ah, int request,
const void *args, uint32_t argsize, void **result, uint32_t *resultsize)
{
HAL_EEPROM_v1 *ee = AH_PRIVATE(ah)->ah_eeprom;
switch (request) {
case HAL_DIAG_EEPROM:
*result = ee;
*resultsize = sizeof(*ee);
return AH_TRUE;
}
return AH_FALSE;
}
static uint16_t
v1EepromGetSpurChan(struct ath_hal *ah, int ix, HAL_BOOL is2GHz)
{
return AR_NO_SPUR;
}
/*
* Reclaim any EEPROM-related storage.
*/
static void
v1EepromDetach(struct ath_hal *ah)
{
HAL_EEPROM_v1 *ee = AH_PRIVATE(ah)->ah_eeprom;
ath_hal_free(ee);
AH_PRIVATE(ah)->ah_eeprom = AH_NULL;
}
HAL_STATUS
ath_hal_v1EepromAttach(struct ath_hal *ah)
{
HAL_EEPROM_v1 *ee = AH_PRIVATE(ah)->ah_eeprom;
uint16_t athvals[AR_EEPROM_ATHEROS_MAX]; /* XXX off stack */
uint16_t protect, version, eeval;
uint32_t sum;
int i, loc;
HALASSERT(ee == AH_NULL);
if (!ath_hal_eepromRead(ah, AR_EEPROM_MAGIC, &eeval)) {
HALDEBUG(ah, HAL_DEBUG_ANY,
"%s: cannot read EEPROM magic number\n", __func__);
return HAL_EEREAD;
}
if (eeval != 0x5aa5) {
HALDEBUG(ah, HAL_DEBUG_ANY,
"%s: invalid EEPROM magic number 0x%x\n", __func__, eeval);
return HAL_EEMAGIC;
}
if (!ath_hal_eepromRead(ah, AR_EEPROM_PROTECT, &protect)) {
HALDEBUG(ah, HAL_DEBUG_ANY,
"%s: cannot read EEPROM protection bits; read locked?\n",
__func__);
return HAL_EEREAD;
}
HALDEBUG(ah, HAL_DEBUG_ATTACH, "EEPROM protect 0x%x\n", protect);
/* XXX check proper access before continuing */
if (!ath_hal_eepromRead(ah, AR_EEPROM_VERSION, &version)) {
HALDEBUG(ah, HAL_DEBUG_ANY,
"%s: unable to read EEPROM version\n", __func__);
return HAL_EEREAD;
}
if (((version>>12) & 0xf) != 1) {
/*
* This code only groks the version 1 EEPROM layout.
*/
HALDEBUG(ah, HAL_DEBUG_ANY,
"%s: unsupported EEPROM version 0x%x found\n",
__func__, version);
return HAL_EEVERSION;
}
/*
* Read the Atheros EEPROM entries and calculate the checksum.
*/
sum = 0;
for (i = 0; i < AR_EEPROM_ATHEROS_MAX; i++) {
if (!ath_hal_eepromRead(ah, AR_EEPROM_ATHEROS(i), &athvals[i]))
return HAL_EEREAD;
sum ^= athvals[i];
}
if (sum != 0xffff) {
HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad EEPROM checksum 0x%x\n",
__func__, sum);
return HAL_EEBADSUM;
}
/*
* Valid checksum, fetch the regulatory domain and save values.
*/
if (!ath_hal_eepromRead(ah, AR_EEPROM_REG_DOMAIN, &eeval)) {
HALDEBUG(ah, HAL_DEBUG_ANY,
"%s: cannot read regdomain from EEPROM\n", __func__);
return HAL_EEREAD;
}
ee = ath_hal_malloc(sizeof(HAL_EEPROM_v1));
if (ee == AH_NULL) {
/* XXX message */
return HAL_ENOMEM;
}
ee->ee_version = version;
ee->ee_protect = protect;
ee->ee_antenna = athvals[2];
ee->ee_biasCurrents = athvals[3];
ee->ee_thresh62 = athvals[4] & 0xff;
ee->ee_xlnaOn = (athvals[4] >> 8) & 0xff;
ee->ee_xpaOn = athvals[5] & 0xff;
ee->ee_xpaOff = (athvals[5] >> 8) & 0xff;
ee->ee_regDomain[0] = (athvals[6] >> 8) & 0xff;
ee->ee_regDomain[1] = athvals[6] & 0xff;
ee->ee_regDomain[2] = (athvals[7] >> 8) & 0xff;
ee->ee_regDomain[3] = athvals[7] & 0xff;
ee->ee_rfKill = athvals[8] & 0x1;
ee->ee_devType = (athvals[8] >> 1) & 0x7;
for (i = 0, loc = AR_EEPROM_ATHEROS_TP_SETTINGS; i < AR_CHANNELS_MAX; i++, loc += AR_TP_SETTINGS_SIZE) {
struct tpcMap *chan = &ee->ee_tpc[i];
/* Copy pcdac and gain_f values from EEPROM */
chan->pcdac[0] = (athvals[loc] >> 10) & 0x3F;
chan->gainF[0] = (athvals[loc] >> 4) & 0x3F;
chan->pcdac[1] = ((athvals[loc] << 2) & 0x3C)
| ((athvals[loc+1] >> 14) & 0x03);
chan->gainF[1] = (athvals[loc+1] >> 8) & 0x3F;
chan->pcdac[2] = (athvals[loc+1] >> 2) & 0x3F;
chan->gainF[2] = ((athvals[loc+1] << 4) & 0x30)
| ((athvals[loc+2] >> 12) & 0x0F);
chan->pcdac[3] = (athvals[loc+2] >> 6) & 0x3F;
chan->gainF[3] = athvals[loc+2] & 0x3F;
chan->pcdac[4] = (athvals[loc+3] >> 10) & 0x3F;
chan->gainF[4] = (athvals[loc+3] >> 4) & 0x3F;
chan->pcdac[5] = ((athvals[loc+3] << 2) & 0x3C)
| ((athvals[loc+4] >> 14) & 0x03);
chan->gainF[5] = (athvals[loc+4] >> 8) & 0x3F;
chan->pcdac[6] = (athvals[loc+4] >> 2) & 0x3F;
chan->gainF[6] = ((athvals[loc+4] << 4) & 0x30)
| ((athvals[loc+5] >> 12) & 0x0F);
chan->pcdac[7] = (athvals[loc+5] >> 6) & 0x3F;
chan->gainF[7] = athvals[loc+5] & 0x3F;
chan->pcdac[8] = (athvals[loc+6] >> 10) & 0x3F;
chan->gainF[8] = (athvals[loc+6] >> 4) & 0x3F;
chan->pcdac[9] = ((athvals[loc+6] << 2) & 0x3C)
| ((athvals[loc+7] >> 14) & 0x03);
chan->gainF[9] = (athvals[loc+7] >> 8) & 0x3F;
chan->pcdac[10] = (athvals[loc+7] >> 2) & 0x3F;
chan->gainF[10] = ((athvals[loc+7] << 4) & 0x30)
| ((athvals[loc+8] >> 12) & 0x0F);
/* Copy Regulatory Domain and Rate Information from EEPROM */
chan->rate36 = (athvals[loc+8] >> 6) & 0x3F;
chan->rate48 = athvals[loc+8] & 0x3F;
chan->rate54 = (athvals[loc+9] >> 10) & 0x3F;
chan->regdmn[0] = (athvals[loc+9] >> 4) & 0x3F;
chan->regdmn[1] = ((athvals[loc+9] << 2) & 0x3C)
| ((athvals[loc+10] >> 14) & 0x03);
chan->regdmn[2] = (athvals[loc+10] >> 8) & 0x3F;
chan->regdmn[3] = (athvals[loc+10] >> 2) & 0x3F;
}
AH_PRIVATE(ah)->ah_eeprom = ee;
AH_PRIVATE(ah)->ah_eeversion = version;
AH_PRIVATE(ah)->ah_eepromDetach = v1EepromDetach;
AH_PRIVATE(ah)->ah_eepromGet = v1EepromGet;
AH_PRIVATE(ah)->ah_eepromSet = v1EepromSet;
AH_PRIVATE(ah)->ah_getSpurChan = v1EepromGetSpurChan;
AH_PRIVATE(ah)->ah_eepromDiag = v1EepromDiag;
return HAL_OK;
}

99
ah_eeprom_v1.h Normal file
View File

@ -0,0 +1,99 @@
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
*
* Permission to use, copy, modify, and/or 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.
*
* $Id: ah_eeprom_v1.h,v 1.1 2008/11/11 02:40:11 sam Exp $
*/
#ifndef _ATH_AH_EEPROM_V1_H_
#define _ATH_AH_EEPROM_V1_H_
#include "ah_eeprom.h"
/*
* EEPROM defines for Version 1 Crete EEPROM.
*
* The EEPROM is segmented into three sections:
*
* PCI/Cardbus default configuration settings
* Cardbus CIS tuples and vendor-specific data
* Atheros-specific data
*
* EEPROM entries are read 32-bits at a time through the PCI bus
* interface but are all 16-bit values.
*
* Access to the Atheros-specific data is controlled by protection
* bits and the data is checksum'd. The driver reads the Atheros
* data from the EEPROM at attach and caches it in its private state.
* This data includes the local regulatory domain, channel calibration
* settings, and phy-related configuration settings.
*/
#define AR_EEPROM_MAC(i) (0x1f-(i))/* MAC address word */
#define AR_EEPROM_MAGIC 0x3d /* magic number */
#define AR_EEPROM_PROTECT 0x3f /* Atheros segment protect register */
#define AR_EEPROM_PROTOTECT_WP_128_191 0x80
#define AR_EEPROM_REG_DOMAIN 0xbf /* Current regulatory domain register */
#define AR_EEPROM_ATHEROS_BASE 0xc0 /* Base of Atheros-specific data */
#define AR_EEPROM_ATHEROS_MAX 64 /* 64x2=128 bytes of EEPROM settings */
#define AR_EEPROM_ATHEROS(n) (AR_EEPROM_ATHEROS_BASE+(n))
#define AR_EEPROM_VERSION AR_EEPROM_ATHEROS(1)
#define AR_EEPROM_ATHEROS_TP_SETTINGS 0x09 /* Transmit power settings */
#define AR_REG_DOMAINS_MAX 4 /* # of Regulatory Domains */
#define AR_CHANNELS_MAX 5 /* # of Channel calibration groups */
#define AR_TP_SETTINGS_SIZE 11 /* # locations/Channel group */
#define AR_TP_SCALING_ENTRIES 11 /* # entries in transmit power dBm->pcdac */
/*
* NB: we store the rfsilent select+polarity data packed
* with the encoding used in later parts so values
* returned to applications are consistent.
*/
#define AR_EEPROM_RFSILENT_GPIO_SEL 0x001c
#define AR_EEPROM_RFSILENT_GPIO_SEL_S 2
#define AR_EEPROM_RFSILENT_POLARITY 0x0002
#define AR_EEPROM_RFSILENT_POLARITY_S 1
#define AR_I2DBM(x) ((uint8_t)((x * 2) + 3))
/*
* Transmit power and channel calibration settings.
*/
struct tpcMap {
uint8_t pcdac[AR_TP_SCALING_ENTRIES];
uint8_t gainF[AR_TP_SCALING_ENTRIES];
uint8_t rate36;
uint8_t rate48;
uint8_t rate54;
uint8_t regdmn[AR_REG_DOMAINS_MAX];
};
/*
* Information retrieved from EEPROM.
*/
typedef struct {
uint16_t ee_version; /* Version field */
uint16_t ee_protect; /* EEPROM protect field */
uint16_t ee_antenna; /* Antenna Settings */
uint16_t ee_biasCurrents; /* OB, DB */
uint8_t ee_thresh62; /* thresh62 */
uint8_t ee_xlnaOn; /* External LNA timing */
uint8_t ee_xpaOff; /* Extern output stage timing */
uint8_t ee_xpaOn; /* Extern output stage timing */
uint8_t ee_rfKill; /* Single low bit signalling if RF Kill is implemented */
uint8_t ee_devType; /* Type: PCI, miniPCI, CB */
uint8_t ee_regDomain[AR_REG_DOMAINS_MAX];
/* calibrated reg domains */
struct tpcMap ee_tpc[AR_CHANNELS_MAX];
} HAL_EEPROM_v1;
#endif /* _ATH_AH_EEPROM_V1_H_ */

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ah_eeprom_v14.c,v 1.3 2008/11/10 04:08:00 sam Exp $
* $Id: ah_eeprom_v14.c,v 1.4 2008/11/10 19:04:26 sam Exp $
*/
#include "opt_ah.h"
@ -37,10 +37,10 @@ v14EepromGet(struct ath_hal *ah, int param, void *val)
switch (param) {
case AR_EEP_NFTHRESH_5:
*(int8_t *)val = pModal[0].noiseFloorThreshCh[0];
*(int16_t *)val = pModal[0].noiseFloorThreshCh[0];
return HAL_OK;
case AR_EEP_NFTHRESH_2:
*(int8_t *)val = pModal[1].noiseFloorThreshCh[0];
*(int16_t *)val = pModal[1].noiseFloorThreshCh[0];
return HAL_OK;
case AR_EEP_MACADDR: /* Get MAC Address */
sum = 0;

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ah_eeprom_v3.c,v 1.3 2008/11/10 04:08:00 sam Exp $
* $Id: ah_eeprom_v3.c,v 1.4 2008/11/27 22:39:42 sam Exp $
*/
#include "opt_ah.h"
@ -1765,9 +1765,8 @@ legacyEepromDetach(struct ath_hal *ah)
}
/*
* TODO: Need to talk to Praveen about this, these are
* not valid 2.4 channels, either we change these
* or I need to change the beanie coding to accept these
* These are not valid 2.4 channels, either we change 'em
* or we need to change the coding to accept them.
*/
static const uint16_t channels11b[] = { 2412, 2447, 2484 };
static const uint16_t channels11g[] = { 2312, 2412, 2484 };

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ah_internal.h,v 1.17 2008/11/10 04:08:00 sam Exp $
* $Id: ah_internal.h,v 1.21 2008/11/27 22:29:27 sam Exp $
*/
#ifndef _ATH_AH_INTERAL_H_
#define _ATH_AH_INTERAL_H_
@ -66,6 +66,9 @@ typedef struct {
/*
* Transmit power scale factor.
*
* NB: This is not public because we want to discourage the use of
* scaling; folks should use the tx power limit interface.
*/
typedef enum {
HAL_TP_SCALE_MAX = 0, /* no scaling (default) */
@ -165,7 +168,23 @@ typedef struct {
/*
* The ``private area'' follows immediately after the ``public area''
* in the data structure returned by ath_hal_attach.
* in the data structure returned by ath_hal_attach. Private data are
* used by device-independent code such as the regulatory domain support.
* In general, code within the HAL should never depend on data in the
* public area. Instead any public data needed internally should be
* shadowed here.
*
* When declaring a device-specific ath_hal data structure this structure
* is assumed to at the front; e.g.
*
* struct ath_hal_5212 {
* struct ath_hal_private ah_priv;
* ...
* };
*
* It might be better to manage the method pointers in this structure
* using an indirect pointer to a read-only data structure but this would
* disallow class-style method overriding.
*/
struct ath_hal_private {
struct ath_hal h; /* public area */
@ -189,6 +208,8 @@ struct ath_hal_private {
HAL_CHANNEL *, uint32_t);
int16_t (*ah_getNfAdjust)(struct ath_hal *,
const HAL_CHANNEL_INTERNAL*);
void (*ah_getNoiseFloor)(struct ath_hal *,
int16_t nfarray[]);
void *ah_eeprom; /* opaque EEPROM state */
uint16_t ah_eeversion; /* EEPROM version */
@ -267,6 +288,8 @@ struct ath_hal_private {
AH_PRIVATE(_ah)->ah_getChipPowerLimits(_ah, _chans, _nchan)
#define ath_hal_getNfAdjust(_ah, _c) \
AH_PRIVATE(_ah)->ah_getNfAdjust(_ah, _c)
#define ath_hal_getNoiseFloor(_ah, _nfArray) \
AH_PRIVATE(_ah)->ah_getNoiseFloor(_ah, _nfArray)
#define ath_hal_eepromDetach(_ah) \
AH_PRIVATE(_ah)->ah_eepromDetach(_ah)

File diff suppressed because it is too large Load Diff

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ar5210.h,v 1.6 2008/11/10 04:08:02 sam Exp $
* $Id: ar5210.h,v 1.8 2008/11/11 02:40:13 sam Exp $
*/
#ifndef _ATH_AR5210_H_
#define _ATH_AR5210_H_
@ -90,67 +90,7 @@
#define INIT_PROTO_TIME_CNTRL_TURBO ( (INIT_CARR_SENSE_EN << 26) | (INIT_EIFS_TURBO << 12) | \
(INIT_ProgIFS_TURBO) )
/*
* EEPROM defines for Version 1 Crete EEPROM.
*
* The EEPROM is segmented into three sections:
*
* PCI/Cardbus default configuration settings
* Cardbus CIS tuples and vendor-specific data
* Atheros-specific data
*
* EEPROM entries are read 32-bits at a time through the PCI bus
* interface but are all 16-bit values.
*
* Access to the Atheros-specific data is controlled by protection
* bits and the data is checksum'd. The driver reads the Atheros
* data from the EEPROM at attach and caches it in its private state.
* This data includes the local regulatory domain, channel calibration
* settings, and phy-related configuration settings.
*/
#define AR_EEPROM_MAC(i) (0x1f-(i))/* MAC address word */
#define AR_EEPROM_MAGIC 0x3d /* magic number */
#define AR_EEPROM_PROTECT 0x3f /* Atheros segment protect register */
#define AR_EEPROM_PROTOTECT_WP_128_191 0x80
#define AR_EEPROM_REG_DOMAIN 0xbf /* Current regulatory domain register */
#define AR_EEPROM_ATHEROS_BASE 0xc0 /* Base of Atheros-specific data */
#define AR_EEPROM_ATHEROS_MAX 64 /* 64x2=128 bytes of EEPROM settings */
#define AR_EEPROM_ATHEROS(n) (AR_EEPROM_ATHEROS_BASE+(n))
#define AR_EEPROM_VERSION AR_EEPROM_ATHEROS(1)
#define AR_EEPROM_ATHEROS_TP_SETTINGS 0x09 /* Transmit power settings */
#define AR_REG_DOMAINS_MAX 4 /* # of Regulatory Domains */
#define AR_CHANNELS_MAX 5 /* # of Channel calibration groups */
#define AR_TP_SETTINGS_SIZE 11 /* # locations/Channel group */
#define AR_TP_SCALING_ENTRIES 11 /* # entries in transmit power dBm->pcdac */
/*
* NB: we store the rfsilent select+polarity data packed
* with the encoding used in later parts so values
* returned to applications are consistent.
*/
#define AR_EEPROM_RFSILENT_GPIO_SEL 0x001c
#define AR_EEPROM_RFSILENT_GPIO_SEL_S 2
#define AR_EEPROM_RFSILENT_POLARITY 0x0002
#define AR_EEPROM_RFSILENT_POLARITY_S 1
#define AR_I2DBM(x) ((uint8_t)((x * 2) + 3))
/*
* Transmit power and channel calibration settings.
*/
struct tpcMap {
uint8_t pcdac[AR_TP_SCALING_ENTRIES];
uint8_t gainF[AR_TP_SCALING_ENTRIES];
uint8_t rate36;
uint8_t rate48;
uint8_t rate54;
uint8_t regdmn[AR_REG_DOMAINS_MAX];
};
/* NB: this is in ah_eeprom.h which isn't used for 5210 support */
#ifndef MAX_RATE_POWER
#define MAX_RATE_POWER 60
#endif
#define AR5210_MAX_RATE_POWER 60
#undef HAL_NUM_TX_QUEUES /* from ah.h */
#define HAL_NUM_TX_QUEUES 3
@ -158,22 +98,6 @@ struct tpcMap {
struct ath_hal_5210 {
struct ath_hal_private ah_priv; /* base definitions */
/*
* Information retrieved from EEPROM
*/
uint16_t ah_eeversion; /* EEPROM Version field */
uint16_t ah_eeprotect; /* EEPROM protection settings */
uint16_t ah_antenna; /* Antenna Settings */
uint16_t ah_biasCurrents; /* OB, DB */
uint8_t ah_thresh62; /* thresh62 */
uint8_t ah_xlnaOn; /* External LNA timing */
uint8_t ah_xpaOff; /* Extern output stage timing */
uint8_t ah_xpaOn; /* Extern output stage timing */
uint8_t ah_rfKill; /* Single low bit signalling if RF Kill is implemented */
uint8_t ah_devType; /* Type: PCI, miniPCI, CB */
uint8_t ah_regDomain[AR_REG_DOMAINS_MAX];
/* calibrated reg domains */
struct tpcMap ah_tpc[AR_CHANNELS_MAX];
uint8_t ah_macaddr[IEEE80211_ADDR_LEN];
/*
* Runtime state.
@ -213,6 +137,9 @@ extern HAL_BOOL ar5210PhyDisable(struct ath_hal *);
extern HAL_BOOL ar5210Disable(struct ath_hal *);
extern HAL_BOOL ar5210ChipReset(struct ath_hal *, HAL_CHANNEL *);
extern HAL_BOOL ar5210PerCalibration(struct ath_hal *, HAL_CHANNEL *, HAL_BOOL *);
extern HAL_BOOL ar5210PerCalibrationN(struct ath_hal *ah, HAL_CHANNEL *chan,
u_int chainMask, HAL_BOOL longCal, HAL_BOOL *isCalDone);
extern HAL_BOOL ar5210ResetCalValid(struct ath_hal *ah, HAL_CHANNEL *chan);
extern int16_t ar5210GetNoiseFloor(struct ath_hal *);
extern int16_t ar5210GetNfAdjust(struct ath_hal *,
const HAL_CHANNEL_INTERNAL *);

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ar5210_attach.c,v 1.7 2008/11/10 04:08:02 sam Exp $
* $Id: ar5210_attach.c,v 1.9 2008/11/11 02:40:13 sam Exp $
*/
#include "opt_ah.h"
@ -27,6 +27,8 @@
#include "ar5210/ar5210reg.h"
#include "ar5210/ar5210phy.h"
#include "ah_eeprom_v1.h"
static HAL_BOOL ar5210GetChannelEdges(struct ath_hal *,
uint16_t flags, uint16_t *low, uint16_t *high);
static HAL_BOOL ar5210GetChipPowerLimits(struct ath_hal *ah,
@ -46,6 +48,8 @@ static const struct ath_hal_private ar5210hal = {{
.ah_disable = ar5210Disable,
.ah_setPCUConfig = ar5210SetPCUConfig,
.ah_perCalibration = ar5210PerCalibration,
.ah_perCalibrationN = ar5210PerCalibrationN,
.ah_resetCalValid = ar5210ResetCalValid,
.ah_setTxPowerLimit = ar5210SetTxPowerLimit,
.ah_getChanNoise = ath_hal_getChanNoise,
@ -93,6 +97,7 @@ static const struct ath_hal_private ar5210hal = {{
.ah_setMacAddress = ar5210SetMacAddress,
.ah_getBssIdMask = ar5210GetBssIdMask,
.ah_setBssIdMask = ar5210SetBssIdMask,
.ah_setRegulatoryDomain = ar5210SetRegulatoryDomain,
.ah_setLedState = ar5210SetLedState,
.ah_writeAssocid = ar5210WriteAssocid,
.ah_gpioCfgInput = ar5210GpioCfgInput,
@ -171,10 +176,10 @@ ar5210Attach(uint16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HA
#define N(a) (sizeof(a)/sizeof(a[0]))
struct ath_hal_5210 *ahp;
struct ath_hal *ah;
u_int i, loc;
uint32_t revid, pcicfg, sum;
uint16_t athvals[AR_EEPROM_ATHEROS_MAX], eeval;
uint32_t revid, pcicfg;
uint16_t eeval;
HAL_STATUS ecode;
int i;
HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH,
"%s: devid 0x%x sc %p st %p sh %p\n", __func__, devid,
@ -199,7 +204,7 @@ ar5210Attach(uint16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HA
AH_PRIVATE(ah)->ah_devid = devid;
AH_PRIVATE(ah)->ah_subvendorid = 0; /* XXX */
AH_PRIVATE(ah)->ah_powerLimit = MAX_RATE_POWER;
AH_PRIVATE(ah)->ah_powerLimit = AR5210_MAX_RATE_POWER;
AH_PRIVATE(ah)->ah_tpScale = HAL_TP_SCALE_MAX; /* no scaling */
ahp->ah_powerMode = HAL_PM_UNDEFINED;
@ -234,169 +239,40 @@ ar5210Attach(uint16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HA
/*
* Read all the settings from the EEPROM and stash
* ones we'll use later in our state block.
* ones we'll use later.
*/
pcicfg = OS_REG_READ(ah, AR_PCICFG);
OS_REG_WRITE(ah, AR_PCICFG, pcicfg | AR_PCICFG_EEPROMSEL);
if (!ar5210EepromRead(ah, AR_EEPROM_MAGIC, &eeval)) {
HALDEBUG(ah, HAL_DEBUG_ANY,
"%s: cannot read EEPROM magic number\n", __func__);
ecode = HAL_EEREAD;
ecode = ath_hal_v1EepromAttach(ah);
if (ecode != HAL_OK) {
goto eebad;
}
if (eeval != 0x5aa5) {
ecode = ath_hal_eepromGet(ah, AR_EEP_REGDMN_0, &eeval);
if (ecode != HAL_OK) {
HALDEBUG(ah, HAL_DEBUG_ANY,
"%s: invalid EEPROM magic number 0x%x\n", __func__, eeval);
ecode = HAL_EEMAGIC;
goto eebad;
}
if (!ar5210EepromRead(ah, AR_EEPROM_PROTECT, &eeval)) {
HALDEBUG(ah, HAL_DEBUG_ANY,
"%s: cannot read EEPROM protection bits; read locked?\n",
"%s: cannot read regulatory domain from EEPROM\n",
__func__);
ecode = HAL_EEREAD;
goto eebad;
}
HALDEBUG(ah, HAL_DEBUG_ATTACH, "EEPROM protect 0x%x\n", eeval);
ahp->ah_eeprotect = eeval;
/* XXX check proper access before continuing */
if (!ar5210EepromRead(ah, AR_EEPROM_VERSION, &eeval)) {
}
AH_PRIVATE(ah)->ah_currentRD = eeval;
ecode = ath_hal_eepromGet(ah, AR_EEP_MACADDR, ahp->ah_macaddr);
if (ecode != HAL_OK) {
HALDEBUG(ah, HAL_DEBUG_ANY,
"%s: unable to read EEPROM version\n", __func__);
ecode = HAL_EEREAD;
"%s: error getting mac address from EEPROM\n", __func__);
goto eebad;
}
ahp->ah_eeversion = (eeval>>12) & 0xf;
if (ahp->ah_eeversion != 1) {
/*
* This driver only groks the version 1 EEPROM layout.
*/
HALDEBUG(ah, HAL_DEBUG_ANY,
"%s: unsupported EEPROM version %u (0x%x) found\n",
__func__, ahp->ah_eeversion, eeval);
ecode = HAL_EEVERSION;
goto eebad;
}
}
OS_REG_WRITE(ah, AR_PCICFG, pcicfg); /* disable EEPROM access */
/*
* Read the Atheros EEPROM entries and calculate the checksum.
*/
sum = 0;
for (i = 0; i < AR_EEPROM_ATHEROS_MAX; i++) {
if (!ar5210EepromRead(ah, AR_EEPROM_ATHEROS(i), &athvals[i])) {
ecode = HAL_EEREAD;
goto eebad;
}
sum ^= athvals[i];
}
if (sum != 0xffff) {
HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad EEPROM checksum 0x%x\n",
__func__, sum);
ecode = HAL_EEBADSUM;
goto eebad;
}
/*
* Valid checksum, fetch the regulatory domain and save values.
*/
if (!ar5210EepromRead(ah, AR_EEPROM_REG_DOMAIN, &eeval)) {
HALDEBUG(ah, HAL_DEBUG_ANY,
"%s: cannot read regdomain from EEPROM\n", __func__);
ecode = HAL_EEREAD;
goto eebad;
}
AH_PRIVATE(ah)->ah_currentRD = eeval & 0xff;
ahp->ah_antenna = athvals[2];
ahp->ah_biasCurrents = athvals[3];
ahp->ah_thresh62 = athvals[4] & 0xff;
ahp->ah_xlnaOn = (athvals[4] >> 8) & 0xff;
ahp->ah_xpaOn = athvals[5] & 0xff;
ahp->ah_xpaOff = (athvals[5] >> 8) & 0xff;
ahp->ah_regDomain[0] = (athvals[6] >> 8) & 0xff;
ahp->ah_regDomain[1] = athvals[6] & 0xff;
ahp->ah_regDomain[2] = (athvals[7] >> 8) & 0xff;
ahp->ah_regDomain[3] = athvals[7] & 0xff;
ahp->ah_rfKill = athvals[8] & 0x1;
ahp->ah_devType = (athvals[8] >> 1) & 0x7;
AH_PRIVATE(ah)->ah_getNfAdjust = ar5210GetNfAdjust;
for (i = 0, loc = AR_EEPROM_ATHEROS_TP_SETTINGS; i < AR_CHANNELS_MAX; i++, loc += AR_TP_SETTINGS_SIZE) {
struct tpcMap *chan = &ahp->ah_tpc[i];
/* Copy pcdac and gain_f values from EEPROM */
chan->pcdac[0] = (athvals[loc] >> 10) & 0x3F;
chan->gainF[0] = (athvals[loc] >> 4) & 0x3F;
chan->pcdac[1] = ((athvals[loc] << 2) & 0x3C)
| ((athvals[loc+1] >> 14) & 0x03);
chan->gainF[1] = (athvals[loc+1] >> 8) & 0x3F;
chan->pcdac[2] = (athvals[loc+1] >> 2) & 0x3F;
chan->gainF[2] = ((athvals[loc+1] << 4) & 0x30)
| ((athvals[loc+2] >> 12) & 0x0F);
chan->pcdac[3] = (athvals[loc+2] >> 6) & 0x3F;
chan->gainF[3] = athvals[loc+2] & 0x3F;
chan->pcdac[4] = (athvals[loc+3] >> 10) & 0x3F;
chan->gainF[4] = (athvals[loc+3] >> 4) & 0x3F;
chan->pcdac[5] = ((athvals[loc+3] << 2) & 0x3C)
| ((athvals[loc+4] >> 14) & 0x03);
chan->gainF[5] = (athvals[loc+4] >> 8) & 0x3F;
chan->pcdac[6] = (athvals[loc+4] >> 2) & 0x3F;
chan->gainF[6] = ((athvals[loc+4] << 4) & 0x30)
| ((athvals[loc+5] >> 12) & 0x0F);
chan->pcdac[7] = (athvals[loc+5] >> 6) & 0x3F;
chan->gainF[7] = athvals[loc+5] & 0x3F;
chan->pcdac[8] = (athvals[loc+6] >> 10) & 0x3F;
chan->gainF[8] = (athvals[loc+6] >> 4) & 0x3F;
chan->pcdac[9] = ((athvals[loc+6] << 2) & 0x3C)
| ((athvals[loc+7] >> 14) & 0x03);
chan->gainF[9] = (athvals[loc+7] >> 8) & 0x3F;
chan->pcdac[10] = (athvals[loc+7] >> 2) & 0x3F;
chan->gainF[10] = ((athvals[loc+7] << 4) & 0x30)
| ((athvals[loc+8] >> 12) & 0x0F);
/* Copy Regulatory Domain and Rate Information from EEPROM */
chan->rate36 = (athvals[loc+8] >> 6) & 0x3F;
chan->rate48 = athvals[loc+8] & 0x3F;
chan->rate54 = (athvals[loc+9] >> 10) & 0x3F;
chan->regdmn[0] = (athvals[loc+9] >> 4) & 0x3F;
chan->regdmn[1] = ((athvals[loc+9] << 2) & 0x3C)
| ((athvals[loc+10] >> 14) & 0x03);
chan->regdmn[2] = (athvals[loc+10] >> 8) & 0x3F;
chan->regdmn[3] = (athvals[loc+10] >> 2) & 0x3F;
}
/*
* Got everything we need now to setup the capabilities.
*/
(void) ar5210FillCapabilityInfo(ah);
sum = 0;
for (i = 0; i < 3; i++) {
if (!ar5210EepromRead(ah, AR_EEPROM_MAC(i), &eeval)) {
HALDEBUG(ah, HAL_DEBUG_ANY,
"%s: cannot read EEPROM location %u\n", __func__, i);
ecode = HAL_EEREAD;
goto bad;
}
sum += eeval;
ahp->ah_macaddr[2*i + 0] = eeval >> 8;
ahp->ah_macaddr[2*i + 1] = eeval & 0xff;
}
if (sum == 0 || sum == 0xffff*3) {
HALDEBUG(ah, HAL_DEBUG_ANY, "%s: mac address read failed: %s\n",
__func__, ath_hal_ether_sprintf(ahp->ah_macaddr));
ecode = HAL_EEBADMAC;
goto eebad;
}
OS_REG_WRITE(ah, AR_PCICFG, pcicfg); /* disable EEPROM access */
HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: return\n", __func__);
return ah;
eebad:
OS_REG_WRITE(ah, AR_PCICFG, pcicfg); /* disable EEPROM access */
bad:
@ -416,6 +292,7 @@ ar5210Detach(struct ath_hal *ah)
HALASSERT(ah != AH_NULL);
HALASSERT(ah->ah_magic == AR5210_MAGIC);
ath_hal_eepromDetach(ah);
ath_hal_free(ah);
}
@ -447,7 +324,7 @@ ar5210GetChipPowerLimits(struct ath_hal *ah, HAL_CHANNEL *chans, uint32_t nchans
HALDEBUG(ah, HAL_DEBUG_ATTACH,
"%s: no min/max power for %u/0x%x\n",
__func__, chan->channel, chan->channelFlags);
chan->maxTxPower = MAX_RATE_POWER;
chan->maxTxPower = AR5210_MAX_RATE_POWER;
chan->minTxPower = 0;
}
return AH_TRUE;
@ -477,7 +354,7 @@ ar5210FillCapabilityInfo(struct ath_hal *ah)
pCap->halChanHalfRate = AH_FALSE;
pCap->halChanQuarterRate = AH_FALSE;
if (AH5210(ah)->ah_rfKill) {
if (ath_hal_eepromGetFlag(ah, AR_EEP_RFKILL)) {
/*
* Setup initial rfsilent settings based on the EEPROM
* contents. Pin 0, polarity 0 is fixed; record this

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ar5210_misc.c,v 1.4 2008/11/10 04:08:02 sam Exp $
* $Id: ar5210_misc.c,v 1.6 2008/11/27 22:29:37 sam Exp $
*/
#include "opt_ah.h"
@ -27,6 +27,8 @@
#include "ar5210/ar5210reg.h"
#include "ar5210/ar5210phy.h"
#include "ah_eeprom_v1.h"
#define AR_NUM_GPIO 6 /* 6 GPIO bits */
#define AR_GPIOD_MASK 0x2f /* 6-bit mask */
@ -78,6 +80,46 @@ ar5210EepromRead(struct ath_hal *ah, u_int off, uint16_t *data)
return AH_TRUE;
}
#ifdef AH_SUPPORT_WRITE_EEPROM
/*
* Write 16 bits of data to the specified EEPROM offset.
*/
HAL_BOOL
ar5210EepromWrite(struct ath_hal *ah, u_int off, uint16_t data)
{
return AH_FALSE;
}
#endif /* AH_SUPPORT_WRITE_EEPROM */
/*
* Attempt to change the cards operating regulatory domain to the given value
*/
HAL_BOOL
ar5210SetRegulatoryDomain(struct ath_hal *ah,
uint16_t regDomain, HAL_STATUS *status)
{
HAL_STATUS ecode;
if (AH_PRIVATE(ah)->ah_currentRD == regDomain) {
ecode = HAL_EINVAL;
goto bad;
}
/*
* Check if EEPROM is configured to allow this; must
* be a proper version and the protection bits must
* permit re-writing that segment of the EEPROM.
*/
if (ath_hal_eepromGetFlag(ah, AR_EEP_WRITEPROTECT)) {
ecode = HAL_EEWRITE;
goto bad;
}
ecode = HAL_EIO; /* disallow all writes */
bad:
if (status)
*status = ecode;
return AH_FALSE;
}
/*
* Return the wireless modes (a,b,g,t) supported by hardware.
*
@ -302,11 +344,10 @@ ar5210GetTsf64(struct ath_hal *ah)
* then we re-reading AR_TSF_U32 does no good as the
* low bits will be meaningless. Likewise reading
* L32, U32, U32, then comparing the last two reads
* to check for rollover
* doesn't help if preempted--so we take this approach
* as it costs one less PCI read which can be noticeable
* when doing things like timestamping packets in
* monitor mode.
* to check for rollover doesn't help if preempted--so
* we take this approach as it costs one less PCI
* read which can be noticeable when doing things
* like timestamping packets in monitor mode.
*/
u32++;
}

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ar5210_reset.c,v 1.5 2008/11/10 04:08:02 sam Exp $
* $Id: ar5210_reset.c,v 1.8 2008/11/11 17:25:16 sam Exp $
*/
#include "opt_ah.h"
@ -27,6 +27,8 @@
#include "ar5210/ar5210reg.h"
#include "ar5210/ar5210phy.h"
#include "ah_eeprom_v1.h"
typedef struct {
uint32_t Offset;
uint32_t Value;
@ -73,6 +75,7 @@ ar5210Reset(struct ath_hal *ah, HAL_OPMODE opmode,
#define N(a) (sizeof (a) /sizeof (a[0]))
#define FAIL(_code) do { ecode = _code; goto bad; } while (0)
struct ath_hal_5210 *ahp = AH5210(ah);
const HAL_EEPROM_v1 *ee = AH_PRIVATE(ah)->ah_eeprom;
HAL_CHANNEL_INTERNAL *ichan;
HAL_STATUS ecode;
uint32_t ledstate;
@ -214,22 +217,22 @@ ar5210Reset(struct ath_hal *ah, HAL_OPMODE opmode,
OS_REG_WRITE(ah, AR_PHY(10),
(OS_REG_READ(ah, AR_PHY(10)) & 0xFFFF00FF) |
(ahp->ah_xlnaOn << 8));
(ee->ee_xlnaOn << 8));
OS_REG_WRITE(ah, AR_PHY(13),
(ahp->ah_xpaOff << 24) | (ahp->ah_xpaOff << 16) |
(ahp->ah_xpaOn << 8) | ahp->ah_xpaOn);
(ee->ee_xpaOff << 24) | (ee->ee_xpaOff << 16) |
(ee->ee_xpaOn << 8) | ee->ee_xpaOn);
OS_REG_WRITE(ah, AR_PHY(17),
(OS_REG_READ(ah, AR_PHY(17)) & 0xFFFFC07F) |
((ahp->ah_antenna >> 1) & 0x3F80));
((ee->ee_antenna >> 1) & 0x3F80));
OS_REG_WRITE(ah, AR_PHY(18),
(OS_REG_READ(ah, AR_PHY(18)) & 0xFFFC0FFF) |
((ahp->ah_antenna << 10) & 0x3F000));
((ee->ee_antenna << 10) & 0x3F000));
OS_REG_WRITE(ah, AR_PHY(25),
(OS_REG_READ(ah, AR_PHY(25)) & 0xFFF80FFF) |
((ahp->ah_thresh62 << 12) & 0x7F000));
((ee->ee_thresh62 << 12) & 0x7F000));
OS_REG_WRITE(ah, AR_PHY(68),
(OS_REG_READ(ah, AR_PHY(68)) & 0xFFFFFFFC) |
(ahp->ah_antenna & 0x3));
(ee->ee_antenna & 0x3));
if (!ar5210SetChannel(ah, ichan)) {
HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unable to set channel\n",
@ -443,7 +446,8 @@ enum {
* changes.
*/
HAL_BOOL
ar5210PerCalibration(struct ath_hal *ah, HAL_CHANNEL *chan, HAL_BOOL *isIQdone)
ar5210PerCalibrationN(struct ath_hal *ah, HAL_CHANNEL *chan, u_int chainMask,
HAL_BOOL longCal, HAL_BOOL *isCalDone)
{
uint32_t regBeacon;
uint32_t reg9858, reg985c, reg9868;
@ -559,11 +563,23 @@ ar5210PerCalibration(struct ath_hal *ah, HAL_CHANNEL *chan, HAL_BOOL *isIQdone)
/* Re-enable Beacons */
OS_REG_WRITE(ah, AR_BEACON, regBeacon);
*isIQdone = AH_TRUE;
*isCalDone = AH_TRUE;
return AH_TRUE;
}
HAL_BOOL
ar5210PerCalibration(struct ath_hal *ah, HAL_CHANNEL *chan, HAL_BOOL *isIQdone)
{
return ar5210PerCalibrationN(ah, chan, 0x1, AH_TRUE, isIQdone);
}
HAL_BOOL
ar5210ResetCalValid(struct ath_hal *ah, HAL_CHANNEL *chan)
{
return AH_TRUE;
}
/*
* Writes the given reset bit mask into the reset register
*/
@ -600,7 +616,7 @@ ar5210SetResetReg(struct ath_hal *ah, uint32_t resetMask, u_int delay)
* Returns: the pcdac value
*/
static uint8_t
getPcdac(struct ath_hal *ah, struct tpcMap *pRD, uint8_t dBm)
getPcdac(struct ath_hal *ah, const struct tpcMap *pRD, uint8_t dBm)
{
int32_t i;
int useNextEntry = AH_FALSE;
@ -643,7 +659,8 @@ getPcdac(struct ath_hal *ah, struct tpcMap *pRD, uint8_t dBm)
* Find or interpolates the gainF value from the table ptr.
*/
static uint8_t
getGainF(struct ath_hal *ah, struct tpcMap *pRD, uint8_t pcdac, uint8_t *dBm)
getGainF(struct ath_hal *ah, const struct tpcMap *pRD,
uint8_t pcdac, uint8_t *dBm)
{
uint32_t interp;
int low, high, i;
@ -705,7 +722,7 @@ getGainF(struct ath_hal *ah, struct tpcMap *pRD, uint8_t pcdac, uint8_t *dBm)
HAL_BOOL
ar5210SetTxPowerLimit(struct ath_hal *ah, uint32_t limit)
{
AH_PRIVATE(ah)->ah_powerLimit = AH_MIN(limit, MAX_RATE_POWER);
AH_PRIVATE(ah)->ah_powerLimit = AH_MIN(limit, AR5210_MAX_RATE_POWER);
/* XXX flush to h/w */
return AH_TRUE;
}
@ -716,15 +733,15 @@ ar5210SetTxPowerLimit(struct ath_hal *ah, uint32_t limit)
static HAL_BOOL
setupPowerSettings(struct ath_hal *ah, HAL_CHANNEL *chan, uint8_t cp[17])
{
struct ath_hal_5210 *ahp = AH5210(ah);
const HAL_EEPROM_v1 *ee = AH_PRIVATE(ah)->ah_eeprom;
uint8_t gainFRD, gainF36, gainF48, gainF54;
uint8_t dBmRD, dBm36, dBm48, dBm54, dontcare;
uint32_t rd, group;
struct tpcMap *pRD;
const struct tpcMap *pRD;
/* Set OB/DB Values regardless of channel */
cp[15] = (ahp->ah_biasCurrents >> 4) & 0x7;
cp[16] = ahp->ah_biasCurrents & 0x7;
cp[15] = (ee->ee_biasCurrents >> 4) & 0x7;
cp[16] = ee->ee_biasCurrents & 0x7;
if (chan->channel < 5170 || chan->channel > 5320) {
HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel %u\n",
@ -732,11 +749,12 @@ setupPowerSettings(struct ath_hal *ah, HAL_CHANNEL *chan, uint8_t cp[17])
return AH_FALSE;
}
HALASSERT(ahp->ah_eeversion == 1);
HALASSERT(ee->ee_version >= AR_EEPROM_VER1 &&
ee->ee_version < AR_EEPROM_VER3);
/* Match regulatory domain */
for (rd = 0; rd < AR_REG_DOMAINS_MAX; rd++)
if (AH_PRIVATE(ah)->ah_currentRD == ahp->ah_regDomain[rd])
if (AH_PRIVATE(ah)->ah_currentRD == ee->ee_regDomain[rd])
break;
if (rd == AR_REG_DOMAINS_MAX) {
#ifdef AH_DEBUG
@ -756,7 +774,7 @@ setupPowerSettings(struct ath_hal *ah, HAL_CHANNEL *chan, uint8_t cp[17])
/* Integer divide will set group from 0 to 4 */
group = group / 3;
pRD = &ahp->ah_tpc[group];
pRD = &ee->ee_tpc[group];
/* Set PC DAC Values */
cp[14] = pRD->regdmn[rd];
@ -773,7 +791,7 @@ setupPowerSettings(struct ath_hal *ah, HAL_CHANNEL *chan, uint8_t cp[17])
/* Power Scale if requested */
if (AH_PRIVATE(ah)->ah_tpScale != HAL_TP_SCALE_MAX) {
static const uint16_t tpcScaleReductionTable[5] =
{ 0, 3, 6, 9, MAX_RATE_POWER };
{ 0, 3, 6, 9, AR5210_MAX_RATE_POWER };
uint16_t tpScale;
tpScale = tpcScaleReductionTable[AH_PRIVATE(ah)->ah_tpScale];
@ -860,7 +878,7 @@ ar5210SetTransmitPower(struct ath_hal *ah, HAL_CHANNEL *chan)
for (i = 7; i < 15; i++)
cp[i] = ath_hal_reverseBits(cp[i], 6);
/* merge transmit power values into the register */
/* merge transmit power values into the register - quite gross */
pwr_regs[0] |= ((cp[1] << 5) & 0xE0) | (cp[0] & 0x1F);
pwr_regs[1] |= ((cp[3] << 7) & 0x80) | ((cp[2] << 2) & 0x7C) |
((cp[1] >> 3) & 0x03);

View File

@ -68,7 +68,7 @@ struct ar5210_desc {
/* TX ds_ctl1 */
#define AR_BufLen 0x00000fff /* data buffer length */
#define AR_More 0x00001000 /* more desc in this frame */
#define AR_EncryptKeyIdx 0x0007e000 /* encrypt key table index */
#define AR_EncryptKeyIdx 0x0007e000 /* ecnrypt key table index */
#define AR_EncryptKeyIdx_S 13
#define AR_RTSDuration 0xfff80000 /* lower 13bit of duration */

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ar5211.h,v 1.7 2008/11/10 04:08:02 sam Exp $
* $Id: ar5211.h,v 1.8 2008/11/10 22:08:47 sam Exp $
*/
#ifndef _ATH_AR5211_H_
#define _ATH_AR5211_H_
@ -155,6 +155,9 @@ extern HAL_BOOL ar5211PhyDisable(struct ath_hal *);
extern HAL_BOOL ar5211Disable(struct ath_hal *);
extern HAL_BOOL ar5211ChipReset(struct ath_hal *, uint16_t);
extern HAL_BOOL ar5211PerCalibration(struct ath_hal *, HAL_CHANNEL *, HAL_BOOL *);
extern HAL_BOOL ar5211PerCalibrationN(struct ath_hal *ah, HAL_CHANNEL *chan,
u_int chainMask, HAL_BOOL longCal, HAL_BOOL *isCalDone);
extern HAL_BOOL ar5211ResetCalValid(struct ath_hal *ah, HAL_CHANNEL *chan);
extern HAL_BOOL ar5211SetTxPowerLimit(struct ath_hal *, uint32_t limit);
extern HAL_BOOL ar5211SetTransmitPower(struct ath_hal *, HAL_CHANNEL *);
extern HAL_BOOL ar5211CalNoiseFloor(struct ath_hal *, HAL_CHANNEL_INTERNAL *);
@ -224,6 +227,9 @@ extern HAL_BOOL ar5211SetMacAddress(struct ath_hal *ah, const uint8_t *);
extern void ar5211GetBssIdMask(struct ath_hal *, uint8_t *);
extern HAL_BOOL ar5211SetBssIdMask(struct ath_hal *, const uint8_t *);
extern HAL_BOOL ar5211EepromRead(struct ath_hal *, u_int off, uint16_t *data);
extern HAL_BOOL ar5211EepromWrite(struct ath_hal *, u_int off, uint16_t data);
extern HAL_BOOL ar5211SetRegulatoryDomain(struct ath_hal *,
uint16_t, HAL_STATUS *);
extern u_int ar5211GetWirelessModes(struct ath_hal *);
extern void ar5211EnableRfKill(struct ath_hal *);
extern uint32_t ar5211GpioGet(struct ath_hal *, uint32_t gpio);

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ar5211_attach.c,v 1.8 2008/11/10 04:08:02 sam Exp $
* $Id: ar5211_attach.c,v 1.11 2008/11/27 22:29:52 sam Exp $
*/
#include "opt_ah.h"
@ -49,6 +49,8 @@ static const struct ath_hal_private ar5211hal = {{
.ah_disable = ar5211Disable,
.ah_setPCUConfig = ar5211SetPCUConfig,
.ah_perCalibration = ar5211PerCalibration,
.ah_perCalibrationN = ar5211PerCalibrationN,
.ah_resetCalValid = ar5211ResetCalValid,
.ah_setTxPowerLimit = ar5211SetTxPowerLimit,
.ah_getChanNoise = ath_hal_getChanNoise,
@ -96,6 +98,7 @@ static const struct ath_hal_private ar5211hal = {{
.ah_setMacAddress = ar5211SetMacAddress,
.ah_getBssIdMask = ar5211GetBssIdMask,
.ah_setBssIdMask = ar5211SetBssIdMask,
.ah_setRegulatoryDomain = ar5211SetRegulatoryDomain,
.ah_setLedState = ar5211SetLedState,
.ah_writeAssocid = ar5211WriteAssocid,
.ah_gpioCfgInput = ar5211GpioCfgInput,
@ -329,7 +332,7 @@ ar5211Attach(uint16_t devid, HAL_SOFTC sc,
}
AH_PRIVATE(ah)->ah_currentRD = eeval;
AH_PRIVATE(ah)->ah_getNfAdjust = ar5211GetNfAdjust;
/*
* Got everything we need now to setup the capabilities.
*/
@ -459,9 +462,6 @@ ar5211FillCapabilityInfo(struct ath_hal *ah)
struct ath_hal_private *ahpriv = AH_PRIVATE(ah);
HAL_CAPABILITIES *pCap = &ahpriv->ah_caps;
if (AH_PRIVATE(ah)->ah_currentRD == 1)
return AH_FALSE;
/* Construct wireless mode from EEPROM */
pCap->halWirelessModes = 0;
if (ath_hal_eepromGetFlag(ah, AR_EEP_AMODE)) {

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ar5211_interrupts.c,v 1.5 2008/11/10 04:08:02 sam Exp $
* $Id: ar5211_interrupts.c,v 1.6 2008/11/27 22:29:52 sam Exp $
*/
#include "opt_ah.h"
@ -67,7 +67,9 @@ ar5211GetPendingInterrupts(struct ath_hal *ah, HAL_INT *masked)
if (isr & (AR_ISR_TXOK | AR_ISR_TXDESC | AR_ISR_TXERR | AR_ISR_TXEOL))
*masked |= HAL_INT_TX;
/*
* RXORN can hang the receive path so we force a hardware
* Receive overrun is usually non-fatal on Oahu/Spirit.
* BUT on some parts rx could fail and the chip must be reset.
* So we force a hardware reset in all cases.
*/
if ((isr & AR_ISR_RXORN) && AH_PRIVATE(ah)->ah_rxornIsFatal) {
HALDEBUG(ah, HAL_DEBUG_ANY,

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ar5211_misc.c,v 1.6 2008/11/10 04:08:02 sam Exp $
* $Id: ar5211_misc.c,v 1.7 2008/11/27 22:29:52 sam Exp $
*/
#include "opt_ah.h"
@ -83,6 +83,55 @@ ar5211EepromRead(struct ath_hal *ah, u_int off, uint16_t *data)
return AH_TRUE;
}
#ifdef AH_SUPPORT_WRITE_EEPROM
/*
* Write 16 bits of data to the specified EEPROM offset.
*/
HAL_BOOL
ar5211EepromWrite(struct ath_hal *ah, u_int off, uint16_t data)
{
return AH_FALSE;
}
#endif /* AH_SUPPORT_WRITE_EEPROM */
/*
* Attempt to change the cards operating regulatory domain to the given value
*/
HAL_BOOL
ar5211SetRegulatoryDomain(struct ath_hal *ah,
uint16_t regDomain, HAL_STATUS *status)
{
HAL_STATUS ecode;
if (AH_PRIVATE(ah)->ah_currentRD == regDomain) {
ecode = HAL_EINVAL;
goto bad;
}
/*
* Check if EEPROM is configured to allow this; must
* be a proper version and the protection bits must
* permit re-writing that segment of the EEPROM.
*/
if (ath_hal_eepromGetFlag(ah, AR_EEP_WRITEPROTECT)) {
ecode = HAL_EEWRITE;
goto bad;
}
#ifdef AH_SUPPORT_WRITE_REGDOMAIN
if (ar5211EepromWrite(ah, AR_EEPROM_REG_DOMAIN, regDomain)) {
HALDEBUG(ah, HAL_DEBUG_ANY,
"%s: set regulatory domain to %u (0x%x)\n",
__func__, regDomain, regDomain);
AH_PRIVATE(ah)->ah_currentRD = regDomain;
return AH_TRUE;
}
#endif
ecode = HAL_EIO;
bad:
if (status)
*status = ecode;
return AH_FALSE;
}
/*
* Return the wireless modes (a,b,g,t) supported by hardware.
*
@ -292,11 +341,10 @@ ar5211GetTsf64(struct ath_hal *ah)
* then we re-reading AR_TSF_U32 does no good as the
* low bits will be meaningless. Likewise reading
* L32, U32, U32, then comparing the last two reads
* to check for rollover
* doesn't help if preempted--so we take this approach
* as it costs one less PCI read which can be noticeable
* when doing things like timestamping packets in
* monitor mode.
* to check for rollover doesn't help if preempted--so
* we take this approach as it costs one less PCI
* read which can be noticeable when doing things
* like timestamping packets in monitor mode.
*/
u32++;
}

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ar5211_reset.c,v 1.6 2008/11/10 04:08:03 sam Exp $
* $Id: ar5211_reset.c,v 1.9 2008/11/27 22:29:52 sam Exp $
*/
#include "opt_ah.h"
@ -222,7 +222,7 @@ uint32_t softLedCfg, softLedState;
* not accurate enough (e.g. 1 ms resolution).
* 2. It would still not be accurate.
*
* The most important aspect of this solution,
* The most important aspect of this workaround,
* is that, after reset, the TSF is behind
* other STAs TSFs. This will allow the STA to
* properly resynchronize its TSF in adhoc mode.
@ -408,7 +408,7 @@ uint32_t softLedCfg, softLedState;
/*
* for pre-Production Oahu only.
* Disable clock gating in all DMA blocks. Helps when using
* 11B and AES. This will result in higher power consumption.
* 11B and AES but results in higher power consumption.
*/
if (AH_PRIVATE(ah)->ah_macVersion == AR_SREV_VERSION_OAHU &&
AH_PRIVATE(ah)->ah_macRev < AR_SREV_OAHU_PROD) {
@ -665,7 +665,8 @@ ar5211ChipReset(struct ath_hal *ah, uint16_t channelFlags)
* changes.
*/
HAL_BOOL
ar5211PerCalibration(struct ath_hal *ah, HAL_CHANNEL *chan, HAL_BOOL *isIQdone)
ar5211PerCalibrationN(struct ath_hal *ah, HAL_CHANNEL *chan, u_int chainMask,
HAL_BOOL longCal, HAL_BOOL *isCalDone)
{
struct ath_hal_5211 *ahp = AH5211(ah);
HAL_CHANNEL_INTERNAL *ichan;
@ -729,31 +730,44 @@ ar5211PerCalibration(struct ath_hal *ah, HAL_CHANNEL *chan, HAL_BOOL *isIQdone)
OS_REG_WRITE(ah, AR_PHY_TIMING_CTRL4, data);
}
}
*isCalDone = !ahp->ah_bIQCalibration;
/* Perform noise floor and set status */
if (!ar5211IsNfGood(ah, ichan)) {
/* report up and clear internal state */
chan->channelFlags |= CHANNEL_CW_INT;
ichan->channelFlags &= ~CHANNEL_CW_INT;
return AH_FALSE;
}
if (!ar5211CalNoiseFloor(ah, ichan)) {
/*
* Delay 5ms before retrying the noise floor
* just to make sure, as we are in an error
* condition here.
*/
OS_DELAY(5000);
if (!ar5211CalNoiseFloor(ah, ichan)) {
if (!IS_CHAN_CCK(chan))
chan->channelFlags |= CHANNEL_CW_INT;
if (longCal) {
/* Perform noise floor and set status */
if (!ar5211IsNfGood(ah, ichan)) {
/* report up and clear internal state */
chan->channelFlags |= CHANNEL_CW_INT;
ichan->channelFlags &= ~CHANNEL_CW_INT;
return AH_FALSE;
}
if (!ar5211CalNoiseFloor(ah, ichan)) {
/*
* Delay 5ms before retrying the noise floor
* just to make sure, as we are in an error
* condition here.
*/
OS_DELAY(5000);
if (!ar5211CalNoiseFloor(ah, ichan)) {
if (!IS_CHAN_CCK(chan))
chan->channelFlags |= CHANNEL_CW_INT;
return AH_FALSE;
}
}
ar5211RequestRfgain(ah);
}
return AH_TRUE;
}
ar5211RequestRfgain(ah);
*isIQdone = !ahp->ah_bIQCalibration;
HAL_BOOL
ar5211PerCalibration(struct ath_hal *ah, HAL_CHANNEL *chan, HAL_BOOL *isIQdone)
{
return ar5211PerCalibrationN(ah, chan, 0x1, AH_TRUE, isIQdone);
}
HAL_BOOL
ar5211ResetCalValid(struct ath_hal *ah, HAL_CHANNEL *chan)
{
/* XXX */
return AH_TRUE;
}

View File

@ -364,7 +364,7 @@ ar5211ResetTxQueue(struct ath_hal *ah, u_int q)
#ifndef AH_DISABLE_WME
/*
* This is a really not the right way to do it, but
* Yes, this is a hack and not the right way to do it, but
* it does get the lockout bits and backoff set for the
* high-pri WME queues for testing. We need to either extend
* the meaning of queueInfo->mode, or create something like

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ar2316.c,v 1.8 2008/11/10 04:08:03 sam Exp $
* $Id: ar2316.c,v 1.9 2008/11/15 22:15:46 sam Exp $
*/
#include "opt_ah.h"
@ -519,8 +519,11 @@ ar2316SetPowerTable(struct ath_hal *ah,
int16_t minCalPower2316_t2;
uint16_t *pdadcValues = ahp->ah_pcdacTable;
uint16_t gainBoundaries[4];
uint32_t i, reg32, regoffset, tpcrg1;
int numPdGainsUsed;
uint32_t reg32, regoffset;
int i, numPdGainsUsed;
#ifndef AH_USE_INIPDGAIN
uint32_t tpcrg1;
#endif
HALDEBUG(ah, HAL_DEBUG_RFPARAM, "%s: chan 0x%x flag 0x%x\n",
__func__, chan->channel,chan->channelFlags);
@ -542,10 +545,16 @@ ar2316SetPowerTable(struct ath_hal *ah,
&minCalPower2316_t2,gainBoundaries, rfXpdGain, pdadcValues);
HALASSERT(1 <= numPdGainsUsed && numPdGainsUsed <= 3);
#if 0
#ifdef AH_USE_INIPDGAIN
/*
* Use pd_gains curve from eeprom; Atheros always uses
* the default curve from the ini file but some vendors
* (e.g. Zcomax) want to override this curve and not
* honoring their settings results in tx power 5dBm low.
*/
OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
(pRawDataset->pDataPerChannel[0].numPdGains - 1));
#endif
#else
tpcrg1 = OS_REG_READ(ah, AR_PHY_TPCRG1);
tpcrg1 = (tpcrg1 &~ AR_PHY_TPCRG1_NUM_PD_GAIN)
| SM(numPdGainsUsed-1, AR_PHY_TPCRG1_NUM_PD_GAIN);
@ -570,6 +579,7 @@ ar2316SetPowerTable(struct ath_hal *ah,
__func__, OS_REG_READ(ah, AR_PHY_TPCRG1), tpcrg1);
#endif
OS_REG_WRITE(ah, AR_PHY_TPCRG1, tpcrg1);
#endif
/*
* Note the pdadc table may not start at 0 dBm power, could be

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ar2317.c,v 1.7 2008/11/10 04:08:03 sam Exp $
* $Id: ar2317.c,v 1.8 2008/11/15 22:15:46 sam Exp $
*/
#include "opt_ah.h"
@ -496,8 +496,11 @@ ar2317SetPowerTable(struct ath_hal *ah,
int16_t minCalPower2317_t2;
uint16_t *pdadcValues = ahp->ah_pcdacTable;
uint16_t gainBoundaries[4];
uint32_t i, reg32, regoffset, tpcrg1;
int numPdGainsUsed;
uint32_t reg32, regoffset;
int i, numPdGainsUsed;
#ifndef AH_USE_INIPDGAIN
uint32_t tpcrg1;
#endif
HALDEBUG(ah, HAL_DEBUG_RFPARAM, "%s: chan 0x%x flag 0x%x\n",
__func__, chan->channel,chan->channelFlags);
@ -519,16 +522,16 @@ ar2317SetPowerTable(struct ath_hal *ah,
&minCalPower2317_t2,gainBoundaries, rfXpdGain, pdadcValues);
HALASSERT(1 <= numPdGainsUsed && numPdGainsUsed <= 3);
#ifdef AH_USE_INIPDGAIN
/*
* Use pd_gains curve from eeprom; Atheros always uses
* the default curve from the ini file but some vendors
* (e.g. Zcomax) want to override this curve and not
* honoring their settings results in tx power 5dBm low.
*/
#if 0
OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
(pRawDataset->pDataPerChannel[0].numPdGains - 1));
#endif
#else
tpcrg1 = OS_REG_READ(ah, AR_PHY_TPCRG1);
tpcrg1 = (tpcrg1 &~ AR_PHY_TPCRG1_NUM_PD_GAIN)
| SM(numPdGainsUsed-1, AR_PHY_TPCRG1_NUM_PD_GAIN);
@ -553,6 +556,7 @@ ar2317SetPowerTable(struct ath_hal *ah,
__func__, OS_REG_READ(ah, AR_PHY_TPCRG1), tpcrg1);
#endif
OS_REG_WRITE(ah, AR_PHY_TPCRG1, tpcrg1);
#endif
/*
* Note the pdadc table may not start at 0 dBm power, could be

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ar2413.c,v 1.7 2008/11/10 04:08:03 sam Exp $
* $Id: ar2413.c,v 1.8 2008/11/15 22:15:46 sam Exp $
*/
#include "opt_ah.h"
@ -513,8 +513,11 @@ ar2413SetPowerTable(struct ath_hal *ah,
int16_t minCalPower2413_t2;
uint16_t *pdadcValues = ahp->ah_pcdacTable;
uint16_t gainBoundaries[4];
uint32_t i, reg32, regoffset, tpcrg1;
int numPdGainsUsed;
uint32_t reg32, regoffset;
int i, numPdGainsUsed;
#ifndef AH_USE_INIPDGAIN
uint32_t tpcrg1;
#endif
HALDEBUG(ah, HAL_DEBUG_RFPARAM, "%s: chan 0x%x flag 0x%x\n",
__func__, chan->channel,chan->channelFlags);
@ -536,10 +539,16 @@ ar2413SetPowerTable(struct ath_hal *ah,
&minCalPower2413_t2,gainBoundaries, rfXpdGain, pdadcValues);
HALASSERT(1 <= numPdGainsUsed && numPdGainsUsed <= 3);
#if 0
#ifdef AH_USE_INIPDGAIN
/*
* Use pd_gains curve from eeprom; Atheros always uses
* the default curve from the ini file but some vendors
* (e.g. Zcomax) want to override this curve and not
* honoring their settings results in tx power 5dBm low.
*/
OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
(pRawDataset->pDataPerChannel[0].numPdGains - 1));
#endif
#else
tpcrg1 = OS_REG_READ(ah, AR_PHY_TPCRG1);
tpcrg1 = (tpcrg1 &~ AR_PHY_TPCRG1_NUM_PD_GAIN)
| SM(numPdGainsUsed-1, AR_PHY_TPCRG1_NUM_PD_GAIN);
@ -564,6 +573,7 @@ ar2413SetPowerTable(struct ath_hal *ah,
__func__, OS_REG_READ(ah, AR_PHY_TPCRG1), tpcrg1);
#endif
OS_REG_WRITE(ah, AR_PHY_TPCRG1, tpcrg1);
#endif
/*
* Note the pdadc table may not start at 0 dBm power, could be

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ar2425.c,v 1.7 2008/11/10 04:08:03 sam Exp $
* $Id: ar2425.c,v 1.8 2008/11/16 21:33:05 sam Exp $
*/
#include "opt_ah.h"
@ -160,12 +160,10 @@ ar2425SetRfRegs(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan, uint16_t modesIn
for (i = 0; i < N(ar5212Bank##_ix##_2425); i++) \
(_priv)->Bank##_ix##Data[i] = ar5212Bank##_ix##_2425[i][_col];\
} while (0)
struct ath_hal_5212 *ahp = AH5212(ah);
#if 0
uint16_t ob2GHz = 0, db2GHz = 0;
#endif
struct ath_hal_5212 *ahp = AH5212(ah);
const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
struct ar2425State *priv = AR2425(ah);
uint16_t ob2GHz = 0, db2GHz = 0;
int regWrites = 0;
HALDEBUG(ah, HAL_DEBUG_RFPARAM,
@ -173,24 +171,24 @@ ar2425SetRfRegs(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan, uint16_t modesIn
__func__, chan->channel, chan->channelFlags, modesIndex);
HALASSERT(priv);
#if 0
/* Setup rf parameters */
switch (chan->channelFlags & CHANNEL_ALL) {
case CHANNEL_B:
ob2GHz = ahp->ah_obFor24;
db2GHz = ahp->ah_dbFor24;
break;
case CHANNEL_G:
case CHANNEL_108G:
ob2GHz = ahp->ah_obFor24g;
db2GHz = ahp->ah_dbFor24g;
break;
default:
HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n",
__func__, chan->channelFlags);
return AH_FALSE;
}
#endif
switch (chan->channelFlags & CHANNEL_ALL) {
case CHANNEL_B:
ob2GHz = ee->ee_obFor24;
db2GHz = ee->ee_dbFor24;
break;
case CHANNEL_G:
case CHANNEL_108G:
ob2GHz = ee->ee_obFor24g;
db2GHz = ee->ee_dbFor24g;
break;
default:
HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n",
__func__, chan->channelFlags);
return AH_FALSE;
}
/* Bank 1 Write */
RF_BANK_SETUP(priv, 1, 1);
@ -202,10 +200,10 @@ ar2425SetRfRegs(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan, uint16_t modesIn
/* Bank 6 Write */
RF_BANK_SETUP(priv, 6, modesIndex);
#if 0
ar5212ModifyRfBuffer(priv->Bank6Data, ob2GHz, 3, 193, 0);
ar5212ModifyRfBuffer(priv->Bank6Data, db2GHz, 3, 190, 0);
#endif
/* Bank 7 Setup */
RF_BANK_SETUP(priv, 7, modesIndex);

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ar5212.h,v 1.9 2008/11/10 04:08:03 sam Exp $
* $Id: ar5212.h,v 1.16 2008/11/22 07:42:00 sam Exp $
*/
#ifndef _ATH_AR5212_H_
#define _ATH_AR5212_H_
@ -267,10 +267,12 @@ struct ath_hal_5212 {
uint32_t ah_txEolInterruptMask;
uint32_t ah_txUrnInterruptMask;
HAL_TX_QUEUE_INFO ah_txq[HAL_NUM_TX_QUEUES];
uint32_t ah_intrTxqs; /* tx q interrupt state */
/* decomp mask array */
uint8_t ah_decompMask[HAL_DECOMP_MASK_SIZE];
uint8_t ah_decompMask[HAL_DECOMP_MASK_SIZE];
HAL_POWER_MODE ah_powerMode;
HAL_ANT_SETTING ah_diversityControl; /* antenna setting */
HAL_ANT_SETTING ah_antControl; /* antenna setting */
HAL_BOOL ah_diversity; /* fast diversity setting */
enum {
IQ_CAL_INACTIVE,
IQ_CAL_RUNNING,
@ -283,6 +285,8 @@ struct ath_hal_5212 {
uint32_t ah_rssiThr; /* RSSI_THR settings */
HAL_BOOL ah_cwCalRequire; /* for ap51 */
HAL_BOOL ah_tpcEnabled; /* per-packet tpc enabled */
HAL_BOOL ah_phyPowerOn; /* PHY power state */
HAL_BOOL ah_isHb63; /* cached HB63 check */
uint32_t ah_macTPC; /* tpc register */
uint32_t ah_beaconInterval; /* XXX */
enum {
@ -301,18 +305,12 @@ struct ath_hal_5212 {
u_int ah_acktimeout; /* user-specified ack timeout */
u_int ah_ctstimeout; /* user-specified cts timeout */
u_int ah_sifstime; /* user-specified sifs time */
/*
* XXX
* 11g-specific stuff; belongs in the driver.
*/
uint8_t ah_gBeaconRate; /* fixed rate for G beacons */
/*
* RF Silent handling; setup according to the EEPROM.
*/
uint32_t ah_gpioSelect; /* GPIO pin to use */
uint32_t ah_polarity; /* polarity to disable RF */
uint32_t ah_gpioBit; /* after init, prev value */
HAL_BOOL ah_eepEnabled; /* EEPROM bit for capability */
/*
* ANI support.
*/
@ -330,30 +328,16 @@ struct ath_hal_5212 {
uint16_t *ah_pcdacTable;
u_int ah_pcdacTableSize;
uint16_t ah_ratesArray[16];
/*
* Tx queue interrupt state.
*/
uint32_t ah_intrTxqs;
HAL_BOOL ah_isHb63; /* cached HB63 check */
};
#define AH5212(_ah) ((struct ath_hal_5212 *)(_ah))
#define IS_5112(ah) \
((AH_PRIVATE(ah)->ah_analog5GhzRev&0xf0) >= AR_RAD5112_SREV_MAJOR \
&& (AH_PRIVATE(ah)->ah_analog5GhzRev&0xf0) < AR_RAD2316_SREV_MAJOR )
#define IS_RAD5112_REV1(ah) \
((AH_PRIVATE(ah)->ah_analog5GhzRev&0x0f) < (AR_RAD5112_SREV_2_0&0x0f))
#define IS_RADX112_REV2(ah) \
(IS_5112(ah) && \
((AH_PRIVATE(ah)->ah_analog5GhzRev == AR_RAD5112_SREV_2_0) || \
(AH_PRIVATE(ah)->ah_analog5GhzRev == AR_RAD2112_SREV_2_0) || \
(AH_PRIVATE(ah)->ah_analog5GhzRev == AR_RAD2112_SREV_2_1) || \
(AH_PRIVATE(ah)->ah_analog5GhzRev == AR_RAD5112_SREV_2_1)))
#define IS_5312_2_X(ah) \
(((AH_PRIVATE(ah)->ah_macVersion) == AR_SREV_VERSION_VENICE) && \
(((AH_PRIVATE(ah)->ah_macRev) == 2) || ((AH_PRIVATE(ah)->ah_macRev) == 7)))
/*
* IS_XXXX macros test the MAC version
* IS_RADXXX macros test the radio/RF version (matching both 2G-only and 2/5G)
*
* Some single chip radios have equivalent radio/RF (e.g. 5112)
* for those use IS_RADXXX_ANY macros.
*/
#define IS_2317(ah) \
((AH_PRIVATE(ah)->ah_devid == AR5212_AR2317_REV1) || \
(AH_PRIVATE(ah)->ah_devid == AR5212_AR2317_REV2))
@ -375,6 +359,29 @@ struct ath_hal_5212 {
#define IS_PCIE(ah) (IS_5424(ah) || IS_2425(ah))
#define AH_RADIO_MAJOR(ah) \
(AH_PRIVATE(ah)->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR)
#define AH_RADIO_MINOR(ah) \
(AH_PRIVATE(ah)->ah_analog5GhzRev & AR_RADIO_SREV_MINOR)
#define IS_RAD5111(ah) \
(AH_RADIO_MAJOR(ah) == AR_RAD5111_SREV_MAJOR || \
AH_RADIO_MAJOR(ah) == AR_RAD2111_SREV_MAJOR)
#define IS_RAD5112(ah) \
(AH_RADIO_MAJOR(ah) == AR_RAD5112_SREV_MAJOR || \
AH_RADIO_MAJOR(ah) == AR_RAD2112_SREV_MAJOR)
/* NB: does not include 5413 as Atheros' IS_5112 macro does */
#define IS_RAD5112_ANY(ah) \
(AR_RAD5112_SREV_MAJOR <= AH_RADIO_MAJOR(ah) && \
AH_RADIO_MAJOR(ah) <= AR_RAD2413_SREV_MAJOR)
#define IS_RAD5112_REV1(ah) \
(IS_RAD5112(ah) && \
AH_RADIO_MINOR(ah) < (AR_RAD5112_SREV_2_0 & AR_RADIO_SREV_MINOR))
#define IS_RADX112_REV2(ah) \
(AH_PRIVATE(ah)->ah_analog5GhzRev == AR_RAD5112_SREV_2_0 || \
AH_PRIVATE(ah)->ah_analog5GhzRev == AR_RAD2112_SREV_2_0 || \
AH_PRIVATE(ah)->ah_analog5GhzRev == AR_RAD2112_SREV_2_1 || \
AH_PRIVATE(ah)->ah_analog5GhzRev == AR_RAD5112_SREV_2_1)
#define ar5212RfDetach(ah) do { \
if (AH5212(ah)->ah_rfHal != AH_NULL) \
AH5212(ah)->ah_rfHal->rfDetach(ah); \
@ -534,7 +541,11 @@ extern void ar5212SetOperatingMode(struct ath_hal *ah, int opmode);
extern HAL_BOOL ar5212PhyDisable(struct ath_hal *ah);
extern HAL_BOOL ar5212Disable(struct ath_hal *ah);
extern HAL_BOOL ar5212ChipReset(struct ath_hal *ah, HAL_CHANNEL *);
extern HAL_BOOL ar5212PerCalibration(struct ath_hal *ah, HAL_CHANNEL *chan, HAL_BOOL *isIQdone);
extern HAL_BOOL ar5212PerCalibration(struct ath_hal *ah, HAL_CHANNEL *chan,
HAL_BOOL *isIQdone);
extern HAL_BOOL ar5212PerCalibrationN(struct ath_hal *ah, HAL_CHANNEL *chan,
u_int chainMask, HAL_BOOL longCal, HAL_BOOL *isCalDone);
extern HAL_BOOL ar5212ResetCalValid(struct ath_hal *ah, HAL_CHANNEL *chan);
extern int16_t ar5212GetNoiseFloor(struct ath_hal *ah);
extern void ar5212InitNfCalHistBuffer(struct ath_hal *);
extern int16_t ar5212GetNfHistMid(const int16_t calData[]);
@ -546,6 +557,7 @@ extern HAL_BOOL ar5212GetChipPowerLimits(struct ath_hal *ah,
HAL_CHANNEL *chans, uint32_t nchans);
extern void ar5212InitializeGainValues(struct ath_hal *);
extern HAL_RFGAIN ar5212GetRfgain(struct ath_hal *ah);
extern void ar5212RequestRfgain(struct ath_hal *);
extern HAL_BOOL ar5212UpdateTxTrigLevel(struct ath_hal *,
HAL_BOOL IncTrigLevel);

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ar5212_ani.c,v 1.5 2008/11/10 04:08:03 sam Exp $
* $Id: ar5212_ani.c,v 1.7 2008/11/21 00:16:21 sam Exp $
*/
#include "opt_ah.h"
@ -435,13 +435,17 @@ ar5212AniOfdmErrTrigger(struct ath_hal *ah)
aniState = ahp->ah_curani;
params = aniState->params;
/* First, raise noise immunity level, up to max */
if (aniState->noiseImmunityLevel < params->maxNoiseImmunityLevel) {
if (aniState->noiseImmunityLevel+1 < params->maxNoiseImmunityLevel) {
HALDEBUG(ah, HAL_DEBUG_ANI, "%s: raise NI to %u\n", __func__,
aniState->noiseImmunityLevel + 1);
ar5212AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL,
aniState->noiseImmunityLevel + 1);
return;
}
/* then, raise spur immunity level, up to max */
if (aniState->spurImmunityLevel < params->maxSpurImmunityLevel) {
if (aniState->spurImmunityLevel+1 < params->maxSpurImmunityLevel) {
HALDEBUG(ah, HAL_DEBUG_ANI, "%s: raise SI to %u\n", __func__,
aniState->spurImmunityLevel + 1);
ar5212AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL,
aniState->spurImmunityLevel + 1);
return;
@ -455,6 +459,8 @@ ar5212AniOfdmErrTrigger(struct ath_hal *ah)
* weak sig detect.
*/
if (!aniState->ofdmWeakSigDetectOff) {
HALDEBUG(ah, HAL_DEBUG_ANI,
"%s: rssi %d OWSD off\n", __func__, rssi);
ar5212AniControl(ah,
HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
AH_FALSE);
@ -466,7 +472,10 @@ ar5212AniOfdmErrTrigger(struct ath_hal *ah)
* If weak sig detect is already off, as last resort,
* raise firstep level
*/
if (aniState->firstepLevel < params->maxFirstepLevel) {
if (aniState->firstepLevel+1 < params->maxFirstepLevel) {
HALDEBUG(ah, HAL_DEBUG_ANI,
"%s: rssi %d raise ST %u\n", __func__, rssi,
aniState->firstepLevel+1);
ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
aniState->firstepLevel + 1);
return;
@ -476,13 +485,20 @@ ar5212AniOfdmErrTrigger(struct ath_hal *ah)
* Beacon rssi in mid range, need ofdm weak signal
* detect, but we can raise firststepLevel.
*/
if (aniState->ofdmWeakSigDetectOff)
if (aniState->ofdmWeakSigDetectOff) {
HALDEBUG(ah, HAL_DEBUG_ANI,
"%s: rssi %d OWSD on\n", __func__, rssi);
ar5212AniControl(ah,
HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
AH_TRUE);
if (aniState->firstepLevel < params->maxFirstepLevel)
}
if (aniState->firstepLevel+1 < params->maxFirstepLevel) {
HALDEBUG(ah, HAL_DEBUG_ANI,
"%s: rssi %d raise ST %u\n", __func__, rssi,
aniState->firstepLevel+1);
ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
aniState->firstepLevel + 1);
}
return;
} else {
/*
@ -492,13 +508,22 @@ ar5212AniOfdmErrTrigger(struct ath_hal *ah)
*/
/* XXX can optimize */
if (IS_CHAN_B(chan) || IS_CHAN_G(chan)) {
if (!aniState->ofdmWeakSigDetectOff)
if (!aniState->ofdmWeakSigDetectOff) {
HALDEBUG(ah, HAL_DEBUG_ANI,
"%s: rssi %d OWSD off\n",
__func__, rssi);
ar5212AniControl(ah,
HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
AH_FALSE);
if (aniState->firstepLevel > 0)
}
if (aniState->firstepLevel > 0) {
HALDEBUG(ah, HAL_DEBUG_ANI,
"%s: rssi %d zero ST (was %u)\n",
__func__, rssi,
aniState->firstepLevel);
ar5212AniControl(ah,
HAL_ANI_FIRSTEP_LEVEL, 0);
}
return;
}
}
@ -521,7 +546,9 @@ ar5212AniCckErrTrigger(struct ath_hal *ah)
/* first, raise noise immunity level, up to max */
aniState = ahp->ah_curani;
params = aniState->params;
if (aniState->noiseImmunityLevel < params->maxNoiseImmunityLevel) {
if (aniState->noiseImmunityLevel+1 < params->maxNoiseImmunityLevel) {
HALDEBUG(ah, HAL_DEBUG_ANI, "%s: raise NI to %u\n", __func__,
aniState->noiseImmunityLevel + 1);
ar5212AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL,
aniState->noiseImmunityLevel + 1);
return;
@ -534,9 +561,13 @@ ar5212AniCckErrTrigger(struct ath_hal *ah)
* Beacon signal in mid and high range,
* raise firstep level.
*/
if (aniState->firstepLevel < params->maxFirstepLevel)
if (aniState->firstepLevel+1 < params->maxFirstepLevel) {
HALDEBUG(ah, HAL_DEBUG_ANI,
"%s: rssi %d raise ST %u\n", __func__, rssi,
aniState->firstepLevel+1);
ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
aniState->firstepLevel + 1);
}
} else {
/*
* Beacon rssi is low, zero firstep level to maximize
@ -544,9 +575,14 @@ ar5212AniCckErrTrigger(struct ath_hal *ah)
*/
/* XXX can optimize */
if (IS_CHAN_B(chan) || IS_CHAN_G(chan)) {
if (aniState->firstepLevel > 0)
if (aniState->firstepLevel > 0) {
HALDEBUG(ah, HAL_DEBUG_ANI,
"%s: rssi %d zero ST (was %u)\n",
__func__, rssi,
aniState->firstepLevel);
ar5212AniControl(ah,
HAL_ANI_FIRSTEP_LEVEL, 0);
}
}
}
}
@ -564,9 +600,6 @@ ar5212AniRestart(struct ath_hal *ah, struct ar5212AniState *aniState)
* NB: these are written on reset based on the
* ini so we must re-write them!
*/
HALDEBUG(ah, HAL_DEBUG_ANI,
"%s: Writing ofdmbase=%u cckbase=%u\n", __func__,
params->ofdmPhyErrBase, params->cckPhyErrBase);
OS_REG_WRITE(ah, AR_PHYCNT1, params->ofdmPhyErrBase);
OS_REG_WRITE(ah, AR_PHYCNT2, params->cckPhyErrBase);
OS_REG_WRITE(ah, AR_PHYCNTMASK1, AR_PHY_ERR_OFDM_TIMING);
@ -781,12 +814,17 @@ ar5212AniLowerImmunity(struct ath_hal *ah)
* detection or lower firstep level.
*/
if (aniState->ofdmWeakSigDetectOff) {
HALDEBUG(ah, HAL_DEBUG_ANI,
"%s: rssi %d OWSD on\n", __func__, rssi);
ar5212AniControl(ah,
HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
AH_TRUE);
return;
}
if (aniState->firstepLevel > 0) {
HALDEBUG(ah, HAL_DEBUG_ANI,
"%s: rssi %d lower ST %u\n", __func__, rssi,
aniState->firstepLevel-1);
ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
aniState->firstepLevel - 1);
return;
@ -796,6 +834,9 @@ ar5212AniLowerImmunity(struct ath_hal *ah)
* Beacon rssi is low, reduce firstep level.
*/
if (aniState->firstepLevel > 0) {
HALDEBUG(ah, HAL_DEBUG_ANI,
"%s: rssi %d lower ST %u\n", __func__, rssi,
aniState->firstepLevel-1);
ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
aniState->firstepLevel - 1);
return;
@ -804,6 +845,8 @@ ar5212AniLowerImmunity(struct ath_hal *ah)
}
/* then lower spur immunity level, down to zero */
if (aniState->spurImmunityLevel > 0) {
HALDEBUG(ah, HAL_DEBUG_ANI, "%s: lower SI %u\n",
__func__, aniState->spurImmunityLevel-1);
ar5212AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL,
aniState->spurImmunityLevel - 1);
return;
@ -813,6 +856,8 @@ ar5212AniLowerImmunity(struct ath_hal *ah)
* zero for now
*/
if (aniState->noiseImmunityLevel > 0) {
HALDEBUG(ah, HAL_DEBUG_ANI, "%s: lower NI %u\n",
__func__, aniState->noiseImmunityLevel-1);
ar5212AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL,
aniState->noiseImmunityLevel - 1);
return;
@ -956,10 +1001,16 @@ ar5212AniPoll(struct ath_hal *ah, const HAL_NODE_STATS *stats,
/* check to see if need to raise immunity */
if (aniState->ofdmPhyErrCount > aniState->listenTime *
params->ofdmTrigHigh / 1000) {
HALDEBUG(ah, HAL_DEBUG_ANI,
"%s: OFDM err %u listenTime %u\n", __func__,
aniState->ofdmPhyErrCount, aniState->listenTime);
ar5212AniOfdmErrTrigger(ah);
ar5212AniRestart(ah, aniState);
} else if (aniState->cckPhyErrCount > aniState->listenTime *
params->cckTrigHigh / 1000) {
HALDEBUG(ah, HAL_DEBUG_ANI,
"%s: CCK err %u listenTime %u\n", __func__,
aniState->cckPhyErrCount, aniState->listenTime);
ar5212AniCckErrTrigger(ah);
ar5212AniRestart(ah, aniState);
}

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ar5212_attach.c,v 1.12 2008/11/10 04:08:03 sam Exp $
* $Id: ar5212_attach.c,v 1.18 2008/11/19 22:10:42 sam Exp $
*/
#include "opt_ah.h"
@ -56,6 +56,8 @@ static const struct ath_hal_private ar5212hal = {{
.ah_disable = ar5212Disable,
.ah_setPCUConfig = ar5212SetPCUConfig,
.ah_perCalibration = ar5212PerCalibration,
.ah_perCalibrationN = ar5212PerCalibrationN,
.ah_resetCalValid = ar5212ResetCalValid,
.ah_setTxPowerLimit = ar5212SetTxPowerLimit,
.ah_getChanNoise = ath_hal_getChanNoise,
@ -103,6 +105,7 @@ static const struct ath_hal_private ar5212hal = {{
.ah_setMacAddress = ar5212SetMacAddress,
.ah_getBssIdMask = ar5212GetBssIdMask,
.ah_setBssIdMask = ar5212SetBssIdMask,
.ah_setRegulatoryDomain = ar5212SetRegulatoryDomain,
.ah_setLedState = ar5212SetLedState,
.ah_writeAssocid = ar5212WriteAssocid,
.ah_gpioCfgInput = ar5212GpioCfgInput,
@ -271,7 +274,8 @@ ar5212InitState(struct ath_hal_5212 *ahp, uint16_t devid, HAL_SOFTC sc,
AH_PRIVATE(ah)->ah_powerLimit = MAX_RATE_POWER;
AH_PRIVATE(ah)->ah_tpScale = HAL_TP_SCALE_MAX; /* no scaling */
ahp->ah_diversityControl = HAL_ANT_VARIABLE;
ahp->ah_antControl = HAL_ANT_VARIABLE;
ahp->ah_diversity = AH_TRUE;
ahp->ah_bIQCalibration = AH_FALSE;
/*
* Enable MIC handling.
@ -279,6 +283,7 @@ ar5212InitState(struct ath_hal_5212 *ahp, uint16_t devid, HAL_SOFTC sc,
ahp->ah_staId1Defaults = AR_STA_ID1_CRPT_MIC_ENABLE;
ahp->ah_rssiThr = INIT_RSSI_THR;
ahp->ah_tpcEnabled = AH_FALSE; /* disabled by default */
ahp->ah_phyPowerOn = AH_FALSE;
ahp->ah_macTPC = SM(MAX_RATE_POWER, AR_TPC_ACK)
| SM(MAX_RATE_POWER, AR_TPC_CTS)
| SM(MAX_RATE_POWER, AR_TPC_CHIRP);
@ -289,11 +294,6 @@ ar5212InitState(struct ath_hal_5212 *ahp, uint16_t devid, HAL_SOFTC sc,
ahp->ah_ctstimeout = (u_int) -1;
ahp->ah_sifstime = (u_int) -1;
OS_MEMCPY(&ahp->ah_bssidmask, defbssidmask, IEEE80211_ADDR_LEN);
/*
* 11g-specific stuff
*/
ahp->ah_gBeaconRate = 0; /* adhoc beacon fixed rate */
#undef N
}
@ -444,15 +444,18 @@ ar5212Attach(uint16_t devid, HAL_SOFTC sc,
break;
}
if (IS_2413(ah)) { /* Griffin */
AH_PRIVATE(ah)->ah_analog5GhzRev = 0x51;
AH_PRIVATE(ah)->ah_analog5GhzRev =
AR_RAD2413_SREV_MAJOR | 0x1;
break;
}
if (IS_5413(ah)) { /* Eagle */
AH_PRIVATE(ah)->ah_analog5GhzRev = 0x62;
AH_PRIVATE(ah)->ah_analog5GhzRev =
AR_RAD5413_SREV_MAJOR | 0x2;
break;
}
if (IS_2425(ah) || IS_2417(ah)) {/* Swan or Nala */
AH_PRIVATE(ah)->ah_analog5GhzRev = 0xA2;
AH_PRIVATE(ah)->ah_analog5GhzRev =
AR_RAD5424_SREV_MAJOR | 0x2;
break;
}
}
@ -465,7 +468,7 @@ ar5212Attach(uint16_t devid, HAL_SOFTC sc,
goto bad;
#endif
}
if (!IS_5413(ah) && IS_5112(ah) && IS_RAD5112_REV1(ah)) {
if (IS_RAD5112_REV1(ah)) {
HALDEBUG(ah, HAL_DEBUG_ANY,
"%s: 5112 Rev 1 is not supported by this "
"driver (analog5GhzRev 0x%x)\n", __func__,
@ -565,7 +568,7 @@ ar5212Attach(uint16_t devid, HAL_SOFTC sc,
#else
ecode = HAL_ENOTSUPP;
#endif
else if (IS_5112(ah))
else if (IS_RAD5112(ah))
#ifdef AH_SUPPORT_5112
rfStatus = ar5112RfAttach(ah, &ecode);
#else
@ -577,7 +580,7 @@ ar5212Attach(uint16_t devid, HAL_SOFTC sc,
#else
ecode = HAL_ENOTSUPP;
#endif
else
else if (IS_RAD5111(ah))
#ifdef AH_SUPPORT_5111
rfStatus = ar5111RfAttach(ah, &ecode);
#else
@ -788,7 +791,8 @@ ar5212FillCapabilityInfo(struct ath_hal *ah)
}
pCap->halLow2GhzChan = 2312;
if (IS_5112(ah) || IS_2413(ah) || IS_5413(ah) || IS_2425(ah))
/* XXX 2417 too? */
if (IS_RAD5112_ANY(ah) || IS_5413(ah) || IS_2425(ah) || IS_2417(ah))
pCap->halHigh2GhzChan = 2500;
else
pCap->halHigh2GhzChan = 2732;
@ -850,14 +854,8 @@ ar5212FillCapabilityInfo(struct ath_hal *ah)
else
pCap->halKeyCacheSize = AR_KEYTABLE_SIZE;
if (IS_5112(ah)) {
pCap->halChanHalfRate = AH_TRUE;
pCap->halChanQuarterRate = AH_TRUE;
} else {
/* XXX not needed */
pCap->halChanHalfRate = AH_FALSE;
pCap->halChanQuarterRate = AH_FALSE;
}
pCap->halChanHalfRate = AH_TRUE;
pCap->halChanQuarterRate = AH_TRUE;
if (ath_hal_eepromGetFlag(ah, AR_EEP_RFKILL) &&
ath_hal_eepromGet(ah, AR_EEP_RFSILENT, &ahpriv->ah_rfsilent) == HAL_OK) {

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ar5212_interrupts.c,v 1.5 2008/11/10 04:08:03 sam Exp $
* $Id: ar5212_interrupts.c,v 1.6 2008/11/27 22:30:00 sam Exp $
*/
#include "opt_ah.h"
@ -96,7 +96,9 @@ ar5212GetPendingInterrupts(struct ath_hal *ah, HAL_INT *masked)
}
/*
* RXORN can hang the receive path so we force a hardware
* Receive overrun is usually non-fatal on Oahu/Spirit.
* BUT on some parts rx could fail and the chip must be reset.
* So we force a hardware reset in all cases.
*/
if ((isr & AR_ISR_RXORN) && AH_PRIVATE(ah)->ah_rxornIsFatal) {
HALDEBUG(ah, HAL_DEBUG_ANY,

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ar5212_misc.c,v 1.8 2008/11/10 04:08:03 sam Exp $
* $Id: ar5212_misc.c,v 1.12 2008/11/27 22:30:00 sam Exp $
*/
#include "opt_ah.h"
@ -79,12 +79,44 @@ ar5212SetBssIdMask(struct ath_hal *ah, const uint8_t *mask)
return AH_TRUE;
}
/*
* Attempt to change the cards operating regulatory domain to the given value
*/
HAL_BOOL
ar5212SetRegulatoryDomain(struct ath_hal *ah,
uint16_t regDomain, HAL_STATUS *status)
{
HAL_STATUS ecode;
if (AH_PRIVATE(ah)->ah_currentRD == regDomain) {
ecode = HAL_EINVAL;
goto bad;
}
if (ath_hal_eepromGetFlag(ah, AR_EEP_WRITEPROTECT)) {
ecode = HAL_EEWRITE;
goto bad;
}
#ifdef AH_SUPPORT_WRITE_REGDOMAIN
if (ath_hal_eepromWrite(ah, AR_EEPROM_REG_DOMAIN, regDomain)) {
HALDEBUG(ah, HAL_DEBUG_ANY,
"%s: set regulatory domain to %u (0x%x)\n",
__func__, regDomain, regDomain);
AH_PRIVATE(ah)->ah_currentRD = regDomain;
return AH_TRUE;
}
#endif
ecode = HAL_EIO;
bad:
if (status)
*status = ecode;
return AH_FALSE;
}
/*
* Return the wireless modes (a,b,g,t) supported by hardware.
*
* This value is what is actually supported by the hardware
* and is unaffected by regulatory/country code settings.
*
*/
u_int
ar5212GetWirelessModes(struct ath_hal *ah)
@ -95,6 +127,10 @@ ar5212GetWirelessModes(struct ath_hal *ah)
mode = HAL_MODE_11A;
if (!ath_hal_eepromGetFlag(ah, AR_EEP_TURBO5DISABLE))
mode |= HAL_MODE_TURBO | HAL_MODE_108A;
if (AH_PRIVATE(ah)->ah_caps.halChanHalfRate)
mode |= HAL_MODE_11A_HALF_RATE;
if (AH_PRIVATE(ah)->ah_caps.halChanQuarterRate)
mode |= HAL_MODE_11A_QUARTER_RATE;
}
if (ath_hal_eepromGetFlag(ah, AR_EEP_BMODE))
mode |= HAL_MODE_11B;
@ -103,6 +139,10 @@ ar5212GetWirelessModes(struct ath_hal *ah)
mode |= HAL_MODE_11G;
if (!ath_hal_eepromGetFlag(ah, AR_EEP_TURBO2DISABLE))
mode |= HAL_MODE_108G;
if (AH_PRIVATE(ah)->ah_caps.halChanHalfRate)
mode |= HAL_MODE_11G_HALF_RATE;
if (AH_PRIVATE(ah)->ah_caps.halChanQuarterRate)
mode |= HAL_MODE_11G_QUARTER_RATE;
}
return mode;
}
@ -212,11 +252,10 @@ ar5212GetTsf64(struct ath_hal *ah)
* then we re-reading AR_TSF_U32 does no good as the
* low bits will be meaningless. Likewise reading
* L32, U32, U32, then comparing the last two reads
* to check for rollover
* doesn't help if preempted--so we take this approach
* as it costs one less PCI read which can be noticeable
* when doing things like timestamping packets in
* monitor mode.
* to check for rollover doesn't help if preempted--so
* we take this approach as it costs one less PCI read
* which can be noticeable when doing things like
* timestamping packets in monitor mode.
*/
u32++;
}
@ -382,19 +421,22 @@ ar5212SetDefAntenna(struct ath_hal *ah, u_int antenna)
HAL_ANT_SETTING
ar5212GetAntennaSwitch(struct ath_hal *ah)
{
return AH5212(ah)->ah_diversityControl;
return AH5212(ah)->ah_antControl;
}
HAL_BOOL
ar5212SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING settings)
ar5212SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING setting)
{
const HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan;
struct ath_hal_5212 *ahp = AH5212(ah);
const HAL_CHANNEL_INTERNAL *ichan = AH_PRIVATE(ah)->ah_curchan;
if (chan == AH_NULL) {
AH5212(ah)->ah_diversityControl = settings;
if (!ahp->ah_phyPowerOn || ichan == AH_NULL) {
/* PHY powered off, just stash settings */
ahp->ah_antControl = setting;
ahp->ah_diversity = (setting == HAL_ANT_VARIABLE);
return AH_TRUE;
}
return ar5212SetAntennaSwitchInternal(ah, settings, chan);
return ar5212SetAntennaSwitchInternal(ah, setting, ichan);
}
HAL_BOOL
@ -632,7 +674,8 @@ ar5212SetupClock(struct ath_hal *ah, HAL_OPMODE opmode)
* from A2.
*/
OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f);
OS_REG_WRITE(ah, AR_PHY_REFCLKPD, IS_5112(ah) ? 0x14 : 0x18);
OS_REG_WRITE(ah, AR_PHY_REFCLKPD,
IS_RAD5112_ANY(ah) || IS_5413(ah) ? 0x14 : 0x18);
OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, 1);
OS_REG_WRITE(ah, AR_TSF_PARM, 61); /* 32 KHz TSF incr */
OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_SEL, 1);
@ -669,8 +712,9 @@ ar5212SetupClock(struct ath_hal *ah, HAL_OPMODE opmode)
OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x0c);
OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0xff);
OS_REG_WRITE(ah, AR_PHY_REFCLKPD,
IS_5112(ah) || IS_2417(ah) ? 0x14 : 0x18);
OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, IS_5112(ah) ? 39 : 31);
IS_RAD5112_ANY(ah) || IS_5413(ah) || IS_2417(ah) ? 0x14 : 0x18);
OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32,
IS_RAD5112_ANY(ah) || IS_5413(ah) ? 39 : 31);
}
}
@ -686,7 +730,8 @@ ar5212RestoreClock(struct ath_hal *ah, HAL_OPMODE opmode)
OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_SEL, 0);
OS_REG_WRITE(ah, AR_TSF_PARM, 1); /* 32 MHz TSF incr */
OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, IS_5112(ah) ? 39 : 31);
OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32,
IS_RAD5112_ANY(ah) || IS_5413(ah) ? 39 : 31);
/*
* Restore BB registers to power-on defaults
@ -696,7 +741,8 @@ ar5212RestoreClock(struct ath_hal *ah, HAL_OPMODE opmode)
OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e);
OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x0c);
OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0xff);
OS_REG_WRITE(ah, AR_PHY_REFCLKPD, IS_5112(ah) ? 0x14 : 0x18);
OS_REG_WRITE(ah, AR_PHY_REFCLKPD,
IS_RAD5112_ANY(ah) || IS_5413(ah) ? 0x14 : 0x18);
}
}
@ -782,9 +828,7 @@ ar5212GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
case 0: /* hardware capability */
return HAL_OK;
case 1: /* current setting */
return (OS_REG_READ(ah, AR_PHY_CCK_DETECT) &
AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV) ?
HAL_OK : HAL_ENXIO;
return ahp->ah_diversity ? HAL_OK : HAL_ENXIO;
}
return HAL_EINVAL;
case HAL_CAP_DIAG:
@ -892,12 +936,15 @@ ar5212SetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
OS_REG_WRITE(ah, AR_MISC_MODE, ahp->ah_miscMode);
return AH_TRUE;
case HAL_CAP_DIVERSITY:
v = OS_REG_READ(ah, AR_PHY_CCK_DETECT);
if (setting)
v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
else
v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, v);
if (ahp->ah_phyPowerOn) {
v = OS_REG_READ(ah, AR_PHY_CCK_DETECT);
if (setting)
v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
else
v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, v);
}
ahp->ah_diversity = (setting != 0);
return AH_TRUE;
case HAL_CAP_DIAG: /* hardware diagnostic support */
/*

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ar5212_phy.c,v 1.4 2008/11/10 01:19:38 sam Exp $
* $Id: ar5212_phy.c,v 1.5 2008/11/15 03:43:53 sam Exp $
*/
#include "opt_ah.h"
@ -47,7 +47,7 @@ HAL_RATE_TABLE ar5212_11a_table = {
},
};
HAL_RATE_TABLE ar5212_11a_half_table = {
HAL_RATE_TABLE ar5212_half_table = {
8, /* number of rates */
{ 0 },
{
@ -64,7 +64,7 @@ HAL_RATE_TABLE ar5212_11a_half_table = {
},
};
HAL_RATE_TABLE ar5212_11a_quarter_table = {
HAL_RATE_TABLE ar5212_quarter_table = {
8, /* number of rates */
{ 0 },
{
@ -184,10 +184,12 @@ ar5212GetRateTable(struct ath_hal *ah, u_int mode)
rt = &ar5212_turbog_table;
break;
case HAL_MODE_11A_HALF_RATE:
rt = &ar5212_11a_half_table;
case HAL_MODE_11G_HALF_RATE:
rt = &ar5212_half_table;
break;
case HAL_MODE_11A_QUARTER_RATE:
rt = &ar5212_11a_quarter_table;
case HAL_MODE_11G_QUARTER_RATE:
rt = &ar5212_quarter_table;
break;
default:
HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid mode 0x%x\n",

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ar5212_reset.c,v 1.12 2008/11/10 04:08:03 sam Exp $
* $Id: ar5212_reset.c,v 1.20 2008/11/27 22:30:00 sam Exp $
*/
#include "opt_ah.h"
@ -47,32 +47,23 @@ void ar5212SetDeltaSlope(struct ath_hal *, HAL_CHANNEL *);
HAL_BOOL ar5212SetTransmitPower(struct ath_hal *ah,
HAL_CHANNEL_INTERNAL *chan, uint16_t *rfXpdGain);
static HAL_BOOL ar5212SetRateTable(struct ath_hal *,
HAL_CHANNEL *, int16_t tpcScaleReduction, int16_t powerLimit,
HAL_BOOL commit,
int16_t *minPower, int16_t *maxPower);
HAL_CHANNEL *, int16_t tpcScaleReduction, int16_t powerLimit,
HAL_BOOL commit, int16_t *minPower, int16_t *maxPower);
static void ar5212CorrectGainDelta(struct ath_hal *, int twiceOfdmCckDelta);
static void ar5212GetTargetPowers(struct ath_hal *, HAL_CHANNEL *,
const TRGT_POWER_INFO *pPowerInfo, uint16_t numChannels,
TRGT_POWER_INFO *pNewPower);
const TRGT_POWER_INFO *pPowerInfo, uint16_t numChannels,
TRGT_POWER_INFO *pNewPower);
static uint16_t ar5212GetMaxEdgePower(uint16_t channel,
const RD_EDGES_POWER *pRdEdgesPower);
static void ar5212RequestRfgain(struct ath_hal *);
static HAL_BOOL ar5212InvalidGainReadback(struct ath_hal *, GAIN_VALUES *);
static HAL_BOOL ar5212IsGainAdjustNeeded(struct ath_hal *, const GAIN_VALUES *);
static int32_t ar5212AdjustGain(struct ath_hal *, GAIN_VALUES *);
const RD_EDGES_POWER *pRdEdgesPower);
void ar5212SetRateDurationTable(struct ath_hal *, HAL_CHANNEL *);
static uint32_t ar5212GetRfField(uint32_t *rfBuf, uint32_t numBits,
uint32_t firstBit, uint32_t column);
static void ar5212GetGainFCorrection(struct ath_hal *ah);
HAL_BOOL ar5212SetXrMode(struct ath_hal *ah, HAL_OPMODE opmode,HAL_CHANNEL *chan);
void ar5212SetIFSTiming(struct ath_hal *, HAL_CHANNEL *);
void ar5212SetIFSTiming(struct ath_hal *, HAL_CHANNEL *);
/* NB: public for RF backend use */
void ar5212GetLowerUpperValues(uint16_t value,
uint16_t *pList, uint16_t listSize,
uint16_t *pLowerValue, uint16_t *pUpperValue);
void ar5212ModifyRfBuffer(uint32_t *rfBuf, uint32_t reg32,
uint32_t numBits, uint32_t firstBit, uint32_t column);
void ar5212GetLowerUpperValues(uint16_t value,
uint16_t *pList, uint16_t listSize,
uint16_t *pLowerValue, uint16_t *pUpperValue);
void ar5212ModifyRfBuffer(uint32_t *rfBuf, uint32_t reg32,
uint32_t numBits, uint32_t firstBit, uint32_t column);
static int
write_common(struct ath_hal *ah, const HAL_INI_ARRAY *ia,
@ -463,8 +454,9 @@ ar5212Reset(struct ath_hal *ah, HAL_OPMODE opmode,
ar5212SetRateDurationTable(ah, chan);
/* Set Tx frame start to tx data start delay */
if (IS_5112(ah) && (IS_CHAN_HALF_RATE(AH_PRIVATE(ah)->ah_curchan) ||
IS_CHAN_QUARTER_RATE(AH_PRIVATE(ah)->ah_curchan))) {
if (IS_RAD5112_ANY(ah) &&
(IS_CHAN_HALF_RATE(AH_PRIVATE(ah)->ah_curchan) ||
IS_CHAN_QUARTER_RATE(AH_PRIVATE(ah)->ah_curchan))) {
txFrm2TxDStart =
(IS_CHAN_HALF_RATE(AH_PRIVATE(ah)->ah_curchan)) ?
TX_FRAME_D_START_HALF_RATE:
@ -906,7 +898,7 @@ ar5212ChipReset(struct ath_hal *ah, HAL_CHANNEL *chan)
if (chan != AH_NULL) { /* NB: can be null during attach */
uint32_t rfMode, phyPLL = 0, curPhyPLL, turbo;
if (IS_5413(ah)) {
if (IS_5413(ah)) { /* NB: =>'s 5424 also */
rfMode = AR_PHY_MODE_AR5112;
if (IS_CHAN_HALF_RATE(chan))
rfMode |= AR_PHY_MODE_HALF;
@ -917,33 +909,26 @@ ar5212ChipReset(struct ath_hal *ah, HAL_CHANNEL *chan)
phyPLL = AR_PHY_PLL_CTL_44_5112;
else
phyPLL = AR_PHY_PLL_CTL_40_5413;
}
else if (IS_5112(ah) || IS_2413(ah) || IS_2425(ah) || IS_2417(ah)) {
rfMode = AR_PHY_MODE_AR5112;
if (IS_CHAN_CCK(chan) || IS_CHAN_G(chan)) {
phyPLL = AR_PHY_PLL_CTL_44_5112;
} else {
if (IS_CHAN_HALF_RATE(chan)) {
phyPLL = AR_PHY_PLL_CTL_40_5112_HALF;
} else if (IS_CHAN_QUARTER_RATE(chan)) {
phyPLL = AR_PHY_PLL_CTL_40_5112_QUARTER;
} else {
phyPLL = AR_PHY_PLL_CTL_40_5112;
}
}
} else {
} else if (IS_RAD5111(ah)) {
rfMode = AR_PHY_MODE_AR5111;
if (IS_CHAN_CCK(chan) || IS_CHAN_G(chan)) {
if (IS_CHAN_CCK(chan) || IS_CHAN_G(chan))
phyPLL = AR_PHY_PLL_CTL_44;
} else {
if (IS_CHAN_HALF_RATE(chan)) {
phyPLL = AR_PHY_PLL_CTL_40_HALF;
} else if (IS_CHAN_QUARTER_RATE(chan)) {
phyPLL = AR_PHY_PLL_CTL_40_QUARTER;
} else {
phyPLL = AR_PHY_PLL_CTL_40;
}
}
else
phyPLL = AR_PHY_PLL_CTL_40;
if (IS_CHAN_HALF_RATE(chan))
phyPLL = AR_PHY_PLL_CTL_HALF;
else if (IS_CHAN_QUARTER_RATE(chan))
phyPLL = AR_PHY_PLL_CTL_QUARTER;
} else { /* 5112, 2413, 2316, 2317 */
rfMode = AR_PHY_MODE_AR5112;
if (IS_CHAN_CCK(chan) || IS_CHAN_G(chan))
phyPLL = AR_PHY_PLL_CTL_44_5112;
else
phyPLL = AR_PHY_PLL_CTL_40_5112;
if (IS_CHAN_HALF_RATE(chan))
phyPLL |= AR_PHY_PLL_CTL_HALF;
else if (IS_CHAN_QUARTER_RATE(chan))
phyPLL |= AR_PHY_PLL_CTL_QUARTER;
}
if (IS_CHAN_OFDM(chan) && (IS_CHAN_CCK(chan) ||
IS_CHAN_G(chan)))
@ -992,7 +977,8 @@ ar5212ChipReset(struct ath_hal *ah, HAL_CHANNEL *chan)
* changes.
*/
HAL_BOOL
ar5212PerCalibration(struct ath_hal *ah, HAL_CHANNEL *chan, HAL_BOOL *isIQdone)
ar5212PerCalibrationN(struct ath_hal *ah, HAL_CHANNEL *chan, u_int chainMask,
HAL_BOOL longCal, HAL_BOOL *isCalDone)
{
#define IQ_CAL_TRIES 10
struct ath_hal_5212 *ahp = AH5212(ah);
@ -1004,7 +990,7 @@ ar5212PerCalibration(struct ath_hal *ah, HAL_CHANNEL *chan, HAL_BOOL *isIQdone)
HAL_BOOL isBmode = AH_FALSE;
OS_MARK(ah, AH_MARK_PERCAL, chan->channel);
*isIQdone = AH_FALSE;
*isCalDone = AH_FALSE;
ichan = ath_hal_checkchannel(ah, chan);
if (ichan == AH_NULL) {
HALDEBUG(ah, HAL_DEBUG_ANY,
@ -1015,10 +1001,9 @@ ar5212PerCalibration(struct ath_hal *ah, HAL_CHANNEL *chan, HAL_BOOL *isIQdone)
SAVE_CCK(ah, ichan, ichan_isBmode);
SAVE_CCK(ah, chan, isBmode);
/* XXX EAR */
if ((ahp->ah_bIQCalibration == IQ_CAL_DONE) ||
(ahp->ah_bIQCalibration == IQ_CAL_INACTIVE))
*isIQdone = AH_TRUE;
if (ahp->ah_bIQCalibration == IQ_CAL_DONE ||
ahp->ah_bIQCalibration == IQ_CAL_INACTIVE)
*isCalDone = AH_TRUE;
/* IQ calibration in progress. Check to see if it has finished. */
if (ahp->ah_bIQCalibration == IQ_CAL_RUNNING &&
@ -1027,7 +1012,7 @@ ar5212PerCalibration(struct ath_hal *ah, HAL_CHANNEL *chan, HAL_BOOL *isIQdone)
/* IQ Calibration has finished. */
ahp->ah_bIQCalibration = IQ_CAL_INACTIVE;
*isIQdone = AH_TRUE;
*isCalDone = AH_TRUE;
/* workaround for misgated IQ Cal results */
i = 0;
@ -1097,9 +1082,8 @@ ar5212PerCalibration(struct ath_hal *ah, HAL_CHANNEL *chan, HAL_BOOL *isIQdone)
ichan->iCoff = iCoff;
ichan->qCoff = qCoff;
}
} else if (!IS_CHAN_B(chan) &&
ahp->ah_bIQCalibration == IQ_CAL_DONE &&
!ichan->iqCalValid) {
} else if (!IS_CHAN_B(chan) && ahp->ah_bIQCalibration == IQ_CAL_DONE &&
!ichan->iqCalValid) {
/*
* Start IQ calibration if configured channel has changed.
* Use a magic number of 15 based on default value.
@ -1113,22 +1097,21 @@ ar5212PerCalibration(struct ath_hal *ah, HAL_CHANNEL *chan, HAL_BOOL *isIQdone)
}
/* XXX EAR */
/* Check noise floor results */
ar5212GetNf(ah, ichan);
if ((ichan->channelFlags & CHANNEL_CW_INT) == 0) {
/* Perform calibration for 5Ghz channels and any OFDM on 5112 */
if ((IS_CHAN_5GHZ(chan) ||
(IS_5112(ah) && IS_CHAN_OFDM(chan))) &&
!(IS_2413(ah) || IS_5413(ah) || IS_2417(ah)))
ar5212RequestRfgain(ah);
if (longCal) {
/* Check noise floor results */
ar5212GetNf(ah, ichan);
/* XXX EAR */
} else {
/* report up and clear internal state */
chan->channelFlags |= CHANNEL_CW_INT;
ichan->channelFlags &= ~CHANNEL_CW_INT;
if ((ichan->channelFlags & CHANNEL_CW_INT) == 0) {
/* Perform cal for 5Ghz channels and any OFDM on 5112 */
if (IS_CHAN_5GHZ(chan) ||
(IS_RAD5112(ah) && IS_CHAN_OFDM(chan)))
ar5212RequestRfgain(ah);
} else {
/* report up and clear internal state */
chan->channelFlags |= CHANNEL_CW_INT;
ichan->channelFlags &= ~CHANNEL_CW_INT;
}
}
RESTORE_CCK(ah, ichan, ichan_isBmode);
RESTORE_CCK(ah, chan, isBmode);
@ -1136,6 +1119,19 @@ ar5212PerCalibration(struct ath_hal *ah, HAL_CHANNEL *chan, HAL_BOOL *isIQdone)
#undef IQ_CAL_TRIES
}
HAL_BOOL
ar5212PerCalibration(struct ath_hal *ah, HAL_CHANNEL *chan, HAL_BOOL *isIQdone)
{
return ar5212PerCalibrationN(ah, chan, 0x1, AH_TRUE, isIQdone);
}
HAL_BOOL
ar5212ResetCalValid(struct ath_hal *ah, HAL_CHANNEL *chan)
{
/* XXX */
return AH_TRUE;
}
/*
* Write the given reset bit mask into the reset register
*/
@ -1174,6 +1170,9 @@ ar5212SetResetReg(struct ath_hal *ah, uint32_t resetMask)
if (ar5212SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE))
(void) OS_REG_READ(ah, AR_ISR_RAC);
}
/* track PHY power state so we don't try to r/w BB registers */
AH5212(ah)->ah_phyPowerOn = ((resetMask & AR_RC_BB) == 0);
return rt;
}
@ -1383,42 +1382,6 @@ ar5212SetCompRegs(struct ath_hal *ah)
}
}
#define MAX_ANALOG_START 319 /* XXX */
/*
* Find analog bits of given parameter data and return a reversed value
*/
static uint32_t
ar5212GetRfField(uint32_t *rfBuf, uint32_t numBits, uint32_t firstBit, uint32_t column)
{
uint32_t reg32 = 0, mask, arrayEntry, lastBit;
uint32_t bitPosition, bitsShifted;
int32_t bitsLeft;
HALASSERT(column <= 3);
HALASSERT(numBits <= 32);
HALASSERT(firstBit + numBits <= MAX_ANALOG_START);
arrayEntry = (firstBit - 1) / 8;
bitPosition = (firstBit - 1) % 8;
bitsLeft = numBits;
bitsShifted = 0;
while (bitsLeft > 0) {
lastBit = (bitPosition + bitsLeft > 8) ?
(8) : (bitPosition + bitsLeft);
mask = (((1 << lastBit) - 1) ^ ((1 << bitPosition) - 1)) <<
(column * 8);
reg32 |= (((rfBuf[arrayEntry] & mask) >> (column * 8)) >>
bitPosition) << bitsShifted;
bitsShifted += lastBit - bitPosition;
bitsLeft -= (8 - bitPosition);
bitPosition = 0;
arrayEntry++;
}
reg32 = ath_hal_reverseBits(reg32, numBits);
return reg32;
}
HAL_BOOL
ar5212SetAntennaSwitchInternal(struct ath_hal *ah, HAL_ANT_SETTING settings,
const HAL_CHANNEL_INTERNAL *chan)
@ -1434,6 +1397,7 @@ ar5212SetAntennaSwitchInternal(struct ath_hal *ah, HAL_ANT_SETTING settings,
HAL_CHANNEL_INTERNAL ichan = *chan;
HALASSERT(ah->ah_magic == AR5212_MAGIC);
HALASSERT(ahp->ah_phyPowerOn);
SAVE_CCK(ah, &ichan, isBmode);
switch (ichan.channelFlags & CHANNEL_ALL_NOTURBO) {
@ -1482,13 +1446,15 @@ ar5212SetAntennaSwitchInternal(struct ath_hal *ah, HAL_ANT_SETTING settings,
"%s: Setting fast diversity off.\n", __func__);
OS_REG_CLR_BIT(ah,AR_PHY_CCK_DETECT,
AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV);
ahp->ah_diversity = AH_FALSE;
} else {
HALDEBUG(ah, HAL_DEBUG_RFPARAM,
"%s: Setting fast diversity on.\n", __func__);
OS_REG_SET_BIT(ah,AR_PHY_CCK_DETECT,
AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV);
ahp->ah_diversity = AH_TRUE;
}
ahp->ah_diversityControl = settings;
ahp->ah_antControl = settings;
OS_REG_WRITE(ah, ANT_SWITCH_TABLE1, antSwitchA);
OS_REG_WRITE(ah, ANT_SWITCH_TABLE2, antSwitchB);
@ -1502,7 +1468,7 @@ HAL_BOOL
ar5212IsSpurChannel(struct ath_hal *ah, HAL_CHANNEL *chan)
{
uint32_t clockFreq =
((IS_5413(ah) || IS_2413(ah) || IS_5112(ah) || IS_2417(ah)) ? 40 : 32);
((IS_5413(ah) || IS_RAD5112_ANY(ah) || IS_2417(ah)) ? 40 : 32);
return ( ((chan->channel % clockFreq) != 0)
&& (((chan->channel % clockFreq) < 10)
|| (((chan->channel) % clockFreq) > 22)) );
@ -1534,7 +1500,7 @@ ar5212SetBoardValues(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan)
case CHANNEL_A:
case CHANNEL_T:
arrayMode = headerInfo11A;
if (!IS_5112(ah) && !IS_2413(ah) && !IS_5413(ah))
if (!IS_RAD5112_ANY(ah) && !IS_2413(ah) && !IS_5413(ah))
OS_REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL,
AR_PHY_FRAME_CTL_TX_CLIP,
ahp->ah_gainValues.currStep->paramVal[GP_TXCLIP]);
@ -1556,7 +1522,7 @@ ar5212SetBoardValues(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan)
AR_PHY_BIS(ah, 68, 0xFFFFFC06,
(ee->ee_antennaControl[0][arrayMode] << 4) | 0x1);
ar5212SetAntennaSwitchInternal(ah, ahp->ah_diversityControl, chan);
ar5212SetAntennaSwitchInternal(ah, ahp->ah_antControl, chan);
/* Set the Noise Floor Thresh on ar5211 devices */
OS_REG_WRITE(ah, AR_PHY(90),
@ -2566,278 +2532,16 @@ ar5212GetLowerUpperValues(uint16_t v, uint16_t *lp, uint16_t listSize,
HALASSERT(AH_FALSE); /* should not reach here */
}
static const GAIN_OPTIMIZATION_LADDER gainLadder = {
9, /* numStepsInLadder */
4, /* defaultStepNum */
{ { {4, 1, 1, 1}, 6, "FG8"},
{ {4, 0, 1, 1}, 4, "FG7"},
{ {3, 1, 1, 1}, 3, "FG6"},
{ {4, 0, 0, 1}, 1, "FG5"},
{ {4, 1, 1, 0}, 0, "FG4"}, /* noJack */
{ {4, 0, 1, 0}, -2, "FG3"}, /* halfJack */
{ {3, 1, 1, 0}, -3, "FG2"}, /* clip3 */
{ {4, 0, 0, 0}, -4, "FG1"}, /* noJack */
{ {2, 1, 1, 0}, -6, "FG0"} /* clip2 */
}
};
const static GAIN_OPTIMIZATION_LADDER gainLadder5112 = {
8, /* numStepsInLadder */
1, /* defaultStepNum */
{ { {3, 0,0,0, 0,0,0}, 6, "FG7"}, /* most fixed gain */
{ {2, 0,0,0, 0,0,0}, 0, "FG6"},
{ {1, 0,0,0, 0,0,0}, -3, "FG5"},
{ {0, 0,0,0, 0,0,0}, -6, "FG4"},
{ {0, 1,1,0, 0,0,0}, -8, "FG3"},
{ {0, 1,1,0, 1,1,0}, -10, "FG2"},
{ {0, 1,0,1, 1,1,0}, -13, "FG1"},
{ {0, 1,0,1, 1,0,1}, -16, "FG0"}, /* least fixed gain */
}
};
/*
* Initialize the gain structure to good values
*/
void
ar5212InitializeGainValues(struct ath_hal *ah)
{
struct ath_hal_5212 *ahp = AH5212(ah);
GAIN_VALUES *gv = &ahp->ah_gainValues;
/* initialize gain optimization values */
if (IS_5112(ah)) {
gv->currStepNum = gainLadder5112.defaultStepNum;
gv->currStep =
&gainLadder5112.optStep[gainLadder5112.defaultStepNum];
gv->active = AH_TRUE;
gv->loTrig = 20;
gv->hiTrig = 85;
} else {
gv->currStepNum = gainLadder.defaultStepNum;
gv->currStep = &gainLadder.optStep[gainLadder.defaultStepNum];
gv->active = AH_TRUE;
gv->loTrig = 20;
gv->hiTrig = 35;
}
}
static HAL_BOOL
ar5212InvalidGainReadback(struct ath_hal *ah, GAIN_VALUES *gv)
{
uint32_t gStep, g, mixOvr;
uint32_t L1, L2, L3, L4;
if (IS_5112(ah)) {
mixOvr = ar5212GetRfField(ar5212GetRfBank(ah, 7), 1, 36, 0);
L1 = 0;
L2 = 107;
L3 = 0;
L4 = 107;
if (mixOvr == 1) {
L2 = 83;
L4 = 83;
gv->hiTrig = 55;
}
} else {
gStep = ar5212GetRfField(ar5212GetRfBank(ah, 7), 6, 37, 0);
L1 = 0;
L2 = (gStep == 0x3f) ? 50 : gStep + 4;
L3 = (gStep != 0x3f) ? 0x40 : L1;
L4 = L3 + 50;
gv->loTrig = L1 + (gStep == 0x3f ? DYN_ADJ_LO_MARGIN : 0);
/* never adjust if != 0x3f */
gv->hiTrig = L4 - (gStep == 0x3f ? DYN_ADJ_UP_MARGIN : -5);
}
g = gv->currGain;
return !((g >= L1 && g<= L2) || (g >= L3 && g <= L4));
}
/*
* Enable the probe gain check on the next packet
*/
static void
ar5212RequestRfgain(struct ath_hal *ah)
{
struct ath_hal_5212 *ahp = AH5212(ah);
uint32_t probePowerIndex;
/* Enable the gain readback probe */
probePowerIndex = ahp->ah_ofdmTxPower + ahp->ah_txPowerIndexOffset;
OS_REG_WRITE(ah, AR_PHY_PAPD_PROBE,
SM(probePowerIndex, AR_PHY_PAPD_PROBE_POWERTX)
| AR_PHY_PAPD_PROBE_NEXT_TX);
ahp->ah_rfgainState = HAL_RFGAIN_READ_REQUESTED;
}
/*
* Exported call to check for a recent gain reading and return
* the current state of the thermal calibration gain engine.
*/
HAL_RFGAIN
ar5212GetRfgain(struct ath_hal *ah)
{
struct ath_hal_5212 *ahp = AH5212(ah);
GAIN_VALUES *gv = &ahp->ah_gainValues;
uint32_t rddata, probeType;
if (!gv->active)
return HAL_RFGAIN_INACTIVE;
if (ahp->ah_rfgainState == HAL_RFGAIN_READ_REQUESTED) {
/* Caller had asked to setup a new reading. Check it. */
rddata = OS_REG_READ(ah, AR_PHY_PAPD_PROBE);
if ((rddata & AR_PHY_PAPD_PROBE_NEXT_TX) == 0) {
/* bit got cleared, we have a new reading. */
gv->currGain = rddata >> AR_PHY_PAPD_PROBE_GAINF_S;
probeType = MS(rddata, AR_PHY_PAPD_PROBE_TYPE);
if (probeType == AR_PHY_PAPD_PROBE_TYPE_CCK) {
const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
HALASSERT(IS_5112(ah));
HALASSERT(ah->ah_magic == AR5212_MAGIC);
if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_2)
gv->currGain += ee->ee_cckOfdmGainDelta;
else
gv->currGain += PHY_PROBE_CCK_CORRECTION;
}
if (IS_5112(ah)) {
ar5212GetGainFCorrection(ah);
if (gv->currGain >= gv->gainFCorrection)
gv->currGain -= gv->gainFCorrection;
else
gv->currGain = 0;
}
/* inactive by default */
ahp->ah_rfgainState = HAL_RFGAIN_INACTIVE;
if (!ar5212InvalidGainReadback(ah, gv) &&
ar5212IsGainAdjustNeeded(ah, gv) &&
ar5212AdjustGain(ah, gv) > 0) {
/*
* Change needed. Copy ladder info
* into eeprom info.
*/
ahp->ah_rfgainState = HAL_RFGAIN_NEED_CHANGE;
/* for ap51 */
ahp->ah_cwCalRequire = AH_TRUE;
/* Request IQ recalibration for temperature chang */
ahp->ah_bIQCalibration = IQ_CAL_INACTIVE;
}
}
}
return ahp->ah_rfgainState;
}
/*
* Check to see if our readback gain level sits within the linear
* region of our current variable attenuation window
*/
static HAL_BOOL
ar5212IsGainAdjustNeeded(struct ath_hal *ah, const GAIN_VALUES *gv)
{
return (gv->currGain <= gv->loTrig || gv->currGain >= gv->hiTrig);
}
/*
* Move the rabbit ears in the correct direction.
*/
static int32_t
ar5212AdjustGain(struct ath_hal *ah, GAIN_VALUES *gv)
{
const GAIN_OPTIMIZATION_LADDER *gl;
if (IS_5112(ah))
gl = &gainLadder5112;
else
gl = &gainLadder;
gv->currStep = &gl->optStep[gv->currStepNum];
if (gv->currGain >= gv->hiTrig) {
if (gv->currStepNum == 0) {
HALDEBUG(ah, HAL_DEBUG_ANY, "%s: Max gain limit.\n",
__func__);
return -1;
}
HALDEBUG(ah, HAL_DEBUG_RFPARAM,
"%s: Adding gain: currG=%d [%s] --> ",
__func__, gv->currGain, gv->currStep->stepName);
gv->targetGain = gv->currGain;
while (gv->targetGain >= gv->hiTrig && gv->currStepNum > 0) {
gv->targetGain -= 2 * (gl->optStep[--(gv->currStepNum)].stepGain -
gv->currStep->stepGain);
gv->currStep = &gl->optStep[gv->currStepNum];
}
HALDEBUG(ah, HAL_DEBUG_RFPARAM, "targG=%d [%s]\n",
gv->targetGain, gv->currStep->stepName);
return 1;
}
if (gv->currGain <= gv->loTrig) {
if (gv->currStepNum == gl->numStepsInLadder-1) {
HALDEBUG(ah, HAL_DEBUG_RFPARAM,
"%s: Min gain limit.\n", __func__);
return -2;
}
HALDEBUG(ah, HAL_DEBUG_RFPARAM,
"%s: Deducting gain: currG=%d [%s] --> ",
__func__, gv->currGain, gv->currStep->stepName);
gv->targetGain = gv->currGain;
while (gv->targetGain <= gv->loTrig &&
gv->currStepNum < (gl->numStepsInLadder - 1)) {
gv->targetGain -= 2 *
(gl->optStep[++(gv->currStepNum)].stepGain - gv->currStep->stepGain);
gv->currStep = &gl->optStep[gv->currStepNum];
}
HALDEBUG(ah, HAL_DEBUG_RFPARAM, "targG=%d [%s]\n",
gv->targetGain, gv->currStep->stepName);
return 2;
}
return 0; /* caller didn't call needAdjGain first */
}
/*
* Read rf register to determine if gainF needs correction
*/
static void
ar5212GetGainFCorrection(struct ath_hal *ah)
{
struct ath_hal_5212 *ahp = AH5212(ah);
GAIN_VALUES *gv = &ahp->ah_gainValues;
HALASSERT(IS_RADX112_REV2(ah));
gv->gainFCorrection = 0;
if (ar5212GetRfField(ar5212GetRfBank(ah, 7), 1, 36, 0) == 1) {
uint32_t mixGain = gv->currStep->paramVal[0];
uint32_t gainStep =
ar5212GetRfField(ar5212GetRfBank(ah, 7), 4, 32, 0);
switch (mixGain) {
case 0 :
gv->gainFCorrection = 0;
break;
case 1 :
gv->gainFCorrection = gainStep;
break;
case 2 :
gv->gainFCorrection = 2 * gainStep - 5;
break;
case 3 :
gv->gainFCorrection = 2 * gainStep;
break;
}
}
}
/*
* Perform analog "swizzling" of parameters into their location
*
* NB: used by RF backends
*/
void
ar5212ModifyRfBuffer(uint32_t *rfBuf, uint32_t reg32, uint32_t numBits,
uint32_t firstBit, uint32_t column)
{
#define MAX_ANALOG_START 319 /* XXX */
uint32_t tmp32, mask, arrayEntry, lastBit;
int32_t bitPosition, bitsLeft;
@ -2862,6 +2566,7 @@ ar5212ModifyRfBuffer(uint32_t *rfBuf, uint32_t reg32, uint32_t numBits,
bitPosition = 0;
arrayEntry++;
}
#undef MAX_ANALOG_START
}
/*
@ -2881,6 +2586,7 @@ ar5212SetRateDurationTable(struct ath_hal *ah, HAL_CHANNEL *chan)
const HAL_RATE_TABLE *rt;
int i;
/* NB: band doesn't matter for 1/2 and 1/4 rate */
if (IS_CHAN_HALF_RATE(chan)) {
rt = ar5212GetRateTable(ah, HAL_MODE_11A_HALF_RATE);
} else if (IS_CHAN_QUARTER_RATE(chan)) {
@ -2931,6 +2637,8 @@ ar5212SetIFSTiming(struct ath_hal *ah, HAL_CHANNEL *chan)
{
uint32_t txLat, rxLat, usec, slot, refClock, eifs, init_usec;
HALASSERT(IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan));
refClock = OS_REG_READ(ah, AR_USEC) & AR_USEC_USEC32;
if (IS_CHAN_HALF_RATE(chan)) {
slot = IFS_SLOT_HALF_RATE;
@ -2953,7 +2661,5 @@ ar5212SetIFSTiming(struct ath_hal *ah, HAL_CHANNEL *chan)
OS_REG_WRITE(ah, AR_D_GBL_IFS_EIFS, eifs);
OS_REG_RMW_FIELD(ah, AR_D_GBL_IFS_MISC,
AR_D_GBL_IFS_MISC_USEC_DURATION, init_usec);
return;
}
#endif /* AH_SUPPORT_AR5212 */

333
ar5212/ar5212_rfgain.c Normal file
View File

@ -0,0 +1,333 @@
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
*
* Permission to use, copy, modify, and/or 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.
*
* $Id: ar5212_rfgain.c,v 1.2 2008/11/19 21:23:01 sam Exp $
*/
#include "opt_ah.h"
#ifdef AH_SUPPORT_AR5212
#include "ah.h"
#include "ah_internal.h"
#include "ah_devid.h"
#include "ar5212/ar5212.h"
#include "ar5212/ar5212reg.h"
#include "ar5212/ar5212phy.h"
#include "ah_eeprom_v3.h"
static const GAIN_OPTIMIZATION_LADDER gainLadder = {
9, /* numStepsInLadder */
4, /* defaultStepNum */
{ { {4, 1, 1, 1}, 6, "FG8"},
{ {4, 0, 1, 1}, 4, "FG7"},
{ {3, 1, 1, 1}, 3, "FG6"},
{ {4, 0, 0, 1}, 1, "FG5"},
{ {4, 1, 1, 0}, 0, "FG4"}, /* noJack */
{ {4, 0, 1, 0}, -2, "FG3"}, /* halfJack */
{ {3, 1, 1, 0}, -3, "FG2"}, /* clip3 */
{ {4, 0, 0, 0}, -4, "FG1"}, /* noJack */
{ {2, 1, 1, 0}, -6, "FG0"} /* clip2 */
}
};
static const GAIN_OPTIMIZATION_LADDER gainLadder5112 = {
8, /* numStepsInLadder */
1, /* defaultStepNum */
{ { {3, 0,0,0, 0,0,0}, 6, "FG7"}, /* most fixed gain */
{ {2, 0,0,0, 0,0,0}, 0, "FG6"},
{ {1, 0,0,0, 0,0,0}, -3, "FG5"},
{ {0, 0,0,0, 0,0,0}, -6, "FG4"},
{ {0, 1,1,0, 0,0,0}, -8, "FG3"},
{ {0, 1,1,0, 1,1,0}, -10, "FG2"},
{ {0, 1,0,1, 1,1,0}, -13, "FG1"},
{ {0, 1,0,1, 1,0,1}, -16, "FG0"}, /* least fixed gain */
}
};
/*
* Initialize the gain structure to good values
*/
void
ar5212InitializeGainValues(struct ath_hal *ah)
{
struct ath_hal_5212 *ahp = AH5212(ah);
GAIN_VALUES *gv = &ahp->ah_gainValues;
/* initialize gain optimization values */
if (IS_RAD5112_ANY(ah)) {
gv->currStepNum = gainLadder5112.defaultStepNum;
gv->currStep =
&gainLadder5112.optStep[gainLadder5112.defaultStepNum];
gv->active = AH_TRUE;
gv->loTrig = 20;
gv->hiTrig = 85;
} else {
gv->currStepNum = gainLadder.defaultStepNum;
gv->currStep = &gainLadder.optStep[gainLadder.defaultStepNum];
gv->active = AH_TRUE;
gv->loTrig = 20;
gv->hiTrig = 35;
}
}
#define MAX_ANALOG_START 319 /* XXX */
/*
* Find analog bits of given parameter data and return a reversed value
*/
static uint32_t
ar5212GetRfField(uint32_t *rfBuf, uint32_t numBits, uint32_t firstBit, uint32_t column)
{
uint32_t reg32 = 0, mask, arrayEntry, lastBit;
uint32_t bitPosition, bitsShifted;
int32_t bitsLeft;
HALASSERT(column <= 3);
HALASSERT(numBits <= 32);
HALASSERT(firstBit + numBits <= MAX_ANALOG_START);
arrayEntry = (firstBit - 1) / 8;
bitPosition = (firstBit - 1) % 8;
bitsLeft = numBits;
bitsShifted = 0;
while (bitsLeft > 0) {
lastBit = (bitPosition + bitsLeft > 8) ?
(8) : (bitPosition + bitsLeft);
mask = (((1 << lastBit) - 1) ^ ((1 << bitPosition) - 1)) <<
(column * 8);
reg32 |= (((rfBuf[arrayEntry] & mask) >> (column * 8)) >>
bitPosition) << bitsShifted;
bitsShifted += lastBit - bitPosition;
bitsLeft -= (8 - bitPosition);
bitPosition = 0;
arrayEntry++;
}
reg32 = ath_hal_reverseBits(reg32, numBits);
return reg32;
}
static HAL_BOOL
ar5212InvalidGainReadback(struct ath_hal *ah, GAIN_VALUES *gv)
{
uint32_t gStep, g, mixOvr;
uint32_t L1, L2, L3, L4;
if (IS_RAD5112_ANY(ah)) {
mixOvr = ar5212GetRfField(ar5212GetRfBank(ah, 7), 1, 36, 0);
L1 = 0;
L2 = 107;
L3 = 0;
L4 = 107;
if (mixOvr == 1) {
L2 = 83;
L4 = 83;
gv->hiTrig = 55;
}
} else {
gStep = ar5212GetRfField(ar5212GetRfBank(ah, 7), 6, 37, 0);
L1 = 0;
L2 = (gStep == 0x3f) ? 50 : gStep + 4;
L3 = (gStep != 0x3f) ? 0x40 : L1;
L4 = L3 + 50;
gv->loTrig = L1 + (gStep == 0x3f ? DYN_ADJ_LO_MARGIN : 0);
/* never adjust if != 0x3f */
gv->hiTrig = L4 - (gStep == 0x3f ? DYN_ADJ_UP_MARGIN : -5);
}
g = gv->currGain;
return !((g >= L1 && g<= L2) || (g >= L3 && g <= L4));
}
/*
* Enable the probe gain check on the next packet
*/
void
ar5212RequestRfgain(struct ath_hal *ah)
{
struct ath_hal_5212 *ahp = AH5212(ah);
uint32_t probePowerIndex;
/* Enable the gain readback probe */
probePowerIndex = ahp->ah_ofdmTxPower + ahp->ah_txPowerIndexOffset;
OS_REG_WRITE(ah, AR_PHY_PAPD_PROBE,
SM(probePowerIndex, AR_PHY_PAPD_PROBE_POWERTX)
| AR_PHY_PAPD_PROBE_NEXT_TX);
ahp->ah_rfgainState = HAL_RFGAIN_READ_REQUESTED;
}
/*
* Check to see if our readback gain level sits within the linear
* region of our current variable attenuation window
*/
static HAL_BOOL
ar5212IsGainAdjustNeeded(struct ath_hal *ah, const GAIN_VALUES *gv)
{
return (gv->currGain <= gv->loTrig || gv->currGain >= gv->hiTrig);
}
/*
* Move the rabbit ears in the correct direction.
*/
static int32_t
ar5212AdjustGain(struct ath_hal *ah, GAIN_VALUES *gv)
{
const GAIN_OPTIMIZATION_LADDER *gl;
if (IS_RAD5112_ANY(ah))
gl = &gainLadder5112;
else
gl = &gainLadder;
gv->currStep = &gl->optStep[gv->currStepNum];
if (gv->currGain >= gv->hiTrig) {
if (gv->currStepNum == 0) {
HALDEBUG(ah, HAL_DEBUG_ANY, "%s: Max gain limit.\n",
__func__);
return -1;
}
HALDEBUG(ah, HAL_DEBUG_RFPARAM,
"%s: Adding gain: currG=%d [%s] --> ",
__func__, gv->currGain, gv->currStep->stepName);
gv->targetGain = gv->currGain;
while (gv->targetGain >= gv->hiTrig && gv->currStepNum > 0) {
gv->targetGain -= 2 * (gl->optStep[--(gv->currStepNum)].stepGain -
gv->currStep->stepGain);
gv->currStep = &gl->optStep[gv->currStepNum];
}
HALDEBUG(ah, HAL_DEBUG_RFPARAM, "targG=%d [%s]\n",
gv->targetGain, gv->currStep->stepName);
return 1;
}
if (gv->currGain <= gv->loTrig) {
if (gv->currStepNum == gl->numStepsInLadder-1) {
HALDEBUG(ah, HAL_DEBUG_RFPARAM,
"%s: Min gain limit.\n", __func__);
return -2;
}
HALDEBUG(ah, HAL_DEBUG_RFPARAM,
"%s: Deducting gain: currG=%d [%s] --> ",
__func__, gv->currGain, gv->currStep->stepName);
gv->targetGain = gv->currGain;
while (gv->targetGain <= gv->loTrig &&
gv->currStepNum < (gl->numStepsInLadder - 1)) {
gv->targetGain -= 2 *
(gl->optStep[++(gv->currStepNum)].stepGain - gv->currStep->stepGain);
gv->currStep = &gl->optStep[gv->currStepNum];
}
HALDEBUG(ah, HAL_DEBUG_RFPARAM, "targG=%d [%s]\n",
gv->targetGain, gv->currStep->stepName);
return 2;
}
return 0; /* caller didn't call needAdjGain first */
}
/*
* Read rf register to determine if gainF needs correction
*/
static void
ar5212GetGainFCorrection(struct ath_hal *ah)
{
struct ath_hal_5212 *ahp = AH5212(ah);
GAIN_VALUES *gv = &ahp->ah_gainValues;
HALASSERT(IS_RADX112_REV2(ah));
gv->gainFCorrection = 0;
if (ar5212GetRfField(ar5212GetRfBank(ah, 7), 1, 36, 0) == 1) {
uint32_t mixGain = gv->currStep->paramVal[0];
uint32_t gainStep =
ar5212GetRfField(ar5212GetRfBank(ah, 7), 4, 32, 0);
switch (mixGain) {
case 0 :
gv->gainFCorrection = 0;
break;
case 1 :
gv->gainFCorrection = gainStep;
break;
case 2 :
gv->gainFCorrection = 2 * gainStep - 5;
break;
case 3 :
gv->gainFCorrection = 2 * gainStep;
break;
}
}
}
/*
* Exported call to check for a recent gain reading and return
* the current state of the thermal calibration gain engine.
*/
HAL_RFGAIN
ar5212GetRfgain(struct ath_hal *ah)
{
struct ath_hal_5212 *ahp = AH5212(ah);
GAIN_VALUES *gv = &ahp->ah_gainValues;
uint32_t rddata, probeType;
if (!gv->active)
return HAL_RFGAIN_INACTIVE;
if (ahp->ah_rfgainState == HAL_RFGAIN_READ_REQUESTED) {
/* Caller had asked to setup a new reading. Check it. */
rddata = OS_REG_READ(ah, AR_PHY_PAPD_PROBE);
if ((rddata & AR_PHY_PAPD_PROBE_NEXT_TX) == 0) {
/* bit got cleared, we have a new reading. */
gv->currGain = rddata >> AR_PHY_PAPD_PROBE_GAINF_S;
probeType = MS(rddata, AR_PHY_PAPD_PROBE_TYPE);
if (probeType == AR_PHY_PAPD_PROBE_TYPE_CCK) {
const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
HALASSERT(IS_RAD5112_ANY(ah));
HALASSERT(ah->ah_magic == AR5212_MAGIC);
if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_2)
gv->currGain += ee->ee_cckOfdmGainDelta;
else
gv->currGain += PHY_PROBE_CCK_CORRECTION;
}
if (IS_RADX112_REV2(ah)) {
ar5212GetGainFCorrection(ah);
if (gv->currGain >= gv->gainFCorrection)
gv->currGain -= gv->gainFCorrection;
else
gv->currGain = 0;
}
/* inactive by default */
ahp->ah_rfgainState = HAL_RFGAIN_INACTIVE;
if (!ar5212InvalidGainReadback(ah, gv) &&
ar5212IsGainAdjustNeeded(ah, gv) &&
ar5212AdjustGain(ah, gv) > 0) {
/*
* Change needed. Copy ladder info
* into eeprom info.
*/
ahp->ah_rfgainState = HAL_RFGAIN_NEED_CHANGE;
/* for ap51 */
ahp->ah_cwCalRequire = AH_TRUE;
/* Request IQ recalibration for temperature chang */
ahp->ah_bIQCalibration = IQ_CAL_INACTIVE;
}
}
}
return ahp->ah_rfgainState;
}
#endif /* AH_SUPPORT_AR5212 */

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ar5212phy.h,v 1.5 2008/11/04 01:08:40 sam Exp $
* $Id: ar5212phy.h,v 1.7 2008/11/19 21:23:01 sam Exp $
*/
#ifndef _DEV_ATH_AR5212PHY_H_
#define _DEV_ATH_AR5212PHY_H_
@ -113,6 +113,7 @@
#define AR_PHY_AGC_CONTROL_CAL 0x00000001 /* do internal calibration */
#define AR_PHY_AGC_CONTROL_NF 0x00000002 /* do noise-floor calculation */
#define AR_PHY_AGC_CONTROL_ENABLE_NF 0x00008000 /* Enable noise floor calibration to happen */
#define AR_PHY_AGC_CONTROL_FLTR_CAL 0x00010000 /* Allow Filter calibration */
#define AR_PHY_AGC_CONTROL_NO_UPDATE_NF 0x00020000 /* Don't update noise floor automatically */
#define AR_PHY_SFCORR_LOW 0x986C
@ -136,16 +137,14 @@
#define AR_PHY_SLEEP_CTR_LIMIT 0x9874
#define AR_PHY_SLEEP_SCAL 0x9878
#define AR_PHY_PLL_CTL 0x987c /* PLL control register */
#define AR_PHY_PLL_CTL_40 0xaa /* 40 MHz */
#define AR_PHY_PLL_CTL_44 0xab /* 44 MHz for 11b, 11g */
#define AR_PHY_PLL_CTL_40_HALF 0x1aa /* 40 MHz for 11a, turbos (Half)*/
#define AR_PHY_PLL_CTL_40_QUARTER 0x2aa /* 40 MHz for 11a, turbos (Quarter)*/
#define AR_PHY_PLL_CTL_44_5112 0xeb /* 44 MHz for 11b, 11g */
#define AR_PHY_PLL_CTL_40_5112 0xea /* 40 MHz for 11a, turbos */
#define AR_PHY_PLL_CTL_40_5112_HALF 0x1ea /* 40 MHz for 11a, turbos (Half)*/
#define AR_PHY_PLL_CTL_40_5112_QUARTER 0x2ea /* 40 MHz for 11a, turbos (Quarter)*/
#define AR_PHY_PLL_CTL_40_5413 0x04 /* 40 MHz for 11a, turbos with 5413 */
#define AR_PHY_PLL_CTL 0x987c /* PLL control register */
#define AR_PHY_PLL_CTL_40 0xaa /* 40 MHz */
#define AR_PHY_PLL_CTL_44 0xab /* 44 MHz for 11b, 11g */
#define AR_PHY_PLL_CTL_44_5112 0xeb /* 44 MHz for 11b, 11g */
#define AR_PHY_PLL_CTL_40_5112 0xea /* 40 MHz for 11a, turbos */
#define AR_PHY_PLL_CTL_40_5413 0x04 /* 40 MHz for 11a, turbos with 5413 */
#define AR_PHY_PLL_CTL_HALF 0x100 /* Half clock for 1/2 chan width */
#define AR_PHY_PLL_CTL_QUARTER 0x200 /* Quarter clock for 1/4 chan width */
#define AR_PHY_BIN_MASK_1 0x9900
#define AR_PHY_BIN_MASK_2 0x9904

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ar5212reg.h,v 1.4 2008/10/12 17:07:17 sam Exp $
* $Id: ar5212reg.h,v 1.5 2008/11/16 06:45:43 sam Exp $
*/
#ifndef _DEV_ATH_AR5212REG_H_
#define _DEV_ATH_AR5212REG_H_
@ -762,9 +762,9 @@
#define AR_SREV_CRETE_MS 5 /* FCS metal spin */
#define AR_SREV_CRETE_MS23 7 /* 2.3 metal spin (6 skipped) */
#define AR_SREV_CRETE_23 8 /* 2.3 full tape out */
#define AR_SREV_GRIFFIN_LITE 8
#define AR_SREV_HAINAN 9
#define AR_SREV_CONDOR 11
#define AR_SREV_GRIFFIN_LITE 8
#define AR_SREV_HAINAN 9
#define AR_SREV_CONDOR 11
#define AR_SREV_VERSION 0x000000F0 /* Mask for Chip version */
#define AR_SREV_VERSION_CRETE 0
#define AR_SREV_VERSION_MAUI_1 1
@ -773,38 +773,39 @@
#define AR_SREV_VERSION_OAHU 4
#define AR_SREV_VERSION_VENICE 5
#define AR_SREV_VERSION_GRIFFIN 7
#define AR_SREV_VERSION_CONDOR 9
#define AR_SREV_VERSION_EAGLE 10
#define AR_SREV_VERSION_CONDOR 9
#define AR_SREV_VERSION_EAGLE 10
#define AR_SREV_VERSION_COBRA 11
#define AR_SREV_2413 AR_SREV_VERSION_GRIFFIN
#define AR_SREV_5413 AR_SREV_VERSION_EAGLE
#define AR_SREV_5413 AR_SREV_VERSION_EAGLE
#define AR_SREV_2415 AR_SREV_VERSION_COBRA
#define AR_SREV_5424 AR_SREV_VERSION_CONDOR
#define AR_SREV_2425 14 /* SWAN */
#define AR_SREV_2417 15 /* Nala */
#define AR_SREV_5424 AR_SREV_VERSION_CONDOR
#define AR_SREV_2425 14 /* SWAN */
#define AR_SREV_2417 15 /* Nala */
#define AR_SREV_OAHU_ES 0 /* Engineering Sample */
#define AR_SREV_OAHU_PROD 2 /* Production */
#define AR_PHYREV_HAINAN 0x43
#define AR_ANALOG5REV_HAINAN 0x46
#define AR_PHYREV_HAINAN 0x43
#define AR_ANALOG5REV_HAINAN 0x46
#define AR_RADIO_SREV_MAJOR 0xF0
#define AR_RADIO_SREV_MAJOR 0xF0
#define AR_RADIO_SREV_MINOR 0x0F
#define AR_RAD5111_SREV_MAJOR 0x10 /* All current supported ar5211 5 GHz
radios are rev 0x10 */
#define AR_RAD5111_SREV_PROD 0x15 /* Current production level radios */
#define AR_RAD2111_SREV_MAJOR 0x20 /* All current supported ar5211 2 GHz
radios are rev 0x10 */
#define AR_RAD5112_SREV_MAJOR 0x30 /* 5112 Major Rev */
#define AR_RAD5112_SREV_2_0 0x35 /* AR5112 Revision 2.0 */
#define AR_RAD5112_SREV_2_1 0x36 /* AR5112 Revision 2.1 */
#define AR_RAD2112_SREV_MAJOR 0x40 /* 2112 Major Rev */
#define AR_RAD2112_SREV_2_0 0x45 /* AR2112 Revision 2.0 */
#define AR_RAD2112_SREV_2_1 0x46 /* AR2112 Revision 2.1 */
#define AR_RAD2413_SREV_MAJOR 0x50 /* 2413 Major Rev */
#define AR_RAD5413_SREV_MAJOR 0x60 /* 5413 Major Rev */
#define AR_RAD5424_SREV_MAJOR 0xa0 /* Mostly same as 5413 Major Rev */
#define AR_RAD2316_SREV_MAJOR 0x70 /* 2316 Major Rev */
#define AR_RAD2317_SREV_MAJOR 0x80 /* 2317 Major Rev */
#define AR_RAD5112_SREV_2_0 0x35 /* AR5112 Revision 2.0 */
#define AR_RAD2112_SREV_2_0 0x45 /* AR2112 Revision 2.0 */
#define AR_RAD5112_SREV_2_1 0x36 /* AR5112 Revision 2.1 */
#define AR_RAD2112_SREV_2_1 0x46 /* AR2112 Revision 2.1 */
#define AR_RAD5424_SREV_MAJOR 0xa0 /* Mostly same as 5413 Major Rev */
#define AR_PCIE_PMC_ENA_L1 0x01 /* enable PCIe core enter L1 when
d2_sleep_en is asserted */

View File

@ -45,5 +45,6 @@
* is controlled
*/
#define AR5311_D_MISC_SEQ_NUM_CONTROL 0x01000000 /* seq num local or global */
#define AR5311_DIAG_USE_ECO 0x00000400 /* "super secret" enable ECO */
#endif /* _DEV_ATH_AR5311REG_H_ */

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ar5413.c,v 1.7 2008/11/10 04:08:03 sam Exp $
* $Id: ar5413.c,v 1.8 2008/11/15 22:15:46 sam Exp $
*/
#include "opt_ah.h"
@ -549,8 +549,11 @@ ar5413SetPowerTable(struct ath_hal *ah,
int16_t minCalPower5413_t2;
uint16_t *pdadcValues = ahp->ah_pcdacTable;
uint16_t gainBoundaries[4];
uint32_t i, reg32, regoffset, tpcrg1;
int numPdGainsUsed;
uint32_t reg32, regoffset;
int i, numPdGainsUsed;
#ifndef AH_USE_INIPDGAIN
uint32_t tpcrg1;
#endif
HALDEBUG(ah, HAL_DEBUG_RFPARAM, "%s: chan 0x%x flag 0x%x\n",
__func__, chan->channel,chan->channelFlags);
@ -572,10 +575,16 @@ ar5413SetPowerTable(struct ath_hal *ah,
&minCalPower5413_t2,gainBoundaries, rfXpdGain, pdadcValues);
HALASSERT(1 <= numPdGainsUsed && numPdGainsUsed <= 3);
#if 0
#ifdef AH_USE_INIPDGAIN
/*
* Use pd_gains curve from eeprom; Atheros always uses
* the default curve from the ini file but some vendors
* (e.g. Zcomax) want to override this curve and not
* honoring their settings results in tx power 5dBm low.
*/
OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
(pRawDataset->pDataPerChannel[0].numPdGains - 1));
#endif
#else
tpcrg1 = OS_REG_READ(ah, AR_PHY_TPCRG1);
tpcrg1 = (tpcrg1 &~ AR_PHY_TPCRG1_NUM_PD_GAIN)
| SM(numPdGainsUsed-1, AR_PHY_TPCRG1_NUM_PD_GAIN);
@ -600,6 +609,7 @@ ar5413SetPowerTable(struct ath_hal *ah,
__func__, OS_REG_READ(ah, AR_PHY_TPCRG1), tpcrg1);
#endif
OS_REG_WRITE(ah, AR_PHY_TPCRG1, tpcrg1);
#endif
/*
* Note the pdadc table may not start at 0 dBm power, could be

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ar5312.h,v 1.4 2008/11/10 04:08:04 sam Exp $
* $Id: ar5312.h,v 1.5 2008/11/22 07:37:40 sam Exp $
*/
#ifndef _ATH_AR5312_H_
#define _ATH_AR5312_H_
@ -30,15 +30,13 @@
(((const struct ar531x_config *)((_ah)->ah_st))->radio)
#define IS_5312_2_X(ah) \
(((AH_PRIVATE(ah)->ah_macVersion) == AR_SREV_VERSION_VENICE) && \
(((AH_PRIVATE(ah)->ah_macRev) == 2) || ((AH_PRIVATE(ah)->ah_macRev) == 7)))
(AH_PRIVATE(ah)->ah_macVersion == AR_SREV_VERSION_VENICE && \
(AH_PRIVATE(ah)->ah_macRev == 2 || AH_PRIVATE(ah)->ah_macRev == 7))
#define IS_5315(ah) \
((AH_PRIVATE(ah)->ah_devid == AR5212_AR2315_REV6) || \
(AH_PRIVATE(ah)->ah_devid == AR5212_AR2315_REV7) || \
(AH_PRIVATE(ah)->ah_devid == AR5212_AR2317_REV1) || \
(AH_PRIVATE(ah)->ah_devid == AR5212_AR2317_REV2))
(AH_PRIVATE(ah)->ah_devid == AR5212_AR2315_REV6 || \
AH_PRIVATE(ah)->ah_devid == AR5212_AR2315_REV7 || \
AH_PRIVATE(ah)->ah_devid == AR5212_AR2317_REV1 || \
AH_PRIVATE(ah)->ah_devid == AR5212_AR2317_REV2)
extern struct ath_hal * ar5312Attach(uint16_t devid, HAL_SOFTC sc,
HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS *status);
@ -76,5 +74,6 @@ extern HAL_BOOL ar5312GetPowerStatus(struct ath_hal *ah);
/* BSP functions */
extern HAL_BOOL ar5312EepromRead(struct ath_hal *, u_int off, uint16_t *data);
extern HAL_BOOL ar5312EepromWrite(struct ath_hal *, u_int off, uint16_t data);
#endif /* _ATH_AR3212_H_ */

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ar5312_attach.c,v 1.6 2008/11/10 04:08:04 sam Exp $
* $Id: ar5312_attach.c,v 1.8 2008/11/27 22:30:03 sam Exp $
*/
#include "opt_ah.h"
@ -39,13 +39,6 @@
#define AH_5212_COMMON
#include "ar5212/ar5212.ini"
/*
* These are not valid 2.4 channels, either we change these
* or we need to change the coding to accept these
*/
static const uint16_t channels11b[] = { 2412, 2447, 2484 };
static const uint16_t channels11g[] = { 2312, 2412, 2484 };
static HAL_BOOL ar5312GetMacAddr(struct ath_hal *ah);
static void
@ -217,7 +210,7 @@ ar5312Attach(uint16_t devid, HAL_SOFTC sc,
goto bad;
}
#endif
if (IS_5112(ah) && !IS_RADX112_REV2(ah)) {
if (IS_RAD5112(ah) && !IS_RADX112_REV2(ah)) {
#ifdef AH_DEBUG
ath_hal_printf(ah, "%s: 5112 Rev 1 is not supported by this "
"driver (analog5GhzRev 0x%x)\n", __func__,
@ -293,13 +286,13 @@ ar5312Attach(uint16_t devid, HAL_SOFTC sc,
#else
ecode = HAL_ENOTSUPP;
#endif
else if (IS_5112(ah))
else if (IS_RAD5112_ANY(ah))
#ifdef AH_SUPPORT_5112
rfStatus = ar5112RfAttach(ah, &ecode);
#else
ecode = HAL_ENOTSUPP;
#endif
else
else if (IS_RAD5111(ah))
#ifdef AH_SUPPORT_5111
rfStatus = ar5111RfAttach(ah, &ecode);
#else

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ar5312_misc.c,v 1.3 2008/11/10 04:08:04 sam Exp $
* $Id: ar5312_misc.c,v 1.4 2008/11/22 07:40:15 sam Exp $
*/
#include "opt_ah.h"
@ -108,7 +108,8 @@ ar5312SetupClock(struct ath_hal *ah, HAL_OPMODE opmode)
OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0c);
OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x03);
OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0x05);
OS_REG_WRITE(ah, AR_PHY_REFCLKPD, (IS_5112(ah) || IS_2413(ah)) ? 0x14 : 0x18);
OS_REG_WRITE(ah, AR_PHY_REFCLKPD,
IS_RAD5112_ANY(ah) ? 0x14 : 0x18);
OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, 1);
OS_REG_WRITE(ah, AR_TSF_PARM, 61); /* 32 KHz TSF incr */
@ -116,7 +117,7 @@ ar5312SetupClock(struct ath_hal *ah, HAL_OPMODE opmode)
} else {
OS_REG_WRITE(ah, AR_TSF_PARM, 1); /* 32 MHz TSF incr */
OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32,
(IS_5112(ah) || IS_2413(ah)) ? 39 : 31);
IS_RAD5112_ANY(ah) ? 39 : 31);
OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f);
OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x7f);
@ -128,7 +129,8 @@ ar5312SetupClock(struct ath_hal *ah, HAL_OPMODE opmode)
OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e);
OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x0c);
OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0xff);
OS_REG_WRITE(ah, AR_PHY_REFCLKPD, (IS_5112(ah) || IS_2413(ah)) ? 0x14 : 0x18);
OS_REG_WRITE(ah, AR_PHY_REFCLKPD,
IS_RAD5112_ANY(ah) ? 0x14 : 0x18);
}
}
}
@ -143,7 +145,7 @@ ar5312RestoreClock(struct ath_hal *ah, HAL_OPMODE opmode)
/* # Set sleep clock rate back to 32 MHz. */
OS_REG_WRITE(ah, AR_TSF_PARM, 1); /* 32 MHz TSF incr */
OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32,
(IS_5112(ah) || IS_2413(ah)) ? 39 : 31);
IS_RAD5112_ANY(ah) ? 39 : 31);
/*
* Restore BB registers to power-on defaults
@ -157,7 +159,8 @@ ar5312RestoreClock(struct ath_hal *ah, HAL_OPMODE opmode)
OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e);
OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x0c);
OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0xff);
OS_REG_WRITE(ah, AR_PHY_REFCLKPD, (IS_5112(ah) || IS_2413(ah)) ? 0x14 : 0x18);
OS_REG_WRITE(ah, AR_PHY_REFCLKPD,
IS_RAD5112_ANY(ah) ? 0x14 : 0x18);
}
}
}

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ar5312_reset.c,v 1.9 2008/11/10 04:08:04 sam Exp $
* $Id: ar5312_reset.c,v 1.10 2008/11/22 07:41:37 sam Exp $
*/
#include "opt_ah.h"
@ -173,7 +173,7 @@ ar5312Reset(struct ath_hal *ah, HAL_OPMODE opmode,
* -channel change requested - so it's not the initial reset.
* -it's not a change to the current channel - often called when switching modes
* on a channel
* -the modes of the previous and requested channel are the same
* -the modes of the previous and requested channel are the same - some ugly code for XR
*/
if (bChannelChange &&
(AH_PRIVATE(ah)->ah_curchan != AH_NULL) &&
@ -406,8 +406,9 @@ ar5312Reset(struct ath_hal *ah, HAL_OPMODE opmode,
ar5212SetRateDurationTable(ah, chan);
/* Set Tx frame start to tx data start delay */
if (IS_5112(ah) && (IS_CHAN_HALF_RATE(AH_PRIVATE(ah)->ah_curchan) ||
IS_CHAN_QUARTER_RATE(AH_PRIVATE(ah)->ah_curchan))) {
if (IS_RAD5112_ANY(ah) &&
(IS_CHAN_HALF_RATE(AH_PRIVATE(ah)->ah_curchan) ||
IS_CHAN_QUARTER_RATE(AH_PRIVATE(ah)->ah_curchan))) {
txFrm2TxDStart =
(IS_CHAN_HALF_RATE(AH_PRIVATE(ah)->ah_curchan)) ?
TX_FRAME_D_START_HALF_RATE:
@ -679,7 +680,7 @@ ar5312ChipReset(struct ath_hal *ah, HAL_CHANNEL *chan)
if (chan != AH_NULL) { /* NB: can be null during attach */
uint32_t rfMode, phyPLL = 0, curPhyPLL, turbo;
if (IS_5112(ah) || IS_2413(ah)) {
if (IS_RAD5112_ANY(ah)) {
rfMode = AR_PHY_MODE_AR5112;
if (!IS_5315(ah)) {
if (IS_CHAN_CCK(chan) || IS_CHAN_G(chan)) {
@ -694,31 +695,25 @@ ar5312ChipReset(struct ath_hal *ah, HAL_CHANNEL *chan)
}
}
} else {
if (IS_CHAN_CCK(chan) || IS_CHAN_G(chan)) {
if (IS_CHAN_CCK(chan) || IS_CHAN_G(chan))
phyPLL = AR_PHY_PLL_CTL_44_5112;
} else {
if (IS_CHAN_HALF_RATE(chan)) {
phyPLL = AR_PHY_PLL_CTL_40_5112_HALF;
} else if (IS_CHAN_QUARTER_RATE(chan)) {
phyPLL = AR_PHY_PLL_CTL_40_5112_QUARTER;
} else {
phyPLL = AR_PHY_PLL_CTL_40_5112;
}
}
else
phyPLL = AR_PHY_PLL_CTL_40_5112;
if (IS_CHAN_HALF_RATE(chan))
phyPLL |= AR_PHY_PLL_CTL_HALF;
else if (IS_CHAN_QUARTER_RATE(chan))
phyPLL |= AR_PHY_PLL_CTL_QUARTER;
}
} else {
rfMode = AR_PHY_MODE_AR5111;
if (IS_CHAN_CCK(chan) || IS_CHAN_G(chan)) {
if (IS_CHAN_CCK(chan) || IS_CHAN_G(chan))
phyPLL = AR_PHY_PLL_CTL_44;
} else {
if (IS_CHAN_HALF_RATE(chan)) {
phyPLL = AR_PHY_PLL_CTL_40_HALF;
} else if (IS_CHAN_QUARTER_RATE(chan)) {
phyPLL = AR_PHY_PLL_CTL_40_QUARTER;
} else {
phyPLL = AR_PHY_PLL_CTL_40;
}
}
else
phyPLL = AR_PHY_PLL_CTL_40;
if (IS_CHAN_HALF_RATE(chan))
phyPLL = AR_PHY_PLL_CTL_HALF;
else if (IS_CHAN_QUARTER_RATE(chan))
phyPLL = AR_PHY_PLL_CTL_QUARTER;
}
if (IS_CHAN_OFDM(chan) && (IS_CHAN_CCK(chan) ||
IS_CHAN_G(chan)))

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ar2133.c,v 1.10 2008/11/10 04:08:04 sam Exp $
* $Id: ar2133.c,v 1.13 2008/11/11 00:11:30 sam Exp $
*/
#include "opt_ah.h"
@ -330,6 +330,64 @@ ar2133GetChannelMaxMinPower(struct ath_hal *ah, HAL_CHANNEL *chan, int16_t *maxP
#endif
}
static void
ar2133GetNoiseFloor(struct ath_hal *ah, int16_t nfarray[])
{
struct ath_hal_5416 *ahp = AH5416(ah);
int16_t nf;
switch (ahp->ah_rx_chainmask) {
case 0x7:
nf = MS(OS_REG_READ(ah, AR_PHY_CH2_CCA), AR_PHY_CH2_MINCCA_PWR);
if (nf & 0x100)
nf = 0 - ((nf ^ 0x1ff) + 1);
HALDEBUG(ah, HAL_DEBUG_NFCAL,
"NF calibrated [ctl] [chain 2] is %d\n", nf);
nfarray[4] = nf;
nf = MS(OS_REG_READ(ah, AR_PHY_CH2_EXT_CCA), AR_PHY_CH2_EXT_MINCCA_PWR);
if (nf & 0x100)
nf = 0 - ((nf ^ 0x1ff) + 1);
HALDEBUG(ah, HAL_DEBUG_NFCAL,
"NF calibrated [ext] [chain 2] is %d\n", nf);
nfarray[5] = nf;
/* fall thru... */
case 0x3:
case 0x5:
nf = MS(OS_REG_READ(ah, AR_PHY_CH1_CCA), AR_PHY_CH1_MINCCA_PWR);
if (nf & 0x100)
nf = 0 - ((nf ^ 0x1ff) + 1);
HALDEBUG(ah, HAL_DEBUG_NFCAL,
"NF calibrated [ctl] [chain 1] is %d\n", nf);
nfarray[2] = nf;
nf = MS(OS_REG_READ(ah, AR_PHY_CH1_EXT_CCA), AR_PHY_CH1_EXT_MINCCA_PWR);
if (nf & 0x100)
nf = 0 - ((nf ^ 0x1ff) + 1);
HALDEBUG(ah, HAL_DEBUG_NFCAL,
"NF calibrated [ext] [chain 1] is %d\n", nf);
nfarray[3] = nf;
/* fall thru... */
case 0x1:
nf = MS(OS_REG_READ(ah, AR_PHY_CCA), AR_PHY_MINCCA_PWR);
if (nf & 0x100)
nf = 0 - ((nf ^ 0x1ff) + 1);
HALDEBUG(ah, HAL_DEBUG_NFCAL,
"NF calibrated [ctl] [chain 0] is %d\n", nf);
nfarray[0] = nf;
nf = MS(OS_REG_READ(ah, AR_PHY_EXT_CCA), AR_PHY_EXT_MINCCA_PWR);
if (nf & 0x100)
nf = 0 - ((nf ^ 0x1ff) + 1);
HALDEBUG(ah, HAL_DEBUG_NFCAL,
"NF calibrated [ext] [chain 0] is %d\n", nf);
nfarray[1] = nf;
break;
}
}
/*
* Adjust NF based on statistical values for 5GHz frequencies.
* Stubbed:Not used by Fowl
@ -404,6 +462,7 @@ ar2133RfAttach(struct ath_hal *ah, HAL_STATUS *status)
* direct call instead of thunking.
*/
AH_PRIVATE(ah)->ah_getNfAdjust = priv->base.getNfAdjust;
AH_PRIVATE(ah)->ah_getNoiseFloor = ar2133GetNoiseFloor;
return AH_TRUE;
}

View File

@ -14,19 +14,20 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ar5416.h,v 1.16 2008/11/10 04:08:04 sam Exp $
* $Id: ar5416.h,v 1.19 2008/11/11 21:38:13 sam Exp $
*/
#ifndef _ATH_AR5416_H_
#define _ATH_AR5416_H_
#include "ar5212/ar5212.h"
#include "ar5416_cal.h"
#define AR5416_MAGIC 0x20065416
enum {
HAL_RESET_POWER_ON,
HAL_RESET_WARM,
HAL_RESET_COLD,
HAL_RESET_POWER_ON,
HAL_RESET_WARM,
HAL_RESET_COLD,
};
typedef struct {
@ -40,71 +41,10 @@ typedef struct {
#define AR5416_MAX_RATE_POWER 63
#define AR5416_KEYTABLE_SIZE 128
#define AR5416_NUM_NF_READINGS 6 /* (3 chains * (ctl + ext) */
#define AR5416_CCA_MAX_GOOD_VALUE -85
#define AR5416_CCA_MAX_HIGH_VALUE -62
#define AR5416_CCA_MIN_BAD_VALUE -140
#define INIT_CAL(_perCal) do { \
(_perCal)->calState = CAL_WAITING; \
(_perCal)->calNext = AH_NULL; \
} while (0)
#define INSERT_CAL(_ahp, _perCal) do { \
if ((_ahp)->ah_cal_last == AH_NULL) { \
(_ahp)->ah_cal_list = (_ahp)->ah_cal_last = (_perCal); \
((_ahp)->ah_cal_last)->calNext = (_perCal); \
} else { \
((_ahp)->ah_cal_last)->calNext = (_perCal); \
(_ahp)->ah_cal_last = (_perCal); \
(_perCal)->calNext = (_ahp)->ah_cal_list; \
} \
} while (0)
typedef enum cal_types {
ADC_DC_INIT_CAL = 0x1,
ADC_GAIN_CAL = 0x2,
ADC_DC_CAL = 0x4,
IQ_MISMATCH_CAL = 0x8
} HAL_CAL_TYPE;
/* Calibrate state */
typedef enum cal_state {
CAL_INACTIVE,
CAL_WAITING,
CAL_RUNNING,
CAL_DONE
} HAL_CAL_STATE;
typedef union {
uint32_t u;
int32_t s;
} HAL_CAL_SAMPLE;
#define MIN_CAL_SAMPLES 1
#define MAX_CAL_SAMPLES 64
#define INIT_LOG_COUNT 5
#define PER_MIN_LOG_COUNT 2
#define PER_MAX_LOG_COUNT 10
/* Per Calibration data structure */
typedef struct per_cal_data {
const char *calName; /* for diagnostics */
HAL_CAL_TYPE calType; /* Type of calibration */
uint32_t calNumSamples; /* # SW samples to collect */
uint32_t calCountMax; /* # HW samples to collect */
void (*calCollect)(struct ath_hal *); /* Accumulator function */
/* Post-processing function */
void (*calPostProc)(struct ath_hal *, uint8_t);
} HAL_PERCAL_DATA;
/* List structure for calibration data */
typedef struct cal_list {
struct cal_list *calNext;
HAL_CAL_STATE calState;
const HAL_PERCAL_DATA *calData;
} HAL_CAL_LIST;
struct ath_hal_5416 {
struct ath_hal_5212 ah_5212;
@ -119,7 +59,6 @@ struct ath_hal_5416 {
HAL_INI_ARRAY ah_ini_addac;
u_int ah_globaltxtimeout; /* global tx timeout */
int ah_clksel;
int ah_hangs; /* h/w hangs state */
uint8_t ah_keytype[AR5416_KEYTABLE_SIZE];
/*
@ -130,43 +69,11 @@ struct ath_hal_5416 {
uint32_t ah_extBusy;
uint32_t ah_rx_chainmask;
uint32_t ah_tx_chainmask;
/*
* Periodic calibration state.
*/
HAL_CAL_TYPE ah_suppCals;
HAL_CAL_LIST ah_iqCalData;
HAL_CAL_LIST ah_adcGainCalData;
HAL_CAL_LIST ah_adcDcCalInitData;
HAL_CAL_LIST ah_adcDcCalData;
HAL_CAL_LIST *ah_cal_list;
HAL_CAL_LIST *ah_cal_last;
HAL_CAL_LIST *ah_cal_curr;
#define AR5416_MAX_CHAINS 3 /* XXX dup's eeprom def */
HAL_CAL_SAMPLE ah_caldata[4][AR5416_MAX_CHAINS];
int ah_calSamples;
/*
* Noise floor cal histogram support.
* XXX be nice to re-use space in ar5212
*/
struct ar5212NfCalHist ah_nfCalHist[AR5416_NUM_NF_READINGS];
struct ar5416PerCal ah_cal; /* periodic calibration state */
};
#define AH5416(_ah) ((struct ath_hal_5416 *)(_ah))
/* IQ Cal aliases */
#define ah_totalPowerMeasI(i) ah_caldata[0][i].u
#define ah_totalPowerMeasQ(i) ah_caldata[1][i].u
#define ah_totalIqCorrMeas(i) ah_caldata[2][i].s
/* Adc Gain Cal aliases */
#define ah_totalAdcIOddPhase(i) ah_caldata[0][i].u
#define ah_totalAdcIEvenPhase(i) ah_caldata[1][i].u
#define ah_totalAdcQOddPhase(i) ah_caldata[2][i].u
#define ah_totalAdcQEvenPhase(i) ah_caldata[3][i].u
/* Adc DC Offset Cal aliases */
#define ah_totalAdcDcOffsetIOddPhase(i) ah_caldata[0][i].s
#define ah_totalAdcDcOffsetIEvenPhase(i) ah_caldata[1][i].s
#define ah_totalAdcDcOffsetQOddPhase(i) ah_caldata[2][i].s
#define ah_totalAdcDcOffsetQEvenPhase(i) ah_caldata[3][i].s
#define IS_5416_PCI(ah) ((AH_PRIVATE(ah)->ah_macVersion) == AR_SREV_VERSION_OWL_PCI)
#define IS_5416_PCIE(ah) ((AH_PRIVATE(ah)->ah_macVersion) == AR_SREV_VERSION_OWL_PCIE)
#undef IS_PCIE
@ -187,8 +94,17 @@ extern HAL_BOOL ar5416FillCapabilityInfo(struct ath_hal *ah);
#define IS_5GHZ_FAST_CLOCK_EN(_ah, _c) \
(IS_CHAN_5GHZ(_c) && ath_hal_eepromGetFlag(ah, AR_EEP_FSTCLK_5G))
extern HAL_BOOL ar5416AniAttach(struct ath_hal *ah);
extern void ar5416AniDetach(struct ath_hal *ah);
extern void ar5416AniAttach(struct ath_hal *, const struct ar5212AniParams *,
const struct ar5212AniParams *, HAL_BOOL ena);
extern void ar5416AniDetach(struct ath_hal *);
extern HAL_BOOL ar5416AniControl(struct ath_hal *, HAL_ANI_CMD cmd, int param);
extern HAL_BOOL ar5416AniSetParams(struct ath_hal *,
const struct ar5212AniParams *, const struct ar5212AniParams *);
extern void ar5416ProcessMibIntr(struct ath_hal *, const HAL_NODE_STATS *);
extern void ar5416AniPoll(struct ath_hal *, const HAL_NODE_STATS *,
HAL_CHANNEL *);
extern void ar5416AniReset(struct ath_hal *, HAL_CHANNEL_INTERNAL *,
HAL_OPMODE, int);
extern void ar5416SetBeaconTimers(struct ath_hal *, const HAL_BEACON_TIMERS *);
extern void ar5416BeaconInit(struct ath_hal *ah,
@ -250,17 +166,6 @@ extern HAL_RFGAIN ar5416GetRfgain(struct ath_hal *ah);
extern HAL_BOOL ar5416Disable(struct ath_hal *ah);
extern HAL_BOOL ar5416ChipReset(struct ath_hal *ah, HAL_CHANNEL *);
extern HAL_BOOL ar5416SetResetReg(struct ath_hal *, uint32_t type);
extern HAL_BOOL ar5416PerCalibration(struct ath_hal *, HAL_CHANNEL *,
HAL_BOOL *isIQdone);
extern void ar5416ResetCalValid(struct ath_hal *ah, HAL_CHANNEL *chan,
HAL_BOOL *isIQdone);
extern void ar5416IQCalCollect(struct ath_hal *ah);
extern void ar5416IQCalibration(struct ath_hal *ah, uint8_t numChains);
extern void ar5416AdcGainCalCollect(struct ath_hal *ah);
extern void ar5416AdcGainCalibration(struct ath_hal *ah, uint8_t numChains);
extern void ar5416AdcDcCalCollect(struct ath_hal *ah);
extern void ar5416AdcDcCalibration(struct ath_hal *ah, uint8_t numChains);
extern void ar5416InitNfHistBuff(struct ar5212NfCalHist *h);
extern HAL_BOOL ar5416SetTxPowerLimit(struct ath_hal *ah, uint32_t limit);
extern HAL_BOOL ar5416GetChipPowerLimits(struct ath_hal *ah,
HAL_CHANNEL *chans, uint32_t nchans);

888
ar5416/ar5416_ani.c Normal file
View File

@ -0,0 +1,888 @@
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
*
* Permission to use, copy, modify, and/or 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.
*
* $Id: ar5416_ani.c,v 1.1 2008/11/11 20:46:06 sam Exp $
*/
#include "opt_ah.h"
#ifdef AH_SUPPORT_AR5416
/*
* XXX this is virtually the same code as for 5212; we reuse
* storage in the 5212 state block; need to refactor.
*/
#include "ah.h"
#include "ah_internal.h"
#include "ah_desc.h"
#include "ar5416/ar5416.h"
#include "ar5416/ar5416reg.h"
#include "ar5416/ar5416phy.h"
/*
* Anti noise immunity support. We track phy errors and react
* to excessive errors by adjusting the noise immunity parameters.
*/
#define HAL_EP_RND(x, mul) \
((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
#define BEACON_RSSI(ahp) \
HAL_EP_RND(ahp->ah_stats.ast_nodestats.ns_avgbrssi, \
HAL_RSSI_EP_MULTIPLIER)
/*
* ANI processing tunes radio parameters according to PHY errors
* and related information. This is done for for noise and spur
* immunity in all operating modes if the device indicates it's
* capable at attach time. In addition, when there is a reference
* rssi value (e.g. beacon frames from an ap in station mode)
* further tuning is done.
*
* ANI_ENA indicates whether any ANI processing should be done;
* this is specified at attach time.
*
* ANI_ENA_RSSI indicates whether rssi-based processing should
* done, this is enabled based on operating mode and is meaningful
* only if ANI_ENA is true.
*
* ANI parameters are typically controlled only by the hal. The
* AniControl interface however permits manual tuning through the
* diagnostic api.
*/
#define ANI_ENA(ah) \
(AH5212(ah)->ah_procPhyErr & HAL_ANI_ENA)
#define ANI_ENA_RSSI(ah) \
(AH5212(ah)->ah_procPhyErr & HAL_RSSI_ANI_ENA)
#define ah_mibStats ah_stats.ast_mibstats
static void
enableAniMIBCounters(struct ath_hal *ah, const struct ar5212AniParams *params)
{
struct ath_hal_5212 *ahp = AH5212(ah);
HALDEBUG(ah, HAL_DEBUG_ANI, "%s: Enable mib counters: "
"OfdmPhyErrBase 0x%x cckPhyErrBase 0x%x\n",
__func__, params->ofdmPhyErrBase, params->cckPhyErrBase);
OS_REG_WRITE(ah, AR_FILTOFDM, 0);
OS_REG_WRITE(ah, AR_FILTCCK, 0);
OS_REG_WRITE(ah, AR_PHYCNT1, params->ofdmPhyErrBase);
OS_REG_WRITE(ah, AR_PHYCNT2, params->cckPhyErrBase);
OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
ar5212UpdateMibCounters(ah, &ahp->ah_mibStats); /* save+clear counters*/
ar5212EnableMibCounters(ah); /* enable everything */
}
static void
disableAniMIBCounters(struct ath_hal *ah)
{
struct ath_hal_5212 *ahp = AH5212(ah);
HALDEBUG(ah, HAL_DEBUG_ANI, "Disable MIB counters\n");
ar5212UpdateMibCounters(ah, &ahp->ah_mibStats); /* save stats */
ar5212DisableMibCounters(ah); /* disable everything */
OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, 0);
OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, 0);
}
/*
* This routine returns the index into the aniState array that
* corresponds to the channel in *chan. If no match is found and the
* array is still not fully utilized, a new entry is created for the
* channel. We assume the attach function has already initialized the
* ah_ani values and only the channel field needs to be set.
*/
static int
ar5416GetAniChannelIndex(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan)
{
#define N(a) (sizeof(a) / sizeof(a[0]))
struct ath_hal_5212 *ahp = AH5212(ah);
int i;
for (i = 0; i < N(ahp->ah_ani); i++) {
struct ar5212AniState *asp = &ahp->ah_ani[i];
if (asp->c.channel == chan->channel)
return i;
if (asp->c.channel == 0) {
asp->c.channel = chan->channel;
asp->c.channelFlags = chan->channelFlags;
asp->c.privFlags = chan->privFlags;
asp->isSetup = AH_FALSE;
if (IS_CHAN_2GHZ(chan))
asp->params = &ahp->ah_aniParams24;
else
asp->params = &ahp->ah_aniParams5;
return i;
}
}
/* XXX statistic */
HALDEBUG(ah, HAL_DEBUG_ANY,
"No more channel states left. Using channel 0\n");
return 0; /* XXX gotta return something valid */
#undef N
}
static void
setPhyErrBase(struct ath_hal *ah, struct ar5212AniParams *params)
{
if (params->ofdmTrigHigh >= AR_PHY_COUNTMAX) {
HALDEBUG(ah, HAL_DEBUG_ANY,
"OFDM Trigger %d is too high for hw counters, using max\n",
params->ofdmTrigHigh);
params->ofdmPhyErrBase = 0;
} else
params->ofdmPhyErrBase = AR_PHY_COUNTMAX - params->ofdmTrigHigh;
if (params->cckTrigHigh >= AR_PHY_COUNTMAX) {
HALDEBUG(ah, HAL_DEBUG_ANY,
"CCK Trigger %d is too high for hw counters, using max\n",
params->cckTrigHigh);
params->cckPhyErrBase = 0;
} else
params->cckPhyErrBase = AR_PHY_COUNTMAX - params->cckTrigHigh;
}
/*
* Setup ANI handling. Sets all thresholds and reset the
* channel statistics. Note that ar5416AniReset should be
* called by ar5416Reset before anything else happens and
* that's where we force initial settings.
*/
void
ar5416AniAttach(struct ath_hal *ah, const struct ar5212AniParams *params24,
const struct ar5212AniParams *params5, HAL_BOOL enable)
{
struct ath_hal_5212 *ahp = AH5212(ah);
if (params24 != AH_NULL) {
OS_MEMCPY(&ahp->ah_aniParams24, params24, sizeof(*params24));
setPhyErrBase(ah, &ahp->ah_aniParams24);
}
if (params5 != AH_NULL) {
OS_MEMCPY(&ahp->ah_aniParams5, params5, sizeof(*params5));
setPhyErrBase(ah, &ahp->ah_aniParams5);
}
OS_MEMZERO(ahp->ah_ani, sizeof(ahp->ah_ani));
/* Enable MIB Counters */
enableAniMIBCounters(ah, &ahp->ah_aniParams24 /*XXX*/);
if (enable) { /* Enable ani now */
HALASSERT(params24 != AH_NULL && params5 != AH_NULL);
ahp->ah_procPhyErr |= HAL_ANI_ENA;
} else {
ahp->ah_procPhyErr &= ~HAL_ANI_ENA;
}
}
/*
* Cleanup any ANI state setup.
*/
void
ar5416AniDetach(struct ath_hal *ah)
{
HALDEBUG(ah, HAL_DEBUG_ANI, "Detaching Ani\n");
disableAniMIBCounters(ah);
}
/*
* Control Adaptive Noise Immunity Parameters
*/
HAL_BOOL
ar5416AniControl(struct ath_hal *ah, HAL_ANI_CMD cmd, int param)
{
typedef int TABLE[];
struct ath_hal_5212 *ahp = AH5212(ah);
struct ar5212AniState *aniState = ahp->ah_curani;
const struct ar5212AniParams *params = aniState->params;
OS_MARK(ah, AH_MARK_ANI_CONTROL, cmd);
switch (cmd) {
case HAL_ANI_NOISE_IMMUNITY_LEVEL: {
u_int level = param;
if (level >= params->maxNoiseImmunityLevel) {
HALDEBUG(ah, HAL_DEBUG_ANY,
"%s: level out of range (%u > %u)\n",
__func__, level, params->maxNoiseImmunityLevel);
return AH_FALSE;
}
OS_REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
AR_PHY_DESIRED_SZ_TOT_DES, params->totalSizeDesired[level]);
OS_REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
AR_PHY_AGC_CTL1_COARSE_LOW, params->coarseLow[level]);
OS_REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
AR_PHY_AGC_CTL1_COARSE_HIGH, params->coarseHigh[level]);
OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
AR_PHY_FIND_SIG_FIRPWR, params->firpwr[level]);
if (level > aniState->noiseImmunityLevel)
ahp->ah_stats.ast_ani_niup++;
else if (level < aniState->noiseImmunityLevel)
ahp->ah_stats.ast_ani_nidown++;
aniState->noiseImmunityLevel = level;
break;
}
case HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION: {
static const TABLE m1ThreshLow = { 127, 50 };
static const TABLE m2ThreshLow = { 127, 40 };
static const TABLE m1Thresh = { 127, 0x4d };
static const TABLE m2Thresh = { 127, 0x40 };
static const TABLE m2CountThr = { 31, 16 };
static const TABLE m2CountThrLow = { 63, 48 };
u_int on = param ? 1 : 0;
OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
AR_PHY_SFCORR_LOW_M1_THRESH_LOW, m1ThreshLow[on]);
OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
AR_PHY_SFCORR_LOW_M2_THRESH_LOW, m2ThreshLow[on]);
OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR,
AR_PHY_SFCORR_M1_THRESH, m1Thresh[on]);
OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR,
AR_PHY_SFCORR_M2_THRESH, m2Thresh[on]);
OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR,
AR_PHY_SFCORR_M2COUNT_THR, m2CountThr[on]);
OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, m2CountThrLow[on]);
OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1ThreshLow[on]);
OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
AR_PHY_SFCORR_EXT_M2_THRESH_LOW, m2ThreshLow[on]);
OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
AR_PHY_SFCORR_EXT_M1_THRESH, m1Thresh[on]);
OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
AR_PHY_SFCORR_EXT_M2_THRESH, m2Thresh[on]);
if (on) {
OS_REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
} else {
OS_REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
}
if (on)
ahp->ah_stats.ast_ani_ofdmon++;
else
ahp->ah_stats.ast_ani_ofdmoff++;
aniState->ofdmWeakSigDetectOff = !on;
break;
}
case HAL_ANI_CCK_WEAK_SIGNAL_THR: {
static const TABLE weakSigThrCck = { 8, 6 };
u_int high = param ? 1 : 0;
OS_REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT,
AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK, weakSigThrCck[high]);
if (high)
ahp->ah_stats.ast_ani_cckhigh++;
else
ahp->ah_stats.ast_ani_ccklow++;
aniState->cckWeakSigThreshold = high;
break;
}
case HAL_ANI_FIRSTEP_LEVEL: {
u_int level = param;
if (level >= params->maxFirstepLevel) {
HALDEBUG(ah, HAL_DEBUG_ANY,
"%s: level out of range (%u > %u)\n",
__func__, level, params->maxFirstepLevel);
return AH_FALSE;
}
OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
AR_PHY_FIND_SIG_FIRSTEP, params->firstep[level]);
if (level > aniState->firstepLevel)
ahp->ah_stats.ast_ani_stepup++;
else if (level < aniState->firstepLevel)
ahp->ah_stats.ast_ani_stepdown++;
aniState->firstepLevel = level;
break;
}
case HAL_ANI_SPUR_IMMUNITY_LEVEL: {
u_int level = param;
if (level >= params->maxSpurImmunityLevel) {
HALDEBUG(ah, HAL_DEBUG_ANY,
"%s: level out of range (%u > %u)\n",
__func__, level, params->maxSpurImmunityLevel);
return AH_FALSE;
}
OS_REG_RMW_FIELD(ah, AR_PHY_TIMING5,
AR_PHY_TIMING5_CYCPWR_THR1, params->cycPwrThr1[level]);
if (level > aniState->spurImmunityLevel)
ahp->ah_stats.ast_ani_spurup++;
else if (level < aniState->spurImmunityLevel)
ahp->ah_stats.ast_ani_spurdown++;
aniState->spurImmunityLevel = level;
break;
}
case HAL_ANI_PRESENT:
break;
case HAL_ANI_MODE:
if (param == 0) {
ahp->ah_procPhyErr &= ~HAL_ANI_ENA;
/* Turn off HW counters if we have them */
ar5416AniDetach(ah);
ar5212SetRxFilter(ah,
ar5212GetRxFilter(ah) &~ HAL_RX_FILTER_PHYERR);
} else { /* normal/auto mode */
/* don't mess with state if already enabled */
if (ahp->ah_procPhyErr & HAL_ANI_ENA)
break;
ar5212SetRxFilter(ah,
ar5212GetRxFilter(ah) &~ HAL_RX_FILTER_PHYERR);
/* Enable MIB Counters */
enableAniMIBCounters(ah, ahp->ah_curani != AH_NULL ?
ahp->ah_curani->params: &ahp->ah_aniParams24 /*XXX*/);
ahp->ah_procPhyErr |= HAL_ANI_ENA;
}
break;
#ifdef AH_PRIVATE_DIAG
case HAL_ANI_PHYERR_RESET:
ahp->ah_stats.ast_ani_ofdmerrs = 0;
ahp->ah_stats.ast_ani_cckerrs = 0;
break;
#endif /* AH_PRIVATE_DIAG */
default:
HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid cmd %u\n",
__func__, cmd);
return AH_FALSE;
}
return AH_TRUE;
}
static void
ar5416AniOfdmErrTrigger(struct ath_hal *ah)
{
struct ath_hal_5212 *ahp = AH5212(ah);
HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan;
struct ar5212AniState *aniState;
const struct ar5212AniParams *params;
HALASSERT(chan != AH_NULL);
if (!ANI_ENA(ah))
return;
aniState = ahp->ah_curani;
params = aniState->params;
/* First, raise noise immunity level, up to max */
if (aniState->noiseImmunityLevel+1 < params->maxNoiseImmunityLevel) {
ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL,
aniState->noiseImmunityLevel + 1);
return;
}
/* then, raise spur immunity level, up to max */
if (aniState->spurImmunityLevel+1 < params->maxSpurImmunityLevel) {
ar5416AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL,
aniState->spurImmunityLevel + 1);
return;
}
if (ANI_ENA_RSSI(ah)) {
int32_t rssi = BEACON_RSSI(ahp);
if (rssi > params->rssiThrHigh) {
/*
* Beacon rssi is high, can turn off ofdm
* weak sig detect.
*/
if (!aniState->ofdmWeakSigDetectOff) {
ar5416AniControl(ah,
HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
AH_FALSE);
ar5416AniControl(ah,
HAL_ANI_SPUR_IMMUNITY_LEVEL, 0);
return;
}
/*
* If weak sig detect is already off, as last resort,
* raise firstep level
*/
if (aniState->firstepLevel+1 < params->maxFirstepLevel) {
ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
aniState->firstepLevel + 1);
return;
}
} else if (rssi > params->rssiThrLow) {
/*
* Beacon rssi in mid range, need ofdm weak signal
* detect, but we can raise firststepLevel.
*/
if (aniState->ofdmWeakSigDetectOff)
ar5416AniControl(ah,
HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
AH_TRUE);
if (aniState->firstepLevel+1 < params->maxFirstepLevel)
ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
aniState->firstepLevel + 1);
return;
} else {
/*
* Beacon rssi is low, if in 11b/g mode, turn off ofdm
* weak signal detection and zero firstepLevel to
* maximize CCK sensitivity
*/
/* XXX can optimize */
if (IS_CHAN_B(chan) || IS_CHAN_G(chan)) {
if (!aniState->ofdmWeakSigDetectOff)
ar5416AniControl(ah,
HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
AH_FALSE);
if (aniState->firstepLevel > 0)
ar5416AniControl(ah,
HAL_ANI_FIRSTEP_LEVEL, 0);
return;
}
}
}
}
static void
ar5416AniCckErrTrigger(struct ath_hal *ah)
{
struct ath_hal_5212 *ahp = AH5212(ah);
HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan;
struct ar5212AniState *aniState;
const struct ar5212AniParams *params;
HALASSERT(chan != AH_NULL);
if (!ANI_ENA(ah))
return;
/* first, raise noise immunity level, up to max */
aniState = ahp->ah_curani;
params = aniState->params;
if (aniState->noiseImmunityLevel+1 < params->maxNoiseImmunityLevel) {
ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL,
aniState->noiseImmunityLevel + 1);
return;
}
if (ANI_ENA_RSSI(ah)) {
int32_t rssi = BEACON_RSSI(ahp);
if (rssi > params->rssiThrLow) {
/*
* Beacon signal in mid and high range,
* raise firstep level.
*/
if (aniState->firstepLevel+1 < params->maxFirstepLevel)
ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
aniState->firstepLevel + 1);
} else {
/*
* Beacon rssi is low, zero firstep level to maximize
* CCK sensitivity in 11b/g mode.
*/
/* XXX can optimize */
if (IS_CHAN_B(chan) || IS_CHAN_G(chan)) {
if (aniState->firstepLevel > 0)
ar5416AniControl(ah,
HAL_ANI_FIRSTEP_LEVEL, 0);
}
}
}
}
static void
ar5416AniRestart(struct ath_hal *ah, struct ar5212AniState *aniState)
{
struct ath_hal_5212 *ahp = AH5212(ah);
const struct ar5212AniParams *params = aniState->params;
aniState->listenTime = 0;
/*
* NB: these are written on reset based on the
* ini so we must re-write them!
*/
HALDEBUG(ah, HAL_DEBUG_ANI,
"%s: Writing ofdmbase=%u cckbase=%u\n", __func__,
params->ofdmPhyErrBase, params->cckPhyErrBase);
OS_REG_WRITE(ah, AR_PHY_ERR_1, params->ofdmPhyErrBase);
OS_REG_WRITE(ah, AR_PHY_ERR_2, params->cckPhyErrBase);
OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_CCK_TIMING);
/* Clear the mib counters and save them in the stats */
ar5212UpdateMibCounters(ah, &ahp->ah_mibStats);
aniState->ofdmPhyErrCount = 0;
aniState->cckPhyErrCount = 0;
}
/*
* Restore/reset the ANI parameters and reset the statistics.
* This routine must be called for every channel change.
*
* NOTE: This is where ah_curani is set; other ani code assumes
* it is setup to reflect the current channel.
*/
void
ar5416AniReset(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan,
HAL_OPMODE opmode, int restore)
{
struct ath_hal_5212 *ahp = AH5212(ah);
struct ar5212AniState *aniState;
uint32_t rxfilter;
int index;
index = ar5416GetAniChannelIndex(ah, chan);
aniState = &ahp->ah_ani[index];
ahp->ah_curani = aniState;
#if 0
ath_hal_printf(ah,"%s: chan %u/0x%x restore %d setup %d opmode %u\n",
__func__, chan->channel, chan->channelFlags, restore,
aniState->isSetup, opmode);
#else
HALDEBUG(ah, HAL_DEBUG_ANI,
"%s: chan %u/0x%x restore %d setup %d opmode %u\n",
__func__, chan->channel, chan->channelFlags, restore,
aniState->isSetup, opmode);
#endif
OS_MARK(ah, AH_MARK_ANI_RESET, opmode);
/*
* Turn off PHY error frame delivery while we futz with settings.
*/
rxfilter = ar5212GetRxFilter(ah);
ar5212SetRxFilter(ah, rxfilter &~ HAL_RX_FILTER_PHYERR);
/*
* Automatic processing is done only in station mode right now.
*/
if (opmode == HAL_M_STA)
ahp->ah_procPhyErr |= HAL_RSSI_ANI_ENA;
else
ahp->ah_procPhyErr &= ~HAL_RSSI_ANI_ENA;
/*
* Set all ani parameters. We either set them to initial
* values or restore the previous ones for the channel.
* XXX if ANI follows hardware, we don't care what mode we're
* XXX in, we should keep the ani parameters
*/
if (restore && aniState->isSetup) {
ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL,
aniState->noiseImmunityLevel);
ar5416AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL,
aniState->spurImmunityLevel);
ar5416AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
!aniState->ofdmWeakSigDetectOff);
ar5416AniControl(ah, HAL_ANI_CCK_WEAK_SIGNAL_THR,
aniState->cckWeakSigThreshold);
ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
aniState->firstepLevel);
} else {
ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, 0);
ar5416AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, 0);
ar5416AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
AH_TRUE);
ar5416AniControl(ah, HAL_ANI_CCK_WEAK_SIGNAL_THR, AH_FALSE);
ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, 0);
aniState->isSetup = AH_TRUE;
}
ar5416AniRestart(ah, aniState);
/* restore RX filter mask */
ar5212SetRxFilter(ah, rxfilter);
}
/*
* Process a MIB interrupt. We may potentially be invoked because
* any of the MIB counters overflow/trigger so don't assume we're
* here because a PHY error counter triggered.
*/
void
ar5416ProcessMibIntr(struct ath_hal *ah, const HAL_NODE_STATS *stats)
{
struct ath_hal_5212 *ahp = AH5212(ah);
uint32_t phyCnt1, phyCnt2;
HALDEBUG(ah, HAL_DEBUG_ANI, "%s: mibc 0x%x phyCnt1 0x%x phyCnt2 0x%x "
"filtofdm 0x%x filtcck 0x%x\n",
__func__, OS_REG_READ(ah, AR_MIBC),
OS_REG_READ(ah, AR_PHYCNT1), OS_REG_READ(ah, AR_PHYCNT2),
OS_REG_READ(ah, AR_FILTOFDM), OS_REG_READ(ah, AR_FILTCCK));
/*
* First order of business is to clear whatever caused
* the interrupt so we don't keep getting interrupted.
* We have the usual mib counters that are reset-on-read
* and the additional counters that appeared starting in
* Hainan. We collect the mib counters and explicitly
* zero additional counters we are not using. Anything
* else is reset only if it caused the interrupt.
*/
/* NB: these are not reset-on-read */
phyCnt1 = OS_REG_READ(ah, AR_PHY_ERR_1);
phyCnt2 = OS_REG_READ(ah, AR_PHY_ERR_2);
/* not used, always reset them in case they are the cause */
OS_REG_WRITE(ah, AR_FILTOFDM, 0);
OS_REG_WRITE(ah, AR_FILTCCK, 0);
if ((OS_REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING) == 0)
OS_REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR);
/* Clear the mib counters and save them in the stats */
ar5212UpdateMibCounters(ah, &ahp->ah_mibStats);
ahp->ah_stats.ast_nodestats = *stats;
/*
* Check for an ani stat hitting the trigger threshold.
* When this happens we get a MIB interrupt and the top
* 2 bits of the counter register will be 0b11, hence
* the mask check of phyCnt?.
*/
if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) {
struct ar5212AniState *aniState = ahp->ah_curani;
const struct ar5212AniParams *params = aniState->params;
uint32_t ofdmPhyErrCnt, cckPhyErrCnt;
ofdmPhyErrCnt = phyCnt1 - params->ofdmPhyErrBase;
ahp->ah_stats.ast_ani_ofdmerrs +=
ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
cckPhyErrCnt = phyCnt2 - params->cckPhyErrBase;
ahp->ah_stats.ast_ani_cckerrs +=
cckPhyErrCnt - aniState->cckPhyErrCount;
aniState->cckPhyErrCount = cckPhyErrCnt;
/*
* NB: figure out which counter triggered. If both
* trigger we'll only deal with one as the processing
* clobbers the error counter so the trigger threshold
* check will never be true.
*/
if (aniState->ofdmPhyErrCount > params->ofdmTrigHigh)
ar5416AniOfdmErrTrigger(ah);
if (aniState->cckPhyErrCount > params->cckTrigHigh)
ar5416AniCckErrTrigger(ah);
/* NB: always restart to insure the h/w counters are reset */
ar5416AniRestart(ah, aniState);
}
}
static void
ar5416AniLowerImmunity(struct ath_hal *ah)
{
struct ath_hal_5212 *ahp = AH5212(ah);
struct ar5212AniState *aniState;
const struct ar5212AniParams *params;
HALASSERT(ANI_ENA(ah));
aniState = ahp->ah_curani;
params = aniState->params;
if (ANI_ENA_RSSI(ah)) {
int32_t rssi = BEACON_RSSI(ahp);
if (rssi > params->rssiThrHigh) {
/*
* Beacon signal is high, leave ofdm weak signal
* detection off or it may oscillate. Let it fall
* through.
*/
} else if (rssi > params->rssiThrLow) {
/*
* Beacon rssi in mid range, turn on ofdm weak signal
* detection or lower firstep level.
*/
if (aniState->ofdmWeakSigDetectOff) {
ar5416AniControl(ah,
HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
AH_TRUE);
return;
}
if (aniState->firstepLevel > 0) {
ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
aniState->firstepLevel - 1);
return;
}
} else {
/*
* Beacon rssi is low, reduce firstep level.
*/
if (aniState->firstepLevel > 0) {
ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
aniState->firstepLevel - 1);
return;
}
}
}
/* then lower spur immunity level, down to zero */
if (aniState->spurImmunityLevel > 0) {
ar5416AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL,
aniState->spurImmunityLevel - 1);
return;
}
/*
* if all else fails, lower noise immunity level down to a min value
* zero for now
*/
if (aniState->noiseImmunityLevel > 0) {
ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL,
aniState->noiseImmunityLevel - 1);
return;
}
}
#define CLOCK_RATE 44000 /* XXX use mac_usec or similar */
/* convert HW counter values to ms using 11g clock rate, goo9d enough
for 11a and Turbo */
/*
* Return an approximation of the time spent ``listening'' by
* deducting the cycles spent tx'ing and rx'ing from the total
* cycle count since our last call. A return value <0 indicates
* an invalid/inconsistent time.
*/
static int32_t
ar5416AniGetListenTime(struct ath_hal *ah)
{
struct ath_hal_5212 *ahp = AH5212(ah);
struct ar5212AniState *aniState;
uint32_t txFrameCount, rxFrameCount, cycleCount;
int32_t listenTime;
txFrameCount = OS_REG_READ(ah, AR_TFCNT);
rxFrameCount = OS_REG_READ(ah, AR_RFCNT);
cycleCount = OS_REG_READ(ah, AR_CCCNT);
aniState = ahp->ah_curani;
if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) {
/*
* Cycle counter wrap (or initial call); it's not possible
* to accurately calculate a value because the registers
* right shift rather than wrap--so punt and return 0.
*/
listenTime = 0;
ahp->ah_stats.ast_ani_lzero++;
} else {
int32_t ccdelta = cycleCount - aniState->cycleCount;
int32_t rfdelta = rxFrameCount - aniState->rxFrameCount;
int32_t tfdelta = txFrameCount - aniState->txFrameCount;
listenTime = (ccdelta - rfdelta - tfdelta) / CLOCK_RATE;
}
aniState->cycleCount = cycleCount;
aniState->txFrameCount = txFrameCount;
aniState->rxFrameCount = rxFrameCount;
return listenTime;
}
/*
* Update ani stats in preparation for listen time processing.
*/
static void
updateMIBStats(struct ath_hal *ah, struct ar5212AniState *aniState)
{
struct ath_hal_5212 *ahp = AH5212(ah);
const struct ar5212AniParams *params = aniState->params;
uint32_t phyCnt1, phyCnt2;
int32_t ofdmPhyErrCnt, cckPhyErrCnt;
/* Clear the mib counters and save them in the stats */
ar5212UpdateMibCounters(ah, &ahp->ah_mibStats);
/* NB: these are not reset-on-read */
phyCnt1 = OS_REG_READ(ah, AR_PHY_ERR_1);
phyCnt2 = OS_REG_READ(ah, AR_PHY_ERR_2);
/* NB: these are spec'd to never roll-over */
ofdmPhyErrCnt = phyCnt1 - params->ofdmPhyErrBase;
if (ofdmPhyErrCnt < 0) {
HALDEBUG(ah, HAL_DEBUG_ANI, "OFDM phyErrCnt %d phyCnt1 0x%x\n",
ofdmPhyErrCnt, phyCnt1);
ofdmPhyErrCnt = AR_PHY_COUNTMAX;
}
ahp->ah_stats.ast_ani_ofdmerrs +=
ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
cckPhyErrCnt = phyCnt2 - params->cckPhyErrBase;
if (cckPhyErrCnt < 0) {
HALDEBUG(ah, HAL_DEBUG_ANI, "CCK phyErrCnt %d phyCnt2 0x%x\n",
cckPhyErrCnt, phyCnt2);
cckPhyErrCnt = AR_PHY_COUNTMAX;
}
ahp->ah_stats.ast_ani_cckerrs +=
cckPhyErrCnt - aniState->cckPhyErrCount;
aniState->cckPhyErrCount = cckPhyErrCnt;
}
/*
* Do periodic processing. This routine is called from the
* driver's rx interrupt handler after processing frames.
*/
void
ar5416AniPoll(struct ath_hal *ah, const HAL_NODE_STATS *stats,
HAL_CHANNEL *chan)
{
struct ath_hal_5212 *ahp = AH5212(ah);
struct ar5212AniState *aniState = ahp->ah_curani;
const struct ar5212AniParams *params;
int32_t listenTime;
ahp->ah_stats.ast_nodestats.ns_avgbrssi = stats->ns_avgbrssi;
/* XXX can aniState be null? */
if (aniState == AH_NULL)
return;
if (!ANI_ENA(ah))
return;
listenTime = ar5416AniGetListenTime(ah);
if (listenTime < 0) {
ahp->ah_stats.ast_ani_lneg++;
/* restart ANI period if listenTime is invalid */
ar5416AniRestart(ah, aniState);
}
/* XXX beware of overflow? */
aniState->listenTime += listenTime;
OS_MARK(ah, AH_MARK_ANI_POLL, aniState->listenTime);
params = aniState->params;
if (aniState->listenTime > 5*params->period) {
/*
* Check to see if need to lower immunity if
* 5 aniPeriods have passed
*/
updateMIBStats(ah, aniState);
if (aniState->ofdmPhyErrCount <= aniState->listenTime *
params->ofdmTrigLow/1000 &&
aniState->cckPhyErrCount <= aniState->listenTime *
params->cckTrigLow/1000)
ar5416AniLowerImmunity(ah);
ar5416AniRestart(ah, aniState);
} else if (aniState->listenTime > params->period) {
updateMIBStats(ah, aniState);
/* check to see if need to raise immunity */
if (aniState->ofdmPhyErrCount > aniState->listenTime *
params->ofdmTrigHigh / 1000) {
ar5416AniOfdmErrTrigger(ah);
ar5416AniRestart(ah, aniState);
} else if (aniState->cckPhyErrCount > aniState->listenTime *
params->cckTrigHigh / 1000) {
ar5416AniCckErrTrigger(ah);
ar5416AniRestart(ah, aniState);
}
}
}
#endif /* AH_SUPPORT_AR5416 */

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ar5416_attach.c,v 1.19 2008/11/10 04:08:04 sam Exp $
* $Id: ar5416_attach.c,v 1.27 2008/11/27 22:30:07 sam Exp $
*/
#include "opt_ah.h"
@ -83,6 +83,8 @@ ar5416InitState(struct ath_hal_5416 *ahp5416, uint16_t devid, HAL_SOFTC sc,
ah->ah_phyDisable = ar5416PhyDisable;
ah->ah_disable = ar5416Disable;
ah->ah_perCalibration = ar5416PerCalibration;
ah->ah_perCalibrationN = ar5416PerCalibrationN,
ah->ah_resetCalValid = ar5416ResetCalValid,
ah->ah_setTxPowerLimit = ar5416SetTxPowerLimit;
/* Transmit functions */
@ -97,6 +99,8 @@ ar5416InitState(struct ath_hal_5416 *ahp5416, uint16_t devid, HAL_SOFTC sc,
ah->ah_stopPcuReceive = ar5416StopPcuReceive;
ah->ah_setupRxDesc = ar5416SetupRxDesc;
ah->ah_procRxDesc = ar5416ProcRxDesc;
ah->ah_rxMonitor = ar5416AniPoll,
ah->ah_procMibEvent = ar5416ProcessMibIntr,
/* Misc Functions */
ah->ah_getDiagState = ar5416GetDiagState;
@ -157,24 +161,10 @@ ar5416InitState(struct ath_hal_5416 *ahp5416, uint16_t devid, HAL_SOFTC sc,
ahp->ah_priv.ah_getChipPowerLimits = ar5416GetChipPowerLimits;
/*
* XXX - Do we need a board specific chain mask?
* Start by setting all Owl devices to 2x2
*/
AH5416(ah)->ah_rx_chainmask = AR5416_DEFAULT_RXCHAINMASK;
AH5416(ah)->ah_tx_chainmask = AR5416_DEFAULT_TXCHAINMASK;
AH5416(ah)->ah_clksel = 0; /* XXX */
/* NB: ah_keytype is initialized to zero which is ok */
#if 0
ah->ah_descinfo.rxctl_numwords = RXCTL_NUMWORDS(ah);
ah->ah_descinfo.rxctl_offset = RXCTL_OFFSET(ah);
ah->ah_descinfo.rxstatus_numwords = RXSTATUS_NUMWORDS(ah);
ah->ah_descinfo.rxstatus_offset = RXSTATUS_OFFSET(ah);
ah->ah_descinfo.txctl_numwords = TXCTL_NUMWORDS(ah);
ah->ah_descinfo.txctl_offset = TXCTL_OFFSET(ah);
ah->ah_descinfo.txstatus_numwords = TXSTATUS_NUMWORDS(ah);
ah->ah_descinfo.txstatus_offset = TXSTATUS_OFFSET(ah);
#endif
}
/*
@ -330,7 +320,7 @@ ar5416Attach(uint16_t devid, HAL_SOFTC sc,
* ah_miscMode is populated by ar5416FillCapabilityInfo()
* starting from griffin. Set here to make sure that
* AR_MISC_MODE_MIC_NEW_LOC_ENABLE is set before a GTK is
* placed into hardware
* placed into hardware.
*/
if (ahp->ah_miscMode != 0)
OS_REG_WRITE(ah, AR_MISC_MODE, ahp->ah_miscMode);
@ -344,9 +334,8 @@ ar5416Attach(uint16_t devid, HAL_SOFTC sc,
goto bad;
}
ar5212InitializeGainValues(ah); /* gain ladder */
ar5416AniSetup(ah); /* Anti Noise Immunity */
ar5416InitNfHistBuff(AH5416(ah)->ah_nfCalHist);
ar5416InitNfHistBuff(AH5416(ah)->ah_cal.nfCalHist);
HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: return\n", __func__);
@ -367,7 +356,7 @@ ar5416Detach(struct ath_hal *ah)
HALASSERT(ah != AH_NULL);
HALASSERT(ah->ah_magic == AR5416_MAGIC);
ar5212AniDetach(ah);
ar5416AniDetach(ah);
ar5212RfDetach(ah);
ah->ah_disable(ah);
ar5416SetPowerMode(ah, HAL_PM_FULL_SLEEP, AH_TRUE);

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ar5416_beacon.c,v 1.7 2008/11/10 04:08:04 sam Exp $
* $Id: ar5416_beacon.c,v 1.8 2008/11/11 01:03:12 sam Exp $
*/
#include "opt_ah.h"
@ -32,7 +32,7 @@
/*
* Initialize all of the hardware registers used to
* send beacons. Note that for station operation the
* driver calls ar5212SetStaBeaconTimers instead.
* driver calls ar5416SetStaBeaconTimers instead.
*/
void
ar5416SetBeaconTimers(struct ath_hal *ah, const HAL_BEACON_TIMERS *bt)

669
ar5416/ar5416_cal.c Normal file
View File

@ -0,0 +1,669 @@
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
*
* Permission to use, copy, modify, and/or 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.
*
* $Id: ar5416_cal.c,v 1.7 2008/11/11 17:43:23 sam Exp $
*/
#include "opt_ah.h"
#ifdef AH_SUPPORT_AR5416
#include "ah.h"
#include "ah_internal.h"
#include "ah_devid.h"
#include "ah_eeprom_v14.h"
#include "ar5416/ar5416.h"
#include "ar5416/ar5416reg.h"
#include "ar5416/ar5416phy.h"
#ifdef AH_SUPPORT_AR9280
#include "ar5416/ar9280.h"
#endif
/* Owl specific stuff */
#define NUM_NOISEFLOOR_READINGS 6 /* 3 chains * (ctl + ext) */
static void ar5416StartNFCal(struct ath_hal *ah);
static void ar5416LoadNF(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *);
static int16_t ar5416GetNf(struct ath_hal *, HAL_CHANNEL_INTERNAL *);
/*
* Determine if calibration is supported by device and channel flags
*/
static OS_INLINE HAL_BOOL
ar5416IsCalSupp(struct ath_hal *ah, HAL_CHANNEL *chan, HAL_CAL_TYPE calType)
{
struct ar5416PerCal *cal = &AH5416(ah)->ah_cal;
switch (calType & cal->suppCals) {
case IQ_MISMATCH_CAL:
/* Run IQ Mismatch for non-CCK only */
return !IS_CHAN_B(chan);
case ADC_GAIN_CAL:
case ADC_DC_CAL:
/* Run ADC Gain Cal for non-CCK & non 2GHz-HT20 only */
return !IS_CHAN_B(chan) &&
!(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan));
}
return AH_FALSE;
}
/*
* Setup HW to collect samples used for current cal
*/
static void
ar5416SetupMeasurement(struct ath_hal *ah, HAL_CAL_LIST *currCal)
{
/* Start calibration w/ 2^(INIT_IQCAL_LOG_COUNT_MAX+1) samples */
OS_REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4,
AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX,
currCal->calData->calCountMax);
/* Select calibration to run */
switch (currCal->calData->calType) {
case IQ_MISMATCH_CAL:
OS_REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);
HALDEBUG(ah, HAL_DEBUG_PERCAL,
"%s: start IQ Mismatch calibration\n", __func__);
break;
case ADC_GAIN_CAL:
OS_REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN);
HALDEBUG(ah, HAL_DEBUG_PERCAL,
"%s: start ADC Gain calibration\n", __func__);
break;
case ADC_DC_CAL:
OS_REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER);
HALDEBUG(ah, HAL_DEBUG_PERCAL,
"%s: start ADC DC calibration\n", __func__);
break;
case ADC_DC_INIT_CAL:
OS_REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT);
HALDEBUG(ah, HAL_DEBUG_PERCAL,
"%s: start Init ADC DC calibration\n", __func__);
break;
}
/* Kick-off cal */
OS_REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4, AR_PHY_TIMING_CTRL4_DO_CAL);
}
/*
* Initialize shared data structures and prepare a cal to be run.
*/
static void
ar5416ResetMeasurement(struct ath_hal *ah, HAL_CAL_LIST *currCal)
{
struct ar5416PerCal *cal = &AH5416(ah)->ah_cal;
/* Reset data structures shared between different calibrations */
OS_MEMZERO(cal->caldata, sizeof(cal->caldata));
cal->calSamples = 0;
/* Setup HW for new calibration */
ar5416SetupMeasurement(ah, currCal);
/* Change SW state to RUNNING for this calibration */
currCal->calState = CAL_RUNNING;
}
#if 0
/*
* Run non-periodic calibrations.
*/
static HAL_BOOL
ar5416RunInitCals(struct ath_hal *ah, int init_cal_count)
{
struct ath_hal_5416 *ahp = AH5416(ah);
struct ar5416PerCal *cal = &AH5416(ah)->ah_cal;
HAL_CHANNEL_INTERNAL ichan; /* XXX bogus */
HAL_CAL_LIST *curCal = ahp->ah_cal_curr;
HAL_BOOL isCalDone;
int i;
if (curCal == AH_NULL)
return AH_FALSE;
ichan.calValid = 0;
for (i = 0; i < init_cal_count; i++) {
/* Reset this Cal */
ar5416ResetMeasurement(ah, curCal);
/* Poll for offset calibration complete */
if (!ath_hal_wait(ah, AR_PHY_TIMING_CTRL4, AR_PHY_TIMING_CTRL4_DO_CAL, 0)) {
HALDEBUG(ah, HAL_DEBUG_ANY,
"%s: Cal %d failed to finish in 100ms.\n",
__func__, curCal->calData->calType);
/* Re-initialize list pointers for periodic cals */
cal->cal_list = cal->cal_last = cal->cal_curr = AH_NULL;
return AH_FALSE;
}
/* Run this cal */
ar5416DoCalibration(ah, &ichan, ahp->ah_rxchainmask,
curCal, &isCalDone);
if (!isCalDone)
HALDEBUG(ah, HAL_DEBUG_ANY,
"%s: init cal %d did not complete.\n",
__func__, curCal->calData->calType);
if (curCal->calNext != AH_NULL)
curCal = curCal->calNext;
}
/* Re-initialize list pointers for periodic cals */
cal->cal_list = cal->cal_last = cal->cal_curr = AH_NULL;
return AH_TRUE;
}
#endif
/*
* Initialize Calibration infrastructure.
*/
HAL_BOOL
ar5416InitCal(struct ath_hal *ah, HAL_CHANNEL *chan)
{
struct ar5416PerCal *cal = &AH5416(ah)->ah_cal;
HAL_CHANNEL_INTERNAL *ichan;
ichan = ath_hal_checkchannel(ah, chan);
HALASSERT(ichan != AH_NULL);
if (AR_SREV_MERLIN_10_OR_LATER(ah)) {
/* Enable Rx Filter Cal */
OS_REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);
OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
AR_PHY_AGC_CONTROL_FLTR_CAL);
/* Clear the carrier leak cal bit */
OS_REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
/* kick off the cal */
OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL);
/* Poll for offset calibration complete */
if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) {
HALDEBUG(ah, HAL_DEBUG_ANY,
"%s: offset calibration failed to complete in 1ms; "
"noisy environment?\n", __func__);
return AH_FALSE;
}
/* Set the cl cal bit and rerun the cal a 2nd time */
/* Enable Rx Filter Cal */
OS_REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);
OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
AR_PHY_AGC_CONTROL_FLTR_CAL);
OS_REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
}
/* Calibrate the AGC */
OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL);
/* Poll for offset calibration complete */
if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) {
HALDEBUG(ah, HAL_DEBUG_ANY,
"%s: offset calibration did not complete in 1ms; "
"noisy environment?\n", __func__);
return AH_FALSE;
}
/*
* Do NF calibration after DC offset and other CALs.
* Per system engineers, noise floor value can sometimes be 20 dB
* higher than normal value if DC offset and noise floor cal are
* triggered at the same time.
*/
OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
/* Initialize list pointers */
cal->cal_list = cal->cal_last = cal->cal_curr = AH_NULL;
/*
* Enable IQ, ADC Gain, ADC DC Offset Cals
*/
if (AR_SREV_SOWL_10_OR_LATER(ah)) {
/* Setup all non-periodic, init time only calibrations */
/* XXX: Init DC Offset not working yet */
#if 0
if (ar5416IsCalSupp(ah, chan, ADC_DC_INIT_CAL)) {
INIT_CAL(&cal->adcDcCalInitData);
INSERT_CAL(cal, &cal->adcDcCalInitData);
}
/* Initialize current pointer to first element in list */
cal->cal_curr = cal->cal_list;
if (cal->ah_cal_curr != AH_NULL && !ar5416RunInitCals(ah, 0))
return AH_FALSE;
#endif
}
/* If Cals are supported, add them to list via INIT/INSERT_CAL */
if (ar5416IsCalSupp(ah, chan, ADC_GAIN_CAL)) {
INIT_CAL(&cal->adcGainCalData);
INSERT_CAL(cal, &cal->adcGainCalData);
HALDEBUG(ah, HAL_DEBUG_PERCAL,
"%s: enable ADC Gain Calibration.\n", __func__);
}
if (ar5416IsCalSupp(ah, chan, ADC_DC_CAL)) {
INIT_CAL(&cal->adcDcCalData);
INSERT_CAL(cal, &cal->adcDcCalData);
HALDEBUG(ah, HAL_DEBUG_PERCAL,
"%s: enable ADC DC Calibration.\n", __func__);
}
if (ar5416IsCalSupp(ah, chan, IQ_MISMATCH_CAL)) {
INIT_CAL(&cal->iqCalData);
INSERT_CAL(cal, &cal->iqCalData);
HALDEBUG(ah, HAL_DEBUG_PERCAL,
"%s: enable IQ Calibration.\n", __func__);
}
/* Initialize current pointer to first element in list */
cal->cal_curr = cal->cal_list;
/* Kick off measurements for the first cal */
if (cal->cal_curr != AH_NULL)
ar5416ResetMeasurement(ah, cal->cal_curr);
/* Mark all calibrations on this channel as being invalid */
ichan->calValid = 0;
return AH_TRUE;
}
/*
* Entry point for upper layers to restart current cal.
* Reset the calibration valid bit in channel.
*/
HAL_BOOL
ar5416ResetCalValid(struct ath_hal *ah, HAL_CHANNEL *chan)
{
struct ar5416PerCal *cal = &AH5416(ah)->ah_cal;
HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);
HAL_CAL_LIST *currCal = cal->cal_curr;
if (!AR_SREV_SOWL_10_OR_LATER(ah))
return AH_FALSE;
if (currCal == AH_NULL)
return AH_FALSE;
if (ichan == AH_NULL) {
HALDEBUG(ah, HAL_DEBUG_ANY,
"%s: invalid channel %u/0x%x; no mapping\n",
__func__, chan->channel, chan->channelFlags);
return AH_FALSE;
}
/*
* Expected that this calibration has run before, post-reset.
* Current state should be done
*/
if (currCal->calState != CAL_DONE) {
HALDEBUG(ah, HAL_DEBUG_ANY,
"%s: Calibration state incorrect, %d\n",
__func__, currCal->calState);
return AH_FALSE;
}
/* Verify Cal is supported on this channel */
if (!ar5416IsCalSupp(ah, chan, currCal->calData->calType))
return AH_FALSE;
HALDEBUG(ah, HAL_DEBUG_PERCAL,
"%s: Resetting Cal %d state for channel %u/0x%x\n",
__func__, currCal->calData->calType, chan->channel,
chan->channelFlags);
/* Disable cal validity in channel */
ichan->calValid &= ~currCal->calData->calType;
currCal->calState = CAL_WAITING;
return AH_TRUE;
}
/*
* Recalibrate the lower PHY chips to account for temperature/environment
* changes.
*/
static void
ar5416DoCalibration(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan,
uint8_t rxchainmask, HAL_CAL_LIST *currCal, HAL_BOOL *isCalDone)
{
struct ar5416PerCal *cal = &AH5416(ah)->ah_cal;
/* Cal is assumed not done until explicitly set below */
*isCalDone = AH_FALSE;
HALDEBUG(ah, HAL_DEBUG_PERCAL,
"%s: %s Calibration, state %d, calValid 0x%x\n",
__func__, currCal->calData->calName, currCal->calState,
ichan->calValid);
/* Calibration in progress. */
if (currCal->calState == CAL_RUNNING) {
/* Check to see if it has finished. */
if (!(OS_REG_READ(ah, AR_PHY_TIMING_CTRL4) & AR_PHY_TIMING_CTRL4_DO_CAL)) {
HALDEBUG(ah, HAL_DEBUG_PERCAL,
"%s: sample %d of %d finished\n",
__func__, cal->calSamples,
currCal->calData->calNumSamples);
/*
* Collect measurements for active chains.
*/
currCal->calData->calCollect(ah);
if (++cal->calSamples >= currCal->calData->calNumSamples) {
int i, numChains = 0;
for (i = 0; i < AR5416_MAX_CHAINS; i++) {
if (rxchainmask & (1 << i))
numChains++;
}
/*
* Process accumulated data
*/
currCal->calData->calPostProc(ah, numChains);
/* Calibration has finished. */
ichan->calValid |= currCal->calData->calType;
currCal->calState = CAL_DONE;
*isCalDone = AH_TRUE;
} else {
/*
* Set-up to collect of another sub-sample.
*/
ar5416SetupMeasurement(ah, currCal);
}
}
} else if (!(ichan->calValid & currCal->calData->calType)) {
/* If current cal is marked invalid in channel, kick it off */
ar5416ResetMeasurement(ah, currCal);
}
}
/*
* Internal interface to schedule periodic calibration work.
*/
HAL_BOOL
ar5416PerCalibrationN(struct ath_hal *ah, HAL_CHANNEL *chan,
u_int rxchainmask, HAL_BOOL longcal, HAL_BOOL *isCalDone)
{
struct ar5416PerCal *cal = &AH5416(ah)->ah_cal;
HAL_CAL_LIST *currCal = cal->cal_curr;
HAL_CHANNEL_INTERNAL *ichan;
OS_MARK(ah, AH_MARK_PERCAL, chan->channel);
*isCalDone = AH_TRUE;
/* Invalid channel check */
ichan = ath_hal_checkchannel(ah, chan);
if (ichan == AH_NULL) {
HALDEBUG(ah, HAL_DEBUG_ANY,
"%s: invalid channel %u/0x%x; no mapping\n",
__func__, chan->channel, chan->channelFlags);
return AH_FALSE;
}
/*
* For given calibration:
* 1. Call generic cal routine
* 2. When this cal is done (isCalDone) if we have more cals waiting
* (eg after reset), mask this to upper layers by not propagating
* isCalDone if it is set to TRUE.
* Instead, change isCalDone to FALSE and setup the waiting cal(s)
* to be run.
*/
if (currCal != AH_NULL &&
(currCal->calState == CAL_RUNNING ||
currCal->calState == CAL_WAITING)) {
ar5416DoCalibration(ah, ichan, rxchainmask, currCal, isCalDone);
if (*isCalDone == AH_TRUE) {
cal->cal_curr = currCal = currCal->calNext;
if (currCal->calState == CAL_WAITING) {
*isCalDone = AH_FALSE;
ar5416ResetMeasurement(ah, currCal);
}
}
}
/* Do NF cal only at longer intervals */
if (longcal) {
/*
* Get the value from the previous NF cal
* and update the history buffer.
*/
ar5416GetNf(ah, ichan);
/*
* Load the NF from history buffer of the current channel.
* NF is slow time-variant, so it is OK to use a
* historical value.
*/
ar5416LoadNF(ah, AH_PRIVATE(ah)->ah_curchan);
/* start NF calibration, without updating BB NF register*/
ar5416StartNFCal(ah);
if ((ichan->channelFlags & CHANNEL_CW_INT) != 0) {
/* report up and clear internal state */
chan->channelFlags |= CHANNEL_CW_INT;
ichan->channelFlags &= ~CHANNEL_CW_INT;
}
}
return AH_TRUE;
}
/*
* Recalibrate the lower PHY chips to account for temperature/environment
* changes.
*/
HAL_BOOL
ar5416PerCalibration(struct ath_hal *ah, HAL_CHANNEL *chan, HAL_BOOL *isIQdone)
{
struct ath_hal_5416 *ahp = AH5416(ah);
struct ar5416PerCal *cal = &AH5416(ah)->ah_cal;
HAL_CAL_LIST *curCal = cal->cal_curr;
if (curCal != AH_NULL && curCal->calData->calType == IQ_MISMATCH_CAL) {
return ar5416PerCalibrationN(ah, chan, ahp->ah_rx_chainmask,
AH_TRUE, isIQdone);
} else {
HAL_BOOL isCalDone;
*isIQdone = AH_FALSE;
return ar5416PerCalibrationN(ah, chan, ahp->ah_rx_chainmask,
AH_TRUE, &isCalDone);
}
}
static HAL_BOOL
ar5416GetEepromNoiseFloorThresh(struct ath_hal *ah,
const HAL_CHANNEL_INTERNAL *chan, int16_t *nft)
{
switch (chan->channelFlags & CHANNEL_ALL_NOTURBO) {
case CHANNEL_A:
case CHANNEL_A_HT20:
case CHANNEL_A_HT40PLUS:
case CHANNEL_A_HT40MINUS:
ath_hal_eepromGet(ah, AR_EEP_NFTHRESH_5, nft);
break;
case CHANNEL_B:
case CHANNEL_G:
case CHANNEL_G_HT20:
case CHANNEL_G_HT40PLUS:
case CHANNEL_G_HT40MINUS:
ath_hal_eepromGet(ah, AR_EEP_NFTHRESH_2, nft);
break;
default:
HALDEBUG(ah, HAL_DEBUG_ANY,
"%s: invalid channel flags 0x%x\n",
__func__, chan->channelFlags);
return AH_FALSE;
}
return AH_TRUE;
}
static void
ar5416StartNFCal(struct ath_hal *ah)
{
OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_ENABLE_NF);
OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
}
static void
ar5416LoadNF(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan)
{
static const uint32_t ar5416_cca_regs[] = {
AR_PHY_CCA,
AR_PHY_CH1_CCA,
AR_PHY_CH2_CCA,
AR_PHY_EXT_CCA,
AR_PHY_CH1_EXT_CCA,
AR_PHY_CH2_EXT_CCA
};
struct ar5212NfCalHist *h;
int i, j;
int32_t val;
uint8_t chainmask;
/*
* Force NF calibration for all chains.
*/
if (AR_SREV_KITE(ah)) {
/* Kite has only one chain */
chainmask = 0x9;
} else if (AR_SREV_MERLIN(ah)) {
/* Merlin has only two chains */
chainmask = 0x1B;
} else {
chainmask = 0x3F;
}
/*
* Write filtered NF values into maxCCApwr register parameter
* so we can load below.
*/
h = AH5416(ah)->ah_cal.nfCalHist;
for (i = 0; i < AR5416_NUM_NF_READINGS; i ++)
if (chainmask & (1 << i)) {
val = OS_REG_READ(ah, ar5416_cca_regs[i]);
val &= 0xFFFFFE00;
val |= (((uint32_t)(h[i].privNF) << 1) & 0x1ff);
OS_REG_WRITE(ah, ar5416_cca_regs[i], val);
}
/* Load software filtered NF value into baseband internal minCCApwr variable. */
OS_REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_ENABLE_NF);
OS_REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
/* Wait for load to complete, should be fast, a few 10s of us. */
for (j = 0; j < 1000; j++) {
if ((OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) == 0)
break;
OS_DELAY(10);
}
/*
* Restore maxCCAPower register parameter again so that we're not capped
* by the median we just loaded. This will be initial (and max) value
* of next noise floor calibration the baseband does.
*/
for (i = 0; i < AR5416_NUM_NF_READINGS; i ++)
if (chainmask & (1 << i)) {
val = OS_REG_READ(ah, ar5416_cca_regs[i]);
val &= 0xFFFFFE00;
val |= (((uint32_t)(-50) << 1) & 0x1ff);
OS_REG_WRITE(ah, ar5416_cca_regs[i], val);
}
}
void
ar5416InitNfHistBuff(struct ar5212NfCalHist *h)
{
int i, j;
for (i = 0; i < AR5416_NUM_NF_READINGS; i ++) {
h[i].currIndex = 0;
h[i].privNF = AR5416_CCA_MAX_GOOD_VALUE;
h[i].invalidNFcount = AR512_NF_CAL_HIST_MAX;
for (j = 0; j < AR512_NF_CAL_HIST_MAX; j ++)
h[i].nfCalBuffer[j] = AR5416_CCA_MAX_GOOD_VALUE;
}
}
/*
* Update the noise floor buffer as a ring buffer
*/
static void
ar5416UpdateNFHistBuff(struct ar5212NfCalHist *h, int16_t *nfarray)
{
int i;
for (i = 0; i < AR5416_NUM_NF_READINGS; i ++) {
h[i].nfCalBuffer[h[i].currIndex] = nfarray[i];
if (++h[i].currIndex >= AR512_NF_CAL_HIST_MAX)
h[i].currIndex = 0;
if (h[i].invalidNFcount > 0) {
if (nfarray[i] < AR5416_CCA_MIN_BAD_VALUE ||
nfarray[i] > AR5416_CCA_MAX_HIGH_VALUE) {
h[i].invalidNFcount = AR512_NF_CAL_HIST_MAX;
} else {
h[i].invalidNFcount--;
h[i].privNF = nfarray[i];
}
} else {
h[i].privNF = ar5212GetNfHistMid(h[i].nfCalBuffer);
}
}
}
/*
* Read the NF and check it against the noise floor threshhold
*/
static int16_t
ar5416GetNf(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan)
{
int16_t nf, nfThresh;
if (OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) {
HALDEBUG(ah, HAL_DEBUG_ANY,
"%s: NF didn't complete in calibration window\n", __func__);
nf = 0;
} else {
/* Finished NF cal, check against threshold */
int16_t nfarray[NUM_NOISEFLOOR_READINGS] = { 0 };
/* TODO - enhance for multiple chains and ext ch */
ath_hal_getNoiseFloor(ah, nfarray);
nf = nfarray[0];
if (ar5416GetEepromNoiseFloorThresh(ah, chan, &nfThresh)) {
if (nf > nfThresh) {
HALDEBUG(ah, HAL_DEBUG_ANY,
"%s: noise floor failed detected; "
"detected %d, threshold %d\n", __func__,
nf, nfThresh);
/*
* NB: Don't discriminate 2.4 vs 5Ghz, if this
* happens it indicates a problem regardless
* of the band.
*/
chan->channelFlags |= CHANNEL_CW_INT;
nf = 0;
}
} else {
nf = 0;
}
ar5416UpdateNFHistBuff(AH5416(ah)->ah_cal.nfCalHist, nfarray);
chan->rawNoiseFloor = nf;
}
return nf;
}
#endif /* AH_SUPPORT_AR5416 */

119
ar5416/ar5416_cal.h Normal file
View File

@ -0,0 +1,119 @@
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
*
* Permission to use, copy, modify, and/or 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.
*
* $Id: ar5416_cal.h,v 1.3 2008/11/11 17:43:23 sam Exp $
*/
#ifndef _ATH_AR5416_CAL_H_
#define _ATH_AR5416_CAL_H_
typedef enum {
ADC_DC_INIT_CAL = 0x1,
ADC_GAIN_CAL = 0x2,
ADC_DC_CAL = 0x4,
IQ_MISMATCH_CAL = 0x8
} HAL_CAL_TYPE;
/* Calibrate state */
typedef enum {
CAL_INACTIVE,
CAL_WAITING,
CAL_RUNNING,
CAL_DONE
} HAL_CAL_STATE;
typedef union {
uint32_t u;
int32_t s;
} HAL_CAL_SAMPLE;
#define MIN_CAL_SAMPLES 1
#define MAX_CAL_SAMPLES 64
#define INIT_LOG_COUNT 5
#define PER_MIN_LOG_COUNT 2
#define PER_MAX_LOG_COUNT 10
/* Per Calibration data structure */
typedef struct per_cal_data {
const char *calName; /* for diagnostics */
HAL_CAL_TYPE calType; /* Type of calibration */
uint32_t calNumSamples; /* # SW samples to collect */
uint32_t calCountMax; /* # HW samples to collect */
void (*calCollect)(struct ath_hal *); /* Accumulator function */
/* Post-processing function */
void (*calPostProc)(struct ath_hal *, uint8_t);
} HAL_PERCAL_DATA;
/* List structure for calibration data */
typedef struct cal_list {
struct cal_list *calNext;
HAL_CAL_STATE calState;
const HAL_PERCAL_DATA *calData;
} HAL_CAL_LIST;
struct ar5416PerCal {
/*
* Periodic calibration state.
*/
HAL_CAL_TYPE suppCals;
HAL_CAL_LIST iqCalData;
HAL_CAL_LIST adcGainCalData;
HAL_CAL_LIST adcDcCalInitData;
HAL_CAL_LIST adcDcCalData;
HAL_CAL_LIST *cal_list;
HAL_CAL_LIST *cal_last;
HAL_CAL_LIST *cal_curr;
#define AR5416_MAX_CHAINS 3 /* XXX dup's eeprom def */
HAL_CAL_SAMPLE caldata[4][AR5416_MAX_CHAINS];
int calSamples;
/*
* Noise floor cal histogram support.
* XXX be nice to re-use space in ar5212
*/
#define AR5416_NUM_NF_READINGS 6 /* (3 chains * (ctl + ext) */
struct ar5212NfCalHist nfCalHist[AR5416_NUM_NF_READINGS];
};
#define INIT_CAL(_perCal) do { \
(_perCal)->calState = CAL_WAITING; \
(_perCal)->calNext = AH_NULL; \
} while (0)
#define INSERT_CAL(_cal, _perCal) do { \
if ((_cal)->cal_last == AH_NULL) { \
(_cal)->cal_list = (_cal)->cal_last = (_perCal); \
((_cal)->cal_last)->calNext = (_perCal); \
} else { \
((_cal)->cal_last)->calNext = (_perCal); \
(_cal)->cal_last = (_perCal); \
(_perCal)->calNext = (_cal)->cal_list; \
} \
} while (0)
HAL_BOOL ar5416InitCal(struct ath_hal *ah, HAL_CHANNEL *chan);
HAL_BOOL ar5416PerCalibration(struct ath_hal *, HAL_CHANNEL *,
HAL_BOOL *isIQdone);
HAL_BOOL ar5416PerCalibrationN(struct ath_hal *ah, HAL_CHANNEL *chan,
u_int chainMask, HAL_BOOL longCal, HAL_BOOL *isCalDone);
HAL_BOOL ar5416ResetCalValid(struct ath_hal *ah, HAL_CHANNEL *chan);
void ar5416IQCalCollect(struct ath_hal *ah);
void ar5416IQCalibration(struct ath_hal *ah, uint8_t numChains);
void ar5416AdcGainCalCollect(struct ath_hal *ah);
void ar5416AdcGainCalibration(struct ath_hal *ah, uint8_t numChains);
void ar5416AdcDcCalCollect(struct ath_hal *ah);
void ar5416AdcDcCalibration(struct ath_hal *ah, uint8_t numChains);
void ar5416InitNfHistBuff(struct ar5212NfCalHist *h);
#endif /* _ATH_AR5416_CAL_H_ */

114
ar5416/ar5416_cal_adcdc.c Normal file
View File

@ -0,0 +1,114 @@
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
*
* Permission to use, copy, modify, and/or 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.
*
* $Id: ar5416_cal_adcdc.c,v 1.2 2008/11/11 17:43:23 sam Exp $
*/
#include "opt_ah.h"
#ifdef AH_SUPPORT_AR5416
#include "ah.h"
#include "ah_internal.h"
#include "ah_devid.h"
#include "ar5416/ar5416.h"
#include "ar5416/ar5416reg.h"
#include "ar5416/ar5416phy.h"
/* Adc DC Offset Cal aliases */
#define totalAdcDcOffsetIOddPhase(i) caldata[0][i].s
#define totalAdcDcOffsetIEvenPhase(i) caldata[1][i].s
#define totalAdcDcOffsetQOddPhase(i) caldata[2][i].s
#define totalAdcDcOffsetQEvenPhase(i) caldata[3][i].s
void
ar5416AdcDcCalCollect(struct ath_hal *ah)
{
struct ar5416PerCal *cal = &AH5416(ah)->ah_cal;
int i;
for (i = 0; i < AR5416_MAX_CHAINS; i++) {
cal->totalAdcDcOffsetIOddPhase(i) += (int32_t)
OS_REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
cal->totalAdcDcOffsetIEvenPhase(i) += (int32_t)
OS_REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
cal->totalAdcDcOffsetQOddPhase(i) += (int32_t)
OS_REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
cal->totalAdcDcOffsetQEvenPhase(i) += (int32_t)
OS_REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
HALDEBUG(ah, HAL_DEBUG_PERCAL,
"%d: Chn %d oddi=0x%08x; eveni=0x%08x; oddq=0x%08x; evenq=0x%08x;\n",
cal->calSamples, i,
cal->totalAdcDcOffsetIOddPhase(i),
cal->totalAdcDcOffsetIEvenPhase(i),
cal->totalAdcDcOffsetQOddPhase(i),
cal->totalAdcDcOffsetQEvenPhase(i));
}
}
void
ar5416AdcDcCalibration(struct ath_hal *ah, uint8_t numChains)
{
struct ar5416PerCal *cal = &AH5416(ah)->ah_cal;
const HAL_PERCAL_DATA *calData = cal->cal_curr->calData;
uint32_t numSamples;
int i;
numSamples = (1 << (calData->calCountMax + 5)) * calData->calNumSamples;
for (i = 0; i < numChains; i++) {
uint32_t iOddMeasOffset = cal->totalAdcDcOffsetIOddPhase(i);
uint32_t iEvenMeasOffset = cal->totalAdcDcOffsetIEvenPhase(i);
int32_t qOddMeasOffset = cal->totalAdcDcOffsetQOddPhase(i);
int32_t qEvenMeasOffset = cal->totalAdcDcOffsetQEvenPhase(i);
int32_t qDcMismatch, iDcMismatch;
uint32_t val;
HALDEBUG(ah, HAL_DEBUG_PERCAL,
"Starting ADC DC Offset Cal for Chain %d\n", i);
HALDEBUG(ah, HAL_DEBUG_PERCAL, " pwr_meas_odd_i = %d\n",
iOddMeasOffset);
HALDEBUG(ah, HAL_DEBUG_PERCAL, " pwr_meas_even_i = %d\n",
iEvenMeasOffset);
HALDEBUG(ah, HAL_DEBUG_PERCAL, " pwr_meas_odd_q = %d\n",
qOddMeasOffset);
HALDEBUG(ah, HAL_DEBUG_PERCAL, " pwr_meas_even_q = %d\n",
qEvenMeasOffset);
HALASSERT(numSamples);
iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) /
numSamples) & 0x1ff;
qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) /
numSamples) & 0x1ff;
HALDEBUG(ah, HAL_DEBUG_PERCAL,
" dc_offset_mismatch_i = 0x%08x\n", iDcMismatch);
HALDEBUG(ah, HAL_DEBUG_PERCAL,
" dc_offset_mismatch_q = 0x%08x\n", qDcMismatch);
val = OS_REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
val &= 0xc0000fff;
val |= (qDcMismatch << 12) | (iDcMismatch << 21);
OS_REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
HALDEBUG(ah, HAL_DEBUG_PERCAL,
"ADC DC Offset Cal done for Chain %d\n", i);
}
OS_REG_SET_BIT(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE);
}
#endif /* AH_SUPPORT_AR5416 */

119
ar5416/ar5416_cal_adcgain.c Normal file
View File

@ -0,0 +1,119 @@
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
*
* Permission to use, copy, modify, and/or 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.
*
* $Id: ar5416_cal_adcgain.c,v 1.2 2008/11/11 17:43:23 sam Exp $
*/
#include "opt_ah.h"
#ifdef AH_SUPPORT_AR5416
#include "ah.h"
#include "ah_internal.h"
#include "ah_devid.h"
#include "ar5416/ar5416.h"
#include "ar5416/ar5416reg.h"
#include "ar5416/ar5416phy.h"
/* Adc Gain Cal aliases */
#define totalAdcIOddPhase(i) caldata[0][i].u
#define totalAdcIEvenPhase(i) caldata[1][i].u
#define totalAdcQOddPhase(i) caldata[2][i].u
#define totalAdcQEvenPhase(i) caldata[3][i].u
/*
* Collect data from HW to later perform ADC Gain Calibration
*/
void
ar5416AdcGainCalCollect(struct ath_hal *ah)
{
struct ar5416PerCal *cal = &AH5416(ah)->ah_cal;
int i;
/*
* Accumulate ADC Gain cal measures for active chains
*/
for (i = 0; i < AR5416_MAX_CHAINS; i++) {
cal->totalAdcIOddPhase(i) +=
OS_REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
cal->totalAdcIEvenPhase(i) +=
OS_REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
cal->totalAdcQOddPhase(i) +=
OS_REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
cal->totalAdcQEvenPhase(i) +=
OS_REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
HALDEBUG(ah, HAL_DEBUG_PERCAL,
"%d: Chn %d oddi=0x%08x; eveni=0x%08x; oddq=0x%08x; evenq=0x%08x;\n",
cal->calSamples, i, cal->totalAdcIOddPhase(i),
cal->totalAdcIEvenPhase(i), cal->totalAdcQOddPhase(i),
cal->totalAdcQEvenPhase(i));
}
}
/*
* Use HW data to do ADC Gain Calibration
*/
void
ar5416AdcGainCalibration(struct ath_hal *ah, uint8_t numChains)
{
struct ar5416PerCal *cal = &AH5416(ah)->ah_cal;
uint32_t i;
for (i = 0; i < numChains; i++) {
uint32_t iOddMeasOffset = cal->totalAdcIOddPhase(i);
uint32_t iEvenMeasOffset = cal->totalAdcIEvenPhase(i);
uint32_t qOddMeasOffset = cal->totalAdcQOddPhase(i);
uint32_t qEvenMeasOffset = cal->totalAdcQEvenPhase(i);
HALDEBUG(ah, HAL_DEBUG_PERCAL,
"Start ADC Gain Cal for Chain %d\n", i);
HALDEBUG(ah, HAL_DEBUG_PERCAL,
" pwr_meas_odd_i = 0x%08x\n", iOddMeasOffset);
HALDEBUG(ah, HAL_DEBUG_PERCAL,
" pwr_meas_even_i = 0x%08x\n", iEvenMeasOffset);
HALDEBUG(ah, HAL_DEBUG_PERCAL,
" pwr_meas_odd_q = 0x%08x\n", qOddMeasOffset);
HALDEBUG(ah, HAL_DEBUG_PERCAL,
" pwr_meas_even_q = 0x%08x\n", qEvenMeasOffset);
if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) {
uint32_t iGainMismatch =
((iEvenMeasOffset*32)/iOddMeasOffset) & 0x3f;
uint32_t qGainMismatch =
((qOddMeasOffset*32)/qEvenMeasOffset) & 0x3f;
uint32_t val;
HALDEBUG(ah, HAL_DEBUG_PERCAL,
" gain_mismatch_i = 0x%08x\n",
iGainMismatch);
HALDEBUG(ah, HAL_DEBUG_PERCAL,
" gain_mismatch_q = 0x%08x\n",
qGainMismatch);
val = OS_REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
val &= 0xfffff000;
val |= (qGainMismatch) | (iGainMismatch << 6);
OS_REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
HALDEBUG(ah, HAL_DEBUG_PERCAL,
"ADC Gain Cal done for Chain %d\n", i);
}
}
OS_REG_SET_BIT(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
AR_PHY_NEW_ADC_GAIN_CORR_ENABLE);
}
#endif /* AH_SUPPORT_AR5416 */

135
ar5416/ar5416_cal_iq.c Normal file
View File

@ -0,0 +1,135 @@
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
*
* Permission to use, copy, modify, and/or 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.
*
* $Id: ar5416_cal_iq.c,v 1.2 2008/11/11 17:43:23 sam Exp $
*/
#include "opt_ah.h"
#ifdef AH_SUPPORT_AR5416
#include "ah.h"
#include "ah_internal.h"
#include "ah_devid.h"
#include "ar5416/ar5416.h"
#include "ar5416/ar5416reg.h"
#include "ar5416/ar5416phy.h"
/* IQ Cal aliases */
#define totalPowerMeasI(i) caldata[0][i].u
#define totalPowerMeasQ(i) caldata[1][i].u
#define totalIqCorrMeas(i) caldata[2][i].s
/*
* Collect data from HW to later perform IQ Mismatch Calibration
*/
void
ar5416IQCalCollect(struct ath_hal *ah)
{
struct ar5416PerCal *cal = &AH5416(ah)->ah_cal;
int i;
/*
* Accumulate IQ cal measures for active chains
*/
for (i = 0; i < AR5416_MAX_CHAINS; i++) {
cal->totalPowerMeasI(i) +=
OS_REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
cal->totalPowerMeasQ(i) +=
OS_REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
cal->totalIqCorrMeas(i) += (int32_t)
OS_REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
HALDEBUG(ah, HAL_DEBUG_PERCAL,
"%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
cal->calSamples, i, cal->totalPowerMeasI(i),
cal->totalPowerMeasQ(i), cal->totalIqCorrMeas(i));
}
}
/*
* Use HW data to do IQ Mismatch Calibration
*/
void
ar5416IQCalibration(struct ath_hal *ah, uint8_t numChains)
{
struct ar5416PerCal *cal = &AH5416(ah)->ah_cal;
int i;
for (i = 0; i < numChains; i++) {
uint32_t powerMeasI = cal->totalPowerMeasI(i);
uint32_t powerMeasQ = cal->totalPowerMeasQ(i);
uint32_t iqCorrMeas = cal->totalIqCorrMeas(i);
uint32_t qCoffDenom, iCoffDenom;
int iqCorrNeg;
HALDEBUG(ah, HAL_DEBUG_PERCAL,
"Start IQ Cal and Correction for Chain %d\n", i);
HALDEBUG(ah, HAL_DEBUG_PERCAL,
"Orignal: iq_corr_meas = 0x%08x\n", iqCorrMeas);
iqCorrNeg = 0;
/* iqCorrMeas is always negative. */
if (iqCorrMeas > 0x80000000) {
iqCorrMeas = (0xffffffff - iqCorrMeas) + 1;
iqCorrNeg = 1;
}
HALDEBUG(ah, HAL_DEBUG_PERCAL, " pwr_meas_i = 0x%08x\n",
powerMeasI);
HALDEBUG(ah, HAL_DEBUG_PERCAL, " pwr_meas_q = 0x%08x\n",
powerMeasQ);
HALDEBUG(ah, HAL_DEBUG_PERCAL, " iqCorrNeg is 0x%08x\n",
iqCorrNeg);
iCoffDenom = (powerMeasI/2 + powerMeasQ/2)/ 128;
qCoffDenom = powerMeasQ / 64;
/* Protect against divide-by-0 */
if (powerMeasQ != 0) {
/* IQ corr_meas is already negated if iqcorr_neg == 1 */
int32_t iCoff = iqCorrMeas/iCoffDenom;
int32_t qCoff = powerMeasI/qCoffDenom - 64;
HALDEBUG(ah, HAL_DEBUG_PERCAL, " iCoff = 0x%08x\n",
iCoff);
HALDEBUG(ah, HAL_DEBUG_PERCAL, " qCoff = 0x%08x\n",
qCoff);
/* Negate iCoff if iqCorrNeg == 0 */
iCoff = iCoff & 0x3f;
HALDEBUG(ah, HAL_DEBUG_PERCAL,
"New: iCoff = 0x%08x\n", iCoff);
if (iqCorrNeg == 0x0)
iCoff = 0x40 - iCoff;
if (qCoff > 15)
qCoff = 15;
else if (qCoff <= -16)
qCoff = 16;
HALDEBUG(ah, HAL_DEBUG_PERCAL,
" : iCoff = 0x%x qCoff = 0x%x\n", iCoff, qCoff);
OS_REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4_CHAIN(i),
AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF, iCoff);
OS_REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4_CHAIN(i),
AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF, qCoff);
HALDEBUG(ah, HAL_DEBUG_PERCAL,
"IQ Cal and Correction done for Chain %d\n", i);
}
}
OS_REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4,
AR_PHY_TIMING_CTRL4_IQCORR_ENABLE);
}
#endif /* AH_SUPPORT_AR5416 */

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ar5416_misc.c,v 1.9 2008/11/10 04:08:04 sam Exp $
* $Id: ar5416_misc.c,v 1.12 2008/11/27 22:30:07 sam Exp $
*/
#include "opt_ah.h"
@ -277,7 +277,7 @@ ar5416GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
case HAL_BB_HANG_RIFS:
return AR_SREV_SOWL(ah) ? HAL_OK : HAL_ENOTSUPP;
case HAL_BB_HANG_DFS:
return AR_SREV_SOWL(ah) ? HAL_OK : HAL_ENOTSUPP;
return AR_SREV_SOWL(ah) ? HAL_OK : HAL_ENOTSUPP;
case HAL_BB_HANG_RX_CLEAR:
return AR_SREV_MERLIN(ah) ? HAL_OK : HAL_ENOTSUPP;
}
@ -285,7 +285,8 @@ ar5416GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
case HAL_CAP_MAC_HANG:
return ((ah->ah_macVersion == AR_XSREV_VERSION_OWL_PCI) ||
(ah->ah_macVersion == AR_XSREV_VERSION_OWL_PCIE) ||
AR_SREV_SOWL(ah)) ? HAL_OK : HAL_ENOTSUPP;
AR_SREV_SOWL(ah)) ?
HAL_OK : HAL_ENOTSUPP;
default:
break;
}
@ -316,6 +317,7 @@ ar5416GetDiagState(struct ath_hal *ah, int request,
ahp->ah_hangs = 0;
if (hangs & HAL_BB_HANGS)
ahp->ah_hangs |= ar5416DetectBBHang(ah);
/* NB: if BB is hung MAC will be hung too so skip check */
if (ahp->ah_hangs == 0 && (hangs & HAL_MAC_HANGS))
ahp->ah_hangs |= ar5416DetectMacHang(ah);
*result = &ahp->ah_hangs;

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ar5416_phy.c,v 1.3 2008/11/10 01:19:39 sam Exp $
* $Id: ar5416_phy.c,v 1.4 2008/11/27 22:30:08 sam Exp $
*/
#include "opt_ah.h"
@ -40,7 +40,7 @@ HAL_RATE_TABLE ar5416_11ng_table = {
/* 2 Mb */ { AH_TRUE, CCK, 2000, 0x1a, 0x04, (0x80| 4), 1 },
/* 5.5 Mb */ { AH_TRUE, CCK, 5500, 0x19, 0x04, (0x80|11), 2 },
/* 11 Mb */ { AH_TRUE, CCK, 11000, 0x18, 0x04, (0x80|22), 3 },
/* We remove rates 6, 9 from rate ctrl */
/* Remove rates 6, 9 from rate ctrl */
/* 6 Mb */ { AH_FALSE, OFDM, 6000, 0x0b, 0x00, 12, 4 },
/* 9 Mb */ { AH_FALSE, OFDM, 9000, 0x0f, 0x00, 18, 4 },
/* 12 Mb */ { AH_TRUE, OFDM, 12000, 0x0a, 0x00, 24, 6 },

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ar5416_power.c,v 1.5 2008/11/10 04:08:04 sam Exp $
* $Id: ar5416_power.c,v 1.6 2008/11/11 00:11:30 sam Exp $
*/
#include "opt_ah.h"

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ar5416_recv.c,v 1.5 2008/11/10 04:08:04 sam Exp $
* $Id: ar5416_recv.c,v 1.7 2008/11/11 20:46:06 sam Exp $
*/
#include "opt_ah.h"
@ -36,12 +36,15 @@ ar5416StartPcuReceive(struct ath_hal *ah)
{
struct ath_hal_private *ahp = AH_PRIVATE(ah);
OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT);
HALDEBUG(ah, HAL_DEBUG_RX, "%s: Start PCU Receive \n", __func__);
ar5212EnableMibCounters(ah);
/* NB: restore current settings */
ar5212AniReset(ah, ahp->ah_curchan, ahp->ah_opmode, AH_TRUE);
ar5416AniReset(ah, ahp->ah_curchan, ahp->ah_opmode, AH_TRUE);
/*
* NB: must do after enabling phy errors to avoid rx
* frames w/ corrupted descriptor status.
*/
OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT);
}
/*

File diff suppressed because it is too large Load Diff

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ar5416_xmit.c,v 1.8 2008/11/10 04:08:05 sam Exp $
* $Id: ar5416_xmit.c,v 1.9 2008/11/27 22:30:08 sam Exp $
*/
#include "opt_ah.h"

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ar5416desc.h,v 1.6 2008/11/10 04:08:05 sam Exp $
* $Id: ar5416desc.h,v 1.7 2008/11/11 00:11:30 sam Exp $
*/
#ifndef _ATH_AR5416_DESC_H_
#define _ATH_AR5416_DESC_H

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ar5416phy.h,v 1.8 2008/11/06 22:08:01 sam Exp $
* $Id: ar5416phy.h,v 1.10 2008/11/11 20:46:06 sam Exp $
*/
#ifndef _DEV_ATH_AR5416PHY_H_
#define _DEV_ATH_AR5416PHY_H_
@ -218,6 +218,14 @@
#define AR_PHY_SPUR_REG 0x994c
#define AR_PHY_SFCORR_EXT 0x99c0
#define AR_PHY_SFCORR_EXT_M1_THRESH 0x0000007F
#define AR_PHY_SFCORR_EXT_M1_THRESH_S 0
#define AR_PHY_SFCORR_EXT_M2_THRESH 0x00003F80
#define AR_PHY_SFCORR_EXT_M2_THRESH_S 7
#define AR_PHY_SFCORR_EXT_M1_THRESH_LOW 0x001FC000
#define AR_PHY_SFCORR_EXT_M1_THRESH_LOW_S 14
#define AR_PHY_SFCORR_EXT_M2_THRESH_LOW 0x0FE00000
#define AR_PHY_SFCORR_EXT_M2_THRESH_LOW_S 21
#define AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S 28
/* enable vit puncture per rate, 8 bits, lsb is low rate */
@ -237,4 +245,6 @@
#define AR_PHY_CHANNEL_MASK_01_30 0x99d4
#define AR_PHY_CHANNEL_MASK_31_60 0x99d8
#define AR_PHY_CL_CAL_CTL 0xA358 /* carrier leak cal control */
#define AR_PHY_CL_CAL_ENABLE 0x00000002
#endif /* _DEV_ATH_AR5416PHY_H_ */

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ar5416reg.h,v 1.9 2008/11/06 22:07:22 sam Exp $
* $Id: ar5416reg.h,v 1.10 2008/11/11 00:11:30 sam Exp $
*/
#ifndef _DEV_ATH_AR5416REG_H
#define _DEV_ATH_AR5416REG_H
@ -445,10 +445,6 @@
#define IS_5416V2(_ah) ((_ah)->ah_macRev >= AR_SREV_REVISION_OWL_20)
#define IS_5416V2_2(_ah) ((_ah)->ah_macRev == AR_SREV_REVISION_OWL_22)
#define AR_SREV_VERSION_HOWL 0x014
#define AR_SREV_HOWL(_ah) \
(AH_PRIVATE((_ah))->ah_macVersion == AR_SREV_VERSION_HOWL)
/* Expanded Mac Silicon Rev (16 bits starting with Sowl) */
#define AR_XSREV_ID 0xFFFFFFFF /* Chip ID */
#define AR_XSREV_ID_S 0

View File

@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: ar9160_attach.c,v 1.10 2008/11/10 04:08:05 sam Exp $
* $Id: ar9160_attach.c,v 1.14 2008/11/27 22:30:08 sam Exp $
*/
#include "opt_ah.h"
@ -129,11 +129,11 @@ ar9160Attach(uint16_t devid, HAL_SOFTC sc,
/* override 5416 methods for our needs */
ah->ah_detach = ar9160Detach;
AH5416(ah)->ah_iqCalData.calData = &ar9160_iq_cal;
AH5416(ah)->ah_adcGainCalData.calData = &ar9160_adc_gain_cal;
AH5416(ah)->ah_adcDcCalData.calData = &ar9160_adc_dc_cal;
AH5416(ah)->ah_adcDcCalInitData.calData = &ar9160_adc_init_dc_cal;
AH5416(ah)->ah_suppCals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL;
AH5416(ah)->ah_cal.iqCalData.calData = &ar9160_iq_cal;
AH5416(ah)->ah_cal.adcGainCalData.calData = &ar9160_adc_gain_cal;
AH5416(ah)->ah_cal.adcDcCalData.calData = &ar9160_adc_dc_cal;
AH5416(ah)->ah_cal.adcDcCalInitData.calData = &ar9160_adc_init_dc_cal;
AH5416(ah)->ah_cal.suppCals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL;
if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON)) {
/* reset chip */
@ -255,14 +255,13 @@ ar9160Attach(uint16_t devid, HAL_SOFTC sc,
* ah_miscMode is populated by ar5416FillCapabilityInfo()
* starting from griffin. Set here to make sure that
* AR_MISC_MODE_MIC_NEW_LOC_ENABLE is set before a GTK is
* placed into hardware
* placed into hardware.
*/
if (ahp->ah_miscMode != 0)
OS_REG_WRITE(ah, AR_MISC_MODE, ahp->ah_miscMode);
ar5212InitializeGainValues(ah); /* gain ladder */
ar9160AniSetup(ah); /* Anti Noise Immunity */
ar5416InitNfHistBuff(AH5416(ah)->ah_nfCalHist);
ar5416InitNfHistBuff(AH5416(ah)->ah_cal.nfCalHist);
HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: return\n", __func__);

View File

@ -14,6 +14,6 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: version.h,v 1.31 2008/11/10 01:05:31 sam Exp $
* $Id: version.h,v 1.64 2008/11/27 22:29:27 sam Exp $
*/
#define ATH_HAL_VERSION "0.11.2.0"
#define ATH_HAL_VERSION "0.11.3.7"