提交 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,12 +99,11 @@ ath5k_ani_set_noise_immunity_level(struct ath5k_hw *ah, int level) ...@@ -91,12 +99,11 @@ ath5k_ani_set_noise_immunity_level(struct ath5k_hw *ah, int level)
ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_ANI, "new level %d", level); ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_ANI, "new level %d", level);
} }
/** /**
* ath5k_ani_set_spur_immunity_level() - Set spur immunity level * ath5k_ani_set_spur_immunity_level() - Set spur immunity level
* * @ah: The &struct ath5k_hw
* @level: level between 0 and @max_spur_level (the maximum level is dependent * @level: level between 0 and @max_spur_level (the maximum level is dependent
* on the chip revision). * on the chip revision).
*/ */
void void
ath5k_ani_set_spur_immunity_level(struct ath5k_hw *ah, int level) ath5k_ani_set_spur_immunity_level(struct ath5k_hw *ah, int level)
...@@ -117,10 +124,9 @@ ath5k_ani_set_spur_immunity_level(struct ath5k_hw *ah, int level) ...@@ -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,13 +203,16 @@ ath5k_ani_set_cck_weak_signal_detection(struct ath5k_hw *ah, bool on) ...@@ -200,13 +203,16 @@ ath5k_ani_set_cck_weak_signal_detection(struct ath5k_hw *ah, bool on)
} }
/*** ANI algorithm ***/ /***************\
* ANI algorithm *
\***************/
/** /**
* ath5k_ani_raise_immunity() - Increase noise immunity * ath5k_ani_raise_immunity() - Increase noise immunity
* * @ah: The &struct ath5k_hw
* @as: The &struct ath5k_ani_state
* @ofdm_trigger: If this is true we are called because of too many OFDM errors, * @ofdm_trigger: If this is true we are called because of too many OFDM errors,
* the algorithm will tune more parameters then. * the algorithm will tune more parameters then.
* *
* Try to raise noise immunity (=decrease sensitivity) in several steps * Try to raise noise immunity (=decrease sensitivity) in several steps
* depending on the average RSSI of the beacons we received. * depending on the average RSSI of the beacons we received.
...@@ -290,9 +296,10 @@ ath5k_ani_raise_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as, ...@@ -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)
{ {
......
...@@ -40,13 +40,13 @@ enum ath5k_phy_error_code; ...@@ -40,13 +40,13 @@ enum ath5k_phy_error_code;
* enum ath5k_ani_mode - mode for ANI / noise sensitivity * enum ath5k_ani_mode - mode for ANI / noise sensitivity
* *
* @ATH5K_ANI_MODE_OFF: Turn ANI off. This can be useful to just stop the ANI * @ATH5K_ANI_MODE_OFF: Turn ANI off. This can be useful to just stop the ANI
* algorithm after it has been on auto mode. * algorithm after it has been on auto mode.
* ATH5K_ANI_MODE_MANUAL_LOW: Manually set all immunity parameters to low, * @ATH5K_ANI_MODE_MANUAL_LOW: Manually set all immunity parameters to low,
* maximizing sensitivity. ANI will not run. * maximizing sensitivity. ANI will not run.
* ATH5K_ANI_MODE_MANUAL_HIGH: Manually set all immunity parameters to high, * @ATH5K_ANI_MODE_MANUAL_HIGH: Manually set all immunity parameters to high,
* minimizing sensitivity. ANI will not run. * minimizing sensitivity. ANI will not run.
* ATH5K_ANI_MODE_AUTO: Automatically control immunity parameters based on the * @ATH5K_ANI_MODE_AUTO: Automatically control immunity parameters based on the
* amount of OFDM and CCK frame errors (default). * amount of OFDM and CCK frame errors (default).
*/ */
enum ath5k_ani_mode { enum ath5k_ani_mode {
ATH5K_ANI_MODE_OFF = 0, ATH5K_ANI_MODE_OFF = 0,
...@@ -58,8 +58,22 @@ enum ath5k_ani_mode { ...@@ -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,21 +725,24 @@ ath5k_txbuf_setup(struct ath5k_hw *ah, struct ath5k_buf *bf, ...@@ -721,21 +725,24 @@ ath5k_txbuf_setup(struct ath5k_hw *ah, struct ath5k_buf *bf,
if (ret) if (ret)
goto err_unmap; goto err_unmap;
memset(mrr_rate, 0, sizeof(mrr_rate)); /* Set up MRR descriptor */
memset(mrr_tries, 0, sizeof(mrr_tries)); if (ah->ah_capabilities.cap_has_mrr_support) {
for (i = 0; i < 3; i++) { memset(mrr_rate, 0, sizeof(mrr_rate));
rate = ieee80211_get_alt_retry_rate(ah->hw, info, i); memset(mrr_tries, 0, sizeof(mrr_tries));
if (!rate) for (i = 0; i < 3; i++) {
break; rate = ieee80211_get_alt_retry_rate(ah->hw, info, i);
if (!rate)
break;
mrr_rate[i] = rate->hw_value; mrr_rate[i] = rate->hw_value;
mrr_tries[i] = info->control.rates[i + 1].count; mrr_tries[i] = info->control.rates[i + 1].count;
} }
ath5k_hw_setup_mrr_tx_desc(ah, ds, ath5k_hw_setup_mrr_tx_desc(ah, ds,
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);
/*
* Fatal hw error -> Log and reset
*
* Fatal errors are unrecoverable so we have to
* reset the card. These errors include bus and
* dma errors.
*/
if (unlikely(status & AR5K_INT_FATAL)) { if (unlikely(status & AR5K_INT_FATAL)) {
/*
* Fatal errors are unrecoverable.
* Typically these are caused by DMA errors.
*/
ATH5K_DBG(ah, ATH5K_DEBUG_RESET, ATH5K_DBG(ah, ATH5K_DEBUG_RESET,
"fatal int, resetting\n"); "fatal int, resetting\n");
ieee80211_queue_work(ah->hw, &ah->reset_work); ieee80211_queue_work(ah->hw, &ah->reset_work);
/*
* RX Overrun -> Count and reset if needed
*
* Receive buffers are full. Either the bus is busy or
* the CPU is not fast enough to process all received
* frames.
*/
} else if (unlikely(status & AR5K_INT_RXORN)) { } else if (unlikely(status & AR5K_INT_RXORN)) {
/* /*
* Receive buffers are full. Either the bus is busy or
* the CPU is not fast enough to process all received
* frames.
* Older chipsets need a reset to come out of this * Older chipsets need a reset to come out of this
* condition, but we treat it as RX for newer chips. * condition, but we treat it as RX for newer chips.
* We don't know exactly which versions need a reset - * We don't know exactly which versions need a reset
* this guess is copied from the HAL. * this guess is copied from the HAL.
*/ */
ah->stats.rxorn_intr++; ah->stats.rxorn_intr++;
if (ah->ah_mac_srev < AR5K_SREV_AR5212) { if (ah->ah_mac_srev < AR5K_SREV_AR5212) {
ATH5K_DBG(ah, ATH5K_DEBUG_RESET, ATH5K_DBG(ah, ATH5K_DEBUG_RESET,
"rx overrun, resetting\n"); "rx overrun, resetting\n");
ieee80211_queue_work(ah->hw, &ah->reset_work); ieee80211_queue_work(ah->hw, &ah->reset_work);
} else } else
ath5k_schedule_rx(ah); ath5k_schedule_rx(ah);
} else { } else {
/* Software Beacon Alert -> Schedule beacon tasklet */
if (status & AR5K_INT_SWBA) if (status & AR5K_INT_SWBA)
tasklet_hi_schedule(&ah->beacontq); tasklet_hi_schedule(&ah->beacontq);
if (status & AR5K_INT_RXEOL) { /*
/* * No more RX descriptors -> Just count
* NB: the hardware should re-read the link when *
* RXE bit is written, but it doesn't work at * NB: the hardware should re-read the link when
* least on older hardware revs. * RXE bit is written, but it doesn't work at
*/ * least on older hardware revs.
*/
if (status & AR5K_INT_RXEOL)
ah->stats.rxeol_intr++; ah->stats.rxeol_intr++;
}
if (status & AR5K_INT_TXURN) {
/* bump tx trigger level */ /* TX Underrun -> Bump tx trigger level */
if (status & AR5K_INT_TXURN)
ath5k_hw_update_tx_triglevel(ah, true); ath5k_hw_update_tx_triglevel(ah, true);
}
/* RX -> Schedule rx tasklet */
if (status & (AR5K_INT_RXOK | AR5K_INT_RXERR)) if (status & (AR5K_INT_RXOK | AR5K_INT_RXERR))
ath5k_schedule_rx(ah); ath5k_schedule_rx(ah);
if (status & (AR5K_INT_TXOK | AR5K_INT_TXDESC
| AR5K_INT_TXERR | AR5K_INT_TXEOL)) /* TX -> Schedule tx tasklet */
if (status & (AR5K_INT_TXOK
| AR5K_INT_TXDESC
| AR5K_INT_TXERR
| AR5K_INT_TXEOL))
ath5k_schedule_tx(ah); ath5k_schedule_tx(ah);
if (status & AR5K_INT_BMISS) {
/* TODO */ /* Missed beacon -> TODO
} if (status & AR5K_INT_BMISS)
*/
/* MIB event -> Update counters and notify ANI */
if (status & AR5K_INT_MIB) { if (status & AR5K_INT_MIB) {
ah->stats.mib_intr++; ah->stats.mib_intr++;
ath5k_hw_update_mib_counters(ah); ath5k_hw_update_mib_counters(ah);
ath5k_ani_mib_intr(ah); ath5k_ani_mib_intr(ah);
} }
/* GPIO -> Notify RFKill layer */
if (status & AR5K_INT_GPIO) if (status & AR5K_INT_GPIO)
tasklet_schedule(&ah->rf_kill.toggleq); tasklet_schedule(&ah->rf_kill.toggleq);
...@@ -2222,12 +2283,19 @@ ath5k_intr(int irq, void *dev_id) ...@@ -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)) {
ah->ah_cal_next_full = jiffies +
msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_FULL);
ah->ah_cal_mask |= AR5K_CALIBRATION_FULL;
ATH5K_DBG(ah, ATH5K_DEBUG_CALIBRATE,
"running full calibration\n");
if (ath5k_hw_gainf_calibrate(ah) == AR5K_RFGAIN_NEED_CHANGE) {
/*
* Rfgain is out of bounds, reset the chip
* to load new gain values.
*/
ATH5K_DBG(ah, ATH5K_DEBUG_RESET,
"got new rfgain, resetting\n");
ieee80211_queue_work(ah->hw, &ah->reset_work);
}
/* TODO: On full calibration we should stop TX here,
* so that it doesn't interfere (mostly due to gain_f
* calibration that messes with tx packets -see phy.c).
*
* NOTE: Stopping the queues from above is not enough
* to stop TX but saves us from disconecting (at least
* we don't lose packets). */
ieee80211_stop_queues(ah->hw);
} else
ah->ah_cal_mask |= AR5K_CALIBRATION_SHORT;
/* Only full calibration for now */
ah->ah_cal_mask |= AR5K_CALIBRATION_FULL;
ATH5K_DBG(ah, ATH5K_DEBUG_CALIBRATE, "channel %u/%x\n", ATH5K_DBG(ah, ATH5K_DEBUG_CALIBRATE, "channel %u/%x\n",
ieee80211_frequency_to_channel(ah->curchan->center_freq), ieee80211_frequency_to_channel(ah->curchan->center_freq),
ah->curchan->hw_value); ah->curchan->hw_value);
if (ath5k_hw_gainf_calibrate(ah) == AR5K_RFGAIN_NEED_CHANGE) {
/*
* Rfgain is out of bounds, reset the chip
* to load new gain values.
*/
ATH5K_DBG(ah, ATH5K_DEBUG_RESET, "calibration, resetting\n");
ieee80211_queue_work(ah->hw, &ah->reset_work);
}
if (ath5k_hw_phy_calibrate(ah, ah->curchan)) if (ath5k_hw_phy_calibrate(ah, ah->curchan))
ATH5K_ERR(ah, "calibration of channel %u failed\n", ATH5K_ERR(ah, "calibration of channel %u failed\n",
ieee80211_frequency_to_channel( ieee80211_frequency_to_channel(
ah->curchan->center_freq)); ah->curchan->center_freq));
/* Noise floor calibration interrupts rx/tx path while I/Q calibration /* Clear calibration flags */
* doesn't. if (ah->ah_cal_mask & AR5K_CALIBRATION_FULL) {
* TODO: We should stop TX here, so that it doesn't interfere. ieee80211_wake_queues(ah->hw);
* Note that stopping the queues is not enough to stop TX! */ ah->ah_cal_mask &= ~AR5K_CALIBRATION_FULL;
if (time_is_before_eq_jiffies(ah->ah_cal_next_nf)) { } else if (ah->ah_cal_mask & AR5K_CALIBRATION_SHORT)
ah->ah_cal_next_nf = jiffies + ah->ah_cal_mask &= ~AR5K_CALIBRATION_SHORT;
msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_NF);
ath5k_hw_update_noise_floor(ah);
}
ah->ah_cal_mask &= ~AR5K_CALIBRATION_FULL;
} }
...@@ -2407,8 +2492,8 @@ ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops) ...@@ -2407,8 +2492,8 @@ ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops)
if (ret) if (ret)
goto err_irq; goto err_irq;
/* set up multi-rate retry capabilities */ /* Set up multi-rate retry capabilities */
if (ah->ah_version == AR5K_AR5212) { if (ah->ah_capabilities.cap_has_mrr_support) {
hw->max_rates = 4; hw->max_rates = 4;
hw->max_rate_tries = max(AR5K_INIT_RETRY_SHORT, hw->max_rate_tries = max(AR5K_INIT_RETRY_SHORT,
AR5K_INIT_RETRY_LONG); AR5K_INIT_RETRY_LONG);
...@@ -2544,15 +2629,22 @@ int ath5k_start(struct ieee80211_hw *hw) ...@@ -2544,15 +2629,22 @@ int ath5k_start(struct ieee80211_hw *hw)
* and then setup of the interrupt mask. * and then setup of the interrupt mask.
*/ */
ah->curchan = ah->hw->conf.channel; ah->curchan = ah->hw->conf.channel;
ah->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL | ah->imask = AR5K_INT_RXOK
AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL | | AR5K_INT_RXERR
AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_MIB; | AR5K_INT_RXEOL
| AR5K_INT_RXORN
| AR5K_INT_TXDESC
| AR5K_INT_TXEOL
| AR5K_INT_FATAL
| AR5K_INT_GLOBAL
| AR5K_INT_MIB;
ret = ath5k_reset(ah, NULL, false); ret = ath5k_reset(ah, NULL, false);
if (ret) if (ret)
goto done; goto done;
ath5k_rfkill_hw_start(ah); if (!ath5k_modparam_no_hw_rfkill_switch)
ath5k_rfkill_hw_start(ah);
/* /*
* Reset the key cache since some parts do not reset the * Reset the key cache since some parts do not reset the
...@@ -2585,7 +2677,6 @@ static void ath5k_stop_tasklets(struct ath5k_hw *ah) ...@@ -2585,7 +2677,6 @@ static void ath5k_stop_tasklets(struct ath5k_hw *ah)
ah->tx_pending = false; ah->tx_pending = false;
tasklet_kill(&ah->rxtq); tasklet_kill(&ah->rxtq);
tasklet_kill(&ah->txtq); tasklet_kill(&ah->txtq);
tasklet_kill(&ah->calib);
tasklet_kill(&ah->beacontq); tasklet_kill(&ah->beacontq);
tasklet_kill(&ah->ani_tasklet); tasklet_kill(&ah->ani_tasklet);
} }
...@@ -2637,7 +2728,8 @@ void ath5k_stop(struct ieee80211_hw *hw) ...@@ -2637,7 +2728,8 @@ void ath5k_stop(struct ieee80211_hw *hw)
cancel_delayed_work_sync(&ah->tx_complete_work); cancel_delayed_work_sync(&ah->tx_complete_work);
ath5k_rfkill_hw_stop(ah); if (!ath5k_modparam_no_hw_rfkill_switch)
ath5k_rfkill_hw_stop(ah);
} }
/* /*
...@@ -2689,9 +2781,24 @@ ath5k_reset(struct ath5k_hw *ah, struct ieee80211_channel *chan, ...@@ -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;
if (AR5K_EEPROM_HDR_11B(ee_header)) /* Override 2GHz modes on SoCs that need it
__set_bit(AR5K_MODE_11B, caps->cap_mode); * NOTE: cap_needs_2GHz_ovr gets set from
* ath_ahb_probe */
if (AR5K_EEPROM_HDR_11G(ee_header) && if (!caps->cap_needs_2GHz_ovr) {
ah->ah_version != AR5K_AR5211) if (AR5K_EEPROM_HDR_11B(ee_header))
__set_bit(AR5K_MODE_11G, caps->cap_mode); __set_bit(AR5K_MODE_11B,
caps->cap_mode);
if (AR5K_EEPROM_HDR_11G(ee_header) &&
ah->ah_version != AR5K_AR5211)
__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,20 +26,61 @@ ...@@ -26,20 +26,61 @@
#include "debug.h" #include "debug.h"
/**
* DOC: Hardware descriptor functions
*
* Here we handle the processing of the low-level hw descriptors
* that hw reads and writes via DMA for each TX and RX attempt (that means
* we can also have descriptors for failed TX/RX tries). We have two kind of
* descriptors for RX and TX, control descriptors tell the hw how to send or
* receive a packet where to read/write it from/to etc and status descriptors
* that contain information about how the packet was sent or received (errors
* included).
*
* Descriptor format is not exactly the same for each MAC chip version so we
* have function pointers on &struct ath5k_hw we initialize at runtime based on
* the chip used.
*/
/************************\ /************************\
* TX Control descriptors * * TX Control descriptors *
\************************/ \************************/
/* /**
* Initialize the 2-word tx control descriptor on 5210/5211 * ath5k_hw_setup_2word_tx_desc() - Initialize a 2-word tx control descriptor
* @ah: The &struct ath5k_hw
* @desc: The &struct ath5k_desc
* @pkt_len: Frame length in bytes
* @hdr_len: Header length in bytes (only used on AR5210)
* @padsize: Any padding we've added to the frame length
* @type: One of enum ath5k_pkt_type
* @tx_power: Tx power in 0.5dB steps
* @tx_rate0: HW idx for transmission rate
* @tx_tries0: Max number of retransmissions
* @key_index: Index on key table to use for encryption
* @antenna_mode: Which antenna to use (0 for auto)
* @flags: One of AR5K_TXDESC_* flags (desc.h)
* @rtscts_rate: HW idx for RTS/CTS transmission rate
* @rtscts_duration: What to put on duration field on the header of RTS/CTS
*
* Internal function to initialize a 2-Word TX control descriptor
* found on AR5210 and AR5211 MACs chips.
*
* Returns 0 on success or -EINVAL on false input
*/ */
static int static int
ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah,
unsigned int pkt_len, unsigned int hdr_len, int padsize, struct ath5k_desc *desc,
enum ath5k_pkt_type type, unsigned int pkt_len, unsigned int hdr_len,
unsigned int tx_power, unsigned int tx_rate0, unsigned int tx_tries0, int padsize,
unsigned int key_index, unsigned int antenna_mode, unsigned int flags, enum ath5k_pkt_type type,
unsigned int rtscts_rate, unsigned int rtscts_duration) unsigned int tx_power,
unsigned int tx_rate0, unsigned int tx_tries0,
unsigned int key_index,
unsigned int antenna_mode,
unsigned int flags,
unsigned int rtscts_rate, unsigned int rtscts_duration)
{ {
u32 frame_type; u32 frame_type;
struct ath5k_hw_2w_tx_ctl *tx_ctl; struct ath5k_hw_2w_tx_ctl *tx_ctl;
...@@ -172,17 +213,40 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, ...@@ -172,17 +213,40 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
return 0; return 0;
} }
/* /**
* Initialize the 4-word tx control descriptor on 5212 * ath5k_hw_setup_4word_tx_desc() - Initialize a 4-word tx control descriptor
* @ah: The &struct ath5k_hw
* @desc: The &struct ath5k_desc
* @pkt_len: Frame length in bytes
* @hdr_len: Header length in bytes (only used on AR5210)
* @padsize: Any padding we've added to the frame length
* @type: One of enum ath5k_pkt_type
* @tx_power: Tx power in 0.5dB steps
* @tx_rate0: HW idx for transmission rate
* @tx_tries0: Max number of retransmissions
* @key_index: Index on key table to use for encryption
* @antenna_mode: Which antenna to use (0 for auto)
* @flags: One of AR5K_TXDESC_* flags (desc.h)
* @rtscts_rate: HW idx for RTS/CTS transmission rate
* @rtscts_duration: What to put on duration field on the header of RTS/CTS
*
* Internal function to initialize a 4-Word TX control descriptor
* found on AR5212 and later MACs chips.
*
* Returns 0 on success or -EINVAL on false input
*/ */
static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, static int
struct ath5k_desc *desc, unsigned int pkt_len, unsigned int hdr_len, ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
int padsize, struct ath5k_desc *desc,
enum ath5k_pkt_type type, unsigned int tx_power, unsigned int tx_rate0, unsigned int pkt_len, unsigned int hdr_len,
unsigned int tx_tries0, unsigned int key_index, int padsize,
unsigned int antenna_mode, unsigned int flags, enum ath5k_pkt_type type,
unsigned int rtscts_rate, unsigned int tx_power,
unsigned int rtscts_duration) unsigned int tx_rate0, unsigned int tx_tries0,
unsigned int key_index,
unsigned int antenna_mode,
unsigned int flags,
unsigned int rtscts_rate, unsigned int rtscts_duration)
{ {
struct ath5k_hw_4w_tx_ctl *tx_ctl; struct ath5k_hw_4w_tx_ctl *tx_ctl;
unsigned int frame_len; unsigned int frame_len;
...@@ -292,13 +356,29 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, ...@@ -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,11 +550,17 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, ...@@ -460,11 +550,17 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah,
* RX Descriptors * * RX Descriptors *
\****************/ \****************/
/* /**
* Initialize an rx control descriptor * ath5k_hw_setup_rx_desc() - Initialize an rx control descriptor
* @ah: The &struct ath5k_hw
* @desc: The &struct ath5k_desc
* @size: RX buffer length in bytes
* @flags: One of AR5K_RXDESC_* flags
*/ */
int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, int
u32 size, unsigned int flags) ath5k_hw_setup_rx_desc(struct ath5k_hw *ah,
struct ath5k_desc *desc,
u32 size, unsigned int flags)
{ {
struct ath5k_hw_rx_ctl *rx_ctl; struct ath5k_hw_rx_ctl *rx_ctl;
...@@ -491,11 +587,22 @@ int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, ...@@ -491,11 +587,22 @@ int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
return 0; return 0;
} }
/* /**
* Process the rx status descriptor on 5210/5211 * ath5k_hw_proc_5210_rx_status() - Process the rx status descriptor on 5210/1
* @ah: The &struct ath5k_hw
* @desc: The &struct ath5k_desc
* @rs: The &struct ath5k_rx_status
*
* Internal function used to process an RX status descriptor
* on AR5210/5211 MAC.
*
* Returns 0 on success or -EINPROGRESS in case we haven't received the who;e
* frame yet.
*/ */
static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah, static int
struct ath5k_desc *desc, struct ath5k_rx_status *rs) ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah,
struct ath5k_desc *desc,
struct ath5k_rx_status *rs)
{ {
struct ath5k_hw_rx_status *rx_status; struct ath5k_hw_rx_status *rx_status;
...@@ -574,12 +681,22 @@ static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah, ...@@ -574,12 +681,22 @@ static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah,
return 0; return 0;
} }
/* /**
* Process the rx status descriptor on 5212 * ath5k_hw_proc_5212_rx_status() - Process the rx status descriptor on 5212
* @ah: The &struct ath5k_hw
* @desc: The &struct ath5k_desc
* @rs: The &struct ath5k_rx_status
*
* Internal function used to process an RX status descriptor
* on AR5212 and later MAC.
*
* Returns 0 on success or -EINPROGRESS in case we haven't received the who;e
* frame yet.
*/ */
static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah, static int
struct ath5k_desc *desc, ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah,
struct ath5k_rx_status *rs) struct ath5k_desc *desc,
struct ath5k_rx_status *rs)
{ {
struct ath5k_hw_rx_status *rx_status; struct ath5k_hw_rx_status *rx_status;
u32 rxstat0, rxstat1; u32 rxstat0, rxstat1;
...@@ -646,10 +763,16 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah, ...@@ -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);
* Get abstract interrupt mask (driver-compatible) sisr1 = ath5k_hw_reg_read(ah, AR5K_SISR1);
*/ sisr2 = ath5k_hw_reg_read(ah, AR5K_SISR2);
*interrupt_mask = (data & AR5K_INT_COMMON) & ah->ah_imr; sisr3 = ath5k_hw_reg_read(ah, AR5K_SISR3);
sisr4 = ath5k_hw_reg_read(ah, AR5K_SISR4);
if (ah->ah_version != AR5K_AR5210) { /*
u32 sisr2 = ath5k_hw_reg_read(ah, AR5K_RAC_SISR2); * PISR holds the logical OR of interrupt bits
* from SISR registers:
*
* TXOK and TXDESC -> Logical OR of TXOK and TXDESC
* per-queue bits on SISR0
*
* TXERR and TXEOL -> Logical OR of TXERR and TXEOL
* per-queue bits on SISR1
*
* TXURN -> Logical OR of TXURN per-queue bits on SISR2
*
* HIUERR -> Logical OR of MCABT, SSERR and DPER bits on SISR2
*
* BCNMISC -> Logical OR of TIM, CAB_END, DTIM_SYNC
* BCN_TIMEOUT, CAB_TIMEOUT and DTIM
* (and TSFOOR ?) bits on SISR2
*
* QCBRORN and QCBRURN -> Logical OR of QCBRORN and
* QCBRURN per-queue bits on SISR3
* QTRIG -> Logical OR of QTRIG per-queue bits on SISR4
*
* If we clean these bits on PISR we 'll also clear all
* related bits from SISRs, e.g. if we write the TXOK bit on
* PISR we 'll clean all TXOK bits from SISR0 so if a new TXOK
* interrupt got fired for another queue while we were reading
* the interrupt registers and we write back the TXOK bit on
* PISR we 'll lose it. So make sure that we don't write back
* on PISR any bits that come from SISRs. Clearing them from
* SISRs will also clear PISR so no need to worry here.
*/
/*HIU = Host Interface Unit (PCI etc)*/ pisr_clear = pisr & ~AR5K_ISR_BITS_FROM_SISRS;
if (unlikely(data & (AR5K_ISR_HIUERR)))
*interrupt_mask |= AR5K_INT_FATAL;
/*Beacon Not Ready*/ /*
if (unlikely(data & (AR5K_ISR_BNR))) * Write to clear them...
*interrupt_mask |= AR5K_INT_BNR; * Note: This means that each bit we write back
* to the registers will get cleared, leaving the
* rest unaffected. So this won't affect new interrupts
* we didn't catch while reading/processing, we 'll get
* them next time get_isr gets called.
*/
ath5k_hw_reg_write(ah, sisr0, AR5K_SISR0);
ath5k_hw_reg_write(ah, sisr1, AR5K_SISR1);
ath5k_hw_reg_write(ah, sisr2, AR5K_SISR2);
ath5k_hw_reg_write(ah, sisr3, AR5K_SISR3);
ath5k_hw_reg_write(ah, sisr4, AR5K_SISR4);
ath5k_hw_reg_write(ah, pisr_clear, AR5K_PISR);
/* Flush previous write */
ath5k_hw_reg_read(ah, AR5K_PISR);
if (unlikely(sisr2 & (AR5K_SISR2_SSERR | /*
AR5K_SISR2_DPERR | * Filter out the non-common bits from the interrupt
AR5K_SISR2_MCABT))) * status.
*interrupt_mask |= AR5K_INT_FATAL; */
*interrupt_mask = (pisr & AR5K_INT_COMMON) & ah->ah_imr;
/* 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 (data & AR5K_ISR_TIM) 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);
......
...@@ -18,13 +18,17 @@ ...@@ -18,13 +18,17 @@
* *
*/ */
/* /**
* struct ath5k_ini_rfgain - RF Gain table
* @rfg_register: RF Gain register address
* @rfg_value: Register value for 5 and 2GHz
*
* Mode-specific RF Gain table (64bytes) for RF5111/5112 * Mode-specific RF Gain table (64bytes) for RF5111/5112
* (RF5110 only comes with AR5210 and only supports a/turbo a mode so initial * (RF5110 only comes with AR5210 and only supports a/turbo a mode so initial
* RF Gain values are included in AR5K_AR5210_INI) * RF Gain values are included in AR5K_AR5210_INI)
*/ */
struct ath5k_ini_rfgain { struct ath5k_ini_rfgain {
u16 rfg_register; /* RF Gain register address */ u16 rfg_register;
u32 rfg_value[2]; /* [freq (see below)] */ u32 rfg_value[2]; /* [freq (see below)] */
}; };
...@@ -455,18 +459,31 @@ static const struct ath5k_ini_rfgain rfgain_2425[] = { ...@@ -455,18 +459,31 @@ static const struct ath5k_ini_rfgain rfgain_2425[] = {
#define AR5K_GAIN_CHECK_ADJUST(_g) \ #define AR5K_GAIN_CHECK_ADJUST(_g) \
((_g)->g_current <= (_g)->g_low || (_g)->g_current >= (_g)->g_high) ((_g)->g_current <= (_g)->g_low || (_g)->g_current >= (_g)->g_high)
/**
* struct ath5k_gain_opt_step - An RF gain optimization step
* @gos_param: Set of parameters
* @gos_gain: Gain
*/
struct ath5k_gain_opt_step { struct ath5k_gain_opt_step {
s8 gos_param[AR5K_GAIN_CRN_MAX_FIX_BITS]; s8 gos_param[AR5K_GAIN_CRN_MAX_FIX_BITS];
s8 gos_gain; s8 gos_gain;
}; };
/**
* struct ath5k_gain_opt - RF Gain optimization ladder
* @go_default: The default step
* @go_steps_count: How many optimization steps
* @go_step: Array of &struct ath5k_gain_opt_step
*/
struct ath5k_gain_opt { struct ath5k_gain_opt {
u8 go_default; u8 go_default;
u8 go_steps_count; u8 go_steps_count;
const struct ath5k_gain_opt_step go_step[AR5K_GAIN_STEP_COUNT]; const struct ath5k_gain_opt_step go_step[AR5K_GAIN_STEP_COUNT];
}; };
/* /*
* RF5111
* Parameters on gos_param: * Parameters on gos_param:
* 1) Tx clip PHY register * 1) Tx clip PHY register
* 2) PWD 90 RF register * 2) PWD 90 RF register
...@@ -490,6 +507,7 @@ static const struct ath5k_gain_opt rfgain_opt_5111 = { ...@@ -490,6 +507,7 @@ static const struct ath5k_gain_opt rfgain_opt_5111 = {
}; };
/* /*
* RF5112
* Parameters on gos_param: * Parameters on gos_param:
* 1) Mixgain ovr RF register * 1) Mixgain ovr RF register
* 2) PWD 138 RF register * 2) PWD 138 RF register
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册