Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem

This commit is contained in:
John W. Linville 2011-12-06 10:47:12 -05:00
commit d39aeaf260
132 changed files with 6643 additions and 2813 deletions

View File

@ -166,7 +166,9 @@ static int ath_ahb_probe(struct platform_device *pdev)
if (to_platform_device(ah->dev)->id == 0 && if (to_platform_device(ah->dev)->id == 0 &&
(bcfg->config->flags & (BD_WLAN0 | BD_WLAN1)) == (bcfg->config->flags & (BD_WLAN0 | BD_WLAN1)) ==
(BD_WLAN1 | BD_WLAN0)) (BD_WLAN1 | BD_WLAN0))
__set_bit(ATH_STAT_2G_DISABLED, ah->status); ah->ah_capabilities.cap_needs_2GHz_ovr = true;
else
ah->ah_capabilities.cap_needs_2GHz_ovr = false;
} }
ret = ath5k_init_ah(ah, &ath_ahb_bus_ops); ret = ath5k_init_ah(ah, &ath_ahb_bus_ops);

View File

@ -27,15 +27,21 @@
* or reducing sensitivity as necessary. * or reducing sensitivity as necessary.
* *
* The parameters are: * The parameters are:
*
* - "noise immunity" * - "noise immunity"
*
* - "spur immunity" * - "spur immunity"
*
* - "firstep level" * - "firstep level"
*
* - "OFDM weak signal detection" * - "OFDM weak signal detection"
*
* - "CCK weak signal detection" * - "CCK weak signal detection"
* *
* Basically we look at the amount of ODFM and CCK timing errors we get and then * Basically we look at the amount of ODFM and CCK timing errors we get and then
* raise or lower immunity accordingly by setting one or more of these * raise or lower immunity accordingly by setting one or more of these
* parameters. * parameters.
*
* Newer chipsets have PHY error counters in hardware which will generate a MIB * Newer chipsets have PHY error counters in hardware which will generate a MIB
* interrupt when they overflow. Older hardware has too enable PHY error frames * interrupt when they overflow. Older hardware has too enable PHY error frames
* by setting a RX flag and then count every single PHY error. When a specified * by setting a RX flag and then count every single PHY error. When a specified
@ -45,11 +51,13 @@
*/ */
/*** ANI parameter control ***/ /***********************\
* ANI parameter control *
\***********************/
/** /**
* ath5k_ani_set_noise_immunity_level() - Set noise immunity level * ath5k_ani_set_noise_immunity_level() - Set noise immunity level
* * @ah: The &struct ath5k_hw
* @level: level between 0 and @ATH5K_ANI_MAX_NOISE_IMM_LVL * @level: level between 0 and @ATH5K_ANI_MAX_NOISE_IMM_LVL
*/ */
void void
@ -91,12 +99,11 @@ ath5k_ani_set_noise_immunity_level(struct ath5k_hw *ah, int level)
ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_ANI, "new level %d", level); ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_ANI, "new level %d", level);
} }
/** /**
* ath5k_ani_set_spur_immunity_level() - Set spur immunity level * ath5k_ani_set_spur_immunity_level() - Set spur immunity level
* * @ah: The &struct ath5k_hw
* @level: level between 0 and @max_spur_level (the maximum level is dependent * @level: level between 0 and @max_spur_level (the maximum level is dependent
* on the chip revision). * on the chip revision).
*/ */
void void
ath5k_ani_set_spur_immunity_level(struct ath5k_hw *ah, int level) ath5k_ani_set_spur_immunity_level(struct ath5k_hw *ah, int level)
@ -117,10 +124,9 @@ ath5k_ani_set_spur_immunity_level(struct ath5k_hw *ah, int level)
ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_ANI, "new level %d", level); ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_ANI, "new level %d", level);
} }
/** /**
* ath5k_ani_set_firstep_level() - Set "firstep" level * ath5k_ani_set_firstep_level() - Set "firstep" level
* * @ah: The &struct ath5k_hw
* @level: level between 0 and @ATH5K_ANI_MAX_FIRSTEP_LVL * @level: level between 0 and @ATH5K_ANI_MAX_FIRSTEP_LVL
*/ */
void void
@ -140,11 +146,9 @@ ath5k_ani_set_firstep_level(struct ath5k_hw *ah, int level)
ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_ANI, "new level %d", level); ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_ANI, "new level %d", level);
} }
/** /**
* ath5k_ani_set_ofdm_weak_signal_detection() - Control OFDM weak signal * ath5k_ani_set_ofdm_weak_signal_detection() - Set OFDM weak signal detection
* detection * @ah: The &struct ath5k_hw
*
* @on: turn on or off * @on: turn on or off
*/ */
void void
@ -182,10 +186,9 @@ ath5k_ani_set_ofdm_weak_signal_detection(struct ath5k_hw *ah, bool on)
on ? "on" : "off"); on ? "on" : "off");
} }
/** /**
* ath5k_ani_set_cck_weak_signal_detection() - control CCK weak signal detection * ath5k_ani_set_cck_weak_signal_detection() - Set CCK weak signal detection
* * @ah: The &struct ath5k_hw
* @on: turn on or off * @on: turn on or off
*/ */
void void
@ -200,13 +203,16 @@ ath5k_ani_set_cck_weak_signal_detection(struct ath5k_hw *ah, bool on)
} }
/*** ANI algorithm ***/ /***************\
* ANI algorithm *
\***************/
/** /**
* ath5k_ani_raise_immunity() - Increase noise immunity * ath5k_ani_raise_immunity() - Increase noise immunity
* * @ah: The &struct ath5k_hw
* @as: The &struct ath5k_ani_state
* @ofdm_trigger: If this is true we are called because of too many OFDM errors, * @ofdm_trigger: If this is true we are called because of too many OFDM errors,
* the algorithm will tune more parameters then. * the algorithm will tune more parameters then.
* *
* Try to raise noise immunity (=decrease sensitivity) in several steps * Try to raise noise immunity (=decrease sensitivity) in several steps
* depending on the average RSSI of the beacons we received. * depending on the average RSSI of the beacons we received.
@ -290,9 +296,10 @@ ath5k_ani_raise_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as,
*/ */
} }
/** /**
* ath5k_ani_lower_immunity() - Decrease noise immunity * ath5k_ani_lower_immunity() - Decrease noise immunity
* @ah: The &struct ath5k_hw
* @as: The &struct ath5k_ani_state
* *
* Try to lower noise immunity (=increase sensitivity) in several steps * Try to lower noise immunity (=increase sensitivity) in several steps
* depending on the average RSSI of the beacons we received. * depending on the average RSSI of the beacons we received.
@ -352,9 +359,10 @@ ath5k_ani_lower_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as)
} }
} }
/** /**
* ath5k_hw_ani_get_listen_time() - Update counters and return listening time * ath5k_hw_ani_get_listen_time() - Update counters and return listening time
* @ah: The &struct ath5k_hw
* @as: The &struct ath5k_ani_state
* *
* Return an approximation of the time spent "listening" in milliseconds (ms) * Return an approximation of the time spent "listening" in milliseconds (ms)
* since the last call of this function. * since the last call of this function.
@ -379,9 +387,10 @@ ath5k_hw_ani_get_listen_time(struct ath5k_hw *ah, struct ath5k_ani_state *as)
return listen; return listen;
} }
/** /**
* ath5k_ani_save_and_clear_phy_errors() - Clear and save PHY error counters * ath5k_ani_save_and_clear_phy_errors() - Clear and save PHY error counters
* @ah: The &struct ath5k_hw
* @as: The &struct ath5k_ani_state
* *
* Clear the PHY error counters as soon as possible, since this might be called * Clear the PHY error counters as soon as possible, since this might be called
* from a MIB interrupt and we want to make sure we don't get interrupted again. * from a MIB interrupt and we want to make sure we don't get interrupted again.
@ -429,14 +438,14 @@ ath5k_ani_save_and_clear_phy_errors(struct ath5k_hw *ah,
return 1; return 1;
} }
/** /**
* ath5k_ani_period_restart() - Restart ANI period * ath5k_ani_period_restart() - Restart ANI period
* @as: The &struct ath5k_ani_state
* *
* Just reset counters, so they are clear for the next "ani period". * Just reset counters, so they are clear for the next "ani period".
*/ */
static void static void
ath5k_ani_period_restart(struct ath5k_hw *ah, struct ath5k_ani_state *as) ath5k_ani_period_restart(struct ath5k_ani_state *as)
{ {
/* keep last values for debugging */ /* keep last values for debugging */
as->last_ofdm_errors = as->ofdm_errors; as->last_ofdm_errors = as->ofdm_errors;
@ -448,9 +457,9 @@ ath5k_ani_period_restart(struct ath5k_hw *ah, struct ath5k_ani_state *as)
as->listen_time = 0; as->listen_time = 0;
} }
/** /**
* ath5k_ani_calibration() - The main ANI calibration function * ath5k_ani_calibration() - The main ANI calibration function
* @ah: The &struct ath5k_hw
* *
* We count OFDM and CCK errors relative to the time where we did not send or * We count OFDM and CCK errors relative to the time where we did not send or
* receive ("listen" time) and raise or lower immunity accordingly. * receive ("listen" time) and raise or lower immunity accordingly.
@ -492,7 +501,7 @@ ath5k_ani_calibration(struct ath5k_hw *ah)
/* too many PHY errors - we have to raise immunity */ /* too many PHY errors - we have to raise immunity */
bool ofdm_flag = as->ofdm_errors > ofdm_high ? true : false; bool ofdm_flag = as->ofdm_errors > ofdm_high ? true : false;
ath5k_ani_raise_immunity(ah, as, ofdm_flag); ath5k_ani_raise_immunity(ah, as, ofdm_flag);
ath5k_ani_period_restart(ah, as); ath5k_ani_period_restart(as);
} else if (as->listen_time > 5 * ATH5K_ANI_LISTEN_PERIOD) { } else if (as->listen_time > 5 * ATH5K_ANI_LISTEN_PERIOD) {
/* If more than 5 (TODO: why 5?) periods have passed and we got /* If more than 5 (TODO: why 5?) periods have passed and we got
@ -504,15 +513,18 @@ ath5k_ani_calibration(struct ath5k_hw *ah)
if (as->ofdm_errors <= ofdm_low && as->cck_errors <= cck_low) if (as->ofdm_errors <= ofdm_low && as->cck_errors <= cck_low)
ath5k_ani_lower_immunity(ah, as); ath5k_ani_lower_immunity(ah, as);
ath5k_ani_period_restart(ah, as); ath5k_ani_period_restart(as);
} }
} }
/*** INTERRUPT HANDLER ***/ /*******************\
* Interrupt handler *
\*******************/
/** /**
* ath5k_ani_mib_intr() - Interrupt handler for ANI MIB counters * ath5k_ani_mib_intr() - Interrupt handler for ANI MIB counters
* @ah: The &struct ath5k_hw
* *
* Just read & reset the registers quickly, so they don't generate more * Just read & reset the registers quickly, so they don't generate more
* interrupts, save the counters and schedule the tasklet to decide whether * interrupts, save the counters and schedule the tasklet to decide whether
@ -549,9 +561,11 @@ ath5k_ani_mib_intr(struct ath5k_hw *ah)
tasklet_schedule(&ah->ani_tasklet); tasklet_schedule(&ah->ani_tasklet);
} }
/** /**
* ath5k_ani_phy_error_report() - Used by older HW to report PHY errors * ath5k_ani_phy_error_report - Used by older HW to report PHY errors
*
* @ah: The &struct ath5k_hw
* @phyerr: One of enum ath5k_phy_error_code
* *
* This is used by hardware without PHY error counters to report PHY errors * This is used by hardware without PHY error counters to report PHY errors
* on a frame-by-frame basis, instead of the interrupt. * on a frame-by-frame basis, instead of the interrupt.
@ -574,10 +588,13 @@ ath5k_ani_phy_error_report(struct ath5k_hw *ah,
} }
/*** INIT ***/ /****************\
* Initialization *
\****************/
/** /**
* ath5k_enable_phy_err_counters() - Enable PHY error counters * ath5k_enable_phy_err_counters() - Enable PHY error counters
* @ah: The &struct ath5k_hw
* *
* Enable PHY error counters for OFDM and CCK timing errors. * Enable PHY error counters for OFDM and CCK timing errors.
*/ */
@ -596,9 +613,9 @@ ath5k_enable_phy_err_counters(struct ath5k_hw *ah)
ath5k_hw_reg_write(ah, 0, AR5K_CCK_FIL_CNT); ath5k_hw_reg_write(ah, 0, AR5K_CCK_FIL_CNT);
} }
/** /**
* ath5k_disable_phy_err_counters() - Disable PHY error counters * ath5k_disable_phy_err_counters() - Disable PHY error counters
* @ah: The &struct ath5k_hw
* *
* Disable PHY error counters for OFDM and CCK timing errors. * Disable PHY error counters for OFDM and CCK timing errors.
*/ */
@ -615,10 +632,10 @@ ath5k_disable_phy_err_counters(struct ath5k_hw *ah)
ath5k_hw_reg_write(ah, 0, AR5K_CCK_FIL_CNT); ath5k_hw_reg_write(ah, 0, AR5K_CCK_FIL_CNT);
} }
/** /**
* ath5k_ani_init() - Initialize ANI * ath5k_ani_init() - Initialize ANI
* @mode: Which mode to use (auto, manual high, manual low, off) * @ah: The &struct ath5k_hw
* @mode: One of enum ath5k_ani_mode
* *
* Initialize ANI according to mode. * Initialize ANI according to mode.
*/ */
@ -695,10 +712,18 @@ ath5k_ani_init(struct ath5k_hw *ah, enum ath5k_ani_mode mode)
} }
/*** DEBUG ***/ /**************\
* Debug output *
\**************/
#ifdef CONFIG_ATH5K_DEBUG #ifdef CONFIG_ATH5K_DEBUG
/**
* ath5k_ani_print_counters() - Print ANI counters
* @ah: The &struct ath5k_hw
*
* Used for debugging ANI
*/
void void
ath5k_ani_print_counters(struct ath5k_hw *ah) ath5k_ani_print_counters(struct ath5k_hw *ah)
{ {

View File

@ -40,13 +40,13 @@ enum ath5k_phy_error_code;
* enum ath5k_ani_mode - mode for ANI / noise sensitivity * enum ath5k_ani_mode - mode for ANI / noise sensitivity
* *
* @ATH5K_ANI_MODE_OFF: Turn ANI off. This can be useful to just stop the ANI * @ATH5K_ANI_MODE_OFF: Turn ANI off. This can be useful to just stop the ANI
* algorithm after it has been on auto mode. * algorithm after it has been on auto mode.
* ATH5K_ANI_MODE_MANUAL_LOW: Manually set all immunity parameters to low, * @ATH5K_ANI_MODE_MANUAL_LOW: Manually set all immunity parameters to low,
* maximizing sensitivity. ANI will not run. * maximizing sensitivity. ANI will not run.
* ATH5K_ANI_MODE_MANUAL_HIGH: Manually set all immunity parameters to high, * @ATH5K_ANI_MODE_MANUAL_HIGH: Manually set all immunity parameters to high,
* minimizing sensitivity. ANI will not run. * minimizing sensitivity. ANI will not run.
* ATH5K_ANI_MODE_AUTO: Automatically control immunity parameters based on the * @ATH5K_ANI_MODE_AUTO: Automatically control immunity parameters based on the
* amount of OFDM and CCK frame errors (default). * amount of OFDM and CCK frame errors (default).
*/ */
enum ath5k_ani_mode { enum ath5k_ani_mode {
ATH5K_ANI_MODE_OFF = 0, ATH5K_ANI_MODE_OFF = 0,
@ -58,8 +58,22 @@ enum ath5k_ani_mode {
/** /**
* struct ath5k_ani_state - ANI state and associated counters * struct ath5k_ani_state - ANI state and associated counters
* * @ani_mode: One of enum ath5k_ani_mode
* @max_spur_level: the maximum spur level is chip dependent * @noise_imm_level: Noise immunity level
* @spur_level: Spur immunity level
* @firstep_level: FIRstep level
* @ofdm_weak_sig: OFDM weak signal detection state (on/off)
* @cck_weak_sig: CCK weak signal detection state (on/off)
* @max_spur_level: Max spur immunity level (chip specific)
* @listen_time: Listen time
* @ofdm_errors: OFDM timing error count
* @cck_errors: CCK timing error count
* @last_cc: The &struct ath_cycle_counters (for stats)
* @last_listen: Listen time from previous run (for stats)
* @last_ofdm_errors: OFDM timing error count from previous run (for tats)
* @last_cck_errors: CCK timing error count from previous run (for stats)
* @sum_ofdm_errors: Sum of OFDM timing errors (for stats)
* @sum_cck_errors: Sum of all CCK timing errors (for stats)
*/ */
struct ath5k_ani_state { struct ath5k_ani_state {
enum ath5k_ani_mode ani_mode; enum ath5k_ani_mode ani_mode;

View File

@ -187,10 +187,9 @@
#define AR5K_TUNE_MAX_TXPOWER 63 #define AR5K_TUNE_MAX_TXPOWER 63
#define AR5K_TUNE_DEFAULT_TXPOWER 25 #define AR5K_TUNE_DEFAULT_TXPOWER 25
#define AR5K_TUNE_TPC_TXPOWER false #define AR5K_TUNE_TPC_TXPOWER false
#define ATH5K_TUNE_CALIBRATION_INTERVAL_FULL 10000 /* 10 sec */ #define ATH5K_TUNE_CALIBRATION_INTERVAL_FULL 60000 /* 60 sec */
#define ATH5K_TUNE_CALIBRATION_INTERVAL_SHORT 10000 /* 10 sec */
#define ATH5K_TUNE_CALIBRATION_INTERVAL_ANI 1000 /* 1 sec */ #define ATH5K_TUNE_CALIBRATION_INTERVAL_ANI 1000 /* 1 sec */
#define ATH5K_TUNE_CALIBRATION_INTERVAL_NF 60000 /* 60 sec */
#define ATH5K_TX_COMPLETE_POLL_INT 3000 /* 3 sec */ #define ATH5K_TX_COMPLETE_POLL_INT 3000 /* 3 sec */
#define AR5K_INIT_CARR_SENSE_EN 1 #define AR5K_INIT_CARR_SENSE_EN 1
@ -262,16 +261,34 @@
#define AR5K_AGC_SETTLING_TURBO 37 #define AR5K_AGC_SETTLING_TURBO 37
/* GENERIC CHIPSET DEFINITIONS */
/* MAC Chips */ /*****************************\
* GENERIC CHIPSET DEFINITIONS *
\*****************************/
/**
* enum ath5k_version - MAC Chips
* @AR5K_AR5210: AR5210 (Crete)
* @AR5K_AR5211: AR5211 (Oahu/Maui)
* @AR5K_AR5212: AR5212 (Venice) and newer
*/
enum ath5k_version { enum ath5k_version {
AR5K_AR5210 = 0, AR5K_AR5210 = 0,
AR5K_AR5211 = 1, AR5K_AR5211 = 1,
AR5K_AR5212 = 2, AR5K_AR5212 = 2,
}; };
/* PHY Chips */ /**
* enum ath5k_radio - PHY Chips
* @AR5K_RF5110: RF5110 (Fez)
* @AR5K_RF5111: RF5111 (Sombrero)
* @AR5K_RF5112: RF2112/5112(A) (Derby/Derby2)
* @AR5K_RF2413: RF2413/2414 (Griffin/Griffin-Lite)
* @AR5K_RF5413: RF5413/5414/5424 (Eagle/Condor)
* @AR5K_RF2316: RF2315/2316 (Cobra SoC)
* @AR5K_RF2317: RF2317 (Spider SoC)
* @AR5K_RF2425: RF2425/2417 (Swan/Nalla)
*/
enum ath5k_radio { enum ath5k_radio {
AR5K_RF5110 = 0, AR5K_RF5110 = 0,
AR5K_RF5111 = 1, AR5K_RF5111 = 1,
@ -303,11 +320,11 @@ enum ath5k_radio {
#define AR5K_SREV_AR5213A 0x59 /* Hainan */ #define AR5K_SREV_AR5213A 0x59 /* Hainan */
#define AR5K_SREV_AR2413 0x78 /* Griffin lite */ #define AR5K_SREV_AR2413 0x78 /* Griffin lite */
#define AR5K_SREV_AR2414 0x70 /* Griffin */ #define AR5K_SREV_AR2414 0x70 /* Griffin */
#define AR5K_SREV_AR2315_R6 0x86 /* AP51-Light */ #define AR5K_SREV_AR2315_R6 0x86 /* AP51-Light */
#define AR5K_SREV_AR2315_R7 0x87 /* AP51-Full */ #define AR5K_SREV_AR2315_R7 0x87 /* AP51-Full */
#define AR5K_SREV_AR5424 0x90 /* Condor */ #define AR5K_SREV_AR5424 0x90 /* Condor */
#define AR5K_SREV_AR2317_R1 0x90 /* AP61-Light */ #define AR5K_SREV_AR2317_R1 0x90 /* AP61-Light */
#define AR5K_SREV_AR2317_R2 0x91 /* AP61-Full */ #define AR5K_SREV_AR2317_R2 0x91 /* AP61-Full */
#define AR5K_SREV_AR5413 0xa4 /* Eagle lite */ #define AR5K_SREV_AR5413 0xa4 /* Eagle lite */
#define AR5K_SREV_AR5414 0xa0 /* Eagle */ #define AR5K_SREV_AR5414 0xa0 /* Eagle */
#define AR5K_SREV_AR2415 0xb0 /* Talon */ #define AR5K_SREV_AR2415 0xb0 /* Talon */
@ -344,32 +361,40 @@ enum ath5k_radio {
/* TODO add support to mac80211 for vendor-specific rates and modes */ /* TODO add support to mac80211 for vendor-specific rates and modes */
/* /**
* DOC: Atheros XR
*
* Some of this information is based on Documentation from: * Some of this information is based on Documentation from:
* *
* http://madwifi-project.org/wiki/ChipsetFeatures/SuperAG * http://madwifi-project.org/wiki/ChipsetFeatures/SuperAG
* *
* Modulation for Atheros' eXtended Range - range enhancing extension that is * Atheros' eXtended Range - range enhancing extension is a modulation scheme
* supposed to double the distance an Atheros client device can keep a * that is supposed to double the link distance between an Atheros XR-enabled
* connection with an Atheros access point. This is achieved by increasing * client device with an Atheros XR-enabled access point. This is achieved
* the receiver sensitivity up to, -105dBm, which is about 20dB above what * by increasing the receiver sensitivity up to, -105dBm, which is about 20dB
* the 802.11 specifications demand. In addition, new (proprietary) data rates * above what the 802.11 specifications demand. In addition, new (proprietary)
* are introduced: 3, 2, 1, 0.5 and 0.25 MBit/s. * data rates are introduced: 3, 2, 1, 0.5 and 0.25 MBit/s.
* *
* Please note that can you either use XR or TURBO but you cannot use both, * Please note that can you either use XR or TURBO but you cannot use both,
* they are exclusive. * they are exclusive.
* *
* Also note that we do not plan to support XR mode at least for now. You can
* get a mode similar to XR by using 5MHz bwmode.
*/ */
#define MODULATION_XR 0x00000200
/*
* Modulation for Atheros' Turbo G and Turbo A, its supposed to provide a /**
* throughput transmission speed up to 40Mbit/s-60Mbit/s at a 108Mbit/s * DOC: Atheros SuperAG
* signaling rate achieved through the bonding of two 54Mbit/s 802.11g *
* channels. To use this feature your Access Point must also support it. * In addition to XR we have another modulation scheme called TURBO mode
* that is supposed to provide a throughput transmission speed up to 40Mbit/s
* -60Mbit/s at a 108Mbit/s signaling rate achieved through the bonding of two
* 54Mbit/s 802.11g channels. To use this feature both ends must support it.
* There is also a distinction between "static" and "dynamic" turbo modes: * There is also a distinction between "static" and "dynamic" turbo modes:
* *
* - Static: is the dumb version: devices set to this mode stick to it until * - Static: is the dumb version: devices set to this mode stick to it until
* the mode is turned off. * the mode is turned off.
*
* - Dynamic: is the intelligent version, the network decides itself if it * - Dynamic: is the intelligent version, the network decides itself if it
* is ok to use turbo. As soon as traffic is detected on adjacent channels * is ok to use turbo. As soon as traffic is detected on adjacent channels
* (which would get used in turbo mode), or when a non-turbo station joins * (which would get used in turbo mode), or when a non-turbo station joins
@ -383,24 +408,39 @@ enum ath5k_radio {
* *
* http://www.pcworld.com/article/id,113428-page,1/article.html * http://www.pcworld.com/article/id,113428-page,1/article.html
* *
* The channel bonding seems to be driver specific though. In addition to * The channel bonding seems to be driver specific though.
* deciding what channels will be used, these "Turbo" modes are accomplished *
* by also enabling the following features: * In addition to TURBO modes we also have the following features for even
* greater speed-up:
* *
* - Bursting: allows multiple frames to be sent at once, rather than pausing * - Bursting: allows multiple frames to be sent at once, rather than pausing
* after each frame. Bursting is a standards-compliant feature that can be * after each frame. Bursting is a standards-compliant feature that can be
* used with any Access Point. * used with any Access Point.
*
* - Fast frames: increases the amount of information that can be sent per * - Fast frames: increases the amount of information that can be sent per
* frame, also resulting in a reduction of transmission overhead. It is a * frame, also resulting in a reduction of transmission overhead. It is a
* proprietary feature that needs to be supported by the Access Point. * proprietary feature that needs to be supported by the Access Point.
*
* - Compression: data frames are compressed in real time using a Lempel Ziv * - Compression: data frames are compressed in real time using a Lempel Ziv
* algorithm. This is done transparently. Once this feature is enabled, * algorithm. This is done transparently. Once this feature is enabled,
* compression and decompression takes place inside the chipset, without * compression and decompression takes place inside the chipset, without
* putting additional load on the host CPU. * putting additional load on the host CPU.
* *
* As with XR we also don't plan to support SuperAG features for now. You can
* get a mode similar to TURBO by using 40MHz bwmode.
*/ */
#define MODULATION_TURBO 0x00000080
/**
* enum ath5k_driver_mode - PHY operation mode
* @AR5K_MODE_11A: 802.11a
* @AR5K_MODE_11B: 802.11b
* @AR5K_MODE_11G: 801.11g
* @AR5K_MODE_MAX: Used for boundary checks
*
* Do not change the order here, we use these as
* array indices and it also maps EEPROM structures.
*/
enum ath5k_driver_mode { enum ath5k_driver_mode {
AR5K_MODE_11A = 0, AR5K_MODE_11A = 0,
AR5K_MODE_11B = 1, AR5K_MODE_11B = 1,
@ -408,30 +448,64 @@ enum ath5k_driver_mode {
AR5K_MODE_MAX = 3 AR5K_MODE_MAX = 3
}; };
/**
* enum ath5k_ant_mode - Antenna operation mode
* @AR5K_ANTMODE_DEFAULT: Default antenna setup
* @AR5K_ANTMODE_FIXED_A: Only antenna A is present
* @AR5K_ANTMODE_FIXED_B: Only antenna B is present
* @AR5K_ANTMODE_SINGLE_AP: STA locked on a single ap
* @AR5K_ANTMODE_SECTOR_AP: AP with tx antenna set on tx desc
* @AR5K_ANTMODE_SECTOR_STA: STA with tx antenna set on tx desc
* @AR5K_ANTMODE_DEBUG: Debug mode -A -> Rx, B-> Tx-
* @AR5K_ANTMODE_MAX: Used for boundary checks
*
* For more infos on antenna control check out phy.c
*/
enum ath5k_ant_mode { enum ath5k_ant_mode {
AR5K_ANTMODE_DEFAULT = 0, /* default antenna setup */ AR5K_ANTMODE_DEFAULT = 0,
AR5K_ANTMODE_FIXED_A = 1, /* only antenna A is present */ AR5K_ANTMODE_FIXED_A = 1,
AR5K_ANTMODE_FIXED_B = 2, /* only antenna B is present */ AR5K_ANTMODE_FIXED_B = 2,
AR5K_ANTMODE_SINGLE_AP = 3, /* sta locked on a single ap */ AR5K_ANTMODE_SINGLE_AP = 3,
AR5K_ANTMODE_SECTOR_AP = 4, /* AP with tx antenna set on tx desc */ AR5K_ANTMODE_SECTOR_AP = 4,
AR5K_ANTMODE_SECTOR_STA = 5, /* STA with tx antenna set on tx desc */ AR5K_ANTMODE_SECTOR_STA = 5,
AR5K_ANTMODE_DEBUG = 6, /* Debug mode -A -> Rx, B-> Tx- */ AR5K_ANTMODE_DEBUG = 6,
AR5K_ANTMODE_MAX, AR5K_ANTMODE_MAX,
}; };
/**
* enum ath5k_bw_mode - Bandwidth operation mode
* @AR5K_BWMODE_DEFAULT: 20MHz, default operation
* @AR5K_BWMODE_5MHZ: Quarter rate
* @AR5K_BWMODE_10MHZ: Half rate
* @AR5K_BWMODE_40MHZ: Turbo
*/
enum ath5k_bw_mode { enum ath5k_bw_mode {
AR5K_BWMODE_DEFAULT = 0, /* 20MHz, default operation */ AR5K_BWMODE_DEFAULT = 0,
AR5K_BWMODE_5MHZ = 1, /* Quarter rate */ AR5K_BWMODE_5MHZ = 1,
AR5K_BWMODE_10MHZ = 2, /* Half rate */ AR5K_BWMODE_10MHZ = 2,
AR5K_BWMODE_40MHZ = 3 /* Turbo */ AR5K_BWMODE_40MHZ = 3
}; };
/****************\ /****************\
TX DEFINITIONS TX DEFINITIONS
\****************/ \****************/
/* /**
* TX Status descriptor * struct ath5k_tx_status - TX Status descriptor
* @ts_seqnum: Sequence number
* @ts_tstamp: Timestamp
* @ts_status: Status code
* @ts_final_idx: Final transmission series index
* @ts_final_retry: Final retry count
* @ts_rssi: RSSI for received ACK
* @ts_shortretry: Short retry count
* @ts_virtcol: Virtual collision count
* @ts_antenna: Antenna used
*
* TX status descriptor gets filled by the hw
* on each transmission attempt.
*/ */
struct ath5k_tx_status { struct ath5k_tx_status {
u16 ts_seqnum; u16 ts_seqnum;
@ -454,7 +528,6 @@ struct ath5k_tx_status {
* enum ath5k_tx_queue - Queue types used to classify tx queues. * enum ath5k_tx_queue - Queue types used to classify tx queues.
* @AR5K_TX_QUEUE_INACTIVE: q is unused -- see ath5k_hw_release_tx_queue * @AR5K_TX_QUEUE_INACTIVE: q is unused -- see ath5k_hw_release_tx_queue
* @AR5K_TX_QUEUE_DATA: A normal data queue * @AR5K_TX_QUEUE_DATA: A normal data queue
* @AR5K_TX_QUEUE_XR_DATA: An XR-data queue
* @AR5K_TX_QUEUE_BEACON: The beacon queue * @AR5K_TX_QUEUE_BEACON: The beacon queue
* @AR5K_TX_QUEUE_CAB: The after-beacon queue * @AR5K_TX_QUEUE_CAB: The after-beacon queue
* @AR5K_TX_QUEUE_UAPSD: Unscheduled Automatic Power Save Delivery queue * @AR5K_TX_QUEUE_UAPSD: Unscheduled Automatic Power Save Delivery queue
@ -462,7 +535,6 @@ struct ath5k_tx_status {
enum ath5k_tx_queue { enum ath5k_tx_queue {
AR5K_TX_QUEUE_INACTIVE = 0, AR5K_TX_QUEUE_INACTIVE = 0,
AR5K_TX_QUEUE_DATA, AR5K_TX_QUEUE_DATA,
AR5K_TX_QUEUE_XR_DATA,
AR5K_TX_QUEUE_BEACON, AR5K_TX_QUEUE_BEACON,
AR5K_TX_QUEUE_CAB, AR5K_TX_QUEUE_CAB,
AR5K_TX_QUEUE_UAPSD, AR5K_TX_QUEUE_UAPSD,
@ -471,36 +543,46 @@ enum ath5k_tx_queue {
#define AR5K_NUM_TX_QUEUES 10 #define AR5K_NUM_TX_QUEUES 10
#define AR5K_NUM_TX_QUEUES_NOQCU 2 #define AR5K_NUM_TX_QUEUES_NOQCU 2
/* /**
* Queue syb-types to classify normal data queues. * enum ath5k_tx_queue_subtype - Queue sub-types to classify normal data queues
* @AR5K_WME_AC_BK: Background traffic
* @AR5K_WME_AC_BE: Best-effort (normal) traffic
* @AR5K_WME_AC_VI: Video traffic
* @AR5K_WME_AC_VO: Voice traffic
*
* These are the 4 Access Categories as defined in * These are the 4 Access Categories as defined in
* WME spec. 0 is the lowest priority and 4 is the * WME spec. 0 is the lowest priority and 4 is the
* highest. Normal data that hasn't been classified * highest. Normal data that hasn't been classified
* goes to the Best Effort AC. * goes to the Best Effort AC.
*/ */
enum ath5k_tx_queue_subtype { enum ath5k_tx_queue_subtype {
AR5K_WME_AC_BK = 0, /*Background traffic*/ AR5K_WME_AC_BK = 0,
AR5K_WME_AC_BE, /*Best-effort (normal) traffic*/ AR5K_WME_AC_BE,
AR5K_WME_AC_VI, /*Video traffic*/ AR5K_WME_AC_VI,
AR5K_WME_AC_VO, /*Voice traffic*/ AR5K_WME_AC_VO,
}; };
/* /**
* Queue ID numbers as returned by the hw functions, each number * enum ath5k_tx_queue_id - Queue ID numbers as returned by the hw functions
* represents a hw queue. If hw does not support hw queues * @AR5K_TX_QUEUE_ID_NOQCU_DATA: Data queue on AR5210 (no QCU available)
* (eg 5210) all data goes in one queue. These match * @AR5K_TX_QUEUE_ID_NOQCU_BEACON: Beacon queue on AR5210 (no QCU available)
* d80211 definitions (net80211/MadWiFi don't use them). * @AR5K_TX_QUEUE_ID_DATA_MIN: Data queue min index
* @AR5K_TX_QUEUE_ID_DATA_MAX: Data queue max index
* @AR5K_TX_QUEUE_ID_CAB: Content after beacon queue
* @AR5K_TX_QUEUE_ID_BEACON: Beacon queue
* @AR5K_TX_QUEUE_ID_UAPSD: Urgent Automatic Power Save Delivery,
*
* Each number represents a hw queue. If hw does not support hw queues
* (eg 5210) all data goes in one queue.
*/ */
enum ath5k_tx_queue_id { enum ath5k_tx_queue_id {
AR5K_TX_QUEUE_ID_NOQCU_DATA = 0, AR5K_TX_QUEUE_ID_NOQCU_DATA = 0,
AR5K_TX_QUEUE_ID_NOQCU_BEACON = 1, AR5K_TX_QUEUE_ID_NOQCU_BEACON = 1,
AR5K_TX_QUEUE_ID_DATA_MIN = 0, /*IEEE80211_TX_QUEUE_DATA0*/ AR5K_TX_QUEUE_ID_DATA_MIN = 0,
AR5K_TX_QUEUE_ID_DATA_MAX = 3, /*IEEE80211_TX_QUEUE_DATA3*/ AR5K_TX_QUEUE_ID_DATA_MAX = 3,
AR5K_TX_QUEUE_ID_DATA_SVP = 5, /*IEEE80211_TX_QUEUE_SVP - Spectralink Voice Protocol*/ AR5K_TX_QUEUE_ID_UAPSD = 7,
AR5K_TX_QUEUE_ID_CAB = 6, /*IEEE80211_TX_QUEUE_AFTER_BEACON*/ AR5K_TX_QUEUE_ID_CAB = 8,
AR5K_TX_QUEUE_ID_BEACON = 7, /*IEEE80211_TX_QUEUE_BEACON*/ AR5K_TX_QUEUE_ID_BEACON = 9,
AR5K_TX_QUEUE_ID_UAPSD = 8,
AR5K_TX_QUEUE_ID_XR_DATA = 9,
}; };
/* /*
@ -521,46 +603,70 @@ enum ath5k_tx_queue_id {
#define AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS 0x1000 /* Disable backoff while bursting */ #define AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS 0x1000 /* Disable backoff while bursting */
#define AR5K_TXQ_FLAG_COMPRESSION_ENABLE 0x2000 /* Enable hw compression -not implemented-*/ #define AR5K_TXQ_FLAG_COMPRESSION_ENABLE 0x2000 /* Enable hw compression -not implemented-*/
/* /**
* Data transmit queue state. One of these exists for each * struct ath5k_txq - Transmit queue state
* hardware transmit queue. Packets sent to us from above * @qnum: Hardware q number
* are assigned to queues based on their priority. Not all * @link: Link ptr in last TX desc
* devices support a complete set of hardware transmit queues. * @q: Transmit queue (&struct list_head)
* For those devices the array sc_ac2q will map multiple * @lock: Lock on q and link
* priorities to fewer hardware queues (typically all to one * @setup: Is the queue configured
* hardware queue). * @txq_len:Number of queued buffers
* @txq_max: Max allowed num of queued buffers
* @txq_poll_mark: Used to check if queue got stuck
* @txq_stuck: Queue stuck counter
*
* One of these exists for each hardware transmit queue.
* Packets sent to us from above are assigned to queues based
* on their priority. Not all devices support a complete set
* of hardware transmit queues. For those devices the array
* sc_ac2q will map multiple priorities to fewer hardware queues
* (typically all to one hardware queue).
*/ */
struct ath5k_txq { struct ath5k_txq {
unsigned int qnum; /* hardware q number */ unsigned int qnum;
u32 *link; /* link ptr in last TX desc */ u32 *link;
struct list_head q; /* transmit queue */ struct list_head q;
spinlock_t lock; /* lock on q and link */ spinlock_t lock;
bool setup; bool setup;
int txq_len; /* number of queued buffers */ int txq_len;
int txq_max; /* max allowed num of queued buffers */ int txq_max;
bool txq_poll_mark; bool txq_poll_mark;
unsigned int txq_stuck; /* informational counter */ unsigned int txq_stuck;
}; };
/* /**
* A struct to hold tx queue's parameters * struct ath5k_txq_info - A struct to hold TX queue's parameters
* @tqi_type: One of enum ath5k_tx_queue
* @tqi_subtype: One of enum ath5k_tx_queue_subtype
* @tqi_flags: TX queue flags (see above)
* @tqi_aifs: Arbitrated Inter-frame Space
* @tqi_cw_min: Minimum Contention Window
* @tqi_cw_max: Maximum Contention Window
* @tqi_cbr_period: Constant bit rate period
* @tqi_ready_time: Time queue waits after an event when RDYTIME is enabled
*/ */
struct ath5k_txq_info { struct ath5k_txq_info {
enum ath5k_tx_queue tqi_type; enum ath5k_tx_queue tqi_type;
enum ath5k_tx_queue_subtype tqi_subtype; enum ath5k_tx_queue_subtype tqi_subtype;
u16 tqi_flags; /* Tx queue flags (see above) */ u16 tqi_flags;
u8 tqi_aifs; /* Arbitrated Interframe Space */ u8 tqi_aifs;
u16 tqi_cw_min; /* Minimum Contention Window */ u16 tqi_cw_min;
u16 tqi_cw_max; /* Maximum Contention Window */ u16 tqi_cw_max;
u32 tqi_cbr_period; /* Constant bit rate period */ u32 tqi_cbr_period;
u32 tqi_cbr_overflow_limit; u32 tqi_cbr_overflow_limit;
u32 tqi_burst_time; u32 tqi_burst_time;
u32 tqi_ready_time; /* Time queue waits after an event */ u32 tqi_ready_time;
}; };
/* /**
* Transmit packet types. * enum ath5k_pkt_type - Transmit packet types
* used on tx control descriptor * @AR5K_PKT_TYPE_NORMAL: Normal data
* @AR5K_PKT_TYPE_ATIM: ATIM
* @AR5K_PKT_TYPE_PSPOLL: PS-Poll
* @AR5K_PKT_TYPE_BEACON: Beacon
* @AR5K_PKT_TYPE_PROBE_RESP: Probe response
* @AR5K_PKT_TYPE_PIFS: PIFS
* Used on tx control descriptor
*/ */
enum ath5k_pkt_type { enum ath5k_pkt_type {
AR5K_PKT_TYPE_NORMAL = 0, AR5K_PKT_TYPE_NORMAL = 0,
@ -583,27 +689,23 @@ enum ath5k_pkt_type {
(ah->ah_txpower.txp_rates_power_table[(_r)] & 0x3f) << (_v) \ (ah->ah_txpower.txp_rates_power_table[(_r)] & 0x3f) << (_v) \
) )
/*
* DMA size definitions (2^(n+2))
*/
enum ath5k_dmasize {
AR5K_DMASIZE_4B = 0,
AR5K_DMASIZE_8B,
AR5K_DMASIZE_16B,
AR5K_DMASIZE_32B,
AR5K_DMASIZE_64B,
AR5K_DMASIZE_128B,
AR5K_DMASIZE_256B,
AR5K_DMASIZE_512B
};
/****************\ /****************\
RX DEFINITIONS RX DEFINITIONS
\****************/ \****************/
/* /**
* RX Status descriptor * struct ath5k_rx_status - RX Status descriptor
* @rs_datalen: Data length
* @rs_tstamp: Timestamp
* @rs_status: Status code
* @rs_phyerr: PHY error mask
* @rs_rssi: RSSI in 0.5dbm units
* @rs_keyix: Index to the key used for decrypting
* @rs_rate: Rate used to decode the frame
* @rs_antenna: Antenna used to receive the frame
* @rs_more: Indicates this is a frame fragment (Fast frames)
*/ */
struct ath5k_rx_status { struct ath5k_rx_status {
u16 rs_datalen; u16 rs_datalen;
@ -645,10 +747,18 @@ struct ath5k_rx_status {
#define TSF_TO_TU(_tsf) (u32)((_tsf) >> 10) #define TSF_TO_TU(_tsf) (u32)((_tsf) >> 10)
/*******************************\ /*******************************\
GAIN OPTIMIZATION DEFINITIONS GAIN OPTIMIZATION DEFINITIONS
\*******************************/ \*******************************/
/**
* enum ath5k_rfgain - RF Gain optimization engine state
* @AR5K_RFGAIN_INACTIVE: Engine disabled
* @AR5K_RFGAIN_ACTIVE: Probe active
* @AR5K_RFGAIN_READ_REQUESTED: Probe requested
* @AR5K_RFGAIN_NEED_CHANGE: Gain_F needs change
*/
enum ath5k_rfgain { enum ath5k_rfgain {
AR5K_RFGAIN_INACTIVE = 0, AR5K_RFGAIN_INACTIVE = 0,
AR5K_RFGAIN_ACTIVE, AR5K_RFGAIN_ACTIVE,
@ -656,6 +766,16 @@ enum ath5k_rfgain {
AR5K_RFGAIN_NEED_CHANGE, AR5K_RFGAIN_NEED_CHANGE,
}; };
/**
* struct ath5k_gain - RF Gain optimization engine state data
* @g_step_idx: Current step index
* @g_current: Current gain
* @g_target: Target gain
* @g_low: Low gain boundary
* @g_high: High gain boundary
* @g_f_corr: Gain_F correction
* @g_state: One of enum ath5k_rfgain
*/
struct ath5k_gain { struct ath5k_gain {
u8 g_step_idx; u8 g_step_idx;
u8 g_current; u8 g_current;
@ -666,6 +786,8 @@ struct ath5k_gain {
u8 g_state; u8 g_state;
}; };
/********************\ /********************\
COMMON DEFINITIONS COMMON DEFINITIONS
\********************/ \********************/
@ -674,9 +796,14 @@ struct ath5k_gain {
#define AR5K_SLOT_TIME_20 880 #define AR5K_SLOT_TIME_20 880
#define AR5K_SLOT_TIME_MAX 0xffff #define AR5K_SLOT_TIME_MAX 0xffff
/* /**
* The following structure is used to map 2GHz channels to * struct ath5k_athchan_2ghz - 2GHz to 5GHZ map for RF5111
* 5GHz Atheros channels. * @a2_flags: Channel flags (internal)
* @a2_athchan: HW channel number (internal)
*
* This structure is used to map 2GHz channels to
* 5GHz Atheros channels on 2111 frequency converter
* that comes together with RF5111
* TODO: Clean up * TODO: Clean up
*/ */
struct ath5k_athchan_2ghz { struct ath5k_athchan_2ghz {
@ -684,36 +811,80 @@ struct ath5k_athchan_2ghz {
u16 a2_athchan; u16 a2_athchan;
}; };
/**
* enum ath5k_dmasize - DMA size definitions (2^(n+2))
* @AR5K_DMASIZE_4B: 4Bytes
* @AR5K_DMASIZE_8B: 8Bytes
* @AR5K_DMASIZE_16B: 16Bytes
* @AR5K_DMASIZE_32B: 32Bytes
* @AR5K_DMASIZE_64B: 64Bytes (Default)
* @AR5K_DMASIZE_128B: 128Bytes
* @AR5K_DMASIZE_256B: 256Bytes
* @AR5K_DMASIZE_512B: 512Bytes
*
* These are used to set DMA burst size on hw
*
* Note: Some platforms can't handle more than 4Bytes
* be careful on embedded boards.
*/
enum ath5k_dmasize {
AR5K_DMASIZE_4B = 0,
AR5K_DMASIZE_8B,
AR5K_DMASIZE_16B,
AR5K_DMASIZE_32B,
AR5K_DMASIZE_64B,
AR5K_DMASIZE_128B,
AR5K_DMASIZE_256B,
AR5K_DMASIZE_512B
};
/******************\ /******************\
RATE DEFINITIONS RATE DEFINITIONS
\******************/ \******************/
/** /**
* DOC: Rate codes
*
* Seems the ar5xxx hardware supports up to 32 rates, indexed by 1-32. * Seems the ar5xxx hardware supports up to 32 rates, indexed by 1-32.
* *
* The rate code is used to get the RX rate or set the TX rate on the * The rate code is used to get the RX rate or set the TX rate on the
* hardware descriptors. It is also used for internal modulation control * hardware descriptors. It is also used for internal modulation control
* and settings. * and settings.
* *
* This is the hardware rate map we are aware of: * This is the hardware rate map we are aware of (html unfriendly):
* *
* rate_code 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 * Rate code Rate (Kbps)
* rate_kbps 3000 1000 ? ? ? 2000 500 48000 * --------- -----------
* 0x01 3000 (XR)
* 0x02 1000 (XR)
* 0x03 250 (XR)
* 0x04 - 05 -Reserved-
* 0x06 2000 (XR)
* 0x07 500 (XR)
* 0x08 48000 (OFDM)
* 0x09 24000 (OFDM)
* 0x0A 12000 (OFDM)
* 0x0B 6000 (OFDM)
* 0x0C 54000 (OFDM)
* 0x0D 36000 (OFDM)
* 0x0E 18000 (OFDM)
* 0x0F 9000 (OFDM)
* 0x10 - 17 -Reserved-
* 0x18 11000L (CCK)
* 0x19 5500L (CCK)
* 0x1A 2000L (CCK)
* 0x1B 1000L (CCK)
* 0x1C 11000S (CCK)
* 0x1D 5500S (CCK)
* 0x1E 2000S (CCK)
* 0x1F -Reserved-
* *
* rate_code 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 * "S" indicates CCK rates with short preamble and "L" with long preamble.
* rate_kbps 24000 12000 6000 54000 36000 18000 9000 ?
*
* rate_code 17 18 19 20 21 22 23 24
* rate_kbps ? ? ? ? ? ? ? 11000
*
* rate_code 25 26 27 28 29 30 31 32
* rate_kbps 5500 2000 1000 11000S 5500S 2000S ? ?
*
* "S" indicates CCK rates with short preamble.
* *
* AR5211 has different rate codes for CCK (802.11B) rates. It only uses the * AR5211 has different rate codes for CCK (802.11B) rates. It only uses the
* lowest 4 bits, so they are the same as below with a 0xF mask. * lowest 4 bits, so they are the same as above with a 0xF mask.
* (0xB, 0xA, 0x9 and 0x8 for 1M, 2M, 5.5M and 11M). * (0xB, 0xA, 0x9 and 0x8 for 1M, 2M, 5.5M and 11M).
* We handle this in ath5k_setup_bands(). * We handle this in ath5k_setup_bands().
*/ */
@ -733,13 +904,9 @@ struct ath5k_athchan_2ghz {
#define ATH5K_RATE_CODE_36M 0x0D #define ATH5K_RATE_CODE_36M 0x0D
#define ATH5K_RATE_CODE_48M 0x08 #define ATH5K_RATE_CODE_48M 0x08
#define ATH5K_RATE_CODE_54M 0x0C #define ATH5K_RATE_CODE_54M 0x0C
/* XR */
#define ATH5K_RATE_CODE_XR_500K 0x07
#define ATH5K_RATE_CODE_XR_1M 0x02
#define ATH5K_RATE_CODE_XR_2M 0x06
#define ATH5K_RATE_CODE_XR_3M 0x01
/* adding this flag to rate_code enables short preamble */ /* Adding this flag to rate_code on B rates
* enables short preamble */
#define AR5K_SET_SHORT_PREAMBLE 0x04 #define AR5K_SET_SHORT_PREAMBLE 0x04
/* /*
@ -769,49 +936,65 @@ extern int ath5k_modparam_nohwcrypt;
/** /**
* enum ath5k_int - Hardware interrupt masks helpers * enum ath5k_int - Hardware interrupt masks helpers
* @AR5K_INT_RXOK: Frame successfully received
* @AR5K_INT_RXDESC: Request RX descriptor/Read RX descriptor
* @AR5K_INT_RXERR: Frame reception failed
* @AR5K_INT_RXNOFRM: No frame received within a specified time period
* @AR5K_INT_RXEOL: Reached "End Of List", means we need more RX descriptors
* @AR5K_INT_RXORN: Indicates we got RX FIFO overrun. Note that Rx overrun is
* not always fatal, on some chips we can continue operation
* without resetting the card, that's why %AR5K_INT_FATAL is not
* common for all chips.
* @AR5K_INT_RX_ALL: Mask to identify all RX related interrupts
*
* @AR5K_INT_TXOK: Frame transmission success
* @AR5K_INT_TXDESC: Request TX descriptor/Read TX status descriptor
* @AR5K_INT_TXERR: Frame transmission failure
* @AR5K_INT_TXEOL: Received End Of List for VEOL (Virtual End Of List). The
* Queue Control Unit (QCU) signals an EOL interrupt only if a
* descriptor's LinkPtr is NULL. For more details, refer to:
* "http://www.freepatentsonline.com/20030225739.html"
* @AR5K_INT_TXNOFRM: No frame was transmitted within a specified time period
* @AR5K_INT_TXURN: Indicates we got TX FIFO underrun. In such case we should
* increase the TX trigger threshold.
* @AR5K_INT_TX_ALL: Mask to identify all TX related interrupts
* *
* @AR5K_INT_RX: mask to identify received frame interrupts, of type
* AR5K_ISR_RXOK or AR5K_ISR_RXERR
* @AR5K_INT_RXDESC: Request RX descriptor/Read RX descriptor (?)
* @AR5K_INT_RXNOFRM: No frame received (?)
* @AR5K_INT_RXEOL: received End Of List for VEOL (Virtual End Of List). The
* Queue Control Unit (QCU) signals an EOL interrupt only if a descriptor's
* LinkPtr is NULL. For more details, refer to:
* http://www.freepatentsonline.com/20030225739.html
* @AR5K_INT_RXORN: Indicates we got RX overrun (eg. no more descriptors).
* Note that Rx overrun is not always fatal, on some chips we can continue
* operation without resetting the card, that's why int_fatal is not
* common for all chips.
* @AR5K_INT_TX: mask to identify received frame interrupts, of type
* AR5K_ISR_TXOK or AR5K_ISR_TXERR
* @AR5K_INT_TXDESC: Request TX descriptor/Read TX status descriptor (?)
* @AR5K_INT_TXURN: received when we should increase the TX trigger threshold
* We currently do increments on interrupt by
* (AR5K_TUNE_MAX_TX_FIFO_THRES - current_trigger_level) / 2
* @AR5K_INT_MIB: Indicates the either Management Information Base counters or * @AR5K_INT_MIB: Indicates the either Management Information Base counters or
* one of the PHY error counters reached the maximum value and should be * one of the PHY error counters reached the maximum value and
* read and cleared. * should be read and cleared.
* @AR5K_INT_SWI: Software triggered interrupt.
* @AR5K_INT_RXPHY: RX PHY Error * @AR5K_INT_RXPHY: RX PHY Error
* @AR5K_INT_RXKCM: RX Key cache miss * @AR5K_INT_RXKCM: RX Key cache miss
* @AR5K_INT_SWBA: SoftWare Beacon Alert - indicates its time to send a * @AR5K_INT_SWBA: SoftWare Beacon Alert - indicates its time to send a
* beacon that must be handled in software. The alternative is if you * beacon that must be handled in software. The alternative is if
* have VEOL support, in that case you let the hardware deal with things. * you have VEOL support, in that case you let the hardware deal
* with things.
* @AR5K_INT_BRSSI: Beacon received with an RSSI value below our threshold
* @AR5K_INT_BMISS: If in STA mode this indicates we have stopped seeing * @AR5K_INT_BMISS: If in STA mode this indicates we have stopped seeing
* beacons from the AP have associated with, we should probably try to * beacons from the AP have associated with, we should probably
* reassociate. When in IBSS mode this might mean we have not received * try to reassociate. When in IBSS mode this might mean we have
* any beacons from any local stations. Note that every station in an * not received any beacons from any local stations. Note that
* IBSS schedules to send beacons at the Target Beacon Transmission Time * every station in an IBSS schedules to send beacons at the
* (TBTT) with a random backoff. * Target Beacon Transmission Time (TBTT) with a random backoff.
* @AR5K_INT_BNR: Beacon Not Ready interrupt - ?? * @AR5K_INT_BNR: Beacon queue got triggered (DMA beacon alert) while empty.
* @AR5K_INT_GPIO: GPIO interrupt is used for RF Kill, disabled for now * @AR5K_INT_TIM: Beacon with local station's TIM bit set
* until properly handled * @AR5K_INT_DTIM: Beacon with DTIM bit and zero DTIM count received
* @AR5K_INT_FATAL: Fatal errors were encountered, typically caused by DMA * @AR5K_INT_DTIM_SYNC: DTIM sync lost
* errors. These types of errors we can enable seem to be of type * @AR5K_INT_GPIO: GPIO interrupt is used for RF Kill switches connected to
* AR5K_SIMR2_MCABT, AR5K_SIMR2_SSERR and AR5K_SIMR2_DPERR. * our GPIO pins.
* @AR5K_INT_BCN_TIMEOUT: Beacon timeout, we waited after TBTT but got noting
* @AR5K_INT_CAB_TIMEOUT: We waited for CAB traffic after the beacon but got
* nothing or an incomplete CAB frame sequence.
* @AR5K_INT_QCBRORN: A queue got it's CBR counter expired
* @AR5K_INT_QCBRURN: A queue got triggered wile empty
* @AR5K_INT_QTRIG: A queue got triggered
*
* @AR5K_INT_FATAL: Fatal errors were encountered, typically caused by bus/DMA
* errors. Indicates we need to reset the card.
* @AR5K_INT_GLOBAL: Used to clear and set the IER * @AR5K_INT_GLOBAL: Used to clear and set the IER
* @AR5K_INT_NOCARD: signals the card has been removed * @AR5K_INT_NOCARD: Signals the card has been removed
* @AR5K_INT_COMMON: common interrupts shared among MACs with the same * @AR5K_INT_COMMON: Common interrupts shared among MACs with the same
* bit value * bit value
* *
* These are mapped to take advantage of some common bits * These are mapped to take advantage of some common bits
* between the MACs, to be able to set intr properties * between the MACs, to be able to set intr properties
@ -847,15 +1030,15 @@ enum ath5k_int {
AR5K_INT_GPIO = 0x01000000, AR5K_INT_GPIO = 0x01000000,
AR5K_INT_BCN_TIMEOUT = 0x02000000, /* Non common */ AR5K_INT_BCN_TIMEOUT = 0x02000000, /* Non common */
AR5K_INT_CAB_TIMEOUT = 0x04000000, /* Non common */ AR5K_INT_CAB_TIMEOUT = 0x04000000, /* Non common */
AR5K_INT_RX_DOPPLER = 0x08000000, /* Non common */ AR5K_INT_QCBRORN = 0x08000000, /* Non common */
AR5K_INT_QCBRORN = 0x10000000, /* Non common */ AR5K_INT_QCBRURN = 0x10000000, /* Non common */
AR5K_INT_QCBRURN = 0x20000000, /* Non common */ AR5K_INT_QTRIG = 0x20000000, /* Non common */
AR5K_INT_QTRIG = 0x40000000, /* Non common */
AR5K_INT_GLOBAL = 0x80000000, AR5K_INT_GLOBAL = 0x80000000,
AR5K_INT_TX_ALL = AR5K_INT_TXOK AR5K_INT_TX_ALL = AR5K_INT_TXOK
| AR5K_INT_TXDESC | AR5K_INT_TXDESC
| AR5K_INT_TXERR | AR5K_INT_TXERR
| AR5K_INT_TXNOFRM
| AR5K_INT_TXEOL | AR5K_INT_TXEOL
| AR5K_INT_TXURN, | AR5K_INT_TXURN,
@ -891,15 +1074,32 @@ enum ath5k_int {
AR5K_INT_NOCARD = 0xffffffff AR5K_INT_NOCARD = 0xffffffff
}; };
/* mask which calibration is active at the moment */ /**
* enum ath5k_calibration_mask - Mask which calibration is active at the moment
* @AR5K_CALIBRATION_FULL: Full calibration (AGC + SHORT)
* @AR5K_CALIBRATION_SHORT: Short calibration (NF + I/Q)
* @AR5K_CALIBRATION_NF: Noise Floor calibration
* @AR5K_CALIBRATION_ANI: Adaptive Noise Immunity
*/
enum ath5k_calibration_mask { enum ath5k_calibration_mask {
AR5K_CALIBRATION_FULL = 0x01, AR5K_CALIBRATION_FULL = 0x01,
AR5K_CALIBRATION_SHORT = 0x02, AR5K_CALIBRATION_SHORT = 0x02,
AR5K_CALIBRATION_ANI = 0x04, AR5K_CALIBRATION_NF = 0x04,
AR5K_CALIBRATION_ANI = 0x08,
}; };
/* /**
* Power management * enum ath5k_power_mode - Power management modes
* @AR5K_PM_UNDEFINED: Undefined
* @AR5K_PM_AUTO: Allow card to sleep if possible
* @AR5K_PM_AWAKE: Force card to wake up
* @AR5K_PM_FULL_SLEEP: Force card to full sleep (DANGEROUS)
* @AR5K_PM_NETWORK_SLEEP: Allow to sleep for a specified duration
*
* Currently only PM_AWAKE is used, FULL_SLEEP and NETWORK_SLEEP/AUTO
* are also known to have problems on some cards. This is not a big
* problem though because we can have almost the same effect as
* FULL_SLEEP by putting card on warm reset (it's almost powered down).
*/ */
enum ath5k_power_mode { enum ath5k_power_mode {
AR5K_PM_UNDEFINED = 0, AR5K_PM_UNDEFINED = 0,
@ -957,6 +1157,8 @@ struct ath5k_capabilities {
} cap_queues; } cap_queues;
bool cap_has_phyerr_counters; bool cap_has_phyerr_counters;
bool cap_has_mrr_support;
bool cap_needs_2GHz_ovr;
}; };
/* size of noise floor history (keep it a power of two) */ /* size of noise floor history (keep it a power of two) */
@ -1072,13 +1274,11 @@ struct ath5k_hw {
dma_addr_t desc_daddr; /* DMA (physical) address */ dma_addr_t desc_daddr; /* DMA (physical) address */
size_t desc_len; /* size of TX/RX descriptors */ size_t desc_len; /* size of TX/RX descriptors */
DECLARE_BITMAP(status, 6); DECLARE_BITMAP(status, 4);
#define ATH_STAT_INVALID 0 /* disable hardware accesses */ #define ATH_STAT_INVALID 0 /* disable hardware accesses */
#define ATH_STAT_MRRETRY 1 /* multi-rate retry support */ #define ATH_STAT_PROMISC 1
#define ATH_STAT_PROMISC 2 #define ATH_STAT_LEDSOFT 2 /* enable LED gpio status */
#define ATH_STAT_LEDSOFT 3 /* enable LED gpio status */ #define ATH_STAT_STARTED 3 /* opened & irqs enabled */
#define ATH_STAT_STARTED 4 /* opened & irqs enabled */
#define ATH_STAT_2G_DISABLED 5 /* multiband radio without 2G */
unsigned int filter_flags; /* HW flags, AR5K_RX_FILTER_* */ unsigned int filter_flags; /* HW flags, AR5K_RX_FILTER_* */
struct ieee80211_channel *curchan; /* current h/w channel */ struct ieee80211_channel *curchan; /* current h/w channel */
@ -1097,6 +1297,7 @@ struct ath5k_hw {
led_on; /* pin setting for LED on */ led_on; /* pin setting for LED on */
struct work_struct reset_work; /* deferred chip reset */ struct work_struct reset_work; /* deferred chip reset */
struct work_struct calib_work; /* deferred phy calibration */
struct list_head rxbuf; /* receive buffer */ struct list_head rxbuf; /* receive buffer */
spinlock_t rxbuflock; spinlock_t rxbuflock;
@ -1113,8 +1314,6 @@ struct ath5k_hw {
struct ath5k_rfkill rf_kill; struct ath5k_rfkill rf_kill;
struct tasklet_struct calib; /* calibration tasklet */
spinlock_t block; /* protects beacon */ spinlock_t block; /* protects beacon */
struct tasklet_struct beacontq; /* beacon intr tasklet */ struct tasklet_struct beacontq; /* beacon intr tasklet */
struct list_head bcbuf; /* beacon buffer */ struct list_head bcbuf; /* beacon buffer */
@ -1144,7 +1343,7 @@ struct ath5k_hw {
enum ath5k_int ah_imr; enum ath5k_int ah_imr;
struct ieee80211_channel *ah_current_channel; struct ieee80211_channel *ah_current_channel;
bool ah_calibration; bool ah_iq_cal_needed;
bool ah_single_chip; bool ah_single_chip;
enum ath5k_version ah_version; enum ath5k_version ah_version;
@ -1187,7 +1386,13 @@ struct ath5k_hw {
u32 ah_txq_imr_cbrurn; u32 ah_txq_imr_cbrurn;
u32 ah_txq_imr_qtrig; u32 ah_txq_imr_qtrig;
u32 ah_txq_imr_nofrm; u32 ah_txq_imr_nofrm;
u32 ah_txq_isr;
u32 ah_txq_isr_txok_all;
u32 ah_txq_isr_txurn;
u32 ah_txq_isr_qcborn;
u32 ah_txq_isr_qcburn;
u32 ah_txq_isr_qtrig;
u32 *ah_rf_banks; u32 *ah_rf_banks;
size_t ah_rf_banks_size; size_t ah_rf_banks_size;
size_t ah_rf_regs_count; size_t ah_rf_regs_count;
@ -1228,8 +1433,8 @@ struct ath5k_hw {
/* Calibration timestamp */ /* Calibration timestamp */
unsigned long ah_cal_next_full; unsigned long ah_cal_next_full;
unsigned long ah_cal_next_short;
unsigned long ah_cal_next_ani; unsigned long ah_cal_next_ani;
unsigned long ah_cal_next_nf;
/* Calibration mask */ /* Calibration mask */
u8 ah_cal_mask; u8 ah_cal_mask;
@ -1338,11 +1543,11 @@ void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah);
u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah); u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah);
void ath5k_hw_set_tsf64(struct ath5k_hw *ah, u64 tsf64); void ath5k_hw_set_tsf64(struct ath5k_hw *ah, u64 tsf64);
void ath5k_hw_reset_tsf(struct ath5k_hw *ah); void ath5k_hw_reset_tsf(struct ath5k_hw *ah);
void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval); void ath5k_hw_init_beacon_timers(struct ath5k_hw *ah, u32 next_beacon,
u32 interval);
bool ath5k_hw_check_beacon_timers(struct ath5k_hw *ah, int intval); bool ath5k_hw_check_beacon_timers(struct ath5k_hw *ah, int intval);
/* Init function */ /* Init function */
void ath5k_hw_pcu_init(struct ath5k_hw *ah, enum nl80211_iftype op_mode, void ath5k_hw_pcu_init(struct ath5k_hw *ah, enum nl80211_iftype op_mode);
u8 mode);
/* Queue Control Unit, DFS Control Unit Functions */ /* Queue Control Unit, DFS Control Unit Functions */
int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue, int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue,

View File

@ -27,8 +27,7 @@
#include "debug.h" #include "debug.h"
/** /**
* ath5k_hw_post - Power On Self Test helper function * ath5k_hw_post() - Power On Self Test helper function
*
* @ah: The &struct ath5k_hw * @ah: The &struct ath5k_hw
*/ */
static int ath5k_hw_post(struct ath5k_hw *ah) static int ath5k_hw_post(struct ath5k_hw *ah)
@ -92,8 +91,7 @@ static int ath5k_hw_post(struct ath5k_hw *ah)
} }
/** /**
* ath5k_hw_init - Check if hw is supported and init the needed structs * ath5k_hw_init() - Check if hw is supported and init the needed structs
*
* @ah: The &struct ath5k_hw associated with the device * @ah: The &struct ath5k_hw associated with the device
* *
* Check if the device is supported, perform a POST and initialize the needed * Check if the device is supported, perform a POST and initialize the needed
@ -298,7 +296,7 @@ int ath5k_hw_init(struct ath5k_hw *ah)
/* Reset SERDES to load new settings */ /* Reset SERDES to load new settings */
ath5k_hw_reg_write(ah, 0x00000000, AR5K_PCIE_SERDES_RESET); ath5k_hw_reg_write(ah, 0x00000000, AR5K_PCIE_SERDES_RESET);
mdelay(1); usleep_range(1000, 1500);
} }
/* Get misc capabilities */ /* Get misc capabilities */
@ -308,11 +306,6 @@ int ath5k_hw_init(struct ath5k_hw *ah)
goto err; goto err;
} }
if (test_bit(ATH_STAT_2G_DISABLED, ah->status)) {
__clear_bit(AR5K_MODE_11B, ah->ah_capabilities.cap_mode);
__clear_bit(AR5K_MODE_11G, ah->ah_capabilities.cap_mode);
}
/* Crypto settings */ /* Crypto settings */
common->keymax = (ah->ah_version == AR5K_AR5210 ? common->keymax = (ah->ah_version == AR5K_AR5210 ?
AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211); AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211);
@ -349,8 +342,7 @@ int ath5k_hw_init(struct ath5k_hw *ah)
} }
/** /**
* ath5k_hw_deinit - Free the ath5k_hw struct * ath5k_hw_deinit() - Free the &struct ath5k_hw
*
* @ah: The &struct ath5k_hw * @ah: The &struct ath5k_hw
*/ */
void ath5k_hw_deinit(struct ath5k_hw *ah) void ath5k_hw_deinit(struct ath5k_hw *ah)

View File

@ -80,6 +80,11 @@ static int modparam_fastchanswitch;
module_param_named(fastchanswitch, modparam_fastchanswitch, bool, S_IRUGO); module_param_named(fastchanswitch, modparam_fastchanswitch, bool, S_IRUGO);
MODULE_PARM_DESC(fastchanswitch, "Enable fast channel switching for AR2413/AR5413 radios."); MODULE_PARM_DESC(fastchanswitch, "Enable fast channel switching for AR2413/AR5413 radios.");
static int ath5k_modparam_no_hw_rfkill_switch;
module_param_named(no_hw_rfkill_switch, ath5k_modparam_no_hw_rfkill_switch,
bool, S_IRUGO);
MODULE_PARM_DESC(no_hw_rfkill_switch, "Ignore the GPIO RFKill switch state");
/* Module info */ /* Module info */
MODULE_AUTHOR("Jiri Slaby"); MODULE_AUTHOR("Jiri Slaby");
@ -183,7 +188,6 @@ static const struct ieee80211_rate ath5k_rates[] = {
{ .bitrate = 540, { .bitrate = 540,
.hw_value = ATH5K_RATE_CODE_54M, .hw_value = ATH5K_RATE_CODE_54M,
.flags = 0 }, .flags = 0 },
/* XR missing */
}; };
static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp) static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp)
@ -721,22 +725,25 @@ ath5k_txbuf_setup(struct ath5k_hw *ah, struct ath5k_buf *bf,
if (ret) if (ret)
goto err_unmap; goto err_unmap;
memset(mrr_rate, 0, sizeof(mrr_rate)); /* Set up MRR descriptor */
memset(mrr_tries, 0, sizeof(mrr_tries)); if (ah->ah_capabilities.cap_has_mrr_support) {
for (i = 0; i < 3; i++) { memset(mrr_rate, 0, sizeof(mrr_rate));
rate = ieee80211_get_alt_retry_rate(ah->hw, info, i); memset(mrr_tries, 0, sizeof(mrr_tries));
if (!rate) for (i = 0; i < 3; i++) {
break; rate = ieee80211_get_alt_retry_rate(ah->hw, info, i);
if (!rate)
break;
mrr_rate[i] = rate->hw_value; mrr_rate[i] = rate->hw_value;
mrr_tries[i] = info->control.rates[i + 1].count; mrr_tries[i] = info->control.rates[i + 1].count;
}
ath5k_hw_setup_mrr_tx_desc(ah, ds,
mrr_rate[0], mrr_tries[0],
mrr_rate[1], mrr_tries[1],
mrr_rate[2], mrr_tries[2]);
} }
ath5k_hw_setup_mrr_tx_desc(ah, ds,
mrr_rate[0], mrr_tries[0],
mrr_rate[1], mrr_tries[1],
mrr_rate[2], mrr_tries[2]);
ds->ds_link = 0; ds->ds_link = 0;
ds->ds_data = bf->skbaddr; ds->ds_data = bf->skbaddr;
@ -1689,7 +1696,7 @@ ath5k_tasklet_tx(unsigned long data)
struct ath5k_hw *ah = (void *)data; struct ath5k_hw *ah = (void *)data;
for (i = 0; i < AR5K_NUM_TX_QUEUES; i++) for (i = 0; i < AR5K_NUM_TX_QUEUES; i++)
if (ah->txqs[i].setup && (ah->ah_txq_isr & BIT(i))) if (ah->txqs[i].setup && (ah->ah_txq_isr_txok_all & BIT(i)))
ath5k_tx_processq(ah, &ah->txqs[i]); ath5k_tx_processq(ah, &ah->txqs[i]);
ah->tx_pending = false; ah->tx_pending = false;
@ -2005,7 +2012,7 @@ ath5k_beacon_update_timers(struct ath5k_hw *ah, u64 bc_tsf)
ah->nexttbtt = nexttbtt; ah->nexttbtt = nexttbtt;
intval |= AR5K_BEACON_ENA; intval |= AR5K_BEACON_ENA;
ath5k_hw_init_beacon(ah, nexttbtt, intval); ath5k_hw_init_beacon_timers(ah, nexttbtt, intval);
/* /*
* debugging output last in order to preserve the time critical aspect * debugging output last in order to preserve the time critical aspect
@ -2112,16 +2119,29 @@ static void
ath5k_intr_calibration_poll(struct ath5k_hw *ah) ath5k_intr_calibration_poll(struct ath5k_hw *ah)
{ {
if (time_is_before_eq_jiffies(ah->ah_cal_next_ani) && if (time_is_before_eq_jiffies(ah->ah_cal_next_ani) &&
!(ah->ah_cal_mask & AR5K_CALIBRATION_FULL)) { !(ah->ah_cal_mask & AR5K_CALIBRATION_FULL) &&
/* run ANI only when full calibration is not active */ !(ah->ah_cal_mask & AR5K_CALIBRATION_SHORT)) {
/* Run ANI only when calibration is not active */
ah->ah_cal_next_ani = jiffies + ah->ah_cal_next_ani = jiffies +
msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_ANI); msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_ANI);
tasklet_schedule(&ah->ani_tasklet); tasklet_schedule(&ah->ani_tasklet);
} else if (time_is_before_eq_jiffies(ah->ah_cal_next_full)) { } else if (time_is_before_eq_jiffies(ah->ah_cal_next_short) &&
ah->ah_cal_next_full = jiffies + !(ah->ah_cal_mask & AR5K_CALIBRATION_FULL) &&
msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_FULL); !(ah->ah_cal_mask & AR5K_CALIBRATION_SHORT)) {
tasklet_schedule(&ah->calib);
/* Run calibration only when another calibration
* is not running.
*
* Note: This is for both full/short calibration,
* if it's time for a full one, ath5k_calibrate_work will deal
* with it. */
ah->ah_cal_next_short = jiffies +
msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_SHORT);
ieee80211_queue_work(ah->hw, &ah->calib_work);
} }
/* we could use SWI to generate enough interrupts to meet our /* we could use SWI to generate enough interrupts to meet our
* calibration interval requirements, if necessary: * calibration interval requirements, if necessary:
@ -2149,69 +2169,110 @@ ath5k_intr(int irq, void *dev_id)
enum ath5k_int status; enum ath5k_int status;
unsigned int counter = 1000; unsigned int counter = 1000;
/*
* If hw is not ready (or detached) and we get an
* interrupt, or if we have no interrupts pending
* (that means it's not for us) skip it.
*
* NOTE: Group 0/1 PCI interface registers are not
* supported on WiSOCs, so we can't check for pending
* interrupts (ISR belongs to another register group
* so we are ok).
*/
if (unlikely(test_bit(ATH_STAT_INVALID, ah->status) || if (unlikely(test_bit(ATH_STAT_INVALID, ah->status) ||
((ath5k_get_bus_type(ah) != ATH_AHB) && ((ath5k_get_bus_type(ah) != ATH_AHB) &&
!ath5k_hw_is_intr_pending(ah)))) !ath5k_hw_is_intr_pending(ah))))
return IRQ_NONE; return IRQ_NONE;
/** Main loop **/
do { do {
ath5k_hw_get_isr(ah, &status); /* NB: clears IRQ too */ ath5k_hw_get_isr(ah, &status); /* NB: clears IRQ too */
ATH5K_DBG(ah, ATH5K_DEBUG_INTR, "status 0x%x/0x%x\n", ATH5K_DBG(ah, ATH5K_DEBUG_INTR, "status 0x%x/0x%x\n",
status, ah->imask); status, ah->imask);
/*
* Fatal hw error -> Log and reset
*
* Fatal errors are unrecoverable so we have to
* reset the card. These errors include bus and
* dma errors.
*/
if (unlikely(status & AR5K_INT_FATAL)) { if (unlikely(status & AR5K_INT_FATAL)) {
/*
* Fatal errors are unrecoverable.
* Typically these are caused by DMA errors.
*/
ATH5K_DBG(ah, ATH5K_DEBUG_RESET, ATH5K_DBG(ah, ATH5K_DEBUG_RESET,
"fatal int, resetting\n"); "fatal int, resetting\n");
ieee80211_queue_work(ah->hw, &ah->reset_work); ieee80211_queue_work(ah->hw, &ah->reset_work);
/*
* RX Overrun -> Count and reset if needed
*
* Receive buffers are full. Either the bus is busy or
* the CPU is not fast enough to process all received
* frames.
*/
} else if (unlikely(status & AR5K_INT_RXORN)) { } else if (unlikely(status & AR5K_INT_RXORN)) {
/* /*
* Receive buffers are full. Either the bus is busy or
* the CPU is not fast enough to process all received
* frames.
* Older chipsets need a reset to come out of this * Older chipsets need a reset to come out of this
* condition, but we treat it as RX for newer chips. * condition, but we treat it as RX for newer chips.
* We don't know exactly which versions need a reset - * We don't know exactly which versions need a reset
* this guess is copied from the HAL. * this guess is copied from the HAL.
*/ */
ah->stats.rxorn_intr++; ah->stats.rxorn_intr++;
if (ah->ah_mac_srev < AR5K_SREV_AR5212) { if (ah->ah_mac_srev < AR5K_SREV_AR5212) {
ATH5K_DBG(ah, ATH5K_DEBUG_RESET, ATH5K_DBG(ah, ATH5K_DEBUG_RESET,
"rx overrun, resetting\n"); "rx overrun, resetting\n");
ieee80211_queue_work(ah->hw, &ah->reset_work); ieee80211_queue_work(ah->hw, &ah->reset_work);
} else } else
ath5k_schedule_rx(ah); ath5k_schedule_rx(ah);
} else { } else {
/* Software Beacon Alert -> Schedule beacon tasklet */
if (status & AR5K_INT_SWBA) if (status & AR5K_INT_SWBA)
tasklet_hi_schedule(&ah->beacontq); tasklet_hi_schedule(&ah->beacontq);
if (status & AR5K_INT_RXEOL) { /*
/* * No more RX descriptors -> Just count
* NB: the hardware should re-read the link when *
* RXE bit is written, but it doesn't work at * NB: the hardware should re-read the link when
* least on older hardware revs. * RXE bit is written, but it doesn't work at
*/ * least on older hardware revs.
*/
if (status & AR5K_INT_RXEOL)
ah->stats.rxeol_intr++; ah->stats.rxeol_intr++;
}
if (status & AR5K_INT_TXURN) {
/* bump tx trigger level */ /* TX Underrun -> Bump tx trigger level */
if (status & AR5K_INT_TXURN)
ath5k_hw_update_tx_triglevel(ah, true); ath5k_hw_update_tx_triglevel(ah, true);
}
/* RX -> Schedule rx tasklet */
if (status & (AR5K_INT_RXOK | AR5K_INT_RXERR)) if (status & (AR5K_INT_RXOK | AR5K_INT_RXERR))
ath5k_schedule_rx(ah); ath5k_schedule_rx(ah);
if (status & (AR5K_INT_TXOK | AR5K_INT_TXDESC
| AR5K_INT_TXERR | AR5K_INT_TXEOL)) /* TX -> Schedule tx tasklet */
if (status & (AR5K_INT_TXOK
| AR5K_INT_TXDESC
| AR5K_INT_TXERR
| AR5K_INT_TXEOL))
ath5k_schedule_tx(ah); ath5k_schedule_tx(ah);
if (status & AR5K_INT_BMISS) {
/* TODO */ /* Missed beacon -> TODO
} if (status & AR5K_INT_BMISS)
*/
/* MIB event -> Update counters and notify ANI */
if (status & AR5K_INT_MIB) { if (status & AR5K_INT_MIB) {
ah->stats.mib_intr++; ah->stats.mib_intr++;
ath5k_hw_update_mib_counters(ah); ath5k_hw_update_mib_counters(ah);
ath5k_ani_mib_intr(ah); ath5k_ani_mib_intr(ah);
} }
/* GPIO -> Notify RFKill layer */
if (status & AR5K_INT_GPIO) if (status & AR5K_INT_GPIO)
tasklet_schedule(&ah->rf_kill.toggleq); tasklet_schedule(&ah->rf_kill.toggleq);
@ -2222,12 +2283,19 @@ ath5k_intr(int irq, void *dev_id)
} while (ath5k_hw_is_intr_pending(ah) && --counter > 0); } while (ath5k_hw_is_intr_pending(ah) && --counter > 0);
/*
* Until we handle rx/tx interrupts mask them on IMR
*
* NOTE: ah->(rx/tx)_pending are set when scheduling the tasklets
* and unset after we 've handled the interrupts.
*/
if (ah->rx_pending || ah->tx_pending) if (ah->rx_pending || ah->tx_pending)
ath5k_set_current_imask(ah); ath5k_set_current_imask(ah);
if (unlikely(!counter)) if (unlikely(!counter))
ATH5K_WARN(ah, "too many interrupts, giving up for now\n"); ATH5K_WARN(ah, "too many interrupts, giving up for now\n");
/* Fire up calibration poll */
ath5k_intr_calibration_poll(ah); ath5k_intr_calibration_poll(ah);
return IRQ_HANDLED; return IRQ_HANDLED;
@ -2238,41 +2306,58 @@ ath5k_intr(int irq, void *dev_id)
* for temperature/environment changes. * for temperature/environment changes.
*/ */
static void static void
ath5k_tasklet_calibrate(unsigned long data) ath5k_calibrate_work(struct work_struct *work)
{ {
struct ath5k_hw *ah = (void *)data; struct ath5k_hw *ah = container_of(work, struct ath5k_hw,
calib_work);
/* Should we run a full calibration ? */
if (time_is_before_eq_jiffies(ah->ah_cal_next_full)) {
ah->ah_cal_next_full = jiffies +
msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_FULL);
ah->ah_cal_mask |= AR5K_CALIBRATION_FULL;
ATH5K_DBG(ah, ATH5K_DEBUG_CALIBRATE,
"running full calibration\n");
if (ath5k_hw_gainf_calibrate(ah) == AR5K_RFGAIN_NEED_CHANGE) {
/*
* Rfgain is out of bounds, reset the chip
* to load new gain values.
*/
ATH5K_DBG(ah, ATH5K_DEBUG_RESET,
"got new rfgain, resetting\n");
ieee80211_queue_work(ah->hw, &ah->reset_work);
}
/* TODO: On full calibration we should stop TX here,
* so that it doesn't interfere (mostly due to gain_f
* calibration that messes with tx packets -see phy.c).
*
* NOTE: Stopping the queues from above is not enough
* to stop TX but saves us from disconecting (at least
* we don't lose packets). */
ieee80211_stop_queues(ah->hw);
} else
ah->ah_cal_mask |= AR5K_CALIBRATION_SHORT;
/* Only full calibration for now */
ah->ah_cal_mask |= AR5K_CALIBRATION_FULL;
ATH5K_DBG(ah, ATH5K_DEBUG_CALIBRATE, "channel %u/%x\n", ATH5K_DBG(ah, ATH5K_DEBUG_CALIBRATE, "channel %u/%x\n",
ieee80211_frequency_to_channel(ah->curchan->center_freq), ieee80211_frequency_to_channel(ah->curchan->center_freq),
ah->curchan->hw_value); ah->curchan->hw_value);
if (ath5k_hw_gainf_calibrate(ah) == AR5K_RFGAIN_NEED_CHANGE) {
/*
* Rfgain is out of bounds, reset the chip
* to load new gain values.
*/
ATH5K_DBG(ah, ATH5K_DEBUG_RESET, "calibration, resetting\n");
ieee80211_queue_work(ah->hw, &ah->reset_work);
}
if (ath5k_hw_phy_calibrate(ah, ah->curchan)) if (ath5k_hw_phy_calibrate(ah, ah->curchan))
ATH5K_ERR(ah, "calibration of channel %u failed\n", ATH5K_ERR(ah, "calibration of channel %u failed\n",
ieee80211_frequency_to_channel( ieee80211_frequency_to_channel(
ah->curchan->center_freq)); ah->curchan->center_freq));
/* Noise floor calibration interrupts rx/tx path while I/Q calibration /* Clear calibration flags */
* doesn't. if (ah->ah_cal_mask & AR5K_CALIBRATION_FULL) {
* TODO: We should stop TX here, so that it doesn't interfere. ieee80211_wake_queues(ah->hw);
* Note that stopping the queues is not enough to stop TX! */ ah->ah_cal_mask &= ~AR5K_CALIBRATION_FULL;
if (time_is_before_eq_jiffies(ah->ah_cal_next_nf)) { } else if (ah->ah_cal_mask & AR5K_CALIBRATION_SHORT)
ah->ah_cal_next_nf = jiffies + ah->ah_cal_mask &= ~AR5K_CALIBRATION_SHORT;
msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_NF);
ath5k_hw_update_noise_floor(ah);
}
ah->ah_cal_mask &= ~AR5K_CALIBRATION_FULL;
} }
@ -2407,8 +2492,8 @@ ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops)
if (ret) if (ret)
goto err_irq; goto err_irq;
/* set up multi-rate retry capabilities */ /* Set up multi-rate retry capabilities */
if (ah->ah_version == AR5K_AR5212) { if (ah->ah_capabilities.cap_has_mrr_support) {
hw->max_rates = 4; hw->max_rates = 4;
hw->max_rate_tries = max(AR5K_INIT_RETRY_SHORT, hw->max_rate_tries = max(AR5K_INIT_RETRY_SHORT,
AR5K_INIT_RETRY_LONG); AR5K_INIT_RETRY_LONG);
@ -2544,15 +2629,22 @@ int ath5k_start(struct ieee80211_hw *hw)
* and then setup of the interrupt mask. * and then setup of the interrupt mask.
*/ */
ah->curchan = ah->hw->conf.channel; ah->curchan = ah->hw->conf.channel;
ah->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL | ah->imask = AR5K_INT_RXOK
AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL | | AR5K_INT_RXERR
AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_MIB; | AR5K_INT_RXEOL
| AR5K_INT_RXORN
| AR5K_INT_TXDESC
| AR5K_INT_TXEOL
| AR5K_INT_FATAL
| AR5K_INT_GLOBAL
| AR5K_INT_MIB;
ret = ath5k_reset(ah, NULL, false); ret = ath5k_reset(ah, NULL, false);
if (ret) if (ret)
goto done; goto done;
ath5k_rfkill_hw_start(ah); if (!ath5k_modparam_no_hw_rfkill_switch)
ath5k_rfkill_hw_start(ah);
/* /*
* Reset the key cache since some parts do not reset the * Reset the key cache since some parts do not reset the
@ -2585,7 +2677,6 @@ static void ath5k_stop_tasklets(struct ath5k_hw *ah)
ah->tx_pending = false; ah->tx_pending = false;
tasklet_kill(&ah->rxtq); tasklet_kill(&ah->rxtq);
tasklet_kill(&ah->txtq); tasklet_kill(&ah->txtq);
tasklet_kill(&ah->calib);
tasklet_kill(&ah->beacontq); tasklet_kill(&ah->beacontq);
tasklet_kill(&ah->ani_tasklet); tasklet_kill(&ah->ani_tasklet);
} }
@ -2637,7 +2728,8 @@ void ath5k_stop(struct ieee80211_hw *hw)
cancel_delayed_work_sync(&ah->tx_complete_work); cancel_delayed_work_sync(&ah->tx_complete_work);
ath5k_rfkill_hw_stop(ah); if (!ath5k_modparam_no_hw_rfkill_switch)
ath5k_rfkill_hw_stop(ah);
} }
/* /*
@ -2689,9 +2781,24 @@ ath5k_reset(struct ath5k_hw *ah, struct ieee80211_channel *chan,
ath5k_ani_init(ah, ani_mode); ath5k_ani_init(ah, ani_mode);
ah->ah_cal_next_full = jiffies + msecs_to_jiffies(100); /*
ah->ah_cal_next_ani = jiffies; * Set calibration intervals
ah->ah_cal_next_nf = jiffies; *
* Note: We don't need to run calibration imediately
* since some initial calibration is done on reset
* even for fast channel switching. Also on scanning
* this will get set again and again and it won't get
* executed unless we connect somewhere and spend some
* time on the channel (that's what calibration needs
* anyway to be accurate).
*/
ah->ah_cal_next_full = jiffies +
msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_FULL);
ah->ah_cal_next_ani = jiffies +
msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_ANI);
ah->ah_cal_next_short = jiffies +
msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_SHORT);
ewma_init(&ah->ah_beacon_rssi_avg, 1024, 8); ewma_init(&ah->ah_beacon_rssi_avg, 1024, 8);
/* clear survey data and cycle counters */ /* clear survey data and cycle counters */
@ -2744,20 +2851,6 @@ ath5k_init(struct ieee80211_hw *hw)
int ret; int ret;
/*
* Check if the MAC has multi-rate retry support.
* We do this by trying to setup a fake extended
* descriptor. MACs that don't have support will
* return false w/o doing anything. MACs that do
* support it will return true w/o doing anything.
*/
ret = ath5k_hw_setup_mrr_tx_desc(ah, NULL, 0, 0, 0, 0, 0, 0);
if (ret < 0)
goto err;
if (ret > 0)
__set_bit(ATH_STAT_MRRETRY, ah->status);
/* /*
* Collect the channel list. The 802.11 layer * Collect the channel list. The 802.11 layer
* is responsible for filtering this list based * is responsible for filtering this list based
@ -2841,11 +2934,11 @@ ath5k_init(struct ieee80211_hw *hw)
tasklet_init(&ah->rxtq, ath5k_tasklet_rx, (unsigned long)ah); tasklet_init(&ah->rxtq, ath5k_tasklet_rx, (unsigned long)ah);
tasklet_init(&ah->txtq, ath5k_tasklet_tx, (unsigned long)ah); tasklet_init(&ah->txtq, ath5k_tasklet_tx, (unsigned long)ah);
tasklet_init(&ah->calib, ath5k_tasklet_calibrate, (unsigned long)ah);
tasklet_init(&ah->beacontq, ath5k_tasklet_beacon, (unsigned long)ah); tasklet_init(&ah->beacontq, ath5k_tasklet_beacon, (unsigned long)ah);
tasklet_init(&ah->ani_tasklet, ath5k_tasklet_ani, (unsigned long)ah); tasklet_init(&ah->ani_tasklet, ath5k_tasklet_ani, (unsigned long)ah);
INIT_WORK(&ah->reset_work, ath5k_reset_work); INIT_WORK(&ah->reset_work, ath5k_reset_work);
INIT_WORK(&ah->calib_work, ath5k_calibrate_work);
INIT_DELAYED_WORK(&ah->tx_complete_work, ath5k_tx_complete_poll_work); INIT_DELAYED_WORK(&ah->tx_complete_work, ath5k_tx_complete_poll_work);
ret = ath5k_hw_common(ah)->bus_ops->eeprom_read_mac(ah, mac); ret = ath5k_hw_common(ah)->bus_ops->eeprom_read_mac(ah, mac);

View File

@ -85,12 +85,19 @@ int ath5k_hw_set_capabilities(struct ath5k_hw *ah)
caps->cap_range.range_2ghz_min = 2412; caps->cap_range.range_2ghz_min = 2412;
caps->cap_range.range_2ghz_max = 2732; caps->cap_range.range_2ghz_max = 2732;
if (AR5K_EEPROM_HDR_11B(ee_header)) /* Override 2GHz modes on SoCs that need it
__set_bit(AR5K_MODE_11B, caps->cap_mode); * NOTE: cap_needs_2GHz_ovr gets set from
* ath_ahb_probe */
if (!caps->cap_needs_2GHz_ovr) {
if (AR5K_EEPROM_HDR_11B(ee_header))
__set_bit(AR5K_MODE_11B,
caps->cap_mode);
if (AR5K_EEPROM_HDR_11G(ee_header) && if (AR5K_EEPROM_HDR_11G(ee_header) &&
ah->ah_version != AR5K_AR5211) ah->ah_version != AR5K_AR5211)
__set_bit(AR5K_MODE_11G, caps->cap_mode); __set_bit(AR5K_MODE_11G,
caps->cap_mode);
}
} }
} }
@ -103,12 +110,18 @@ int ath5k_hw_set_capabilities(struct ath5k_hw *ah)
else else
caps->cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES; caps->cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES;
/* newer hardware has PHY error counters */ /* Newer hardware has PHY error counters */
if (ah->ah_mac_srev >= AR5K_SREV_AR5213A) if (ah->ah_mac_srev >= AR5K_SREV_AR5213A)
caps->cap_has_phyerr_counters = true; caps->cap_has_phyerr_counters = true;
else else
caps->cap_has_phyerr_counters = false; caps->cap_has_phyerr_counters = false;
/* MACs since AR5212 have MRR support */
if (ah->ah_version == AR5K_AR5212)
caps->cap_has_mrr_support = true;
else
caps->cap_has_mrr_support = false;
return 0; return 0;
} }

View File

@ -26,20 +26,61 @@
#include "debug.h" #include "debug.h"
/**
* DOC: Hardware descriptor functions
*
* Here we handle the processing of the low-level hw descriptors
* that hw reads and writes via DMA for each TX and RX attempt (that means
* we can also have descriptors for failed TX/RX tries). We have two kind of
* descriptors for RX and TX, control descriptors tell the hw how to send or
* receive a packet where to read/write it from/to etc and status descriptors
* that contain information about how the packet was sent or received (errors
* included).
*
* Descriptor format is not exactly the same for each MAC chip version so we
* have function pointers on &struct ath5k_hw we initialize at runtime based on
* the chip used.
*/
/************************\ /************************\
* TX Control descriptors * * TX Control descriptors *
\************************/ \************************/
/* /**
* Initialize the 2-word tx control descriptor on 5210/5211 * ath5k_hw_setup_2word_tx_desc() - Initialize a 2-word tx control descriptor
* @ah: The &struct ath5k_hw
* @desc: The &struct ath5k_desc
* @pkt_len: Frame length in bytes
* @hdr_len: Header length in bytes (only used on AR5210)
* @padsize: Any padding we've added to the frame length
* @type: One of enum ath5k_pkt_type
* @tx_power: Tx power in 0.5dB steps
* @tx_rate0: HW idx for transmission rate
* @tx_tries0: Max number of retransmissions
* @key_index: Index on key table to use for encryption
* @antenna_mode: Which antenna to use (0 for auto)
* @flags: One of AR5K_TXDESC_* flags (desc.h)
* @rtscts_rate: HW idx for RTS/CTS transmission rate
* @rtscts_duration: What to put on duration field on the header of RTS/CTS
*
* Internal function to initialize a 2-Word TX control descriptor
* found on AR5210 and AR5211 MACs chips.
*
* Returns 0 on success or -EINVAL on false input
*/ */
static int static int
ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah,
unsigned int pkt_len, unsigned int hdr_len, int padsize, struct ath5k_desc *desc,
enum ath5k_pkt_type type, unsigned int pkt_len, unsigned int hdr_len,
unsigned int tx_power, unsigned int tx_rate0, unsigned int tx_tries0, int padsize,
unsigned int key_index, unsigned int antenna_mode, unsigned int flags, enum ath5k_pkt_type type,
unsigned int rtscts_rate, unsigned int rtscts_duration) unsigned int tx_power,
unsigned int tx_rate0, unsigned int tx_tries0,
unsigned int key_index,
unsigned int antenna_mode,
unsigned int flags,
unsigned int rtscts_rate, unsigned int rtscts_duration)
{ {
u32 frame_type; u32 frame_type;
struct ath5k_hw_2w_tx_ctl *tx_ctl; struct ath5k_hw_2w_tx_ctl *tx_ctl;
@ -172,17 +213,40 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
return 0; return 0;
} }
/* /**
* Initialize the 4-word tx control descriptor on 5212 * ath5k_hw_setup_4word_tx_desc() - Initialize a 4-word tx control descriptor
* @ah: The &struct ath5k_hw
* @desc: The &struct ath5k_desc
* @pkt_len: Frame length in bytes
* @hdr_len: Header length in bytes (only used on AR5210)
* @padsize: Any padding we've added to the frame length
* @type: One of enum ath5k_pkt_type
* @tx_power: Tx power in 0.5dB steps
* @tx_rate0: HW idx for transmission rate
* @tx_tries0: Max number of retransmissions
* @key_index: Index on key table to use for encryption
* @antenna_mode: Which antenna to use (0 for auto)
* @flags: One of AR5K_TXDESC_* flags (desc.h)
* @rtscts_rate: HW idx for RTS/CTS transmission rate
* @rtscts_duration: What to put on duration field on the header of RTS/CTS
*
* Internal function to initialize a 4-Word TX control descriptor
* found on AR5212 and later MACs chips.
*
* Returns 0 on success or -EINVAL on false input
*/ */
static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, static int
struct ath5k_desc *desc, unsigned int pkt_len, unsigned int hdr_len, ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
int padsize, struct ath5k_desc *desc,
enum ath5k_pkt_type type, unsigned int tx_power, unsigned int tx_rate0, unsigned int pkt_len, unsigned int hdr_len,
unsigned int tx_tries0, unsigned int key_index, int padsize,
unsigned int antenna_mode, unsigned int flags, enum ath5k_pkt_type type,
unsigned int rtscts_rate, unsigned int tx_power,
unsigned int rtscts_duration) unsigned int tx_rate0, unsigned int tx_tries0,
unsigned int key_index,
unsigned int antenna_mode,
unsigned int flags,
unsigned int rtscts_rate, unsigned int rtscts_duration)
{ {
struct ath5k_hw_4w_tx_ctl *tx_ctl; struct ath5k_hw_4w_tx_ctl *tx_ctl;
unsigned int frame_len; unsigned int frame_len;
@ -292,13 +356,29 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
return 0; return 0;
} }
/* /**
* Initialize a 4-word multi rate retry tx control descriptor on 5212 * ath5k_hw_setup_mrr_tx_desc() - Initialize an MRR tx control descriptor
* @ah: The &struct ath5k_hw
* @desc: The &struct ath5k_desc
* @tx_rate1: HW idx for rate used on transmission series 1
* @tx_tries1: Max number of retransmissions for transmission series 1
* @tx_rate2: HW idx for rate used on transmission series 2
* @tx_tries2: Max number of retransmissions for transmission series 2
* @tx_rate3: HW idx for rate used on transmission series 3
* @tx_tries3: Max number of retransmissions for transmission series 3
*
* Multi rate retry (MRR) tx control descriptors are available only on AR5212
* MACs, they are part of the normal 4-word tx control descriptor (see above)
* but we handle them through a separate function for better abstraction.
*
* Returns 0 on success or -EINVAL on invalid input
*/ */
int int
ath5k_hw_setup_mrr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, ath5k_hw_setup_mrr_tx_desc(struct ath5k_hw *ah,
unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2, struct ath5k_desc *desc,
u_int tx_tries2, unsigned int tx_rate3, u_int tx_tries3) u_int tx_rate1, u_int tx_tries1,
u_int tx_rate2, u_int tx_tries2,
u_int tx_rate3, u_int tx_tries3)
{ {
struct ath5k_hw_4w_tx_ctl *tx_ctl; struct ath5k_hw_4w_tx_ctl *tx_ctl;
@ -350,11 +430,16 @@ ath5k_hw_setup_mrr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
* TX Status descriptors * * TX Status descriptors *
\***********************/ \***********************/
/* /**
* Process the tx status descriptor on 5210/5211 * ath5k_hw_proc_2word_tx_status() - Process a tx status descriptor on 5210/1
* @ah: The &struct ath5k_hw
* @desc: The &struct ath5k_desc
* @ts: The &struct ath5k_tx_status
*/ */
static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah, static int
struct ath5k_desc *desc, struct ath5k_tx_status *ts) ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah,
struct ath5k_desc *desc,
struct ath5k_tx_status *ts)
{ {
struct ath5k_hw_2w_tx_ctl *tx_ctl; struct ath5k_hw_2w_tx_ctl *tx_ctl;
struct ath5k_hw_tx_status *tx_status; struct ath5k_hw_tx_status *tx_status;
@ -399,11 +484,16 @@ static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah,
return 0; return 0;
} }
/* /**
* Process a tx status descriptor on 5212 * ath5k_hw_proc_4word_tx_status() - Process a tx status descriptor on 5212
* @ah: The &struct ath5k_hw
* @desc: The &struct ath5k_desc
* @ts: The &struct ath5k_tx_status
*/ */
static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, static int
struct ath5k_desc *desc, struct ath5k_tx_status *ts) ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah,
struct ath5k_desc *desc,
struct ath5k_tx_status *ts)
{ {
struct ath5k_hw_4w_tx_ctl *tx_ctl; struct ath5k_hw_4w_tx_ctl *tx_ctl;
struct ath5k_hw_tx_status *tx_status; struct ath5k_hw_tx_status *tx_status;
@ -460,11 +550,17 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah,
* RX Descriptors * * RX Descriptors *
\****************/ \****************/
/* /**
* Initialize an rx control descriptor * ath5k_hw_setup_rx_desc() - Initialize an rx control descriptor
* @ah: The &struct ath5k_hw
* @desc: The &struct ath5k_desc
* @size: RX buffer length in bytes
* @flags: One of AR5K_RXDESC_* flags
*/ */
int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, int
u32 size, unsigned int flags) ath5k_hw_setup_rx_desc(struct ath5k_hw *ah,
struct ath5k_desc *desc,
u32 size, unsigned int flags)
{ {
struct ath5k_hw_rx_ctl *rx_ctl; struct ath5k_hw_rx_ctl *rx_ctl;
@ -491,11 +587,22 @@ int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
return 0; return 0;
} }
/* /**
* Process the rx status descriptor on 5210/5211 * ath5k_hw_proc_5210_rx_status() - Process the rx status descriptor on 5210/1
* @ah: The &struct ath5k_hw
* @desc: The &struct ath5k_desc
* @rs: The &struct ath5k_rx_status
*
* Internal function used to process an RX status descriptor
* on AR5210/5211 MAC.
*
* Returns 0 on success or -EINPROGRESS in case we haven't received the who;e
* frame yet.
*/ */
static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah, static int
struct ath5k_desc *desc, struct ath5k_rx_status *rs) ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah,
struct ath5k_desc *desc,
struct ath5k_rx_status *rs)
{ {
struct ath5k_hw_rx_status *rx_status; struct ath5k_hw_rx_status *rx_status;
@ -574,12 +681,22 @@ static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah,
return 0; return 0;
} }
/* /**
* Process the rx status descriptor on 5212 * ath5k_hw_proc_5212_rx_status() - Process the rx status descriptor on 5212
* @ah: The &struct ath5k_hw
* @desc: The &struct ath5k_desc
* @rs: The &struct ath5k_rx_status
*
* Internal function used to process an RX status descriptor
* on AR5212 and later MAC.
*
* Returns 0 on success or -EINPROGRESS in case we haven't received the who;e
* frame yet.
*/ */
static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah, static int
struct ath5k_desc *desc, ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah,
struct ath5k_rx_status *rs) struct ath5k_desc *desc,
struct ath5k_rx_status *rs)
{ {
struct ath5k_hw_rx_status *rx_status; struct ath5k_hw_rx_status *rx_status;
u32 rxstat0, rxstat1; u32 rxstat0, rxstat1;
@ -646,10 +763,16 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah,
* Attach * * Attach *
\********/ \********/
/* /**
* Init function pointers inside ath5k_hw struct * ath5k_hw_init_desc_functions() - Init function pointers inside ah
* @ah: The &struct ath5k_hw
*
* Maps the internal descriptor functions to the function pointers on ah, used
* from above. This is used as an abstraction layer to handle the various chips
* the same way.
*/ */
int ath5k_hw_init_desc_functions(struct ath5k_hw *ah) int
ath5k_hw_init_desc_functions(struct ath5k_hw *ah)
{ {
if (ah->ah_version == AR5K_AR5212) { if (ah->ah_version == AR5K_AR5212) {
ah->ah_setup_tx_desc = ath5k_hw_setup_4word_tx_desc; ah->ah_setup_tx_desc = ath5k_hw_setup_4word_tx_desc;

View File

@ -20,25 +20,30 @@
* RX/TX descriptor structures * RX/TX descriptor structures
*/ */
/* /**
* Common hardware RX control descriptor * struct ath5k_hw_rx_ctl - Common hardware RX control descriptor
* @rx_control_0: RX control word 0
* @rx_control_1: RX control word 1
*/ */
struct ath5k_hw_rx_ctl { struct ath5k_hw_rx_ctl {
u32 rx_control_0; /* RX control word 0 */ u32 rx_control_0;
u32 rx_control_1; /* RX control word 1 */ u32 rx_control_1;
} __packed __aligned(4); } __packed __aligned(4);
/* RX control word 1 fields/flags */ /* RX control word 1 fields/flags */
#define AR5K_DESC_RX_CTL1_BUF_LEN 0x00000fff /* data buffer length */ #define AR5K_DESC_RX_CTL1_BUF_LEN 0x00000fff /* data buffer length */
#define AR5K_DESC_RX_CTL1_INTREQ 0x00002000 /* RX interrupt request */ #define AR5K_DESC_RX_CTL1_INTREQ 0x00002000 /* RX interrupt request */
/* /**
* Common hardware RX status descriptor * struct ath5k_hw_rx_status - Common hardware RX status descriptor
* @rx_status_0: RX status word 0
* @rx_status_1: RX status word 1
*
* 5210, 5211 and 5212 differ only in the fields and flags defined below * 5210, 5211 and 5212 differ only in the fields and flags defined below
*/ */
struct ath5k_hw_rx_status { struct ath5k_hw_rx_status {
u32 rx_status_0; /* RX status word 0 */ u32 rx_status_0;
u32 rx_status_1; /* RX status word 1 */ u32 rx_status_1;
} __packed __aligned(4); } __packed __aligned(4);
/* 5210/5211 */ /* 5210/5211 */
@ -98,17 +103,36 @@ struct ath5k_hw_rx_status {
/** /**
* enum ath5k_phy_error_code - PHY Error codes * enum ath5k_phy_error_code - PHY Error codes
* @AR5K_RX_PHY_ERROR_UNDERRUN: Transmit underrun, [5210] No error
* @AR5K_RX_PHY_ERROR_TIMING: Timing error
* @AR5K_RX_PHY_ERROR_PARITY: Illegal parity
* @AR5K_RX_PHY_ERROR_RATE: Illegal rate
* @AR5K_RX_PHY_ERROR_LENGTH: Illegal length
* @AR5K_RX_PHY_ERROR_RADAR: Radar detect, [5210] 64 QAM rate
* @AR5K_RX_PHY_ERROR_SERVICE: Illegal service
* @AR5K_RX_PHY_ERROR_TOR: Transmit override receive
* @AR5K_RX_PHY_ERROR_OFDM_TIMING: OFDM Timing error [5212+]
* @AR5K_RX_PHY_ERROR_OFDM_SIGNAL_PARITY: OFDM Signal parity error [5212+]
* @AR5K_RX_PHY_ERROR_OFDM_RATE_ILLEGAL: OFDM Illegal rate [5212+]
* @AR5K_RX_PHY_ERROR_OFDM_LENGTH_ILLEGAL: OFDM Illegal length [5212+]
* @AR5K_RX_PHY_ERROR_OFDM_POWER_DROP: OFDM Power drop [5212+]
* @AR5K_RX_PHY_ERROR_OFDM_SERVICE: OFDM Service (?) [5212+]
* @AR5K_RX_PHY_ERROR_OFDM_RESTART: OFDM Restart (?) [5212+]
* @AR5K_RX_PHY_ERROR_CCK_TIMING: CCK Timing error [5212+]
* @AR5K_RX_PHY_ERROR_CCK_HEADER_CRC: Header CRC error [5212+]
* @AR5K_RX_PHY_ERROR_CCK_RATE_ILLEGAL: Illegal rate [5212+]
* @AR5K_RX_PHY_ERROR_CCK_SERVICE: CCK Service (?) [5212+]
* @AR5K_RX_PHY_ERROR_CCK_RESTART: CCK Restart (?) [5212+]
*/ */
enum ath5k_phy_error_code { enum ath5k_phy_error_code {
AR5K_RX_PHY_ERROR_UNDERRUN = 0, /* Transmit underrun, [5210] No error */ AR5K_RX_PHY_ERROR_UNDERRUN = 0,
AR5K_RX_PHY_ERROR_TIMING = 1, /* Timing error */ AR5K_RX_PHY_ERROR_TIMING = 1,
AR5K_RX_PHY_ERROR_PARITY = 2, /* Illegal parity */ AR5K_RX_PHY_ERROR_PARITY = 2,
AR5K_RX_PHY_ERROR_RATE = 3, /* Illegal rate */ AR5K_RX_PHY_ERROR_RATE = 3,
AR5K_RX_PHY_ERROR_LENGTH = 4, /* Illegal length */ AR5K_RX_PHY_ERROR_LENGTH = 4,
AR5K_RX_PHY_ERROR_RADAR = 5, /* Radar detect, [5210] 64 QAM rate */ AR5K_RX_PHY_ERROR_RADAR = 5,
AR5K_RX_PHY_ERROR_SERVICE = 6, /* Illegal service */ AR5K_RX_PHY_ERROR_SERVICE = 6,
AR5K_RX_PHY_ERROR_TOR = 7, /* Transmit override receive */ AR5K_RX_PHY_ERROR_TOR = 7,
/* these are specific to the 5212 */
AR5K_RX_PHY_ERROR_OFDM_TIMING = 17, AR5K_RX_PHY_ERROR_OFDM_TIMING = 17,
AR5K_RX_PHY_ERROR_OFDM_SIGNAL_PARITY = 18, AR5K_RX_PHY_ERROR_OFDM_SIGNAL_PARITY = 18,
AR5K_RX_PHY_ERROR_OFDM_RATE_ILLEGAL = 19, AR5K_RX_PHY_ERROR_OFDM_RATE_ILLEGAL = 19,
@ -123,12 +147,14 @@ enum ath5k_phy_error_code {
AR5K_RX_PHY_ERROR_CCK_RESTART = 31, AR5K_RX_PHY_ERROR_CCK_RESTART = 31,
}; };
/* /**
* 5210/5211 hardware 2-word TX control descriptor * struct ath5k_hw_2w_tx_ctl - 5210/5211 hardware 2-word TX control descriptor
* @tx_control_0: TX control word 0
* @tx_control_1: TX control word 1
*/ */
struct ath5k_hw_2w_tx_ctl { struct ath5k_hw_2w_tx_ctl {
u32 tx_control_0; /* TX control word 0 */ u32 tx_control_0;
u32 tx_control_1; /* TX control word 1 */ u32 tx_control_1;
} __packed __aligned(4); } __packed __aligned(4);
/* TX control word 0 fields/flags */ /* TX control word 0 fields/flags */
@ -177,14 +203,18 @@ struct ath5k_hw_2w_tx_ctl {
#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS 4 #define AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS 4
#define AR5K_AR5211_TX_DESC_FRAME_TYPE_PRESP 4 #define AR5K_AR5211_TX_DESC_FRAME_TYPE_PRESP 4
/* /**
* 5212 hardware 4-word TX control descriptor * struct ath5k_hw_4w_tx_ctl - 5212 hardware 4-word TX control descriptor
* @tx_control_0: TX control word 0
* @tx_control_1: TX control word 1
* @tx_control_2: TX control word 2
* @tx_control_3: TX control word 3
*/ */
struct ath5k_hw_4w_tx_ctl { struct ath5k_hw_4w_tx_ctl {
u32 tx_control_0; /* TX control word 0 */ u32 tx_control_0;
u32 tx_control_1; /* TX control word 1 */ u32 tx_control_1;
u32 tx_control_2; /* TX control word 2 */ u32 tx_control_2;
u32 tx_control_3; /* TX control word 3 */ u32 tx_control_3;
} __packed __aligned(4); } __packed __aligned(4);
/* TX control word 0 fields/flags */ /* TX control word 0 fields/flags */
@ -238,12 +268,14 @@ struct ath5k_hw_4w_tx_ctl {
#define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE 0x01f00000 /* RTS or CTS rate */ #define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE 0x01f00000 /* RTS or CTS rate */
#define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE_S 20 #define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE_S 20
/* /**
* Common TX status descriptor * struct ath5k_hw_tx_status - Common TX status descriptor
* @tx_status_0: TX status word 0
* @tx_status_1: TX status word 1
*/ */
struct ath5k_hw_tx_status { struct ath5k_hw_tx_status {
u32 tx_status_0; /* TX status word 0 */ u32 tx_status_0;
u32 tx_status_1; /* TX status word 1 */ u32 tx_status_1;
} __packed __aligned(4); } __packed __aligned(4);
/* TX status word 0 fields/flags */ /* TX status word 0 fields/flags */
@ -276,37 +308,47 @@ struct ath5k_hw_tx_status {
#define AR5K_DESC_TX_STATUS1_COMP_SUCCESS_5212 0x00800000 /* [5212] compression status */ #define AR5K_DESC_TX_STATUS1_COMP_SUCCESS_5212 0x00800000 /* [5212] compression status */
#define AR5K_DESC_TX_STATUS1_XMIT_ANTENNA_5212 0x01000000 /* [5212] transmit antenna */ #define AR5K_DESC_TX_STATUS1_XMIT_ANTENNA_5212 0x01000000 /* [5212] transmit antenna */
/* /**
* 5210/5211 hardware TX descriptor * struct ath5k_hw_5210_tx_desc - 5210/5211 hardware TX descriptor
* @tx_ctl: The &struct ath5k_hw_2w_tx_ctl
* @tx_stat: The &struct ath5k_hw_tx_status
*/ */
struct ath5k_hw_5210_tx_desc { struct ath5k_hw_5210_tx_desc {
struct ath5k_hw_2w_tx_ctl tx_ctl; struct ath5k_hw_2w_tx_ctl tx_ctl;
struct ath5k_hw_tx_status tx_stat; struct ath5k_hw_tx_status tx_stat;
} __packed __aligned(4); } __packed __aligned(4);
/* /**
* 5212 hardware TX descriptor * struct ath5k_hw_5212_tx_desc - 5212 hardware TX descriptor
* @tx_ctl: The &struct ath5k_hw_4w_tx_ctl
* @tx_stat: The &struct ath5k_hw_tx_status
*/ */
struct ath5k_hw_5212_tx_desc { struct ath5k_hw_5212_tx_desc {
struct ath5k_hw_4w_tx_ctl tx_ctl; struct ath5k_hw_4w_tx_ctl tx_ctl;
struct ath5k_hw_tx_status tx_stat; struct ath5k_hw_tx_status tx_stat;
} __packed __aligned(4); } __packed __aligned(4);
/* /**
* Common hardware RX descriptor * struct ath5k_hw_all_rx_desc - Common hardware RX descriptor
* @rx_ctl: The &struct ath5k_hw_rx_ctl
* @rx_stat: The &struct ath5k_hw_rx_status
*/ */
struct ath5k_hw_all_rx_desc { struct ath5k_hw_all_rx_desc {
struct ath5k_hw_rx_ctl rx_ctl; struct ath5k_hw_rx_ctl rx_ctl;
struct ath5k_hw_rx_status rx_stat; struct ath5k_hw_rx_status rx_stat;
} __packed __aligned(4); } __packed __aligned(4);
/* /**
* Atheros hardware DMA descriptor * struct ath5k_desc - Atheros hardware DMA descriptor
* @ds_link: Physical address of the next descriptor
* @ds_data: Physical address of data buffer (skb)
* @ud: Union containing hw_5xxx_tx_desc structs and hw_all_rx_desc
*
* This is read and written to by the hardware * This is read and written to by the hardware
*/ */
struct ath5k_desc { struct ath5k_desc {
u32 ds_link; /* physical address of the next descriptor */ u32 ds_link;
u32 ds_data; /* physical address of data buffer (skb) */ u32 ds_data;
union { union {
struct ath5k_hw_5210_tx_desc ds_tx5210; struct ath5k_hw_5210_tx_desc ds_tx5210;

View File

@ -20,16 +20,13 @@
* DMA and interrupt masking functions * * DMA and interrupt masking functions *
\*************************************/ \*************************************/
/* /**
* dma.c - DMA and interrupt masking functions * DOC: DMA and interrupt masking functions
* *
* Here we setup descriptor pointers (rxdp/txdp) start/stop dma engine and * Here we setup descriptor pointers (rxdp/txdp) start/stop dma engine and
* handle queue setup for 5210 chipset (rest are handled on qcu.c). * handle queue setup for 5210 chipset (rest are handled on qcu.c).
* Also we setup interrupt mask register (IMR) and read the various interrupt * Also we setup interrupt mask register (IMR) and read the various interrupt
* status registers (ISR). * status registers (ISR).
*
* TODO: Handle SISR on 5211+ and introduce a function to return the queue
* number that resulted the interrupt.
*/ */
#include "ath5k.h" #include "ath5k.h"
@ -42,22 +39,22 @@
\*********/ \*********/
/** /**
* ath5k_hw_start_rx_dma - Start DMA receive * ath5k_hw_start_rx_dma() - Start DMA receive
*
* @ah: The &struct ath5k_hw * @ah: The &struct ath5k_hw
*/ */
void ath5k_hw_start_rx_dma(struct ath5k_hw *ah) void
ath5k_hw_start_rx_dma(struct ath5k_hw *ah)
{ {
ath5k_hw_reg_write(ah, AR5K_CR_RXE, AR5K_CR); ath5k_hw_reg_write(ah, AR5K_CR_RXE, AR5K_CR);
ath5k_hw_reg_read(ah, AR5K_CR); ath5k_hw_reg_read(ah, AR5K_CR);
} }
/** /**
* ath5k_hw_stop_rx_dma - Stop DMA receive * ath5k_hw_stop_rx_dma() - Stop DMA receive
*
* @ah: The &struct ath5k_hw * @ah: The &struct ath5k_hw
*/ */
static int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah) static int
ath5k_hw_stop_rx_dma(struct ath5k_hw *ah)
{ {
unsigned int i; unsigned int i;
@ -79,24 +76,24 @@ static int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah)
} }
/** /**
* ath5k_hw_get_rxdp - Get RX Descriptor's address * ath5k_hw_get_rxdp() - Get RX Descriptor's address
*
* @ah: The &struct ath5k_hw * @ah: The &struct ath5k_hw
*/ */
u32 ath5k_hw_get_rxdp(struct ath5k_hw *ah) u32
ath5k_hw_get_rxdp(struct ath5k_hw *ah)
{ {
return ath5k_hw_reg_read(ah, AR5K_RXDP); return ath5k_hw_reg_read(ah, AR5K_RXDP);
} }
/** /**
* ath5k_hw_set_rxdp - Set RX Descriptor's address * ath5k_hw_set_rxdp() - Set RX Descriptor's address
*
* @ah: The &struct ath5k_hw * @ah: The &struct ath5k_hw
* @phys_addr: RX descriptor address * @phys_addr: RX descriptor address
* *
* Returns -EIO if rx is active * Returns -EIO if rx is active
*/ */
int ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr) int
ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr)
{ {
if (ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_CR_RXE) { if (ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_CR_RXE) {
ATH5K_DBG(ah, ATH5K_DEBUG_DMA, ATH5K_DBG(ah, ATH5K_DEBUG_DMA,
@ -114,8 +111,7 @@ int ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr)
\**********/ \**********/
/** /**
* ath5k_hw_start_tx_dma - Start DMA transmit for a specific queue * ath5k_hw_start_tx_dma() - Start DMA transmit for a specific queue
*
* @ah: The &struct ath5k_hw * @ah: The &struct ath5k_hw
* @queue: The hw queue number * @queue: The hw queue number
* *
@ -128,7 +124,8 @@ int ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr)
* NOTE: Must be called after setting up tx control descriptor for that * NOTE: Must be called after setting up tx control descriptor for that
* queue (see below). * queue (see below).
*/ */
int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue) int
ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue)
{ {
u32 tx_queue; u32 tx_queue;
@ -177,17 +174,16 @@ int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue)
} }
/** /**
* ath5k_hw_stop_tx_dma - Stop DMA transmit on a specific queue * ath5k_hw_stop_tx_dma() - Stop DMA transmit on a specific queue
*
* @ah: The &struct ath5k_hw * @ah: The &struct ath5k_hw
* @queue: The hw queue number * @queue: The hw queue number
* *
* Stop DMA transmit on a specific hw queue and drain queue so we don't * Stop DMA transmit on a specific hw queue and drain queue so we don't
* have any pending frames. Returns -EBUSY if we still have pending frames, * have any pending frames. Returns -EBUSY if we still have pending frames,
* -EINVAL if queue number is out of range or inactive. * -EINVAL if queue number is out of range or inactive.
*
*/ */
static int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue) static int
ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
{ {
unsigned int i = 40; unsigned int i = 40;
u32 tx_queue, pending; u32 tx_queue, pending;
@ -320,14 +316,14 @@ static int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
} }
/** /**
* ath5k_hw_stop_beacon_queue - Stop beacon queue * ath5k_hw_stop_beacon_queue() - Stop beacon queue
* * @ah: The &struct ath5k_hw
* @ah The &struct ath5k_hw * @queue: The queue number
* @queue The queue number
* *
* Returns -EIO if queue didn't stop * Returns -EIO if queue didn't stop
*/ */
int ath5k_hw_stop_beacon_queue(struct ath5k_hw *ah, unsigned int queue) int
ath5k_hw_stop_beacon_queue(struct ath5k_hw *ah, unsigned int queue)
{ {
int ret; int ret;
ret = ath5k_hw_stop_tx_dma(ah, queue); ret = ath5k_hw_stop_tx_dma(ah, queue);
@ -340,8 +336,7 @@ int ath5k_hw_stop_beacon_queue(struct ath5k_hw *ah, unsigned int queue)
} }
/** /**
* ath5k_hw_get_txdp - Get TX Descriptor's address for a specific queue * ath5k_hw_get_txdp() - Get TX Descriptor's address for a specific queue
*
* @ah: The &struct ath5k_hw * @ah: The &struct ath5k_hw
* @queue: The hw queue number * @queue: The hw queue number
* *
@ -352,7 +347,8 @@ int ath5k_hw_stop_beacon_queue(struct ath5k_hw *ah, unsigned int queue)
* *
* XXX: Is TXDP read and clear ? * XXX: Is TXDP read and clear ?
*/ */
u32 ath5k_hw_get_txdp(struct ath5k_hw *ah, unsigned int queue) u32
ath5k_hw_get_txdp(struct ath5k_hw *ah, unsigned int queue)
{ {
u16 tx_reg; u16 tx_reg;
@ -382,10 +378,10 @@ u32 ath5k_hw_get_txdp(struct ath5k_hw *ah, unsigned int queue)
} }
/** /**
* ath5k_hw_set_txdp - Set TX Descriptor's address for a specific queue * ath5k_hw_set_txdp() - Set TX Descriptor's address for a specific queue
*
* @ah: The &struct ath5k_hw * @ah: The &struct ath5k_hw
* @queue: The hw queue number * @queue: The hw queue number
* @phys_addr: The physical address
* *
* Set TX descriptor's address for a specific queue. For 5210 we ignore * Set TX descriptor's address for a specific queue. For 5210 we ignore
* the queue number and we use tx queue type since we only have 2 queues * the queue number and we use tx queue type since we only have 2 queues
@ -394,7 +390,8 @@ u32 ath5k_hw_get_txdp(struct ath5k_hw *ah, unsigned int queue)
* Returns -EINVAL if queue type is invalid for 5210 and -EIO if queue is still * Returns -EINVAL if queue type is invalid for 5210 and -EIO if queue is still
* active. * active.
*/ */
int ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr) int
ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr)
{ {
u16 tx_reg; u16 tx_reg;
@ -435,8 +432,7 @@ int ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr)
} }
/** /**
* ath5k_hw_update_tx_triglevel - Update tx trigger level * ath5k_hw_update_tx_triglevel() - Update tx trigger level
*
* @ah: The &struct ath5k_hw * @ah: The &struct ath5k_hw
* @increase: Flag to force increase of trigger level * @increase: Flag to force increase of trigger level
* *
@ -444,15 +440,15 @@ int ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr)
* buffer (aka FIFO threshold) that is used to indicate when PCU flushes * buffer (aka FIFO threshold) that is used to indicate when PCU flushes
* the buffer and transmits its data. Lowering this results sending small * the buffer and transmits its data. Lowering this results sending small
* frames more quickly but can lead to tx underruns, raising it a lot can * frames more quickly but can lead to tx underruns, raising it a lot can
* result other problems (i think bmiss is related). Right now we start with * result other problems. Right now we start with the lowest possible
* the lowest possible (64Bytes) and if we get tx underrun we increase it using * (64Bytes) and if we get tx underrun we increase it using the increase
* the increase flag. Returns -EIO if we have reached maximum/minimum. * flag. Returns -EIO if we have reached maximum/minimum.
* *
* XXX: Link this with tx DMA size ? * XXX: Link this with tx DMA size ?
* XXX: Use it to save interrupts ? * XXX2: Use it to save interrupts ?
* TODO: Needs testing, i think it's related to bmiss...
*/ */
int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase) int
ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase)
{ {
u32 trigger_level, imr; u32 trigger_level, imr;
int ret = -EIO; int ret = -EIO;
@ -498,21 +494,20 @@ int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase)
\*******************/ \*******************/
/** /**
* ath5k_hw_is_intr_pending - Check if we have pending interrupts * ath5k_hw_is_intr_pending() - Check if we have pending interrupts
*
* @ah: The &struct ath5k_hw * @ah: The &struct ath5k_hw
* *
* Check if we have pending interrupts to process. Returns 1 if we * Check if we have pending interrupts to process. Returns 1 if we
* have pending interrupts and 0 if we haven't. * have pending interrupts and 0 if we haven't.
*/ */
bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah) bool
ath5k_hw_is_intr_pending(struct ath5k_hw *ah)
{ {
return ath5k_hw_reg_read(ah, AR5K_INTPEND) == 1 ? 1 : 0; return ath5k_hw_reg_read(ah, AR5K_INTPEND) == 1 ? 1 : 0;
} }
/** /**
* ath5k_hw_get_isr - Get interrupt status * ath5k_hw_get_isr() - Get interrupt status
*
* @ah: The @struct ath5k_hw * @ah: The @struct ath5k_hw
* @interrupt_mask: Driver's interrupt mask used to filter out * @interrupt_mask: Driver's interrupt mask used to filter out
* interrupts in sw. * interrupts in sw.
@ -523,62 +518,162 @@ bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah)
* being mapped on some standard non hw-specific positions * being mapped on some standard non hw-specific positions
* (check out &ath5k_int). * (check out &ath5k_int).
* *
* NOTE: We use read-and-clear register, so after this function is called ISR * NOTE: We do write-to-clear, so the active PISR/SISR bits at the time this
* is zeroed. * function gets called are cleared on return.
*/ */
int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask) int
ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask)
{ {
u32 data; u32 data = 0;
/* /*
* Read interrupt status from the Interrupt Status register * Read interrupt status from Primary Interrupt
* on 5210 * Register.
*
* Note: PISR/SISR Not available on 5210
*/ */
if (ah->ah_version == AR5K_AR5210) { if (ah->ah_version == AR5K_AR5210) {
data = ath5k_hw_reg_read(ah, AR5K_ISR); u32 isr = 0;
if (unlikely(data == AR5K_INT_NOCARD)) { isr = ath5k_hw_reg_read(ah, AR5K_ISR);
*interrupt_mask = data; if (unlikely(isr == AR5K_INT_NOCARD)) {
*interrupt_mask = isr;
return -ENODEV; return -ENODEV;
} }
} else {
/* /*
* Read interrupt status from Interrupt * Filter out the non-common bits from the interrupt
* Status Register shadow copy (Read And Clear) * status.
*
* Note: PISR/SISR Not available on 5210
*/ */
data = ath5k_hw_reg_read(ah, AR5K_RAC_PISR); *interrupt_mask = (isr & AR5K_INT_COMMON) & ah->ah_imr;
if (unlikely(data == AR5K_INT_NOCARD)) {
*interrupt_mask = data; /* Hanlde INT_FATAL */
if (unlikely(isr & (AR5K_ISR_SSERR | AR5K_ISR_MCABT
| AR5K_ISR_DPERR)))
*interrupt_mask |= AR5K_INT_FATAL;
/*
* XXX: BMISS interrupts may occur after association.
* I found this on 5210 code but it needs testing. If this is
* true we should disable them before assoc and re-enable them
* after a successful assoc + some jiffies.
interrupt_mask &= ~AR5K_INT_BMISS;
*/
data = isr;
} else {
u32 pisr = 0;
u32 pisr_clear = 0;
u32 sisr0 = 0;
u32 sisr1 = 0;
u32 sisr2 = 0;
u32 sisr3 = 0;
u32 sisr4 = 0;
/* Read PISR and SISRs... */
pisr = ath5k_hw_reg_read(ah, AR5K_PISR);
if (unlikely(pisr == AR5K_INT_NOCARD)) {
*interrupt_mask = pisr;
return -ENODEV; return -ENODEV;
} }
}
/* sisr0 = ath5k_hw_reg_read(ah, AR5K_SISR0);
* Get abstract interrupt mask (driver-compatible) sisr1 = ath5k_hw_reg_read(ah, AR5K_SISR1);
*/ sisr2 = ath5k_hw_reg_read(ah, AR5K_SISR2);
*interrupt_mask = (data & AR5K_INT_COMMON) & ah->ah_imr; sisr3 = ath5k_hw_reg_read(ah, AR5K_SISR3);
sisr4 = ath5k_hw_reg_read(ah, AR5K_SISR4);
if (ah->ah_version != AR5K_AR5210) { /*
u32 sisr2 = ath5k_hw_reg_read(ah, AR5K_RAC_SISR2); * PISR holds the logical OR of interrupt bits
* from SISR registers:
*
* TXOK and TXDESC -> Logical OR of TXOK and TXDESC
* per-queue bits on SISR0
*
* TXERR and TXEOL -> Logical OR of TXERR and TXEOL
* per-queue bits on SISR1
*
* TXURN -> Logical OR of TXURN per-queue bits on SISR2
*
* HIUERR -> Logical OR of MCABT, SSERR and DPER bits on SISR2
*
* BCNMISC -> Logical OR of TIM, CAB_END, DTIM_SYNC
* BCN_TIMEOUT, CAB_TIMEOUT and DTIM
* (and TSFOOR ?) bits on SISR2
*
* QCBRORN and QCBRURN -> Logical OR of QCBRORN and
* QCBRURN per-queue bits on SISR3
* QTRIG -> Logical OR of QTRIG per-queue bits on SISR4
*
* If we clean these bits on PISR we 'll also clear all
* related bits from SISRs, e.g. if we write the TXOK bit on
* PISR we 'll clean all TXOK bits from SISR0 so if a new TXOK
* interrupt got fired for another queue while we were reading
* the interrupt registers and we write back the TXOK bit on
* PISR we 'll lose it. So make sure that we don't write back
* on PISR any bits that come from SISRs. Clearing them from
* SISRs will also clear PISR so no need to worry here.
*/
/*HIU = Host Interface Unit (PCI etc)*/ pisr_clear = pisr & ~AR5K_ISR_BITS_FROM_SISRS;
if (unlikely(data & (AR5K_ISR_HIUERR)))
*interrupt_mask |= AR5K_INT_FATAL;
/*Beacon Not Ready*/ /*
if (unlikely(data & (AR5K_ISR_BNR))) * Write to clear them...
*interrupt_mask |= AR5K_INT_BNR; * Note: This means that each bit we write back
* to the registers will get cleared, leaving the
* rest unaffected. So this won't affect new interrupts
* we didn't catch while reading/processing, we 'll get
* them next time get_isr gets called.
*/
ath5k_hw_reg_write(ah, sisr0, AR5K_SISR0);
ath5k_hw_reg_write(ah, sisr1, AR5K_SISR1);
ath5k_hw_reg_write(ah, sisr2, AR5K_SISR2);
ath5k_hw_reg_write(ah, sisr3, AR5K_SISR3);
ath5k_hw_reg_write(ah, sisr4, AR5K_SISR4);
ath5k_hw_reg_write(ah, pisr_clear, AR5K_PISR);
/* Flush previous write */
ath5k_hw_reg_read(ah, AR5K_PISR);
if (unlikely(sisr2 & (AR5K_SISR2_SSERR | /*
AR5K_SISR2_DPERR | * Filter out the non-common bits from the interrupt
AR5K_SISR2_MCABT))) * status.
*interrupt_mask |= AR5K_INT_FATAL; */
*interrupt_mask = (pisr & AR5K_INT_COMMON) & ah->ah_imr;
if (data & AR5K_ISR_TIM)
/* We treat TXOK,TXDESC, TXERR and TXEOL
* the same way (schedule the tx tasklet)
* so we track them all together per queue */
if (pisr & AR5K_ISR_TXOK)
ah->ah_txq_isr_txok_all |= AR5K_REG_MS(sisr0,
AR5K_SISR0_QCU_TXOK);
if (pisr & AR5K_ISR_TXDESC)
ah->ah_txq_isr_txok_all |= AR5K_REG_MS(sisr0,
AR5K_SISR0_QCU_TXDESC);
if (pisr & AR5K_ISR_TXERR)
ah->ah_txq_isr_txok_all |= AR5K_REG_MS(sisr1,
AR5K_SISR1_QCU_TXERR);
if (pisr & AR5K_ISR_TXEOL)
ah->ah_txq_isr_txok_all |= AR5K_REG_MS(sisr1,
AR5K_SISR1_QCU_TXEOL);
/* Currently this is not much usefull since we treat
* all queues the same way if we get a TXURN (update
* tx trigger level) but we might need it later on*/
if (pisr & AR5K_ISR_TXURN)
ah->ah_txq_isr_txurn |= AR5K_REG_MS(sisr2,
AR5K_SISR2_QCU_TXURN);
/* Misc Beacon related interrupts */
/* For AR5211 */
if (pisr & AR5K_ISR_TIM)
*interrupt_mask |= AR5K_INT_TIM; *interrupt_mask |= AR5K_INT_TIM;
if (data & AR5K_ISR_BCNMISC) { /* For AR5212+ */
if (pisr & AR5K_ISR_BCNMISC) {
if (sisr2 & AR5K_SISR2_TIM) if (sisr2 & AR5K_SISR2_TIM)
*interrupt_mask |= AR5K_INT_TIM; *interrupt_mask |= AR5K_INT_TIM;
if (sisr2 & AR5K_SISR2_DTIM) if (sisr2 & AR5K_SISR2_DTIM)
@ -591,63 +686,39 @@ int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask)
*interrupt_mask |= AR5K_INT_CAB_TIMEOUT; *interrupt_mask |= AR5K_INT_CAB_TIMEOUT;
} }
if (data & AR5K_ISR_RXDOPPLER) /* Below interrupts are unlikely to happen */
*interrupt_mask |= AR5K_INT_RX_DOPPLER;
if (data & AR5K_ISR_QCBRORN) {
*interrupt_mask |= AR5K_INT_QCBRORN;
ah->ah_txq_isr |= AR5K_REG_MS(
ath5k_hw_reg_read(ah, AR5K_RAC_SISR3),
AR5K_SISR3_QCBRORN);
}
if (data & AR5K_ISR_QCBRURN) {
*interrupt_mask |= AR5K_INT_QCBRURN;
ah->ah_txq_isr |= AR5K_REG_MS(
ath5k_hw_reg_read(ah, AR5K_RAC_SISR3),
AR5K_SISR3_QCBRURN);
}
if (data & AR5K_ISR_QTRIG) {
*interrupt_mask |= AR5K_INT_QTRIG;
ah->ah_txq_isr |= AR5K_REG_MS(
ath5k_hw_reg_read(ah, AR5K_RAC_SISR4),
AR5K_SISR4_QTRIG);
}
if (data & AR5K_ISR_TXOK) /* HIU = Host Interface Unit (PCI etc)
ah->ah_txq_isr |= AR5K_REG_MS( * Can be one of MCABT, SSERR, DPERR from SISR2 */
ath5k_hw_reg_read(ah, AR5K_RAC_SISR0), if (unlikely(pisr & (AR5K_ISR_HIUERR)))
AR5K_SISR0_QCU_TXOK);
if (data & AR5K_ISR_TXDESC)
ah->ah_txq_isr |= AR5K_REG_MS(
ath5k_hw_reg_read(ah, AR5K_RAC_SISR0),
AR5K_SISR0_QCU_TXDESC);
if (data & AR5K_ISR_TXERR)
ah->ah_txq_isr |= AR5K_REG_MS(
ath5k_hw_reg_read(ah, AR5K_RAC_SISR1),
AR5K_SISR1_QCU_TXERR);
if (data & AR5K_ISR_TXEOL)
ah->ah_txq_isr |= AR5K_REG_MS(
ath5k_hw_reg_read(ah, AR5K_RAC_SISR1),
AR5K_SISR1_QCU_TXEOL);
if (data & AR5K_ISR_TXURN)
ah->ah_txq_isr |= AR5K_REG_MS(
ath5k_hw_reg_read(ah, AR5K_RAC_SISR2),
AR5K_SISR2_QCU_TXURN);
} else {
if (unlikely(data & (AR5K_ISR_SSERR | AR5K_ISR_MCABT
| AR5K_ISR_HIUERR | AR5K_ISR_DPERR)))
*interrupt_mask |= AR5K_INT_FATAL; *interrupt_mask |= AR5K_INT_FATAL;
/* /*Beacon Not Ready*/
* XXX: BMISS interrupts may occur after association. if (unlikely(pisr & (AR5K_ISR_BNR)))
* I found this on 5210 code but it needs testing. If this is *interrupt_mask |= AR5K_INT_BNR;
* true we should disable them before assoc and re-enable them
* after a successful assoc + some jiffies. /* A queue got CBR overrun */
interrupt_mask &= ~AR5K_INT_BMISS; if (unlikely(pisr & (AR5K_ISR_QCBRORN))) {
*/ *interrupt_mask |= AR5K_INT_QCBRORN;
ah->ah_txq_isr_qcborn |= AR5K_REG_MS(sisr3,
AR5K_SISR3_QCBRORN);
}
/* A queue got CBR underrun */
if (unlikely(pisr & (AR5K_ISR_QCBRURN))) {
*interrupt_mask |= AR5K_INT_QCBRURN;
ah->ah_txq_isr_qcburn |= AR5K_REG_MS(sisr3,
AR5K_SISR3_QCBRURN);
}
/* A queue got triggered */
if (unlikely(pisr & (AR5K_ISR_QTRIG))) {
*interrupt_mask |= AR5K_INT_QTRIG;
ah->ah_txq_isr_qtrig |= AR5K_REG_MS(sisr4,
AR5K_SISR4_QTRIG);
}
data = pisr;
} }
/* /*
@ -661,8 +732,7 @@ int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask)
} }
/** /**
* ath5k_hw_set_imr - Set interrupt mask * ath5k_hw_set_imr() - Set interrupt mask
*
* @ah: The &struct ath5k_hw * @ah: The &struct ath5k_hw
* @new_mask: The new interrupt mask to be set * @new_mask: The new interrupt mask to be set
* *
@ -670,7 +740,8 @@ int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask)
* ath5k_int bits to hw-specific bits to remove abstraction and writing * ath5k_int bits to hw-specific bits to remove abstraction and writing
* Interrupt Mask Register. * Interrupt Mask Register.
*/ */
enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask) enum ath5k_int
ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask)
{ {
enum ath5k_int old_mask, int_mask; enum ath5k_int old_mask, int_mask;
@ -697,16 +768,14 @@ enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask)
u32 simr2 = ath5k_hw_reg_read(ah, AR5K_SIMR2) u32 simr2 = ath5k_hw_reg_read(ah, AR5K_SIMR2)
& AR5K_SIMR2_QCU_TXURN; & AR5K_SIMR2_QCU_TXURN;
/* Fatal interrupt abstraction for 5211+ */
if (new_mask & AR5K_INT_FATAL) { if (new_mask & AR5K_INT_FATAL) {
int_mask |= AR5K_IMR_HIUERR; int_mask |= AR5K_IMR_HIUERR;
simr2 |= (AR5K_SIMR2_MCABT | AR5K_SIMR2_SSERR simr2 |= (AR5K_SIMR2_MCABT | AR5K_SIMR2_SSERR
| AR5K_SIMR2_DPERR); | AR5K_SIMR2_DPERR);
} }
/*Beacon Not Ready*/ /* Misc beacon related interrupts */
if (new_mask & AR5K_INT_BNR)
int_mask |= AR5K_INT_BNR;
if (new_mask & AR5K_INT_TIM) if (new_mask & AR5K_INT_TIM)
int_mask |= AR5K_IMR_TIM; int_mask |= AR5K_IMR_TIM;
@ -721,8 +790,9 @@ enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask)
if (new_mask & AR5K_INT_CAB_TIMEOUT) if (new_mask & AR5K_INT_CAB_TIMEOUT)
simr2 |= AR5K_SISR2_CAB_TIMEOUT; simr2 |= AR5K_SISR2_CAB_TIMEOUT;
if (new_mask & AR5K_INT_RX_DOPPLER) /*Beacon Not Ready*/
int_mask |= AR5K_IMR_RXDOPPLER; if (new_mask & AR5K_INT_BNR)
int_mask |= AR5K_INT_BNR;
/* Note: Per queue interrupt masks /* Note: Per queue interrupt masks
* are set via ath5k_hw_reset_tx_queue() (qcu.c) */ * are set via ath5k_hw_reset_tx_queue() (qcu.c) */
@ -730,10 +800,12 @@ enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask)
ath5k_hw_reg_write(ah, simr2, AR5K_SIMR2); ath5k_hw_reg_write(ah, simr2, AR5K_SIMR2);
} else { } else {
/* Fatal interrupt abstraction for 5210 */
if (new_mask & AR5K_INT_FATAL) if (new_mask & AR5K_INT_FATAL)
int_mask |= (AR5K_IMR_SSERR | AR5K_IMR_MCABT int_mask |= (AR5K_IMR_SSERR | AR5K_IMR_MCABT
| AR5K_IMR_HIUERR | AR5K_IMR_DPERR); | AR5K_IMR_HIUERR | AR5K_IMR_DPERR);
/* Only common interrupts left for 5210 (no SIMRs) */
ath5k_hw_reg_write(ah, int_mask, AR5K_IMR); ath5k_hw_reg_write(ah, int_mask, AR5K_IMR);
} }
@ -760,8 +832,7 @@ enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask)
\********************/ \********************/
/** /**
* ath5k_hw_dma_init - Initialize DMA unit * ath5k_hw_dma_init() - Initialize DMA unit
*
* @ah: The &struct ath5k_hw * @ah: The &struct ath5k_hw
* *
* Set DMA size and pre-enable interrupts * Set DMA size and pre-enable interrupts
@ -770,7 +841,8 @@ enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask)
* *
* XXX: Save/restore RXDP/TXDP registers ? * XXX: Save/restore RXDP/TXDP registers ?
*/ */
void ath5k_hw_dma_init(struct ath5k_hw *ah) void
ath5k_hw_dma_init(struct ath5k_hw *ah)
{ {
/* /*
* Set Rx/Tx DMA Configuration * Set Rx/Tx DMA Configuration
@ -799,8 +871,7 @@ void ath5k_hw_dma_init(struct ath5k_hw *ah)
} }
/** /**
* ath5k_hw_dma_stop - stop DMA unit * ath5k_hw_dma_stop() - stop DMA unit
*
* @ah: The &struct ath5k_hw * @ah: The &struct ath5k_hw
* *
* Stop tx/rx DMA and interrupts. Returns * Stop tx/rx DMA and interrupts. Returns
@ -810,7 +881,8 @@ void ath5k_hw_dma_init(struct ath5k_hw *ah)
* stuck frames on tx queues, only a reset * stuck frames on tx queues, only a reset
* can fix that. * can fix that.
*/ */
int ath5k_hw_dma_stop(struct ath5k_hw *ah) int
ath5k_hw_dma_stop(struct ath5k_hw *ah)
{ {
int i, qmax, err; int i, qmax, err;
err = 0; err = 0;

View File

@ -24,10 +24,33 @@
#include "reg.h" #include "reg.h"
#include "debug.h" #include "debug.h"
/*
* Set led state /**
* DOC: GPIO/LED functions
*
* Here we control the 6 bidirectional GPIO pins provided by the hw.
* We can set a GPIO pin to be an input or an output pin on GPIO control
* register and then read or set its status from GPIO data input/output
* registers.
*
* We also control the two LED pins provided by the hw, LED_0 is our
* "power" LED and LED_1 is our "network activity" LED but many scenarios
* are available from hw. Vendors might also provide LEDs connected to the
* GPIO pins, we handle them through the LED subsystem on led.c
*/ */
void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state)
/**
* ath5k_hw_set_ledstate() - Set led state
* @ah: The &struct ath5k_hw
* @state: One of AR5K_LED_*
*
* Used to set the LED blinking state. This only
* works for the LED connected to the LED_0, LED_1 pins,
* not the GPIO based.
*/
void
ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state)
{ {
u32 led; u32 led;
/*5210 has different led mode handling*/ /*5210 has different led mode handling*/
@ -74,10 +97,13 @@ void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state)
AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, led_5210); AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, led_5210);
} }
/* /**
* Set GPIO inputs * ath5k_hw_set_gpio_input() - Set GPIO inputs
* @ah: The &struct ath5k_hw
* @gpio: GPIO pin to set as input
*/ */
int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio) int
ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio)
{ {
if (gpio >= AR5K_NUM_GPIO) if (gpio >= AR5K_NUM_GPIO)
return -EINVAL; return -EINVAL;
@ -89,10 +115,13 @@ int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio)
return 0; return 0;
} }
/* /**
* Set GPIO outputs * ath5k_hw_set_gpio_output() - Set GPIO outputs
* @ah: The &struct ath5k_hw
* @gpio: The GPIO pin to set as output
*/ */
int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio) int
ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio)
{ {
if (gpio >= AR5K_NUM_GPIO) if (gpio >= AR5K_NUM_GPIO)
return -EINVAL; return -EINVAL;
@ -104,10 +133,13 @@ int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio)
return 0; return 0;
} }
/* /**
* Get GPIO state * ath5k_hw_get_gpio() - Get GPIO state
* @ah: The &struct ath5k_hw
* @gpio: The GPIO pin to read
*/ */
u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio) u32
ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio)
{ {
if (gpio >= AR5K_NUM_GPIO) if (gpio >= AR5K_NUM_GPIO)
return 0xffffffff; return 0xffffffff;
@ -117,10 +149,14 @@ u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio)
0x1; 0x1;
} }
/* /**
* Set GPIO state * ath5k_hw_set_gpio() - Set GPIO state
* @ah: The &struct ath5k_hw
* @gpio: The GPIO pin to set
* @val: Value to set (boolean)
*/ */
int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val) int
ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val)
{ {
u32 data; u32 data;
@ -138,10 +174,19 @@ int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val)
return 0; return 0;
} }
/* /**
* Initialize the GPIO interrupt (RFKill switch) * ath5k_hw_set_gpio_intr() - Initialize the GPIO interrupt (RFKill switch)
* @ah: The &struct ath5k_hw
* @gpio: The GPIO pin to use
* @interrupt_level: True to generate interrupt on active pin (high)
*
* This function is used to set up the GPIO interrupt for the hw RFKill switch.
* That switch is connected to a GPIO pin and it's number is stored on EEPROM.
* It can either open or close the circuit to indicate that we should disable
* RF/Wireless to save power (we also get that from EEPROM).
*/ */
void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio, void
ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio,
u32 interrupt_level) u32 interrupt_level)
{ {
u32 data; u32 data;

View File

@ -23,24 +23,27 @@
#include "reg.h" #include "reg.h"
#include "debug.h" #include "debug.h"
/* /**
* Mode-independent initial register writes * struct ath5k_ini - Mode-independent initial register writes
* @ini_register: Register address
* @ini_value: Default value
* @ini_mode: 0 to write 1 to read (and clear)
*/ */
struct ath5k_ini { struct ath5k_ini {
u16 ini_register; u16 ini_register;
u32 ini_value; u32 ini_value;
enum { enum {
AR5K_INI_WRITE = 0, /* Default */ AR5K_INI_WRITE = 0, /* Default */
AR5K_INI_READ = 1, /* Cleared on read */ AR5K_INI_READ = 1,
} ini_mode; } ini_mode;
}; };
/* /**
* Mode specific initial register values * struct ath5k_ini_mode - Mode specific initial register values
* @mode_register: Register address
* @mode_value: Set of values for each enum ath5k_driver_mode
*/ */
struct ath5k_ini_mode { struct ath5k_ini_mode {
u16 mode_register; u16 mode_register;
u32 mode_value[3]; u32 mode_value[3];
@ -386,11 +389,10 @@ static const struct ath5k_ini ar5211_ini[] = {
/* Initial mode-specific settings for AR5211 /* Initial mode-specific settings for AR5211
* 5211 supports OFDM-only g (draft g) but we * 5211 supports OFDM-only g (draft g) but we
* need to test it ! * need to test it ! */
*/
static const struct ath5k_ini_mode ar5211_ini_mode[] = { static const struct ath5k_ini_mode ar5211_ini_mode[] = {
{ AR5K_TXCFG, { AR5K_TXCFG,
/* A/XR B G */ /* A B G */
{ 0x00000015, 0x0000001d, 0x00000015 } }, { 0x00000015, 0x0000001d, 0x00000015 } },
{ AR5K_QUEUE_DFS_LOCAL_IFS(0), { AR5K_QUEUE_DFS_LOCAL_IFS(0),
{ 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } }, { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
@ -460,7 +462,7 @@ static const struct ath5k_ini_mode ar5211_ini_mode[] = {
{ 0x00000010, 0x00000010, 0x00000010 } }, { 0x00000010, 0x00000010, 0x00000010 } },
}; };
/* Initial register settings for AR5212 */ /* Initial register settings for AR5212 and newer chips */
static const struct ath5k_ini ar5212_ini_common_start[] = { static const struct ath5k_ini ar5212_ini_common_start[] = {
{ AR5K_RXDP, 0x00000000 }, { AR5K_RXDP, 0x00000000 },
{ AR5K_RXCFG, 0x00000005 }, { AR5K_RXCFG, 0x00000005 },
@ -724,7 +726,8 @@ static const struct ath5k_ini_mode ar5212_ini_mode_start[] = {
{ 0x00000000, 0x00000000, 0x00000108 } }, { 0x00000000, 0x00000000, 0x00000108 } },
}; };
/* Initial mode-specific settings for AR5212 + RF5111 (Written after ar5212_ini) */ /* Initial mode-specific settings for AR5212 + RF5111
* (Written after ar5212_ini) */
static const struct ath5k_ini_mode rf5111_ini_mode_end[] = { static const struct ath5k_ini_mode rf5111_ini_mode_end[] = {
{ AR5K_TXCFG, { AR5K_TXCFG,
/* A/XR B G */ /* A/XR B G */
@ -757,6 +760,7 @@ static const struct ath5k_ini_mode rf5111_ini_mode_end[] = {
{ 0x1883800a, 0x1873800a, 0x1883800a } }, { 0x1883800a, 0x1873800a, 0x1883800a } },
}; };
/* Common for all modes */
static const struct ath5k_ini rf5111_ini_common_end[] = { static const struct ath5k_ini rf5111_ini_common_end[] = {
{ AR5K_DCU_FP, 0x00000000 }, { AR5K_DCU_FP, 0x00000000 },
{ AR5K_PHY_AGC, 0x00000000 }, { AR5K_PHY_AGC, 0x00000000 },
@ -774,7 +778,9 @@ static const struct ath5k_ini rf5111_ini_common_end[] = {
{ 0xa23c, 0x13c889af }, { 0xa23c, 0x13c889af },
}; };
/* Initial mode-specific settings for AR5212 + RF5112 (Written after ar5212_ini) */
/* Initial mode-specific settings for AR5212 + RF5112
* (Written after ar5212_ini) */
static const struct ath5k_ini_mode rf5112_ini_mode_end[] = { static const struct ath5k_ini_mode rf5112_ini_mode_end[] = {
{ AR5K_TXCFG, { AR5K_TXCFG,
/* A/XR B G */ /* A/XR B G */
@ -825,7 +831,9 @@ static const struct ath5k_ini rf5112_ini_common_end[] = {
{ 0xa23c, 0x13c889af }, { 0xa23c, 0x13c889af },
}; };
/* Initial mode-specific settings for RF5413/5414 (Written after ar5212_ini) */
/* Initial mode-specific settings for RF5413/5414
* (Written after ar5212_ini) */
static const struct ath5k_ini_mode rf5413_ini_mode_end[] = { static const struct ath5k_ini_mode rf5413_ini_mode_end[] = {
{ AR5K_TXCFG, { AR5K_TXCFG,
/* A/XR B G */ /* A/XR B G */
@ -963,7 +971,8 @@ static const struct ath5k_ini rf5413_ini_common_end[] = {
{ 0xa384, 0xf3307ff0 }, { 0xa384, 0xf3307ff0 },
}; };
/* Initial mode-specific settings for RF2413/2414 (Written after ar5212_ini) */ /* Initial mode-specific settings for RF2413/2414
* (Written after ar5212_ini) */
/* XXX: a mode ? */ /* XXX: a mode ? */
static const struct ath5k_ini_mode rf2413_ini_mode_end[] = { static const struct ath5k_ini_mode rf2413_ini_mode_end[] = {
{ AR5K_TXCFG, { AR5K_TXCFG,
@ -1085,7 +1094,8 @@ static const struct ath5k_ini rf2413_ini_common_end[] = {
{ 0xa384, 0xf3307ff0 }, { 0xa384, 0xf3307ff0 },
}; };
/* Initial mode-specific settings for RF2425 (Written after ar5212_ini) */ /* Initial mode-specific settings for RF2425
* (Written after ar5212_ini) */
/* XXX: a mode ? */ /* XXX: a mode ? */
static const struct ath5k_ini_mode rf2425_ini_mode_end[] = { static const struct ath5k_ini_mode rf2425_ini_mode_end[] = {
{ AR5K_TXCFG, { AR5K_TXCFG,
@ -1357,10 +1367,15 @@ static const struct ath5k_ini rf5112_ini_bbgain[] = {
}; };
/* /**
* Write initial register dump * ath5k_hw_ini_registers() - Write initial register dump common for all modes
* @ah: The &struct ath5k_hw
* @size: Dump size
* @ini_regs: The array of &struct ath5k_ini
* @skip_pcu: Skip PCU registers
*/ */
static void ath5k_hw_ini_registers(struct ath5k_hw *ah, unsigned int size, static void
ath5k_hw_ini_registers(struct ath5k_hw *ah, unsigned int size,
const struct ath5k_ini *ini_regs, bool skip_pcu) const struct ath5k_ini *ini_regs, bool skip_pcu)
{ {
unsigned int i; unsigned int i;
@ -1388,7 +1403,15 @@ static void ath5k_hw_ini_registers(struct ath5k_hw *ah, unsigned int size,
} }
} }
static void ath5k_hw_ini_mode_registers(struct ath5k_hw *ah, /**
* ath5k_hw_ini_mode_registers() - Write initial mode-specific register dump
* @ah: The &struct ath5k_hw
* @size: Dump size
* @ini_mode: The array of &struct ath5k_ini_mode
* @mode: One of enum ath5k_driver_mode
*/
static void
ath5k_hw_ini_mode_registers(struct ath5k_hw *ah,
unsigned int size, const struct ath5k_ini_mode *ini_mode, unsigned int size, const struct ath5k_ini_mode *ini_mode,
u8 mode) u8 mode)
{ {
@ -1402,7 +1425,17 @@ static void ath5k_hw_ini_mode_registers(struct ath5k_hw *ah,
} }
int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool skip_pcu) /**
* ath5k_hw_write_initvals() - Write initial chip-specific register dump
* @ah: The &struct ath5k_hw
* @mode: One of enum ath5k_driver_mode
* @skip_pcu: Skip PCU registers
*
* Write initial chip-specific register dump, to get the chipset on a
* clean and ready-to-work state after warm reset.
*/
int
ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool skip_pcu)
{ {
/* /*
* Write initial register settings * Write initial register settings

View File

@ -98,7 +98,7 @@ ath5k_pci_eeprom_read(struct ath_common *common, u32 offset, u16 *data)
0xffff); 0xffff);
return true; return true;
} }
udelay(15); usleep_range(15, 20);
} }
return false; return false;

View File

@ -30,11 +30,47 @@
#include "reg.h" #include "reg.h"
#include "debug.h" #include "debug.h"
/* /**
* DOC: Protocol Control Unit (PCU) functions
*
* Protocol control unit is responsible to maintain various protocol
* properties before a frame is send and after a frame is received to/from
* baseband. To be more specific, PCU handles:
*
* - Buffering of RX and TX frames (after QCU/DCUs)
*
* - Encrypting and decrypting (using the built-in engine)
*
* - Generating ACKs, RTS/CTS frames
*
* - Maintaining TSF
*
* - FCS
*
* - Updating beacon data (with TSF etc)
*
* - Generating virtual CCA
*
* - RX/Multicast filtering
*
* - BSSID filtering
*
* - Various statistics
*
* -Different operating modes: AP, STA, IBSS
*
* Note: Most of these functions can be tweaked/bypassed so you can do
* them on sw above for debugging or research. For more infos check out PCU
* registers on reg.h.
*/
/**
* DOC: ACK rates
*
* AR5212+ can use higher rates for ack transmission * AR5212+ can use higher rates for ack transmission
* based on current tx rate instead of the base rate. * based on current tx rate instead of the base rate.
* It does this to better utilize channel usage. * It does this to better utilize channel usage.
* This is a mapping between G rates (that cover both * There is a mapping between G rates (that cover both
* CCK and OFDM) and ack rates that we use when setting * CCK and OFDM) and ack rates that we use when setting
* rate -> duration table. This mapping is hw-based so * rate -> duration table. This mapping is hw-based so
* don't change anything. * don't change anything.
@ -63,17 +99,18 @@ static const unsigned int ack_rates_high[] =
\*******************/ \*******************/
/** /**
* ath5k_hw_get_frame_duration - Get tx time of a frame * ath5k_hw_get_frame_duration() - Get tx time of a frame
*
* @ah: The &struct ath5k_hw * @ah: The &struct ath5k_hw
* @len: Frame's length in bytes * @len: Frame's length in bytes
* @rate: The @struct ieee80211_rate * @rate: The @struct ieee80211_rate
* @shortpre: Indicate short preample
* *
* Calculate tx duration of a frame given it's rate and length * Calculate tx duration of a frame given it's rate and length
* It extends ieee80211_generic_frame_duration for non standard * It extends ieee80211_generic_frame_duration for non standard
* bwmodes. * bwmodes.
*/ */
int ath5k_hw_get_frame_duration(struct ath5k_hw *ah, int
ath5k_hw_get_frame_duration(struct ath5k_hw *ah,
int len, struct ieee80211_rate *rate, bool shortpre) int len, struct ieee80211_rate *rate, bool shortpre)
{ {
int sifs, preamble, plcp_bits, sym_time; int sifs, preamble, plcp_bits, sym_time;
@ -129,11 +166,11 @@ int ath5k_hw_get_frame_duration(struct ath5k_hw *ah,
} }
/** /**
* ath5k_hw_get_default_slottime - Get the default slot time for current mode * ath5k_hw_get_default_slottime() - Get the default slot time for current mode
*
* @ah: The &struct ath5k_hw * @ah: The &struct ath5k_hw
*/ */
unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah) unsigned int
ath5k_hw_get_default_slottime(struct ath5k_hw *ah)
{ {
struct ieee80211_channel *channel = ah->ah_current_channel; struct ieee80211_channel *channel = ah->ah_current_channel;
unsigned int slot_time; unsigned int slot_time;
@ -160,11 +197,11 @@ unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah)
} }
/** /**
* ath5k_hw_get_default_sifs - Get the default SIFS for current mode * ath5k_hw_get_default_sifs() - Get the default SIFS for current mode
*
* @ah: The &struct ath5k_hw * @ah: The &struct ath5k_hw
*/ */
unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah) unsigned int
ath5k_hw_get_default_sifs(struct ath5k_hw *ah)
{ {
struct ieee80211_channel *channel = ah->ah_current_channel; struct ieee80211_channel *channel = ah->ah_current_channel;
unsigned int sifs; unsigned int sifs;
@ -191,17 +228,17 @@ unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah)
} }
/** /**
* ath5k_hw_update_mib_counters - Update MIB counters (mac layer statistics) * ath5k_hw_update_mib_counters() - Update MIB counters (mac layer statistics)
*
* @ah: The &struct ath5k_hw * @ah: The &struct ath5k_hw
* *
* Reads MIB counters from PCU and updates sw statistics. Is called after a * Reads MIB counters from PCU and updates sw statistics. Is called after a
* MIB interrupt, because one of these counters might have reached their maximum * MIB interrupt, because one of these counters might have reached their maximum
* and triggered the MIB interrupt, to let us read and clear the counter. * and triggered the MIB interrupt, to let us read and clear the counter.
* *
* Is called in interrupt context! * NOTE: Is called in interrupt context!
*/ */
void ath5k_hw_update_mib_counters(struct ath5k_hw *ah) void
ath5k_hw_update_mib_counters(struct ath5k_hw *ah)
{ {
struct ath5k_statistics *stats = &ah->stats; struct ath5k_statistics *stats = &ah->stats;
@ -219,10 +256,8 @@ void ath5k_hw_update_mib_counters(struct ath5k_hw *ah)
\******************/ \******************/
/** /**
* ath5k_hw_write_rate_duration - fill rate code to duration table * ath5k_hw_write_rate_duration() - Fill rate code to duration table
* * @ah: The &struct ath5k_hw
* @ah: the &struct ath5k_hw
* @mode: one of enum ath5k_driver_mode
* *
* Write the rate code to duration table upon hw reset. This is a helper for * Write the rate code to duration table upon hw reset. This is a helper for
* ath5k_hw_pcu_init(). It seems all this is doing is setting an ACK timeout on * ath5k_hw_pcu_init(). It seems all this is doing is setting an ACK timeout on
@ -236,7 +271,8 @@ void ath5k_hw_update_mib_counters(struct ath5k_hw *ah)
* that include all OFDM and CCK rates. * that include all OFDM and CCK rates.
* *
*/ */
static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah) static inline void
ath5k_hw_write_rate_duration(struct ath5k_hw *ah)
{ {
struct ieee80211_rate *rate; struct ieee80211_rate *rate;
unsigned int i; unsigned int i;
@ -280,12 +316,12 @@ static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah)
} }
/** /**
* ath5k_hw_set_ack_timeout - Set ACK timeout on PCU * ath5k_hw_set_ack_timeout() - Set ACK timeout on PCU
*
* @ah: The &struct ath5k_hw * @ah: The &struct ath5k_hw
* @timeout: Timeout in usec * @timeout: Timeout in usec
*/ */
static int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout) static int
ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout)
{ {
if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK)) if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK))
<= timeout) <= timeout)
@ -298,12 +334,12 @@ static int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout)
} }
/** /**
* ath5k_hw_set_cts_timeout - Set CTS timeout on PCU * ath5k_hw_set_cts_timeout() - Set CTS timeout on PCU
*
* @ah: The &struct ath5k_hw * @ah: The &struct ath5k_hw
* @timeout: Timeout in usec * @timeout: Timeout in usec
*/ */
static int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout) static int
ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout)
{ {
if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS)) if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS))
<= timeout) <= timeout)
@ -321,14 +357,14 @@ static int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout)
\*******************/ \*******************/
/** /**
* ath5k_hw_set_lladdr - Set station id * ath5k_hw_set_lladdr() - Set station id
*
* @ah: The &struct ath5k_hw * @ah: The &struct ath5k_hw
* @mac: The card's mac address * @mac: The card's mac address (array of octets)
* *
* Set station id on hw using the provided mac address * Set station id on hw using the provided mac address
*/ */
int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac) int
ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac)
{ {
struct ath_common *common = ath5k_hw_common(ah); struct ath_common *common = ath5k_hw_common(ah);
u32 low_id, high_id; u32 low_id, high_id;
@ -349,14 +385,14 @@ int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac)
} }
/** /**
* ath5k_hw_set_bssid - Set current BSSID on hw * ath5k_hw_set_bssid() - Set current BSSID on hw
*
* @ah: The &struct ath5k_hw * @ah: The &struct ath5k_hw
* *
* Sets the current BSSID and BSSID mask we have from the * Sets the current BSSID and BSSID mask we have from the
* common struct into the hardware * common struct into the hardware
*/ */
void ath5k_hw_set_bssid(struct ath5k_hw *ah) void
ath5k_hw_set_bssid(struct ath5k_hw *ah)
{ {
struct ath_common *common = ath5k_hw_common(ah); struct ath_common *common = ath5k_hw_common(ah);
u16 tim_offset = 0; u16 tim_offset = 0;
@ -389,7 +425,23 @@ void ath5k_hw_set_bssid(struct ath5k_hw *ah)
ath5k_hw_enable_pspoll(ah, NULL, 0); ath5k_hw_enable_pspoll(ah, NULL, 0);
} }
void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask) /**
* ath5k_hw_set_bssid_mask() - Filter out bssids we listen
* @ah: The &struct ath5k_hw
* @mask: The BSSID mask to set (array of octets)
*
* BSSID masking is a method used by AR5212 and newer hardware to inform PCU
* which bits of the interface's MAC address should be looked at when trying
* to decide which packets to ACK. In station mode and AP mode with a single
* BSS every bit matters since we lock to only one BSS. In AP mode with
* multiple BSSes (virtual interfaces) not every bit matters because hw must
* accept frames for all BSSes and so we tweak some bits of our mac address
* in order to have multiple BSSes.
*
* For more information check out ../hw.c of the common ath module.
*/
void
ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask)
{ {
struct ath_common *common = ath5k_hw_common(ah); struct ath_common *common = ath5k_hw_common(ah);
@ -400,18 +452,21 @@ void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask)
ath_hw_setbssidmask(common); ath_hw_setbssidmask(common);
} }
/* /**
* Set multicast filter * ath5k_hw_set_mcast_filter() - Set multicast filter
* @ah: The &struct ath5k_hw
* @filter0: Lower 32bits of muticast filter
* @filter1: Higher 16bits of multicast filter
*/ */
void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1) void
ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1)
{ {
ath5k_hw_reg_write(ah, filter0, AR5K_MCAST_FILTER0); ath5k_hw_reg_write(ah, filter0, AR5K_MCAST_FILTER0);
ath5k_hw_reg_write(ah, filter1, AR5K_MCAST_FILTER1); ath5k_hw_reg_write(ah, filter1, AR5K_MCAST_FILTER1);
} }
/** /**
* ath5k_hw_get_rx_filter - Get current rx filter * ath5k_hw_get_rx_filter() - Get current rx filter
*
* @ah: The &struct ath5k_hw * @ah: The &struct ath5k_hw
* *
* Returns the RX filter by reading rx filter and * Returns the RX filter by reading rx filter and
@ -420,7 +475,8 @@ void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1)
* and pass to the driver. For a list of frame types * and pass to the driver. For a list of frame types
* check out reg.h. * check out reg.h.
*/ */
u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah) u32
ath5k_hw_get_rx_filter(struct ath5k_hw *ah)
{ {
u32 data, filter = 0; u32 data, filter = 0;
@ -440,8 +496,7 @@ u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah)
} }
/** /**
* ath5k_hw_set_rx_filter - Set rx filter * ath5k_hw_set_rx_filter() - Set rx filter
*
* @ah: The &struct ath5k_hw * @ah: The &struct ath5k_hw
* @filter: RX filter mask (see reg.h) * @filter: RX filter mask (see reg.h)
* *
@ -449,7 +504,8 @@ u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah)
* register on 5212 and newer chips so that we have proper PHY * register on 5212 and newer chips so that we have proper PHY
* error reporting. * error reporting.
*/ */
void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter) void
ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter)
{ {
u32 data = 0; u32 data = 0;
@ -493,13 +549,13 @@ void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter)
#define ATH5K_MAX_TSF_READ 10 #define ATH5K_MAX_TSF_READ 10
/** /**
* ath5k_hw_get_tsf64 - Get the full 64bit TSF * ath5k_hw_get_tsf64() - Get the full 64bit TSF
*
* @ah: The &struct ath5k_hw * @ah: The &struct ath5k_hw
* *
* Returns the current TSF * Returns the current TSF
*/ */
u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah) u64
ath5k_hw_get_tsf64(struct ath5k_hw *ah)
{ {
u32 tsf_lower, tsf_upper1, tsf_upper2; u32 tsf_lower, tsf_upper1, tsf_upper2;
int i; int i;
@ -536,28 +592,30 @@ u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah)
return ((u64)tsf_upper1 << 32) | tsf_lower; return ((u64)tsf_upper1 << 32) | tsf_lower;
} }
#undef ATH5K_MAX_TSF_READ
/** /**
* ath5k_hw_set_tsf64 - Set a new 64bit TSF * ath5k_hw_set_tsf64() - Set a new 64bit TSF
*
* @ah: The &struct ath5k_hw * @ah: The &struct ath5k_hw
* @tsf64: The new 64bit TSF * @tsf64: The new 64bit TSF
* *
* Sets the new TSF * Sets the new TSF
*/ */
void ath5k_hw_set_tsf64(struct ath5k_hw *ah, u64 tsf64) void
ath5k_hw_set_tsf64(struct ath5k_hw *ah, u64 tsf64)
{ {
ath5k_hw_reg_write(ah, tsf64 & 0xffffffff, AR5K_TSF_L32); ath5k_hw_reg_write(ah, tsf64 & 0xffffffff, AR5K_TSF_L32);
ath5k_hw_reg_write(ah, (tsf64 >> 32) & 0xffffffff, AR5K_TSF_U32); ath5k_hw_reg_write(ah, (tsf64 >> 32) & 0xffffffff, AR5K_TSF_U32);
} }
/** /**
* ath5k_hw_reset_tsf - Force a TSF reset * ath5k_hw_reset_tsf() - Force a TSF reset
*
* @ah: The &struct ath5k_hw * @ah: The &struct ath5k_hw
* *
* Forces a TSF reset on PCU * Forces a TSF reset on PCU
*/ */
void ath5k_hw_reset_tsf(struct ath5k_hw *ah) void
ath5k_hw_reset_tsf(struct ath5k_hw *ah)
{ {
u32 val; u32 val;
@ -573,10 +631,17 @@ void ath5k_hw_reset_tsf(struct ath5k_hw *ah)
ath5k_hw_reg_write(ah, val, AR5K_BEACON); ath5k_hw_reg_write(ah, val, AR5K_BEACON);
} }
/* /**
* Initialize beacon timers * ath5k_hw_init_beacon_timers() - Initialize beacon timers
* @ah: The &struct ath5k_hw
* @next_beacon: Next TBTT
* @interval: Current beacon interval
*
* This function is used to initialize beacon timers based on current
* operation mode and settings.
*/ */
void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval) void
ath5k_hw_init_beacon_timers(struct ath5k_hw *ah, u32 next_beacon, u32 interval)
{ {
u32 timer1, timer2, timer3; u32 timer1, timer2, timer3;
@ -655,8 +720,7 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval)
} }
/** /**
* ath5k_check_timer_win - Check if timer B is timer A + window * ath5k_check_timer_win() - Check if timer B is timer A + window
*
* @a: timer a (before b) * @a: timer a (before b)
* @b: timer b (after a) * @b: timer b (after a)
* @window: difference between a and b * @window: difference between a and b
@ -686,12 +750,11 @@ ath5k_check_timer_win(int a, int b, int window, int intval)
} }
/** /**
* ath5k_hw_check_beacon_timers - Check if the beacon timers are correct * ath5k_hw_check_beacon_timers() - Check if the beacon timers are correct
*
* @ah: The &struct ath5k_hw * @ah: The &struct ath5k_hw
* @intval: beacon interval * @intval: beacon interval
* *
* This is a workaround for IBSS mode: * This is a workaround for IBSS mode
* *
* The need for this function arises from the fact that we have 4 separate * The need for this function arises from the fact that we have 4 separate
* HW timer registers (TIMER0 - TIMER3), which are closely related to the * HW timer registers (TIMER0 - TIMER3), which are closely related to the
@ -746,14 +809,14 @@ ath5k_hw_check_beacon_timers(struct ath5k_hw *ah, int intval)
} }
/** /**
* ath5k_hw_set_coverage_class - Set IEEE 802.11 coverage class * ath5k_hw_set_coverage_class() - Set IEEE 802.11 coverage class
*
* @ah: The &struct ath5k_hw * @ah: The &struct ath5k_hw
* @coverage_class: IEEE 802.11 coverage class number * @coverage_class: IEEE 802.11 coverage class number
* *
* Sets IFS intervals and ACK/CTS timeouts for given coverage class. * Sets IFS intervals and ACK/CTS timeouts for given coverage class.
*/ */
void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class) void
ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class)
{ {
/* As defined by IEEE 802.11-2007 17.3.8.6 */ /* As defined by IEEE 802.11-2007 17.3.8.6 */
int slot_time = ath5k_hw_get_default_slottime(ah) + 3 * coverage_class; int slot_time = ath5k_hw_get_default_slottime(ah) + 3 * coverage_class;
@ -772,8 +835,7 @@ void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class)
\***************************/ \***************************/
/** /**
* ath5k_hw_start_rx_pcu - Start RX engine * ath5k_hw_start_rx_pcu() - Start RX engine
*
* @ah: The &struct ath5k_hw * @ah: The &struct ath5k_hw
* *
* Starts RX engine on PCU so that hw can process RXed frames * Starts RX engine on PCU so that hw can process RXed frames
@ -781,32 +843,33 @@ void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class)
* *
* NOTE: RX DMA should be already enabled using ath5k_hw_start_rx_dma * NOTE: RX DMA should be already enabled using ath5k_hw_start_rx_dma
*/ */
void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah) void
ath5k_hw_start_rx_pcu(struct ath5k_hw *ah)
{ {
AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
} }
/** /**
* at5k_hw_stop_rx_pcu - Stop RX engine * at5k_hw_stop_rx_pcu() - Stop RX engine
*
* @ah: The &struct ath5k_hw * @ah: The &struct ath5k_hw
* *
* Stops RX engine on PCU * Stops RX engine on PCU
*/ */
void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah) void
ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah)
{ {
AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
} }
/** /**
* ath5k_hw_set_opmode - Set PCU operating mode * ath5k_hw_set_opmode() - Set PCU operating mode
*
* @ah: The &struct ath5k_hw * @ah: The &struct ath5k_hw
* @op_mode: &enum nl80211_iftype operating mode * @op_mode: One of enum nl80211_iftype
* *
* Configure PCU for the various operating modes (AP/STA etc) * Configure PCU for the various operating modes (AP/STA etc)
*/ */
int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype op_mode) int
ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype op_mode)
{ {
struct ath_common *common = ath5k_hw_common(ah); struct ath_common *common = ath5k_hw_common(ah);
u32 pcu_reg, beacon_reg, low_id, high_id; u32 pcu_reg, beacon_reg, low_id, high_id;
@ -873,8 +936,17 @@ int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype op_mode)
return 0; return 0;
} }
void ath5k_hw_pcu_init(struct ath5k_hw *ah, enum nl80211_iftype op_mode, /**
u8 mode) * ath5k_hw_pcu_init() - Initialize PCU
* @ah: The &struct ath5k_hw
* @op_mode: One of enum nl80211_iftype
* @mode: One of enum ath5k_driver_mode
*
* This function is used to initialize PCU by setting current
* operation mode and various other settings.
*/
void
ath5k_hw_pcu_init(struct ath5k_hw *ah, enum nl80211_iftype op_mode)
{ {
/* Set bssid and bssid mask */ /* Set bssid and bssid mask */
ath5k_hw_set_bssid(ah); ath5k_hw_set_bssid(ah);

File diff suppressed because it is too large Load Diff

View File

@ -17,23 +17,48 @@
*/ */
/********************************************\ /********************************************\
Queue Control Unit, DFS Control Unit Functions Queue Control Unit, DCF Control Unit Functions
\********************************************/ \********************************************/
#include "ath5k.h" #include "ath5k.h"
#include "reg.h" #include "reg.h"
#include "debug.h" #include "debug.h"
#include <linux/log2.h>
/**
* DOC: Queue Control Unit (QCU)/DCF Control Unit (DCU) functions
*
* Here we setup parameters for the 12 available TX queues. Note that
* on the various registers we can usually only map the first 10 of them so
* basically we have 10 queues to play with. Each queue has a matching
* QCU that controls when the queue will get triggered and multiple QCUs
* can be mapped to a single DCU that controls the various DFS parameters
* for the various queues. In our setup we have a 1:1 mapping between QCUs
* and DCUs allowing us to have different DFS settings for each queue.
*
* When a frame goes into a TX queue, QCU decides when it'll trigger a
* transmission based on various criteria (such as how many data we have inside
* it's buffer or -if it's a beacon queue- if it's time to fire up the queue
* based on TSF etc), DCU adds backoff, IFSes etc and then a scheduler
* (arbitrator) decides the priority of each QCU based on it's configuration
* (e.g. beacons are always transmitted when they leave DCU bypassing all other
* frames from other queues waiting to be transmitted). After a frame leaves
* the DCU it goes to PCU for further processing and then to PHY for
* the actual transmission.
*/
/******************\ /******************\
* Helper functions * * Helper functions *
\******************/ \******************/
/* /**
* Get number of pending frames * ath5k_hw_num_tx_pending() - Get number of pending frames for a given queue
* for a specific queue [5211+] * @ah: The &struct ath5k_hw
* @queue: One of enum ath5k_tx_queue_id
*/ */
u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue) u32
ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue)
{ {
u32 pending; u32 pending;
AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
@ -58,10 +83,13 @@ u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue)
return pending; return pending;
} }
/* /**
* Set a transmit queue inactive * ath5k_hw_release_tx_queue() - Set a transmit queue inactive
* @ah: The &struct ath5k_hw
* @queue: One of enum ath5k_tx_queue_id
*/ */
void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue) void
ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue)
{ {
if (WARN_ON(queue >= ah->ah_capabilities.cap_queues.q_tx_num)) if (WARN_ON(queue >= ah->ah_capabilities.cap_queues.q_tx_num))
return; return;
@ -72,34 +100,56 @@ void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue)
AR5K_Q_DISABLE_BITS(ah->ah_txq_status, queue); AR5K_Q_DISABLE_BITS(ah->ah_txq_status, queue);
} }
/* /**
* ath5k_cw_validate() - Make sure the given cw is valid
* @cw_req: The contention window value to check
*
* Make sure cw is a power of 2 minus 1 and smaller than 1024 * Make sure cw is a power of 2 minus 1 and smaller than 1024
*/ */
static u16 ath5k_cw_validate(u16 cw_req) static u16
ath5k_cw_validate(u16 cw_req)
{ {
u32 cw = 1;
cw_req = min(cw_req, (u16)1023); cw_req = min(cw_req, (u16)1023);
while (cw < cw_req) /* Check if cw_req + 1 a power of 2 */
cw = (cw << 1) | 1; if (is_power_of_2(cw_req + 1))
return cw_req;
return cw; /* Check if cw_req is a power of 2 */
if (is_power_of_2(cw_req))
return cw_req - 1;
/* If none of the above is correct
* find the closest power of 2 */
cw_req = (u16) roundup_pow_of_two(cw_req) - 1;
return cw_req;
} }
/* /**
* Get properties for a transmit queue * ath5k_hw_get_tx_queueprops() - Get properties for a transmit queue
* @ah: The &struct ath5k_hw
* @queue: One of enum ath5k_tx_queue_id
* @queue_info: The &struct ath5k_txq_info to fill
*/ */
int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue, int
ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue,
struct ath5k_txq_info *queue_info) struct ath5k_txq_info *queue_info)
{ {
memcpy(queue_info, &ah->ah_txq[queue], sizeof(struct ath5k_txq_info)); memcpy(queue_info, &ah->ah_txq[queue], sizeof(struct ath5k_txq_info));
return 0; return 0;
} }
/* /**
* Set properties for a transmit queue * ath5k_hw_set_tx_queueprops() - Set properties for a transmit queue
* @ah: The &struct ath5k_hw
* @queue: One of enum ath5k_tx_queue_id
* @qinfo: The &struct ath5k_txq_info to use
*
* Returns 0 on success or -EIO if queue is inactive
*/ */
int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue, int
ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue,
const struct ath5k_txq_info *qinfo) const struct ath5k_txq_info *qinfo)
{ {
struct ath5k_txq_info *qi; struct ath5k_txq_info *qi;
@ -139,10 +189,16 @@ int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue,
return 0; return 0;
} }
/* /**
* Initialize a transmit queue * ath5k_hw_setup_tx_queue() - Initialize a transmit queue
* @ah: The &struct ath5k_hw
* @queue_type: One of enum ath5k_tx_queue
* @queue_info: The &struct ath5k_txq_info to use
*
* Returns 0 on success, -EINVAL on invalid arguments
*/ */
int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type, int
ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type,
struct ath5k_txq_info *queue_info) struct ath5k_txq_info *queue_info)
{ {
unsigned int queue; unsigned int queue;
@ -217,10 +273,16 @@ int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type,
* Single QCU/DCU initialization * * Single QCU/DCU initialization *
\*******************************/ \*******************************/
/* /**
* Set tx retry limits on DCU * ath5k_hw_set_tx_retry_limits() - Set tx retry limits on DCU
* @ah: The &struct ath5k_hw
* @queue: One of enum ath5k_tx_queue_id
*
* This function is used when initializing a queue, to set
* retry limits based on ah->ah_retry_* and the chipset used.
*/ */
void ath5k_hw_set_tx_retry_limits(struct ath5k_hw *ah, void
ath5k_hw_set_tx_retry_limits(struct ath5k_hw *ah,
unsigned int queue) unsigned int queue)
{ {
/* Single data queue on AR5210 */ /* Single data queue on AR5210 */
@ -255,15 +317,15 @@ void ath5k_hw_set_tx_retry_limits(struct ath5k_hw *ah,
} }
/** /**
* ath5k_hw_reset_tx_queue - Initialize a single hw queue * ath5k_hw_reset_tx_queue() - Initialize a single hw queue
* @ah: The &struct ath5k_hw
* @queue: One of enum ath5k_tx_queue_id
* *
* @ah The &struct ath5k_hw * Set DCF properties for the given transmit queue on DCU
* @queue The hw queue number
*
* Set DFS properties for the given transmit queue on DCU
* and configures all queue-specific parameters. * and configures all queue-specific parameters.
*/ */
int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) int
ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
{ {
struct ath5k_txq_info *tq = &ah->ah_txq[queue]; struct ath5k_txq_info *tq = &ah->ah_txq[queue];
@ -491,10 +553,9 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
\**************************/ \**************************/
/** /**
* ath5k_hw_set_ifs_intervals - Set global inter-frame spaces on DCU * ath5k_hw_set_ifs_intervals() - Set global inter-frame spaces on DCU
* * @ah: The &struct ath5k_hw
* @ah The &struct ath5k_hw * @slot_time: Slot time in us
* @slot_time Slot time in us
* *
* Sets the global IFS intervals on DCU (also works on AR5210) for * Sets the global IFS intervals on DCU (also works on AR5210) for
* the given slot time and the current bwmode. * the given slot time and the current bwmode.
@ -597,7 +658,15 @@ int ath5k_hw_set_ifs_intervals(struct ath5k_hw *ah, unsigned int slot_time)
} }
int ath5k_hw_init_queues(struct ath5k_hw *ah) /**
* ath5k_hw_init_queues() - Initialize tx queues
* @ah: The &struct ath5k_hw
*
* Initializes all tx queues based on information on
* ah->ah_txq* set by the driver
*/
int
ath5k_hw_init_queues(struct ath5k_hw *ah)
{ {
int i, ret; int i, ret;

View File

@ -280,6 +280,10 @@
* 5211/5212 we have one primary and 4 secondary registers. * 5211/5212 we have one primary and 4 secondary registers.
* So we have AR5K_ISR for 5210 and AR5K_PISR /SISRx for 5211/5212. * So we have AR5K_ISR for 5210 and AR5K_PISR /SISRx for 5211/5212.
* Most of these bits are common for all chipsets. * Most of these bits are common for all chipsets.
*
* NOTE: On 5211+ TXOK, TXDESC, TXERR, TXEOL and TXURN contain
* the logical OR from per-queue interrupt bits found on SISR registers
* (see below).
*/ */
#define AR5K_ISR 0x001c /* Register Address [5210] */ #define AR5K_ISR 0x001c /* Register Address [5210] */
#define AR5K_PISR 0x0080 /* Register Address [5211+] */ #define AR5K_PISR 0x0080 /* Register Address [5211+] */
@ -292,7 +296,10 @@
#define AR5K_ISR_TXOK 0x00000040 /* Frame successfully transmitted */ #define AR5K_ISR_TXOK 0x00000040 /* Frame successfully transmitted */
#define AR5K_ISR_TXDESC 0x00000080 /* TX descriptor request */ #define AR5K_ISR_TXDESC 0x00000080 /* TX descriptor request */
#define AR5K_ISR_TXERR 0x00000100 /* Transmit error */ #define AR5K_ISR_TXERR 0x00000100 /* Transmit error */
#define AR5K_ISR_TXNOFRM 0x00000200 /* No frame transmitted (transmit timeout) */ #define AR5K_ISR_TXNOFRM 0x00000200 /* No frame transmitted (transmit timeout)
* NOTE: We don't have per-queue info for this
* one, but we can enable it per-queue through
* TXNOFRM_QCU field on TXNOFRM register */
#define AR5K_ISR_TXEOL 0x00000400 /* Empty TX descriptor */ #define AR5K_ISR_TXEOL 0x00000400 /* Empty TX descriptor */
#define AR5K_ISR_TXURN 0x00000800 /* Transmit FIFO underrun */ #define AR5K_ISR_TXURN 0x00000800 /* Transmit FIFO underrun */
#define AR5K_ISR_MIB 0x00001000 /* Update MIB counters */ #define AR5K_ISR_MIB 0x00001000 /* Update MIB counters */
@ -302,21 +309,29 @@
#define AR5K_ISR_SWBA 0x00010000 /* Software beacon alert */ #define AR5K_ISR_SWBA 0x00010000 /* Software beacon alert */
#define AR5K_ISR_BRSSI 0x00020000 /* Beacon rssi below threshold (?) */ #define AR5K_ISR_BRSSI 0x00020000 /* Beacon rssi below threshold (?) */
#define AR5K_ISR_BMISS 0x00040000 /* Beacon missed */ #define AR5K_ISR_BMISS 0x00040000 /* Beacon missed */
#define AR5K_ISR_HIUERR 0x00080000 /* Host Interface Unit error [5211+] */ #define AR5K_ISR_HIUERR 0x00080000 /* Host Interface Unit error [5211+]
* 'or' of MCABT, SSERR, DPERR from SISR2 */
#define AR5K_ISR_BNR 0x00100000 /* Beacon not ready [5211+] */ #define AR5K_ISR_BNR 0x00100000 /* Beacon not ready [5211+] */
#define AR5K_ISR_MCABT 0x00100000 /* Master Cycle Abort [5210] */ #define AR5K_ISR_MCABT 0x00100000 /* Master Cycle Abort [5210] */
#define AR5K_ISR_RXCHIRP 0x00200000 /* CHIRP Received [5212+] */ #define AR5K_ISR_RXCHIRP 0x00200000 /* CHIRP Received [5212+] */
#define AR5K_ISR_SSERR 0x00200000 /* Signaled System Error [5210] */ #define AR5K_ISR_SSERR 0x00200000 /* Signaled System Error [5210] */
#define AR5K_ISR_DPERR 0x00400000 /* Det par Error (?) [5210] */ #define AR5K_ISR_DPERR 0x00400000 /* Bus parity error [5210] */
#define AR5K_ISR_RXDOPPLER 0x00400000 /* Doppler chirp received [5212+] */ #define AR5K_ISR_RXDOPPLER 0x00400000 /* Doppler chirp received [5212+] */
#define AR5K_ISR_TIM 0x00800000 /* [5211+] */ #define AR5K_ISR_TIM 0x00800000 /* [5211+] */
#define AR5K_ISR_BCNMISC 0x00800000 /* 'or' of TIM, CAB_END, DTIM_SYNC, BCN_TIMEOUT, #define AR5K_ISR_BCNMISC 0x00800000 /* Misc beacon related interrupt
CAB_TIMEOUT and DTIM bits from SISR2 [5212+] */ * 'or' of TIM, CAB_END, DTIM_SYNC, BCN_TIMEOUT,
* CAB_TIMEOUT and DTIM bits from SISR2 [5212+] */
#define AR5K_ISR_GPIO 0x01000000 /* GPIO (rf kill) */ #define AR5K_ISR_GPIO 0x01000000 /* GPIO (rf kill) */
#define AR5K_ISR_QCBRORN 0x02000000 /* QCU CBR overrun [5211+] */ #define AR5K_ISR_QCBRORN 0x02000000 /* QCU CBR overrun [5211+] */
#define AR5K_ISR_QCBRURN 0x04000000 /* QCU CBR underrun [5211+] */ #define AR5K_ISR_QCBRURN 0x04000000 /* QCU CBR underrun [5211+] */
#define AR5K_ISR_QTRIG 0x08000000 /* QCU scheduling trigger [5211+] */ #define AR5K_ISR_QTRIG 0x08000000 /* QCU scheduling trigger [5211+] */
#define AR5K_ISR_BITS_FROM_SISRS (AR5K_ISR_TXOK | AR5K_ISR_TXDESC |\
AR5K_ISR_TXERR | AR5K_ISR_TXEOL |\
AR5K_ISR_TXURN | AR5K_ISR_HIUERR |\
AR5K_ISR_BCNMISC | AR5K_ISR_QCBRORN |\
AR5K_ISR_QCBRURN | AR5K_ISR_QTRIG)
/* /*
* Secondary status registers [5211+] (0 - 4) * Secondary status registers [5211+] (0 - 4)
* *
@ -347,7 +362,7 @@
#define AR5K_SISR2_BCN_TIMEOUT 0x08000000 /* Beacon Timeout [5212+] */ #define AR5K_SISR2_BCN_TIMEOUT 0x08000000 /* Beacon Timeout [5212+] */
#define AR5K_SISR2_CAB_TIMEOUT 0x10000000 /* CAB Timeout [5212+] */ #define AR5K_SISR2_CAB_TIMEOUT 0x10000000 /* CAB Timeout [5212+] */
#define AR5K_SISR2_DTIM 0x20000000 /* [5212+] */ #define AR5K_SISR2_DTIM 0x20000000 /* [5212+] */
#define AR5K_SISR2_TSFOOR 0x80000000 /* TSF OOR (?) */ #define AR5K_SISR2_TSFOOR 0x80000000 /* TSF Out of range */
#define AR5K_SISR3 0x0090 /* Register Address [5211+] */ #define AR5K_SISR3 0x0090 /* Register Address [5211+] */
#define AR5K_SISR3_QCBRORN 0x000003ff /* Mask for QCBRORN */ #define AR5K_SISR3_QCBRORN 0x000003ff /* Mask for QCBRORN */

View File

@ -19,9 +19,9 @@
* *
*/ */
/*****************************\ /****************************\
Reset functions and helpers Reset function and helpers
\*****************************/ \****************************/
#include <asm/unaligned.h> #include <asm/unaligned.h>
@ -33,14 +33,36 @@
#include "debug.h" #include "debug.h"
/**
* DOC: Reset function and helpers
*
* Here we implement the main reset routine, used to bring the card
* to a working state and ready to receive. We also handle routines
* that don't fit on other places such as clock, sleep and power control
*/
/******************\ /******************\
* Helper functions * * Helper functions *
\******************/ \******************/
/* /**
* Check if a register write has been completed * ath5k_hw_register_timeout() - Poll a register for a flag/field change
* @ah: The &struct ath5k_hw
* @reg: The register to read
* @flag: The flag/field to check on the register
* @val: The field value we expect (if we check a field)
* @is_set: Instead of checking if the flag got cleared, check if it got set
*
* Some registers contain flags that indicate that an operation is
* running. We use this function to poll these registers and check
* if these flags get cleared. We also use it to poll a register
* field (containing multiple flags) until it gets a specific value.
*
* Returns -EAGAIN if we exceeded AR5K_TUNE_REGISTER_TIMEOUT * 15us or 0
*/ */
int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val, int
ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val,
bool is_set) bool is_set)
{ {
int i; int i;
@ -64,35 +86,48 @@ int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val,
\*************************/ \*************************/
/** /**
* ath5k_hw_htoclock - Translate usec to hw clock units * ath5k_hw_htoclock() - Translate usec to hw clock units
*
* @ah: The &struct ath5k_hw * @ah: The &struct ath5k_hw
* @usec: value in microseconds * @usec: value in microseconds
*
* Translate usecs to hw clock units based on the current
* hw clock rate.
*
* Returns number of clock units
*/ */
unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec) unsigned int
ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec)
{ {
struct ath_common *common = ath5k_hw_common(ah); struct ath_common *common = ath5k_hw_common(ah);
return usec * common->clockrate; return usec * common->clockrate;
} }
/** /**
* ath5k_hw_clocktoh - Translate hw clock units to usec * ath5k_hw_clocktoh() - Translate hw clock units to usec
* @ah: The &struct ath5k_hw
* @clock: value in hw clock units * @clock: value in hw clock units
*
* Translate hw clock units to usecs based on the current
* hw clock rate.
*
* Returns number of usecs
*/ */
unsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock) unsigned int
ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock)
{ {
struct ath_common *common = ath5k_hw_common(ah); struct ath_common *common = ath5k_hw_common(ah);
return clock / common->clockrate; return clock / common->clockrate;
} }
/** /**
* ath5k_hw_init_core_clock - Initialize core clock * ath5k_hw_init_core_clock() - Initialize core clock
* @ah: The &struct ath5k_hw
* *
* @ah The &struct ath5k_hw * Initialize core clock parameters (usec, usec32, latencies etc),
* * based on current bwmode and chipset properties.
* Initialize core clock parameters (usec, usec32, latencies etc).
*/ */
static void ath5k_hw_init_core_clock(struct ath5k_hw *ah) static void
ath5k_hw_init_core_clock(struct ath5k_hw *ah)
{ {
struct ieee80211_channel *channel = ah->ah_current_channel; struct ieee80211_channel *channel = ah->ah_current_channel;
struct ath_common *common = ath5k_hw_common(ah); struct ath_common *common = ath5k_hw_common(ah);
@ -227,16 +262,21 @@ static void ath5k_hw_init_core_clock(struct ath5k_hw *ah)
} }
} }
/* /**
* ath5k_hw_set_sleep_clock() - Setup sleep clock operation
* @ah: The &struct ath5k_hw
* @enable: Enable sleep clock operation (false to disable)
*
* If there is an external 32KHz crystal available, use it * If there is an external 32KHz crystal available, use it
* as ref. clock instead of 32/40MHz clock and baseband clocks * as ref. clock instead of 32/40MHz clock and baseband clocks
* to save power during sleep or restore normal 32/40MHz * to save power during sleep or restore normal 32/40MHz
* operation. * operation.
* *
* XXX: When operating on 32KHz certain PHY registers (27 - 31, * NOTE: When operating on 32KHz certain PHY registers (27 - 31,
* 123 - 127) require delay on access. * 123 - 127) require delay on access.
*/ */
static void ath5k_hw_set_sleep_clock(struct ath5k_hw *ah, bool enable) static void
ath5k_hw_set_sleep_clock(struct ath5k_hw *ah, bool enable)
{ {
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
u32 scal, spending, sclock; u32 scal, spending, sclock;
@ -340,10 +380,19 @@ static void ath5k_hw_set_sleep_clock(struct ath5k_hw *ah, bool enable)
* Reset/Sleep control * * Reset/Sleep control *
\*********************/ \*********************/
/* /**
* Reset chipset * ath5k_hw_nic_reset() - Reset the various chipset units
* @ah: The &struct ath5k_hw
* @val: Mask to indicate what units to reset
*
* To reset the various chipset units we need to write
* the mask to AR5K_RESET_CTL and poll the register until
* all flags are cleared.
*
* Returns 0 if we are O.K. or -EAGAIN (from athk5_hw_register_timeout)
*/ */
static int ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val) static int
ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val)
{ {
int ret; int ret;
u32 mask = val ? val : ~0U; u32 mask = val ? val : ~0U;
@ -357,7 +406,7 @@ static int ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val)
ath5k_hw_reg_write(ah, val, AR5K_RESET_CTL); ath5k_hw_reg_write(ah, val, AR5K_RESET_CTL);
/* Wait at least 128 PCI clocks */ /* Wait at least 128 PCI clocks */
udelay(15); usleep_range(15, 20);
if (ah->ah_version == AR5K_AR5210) { if (ah->ah_version == AR5K_AR5210) {
val &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_DMA val &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_DMA
@ -382,12 +431,17 @@ static int ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val)
return ret; return ret;
} }
/* /**
* Reset AHB chipset * ath5k_hw_wisoc_reset() - Reset AHB chipset
* AR5K_RESET_CTL_PCU flag resets WMAC * @ah: The &struct ath5k_hw
* AR5K_RESET_CTL_BASEBAND flag resets WBB * @flags: Mask to indicate what units to reset
*
* Same as ath5k_hw_nic_reset but for AHB based devices
*
* Returns 0 if we are O.K. or -EAGAIN (from athk5_hw_register_timeout)
*/ */
static int ath5k_hw_wisoc_reset(struct ath5k_hw *ah, u32 flags) static int
ath5k_hw_wisoc_reset(struct ath5k_hw *ah, u32 flags)
{ {
u32 mask = flags ? flags : ~0U; u32 mask = flags ? flags : ~0U;
u32 __iomem *reg; u32 __iomem *reg;
@ -422,7 +476,7 @@ static int ath5k_hw_wisoc_reset(struct ath5k_hw *ah, u32 flags)
regval = __raw_readl(reg); regval = __raw_readl(reg);
__raw_writel(regval | val, reg); __raw_writel(regval | val, reg);
regval = __raw_readl(reg); regval = __raw_readl(reg);
udelay(100); usleep_range(100, 150);
/* Bring BB/MAC out of reset */ /* Bring BB/MAC out of reset */
__raw_writel(regval & ~val, reg); __raw_writel(regval & ~val, reg);
@ -439,11 +493,23 @@ static int ath5k_hw_wisoc_reset(struct ath5k_hw *ah, u32 flags)
return 0; return 0;
} }
/**
/* * ath5k_hw_set_power_mode() - Set power mode
* Sleep control * @ah: The &struct ath5k_hw
* @mode: One of enum ath5k_power_mode
* @set_chip: Set to true to write sleep control register
* @sleep_duration: How much time the device is allowed to sleep
* when sleep logic is enabled (in 128 microsecond increments).
*
* This function is used to configure sleep policy and allowed
* sleep modes. For more information check out the sleep control
* register on reg.h and STA_ID1.
*
* Returns 0 on success, -EIO if chip didn't wake up or -EINVAL if an invalid
* mode is requested.
*/ */
static int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, static int
ath5k_hw_set_power_mode(struct ath5k_hw *ah, enum ath5k_power_mode mode,
bool set_chip, u16 sleep_duration) bool set_chip, u16 sleep_duration)
{ {
unsigned int i; unsigned int i;
@ -493,7 +559,7 @@ static int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode,
ath5k_hw_reg_write(ah, data | AR5K_SLEEP_CTL_SLE_WAKE, ath5k_hw_reg_write(ah, data | AR5K_SLEEP_CTL_SLE_WAKE,
AR5K_SLEEP_CTL); AR5K_SLEEP_CTL);
udelay(15); usleep_range(15, 20);
for (i = 200; i > 0; i--) { for (i = 200; i > 0; i--) {
/* Check if the chip did wake up */ /* Check if the chip did wake up */
@ -502,7 +568,7 @@ static int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode,
break; break;
/* Wait a bit and retry */ /* Wait a bit and retry */
udelay(50); usleep_range(50, 75);
ath5k_hw_reg_write(ah, data | AR5K_SLEEP_CTL_SLE_WAKE, ath5k_hw_reg_write(ah, data | AR5K_SLEEP_CTL_SLE_WAKE,
AR5K_SLEEP_CTL); AR5K_SLEEP_CTL);
} }
@ -523,17 +589,20 @@ static int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode,
return 0; return 0;
} }
/* /**
* Put device on hold * ath5k_hw_on_hold() - Put device on hold
* @ah: The &struct ath5k_hw
* *
* Put MAC and Baseband on warm reset and * Put MAC and Baseband on warm reset and keep that state
* keep that state (don't clean sleep control * (don't clean sleep control register). After this MAC
* register). After this MAC and Baseband are * and Baseband are disabled and a full reset is needed
* disabled and a full reset is needed to come * to come back. This way we save as much power as possible
* back. This way we save as much power as possible
* without putting the card on full sleep. * without putting the card on full sleep.
*
* Returns 0 on success or -EIO on error
*/ */
int ath5k_hw_on_hold(struct ath5k_hw *ah) int
ath5k_hw_on_hold(struct ath5k_hw *ah)
{ {
struct pci_dev *pdev = ah->pdev; struct pci_dev *pdev = ah->pdev;
u32 bus_flags; u32 bus_flags;
@ -543,7 +612,7 @@ int ath5k_hw_on_hold(struct ath5k_hw *ah)
return 0; return 0;
/* Make sure device is awake */ /* Make sure device is awake */
ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); ret = ath5k_hw_set_power_mode(ah, AR5K_PM_AWAKE, true, 0);
if (ret) { if (ret) {
ATH5K_ERR(ah, "failed to wakeup the MAC Chip\n"); ATH5K_ERR(ah, "failed to wakeup the MAC Chip\n");
return ret; return ret;
@ -563,7 +632,7 @@ int ath5k_hw_on_hold(struct ath5k_hw *ah)
ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU | ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA | AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA |
AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI); AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI);
mdelay(2); usleep_range(2000, 2500);
} else { } else {
ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU | ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
AR5K_RESET_CTL_BASEBAND | bus_flags); AR5K_RESET_CTL_BASEBAND | bus_flags);
@ -575,7 +644,7 @@ int ath5k_hw_on_hold(struct ath5k_hw *ah)
} }
/* ...wakeup again!*/ /* ...wakeup again!*/
ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); ret = ath5k_hw_set_power_mode(ah, AR5K_PM_AWAKE, true, 0);
if (ret) { if (ret) {
ATH5K_ERR(ah, "failed to put device on hold\n"); ATH5K_ERR(ah, "failed to put device on hold\n");
return ret; return ret;
@ -584,11 +653,18 @@ int ath5k_hw_on_hold(struct ath5k_hw *ah)
return ret; return ret;
} }
/* /**
* ath5k_hw_nic_wakeup() - Force card out of sleep
* @ah: The &struct ath5k_hw
* @channel: The &struct ieee80211_channel
*
* Bring up MAC + PHY Chips and program PLL * Bring up MAC + PHY Chips and program PLL
* Channel is NULL for the initial wakeup. * NOTE: Channel is NULL for the initial wakeup.
*
* Returns 0 on success, -EIO on hw failure or -EINVAL for false channel infos
*/ */
int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel) int
ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel)
{ {
struct pci_dev *pdev = ah->pdev; struct pci_dev *pdev = ah->pdev;
u32 turbo, mode, clock, bus_flags; u32 turbo, mode, clock, bus_flags;
@ -600,7 +676,7 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel)
if ((ath5k_get_bus_type(ah) != ATH_AHB) || channel) { if ((ath5k_get_bus_type(ah) != ATH_AHB) || channel) {
/* Wakeup the device */ /* Wakeup the device */
ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); ret = ath5k_hw_set_power_mode(ah, AR5K_PM_AWAKE, true, 0);
if (ret) { if (ret) {
ATH5K_ERR(ah, "failed to wakeup the MAC Chip\n"); ATH5K_ERR(ah, "failed to wakeup the MAC Chip\n");
return ret; return ret;
@ -621,7 +697,7 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel)
ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU | ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA | AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA |
AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI); AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI);
mdelay(2); usleep_range(2000, 2500);
} else { } else {
if (ath5k_get_bus_type(ah) == ATH_AHB) if (ath5k_get_bus_type(ah) == ATH_AHB)
ret = ath5k_hw_wisoc_reset(ah, AR5K_RESET_CTL_PCU | ret = ath5k_hw_wisoc_reset(ah, AR5K_RESET_CTL_PCU |
@ -637,7 +713,7 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel)
} }
/* ...wakeup again!...*/ /* ...wakeup again!...*/
ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); ret = ath5k_hw_set_power_mode(ah, AR5K_PM_AWAKE, true, 0);
if (ret) { if (ret) {
ATH5K_ERR(ah, "failed to resume the MAC Chip\n"); ATH5K_ERR(ah, "failed to resume the MAC Chip\n");
return ret; return ret;
@ -739,7 +815,7 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel)
/* ...update PLL if needed */ /* ...update PLL if needed */
if (ath5k_hw_reg_read(ah, AR5K_PHY_PLL) != clock) { if (ath5k_hw_reg_read(ah, AR5K_PHY_PLL) != clock) {
ath5k_hw_reg_write(ah, clock, AR5K_PHY_PLL); ath5k_hw_reg_write(ah, clock, AR5K_PHY_PLL);
udelay(300); usleep_range(300, 350);
} }
/* ...set the PHY operating mode */ /* ...set the PHY operating mode */
@ -755,8 +831,19 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel)
* Post-initvals register modifications * * Post-initvals register modifications *
\**************************************/ \**************************************/
/* TODO: Half/Quarter rate */ /**
static void ath5k_hw_tweak_initval_settings(struct ath5k_hw *ah, * ath5k_hw_tweak_initval_settings() - Tweak initial settings
* @ah: The &struct ath5k_hw
* @channel: The &struct ieee80211_channel
*
* Some settings are not handled on initvals, e.g. bwmode
* settings, some phy settings, workarounds etc that in general
* don't fit anywhere else or are too small to introduce a separate
* function for each one. So we have this function to handle
* them all during reset and complete card's initialization.
*/
static void
ath5k_hw_tweak_initval_settings(struct ath5k_hw *ah,
struct ieee80211_channel *channel) struct ieee80211_channel *channel)
{ {
if (ah->ah_version == AR5K_AR5212 && if (ah->ah_version == AR5K_AR5212 &&
@ -875,7 +962,16 @@ static void ath5k_hw_tweak_initval_settings(struct ath5k_hw *ah,
} }
} }
static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah, /**
* ath5k_hw_commit_eeprom_settings() - Commit settings from EEPROM
* @ah: The &struct ath5k_hw
* @channel: The &struct ieee80211_channel
*
* Use settings stored on EEPROM to properly initialize the card
* based on various infos and per-mode calibration data.
*/
static void
ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah,
struct ieee80211_channel *channel) struct ieee80211_channel *channel)
{ {
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
@ -1029,7 +1125,23 @@ static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah,
* Main reset function * * Main reset function *
\*********************/ \*********************/
int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, /**
* ath5k_hw_reset() - The main reset function
* @ah: The &struct ath5k_hw
* @op_mode: One of enum nl80211_iftype
* @channel: The &struct ieee80211_channel
* @fast: Enable fast channel switching
* @skip_pcu: Skip pcu initialization
*
* This is the function we call each time we want to (re)initialize the
* card and pass new settings to hw. We also call it when hw runs into
* trouble to make it come back to a working state.
*
* Returns 0 on success, -EINVAL on false op_mode or channel infos, or -EIO
* on failure.
*/
int
ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
struct ieee80211_channel *channel, bool fast, bool skip_pcu) struct ieee80211_channel *channel, bool fast, bool skip_pcu)
{ {
u32 s_seq[10], s_led[3], tsf_up, tsf_lo; u32 s_seq[10], s_led[3], tsf_up, tsf_lo;
@ -1242,7 +1354,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
/* /*
* Initialize PCU * Initialize PCU
*/ */
ath5k_hw_pcu_init(ah, op_mode, mode); ath5k_hw_pcu_init(ah, op_mode);
/* /*
* Initialize PHY * Initialize PHY

View File

@ -18,7 +18,9 @@
*/ */
/* /**
* DOC: RF Buffer registers
*
* There are some special registers on the RF chip * There are some special registers on the RF chip
* that control various operation settings related mostly to * that control various operation settings related mostly to
* the analog parts (channel, gain adjustment etc). * the analog parts (channel, gain adjustment etc).
@ -44,40 +46,63 @@
*/ */
/* /**
* struct ath5k_ini_rfbuffer - Initial RF Buffer settings
* @rfb_bank: RF Bank number
* @rfb_ctrl_register: RF Buffer control register
* @rfb_mode_data: RF Buffer data for each mode
*
* Struct to hold default mode specific RF * Struct to hold default mode specific RF
* register values (RF Banks) * register values (RF Banks) for each chip.
*/ */
struct ath5k_ini_rfbuffer { struct ath5k_ini_rfbuffer {
u8 rfb_bank; /* RF Bank number */ u8 rfb_bank;
u16 rfb_ctrl_register; /* RF Buffer control register */ u16 rfb_ctrl_register;
u32 rfb_mode_data[3]; /* RF Buffer data for each mode */ u32 rfb_mode_data[3];
}; };
/* /**
* struct ath5k_rfb_field - An RF Buffer field (register/value)
* @len: Field length
* @pos: Offset on the raw packet
* @col: Used for shifting
*
* Struct to hold RF Buffer field * Struct to hold RF Buffer field
* infos used to access certain RF * infos used to access certain RF
* analog registers * analog registers
*/ */
struct ath5k_rfb_field { struct ath5k_rfb_field {
u8 len; /* Field length */ u8 len;
u16 pos; /* Offset on the raw packet */ u16 pos;
u8 col; /* Column -used for shifting */ u8 col;
}; };
/* /**
* RF analog register definition * struct ath5k_rf_reg - RF analog register definition
* @bank: RF Buffer Bank number
* @index: Register's index on ath5k_rf_regx_idx
* @field: The &struct ath5k_rfb_field
*
* We use this struct to define the set of RF registers
* on each chip that we want to tweak. Some RF registers
* are common between different chip versions so this saves
* us space and complexity because we can refer to an rf
* register by it's index no matter what chip we work with
* as long as it has that register.
*/ */
struct ath5k_rf_reg { struct ath5k_rf_reg {
u8 bank; /* RF Buffer Bank number */ u8 bank;
u8 index; /* Register's index on rf_regs_idx */ u8 index;
struct ath5k_rfb_field field; /* RF Buffer field for this register */ struct ath5k_rfb_field field;
}; };
/* Map RF registers to indexes /**
* enum ath5k_rf_regs_idx - Map RF registers to indexes
*
* We do this to handle common bits and make our * We do this to handle common bits and make our
* life easier by using an index for each register * life easier by using an index for each register
* instead of a full rfb_field */ * instead of a full rfb_field
*/
enum ath5k_rf_regs_idx { enum ath5k_rf_regs_idx {
/* BANK 2 */ /* BANK 2 */
AR5K_RF_TURBO = 0, AR5K_RF_TURBO = 0,

View File

@ -18,13 +18,17 @@
* *
*/ */
/* /**
* struct ath5k_ini_rfgain - RF Gain table
* @rfg_register: RF Gain register address
* @rfg_value: Register value for 5 and 2GHz
*
* Mode-specific RF Gain table (64bytes) for RF5111/5112 * Mode-specific RF Gain table (64bytes) for RF5111/5112
* (RF5110 only comes with AR5210 and only supports a/turbo a mode so initial * (RF5110 only comes with AR5210 and only supports a/turbo a mode so initial
* RF Gain values are included in AR5K_AR5210_INI) * RF Gain values are included in AR5K_AR5210_INI)
*/ */
struct ath5k_ini_rfgain { struct ath5k_ini_rfgain {
u16 rfg_register; /* RF Gain register address */ u16 rfg_register;
u32 rfg_value[2]; /* [freq (see below)] */ u32 rfg_value[2]; /* [freq (see below)] */
}; };
@ -455,18 +459,31 @@ static const struct ath5k_ini_rfgain rfgain_2425[] = {
#define AR5K_GAIN_CHECK_ADJUST(_g) \ #define AR5K_GAIN_CHECK_ADJUST(_g) \
((_g)->g_current <= (_g)->g_low || (_g)->g_current >= (_g)->g_high) ((_g)->g_current <= (_g)->g_low || (_g)->g_current >= (_g)->g_high)
/**
* struct ath5k_gain_opt_step - An RF gain optimization step
* @gos_param: Set of parameters
* @gos_gain: Gain
*/
struct ath5k_gain_opt_step { struct ath5k_gain_opt_step {
s8 gos_param[AR5K_GAIN_CRN_MAX_FIX_BITS]; s8 gos_param[AR5K_GAIN_CRN_MAX_FIX_BITS];
s8 gos_gain; s8 gos_gain;
}; };
/**
* struct ath5k_gain_opt - RF Gain optimization ladder
* @go_default: The default step
* @go_steps_count: How many optimization steps
* @go_step: Array of &struct ath5k_gain_opt_step
*/
struct ath5k_gain_opt { struct ath5k_gain_opt {
u8 go_default; u8 go_default;
u8 go_steps_count; u8 go_steps_count;
const struct ath5k_gain_opt_step go_step[AR5K_GAIN_STEP_COUNT]; const struct ath5k_gain_opt_step go_step[AR5K_GAIN_STEP_COUNT];
}; };
/* /*
* RF5111
* Parameters on gos_param: * Parameters on gos_param:
* 1) Tx clip PHY register * 1) Tx clip PHY register
* 2) PWD 90 RF register * 2) PWD 90 RF register
@ -490,6 +507,7 @@ static const struct ath5k_gain_opt rfgain_opt_5111 = {
}; };
/* /*
* RF5112
* Parameters on gos_param: * Parameters on gos_param:
* 1) Mixgain ovr RF register * 1) Mixgain ovr RF register
* 2) PWD 138 RF register * 2) PWD 138 RF register

View File

@ -34,7 +34,8 @@ ath9k_hw-y:= \
ar9002_mac.o \ ar9002_mac.o \
ar9003_mac.o \ ar9003_mac.o \
ar9003_eeprom.o \ ar9003_eeprom.o \
ar9003_paprd.o ar9003_paprd.o \
ar9003_mci.o
obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o

View File

@ -18,6 +18,7 @@
#include "hw-ops.h" #include "hw-ops.h"
#include "ar9003_phy.h" #include "ar9003_phy.h"
#include "ar9003_rtt.h" #include "ar9003_rtt.h"
#include "ar9003_mci.h"
#define MAX_MEASUREMENT MAX_IQCAL_MEASUREMENT #define MAX_MEASUREMENT MAX_IQCAL_MEASUREMENT
#define MAX_MAG_DELTA 11 #define MAX_MAG_DELTA 11
@ -824,7 +825,7 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable)
chan_info_tab[i] + offset); chan_info_tab[i] + offset);
ath_dbg(common, ATH_DBG_CALIBRATE, ath_dbg(common, ATH_DBG_CALIBRATE,
"IQ RES[%d]=0x%x" "IQ_RES[%d]=0x%x "
"IQ_RES[%d]=0x%x\n", "IQ_RES[%d]=0x%x\n",
idx, iq_res[idx], idx + 1, idx, iq_res[idx], idx + 1,
iq_res[idx + 1]); iq_res[idx + 1]);
@ -934,10 +935,12 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
{ {
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_hw_cal_data *caldata = ah->caldata; struct ath9k_hw_cal_data *caldata = ah->caldata;
struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
bool txiqcal_done = false, txclcal_done = false; bool txiqcal_done = false, txclcal_done = false;
bool is_reusable = true, status = true; bool is_reusable = true, status = true;
bool run_rtt_cal = false, run_agc_cal; bool run_rtt_cal = false, run_agc_cal;
bool rtt = !!(ah->caps.hw_caps & ATH9K_HW_CAP_RTT); bool rtt = !!(ah->caps.hw_caps & ATH9K_HW_CAP_RTT);
bool mci = !!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI);
u32 agc_ctrl = 0, agc_supp_cals = AR_PHY_AGC_CONTROL_OFFSET_CAL | u32 agc_ctrl = 0, agc_supp_cals = AR_PHY_AGC_CONTROL_OFFSET_CAL |
AR_PHY_AGC_CONTROL_FLTR_CAL | AR_PHY_AGC_CONTROL_FLTR_CAL |
AR_PHY_AGC_CONTROL_PKDET_CAL; AR_PHY_AGC_CONTROL_PKDET_CAL;
@ -1005,6 +1008,31 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
} else if (caldata && !caldata->done_txiqcal_once) } else if (caldata && !caldata->done_txiqcal_once)
run_agc_cal = true; run_agc_cal = true;
if (mci && IS_CHAN_2GHZ(chan) &&
(mci_hw->bt_state == MCI_BT_AWAKE) &&
run_agc_cal &&
!(mci_hw->config & ATH_MCI_CONFIG_DISABLE_MCI_CAL)) {
u32 pld[4] = {0, 0, 0, 0};
/* send CAL_REQ only when BT is AWAKE. */
ath_dbg(common, ATH_DBG_MCI, "MCI send WLAN_CAL_REQ 0x%x\n",
mci_hw->wlan_cal_seq);
MCI_GPM_SET_CAL_TYPE(pld, MCI_GPM_WLAN_CAL_REQ);
pld[MCI_GPM_WLAN_CAL_W_SEQUENCE] = mci_hw->wlan_cal_seq++;
ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16, true, false);
/* Wait BT_CAL_GRANT for 50ms */
ath_dbg(common, ATH_DBG_MCI, "MCI wait for BT_CAL_GRANT");
if (ar9003_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_GRANT, 0, 50000))
ath_dbg(common, ATH_DBG_MCI, "MCI got BT_CAL_GRANT");
else {
is_reusable = false;
ath_dbg(common, ATH_DBG_MCI, "\nMCI BT is not responding");
}
}
txiqcal_done = ar9003_hw_tx_iq_cal_run(ah); txiqcal_done = ar9003_hw_tx_iq_cal_run(ah);
REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
udelay(5); udelay(5);
@ -1022,6 +1050,21 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
AR_PHY_AGC_CONTROL_CAL, AR_PHY_AGC_CONTROL_CAL,
0, AH_WAIT_TIMEOUT); 0, AH_WAIT_TIMEOUT);
} }
if (mci && IS_CHAN_2GHZ(chan) &&
(mci_hw->bt_state == MCI_BT_AWAKE) &&
run_agc_cal &&
!(mci_hw->config & ATH_MCI_CONFIG_DISABLE_MCI_CAL)) {
u32 pld[4] = {0, 0, 0, 0};
ath_dbg(common, ATH_DBG_MCI, "MCI Send WLAN_CAL_DONE 0x%x\n",
mci_hw->wlan_cal_done);
MCI_GPM_SET_CAL_TYPE(pld, MCI_GPM_WLAN_CAL_DONE);
pld[MCI_GPM_WLAN_CAL_W_SEQUENCE] = mci_hw->wlan_cal_done++;
ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16, true, false);
}
if (rtt && !run_rtt_cal) { if (rtt && !run_rtt_cal) {
agc_ctrl |= agc_supp_cals; agc_ctrl |= agc_supp_cals;
REG_WRITE(ah, AR_PHY_AGC_CONTROL, agc_ctrl); REG_WRITE(ah, AR_PHY_AGC_CONTROL, agc_ctrl);

View File

@ -4779,7 +4779,7 @@ static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah,
{ {
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
struct ar9300_eeprom *pEepData = &ah->eeprom.ar9300_eep; struct ar9300_eeprom *pEepData = &ah->eeprom.ar9300_eep;
u16 twiceMaxEdgePower = MAX_RATE_POWER; u16 twiceMaxEdgePower;
int i; int i;
u16 scaledPower = 0, minCtlPower; u16 scaledPower = 0, minCtlPower;
static const u16 ctlModesFor11a[] = { static const u16 ctlModesFor11a[] = {
@ -4880,6 +4880,7 @@ static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah,
ctlNum = AR9300_NUM_CTLS_5G; ctlNum = AR9300_NUM_CTLS_5G;
} }
twiceMaxEdgePower = MAX_RATE_POWER;
for (i = 0; (i < ctlNum) && ctlIndex[i]; i++) { for (i = 0; (i < ctlNum) && ctlIndex[i]; i++) {
ath_dbg(common, ATH_DBG_REGULATORY, ath_dbg(common, ATH_DBG_REGULATORY,
"LOOP-Ctlidx %d: cfgCtl 0x%2.2x pCtlMode 0x%2.2x ctlIndex 0x%2.2x chan %d\n", "LOOP-Ctlidx %d: cfgCtl 0x%2.2x pCtlMode 0x%2.2x ctlIndex 0x%2.2x chan %d\n",

View File

@ -175,15 +175,47 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
u32 isr = 0; u32 isr = 0;
u32 mask2 = 0; u32 mask2 = 0;
struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath9k_hw_capabilities *pCap = &ah->caps;
u32 sync_cause = 0;
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
u32 sync_cause = 0, async_cause;
if (REG_READ(ah, AR_INTR_ASYNC_CAUSE) & AR_INTR_MAC_IRQ) { async_cause = REG_READ(ah, AR_INTR_ASYNC_CAUSE);
if (async_cause & (AR_INTR_MAC_IRQ | AR_INTR_ASYNC_MASK_MCI)) {
if ((REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M) if ((REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M)
== AR_RTC_STATUS_ON) == AR_RTC_STATUS_ON)
isr = REG_READ(ah, AR_ISR); isr = REG_READ(ah, AR_ISR);
} }
if (async_cause & AR_INTR_ASYNC_MASK_MCI) {
u32 raw_intr, rx_msg_intr;
rx_msg_intr = REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW);
raw_intr = REG_READ(ah, AR_MCI_INTERRUPT_RAW);
if ((raw_intr == 0xdeadbeef) || (rx_msg_intr == 0xdeadbeef))
ath_dbg(common, ATH_DBG_MCI,
"MCI gets 0xdeadbeef during MCI int processing"
"new raw_intr=0x%08x, new rx_msg_raw=0x%08x, "
"raw_intr=0x%08x, rx_msg_raw=0x%08x\n",
raw_intr, rx_msg_intr, mci->raw_intr,
mci->rx_msg_intr);
else {
mci->rx_msg_intr |= rx_msg_intr;
mci->raw_intr |= raw_intr;
*masked |= ATH9K_INT_MCI;
if (rx_msg_intr & AR_MCI_INTERRUPT_RX_MSG_CONT_INFO)
mci->cont_status =
REG_READ(ah, AR_MCI_CONT_STATUS);
REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, rx_msg_intr);
REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, raw_intr);
ath_dbg(common, ATH_DBG_MCI, "AR_INTR_SYNC_MCI\n");
}
}
sync_cause = REG_READ(ah, AR_INTR_SYNC_CAUSE) & AR_INTR_SYNC_DEFAULT; sync_cause = REG_READ(ah, AR_INTR_SYNC_CAUSE) & AR_INTR_SYNC_DEFAULT;
*masked = 0; *masked = 0;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,102 @@
/*
* Copyright (c) 2010-2011 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.
*/
#ifndef AR9003_MCI_H
#define AR9003_MCI_H
#define MCI_FLAG_DISABLE_TIMESTAMP 0x00000001 /* Disable time stamp */
/* Default remote BT device MCI COEX version */
#define MCI_GPM_COEX_MAJOR_VERSION_DEFAULT 3
#define MCI_GPM_COEX_MINOR_VERSION_DEFAULT 0
/* Local WLAN MCI COEX version */
#define MCI_GPM_COEX_MAJOR_VERSION_WLAN 3
#define MCI_GPM_COEX_MINOR_VERSION_WLAN 0
enum mci_gpm_coex_query_type {
MCI_GPM_COEX_QUERY_BT_ALL_INFO = BIT(0),
MCI_GPM_COEX_QUERY_BT_TOPOLOGY = BIT(1),
MCI_GPM_COEX_QUERY_BT_DEBUG = BIT(2),
};
enum mci_gpm_coex_halt_bt_gpm {
MCI_GPM_COEX_BT_GPM_UNHALT,
MCI_GPM_COEX_BT_GPM_HALT
};
enum mci_gpm_coex_bt_update_flags_op {
MCI_GPM_COEX_BT_FLAGS_READ,
MCI_GPM_COEX_BT_FLAGS_SET,
MCI_GPM_COEX_BT_FLAGS_CLEAR
};
#define MCI_NUM_BT_CHANNELS 79
#define MCI_BT_MCI_FLAGS_UPDATE_CORR 0x00000002
#define MCI_BT_MCI_FLAGS_UPDATE_HDR 0x00000004
#define MCI_BT_MCI_FLAGS_UPDATE_PLD 0x00000008
#define MCI_BT_MCI_FLAGS_LNA_CTRL 0x00000010
#define MCI_BT_MCI_FLAGS_DEBUG 0x00000020
#define MCI_BT_MCI_FLAGS_SCHED_MSG 0x00000040
#define MCI_BT_MCI_FLAGS_CONT_MSG 0x00000080
#define MCI_BT_MCI_FLAGS_COEX_GPM 0x00000100
#define MCI_BT_MCI_FLAGS_CPU_INT_MSG 0x00000200
#define MCI_BT_MCI_FLAGS_MCI_MODE 0x00000400
#define MCI_BT_MCI_FLAGS_AR9462_MODE 0x00001000
#define MCI_BT_MCI_FLAGS_OTHER 0x00010000
#define MCI_DEFAULT_BT_MCI_FLAGS 0x00011dde
#define MCI_TOGGLE_BT_MCI_FLAGS (MCI_BT_MCI_FLAGS_UPDATE_CORR | \
MCI_BT_MCI_FLAGS_UPDATE_HDR | \
MCI_BT_MCI_FLAGS_UPDATE_PLD | \
MCI_BT_MCI_FLAGS_MCI_MODE)
#define MCI_2G_FLAGS_CLEAR_MASK 0x00000000
#define MCI_2G_FLAGS_SET_MASK MCI_TOGGLE_BT_MCI_FLAGS
#define MCI_2G_FLAGS MCI_DEFAULT_BT_MCI_FLAGS
#define MCI_5G_FLAGS_CLEAR_MASK MCI_TOGGLE_BT_MCI_FLAGS
#define MCI_5G_FLAGS_SET_MASK 0x00000000
#define MCI_5G_FLAGS (MCI_DEFAULT_BT_MCI_FLAGS & \
~MCI_TOGGLE_BT_MCI_FLAGS)
/*
* Default value for AR9462 is 0x00002201
*/
#define ATH_MCI_CONFIG_CONCUR_TX 0x00000003
#define ATH_MCI_CONFIG_MCI_OBS_MCI 0x00000004
#define ATH_MCI_CONFIG_MCI_OBS_TXRX 0x00000008
#define ATH_MCI_CONFIG_MCI_OBS_BT 0x00000010
#define ATH_MCI_CONFIG_DISABLE_MCI_CAL 0x00000020
#define ATH_MCI_CONFIG_DISABLE_OSLA 0x00000040
#define ATH_MCI_CONFIG_DISABLE_FTP_STOMP 0x00000080
#define ATH_MCI_CONFIG_AGGR_THRESH 0x00000700
#define ATH_MCI_CONFIG_AGGR_THRESH_S 8
#define ATH_MCI_CONFIG_DISABLE_AGGR_THRESH 0x00000800
#define ATH_MCI_CONFIG_CLK_DIV 0x00003000
#define ATH_MCI_CONFIG_CLK_DIV_S 12
#define ATH_MCI_CONFIG_DISABLE_TUNING 0x00004000
#define ATH_MCI_CONFIG_MCI_WEIGHT_DBG 0x40000000
#define ATH_MCI_CONFIG_DISABLE_MCI 0x80000000
#define ATH_MCI_CONFIG_MCI_OBS_MASK (ATH_MCI_CONFIG_MCI_OBS_MCI | \
ATH_MCI_CONFIG_MCI_OBS_TXRX | \
ATH_MCI_CONFIG_MCI_OBS_BT)
#define ATH_MCI_CONFIG_MCI_OBS_GPIO 0x0000002F
#endif

View File

@ -490,6 +490,8 @@
#define AR_PHY_TEST_CTL_TSTADC_EN_S 8 #define AR_PHY_TEST_CTL_TSTADC_EN_S 8
#define AR_PHY_TEST_CTL_RX_OBS_SEL 0x3C00 #define AR_PHY_TEST_CTL_RX_OBS_SEL 0x3C00
#define AR_PHY_TEST_CTL_RX_OBS_SEL_S 10 #define AR_PHY_TEST_CTL_RX_OBS_SEL_S 10
#define AR_PHY_TEST_CTL_DEBUGPORT_SEL 0xe0000000
#define AR_PHY_TEST_CTL_DEBUGPORT_SEL_S 29
#define AR_PHY_TSTDAC (AR_SM_BASE + 0x168) #define AR_PHY_TSTDAC (AR_SM_BASE + 0x168)
@ -1001,6 +1003,7 @@
/* GLB Registers */ /* GLB Registers */
#define AR_GLB_BASE 0x20000 #define AR_GLB_BASE 0x20000
#define AR_GLB_GPIO_CONTROL (AR_GLB_BASE)
#define AR_PHY_GLB_CONTROL (AR_GLB_BASE + 0x44) #define AR_PHY_GLB_CONTROL (AR_GLB_BASE + 0x44)
#define AR_GLB_SCRATCH(_ah) (AR_GLB_BASE + \ #define AR_GLB_SCRATCH(_ah) (AR_GLB_BASE + \
(AR_SREV_9462_20(_ah) ? 0x4c : 0x50)) (AR_SREV_9462_20(_ah) ? 0x4c : 0x50))

View File

@ -462,7 +462,7 @@ void ath9k_btcoex_timer_pause(struct ath_softc *sc);
#define ATH_LED_PIN_9287 8 #define ATH_LED_PIN_9287 8
#define ATH_LED_PIN_9300 10 #define ATH_LED_PIN_9300 10
#define ATH_LED_PIN_9485 6 #define ATH_LED_PIN_9485 6
#define ATH_LED_PIN_9462 0 #define ATH_LED_PIN_9462 4
#ifdef CONFIG_MAC80211_LEDS #ifdef CONFIG_MAC80211_LEDS
void ath_init_leds(struct ath_softc *sc); void ath_init_leds(struct ath_softc *sc);
@ -647,6 +647,7 @@ struct ath_softc {
struct delayed_work tx_complete_work; struct delayed_work tx_complete_work;
struct delayed_work hw_pll_work; struct delayed_work hw_pll_work;
struct ath_btcoex btcoex; struct ath_btcoex btcoex;
struct ath_mci_coex mci_coex;
struct ath_descdma txsdma; struct ath_descdma txsdma;

View File

@ -21,7 +21,7 @@ enum ath_bt_mode {
ATH_BT_COEX_MODE_LEGACY, /* legacy rx_clear mode */ ATH_BT_COEX_MODE_LEGACY, /* legacy rx_clear mode */
ATH_BT_COEX_MODE_UNSLOTTED, /* untimed/unslotted mode */ ATH_BT_COEX_MODE_UNSLOTTED, /* untimed/unslotted mode */
ATH_BT_COEX_MODE_SLOTTED, /* slotted mode */ ATH_BT_COEX_MODE_SLOTTED, /* slotted mode */
ATH_BT_COEX_MODE_DISALBED, /* coexistence disabled */ ATH_BT_COEX_MODE_DISABLED, /* coexistence disabled */
}; };
struct ath_btcoex_config { struct ath_btcoex_config {

View File

@ -54,8 +54,39 @@ enum ath_btcoex_scheme {
ATH_BTCOEX_CFG_MCI, ATH_BTCOEX_CFG_MCI,
}; };
struct ath9k_hw_mci {
u32 raw_intr;
u32 rx_msg_intr;
u32 cont_status;
u32 gpm_addr;
u32 gpm_len;
u32 gpm_idx;
u32 sched_addr;
u32 wlan_channels[4];
u32 wlan_cal_seq;
u32 wlan_cal_done;
u32 config;
u8 *gpm_buf;
u8 *sched_buf;
bool ready;
bool update_2g5g;
bool is_2g;
bool query_bt;
bool unhalt_bt_gpm; /* need send UNHALT */
bool halted_bt_gpm; /* HALT sent */
bool need_flush_btinfo;
bool bt_version_known;
bool wlan_channels_update;
u8 wlan_ver_major;
u8 wlan_ver_minor;
u8 bt_ver_major;
u8 bt_ver_minor;
u8 bt_state;
};
struct ath_btcoex_hw { struct ath_btcoex_hw {
enum ath_btcoex_scheme scheme; enum ath_btcoex_scheme scheme;
struct ath9k_hw_mci mci;
bool enabled; bool enabled;
u8 wlanactive_gpio; u8 wlanactive_gpio;
u8 btactive_gpio; u8 btactive_gpio;

View File

@ -473,7 +473,7 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah,
int i; int i;
u16 twiceMinEdgePower; u16 twiceMinEdgePower;
u16 twiceMaxEdgePower = MAX_RATE_POWER; u16 twiceMaxEdgePower;
u16 scaledPower = 0, minCtlPower; u16 scaledPower = 0, minCtlPower;
u16 numCtlModes; u16 numCtlModes;
const u16 *pCtlMode; const u16 *pCtlMode;
@ -542,9 +542,7 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah,
else else
freq = centers.ctl_center; freq = centers.ctl_center;
if (ah->eep_ops->get_eeprom_ver(ah) == 14 && twiceMaxEdgePower = MAX_RATE_POWER;
ah->eep_ops->get_eeprom_rev(ah) <= 2)
twiceMaxEdgePower = MAX_RATE_POWER;
for (i = 0; (i < AR5416_EEP4K_NUM_CTLS) && for (i = 0; (i < AR5416_EEP4K_NUM_CTLS) &&
pEepData->ctlIndex[i]; i++) { pEepData->ctlIndex[i]; i++) {

View File

@ -569,7 +569,7 @@ static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah,
#define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 #define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6
#define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 #define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10
u16 twiceMaxEdgePower = MAX_RATE_POWER; u16 twiceMaxEdgePower;
int i; int i;
struct cal_ctl_data_ar9287 *rep; struct cal_ctl_data_ar9287 *rep;
struct cal_target_power_leg targetPowerOfdm = {0, {0, 0, 0, 0} }, struct cal_target_power_leg targetPowerOfdm = {0, {0, 0, 0, 0} },
@ -669,6 +669,7 @@ static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah,
else else
freq = centers.ctl_center; freq = centers.ctl_center;
twiceMaxEdgePower = MAX_RATE_POWER;
/* Walk through the CTL indices stored in EEPROM */ /* Walk through the CTL indices stored in EEPROM */
for (i = 0; (i < AR9287_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { for (i = 0; (i < AR9287_NUM_CTLS) && pEepData->ctlIndex[i]; i++) {
struct cal_ctl_edges *pRdEdgesPower; struct cal_ctl_edges *pRdEdgesPower;

View File

@ -1000,7 +1000,7 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah,
#define REDUCE_SCALED_POWER_BY_THREE_CHAIN 9 /* 10*log10(3)*2 */ #define REDUCE_SCALED_POWER_BY_THREE_CHAIN 9 /* 10*log10(3)*2 */
struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; struct ar5416_eeprom_def *pEepData = &ah->eeprom.def;
u16 twiceMaxEdgePower = MAX_RATE_POWER; u16 twiceMaxEdgePower;
int i; int i;
struct cal_ctl_data *rep; struct cal_ctl_data *rep;
struct cal_target_power_leg targetPowerOfdm, targetPowerCck = { struct cal_target_power_leg targetPowerOfdm, targetPowerCck = {
@ -1121,9 +1121,7 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah,
else else
freq = centers.ctl_center; freq = centers.ctl_center;
if (ah->eep_ops->get_eeprom_ver(ah) == 14 && twiceMaxEdgePower = MAX_RATE_POWER;
ah->eep_ops->get_eeprom_rev(ah) <= 2)
twiceMaxEdgePower = MAX_RATE_POWER;
for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) {
if ((((cfgCtl & ~CTL_MODE_M) | if ((((cfgCtl & ~CTL_MODE_M) |

View File

@ -1350,6 +1350,7 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah)
static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type) static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type)
{ {
bool ret = false;
if (AR_SREV_9300_20_OR_LATER(ah)) { if (AR_SREV_9300_20_OR_LATER(ah)) {
REG_WRITE(ah, AR_WA, ah->WARegVal); REG_WRITE(ah, AR_WA, ah->WARegVal);
@ -1361,13 +1362,20 @@ static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type)
switch (type) { switch (type) {
case ATH9K_RESET_POWER_ON: case ATH9K_RESET_POWER_ON:
return ath9k_hw_set_reset_power_on(ah); ret = ath9k_hw_set_reset_power_on(ah);
break;
case ATH9K_RESET_WARM: case ATH9K_RESET_WARM:
case ATH9K_RESET_COLD: case ATH9K_RESET_COLD:
return ath9k_hw_set_reset(ah, type); ret = ath9k_hw_set_reset(ah, type);
break;
default: default:
return false; break;
} }
if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
return ret;
} }
static bool ath9k_hw_chip_reset(struct ath_hw *ah, static bool ath9k_hw_chip_reset(struct ath_hw *ah,
@ -1506,6 +1514,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
struct ath9k_hw_cal_data *caldata, bool bChannelChange) struct ath9k_hw_cal_data *caldata, bool bChannelChange)
{ {
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
u32 saveLedState; u32 saveLedState;
struct ath9k_channel *curchan = ah->curchan; struct ath9k_channel *curchan = ah->curchan;
u32 saveDefAntenna; u32 saveDefAntenna;
@ -1513,6 +1522,53 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
u64 tsf = 0; u64 tsf = 0;
int i, r; int i, r;
bool allow_fbs = false; bool allow_fbs = false;
bool mci = !!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI);
bool save_fullsleep = ah->chip_fullsleep;
if (mci) {
ar9003_mci_2g5g_changed(ah, IS_CHAN_2GHZ(chan));
if (mci_hw->bt_state == MCI_BT_CAL_START) {
u32 payload[4] = {0, 0, 0, 0};
ath_dbg(common, ATH_DBG_MCI, "MCI stop rx for BT CAL");
mci_hw->bt_state = MCI_BT_CAL;
/*
* MCI FIX: disable mci interrupt here. This is to avoid
* SW_MSG_DONE or RX_MSG bits to trigger MCI_INT and
* lead to mci_intr reentry.
*/
ar9003_mci_disable_interrupt(ah);
ath_dbg(common, ATH_DBG_MCI, "send WLAN_CAL_GRANT");
MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_GRANT);
ar9003_mci_send_message(ah, MCI_GPM, 0, payload,
16, true, false);
ath_dbg(common, ATH_DBG_MCI, "\nMCI BT is calibrating");
/* Wait BT calibration to be completed for 25ms */
if (ar9003_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_DONE,
0, 25000))
ath_dbg(common, ATH_DBG_MCI,
"MCI got BT_CAL_DONE\n");
else
ath_dbg(common, ATH_DBG_MCI,
"MCI ### BT cal takes to long, force"
"bt_state to be bt_awake\n");
mci_hw->bt_state = MCI_BT_AWAKE;
/* MCI FIX: enable mci interrupt here */
ar9003_mci_enable_interrupt(ah);
return true;
}
}
if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
return -EIO; return -EIO;
@ -1550,12 +1606,29 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
if (ath9k_hw_channel_change(ah, chan)) { if (ath9k_hw_channel_change(ah, chan)) {
ath9k_hw_loadnf(ah, ah->curchan); ath9k_hw_loadnf(ah, ah->curchan);
ath9k_hw_start_nfcal(ah, true); ath9k_hw_start_nfcal(ah, true);
if (mci && mci_hw->ready)
ar9003_mci_2g5g_switch(ah, true);
if (AR_SREV_9271(ah)) if (AR_SREV_9271(ah))
ar9002_hw_load_ani_reg(ah, chan); ar9002_hw_load_ani_reg(ah, chan);
return 0; return 0;
} }
} }
if (mci) {
ar9003_mci_disable_interrupt(ah);
if (mci_hw->ready && !save_fullsleep) {
ar9003_mci_mute_bt(ah);
udelay(20);
REG_WRITE(ah, AR_BTCOEX_CTRL, 0);
}
mci_hw->bt_state = MCI_BT_SLEEP;
mci_hw->ready = false;
}
saveDefAntenna = REG_READ(ah, AR_DEF_ANTENNA); saveDefAntenna = REG_READ(ah, AR_DEF_ANTENNA);
if (saveDefAntenna == 0) if (saveDefAntenna == 0)
saveDefAntenna = 1; saveDefAntenna = 1;
@ -1611,6 +1684,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
if (r) if (r)
return r; return r;
if (mci)
ar9003_mci_reset(ah, false, IS_CHAN_2GHZ(chan), save_fullsleep);
/* /*
* Some AR91xx SoC devices frequently fail to accept TSF writes * Some AR91xx SoC devices frequently fail to accept TSF writes
* right after the chip reset. When that happens, write a new * right after the chip reset. When that happens, write a new
@ -1728,6 +1804,55 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
ath9k_hw_loadnf(ah, chan); ath9k_hw_loadnf(ah, chan);
ath9k_hw_start_nfcal(ah, true); ath9k_hw_start_nfcal(ah, true);
if (mci && mci_hw->ready) {
if (IS_CHAN_2GHZ(chan) &&
(mci_hw->bt_state == MCI_BT_SLEEP)) {
if (ar9003_mci_check_int(ah,
AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET) ||
ar9003_mci_check_int(ah,
AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)) {
/*
* BT is sleeping. Check if BT wakes up during
* WLAN calibration. If BT wakes up during
* WLAN calibration, need to go through all
* message exchanges again and recal.
*/
ath_dbg(common, ATH_DBG_MCI, "MCI BT wakes up"
"during WLAN calibration\n");
REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET |
AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE);
ath_dbg(common, ATH_DBG_MCI, "MCI send"
"REMOTE_RESET\n");
ar9003_mci_remote_reset(ah, true);
ar9003_mci_send_sys_waking(ah, true);
udelay(1);
if (IS_CHAN_2GHZ(chan))
ar9003_mci_send_lna_transfer(ah, true);
mci_hw->bt_state = MCI_BT_AWAKE;
ath_dbg(common, ATH_DBG_MCI, "MCI re-cal\n");
if (caldata) {
caldata->done_txiqcal_once = false;
caldata->done_txclcal_once = false;
caldata->rtt_hist.num_readings = 0;
}
if (!ath9k_hw_init_cal(ah, chan))
return -EIO;
}
}
ar9003_mci_enable_interrupt(ah);
}
ENABLE_REGWRITE_BUFFER(ah); ENABLE_REGWRITE_BUFFER(ah);
ath9k_hw_restore_chainmask(ah); ath9k_hw_restore_chainmask(ah);
@ -1770,6 +1895,21 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
if (ah->btcoex_hw.enabled) if (ah->btcoex_hw.enabled)
ath9k_hw_btcoex_enable(ah); ath9k_hw_btcoex_enable(ah);
if (mci && mci_hw->ready) {
/*
* check BT state again to make
* sure it's not changed.
*/
ar9003_mci_sync_bt_state(ah);
ar9003_mci_2g5g_switch(ah, true);
if ((mci_hw->bt_state == MCI_BT_AWAKE) &&
(mci_hw->query_bt == true)) {
mci_hw->need_flush_btinfo = true;
}
}
if (AR_SREV_9300_20_OR_LATER(ah)) { if (AR_SREV_9300_20_OR_LATER(ah)) {
ar9003_hw_bb_watchdog_config(ah); ar9003_hw_bb_watchdog_config(ah);
@ -1934,6 +2074,7 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode) bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
{ {
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
int status = true, setChip = true; int status = true, setChip = true;
static const char *modes[] = { static const char *modes[] = {
"AWAKE", "AWAKE",
@ -1951,12 +2092,35 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
switch (mode) { switch (mode) {
case ATH9K_PM_AWAKE: case ATH9K_PM_AWAKE:
status = ath9k_hw_set_power_awake(ah, setChip); status = ath9k_hw_set_power_awake(ah, setChip);
if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
break; break;
case ATH9K_PM_FULL_SLEEP: case ATH9K_PM_FULL_SLEEP:
if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI) {
if (ar9003_mci_state(ah, MCI_STATE_ENABLE, NULL) &&
(mci->bt_state != MCI_BT_SLEEP) &&
!mci->halted_bt_gpm) {
ath_dbg(common, ATH_DBG_MCI, "MCI halt BT GPM"
"(full_sleep)");
ar9003_mci_send_coex_halt_bt_gpm(ah,
true, true);
}
mci->ready = false;
REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
}
ath9k_set_power_sleep(ah, setChip); ath9k_set_power_sleep(ah, setChip);
ah->chip_fullsleep = true; ah->chip_fullsleep = true;
break; break;
case ATH9K_PM_NETWORK_SLEEP: case ATH9K_PM_NETWORK_SLEEP:
if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
ath9k_set_power_network_sleep(ah, setChip); ath9k_set_power_network_sleep(ah, setChip);
break; break;
default: default:
@ -2149,6 +2313,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
if (AR_SREV_9485(ah) || AR_SREV_9285(ah) || AR_SREV_9330(ah)) if (AR_SREV_9485(ah) || AR_SREV_9285(ah) || AR_SREV_9330(ah))
chip_chainmask = 1; chip_chainmask = 1;
else if (AR_SREV_9462(ah))
chip_chainmask = 3;
else if (!AR_SREV_9280_20_OR_LATER(ah)) else if (!AR_SREV_9280_20_OR_LATER(ah))
chip_chainmask = 7; chip_chainmask = 7;
else if (!AR_SREV_9300_20_OR_LATER(ah) || AR_SREV_9340(ah)) else if (!AR_SREV_9300_20_OR_LATER(ah) || AR_SREV_9340(ah))
@ -2234,7 +2400,9 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS; pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS;
if (common->btcoex_enabled) { if (common->btcoex_enabled) {
if (AR_SREV_9300_20_OR_LATER(ah)) { if (AR_SREV_9462(ah))
btcoex_hw->scheme = ATH_BTCOEX_CFG_MCI;
else if (AR_SREV_9300_20_OR_LATER(ah)) {
btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE; btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE;
btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9300; btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9300;
btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9300; btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9300;
@ -2332,7 +2500,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
if (AR_SREV_9300_20_OR_LATER(ah)) { if (AR_SREV_9300_20_OR_LATER(ah)) {
ah->enabled_cals |= TX_IQ_CAL; ah->enabled_cals |= TX_IQ_CAL;
if (!AR_SREV_9330(ah)) if (AR_SREV_9485_OR_LATER(ah))
ah->enabled_cals |= TX_IQ_ON_AGC_CAL; ah->enabled_cals |= TX_IQ_ON_AGC_CAL;
} }
if (AR_SREV_9462(ah)) if (AR_SREV_9462(ah))

View File

@ -126,6 +126,16 @@
#define AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL 4 #define AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL 4
#define AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED 5 #define AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED 5
#define AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED 6 #define AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED 6
#define AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_DATA 0x16
#define AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_CLK 0x17
#define AR_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA 0x18
#define AR_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK 0x19
#define AR_GPIO_OUTPUT_MUX_AS_WL_IN_TX 0x14
#define AR_GPIO_OUTPUT_MUX_AS_WL_IN_RX 0x13
#define AR_GPIO_OUTPUT_MUX_AS_BT_IN_TX 9
#define AR_GPIO_OUTPUT_MUX_AS_BT_IN_RX 8
#define AR_GPIO_OUTPUT_MUX_AS_RUCKUS_STROBE 0x1d
#define AR_GPIO_OUTPUT_MUX_AS_RUCKUS_DATA 0x1e
#define AR_GPIOD_MASK 0x00001FFF #define AR_GPIOD_MASK 0x00001FFF
#define AR_GPIO_BIT(_gpio) (1 << (_gpio)) #define AR_GPIO_BIT(_gpio) (1 << (_gpio))
@ -266,6 +276,7 @@ enum ath9k_int {
ATH9K_INT_TX = 0x00000040, ATH9K_INT_TX = 0x00000040,
ATH9K_INT_TXDESC = 0x00000080, ATH9K_INT_TXDESC = 0x00000080,
ATH9K_INT_TIM_TIMER = 0x00000100, ATH9K_INT_TIM_TIMER = 0x00000100,
ATH9K_INT_MCI = 0x00000200,
ATH9K_INT_BB_WATCHDOG = 0x00000400, ATH9K_INT_BB_WATCHDOG = 0x00000400,
ATH9K_INT_TXURN = 0x00000800, ATH9K_INT_TXURN = 0x00000800,
ATH9K_INT_MIB = 0x00001000, ATH9K_INT_MIB = 0x00001000,
@ -417,6 +428,25 @@ enum ath9k_rx_qtype {
ATH9K_RX_QUEUE_MAX, ATH9K_RX_QUEUE_MAX,
}; };
enum mci_message_header { /* length of payload */
MCI_LNA_CTRL = 0x10, /* len = 0 */
MCI_CONT_NACK = 0x20, /* len = 0 */
MCI_CONT_INFO = 0x30, /* len = 4 */
MCI_CONT_RST = 0x40, /* len = 0 */
MCI_SCHD_INFO = 0x50, /* len = 16 */
MCI_CPU_INT = 0x60, /* len = 4 */
MCI_SYS_WAKING = 0x70, /* len = 0 */
MCI_GPM = 0x80, /* len = 16 */
MCI_LNA_INFO = 0x90, /* len = 1 */
MCI_LNA_STATE = 0x94,
MCI_LNA_TAKE = 0x98,
MCI_LNA_TRANS = 0x9c,
MCI_SYS_SLEEPING = 0xa0, /* len = 0 */
MCI_REQ_WAKE = 0xc0, /* len = 0 */
MCI_DEBUG_16 = 0xfe, /* len = 2 */
MCI_REMOTE_RESET = 0xff /* len = 16 */
};
enum ath_mci_gpm_coex_profile_type { enum ath_mci_gpm_coex_profile_type {
MCI_GPM_COEX_PROFILE_UNKNOWN, MCI_GPM_COEX_PROFILE_UNKNOWN,
MCI_GPM_COEX_PROFILE_RFCOMM, MCI_GPM_COEX_PROFILE_RFCOMM,
@ -427,6 +457,132 @@ enum ath_mci_gpm_coex_profile_type {
MCI_GPM_COEX_PROFILE_MAX MCI_GPM_COEX_PROFILE_MAX
}; };
/* MCI GPM/Coex opcode/type definitions */
enum {
MCI_GPM_COEX_W_GPM_PAYLOAD = 1,
MCI_GPM_COEX_B_GPM_TYPE = 4,
MCI_GPM_COEX_B_GPM_OPCODE = 5,
/* MCI_GPM_WLAN_CAL_REQ, MCI_GPM_WLAN_CAL_DONE */
MCI_GPM_WLAN_CAL_W_SEQUENCE = 2,
/* MCI_GPM_COEX_VERSION_QUERY */
/* MCI_GPM_COEX_VERSION_RESPONSE */
MCI_GPM_COEX_B_MAJOR_VERSION = 6,
MCI_GPM_COEX_B_MINOR_VERSION = 7,
/* MCI_GPM_COEX_STATUS_QUERY */
MCI_GPM_COEX_B_BT_BITMAP = 6,
MCI_GPM_COEX_B_WLAN_BITMAP = 7,
/* MCI_GPM_COEX_HALT_BT_GPM */
MCI_GPM_COEX_B_HALT_STATE = 6,
/* MCI_GPM_COEX_WLAN_CHANNELS */
MCI_GPM_COEX_B_CHANNEL_MAP = 6,
/* MCI_GPM_COEX_BT_PROFILE_INFO */
MCI_GPM_COEX_B_PROFILE_TYPE = 6,
MCI_GPM_COEX_B_PROFILE_LINKID = 7,
MCI_GPM_COEX_B_PROFILE_STATE = 8,
MCI_GPM_COEX_B_PROFILE_ROLE = 9,
MCI_GPM_COEX_B_PROFILE_RATE = 10,
MCI_GPM_COEX_B_PROFILE_VOTYPE = 11,
MCI_GPM_COEX_H_PROFILE_T = 12,
MCI_GPM_COEX_B_PROFILE_W = 14,
MCI_GPM_COEX_B_PROFILE_A = 15,
/* MCI_GPM_COEX_BT_STATUS_UPDATE */
MCI_GPM_COEX_B_STATUS_TYPE = 6,
MCI_GPM_COEX_B_STATUS_LINKID = 7,
MCI_GPM_COEX_B_STATUS_STATE = 8,
/* MCI_GPM_COEX_BT_UPDATE_FLAGS */
MCI_GPM_COEX_W_BT_FLAGS = 6,
MCI_GPM_COEX_B_BT_FLAGS_OP = 10
};
enum mci_gpm_subtype {
MCI_GPM_BT_CAL_REQ = 0,
MCI_GPM_BT_CAL_GRANT = 1,
MCI_GPM_BT_CAL_DONE = 2,
MCI_GPM_WLAN_CAL_REQ = 3,
MCI_GPM_WLAN_CAL_GRANT = 4,
MCI_GPM_WLAN_CAL_DONE = 5,
MCI_GPM_COEX_AGENT = 0x0c,
MCI_GPM_RSVD_PATTERN = 0xfe,
MCI_GPM_RSVD_PATTERN32 = 0xfefefefe,
MCI_GPM_BT_DEBUG = 0xff
};
enum mci_bt_state {
MCI_BT_SLEEP,
MCI_BT_AWAKE,
MCI_BT_CAL_START,
MCI_BT_CAL
};
/* Type of state query */
enum mci_state_type {
MCI_STATE_ENABLE,
MCI_STATE_INIT_GPM_OFFSET,
MCI_STATE_NEXT_GPM_OFFSET,
MCI_STATE_LAST_GPM_OFFSET,
MCI_STATE_BT,
MCI_STATE_SET_BT_SLEEP,
MCI_STATE_SET_BT_AWAKE,
MCI_STATE_SET_BT_CAL_START,
MCI_STATE_SET_BT_CAL,
MCI_STATE_LAST_SCHD_MSG_OFFSET,
MCI_STATE_REMOTE_SLEEP,
MCI_STATE_CONT_RSSI_POWER,
MCI_STATE_CONT_PRIORITY,
MCI_STATE_CONT_TXRX,
MCI_STATE_RESET_REQ_WAKE,
MCI_STATE_SEND_WLAN_COEX_VERSION,
MCI_STATE_SET_BT_COEX_VERSION,
MCI_STATE_SEND_WLAN_CHANNELS,
MCI_STATE_SEND_VERSION_QUERY,
MCI_STATE_SEND_STATUS_QUERY,
MCI_STATE_NEED_FLUSH_BT_INFO,
MCI_STATE_SET_CONCUR_TX_PRI,
MCI_STATE_RECOVER_RX,
MCI_STATE_NEED_FTP_STOMP,
MCI_STATE_NEED_TUNING,
MCI_STATE_DEBUG,
MCI_STATE_MAX
};
enum mci_gpm_coex_opcode {
MCI_GPM_COEX_VERSION_QUERY,
MCI_GPM_COEX_VERSION_RESPONSE,
MCI_GPM_COEX_STATUS_QUERY,
MCI_GPM_COEX_HALT_BT_GPM,
MCI_GPM_COEX_WLAN_CHANNELS,
MCI_GPM_COEX_BT_PROFILE_INFO,
MCI_GPM_COEX_BT_STATUS_UPDATE,
MCI_GPM_COEX_BT_UPDATE_FLAGS
};
#define MCI_GPM_NOMORE 0
#define MCI_GPM_MORE 1
#define MCI_GPM_INVALID 0xffffffff
#define MCI_GPM_RECYCLE(_p_gpm) do { \
*(((u32 *)_p_gpm) + MCI_GPM_COEX_W_GPM_PAYLOAD) = \
MCI_GPM_RSVD_PATTERN32; \
} while (0)
#define MCI_GPM_TYPE(_p_gpm) \
(*(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_TYPE) & 0xff)
#define MCI_GPM_OPCODE(_p_gpm) \
(*(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_OPCODE) & 0xff)
#define MCI_GPM_SET_CAL_TYPE(_p_gpm, _cal_type) do { \
*(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_TYPE) = (_cal_type) & 0xff;\
} while (0)
#define MCI_GPM_SET_TYPE_OPCODE(_p_gpm, _type, _opcode) do { \
*(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_TYPE) = (_type) & 0xff; \
*(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_OPCODE) = (_opcode) & 0xff;\
} while (0)
#define MCI_GPM_IS_CAL_TYPE(_type) ((_type) <= MCI_GPM_WLAN_CAL_DONE)
struct ath9k_beacon_state { struct ath9k_beacon_state {
u32 bs_nexttbtt; u32 bs_nexttbtt;
u32 bs_nextdtim; u32 bs_nextdtim;
@ -1047,6 +1203,32 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning);
void ath9k_hw_proc_mib_event(struct ath_hw *ah); void ath9k_hw_proc_mib_event(struct ath_hw *ah);
void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan); void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan);
bool ar9003_mci_send_message(struct ath_hw *ah, u8 header, u32 flag,
u32 *payload, u8 len, bool wait_done,
bool check_bt);
void ar9003_mci_mute_bt(struct ath_hw *ah);
u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data);
void ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf,
u16 len, u32 sched_addr);
void ar9003_mci_cleanup(struct ath_hw *ah);
void ar9003_mci_send_coex_halt_bt_gpm(struct ath_hw *ah, bool halt,
bool wait_done);
u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type,
u8 gpm_opcode, int time_out);
void ar9003_mci_2g5g_changed(struct ath_hw *ah, bool is_2g);
void ar9003_mci_disable_interrupt(struct ath_hw *ah);
void ar9003_mci_enable_interrupt(struct ath_hw *ah);
void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool wait_done);
void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
bool is_full_sleep);
bool ar9003_mci_check_int(struct ath_hw *ah, u32 ints);
void ar9003_mci_remote_reset(struct ath_hw *ah, bool wait_done);
void ar9003_mci_send_sys_waking(struct ath_hw *ah, bool wait_done);
void ar9003_mci_send_lna_transfer(struct ath_hw *ah, bool wait_done);
void ar9003_mci_sync_bt_state(struct ath_hw *ah);
void ar9003_mci_get_interrupt(struct ath_hw *ah, u32 *raw_intr,
u32 *rx_msg_intr);
#define ATH9K_CLOCK_RATE_CCK 22 #define ATH9K_CLOCK_RATE_CCK 22
#define ATH9K_CLOCK_RATE_5GHZ_OFDM 40 #define ATH9K_CLOCK_RATE_5GHZ_OFDM 40
#define ATH9K_CLOCK_RATE_2GHZ_OFDM 44 #define ATH9K_CLOCK_RATE_2GHZ_OFDM 44

View File

@ -408,6 +408,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
static int ath9k_init_btcoex(struct ath_softc *sc) static int ath9k_init_btcoex(struct ath_softc *sc)
{ {
struct ath_txq *txq; struct ath_txq *txq;
struct ath_hw *ah = sc->sc_ah;
int r; int r;
switch (sc->sc_ah->btcoex_hw.scheme) { switch (sc->sc_ah->btcoex_hw.scheme) {
@ -423,9 +424,38 @@ static int ath9k_init_btcoex(struct ath_softc *sc)
return -1; return -1;
txq = sc->tx.txq_map[WME_AC_BE]; txq = sc->tx.txq_map[WME_AC_BE];
ath9k_hw_init_btcoex_hw(sc->sc_ah, txq->axq_qnum); ath9k_hw_init_btcoex_hw(sc->sc_ah, txq->axq_qnum);
sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
break;
case ATH_BTCOEX_CFG_MCI:
sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW; sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
sc->btcoex.duty_cycle = ATH_BTCOEX_DEF_DUTY_CYCLE; sc->btcoex.duty_cycle = ATH_BTCOEX_DEF_DUTY_CYCLE;
INIT_LIST_HEAD(&sc->btcoex.mci.info); INIT_LIST_HEAD(&sc->btcoex.mci.info);
r = ath_mci_setup(sc);
if (r)
return r;
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI) {
ah->btcoex_hw.mci.ready = false;
ah->btcoex_hw.mci.bt_state = 0;
ah->btcoex_hw.mci.bt_ver_major = 3;
ah->btcoex_hw.mci.bt_ver_minor = 0;
ah->btcoex_hw.mci.bt_version_known = false;
ah->btcoex_hw.mci.update_2g5g = true;
ah->btcoex_hw.mci.is_2g = true;
ah->btcoex_hw.mci.wlan_channels_update = false;
ah->btcoex_hw.mci.wlan_channels[0] = 0x00000000;
ah->btcoex_hw.mci.wlan_channels[1] = 0xffffffff;
ah->btcoex_hw.mci.wlan_channels[2] = 0xffffffff;
ah->btcoex_hw.mci.wlan_channels[3] = 0x7fffffff;
ah->btcoex_hw.mci.query_bt = true;
ah->btcoex_hw.mci.unhalt_bt_gpm = true;
ah->btcoex_hw.mci.halted_bt_gpm = false;
ah->btcoex_hw.mci.need_flush_btinfo = false;
ah->btcoex_hw.mci.wlan_cal_seq = 0;
ah->btcoex_hw.mci.wlan_cal_done = 0;
ah->btcoex_hw.mci.config = 0x2201;
}
break; break;
default: default:
WARN_ON(1); WARN_ON(1);
@ -839,6 +869,9 @@ static void ath9k_deinit_softc(struct ath_softc *sc)
sc->sc_ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) sc->sc_ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
ath_gen_timer_free(sc->sc_ah, sc->btcoex.no_stomp_timer); ath_gen_timer_free(sc->sc_ah, sc->btcoex.no_stomp_timer);
if (sc->sc_ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_MCI)
ath_mci_cleanup(sc);
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
if (ATH_TXQ_SETUP(sc, i)) if (ATH_TXQ_SETUP(sc, i))
ath_tx_cleanupq(sc, &sc->tx.txq[i]); ath_tx_cleanupq(sc, &sc->tx.txq[i]);

View File

@ -760,7 +760,10 @@ bool ath9k_hw_intrpend(struct ath_hw *ah)
return true; return true;
host_isr = REG_READ(ah, AR_INTR_ASYNC_CAUSE); host_isr = REG_READ(ah, AR_INTR_ASYNC_CAUSE);
if ((host_isr & AR_INTR_MAC_IRQ) && (host_isr != AR_INTR_SPURIOUS))
if (((host_isr & AR_INTR_MAC_IRQ) ||
(host_isr & AR_INTR_ASYNC_MASK_MCI)) &&
(host_isr != AR_INTR_SPURIOUS))
return true; return true;
host_isr = REG_READ(ah, AR_INTR_SYNC_CAUSE); host_isr = REG_READ(ah, AR_INTR_SYNC_CAUSE);
@ -798,6 +801,7 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah)
{ {
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
u32 sync_default = AR_INTR_SYNC_DEFAULT; u32 sync_default = AR_INTR_SYNC_DEFAULT;
u32 async_mask;
if (!(ah->imask & ATH9K_INT_GLOBAL)) if (!(ah->imask & ATH9K_INT_GLOBAL))
return; return;
@ -812,13 +816,16 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah)
if (AR_SREV_9340(ah)) if (AR_SREV_9340(ah))
sync_default &= ~AR_INTR_SYNC_HOST1_FATAL; sync_default &= ~AR_INTR_SYNC_HOST1_FATAL;
async_mask = AR_INTR_MAC_IRQ;
if (ah->imask & ATH9K_INT_MCI)
async_mask |= AR_INTR_ASYNC_MASK_MCI;
ath_dbg(common, ATH_DBG_INTERRUPT, "enable IER\n"); ath_dbg(common, ATH_DBG_INTERRUPT, "enable IER\n");
REG_WRITE(ah, AR_IER, AR_IER_ENABLE); REG_WRITE(ah, AR_IER, AR_IER_ENABLE);
if (!AR_SREV_9100(ah)) { if (!AR_SREV_9100(ah)) {
REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, async_mask);
AR_INTR_MAC_IRQ); REG_WRITE(ah, AR_INTR_ASYNC_MASK, async_mask);
REG_WRITE(ah, AR_INTR_ASYNC_MASK, AR_INTR_MAC_IRQ);
REG_WRITE(ah, AR_INTR_SYNC_ENABLE, sync_default); REG_WRITE(ah, AR_INTR_SYNC_ENABLE, sync_default);
REG_WRITE(ah, AR_INTR_SYNC_MASK, sync_default); REG_WRITE(ah, AR_INTR_SYNC_MASK, sync_default);

View File

@ -742,6 +742,9 @@ void ath9k_tasklet(unsigned long data)
if (status & ATH9K_INT_GENTIMER) if (status & ATH9K_INT_GENTIMER)
ath_gen_timer_isr(sc->sc_ah); ath_gen_timer_isr(sc->sc_ah);
if (status & ATH9K_INT_MCI)
ath_mci_intr(sc);
out: out:
/* re-enable hardware interrupt */ /* re-enable hardware interrupt */
ath9k_hw_enable_interrupts(ah); ath9k_hw_enable_interrupts(ah);
@ -764,7 +767,8 @@ irqreturn_t ath_isr(int irq, void *dev)
ATH9K_INT_BMISS | \ ATH9K_INT_BMISS | \
ATH9K_INT_CST | \ ATH9K_INT_CST | \
ATH9K_INT_TSFOOR | \ ATH9K_INT_TSFOOR | \
ATH9K_INT_GENTIMER) ATH9K_INT_GENTIMER | \
ATH9K_INT_MCI)
struct ath_softc *sc = dev; struct ath_softc *sc = dev;
struct ath_hw *ah = sc->sc_ah; struct ath_hw *ah = sc->sc_ah;
@ -1119,6 +1123,9 @@ static int ath9k_start(struct ieee80211_hw *hw)
if (ah->caps.hw_caps & ATH9K_HW_CAP_HT) if (ah->caps.hw_caps & ATH9K_HW_CAP_HT)
ah->imask |= ATH9K_INT_CST; ah->imask |= ATH9K_INT_CST;
if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
ah->imask |= ATH9K_INT_MCI;
sc->sc_flags &= ~SC_OP_INVALID; sc->sc_flags &= ~SC_OP_INVALID;
sc->sc_ah->is_monitoring = false; sc->sc_ah->is_monitoring = false;

View File

@ -14,6 +14,9 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include "ath9k.h" #include "ath9k.h"
#include "mci.h" #include "mci.h"
@ -181,6 +184,56 @@ static void ath_mci_update_scheme(struct ath_softc *sc)
ath9k_btcoex_timer_resume(sc); ath9k_btcoex_timer_resume(sc);
} }
static void ath_mci_cal_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload)
{
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
u32 payload[4] = {0, 0, 0, 0};
switch (opcode) {
case MCI_GPM_BT_CAL_REQ:
ath_dbg(common, ATH_DBG_MCI, "MCI received BT_CAL_REQ\n");
if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_AWAKE) {
ar9003_mci_state(ah, MCI_STATE_SET_BT_CAL_START, NULL);
ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
} else
ath_dbg(common, ATH_DBG_MCI,
"MCI State mismatches: %d\n",
ar9003_mci_state(ah, MCI_STATE_BT, NULL));
break;
case MCI_GPM_BT_CAL_DONE:
ath_dbg(common, ATH_DBG_MCI, "MCI received BT_CAL_DONE\n");
if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_CAL)
ath_dbg(common, ATH_DBG_MCI, "MCI error illegal!\n");
else
ath_dbg(common, ATH_DBG_MCI, "MCI BT not in CAL state\n");
break;
case MCI_GPM_BT_CAL_GRANT:
ath_dbg(common, ATH_DBG_MCI, "MCI received BT_CAL_GRANT\n");
/* Send WLAN_CAL_DONE for now */
ath_dbg(common, ATH_DBG_MCI, "MCI send WLAN_CAL_DONE\n");
MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_DONE);
ar9003_mci_send_message(sc->sc_ah, MCI_GPM, 0, payload,
16, false, true);
break;
default:
ath_dbg(common, ATH_DBG_MCI, "MCI Unknown GPM CAL message\n");
break;
}
}
void ath_mci_process_profile(struct ath_softc *sc, void ath_mci_process_profile(struct ath_softc *sc,
struct ath_mci_profile_info *info) struct ath_mci_profile_info *info)
{ {
@ -252,3 +305,369 @@ void ath_mci_process_status(struct ath_softc *sc,
if (old_num_mgmt != mci->num_mgmt) if (old_num_mgmt != mci->num_mgmt)
ath_mci_update_scheme(sc); ath_mci_update_scheme(sc);
} }
static void ath_mci_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload)
{
struct ath_hw *ah = sc->sc_ah;
struct ath_mci_profile_info profile_info;
struct ath_mci_profile_status profile_status;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
u32 version;
u8 major;
u8 minor;
u32 seq_num;
switch (opcode) {
case MCI_GPM_COEX_VERSION_QUERY:
ath_dbg(common, ATH_DBG_MCI,
"MCI Recv GPM COEX Version Query.\n");
version = ar9003_mci_state(ah,
MCI_STATE_SEND_WLAN_COEX_VERSION, NULL);
break;
case MCI_GPM_COEX_VERSION_RESPONSE:
ath_dbg(common, ATH_DBG_MCI,
"MCI Recv GPM COEX Version Response.\n");
major = *(rx_payload + MCI_GPM_COEX_B_MAJOR_VERSION);
minor = *(rx_payload + MCI_GPM_COEX_B_MINOR_VERSION);
ath_dbg(common, ATH_DBG_MCI,
"MCI BT Coex version: %d.%d\n", major, minor);
version = (major << 8) + minor;
version = ar9003_mci_state(ah,
MCI_STATE_SET_BT_COEX_VERSION, &version);
break;
case MCI_GPM_COEX_STATUS_QUERY:
ath_dbg(common, ATH_DBG_MCI,
"MCI Recv GPM COEX Status Query = 0x%02x.\n",
*(rx_payload + MCI_GPM_COEX_B_WLAN_BITMAP));
ar9003_mci_state(ah,
MCI_STATE_SEND_WLAN_CHANNELS, NULL);
break;
case MCI_GPM_COEX_BT_PROFILE_INFO:
ath_dbg(common, ATH_DBG_MCI,
"MCI Recv GPM Coex BT profile info\n");
memcpy(&profile_info,
(rx_payload + MCI_GPM_COEX_B_PROFILE_TYPE), 10);
if ((profile_info.type == MCI_GPM_COEX_PROFILE_UNKNOWN)
|| (profile_info.type >=
MCI_GPM_COEX_PROFILE_MAX)) {
ath_dbg(common, ATH_DBG_MCI,
"illegal profile type = %d,"
"state = %d\n", profile_info.type,
profile_info.start);
break;
}
ath_mci_process_profile(sc, &profile_info);
break;
case MCI_GPM_COEX_BT_STATUS_UPDATE:
profile_status.is_link = *(rx_payload +
MCI_GPM_COEX_B_STATUS_TYPE);
profile_status.conn_handle = *(rx_payload +
MCI_GPM_COEX_B_STATUS_LINKID);
profile_status.is_critical = *(rx_payload +
MCI_GPM_COEX_B_STATUS_STATE);
seq_num = *((u32 *)(rx_payload + 12));
ath_dbg(common, ATH_DBG_MCI,
"MCI Recv GPM COEX BT_Status_Update: "
"is_link=%d, linkId=%d, state=%d, SEQ=%d\n",
profile_status.is_link, profile_status.conn_handle,
profile_status.is_critical, seq_num);
ath_mci_process_status(sc, &profile_status);
break;
default:
ath_dbg(common, ATH_DBG_MCI,
"MCI Unknown GPM COEX message = 0x%02x\n", opcode);
break;
}
}
static int ath_mci_buf_alloc(struct ath_softc *sc, struct ath_mci_buf *buf)
{
int error = 0;
buf->bf_addr = dma_alloc_coherent(sc->dev, buf->bf_len,
&buf->bf_paddr, GFP_KERNEL);
if (buf->bf_addr == NULL) {
error = -ENOMEM;
goto fail;
}
return 0;
fail:
memset(buf, 0, sizeof(*buf));
return error;
}
static void ath_mci_buf_free(struct ath_softc *sc, struct ath_mci_buf *buf)
{
if (buf->bf_addr) {
dma_free_coherent(sc->dev, buf->bf_len, buf->bf_addr,
buf->bf_paddr);
memset(buf, 0, sizeof(*buf));
}
}
int ath_mci_setup(struct ath_softc *sc)
{
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_mci_coex *mci = &sc->mci_coex;
int error = 0;
mci->sched_buf.bf_len = ATH_MCI_SCHED_BUF_SIZE + ATH_MCI_GPM_BUF_SIZE;
if (ath_mci_buf_alloc(sc, &mci->sched_buf)) {
ath_dbg(common, ATH_DBG_FATAL, "MCI buffer alloc failed\n");
error = -ENOMEM;
goto fail;
}
mci->sched_buf.bf_len = ATH_MCI_SCHED_BUF_SIZE;
memset(mci->sched_buf.bf_addr, MCI_GPM_RSVD_PATTERN,
mci->sched_buf.bf_len);
mci->gpm_buf.bf_len = ATH_MCI_GPM_BUF_SIZE;
mci->gpm_buf.bf_addr = (u8 *)mci->sched_buf.bf_addr +
mci->sched_buf.bf_len;
mci->gpm_buf.bf_paddr = mci->sched_buf.bf_paddr + mci->sched_buf.bf_len;
/* initialize the buffer */
memset(mci->gpm_buf.bf_addr, MCI_GPM_RSVD_PATTERN, mci->gpm_buf.bf_len);
ar9003_mci_setup(sc->sc_ah, mci->gpm_buf.bf_paddr,
mci->gpm_buf.bf_addr, (mci->gpm_buf.bf_len >> 4),
mci->sched_buf.bf_paddr);
fail:
return error;
}
void ath_mci_cleanup(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
struct ath_mci_coex *mci = &sc->mci_coex;
/*
* both schedule and gpm buffers will be released
*/
ath_mci_buf_free(sc, &mci->sched_buf);
ar9003_mci_cleanup(ah);
}
void ath_mci_intr(struct ath_softc *sc)
{
struct ath_mci_coex *mci = &sc->mci_coex;
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
u32 mci_int, mci_int_rxmsg;
u32 offset, subtype, opcode;
u32 *pgpm;
u32 more_data = MCI_GPM_MORE;
bool skip_gpm = false;
ar9003_mci_get_interrupt(sc->sc_ah, &mci_int, &mci_int_rxmsg);
if (ar9003_mci_state(ah, MCI_STATE_ENABLE, NULL) == 0) {
ar9003_mci_state(sc->sc_ah, MCI_STATE_INIT_GPM_OFFSET, NULL);
ath_dbg(common, ATH_DBG_MCI,
"MCI interrupt but MCI disabled\n");
ath_dbg(common, ATH_DBG_MCI,
"MCI interrupt: intr = 0x%x, intr_rxmsg = 0x%x\n",
mci_int, mci_int_rxmsg);
return;
}
if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE) {
u32 payload[4] = { 0xffffffff, 0xffffffff,
0xffffffff, 0xffffff00};
/*
* The following REMOTE_RESET and SYS_WAKING used to sent
* only when BT wake up. Now they are always sent, as a
* recovery method to reset BT MCI's RX alignment.
*/
ath_dbg(common, ATH_DBG_MCI, "MCI interrupt send REMOTE_RESET\n");
ar9003_mci_send_message(ah, MCI_REMOTE_RESET, 0,
payload, 16, true, false);
ath_dbg(common, ATH_DBG_MCI, "MCI interrupt send SYS_WAKING\n");
ar9003_mci_send_message(ah, MCI_SYS_WAKING, 0,
NULL, 0, true, false);
mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE;
ar9003_mci_state(ah, MCI_STATE_RESET_REQ_WAKE, NULL);
/*
* always do this for recovery and 2G/5G toggling and LNA_TRANS
*/
ath_dbg(common, ATH_DBG_MCI, "MCI Set BT state to AWAKE.\n");
ar9003_mci_state(ah, MCI_STATE_SET_BT_AWAKE, NULL);
}
/* Processing SYS_WAKING/SYS_SLEEPING */
if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING) {
mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING;
if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_SLEEP) {
if (ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL)
== MCI_BT_SLEEP)
ath_dbg(common, ATH_DBG_MCI,
"MCI BT stays in sleep mode\n");
else {
ath_dbg(common, ATH_DBG_MCI,
"MCI Set BT state to AWAKE.\n");
ar9003_mci_state(ah,
MCI_STATE_SET_BT_AWAKE, NULL);
}
} else
ath_dbg(common, ATH_DBG_MCI,
"MCI BT stays in AWAKE mode.\n");
}
if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING) {
mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING;
if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_AWAKE) {
if (ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL)
== MCI_BT_AWAKE)
ath_dbg(common, ATH_DBG_MCI,
"MCI BT stays in AWAKE mode.\n");
else {
ath_dbg(common, ATH_DBG_MCI,
"MCI SetBT state to SLEEP\n");
ar9003_mci_state(ah, MCI_STATE_SET_BT_SLEEP,
NULL);
}
} else
ath_dbg(common, ATH_DBG_MCI,
"MCI BT stays in SLEEP mode\n");
}
if ((mci_int & AR_MCI_INTERRUPT_RX_INVALID_HDR) ||
(mci_int & AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT)) {
ath_dbg(common, ATH_DBG_MCI, "MCI RX broken, skip GPM msgs\n");
ar9003_mci_state(ah, MCI_STATE_RECOVER_RX, NULL);
skip_gpm = true;
}
if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO) {
mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO;
offset = ar9003_mci_state(ah, MCI_STATE_LAST_SCHD_MSG_OFFSET,
NULL);
}
if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_GPM) {
mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_GPM;
while (more_data == MCI_GPM_MORE) {
pgpm = mci->gpm_buf.bf_addr;
offset = ar9003_mci_state(ah,
MCI_STATE_NEXT_GPM_OFFSET, &more_data);
if (offset == MCI_GPM_INVALID)
break;
pgpm += (offset >> 2);
/*
* The first dword is timer.
* The real data starts from 2nd dword.
*/
subtype = MCI_GPM_TYPE(pgpm);
opcode = MCI_GPM_OPCODE(pgpm);
if (!skip_gpm) {
if (MCI_GPM_IS_CAL_TYPE(subtype))
ath_mci_cal_msg(sc, subtype,
(u8 *) pgpm);
else {
switch (subtype) {
case MCI_GPM_COEX_AGENT:
ath_mci_msg(sc, opcode,
(u8 *) pgpm);
break;
default:
break;
}
}
}
MCI_GPM_RECYCLE(pgpm);
}
}
if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_HW_MSG_MASK) {
if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL)
mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL;
if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_LNA_INFO) {
mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_LNA_INFO;
ath_dbg(common, ATH_DBG_MCI, "MCI LNA_INFO\n");
}
if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_INFO) {
int value_dbm = ar9003_mci_state(ah,
MCI_STATE_CONT_RSSI_POWER, NULL);
mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_CONT_INFO;
if (ar9003_mci_state(ah, MCI_STATE_CONT_TXRX, NULL))
ath_dbg(common, ATH_DBG_MCI,
"MCI CONT_INFO: "
"(tx) pri = %d, pwr = %d dBm\n",
ar9003_mci_state(ah,
MCI_STATE_CONT_PRIORITY, NULL),
value_dbm);
else
ath_dbg(common, ATH_DBG_MCI,
"MCI CONT_INFO:"
"(rx) pri = %d,pwr = %d dBm\n",
ar9003_mci_state(ah,
MCI_STATE_CONT_PRIORITY, NULL),
value_dbm);
}
if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_NACK) {
mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_CONT_NACK;
ath_dbg(common, ATH_DBG_MCI, "MCI CONT_NACK\n");
}
if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_RST) {
mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_CONT_RST;
ath_dbg(common, ATH_DBG_MCI, "MCI CONT_RST\n");
}
}
if ((mci_int & AR_MCI_INTERRUPT_RX_INVALID_HDR) ||
(mci_int & AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT))
mci_int &= ~(AR_MCI_INTERRUPT_RX_INVALID_HDR |
AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT);
if (mci_int_rxmsg & 0xfffffffe)
ath_dbg(common, ATH_DBG_MCI,
"MCI not processed mci_int_rxmsg = 0x%x\n",
mci_int_rxmsg);
}

View File

@ -17,6 +17,9 @@
#ifndef MCI_H #ifndef MCI_H
#define MCI_H #define MCI_H
#define ATH_MCI_SCHED_BUF_SIZE (16 * 16) /* 16 entries, 4 dword each */
#define ATH_MCI_GPM_MAX_ENTRY 16
#define ATH_MCI_GPM_BUF_SIZE (ATH_MCI_GPM_MAX_ENTRY * 16)
#define ATH_MCI_DEF_BT_PERIOD 40 #define ATH_MCI_DEF_BT_PERIOD 40
#define ATH_MCI_BDR_DUTY_CYCLE 20 #define ATH_MCI_BDR_DUTY_CYCLE 20
#define ATH_MCI_MAX_DUTY_CYCLE 90 #define ATH_MCI_MAX_DUTY_CYCLE 90
@ -110,9 +113,26 @@ struct ath_mci_profile {
u8 num_bdr; u8 num_bdr;
}; };
struct ath_mci_buf {
void *bf_addr; /* virtual addr of desc */
dma_addr_t bf_paddr; /* physical addr of buffer */
u32 bf_len; /* len of data */
};
struct ath_mci_coex {
atomic_t mci_cal_flag;
struct ath_mci_buf sched_buf;
struct ath_mci_buf gpm_buf;
u32 bt_cal_start;
};
void ath_mci_flush_profile(struct ath_mci_profile *mci); void ath_mci_flush_profile(struct ath_mci_profile *mci);
void ath_mci_process_profile(struct ath_softc *sc, void ath_mci_process_profile(struct ath_softc *sc,
struct ath_mci_profile_info *info); struct ath_mci_profile_info *info);
void ath_mci_process_status(struct ath_softc *sc, void ath_mci_process_status(struct ath_softc *sc,
struct ath_mci_profile_status *status); struct ath_mci_profile_status *status);
int ath_mci_setup(struct ath_softc *sc);
void ath_mci_cleanup(struct ath_softc *sc);
void ath_mci_intr(struct ath_softc *sc);
#endif #endif

View File

@ -475,7 +475,6 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
return rfilt; return rfilt;
#undef RX_FILTER_PRESERVE
} }
int ath_startrecv(struct ath_softc *sc) int ath_startrecv(struct ath_softc *sc)
@ -1923,15 +1922,20 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
skb = hdr_skb; skb = hdr_skb;
} }
/*
* change the default rx antenna if rx diversity chooses the if (ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) {
* other antenna 3 times in a row.
*/ /*
if (sc->rx.defant != rs.rs_antenna) { * change the default rx antenna if rx diversity
if (++sc->rx.rxotherant >= 3) * chooses the other antenna 3 times in a row.
ath_setdefantenna(sc, rs.rs_antenna); */
} else { if (sc->rx.defant != rs.rs_antenna) {
sc->rx.rxotherant = 0; if (++sc->rx.rxotherant >= 3)
ath_setdefantenna(sc, rs.rs_antenna);
} else {
sc->rx.rxotherant = 0;
}
} }
if (rxs->flag & RX_FLAG_MMIC_STRIPPED) if (rxs->flag & RX_FLAG_MMIC_STRIPPED)

View File

@ -1006,6 +1006,8 @@ enum {
#define AR_INTR_ASYNC_MASK (AR_SREV_9340(ah) ? 0x4018 : 0x4030) #define AR_INTR_ASYNC_MASK (AR_SREV_9340(ah) ? 0x4018 : 0x4030)
#define AR_INTR_ASYNC_MASK_GPIO 0xFFFC0000 #define AR_INTR_ASYNC_MASK_GPIO 0xFFFC0000
#define AR_INTR_ASYNC_MASK_GPIO_S 18 #define AR_INTR_ASYNC_MASK_GPIO_S 18
#define AR_INTR_ASYNC_MASK_MCI 0x00000080
#define AR_INTR_ASYNC_MASK_MCI_S 7
#define AR_INTR_SYNC_MASK (AR_SREV_9340(ah) ? 0x401c : 0x4034) #define AR_INTR_SYNC_MASK (AR_SREV_9340(ah) ? 0x401c : 0x4034)
#define AR_INTR_SYNC_MASK_GPIO 0xFFFC0000 #define AR_INTR_SYNC_MASK_GPIO 0xFFFC0000
@ -1013,6 +1015,14 @@ enum {
#define AR_INTR_ASYNC_CAUSE_CLR (AR_SREV_9340(ah) ? 0x4020 : 0x4038) #define AR_INTR_ASYNC_CAUSE_CLR (AR_SREV_9340(ah) ? 0x4020 : 0x4038)
#define AR_INTR_ASYNC_CAUSE (AR_SREV_9340(ah) ? 0x4020 : 0x4038) #define AR_INTR_ASYNC_CAUSE (AR_SREV_9340(ah) ? 0x4020 : 0x4038)
#define AR_INTR_ASYNC_CAUSE_MCI 0x00000080
#define AR_INTR_ASYNC_USED (AR_INTR_MAC_IRQ | \
AR_INTR_ASYNC_CAUSE_MCI)
/* Asynchronous Interrupt Enable Register */
#define AR_INTR_ASYNC_ENABLE_MCI 0x00000080
#define AR_INTR_ASYNC_ENABLE_MCI_S 7
#define AR_INTR_ASYNC_ENABLE (AR_SREV_9340(ah) ? 0x4024 : 0x403c) #define AR_INTR_ASYNC_ENABLE (AR_SREV_9340(ah) ? 0x4024 : 0x403c)
#define AR_INTR_ASYNC_ENABLE_GPIO 0xFFFC0000 #define AR_INTR_ASYNC_ENABLE_GPIO 0xFFFC0000
@ -1269,6 +1279,8 @@ enum {
#define AR_RTC_INTR_MASK \ #define AR_RTC_INTR_MASK \
((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0058) : 0x7058) ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0058) : 0x7058)
#define AR_RTC_KEEP_AWAKE 0x7034
/* RTC_DERIVED_* - only for AR9100 */ /* RTC_DERIVED_* - only for AR9100 */
#define AR_RTC_DERIVED_CLK \ #define AR_RTC_DERIVED_CLK \
@ -1555,6 +1567,8 @@ enum {
#define AR_DIAG_FRAME_NV0 0x00020000 #define AR_DIAG_FRAME_NV0 0x00020000
#define AR_DIAG_OBS_PT_SEL1 0x000C0000 #define AR_DIAG_OBS_PT_SEL1 0x000C0000
#define AR_DIAG_OBS_PT_SEL1_S 18 #define AR_DIAG_OBS_PT_SEL1_S 18
#define AR_DIAG_OBS_PT_SEL2 0x08000000
#define AR_DIAG_OBS_PT_SEL2_S 27
#define AR_DIAG_FORCE_RX_CLEAR 0x00100000 /* force rx_clear high */ #define AR_DIAG_FORCE_RX_CLEAR 0x00100000 /* force rx_clear high */
#define AR_DIAG_IGNORE_VIRT_CS 0x00200000 #define AR_DIAG_IGNORE_VIRT_CS 0x00200000
#define AR_DIAG_FORCE_CH_IDLE_HIGH 0x00400000 #define AR_DIAG_FORCE_CH_IDLE_HIGH 0x00400000
@ -1929,37 +1943,277 @@ enum {
#define AR_PHY_AGC_CONTROL_YCOK_MAX_S 6 #define AR_PHY_AGC_CONTROL_YCOK_MAX_S 6
/* MCI Registers */ /* MCI Registers */
#define AR_MCI_INTERRUPT_RX_MSG_EN 0x183c
#define AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET 0x00000001 #define AR_MCI_COMMAND0 0x1800
#define AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET_S 0 #define AR_MCI_COMMAND0_HEADER 0xFF
#define AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL 0x00000002 #define AR_MCI_COMMAND0_HEADER_S 0
#define AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL_S 1 #define AR_MCI_COMMAND0_LEN 0x1f00
#define AR_MCI_INTERRUPT_RX_MSG_CONT_NACK 0x00000004 #define AR_MCI_COMMAND0_LEN_S 8
#define AR_MCI_INTERRUPT_RX_MSG_CONT_NACK_S 2 #define AR_MCI_COMMAND0_DISABLE_TIMESTAMP 0x2000
#define AR_MCI_INTERRUPT_RX_MSG_CONT_INFO 0x00000008 #define AR_MCI_COMMAND0_DISABLE_TIMESTAMP_S 13
#define AR_MCI_INTERRUPT_RX_MSG_CONT_INFO_S 3
#define AR_MCI_INTERRUPT_RX_MSG_CONT_RST 0x00000010 #define AR_MCI_COMMAND1 0x1804
#define AR_MCI_INTERRUPT_RX_MSG_CONT_RST_S 4
#define AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO 0x00000020 #define AR_MCI_COMMAND2 0x1808
#define AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO_S 5 #define AR_MCI_COMMAND2_RESET_TX 0x01
#define AR_MCI_INTERRUPT_RX_MSG_CPU_INT 0x00000040 #define AR_MCI_COMMAND2_RESET_TX_S 0
#define AR_MCI_INTERRUPT_RX_MSG_CPU_INT_S 6 #define AR_MCI_COMMAND2_RESET_RX 0x02
#define AR_MCI_INTERRUPT_RX_MSG_GPM 0x00000100 #define AR_MCI_COMMAND2_RESET_RX_S 1
#define AR_MCI_INTERRUPT_RX_MSG_GPM_S 8 #define AR_MCI_COMMAND2_RESET_RX_NUM_CYCLES 0x3FC
#define AR_MCI_INTERRUPT_RX_MSG_LNA_INFO 0x00000200 #define AR_MCI_COMMAND2_RESET_RX_NUM_CYCLES_S 2
#define AR_MCI_INTERRUPT_RX_MSG_LNA_INFO_S 9 #define AR_MCI_COMMAND2_RESET_REQ_WAKEUP 0x400
#define AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING 0x00000400 #define AR_MCI_COMMAND2_RESET_REQ_WAKEUP_S 10
#define AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING_S 10
#define AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING 0x00000800 #define AR_MCI_RX_CTRL 0x180c
#define AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING_S 11
#define AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE 0x00001000 #define AR_MCI_TX_CTRL 0x1810
#define AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE_S 12 /* 0 = no division, 1 = divide by 2, 2 = divide by 4, 3 = divide by 8 */
#define AR_MCI_INTERRUPT_RX_HW_MSG_MASK (AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO | \ #define AR_MCI_TX_CTRL_CLK_DIV 0x03
#define AR_MCI_TX_CTRL_CLK_DIV_S 0
#define AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE 0x04
#define AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE_S 2
#define AR_MCI_TX_CTRL_GAIN_UPDATE_FREQ 0xFFFFF8
#define AR_MCI_TX_CTRL_GAIN_UPDATE_FREQ_S 3
#define AR_MCI_TX_CTRL_GAIN_UPDATE_NUM 0xF000000
#define AR_MCI_TX_CTRL_GAIN_UPDATE_NUM_S 24
#define AR_MCI_MSG_ATTRIBUTES_TABLE 0x1814
#define AR_MCI_MSG_ATTRIBUTES_TABLE_CHECKSUM 0xFFFF
#define AR_MCI_MSG_ATTRIBUTES_TABLE_CHECKSUM_S 0
#define AR_MCI_MSG_ATTRIBUTES_TABLE_INVALID_HDR 0xFFFF0000
#define AR_MCI_MSG_ATTRIBUTES_TABLE_INVALID_HDR_S 16
#define AR_MCI_SCHD_TABLE_0 0x1818
#define AR_MCI_SCHD_TABLE_1 0x181c
#define AR_MCI_GPM_0 0x1820
#define AR_MCI_GPM_1 0x1824
#define AR_MCI_GPM_WRITE_PTR 0xFFFF0000
#define AR_MCI_GPM_WRITE_PTR_S 16
#define AR_MCI_GPM_BUF_LEN 0x0000FFFF
#define AR_MCI_GPM_BUF_LEN_S 0
#define AR_MCI_INTERRUPT_RAW 0x1828
#define AR_MCI_INTERRUPT_EN 0x182c
#define AR_MCI_INTERRUPT_SW_MSG_DONE 0x00000001
#define AR_MCI_INTERRUPT_SW_MSG_DONE_S 0
#define AR_MCI_INTERRUPT_CPU_INT_MSG 0x00000002
#define AR_MCI_INTERRUPT_CPU_INT_MSG_S 1
#define AR_MCI_INTERRUPT_RX_CKSUM_FAIL 0x00000004
#define AR_MCI_INTERRUPT_RX_CKSUM_FAIL_S 2
#define AR_MCI_INTERRUPT_RX_INVALID_HDR 0x00000008
#define AR_MCI_INTERRUPT_RX_INVALID_HDR_S 3
#define AR_MCI_INTERRUPT_RX_HW_MSG_FAIL 0x00000010
#define AR_MCI_INTERRUPT_RX_HW_MSG_FAIL_S 4
#define AR_MCI_INTERRUPT_RX_SW_MSG_FAIL 0x00000020
#define AR_MCI_INTERRUPT_RX_SW_MSG_FAIL_S 5
#define AR_MCI_INTERRUPT_TX_HW_MSG_FAIL 0x00000080
#define AR_MCI_INTERRUPT_TX_HW_MSG_FAIL_S 7
#define AR_MCI_INTERRUPT_TX_SW_MSG_FAIL 0x00000100
#define AR_MCI_INTERRUPT_TX_SW_MSG_FAIL_S 8
#define AR_MCI_INTERRUPT_RX_MSG 0x00000200
#define AR_MCI_INTERRUPT_RX_MSG_S 9
#define AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE 0x00000400
#define AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE_S 10
#define AR_MCI_INTERRUPT_BT_PRI 0x07fff800
#define AR_MCI_INTERRUPT_BT_PRI_S 11
#define AR_MCI_INTERRUPT_BT_PRI_THRESH 0x08000000
#define AR_MCI_INTERRUPT_BT_PRI_THRESH_S 27
#define AR_MCI_INTERRUPT_BT_FREQ 0x10000000
#define AR_MCI_INTERRUPT_BT_FREQ_S 28
#define AR_MCI_INTERRUPT_BT_STOMP 0x20000000
#define AR_MCI_INTERRUPT_BT_STOMP_S 29
#define AR_MCI_INTERRUPT_BB_AIC_IRQ 0x40000000
#define AR_MCI_INTERRUPT_BB_AIC_IRQ_S 30
#define AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT 0x80000000
#define AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT_S 31
#define AR_MCI_INTERRUPT_DEFAULT (AR_MCI_INTERRUPT_SW_MSG_DONE | \
AR_MCI_INTERRUPT_RX_INVALID_HDR | \
AR_MCI_INTERRUPT_RX_HW_MSG_FAIL | \
AR_MCI_INTERRUPT_RX_SW_MSG_FAIL | \
AR_MCI_INTERRUPT_TX_HW_MSG_FAIL | \
AR_MCI_INTERRUPT_TX_SW_MSG_FAIL | \
AR_MCI_INTERRUPT_RX_MSG | \
AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE | \
AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT)
#define AR_MCI_INTERRUPT_MSG_FAIL_MASK (AR_MCI_INTERRUPT_RX_HW_MSG_FAIL | \
AR_MCI_INTERRUPT_RX_SW_MSG_FAIL | \
AR_MCI_INTERRUPT_TX_HW_MSG_FAIL | \
AR_MCI_INTERRUPT_TX_SW_MSG_FAIL)
#define AR_MCI_REMOTE_CPU_INT 0x1830
#define AR_MCI_REMOTE_CPU_INT_EN 0x1834
#define AR_MCI_INTERRUPT_RX_MSG_RAW 0x1838
#define AR_MCI_INTERRUPT_RX_MSG_EN 0x183c
#define AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET 0x00000001
#define AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET_S 0
#define AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL 0x00000002
#define AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL_S 1
#define AR_MCI_INTERRUPT_RX_MSG_CONT_NACK 0x00000004
#define AR_MCI_INTERRUPT_RX_MSG_CONT_NACK_S 2
#define AR_MCI_INTERRUPT_RX_MSG_CONT_INFO 0x00000008
#define AR_MCI_INTERRUPT_RX_MSG_CONT_INFO_S 3
#define AR_MCI_INTERRUPT_RX_MSG_CONT_RST 0x00000010
#define AR_MCI_INTERRUPT_RX_MSG_CONT_RST_S 4
#define AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO 0x00000020
#define AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO_S 5
#define AR_MCI_INTERRUPT_RX_MSG_CPU_INT 0x00000040
#define AR_MCI_INTERRUPT_RX_MSG_CPU_INT_S 6
#define AR_MCI_INTERRUPT_RX_MSG_GPM 0x00000100
#define AR_MCI_INTERRUPT_RX_MSG_GPM_S 8
#define AR_MCI_INTERRUPT_RX_MSG_LNA_INFO 0x00000200
#define AR_MCI_INTERRUPT_RX_MSG_LNA_INFO_S 9
#define AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING 0x00000400
#define AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING_S 10
#define AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING 0x00000800
#define AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING_S 11
#define AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE 0x00001000
#define AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE_S 12
#define AR_MCI_INTERRUPT_RX_HW_MSG_MASK (AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO | \
AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL| \ AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL| \
AR_MCI_INTERRUPT_RX_MSG_LNA_INFO | \ AR_MCI_INTERRUPT_RX_MSG_LNA_INFO | \
AR_MCI_INTERRUPT_RX_MSG_CONT_NACK | \ AR_MCI_INTERRUPT_RX_MSG_CONT_NACK | \
AR_MCI_INTERRUPT_RX_MSG_CONT_INFO | \ AR_MCI_INTERRUPT_RX_MSG_CONT_INFO | \
AR_MCI_INTERRUPT_RX_MSG_CONT_RST) AR_MCI_INTERRUPT_RX_MSG_CONT_RST)
#define AR_MCI_INTERRUPT_RX_MSG_DEFAULT (AR_MCI_INTERRUPT_RX_MSG_GPM | \
AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET| \
AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING | \
AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING| \
AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO | \
AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL | \
AR_MCI_INTERRUPT_RX_MSG_LNA_INFO | \
AR_MCI_INTERRUPT_RX_MSG_CONT_NACK | \
AR_MCI_INTERRUPT_RX_MSG_CONT_INFO | \
AR_MCI_INTERRUPT_RX_MSG_CONT_RST | \
AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)
#define AR_MCI_CPU_INT 0x1840
#define AR_MCI_RX_STATUS 0x1844
#define AR_MCI_RX_LAST_SCHD_MSG_INDEX 0x00000F00
#define AR_MCI_RX_LAST_SCHD_MSG_INDEX_S 8
#define AR_MCI_RX_REMOTE_SLEEP 0x00001000
#define AR_MCI_RX_REMOTE_SLEEP_S 12
#define AR_MCI_RX_MCI_CLK_REQ 0x00002000
#define AR_MCI_RX_MCI_CLK_REQ_S 13
#define AR_MCI_CONT_STATUS 0x1848
#define AR_MCI_CONT_RSSI_POWER 0x000000FF
#define AR_MCI_CONT_RSSI_POWER_S 0
#define AR_MCI_CONT_RRIORITY 0x0000FF00
#define AR_MCI_CONT_RRIORITY_S 8
#define AR_MCI_CONT_TXRX 0x00010000
#define AR_MCI_CONT_TXRX_S 16
#define AR_MCI_BT_PRI0 0x184c
#define AR_MCI_BT_PRI1 0x1850
#define AR_MCI_BT_PRI2 0x1854
#define AR_MCI_BT_PRI3 0x1858
#define AR_MCI_BT_PRI 0x185c
#define AR_MCI_WL_FREQ0 0x1860
#define AR_MCI_WL_FREQ1 0x1864
#define AR_MCI_WL_FREQ2 0x1868
#define AR_MCI_GAIN 0x186c
#define AR_MCI_WBTIMER1 0x1870
#define AR_MCI_WBTIMER2 0x1874
#define AR_MCI_WBTIMER3 0x1878
#define AR_MCI_WBTIMER4 0x187c
#define AR_MCI_MAXGAIN 0x1880
#define AR_MCI_HW_SCHD_TBL_CTL 0x1884
#define AR_MCI_HW_SCHD_TBL_D0 0x1888
#define AR_MCI_HW_SCHD_TBL_D1 0x188c
#define AR_MCI_HW_SCHD_TBL_D2 0x1890
#define AR_MCI_HW_SCHD_TBL_D3 0x1894
#define AR_MCI_TX_PAYLOAD0 0x1898
#define AR_MCI_TX_PAYLOAD1 0x189c
#define AR_MCI_TX_PAYLOAD2 0x18a0
#define AR_MCI_TX_PAYLOAD3 0x18a4
#define AR_BTCOEX_WBTIMER 0x18a8
#define AR_BTCOEX_CTRL 0x18ac
#define AR_BTCOEX_CTRL_AR9462_MODE 0x00000001
#define AR_BTCOEX_CTRL_AR9462_MODE_S 0
#define AR_BTCOEX_CTRL_WBTIMER_EN 0x00000002
#define AR_BTCOEX_CTRL_WBTIMER_EN_S 1
#define AR_BTCOEX_CTRL_MCI_MODE_EN 0x00000004
#define AR_BTCOEX_CTRL_MCI_MODE_EN_S 2
#define AR_BTCOEX_CTRL_LNA_SHARED 0x00000008
#define AR_BTCOEX_CTRL_LNA_SHARED_S 3
#define AR_BTCOEX_CTRL_PA_SHARED 0x00000010
#define AR_BTCOEX_CTRL_PA_SHARED_S 4
#define AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN 0x00000020
#define AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN_S 5
#define AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN 0x00000040
#define AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN_S 6
#define AR_BTCOEX_CTRL_NUM_ANTENNAS 0x00000180
#define AR_BTCOEX_CTRL_NUM_ANTENNAS_S 7
#define AR_BTCOEX_CTRL_RX_CHAIN_MASK 0x00000E00
#define AR_BTCOEX_CTRL_RX_CHAIN_MASK_S 9
#define AR_BTCOEX_CTRL_AGGR_THRESH 0x00007000
#define AR_BTCOEX_CTRL_AGGR_THRESH_S 12
#define AR_BTCOEX_CTRL_1_CHAIN_BCN 0x00080000
#define AR_BTCOEX_CTRL_1_CHAIN_BCN_S 19
#define AR_BTCOEX_CTRL_1_CHAIN_ACK 0x00100000
#define AR_BTCOEX_CTRL_1_CHAIN_ACK_S 20
#define AR_BTCOEX_CTRL_WAIT_BA_MARGIN 0x1FE00000
#define AR_BTCOEX_CTRL_WAIT_BA_MARGIN_S 28
#define AR_BTCOEX_CTRL_REDUCE_TXPWR 0x20000000
#define AR_BTCOEX_CTRL_REDUCE_TXPWR_S 29
#define AR_BTCOEX_CTRL_SPDT_ENABLE_10 0x40000000
#define AR_BTCOEX_CTRL_SPDT_ENABLE_10_S 30
#define AR_BTCOEX_CTRL_SPDT_POLARITY 0x80000000
#define AR_BTCOEX_CTRL_SPDT_POLARITY_S 31
#define AR_BTCOEX_WL_WEIGHTS0 0x18b0
#define AR_BTCOEX_WL_WEIGHTS1 0x18b4
#define AR_BTCOEX_WL_WEIGHTS2 0x18b8
#define AR_BTCOEX_WL_WEIGHTS3 0x18bc
#define AR_BTCOEX_MAX_TXPWR(_x) (0x18c0 + ((_x) << 2))
#define AR_BTCOEX_WL_LNA 0x1940
#define AR_BTCOEX_RFGAIN_CTRL 0x1944
#define AR_BTCOEX_CTRL2 0x1948
#define AR_BTCOEX_CTRL2_TXPWR_THRESH 0x0007F800
#define AR_BTCOEX_CTRL2_TXPWR_THRESH_S 11
#define AR_BTCOEX_CTRL2_TX_CHAIN_MASK 0x00380000
#define AR_BTCOEX_CTRL2_TX_CHAIN_MASK_S 19
#define AR_BTCOEX_CTRL2_RX_DEWEIGHT 0x00400000
#define AR_BTCOEX_CTRL2_RX_DEWEIGHT_S 22
#define AR_BTCOEX_CTRL2_GPIO_OBS_SEL 0x00800000
#define AR_BTCOEX_CTRL2_GPIO_OBS_SEL_S 23
#define AR_BTCOEX_CTRL2_MAC_BB_OBS_SEL 0x01000000
#define AR_BTCOEX_CTRL2_MAC_BB_OBS_SEL_S 24
#define AR_BTCOEX_CTRL2_DESC_BASED_TXPWR_ENABLE 0x02000000
#define AR_BTCOEX_CTRL2_DESC_BASED_TXPWR_ENABLE_S 25
#define AR_BTCOEX_CTRL_SPDT_ENABLE 0x00000001
#define AR_BTCOEX_CTRL_SPDT_ENABLE_S 0
#define AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL 0x00000002
#define AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL_S 1
#define AR_BTCOEX_CTRL_USE_LATCHED_BT_ANT 0x00000004
#define AR_BTCOEX_CTRL_USE_LATCHED_BT_ANT_S 2
#define AR_GLB_WLAN_UART_INTF_EN 0x00020000
#define AR_GLB_WLAN_UART_INTF_EN_S 17
#define AR_GLB_DS_JTAG_DISABLE 0x00040000
#define AR_GLB_DS_JTAG_DISABLE_S 18
#define AR_BTCOEX_RC 0x194c
#define AR_BTCOEX_MAX_RFGAIN(_x) (0x1950 + ((_x) << 2))
#define AR_BTCOEX_DBG 0x1a50
#define AR_MCI_LAST_HW_MSG_HDR 0x1a54
#define AR_MCI_LAST_HW_MSG_BDY 0x1a58
#define AR_MCI_SCHD_TABLE_2 0x1a5c
#define AR_MCI_SCHD_TABLE_2_MEM_BASED 0x00000001
#define AR_MCI_SCHD_TABLE_2_MEM_BASED_S 0
#define AR_MCI_SCHD_TABLE_2_HW_BASED 0x00000002
#define AR_MCI_SCHD_TABLE_2_HW_BASED_S 1
#define AR_BTCOEX_CTRL3 0x1a60
#define AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT 0x00000fff
#define AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT_S 0
#endif #endif

View File

@ -179,6 +179,11 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
spin_lock_bh(&txq->axq_lock); spin_lock_bh(&txq->axq_lock);
} }
if (tid->baw_head == tid->baw_tail) {
tid->state &= ~AGGR_ADDBA_COMPLETE;
tid->state &= ~AGGR_CLEANUP;
}
spin_unlock_bh(&txq->axq_lock); spin_unlock_bh(&txq->axq_lock);
} }
@ -556,15 +561,9 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
spin_unlock_bh(&txq->axq_lock); spin_unlock_bh(&txq->axq_lock);
} }
if (tid->state & AGGR_CLEANUP) { if (tid->state & AGGR_CLEANUP)
ath_tx_flush_tid(sc, tid); ath_tx_flush_tid(sc, tid);
if (tid->baw_head == tid->baw_tail) {
tid->state &= ~AGGR_ADDBA_COMPLETE;
tid->state &= ~AGGR_CLEANUP;
}
}
rcu_read_unlock(); rcu_read_unlock();
if (needreset) { if (needreset) {

View File

@ -1,25 +0,0 @@
/*
* Copyright (c) 2011 Broadcom Corporation
*
* 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.
*/
#ifndef _bcmchip_h_
#define _bcmchip_h_
/* bcm4329 */
/* firmware name */
#define BCM4329_FW_NAME "brcm/bcm4329-fullmac-4.bin"
#define BCM4329_NV_NAME "brcm/bcm4329-fullmac-4.txt"
#endif /* _bcmchip_h_ */

View File

@ -40,7 +40,8 @@
static void brcmf_sdioh_irqhandler(struct sdio_func *func) static void brcmf_sdioh_irqhandler(struct sdio_func *func)
{ {
struct brcmf_sdio_dev *sdiodev = dev_get_drvdata(&func->card->dev); struct brcmf_bus *bus_if = dev_get_drvdata(&func->card->dev);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv;
brcmf_dbg(TRACE, "***IRQHandler\n"); brcmf_dbg(TRACE, "***IRQHandler\n");
@ -222,19 +223,12 @@ bool brcmf_sdcard_regfail(struct brcmf_sdio_dev *sdiodev)
return sdiodev->regfail; return sdiodev->regfail;
} }
int static int brcmf_sdcard_recv_prepare(struct brcmf_sdio_dev *sdiodev, uint fn,
brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, uint flags, uint width, u32 *addr)
uint flags,
u8 *buf, uint nbytes, struct sk_buff *pkt)
{ {
int status; uint bar0 = *addr & ~SBSDIO_SB_OFT_ADDR_MASK;
uint incr_fix;
uint width;
uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
int err = 0; int err = 0;
brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n", fn, addr, nbytes);
/* Async not implemented yet */ /* Async not implemented yet */
if (flags & SDIO_REQ_ASYNC) if (flags & SDIO_REQ_ASYNC)
return -ENOTSUPP; return -ENOTSUPP;
@ -247,29 +241,114 @@ brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
sdiodev->sbwad = bar0; sdiodev->sbwad = bar0;
} }
addr &= SBSDIO_SB_OFT_ADDR_MASK; *addr &= SBSDIO_SB_OFT_ADDR_MASK;
if (width == 4)
*addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
return 0;
}
int
brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
uint flags, u8 *buf, uint nbytes)
{
struct sk_buff *mypkt;
int err;
mypkt = brcmu_pkt_buf_get_skb(nbytes);
if (!mypkt) {
brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n",
nbytes);
return -EIO;
}
err = brcmf_sdcard_recv_pkt(sdiodev, addr, fn, flags, mypkt);
if (!err)
memcpy(buf, mypkt->data, nbytes);
brcmu_pkt_buf_free_skb(mypkt);
return err;
}
int
brcmf_sdcard_recv_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
uint flags, struct sk_buff *pkt)
{
uint incr_fix;
uint width;
int err = 0;
brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n",
fn, addr, pkt->len);
width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
err = brcmf_sdcard_recv_prepare(sdiodev, fn, flags, width, &addr);
if (err)
return err;
incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC; incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC;
err = brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_READ,
fn, addr, pkt);
return err;
}
int brcmf_sdcard_recv_chain(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
uint flags, struct sk_buff_head *pktq)
{
uint incr_fix;
uint width;
int err = 0;
brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n",
fn, addr, pktq->qlen);
width = (flags & SDIO_REQ_4BYTE) ? 4 : 2; width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
if (width == 4) err = brcmf_sdcard_recv_prepare(sdiodev, fn, flags, width, &addr);
addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; if (err)
return err;
status = brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_READ, incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC;
fn, addr, width, nbytes, buf, pkt); err = brcmf_sdioh_request_chain(sdiodev, incr_fix, SDIOH_READ, fn, addr,
pktq);
return status; return err;
} }
int int
brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
uint flags, u8 *buf, uint nbytes, struct sk_buff *pkt) uint flags, u8 *buf, uint nbytes)
{
struct sk_buff *mypkt;
int err;
mypkt = brcmu_pkt_buf_get_skb(nbytes);
if (!mypkt) {
brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n",
nbytes);
return -EIO;
}
memcpy(mypkt->data, buf, nbytes);
err = brcmf_sdcard_send_pkt(sdiodev, addr, fn, flags, mypkt);
brcmu_pkt_buf_free_skb(mypkt);
return err;
}
int
brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
uint flags, struct sk_buff *pkt)
{ {
uint incr_fix; uint incr_fix;
uint width; uint width;
uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK; uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
int err = 0; int err = 0;
brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n", fn, addr, nbytes); brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n",
fn, addr, pkt->len);
/* Async not implemented yet */ /* Async not implemented yet */
if (flags & SDIO_REQ_ASYNC) if (flags & SDIO_REQ_ASYNC)
@ -291,18 +370,39 @@ brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
return brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_WRITE, fn, return brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_WRITE, fn,
addr, width, nbytes, buf, pkt); addr, pkt);
} }
int brcmf_sdcard_rwdata(struct brcmf_sdio_dev *sdiodev, uint rw, u32 addr, int brcmf_sdcard_rwdata(struct brcmf_sdio_dev *sdiodev, uint rw, u32 addr,
u8 *buf, uint nbytes) u8 *buf, uint nbytes)
{ {
struct sk_buff *mypkt;
bool write = rw ? SDIOH_WRITE : SDIOH_READ;
int err;
addr &= SBSDIO_SB_OFT_ADDR_MASK; addr &= SBSDIO_SB_OFT_ADDR_MASK;
addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
return brcmf_sdioh_request_buffer(sdiodev, SDIOH_DATA_INC, mypkt = brcmu_pkt_buf_get_skb(nbytes);
(rw ? SDIOH_WRITE : SDIOH_READ), SDIO_FUNC_1, if (!mypkt) {
addr, 4, nbytes, buf, NULL); brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n",
nbytes);
return -EIO;
}
/* For a write, copy the buffer data into the packet. */
if (write)
memcpy(mypkt->data, buf, nbytes);
err = brcmf_sdioh_request_buffer(sdiodev, SDIOH_DATA_INC, write,
SDIO_FUNC_1, addr, mypkt);
/* For a read, copy the packet data back to the buffer. */
if (!err && !write)
memcpy(buf, mypkt->data, nbytes);
brcmu_pkt_buf_free_skb(mypkt);
return err;
} }
int brcmf_sdcard_abort(struct brcmf_sdio_dev *sdiodev, uint fn) int brcmf_sdcard_abort(struct brcmf_sdio_dev *sdiodev, uint fn)
@ -333,7 +433,7 @@ int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
sdiodev->sbwad = SI_ENUM_BASE; sdiodev->sbwad = SI_ENUM_BASE;
/* try to attach to the target device */ /* try to attach to the target device */
sdiodev->bus = brcmf_sdbrcm_probe(0, 0, 0, 0, regs, sdiodev); sdiodev->bus = brcmf_sdbrcm_probe(regs, sdiodev);
if (!sdiodev->bus) { if (!sdiodev->bus) {
brcmf_dbg(ERROR, "device attach failed\n"); brcmf_dbg(ERROR, "device attach failed\n");
ret = -ENODEV; ret = -ENODEV;

View File

@ -204,62 +204,75 @@ int brcmf_sdioh_request_word(struct brcmf_sdio_dev *sdiodev,
return err_ret; return err_ret;
} }
/* precondition: host controller is claimed */
static int static int
brcmf_sdioh_request_packet(struct brcmf_sdio_dev *sdiodev, uint fix_inc, brcmf_sdioh_request_data(struct brcmf_sdio_dev *sdiodev, uint write, bool fifo,
uint write, uint func, uint addr, uint func, uint addr, struct sk_buff *pkt, uint pktlen)
struct sk_buff *pkt) {
int err_ret = 0;
if ((write) && (!fifo)) {
err_ret = sdio_memcpy_toio(sdiodev->func[func], addr,
((u8 *) (pkt->data)), pktlen);
} else if (write) {
err_ret = sdio_memcpy_toio(sdiodev->func[func], addr,
((u8 *) (pkt->data)), pktlen);
} else if (fifo) {
err_ret = sdio_readsb(sdiodev->func[func],
((u8 *) (pkt->data)), addr, pktlen);
} else {
err_ret = sdio_memcpy_fromio(sdiodev->func[func],
((u8 *) (pkt->data)),
addr, pktlen);
}
return err_ret;
}
/*
* This function takes a queue of packets. The packets on the queue
* are assumed to be properly aligned by the caller.
*/
int
brcmf_sdioh_request_chain(struct brcmf_sdio_dev *sdiodev, uint fix_inc,
uint write, uint func, uint addr,
struct sk_buff_head *pktq)
{ {
bool fifo = (fix_inc == SDIOH_DATA_FIX); bool fifo = (fix_inc == SDIOH_DATA_FIX);
u32 SGCount = 0; u32 SGCount = 0;
int err_ret = 0; int err_ret = 0;
struct sk_buff *pnext; struct sk_buff *pkt;
brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(TRACE, "Enter\n");
brcmf_pm_resume_wait(sdiodev, &sdiodev->request_packet_wait); brcmf_pm_resume_wait(sdiodev, &sdiodev->request_chain_wait);
if (brcmf_pm_resume_error(sdiodev)) if (brcmf_pm_resume_error(sdiodev))
return -EIO; return -EIO;
/* Claim host controller */ /* Claim host controller */
sdio_claim_host(sdiodev->func[func]); sdio_claim_host(sdiodev->func[func]);
for (pnext = pkt; pnext; pnext = pnext->next) {
uint pkt_len = pnext->len; skb_queue_walk(pktq, pkt) {
uint pkt_len = pkt->len;
pkt_len += 3; pkt_len += 3;
pkt_len &= 0xFFFFFFFC; pkt_len &= 0xFFFFFFFC;
if ((write) && (!fifo)) { err_ret = brcmf_sdioh_request_data(sdiodev, write, fifo, func,
err_ret = sdio_memcpy_toio(sdiodev->func[func], addr, addr, pkt, pkt_len);
((u8 *) (pnext->data)),
pkt_len);
} else if (write) {
err_ret = sdio_memcpy_toio(sdiodev->func[func], addr,
((u8 *) (pnext->data)),
pkt_len);
} else if (fifo) {
err_ret = sdio_readsb(sdiodev->func[func],
((u8 *) (pnext->data)),
addr, pkt_len);
} else {
err_ret = sdio_memcpy_fromio(sdiodev->func[func],
((u8 *) (pnext->data)),
addr, pkt_len);
}
if (err_ret) { if (err_ret) {
brcmf_dbg(ERROR, "%s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=0x%08x\n", brcmf_dbg(ERROR, "%s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=0x%08x\n",
write ? "TX" : "RX", pnext, SGCount, addr, write ? "TX" : "RX", pkt, SGCount, addr,
pkt_len, err_ret); pkt_len, err_ret);
} else { } else {
brcmf_dbg(TRACE, "%s xfr'd %p[%d], addr=0x%05x, len=%d\n", brcmf_dbg(TRACE, "%s xfr'd %p[%d], addr=0x%05x, len=%d\n",
write ? "TX" : "RX", pnext, SGCount, addr, write ? "TX" : "RX", pkt, SGCount, addr,
pkt_len); pkt_len);
} }
if (!fifo) if (!fifo)
addr += pkt_len; addr += pkt_len;
SGCount++;
SGCount++;
} }
/* Release host controller */ /* Release host controller */
@ -270,91 +283,45 @@ brcmf_sdioh_request_packet(struct brcmf_sdio_dev *sdiodev, uint fix_inc,
} }
/* /*
* This function takes a buffer or packet, and fixes everything up * This function takes a single DMA-able packet.
* so that in the end, a DMA-able packet is created.
*
* A buffer does not have an associated packet pointer,
* and may or may not be aligned.
* A packet may consist of a single packet, or a packet chain.
* If it is a packet chain, then all the packets in the chain
* must be properly aligned.
*
* If the packet data is not aligned, then there may only be
* one packet, and in this case, it is copied to a new
* aligned packet.
*
*/ */
int brcmf_sdioh_request_buffer(struct brcmf_sdio_dev *sdiodev, int brcmf_sdioh_request_buffer(struct brcmf_sdio_dev *sdiodev,
uint fix_inc, uint write, uint func, uint addr, uint fix_inc, uint write, uint func, uint addr,
uint reg_width, uint buflen_u, u8 *buffer,
struct sk_buff *pkt) struct sk_buff *pkt)
{ {
int Status; int status;
struct sk_buff *mypkt = NULL; uint pkt_len = pkt->len;
bool fifo = (fix_inc == SDIOH_DATA_FIX);
brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(TRACE, "Enter\n");
if (pkt == NULL)
return -EINVAL;
brcmf_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait); brcmf_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait);
if (brcmf_pm_resume_error(sdiodev)) if (brcmf_pm_resume_error(sdiodev))
return -EIO; return -EIO;
/* Case 1: we don't have a packet. */
if (pkt == NULL) {
brcmf_dbg(DATA, "Creating new %s Packet, len=%d\n",
write ? "TX" : "RX", buflen_u);
mypkt = brcmu_pkt_buf_get_skb(buflen_u);
if (!mypkt) {
brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n",
buflen_u);
return -EIO;
}
/* For a write, copy the buffer data into the packet. */ /* Claim host controller */
if (write) sdio_claim_host(sdiodev->func[func]);
memcpy(mypkt->data, buffer, buflen_u);
Status = brcmf_sdioh_request_packet(sdiodev, fix_inc, write, pkt_len += 3;
func, addr, mypkt); pkt_len &= (uint)~3;
/* For a read, copy the packet data back to the buffer. */ status = brcmf_sdioh_request_data(sdiodev, write, fifo, func,
if (!write) addr, pkt, pkt_len);
memcpy(buffer, mypkt->data, buflen_u); if (status) {
brcmf_dbg(ERROR, "%s FAILED %p, addr=0x%05x, pkt_len=%d, ERR=0x%08x\n",
brcmu_pkt_buf_free_skb(mypkt); write ? "TX" : "RX", pkt, addr, pkt_len, status);
} else if (((ulong) (pkt->data) & DMA_ALIGN_MASK) != 0) { } else {
/* brcmf_dbg(TRACE, "%s xfr'd %p, addr=0x%05x, len=%d\n",
* Case 2: We have a packet, but it is unaligned. write ? "TX" : "RX", pkt, addr, pkt_len);
* In this case, we cannot have a chain (pkt->next == NULL)
*/
brcmf_dbg(DATA, "Creating aligned %s Packet, len=%d\n",
write ? "TX" : "RX", pkt->len);
mypkt = brcmu_pkt_buf_get_skb(pkt->len);
if (!mypkt) {
brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n",
pkt->len);
return -EIO;
}
/* For a write, copy the buffer data into the packet. */
if (write)
memcpy(mypkt->data, pkt->data, pkt->len);
Status = brcmf_sdioh_request_packet(sdiodev, fix_inc, write,
func, addr, mypkt);
/* For a read, copy the packet data back to the buffer. */
if (!write)
memcpy(pkt->data, mypkt->data, mypkt->len);
brcmu_pkt_buf_free_skb(mypkt);
} else { /* case 3: We have a packet and
it is aligned. */
brcmf_dbg(DATA, "Aligned %s Packet, direct DMA\n",
write ? "Tx" : "Rx");
Status = brcmf_sdioh_request_packet(sdiodev, fix_inc, write,
func, addr, pkt);
} }
return Status; /* Release host controller */
sdio_release_host(sdiodev->func[func]);
return status;
} }
/* Read client card reg */ /* Read client card reg */
@ -494,6 +461,7 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
{ {
int ret = 0; int ret = 0;
struct brcmf_sdio_dev *sdiodev; struct brcmf_sdio_dev *sdiodev;
struct brcmf_bus *bus_if;
brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(TRACE, "Enter\n");
brcmf_dbg(TRACE, "func->class=%x\n", func->class); brcmf_dbg(TRACE, "func->class=%x\n", func->class);
brcmf_dbg(TRACE, "sdio_vendor: 0x%04x\n", func->vendor); brcmf_dbg(TRACE, "sdio_vendor: 0x%04x\n", func->vendor);
@ -505,22 +473,31 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
brcmf_dbg(ERROR, "card private drvdata occupied\n"); brcmf_dbg(ERROR, "card private drvdata occupied\n");
return -ENXIO; return -ENXIO;
} }
sdiodev = kzalloc(sizeof(struct brcmf_sdio_dev), GFP_KERNEL); bus_if = kzalloc(sizeof(struct brcmf_bus), GFP_KERNEL);
if (!sdiodev) if (!bus_if)
return -ENOMEM; return -ENOMEM;
sdiodev = kzalloc(sizeof(struct brcmf_sdio_dev), GFP_KERNEL);
if (!sdiodev) {
kfree(bus_if);
return -ENOMEM;
}
sdiodev->dev = &func->card->dev;
sdiodev->func[0] = func->card->sdio_func[0]; sdiodev->func[0] = func->card->sdio_func[0];
sdiodev->func[1] = func; sdiodev->func[1] = func;
dev_set_drvdata(&func->card->dev, sdiodev); bus_if->bus_priv = sdiodev;
bus_if->type = SDIO_BUS;
dev_set_drvdata(&func->card->dev, bus_if);
atomic_set(&sdiodev->suspend, false); atomic_set(&sdiodev->suspend, false);
init_waitqueue_head(&sdiodev->request_byte_wait); init_waitqueue_head(&sdiodev->request_byte_wait);
init_waitqueue_head(&sdiodev->request_word_wait); init_waitqueue_head(&sdiodev->request_word_wait);
init_waitqueue_head(&sdiodev->request_packet_wait); init_waitqueue_head(&sdiodev->request_chain_wait);
init_waitqueue_head(&sdiodev->request_buffer_wait); init_waitqueue_head(&sdiodev->request_buffer_wait);
} }
if (func->num == 2) { if (func->num == 2) {
sdiodev = dev_get_drvdata(&func->card->dev); bus_if = dev_get_drvdata(&func->card->dev);
sdiodev = bus_if->bus_priv;
if ((!sdiodev) || (sdiodev->func[1]->card != func->card)) if ((!sdiodev) || (sdiodev->func[1]->card != func->card))
return -ENODEV; return -ENODEV;
sdiodev->func[2] = func; sdiodev->func[2] = func;
@ -534,6 +511,7 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
static void brcmf_ops_sdio_remove(struct sdio_func *func) static void brcmf_ops_sdio_remove(struct sdio_func *func)
{ {
struct brcmf_bus *bus_if;
struct brcmf_sdio_dev *sdiodev; struct brcmf_sdio_dev *sdiodev;
brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(TRACE, "Enter\n");
brcmf_dbg(INFO, "func->class=%x\n", func->class); brcmf_dbg(INFO, "func->class=%x\n", func->class);
@ -542,10 +520,12 @@ static void brcmf_ops_sdio_remove(struct sdio_func *func)
brcmf_dbg(INFO, "Function#: 0x%04x\n", func->num); brcmf_dbg(INFO, "Function#: 0x%04x\n", func->num);
if (func->num == 2) { if (func->num == 2) {
sdiodev = dev_get_drvdata(&func->card->dev); bus_if = dev_get_drvdata(&func->card->dev);
sdiodev = bus_if->bus_priv;
brcmf_dbg(TRACE, "F2 found, calling brcmf_sdio_remove...\n"); brcmf_dbg(TRACE, "F2 found, calling brcmf_sdio_remove...\n");
brcmf_sdio_remove(sdiodev); brcmf_sdio_remove(sdiodev);
dev_set_drvdata(&func->card->dev, NULL); dev_set_drvdata(&func->card->dev, NULL);
kfree(bus_if);
kfree(sdiodev); kfree(sdiodev);
} }
} }
@ -556,11 +536,12 @@ static int brcmf_sdio_suspend(struct device *dev)
mmc_pm_flag_t sdio_flags; mmc_pm_flag_t sdio_flags;
struct brcmf_sdio_dev *sdiodev; struct brcmf_sdio_dev *sdiodev;
struct sdio_func *func = dev_to_sdio_func(dev); struct sdio_func *func = dev_to_sdio_func(dev);
struct brcmf_bus *bus_if = dev_get_drvdata(&func->card->dev);
int ret = 0; int ret = 0;
brcmf_dbg(TRACE, "\n"); brcmf_dbg(TRACE, "\n");
sdiodev = dev_get_drvdata(&func->card->dev); sdiodev = bus_if->bus_priv;
atomic_set(&sdiodev->suspend, true); atomic_set(&sdiodev->suspend, true);
@ -585,8 +566,9 @@ static int brcmf_sdio_resume(struct device *dev)
{ {
struct brcmf_sdio_dev *sdiodev; struct brcmf_sdio_dev *sdiodev;
struct sdio_func *func = dev_to_sdio_func(dev); struct sdio_func *func = dev_to_sdio_func(dev);
struct brcmf_bus *bus_if = dev_get_drvdata(&func->card->dev);
sdiodev = dev_get_drvdata(&func->card->dev); sdiodev = bus_if->bus_priv;
brcmf_sdio_wdtmr_enable(sdiodev, true); brcmf_sdio_wdtmr_enable(sdiodev, true);
atomic_set(&sdiodev->suspend, false); atomic_set(&sdiodev->suspend, false);
return 0; return 0;
@ -610,17 +592,26 @@ static struct sdio_driver brcmf_sdmmc_driver = {
#endif /* CONFIG_PM_SLEEP */ #endif /* CONFIG_PM_SLEEP */
}; };
/* bus register interface */ static void __exit brcmf_sdio_exit(void)
int brcmf_bus_register(void)
{
brcmf_dbg(TRACE, "Enter\n");
return sdio_register_driver(&brcmf_sdmmc_driver);
}
void brcmf_bus_unregister(void)
{ {
brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(TRACE, "Enter\n");
sdio_unregister_driver(&brcmf_sdmmc_driver); sdio_unregister_driver(&brcmf_sdmmc_driver);
} }
static int __init brcmf_sdio_init(void)
{
int ret;
brcmf_dbg(TRACE, "Enter\n");
ret = sdio_register_driver(&brcmf_sdmmc_driver);
if (ret)
brcmf_dbg(ERROR, "sdio_register_driver failed: %d\n", ret);
return ret;
}
module_init(brcmf_sdio_init);
module_exit(brcmf_sdio_exit);

View File

@ -571,8 +571,14 @@ struct brcmf_dcmd {
uint needed; /* bytes needed (optional) */ uint needed; /* bytes needed (optional) */
}; };
struct brcmf_bus {
u8 type; /* bus type */
void *bus_priv; /* pointer to bus private structure */
enum brcmf_bus_state state;
};
/* Forward decls for struct brcmf_pub (see below) */ /* Forward decls for struct brcmf_pub (see below) */
struct brcmf_bus; /* device bus info */ struct brcmf_sdio; /* device bus info */
struct brcmf_proto; /* device communication protocol info */ struct brcmf_proto; /* device communication protocol info */
struct brcmf_info; /* device driver info */ struct brcmf_info; /* device driver info */
struct brcmf_cfg80211_dev; /* cfg80211 device info */ struct brcmf_cfg80211_dev; /* cfg80211 device info */
@ -580,15 +586,16 @@ struct brcmf_cfg80211_dev; /* cfg80211 device info */
/* Common structure for module and instance linkage */ /* Common structure for module and instance linkage */
struct brcmf_pub { struct brcmf_pub {
/* Linkage ponters */ /* Linkage ponters */
struct brcmf_bus *bus; struct brcmf_sdio *bus;
struct brcmf_bus *bus_if;
struct brcmf_proto *prot; struct brcmf_proto *prot;
struct brcmf_info *info; struct brcmf_info *info;
struct brcmf_cfg80211_dev *config; struct brcmf_cfg80211_dev *config;
struct device *dev; /* fullmac dongle device pointer */
/* Internal brcmf items */ /* Internal brcmf items */
bool up; /* Driver up/down (to OS) */ bool up; /* Driver up/down (to OS) */
bool txoff; /* Transmit flow-controlled */ bool txoff; /* Transmit flow-controlled */
enum brcmf_bus_state busstate;
uint hdrlen; /* Total BRCMF header length (proto + bus) */ uint hdrlen; /* Total BRCMF header length (proto + bus) */
uint maxctl; /* Max size rxctl request from proto to bus */ uint maxctl; /* Max size rxctl request from proto to bus */
uint rxsz; /* Rx buffer size bus module should use */ uint rxsz; /* Rx buffer size bus module should use */
@ -656,7 +663,6 @@ struct brcmf_pub {
u8 country_code[BRCM_CNTRY_BUF_SZ]; u8 country_code[BRCM_CNTRY_BUF_SZ];
char eventmask[BRCMF_EVENTING_MASK_LEN]; char eventmask[BRCMF_EVENTING_MASK_LEN];
}; };
struct brcmf_if_event { struct brcmf_if_event {
@ -681,8 +687,8 @@ extern uint brcmf_c_mkiovar(char *name, char *data, uint datalen,
* Returned structure should have bus and prot pointers filled in. * Returned structure should have bus and prot pointers filled in.
* bus_hdrlen specifies required headroom for bus module header. * bus_hdrlen specifies required headroom for bus module header.
*/ */
extern struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus, extern struct brcmf_pub *brcmf_attach(struct brcmf_sdio *bus,
uint bus_hdrlen); uint bus_hdrlen, struct device *dev);
extern int brcmf_net_attach(struct brcmf_pub *drvr, int idx); extern int brcmf_net_attach(struct brcmf_pub *drvr, int idx);
extern int brcmf_netdev_wait_pend8021x(struct net_device *ndev); extern int brcmf_netdev_wait_pend8021x(struct net_device *ndev);
@ -699,7 +705,16 @@ extern bool brcmf_c_prec_enq(struct brcmf_pub *drvr, struct pktq *q,
/* Receive frame for delivery to OS. Callee disposes of rxp. */ /* Receive frame for delivery to OS. Callee disposes of rxp. */
extern void brcmf_rx_frame(struct brcmf_pub *drvr, int ifidx, extern void brcmf_rx_frame(struct brcmf_pub *drvr, int ifidx,
struct sk_buff *rxp, int numpkt); struct sk_buff_head *rxlist);
static inline void brcmf_rx_packet(struct brcmf_pub *drvr, int ifidx,
struct sk_buff *pkt)
{
struct sk_buff_head q;
skb_queue_head_init(&q);
skb_queue_tail(&q, pkt);
brcmf_rx_frame(drvr, ifidx, &q);
}
/* Return pointer to interface name */ /* Return pointer to interface name */
extern char *brcmf_ifname(struct brcmf_pub *drvr, int idx); extern char *brcmf_ifname(struct brcmf_pub *drvr, int idx);
@ -724,8 +739,6 @@ extern int brcmf_c_host_event(struct brcmf_info *drvr_priv, int *idx,
void *pktdata, struct brcmf_event_msg *, void *pktdata, struct brcmf_event_msg *,
void **data_ptr); void **data_ptr);
extern void brcmf_c_init(void);
extern int brcmf_add_if(struct brcmf_info *drvr_priv, int ifidx, extern int brcmf_add_if(struct brcmf_info *drvr_priv, int ifidx,
char *name, u8 *mac_addr); char *name, u8 *mac_addr);
extern void brcmf_del_if(struct brcmf_info *drvr_priv, int ifidx); extern void brcmf_del_if(struct brcmf_info *drvr_priv, int ifidx);

View File

@ -27,31 +27,24 @@
* Exported from brcmf bus module (brcmf_usb, brcmf_sdio) * Exported from brcmf bus module (brcmf_usb, brcmf_sdio)
*/ */
/* Indicate (dis)interest in finding dongles. */
extern int brcmf_bus_register(void);
extern void brcmf_bus_unregister(void);
/* obtain linux device object providing bus function */
extern struct device *brcmf_bus_get_device(struct brcmf_bus *bus);
/* Stop bus module: clear pending frames, disable data flow */ /* Stop bus module: clear pending frames, disable data flow */
extern void brcmf_sdbrcm_bus_stop(struct brcmf_bus *bus); extern void brcmf_sdbrcm_bus_stop(struct device *dev);
/* Initialize bus module: prepare for communication w/dongle */ /* Initialize bus module: prepare for communication w/dongle */
extern int brcmf_sdbrcm_bus_init(struct brcmf_pub *drvr); extern int brcmf_sdbrcm_bus_init(struct device *dev);
/* Send a data frame to the dongle. Callee disposes of txp. */ /* Send a data frame to the dongle. Callee disposes of txp. */
extern int brcmf_sdbrcm_bus_txdata(struct brcmf_bus *bus, struct sk_buff *txp); extern int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *txp);
/* Send/receive a control message to/from the dongle. /* Send/receive a control message to/from the dongle.
* Expects caller to enforce a single outstanding transaction. * Expects caller to enforce a single outstanding transaction.
*/ */
extern int extern int
brcmf_sdbrcm_bus_txctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen); brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen);
extern int extern int
brcmf_sdbrcm_bus_rxctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen); brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen);
extern void brcmf_sdbrcm_wd_timer(struct brcmf_bus *bus, uint wdtick); extern void brcmf_sdbrcm_wd_timer(struct brcmf_sdio *bus, uint wdtick);
#endif /* _BRCMF_BUS_H_ */ #endif /* _BRCMF_BUS_H_ */

View File

@ -116,7 +116,7 @@ static int brcmf_proto_cdc_msg(struct brcmf_pub *drvr)
len = CDC_MAX_MSG_SIZE; len = CDC_MAX_MSG_SIZE;
/* Send request */ /* Send request */
return brcmf_sdbrcm_bus_txctl(drvr->bus, (unsigned char *)&prot->msg, return brcmf_sdbrcm_bus_txctl(drvr->dev, (unsigned char *)&prot->msg,
len); len);
} }
@ -128,7 +128,7 @@ static int brcmf_proto_cdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len)
brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(TRACE, "Enter\n");
do { do {
ret = brcmf_sdbrcm_bus_rxctl(drvr->bus, ret = brcmf_sdbrcm_bus_rxctl(drvr->dev,
(unsigned char *)&prot->msg, (unsigned char *)&prot->msg,
len + sizeof(struct brcmf_proto_cdc_dcmd)); len + sizeof(struct brcmf_proto_cdc_dcmd));
if (ret < 0) if (ret < 0)
@ -280,7 +280,7 @@ brcmf_proto_dcmd(struct brcmf_pub *drvr, int ifidx, struct brcmf_dcmd *dcmd,
struct brcmf_proto *prot = drvr->prot; struct brcmf_proto *prot = drvr->prot;
int ret = -1; int ret = -1;
if (drvr->busstate == BRCMF_BUS_DOWN) { if (drvr->bus_if->state == BRCMF_BUS_DOWN) {
brcmf_dbg(ERROR, "bus is down. we have nothing to do.\n"); brcmf_dbg(ERROR, "bus is down. we have nothing to do.\n");
return ret; return ret;
} }

View File

@ -32,8 +32,6 @@
#define PKTFILTER_BUF_SIZE 2048 #define PKTFILTER_BUF_SIZE 2048
#define BRCMF_ARPOL_MODE 0xb /* agent|snoop|peer_autoreply */ #define BRCMF_ARPOL_MODE 0xb /* agent|snoop|peer_autoreply */
int brcmf_msg_level;
#define MSGTRACE_VERSION 1 #define MSGTRACE_VERSION 1
#define BRCMF_PKT_FILTER_FIXED_LEN offsetof(struct brcmf_pkt_filter_le, u) #define BRCMF_PKT_FILTER_FIXED_LEN offsetof(struct brcmf_pkt_filter_le, u)
@ -85,19 +83,6 @@ brcmf_c_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
return len; return len;
} }
void brcmf_c_init(void)
{
/* Init global variables at run-time, not as part of the declaration.
* This is required to support init/de-init of the driver.
* Initialization
* of globals as part of the declaration results in non-deterministic
* behaviour since the value of the globals may be different on the
* first time that the driver is initialized vs subsequent
* initializations.
*/
brcmf_msg_level = BRCMF_ERROR_VAL;
}
bool brcmf_c_prec_enq(struct brcmf_pub *drvr, struct pktq *q, bool brcmf_c_prec_enq(struct brcmf_pub *drvr, struct pktq *q,
struct sk_buff *pkt, int prec) struct sk_buff *pkt, int prec)
{ {

View File

@ -43,7 +43,6 @@
#include "dhd_proto.h" #include "dhd_proto.h"
#include "dhd_dbg.h" #include "dhd_dbg.h"
#include "wl_cfg80211.h" #include "wl_cfg80211.h"
#include "bcmchip.h"
MODULE_AUTHOR("Broadcom Corporation"); MODULE_AUTHOR("Broadcom Corporation");
MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN fullmac driver."); MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN fullmac driver.");
@ -77,6 +76,7 @@ struct brcmf_info {
}; };
/* Error bits */ /* Error bits */
int brcmf_msg_level = BRCMF_ERROR_VAL;
module_param(brcmf_msg_level, int, 0); module_param(brcmf_msg_level, int, 0);
int brcmf_ifname2idx(struct brcmf_info *drvr_priv, char *name) int brcmf_ifname2idx(struct brcmf_info *drvr_priv, char *name)
@ -292,7 +292,7 @@ int brcmf_sendpkt(struct brcmf_pub *drvr, int ifidx, struct sk_buff *pktbuf)
struct brcmf_info *drvr_priv = drvr->info; struct brcmf_info *drvr_priv = drvr->info;
/* Reject if down */ /* Reject if down */
if (!drvr->up || (drvr->busstate == BRCMF_BUS_DOWN)) if (!drvr->up || (drvr->bus_if->state == BRCMF_BUS_DOWN))
return -ENODEV; return -ENODEV;
/* Update multicast statistic */ /* Update multicast statistic */
@ -310,7 +310,7 @@ int brcmf_sendpkt(struct brcmf_pub *drvr, int ifidx, struct sk_buff *pktbuf)
brcmf_proto_hdrpush(drvr, ifidx, pktbuf); brcmf_proto_hdrpush(drvr, ifidx, pktbuf);
/* Use bus module to send data frame */ /* Use bus module to send data frame */
return brcmf_sdbrcm_bus_txdata(drvr->bus, pktbuf); return brcmf_sdbrcm_bus_txdata(drvr->dev, pktbuf);
} }
static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev) static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev)
@ -322,9 +322,11 @@ static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev)
brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(TRACE, "Enter\n");
/* Reject if down */ /* Reject if down */
if (!drvr_priv->pub.up || (drvr_priv->pub.busstate == BRCMF_BUS_DOWN)) { if (!drvr_priv->pub.up ||
brcmf_dbg(ERROR, "xmit rejected pub.up=%d busstate=%d\n", (drvr_priv->pub.bus_if->state == BRCMF_BUS_DOWN)) {
drvr_priv->pub.up, drvr_priv->pub.busstate); brcmf_dbg(ERROR, "xmit rejected pub.up=%d state=%d\n",
drvr_priv->pub.up,
drvr_priv->pub.bus_if->state);
netif_stop_queue(ndev); netif_stop_queue(ndev);
return -ENODEV; return -ENODEV;
} }
@ -397,26 +399,21 @@ static int brcmf_host_event(struct brcmf_info *drvr_priv, int *ifidx,
return bcmerror; return bcmerror;
} }
void brcmf_rx_frame(struct brcmf_pub *drvr, int ifidx, struct sk_buff *skb, void brcmf_rx_frame(struct brcmf_pub *drvr, int ifidx,
int numpkt) struct sk_buff_head *skb_list)
{ {
struct brcmf_info *drvr_priv = drvr->info; struct brcmf_info *drvr_priv = drvr->info;
unsigned char *eth; unsigned char *eth;
uint len; uint len;
void *data; void *data;
struct sk_buff *pnext, *save_pktbuf; struct sk_buff *skb, *pnext;
int i;
struct brcmf_if *ifp; struct brcmf_if *ifp;
struct brcmf_event_msg event; struct brcmf_event_msg event;
brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(TRACE, "Enter\n");
save_pktbuf = skb; skb_queue_walk_safe(skb_list, skb, pnext) {
skb_unlink(skb, skb_list);
for (i = 0; skb && i < numpkt; i++, skb = pnext) {
pnext = skb->next;
skb->next = NULL;
/* Get the protocol, maintain skb around eth_type_trans() /* Get the protocol, maintain skb around eth_type_trans()
* The main reason for this hack is for the limitation of * The main reason for this hack is for the limitation of
@ -437,6 +434,12 @@ void brcmf_rx_frame(struct brcmf_pub *drvr, int ifidx, struct sk_buff *skb,
if (ifp == NULL) if (ifp == NULL)
ifp = drvr_priv->iflist[0]; ifp = drvr_priv->iflist[0];
if (!ifp || !ifp->ndev ||
ifp->ndev->reg_state != NETREG_REGISTERED) {
brcmu_pkt_buf_free_skb(skb);
continue;
}
skb->dev = ifp->ndev; skb->dev = ifp->ndev;
skb->protocol = eth_type_trans(skb, skb->dev); skb->protocol = eth_type_trans(skb, skb->dev);
@ -605,9 +608,7 @@ static void brcmf_ethtool_get_drvinfo(struct net_device *ndev,
sprintf(info->driver, KBUILD_MODNAME); sprintf(info->driver, KBUILD_MODNAME);
sprintf(info->version, "%lu", drvr_priv->pub.drv_version); sprintf(info->version, "%lu", drvr_priv->pub.drv_version);
sprintf(info->fw_version, "%s", BCM4329_FW_NAME); sprintf(info->bus_info, "%s", dev_name(drvr_priv->pub.dev));
sprintf(info->bus_info, "%s",
dev_name(brcmf_bus_get_device(drvr_priv->pub.bus)));
} }
static struct ethtool_ops brcmf_ethtool_ops = { static struct ethtool_ops brcmf_ethtool_ops = {
@ -761,7 +762,7 @@ s32 brcmf_exec_dcmd(struct net_device *ndev, u32 cmd, void *arg, u32 len)
buflen = min_t(uint, dcmd.len, BRCMF_DCMD_MAXLEN); buflen = min_t(uint, dcmd.len, BRCMF_DCMD_MAXLEN);
/* send to dongle (must be up, and wl) */ /* send to dongle (must be up, and wl) */
if ((drvr_priv->pub.busstate != BRCMF_BUS_DATA)) { if ((drvr_priv->pub.bus_if->state != BRCMF_BUS_DATA)) {
brcmf_dbg(ERROR, "DONGLE_DOWN\n"); brcmf_dbg(ERROR, "DONGLE_DOWN\n");
err = -EIO; err = -EIO;
goto done; goto done;
@ -940,7 +941,8 @@ void brcmf_del_if(struct brcmf_info *drvr_priv, int ifidx)
} }
} }
struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus, uint bus_hdrlen) struct brcmf_pub *brcmf_attach(struct brcmf_sdio *bus, uint bus_hdrlen,
struct device *dev)
{ {
struct brcmf_info *drvr_priv = NULL; struct brcmf_info *drvr_priv = NULL;
@ -959,6 +961,8 @@ struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus, uint bus_hdrlen)
/* Link to bus module */ /* Link to bus module */
drvr_priv->pub.bus = bus; drvr_priv->pub.bus = bus;
drvr_priv->pub.hdrlen = bus_hdrlen; drvr_priv->pub.hdrlen = bus_hdrlen;
drvr_priv->pub.bus_if = dev_get_drvdata(dev);
drvr_priv->pub.dev = dev;
/* Attach and link in the protocol */ /* Attach and link in the protocol */
if (brcmf_proto_attach(&drvr_priv->pub) != 0) { if (brcmf_proto_attach(&drvr_priv->pub) != 0) {
@ -988,14 +992,14 @@ int brcmf_bus_start(struct brcmf_pub *drvr)
brcmf_dbg(TRACE, "\n"); brcmf_dbg(TRACE, "\n");
/* Bring up the bus */ /* Bring up the bus */
ret = brcmf_sdbrcm_bus_init(&drvr_priv->pub); ret = brcmf_sdbrcm_bus_init(drvr_priv->pub.dev);
if (ret != 0) { if (ret != 0) {
brcmf_dbg(ERROR, "brcmf_sdbrcm_bus_init failed %d\n", ret); brcmf_dbg(ERROR, "brcmf_sdbrcm_bus_init failed %d\n", ret);
return ret; return ret;
} }
/* If bus is not ready, can't come up */ /* If bus is not ready, can't come up */
if (drvr_priv->pub.busstate != BRCMF_BUS_DATA) { if (drvr_priv->pub.bus_if->state != BRCMF_BUS_DATA) {
brcmf_dbg(ERROR, "failed bus is not ready\n"); brcmf_dbg(ERROR, "failed bus is not ready\n");
return -ENODEV; return -ENODEV;
} }
@ -1077,10 +1081,7 @@ int brcmf_net_attach(struct brcmf_pub *drvr, int ifidx)
/* attach to cfg80211 for primary interface */ /* attach to cfg80211 for primary interface */
if (!ifidx) { if (!ifidx) {
drvr->config = drvr->config = brcmf_cfg80211_attach(ndev, drvr->dev, drvr);
brcmf_cfg80211_attach(ndev,
brcmf_bus_get_device(drvr->bus),
drvr);
if (drvr->config == NULL) { if (drvr->config == NULL) {
brcmf_dbg(ERROR, "wl_cfg80211_attach failed\n"); brcmf_dbg(ERROR, "wl_cfg80211_attach failed\n");
goto fail; goto fail;
@ -1114,7 +1115,7 @@ static void brcmf_bus_detach(struct brcmf_pub *drvr)
brcmf_proto_stop(&drvr_priv->pub); brcmf_proto_stop(&drvr_priv->pub);
/* Stop the bus module */ /* Stop the bus module */
brcmf_sdbrcm_bus_stop(drvr_priv->pub.bus); brcmf_sdbrcm_bus_stop(drvr_priv->pub.dev);
} }
} }
} }
@ -1148,34 +1149,6 @@ void brcmf_detach(struct brcmf_pub *drvr)
} }
} }
static void __exit brcmf_module_cleanup(void)
{
brcmf_dbg(TRACE, "Enter\n");
brcmf_bus_unregister();
}
static int __init brcmf_module_init(void)
{
int error;
brcmf_dbg(TRACE, "Enter\n");
error = brcmf_bus_register();
if (error) {
brcmf_dbg(ERROR, "brcmf_bus_register failed\n");
goto failed;
}
return 0;
failed:
return -EINVAL;
}
module_init(brcmf_module_init);
module_exit(brcmf_module_cleanup);
int brcmf_os_proto_block(struct brcmf_pub *drvr) int brcmf_os_proto_block(struct brcmf_pub *drvr)
{ {
struct brcmf_info *drvr_priv = drvr->info; struct brcmf_info *drvr_priv = drvr->info;

View File

@ -91,7 +91,6 @@ struct rte_console {
#include "dhd_bus.h" #include "dhd_bus.h"
#include "dhd_proto.h" #include "dhd_proto.h"
#include "dhd_dbg.h" #include "dhd_dbg.h"
#include <bcmchip.h>
#define TXQLEN 2048 /* bulk tx queue length */ #define TXQLEN 2048 /* bulk tx queue length */
#define TXHI (TXQLEN - 256) /* turn on flow control above TXHI */ #define TXHI (TXQLEN - 256) /* turn on flow control above TXHI */
@ -310,6 +309,11 @@ struct rte_console {
/* Flags for SDH calls */ /* Flags for SDH calls */
#define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED) #define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED)
#define BRCMFMAC_FW_NAME "brcm/brcmfmac.bin"
#define BRCMFMAC_NV_NAME "brcm/brcmfmac.txt"
MODULE_FIRMWARE(BRCMFMAC_FW_NAME);
MODULE_FIRMWARE(BRCMFMAC_NV_NAME);
/* /*
* Conversion of 802.1D priority to precedence level * Conversion of 802.1D priority to precedence level
*/ */
@ -445,7 +449,7 @@ struct sdpcm_shared_le {
/* misc chip info needed by some of the routines */ /* misc chip info needed by some of the routines */
/* Private data for SDIO bus interaction */ /* Private data for SDIO bus interaction */
struct brcmf_bus { struct brcmf_sdio {
struct brcmf_pub *drvr; struct brcmf_pub *drvr;
struct brcmf_sdio_dev *sdiodev; /* sdio device handler */ struct brcmf_sdio_dev *sdiodev; /* sdio device handler */
@ -562,9 +566,7 @@ struct brcmf_bus {
struct semaphore sdsem; struct semaphore sdsem;
const char *fw_name;
const struct firmware *firmware; const struct firmware *firmware;
const char *nv_name;
u32 fw_ptr; u32 fw_ptr;
}; };
@ -602,7 +604,7 @@ static void pkt_align(struct sk_buff *p, int len, int align)
} }
/* To check if there's window offered */ /* To check if there's window offered */
static bool data_ok(struct brcmf_bus *bus) static bool data_ok(struct brcmf_sdio *bus)
{ {
return (u8)(bus->tx_max - bus->tx_seq) != 0 && return (u8)(bus->tx_max - bus->tx_seq) != 0 &&
((u8)(bus->tx_max - bus->tx_seq) & 0x80) == 0; ((u8)(bus->tx_max - bus->tx_seq) & 0x80) == 0;
@ -613,7 +615,7 @@ static bool data_ok(struct brcmf_bus *bus)
* adresses on the 32 bit backplane bus. * adresses on the 32 bit backplane bus.
*/ */
static void static void
r_sdreg32(struct brcmf_bus *bus, u32 *regvar, u32 reg_offset, u32 *retryvar) r_sdreg32(struct brcmf_sdio *bus, u32 *regvar, u32 reg_offset, u32 *retryvar)
{ {
u8 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV); u8 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
*retryvar = 0; *retryvar = 0;
@ -633,7 +635,7 @@ r_sdreg32(struct brcmf_bus *bus, u32 *regvar, u32 reg_offset, u32 *retryvar)
} }
static void static void
w_sdreg32(struct brcmf_bus *bus, u32 regval, u32 reg_offset, u32 *retryvar) w_sdreg32(struct brcmf_sdio *bus, u32 regval, u32 reg_offset, u32 *retryvar)
{ {
u8 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV); u8 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
*retryvar = 0; *retryvar = 0;
@ -658,14 +660,14 @@ w_sdreg32(struct brcmf_bus *bus, u32 regval, u32 reg_offset, u32 *retryvar)
/* Packet free applicable unconditionally for sdio and sdspi. /* Packet free applicable unconditionally for sdio and sdspi.
* Conditional if bufpool was present for gspi bus. * Conditional if bufpool was present for gspi bus.
*/ */
static void brcmf_sdbrcm_pktfree2(struct brcmf_bus *bus, struct sk_buff *pkt) static void brcmf_sdbrcm_pktfree2(struct brcmf_sdio *bus, struct sk_buff *pkt)
{ {
if (bus->usebufpool) if (bus->usebufpool)
brcmu_pkt_buf_free_skb(pkt); brcmu_pkt_buf_free_skb(pkt);
} }
/* Turn backplane clock on or off */ /* Turn backplane clock on or off */
static int brcmf_sdbrcm_htclk(struct brcmf_bus *bus, bool on, bool pendok) static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
{ {
int err; int err;
u8 clkctl, clkreq, devctl; u8 clkctl, clkreq, devctl;
@ -786,7 +788,7 @@ static int brcmf_sdbrcm_htclk(struct brcmf_bus *bus, bool on, bool pendok)
} }
/* Change idle/active SD state */ /* Change idle/active SD state */
static int brcmf_sdbrcm_sdclk(struct brcmf_bus *bus, bool on) static int brcmf_sdbrcm_sdclk(struct brcmf_sdio *bus, bool on)
{ {
brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(TRACE, "Enter\n");
@ -799,7 +801,7 @@ static int brcmf_sdbrcm_sdclk(struct brcmf_bus *bus, bool on)
} }
/* Transition SD and backplane clock readiness */ /* Transition SD and backplane clock readiness */
static int brcmf_sdbrcm_clkctl(struct brcmf_bus *bus, uint target, bool pendok) static int brcmf_sdbrcm_clkctl(struct brcmf_sdio *bus, uint target, bool pendok)
{ {
#ifdef BCMDBG #ifdef BCMDBG
uint oldstate = bus->clkstate; uint oldstate = bus->clkstate;
@ -855,7 +857,7 @@ static int brcmf_sdbrcm_clkctl(struct brcmf_bus *bus, uint target, bool pendok)
return 0; return 0;
} }
static int brcmf_sdbrcm_bussleep(struct brcmf_bus *bus, bool sleep) static int brcmf_sdbrcm_bussleep(struct brcmf_sdio *bus, bool sleep)
{ {
uint retries = 0; uint retries = 0;
@ -927,13 +929,13 @@ static int brcmf_sdbrcm_bussleep(struct brcmf_bus *bus, bool sleep)
return 0; return 0;
} }
static void bus_wake(struct brcmf_bus *bus) static void bus_wake(struct brcmf_sdio *bus)
{ {
if (bus->sleeping) if (bus->sleeping)
brcmf_sdbrcm_bussleep(bus, false); brcmf_sdbrcm_bussleep(bus, false);
} }
static u32 brcmf_sdbrcm_hostmail(struct brcmf_bus *bus) static u32 brcmf_sdbrcm_hostmail(struct brcmf_sdio *bus)
{ {
u32 intstatus = 0; u32 intstatus = 0;
u32 hmb_data; u32 hmb_data;
@ -1009,7 +1011,7 @@ static u32 brcmf_sdbrcm_hostmail(struct brcmf_bus *bus)
return intstatus; return intstatus;
} }
static void brcmf_sdbrcm_rxfail(struct brcmf_bus *bus, bool abort, bool rtx) static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)
{ {
uint retries = 0; uint retries = 0;
u16 lastrbc; u16 lastrbc;
@ -1066,11 +1068,11 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_bus *bus, bool abort, bool rtx)
/* If we can't reach the device, signal failure */ /* If we can't reach the device, signal failure */
if (err || brcmf_sdcard_regfail(bus->sdiodev)) if (err || brcmf_sdcard_regfail(bus->sdiodev))
bus->drvr->busstate = BRCMF_BUS_DOWN; bus->drvr->bus_if->state = BRCMF_BUS_DOWN;
} }
/* copy a buffer into a pkt buffer chain */ /* copy a buffer into a pkt buffer chain */
static uint brcmf_sdbrcm_glom_from_buf(struct brcmf_bus *bus, uint len) static uint brcmf_sdbrcm_glom_from_buf(struct brcmf_sdio *bus, uint len)
{ {
uint n, ret = 0; uint n, ret = 0;
struct sk_buff *p; struct sk_buff *p;
@ -1093,7 +1095,7 @@ static uint brcmf_sdbrcm_glom_from_buf(struct brcmf_bus *bus, uint len)
} }
/* return total length of buffer chain */ /* return total length of buffer chain */
static uint brcmf_sdbrcm_glom_len(struct brcmf_bus *bus) static uint brcmf_sdbrcm_glom_len(struct brcmf_sdio *bus)
{ {
struct sk_buff *p; struct sk_buff *p;
uint total; uint total;
@ -1104,7 +1106,7 @@ static uint brcmf_sdbrcm_glom_len(struct brcmf_bus *bus)
return total; return total;
} }
static void brcmf_sdbrcm_free_glom(struct brcmf_bus *bus) static void brcmf_sdbrcm_free_glom(struct brcmf_sdio *bus)
{ {
struct sk_buff *cur, *next; struct sk_buff *cur, *next;
@ -1114,13 +1116,13 @@ static void brcmf_sdbrcm_free_glom(struct brcmf_bus *bus)
} }
} }
static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq) static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
{ {
u16 dlen, totlen; u16 dlen, totlen;
u8 *dptr, num = 0; u8 *dptr, num = 0;
u16 sublen, check; u16 sublen, check;
struct sk_buff *pfirst, *plast, *pnext, *save_pfirst; struct sk_buff *pfirst, *pnext;
int errcode; int errcode;
u8 chan, seq, doff, sfdoff; u8 chan, seq, doff, sfdoff;
@ -1137,7 +1139,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
/* If there's a descriptor, generate the packet chain */ /* If there's a descriptor, generate the packet chain */
if (bus->glomd) { if (bus->glomd) {
pfirst = plast = pnext = NULL; pfirst = pnext = NULL;
dlen = (u16) (bus->glomd->len); dlen = (u16) (bus->glomd->len);
dptr = bus->glomd->data; dptr = bus->glomd->data;
if (!dlen || (dlen & 1)) { if (!dlen || (dlen & 1)) {
@ -1228,17 +1230,14 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
* packet and and copy into the chain. * packet and and copy into the chain.
*/ */
if (usechain) { if (usechain) {
errcode = brcmf_sdcard_recv_buf(bus->sdiodev, errcode = brcmf_sdcard_recv_chain(bus->sdiodev,
bus->sdiodev->sbwad, bus->sdiodev->sbwad,
SDIO_FUNC_2, SDIO_FUNC_2, F2SYNC, &bus->glom);
F2SYNC, (u8 *) pfirst->data, dlen,
pfirst);
} else if (bus->dataptr) { } else if (bus->dataptr) {
errcode = brcmf_sdcard_recv_buf(bus->sdiodev, errcode = brcmf_sdcard_recv_buf(bus->sdiodev,
bus->sdiodev->sbwad, bus->sdiodev->sbwad,
SDIO_FUNC_2, SDIO_FUNC_2, F2SYNC,
F2SYNC, bus->dataptr, dlen, bus->dataptr, dlen);
NULL);
sublen = (u16) brcmf_sdbrcm_glom_from_buf(bus, dlen); sublen = (u16) brcmf_sdbrcm_glom_from_buf(bus, dlen);
if (sublen != dlen) { if (sublen != dlen) {
brcmf_dbg(ERROR, "FAILED TO COPY, dlen %d sublen %d\n", brcmf_dbg(ERROR, "FAILED TO COPY, dlen %d sublen %d\n",
@ -1338,10 +1337,14 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
/* Remove superframe header, remember offset */ /* Remove superframe header, remember offset */
skb_pull(pfirst, doff); skb_pull(pfirst, doff);
sfdoff = doff; sfdoff = doff;
num = 0;
/* Validate all the subframe headers */ /* Validate all the subframe headers */
for (num = 0, pnext = pfirst; pnext && !errcode; skb_queue_walk(&bus->glom, pnext) {
num++, pnext = pnext->next) { /* leave when invalid subframe is found */
if (errcode)
break;
dptr = (u8 *) (pnext->data); dptr = (u8 *) (pnext->data);
dlen = (u16) (pnext->len); dlen = (u16) (pnext->len);
sublen = get_unaligned_le16(dptr); sublen = get_unaligned_le16(dptr);
@ -1374,6 +1377,8 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
num, doff, sublen, SDPCM_HDRLEN); num, doff, sublen, SDPCM_HDRLEN);
errcode = -1; errcode = -1;
} }
/* increase the subframe count */
num++;
} }
if (errcode) { if (errcode) {
@ -1394,13 +1399,8 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
} }
/* Basic SD framing looks ok - process each packet (header) */ /* Basic SD framing looks ok - process each packet (header) */
save_pfirst = pfirst;
plast = NULL;
for (num = 0; pfirst; rxseq++, pfirst = pnext) {
pnext = pfirst->next;
pfirst->next = NULL;
skb_queue_walk_safe(&bus->glom, pfirst, pnext) {
dptr = (u8 *) (pfirst->data); dptr = (u8 *) (pfirst->data);
sublen = get_unaligned_le16(dptr); sublen = get_unaligned_le16(dptr);
chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
@ -1420,6 +1420,8 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
bus->rx_badseq++; bus->rx_badseq++;
rxseq = seq; rxseq = seq;
} }
rxseq++;
#ifdef BCMDBG #ifdef BCMDBG
if (BRCMF_BYTES_ON() && BRCMF_DATA_ON()) { if (BRCMF_BYTES_ON() && BRCMF_DATA_ON()) {
printk(KERN_DEBUG "Rx Subframe Data:\n"); printk(KERN_DEBUG "Rx Subframe Data:\n");
@ -1432,36 +1434,22 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
skb_pull(pfirst, doff); skb_pull(pfirst, doff);
if (pfirst->len == 0) { if (pfirst->len == 0) {
skb_unlink(pfirst, &bus->glom);
brcmu_pkt_buf_free_skb(pfirst); brcmu_pkt_buf_free_skb(pfirst);
if (plast)
plast->next = pnext;
else
save_pfirst = pnext;
continue; continue;
} else if (brcmf_proto_hdrpull(bus->drvr, &ifidx, } else if (brcmf_proto_hdrpull(bus->drvr, &ifidx,
pfirst) != 0) { pfirst) != 0) {
brcmf_dbg(ERROR, "rx protocol error\n"); brcmf_dbg(ERROR, "rx protocol error\n");
bus->drvr->rx_errors++; bus->drvr->rx_errors++;
skb_unlink(pfirst, &bus->glom);
brcmu_pkt_buf_free_skb(pfirst); brcmu_pkt_buf_free_skb(pfirst);
if (plast)
plast->next = pnext;
else
save_pfirst = pnext;
continue; continue;
} }
/* this packet will go up, link back into
chain and count it */
pfirst->next = pnext;
plast = pfirst;
num++;
#ifdef BCMDBG #ifdef BCMDBG
if (BRCMF_GLOM_ON()) { if (BRCMF_GLOM_ON()) {
brcmf_dbg(GLOM, "subframe %d to stack, %p (%p/%d) nxt/lnk %p/%p\n", brcmf_dbg(GLOM, "subframe %d to stack, %p (%p/%d) nxt/lnk %p/%p\n",
num, pfirst, pfirst->data, bus->glom.qlen, pfirst, pfirst->data,
pfirst->len, pfirst->next, pfirst->len, pfirst->next,
pfirst->prev); pfirst->prev);
print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
@ -1470,19 +1458,20 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
} }
#endif /* BCMDBG */ #endif /* BCMDBG */
} }
if (num) { /* sent any remaining packets up */
if (bus->glom.qlen) {
up(&bus->sdsem); up(&bus->sdsem);
brcmf_rx_frame(bus->drvr, ifidx, save_pfirst, num); brcmf_rx_frame(bus->drvr, ifidx, &bus->glom);
down(&bus->sdsem); down(&bus->sdsem);
} }
bus->rxglomframes++; bus->rxglomframes++;
bus->rxglompkts += num; bus->rxglompkts += bus->glom.qlen;
} }
return num; return num;
} }
static int brcmf_sdbrcm_dcmd_resp_wait(struct brcmf_bus *bus, uint *condition, static int brcmf_sdbrcm_dcmd_resp_wait(struct brcmf_sdio *bus, uint *condition,
bool *pending) bool *pending)
{ {
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
@ -1504,7 +1493,7 @@ static int brcmf_sdbrcm_dcmd_resp_wait(struct brcmf_bus *bus, uint *condition,
return timeout; return timeout;
} }
static int brcmf_sdbrcm_dcmd_resp_wake(struct brcmf_bus *bus) static int brcmf_sdbrcm_dcmd_resp_wake(struct brcmf_sdio *bus)
{ {
if (waitqueue_active(&bus->dcmd_resp_wait)) if (waitqueue_active(&bus->dcmd_resp_wait))
wake_up_interruptible(&bus->dcmd_resp_wait); wake_up_interruptible(&bus->dcmd_resp_wait);
@ -1512,7 +1501,7 @@ static int brcmf_sdbrcm_dcmd_resp_wake(struct brcmf_bus *bus)
return 0; return 0;
} }
static void static void
brcmf_sdbrcm_read_control(struct brcmf_bus *bus, u8 *hdr, uint len, uint doff) brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)
{ {
uint rdlen, pad; uint rdlen, pad;
@ -1570,8 +1559,7 @@ brcmf_sdbrcm_read_control(struct brcmf_bus *bus, u8 *hdr, uint len, uint doff)
sdret = brcmf_sdcard_recv_buf(bus->sdiodev, sdret = brcmf_sdcard_recv_buf(bus->sdiodev,
bus->sdiodev->sbwad, bus->sdiodev->sbwad,
SDIO_FUNC_2, SDIO_FUNC_2,
F2SYNC, (bus->rxctl + BRCMF_FIRSTREAD), rdlen, F2SYNC, (bus->rxctl + BRCMF_FIRSTREAD), rdlen);
NULL);
bus->f2rxdata++; bus->f2rxdata++;
/* Control frame failures need retransmission */ /* Control frame failures need retransmission */
@ -1602,7 +1590,7 @@ brcmf_sdbrcm_read_control(struct brcmf_bus *bus, u8 *hdr, uint len, uint doff)
} }
/* Pad read to blocksize for efficiency */ /* Pad read to blocksize for efficiency */
static void brcmf_pad(struct brcmf_bus *bus, u16 *pad, u16 *rdlen) static void brcmf_pad(struct brcmf_sdio *bus, u16 *pad, u16 *rdlen)
{ {
if (bus->roundup && bus->blocksize && *rdlen > bus->blocksize) { if (bus->roundup && bus->blocksize && *rdlen > bus->blocksize) {
*pad = bus->blocksize - (*rdlen % bus->blocksize); *pad = bus->blocksize - (*rdlen % bus->blocksize);
@ -1615,7 +1603,7 @@ static void brcmf_pad(struct brcmf_bus *bus, u16 *pad, u16 *rdlen)
} }
static void static void
brcmf_alloc_pkt_and_read(struct brcmf_bus *bus, u16 rdlen, brcmf_alloc_pkt_and_read(struct brcmf_sdio *bus, u16 rdlen,
struct sk_buff **pkt, u8 **rxbuf) struct sk_buff **pkt, u8 **rxbuf)
{ {
int sdret; /* Return code from calls */ int sdret; /* Return code from calls */
@ -1627,9 +1615,8 @@ brcmf_alloc_pkt_and_read(struct brcmf_bus *bus, u16 rdlen,
pkt_align(*pkt, rdlen, BRCMF_SDALIGN); pkt_align(*pkt, rdlen, BRCMF_SDALIGN);
*rxbuf = (u8 *) ((*pkt)->data); *rxbuf = (u8 *) ((*pkt)->data);
/* Read the entire frame */ /* Read the entire frame */
sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad, sdret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad,
SDIO_FUNC_2, F2SYNC, SDIO_FUNC_2, F2SYNC, *pkt);
*rxbuf, rdlen, *pkt);
bus->f2rxdata++; bus->f2rxdata++;
if (sdret < 0) { if (sdret < 0) {
@ -1648,7 +1635,7 @@ brcmf_alloc_pkt_and_read(struct brcmf_bus *bus, u16 rdlen,
/* Checks the header */ /* Checks the header */
static int static int
brcmf_check_rxbuf(struct brcmf_bus *bus, struct sk_buff *pkt, u8 *rxbuf, brcmf_check_rxbuf(struct brcmf_sdio *bus, struct sk_buff *pkt, u8 *rxbuf,
u8 rxseq, u16 nextlen, u16 *len) u8 rxseq, u16 nextlen, u16 *len)
{ {
u16 check; u16 check;
@ -1704,7 +1691,7 @@ brcmf_check_rxbuf(struct brcmf_bus *bus, struct sk_buff *pkt, u8 *rxbuf,
/* Return true if there may be more frames to read */ /* Return true if there may be more frames to read */
static uint static uint
brcmf_sdbrcm_readframes(struct brcmf_bus *bus, uint maxframes, bool *finished) brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished)
{ {
u16 len, check; /* Extracted hardware header fields */ u16 len, check; /* Extracted hardware header fields */
u8 chan, seq, doff; /* Extracted software header fields */ u8 chan, seq, doff; /* Extracted software header fields */
@ -1727,7 +1714,8 @@ brcmf_sdbrcm_readframes(struct brcmf_bus *bus, uint maxframes, bool *finished)
*finished = false; *finished = false;
for (rxseq = bus->rx_seq, rxleft = maxframes; for (rxseq = bus->rx_seq, rxleft = maxframes;
!bus->rxskip && rxleft && bus->drvr->busstate != BRCMF_BUS_DOWN; !bus->rxskip && rxleft &&
bus->drvr->bus_if->state != BRCMF_BUS_DOWN;
rxseq++, rxleft--) { rxseq++, rxleft--) {
/* Handle glomming separately */ /* Handle glomming separately */
@ -1857,7 +1845,7 @@ brcmf_sdbrcm_readframes(struct brcmf_bus *bus, uint maxframes, bool *finished)
/* Read frame header (hardware and software) */ /* Read frame header (hardware and software) */
sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad, sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad,
SDIO_FUNC_2, F2SYNC, bus->rxhdr, SDIO_FUNC_2, F2SYNC, bus->rxhdr,
BRCMF_FIRSTREAD, NULL); BRCMF_FIRSTREAD);
bus->f2rxhdrs++; bus->f2rxhdrs++;
if (sdret < 0) { if (sdret < 0) {
@ -2006,9 +1994,8 @@ brcmf_sdbrcm_readframes(struct brcmf_bus *bus, uint maxframes, bool *finished)
pkt_align(pkt, rdlen, BRCMF_SDALIGN); pkt_align(pkt, rdlen, BRCMF_SDALIGN);
/* Read the remaining frame data */ /* Read the remaining frame data */
sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad, sdret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad,
SDIO_FUNC_2, F2SYNC, ((u8 *) (pkt->data)), SDIO_FUNC_2, F2SYNC, pkt);
rdlen, pkt);
bus->f2rxdata++; bus->f2rxdata++;
if (sdret < 0) { if (sdret < 0) {
@ -2075,7 +2062,7 @@ brcmf_sdbrcm_readframes(struct brcmf_bus *bus, uint maxframes, bool *finished)
/* Unlock during rx call */ /* Unlock during rx call */
up(&bus->sdsem); up(&bus->sdsem);
brcmf_rx_frame(bus->drvr, ifidx, pkt, 1); brcmf_rx_packet(bus->drvr, ifidx, pkt);
down(&bus->sdsem); down(&bus->sdsem);
} }
rxcount = maxframes - rxleft; rxcount = maxframes - rxleft;
@ -2095,16 +2082,8 @@ brcmf_sdbrcm_readframes(struct brcmf_bus *bus, uint maxframes, bool *finished)
return rxcount; return rxcount;
} }
static int
brcmf_sdbrcm_send_buf(struct brcmf_bus *bus, u32 addr, uint fn, uint flags,
u8 *buf, uint nbytes, struct sk_buff *pkt)
{
return brcmf_sdcard_send_buf
(bus->sdiodev, addr, fn, flags, buf, nbytes, pkt);
}
static void static void
brcmf_sdbrcm_wait_for_event(struct brcmf_bus *bus, bool *lockvar) brcmf_sdbrcm_wait_for_event(struct brcmf_sdio *bus, bool *lockvar)
{ {
up(&bus->sdsem); up(&bus->sdsem);
wait_event_interruptible_timeout(bus->ctrl_wait, wait_event_interruptible_timeout(bus->ctrl_wait,
@ -2114,7 +2093,7 @@ brcmf_sdbrcm_wait_for_event(struct brcmf_bus *bus, bool *lockvar)
} }
static void static void
brcmf_sdbrcm_wait_event_wakeup(struct brcmf_bus *bus) brcmf_sdbrcm_wait_event_wakeup(struct brcmf_sdio *bus)
{ {
if (waitqueue_active(&bus->ctrl_wait)) if (waitqueue_active(&bus->ctrl_wait))
wake_up_interruptible(&bus->ctrl_wait); wake_up_interruptible(&bus->ctrl_wait);
@ -2123,7 +2102,7 @@ brcmf_sdbrcm_wait_event_wakeup(struct brcmf_bus *bus)
/* Writes a HW/SW header into the packet and sends it. */ /* Writes a HW/SW header into the packet and sends it. */
/* Assumes: (a) header space already there, (b) caller holds lock */ /* Assumes: (a) header space already there, (b) caller holds lock */
static int brcmf_sdbrcm_txpkt(struct brcmf_bus *bus, struct sk_buff *pkt, static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,
uint chan, bool free_pkt) uint chan, bool free_pkt)
{ {
int ret; int ret;
@ -2212,9 +2191,8 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_bus *bus, struct sk_buff *pkt,
if (len & (ALIGNMENT - 1)) if (len & (ALIGNMENT - 1))
len = roundup(len, ALIGNMENT); len = roundup(len, ALIGNMENT);
ret = brcmf_sdbrcm_send_buf(bus, bus->sdiodev->sbwad, ret = brcmf_sdcard_send_pkt(bus->sdiodev, bus->sdiodev->sbwad,
SDIO_FUNC_2, F2SYNC, frame, SDIO_FUNC_2, F2SYNC, pkt);
len, pkt);
bus->f2txdata++; bus->f2txdata++;
if (ret < 0) { if (ret < 0) {
@ -2261,7 +2239,7 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_bus *bus, struct sk_buff *pkt,
return ret; return ret;
} }
static uint brcmf_sdbrcm_sendfromq(struct brcmf_bus *bus, uint maxframes) static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes)
{ {
struct sk_buff *pkt; struct sk_buff *pkt;
u32 intstatus = 0; u32 intstatus = 0;
@ -2309,14 +2287,14 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_bus *bus, uint maxframes)
} }
/* Deflow-control stack if needed */ /* Deflow-control stack if needed */
if (drvr->up && (drvr->busstate == BRCMF_BUS_DATA) && if (drvr->up && (drvr->bus_if->state == BRCMF_BUS_DATA) &&
drvr->txoff && (pktq_len(&bus->txq) < TXLOW)) drvr->txoff && (pktq_len(&bus->txq) < TXLOW))
brcmf_txflowcontrol(drvr, 0, OFF); brcmf_txflowcontrol(drvr, 0, OFF);
return cnt; return cnt;
} }
static bool brcmf_sdbrcm_dpc(struct brcmf_bus *bus) static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
{ {
u32 intstatus, newstatus = 0; u32 intstatus, newstatus = 0;
uint retries = 0; uint retries = 0;
@ -2344,7 +2322,7 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_bus *bus)
SBSDIO_DEVICE_CTL, &err); SBSDIO_DEVICE_CTL, &err);
if (err) { if (err) {
brcmf_dbg(ERROR, "error reading DEVCTL: %d\n", err); brcmf_dbg(ERROR, "error reading DEVCTL: %d\n", err);
bus->drvr->busstate = BRCMF_BUS_DOWN; bus->drvr->bus_if->state = BRCMF_BUS_DOWN;
} }
#endif /* BCMDBG */ #endif /* BCMDBG */
@ -2354,7 +2332,7 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_bus *bus)
if (err) { if (err) {
brcmf_dbg(ERROR, "error reading CSR: %d\n", brcmf_dbg(ERROR, "error reading CSR: %d\n",
err); err);
bus->drvr->busstate = BRCMF_BUS_DOWN; bus->drvr->bus_if->state = BRCMF_BUS_DOWN;
} }
brcmf_dbg(INFO, "DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n", brcmf_dbg(INFO, "DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n",
@ -2367,7 +2345,7 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_bus *bus)
if (err) { if (err) {
brcmf_dbg(ERROR, "error reading DEVCTL: %d\n", brcmf_dbg(ERROR, "error reading DEVCTL: %d\n",
err); err);
bus->drvr->busstate = BRCMF_BUS_DOWN; bus->drvr->bus_if->state = BRCMF_BUS_DOWN;
} }
devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
@ -2375,7 +2353,7 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_bus *bus)
if (err) { if (err) {
brcmf_dbg(ERROR, "error writing DEVCTL: %d\n", brcmf_dbg(ERROR, "error writing DEVCTL: %d\n",
err); err);
bus->drvr->busstate = BRCMF_BUS_DOWN; bus->drvr->bus_if->state = BRCMF_BUS_DOWN;
} }
bus->clkstate = CLK_AVAIL; bus->clkstate = CLK_AVAIL;
} else { } else {
@ -2477,9 +2455,9 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_bus *bus)
(bus->clkstate == CLK_AVAIL)) { (bus->clkstate == CLK_AVAIL)) {
int ret, i; int ret, i;
ret = brcmf_sdbrcm_send_buf(bus, bus->sdiodev->sbwad, ret = brcmf_sdcard_send_buf(bus->sdiodev, bus->sdiodev->sbwad,
SDIO_FUNC_2, F2SYNC, (u8 *) bus->ctrl_frame_buf, SDIO_FUNC_2, F2SYNC, (u8 *) bus->ctrl_frame_buf,
(u32) bus->ctrl_frame_len, NULL); (u32) bus->ctrl_frame_len);
if (ret < 0) { if (ret < 0) {
/* On failure, abort the command and /* On failure, abort the command and
@ -2531,11 +2509,11 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_bus *bus)
else await next interrupt */ else await next interrupt */
/* On failed register access, all bets are off: /* On failed register access, all bets are off:
no resched or interrupts */ no resched or interrupts */
if ((bus->drvr->busstate == BRCMF_BUS_DOWN) || if ((bus->drvr->bus_if->state == BRCMF_BUS_DOWN) ||
brcmf_sdcard_regfail(bus->sdiodev)) { brcmf_sdcard_regfail(bus->sdiodev)) {
brcmf_dbg(ERROR, "failed backplane access over SDIO, halting operation %d\n", brcmf_dbg(ERROR, "failed backplane access over SDIO, halting operation %d\n",
brcmf_sdcard_regfail(bus->sdiodev)); brcmf_sdcard_regfail(bus->sdiodev));
bus->drvr->busstate = BRCMF_BUS_DOWN; bus->drvr->bus_if->state = BRCMF_BUS_DOWN;
bus->intstatus = 0; bus->intstatus = 0;
} else if (bus->clkstate == CLK_PENDING) { } else if (bus->clkstate == CLK_PENDING) {
brcmf_dbg(INFO, "rescheduled due to CLK_PENDING awaiting I_CHIPACTIVE interrupt\n"); brcmf_dbg(INFO, "rescheduled due to CLK_PENDING awaiting I_CHIPACTIVE interrupt\n");
@ -2562,7 +2540,7 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_bus *bus)
static int brcmf_sdbrcm_dpc_thread(void *data) static int brcmf_sdbrcm_dpc_thread(void *data)
{ {
struct brcmf_bus *bus = (struct brcmf_bus *) data; struct brcmf_sdio *bus = (struct brcmf_sdio *) data;
allow_signal(SIGTERM); allow_signal(SIGTERM);
/* Run until signal received */ /* Run until signal received */
@ -2572,12 +2550,12 @@ static int brcmf_sdbrcm_dpc_thread(void *data)
if (!wait_for_completion_interruptible(&bus->dpc_wait)) { if (!wait_for_completion_interruptible(&bus->dpc_wait)) {
/* Call bus dpc unless it indicated down /* Call bus dpc unless it indicated down
(then clean stop) */ (then clean stop) */
if (bus->drvr->busstate != BRCMF_BUS_DOWN) { if (bus->drvr->bus_if->state != BRCMF_BUS_DOWN) {
if (brcmf_sdbrcm_dpc(bus)) if (brcmf_sdbrcm_dpc(bus))
complete(&bus->dpc_wait); complete(&bus->dpc_wait);
} else { } else {
/* after stopping the bus, exit thread */ /* after stopping the bus, exit thread */
brcmf_sdbrcm_bus_stop(bus); brcmf_sdbrcm_bus_stop(bus->sdiodev->dev);
bus->dpc_tsk = NULL; bus->dpc_tsk = NULL;
break; break;
} }
@ -2587,10 +2565,13 @@ static int brcmf_sdbrcm_dpc_thread(void *data)
return 0; return 0;
} }
int brcmf_sdbrcm_bus_txdata(struct brcmf_bus *bus, struct sk_buff *pkt) int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt)
{ {
int ret = -EBADE; int ret = -EBADE;
uint datalen, prec; uint datalen, prec;
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv;
struct brcmf_sdio *bus = sdiodev->bus;
brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(TRACE, "Enter\n");
@ -2638,7 +2619,7 @@ int brcmf_sdbrcm_bus_txdata(struct brcmf_bus *bus, struct sk_buff *pkt)
} }
static int static int
brcmf_sdbrcm_membytes(struct brcmf_bus *bus, bool write, u32 address, u8 *data, brcmf_sdbrcm_membytes(struct brcmf_sdio *bus, bool write, u32 address, u8 *data,
uint size) uint size)
{ {
int bcmerror = 0; int bcmerror = 0;
@ -2699,7 +2680,7 @@ brcmf_sdbrcm_membytes(struct brcmf_bus *bus, bool write, u32 address, u8 *data,
#ifdef BCMDBG #ifdef BCMDBG
#define CONSOLE_LINE_MAX 192 #define CONSOLE_LINE_MAX 192
static int brcmf_sdbrcm_readconsole(struct brcmf_bus *bus) static int brcmf_sdbrcm_readconsole(struct brcmf_sdio *bus)
{ {
struct brcmf_console *c = &bus->console; struct brcmf_console *c = &bus->console;
u8 line[CONSOLE_LINE_MAX], ch; u8 line[CONSOLE_LINE_MAX], ch;
@ -2776,14 +2757,14 @@ static int brcmf_sdbrcm_readconsole(struct brcmf_bus *bus)
} }
#endif /* BCMDBG */ #endif /* BCMDBG */
static int brcmf_tx_frame(struct brcmf_bus *bus, u8 *frame, u16 len) static int brcmf_tx_frame(struct brcmf_sdio *bus, u8 *frame, u16 len)
{ {
int i; int i;
int ret; int ret;
bus->ctrl_frame_stat = false; bus->ctrl_frame_stat = false;
ret = brcmf_sdbrcm_send_buf(bus, bus->sdiodev->sbwad, ret = brcmf_sdcard_send_buf(bus->sdiodev, bus->sdiodev->sbwad,
SDIO_FUNC_2, F2SYNC, frame, len, NULL); SDIO_FUNC_2, F2SYNC, frame, len);
if (ret < 0) { if (ret < 0) {
/* On failure, abort the command and terminate the frame */ /* On failure, abort the command and terminate the frame */
@ -2819,7 +2800,7 @@ static int brcmf_tx_frame(struct brcmf_bus *bus, u8 *frame, u16 len)
} }
int int
brcmf_sdbrcm_bus_txctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen) brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
{ {
u8 *frame; u8 *frame;
u16 len; u16 len;
@ -2827,6 +2808,9 @@ brcmf_sdbrcm_bus_txctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen)
uint retries = 0; uint retries = 0;
u8 doff = 0; u8 doff = 0;
int ret = -1; int ret = -1;
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv;
struct brcmf_sdio *bus = sdiodev->bus;
brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(TRACE, "Enter\n");
@ -2934,11 +2918,14 @@ brcmf_sdbrcm_bus_txctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen)
} }
int int
brcmf_sdbrcm_bus_rxctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen) brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)
{ {
int timeleft; int timeleft;
uint rxlen = 0; uint rxlen = 0;
bool pending; bool pending;
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv;
struct brcmf_sdio *bus = sdiodev->bus;
brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(TRACE, "Enter\n");
@ -2971,7 +2958,7 @@ brcmf_sdbrcm_bus_rxctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen)
return rxlen ? (int)rxlen : -ETIMEDOUT; return rxlen ? (int)rxlen : -ETIMEDOUT;
} }
static int brcmf_sdbrcm_downloadvars(struct brcmf_bus *bus, void *arg, int len) static int brcmf_sdbrcm_downloadvars(struct brcmf_sdio *bus, void *arg, int len)
{ {
int bcmerror = 0; int bcmerror = 0;
@ -3004,7 +2991,7 @@ static int brcmf_sdbrcm_downloadvars(struct brcmf_bus *bus, void *arg, int len)
return bcmerror; return bcmerror;
} }
static int brcmf_sdbrcm_write_vars(struct brcmf_bus *bus) static int brcmf_sdbrcm_write_vars(struct brcmf_sdio *bus)
{ {
int bcmerror = 0; int bcmerror = 0;
u32 varsize; u32 varsize;
@ -3091,7 +3078,7 @@ static int brcmf_sdbrcm_write_vars(struct brcmf_bus *bus)
return bcmerror; return bcmerror;
} }
static int brcmf_sdbrcm_download_state(struct brcmf_bus *bus, bool enter) static int brcmf_sdbrcm_download_state(struct brcmf_sdio *bus, bool enter)
{ {
uint retries; uint retries;
int bcmerror = 0; int bcmerror = 0;
@ -3134,13 +3121,13 @@ static int brcmf_sdbrcm_download_state(struct brcmf_bus *bus, bool enter)
/* Allow HT Clock now that the ARM is running. */ /* Allow HT Clock now that the ARM is running. */
bus->alp_only = false; bus->alp_only = false;
bus->drvr->busstate = BRCMF_BUS_LOAD; bus->drvr->bus_if->state = BRCMF_BUS_LOAD;
} }
fail: fail:
return bcmerror; return bcmerror;
} }
static int brcmf_sdbrcm_get_image(char *buf, int len, struct brcmf_bus *bus) static int brcmf_sdbrcm_get_image(char *buf, int len, struct brcmf_sdio *bus)
{ {
if (bus->firmware->size < bus->fw_ptr + len) if (bus->firmware->size < bus->fw_ptr + len)
len = bus->firmware->size - bus->fw_ptr; len = bus->firmware->size - bus->fw_ptr;
@ -3150,10 +3137,7 @@ static int brcmf_sdbrcm_get_image(char *buf, int len, struct brcmf_bus *bus)
return len; return len;
} }
MODULE_FIRMWARE(BCM4329_FW_NAME); static int brcmf_sdbrcm_download_code_file(struct brcmf_sdio *bus)
MODULE_FIRMWARE(BCM4329_NV_NAME);
static int brcmf_sdbrcm_download_code_file(struct brcmf_bus *bus)
{ {
int offset = 0; int offset = 0;
uint len; uint len;
@ -3162,8 +3146,7 @@ static int brcmf_sdbrcm_download_code_file(struct brcmf_bus *bus)
brcmf_dbg(INFO, "Enter\n"); brcmf_dbg(INFO, "Enter\n");
bus->fw_name = BCM4329_FW_NAME; ret = request_firmware(&bus->firmware, BRCMFMAC_FW_NAME,
ret = request_firmware(&bus->firmware, bus->fw_name,
&bus->sdiodev->func[2]->dev); &bus->sdiodev->func[2]->dev);
if (ret) { if (ret) {
brcmf_dbg(ERROR, "Fail to request firmware %d\n", ret); brcmf_dbg(ERROR, "Fail to request firmware %d\n", ret);
@ -3253,15 +3236,14 @@ static uint brcmf_process_nvram_vars(char *varbuf, uint len)
return buf_len; return buf_len;
} }
static int brcmf_sdbrcm_download_nvram(struct brcmf_bus *bus) static int brcmf_sdbrcm_download_nvram(struct brcmf_sdio *bus)
{ {
uint len; uint len;
char *memblock = NULL; char *memblock = NULL;
char *bufp; char *bufp;
int ret; int ret;
bus->nv_name = BCM4329_NV_NAME; ret = request_firmware(&bus->firmware, BRCMFMAC_NV_NAME,
ret = request_firmware(&bus->firmware, bus->nv_name,
&bus->sdiodev->func[2]->dev); &bus->sdiodev->func[2]->dev);
if (ret) { if (ret) {
brcmf_dbg(ERROR, "Fail to request nvram %d\n", ret); brcmf_dbg(ERROR, "Fail to request nvram %d\n", ret);
@ -3301,7 +3283,7 @@ static int brcmf_sdbrcm_download_nvram(struct brcmf_bus *bus)
return ret; return ret;
} }
static int _brcmf_sdbrcm_download_firmware(struct brcmf_bus *bus) static int _brcmf_sdbrcm_download_firmware(struct brcmf_sdio *bus)
{ {
int bcmerror = -1; int bcmerror = -1;
@ -3334,7 +3316,7 @@ static int _brcmf_sdbrcm_download_firmware(struct brcmf_bus *bus)
} }
static bool static bool
brcmf_sdbrcm_download_firmware(struct brcmf_bus *bus) brcmf_sdbrcm_download_firmware(struct brcmf_sdio *bus)
{ {
bool ret; bool ret;
@ -3348,12 +3330,15 @@ brcmf_sdbrcm_download_firmware(struct brcmf_bus *bus)
return ret; return ret;
} }
void brcmf_sdbrcm_bus_stop(struct brcmf_bus *bus) void brcmf_sdbrcm_bus_stop(struct device *dev)
{ {
u32 local_hostintmask; u32 local_hostintmask;
u8 saveclk; u8 saveclk;
uint retries; uint retries;
int err; int err;
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv;
struct brcmf_sdio *bus = sdiodev->bus;
brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(TRACE, "Enter\n");
@ -3382,7 +3367,7 @@ void brcmf_sdbrcm_bus_stop(struct brcmf_bus *bus)
bus->hostintmask = 0; bus->hostintmask = 0;
/* Change our idea of bus state */ /* Change our idea of bus state */
bus->drvr->busstate = BRCMF_BUS_DOWN; bus->drvr->bus_if->state = BRCMF_BUS_DOWN;
/* Force clocks on backplane to be sure F2 interrupt propagates */ /* Force clocks on backplane to be sure F2 interrupt propagates */
saveclk = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, saveclk = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
@ -3426,9 +3411,11 @@ void brcmf_sdbrcm_bus_stop(struct brcmf_bus *bus)
up(&bus->sdsem); up(&bus->sdsem);
} }
int brcmf_sdbrcm_bus_init(struct brcmf_pub *drvr) int brcmf_sdbrcm_bus_init(struct device *dev)
{ {
struct brcmf_bus *bus = drvr->bus; struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv;
struct brcmf_sdio *bus = sdiodev->bus;
unsigned long timeout; unsigned long timeout;
uint retries = 0; uint retries = 0;
u8 ready, enable; u8 ready, enable;
@ -3438,7 +3425,7 @@ int brcmf_sdbrcm_bus_init(struct brcmf_pub *drvr)
brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(TRACE, "Enter\n");
/* try to download image and nvram to the dongle */ /* try to download image and nvram to the dongle */
if (drvr->busstate == BRCMF_BUS_DOWN) { if (bus_if->state == BRCMF_BUS_DOWN) {
if (!(brcmf_sdbrcm_download_firmware(bus))) if (!(brcmf_sdbrcm_download_firmware(bus)))
return -1; return -1;
} }
@ -3504,7 +3491,7 @@ int brcmf_sdbrcm_bus_init(struct brcmf_pub *drvr)
SBSDIO_WATERMARK, 8, &err); SBSDIO_WATERMARK, 8, &err);
/* Set bus state according to enable result */ /* Set bus state according to enable result */
drvr->busstate = BRCMF_BUS_DATA; bus_if->state = BRCMF_BUS_DATA;
} }
else { else {
@ -3519,7 +3506,7 @@ int brcmf_sdbrcm_bus_init(struct brcmf_pub *drvr)
SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err); SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err);
/* If we didn't come up, turn off backplane clock */ /* If we didn't come up, turn off backplane clock */
if (drvr->busstate != BRCMF_BUS_DATA) if (bus_if->state != BRCMF_BUS_DATA)
brcmf_sdbrcm_clkctl(bus, CLK_NONE, false); brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
exit: exit:
@ -3530,7 +3517,7 @@ int brcmf_sdbrcm_bus_init(struct brcmf_pub *drvr)
void brcmf_sdbrcm_isr(void *arg) void brcmf_sdbrcm_isr(void *arg)
{ {
struct brcmf_bus *bus = (struct brcmf_bus *) arg; struct brcmf_sdio *bus = (struct brcmf_sdio *) arg;
brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(TRACE, "Enter\n");
@ -3539,7 +3526,7 @@ void brcmf_sdbrcm_isr(void *arg)
return; return;
} }
if (bus->drvr->busstate == BRCMF_BUS_DOWN) { if (bus->drvr->bus_if->state == BRCMF_BUS_DOWN) {
brcmf_dbg(ERROR, "bus is down. we have nothing to do\n"); brcmf_dbg(ERROR, "bus is down. we have nothing to do\n");
return; return;
} }
@ -3562,14 +3549,14 @@ void brcmf_sdbrcm_isr(void *arg)
complete(&bus->dpc_wait); complete(&bus->dpc_wait);
} }
static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_pub *drvr) static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
{ {
struct brcmf_bus *bus; #ifdef BCMDBG
struct brcmf_bus *bus_if = dev_get_drvdata(bus->sdiodev->dev);
#endif /* BCMDBG */
brcmf_dbg(TIMER, "Enter\n"); brcmf_dbg(TIMER, "Enter\n");
bus = drvr->bus;
/* Ignore the timer if simulating bus down */ /* Ignore the timer if simulating bus down */
if (bus->sleeping) if (bus->sleeping)
return false; return false;
@ -3613,7 +3600,8 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_pub *drvr)
} }
#ifdef BCMDBG #ifdef BCMDBG
/* Poll for console output periodically */ /* Poll for console output periodically */
if (drvr->busstate == BRCMF_BUS_DATA && bus->console_interval != 0) { if (bus_if->state == BRCMF_BUS_DATA &&
bus->console_interval != 0) {
bus->console.count += BRCMF_WD_POLL_MS; bus->console.count += BRCMF_WD_POLL_MS;
if (bus->console.count >= bus->console_interval) { if (bus->console.count >= bus->console_interval) {
bus->console.count -= bus->console_interval; bus->console.count -= bus->console_interval;
@ -3651,7 +3639,7 @@ static bool brcmf_sdbrcm_chipmatch(u16 chipid)
return false; return false;
} }
static void brcmf_sdbrcm_release_malloc(struct brcmf_bus *bus) static void brcmf_sdbrcm_release_malloc(struct brcmf_sdio *bus)
{ {
brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(TRACE, "Enter\n");
@ -3663,7 +3651,7 @@ static void brcmf_sdbrcm_release_malloc(struct brcmf_bus *bus)
bus->databuf = NULL; bus->databuf = NULL;
} }
static bool brcmf_sdbrcm_probe_malloc(struct brcmf_bus *bus) static bool brcmf_sdbrcm_probe_malloc(struct brcmf_sdio *bus)
{ {
brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(TRACE, "Enter\n");
@ -3699,7 +3687,7 @@ static bool brcmf_sdbrcm_probe_malloc(struct brcmf_bus *bus)
} }
static bool static bool
brcmf_sdbrcm_probe_attach(struct brcmf_bus *bus, u32 regsva) brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva)
{ {
u8 clkctl = 0; u8 clkctl = 0;
int err = 0; int err = 0;
@ -3784,7 +3772,7 @@ brcmf_sdbrcm_probe_attach(struct brcmf_bus *bus, u32 regsva)
return false; return false;
} }
static bool brcmf_sdbrcm_probe_init(struct brcmf_bus *bus) static bool brcmf_sdbrcm_probe_init(struct brcmf_sdio *bus)
{ {
brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(TRACE, "Enter\n");
@ -3792,7 +3780,7 @@ static bool brcmf_sdbrcm_probe_init(struct brcmf_bus *bus)
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx, brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx,
SDIO_FUNC_ENABLE_1, NULL); SDIO_FUNC_ENABLE_1, NULL);
bus->drvr->busstate = BRCMF_BUS_DOWN; bus->drvr->bus_if->state = BRCMF_BUS_DOWN;
bus->sleeping = false; bus->sleeping = false;
bus->rxflow = false; bus->rxflow = false;
@ -3819,7 +3807,7 @@ static bool brcmf_sdbrcm_probe_init(struct brcmf_bus *bus)
static int static int
brcmf_sdbrcm_watchdog_thread(void *data) brcmf_sdbrcm_watchdog_thread(void *data)
{ {
struct brcmf_bus *bus = (struct brcmf_bus *)data; struct brcmf_sdio *bus = (struct brcmf_sdio *)data;
allow_signal(SIGTERM); allow_signal(SIGTERM);
/* Run until signal received */ /* Run until signal received */
@ -3827,7 +3815,7 @@ brcmf_sdbrcm_watchdog_thread(void *data)
if (kthread_should_stop()) if (kthread_should_stop())
break; break;
if (!wait_for_completion_interruptible(&bus->watchdog_wait)) { if (!wait_for_completion_interruptible(&bus->watchdog_wait)) {
brcmf_sdbrcm_bus_watchdog(bus->drvr); brcmf_sdbrcm_bus_watchdog(bus);
/* Count the tick for reference */ /* Count the tick for reference */
bus->drvr->tickcnt++; bus->drvr->tickcnt++;
} else } else
@ -3839,7 +3827,7 @@ brcmf_sdbrcm_watchdog_thread(void *data)
static void static void
brcmf_sdbrcm_watchdog(unsigned long data) brcmf_sdbrcm_watchdog(unsigned long data)
{ {
struct brcmf_bus *bus = (struct brcmf_bus *)data; struct brcmf_sdio *bus = (struct brcmf_sdio *)data;
if (bus->watchdog_tsk) { if (bus->watchdog_tsk) {
complete(&bus->watchdog_wait); complete(&bus->watchdog_wait);
@ -3850,7 +3838,7 @@ brcmf_sdbrcm_watchdog(unsigned long data)
} }
} }
static void brcmf_sdbrcm_release_dongle(struct brcmf_bus *bus) static void brcmf_sdbrcm_release_dongle(struct brcmf_sdio *bus)
{ {
brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(TRACE, "Enter\n");
@ -3867,7 +3855,7 @@ static void brcmf_sdbrcm_release_dongle(struct brcmf_bus *bus)
} }
/* Detach and free everything */ /* Detach and free everything */
static void brcmf_sdbrcm_release(struct brcmf_bus *bus) static void brcmf_sdbrcm_release(struct brcmf_sdio *bus)
{ {
brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(TRACE, "Enter\n");
@ -3889,21 +3877,10 @@ static void brcmf_sdbrcm_release(struct brcmf_bus *bus)
brcmf_dbg(TRACE, "Disconnected\n"); brcmf_dbg(TRACE, "Disconnected\n");
} }
void *brcmf_sdbrcm_probe(u16 bus_no, u16 slot, u16 func, uint bustype, void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
u32 regsva, struct brcmf_sdio_dev *sdiodev)
{ {
int ret; int ret;
struct brcmf_bus *bus; struct brcmf_sdio *bus;
/* Init global variables at run-time, not as part of the declaration.
* This is required to support init/de-init of the driver.
* Initialization
* of globals as part of the declaration results in non-deterministic
* behavior since the value of the globals may be different on the
* first time that the driver is initialized vs subsequent
* initializations.
*/
brcmf_c_init();
brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(TRACE, "Enter\n");
@ -3911,7 +3888,7 @@ void *brcmf_sdbrcm_probe(u16 bus_no, u16 slot, u16 func, uint bustype,
* regsva == SI_ENUM_BASE*/ * regsva == SI_ENUM_BASE*/
/* Allocate private bus interface state */ /* Allocate private bus interface state */
bus = kzalloc(sizeof(struct brcmf_bus), GFP_ATOMIC); bus = kzalloc(sizeof(struct brcmf_sdio), GFP_ATOMIC);
if (!bus) if (!bus)
goto fail; goto fail;
@ -3963,7 +3940,7 @@ void *brcmf_sdbrcm_probe(u16 bus_no, u16 slot, u16 func, uint bustype,
} }
/* Attach to the brcmf/OS/network interface */ /* Attach to the brcmf/OS/network interface */
bus->drvr = brcmf_attach(bus, SDPCM_RESERVE); bus->drvr = brcmf_attach(bus, SDPCM_RESERVE, bus->sdiodev->dev);
if (!bus->drvr) { if (!bus->drvr) {
brcmf_dbg(ERROR, "brcmf_attach failed\n"); brcmf_dbg(ERROR, "brcmf_attach failed\n");
goto fail; goto fail;
@ -4015,7 +3992,7 @@ void *brcmf_sdbrcm_probe(u16 bus_no, u16 slot, u16 func, uint bustype,
void brcmf_sdbrcm_disconnect(void *ptr) void brcmf_sdbrcm_disconnect(void *ptr)
{ {
struct brcmf_bus *bus = (struct brcmf_bus *)ptr; struct brcmf_sdio *bus = (struct brcmf_sdio *)ptr;
brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(TRACE, "Enter\n");
@ -4025,13 +4002,8 @@ void brcmf_sdbrcm_disconnect(void *ptr)
brcmf_dbg(TRACE, "Disconnected\n"); brcmf_dbg(TRACE, "Disconnected\n");
} }
struct device *brcmf_bus_get_device(struct brcmf_bus *bus)
{
return &bus->sdiodev->func[2]->dev;
}
void void
brcmf_sdbrcm_wd_timer(struct brcmf_bus *bus, uint wdtick) brcmf_sdbrcm_wd_timer(struct brcmf_sdio *bus, uint wdtick)
{ {
/* Totally stop the timer */ /* Totally stop the timer */
if (!wdtick && bus->wd_timer_valid == true) { if (!wdtick && bus->wd_timer_valid == true) {
@ -4042,7 +4014,7 @@ brcmf_sdbrcm_wd_timer(struct brcmf_bus *bus, uint wdtick)
} }
/* don't start the wd until fw is loaded */ /* don't start the wd until fw is loaded */
if (bus->drvr->busstate == BRCMF_BUS_DOWN) if (bus->drvr->bus_if->state == BRCMF_BUS_DOWN)
return; return;
if (wdtick) { if (wdtick) {

View File

@ -132,9 +132,9 @@ struct brcmf_sdio_dev {
atomic_t suspend; /* suspend flag */ atomic_t suspend; /* suspend flag */
wait_queue_head_t request_byte_wait; wait_queue_head_t request_byte_wait;
wait_queue_head_t request_word_wait; wait_queue_head_t request_word_wait;
wait_queue_head_t request_packet_wait; wait_queue_head_t request_chain_wait;
wait_queue_head_t request_buffer_wait; wait_queue_head_t request_buffer_wait;
struct device *dev;
}; };
/* Register/deregister device interrupt handler. */ /* Register/deregister device interrupt handler. */
@ -182,11 +182,21 @@ extern bool brcmf_sdcard_regfail(struct brcmf_sdio_dev *sdiodev);
* NOTE: Async operation is not currently supported. * NOTE: Async operation is not currently supported.
*/ */
extern int extern int
brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
uint flags, struct sk_buff *pkt);
extern int
brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
uint flags, u8 *buf, uint nbytes, struct sk_buff *pkt); uint flags, u8 *buf, uint nbytes);
extern int
brcmf_sdcard_recv_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
uint flags, struct sk_buff *pkt);
extern int extern int
brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
uint flags, u8 *buf, uint nbytes, struct sk_buff *pkt); uint flags, u8 *buf, uint nbytes);
extern int
brcmf_sdcard_recv_chain(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
uint flags, struct sk_buff_head *pktq);
/* Flags bits */ /* Flags bits */
@ -237,16 +247,18 @@ brcmf_sdioh_request_word(struct brcmf_sdio_dev *sdiodev,
/* read or write any buffer using cmd53 */ /* read or write any buffer using cmd53 */
extern int extern int
brcmf_sdioh_request_buffer(struct brcmf_sdio_dev *sdiodev, brcmf_sdioh_request_buffer(struct brcmf_sdio_dev *sdiodev,
uint fix_inc, uint rw, uint fnc_num, uint fix_inc, uint rw, uint fnc_num, u32 addr,
u32 addr, uint regwidth, struct sk_buff *pkt);
u32 buflen, u8 *buffer, struct sk_buff *pkt); extern int
brcmf_sdioh_request_chain(struct brcmf_sdio_dev *sdiodev, uint fix_inc,
uint write, uint func, uint addr,
struct sk_buff_head *pktq);
/* Watchdog timer interface for pm ops */ /* Watchdog timer interface for pm ops */
extern void brcmf_sdio_wdtmr_enable(struct brcmf_sdio_dev *sdiodev, extern void brcmf_sdio_wdtmr_enable(struct brcmf_sdio_dev *sdiodev,
bool enable); bool enable);
extern void *brcmf_sdbrcm_probe(u16 bus_no, u16 slot, u16 func, uint bustype, extern void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev);
u32 regsva, struct brcmf_sdio_dev *sdiodev);
extern void brcmf_sdbrcm_disconnect(void *ptr); extern void brcmf_sdbrcm_disconnect(void *ptr);
extern void brcmf_sdbrcm_isr(void *arg); extern void brcmf_sdbrcm_isr(void *arg);
#endif /* _BRCM_SDH_H_ */ #endif /* _BRCM_SDH_H_ */

View File

@ -1429,7 +1429,7 @@ brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
static s32 static s32
brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, brcmf_cfg80211_set_tx_power(struct wiphy *wiphy,
enum nl80211_tx_power_setting type, s32 dbm) enum nl80211_tx_power_setting type, s32 mbm)
{ {
struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
@ -1437,6 +1437,7 @@ brcmf_cfg80211_set_tx_power(struct wiphy *wiphy,
u16 txpwrmw; u16 txpwrmw;
s32 err = 0; s32 err = 0;
s32 disable = 0; s32 disable = 0;
s32 dbm = MBM_TO_DBM(mbm);
WL_TRACE("Enter\n"); WL_TRACE("Enter\n");
if (!check_sys_up(wiphy)) if (!check_sys_up(wiphy))
@ -1446,12 +1447,6 @@ brcmf_cfg80211_set_tx_power(struct wiphy *wiphy,
case NL80211_TX_POWER_AUTOMATIC: case NL80211_TX_POWER_AUTOMATIC:
break; break;
case NL80211_TX_POWER_LIMITED: case NL80211_TX_POWER_LIMITED:
if (dbm < 0) {
WL_ERR("TX_POWER_LIMITED - dbm is negative\n");
err = -EINVAL;
goto done;
}
break;
case NL80211_TX_POWER_FIXED: case NL80211_TX_POWER_FIXED:
if (dbm < 0) { if (dbm < 0) {
WL_ERR("TX_POWER_FIXED - dbm is negative\n"); WL_ERR("TX_POWER_FIXED - dbm is negative\n");

View File

@ -1239,10 +1239,9 @@ bool dma_rxreset(struct dma_pub *pub)
* the error(toss frames) could be fatal and cause many subsequent hard * the error(toss frames) could be fatal and cause many subsequent hard
* to debug problems * to debug problems
*/ */
int dma_txfast(struct dma_pub *pub, struct sk_buff *p0, bool commit) int dma_txfast(struct dma_pub *pub, struct sk_buff *p, bool commit)
{ {
struct dma_info *di = (struct dma_info *)pub; struct dma_info *di = (struct dma_info *)pub;
struct sk_buff *p, *next;
unsigned char *data; unsigned char *data;
uint len; uint len;
u16 txout; u16 txout;
@ -1254,50 +1253,37 @@ int dma_txfast(struct dma_pub *pub, struct sk_buff *p0, bool commit)
txout = di->txout; txout = di->txout;
/* /*
* Walk the chain of packet buffers * obtain and initialize transmit descriptor entry.
* allocating and initializing transmit descriptor entries.
*/ */
for (p = p0; p; p = next) { data = p->data;
data = p->data; len = p->len;
len = p->len;
next = p->next;
/* return nonzero if out of tx descriptors */ /* no use to transmit a zero length packet */
if (nexttxd(di, txout) == di->txin) if (len == 0)
goto outoftxd; return 0;
if (len == 0) /* return nonzero if out of tx descriptors */
continue; if (nexttxd(di, txout) == di->txin)
goto outoftxd;
/* get physical address of buffer start */ /* get physical address of buffer start */
pa = pci_map_single(di->pbus, data, len, PCI_DMA_TODEVICE); pa = pci_map_single(di->pbus, data, len, PCI_DMA_TODEVICE);
flags = 0; /* With a DMA segment list, Descriptor table is filled
if (p == p0) * using the segment list instead of looping over
flags |= D64_CTRL1_SOF; * buffers in multi-chain DMA. Therefore, EOF for SGLIST
* is when end of segment list is reached.
*/
flags = D64_CTRL1_SOF | D64_CTRL1_IOC | D64_CTRL1_EOF;
if (txout == (di->ntxd - 1))
flags |= D64_CTRL1_EOT;
/* With a DMA segment list, Descriptor table is filled dma64_dd_upd(di, di->txd64, pa, txout, &flags, len);
* using the segment list instead of looping over
* buffers in multi-chain DMA. Therefore, EOF for SGLIST
* is when end of segment list is reached.
*/
if (next == NULL)
flags |= (D64_CTRL1_IOC | D64_CTRL1_EOF);
if (txout == (di->ntxd - 1))
flags |= D64_CTRL1_EOT;
dma64_dd_upd(di, di->txd64, pa, txout, &flags, len); txout = nexttxd(di, txout);
txout = nexttxd(di, txout);
}
/* if last txd eof not set, fix it */
if (!(flags & D64_CTRL1_EOF))
di->txd64[prevtxd(di, txout)].ctrl1 =
cpu_to_le32(flags | D64_CTRL1_IOC | D64_CTRL1_EOF);
/* save the packet */ /* save the packet */
di->txp[prevtxd(di, txout)] = p0; di->txp[prevtxd(di, txout)] = p;
/* bump the tx descriptor index */ /* bump the tx descriptor index */
di->txout = txout; di->txout = txout;
@ -1314,7 +1300,7 @@ int dma_txfast(struct dma_pub *pub, struct sk_buff *p0, bool commit)
outoftxd: outoftxd:
DMA_ERROR("%s: out of txds !!!\n", di->name); DMA_ERROR("%s: out of txds !!!\n", di->name);
brcmu_pkt_buf_free_skb(p0); brcmu_pkt_buf_free_skb(p);
di->dma.txavail = 0; di->dma.txavail = 0;
di->dma.txnobuf++; di->dma.txnobuf++;
return -1; return -1;

View File

@ -40,10 +40,10 @@
#define MAC_FILTERS (FIF_PROMISC_IN_BSS | \ #define MAC_FILTERS (FIF_PROMISC_IN_BSS | \
FIF_ALLMULTI | \ FIF_ALLMULTI | \
FIF_FCSFAIL | \ FIF_FCSFAIL | \
FIF_PLCPFAIL | \
FIF_CONTROL | \ FIF_CONTROL | \
FIF_OTHER_BSS | \ FIF_OTHER_BSS | \
FIF_BCN_PRBRESP_PROMISC) FIF_BCN_PRBRESP_PROMISC | \
FIF_PSPOLL)
#define CHAN2GHZ(channel, freqency, chflags) { \ #define CHAN2GHZ(channel, freqency, chflags) { \
.band = IEEE80211_BAND_2GHZ, \ .band = IEEE80211_BAND_2GHZ, \
@ -373,7 +373,7 @@ static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed)
conf->listen_interval); conf->listen_interval);
} }
if (changed & IEEE80211_CONF_CHANGE_MONITOR) if (changed & IEEE80211_CONF_CHANGE_MONITOR)
wiphy_err(wiphy, "%s: change monitor mode: %s (implement)\n", wiphy_dbg(wiphy, "%s: change monitor mode: %s\n",
__func__, conf->flags & IEEE80211_CONF_MONITOR ? __func__, conf->flags & IEEE80211_CONF_MONITOR ?
"true" : "false"); "true" : "false");
if (changed & IEEE80211_CONF_CHANGE_PS) if (changed & IEEE80211_CONF_CHANGE_PS)
@ -550,29 +550,25 @@ brcms_ops_configure_filter(struct ieee80211_hw *hw,
changed_flags &= MAC_FILTERS; changed_flags &= MAC_FILTERS;
*total_flags &= MAC_FILTERS; *total_flags &= MAC_FILTERS;
if (changed_flags & FIF_PROMISC_IN_BSS) if (changed_flags & FIF_PROMISC_IN_BSS)
wiphy_err(wiphy, "FIF_PROMISC_IN_BSS\n"); wiphy_dbg(wiphy, "FIF_PROMISC_IN_BSS\n");
if (changed_flags & FIF_ALLMULTI) if (changed_flags & FIF_ALLMULTI)
wiphy_err(wiphy, "FIF_ALLMULTI\n"); wiphy_dbg(wiphy, "FIF_ALLMULTI\n");
if (changed_flags & FIF_FCSFAIL) if (changed_flags & FIF_FCSFAIL)
wiphy_err(wiphy, "FIF_FCSFAIL\n"); wiphy_dbg(wiphy, "FIF_FCSFAIL\n");
if (changed_flags & FIF_PLCPFAIL)
wiphy_err(wiphy, "FIF_PLCPFAIL\n");
if (changed_flags & FIF_CONTROL) if (changed_flags & FIF_CONTROL)
wiphy_err(wiphy, "FIF_CONTROL\n"); wiphy_dbg(wiphy, "FIF_CONTROL\n");
if (changed_flags & FIF_OTHER_BSS) if (changed_flags & FIF_OTHER_BSS)
wiphy_err(wiphy, "FIF_OTHER_BSS\n"); wiphy_dbg(wiphy, "FIF_OTHER_BSS\n");
if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { if (changed_flags & FIF_PSPOLL)
spin_lock_bh(&wl->lock); wiphy_dbg(wiphy, "FIF_PSPOLL\n");
if (*total_flags & FIF_BCN_PRBRESP_PROMISC) { if (changed_flags & FIF_BCN_PRBRESP_PROMISC)
wl->pub->mac80211_state |= MAC80211_PROMISC_BCNS; wiphy_dbg(wiphy, "FIF_BCN_PRBRESP_PROMISC\n");
brcms_c_mac_bcn_promisc_change(wl->wlc, 1);
} else { spin_lock_bh(&wl->lock);
brcms_c_mac_bcn_promisc_change(wl->wlc, 0); brcms_c_mac_promisc(wl->wlc, *total_flags);
wl->pub->mac80211_state &= ~MAC80211_PROMISC_BCNS; spin_unlock_bh(&wl->lock);
}
spin_unlock_bh(&wl->lock);
}
return; return;
} }

View File

@ -955,8 +955,6 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs)
brcms_c_txfifo_complete(wlc, queue, 1); brcms_c_txfifo_complete(wlc, queue, 1);
if (lastframe) { if (lastframe) {
p->next = NULL;
p->prev = NULL;
/* remove PLCP & Broadcom tx descriptor header */ /* remove PLCP & Broadcom tx descriptor header */
skb_pull(p, D11_PHY_HDR_LEN); skb_pull(p, D11_PHY_HDR_LEN);
skb_pull(p, D11_TXH_LEN); skb_pull(p, D11_TXH_LEN);
@ -3064,7 +3062,7 @@ static bool brcms_c_ps_allowed(struct brcms_c_info *wlc)
return false; return false;
/* disallow PS when one of these meets when not scanning */ /* disallow PS when one of these meets when not scanning */
if (wlc->monitor) if (wlc->filter_flags & FIF_PROMISC_IN_BSS)
return false; return false;
if (cfg->associated) { if (cfg->associated) {
@ -3584,29 +3582,31 @@ static void brcms_c_bandinit_ordered(struct brcms_c_info *wlc,
} }
/* /*
* Set or clear maccontrol bits MCTL_PROMISC, MCTL_BCNS_PROMISC and * Set or clear filtering related maccontrol bits based on
* MCTL_KEEPCONTROL * specified filter flags
*/ */
static void brcms_c_mac_promisc(struct brcms_c_info *wlc) void brcms_c_mac_promisc(struct brcms_c_info *wlc, uint filter_flags)
{ {
u32 promisc_bits = 0; u32 promisc_bits = 0;
if (wlc->bcnmisc_monitor) wlc->filter_flags = filter_flags;
if (filter_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS))
promisc_bits |= MCTL_PROMISC;
if (filter_flags & FIF_BCN_PRBRESP_PROMISC)
promisc_bits |= MCTL_BCNS_PROMISC; promisc_bits |= MCTL_BCNS_PROMISC;
if (wlc->monitor) if (filter_flags & FIF_FCSFAIL)
promisc_bits |= promisc_bits |= MCTL_KEEPBADFCS;
MCTL_PROMISC | MCTL_BCNS_PROMISC | MCTL_KEEPCONTROL;
if (filter_flags & (FIF_CONTROL | FIF_PSPOLL))
promisc_bits |= MCTL_KEEPCONTROL;
brcms_b_mctrl(wlc->hw, brcms_b_mctrl(wlc->hw,
MCTL_PROMISC | MCTL_BCNS_PROMISC | MCTL_KEEPCONTROL, MCTL_PROMISC | MCTL_BCNS_PROMISC |
promisc_bits); MCTL_KEEPCONTROL | MCTL_KEEPBADFCS,
} promisc_bits);
void brcms_c_mac_bcn_promisc_change(struct brcms_c_info *wlc, bool promisc)
{
wlc->bcnmisc_monitor = promisc;
brcms_c_mac_promisc(wlc);
} }
/* /*
@ -3636,9 +3636,6 @@ static void brcms_c_ucode_mac_upd(struct brcms_c_info *wlc)
} else { } else {
/* disable an active IBSS if we are not on the home channel */ /* disable an active IBSS if we are not on the home channel */
} }
/* update the various promisc bits */
brcms_c_mac_promisc(wlc);
} }
static void brcms_c_write_rate_shm(struct brcms_c_info *wlc, u8 rate, static void brcms_c_write_rate_shm(struct brcms_c_info *wlc, u8 rate,
@ -8074,14 +8071,8 @@ static void brcms_c_recv(struct brcms_c_info *wlc, struct sk_buff *p)
len = p->len; len = p->len;
if (rxh->RxStatus1 & RXS_FCSERR) { if (rxh->RxStatus1 & RXS_FCSERR) {
if (wlc->pub->mac80211_state & MAC80211_PROMISC_BCNS) { if (!(wlc->filter_flags & FIF_FCSFAIL))
wiphy_err(wlc->wiphy, "FCSERR while scanning******* -"
" tossing\n");
goto toss; goto toss;
} else {
wiphy_err(wlc->wiphy, "RCSERR!!!\n");
goto toss;
}
} }
/* check received pkt has at least frame control field */ /* check received pkt has at least frame control field */

View File

@ -519,8 +519,7 @@ struct brcms_c_info {
struct brcms_timer *radio_timer; struct brcms_timer *radio_timer;
/* promiscuous */ /* promiscuous */
bool monitor; uint filter_flags;
bool bcnmisc_monitor;
/* driver feature */ /* driver feature */
bool _rifs; bool _rifs;
@ -658,8 +657,7 @@ extern void brcms_c_print_txdesc(struct d11txh *txh);
#endif #endif
extern int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config); extern int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config);
extern void brcms_c_mac_bcn_promisc_change(struct brcms_c_info *wlc, extern void brcms_c_mac_promisc(struct brcms_c_info *wlc, uint filter_flags);
bool promisc);
extern void brcms_c_send_q(struct brcms_c_info *wlc); extern void brcms_c_send_q(struct brcms_c_info *wlc);
extern int brcms_c_prep_pdu(struct brcms_c_info *wlc, struct sk_buff *pdu, extern int brcms_c_prep_pdu(struct brcms_c_info *wlc, struct sk_buff *pdu,
uint *fifo); uint *fifo);

View File

@ -109,7 +109,7 @@ static const struct chan_info_basic chan_info_all[] = {
{204, 5020}, {204, 5020},
{208, 5040}, {208, 5040},
{212, 5060}, {212, 5060},
{216, 50800} {216, 5080}
}; };
static const u8 ofdm_rate_lookup[] = { static const u8 ofdm_rate_lookup[] = {

View File

@ -655,6 +655,9 @@ static const struct pcmcia_device_id hostap_cs_ids[] = {
PCMCIA_DEVICE_PROD_ID123( PCMCIA_DEVICE_PROD_ID123(
"Addtron", "AWP-100 Wireless PCMCIA", "Version 01.02", "Addtron", "AWP-100 Wireless PCMCIA", "Version 01.02",
0xe6ec52ce, 0x08649af2, 0x4b74baa0), 0xe6ec52ce, 0x08649af2, 0x4b74baa0),
PCMCIA_DEVICE_PROD_ID123(
"Canon", "Wireless LAN CF Card K30225", "Version 01.00",
0x96ef6fe2, 0x263fcbab, 0xa57adb8c),
PCMCIA_DEVICE_PROD_ID123( PCMCIA_DEVICE_PROD_ID123(
"D", "Link DWL-650 11Mbps WLAN Card", "Version 01.02", "D", "Link DWL-650 11Mbps WLAN Card", "Version 01.02",
0x71b18589, 0xb6f1b0ab, 0x4b74baa0), 0x71b18589, 0xb6f1b0ab, 0x4b74baa0),

View File

@ -147,16 +147,7 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv)
iwl1000_set_ct_threshold(priv); iwl1000_set_ct_threshold(priv);
/* Set initial sensitivity parameters */ /* Set initial sensitivity parameters */
/* Set initial calibration set */
hw_params(priv).sens = &iwl1000_sensitivity; hw_params(priv).sens = &iwl1000_sensitivity;
hw_params(priv).calib_init_cfg =
BIT(IWL_CALIB_XTAL) |
BIT(IWL_CALIB_LO) |
BIT(IWL_CALIB_TX_IQ) |
BIT(IWL_CALIB_TX_IQ_PERD) |
BIT(IWL_CALIB_BASE_BAND);
if (priv->cfg->need_dc_calib)
hw_params(priv).calib_init_cfg |= BIT(IWL_CALIB_DC);
return 0; return 0;
} }
@ -191,6 +182,7 @@ static struct iwl_base_params iwl1000_base_params = {
.chain_noise_scale = 1000, .chain_noise_scale = 1000,
.wd_timeout = IWL_DEF_WD_TIMEOUT, .wd_timeout = IWL_DEF_WD_TIMEOUT,
.max_event_log_size = 128, .max_event_log_size = 128,
.wd_disable = true,
}; };
static struct iwl_ht_params iwl1000_ht_params = { static struct iwl_ht_params iwl1000_ht_params = {
.ht_greenfield_support = true, .ht_greenfield_support = true,

View File

@ -143,17 +143,7 @@ static int iwl2000_hw_set_hw_params(struct iwl_priv *priv)
iwl2000_set_ct_threshold(priv); iwl2000_set_ct_threshold(priv);
/* Set initial sensitivity parameters */ /* Set initial sensitivity parameters */
/* Set initial calibration set */
hw_params(priv).sens = &iwl2000_sensitivity; hw_params(priv).sens = &iwl2000_sensitivity;
hw_params(priv).calib_init_cfg =
BIT(IWL_CALIB_XTAL) |
BIT(IWL_CALIB_LO) |
BIT(IWL_CALIB_TX_IQ) |
BIT(IWL_CALIB_BASE_BAND);
if (priv->cfg->need_dc_calib)
hw_params(priv).calib_rt_cfg |= IWL_CALIB_CFG_DC_IDX;
if (priv->cfg->need_temp_offset_calib)
hw_params(priv).calib_init_cfg |= BIT(IWL_CALIB_TEMP_OFFSET);
return 0; return 0;
} }
@ -258,7 +248,6 @@ static struct iwl_bt_params iwl2030_bt_params = {
.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \
.lib = &iwl2000_lib, \ .lib = &iwl2000_lib, \
.base_params = &iwl2000_base_params, \ .base_params = &iwl2000_base_params, \
.need_dc_calib = true, \
.need_temp_offset_calib = true, \ .need_temp_offset_calib = true, \
.temp_offset_v2 = true, \ .temp_offset_v2 = true, \
.led_mode = IWL_LED_RF_STATE, \ .led_mode = IWL_LED_RF_STATE, \
@ -286,7 +275,6 @@ struct iwl_cfg iwl2000_2bgn_d_cfg = {
.lib = &iwl2030_lib, \ .lib = &iwl2030_lib, \
.base_params = &iwl2030_base_params, \ .base_params = &iwl2030_base_params, \
.bt_params = &iwl2030_bt_params, \ .bt_params = &iwl2030_bt_params, \
.need_dc_calib = true, \
.need_temp_offset_calib = true, \ .need_temp_offset_calib = true, \
.temp_offset_v2 = true, \ .temp_offset_v2 = true, \
.led_mode = IWL_LED_RF_STATE, \ .led_mode = IWL_LED_RF_STATE, \
@ -308,7 +296,6 @@ struct iwl_cfg iwl2030_2bgn_cfg = {
.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \
.lib = &iwl2000_lib, \ .lib = &iwl2000_lib, \
.base_params = &iwl2000_base_params, \ .base_params = &iwl2000_base_params, \
.need_dc_calib = true, \
.need_temp_offset_calib = true, \ .need_temp_offset_calib = true, \
.temp_offset_v2 = true, \ .temp_offset_v2 = true, \
.led_mode = IWL_LED_RF_STATE, \ .led_mode = IWL_LED_RF_STATE, \
@ -338,7 +325,6 @@ struct iwl_cfg iwl105_bgn_d_cfg = {
.lib = &iwl2030_lib, \ .lib = &iwl2030_lib, \
.base_params = &iwl2030_base_params, \ .base_params = &iwl2030_base_params, \
.bt_params = &iwl2030_bt_params, \ .bt_params = &iwl2030_bt_params, \
.need_dc_calib = true, \
.need_temp_offset_calib = true, \ .need_temp_offset_calib = true, \
.temp_offset_v2 = true, \ .temp_offset_v2 = true, \
.led_mode = IWL_LED_RF_STATE, \ .led_mode = IWL_LED_RF_STATE, \

View File

@ -186,14 +186,7 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
iwl5000_set_ct_threshold(priv); iwl5000_set_ct_threshold(priv);
/* Set initial sensitivity parameters */ /* Set initial sensitivity parameters */
/* Set initial calibration set */
hw_params(priv).sens = &iwl5000_sensitivity; hw_params(priv).sens = &iwl5000_sensitivity;
hw_params(priv).calib_init_cfg =
BIT(IWL_CALIB_XTAL) |
BIT(IWL_CALIB_LO) |
BIT(IWL_CALIB_TX_IQ) |
BIT(IWL_CALIB_TX_IQ_PERD) |
BIT(IWL_CALIB_BASE_BAND);
return 0; return 0;
} }
@ -222,14 +215,7 @@ static int iwl5150_hw_set_hw_params(struct iwl_priv *priv)
iwl5150_set_ct_threshold(priv); iwl5150_set_ct_threshold(priv);
/* Set initial sensitivity parameters */ /* Set initial sensitivity parameters */
/* Set initial calibration set */
hw_params(priv).sens = &iwl5150_sensitivity; hw_params(priv).sens = &iwl5150_sensitivity;
hw_params(priv).calib_init_cfg =
BIT(IWL_CALIB_LO) |
BIT(IWL_CALIB_TX_IQ) |
BIT(IWL_CALIB_BASE_BAND);
if (priv->cfg->need_dc_calib)
hw_params(priv).calib_init_cfg |= BIT(IWL_CALIB_DC);
return 0; return 0;
} }
@ -364,6 +350,7 @@ static struct iwl_base_params iwl5000_base_params = {
.wd_timeout = IWL_LONG_WD_TIMEOUT, .wd_timeout = IWL_LONG_WD_TIMEOUT,
.max_event_log_size = 512, .max_event_log_size = 512,
.no_idle_support = true, .no_idle_support = true,
.wd_disable = true,
}; };
static struct iwl_ht_params iwl5000_ht_params = { static struct iwl_ht_params iwl5000_ht_params = {
.ht_greenfield_support = true, .ht_greenfield_support = true,
@ -433,7 +420,7 @@ struct iwl_cfg iwl5350_agn_cfg = {
.eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, \ .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, \
.lib = &iwl5150_lib, \ .lib = &iwl5150_lib, \
.base_params = &iwl5000_base_params, \ .base_params = &iwl5000_base_params, \
.need_dc_calib = true, \ .no_xtal_calib = true, \
.led_mode = IWL_LED_BLINK, \ .led_mode = IWL_LED_BLINK, \
.internal_wimax_coex = true .internal_wimax_coex = true

View File

@ -46,11 +46,12 @@
#include "iwl-cfg.h" #include "iwl-cfg.h"
/* Highest firmware API version supported */ /* Highest firmware API version supported */
#define IWL6000_UCODE_API_MAX 4 #define IWL6000_UCODE_API_MAX 6
#define IWL6050_UCODE_API_MAX 5 #define IWL6050_UCODE_API_MAX 5
#define IWL6000G2_UCODE_API_MAX 6 #define IWL6000G2_UCODE_API_MAX 6
/* Oldest version we won't warn about */ /* Oldest version we won't warn about */
#define IWL6000_UCODE_API_OK 4
#define IWL6000G2_UCODE_API_OK 5 #define IWL6000G2_UCODE_API_OK 5
/* Lowest firmware API version supported */ /* Lowest firmware API version supported */
@ -164,17 +165,7 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv)
iwl6000_set_ct_threshold(priv); iwl6000_set_ct_threshold(priv);
/* Set initial sensitivity parameters */ /* Set initial sensitivity parameters */
/* Set initial calibration set */
hw_params(priv).sens = &iwl6000_sensitivity; hw_params(priv).sens = &iwl6000_sensitivity;
hw_params(priv).calib_init_cfg =
BIT(IWL_CALIB_XTAL) |
BIT(IWL_CALIB_LO) |
BIT(IWL_CALIB_TX_IQ) |
BIT(IWL_CALIB_BASE_BAND);
if (priv->cfg->need_dc_calib)
hw_params(priv).calib_rt_cfg |= IWL_CALIB_CFG_DC_IDX;
if (priv->cfg->need_temp_offset_calib)
hw_params(priv).calib_init_cfg |= BIT(IWL_CALIB_TEMP_OFFSET);
return 0; return 0;
} }
@ -364,7 +355,6 @@ static struct iwl_bt_params iwl6000_bt_params = {
.eeprom_calib_ver = EEPROM_6005_TX_POWER_VERSION, \ .eeprom_calib_ver = EEPROM_6005_TX_POWER_VERSION, \
.lib = &iwl6000_lib, \ .lib = &iwl6000_lib, \
.base_params = &iwl6000_g2_base_params, \ .base_params = &iwl6000_g2_base_params, \
.need_dc_calib = true, \
.need_temp_offset_calib = true, \ .need_temp_offset_calib = true, \
.led_mode = IWL_LED_RF_STATE .led_mode = IWL_LED_RF_STATE
@ -406,7 +396,6 @@ struct iwl_cfg iwl6005_2agn_d_cfg = {
.lib = &iwl6030_lib, \ .lib = &iwl6030_lib, \
.base_params = &iwl6000_g2_base_params, \ .base_params = &iwl6000_g2_base_params, \
.bt_params = &iwl6000_bt_params, \ .bt_params = &iwl6000_bt_params, \
.need_dc_calib = true, \
.need_temp_offset_calib = true, \ .need_temp_offset_calib = true, \
.led_mode = IWL_LED_RF_STATE, \ .led_mode = IWL_LED_RF_STATE, \
.adv_pm = true \ .adv_pm = true \
@ -469,6 +458,7 @@ struct iwl_cfg iwl130_bg_cfg = {
#define IWL_DEVICE_6000i \ #define IWL_DEVICE_6000i \
.fw_name_pre = IWL6000_FW_PRE, \ .fw_name_pre = IWL6000_FW_PRE, \
.ucode_api_max = IWL6000_UCODE_API_MAX, \ .ucode_api_max = IWL6000_UCODE_API_MAX, \
.ucode_api_ok = IWL6000_UCODE_API_OK, \
.ucode_api_min = IWL6000_UCODE_API_MIN, \ .ucode_api_min = IWL6000_UCODE_API_MIN, \
.valid_tx_ant = ANT_BC, /* .cfg overwrite */ \ .valid_tx_ant = ANT_BC, /* .cfg overwrite */ \
.valid_rx_ant = ANT_BC, /* .cfg overwrite */ \ .valid_rx_ant = ANT_BC, /* .cfg overwrite */ \
@ -506,7 +496,6 @@ struct iwl_cfg iwl6000i_2bg_cfg = {
.eeprom_ver = EEPROM_6050_EEPROM_VERSION, \ .eeprom_ver = EEPROM_6050_EEPROM_VERSION, \
.eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION, \ .eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION, \
.base_params = &iwl6050_base_params, \ .base_params = &iwl6050_base_params, \
.need_dc_calib = true, \
.led_mode = IWL_LED_BLINK, \ .led_mode = IWL_LED_BLINK, \
.internal_wimax_coex = true .internal_wimax_coex = true
@ -530,7 +519,6 @@ struct iwl_cfg iwl6050_2abg_cfg = {
.eeprom_ver = EEPROM_6150_EEPROM_VERSION, \ .eeprom_ver = EEPROM_6150_EEPROM_VERSION, \
.eeprom_calib_ver = EEPROM_6150_TX_POWER_VERSION, \ .eeprom_calib_ver = EEPROM_6150_TX_POWER_VERSION, \
.base_params = &iwl6050_base_params, \ .base_params = &iwl6050_base_params, \
.need_dc_calib = true, \
.led_mode = IWL_LED_BLINK, \ .led_mode = IWL_LED_BLINK, \
.internal_wimax_coex = true .internal_wimax_coex = true
@ -549,17 +537,17 @@ struct iwl_cfg iwl6000_3agn_cfg = {
.name = "Intel(R) Centrino(R) Ultimate-N 6300 AGN", .name = "Intel(R) Centrino(R) Ultimate-N 6300 AGN",
.fw_name_pre = IWL6000_FW_PRE, .fw_name_pre = IWL6000_FW_PRE,
.ucode_api_max = IWL6000_UCODE_API_MAX, .ucode_api_max = IWL6000_UCODE_API_MAX,
.ucode_api_ok = IWL6000_UCODE_API_OK,
.ucode_api_min = IWL6000_UCODE_API_MIN, .ucode_api_min = IWL6000_UCODE_API_MIN,
.eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION, .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,
.lib = &iwl6000_lib, .lib = &iwl6000_lib,
.base_params = &iwl6000_base_params, .base_params = &iwl6000_base_params,
.ht_params = &iwl6000_ht_params, .ht_params = &iwl6000_ht_params,
.need_dc_calib = true,
.led_mode = IWL_LED_BLINK, .led_mode = IWL_LED_BLINK,
}; };
MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_OK));
MODULE_FIRMWARE(IWL6050_MODULE_FIRMWARE(IWL6050_UCODE_API_MAX)); MODULE_FIRMWARE(IWL6050_MODULE_FIRMWARE(IWL6050_UCODE_API_MAX));
MODULE_FIRMWARE(IWL6005_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX)); MODULE_FIRMWARE(IWL6005_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX));
MODULE_FIRMWARE(IWL6030_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX)); MODULE_FIRMWARE(IWL6030_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX));

View File

@ -84,54 +84,62 @@ struct statistics_general_data {
int iwl_send_calib_results(struct iwl_priv *priv) int iwl_send_calib_results(struct iwl_priv *priv)
{ {
int ret = 0;
int i = 0;
struct iwl_host_cmd hcmd = { struct iwl_host_cmd hcmd = {
.id = REPLY_PHY_CALIBRATION_CMD, .id = REPLY_PHY_CALIBRATION_CMD,
.flags = CMD_SYNC, .flags = CMD_SYNC,
}; };
struct iwl_calib_result *res;
for (i = 0; i < IWL_CALIB_MAX; i++) { list_for_each_entry(res, &priv->calib_results, list) {
if ((BIT(i) & hw_params(priv).calib_init_cfg) && int ret;
priv->calib_results[i].buf) {
hcmd.len[0] = priv->calib_results[i].buf_len; hcmd.len[0] = res->cmd_len;
hcmd.data[0] = priv->calib_results[i].buf; hcmd.data[0] = &res->hdr;
hcmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY; hcmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
ret = iwl_trans_send_cmd(trans(priv), &hcmd); ret = iwl_trans_send_cmd(trans(priv), &hcmd);
if (ret) { if (ret) {
IWL_ERR(priv, "Error %d iteration %d\n", IWL_ERR(priv, "Error %d on calib cmd %d\n",
ret, i); ret, res->hdr.op_code);
break; return ret;
}
} }
} }
return ret; return 0;
} }
int iwl_calib_set(struct iwl_calib_result *res, const u8 *buf, int len) int iwl_calib_set(struct iwl_priv *priv,
const struct iwl_calib_hdr *cmd, int len)
{ {
if (res->buf_len != len) { struct iwl_calib_result *res, *tmp;
kfree(res->buf);
res->buf = kzalloc(len, GFP_ATOMIC); res = kmalloc(sizeof(*res) + len - sizeof(struct iwl_calib_hdr),
} GFP_ATOMIC);
if (unlikely(res->buf == NULL)) if (!res)
return -ENOMEM; return -ENOMEM;
memcpy(&res->hdr, cmd, len);
res->cmd_len = len;
list_for_each_entry(tmp, &priv->calib_results, list) {
if (tmp->hdr.op_code == res->hdr.op_code) {
list_replace(&tmp->list, &res->list);
kfree(tmp);
return 0;
}
}
/* wasn't in list already */
list_add_tail(&res->list, &priv->calib_results);
res->buf_len = len;
memcpy(res->buf, buf, len);
return 0; return 0;
} }
void iwl_calib_free_results(struct iwl_priv *priv) void iwl_calib_free_results(struct iwl_priv *priv)
{ {
int i; struct iwl_calib_result *res, *tmp;
for (i = 0; i < IWL_CALIB_MAX; i++) { list_for_each_entry_safe(res, tmp, &priv->calib_results, list) {
kfree(priv->calib_results[i].buf); list_del(&res->list);
priv->calib_results[i].buf = NULL; kfree(res);
priv->calib_results[i].buf_len = 0;
} }
} }

View File

@ -73,7 +73,8 @@ void iwl_init_sensitivity(struct iwl_priv *priv);
void iwl_reset_run_time_calib(struct iwl_priv *priv); void iwl_reset_run_time_calib(struct iwl_priv *priv);
int iwl_send_calib_results(struct iwl_priv *priv); int iwl_send_calib_results(struct iwl_priv *priv);
int iwl_calib_set(struct iwl_calib_result *res, const u8 *buf, int len); int iwl_calib_set(struct iwl_priv *priv,
const struct iwl_calib_hdr *cmd, int len);
void iwl_calib_free_results(struct iwl_priv *priv); void iwl_calib_free_results(struct iwl_priv *priv);
#endif /* __iwl_calib_h__ */ #endif /* __iwl_calib_h__ */

View File

@ -117,6 +117,7 @@ const char *get_cmd_string(u8 cmd)
IWL_CMD(REPLY_WOWLAN_TKIP_PARAMS); IWL_CMD(REPLY_WOWLAN_TKIP_PARAMS);
IWL_CMD(REPLY_WOWLAN_KEK_KCK_MATERIAL); IWL_CMD(REPLY_WOWLAN_KEK_KCK_MATERIAL);
IWL_CMD(REPLY_WOWLAN_GET_STATUS); IWL_CMD(REPLY_WOWLAN_GET_STATUS);
IWL_CMD(REPLY_D3_CONFIG);
default: default:
return "UNKNOWN"; return "UNKNOWN";

View File

@ -529,6 +529,24 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
return 0; return 0;
} }
void iwlagn_config_ht40(struct ieee80211_conf *conf,
struct iwl_rxon_context *ctx)
{
if (conf_is_ht40_minus(conf)) {
ctx->ht.extension_chan_offset =
IEEE80211_HT_PARAM_CHA_SEC_BELOW;
ctx->ht.is_40mhz = true;
} else if (conf_is_ht40_plus(conf)) {
ctx->ht.extension_chan_offset =
IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
ctx->ht.is_40mhz = true;
} else {
ctx->ht.extension_chan_offset =
IEEE80211_HT_PARAM_CHA_SEC_NONE;
ctx->ht.is_40mhz = false;
}
}
int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed)
{ {
struct iwl_priv *priv = hw->priv; struct iwl_priv *priv = hw->priv;
@ -590,19 +608,11 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed)
ctx->ht.enabled = conf_is_ht(conf); ctx->ht.enabled = conf_is_ht(conf);
if (ctx->ht.enabled) { if (ctx->ht.enabled) {
if (conf_is_ht40_minus(conf)) { /* if HT40 is used, it should not change
ctx->ht.extension_chan_offset = * after associated except channel switch */
IEEE80211_HT_PARAM_CHA_SEC_BELOW; if (iwl_is_associated_ctx(ctx) &&
ctx->ht.is_40mhz = true; !ctx->ht.is_40mhz)
} else if (conf_is_ht40_plus(conf)) { iwlagn_config_ht40(conf, ctx);
ctx->ht.extension_chan_offset =
IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
ctx->ht.is_40mhz = true;
} else {
ctx->ht.extension_chan_offset =
IEEE80211_HT_PARAM_CHA_SEC_NONE;
ctx->ht.is_40mhz = false;
}
} else } else
ctx->ht.is_40mhz = false; ctx->ht.is_40mhz = false;

View File

@ -1250,9 +1250,6 @@ int iwl_set_dynamic_key(struct iwl_priv *priv,
switch (keyconf->cipher) { switch (keyconf->cipher) {
case WLAN_CIPHER_SUITE_TKIP: case WLAN_CIPHER_SUITE_TKIP:
keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
if (sta) if (sta)
addr = sta->addr; addr = sta->addr;
else /* station mode case only */ else /* station mode case only */
@ -1265,8 +1262,6 @@ int iwl_set_dynamic_key(struct iwl_priv *priv,
seq.tkip.iv32, p1k, CMD_SYNC); seq.tkip.iv32, p1k, CMD_SYNC);
break; break;
case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_CCMP:
keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
/* fall through */
case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104: case WLAN_CIPHER_SUITE_WEP104:
ret = iwlagn_send_sta_key(priv, keyconf, sta_id, ret = iwlagn_send_sta_key(priv, keyconf, sta_id,

View File

@ -222,8 +222,7 @@ static int iwlagn_set_Xtal_calib(struct iwl_priv *priv)
iwl_set_calib_hdr(&cmd.hdr, IWL_PHY_CALIBRATE_CRYSTAL_FRQ_CMD); iwl_set_calib_hdr(&cmd.hdr, IWL_PHY_CALIBRATE_CRYSTAL_FRQ_CMD);
cmd.cap_pin1 = le16_to_cpu(xtal_calib[0]); cmd.cap_pin1 = le16_to_cpu(xtal_calib[0]);
cmd.cap_pin2 = le16_to_cpu(xtal_calib[1]); cmd.cap_pin2 = le16_to_cpu(xtal_calib[1]);
return iwl_calib_set(&priv->calib_results[IWL_CALIB_XTAL], return iwl_calib_set(priv, (void *)&cmd, sizeof(cmd));
(u8 *)&cmd, sizeof(cmd));
} }
static int iwlagn_set_temperature_offset_calib(struct iwl_priv *priv) static int iwlagn_set_temperature_offset_calib(struct iwl_priv *priv)
@ -240,8 +239,7 @@ static int iwlagn_set_temperature_offset_calib(struct iwl_priv *priv)
IWL_DEBUG_CALIB(priv, "Radio sensor offset: %d\n", IWL_DEBUG_CALIB(priv, "Radio sensor offset: %d\n",
le16_to_cpu(cmd.radio_sensor_offset)); le16_to_cpu(cmd.radio_sensor_offset));
return iwl_calib_set(&priv->calib_results[IWL_CALIB_TEMP_OFFSET], return iwl_calib_set(priv, (void *)&cmd, sizeof(cmd));
(u8 *)&cmd, sizeof(cmd));
} }
static int iwlagn_set_temperature_offset_calib_v2(struct iwl_priv *priv) static int iwlagn_set_temperature_offset_calib_v2(struct iwl_priv *priv)
@ -276,8 +274,7 @@ static int iwlagn_set_temperature_offset_calib_v2(struct iwl_priv *priv)
IWL_DEBUG_CALIB(priv, "Voltage Ref: %d\n", IWL_DEBUG_CALIB(priv, "Voltage Ref: %d\n",
le16_to_cpu(cmd.burntVoltageRef)); le16_to_cpu(cmd.burntVoltageRef));
return iwl_calib_set(&priv->calib_results[IWL_CALIB_TEMP_OFFSET], return iwl_calib_set(priv, (void *)&cmd, sizeof(cmd));
(u8 *)&cmd, sizeof(cmd));
} }
static int iwlagn_send_calib_cfg(struct iwl_priv *priv) static int iwlagn_send_calib_cfg(struct iwl_priv *priv)
@ -306,37 +303,14 @@ int iwlagn_rx_calib_result(struct iwl_priv *priv,
struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_calib_hdr *hdr = (struct iwl_calib_hdr *)pkt->u.raw; struct iwl_calib_hdr *hdr = (struct iwl_calib_hdr *)pkt->u.raw;
int len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; int len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
int index;
/* reduce the size of the length field itself */ /* reduce the size of the length field itself */
len -= 4; len -= 4;
/* Define the order in which the results will be sent to the runtime if (iwl_calib_set(priv, hdr, len))
* uCode. iwl_send_calib_results sends them in a row according to IWL_ERR(priv, "Failed to record calibration data %d\n",
* their index. We sort them here hdr->op_code);
*/
switch (hdr->op_code) {
case IWL_PHY_CALIBRATE_DC_CMD:
index = IWL_CALIB_DC;
break;
case IWL_PHY_CALIBRATE_LO_CMD:
index = IWL_CALIB_LO;
break;
case IWL_PHY_CALIBRATE_TX_IQ_CMD:
index = IWL_CALIB_TX_IQ;
break;
case IWL_PHY_CALIBRATE_TX_IQ_PERD_CMD:
index = IWL_CALIB_TX_IQ_PERD;
break;
case IWL_PHY_CALIBRATE_BASE_BAND_CMD:
index = IWL_CALIB_BASE_BAND;
break;
default:
IWL_ERR(priv, "Unknown calibration notification %d\n",
hdr->op_code);
return -1;
}
iwl_calib_set(&priv->calib_results[index], pkt->u.raw, len);
return 0; return 0;
} }
@ -477,9 +451,11 @@ static int iwlagn_alive_notify(struct iwl_priv *priv)
if (ret) if (ret)
return ret; return ret;
ret = iwlagn_set_Xtal_calib(priv); if (!priv->cfg->no_xtal_calib) {
if (ret) ret = iwlagn_set_Xtal_calib(priv);
return ret; if (ret)
return ret;
}
return iwl_send_calib_results(priv); return iwl_send_calib_results(priv);
} }

View File

@ -1575,6 +1575,8 @@ static int iwl_init_drv(struct iwl_priv *priv)
mutex_init(&priv->shrd->mutex); mutex_init(&priv->shrd->mutex);
INIT_LIST_HEAD(&priv->calib_results);
priv->ieee_channels = NULL; priv->ieee_channels = NULL;
priv->ieee_rates = NULL; priv->ieee_rates = NULL;
priv->band = IEEE80211_BAND_2GHZ; priv->band = IEEE80211_BAND_2GHZ;
@ -1680,6 +1682,35 @@ static int iwl_set_hw_params(struct iwl_priv *priv)
static void iwl_debug_config(struct iwl_priv *priv)
{
dev_printk(KERN_INFO, bus(priv)->dev, "CONFIG_IWLWIFI_DEBUG "
#ifdef CONFIG_IWLWIFI_DEBUG
"enabled\n");
#else
"disabled\n");
#endif
dev_printk(KERN_INFO, bus(priv)->dev, "CONFIG_IWLWIFI_DEBUGFS "
#ifdef CONFIG_IWLWIFI_DEBUGFS
"enabled\n");
#else
"disabled\n");
#endif
dev_printk(KERN_INFO, bus(priv)->dev, "CONFIG_IWLWIFI_DEVICE_TRACING "
#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
"enabled\n");
#else
"disabled\n");
#endif
dev_printk(KERN_INFO, bus(priv)->dev, "CONFIG_IWLWIFI_DEVICE_SVTOOL "
#ifdef CONFIG_IWLWIFI_DEVICE_SVTOOL
"enabled\n");
#else
"disabled\n");
#endif
}
int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops, int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops,
struct iwl_cfg *cfg) struct iwl_cfg *cfg)
{ {
@ -1715,6 +1746,9 @@ int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops,
SET_IEEE80211_DEV(hw, bus(priv)->dev); SET_IEEE80211_DEV(hw, bus(priv)->dev);
/* what debugging capabilities we have */
iwl_debug_config(priv);
IWL_DEBUG_INFO(priv, "*** LOAD DRIVER ***\n"); IWL_DEBUG_INFO(priv, "*** LOAD DRIVER ***\n");
priv->cfg = cfg; priv->cfg = cfg;
@ -1988,9 +2022,10 @@ MODULE_PARM_DESC(plcp_check, "Check plcp health (default: 1 [enabled])");
module_param_named(ack_check, iwlagn_mod_params.ack_check, bool, S_IRUGO); module_param_named(ack_check, iwlagn_mod_params.ack_check, bool, S_IRUGO);
MODULE_PARM_DESC(ack_check, "Check ack health (default: 0 [disabled])"); MODULE_PARM_DESC(ack_check, "Check ack health (default: 0 [disabled])");
module_param_named(wd_disable, iwlagn_mod_params.wd_disable, bool, S_IRUGO); module_param_named(wd_disable, iwlagn_mod_params.wd_disable, int, S_IRUGO);
MODULE_PARM_DESC(wd_disable, MODULE_PARM_DESC(wd_disable,
"Disable stuck queue watchdog timer (default: 0 [enabled])"); "Disable stuck queue watchdog timer 0=system default, "
"1=disable, 2=enable (default: 0)");
/* /*
* set bt_coex_active to true, uCode will do kill/defer * set bt_coex_active to true, uCode will do kill/defer

View File

@ -101,6 +101,8 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf, struct ieee80211_bss_conf *bss_conf,
u32 changes); u32 changes);
void iwlagn_config_ht40(struct ieee80211_conf *conf,
struct iwl_rxon_context *ctx);
/* uCode */ /* uCode */
int iwlagn_rx_calib_result(struct iwl_priv *priv, int iwlagn_rx_calib_result(struct iwl_priv *priv,

View File

@ -1505,11 +1505,23 @@ void iwl_setup_watchdog(struct iwl_priv *priv)
{ {
unsigned int timeout = priv->cfg->base_params->wd_timeout; unsigned int timeout = priv->cfg->base_params->wd_timeout;
if (timeout && !iwlagn_mod_params.wd_disable) if (!iwlagn_mod_params.wd_disable) {
mod_timer(&priv->watchdog, /* use system default */
jiffies + msecs_to_jiffies(IWL_WD_TICK(timeout))); if (timeout && !priv->cfg->base_params->wd_disable)
else mod_timer(&priv->watchdog,
del_timer(&priv->watchdog); jiffies +
msecs_to_jiffies(IWL_WD_TICK(timeout)));
else
del_timer(&priv->watchdog);
} else {
/* module parameter overwrite default configuration */
if (timeout && iwlagn_mod_params.wd_disable == 2)
mod_timer(&priv->watchdog,
jiffies +
msecs_to_jiffies(IWL_WD_TICK(timeout)));
else
del_timer(&priv->watchdog);
}
} }
/** /**

View File

@ -113,6 +113,7 @@ struct iwl_lib_ops {
* @shadow_reg_enable: HW shadhow register bit * @shadow_reg_enable: HW shadhow register bit
* @no_idle_support: do not support idle mode * @no_idle_support: do not support idle mode
* @hd_v2: v2 of enhanced sensitivity value, used for 2000 series and up * @hd_v2: v2 of enhanced sensitivity value, used for 2000 series and up
* wd_disable: disable watchdog timer
*/ */
struct iwl_base_params { struct iwl_base_params {
int eeprom_size; int eeprom_size;
@ -134,6 +135,7 @@ struct iwl_base_params {
const bool shadow_reg_enable; const bool shadow_reg_enable;
const bool no_idle_support; const bool no_idle_support;
const bool hd_v2; const bool hd_v2;
const bool wd_disable;
}; };
/* /*
* @advanced_bt_coexist: support advanced bt coexist * @advanced_bt_coexist: support advanced bt coexist
@ -184,8 +186,9 @@ struct iwl_ht_params {
* @ht_params: point to ht patameters * @ht_params: point to ht patameters
* @bt_params: pointer to bt parameters * @bt_params: pointer to bt parameters
* @pa_type: used by 6000 series only to identify the type of Power Amplifier * @pa_type: used by 6000 series only to identify the type of Power Amplifier
* @need_dc_calib: need to perform init dc calibration
* @need_temp_offset_calib: need to perform temperature offset calibration * @need_temp_offset_calib: need to perform temperature offset calibration
* @no_xtal_calib: some devices do not need crystal calibration data,
* don't send it to those
* @scan_antennas: available antenna for scan operation * @scan_antennas: available antenna for scan operation
* @led_mode: 0=blinking, 1=On(RF On)/Off(RF Off) * @led_mode: 0=blinking, 1=On(RF On)/Off(RF Off)
* @adv_pm: advance power management * @adv_pm: advance power management
@ -222,8 +225,8 @@ struct iwl_cfg {
struct iwl_ht_params *ht_params; struct iwl_ht_params *ht_params;
struct iwl_bt_params *bt_params; struct iwl_bt_params *bt_params;
enum iwl_pa_type pa_type; /* if used set to IWL_PA_SYSTEM */ enum iwl_pa_type pa_type; /* if used set to IWL_PA_SYSTEM */
const bool need_dc_calib; /* if used set to true */
const bool need_temp_offset_calib; /* if used set to true */ const bool need_temp_offset_calib; /* if used set to true */
const bool no_xtal_calib;
u8 scan_rx_antennas[IEEE80211_NUM_BANDS]; u8 scan_rx_antennas[IEEE80211_NUM_BANDS];
enum iwl_led_mode led_mode; enum iwl_led_mode led_mode;
const bool adv_pm; const bool adv_pm;

View File

@ -442,26 +442,12 @@ enum iwlagn_chain_noise_state {
}; };
/*
* enum iwl_calib
* defines the order in which results of initial calibrations
* should be sent to the runtime uCode
*/
enum iwl_calib {
IWL_CALIB_XTAL,
IWL_CALIB_DC,
IWL_CALIB_LO,
IWL_CALIB_TX_IQ,
IWL_CALIB_TX_IQ_PERD,
IWL_CALIB_BASE_BAND,
IWL_CALIB_TEMP_OFFSET,
IWL_CALIB_MAX
};
/* Opaque calibration results */ /* Opaque calibration results */
struct iwl_calib_result { struct iwl_calib_result {
void *buf; struct list_head list;
size_t buf_len; size_t cmd_len;
struct iwl_calib_hdr hdr;
/* data follows */
}; };
/* Sensitivity calib data */ /* Sensitivity calib data */
@ -869,7 +855,7 @@ struct iwl_priv {
s32 last_temperature; s32 last_temperature;
/* init calibration results */ /* init calibration results */
struct iwl_calib_result calib_results[IWL_CALIB_MAX]; struct list_head calib_results;
struct iwl_wipan_noa_data __rcu *noa_data; struct iwl_wipan_noa_data __rcu *noa_data;

View File

@ -120,7 +120,7 @@ extern struct iwl_mod_params iwlagn_mod_params;
* @restart_fw: restart firmware, default = 1 * @restart_fw: restart firmware, default = 1
* @plcp_check: enable plcp health check, default = true * @plcp_check: enable plcp health check, default = true
* @ack_check: disable ack health check, default = false * @ack_check: disable ack health check, default = false
* @wd_disable: enable stuck queue check, default = false * @wd_disable: enable stuck queue check, default = 0
* @bt_coex_active: enable bt coex, default = true * @bt_coex_active: enable bt coex, default = true
* @led_mode: system default, default = 0 * @led_mode: system default, default = 0
* @no_sleep_autoadjust: disable autoadjust, default = true * @no_sleep_autoadjust: disable autoadjust, default = true
@ -141,7 +141,7 @@ struct iwl_mod_params {
int restart_fw; int restart_fw;
bool plcp_check; bool plcp_check;
bool ack_check; bool ack_check;
bool wd_disable; int wd_disable;
bool bt_coex_active; bool bt_coex_active;
int led_mode; int led_mode;
bool no_sleep_autoadjust; bool no_sleep_autoadjust;
@ -174,7 +174,6 @@ struct iwl_mod_params {
* @ct_kill_exit_threshold: when to reeable the device - in hw dependent unit * @ct_kill_exit_threshold: when to reeable the device - in hw dependent unit
* relevant for 1000, 6000 and up * relevant for 1000, 6000 and up
* @wd_timeout: TX queues watchdog timeout * @wd_timeout: TX queues watchdog timeout
* @calib_init_cfg: setup initial calibrations for the hw
* @calib_rt_cfg: setup runtime calibrations for the hw * @calib_rt_cfg: setup runtime calibrations for the hw
* @struct iwl_sensitivity_ranges: range of sensitivity values * @struct iwl_sensitivity_ranges: range of sensitivity values
*/ */
@ -195,7 +194,6 @@ struct iwl_hw_params {
u32 ct_kill_exit_threshold; u32 ct_kill_exit_threshold;
unsigned int wd_timeout; unsigned int wd_timeout;
u32 calib_init_cfg;
u32 calib_rt_cfg; u32 calib_rt_cfg;
const struct iwl_sensitivity_ranges *sens; const struct iwl_sensitivity_ranges *sens;
}; };

View File

@ -276,7 +276,7 @@ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb)
IWL_INFO(priv, "testmode register access command offset 0x%x\n", ofs); IWL_INFO(priv, "testmode register access command offset 0x%x\n", ofs);
switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) { switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
case IWL_TM_CMD_APP2DEV_REG_READ32: case IWL_TM_CMD_APP2DEV_DIRECT_REG_READ32:
val32 = iwl_read32(bus(priv), ofs); val32 = iwl_read32(bus(priv), ofs);
IWL_INFO(priv, "32bit value to read 0x%x\n", val32); IWL_INFO(priv, "32bit value to read 0x%x\n", val32);
@ -291,7 +291,7 @@ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb)
IWL_DEBUG_INFO(priv, IWL_DEBUG_INFO(priv,
"Error sending msg : %d\n", status); "Error sending msg : %d\n", status);
break; break;
case IWL_TM_CMD_APP2DEV_REG_WRITE32: case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32:
if (!tb[IWL_TM_ATTR_REG_VALUE32]) { if (!tb[IWL_TM_ATTR_REG_VALUE32]) {
IWL_DEBUG_INFO(priv, IWL_DEBUG_INFO(priv,
"Error finding value to write\n"); "Error finding value to write\n");
@ -302,7 +302,7 @@ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb)
iwl_write32(bus(priv), ofs, val32); iwl_write32(bus(priv), ofs, val32);
} }
break; break;
case IWL_TM_CMD_APP2DEV_REG_WRITE8: case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8:
if (!tb[IWL_TM_ATTR_REG_VALUE8]) { if (!tb[IWL_TM_ATTR_REG_VALUE8]) {
IWL_DEBUG_INFO(priv, "Error finding value to write\n"); IWL_DEBUG_INFO(priv, "Error finding value to write\n");
return -ENOMSG; return -ENOMSG;
@ -312,6 +312,32 @@ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb)
iwl_write8(bus(priv), ofs, val8); iwl_write8(bus(priv), ofs, val8);
} }
break; break;
case IWL_TM_CMD_APP2DEV_INDIRECT_REG_READ32:
val32 = iwl_read_prph(bus(priv), ofs);
IWL_INFO(priv, "32bit value to read 0x%x\n", val32);
skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20);
if (!skb) {
IWL_DEBUG_INFO(priv, "Error allocating memory\n");
return -ENOMEM;
}
NLA_PUT_U32(skb, IWL_TM_ATTR_REG_VALUE32, val32);
status = cfg80211_testmode_reply(skb);
if (status < 0)
IWL_DEBUG_INFO(priv,
"Error sending msg : %d\n", status);
break;
case IWL_TM_CMD_APP2DEV_INDIRECT_REG_WRITE32:
if (!tb[IWL_TM_ATTR_REG_VALUE32]) {
IWL_DEBUG_INFO(priv,
"Error finding value to write\n");
return -ENOMSG;
} else {
val32 = nla_get_u32(tb[IWL_TM_ATTR_REG_VALUE32]);
IWL_INFO(priv, "32bit value to write 0x%x\n", val32);
iwl_write_prph(bus(priv), ofs, val32);
}
break;
default: default:
IWL_DEBUG_INFO(priv, "Unknown testmode register command ID\n"); IWL_DEBUG_INFO(priv, "Unknown testmode register command ID\n");
return -ENOSYS; return -ENOSYS;
@ -665,9 +691,11 @@ int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
IWL_DEBUG_INFO(priv, "testmode cmd to uCode\n"); IWL_DEBUG_INFO(priv, "testmode cmd to uCode\n");
result = iwl_testmode_ucode(hw, tb); result = iwl_testmode_ucode(hw, tb);
break; break;
case IWL_TM_CMD_APP2DEV_REG_READ32: case IWL_TM_CMD_APP2DEV_DIRECT_REG_READ32:
case IWL_TM_CMD_APP2DEV_REG_WRITE32: case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32:
case IWL_TM_CMD_APP2DEV_REG_WRITE8: case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8:
case IWL_TM_CMD_APP2DEV_INDIRECT_REG_READ32:
case IWL_TM_CMD_APP2DEV_INDIRECT_REG_WRITE32:
IWL_DEBUG_INFO(priv, "testmode cmd to register\n"); IWL_DEBUG_INFO(priv, "testmode cmd to register\n");
result = iwl_testmode_reg(hw, tb); result = iwl_testmode_reg(hw, tb);
break; break;

View File

@ -76,9 +76,9 @@
* the actual uCode host command ID is carried with * the actual uCode host command ID is carried with
* IWL_TM_ATTR_UCODE_CMD_ID * IWL_TM_ATTR_UCODE_CMD_ID
* *
* @IWL_TM_CMD_APP2DEV_REG_READ32: * @IWL_TM_CMD_APP2DEV_DIRECT_REG_READ32:
* @IWL_TM_CMD_APP2DEV_REG_WRITE32: * @IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32:
* @IWL_TM_CMD_APP2DEV_REG_WRITE8: * @IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8:
* commands from user applicaiton to access register * commands from user applicaiton to access register
* *
* @IWL_TM_CMD_APP2DEV_GET_DEVICENAME: retrieve device name * @IWL_TM_CMD_APP2DEV_GET_DEVICENAME: retrieve device name
@ -107,12 +107,16 @@
* commands from user application to own change the ownership of the uCode * commands from user application to own change the ownership of the uCode
* if application has the ownership, the only host command from * if application has the ownership, the only host command from
* testmode will deliver to uCode. Default owner is driver * testmode will deliver to uCode. Default owner is driver
* @IWL_TM_CMD_APP2DEV_INDIRECT_REG_READ32:
* @IWL_TM_CMD_APP2DEV_INDIRECT_REG_WRITE32:
* commands from user applicaiton to indirectly access peripheral register
*
*/ */
enum iwl_tm_cmd_t { enum iwl_tm_cmd_t {
IWL_TM_CMD_APP2DEV_UCODE = 1, IWL_TM_CMD_APP2DEV_UCODE = 1,
IWL_TM_CMD_APP2DEV_REG_READ32 = 2, IWL_TM_CMD_APP2DEV_DIRECT_REG_READ32 = 2,
IWL_TM_CMD_APP2DEV_REG_WRITE32 = 3, IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32 = 3,
IWL_TM_CMD_APP2DEV_REG_WRITE8 = 4, IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8 = 4,
IWL_TM_CMD_APP2DEV_GET_DEVICENAME = 5, IWL_TM_CMD_APP2DEV_GET_DEVICENAME = 5,
IWL_TM_CMD_APP2DEV_LOAD_INIT_FW = 6, IWL_TM_CMD_APP2DEV_LOAD_INIT_FW = 6,
IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB = 7, IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB = 7,
@ -126,7 +130,9 @@ enum iwl_tm_cmd_t {
IWL_TM_CMD_DEV2APP_UCODE_RX_PKT = 15, IWL_TM_CMD_DEV2APP_UCODE_RX_PKT = 15,
IWL_TM_CMD_DEV2APP_EEPROM_RSP = 16, IWL_TM_CMD_DEV2APP_EEPROM_RSP = 16,
IWL_TM_CMD_APP2DEV_OWNERSHIP = 17, IWL_TM_CMD_APP2DEV_OWNERSHIP = 17,
IWL_TM_CMD_MAX = 18, IWL_TM_CMD_APP2DEV_INDIRECT_REG_READ32 = 18,
IWL_TM_CMD_APP2DEV_INDIRECT_REG_WRITE32 = 19,
IWL_TM_CMD_MAX = 20,
}; };
/* /*

View File

@ -1100,13 +1100,21 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
hdr->seq_ctrl = hdr->seq_ctrl & hdr->seq_ctrl = hdr->seq_ctrl &
cpu_to_le16(IEEE80211_SCTL_FRAG); cpu_to_le16(IEEE80211_SCTL_FRAG);
hdr->seq_ctrl |= cpu_to_le16(seq_number); hdr->seq_ctrl |= cpu_to_le16(seq_number);
seq_number += 0x10;
/* aggregation is on for this <sta,tid> */ /* aggregation is on for this <sta,tid> */
if (info->flags & IEEE80211_TX_CTL_AMPDU) { if (info->flags & IEEE80211_TX_CTL_AMPDU) {
WARN_ON_ONCE(tid_data->agg.state != IWL_AGG_ON); if (WARN_ON_ONCE(tid_data->agg.state != IWL_AGG_ON)) {
IWL_ERR(trans, "TX_CTL_AMPDU while not in AGG:"
" Tx flags = 0x%08x, agg.state = %d",
info->flags, tid_data->agg.state);
IWL_ERR(trans, "sta_id = %d, tid = %d "
"txq_id = %d, seq_num = %d", sta_id,
tid, tid_data->agg.txq_id,
seq_number >> 4);
}
txq_id = tid_data->agg.txq_id; txq_id = tid_data->agg.txq_id;
is_agg = true; is_agg = true;
} }
seq_number += 0x10;
} }
/* Copy MAC header from skb into command buffer */ /* Copy MAC header from skb into command buffer */

View File

@ -1291,7 +1291,6 @@ static struct spi_driver libertas_spi_driver = {
.remove = __devexit_p(libertas_spi_remove), .remove = __devexit_p(libertas_spi_remove),
.driver = { .driver = {
.name = "libertas_spi", .name = "libertas_spi",
.bus = &spi_bus_type,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.pm = &if_spi_pm_ops, .pm = &if_spi_pm_ops,
}, },

View File

@ -120,10 +120,11 @@ mwifiex_cfg80211_del_key(struct wiphy *wiphy, struct net_device *netdev,
static int static int
mwifiex_cfg80211_set_tx_power(struct wiphy *wiphy, mwifiex_cfg80211_set_tx_power(struct wiphy *wiphy,
enum nl80211_tx_power_setting type, enum nl80211_tx_power_setting type,
int dbm) int mbm)
{ {
struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
struct mwifiex_power_cfg power_cfg; struct mwifiex_power_cfg power_cfg;
int dbm = MBM_TO_DBM(mbm);
if (type == NL80211_TX_POWER_FIXED) { if (type == NL80211_TX_POWER_FIXED) {
power_cfg.is_power_auto = 0; power_cfg.is_power_auto = 0;

View File

@ -700,7 +700,6 @@ static int __devexit p54spi_remove(struct spi_device *spi)
static struct spi_driver p54spi_driver = { static struct spi_driver p54spi_driver = {
.driver = { .driver = {
.name = "p54spi", .name = "p54spi",
.bus = &spi_bus_type,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}, },

View File

@ -2493,323 +2493,7 @@ prism54_set_mac_address(struct net_device *ndev, void *addr)
return ret; return ret;
} }
/* Note: currently, use hostapd ioctl from the Host AP driver for WPA
* support. This is to be replaced with Linux wireless extensions once they
* get WPA support. */
/* Note II: please leave all this together as it will be easier to remove later,
* once wireless extensions add WPA support -mcgrof */
/* PRISM54_HOSTAPD ioctl() cmd: */
enum {
PRISM2_SET_ENCRYPTION = 6,
PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12,
PRISM2_HOSTAPD_MLME = 13,
PRISM2_HOSTAPD_SCAN_REQ = 14,
};
#define PRISM54_SET_WPA SIOCIWFIRSTPRIV+12 #define PRISM54_SET_WPA SIOCIWFIRSTPRIV+12
#define PRISM54_HOSTAPD SIOCIWFIRSTPRIV+25
#define PRISM54_DROP_UNENCRYPTED SIOCIWFIRSTPRIV+26
#define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024
#define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
offsetof(struct prism2_hostapd_param, u.generic_elem.data)
/* Maximum length for algorithm names (-1 for nul termination)
* used in ioctl() */
#define HOSTAP_CRYPT_ALG_NAME_LEN 16
struct prism2_hostapd_param {
u32 cmd;
u8 sta_addr[ETH_ALEN];
union {
struct {
u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN];
u32 flags;
u32 err;
u8 idx;
u8 seq[8]; /* sequence counter (set: RX, get: TX) */
u16 key_len;
u8 key[0];
} crypt;
struct {
u8 len;
u8 data[0];
} generic_elem;
struct {
#define MLME_STA_DEAUTH 0
#define MLME_STA_DISASSOC 1
u16 cmd;
u16 reason_code;
} mlme;
struct {
u8 ssid_len;
u8 ssid[32];
} scan_req;
} u;
};
static int
prism2_ioctl_set_encryption(struct net_device *dev,
struct prism2_hostapd_param *param,
int param_len)
{
islpci_private *priv = netdev_priv(dev);
int rvalue = 0, force = 0;
int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0;
union oid_res_t r;
/* with the new API, it's impossible to get a NULL pointer.
* New version of iwconfig set the IW_ENCODE_NOKEY flag
* when no key is given, but older versions don't. */
if (param->u.crypt.key_len > 0) {
/* we have a key to set */
int index = param->u.crypt.idx;
int current_index;
struct obj_key key = { DOT11_PRIV_TKIP, 0, "" };
/* get the current key index */
rvalue = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r);
current_index = r.u;
/* Verify that the key is not marked as invalid */
if (!(param->u.crypt.flags & IW_ENCODE_NOKEY)) {
key.length = param->u.crypt.key_len > sizeof (param->u.crypt.key) ?
sizeof (param->u.crypt.key) : param->u.crypt.key_len;
memcpy(key.key, param->u.crypt.key, key.length);
if (key.length == 32)
/* we want WPA-PSK */
key.type = DOT11_PRIV_TKIP;
if ((index < 0) || (index > 3))
/* no index provided use the current one */
index = current_index;
/* now send the key to the card */
rvalue |=
mgt_set_request(priv, DOT11_OID_DEFKEYX, index,
&key);
}
/*
* If a valid key is set, encryption should be enabled
* (user may turn it off later).
* This is also how "iwconfig ethX key on" works
*/
if ((index == current_index) && (key.length > 0))
force = 1;
} else {
int index = (param->u.crypt.flags & IW_ENCODE_INDEX) - 1;
if ((index >= 0) && (index <= 3)) {
/* we want to set the key index */
rvalue |=
mgt_set_request(priv, DOT11_OID_DEFKEYID, 0,
&index);
} else {
if (!(param->u.crypt.flags & IW_ENCODE_MODE)) {
/* we cannot do anything. Complain. */
return -EINVAL;
}
}
}
/* now read the flags */
if (param->u.crypt.flags & IW_ENCODE_DISABLED) {
/* Encoding disabled,
* authen = DOT11_AUTH_OS;
* invoke = 0;
* exunencrypt = 0; */
}
if (param->u.crypt.flags & IW_ENCODE_OPEN)
/* Encode but accept non-encoded packets. No auth */
invoke = 1;
if ((param->u.crypt.flags & IW_ENCODE_RESTRICTED) || force) {
/* Refuse non-encoded packets. Auth */
authen = DOT11_AUTH_BOTH;
invoke = 1;
exunencrypt = 1;
}
/* do the change if requested */
if ((param->u.crypt.flags & IW_ENCODE_MODE) || force) {
rvalue |=
mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen);
rvalue |=
mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &invoke);
rvalue |=
mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0,
&exunencrypt);
}
return rvalue;
}
static int
prism2_ioctl_set_generic_element(struct net_device *ndev,
struct prism2_hostapd_param *param,
int param_len)
{
islpci_private *priv = netdev_priv(ndev);
int max_len, len, alen, ret=0;
struct obj_attachment *attach;
len = param->u.generic_elem.len;
max_len = param_len - PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN;
if (max_len < 0 || max_len < len)
return -EINVAL;
alen = sizeof(*attach) + len;
attach = kzalloc(alen, GFP_KERNEL);
if (attach == NULL)
return -ENOMEM;
#define WLAN_FC_TYPE_MGMT 0
#define WLAN_FC_STYPE_ASSOC_REQ 0
#define WLAN_FC_STYPE_REASSOC_REQ 2
/* Note: endianness is covered by mgt_set_varlen */
attach->type = (WLAN_FC_TYPE_MGMT << 2) |
(WLAN_FC_STYPE_ASSOC_REQ << 4);
attach->id = -1;
attach->size = len;
memcpy(attach->data, param->u.generic_elem.data, len);
ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, len);
if (ret == 0) {
attach->type = (WLAN_FC_TYPE_MGMT << 2) |
(WLAN_FC_STYPE_REASSOC_REQ << 4);
ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, len);
if (ret == 0)
printk(KERN_DEBUG "%s: WPA IE Attachment was set\n",
ndev->name);
}
kfree(attach);
return ret;
}
static int
prism2_ioctl_mlme(struct net_device *dev, struct prism2_hostapd_param *param)
{
return -EOPNOTSUPP;
}
static int
prism2_ioctl_scan_req(struct net_device *ndev,
struct prism2_hostapd_param *param)
{
islpci_private *priv = netdev_priv(ndev);
struct iw_request_info info;
int i, rvalue;
struct obj_bsslist *bsslist;
u32 noise = 0;
char *extra = "";
char *current_ev = "foo";
union oid_res_t r;
if (islpci_get_state(priv) < PRV_STATE_INIT) {
/* device is not ready, fail gently */
return 0;
}
/* first get the noise value. We will use it to report the link quality */
rvalue = mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r);
noise = r.u;
/* Ask the device for a list of known bss. We can report at most
* IW_MAX_AP=64 to the range struct. But the device won't repport anything
* if you change the value of IWMAX_BSS=24.
*/
rvalue |= mgt_get_request(priv, DOT11_OID_BSSLIST, 0, NULL, &r);
bsslist = r.ptr;
info.cmd = PRISM54_HOSTAPD;
info.flags = 0;
/* ok now, scan the list and translate its info */
for (i = 0; i < min(IW_MAX_AP, (int) bsslist->nr); i++)
current_ev = prism54_translate_bss(ndev, &info, current_ev,
extra + IW_SCAN_MAX_DATA,
&(bsslist->bsslist[i]),
noise);
kfree(bsslist);
return rvalue;
}
static int
prism54_hostapd(struct net_device *ndev, struct iw_point *p)
{
struct prism2_hostapd_param *param;
int ret = 0;
u32 uwrq;
printk(KERN_DEBUG "prism54_hostapd - len=%d\n", p->length);
if (p->length < sizeof(struct prism2_hostapd_param) ||
p->length > PRISM2_HOSTAPD_MAX_BUF_SIZE || !p->pointer)
return -EINVAL;
param = memdup_user(p->pointer, p->length);
if (IS_ERR(param))
return PTR_ERR(param);
switch (param->cmd) {
case PRISM2_SET_ENCRYPTION:
printk(KERN_DEBUG "%s: Caught WPA supplicant set encryption request\n",
ndev->name);
ret = prism2_ioctl_set_encryption(ndev, param, p->length);
break;
case PRISM2_HOSTAPD_SET_GENERIC_ELEMENT:
printk(KERN_DEBUG "%s: Caught WPA supplicant set WPA IE request\n",
ndev->name);
ret = prism2_ioctl_set_generic_element(ndev, param,
p->length);
break;
case PRISM2_HOSTAPD_MLME:
printk(KERN_DEBUG "%s: Caught WPA supplicant MLME request\n",
ndev->name);
ret = prism2_ioctl_mlme(ndev, param);
break;
case PRISM2_HOSTAPD_SCAN_REQ:
printk(KERN_DEBUG "%s: Caught WPA supplicant scan request\n",
ndev->name);
ret = prism2_ioctl_scan_req(ndev, param);
break;
case PRISM54_SET_WPA:
printk(KERN_DEBUG "%s: Caught WPA supplicant wpa init request\n",
ndev->name);
uwrq = 1;
ret = prism54_set_wpa(ndev, NULL, &uwrq, NULL);
break;
case PRISM54_DROP_UNENCRYPTED:
printk(KERN_DEBUG "%s: Caught WPA drop unencrypted request\n",
ndev->name);
#if 0
uwrq = 0x01;
mgt_set(priv, DOT11_OID_EXUNENCRYPTED, &uwrq);
down_write(&priv->mib_sem);
mgt_commit(priv);
up_write(&priv->mib_sem);
#endif
/* Not necessary, as set_wpa does it, should we just do it here though? */
ret = 0;
break;
default:
printk(KERN_DEBUG "%s: Caught a WPA supplicant request that is not supported\n",
ndev->name);
ret = -EOPNOTSUPP;
break;
}
if (ret == 0 && copy_to_user(p->pointer, param, p->length))
ret = -EFAULT;
kfree(param);
return ret;
}
static int static int
prism54_set_wpa(struct net_device *ndev, struct iw_request_info *info, prism54_set_wpa(struct net_device *ndev, struct iw_request_info *info,
@ -3223,20 +2907,3 @@ const struct iw_handler_def prism54_handler_def = {
.private_args = (struct iw_priv_args *) prism54_private_args, .private_args = (struct iw_priv_args *) prism54_private_args,
.get_wireless_stats = prism54_get_wireless_stats, .get_wireless_stats = prism54_get_wireless_stats,
}; };
/* For wpa_supplicant */
int
prism54_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
{
struct iwreq *wrq = (struct iwreq *) rq;
int ret = -1;
switch (cmd) {
case PRISM54_HOSTAPD:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
ret = prism54_hostapd(ndev, &wrq->u.data);
return ret;
}
return -EOPNOTSUPP;
}

View File

@ -43,8 +43,6 @@ void prism54_wpa_bss_ie_clean(islpci_private *priv);
int prism54_set_mac_address(struct net_device *, void *); int prism54_set_mac_address(struct net_device *, void *);
int prism54_ioctl(struct net_device *, struct ifreq *, int);
extern const struct iw_handler_def prism54_handler_def; extern const struct iw_handler_def prism54_handler_def;
#endif /* _ISL_IOCTL_H */ #endif /* _ISL_IOCTL_H */

View File

@ -804,7 +804,6 @@ static const struct ethtool_ops islpci_ethtool_ops = {
static const struct net_device_ops islpci_netdev_ops = { static const struct net_device_ops islpci_netdev_ops = {
.ndo_open = islpci_open, .ndo_open = islpci_open,
.ndo_stop = islpci_close, .ndo_stop = islpci_close,
.ndo_do_ioctl = prism54_ioctl,
.ndo_start_xmit = islpci_eth_transmit, .ndo_start_xmit = islpci_eth_transmit,
.ndo_tx_timeout = islpci_eth_tx_timeout, .ndo_tx_timeout = islpci_eth_tx_timeout,
.ndo_set_mac_address = prism54_set_mac_address, .ndo_set_mac_address = prism54_set_mac_address,

View File

@ -1203,8 +1203,10 @@ void rt2800_config_filter(struct rt2x00_dev *rt2x00dev,
!(filter_flags & FIF_CONTROL)); !(filter_flags & FIF_CONTROL));
rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_PSPOLL, rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_PSPOLL,
!(filter_flags & FIF_PSPOLL)); !(filter_flags & FIF_PSPOLL));
rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BA, 1); rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BA,
rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BAR, 0); !(filter_flags & FIF_CONTROL));
rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BAR,
!(filter_flags & FIF_CONTROL));
rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_CNTL, rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_CNTL,
!(filter_flags & FIF_CONTROL)); !(filter_flags & FIF_CONTROL));
rt2800_register_write(rt2x00dev, RX_FILTER_CFG, reg); rt2800_register_write(rt2x00dev, RX_FILTER_CFG, reg);

View File

@ -780,6 +780,7 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id)
unsigned long flags; unsigned long flags;
u32 inta = 0; u32 inta = 0;
u32 intb = 0; u32 intb = 0;
irqreturn_t ret = IRQ_HANDLED;
spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
@ -787,8 +788,10 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id)
rtlpriv->cfg->ops->interrupt_recognized(hw, &inta, &intb); rtlpriv->cfg->ops->interrupt_recognized(hw, &inta, &intb);
/*Shared IRQ or HW disappared */ /*Shared IRQ or HW disappared */
if (!inta || inta == 0xffff) if (!inta || inta == 0xffff) {
ret = IRQ_NONE;
goto done; goto done;
}
/*<1> beacon related */ /*<1> beacon related */
if (inta & rtlpriv->cfg->maps[RTL_IMR_TBDOK]) { if (inta & rtlpriv->cfg->maps[RTL_IMR_TBDOK]) {
@ -892,7 +895,7 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id)
done: done:
spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
return IRQ_HANDLED; return ret;
} }
static void _rtl_pci_irq_tasklet(struct ieee80211_hw *hw) static void _rtl_pci_irq_tasklet(struct ieee80211_hw *hw)

View File

@ -319,7 +319,6 @@ static int __devexit wl1251_spi_remove(struct spi_device *spi)
static struct spi_driver wl1251_spi_driver = { static struct spi_driver wl1251_spi_driver = {
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.bus = &spi_bus_type,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}, },

View File

@ -462,7 +462,6 @@ static int __devexit wl1271_remove(struct spi_device *spi)
static struct spi_driver wl1271_spi_driver = { static struct spi_driver wl1271_spi_driver = {
.driver = { .driver = {
.name = "wl1271_spi", .name = "wl1271_spi",
.bus = &spi_bus_type,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}, },

View File

@ -1339,7 +1339,7 @@ static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg,
return 0; return 0;
} }
int pn533_data_exchange(struct nfc_dev *nfc_dev, u32 target_idx, static int pn533_data_exchange(struct nfc_dev *nfc_dev, u32 target_idx,
struct sk_buff *skb, struct sk_buff *skb,
data_exchange_cb_t cb, data_exchange_cb_t cb,
void *cb_context) void *cb_context)

View File

@ -538,6 +538,9 @@
* OLBC handling in hostapd. Beacons are reported in %NL80211_CMD_FRAME * OLBC handling in hostapd. Beacons are reported in %NL80211_CMD_FRAME
* messages. Note that per PHY only one application may register. * messages. Note that per PHY only one application may register.
* *
* @NL80211_CMD_SET_NOACK_MAP: sets a bitmap for the individual TIDs whether
* No Acknowledgement Policy should be applied.
*
* @NL80211_CMD_MAX: highest used command number * @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use * @__NL80211_CMD_AFTER_LAST: internal use
*/ */
@ -675,6 +678,8 @@ enum nl80211_commands {
NL80211_CMD_UNEXPECTED_4ADDR_FRAME, NL80211_CMD_UNEXPECTED_4ADDR_FRAME,
NL80211_CMD_SET_NOACK_MAP,
/* add new commands above here */ /* add new commands above here */
/* used to define NL80211_CMD_MAX below */ /* used to define NL80211_CMD_MAX below */
@ -1185,6 +1190,9 @@ enum nl80211_commands {
* abides to when initiating radiation on DFS channels. A country maps * abides to when initiating radiation on DFS channels. A country maps
* to one DFS region. * to one DFS region.
* *
* @NL80211_ATTR_NOACK_MAP: This u16 bitmap contains the No Ack Policy of
* up to 16 TIDs.
*
* @NL80211_ATTR_MAX: highest attribute number currently defined * @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use * @__NL80211_ATTR_AFTER_LAST: internal use
*/ */
@ -1428,6 +1436,8 @@ enum nl80211_attrs {
NL80211_ATTR_DISABLE_HT, NL80211_ATTR_DISABLE_HT,
NL80211_ATTR_HT_CAPABILITY_MASK, NL80211_ATTR_HT_CAPABILITY_MASK,
NL80211_ATTR_NOACK_MAP,
/* add attributes here, update the policy in nl80211.c */ /* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST, __NL80211_ATTR_AFTER_LAST,
@ -2084,6 +2094,10 @@ enum nl80211_mntr_flags {
* access to a broader network beyond the MBSS. This is done via Root * access to a broader network beyond the MBSS. This is done via Root
* Announcement frames. * Announcement frames.
* *
* @NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL: The minimum interval of time (in
* TUs) during which a mesh STA can send only one Action frame containing a
* PERR element.
*
* @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute
* *
* @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
@ -2107,6 +2121,7 @@ enum nl80211_meshconf_params {
NL80211_MESHCONF_ELEMENT_TTL, NL80211_MESHCONF_ELEMENT_TTL,
NL80211_MESHCONF_HWMP_RANN_INTERVAL, NL80211_MESHCONF_HWMP_RANN_INTERVAL,
NL80211_MESHCONF_GATE_ANNOUNCEMENTS, NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
/* keep last */ /* keep last */
__NL80211_MESHCONF_ATTR_AFTER_LAST, __NL80211_MESHCONF_ATTR_AFTER_LAST,

View File

@ -782,6 +782,7 @@ struct mesh_config {
u16 min_discovery_timeout; u16 min_discovery_timeout;
u32 dot11MeshHWMPactivePathTimeout; u32 dot11MeshHWMPactivePathTimeout;
u16 dot11MeshHWMPpreqMinInterval; u16 dot11MeshHWMPpreqMinInterval;
u16 dot11MeshHWMPperrMinInterval;
u16 dot11MeshHWMPnetDiameterTraversalTime; u16 dot11MeshHWMPnetDiameterTraversalTime;
u8 dot11MeshHWMPRootMode; u8 dot11MeshHWMPRootMode;
u16 dot11MeshHWMPRannInterval; u16 dot11MeshHWMPRannInterval;
@ -802,6 +803,7 @@ struct mesh_config {
* @ie_len: length of vendor information elements * @ie_len: length of vendor information elements
* @is_authenticated: this mesh requires authentication * @is_authenticated: this mesh requires authentication
* @is_secure: this mesh uses security * @is_secure: this mesh uses security
* @mcast_rate: multicat rate for Mesh Node [6Mbps is the default for 802.11a]
* *
* These parameters are fixed when the mesh is created. * These parameters are fixed when the mesh is created.
*/ */
@ -814,6 +816,7 @@ struct mesh_setup {
u8 ie_len; u8 ie_len;
bool is_authenticated; bool is_authenticated;
bool is_secure; bool is_secure;
int mcast_rate[IEEE80211_NUM_BANDS];
}; };
/** /**
@ -1399,7 +1402,8 @@ struct cfg80211_gtk_rekey_data {
* have changed. The actual parameter values are available in * have changed. The actual parameter values are available in
* struct wiphy. If returning an error, no value should be changed. * struct wiphy. If returning an error, no value should be changed.
* *
* @set_tx_power: set the transmit power according to the parameters * @set_tx_power: set the transmit power according to the parameters,
* the power passed is in mBm, to get dBm use MBM_TO_DBM().
* @get_tx_power: store the current TX power into the dbm variable; * @get_tx_power: store the current TX power into the dbm variable;
* return 0 if successful * return 0 if successful
* *
@ -1465,6 +1469,8 @@ struct cfg80211_gtk_rekey_data {
* *
* @probe_client: probe an associated client, must return a cookie that it * @probe_client: probe an associated client, must return a cookie that it
* later passes to cfg80211_probe_status(). * later passes to cfg80211_probe_status().
*
* @set_noack_map: Set the NoAck Map for the TIDs.
*/ */
struct cfg80211_ops { struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@ -1658,6 +1664,10 @@ struct cfg80211_ops {
int (*probe_client)(struct wiphy *wiphy, struct net_device *dev, int (*probe_client)(struct wiphy *wiphy, struct net_device *dev,
const u8 *peer, u64 *cookie); const u8 *peer, u64 *cookie);
int (*set_noack_map)(struct wiphy *wiphy,
struct net_device *dev,
u16 noack_map);
struct ieee80211_channel *(*get_channel)(struct wiphy *wiphy); struct ieee80211_channel *(*get_channel)(struct wiphy *wiphy);
}; };

View File

@ -247,15 +247,3 @@ config MAC80211_DEBUG_COUNTERS
and show them in debugfs. and show them in debugfs.
If unsure, say N. If unsure, say N.
config MAC80211_DRIVER_API_TRACER
bool "Driver API tracer"
depends on MAC80211_DEBUG_MENU
depends on EVENT_TRACING
help
Say Y here to make mac80211 register with the ftrace
framework for the driver API -- you can then see which
driver methods it is calling and which API functions
drivers are calling by looking at the trace.
If unsure, say Y.

View File

@ -24,7 +24,8 @@ mac80211-y := \
util.o \ util.o \
wme.o \ wme.o \
event.o \ event.o \
chan.o chan.o \
driver-trace.o
mac80211-$(CONFIG_MAC80211_LEDS) += led.o mac80211-$(CONFIG_MAC80211_LEDS) += led.o
mac80211-$(CONFIG_MAC80211_DEBUGFS) += \ mac80211-$(CONFIG_MAC80211_DEBUGFS) += \
@ -41,7 +42,6 @@ mac80211-$(CONFIG_MAC80211_MESH) += \
mac80211-$(CONFIG_PM) += pm.o mac80211-$(CONFIG_PM) += pm.o
mac80211-$(CONFIG_MAC80211_DRIVER_API_TRACER) += driver-trace.o
CFLAGS_driver-trace.o := -I$(src) CFLAGS_driver-trace.o := -I$(src)
# objects for PID algorithm # objects for PID algorithm

View File

@ -73,8 +73,11 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
RCU_INIT_POINTER(sta->ampdu_mlme.tid_rx[tid], NULL); RCU_INIT_POINTER(sta->ampdu_mlme.tid_rx[tid], NULL);
#ifdef CONFIG_MAC80211_HT_DEBUG #ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "Rx BA session stop requested for %pM tid %u\n", printk(KERN_DEBUG
sta->sta.addr, tid); "Rx BA session stop requested for %pM tid %u %s reason: %d\n",
sta->sta.addr, tid,
initiator == WLAN_BACK_RECIPIENT ? "recipient" : "inititator",
(int)reason);
#endif /* CONFIG_MAC80211_HT_DEBUG */ #endif /* CONFIG_MAC80211_HT_DEBUG */
if (drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_STOP, if (drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_STOP,
@ -85,7 +88,7 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
/* check if this is a self generated aggregation halt */ /* check if this is a self generated aggregation halt */
if (initiator == WLAN_BACK_RECIPIENT && tx) if (initiator == WLAN_BACK_RECIPIENT && tx)
ieee80211_send_delba(sta->sdata, sta->sta.addr, ieee80211_send_delba(sta->sdata, sta->sta.addr,
tid, 0, reason); tid, WLAN_BACK_RECIPIENT, reason);
del_timer_sync(&tid_rx->session_timer); del_timer_sync(&tid_rx->session_timer);
del_timer_sync(&tid_rx->reorder_timer); del_timer_sync(&tid_rx->reorder_timer);
@ -109,7 +112,7 @@ void ieee80211_stop_rx_ba_session(struct ieee80211_vif *vif, u16 ba_rx_bitmap,
int i; int i;
rcu_read_lock(); rcu_read_lock();
sta = sta_info_get(sdata, addr); sta = sta_info_get_bss(sdata, addr);
if (!sta) { if (!sta) {
rcu_read_unlock(); rcu_read_unlock();
return; return;

View File

@ -186,6 +186,7 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
#endif /* CONFIG_MAC80211_HT_DEBUG */ #endif /* CONFIG_MAC80211_HT_DEBUG */
del_timer_sync(&tid_tx->addba_resp_timer); del_timer_sync(&tid_tx->addba_resp_timer);
del_timer_sync(&tid_tx->session_timer);
/* /*
* After this packets are no longer handed right through * After this packets are no longer handed right through
@ -369,6 +370,28 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
tid_tx->timeout); tid_tx->timeout);
} }
/*
* After accepting the AddBA Response we activated a timer,
* resetting it after each frame that we send.
*/
static void sta_tx_agg_session_timer_expired(unsigned long data)
{
/* not an elegant detour, but there is no choice as the timer passes
* only one argument, and various sta_info are needed here, so init
* flow in sta_info_create gives the TID as data, while the timer_to_id
* array gives the sta through container_of */
u8 *ptid = (u8 *)data;
u8 *timer_to_id = ptid - *ptid;
struct sta_info *sta = container_of(timer_to_id, struct sta_info,
timer_to_tid[0]);
#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "tx session timer expired on tid %d\n", (u16)*ptid);
#endif
ieee80211_stop_tx_ba_session(&sta->sta, *ptid);
}
int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
u16 timeout) u16 timeout)
{ {
@ -438,11 +461,16 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
tid_tx->timeout = timeout; tid_tx->timeout = timeout;
/* Tx timer */ /* response timer */
tid_tx->addba_resp_timer.function = sta_addba_resp_timer_expired; tid_tx->addba_resp_timer.function = sta_addba_resp_timer_expired;
tid_tx->addba_resp_timer.data = (unsigned long)&sta->timer_to_tid[tid]; tid_tx->addba_resp_timer.data = (unsigned long)&sta->timer_to_tid[tid];
init_timer(&tid_tx->addba_resp_timer); init_timer(&tid_tx->addba_resp_timer);
/* tx timer */
tid_tx->session_timer.function = sta_tx_agg_session_timer_expired;
tid_tx->session_timer.data = (unsigned long)&sta->timer_to_tid[tid];
init_timer(&tid_tx->session_timer);
/* assign a dialog token */ /* assign a dialog token */
sta->ampdu_mlme.dialog_token_allocator++; sta->ampdu_mlme.dialog_token_allocator++;
tid_tx->dialog_token = sta->ampdu_mlme.dialog_token_allocator; tid_tx->dialog_token = sta->ampdu_mlme.dialog_token_allocator;
@ -547,7 +575,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid)
} }
mutex_lock(&local->sta_mtx); mutex_lock(&local->sta_mtx);
sta = sta_info_get(sdata, ra); sta = sta_info_get_bss(sdata, ra);
if (!sta) { if (!sta) {
mutex_unlock(&local->sta_mtx); mutex_unlock(&local->sta_mtx);
#ifdef CONFIG_MAC80211_HT_DEBUG #ifdef CONFIG_MAC80211_HT_DEBUG
@ -676,7 +704,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
mutex_lock(&local->sta_mtx); mutex_lock(&local->sta_mtx);
sta = sta_info_get(sdata, ra); sta = sta_info_get_bss(sdata, ra);
if (!sta) { if (!sta) {
#ifdef CONFIG_MAC80211_HT_DEBUG #ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "Could not find station: %pM\n", ra); printk(KERN_DEBUG "Could not find station: %pM\n", ra);
@ -814,6 +842,11 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
ieee80211_agg_tx_operational(local, sta, tid); ieee80211_agg_tx_operational(local, sta, tid);
sta->ampdu_mlme.addba_req_num[tid] = 0; sta->ampdu_mlme.addba_req_num[tid] = 0;
if (tid_tx->timeout)
mod_timer(&tid_tx->session_timer,
TU_TO_EXP_TIME(tid_tx->timeout));
} else { } else {
___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR, ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR,
true); true);

View File

@ -102,6 +102,16 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
return 0; return 0;
} }
static int ieee80211_set_noack_map(struct wiphy *wiphy,
struct net_device *dev,
u16 noack_map)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
sdata->noack_map = noack_map;
return 0;
}
static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
u8 key_idx, bool pairwise, const u8 *mac_addr, u8 key_idx, bool pairwise, const u8 *mac_addr,
struct key_params *params) struct key_params *params)
@ -499,7 +509,7 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
if (!resp || !resp_len) if (!resp || !resp_len)
return -EINVAL; return -EINVAL;
old = sdata->u.ap.probe_resp; old = rtnl_dereference(sdata->u.ap.probe_resp);
new = dev_alloc_skb(resp_len); new = dev_alloc_skb(resp_len);
if (!new) if (!new)
@ -1185,6 +1195,8 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh,
{ {
u8 *new_ie; u8 *new_ie;
const u8 *old_ie; const u8 *old_ie;
struct ieee80211_sub_if_data *sdata = container_of(ifmsh,
struct ieee80211_sub_if_data, u.mesh);
/* allocate information elements */ /* allocate information elements */
new_ie = NULL; new_ie = NULL;
@ -1211,6 +1223,10 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh,
if (setup->is_secure) if (setup->is_secure)
ifmsh->security |= IEEE80211_MESH_SEC_SECURED; ifmsh->security |= IEEE80211_MESH_SEC_SECURED;
/* mcast rate setting in Mesh Node */
memcpy(sdata->vif.bss_conf.mcast_rate, setup->mcast_rate,
sizeof(setup->mcast_rate));
return 0; return 0;
} }
@ -1256,6 +1272,9 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy,
if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, mask)) if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, mask))
conf->dot11MeshHWMPpreqMinInterval = conf->dot11MeshHWMPpreqMinInterval =
nconf->dot11MeshHWMPpreqMinInterval; nconf->dot11MeshHWMPpreqMinInterval;
if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL, mask))
conf->dot11MeshHWMPperrMinInterval =
nconf->dot11MeshHWMPperrMinInterval;
if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
mask)) mask))
conf->dot11MeshHWMPnetDiameterTraversalTime = conf->dot11MeshHWMPnetDiameterTraversalTime =
@ -2698,4 +2717,5 @@ struct cfg80211_ops mac80211_config_ops = {
.tdls_mgmt = ieee80211_tdls_mgmt, .tdls_mgmt = ieee80211_tdls_mgmt,
.probe_client = ieee80211_probe_client, .probe_client = ieee80211_probe_client,
.get_channel = ieee80211_wiphy_get_channel, .get_channel = ieee80211_wiphy_get_channel,
.set_noack_map = ieee80211_set_noack_map,
}; };

View File

@ -97,40 +97,6 @@ static const struct file_operations reset_ops = {
.llseek = noop_llseek, .llseek = noop_llseek,
}; };
static ssize_t noack_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ieee80211_local *local = file->private_data;
return mac80211_format_buffer(user_buf, count, ppos, "%d\n",
local->wifi_wme_noack_test);
}
static ssize_t noack_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ieee80211_local *local = file->private_data;
char buf[10];
size_t len;
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
return -EFAULT;
buf[len] = '\0';
local->wifi_wme_noack_test = !!simple_strtoul(buf, NULL, 0);
return count;
}
static const struct file_operations noack_ops = {
.read = noack_read,
.write = noack_write,
.open = mac80211_open_file_generic,
.llseek = default_llseek,
};
static ssize_t uapsd_queues_read(struct file *file, char __user *user_buf, static ssize_t uapsd_queues_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
@ -398,7 +364,6 @@ void debugfs_hw_add(struct ieee80211_local *local)
DEBUGFS_ADD(wep_iv); DEBUGFS_ADD(wep_iv);
DEBUGFS_ADD(queues); DEBUGFS_ADD(queues);
DEBUGFS_ADD_MODE(reset, 0200); DEBUGFS_ADD_MODE(reset, 0200);
DEBUGFS_ADD(noack);
DEBUGFS_ADD(uapsd_queues); DEBUGFS_ADD(uapsd_queues);
DEBUGFS_ADD(uapsd_max_sp_len); DEBUGFS_ADD(uapsd_max_sp_len);
DEBUGFS_ADD(channel_type); DEBUGFS_ADD(channel_type);

View File

@ -405,6 +405,8 @@ IEEE80211_IF_FILE(dot11MeshHWMPactivePathTimeout,
u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout, DEC); u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout, DEC);
IEEE80211_IF_FILE(dot11MeshHWMPpreqMinInterval, IEEE80211_IF_FILE(dot11MeshHWMPpreqMinInterval,
u.mesh.mshcfg.dot11MeshHWMPpreqMinInterval, DEC); u.mesh.mshcfg.dot11MeshHWMPpreqMinInterval, DEC);
IEEE80211_IF_FILE(dot11MeshHWMPperrMinInterval,
u.mesh.mshcfg.dot11MeshHWMPperrMinInterval, DEC);
IEEE80211_IF_FILE(dot11MeshHWMPnetDiameterTraversalTime, IEEE80211_IF_FILE(dot11MeshHWMPnetDiameterTraversalTime,
u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime, DEC); u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime, DEC);
IEEE80211_IF_FILE(dot11MeshHWMPmaxPREQretries, IEEE80211_IF_FILE(dot11MeshHWMPmaxPREQretries,
@ -534,6 +536,7 @@ static void add_mesh_config(struct ieee80211_sub_if_data *sdata)
MESHPARAMS_ADD(dot11MeshMaxPeerLinks); MESHPARAMS_ADD(dot11MeshMaxPeerLinks);
MESHPARAMS_ADD(dot11MeshHWMPactivePathTimeout); MESHPARAMS_ADD(dot11MeshHWMPactivePathTimeout);
MESHPARAMS_ADD(dot11MeshHWMPpreqMinInterval); MESHPARAMS_ADD(dot11MeshHWMPpreqMinInterval);
MESHPARAMS_ADD(dot11MeshHWMPperrMinInterval);
MESHPARAMS_ADD(dot11MeshHWMPnetDiameterTraversalTime); MESHPARAMS_ADD(dot11MeshHWMPnetDiameterTraversalTime);
MESHPARAMS_ADD(dot11MeshHWMPmaxPREQretries); MESHPARAMS_ADD(dot11MeshHWMPmaxPREQretries);
MESHPARAMS_ADD(path_refresh_time); MESHPARAMS_ADD(path_refresh_time);

View File

@ -10,6 +10,16 @@ static inline void check_sdata_in_driver(struct ieee80211_sub_if_data *sdata)
WARN_ON(!(sdata->flags & IEEE80211_SDATA_IN_DRIVER)); WARN_ON(!(sdata->flags & IEEE80211_SDATA_IN_DRIVER));
} }
static inline struct ieee80211_sub_if_data *
get_bss_sdata(struct ieee80211_sub_if_data *sdata)
{
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
sdata = container_of(sdata->bss, struct ieee80211_sub_if_data,
u.ap);
return sdata;
}
static inline void drv_tx(struct ieee80211_local *local, struct sk_buff *skb) static inline void drv_tx(struct ieee80211_local *local, struct sk_buff *skb)
{ {
local->ops->tx(&local->hw, skb); local->ops->tx(&local->hw, skb);
@ -421,6 +431,7 @@ static inline void drv_sta_notify(struct ieee80211_local *local,
enum sta_notify_cmd cmd, enum sta_notify_cmd cmd,
struct ieee80211_sta *sta) struct ieee80211_sta *sta)
{ {
sdata = get_bss_sdata(sdata);
check_sdata_in_driver(sdata); check_sdata_in_driver(sdata);
trace_drv_sta_notify(local, sdata, cmd, sta); trace_drv_sta_notify(local, sdata, cmd, sta);
@ -437,6 +448,7 @@ static inline int drv_sta_add(struct ieee80211_local *local,
might_sleep(); might_sleep();
sdata = get_bss_sdata(sdata);
check_sdata_in_driver(sdata); check_sdata_in_driver(sdata);
trace_drv_sta_add(local, sdata, sta); trace_drv_sta_add(local, sdata, sta);
@ -454,6 +466,7 @@ static inline void drv_sta_remove(struct ieee80211_local *local,
{ {
might_sleep(); might_sleep();
sdata = get_bss_sdata(sdata);
check_sdata_in_driver(sdata); check_sdata_in_driver(sdata);
trace_drv_sta_remove(local, sdata, sta); trace_drv_sta_remove(local, sdata, sta);
@ -547,6 +560,7 @@ static inline int drv_ampdu_action(struct ieee80211_local *local,
might_sleep(); might_sleep();
sdata = get_bss_sdata(sdata);
check_sdata_in_driver(sdata); check_sdata_in_driver(sdata);
trace_drv_ampdu_action(local, sdata, action, sta, tid, ssn, buf_size); trace_drv_ampdu_action(local, sdata, action, sta, tid, ssn, buf_size);

Some files were not shown because too many files have changed in this diff Show More