提交 d39aeaf2 编写于 作者: J John W. Linville

Merge branch 'master' of...

Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
...@@ -166,7 +166,9 @@ static int ath_ahb_probe(struct platform_device *pdev) ...@@ -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);
......
...@@ -27,15 +27,21 @@ ...@@ -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 @@ ...@@ -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,10 +99,9 @@ ath5k_ani_set_noise_immunity_level(struct ath5k_hw *ah, int level) ...@@ -91,10 +99,9 @@ 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).
*/ */
...@@ -117,10 +124,9 @@ 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) ...@@ -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) ...@@ -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,11 +203,14 @@ ath5k_ani_set_cck_weak_signal_detection(struct ath5k_hw *ah, bool on) ...@@ -200,11 +203,14 @@ 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.
* *
...@@ -290,9 +296,10 @@ ath5k_ani_raise_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as, ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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)
{ {
......
...@@ -41,11 +41,11 @@ enum ath5k_phy_error_code; ...@@ -41,11 +41,11 @@ enum ath5k_phy_error_code;
* *
* @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 {
...@@ -58,8 +58,22 @@ enum ath5k_ani_mode { ...@@ -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;
......
...@@ -27,8 +27,7 @@ ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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)
......
...@@ -80,6 +80,11 @@ static int modparam_fastchanswitch; ...@@ -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[] = { ...@@ -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,6 +725,8 @@ ath5k_txbuf_setup(struct ath5k_hw *ah, struct ath5k_buf *bf, ...@@ -721,6 +725,8 @@ ath5k_txbuf_setup(struct ath5k_hw *ah, struct ath5k_buf *bf,
if (ret) if (ret)
goto err_unmap; goto err_unmap;
/* Set up MRR descriptor */
if (ah->ah_capabilities.cap_has_mrr_support) {
memset(mrr_rate, 0, sizeof(mrr_rate)); memset(mrr_rate, 0, sizeof(mrr_rate));
memset(mrr_tries, 0, sizeof(mrr_tries)); memset(mrr_tries, 0, sizeof(mrr_tries));
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
...@@ -736,6 +742,7 @@ ath5k_txbuf_setup(struct ath5k_hw *ah, struct ath5k_buf *bf, ...@@ -736,6 +742,7 @@ ath5k_txbuf_setup(struct ath5k_hw *ah, struct ath5k_buf *bf,
mrr_rate[0], mrr_tries[0], mrr_rate[0], mrr_tries[0],
mrr_rate[1], mrr_tries[1], mrr_rate[1], mrr_tries[1],
mrr_rate[2], mrr_tries[2]); 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) ...@@ -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) ...@@ -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 ...@@ -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) ...@@ -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);
if (unlikely(status & AR5K_INT_FATAL)) {
/* /*
* Fatal errors are unrecoverable. * Fatal hw error -> Log and reset
* Typically these are caused by DMA errors. *
* Fatal errors are unrecoverable so we have to
* reset the card. These errors include bus and
* dma errors.
*/ */
if (unlikely(status & AR5K_INT_FATAL)) {
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);
} else if (unlikely(status & AR5K_INT_RXORN)) {
/* /*
* RX Overrun -> Count and reset if needed
*
* Receive buffers are full. Either the bus is busy or * Receive buffers are full. Either the bus is busy or
* the CPU is not fast enough to process all received * the CPU is not fast enough to process all received
* frames. * frames.
*/
} else if (unlikely(status & AR5K_INT_RXORN)) {
/*
* 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 * NB: the hardware should re-read the link when
* RXE bit is written, but it doesn't work at * RXE bit is written, but it doesn't work at
* least on older hardware revs. * 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) ...@@ -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) ...@@ -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)) {
/* Only full calibration for now */ ah->ah_cal_next_full = jiffies +
msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_FULL);
ah->ah_cal_mask |= AR5K_CALIBRATION_FULL; ah->ah_cal_mask |= AR5K_CALIBRATION_FULL;
ATH5K_DBG(ah, ATH5K_DEBUG_CALIBRATE, "channel %u/%x\n", ATH5K_DBG(ah, ATH5K_DEBUG_CALIBRATE,
ieee80211_frequency_to_channel(ah->curchan->center_freq), "running full calibration\n");
ah->curchan->hw_value);
if (ath5k_hw_gainf_calibrate(ah) == AR5K_RFGAIN_NEED_CHANGE) { if (ath5k_hw_gainf_calibrate(ah) == AR5K_RFGAIN_NEED_CHANGE) {
/* /*
* Rfgain is out of bounds, reset the chip * Rfgain is out of bounds, reset the chip
* to load new gain values. * to load new gain values.
*/ */
ATH5K_DBG(ah, ATH5K_DEBUG_RESET, "calibration, resetting\n"); ATH5K_DBG(ah, ATH5K_DEBUG_RESET,
"got new rfgain, resetting\n");
ieee80211_queue_work(ah->hw, &ah->reset_work); 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;
ATH5K_DBG(ah, ATH5K_DEBUG_CALIBRATE, "channel %u/%x\n",
ieee80211_frequency_to_channel(ah->curchan->center_freq),
ah->curchan->hw_value);
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! */
if (time_is_before_eq_jiffies(ah->ah_cal_next_nf)) {
ah->ah_cal_next_nf = jiffies +
msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_NF);
ath5k_hw_update_noise_floor(ah);
}
ah->ah_cal_mask &= ~AR5K_CALIBRATION_FULL; ah->ah_cal_mask &= ~AR5K_CALIBRATION_FULL;
} else if (ah->ah_cal_mask & AR5K_CALIBRATION_SHORT)
ah->ah_cal_mask &= ~AR5K_CALIBRATION_SHORT;
} }
...@@ -2407,8 +2492,8 @@ ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops) ...@@ -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,14 +2629,21 @@ int ath5k_start(struct ieee80211_hw *hw) ...@@ -2544,14 +2629,21 @@ 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;
if (!ath5k_modparam_no_hw_rfkill_switch)
ath5k_rfkill_hw_start(ah); ath5k_rfkill_hw_start(ah);
/* /*
...@@ -2585,7 +2677,6 @@ static void ath5k_stop_tasklets(struct ath5k_hw *ah) ...@@ -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,6 +2728,7 @@ void ath5k_stop(struct ieee80211_hw *hw) ...@@ -2637,6 +2728,7 @@ void ath5k_stop(struct ieee80211_hw *hw)
cancel_delayed_work_sync(&ah->tx_complete_work); cancel_delayed_work_sync(&ah->tx_complete_work);
if (!ath5k_modparam_no_hw_rfkill_switch)
ath5k_rfkill_hw_stop(ah); ath5k_rfkill_hw_stop(ah);
} }
...@@ -2689,9 +2781,24 @@ ath5k_reset(struct ath5k_hw *ah, struct ieee80211_channel *chan, ...@@ -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) ...@@ -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) ...@@ -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);
......
...@@ -85,12 +85,19 @@ int ath5k_hw_set_capabilities(struct ath5k_hw *ah) ...@@ -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;
/* Override 2GHz modes on SoCs that need it
* NOTE: cap_needs_2GHz_ovr gets set from
* ath_ahb_probe */
if (!caps->cap_needs_2GHz_ovr) {
if (AR5K_EEPROM_HDR_11B(ee_header)) if (AR5K_EEPROM_HDR_11B(ee_header))
__set_bit(AR5K_MODE_11B, caps->cap_mode); __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) ...@@ -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;
} }
......
...@@ -26,19 +26,60 @@ ...@@ -26,19 +26,60 @@
#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,
unsigned int pkt_len, unsigned int hdr_len,
int padsize,
enum ath5k_pkt_type type, enum ath5k_pkt_type type,
unsigned int tx_power, unsigned int tx_rate0, unsigned int tx_tries0, unsigned int tx_power,
unsigned int key_index, unsigned int antenna_mode, unsigned int flags, 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) unsigned int rtscts_rate, unsigned int rtscts_duration)
{ {
u32 frame_type; u32 frame_type;
...@@ -172,17 +213,40 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, ...@@ -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,
struct ath5k_desc *desc,
unsigned int pkt_len, unsigned int hdr_len,
int padsize, int padsize,
enum ath5k_pkt_type type, unsigned int tx_power, unsigned int tx_rate0, enum ath5k_pkt_type type,
unsigned int tx_tries0, unsigned int key_index, unsigned int tx_power,
unsigned int antenna_mode, unsigned int flags, unsigned int tx_rate0, unsigned int tx_tries0,
unsigned int rtscts_rate, unsigned int key_index,
unsigned int rtscts_duration) 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, ...@@ -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, ...@@ -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, ...@@ -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,10 +550,16 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, ...@@ -460,10 +550,16 @@ 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
ath5k_hw_setup_rx_desc(struct ath5k_hw *ah,
struct ath5k_desc *desc,
u32 size, unsigned int flags) 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, ...@@ -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,10 +681,20 @@ static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah, ...@@ -574,10 +681,20 @@ 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
ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah,
struct ath5k_desc *desc, struct ath5k_desc *desc,
struct ath5k_rx_status *rs) struct ath5k_rx_status *rs)
{ {
...@@ -646,10 +763,16 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah, ...@@ -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;
......
...@@ -20,25 +20,30 @@ ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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;
......
...@@ -20,16 +20,13 @@ ...@@ -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 @@ ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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);
sisr1 = ath5k_hw_reg_read(ah, AR5K_SISR1);
sisr2 = ath5k_hw_reg_read(ah, AR5K_SISR2);
sisr3 = ath5k_hw_reg_read(ah, AR5K_SISR3);
sisr4 = ath5k_hw_reg_read(ah, AR5K_SISR4);
/* /*
* Get abstract interrupt mask (driver-compatible) * 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.
*/ */
*interrupt_mask = (data & AR5K_INT_COMMON) & ah->ah_imr;
if (ah->ah_version != AR5K_AR5210) { pisr_clear = pisr & ~AR5K_ISR_BITS_FROM_SISRS;
u32 sisr2 = ath5k_hw_reg_read(ah, AR5K_RAC_SISR2);
/*HIU = Host Interface Unit (PCI etc)*/ /*
if (unlikely(data & (AR5K_ISR_HIUERR))) * Write to clear them...
*interrupt_mask |= AR5K_INT_FATAL; * 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);
/*Beacon Not Ready*/ /*
if (unlikely(data & (AR5K_ISR_BNR))) * Filter out the non-common bits from the interrupt
*interrupt_mask |= AR5K_INT_BNR; * status.
*/
*interrupt_mask = (pisr & AR5K_INT_COMMON) & ah->ah_imr;
if (unlikely(sisr2 & (AR5K_SISR2_SSERR |
AR5K_SISR2_DPERR |
AR5K_SISR2_MCABT)))
*interrupt_mask |= AR5K_INT_FATAL;
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) ...@@ -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) { /* HIU = Host Interface Unit (PCI etc)
* Can be one of MCABT, SSERR, DPERR from SISR2 */
if (unlikely(pisr & (AR5K_ISR_HIUERR)))
*interrupt_mask |= AR5K_INT_FATAL;
/*Beacon Not Ready*/
if (unlikely(pisr & (AR5K_ISR_BNR)))
*interrupt_mask |= AR5K_INT_BNR;
/* A queue got CBR overrun */
if (unlikely(pisr & (AR5K_ISR_QCBRORN))) {
*interrupt_mask |= AR5K_INT_QCBRORN; *interrupt_mask |= AR5K_INT_QCBRORN;
ah->ah_txq_isr |= AR5K_REG_MS( ah->ah_txq_isr_qcborn |= AR5K_REG_MS(sisr3,
ath5k_hw_reg_read(ah, AR5K_RAC_SISR3),
AR5K_SISR3_QCBRORN); AR5K_SISR3_QCBRORN);
} }
if (data & AR5K_ISR_QCBRURN) {
/* A queue got CBR underrun */
if (unlikely(pisr & (AR5K_ISR_QCBRURN))) {
*interrupt_mask |= AR5K_INT_QCBRURN; *interrupt_mask |= AR5K_INT_QCBRURN;
ah->ah_txq_isr |= AR5K_REG_MS( ah->ah_txq_isr_qcburn |= AR5K_REG_MS(sisr3,
ath5k_hw_reg_read(ah, AR5K_RAC_SISR3),
AR5K_SISR3_QCBRURN); AR5K_SISR3_QCBRURN);
} }
if (data & AR5K_ISR_QTRIG) {
/* A queue got triggered */
if (unlikely(pisr & (AR5K_ISR_QTRIG))) {
*interrupt_mask |= AR5K_INT_QTRIG; *interrupt_mask |= AR5K_INT_QTRIG;
ah->ah_txq_isr |= AR5K_REG_MS( ah->ah_txq_isr_qtrig |= AR5K_REG_MS(sisr4,
ath5k_hw_reg_read(ah, AR5K_RAC_SISR4),
AR5K_SISR4_QTRIG); AR5K_SISR4_QTRIG);
} }
if (data & AR5K_ISR_TXOK) data = pisr;
ah->ah_txq_isr |= AR5K_REG_MS(
ath5k_hw_reg_read(ah, AR5K_RAC_SISR0),
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;
/*
* 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;
*/
} }
/* /*
...@@ -661,8 +732,7 @@ int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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;
......
...@@ -24,10 +24,33 @@ ...@@ -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
*/
/**
* 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) 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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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;
......
...@@ -23,24 +23,27 @@ ...@@ -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[] = { ...@@ -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[] = { ...@@ -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[] = { ...@@ -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[] = { ...@@ -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[] = { ...@@ -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[] = { ...@@ -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[] = { ...@@ -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[] = { ...@@ -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[] = { ...@@ -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, ...@@ -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, ...@@ -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
......
...@@ -98,7 +98,7 @@ ath5k_pci_eeprom_read(struct ath_common *common, u32 offset, u16 *data) ...@@ -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;
......
...@@ -30,11 +30,47 @@ ...@@ -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[] = ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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);
......
...@@ -280,6 +280,10 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 */
......
...@@ -18,7 +18,9 @@ ...@@ -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 @@ ...@@ -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,
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册