diff options
Diffstat (limited to 'drivers/net/wireless')
232 files changed, 12692 insertions, 8657 deletions
diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index 4596c33a7a69..c1d699fd5717 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -152,6 +152,7 @@ struct ath_common { struct ath_cycle_counters cc_survey; struct ath_regulatory regulatory; + struct ath_regulatory reg_world_copy; const struct ath_ops *ops; const struct ath_bus_ops *bus_ops; @@ -214,6 +215,10 @@ do { \ * @ATH_DBG_HWTIMER: hardware timer handling * @ATH_DBG_BTCOEX: bluetooth coexistance * @ATH_DBG_BSTUCK: stuck beacons + * @ATH_DBG_MCI: Message Coexistence Interface, a private protocol + * used exclusively for WLAN-BT coexistence starting from + * AR9462. + * @ATH_DBG_DFS: radar datection * @ATH_DBG_ANY: enable all debugging * * The debug level is used to control the amount and type of debugging output @@ -240,6 +245,7 @@ enum ATH_DEBUG { ATH_DBG_WMI = 0x00004000, ATH_DBG_BSTUCK = 0x00008000, ATH_DBG_MCI = 0x00010000, + ATH_DBG_DFS = 0x00020000, ATH_DBG_ANY = 0xffffffff }; diff --git a/drivers/net/wireless/ath/ath5k/ahb.c b/drivers/net/wireless/ath/ath5k/ahb.c index e5be7e701816..ee7ea572b065 100644 --- a/drivers/net/wireless/ath/ath5k/ahb.c +++ b/drivers/net/wireless/ath/ath5k/ahb.c @@ -166,7 +166,9 @@ static int ath_ahb_probe(struct platform_device *pdev) if (to_platform_device(ah->dev)->id == 0 && (bcfg->config->flags & (BD_WLAN0 | BD_WLAN1)) == (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); diff --git a/drivers/net/wireless/ath/ath5k/ani.c b/drivers/net/wireless/ath/ath5k/ani.c index bea90e6be70e..bf674161a217 100644 --- a/drivers/net/wireless/ath/ath5k/ani.c +++ b/drivers/net/wireless/ath/ath5k/ani.c @@ -27,15 +27,21 @@ * or reducing sensitivity as necessary. * * The parameters are: + * * - "noise immunity" + * * - "spur immunity" + * * - "firstep level" + * * - "OFDM weak signal detection" + * * - "CCK weak signal detection" * * 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 * parameters. + * * 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 * by setting a RX flag and then count every single PHY error. When a specified @@ -45,11 +51,13 @@ */ -/*** ANI parameter control ***/ +/***********************\ +* ANI parameter control * +\***********************/ /** * ath5k_ani_set_noise_immunity_level() - Set noise immunity level - * + * @ah: The &struct ath5k_hw * @level: level between 0 and @ATH5K_ANI_MAX_NOISE_IMM_LVL */ void @@ -91,12 +99,11 @@ ath5k_ani_set_noise_immunity_level(struct ath5k_hw *ah, int level) ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_ANI, "new level %d", level); } - /** * ath5k_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 - * on the chip revision). + * on the chip revision). */ void 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_ani_set_firstep_level() - Set "firstep" level - * + * @ah: The &struct ath5k_hw * @level: level between 0 and @ATH5K_ANI_MAX_FIRSTEP_LVL */ void @@ -140,11 +146,9 @@ ath5k_ani_set_firstep_level(struct ath5k_hw *ah, int level) ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_ANI, "new level %d", level); } - /** - * ath5k_ani_set_ofdm_weak_signal_detection() - Control OFDM weak signal - * detection - * + * ath5k_ani_set_ofdm_weak_signal_detection() - Set OFDM weak signal detection + * @ah: The &struct ath5k_hw * @on: turn on or off */ void @@ -182,10 +186,9 @@ ath5k_ani_set_ofdm_weak_signal_detection(struct ath5k_hw *ah, bool on) 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 */ void @@ -200,13 +203,16 @@ ath5k_ani_set_cck_weak_signal_detection(struct ath5k_hw *ah, bool on) } -/*** ANI algorithm ***/ +/***************\ +* ANI algorithm * +\***************/ /** * ath5k_ani_raise_immunity() - Increase noise immunity - * + * @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, - * the algorithm will tune more parameters then. + * the algorithm will tune more parameters then. * * Try to raise noise immunity (=decrease sensitivity) in several steps * depending on the average RSSI of the beacons we received. @@ -290,9 +296,10 @@ ath5k_ani_raise_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as, */ } - /** * ath5k_ani_lower_immunity() - Decrease noise immunity + * @ah: The &struct ath5k_hw + * @as: The &struct ath5k_ani_state * * Try to lower noise immunity (=increase sensitivity) in several steps * depending on the average RSSI of the beacons we received. @@ -352,9 +359,10 @@ ath5k_ani_lower_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as) } } - /** * ath5k_hw_ani_get_listen_time() - Update counters and return listening time + * @ah: The &struct ath5k_hw + * @as: The &struct ath5k_ani_state * * Return an approximation of the time spent "listening" in milliseconds (ms) * since the last call of this function. @@ -379,9 +387,10 @@ ath5k_hw_ani_get_listen_time(struct ath5k_hw *ah, struct ath5k_ani_state *as) return listen; } - /** * 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 * from a MIB interrupt and we want to make sure we don't get interrupted again. @@ -429,14 +438,14 @@ ath5k_ani_save_and_clear_phy_errors(struct ath5k_hw *ah, return 1; } - /** * 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". */ 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 */ as->last_ofdm_errors = as->ofdm_errors; @@ -448,9 +457,9 @@ ath5k_ani_period_restart(struct ath5k_hw *ah, struct ath5k_ani_state *as) as->listen_time = 0; } - /** * 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 * receive ("listen" time) and raise or lower immunity accordingly. @@ -492,7 +501,7 @@ ath5k_ani_calibration(struct ath5k_hw *ah) /* too many PHY errors - we have to raise immunity */ bool ofdm_flag = as->ofdm_errors > ofdm_high ? true : false; 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) { /* If more than 5 (TODO: why 5?) periods have passed and we got @@ -504,15 +513,18 @@ ath5k_ani_calibration(struct ath5k_hw *ah) if (as->ofdm_errors <= ofdm_low && as->cck_errors <= cck_low) 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 + * @ah: The &struct ath5k_hw * * Just read & reset the registers quickly, so they don't generate more * interrupts, save the counters and schedule the tasklet to decide whether @@ -549,9 +561,11 @@ ath5k_ani_mib_intr(struct ath5k_hw *ah) tasklet_schedule(&ah->ani_tasklet); } - /** - * 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 * on a frame-by-frame basis, instead of the interrupt. @@ -574,10 +588,13 @@ ath5k_ani_phy_error_report(struct ath5k_hw *ah, } -/*** INIT ***/ +/****************\ +* Initialization * +\****************/ /** * ath5k_enable_phy_err_counters() - Enable PHY error counters + * @ah: The &struct ath5k_hw * * Enable PHY error counters for OFDM and CCK timing errors. */ @@ -596,9 +613,9 @@ ath5k_enable_phy_err_counters(struct ath5k_hw *ah) ath5k_hw_reg_write(ah, 0, AR5K_CCK_FIL_CNT); } - /** * ath5k_disable_phy_err_counters() - Disable PHY error counters + * @ah: The &struct ath5k_hw * * Disable PHY error counters for OFDM and CCK timing errors. */ @@ -615,10 +632,10 @@ ath5k_disable_phy_err_counters(struct ath5k_hw *ah) ath5k_hw_reg_write(ah, 0, AR5K_CCK_FIL_CNT); } - /** * ath5k_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. */ @@ -695,10 +712,18 @@ ath5k_ani_init(struct ath5k_hw *ah, enum ath5k_ani_mode mode) } -/*** DEBUG ***/ +/**************\ +* Debug output * +\**************/ #ifdef CONFIG_ATH5K_DEBUG +/** + * ath5k_ani_print_counters() - Print ANI counters + * @ah: The &struct ath5k_hw + * + * Used for debugging ANI + */ void ath5k_ani_print_counters(struct ath5k_hw *ah) { diff --git a/drivers/net/wireless/ath/ath5k/ani.h b/drivers/net/wireless/ath/ath5k/ani.h index 7358b6c83c6c..21aa355460bb 100644 --- a/drivers/net/wireless/ath/ath5k/ani.h +++ b/drivers/net/wireless/ath/ath5k/ani.h @@ -40,13 +40,13 @@ enum ath5k_phy_error_code; * 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 - * algorithm after it has been on auto mode. - * ATH5K_ANI_MODE_MANUAL_LOW: Manually set all immunity parameters to low, - * maximizing sensitivity. ANI will not run. - * ATH5K_ANI_MODE_MANUAL_HIGH: Manually set all immunity parameters to high, - * minimizing sensitivity. ANI will not run. - * ATH5K_ANI_MODE_AUTO: Automatically control immunity parameters based on the - * amount of OFDM and CCK frame errors (default). + * algorithm after it has been on auto mode. + * @ATH5K_ANI_MODE_MANUAL_LOW: Manually set all immunity parameters to low, + * maximizing sensitivity. ANI will not run. + * @ATH5K_ANI_MODE_MANUAL_HIGH: Manually set all immunity parameters to high, + * minimizing sensitivity. ANI will not run. + * @ATH5K_ANI_MODE_AUTO: Automatically control immunity parameters based on the + * amount of OFDM and CCK frame errors (default). */ enum ath5k_ani_mode { ATH5K_ANI_MODE_OFF = 0, @@ -58,8 +58,22 @@ enum ath5k_ani_mode { /** * struct ath5k_ani_state - ANI state and associated counters - * - * @max_spur_level: the maximum spur level is chip dependent + * @ani_mode: One of enum ath5k_ani_mode + * @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 { enum ath5k_ani_mode ani_mode; diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index fecbcd9a4259..c2b2518c2ecd 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -187,10 +187,9 @@ #define AR5K_TUNE_MAX_TXPOWER 63 #define AR5K_TUNE_DEFAULT_TXPOWER 25 #define AR5K_TUNE_TPC_TXPOWER false -#define ATH5K_TUNE_CALIBRATION_INTERVAL_FULL 10000 /* 10 sec */ +#define ATH5K_TUNE_CALIBRATION_INTERVAL_FULL 60000 /* 60 sec */ +#define ATH5K_TUNE_CALIBRATION_INTERVAL_SHORT 10000 /* 10 sec */ #define ATH5K_TUNE_CALIBRATION_INTERVAL_ANI 1000 /* 1 sec */ -#define ATH5K_TUNE_CALIBRATION_INTERVAL_NF 60000 /* 60 sec */ - #define ATH5K_TX_COMPLETE_POLL_INT 3000 /* 3 sec */ #define AR5K_INIT_CARR_SENSE_EN 1 @@ -262,16 +261,34 @@ #define AR5K_AGC_SETTLING_TURBO 37 -/* GENERIC CHIPSET DEFINITIONS */ -/* MAC Chips */ +/*****************************\ +* GENERIC CHIPSET DEFINITIONS * +\*****************************/ + +/** + * enum ath5k_version - MAC Chips + * @AR5K_AR5210: AR5210 (Crete) + * @AR5K_AR5211: AR5211 (Oahu/Maui) + * @AR5K_AR5212: AR5212 (Venice) and newer + */ enum ath5k_version { AR5K_AR5210 = 0, AR5K_AR5211 = 1, AR5K_AR5212 = 2, }; -/* PHY Chips */ +/** + * enum ath5k_radio - PHY Chips + * @AR5K_RF5110: RF5110 (Fez) + * @AR5K_RF5111: RF5111 (Sombrero) + * @AR5K_RF5112: RF2112/5112(A) (Derby/Derby2) + * @AR5K_RF2413: RF2413/2414 (Griffin/Griffin-Lite) + * @AR5K_RF5413: RF5413/5414/5424 (Eagle/Condor) + * @AR5K_RF2316: RF2315/2316 (Cobra SoC) + * @AR5K_RF2317: RF2317 (Spider SoC) + * @AR5K_RF2425: RF2425/2417 (Swan/Nalla) + */ enum ath5k_radio { AR5K_RF5110 = 0, AR5K_RF5111 = 1, @@ -303,11 +320,11 @@ enum ath5k_radio { #define AR5K_SREV_AR5213A 0x59 /* Hainan */ #define AR5K_SREV_AR2413 0x78 /* Griffin lite */ #define AR5K_SREV_AR2414 0x70 /* Griffin */ -#define AR5K_SREV_AR2315_R6 0x86 /* AP51-Light */ -#define AR5K_SREV_AR2315_R7 0x87 /* AP51-Full */ +#define AR5K_SREV_AR2315_R6 0x86 /* AP51-Light */ +#define AR5K_SREV_AR2315_R7 0x87 /* AP51-Full */ #define AR5K_SREV_AR5424 0x90 /* Condor */ -#define AR5K_SREV_AR2317_R1 0x90 /* AP61-Light */ -#define AR5K_SREV_AR2317_R2 0x91 /* AP61-Full */ +#define AR5K_SREV_AR2317_R1 0x90 /* AP61-Light */ +#define AR5K_SREV_AR2317_R2 0x91 /* AP61-Full */ #define AR5K_SREV_AR5413 0xa4 /* Eagle lite */ #define AR5K_SREV_AR5414 0xa0 /* Eagle */ #define AR5K_SREV_AR2415 0xb0 /* Talon */ @@ -344,32 +361,40 @@ enum ath5k_radio { /* TODO add support to mac80211 for vendor-specific rates and modes */ -/* +/** + * DOC: Atheros XR + * * Some of this information is based on Documentation from: * * http://madwifi-project.org/wiki/ChipsetFeatures/SuperAG * - * Modulation for Atheros' eXtended Range - range enhancing extension that is - * supposed to double the distance an Atheros client device can keep a - * connection with an Atheros access point. This is achieved by increasing - * the receiver sensitivity up to, -105dBm, which is about 20dB above what - * the 802.11 specifications demand. In addition, new (proprietary) data rates - * are introduced: 3, 2, 1, 0.5 and 0.25 MBit/s. + * Atheros' eXtended Range - range enhancing extension is a modulation scheme + * that is supposed to double the link distance between an Atheros XR-enabled + * client device with an Atheros XR-enabled access point. This is achieved + * by increasing the receiver sensitivity up to, -105dBm, which is about 20dB + * above what the 802.11 specifications demand. In addition, new (proprietary) + * data rates are introduced: 3, 2, 1, 0.5 and 0.25 MBit/s. * * Please note that can you either use XR or TURBO but you cannot use both, * they are exclusive. * + * Also note that we do not plan to support XR mode at least for now. You can + * get a mode similar to XR by using 5MHz bwmode. */ -#define MODULATION_XR 0x00000200 -/* - * Modulation for Atheros' Turbo G and Turbo A, its supposed to provide a - * throughput transmission speed up to 40Mbit/s-60Mbit/s at a 108Mbit/s - * signaling rate achieved through the bonding of two 54Mbit/s 802.11g - * channels. To use this feature your Access Point must also support it. + + +/** + * DOC: Atheros SuperAG + * + * In addition to XR we have another modulation scheme called TURBO mode + * that is supposed to provide a throughput transmission speed up to 40Mbit/s + * -60Mbit/s at a 108Mbit/s signaling rate achieved through the bonding of two + * 54Mbit/s 802.11g channels. To use this feature both ends must support it. * There is also a distinction between "static" and "dynamic" turbo modes: * * - Static: is the dumb version: devices set to this mode stick to it until * the mode is turned off. + * * - Dynamic: is the intelligent version, the network decides itself if it * is ok to use turbo. As soon as traffic is detected on adjacent channels * (which would get used in turbo mode), or when a non-turbo station joins @@ -383,24 +408,39 @@ enum ath5k_radio { * * http://www.pcworld.com/article/id,113428-page,1/article.html * - * The channel bonding seems to be driver specific though. In addition to - * deciding what channels will be used, these "Turbo" modes are accomplished - * by also enabling the following features: + * The channel bonding seems to be driver specific though. + * + * In addition to TURBO modes we also have the following features for even + * greater speed-up: * * - Bursting: allows multiple frames to be sent at once, rather than pausing * after each frame. Bursting is a standards-compliant feature that can be * used with any Access Point. + * * - Fast frames: increases the amount of information that can be sent per * frame, also resulting in a reduction of transmission overhead. It is a * proprietary feature that needs to be supported by the Access Point. + * * - Compression: data frames are compressed in real time using a Lempel Ziv * algorithm. This is done transparently. Once this feature is enabled, * compression and decompression takes place inside the chipset, without * putting additional load on the host CPU. * + * As with XR we also don't plan to support SuperAG features for now. You can + * get a mode similar to TURBO by using 40MHz bwmode. */ -#define MODULATION_TURBO 0x00000080 + +/** + * enum ath5k_driver_mode - PHY operation mode + * @AR5K_MODE_11A: 802.11a + * @AR5K_MODE_11B: 802.11b + * @AR5K_MODE_11G: 801.11g + * @AR5K_MODE_MAX: Used for boundary checks + * + * Do not change the order here, we use these as + * array indices and it also maps EEPROM structures. + */ enum ath5k_driver_mode { AR5K_MODE_11A = 0, AR5K_MODE_11B = 1, @@ -408,30 +448,64 @@ enum ath5k_driver_mode { AR5K_MODE_MAX = 3 }; +/** + * enum ath5k_ant_mode - Antenna operation mode + * @AR5K_ANTMODE_DEFAULT: Default antenna setup + * @AR5K_ANTMODE_FIXED_A: Only antenna A is present + * @AR5K_ANTMODE_FIXED_B: Only antenna B is present + * @AR5K_ANTMODE_SINGLE_AP: STA locked on a single ap + * @AR5K_ANTMODE_SECTOR_AP: AP with tx antenna set on tx desc + * @AR5K_ANTMODE_SECTOR_STA: STA with tx antenna set on tx desc + * @AR5K_ANTMODE_DEBUG: Debug mode -A -> Rx, B-> Tx- + * @AR5K_ANTMODE_MAX: Used for boundary checks + * + * For more infos on antenna control check out phy.c + */ enum ath5k_ant_mode { - AR5K_ANTMODE_DEFAULT = 0, /* default antenna setup */ - AR5K_ANTMODE_FIXED_A = 1, /* only antenna A is present */ - AR5K_ANTMODE_FIXED_B = 2, /* only antenna B is present */ - AR5K_ANTMODE_SINGLE_AP = 3, /* sta locked on a single ap */ - AR5K_ANTMODE_SECTOR_AP = 4, /* AP with tx antenna set on tx desc */ - AR5K_ANTMODE_SECTOR_STA = 5, /* STA with tx antenna set on tx desc */ - AR5K_ANTMODE_DEBUG = 6, /* Debug mode -A -> Rx, B-> Tx- */ + AR5K_ANTMODE_DEFAULT = 0, + AR5K_ANTMODE_FIXED_A = 1, + AR5K_ANTMODE_FIXED_B = 2, + AR5K_ANTMODE_SINGLE_AP = 3, + AR5K_ANTMODE_SECTOR_AP = 4, + AR5K_ANTMODE_SECTOR_STA = 5, + AR5K_ANTMODE_DEBUG = 6, AR5K_ANTMODE_MAX, }; +/** + * enum ath5k_bw_mode - Bandwidth operation mode + * @AR5K_BWMODE_DEFAULT: 20MHz, default operation + * @AR5K_BWMODE_5MHZ: Quarter rate + * @AR5K_BWMODE_10MHZ: Half rate + * @AR5K_BWMODE_40MHZ: Turbo + */ enum ath5k_bw_mode { - AR5K_BWMODE_DEFAULT = 0, /* 20MHz, default operation */ - AR5K_BWMODE_5MHZ = 1, /* Quarter rate */ - AR5K_BWMODE_10MHZ = 2, /* Half rate */ - AR5K_BWMODE_40MHZ = 3 /* Turbo */ + AR5K_BWMODE_DEFAULT = 0, + AR5K_BWMODE_5MHZ = 1, + AR5K_BWMODE_10MHZ = 2, + AR5K_BWMODE_40MHZ = 3 }; + + /****************\ TX DEFINITIONS \****************/ -/* - * TX Status descriptor +/** + * struct ath5k_tx_status - TX Status descriptor + * @ts_seqnum: Sequence number + * @ts_tstamp: Timestamp + * @ts_status: Status code + * @ts_final_idx: Final transmission series index + * @ts_final_retry: Final retry count + * @ts_rssi: RSSI for received ACK + * @ts_shortretry: Short retry count + * @ts_virtcol: Virtual collision count + * @ts_antenna: Antenna used + * + * TX status descriptor gets filled by the hw + * on each transmission attempt. */ struct ath5k_tx_status { u16 ts_seqnum; @@ -454,7 +528,6 @@ struct ath5k_tx_status { * enum ath5k_tx_queue - Queue types used to classify tx queues. * @AR5K_TX_QUEUE_INACTIVE: q is unused -- see ath5k_hw_release_tx_queue * @AR5K_TX_QUEUE_DATA: A normal data queue - * @AR5K_TX_QUEUE_XR_DATA: An XR-data queue * @AR5K_TX_QUEUE_BEACON: The beacon queue * @AR5K_TX_QUEUE_CAB: The after-beacon queue * @AR5K_TX_QUEUE_UAPSD: Unscheduled Automatic Power Save Delivery queue @@ -462,7 +535,6 @@ struct ath5k_tx_status { enum ath5k_tx_queue { AR5K_TX_QUEUE_INACTIVE = 0, AR5K_TX_QUEUE_DATA, - AR5K_TX_QUEUE_XR_DATA, AR5K_TX_QUEUE_BEACON, AR5K_TX_QUEUE_CAB, AR5K_TX_QUEUE_UAPSD, @@ -471,36 +543,46 @@ enum ath5k_tx_queue { #define AR5K_NUM_TX_QUEUES 10 #define AR5K_NUM_TX_QUEUES_NOQCU 2 -/* - * Queue syb-types to classify normal data queues. +/** + * enum ath5k_tx_queue_subtype - Queue sub-types to classify normal data queues + * @AR5K_WME_AC_BK: Background traffic + * @AR5K_WME_AC_BE: Best-effort (normal) traffic + * @AR5K_WME_AC_VI: Video traffic + * @AR5K_WME_AC_VO: Voice traffic + * * These are the 4 Access Categories as defined in * WME spec. 0 is the lowest priority and 4 is the * highest. Normal data that hasn't been classified * goes to the Best Effort AC. */ enum ath5k_tx_queue_subtype { - AR5K_WME_AC_BK = 0, /*Background traffic*/ - AR5K_WME_AC_BE, /*Best-effort (normal) traffic*/ - AR5K_WME_AC_VI, /*Video traffic*/ - AR5K_WME_AC_VO, /*Voice traffic*/ + AR5K_WME_AC_BK = 0, + AR5K_WME_AC_BE, + AR5K_WME_AC_VI, + AR5K_WME_AC_VO, }; -/* - * Queue ID numbers as returned by the hw functions, each number - * represents a hw queue. If hw does not support hw queues - * (eg 5210) all data goes in one queue. These match - * d80211 definitions (net80211/MadWiFi don't use them). +/** + * enum ath5k_tx_queue_id - Queue ID numbers as returned by the hw functions + * @AR5K_TX_QUEUE_ID_NOQCU_DATA: Data queue on AR5210 (no QCU available) + * @AR5K_TX_QUEUE_ID_NOQCU_BEACON: Beacon queue on AR5210 (no QCU available) + * @AR5K_TX_QUEUE_ID_DATA_MIN: Data queue min index + * @AR5K_TX_QUEUE_ID_DATA_MAX: Data queue max index + * @AR5K_TX_QUEUE_ID_CAB: Content after beacon queue + * @AR5K_TX_QUEUE_ID_BEACON: Beacon queue + * @AR5K_TX_QUEUE_ID_UAPSD: Urgent Automatic Power Save Delivery, + * + * Each number represents a hw queue. If hw does not support hw queues + * (eg 5210) all data goes in one queue. */ enum ath5k_tx_queue_id { AR5K_TX_QUEUE_ID_NOQCU_DATA = 0, AR5K_TX_QUEUE_ID_NOQCU_BEACON = 1, - AR5K_TX_QUEUE_ID_DATA_MIN = 0, /*IEEE80211_TX_QUEUE_DATA0*/ - AR5K_TX_QUEUE_ID_DATA_MAX = 3, /*IEEE80211_TX_QUEUE_DATA3*/ - AR5K_TX_QUEUE_ID_DATA_SVP = 5, /*IEEE80211_TX_QUEUE_SVP - Spectralink Voice Protocol*/ - AR5K_TX_QUEUE_ID_CAB = 6, /*IEEE80211_TX_QUEUE_AFTER_BEACON*/ - AR5K_TX_QUEUE_ID_BEACON = 7, /*IEEE80211_TX_QUEUE_BEACON*/ - AR5K_TX_QUEUE_ID_UAPSD = 8, - AR5K_TX_QUEUE_ID_XR_DATA = 9, + AR5K_TX_QUEUE_ID_DATA_MIN = 0, + AR5K_TX_QUEUE_ID_DATA_MAX = 3, + AR5K_TX_QUEUE_ID_UAPSD = 7, + AR5K_TX_QUEUE_ID_CAB = 8, + AR5K_TX_QUEUE_ID_BEACON = 9, }; /* @@ -521,46 +603,70 @@ enum ath5k_tx_queue_id { #define AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS 0x1000 /* Disable backoff while bursting */ #define AR5K_TXQ_FLAG_COMPRESSION_ENABLE 0x2000 /* Enable hw compression -not implemented-*/ -/* - * Data transmit queue state. One of these exists for each - * hardware transmit queue. Packets sent to us from above - * are assigned to queues based on their priority. Not all - * devices support a complete set of hardware transmit queues. - * For those devices the array sc_ac2q will map multiple - * priorities to fewer hardware queues (typically all to one - * hardware queue). +/** + * struct ath5k_txq - Transmit queue state + * @qnum: Hardware q number + * @link: Link ptr in last TX desc + * @q: Transmit queue (&struct list_head) + * @lock: Lock on q and link + * @setup: Is the queue configured + * @txq_len:Number of queued buffers + * @txq_max: Max allowed num of queued buffers + * @txq_poll_mark: Used to check if queue got stuck + * @txq_stuck: Queue stuck counter + * + * One of these exists for each hardware transmit queue. + * Packets sent to us from above are assigned to queues based + * on their priority. Not all devices support a complete set + * of hardware transmit queues. For those devices the array + * sc_ac2q will map multiple priorities to fewer hardware queues + * (typically all to one hardware queue). */ struct ath5k_txq { - unsigned int qnum; /* hardware q number */ - u32 *link; /* link ptr in last TX desc */ - struct list_head q; /* transmit queue */ - spinlock_t lock; /* lock on q and link */ + unsigned int qnum; + u32 *link; + struct list_head q; + spinlock_t lock; bool setup; - int txq_len; /* number of queued buffers */ - int txq_max; /* max allowed num of queued buffers */ + int txq_len; + int txq_max; bool txq_poll_mark; - unsigned int txq_stuck; /* informational counter */ + unsigned int txq_stuck; }; -/* - * A struct to hold tx queue's parameters +/** + * struct ath5k_txq_info - A struct to hold TX queue's parameters + * @tqi_type: One of enum ath5k_tx_queue + * @tqi_subtype: One of enum ath5k_tx_queue_subtype + * @tqi_flags: TX queue flags (see above) + * @tqi_aifs: Arbitrated Inter-frame Space + * @tqi_cw_min: Minimum Contention Window + * @tqi_cw_max: Maximum Contention Window + * @tqi_cbr_period: Constant bit rate period + * @tqi_ready_time: Time queue waits after an event when RDYTIME is enabled */ struct ath5k_txq_info { enum ath5k_tx_queue tqi_type; enum ath5k_tx_queue_subtype tqi_subtype; - u16 tqi_flags; /* Tx queue flags (see above) */ - u8 tqi_aifs; /* Arbitrated Interframe Space */ - u16 tqi_cw_min; /* Minimum Contention Window */ - u16 tqi_cw_max; /* Maximum Contention Window */ - u32 tqi_cbr_period; /* Constant bit rate period */ + u16 tqi_flags; + u8 tqi_aifs; + u16 tqi_cw_min; + u16 tqi_cw_max; + u32 tqi_cbr_period; u32 tqi_cbr_overflow_limit; u32 tqi_burst_time; - u32 tqi_ready_time; /* Time queue waits after an event */ + u32 tqi_ready_time; }; -/* - * Transmit packet types. - * used on tx control descriptor +/** + * enum ath5k_pkt_type - Transmit packet types + * @AR5K_PKT_TYPE_NORMAL: Normal data + * @AR5K_PKT_TYPE_ATIM: ATIM + * @AR5K_PKT_TYPE_PSPOLL: PS-Poll + * @AR5K_PKT_TYPE_BEACON: Beacon + * @AR5K_PKT_TYPE_PROBE_RESP: Probe response + * @AR5K_PKT_TYPE_PIFS: PIFS + * Used on tx control descriptor */ enum ath5k_pkt_type { AR5K_PKT_TYPE_NORMAL = 0, @@ -583,27 +689,23 @@ enum ath5k_pkt_type { (ah->ah_txpower.txp_rates_power_table[(_r)] & 0x3f) << (_v) \ ) -/* - * DMA size definitions (2^(n+2)) - */ -enum ath5k_dmasize { - AR5K_DMASIZE_4B = 0, - AR5K_DMASIZE_8B, - AR5K_DMASIZE_16B, - AR5K_DMASIZE_32B, - AR5K_DMASIZE_64B, - AR5K_DMASIZE_128B, - AR5K_DMASIZE_256B, - AR5K_DMASIZE_512B -}; /****************\ RX DEFINITIONS \****************/ -/* - * RX Status descriptor +/** + * struct ath5k_rx_status - RX Status descriptor + * @rs_datalen: Data length + * @rs_tstamp: Timestamp + * @rs_status: Status code + * @rs_phyerr: PHY error mask + * @rs_rssi: RSSI in 0.5dbm units + * @rs_keyix: Index to the key used for decrypting + * @rs_rate: Rate used to decode the frame + * @rs_antenna: Antenna used to receive the frame + * @rs_more: Indicates this is a frame fragment (Fast frames) */ struct ath5k_rx_status { u16 rs_datalen; @@ -645,10 +747,18 @@ struct ath5k_rx_status { #define TSF_TO_TU(_tsf) (u32)((_tsf) >> 10) + /*******************************\ GAIN OPTIMIZATION DEFINITIONS \*******************************/ +/** + * enum ath5k_rfgain - RF Gain optimization engine state + * @AR5K_RFGAIN_INACTIVE: Engine disabled + * @AR5K_RFGAIN_ACTIVE: Probe active + * @AR5K_RFGAIN_READ_REQUESTED: Probe requested + * @AR5K_RFGAIN_NEED_CHANGE: Gain_F needs change + */ enum ath5k_rfgain { AR5K_RFGAIN_INACTIVE = 0, AR5K_RFGAIN_ACTIVE, @@ -656,6 +766,16 @@ enum ath5k_rfgain { AR5K_RFGAIN_NEED_CHANGE, }; +/** + * struct ath5k_gain - RF Gain optimization engine state data + * @g_step_idx: Current step index + * @g_current: Current gain + * @g_target: Target gain + * @g_low: Low gain boundary + * @g_high: High gain boundary + * @g_f_corr: Gain_F correction + * @g_state: One of enum ath5k_rfgain + */ struct ath5k_gain { u8 g_step_idx; u8 g_current; @@ -666,6 +786,8 @@ struct ath5k_gain { u8 g_state; }; + + /********************\ COMMON DEFINITIONS \********************/ @@ -674,9 +796,14 @@ struct ath5k_gain { #define AR5K_SLOT_TIME_20 880 #define AR5K_SLOT_TIME_MAX 0xffff -/* - * The following structure is used to map 2GHz channels to - * 5GHz Atheros channels. +/** + * struct ath5k_athchan_2ghz - 2GHz to 5GHZ map for RF5111 + * @a2_flags: Channel flags (internal) + * @a2_athchan: HW channel number (internal) + * + * This structure is used to map 2GHz channels to + * 5GHz Atheros channels on 2111 frequency converter + * that comes together with RF5111 * TODO: Clean up */ struct ath5k_athchan_2ghz { @@ -684,36 +811,80 @@ struct ath5k_athchan_2ghz { u16 a2_athchan; }; +/** + * enum ath5k_dmasize - DMA size definitions (2^(n+2)) + * @AR5K_DMASIZE_4B: 4Bytes + * @AR5K_DMASIZE_8B: 8Bytes + * @AR5K_DMASIZE_16B: 16Bytes + * @AR5K_DMASIZE_32B: 32Bytes + * @AR5K_DMASIZE_64B: 64Bytes (Default) + * @AR5K_DMASIZE_128B: 128Bytes + * @AR5K_DMASIZE_256B: 256Bytes + * @AR5K_DMASIZE_512B: 512Bytes + * + * These are used to set DMA burst size on hw + * + * Note: Some platforms can't handle more than 4Bytes + * be careful on embedded boards. + */ +enum ath5k_dmasize { + AR5K_DMASIZE_4B = 0, + AR5K_DMASIZE_8B, + AR5K_DMASIZE_16B, + AR5K_DMASIZE_32B, + AR5K_DMASIZE_64B, + AR5K_DMASIZE_128B, + AR5K_DMASIZE_256B, + AR5K_DMASIZE_512B +}; + + /******************\ RATE DEFINITIONS \******************/ /** + * DOC: Rate codes + * * Seems the ar5xxx hardware supports up to 32 rates, indexed by 1-32. * * The rate code is used to get the RX rate or set the TX rate on the * hardware descriptors. It is also used for internal modulation control * and settings. * - * This is the hardware rate map we are aware of: - * - * rate_code 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 - * rate_kbps 3000 1000 ? ? ? 2000 500 48000 - * - * rate_code 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 - * rate_kbps 24000 12000 6000 54000 36000 18000 9000 ? + * This is the hardware rate map we are aware of (html unfriendly): * - * rate_code 17 18 19 20 21 22 23 24 - * rate_kbps ? ? ? ? ? ? ? 11000 + * Rate code Rate (Kbps) + * --------- ----------- + * 0x01 3000 (XR) + * 0x02 1000 (XR) + * 0x03 250 (XR) + * 0x04 - 05 -Reserved- + * 0x06 2000 (XR) + * 0x07 500 (XR) + * 0x08 48000 (OFDM) + * 0x09 24000 (OFDM) + * 0x0A 12000 (OFDM) + * 0x0B 6000 (OFDM) + * 0x0C 54000 (OFDM) + * 0x0D 36000 (OFDM) + * 0x0E 18000 (OFDM) + * 0x0F 9000 (OFDM) + * 0x10 - 17 -Reserved- + * 0x18 11000L (CCK) + * 0x19 5500L (CCK) + * 0x1A 2000L (CCK) + * 0x1B 1000L (CCK) + * 0x1C 11000S (CCK) + * 0x1D 5500S (CCK) + * 0x1E 2000S (CCK) + * 0x1F -Reserved- * - * rate_code 25 26 27 28 29 30 31 32 - * rate_kbps 5500 2000 1000 11000S 5500S 2000S ? ? - * - * "S" indicates CCK rates with short preamble. + * "S" indicates CCK rates with short preamble and "L" with long preamble. * * AR5211 has different rate codes for CCK (802.11B) rates. It only uses the - * lowest 4 bits, so they are the same as below with a 0xF mask. + * lowest 4 bits, so they are the same as above with a 0xF mask. * (0xB, 0xA, 0x9 and 0x8 for 1M, 2M, 5.5M and 11M). * We handle this in ath5k_setup_bands(). */ @@ -733,13 +904,9 @@ struct ath5k_athchan_2ghz { #define ATH5K_RATE_CODE_36M 0x0D #define ATH5K_RATE_CODE_48M 0x08 #define ATH5K_RATE_CODE_54M 0x0C -/* XR */ -#define ATH5K_RATE_CODE_XR_500K 0x07 -#define ATH5K_RATE_CODE_XR_1M 0x02 -#define ATH5K_RATE_CODE_XR_2M 0x06 -#define ATH5K_RATE_CODE_XR_3M 0x01 -/* adding this flag to rate_code enables short preamble */ +/* Adding this flag to rate_code on B rates + * enables short preamble */ #define AR5K_SET_SHORT_PREAMBLE 0x04 /* @@ -747,7 +914,7 @@ struct ath5k_athchan_2ghz { */ #define AR5K_KEYCACHE_SIZE 8 -extern int ath5k_modparam_nohwcrypt; +extern bool ath5k_modparam_nohwcrypt; /***********************\ HW RELATED DEFINITIONS @@ -769,49 +936,65 @@ extern int ath5k_modparam_nohwcrypt; /** * enum ath5k_int - Hardware interrupt masks helpers + * @AR5K_INT_RXOK: Frame successfully received + * @AR5K_INT_RXDESC: Request RX descriptor/Read RX descriptor + * @AR5K_INT_RXERR: Frame reception failed + * @AR5K_INT_RXNOFRM: No frame received within a specified time period + * @AR5K_INT_RXEOL: Reached "End Of List", means we need more RX descriptors + * @AR5K_INT_RXORN: Indicates we got RX FIFO overrun. Note that Rx overrun is + * not always fatal, on some chips we can continue operation + * without resetting the card, that's why %AR5K_INT_FATAL is not + * common for all chips. + * @AR5K_INT_RX_ALL: Mask to identify all RX related interrupts + * + * @AR5K_INT_TXOK: Frame transmission success + * @AR5K_INT_TXDESC: Request TX descriptor/Read TX status descriptor + * @AR5K_INT_TXERR: Frame transmission failure + * @AR5K_INT_TXEOL: Received End Of List for VEOL (Virtual End Of List). The + * Queue Control Unit (QCU) signals an EOL interrupt only if a + * descriptor's LinkPtr is NULL. For more details, refer to: + * "http://www.freepatentsonline.com/20030225739.html" + * @AR5K_INT_TXNOFRM: No frame was transmitted within a specified time period + * @AR5K_INT_TXURN: Indicates we got TX FIFO underrun. In such case we should + * increase the TX trigger threshold. + * @AR5K_INT_TX_ALL: Mask to identify all TX related interrupts * - * @AR5K_INT_RX: mask to identify received frame interrupts, of type - * AR5K_ISR_RXOK or AR5K_ISR_RXERR - * @AR5K_INT_RXDESC: Request RX descriptor/Read RX descriptor (?) - * @AR5K_INT_RXNOFRM: No frame received (?) - * @AR5K_INT_RXEOL: received End Of List for VEOL (Virtual End Of List). The - * Queue Control Unit (QCU) signals an EOL interrupt only if a descriptor's - * LinkPtr is NULL. For more details, refer to: - * http://www.freepatentsonline.com/20030225739.html - * @AR5K_INT_RXORN: Indicates we got RX overrun (eg. no more descriptors). - * Note that Rx overrun is not always fatal, on some chips we can continue - * operation without resetting the card, that's why int_fatal is not - * common for all chips. - * @AR5K_INT_TX: mask to identify received frame interrupts, of type - * AR5K_ISR_TXOK or AR5K_ISR_TXERR - * @AR5K_INT_TXDESC: Request TX descriptor/Read TX status descriptor (?) - * @AR5K_INT_TXURN: received when we should increase the TX trigger threshold - * We currently do increments on interrupt by - * (AR5K_TUNE_MAX_TX_FIFO_THRES - current_trigger_level) / 2 * @AR5K_INT_MIB: Indicates the either Management Information Base counters or - * one of the PHY error counters reached the maximum value and should be - * read and cleared. + * one of the PHY error counters reached the maximum value and + * should be read and cleared. + * @AR5K_INT_SWI: Software triggered interrupt. * @AR5K_INT_RXPHY: RX PHY Error * @AR5K_INT_RXKCM: RX Key cache miss * @AR5K_INT_SWBA: SoftWare Beacon Alert - indicates its time to send a - * beacon that must be handled in software. The alternative is if you - * have VEOL support, in that case you let the hardware deal with things. + * beacon that must be handled in software. The alternative is if + * you have VEOL support, in that case you let the hardware deal + * with things. + * @AR5K_INT_BRSSI: Beacon received with an RSSI value below our threshold * @AR5K_INT_BMISS: If in STA mode this indicates we have stopped seeing - * beacons from the AP have associated with, we should probably try to - * reassociate. When in IBSS mode this might mean we have not received - * any beacons from any local stations. Note that every station in an - * IBSS schedules to send beacons at the Target Beacon Transmission Time - * (TBTT) with a random backoff. - * @AR5K_INT_BNR: Beacon Not Ready interrupt - ?? - * @AR5K_INT_GPIO: GPIO interrupt is used for RF Kill, disabled for now - * until properly handled - * @AR5K_INT_FATAL: Fatal errors were encountered, typically caused by DMA - * errors. These types of errors we can enable seem to be of type - * AR5K_SIMR2_MCABT, AR5K_SIMR2_SSERR and AR5K_SIMR2_DPERR. + * beacons from the AP have associated with, we should probably + * try to reassociate. When in IBSS mode this might mean we have + * not received any beacons from any local stations. Note that + * every station in an IBSS schedules to send beacons at the + * Target Beacon Transmission Time (TBTT) with a random backoff. + * @AR5K_INT_BNR: Beacon queue got triggered (DMA beacon alert) while empty. + * @AR5K_INT_TIM: Beacon with local station's TIM bit set + * @AR5K_INT_DTIM: Beacon with DTIM bit and zero DTIM count received + * @AR5K_INT_DTIM_SYNC: DTIM sync lost + * @AR5K_INT_GPIO: GPIO interrupt is used for RF Kill switches connected to + * our GPIO pins. + * @AR5K_INT_BCN_TIMEOUT: Beacon timeout, we waited after TBTT but got noting + * @AR5K_INT_CAB_TIMEOUT: We waited for CAB traffic after the beacon but got + * nothing or an incomplete CAB frame sequence. + * @AR5K_INT_QCBRORN: A queue got it's CBR counter expired + * @AR5K_INT_QCBRURN: A queue got triggered wile empty + * @AR5K_INT_QTRIG: A queue got triggered + * + * @AR5K_INT_FATAL: Fatal errors were encountered, typically caused by bus/DMA + * errors. Indicates we need to reset the card. * @AR5K_INT_GLOBAL: Used to clear and set the IER - * @AR5K_INT_NOCARD: signals the card has been removed - * @AR5K_INT_COMMON: common interrupts shared among MACs with the same - * bit value + * @AR5K_INT_NOCARD: Signals the card has been removed + * @AR5K_INT_COMMON: Common interrupts shared among MACs with the same + * bit value * * These are mapped to take advantage of some common bits * between the MACs, to be able to set intr properties @@ -847,15 +1030,15 @@ enum ath5k_int { AR5K_INT_GPIO = 0x01000000, AR5K_INT_BCN_TIMEOUT = 0x02000000, /* Non common */ AR5K_INT_CAB_TIMEOUT = 0x04000000, /* Non common */ - AR5K_INT_RX_DOPPLER = 0x08000000, /* Non common */ - AR5K_INT_QCBRORN = 0x10000000, /* Non common */ - AR5K_INT_QCBRURN = 0x20000000, /* Non common */ - AR5K_INT_QTRIG = 0x40000000, /* Non common */ + AR5K_INT_QCBRORN = 0x08000000, /* Non common */ + AR5K_INT_QCBRURN = 0x10000000, /* Non common */ + AR5K_INT_QTRIG = 0x20000000, /* Non common */ AR5K_INT_GLOBAL = 0x80000000, AR5K_INT_TX_ALL = AR5K_INT_TXOK | AR5K_INT_TXDESC | AR5K_INT_TXERR + | AR5K_INT_TXNOFRM | AR5K_INT_TXEOL | AR5K_INT_TXURN, @@ -891,15 +1074,32 @@ enum ath5k_int { AR5K_INT_NOCARD = 0xffffffff }; -/* mask which calibration is active at the moment */ +/** + * enum ath5k_calibration_mask - Mask which calibration is active at the moment + * @AR5K_CALIBRATION_FULL: Full calibration (AGC + SHORT) + * @AR5K_CALIBRATION_SHORT: Short calibration (NF + I/Q) + * @AR5K_CALIBRATION_NF: Noise Floor calibration + * @AR5K_CALIBRATION_ANI: Adaptive Noise Immunity + */ enum ath5k_calibration_mask { AR5K_CALIBRATION_FULL = 0x01, AR5K_CALIBRATION_SHORT = 0x02, - AR5K_CALIBRATION_ANI = 0x04, + AR5K_CALIBRATION_NF = 0x04, + AR5K_CALIBRATION_ANI = 0x08, }; -/* - * Power management +/** + * enum ath5k_power_mode - Power management modes + * @AR5K_PM_UNDEFINED: Undefined + * @AR5K_PM_AUTO: Allow card to sleep if possible + * @AR5K_PM_AWAKE: Force card to wake up + * @AR5K_PM_FULL_SLEEP: Force card to full sleep (DANGEROUS) + * @AR5K_PM_NETWORK_SLEEP: Allow to sleep for a specified duration + * + * Currently only PM_AWAKE is used, FULL_SLEEP and NETWORK_SLEEP/AUTO + * are also known to have problems on some cards. This is not a big + * problem though because we can have almost the same effect as + * FULL_SLEEP by putting card on warm reset (it's almost powered down). */ enum ath5k_power_mode { AR5K_PM_UNDEFINED = 0, @@ -957,6 +1157,8 @@ struct ath5k_capabilities { } cap_queues; bool cap_has_phyerr_counters; + bool cap_has_mrr_support; + bool cap_needs_2GHz_ovr; }; /* size of noise floor history (keep it a power of two) */ @@ -1072,13 +1274,11 @@ struct ath5k_hw { dma_addr_t desc_daddr; /* DMA (physical) address */ size_t desc_len; /* size of TX/RX descriptors */ - DECLARE_BITMAP(status, 6); + DECLARE_BITMAP(status, 4); #define ATH_STAT_INVALID 0 /* disable hardware accesses */ -#define ATH_STAT_MRRETRY 1 /* multi-rate retry support */ -#define ATH_STAT_PROMISC 2 -#define ATH_STAT_LEDSOFT 3 /* enable LED gpio status */ -#define ATH_STAT_STARTED 4 /* opened & irqs enabled */ -#define ATH_STAT_2G_DISABLED 5 /* multiband radio without 2G */ +#define ATH_STAT_PROMISC 1 +#define ATH_STAT_LEDSOFT 2 /* enable LED gpio status */ +#define ATH_STAT_STARTED 3 /* opened & irqs enabled */ unsigned int filter_flags; /* HW flags, AR5K_RX_FILTER_* */ struct ieee80211_channel *curchan; /* current h/w channel */ @@ -1097,6 +1297,7 @@ struct ath5k_hw { led_on; /* pin setting for LED on */ struct work_struct reset_work; /* deferred chip reset */ + struct work_struct calib_work; /* deferred phy calibration */ struct list_head rxbuf; /* receive buffer */ spinlock_t rxbuflock; @@ -1113,8 +1314,6 @@ struct ath5k_hw { struct ath5k_rfkill rf_kill; - struct tasklet_struct calib; /* calibration tasklet */ - spinlock_t block; /* protects beacon */ struct tasklet_struct beacontq; /* beacon intr tasklet */ struct list_head bcbuf; /* beacon buffer */ @@ -1144,7 +1343,7 @@ struct ath5k_hw { enum ath5k_int ah_imr; struct ieee80211_channel *ah_current_channel; - bool ah_calibration; + bool ah_iq_cal_needed; bool ah_single_chip; enum ath5k_version ah_version; @@ -1187,7 +1386,13 @@ struct ath5k_hw { u32 ah_txq_imr_cbrurn; u32 ah_txq_imr_qtrig; u32 ah_txq_imr_nofrm; - u32 ah_txq_isr; + + u32 ah_txq_isr_txok_all; + u32 ah_txq_isr_txurn; + u32 ah_txq_isr_qcborn; + u32 ah_txq_isr_qcburn; + u32 ah_txq_isr_qtrig; + u32 *ah_rf_banks; size_t ah_rf_banks_size; size_t ah_rf_regs_count; @@ -1228,8 +1433,8 @@ struct ath5k_hw { /* Calibration timestamp */ unsigned long ah_cal_next_full; + unsigned long ah_cal_next_short; unsigned long ah_cal_next_ani; - unsigned long ah_cal_next_nf; /* Calibration mask */ u8 ah_cal_mask; @@ -1338,11 +1543,11 @@ void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah); u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah); void ath5k_hw_set_tsf64(struct ath5k_hw *ah, u64 tsf64); void ath5k_hw_reset_tsf(struct ath5k_hw *ah); -void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval); +void ath5k_hw_init_beacon_timers(struct ath5k_hw *ah, u32 next_beacon, + u32 interval); bool ath5k_hw_check_beacon_timers(struct ath5k_hw *ah, int intval); /* Init function */ -void ath5k_hw_pcu_init(struct ath5k_hw *ah, enum nl80211_iftype op_mode, - u8 mode); +void ath5k_hw_pcu_init(struct ath5k_hw *ah, enum nl80211_iftype op_mode); /* Queue Control Unit, DFS Control Unit Functions */ int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue, diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index 91627dd2c26a..d7114c75fe9b 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -27,8 +27,7 @@ #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 */ 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 * * Check if the device is supported, perform a POST and initialize the needed @@ -298,7 +296,7 @@ int ath5k_hw_init(struct ath5k_hw *ah) /* Reset SERDES to load new settings */ ath5k_hw_reg_write(ah, 0x00000000, AR5K_PCIE_SERDES_RESET); - mdelay(1); + usleep_range(1000, 1500); } /* Get misc capabilities */ @@ -308,11 +306,6 @@ int ath5k_hw_init(struct ath5k_hw *ah) 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 */ common->keymax = (ah->ah_version == AR5K_AR5210 ? AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211); @@ -349,8 +342,7 @@ err: } /** - * ath5k_hw_deinit - Free the ath5k_hw struct - * + * ath5k_hw_deinit() - Free the &struct ath5k_hw * @ah: The &struct ath5k_hw */ void ath5k_hw_deinit(struct ath5k_hw *ah) diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index b346d0492001..d366dadcf86e 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -68,18 +68,23 @@ #define CREATE_TRACE_POINTS #include "trace.h" -int ath5k_modparam_nohwcrypt; +bool ath5k_modparam_nohwcrypt; module_param_named(nohwcrypt, ath5k_modparam_nohwcrypt, bool, S_IRUGO); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); -static int modparam_all_channels; +static bool modparam_all_channels; module_param_named(all_channels, modparam_all_channels, bool, S_IRUGO); MODULE_PARM_DESC(all_channels, "Expose all channels the device can use."); -static int modparam_fastchanswitch; +static bool modparam_fastchanswitch; module_param_named(fastchanswitch, modparam_fastchanswitch, bool, S_IRUGO); 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_AUTHOR("Jiri Slaby"); @@ -183,7 +188,6 @@ static const struct ieee80211_rate ath5k_rates[] = { { .bitrate = 540, .hw_value = ATH5K_RATE_CODE_54M, .flags = 0 }, - /* XR missing */ }; 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, if (ret) goto err_unmap; - memset(mrr_rate, 0, sizeof(mrr_rate)); - memset(mrr_tries, 0, sizeof(mrr_tries)); - for (i = 0; i < 3; i++) { - rate = ieee80211_get_alt_retry_rate(ah->hw, info, i); - if (!rate) - break; + /* Set up MRR descriptor */ + if (ah->ah_capabilities.cap_has_mrr_support) { + memset(mrr_rate, 0, sizeof(mrr_rate)); + memset(mrr_tries, 0, sizeof(mrr_tries)); + for (i = 0; i < 3; i++) { + rate = ieee80211_get_alt_retry_rate(ah->hw, info, i); + if (!rate) + break; - mrr_rate[i] = rate->hw_value; - mrr_tries[i] = info->control.rates[i + 1].count; - } + mrr_rate[i] = rate->hw_value; + mrr_tries[i] = info->control.rates[i + 1].count; + } - ath5k_hw_setup_mrr_tx_desc(ah, ds, - mrr_rate[0], mrr_tries[0], - mrr_rate[1], mrr_tries[1], - mrr_rate[2], mrr_tries[2]); + ath5k_hw_setup_mrr_tx_desc(ah, ds, + mrr_rate[0], mrr_tries[0], + mrr_rate[1], mrr_tries[1], + mrr_rate[2], mrr_tries[2]); + } ds->ds_link = 0; ds->ds_data = bf->skbaddr; @@ -1689,7 +1696,7 @@ ath5k_tasklet_tx(unsigned long data) struct ath5k_hw *ah = (void *)data; 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]); ah->tx_pending = false; @@ -2005,7 +2012,7 @@ ath5k_beacon_update_timers(struct ath5k_hw *ah, u64 bc_tsf) ah->nexttbtt = nexttbtt; 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 @@ -2112,16 +2119,29 @@ static void ath5k_intr_calibration_poll(struct ath5k_hw *ah) { if (time_is_before_eq_jiffies(ah->ah_cal_next_ani) && - !(ah->ah_cal_mask & AR5K_CALIBRATION_FULL)) { - /* run ANI only when full calibration is not active */ + !(ah->ah_cal_mask & AR5K_CALIBRATION_FULL) && + !(ah->ah_cal_mask & AR5K_CALIBRATION_SHORT)) { + + /* Run ANI only when calibration is not active */ + ah->ah_cal_next_ani = jiffies + msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_ANI); tasklet_schedule(&ah->ani_tasklet); - } else 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); - tasklet_schedule(&ah->calib); + } else if (time_is_before_eq_jiffies(ah->ah_cal_next_short) && + !(ah->ah_cal_mask & AR5K_CALIBRATION_FULL) && + !(ah->ah_cal_mask & AR5K_CALIBRATION_SHORT)) { + + /* 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 * calibration interval requirements, if necessary: @@ -2149,69 +2169,110 @@ ath5k_intr(int irq, void *dev_id) enum ath5k_int status; 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) || - ((ath5k_get_bus_type(ah) != ATH_AHB) && - !ath5k_hw_is_intr_pending(ah)))) + ((ath5k_get_bus_type(ah) != ATH_AHB) && + !ath5k_hw_is_intr_pending(ah)))) return IRQ_NONE; + /** Main loop **/ 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", 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)) { - /* - * Fatal errors are unrecoverable. - * Typically these are caused by DMA errors. - */ + ATH5K_DBG(ah, ATH5K_DEBUG_RESET, "fatal int, resetting\n"); 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)) { + /* - * 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 * 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. */ ah->stats.rxorn_intr++; + if (ah->ah_mac_srev < AR5K_SREV_AR5212) { ATH5K_DBG(ah, ATH5K_DEBUG_RESET, "rx overrun, resetting\n"); ieee80211_queue_work(ah->hw, &ah->reset_work); } else ath5k_schedule_rx(ah); + } else { + + /* Software Beacon Alert -> Schedule beacon tasklet */ if (status & AR5K_INT_SWBA) tasklet_hi_schedule(&ah->beacontq); - if (status & AR5K_INT_RXEOL) { - /* - * NB: the hardware should re-read the link when - * RXE bit is written, but it doesn't work at - * least on older hardware revs. - */ + /* + * 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 + * least on older hardware revs. + */ + if (status & AR5K_INT_RXEOL) 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); - } + + /* RX -> Schedule rx tasklet */ if (status & (AR5K_INT_RXOK | AR5K_INT_RXERR)) 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); - 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) { ah->stats.mib_intr++; ath5k_hw_update_mib_counters(ah); ath5k_ani_mib_intr(ah); } + + /* GPIO -> Notify RFKill layer */ if (status & AR5K_INT_GPIO) tasklet_schedule(&ah->rf_kill.toggleq); @@ -2222,12 +2283,19 @@ ath5k_intr(int irq, void *dev_id) } while (ath5k_hw_is_intr_pending(ah) && --counter > 0); + /* + * 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) ath5k_set_current_imask(ah); if (unlikely(!counter)) ATH5K_WARN(ah, "too many interrupts, giving up for now\n"); + /* Fire up calibration poll */ ath5k_intr_calibration_poll(ah); return IRQ_HANDLED; @@ -2238,41 +2306,58 @@ ath5k_intr(int irq, void *dev_id) * for temperature/environment changes. */ 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", ieee80211_frequency_to_channel(ah->curchan->center_freq), 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)) ATH5K_ERR(ah, "calibration of channel %u failed\n", ieee80211_frequency_to_channel( ah->curchan->center_freq)); - /* Noise floor calibration interrupts rx/tx path while I/Q calibration - * doesn't. - * TODO: We should stop TX here, so that it doesn't interfere. - * Note that stopping the queues is not enough to stop TX! */ - if (time_is_before_eq_jiffies(ah->ah_cal_next_nf)) { - ah->ah_cal_next_nf = jiffies + - msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_NF); - ath5k_hw_update_noise_floor(ah); - } - - ah->ah_cal_mask &= ~AR5K_CALIBRATION_FULL; + /* Clear calibration flags */ + if (ah->ah_cal_mask & AR5K_CALIBRATION_FULL) { + ieee80211_wake_queues(ah->hw); + ah->ah_cal_mask &= ~AR5K_CALIBRATION_FULL; + } else if (ah->ah_cal_mask & AR5K_CALIBRATION_SHORT) + ah->ah_cal_mask &= ~AR5K_CALIBRATION_SHORT; } @@ -2407,8 +2492,8 @@ ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops) if (ret) goto err_irq; - /* set up multi-rate retry capabilities */ - if (ah->ah_version == AR5K_AR5212) { + /* Set up multi-rate retry capabilities */ + if (ah->ah_capabilities.cap_has_mrr_support) { hw->max_rates = 4; hw->max_rate_tries = max(AR5K_INIT_RETRY_SHORT, AR5K_INIT_RETRY_LONG); @@ -2544,15 +2629,22 @@ int ath5k_start(struct ieee80211_hw *hw) * and then setup of the interrupt mask. */ ah->curchan = ah->hw->conf.channel; - ah->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL | - AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL | - AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_MIB; + ah->imask = AR5K_INT_RXOK + | AR5K_INT_RXERR + | 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); if (ret) 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 @@ -2585,7 +2677,6 @@ static void ath5k_stop_tasklets(struct ath5k_hw *ah) ah->tx_pending = false; tasklet_kill(&ah->rxtq); tasklet_kill(&ah->txtq); - tasklet_kill(&ah->calib); tasklet_kill(&ah->beacontq); tasklet_kill(&ah->ani_tasklet); } @@ -2637,7 +2728,8 @@ void ath5k_stop(struct ieee80211_hw *hw) cancel_delayed_work_sync(&ah->tx_complete_work); - ath5k_rfkill_hw_stop(ah); + if (!ath5k_modparam_no_hw_rfkill_switch) + ath5k_rfkill_hw_stop(ah); } /* @@ -2689,9 +2781,24 @@ ath5k_reset(struct ath5k_hw *ah, struct ieee80211_channel *chan, ath5k_ani_init(ah, ani_mode); - ah->ah_cal_next_full = jiffies + msecs_to_jiffies(100); - ah->ah_cal_next_ani = jiffies; - ah->ah_cal_next_nf = jiffies; + /* + * Set calibration intervals + * + * 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); /* clear survey data and cycle counters */ @@ -2745,20 +2852,6 @@ ath5k_init(struct ieee80211_hw *hw) /* - * 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 * is responsible for filtering this list based * on settings like the phy mode and regulatory @@ -2841,11 +2934,11 @@ ath5k_init(struct ieee80211_hw *hw) tasklet_init(&ah->rxtq, ath5k_tasklet_rx, (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->ani_tasklet, ath5k_tasklet_ani, (unsigned long)ah); 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); ret = ath5k_hw_common(ah)->bus_ops->eeprom_read_mac(ah, mac); diff --git a/drivers/net/wireless/ath/ath5k/caps.c b/drivers/net/wireless/ath/ath5k/caps.c index 810fba96702b..994169ad39cb 100644 --- a/drivers/net/wireless/ath/ath5k/caps.c +++ b/drivers/net/wireless/ath/ath5k/caps.c @@ -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_max = 2732; - if (AR5K_EEPROM_HDR_11B(ee_header)) - __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); + /* Override 2GHz modes on SoCs that need it + * NOTE: cap_needs_2GHz_ovr gets set from + * ath_ahb_probe */ + if (!caps->cap_needs_2GHz_ovr) { + if (AR5K_EEPROM_HDR_11B(ee_header)) + __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) else 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) caps->cap_has_phyerr_counters = true; else 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; } diff --git a/drivers/net/wireless/ath/ath5k/desc.c b/drivers/net/wireless/ath/ath5k/desc.c index 7e88dda82221..f8bfa3ac2af0 100644 --- a/drivers/net/wireless/ath/ath5k/desc.c +++ b/drivers/net/wireless/ath/ath5k/desc.c @@ -26,20 +26,61 @@ #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 * \************************/ -/* - * 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 -ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, - unsigned int pkt_len, unsigned int hdr_len, int padsize, - enum ath5k_pkt_type type, - 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) +ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, + struct ath5k_desc *desc, + unsigned int pkt_len, unsigned int hdr_len, + int padsize, + enum ath5k_pkt_type type, + 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; struct ath5k_hw_2w_tx_ctl *tx_ctl; @@ -172,17 +213,40 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, return 0; } -/* - * 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, - struct ath5k_desc *desc, unsigned int pkt_len, unsigned int hdr_len, - int padsize, - enum ath5k_pkt_type type, 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) +static int +ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, + struct ath5k_desc *desc, + unsigned int pkt_len, unsigned int hdr_len, + int padsize, + enum ath5k_pkt_type type, + 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) { struct ath5k_hw_4w_tx_ctl *tx_ctl; unsigned int frame_len; @@ -292,13 +356,29 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, 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 -ath5k_hw_setup_mrr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, - unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2, - u_int tx_tries2, unsigned int tx_rate3, u_int tx_tries3) +ath5k_hw_setup_mrr_tx_desc(struct ath5k_hw *ah, + struct ath5k_desc *desc, + 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; @@ -350,11 +430,16 @@ ath5k_hw_setup_mrr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, * 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, - struct ath5k_desc *desc, struct ath5k_tx_status *ts) +static int +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_tx_status *tx_status; @@ -399,11 +484,16 @@ static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah, 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, - struct ath5k_desc *desc, struct ath5k_tx_status *ts) +static int +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_tx_status *tx_status; @@ -460,11 +550,17 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, * 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, - u32 size, unsigned int flags) +int +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; @@ -491,11 +587,22 @@ int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, 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, - struct ath5k_desc *desc, struct ath5k_rx_status *rs) +static int +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; @@ -574,12 +681,22 @@ static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah, 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, - struct ath5k_desc *desc, - struct ath5k_rx_status *rs) +static int +ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah, + struct ath5k_desc *desc, + struct ath5k_rx_status *rs) { struct ath5k_hw_rx_status *rx_status; u32 rxstat0, rxstat1; @@ -646,10 +763,16 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah, * 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) { ah->ah_setup_tx_desc = ath5k_hw_setup_4word_tx_desc; diff --git a/drivers/net/wireless/ath/ath5k/desc.h b/drivers/net/wireless/ath/ath5k/desc.h index cfd529b548f3..8d6c01a49ea3 100644 --- a/drivers/net/wireless/ath/ath5k/desc.h +++ b/drivers/net/wireless/ath/ath5k/desc.h @@ -20,25 +20,30 @@ * 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 { - u32 rx_control_0; /* RX control word 0 */ - u32 rx_control_1; /* RX control word 1 */ + u32 rx_control_0; + u32 rx_control_1; } __packed __aligned(4); /* RX control word 1 fields/flags */ #define AR5K_DESC_RX_CTL1_BUF_LEN 0x00000fff /* data buffer length */ #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 */ struct ath5k_hw_rx_status { - u32 rx_status_0; /* RX status word 0 */ - u32 rx_status_1; /* RX status word 1 */ + u32 rx_status_0; + u32 rx_status_1; } __packed __aligned(4); /* 5210/5211 */ @@ -98,17 +103,36 @@ struct ath5k_hw_rx_status { /** * 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 { - AR5K_RX_PHY_ERROR_UNDERRUN = 0, /* Transmit underrun, [5210] No error */ - AR5K_RX_PHY_ERROR_TIMING = 1, /* Timing error */ - AR5K_RX_PHY_ERROR_PARITY = 2, /* Illegal parity */ - AR5K_RX_PHY_ERROR_RATE = 3, /* Illegal rate */ - AR5K_RX_PHY_ERROR_LENGTH = 4, /* Illegal length */ - AR5K_RX_PHY_ERROR_RADAR = 5, /* Radar detect, [5210] 64 QAM rate */ - AR5K_RX_PHY_ERROR_SERVICE = 6, /* Illegal service */ - AR5K_RX_PHY_ERROR_TOR = 7, /* Transmit override receive */ - /* these are specific to the 5212 */ + AR5K_RX_PHY_ERROR_UNDERRUN = 0, + AR5K_RX_PHY_ERROR_TIMING = 1, + AR5K_RX_PHY_ERROR_PARITY = 2, + AR5K_RX_PHY_ERROR_RATE = 3, + AR5K_RX_PHY_ERROR_LENGTH = 4, + AR5K_RX_PHY_ERROR_RADAR = 5, + AR5K_RX_PHY_ERROR_SERVICE = 6, + AR5K_RX_PHY_ERROR_TOR = 7, AR5K_RX_PHY_ERROR_OFDM_TIMING = 17, AR5K_RX_PHY_ERROR_OFDM_SIGNAL_PARITY = 18, AR5K_RX_PHY_ERROR_OFDM_RATE_ILLEGAL = 19, @@ -123,12 +147,14 @@ enum ath5k_phy_error_code { 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 { - u32 tx_control_0; /* TX control word 0 */ - u32 tx_control_1; /* TX control word 1 */ + u32 tx_control_0; + u32 tx_control_1; } __packed __aligned(4); /* TX control word 0 fields/flags */ @@ -177,14 +203,18 @@ struct ath5k_hw_2w_tx_ctl { #define AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS 4 #define AR5K_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 { - u32 tx_control_0; /* TX control word 0 */ - u32 tx_control_1; /* TX control word 1 */ - u32 tx_control_2; /* TX control word 2 */ - u32 tx_control_3; /* TX control word 3 */ + u32 tx_control_0; + u32 tx_control_1; + u32 tx_control_2; + u32 tx_control_3; } __packed __aligned(4); /* TX control word 0 fields/flags */ @@ -238,12 +268,14 @@ struct ath5k_hw_4w_tx_ctl { #define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE 0x01f00000 /* RTS or CTS rate */ #define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE_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 { - u32 tx_status_0; /* TX status word 0 */ - u32 tx_status_1; /* TX status word 1 */ + u32 tx_status_0; + u32 tx_status_1; } __packed __aligned(4); /* TX status word 0 fields/flags */ @@ -276,37 +308,47 @@ struct ath5k_hw_tx_status { #define AR5K_DESC_TX_STATUS1_COMP_SUCCESS_5212 0x00800000 /* [5212] compression status */ #define AR5K_DESC_TX_STATUS1_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_2w_tx_ctl tx_ctl; struct ath5k_hw_tx_status tx_stat; } __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_4w_tx_ctl tx_ctl; struct ath5k_hw_tx_status tx_stat; } __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_rx_ctl rx_ctl; struct ath5k_hw_rx_status rx_stat; } __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 */ struct ath5k_desc { - u32 ds_link; /* physical address of the next descriptor */ - u32 ds_data; /* physical address of data buffer (skb) */ + u32 ds_link; + u32 ds_data; union { struct ath5k_hw_5210_tx_desc ds_tx5210; diff --git a/drivers/net/wireless/ath/ath5k/dma.c b/drivers/net/wireless/ath/ath5k/dma.c index 2481f9c7f4b6..5cc9aa814697 100644 --- a/drivers/net/wireless/ath/ath5k/dma.c +++ b/drivers/net/wireless/ath/ath5k/dma.c @@ -20,16 +20,13 @@ * 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 * handle queue setup for 5210 chipset (rest are handled on qcu.c). * Also we setup interrupt mask register (IMR) and read the various interrupt * status registers (ISR). - * - * TODO: Handle SISR on 5211+ and introduce a function to return the queue - * number that resulted the interrupt. */ #include "ath5k.h" @@ -42,22 +39,22 @@ \*********/ /** - * ath5k_hw_start_rx_dma - Start DMA receive - * + * ath5k_hw_start_rx_dma() - Start DMA receive * @ah: The &struct ath5k_hw */ -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_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 */ -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; @@ -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 */ -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); } /** - * ath5k_hw_set_rxdp - Set RX Descriptor's address - * + * ath5k_hw_set_rxdp() - Set RX Descriptor's address * @ah: The &struct ath5k_hw * @phys_addr: RX descriptor address * * 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) { ATH5K_DBG(ah, ATH5K_DEBUG_DMA, @@ -114,8 +111,7 @@ int ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr) \**********/ /** - * ath5k_hw_start_tx_dma - Start DMA transmit for a specific queue - * + * ath5k_hw_start_tx_dma() - Start DMA transmit for a specific queue * @ah: The &struct ath5k_hw * @queue: The hw queue number * @@ -128,7 +124,8 @@ int ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr) * NOTE: Must be called after setting up tx control descriptor for that * 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; @@ -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 * @queue: The hw queue number * * 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, * -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; u32 tx_queue, pending; @@ -320,14 +316,14 @@ static int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue) } /** - * ath5k_hw_stop_beacon_queue - Stop beacon queue - * - * @ah The &struct ath5k_hw - * @queue The queue number + * ath5k_hw_stop_beacon_queue() - Stop beacon queue + * @ah: The &struct ath5k_hw + * @queue: The queue number * * 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; ret = ath5k_hw_stop_tx_dma(ah, queue); @@ -340,8 +336,7 @@ int ath5k_hw_stop_beacon_queue(struct ath5k_hw *ah, unsigned int queue) } /** - * ath5k_hw_get_txdp - Get TX Descriptor's address for a specific queue - * + * ath5k_hw_get_txdp() - Get TX Descriptor's address for a specific queue * @ah: The &struct ath5k_hw * @queue: The hw queue number * @@ -352,7 +347,8 @@ int ath5k_hw_stop_beacon_queue(struct ath5k_hw *ah, unsigned int queue) * * XXX: Is TXDP read and clear ? */ -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; @@ -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 * @queue: The hw queue number + * @phys_addr: The physical address * * 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 @@ -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 * 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; @@ -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 * @increase: Flag to force increase of trigger level * @@ -444,15 +440,15 @@ int ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr) * buffer (aka FIFO threshold) that is used to indicate when PCU flushes * 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 - * result other problems (i think bmiss is related). Right now we start with - * the lowest possible (64Bytes) and if we get tx underrun we increase it using - * the increase flag. Returns -EIO if we have reached maximum/minimum. + * result other problems. Right now we start with the lowest possible + * (64Bytes) and if we get tx underrun we increase it using the increase + * flag. Returns -EIO if we have reached maximum/minimum. * * XXX: Link this with tx DMA size ? - * XXX: Use it to save interrupts ? - * TODO: Needs testing, i think it's related to bmiss... + * XXX2: Use it to save interrupts ? */ -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; int ret = -EIO; @@ -498,21 +494,20 @@ done: \*******************/ /** - * 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 * * Check if we have pending interrupts to process. Returns 1 if we * 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; } /** - * ath5k_hw_get_isr - Get interrupt status - * + * ath5k_hw_get_isr() - Get interrupt status * @ah: The @struct ath5k_hw * @interrupt_mask: Driver's interrupt mask used to filter out * interrupts in sw. @@ -523,62 +518,162 @@ bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah) * being mapped on some standard non hw-specific positions * (check out &ath5k_int). * - * NOTE: We use read-and-clear register, so after this function is called ISR - * is zeroed. + * NOTE: We do write-to-clear, so the active PISR/SISR bits at the time this + * 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 - * on 5210 + * Read interrupt status from Primary Interrupt + * Register. + * + * Note: PISR/SISR Not available on 5210 */ if (ah->ah_version == AR5K_AR5210) { - data = ath5k_hw_reg_read(ah, AR5K_ISR); - if (unlikely(data == AR5K_INT_NOCARD)) { - *interrupt_mask = data; + u32 isr = 0; + isr = ath5k_hw_reg_read(ah, AR5K_ISR); + if (unlikely(isr == AR5K_INT_NOCARD)) { + *interrupt_mask = isr; return -ENODEV; } - } else { + /* - * Read interrupt status from Interrupt - * Status Register shadow copy (Read And Clear) - * - * Note: PISR/SISR Not available on 5210 + * Filter out the non-common bits from the interrupt + * status. */ - data = ath5k_hw_reg_read(ah, AR5K_RAC_PISR); - if (unlikely(data == AR5K_INT_NOCARD)) { - *interrupt_mask = data; + *interrupt_mask = (isr & AR5K_INT_COMMON) & ah->ah_imr; + + /* 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; } - } - /* - * Get abstract interrupt mask (driver-compatible) - */ - *interrupt_mask = (data & AR5K_INT_COMMON) & ah->ah_imr; + sisr0 = ath5k_hw_reg_read(ah, AR5K_SISR0); + sisr1 = ath5k_hw_reg_read(ah, AR5K_SISR1); + sisr2 = ath5k_hw_reg_read(ah, AR5K_SISR2); + sisr3 = ath5k_hw_reg_read(ah, AR5K_SISR3); + sisr4 = ath5k_hw_reg_read(ah, AR5K_SISR4); - 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)*/ - if (unlikely(data & (AR5K_ISR_HIUERR))) - *interrupt_mask |= AR5K_INT_FATAL; + pisr_clear = pisr & ~AR5K_ISR_BITS_FROM_SISRS; - /*Beacon Not Ready*/ - if (unlikely(data & (AR5K_ISR_BNR))) - *interrupt_mask |= AR5K_INT_BNR; + /* + * Write to clear them... + * 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 | - AR5K_SISR2_MCABT))) - *interrupt_mask |= AR5K_INT_FATAL; + /* + * Filter out the non-common bits from the interrupt + * status. + */ + *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; - if (data & AR5K_ISR_BCNMISC) { + /* For AR5212+ */ + if (pisr & AR5K_ISR_BCNMISC) { if (sisr2 & AR5K_SISR2_TIM) *interrupt_mask |= AR5K_INT_TIM; if (sisr2 & AR5K_SISR2_DTIM) @@ -591,63 +686,39 @@ int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask) *interrupt_mask |= AR5K_INT_CAB_TIMEOUT; } - if (data & AR5K_ISR_RXDOPPLER) - *interrupt_mask |= AR5K_INT_RX_DOPPLER; - if (data & AR5K_ISR_QCBRORN) { + /* Below interrupts are unlikely to happen */ + + /* 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; - ah->ah_txq_isr |= AR5K_REG_MS( - ath5k_hw_reg_read(ah, AR5K_RAC_SISR3), - AR5K_SISR3_QCBRORN); + ah->ah_txq_isr_qcborn |= AR5K_REG_MS(sisr3, + AR5K_SISR3_QCBRORN); } - if (data & AR5K_ISR_QCBRURN) { + + /* A queue got CBR underrun */ + if (unlikely(pisr & (AR5K_ISR_QCBRURN))) { *interrupt_mask |= AR5K_INT_QCBRURN; - ah->ah_txq_isr |= AR5K_REG_MS( - ath5k_hw_reg_read(ah, AR5K_RAC_SISR3), - AR5K_SISR3_QCBRURN); + ah->ah_txq_isr_qcburn |= AR5K_REG_MS(sisr3, + AR5K_SISR3_QCBRURN); } - if (data & AR5K_ISR_QTRIG) { + + /* A queue got triggered */ + if (unlikely(pisr & (AR5K_ISR_QTRIG))) { *interrupt_mask |= AR5K_INT_QTRIG; - ah->ah_txq_isr |= AR5K_REG_MS( - ath5k_hw_reg_read(ah, AR5K_RAC_SISR4), - AR5K_SISR4_QTRIG); + ah->ah_txq_isr_qtrig |= AR5K_REG_MS(sisr4, + AR5K_SISR4_QTRIG); } - if (data & AR5K_ISR_TXOK) - 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; - */ + data = pisr; } /* @@ -661,8 +732,7 @@ int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask) } /** - * ath5k_hw_set_imr - Set interrupt mask - * + * ath5k_hw_set_imr() - Set interrupt mask * @ah: The &struct ath5k_hw * @new_mask: The new interrupt mask to be set * @@ -670,7 +740,8 @@ int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask) * ath5k_int bits to hw-specific bits to remove abstraction and writing * 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; @@ -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) & AR5K_SIMR2_QCU_TXURN; + /* Fatal interrupt abstraction for 5211+ */ if (new_mask & AR5K_INT_FATAL) { int_mask |= AR5K_IMR_HIUERR; simr2 |= (AR5K_SIMR2_MCABT | AR5K_SIMR2_SSERR | AR5K_SIMR2_DPERR); } - /*Beacon Not Ready*/ - if (new_mask & AR5K_INT_BNR) - int_mask |= AR5K_INT_BNR; - + /* Misc beacon related interrupts */ if (new_mask & AR5K_INT_TIM) int_mask |= AR5K_IMR_TIM; @@ -721,8 +790,9 @@ enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask) if (new_mask & AR5K_INT_CAB_TIMEOUT) simr2 |= AR5K_SISR2_CAB_TIMEOUT; - if (new_mask & AR5K_INT_RX_DOPPLER) - int_mask |= AR5K_IMR_RXDOPPLER; + /*Beacon Not Ready*/ + if (new_mask & AR5K_INT_BNR) + int_mask |= AR5K_INT_BNR; /* Note: Per queue interrupt masks * are set via ath5k_hw_reset_tx_queue() (qcu.c) */ @@ -730,10 +800,12 @@ enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask) ath5k_hw_reg_write(ah, simr2, AR5K_SIMR2); } else { + /* Fatal interrupt abstraction for 5210 */ if (new_mask & AR5K_INT_FATAL) int_mask |= (AR5K_IMR_SSERR | AR5K_IMR_MCABT | AR5K_IMR_HIUERR | AR5K_IMR_DPERR); + /* Only common interrupts left for 5210 (no SIMRs) */ ath5k_hw_reg_write(ah, int_mask, AR5K_IMR); } @@ -760,8 +832,7 @@ enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask) \********************/ /** - * ath5k_hw_dma_init - Initialize DMA unit - * + * ath5k_hw_dma_init() - Initialize DMA unit * @ah: The &struct ath5k_hw * * Set DMA size and pre-enable interrupts @@ -770,7 +841,8 @@ enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask) * * XXX: Save/restore RXDP/TXDP registers ? */ -void ath5k_hw_dma_init(struct ath5k_hw *ah) +void +ath5k_hw_dma_init(struct ath5k_hw *ah) { /* * Set Rx/Tx DMA Configuration @@ -799,8 +871,7 @@ void ath5k_hw_dma_init(struct ath5k_hw *ah) } /** - * ath5k_hw_dma_stop - stop DMA unit - * + * ath5k_hw_dma_stop() - stop DMA unit * @ah: The &struct ath5k_hw * * Stop tx/rx DMA and interrupts. Returns @@ -810,7 +881,8 @@ void ath5k_hw_dma_init(struct ath5k_hw *ah) * stuck frames on tx queues, only a reset * 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; err = 0; diff --git a/drivers/net/wireless/ath/ath5k/gpio.c b/drivers/net/wireless/ath/ath5k/gpio.c index 859297811914..73d3dd8a306a 100644 --- a/drivers/net/wireless/ath/ath5k/gpio.c +++ b/drivers/net/wireless/ath/ath5k/gpio.c @@ -24,10 +24,33 @@ #include "reg.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; /*5210 has different led mode handling*/ @@ -74,10 +97,13 @@ void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state) AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, led_5210); } -/* - * 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) return -EINVAL; @@ -89,10 +115,13 @@ int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio) 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) return -EINVAL; @@ -104,10 +133,13 @@ int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio) 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) return 0xffffffff; @@ -117,10 +149,14 @@ u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio) 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; @@ -138,10 +174,19 @@ int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val) 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 data; diff --git a/drivers/net/wireless/ath/ath5k/initvals.c b/drivers/net/wireless/ath/ath5k/initvals.c index 1ffecc0fd3ed..a1ea78e05b47 100644 --- a/drivers/net/wireless/ath/ath5k/initvals.c +++ b/drivers/net/wireless/ath/ath5k/initvals.c @@ -23,24 +23,27 @@ #include "reg.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 { u16 ini_register; u32 ini_value; enum { AR5K_INI_WRITE = 0, /* Default */ - AR5K_INI_READ = 1, /* Cleared on read */ + AR5K_INI_READ = 1, } 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 { u16 mode_register; u32 mode_value[3]; @@ -386,11 +389,10 @@ static const struct ath5k_ini ar5211_ini[] = { /* Initial mode-specific settings for AR5211 * 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[] = { { AR5K_TXCFG, - /* A/XR B G */ + /* A B G */ { 0x00000015, 0x0000001d, 0x00000015 } }, { AR5K_QUEUE_DFS_LOCAL_IFS(0), { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } }, @@ -460,7 +462,7 @@ static const struct ath5k_ini_mode ar5211_ini_mode[] = { { 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[] = { { AR5K_RXDP, 0x00000000 }, { AR5K_RXCFG, 0x00000005 }, @@ -724,7 +726,8 @@ static const struct ath5k_ini_mode ar5212_ini_mode_start[] = { { 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[] = { { AR5K_TXCFG, /* A/XR B G */ @@ -757,6 +760,7 @@ static const struct ath5k_ini_mode rf5111_ini_mode_end[] = { { 0x1883800a, 0x1873800a, 0x1883800a } }, }; +/* Common for all modes */ static const struct ath5k_ini rf5111_ini_common_end[] = { { AR5K_DCU_FP, 0x00000000 }, { AR5K_PHY_AGC, 0x00000000 }, @@ -774,7 +778,9 @@ static const struct ath5k_ini rf5111_ini_common_end[] = { { 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[] = { { AR5K_TXCFG, /* A/XR B G */ @@ -825,7 +831,9 @@ static const struct ath5k_ini rf5112_ini_common_end[] = { { 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[] = { { AR5K_TXCFG, /* A/XR B G */ @@ -963,7 +971,8 @@ static const struct ath5k_ini rf5413_ini_common_end[] = { { 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 ? */ static const struct ath5k_ini_mode rf2413_ini_mode_end[] = { { AR5K_TXCFG, @@ -1085,7 +1094,8 @@ static const struct ath5k_ini rf2413_ini_common_end[] = { { 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 ? */ static const struct ath5k_ini_mode rf2425_ini_mode_end[] = { { AR5K_TXCFG, @@ -1357,10 +1367,15 @@ static const struct ath5k_ini rf5112_ini_bbgain[] = { }; -/* - * Write initial register dump +/** + * ath5k_hw_ini_registers() - Write initial register dump common for all modes + * @ah: The &struct ath5k_hw + * @size: Dump size + * @ini_regs: The array of &struct ath5k_ini + * @skip_pcu: Skip PCU registers */ -static void ath5k_hw_ini_registers(struct ath5k_hw *ah, unsigned int size, +static void +ath5k_hw_ini_registers(struct ath5k_hw *ah, unsigned int size, const struct ath5k_ini *ini_regs, bool skip_pcu) { unsigned int i; @@ -1388,7 +1403,15 @@ static void ath5k_hw_ini_registers(struct ath5k_hw *ah, unsigned int size, } } -static void ath5k_hw_ini_mode_registers(struct ath5k_hw *ah, +/** + * ath5k_hw_ini_mode_registers() - Write initial mode-specific register dump + * @ah: The &struct ath5k_hw + * @size: Dump size + * @ini_mode: The array of &struct ath5k_ini_mode + * @mode: One of enum ath5k_driver_mode + */ +static void +ath5k_hw_ini_mode_registers(struct ath5k_hw *ah, unsigned int size, const struct ath5k_ini_mode *ini_mode, u8 mode) { @@ -1402,7 +1425,17 @@ static void ath5k_hw_ini_mode_registers(struct ath5k_hw *ah, } -int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool skip_pcu) +/** + * ath5k_hw_write_initvals() - Write initial chip-specific register dump + * @ah: The &struct ath5k_hw + * @mode: One of enum ath5k_driver_mode + * @skip_pcu: Skip PCU registers + * + * Write initial chip-specific register dump, to get the chipset on a + * clean and ready-to-work state after warm reset. + */ +int +ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool skip_pcu) { /* * Write initial register settings diff --git a/drivers/net/wireless/ath/ath5k/pci.c b/drivers/net/wireless/ath/ath5k/pci.c index dfa48eb7d953..849fa060ebc4 100644 --- a/drivers/net/wireless/ath/ath5k/pci.c +++ b/drivers/net/wireless/ath/ath5k/pci.c @@ -98,7 +98,7 @@ ath5k_pci_eeprom_read(struct ath_common *common, u32 offset, u16 *data) 0xffff); return true; } - udelay(15); + usleep_range(15, 20); } return false; diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index a7eafa3edc21..cebfd6fd31d3 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -30,11 +30,47 @@ #include "reg.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 * based on current tx rate instead of the base rate. * 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 * rate -> duration table. This mapping is hw-based so * don't change anything. @@ -63,17 +99,18 @@ static const unsigned int ack_rates_high[] = \*******************/ /** - * ath5k_hw_get_frame_duration - Get tx time of a frame - * + * ath5k_hw_get_frame_duration() - Get tx time of a frame * @ah: The &struct ath5k_hw * @len: Frame's length in bytes * @rate: The @struct ieee80211_rate + * @shortpre: Indicate short preample * * Calculate tx duration of a frame given it's rate and length * It extends ieee80211_generic_frame_duration for non standard * 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 sifs, preamble, plcp_bits, sym_time; @@ -129,11 +166,11 @@ int ath5k_hw_get_frame_duration(struct ath5k_hw *ah, } /** - * ath5k_hw_get_default_slottime - Get the default slot time for current mode - * + * ath5k_hw_get_default_slottime() - Get the default slot time for current mode * @ah: The &struct ath5k_hw */ -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; unsigned int slot_time; @@ -160,11 +197,11 @@ unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah) } /** - * ath5k_hw_get_default_sifs - Get the default SIFS for current mode - * + * ath5k_hw_get_default_sifs() - Get the default SIFS for current mode * @ah: The &struct ath5k_hw */ -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; unsigned int sifs; @@ -191,17 +228,17 @@ unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah) } /** - * ath5k_hw_update_mib_counters - Update MIB counters (mac layer statistics) - * + * ath5k_hw_update_mib_counters() - Update MIB counters (mac layer statistics) * @ah: The &struct ath5k_hw * * 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 * 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; @@ -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 - * - * @ah: the &struct ath5k_hw - * @mode: one of enum ath5k_driver_mode + * ath5k_hw_write_rate_duration() - Fill rate code to duration table + * @ah: The &struct ath5k_hw * * 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 @@ -236,7 +271,8 @@ void ath5k_hw_update_mib_counters(struct ath5k_hw *ah) * 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; unsigned int i; @@ -280,12 +316,12 @@ static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah) } /** - * ath5k_hw_set_ack_timeout - Set ACK timeout on PCU - * + * ath5k_hw_set_ack_timeout() - Set ACK timeout on PCU * @ah: The &struct ath5k_hw * @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)) <= 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 * @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)) <= 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 - * @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 */ -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); u32 low_id, high_id; @@ -349,14 +385,14 @@ int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac) } /** - * ath5k_hw_set_bssid - Set current BSSID on hw - * + * ath5k_hw_set_bssid() - Set current BSSID on hw * @ah: The &struct ath5k_hw * * Sets the current BSSID and BSSID mask we have from the * 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); u16 tim_offset = 0; @@ -389,7 +425,23 @@ void ath5k_hw_set_bssid(struct ath5k_hw *ah) 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); @@ -400,18 +452,21 @@ void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask) 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, 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 * * Returns the RX filter by reading rx filter and @@ -420,7 +475,8 @@ void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1) * and pass to the driver. For a list of frame types * 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; @@ -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 * @filter: RX filter mask (see reg.h) * @@ -449,7 +504,8 @@ u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah) * register on 5212 and newer chips so that we have proper PHY * 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; @@ -493,13 +549,13 @@ void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter) #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 * * 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; int i; @@ -536,28 +592,30 @@ u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah) 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 * @tsf64: The new 64bit 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 >> 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 * * 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; @@ -573,10 +631,17 @@ void ath5k_hw_reset_tsf(struct ath5k_hw *ah) 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; @@ -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) * @b: timer b (after a) * @window: difference between a and b @@ -686,12 +750,11 @@ ath5k_check_timer_win(int a, int b, int window, int intval) } /** - * ath5k_hw_check_beacon_timers - Check if the beacon timers are correct - * + * ath5k_hw_check_beacon_timers() - Check if the beacon timers are correct * @ah: The &struct ath5k_hw * @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 * HW timer registers (TIMER0 - TIMER3), which are closely related to the @@ -746,14 +809,14 @@ ath5k_hw_check_beacon_timers(struct ath5k_hw *ah, int intval) } /** - * ath5k_hw_set_coverage_class - Set IEEE 802.11 coverage class - * + * ath5k_hw_set_coverage_class() - Set IEEE 802.11 coverage class * @ah: The &struct ath5k_hw * @coverage_class: IEEE 802.11 coverage class number * * 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 */ int slot_time = ath5k_hw_get_default_slottime(ah) + 3 * coverage_class; @@ -772,8 +835,7 @@ void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class) \***************************/ /** - * ath5k_hw_start_rx_pcu - Start RX engine - * + * ath5k_hw_start_rx_pcu() - Start RX engine * @ah: The &struct ath5k_hw * * Starts RX engine on PCU so that hw can process RXed frames @@ -781,32 +843,33 @@ void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class) * * NOTE: RX DMA should be already enabled using ath5k_hw_start_rx_dma */ -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); } /** - * at5k_hw_stop_rx_pcu - Stop RX engine - * + * at5k_hw_stop_rx_pcu() - Stop RX engine * @ah: The &struct ath5k_hw * * 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); } /** - * ath5k_hw_set_opmode - Set PCU operating mode - * + * ath5k_hw_set_opmode() - Set PCU operating mode * @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) */ -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); u32 pcu_reg, beacon_reg, low_id, high_id; @@ -873,8 +936,17 @@ int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype op_mode) return 0; } -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 */ ath5k_hw_set_bssid(ah); diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 01cb72de44cb..e1f8613426a9 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -1,6 +1,4 @@ /* - * PHY functions - * * Copyright (c) 2004-2007 Reyk Floeter <reyk@openbsd.org> * Copyright (c) 2006-2009 Nick Kossifidis <mickflemm@gmail.com> * Copyright (c) 2007-2008 Jiri Slaby <jirislaby@gmail.com> @@ -20,6 +18,10 @@ * */ +/***********************\ +* PHY related functions * +\***********************/ + #include <linux/delay.h> #include <linux/slab.h> #include <asm/unaligned.h> @@ -31,14 +33,53 @@ #include "../regd.h" +/** + * DOC: PHY related functions + * + * Here we handle the low-level functions related to baseband + * and analog frontend (RF) parts. This is by far the most complex + * part of the hw code so make sure you know what you are doing. + * + * Here is a list of what this is all about: + * + * - Channel setting/switching + * + * - Automatic Gain Control (AGC) calibration + * + * - Noise Floor calibration + * + * - I/Q imbalance calibration (QAM correction) + * + * - Calibration due to thermal changes (gain_F) + * + * - Spur noise mitigation + * + * - RF/PHY initialization for the various operating modes and bwmodes + * + * - Antenna control + * + * - TX power control per channel/rate/packet type + * + * Also have in mind we never got documentation for most of these + * functions, what we have comes mostly from Atheros's code, reverse + * engineering and patent docs/presentations etc. + */ + + /******************\ * Helper functions * \******************/ -/* - * Get the PHY Chip revision +/** + * ath5k_hw_radio_revision() - Get the PHY Chip revision + * @ah: The &struct ath5k_hw + * @band: One of enum ieee80211_band + * + * Returns the revision number of a 2GHz, 5GHz or single chip + * radio. */ -u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, enum ieee80211_band band) +u16 +ath5k_hw_radio_revision(struct ath5k_hw *ah, enum ieee80211_band band) { unsigned int i; u32 srev; @@ -58,7 +99,7 @@ u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, enum ieee80211_band band) return 0; } - mdelay(2); + usleep_range(2000, 2500); /* ...wait until PHY is ready and read the selected radio revision */ ath5k_hw_reg_write(ah, 0x00001c16, AR5K_PHY(0x34)); @@ -81,10 +122,16 @@ u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, enum ieee80211_band band) return ret; } -/* - * Check if a channel is supported +/** + * ath5k_channel_ok() - Check if a channel is supported by the hw + * @ah: The &struct ath5k_hw + * @channel: The &struct ieee80211_channel + * + * Note: We don't do any regulatory domain checks here, it's just + * a sanity check. */ -bool ath5k_channel_ok(struct ath5k_hw *ah, struct ieee80211_channel *channel) +bool +ath5k_channel_ok(struct ath5k_hw *ah, struct ieee80211_channel *channel) { u16 freq = channel->center_freq; @@ -101,7 +148,13 @@ bool ath5k_channel_ok(struct ath5k_hw *ah, struct ieee80211_channel *channel) return false; } -bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah, +/** + * ath5k_hw_chan_has_spur_noise() - Check if channel is sensitive to spur noise + * @ah: The &struct ath5k_hw + * @channel: The &struct ieee80211_channel + */ +bool +ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah, struct ieee80211_channel *channel) { u8 refclk_freq; @@ -122,11 +175,20 @@ bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah, return false; } -/* - * Used to modify RF Banks before writing them to AR5K_RF_BUFFER +/** + * ath5k_hw_rfb_op() - Perform an operation on the given RF Buffer + * @ah: The &struct ath5k_hw + * @rf_regs: The struct ath5k_rf_reg + * @val: New value + * @reg_id: RF register ID + * @set: Indicate we need to swap data + * + * This is an internal function used to modify RF Banks before + * writing them to AR5K_RF_BUFFER. Check out rfbuffer.h for more + * infos. */ -static unsigned int ath5k_hw_rfb_op(struct ath5k_hw *ah, - const struct ath5k_rf_reg *rf_regs, +static unsigned int +ath5k_hw_rfb_op(struct ath5k_hw *ah, const struct ath5k_rf_reg *rf_regs, u32 val, u8 reg_id, bool set) { const struct ath5k_rf_reg *rfreg = NULL; @@ -204,8 +266,7 @@ static unsigned int ath5k_hw_rfb_op(struct ath5k_hw *ah, } /** - * ath5k_hw_write_ofdm_timings - set OFDM timings on AR5212 - * + * ath5k_hw_write_ofdm_timings() - set OFDM timings on AR5212 * @ah: the &struct ath5k_hw * @channel: the currently set channel upon reset * @@ -216,10 +277,11 @@ static unsigned int ath5k_hw_rfb_op(struct ath5k_hw *ah, * mantissa and provide these values on hw. * * For more infos i think this patent is related - * http://www.freepatentsonline.com/7184495.html + * "http://www.freepatentsonline.com/7184495.html" */ -static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah, - struct ieee80211_channel *channel) +static inline int +ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah, + struct ieee80211_channel *channel) { /* Get exponent and mantissa and set it */ u32 coef_scaled, coef_exp, coef_man, @@ -278,6 +340,10 @@ static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah, return 0; } +/** + * ath5k_hw_phy_disable() - Disable PHY + * @ah: The &struct ath5k_hw + */ int ath5k_hw_phy_disable(struct ath5k_hw *ah) { /*Just a try M.F.*/ @@ -286,10 +352,13 @@ int ath5k_hw_phy_disable(struct ath5k_hw *ah) return 0; } -/* - * Wait for synth to settle +/** + * ath5k_hw_wait_for_synth() - Wait for synth to settle + * @ah: The &struct ath5k_hw + * @channel: The &struct ieee80211_channel */ -static void ath5k_hw_wait_for_synth(struct ath5k_hw *ah, +static void +ath5k_hw_wait_for_synth(struct ath5k_hw *ah, struct ieee80211_channel *channel) { /* @@ -308,9 +377,9 @@ static void ath5k_hw_wait_for_synth(struct ath5k_hw *ah, delay = delay << 2; /* XXX: /2 on turbo ? Let's be safe * for now */ - udelay(100 + delay); + usleep_range(100 + delay, 100 + (2 * delay)); } else { - mdelay(1); + usleep_range(1000, 1500); } } @@ -319,7 +388,9 @@ static void ath5k_hw_wait_for_synth(struct ath5k_hw *ah, * RF Gain optimization * \**********************/ -/* +/** + * DOC: RF Gain optimization + * * This code is used to optimize RF gain on different environments * (temperature mostly) based on feedback from a power detector. * @@ -328,22 +399,22 @@ static void ath5k_hw_wait_for_synth(struct ath5k_hw *ah, * no gain optimization ladder-. * * For more infos check out this patent doc - * http://www.freepatentsonline.com/7400691.html + * "http://www.freepatentsonline.com/7400691.html" * * This paper describes power drops as seen on the receiver due to * probe packets - * http://www.cnri.dit.ie/publications/ICT08%20-%20Practical%20Issues - * %20of%20Power%20Control.pdf + * "http://www.cnri.dit.ie/publications/ICT08%20-%20Practical%20Issues + * %20of%20Power%20Control.pdf" * * And this is the MadWiFi bug entry related to the above - * http://madwifi-project.org/ticket/1659 + * "http://madwifi-project.org/ticket/1659" * with various measurements and diagrams - * - * TODO: Deal with power drops due to probes by setting an appropriate - * tx power on the probe packets ! Make this part of the calibration process. */ -/* Initialize ah_gain during attach */ +/** + * ath5k_hw_rfgain_opt_init() - Initialize ah_gain during attach + * @ah: The &struct ath5k_hw + */ int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah) { /* Initialize the gain optimization values */ @@ -367,17 +438,21 @@ int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah) return 0; } -/* Schedule a gain probe check on the next transmitted packet. +/** + * ath5k_hw_request_rfgain_probe() - Request a PAPD probe packet + * @ah: The &struct ath5k_hw + * + * Schedules a gain probe check on the next transmitted packet. * That means our next packet is going to be sent with lower * tx power and a Peak to Average Power Detector (PAPD) will try * to measure the gain. * - * XXX: How about forcing a tx packet (bypassing PCU arbitrator etc) + * TODO: Force a tx packet (bypassing PCU arbitrator etc) * just after we enable the probe so that we don't mess with - * standard traffic ? Maybe it's time to use sw interrupts and - * a probe tasklet !!! + * standard traffic. */ -static void ath5k_hw_request_rfgain_probe(struct ath5k_hw *ah) +static void +ath5k_hw_request_rfgain_probe(struct ath5k_hw *ah) { /* Skip if gain calibration is inactive or @@ -395,9 +470,15 @@ static void ath5k_hw_request_rfgain_probe(struct ath5k_hw *ah) } -/* Calculate gain_F measurement correction - * based on the current step for RF5112 rev. 2 */ -static u32 ath5k_hw_rf_gainf_corr(struct ath5k_hw *ah) +/** + * ath5k_hw_rf_gainf_corr() - Calculate Gain_F measurement correction + * @ah: The &struct ath5k_hw + * + * Calculate Gain_F measurement correction + * based on the current step for RF5112 rev. 2 + */ +static u32 +ath5k_hw_rf_gainf_corr(struct ath5k_hw *ah) { u32 mix, step; u32 *rf; @@ -450,11 +531,19 @@ static u32 ath5k_hw_rf_gainf_corr(struct ath5k_hw *ah) return ah->ah_gain.g_f_corr; } -/* Check if current gain_F measurement is in the range of our +/** + * ath5k_hw_rf_check_gainf_readback() - Validate Gain_F feedback from detector + * @ah: The &struct ath5k_hw + * + * Check if current gain_F measurement is in the range of our * power detector windows. If we get a measurement outside range * we know it's not accurate (detectors can't measure anything outside - * their detection window) so we must ignore it */ -static bool ath5k_hw_rf_check_gainf_readback(struct ath5k_hw *ah) + * their detection window) so we must ignore it. + * + * Returns true if readback was O.K. or false on failure + */ +static bool +ath5k_hw_rf_check_gainf_readback(struct ath5k_hw *ah) { const struct ath5k_rf_reg *rf_regs; u32 step, mix_ovr, level[4]; @@ -506,9 +595,15 @@ static bool ath5k_hw_rf_check_gainf_readback(struct ath5k_hw *ah) ah->ah_gain.g_current <= level[3]); } -/* Perform gain_F adjustment by choosing the right set - * of parameters from RF gain optimization ladder */ -static s8 ath5k_hw_rf_gainf_adjust(struct ath5k_hw *ah) +/** + * ath5k_hw_rf_gainf_adjust() - Perform Gain_F adjustment + * @ah: The &struct ath5k_hw + * + * Choose the right target gain based on current gain + * and RF gain optimization ladder + */ +static s8 +ath5k_hw_rf_gainf_adjust(struct ath5k_hw *ah) { const struct ath5k_gain_opt *go; const struct ath5k_gain_opt_step *g_step; @@ -572,13 +667,18 @@ done: return ret; } -/* Main callback for thermal RF gain calibration engine +/** + * ath5k_hw_gainf_calibrate() - Do a gain_F calibration + * @ah: The &struct ath5k_hw + * + * Main callback for thermal RF gain calibration engine * Check for a new gain reading and schedule an adjustment * if needed. * - * TODO: Use sw interrupt to schedule reset if gain_F needs - * adjustment */ -enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah) + * Returns one of enum ath5k_rfgain codes + */ +enum ath5k_rfgain +ath5k_hw_gainf_calibrate(struct ath5k_hw *ah) { u32 data, type; struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; @@ -638,10 +738,18 @@ done: return ah->ah_gain.g_state; } -/* Write initial RF gain table to set the RF sensitivity - * this one works on all RF chips and has nothing to do - * with gain_F calibration */ -static int ath5k_hw_rfgain_init(struct ath5k_hw *ah, enum ieee80211_band band) +/** + * ath5k_hw_rfgain_init() - Write initial RF gain settings to hw + * @ah: The &struct ath5k_hw + * @band: One of enum ieee80211_band + * + * Write initial RF gain table to set the RF sensitivity. + * + * NOTE: This one works on all RF chips and has nothing to do + * with Gain_F calibration + */ +static int +ath5k_hw_rfgain_init(struct ath5k_hw *ah, enum ieee80211_band band) { const struct ath5k_ini_rfgain *ath5k_rfg; unsigned int i, size, index; @@ -688,16 +796,23 @@ static int ath5k_hw_rfgain_init(struct ath5k_hw *ah, enum ieee80211_band band) } - /********************\ * RF Registers setup * \********************/ -/* - * Setup RF registers by writing RF buffer on hw +/** + * ath5k_hw_rfregs_init() - Initialize RF register settings + * @ah: The &struct ath5k_hw + * @channel: The &struct ieee80211_channel + * @mode: One of enum ath5k_driver_mode + * + * Setup RF registers by writing RF buffer on hw. For + * more infos on this, check out rfbuffer.h */ -static int ath5k_hw_rfregs_init(struct ath5k_hw *ah, - struct ieee80211_channel *channel, unsigned int mode) +static int +ath5k_hw_rfregs_init(struct ath5k_hw *ah, + struct ieee80211_channel *channel, + unsigned int mode) { const struct ath5k_rf_reg *rf_regs; const struct ath5k_ini_rfbuffer *ini_rfb; @@ -1055,19 +1170,18 @@ static int ath5k_hw_rfregs_init(struct ath5k_hw *ah, PHY/RF channel functions \**************************/ -/* - * Conversion needed for RF5110 +/** + * ath5k_hw_rf5110_chan2athchan() - Convert channel freq on RF5110 + * @channel: The &struct ieee80211_channel + * + * Map channel frequency to IEEE channel number and convert it + * to an internal channel value used by the RF5110 chipset. */ -static u32 ath5k_hw_rf5110_chan2athchan(struct ieee80211_channel *channel) +static u32 +ath5k_hw_rf5110_chan2athchan(struct ieee80211_channel *channel) { u32 athchan; - /* - * Convert IEEE channel/MHz to an internal channel value used - * by the AR5210 chipset. This has not been verified with - * newer chipsets like the AR5212A who have a completely - * different RF/PHY part. - */ athchan = (ath5k_hw_bitswap( (ieee80211_frequency_to_channel( channel->center_freq) - 24) / 2, 5) @@ -1075,10 +1189,13 @@ static u32 ath5k_hw_rf5110_chan2athchan(struct ieee80211_channel *channel) return athchan; } -/* - * Set channel on RF5110 +/** + * ath5k_hw_rf5110_channel() - Set channel frequency on RF5110 + * @ah: The &struct ath5k_hw + * @channel: The &struct ieee80211_channel */ -static int ath5k_hw_rf5110_channel(struct ath5k_hw *ah, +static int +ath5k_hw_rf5110_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel) { u32 data; @@ -1089,15 +1206,23 @@ static int ath5k_hw_rf5110_channel(struct ath5k_hw *ah, data = ath5k_hw_rf5110_chan2athchan(channel); ath5k_hw_reg_write(ah, data, AR5K_RF_BUFFER); ath5k_hw_reg_write(ah, 0, AR5K_RF_BUFFER_CONTROL_0); - mdelay(1); + usleep_range(1000, 1500); return 0; } -/* - * Conversion needed for 5111 +/** + * ath5k_hw_rf5111_chan2athchan() - Handle 2GHz channels on RF5111/2111 + * @ieee: IEEE channel number + * @athchan: The &struct ath5k_athchan_2ghz + * + * In order to enable the RF2111 frequency converter on RF5111/2111 setups + * we need to add some offsets and extra flags to the data values we pass + * on to the PHY. So for every 2GHz channel this function gets called + * to do the conversion. */ -static int ath5k_hw_rf5111_chan2athchan(unsigned int ieee, +static int +ath5k_hw_rf5111_chan2athchan(unsigned int ieee, struct ath5k_athchan_2ghz *athchan) { int channel; @@ -1123,10 +1248,13 @@ static int ath5k_hw_rf5111_chan2athchan(unsigned int ieee, return 0; } -/* - * Set channel on 5111 +/** + * ath5k_hw_rf5111_channel() - Set channel frequency on RF5111/2111 + * @ah: The &struct ath5k_hw + * @channel: The &struct ieee80211_channel */ -static int ath5k_hw_rf5111_channel(struct ath5k_hw *ah, +static int +ath5k_hw_rf5111_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel) { struct ath5k_athchan_2ghz ath5k_channel_2ghz; @@ -1171,10 +1299,20 @@ static int ath5k_hw_rf5111_channel(struct ath5k_hw *ah, return 0; } -/* - * Set channel on 5112 and newer +/** + * ath5k_hw_rf5112_channel() - Set channel frequency on 5112 and newer + * @ah: The &struct ath5k_hw + * @channel: The &struct ieee80211_channel + * + * On RF5112/2112 and newer we don't need to do any conversion. + * We pass the frequency value after a few modifications to the + * chip directly. + * + * NOTE: Make sure channel frequency given is within our range or else + * we might damage the chip ! Use ath5k_channel_ok before calling this one. */ -static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah, +static int +ath5k_hw_rf5112_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel) { u32 data, data0, data1, data2; @@ -1183,17 +1321,37 @@ static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah, data = data0 = data1 = data2 = 0; c = channel->center_freq; + /* My guess based on code: + * 2GHz RF has 2 synth modes, one with a Local Oscillator + * at 2224Hz and one with a LO at 2192Hz. IF is 1520Hz + * (3040/2). data0 is used to set the PLL divider and data1 + * selects synth mode. */ if (c < 4800) { + /* Channel 14 and all frequencies with 2Hz spacing + * below/above (non-standard channels) */ if (!((c - 2224) % 5)) { + /* Same as (c - 2224) / 5 */ data0 = ((2 * (c - 704)) - 3040) / 10; data1 = 1; + /* Channel 1 and all frequencies with 5Hz spacing + * below/above (standard channels without channel 14) */ } else if (!((c - 2192) % 5)) { + /* Same as (c - 2192) / 5 */ data0 = ((2 * (c - 672)) - 3040) / 10; data1 = 0; } else return -EINVAL; data0 = ath5k_hw_bitswap((data0 << 2) & 0xff, 8); + /* This is more complex, we have a single synthesizer with + * 4 reference clock settings (?) based on frequency spacing + * and set using data2. LO is at 4800Hz and data0 is again used + * to set some divider. + * + * NOTE: There is an old atheros presentation at Stanford + * that mentions a method called dual direct conversion + * with 1GHz sliding IF for RF5110. Maybe that's what we + * have here, or an updated version. */ } else if ((c % 5) != 2 || c > 5435) { if (!(c % 20) && c >= 5120) { data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8); @@ -1219,10 +1377,16 @@ static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah, return 0; } -/* - * Set the channel on the RF2425 +/** + * ath5k_hw_rf2425_channel() - Set channel frequency on RF2425 + * @ah: The &struct ath5k_hw + * @channel: The &struct ieee80211_channel + * + * AR2425/2417 have a different 2GHz RF so code changes + * a little bit from RF5112. */ -static int ath5k_hw_rf2425_channel(struct ath5k_hw *ah, +static int +ath5k_hw_rf2425_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel) { u32 data, data0, data2; @@ -1258,10 +1422,16 @@ static int ath5k_hw_rf2425_channel(struct ath5k_hw *ah, return 0; } -/* - * Set a channel on the radio chip +/** + * ath5k_hw_channel() - Set a channel on the radio chip + * @ah: The &struct ath5k_hw + * @channel: The &struct ieee80211_channel + * + * This is the main function called to set a channel on the + * radio chip based on the radio chip version. */ -static int ath5k_hw_channel(struct ath5k_hw *ah, +static int +ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel) { int ret; @@ -1313,11 +1483,46 @@ static int ath5k_hw_channel(struct ath5k_hw *ah, return 0; } + /*****************\ PHY calibration \*****************/ -static s32 ath5k_hw_read_measured_noise_floor(struct ath5k_hw *ah) +/** + * DOC: PHY Calibration routines + * + * Noise floor calibration: When we tell the hardware to + * perform a noise floor calibration by setting the + * AR5K_PHY_AGCCTL_NF bit on AR5K_PHY_AGCCTL, it will periodically + * sample-and-hold the minimum noise level seen at the antennas. + * This value is then stored in a ring buffer of recently measured + * noise floor values so we have a moving window of the last few + * samples. The median of the values in the history is then loaded + * into the hardware for its own use for RSSI and CCA measurements. + * This type of calibration doesn't interfere with traffic. + * + * AGC calibration: When we tell the hardware to perform + * an AGC (Automatic Gain Control) calibration by setting the + * AR5K_PHY_AGCCTL_CAL, hw disconnects the antennas and does + * a calibration on the DC offsets of ADCs. During this period + * rx/tx gets disabled so we have to deal with it on the driver + * part. + * + * I/Q calibration: When we tell the hardware to perform + * an I/Q calibration, it tries to correct I/Q imbalance and + * fix QAM constellation by sampling data from rxed frames. + * It doesn't interfere with traffic. + * + * For more infos on AGC and I/Q calibration check out patent doc + * #03/094463. + */ + +/** + * ath5k_hw_read_measured_noise_floor() - Read measured NF from hw + * @ah: The &struct ath5k_hw + */ +static s32 +ath5k_hw_read_measured_noise_floor(struct ath5k_hw *ah) { s32 val; @@ -1325,7 +1530,12 @@ static s32 ath5k_hw_read_measured_noise_floor(struct ath5k_hw *ah) return sign_extend32(AR5K_REG_MS(val, AR5K_PHY_NF_MINCCA_PWR), 8); } -void ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah) +/** + * ath5k_hw_init_nfcal_hist() - Initialize NF calibration history buffer + * @ah: The &struct ath5k_hw + */ +void +ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah) { int i; @@ -1334,6 +1544,11 @@ void ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah) ah->ah_nfcal_hist.nfval[i] = AR5K_TUNE_CCA_MAX_GOOD_VALUE; } +/** + * ath5k_hw_update_nfcal_hist() - Update NF calibration history buffer + * @ah: The &struct ath5k_hw + * @noise_floor: The NF we got from hw + */ static void ath5k_hw_update_nfcal_hist(struct ath5k_hw *ah, s16 noise_floor) { struct ath5k_nfcal_hist *hist = &ah->ah_nfcal_hist; @@ -1341,7 +1556,12 @@ static void ath5k_hw_update_nfcal_hist(struct ath5k_hw *ah, s16 noise_floor) hist->nfval[hist->index] = noise_floor; } -static s16 ath5k_hw_get_median_noise_floor(struct ath5k_hw *ah) +/** + * ath5k_hw_get_median_noise_floor() - Get median NF from history buffer + * @ah: The &struct ath5k_hw + */ +static s16 +ath5k_hw_get_median_noise_floor(struct ath5k_hw *ah) { s16 sort[ATH5K_NF_CAL_HIST_MAX]; s16 tmp; @@ -1364,18 +1584,16 @@ static s16 ath5k_hw_get_median_noise_floor(struct ath5k_hw *ah) return sort[(ATH5K_NF_CAL_HIST_MAX - 1) / 2]; } -/* - * When we tell the hardware to perform a noise floor calibration - * by setting the AR5K_PHY_AGCCTL_NF bit, it will periodically - * sample-and-hold the minimum noise level seen at the antennas. - * This value is then stored in a ring buffer of recently measured - * noise floor values so we have a moving window of the last few - * samples. +/** + * ath5k_hw_update_noise_floor() - Update NF on hardware + * @ah: The &struct ath5k_hw * - * The median of the values in the history is then loaded into the - * hardware for its own use for RSSI and CCA measurements. + * This is the main function we call to perform a NF calibration, + * it reads NF from hardware, calculates the median and updates + * NF on hw. */ -void ath5k_hw_update_noise_floor(struct ath5k_hw *ah) +void +ath5k_hw_update_noise_floor(struct ath5k_hw *ah) { struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; u32 val; @@ -1390,6 +1608,8 @@ void ath5k_hw_update_noise_floor(struct ath5k_hw *ah) return; } + ah->ah_cal_mask |= AR5K_CALIBRATION_NF; + ee_mode = ath5k_eeprom_mode_from_channel(ah->ah_current_channel); /* completed NF calibration, test threshold */ @@ -1434,20 +1654,29 @@ void ath5k_hw_update_noise_floor(struct ath5k_hw *ah) ah->ah_noise_floor = nf; + ah->ah_cal_mask &= ~AR5K_CALIBRATION_NF; + ATH5K_DBG(ah, ATH5K_DEBUG_CALIBRATE, "noise floor calibrated: %d\n", nf); } -/* - * Perform a PHY calibration on RF5110 - * -Fix BPSK/QAM Constellation (I/Q correction) +/** + * ath5k_hw_rf5110_calibrate() - Perform a PHY calibration on RF5110 + * @ah: The &struct ath5k_hw + * @channel: The &struct ieee80211_channel + * + * Do a complete PHY calibration (AGC + NF + I/Q) on RF5110 */ -static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, +static int +ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, struct ieee80211_channel *channel) { u32 phy_sig, phy_agc, phy_sat, beacon; int ret; + if (!(ah->ah_cal_mask & AR5K_CALIBRATION_FULL)) + return 0; + /* * Disable beacons and RX/TX queues, wait */ @@ -1456,7 +1685,7 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, beacon = ath5k_hw_reg_read(ah, AR5K_BEACON_5210); ath5k_hw_reg_write(ah, beacon & ~AR5K_BEACON_ENABLE, AR5K_BEACON_5210); - mdelay(2); + usleep_range(2000, 2500); /* * Set the channel (with AGC turned off) @@ -1469,7 +1698,7 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, * Activate PHY and wait */ ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT); - mdelay(1); + usleep_range(1000, 1500); AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE); @@ -1506,7 +1735,7 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, ath5k_hw_reg_write(ah, AR5K_PHY_RFSTG_DISABLE, AR5K_PHY_RFSTG); AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE); - mdelay(1); + usleep_range(1000, 1500); /* * Enable calibration and wait until completion @@ -1537,8 +1766,9 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, return 0; } -/* - * Perform I/Q calibration on RF5111/5112 and newer chips +/** + * ath5k_hw_rf511x_iq_calibrate() - Perform I/Q calibration on RF5111 and newer + * @ah: The &struct ath5k_hw */ static int ath5k_hw_rf511x_iq_calibrate(struct ath5k_hw *ah) @@ -1547,12 +1777,19 @@ ath5k_hw_rf511x_iq_calibrate(struct ath5k_hw *ah) s32 iq_corr, i_coff, i_coffd, q_coff, q_coffd; int i; - if (!ah->ah_calibration || - ath5k_hw_reg_read(ah, AR5K_PHY_IQ) & AR5K_PHY_IQ_RUN) - return 0; + /* Skip if I/Q calibration is not needed or if it's still running */ + if (!ah->ah_iq_cal_needed) + return -EINVAL; + else if (ath5k_hw_reg_read(ah, AR5K_PHY_IQ) & AR5K_PHY_IQ_RUN) { + ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_CALIBRATE, + "I/Q calibration still running"); + return -EBUSY; + } /* Calibration has finished, get the results and re-run */ - /* work around empty results which can apparently happen on 5212 */ + + /* Work around for empty results which can apparently happen on 5212: + * Read registers up to 10 times until we get both i_pr and q_pwr */ for (i = 0; i <= 10; i++) { iq_corr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_CORR); i_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_I); @@ -1570,9 +1807,13 @@ ath5k_hw_rf511x_iq_calibrate(struct ath5k_hw *ah) else q_coffd = q_pwr >> 7; - /* protect against divide by 0 and loss of sign bits */ + /* In case i_coffd became zero, cancel calibration + * not only it's too small, it'll also result a divide + * by zero later on. */ if (i_coffd == 0 || q_coffd < 2) - return 0; + return -ECANCELED; + + /* Protect against loss of sign bits */ i_coff = (-iq_corr) / i_coffd; i_coff = clamp(i_coff, -32, 31); /* signed 6 bit */ @@ -1601,10 +1842,17 @@ ath5k_hw_rf511x_iq_calibrate(struct ath5k_hw *ah) return 0; } -/* - * Perform a PHY calibration +/** + * ath5k_hw_phy_calibrate() - Perform a PHY calibration + * @ah: The &struct ath5k_hw + * @channel: The &struct ieee80211_channel + * + * The main function we call from above to perform + * a short or full PHY calibration based on RF chip + * and current channel */ -int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, +int +ath5k_hw_phy_calibrate(struct ath5k_hw *ah, struct ieee80211_channel *channel) { int ret; @@ -1613,10 +1861,43 @@ int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, return ath5k_hw_rf5110_calibrate(ah, channel); ret = ath5k_hw_rf511x_iq_calibrate(ah); + if (ret) { + ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_CALIBRATE, + "No I/Q correction performed (%uMHz)\n", + channel->center_freq); + + /* Happens all the time if there is not much + * traffic, consider it normal behaviour. */ + ret = 0; + } + + /* On full calibration do an AGC calibration and + * request a PAPD probe for gainf calibration if + * needed */ + if (ah->ah_cal_mask & AR5K_CALIBRATION_FULL) { - if ((ah->ah_radio == AR5K_RF5111 || ah->ah_radio == AR5K_RF5112) && - (channel->hw_value != AR5K_MODE_11B)) - ath5k_hw_request_rfgain_probe(ah); + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, + AR5K_PHY_AGCCTL_CAL); + + ret = ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL, + AR5K_PHY_AGCCTL_CAL | AR5K_PHY_AGCCTL_NF, + 0, false); + if (ret) { + ATH5K_ERR(ah, + "gain calibration timeout (%uMHz)\n", + channel->center_freq); + } + + if ((ah->ah_radio == AR5K_RF5111 || + ah->ah_radio == AR5K_RF5112) + && (channel->hw_value != AR5K_MODE_11B)) + ath5k_hw_request_rfgain_probe(ah); + } + + /* Update noise floor + * XXX: Only do this after AGC calibration */ + if (!(ah->ah_cal_mask & AR5K_CALIBRATION_NF)) + ath5k_hw_update_noise_floor(ah); return ret; } @@ -1626,6 +1907,16 @@ int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, * Spur mitigation functions * \***************************/ +/** + * ath5k_hw_set_spur_mitigation_filter() - Configure SPUR filter + * @ah: The &struct ath5k_hw + * @channel: The &struct ieee80211_channel + * + * This function gets called during PHY initialization to + * configure the spur filter for the given channel. Spur is noise + * generated due to "reflection" effects, for more information on this + * method check out patent US7643810 + */ static void ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah, struct ieee80211_channel *channel) @@ -1865,15 +2156,73 @@ ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah, * Antenna control * \*****************/ -static void /*TODO:Boundary check*/ +/** + * DOC: Antenna control + * + * Hw supports up to 14 antennas ! I haven't found any card that implements + * that. The maximum number of antennas I've seen is up to 4 (2 for 2GHz and 2 + * for 5GHz). Antenna 1 (MAIN) should be omnidirectional, 2 (AUX) + * omnidirectional or sectorial and antennas 3-14 sectorial (or directional). + * + * We can have a single antenna for RX and multiple antennas for TX. + * RX antenna is our "default" antenna (usually antenna 1) set on + * DEFAULT_ANTENNA register and TX antenna is set on each TX control descriptor + * (0 for automatic selection, 1 - 14 antenna number). + * + * We can let hw do all the work doing fast antenna diversity for both + * tx and rx or we can do things manually. Here are the options we have + * (all are bits of STA_ID1 register): + * + * AR5K_STA_ID1_DEFAULT_ANTENNA -> When 0 is set as the TX antenna on TX + * control descriptor, use the default antenna to transmit or else use the last + * antenna on which we received an ACK. + * + * AR5K_STA_ID1_DESC_ANTENNA -> Update default antenna after each TX frame to + * the antenna on which we got the ACK for that frame. + * + * AR5K_STA_ID1_RTS_DEF_ANTENNA -> Use default antenna for RTS or else use the + * one on the TX descriptor. + * + * AR5K_STA_ID1_SELFGEN_DEF_ANT -> Use default antenna for self generated frames + * (ACKs etc), or else use current antenna (the one we just used for TX). + * + * Using the above we support the following scenarios: + * + * AR5K_ANTMODE_DEFAULT -> Hw handles antenna diversity etc automatically + * + * AR5K_ANTMODE_FIXED_A -> Only antenna A (MAIN) is present + * + * AR5K_ANTMODE_FIXED_B -> Only antenna B (AUX) is present + * + * AR5K_ANTMODE_SINGLE_AP -> Sta locked on a single ap + * + * AR5K_ANTMODE_SECTOR_AP -> AP with tx antenna set on tx desc + * + * AR5K_ANTMODE_SECTOR_STA -> STA with tx antenna set on tx desc + * + * AR5K_ANTMODE_DEBUG Debug mode -A -> Rx, B-> Tx- + * + * Also note that when setting antenna to F on tx descriptor card inverts + * current tx antenna. + */ + +/** + * ath5k_hw_set_def_antenna() - Set default rx antenna on AR5211/5212 and newer + * @ah: The &struct ath5k_hw + * @ant: Antenna number + */ +static void ath5k_hw_set_def_antenna(struct ath5k_hw *ah, u8 ant) { if (ah->ah_version != AR5K_AR5210) ath5k_hw_reg_write(ah, ant & 0x7, AR5K_DEFAULT_ANTENNA); } -/* - * Enable/disable fast rx antenna diversity +/** + * ath5k_hw_set_fast_div() - Enable/disable fast rx antenna diversity + * @ah: The &struct ath5k_hw + * @ee_mode: One of enum ath5k_driver_mode + * @enable: True to enable, false to disable */ static void ath5k_hw_set_fast_div(struct ath5k_hw *ah, u8 ee_mode, bool enable) @@ -1913,6 +2262,14 @@ ath5k_hw_set_fast_div(struct ath5k_hw *ah, u8 ee_mode, bool enable) } } +/** + * ath5k_hw_set_antenna_switch() - Set up antenna switch table + * @ah: The &struct ath5k_hw + * @ee_mode: One of enum ath5k_driver_mode + * + * Switch table comes from EEPROM and includes information on controlling + * the 2 antenna RX attenuators + */ void ath5k_hw_set_antenna_switch(struct ath5k_hw *ah, u8 ee_mode) { @@ -1944,8 +2301,10 @@ ath5k_hw_set_antenna_switch(struct ath5k_hw *ah, u8 ee_mode) AR5K_PHY_ANT_SWITCH_TABLE_1); } -/* - * Set antenna operating mode +/** + * ath5k_hw_set_antenna_mode() - Set antenna operating mode + * @ah: The &struct ath5k_hw + * @ant_mode: One of enum ath5k_ant_mode */ void ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode) @@ -2068,8 +2427,13 @@ ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode) * Helper functions */ -/* - * Do linear interpolation between two given (x, y) points +/** + * ath5k_get_interpolated_value() - Get interpolated Y val between two points + * @target: X value of the middle point + * @x_left: X value of the left point + * @x_right: X value of the right point + * @y_left: Y value of the left point + * @y_right: Y value of the right point */ static s16 ath5k_get_interpolated_value(s16 target, s16 x_left, s16 x_right, @@ -2096,13 +2460,18 @@ ath5k_get_interpolated_value(s16 target, s16 x_left, s16 x_right, return result; } -/* - * Find vertical boundary (min pwr) for the linear PCDAC curve. +/** + * ath5k_get_linear_pcdac_min() - Find vertical boundary (min pwr) for the + * linear PCDAC curve + * @stepL: Left array with y values (pcdac steps) + * @stepR: Right array with y values (pcdac steps) + * @pwrL: Left array with x values (power steps) + * @pwrR: Right array with x values (power steps) * * Since we have the top of the curve and we draw the line below * until we reach 1 (1 pcdac step) we need to know which point - * (x value) that is so that we don't go below y axis and have negative - * pcdac values when creating the curve, or fill the table with zeroes. + * (x value) that is so that we don't go below x axis and have negative + * pcdac values when creating the curve, or fill the table with zeros. */ static s16 ath5k_get_linear_pcdac_min(const u8 *stepL, const u8 *stepR, @@ -2148,7 +2517,16 @@ ath5k_get_linear_pcdac_min(const u8 *stepL, const u8 *stepR, return max(min_pwrL, min_pwrR); } -/* +/** + * ath5k_create_power_curve() - Create a Power to PDADC or PCDAC curve + * @pmin: Minimum power value (xmin) + * @pmax: Maximum power value (xmax) + * @pwr: Array of power steps (x values) + * @vpd: Array of matching PCDAC/PDADC steps (y values) + * @num_points: Number of provided points + * @vpd_table: Array to fill with the full PCDAC/PDADC values (y values) + * @type: One of enum ath5k_powertable_type (eeprom.h) + * * Interpolate (pwr,vpd) points to create a Power to PDADC or a * Power to PCDAC curve. * @@ -2206,7 +2584,14 @@ ath5k_create_power_curve(s16 pmin, s16 pmax, } } -/* +/** + * ath5k_get_chan_pcal_surrounding_piers() - Get surrounding calibration piers + * for a given channel. + * @ah: The &struct ath5k_hw + * @channel: The &struct ieee80211_channel + * @pcinfo_l: The &struct ath5k_chan_pcal_info to put the left cal. pier + * @pcinfo_r: The &struct ath5k_chan_pcal_info to put the right cal. pier + * * Get the surrounding per-channel power calibration piers * for a given frequency so that we can interpolate between * them and come up with an appropriate dataset for our current @@ -2289,11 +2674,17 @@ done: *pcinfo_r = &pcinfo[idx_r]; } -/* +/** + * ath5k_get_rate_pcal_data() - Get the interpolated per-rate power + * calibration data + * @ah: The &struct ath5k_hw *ah, + * @channel: The &struct ieee80211_channel + * @rates: The &struct ath5k_rate_pcal_info to fill + * * Get the surrounding per-rate power calibration data * for a given frequency and interpolate between power * values to set max target power supported by hw for - * each rate. + * each rate on this frequency. */ static void ath5k_get_rate_pcal_data(struct ath5k_hw *ah, @@ -2381,7 +2772,11 @@ done: rpinfo[idx_r].target_power_54); } -/* +/** + * ath5k_get_max_ctl_power() - Get max edge power for a given frequency + * @ah: the &struct ath5k_hw + * @channel: The &struct ieee80211_channel + * * Get the max edge power for this channel if * we have such data from EEPROM's Conformance Test * Limits (CTL), and limit max power if needed. @@ -2461,8 +2856,39 @@ ath5k_get_max_ctl_power(struct ath5k_hw *ah, * Power to PCDAC table functions */ -/* - * Fill Power to PCDAC table on RF5111 +/** + * DOC: Power to PCDAC table functions + * + * For RF5111 we have an XPD -eXternal Power Detector- curve + * for each calibrated channel. Each curve has 0,5dB Power steps + * on x axis and PCDAC steps (offsets) on y axis and looks like an + * exponential function. To recreate the curve we read 11 points + * from eeprom (eeprom.c) and interpolate here. + * + * For RF5112 we have 4 XPD -eXternal Power Detector- curves + * for each calibrated channel on 0, -6, -12 and -18dBm but we only + * use the higher (3) and the lower (0) curves. Each curve again has 0.5dB + * power steps on x axis and PCDAC steps on y axis and looks like a + * linear function. To recreate the curve and pass the power values + * on hw, we get 4 points for xpd 0 (lower gain -> max power) + * and 3 points for xpd 3 (higher gain -> lower power) from eeprom (eeprom.c) + * and interpolate here. + * + * For a given channel we get the calibrated points (piers) for it or + * -if we don't have calibration data for this specific channel- from the + * available surrounding channels we have calibration data for, after we do a + * linear interpolation between them. Then since we have our calibrated points + * for this channel, we do again a linear interpolation between them to get the + * whole curve. + * + * We finally write the Y values of the curve(s) (the PCDAC values) on hw + */ + +/** + * ath5k_fill_pwr_to_pcdac_table() - Fill Power to PCDAC table on RF5111 + * @ah: The &struct ath5k_hw + * @table_min: Minimum power (x min) + * @table_max: Maximum power (x max) * * No further processing is needed for RF5111, the only thing we have to * do is fill the values below and above calibration range since eeprom data @@ -2503,10 +2929,14 @@ ath5k_fill_pwr_to_pcdac_table(struct ath5k_hw *ah, s16* table_min, } -/* - * Combine available XPD Curves and fill Linear Power to PCDAC table - * on RF5112 +/** + * ath5k_combine_linear_pcdac_curves() - Combine available PCDAC Curves + * @ah: The &struct ath5k_hw + * @table_min: Minimum power (x min) + * @table_max: Maximum power (x max) + * @pdcurves: Number of pd curves * + * Combine available XPD Curves and fill Linear Power to PCDAC table on RF5112 * RFX112 can have up to 2 curves (one for low txpower range and one for * higher txpower range). We need to put them both on pcdac_out and place * them in the correct location. In case we only have one curve available @@ -2608,7 +3038,10 @@ ath5k_combine_linear_pcdac_curves(struct ath5k_hw *ah, s16* table_min, } } -/* Write PCDAC values on hw */ +/** + * ath5k_write_pcdac_table() - Write the PCDAC values on hw + * @ah: The &struct ath5k_hw + */ static void ath5k_write_pcdac_table(struct ath5k_hw *ah) { @@ -2631,9 +3064,32 @@ ath5k_write_pcdac_table(struct ath5k_hw *ah) * Power to PDADC table functions */ -/* - * Set the gain boundaries and create final Power to PDADC table +/** + * DOC: Power to PDADC table functions + * + * For RF2413 and later we have a Power to PDADC table (Power Detector) + * instead of a PCDAC (Power Control) and 4 pd gain curves for each + * calibrated channel. Each curve has power on x axis in 0.5 db steps and + * PDADC steps on y axis and looks like an exponential function like the + * RF5111 curve. + * + * To recreate the curves we read the points from eeprom (eeprom.c) + * and interpolate here. Note that in most cases only 2 (higher and lower) + * curves are used (like RF5112) but vendors have the opportunity to include + * all 4 curves on eeprom. The final curve (higher power) has an extra + * point for better accuracy like RF5112. * + * The process is similar to what we do above for RF5111/5112 + */ + +/** + * ath5k_combine_pwr_to_pdadc_curves() - Combine the various PDADC curves + * @ah: The &struct ath5k_hw + * @pwr_min: Minimum power (x min) + * @pwr_max: Maximum power (x max) + * @pdcurves: Number of available curves + * + * Combine the various pd curves and create the final Power to PDADC table * We can have up to 4 pd curves, we need to do a similar process * as we do for RF5112. This time we don't have an edge_flag but we * set the gain boundaries on a separate register. @@ -2757,7 +3213,11 @@ ath5k_combine_pwr_to_pdadc_curves(struct ath5k_hw *ah, } -/* Write PDADC values on hw */ +/** + * ath5k_write_pwr_to_pdadc_table() - Write the PDADC values on hw + * @ah: The &struct ath5k_hw + * @ee_mode: One of enum ath5k_driver_mode + */ static void ath5k_write_pwr_to_pdadc_table(struct ath5k_hw *ah, u8 ee_mode) { @@ -2814,7 +3274,13 @@ ath5k_write_pwr_to_pdadc_table(struct ath5k_hw *ah, u8 ee_mode) * Common code for PCDAC/PDADC tables */ -/* +/** + * ath5k_setup_channel_powertable() - Set up power table for this channel + * @ah: The &struct ath5k_hw + * @channel: The &struct ieee80211_channel + * @ee_mode: One of enum ath5k_driver_mode + * @type: One of enum ath5k_powertable_type (eeprom.h) + * * This is the main function that uses all of the above * to set PCDAC/PDADC table on hw for the current channel. * This table is used for tx power calibration on the baseband, @@ -3012,7 +3478,12 @@ ath5k_setup_channel_powertable(struct ath5k_hw *ah, return 0; } -/* Write power table for current channel to hw */ +/** + * ath5k_write_channel_powertable() - Set power table for current channel on hw + * @ah: The &struct ath5k_hw + * @ee_mode: One of enum ath5k_driver_mode + * @type: One of enum ath5k_powertable_type (eeprom.h) + */ static void ath5k_write_channel_powertable(struct ath5k_hw *ah, u8 ee_mode, u8 type) { @@ -3022,28 +3493,36 @@ ath5k_write_channel_powertable(struct ath5k_hw *ah, u8 ee_mode, u8 type) ath5k_write_pcdac_table(ah); } -/* - * Per-rate tx power setting + +/** + * DOC: Per-rate tx power setting * - * This is the code that sets the desired tx power (below + * This is the code that sets the desired tx power limit (below * maximum) on hw for each rate (we also have TPC that sets - * power per packet). We do that by providing an index on the - * PCDAC/PDADC table we set up. - */ - -/* - * Set rate power table + * power per packet type). We do that by providing an index on the + * PCDAC/PDADC table we set up above, for each rate. * * For now we only limit txpower based on maximum tx power - * supported by hw (what's inside rate_info). We need to limit - * this even more, based on regulatory domain etc. + * supported by hw (what's inside rate_info) + conformance test + * limits. We need to limit this even more, based on regulatory domain + * etc to be safe. Normally this is done from above so we don't care + * here, all we care is that the tx power we set will be O.K. + * for the hw (e.g. won't create noise on PA etc). * - * Rate power table contains indices to PCDAC/PDADC table (0.5dB steps) - * and is indexed as follows: + * Rate power table contains indices to PCDAC/PDADC table (0.5dB steps - + * x values) and is indexed as follows: * rates[0] - rates[7] -> OFDM rates * rates[8] - rates[14] -> CCK rates * rates[15] -> XR rates (they all have the same power) */ + +/** + * ath5k_setup_rate_powertable() - Set up rate power table for a given tx power + * @ah: The &struct ath5k_hw + * @max_pwr: The maximum tx power requested in 0.5dB steps + * @rate_info: The &struct ath5k_rate_pcal_info to fill + * @ee_mode: One of enum ath5k_driver_mode + */ static void ath5k_setup_rate_powertable(struct ath5k_hw *ah, u16 max_pwr, struct ath5k_rate_pcal_info *rate_info, @@ -3114,8 +3593,14 @@ ath5k_setup_rate_powertable(struct ath5k_hw *ah, u16 max_pwr, } -/* - * Set transmission power +/** + * ath5k_hw_txpower() - Set transmission power limit for a given channel + * @ah: The &struct ath5k_hw + * @channel: The &struct ieee80211_channel + * @txpower: Requested tx power in 0.5dB steps + * + * Combines all of the above to set the requested tx power limit + * on hw. */ static int ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, @@ -3233,7 +3718,16 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, return 0; } -int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower) +/** + * ath5k_hw_set_txpower_limit() - Set txpower limit for the current channel + * @ah: The &struct ath5k_hw + * @txpower: The requested tx power limit in 0.5dB steps + * + * This function provides access to ath5k_hw_txpower to the driver in + * case user or an application changes it while PHY is running. + */ +int +ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower) { ATH5K_DBG(ah, ATH5K_DEBUG_TXPOWER, "changing txpower to %d\n", txpower); @@ -3241,11 +3735,26 @@ int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower) return ath5k_hw_txpower(ah, ah->ah_current_channel, txpower); } + /*************\ Init function \*************/ -int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel, +/** + * ath5k_hw_phy_init() - Initialize PHY + * @ah: The &struct ath5k_hw + * @channel: The @struct ieee80211_channel + * @mode: One of enum ath5k_driver_mode + * @fast: Try a fast channel switch instead + * + * This is the main function used during reset to initialize PHY + * or do a fast channel change if possible. + * + * NOTE: Do not call this one from the driver, it assumes PHY is in a + * warm reset state ! + */ +int +ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel, u8 mode, bool fast) { struct ieee80211_channel *curr_channel; @@ -3355,7 +3864,7 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel, if (ret) return ret; - mdelay(1); + usleep_range(1000, 1500); /* * Write RF buffer @@ -3376,10 +3885,10 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel, } } else if (ah->ah_version == AR5K_AR5210) { - mdelay(1); + usleep_range(1000, 1500); /* Disable phy and wait */ ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT); - mdelay(1); + usleep_range(1000, 1500); } /* Set channel on PHY */ @@ -3405,7 +3914,7 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel, for (i = 0; i <= 20; i++) { if (!(ath5k_hw_reg_read(ah, AR5K_PHY_ADC_TEST) & 0x10)) break; - udelay(200); + usleep_range(200, 250); } ath5k_hw_reg_write(ah, phy_tst1, AR5K_PHY_TST1); @@ -3433,9 +3942,9 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel, /* At the same time start I/Q calibration for QAM constellation * -no need for CCK- */ - ah->ah_calibration = false; + ah->ah_iq_cal_needed = false; if (!(mode == AR5K_MODE_11B)) { - ah->ah_calibration = true; + ah->ah_iq_cal_needed = true; AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15); AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c index 776654228eaa..30b50f934172 100644 --- a/drivers/net/wireless/ath/ath5k/qcu.c +++ b/drivers/net/wireless/ath/ath5k/qcu.c @@ -17,23 +17,48 @@ */ /********************************************\ -Queue Control Unit, DFS Control Unit Functions +Queue Control Unit, DCF Control Unit Functions \********************************************/ #include "ath5k.h" #include "reg.h" #include "debug.h" +#include <linux/log2.h> + +/** + * DOC: Queue Control Unit (QCU)/DCF Control Unit (DCU) functions + * + * Here we setup parameters for the 12 available TX queues. Note that + * on the various registers we can usually only map the first 10 of them so + * basically we have 10 queues to play with. Each queue has a matching + * QCU that controls when the queue will get triggered and multiple QCUs + * can be mapped to a single DCU that controls the various DFS parameters + * for the various queues. In our setup we have a 1:1 mapping between QCUs + * and DCUs allowing us to have different DFS settings for each queue. + * + * When a frame goes into a TX queue, QCU decides when it'll trigger a + * transmission based on various criteria (such as how many data we have inside + * it's buffer or -if it's a beacon queue- if it's time to fire up the queue + * based on TSF etc), DCU adds backoff, IFSes etc and then a scheduler + * (arbitrator) decides the priority of each QCU based on it's configuration + * (e.g. beacons are always transmitted when they leave DCU bypassing all other + * frames from other queues waiting to be transmitted). After a frame leaves + * the DCU it goes to PCU for further processing and then to PHY for + * the actual transmission. + */ /******************\ * Helper functions * \******************/ -/* - * Get number of pending frames - * for a specific queue [5211+] +/** + * ath5k_hw_num_tx_pending() - Get number of pending frames for a given queue + * @ah: The &struct ath5k_hw + * @queue: One of enum ath5k_tx_queue_id */ -u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue) +u32 +ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue) { u32 pending; AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); @@ -58,10 +83,13 @@ u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue) return pending; } -/* - * Set a transmit queue inactive +/** + * ath5k_hw_release_tx_queue() - Set a transmit queue inactive + * @ah: The &struct ath5k_hw + * @queue: One of enum ath5k_tx_queue_id */ -void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue) +void +ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue) { if (WARN_ON(queue >= ah->ah_capabilities.cap_queues.q_tx_num)) return; @@ -72,34 +100,56 @@ void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue) AR5K_Q_DISABLE_BITS(ah->ah_txq_status, queue); } -/* +/** + * ath5k_cw_validate() - Make sure the given cw is valid + * @cw_req: The contention window value to check + * * Make sure cw is a power of 2 minus 1 and smaller than 1024 */ -static u16 ath5k_cw_validate(u16 cw_req) +static u16 +ath5k_cw_validate(u16 cw_req) { - u32 cw = 1; cw_req = min(cw_req, (u16)1023); - while (cw < cw_req) - cw = (cw << 1) | 1; + /* Check if cw_req + 1 a power of 2 */ + if (is_power_of_2(cw_req + 1)) + return cw_req; - return cw; + /* Check if cw_req is a power of 2 */ + if (is_power_of_2(cw_req)) + return cw_req - 1; + + /* If none of the above is correct + * find the closest power of 2 */ + cw_req = (u16) roundup_pow_of_two(cw_req) - 1; + + return cw_req; } -/* - * Get properties for a transmit queue +/** + * ath5k_hw_get_tx_queueprops() - Get properties for a transmit queue + * @ah: The &struct ath5k_hw + * @queue: One of enum ath5k_tx_queue_id + * @queue_info: The &struct ath5k_txq_info to fill */ -int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue, +int +ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue, struct ath5k_txq_info *queue_info) { memcpy(queue_info, &ah->ah_txq[queue], sizeof(struct ath5k_txq_info)); return 0; } -/* - * Set properties for a transmit queue +/** + * ath5k_hw_set_tx_queueprops() - Set properties for a transmit queue + * @ah: The &struct ath5k_hw + * @queue: One of enum ath5k_tx_queue_id + * @qinfo: The &struct ath5k_txq_info to use + * + * Returns 0 on success or -EIO if queue is inactive */ -int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue, +int +ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue, const struct ath5k_txq_info *qinfo) { struct ath5k_txq_info *qi; @@ -139,10 +189,16 @@ int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue, return 0; } -/* - * Initialize a transmit queue +/** + * ath5k_hw_setup_tx_queue() - Initialize a transmit queue + * @ah: The &struct ath5k_hw + * @queue_type: One of enum ath5k_tx_queue + * @queue_info: The &struct ath5k_txq_info to use + * + * Returns 0 on success, -EINVAL on invalid arguments */ -int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type, +int +ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type, struct ath5k_txq_info *queue_info) { unsigned int queue; @@ -217,10 +273,16 @@ int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type, * Single QCU/DCU initialization * \*******************************/ -/* - * Set tx retry limits on DCU +/** + * ath5k_hw_set_tx_retry_limits() - Set tx retry limits on DCU + * @ah: The &struct ath5k_hw + * @queue: One of enum ath5k_tx_queue_id + * + * This function is used when initializing a queue, to set + * retry limits based on ah->ah_retry_* and the chipset used. */ -void ath5k_hw_set_tx_retry_limits(struct ath5k_hw *ah, +void +ath5k_hw_set_tx_retry_limits(struct ath5k_hw *ah, unsigned int queue) { /* Single data queue on AR5210 */ @@ -255,15 +317,15 @@ void ath5k_hw_set_tx_retry_limits(struct ath5k_hw *ah, } /** - * ath5k_hw_reset_tx_queue - Initialize a single hw queue + * ath5k_hw_reset_tx_queue() - Initialize a single hw queue + * @ah: The &struct ath5k_hw + * @queue: One of enum ath5k_tx_queue_id * - * @ah The &struct ath5k_hw - * @queue The hw queue number - * - * Set DFS properties for the given transmit queue on DCU + * Set DCF properties for the given transmit queue on DCU * and configures all queue-specific parameters. */ -int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) +int +ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) { struct ath5k_txq_info *tq = &ah->ah_txq[queue]; @@ -491,10 +553,9 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) \**************************/ /** - * ath5k_hw_set_ifs_intervals - Set global inter-frame spaces on DCU - * - * @ah The &struct ath5k_hw - * @slot_time Slot time in us + * ath5k_hw_set_ifs_intervals() - Set global inter-frame spaces on DCU + * @ah: The &struct ath5k_hw + * @slot_time: Slot time in us * * Sets the global IFS intervals on DCU (also works on AR5210) for * the given slot time and the current bwmode. @@ -597,7 +658,15 @@ int ath5k_hw_set_ifs_intervals(struct ath5k_hw *ah, unsigned int slot_time) } -int ath5k_hw_init_queues(struct ath5k_hw *ah) +/** + * ath5k_hw_init_queues() - Initialize tx queues + * @ah: The &struct ath5k_hw + * + * Initializes all tx queues based on information on + * ah->ah_txq* set by the driver + */ +int +ath5k_hw_init_queues(struct ath5k_hw *ah) { int i, ret; diff --git a/drivers/net/wireless/ath/ath5k/reg.h b/drivers/net/wireless/ath/ath5k/reg.h index f5c1000045d3..0ea1608b47fd 100644 --- a/drivers/net/wireless/ath/ath5k/reg.h +++ b/drivers/net/wireless/ath/ath5k/reg.h @@ -280,6 +280,10 @@ * 5211/5212 we have one primary and 4 secondary registers. * So we have AR5K_ISR for 5210 and AR5K_PISR /SISRx for 5211/5212. * Most of these bits are common for all chipsets. + * + * NOTE: On 5211+ TXOK, TXDESC, TXERR, TXEOL and TXURN contain + * the logical OR from per-queue interrupt bits found on SISR registers + * (see below). */ #define AR5K_ISR 0x001c /* Register Address [5210] */ #define AR5K_PISR 0x0080 /* Register Address [5211+] */ @@ -292,7 +296,10 @@ #define AR5K_ISR_TXOK 0x00000040 /* Frame successfully transmitted */ #define AR5K_ISR_TXDESC 0x00000080 /* TX descriptor request */ #define AR5K_ISR_TXERR 0x00000100 /* Transmit error */ -#define AR5K_ISR_TXNOFRM 0x00000200 /* No frame transmitted (transmit timeout) */ +#define AR5K_ISR_TXNOFRM 0x00000200 /* No frame transmitted (transmit timeout) + * NOTE: We don't have per-queue info for this + * one, but we can enable it per-queue through + * TXNOFRM_QCU field on TXNOFRM register */ #define AR5K_ISR_TXEOL 0x00000400 /* Empty TX descriptor */ #define AR5K_ISR_TXURN 0x00000800 /* Transmit FIFO underrun */ #define AR5K_ISR_MIB 0x00001000 /* Update MIB counters */ @@ -302,21 +309,29 @@ #define AR5K_ISR_SWBA 0x00010000 /* Software beacon alert */ #define AR5K_ISR_BRSSI 0x00020000 /* Beacon rssi below threshold (?) */ #define AR5K_ISR_BMISS 0x00040000 /* Beacon missed */ -#define AR5K_ISR_HIUERR 0x00080000 /* Host Interface Unit error [5211+] */ +#define AR5K_ISR_HIUERR 0x00080000 /* Host Interface Unit error [5211+] + * 'or' of MCABT, SSERR, DPERR from SISR2 */ #define AR5K_ISR_BNR 0x00100000 /* Beacon not ready [5211+] */ #define AR5K_ISR_MCABT 0x00100000 /* Master Cycle Abort [5210] */ #define AR5K_ISR_RXCHIRP 0x00200000 /* CHIRP Received [5212+] */ #define AR5K_ISR_SSERR 0x00200000 /* Signaled System Error [5210] */ -#define AR5K_ISR_DPERR 0x00400000 /* Det par Error (?) [5210] */ +#define AR5K_ISR_DPERR 0x00400000 /* Bus parity error [5210] */ #define AR5K_ISR_RXDOPPLER 0x00400000 /* Doppler chirp received [5212+] */ #define AR5K_ISR_TIM 0x00800000 /* [5211+] */ -#define AR5K_ISR_BCNMISC 0x00800000 /* 'or' of TIM, CAB_END, DTIM_SYNC, BCN_TIMEOUT, - CAB_TIMEOUT and DTIM bits from SISR2 [5212+] */ +#define AR5K_ISR_BCNMISC 0x00800000 /* Misc beacon related interrupt + * 'or' of TIM, CAB_END, DTIM_SYNC, BCN_TIMEOUT, + * CAB_TIMEOUT and DTIM bits from SISR2 [5212+] */ #define AR5K_ISR_GPIO 0x01000000 /* GPIO (rf kill) */ #define AR5K_ISR_QCBRORN 0x02000000 /* QCU CBR overrun [5211+] */ #define AR5K_ISR_QCBRURN 0x04000000 /* QCU CBR underrun [5211+] */ #define AR5K_ISR_QTRIG 0x08000000 /* QCU scheduling trigger [5211+] */ +#define AR5K_ISR_BITS_FROM_SISRS (AR5K_ISR_TXOK | AR5K_ISR_TXDESC |\ + AR5K_ISR_TXERR | AR5K_ISR_TXEOL |\ + AR5K_ISR_TXURN | AR5K_ISR_HIUERR |\ + AR5K_ISR_BCNMISC | AR5K_ISR_QCBRORN |\ + AR5K_ISR_QCBRURN | AR5K_ISR_QTRIG) + /* * Secondary status registers [5211+] (0 - 4) * @@ -347,7 +362,7 @@ #define AR5K_SISR2_BCN_TIMEOUT 0x08000000 /* Beacon Timeout [5212+] */ #define AR5K_SISR2_CAB_TIMEOUT 0x10000000 /* CAB Timeout [5212+] */ #define AR5K_SISR2_DTIM 0x20000000 /* [5212+] */ -#define AR5K_SISR2_TSFOOR 0x80000000 /* TSF OOR (?) */ +#define AR5K_SISR2_TSFOOR 0x80000000 /* TSF Out of range */ #define AR5K_SISR3 0x0090 /* Register Address [5211+] */ #define AR5K_SISR3_QCBRORN 0x000003ff /* Mask for QCBRORN */ diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index 2abac257b4b4..250db40b751d 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -19,9 +19,9 @@ * */ -/*****************************\ - Reset functions and helpers -\*****************************/ +/****************************\ + Reset function and helpers +\****************************/ #include <asm/unaligned.h> @@ -33,14 +33,36 @@ #include "debug.h" +/** + * DOC: Reset function and helpers + * + * Here we implement the main reset routine, used to bring the card + * to a working state and ready to receive. We also handle routines + * that don't fit on other places such as clock, sleep and power control + */ + + /******************\ * Helper functions * \******************/ -/* - * Check if a register write has been completed +/** + * ath5k_hw_register_timeout() - Poll a register for a flag/field change + * @ah: The &struct ath5k_hw + * @reg: The register to read + * @flag: The flag/field to check on the register + * @val: The field value we expect (if we check a field) + * @is_set: Instead of checking if the flag got cleared, check if it got set + * + * Some registers contain flags that indicate that an operation is + * running. We use this function to poll these registers and check + * if these flags get cleared. We also use it to poll a register + * field (containing multiple flags) until it gets a specific value. + * + * Returns -EAGAIN if we exceeded AR5K_TUNE_REGISTER_TIMEOUT * 15us or 0 */ -int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val, +int +ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val, bool is_set) { int i; @@ -64,35 +86,48 @@ int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val, \*************************/ /** - * ath5k_hw_htoclock - Translate usec to hw clock units - * + * ath5k_hw_htoclock() - Translate usec to hw clock units * @ah: The &struct ath5k_hw * @usec: value in microseconds + * + * Translate usecs to hw clock units based on the current + * hw clock rate. + * + * Returns number of clock units */ -unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec) +unsigned int +ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec) { struct ath_common *common = ath5k_hw_common(ah); return usec * common->clockrate; } /** - * ath5k_hw_clocktoh - Translate hw clock units to usec + * ath5k_hw_clocktoh() - Translate hw clock units to usec + * @ah: The &struct ath5k_hw * @clock: value in hw clock units + * + * Translate hw clock units to usecs based on the current + * hw clock rate. + * + * Returns number of usecs */ -unsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock) +unsigned int +ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock) { struct ath_common *common = ath5k_hw_common(ah); return clock / common->clockrate; } /** - * ath5k_hw_init_core_clock - Initialize core clock - * - * @ah The &struct ath5k_hw + * ath5k_hw_init_core_clock() - Initialize core clock + * @ah: The &struct ath5k_hw * - * Initialize core clock parameters (usec, usec32, latencies etc). + * Initialize core clock parameters (usec, usec32, latencies etc), + * based on current bwmode and chipset properties. */ -static void ath5k_hw_init_core_clock(struct ath5k_hw *ah) +static void +ath5k_hw_init_core_clock(struct ath5k_hw *ah) { struct ieee80211_channel *channel = ah->ah_current_channel; struct ath_common *common = ath5k_hw_common(ah); @@ -227,16 +262,21 @@ static void ath5k_hw_init_core_clock(struct ath5k_hw *ah) } } -/* +/** + * ath5k_hw_set_sleep_clock() - Setup sleep clock operation + * @ah: The &struct ath5k_hw + * @enable: Enable sleep clock operation (false to disable) + * * If there is an external 32KHz crystal available, use it * as ref. clock instead of 32/40MHz clock and baseband clocks * to save power during sleep or restore normal 32/40MHz * operation. * - * XXX: When operating on 32KHz certain PHY registers (27 - 31, - * 123 - 127) require delay on access. + * NOTE: When operating on 32KHz certain PHY registers (27 - 31, + * 123 - 127) require delay on access. */ -static void ath5k_hw_set_sleep_clock(struct ath5k_hw *ah, bool enable) +static void +ath5k_hw_set_sleep_clock(struct ath5k_hw *ah, bool enable) { struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; u32 scal, spending, sclock; @@ -340,10 +380,19 @@ static void ath5k_hw_set_sleep_clock(struct ath5k_hw *ah, bool enable) * Reset/Sleep control * \*********************/ -/* - * Reset chipset +/** + * ath5k_hw_nic_reset() - Reset the various chipset units + * @ah: The &struct ath5k_hw + * @val: Mask to indicate what units to reset + * + * To reset the various chipset units we need to write + * the mask to AR5K_RESET_CTL and poll the register until + * all flags are cleared. + * + * Returns 0 if we are O.K. or -EAGAIN (from athk5_hw_register_timeout) */ -static int ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val) +static int +ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val) { int ret; u32 mask = val ? val : ~0U; @@ -357,7 +406,7 @@ static int ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val) ath5k_hw_reg_write(ah, val, AR5K_RESET_CTL); /* Wait at least 128 PCI clocks */ - udelay(15); + usleep_range(15, 20); if (ah->ah_version == AR5K_AR5210) { val &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_DMA @@ -382,12 +431,17 @@ static int ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val) return ret; } -/* - * Reset AHB chipset - * AR5K_RESET_CTL_PCU flag resets WMAC - * AR5K_RESET_CTL_BASEBAND flag resets WBB +/** + * ath5k_hw_wisoc_reset() - Reset AHB chipset + * @ah: The &struct ath5k_hw + * @flags: Mask to indicate what units to reset + * + * Same as ath5k_hw_nic_reset but for AHB based devices + * + * Returns 0 if we are O.K. or -EAGAIN (from athk5_hw_register_timeout) */ -static int ath5k_hw_wisoc_reset(struct ath5k_hw *ah, u32 flags) +static int +ath5k_hw_wisoc_reset(struct ath5k_hw *ah, u32 flags) { u32 mask = flags ? flags : ~0U; u32 __iomem *reg; @@ -422,7 +476,7 @@ static int ath5k_hw_wisoc_reset(struct ath5k_hw *ah, u32 flags) regval = __raw_readl(reg); __raw_writel(regval | val, reg); regval = __raw_readl(reg); - udelay(100); + usleep_range(100, 150); /* Bring BB/MAC out of reset */ __raw_writel(regval & ~val, reg); @@ -439,11 +493,23 @@ static int ath5k_hw_wisoc_reset(struct ath5k_hw *ah, u32 flags) return 0; } - -/* - * Sleep control +/** + * ath5k_hw_set_power_mode() - Set power mode + * @ah: The &struct ath5k_hw + * @mode: One of enum ath5k_power_mode + * @set_chip: Set to true to write sleep control register + * @sleep_duration: How much time the device is allowed to sleep + * when sleep logic is enabled (in 128 microsecond increments). + * + * This function is used to configure sleep policy and allowed + * sleep modes. For more information check out the sleep control + * register on reg.h and STA_ID1. + * + * Returns 0 on success, -EIO if chip didn't wake up or -EINVAL if an invalid + * mode is requested. */ -static int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, +static int +ath5k_hw_set_power_mode(struct ath5k_hw *ah, enum ath5k_power_mode mode, bool set_chip, u16 sleep_duration) { unsigned int i; @@ -493,7 +559,7 @@ static int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, ath5k_hw_reg_write(ah, data | AR5K_SLEEP_CTL_SLE_WAKE, AR5K_SLEEP_CTL); - udelay(15); + usleep_range(15, 20); for (i = 200; i > 0; i--) { /* Check if the chip did wake up */ @@ -502,7 +568,7 @@ static int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, break; /* Wait a bit and retry */ - udelay(50); + usleep_range(50, 75); ath5k_hw_reg_write(ah, data | AR5K_SLEEP_CTL_SLE_WAKE, AR5K_SLEEP_CTL); } @@ -523,17 +589,20 @@ commit: return 0; } -/* - * Put device on hold +/** + * ath5k_hw_on_hold() - Put device on hold + * @ah: The &struct ath5k_hw * - * Put MAC and Baseband on warm reset and - * keep that state (don't clean sleep control - * register). After this MAC and Baseband are - * disabled and a full reset is needed to come - * back. This way we save as much power as possible + * Put MAC and Baseband on warm reset and keep that state + * (don't clean sleep control register). After this MAC + * and Baseband are disabled and a full reset is needed + * to come back. This way we save as much power as possible * without putting the card on full sleep. + * + * Returns 0 on success or -EIO on error */ -int ath5k_hw_on_hold(struct ath5k_hw *ah) +int +ath5k_hw_on_hold(struct ath5k_hw *ah) { struct pci_dev *pdev = ah->pdev; u32 bus_flags; @@ -543,7 +612,7 @@ int ath5k_hw_on_hold(struct ath5k_hw *ah) return 0; /* Make sure device is awake */ - ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); + ret = ath5k_hw_set_power_mode(ah, AR5K_PM_AWAKE, true, 0); if (ret) { ATH5K_ERR(ah, "failed to wakeup the MAC Chip\n"); return ret; @@ -563,7 +632,7 @@ int ath5k_hw_on_hold(struct ath5k_hw *ah) ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA | AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI); - mdelay(2); + usleep_range(2000, 2500); } else { ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND | bus_flags); @@ -575,7 +644,7 @@ int ath5k_hw_on_hold(struct ath5k_hw *ah) } /* ...wakeup again!*/ - ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); + ret = ath5k_hw_set_power_mode(ah, AR5K_PM_AWAKE, true, 0); if (ret) { ATH5K_ERR(ah, "failed to put device on hold\n"); return ret; @@ -584,11 +653,18 @@ int ath5k_hw_on_hold(struct ath5k_hw *ah) return ret; } -/* +/** + * ath5k_hw_nic_wakeup() - Force card out of sleep + * @ah: The &struct ath5k_hw + * @channel: The &struct ieee80211_channel + * * Bring up MAC + PHY Chips and program PLL - * Channel is NULL for the initial wakeup. + * NOTE: Channel is NULL for the initial wakeup. + * + * Returns 0 on success, -EIO on hw failure or -EINVAL for false channel infos */ -int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel) +int +ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel) { struct pci_dev *pdev = ah->pdev; u32 turbo, mode, clock, bus_flags; @@ -600,7 +676,7 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel) if ((ath5k_get_bus_type(ah) != ATH_AHB) || channel) { /* Wakeup the device */ - ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); + ret = ath5k_hw_set_power_mode(ah, AR5K_PM_AWAKE, true, 0); if (ret) { ATH5K_ERR(ah, "failed to wakeup the MAC Chip\n"); return ret; @@ -621,7 +697,7 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel) ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA | AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI); - mdelay(2); + usleep_range(2000, 2500); } else { if (ath5k_get_bus_type(ah) == ATH_AHB) ret = ath5k_hw_wisoc_reset(ah, AR5K_RESET_CTL_PCU | @@ -637,7 +713,7 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel) } /* ...wakeup again!...*/ - ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); + ret = ath5k_hw_set_power_mode(ah, AR5K_PM_AWAKE, true, 0); if (ret) { ATH5K_ERR(ah, "failed to resume the MAC Chip\n"); return ret; @@ -739,7 +815,7 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel) /* ...update PLL if needed */ if (ath5k_hw_reg_read(ah, AR5K_PHY_PLL) != clock) { ath5k_hw_reg_write(ah, clock, AR5K_PHY_PLL); - udelay(300); + usleep_range(300, 350); } /* ...set the PHY operating mode */ @@ -755,8 +831,19 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel) * Post-initvals register modifications * \**************************************/ -/* TODO: Half/Quarter rate */ -static void ath5k_hw_tweak_initval_settings(struct ath5k_hw *ah, +/** + * ath5k_hw_tweak_initval_settings() - Tweak initial settings + * @ah: The &struct ath5k_hw + * @channel: The &struct ieee80211_channel + * + * Some settings are not handled on initvals, e.g. bwmode + * settings, some phy settings, workarounds etc that in general + * don't fit anywhere else or are too small to introduce a separate + * function for each one. So we have this function to handle + * them all during reset and complete card's initialization. + */ +static void +ath5k_hw_tweak_initval_settings(struct ath5k_hw *ah, struct ieee80211_channel *channel) { if (ah->ah_version == AR5K_AR5212 && @@ -875,7 +962,16 @@ static void ath5k_hw_tweak_initval_settings(struct ath5k_hw *ah, } } -static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah, +/** + * ath5k_hw_commit_eeprom_settings() - Commit settings from EEPROM + * @ah: The &struct ath5k_hw + * @channel: The &struct ieee80211_channel + * + * Use settings stored on EEPROM to properly initialize the card + * based on various infos and per-mode calibration data. + */ +static void +ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah, struct ieee80211_channel *channel) { struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; @@ -1029,7 +1125,23 @@ static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah, * Main reset function * \*********************/ -int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, +/** + * ath5k_hw_reset() - The main reset function + * @ah: The &struct ath5k_hw + * @op_mode: One of enum nl80211_iftype + * @channel: The &struct ieee80211_channel + * @fast: Enable fast channel switching + * @skip_pcu: Skip pcu initialization + * + * This is the function we call each time we want to (re)initialize the + * card and pass new settings to hw. We also call it when hw runs into + * trouble to make it come back to a working state. + * + * Returns 0 on success, -EINVAL on false op_mode or channel infos, or -EIO + * on failure. + */ +int +ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, struct ieee80211_channel *channel, bool fast, bool skip_pcu) { u32 s_seq[10], s_led[3], tsf_up, tsf_lo; @@ -1047,7 +1159,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, */ if (fast && (ah->ah_radio != AR5K_RF2413) && (ah->ah_radio != AR5K_RF5413)) - fast = 0; + fast = false; /* Disable sleep clock operation * to avoid register access delay on certain @@ -1073,7 +1185,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, if (ret && fast) { ATH5K_DBG(ah, ATH5K_DEBUG_RESET, "DMA didn't stop, falling back to normal reset\n"); - fast = 0; + fast = false; /* Non fatal, just continue with * normal reset */ ret = 0; @@ -1242,7 +1354,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, /* * Initialize PCU */ - ath5k_hw_pcu_init(ah, op_mode, mode); + ath5k_hw_pcu_init(ah, op_mode); /* * Initialize PHY diff --git a/drivers/net/wireless/ath/ath5k/rfbuffer.h b/drivers/net/wireless/ath/ath5k/rfbuffer.h index 5d11c23b4297..aed34d9954c0 100644 --- a/drivers/net/wireless/ath/ath5k/rfbuffer.h +++ b/drivers/net/wireless/ath/ath5k/rfbuffer.h @@ -18,7 +18,9 @@ */ -/* +/** + * DOC: RF Buffer registers + * * There are some special registers on the RF chip * that control various operation settings related mostly to * the analog parts (channel, gain adjustment etc). @@ -44,40 +46,63 @@ */ -/* +/** + * struct ath5k_ini_rfbuffer - Initial RF Buffer settings + * @rfb_bank: RF Bank number + * @rfb_ctrl_register: RF Buffer control register + * @rfb_mode_data: RF Buffer data for each mode + * * Struct to hold default mode specific RF - * register values (RF Banks) + * register values (RF Banks) for each chip. */ struct ath5k_ini_rfbuffer { - u8 rfb_bank; /* RF Bank number */ - u16 rfb_ctrl_register; /* RF Buffer control register */ - u32 rfb_mode_data[3]; /* RF Buffer data for each mode */ + u8 rfb_bank; + u16 rfb_ctrl_register; + u32 rfb_mode_data[3]; }; -/* +/** + * struct ath5k_rfb_field - An RF Buffer field (register/value) + * @len: Field length + * @pos: Offset on the raw packet + * @col: Used for shifting + * * Struct to hold RF Buffer field * infos used to access certain RF * analog registers */ struct ath5k_rfb_field { - u8 len; /* Field length */ - u16 pos; /* Offset on the raw packet */ - u8 col; /* Column -used for shifting */ + u8 len; + u16 pos; + u8 col; }; -/* - * RF analog register definition +/** + * struct ath5k_rf_reg - RF analog register definition + * @bank: RF Buffer Bank number + * @index: Register's index on ath5k_rf_regx_idx + * @field: The &struct ath5k_rfb_field + * + * We use this struct to define the set of RF registers + * on each chip that we want to tweak. Some RF registers + * are common between different chip versions so this saves + * us space and complexity because we can refer to an rf + * register by it's index no matter what chip we work with + * as long as it has that register. */ struct ath5k_rf_reg { - u8 bank; /* RF Buffer Bank number */ - u8 index; /* Register's index on rf_regs_idx */ - struct ath5k_rfb_field field; /* RF Buffer field for this register */ + u8 bank; + u8 index; + struct ath5k_rfb_field field; }; -/* Map RF registers to indexes +/** + * enum ath5k_rf_regs_idx - Map RF registers to indexes + * * We do this to handle common bits and make our * life easier by using an index for each register - * instead of a full rfb_field */ + * instead of a full rfb_field + */ enum ath5k_rf_regs_idx { /* BANK 2 */ AR5K_RF_TURBO = 0, diff --git a/drivers/net/wireless/ath/ath5k/rfgain.h b/drivers/net/wireless/ath/ath5k/rfgain.h index ebfae052d89e..4d21df0e5975 100644 --- a/drivers/net/wireless/ath/ath5k/rfgain.h +++ b/drivers/net/wireless/ath/ath5k/rfgain.h @@ -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 * (RF5110 only comes with AR5210 and only supports a/turbo a mode so initial * RF Gain values are included in AR5K_AR5210_INI) */ struct ath5k_ini_rfgain { - u16 rfg_register; /* RF Gain register address */ + u16 rfg_register; u32 rfg_value[2]; /* [freq (see below)] */ }; @@ -455,18 +459,31 @@ static const struct ath5k_ini_rfgain rfgain_2425[] = { #define AR5K_GAIN_CHECK_ADJUST(_g) \ ((_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 { s8 gos_param[AR5K_GAIN_CRN_MAX_FIX_BITS]; 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 { u8 go_default; u8 go_steps_count; const struct ath5k_gain_opt_step go_step[AR5K_GAIN_STEP_COUNT]; }; + /* + * RF5111 * Parameters on gos_param: * 1) Tx clip PHY register * 2) PWD 90 RF register @@ -490,6 +507,7 @@ static const struct ath5k_gain_opt rfgain_opt_5111 = { }; /* + * RF5112 * Parameters on gos_param: * 1) Mixgain ovr RF register * 2) PWD 138 RF register diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index 30050af9d4c6..5acb4a4b93bf 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -361,7 +361,7 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx) ath6kl_dbg(ATH6KL_DBG_TRC, "failed to request P2P " "capabilities (%d) - assuming P2P not " "supported\n", ret); - ar->p2p = 0; + ar->p2p = false; } } diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index 7b4c074e12fa..1b4786ae00ac 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -2,6 +2,9 @@ config ATH9K_HW tristate config ATH9K_COMMON tristate +config ATH9K_DFS_DEBUGFS + def_bool y + depends on ATH9K_DEBUGFS && ATH9K_DFS_CERTIFIED config ATH9K tristate "Atheros 802.11n wireless cards support" @@ -51,6 +54,25 @@ config ATH9K_DEBUGFS Also required for changing debug message flags at run time. +config ATH9K_DFS_CERTIFIED + bool "Atheros DFS support for certified platforms" + depends on ATH9K && EXPERT + default n + ---help--- + This option enables DFS support for initiating radiation on + ath9k. There is no way to dynamically detect if a card was DFS + certified and as such this is left as a build time option. This + option should only be enabled by system integrators that can + guarantee that all the platforms that their kernel will run on + have obtained appropriate regulatory body certification for a + respective Atheros card by using ath9k on the target shipping + platforms. + + This is currently only a placeholder for future DFS support, + as DFS support requires more components that still need to be + developed. At this point enabling this option won't do anything + except increase code size. + config ATH9K_RATE_CONTROL bool "Atheros ath9k rate control" depends on ATH9K diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index 49d3f25f509d..da02242499af 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -10,6 +10,8 @@ ath9k-$(CONFIG_ATH9K_RATE_CONTROL) += rc.o ath9k-$(CONFIG_ATH9K_PCI) += pci.o ath9k-$(CONFIG_ATH9K_AHB) += ahb.o ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o +ath9k-$(CONFIG_ATH9K_DFS_DEBUGFS) += dfs_debug.o +ath9k-$(CONFIG_ATH9K_DFS_CERTIFIED) += dfs.o obj-$(CONFIG_ATH9K) += ath9k.o @@ -34,7 +36,8 @@ ath9k_hw-y:= \ ar9002_mac.o \ ar9003_mac.o \ ar9003_eeprom.o \ - ar9003_paprd.o + ar9003_paprd.o \ + ar9003_mci.o obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c index 88279e325dca..157337febc2b 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c @@ -203,7 +203,7 @@ static void ar9002_hw_iqcalibrate(struct ath_hw *ah, u8 numChains) i); ath_dbg(common, ATH_DBG_CALIBRATE, - "Orignal: Chn %diq_corr_meas = 0x%08x\n", + "Original: Chn %d iq_corr_meas = 0x%08x\n", i, ah->totalIqCorrMeas[i]); iqCorrNeg = 0; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 12a730dcb500..23b3a6c57800 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -18,6 +18,7 @@ #include "hw-ops.h" #include "ar9003_phy.h" #include "ar9003_rtt.h" +#include "ar9003_mci.h" #define MAX_MEASUREMENT MAX_IQCAL_MEASUREMENT #define MAX_MAG_DELTA 11 @@ -225,7 +226,7 @@ static void ar9003_hw_iqcalibrate(struct ath_hw *ah, u8 numChains) i); ath_dbg(common, ATH_DBG_CALIBRATE, - "Orignal: Chn %diq_corr_meas = 0x%08x\n", + "Original: Chn %d iq_corr_meas = 0x%08x\n", i, ah->totalIqCorrMeas[i]); iqCorrNeg = 0; @@ -824,7 +825,7 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable) chan_info_tab[i] + offset); ath_dbg(common, ATH_DBG_CALIBRATE, - "IQ RES[%d]=0x%x" + "IQ_RES[%d]=0x%x " "IQ_RES[%d]=0x%x\n", idx, iq_res[idx], idx + 1, iq_res[idx + 1]); @@ -934,10 +935,12 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, { struct ath_common *common = ath9k_hw_common(ah); struct ath9k_hw_cal_data *caldata = ah->caldata; + struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; bool txiqcal_done = false, txclcal_done = false; bool is_reusable = true, status = true; bool run_rtt_cal = false, run_agc_cal; bool rtt = !!(ah->caps.hw_caps & ATH9K_HW_CAP_RTT); + bool mci = !!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI); u32 agc_ctrl = 0, agc_supp_cals = AR_PHY_AGC_CONTROL_OFFSET_CAL | AR_PHY_AGC_CONTROL_FLTR_CAL | AR_PHY_AGC_CONTROL_PKDET_CAL; @@ -1005,6 +1008,31 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, } else if (caldata && !caldata->done_txiqcal_once) run_agc_cal = true; + if (mci && IS_CHAN_2GHZ(chan) && + (mci_hw->bt_state == MCI_BT_AWAKE) && + run_agc_cal && + !(mci_hw->config & ATH_MCI_CONFIG_DISABLE_MCI_CAL)) { + + u32 pld[4] = {0, 0, 0, 0}; + + /* send CAL_REQ only when BT is AWAKE. */ + ath_dbg(common, ATH_DBG_MCI, "MCI send WLAN_CAL_REQ 0x%x\n", + mci_hw->wlan_cal_seq); + MCI_GPM_SET_CAL_TYPE(pld, MCI_GPM_WLAN_CAL_REQ); + pld[MCI_GPM_WLAN_CAL_W_SEQUENCE] = mci_hw->wlan_cal_seq++; + ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16, true, false); + + /* Wait BT_CAL_GRANT for 50ms */ + ath_dbg(common, ATH_DBG_MCI, "MCI wait for BT_CAL_GRANT"); + + if (ar9003_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_GRANT, 0, 50000)) + ath_dbg(common, ATH_DBG_MCI, "MCI got BT_CAL_GRANT"); + else { + is_reusable = false; + ath_dbg(common, ATH_DBG_MCI, "\nMCI BT is not responding"); + } + } + txiqcal_done = ar9003_hw_tx_iq_cal_run(ah); REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); udelay(5); @@ -1022,6 +1050,21 @@ skip_tx_iqcal: AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT); } + + if (mci && IS_CHAN_2GHZ(chan) && + (mci_hw->bt_state == MCI_BT_AWAKE) && + run_agc_cal && + !(mci_hw->config & ATH_MCI_CONFIG_DISABLE_MCI_CAL)) { + + u32 pld[4] = {0, 0, 0, 0}; + + ath_dbg(common, ATH_DBG_MCI, "MCI Send WLAN_CAL_DONE 0x%x\n", + mci_hw->wlan_cal_done); + MCI_GPM_SET_CAL_TYPE(pld, MCI_GPM_WLAN_CAL_DONE); + pld[MCI_GPM_WLAN_CAL_W_SEQUENCE] = mci_hw->wlan_cal_done++; + ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16, true, false); + } + if (rtt && !run_rtt_cal) { agc_ctrl |= agc_supp_cals; REG_WRITE(ah, AR_PHY_AGC_CONTROL, agc_ctrl); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index a93bd63ad23b..4ba6f52943a8 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -4779,7 +4779,7 @@ static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah, { struct ath_common *common = ath9k_hw_common(ah); struct ar9300_eeprom *pEepData = &ah->eeprom.ar9300_eep; - u16 twiceMaxEdgePower = MAX_RATE_POWER; + u16 twiceMaxEdgePower; int i; u16 scaledPower = 0, minCtlPower; static const u16 ctlModesFor11a[] = { @@ -4880,6 +4880,7 @@ static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah, ctlNum = AR9300_NUM_CTLS_5G; } + twiceMaxEdgePower = MAX_RATE_POWER; for (i = 0; (i < ctlNum) && ctlIndex[i]; i++) { ath_dbg(common, ATH_DBG_REGULATORY, "LOOP-Ctlidx %d: cfgCtl 0x%2.2x pCtlMode 0x%2.2x ctlIndex 0x%2.2x chan %d\n", diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c index ccde784a842f..631fe4f2e495 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c @@ -175,20 +175,24 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) u32 isr = 0; u32 mask2 = 0; struct ath9k_hw_capabilities *pCap = &ah->caps; - u32 sync_cause = 0; struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; + u32 sync_cause = 0, async_cause; - if (REG_READ(ah, AR_INTR_ASYNC_CAUSE) & AR_INTR_MAC_IRQ) { + async_cause = REG_READ(ah, AR_INTR_ASYNC_CAUSE); + + if (async_cause & (AR_INTR_MAC_IRQ | AR_INTR_ASYNC_MASK_MCI)) { if ((REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M) == AR_RTC_STATUS_ON) isr = REG_READ(ah, AR_ISR); } + sync_cause = REG_READ(ah, AR_INTR_SYNC_CAUSE) & AR_INTR_SYNC_DEFAULT; *masked = 0; - if (!isr && !sync_cause) + if (!isr && !sync_cause && !async_cause) return false; if (isr) { @@ -294,6 +298,35 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) ar9003_hw_bb_watchdog_read(ah); } + if (async_cause & AR_INTR_ASYNC_MASK_MCI) { + u32 raw_intr, rx_msg_intr; + + rx_msg_intr = REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW); + raw_intr = REG_READ(ah, AR_MCI_INTERRUPT_RAW); + + if ((raw_intr == 0xdeadbeef) || (rx_msg_intr == 0xdeadbeef)) + ath_dbg(common, ATH_DBG_MCI, + "MCI gets 0xdeadbeef during MCI int processing" + "new raw_intr=0x%08x, new rx_msg_raw=0x%08x, " + "raw_intr=0x%08x, rx_msg_raw=0x%08x\n", + raw_intr, rx_msg_intr, mci->raw_intr, + mci->rx_msg_intr); + else { + mci->rx_msg_intr |= rx_msg_intr; + mci->raw_intr |= raw_intr; + *masked |= ATH9K_INT_MCI; + + if (rx_msg_intr & AR_MCI_INTERRUPT_RX_MSG_CONT_INFO) + mci->cont_status = + REG_READ(ah, AR_MCI_CONT_STATUS); + + REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, rx_msg_intr); + REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, raw_intr); + ath_dbg(common, ATH_DBG_MCI, "AR_INTR_SYNC_MCI\n"); + + } + } + if (sync_cause) { if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) { REG_WRITE(ah, AR_RC, AR_RC_HOSTIF); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c new file mode 100644 index 000000000000..8599822dc83f --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c @@ -0,0 +1,1464 @@ +/* + * Copyright (c) 2008-2011 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <linux/export.h> +#include "hw.h" +#include "ar9003_phy.h" +#include "ar9003_mci.h" + +static void ar9003_mci_reset_req_wakeup(struct ath_hw *ah) +{ + if (!AR_SREV_9462_20(ah)) + return; + + REG_RMW_FIELD(ah, AR_MCI_COMMAND2, + AR_MCI_COMMAND2_RESET_REQ_WAKEUP, 1); + udelay(1); + REG_RMW_FIELD(ah, AR_MCI_COMMAND2, + AR_MCI_COMMAND2_RESET_REQ_WAKEUP, 0); +} + +static int ar9003_mci_wait_for_interrupt(struct ath_hw *ah, u32 address, + u32 bit_position, int time_out) +{ + struct ath_common *common = ath9k_hw_common(ah); + + while (time_out) { + + if (REG_READ(ah, address) & bit_position) { + + REG_WRITE(ah, address, bit_position); + + if (address == AR_MCI_INTERRUPT_RX_MSG_RAW) { + + if (bit_position & + AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE) + ar9003_mci_reset_req_wakeup(ah); + + if (bit_position & + (AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING | + AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING)) + REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, + AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE); + + REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, + AR_MCI_INTERRUPT_RX_MSG); + } + break; + } + + udelay(10); + time_out -= 10; + + if (time_out < 0) + break; + } + + if (time_out <= 0) { + ath_dbg(common, ATH_DBG_MCI, + "MCI Wait for Reg 0x%08x = 0x%08x timeout.\n", + address, bit_position); + ath_dbg(common, ATH_DBG_MCI, + "MCI INT_RAW = 0x%08x, RX_MSG_RAW = 0x%08x", + REG_READ(ah, AR_MCI_INTERRUPT_RAW), + REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW)); + time_out = 0; + } + + return time_out; +} + +void ar9003_mci_remote_reset(struct ath_hw *ah, bool wait_done) +{ + u32 payload[4] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffff00}; + + ar9003_mci_send_message(ah, MCI_REMOTE_RESET, 0, payload, 16, + wait_done, false); + udelay(5); +} + +void ar9003_mci_send_lna_transfer(struct ath_hw *ah, bool wait_done) +{ + u32 payload = 0x00000000; + + ar9003_mci_send_message(ah, MCI_LNA_TRANS, 0, &payload, 1, + wait_done, false); +} + +static void ar9003_mci_send_req_wake(struct ath_hw *ah, bool wait_done) +{ + ar9003_mci_send_message(ah, MCI_REQ_WAKE, MCI_FLAG_DISABLE_TIMESTAMP, + NULL, 0, wait_done, false); + udelay(5); +} + +void ar9003_mci_send_sys_waking(struct ath_hw *ah, bool wait_done) +{ + ar9003_mci_send_message(ah, MCI_SYS_WAKING, MCI_FLAG_DISABLE_TIMESTAMP, + NULL, 0, wait_done, false); +} + +static void ar9003_mci_send_lna_take(struct ath_hw *ah, bool wait_done) +{ + u32 payload = 0x70000000; + + ar9003_mci_send_message(ah, MCI_LNA_TAKE, 0, &payload, 1, + wait_done, false); +} + +static void ar9003_mci_send_sys_sleeping(struct ath_hw *ah, bool wait_done) +{ + ar9003_mci_send_message(ah, MCI_SYS_SLEEPING, + MCI_FLAG_DISABLE_TIMESTAMP, + NULL, 0, wait_done, false); +} + +static void ar9003_mci_send_coex_version_query(struct ath_hw *ah, + bool wait_done) +{ + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; + u32 payload[4] = {0, 0, 0, 0}; + + if (!mci->bt_version_known && + (mci->bt_state != MCI_BT_SLEEP)) { + ath_dbg(common, ATH_DBG_MCI, "MCI Send Coex version query\n"); + MCI_GPM_SET_TYPE_OPCODE(payload, + MCI_GPM_COEX_AGENT, MCI_GPM_COEX_VERSION_QUERY); + ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, + wait_done, true); + } +} + +static void ar9003_mci_send_coex_version_response(struct ath_hw *ah, + bool wait_done) +{ + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; + u32 payload[4] = {0, 0, 0, 0}; + + ath_dbg(common, ATH_DBG_MCI, "MCI Send Coex version response\n"); + MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT, + MCI_GPM_COEX_VERSION_RESPONSE); + *(((u8 *)payload) + MCI_GPM_COEX_B_MAJOR_VERSION) = + mci->wlan_ver_major; + *(((u8 *)payload) + MCI_GPM_COEX_B_MINOR_VERSION) = + mci->wlan_ver_minor; + ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, wait_done, true); +} + +static void ar9003_mci_send_coex_wlan_channels(struct ath_hw *ah, + bool wait_done) +{ + struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; + u32 *payload = &mci->wlan_channels[0]; + + if ((mci->wlan_channels_update == true) && + (mci->bt_state != MCI_BT_SLEEP)) { + MCI_GPM_SET_TYPE_OPCODE(payload, + MCI_GPM_COEX_AGENT, MCI_GPM_COEX_WLAN_CHANNELS); + ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, + wait_done, true); + MCI_GPM_SET_TYPE_OPCODE(payload, 0xff, 0xff); + } +} + +static void ar9003_mci_send_coex_bt_status_query(struct ath_hw *ah, + bool wait_done, u8 query_type) +{ + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; + u32 payload[4] = {0, 0, 0, 0}; + bool query_btinfo = !!(query_type & (MCI_GPM_COEX_QUERY_BT_ALL_INFO | + MCI_GPM_COEX_QUERY_BT_TOPOLOGY)); + + if (mci->bt_state != MCI_BT_SLEEP) { + + ath_dbg(common, ATH_DBG_MCI, + "MCI Send Coex BT Status Query 0x%02X\n", query_type); + + MCI_GPM_SET_TYPE_OPCODE(payload, + MCI_GPM_COEX_AGENT, MCI_GPM_COEX_STATUS_QUERY); + + *(((u8 *)payload) + MCI_GPM_COEX_B_BT_BITMAP) = query_type; + /* + * If bt_status_query message is not sent successfully, + * then need_flush_btinfo should be set again. + */ + if (!ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, + wait_done, true)) { + if (query_btinfo) { + mci->need_flush_btinfo = true; + + ath_dbg(common, ATH_DBG_MCI, + "MCI send bt_status_query fail, " + "set flush flag again\n"); + } + } + + if (query_btinfo) + mci->query_bt = false; + } +} + +void ar9003_mci_send_coex_halt_bt_gpm(struct ath_hw *ah, bool halt, + bool wait_done) +{ + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; + u32 payload[4] = {0, 0, 0, 0}; + + ath_dbg(common, ATH_DBG_MCI, "MCI Send Coex %s BT GPM.\n", + (halt) ? "halt" : "unhalt"); + + MCI_GPM_SET_TYPE_OPCODE(payload, + MCI_GPM_COEX_AGENT, MCI_GPM_COEX_HALT_BT_GPM); + + if (halt) { + mci->query_bt = true; + /* Send next unhalt no matter halt sent or not */ + mci->unhalt_bt_gpm = true; + mci->need_flush_btinfo = true; + *(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) = + MCI_GPM_COEX_BT_GPM_HALT; + } else + *(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) = + MCI_GPM_COEX_BT_GPM_UNHALT; + + ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, wait_done, true); +} + + +static void ar9003_mci_prep_interface(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; + u32 saved_mci_int_en; + u32 mci_timeout = 150; + + mci->bt_state = MCI_BT_SLEEP; + saved_mci_int_en = REG_READ(ah, AR_MCI_INTERRUPT_EN); + + REG_WRITE(ah, AR_MCI_INTERRUPT_EN, 0); + REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, + REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW)); + REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, + REG_READ(ah, AR_MCI_INTERRUPT_RAW)); + + /* Remote Reset */ + ath_dbg(common, ATH_DBG_MCI, "MCI Reset sequence start\n"); + ath_dbg(common, ATH_DBG_MCI, "MCI send REMOTE_RESET\n"); + ar9003_mci_remote_reset(ah, true); + + /* + * This delay is required for the reset delay worst case value 255 in + * MCI_COMMAND2 register + */ + + if (AR_SREV_9462_10(ah)) + udelay(252); + + ath_dbg(common, ATH_DBG_MCI, "MCI Send REQ_WAKE to remoter(BT)\n"); + ar9003_mci_send_req_wake(ah, true); + + if (ar9003_mci_wait_for_interrupt(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, + AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING, 500)) { + + ath_dbg(common, ATH_DBG_MCI, + "MCI SYS_WAKING from remote(BT)\n"); + mci->bt_state = MCI_BT_AWAKE; + + if (AR_SREV_9462_10(ah)) + udelay(10); + /* + * we don't need to send more remote_reset at this moment. + * If BT receive first remote_reset, then BT HW will + * be cleaned up and will be able to receive req_wake + * and BT HW will respond sys_waking. + * In this case, WLAN will receive BT's HW sys_waking. + * Otherwise, if BT SW missed initial remote_reset, + * that remote_reset will still clean up BT MCI RX, + * and the req_wake will wake BT up, + * and BT SW will respond this req_wake with a remote_reset and + * sys_waking. In this case, WLAN will receive BT's SW + * sys_waking. In either case, BT's RX is cleaned up. So we + * don't need to reply BT's remote_reset now, if any. + * Similarly, if in any case, WLAN can receive BT's sys_waking, + * that means WLAN's RX is also fine. + */ + + /* Send SYS_WAKING to BT */ + + ath_dbg(common, ATH_DBG_MCI, + "MCI send SW SYS_WAKING to remote BT\n"); + + ar9003_mci_send_sys_waking(ah, true); + udelay(10); + + /* + * Set BT priority interrupt value to be 0xff to + * avoid having too many BT PRIORITY interrupts. + */ + + REG_WRITE(ah, AR_MCI_BT_PRI0, 0xFFFFFFFF); + REG_WRITE(ah, AR_MCI_BT_PRI1, 0xFFFFFFFF); + REG_WRITE(ah, AR_MCI_BT_PRI2, 0xFFFFFFFF); + REG_WRITE(ah, AR_MCI_BT_PRI3, 0xFFFFFFFF); + REG_WRITE(ah, AR_MCI_BT_PRI, 0X000000FF); + + /* + * A contention reset will be received after send out + * sys_waking. Also BT priority interrupt bits will be set. + * Clear those bits before the next step. + */ + + REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, + AR_MCI_INTERRUPT_RX_MSG_CONT_RST); + REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, + AR_MCI_INTERRUPT_BT_PRI); + + if (AR_SREV_9462_10(ah) || mci->is_2g) { + /* Send LNA_TRANS */ + ath_dbg(common, ATH_DBG_MCI, + "MCI send LNA_TRANS to BT\n"); + ar9003_mci_send_lna_transfer(ah, true); + udelay(5); + } + + if (AR_SREV_9462_10(ah) || (mci->is_2g && + !mci->update_2g5g)) { + if (ar9003_mci_wait_for_interrupt(ah, + AR_MCI_INTERRUPT_RX_MSG_RAW, + AR_MCI_INTERRUPT_RX_MSG_LNA_INFO, + mci_timeout)) + ath_dbg(common, ATH_DBG_MCI, + "MCI WLAN has control over the LNA & " + "BT obeys it\n"); + else + ath_dbg(common, ATH_DBG_MCI, + "MCI BT didn't respond to" + "LNA_TRANS\n"); + } + + if (AR_SREV_9462_10(ah)) { + /* Send another remote_reset to deassert BT clk_req. */ + ath_dbg(common, ATH_DBG_MCI, + "MCI another remote_reset to " + "deassert clk_req\n"); + ar9003_mci_remote_reset(ah, true); + udelay(252); + } + } + + /* Clear the extra redundant SYS_WAKING from BT */ + if ((mci->bt_state == MCI_BT_AWAKE) && + (REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, + AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING)) && + (REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, + AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING) == 0)) { + + REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, + AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING); + REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, + AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE); + } + + REG_WRITE(ah, AR_MCI_INTERRUPT_EN, saved_mci_int_en); +} + +void ar9003_mci_disable_interrupt(struct ath_hw *ah) +{ + REG_WRITE(ah, AR_MCI_INTERRUPT_EN, 0); + REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN, 0); +} + +void ar9003_mci_enable_interrupt(struct ath_hw *ah) +{ + + REG_WRITE(ah, AR_MCI_INTERRUPT_EN, AR_MCI_INTERRUPT_DEFAULT); + REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN, + AR_MCI_INTERRUPT_RX_MSG_DEFAULT); +} + +bool ar9003_mci_check_int(struct ath_hw *ah, u32 ints) +{ + u32 intr; + + intr = REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW); + return ((intr & ints) == ints); +} + +void ar9003_mci_get_interrupt(struct ath_hw *ah, u32 *raw_intr, + u32 *rx_msg_intr) +{ + struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; + *raw_intr = mci->raw_intr; + *rx_msg_intr = mci->rx_msg_intr; + + /* Clean int bits after the values are read. */ + mci->raw_intr = 0; + mci->rx_msg_intr = 0; +} +EXPORT_SYMBOL(ar9003_mci_get_interrupt); + +void ar9003_mci_2g5g_changed(struct ath_hw *ah, bool is_2g) +{ + struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; + + if (!mci->update_2g5g && + (mci->is_2g != is_2g)) + mci->update_2g5g = true; + + mci->is_2g = is_2g; +} + +static bool ar9003_mci_is_gpm_valid(struct ath_hw *ah, u32 msg_index) +{ + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; + u32 *payload; + u32 recv_type, offset; + + if (msg_index == MCI_GPM_INVALID) + return false; + + offset = msg_index << 4; + + payload = (u32 *)(mci->gpm_buf + offset); + recv_type = MCI_GPM_TYPE(payload); + + if (recv_type == MCI_GPM_RSVD_PATTERN) { + ath_dbg(common, ATH_DBG_MCI, "MCI Skip RSVD GPM\n"); + return false; + } + + return true; +} + +static void ar9003_mci_observation_set_up(struct ath_hw *ah) +{ + struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; + if (mci->config & ATH_MCI_CONFIG_MCI_OBS_MCI) { + + ath9k_hw_cfg_output(ah, 3, + AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_DATA); + ath9k_hw_cfg_output(ah, 2, AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_CLK); + ath9k_hw_cfg_output(ah, 1, AR_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA); + ath9k_hw_cfg_output(ah, 0, AR_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK); + + } else if (mci->config & ATH_MCI_CONFIG_MCI_OBS_TXRX) { + + ath9k_hw_cfg_output(ah, 3, AR_GPIO_OUTPUT_MUX_AS_WL_IN_TX); + ath9k_hw_cfg_output(ah, 2, AR_GPIO_OUTPUT_MUX_AS_WL_IN_RX); + ath9k_hw_cfg_output(ah, 1, AR_GPIO_OUTPUT_MUX_AS_BT_IN_TX); + ath9k_hw_cfg_output(ah, 0, AR_GPIO_OUTPUT_MUX_AS_BT_IN_RX); + ath9k_hw_cfg_output(ah, 5, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + + } else if (mci->config & ATH_MCI_CONFIG_MCI_OBS_BT) { + + ath9k_hw_cfg_output(ah, 3, AR_GPIO_OUTPUT_MUX_AS_BT_IN_TX); + ath9k_hw_cfg_output(ah, 2, AR_GPIO_OUTPUT_MUX_AS_BT_IN_RX); + ath9k_hw_cfg_output(ah, 1, AR_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA); + ath9k_hw_cfg_output(ah, 0, AR_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK); + + } else + return; + + REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE); + + if (AR_SREV_9462_20_OR_LATER(ah)) { + REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL, + AR_GLB_DS_JTAG_DISABLE, 1); + REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL, + AR_GLB_WLAN_UART_INTF_EN, 0); + REG_SET_BIT(ah, AR_GLB_GPIO_CONTROL, + ATH_MCI_CONFIG_MCI_OBS_GPIO); + } + + REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_GPIO_OBS_SEL, 0); + REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_MAC_BB_OBS_SEL, 1); + REG_WRITE(ah, AR_OBS, 0x4b); + REG_RMW_FIELD(ah, AR_DIAG_SW, AR_DIAG_OBS_PT_SEL1, 0x03); + REG_RMW_FIELD(ah, AR_DIAG_SW, AR_DIAG_OBS_PT_SEL2, 0x01); + REG_RMW_FIELD(ah, AR_MACMISC, AR_MACMISC_MISC_OBS_BUS_LSB, 0x02); + REG_RMW_FIELD(ah, AR_MACMISC, AR_MACMISC_MISC_OBS_BUS_MSB, 0x03); + REG_RMW_FIELD(ah, AR_PHY_TEST_CTL_STATUS, + AR_PHY_TEST_CTL_DEBUGPORT_SEL, 0x07); +} + +static bool ar9003_mci_send_coex_bt_flags(struct ath_hw *ah, bool wait_done, + u8 opcode, u32 bt_flags) +{ + struct ath_common *common = ath9k_hw_common(ah); + u32 pld[4] = {0, 0, 0, 0}; + + MCI_GPM_SET_TYPE_OPCODE(pld, + MCI_GPM_COEX_AGENT, MCI_GPM_COEX_BT_UPDATE_FLAGS); + + *(((u8 *)pld) + MCI_GPM_COEX_B_BT_FLAGS_OP) = opcode; + *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 0) = bt_flags & 0xFF; + *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 1) = (bt_flags >> 8) & 0xFF; + *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 2) = (bt_flags >> 16) & 0xFF; + *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 3) = (bt_flags >> 24) & 0xFF; + + ath_dbg(common, ATH_DBG_MCI, + "MCI BT_MCI_FLAGS: Send Coex BT Update Flags %s 0x%08x\n", + (opcode == MCI_GPM_COEX_BT_FLAGS_READ) ? "READ" : + ((opcode == MCI_GPM_COEX_BT_FLAGS_SET) ? "SET" : "CLEAR"), + bt_flags); + + return ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16, + wait_done, true); +} + +void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g, + bool is_full_sleep) +{ + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; + u32 regval, thresh; + + ath_dbg(common, ATH_DBG_MCI, "MCI full_sleep = %d, is_2g = %d\n", + is_full_sleep, is_2g); + + /* + * GPM buffer and scheduling message buffer are not allocated + */ + + if (!mci->gpm_addr && !mci->sched_addr) { + ath_dbg(common, ATH_DBG_MCI, + "MCI GPM and schedule buffers are not allocated"); + return; + } + + if (REG_READ(ah, AR_BTCOEX_CTRL) == 0xdeadbeef) { + ath_dbg(common, ATH_DBG_MCI, + "MCI it's deadbeef, quit mci_reset\n"); + return; + } + + /* Program MCI DMA related registers */ + REG_WRITE(ah, AR_MCI_GPM_0, mci->gpm_addr); + REG_WRITE(ah, AR_MCI_GPM_1, mci->gpm_len); + REG_WRITE(ah, AR_MCI_SCHD_TABLE_0, mci->sched_addr); + + /* + * To avoid MCI state machine be affected by incoming remote MCI msgs, + * MCI mode will be enabled later, right before reset the MCI TX and RX. + */ + + regval = SM(1, AR_BTCOEX_CTRL_AR9462_MODE) | + SM(1, AR_BTCOEX_CTRL_WBTIMER_EN) | + SM(1, AR_BTCOEX_CTRL_PA_SHARED) | + SM(1, AR_BTCOEX_CTRL_LNA_SHARED) | + SM(2, AR_BTCOEX_CTRL_NUM_ANTENNAS) | + SM(3, AR_BTCOEX_CTRL_RX_CHAIN_MASK) | + SM(0, AR_BTCOEX_CTRL_1_CHAIN_ACK) | + SM(0, AR_BTCOEX_CTRL_1_CHAIN_BCN) | + SM(0, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); + + if (is_2g && (AR_SREV_9462_20(ah)) && + !(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA)) { + + regval |= SM(1, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); + ath_dbg(common, ATH_DBG_MCI, + "MCI sched one step look ahead\n"); + + if (!(mci->config & + ATH_MCI_CONFIG_DISABLE_AGGR_THRESH)) { + + thresh = MS(mci->config, + ATH_MCI_CONFIG_AGGR_THRESH); + thresh &= 7; + regval |= SM(1, + AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN); + regval |= SM(thresh, AR_BTCOEX_CTRL_AGGR_THRESH); + + REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2, + AR_MCI_SCHD_TABLE_2_HW_BASED, 1); + REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2, + AR_MCI_SCHD_TABLE_2_MEM_BASED, 1); + + } else + ath_dbg(common, ATH_DBG_MCI, + "MCI sched aggr thresh: off\n"); + } else + ath_dbg(common, ATH_DBG_MCI, + "MCI SCHED one step look ahead off\n"); + + if (AR_SREV_9462_10(ah)) + regval |= SM(1, AR_BTCOEX_CTRL_SPDT_ENABLE_10); + + REG_WRITE(ah, AR_BTCOEX_CTRL, regval); + + if (AR_SREV_9462_20(ah)) { + REG_SET_BIT(ah, AR_PHY_GLB_CONTROL, + AR_BTCOEX_CTRL_SPDT_ENABLE); + REG_RMW_FIELD(ah, AR_BTCOEX_CTRL3, + AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT, 20); + } + + REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_RX_DEWEIGHT, 1); + REG_RMW_FIELD(ah, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX, 0); + + thresh = MS(mci->config, ATH_MCI_CONFIG_CLK_DIV); + REG_RMW_FIELD(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_CLK_DIV, thresh); + REG_SET_BIT(ah, AR_BTCOEX_CTRL, AR_BTCOEX_CTRL_MCI_MODE_EN); + + /* Resetting the Rx and Tx paths of MCI */ + regval = REG_READ(ah, AR_MCI_COMMAND2); + regval |= SM(1, AR_MCI_COMMAND2_RESET_TX); + REG_WRITE(ah, AR_MCI_COMMAND2, regval); + + udelay(1); + + regval &= ~SM(1, AR_MCI_COMMAND2_RESET_TX); + REG_WRITE(ah, AR_MCI_COMMAND2, regval); + + if (is_full_sleep) { + ar9003_mci_mute_bt(ah); + udelay(100); + } + + regval |= SM(1, AR_MCI_COMMAND2_RESET_RX); + REG_WRITE(ah, AR_MCI_COMMAND2, regval); + udelay(1); + regval &= ~SM(1, AR_MCI_COMMAND2_RESET_RX); + REG_WRITE(ah, AR_MCI_COMMAND2, regval); + + ar9003_mci_state(ah, MCI_STATE_INIT_GPM_OFFSET, NULL); + REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE, + (SM(0xe801, AR_MCI_MSG_ATTRIBUTES_TABLE_INVALID_HDR) | + SM(0x0000, AR_MCI_MSG_ATTRIBUTES_TABLE_CHECKSUM))); + + REG_CLR_BIT(ah, AR_MCI_TX_CTRL, + AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); + + if (AR_SREV_9462_20_OR_LATER(ah)) + ar9003_mci_observation_set_up(ah); + + mci->ready = true; + ar9003_mci_prep_interface(ah); + + if (en_int) + ar9003_mci_enable_interrupt(ah); +} + +void ar9003_mci_mute_bt(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + + /* disable all MCI messages */ + REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE, 0xffff0000); + REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS0, 0xffffffff); + REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS1, 0xffffffff); + REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS2, 0xffffffff); + REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS3, 0xffffffff); + REG_SET_BIT(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); + + /* wait pending HW messages to flush out */ + udelay(10); + + /* + * Send LNA_TAKE and SYS_SLEEPING when + * 1. reset not after resuming from full sleep + * 2. before reset MCI RX, to quiet BT and avoid MCI RX misalignment + */ + + ath_dbg(common, ATH_DBG_MCI, "MCI Send LNA take\n"); + ar9003_mci_send_lna_take(ah, true); + + udelay(5); + + ath_dbg(common, ATH_DBG_MCI, "MCI Send sys sleeping\n"); + ar9003_mci_send_sys_sleeping(ah, true); +} + +void ar9003_mci_sync_bt_state(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; + u32 cur_bt_state; + + cur_bt_state = ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL); + + if (mci->bt_state != cur_bt_state) { + ath_dbg(common, ATH_DBG_MCI, + "MCI BT state mismatches. old: %d, new: %d\n", + mci->bt_state, cur_bt_state); + mci->bt_state = cur_bt_state; + } + + if (mci->bt_state != MCI_BT_SLEEP) { + + ar9003_mci_send_coex_version_query(ah, true); + ar9003_mci_send_coex_wlan_channels(ah, true); + + if (mci->unhalt_bt_gpm == true) { + ath_dbg(common, ATH_DBG_MCI, "MCI unhalt BT GPM"); + ar9003_mci_send_coex_halt_bt_gpm(ah, false, true); + } + } +} + +static void ar9003_mci_send_2g5g_status(struct ath_hw *ah, bool wait_done) +{ + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; + u32 new_flags, to_set, to_clear; + + if (AR_SREV_9462_20(ah) && + mci->update_2g5g && + (mci->bt_state != MCI_BT_SLEEP)) { + + if (mci->is_2g) { + new_flags = MCI_2G_FLAGS; + to_clear = MCI_2G_FLAGS_CLEAR_MASK; + to_set = MCI_2G_FLAGS_SET_MASK; + } else { + new_flags = MCI_5G_FLAGS; + to_clear = MCI_5G_FLAGS_CLEAR_MASK; + to_set = MCI_5G_FLAGS_SET_MASK; + } + + ath_dbg(common, ATH_DBG_MCI, + "MCI BT_MCI_FLAGS: %s 0x%08x clr=0x%08x, set=0x%08x\n", + mci->is_2g ? "2G" : "5G", new_flags, to_clear, to_set); + + if (to_clear) + ar9003_mci_send_coex_bt_flags(ah, wait_done, + MCI_GPM_COEX_BT_FLAGS_CLEAR, to_clear); + + if (to_set) + ar9003_mci_send_coex_bt_flags(ah, wait_done, + MCI_GPM_COEX_BT_FLAGS_SET, to_set); + } + + if (AR_SREV_9462_10(ah) && (mci->bt_state != MCI_BT_SLEEP)) + mci->update_2g5g = false; +} + +static void ar9003_mci_queue_unsent_gpm(struct ath_hw *ah, u8 header, + u32 *payload, bool queue) +{ + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; + u8 type, opcode; + + if (queue) { + + if (payload) + ath_dbg(common, ATH_DBG_MCI, + "MCI ERROR: Send fail: %02x: %02x %02x %02x\n", + header, + *(((u8 *)payload) + 4), + *(((u8 *)payload) + 5), + *(((u8 *)payload) + 6)); + else + ath_dbg(common, ATH_DBG_MCI, + "MCI ERROR: Send fail: %02x\n", header); + } + + /* check if the message is to be queued */ + if (header != MCI_GPM) + return; + + type = MCI_GPM_TYPE(payload); + opcode = MCI_GPM_OPCODE(payload); + + if (type != MCI_GPM_COEX_AGENT) + return; + + switch (opcode) { + case MCI_GPM_COEX_BT_UPDATE_FLAGS: + + if (AR_SREV_9462_10(ah)) + break; + + if (*(((u8 *)payload) + MCI_GPM_COEX_B_BT_FLAGS_OP) == + MCI_GPM_COEX_BT_FLAGS_READ) + break; + + mci->update_2g5g = queue; + + if (queue) + ath_dbg(common, ATH_DBG_MCI, + "MCI BT_MCI_FLAGS: 2G5G status <queued> %s.\n", + mci->is_2g ? "2G" : "5G"); + else + ath_dbg(common, ATH_DBG_MCI, + "MCI BT_MCI_FLAGS: 2G5G status <sent> %s.\n", + mci->is_2g ? "2G" : "5G"); + + break; + + case MCI_GPM_COEX_WLAN_CHANNELS: + + mci->wlan_channels_update = queue; + if (queue) + ath_dbg(common, ATH_DBG_MCI, + "MCI WLAN channel map <queued>\n"); + else + ath_dbg(common, ATH_DBG_MCI, + "MCI WLAN channel map <sent>\n"); + break; + + case MCI_GPM_COEX_HALT_BT_GPM: + + if (*(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) == + MCI_GPM_COEX_BT_GPM_UNHALT) { + + mci->unhalt_bt_gpm = queue; + + if (queue) + ath_dbg(common, ATH_DBG_MCI, + "MCI UNHALT BT GPM <queued>\n"); + else { + mci->halted_bt_gpm = false; + ath_dbg(common, ATH_DBG_MCI, + "MCI UNHALT BT GPM <sent>\n"); + } + } + + if (*(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) == + MCI_GPM_COEX_BT_GPM_HALT) { + + mci->halted_bt_gpm = !queue; + + if (queue) + ath_dbg(common, ATH_DBG_MCI, + "MCI HALT BT GPM <not sent>\n"); + else + ath_dbg(common, ATH_DBG_MCI, + "MCI UNHALT BT GPM <sent>\n"); + } + + break; + default: + break; + } +} + +void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool wait_done) +{ + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; + + if (mci->update_2g5g) { + if (mci->is_2g) { + + ar9003_mci_send_2g5g_status(ah, true); + ath_dbg(common, ATH_DBG_MCI, "MCI Send LNA trans\n"); + ar9003_mci_send_lna_transfer(ah, true); + udelay(5); + + REG_CLR_BIT(ah, AR_MCI_TX_CTRL, + AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); + + if (AR_SREV_9462_20(ah)) { + REG_CLR_BIT(ah, AR_PHY_GLB_CONTROL, + AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL); + if (!(mci->config & + ATH_MCI_CONFIG_DISABLE_OSLA)) { + REG_SET_BIT(ah, AR_BTCOEX_CTRL, + AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); + } + } + } else { + ath_dbg(common, ATH_DBG_MCI, "MCI Send LNA take\n"); + ar9003_mci_send_lna_take(ah, true); + udelay(5); + + REG_SET_BIT(ah, AR_MCI_TX_CTRL, + AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); + + if (AR_SREV_9462_20(ah)) { + REG_SET_BIT(ah, AR_PHY_GLB_CONTROL, + AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL); + REG_CLR_BIT(ah, AR_BTCOEX_CTRL, + AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); + } + + ar9003_mci_send_2g5g_status(ah, true); + } + } +} + +bool ar9003_mci_send_message(struct ath_hw *ah, u8 header, u32 flag, + u32 *payload, u8 len, bool wait_done, + bool check_bt) +{ + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; + bool msg_sent = false; + u32 regval; + u32 saved_mci_int_en; + int i; + + saved_mci_int_en = REG_READ(ah, AR_MCI_INTERRUPT_EN); + regval = REG_READ(ah, AR_BTCOEX_CTRL); + + if ((regval == 0xdeadbeef) || !(regval & AR_BTCOEX_CTRL_MCI_MODE_EN)) { + + ath_dbg(common, ATH_DBG_MCI, + "MCI Not sending 0x%x. MCI is not enabled. " + "full_sleep = %d\n", header, + (ah->power_mode == ATH9K_PM_FULL_SLEEP) ? 1 : 0); + + ar9003_mci_queue_unsent_gpm(ah, header, payload, true); + return false; + + } else if (check_bt && (mci->bt_state == MCI_BT_SLEEP)) { + + ath_dbg(common, ATH_DBG_MCI, + "MCI Don't send message 0x%x. BT is in sleep state\n", header); + + ar9003_mci_queue_unsent_gpm(ah, header, payload, true); + return false; + } + + if (wait_done) + REG_WRITE(ah, AR_MCI_INTERRUPT_EN, 0); + + /* Need to clear SW_MSG_DONE raw bit before wait */ + + REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, + (AR_MCI_INTERRUPT_SW_MSG_DONE | + AR_MCI_INTERRUPT_MSG_FAIL_MASK)); + + if (payload) { + for (i = 0; (i * 4) < len; i++) + REG_WRITE(ah, (AR_MCI_TX_PAYLOAD0 + i * 4), + *(payload + i)); + } + + REG_WRITE(ah, AR_MCI_COMMAND0, + (SM((flag & MCI_FLAG_DISABLE_TIMESTAMP), + AR_MCI_COMMAND0_DISABLE_TIMESTAMP) | + SM(len, AR_MCI_COMMAND0_LEN) | + SM(header, AR_MCI_COMMAND0_HEADER))); + + if (wait_done && + !(ar9003_mci_wait_for_interrupt(ah, AR_MCI_INTERRUPT_RAW, + AR_MCI_INTERRUPT_SW_MSG_DONE, 500))) + ar9003_mci_queue_unsent_gpm(ah, header, payload, true); + else { + ar9003_mci_queue_unsent_gpm(ah, header, payload, false); + msg_sent = true; + } + + if (wait_done) + REG_WRITE(ah, AR_MCI_INTERRUPT_EN, saved_mci_int_en); + + return msg_sent; +} +EXPORT_SYMBOL(ar9003_mci_send_message); + +void ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf, + u16 len, u32 sched_addr) +{ + struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; + void *sched_buf = (void *)((char *) gpm_buf + (sched_addr - gpm_addr)); + + mci->gpm_addr = gpm_addr; + mci->gpm_buf = gpm_buf; + mci->gpm_len = len; + mci->sched_addr = sched_addr; + mci->sched_buf = sched_buf; + + ar9003_mci_reset(ah, true, true, true); +} +EXPORT_SYMBOL(ar9003_mci_setup); + +void ar9003_mci_cleanup(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + + /* Turn off MCI and Jupiter mode. */ + REG_WRITE(ah, AR_BTCOEX_CTRL, 0x00); + ath_dbg(common, ATH_DBG_MCI, "MCI ar9003_mci_cleanup\n"); + ar9003_mci_disable_interrupt(ah); +} +EXPORT_SYMBOL(ar9003_mci_cleanup); + +static void ar9003_mci_process_gpm_extra(struct ath_hw *ah, u8 gpm_type, + u8 gpm_opcode, u32 *p_gpm) +{ + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; + u8 *p_data = (u8 *) p_gpm; + + if (gpm_type != MCI_GPM_COEX_AGENT) + return; + + switch (gpm_opcode) { + case MCI_GPM_COEX_VERSION_QUERY: + ath_dbg(common, ATH_DBG_MCI, + "MCI Recv GPM COEX Version Query\n"); + ar9003_mci_send_coex_version_response(ah, true); + break; + case MCI_GPM_COEX_VERSION_RESPONSE: + ath_dbg(common, ATH_DBG_MCI, + "MCI Recv GPM COEX Version Response\n"); + mci->bt_ver_major = + *(p_data + MCI_GPM_COEX_B_MAJOR_VERSION); + mci->bt_ver_minor = + *(p_data + MCI_GPM_COEX_B_MINOR_VERSION); + mci->bt_version_known = true; + ath_dbg(common, ATH_DBG_MCI, + "MCI BT Coex version: %d.%d\n", + mci->bt_ver_major, + mci->bt_ver_minor); + break; + case MCI_GPM_COEX_STATUS_QUERY: + ath_dbg(common, ATH_DBG_MCI, + "MCI Recv GPM COEX Status Query = 0x%02X.\n", + *(p_data + MCI_GPM_COEX_B_WLAN_BITMAP)); + mci->wlan_channels_update = true; + ar9003_mci_send_coex_wlan_channels(ah, true); + break; + case MCI_GPM_COEX_BT_PROFILE_INFO: + mci->query_bt = true; + ath_dbg(common, ATH_DBG_MCI, + "MCI Recv GPM COEX BT_Profile_Info\n"); + break; + case MCI_GPM_COEX_BT_STATUS_UPDATE: + mci->query_bt = true; + ath_dbg(common, ATH_DBG_MCI, + "MCI Recv GPM COEX BT_Status_Update " + "SEQ=%d (drop&query)\n", *(p_gpm + 3)); + break; + default: + break; + } +} + +u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type, + u8 gpm_opcode, int time_out) +{ + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; + u32 *p_gpm = NULL, mismatch = 0, more_data; + u32 offset; + u8 recv_type = 0, recv_opcode = 0; + bool b_is_bt_cal_done = (gpm_type == MCI_GPM_BT_CAL_DONE); + + more_data = time_out ? MCI_GPM_NOMORE : MCI_GPM_MORE; + + while (time_out > 0) { + if (p_gpm) { + MCI_GPM_RECYCLE(p_gpm); + p_gpm = NULL; + } + + if (more_data != MCI_GPM_MORE) + time_out = ar9003_mci_wait_for_interrupt(ah, + AR_MCI_INTERRUPT_RX_MSG_RAW, + AR_MCI_INTERRUPT_RX_MSG_GPM, + time_out); + + if (!time_out) + break; + + offset = ar9003_mci_state(ah, + MCI_STATE_NEXT_GPM_OFFSET, &more_data); + + if (offset == MCI_GPM_INVALID) + continue; + + p_gpm = (u32 *) (mci->gpm_buf + offset); + recv_type = MCI_GPM_TYPE(p_gpm); + recv_opcode = MCI_GPM_OPCODE(p_gpm); + + if (MCI_GPM_IS_CAL_TYPE(recv_type)) { + + if (recv_type == gpm_type) { + + if ((gpm_type == MCI_GPM_BT_CAL_DONE) && + !b_is_bt_cal_done) { + gpm_type = MCI_GPM_BT_CAL_GRANT; + ath_dbg(common, ATH_DBG_MCI, + "MCI Recv BT_CAL_DONE" + "wait BT_CAL_GRANT\n"); + continue; + } + + break; + } + } else if ((recv_type == gpm_type) && + (recv_opcode == gpm_opcode)) + break; + + /* not expected message */ + + /* + * check if it's cal_grant + * + * When we're waiting for cal_grant in reset routine, + * it's possible that BT sends out cal_request at the + * same time. Since BT's calibration doesn't happen + * that often, we'll let BT completes calibration then + * we continue to wait for cal_grant from BT. + * Orginal: Wait BT_CAL_GRANT. + * New: Receive BT_CAL_REQ -> send WLAN_CAL_GRANT->wait + * BT_CAL_DONE -> Wait BT_CAL_GRANT. + */ + + if ((gpm_type == MCI_GPM_BT_CAL_GRANT) && + (recv_type == MCI_GPM_BT_CAL_REQ)) { + + u32 payload[4] = {0, 0, 0, 0}; + + gpm_type = MCI_GPM_BT_CAL_DONE; + ath_dbg(common, ATH_DBG_MCI, + "MCI Rcv BT_CAL_REQ, send WLAN_CAL_GRANT\n"); + + MCI_GPM_SET_CAL_TYPE(payload, + MCI_GPM_WLAN_CAL_GRANT); + + ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, + false, false); + + ath_dbg(common, ATH_DBG_MCI, + "MCI now wait for BT_CAL_DONE\n"); + + continue; + } else { + ath_dbg(common, ATH_DBG_MCI, "MCI GPM subtype" + "not match 0x%x\n", *(p_gpm + 1)); + mismatch++; + ar9003_mci_process_gpm_extra(ah, recv_type, + recv_opcode, p_gpm); + } + } + if (p_gpm) { + MCI_GPM_RECYCLE(p_gpm); + p_gpm = NULL; + } + + if (time_out <= 0) { + time_out = 0; + ath_dbg(common, ATH_DBG_MCI, + "MCI GPM received timeout, mismatch = %d\n", mismatch); + } else + ath_dbg(common, ATH_DBG_MCI, + "MCI Receive GPM type=0x%x, code=0x%x\n", + gpm_type, gpm_opcode); + + while (more_data == MCI_GPM_MORE) { + + ath_dbg(common, ATH_DBG_MCI, "MCI discard remaining GPM\n"); + offset = ar9003_mci_state(ah, MCI_STATE_NEXT_GPM_OFFSET, + &more_data); + + if (offset == MCI_GPM_INVALID) + break; + + p_gpm = (u32 *) (mci->gpm_buf + offset); + recv_type = MCI_GPM_TYPE(p_gpm); + recv_opcode = MCI_GPM_OPCODE(p_gpm); + + if (!MCI_GPM_IS_CAL_TYPE(recv_type)) + ar9003_mci_process_gpm_extra(ah, recv_type, + recv_opcode, p_gpm); + + MCI_GPM_RECYCLE(p_gpm); + } + + return time_out; +} + +u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data) +{ + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; + u32 value = 0, more_gpm = 0, gpm_ptr; + u8 query_type; + + switch (state_type) { + case MCI_STATE_ENABLE: + if (mci->ready) { + + value = REG_READ(ah, AR_BTCOEX_CTRL); + + if ((value == 0xdeadbeef) || (value == 0xffffffff)) + value = 0; + } + value &= AR_BTCOEX_CTRL_MCI_MODE_EN; + break; + case MCI_STATE_INIT_GPM_OFFSET: + value = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR); + ath_dbg(common, ATH_DBG_MCI, + "MCI GPM initial WRITE_PTR=%d\n", value); + mci->gpm_idx = value; + break; + case MCI_STATE_NEXT_GPM_OFFSET: + case MCI_STATE_LAST_GPM_OFFSET: + /* + * This could be useful to avoid new GPM message interrupt which + * may lead to spurious interrupt after power sleep, or multiple + * entry of ath_mci_intr(). + * Adding empty GPM check by returning HAL_MCI_GPM_INVALID can + * alleviate this effect, but clearing GPM RX interrupt bit is + * safe, because whether this is called from hw or driver code + * there must be an interrupt bit set/triggered initially + */ + REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, + AR_MCI_INTERRUPT_RX_MSG_GPM); + + gpm_ptr = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR); + value = gpm_ptr; + + if (value == 0) + value = mci->gpm_len - 1; + else if (value >= mci->gpm_len) { + if (value != 0xFFFF) { + value = 0; + ath_dbg(common, ATH_DBG_MCI, "MCI GPM offset" + "out of range\n"); + } + } else + value--; + + if (value == 0xFFFF) { + value = MCI_GPM_INVALID; + more_gpm = MCI_GPM_NOMORE; + ath_dbg(common, ATH_DBG_MCI, "MCI GPM ptr invalid" + "@ptr=%d, offset=%d, more=GPM_NOMORE\n", + gpm_ptr, value); + } else if (state_type == MCI_STATE_NEXT_GPM_OFFSET) { + + if (gpm_ptr == mci->gpm_idx) { + value = MCI_GPM_INVALID; + more_gpm = MCI_GPM_NOMORE; + + ath_dbg(common, ATH_DBG_MCI, "MCI GPM message" + "not available @ptr=%d, @offset=%d," + "more=GPM_NOMORE\n", gpm_ptr, value); + } else { + for (;;) { + + u32 temp_index; + + /* skip reserved GPM if any */ + + if (value != mci->gpm_idx) + more_gpm = MCI_GPM_MORE; + else + more_gpm = MCI_GPM_NOMORE; + + temp_index = mci->gpm_idx; + mci->gpm_idx++; + + if (mci->gpm_idx >= + mci->gpm_len) + mci->gpm_idx = 0; + + ath_dbg(common, ATH_DBG_MCI, + "MCI GPM message got ptr=%d," + "@offset=%d, more=%d\n", + gpm_ptr, temp_index, + (more_gpm == MCI_GPM_MORE)); + + if (ar9003_mci_is_gpm_valid(ah, + temp_index)) { + value = temp_index; + break; + } + + if (more_gpm == MCI_GPM_NOMORE) { + value = MCI_GPM_INVALID; + break; + } + } + } + if (p_data) + *p_data = more_gpm; + } + + if (value != MCI_GPM_INVALID) + value <<= 4; + + break; + case MCI_STATE_LAST_SCHD_MSG_OFFSET: + value = MS(REG_READ(ah, AR_MCI_RX_STATUS), + AR_MCI_RX_LAST_SCHD_MSG_INDEX); + /* Make it in bytes */ + value <<= 4; + break; + + case MCI_STATE_REMOTE_SLEEP: + value = MS(REG_READ(ah, AR_MCI_RX_STATUS), + AR_MCI_RX_REMOTE_SLEEP) ? + MCI_BT_SLEEP : MCI_BT_AWAKE; + break; + + case MCI_STATE_CONT_RSSI_POWER: + value = MS(mci->cont_status, AR_MCI_CONT_RSSI_POWER); + break; + + case MCI_STATE_CONT_PRIORITY: + value = MS(mci->cont_status, AR_MCI_CONT_RRIORITY); + break; + + case MCI_STATE_CONT_TXRX: + value = MS(mci->cont_status, AR_MCI_CONT_TXRX); + break; + + case MCI_STATE_BT: + value = mci->bt_state; + break; + + case MCI_STATE_SET_BT_SLEEP: + mci->bt_state = MCI_BT_SLEEP; + break; + + case MCI_STATE_SET_BT_AWAKE: + mci->bt_state = MCI_BT_AWAKE; + ar9003_mci_send_coex_version_query(ah, true); + ar9003_mci_send_coex_wlan_channels(ah, true); + + if (mci->unhalt_bt_gpm) { + + ath_dbg(common, ATH_DBG_MCI, + "MCI unhalt BT GPM\n"); + ar9003_mci_send_coex_halt_bt_gpm(ah, false, true); + } + + ar9003_mci_2g5g_switch(ah, true); + break; + + case MCI_STATE_SET_BT_CAL_START: + mci->bt_state = MCI_BT_CAL_START; + break; + + case MCI_STATE_SET_BT_CAL: + mci->bt_state = MCI_BT_CAL; + break; + + case MCI_STATE_RESET_REQ_WAKE: + ar9003_mci_reset_req_wakeup(ah); + mci->update_2g5g = true; + + if ((AR_SREV_9462_20_OR_LATER(ah)) && + (mci->config & ATH_MCI_CONFIG_MCI_OBS_MASK)) { + /* Check if we still have control of the GPIOs */ + if ((REG_READ(ah, AR_GLB_GPIO_CONTROL) & + ATH_MCI_CONFIG_MCI_OBS_GPIO) != + ATH_MCI_CONFIG_MCI_OBS_GPIO) { + + ath_dbg(common, ATH_DBG_MCI, + "MCI reconfigure observation"); + ar9003_mci_observation_set_up(ah); + } + } + break; + + case MCI_STATE_SEND_WLAN_COEX_VERSION: + ar9003_mci_send_coex_version_response(ah, true); + break; + + case MCI_STATE_SET_BT_COEX_VERSION: + + if (!p_data) + ath_dbg(common, ATH_DBG_MCI, + "MCI Set BT Coex version with NULL data!!\n"); + else { + mci->bt_ver_major = (*p_data >> 8) & 0xff; + mci->bt_ver_minor = (*p_data) & 0xff; + mci->bt_version_known = true; + ath_dbg(common, ATH_DBG_MCI, + "MCI BT version set: %d.%d\n", + mci->bt_ver_major, + mci->bt_ver_minor); + } + break; + + case MCI_STATE_SEND_WLAN_CHANNELS: + if (p_data) { + if (((mci->wlan_channels[1] & 0xffff0000) == + (*(p_data + 1) & 0xffff0000)) && + (mci->wlan_channels[2] == *(p_data + 2)) && + (mci->wlan_channels[3] == *(p_data + 3))) + break; + + mci->wlan_channels[0] = *p_data++; + mci->wlan_channels[1] = *p_data++; + mci->wlan_channels[2] = *p_data++; + mci->wlan_channels[3] = *p_data++; + } + mci->wlan_channels_update = true; + ar9003_mci_send_coex_wlan_channels(ah, true); + break; + + case MCI_STATE_SEND_VERSION_QUERY: + ar9003_mci_send_coex_version_query(ah, true); + break; + + case MCI_STATE_SEND_STATUS_QUERY: + query_type = (AR_SREV_9462_10(ah)) ? + MCI_GPM_COEX_QUERY_BT_ALL_INFO : + MCI_GPM_COEX_QUERY_BT_TOPOLOGY; + + ar9003_mci_send_coex_bt_status_query(ah, true, query_type); + break; + + case MCI_STATE_NEED_FLUSH_BT_INFO: + /* + * btcoex_hw.mci.unhalt_bt_gpm means whether it's + * needed to send UNHALT message. It's set whenever + * there's a request to send HALT message. + * mci_halted_bt_gpm means whether HALT message is sent + * out successfully. + * + * Checking (mci_unhalt_bt_gpm == false) instead of + * checking (ah->mci_halted_bt_gpm == false) will make + * sure currently is in UNHALT-ed mode and BT can + * respond to status query. + */ + value = (!mci->unhalt_bt_gpm && + mci->need_flush_btinfo) ? 1 : 0; + if (p_data) + mci->need_flush_btinfo = + (*p_data != 0) ? true : false; + break; + + case MCI_STATE_RECOVER_RX: + + ath_dbg(common, ATH_DBG_MCI, "MCI hw RECOVER_RX\n"); + ar9003_mci_prep_interface(ah); + mci->query_bt = true; + mci->need_flush_btinfo = true; + ar9003_mci_send_coex_wlan_channels(ah, true); + ar9003_mci_2g5g_switch(ah, true); + break; + + case MCI_STATE_NEED_FTP_STOMP: + value = !(mci->config & ATH_MCI_CONFIG_DISABLE_FTP_STOMP); + break; + + case MCI_STATE_NEED_TUNING: + value = !(mci->config & ATH_MCI_CONFIG_DISABLE_TUNING); + break; + + default: + break; + + } + + return value; +} +EXPORT_SYMBOL(ar9003_mci_state); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.h b/drivers/net/wireless/ath/ath9k/ar9003_mci.h new file mode 100644 index 000000000000..798da116a44c --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2010-2011 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef AR9003_MCI_H +#define AR9003_MCI_H + +#define MCI_FLAG_DISABLE_TIMESTAMP 0x00000001 /* Disable time stamp */ + +/* Default remote BT device MCI COEX version */ +#define MCI_GPM_COEX_MAJOR_VERSION_DEFAULT 3 +#define MCI_GPM_COEX_MINOR_VERSION_DEFAULT 0 + +/* Local WLAN MCI COEX version */ +#define MCI_GPM_COEX_MAJOR_VERSION_WLAN 3 +#define MCI_GPM_COEX_MINOR_VERSION_WLAN 0 + +enum mci_gpm_coex_query_type { + MCI_GPM_COEX_QUERY_BT_ALL_INFO = BIT(0), + MCI_GPM_COEX_QUERY_BT_TOPOLOGY = BIT(1), + MCI_GPM_COEX_QUERY_BT_DEBUG = BIT(2), +}; + +enum mci_gpm_coex_halt_bt_gpm { + MCI_GPM_COEX_BT_GPM_UNHALT, + MCI_GPM_COEX_BT_GPM_HALT +}; + +enum mci_gpm_coex_bt_update_flags_op { + MCI_GPM_COEX_BT_FLAGS_READ, + MCI_GPM_COEX_BT_FLAGS_SET, + MCI_GPM_COEX_BT_FLAGS_CLEAR +}; + +#define MCI_NUM_BT_CHANNELS 79 + +#define MCI_BT_MCI_FLAGS_UPDATE_CORR 0x00000002 +#define MCI_BT_MCI_FLAGS_UPDATE_HDR 0x00000004 +#define MCI_BT_MCI_FLAGS_UPDATE_PLD 0x00000008 +#define MCI_BT_MCI_FLAGS_LNA_CTRL 0x00000010 +#define MCI_BT_MCI_FLAGS_DEBUG 0x00000020 +#define MCI_BT_MCI_FLAGS_SCHED_MSG 0x00000040 +#define MCI_BT_MCI_FLAGS_CONT_MSG 0x00000080 +#define MCI_BT_MCI_FLAGS_COEX_GPM 0x00000100 +#define MCI_BT_MCI_FLAGS_CPU_INT_MSG 0x00000200 +#define MCI_BT_MCI_FLAGS_MCI_MODE 0x00000400 +#define MCI_BT_MCI_FLAGS_AR9462_MODE 0x00001000 +#define MCI_BT_MCI_FLAGS_OTHER 0x00010000 + +#define MCI_DEFAULT_BT_MCI_FLAGS 0x00011dde + +#define MCI_TOGGLE_BT_MCI_FLAGS (MCI_BT_MCI_FLAGS_UPDATE_CORR | \ + MCI_BT_MCI_FLAGS_UPDATE_HDR | \ + MCI_BT_MCI_FLAGS_UPDATE_PLD | \ + MCI_BT_MCI_FLAGS_MCI_MODE) + +#define MCI_2G_FLAGS_CLEAR_MASK 0x00000000 +#define MCI_2G_FLAGS_SET_MASK MCI_TOGGLE_BT_MCI_FLAGS +#define MCI_2G_FLAGS MCI_DEFAULT_BT_MCI_FLAGS + +#define MCI_5G_FLAGS_CLEAR_MASK MCI_TOGGLE_BT_MCI_FLAGS +#define MCI_5G_FLAGS_SET_MASK 0x00000000 +#define MCI_5G_FLAGS (MCI_DEFAULT_BT_MCI_FLAGS & \ + ~MCI_TOGGLE_BT_MCI_FLAGS) + +/* + * Default value for AR9462 is 0x00002201 + */ +#define ATH_MCI_CONFIG_CONCUR_TX 0x00000003 +#define ATH_MCI_CONFIG_MCI_OBS_MCI 0x00000004 +#define ATH_MCI_CONFIG_MCI_OBS_TXRX 0x00000008 +#define ATH_MCI_CONFIG_MCI_OBS_BT 0x00000010 +#define ATH_MCI_CONFIG_DISABLE_MCI_CAL 0x00000020 +#define ATH_MCI_CONFIG_DISABLE_OSLA 0x00000040 +#define ATH_MCI_CONFIG_DISABLE_FTP_STOMP 0x00000080 +#define ATH_MCI_CONFIG_AGGR_THRESH 0x00000700 +#define ATH_MCI_CONFIG_AGGR_THRESH_S 8 +#define ATH_MCI_CONFIG_DISABLE_AGGR_THRESH 0x00000800 +#define ATH_MCI_CONFIG_CLK_DIV 0x00003000 +#define ATH_MCI_CONFIG_CLK_DIV_S 12 +#define ATH_MCI_CONFIG_DISABLE_TUNING 0x00004000 +#define ATH_MCI_CONFIG_MCI_WEIGHT_DBG 0x40000000 +#define ATH_MCI_CONFIG_DISABLE_MCI 0x80000000 + +#define ATH_MCI_CONFIG_MCI_OBS_MASK (ATH_MCI_CONFIG_MCI_OBS_MCI | \ + ATH_MCI_CONFIG_MCI_OBS_TXRX | \ + ATH_MCI_CONFIG_MCI_OBS_BT) +#define ATH_MCI_CONFIG_MCI_OBS_GPIO 0x0000002F + +#endif diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index 497d7461838a..ed64114571fc 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -490,6 +490,8 @@ #define AR_PHY_TEST_CTL_TSTADC_EN_S 8 #define AR_PHY_TEST_CTL_RX_OBS_SEL 0x3C00 #define AR_PHY_TEST_CTL_RX_OBS_SEL_S 10 +#define AR_PHY_TEST_CTL_DEBUGPORT_SEL 0xe0000000 +#define AR_PHY_TEST_CTL_DEBUGPORT_SEL_S 29 #define AR_PHY_TSTDAC (AR_SM_BASE + 0x168) @@ -1001,6 +1003,7 @@ /* GLB Registers */ #define AR_GLB_BASE 0x20000 +#define AR_GLB_GPIO_CONTROL (AR_GLB_BASE) #define AR_PHY_GLB_CONTROL (AR_GLB_BASE + 0x44) #define AR_GLB_SCRATCH(_ah) (AR_GLB_BASE + \ (AR_SREV_9462_20(_ah) ? 0x4c : 0x50)) diff --git a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h index 259a6f312afb..dc2054f0378e 100644 --- a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h @@ -41,24 +41,24 @@ static const u32 ar9462_pciephy_clkreq_enable_L1_2p0[][2] = { static const u32 ar9462_2p0_baseband_postamble[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011}, - {0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e}, - {0x00009824, 0x5ac640de, 0x5ac640d0, 0x5ac640d0, 0x5ac640de}, - {0x00009828, 0x0796be89, 0x0696b081, 0x0696b881, 0x0796be89}, + {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a800d}, + {0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a01ae}, + {0x00009824, 0x5ac640de, 0x5ac640d0, 0x5ac640d0, 0x63c640da}, + {0x00009828, 0x0796be89, 0x0696b081, 0x0696b881, 0x09143e81}, {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, {0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c}, {0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4}, {0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x037216a0}, {0x00009e04, 0x001c2020, 0x001c2020, 0x001c2020, 0x001c2020}, - {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2}, - {0x00009e10, 0x92c88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x92c84d2e}, - {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3379605e, 0x33795d5e}, + {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000d8}, + {0x00009e10, 0x92c88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec86d2e}, + {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3376605e, 0x33795d5e}, {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, - {0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c782}, - {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27}, + {0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c282}, + {0x00009e44, 0x62321e27, 0x62321e27, 0xfe291e27, 0xfe291e27}, {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, {0x0000a204, 0x013187c0, 0x013187c4, 0x013187c4, 0x013187c0}, @@ -81,6 +81,15 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = { {0x0000a2d0, 0x00041981, 0x00041981, 0x00041981, 0x00041982}, {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b}, {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a3a4, 0x00000010, 0x00000010, 0x00000000, 0x00000000}, + {0x0000a3a8, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa}, + {0x0000a3ac, 0xaaaaaa00, 0xaaaaaa30, 0xaaaaaa00, 0xaaaaaa00}, + {0x0000a41c, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce}, + {0x0000a420, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce}, + {0x0000a424, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce}, + {0x0000a428, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce}, + {0x0000a42c, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce}, + {0x0000a430, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce}, {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, {0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x00100000}, {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, @@ -1107,11 +1116,11 @@ static const u32 ar9462_2p0_baseband_core[][2] = { {0x00009e30, 0x06336f77}, {0x00009e34, 0x6af6532f}, {0x00009e38, 0x0cc80c00}, - {0x00009e40, 0x0d261820}, + {0x00009e40, 0x15262820}, {0x00009e4c, 0x00001004}, {0x00009e50, 0x00ff03f1}, - {0x00009e54, 0xe4c355c7}, - {0x00009e58, 0xfd897735}, + {0x00009e54, 0xe4c555c2}, + {0x00009e58, 0xfd857722}, {0x00009e5c, 0xe9198724}, {0x00009fc0, 0x803e4788}, {0x00009fc4, 0x0001efb5}, @@ -1142,9 +1151,6 @@ static const u32 ar9462_2p0_baseband_core[][2] = { {0x0000a398, 0x001f0e0f}, {0x0000a39c, 0x0075393f}, {0x0000a3a0, 0xb79f6427}, - {0x0000a3a4, 0x00000000}, - {0x0000a3a8, 0xaaaaaaaa}, - {0x0000a3ac, 0x3c466478}, {0x0000a3c0, 0x20202020}, {0x0000a3c4, 0x22222220}, {0x0000a3c8, 0x20200020}, @@ -1167,12 +1173,6 @@ static const u32 ar9462_2p0_baseband_core[][2] = { {0x0000a40c, 0x00820820}, {0x0000a414, 0x1ce739ce}, {0x0000a418, 0x2d001dce}, - {0x0000a41c, 0x1ce739ce}, - {0x0000a420, 0x000001ce}, - {0x0000a424, 0x1ce739ce}, - {0x0000a428, 0x000001ce}, - {0x0000a42c, 0x1ce739ce}, - {0x0000a430, 0x1ce739ce}, {0x0000a434, 0x00000000}, {0x0000a438, 0x00001801}, {0x0000a43c, 0x00100000}, diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 93b45b4b3033..130e5dba9555 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -159,6 +159,9 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd, /* return block-ack bitmap index given sequence and starting sequence */ #define ATH_BA_INDEX(_st, _seq) (((_seq) - (_st)) & (IEEE80211_SEQ_MAX - 1)) +/* return the seqno for _start + _offset */ +#define ATH_BA_INDEX2SEQ(_seq, _offset) (((_seq) + (_offset)) & (IEEE80211_SEQ_MAX - 1)) + /* returns delimiter padding required given the packet length */ #define ATH_AGGR_GET_NDELIM(_len) \ (((_len) >= ATH_AGGR_MINPLEN) ? 0 : \ @@ -238,6 +241,7 @@ struct ath_atx_tid { struct ath_node *an; struct ath_atx_ac *ac; unsigned long tx_buf[BITS_TO_LONGS(ATH_TID_MAX_BUFS)]; + int bar_index; u16 seq_start; u16 seq_next; u16 baw_size; @@ -252,9 +256,9 @@ struct ath_atx_tid { struct ath_node { #ifdef CONFIG_ATH9K_DEBUGFS struct list_head list; /* for sc->nodes */ +#endif struct ieee80211_sta *sta; /* station struct we're part of */ struct ieee80211_vif *vif; /* interface with which we're associated */ -#endif struct ath_atx_tid tid[WME_NUM_TID]; struct ath_atx_ac ac[WME_NUM_AC]; int ps_key; @@ -276,7 +280,6 @@ struct ath_tx_control { }; #define ATH_TX_ERROR 0x01 -#define ATH_TX_BAR 0x02 /** * @txq_map: Index is mac80211 queue number. This is @@ -462,7 +465,7 @@ void ath9k_btcoex_timer_pause(struct ath_softc *sc); #define ATH_LED_PIN_9287 8 #define ATH_LED_PIN_9300 10 #define ATH_LED_PIN_9485 6 -#define ATH_LED_PIN_9462 0 +#define ATH_LED_PIN_9462 4 #ifdef CONFIG_MAC80211_LEDS void ath_init_leds(struct ath_softc *sc); @@ -542,7 +545,7 @@ struct ath_ant_comb { #define DEFAULT_CACHELINE 32 #define ATH_REGCLASSIDS_MAX 10 #define ATH_CABQ_READY_TIME 80 /* % of beacon interval */ -#define ATH_MAX_SW_RETRIES 10 +#define ATH_MAX_SW_RETRIES 30 #define ATH_CHAN_MAX 255 #define ATH_TXPOWER_MAX 100 /* .5 dBm units */ @@ -647,6 +650,7 @@ struct ath_softc { struct delayed_work tx_complete_work; struct delayed_work hw_pll_work; struct ath_btcoex btcoex; + struct ath_mci_coex mci_coex; struct ath_descdma txsdma; diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index 9ac28d9de597..bbb20810ec10 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -21,7 +21,7 @@ enum ath_bt_mode { ATH_BT_COEX_MODE_LEGACY, /* legacy rx_clear mode */ ATH_BT_COEX_MODE_UNSLOTTED, /* untimed/unslotted mode */ ATH_BT_COEX_MODE_SLOTTED, /* slotted mode */ - ATH_BT_COEX_MODE_DISALBED, /* coexistence disabled */ + ATH_BT_COEX_MODE_DISABLED, /* coexistence disabled */ }; struct ath_btcoex_config { diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index d5e5db1faad9..278361c867ca 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -54,8 +54,39 @@ enum ath_btcoex_scheme { ATH_BTCOEX_CFG_MCI, }; +struct ath9k_hw_mci { + u32 raw_intr; + u32 rx_msg_intr; + u32 cont_status; + u32 gpm_addr; + u32 gpm_len; + u32 gpm_idx; + u32 sched_addr; + u32 wlan_channels[4]; + u32 wlan_cal_seq; + u32 wlan_cal_done; + u32 config; + u8 *gpm_buf; + u8 *sched_buf; + bool ready; + bool update_2g5g; + bool is_2g; + bool query_bt; + bool unhalt_bt_gpm; /* need send UNHALT */ + bool halted_bt_gpm; /* HALT sent */ + bool need_flush_btinfo; + bool bt_version_known; + bool wlan_channels_update; + u8 wlan_ver_major; + u8 wlan_ver_minor; + u8 bt_ver_major; + u8 bt_ver_minor; + u8 bt_state; +}; + struct ath_btcoex_hw { enum ath_btcoex_scheme scheme; + struct ath9k_hw_mci mci; bool enabled; u8 wlanactive_gpio; u8 btactive_gpio; diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 6fb719d85b37..68d972bf232d 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -856,7 +856,7 @@ void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, sc->debug.stats.txstats[qnum].tx_bytes_all += bf->bf_mpdu->len; if (bf_isampdu(bf)) { - if (flags & ATH_TX_BAR) + if (flags & ATH_TX_ERROR) TX_STAT_INC(qnum, a_xretries); else TX_STAT_INC(qnum, a_completed); @@ -1630,6 +1630,9 @@ int ath9k_init_debug(struct ath_hw *ah) debugfs_create_file("debug", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_debug); #endif + + ath9k_dfs_init_debug(sc); + debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_dma); debugfs_create_file("interrupt", S_IRUSR, sc->debug.debugfs_phy, sc, diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index 356352ac2d6e..776a24ada600 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -19,6 +19,7 @@ #include "hw.h" #include "rc.h" +#include "dfs_debug.h" struct ath_txq; struct ath_buf; @@ -187,6 +188,7 @@ struct ath_stats { struct ath_interrupt_stats istats; struct ath_tx_stats txstats[ATH9K_NUM_TX_QUEUES]; struct ath_rx_stats rxstats; + struct ath_dfs_stats dfs_stats; u32 reset[__RESET_TYPE_MAX]; }; diff --git a/drivers/net/wireless/ath/ath9k/dfs.c b/drivers/net/wireless/ath/ath9k/dfs.c new file mode 100644 index 000000000000..e4e84a9e6273 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/dfs.c @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2008-2011 Atheros Communications Inc. + * Copyright (c) 2011 Neratec Solutions AG + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "hw.h" +#include "hw-ops.h" +#include "ath9k.h" +#include "dfs.h" +#include "dfs_debug.h" + +/* + * TODO: move into or synchronize this with generic header + * as soon as IF is defined + */ +struct dfs_radar_pulse { + u16 freq; + u64 ts; + u32 width; + u8 rssi; +}; + +/* internal struct to pass radar data */ +struct ath_radar_data { + u8 pulse_bw_info; + u8 rssi; + u8 ext_rssi; + u8 pulse_length_ext; + u8 pulse_length_pri; +}; + +/* convert pulse duration to usecs, considering clock mode */ +static u32 dur_to_usecs(struct ath_hw *ah, u32 dur) +{ + const u32 AR93X_NSECS_PER_DUR = 800; + const u32 AR93X_NSECS_PER_DUR_FAST = (8000 / 11); + u32 nsecs; + + if (IS_CHAN_A_FAST_CLOCK(ah, ah->curchan)) + nsecs = dur * AR93X_NSECS_PER_DUR_FAST; + else + nsecs = dur * AR93X_NSECS_PER_DUR; + + return (nsecs + 500) / 1000; +} + +#define PRI_CH_RADAR_FOUND 0x01 +#define EXT_CH_RADAR_FOUND 0x02 +static bool +ath9k_postprocess_radar_event(struct ath_softc *sc, + struct ath_radar_data *are, + struct dfs_radar_pulse *drp) +{ + u8 rssi; + u16 dur; + + ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_DFS, + "pulse_bw_info=0x%x, pri,ext len/rssi=(%u/%u, %u/%u)\n", + are->pulse_bw_info, + are->pulse_length_pri, are->rssi, + are->pulse_length_ext, are->ext_rssi); + + /* + * Only the last 2 bits of the BW info are relevant, they indicate + * which channel the radar was detected in. + */ + are->pulse_bw_info &= 0x03; + + switch (are->pulse_bw_info) { + case PRI_CH_RADAR_FOUND: + /* radar in ctrl channel */ + dur = are->pulse_length_pri; + DFS_STAT_INC(sc, pri_phy_errors); + /* + * cannot use ctrl channel RSSI + * if extension channel is stronger + */ + rssi = (are->ext_rssi >= (are->rssi + 3)) ? 0 : are->rssi; + break; + case EXT_CH_RADAR_FOUND: + /* radar in extension channel */ + dur = are->pulse_length_ext; + DFS_STAT_INC(sc, ext_phy_errors); + /* + * cannot use extension channel RSSI + * if control channel is stronger + */ + rssi = (are->rssi >= (are->ext_rssi + 12)) ? 0 : are->ext_rssi; + break; + case (PRI_CH_RADAR_FOUND | EXT_CH_RADAR_FOUND): + /* + * Conducted testing, when pulse is on DC, both pri and ext + * durations are reported to be same + * + * Radiated testing, when pulse is on DC, different pri and + * ext durations are reported, so take the larger of the two + */ + if (are->pulse_length_ext >= are->pulse_length_pri) + dur = are->pulse_length_ext; + else + dur = are->pulse_length_pri; + DFS_STAT_INC(sc, dc_phy_errors); + + /* when both are present use stronger one */ + rssi = (are->rssi < are->ext_rssi) ? are->ext_rssi : are->rssi; + break; + default: + /* + * Bogus bandwidth info was received in descriptor, + * so ignore this PHY error + */ + DFS_STAT_INC(sc, bwinfo_discards); + return false; + } + + if (rssi == 0) { + DFS_STAT_INC(sc, rssi_discards); + return false; + } + + /* + * TODO: check chirping pulses + * checks for chirping are dependent on the DFS regulatory domain + * used, which is yet TBD + */ + + /* convert duration to usecs */ + drp->width = dur_to_usecs(sc->sc_ah, dur); + drp->rssi = rssi; + + DFS_STAT_INC(sc, pulses_detected); + return true; +} +#undef PRI_CH_RADAR_FOUND +#undef EXT_CH_RADAR_FOUND + +/* + * DFS: check PHY-error for radar pulse and feed the detector + */ +void ath9k_dfs_process_phyerr(struct ath_softc *sc, void *data, + struct ath_rx_status *rs, u64 mactime) +{ + struct ath_radar_data ard; + u16 datalen; + char *vdata_end; + struct dfs_radar_pulse drp; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + + if ((!(rs->rs_phyerr != ATH9K_PHYERR_RADAR)) && + (!(rs->rs_phyerr != ATH9K_PHYERR_FALSE_RADAR_EXT))) { + ath_dbg(common, ATH_DBG_DFS, + "Error: rs_phyer=0x%x not a radar error\n", + rs->rs_phyerr); + return; + } + + datalen = rs->rs_datalen; + if (datalen == 0) { + DFS_STAT_INC(sc, datalen_discards); + return; + } + + ard.rssi = rs->rs_rssi_ctl0; + ard.ext_rssi = rs->rs_rssi_ext0; + + /* + * hardware stores this as 8 bit signed value. + * we will cap it at 0 if it is a negative number + */ + if (ard.rssi & 0x80) + ard.rssi = 0; + if (ard.ext_rssi & 0x80) + ard.ext_rssi = 0; + + vdata_end = (char *)data + datalen; + ard.pulse_bw_info = vdata_end[-1]; + ard.pulse_length_ext = vdata_end[-2]; + ard.pulse_length_pri = vdata_end[-3]; + + ath_dbg(common, ATH_DBG_DFS, + "bw_info=%d, length_pri=%d, length_ext=%d, " + "rssi_pri=%d, rssi_ext=%d\n", + ard.pulse_bw_info, ard.pulse_length_pri, ard.pulse_length_ext, + ard.rssi, ard.ext_rssi); + + drp.freq = ah->curchan->channel; + drp.ts = mactime; + if (ath9k_postprocess_radar_event(sc, &ard, &drp)) { + static u64 last_ts; + ath_dbg(common, ATH_DBG_DFS, + "ath9k_dfs_process_phyerr: channel=%d, ts=%llu, " + "width=%d, rssi=%d, delta_ts=%llu\n", + drp.freq, drp.ts, drp.width, drp.rssi, drp.ts-last_ts); + last_ts = drp.ts; + /* + * TODO: forward pulse to pattern detector + * + * ieee80211_add_radar_pulse(drp.freq, drp.ts, + * drp.width, drp.rssi); + */ + } +} diff --git a/drivers/net/wireless/ath/ath9k/dfs.h b/drivers/net/wireless/ath/ath9k/dfs.h new file mode 100644 index 000000000000..c2412857f122 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/dfs.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2008-2011 Atheros Communications Inc. + * Copyright (c) 2011 Neratec Solutions AG + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef ATH9K_DFS_H +#define ATH9K_DFS_H + +#if defined(CONFIG_ATH9K_DFS_CERTIFIED) +/** + * ath9k_dfs_process_phyerr - process radar PHY error + * @sc: ath_softc + * @data: RX payload data + * @rs: RX status after processing descriptor + * @mactime: receive time + * + * This function is called whenever the HW DFS module detects a radar + * pulse and reports it as a PHY error. + * + * The radar information provided as raw payload data is validated and + * filtered for false pulses. Events passing all tests are forwarded to + * the upper layer for pattern detection. + */ +void ath9k_dfs_process_phyerr(struct ath_softc *sc, void *data, + struct ath_rx_status *rs, u64 mactime); +#else +static inline void ath9k_dfs_process_phyerr(struct ath_softc *sc, void *data, + struct ath_rx_status *rs, u64 mactime) { } +#endif + +#endif /* ATH9K_DFS_H */ diff --git a/drivers/net/wireless/ath/ath9k/dfs_debug.c b/drivers/net/wireless/ath/ath9k/dfs_debug.c new file mode 100644 index 000000000000..106d031d834a --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/dfs_debug.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2008-2011 Atheros Communications Inc. + * Copyright (c) 2011 Neratec Solutions AG + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <linux/debugfs.h> +#include <linux/export.h> + +#include "ath9k.h" +#include "dfs_debug.h" + +#define ATH9K_DFS_STAT(s, p) \ + len += snprintf(buf + len, size - len, "%28s : %10u\n", s, \ + sc->debug.stats.dfs_stats.p); + +static ssize_t read_file_dfs(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + struct ath9k_hw_version *hw_ver = &sc->sc_ah->hw_version; + char *buf; + unsigned int len = 0, size = 8000; + ssize_t retval = 0; + + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + len += snprintf(buf + len, size - len, "DFS support for " + "macVersion = 0x%x, macRev = 0x%x: %s\n", + hw_ver->macVersion, hw_ver->macRev, + (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_DFS) ? + "enabled" : "disabled"); + ATH9K_DFS_STAT("DFS pulses detected ", pulses_detected); + ATH9K_DFS_STAT("Datalen discards ", datalen_discards); + ATH9K_DFS_STAT("RSSI discards ", rssi_discards); + ATH9K_DFS_STAT("BW info discards ", bwinfo_discards); + ATH9K_DFS_STAT("Primary channel pulses ", pri_phy_errors); + ATH9K_DFS_STAT("Secondary channel pulses", ext_phy_errors); + ATH9K_DFS_STAT("Dual channel pulses ", dc_phy_errors); + + if (len > size) + len = size; + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; +} + +static int ath9k_dfs_debugfs_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + + return 0; +} + +static const struct file_operations fops_dfs_stats = { + .read = read_file_dfs, + .open = ath9k_dfs_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +void ath9k_dfs_init_debug(struct ath_softc *sc) +{ + debugfs_create_file("dfs_stats", S_IRUSR, + sc->debug.debugfs_phy, sc, &fops_dfs_stats); +} diff --git a/drivers/net/wireless/ath/ath9k/dfs_debug.h b/drivers/net/wireless/ath/ath9k/dfs_debug.h new file mode 100644 index 000000000000..6e1e2a71659e --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/dfs_debug.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2008-2011 Atheros Communications Inc. + * Copyright (c) 2011 Neratec Solutions AG + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +#ifndef DFS_DEBUG_H +#define DFS_DEBUG_H + +#include "hw.h" + +/** + * struct ath_dfs_stats - DFS Statistics + * + * @pulses_detected: No. of pulses detected so far + * @datalen_discards: No. of pulses discarded due to invalid datalen + * @rssi_discards: No. of pulses discarded due to invalid RSSI + * @bwinfo_discards: No. of pulses discarded due to invalid BW info + * @pri_phy_errors: No. of pulses reported for primary channel + * @ext_phy_errors: No. of pulses reported for extension channel + * @dc_phy_errors: No. of pulses reported for primary + extension channel + */ +struct ath_dfs_stats { + u32 pulses_detected; + u32 datalen_discards; + u32 rssi_discards; + u32 bwinfo_discards; + u32 pri_phy_errors; + u32 ext_phy_errors; + u32 dc_phy_errors; +}; + +#if defined(CONFIG_ATH9K_DFS_DEBUGFS) + +#define DFS_STAT_INC(sc, c) (sc->debug.stats.dfs_stats.c++) +void ath9k_dfs_init_debug(struct ath_softc *sc); + +#else + +#define DFS_STAT_INC(sc, c) do { } while (0) +static inline void ath9k_dfs_init_debug(struct ath_softc *sc) { } + +#endif /* CONFIG_ATH9K_DFS_DEBUGFS */ + +#endif /* DFS_DEBUG_H */ diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index 9a7520f987f0..61fcab0e2d76 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -473,7 +473,7 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, int i; u16 twiceMinEdgePower; - u16 twiceMaxEdgePower = MAX_RATE_POWER; + u16 twiceMaxEdgePower; u16 scaledPower = 0, minCtlPower; u16 numCtlModes; const u16 *pCtlMode; @@ -542,9 +542,7 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, else freq = centers.ctl_center; - if (ah->eep_ops->get_eeprom_ver(ah) == 14 && - ah->eep_ops->get_eeprom_rev(ah) <= 2) - twiceMaxEdgePower = MAX_RATE_POWER; + twiceMaxEdgePower = MAX_RATE_POWER; for (i = 0; (i < AR5416_EEP4K_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c index 4f5c50a87ce3..0981c073471d 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -569,7 +569,7 @@ static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah, #define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 #define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 - u16 twiceMaxEdgePower = MAX_RATE_POWER; + u16 twiceMaxEdgePower; int i; struct cal_ctl_data_ar9287 *rep; struct cal_target_power_leg targetPowerOfdm = {0, {0, 0, 0, 0} }, @@ -669,6 +669,7 @@ static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah, else freq = centers.ctl_center; + twiceMaxEdgePower = MAX_RATE_POWER; /* Walk through the CTL indices stored in EEPROM */ for (i = 0; (i < AR9287_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { struct cal_ctl_edges *pRdEdgesPower; diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c index 81e629671679..9681c099d0a5 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_def.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c @@ -385,7 +385,7 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) if ((ah->hw_version.devid == AR9280_DEVID_PCI) && ((eep->baseEepHeader.version & 0xff) > 0x0a) && (eep->baseEepHeader.pwdclkind == 0)) - ah->need_an_top2_fixup = 1; + ah->need_an_top2_fixup = true; if ((common->bus_ops->ath_bus_type == ATH_USB) && (AR_SREV_9280(ah))) @@ -1000,7 +1000,7 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, #define REDUCE_SCALED_POWER_BY_THREE_CHAIN 9 /* 10*log10(3)*2 */ struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; - u16 twiceMaxEdgePower = MAX_RATE_POWER; + u16 twiceMaxEdgePower; int i; struct cal_ctl_data *rep; struct cal_target_power_leg targetPowerOfdm, targetPowerCck = { @@ -1121,9 +1121,7 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, else freq = centers.ctl_center; - if (ah->eep_ops->get_eeprom_ver(ah) == 14 && - ah->eep_ops->get_eeprom_rev(ah) <= 2) - twiceMaxEdgePower = MAX_RATE_POWER; + twiceMaxEdgePower = MAX_RATE_POWER; for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { if ((((cfgCtl & ~CTL_MODE_M) | diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 0b9a0e8a4958..f8ce4ea6f65c 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -808,7 +808,8 @@ void ath9k_htc_ani_work(struct work_struct *work) } /* Verify whether we must check ANI */ - if ((timestamp - common->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) { + if (ah->config.enable_ani && + (timestamp - common->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) { aniflag = true; common->ani.checkani_timer = timestamp; } @@ -838,7 +839,7 @@ set_timer: * short calibration and long calibration. */ cal_interval = ATH_LONG_CALINTERVAL; - if (priv->ah->config.enable_ani) + if (ah->config.enable_ani) cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL); if (!common->ani.caldone) cal_interval = min(cal_interval, (u32)short_cal_interval); diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h index e74c233757a2..c4ad0b06bdbc 100644 --- a/drivers/net/wireless/ath/ath9k/hw-ops.h +++ b/drivers/net/wireless/ath/ath9k/hw-ops.h @@ -212,4 +212,13 @@ static inline int ath9k_hw_fast_chan_change(struct ath_hw *ah, return ath9k_hw_private_ops(ah)->fast_chan_change(ah, chan, ini_reloaded); } + +static inline void ath9k_hw_set_radar_params(struct ath_hw *ah) +{ + if (!ath9k_hw_private_ops(ah)->set_radar_params) + return; + + ath9k_hw_private_ops(ah)->set_radar_params(ah, &ah->radar_conf); +} + #endif /* ATH9K_HW_OPS_H */ diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 8876134b35bd..8cda9a1513a7 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -504,7 +504,7 @@ static int ath9k_hw_post_init(struct ath_hw *ah) return ecode; } - if (!AR_SREV_9100(ah) && !AR_SREV_9340(ah)) { + if (ah->config.enable_ani) { ath9k_hw_ani_setup(ah); ath9k_hw_ani_init(ah); } @@ -610,6 +610,10 @@ static int __ath9k_hw_init(struct ath_hw *ah) if (!AR_SREV_9300_20_OR_LATER(ah)) ah->ani_function &= ~ATH9K_ANI_MRC_CCK; + /* disable ANI for 9340 */ + if (AR_SREV_9340(ah)) + ah->config.enable_ani = false; + ath9k_hw_init_mode_regs(ah); if (!ah->is_pciexpress) @@ -1350,6 +1354,7 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah) static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type) { + bool ret = false; if (AR_SREV_9300_20_OR_LATER(ah)) { REG_WRITE(ah, AR_WA, ah->WARegVal); @@ -1361,13 +1366,20 @@ static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type) switch (type) { case ATH9K_RESET_POWER_ON: - return ath9k_hw_set_reset_power_on(ah); + ret = ath9k_hw_set_reset_power_on(ah); + break; case ATH9K_RESET_WARM: case ATH9K_RESET_COLD: - return ath9k_hw_set_reset(ah, type); + ret = ath9k_hw_set_reset(ah, type); + break; default: - return false; + break; } + + if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI) + REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2); + + return ret; } static bool ath9k_hw_chip_reset(struct ath_hw *ah, @@ -1506,6 +1518,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, struct ath9k_hw_cal_data *caldata, bool bChannelChange) { struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; u32 saveLedState; struct ath9k_channel *curchan = ah->curchan; u32 saveDefAntenna; @@ -1513,6 +1526,53 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, u64 tsf = 0; int i, r; bool allow_fbs = false; + bool mci = !!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI); + bool save_fullsleep = ah->chip_fullsleep; + + if (mci) { + + ar9003_mci_2g5g_changed(ah, IS_CHAN_2GHZ(chan)); + + if (mci_hw->bt_state == MCI_BT_CAL_START) { + u32 payload[4] = {0, 0, 0, 0}; + + ath_dbg(common, ATH_DBG_MCI, "MCI stop rx for BT CAL"); + + mci_hw->bt_state = MCI_BT_CAL; + + /* + * MCI FIX: disable mci interrupt here. This is to avoid + * SW_MSG_DONE or RX_MSG bits to trigger MCI_INT and + * lead to mci_intr reentry. + */ + + ar9003_mci_disable_interrupt(ah); + + ath_dbg(common, ATH_DBG_MCI, "send WLAN_CAL_GRANT"); + MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_GRANT); + ar9003_mci_send_message(ah, MCI_GPM, 0, payload, + 16, true, false); + + ath_dbg(common, ATH_DBG_MCI, "\nMCI BT is calibrating"); + + /* Wait BT calibration to be completed for 25ms */ + + if (ar9003_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_DONE, + 0, 25000)) + ath_dbg(common, ATH_DBG_MCI, + "MCI got BT_CAL_DONE\n"); + else + ath_dbg(common, ATH_DBG_MCI, + "MCI ### BT cal takes to long, force" + "bt_state to be bt_awake\n"); + mci_hw->bt_state = MCI_BT_AWAKE; + /* MCI FIX: enable mci interrupt here */ + ar9003_mci_enable_interrupt(ah); + + return true; + } + } + if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) return -EIO; @@ -1550,12 +1610,29 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, if (ath9k_hw_channel_change(ah, chan)) { ath9k_hw_loadnf(ah, ah->curchan); ath9k_hw_start_nfcal(ah, true); + if (mci && mci_hw->ready) + ar9003_mci_2g5g_switch(ah, true); + if (AR_SREV_9271(ah)) ar9002_hw_load_ani_reg(ah, chan); return 0; } } + if (mci) { + ar9003_mci_disable_interrupt(ah); + + if (mci_hw->ready && !save_fullsleep) { + ar9003_mci_mute_bt(ah); + udelay(20); + REG_WRITE(ah, AR_BTCOEX_CTRL, 0); + } + + mci_hw->bt_state = MCI_BT_SLEEP; + mci_hw->ready = false; + } + + saveDefAntenna = REG_READ(ah, AR_DEF_ANTENNA); if (saveDefAntenna == 0) saveDefAntenna = 1; @@ -1611,6 +1688,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, if (r) return r; + if (mci) + ar9003_mci_reset(ah, false, IS_CHAN_2GHZ(chan), save_fullsleep); + /* * Some AR91xx SoC devices frequently fail to accept TSF writes * right after the chip reset. When that happens, write a new @@ -1728,6 +1808,55 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ath9k_hw_loadnf(ah, chan); ath9k_hw_start_nfcal(ah, true); + if (mci && mci_hw->ready) { + + if (IS_CHAN_2GHZ(chan) && + (mci_hw->bt_state == MCI_BT_SLEEP)) { + + if (ar9003_mci_check_int(ah, + AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET) || + ar9003_mci_check_int(ah, + AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)) { + + /* + * BT is sleeping. Check if BT wakes up during + * WLAN calibration. If BT wakes up during + * WLAN calibration, need to go through all + * message exchanges again and recal. + */ + + ath_dbg(common, ATH_DBG_MCI, "MCI BT wakes up" + "during WLAN calibration\n"); + + REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, + AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET | + AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE); + ath_dbg(common, ATH_DBG_MCI, "MCI send" + "REMOTE_RESET\n"); + ar9003_mci_remote_reset(ah, true); + ar9003_mci_send_sys_waking(ah, true); + udelay(1); + if (IS_CHAN_2GHZ(chan)) + ar9003_mci_send_lna_transfer(ah, true); + + mci_hw->bt_state = MCI_BT_AWAKE; + + ath_dbg(common, ATH_DBG_MCI, "MCI re-cal\n"); + + if (caldata) { + caldata->done_txiqcal_once = false; + caldata->done_txclcal_once = false; + caldata->rtt_hist.num_readings = 0; + } + + if (!ath9k_hw_init_cal(ah, chan)) + return -EIO; + + } + } + ar9003_mci_enable_interrupt(ah); + } + ENABLE_REGWRITE_BUFFER(ah); ath9k_hw_restore_chainmask(ah); @@ -1770,6 +1899,21 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, if (ah->btcoex_hw.enabled) ath9k_hw_btcoex_enable(ah); + if (mci && mci_hw->ready) { + /* + * check BT state again to make + * sure it's not changed. + */ + + ar9003_mci_sync_bt_state(ah); + ar9003_mci_2g5g_switch(ah, true); + + if ((mci_hw->bt_state == MCI_BT_AWAKE) && + (mci_hw->query_bt == true)) { + mci_hw->need_flush_btinfo = true; + } + } + if (AR_SREV_9300_20_OR_LATER(ah)) { ar9003_hw_bb_watchdog_config(ah); @@ -1934,6 +2078,7 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip) bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode) { struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; int status = true, setChip = true; static const char *modes[] = { "AWAKE", @@ -1951,12 +2096,35 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode) switch (mode) { case ATH9K_PM_AWAKE: status = ath9k_hw_set_power_awake(ah, setChip); + + if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI) + REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2); + break; case ATH9K_PM_FULL_SLEEP: + + if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI) { + if (ar9003_mci_state(ah, MCI_STATE_ENABLE, NULL) && + (mci->bt_state != MCI_BT_SLEEP) && + !mci->halted_bt_gpm) { + ath_dbg(common, ATH_DBG_MCI, "MCI halt BT GPM" + "(full_sleep)"); + ar9003_mci_send_coex_halt_bt_gpm(ah, + true, true); + } + + mci->ready = false; + REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2); + } + ath9k_set_power_sleep(ah, setChip); ah->chip_fullsleep = true; break; case ATH9K_PM_NETWORK_SLEEP: + + if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI) + REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2); + ath9k_set_power_network_sleep(ah, setChip); break; default: @@ -2109,6 +2277,30 @@ static u8 fixup_chainmask(u8 chip_chainmask, u8 eeprom_chainmask) return chip_chainmask; } +/** + * ath9k_hw_dfs_tested - checks if DFS has been tested with used chipset + * @ah: the atheros hardware data structure + * + * We enable DFS support upstream on chipsets which have passed a series + * of tests. The testing requirements are going to be documented. Desired + * test requirements are documented at: + * + * http://wireless.kernel.org/en/users/Drivers/ath9k/dfs + * + * Once a new chipset gets properly tested an individual commit can be used + * to document the testing for DFS for that chipset. + */ +static bool ath9k_hw_dfs_tested(struct ath_hw *ah) +{ + + switch (ah->hw_version.macVersion) { + /* AR9580 will likely be our first target to get testing on */ + case AR_SREV_VERSION_9580: + default: + return false; + } +} + int ath9k_hw_fill_cap_info(struct ath_hw *ah) { struct ath9k_hw_capabilities *pCap = &ah->caps; @@ -2149,6 +2341,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) if (AR_SREV_9485(ah) || AR_SREV_9285(ah) || AR_SREV_9330(ah)) chip_chainmask = 1; + else if (AR_SREV_9462(ah)) + chip_chainmask = 3; else if (!AR_SREV_9280_20_OR_LATER(ah)) chip_chainmask = 7; else if (!AR_SREV_9300_20_OR_LATER(ah) || AR_SREV_9340(ah)) @@ -2205,12 +2399,10 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) else pCap->num_gpio_pins = AR_NUM_GPIO; - if (AR_SREV_9160_10_OR_LATER(ah) || AR_SREV_9100(ah)) { - pCap->hw_caps |= ATH9K_HW_CAP_CST; + if (AR_SREV_9160_10_OR_LATER(ah) || AR_SREV_9100(ah)) pCap->rts_aggr_limit = ATH_AMPDU_LIMIT_MAX; - } else { + else pCap->rts_aggr_limit = (8 * 1024); - } #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) ah->rfsilent = ah->eep_ops->get_eeprom(ah, EEP_RF_SILENT); @@ -2234,7 +2426,9 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS; if (common->btcoex_enabled) { - if (AR_SREV_9300_20_OR_LATER(ah)) { + if (AR_SREV_9462(ah)) + btcoex_hw->scheme = ATH_BTCOEX_CFG_MCI; + else if (AR_SREV_9300_20_OR_LATER(ah)) { btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE; btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9300; btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9300; @@ -2318,6 +2512,9 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) pCap->pcie_lcr_offset = 0x80; } + if (ath9k_hw_dfs_tested(ah)) + pCap->hw_caps |= ATH9K_HW_CAP_DFS; + tx_chainmask = pCap->tx_chainmask; rx_chainmask = pCap->rx_chainmask; while (tx_chainmask || rx_chainmask) { @@ -2332,7 +2529,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) if (AR_SREV_9300_20_OR_LATER(ah)) { ah->enabled_cals |= TX_IQ_CAL; - if (!AR_SREV_9330(ah)) + if (AR_SREV_9485_OR_LATER(ah)) ah->enabled_cals |= TX_IQ_ON_AGC_CAL; } if (AR_SREV_9462(ah)) diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 3cb878c28ccf..615cc839f0de 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -126,6 +126,16 @@ #define AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL 4 #define AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED 5 #define AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED 6 +#define AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_DATA 0x16 +#define AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_CLK 0x17 +#define AR_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA 0x18 +#define AR_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK 0x19 +#define AR_GPIO_OUTPUT_MUX_AS_WL_IN_TX 0x14 +#define AR_GPIO_OUTPUT_MUX_AS_WL_IN_RX 0x13 +#define AR_GPIO_OUTPUT_MUX_AS_BT_IN_TX 9 +#define AR_GPIO_OUTPUT_MUX_AS_BT_IN_RX 8 +#define AR_GPIO_OUTPUT_MUX_AS_RUCKUS_STROBE 0x1d +#define AR_GPIO_OUTPUT_MUX_AS_RUCKUS_DATA 0x1e #define AR_GPIOD_MASK 0x00001FFF #define AR_GPIO_BIT(_gpio) (1 << (_gpio)) @@ -186,21 +196,21 @@ enum ath_ini_subsys { enum ath9k_hw_caps { ATH9K_HW_CAP_HT = BIT(0), ATH9K_HW_CAP_RFSILENT = BIT(1), - ATH9K_HW_CAP_CST = BIT(2), - ATH9K_HW_CAP_AUTOSLEEP = BIT(4), - ATH9K_HW_CAP_4KB_SPLITTRANS = BIT(5), - ATH9K_HW_CAP_EDMA = BIT(6), - ATH9K_HW_CAP_RAC_SUPPORTED = BIT(7), - ATH9K_HW_CAP_LDPC = BIT(8), - ATH9K_HW_CAP_FASTCLOCK = BIT(9), - ATH9K_HW_CAP_SGI_20 = BIT(10), - ATH9K_HW_CAP_PAPRD = BIT(11), - ATH9K_HW_CAP_ANT_DIV_COMB = BIT(12), - ATH9K_HW_CAP_2GHZ = BIT(13), - ATH9K_HW_CAP_5GHZ = BIT(14), - ATH9K_HW_CAP_APM = BIT(15), - ATH9K_HW_CAP_RTT = BIT(16), - ATH9K_HW_CAP_MCI = BIT(17), + ATH9K_HW_CAP_AUTOSLEEP = BIT(2), + ATH9K_HW_CAP_4KB_SPLITTRANS = BIT(3), + ATH9K_HW_CAP_EDMA = BIT(4), + ATH9K_HW_CAP_RAC_SUPPORTED = BIT(5), + ATH9K_HW_CAP_LDPC = BIT(6), + ATH9K_HW_CAP_FASTCLOCK = BIT(7), + ATH9K_HW_CAP_SGI_20 = BIT(8), + ATH9K_HW_CAP_PAPRD = BIT(9), + ATH9K_HW_CAP_ANT_DIV_COMB = BIT(10), + ATH9K_HW_CAP_2GHZ = BIT(11), + ATH9K_HW_CAP_5GHZ = BIT(12), + ATH9K_HW_CAP_APM = BIT(13), + ATH9K_HW_CAP_RTT = BIT(14), + ATH9K_HW_CAP_MCI = BIT(15), + ATH9K_HW_CAP_DFS = BIT(16), }; struct ath9k_hw_capabilities { @@ -266,6 +276,7 @@ enum ath9k_int { ATH9K_INT_TX = 0x00000040, ATH9K_INT_TXDESC = 0x00000080, ATH9K_INT_TIM_TIMER = 0x00000100, + ATH9K_INT_MCI = 0x00000200, ATH9K_INT_BB_WATCHDOG = 0x00000400, ATH9K_INT_TXURN = 0x00000800, ATH9K_INT_MIB = 0x00001000, @@ -417,6 +428,25 @@ enum ath9k_rx_qtype { ATH9K_RX_QUEUE_MAX, }; +enum mci_message_header { /* length of payload */ + MCI_LNA_CTRL = 0x10, /* len = 0 */ + MCI_CONT_NACK = 0x20, /* len = 0 */ + MCI_CONT_INFO = 0x30, /* len = 4 */ + MCI_CONT_RST = 0x40, /* len = 0 */ + MCI_SCHD_INFO = 0x50, /* len = 16 */ + MCI_CPU_INT = 0x60, /* len = 4 */ + MCI_SYS_WAKING = 0x70, /* len = 0 */ + MCI_GPM = 0x80, /* len = 16 */ + MCI_LNA_INFO = 0x90, /* len = 1 */ + MCI_LNA_STATE = 0x94, + MCI_LNA_TAKE = 0x98, + MCI_LNA_TRANS = 0x9c, + MCI_SYS_SLEEPING = 0xa0, /* len = 0 */ + MCI_REQ_WAKE = 0xc0, /* len = 0 */ + MCI_DEBUG_16 = 0xfe, /* len = 2 */ + MCI_REMOTE_RESET = 0xff /* len = 16 */ +}; + enum ath_mci_gpm_coex_profile_type { MCI_GPM_COEX_PROFILE_UNKNOWN, MCI_GPM_COEX_PROFILE_RFCOMM, @@ -427,6 +457,132 @@ enum ath_mci_gpm_coex_profile_type { MCI_GPM_COEX_PROFILE_MAX }; +/* MCI GPM/Coex opcode/type definitions */ +enum { + MCI_GPM_COEX_W_GPM_PAYLOAD = 1, + MCI_GPM_COEX_B_GPM_TYPE = 4, + MCI_GPM_COEX_B_GPM_OPCODE = 5, + /* MCI_GPM_WLAN_CAL_REQ, MCI_GPM_WLAN_CAL_DONE */ + MCI_GPM_WLAN_CAL_W_SEQUENCE = 2, + + /* MCI_GPM_COEX_VERSION_QUERY */ + /* MCI_GPM_COEX_VERSION_RESPONSE */ + MCI_GPM_COEX_B_MAJOR_VERSION = 6, + MCI_GPM_COEX_B_MINOR_VERSION = 7, + /* MCI_GPM_COEX_STATUS_QUERY */ + MCI_GPM_COEX_B_BT_BITMAP = 6, + MCI_GPM_COEX_B_WLAN_BITMAP = 7, + /* MCI_GPM_COEX_HALT_BT_GPM */ + MCI_GPM_COEX_B_HALT_STATE = 6, + /* MCI_GPM_COEX_WLAN_CHANNELS */ + MCI_GPM_COEX_B_CHANNEL_MAP = 6, + /* MCI_GPM_COEX_BT_PROFILE_INFO */ + MCI_GPM_COEX_B_PROFILE_TYPE = 6, + MCI_GPM_COEX_B_PROFILE_LINKID = 7, + MCI_GPM_COEX_B_PROFILE_STATE = 8, + MCI_GPM_COEX_B_PROFILE_ROLE = 9, + MCI_GPM_COEX_B_PROFILE_RATE = 10, + MCI_GPM_COEX_B_PROFILE_VOTYPE = 11, + MCI_GPM_COEX_H_PROFILE_T = 12, + MCI_GPM_COEX_B_PROFILE_W = 14, + MCI_GPM_COEX_B_PROFILE_A = 15, + /* MCI_GPM_COEX_BT_STATUS_UPDATE */ + MCI_GPM_COEX_B_STATUS_TYPE = 6, + MCI_GPM_COEX_B_STATUS_LINKID = 7, + MCI_GPM_COEX_B_STATUS_STATE = 8, + /* MCI_GPM_COEX_BT_UPDATE_FLAGS */ + MCI_GPM_COEX_W_BT_FLAGS = 6, + MCI_GPM_COEX_B_BT_FLAGS_OP = 10 +}; + +enum mci_gpm_subtype { + MCI_GPM_BT_CAL_REQ = 0, + MCI_GPM_BT_CAL_GRANT = 1, + MCI_GPM_BT_CAL_DONE = 2, + MCI_GPM_WLAN_CAL_REQ = 3, + MCI_GPM_WLAN_CAL_GRANT = 4, + MCI_GPM_WLAN_CAL_DONE = 5, + MCI_GPM_COEX_AGENT = 0x0c, + MCI_GPM_RSVD_PATTERN = 0xfe, + MCI_GPM_RSVD_PATTERN32 = 0xfefefefe, + MCI_GPM_BT_DEBUG = 0xff +}; + +enum mci_bt_state { + MCI_BT_SLEEP, + MCI_BT_AWAKE, + MCI_BT_CAL_START, + MCI_BT_CAL +}; + +/* Type of state query */ +enum mci_state_type { + MCI_STATE_ENABLE, + MCI_STATE_INIT_GPM_OFFSET, + MCI_STATE_NEXT_GPM_OFFSET, + MCI_STATE_LAST_GPM_OFFSET, + MCI_STATE_BT, + MCI_STATE_SET_BT_SLEEP, + MCI_STATE_SET_BT_AWAKE, + MCI_STATE_SET_BT_CAL_START, + MCI_STATE_SET_BT_CAL, + MCI_STATE_LAST_SCHD_MSG_OFFSET, + MCI_STATE_REMOTE_SLEEP, + MCI_STATE_CONT_RSSI_POWER, + MCI_STATE_CONT_PRIORITY, + MCI_STATE_CONT_TXRX, + MCI_STATE_RESET_REQ_WAKE, + MCI_STATE_SEND_WLAN_COEX_VERSION, + MCI_STATE_SET_BT_COEX_VERSION, + MCI_STATE_SEND_WLAN_CHANNELS, + MCI_STATE_SEND_VERSION_QUERY, + MCI_STATE_SEND_STATUS_QUERY, + MCI_STATE_NEED_FLUSH_BT_INFO, + MCI_STATE_SET_CONCUR_TX_PRI, + MCI_STATE_RECOVER_RX, + MCI_STATE_NEED_FTP_STOMP, + MCI_STATE_NEED_TUNING, + MCI_STATE_DEBUG, + MCI_STATE_MAX +}; + +enum mci_gpm_coex_opcode { + MCI_GPM_COEX_VERSION_QUERY, + MCI_GPM_COEX_VERSION_RESPONSE, + MCI_GPM_COEX_STATUS_QUERY, + MCI_GPM_COEX_HALT_BT_GPM, + MCI_GPM_COEX_WLAN_CHANNELS, + MCI_GPM_COEX_BT_PROFILE_INFO, + MCI_GPM_COEX_BT_STATUS_UPDATE, + MCI_GPM_COEX_BT_UPDATE_FLAGS +}; + +#define MCI_GPM_NOMORE 0 +#define MCI_GPM_MORE 1 +#define MCI_GPM_INVALID 0xffffffff + +#define MCI_GPM_RECYCLE(_p_gpm) do { \ + *(((u32 *)_p_gpm) + MCI_GPM_COEX_W_GPM_PAYLOAD) = \ + MCI_GPM_RSVD_PATTERN32; \ +} while (0) + +#define MCI_GPM_TYPE(_p_gpm) \ + (*(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_TYPE) & 0xff) + +#define MCI_GPM_OPCODE(_p_gpm) \ + (*(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_OPCODE) & 0xff) + +#define MCI_GPM_SET_CAL_TYPE(_p_gpm, _cal_type) do { \ + *(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_TYPE) = (_cal_type) & 0xff;\ +} while (0) + +#define MCI_GPM_SET_TYPE_OPCODE(_p_gpm, _type, _opcode) do { \ + *(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_TYPE) = (_type) & 0xff; \ + *(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_OPCODE) = (_opcode) & 0xff;\ +} while (0) + +#define MCI_GPM_IS_CAL_TYPE(_type) ((_type) <= MCI_GPM_WLAN_CAL_DONE) + struct ath9k_beacon_state { u32 bs_nexttbtt; u32 bs_nextdtim; @@ -954,7 +1110,6 @@ bool ath9k_hw_disable(struct ath_hw *ah); void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit, bool test); void ath9k_hw_setopmode(struct ath_hw *ah); void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1); -void ath9k_hw_setbssidmask(struct ath_hw *ah); void ath9k_hw_write_associd(struct ath_hw *ah); u32 ath9k_hw_gettsf32(struct ath_hw *ah); u64 ath9k_hw_gettsf64(struct ath_hw *ah); @@ -1047,6 +1202,32 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning); void ath9k_hw_proc_mib_event(struct ath_hw *ah); void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan); +bool ar9003_mci_send_message(struct ath_hw *ah, u8 header, u32 flag, + u32 *payload, u8 len, bool wait_done, + bool check_bt); +void ar9003_mci_mute_bt(struct ath_hw *ah); +u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data); +void ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf, + u16 len, u32 sched_addr); +void ar9003_mci_cleanup(struct ath_hw *ah); +void ar9003_mci_send_coex_halt_bt_gpm(struct ath_hw *ah, bool halt, + bool wait_done); +u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type, + u8 gpm_opcode, int time_out); +void ar9003_mci_2g5g_changed(struct ath_hw *ah, bool is_2g); +void ar9003_mci_disable_interrupt(struct ath_hw *ah); +void ar9003_mci_enable_interrupt(struct ath_hw *ah); +void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool wait_done); +void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g, + bool is_full_sleep); +bool ar9003_mci_check_int(struct ath_hw *ah, u32 ints); +void ar9003_mci_remote_reset(struct ath_hw *ah, bool wait_done); +void ar9003_mci_send_sys_waking(struct ath_hw *ah, bool wait_done); +void ar9003_mci_send_lna_transfer(struct ath_hw *ah, bool wait_done); +void ar9003_mci_sync_bt_state(struct ath_hw *ah); +void ar9003_mci_get_interrupt(struct ath_hw *ah, u32 *raw_intr, + u32 *rx_msg_intr); + #define ATH9K_CLOCK_RATE_CCK 22 #define ATH9K_CLOCK_RATE_5GHZ_OFDM 40 #define ATH9K_CLOCK_RATE_2GHZ_OFDM 44 diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index e046de94836a..c5df98139c4d 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -258,6 +258,8 @@ static void setup_ht_cap(struct ath_softc *sc, if (AR_SREV_9330(ah) || AR_SREV_9485(ah)) max_streams = 1; + else if (AR_SREV_9462(ah)) + max_streams = 2; else if (AR_SREV_9300_20_OR_LATER(ah)) max_streams = 3; else @@ -295,9 +297,22 @@ static int ath9k_reg_notifier(struct wiphy *wiphy, { struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct ath_softc *sc = hw->priv; - struct ath_regulatory *reg = ath9k_hw_regulatory(sc->sc_ah); + struct ath_hw *ah = sc->sc_ah; + struct ath_regulatory *reg = ath9k_hw_regulatory(ah); + int ret; + + ret = ath_reg_notifier_apply(wiphy, request, reg); + + /* Set tx power */ + if (ah->curchan) { + sc->config.txpowlimit = 2 * ah->curchan->chan->max_power; + ath9k_ps_wakeup(sc); + ath9k_hw_set_txpowerlimit(ah, sc->config.txpowlimit, false); + sc->curtxpow = ath9k_hw_regulatory(ah)->power_limit; + ath9k_ps_restore(sc); + } - return ath_reg_notifier_apply(wiphy, request, reg); + return ret; } /* @@ -408,6 +423,7 @@ fail: static int ath9k_init_btcoex(struct ath_softc *sc) { struct ath_txq *txq; + struct ath_hw *ah = sc->sc_ah; int r; switch (sc->sc_ah->btcoex_hw.scheme) { @@ -424,8 +440,37 @@ static int ath9k_init_btcoex(struct ath_softc *sc) txq = sc->tx.txq_map[WME_AC_BE]; ath9k_hw_init_btcoex_hw(sc->sc_ah, txq->axq_qnum); sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW; + break; + case ATH_BTCOEX_CFG_MCI: + sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW; sc->btcoex.duty_cycle = ATH_BTCOEX_DEF_DUTY_CYCLE; INIT_LIST_HEAD(&sc->btcoex.mci.info); + + r = ath_mci_setup(sc); + if (r) + return r; + + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI) { + ah->btcoex_hw.mci.ready = false; + ah->btcoex_hw.mci.bt_state = 0; + ah->btcoex_hw.mci.bt_ver_major = 3; + ah->btcoex_hw.mci.bt_ver_minor = 0; + ah->btcoex_hw.mci.bt_version_known = false; + ah->btcoex_hw.mci.update_2g5g = true; + ah->btcoex_hw.mci.is_2g = true; + ah->btcoex_hw.mci.wlan_channels_update = false; + ah->btcoex_hw.mci.wlan_channels[0] = 0x00000000; + ah->btcoex_hw.mci.wlan_channels[1] = 0xffffffff; + ah->btcoex_hw.mci.wlan_channels[2] = 0xffffffff; + ah->btcoex_hw.mci.wlan_channels[3] = 0x7fffffff; + ah->btcoex_hw.mci.query_bt = true; + ah->btcoex_hw.mci.unhalt_bt_gpm = true; + ah->btcoex_hw.mci.halted_bt_gpm = false; + ah->btcoex_hw.mci.need_flush_btinfo = false; + ah->btcoex_hw.mci.wlan_cal_seq = 0; + ah->btcoex_hw.mci.wlan_cal_done = 0; + ah->btcoex_hw.mci.config = 0x2201; + } break; default: WARN_ON(1); @@ -839,6 +884,9 @@ static void ath9k_deinit_softc(struct ath_softc *sc) sc->sc_ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) ath_gen_timer_free(sc->sc_ah, sc->btcoex.no_stomp_timer); + if (sc->sc_ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_MCI) + ath_mci_cleanup(sc); + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) if (ATH_TXQ_SETUP(sc, i)) ath_tx_cleanupq(sc, &sc->tx.txq[i]); diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index ecdb6fd29079..0e4fbb3bea33 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -760,7 +760,10 @@ bool ath9k_hw_intrpend(struct ath_hw *ah) return true; host_isr = REG_READ(ah, AR_INTR_ASYNC_CAUSE); - if ((host_isr & AR_INTR_MAC_IRQ) && (host_isr != AR_INTR_SPURIOUS)) + + if (((host_isr & AR_INTR_MAC_IRQ) || + (host_isr & AR_INTR_ASYNC_MASK_MCI)) && + (host_isr != AR_INTR_SPURIOUS)) return true; host_isr = REG_READ(ah, AR_INTR_SYNC_CAUSE); @@ -798,6 +801,7 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); u32 sync_default = AR_INTR_SYNC_DEFAULT; + u32 async_mask; if (!(ah->imask & ATH9K_INT_GLOBAL)) return; @@ -812,13 +816,16 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah) if (AR_SREV_9340(ah)) sync_default &= ~AR_INTR_SYNC_HOST1_FATAL; + async_mask = AR_INTR_MAC_IRQ; + + if (ah->imask & ATH9K_INT_MCI) + async_mask |= AR_INTR_ASYNC_MASK_MCI; + ath_dbg(common, ATH_DBG_INTERRUPT, "enable IER\n"); REG_WRITE(ah, AR_IER, AR_IER_ENABLE); if (!AR_SREV_9100(ah)) { - REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, - AR_INTR_MAC_IRQ); - REG_WRITE(ah, AR_INTR_ASYNC_MASK, AR_INTR_MAC_IRQ); - + REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, async_mask); + REG_WRITE(ah, AR_INTR_ASYNC_MASK, async_mask); REG_WRITE(ah, AR_INTR_SYNC_ENABLE, sync_default); REG_WRITE(ah, AR_INTR_SYNC_MASK, sync_default); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index e43c41cff25b..7fbc4bdd4efe 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -118,7 +118,7 @@ void ath9k_ps_restore(struct ath_softc *sc) if (--sc->ps_usecount != 0) goto unlock; - if (sc->ps_idle) + if (sc->ps_idle && (sc->ps_flags & PS_WAIT_FOR_TX_ACK)) mode = ATH9K_PM_FULL_SLEEP; else if (sc->ps_enabled && !(sc->ps_flags & (PS_WAIT_FOR_BEACON | @@ -286,7 +286,7 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) ath_start_ani(common); } - if (ath9k_hw_ops(ah)->antdiv_comb_conf_get && sc->ant_rx != 3) { + if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx != 3) { struct ath_hw_antcomb_conf div_ant_conf; u8 lna_conf; @@ -332,7 +332,8 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan, hchan = ah->curchan; } - if (fastcc && !ath9k_hw_check_alive(ah)) + if (fastcc && (ah->chip_fullsleep || + !ath9k_hw_check_alive(ah))) fastcc = false; if (!ath_prepare_reset(sc, retry_tx, flush)) @@ -561,7 +562,6 @@ void ath_ani_calibrate(unsigned long data) /* Long calibration runs independently of short calibration. */ if ((timestamp - common->ani.longcal_timer) >= long_cal_interval) { longcal = true; - ath_dbg(common, ATH_DBG_ANI, "longcal @%lu\n", jiffies); common->ani.longcal_timer = timestamp; } @@ -569,8 +569,6 @@ void ath_ani_calibrate(unsigned long data) if (!common->ani.caldone) { if ((timestamp - common->ani.shortcal_timer) >= short_cal_interval) { shortcal = true; - ath_dbg(common, ATH_DBG_ANI, - "shortcal @%lu\n", jiffies); common->ani.shortcal_timer = timestamp; common->ani.resetcal_timer = timestamp; } @@ -584,8 +582,9 @@ void ath_ani_calibrate(unsigned long data) } /* Verify whether we must check ANI */ - if ((timestamp - common->ani.checkani_timer) >= - ah->config.ani_poll_interval) { + if (sc->sc_ah->config.enable_ani + && (timestamp - common->ani.checkani_timer) >= + ah->config.ani_poll_interval) { aniflag = true; common->ani.checkani_timer = timestamp; } @@ -605,6 +604,11 @@ void ath_ani_calibrate(unsigned long data) ah->rxchainmask, longcal); } + ath_dbg(common, ATH_DBG_ANI, + "Calibration @%lu finished: %s %s %s, caldone: %s\n", jiffies, + longcal ? "long" : "", shortcal ? "short" : "", + aniflag ? "ani" : "", common->ani.caldone ? "true" : "false"); + ath9k_ps_restore(sc); set_timer: @@ -640,9 +644,9 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta, spin_lock(&sc->nodes_lock); list_add(&an->list, &sc->nodes); spin_unlock(&sc->nodes_lock); +#endif an->sta = sta; an->vif = vif; -#endif if (sc->sc_flags & SC_OP_TXAGGR) { ath_tx_node_init(sc, an); an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + @@ -742,6 +746,9 @@ void ath9k_tasklet(unsigned long data) if (status & ATH9K_INT_GENTIMER) ath_gen_timer_isr(sc->sc_ah); + if (status & ATH9K_INT_MCI) + ath_mci_intr(sc); + out: /* re-enable hardware interrupt */ ath9k_hw_enable_interrupts(ah); @@ -764,7 +771,8 @@ irqreturn_t ath_isr(int irq, void *dev) ATH9K_INT_BMISS | \ ATH9K_INT_CST | \ ATH9K_INT_TSFOOR | \ - ATH9K_INT_GENTIMER) + ATH9K_INT_GENTIMER | \ + ATH9K_INT_MCI) struct ath_softc *sc = dev; struct ath_hw *ah = sc->sc_ah; @@ -882,82 +890,6 @@ chip_reset: #undef SCHED_INTR } -static void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) -{ - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - struct ieee80211_channel *channel = hw->conf.channel; - int r; - - ath9k_ps_wakeup(sc); - spin_lock_bh(&sc->sc_pcu_lock); - atomic_set(&ah->intr_ref_cnt, -1); - - ath9k_hw_configpcipowersave(ah, false); - - if (!ah->curchan) - ah->curchan = ath9k_cmn_get_curchannel(sc->hw, ah); - - r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); - if (r) { - ath_err(common, - "Unable to reset channel (%u MHz), reset status %d\n", - channel->center_freq, r); - } - - ath_complete_reset(sc, true); - - /* Enable LED */ - ath9k_hw_cfg_output(ah, ah->led_pin, - AR_GPIO_OUTPUT_MUX_AS_OUTPUT); - ath9k_hw_set_gpio(ah, ah->led_pin, 0); - - spin_unlock_bh(&sc->sc_pcu_lock); - - ath9k_ps_restore(sc); -} - -void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) -{ - struct ath_hw *ah = sc->sc_ah; - struct ieee80211_channel *channel = hw->conf.channel; - int r; - - ath9k_ps_wakeup(sc); - - ath_cancel_work(sc); - - spin_lock_bh(&sc->sc_pcu_lock); - - /* - * Keep the LED on when the radio is disabled - * during idle unassociated state. - */ - if (!sc->ps_idle) { - ath9k_hw_set_gpio(ah, ah->led_pin, 1); - ath9k_hw_cfg_gpio_input(ah, ah->led_pin); - } - - ath_prepare_reset(sc, false, true); - - if (!ah->curchan) - ah->curchan = ath9k_cmn_get_curchannel(hw, ah); - - r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); - if (r) { - ath_err(ath9k_hw_common(sc->sc_ah), - "Unable to reset channel (%u MHz), reset status %d\n", - channel->center_freq, r); - } - - ath9k_hw_phy_disable(ah); - - ath9k_hw_configpcipowersave(ah, true); - - spin_unlock_bh(&sc->sc_pcu_lock); - ath9k_ps_restore(sc); -} - static int ath_reset(struct ath_softc *sc, bool retry_tx) { int r; @@ -1093,6 +1025,9 @@ static int ath9k_start(struct ieee80211_hw *hw) * and then setup of the interrupt mask. */ spin_lock_bh(&sc->sc_pcu_lock); + + atomic_set(&ah->intr_ref_cnt, -1); + r = ath9k_hw_reset(ah, init_channel, ah->caldata, false); if (r) { ath_err(common, @@ -1119,6 +1054,9 @@ static int ath9k_start(struct ieee80211_hw *hw) if (ah->caps.hw_caps & ATH9K_HW_CAP_HT) ah->imask |= ATH9K_INT_CST; + if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI) + ah->imask |= ATH9K_INT_MCI; + sc->sc_flags &= ~SC_OP_INVALID; sc->sc_ah->is_monitoring = false; @@ -1131,6 +1069,18 @@ static int ath9k_start(struct ieee80211_hw *hw) goto mutex_unlock; } + if (ah->led_pin >= 0) { + ath9k_hw_cfg_output(ah, ah->led_pin, + AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + ath9k_hw_set_gpio(ah, ah->led_pin, 0); + } + + /* + * Reset key cache to sane defaults (all entries cleared) instead of + * semi-random values after suspend/resume. + */ + ath9k_cmn_init_crypto(sc->sc_ah); + spin_unlock_bh(&sc->sc_pcu_lock); if ((ah->btcoex_hw.scheme != ATH_BTCOEX_CFG_NONE) && @@ -1176,6 +1126,13 @@ static void ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) } } + /* + * Cannot tx while the hardware is in full sleep, it first needs a full + * chip reset to recover from that + */ + if (unlikely(sc->sc_ah->power_mode == ATH9K_PM_FULL_SLEEP)) + goto exit; + if (unlikely(sc->sc_ah->power_mode != ATH9K_PM_AWAKE)) { /* * We are using PS-Poll and mac80211 can request TX while in @@ -1222,6 +1179,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); + bool prev_idle; mutex_lock(&sc->mutex); @@ -1252,35 +1210,45 @@ static void ath9k_stop(struct ieee80211_hw *hw) * before setting the invalid flag. */ ath9k_hw_disable_interrupts(ah); - if (!(sc->sc_flags & SC_OP_INVALID)) { - ath_drain_all_txq(sc, false); - ath_stoprecv(sc); - ath9k_hw_phy_disable(ah); - } else - sc->rx.rxlink = NULL; + spin_unlock_bh(&sc->sc_pcu_lock); + + /* we can now sync irq and kill any running tasklets, since we already + * disabled interrupts and not holding a spin lock */ + synchronize_irq(sc->irq); + tasklet_kill(&sc->intr_tq); + tasklet_kill(&sc->bcon_tasklet); + + prev_idle = sc->ps_idle; + sc->ps_idle = true; + + spin_lock_bh(&sc->sc_pcu_lock); + + if (ah->led_pin >= 0) { + ath9k_hw_set_gpio(ah, ah->led_pin, 1); + ath9k_hw_cfg_gpio_input(ah, ah->led_pin); + } + + ath_prepare_reset(sc, false, true); if (sc->rx.frag) { dev_kfree_skb_any(sc->rx.frag); sc->rx.frag = NULL; } - /* disable HAL and put h/w to sleep */ - ath9k_hw_disable(ah); + if (!ah->curchan) + ah->curchan = ath9k_cmn_get_curchannel(hw, ah); + + ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); + ath9k_hw_phy_disable(ah); - spin_unlock_bh(&sc->sc_pcu_lock); + ath9k_hw_configpcipowersave(ah, true); - /* we can now sync irq and kill any running tasklets, since we already - * disabled interrupts and not holding a spin lock */ - synchronize_irq(sc->irq); - tasklet_kill(&sc->intr_tq); - tasklet_kill(&sc->bcon_tasklet); + spin_unlock_bh(&sc->sc_pcu_lock); ath9k_ps_restore(sc); - sc->ps_idle = true; - ath_radio_disable(sc, hw); - sc->sc_flags |= SC_OP_INVALID; + sc->ps_idle = prev_idle; mutex_unlock(&sc->mutex); @@ -1620,8 +1588,8 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_conf *conf = &hw->conf; - bool disable_radio = false; + ath9k_ps_wakeup(sc); mutex_lock(&sc->mutex); /* @@ -1632,13 +1600,8 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) */ if (changed & IEEE80211_CONF_CHANGE_IDLE) { sc->ps_idle = !!(conf->flags & IEEE80211_CONF_IDLE); - if (!sc->ps_idle) { - ath_radio_enable(sc, hw); - ath_dbg(common, ATH_DBG_CONFIG, - "not-idle: enabling radio\n"); - } else { - disable_radio = true; - } + if (sc->ps_idle) + ath_cancel_work(sc); } /* @@ -1745,18 +1708,12 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) ath_dbg(common, ATH_DBG_CONFIG, "Set power: %d\n", conf->power_level); sc->config.txpowlimit = 2 * conf->power_level; - ath9k_ps_wakeup(sc); ath9k_cmn_update_txpow(ah, sc->curtxpow, sc->config.txpowlimit, &sc->curtxpow); - ath9k_ps_restore(sc); - } - - if (disable_radio) { - ath_dbg(common, ATH_DBG_CONFIG, "idle: disabling radio\n"); - ath_radio_disable(sc, hw); } mutex_unlock(&sc->mutex); + ath9k_ps_restore(sc); return 0; } @@ -1916,7 +1873,8 @@ static int ath9k_set_key(struct ieee80211_hw *hw, if (ath9k_modparam_nohwcrypt) return -ENOSPC; - if (vif->type == NL80211_IFTYPE_ADHOC && + if ((vif->type == NL80211_IFTYPE_ADHOC || + vif->type == NL80211_IFTYPE_MESH_POINT) && (key->cipher == WLAN_CIPHER_SUITE_TKIP || key->cipher == WLAN_CIPHER_SUITE_CCMP) && !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { @@ -2324,9 +2282,6 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop) return; } - if (drop) - timeout = 1; - for (j = 0; j < timeout; j++) { bool npend = false; @@ -2344,21 +2299,22 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop) } if (!npend) - goto out; + break; } - ath9k_ps_wakeup(sc); - spin_lock_bh(&sc->sc_pcu_lock); - drain_txq = ath_drain_all_txq(sc, false); - spin_unlock_bh(&sc->sc_pcu_lock); + if (drop) { + ath9k_ps_wakeup(sc); + spin_lock_bh(&sc->sc_pcu_lock); + drain_txq = ath_drain_all_txq(sc, false); + spin_unlock_bh(&sc->sc_pcu_lock); - if (!drain_txq) - ath_reset(sc, false); + if (!drain_txq) + ath_reset(sc, false); - ath9k_ps_restore(sc); - ieee80211_wake_queues(hw); + ath9k_ps_restore(sc); + ieee80211_wake_queues(hw); + } -out: ieee80211_queue_delayed_work(hw, &sc->tx_complete_work, 0); mutex_unlock(&sc->mutex); } diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c index 0fbb141bc302..691bf47906e2 100644 --- a/drivers/net/wireless/ath/ath9k/mci.c +++ b/drivers/net/wireless/ath/ath9k/mci.c @@ -14,6 +14,9 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <linux/dma-mapping.h> +#include <linux/slab.h> + #include "ath9k.h" #include "mci.h" @@ -181,8 +184,58 @@ static void ath_mci_update_scheme(struct ath_softc *sc) ath9k_btcoex_timer_resume(sc); } -void ath_mci_process_profile(struct ath_softc *sc, - struct ath_mci_profile_info *info) + +static void ath_mci_cal_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + u32 payload[4] = {0, 0, 0, 0}; + + switch (opcode) { + case MCI_GPM_BT_CAL_REQ: + + ath_dbg(common, ATH_DBG_MCI, "MCI received BT_CAL_REQ\n"); + + if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_AWAKE) { + ar9003_mci_state(ah, MCI_STATE_SET_BT_CAL_START, NULL); + ieee80211_queue_work(sc->hw, &sc->hw_reset_work); + } else + ath_dbg(common, ATH_DBG_MCI, + "MCI State mismatches: %d\n", + ar9003_mci_state(ah, MCI_STATE_BT, NULL)); + + break; + + case MCI_GPM_BT_CAL_DONE: + + ath_dbg(common, ATH_DBG_MCI, "MCI received BT_CAL_DONE\n"); + + if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_CAL) + ath_dbg(common, ATH_DBG_MCI, "MCI error illegal!\n"); + else + ath_dbg(common, ATH_DBG_MCI, "MCI BT not in CAL state\n"); + + break; + + case MCI_GPM_BT_CAL_GRANT: + + ath_dbg(common, ATH_DBG_MCI, "MCI received BT_CAL_GRANT\n"); + + /* Send WLAN_CAL_DONE for now */ + ath_dbg(common, ATH_DBG_MCI, "MCI send WLAN_CAL_DONE\n"); + MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_DONE); + ar9003_mci_send_message(sc->sc_ah, MCI_GPM, 0, payload, + 16, false, true); + break; + + default: + ath_dbg(common, ATH_DBG_MCI, "MCI Unknown GPM CAL message\n"); + break; + } +} + +static void ath_mci_process_profile(struct ath_softc *sc, + struct ath_mci_profile_info *info) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_btcoex *btcoex = &sc->btcoex; @@ -208,8 +261,8 @@ void ath_mci_process_profile(struct ath_softc *sc, ath_mci_update_scheme(sc); } -void ath_mci_process_status(struct ath_softc *sc, - struct ath_mci_profile_status *status) +static void ath_mci_process_status(struct ath_softc *sc, + struct ath_mci_profile_status *status) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_btcoex *btcoex = &sc->btcoex; @@ -252,3 +305,369 @@ void ath_mci_process_status(struct ath_softc *sc, if (old_num_mgmt != mci->num_mgmt) ath_mci_update_scheme(sc); } + +static void ath_mci_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_mci_profile_info profile_info; + struct ath_mci_profile_status profile_status; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + u32 version; + u8 major; + u8 minor; + u32 seq_num; + + switch (opcode) { + + case MCI_GPM_COEX_VERSION_QUERY: + ath_dbg(common, ATH_DBG_MCI, + "MCI Recv GPM COEX Version Query.\n"); + version = ar9003_mci_state(ah, + MCI_STATE_SEND_WLAN_COEX_VERSION, NULL); + break; + + case MCI_GPM_COEX_VERSION_RESPONSE: + ath_dbg(common, ATH_DBG_MCI, + "MCI Recv GPM COEX Version Response.\n"); + major = *(rx_payload + MCI_GPM_COEX_B_MAJOR_VERSION); + minor = *(rx_payload + MCI_GPM_COEX_B_MINOR_VERSION); + ath_dbg(common, ATH_DBG_MCI, + "MCI BT Coex version: %d.%d\n", major, minor); + version = (major << 8) + minor; + version = ar9003_mci_state(ah, + MCI_STATE_SET_BT_COEX_VERSION, &version); + break; + + case MCI_GPM_COEX_STATUS_QUERY: + ath_dbg(common, ATH_DBG_MCI, + "MCI Recv GPM COEX Status Query = 0x%02x.\n", + *(rx_payload + MCI_GPM_COEX_B_WLAN_BITMAP)); + ar9003_mci_state(ah, + MCI_STATE_SEND_WLAN_CHANNELS, NULL); + break; + + case MCI_GPM_COEX_BT_PROFILE_INFO: + ath_dbg(common, ATH_DBG_MCI, + "MCI Recv GPM Coex BT profile info\n"); + memcpy(&profile_info, + (rx_payload + MCI_GPM_COEX_B_PROFILE_TYPE), 10); + + if ((profile_info.type == MCI_GPM_COEX_PROFILE_UNKNOWN) + || (profile_info.type >= + MCI_GPM_COEX_PROFILE_MAX)) { + + ath_dbg(common, ATH_DBG_MCI, + "illegal profile type = %d," + "state = %d\n", profile_info.type, + profile_info.start); + break; + } + + ath_mci_process_profile(sc, &profile_info); + break; + + case MCI_GPM_COEX_BT_STATUS_UPDATE: + profile_status.is_link = *(rx_payload + + MCI_GPM_COEX_B_STATUS_TYPE); + profile_status.conn_handle = *(rx_payload + + MCI_GPM_COEX_B_STATUS_LINKID); + profile_status.is_critical = *(rx_payload + + MCI_GPM_COEX_B_STATUS_STATE); + + seq_num = *((u32 *)(rx_payload + 12)); + ath_dbg(common, ATH_DBG_MCI, + "MCI Recv GPM COEX BT_Status_Update: " + "is_link=%d, linkId=%d, state=%d, SEQ=%d\n", + profile_status.is_link, profile_status.conn_handle, + profile_status.is_critical, seq_num); + + ath_mci_process_status(sc, &profile_status); + break; + + default: + ath_dbg(common, ATH_DBG_MCI, + "MCI Unknown GPM COEX message = 0x%02x\n", opcode); + break; + } +} + +static int ath_mci_buf_alloc(struct ath_softc *sc, struct ath_mci_buf *buf) +{ + int error = 0; + + buf->bf_addr = dma_alloc_coherent(sc->dev, buf->bf_len, + &buf->bf_paddr, GFP_KERNEL); + + if (buf->bf_addr == NULL) { + error = -ENOMEM; + goto fail; + } + + return 0; + +fail: + memset(buf, 0, sizeof(*buf)); + return error; +} + +static void ath_mci_buf_free(struct ath_softc *sc, struct ath_mci_buf *buf) +{ + if (buf->bf_addr) { + dma_free_coherent(sc->dev, buf->bf_len, buf->bf_addr, + buf->bf_paddr); + memset(buf, 0, sizeof(*buf)); + } +} + +int ath_mci_setup(struct ath_softc *sc) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_mci_coex *mci = &sc->mci_coex; + int error = 0; + + mci->sched_buf.bf_len = ATH_MCI_SCHED_BUF_SIZE + ATH_MCI_GPM_BUF_SIZE; + + if (ath_mci_buf_alloc(sc, &mci->sched_buf)) { + ath_dbg(common, ATH_DBG_FATAL, "MCI buffer alloc failed\n"); + error = -ENOMEM; + goto fail; + } + + mci->sched_buf.bf_len = ATH_MCI_SCHED_BUF_SIZE; + + memset(mci->sched_buf.bf_addr, MCI_GPM_RSVD_PATTERN, + mci->sched_buf.bf_len); + + mci->gpm_buf.bf_len = ATH_MCI_GPM_BUF_SIZE; + mci->gpm_buf.bf_addr = (u8 *)mci->sched_buf.bf_addr + + mci->sched_buf.bf_len; + mci->gpm_buf.bf_paddr = mci->sched_buf.bf_paddr + mci->sched_buf.bf_len; + + /* initialize the buffer */ + memset(mci->gpm_buf.bf_addr, MCI_GPM_RSVD_PATTERN, mci->gpm_buf.bf_len); + + ar9003_mci_setup(sc->sc_ah, mci->gpm_buf.bf_paddr, + mci->gpm_buf.bf_addr, (mci->gpm_buf.bf_len >> 4), + mci->sched_buf.bf_paddr); +fail: + return error; +} + +void ath_mci_cleanup(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_mci_coex *mci = &sc->mci_coex; + + /* + * both schedule and gpm buffers will be released + */ + ath_mci_buf_free(sc, &mci->sched_buf); + ar9003_mci_cleanup(ah); +} + +void ath_mci_intr(struct ath_softc *sc) +{ + struct ath_mci_coex *mci = &sc->mci_coex; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + u32 mci_int, mci_int_rxmsg; + u32 offset, subtype, opcode; + u32 *pgpm; + u32 more_data = MCI_GPM_MORE; + bool skip_gpm = false; + + ar9003_mci_get_interrupt(sc->sc_ah, &mci_int, &mci_int_rxmsg); + + if (ar9003_mci_state(ah, MCI_STATE_ENABLE, NULL) == 0) { + + ar9003_mci_state(sc->sc_ah, MCI_STATE_INIT_GPM_OFFSET, NULL); + ath_dbg(common, ATH_DBG_MCI, + "MCI interrupt but MCI disabled\n"); + + ath_dbg(common, ATH_DBG_MCI, + "MCI interrupt: intr = 0x%x, intr_rxmsg = 0x%x\n", + mci_int, mci_int_rxmsg); + return; + } + + if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE) { + u32 payload[4] = { 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffff00}; + + /* + * The following REMOTE_RESET and SYS_WAKING used to sent + * only when BT wake up. Now they are always sent, as a + * recovery method to reset BT MCI's RX alignment. + */ + ath_dbg(common, ATH_DBG_MCI, "MCI interrupt send REMOTE_RESET\n"); + + ar9003_mci_send_message(ah, MCI_REMOTE_RESET, 0, + payload, 16, true, false); + ath_dbg(common, ATH_DBG_MCI, "MCI interrupt send SYS_WAKING\n"); + ar9003_mci_send_message(ah, MCI_SYS_WAKING, 0, + NULL, 0, true, false); + + mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE; + ar9003_mci_state(ah, MCI_STATE_RESET_REQ_WAKE, NULL); + + /* + * always do this for recovery and 2G/5G toggling and LNA_TRANS + */ + ath_dbg(common, ATH_DBG_MCI, "MCI Set BT state to AWAKE.\n"); + ar9003_mci_state(ah, MCI_STATE_SET_BT_AWAKE, NULL); + } + + /* Processing SYS_WAKING/SYS_SLEEPING */ + if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING) { + mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING; + + if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_SLEEP) { + + if (ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL) + == MCI_BT_SLEEP) + ath_dbg(common, ATH_DBG_MCI, + "MCI BT stays in sleep mode\n"); + else { + ath_dbg(common, ATH_DBG_MCI, + "MCI Set BT state to AWAKE.\n"); + ar9003_mci_state(ah, + MCI_STATE_SET_BT_AWAKE, NULL); + } + } else + ath_dbg(common, ATH_DBG_MCI, + "MCI BT stays in AWAKE mode.\n"); + } + + if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING) { + + mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING; + + if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_AWAKE) { + + if (ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL) + == MCI_BT_AWAKE) + ath_dbg(common, ATH_DBG_MCI, + "MCI BT stays in AWAKE mode.\n"); + else { + ath_dbg(common, ATH_DBG_MCI, + "MCI SetBT state to SLEEP\n"); + ar9003_mci_state(ah, MCI_STATE_SET_BT_SLEEP, + NULL); + } + } else + ath_dbg(common, ATH_DBG_MCI, + "MCI BT stays in SLEEP mode\n"); + } + + if ((mci_int & AR_MCI_INTERRUPT_RX_INVALID_HDR) || + (mci_int & AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT)) { + + ath_dbg(common, ATH_DBG_MCI, "MCI RX broken, skip GPM msgs\n"); + ar9003_mci_state(ah, MCI_STATE_RECOVER_RX, NULL); + skip_gpm = true; + } + + if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO) { + + mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO; + offset = ar9003_mci_state(ah, MCI_STATE_LAST_SCHD_MSG_OFFSET, + NULL); + } + + if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_GPM) { + + mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_GPM; + + while (more_data == MCI_GPM_MORE) { + + pgpm = mci->gpm_buf.bf_addr; + offset = ar9003_mci_state(ah, + MCI_STATE_NEXT_GPM_OFFSET, &more_data); + + if (offset == MCI_GPM_INVALID) + break; + + pgpm += (offset >> 2); + + /* + * The first dword is timer. + * The real data starts from 2nd dword. + */ + + subtype = MCI_GPM_TYPE(pgpm); + opcode = MCI_GPM_OPCODE(pgpm); + + if (!skip_gpm) { + + if (MCI_GPM_IS_CAL_TYPE(subtype)) + ath_mci_cal_msg(sc, subtype, + (u8 *) pgpm); + else { + switch (subtype) { + case MCI_GPM_COEX_AGENT: + ath_mci_msg(sc, opcode, + (u8 *) pgpm); + break; + default: + break; + } + } + } + MCI_GPM_RECYCLE(pgpm); + } + } + + if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_HW_MSG_MASK) { + + if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL) + mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL; + + if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_LNA_INFO) { + mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_LNA_INFO; + ath_dbg(common, ATH_DBG_MCI, "MCI LNA_INFO\n"); + } + + if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_INFO) { + + int value_dbm = ar9003_mci_state(ah, + MCI_STATE_CONT_RSSI_POWER, NULL); + + mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_CONT_INFO; + + if (ar9003_mci_state(ah, MCI_STATE_CONT_TXRX, NULL)) + ath_dbg(common, ATH_DBG_MCI, + "MCI CONT_INFO: " + "(tx) pri = %d, pwr = %d dBm\n", + ar9003_mci_state(ah, + MCI_STATE_CONT_PRIORITY, NULL), + value_dbm); + else + ath_dbg(common, ATH_DBG_MCI, + "MCI CONT_INFO:" + "(rx) pri = %d,pwr = %d dBm\n", + ar9003_mci_state(ah, + MCI_STATE_CONT_PRIORITY, NULL), + value_dbm); + } + + if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_NACK) { + mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_CONT_NACK; + ath_dbg(common, ATH_DBG_MCI, "MCI CONT_NACK\n"); + } + + if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_RST) { + mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_CONT_RST; + ath_dbg(common, ATH_DBG_MCI, "MCI CONT_RST\n"); + } + } + + if ((mci_int & AR_MCI_INTERRUPT_RX_INVALID_HDR) || + (mci_int & AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT)) + mci_int &= ~(AR_MCI_INTERRUPT_RX_INVALID_HDR | + AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT); + + if (mci_int_rxmsg & 0xfffffffe) + ath_dbg(common, ATH_DBG_MCI, + "MCI not processed mci_int_rxmsg = 0x%x\n", + mci_int_rxmsg); +} diff --git a/drivers/net/wireless/ath/ath9k/mci.h b/drivers/net/wireless/ath/ath9k/mci.h index 9590c61822d1..29e3e51d078f 100644 --- a/drivers/net/wireless/ath/ath9k/mci.h +++ b/drivers/net/wireless/ath/ath9k/mci.h @@ -17,6 +17,9 @@ #ifndef MCI_H #define MCI_H +#define ATH_MCI_SCHED_BUF_SIZE (16 * 16) /* 16 entries, 4 dword each */ +#define ATH_MCI_GPM_MAX_ENTRY 16 +#define ATH_MCI_GPM_BUF_SIZE (ATH_MCI_GPM_MAX_ENTRY * 16) #define ATH_MCI_DEF_BT_PERIOD 40 #define ATH_MCI_BDR_DUTY_CYCLE 20 #define ATH_MCI_MAX_DUTY_CYCLE 90 @@ -110,9 +113,22 @@ struct ath_mci_profile { u8 num_bdr; }; + +struct ath_mci_buf { + void *bf_addr; /* virtual addr of desc */ + dma_addr_t bf_paddr; /* physical addr of buffer */ + u32 bf_len; /* len of data */ +}; + +struct ath_mci_coex { + atomic_t mci_cal_flag; + struct ath_mci_buf sched_buf; + struct ath_mci_buf gpm_buf; + u32 bt_cal_start; +}; + void ath_mci_flush_profile(struct ath_mci_profile *mci); -void ath_mci_process_profile(struct ath_softc *sc, - struct ath_mci_profile_info *info); -void ath_mci_process_status(struct ath_softc *sc, - struct ath_mci_profile_status *status); +int ath_mci_setup(struct ath_softc *sc); +void ath_mci_cleanup(struct ath_softc *sc); +void ath_mci_intr(struct ath_softc *sc); #endif diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 2dcdf63cb390..a439edc5dc06 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -307,12 +307,11 @@ static int ath_pci_suspend(struct device *device) struct ieee80211_hw *hw = pci_get_drvdata(pdev); struct ath_softc *sc = hw->priv; - ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); - /* The device has to be moved to FULLSLEEP forcibly. * Otherwise the chip never moved to full sleep, * when no interface is up. */ + ath9k_hw_disable(sc->sc_ah); ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP); return 0; @@ -321,8 +320,6 @@ static int ath_pci_suspend(struct device *device) static int ath_pci_resume(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); - struct ieee80211_hw *hw = pci_get_drvdata(pdev); - struct ath_softc *sc = hw->priv; u32 val; /* @@ -334,22 +331,6 @@ static int ath_pci_resume(struct device *device) if ((val & 0x0000ff00) != 0) pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); - ath9k_ps_wakeup(sc); - /* Enable LED */ - ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin, - AR_GPIO_OUTPUT_MUX_AS_OUTPUT); - ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0); - - /* - * Reset key cache to sane defaults (all entries cleared) instead of - * semi-random values after suspend/resume. - */ - ath9k_cmn_init_crypto(sc->sc_ah); - ath9k_ps_restore(sc); - - sc->ps_idle = true; - ath_radio_disable(sc, hw); - return 0; } diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 888abc2be3a5..528d5f3e868c 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -1271,7 +1271,9 @@ static void ath_rc_init(struct ath_softc *sc, ath_rc_priv->max_valid_rate = k; ath_rc_sort_validrates(rate_table, ath_rc_priv); - ath_rc_priv->rate_max_phy = ath_rc_priv->valid_rate_index[k-4]; + ath_rc_priv->rate_max_phy = (k > 4) ? + ath_rc_priv->valid_rate_index[k-4] : + ath_rc_priv->valid_rate_index[k-1]; ath_rc_priv->rate_table = rate_table; ath_dbg(common, ATH_DBG_CONFIG, diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 4c8e296f663b..ad5176de07dc 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -475,7 +475,6 @@ u32 ath_calcrxfilter(struct ath_softc *sc) return rfilt; -#undef RX_FILTER_PRESERVE } int ath_startrecv(struct ath_softc *sc) @@ -1824,6 +1823,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) hdr = (struct ieee80211_hdr *) (hdr_skb->data + rx_status_len); rxs = IEEE80211_SKB_RXCB(hdr_skb); if (ieee80211_is_beacon(hdr->frame_control) && + !is_zero_ether_addr(common->curbssid) && !compare_ether_addr(hdr->addr3, common->curbssid)) rs.is_mybeacon = true; else @@ -1923,15 +1923,20 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) skb = hdr_skb; } - /* - * change the default rx antenna if rx diversity chooses the - * other antenna 3 times in a row. - */ - if (sc->rx.defant != rs.rs_antenna) { - if (++sc->rx.rxotherant >= 3) - ath_setdefantenna(sc, rs.rs_antenna); - } else { - sc->rx.rxotherant = 0; + + if (ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) { + + /* + * change the default rx antenna if rx diversity + * chooses the other antenna 3 times in a row. + */ + if (sc->rx.defant != rs.rs_antenna) { + if (++sc->rx.rxotherant >= 3) + ath_setdefantenna(sc, rs.rs_antenna); + } else { + sc->rx.rxotherant = 0; + } + } if (rxs->flag & RX_FLAG_MMIC_STRIPPED) diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 45910975d853..6e2f18861f5d 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -1006,6 +1006,8 @@ enum { #define AR_INTR_ASYNC_MASK (AR_SREV_9340(ah) ? 0x4018 : 0x4030) #define AR_INTR_ASYNC_MASK_GPIO 0xFFFC0000 #define AR_INTR_ASYNC_MASK_GPIO_S 18 +#define AR_INTR_ASYNC_MASK_MCI 0x00000080 +#define AR_INTR_ASYNC_MASK_MCI_S 7 #define AR_INTR_SYNC_MASK (AR_SREV_9340(ah) ? 0x401c : 0x4034) #define AR_INTR_SYNC_MASK_GPIO 0xFFFC0000 @@ -1013,6 +1015,14 @@ enum { #define AR_INTR_ASYNC_CAUSE_CLR (AR_SREV_9340(ah) ? 0x4020 : 0x4038) #define AR_INTR_ASYNC_CAUSE (AR_SREV_9340(ah) ? 0x4020 : 0x4038) +#define AR_INTR_ASYNC_CAUSE_MCI 0x00000080 +#define AR_INTR_ASYNC_USED (AR_INTR_MAC_IRQ | \ + AR_INTR_ASYNC_CAUSE_MCI) + +/* Asynchronous Interrupt Enable Register */ +#define AR_INTR_ASYNC_ENABLE_MCI 0x00000080 +#define AR_INTR_ASYNC_ENABLE_MCI_S 7 + #define AR_INTR_ASYNC_ENABLE (AR_SREV_9340(ah) ? 0x4024 : 0x403c) #define AR_INTR_ASYNC_ENABLE_GPIO 0xFFFC0000 @@ -1269,6 +1279,8 @@ enum { #define AR_RTC_INTR_MASK \ ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0058) : 0x7058) +#define AR_RTC_KEEP_AWAKE 0x7034 + /* RTC_DERIVED_* - only for AR9100 */ #define AR_RTC_DERIVED_CLK \ @@ -1555,6 +1567,8 @@ enum { #define AR_DIAG_FRAME_NV0 0x00020000 #define AR_DIAG_OBS_PT_SEL1 0x000C0000 #define AR_DIAG_OBS_PT_SEL1_S 18 +#define AR_DIAG_OBS_PT_SEL2 0x08000000 +#define AR_DIAG_OBS_PT_SEL2_S 27 #define AR_DIAG_FORCE_RX_CLEAR 0x00100000 /* force rx_clear high */ #define AR_DIAG_IGNORE_VIRT_CS 0x00200000 #define AR_DIAG_FORCE_CH_IDLE_HIGH 0x00400000 @@ -1929,37 +1943,277 @@ enum { #define AR_PHY_AGC_CONTROL_YCOK_MAX_S 6 /* MCI Registers */ -#define AR_MCI_INTERRUPT_RX_MSG_EN 0x183c -#define AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET 0x00000001 -#define AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET_S 0 -#define AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL 0x00000002 -#define AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL_S 1 -#define AR_MCI_INTERRUPT_RX_MSG_CONT_NACK 0x00000004 -#define AR_MCI_INTERRUPT_RX_MSG_CONT_NACK_S 2 -#define AR_MCI_INTERRUPT_RX_MSG_CONT_INFO 0x00000008 -#define AR_MCI_INTERRUPT_RX_MSG_CONT_INFO_S 3 -#define AR_MCI_INTERRUPT_RX_MSG_CONT_RST 0x00000010 -#define AR_MCI_INTERRUPT_RX_MSG_CONT_RST_S 4 -#define AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO 0x00000020 -#define AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO_S 5 -#define AR_MCI_INTERRUPT_RX_MSG_CPU_INT 0x00000040 -#define AR_MCI_INTERRUPT_RX_MSG_CPU_INT_S 6 -#define AR_MCI_INTERRUPT_RX_MSG_GPM 0x00000100 -#define AR_MCI_INTERRUPT_RX_MSG_GPM_S 8 -#define AR_MCI_INTERRUPT_RX_MSG_LNA_INFO 0x00000200 -#define AR_MCI_INTERRUPT_RX_MSG_LNA_INFO_S 9 -#define AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING 0x00000400 -#define AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING_S 10 -#define AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING 0x00000800 -#define AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING_S 11 -#define AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE 0x00001000 -#define AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE_S 12 -#define AR_MCI_INTERRUPT_RX_HW_MSG_MASK (AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO | \ + +#define AR_MCI_COMMAND0 0x1800 +#define AR_MCI_COMMAND0_HEADER 0xFF +#define AR_MCI_COMMAND0_HEADER_S 0 +#define AR_MCI_COMMAND0_LEN 0x1f00 +#define AR_MCI_COMMAND0_LEN_S 8 +#define AR_MCI_COMMAND0_DISABLE_TIMESTAMP 0x2000 +#define AR_MCI_COMMAND0_DISABLE_TIMESTAMP_S 13 + +#define AR_MCI_COMMAND1 0x1804 + +#define AR_MCI_COMMAND2 0x1808 +#define AR_MCI_COMMAND2_RESET_TX 0x01 +#define AR_MCI_COMMAND2_RESET_TX_S 0 +#define AR_MCI_COMMAND2_RESET_RX 0x02 +#define AR_MCI_COMMAND2_RESET_RX_S 1 +#define AR_MCI_COMMAND2_RESET_RX_NUM_CYCLES 0x3FC +#define AR_MCI_COMMAND2_RESET_RX_NUM_CYCLES_S 2 +#define AR_MCI_COMMAND2_RESET_REQ_WAKEUP 0x400 +#define AR_MCI_COMMAND2_RESET_REQ_WAKEUP_S 10 + +#define AR_MCI_RX_CTRL 0x180c + +#define AR_MCI_TX_CTRL 0x1810 +/* 0 = no division, 1 = divide by 2, 2 = divide by 4, 3 = divide by 8 */ +#define AR_MCI_TX_CTRL_CLK_DIV 0x03 +#define AR_MCI_TX_CTRL_CLK_DIV_S 0 +#define AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE 0x04 +#define AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE_S 2 +#define AR_MCI_TX_CTRL_GAIN_UPDATE_FREQ 0xFFFFF8 +#define AR_MCI_TX_CTRL_GAIN_UPDATE_FREQ_S 3 +#define AR_MCI_TX_CTRL_GAIN_UPDATE_NUM 0xF000000 +#define AR_MCI_TX_CTRL_GAIN_UPDATE_NUM_S 24 + +#define AR_MCI_MSG_ATTRIBUTES_TABLE 0x1814 +#define AR_MCI_MSG_ATTRIBUTES_TABLE_CHECKSUM 0xFFFF +#define AR_MCI_MSG_ATTRIBUTES_TABLE_CHECKSUM_S 0 +#define AR_MCI_MSG_ATTRIBUTES_TABLE_INVALID_HDR 0xFFFF0000 +#define AR_MCI_MSG_ATTRIBUTES_TABLE_INVALID_HDR_S 16 + +#define AR_MCI_SCHD_TABLE_0 0x1818 +#define AR_MCI_SCHD_TABLE_1 0x181c +#define AR_MCI_GPM_0 0x1820 +#define AR_MCI_GPM_1 0x1824 +#define AR_MCI_GPM_WRITE_PTR 0xFFFF0000 +#define AR_MCI_GPM_WRITE_PTR_S 16 +#define AR_MCI_GPM_BUF_LEN 0x0000FFFF +#define AR_MCI_GPM_BUF_LEN_S 0 + +#define AR_MCI_INTERRUPT_RAW 0x1828 +#define AR_MCI_INTERRUPT_EN 0x182c +#define AR_MCI_INTERRUPT_SW_MSG_DONE 0x00000001 +#define AR_MCI_INTERRUPT_SW_MSG_DONE_S 0 +#define AR_MCI_INTERRUPT_CPU_INT_MSG 0x00000002 +#define AR_MCI_INTERRUPT_CPU_INT_MSG_S 1 +#define AR_MCI_INTERRUPT_RX_CKSUM_FAIL 0x00000004 +#define AR_MCI_INTERRUPT_RX_CKSUM_FAIL_S 2 +#define AR_MCI_INTERRUPT_RX_INVALID_HDR 0x00000008 +#define AR_MCI_INTERRUPT_RX_INVALID_HDR_S 3 +#define AR_MCI_INTERRUPT_RX_HW_MSG_FAIL 0x00000010 +#define AR_MCI_INTERRUPT_RX_HW_MSG_FAIL_S 4 +#define AR_MCI_INTERRUPT_RX_SW_MSG_FAIL 0x00000020 +#define AR_MCI_INTERRUPT_RX_SW_MSG_FAIL_S 5 +#define AR_MCI_INTERRUPT_TX_HW_MSG_FAIL 0x00000080 +#define AR_MCI_INTERRUPT_TX_HW_MSG_FAIL_S 7 +#define AR_MCI_INTERRUPT_TX_SW_MSG_FAIL 0x00000100 +#define AR_MCI_INTERRUPT_TX_SW_MSG_FAIL_S 8 +#define AR_MCI_INTERRUPT_RX_MSG 0x00000200 +#define AR_MCI_INTERRUPT_RX_MSG_S 9 +#define AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE 0x00000400 +#define AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE_S 10 +#define AR_MCI_INTERRUPT_BT_PRI 0x07fff800 +#define AR_MCI_INTERRUPT_BT_PRI_S 11 +#define AR_MCI_INTERRUPT_BT_PRI_THRESH 0x08000000 +#define AR_MCI_INTERRUPT_BT_PRI_THRESH_S 27 +#define AR_MCI_INTERRUPT_BT_FREQ 0x10000000 +#define AR_MCI_INTERRUPT_BT_FREQ_S 28 +#define AR_MCI_INTERRUPT_BT_STOMP 0x20000000 +#define AR_MCI_INTERRUPT_BT_STOMP_S 29 +#define AR_MCI_INTERRUPT_BB_AIC_IRQ 0x40000000 +#define AR_MCI_INTERRUPT_BB_AIC_IRQ_S 30 +#define AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT 0x80000000 +#define AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT_S 31 + +#define AR_MCI_INTERRUPT_DEFAULT (AR_MCI_INTERRUPT_SW_MSG_DONE | \ + AR_MCI_INTERRUPT_RX_INVALID_HDR | \ + AR_MCI_INTERRUPT_RX_HW_MSG_FAIL | \ + AR_MCI_INTERRUPT_RX_SW_MSG_FAIL | \ + AR_MCI_INTERRUPT_TX_HW_MSG_FAIL | \ + AR_MCI_INTERRUPT_TX_SW_MSG_FAIL | \ + AR_MCI_INTERRUPT_RX_MSG | \ + AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE | \ + AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT) + +#define AR_MCI_INTERRUPT_MSG_FAIL_MASK (AR_MCI_INTERRUPT_RX_HW_MSG_FAIL | \ + AR_MCI_INTERRUPT_RX_SW_MSG_FAIL | \ + AR_MCI_INTERRUPT_TX_HW_MSG_FAIL | \ + AR_MCI_INTERRUPT_TX_SW_MSG_FAIL) + +#define AR_MCI_REMOTE_CPU_INT 0x1830 +#define AR_MCI_REMOTE_CPU_INT_EN 0x1834 +#define AR_MCI_INTERRUPT_RX_MSG_RAW 0x1838 +#define AR_MCI_INTERRUPT_RX_MSG_EN 0x183c +#define AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET 0x00000001 +#define AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET_S 0 +#define AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL 0x00000002 +#define AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL_S 1 +#define AR_MCI_INTERRUPT_RX_MSG_CONT_NACK 0x00000004 +#define AR_MCI_INTERRUPT_RX_MSG_CONT_NACK_S 2 +#define AR_MCI_INTERRUPT_RX_MSG_CONT_INFO 0x00000008 +#define AR_MCI_INTERRUPT_RX_MSG_CONT_INFO_S 3 +#define AR_MCI_INTERRUPT_RX_MSG_CONT_RST 0x00000010 +#define AR_MCI_INTERRUPT_RX_MSG_CONT_RST_S 4 +#define AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO 0x00000020 +#define AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO_S 5 +#define AR_MCI_INTERRUPT_RX_MSG_CPU_INT 0x00000040 +#define AR_MCI_INTERRUPT_RX_MSG_CPU_INT_S 6 +#define AR_MCI_INTERRUPT_RX_MSG_GPM 0x00000100 +#define AR_MCI_INTERRUPT_RX_MSG_GPM_S 8 +#define AR_MCI_INTERRUPT_RX_MSG_LNA_INFO 0x00000200 +#define AR_MCI_INTERRUPT_RX_MSG_LNA_INFO_S 9 +#define AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING 0x00000400 +#define AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING_S 10 +#define AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING 0x00000800 +#define AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING_S 11 +#define AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE 0x00001000 +#define AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE_S 12 +#define AR_MCI_INTERRUPT_RX_HW_MSG_MASK (AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO | \ AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL| \ AR_MCI_INTERRUPT_RX_MSG_LNA_INFO | \ AR_MCI_INTERRUPT_RX_MSG_CONT_NACK | \ AR_MCI_INTERRUPT_RX_MSG_CONT_INFO | \ AR_MCI_INTERRUPT_RX_MSG_CONT_RST) +#define AR_MCI_INTERRUPT_RX_MSG_DEFAULT (AR_MCI_INTERRUPT_RX_MSG_GPM | \ + AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET| \ + AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING | \ + AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING| \ + AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO | \ + AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL | \ + AR_MCI_INTERRUPT_RX_MSG_LNA_INFO | \ + AR_MCI_INTERRUPT_RX_MSG_CONT_NACK | \ + AR_MCI_INTERRUPT_RX_MSG_CONT_INFO | \ + AR_MCI_INTERRUPT_RX_MSG_CONT_RST | \ + AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE) + +#define AR_MCI_CPU_INT 0x1840 + +#define AR_MCI_RX_STATUS 0x1844 +#define AR_MCI_RX_LAST_SCHD_MSG_INDEX 0x00000F00 +#define AR_MCI_RX_LAST_SCHD_MSG_INDEX_S 8 +#define AR_MCI_RX_REMOTE_SLEEP 0x00001000 +#define AR_MCI_RX_REMOTE_SLEEP_S 12 +#define AR_MCI_RX_MCI_CLK_REQ 0x00002000 +#define AR_MCI_RX_MCI_CLK_REQ_S 13 + +#define AR_MCI_CONT_STATUS 0x1848 +#define AR_MCI_CONT_RSSI_POWER 0x000000FF +#define AR_MCI_CONT_RSSI_POWER_S 0 +#define AR_MCI_CONT_RRIORITY 0x0000FF00 +#define AR_MCI_CONT_RRIORITY_S 8 +#define AR_MCI_CONT_TXRX 0x00010000 +#define AR_MCI_CONT_TXRX_S 16 + +#define AR_MCI_BT_PRI0 0x184c +#define AR_MCI_BT_PRI1 0x1850 +#define AR_MCI_BT_PRI2 0x1854 +#define AR_MCI_BT_PRI3 0x1858 +#define AR_MCI_BT_PRI 0x185c +#define AR_MCI_WL_FREQ0 0x1860 +#define AR_MCI_WL_FREQ1 0x1864 +#define AR_MCI_WL_FREQ2 0x1868 +#define AR_MCI_GAIN 0x186c +#define AR_MCI_WBTIMER1 0x1870 +#define AR_MCI_WBTIMER2 0x1874 +#define AR_MCI_WBTIMER3 0x1878 +#define AR_MCI_WBTIMER4 0x187c +#define AR_MCI_MAXGAIN 0x1880 +#define AR_MCI_HW_SCHD_TBL_CTL 0x1884 +#define AR_MCI_HW_SCHD_TBL_D0 0x1888 +#define AR_MCI_HW_SCHD_TBL_D1 0x188c +#define AR_MCI_HW_SCHD_TBL_D2 0x1890 +#define AR_MCI_HW_SCHD_TBL_D3 0x1894 +#define AR_MCI_TX_PAYLOAD0 0x1898 +#define AR_MCI_TX_PAYLOAD1 0x189c +#define AR_MCI_TX_PAYLOAD2 0x18a0 +#define AR_MCI_TX_PAYLOAD3 0x18a4 +#define AR_BTCOEX_WBTIMER 0x18a8 + +#define AR_BTCOEX_CTRL 0x18ac +#define AR_BTCOEX_CTRL_AR9462_MODE 0x00000001 +#define AR_BTCOEX_CTRL_AR9462_MODE_S 0 +#define AR_BTCOEX_CTRL_WBTIMER_EN 0x00000002 +#define AR_BTCOEX_CTRL_WBTIMER_EN_S 1 +#define AR_BTCOEX_CTRL_MCI_MODE_EN 0x00000004 +#define AR_BTCOEX_CTRL_MCI_MODE_EN_S 2 +#define AR_BTCOEX_CTRL_LNA_SHARED 0x00000008 +#define AR_BTCOEX_CTRL_LNA_SHARED_S 3 +#define AR_BTCOEX_CTRL_PA_SHARED 0x00000010 +#define AR_BTCOEX_CTRL_PA_SHARED_S 4 +#define AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN 0x00000020 +#define AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN_S 5 +#define AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN 0x00000040 +#define AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN_S 6 +#define AR_BTCOEX_CTRL_NUM_ANTENNAS 0x00000180 +#define AR_BTCOEX_CTRL_NUM_ANTENNAS_S 7 +#define AR_BTCOEX_CTRL_RX_CHAIN_MASK 0x00000E00 +#define AR_BTCOEX_CTRL_RX_CHAIN_MASK_S 9 +#define AR_BTCOEX_CTRL_AGGR_THRESH 0x00007000 +#define AR_BTCOEX_CTRL_AGGR_THRESH_S 12 +#define AR_BTCOEX_CTRL_1_CHAIN_BCN 0x00080000 +#define AR_BTCOEX_CTRL_1_CHAIN_BCN_S 19 +#define AR_BTCOEX_CTRL_1_CHAIN_ACK 0x00100000 +#define AR_BTCOEX_CTRL_1_CHAIN_ACK_S 20 +#define AR_BTCOEX_CTRL_WAIT_BA_MARGIN 0x1FE00000 +#define AR_BTCOEX_CTRL_WAIT_BA_MARGIN_S 28 +#define AR_BTCOEX_CTRL_REDUCE_TXPWR 0x20000000 +#define AR_BTCOEX_CTRL_REDUCE_TXPWR_S 29 +#define AR_BTCOEX_CTRL_SPDT_ENABLE_10 0x40000000 +#define AR_BTCOEX_CTRL_SPDT_ENABLE_10_S 30 +#define AR_BTCOEX_CTRL_SPDT_POLARITY 0x80000000 +#define AR_BTCOEX_CTRL_SPDT_POLARITY_S 31 + +#define AR_BTCOEX_WL_WEIGHTS0 0x18b0 +#define AR_BTCOEX_WL_WEIGHTS1 0x18b4 +#define AR_BTCOEX_WL_WEIGHTS2 0x18b8 +#define AR_BTCOEX_WL_WEIGHTS3 0x18bc +#define AR_BTCOEX_MAX_TXPWR(_x) (0x18c0 + ((_x) << 2)) +#define AR_BTCOEX_WL_LNA 0x1940 +#define AR_BTCOEX_RFGAIN_CTRL 0x1944 + +#define AR_BTCOEX_CTRL2 0x1948 +#define AR_BTCOEX_CTRL2_TXPWR_THRESH 0x0007F800 +#define AR_BTCOEX_CTRL2_TXPWR_THRESH_S 11 +#define AR_BTCOEX_CTRL2_TX_CHAIN_MASK 0x00380000 +#define AR_BTCOEX_CTRL2_TX_CHAIN_MASK_S 19 +#define AR_BTCOEX_CTRL2_RX_DEWEIGHT 0x00400000 +#define AR_BTCOEX_CTRL2_RX_DEWEIGHT_S 22 +#define AR_BTCOEX_CTRL2_GPIO_OBS_SEL 0x00800000 +#define AR_BTCOEX_CTRL2_GPIO_OBS_SEL_S 23 +#define AR_BTCOEX_CTRL2_MAC_BB_OBS_SEL 0x01000000 +#define AR_BTCOEX_CTRL2_MAC_BB_OBS_SEL_S 24 +#define AR_BTCOEX_CTRL2_DESC_BASED_TXPWR_ENABLE 0x02000000 +#define AR_BTCOEX_CTRL2_DESC_BASED_TXPWR_ENABLE_S 25 + +#define AR_BTCOEX_CTRL_SPDT_ENABLE 0x00000001 +#define AR_BTCOEX_CTRL_SPDT_ENABLE_S 0 +#define AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL 0x00000002 +#define AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL_S 1 +#define AR_BTCOEX_CTRL_USE_LATCHED_BT_ANT 0x00000004 +#define AR_BTCOEX_CTRL_USE_LATCHED_BT_ANT_S 2 +#define AR_GLB_WLAN_UART_INTF_EN 0x00020000 +#define AR_GLB_WLAN_UART_INTF_EN_S 17 +#define AR_GLB_DS_JTAG_DISABLE 0x00040000 +#define AR_GLB_DS_JTAG_DISABLE_S 18 + +#define AR_BTCOEX_RC 0x194c +#define AR_BTCOEX_MAX_RFGAIN(_x) (0x1950 + ((_x) << 2)) +#define AR_BTCOEX_DBG 0x1a50 +#define AR_MCI_LAST_HW_MSG_HDR 0x1a54 +#define AR_MCI_LAST_HW_MSG_BDY 0x1a58 + +#define AR_MCI_SCHD_TABLE_2 0x1a5c +#define AR_MCI_SCHD_TABLE_2_MEM_BASED 0x00000001 +#define AR_MCI_SCHD_TABLE_2_MEM_BASED_S 0 +#define AR_MCI_SCHD_TABLE_2_HW_BASED 0x00000002 +#define AR_MCI_SCHD_TABLE_2_HW_BASED_S 1 + +#define AR_BTCOEX_CTRL3 0x1a60 +#define AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT 0x00000fff +#define AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT_S 0 + #endif diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 55d077e7135d..2622fcee8c96 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -53,7 +53,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, int tx_flags, struct ath_txq *txq); static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, struct ath_txq *txq, struct list_head *bf_q, - struct ath_tx_status *ts, int txok, int sendbar); + struct ath_tx_status *ts, int txok); static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, struct list_head *head, bool internal); static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf, @@ -150,6 +150,12 @@ static struct ath_frame_info *get_frame_info(struct sk_buff *skb) return (struct ath_frame_info *) &tx_info->rate_driver_data[0]; } +static void ath_send_bar(struct ath_atx_tid *tid, u16 seqno) +{ + ieee80211_send_bar(tid->an->vif, tid->an->sta->addr, tid->tidno, + seqno << IEEE80211_SEQ_SEQ_SHIFT); +} + static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) { struct ath_txq *txq = tid->ac->txq; @@ -158,28 +164,33 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) struct list_head bf_head; struct ath_tx_status ts; struct ath_frame_info *fi; + bool sendbar = false; INIT_LIST_HEAD(&bf_head); memset(&ts, 0, sizeof(ts)); - spin_lock_bh(&txq->axq_lock); while ((skb = __skb_dequeue(&tid->buf_q))) { fi = get_frame_info(skb); bf = fi->bf; - spin_unlock_bh(&txq->axq_lock); if (bf && fi->retries) { list_add_tail(&bf->list, &bf_head); ath_tx_update_baw(sc, tid, bf->bf_state.seqno); - ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 1); + ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0); + sendbar = true; } else { ath_tx_send_normal(sc, txq, NULL, skb); } - spin_lock_bh(&txq->axq_lock); } - spin_unlock_bh(&txq->axq_lock); + if (tid->baw_head == tid->baw_tail) { + tid->state &= ~AGGR_ADDBA_COMPLETE; + tid->state &= ~AGGR_CLEANUP; + } + + if (sendbar) + ath_send_bar(tid, tid->seq_start); } static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, @@ -195,6 +206,8 @@ static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, while (tid->baw_head != tid->baw_tail && !test_bit(tid->baw_head, tid->tx_buf)) { INCR(tid->seq_start, IEEE80211_SEQ_MAX); INCR(tid->baw_head, ATH_TID_MAX_BUFS); + if (tid->bar_index >= 0) + tid->bar_index--; } } @@ -238,9 +251,7 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, bf = fi->bf; if (!bf) { - spin_unlock(&txq->axq_lock); ath_tx_complete(sc, skb, ATH_TX_ERROR, txq); - spin_lock(&txq->axq_lock); continue; } @@ -249,24 +260,26 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, if (fi->retries) ath_tx_update_baw(sc, tid, bf->bf_state.seqno); - spin_unlock(&txq->axq_lock); - ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0); - spin_lock(&txq->axq_lock); + ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0); } tid->seq_next = tid->seq_start; tid->baw_tail = tid->baw_head; + tid->bar_index = -1; } static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq, - struct sk_buff *skb) + struct sk_buff *skb, int count) { struct ath_frame_info *fi = get_frame_info(skb); struct ath_buf *bf = fi->bf; struct ieee80211_hdr *hdr; + int prev = fi->retries; TX_STAT_INC(txq->axq_qnum, a_retries); - if (fi->retries++ > 0) + fi->retries += count; + + if (prev > 0) return; hdr = (struct ieee80211_hdr *)skb->data; @@ -365,7 +378,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *bf_next, *bf_last = bf->bf_lastbf; struct list_head bf_head; struct sk_buff_head bf_pending; - u16 seq_st = 0, acked_cnt = 0, txfail_cnt = 0; + u16 seq_st = 0, acked_cnt = 0, txfail_cnt = 0, seq_first; u32 ba[WME_BA_BMP_SIZE >> 5]; int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0; bool rc_update = true; @@ -374,6 +387,8 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, int nframes; u8 tidno; bool flush = !!(ts->ts_status & ATH9K_TX_FLUSH); + int i, retries; + int bar_index = -1; skb = bf->bf_mpdu; hdr = (struct ieee80211_hdr *)skb->data; @@ -382,6 +397,10 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, memcpy(rates, tx_info->control.rates, sizeof(rates)); + retries = ts->ts_longretry + 1; + for (i = 0; i < ts->ts_rateindex; i++) + retries += rates[i].count; + rcu_read_lock(); sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr1, hdr->addr2); @@ -395,8 +414,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, if (!bf->bf_stale || bf_next != NULL) list_move_tail(&bf->list, &bf_head); - ath_tx_complete_buf(sc, bf, txq, &bf_head, ts, - 0, 0); + ath_tx_complete_buf(sc, bf, txq, &bf_head, ts, 0); bf = bf_next; } @@ -406,6 +424,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, an = (struct ath_node *)sta->drv_priv; tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK; tid = ATH_AN_2_TID(an, tidno); + seq_first = tid->seq_start; /* * The hardware occasionally sends a tx status for the wrong TID. @@ -455,25 +474,25 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, } else if (!isaggr && txok) { /* transmit completion */ acked_cnt++; + } else if ((tid->state & AGGR_CLEANUP) || !retry) { + /* + * cleanup in progress, just fail + * the un-acked sub-frames + */ + txfail = 1; + } else if (flush) { + txpending = 1; + } else if (fi->retries < ATH_MAX_SW_RETRIES) { + if (txok || !an->sleeping) + ath_tx_set_retry(sc, txq, bf->bf_mpdu, + retries); + + txpending = 1; } else { - if ((tid->state & AGGR_CLEANUP) || !retry) { - /* - * cleanup in progress, just fail - * the un-acked sub-frames - */ - txfail = 1; - } else if (flush) { - txpending = 1; - } else if (fi->retries < ATH_MAX_SW_RETRIES) { - if (txok || !an->sleeping) - ath_tx_set_retry(sc, txq, bf->bf_mpdu); - - txpending = 1; - } else { - txfail = 1; - sendbar = 1; - txfail_cnt++; - } + txfail = 1; + txfail_cnt++; + bar_index = max_t(int, bar_index, + ATH_BA_INDEX(seq_first, seqno)); } /* @@ -490,9 +509,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, * complete the acked-ones/xretried ones; update * block-ack window */ - spin_lock_bh(&txq->axq_lock); ath_tx_update_baw(sc, tid, seqno); - spin_unlock_bh(&txq->axq_lock); if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) { memcpy(tx_info->control.rates, rates, sizeof(rates)); @@ -501,33 +518,30 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, } ath_tx_complete_buf(sc, bf, txq, &bf_head, ts, - !txfail, sendbar); + !txfail); } else { /* retry the un-acked ones */ - if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) { - if (bf->bf_next == NULL && bf_last->bf_stale) { - struct ath_buf *tbf; - - tbf = ath_clone_txbuf(sc, bf_last); - /* - * Update tx baw and complete the - * frame with failed status if we - * run out of tx buf. - */ - if (!tbf) { - spin_lock_bh(&txq->axq_lock); - ath_tx_update_baw(sc, tid, seqno); - spin_unlock_bh(&txq->axq_lock); - - ath_tx_complete_buf(sc, bf, txq, - &bf_head, - ts, 0, - !flush); - break; - } - - fi->bf = tbf; + if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) && + bf->bf_next == NULL && bf_last->bf_stale) { + struct ath_buf *tbf; + + tbf = ath_clone_txbuf(sc, bf_last); + /* + * Update tx baw and complete the + * frame with failed status if we + * run out of tx buf. + */ + if (!tbf) { + ath_tx_update_baw(sc, tid, seqno); + + ath_tx_complete_buf(sc, bf, txq, + &bf_head, ts, 0); + bar_index = max_t(int, bar_index, + ATH_BA_INDEX(seq_first, seqno)); + break; } + + fi->bf = tbf; } /* @@ -540,12 +554,18 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, bf = bf_next; } + if (bar_index >= 0) { + u16 bar_seq = ATH_BA_INDEX2SEQ(seq_first, bar_index); + ath_send_bar(tid, ATH_BA_INDEX2SEQ(seq_first, bar_index + 1)); + if (BAW_WITHIN(tid->seq_start, tid->baw_size, bar_seq)) + tid->bar_index = ATH_BA_INDEX(tid->seq_start, bar_seq); + } + /* prepend un-acked frames to the beginning of the pending frame queue */ if (!skb_queue_empty(&bf_pending)) { if (an->sleeping) ieee80211_sta_set_buffered(sta, tid->tidno, true); - spin_lock_bh(&txq->axq_lock); skb_queue_splice(&bf_pending, &tid->buf_q); if (!an->sleeping) { ath_tx_queue_tid(txq, tid); @@ -553,18 +573,11 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, if (ts->ts_status & ATH9K_TXERR_FILT) tid->ac->clear_ps_filter = true; } - spin_unlock_bh(&txq->axq_lock); } - if (tid->state & AGGR_CLEANUP) { + if (tid->state & AGGR_CLEANUP) ath_tx_flush_tid(sc, tid); - if (tid->baw_head == tid->baw_tail) { - tid->state &= ~AGGR_ADDBA_COMPLETE; - tid->state &= ~AGGR_CLEANUP; - } - } - rcu_read_unlock(); if (needreset) { @@ -618,24 +631,26 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, max_4ms_framelen = ATH_AMPDU_LIMIT_MAX; for (i = 0; i < 4; i++) { - if (rates[i].count) { - int modeidx; - if (!(rates[i].flags & IEEE80211_TX_RC_MCS)) { - legacy = 1; - break; - } + int modeidx; - if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) - modeidx = MCS_HT40; - else - modeidx = MCS_HT20; - - if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI) - modeidx++; + if (!rates[i].count) + continue; - frmlen = ath_max_4ms_framelen[modeidx][rates[i].idx]; - max_4ms_framelen = min(max_4ms_framelen, frmlen); + if (!(rates[i].flags & IEEE80211_TX_RC_MCS)) { + legacy = 1; + break; } + + if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + modeidx = MCS_HT40; + else + modeidx = MCS_HT20; + + if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI) + modeidx++; + + frmlen = ath_max_4ms_framelen[modeidx][rates[i].idx]; + max_4ms_framelen = min(max_4ms_framelen, frmlen); } /* @@ -771,8 +786,6 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, bf->bf_state.bf_type = BUF_AMPDU | BUF_AGGR; seqno = bf->bf_state.seqno; - if (!bf_first) - bf_first = bf; /* do not step over block-ack window */ if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) { @@ -780,6 +793,21 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, break; } + if (tid->bar_index > ATH_BA_INDEX(tid->seq_start, seqno)) { + struct ath_tx_status ts = {}; + struct list_head bf_head; + + INIT_LIST_HEAD(&bf_head); + list_add(&bf->list, &bf_head); + __skb_unlink(skb, &tid->buf_q); + ath_tx_update_baw(sc, tid, seqno); + ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0); + continue; + } + + if (!bf_first) + bf_first = bf; + if (!rl) { aggr_limit = ath_lookup_rate(sc, bf, tid); rl = 1; @@ -1122,6 +1150,7 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, txtid->state |= AGGR_ADDBA_PROGRESS; txtid->paused = true; *ssn = txtid->seq_start = txtid->seq_next; + txtid->bar_index = -1; memset(txtid->tx_buf, 0, sizeof(txtid->tx_buf)); txtid->baw_head = txtid->baw_tail = 0; @@ -1156,9 +1185,9 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) txtid->state |= AGGR_CLEANUP; else txtid->state &= ~AGGR_ADDBA_COMPLETE; - spin_unlock_bh(&txq->axq_lock); ath_tx_flush_tid(sc, txtid); + spin_unlock_bh(&txq->axq_lock); } void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, @@ -1400,8 +1429,6 @@ static bool bf_is_ampdu_not_probing(struct ath_buf *bf) static void ath_drain_txq_list(struct ath_softc *sc, struct ath_txq *txq, struct list_head *list, bool retry_tx) - __releases(txq->axq_lock) - __acquires(txq->axq_lock) { struct ath_buf *bf, *lastbf; struct list_head bf_head; @@ -1428,13 +1455,11 @@ static void ath_drain_txq_list(struct ath_softc *sc, struct ath_txq *txq, if (bf_is_ampdu_not_probing(bf)) txq->axq_ampdu_depth--; - spin_unlock_bh(&txq->axq_lock); if (bf_isampdu(bf)) ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0, retry_tx); else - ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0); - spin_lock_bh(&txq->axq_lock); + ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0); } } @@ -1561,11 +1586,9 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) break; } - if (!list_empty(&ac->tid_q)) { - if (!ac->sched) { - ac->sched = true; - list_add_tail(&ac->list, &txq->axq_acq); - } + if (!list_empty(&ac->tid_q) && !ac->sched) { + ac->sched = true; + list_add_tail(&ac->list, &txq->axq_acq); } if (ac == last_ac || @@ -1708,10 +1731,6 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, list_add_tail(&bf->list, &bf_head); bf->bf_state.bf_type = 0; - /* update starting sequence number for subsequent ADDBA request */ - if (tid) - INCR(tid->seq_start, IEEE80211_SEQ_MAX); - bf->bf_lastbf = bf; ath_tx_fill_desc(sc, bf, txq, fi->framelen); ath_tx_txqaddbuf(sc, txq, &bf_head, false); @@ -1819,7 +1838,6 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct sk_buff *skb, struct ath_buf *bf; u8 tidno; - spin_lock_bh(&txctl->txq->axq_lock); if ((sc->sc_flags & SC_OP_TXAGGR) && txctl->an && ieee80211_is_data_qos(hdr->frame_control)) { tidno = ieee80211_get_qos_ctl(hdr)[0] & @@ -1838,7 +1856,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct sk_buff *skb, } else { bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb); if (!bf) - goto out; + return; bf->bf_state.bfs_paprd = txctl->paprd; @@ -1847,9 +1865,6 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct sk_buff *skb, ath_tx_send_normal(sc, txctl->txq, tid, skb); } - -out: - spin_unlock_bh(&txctl->txq->axq_lock); } /* Upon failure caller should free skb */ @@ -1914,11 +1929,13 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, if (txq == sc->tx.txq_map[q] && ++txq->pending_frames > ATH_MAX_QDEPTH && !txq->stopped) { ieee80211_stop_queue(sc->hw, q); - txq->stopped = 1; + txq->stopped = true; } - spin_unlock_bh(&txq->axq_lock); ath_tx_start_dma(sc, skb, txctl); + + spin_unlock_bh(&txq->axq_lock); + return 0; } @@ -1937,9 +1954,6 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, ath_dbg(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb); - if (tx_flags & ATH_TX_BAR) - tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; - if (!(tx_flags & ATH_TX_ERROR)) /* Frame was ACKed */ tx_info->flags |= IEEE80211_TX_STAT_ACK; @@ -1955,7 +1969,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, skb_pull(skb, padsize); } - if (sc->ps_flags & PS_WAIT_FOR_TX_ACK) { + if ((sc->ps_flags & PS_WAIT_FOR_TX_ACK) && !txq->axq_depth) { sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK; ath_dbg(common, ATH_DBG_PS, "Going back to sleep after having received TX status (0x%lx)\n", @@ -1967,15 +1981,13 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, q = skb_get_queue_mapping(skb); if (txq == sc->tx.txq_map[q]) { - spin_lock_bh(&txq->axq_lock); if (WARN_ON(--txq->pending_frames < 0)) txq->pending_frames = 0; if (txq->stopped && txq->pending_frames < ATH_MAX_QDEPTH) { ieee80211_wake_queue(sc->hw, q); - txq->stopped = 0; + txq->stopped = false; } - spin_unlock_bh(&txq->axq_lock); } ieee80211_tx_status(hw, skb); @@ -1983,16 +1995,13 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, struct ath_txq *txq, struct list_head *bf_q, - struct ath_tx_status *ts, int txok, int sendbar) + struct ath_tx_status *ts, int txok) { struct sk_buff *skb = bf->bf_mpdu; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); unsigned long flags; int tx_flags = 0; - if (sendbar) - tx_flags = ATH_TX_BAR; - if (!txok) tx_flags |= ATH_TX_ERROR; @@ -2084,8 +2093,6 @@ static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf, static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq, struct ath_tx_status *ts, struct ath_buf *bf, struct list_head *bf_head) - __releases(txq->axq_lock) - __acquires(txq->axq_lock) { int txok; @@ -2095,16 +2102,12 @@ static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq, if (bf_is_ampdu_not_probing(bf)) txq->axq_ampdu_depth--; - spin_unlock_bh(&txq->axq_lock); - if (!bf_isampdu(bf)) { ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok); - ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok, 0); + ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok); } else ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok, true); - spin_lock_bh(&txq->axq_lock); - if (sc->sc_flags & SC_OP_TXAGGR) ath_txq_schedule(sc, txq); } diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 551859214ee9..db774212161b 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -48,7 +48,7 @@ #include "carl9170.h" #include "cmd.h" -static int modparam_nohwcrypt; +static bool modparam_nohwcrypt; module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); MODULE_PARM_DESC(nohwcrypt, "Disable hardware crypto offload."); diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index 65ecb5bab25a..10dea37431b3 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -21,6 +21,8 @@ #include "regd.h" #include "regd_common.h" +static int __ath_regd_init(struct ath_regulatory *reg); + /* * This is a set of common rules used by our world regulatory domains. * We have 12 world regulatory domains. To save space we consolidate @@ -347,10 +349,26 @@ static void ath_reg_apply_world_flags(struct wiphy *wiphy, } } +static u16 ath_regd_find_country_by_name(char *alpha2) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(allCountries); i++) { + if (!memcmp(allCountries[i].isoName, alpha2, 2)) + return allCountries[i].countryCode; + } + + return -1; +} + int ath_reg_notifier_apply(struct wiphy *wiphy, struct regulatory_request *request, struct ath_regulatory *reg) { + struct ath_common *common = container_of(reg, struct ath_common, + regulatory); + u16 country_code; + /* We always apply this */ ath_reg_apply_radar_flags(wiphy); @@ -363,14 +381,37 @@ int ath_reg_notifier_apply(struct wiphy *wiphy, return 0; switch (request->initiator) { - case NL80211_REGDOM_SET_BY_DRIVER: case NL80211_REGDOM_SET_BY_CORE: + /* + * If common->reg_world_copy is world roaming it means we *were* + * world roaming... so we now have to restore that data. + */ + if (!ath_is_world_regd(&common->reg_world_copy)) + break; + + memcpy(reg, &common->reg_world_copy, + sizeof(struct ath_regulatory)); + break; + case NL80211_REGDOM_SET_BY_DRIVER: case NL80211_REGDOM_SET_BY_USER: break; case NL80211_REGDOM_SET_BY_COUNTRY_IE: - if (ath_is_world_regd(reg)) - ath_reg_apply_world_flags(wiphy, request->initiator, - reg); + if (!ath_is_world_regd(reg)) + break; + + country_code = ath_regd_find_country_by_name(request->alpha2); + if (country_code == (u16) -1) + break; + + reg->current_rd = COUNTRY_ERD_FLAG; + reg->current_rd |= country_code; + + printk(KERN_DEBUG "ath: regdomain 0x%0x updated by CountryIE\n", + reg->current_rd); + __ath_regd_init(reg); + + ath_reg_apply_world_flags(wiphy, request->initiator, reg); + break; } @@ -508,11 +549,7 @@ static void ath_regd_sanitize(struct ath_regulatory *reg) reg->current_rd = 0x64; } -int -ath_regd_init(struct ath_regulatory *reg, - struct wiphy *wiphy, - int (*reg_notifier)(struct wiphy *wiphy, - struct regulatory_request *request)) +static int __ath_regd_init(struct ath_regulatory *reg) { struct country_code_to_enum_rd *country = NULL; u16 regdmn; @@ -583,7 +620,29 @@ ath_regd_init(struct ath_regulatory *reg, printk(KERN_DEBUG "ath: Regpair used: 0x%0x\n", reg->regpair->regDmnEnum); + return 0; +} + +int +ath_regd_init(struct ath_regulatory *reg, + struct wiphy *wiphy, + int (*reg_notifier)(struct wiphy *wiphy, + struct regulatory_request *request)) +{ + struct ath_common *common = container_of(reg, struct ath_common, + regulatory); + int r; + + r = __ath_regd_init(reg); + if (r) + return r; + + if (ath_is_world_regd(reg)) + memcpy(&common->reg_world_copy, reg, + sizeof(struct ath_regulatory)); + ath_regd_init_wiphy(reg, wiphy, reg_notifier); + return 0; } EXPORT_SYMBOL(ath_regd_init); diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 5e45604f0f5d..af23968520b6 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -890,7 +890,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, else ring->ops = &dma32_ops; if (for_tx) { - ring->tx = 1; + ring->tx = true; ring->current_slot = -1; } else { if (ring->index == 0) { @@ -1061,7 +1061,7 @@ void b43_dma_free(struct b43_wldev *dev) static int b43_dma_set_mask(struct b43_wldev *dev, u64 mask) { u64 orig_mask = mask; - bool fallback = 0; + bool fallback = false; int err; /* Try to set the DMA mask. If it fails, try falling back to a @@ -1075,12 +1075,12 @@ static int b43_dma_set_mask(struct b43_wldev *dev, u64 mask) } if (mask == DMA_BIT_MASK(64)) { mask = DMA_BIT_MASK(32); - fallback = 1; + fallback = true; continue; } if (mask == DMA_BIT_MASK(32)) { mask = DMA_BIT_MASK(30); - fallback = 1; + fallback = true; continue; } b43err(dev->wl, "The machine/kernel does not support " @@ -1307,7 +1307,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring, memset(meta, 0, sizeof(*meta)); meta->skb = skb; - meta->is_last_fragment = 1; + meta->is_last_fragment = true; priv_info->bouncebuffer = NULL; meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); @@ -1466,7 +1466,7 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) should_inject_overflow(ring)) { /* This TX ring is full. */ ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); - ring->stopped = 1; + ring->stopped = true; if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index); } @@ -1585,7 +1585,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, if (ring->stopped) { B43_WARN_ON(free_slots(ring) < TX_SLOTS_PER_FRAME); ieee80211_wake_queue(dev->wl->hw, ring->queue_prio); - ring->stopped = 0; + ring->stopped = false; if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { b43dbg(dev->wl, "Woke up TX ring %d\n", ring->index); } diff --git a/drivers/net/wireless/b43/leds.c b/drivers/net/wireless/b43/leds.c index a38c1c6446ad..d79ab2a227e1 100644 --- a/drivers/net/wireless/b43/leds.c +++ b/drivers/net/wireless/b43/leds.c @@ -74,7 +74,7 @@ static void b43_led_update(struct b43_wldev *dev, if (radio_enabled) turn_on = atomic_read(&led->state) != LED_OFF; else - turn_on = 0; + turn_on = false; if (turn_on == led->hw_state) return; led->hw_state = turn_on; @@ -225,11 +225,11 @@ static void b43_led_get_sprominfo(struct b43_wldev *dev, if (sprom[led_index] == 0xFF) { /* There is no LED information in the SPROM * for this LED. Hardcode it here. */ - *activelow = 0; + *activelow = false; switch (led_index) { case 0: *behaviour = B43_LED_ACTIVITY; - *activelow = 1; + *activelow = true; if (dev->dev->board_vendor == PCI_VENDOR_ID_COMPAQ) *behaviour = B43_LED_RADIO_ALL; break; @@ -267,11 +267,11 @@ void b43_leds_init(struct b43_wldev *dev) if (led->wl) { if (dev->phy.radio_on && b43_is_hw_radio_enabled(dev)) { b43_led_turn_on(dev, led->index, led->activelow); - led->hw_state = 1; + led->hw_state = true; atomic_set(&led->state, 1); } else { b43_led_turn_off(dev, led->index, led->activelow); - led->hw_state = 0; + led->hw_state = false; atomic_set(&led->state, 0); } } @@ -280,19 +280,19 @@ void b43_leds_init(struct b43_wldev *dev) led = &dev->wl->leds.led_tx; if (led->wl) { b43_led_turn_off(dev, led->index, led->activelow); - led->hw_state = 0; + led->hw_state = false; atomic_set(&led->state, 0); } led = &dev->wl->leds.led_rx; if (led->wl) { b43_led_turn_off(dev, led->index, led->activelow); - led->hw_state = 0; + led->hw_state = false; atomic_set(&led->state, 0); } led = &dev->wl->leds.led_assoc; if (led->wl) { b43_led_turn_off(dev, led->index, led->activelow); - led->hw_state = 0; + led->hw_state = false; atomic_set(&led->state, 0); } diff --git a/drivers/net/wireless/b43/lo.c b/drivers/net/wireless/b43/lo.c index 4c82d582a524..916123a3d74e 100644 --- a/drivers/net/wireless/b43/lo.c +++ b/drivers/net/wireless/b43/lo.c @@ -826,7 +826,7 @@ void b43_gphy_dc_lt_init(struct b43_wldev *dev, bool update_all) const struct b43_rfatt *rfatt; const struct b43_bbatt *bbatt; u64 power_vector; - bool table_changed = 0; + bool table_changed = false; BUILD_BUG_ON(B43_DC_LT_SIZE != 32); B43_WARN_ON(lo->rfatt_list.len * lo->bbatt_list.len > 64); @@ -876,7 +876,7 @@ void b43_gphy_dc_lt_init(struct b43_wldev *dev, bool update_all) lo->dc_lt[idx] = (lo->dc_lt[idx] & 0xFF00) | (val & 0x00FF); } - table_changed = 1; + table_changed = true; } if (table_changed) { /* The table changed in memory. Update the hardware table. */ @@ -938,7 +938,7 @@ void b43_lo_g_maintanance_work(struct b43_wldev *dev) unsigned long now; unsigned long expire; struct b43_lo_calib *cal, *tmp; - bool current_item_expired = 0; + bool current_item_expired = false; bool hwpctl; if (!lo) @@ -968,7 +968,7 @@ void b43_lo_g_maintanance_work(struct b43_wldev *dev) if (b43_compare_bbatt(&cal->bbatt, &gphy->bbatt) && b43_compare_rfatt(&cal->rfatt, &gphy->rfatt)) { B43_WARN_ON(current_item_expired); - current_item_expired = 1; + current_item_expired = true; } if (b43_debug(dev, B43_DBG_LO)) { b43dbg(dev->wl, "LO: Item BB(%u), RF(%u,%u), " diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 5634d9a9965b..c74f36f6e348 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1122,17 +1122,17 @@ void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags) B43_WARN_ON((ps_flags & B43_PS_AWAKE) && (ps_flags & B43_PS_ASLEEP)); if (ps_flags & B43_PS_ENABLED) { - hwps = 1; + hwps = true; } else if (ps_flags & B43_PS_DISABLED) { - hwps = 0; + hwps = false; } else { //TODO: If powersave is not off and FIXME is not set and we are not in adhoc // and thus is not an AP and we are associated, set bit 25 } if (ps_flags & B43_PS_AWAKE) { - awake = 1; + awake = true; } else if (ps_flags & B43_PS_ASLEEP) { - awake = 0; + awake = false; } else { //TODO: If the device is awake or this is an AP, or we are scanning, or FIXME, // or we are associated, or FIXME, or the latest PS-Poll packet sent was @@ -1140,8 +1140,8 @@ void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags) } /* FIXME: For now we force awake-on and hwps-off */ - hwps = 0; - awake = 1; + hwps = false; + awake = true; macctl = b43_read32(dev, B43_MMIO_MACCTL); if (hwps) @@ -1339,7 +1339,7 @@ static void b43_calculate_link_quality(struct b43_wldev *dev) return; if (dev->noisecalc.calculation_running) return; - dev->noisecalc.calculation_running = 1; + dev->noisecalc.calculation_running = true; dev->noisecalc.nr_samples = 0; b43_generate_noise_sample(dev); @@ -1408,7 +1408,7 @@ static void handle_irq_noise(struct b43_wldev *dev) average -= 48; dev->stats.link_noise = average; - dev->noisecalc.calculation_running = 0; + dev->noisecalc.calculation_running = false; return; } generate_new: @@ -1424,7 +1424,7 @@ static void handle_irq_tbtt_indication(struct b43_wldev *dev) b43_power_saving_ctl_bits(dev, 0); } if (b43_is_mode(dev->wl, NL80211_IFTYPE_ADHOC)) - dev->dfq_valid = 1; + dev->dfq_valid = true; } static void handle_irq_atim_end(struct b43_wldev *dev) @@ -1433,7 +1433,7 @@ static void handle_irq_atim_end(struct b43_wldev *dev) b43_write32(dev, B43_MMIO_MACCMD, b43_read32(dev, B43_MMIO_MACCMD) | B43_MACCMD_DFQ_VALID); - dev->dfq_valid = 0; + dev->dfq_valid = false; } } @@ -1539,7 +1539,7 @@ static void b43_write_beacon_template(struct b43_wldev *dev, unsigned int i, len, variable_len; const struct ieee80211_mgmt *bcn; const u8 *ie; - bool tim_found = 0; + bool tim_found = false; unsigned int rate; u16 ctl; int antenna; @@ -1588,7 +1588,7 @@ static void b43_write_beacon_template(struct b43_wldev *dev, /* A valid TIM is at least 4 bytes long. */ if (ie_len < 4) break; - tim_found = 1; + tim_found = true; tim_position = sizeof(struct b43_plcp_hdr6); tim_position += offsetof(struct ieee80211_mgmt, u.beacon.variable); @@ -1625,7 +1625,7 @@ static void b43_upload_beacon0(struct b43_wldev *dev) if (wl->beacon0_uploaded) return; b43_write_beacon_template(dev, 0x68, 0x18); - wl->beacon0_uploaded = 1; + wl->beacon0_uploaded = true; } static void b43_upload_beacon1(struct b43_wldev *dev) @@ -1635,7 +1635,7 @@ static void b43_upload_beacon1(struct b43_wldev *dev) if (wl->beacon1_uploaded) return; b43_write_beacon_template(dev, 0x468, 0x1A); - wl->beacon1_uploaded = 1; + wl->beacon1_uploaded = true; } static void handle_irq_beacon(struct b43_wldev *dev) @@ -1667,7 +1667,7 @@ static void handle_irq_beacon(struct b43_wldev *dev) if (unlikely(wl->beacon_templates_virgin)) { /* We never uploaded a beacon before. * Upload both templates now, but only mark one valid. */ - wl->beacon_templates_virgin = 0; + wl->beacon_templates_virgin = false; b43_upload_beacon0(dev); b43_upload_beacon1(dev); cmd = b43_read32(dev, B43_MMIO_MACCMD); @@ -1755,8 +1755,8 @@ static void b43_update_templates(struct b43_wl *wl) if (wl->current_beacon) dev_kfree_skb_any(wl->current_beacon); wl->current_beacon = beacon; - wl->beacon0_uploaded = 0; - wl->beacon1_uploaded = 0; + wl->beacon0_uploaded = false; + wl->beacon1_uploaded = false; ieee80211_queue_work(wl->hw, &wl->beacon_update_trigger); } @@ -1913,7 +1913,7 @@ static void b43_do_interrupt_thread(struct b43_wldev *dev) b43err(dev->wl, "This device does not support DMA " "on your system. It will now be switched to PIO.\n"); /* Fall back to PIO transfers if we get fatal DMA errors! */ - dev->use_pio = 1; + dev->use_pio = true; b43_controller_restart(dev, "DMA error"); return; } @@ -2240,12 +2240,12 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx) filename = NULL; else goto err_no_pcm; - fw->pcm_request_failed = 0; + fw->pcm_request_failed = false; err = b43_do_request_fw(ctx, filename, &fw->pcm); if (err == -ENOENT) { /* We did not find a PCM file? Not fatal, but * core rev <= 10 must do without hwcrypto then. */ - fw->pcm_request_failed = 1; + fw->pcm_request_failed = true; } else if (err) goto err_load; @@ -2535,7 +2535,7 @@ static int b43_upload_microcode(struct b43_wldev *dev) dev->wl->hw->queues = dev->wl->mac80211_initially_registered_queues; dev->qos_enabled = !!modparam_qos; /* Default to firmware/hardware crypto acceleration. */ - dev->hwcrypto_enabled = 1; + dev->hwcrypto_enabled = true; if (dev->fw.opensource) { u16 fwcapa; @@ -2549,7 +2549,7 @@ static int b43_upload_microcode(struct b43_wldev *dev) if (!(fwcapa & B43_FWCAPA_HWCRYPTO) || dev->fw.pcm_request_failed) { b43info(dev->wl, "Hardware crypto acceleration not supported by firmware\n"); /* Disable hardware crypto and fall back to software crypto. */ - dev->hwcrypto_enabled = 0; + dev->hwcrypto_enabled = false; } if (!(fwcapa & B43_FWCAPA_QOS)) { b43info(dev->wl, "QoS not supported by firmware\n"); @@ -2557,7 +2557,7 @@ static int b43_upload_microcode(struct b43_wldev *dev) * ieee80211_unregister to make sure the networking core can * properly free possible resources. */ dev->wl->hw->queues = 1; - dev->qos_enabled = 0; + dev->qos_enabled = false; } } else { b43info(dev->wl, "Loading firmware version %u.%u " @@ -3361,10 +3361,10 @@ static int b43_rng_init(struct b43_wl *wl) wl->rng.name = wl->rng_name; wl->rng.data_read = b43_rng_read; wl->rng.priv = (unsigned long)wl; - wl->rng_initialized = 1; + wl->rng_initialized = true; err = hwrng_register(&wl->rng); if (err) { - wl->rng_initialized = 0; + wl->rng_initialized = false; b43err(wl, "Failed to register the random " "number generator (%d)\n", err); } @@ -3702,13 +3702,13 @@ static int b43_switch_band(struct b43_wl *wl, struct ieee80211_channel *chan) case IEEE80211_BAND_5GHZ: if (d->phy.supports_5ghz) { up_dev = d; - gmode = 0; + gmode = false; } break; case IEEE80211_BAND_2GHZ: if (d->phy.supports_2ghz) { up_dev = d; - gmode = 1; + gmode = true; } break; default: @@ -4425,18 +4425,18 @@ static void setup_struct_phy_for_init(struct b43_wldev *dev, atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT); #if B43_DEBUG - phy->phy_locked = 0; - phy->radio_locked = 0; + phy->phy_locked = false; + phy->radio_locked = false; #endif } static void setup_struct_wldev_for_init(struct b43_wldev *dev) { - dev->dfq_valid = 0; + dev->dfq_valid = false; /* Assume the radio is enabled. If it's not enabled, the state will * immediately get fixed on the first periodic work run. */ - dev->radio_hw_enable = 1; + dev->radio_hw_enable = true; /* Stats */ memset(&dev->stats, 0, sizeof(dev->stats)); @@ -4670,16 +4670,16 @@ static int b43_wireless_core_init(struct b43_wldev *dev) if (b43_bus_host_is_pcmcia(dev->dev) || b43_bus_host_is_sdio(dev->dev)) { - dev->__using_pio_transfers = 1; + dev->__using_pio_transfers = true; err = b43_pio_init(dev); } else if (dev->use_pio) { b43warn(dev->wl, "Forced PIO by use_pio module parameter. " "This should not be needed and will result in lower " "performance.\n"); - dev->__using_pio_transfers = 1; + dev->__using_pio_transfers = true; err = b43_pio_init(dev); } else { - dev->__using_pio_transfers = 0; + dev->__using_pio_transfers = false; err = b43_dma_init(dev); } if (err) @@ -4733,7 +4733,7 @@ static int b43_op_add_interface(struct ieee80211_hw *hw, b43dbg(wl, "Adding Interface type %d\n", vif->type); dev = wl->current_dev; - wl->operating = 1; + wl->operating = true; wl->vif = vif; wl->if_type = vif->type; memcpy(wl->mac_addr, vif->addr, ETH_ALEN); @@ -4767,7 +4767,7 @@ static void b43_op_remove_interface(struct ieee80211_hw *hw, B43_WARN_ON(wl->vif != vif); wl->vif = NULL; - wl->operating = 0; + wl->operating = false; b43_adjust_opmode(dev); memset(wl->mac_addr, 0, ETH_ALEN); @@ -4789,12 +4789,12 @@ static int b43_op_start(struct ieee80211_hw *hw) memset(wl->bssid, 0, ETH_ALEN); memset(wl->mac_addr, 0, ETH_ALEN); wl->filter_flags = 0; - wl->radiotap_enabled = 0; + wl->radiotap_enabled = false; b43_qos_clear(wl); - wl->beacon0_uploaded = 0; - wl->beacon1_uploaded = 0; - wl->beacon_templates_virgin = 1; - wl->radio_enabled = 1; + wl->beacon0_uploaded = false; + wl->beacon1_uploaded = false; + wl->beacon_templates_virgin = true; + wl->radio_enabled = true; mutex_lock(&wl->mutex); @@ -4840,7 +4840,7 @@ static void b43_op_stop(struct ieee80211_hw *hw) goto out_unlock; } b43_wireless_core_exit(dev); - wl->radio_enabled = 0; + wl->radio_enabled = false; out_unlock: mutex_unlock(&wl->mutex); @@ -5028,7 +5028,7 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) struct pci_dev *pdev = NULL; int err; u32 tmp; - bool have_2ghz_phy = 0, have_5ghz_phy = 0; + bool have_2ghz_phy = false, have_5ghz_phy = false; /* Do NOT do any device initialization here. * Do it in wireless_core_init() instead. @@ -5071,7 +5071,7 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) } dev->phy.gmode = have_2ghz_phy; - dev->phy.radio_on = 1; + dev->phy.radio_on = true; b43_wireless_core_reset(dev, dev->phy.gmode); err = b43_phy_versioning(dev); @@ -5082,11 +5082,11 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) (pdev->device != 0x4312 && pdev->device != 0x4319 && pdev->device != 0x4324)) { /* No multiband support. */ - have_2ghz_phy = 0; - have_5ghz_phy = 0; + have_2ghz_phy = false; + have_5ghz_phy = false; switch (dev->phy.type) { case B43_PHYTYPE_A: - have_5ghz_phy = 1; + have_5ghz_phy = true; break; case B43_PHYTYPE_LP: //FIXME not always! #if 0 //FIXME enabling 5GHz causes a NULL pointer dereference @@ -5096,7 +5096,7 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) case B43_PHYTYPE_N: case B43_PHYTYPE_HT: case B43_PHYTYPE_LCN: - have_2ghz_phy = 1; + have_2ghz_phy = true; break; default: B43_WARN_ON(1); @@ -5112,8 +5112,8 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) /* FIXME: For now we disable the A-PHY on multi-PHY devices. */ if (dev->phy.type != B43_PHYTYPE_N && dev->phy.type != B43_PHYTYPE_LP) { - have_2ghz_phy = 1; - have_5ghz_phy = 0; + have_2ghz_phy = true; + have_5ghz_phy = false; } } diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index 3ea44bb03684..3f8883b14d9c 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -145,7 +145,7 @@ void b43_radio_lock(struct b43_wldev *dev) #if B43_DEBUG B43_WARN_ON(dev->phy.radio_locked); - dev->phy.radio_locked = 1; + dev->phy.radio_locked = true; #endif macctl = b43_read32(dev, B43_MMIO_MACCTL); @@ -163,7 +163,7 @@ void b43_radio_unlock(struct b43_wldev *dev) #if B43_DEBUG B43_WARN_ON(!dev->phy.radio_locked); - dev->phy.radio_locked = 0; + dev->phy.radio_locked = false; #endif /* Commit any write */ @@ -178,7 +178,7 @@ void b43_phy_lock(struct b43_wldev *dev) { #if B43_DEBUG B43_WARN_ON(dev->phy.phy_locked); - dev->phy.phy_locked = 1; + dev->phy.phy_locked = true; #endif B43_WARN_ON(dev->dev->core_rev < 3); @@ -190,7 +190,7 @@ void b43_phy_unlock(struct b43_wldev *dev) { #if B43_DEBUG B43_WARN_ON(!dev->phy.phy_locked); - dev->phy.phy_locked = 0; + dev->phy.phy_locked = false; #endif B43_WARN_ON(dev->dev->core_rev < 3); diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index 8e157bc213f3..12f467b8d564 100644 --- a/drivers/net/wireless/b43/phy_g.c +++ b/drivers/net/wireless/b43/phy_g.c @@ -897,7 +897,7 @@ b43_radio_interference_mitigation_enable(struct b43_wldev *dev, int mode) if (b43_phy_read(dev, 0x0033) & 0x0800) break; - gphy->aci_enable = 1; + gphy->aci_enable = true; phy_stacksave(B43_PHY_RADIO_BITFIELD); phy_stacksave(B43_PHY_G_CRS); @@ -1038,7 +1038,7 @@ b43_radio_interference_mitigation_disable(struct b43_wldev *dev, int mode) if (!(b43_phy_read(dev, 0x0033) & 0x0800)) break; - gphy->aci_enable = 0; + gphy->aci_enable = false; phy_stackrestore(B43_PHY_RADIO_BITFIELD); phy_stackrestore(B43_PHY_G_CRS); @@ -1956,10 +1956,10 @@ static void b43_phy_init_pctl(struct b43_wldev *dev) bbatt.att = 11; if (phy->radio_rev == 8) { rfatt.att = 15; - rfatt.with_padmix = 1; + rfatt.with_padmix = true; } else { rfatt.att = 9; - rfatt.with_padmix = 0; + rfatt.with_padmix = false; } b43_set_txpower_g(dev, &bbatt, &rfatt, 0); } @@ -2137,7 +2137,7 @@ static void default_radio_attenuation(struct b43_wldev *dev, struct b43_bus_dev *bdev = dev->dev; struct b43_phy *phy = &dev->phy; - rf->with_padmix = 0; + rf->with_padmix = false; if (dev->dev->board_vendor == SSB_BOARDVENDOR_BCM && dev->dev->board_type == SSB_BOARD_BCM4309G) { @@ -2221,7 +2221,7 @@ static void default_radio_attenuation(struct b43_wldev *dev, return; case 8: rf->att = 0xA; - rf->with_padmix = 1; + rf->with_padmix = true; return; case 9: default: @@ -2389,7 +2389,7 @@ static int b43_gphy_init_tssi2dbm_table(struct b43_wldev *dev) B43_WARN_ON((dev->dev->chip_id == 0x4301) && (phy->radio_ver != 0x2050)); /* Not supported anymore */ - gphy->dyn_tssi_tbl = 0; + gphy->dyn_tssi_tbl = false; if (pab0 != 0 && pab1 != 0 && pab2 != 0 && pab0 != -1 && pab1 != -1 && pab2 != -1) { @@ -2404,7 +2404,7 @@ static int b43_gphy_init_tssi2dbm_table(struct b43_wldev *dev) pab1, pab2); if (!gphy->tssi2dbm) return -ENOMEM; - gphy->dyn_tssi_tbl = 1; + gphy->dyn_tssi_tbl = true; } else { /* pabX values not set in SPROM. */ gphy->tgt_idle_tssi = 52; @@ -2504,7 +2504,7 @@ static void b43_gphy_op_free(struct b43_wldev *dev) if (gphy->dyn_tssi_tbl) kfree(gphy->tssi2dbm); - gphy->dyn_tssi_tbl = 0; + gphy->dyn_tssi_tbl = false; gphy->tssi2dbm = NULL; kfree(gphy); @@ -2531,10 +2531,10 @@ static int b43_gphy_op_prepare_hardware(struct b43_wldev *dev) if (phy->rev == 1) { /* Workaround: Temporarly disable gmode through the early init * phase, as the gmode stuff is not needed for phy rev 1 */ - phy->gmode = 0; + phy->gmode = false; b43_wireless_core_reset(dev, 0); b43_phy_initg(dev); - phy->gmode = 1; + phy->gmode = true; b43_wireless_core_reset(dev, 1); } @@ -2613,7 +2613,7 @@ static void b43_gphy_op_software_rfkill(struct b43_wldev *dev, gphy->radio_off_context.rfover); b43_phy_write(dev, B43_PHY_RFOVERVAL, gphy->radio_off_context.rfoverval); - gphy->radio_off_context.valid = 0; + gphy->radio_off_context.valid = false; } channel = phy->channel; b43_gphy_channel_switch(dev, 6, 1); @@ -2626,7 +2626,7 @@ static void b43_gphy_op_software_rfkill(struct b43_wldev *dev, rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL); gphy->radio_off_context.rfover = rfover; gphy->radio_off_context.rfoverval = rfoverval; - gphy->radio_off_context.valid = 1; + gphy->radio_off_context.valid = true; b43_phy_write(dev, B43_PHY_RFOVER, rfover | 0x008C); b43_phy_write(dev, B43_PHY_RFOVERVAL, rfoverval & 0xFF73); } @@ -2711,10 +2711,10 @@ static int b43_gphy_op_interf_mitigation(struct b43_wldev *dev, if ((phy->rev == 0) || (!phy->gmode)) return -ENODEV; - gphy->aci_wlan_automatic = 0; + gphy->aci_wlan_automatic = false; switch (mode) { case B43_INTERFMODE_AUTOWLAN: - gphy->aci_wlan_automatic = 1; + gphy->aci_wlan_automatic = true; if (gphy->aci_enable) mode = B43_INTERFMODE_MANUALWLAN; else @@ -2735,8 +2735,8 @@ static int b43_gphy_op_interf_mitigation(struct b43_wldev *dev, b43_radio_interference_mitigation_disable(dev, currentmode); if (mode == B43_INTERFMODE_NONE) { - gphy->aci_enable = 0; - gphy->aci_hw_rssi = 0; + gphy->aci_enable = false; + gphy->aci_hw_rssi = false; } else b43_radio_interference_mitigation_enable(dev, mode); gphy->interfmode = mode; diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index f93d66b1817b..3ae28561f7a4 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -736,9 +736,9 @@ static void lpphy_set_deaf(struct b43_wldev *dev, bool user) struct b43_phy_lp *lpphy = dev->phy.lp; if (user) - lpphy->crs_usr_disable = 1; + lpphy->crs_usr_disable = true; else - lpphy->crs_sys_disable = 1; + lpphy->crs_sys_disable = true; b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFF1F, 0x80); } @@ -747,9 +747,9 @@ static void lpphy_clear_deaf(struct b43_wldev *dev, bool user) struct b43_phy_lp *lpphy = dev->phy.lp; if (user) - lpphy->crs_usr_disable = 0; + lpphy->crs_usr_disable = false; else - lpphy->crs_sys_disable = 0; + lpphy->crs_sys_disable = false; if (!lpphy->crs_usr_disable && !lpphy->crs_sys_disable) { if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index b17d9b6c33a5..f1a7e5890adc 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -228,10 +228,98 @@ static void b43_chantab_radio_2056_upload(struct b43_wldev *dev, static void b43_radio_2056_setup(struct b43_wldev *dev, const struct b43_nphy_channeltab_entry_rev3 *e) { + struct ssb_sprom *sprom = dev->dev->bus_sprom; + enum ieee80211_band band = b43_current_band(dev->wl); + u16 offset; + u8 i; + u16 bias, cbias, pag_boost, pgag_boost, mixg_boost, padg_boost; + B43_WARN_ON(dev->phy.rev < 3); b43_chantab_radio_2056_upload(dev, e); - /* TODO */ + b2056_upload_syn_pll_cp2(dev, band == IEEE80211_BAND_5GHZ); + + if (sprom->boardflags2_lo & B43_BFL2_GPLL_WAR && + b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { + b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER1, 0x1F); + b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER2, 0x1F); + if (dev->dev->chip_id == 0x4716) { + b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER4, 0x14); + b43_radio_write(dev, B2056_SYN_PLL_CP2, 0); + } else { + b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER4, 0x0B); + b43_radio_write(dev, B2056_SYN_PLL_CP2, 0x14); + } + } + if (sprom->boardflags2_lo & B43_BFL2_APLL_WAR && + b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) { + b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER1, 0x1F); + b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER2, 0x1F); + b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER4, 0x05); + b43_radio_write(dev, B2056_SYN_PLL_CP2, 0x0C); + } + + if (dev->phy.n->ipa2g_on && band == IEEE80211_BAND_2GHZ) { + for (i = 0; i < 2; i++) { + offset = i ? B2056_TX1 : B2056_TX0; + if (dev->phy.rev >= 5) { + b43_radio_write(dev, + offset | B2056_TX_PADG_IDAC, 0xcc); + + if (dev->dev->chip_id == 0x4716) { + bias = 0x40; + cbias = 0x45; + pag_boost = 0x5; + pgag_boost = 0x33; + mixg_boost = 0x55; + } else { + bias = 0x25; + cbias = 0x20; + pag_boost = 0x4; + pgag_boost = 0x03; + mixg_boost = 0x65; + } + padg_boost = 0x77; + + b43_radio_write(dev, + offset | B2056_TX_INTPAG_IMAIN_STAT, + bias); + b43_radio_write(dev, + offset | B2056_TX_INTPAG_IAUX_STAT, + bias); + b43_radio_write(dev, + offset | B2056_TX_INTPAG_CASCBIAS, + cbias); + b43_radio_write(dev, + offset | B2056_TX_INTPAG_BOOST_TUNE, + pag_boost); + b43_radio_write(dev, + offset | B2056_TX_PGAG_BOOST_TUNE, + pgag_boost); + b43_radio_write(dev, + offset | B2056_TX_PADG_BOOST_TUNE, + padg_boost); + b43_radio_write(dev, + offset | B2056_TX_MIXG_BOOST_TUNE, + mixg_boost); + } else { + bias = dev->phy.is_40mhz ? 0x40 : 0x20; + b43_radio_write(dev, + offset | B2056_TX_INTPAG_IMAIN_STAT, + bias); + b43_radio_write(dev, + offset | B2056_TX_INTPAG_IAUX_STAT, + bias); + b43_radio_write(dev, + offset | B2056_TX_INTPAG_CASCBIAS, + 0x30); + } + b43_radio_write(dev, offset | B2056_TX_PA_SPARE1, 0xee); + } + } else if (dev->phy.n->ipa5g_on && band == IEEE80211_BAND_5GHZ) { + /* TODO */ + } + udelay(50); /* VCO calibration */ b43_radio_write(dev, B2056_SYN_PLL_VCOCAL12, 0x00); @@ -387,7 +475,9 @@ static void b43_nphy_tx_power_fix(struct b43_wldev *dev) if (nphy->hang_avoid) b43_nphy_stay_in_carrier_search(dev, 1); - if (dev->phy.rev >= 3) { + if (dev->phy.rev >= 7) { + txpi[0] = txpi[1] = 30; + } else if (dev->phy.rev >= 3) { txpi[0] = 40; txpi[1] = 40; } else if (sprom->revision < 4) { @@ -411,6 +501,9 @@ static void b43_nphy_tx_power_fix(struct b43_wldev *dev) txpi[1] = 91; } } + if (dev->phy.rev < 7 && + (txpi[0] < 40 || txpi[0] > 100 || txpi[1] < 40 || txpi[1] > 10)) + txpi[0] = txpi[1] = 91; /* for (i = 0; i < 2; i++) { @@ -421,15 +514,31 @@ static void b43_nphy_tx_power_fix(struct b43_wldev *dev) for (i = 0; i < 2; i++) { if (dev->phy.rev >= 3) { - /* FIXME: support 5GHz */ - txgain = b43_ntab_tx_gain_rev3plus_2ghz[txpi[i]]; + if (b43_nphy_ipa(dev)) { + txgain = *(b43_nphy_get_ipa_gain_table(dev) + + txpi[i]); + } else if (b43_current_band(dev->wl) == + IEEE80211_BAND_5GHZ) { + /* FIXME: use 5GHz tables */ + txgain = + b43_ntab_tx_gain_rev3plus_2ghz[txpi[i]]; + } else { + if (dev->phy.rev >= 5 && + sprom->fem.ghz5.extpa_gain == 3) + ; /* FIXME: 5GHz_txgain_HiPwrEPA */ + txgain = + b43_ntab_tx_gain_rev3plus_2ghz[txpi[i]]; + } radio_gain = (txgain >> 16) & 0x1FFFF; } else { txgain = b43_ntab_tx_gain_rev0_1_2[txpi[i]]; radio_gain = (txgain >> 16) & 0x1FFF; } - dac_gain = (txgain >> 8) & 0x3F; + if (dev->phy.rev >= 7) + dac_gain = (txgain >> 8) & 0x7; + else + dac_gain = (txgain >> 8) & 0x3F; bbmult = txgain & 0xFF; if (dev->phy.rev >= 3) { @@ -459,7 +568,8 @@ static void b43_nphy_tx_power_fix(struct b43_wldev *dev) u32 tmp32; u16 reg = (i == 0) ? B43_NPHY_PAPD_EN0 : B43_NPHY_PAPD_EN1; - tmp32 = b43_ntab_read(dev, B43_NTAB32(26 + i, txpi[i])); + tmp32 = b43_ntab_read(dev, B43_NTAB32(26 + i, + 576 + txpi[i])); b43_phy_maskset(dev, reg, 0xE00F, (u32) tmp32 << 4); b43_phy_set(dev, reg, 0x4); } @@ -1493,8 +1603,8 @@ static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev) struct ssb_sprom *sprom = dev->dev->bus_sprom; /* TX to RX */ - u8 tx2rx_events[9] = { 0x4, 0x3, 0x6, 0x5, 0x2, 0x1, 0x8, 0x1F }; - u8 tx2rx_delays[9] = { 8, 4, 2, 2, 4, 4, 6, 1 }; + u8 tx2rx_events[8] = { 0x4, 0x3, 0x6, 0x5, 0x2, 0x1, 0x8, 0x1F }; + u8 tx2rx_delays[8] = { 8, 4, 2, 2, 4, 4, 6, 1 }; /* RX to TX */ u8 rx2tx_events_ipa[9] = { 0x0, 0x1, 0x2, 0x8, 0x5, 0x6, 0xF, 0x3, 0x1F }; @@ -1505,6 +1615,9 @@ static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev) u16 tmp16; u32 tmp32; + b43_phy_write(dev, 0x23f, 0x1f8); + b43_phy_write(dev, 0x240, 0x1f8); + tmp32 = b43_ntab_read(dev, B43_NTAB32(30, 0)); tmp32 &= 0xffffff; b43_ntab_write(dev, B43_NTAB32(30, 0), tmp32); @@ -1520,12 +1633,13 @@ static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev) b43_phy_write(dev, 0x2AE, 0x000C); /* TX to RX */ - b43_nphy_set_rf_sequence(dev, 1, tx2rx_events, tx2rx_delays, 9); + b43_nphy_set_rf_sequence(dev, 1, tx2rx_events, tx2rx_delays, + ARRAY_SIZE(tx2rx_events)); /* RX to TX */ if (b43_nphy_ipa(dev)) - b43_nphy_set_rf_sequence(dev, 1, rx2tx_events_ipa, - rx2tx_delays_ipa, 9); + b43_nphy_set_rf_sequence(dev, 0, rx2tx_events_ipa, + rx2tx_delays_ipa, ARRAY_SIZE(rx2tx_events_ipa)); if (nphy->hw_phyrxchain != 3 && nphy->hw_phyrxchain != nphy->hw_phytxchain) { if (b43_nphy_ipa(dev)) { @@ -1533,7 +1647,8 @@ static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev) rx2tx_delays[6] = 1; rx2tx_events[7] = 0x1F; } - b43_nphy_set_rf_sequence(dev, 1, rx2tx_events, rx2tx_delays, 9); + b43_nphy_set_rf_sequence(dev, 1, rx2tx_events, rx2tx_delays, + ARRAY_SIZE(rx2tx_events)); } tmp16 = (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) ? @@ -1547,8 +1662,8 @@ static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev) b43_nphy_gain_ctrl_workarounds(dev); - b43_ntab_write(dev, B43_NTAB32(8, 0), 2); - b43_ntab_write(dev, B43_NTAB32(8, 16), 2); + b43_ntab_write(dev, B43_NTAB16(8, 0), 2); + b43_ntab_write(dev, B43_NTAB16(8, 16), 2); /* TODO */ @@ -1560,6 +1675,8 @@ static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev) b43_radio_write(dev, B2056_RX1 | B2056_RX_MIXA_BIAS_AUX, 0x07); b43_radio_write(dev, B2056_RX0 | B2056_RX_MIXA_LOB_BIAS, 0x88); b43_radio_write(dev, B2056_RX1 | B2056_RX_MIXA_LOB_BIAS, 0x88); + b43_radio_write(dev, B2056_RX0 | B2056_RX_MIXA_CMFB_IDAC, 0x00); + b43_radio_write(dev, B2056_RX1 | B2056_RX_MIXA_CMFB_IDAC, 0x00); b43_radio_write(dev, B2056_RX0 | B2056_RX_MIXG_CMFB_IDAC, 0x00); b43_radio_write(dev, B2056_RX1 | B2056_RX_MIXG_CMFB_IDAC, 0x00); @@ -1584,18 +1701,18 @@ static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev) 0x70); } - b43_phy_write(dev, 0x224, 0x039C); - b43_phy_write(dev, 0x225, 0x0357); - b43_phy_write(dev, 0x226, 0x0317); - b43_phy_write(dev, 0x227, 0x02D7); - b43_phy_write(dev, 0x228, 0x039C); - b43_phy_write(dev, 0x229, 0x0357); - b43_phy_write(dev, 0x22A, 0x0317); - b43_phy_write(dev, 0x22B, 0x02D7); - b43_phy_write(dev, 0x22C, 0x039C); - b43_phy_write(dev, 0x22D, 0x0357); - b43_phy_write(dev, 0x22E, 0x0317); - b43_phy_write(dev, 0x22F, 0x02D7); + b43_phy_write(dev, 0x224, 0x03eb); + b43_phy_write(dev, 0x225, 0x03eb); + b43_phy_write(dev, 0x226, 0x0341); + b43_phy_write(dev, 0x227, 0x0341); + b43_phy_write(dev, 0x228, 0x042b); + b43_phy_write(dev, 0x229, 0x042b); + b43_phy_write(dev, 0x22a, 0x0381); + b43_phy_write(dev, 0x22b, 0x0381); + b43_phy_write(dev, 0x22c, 0x042b); + b43_phy_write(dev, 0x22d, 0x042b); + b43_phy_write(dev, 0x22e, 0x0381); + b43_phy_write(dev, 0x22f, 0x0381); } static void b43_nphy_workarounds_rev1_2(struct b43_wldev *dev) @@ -3258,7 +3375,7 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, if (dev->phy.rev >= 4) { avoid = nphy->hang_avoid; - nphy->hang_avoid = 0; + nphy->hang_avoid = false; } b43_ntab_read_bulk(dev, B43_NTAB16(7, 0x110), 2, save); @@ -3368,7 +3485,7 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, if (phy6or5x && updated[core] == 0) { b43_nphy_update_tx_cal_ladder(dev, core); - updated[core] = 1; + updated[core] = true; } tmp = (params[core].ncorr[type] << 8) | 0x66; @@ -3928,6 +4045,76 @@ int b43_phy_initn(struct b43_wldev *dev) return 0; } +/* http://bcm-v4.sipsolutions.net/802.11/PmuSpurAvoid */ +static void b43_nphy_pmu_spur_avoid(struct b43_wldev *dev, bool avoid) +{ + struct bcma_drv_cc *cc; + u32 pmu_ctl; + + switch (dev->dev->bus_type) { +#ifdef CONFIG_B43_BCMA + case B43_BUS_BCMA: + cc = &dev->dev->bdev->bus->drv_cc; + if (dev->dev->chip_id == 43224 || dev->dev->chip_id == 43225) { + if (avoid) { + bcma_chipco_pll_write(cc, 0x0, 0x11500010); + bcma_chipco_pll_write(cc, 0x1, 0x000C0C06); + bcma_chipco_pll_write(cc, 0x2, 0x0F600a08); + bcma_chipco_pll_write(cc, 0x3, 0x00000000); + bcma_chipco_pll_write(cc, 0x4, 0x2001E920); + bcma_chipco_pll_write(cc, 0x5, 0x88888815); + } else { + bcma_chipco_pll_write(cc, 0x0, 0x11100010); + bcma_chipco_pll_write(cc, 0x1, 0x000c0c06); + bcma_chipco_pll_write(cc, 0x2, 0x03000a08); + bcma_chipco_pll_write(cc, 0x3, 0x00000000); + bcma_chipco_pll_write(cc, 0x4, 0x200005c0); + bcma_chipco_pll_write(cc, 0x5, 0x88888815); + } + pmu_ctl = BCMA_CC_PMU_CTL_PLL_UPD; + } else if (dev->dev->chip_id == 0x4716) { + if (avoid) { + bcma_chipco_pll_write(cc, 0x0, 0x11500060); + bcma_chipco_pll_write(cc, 0x1, 0x080C0C06); + bcma_chipco_pll_write(cc, 0x2, 0x0F600000); + bcma_chipco_pll_write(cc, 0x3, 0x00000000); + bcma_chipco_pll_write(cc, 0x4, 0x2001E924); + bcma_chipco_pll_write(cc, 0x5, 0x88888815); + } else { + bcma_chipco_pll_write(cc, 0x0, 0x11100060); + bcma_chipco_pll_write(cc, 0x1, 0x080c0c06); + bcma_chipco_pll_write(cc, 0x2, 0x03000000); + bcma_chipco_pll_write(cc, 0x3, 0x00000000); + bcma_chipco_pll_write(cc, 0x4, 0x200005c0); + bcma_chipco_pll_write(cc, 0x5, 0x88888815); + } + pmu_ctl = BCMA_CC_PMU_CTL_PLL_UPD | + BCMA_CC_PMU_CTL_NOILPONW; + } else if (dev->dev->chip_id == 0x4322 || + dev->dev->chip_id == 0x4340 || + dev->dev->chip_id == 0x4341) { + bcma_chipco_pll_write(cc, 0x0, 0x11100070); + bcma_chipco_pll_write(cc, 0x1, 0x1014140a); + bcma_chipco_pll_write(cc, 0x5, 0x88888854); + if (avoid) + bcma_chipco_pll_write(cc, 0x2, 0x05201828); + else + bcma_chipco_pll_write(cc, 0x2, 0x05001828); + pmu_ctl = BCMA_CC_PMU_CTL_PLL_UPD; + } else { + return; + } + bcma_cc_set32(cc, BCMA_CC_PMU_CTL, pmu_ctl); + break; +#endif +#ifdef CONFIG_B43_SSB + case B43_BUS_SSB: + /* FIXME */ + break; +#endif + } +} + /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ChanspecSetup */ static void b43_nphy_channel_setup(struct b43_wldev *dev, const struct b43_phy_n_sfo_cfg *e, @@ -3935,6 +4122,7 @@ static void b43_nphy_channel_setup(struct b43_wldev *dev, { struct b43_phy *phy = &dev->phy; struct b43_phy_n *nphy = dev->phy.n; + int ch = new_channel->hw_value; u16 old_band_5ghz; u32 tmp32; @@ -3974,8 +4162,41 @@ static void b43_nphy_channel_setup(struct b43_wldev *dev, b43_nphy_tx_lp_fbw(dev); - if (dev->phy.rev >= 3 && 0) { - /* TODO */ + if (dev->phy.rev >= 3 && + dev->phy.n->spur_avoid != B43_SPUR_AVOID_DISABLE) { + bool avoid = false; + if (dev->phy.n->spur_avoid == B43_SPUR_AVOID_FORCE) { + avoid = true; + } else if (!b43_channel_type_is_40mhz(phy->channel_type)) { + if ((ch >= 5 && ch <= 8) || ch == 13 || ch == 14) + avoid = true; + } else { /* 40MHz */ + if (nphy->aband_spurwar_en && + (ch == 38 || ch == 102 || ch == 118)) + avoid = dev->dev->chip_id == 0x4716; + } + + b43_nphy_pmu_spur_avoid(dev, avoid); + + if (dev->dev->chip_id == 43222 || dev->dev->chip_id == 43224 || + dev->dev->chip_id == 43225) { + b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, + avoid ? 0x5341 : 0x8889); + b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x8); + } + + if (dev->phy.rev == 3 || dev->phy.rev == 4) + ; /* TODO: reset PLL */ + + if (avoid) + b43_phy_set(dev, B43_NPHY_BBCFG, B43_NPHY_BBCFG_RSTRX); + else + b43_phy_mask(dev, B43_NPHY_BBCFG, + ~B43_NPHY_BBCFG_RSTRX & 0xFFFF); + + b43_nphy_reset_cca(dev); + + /* wl sets useless phy_isspuravoid here */ } b43_phy_write(dev, B43_NPHY_NDATAT_DUP40, 0x3830); @@ -4055,10 +4276,13 @@ static void b43_nphy_op_prepare_structs(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; struct b43_phy_n *nphy = phy->n; + struct ssb_sprom *sprom = dev->dev->bus_sprom; memset(nphy, 0, sizeof(*nphy)); nphy->hang_avoid = (phy->rev == 3 || phy->rev == 4); + nphy->spur_avoid = (phy->rev >= 3) ? + B43_SPUR_AVOID_AUTO : B43_SPUR_AVOID_DISABLE; nphy->gain_boost = true; /* this way we follow wl, assume it is true */ nphy->txrx_chain = 2; /* sth different than 0 and 1 for now */ nphy->phyrxchain = 3; /* to avoid b43_nphy_set_rx_core_state like wl */ @@ -4067,6 +4291,38 @@ static void b43_nphy_op_prepare_structs(struct b43_wldev *dev) * 0x7f == 127 and we check for 128 when restoring TX pwr ctl. */ nphy->tx_pwr_idx[0] = 128; nphy->tx_pwr_idx[1] = 128; + + /* Hardware TX power control and 5GHz power gain */ + nphy->txpwrctrl = false; + nphy->pwg_gain_5ghz = false; + if (dev->phy.rev >= 3 || + (dev->dev->board_vendor == PCI_VENDOR_ID_APPLE && + (dev->dev->core_rev == 11 || dev->dev->core_rev == 12))) { + nphy->txpwrctrl = true; + nphy->pwg_gain_5ghz = true; + } else if (sprom->revision >= 4) { + if (dev->phy.rev >= 2 && + (sprom->boardflags2_lo & B43_BFL2_TXPWRCTRL_EN)) { + nphy->txpwrctrl = true; +#ifdef CONFIG_B43_SSB + if (dev->dev->bus_type == B43_BUS_SSB && + dev->dev->sdev->bus->bustype == SSB_BUSTYPE_PCI) { + struct pci_dev *pdev = + dev->dev->sdev->bus->host_pci; + if (pdev->device == 0x4328 || + pdev->device == 0x432a) + nphy->pwg_gain_5ghz = true; + } +#endif + } else if (sprom->boardflags2_lo & B43_BFL2_5G_PWRGAIN) { + nphy->pwg_gain_5ghz = true; + } + } + + if (dev->phy.rev >= 3) { + nphy->ipa2g_on = sprom->fem.ghz2.extpa_gain == 2; + nphy->ipa5g_on = sprom->fem.ghz5.extpa_gain == 2; + } } static void b43_nphy_op_free(struct b43_wldev *dev) diff --git a/drivers/net/wireless/b43/phy_n.h b/drivers/net/wireless/b43/phy_n.h index fbf520285bd1..56ef97b5b815 100644 --- a/drivers/net/wireless/b43/phy_n.h +++ b/drivers/net/wireless/b43/phy_n.h @@ -716,6 +716,12 @@ struct b43_wldev; +enum b43_nphy_spur_avoid { + B43_SPUR_AVOID_DISABLE, + B43_SPUR_AVOID_AUTO, + B43_SPUR_AVOID_FORCE, +}; + struct b43_chanspec { u16 center_freq; enum nl80211_channel_type channel_type; @@ -785,6 +791,7 @@ struct b43_phy_n { u16 mphase_txcal_bestcoeffs[11]; bool txpwrctrl; + bool pwg_gain_5ghz; u8 tx_pwr_idx[2]; u16 adj_pwr_tbl[84]; u16 txcal_bbmult; @@ -803,6 +810,7 @@ struct b43_phy_n { u16 classifier_state; u16 clip_state[2]; + enum b43_nphy_spur_avoid spur_avoid; bool aband_spurwar_en; bool gband_spurwar_en; diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index fcff923b3c18..d07b412a32c4 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -539,7 +539,7 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) /* Not enough memory on the queue. */ err = -EBUSY; ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); - q->stopped = 1; + q->stopped = true; goto out; } @@ -566,7 +566,7 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) (q->free_packet_slots == 0)) { /* The queue is full. */ ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); - q->stopped = 1; + q->stopped = true; } out: @@ -601,7 +601,7 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev, if (q->stopped) { ieee80211_wake_queue(dev->wl->hw, q->queue_prio); - q->stopped = 0; + q->stopped = false; } } diff --git a/drivers/net/wireless/b43/radio_2056.c b/drivers/net/wireless/b43/radio_2056.c index a01f776ca4de..ce037fb6789a 100644 --- a/drivers/net/wireless/b43/radio_2056.c +++ b/drivers/net/wireless/b43/radio_2056.c @@ -1572,14 +1572,14 @@ static const struct b2056_inittab_entry b2056_inittab_rev6_syn[] = { [B2056_SYN_PLL_XTAL5] = { .ghz5 = 0x0077, .ghz2 = 0x0077, NOUPLOAD, }, [B2056_SYN_PLL_XTAL6] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, }, [B2056_SYN_PLL_REFDIV] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, }, - [B2056_SYN_PLL_PFD] = { .ghz5 = 0x0004, .ghz2 = 0x0004, NOUPLOAD, }, + [B2056_SYN_PLL_PFD] = { .ghz5 = 0x0006, .ghz2 = 0x0006, UPLOAD, }, [B2056_SYN_PLL_CP1] = { .ghz5 = 0x000f, .ghz2 = 0x000f, NOUPLOAD, }, - [B2056_SYN_PLL_CP2] = { .ghz5 = 0x0030, .ghz2 = 0x0030, NOUPLOAD, }, + [B2056_SYN_PLL_CP2] = { .ghz5 = 0x003f, .ghz2 = 0x003f, UPLOAD, }, [B2056_SYN_PLL_CP3] = { .ghz5 = 0x0032, .ghz2 = 0x0032, NOUPLOAD, }, - [B2056_SYN_PLL_LOOPFILTER1] = { .ghz5 = 0x000d, .ghz2 = 0x000d, NOUPLOAD, }, - [B2056_SYN_PLL_LOOPFILTER2] = { .ghz5 = 0x000d, .ghz2 = 0x000d, NOUPLOAD, }, + [B2056_SYN_PLL_LOOPFILTER1] = { .ghz5 = 0x0006, .ghz2 = 0x0006, UPLOAD, }, + [B2056_SYN_PLL_LOOPFILTER2] = { .ghz5 = 0x0006, .ghz2 = 0x0006, UPLOAD, }, [B2056_SYN_PLL_LOOPFILTER3] = { .ghz5 = 0x0004, .ghz2 = 0x0004, NOUPLOAD, }, - [B2056_SYN_PLL_LOOPFILTER4] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, + [B2056_SYN_PLL_LOOPFILTER4] = { .ghz5 = 0x002b, .ghz2 = 0x002b, UPLOAD, }, [B2056_SYN_PLL_LOOPFILTER5] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, }, [B2056_SYN_PLL_MMD1] = { .ghz5 = 0x001c, .ghz2 = 0x001c, NOUPLOAD, }, [B2056_SYN_PLL_MMD2] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, }, @@ -9055,6 +9055,21 @@ void b2056_upload_inittabs(struct b43_wldev *dev, B2056_RX1, pts->rx, pts->rx_length); } +void b2056_upload_syn_pll_cp2(struct b43_wldev *dev, bool ghz5) +{ + struct b2056_inittabs_pts *pts; + const struct b2056_inittab_entry *e; + + if (dev->phy.rev >= ARRAY_SIZE(b2056_inittabs)) { + B43_WARN_ON(1); + return; + } + pts = &b2056_inittabs[dev->phy.rev]; + e = &pts->syn[B2056_SYN_PLL_CP2]; + + b43_radio_write(dev, B2056_SYN_PLL_CP2, ghz5 ? e->ghz5 : e->ghz2); +} + const struct b43_nphy_channeltab_entry_rev3 * b43_nphy_get_chantabent_rev3(struct b43_wldev *dev, u16 freq) { diff --git a/drivers/net/wireless/b43/radio_2056.h b/drivers/net/wireless/b43/radio_2056.h index a7159d8578be..5b86673459fa 100644 --- a/drivers/net/wireless/b43/radio_2056.h +++ b/drivers/net/wireless/b43/radio_2056.h @@ -1090,6 +1090,7 @@ struct b43_nphy_channeltab_entry_rev3 { void b2056_upload_inittabs(struct b43_wldev *dev, bool ghz5, bool ignore_uploadflag); +void b2056_upload_syn_pll_cp2(struct b43_wldev *dev, bool ghz5); /* Get the NPHY Channel Switch Table entry for a channel. * Returns NULL on failure to find an entry. */ diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c index 7b326f2efdc9..3252560e9fa1 100644 --- a/drivers/net/wireless/b43/tables_nphy.c +++ b/drivers/net/wireless/b43/tables_nphy.c @@ -2171,6 +2171,48 @@ static const u16 b43_ntab_loftlt1_r3[] = { 0x0000, 0x0000, }; +/* volatile tables, PHY revision >= 3 */ + +/* indexed by antswctl2g */ +static const u16 b43_ntab_antswctl2g_r3[4][32] = { + { + 0x0082, 0x0082, 0x0211, 0x0222, 0x0328, + 0x0000, 0x0000, 0x0000, 0x0144, 0x0000, + 0x0000, 0x0000, 0x0188, 0x0000, 0x0000, + 0x0000, 0x0082, 0x0082, 0x0211, 0x0222, + 0x0328, 0x0000, 0x0000, 0x0000, 0x0144, + 0x0000, 0x0000, 0x0000, 0x0188, 0x0000, + 0x0000, 0x0000, + }, + { + 0x0022, 0x0022, 0x0011, 0x0022, 0x0022, + 0x0000, 0x0000, 0x0000, 0x0011, 0x0000, + 0x0000, 0x0000, 0x0022, 0x0000, 0x0000, + 0x0000, 0x0022, 0x0022, 0x0011, 0x0022, + 0x0022, 0x0000, 0x0000, 0x0000, 0x0011, + 0x0000, 0x0000, 0x0000, 0x0022, 0x0000, + 0x0000, 0x0000, + }, + { + 0x0088, 0x0088, 0x0044, 0x0088, 0x0088, + 0x0000, 0x0000, 0x0000, 0x0044, 0x0000, + 0x0000, 0x0000, 0x0088, 0x0000, 0x0000, + 0x0000, 0x0088, 0x0088, 0x0044, 0x0088, + 0x0088, 0x0000, 0x0000, 0x0000, 0x0044, + 0x0000, 0x0000, 0x0000, 0x0088, 0x0000, + 0x0000, 0x0000, + }, + { + 0x0022, 0x0022, 0x0011, 0x0022, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0011, 0x0000, + 0x0000, 0x0000, 0x0022, 0x0000, 0x0000, + 0x03cc, 0x0022, 0x0022, 0x0011, 0x0022, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0011, + 0x0000, 0x0000, 0x0000, 0x0022, 0x0000, + 0x0000, 0x03cc, + } +}; + /* TX gain tables */ const u32 b43_ntab_tx_gain_rev0_1_2[] = { 0x03cc2b44, 0x03cc2b42, 0x03cc2a44, 0x03cc2a42, @@ -2652,7 +2694,7 @@ const u16 tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3[] = { const s16 tbl_tx_filter_coef_rev4[7][15] = { { -377, 137, -407, 208, -1527, 956, 93, 186, 93, 230, - -44, 230, 20, -191, 201 }, + -44, 230, 201, -191, 201 }, { -77, 20, -98, 49, -93, 60, 56, 111, 56, 26, -5, 26, 34, -32, 34 }, @@ -2838,9 +2880,8 @@ u32 b43_ntab_read(struct b43_wldev *dev, u32 offset) break; case B43_NTAB_32BIT: b43_phy_write(dev, B43_NPHY_TABLE_ADDR, offset); - value = b43_phy_read(dev, B43_NPHY_TABLE_DATAHI); - value <<= 16; - value |= b43_phy_read(dev, B43_NPHY_TABLE_DATALO); + value = b43_phy_read(dev, B43_NPHY_TABLE_DATALO); + value |= b43_phy_read(dev, B43_NPHY_TABLE_DATAHI) << 16; break; default: B43_WARN_ON(1); @@ -2864,6 +2905,12 @@ void b43_ntab_read_bulk(struct b43_wldev *dev, u32 offset, b43_phy_write(dev, B43_NPHY_TABLE_ADDR, offset); for (i = 0; i < nr_elements; i++) { + /* Auto increment broken + caching issue on BCM43224? */ + if (dev->dev->chip_id == 43224 && dev->dev->chip_rev == 1) { + b43_phy_read(dev, B43_NPHY_TABLE_DATALO); + b43_phy_write(dev, B43_NPHY_TABLE_ADDR, offset + i); + } + switch (type) { case B43_NTAB_8BIT: *data = b43_phy_read(dev, B43_NPHY_TABLE_DATALO) & 0xFF; @@ -2874,9 +2921,10 @@ void b43_ntab_read_bulk(struct b43_wldev *dev, u32 offset, data += 2; break; case B43_NTAB_32BIT: - *((u32 *)data) = b43_phy_read(dev, B43_NPHY_TABLE_DATAHI); - *((u32 *)data) <<= 16; - *((u32 *)data) |= b43_phy_read(dev, B43_NPHY_TABLE_DATALO); + *((u32 *)data) = + b43_phy_read(dev, B43_NPHY_TABLE_DATALO); + *((u32 *)data) |= + b43_phy_read(dev, B43_NPHY_TABLE_DATAHI) << 16; data += 4; break; default: @@ -2932,6 +2980,13 @@ void b43_ntab_write_bulk(struct b43_wldev *dev, u32 offset, b43_phy_write(dev, B43_NPHY_TABLE_ADDR, offset); for (i = 0; i < nr_elements; i++) { + /* Auto increment broken + caching issue on BCM43224? */ + if ((offset >> 10) == 9 && dev->dev->chip_id == 43224 && + dev->dev->chip_rev == 1) { + b43_phy_read(dev, B43_NPHY_TABLE_DATALO); + b43_phy_write(dev, B43_NPHY_TABLE_ADDR, offset + i); + } + switch (type) { case B43_NTAB_8BIT: value = *data; @@ -2999,6 +3054,8 @@ void b43_nphy_rev0_1_2_tables_init(struct b43_wldev *dev) } while (0) void b43_nphy_rev3plus_tables_init(struct b43_wldev *dev) { + struct ssb_sprom *sprom = dev->dev->bus_sprom; + /* Static tables */ ntab_upload_r3(dev, B43_NTAB_FRAMESTRUCT_R3, b43_ntab_framestruct_r3); ntab_upload_r3(dev, B43_NTAB_PILOT_R3, b43_ntab_pilot_r3); @@ -3029,7 +3086,11 @@ void b43_nphy_rev3plus_tables_init(struct b43_wldev *dev) ntab_upload_r3(dev, B43_NTAB_C1_LOFEEDTH_R3, b43_ntab_loftlt1_r3); /* Volatile tables */ - /* TODO */ + if (sprom->fem.ghz2.antswlut < ARRAY_SIZE(b43_ntab_antswctl2g_r3)) + ntab_upload_r3(dev, B43_NTAB_ANT_SW_CTL_R3, + b43_ntab_antswctl2g_r3[sprom->fem.ghz2.antswlut]); + else + B43_WARN_ON(1); } struct nphy_gain_ctl_workaround_entry *b43_nphy_get_gain_ctl_workaround_ent( diff --git a/drivers/net/wireless/b43/tables_nphy.h b/drivers/net/wireless/b43/tables_nphy.h index a81696bff0ed..97038c481930 100644 --- a/drivers/net/wireless/b43/tables_nphy.h +++ b/drivers/net/wireless/b43/tables_nphy.h @@ -126,26 +126,29 @@ struct nphy_gain_ctl_workaround_entry *b43_nphy_get_gain_ctl_workaround_ent( #define B43_NTAB_C1_LOFEEDTH B43_NTAB16(0x1B, 0x1C0) /* Local Oscillator Feed Through Lookup Table Core 1 */ #define B43_NTAB_C1_LOFEEDTH_SIZE 128 +/* Volatile N-PHY tables, PHY revision >= 3 */ +#define B43_NTAB_ANT_SW_CTL_R3 B43_NTAB16( 9, 0) /* antenna software control */ + /* Static N-PHY tables, PHY revision >= 3 */ -#define B43_NTAB_FRAMESTRUCT_R3 B43_NTAB32(10, 000) /* frame struct */ -#define B43_NTAB_PILOT_R3 B43_NTAB16(11, 000) /* pilot */ -#define B43_NTAB_TMAP_R3 B43_NTAB32(12, 000) /* TM AP */ -#define B43_NTAB_INTLEVEL_R3 B43_NTAB32(13, 000) /* INT LV */ -#define B43_NTAB_TDTRN_R3 B43_NTAB32(14, 000) /* TD TRN */ -#define B43_NTAB_NOISEVAR0_R3 B43_NTAB32(16, 000) /* noise variance 0 */ +#define B43_NTAB_FRAMESTRUCT_R3 B43_NTAB32(10, 0) /* frame struct */ +#define B43_NTAB_PILOT_R3 B43_NTAB16(11, 0) /* pilot */ +#define B43_NTAB_TMAP_R3 B43_NTAB32(12, 0) /* TM AP */ +#define B43_NTAB_INTLEVEL_R3 B43_NTAB32(13, 0) /* INT LV */ +#define B43_NTAB_TDTRN_R3 B43_NTAB32(14, 0) /* TD TRN */ +#define B43_NTAB_NOISEVAR0_R3 B43_NTAB32(16, 0) /* noise variance 0 */ #define B43_NTAB_NOISEVAR1_R3 B43_NTAB32(16, 128) /* noise variance 1 */ -#define B43_NTAB_MCS_R3 B43_NTAB16(18, 000) /* MCS */ +#define B43_NTAB_MCS_R3 B43_NTAB16(18, 0) /* MCS */ #define B43_NTAB_TDI20A0_R3 B43_NTAB32(19, 128) /* TDI 20/0 */ #define B43_NTAB_TDI20A1_R3 B43_NTAB32(19, 256) /* TDI 20/1 */ #define B43_NTAB_TDI40A0_R3 B43_NTAB32(19, 640) /* TDI 40/0 */ #define B43_NTAB_TDI40A1_R3 B43_NTAB32(19, 768) /* TDI 40/1 */ -#define B43_NTAB_PILOTLT_R3 B43_NTAB32(20, 000) /* PLT lookup */ -#define B43_NTAB_CHANEST_R3 B43_NTAB32(22, 000) /* channel estimate */ -#define B43_NTAB_FRAMELT_R3 B43_NTAB8 (24, 000) /* frame lookup */ -#define B43_NTAB_C0_ESTPLT_R3 B43_NTAB8 (26, 000) /* estimated power lookup 0 */ -#define B43_NTAB_C1_ESTPLT_R3 B43_NTAB8 (27, 000) /* estimated power lookup 1 */ -#define B43_NTAB_C0_ADJPLT_R3 B43_NTAB8 (26, 064) /* adjusted power lookup 0 */ -#define B43_NTAB_C1_ADJPLT_R3 B43_NTAB8 (27, 064) /* adjusted power lookup 1 */ +#define B43_NTAB_PILOTLT_R3 B43_NTAB32(20, 0) /* PLT lookup */ +#define B43_NTAB_CHANEST_R3 B43_NTAB32(22, 0) /* channel estimate */ +#define B43_NTAB_FRAMELT_R3 B43_NTAB8(24, 0) /* frame lookup */ +#define B43_NTAB_C0_ESTPLT_R3 B43_NTAB8(26, 0) /* estimated power lookup 0 */ +#define B43_NTAB_C1_ESTPLT_R3 B43_NTAB8(27, 0) /* estimated power lookup 1 */ +#define B43_NTAB_C0_ADJPLT_R3 B43_NTAB8(26, 64) /* adjusted power lookup 0 */ +#define B43_NTAB_C1_ADJPLT_R3 B43_NTAB8(27, 64) /* adjusted power lookup 1 */ #define B43_NTAB_C0_GAINCTL_R3 B43_NTAB32(26, 192) /* gain control lookup 0 */ #define B43_NTAB_C1_GAINCTL_R3 B43_NTAB32(27, 192) /* gain control lookup 1 */ #define B43_NTAB_C0_IQLT_R3 B43_NTAB32(26, 320) /* I/Q lookup 0 */ diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 5f77cbe0b6aa..2c5367884b3f 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -874,7 +874,7 @@ bool b43_fill_txstatus_report(struct b43_wldev *dev, struct ieee80211_tx_info *report, const struct b43_txstatus *status) { - bool frame_success = 1; + bool frame_success = true; int retry_limit; /* preserve the confiured retry limit before clearing the status @@ -890,7 +890,7 @@ bool b43_fill_txstatus_report(struct b43_wldev *dev, /* The frame was not ACKed... */ if (!(report->flags & IEEE80211_TX_CTL_NO_ACK)) { /* ...but we expected an ACK. */ - frame_success = 0; + frame_success = false; } } if (status->frame_count == 0) { diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c index c5535adf6991..1ee31c55c7ba 100644 --- a/drivers/net/wireless/b43legacy/dma.c +++ b/drivers/net/wireless/b43legacy/dma.c @@ -715,7 +715,7 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev, ring->mmio_base = b43legacy_dmacontroller_base(type, controller_index); ring->index = controller_index; if (for_tx) { - ring->tx = 1; + ring->tx = true; ring->current_slot = -1; } else { if (ring->index == 0) { @@ -806,7 +806,7 @@ void b43legacy_dma_free(struct b43legacy_wldev *dev) static int b43legacy_dma_set_mask(struct b43legacy_wldev *dev, u64 mask) { u64 orig_mask = mask; - bool fallback = 0; + bool fallback = false; int err; /* Try to set the DMA mask. If it fails, try falling back to a @@ -820,12 +820,12 @@ static int b43legacy_dma_set_mask(struct b43legacy_wldev *dev, u64 mask) } if (mask == DMA_BIT_MASK(64)) { mask = DMA_BIT_MASK(32); - fallback = 1; + fallback = true; continue; } if (mask == DMA_BIT_MASK(32)) { mask = DMA_BIT_MASK(30); - fallback = 1; + fallback = true; continue; } b43legacyerr(dev->wl, "The machine/kernel does not support " @@ -858,7 +858,7 @@ int b43legacy_dma_init(struct b43legacy_wldev *dev) #ifdef CONFIG_B43LEGACY_PIO b43legacywarn(dev->wl, "DMA for this device not supported. " "Falling back to PIO\n"); - dev->__using_pio = 1; + dev->__using_pio = true; return -EAGAIN; #else b43legacyerr(dev->wl, "DMA for this device not supported and " @@ -1068,7 +1068,7 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring, memset(meta, 0, sizeof(*meta)); meta->skb = skb; - meta->is_last_fragment = 1; + meta->is_last_fragment = true; meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); /* create a bounce buffer in zone_dma on mapping failure. */ @@ -1187,7 +1187,7 @@ int b43legacy_dma_tx(struct b43legacy_wldev *dev, should_inject_overflow(ring)) { /* This TX ring is full. */ ieee80211_stop_queue(dev->wl->hw, txring_to_priority(ring)); - ring->stopped = 1; + ring->stopped = true; if (b43legacy_debug(dev, B43legacy_DBG_DMAVERBOSE)) b43legacydbg(dev->wl, "Stopped TX ring %d\n", ring->index); @@ -1286,7 +1286,7 @@ void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev, if (ring->stopped) { B43legacy_WARN_ON(free_slots(ring) < SLOTS_PER_PACKET); ieee80211_wake_queue(dev->wl->hw, txring_to_priority(ring)); - ring->stopped = 0; + ring->stopped = false; if (b43legacy_debug(dev, B43legacy_DBG_DMAVERBOSE)) b43legacydbg(dev->wl, "Woke up TX ring %d\n", ring->index); diff --git a/drivers/net/wireless/b43legacy/leds.c b/drivers/net/wireless/b43legacy/leds.c index 2f1bfdc44f94..fd4565389c77 100644 --- a/drivers/net/wireless/b43legacy/leds.c +++ b/drivers/net/wireless/b43legacy/leds.c @@ -203,11 +203,11 @@ void b43legacy_leds_init(struct b43legacy_wldev *dev) if (sprom[i] == 0xFF) { /* There is no LED information in the SPROM * for this LED. Hardcode it here. */ - activelow = 0; + activelow = false; switch (i) { case 0: behaviour = B43legacy_LED_ACTIVITY; - activelow = 1; + activelow = true; if (bus->boardinfo.vendor == PCI_VENDOR_ID_COMPAQ) behaviour = B43legacy_LED_RADIO_ALL; break; diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 20f02437af8c..200138cdb030 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -722,9 +722,9 @@ void b43legacy_wireless_core_reset(struct b43legacy_wldev *dev, u32 flags) macctl &= ~B43legacy_MACCTL_GMODE; if (flags & B43legacy_TMSLOW_GMODE) { macctl |= B43legacy_MACCTL_GMODE; - dev->phy.gmode = 1; + dev->phy.gmode = true; } else - dev->phy.gmode = 0; + dev->phy.gmode = false; macctl |= B43legacy_MACCTL_IHR_ENABLED; b43legacy_write32(dev, B43legacy_MMIO_MACCTL, macctl); } @@ -811,7 +811,7 @@ static void b43legacy_calculate_link_quality(struct b43legacy_wldev *dev) if (dev->noisecalc.calculation_running) return; dev->noisecalc.channel_at_start = dev->phy.channel; - dev->noisecalc.calculation_running = 1; + dev->noisecalc.calculation_running = true; dev->noisecalc.nr_samples = 0; b43legacy_generate_noise_sample(dev); @@ -873,7 +873,7 @@ static void handle_irq_noise(struct b43legacy_wldev *dev) dev->stats.link_noise = average; drop_calculation: - dev->noisecalc.calculation_running = 0; + dev->noisecalc.calculation_running = false; return; } generate_new: @@ -889,7 +889,7 @@ static void handle_irq_tbtt_indication(struct b43legacy_wldev *dev) b43legacy_power_saving_ctl_bits(dev, -1, -1); } if (b43legacy_is_mode(dev->wl, NL80211_IFTYPE_ADHOC)) - dev->dfq_valid = 1; + dev->dfq_valid = true; } static void handle_irq_atim_end(struct b43legacy_wldev *dev) @@ -898,7 +898,7 @@ static void handle_irq_atim_end(struct b43legacy_wldev *dev) b43legacy_write32(dev, B43legacy_MMIO_MACCMD, b43legacy_read32(dev, B43legacy_MMIO_MACCMD) | B43legacy_MACCMD_DFQ_VALID); - dev->dfq_valid = 0; + dev->dfq_valid = false; } } @@ -971,7 +971,7 @@ static void b43legacy_write_beacon_template(struct b43legacy_wldev *dev, unsigned int i, len, variable_len; const struct ieee80211_mgmt *bcn; const u8 *ie; - bool tim_found = 0; + bool tim_found = false; unsigned int rate; u16 ctl; int antenna; @@ -1019,7 +1019,7 @@ static void b43legacy_write_beacon_template(struct b43legacy_wldev *dev, /* A valid TIM is at least 4 bytes long. */ if (ie_len < 4) break; - tim_found = 1; + tim_found = true; tim_position = sizeof(struct b43legacy_plcp_hdr6); tim_position += offsetof(struct ieee80211_mgmt, @@ -1172,7 +1172,7 @@ static void b43legacy_upload_beacon0(struct b43legacy_wldev *dev) * but we don't use that feature anyway. */ b43legacy_write_probe_resp_template(dev, 0x268, 0x4A, &__b43legacy_ratetable[3]); - wl->beacon0_uploaded = 1; + wl->beacon0_uploaded = true; } static void b43legacy_upload_beacon1(struct b43legacy_wldev *dev) @@ -1182,7 +1182,7 @@ static void b43legacy_upload_beacon1(struct b43legacy_wldev *dev) if (wl->beacon1_uploaded) return; b43legacy_write_beacon_template(dev, 0x468, 0x1A); - wl->beacon1_uploaded = 1; + wl->beacon1_uploaded = true; } static void handle_irq_beacon(struct b43legacy_wldev *dev) @@ -1212,7 +1212,7 @@ static void handle_irq_beacon(struct b43legacy_wldev *dev) if (unlikely(wl->beacon_templates_virgin)) { /* We never uploaded a beacon before. * Upload both templates now, but only mark one valid. */ - wl->beacon_templates_virgin = 0; + wl->beacon_templates_virgin = false; b43legacy_upload_beacon0(dev); b43legacy_upload_beacon1(dev); cmd = b43legacy_read32(dev, B43legacy_MMIO_MACCMD); @@ -1275,8 +1275,8 @@ static void b43legacy_update_templates(struct b43legacy_wl *wl) if (wl->current_beacon) dev_kfree_skb_any(wl->current_beacon); wl->current_beacon = beacon; - wl->beacon0_uploaded = 0; - wl->beacon1_uploaded = 0; + wl->beacon0_uploaded = false; + wl->beacon1_uploaded = false; ieee80211_queue_work(wl->hw, &wl->beacon_update_trigger); } @@ -2510,7 +2510,7 @@ static int find_wldev_for_phymode(struct b43legacy_wl *wl, if (d->phy.possible_phymodes & phymode) { /* Ok, this device supports the PHY-mode. * Set the gmode bit. */ - *gmode = 1; + *gmode = true; *dev = d; return 0; @@ -2546,7 +2546,7 @@ static int b43legacy_switch_phymode(struct b43legacy_wl *wl, struct b43legacy_wldev *uninitialized_var(up_dev); struct b43legacy_wldev *down_dev; int err; - bool gmode = 0; + bool gmode = false; int prev_status; err = find_wldev_for_phymode(wl, new_mode, &up_dev, &gmode); @@ -3044,12 +3044,12 @@ static void setup_struct_phy_for_init(struct b43legacy_wldev *dev, /* Assume the radio is enabled. If it's not enabled, the state will * immediately get fixed on the first periodic work run. */ - dev->radio_hw_enable = 1; + dev->radio_hw_enable = true; phy->savedpctlreg = 0xFFFF; - phy->aci_enable = 0; - phy->aci_wlan_automatic = 0; - phy->aci_hw_rssi = 0; + phy->aci_enable = false; + phy->aci_wlan_automatic = false; + phy->aci_hw_rssi = false; lo = phy->_lo_pairs; if (lo) @@ -3081,7 +3081,7 @@ static void setup_struct_phy_for_init(struct b43legacy_wldev *dev, static void setup_struct_wldev_for_init(struct b43legacy_wldev *dev) { /* Flags */ - dev->dfq_valid = 0; + dev->dfq_valid = false; /* Stats */ memset(&dev->stats, 0, sizeof(dev->stats)); @@ -3187,9 +3187,9 @@ static void prepare_phy_data_for_init(struct b43legacy_wldev *dev) phy->lofcal = 0xFFFF; phy->initval = 0xFFFF; - phy->aci_enable = 0; - phy->aci_wlan_automatic = 0; - phy->aci_hw_rssi = 0; + phy->aci_enable = false; + phy->aci_wlan_automatic = false; + phy->aci_hw_rssi = false; phy->antenna_diversity = 0xFFFF; memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig)); @@ -3355,7 +3355,7 @@ static int b43legacy_op_add_interface(struct ieee80211_hw *hw, b43legacydbg(wl, "Adding Interface type %d\n", vif->type); dev = wl->current_dev; - wl->operating = 1; + wl->operating = true; wl->vif = vif; wl->if_type = vif->type; memcpy(wl->mac_addr, vif->addr, ETH_ALEN); @@ -3389,7 +3389,7 @@ static void b43legacy_op_remove_interface(struct ieee80211_hw *hw, B43legacy_WARN_ON(wl->vif != vif); wl->vif = NULL; - wl->operating = 0; + wl->operating = false; spin_lock_irqsave(&wl->irq_lock, flags); b43legacy_adjust_opmode(dev); @@ -3413,10 +3413,10 @@ static int b43legacy_op_start(struct ieee80211_hw *hw) memset(wl->bssid, 0, ETH_ALEN); memset(wl->mac_addr, 0, ETH_ALEN); wl->filter_flags = 0; - wl->beacon0_uploaded = 0; - wl->beacon1_uploaded = 0; - wl->beacon_templates_virgin = 1; - wl->radio_enabled = 1; + wl->beacon0_uploaded = false; + wl->beacon1_uploaded = false; + wl->beacon_templates_virgin = true; + wl->radio_enabled = true; mutex_lock(&wl->mutex); @@ -3455,7 +3455,7 @@ static void b43legacy_op_stop(struct ieee80211_hw *hw) if (b43legacy_status(dev) >= B43legacy_STAT_STARTED) b43legacy_wireless_core_stop(dev); b43legacy_wireless_core_exit(dev); - wl->radio_enabled = 0; + wl->radio_enabled = false; mutex_unlock(&wl->mutex); } @@ -3614,7 +3614,7 @@ static int b43legacy_wireless_core_attach(struct b43legacy_wldev *dev) have_bphy = 1; dev->phy.gmode = (have_gphy || have_bphy); - dev->phy.radio_on = 1; + dev->phy.radio_on = true; tmp = dev->phy.gmode ? B43legacy_TMSLOW_GMODE : 0; b43legacy_wireless_core_reset(dev, tmp); @@ -3705,7 +3705,7 @@ static int b43legacy_one_core_attach(struct ssb_device *dev, (void (*)(unsigned long))b43legacy_interrupt_tasklet, (unsigned long)wldev); if (modparam_pio) - wldev->__using_pio = 1; + wldev->__using_pio = true; INIT_LIST_HEAD(&wldev->list); err = b43legacy_wireless_core_attach(wldev); diff --git a/drivers/net/wireless/b43legacy/radio.c b/drivers/net/wireless/b43legacy/radio.c index 475eb14e665b..fcbafcd603cc 100644 --- a/drivers/net/wireless/b43legacy/radio.c +++ b/drivers/net/wireless/b43legacy/radio.c @@ -1067,7 +1067,7 @@ b43legacy_radio_interference_mitigation_enable(struct b43legacy_wldev *dev, if (b43legacy_phy_read(dev, 0x0033) & 0x0800) break; - phy->aci_enable = 1; + phy->aci_enable = true; phy_stacksave(B43legacy_PHY_RADIO_BITFIELD); phy_stacksave(B43legacy_PHY_G_CRS); @@ -1279,7 +1279,7 @@ b43legacy_radio_interference_mitigation_disable(struct b43legacy_wldev *dev, if (!(b43legacy_phy_read(dev, 0x0033) & 0x0800)) break; - phy->aci_enable = 0; + phy->aci_enable = false; phy_stackrestore(B43legacy_PHY_RADIO_BITFIELD); phy_stackrestore(B43legacy_PHY_G_CRS); @@ -1346,10 +1346,10 @@ int b43legacy_radio_set_interference_mitigation(struct b43legacy_wldev *dev, (phy->rev == 0) || (!phy->gmode)) return -ENODEV; - phy->aci_wlan_automatic = 0; + phy->aci_wlan_automatic = false; switch (mode) { case B43legacy_RADIO_INTERFMODE_AUTOWLAN: - phy->aci_wlan_automatic = 1; + phy->aci_wlan_automatic = true; if (phy->aci_enable) mode = B43legacy_RADIO_INTERFMODE_MANUALWLAN; else @@ -1371,8 +1371,8 @@ int b43legacy_radio_set_interference_mitigation(struct b43legacy_wldev *dev, currentmode); if (mode == B43legacy_RADIO_INTERFMODE_NONE) { - phy->aci_enable = 0; - phy->aci_hw_rssi = 0; + phy->aci_enable = false; + phy->aci_hw_rssi = false; } else b43legacy_radio_interference_mitigation_enable(dev, mode); phy->interfmode = mode; @@ -2102,7 +2102,7 @@ void b43legacy_radio_turn_on(struct b43legacy_wldev *dev) phy->radio_off_context.rfover); b43legacy_phy_write(dev, B43legacy_PHY_RFOVERVAL, phy->radio_off_context.rfoverval); - phy->radio_off_context.valid = 0; + phy->radio_off_context.valid = false; } channel = phy->channel; err = b43legacy_radio_selectchannel(dev, @@ -2113,7 +2113,7 @@ void b43legacy_radio_turn_on(struct b43legacy_wldev *dev) default: B43legacy_BUG_ON(1); } - phy->radio_on = 1; + phy->radio_on = true; } void b43legacy_radio_turn_off(struct b43legacy_wldev *dev, bool force) @@ -2131,14 +2131,14 @@ void b43legacy_radio_turn_off(struct b43legacy_wldev *dev, bool force) if (!force) { phy->radio_off_context.rfover = rfover; phy->radio_off_context.rfoverval = rfoverval; - phy->radio_off_context.valid = 1; + phy->radio_off_context.valid = true; } b43legacy_phy_write(dev, B43legacy_PHY_RFOVER, rfover | 0x008C); b43legacy_phy_write(dev, B43legacy_PHY_RFOVERVAL, rfoverval & 0xFF73); } else b43legacy_phy_write(dev, 0x0015, 0xAA00); - phy->radio_on = 0; + phy->radio_on = false; b43legacydbg(dev->wl, "Radio initialized\n"); } diff --git a/drivers/net/wireless/brcm80211/Kconfig b/drivers/net/wireless/brcm80211/Kconfig index 2069fc8f7ad1..8f54c2eb6824 100644 --- a/drivers/net/wireless/brcm80211/Kconfig +++ b/drivers/net/wireless/brcm80211/Kconfig @@ -3,9 +3,8 @@ config BRCMUTIL config BRCMSMAC tristate "Broadcom IEEE802.11n PCIe SoftMAC WLAN driver" - depends on PCI depends on MAC80211 - depends on BCMA=n + depends on BCMA select BRCMUTIL select FW_LOADER select CRC_CCITT diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmchip.h b/drivers/net/wireless/brcm80211/brcmfmac/bcmchip.h deleted file mode 100644 index cecb5e5f412b..000000000000 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmchip.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2011 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef _bcmchip_h_ -#define _bcmchip_h_ - -/* bcm4329 */ -/* firmware name */ -#define BCM4329_FW_NAME "brcm/bcm4329-fullmac-4.bin" -#define BCM4329_NV_NAME "brcm/bcm4329-fullmac-4.txt" - -#endif /* _bcmchip_h_ */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c index 89ff94da556a..6c85d668c9d7 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c @@ -222,19 +222,12 @@ bool brcmf_sdcard_regfail(struct brcmf_sdio_dev *sdiodev) return sdiodev->regfail; } -int -brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, - uint flags, - u8 *buf, uint nbytes, struct sk_buff *pkt) +static int brcmf_sdcard_recv_prepare(struct brcmf_sdio_dev *sdiodev, uint fn, + uint flags, uint width, u32 *addr) { - int status; - uint incr_fix; - uint width; - uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK; + uint bar0 = *addr & ~SBSDIO_SB_OFT_ADDR_MASK; int err = 0; - brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n", fn, addr, nbytes); - /* Async not implemented yet */ if (flags & SDIO_REQ_ASYNC) return -ENOTSUPP; @@ -247,29 +240,114 @@ brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, sdiodev->sbwad = bar0; } - addr &= SBSDIO_SB_OFT_ADDR_MASK; + *addr &= SBSDIO_SB_OFT_ADDR_MASK; + + if (width == 4) + *addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; + + return 0; +} + +int +brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, + uint flags, u8 *buf, uint nbytes) +{ + struct sk_buff *mypkt; + int err; + + mypkt = brcmu_pkt_buf_get_skb(nbytes); + if (!mypkt) { + brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n", + nbytes); + return -EIO; + } + + err = brcmf_sdcard_recv_pkt(sdiodev, addr, fn, flags, mypkt); + if (!err) + memcpy(buf, mypkt->data, nbytes); + + brcmu_pkt_buf_free_skb(mypkt); + return err; +} + +int +brcmf_sdcard_recv_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, + uint flags, struct sk_buff *pkt) +{ + uint incr_fix; + uint width; + int err = 0; + + brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n", + fn, addr, pkt->len); + + width = (flags & SDIO_REQ_4BYTE) ? 4 : 2; + err = brcmf_sdcard_recv_prepare(sdiodev, fn, flags, width, &addr); + if (err) + return err; incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC; + err = brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_READ, + fn, addr, pkt); + + return err; +} + +int brcmf_sdcard_recv_chain(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, + uint flags, struct sk_buff_head *pktq) +{ + uint incr_fix; + uint width; + int err = 0; + + brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n", + fn, addr, pktq->qlen); + width = (flags & SDIO_REQ_4BYTE) ? 4 : 2; - if (width == 4) - addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; + err = brcmf_sdcard_recv_prepare(sdiodev, fn, flags, width, &addr); + if (err) + return err; - status = brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_READ, - fn, addr, width, nbytes, buf, pkt); + incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC; + err = brcmf_sdioh_request_chain(sdiodev, incr_fix, SDIOH_READ, fn, addr, + pktq); - return status; + return err; } int brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, - uint flags, u8 *buf, uint nbytes, struct sk_buff *pkt) + uint flags, u8 *buf, uint nbytes) +{ + struct sk_buff *mypkt; + int err; + + mypkt = brcmu_pkt_buf_get_skb(nbytes); + if (!mypkt) { + brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n", + nbytes); + return -EIO; + } + + memcpy(mypkt->data, buf, nbytes); + err = brcmf_sdcard_send_pkt(sdiodev, addr, fn, flags, mypkt); + + brcmu_pkt_buf_free_skb(mypkt); + return err; + +} + +int +brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, + uint flags, struct sk_buff *pkt) { uint incr_fix; uint width; uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK; int err = 0; - brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n", fn, addr, nbytes); + brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n", + fn, addr, pkt->len); /* Async not implemented yet */ if (flags & SDIO_REQ_ASYNC) @@ -291,18 +369,39 @@ brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; return brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_WRITE, fn, - addr, width, nbytes, buf, pkt); + addr, pkt); } int brcmf_sdcard_rwdata(struct brcmf_sdio_dev *sdiodev, uint rw, u32 addr, u8 *buf, uint nbytes) { + struct sk_buff *mypkt; + bool write = rw ? SDIOH_WRITE : SDIOH_READ; + int err; + addr &= SBSDIO_SB_OFT_ADDR_MASK; addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; - return brcmf_sdioh_request_buffer(sdiodev, SDIOH_DATA_INC, - (rw ? SDIOH_WRITE : SDIOH_READ), SDIO_FUNC_1, - addr, 4, nbytes, buf, NULL); + mypkt = brcmu_pkt_buf_get_skb(nbytes); + if (!mypkt) { + brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n", + nbytes); + return -EIO; + } + + /* For a write, copy the buffer data into the packet. */ + if (write) + memcpy(mypkt->data, buf, nbytes); + + err = brcmf_sdioh_request_buffer(sdiodev, SDIOH_DATA_INC, write, + SDIO_FUNC_1, addr, mypkt); + + /* For a read, copy the packet data back to the buffer. */ + if (!err && !write) + memcpy(buf, mypkt->data, nbytes); + + brcmu_pkt_buf_free_skb(mypkt); + return err; } int brcmf_sdcard_abort(struct brcmf_sdio_dev *sdiodev, uint fn) @@ -333,7 +432,7 @@ int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) sdiodev->sbwad = SI_ENUM_BASE; /* try to attach to the target device */ - sdiodev->bus = brcmf_sdbrcm_probe(0, 0, 0, 0, regs, sdiodev); + sdiodev->bus = brcmf_sdbrcm_probe(regs, sdiodev); if (!sdiodev->bus) { brcmf_dbg(ERROR, "device attach failed\n"); ret = -ENODEV; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c index bbaeb2d5c93a..b895f198a950 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c @@ -40,6 +40,7 @@ #define DMA_ALIGN_MASK 0x03 #define SDIO_DEVICE_ID_BROADCOM_4329 0x4329 +#define SDIO_DEVICE_ID_BROADCOM_4330 0x4330 #define SDIO_FUNC1_BLOCKSIZE 64 #define SDIO_FUNC2_BLOCKSIZE 512 @@ -47,6 +48,7 @@ /* devices we support, null terminated */ static const struct sdio_device_id brcmf_sdmmc_ids[] = { {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329)}, + {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4330)}, { /* end: all zeroes */ }, }; MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids); @@ -204,62 +206,75 @@ int brcmf_sdioh_request_word(struct brcmf_sdio_dev *sdiodev, return err_ret; } +/* precondition: host controller is claimed */ static int -brcmf_sdioh_request_packet(struct brcmf_sdio_dev *sdiodev, uint fix_inc, - uint write, uint func, uint addr, - struct sk_buff *pkt) +brcmf_sdioh_request_data(struct brcmf_sdio_dev *sdiodev, uint write, bool fifo, + uint func, uint addr, struct sk_buff *pkt, uint pktlen) +{ + int err_ret = 0; + + if ((write) && (!fifo)) { + err_ret = sdio_memcpy_toio(sdiodev->func[func], addr, + ((u8 *) (pkt->data)), pktlen); + } else if (write) { + err_ret = sdio_memcpy_toio(sdiodev->func[func], addr, + ((u8 *) (pkt->data)), pktlen); + } else if (fifo) { + err_ret = sdio_readsb(sdiodev->func[func], + ((u8 *) (pkt->data)), addr, pktlen); + } else { + err_ret = sdio_memcpy_fromio(sdiodev->func[func], + ((u8 *) (pkt->data)), + addr, pktlen); + } + + return err_ret; +} + +/* + * This function takes a queue of packets. The packets on the queue + * are assumed to be properly aligned by the caller. + */ +int +brcmf_sdioh_request_chain(struct brcmf_sdio_dev *sdiodev, uint fix_inc, + uint write, uint func, uint addr, + struct sk_buff_head *pktq) { bool fifo = (fix_inc == SDIOH_DATA_FIX); u32 SGCount = 0; int err_ret = 0; - struct sk_buff *pnext; + struct sk_buff *pkt; brcmf_dbg(TRACE, "Enter\n"); - brcmf_pm_resume_wait(sdiodev, &sdiodev->request_packet_wait); + brcmf_pm_resume_wait(sdiodev, &sdiodev->request_chain_wait); if (brcmf_pm_resume_error(sdiodev)) return -EIO; /* Claim host controller */ sdio_claim_host(sdiodev->func[func]); - for (pnext = pkt; pnext; pnext = pnext->next) { - uint pkt_len = pnext->len; + + skb_queue_walk(pktq, pkt) { + uint pkt_len = pkt->len; pkt_len += 3; pkt_len &= 0xFFFFFFFC; - if ((write) && (!fifo)) { - err_ret = sdio_memcpy_toio(sdiodev->func[func], addr, - ((u8 *) (pnext->data)), - pkt_len); - } else if (write) { - err_ret = sdio_memcpy_toio(sdiodev->func[func], addr, - ((u8 *) (pnext->data)), - pkt_len); - } else if (fifo) { - err_ret = sdio_readsb(sdiodev->func[func], - ((u8 *) (pnext->data)), - addr, pkt_len); - } else { - err_ret = sdio_memcpy_fromio(sdiodev->func[func], - ((u8 *) (pnext->data)), - addr, pkt_len); - } - + err_ret = brcmf_sdioh_request_data(sdiodev, write, fifo, func, + addr, pkt, pkt_len); if (err_ret) { brcmf_dbg(ERROR, "%s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=0x%08x\n", - write ? "TX" : "RX", pnext, SGCount, addr, + write ? "TX" : "RX", pkt, SGCount, addr, pkt_len, err_ret); } else { brcmf_dbg(TRACE, "%s xfr'd %p[%d], addr=0x%05x, len=%d\n", - write ? "TX" : "RX", pnext, SGCount, addr, + write ? "TX" : "RX", pkt, SGCount, addr, pkt_len); } - if (!fifo) addr += pkt_len; - SGCount++; + SGCount++; } /* Release host controller */ @@ -270,91 +285,45 @@ brcmf_sdioh_request_packet(struct brcmf_sdio_dev *sdiodev, uint fix_inc, } /* - * This function takes a buffer or packet, and fixes everything up - * so that in the end, a DMA-able packet is created. - * - * A buffer does not have an associated packet pointer, - * and may or may not be aligned. - * A packet may consist of a single packet, or a packet chain. - * If it is a packet chain, then all the packets in the chain - * must be properly aligned. - * - * If the packet data is not aligned, then there may only be - * one packet, and in this case, it is copied to a new - * aligned packet. - * + * This function takes a single DMA-able packet. */ int brcmf_sdioh_request_buffer(struct brcmf_sdio_dev *sdiodev, uint fix_inc, uint write, uint func, uint addr, - uint reg_width, uint buflen_u, u8 *buffer, struct sk_buff *pkt) { - int Status; - struct sk_buff *mypkt = NULL; + int status; + uint pkt_len = pkt->len; + bool fifo = (fix_inc == SDIOH_DATA_FIX); brcmf_dbg(TRACE, "Enter\n"); + if (pkt == NULL) + return -EINVAL; + brcmf_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait); if (brcmf_pm_resume_error(sdiodev)) return -EIO; - /* Case 1: we don't have a packet. */ - if (pkt == NULL) { - brcmf_dbg(DATA, "Creating new %s Packet, len=%d\n", - write ? "TX" : "RX", buflen_u); - mypkt = brcmu_pkt_buf_get_skb(buflen_u); - if (!mypkt) { - brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n", - buflen_u); - return -EIO; - } - - /* For a write, copy the buffer data into the packet. */ - if (write) - memcpy(mypkt->data, buffer, buflen_u); - - Status = brcmf_sdioh_request_packet(sdiodev, fix_inc, write, - func, addr, mypkt); - - /* For a read, copy the packet data back to the buffer. */ - if (!write) - memcpy(buffer, mypkt->data, buflen_u); - - brcmu_pkt_buf_free_skb(mypkt); - } else if (((ulong) (pkt->data) & DMA_ALIGN_MASK) != 0) { - /* - * Case 2: We have a packet, but it is unaligned. - * In this case, we cannot have a chain (pkt->next == NULL) - */ - brcmf_dbg(DATA, "Creating aligned %s Packet, len=%d\n", - write ? "TX" : "RX", pkt->len); - mypkt = brcmu_pkt_buf_get_skb(pkt->len); - if (!mypkt) { - brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n", - pkt->len); - return -EIO; - } - /* For a write, copy the buffer data into the packet. */ - if (write) - memcpy(mypkt->data, pkt->data, pkt->len); - - Status = brcmf_sdioh_request_packet(sdiodev, fix_inc, write, - func, addr, mypkt); + /* Claim host controller */ + sdio_claim_host(sdiodev->func[func]); - /* For a read, copy the packet data back to the buffer. */ - if (!write) - memcpy(pkt->data, mypkt->data, mypkt->len); + pkt_len += 3; + pkt_len &= (uint)~3; - brcmu_pkt_buf_free_skb(mypkt); - } else { /* case 3: We have a packet and - it is aligned. */ - brcmf_dbg(DATA, "Aligned %s Packet, direct DMA\n", - write ? "Tx" : "Rx"); - Status = brcmf_sdioh_request_packet(sdiodev, fix_inc, write, - func, addr, pkt); + status = brcmf_sdioh_request_data(sdiodev, write, fifo, func, + addr, pkt, pkt_len); + if (status) { + brcmf_dbg(ERROR, "%s FAILED %p, addr=0x%05x, pkt_len=%d, ERR=0x%08x\n", + write ? "TX" : "RX", pkt, addr, pkt_len, status); + } else { + brcmf_dbg(TRACE, "%s xfr'd %p, addr=0x%05x, len=%d\n", + write ? "TX" : "RX", pkt, addr, pkt_len); } - return Status; + /* Release host controller */ + sdio_release_host(sdiodev->func[func]); + + return status; } /* Read client card reg */ @@ -494,6 +463,7 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func, { int ret = 0; struct brcmf_sdio_dev *sdiodev; + struct brcmf_bus *bus_if; brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(TRACE, "func->class=%x\n", func->class); brcmf_dbg(TRACE, "sdio_vendor: 0x%04x\n", func->vendor); @@ -505,17 +475,25 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func, brcmf_dbg(ERROR, "card private drvdata occupied\n"); return -ENXIO; } + bus_if = kzalloc(sizeof(struct brcmf_bus), GFP_KERNEL); + if (!bus_if) + return -ENOMEM; sdiodev = kzalloc(sizeof(struct brcmf_sdio_dev), GFP_KERNEL); - if (!sdiodev) + if (!sdiodev) { + kfree(bus_if); return -ENOMEM; + } sdiodev->func[0] = func->card->sdio_func[0]; sdiodev->func[1] = func; + sdiodev->bus_if = bus_if; + bus_if->bus_priv = sdiodev; + bus_if->type = SDIO_BUS; dev_set_drvdata(&func->card->dev, sdiodev); atomic_set(&sdiodev->suspend, false); init_waitqueue_head(&sdiodev->request_byte_wait); init_waitqueue_head(&sdiodev->request_word_wait); - init_waitqueue_head(&sdiodev->request_packet_wait); + init_waitqueue_head(&sdiodev->request_chain_wait); init_waitqueue_head(&sdiodev->request_buffer_wait); } @@ -525,6 +503,10 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func, return -ENODEV; sdiodev->func[2] = func; + bus_if = sdiodev->bus_if; + sdiodev->dev = &func->dev; + dev_set_drvdata(&func->dev, bus_if); + brcmf_dbg(TRACE, "F2 found, calling brcmf_sdio_probe...\n"); ret = brcmf_sdio_probe(sdiodev); } @@ -534,6 +516,7 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func, static void brcmf_ops_sdio_remove(struct sdio_func *func) { + struct brcmf_bus *bus_if; struct brcmf_sdio_dev *sdiodev; brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(INFO, "func->class=%x\n", func->class); @@ -542,10 +525,13 @@ static void brcmf_ops_sdio_remove(struct sdio_func *func) brcmf_dbg(INFO, "Function#: 0x%04x\n", func->num); if (func->num == 2) { - sdiodev = dev_get_drvdata(&func->card->dev); + bus_if = dev_get_drvdata(&func->dev); + sdiodev = bus_if->bus_priv; brcmf_dbg(TRACE, "F2 found, calling brcmf_sdio_remove...\n"); brcmf_sdio_remove(sdiodev); dev_set_drvdata(&func->card->dev, NULL); + dev_set_drvdata(&func->dev, NULL); + kfree(bus_if); kfree(sdiodev); } } @@ -554,14 +540,12 @@ static void brcmf_ops_sdio_remove(struct sdio_func *func) static int brcmf_sdio_suspend(struct device *dev) { mmc_pm_flag_t sdio_flags; - struct brcmf_sdio_dev *sdiodev; struct sdio_func *func = dev_to_sdio_func(dev); + struct brcmf_sdio_dev *sdiodev = dev_get_drvdata(&func->card->dev); int ret = 0; brcmf_dbg(TRACE, "\n"); - sdiodev = dev_get_drvdata(&func->card->dev); - atomic_set(&sdiodev->suspend, true); sdio_flags = sdio_get_host_pm_caps(sdiodev->func[1]); @@ -583,10 +567,9 @@ static int brcmf_sdio_suspend(struct device *dev) static int brcmf_sdio_resume(struct device *dev) { - struct brcmf_sdio_dev *sdiodev; struct sdio_func *func = dev_to_sdio_func(dev); + struct brcmf_sdio_dev *sdiodev = dev_get_drvdata(&func->card->dev); - sdiodev = dev_get_drvdata(&func->card->dev); brcmf_sdio_wdtmr_enable(sdiodev, true); atomic_set(&sdiodev->suspend, false); return 0; @@ -610,17 +593,26 @@ static struct sdio_driver brcmf_sdmmc_driver = { #endif /* CONFIG_PM_SLEEP */ }; -/* bus register interface */ -int brcmf_bus_register(void) +static void __exit brcmf_sdio_exit(void) { brcmf_dbg(TRACE, "Enter\n"); - return sdio_register_driver(&brcmf_sdmmc_driver); + sdio_unregister_driver(&brcmf_sdmmc_driver); } -void brcmf_bus_unregister(void) +static int __init brcmf_sdio_init(void) { + int ret; + brcmf_dbg(TRACE, "Enter\n"); - sdio_unregister_driver(&brcmf_sdmmc_driver); + ret = sdio_register_driver(&brcmf_sdmmc_driver); + + if (ret) + brcmf_dbg(ERROR, "sdio_register_driver failed: %d\n", ret); + + return ret; } + +module_init(brcmf_sdio_init); +module_exit(brcmf_sdio_exit); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h index 6da519e7578f..ed60f4d69627 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h @@ -87,7 +87,7 @@ #define TOE_TX_CSUM_OL 0x00000001 #define TOE_RX_CSUM_OL 0x00000002 -#define BRCMF_BSS_INFO_VERSION 108 /* curr ver of brcmf_bss_info_le struct */ +#define BRCMF_BSS_INFO_VERSION 109 /* curr ver of brcmf_bss_info_le struct */ /* size of brcmf_scan_params not including variable length array */ #define BRCMF_SCAN_PARAMS_FIXED_SIZE 64 @@ -571,8 +571,14 @@ struct brcmf_dcmd { uint needed; /* bytes needed (optional) */ }; +struct brcmf_bus { + u8 type; /* bus type */ + void *bus_priv; /* pointer to bus private structure */ + enum brcmf_bus_state state; +}; + /* Forward decls for struct brcmf_pub (see below) */ -struct brcmf_bus; /* device bus info */ +struct brcmf_sdio; /* device bus info */ struct brcmf_proto; /* device communication protocol info */ struct brcmf_info; /* device driver info */ struct brcmf_cfg80211_dev; /* cfg80211 device info */ @@ -580,15 +586,16 @@ struct brcmf_cfg80211_dev; /* cfg80211 device info */ /* Common structure for module and instance linkage */ struct brcmf_pub { /* Linkage ponters */ - struct brcmf_bus *bus; + struct brcmf_sdio *bus; + struct brcmf_bus *bus_if; struct brcmf_proto *prot; struct brcmf_info *info; struct brcmf_cfg80211_dev *config; + struct device *dev; /* fullmac dongle device pointer */ /* Internal brcmf items */ bool up; /* Driver up/down (to OS) */ bool txoff; /* Transmit flow-controlled */ - enum brcmf_bus_state busstate; uint hdrlen; /* Total BRCMF header length (proto + bus) */ uint maxctl; /* Max size rxctl request from proto to bus */ uint rxsz; /* Rx buffer size bus module should use */ @@ -656,7 +663,6 @@ struct brcmf_pub { u8 country_code[BRCM_CNTRY_BUF_SZ]; char eventmask[BRCMF_EVENTING_MASK_LEN]; - }; struct brcmf_if_event { @@ -681,8 +687,8 @@ extern uint brcmf_c_mkiovar(char *name, char *data, uint datalen, * Returned structure should have bus and prot pointers filled in. * bus_hdrlen specifies required headroom for bus module header. */ -extern struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus, - uint bus_hdrlen); +extern struct brcmf_pub *brcmf_attach(struct brcmf_sdio *bus, + uint bus_hdrlen, struct device *dev); extern int brcmf_net_attach(struct brcmf_pub *drvr, int idx); extern int brcmf_netdev_wait_pend8021x(struct net_device *ndev); @@ -699,7 +705,16 @@ extern bool brcmf_c_prec_enq(struct brcmf_pub *drvr, struct pktq *q, /* Receive frame for delivery to OS. Callee disposes of rxp. */ extern void brcmf_rx_frame(struct brcmf_pub *drvr, int ifidx, - struct sk_buff *rxp, int numpkt); + struct sk_buff_head *rxlist); +static inline void brcmf_rx_packet(struct brcmf_pub *drvr, int ifidx, + struct sk_buff *pkt) +{ + struct sk_buff_head q; + + skb_queue_head_init(&q); + skb_queue_tail(&q, pkt); + brcmf_rx_frame(drvr, ifidx, &q); +} /* Return pointer to interface name */ extern char *brcmf_ifname(struct brcmf_pub *drvr, int idx); @@ -724,8 +739,6 @@ extern int brcmf_c_host_event(struct brcmf_info *drvr_priv, int *idx, void *pktdata, struct brcmf_event_msg *, void **data_ptr); -extern void brcmf_c_init(void); - extern int brcmf_add_if(struct brcmf_info *drvr_priv, int ifidx, char *name, u8 *mac_addr); extern void brcmf_del_if(struct brcmf_info *drvr_priv, int ifidx); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h index a249407c9a1b..1841f996110b 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h @@ -27,31 +27,24 @@ * Exported from brcmf bus module (brcmf_usb, brcmf_sdio) */ -/* Indicate (dis)interest in finding dongles. */ -extern int brcmf_bus_register(void); -extern void brcmf_bus_unregister(void); - -/* obtain linux device object providing bus function */ -extern struct device *brcmf_bus_get_device(struct brcmf_bus *bus); - /* Stop bus module: clear pending frames, disable data flow */ -extern void brcmf_sdbrcm_bus_stop(struct brcmf_bus *bus); +extern void brcmf_sdbrcm_bus_stop(struct device *dev); /* Initialize bus module: prepare for communication w/dongle */ -extern int brcmf_sdbrcm_bus_init(struct brcmf_pub *drvr); +extern int brcmf_sdbrcm_bus_init(struct device *dev); /* Send a data frame to the dongle. Callee disposes of txp. */ -extern int brcmf_sdbrcm_bus_txdata(struct brcmf_bus *bus, struct sk_buff *txp); +extern int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *txp); /* Send/receive a control message to/from the dongle. * Expects caller to enforce a single outstanding transaction. */ extern int -brcmf_sdbrcm_bus_txctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen); +brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen); extern int -brcmf_sdbrcm_bus_rxctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen); +brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen); -extern void brcmf_sdbrcm_wd_timer(struct brcmf_bus *bus, uint wdtick); +extern void brcmf_sdbrcm_wd_timer(struct brcmf_sdio *bus, uint wdtick); #endif /* _BRCMF_BUS_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c index e34c5c3d1d55..ebd53aa7202b 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c @@ -58,7 +58,7 @@ struct brcmf_proto_cdc_dcmd { * Used on data packets to convey priority across USB. */ #define BDC_HEADER_LEN 4 -#define BDC_PROTO_VER 1 /* Protocol version */ +#define BDC_PROTO_VER 2 /* Protocol version */ #define BDC_FLAG_VER_MASK 0xf0 /* Protocol version mask */ #define BDC_FLAG_VER_SHIFT 4 /* Protocol version shift */ #define BDC_FLAG_SUM_GOOD 0x04 /* Good RX checksums */ @@ -77,7 +77,7 @@ struct brcmf_proto_bdc_header { u8 flags; u8 priority; /* 802.1d Priority, 4:7 flow control info for usb */ u8 flags2; - u8 rssi; + u8 data_offset; }; @@ -116,7 +116,7 @@ static int brcmf_proto_cdc_msg(struct brcmf_pub *drvr) len = CDC_MAX_MSG_SIZE; /* Send request */ - return brcmf_sdbrcm_bus_txctl(drvr->bus, (unsigned char *)&prot->msg, + return brcmf_sdbrcm_bus_txctl(drvr->dev, (unsigned char *)&prot->msg, len); } @@ -128,7 +128,7 @@ static int brcmf_proto_cdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len) brcmf_dbg(TRACE, "Enter\n"); do { - ret = brcmf_sdbrcm_bus_rxctl(drvr->bus, + ret = brcmf_sdbrcm_bus_rxctl(drvr->dev, (unsigned char *)&prot->msg, len + sizeof(struct brcmf_proto_cdc_dcmd)); if (ret < 0) @@ -280,7 +280,7 @@ brcmf_proto_dcmd(struct brcmf_pub *drvr, int ifidx, struct brcmf_dcmd *dcmd, struct brcmf_proto *prot = drvr->prot; int ret = -1; - if (drvr->busstate == BRCMF_BUS_DOWN) { + if (drvr->bus_if->state == BRCMF_BUS_DOWN) { brcmf_dbg(ERROR, "bus is down. we have nothing to do.\n"); return ret; } @@ -372,7 +372,7 @@ void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx, h->priority = (pktbuf->priority & BDC_PRIORITY_MASK); h->flags2 = 0; - h->rssi = 0; + h->data_offset = 0; BDC_SET_IF_IDX(h, ifidx); } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c index 40928e58b6a6..69f335aeb255 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c @@ -32,8 +32,6 @@ #define PKTFILTER_BUF_SIZE 2048 #define BRCMF_ARPOL_MODE 0xb /* agent|snoop|peer_autoreply */ -int brcmf_msg_level; - #define MSGTRACE_VERSION 1 #define BRCMF_PKT_FILTER_FIXED_LEN offsetof(struct brcmf_pkt_filter_le, u) @@ -85,19 +83,6 @@ brcmf_c_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen) return len; } -void brcmf_c_init(void) -{ - /* Init global variables at run-time, not as part of the declaration. - * This is required to support init/de-init of the driver. - * Initialization - * of globals as part of the declaration results in non-deterministic - * behaviour since the value of the globals may be different on the - * first time that the driver is initialized vs subsequent - * initializations. - */ - brcmf_msg_level = BRCMF_ERROR_VAL; -} - bool brcmf_c_prec_enq(struct brcmf_pub *drvr, struct pktq *q, struct sk_buff *pkt, int prec) { diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index 719fd9397eb6..2c3a99d6c9a6 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c @@ -43,7 +43,6 @@ #include "dhd_proto.h" #include "dhd_dbg.h" #include "wl_cfg80211.h" -#include "bcmchip.h" MODULE_AUTHOR("Broadcom Corporation"); MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN fullmac driver."); @@ -77,6 +76,7 @@ struct brcmf_info { }; /* Error bits */ +int brcmf_msg_level = BRCMF_ERROR_VAL; module_param(brcmf_msg_level, int, 0); int brcmf_ifname2idx(struct brcmf_info *drvr_priv, char *name) @@ -292,7 +292,7 @@ int brcmf_sendpkt(struct brcmf_pub *drvr, int ifidx, struct sk_buff *pktbuf) struct brcmf_info *drvr_priv = drvr->info; /* Reject if down */ - if (!drvr->up || (drvr->busstate == BRCMF_BUS_DOWN)) + if (!drvr->up || (drvr->bus_if->state == BRCMF_BUS_DOWN)) return -ENODEV; /* Update multicast statistic */ @@ -310,7 +310,7 @@ int brcmf_sendpkt(struct brcmf_pub *drvr, int ifidx, struct sk_buff *pktbuf) brcmf_proto_hdrpush(drvr, ifidx, pktbuf); /* Use bus module to send data frame */ - return brcmf_sdbrcm_bus_txdata(drvr->bus, pktbuf); + return brcmf_sdbrcm_bus_txdata(drvr->dev, pktbuf); } static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev) @@ -322,9 +322,11 @@ static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev) brcmf_dbg(TRACE, "Enter\n"); /* Reject if down */ - if (!drvr_priv->pub.up || (drvr_priv->pub.busstate == BRCMF_BUS_DOWN)) { - brcmf_dbg(ERROR, "xmit rejected pub.up=%d busstate=%d\n", - drvr_priv->pub.up, drvr_priv->pub.busstate); + if (!drvr_priv->pub.up || + (drvr_priv->pub.bus_if->state == BRCMF_BUS_DOWN)) { + brcmf_dbg(ERROR, "xmit rejected pub.up=%d state=%d\n", + drvr_priv->pub.up, + drvr_priv->pub.bus_if->state); netif_stop_queue(ndev); return -ENODEV; } @@ -397,26 +399,21 @@ static int brcmf_host_event(struct brcmf_info *drvr_priv, int *ifidx, return bcmerror; } -void brcmf_rx_frame(struct brcmf_pub *drvr, int ifidx, struct sk_buff *skb, - int numpkt) +void brcmf_rx_frame(struct brcmf_pub *drvr, int ifidx, + struct sk_buff_head *skb_list) { struct brcmf_info *drvr_priv = drvr->info; unsigned char *eth; uint len; void *data; - struct sk_buff *pnext, *save_pktbuf; - int i; + struct sk_buff *skb, *pnext; struct brcmf_if *ifp; struct brcmf_event_msg event; brcmf_dbg(TRACE, "Enter\n"); - save_pktbuf = skb; - - for (i = 0; skb && i < numpkt; i++, skb = pnext) { - - pnext = skb->next; - skb->next = NULL; + skb_queue_walk_safe(skb_list, skb, pnext) { + skb_unlink(skb, skb_list); /* Get the protocol, maintain skb around eth_type_trans() * The main reason for this hack is for the limitation of @@ -437,6 +434,12 @@ void brcmf_rx_frame(struct brcmf_pub *drvr, int ifidx, struct sk_buff *skb, if (ifp == NULL) ifp = drvr_priv->iflist[0]; + if (!ifp || !ifp->ndev || + ifp->ndev->reg_state != NETREG_REGISTERED) { + brcmu_pkt_buf_free_skb(skb); + continue; + } + skb->dev = ifp->ndev; skb->protocol = eth_type_trans(skb, skb->dev); @@ -605,9 +608,7 @@ static void brcmf_ethtool_get_drvinfo(struct net_device *ndev, sprintf(info->driver, KBUILD_MODNAME); sprintf(info->version, "%lu", drvr_priv->pub.drv_version); - sprintf(info->fw_version, "%s", BCM4329_FW_NAME); - sprintf(info->bus_info, "%s", - dev_name(brcmf_bus_get_device(drvr_priv->pub.bus))); + sprintf(info->bus_info, "%s", dev_name(drvr_priv->pub.dev)); } static struct ethtool_ops brcmf_ethtool_ops = { @@ -761,7 +762,7 @@ s32 brcmf_exec_dcmd(struct net_device *ndev, u32 cmd, void *arg, u32 len) buflen = min_t(uint, dcmd.len, BRCMF_DCMD_MAXLEN); /* send to dongle (must be up, and wl) */ - if ((drvr_priv->pub.busstate != BRCMF_BUS_DATA)) { + if ((drvr_priv->pub.bus_if->state != BRCMF_BUS_DATA)) { brcmf_dbg(ERROR, "DONGLE_DOWN\n"); err = -EIO; goto done; @@ -804,7 +805,7 @@ static int brcmf_netdev_stop(struct net_device *ndev) return 0; /* Set state and stop OS transmissions */ - drvr->up = 0; + drvr->up = false; netif_stop_queue(ndev); return 0; @@ -841,7 +842,7 @@ static int brcmf_netdev_open(struct net_device *ndev) } /* Allow transmit calls */ netif_start_queue(ndev); - drvr_priv->pub.up = 1; + drvr_priv->pub.up = true; if (brcmf_cfg80211_up(drvr_priv->pub.config)) { brcmf_dbg(ERROR, "failed to bring up cfg80211\n"); return -1; @@ -940,7 +941,8 @@ void brcmf_del_if(struct brcmf_info *drvr_priv, int ifidx) } } -struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus, uint bus_hdrlen) +struct brcmf_pub *brcmf_attach(struct brcmf_sdio *bus, uint bus_hdrlen, + struct device *dev) { struct brcmf_info *drvr_priv = NULL; @@ -959,6 +961,8 @@ struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus, uint bus_hdrlen) /* Link to bus module */ drvr_priv->pub.bus = bus; drvr_priv->pub.hdrlen = bus_hdrlen; + drvr_priv->pub.bus_if = dev_get_drvdata(dev); + drvr_priv->pub.dev = dev; /* Attach and link in the protocol */ if (brcmf_proto_attach(&drvr_priv->pub) != 0) { @@ -988,14 +992,14 @@ int brcmf_bus_start(struct brcmf_pub *drvr) brcmf_dbg(TRACE, "\n"); /* Bring up the bus */ - ret = brcmf_sdbrcm_bus_init(&drvr_priv->pub); + ret = brcmf_sdbrcm_bus_init(drvr_priv->pub.dev); if (ret != 0) { brcmf_dbg(ERROR, "brcmf_sdbrcm_bus_init failed %d\n", ret); return ret; } /* If bus is not ready, can't come up */ - if (drvr_priv->pub.busstate != BRCMF_BUS_DATA) { + if (drvr_priv->pub.bus_if->state != BRCMF_BUS_DATA) { brcmf_dbg(ERROR, "failed bus is not ready\n"); return -ENODEV; } @@ -1077,10 +1081,7 @@ int brcmf_net_attach(struct brcmf_pub *drvr, int ifidx) /* attach to cfg80211 for primary interface */ if (!ifidx) { - drvr->config = - brcmf_cfg80211_attach(ndev, - brcmf_bus_get_device(drvr->bus), - drvr); + drvr->config = brcmf_cfg80211_attach(ndev, drvr->dev, drvr); if (drvr->config == NULL) { brcmf_dbg(ERROR, "wl_cfg80211_attach failed\n"); goto fail; @@ -1114,7 +1115,7 @@ static void brcmf_bus_detach(struct brcmf_pub *drvr) brcmf_proto_stop(&drvr_priv->pub); /* Stop the bus module */ - brcmf_sdbrcm_bus_stop(drvr_priv->pub.bus); + brcmf_sdbrcm_bus_stop(drvr_priv->pub.dev); } } } @@ -1148,34 +1149,6 @@ void brcmf_detach(struct brcmf_pub *drvr) } } -static void __exit brcmf_module_cleanup(void) -{ - brcmf_dbg(TRACE, "Enter\n"); - - brcmf_bus_unregister(); -} - -static int __init brcmf_module_init(void) -{ - int error; - - brcmf_dbg(TRACE, "Enter\n"); - - error = brcmf_bus_register(); - - if (error) { - brcmf_dbg(ERROR, "brcmf_bus_register failed\n"); - goto failed; - } - return 0; - -failed: - return -EINVAL; -} - -module_init(brcmf_module_init); -module_exit(brcmf_module_cleanup); - int brcmf_os_proto_block(struct brcmf_pub *drvr) { struct brcmf_info *drvr_priv = drvr->info; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index 22913af26db8..43ba0dd48354 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -91,7 +91,6 @@ struct rte_console { #include "dhd_bus.h" #include "dhd_proto.h" #include "dhd_dbg.h" -#include <bcmchip.h> #define TXQLEN 2048 /* bulk tx queue length */ #define TXHI (TXQLEN - 256) /* turn on flow control above TXHI */ @@ -310,6 +309,11 @@ struct rte_console { /* Flags for SDH calls */ #define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED) +#define BRCMFMAC_FW_NAME "brcm/brcmfmac.bin" +#define BRCMFMAC_NV_NAME "brcm/brcmfmac.txt" +MODULE_FIRMWARE(BRCMFMAC_FW_NAME); +MODULE_FIRMWARE(BRCMFMAC_NV_NAME); + /* * Conversion of 802.1D priority to precedence level */ @@ -445,7 +449,7 @@ struct sdpcm_shared_le { /* misc chip info needed by some of the routines */ /* Private data for SDIO bus interaction */ -struct brcmf_bus { +struct brcmf_sdio { struct brcmf_pub *drvr; struct brcmf_sdio_dev *sdiodev; /* sdio device handler */ @@ -562,9 +566,7 @@ struct brcmf_bus { struct semaphore sdsem; - const char *fw_name; const struct firmware *firmware; - const char *nv_name; u32 fw_ptr; }; @@ -602,7 +604,7 @@ static void pkt_align(struct sk_buff *p, int len, int align) } /* To check if there's window offered */ -static bool data_ok(struct brcmf_bus *bus) +static bool data_ok(struct brcmf_sdio *bus) { return (u8)(bus->tx_max - bus->tx_seq) != 0 && ((u8)(bus->tx_max - bus->tx_seq) & 0x80) == 0; @@ -613,7 +615,7 @@ static bool data_ok(struct brcmf_bus *bus) * adresses on the 32 bit backplane bus. */ static void -r_sdreg32(struct brcmf_bus *bus, u32 *regvar, u32 reg_offset, u32 *retryvar) +r_sdreg32(struct brcmf_sdio *bus, u32 *regvar, u32 reg_offset, u32 *retryvar) { u8 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV); *retryvar = 0; @@ -633,7 +635,7 @@ r_sdreg32(struct brcmf_bus *bus, u32 *regvar, u32 reg_offset, u32 *retryvar) } static void -w_sdreg32(struct brcmf_bus *bus, u32 regval, u32 reg_offset, u32 *retryvar) +w_sdreg32(struct brcmf_sdio *bus, u32 regval, u32 reg_offset, u32 *retryvar) { u8 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV); *retryvar = 0; @@ -658,14 +660,14 @@ w_sdreg32(struct brcmf_bus *bus, u32 regval, u32 reg_offset, u32 *retryvar) /* Packet free applicable unconditionally for sdio and sdspi. * Conditional if bufpool was present for gspi bus. */ -static void brcmf_sdbrcm_pktfree2(struct brcmf_bus *bus, struct sk_buff *pkt) +static void brcmf_sdbrcm_pktfree2(struct brcmf_sdio *bus, struct sk_buff *pkt) { if (bus->usebufpool) brcmu_pkt_buf_free_skb(pkt); } /* Turn backplane clock on or off */ -static int brcmf_sdbrcm_htclk(struct brcmf_bus *bus, bool on, bool pendok) +static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok) { int err; u8 clkctl, clkreq, devctl; @@ -786,7 +788,7 @@ static int brcmf_sdbrcm_htclk(struct brcmf_bus *bus, bool on, bool pendok) } /* Change idle/active SD state */ -static int brcmf_sdbrcm_sdclk(struct brcmf_bus *bus, bool on) +static int brcmf_sdbrcm_sdclk(struct brcmf_sdio *bus, bool on) { brcmf_dbg(TRACE, "Enter\n"); @@ -799,7 +801,7 @@ static int brcmf_sdbrcm_sdclk(struct brcmf_bus *bus, bool on) } /* Transition SD and backplane clock readiness */ -static int brcmf_sdbrcm_clkctl(struct brcmf_bus *bus, uint target, bool pendok) +static int brcmf_sdbrcm_clkctl(struct brcmf_sdio *bus, uint target, bool pendok) { #ifdef BCMDBG uint oldstate = bus->clkstate; @@ -855,7 +857,7 @@ static int brcmf_sdbrcm_clkctl(struct brcmf_bus *bus, uint target, bool pendok) return 0; } -static int brcmf_sdbrcm_bussleep(struct brcmf_bus *bus, bool sleep) +static int brcmf_sdbrcm_bussleep(struct brcmf_sdio *bus, bool sleep) { uint retries = 0; @@ -927,13 +929,13 @@ static int brcmf_sdbrcm_bussleep(struct brcmf_bus *bus, bool sleep) return 0; } -static void bus_wake(struct brcmf_bus *bus) +static void bus_wake(struct brcmf_sdio *bus) { if (bus->sleeping) brcmf_sdbrcm_bussleep(bus, false); } -static u32 brcmf_sdbrcm_hostmail(struct brcmf_bus *bus) +static u32 brcmf_sdbrcm_hostmail(struct brcmf_sdio *bus) { u32 intstatus = 0; u32 hmb_data; @@ -1009,7 +1011,7 @@ static u32 brcmf_sdbrcm_hostmail(struct brcmf_bus *bus) return intstatus; } -static void brcmf_sdbrcm_rxfail(struct brcmf_bus *bus, bool abort, bool rtx) +static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx) { uint retries = 0; u16 lastrbc; @@ -1066,11 +1068,11 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_bus *bus, bool abort, bool rtx) /* If we can't reach the device, signal failure */ if (err || brcmf_sdcard_regfail(bus->sdiodev)) - bus->drvr->busstate = BRCMF_BUS_DOWN; + bus->drvr->bus_if->state = BRCMF_BUS_DOWN; } /* copy a buffer into a pkt buffer chain */ -static uint brcmf_sdbrcm_glom_from_buf(struct brcmf_bus *bus, uint len) +static uint brcmf_sdbrcm_glom_from_buf(struct brcmf_sdio *bus, uint len) { uint n, ret = 0; struct sk_buff *p; @@ -1093,7 +1095,7 @@ static uint brcmf_sdbrcm_glom_from_buf(struct brcmf_bus *bus, uint len) } /* return total length of buffer chain */ -static uint brcmf_sdbrcm_glom_len(struct brcmf_bus *bus) +static uint brcmf_sdbrcm_glom_len(struct brcmf_sdio *bus) { struct sk_buff *p; uint total; @@ -1104,7 +1106,7 @@ static uint brcmf_sdbrcm_glom_len(struct brcmf_bus *bus) return total; } -static void brcmf_sdbrcm_free_glom(struct brcmf_bus *bus) +static void brcmf_sdbrcm_free_glom(struct brcmf_sdio *bus) { struct sk_buff *cur, *next; @@ -1114,13 +1116,13 @@ static void brcmf_sdbrcm_free_glom(struct brcmf_bus *bus) } } -static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq) +static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) { u16 dlen, totlen; u8 *dptr, num = 0; u16 sublen, check; - struct sk_buff *pfirst, *plast, *pnext, *save_pfirst; + struct sk_buff *pfirst, *pnext; int errcode; u8 chan, seq, doff, sfdoff; @@ -1137,7 +1139,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq) /* If there's a descriptor, generate the packet chain */ if (bus->glomd) { - pfirst = plast = pnext = NULL; + pfirst = pnext = NULL; dlen = (u16) (bus->glomd->len); dptr = bus->glomd->data; if (!dlen || (dlen & 1)) { @@ -1228,17 +1230,14 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq) * packet and and copy into the chain. */ if (usechain) { - errcode = brcmf_sdcard_recv_buf(bus->sdiodev, + errcode = brcmf_sdcard_recv_chain(bus->sdiodev, bus->sdiodev->sbwad, - SDIO_FUNC_2, - F2SYNC, (u8 *) pfirst->data, dlen, - pfirst); + SDIO_FUNC_2, F2SYNC, &bus->glom); } else if (bus->dataptr) { errcode = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad, - SDIO_FUNC_2, - F2SYNC, bus->dataptr, dlen, - NULL); + SDIO_FUNC_2, F2SYNC, + bus->dataptr, dlen); sublen = (u16) brcmf_sdbrcm_glom_from_buf(bus, dlen); if (sublen != dlen) { brcmf_dbg(ERROR, "FAILED TO COPY, dlen %d sublen %d\n", @@ -1338,10 +1337,14 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq) /* Remove superframe header, remember offset */ skb_pull(pfirst, doff); sfdoff = doff; + num = 0; /* Validate all the subframe headers */ - for (num = 0, pnext = pfirst; pnext && !errcode; - num++, pnext = pnext->next) { + skb_queue_walk(&bus->glom, pnext) { + /* leave when invalid subframe is found */ + if (errcode) + break; + dptr = (u8 *) (pnext->data); dlen = (u16) (pnext->len); sublen = get_unaligned_le16(dptr); @@ -1374,6 +1377,8 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq) num, doff, sublen, SDPCM_HDRLEN); errcode = -1; } + /* increase the subframe count */ + num++; } if (errcode) { @@ -1394,13 +1399,8 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq) } /* Basic SD framing looks ok - process each packet (header) */ - save_pfirst = pfirst; - plast = NULL; - - for (num = 0; pfirst; rxseq++, pfirst = pnext) { - pnext = pfirst->next; - pfirst->next = NULL; + skb_queue_walk_safe(&bus->glom, pfirst, pnext) { dptr = (u8 *) (pfirst->data); sublen = get_unaligned_le16(dptr); chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); @@ -1420,6 +1420,8 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq) bus->rx_badseq++; rxseq = seq; } + rxseq++; + #ifdef BCMDBG if (BRCMF_BYTES_ON() && BRCMF_DATA_ON()) { printk(KERN_DEBUG "Rx Subframe Data:\n"); @@ -1432,36 +1434,22 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq) skb_pull(pfirst, doff); if (pfirst->len == 0) { + skb_unlink(pfirst, &bus->glom); brcmu_pkt_buf_free_skb(pfirst); - if (plast) - plast->next = pnext; - else - save_pfirst = pnext; - continue; } else if (brcmf_proto_hdrpull(bus->drvr, &ifidx, pfirst) != 0) { brcmf_dbg(ERROR, "rx protocol error\n"); bus->drvr->rx_errors++; + skb_unlink(pfirst, &bus->glom); brcmu_pkt_buf_free_skb(pfirst); - if (plast) - plast->next = pnext; - else - save_pfirst = pnext; - continue; } - /* this packet will go up, link back into - chain and count it */ - pfirst->next = pnext; - plast = pfirst; - num++; - #ifdef BCMDBG if (BRCMF_GLOM_ON()) { brcmf_dbg(GLOM, "subframe %d to stack, %p (%p/%d) nxt/lnk %p/%p\n", - num, pfirst, pfirst->data, + bus->glom.qlen, pfirst, pfirst->data, pfirst->len, pfirst->next, pfirst->prev); print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, @@ -1470,19 +1458,20 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq) } #endif /* BCMDBG */ } - if (num) { + /* sent any remaining packets up */ + if (bus->glom.qlen) { up(&bus->sdsem); - brcmf_rx_frame(bus->drvr, ifidx, save_pfirst, num); + brcmf_rx_frame(bus->drvr, ifidx, &bus->glom); down(&bus->sdsem); } bus->rxglomframes++; - bus->rxglompkts += num; + bus->rxglompkts += bus->glom.qlen; } return num; } -static int brcmf_sdbrcm_dcmd_resp_wait(struct brcmf_bus *bus, uint *condition, +static int brcmf_sdbrcm_dcmd_resp_wait(struct brcmf_sdio *bus, uint *condition, bool *pending) { DECLARE_WAITQUEUE(wait, current); @@ -1504,7 +1493,7 @@ static int brcmf_sdbrcm_dcmd_resp_wait(struct brcmf_bus *bus, uint *condition, return timeout; } -static int brcmf_sdbrcm_dcmd_resp_wake(struct brcmf_bus *bus) +static int brcmf_sdbrcm_dcmd_resp_wake(struct brcmf_sdio *bus) { if (waitqueue_active(&bus->dcmd_resp_wait)) wake_up_interruptible(&bus->dcmd_resp_wait); @@ -1512,7 +1501,7 @@ static int brcmf_sdbrcm_dcmd_resp_wake(struct brcmf_bus *bus) return 0; } static void -brcmf_sdbrcm_read_control(struct brcmf_bus *bus, u8 *hdr, uint len, uint doff) +brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff) { uint rdlen, pad; @@ -1570,8 +1559,7 @@ brcmf_sdbrcm_read_control(struct brcmf_bus *bus, u8 *hdr, uint len, uint doff) sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad, SDIO_FUNC_2, - F2SYNC, (bus->rxctl + BRCMF_FIRSTREAD), rdlen, - NULL); + F2SYNC, (bus->rxctl + BRCMF_FIRSTREAD), rdlen); bus->f2rxdata++; /* Control frame failures need retransmission */ @@ -1602,7 +1590,7 @@ done: } /* Pad read to blocksize for efficiency */ -static void brcmf_pad(struct brcmf_bus *bus, u16 *pad, u16 *rdlen) +static void brcmf_pad(struct brcmf_sdio *bus, u16 *pad, u16 *rdlen) { if (bus->roundup && bus->blocksize && *rdlen > bus->blocksize) { *pad = bus->blocksize - (*rdlen % bus->blocksize); @@ -1615,7 +1603,7 @@ static void brcmf_pad(struct brcmf_bus *bus, u16 *pad, u16 *rdlen) } static void -brcmf_alloc_pkt_and_read(struct brcmf_bus *bus, u16 rdlen, +brcmf_alloc_pkt_and_read(struct brcmf_sdio *bus, u16 rdlen, struct sk_buff **pkt, u8 **rxbuf) { int sdret; /* Return code from calls */ @@ -1627,9 +1615,8 @@ brcmf_alloc_pkt_and_read(struct brcmf_bus *bus, u16 rdlen, pkt_align(*pkt, rdlen, BRCMF_SDALIGN); *rxbuf = (u8 *) ((*pkt)->data); /* Read the entire frame */ - sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad, - SDIO_FUNC_2, F2SYNC, - *rxbuf, rdlen, *pkt); + sdret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad, + SDIO_FUNC_2, F2SYNC, *pkt); bus->f2rxdata++; if (sdret < 0) { @@ -1648,7 +1635,7 @@ brcmf_alloc_pkt_and_read(struct brcmf_bus *bus, u16 rdlen, /* Checks the header */ static int -brcmf_check_rxbuf(struct brcmf_bus *bus, struct sk_buff *pkt, u8 *rxbuf, +brcmf_check_rxbuf(struct brcmf_sdio *bus, struct sk_buff *pkt, u8 *rxbuf, u8 rxseq, u16 nextlen, u16 *len) { u16 check; @@ -1704,7 +1691,7 @@ fail: /* Return true if there may be more frames to read */ static uint -brcmf_sdbrcm_readframes(struct brcmf_bus *bus, uint maxframes, bool *finished) +brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished) { u16 len, check; /* Extracted hardware header fields */ u8 chan, seq, doff; /* Extracted software header fields */ @@ -1727,7 +1714,8 @@ brcmf_sdbrcm_readframes(struct brcmf_bus *bus, uint maxframes, bool *finished) *finished = false; for (rxseq = bus->rx_seq, rxleft = maxframes; - !bus->rxskip && rxleft && bus->drvr->busstate != BRCMF_BUS_DOWN; + !bus->rxskip && rxleft && + bus->drvr->bus_if->state != BRCMF_BUS_DOWN; rxseq++, rxleft--) { /* Handle glomming separately */ @@ -1857,7 +1845,7 @@ brcmf_sdbrcm_readframes(struct brcmf_bus *bus, uint maxframes, bool *finished) /* Read frame header (hardware and software) */ sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad, SDIO_FUNC_2, F2SYNC, bus->rxhdr, - BRCMF_FIRSTREAD, NULL); + BRCMF_FIRSTREAD); bus->f2rxhdrs++; if (sdret < 0) { @@ -2006,9 +1994,8 @@ brcmf_sdbrcm_readframes(struct brcmf_bus *bus, uint maxframes, bool *finished) pkt_align(pkt, rdlen, BRCMF_SDALIGN); /* Read the remaining frame data */ - sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad, - SDIO_FUNC_2, F2SYNC, ((u8 *) (pkt->data)), - rdlen, pkt); + sdret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad, + SDIO_FUNC_2, F2SYNC, pkt); bus->f2rxdata++; if (sdret < 0) { @@ -2075,7 +2062,7 @@ deliver: /* Unlock during rx call */ up(&bus->sdsem); - brcmf_rx_frame(bus->drvr, ifidx, pkt, 1); + brcmf_rx_packet(bus->drvr, ifidx, pkt); down(&bus->sdsem); } rxcount = maxframes - rxleft; @@ -2095,16 +2082,8 @@ deliver: return rxcount; } -static int -brcmf_sdbrcm_send_buf(struct brcmf_bus *bus, u32 addr, uint fn, uint flags, - u8 *buf, uint nbytes, struct sk_buff *pkt) -{ - return brcmf_sdcard_send_buf - (bus->sdiodev, addr, fn, flags, buf, nbytes, pkt); -} - static void -brcmf_sdbrcm_wait_for_event(struct brcmf_bus *bus, bool *lockvar) +brcmf_sdbrcm_wait_for_event(struct brcmf_sdio *bus, bool *lockvar) { up(&bus->sdsem); wait_event_interruptible_timeout(bus->ctrl_wait, @@ -2114,7 +2093,7 @@ brcmf_sdbrcm_wait_for_event(struct brcmf_bus *bus, bool *lockvar) } static void -brcmf_sdbrcm_wait_event_wakeup(struct brcmf_bus *bus) +brcmf_sdbrcm_wait_event_wakeup(struct brcmf_sdio *bus) { if (waitqueue_active(&bus->ctrl_wait)) wake_up_interruptible(&bus->ctrl_wait); @@ -2123,7 +2102,7 @@ brcmf_sdbrcm_wait_event_wakeup(struct brcmf_bus *bus) /* Writes a HW/SW header into the packet and sends it. */ /* Assumes: (a) header space already there, (b) caller holds lock */ -static int brcmf_sdbrcm_txpkt(struct brcmf_bus *bus, struct sk_buff *pkt, +static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt, uint chan, bool free_pkt) { int ret; @@ -2212,9 +2191,8 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_bus *bus, struct sk_buff *pkt, if (len & (ALIGNMENT - 1)) len = roundup(len, ALIGNMENT); - ret = brcmf_sdbrcm_send_buf(bus, bus->sdiodev->sbwad, - SDIO_FUNC_2, F2SYNC, frame, - len, pkt); + ret = brcmf_sdcard_send_pkt(bus->sdiodev, bus->sdiodev->sbwad, + SDIO_FUNC_2, F2SYNC, pkt); bus->f2txdata++; if (ret < 0) { @@ -2261,7 +2239,7 @@ done: return ret; } -static uint brcmf_sdbrcm_sendfromq(struct brcmf_bus *bus, uint maxframes) +static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes) { struct sk_buff *pkt; u32 intstatus = 0; @@ -2309,14 +2287,14 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_bus *bus, uint maxframes) } /* Deflow-control stack if needed */ - if (drvr->up && (drvr->busstate == BRCMF_BUS_DATA) && + if (drvr->up && (drvr->bus_if->state == BRCMF_BUS_DATA) && drvr->txoff && (pktq_len(&bus->txq) < TXLOW)) brcmf_txflowcontrol(drvr, 0, OFF); return cnt; } -static bool brcmf_sdbrcm_dpc(struct brcmf_bus *bus) +static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) { u32 intstatus, newstatus = 0; uint retries = 0; @@ -2344,7 +2322,7 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_bus *bus) SBSDIO_DEVICE_CTL, &err); if (err) { brcmf_dbg(ERROR, "error reading DEVCTL: %d\n", err); - bus->drvr->busstate = BRCMF_BUS_DOWN; + bus->drvr->bus_if->state = BRCMF_BUS_DOWN; } #endif /* BCMDBG */ @@ -2354,7 +2332,7 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_bus *bus) if (err) { brcmf_dbg(ERROR, "error reading CSR: %d\n", err); - bus->drvr->busstate = BRCMF_BUS_DOWN; + bus->drvr->bus_if->state = BRCMF_BUS_DOWN; } brcmf_dbg(INFO, "DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n", @@ -2367,7 +2345,7 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_bus *bus) if (err) { brcmf_dbg(ERROR, "error reading DEVCTL: %d\n", err); - bus->drvr->busstate = BRCMF_BUS_DOWN; + bus->drvr->bus_if->state = BRCMF_BUS_DOWN; } devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, @@ -2375,7 +2353,7 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_bus *bus) if (err) { brcmf_dbg(ERROR, "error writing DEVCTL: %d\n", err); - bus->drvr->busstate = BRCMF_BUS_DOWN; + bus->drvr->bus_if->state = BRCMF_BUS_DOWN; } bus->clkstate = CLK_AVAIL; } else { @@ -2477,9 +2455,9 @@ clkwait: (bus->clkstate == CLK_AVAIL)) { int ret, i; - ret = brcmf_sdbrcm_send_buf(bus, bus->sdiodev->sbwad, + ret = brcmf_sdcard_send_buf(bus->sdiodev, bus->sdiodev->sbwad, SDIO_FUNC_2, F2SYNC, (u8 *) bus->ctrl_frame_buf, - (u32) bus->ctrl_frame_len, NULL); + (u32) bus->ctrl_frame_len); if (ret < 0) { /* On failure, abort the command and @@ -2531,11 +2509,11 @@ clkwait: else await next interrupt */ /* On failed register access, all bets are off: no resched or interrupts */ - if ((bus->drvr->busstate == BRCMF_BUS_DOWN) || + if ((bus->drvr->bus_if->state == BRCMF_BUS_DOWN) || brcmf_sdcard_regfail(bus->sdiodev)) { brcmf_dbg(ERROR, "failed backplane access over SDIO, halting operation %d\n", brcmf_sdcard_regfail(bus->sdiodev)); - bus->drvr->busstate = BRCMF_BUS_DOWN; + bus->drvr->bus_if->state = BRCMF_BUS_DOWN; bus->intstatus = 0; } else if (bus->clkstate == CLK_PENDING) { brcmf_dbg(INFO, "rescheduled due to CLK_PENDING awaiting I_CHIPACTIVE interrupt\n"); @@ -2562,7 +2540,7 @@ clkwait: static int brcmf_sdbrcm_dpc_thread(void *data) { - struct brcmf_bus *bus = (struct brcmf_bus *) data; + struct brcmf_sdio *bus = (struct brcmf_sdio *) data; allow_signal(SIGTERM); /* Run until signal received */ @@ -2572,12 +2550,12 @@ static int brcmf_sdbrcm_dpc_thread(void *data) if (!wait_for_completion_interruptible(&bus->dpc_wait)) { /* Call bus dpc unless it indicated down (then clean stop) */ - if (bus->drvr->busstate != BRCMF_BUS_DOWN) { + if (bus->drvr->bus_if->state != BRCMF_BUS_DOWN) { if (brcmf_sdbrcm_dpc(bus)) complete(&bus->dpc_wait); } else { /* after stopping the bus, exit thread */ - brcmf_sdbrcm_bus_stop(bus); + brcmf_sdbrcm_bus_stop(bus->sdiodev->dev); bus->dpc_tsk = NULL; break; } @@ -2587,10 +2565,13 @@ static int brcmf_sdbrcm_dpc_thread(void *data) return 0; } -int brcmf_sdbrcm_bus_txdata(struct brcmf_bus *bus, struct sk_buff *pkt) +int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt) { int ret = -EBADE; uint datalen, prec; + struct brcmf_bus *bus_if = dev_get_drvdata(dev); + struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv; + struct brcmf_sdio *bus = sdiodev->bus; brcmf_dbg(TRACE, "Enter\n"); @@ -2638,7 +2619,7 @@ int brcmf_sdbrcm_bus_txdata(struct brcmf_bus *bus, struct sk_buff *pkt) } static int -brcmf_sdbrcm_membytes(struct brcmf_bus *bus, bool write, u32 address, u8 *data, +brcmf_sdbrcm_membytes(struct brcmf_sdio *bus, bool write, u32 address, u8 *data, uint size) { int bcmerror = 0; @@ -2699,7 +2680,7 @@ xfer_done: #ifdef BCMDBG #define CONSOLE_LINE_MAX 192 -static int brcmf_sdbrcm_readconsole(struct brcmf_bus *bus) +static int brcmf_sdbrcm_readconsole(struct brcmf_sdio *bus) { struct brcmf_console *c = &bus->console; u8 line[CONSOLE_LINE_MAX], ch; @@ -2776,14 +2757,14 @@ break2: } #endif /* BCMDBG */ -static int brcmf_tx_frame(struct brcmf_bus *bus, u8 *frame, u16 len) +static int brcmf_tx_frame(struct brcmf_sdio *bus, u8 *frame, u16 len) { int i; int ret; bus->ctrl_frame_stat = false; - ret = brcmf_sdbrcm_send_buf(bus, bus->sdiodev->sbwad, - SDIO_FUNC_2, F2SYNC, frame, len, NULL); + ret = brcmf_sdcard_send_buf(bus->sdiodev, bus->sdiodev->sbwad, + SDIO_FUNC_2, F2SYNC, frame, len); if (ret < 0) { /* On failure, abort the command and terminate the frame */ @@ -2819,7 +2800,7 @@ static int brcmf_tx_frame(struct brcmf_bus *bus, u8 *frame, u16 len) } int -brcmf_sdbrcm_bus_txctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen) +brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) { u8 *frame; u16 len; @@ -2827,6 +2808,9 @@ brcmf_sdbrcm_bus_txctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen) uint retries = 0; u8 doff = 0; int ret = -1; + struct brcmf_bus *bus_if = dev_get_drvdata(dev); + struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv; + struct brcmf_sdio *bus = sdiodev->bus; brcmf_dbg(TRACE, "Enter\n"); @@ -2934,11 +2918,14 @@ brcmf_sdbrcm_bus_txctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen) } int -brcmf_sdbrcm_bus_rxctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen) +brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen) { int timeleft; uint rxlen = 0; bool pending; + struct brcmf_bus *bus_if = dev_get_drvdata(dev); + struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv; + struct brcmf_sdio *bus = sdiodev->bus; brcmf_dbg(TRACE, "Enter\n"); @@ -2971,7 +2958,7 @@ brcmf_sdbrcm_bus_rxctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen) return rxlen ? (int)rxlen : -ETIMEDOUT; } -static int brcmf_sdbrcm_downloadvars(struct brcmf_bus *bus, void *arg, int len) +static int brcmf_sdbrcm_downloadvars(struct brcmf_sdio *bus, void *arg, int len) { int bcmerror = 0; @@ -3004,7 +2991,7 @@ err: return bcmerror; } -static int brcmf_sdbrcm_write_vars(struct brcmf_bus *bus) +static int brcmf_sdbrcm_write_vars(struct brcmf_sdio *bus) { int bcmerror = 0; u32 varsize; @@ -3091,7 +3078,7 @@ static int brcmf_sdbrcm_write_vars(struct brcmf_bus *bus) return bcmerror; } -static int brcmf_sdbrcm_download_state(struct brcmf_bus *bus, bool enter) +static int brcmf_sdbrcm_download_state(struct brcmf_sdio *bus, bool enter) { uint retries; int bcmerror = 0; @@ -3134,13 +3121,13 @@ static int brcmf_sdbrcm_download_state(struct brcmf_bus *bus, bool enter) /* Allow HT Clock now that the ARM is running. */ bus->alp_only = false; - bus->drvr->busstate = BRCMF_BUS_LOAD; + bus->drvr->bus_if->state = BRCMF_BUS_LOAD; } fail: return bcmerror; } -static int brcmf_sdbrcm_get_image(char *buf, int len, struct brcmf_bus *bus) +static int brcmf_sdbrcm_get_image(char *buf, int len, struct brcmf_sdio *bus) { if (bus->firmware->size < bus->fw_ptr + len) len = bus->firmware->size - bus->fw_ptr; @@ -3150,10 +3137,7 @@ static int brcmf_sdbrcm_get_image(char *buf, int len, struct brcmf_bus *bus) return len; } -MODULE_FIRMWARE(BCM4329_FW_NAME); -MODULE_FIRMWARE(BCM4329_NV_NAME); - -static int brcmf_sdbrcm_download_code_file(struct brcmf_bus *bus) +static int brcmf_sdbrcm_download_code_file(struct brcmf_sdio *bus) { int offset = 0; uint len; @@ -3162,8 +3146,7 @@ static int brcmf_sdbrcm_download_code_file(struct brcmf_bus *bus) brcmf_dbg(INFO, "Enter\n"); - bus->fw_name = BCM4329_FW_NAME; - ret = request_firmware(&bus->firmware, bus->fw_name, + ret = request_firmware(&bus->firmware, BRCMFMAC_FW_NAME, &bus->sdiodev->func[2]->dev); if (ret) { brcmf_dbg(ERROR, "Fail to request firmware %d\n", ret); @@ -3253,15 +3236,14 @@ static uint brcmf_process_nvram_vars(char *varbuf, uint len) return buf_len; } -static int brcmf_sdbrcm_download_nvram(struct brcmf_bus *bus) +static int brcmf_sdbrcm_download_nvram(struct brcmf_sdio *bus) { uint len; char *memblock = NULL; char *bufp; int ret; - bus->nv_name = BCM4329_NV_NAME; - ret = request_firmware(&bus->firmware, bus->nv_name, + ret = request_firmware(&bus->firmware, BRCMFMAC_NV_NAME, &bus->sdiodev->func[2]->dev); if (ret) { brcmf_dbg(ERROR, "Fail to request nvram %d\n", ret); @@ -3301,7 +3283,7 @@ err: return ret; } -static int _brcmf_sdbrcm_download_firmware(struct brcmf_bus *bus) +static int _brcmf_sdbrcm_download_firmware(struct brcmf_sdio *bus) { int bcmerror = -1; @@ -3334,7 +3316,7 @@ err: } static bool -brcmf_sdbrcm_download_firmware(struct brcmf_bus *bus) +brcmf_sdbrcm_download_firmware(struct brcmf_sdio *bus) { bool ret; @@ -3348,12 +3330,15 @@ brcmf_sdbrcm_download_firmware(struct brcmf_bus *bus) return ret; } -void brcmf_sdbrcm_bus_stop(struct brcmf_bus *bus) +void brcmf_sdbrcm_bus_stop(struct device *dev) { u32 local_hostintmask; u8 saveclk; uint retries; int err; + struct brcmf_bus *bus_if = dev_get_drvdata(dev); + struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv; + struct brcmf_sdio *bus = sdiodev->bus; brcmf_dbg(TRACE, "Enter\n"); @@ -3382,7 +3367,7 @@ void brcmf_sdbrcm_bus_stop(struct brcmf_bus *bus) bus->hostintmask = 0; /* Change our idea of bus state */ - bus->drvr->busstate = BRCMF_BUS_DOWN; + bus->drvr->bus_if->state = BRCMF_BUS_DOWN; /* Force clocks on backplane to be sure F2 interrupt propagates */ saveclk = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, @@ -3426,9 +3411,11 @@ void brcmf_sdbrcm_bus_stop(struct brcmf_bus *bus) up(&bus->sdsem); } -int brcmf_sdbrcm_bus_init(struct brcmf_pub *drvr) +int brcmf_sdbrcm_bus_init(struct device *dev) { - struct brcmf_bus *bus = drvr->bus; + struct brcmf_bus *bus_if = dev_get_drvdata(dev); + struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv; + struct brcmf_sdio *bus = sdiodev->bus; unsigned long timeout; uint retries = 0; u8 ready, enable; @@ -3438,7 +3425,7 @@ int brcmf_sdbrcm_bus_init(struct brcmf_pub *drvr) brcmf_dbg(TRACE, "Enter\n"); /* try to download image and nvram to the dongle */ - if (drvr->busstate == BRCMF_BUS_DOWN) { + if (bus_if->state == BRCMF_BUS_DOWN) { if (!(brcmf_sdbrcm_download_firmware(bus))) return -1; } @@ -3504,7 +3491,7 @@ int brcmf_sdbrcm_bus_init(struct brcmf_pub *drvr) SBSDIO_WATERMARK, 8, &err); /* Set bus state according to enable result */ - drvr->busstate = BRCMF_BUS_DATA; + bus_if->state = BRCMF_BUS_DATA; } else { @@ -3519,7 +3506,7 @@ int brcmf_sdbrcm_bus_init(struct brcmf_pub *drvr) SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err); /* If we didn't come up, turn off backplane clock */ - if (drvr->busstate != BRCMF_BUS_DATA) + if (bus_if->state != BRCMF_BUS_DATA) brcmf_sdbrcm_clkctl(bus, CLK_NONE, false); exit: @@ -3530,7 +3517,7 @@ exit: void brcmf_sdbrcm_isr(void *arg) { - struct brcmf_bus *bus = (struct brcmf_bus *) arg; + struct brcmf_sdio *bus = (struct brcmf_sdio *) arg; brcmf_dbg(TRACE, "Enter\n"); @@ -3539,7 +3526,7 @@ void brcmf_sdbrcm_isr(void *arg) return; } - if (bus->drvr->busstate == BRCMF_BUS_DOWN) { + if (bus->drvr->bus_if->state == BRCMF_BUS_DOWN) { brcmf_dbg(ERROR, "bus is down. we have nothing to do\n"); return; } @@ -3562,14 +3549,14 @@ void brcmf_sdbrcm_isr(void *arg) complete(&bus->dpc_wait); } -static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_pub *drvr) +static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus) { - struct brcmf_bus *bus; +#ifdef BCMDBG + struct brcmf_bus *bus_if = dev_get_drvdata(bus->sdiodev->dev); +#endif /* BCMDBG */ brcmf_dbg(TIMER, "Enter\n"); - bus = drvr->bus; - /* Ignore the timer if simulating bus down */ if (bus->sleeping) return false; @@ -3613,7 +3600,8 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_pub *drvr) } #ifdef BCMDBG /* Poll for console output periodically */ - if (drvr->busstate == BRCMF_BUS_DATA && bus->console_interval != 0) { + if (bus_if->state == BRCMF_BUS_DATA && + bus->console_interval != 0) { bus->console.count += BRCMF_WD_POLL_MS; if (bus->console.count >= bus->console_interval) { bus->console.count -= bus->console_interval; @@ -3648,10 +3636,12 @@ static bool brcmf_sdbrcm_chipmatch(u16 chipid) { if (chipid == BCM4329_CHIP_ID) return true; + if (chipid == BCM4330_CHIP_ID) + return true; return false; } -static void brcmf_sdbrcm_release_malloc(struct brcmf_bus *bus) +static void brcmf_sdbrcm_release_malloc(struct brcmf_sdio *bus) { brcmf_dbg(TRACE, "Enter\n"); @@ -3663,7 +3653,7 @@ static void brcmf_sdbrcm_release_malloc(struct brcmf_bus *bus) bus->databuf = NULL; } -static bool brcmf_sdbrcm_probe_malloc(struct brcmf_bus *bus) +static bool brcmf_sdbrcm_probe_malloc(struct brcmf_sdio *bus) { brcmf_dbg(TRACE, "Enter\n"); @@ -3699,7 +3689,7 @@ fail: } static bool -brcmf_sdbrcm_probe_attach(struct brcmf_bus *bus, u32 regsva) +brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva) { u8 clkctl = 0; int err = 0; @@ -3784,7 +3774,7 @@ fail: return false; } -static bool brcmf_sdbrcm_probe_init(struct brcmf_bus *bus) +static bool brcmf_sdbrcm_probe_init(struct brcmf_sdio *bus) { brcmf_dbg(TRACE, "Enter\n"); @@ -3792,7 +3782,7 @@ static bool brcmf_sdbrcm_probe_init(struct brcmf_bus *bus) brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx, SDIO_FUNC_ENABLE_1, NULL); - bus->drvr->busstate = BRCMF_BUS_DOWN; + bus->drvr->bus_if->state = BRCMF_BUS_DOWN; bus->sleeping = false; bus->rxflow = false; @@ -3819,7 +3809,7 @@ static bool brcmf_sdbrcm_probe_init(struct brcmf_bus *bus) static int brcmf_sdbrcm_watchdog_thread(void *data) { - struct brcmf_bus *bus = (struct brcmf_bus *)data; + struct brcmf_sdio *bus = (struct brcmf_sdio *)data; allow_signal(SIGTERM); /* Run until signal received */ @@ -3827,7 +3817,7 @@ brcmf_sdbrcm_watchdog_thread(void *data) if (kthread_should_stop()) break; if (!wait_for_completion_interruptible(&bus->watchdog_wait)) { - brcmf_sdbrcm_bus_watchdog(bus->drvr); + brcmf_sdbrcm_bus_watchdog(bus); /* Count the tick for reference */ bus->drvr->tickcnt++; } else @@ -3839,7 +3829,7 @@ brcmf_sdbrcm_watchdog_thread(void *data) static void brcmf_sdbrcm_watchdog(unsigned long data) { - struct brcmf_bus *bus = (struct brcmf_bus *)data; + struct brcmf_sdio *bus = (struct brcmf_sdio *)data; if (bus->watchdog_tsk) { complete(&bus->watchdog_wait); @@ -3850,7 +3840,7 @@ brcmf_sdbrcm_watchdog(unsigned long data) } } -static void brcmf_sdbrcm_release_dongle(struct brcmf_bus *bus) +static void brcmf_sdbrcm_release_dongle(struct brcmf_sdio *bus) { brcmf_dbg(TRACE, "Enter\n"); @@ -3867,7 +3857,7 @@ static void brcmf_sdbrcm_release_dongle(struct brcmf_bus *bus) } /* Detach and free everything */ -static void brcmf_sdbrcm_release(struct brcmf_bus *bus) +static void brcmf_sdbrcm_release(struct brcmf_sdio *bus) { brcmf_dbg(TRACE, "Enter\n"); @@ -3889,21 +3879,10 @@ static void brcmf_sdbrcm_release(struct brcmf_bus *bus) brcmf_dbg(TRACE, "Disconnected\n"); } -void *brcmf_sdbrcm_probe(u16 bus_no, u16 slot, u16 func, uint bustype, - u32 regsva, struct brcmf_sdio_dev *sdiodev) +void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev) { int ret; - struct brcmf_bus *bus; - - /* Init global variables at run-time, not as part of the declaration. - * This is required to support init/de-init of the driver. - * Initialization - * of globals as part of the declaration results in non-deterministic - * behavior since the value of the globals may be different on the - * first time that the driver is initialized vs subsequent - * initializations. - */ - brcmf_c_init(); + struct brcmf_sdio *bus; brcmf_dbg(TRACE, "Enter\n"); @@ -3911,7 +3890,7 @@ void *brcmf_sdbrcm_probe(u16 bus_no, u16 slot, u16 func, uint bustype, * regsva == SI_ENUM_BASE*/ /* Allocate private bus interface state */ - bus = kzalloc(sizeof(struct brcmf_bus), GFP_ATOMIC); + bus = kzalloc(sizeof(struct brcmf_sdio), GFP_ATOMIC); if (!bus) goto fail; @@ -3963,7 +3942,7 @@ void *brcmf_sdbrcm_probe(u16 bus_no, u16 slot, u16 func, uint bustype, } /* Attach to the brcmf/OS/network interface */ - bus->drvr = brcmf_attach(bus, SDPCM_RESERVE); + bus->drvr = brcmf_attach(bus, SDPCM_RESERVE, bus->sdiodev->dev); if (!bus->drvr) { brcmf_dbg(ERROR, "brcmf_attach failed\n"); goto fail; @@ -4015,7 +3994,7 @@ fail: void brcmf_sdbrcm_disconnect(void *ptr) { - struct brcmf_bus *bus = (struct brcmf_bus *)ptr; + struct brcmf_sdio *bus = (struct brcmf_sdio *)ptr; brcmf_dbg(TRACE, "Enter\n"); @@ -4025,13 +4004,8 @@ void brcmf_sdbrcm_disconnect(void *ptr) brcmf_dbg(TRACE, "Disconnected\n"); } -struct device *brcmf_bus_get_device(struct brcmf_bus *bus) -{ - return &bus->sdiodev->func[2]->dev; -} - void -brcmf_sdbrcm_wd_timer(struct brcmf_bus *bus, uint wdtick) +brcmf_sdbrcm_wd_timer(struct brcmf_sdio *bus, uint wdtick) { /* Totally stop the timer */ if (!wdtick && bus->wd_timer_valid == true) { @@ -4042,7 +4016,7 @@ brcmf_sdbrcm_wd_timer(struct brcmf_bus *bus, uint wdtick) } /* don't start the wd until fw is loaded */ - if (bus->drvr->busstate == BRCMF_BUS_DOWN) + if (bus->drvr->bus_if->state == BRCMF_BUS_DOWN) return; if (wdtick) { diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c index f6b1822031fe..a6048d78d294 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c @@ -59,37 +59,17 @@ struct sdiod_drive_str { u8 strength; /* Pad Drive Strength in mA */ u8 sel; /* Chip-specific select value */ }; -/* SDIO Drive Strength to sel value table for PMU Rev 1 */ -static const struct sdiod_drive_str sdiod_drive_strength_tab1[] = { - { - 4, 0x2}, { - 2, 0x3}, { - 1, 0x0}, { - 0, 0x0} - }; -/* SDIO Drive Strength to sel value table for PMU Rev 2, 3 */ -static const struct sdiod_drive_str sdiod_drive_strength_tab2[] = { - { - 12, 0x7}, { - 10, 0x6}, { - 8, 0x5}, { - 6, 0x4}, { - 4, 0x2}, { - 2, 0x1}, { - 0, 0x0} - }; -/* SDIO Drive Strength to sel value table for PMU Rev 8 (1.8V) */ -static const struct sdiod_drive_str sdiod_drive_strength_tab3[] = { - { - 32, 0x7}, { - 26, 0x6}, { - 22, 0x5}, { - 16, 0x4}, { - 12, 0x3}, { - 8, 0x2}, { - 4, 0x1}, { - 0, 0x0} - }; +/* SDIO Drive Strength to sel value table for PMU Rev 11 (1.8V) */ +static const struct sdiod_drive_str sdiod_drvstr_tab1_1v8[] = { + {32, 0x6}, + {26, 0x7}, + {22, 0x4}, + {16, 0x5}, + {12, 0x2}, + {8, 0x3}, + {4, 0x0}, + {0, 0x1} +}; u8 brcmf_sdio_chip_getinfidx(struct chip_info *ci, u16 coreid) @@ -396,6 +376,23 @@ static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev, ci->c_inf[3].base = BCM4329_CORE_ARM_BASE; ci->ramsize = BCM4329_RAMSIZE; break; + case BCM4330_CHIP_ID: + ci->c_inf[0].wrapbase = 0x18100000; + ci->c_inf[0].cib = 0x27004211; + ci->c_inf[1].id = BCMA_CORE_SDIO_DEV; + ci->c_inf[1].base = 0x18002000; + ci->c_inf[1].wrapbase = 0x18102000; + ci->c_inf[1].cib = 0x07004211; + ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM; + ci->c_inf[2].base = 0x18004000; + ci->c_inf[2].wrapbase = 0x18104000; + ci->c_inf[2].cib = 0x0d080401; + ci->c_inf[3].id = BCMA_CORE_ARM_CM3; + ci->c_inf[3].base = 0x18003000; + ci->c_inf[3].wrapbase = 0x18103000; + ci->c_inf[3].cib = 0x03004211; + ci->ramsize = 0x48000; + break; default: brcmf_dbg(ERROR, "chipid 0x%x is not supported\n", ci->chip); return -ENODEV; @@ -569,19 +566,8 @@ brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev, return; switch (SDIOD_DRVSTR_KEY(ci->chip, ci->pmurev)) { - case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 1): - str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab1; - str_mask = 0x30000000; - str_shift = 28; - break; - case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 2): - case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 3): - str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab2; - str_mask = 0x00003800; - str_shift = 11; - break; - case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 8): - str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab3; + case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID, 12): + str_tab = (struct sdiod_drive_str *)&sdiod_drvstr_tab1_1v8; str_mask = 0x00003800; str_shift = 11; break; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h b/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h index 726fa8981113..d36a2a855a65 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h @@ -132,9 +132,10 @@ struct brcmf_sdio_dev { atomic_t suspend; /* suspend flag */ wait_queue_head_t request_byte_wait; wait_queue_head_t request_word_wait; - wait_queue_head_t request_packet_wait; + wait_queue_head_t request_chain_wait; wait_queue_head_t request_buffer_wait; - + struct device *dev; + struct brcmf_bus *bus_if; }; /* Register/deregister device interrupt handler. */ @@ -182,11 +183,21 @@ extern bool brcmf_sdcard_regfail(struct brcmf_sdio_dev *sdiodev); * NOTE: Async operation is not currently supported. */ extern int +brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, + uint flags, struct sk_buff *pkt); +extern int brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, - uint flags, u8 *buf, uint nbytes, struct sk_buff *pkt); + uint flags, u8 *buf, uint nbytes); + +extern int +brcmf_sdcard_recv_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, + uint flags, struct sk_buff *pkt); extern int brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, - uint flags, u8 *buf, uint nbytes, struct sk_buff *pkt); + uint flags, u8 *buf, uint nbytes); +extern int +brcmf_sdcard_recv_chain(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, + uint flags, struct sk_buff_head *pktq); /* Flags bits */ @@ -237,16 +248,18 @@ brcmf_sdioh_request_word(struct brcmf_sdio_dev *sdiodev, /* read or write any buffer using cmd53 */ extern int brcmf_sdioh_request_buffer(struct brcmf_sdio_dev *sdiodev, - uint fix_inc, uint rw, uint fnc_num, - u32 addr, uint regwidth, - u32 buflen, u8 *buffer, struct sk_buff *pkt); + uint fix_inc, uint rw, uint fnc_num, u32 addr, + struct sk_buff *pkt); +extern int +brcmf_sdioh_request_chain(struct brcmf_sdio_dev *sdiodev, uint fix_inc, + uint write, uint func, uint addr, + struct sk_buff_head *pktq); /* Watchdog timer interface for pm ops */ extern void brcmf_sdio_wdtmr_enable(struct brcmf_sdio_dev *sdiodev, bool enable); -extern void *brcmf_sdbrcm_probe(u16 bus_no, u16 slot, u16 func, uint bustype, - u32 regsva, struct brcmf_sdio_dev *sdiodev); +extern void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev); extern void brcmf_sdbrcm_disconnect(void *ptr); extern void brcmf_sdbrcm_isr(void *arg); #endif /* _BRCM_SDH_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index cc19a733ac65..f23b0c3e4ea3 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -1429,7 +1429,7 @@ brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev, static s32 brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, - enum nl80211_tx_power_setting type, s32 dbm) + enum nl80211_tx_power_setting type, s32 mbm) { struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); @@ -1437,6 +1437,7 @@ brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, u16 txpwrmw; s32 err = 0; s32 disable = 0; + s32 dbm = MBM_TO_DBM(mbm); WL_TRACE("Enter\n"); if (!check_sys_up(wiphy)) @@ -1446,12 +1447,6 @@ brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, case NL80211_TX_POWER_AUTOMATIC: break; case NL80211_TX_POWER_LIMITED: - if (dbm < 0) { - WL_ERR("TX_POWER_LIMITED - dbm is negative\n"); - err = -EINVAL; - goto done; - } - break; case NL80211_TX_POWER_FIXED: if (dbm < 0) { WL_ERR("TX_POWER_FIXED - dbm is negative\n"); diff --git a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c index 39e305443d7e..ab9bb11abfbb 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c @@ -318,37 +318,13 @@ #define BADIDX (SI_MAXCORES + 1) -/* Newer chips can access PCI/PCIE and CC core without requiring to change - * PCI BAR0 WIN - */ -#define SI_FAST(si) (((si)->pub.buscoretype == PCIE_CORE_ID) || \ - (((si)->pub.buscoretype == PCI_CORE_ID) && \ - (si)->pub.buscorerev >= 13)) - -#define CCREGS_FAST(si) (((char __iomem *)((si)->curmap) + \ - PCI_16KB0_CCREGS_OFFSET)) - #define IS_SIM(chippkg) \ ((chippkg == HDLSIM_PKG_ID) || (chippkg == HWSIM_PKG_ID)) -/* - * Macros to disable/restore function core(D11, ENET, ILINE20, etc) interrupts - * before after core switching to avoid invalid register accesss inside ISR. - */ -#define INTR_OFF(si, intr_val) \ - if ((si)->intrsoff_fn && \ - (si)->coreid[(si)->curidx] == (si)->dev_coreid) \ - intr_val = (*(si)->intrsoff_fn)((si)->intr_arg) - -#define INTR_RESTORE(si, intr_val) \ - if ((si)->intrsrestore_fn && \ - (si)->coreid[(si)->curidx] == (si)->dev_coreid) \ - (*(si)->intrsrestore_fn)((si)->intr_arg, intr_val) +#define PCI(sih) (ai_get_buscoretype(sih) == PCI_CORE_ID) +#define PCIE(sih) (ai_get_buscoretype(sih) == PCIE_CORE_ID) -#define PCI(si) ((si)->pub.buscoretype == PCI_CORE_ID) -#define PCIE(si) ((si)->pub.buscoretype == PCIE_CORE_ID) - -#define PCI_FORCEHT(si) (PCIE(si) && (si->pub.chip == BCM4716_CHIP_ID)) +#define PCI_FORCEHT(sih) (PCIE(sih) && (ai_get_chip_id(sih) == BCM4716_CHIP_ID)) #ifdef BCMDBG #define SI_MSG(fmt, ...) pr_debug(fmt, ##__VA_ARGS__) @@ -360,9 +336,6 @@ (((x) >= (b)) && ((x) < ((b) + SI_MAXCORES * SI_CORE_SIZE)) && \ IS_ALIGNED((x), SI_CORE_SIZE)) -#define PCIEREGS(si) ((__iomem char *)((si)->curmap) + \ - PCI_16KB0_PCIREGS_OFFSET) - struct aidmp { u32 oobselina30; /* 0x000 */ u32 oobselina74; /* 0x004 */ @@ -481,406 +454,13 @@ struct aidmp { u32 componentid3; /* 0xffc */ }; -/* EROM parsing */ - -static u32 -get_erom_ent(struct si_pub *sih, u32 __iomem **eromptr, u32 mask, u32 match) -{ - u32 ent; - uint inv = 0, nom = 0; - - while (true) { - ent = R_REG(*eromptr); - (*eromptr)++; - - if (mask == 0) - break; - - if ((ent & ER_VALID) == 0) { - inv++; - continue; - } - - if (ent == (ER_END | ER_VALID)) - break; - - if ((ent & mask) == match) - break; - - nom++; - } - - return ent; -} - -static u32 -get_asd(struct si_pub *sih, u32 __iomem **eromptr, uint sp, uint ad, uint st, - u32 *addrl, u32 *addrh, u32 *sizel, u32 *sizeh) -{ - u32 asd, sz, szd; - - asd = get_erom_ent(sih, eromptr, ER_VALID, ER_VALID); - if (((asd & ER_TAG1) != ER_ADD) || - (((asd & AD_SP_MASK) >> AD_SP_SHIFT) != sp) || - ((asd & AD_ST_MASK) != st)) { - /* This is not what we want, "push" it back */ - (*eromptr)--; - return 0; - } - *addrl = asd & AD_ADDR_MASK; - if (asd & AD_AG32) - *addrh = get_erom_ent(sih, eromptr, 0, 0); - else - *addrh = 0; - *sizeh = 0; - sz = asd & AD_SZ_MASK; - if (sz == AD_SZ_SZD) { - szd = get_erom_ent(sih, eromptr, 0, 0); - *sizel = szd & SD_SZ_MASK; - if (szd & SD_SG32) - *sizeh = get_erom_ent(sih, eromptr, 0, 0); - } else - *sizel = AD_SZ_BASE << (sz >> AD_SZ_SHIFT); - - return asd; -} - -static void ai_hwfixup(struct si_info *sii) -{ -} - -/* parse the enumeration rom to identify all cores */ -static void ai_scan(struct si_pub *sih, struct chipcregs __iomem *cc) -{ - struct si_info *sii = (struct si_info *)sih; - - u32 erombase; - u32 __iomem *eromptr, *eromlim; - void __iomem *regs = cc; - - erombase = R_REG(&cc->eromptr); - - /* Set wrappers address */ - sii->curwrap = (void *)((unsigned long)cc + SI_CORE_SIZE); - - /* Now point the window at the erom */ - pci_write_config_dword(sii->pbus, PCI_BAR0_WIN, erombase); - eromptr = regs; - eromlim = eromptr + (ER_REMAPCONTROL / sizeof(u32)); - - while (eromptr < eromlim) { - u32 cia, cib, cid, mfg, crev, nmw, nsw, nmp, nsp; - u32 mpd, asd, addrl, addrh, sizel, sizeh; - u32 __iomem *base; - uint i, j, idx; - bool br; - - br = false; - - /* Grok a component */ - cia = get_erom_ent(sih, &eromptr, ER_TAG, ER_CI); - if (cia == (ER_END | ER_VALID)) { - /* Found END of erom */ - ai_hwfixup(sii); - return; - } - base = eromptr - 1; - cib = get_erom_ent(sih, &eromptr, 0, 0); - - if ((cib & ER_TAG) != ER_CI) { - /* CIA not followed by CIB */ - goto error; - } - - cid = (cia & CIA_CID_MASK) >> CIA_CID_SHIFT; - mfg = (cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT; - crev = (cib & CIB_REV_MASK) >> CIB_REV_SHIFT; - nmw = (cib & CIB_NMW_MASK) >> CIB_NMW_SHIFT; - nsw = (cib & CIB_NSW_MASK) >> CIB_NSW_SHIFT; - nmp = (cib & CIB_NMP_MASK) >> CIB_NMP_SHIFT; - nsp = (cib & CIB_NSP_MASK) >> CIB_NSP_SHIFT; - - if (((mfg == MFGID_ARM) && (cid == DEF_AI_COMP)) || (nsp == 0)) - continue; - if ((nmw + nsw == 0)) { - /* A component which is not a core */ - if (cid == OOB_ROUTER_CORE_ID) { - asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, - &addrl, &addrh, &sizel, &sizeh); - if (asd != 0) - sii->oob_router = addrl; - } - continue; - } - - idx = sii->numcores; -/* sii->eromptr[idx] = base; */ - sii->cia[idx] = cia; - sii->cib[idx] = cib; - sii->coreid[idx] = cid; - - for (i = 0; i < nmp; i++) { - mpd = get_erom_ent(sih, &eromptr, ER_VALID, ER_VALID); - if ((mpd & ER_TAG) != ER_MP) { - /* Not enough MP entries for component */ - goto error; - } - } - - /* First Slave Address Descriptor should be port 0: - * the main register space for the core - */ - asd = - get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, &addrl, &addrh, - &sizel, &sizeh); - if (asd == 0) { - /* Try again to see if it is a bridge */ - asd = - get_asd(sih, &eromptr, 0, 0, AD_ST_BRIDGE, &addrl, - &addrh, &sizel, &sizeh); - if (asd != 0) - br = true; - else if ((addrh != 0) || (sizeh != 0) - || (sizel != SI_CORE_SIZE)) { - /* First Slave ASD for core malformed */ - goto error; - } - } - sii->coresba[idx] = addrl; - sii->coresba_size[idx] = sizel; - /* Get any more ASDs in port 0 */ - j = 1; - do { - asd = - get_asd(sih, &eromptr, 0, j, AD_ST_SLAVE, &addrl, - &addrh, &sizel, &sizeh); - if ((asd != 0) && (j == 1) && (sizel == SI_CORE_SIZE)) { - sii->coresba2[idx] = addrl; - sii->coresba2_size[idx] = sizel; - } - j++; - } while (asd != 0); - - /* Go through the ASDs for other slave ports */ - for (i = 1; i < nsp; i++) { - j = 0; - do { - asd = - get_asd(sih, &eromptr, i, j++, AD_ST_SLAVE, - &addrl, &addrh, &sizel, &sizeh); - } while (asd != 0); - if (j == 0) { - /* SP has no address descriptors */ - goto error; - } - } - - /* Now get master wrappers */ - for (i = 0; i < nmw; i++) { - asd = - get_asd(sih, &eromptr, i, 0, AD_ST_MWRAP, &addrl, - &addrh, &sizel, &sizeh); - if (asd == 0) { - /* Missing descriptor for MW */ - goto error; - } - if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) { - /* Master wrapper %d is not 4KB */ - goto error; - } - if (i == 0) - sii->wrapba[idx] = addrl; - } - - /* And finally slave wrappers */ - for (i = 0; i < nsw; i++) { - uint fwp = (nsp == 1) ? 0 : 1; - asd = - get_asd(sih, &eromptr, fwp + i, 0, AD_ST_SWRAP, - &addrl, &addrh, &sizel, &sizeh); - if (asd == 0) { - /* Missing descriptor for SW */ - goto error; - } - if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) { - /* Slave wrapper is not 4KB */ - goto error; - } - if ((nmw == 0) && (i == 0)) - sii->wrapba[idx] = addrl; - } - - /* Don't record bridges */ - if (br) - continue; - - /* Done with core */ - sii->numcores++; - } - - error: - /* Reached end of erom without finding END */ - sii->numcores = 0; - return; -} - -/* - * This function changes the logical "focus" to the indicated core. - * Return the current core's virtual address. Since each core starts with the - * same set of registers (BIST, clock control, etc), the returned address - * contains the first register of this 'common' register block (not to be - * confused with 'common core'). - */ -void __iomem *ai_setcoreidx(struct si_pub *sih, uint coreidx) -{ - struct si_info *sii = (struct si_info *)sih; - u32 addr = sii->coresba[coreidx]; - u32 wrap = sii->wrapba[coreidx]; - - if (coreidx >= sii->numcores) - return NULL; - - /* point bar0 window */ - pci_write_config_dword(sii->pbus, PCI_BAR0_WIN, addr); - /* point bar0 2nd 4KB window */ - pci_write_config_dword(sii->pbus, PCI_BAR0_WIN2, wrap); - sii->curidx = coreidx; - - return sii->curmap; -} - -/* Return the number of address spaces in current core */ -int ai_numaddrspaces(struct si_pub *sih) -{ - return 2; -} - -/* Return the address of the nth address space in the current core */ -u32 ai_addrspace(struct si_pub *sih, uint asidx) -{ - struct si_info *sii; - uint cidx; - - sii = (struct si_info *)sih; - cidx = sii->curidx; - - if (asidx == 0) - return sii->coresba[cidx]; - else if (asidx == 1) - return sii->coresba2[cidx]; - else { - /* Need to parse the erom again to find addr space */ - return 0; - } -} - -/* Return the size of the nth address space in the current core */ -u32 ai_addrspacesize(struct si_pub *sih, uint asidx) -{ - struct si_info *sii; - uint cidx; - - sii = (struct si_info *)sih; - cidx = sii->curidx; - - if (asidx == 0) - return sii->coresba_size[cidx]; - else if (asidx == 1) - return sii->coresba2_size[cidx]; - else { - /* Need to parse the erom again to find addr */ - return 0; - } -} - -uint ai_flag(struct si_pub *sih) -{ - struct si_info *sii; - struct aidmp *ai; - - sii = (struct si_info *)sih; - ai = sii->curwrap; - - return R_REG(&ai->oobselouta30) & 0x1f; -} - -void ai_setint(struct si_pub *sih, int siflag) -{ -} - -uint ai_corevendor(struct si_pub *sih) -{ - struct si_info *sii; - u32 cia; - - sii = (struct si_info *)sih; - cia = sii->cia[sii->curidx]; - return (cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT; -} - -uint ai_corerev(struct si_pub *sih) -{ - struct si_info *sii; - u32 cib; - - sii = (struct si_info *)sih; - cib = sii->cib[sii->curidx]; - return (cib & CIB_REV_MASK) >> CIB_REV_SHIFT; -} - -bool ai_iscoreup(struct si_pub *sih) -{ - struct si_info *sii; - struct aidmp *ai; - - sii = (struct si_info *)sih; - ai = sii->curwrap; - - return (((R_REG(&ai->ioctrl) & (SICF_FGC | SICF_CLOCK_EN)) == - SICF_CLOCK_EN) - && ((R_REG(&ai->resetctrl) & AIRC_RESET) == 0)); -} - -void ai_core_cflags_wo(struct si_pub *sih, u32 mask, u32 val) -{ - struct si_info *sii; - struct aidmp *ai; - u32 w; - - sii = (struct si_info *)sih; - - ai = sii->curwrap; - - if (mask || val) { - w = ((R_REG(&ai->ioctrl) & ~mask) | val); - W_REG(&ai->ioctrl, w); - } -} - -u32 ai_core_cflags(struct si_pub *sih, u32 mask, u32 val) -{ - struct si_info *sii; - struct aidmp *ai; - u32 w; - - sii = (struct si_info *)sih; - ai = sii->curwrap; - - if (mask || val) { - w = ((R_REG(&ai->ioctrl) & ~mask) | val); - W_REG(&ai->ioctrl, w); - } - - return R_REG(&ai->ioctrl); -} - /* return true if PCIE capability exists in the pci config space */ static bool ai_ispcie(struct si_info *sii) { u8 cap_ptr; cap_ptr = - pcicore_find_pci_capability(sii->pbus, PCI_CAP_ID_EXP, NULL, + pcicore_find_pci_capability(sii->pcibus, PCI_CAP_ID_EXP, NULL, NULL); if (!cap_ptr) return false; @@ -896,117 +476,69 @@ static bool ai_buscore_prep(struct si_info *sii) return true; } -u32 ai_core_sflags(struct si_pub *sih, u32 mask, u32 val) -{ - struct si_info *sii; - struct aidmp *ai; - u32 w; - - sii = (struct si_info *)sih; - ai = sii->curwrap; - - if (mask || val) { - w = ((R_REG(&ai->iostatus) & ~mask) | val); - W_REG(&ai->iostatus, w); - } - - return R_REG(&ai->iostatus); -} - static bool -ai_buscore_setup(struct si_info *sii, u32 savewin, uint *origidx) +ai_buscore_setup(struct si_info *sii, struct bcma_device *cc) { - bool pci, pcie; - uint i; - uint pciidx, pcieidx, pcirev, pcierev; - struct chipcregs __iomem *cc; + struct bcma_device *pci = NULL; + struct bcma_device *pcie = NULL; + struct bcma_device *core; - cc = ai_setcoreidx(&sii->pub, SI_CC_IDX); + + /* no cores found, bail out */ + if (cc->bus->nr_cores == 0) + return false; /* get chipcommon rev */ - sii->pub.ccrev = (int)ai_corerev(&sii->pub); + sii->pub.ccrev = cc->id.rev; /* get chipcommon chipstatus */ - if (sii->pub.ccrev >= 11) - sii->pub.chipst = R_REG(&cc->chipstatus); + if (ai_get_ccrev(&sii->pub) >= 11) + sii->chipst = bcma_read32(cc, CHIPCREGOFFS(chipstatus)); /* get chipcommon capabilites */ - sii->pub.cccaps = R_REG(&cc->capabilities); - /* get chipcommon extended capabilities */ - - if (sii->pub.ccrev >= 35) - sii->pub.cccaps_ext = R_REG(&cc->capabilities_ext); + sii->pub.cccaps = bcma_read32(cc, CHIPCREGOFFS(capabilities)); /* get pmu rev and caps */ - if (sii->pub.cccaps & CC_CAP_PMU) { - sii->pub.pmucaps = R_REG(&cc->pmucapabilities); + if (ai_get_cccaps(&sii->pub) & CC_CAP_PMU) { + sii->pub.pmucaps = bcma_read32(cc, + CHIPCREGOFFS(pmucapabilities)); sii->pub.pmurev = sii->pub.pmucaps & PCAP_REV_MASK; } - /* figure out bus/orignal core idx */ - sii->pub.buscoretype = NODEV_CORE_ID; - sii->pub.buscorerev = NOREV; - sii->pub.buscoreidx = BADIDX; - - pci = pcie = false; - pcirev = pcierev = NOREV; - pciidx = pcieidx = BADIDX; - - for (i = 0; i < sii->numcores; i++) { + /* figure out buscore */ + list_for_each_entry(core, &cc->bus->cores, list) { uint cid, crev; - ai_setcoreidx(&sii->pub, i); - cid = ai_coreid(&sii->pub); - crev = ai_corerev(&sii->pub); + cid = core->id.id; + crev = core->id.rev; if (cid == PCI_CORE_ID) { - pciidx = i; - pcirev = crev; - pci = true; + pci = core; } else if (cid == PCIE_CORE_ID) { - pcieidx = i; - pcierev = crev; - pcie = true; + pcie = core; } - - /* find the core idx before entering this func. */ - if ((savewin && (savewin == sii->coresba[i])) || - (cc == sii->regs[i])) - *origidx = i; } if (pci && pcie) { if (ai_ispcie(sii)) - pci = false; + pci = NULL; else - pcie = false; + pcie = NULL; } if (pci) { - sii->pub.buscoretype = PCI_CORE_ID; - sii->pub.buscorerev = pcirev; - sii->pub.buscoreidx = pciidx; + sii->buscore = pci; } else if (pcie) { - sii->pub.buscoretype = PCIE_CORE_ID; - sii->pub.buscorerev = pcierev; - sii->pub.buscoreidx = pcieidx; + sii->buscore = pcie; } /* fixup necessary chip/core configurations */ - if (SI_FAST(sii)) { - if (!sii->pch) { - sii->pch = pcicore_init(&sii->pub, sii->pbus, - (__iomem void *)PCIEREGS(sii)); - if (sii->pch == NULL) - return false; - } + if (!sii->pch) { + sii->pch = pcicore_init(&sii->pub, sii->icbus->drv_pci.core); + if (sii->pch == NULL) + return false; } - if (ai_pci_fixcfg(&sii->pub)) { - /* si_doattach: si_pci_fixcfg failed */ + if (ai_pci_fixcfg(&sii->pub)) return false; - } - - /* return to the original core */ - ai_setcoreidx(&sii->pub, *origidx); return true; } @@ -1019,39 +551,27 @@ static __used void ai_nvram_process(struct si_info *sii) uint w = 0; /* do a pci config read to get subsystem id and subvendor id */ - pci_read_config_dword(sii->pbus, PCI_SUBSYSTEM_VENDOR_ID, &w); + pci_read_config_dword(sii->pcibus, PCI_SUBSYSTEM_VENDOR_ID, &w); sii->pub.boardvendor = w & 0xffff; sii->pub.boardtype = (w >> 16) & 0xffff; - sii->pub.boardflags = getintvar(&sii->pub, BRCMS_SROM_BOARDFLAGS); } static struct si_info *ai_doattach(struct si_info *sii, - void __iomem *regs, struct pci_dev *pbus) + struct bcma_bus *pbus) { struct si_pub *sih = &sii->pub; u32 w, savewin; - struct chipcregs __iomem *cc; + struct bcma_device *cc; uint socitype; - uint origidx; - - memset((unsigned char *) sii, 0, sizeof(struct si_info)); savewin = 0; - sih->buscoreidx = BADIDX; - - sii->curmap = regs; - sii->pbus = pbus; + sii->icbus = pbus; + sii->pcibus = pbus->host_pci; - /* find Chipcommon address */ - pci_read_config_dword(sii->pbus, PCI_BAR0_WIN, &savewin); - if (!GOODCOREADDR(savewin, SI_ENUM_BASE)) - savewin = SI_ENUM_BASE; - - pci_write_config_dword(sii->pbus, PCI_BAR0_WIN, - SI_ENUM_BASE); - cc = (struct chipcregs __iomem *) regs; + /* switch to Chipcommon core */ + cc = pbus->drv_cc.core; /* bus/core/clk setup for register access */ if (!ai_buscore_prep(sii)) @@ -1064,89 +584,69 @@ static struct si_info *ai_doattach(struct si_info *sii, * hosts w/o chipcommon), some way of recognizing them needs to * be added here. */ - w = R_REG(&cc->chipid); + w = bcma_read32(cc, CHIPCREGOFFS(chipid)); socitype = (w & CID_TYPE_MASK) >> CID_TYPE_SHIFT; /* Might as wll fill in chip id rev & pkg */ sih->chip = w & CID_ID_MASK; sih->chiprev = (w & CID_REV_MASK) >> CID_REV_SHIFT; sih->chippkg = (w & CID_PKG_MASK) >> CID_PKG_SHIFT; - sih->issim = false; - /* scan for cores */ - if (socitype == SOCI_AI) { - SI_MSG("Found chip type AI (0x%08x)\n", w); - /* pass chipc address instead of original core base */ - ai_scan(&sii->pub, cc); - } else { - /* Found chip of unknown type */ - return NULL; - } - /* no cores found, bail out */ - if (sii->numcores == 0) + if (socitype != SOCI_AI) return NULL; - /* bus/core/clk setup */ - origidx = SI_CC_IDX; - if (!ai_buscore_setup(sii, savewin, &origidx)) + SI_MSG("Found chip type AI (0x%08x)\n", w); + if (!ai_buscore_setup(sii, cc)) goto exit; /* Init nvram from sprom/otp if they exist */ - if (srom_var_init(&sii->pub, cc)) + if (srom_var_init(&sii->pub)) goto exit; ai_nvram_process(sii); /* === NVRAM, clock is ready === */ - cc = (struct chipcregs __iomem *) ai_setcore(sih, CC_CORE_ID, 0); - W_REG(&cc->gpiopullup, 0); - W_REG(&cc->gpiopulldown, 0); - ai_setcoreidx(sih, origidx); + bcma_write32(cc, CHIPCREGOFFS(gpiopullup), 0); + bcma_write32(cc, CHIPCREGOFFS(gpiopulldown), 0); /* PMU specific initializations */ - if (sih->cccaps & CC_CAP_PMU) { - u32 xtalfreq; + if (ai_get_cccaps(sih) & CC_CAP_PMU) { si_pmu_init(sih); - si_pmu_chip_init(sih); - - xtalfreq = si_pmu_measure_alpclk(sih); - si_pmu_pll_init(sih, xtalfreq); + (void)si_pmu_measure_alpclk(sih); si_pmu_res_init(sih); - si_pmu_swreg_init(sih); } /* setup the GPIO based LED powersave register */ w = getintvar(sih, BRCMS_SROM_LEDDC); if (w == 0) w = DEFAULT_GPIOTIMERVAL; - ai_corereg(sih, SI_CC_IDX, offsetof(struct chipcregs, gpiotimerval), - ~0, w); + ai_cc_reg(sih, offsetof(struct chipcregs, gpiotimerval), + ~0, w); - if (PCIE(sii)) + if (PCIE(sih)) pcicore_attach(sii->pch, SI_DOATTACH); - if (sih->chip == BCM43224_CHIP_ID) { + if (ai_get_chip_id(sih) == BCM43224_CHIP_ID) { /* * enable 12 mA drive strenth for 43224 and * set chipControl register bit 15 */ - if (sih->chiprev == 0) { + if (ai_get_chiprev(sih) == 0) { SI_MSG("Applying 43224A0 WARs\n"); - ai_corereg(sih, SI_CC_IDX, - offsetof(struct chipcregs, chipcontrol), - CCTRL43224_GPIO_TOGGLE, - CCTRL43224_GPIO_TOGGLE); + ai_cc_reg(sih, offsetof(struct chipcregs, chipcontrol), + CCTRL43224_GPIO_TOGGLE, + CCTRL43224_GPIO_TOGGLE); si_pmu_chipcontrol(sih, 0, CCTRL_43224A0_12MA_LED_DRIVE, CCTRL_43224A0_12MA_LED_DRIVE); } - if (sih->chiprev >= 1) { + if (ai_get_chiprev(sih) >= 1) { SI_MSG("Applying 43224B0+ WARs\n"); si_pmu_chipcontrol(sih, 0, CCTRL_43224B0_12MA_LED_DRIVE, CCTRL_43224B0_12MA_LED_DRIVE); } } - if (sih->chip == BCM4313_CHIP_ID) { + if (ai_get_chip_id(sih) == BCM4313_CHIP_ID) { /* * enable 12 mA drive strenth for 4313 and * set chipControl register bit 1 @@ -1167,22 +667,19 @@ static struct si_info *ai_doattach(struct si_info *sii, } /* - * Allocate a si handle. - * devid - pci device id (used to determine chip#) - * osh - opaque OS handle - * regs - virtual address of initial core registers + * Allocate a si handle and do the attach. */ struct si_pub * -ai_attach(void __iomem *regs, struct pci_dev *sdh) +ai_attach(struct bcma_bus *pbus) { struct si_info *sii; /* alloc struct si_info */ - sii = kmalloc(sizeof(struct si_info), GFP_ATOMIC); + sii = kzalloc(sizeof(struct si_info), GFP_ATOMIC); if (sii == NULL) return NULL; - if (ai_doattach(sii, regs, sdh) == NULL) { + if (ai_doattach(sii, pbus) == NULL) { kfree(sii); return NULL; } @@ -1211,292 +708,66 @@ void ai_detach(struct si_pub *sih) kfree(sii); } -/* register driver interrupt disabling and restoring callback functions */ -void -ai_register_intr_callback(struct si_pub *sih, void *intrsoff_fn, - void *intrsrestore_fn, - void *intrsenabled_fn, void *intr_arg) -{ - struct si_info *sii; - - sii = (struct si_info *)sih; - sii->intr_arg = intr_arg; - sii->intrsoff_fn = (u32 (*)(void *)) intrsoff_fn; - sii->intrsrestore_fn = (void (*) (void *, u32)) intrsrestore_fn; - sii->intrsenabled_fn = (bool (*)(void *)) intrsenabled_fn; - /* save current core id. when this function called, the current core - * must be the core which provides driver functions(il, et, wl, etc.) - */ - sii->dev_coreid = sii->coreid[sii->curidx]; -} - -void ai_deregister_intr_callback(struct si_pub *sih) -{ - struct si_info *sii; - - sii = (struct si_info *)sih; - sii->intrsoff_fn = NULL; -} - -uint ai_coreid(struct si_pub *sih) -{ - struct si_info *sii; - - sii = (struct si_info *)sih; - return sii->coreid[sii->curidx]; -} - -uint ai_coreidx(struct si_pub *sih) -{ - struct si_info *sii; - - sii = (struct si_info *)sih; - return sii->curidx; -} - -bool ai_backplane64(struct si_pub *sih) -{ - return (sih->cccaps & CC_CAP_BKPLN64) != 0; -} - /* return index of coreid or BADIDX if not found */ -uint ai_findcoreidx(struct si_pub *sih, uint coreid, uint coreunit) +struct bcma_device *ai_findcore(struct si_pub *sih, u16 coreid, u16 coreunit) { + struct bcma_device *core; struct si_info *sii; uint found; - uint i; sii = (struct si_info *)sih; found = 0; - for (i = 0; i < sii->numcores; i++) - if (sii->coreid[i] == coreid) { + list_for_each_entry(core, &sii->icbus->cores, list) + if (core->id.id == coreid) { if (found == coreunit) - return i; + return core; found++; } - return BADIDX; -} - -/* - * This function changes logical "focus" to the indicated core; - * must be called with interrupts off. - * Moreover, callers should keep interrupts off during switching - * out of and back to d11 core. - */ -void __iomem *ai_setcore(struct si_pub *sih, uint coreid, uint coreunit) -{ - uint idx; - - idx = ai_findcoreidx(sih, coreid, coreunit); - if (idx >= SI_MAXCORES) - return NULL; - - return ai_setcoreidx(sih, idx); -} - -/* Turn off interrupt as required by ai_setcore, before switch core */ -void __iomem *ai_switch_core(struct si_pub *sih, uint coreid, uint *origidx, - uint *intr_val) -{ - void __iomem *cc; - struct si_info *sii; - - sii = (struct si_info *)sih; - - if (SI_FAST(sii)) { - /* Overloading the origidx variable to remember the coreid, - * this works because the core ids cannot be confused with - * core indices. - */ - *origidx = coreid; - if (coreid == CC_CORE_ID) - return CCREGS_FAST(sii); - else if (coreid == sih->buscoretype) - return PCIEREGS(sii); - } - INTR_OFF(sii, *intr_val); - *origidx = sii->curidx; - cc = ai_setcore(sih, coreid, 0); - return cc; -} - -/* restore coreidx and restore interrupt */ -void ai_restore_core(struct si_pub *sih, uint coreid, uint intr_val) -{ - struct si_info *sii; - - sii = (struct si_info *)sih; - if (SI_FAST(sii) - && ((coreid == CC_CORE_ID) || (coreid == sih->buscoretype))) - return; - - ai_setcoreidx(sih, coreid); - INTR_RESTORE(sii, intr_val); -} - -void ai_write_wrapperreg(struct si_pub *sih, u32 offset, u32 val) -{ - struct si_info *sii = (struct si_info *)sih; - u32 *w = (u32 *) sii->curwrap; - W_REG(w + (offset / 4), val); - return; + return NULL; } /* - * Switch to 'coreidx', issue a single arbitrary 32bit register mask&set - * operation, switch back to the original core, and return the new value. - * - * When using the silicon backplane, no fiddling with interrupts or core - * switches is needed. - * - * Also, when using pci/pcie, we can optimize away the core switching for pci - * registers and (on newer pci cores) chipcommon registers. + * read/modify chipcommon core register. */ -uint ai_corereg(struct si_pub *sih, uint coreidx, uint regoff, uint mask, - uint val) +uint ai_cc_reg(struct si_pub *sih, uint regoff, u32 mask, u32 val) { - uint origidx = 0; - u32 __iomem *r = NULL; - uint w; - uint intr_val = 0; - bool fast = false; + struct bcma_device *cc; + u32 w; struct si_info *sii; sii = (struct si_info *)sih; - - if (coreidx >= SI_MAXCORES) - return 0; - - /* - * If pci/pcie, we can get at pci/pcie regs - * and on newer cores to chipc - */ - if ((sii->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { - /* Chipc registers are mapped at 12KB */ - fast = true; - r = (u32 __iomem *)((__iomem char *)sii->curmap + - PCI_16KB0_CCREGS_OFFSET + regoff); - } else if (sii->pub.buscoreidx == coreidx) { - /* - * pci registers are at either in the last 2KB of - * an 8KB window or, in pcie and pci rev 13 at 8KB - */ - fast = true; - if (SI_FAST(sii)) - r = (u32 __iomem *)((__iomem char *)sii->curmap + - PCI_16KB0_PCIREGS_OFFSET + regoff); - else - r = (u32 __iomem *)((__iomem char *)sii->curmap + - ((regoff >= SBCONFIGOFF) ? - PCI_BAR0_PCISBR_OFFSET : - PCI_BAR0_PCIREGS_OFFSET) + regoff); - } - - if (!fast) { - INTR_OFF(sii, intr_val); - - /* save current core index */ - origidx = ai_coreidx(&sii->pub); - - /* switch core */ - r = (u32 __iomem *) ((unsigned char __iomem *) - ai_setcoreidx(&sii->pub, coreidx) + regoff); - } + cc = sii->icbus->drv_cc.core; /* mask and set */ if (mask || val) { - w = (R_REG(r) & ~mask) | val; - W_REG(r, w); + bcma_maskset32(cc, regoff, ~mask, val); } /* readback */ - w = R_REG(r); - - if (!fast) { - /* restore core index */ - if (origidx != coreidx) - ai_setcoreidx(&sii->pub, origidx); - - INTR_RESTORE(sii, intr_val); - } + w = bcma_read32(cc, regoff); return w; } -void ai_core_disable(struct si_pub *sih, u32 bits) -{ - struct si_info *sii; - u32 dummy; - struct aidmp *ai; - - sii = (struct si_info *)sih; - - ai = sii->curwrap; - - /* if core is already in reset, just return */ - if (R_REG(&ai->resetctrl) & AIRC_RESET) - return; - - W_REG(&ai->ioctrl, bits); - dummy = R_REG(&ai->ioctrl); - udelay(10); - - W_REG(&ai->resetctrl, AIRC_RESET); - udelay(1); -} - -/* reset and re-enable a core - * inputs: - * bits - core specific bits that are set during and after reset sequence - * resetbits - core specific bits that are set only during reset sequence - */ -void ai_core_reset(struct si_pub *sih, u32 bits, u32 resetbits) -{ - struct si_info *sii; - struct aidmp *ai; - u32 dummy; - - sii = (struct si_info *)sih; - ai = sii->curwrap; - - /* - * Must do the disable sequence first to work - * for arbitrary current core state. - */ - ai_core_disable(sih, (bits | resetbits)); - - /* - * Now do the initialization sequence. - */ - W_REG(&ai->ioctrl, (bits | SICF_FGC | SICF_CLOCK_EN)); - dummy = R_REG(&ai->ioctrl); - W_REG(&ai->resetctrl, 0); - udelay(1); - - W_REG(&ai->ioctrl, (bits | SICF_CLOCK_EN)); - dummy = R_REG(&ai->ioctrl); - udelay(1); -} - /* return the slow clock source - LPO, XTAL, or PCI */ -static uint ai_slowclk_src(struct si_info *sii) +static uint ai_slowclk_src(struct si_pub *sih, struct bcma_device *cc) { - struct chipcregs __iomem *cc; + struct si_info *sii; u32 val; - if (sii->pub.ccrev < 6) { - pci_read_config_dword(sii->pbus, PCI_GPIO_OUT, + sii = (struct si_info *)sih; + if (ai_get_ccrev(&sii->pub) < 6) { + pci_read_config_dword(sii->pcibus, PCI_GPIO_OUT, &val); if (val & PCI_CFG_GPIO_SCS) return SCC_SS_PCI; return SCC_SS_XTAL; - } else if (sii->pub.ccrev < 10) { - cc = (struct chipcregs __iomem *) - ai_setcoreidx(&sii->pub, sii->curidx); - return R_REG(&cc->slow_clk_ctl) & SCC_SS_MASK; + } else if (ai_get_ccrev(&sii->pub) < 10) { + return bcma_read32(cc, CHIPCREGOFFS(slow_clk_ctl)) & + SCC_SS_MASK; } else /* Insta-clock */ return SCC_SS_XTAL; } @@ -1505,24 +776,24 @@ static uint ai_slowclk_src(struct si_info *sii) * return the ILP (slowclock) min or max frequency * precondition: we've established the chip has dynamic clk control */ -static uint ai_slowclk_freq(struct si_info *sii, bool max_freq, - struct chipcregs __iomem *cc) +static uint ai_slowclk_freq(struct si_pub *sih, bool max_freq, + struct bcma_device *cc) { u32 slowclk; uint div; - slowclk = ai_slowclk_src(sii); - if (sii->pub.ccrev < 6) { + slowclk = ai_slowclk_src(sih, cc); + if (ai_get_ccrev(sih) < 6) { if (slowclk == SCC_SS_PCI) return max_freq ? (PCIMAXFREQ / 64) : (PCIMINFREQ / 64); else return max_freq ? (XTALMAXFREQ / 32) : (XTALMINFREQ / 32); - } else if (sii->pub.ccrev < 10) { + } else if (ai_get_ccrev(sih) < 10) { div = 4 * - (((R_REG(&cc->slow_clk_ctl) & SCC_CD_MASK) >> - SCC_CD_SHIFT) + 1); + (((bcma_read32(cc, CHIPCREGOFFS(slow_clk_ctl)) & + SCC_CD_MASK) >> SCC_CD_SHIFT) + 1); if (slowclk == SCC_SS_LPO) return max_freq ? LPOMAXFREQ : LPOMINFREQ; else if (slowclk == SCC_SS_XTAL) @@ -1533,15 +804,15 @@ static uint ai_slowclk_freq(struct si_info *sii, bool max_freq, : (PCIMINFREQ / div); } else { /* Chipc rev 10 is InstaClock */ - div = R_REG(&cc->system_clk_ctl) >> SYCC_CD_SHIFT; - div = 4 * (div + 1); + div = bcma_read32(cc, CHIPCREGOFFS(system_clk_ctl)); + div = 4 * ((div >> SYCC_CD_SHIFT) + 1); return max_freq ? XTALMAXFREQ : (XTALMINFREQ / div); } return 0; } static void -ai_clkctl_setdelay(struct si_info *sii, struct chipcregs __iomem *cc) +ai_clkctl_setdelay(struct si_pub *sih, struct bcma_device *cc) { uint slowmaxfreq, pll_delay, slowclk; uint pll_on_delay, fref_sel_delay; @@ -1554,55 +825,40 @@ ai_clkctl_setdelay(struct si_info *sii, struct chipcregs __iomem *cc) * powered down by dynamic clk control logic. */ - slowclk = ai_slowclk_src(sii); + slowclk = ai_slowclk_src(sih, cc); if (slowclk != SCC_SS_XTAL) pll_delay += XTAL_ON_DELAY; /* Starting with 4318 it is ILP that is used for the delays */ slowmaxfreq = - ai_slowclk_freq(sii, (sii->pub.ccrev >= 10) ? false : true, cc); + ai_slowclk_freq(sih, + (ai_get_ccrev(sih) >= 10) ? false : true, cc); pll_on_delay = ((slowmaxfreq * pll_delay) + 999999) / 1000000; fref_sel_delay = ((slowmaxfreq * FREF_DELAY) + 999999) / 1000000; - W_REG(&cc->pll_on_delay, pll_on_delay); - W_REG(&cc->fref_sel_delay, fref_sel_delay); + bcma_write32(cc, CHIPCREGOFFS(pll_on_delay), pll_on_delay); + bcma_write32(cc, CHIPCREGOFFS(fref_sel_delay), fref_sel_delay); } /* initialize power control delay registers */ void ai_clkctl_init(struct si_pub *sih) { - struct si_info *sii; - uint origidx = 0; - struct chipcregs __iomem *cc; - bool fast; + struct bcma_device *cc; - if (!(sih->cccaps & CC_CAP_PWR_CTL)) + if (!(ai_get_cccaps(sih) & CC_CAP_PWR_CTL)) return; - sii = (struct si_info *)sih; - fast = SI_FAST(sii); - if (!fast) { - origidx = sii->curidx; - cc = (struct chipcregs __iomem *) - ai_setcore(sih, CC_CORE_ID, 0); - if (cc == NULL) - return; - } else { - cc = (struct chipcregs __iomem *) CCREGS_FAST(sii); - if (cc == NULL) - return; - } + cc = ai_findcore(sih, BCMA_CORE_CHIPCOMMON, 0); + if (cc == NULL) + return; /* set all Instaclk chip ILP to 1 MHz */ - if (sih->ccrev >= 10) - SET_REG(&cc->system_clk_ctl, SYCC_CD_MASK, - (ILP_DIV_1MHZ << SYCC_CD_SHIFT)); + if (ai_get_ccrev(sih) >= 10) + bcma_maskset32(cc, CHIPCREGOFFS(system_clk_ctl), SYCC_CD_MASK, + (ILP_DIV_1MHZ << SYCC_CD_SHIFT)); - ai_clkctl_setdelay(sii, cc); - - if (!fast) - ai_setcoreidx(sih, origidx); + ai_clkctl_setdelay(sih, cc); } /* @@ -1612,47 +868,25 @@ void ai_clkctl_init(struct si_pub *sih) u16 ai_clkctl_fast_pwrup_delay(struct si_pub *sih) { struct si_info *sii; - uint origidx = 0; - struct chipcregs __iomem *cc; + struct bcma_device *cc; uint slowminfreq; u16 fpdelay; - uint intr_val = 0; - bool fast; sii = (struct si_info *)sih; - if (sih->cccaps & CC_CAP_PMU) { - INTR_OFF(sii, intr_val); + if (ai_get_cccaps(sih) & CC_CAP_PMU) { fpdelay = si_pmu_fast_pwrup_delay(sih); - INTR_RESTORE(sii, intr_val); return fpdelay; } - if (!(sih->cccaps & CC_CAP_PWR_CTL)) + if (!(ai_get_cccaps(sih) & CC_CAP_PWR_CTL)) return 0; - fast = SI_FAST(sii); fpdelay = 0; - if (!fast) { - origidx = sii->curidx; - INTR_OFF(sii, intr_val); - cc = (struct chipcregs __iomem *) - ai_setcore(sih, CC_CORE_ID, 0); - if (cc == NULL) - goto done; - } else { - cc = (struct chipcregs __iomem *) CCREGS_FAST(sii); - if (cc == NULL) - goto done; - } - - slowminfreq = ai_slowclk_freq(sii, false, cc); - fpdelay = (((R_REG(&cc->pll_on_delay) + 2) * 1000000) + - (slowminfreq - 1)) / slowminfreq; - - done: - if (!fast) { - ai_setcoreidx(sih, origidx); - INTR_RESTORE(sii, intr_val); + cc = ai_findcore(sih, CC_CORE_ID, 0); + if (cc) { + slowminfreq = ai_slowclk_freq(sih, false, cc); + fpdelay = (((bcma_read32(cc, CHIPCREGOFFS(pll_on_delay)) + 2) + * 1000000) + (slowminfreq - 1)) / slowminfreq; } return fpdelay; } @@ -1666,12 +900,12 @@ int ai_clkctl_xtal(struct si_pub *sih, uint what, bool on) sii = (struct si_info *)sih; /* pcie core doesn't have any mapping to control the xtal pu */ - if (PCIE(sii)) + if (PCIE(sih)) return -1; - pci_read_config_dword(sii->pbus, PCI_GPIO_IN, &in); - pci_read_config_dword(sii->pbus, PCI_GPIO_OUT, &out); - pci_read_config_dword(sii->pbus, PCI_GPIO_OUTEN, &outen); + pci_read_config_dword(sii->pcibus, PCI_GPIO_IN, &in); + pci_read_config_dword(sii->pcibus, PCI_GPIO_OUT, &out); + pci_read_config_dword(sii->pcibus, PCI_GPIO_OUTEN, &outen); /* * Avoid glitching the clock if GPRS is already using it. @@ -1692,9 +926,9 @@ int ai_clkctl_xtal(struct si_pub *sih, uint what, bool on) out |= PCI_CFG_GPIO_XTAL; if (what & PLL) out |= PCI_CFG_GPIO_PLL; - pci_write_config_dword(sii->pbus, + pci_write_config_dword(sii->pcibus, PCI_GPIO_OUT, out); - pci_write_config_dword(sii->pbus, + pci_write_config_dword(sii->pcibus, PCI_GPIO_OUTEN, outen); udelay(XTAL_ON_DELAY); } @@ -1702,7 +936,7 @@ int ai_clkctl_xtal(struct si_pub *sih, uint what, bool on) /* turn pll on */ if (what & PLL) { out &= ~PCI_CFG_GPIO_PLL; - pci_write_config_dword(sii->pbus, + pci_write_config_dword(sii->pcibus, PCI_GPIO_OUT, out); mdelay(2); } @@ -1711,9 +945,9 @@ int ai_clkctl_xtal(struct si_pub *sih, uint what, bool on) out &= ~PCI_CFG_GPIO_XTAL; if (what & PLL) out |= PCI_CFG_GPIO_PLL; - pci_write_config_dword(sii->pbus, + pci_write_config_dword(sii->pcibus, PCI_GPIO_OUT, out); - pci_write_config_dword(sii->pbus, + pci_write_config_dword(sii->pcibus, PCI_GPIO_OUTEN, outen); } @@ -1723,63 +957,52 @@ int ai_clkctl_xtal(struct si_pub *sih, uint what, bool on) /* clk control mechanism through chipcommon, no policy checking */ static bool _ai_clkctl_cc(struct si_info *sii, uint mode) { - uint origidx = 0; - struct chipcregs __iomem *cc; + struct bcma_device *cc; u32 scc; - uint intr_val = 0; - bool fast = SI_FAST(sii); /* chipcommon cores prior to rev6 don't support dynamic clock control */ - if (sii->pub.ccrev < 6) + if (ai_get_ccrev(&sii->pub) < 6) return false; - if (!fast) { - INTR_OFF(sii, intr_val); - origidx = sii->curidx; - cc = (struct chipcregs __iomem *) - ai_setcore(&sii->pub, CC_CORE_ID, 0); - } else { - cc = (struct chipcregs __iomem *) CCREGS_FAST(sii); - if (cc == NULL) - goto done; - } + cc = ai_findcore(&sii->pub, BCMA_CORE_CHIPCOMMON, 0); - if (!(sii->pub.cccaps & CC_CAP_PWR_CTL) && (sii->pub.ccrev < 20)) - goto done; + if (!(ai_get_cccaps(&sii->pub) & CC_CAP_PWR_CTL) && + (ai_get_ccrev(&sii->pub) < 20)) + return mode == CLK_FAST; switch (mode) { case CLK_FAST: /* FORCEHT, fast (pll) clock */ - if (sii->pub.ccrev < 10) { + if (ai_get_ccrev(&sii->pub) < 10) { /* * don't forget to force xtal back * on before we clear SCC_DYN_XTAL.. */ ai_clkctl_xtal(&sii->pub, XTAL, ON); - SET_REG(&cc->slow_clk_ctl, - (SCC_XC | SCC_FS | SCC_IP), SCC_IP); - } else if (sii->pub.ccrev < 20) { - OR_REG(&cc->system_clk_ctl, SYCC_HR); + bcma_maskset32(cc, CHIPCREGOFFS(slow_clk_ctl), + (SCC_XC | SCC_FS | SCC_IP), SCC_IP); + } else if (ai_get_ccrev(&sii->pub) < 20) { + bcma_set32(cc, CHIPCREGOFFS(system_clk_ctl), SYCC_HR); } else { - OR_REG(&cc->clk_ctl_st, CCS_FORCEHT); + bcma_set32(cc, CHIPCREGOFFS(clk_ctl_st), CCS_FORCEHT); } /* wait for the PLL */ - if (sii->pub.cccaps & CC_CAP_PMU) { + if (ai_get_cccaps(&sii->pub) & CC_CAP_PMU) { u32 htavail = CCS_HTAVAIL; - SPINWAIT(((R_REG(&cc->clk_ctl_st) & htavail) - == 0), PMU_MAX_TRANSITION_DLY); + SPINWAIT(((bcma_read32(cc, CHIPCREGOFFS(clk_ctl_st)) & + htavail) == 0), PMU_MAX_TRANSITION_DLY); } else { udelay(PLL_DELAY); } break; case CLK_DYNAMIC: /* enable dynamic clock control */ - if (sii->pub.ccrev < 10) { - scc = R_REG(&cc->slow_clk_ctl); + if (ai_get_ccrev(&sii->pub) < 10) { + scc = bcma_read32(cc, CHIPCREGOFFS(slow_clk_ctl)); scc &= ~(SCC_FS | SCC_IP | SCC_XC); if ((scc & SCC_SS_MASK) != SCC_SS_XTAL) scc |= SCC_XC; - W_REG(&cc->slow_clk_ctl, scc); + bcma_write32(cc, CHIPCREGOFFS(slow_clk_ctl), scc); /* * for dynamic control, we have to @@ -1787,11 +1010,11 @@ static bool _ai_clkctl_cc(struct si_info *sii, uint mode) */ if (scc & SCC_XC) ai_clkctl_xtal(&sii->pub, XTAL, OFF); - } else if (sii->pub.ccrev < 20) { + } else if (ai_get_ccrev(&sii->pub) < 20) { /* Instaclock */ - AND_REG(&cc->system_clk_ctl, ~SYCC_HR); + bcma_mask32(cc, CHIPCREGOFFS(system_clk_ctl), ~SYCC_HR); } else { - AND_REG(&cc->clk_ctl_st, ~CCS_FORCEHT); + bcma_mask32(cc, CHIPCREGOFFS(clk_ctl_st), ~CCS_FORCEHT); } break; @@ -1799,11 +1022,6 @@ static bool _ai_clkctl_cc(struct si_info *sii, uint mode) break; } - done: - if (!fast) { - ai_setcoreidx(&sii->pub, origidx); - INTR_RESTORE(sii, intr_val); - } return mode == CLK_FAST; } @@ -1822,46 +1040,25 @@ bool ai_clkctl_cc(struct si_pub *sih, uint mode) sii = (struct si_info *)sih; /* chipcommon cores prior to rev6 don't support dynamic clock control */ - if (sih->ccrev < 6) + if (ai_get_ccrev(sih) < 6) return false; - if (PCI_FORCEHT(sii)) + if (PCI_FORCEHT(sih)) return mode == CLK_FAST; return _ai_clkctl_cc(sii, mode); } -/* Build device path */ -int ai_devpath(struct si_pub *sih, char *path, int size) -{ - int slen; - - if (!path || size <= 0) - return -1; - - slen = snprintf(path, (size_t) size, "pci/%u/%u/", - ((struct si_info *)sih)->pbus->bus->number, - PCI_SLOT(((struct pci_dev *) - (((struct si_info *)(sih))->pbus))->devfn)); - - if (slen < 0 || slen >= size) { - path[0] = '\0'; - return -1; - } - - return 0; -} - void ai_pci_up(struct si_pub *sih) { struct si_info *sii; sii = (struct si_info *)sih; - if (PCI_FORCEHT(sii)) + if (PCI_FORCEHT(sih)) _ai_clkctl_cc(sii, CLK_FAST); - if (PCIE(sii)) + if (PCIE(sih)) pcicore_up(sii->pch, SI_PCIUP); } @@ -1884,7 +1081,7 @@ void ai_pci_down(struct si_pub *sih) sii = (struct si_info *)sih; /* release FORCEHT since chip is going to "down" state */ - if (PCI_FORCEHT(sii)) + if (PCI_FORCEHT(sih)) _ai_clkctl_cc(sii, CLK_DYNAMIC); pcicore_down(sii->pch, SI_PCIDOWN); @@ -1897,42 +1094,23 @@ void ai_pci_down(struct si_pub *sih) void ai_pci_setup(struct si_pub *sih, uint coremask) { struct si_info *sii; - struct sbpciregs __iomem *regs = NULL; - u32 siflag = 0, w; - uint idx = 0; + u32 w; sii = (struct si_info *)sih; - if (PCI(sii)) { - /* get current core index */ - idx = sii->curidx; - - /* we interrupt on this backplane flag number */ - siflag = ai_flag(sih); - - /* switch over to pci core */ - regs = ai_setcoreidx(sih, sii->pub.buscoreidx); - } - /* * Enable sb->pci interrupts. Assume * PCI rev 2.3 support was added in pci core rev 6 and things changed.. */ - if (PCIE(sii) || (PCI(sii) && ((sii->pub.buscorerev) >= 6))) { + if (PCIE(sih) || (PCI(sih) && (ai_get_buscorerev(sih) >= 6))) { /* pci config write to set this core bit in PCIIntMask */ - pci_read_config_dword(sii->pbus, PCI_INT_MASK, &w); + pci_read_config_dword(sii->pcibus, PCI_INT_MASK, &w); w |= (coremask << PCI_SBIM_SHIFT); - pci_write_config_dword(sii->pbus, PCI_INT_MASK, w); - } else { - /* set sbintvec bit for our flag number */ - ai_setint(sih, siflag); + pci_write_config_dword(sii->pcibus, PCI_INT_MASK, w); } - if (PCI(sii)) { - pcicore_pci_setup(sii->pch, regs); - - /* switch back to previous core */ - ai_setcoreidx(sih, idx); + if (PCI(sih)) { + pcicore_pci_setup(sii->pch); } } @@ -1942,25 +1120,11 @@ void ai_pci_setup(struct si_pub *sih, uint coremask) */ int ai_pci_fixcfg(struct si_pub *sih) { - uint origidx; - void __iomem *regs = NULL; struct si_info *sii = (struct si_info *)sih; /* Fixup PI in SROM shadow area to enable the correct PCI core access */ - /* save the current index */ - origidx = ai_coreidx(&sii->pub); - /* check 'pi' is correct and fix it if not */ - regs = ai_setcore(&sii->pub, sii->pub.buscoretype, 0); - if (sii->pub.buscoretype == PCIE_CORE_ID) - pcicore_fixcfg_pcie(sii->pch, - (struct sbpcieregs __iomem *)regs); - else if (sii->pub.buscoretype == PCI_CORE_ID) - pcicore_fixcfg_pci(sii->pch, (struct sbpciregs __iomem *)regs); - - /* restore the original index */ - ai_setcoreidx(&sii->pub, origidx); - + pcicore_fixcfg(sii->pch); pcicore_hwup(sii->pch); return 0; } @@ -1971,58 +1135,42 @@ u32 ai_gpiocontrol(struct si_pub *sih, u32 mask, u32 val, u8 priority) uint regoff; regoff = offsetof(struct chipcregs, gpiocontrol); - return ai_corereg(sih, SI_CC_IDX, regoff, mask, val); + return ai_cc_reg(sih, regoff, mask, val); } void ai_chipcontrl_epa4331(struct si_pub *sih, bool on) { - struct si_info *sii; - struct chipcregs __iomem *cc; - uint origidx; + struct bcma_device *cc; u32 val; - sii = (struct si_info *)sih; - origidx = ai_coreidx(sih); - - cc = (struct chipcregs __iomem *) ai_setcore(sih, CC_CORE_ID, 0); - - val = R_REG(&cc->chipcontrol); + cc = ai_findcore(sih, CC_CORE_ID, 0); if (on) { - if (sih->chippkg == 9 || sih->chippkg == 0xb) + if (ai_get_chippkg(sih) == 9 || ai_get_chippkg(sih) == 0xb) /* Ext PA Controls for 4331 12x9 Package */ - W_REG(&cc->chipcontrol, val | - CCTRL4331_EXTPA_EN | - CCTRL4331_EXTPA_ON_GPIO2_5); + bcma_set32(cc, CHIPCREGOFFS(chipcontrol), + CCTRL4331_EXTPA_EN | + CCTRL4331_EXTPA_ON_GPIO2_5); else /* Ext PA Controls for 4331 12x12 Package */ - W_REG(&cc->chipcontrol, - val | CCTRL4331_EXTPA_EN); + bcma_set32(cc, CHIPCREGOFFS(chipcontrol), + CCTRL4331_EXTPA_EN); } else { val &= ~(CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_ON_GPIO2_5); - W_REG(&cc->chipcontrol, val); + bcma_mask32(cc, CHIPCREGOFFS(chipcontrol), + ~(CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_ON_GPIO2_5)); } - - ai_setcoreidx(sih, origidx); } /* Enable BT-COEX & Ex-PA for 4313 */ void ai_epa_4313war(struct si_pub *sih) { - struct si_info *sii; - struct chipcregs __iomem *cc; - uint origidx; + struct bcma_device *cc; - sii = (struct si_info *)sih; - origidx = ai_coreidx(sih); - - cc = ai_setcore(sih, CC_CORE_ID, 0); + cc = ai_findcore(sih, CC_CORE_ID, 0); /* EPA Fix */ - W_REG(&cc->gpiocontrol, - R_REG(&cc->gpiocontrol) | GPIO_CTRL_EPA_EN_MASK); - - ai_setcoreidx(sih, origidx); + bcma_set32(cc, CHIPCREGOFFS(gpiocontrol), GPIO_CTRL_EPA_EN_MASK); } /* check if the device is removed */ @@ -2033,7 +1181,7 @@ bool ai_deviceremoved(struct si_pub *sih) sii = (struct si_info *)sih; - pci_read_config_dword(sii->pbus, PCI_VENDOR_ID, &w); + pci_read_config_dword(sii->pcibus, PCI_VENDOR_ID, &w); if ((w & 0xFFFF) != PCI_VENDOR_ID_BROADCOM) return true; @@ -2042,26 +1190,23 @@ bool ai_deviceremoved(struct si_pub *sih) bool ai_is_sprom_available(struct si_pub *sih) { - if (sih->ccrev >= 31) { - struct si_info *sii; - uint origidx; - struct chipcregs __iomem *cc; + struct si_info *sii = (struct si_info *)sih; + + if (ai_get_ccrev(sih) >= 31) { + struct bcma_device *cc; u32 sromctrl; - if ((sih->cccaps & CC_CAP_SROM) == 0) + if ((ai_get_cccaps(sih) & CC_CAP_SROM) == 0) return false; - sii = (struct si_info *)sih; - origidx = sii->curidx; - cc = ai_setcoreidx(sih, SI_CC_IDX); - sromctrl = R_REG(&cc->sromcontrol); - ai_setcoreidx(sih, origidx); + cc = ai_findcore(sih, BCMA_CORE_CHIPCOMMON, 0); + sromctrl = bcma_read32(cc, CHIPCREGOFFS(sromcontrol)); return sromctrl & SRC_PRESENT; } - switch (sih->chip) { + switch (ai_get_chip_id(sih)) { case BCM4313_CHIP_ID: - return (sih->chipst & CST4313_SPROM_PRESENT) != 0; + return (sii->chipst & CST4313_SPROM_PRESENT) != 0; default: return true; } @@ -2069,9 +1214,11 @@ bool ai_is_sprom_available(struct si_pub *sih) bool ai_is_otp_disabled(struct si_pub *sih) { - switch (sih->chip) { + struct si_info *sii = (struct si_info *)sih; + + switch (ai_get_chip_id(sih)) { case BCM4313_CHIP_ID: - return (sih->chipst & CST4313_OTP_PRESENT) == 0; + return (sii->chipst & CST4313_OTP_PRESENT) == 0; /* These chips always have their OTP on */ case BCM43224_CHIP_ID: case BCM43225_CHIP_ID: @@ -2079,3 +1226,15 @@ bool ai_is_otp_disabled(struct si_pub *sih) return false; } } + +uint ai_get_buscoretype(struct si_pub *sih) +{ + struct si_info *sii = (struct si_info *)sih; + return sii->buscore->id.id; +} + +uint ai_get_buscorerev(struct si_pub *sih) +{ + struct si_info *sii = (struct si_info *)sih; + return sii->buscore->id.rev; +} diff --git a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h index b51d1e421e24..f84c6f781692 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h @@ -17,6 +17,8 @@ #ifndef _BRCM_AIUTILS_H_ #define _BRCM_AIUTILS_H_ +#include <linux/bcma/bcma.h> + #include "types.h" /* @@ -144,26 +146,15 @@ * public (read-only) portion of aiutils handle returned by si_attach() */ struct si_pub { - uint buscoretype; /* PCI_CORE_ID, PCIE_CORE_ID, PCMCIA_CORE_ID */ - uint buscorerev; /* buscore rev */ - uint buscoreidx; /* buscore index */ int ccrev; /* chip common core rev */ u32 cccaps; /* chip common capabilities */ - u32 cccaps_ext; /* chip common capabilities extension */ int pmurev; /* pmu core rev */ u32 pmucaps; /* pmu capabilities */ uint boardtype; /* board type */ uint boardvendor; /* board vendor */ - uint boardflags; /* board flags */ - uint boardflags2; /* board flags2 */ uint chip; /* chip number */ uint chiprev; /* chip revision */ uint chippkg; /* chip package option */ - u32 chipst; /* chip status */ - bool issim; /* chip is in simulation or emulation */ - uint socirev; /* SOC interconnect rev */ - bool pci_pr32414; - }; struct pci_dev; @@ -179,38 +170,13 @@ struct gpioh_item { /* misc si info needed by some of the routines */ struct si_info { struct si_pub pub; /* back plane public state (must be first) */ - struct pci_dev *pbus; /* handle to pci bus */ - uint dev_coreid; /* the core provides driver functions */ - void *intr_arg; /* interrupt callback function arg */ - u32 (*intrsoff_fn) (void *intr_arg); /* turns chip interrupts off */ - /* restore chip interrupts */ - void (*intrsrestore_fn) (void *intr_arg, u32 arg); - /* check if interrupts are enabled */ - bool (*intrsenabled_fn) (void *intr_arg); - + struct bcma_bus *icbus; /* handle to soc interconnect bus */ + struct pci_dev *pcibus; /* handle to pci bus */ struct pcicore_info *pch; /* PCI/E core handle */ - + struct bcma_device *buscore; struct list_head var_list; /* list of srom variables */ - void __iomem *curmap; /* current regs va */ - void __iomem *regs[SI_MAXCORES]; /* other regs va */ - - uint curidx; /* current core index */ - uint numcores; /* # discovered cores */ - uint coreid[SI_MAXCORES]; /* id of each core */ - u32 coresba[SI_MAXCORES]; /* backplane address of each core */ - void *regs2[SI_MAXCORES]; /* 2nd virtual address per core (usbh20) */ - u32 coresba2[SI_MAXCORES]; /* 2nd phys address per core (usbh20) */ - u32 coresba_size[SI_MAXCORES]; /* backplane address space size */ - u32 coresba2_size[SI_MAXCORES]; /* second address space size */ - - void *curwrap; /* current wrapper va */ - void *wrappers[SI_MAXCORES]; /* other cores wrapper va */ - u32 wrapba[SI_MAXCORES]; /* address of controlling wrapper */ - - u32 cia[SI_MAXCORES]; /* erom cia entry for each core */ - u32 cib[SI_MAXCORES]; /* erom cia entry for each core */ - u32 oob_router; /* oob router registers for axi */ + u32 chipst; /* chip status */ }; /* @@ -223,52 +189,15 @@ struct si_info { /* AMBA Interconnect exported externs */ -extern uint ai_flag(struct si_pub *sih); -extern void ai_setint(struct si_pub *sih, int siflag); -extern uint ai_coreidx(struct si_pub *sih); -extern uint ai_corevendor(struct si_pub *sih); -extern uint ai_corerev(struct si_pub *sih); -extern bool ai_iscoreup(struct si_pub *sih); -extern u32 ai_core_cflags(struct si_pub *sih, u32 mask, u32 val); -extern void ai_core_cflags_wo(struct si_pub *sih, u32 mask, u32 val); -extern u32 ai_core_sflags(struct si_pub *sih, u32 mask, u32 val); -extern uint ai_corereg(struct si_pub *sih, uint coreidx, uint regoff, uint mask, - uint val); -extern void ai_core_reset(struct si_pub *sih, u32 bits, u32 resetbits); -extern void ai_core_disable(struct si_pub *sih, u32 bits); -extern int ai_numaddrspaces(struct si_pub *sih); -extern u32 ai_addrspace(struct si_pub *sih, uint asidx); -extern u32 ai_addrspacesize(struct si_pub *sih, uint asidx); -extern void ai_write_wrap_reg(struct si_pub *sih, u32 offset, u32 val); +extern struct bcma_device *ai_findcore(struct si_pub *sih, + u16 coreid, u16 coreunit); +extern u32 ai_core_cflags(struct bcma_device *core, u32 mask, u32 val); /* === exported functions === */ -extern struct si_pub *ai_attach(void __iomem *regs, struct pci_dev *sdh); +extern struct si_pub *ai_attach(struct bcma_bus *pbus); extern void ai_detach(struct si_pub *sih); -extern uint ai_coreid(struct si_pub *sih); -extern uint ai_corerev(struct si_pub *sih); -extern uint ai_corereg(struct si_pub *sih, uint coreidx, uint regoff, uint mask, - uint val); -extern void ai_write_wrapperreg(struct si_pub *sih, u32 offset, u32 val); -extern u32 ai_core_cflags(struct si_pub *sih, u32 mask, u32 val); -extern u32 ai_core_sflags(struct si_pub *sih, u32 mask, u32 val); -extern bool ai_iscoreup(struct si_pub *sih); -extern uint ai_findcoreidx(struct si_pub *sih, uint coreid, uint coreunit); -extern void __iomem *ai_setcoreidx(struct si_pub *sih, uint coreidx); -extern void __iomem *ai_setcore(struct si_pub *sih, uint coreid, uint coreunit); -extern void __iomem *ai_switch_core(struct si_pub *sih, uint coreid, - uint *origidx, uint *intr_val); -extern void ai_restore_core(struct si_pub *sih, uint coreid, uint intr_val); -extern void ai_core_reset(struct si_pub *sih, u32 bits, u32 resetbits); -extern void ai_core_disable(struct si_pub *sih, u32 bits); -extern u32 ai_alp_clock(struct si_pub *sih); -extern u32 ai_ilp_clock(struct si_pub *sih); +extern uint ai_cc_reg(struct si_pub *sih, uint regoff, u32 mask, u32 val); extern void ai_pci_setup(struct si_pub *sih, uint coremask); -extern void ai_setint(struct si_pub *sih, int siflag); -extern bool ai_backplane64(struct si_pub *sih); -extern void ai_register_intr_callback(struct si_pub *sih, void *intrsoff_fn, - void *intrsrestore_fn, - void *intrsenabled_fn, void *intr_arg); -extern void ai_deregister_intr_callback(struct si_pub *sih); extern void ai_clkctl_init(struct si_pub *sih); extern u16 ai_clkctl_fast_pwrup_delay(struct si_pub *sih); extern bool ai_clkctl_cc(struct si_pub *sih, uint mode); @@ -283,13 +212,6 @@ extern bool ai_is_otp_disabled(struct si_pub *sih); /* SPROM availability */ extern bool ai_is_sprom_available(struct si_pub *sih); -/* - * Build device path. Path size must be >= SI_DEVPATH_BUFSZ. - * The returned path is NULL terminated and has trailing '/'. - * Return 0 on success, nonzero otherwise. - */ -extern int ai_devpath(struct si_pub *sih, char *path, int size); - extern void ai_pci_sleep(struct si_pub *sih); extern void ai_pci_down(struct si_pub *sih); extern void ai_pci_up(struct si_pub *sih); @@ -299,4 +221,52 @@ extern void ai_chipcontrl_epa4331(struct si_pub *sih, bool on); /* Enable Ex-PA for 4313 */ extern void ai_epa_4313war(struct si_pub *sih); +extern uint ai_get_buscoretype(struct si_pub *sih); +extern uint ai_get_buscorerev(struct si_pub *sih); + +static inline int ai_get_ccrev(struct si_pub *sih) +{ + return sih->ccrev; +} + +static inline u32 ai_get_cccaps(struct si_pub *sih) +{ + return sih->cccaps; +} + +static inline int ai_get_pmurev(struct si_pub *sih) +{ + return sih->pmurev; +} + +static inline u32 ai_get_pmucaps(struct si_pub *sih) +{ + return sih->pmucaps; +} + +static inline uint ai_get_boardtype(struct si_pub *sih) +{ + return sih->boardtype; +} + +static inline uint ai_get_boardvendor(struct si_pub *sih) +{ + return sih->boardvendor; +} + +static inline uint ai_get_chip_id(struct si_pub *sih) +{ + return sih->chip; +} + +static inline uint ai_get_chiprev(struct si_pub *sih) +{ + return sih->chiprev; +} + +static inline uint ai_get_chippkg(struct si_pub *sih) +{ + return sih->chippkg; +} + #endif /* _BRCM_AIUTILS_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c index 43f7a724dda8..90911eec0cf5 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c @@ -1118,14 +1118,17 @@ brcms_c_ampdu_dotxstatus(struct ampdu_info *ampdu, struct scb *scb, u8 status_delay = 0; /* wait till the next 8 bytes of txstatus is available */ - while (((s1 = R_REG(&wlc->regs->frmtxstatus)) & TXS_V) == 0) { + s1 = bcma_read32(wlc->hw->d11core, D11REGOFFS(frmtxstatus)); + while ((s1 & TXS_V) == 0) { udelay(1); status_delay++; if (status_delay > 10) return; /* error condition */ + s1 = bcma_read32(wlc->hw->d11core, + D11REGOFFS(frmtxstatus)); } - s2 = R_REG(&wlc->regs->frmtxstatus2); + s2 = bcma_read32(wlc->hw->d11core, D11REGOFFS(frmtxstatus2)); } if (scb) { diff --git a/drivers/net/wireless/brcm80211/brcmsmac/d11.h b/drivers/net/wireless/brcm80211/brcmsmac/d11.h index ed51616abc85..1948cb2771e9 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/d11.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/d11.h @@ -430,6 +430,9 @@ struct d11regs { u16 PAD[0x380]; /* 0x800 - 0xEFE */ }; +/* d11 register field offset */ +#define D11REGOFFS(field) offsetof(struct d11regs, field) + #define PIHR_BASE 0x0400 /* byte address of packed IHR region */ /* biststatus */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/dma.c b/drivers/net/wireless/brcm80211/brcmsmac/dma.c index 0bb8c37e979e..2e90a9a16ed6 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/dma.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/dma.c @@ -27,6 +27,13 @@ #include "soc.h" /* + * dma register field offset calculation + */ +#define DMA64REGOFFS(field) offsetof(struct dma64regs, field) +#define DMA64TXREGOFFS(di, field) (di->d64txregbase + DMA64REGOFFS(field)) +#define DMA64RXREGOFFS(di, field) (di->d64rxregbase + DMA64REGOFFS(field)) + +/* * DMA hardware requires each descriptor ring to be 8kB aligned, and fit within * a contiguous 8kB physical address. */ @@ -220,15 +227,16 @@ struct dma_info { uint *msg_level; /* message level pointer */ char name[MAXNAMEL]; /* callers name for diag msgs */ - struct pci_dev *pbus; /* bus handle */ + struct bcma_device *core; + struct device *dmadev; bool dma64; /* this dma engine is operating in 64-bit mode */ bool addrext; /* this dma engine supports DmaExtendedAddrChanges */ /* 64-bit dma tx engine registers */ - struct dma64regs __iomem *d64txregs; + uint d64txregbase; /* 64-bit dma rx engine registers */ - struct dma64regs __iomem *d64rxregs; + uint d64rxregbase; /* pointer to dma64 tx descriptor ring */ struct dma64desc *txd64; /* pointer to dma64 rx descriptor ring */ @@ -375,15 +383,16 @@ static uint _dma_ctrlflags(struct dma_info *di, uint mask, uint flags) if (dmactrlflags & DMA_CTRL_PEN) { u32 control; - control = R_REG(&di->d64txregs->control); - W_REG(&di->d64txregs->control, + control = bcma_read32(di->core, DMA64TXREGOFFS(di, control)); + bcma_write32(di->core, DMA64TXREGOFFS(di, control), control | D64_XC_PD); - if (R_REG(&di->d64txregs->control) & D64_XC_PD) + if (bcma_read32(di->core, DMA64TXREGOFFS(di, control)) & + D64_XC_PD) /* We *can* disable it so it is supported, * restore control register */ - W_REG(&di->d64txregs->control, - control); + bcma_write32(di->core, DMA64TXREGOFFS(di, control), + control); else /* Not supported, don't allow it to be enabled */ dmactrlflags &= ~DMA_CTRL_PEN; @@ -394,12 +403,12 @@ static uint _dma_ctrlflags(struct dma_info *di, uint mask, uint flags) return dmactrlflags; } -static bool _dma64_addrext(struct dma64regs __iomem *dma64regs) +static bool _dma64_addrext(struct dma_info *di, uint ctrl_offset) { u32 w; - OR_REG(&dma64regs->control, D64_XC_AE); - w = R_REG(&dma64regs->control); - AND_REG(&dma64regs->control, ~D64_XC_AE); + bcma_set32(di->core, ctrl_offset, D64_XC_AE); + w = bcma_read32(di->core, ctrl_offset); + bcma_mask32(di->core, ctrl_offset, ~D64_XC_AE); return (w & D64_XC_AE) == D64_XC_AE; } @@ -412,13 +421,13 @@ static bool _dma_isaddrext(struct dma_info *di) /* DMA64 supports full 32- or 64-bit operation. AE is always valid */ /* not all tx or rx channel are available */ - if (di->d64txregs != NULL) { - if (!_dma64_addrext(di->d64txregs)) + if (di->d64txregbase != 0) { + if (!_dma64_addrext(di, DMA64TXREGOFFS(di, control))) DMA_ERROR("%s: DMA64 tx doesn't have AE set\n", di->name); return true; - } else if (di->d64rxregs != NULL) { - if (!_dma64_addrext(di->d64rxregs)) + } else if (di->d64rxregbase != 0) { + if (!_dma64_addrext(di, DMA64RXREGOFFS(di, control))) DMA_ERROR("%s: DMA64 rx doesn't have AE set\n", di->name); return true; @@ -432,14 +441,14 @@ static bool _dma_descriptor_align(struct dma_info *di) u32 addrl; /* Check to see if the descriptors need to be aligned on 4K/8K or not */ - if (di->d64txregs != NULL) { - W_REG(&di->d64txregs->addrlow, 0xff0); - addrl = R_REG(&di->d64txregs->addrlow); + if (di->d64txregbase != 0) { + bcma_write32(di->core, DMA64TXREGOFFS(di, addrlow), 0xff0); + addrl = bcma_read32(di->core, DMA64TXREGOFFS(di, addrlow)); if (addrl != 0) return false; - } else if (di->d64rxregs != NULL) { - W_REG(&di->d64rxregs->addrlow, 0xff0); - addrl = R_REG(&di->d64rxregs->addrlow); + } else if (di->d64rxregbase != 0) { + bcma_write32(di->core, DMA64RXREGOFFS(di, addrlow), 0xff0); + addrl = bcma_read32(di->core, DMA64RXREGOFFS(di, addrlow)); if (addrl != 0) return false; } @@ -450,7 +459,7 @@ static bool _dma_descriptor_align(struct dma_info *di) * Descriptor table must start at the DMA hardware dictated alignment, so * allocated memory must be large enough to support this requirement. */ -static void *dma_alloc_consistent(struct pci_dev *pdev, uint size, +static void *dma_alloc_consistent(struct dma_info *di, uint size, u16 align_bits, uint *alloced, dma_addr_t *pap) { @@ -460,7 +469,7 @@ static void *dma_alloc_consistent(struct pci_dev *pdev, uint size, size += align; *alloced = size; } - return pci_alloc_consistent(pdev, size, pap); + return dma_alloc_coherent(di->dmadev, size, pap, GFP_ATOMIC); } static @@ -486,7 +495,7 @@ static void *dma_ringalloc(struct dma_info *di, u32 boundary, uint size, u32 desc_strtaddr; u32 alignbytes = 1 << *alignbits; - va = dma_alloc_consistent(di->pbus, size, *alignbits, alloced, descpa); + va = dma_alloc_consistent(di, size, *alignbits, alloced, descpa); if (NULL == va) return NULL; @@ -495,8 +504,8 @@ static void *dma_ringalloc(struct dma_info *di, u32 boundary, uint size, if (((desc_strtaddr + size - 1) & boundary) != (desc_strtaddr & boundary)) { *alignbits = dma_align_sizetobits(size); - pci_free_consistent(di->pbus, size, va, *descpa); - va = dma_alloc_consistent(di->pbus, size, *alignbits, + dma_free_coherent(di->dmadev, size, va, *descpa); + va = dma_alloc_consistent(di, size, *alignbits, alloced, descpa); } return va; @@ -556,12 +565,13 @@ static bool _dma_alloc(struct dma_info *di, uint direction) } struct dma_pub *dma_attach(char *name, struct si_pub *sih, - void __iomem *dmaregstx, void __iomem *dmaregsrx, - uint ntxd, uint nrxd, - uint rxbufsize, int rxextheadroom, - uint nrxpost, uint rxoffset, uint *msg_level) + struct bcma_device *core, + uint txregbase, uint rxregbase, uint ntxd, uint nrxd, + uint rxbufsize, int rxextheadroom, + uint nrxpost, uint rxoffset, uint *msg_level) { struct dma_info *di; + u8 rev = core->id.rev; uint size; /* allocate private info structure */ @@ -572,11 +582,13 @@ struct dma_pub *dma_attach(char *name, struct si_pub *sih, di->msg_level = msg_level ? msg_level : &dma_msg_level; - di->dma64 = ((ai_core_sflags(sih, 0, 0) & SISF_DMA64) == SISF_DMA64); + di->dma64 = + ((bcma_aread32(core, BCMA_IOST) & SISF_DMA64) == SISF_DMA64); - /* init dma reg pointer */ - di->d64txregs = (struct dma64regs __iomem *) dmaregstx; - di->d64rxregs = (struct dma64regs __iomem *) dmaregsrx; + /* init dma reg info */ + di->core = core; + di->d64txregbase = txregbase; + di->d64rxregbase = rxregbase; /* * Default flags (which can be changed by the driver calling @@ -585,16 +597,17 @@ struct dma_pub *dma_attach(char *name, struct si_pub *sih, */ _dma_ctrlflags(di, DMA_CTRL_ROC | DMA_CTRL_PEN, 0); - DMA_TRACE("%s: %s flags 0x%x ntxd %d nrxd %d rxbufsize %d rxextheadroom %d nrxpost %d rxoffset %d dmaregstx %p dmaregsrx %p\n", - name, "DMA64", + DMA_TRACE("%s: %s flags 0x%x ntxd %d nrxd %d " + "rxbufsize %d rxextheadroom %d nrxpost %d rxoffset %d " + "txregbase %u rxregbase %u\n", name, "DMA64", di->dma.dmactrlflags, ntxd, nrxd, rxbufsize, - rxextheadroom, nrxpost, rxoffset, dmaregstx, dmaregsrx); + rxextheadroom, nrxpost, rxoffset, txregbase, rxregbase); /* make a private copy of our callers name */ strncpy(di->name, name, MAXNAMEL); di->name[MAXNAMEL - 1] = '\0'; - di->pbus = ((struct si_info *)sih)->pbus; + di->dmadev = core->dma_dev; /* save tunables */ di->ntxd = (u16) ntxd; @@ -626,12 +639,12 @@ struct dma_pub *dma_attach(char *name, struct si_pub *sih, di->dataoffsetlow = di->ddoffsetlow; di->dataoffsethigh = di->ddoffsethigh; /* WAR64450 : DMACtl.Addr ext fields are not supported in SDIOD core. */ - if ((ai_coreid(sih) == SDIOD_CORE_ID) - && ((ai_corerev(sih) > 0) && (ai_corerev(sih) <= 2))) - di->addrext = 0; - else if ((ai_coreid(sih) == I2S_CORE_ID) && - ((ai_corerev(sih) == 0) || (ai_corerev(sih) == 1))) - di->addrext = 0; + if ((core->id.id == SDIOD_CORE_ID) + && ((rev > 0) && (rev <= 2))) + di->addrext = false; + else if ((core->id.id == I2S_CORE_ID) && + ((rev == 0) || (rev == 1))) + di->addrext = false; else di->addrext = _dma_isaddrext(di); @@ -749,13 +762,13 @@ void dma_detach(struct dma_pub *pub) /* free dma descriptor rings */ if (di->txd64) - pci_free_consistent(di->pbus, di->txdalloc, - ((s8 *)di->txd64 - di->txdalign), - (di->txdpaorig)); + dma_free_coherent(di->dmadev, di->txdalloc, + ((s8 *)di->txd64 - di->txdalign), + (di->txdpaorig)); if (di->rxd64) - pci_free_consistent(di->pbus, di->rxdalloc, - ((s8 *)di->rxd64 - di->rxdalign), - (di->rxdpaorig)); + dma_free_coherent(di->dmadev, di->rxdalloc, + ((s8 *)di->rxd64 - di->rxdalign), + (di->rxdpaorig)); /* free packet pointer vectors */ kfree(di->txp); @@ -780,11 +793,15 @@ _dma_ddtable_init(struct dma_info *di, uint direction, dma_addr_t pa) if ((di->ddoffsetlow == 0) || !(pa & PCI32ADDR_HIGH)) { if (direction == DMA_TX) { - W_REG(&di->d64txregs->addrlow, pa + di->ddoffsetlow); - W_REG(&di->d64txregs->addrhigh, di->ddoffsethigh); + bcma_write32(di->core, DMA64TXREGOFFS(di, addrlow), + pa + di->ddoffsetlow); + bcma_write32(di->core, DMA64TXREGOFFS(di, addrhigh), + di->ddoffsethigh); } else { - W_REG(&di->d64rxregs->addrlow, pa + di->ddoffsetlow); - W_REG(&di->d64rxregs->addrhigh, di->ddoffsethigh); + bcma_write32(di->core, DMA64RXREGOFFS(di, addrlow), + pa + di->ddoffsetlow); + bcma_write32(di->core, DMA64RXREGOFFS(di, addrhigh), + di->ddoffsethigh); } } else { /* DMA64 32bits address extension */ @@ -795,15 +812,19 @@ _dma_ddtable_init(struct dma_info *di, uint direction, dma_addr_t pa) pa &= ~PCI32ADDR_HIGH; if (direction == DMA_TX) { - W_REG(&di->d64txregs->addrlow, pa + di->ddoffsetlow); - W_REG(&di->d64txregs->addrhigh, di->ddoffsethigh); - SET_REG(&di->d64txregs->control, - D64_XC_AE, (ae << D64_XC_AE_SHIFT)); + bcma_write32(di->core, DMA64TXREGOFFS(di, addrlow), + pa + di->ddoffsetlow); + bcma_write32(di->core, DMA64TXREGOFFS(di, addrhigh), + di->ddoffsethigh); + bcma_maskset32(di->core, DMA64TXREGOFFS(di, control), + D64_XC_AE, (ae << D64_XC_AE_SHIFT)); } else { - W_REG(&di->d64rxregs->addrlow, pa + di->ddoffsetlow); - W_REG(&di->d64rxregs->addrhigh, di->ddoffsethigh); - SET_REG(&di->d64rxregs->control, - D64_RC_AE, (ae << D64_RC_AE_SHIFT)); + bcma_write32(di->core, DMA64RXREGOFFS(di, addrlow), + pa + di->ddoffsetlow); + bcma_write32(di->core, DMA64RXREGOFFS(di, addrhigh), + di->ddoffsethigh); + bcma_maskset32(di->core, DMA64RXREGOFFS(di, control), + D64_RC_AE, (ae << D64_RC_AE_SHIFT)); } } } @@ -815,9 +836,9 @@ static void _dma_rxenable(struct dma_info *di) DMA_TRACE("%s:\n", di->name); - control = - (R_REG(&di->d64rxregs->control) & D64_RC_AE) | - D64_RC_RE; + control = D64_RC_RE | (bcma_read32(di->core, + DMA64RXREGOFFS(di, control)) & + D64_RC_AE); if ((dmactrlflags & DMA_CTRL_PEN) == 0) control |= D64_RC_PD; @@ -825,7 +846,7 @@ static void _dma_rxenable(struct dma_info *di) if (dmactrlflags & DMA_CTRL_ROC) control |= D64_RC_OC; - W_REG(&di->d64rxregs->control, + bcma_write32(di->core, DMA64RXREGOFFS(di, control), ((di->rxoffset << D64_RC_RO_SHIFT) | control)); } @@ -868,7 +889,8 @@ static struct sk_buff *dma64_getnextrxp(struct dma_info *di, bool forceall) return NULL; curr = - B2I(((R_REG(&di->d64rxregs->status0) & D64_RS0_CD_MASK) - + B2I(((bcma_read32(di->core, + DMA64RXREGOFFS(di, status0)) & D64_RS0_CD_MASK) - di->rcvptrbase) & D64_RS0_CD_MASK, struct dma64desc); /* ignore curr if forceall */ @@ -882,7 +904,7 @@ static struct sk_buff *dma64_getnextrxp(struct dma_info *di, bool forceall) pa = le32_to_cpu(di->rxd64[i].addrlow) - di->dataoffsetlow; /* clear this packet from the descriptor ring */ - pci_unmap_single(di->pbus, pa, di->rxbufsize, PCI_DMA_FROMDEVICE); + dma_unmap_single(di->dmadev, pa, di->rxbufsize, DMA_FROM_DEVICE); di->rxd64[i].addrlow = cpu_to_le32(0xdeadbeef); di->rxd64[i].addrhigh = cpu_to_le32(0xdeadbeef); @@ -950,12 +972,12 @@ int dma_rx(struct dma_pub *pub, struct sk_buff_head *skb_list) if (resid > 0) { uint cur; cur = - B2I(((R_REG(&di->d64rxregs->status0) & - D64_RS0_CD_MASK) - - di->rcvptrbase) & D64_RS0_CD_MASK, - struct dma64desc); + B2I(((bcma_read32(di->core, + DMA64RXREGOFFS(di, status0)) & + D64_RS0_CD_MASK) - di->rcvptrbase) & + D64_RS0_CD_MASK, struct dma64desc); DMA_ERROR("rxin %d rxout %d, hw_curr %d\n", - di->rxin, di->rxout, cur); + di->rxin, di->rxout, cur); } #endif /* BCMDBG */ @@ -983,8 +1005,10 @@ static bool dma64_rxidle(struct dma_info *di) if (di->nrxd == 0) return true; - return ((R_REG(&di->d64rxregs->status0) & D64_RS0_CD_MASK) == - (R_REG(&di->d64rxregs->ptr) & D64_RS0_CD_MASK)); + return ((bcma_read32(di->core, + DMA64RXREGOFFS(di, status0)) & D64_RS0_CD_MASK) == + (bcma_read32(di->core, DMA64RXREGOFFS(di, ptr)) & + D64_RS0_CD_MASK)); } /* @@ -1048,8 +1072,8 @@ bool dma_rxfill(struct dma_pub *pub) */ *(u32 *) (p->data) = 0; - pa = pci_map_single(di->pbus, p->data, - di->rxbufsize, PCI_DMA_FROMDEVICE); + pa = dma_map_single(di->dmadev, p->data, di->rxbufsize, + DMA_FROM_DEVICE); /* save the free packet pointer */ di->rxp[rxout] = p; @@ -1067,7 +1091,7 @@ bool dma_rxfill(struct dma_pub *pub) di->rxout = rxout; /* update the chip lastdscr pointer */ - W_REG(&di->d64rxregs->ptr, + bcma_write32(di->core, DMA64RXREGOFFS(di, ptr), di->rcvptrbase + I2B(rxout, struct dma64desc)); return ring_empty; @@ -1128,7 +1152,7 @@ void dma_txinit(struct dma_pub *pub) if ((di->dma.dmactrlflags & DMA_CTRL_PEN) == 0) control |= D64_XC_PD; - OR_REG(&di->d64txregs->control, control); + bcma_set32(di->core, DMA64TXREGOFFS(di, control), control); /* DMA engine with alignment requirement requires table to be inited * before enabling the engine @@ -1146,7 +1170,7 @@ void dma_txsuspend(struct dma_pub *pub) if (di->ntxd == 0) return; - OR_REG(&di->d64txregs->control, D64_XC_SE); + bcma_set32(di->core, DMA64TXREGOFFS(di, control), D64_XC_SE); } void dma_txresume(struct dma_pub *pub) @@ -1158,7 +1182,7 @@ void dma_txresume(struct dma_pub *pub) if (di->ntxd == 0) return; - AND_REG(&di->d64txregs->control, ~D64_XC_SE); + bcma_mask32(di->core, DMA64TXREGOFFS(di, control), ~D64_XC_SE); } bool dma_txsuspended(struct dma_pub *pub) @@ -1166,8 +1190,9 @@ bool dma_txsuspended(struct dma_pub *pub) struct dma_info *di = (struct dma_info *)pub; return (di->ntxd == 0) || - ((R_REG(&di->d64txregs->control) & D64_XC_SE) == - D64_XC_SE); + ((bcma_read32(di->core, + DMA64TXREGOFFS(di, control)) & D64_XC_SE) == + D64_XC_SE); } void dma_txreclaim(struct dma_pub *pub, enum txd_range range) @@ -1200,16 +1225,17 @@ bool dma_txreset(struct dma_pub *pub) return true; /* suspend tx DMA first */ - W_REG(&di->d64txregs->control, D64_XC_SE); + bcma_write32(di->core, DMA64TXREGOFFS(di, control), D64_XC_SE); SPINWAIT(((status = - (R_REG(&di->d64txregs->status0) & D64_XS0_XS_MASK)) - != D64_XS0_XS_DISABLED) && (status != D64_XS0_XS_IDLE) - && (status != D64_XS0_XS_STOPPED), 10000); + (bcma_read32(di->core, DMA64TXREGOFFS(di, status0)) & + D64_XS0_XS_MASK)) != D64_XS0_XS_DISABLED) && + (status != D64_XS0_XS_IDLE) && (status != D64_XS0_XS_STOPPED), + 10000); - W_REG(&di->d64txregs->control, 0); + bcma_write32(di->core, DMA64TXREGOFFS(di, control), 0); SPINWAIT(((status = - (R_REG(&di->d64txregs->status0) & D64_XS0_XS_MASK)) - != D64_XS0_XS_DISABLED), 10000); + (bcma_read32(di->core, DMA64TXREGOFFS(di, status0)) & + D64_XS0_XS_MASK)) != D64_XS0_XS_DISABLED), 10000); /* wait for the last transaction to complete */ udelay(300); @@ -1225,10 +1251,10 @@ bool dma_rxreset(struct dma_pub *pub) if (di->nrxd == 0) return true; - W_REG(&di->d64rxregs->control, 0); + bcma_write32(di->core, DMA64RXREGOFFS(di, control), 0); SPINWAIT(((status = - (R_REG(&di->d64rxregs->status0) & D64_RS0_RS_MASK)) - != D64_RS0_RS_DISABLED), 10000); + (bcma_read32(di->core, DMA64RXREGOFFS(di, status0)) & + D64_RS0_RS_MASK)) != D64_RS0_RS_DISABLED), 10000); return status == D64_RS0_RS_DISABLED; } @@ -1239,10 +1265,9 @@ bool dma_rxreset(struct dma_pub *pub) * the error(toss frames) could be fatal and cause many subsequent hard * to debug problems */ -int dma_txfast(struct dma_pub *pub, struct sk_buff *p0, bool commit) +int dma_txfast(struct dma_pub *pub, struct sk_buff *p, bool commit) { struct dma_info *di = (struct dma_info *)pub; - struct sk_buff *p, *next; unsigned char *data; uint len; u16 txout; @@ -1254,57 +1279,44 @@ int dma_txfast(struct dma_pub *pub, struct sk_buff *p0, bool commit) txout = di->txout; /* - * Walk the chain of packet buffers - * allocating and initializing transmit descriptor entries. + * obtain and initialize transmit descriptor entry. */ - for (p = p0; p; p = next) { - data = p->data; - len = p->len; - next = p->next; - - /* return nonzero if out of tx descriptors */ - if (nexttxd(di, txout) == di->txin) - goto outoftxd; - - if (len == 0) - continue; + data = p->data; + len = p->len; - /* get physical address of buffer start */ - pa = pci_map_single(di->pbus, data, len, PCI_DMA_TODEVICE); + /* no use to transmit a zero length packet */ + if (len == 0) + return 0; - flags = 0; - if (p == p0) - flags |= D64_CTRL1_SOF; + /* return nonzero if out of tx descriptors */ + if (nexttxd(di, txout) == di->txin) + goto outoftxd; - /* With a DMA segment list, Descriptor table is filled - * using the segment list instead of looping over - * buffers in multi-chain DMA. Therefore, EOF for SGLIST - * is when end of segment list is reached. - */ - if (next == NULL) - flags |= (D64_CTRL1_IOC | D64_CTRL1_EOF); - if (txout == (di->ntxd - 1)) - flags |= D64_CTRL1_EOT; + /* get physical address of buffer start */ + pa = dma_map_single(di->dmadev, data, len, DMA_TO_DEVICE); - dma64_dd_upd(di, di->txd64, pa, txout, &flags, len); + /* With a DMA segment list, Descriptor table is filled + * using the segment list instead of looping over + * buffers in multi-chain DMA. Therefore, EOF for SGLIST + * is when end of segment list is reached. + */ + flags = D64_CTRL1_SOF | D64_CTRL1_IOC | D64_CTRL1_EOF; + if (txout == (di->ntxd - 1)) + flags |= D64_CTRL1_EOT; - txout = nexttxd(di, txout); - } + dma64_dd_upd(di, di->txd64, pa, txout, &flags, len); - /* if last txd eof not set, fix it */ - if (!(flags & D64_CTRL1_EOF)) - di->txd64[prevtxd(di, txout)].ctrl1 = - cpu_to_le32(flags | D64_CTRL1_IOC | D64_CTRL1_EOF); + txout = nexttxd(di, txout); /* save the packet */ - di->txp[prevtxd(di, txout)] = p0; + di->txp[prevtxd(di, txout)] = p; /* bump the tx descriptor index */ di->txout = txout; /* kick the chip */ if (commit) - W_REG(&di->d64txregs->ptr, + bcma_write32(di->core, DMA64TXREGOFFS(di, ptr), di->xmtptrbase + I2B(txout, struct dma64desc)); /* tx flow control */ @@ -1314,7 +1326,7 @@ int dma_txfast(struct dma_pub *pub, struct sk_buff *p0, bool commit) outoftxd: DMA_ERROR("%s: out of txds !!!\n", di->name); - brcmu_pkt_buf_free_skb(p0); + brcmu_pkt_buf_free_skb(p); di->dma.txavail = 0; di->dma.txnobuf++; return -1; @@ -1352,16 +1364,15 @@ struct sk_buff *dma_getnexttxp(struct dma_pub *pub, enum txd_range range) if (range == DMA_RANGE_ALL) end = di->txout; else { - struct dma64regs __iomem *dregs = di->d64txregs; - - end = (u16) (B2I(((R_REG(&dregs->status0) & - D64_XS0_CD_MASK) - - di->xmtptrbase) & D64_XS0_CD_MASK, - struct dma64desc)); + end = (u16) (B2I(((bcma_read32(di->core, + DMA64TXREGOFFS(di, status0)) & + D64_XS0_CD_MASK) - di->xmtptrbase) & + D64_XS0_CD_MASK, struct dma64desc)); if (range == DMA_RANGE_TRANSFERED) { active_desc = - (u16) (R_REG(&dregs->status1) & + (u16)(bcma_read32(di->core, + DMA64TXREGOFFS(di, status1)) & D64_XS1_AD_MASK); active_desc = (active_desc - di->xmtptrbase) & D64_XS0_CD_MASK; @@ -1390,7 +1401,7 @@ struct sk_buff *dma_getnexttxp(struct dma_pub *pub, enum txd_range range) txp = di->txp[i]; di->txp[i] = NULL; - pci_unmap_single(di->pbus, pa, size, PCI_DMA_TODEVICE); + dma_unmap_single(di->dmadev, pa, size, DMA_TO_DEVICE); } di->txin = i; diff --git a/drivers/net/wireless/brcm80211/brcmsmac/dma.h b/drivers/net/wireless/brcm80211/brcmsmac/dma.h index d317c7c12f91..cc269ee5c499 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/dma.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/dma.h @@ -75,10 +75,11 @@ struct dma_pub { }; extern struct dma_pub *dma_attach(char *name, struct si_pub *sih, - void __iomem *dmaregstx, void __iomem *dmaregsrx, - uint ntxd, uint nrxd, - uint rxbufsize, int rxextheadroom, - uint nrxpost, uint rxoffset, uint *msg_level); + struct bcma_device *d11core, + uint txregbase, uint rxregbase, + uint ntxd, uint nrxd, + uint rxbufsize, int rxextheadroom, + uint nrxpost, uint rxoffset, uint *msg_level); void dma_rxinit(struct dma_pub *pub); int dma_rx(struct dma_pub *pub, struct sk_buff_head *skb_list); diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index ba3e4b5cba71..d106576ce338 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c @@ -17,11 +17,11 @@ #define __UNDEF_NO_VERSION__ #include <linux/etherdevice.h> -#include <linux/pci.h> #include <linux/sched.h> #include <linux/firmware.h> #include <linux/interrupt.h> #include <linux/module.h> +#include <linux/bcma/bcma.h> #include <net/mac80211.h> #include <defs.h> #include "nicpci.h" @@ -40,10 +40,10 @@ #define MAC_FILTERS (FIF_PROMISC_IN_BSS | \ FIF_ALLMULTI | \ FIF_FCSFAIL | \ - FIF_PLCPFAIL | \ FIF_CONTROL | \ FIF_OTHER_BSS | \ - FIF_BCN_PRBRESP_PROMISC) + FIF_BCN_PRBRESP_PROMISC | \ + FIF_PSPOLL) #define CHAN2GHZ(channel, freqency, chflags) { \ .band = IEEE80211_BAND_2GHZ, \ @@ -87,16 +87,14 @@ MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN driver."); MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN cards"); MODULE_LICENSE("Dual BSD/GPL"); -/* recognized PCI IDs */ -static DEFINE_PCI_DEVICE_TABLE(brcms_pci_id_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) }, /* 43225 2G */ - { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) }, /* 43224 DUAL */ - { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) }, /* 4313 DUAL */ - { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) }, /* 43224 Ven */ - {0} -}; -MODULE_DEVICE_TABLE(pci, brcms_pci_id_table); +/* recognized BCMA Core IDs */ +static struct bcma_device_id brcms_coreid_table[] = { + BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 23, BCMA_ANY_CLASS), + BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 24, BCMA_ANY_CLASS), + BCMA_CORETABLE_END +}; +MODULE_DEVICE_TABLE(bcma, brcms_coreid_table); #ifdef BCMDBG static int msglevel = 0xdeadbeef; @@ -373,7 +371,7 @@ static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed) conf->listen_interval); } if (changed & IEEE80211_CONF_CHANGE_MONITOR) - wiphy_err(wiphy, "%s: change monitor mode: %s (implement)\n", + wiphy_dbg(wiphy, "%s: change monitor mode: %s\n", __func__, conf->flags & IEEE80211_CONF_MONITOR ? "true" : "false"); if (changed & IEEE80211_CONF_CHANGE_PS) @@ -550,29 +548,25 @@ brcms_ops_configure_filter(struct ieee80211_hw *hw, changed_flags &= MAC_FILTERS; *total_flags &= MAC_FILTERS; + if (changed_flags & FIF_PROMISC_IN_BSS) - wiphy_err(wiphy, "FIF_PROMISC_IN_BSS\n"); + wiphy_dbg(wiphy, "FIF_PROMISC_IN_BSS\n"); if (changed_flags & FIF_ALLMULTI) - wiphy_err(wiphy, "FIF_ALLMULTI\n"); + wiphy_dbg(wiphy, "FIF_ALLMULTI\n"); if (changed_flags & FIF_FCSFAIL) - wiphy_err(wiphy, "FIF_FCSFAIL\n"); - if (changed_flags & FIF_PLCPFAIL) - wiphy_err(wiphy, "FIF_PLCPFAIL\n"); + wiphy_dbg(wiphy, "FIF_FCSFAIL\n"); if (changed_flags & FIF_CONTROL) - wiphy_err(wiphy, "FIF_CONTROL\n"); + wiphy_dbg(wiphy, "FIF_CONTROL\n"); if (changed_flags & FIF_OTHER_BSS) - wiphy_err(wiphy, "FIF_OTHER_BSS\n"); - if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { - spin_lock_bh(&wl->lock); - if (*total_flags & FIF_BCN_PRBRESP_PROMISC) { - wl->pub->mac80211_state |= MAC80211_PROMISC_BCNS; - brcms_c_mac_bcn_promisc_change(wl->wlc, 1); - } else { - brcms_c_mac_bcn_promisc_change(wl->wlc, 0); - wl->pub->mac80211_state &= ~MAC80211_PROMISC_BCNS; - } - spin_unlock_bh(&wl->lock); - } + wiphy_dbg(wiphy, "FIF_OTHER_BSS\n"); + if (changed_flags & FIF_PSPOLL) + wiphy_dbg(wiphy, "FIF_PSPOLL\n"); + if (changed_flags & FIF_BCN_PRBRESP_PROMISC) + wiphy_dbg(wiphy, "FIF_BCN_PRBRESP_PROMISC\n"); + + spin_lock_bh(&wl->lock); + brcms_c_mac_promisc(wl->wlc, *total_flags); + spin_unlock_bh(&wl->lock); return; } @@ -728,7 +722,7 @@ static const struct ieee80211_ops brcms_ops = { }; /* - * is called in brcms_pci_probe() context, therefore no locking required. + * is called in brcms_bcma_probe() context, therefore no locking required. */ static int brcms_set_hint(struct brcms_info *wl, char *abbrev) { @@ -868,25 +862,15 @@ static void brcms_free(struct brcms_info *wl) #endif kfree(t); } - - /* - * unregister_netdev() calls get_stats() which may read chip - * registers so we cannot unmap the chip registers until - * after calling unregister_netdev() . - */ - if (wl->regsva) - iounmap(wl->regsva); - - wl->regsva = NULL; } /* * called from both kernel as from this kernel module (error flow on attach) * precondition: perimeter lock is not acquired. */ -static void brcms_remove(struct pci_dev *pdev) +static void brcms_remove(struct bcma_device *pdev) { - struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct ieee80211_hw *hw = bcma_get_drvdata(pdev); struct brcms_info *wl = hw->priv; if (wl->wlc) { @@ -894,11 +878,10 @@ static void brcms_remove(struct pci_dev *pdev) wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy); ieee80211_unregister_hw(hw); } - pci_disable_device(pdev); brcms_free(wl); - pci_set_drvdata(pdev, NULL); + bcma_set_drvdata(pdev, NULL); ieee80211_free_hw(hw); } @@ -1006,11 +989,9 @@ static int ieee_hw_init(struct ieee80211_hw *hw) * it as static. * * - * is called in brcms_pci_probe() context, therefore no locking required. + * is called in brcms_bcma_probe() context, therefore no locking required. */ -static struct brcms_info *brcms_attach(u16 vendor, u16 device, - resource_size_t regs, - struct pci_dev *btparam, uint irq) +static struct brcms_info *brcms_attach(struct bcma_device *pdev) { struct brcms_info *wl = NULL; int unit, err; @@ -1024,7 +1005,7 @@ static struct brcms_info *brcms_attach(u16 vendor, u16 device, return NULL; /* allocate private info */ - hw = pci_get_drvdata(btparam); /* btparam == pdev */ + hw = bcma_get_drvdata(pdev); if (hw != NULL) wl = hw->priv; if (WARN_ON(hw == NULL) || WARN_ON(wl == NULL)) @@ -1036,26 +1017,20 @@ static struct brcms_info *brcms_attach(u16 vendor, u16 device, /* setup the bottom half handler */ tasklet_init(&wl->tasklet, brcms_dpc, (unsigned long) wl); - wl->regsva = ioremap_nocache(regs, PCI_BAR0_WINSZ); - if (wl->regsva == NULL) { - wiphy_err(wl->wiphy, "wl%d: ioremap() failed\n", unit); - goto fail; - } spin_lock_init(&wl->lock); spin_lock_init(&wl->isr_lock); /* prepare ucode */ - if (brcms_request_fw(wl, btparam) < 0) { + if (brcms_request_fw(wl, pdev->bus->host_pci) < 0) { wiphy_err(wl->wiphy, "%s: Failed to find firmware usually in " "%s\n", KBUILD_MODNAME, "/lib/firmware/brcm"); brcms_release_fw(wl); - brcms_remove(btparam); + brcms_remove(pdev); return NULL; } /* common load-time initialization */ - wl->wlc = brcms_c_attach(wl, vendor, device, unit, false, - wl->regsva, btparam, &err); + wl->wlc = brcms_c_attach((void *)wl, pdev, unit, false, &err); brcms_release_fw(wl); if (!wl->wlc) { wiphy_err(wl->wiphy, "%s: attach() failed with code %d\n", @@ -1067,11 +1042,12 @@ static struct brcms_info *brcms_attach(u16 vendor, u16 device, wl->pub->ieee_hw = hw; /* register our interrupt handler */ - if (request_irq(irq, brcms_isr, IRQF_SHARED, KBUILD_MODNAME, wl)) { + if (request_irq(pdev->bus->host_pci->irq, brcms_isr, + IRQF_SHARED, KBUILD_MODNAME, wl)) { wiphy_err(wl->wiphy, "wl%d: request_irq() failed\n", unit); goto fail; } - wl->irq = irq; + wl->irq = pdev->bus->host_pci->irq; /* register module */ brcms_c_module_register(wl->pub, "linux", wl, NULL); @@ -1118,37 +1094,18 @@ fail: * * Perimeter lock is initialized in the course of this function. */ -static int __devinit -brcms_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +static int __devinit brcms_bcma_probe(struct bcma_device *pdev) { - int rc; struct brcms_info *wl; struct ieee80211_hw *hw; - u32 val; - - dev_info(&pdev->dev, "bus %d slot %d func %d irq %d\n", - pdev->bus->number, PCI_SLOT(pdev->devfn), - PCI_FUNC(pdev->devfn), pdev->irq); - if ((pdev->vendor != PCI_VENDOR_ID_BROADCOM) || - ((pdev->device != 0x0576) && - ((pdev->device & 0xff00) != 0x4300) && - ((pdev->device & 0xff00) != 0x4700) && - ((pdev->device < 43000) || (pdev->device > 43999)))) - return -ENODEV; + dev_info(&pdev->dev, "mfg %x core %x rev %d class %d irq %d\n", + pdev->id.manuf, pdev->id.id, pdev->id.rev, pdev->id.class, + pdev->bus->host_pci->irq); - rc = pci_enable_device(pdev); - if (rc) { - pr_err("%s: Cannot enable device %d-%d_%d\n", - __func__, pdev->bus->number, PCI_SLOT(pdev->devfn), - PCI_FUNC(pdev->devfn)); + if ((pdev->id.manuf != BCMA_MANUF_BCM) || + (pdev->id.id != BCMA_CORE_80211)) return -ENODEV; - } - pci_set_master(pdev); - - pci_read_config_dword(pdev, 0x40, &val); - if ((val & 0x0000ff00) != 0) - pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); hw = ieee80211_alloc_hw(sizeof(struct brcms_info), &brcms_ops); if (!hw) { @@ -1158,14 +1115,11 @@ brcms_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) SET_IEEE80211_DEV(hw, &pdev->dev); - pci_set_drvdata(pdev, hw); + bcma_set_drvdata(pdev, hw); memset(hw->priv, 0, sizeof(*wl)); - wl = brcms_attach(pdev->vendor, pdev->device, - pci_resource_start(pdev, 0), pdev, - pdev->irq); - + wl = brcms_attach(pdev); if (!wl) { pr_err("%s: %s: brcms_attach failed!\n", KBUILD_MODNAME, __func__); @@ -1174,16 +1128,23 @@ brcms_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return 0; } -static int brcms_suspend(struct pci_dev *pdev, pm_message_t state) +static int brcms_pci_suspend(struct pci_dev *pdev) +{ + pci_save_state(pdev); + pci_disable_device(pdev); + return pci_set_power_state(pdev, PCI_D3hot); +} + +static int brcms_suspend(struct bcma_device *pdev, pm_message_t state) { struct brcms_info *wl; struct ieee80211_hw *hw; - hw = pci_get_drvdata(pdev); + hw = bcma_get_drvdata(pdev); wl = hw->priv; if (!wl) { wiphy_err(wl->wiphy, - "brcms_suspend: pci_get_drvdata failed\n"); + "brcms_suspend: bcma_get_drvdata failed\n"); return -ENODEV; } @@ -1192,25 +1153,14 @@ static int brcms_suspend(struct pci_dev *pdev, pm_message_t state) wl->pub->hw_up = false; spin_unlock_bh(&wl->lock); - pci_save_state(pdev); - pci_disable_device(pdev); - return pci_set_power_state(pdev, PCI_D3hot); + /* temporarily do suspend ourselves */ + return brcms_pci_suspend(pdev->bus->host_pci); } -static int brcms_resume(struct pci_dev *pdev) +static int brcms_pci_resume(struct pci_dev *pdev) { - struct brcms_info *wl; - struct ieee80211_hw *hw; int err = 0; - u32 val; - - hw = pci_get_drvdata(pdev); - wl = hw->priv; - if (!wl) { - wiphy_err(wl->wiphy, - "wl: brcms_resume: pci_get_drvdata failed\n"); - return -ENODEV; - } + uint val; err = pci_set_power_state(pdev, PCI_D0); if (err) @@ -1228,24 +1178,28 @@ static int brcms_resume(struct pci_dev *pdev) if ((val & 0x0000ff00) != 0) pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); + return 0; +} + +static int brcms_resume(struct bcma_device *pdev) +{ /* - * done. driver will be put in up state - * in brcms_ops_add_interface() call. + * just do pci resume for now until bcma supports it. */ - return err; + return brcms_pci_resume(pdev->bus->host_pci); } -static struct pci_driver brcms_pci_driver = { +static struct bcma_driver brcms_bcma_driver = { .name = KBUILD_MODNAME, - .probe = brcms_pci_probe, + .probe = brcms_bcma_probe, .suspend = brcms_suspend, .resume = brcms_resume, .remove = __devexit_p(brcms_remove), - .id_table = brcms_pci_id_table, + .id_table = brcms_coreid_table, }; /** - * This is the main entry point for the WL driver. + * This is the main entry point for the brcmsmac driver. * * This function determines if a device pointed to by pdev is a WL device, * and if so, performs a brcms_attach() on it. @@ -1260,26 +1214,24 @@ static int __init brcms_module_init(void) brcm_msg_level = msglevel; #endif /* BCMDBG */ - error = pci_register_driver(&brcms_pci_driver); + error = bcma_driver_register(&brcms_bcma_driver); + printk(KERN_ERR "%s: register returned %d\n", __func__, error); if (!error) return 0; - - return error; } /** - * This function unloads the WL driver from the system. + * This function unloads the brcmsmac driver from the system. * - * This function unconditionally unloads the WL driver module from the + * This function unconditionally unloads the brcmsmac driver module from the * system. * */ static void __exit brcms_module_exit(void) { - pci_unregister_driver(&brcms_pci_driver); - + bcma_driver_unregister(&brcms_bcma_driver); } module_init(brcms_module_init); @@ -1313,7 +1265,7 @@ uint brcms_reset(struct brcms_info *wl) brcms_c_reset(wl->wlc); /* dpc will not be rescheduled */ - wl->resched = 0; + wl->resched = false; return 0; } @@ -1566,7 +1518,7 @@ fail: } /* - * Precondition: Since this function is called in brcms_pci_probe() context, + * Precondition: Since this function is called in brcms_bcma_probe() context, * no locking is required. */ int brcms_ucode_init_uint(struct brcms_info *wl, size_t *n_bytes, u32 idx) @@ -1606,7 +1558,7 @@ void brcms_ucode_free_buf(void *p) /* * checks validity of all firmware images loaded from user space * - * Precondition: Since this function is called in brcms_pci_probe() context, + * Precondition: Since this function is called in brcms_bcma_probe() context, * no locking is required. */ int brcms_check_firmwares(struct brcms_info *wl) diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h index 6242f188b717..8f60419c37bf 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h @@ -68,8 +68,6 @@ struct brcms_info { spinlock_t lock; /* per-device perimeter lock */ spinlock_t isr_lock; /* per-device ISR synchronization lock */ - /* regsva for unmap in brcms_free() */ - void __iomem *regsva; /* opaque chip registers virtual address */ /* timer related fields */ atomic_t callbacks; /* # outstanding callback functions */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c index 36e3e0638300..f7ed34034f88 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c @@ -388,10 +388,13 @@ static u16 get_sifs(struct brcms_band *band) */ static bool brcms_deviceremoved(struct brcms_c_info *wlc) { + u32 macctrl; + if (!wlc->hw->clk) return ai_deviceremoved(wlc->hw->sih); - return (R_REG(&wlc->hw->regs->maccontrol) & - (MCTL_PSM_JMP_0 | MCTL_IHR_EN)) != MCTL_IHR_EN; + macctrl = bcma_read32(wlc->hw->d11core, + D11REGOFFS(maccontrol)); + return (macctrl & (MCTL_PSM_JMP_0 | MCTL_IHR_EN)) != MCTL_IHR_EN; } /* sum the individual fifo tx pending packet counts */ @@ -582,17 +585,15 @@ brcms_c_attach_malloc(uint unit, uint *err, uint devid) static void brcms_b_update_slot_timing(struct brcms_hardware *wlc_hw, bool shortslot) { - struct d11regs __iomem *regs; - - regs = wlc_hw->regs; + struct bcma_device *core = wlc_hw->d11core; if (shortslot) { /* 11g short slot: 11a timing */ - W_REG(®s->ifs_slot, 0x0207); /* APHY_SLOT_TIME */ + bcma_write16(core, D11REGOFFS(ifs_slot), 0x0207); brcms_b_write_shm(wlc_hw, M_DOT11_SLOT, APHY_SLOT_TIME); } else { /* 11g long slot: 11b timing */ - W_REG(®s->ifs_slot, 0x0212); /* BPHY_SLOT_TIME */ + bcma_write16(core, D11REGOFFS(ifs_slot), 0x0212); brcms_b_write_shm(wlc_hw, M_DOT11_SLOT, BPHY_SLOT_TIME); } } @@ -672,24 +673,22 @@ static uint brcms_c_calc_frame_time(struct brcms_c_info *wlc, u32 ratespec, static void brcms_c_write_inits(struct brcms_hardware *wlc_hw, const struct d11init *inits) { + struct bcma_device *core = wlc_hw->d11core; int i; - u8 __iomem *base; - u8 __iomem *addr; + uint offset; u16 size; u32 value; BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); - base = (u8 __iomem *)wlc_hw->regs; - for (i = 0; inits[i].addr != cpu_to_le16(0xffff); i++) { size = le16_to_cpu(inits[i].size); - addr = base + le16_to_cpu(inits[i].addr); + offset = le16_to_cpu(inits[i].addr); value = le32_to_cpu(inits[i].value); if (size == 2) - W_REG((u16 __iomem *)addr, value); + bcma_write16(core, offset, value); else if (size == 4) - W_REG((u32 __iomem *)addr, value); + bcma_write32(core, offset, value); else break; } @@ -739,6 +738,14 @@ static void brcms_c_ucode_bsinit(struct brcms_hardware *wlc_hw) } } +static void brcms_b_core_ioctl(struct brcms_hardware *wlc_hw, u32 m, u32 v) +{ + struct bcma_device *core = wlc_hw->d11core; + u32 ioctl = bcma_aread32(core, BCMA_IOCTL) & ~m; + + bcma_awrite32(core, BCMA_IOCTL, ioctl | v); +} + static void brcms_b_core_phy_clk(struct brcms_hardware *wlc_hw, bool clk) { BCMMSG(wlc_hw->wlc->wiphy, "wl%d: clk %d\n", wlc_hw->unit, clk); @@ -747,17 +754,17 @@ static void brcms_b_core_phy_clk(struct brcms_hardware *wlc_hw, bool clk) if (OFF == clk) { /* clear gmode bit, put phy into reset */ - ai_core_cflags(wlc_hw->sih, (SICF_PRST | SICF_FGC | SICF_GMODE), - (SICF_PRST | SICF_FGC)); + brcms_b_core_ioctl(wlc_hw, (SICF_PRST | SICF_FGC | SICF_GMODE), + (SICF_PRST | SICF_FGC)); udelay(1); - ai_core_cflags(wlc_hw->sih, (SICF_PRST | SICF_FGC), SICF_PRST); + brcms_b_core_ioctl(wlc_hw, (SICF_PRST | SICF_FGC), SICF_PRST); udelay(1); } else { /* take phy out of reset */ - ai_core_cflags(wlc_hw->sih, (SICF_PRST | SICF_FGC), SICF_FGC); + brcms_b_core_ioctl(wlc_hw, (SICF_PRST | SICF_FGC), SICF_FGC); udelay(1); - ai_core_cflags(wlc_hw->sih, (SICF_FGC), 0); + brcms_b_core_ioctl(wlc_hw, SICF_FGC, 0); udelay(1); } @@ -778,9 +785,14 @@ static void brcms_c_setxband(struct brcms_hardware *wlc_hw, uint bandunit) wlc_hw->wlc->band = wlc_hw->wlc->bandstate[bandunit]; /* set gmode core flag */ - if (wlc_hw->sbclk && !wlc_hw->noreset) - ai_core_cflags(wlc_hw->sih, SICF_GMODE, - ((bandunit == 0) ? SICF_GMODE : 0)); + if (wlc_hw->sbclk && !wlc_hw->noreset) { + u32 gmode = 0; + + if (bandunit == 0) + gmode = SICF_GMODE; + + brcms_b_core_ioctl(wlc_hw, SICF_GMODE, gmode); + } } /* switch to new band but leave it inactive */ @@ -788,10 +800,12 @@ static u32 brcms_c_setband_inact(struct brcms_c_info *wlc, uint bandunit) { struct brcms_hardware *wlc_hw = wlc->hw; u32 macintmask; + u32 macctrl; BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit); - - WARN_ON((R_REG(&wlc_hw->regs->maccontrol) & MCTL_EN_MAC) != 0); + macctrl = bcma_read32(wlc_hw->d11core, + D11REGOFFS(maccontrol)); + WARN_ON((macctrl & MCTL_EN_MAC) != 0); /* disable interrupts */ macintmask = brcms_intrsoff(wlc->wl); @@ -955,8 +969,6 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs) brcms_c_txfifo_complete(wlc, queue, 1); if (lastframe) { - p->next = NULL; - p->prev = NULL; /* remove PLCP & Broadcom tx descriptor header */ skb_pull(p, D11_PHY_HDR_LEN); skb_pull(p, D11_TXH_LEN); @@ -984,7 +996,7 @@ brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal) { bool morepending = false; struct brcms_c_info *wlc = wlc_hw->wlc; - struct d11regs __iomem *regs; + struct bcma_device *core; struct tx_status txstatus, *txs; u32 s1, s2; uint n = 0; @@ -997,18 +1009,18 @@ brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal) BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit); txs = &txstatus; - regs = wlc_hw->regs; + core = wlc_hw->d11core; *fatal = false; + s1 = bcma_read32(core, D11REGOFFS(frmtxstatus)); while (!(*fatal) - && (s1 = R_REG(®s->frmtxstatus)) & TXS_V) { + && (s1 & TXS_V)) { if (s1 == 0xffffffff) { wiphy_err(wlc->wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit, __func__); return morepending; } - - s2 = R_REG(®s->frmtxstatus2); + s2 = bcma_read32(core, D11REGOFFS(frmtxstatus2)); txs->status = s1 & TXS_STATUS_MASK; txs->frameid = (s1 & TXS_FID_MASK) >> TXS_FID_SHIFT; @@ -1021,6 +1033,7 @@ brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal) /* !give others some time to run! */ if (++n >= max_tx_num) break; + s1 = bcma_read32(core, D11REGOFFS(frmtxstatus)); } if (*fatal) @@ -1065,12 +1078,12 @@ brcms_c_mhfdef(struct brcms_c_info *wlc, u16 *mhfs, u16 mhf2_init) } } -static struct dma64regs __iomem * -dmareg(struct brcms_hardware *hw, uint direction, uint fifonum) +static uint +dmareg(uint direction, uint fifonum) { if (direction == DMA_TX) - return &(hw->regs->fifo64regs[fifonum].dmaxmt); - return &(hw->regs->fifo64regs[fifonum].dmarcv); + return offsetof(struct d11regs, fifo64regs[fifonum].dmaxmt); + return offsetof(struct d11regs, fifo64regs[fifonum].dmarcv); } static bool brcms_b_attach_dmapio(struct brcms_c_info *wlc, uint j, bool wme) @@ -1096,9 +1109,9 @@ static bool brcms_b_attach_dmapio(struct brcms_c_info *wlc, uint j, bool wme) * TX: TX_AC_BK_FIFO (TX AC Background data packets) * RX: RX_FIFO (RX data packets) */ - wlc_hw->di[0] = dma_attach(name, wlc_hw->sih, - (wme ? dmareg(wlc_hw, DMA_TX, 0) : - NULL), dmareg(wlc_hw, DMA_RX, 0), + wlc_hw->di[0] = dma_attach(name, wlc_hw->sih, wlc_hw->d11core, + (wme ? dmareg(DMA_TX, 0) : 0), + dmareg(DMA_RX, 0), (wme ? NTXD : 0), NRXD, RXBUFSZ, -1, NRXBUFPOST, BRCMS_HWRXOFF, &brcm_msg_level); @@ -1110,8 +1123,8 @@ static bool brcms_b_attach_dmapio(struct brcms_c_info *wlc, uint j, bool wme) * (legacy) TX_DATA_FIFO (TX data packets) * RX: UNUSED */ - wlc_hw->di[1] = dma_attach(name, wlc_hw->sih, - dmareg(wlc_hw, DMA_TX, 1), NULL, + wlc_hw->di[1] = dma_attach(name, wlc_hw->sih, wlc_hw->d11core, + dmareg(DMA_TX, 1), 0, NTXD, 0, 0, -1, 0, 0, &brcm_msg_level); dma_attach_err |= (NULL == wlc_hw->di[1]); @@ -1121,8 +1134,8 @@ static bool brcms_b_attach_dmapio(struct brcms_c_info *wlc, uint j, bool wme) * TX: TX_AC_VI_FIFO (TX AC Video data packets) * RX: UNUSED */ - wlc_hw->di[2] = dma_attach(name, wlc_hw->sih, - dmareg(wlc_hw, DMA_TX, 2), NULL, + wlc_hw->di[2] = dma_attach(name, wlc_hw->sih, wlc_hw->d11core, + dmareg(DMA_TX, 2), 0, NTXD, 0, 0, -1, 0, 0, &brcm_msg_level); dma_attach_err |= (NULL == wlc_hw->di[2]); @@ -1131,9 +1144,9 @@ static bool brcms_b_attach_dmapio(struct brcms_c_info *wlc, uint j, bool wme) * TX: TX_AC_VO_FIFO (TX AC Voice data packets) * (legacy) TX_CTL_FIFO (TX control & mgmt packets) */ - wlc_hw->di[3] = dma_attach(name, wlc_hw->sih, - dmareg(wlc_hw, DMA_TX, 3), - NULL, NTXD, 0, 0, -1, + wlc_hw->di[3] = dma_attach(name, wlc_hw->sih, wlc_hw->d11core, + dmareg(DMA_TX, 3), + 0, NTXD, 0, 0, -1, 0, 0, &brcm_msg_level); dma_attach_err |= (NULL == wlc_hw->di[3]); /* Cleaner to leave this as if with AP defined */ @@ -1207,7 +1220,7 @@ static void brcms_b_wait_for_wake(struct brcms_hardware *wlc_hw) /* control chip clock to save power, enable dynamic clock or force fast clock */ static void brcms_b_clkctl_clk(struct brcms_hardware *wlc_hw, uint mode) { - if (wlc_hw->sih->cccaps & CC_CAP_PMU) { + if (ai_get_cccaps(wlc_hw->sih) & CC_CAP_PMU) { /* new chips with PMU, CCS_FORCEHT will distribute the HT clock * on backplane, but mac core will still run on ALP(not HT) when * it enters powersave mode, which means the FCA bit may not be @@ -1216,29 +1229,33 @@ static void brcms_b_clkctl_clk(struct brcms_hardware *wlc_hw, uint mode) if (wlc_hw->clk) { if (mode == CLK_FAST) { - OR_REG(&wlc_hw->regs->clk_ctl_st, - CCS_FORCEHT); + bcma_set32(wlc_hw->d11core, + D11REGOFFS(clk_ctl_st), + CCS_FORCEHT); udelay(64); - SPINWAIT(((R_REG - (&wlc_hw->regs-> - clk_ctl_st) & CCS_HTAVAIL) == 0), - PMU_MAX_TRANSITION_DLY); - WARN_ON(!(R_REG - (&wlc_hw->regs-> - clk_ctl_st) & CCS_HTAVAIL)); + SPINWAIT( + ((bcma_read32(wlc_hw->d11core, + D11REGOFFS(clk_ctl_st)) & + CCS_HTAVAIL) == 0), + PMU_MAX_TRANSITION_DLY); + WARN_ON(!(bcma_read32(wlc_hw->d11core, + D11REGOFFS(clk_ctl_st)) & + CCS_HTAVAIL)); } else { - if ((wlc_hw->sih->pmurev == 0) && - (R_REG - (&wlc_hw->regs-> - clk_ctl_st) & (CCS_FORCEHT | CCS_HTAREQ))) - SPINWAIT(((R_REG - (&wlc_hw->regs-> - clk_ctl_st) & CCS_HTAVAIL) - == 0), - PMU_MAX_TRANSITION_DLY); - AND_REG(&wlc_hw->regs->clk_ctl_st, + if ((ai_get_pmurev(wlc_hw->sih) == 0) && + (bcma_read32(wlc_hw->d11core, + D11REGOFFS(clk_ctl_st)) & + (CCS_FORCEHT | CCS_HTAREQ))) + SPINWAIT( + ((bcma_read32(wlc_hw->d11core, + offsetof(struct d11regs, + clk_ctl_st)) & + CCS_HTAVAIL) == 0), + PMU_MAX_TRANSITION_DLY); + bcma_mask32(wlc_hw->d11core, + D11REGOFFS(clk_ctl_st), ~CCS_FORCEHT); } } @@ -1253,7 +1270,7 @@ static void brcms_b_clkctl_clk(struct brcms_hardware *wlc_hw, uint mode) /* check fast clock is available (if core is not in reset) */ if (wlc_hw->forcefastclk && wlc_hw->clk) - WARN_ON(!(ai_core_sflags(wlc_hw->sih, 0, 0) & + WARN_ON(!(bcma_aread32(wlc_hw->d11core, BCMA_IOST) & SISF_FCLKA)); /* @@ -1370,7 +1387,8 @@ static void brcms_c_mctrl_write(struct brcms_hardware *wlc_hw) maccontrol |= MCTL_INFRA; } - W_REG(&wlc_hw->regs->maccontrol, maccontrol); + bcma_write32(wlc_hw->d11core, D11REGOFFS(maccontrol), + maccontrol); } /* set or clear maccontrol bits */ @@ -1464,7 +1482,7 @@ static void brcms_b_set_addrmatch(struct brcms_hardware *wlc_hw, int match_reg_offset, const u8 *addr) { - struct d11regs __iomem *regs; + struct bcma_device *core = wlc_hw->d11core; u16 mac_l; u16 mac_m; u16 mac_h; @@ -1472,38 +1490,36 @@ brcms_b_set_addrmatch(struct brcms_hardware *wlc_hw, int match_reg_offset, BCMMSG(wlc_hw->wlc->wiphy, "wl%d: brcms_b_set_addrmatch\n", wlc_hw->unit); - regs = wlc_hw->regs; mac_l = addr[0] | (addr[1] << 8); mac_m = addr[2] | (addr[3] << 8); mac_h = addr[4] | (addr[5] << 8); /* enter the MAC addr into the RXE match registers */ - W_REG(®s->rcm_ctl, RCM_INC_DATA | match_reg_offset); - W_REG(®s->rcm_mat_data, mac_l); - W_REG(®s->rcm_mat_data, mac_m); - W_REG(®s->rcm_mat_data, mac_h); - + bcma_write16(core, D11REGOFFS(rcm_ctl), + RCM_INC_DATA | match_reg_offset); + bcma_write16(core, D11REGOFFS(rcm_mat_data), mac_l); + bcma_write16(core, D11REGOFFS(rcm_mat_data), mac_m); + bcma_write16(core, D11REGOFFS(rcm_mat_data), mac_h); } void brcms_b_write_template_ram(struct brcms_hardware *wlc_hw, int offset, int len, void *buf) { - struct d11regs __iomem *regs; + struct bcma_device *core = wlc_hw->d11core; u32 word; __le32 word_le; __be32 word_be; bool be_bit; BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); - regs = wlc_hw->regs; - W_REG(®s->tplatewrptr, offset); + bcma_write32(core, D11REGOFFS(tplatewrptr), offset); /* if MCTL_BIGEND bit set in mac control register, * the chip swaps data in fifo, as well as data in * template ram */ - be_bit = (R_REG(®s->maccontrol) & MCTL_BIGEND) != 0; + be_bit = (bcma_read32(core, D11REGOFFS(maccontrol)) & MCTL_BIGEND) != 0; while (len > 0) { memcpy(&word, buf, sizeof(u32)); @@ -1516,7 +1532,7 @@ brcms_b_write_template_ram(struct brcms_hardware *wlc_hw, int offset, int len, word = *(u32 *)&word_le; } - W_REG(®s->tplatewrdata, word); + bcma_write32(core, D11REGOFFS(tplatewrdata), word); buf = (u8 *) buf + sizeof(u32); len -= sizeof(u32); @@ -1527,18 +1543,20 @@ static void brcms_b_set_cwmin(struct brcms_hardware *wlc_hw, u16 newmin) { wlc_hw->band->CWmin = newmin; - W_REG(&wlc_hw->regs->objaddr, OBJADDR_SCR_SEL | S_DOT11_CWMIN); - (void)R_REG(&wlc_hw->regs->objaddr); - W_REG(&wlc_hw->regs->objdata, newmin); + bcma_write32(wlc_hw->d11core, D11REGOFFS(objaddr), + OBJADDR_SCR_SEL | S_DOT11_CWMIN); + (void)bcma_read32(wlc_hw->d11core, D11REGOFFS(objaddr)); + bcma_write32(wlc_hw->d11core, D11REGOFFS(objdata), newmin); } static void brcms_b_set_cwmax(struct brcms_hardware *wlc_hw, u16 newmax) { wlc_hw->band->CWmax = newmax; - W_REG(&wlc_hw->regs->objaddr, OBJADDR_SCR_SEL | S_DOT11_CWMAX); - (void)R_REG(&wlc_hw->regs->objaddr); - W_REG(&wlc_hw->regs->objdata, newmax); + bcma_write32(wlc_hw->d11core, D11REGOFFS(objaddr), + OBJADDR_SCR_SEL | S_DOT11_CWMAX); + (void)bcma_read32(wlc_hw->d11core, D11REGOFFS(objaddr)); + bcma_write32(wlc_hw->d11core, D11REGOFFS(objdata), newmax); } void brcms_b_bw_set(struct brcms_hardware *wlc_hw, u16 bw) @@ -1704,17 +1722,17 @@ void brcms_b_core_phypll_reset(struct brcms_hardware *wlc_hw) { BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); - ai_corereg(wlc_hw->sih, SI_CC_IDX, - offsetof(struct chipcregs, chipcontrol_addr), ~0, 0); + ai_cc_reg(wlc_hw->sih, offsetof(struct chipcregs, chipcontrol_addr), + ~0, 0); udelay(1); - ai_corereg(wlc_hw->sih, SI_CC_IDX, - offsetof(struct chipcregs, chipcontrol_data), 0x4, 0); + ai_cc_reg(wlc_hw->sih, offsetof(struct chipcregs, chipcontrol_data), + 0x4, 0); udelay(1); - ai_corereg(wlc_hw->sih, SI_CC_IDX, - offsetof(struct chipcregs, chipcontrol_data), 0x4, 4); + ai_cc_reg(wlc_hw->sih, offsetof(struct chipcregs, chipcontrol_data), + 0x4, 4); udelay(1); - ai_corereg(wlc_hw->sih, SI_CC_IDX, - offsetof(struct chipcregs, chipcontrol_data), 0x4, 0); + ai_cc_reg(wlc_hw->sih, offsetof(struct chipcregs, chipcontrol_data), + 0x4, 0); udelay(1); } @@ -1728,18 +1746,18 @@ void brcms_b_phyclk_fgc(struct brcms_hardware *wlc_hw, bool clk) return; if (ON == clk) - ai_core_cflags(wlc_hw->sih, SICF_FGC, SICF_FGC); + brcms_b_core_ioctl(wlc_hw, SICF_FGC, SICF_FGC); else - ai_core_cflags(wlc_hw->sih, SICF_FGC, 0); + brcms_b_core_ioctl(wlc_hw, SICF_FGC, 0); } void brcms_b_macphyclk_set(struct brcms_hardware *wlc_hw, bool clk) { if (ON == clk) - ai_core_cflags(wlc_hw->sih, SICF_MPCLKE, SICF_MPCLKE); + brcms_b_core_ioctl(wlc_hw, SICF_MPCLKE, SICF_MPCLKE); else - ai_core_cflags(wlc_hw->sih, SICF_MPCLKE, 0); + brcms_b_core_ioctl(wlc_hw, SICF_MPCLKE, 0); } void brcms_b_phy_reset(struct brcms_hardware *wlc_hw) @@ -1759,7 +1777,7 @@ void brcms_b_phy_reset(struct brcms_hardware *wlc_hw) if (BRCMS_ISNPHY(wlc_hw->band) && NREV_GE(wlc_hw->band->phyrev, 3) && NREV_LE(wlc_hw->band->phyrev, 4)) { /* Set the PHY bandwidth */ - ai_core_cflags(wlc_hw->sih, SICF_BWMASK, phy_bw_clkbits); + brcms_b_core_ioctl(wlc_hw, SICF_BWMASK, phy_bw_clkbits); udelay(1); @@ -1767,13 +1785,13 @@ void brcms_b_phy_reset(struct brcms_hardware *wlc_hw) brcms_b_core_phypll_reset(wlc_hw); /* reset the PHY */ - ai_core_cflags(wlc_hw->sih, (SICF_PRST | SICF_PCLKE), - (SICF_PRST | SICF_PCLKE)); + brcms_b_core_ioctl(wlc_hw, (SICF_PRST | SICF_PCLKE), + (SICF_PRST | SICF_PCLKE)); phy_in_reset = true; } else { - ai_core_cflags(wlc_hw->sih, - (SICF_PRST | SICF_PCLKE | SICF_BWMASK), - (SICF_PRST | SICF_PCLKE | phy_bw_clkbits)); + brcms_b_core_ioctl(wlc_hw, + (SICF_PRST | SICF_PCLKE | SICF_BWMASK), + (SICF_PRST | SICF_PCLKE | phy_bw_clkbits)); } udelay(2); @@ -1790,8 +1808,8 @@ static void brcms_b_setband(struct brcms_hardware *wlc_hw, uint bandunit, u32 macintmask; /* Enable the d11 core before accessing it */ - if (!ai_iscoreup(wlc_hw->sih)) { - ai_core_reset(wlc_hw->sih, 0, 0); + if (!bcma_core_is_enabled(wlc_hw->d11core)) { + bcma_core_enable(wlc_hw->d11core, 0); brcms_c_mctrl_reset(wlc_hw); } @@ -1817,7 +1835,8 @@ static void brcms_b_setband(struct brcms_hardware *wlc_hw, uint bandunit, brcms_intrsrestore(wlc->wl, macintmask); /* ucode should still be suspended.. */ - WARN_ON((R_REG(&wlc_hw->regs->maccontrol) & MCTL_EN_MAC) != 0); + WARN_ON((bcma_read32(wlc_hw->d11core, D11REGOFFS(maccontrol)) & + MCTL_EN_MAC) != 0); } static bool brcms_c_isgoodchip(struct brcms_hardware *wlc_hw) @@ -1845,7 +1864,7 @@ static bool brcms_c_validboardtype(struct brcms_hardware *wlc_hw) uint b2 = boardrev & 0xf; /* voards from other vendors are always considered valid */ - if (wlc_hw->sih->boardvendor != PCI_VENDOR_ID_BROADCOM) + if (ai_get_boardvendor(wlc_hw->sih) != PCI_VENDOR_ID_BROADCOM) return true; /* do some boardrev sanity checks when boardvendor is Broadcom */ @@ -1917,7 +1936,7 @@ static void brcms_b_xtal(struct brcms_hardware *wlc_hw, bool want) static bool brcms_b_radio_read_hwdisabled(struct brcms_hardware *wlc_hw) { bool v, clk, xtal; - u32 resetbits = 0, flags = 0; + u32 flags = 0; xtal = wlc_hw->sbclk; if (!xtal) @@ -1934,22 +1953,22 @@ static bool brcms_b_radio_read_hwdisabled(struct brcms_hardware *wlc_hw) flags |= SICF_PCLKE; /* + * TODO: test suspend/resume + * * AI chip doesn't restore bar0win2 on * hibernation/resume, need sw fixup */ - if ((wlc_hw->sih->chip == BCM43224_CHIP_ID) || - (wlc_hw->sih->chip == BCM43225_CHIP_ID)) - wlc_hw->regs = (struct d11regs __iomem *) - ai_setcore(wlc_hw->sih, D11_CORE_ID, 0); - ai_core_reset(wlc_hw->sih, flags, resetbits); + + bcma_core_enable(wlc_hw->d11core, flags); brcms_c_mctrl_reset(wlc_hw); } - v = ((R_REG(&wlc_hw->regs->phydebug) & PDBG_RFD) != 0); + v = ((bcma_read32(wlc_hw->d11core, + D11REGOFFS(phydebug)) & PDBG_RFD) != 0); /* put core back into reset */ if (!clk) - ai_core_disable(wlc_hw->sih, 0); + bcma_core_disable(wlc_hw->d11core, 0); if (!xtal) brcms_b_xtal(wlc_hw, OFF); @@ -1973,25 +1992,21 @@ static bool wlc_dma_rxreset(struct brcms_hardware *wlc_hw, uint fifo) */ void brcms_b_corereset(struct brcms_hardware *wlc_hw, u32 flags) { - struct d11regs __iomem *regs; uint i; bool fastclk; - u32 resetbits = 0; if (flags == BRCMS_USE_COREFLAGS) flags = (wlc_hw->band->pi ? wlc_hw->band->core_flags : 0); BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); - regs = wlc_hw->regs; - /* request FAST clock if not on */ fastclk = wlc_hw->forcefastclk; if (!fastclk) brcms_b_clkctl_clk(wlc_hw, CLK_FAST); /* reset the dma engines except first time thru */ - if (ai_iscoreup(wlc_hw->sih)) { + if (bcma_core_is_enabled(wlc_hw->d11core)) { for (i = 0; i < NFIFO; i++) if ((wlc_hw->di[i]) && (!dma_txreset(wlc_hw->di[i]))) wiphy_err(wlc_hw->wlc->wiphy, "wl%d: %s: " @@ -2029,14 +2044,14 @@ void brcms_b_corereset(struct brcms_hardware *wlc_hw, u32 flags) * they may touch chipcommon as well. */ wlc_hw->clk = false; - ai_core_reset(wlc_hw->sih, flags, resetbits); + bcma_core_enable(wlc_hw->d11core, flags); wlc_hw->clk = true; if (wlc_hw->band && wlc_hw->band->pi) wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, true); brcms_c_mctrl_reset(wlc_hw); - if (wlc_hw->sih->cccaps & CC_CAP_PMU) + if (ai_get_cccaps(wlc_hw->sih) & CC_CAP_PMU) brcms_b_clkctl_clk(wlc_hw, CLK_FAST); brcms_b_phy_reset(wlc_hw); @@ -2057,7 +2072,7 @@ void brcms_b_corereset(struct brcms_hardware *wlc_hw, u32 flags) */ static void brcms_b_corerev_fifofixup(struct brcms_hardware *wlc_hw) { - struct d11regs __iomem *regs = wlc_hw->regs; + struct bcma_device *core = wlc_hw->d11core; u16 fifo_nu; u16 txfifo_startblk = TXFIFO_START_BLK, txfifo_endblk; u16 txfifo_def, txfifo_def1; @@ -2078,11 +2093,11 @@ static void brcms_b_corerev_fifofixup(struct brcms_hardware *wlc_hw) txfifo_cmd = TXFIFOCMD_RESET_MASK | (fifo_nu << TXFIFOCMD_FIFOSEL_SHIFT); - W_REG(®s->xmtfifocmd, txfifo_cmd); - W_REG(®s->xmtfifodef, txfifo_def); - W_REG(®s->xmtfifodef1, txfifo_def1); + bcma_write16(core, D11REGOFFS(xmtfifocmd), txfifo_cmd); + bcma_write16(core, D11REGOFFS(xmtfifodef), txfifo_def); + bcma_write16(core, D11REGOFFS(xmtfifodef1), txfifo_def1); - W_REG(®s->xmtfifocmd, txfifo_cmd); + bcma_write16(core, D11REGOFFS(xmtfifocmd), txfifo_cmd); txfifo_startblk += wlc_hw->xmtfifo_sz[fifo_nu]; } @@ -2117,27 +2132,27 @@ static void brcms_b_corerev_fifofixup(struct brcms_hardware *wlc_hw) void brcms_b_switch_macfreq(struct brcms_hardware *wlc_hw, u8 spurmode) { - struct d11regs __iomem *regs = wlc_hw->regs; + struct bcma_device *core = wlc_hw->d11core; - if ((wlc_hw->sih->chip == BCM43224_CHIP_ID) || - (wlc_hw->sih->chip == BCM43225_CHIP_ID)) { + if ((ai_get_chip_id(wlc_hw->sih) == BCM43224_CHIP_ID) || + (ai_get_chip_id(wlc_hw->sih) == BCM43225_CHIP_ID)) { if (spurmode == WL_SPURAVOID_ON2) { /* 126Mhz */ - W_REG(®s->tsf_clk_frac_l, 0x2082); - W_REG(®s->tsf_clk_frac_h, 0x8); + bcma_write16(core, D11REGOFFS(tsf_clk_frac_l), 0x2082); + bcma_write16(core, D11REGOFFS(tsf_clk_frac_h), 0x8); } else if (spurmode == WL_SPURAVOID_ON1) { /* 123Mhz */ - W_REG(®s->tsf_clk_frac_l, 0x5341); - W_REG(®s->tsf_clk_frac_h, 0x8); + bcma_write16(core, D11REGOFFS(tsf_clk_frac_l), 0x5341); + bcma_write16(core, D11REGOFFS(tsf_clk_frac_h), 0x8); } else { /* 120Mhz */ - W_REG(®s->tsf_clk_frac_l, 0x8889); - W_REG(®s->tsf_clk_frac_h, 0x8); + bcma_write16(core, D11REGOFFS(tsf_clk_frac_l), 0x8889); + bcma_write16(core, D11REGOFFS(tsf_clk_frac_h), 0x8); } } else if (BRCMS_ISLCNPHY(wlc_hw->band)) { if (spurmode == WL_SPURAVOID_ON1) { /* 82Mhz */ - W_REG(®s->tsf_clk_frac_l, 0x7CE0); - W_REG(®s->tsf_clk_frac_h, 0xC); + bcma_write16(core, D11REGOFFS(tsf_clk_frac_l), 0x7CE0); + bcma_write16(core, D11REGOFFS(tsf_clk_frac_h), 0xC); } else { /* 80Mhz */ - W_REG(®s->tsf_clk_frac_l, 0xCCCD); - W_REG(®s->tsf_clk_frac_h, 0xC); + bcma_write16(core, D11REGOFFS(tsf_clk_frac_l), 0xCCCD); + bcma_write16(core, D11REGOFFS(tsf_clk_frac_h), 0xC); } } } @@ -2146,11 +2161,8 @@ void brcms_b_switch_macfreq(struct brcms_hardware *wlc_hw, u8 spurmode) static void brcms_c_gpio_init(struct brcms_c_info *wlc) { struct brcms_hardware *wlc_hw = wlc->hw; - struct d11regs __iomem *regs; u32 gc, gm; - regs = wlc_hw->regs; - /* use GPIO select 0 to get all gpio signals from the gpio out reg */ brcms_b_mctrl(wlc_hw, MCTL_GPOUT_SEL_MASK, 0); @@ -2181,10 +2193,10 @@ static void brcms_c_gpio_init(struct brcms_c_info *wlc) * The board itself is powered by these GPIOs * (when not sending pattern) so set them high */ - OR_REG(®s->psm_gpio_oe, - (BOARD_GPIO_12 | BOARD_GPIO_13)); - OR_REG(®s->psm_gpio_out, - (BOARD_GPIO_12 | BOARD_GPIO_13)); + bcma_set16(wlc_hw->d11core, D11REGOFFS(psm_gpio_oe), + (BOARD_GPIO_12 | BOARD_GPIO_13)); + bcma_set16(wlc_hw->d11core, D11REGOFFS(psm_gpio_out), + (BOARD_GPIO_12 | BOARD_GPIO_13)); /* Enable antenna diversity, use 2x4 mode */ brcms_b_mhf(wlc_hw, MHF3, MHF3_ANTSEL_EN, @@ -2211,7 +2223,7 @@ static void brcms_c_gpio_init(struct brcms_c_info *wlc) static void brcms_ucode_write(struct brcms_hardware *wlc_hw, const __le32 ucode[], const size_t nbytes) { - struct d11regs __iomem *regs = wlc_hw->regs; + struct bcma_device *core = wlc_hw->d11core; uint i; uint count; @@ -2219,10 +2231,11 @@ static void brcms_ucode_write(struct brcms_hardware *wlc_hw, count = (nbytes / sizeof(u32)); - W_REG(®s->objaddr, (OBJADDR_AUTO_INC | OBJADDR_UCM_SEL)); - (void)R_REG(®s->objaddr); + bcma_write32(core, D11REGOFFS(objaddr), + OBJADDR_AUTO_INC | OBJADDR_UCM_SEL); + (void)bcma_read32(core, D11REGOFFS(objaddr)); for (i = 0; i < count; i++) - W_REG(®s->objdata, le32_to_cpu(ucode[i])); + bcma_write32(core, D11REGOFFS(objdata), le32_to_cpu(ucode[i])); } @@ -2288,7 +2301,7 @@ static void brcms_b_fifoerrors(struct brcms_hardware *wlc_hw) bool fatal = false; uint unit; uint intstatus, idx; - struct d11regs __iomem *regs = wlc_hw->regs; + struct bcma_device *core = wlc_hw->d11core; struct wiphy *wiphy = wlc_hw->wlc->wiphy; unit = wlc_hw->unit; @@ -2296,7 +2309,9 @@ static void brcms_b_fifoerrors(struct brcms_hardware *wlc_hw) for (idx = 0; idx < NFIFO; idx++) { /* read intstatus register and ignore any non-error bits */ intstatus = - R_REG(®s->intctrlregs[idx].intstatus) & I_ERRORS; + bcma_read32(core, + D11REGOFFS(intctrlregs[idx].intstatus)) & + I_ERRORS; if (!intstatus) continue; @@ -2341,8 +2356,9 @@ static void brcms_b_fifoerrors(struct brcms_hardware *wlc_hw) brcms_fatal_error(wlc_hw->wlc->wl); /* big hammer */ break; } else - W_REG(®s->intctrlregs[idx].intstatus, - intstatus); + bcma_write32(core, + D11REGOFFS(intctrlregs[idx].intstatus), + intstatus); } } @@ -2350,28 +2366,7 @@ void brcms_c_intrson(struct brcms_c_info *wlc) { struct brcms_hardware *wlc_hw = wlc->hw; wlc->macintmask = wlc->defmacintmask; - W_REG(&wlc_hw->regs->macintmask, wlc->macintmask); -} - -/* - * callback for siutils.c, which has only wlc handler, no wl they both check - * up, not only because there is no need to off/restore d11 interrupt but also - * because per-port code may require sync with valid interrupt. - */ -static u32 brcms_c_wlintrsoff(struct brcms_c_info *wlc) -{ - if (!wlc->hw->up) - return 0; - - return brcms_intrsoff(wlc->wl); -} - -static void brcms_c_wlintrsrestore(struct brcms_c_info *wlc, u32 macintmask) -{ - if (!wlc->hw->up) - return; - - brcms_intrsrestore(wlc->wl, macintmask); + bcma_write32(wlc_hw->d11core, D11REGOFFS(macintmask), wlc->macintmask); } u32 brcms_c_intrsoff(struct brcms_c_info *wlc) @@ -2384,8 +2379,8 @@ u32 brcms_c_intrsoff(struct brcms_c_info *wlc) macintmask = wlc->macintmask; /* isr can still happen */ - W_REG(&wlc_hw->regs->macintmask, 0); - (void)R_REG(&wlc_hw->regs->macintmask); /* sync readback */ + bcma_write32(wlc_hw->d11core, D11REGOFFS(macintmask), 0); + (void)bcma_read32(wlc_hw->d11core, D11REGOFFS(macintmask)); udelay(1); /* ensure int line is no longer driven */ wlc->macintmask = 0; @@ -2400,7 +2395,7 @@ void brcms_c_intrsrestore(struct brcms_c_info *wlc, u32 macintmask) return; wlc->macintmask = macintmask; - W_REG(&wlc_hw->regs->macintmask, wlc->macintmask); + bcma_write32(wlc_hw->d11core, D11REGOFFS(macintmask), wlc->macintmask); } /* assumes that the d11 MAC is enabled */ @@ -2512,11 +2507,11 @@ brcms_c_mute(struct brcms_c_info *wlc, bool mute_tx) static inline u32 wlc_intstatus(struct brcms_c_info *wlc, bool in_isr) { struct brcms_hardware *wlc_hw = wlc->hw; - struct d11regs __iomem *regs = wlc_hw->regs; + struct bcma_device *core = wlc_hw->d11core; u32 macintstatus; /* macintstatus includes a DMA interrupt summary bit */ - macintstatus = R_REG(®s->macintstatus); + macintstatus = bcma_read32(core, D11REGOFFS(macintstatus)); BCMMSG(wlc->wiphy, "wl%d: macintstatus: 0x%x\n", wlc_hw->unit, macintstatus); @@ -2543,12 +2538,12 @@ static inline u32 wlc_intstatus(struct brcms_c_info *wlc, bool in_isr) * consequences */ /* turn off the interrupts */ - W_REG(®s->macintmask, 0); - (void)R_REG(®s->macintmask); /* sync readback */ + bcma_write32(core, D11REGOFFS(macintmask), 0); + (void)bcma_read32(core, D11REGOFFS(macintmask)); wlc->macintmask = 0; /* clear device interrupts */ - W_REG(®s->macintstatus, macintstatus); + bcma_write32(core, D11REGOFFS(macintstatus), macintstatus); /* MI_DMAINT is indication of non-zero intstatus */ if (macintstatus & MI_DMAINT) @@ -2557,8 +2552,8 @@ static inline u32 wlc_intstatus(struct brcms_c_info *wlc, bool in_isr) * RX_FIFO. If MI_DMAINT is set, assume it * is set and clear the interrupt. */ - W_REG(®s->intctrlregs[RX_FIFO].intstatus, - DEF_RXINTMASK); + bcma_write32(core, D11REGOFFS(intctrlregs[RX_FIFO].intstatus), + DEF_RXINTMASK); return macintstatus; } @@ -2621,7 +2616,7 @@ bool brcms_c_isr(struct brcms_c_info *wlc, bool *wantdpc) void brcms_c_suspend_mac_and_wait(struct brcms_c_info *wlc) { struct brcms_hardware *wlc_hw = wlc->hw; - struct d11regs __iomem *regs = wlc_hw->regs; + struct bcma_device *core = wlc_hw->d11core; u32 mc, mi; struct wiphy *wiphy = wlc->wiphy; @@ -2638,7 +2633,7 @@ void brcms_c_suspend_mac_and_wait(struct brcms_c_info *wlc) /* force the core awake */ brcms_c_ucode_wake_override_set(wlc_hw, BRCMS_WAKE_OVERRIDE_MACSUSPEND); - mc = R_REG(®s->maccontrol); + mc = bcma_read32(core, D11REGOFFS(maccontrol)); if (mc == 0xffffffff) { wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit, @@ -2650,7 +2645,7 @@ void brcms_c_suspend_mac_and_wait(struct brcms_c_info *wlc) WARN_ON(!(mc & MCTL_PSM_RUN)); WARN_ON(!(mc & MCTL_EN_MAC)); - mi = R_REG(®s->macintstatus); + mi = bcma_read32(core, D11REGOFFS(macintstatus)); if (mi == 0xffffffff) { wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit, __func__); @@ -2661,21 +2656,21 @@ void brcms_c_suspend_mac_and_wait(struct brcms_c_info *wlc) brcms_b_mctrl(wlc_hw, MCTL_EN_MAC, 0); - SPINWAIT(!(R_REG(®s->macintstatus) & MI_MACSSPNDD), + SPINWAIT(!(bcma_read32(core, D11REGOFFS(macintstatus)) & MI_MACSSPNDD), BRCMS_MAX_MAC_SUSPEND); - if (!(R_REG(®s->macintstatus) & MI_MACSSPNDD)) { + if (!(bcma_read32(core, D11REGOFFS(macintstatus)) & MI_MACSSPNDD)) { wiphy_err(wiphy, "wl%d: wlc_suspend_mac_and_wait: waited %d uS" " and MI_MACSSPNDD is still not on.\n", wlc_hw->unit, BRCMS_MAX_MAC_SUSPEND); wiphy_err(wiphy, "wl%d: psmdebug 0x%08x, phydebug 0x%08x, " "psm_brc 0x%04x\n", wlc_hw->unit, - R_REG(®s->psmdebug), - R_REG(®s->phydebug), - R_REG(®s->psm_brc)); + bcma_read32(core, D11REGOFFS(psmdebug)), + bcma_read32(core, D11REGOFFS(phydebug)), + bcma_read16(core, D11REGOFFS(psm_brc))); } - mc = R_REG(®s->maccontrol); + mc = bcma_read32(core, D11REGOFFS(maccontrol)); if (mc == 0xffffffff) { wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit, __func__); @@ -2690,7 +2685,7 @@ void brcms_c_suspend_mac_and_wait(struct brcms_c_info *wlc) void brcms_c_enable_mac(struct brcms_c_info *wlc) { struct brcms_hardware *wlc_hw = wlc->hw; - struct d11regs __iomem *regs = wlc_hw->regs; + struct bcma_device *core = wlc_hw->d11core; u32 mc, mi; BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit, @@ -2703,20 +2698,20 @@ void brcms_c_enable_mac(struct brcms_c_info *wlc) if (wlc_hw->mac_suspend_depth > 0) return; - mc = R_REG(®s->maccontrol); + mc = bcma_read32(core, D11REGOFFS(maccontrol)); WARN_ON(mc & MCTL_PSM_JMP_0); WARN_ON(mc & MCTL_EN_MAC); WARN_ON(!(mc & MCTL_PSM_RUN)); brcms_b_mctrl(wlc_hw, MCTL_EN_MAC, MCTL_EN_MAC); - W_REG(®s->macintstatus, MI_MACSSPNDD); + bcma_write32(core, D11REGOFFS(macintstatus), MI_MACSSPNDD); - mc = R_REG(®s->maccontrol); + mc = bcma_read32(core, D11REGOFFS(maccontrol)); WARN_ON(mc & MCTL_PSM_JMP_0); WARN_ON(!(mc & MCTL_EN_MAC)); WARN_ON(!(mc & MCTL_PSM_RUN)); - mi = R_REG(®s->macintstatus); + mi = bcma_read32(core, D11REGOFFS(macintstatus)); WARN_ON(mi & MI_MACSSPNDD); brcms_c_ucode_wake_override_clear(wlc_hw, @@ -2733,55 +2728,53 @@ void brcms_b_band_stf_ss_set(struct brcms_hardware *wlc_hw, u8 stf_mode) static bool brcms_b_validate_chip_access(struct brcms_hardware *wlc_hw) { - struct d11regs __iomem *regs; + struct bcma_device *core = wlc_hw->d11core; u32 w, val; struct wiphy *wiphy = wlc_hw->wlc->wiphy; BCMMSG(wiphy, "wl%d\n", wlc_hw->unit); - regs = wlc_hw->regs; - /* Validate dchip register access */ - W_REG(®s->objaddr, OBJADDR_SHM_SEL | 0); - (void)R_REG(®s->objaddr); - w = R_REG(®s->objdata); + bcma_write32(core, D11REGOFFS(objaddr), OBJADDR_SHM_SEL | 0); + (void)bcma_read32(core, D11REGOFFS(objaddr)); + w = bcma_read32(core, D11REGOFFS(objdata)); /* Can we write and read back a 32bit register? */ - W_REG(®s->objaddr, OBJADDR_SHM_SEL | 0); - (void)R_REG(®s->objaddr); - W_REG(®s->objdata, (u32) 0xaa5555aa); + bcma_write32(core, D11REGOFFS(objaddr), OBJADDR_SHM_SEL | 0); + (void)bcma_read32(core, D11REGOFFS(objaddr)); + bcma_write32(core, D11REGOFFS(objdata), (u32) 0xaa5555aa); - W_REG(®s->objaddr, OBJADDR_SHM_SEL | 0); - (void)R_REG(®s->objaddr); - val = R_REG(®s->objdata); + bcma_write32(core, D11REGOFFS(objaddr), OBJADDR_SHM_SEL | 0); + (void)bcma_read32(core, D11REGOFFS(objaddr)); + val = bcma_read32(core, D11REGOFFS(objdata)); if (val != (u32) 0xaa5555aa) { wiphy_err(wiphy, "wl%d: validate_chip_access: SHM = 0x%x, " "expected 0xaa5555aa\n", wlc_hw->unit, val); return false; } - W_REG(®s->objaddr, OBJADDR_SHM_SEL | 0); - (void)R_REG(®s->objaddr); - W_REG(®s->objdata, (u32) 0x55aaaa55); + bcma_write32(core, D11REGOFFS(objaddr), OBJADDR_SHM_SEL | 0); + (void)bcma_read32(core, D11REGOFFS(objaddr)); + bcma_write32(core, D11REGOFFS(objdata), (u32) 0x55aaaa55); - W_REG(®s->objaddr, OBJADDR_SHM_SEL | 0); - (void)R_REG(®s->objaddr); - val = R_REG(®s->objdata); + bcma_write32(core, D11REGOFFS(objaddr), OBJADDR_SHM_SEL | 0); + (void)bcma_read32(core, D11REGOFFS(objaddr)); + val = bcma_read32(core, D11REGOFFS(objdata)); if (val != (u32) 0x55aaaa55) { wiphy_err(wiphy, "wl%d: validate_chip_access: SHM = 0x%x, " "expected 0x55aaaa55\n", wlc_hw->unit, val); return false; } - W_REG(®s->objaddr, OBJADDR_SHM_SEL | 0); - (void)R_REG(®s->objaddr); - W_REG(®s->objdata, w); + bcma_write32(core, D11REGOFFS(objaddr), OBJADDR_SHM_SEL | 0); + (void)bcma_read32(core, D11REGOFFS(objaddr)); + bcma_write32(core, D11REGOFFS(objdata), w); /* clear CFPStart */ - W_REG(®s->tsf_cfpstart, 0); + bcma_write32(core, D11REGOFFS(tsf_cfpstart), 0); - w = R_REG(®s->maccontrol); + w = bcma_read32(core, D11REGOFFS(maccontrol)); if ((w != (MCTL_IHR_EN | MCTL_WAKE)) && (w != (MCTL_IHR_EN | MCTL_GMODE | MCTL_WAKE))) { wiphy_err(wiphy, "wl%d: validate_chip_access: maccontrol = " @@ -2798,38 +2791,38 @@ static bool brcms_b_validate_chip_access(struct brcms_hardware *wlc_hw) void brcms_b_core_phypll_ctl(struct brcms_hardware *wlc_hw, bool on) { - struct d11regs __iomem *regs; + struct bcma_device *core = wlc_hw->d11core; u32 tmp; BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); tmp = 0; - regs = wlc_hw->regs; if (on) { - if ((wlc_hw->sih->chip == BCM4313_CHIP_ID)) { - OR_REG(®s->clk_ctl_st, - (CCS_ERSRC_REQ_HT | CCS_ERSRC_REQ_D11PLL | - CCS_ERSRC_REQ_PHYPLL)); - SPINWAIT((R_REG(®s->clk_ctl_st) & - (CCS_ERSRC_AVAIL_HT)) != (CCS_ERSRC_AVAIL_HT), + if ((ai_get_chip_id(wlc_hw->sih) == BCM4313_CHIP_ID)) { + bcma_set32(core, D11REGOFFS(clk_ctl_st), + CCS_ERSRC_REQ_HT | + CCS_ERSRC_REQ_D11PLL | + CCS_ERSRC_REQ_PHYPLL); + SPINWAIT((bcma_read32(core, D11REGOFFS(clk_ctl_st)) & + CCS_ERSRC_AVAIL_HT) != CCS_ERSRC_AVAIL_HT, PHYPLL_WAIT_US); - tmp = R_REG(®s->clk_ctl_st); - if ((tmp & (CCS_ERSRC_AVAIL_HT)) != - (CCS_ERSRC_AVAIL_HT)) + tmp = bcma_read32(core, D11REGOFFS(clk_ctl_st)); + if ((tmp & CCS_ERSRC_AVAIL_HT) != CCS_ERSRC_AVAIL_HT) wiphy_err(wlc_hw->wlc->wiphy, "%s: turn on PHY" " PLL failed\n", __func__); } else { - OR_REG(®s->clk_ctl_st, - (CCS_ERSRC_REQ_D11PLL | CCS_ERSRC_REQ_PHYPLL)); - SPINWAIT((R_REG(®s->clk_ctl_st) & + bcma_set32(core, D11REGOFFS(clk_ctl_st), + tmp | CCS_ERSRC_REQ_D11PLL | + CCS_ERSRC_REQ_PHYPLL); + SPINWAIT((bcma_read32(core, D11REGOFFS(clk_ctl_st)) & (CCS_ERSRC_AVAIL_D11PLL | CCS_ERSRC_AVAIL_PHYPLL)) != (CCS_ERSRC_AVAIL_D11PLL | CCS_ERSRC_AVAIL_PHYPLL), PHYPLL_WAIT_US); - tmp = R_REG(®s->clk_ctl_st); + tmp = bcma_read32(core, D11REGOFFS(clk_ctl_st)); if ((tmp & (CCS_ERSRC_AVAIL_D11PLL | CCS_ERSRC_AVAIL_PHYPLL)) != @@ -2843,8 +2836,9 @@ void brcms_b_core_phypll_ctl(struct brcms_hardware *wlc_hw, bool on) * be requesting it; so we'll deassert the request but * not wait for status to comply. */ - AND_REG(®s->clk_ctl_st, ~CCS_ERSRC_REQ_PHYPLL); - tmp = R_REG(®s->clk_ctl_st); + bcma_mask32(core, D11REGOFFS(clk_ctl_st), + ~CCS_ERSRC_REQ_PHYPLL); + (void)bcma_read32(core, D11REGOFFS(clk_ctl_st)); } } @@ -2872,7 +2866,7 @@ static void brcms_c_coredisable(struct brcms_hardware *wlc_hw) brcms_b_core_phypll_ctl(wlc_hw, false); wlc_hw->clk = false; - ai_core_disable(wlc_hw->sih, 0); + bcma_core_disable(wlc_hw->d11core, 0); wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, false); } @@ -2896,35 +2890,31 @@ static void brcms_c_flushqueues(struct brcms_c_info *wlc) static u16 brcms_b_read_objmem(struct brcms_hardware *wlc_hw, uint offset, u32 sel) { - struct d11regs __iomem *regs = wlc_hw->regs; - u16 __iomem *objdata_lo = (u16 __iomem *)®s->objdata; - u16 __iomem *objdata_hi = objdata_lo + 1; - u16 v; + struct bcma_device *core = wlc_hw->d11core; + u16 objoff = D11REGOFFS(objdata); - W_REG(®s->objaddr, sel | (offset >> 2)); - (void)R_REG(®s->objaddr); + bcma_write32(core, D11REGOFFS(objaddr), sel | (offset >> 2)); + (void)bcma_read32(core, D11REGOFFS(objaddr)); if (offset & 2) - v = R_REG(objdata_hi); - else - v = R_REG(objdata_lo); + objoff += 2; - return v; + return bcma_read16(core, objoff); +; } static void brcms_b_write_objmem(struct brcms_hardware *wlc_hw, uint offset, u16 v, u32 sel) { - struct d11regs __iomem *regs = wlc_hw->regs; - u16 __iomem *objdata_lo = (u16 __iomem *)®s->objdata; - u16 __iomem *objdata_hi = objdata_lo + 1; + struct bcma_device *core = wlc_hw->d11core; + u16 objoff = D11REGOFFS(objdata); - W_REG(®s->objaddr, sel | (offset >> 2)); - (void)R_REG(®s->objaddr); + bcma_write32(core, D11REGOFFS(objaddr), sel | (offset >> 2)); + (void)bcma_read32(core, D11REGOFFS(objaddr)); if (offset & 2) - W_REG(objdata_hi, v); - else - W_REG(objdata_lo, v); + objoff += 2; + + bcma_write16(core, objoff, v); } /* @@ -3010,14 +3000,14 @@ static void brcms_b_retrylimit_upd(struct brcms_hardware *wlc_hw, /* write retry limit to SCR, shouldn't need to suspend */ if (wlc_hw->up) { - W_REG(&wlc_hw->regs->objaddr, - OBJADDR_SCR_SEL | S_DOT11_SRC_LMT); - (void)R_REG(&wlc_hw->regs->objaddr); - W_REG(&wlc_hw->regs->objdata, wlc_hw->SRL); - W_REG(&wlc_hw->regs->objaddr, - OBJADDR_SCR_SEL | S_DOT11_LRC_LMT); - (void)R_REG(&wlc_hw->regs->objaddr); - W_REG(&wlc_hw->regs->objdata, wlc_hw->LRL); + bcma_write32(wlc_hw->d11core, D11REGOFFS(objaddr), + OBJADDR_SCR_SEL | S_DOT11_SRC_LMT); + (void)bcma_read32(wlc_hw->d11core, D11REGOFFS(objaddr)); + bcma_write32(wlc_hw->d11core, D11REGOFFS(objdata), wlc_hw->SRL); + bcma_write32(wlc_hw->d11core, D11REGOFFS(objaddr), + OBJADDR_SCR_SEL | S_DOT11_LRC_LMT); + (void)bcma_read32(wlc_hw->d11core, D11REGOFFS(objaddr)); + bcma_write32(wlc_hw->d11core, D11REGOFFS(objdata), wlc_hw->LRL); } } @@ -3064,7 +3054,7 @@ static bool brcms_c_ps_allowed(struct brcms_c_info *wlc) return false; /* disallow PS when one of these meets when not scanning */ - if (wlc->monitor) + if (wlc->filter_flags & FIF_PROMISC_IN_BSS) return false; if (cfg->associated) { @@ -3199,9 +3189,9 @@ void brcms_c_init_scb(struct scb *scb) static void brcms_b_coreinit(struct brcms_c_info *wlc) { struct brcms_hardware *wlc_hw = wlc->hw; - struct d11regs __iomem *regs; + struct bcma_device *core = wlc_hw->d11core; u32 sflags; - uint bcnint_us; + u32 bcnint_us; uint i = 0; bool fifosz_fixup = false; int err = 0; @@ -3209,8 +3199,6 @@ static void brcms_b_coreinit(struct brcms_c_info *wlc) struct wiphy *wiphy = wlc->wiphy; struct brcms_ucode *ucode = &wlc_hw->wlc->wl->ucode; - regs = wlc_hw->regs; - BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit); /* reset PSM */ @@ -3223,20 +3211,20 @@ static void brcms_b_coreinit(struct brcms_c_info *wlc) fifosz_fixup = true; /* let the PSM run to the suspended state, set mode to BSS STA */ - W_REG(®s->macintstatus, -1); + bcma_write32(core, D11REGOFFS(macintstatus), -1); brcms_b_mctrl(wlc_hw, ~0, (MCTL_IHR_EN | MCTL_INFRA | MCTL_PSM_RUN | MCTL_WAKE)); /* wait for ucode to self-suspend after auto-init */ - SPINWAIT(((R_REG(®s->macintstatus) & MI_MACSSPNDD) == 0), - 1000 * 1000); - if ((R_REG(®s->macintstatus) & MI_MACSSPNDD) == 0) + SPINWAIT(((bcma_read32(core, D11REGOFFS(macintstatus)) & + MI_MACSSPNDD) == 0), 1000 * 1000); + if ((bcma_read32(core, D11REGOFFS(macintstatus)) & MI_MACSSPNDD) == 0) wiphy_err(wiphy, "wl%d: wlc_coreinit: ucode did not self-" "suspend!\n", wlc_hw->unit); brcms_c_gpio_init(wlc); - sflags = ai_core_sflags(wlc_hw->sih, 0, 0); + sflags = bcma_aread32(core, BCMA_IOST); if (D11REV_IS(wlc_hw->corerev, 23)) { if (BRCMS_ISNPHY(wlc_hw->band)) @@ -3300,7 +3288,7 @@ static void brcms_b_coreinit(struct brcms_c_info *wlc) wlc_hw->xmtfifo_sz[i], i); /* make sure we can still talk to the mac */ - WARN_ON(R_REG(®s->maccontrol) == 0xffffffff); + WARN_ON(bcma_read32(core, D11REGOFFS(maccontrol)) == 0xffffffff); /* band-specific inits done by wlc_bsinit() */ @@ -3309,7 +3297,7 @@ static void brcms_b_coreinit(struct brcms_c_info *wlc) brcms_b_write_shm(wlc_hw, M_MAX_ANTCNT, ANTCNT); /* enable one rx interrupt per received frame */ - W_REG(®s->intrcvlazy[0], (1 << IRL_FC_SHIFT)); + bcma_write32(core, D11REGOFFS(intrcvlazy[0]), (1 << IRL_FC_SHIFT)); /* set the station mode (BSS STA) */ brcms_b_mctrl(wlc_hw, @@ -3318,19 +3306,21 @@ static void brcms_b_coreinit(struct brcms_c_info *wlc) /* set up Beacon interval */ bcnint_us = 0x8000 << 10; - W_REG(®s->tsf_cfprep, (bcnint_us << CFPREP_CBI_SHIFT)); - W_REG(®s->tsf_cfpstart, bcnint_us); - W_REG(®s->macintstatus, MI_GP1); + bcma_write32(core, D11REGOFFS(tsf_cfprep), + (bcnint_us << CFPREP_CBI_SHIFT)); + bcma_write32(core, D11REGOFFS(tsf_cfpstart), bcnint_us); + bcma_write32(core, D11REGOFFS(macintstatus), MI_GP1); /* write interrupt mask */ - W_REG(®s->intctrlregs[RX_FIFO].intmask, DEF_RXINTMASK); + bcma_write32(core, D11REGOFFS(intctrlregs[RX_FIFO].intmask), + DEF_RXINTMASK); /* allow the MAC to control the PHY clock (dynamic on/off) */ brcms_b_macphyclk_set(wlc_hw, ON); /* program dynamic clock control fast powerup delay register */ wlc->fastpwrup_dly = ai_clkctl_fast_pwrup_delay(wlc_hw->sih); - W_REG(®s->scc_fastpwrup_dly, wlc->fastpwrup_dly); + bcma_write16(core, D11REGOFFS(scc_fastpwrup_dly), wlc->fastpwrup_dly); /* tell the ucode the corerev */ brcms_b_write_shm(wlc_hw, M_MACHW_VER, (u16) wlc_hw->corerev); @@ -3343,19 +3333,21 @@ static void brcms_b_coreinit(struct brcms_c_info *wlc) machwcap >> 16) & 0xffff)); /* write retry limits to SCR, this done after PSM init */ - W_REG(®s->objaddr, OBJADDR_SCR_SEL | S_DOT11_SRC_LMT); - (void)R_REG(®s->objaddr); - W_REG(®s->objdata, wlc_hw->SRL); - W_REG(®s->objaddr, OBJADDR_SCR_SEL | S_DOT11_LRC_LMT); - (void)R_REG(®s->objaddr); - W_REG(®s->objdata, wlc_hw->LRL); + bcma_write32(core, D11REGOFFS(objaddr), + OBJADDR_SCR_SEL | S_DOT11_SRC_LMT); + (void)bcma_read32(core, D11REGOFFS(objaddr)); + bcma_write32(core, D11REGOFFS(objdata), wlc_hw->SRL); + bcma_write32(core, D11REGOFFS(objaddr), + OBJADDR_SCR_SEL | S_DOT11_LRC_LMT); + (void)bcma_read32(core, D11REGOFFS(objaddr)); + bcma_write32(core, D11REGOFFS(objdata), wlc_hw->LRL); /* write rate fallback retry limits */ brcms_b_write_shm(wlc_hw, M_SFRMTXCNTFBRTHSD, wlc_hw->SFBL); brcms_b_write_shm(wlc_hw, M_LFRMTXCNTFBRTHSD, wlc_hw->LFBL); - AND_REG(®s->ifs_ctl, 0x0FFF); - W_REG(®s->ifs_aifsn, EDCF_AIFSN_MIN); + bcma_mask16(core, D11REGOFFS(ifs_ctl), 0x0FFF); + bcma_write16(core, D11REGOFFS(ifs_aifsn), EDCF_AIFSN_MIN); /* init the tx dma engines */ for (i = 0; i < NFIFO; i++) { @@ -3584,29 +3576,31 @@ static void brcms_c_bandinit_ordered(struct brcms_c_info *wlc, } /* - * Set or clear maccontrol bits MCTL_PROMISC, MCTL_BCNS_PROMISC and - * MCTL_KEEPCONTROL + * Set or clear filtering related maccontrol bits based on + * specified filter flags */ -static void brcms_c_mac_promisc(struct brcms_c_info *wlc) +void brcms_c_mac_promisc(struct brcms_c_info *wlc, uint filter_flags) { u32 promisc_bits = 0; - if (wlc->bcnmisc_monitor) + wlc->filter_flags = filter_flags; + + if (filter_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) + promisc_bits |= MCTL_PROMISC; + + if (filter_flags & FIF_BCN_PRBRESP_PROMISC) promisc_bits |= MCTL_BCNS_PROMISC; - if (wlc->monitor) - promisc_bits |= - MCTL_PROMISC | MCTL_BCNS_PROMISC | MCTL_KEEPCONTROL; + if (filter_flags & FIF_FCSFAIL) + promisc_bits |= MCTL_KEEPBADFCS; - brcms_b_mctrl(wlc->hw, - MCTL_PROMISC | MCTL_BCNS_PROMISC | MCTL_KEEPCONTROL, - promisc_bits); -} + if (filter_flags & (FIF_CONTROL | FIF_PSPOLL)) + promisc_bits |= MCTL_KEEPCONTROL; -void brcms_c_mac_bcn_promisc_change(struct brcms_c_info *wlc, bool promisc) -{ - wlc->bcnmisc_monitor = promisc; - brcms_c_mac_promisc(wlc); + brcms_b_mctrl(wlc->hw, + MCTL_PROMISC | MCTL_BCNS_PROMISC | + MCTL_KEEPCONTROL | MCTL_KEEPBADFCS, + promisc_bits); } /* @@ -3636,9 +3630,6 @@ static void brcms_c_ucode_mac_upd(struct brcms_c_info *wlc) } else { /* disable an active IBSS if we are not on the home channel */ } - - /* update the various promisc bits */ - brcms_c_mac_promisc(wlc); } static void brcms_c_write_rate_shm(struct brcms_c_info *wlc, u8 rate, @@ -3813,7 +3804,7 @@ static void brcms_c_set_ps_ctrl(struct brcms_c_info *wlc) BCMMSG(wlc->wiphy, "wl%d: hps %d\n", wlc->pub->unit, hps); - v1 = R_REG(&wlc->regs->maccontrol); + v1 = bcma_read32(wlc->hw->d11core, D11REGOFFS(maccontrol)); v2 = MCTL_WAKE; if (hps) v2 |= MCTL_HPS; @@ -4132,7 +4123,8 @@ void brcms_c_wme_setparams(struct brcms_c_info *wlc, u16 aci, acp_shm.cwmax = params->cw_max; acp_shm.cwcur = acp_shm.cwmin; acp_shm.bslots = - R_REG(&wlc->regs->tsf_random) & acp_shm.cwcur; + bcma_read16(wlc->hw->d11core, D11REGOFFS(tsf_random)) & + acp_shm.cwcur; acp_shm.reggap = acp_shm.bslots + acp_shm.aifs; /* Indicate the new params to the ucode */ acp_shm.status = brcms_b_read_shm(wlc->hw, (M_EDCF_QINFO + @@ -4440,21 +4432,21 @@ struct brcms_pub *brcms_c_pub(struct brcms_c_info *wlc) * initialize software state for each core and band * put the whole chip in reset(driver down state), no clock */ -static int brcms_b_attach(struct brcms_c_info *wlc, u16 vendor, u16 device, - uint unit, bool piomode, void __iomem *regsva, - struct pci_dev *btparam) +static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core, + uint unit, bool piomode) { struct brcms_hardware *wlc_hw; - struct d11regs __iomem *regs; char *macaddr = NULL; uint err = 0; uint j; bool wme = false; struct shared_phy_params sha_params; struct wiphy *wiphy = wlc->wiphy; + struct pci_dev *pcidev = core->bus->host_pci; - BCMMSG(wlc->wiphy, "wl%d: vendor 0x%x device 0x%x\n", unit, vendor, - device); + BCMMSG(wlc->wiphy, "wl%d: vendor 0x%x device 0x%x\n", unit, + pcidev->vendor, + pcidev->device); wme = true; @@ -4471,7 +4463,7 @@ static int brcms_b_attach(struct brcms_c_info *wlc, u16 vendor, u16 device, * Do the hardware portion of the attach. Also initialize software * state that depends on the particular hardware we are running. */ - wlc_hw->sih = ai_attach(regsva, btparam); + wlc_hw->sih = ai_attach(core->bus); if (wlc_hw->sih == NULL) { wiphy_err(wiphy, "wl%d: brcms_b_attach: si_attach failed\n", unit); @@ -4480,25 +4472,19 @@ static int brcms_b_attach(struct brcms_c_info *wlc, u16 vendor, u16 device, } /* verify again the device is supported */ - if (!brcms_c_chipmatch(vendor, device)) { + if (!brcms_c_chipmatch(pcidev->vendor, pcidev->device)) { wiphy_err(wiphy, "wl%d: brcms_b_attach: Unsupported " "vendor/device (0x%x/0x%x)\n", - unit, vendor, device); + unit, pcidev->vendor, pcidev->device); err = 12; goto fail; } - wlc_hw->vendorid = vendor; - wlc_hw->deviceid = device; - - /* set bar0 window to point at D11 core */ - wlc_hw->regs = (struct d11regs __iomem *) - ai_setcore(wlc_hw->sih, D11_CORE_ID, 0); - wlc_hw->corerev = ai_corerev(wlc_hw->sih); - - regs = wlc_hw->regs; + wlc_hw->vendorid = pcidev->vendor; + wlc_hw->deviceid = pcidev->device; - wlc->regs = wlc_hw->regs; + wlc_hw->d11core = core; + wlc_hw->corerev = core->id.rev; /* validate chip, chiprev and corerev */ if (!brcms_c_isgoodchip(wlc_hw)) { @@ -4533,8 +4519,9 @@ static int brcms_b_attach(struct brcms_c_info *wlc, u16 vendor, u16 device, wlc_hw->boardrev = (u16) j; if (!brcms_c_validboardtype(wlc_hw)) { wiphy_err(wiphy, "wl%d: brcms_b_attach: Unsupported Broadcom " - "board type (0x%x)" " or revision level (0x%x)\n", - unit, wlc_hw->sih->boardtype, wlc_hw->boardrev); + "board type (0x%x)" " or revision level (0x%x)\n", + unit, ai_get_boardtype(wlc_hw->sih), + wlc_hw->boardrev); err = 15; goto fail; } @@ -4555,7 +4542,7 @@ static int brcms_b_attach(struct brcms_c_info *wlc, u16 vendor, u16 device, else wlc_hw->_nbands = 1; - if ((wlc_hw->sih->chip == BCM43225_CHIP_ID)) + if ((ai_get_chip_id(wlc_hw->sih) == BCM43225_CHIP_ID)) wlc_hw->_nbands = 1; /* BMAC_NOTE: remove init of pub values when brcms_c_attach() @@ -4587,16 +4574,14 @@ static int brcms_b_attach(struct brcms_c_info *wlc, u16 vendor, u16 device, sha_params.corerev = wlc_hw->corerev; sha_params.vid = wlc_hw->vendorid; sha_params.did = wlc_hw->deviceid; - sha_params.chip = wlc_hw->sih->chip; - sha_params.chiprev = wlc_hw->sih->chiprev; - sha_params.chippkg = wlc_hw->sih->chippkg; + sha_params.chip = ai_get_chip_id(wlc_hw->sih); + sha_params.chiprev = ai_get_chiprev(wlc_hw->sih); + sha_params.chippkg = ai_get_chippkg(wlc_hw->sih); sha_params.sromrev = wlc_hw->sromrev; - sha_params.boardtype = wlc_hw->sih->boardtype; + sha_params.boardtype = ai_get_boardtype(wlc_hw->sih); sha_params.boardrev = wlc_hw->boardrev; - sha_params.boardvendor = wlc_hw->sih->boardvendor; sha_params.boardflags = wlc_hw->boardflags; sha_params.boardflags2 = wlc_hw->boardflags2; - sha_params.buscorerev = wlc_hw->sih->buscorerev; /* alloc and save pointer to shared phy state area */ wlc_hw->phy_sh = wlc_phy_shared_attach(&sha_params); @@ -4618,9 +4603,9 @@ static int brcms_b_attach(struct brcms_c_info *wlc, u16 vendor, u16 device, wlc_hw->band->bandtype = j ? BRCM_BAND_5G : BRCM_BAND_2G; wlc->band->bandunit = j; wlc->band->bandtype = j ? BRCM_BAND_5G : BRCM_BAND_2G; - wlc->core->coreidx = ai_coreidx(wlc_hw->sih); + wlc->core->coreidx = core->core_index; - wlc_hw->machwcap = R_REG(®s->machwcap); + wlc_hw->machwcap = bcma_read32(core, D11REGOFFS(machwcap)); wlc_hw->machwcap_backup = wlc_hw->machwcap; /* init tx fifo size */ @@ -4629,7 +4614,7 @@ static int brcms_b_attach(struct brcms_c_info *wlc, u16 vendor, u16 device, /* Get a phy for this band */ wlc_hw->band->pi = - wlc_phy_attach(wlc_hw->phy_sh, regs, + wlc_phy_attach(wlc_hw->phy_sh, core, wlc_hw->band->bandtype, wlc->wiphy); if (wlc_hw->band->pi == NULL) { @@ -4703,10 +4688,6 @@ static int brcms_b_attach(struct brcms_c_info *wlc, u16 vendor, u16 device, /* Match driver "down" state */ ai_pci_down(wlc_hw->sih); - /* register sb interrupt callback functions */ - ai_register_intr_callback(wlc_hw->sih, (void *)brcms_c_wlintrsoff, - (void *)brcms_c_wlintrsrestore, NULL, wlc); - /* turn off pll and xtal to match driver "down" state */ brcms_b_xtal(wlc_hw, OFF); @@ -4737,10 +4718,9 @@ static int brcms_b_attach(struct brcms_c_info *wlc, u16 vendor, u16 device, goto fail; } - BCMMSG(wlc->wiphy, - "deviceid 0x%x nbands %d board 0x%x macaddr: %s\n", - wlc_hw->deviceid, wlc_hw->_nbands, - wlc_hw->sih->boardtype, macaddr); + BCMMSG(wlc->wiphy, "deviceid 0x%x nbands %d board 0x%x macaddr: %s\n", + wlc_hw->deviceid, wlc_hw->_nbands, ai_get_boardtype(wlc_hw->sih), + macaddr); return err; @@ -4978,7 +4958,6 @@ static int brcms_b_detach(struct brcms_c_info *wlc) * and per-port interrupt object may has been freed. this must * be done before sb core switch */ - ai_deregister_intr_callback(wlc_hw->sih); ai_pci_sleep(wlc_hw->sih); } @@ -5073,13 +5052,11 @@ static void brcms_b_hw_up(struct brcms_hardware *wlc_hw) ai_pci_fixcfg(wlc_hw->sih); /* + * TODO: test suspend/resume + * * AI chip doesn't restore bar0win2 on * hibernation/resume, need sw fixup */ - if ((wlc_hw->sih->chip == BCM43224_CHIP_ID) || - (wlc_hw->sih->chip == BCM43225_CHIP_ID)) - wlc_hw->regs = (struct d11regs __iomem *) - ai_setcore(wlc_hw->sih, D11_CORE_ID, 0); /* * Inform phy that a POR reset has occurred so @@ -5091,7 +5068,7 @@ static void brcms_b_hw_up(struct brcms_hardware *wlc_hw) wlc_hw->wlc->pub->hw_up = true; if ((wlc_hw->boardflags & BFL_FEM) - && (wlc_hw->sih->chip == BCM4313_CHIP_ID)) { + && (ai_get_chip_id(wlc_hw->sih) == BCM4313_CHIP_ID)) { if (! (wlc_hw->boardrev >= 0x1250 && (wlc_hw->boardflags & BFL_FEM_BT))) @@ -5186,7 +5163,7 @@ int brcms_c_up(struct brcms_c_info *wlc) } if ((wlc->pub->boardflags & BFL_FEM) - && (wlc->pub->sih->chip == BCM4313_CHIP_ID)) { + && (ai_get_chip_id(wlc->hw->sih) == BCM4313_CHIP_ID)) { if (wlc->pub->boardrev >= 0x1250 && (wlc->pub->boardflags & BFL_FEM_BT)) brcms_b_mhf(wlc->hw, MHF5, MHF5_4313_GPIOCTRL, @@ -5323,9 +5300,9 @@ static int brcms_b_down_finish(struct brcms_hardware *wlc_hw) } else { /* Reset and disable the core */ - if (ai_iscoreup(wlc_hw->sih)) { - if (R_REG(&wlc_hw->regs->maccontrol) & - MCTL_EN_MAC) + if (bcma_core_is_enabled(wlc_hw->d11core)) { + if (bcma_read32(wlc_hw->d11core, + D11REGOFFS(maccontrol)) & MCTL_EN_MAC) brcms_c_suspend_mac_and_wait(wlc_hw->wlc); callbacks += brcms_reset(wlc_hw->wlc->wl); brcms_c_coredisable(wlc_hw); @@ -7482,11 +7459,11 @@ static void brcms_b_read_tsf(struct brcms_hardware *wlc_hw, u32 *tsf_l_ptr, u32 *tsf_h_ptr) { - struct d11regs __iomem *regs = wlc_hw->regs; + struct bcma_device *core = wlc_hw->d11core; /* read the tsf timer low, then high to get an atomic read */ - *tsf_l_ptr = R_REG(®s->tsf_timerlow); - *tsf_h_ptr = R_REG(®s->tsf_timerhigh); + *tsf_l_ptr = bcma_read32(core, D11REGOFFS(tsf_timerlow)); + *tsf_h_ptr = bcma_read32(core, D11REGOFFS(tsf_timerhigh)); } /* @@ -8074,14 +8051,8 @@ static void brcms_c_recv(struct brcms_c_info *wlc, struct sk_buff *p) len = p->len; if (rxh->RxStatus1 & RXS_FCSERR) { - if (wlc->pub->mac80211_state & MAC80211_PROMISC_BCNS) { - wiphy_err(wlc->wiphy, "FCSERR while scanning******* -" - " tossing\n"); - goto toss; - } else { - wiphy_err(wlc->wiphy, "RCSERR!!!\n"); + if (!(wlc->filter_flags & FIF_FCSFAIL)) goto toss; - } } /* check received pkt has at least frame control field */ @@ -8165,7 +8136,7 @@ bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded) { u32 macintstatus; struct brcms_hardware *wlc_hw = wlc->hw; - struct d11regs __iomem *regs = wlc_hw->regs; + struct bcma_device *core = wlc_hw->d11core; struct wiphy *wiphy = wlc->wiphy; if (brcms_deviceremoved(wlc)) { @@ -8201,7 +8172,7 @@ bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded) /* ATIM window end */ if (macintstatus & MI_ATIMWINEND) { BCMMSG(wlc->wiphy, "end of ATIM window\n"); - OR_REG(®s->maccommand, wlc->qvalid); + bcma_set32(core, D11REGOFFS(maccommand), wlc->qvalid); wlc->qvalid = 0; } @@ -8219,17 +8190,17 @@ bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded) if (macintstatus & MI_GP0) { wiphy_err(wiphy, "wl%d: PSM microcode watchdog fired at %d " - "(seconds). Resetting.\n", wlc_hw->unit, wlc_hw->now); + "(seconds). Resetting.\n", wlc_hw->unit, wlc_hw->now); printk_once("%s : PSM Watchdog, chipid 0x%x, chiprev 0x%x\n", - __func__, wlc_hw->sih->chip, - wlc_hw->sih->chiprev); + __func__, ai_get_chip_id(wlc_hw->sih), + ai_get_chiprev(wlc_hw->sih)); brcms_fatal_error(wlc_hw->wlc->wl); } /* gptimer timeout */ if (macintstatus & MI_TO) - W_REG(®s->gptimer, 0); + bcma_write32(core, D11REGOFFS(gptimer), 0); if (macintstatus & MI_RFDISABLE) { BCMMSG(wlc->wiphy, "wl%d: BMAC Detected a change on the" @@ -8251,13 +8222,11 @@ bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded) void brcms_c_init(struct brcms_c_info *wlc, bool mute_tx) { - struct d11regs __iomem *regs; + struct bcma_device *core = wlc->hw->d11core; u16 chanspec; BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); - regs = wlc->regs; - /* * This will happen if a big-hammer was executed. In * that case, we want to go back to the channel that @@ -8287,8 +8256,8 @@ void brcms_c_init(struct brcms_c_info *wlc, bool mute_tx) * update since init path would reset * to default value */ - W_REG(®s->tsf_cfprep, - (bi << CFPREP_CBI_SHIFT)); + bcma_write32(core, D11REGOFFS(tsf_cfprep), + bi << CFPREP_CBI_SHIFT); /* Update maccontrol PM related bits */ brcms_c_set_ps_ctrl(wlc); @@ -8318,7 +8287,7 @@ void brcms_c_init(struct brcms_c_info *wlc, bool mute_tx) brcms_c_bsinit(wlc); /* Enable EDCF mode (while the MAC is suspended) */ - OR_REG(®s->ifs_ctl, IFS_USEEDCF); + bcma_set16(core, D11REGOFFS(ifs_ctl), IFS_USEEDCF); brcms_c_edcf_setparams(wlc, false); /* Init precedence maps for empty FIFOs */ @@ -8342,7 +8311,7 @@ void brcms_c_init(struct brcms_c_info *wlc, bool mute_tx) brcms_c_txflowcontrol_reset(wlc); /* enable the RF Disable Delay timer */ - W_REG(&wlc->regs->rfdisabledly, RFDISABLE_DEFAULT); + bcma_write32(core, D11REGOFFS(rfdisabledly), RFDISABLE_DEFAULT); /* * Initialize WME parameters; if they haven't been set by some other @@ -8362,9 +8331,8 @@ void brcms_c_init(struct brcms_c_info *wlc, bool mute_tx) * The common driver entry routine. Error codes should be unique */ struct brcms_c_info * -brcms_c_attach(struct brcms_info *wl, u16 vendor, u16 device, uint unit, - bool piomode, void __iomem *regsva, struct pci_dev *btparam, - uint *perr) +brcms_c_attach(struct brcms_info *wl, struct bcma_device *core, uint unit, + bool piomode, uint *perr) { struct brcms_c_info *wlc; uint err = 0; @@ -8372,7 +8340,7 @@ brcms_c_attach(struct brcms_info *wl, u16 vendor, u16 device, uint unit, struct brcms_pub *pub; /* allocate struct brcms_c_info state and its substructures */ - wlc = (struct brcms_c_info *) brcms_c_attach_malloc(unit, &err, device); + wlc = (struct brcms_c_info *) brcms_c_attach_malloc(unit, &err, 0); if (wlc == NULL) goto fail; wlc->wiphy = wl->wiphy; @@ -8399,8 +8367,7 @@ brcms_c_attach(struct brcms_info *wl, u16 vendor, u16 device, uint unit, * low level attach steps(all hw accesses go * inside, no more in rest of the attach) */ - err = brcms_b_attach(wlc, vendor, device, unit, piomode, regsva, - btparam); + err = brcms_b_attach(wlc, core, unit, piomode); if (err) goto fail; diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.h b/drivers/net/wireless/brcm80211/brcmsmac/main.h index 251c350b3164..adb136ec1f04 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/main.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/main.h @@ -334,7 +334,7 @@ struct brcms_hardware { u32 machwcap_backup; /* backup of machwcap */ struct si_pub *sih; /* SI handle (cookie for siutils calls) */ - struct d11regs __iomem *regs; /* pointer to device registers */ + struct bcma_device *d11core; /* pointer to 802.11 core */ struct phy_shim_info *physhim; /* phy shim layer handler */ struct shared_phy *phy_sh; /* pointer to shared phy state */ struct brcms_hw_band *band;/* pointer to active per-band state */ @@ -400,7 +400,6 @@ struct brcms_txq_info { * * pub: pointer to driver public state. * wl: pointer to specific private state. - * regs: pointer to device registers. * hw: HW related state. * clkreq_override: setting for clkreq for PCIE : Auto, 0, 1. * fastpwrup_dly: time in us needed to bring up d11 fast clock. @@ -477,7 +476,6 @@ struct brcms_txq_info { struct brcms_c_info { struct brcms_pub *pub; struct brcms_info *wl; - struct d11regs __iomem *regs; struct brcms_hardware *hw; /* clock */ @@ -519,8 +517,7 @@ struct brcms_c_info { struct brcms_timer *radio_timer; /* promiscuous */ - bool monitor; - bool bcnmisc_monitor; + uint filter_flags; /* driver feature */ bool _rifs; @@ -658,8 +655,7 @@ extern void brcms_c_print_txdesc(struct d11txh *txh); #endif extern int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config); -extern void brcms_c_mac_bcn_promisc_change(struct brcms_c_info *wlc, - bool promisc); +extern void brcms_c_mac_promisc(struct brcms_c_info *wlc, uint filter_flags); extern void brcms_c_send_q(struct brcms_c_info *wlc); extern int brcms_c_prep_pdu(struct brcms_c_info *wlc, struct sk_buff *pdu, uint *fifo); diff --git a/drivers/net/wireless/brcm80211/brcmsmac/nicpci.c b/drivers/net/wireless/brcm80211/brcmsmac/nicpci.c index 0bcb26792046..7fad6dc19258 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/nicpci.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/nicpci.c @@ -139,6 +139,9 @@ #define SRSH_PI_MASK 0xf000 /* bit 15:12 */ #define SRSH_PI_SHIFT 12 /* bit 15:12 */ +#define PCIREGOFFS(field) offsetof(struct sbpciregs, field) +#define PCIEREGOFFS(field) offsetof(struct sbpcieregs, field) + /* Sonics side: PCI core and host control registers */ struct sbpciregs { u32 control; /* PCI control */ @@ -205,11 +208,7 @@ struct sbpcieregs { }; struct pcicore_info { - union { - struct sbpcieregs __iomem *pcieregs; - struct sbpciregs __iomem *pciregs; - } regs; /* Memory mapped register to the core */ - + struct bcma_device *core; struct si_pub *sih; /* System interconnect handle */ struct pci_dev *dev; u8 pciecap_lcreg_offset;/* PCIE capability LCreg offset @@ -224,9 +223,9 @@ struct pcicore_info { }; #define PCIE_ASPM(sih) \ - (((sih)->buscoretype == PCIE_CORE_ID) && \ - (((sih)->buscorerev >= 3) && \ - ((sih)->buscorerev <= 5))) + ((ai_get_buscoretype(sih) == PCIE_CORE_ID) && \ + ((ai_get_buscorerev(sih) >= 3) && \ + (ai_get_buscorerev(sih) <= 5))) /* delay needed between the mdio control/ mdiodata register data access */ @@ -238,8 +237,7 @@ static void pr28829_delay(void) /* Initialize the PCI core. * It's caller's responsibility to make sure that this is done only once */ -struct pcicore_info *pcicore_init(struct si_pub *sih, struct pci_dev *pdev, - void __iomem *regs) +struct pcicore_info *pcicore_init(struct si_pub *sih, struct bcma_device *core) { struct pcicore_info *pi; @@ -249,17 +247,15 @@ struct pcicore_info *pcicore_init(struct si_pub *sih, struct pci_dev *pdev, return NULL; pi->sih = sih; - pi->dev = pdev; + pi->dev = core->bus->host_pci; + pi->core = core; - if (sih->buscoretype == PCIE_CORE_ID) { + if (core->id.id == PCIE_CORE_ID) { u8 cap_ptr; - pi->regs.pcieregs = regs; cap_ptr = pcicore_find_pci_capability(pi->dev, PCI_CAP_ID_EXP, NULL, NULL); pi->pciecap_lcreg_offset = cap_ptr + PCIE_CAP_LINKCTRL_OFFSET; - } else - pi->regs.pciregs = regs; - + } return pi; } @@ -334,37 +330,37 @@ end: /* ***** Register Access API */ static uint -pcie_readreg(struct sbpcieregs __iomem *pcieregs, uint addrtype, uint offset) +pcie_readreg(struct bcma_device *core, uint addrtype, uint offset) { uint retval = 0xFFFFFFFF; switch (addrtype) { case PCIE_CONFIGREGS: - W_REG(&pcieregs->configaddr, offset); - (void)R_REG((&pcieregs->configaddr)); - retval = R_REG(&pcieregs->configdata); + bcma_write32(core, PCIEREGOFFS(configaddr), offset); + (void)bcma_read32(core, PCIEREGOFFS(configaddr)); + retval = bcma_read32(core, PCIEREGOFFS(configdata)); break; case PCIE_PCIEREGS: - W_REG(&pcieregs->pcieindaddr, offset); - (void)R_REG(&pcieregs->pcieindaddr); - retval = R_REG(&pcieregs->pcieinddata); + bcma_write32(core, PCIEREGOFFS(pcieindaddr), offset); + (void)bcma_read32(core, PCIEREGOFFS(pcieindaddr)); + retval = bcma_read32(core, PCIEREGOFFS(pcieinddata)); break; } return retval; } -static uint pcie_writereg(struct sbpcieregs __iomem *pcieregs, uint addrtype, +static uint pcie_writereg(struct bcma_device *core, uint addrtype, uint offset, uint val) { switch (addrtype) { case PCIE_CONFIGREGS: - W_REG((&pcieregs->configaddr), offset); - W_REG((&pcieregs->configdata), val); + bcma_write32(core, PCIEREGOFFS(configaddr), offset); + bcma_write32(core, PCIEREGOFFS(configdata), val); break; case PCIE_PCIEREGS: - W_REG((&pcieregs->pcieindaddr), offset); - W_REG((&pcieregs->pcieinddata), val); + bcma_write32(core, PCIEREGOFFS(pcieindaddr), offset); + bcma_write32(core, PCIEREGOFFS(pcieinddata), val); break; default: break; @@ -374,7 +370,6 @@ static uint pcie_writereg(struct sbpcieregs __iomem *pcieregs, uint addrtype, static bool pcie_mdiosetblock(struct pcicore_info *pi, uint blk) { - struct sbpcieregs __iomem *pcieregs = pi->regs.pcieregs; uint mdiodata, i = 0; uint pcie_serdes_spinwait = 200; @@ -382,12 +377,13 @@ static bool pcie_mdiosetblock(struct pcicore_info *pi, uint blk) (MDIODATA_DEV_ADDR << MDIODATA_DEVADDR_SHF) | (MDIODATA_BLK_ADDR << MDIODATA_REGADDR_SHF) | (blk << 4)); - W_REG(&pcieregs->mdiodata, mdiodata); + bcma_write32(pi->core, PCIEREGOFFS(mdiodata), mdiodata); pr28829_delay(); /* retry till the transaction is complete */ while (i < pcie_serdes_spinwait) { - if (R_REG(&pcieregs->mdiocontrol) & MDIOCTL_ACCESS_DONE) + if (bcma_read32(pi->core, PCIEREGOFFS(mdiocontrol)) & + MDIOCTL_ACCESS_DONE) break; udelay(1000); @@ -404,15 +400,15 @@ static int pcie_mdioop(struct pcicore_info *pi, uint physmedia, uint regaddr, bool write, uint *val) { - struct sbpcieregs __iomem *pcieregs = pi->regs.pcieregs; uint mdiodata; uint i = 0; uint pcie_serdes_spinwait = 10; /* enable mdio access to SERDES */ - W_REG(&pcieregs->mdiocontrol, MDIOCTL_PREAM_EN | MDIOCTL_DIVISOR_VAL); + bcma_write32(pi->core, PCIEREGOFFS(mdiocontrol), + MDIOCTL_PREAM_EN | MDIOCTL_DIVISOR_VAL); - if (pi->sih->buscorerev >= 10) { + if (ai_get_buscorerev(pi->sih) >= 10) { /* new serdes is slower in rw, * using two layers of reg address mapping */ @@ -432,20 +428,22 @@ pcie_mdioop(struct pcicore_info *pi, uint physmedia, uint regaddr, bool write, mdiodata |= (MDIODATA_START | MDIODATA_WRITE | MDIODATA_TA | *val); - W_REG(&pcieregs->mdiodata, mdiodata); + bcma_write32(pi->core, PCIEREGOFFS(mdiodata), mdiodata); pr28829_delay(); /* retry till the transaction is complete */ while (i < pcie_serdes_spinwait) { - if (R_REG(&pcieregs->mdiocontrol) & MDIOCTL_ACCESS_DONE) { + if (bcma_read32(pi->core, PCIEREGOFFS(mdiocontrol)) & + MDIOCTL_ACCESS_DONE) { if (!write) { pr28829_delay(); - *val = (R_REG(&pcieregs->mdiodata) & + *val = (bcma_read32(pi->core, + PCIEREGOFFS(mdiodata)) & MDIODATA_MASK); } /* Disable mdio access to SERDES */ - W_REG(&pcieregs->mdiocontrol, 0); + bcma_write32(pi->core, PCIEREGOFFS(mdiocontrol), 0); return 0; } udelay(1000); @@ -453,7 +451,7 @@ pcie_mdioop(struct pcicore_info *pi, uint physmedia, uint regaddr, bool write, } /* Timed out. Disable mdio access to SERDES. */ - W_REG(&pcieregs->mdiocontrol, 0); + bcma_write32(pi->core, PCIEREGOFFS(mdiocontrol), 0); return 1; } @@ -502,18 +500,18 @@ static void pcie_extendL1timer(struct pcicore_info *pi, bool extend) { u32 w; struct si_pub *sih = pi->sih; - struct sbpcieregs __iomem *pcieregs = pi->regs.pcieregs; - if (sih->buscoretype != PCIE_CORE_ID || sih->buscorerev < 7) + if (ai_get_buscoretype(sih) != PCIE_CORE_ID || + ai_get_buscorerev(sih) < 7) return; - w = pcie_readreg(pcieregs, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG); + w = pcie_readreg(pi->core, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG); if (extend) w |= PCIE_ASPMTIMER_EXTEND; else w &= ~PCIE_ASPMTIMER_EXTEND; - pcie_writereg(pcieregs, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG, w); - w = pcie_readreg(pcieregs, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG); + pcie_writereg(pi->core, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG, w); + w = pcie_readreg(pi->core, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG); } /* centralized clkreq control policy */ @@ -527,25 +525,27 @@ static void pcie_clkreq_upd(struct pcicore_info *pi, uint state) pcie_clkreq(pi, 1, 0); break; case SI_PCIDOWN: - if (sih->buscorerev == 6) { /* turn on serdes PLL down */ - ai_corereg(sih, SI_CC_IDX, - offsetof(struct chipcregs, chipcontrol_addr), - ~0, 0); - ai_corereg(sih, SI_CC_IDX, - offsetof(struct chipcregs, chipcontrol_data), - ~0x40, 0); + /* turn on serdes PLL down */ + if (ai_get_buscorerev(sih) == 6) { + ai_cc_reg(sih, + offsetof(struct chipcregs, chipcontrol_addr), + ~0, 0); + ai_cc_reg(sih, + offsetof(struct chipcregs, chipcontrol_data), + ~0x40, 0); } else if (pi->pcie_pr42767) { pcie_clkreq(pi, 1, 1); } break; case SI_PCIUP: - if (sih->buscorerev == 6) { /* turn off serdes PLL down */ - ai_corereg(sih, SI_CC_IDX, - offsetof(struct chipcregs, chipcontrol_addr), - ~0, 0); - ai_corereg(sih, SI_CC_IDX, - offsetof(struct chipcregs, chipcontrol_data), - ~0x40, 0x40); + /* turn off serdes PLL down */ + if (ai_get_buscorerev(sih) == 6) { + ai_cc_reg(sih, + offsetof(struct chipcregs, chipcontrol_addr), + ~0, 0); + ai_cc_reg(sih, + offsetof(struct chipcregs, chipcontrol_data), + ~0x40, 0x40); } else if (PCIE_ASPM(sih)) { /* disable clkreq */ pcie_clkreq(pi, 1, 0); } @@ -562,7 +562,7 @@ static void pcie_war_polarity(struct pcicore_info *pi) if (pi->pcie_polarity != 0) return; - w = pcie_readreg(pi->regs.pcieregs, PCIE_PCIEREGS, PCIE_PLP_STATUSREG); + w = pcie_readreg(pi->core, PCIE_PCIEREGS, PCIE_PLP_STATUSREG); /* Detect the current polarity at attach and force that polarity and * disable changing the polarity @@ -581,18 +581,15 @@ static void pcie_war_polarity(struct pcicore_info *pi) */ static void pcie_war_aspm_clkreq(struct pcicore_info *pi) { - struct sbpcieregs __iomem *pcieregs = pi->regs.pcieregs; struct si_pub *sih = pi->sih; u16 val16; - u16 __iomem *reg16; u32 w; if (!PCIE_ASPM(sih)) return; /* bypass this on QT or VSIM */ - reg16 = &pcieregs->sprom[SRSH_ASPM_OFFSET]; - val16 = R_REG(reg16); + val16 = bcma_read16(pi->core, PCIEREGOFFS(sprom[SRSH_ASPM_OFFSET])); val16 &= ~SRSH_ASPM_ENB; if (pi->pcie_war_aspm_ovr == PCIE_ASPM_ENAB) @@ -602,15 +599,15 @@ static void pcie_war_aspm_clkreq(struct pcicore_info *pi) else if (pi->pcie_war_aspm_ovr == PCIE_ASPM_L0s_ENAB) val16 |= SRSH_ASPM_L0s_ENB; - W_REG(reg16, val16); + bcma_write16(pi->core, PCIEREGOFFS(sprom[SRSH_ASPM_OFFSET]), val16); pci_read_config_dword(pi->dev, pi->pciecap_lcreg_offset, &w); w &= ~PCIE_ASPM_ENAB; w |= pi->pcie_war_aspm_ovr; pci_write_config_dword(pi->dev, pi->pciecap_lcreg_offset, w); - reg16 = &pcieregs->sprom[SRSH_CLKREQ_OFFSET_REV5]; - val16 = R_REG(reg16); + val16 = bcma_read16(pi->core, + PCIEREGOFFS(sprom[SRSH_CLKREQ_OFFSET_REV5])); if (pi->pcie_war_aspm_ovr != PCIE_ASPM_DISAB) { val16 |= SRSH_CLKREQ_ENB; @@ -618,7 +615,8 @@ static void pcie_war_aspm_clkreq(struct pcicore_info *pi) } else val16 &= ~SRSH_CLKREQ_ENB; - W_REG(reg16, val16); + bcma_write16(pi->core, PCIEREGOFFS(sprom[SRSH_CLKREQ_OFFSET_REV5]), + val16); } /* Apply the polarity determined at the start */ @@ -642,16 +640,15 @@ static void pcie_war_serdes(struct pcicore_info *pi) /* Needs to happen when coming out of 'standby'/'hibernate' */ static void pcie_misc_config_fixup(struct pcicore_info *pi) { - struct sbpcieregs __iomem *pcieregs = pi->regs.pcieregs; u16 val16; - u16 __iomem *reg16; - reg16 = &pcieregs->sprom[SRSH_PCIE_MISC_CONFIG]; - val16 = R_REG(reg16); + val16 = bcma_read16(pi->core, + PCIEREGOFFS(sprom[SRSH_PCIE_MISC_CONFIG])); if ((val16 & SRSH_L23READY_EXIT_NOPERST) == 0) { val16 |= SRSH_L23READY_EXIT_NOPERST; - W_REG(reg16, val16); + bcma_write16(pi->core, + PCIEREGOFFS(sprom[SRSH_PCIE_MISC_CONFIG]), val16); } } @@ -659,62 +656,57 @@ static void pcie_misc_config_fixup(struct pcicore_info *pi) /* Needs to happen when coming out of 'standby'/'hibernate' */ static void pcie_war_noplldown(struct pcicore_info *pi) { - struct sbpcieregs __iomem *pcieregs = pi->regs.pcieregs; - u16 __iomem *reg16; - /* turn off serdes PLL down */ - ai_corereg(pi->sih, SI_CC_IDX, offsetof(struct chipcregs, chipcontrol), - CHIPCTRL_4321_PLL_DOWN, CHIPCTRL_4321_PLL_DOWN); + ai_cc_reg(pi->sih, offsetof(struct chipcregs, chipcontrol), + CHIPCTRL_4321_PLL_DOWN, CHIPCTRL_4321_PLL_DOWN); /* clear srom shadow backdoor */ - reg16 = &pcieregs->sprom[SRSH_BD_OFFSET]; - W_REG(reg16, 0); + bcma_write16(pi->core, PCIEREGOFFS(sprom[SRSH_BD_OFFSET]), 0); } /* Needs to happen when coming out of 'standby'/'hibernate' */ static void pcie_war_pci_setup(struct pcicore_info *pi) { struct si_pub *sih = pi->sih; - struct sbpcieregs __iomem *pcieregs = pi->regs.pcieregs; u32 w; - if (sih->buscorerev == 0 || sih->buscorerev == 1) { - w = pcie_readreg(pcieregs, PCIE_PCIEREGS, + if (ai_get_buscorerev(sih) == 0 || ai_get_buscorerev(sih) == 1) { + w = pcie_readreg(pi->core, PCIE_PCIEREGS, PCIE_TLP_WORKAROUNDSREG); w |= 0x8; - pcie_writereg(pcieregs, PCIE_PCIEREGS, + pcie_writereg(pi->core, PCIE_PCIEREGS, PCIE_TLP_WORKAROUNDSREG, w); } - if (sih->buscorerev == 1) { - w = pcie_readreg(pcieregs, PCIE_PCIEREGS, PCIE_DLLP_LCREG); + if (ai_get_buscorerev(sih) == 1) { + w = pcie_readreg(pi->core, PCIE_PCIEREGS, PCIE_DLLP_LCREG); w |= 0x40; - pcie_writereg(pcieregs, PCIE_PCIEREGS, PCIE_DLLP_LCREG, w); + pcie_writereg(pi->core, PCIE_PCIEREGS, PCIE_DLLP_LCREG, w); } - if (sih->buscorerev == 0) { + if (ai_get_buscorerev(sih) == 0) { pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_TIMER1, 0x8128); pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_CDR, 0x0100); pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_CDRBW, 0x1466); } else if (PCIE_ASPM(sih)) { /* Change the L1 threshold for better performance */ - w = pcie_readreg(pcieregs, PCIE_PCIEREGS, + w = pcie_readreg(pi->core, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG); w &= ~PCIE_L1THRESHOLDTIME_MASK; w |= PCIE_L1THRESHOLD_WARVAL << PCIE_L1THRESHOLDTIME_SHIFT; - pcie_writereg(pcieregs, PCIE_PCIEREGS, + pcie_writereg(pi->core, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG, w); pcie_war_serdes(pi); pcie_war_aspm_clkreq(pi); - } else if (pi->sih->buscorerev == 7) + } else if (ai_get_buscorerev(pi->sih) == 7) pcie_war_noplldown(pi); /* Note that the fix is actually in the SROM, * that's why this is open-ended */ - if (pi->sih->buscorerev >= 6) + if (ai_get_buscorerev(pi->sih) >= 6) pcie_misc_config_fixup(pi); } @@ -745,7 +737,7 @@ void pcicore_attach(struct pcicore_info *pi, int state) void pcicore_hwup(struct pcicore_info *pi) { - if (!pi || pi->sih->buscoretype != PCIE_CORE_ID) + if (!pi || ai_get_buscoretype(pi->sih) != PCIE_CORE_ID) return; pcie_war_pci_setup(pi); @@ -753,7 +745,7 @@ void pcicore_hwup(struct pcicore_info *pi) void pcicore_up(struct pcicore_info *pi, int state) { - if (!pi || pi->sih->buscoretype != PCIE_CORE_ID) + if (!pi || ai_get_buscoretype(pi->sih) != PCIE_CORE_ID) return; /* Restore L1 timer for better performance */ @@ -781,7 +773,7 @@ void pcicore_sleep(struct pcicore_info *pi) void pcicore_down(struct pcicore_info *pi, int state) { - if (!pi || pi->sih->buscoretype != PCIE_CORE_ID) + if (!pi || ai_get_buscoretype(pi->sih) != PCIE_CORE_ID) return; pcie_clkreq_upd(pi, state); @@ -790,46 +782,45 @@ void pcicore_down(struct pcicore_info *pi, int state) pcie_extendL1timer(pi, false); } -/* precondition: current core is sii->buscoretype */ -static void pcicore_fixcfg(struct pcicore_info *pi, u16 __iomem *reg16) +void pcicore_fixcfg(struct pcicore_info *pi) { - struct si_info *sii = (struct si_info *)(pi->sih); + struct bcma_device *core = pi->core; u16 val16; - uint pciidx; + uint regoff; - pciidx = ai_coreidx(&sii->pub); - val16 = R_REG(reg16); - if (((val16 & SRSH_PI_MASK) >> SRSH_PI_SHIFT) != (u16)pciidx) { - val16 = (u16)(pciidx << SRSH_PI_SHIFT) | - (val16 & ~SRSH_PI_MASK); - W_REG(reg16, val16); - } -} + switch (pi->core->id.id) { + case BCMA_CORE_PCI: + regoff = PCIREGOFFS(sprom[SRSH_PI_OFFSET]); + break; -void -pcicore_fixcfg_pci(struct pcicore_info *pi, struct sbpciregs __iomem *pciregs) -{ - pcicore_fixcfg(pi, &pciregs->sprom[SRSH_PI_OFFSET]); -} + case BCMA_CORE_PCIE: + regoff = PCIEREGOFFS(sprom[SRSH_PI_OFFSET]); + break; -void pcicore_fixcfg_pcie(struct pcicore_info *pi, - struct sbpcieregs __iomem *pcieregs) -{ - pcicore_fixcfg(pi, &pcieregs->sprom[SRSH_PI_OFFSET]); + default: + return; + } + + val16 = bcma_read16(pi->core, regoff); + if (((val16 & SRSH_PI_MASK) >> SRSH_PI_SHIFT) != + (u16)core->core_index) { + val16 = ((u16)core->core_index << SRSH_PI_SHIFT) | + (val16 & ~SRSH_PI_MASK); + bcma_write16(pi->core, regoff, val16); + } } /* precondition: current core is pci core */ void -pcicore_pci_setup(struct pcicore_info *pi, struct sbpciregs __iomem *pciregs) +pcicore_pci_setup(struct pcicore_info *pi) { - u32 w; - - OR_REG(&pciregs->sbtopci2, SBTOPCI_PREF | SBTOPCI_BURST); - - if (((struct si_info *)(pi->sih))->pub.buscorerev >= 11) { - OR_REG(&pciregs->sbtopci2, SBTOPCI_RC_READMULTI); - w = R_REG(&pciregs->clkrun); - W_REG(&pciregs->clkrun, w | PCI_CLKRUN_DSBL); - w = R_REG(&pciregs->clkrun); + bcma_set32(pi->core, PCIREGOFFS(sbtopci2), + SBTOPCI_PREF | SBTOPCI_BURST); + + if (pi->core->id.rev >= 11) { + bcma_set32(pi->core, PCIREGOFFS(sbtopci2), + SBTOPCI_RC_READMULTI); + bcma_set32(pi->core, PCIREGOFFS(clkrun), PCI_CLKRUN_DSBL); + (void)bcma_read32(pi->core, PCIREGOFFS(clkrun)); } } diff --git a/drivers/net/wireless/brcm80211/brcmsmac/nicpci.h b/drivers/net/wireless/brcm80211/brcmsmac/nicpci.h index 58aa80dc3329..9fc3ead540a8 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/nicpci.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/nicpci.h @@ -62,8 +62,7 @@ struct sbpciregs; struct sbpcieregs; extern struct pcicore_info *pcicore_init(struct si_pub *sih, - struct pci_dev *pdev, - void __iomem *regs); + struct bcma_device *core); extern void pcicore_deinit(struct pcicore_info *pch); extern void pcicore_attach(struct pcicore_info *pch, int state); extern void pcicore_hwup(struct pcicore_info *pch); @@ -72,11 +71,7 @@ extern void pcicore_sleep(struct pcicore_info *pch); extern void pcicore_down(struct pcicore_info *pch, int state); extern u8 pcicore_find_pci_capability(struct pci_dev *dev, u8 req_cap_id, unsigned char *buf, u32 *buflen); -extern void pcicore_fixcfg_pci(struct pcicore_info *pch, - struct sbpciregs __iomem *pciregs); -extern void pcicore_fixcfg_pcie(struct pcicore_info *pch, - struct sbpcieregs __iomem *pciregs); -extern void pcicore_pci_setup(struct pcicore_info *pch, - struct sbpciregs __iomem *pciregs); +extern void pcicore_fixcfg(struct pcicore_info *pch); +extern void pcicore_pci_setup(struct pcicore_info *pch); #endif /* _BRCM_NICPCI_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/otp.c b/drivers/net/wireless/brcm80211/brcmsmac/otp.c index edf551561fd8..f1ca12625860 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/otp.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/otp.c @@ -77,7 +77,7 @@ struct otp_fn_s { }; struct otpinfo { - uint ccrev; /* chipc revision */ + struct bcma_device *core; /* chipc core */ const struct otp_fn_s *fn; /* OTP functions */ struct si_pub *sih; /* Saved sb handle */ @@ -133,9 +133,10 @@ struct otpinfo { #define OTP_SZ_FU_144 (144/8) /* 144 bits */ static u16 -ipxotp_otpr(struct otpinfo *oi, struct chipcregs __iomem *cc, uint wn) +ipxotp_otpr(struct otpinfo *oi, uint wn) { - return R_REG(&cc->sromotp[wn]); + return bcma_read16(oi->core, + CHIPCREGOFFS(sromotp[wn])); } /* @@ -146,7 +147,7 @@ static int ipxotp_max_rgnsz(struct si_pub *sih, int osizew) { int ret = 0; - switch (sih->chip) { + switch (ai_get_chip_id(sih)) { case BCM43224_CHIP_ID: case BCM43225_CHIP_ID: ret = osizew * 2 - OTP_SZ_FU_72 - OTP_SZ_CHECKSUM; @@ -161,19 +162,21 @@ static int ipxotp_max_rgnsz(struct si_pub *sih, int osizew) return ret; } -static void _ipxotp_init(struct otpinfo *oi, struct chipcregs __iomem *cc) +static void _ipxotp_init(struct otpinfo *oi) { uint k; u32 otpp, st; + int ccrev = ai_get_ccrev(oi->sih); + /* * record word offset of General Use Region * for various chipcommon revs */ - if (oi->sih->ccrev == 21 || oi->sih->ccrev == 24 - || oi->sih->ccrev == 27) { + if (ccrev == 21 || ccrev == 24 + || ccrev == 27) { oi->otpgu_base = REVA4_OTPGU_BASE; - } else if (oi->sih->ccrev == 36) { + } else if (ccrev == 36) { /* * OTP size greater than equal to 2KB (128 words), * otpgu_base is similar to rev23 @@ -182,7 +185,7 @@ static void _ipxotp_init(struct otpinfo *oi, struct chipcregs __iomem *cc) oi->otpgu_base = REVB8_OTPGU_BASE; else oi->otpgu_base = REV36_OTPGU_BASE; - } else if (oi->sih->ccrev == 23 || oi->sih->ccrev >= 25) { + } else if (ccrev == 23 || ccrev >= 25) { oi->otpgu_base = REVB8_OTPGU_BASE; } @@ -190,24 +193,21 @@ static void _ipxotp_init(struct otpinfo *oi, struct chipcregs __iomem *cc) otpp = OTPP_START_BUSY | ((OTPPOC_INIT << OTPP_OC_SHIFT) & OTPP_OC_MASK); - W_REG(&cc->otpprog, otpp); - for (k = 0; - ((st = R_REG(&cc->otpprog)) & OTPP_START_BUSY) - && (k < OTPP_TRIES); k++) - ; + bcma_write32(oi->core, CHIPCREGOFFS(otpprog), otpp); + st = bcma_read32(oi->core, CHIPCREGOFFS(otpprog)); + for (k = 0; (st & OTPP_START_BUSY) && (k < OTPP_TRIES); k++) + st = bcma_read32(oi->core, CHIPCREGOFFS(otpprog)); if (k >= OTPP_TRIES) return; /* Read OTP lock bits and subregion programmed indication bits */ - oi->status = R_REG(&cc->otpstatus); + oi->status = bcma_read32(oi->core, CHIPCREGOFFS(otpstatus)); - if ((oi->sih->chip == BCM43224_CHIP_ID) - || (oi->sih->chip == BCM43225_CHIP_ID)) { + if ((ai_get_chip_id(oi->sih) == BCM43224_CHIP_ID) + || (ai_get_chip_id(oi->sih) == BCM43225_CHIP_ID)) { u32 p_bits; - p_bits = - (ipxotp_otpr(oi, cc, oi->otpgu_base + OTPGU_P_OFF) & - OTPGU_P_MSK) - >> OTPGU_P_SHIFT; + p_bits = (ipxotp_otpr(oi, oi->otpgu_base + OTPGU_P_OFF) & + OTPGU_P_MSK) >> OTPGU_P_SHIFT; oi->status |= (p_bits << OTPS_GUP_SHIFT); } @@ -220,7 +220,7 @@ static void _ipxotp_init(struct otpinfo *oi, struct chipcregs __iomem *cc) oi->hwlim = oi->wsize; if (oi->status & OTPS_GUP_HW) { oi->hwlim = - ipxotp_otpr(oi, cc, oi->otpgu_base + OTPGU_HSB_OFF) / 16; + ipxotp_otpr(oi, oi->otpgu_base + OTPGU_HSB_OFF) / 16; oi->swbase = oi->hwlim; } else oi->swbase = oi->hwbase; @@ -230,7 +230,7 @@ static void _ipxotp_init(struct otpinfo *oi, struct chipcregs __iomem *cc) if (oi->status & OTPS_GUP_SW) { oi->swlim = - ipxotp_otpr(oi, cc, oi->otpgu_base + OTPGU_SFB_OFF) / 16; + ipxotp_otpr(oi, oi->otpgu_base + OTPGU_SFB_OFF) / 16; oi->fbase = oi->swlim; } else oi->fbase = oi->swbase; @@ -240,11 +240,8 @@ static void _ipxotp_init(struct otpinfo *oi, struct chipcregs __iomem *cc) static int ipxotp_init(struct si_pub *sih, struct otpinfo *oi) { - uint idx; - struct chipcregs __iomem *cc; - /* Make sure we're running IPX OTP */ - if (!OTPTYPE_IPX(sih->ccrev)) + if (!OTPTYPE_IPX(ai_get_ccrev(sih))) return -EBADE; /* Make sure OTP is not disabled */ @@ -252,7 +249,7 @@ static int ipxotp_init(struct si_pub *sih, struct otpinfo *oi) return -EBADE; /* Check for otp size */ - switch ((sih->cccaps & CC_CAP_OTPSIZE) >> CC_CAP_OTPSIZE_SHIFT) { + switch ((ai_get_cccaps(sih) & CC_CAP_OTPSIZE) >> CC_CAP_OTPSIZE_SHIFT) { case 0: /* Nothing there */ return -EBADE; @@ -282,21 +279,13 @@ static int ipxotp_init(struct si_pub *sih, struct otpinfo *oi) } /* Retrieve OTP region info */ - idx = ai_coreidx(sih); - cc = ai_setcoreidx(sih, SI_CC_IDX); - - _ipxotp_init(oi, cc); - - ai_setcoreidx(sih, idx); - + _ipxotp_init(oi); return 0; } static int ipxotp_read_region(struct otpinfo *oi, int region, u16 *data, uint *wlen) { - uint idx; - struct chipcregs __iomem *cc; uint base, i, sz; /* Validate region selection */ @@ -365,14 +354,10 @@ ipxotp_read_region(struct otpinfo *oi, int region, u16 *data, uint *wlen) return -EINVAL; } - idx = ai_coreidx(oi->sih); - cc = ai_setcoreidx(oi->sih, SI_CC_IDX); - /* Read the data */ for (i = 0; i < sz; i++) - data[i] = ipxotp_otpr(oi, cc, base + i); + data[i] = ipxotp_otpr(oi, base + i); - ai_setcoreidx(oi->sih, idx); *wlen = sz; return 0; } @@ -384,14 +369,13 @@ static const struct otp_fn_s ipxotp_fn = { static int otp_init(struct si_pub *sih, struct otpinfo *oi) { - int ret; memset(oi, 0, sizeof(struct otpinfo)); - oi->ccrev = sih->ccrev; + oi->core = ai_findcore(sih, BCMA_CORE_CHIPCOMMON, 0); - if (OTPTYPE_IPX(oi->ccrev)) + if (OTPTYPE_IPX(ai_get_ccrev(sih))) oi->fn = &ipxotp_fn; if (oi->fn == NULL) @@ -399,7 +383,7 @@ static int otp_init(struct si_pub *sih, struct otpinfo *oi) oi->sih = sih; - ret = (oi->fn->init) (sih, oi); + ret = (oi->fn->init)(sih, oi); return ret; } diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c index e17edf7e6833..264f8c4c703d 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c @@ -109,7 +109,7 @@ static const struct chan_info_basic chan_info_all[] = { {204, 5020}, {208, 5040}, {212, 5060}, - {216, 50800} + {216, 5080} }; static const u8 ofdm_rate_lookup[] = { @@ -149,9 +149,8 @@ void wlc_radioreg_enter(struct brcms_phy_pub *pih) void wlc_radioreg_exit(struct brcms_phy_pub *pih) { struct brcms_phy *pi = (struct brcms_phy *) pih; - u16 dummy; - dummy = R_REG(&pi->regs->phyversion); + (void)bcma_read16(pi->d11core, D11REGOFFS(phyversion)); pi->phy_wreg = 0; wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, 0); } @@ -186,11 +185,11 @@ u16 read_radio_reg(struct brcms_phy *pi, u16 addr) if ((D11REV_GE(pi->sh->corerev, 24)) || (D11REV_IS(pi->sh->corerev, 22) && (pi->pubpi.phy_type != PHY_TYPE_SSN))) { - W_REG_FLUSH(&pi->regs->radioregaddr, addr); - data = R_REG(&pi->regs->radioregdata); + bcma_wflush16(pi->d11core, D11REGOFFS(radioregaddr), addr); + data = bcma_read16(pi->d11core, D11REGOFFS(radioregdata)); } else { - W_REG_FLUSH(&pi->regs->phy4waddr, addr); - data = R_REG(&pi->regs->phy4wdatalo); + bcma_wflush16(pi->d11core, D11REGOFFS(phy4waddr), addr); + data = bcma_read16(pi->d11core, D11REGOFFS(phy4wdatalo)); } pi->phy_wreg = 0; @@ -203,15 +202,15 @@ void write_radio_reg(struct brcms_phy *pi, u16 addr, u16 val) (D11REV_IS(pi->sh->corerev, 22) && (pi->pubpi.phy_type != PHY_TYPE_SSN))) { - W_REG_FLUSH(&pi->regs->radioregaddr, addr); - W_REG(&pi->regs->radioregdata, val); + bcma_wflush16(pi->d11core, D11REGOFFS(radioregaddr), addr); + bcma_write16(pi->d11core, D11REGOFFS(radioregdata), val); } else { - W_REG_FLUSH(&pi->regs->phy4waddr, addr); - W_REG(&pi->regs->phy4wdatalo, val); + bcma_wflush16(pi->d11core, D11REGOFFS(phy4waddr), addr); + bcma_write16(pi->d11core, D11REGOFFS(phy4wdatalo), val); } if (++pi->phy_wreg >= pi->phy_wreg_limit) { - (void)R_REG(&pi->regs->maccontrol); + (void)bcma_read32(pi->d11core, D11REGOFFS(maccontrol)); pi->phy_wreg = 0; } } @@ -223,19 +222,20 @@ static u32 read_radio_id(struct brcms_phy *pi) if (D11REV_GE(pi->sh->corerev, 24)) { u32 b0, b1, b2; - W_REG_FLUSH(&pi->regs->radioregaddr, 0); - b0 = (u32) R_REG(&pi->regs->radioregdata); - W_REG_FLUSH(&pi->regs->radioregaddr, 1); - b1 = (u32) R_REG(&pi->regs->radioregdata); - W_REG_FLUSH(&pi->regs->radioregaddr, 2); - b2 = (u32) R_REG(&pi->regs->radioregdata); + bcma_wflush16(pi->d11core, D11REGOFFS(radioregaddr), 0); + b0 = (u32) bcma_read16(pi->d11core, D11REGOFFS(radioregdata)); + bcma_wflush16(pi->d11core, D11REGOFFS(radioregaddr), 1); + b1 = (u32) bcma_read16(pi->d11core, D11REGOFFS(radioregdata)); + bcma_wflush16(pi->d11core, D11REGOFFS(radioregaddr), 2); + b2 = (u32) bcma_read16(pi->d11core, D11REGOFFS(radioregdata)); id = ((b0 & 0xf) << 28) | (((b2 << 8) | b1) << 12) | ((b0 >> 4) & 0xf); } else { - W_REG_FLUSH(&pi->regs->phy4waddr, RADIO_IDCODE); - id = (u32) R_REG(&pi->regs->phy4wdatalo); - id |= (u32) R_REG(&pi->regs->phy4wdatahi) << 16; + bcma_wflush16(pi->d11core, D11REGOFFS(phy4waddr), RADIO_IDCODE); + id = (u32) bcma_read16(pi->d11core, D11REGOFFS(phy4wdatalo)); + id |= (u32) bcma_read16(pi->d11core, + D11REGOFFS(phy4wdatahi)) << 16; } pi->phy_wreg = 0; return id; @@ -275,75 +275,52 @@ void mod_radio_reg(struct brcms_phy *pi, u16 addr, u16 mask, u16 val) void write_phy_channel_reg(struct brcms_phy *pi, uint val) { - W_REG(&pi->regs->phychannel, val); + bcma_write16(pi->d11core, D11REGOFFS(phychannel), val); } u16 read_phy_reg(struct brcms_phy *pi, u16 addr) { - struct d11regs __iomem *regs; - - regs = pi->regs; - - W_REG_FLUSH(®s->phyregaddr, addr); + bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr), addr); pi->phy_wreg = 0; - return R_REG(®s->phyregdata); + return bcma_read16(pi->d11core, D11REGOFFS(phyregdata)); } void write_phy_reg(struct brcms_phy *pi, u16 addr, u16 val) { - struct d11regs __iomem *regs; - - regs = pi->regs; - #ifdef CONFIG_BCM47XX - W_REG_FLUSH(®s->phyregaddr, addr); - W_REG(®s->phyregdata, val); + bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr), addr); + bcma_write16(pi->d11core, D11REGOFFS(phyregdata), val); if (addr == 0x72) - (void)R_REG(®s->phyregdata); + (void)bcma_read16(pi->d11core, D11REGOFFS(phyversion)); #else - W_REG((u32 __iomem *)(®s->phyregaddr), addr | (val << 16)); + bcma_write32(pi->d11core, D11REGOFFS(phyregaddr), addr | (val << 16)); if (++pi->phy_wreg >= pi->phy_wreg_limit) { pi->phy_wreg = 0; - (void)R_REG(®s->phyversion); + (void)bcma_read16(pi->d11core, D11REGOFFS(phyversion)); } #endif } void and_phy_reg(struct brcms_phy *pi, u16 addr, u16 val) { - struct d11regs __iomem *regs; - - regs = pi->regs; - - W_REG_FLUSH(®s->phyregaddr, addr); - - W_REG(®s->phyregdata, (R_REG(®s->phyregdata) & val)); + bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr), addr); + bcma_mask16(pi->d11core, D11REGOFFS(phyregdata), val); pi->phy_wreg = 0; } void or_phy_reg(struct brcms_phy *pi, u16 addr, u16 val) { - struct d11regs __iomem *regs; - - regs = pi->regs; - - W_REG_FLUSH(®s->phyregaddr, addr); - - W_REG(®s->phyregdata, (R_REG(®s->phyregdata) | val)); + bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr), addr); + bcma_set16(pi->d11core, D11REGOFFS(phyregdata), val); pi->phy_wreg = 0; } void mod_phy_reg(struct brcms_phy *pi, u16 addr, u16 mask, u16 val) { - struct d11regs __iomem *regs; - - regs = pi->regs; - - W_REG_FLUSH(®s->phyregaddr, addr); - - W_REG(®s->phyregdata, - ((R_REG(®s->phyregdata) & ~mask) | (val & mask))); + val &= mask; + bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr), addr); + bcma_maskset16(pi->d11core, D11REGOFFS(phyregdata), ~mask, val); pi->phy_wreg = 0; } @@ -404,10 +381,8 @@ struct shared_phy *wlc_phy_shared_attach(struct shared_phy_params *shp) sh->sromrev = shp->sromrev; sh->boardtype = shp->boardtype; sh->boardrev = shp->boardrev; - sh->boardvendor = shp->boardvendor; sh->boardflags = shp->boardflags; sh->boardflags2 = shp->boardflags2; - sh->buscorerev = shp->buscorerev; sh->fast_timer = PHY_SW_TIMER_FAST; sh->slow_timer = PHY_SW_TIMER_SLOW; @@ -450,7 +425,7 @@ static u32 wlc_phy_get_radio_ver(struct brcms_phy *pi) } struct brcms_phy_pub * -wlc_phy_attach(struct shared_phy *sh, struct d11regs __iomem *regs, +wlc_phy_attach(struct shared_phy *sh, struct bcma_device *d11core, int bandtype, struct wiphy *wiphy) { struct brcms_phy *pi; @@ -462,7 +437,7 @@ wlc_phy_attach(struct shared_phy *sh, struct d11regs __iomem *regs, if (D11REV_IS(sh->corerev, 4)) sflags = SISF_2G_PHY | SISF_5G_PHY; else - sflags = ai_core_sflags(sh->sih, 0, 0); + sflags = bcma_aread32(d11core, BCMA_IOST); if (bandtype == BRCM_BAND_5G) { if ((sflags & (SISF_5G_PHY | SISF_DB_PHY)) == 0) @@ -480,7 +455,7 @@ wlc_phy_attach(struct shared_phy *sh, struct d11regs __iomem *regs, if (pi == NULL) return NULL; pi->wiphy = wiphy; - pi->regs = regs; + pi->d11core = d11core; pi->sh = sh; pi->phy_init_por = true; pi->phy_wreg_limit = PHY_WREG_LIMIT; @@ -495,7 +470,7 @@ wlc_phy_attach(struct shared_phy *sh, struct d11regs __iomem *regs, pi->pubpi.coreflags = SICF_GMODE; wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags); - phyversion = R_REG(&pi->regs->phyversion); + phyversion = bcma_read16(pi->d11core, D11REGOFFS(phyversion)); pi->pubpi.phy_type = PHY_TYPE(phyversion); pi->pubpi.phy_rev = phyversion & PV_PV_MASK; @@ -507,8 +482,8 @@ wlc_phy_attach(struct shared_phy *sh, struct d11regs __iomem *regs, pi->pubpi.phy_corenum = PHY_CORE_NUM_2; pi->pubpi.ana_rev = (phyversion & PV_AV_MASK) >> PV_AV_SHIFT; - if (!pi->pubpi.phy_type == PHY_TYPE_N && - !pi->pubpi.phy_type == PHY_TYPE_LCN) + if (pi->pubpi.phy_type != PHY_TYPE_N && + pi->pubpi.phy_type != PHY_TYPE_LCN) goto err; if (bandtype == BRCM_BAND_5G) { @@ -779,14 +754,14 @@ void wlc_phy_init(struct brcms_phy_pub *pih, u16 chanspec) pi->radio_chanspec = chanspec; - mc = R_REG(&pi->regs->maccontrol); + mc = bcma_read32(pi->d11core, D11REGOFFS(maccontrol)); if (WARN(mc & MCTL_EN_MAC, "HW error MAC running on init")) return; if (!(pi->measure_hold & PHY_HOLD_FOR_SCAN)) pi->measure_hold |= PHY_HOLD_FOR_NOT_ASSOC; - if (WARN(!(ai_core_sflags(pi->sh->sih, 0, 0) & SISF_FCLKA), + if (WARN(!(bcma_aread32(pi->d11core, BCMA_IOST) & SISF_FCLKA), "HW error SISF_FCLKA\n")) return; @@ -825,8 +800,8 @@ void wlc_phy_cal_init(struct brcms_phy_pub *pih) struct brcms_phy *pi = (struct brcms_phy *) pih; void (*cal_init)(struct brcms_phy *) = NULL; - if (WARN((R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC) != 0, - "HW error: MAC enabled during phy cal\n")) + if (WARN((bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) & + MCTL_EN_MAC) != 0, "HW error: MAC enabled during phy cal\n")) return; if (!pi->initialized) { @@ -1017,7 +992,7 @@ wlc_phy_init_radio_regs(struct brcms_phy *pi, void wlc_phy_do_dummy_tx(struct brcms_phy *pi, bool ofdm, bool pa_on) { #define DUMMY_PKT_LEN 20 - struct d11regs __iomem *regs = pi->regs; + struct bcma_device *core = pi->d11core; int i, count; u8 ofdmpkt[DUMMY_PKT_LEN] = { 0xcc, 0x01, 0x02, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, @@ -1033,26 +1008,28 @@ void wlc_phy_do_dummy_tx(struct brcms_phy *pi, bool ofdm, bool pa_on) wlapi_bmac_write_template_ram(pi->sh->physhim, 0, DUMMY_PKT_LEN, dummypkt); - W_REG(®s->xmtsel, 0); + bcma_write16(core, D11REGOFFS(xmtsel), 0); if (D11REV_GE(pi->sh->corerev, 11)) - W_REG(®s->wepctl, 0x100); + bcma_write16(core, D11REGOFFS(wepctl), 0x100); else - W_REG(®s->wepctl, 0); + bcma_write16(core, D11REGOFFS(wepctl), 0); - W_REG(®s->txe_phyctl, (ofdm ? 1 : 0) | PHY_TXC_ANT_0); + bcma_write16(core, D11REGOFFS(txe_phyctl), + (ofdm ? 1 : 0) | PHY_TXC_ANT_0); if (ISNPHY(pi) || ISLCNPHY(pi)) - W_REG(®s->txe_phyctl1, 0x1A02); + bcma_write16(core, D11REGOFFS(txe_phyctl1), 0x1A02); - W_REG(®s->txe_wm_0, 0); - W_REG(®s->txe_wm_1, 0); + bcma_write16(core, D11REGOFFS(txe_wm_0), 0); + bcma_write16(core, D11REGOFFS(txe_wm_1), 0); - W_REG(®s->xmttplatetxptr, 0); - W_REG(®s->xmttxcnt, DUMMY_PKT_LEN); + bcma_write16(core, D11REGOFFS(xmttplatetxptr), 0); + bcma_write16(core, D11REGOFFS(xmttxcnt), DUMMY_PKT_LEN); - W_REG(®s->xmtsel, ((8 << 8) | (1 << 5) | (1 << 2) | 2)); + bcma_write16(core, D11REGOFFS(xmtsel), + ((8 << 8) | (1 << 5) | (1 << 2) | 2)); - W_REG(®s->txe_ctl, 0); + bcma_write16(core, D11REGOFFS(txe_ctl), 0); if (!pa_on) { if (ISNPHY(pi)) @@ -1060,27 +1037,28 @@ void wlc_phy_do_dummy_tx(struct brcms_phy *pi, bool ofdm, bool pa_on) } if (ISNPHY(pi) || ISLCNPHY(pi)) - W_REG(®s->txe_aux, 0xD0); + bcma_write16(core, D11REGOFFS(txe_aux), 0xD0); else - W_REG(®s->txe_aux, ((1 << 5) | (1 << 4))); + bcma_write16(core, D11REGOFFS(txe_aux), ((1 << 5) | (1 << 4))); - (void)R_REG(®s->txe_aux); + (void)bcma_read16(core, D11REGOFFS(txe_aux)); i = 0; count = ofdm ? 30 : 250; while ((i++ < count) - && (R_REG(®s->txe_status) & (1 << 7))) + && (bcma_read16(core, D11REGOFFS(txe_status)) & (1 << 7))) udelay(10); i = 0; - while ((i++ < 10) - && ((R_REG(®s->txe_status) & (1 << 10)) == 0)) + while ((i++ < 10) && + ((bcma_read16(core, D11REGOFFS(txe_status)) & (1 << 10)) == 0)) udelay(10); i = 0; - while ((i++ < 10) && ((R_REG(®s->ifsstat) & (1 << 8)))) + while ((i++ < 10) && + ((bcma_read16(core, D11REGOFFS(ifsstat)) & (1 << 8)))) udelay(10); if (!pa_on) { @@ -1137,7 +1115,7 @@ static bool wlc_phy_cal_txpower_recalc_sw(struct brcms_phy *pi) void wlc_phy_switch_radio(struct brcms_phy_pub *pih, bool on) { struct brcms_phy *pi = (struct brcms_phy *) pih; - (void)R_REG(&pi->regs->maccontrol); + (void)bcma_read32(pi->d11core, D11REGOFFS(maccontrol)); if (ISNPHY(pi)) { wlc_phy_switch_radio_nphy(pi, on); @@ -1377,7 +1355,7 @@ void wlc_phy_txpower_target_set(struct brcms_phy_pub *ppi, memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_SDM], &txpwr->mcs_40_mimo[0], BRCMS_NUM_RATES_MCS_2_STREAM); - if (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC) + if (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) & MCTL_EN_MAC) mac_enabled = true; if (mac_enabled) @@ -1407,7 +1385,8 @@ int wlc_phy_txpower_set(struct brcms_phy_pub *ppi, uint qdbm, bool override) if (!SCAN_INPROG_PHY(pi)) { bool suspend; - suspend = (0 == (R_REG(&pi->regs->maccontrol) & + suspend = (0 == (bcma_read32(pi->d11core, + D11REGOFFS(maccontrol)) & MCTL_EN_MAC)); if (!suspend) @@ -1860,18 +1839,17 @@ void wlc_phy_runbist_config(struct brcms_phy_pub *ppi, bool start_end) if (NREV_IS(pi->pubpi.phy_rev, 3) || NREV_IS(pi->pubpi.phy_rev, 4)) { - W_REG(&pi->regs->phyregaddr, 0xa0); - (void)R_REG(&pi->regs->phyregaddr); - rxc = R_REG(&pi->regs->phyregdata); - W_REG(&pi->regs->phyregdata, - (0x1 << 15) | rxc); + bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr), + 0xa0); + bcma_set16(pi->d11core, D11REGOFFS(phyregdata), + 0x1 << 15); } } else { if (NREV_IS(pi->pubpi.phy_rev, 3) || NREV_IS(pi->pubpi.phy_rev, 4)) { - W_REG(&pi->regs->phyregaddr, 0xa0); - (void)R_REG(&pi->regs->phyregaddr); - W_REG(&pi->regs->phyregdata, rxc); + bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr), + 0xa0); + bcma_write16(pi->d11core, D11REGOFFS(phyregdata), rxc); } wlc_phy_por_inform(ppi); @@ -1991,7 +1969,9 @@ void wlc_phy_txpower_hw_ctrl_set(struct brcms_phy_pub *ppi, bool hwpwrctrl) pi->txpwrctrl = hwpwrctrl; if (ISNPHY(pi)) { - suspend = (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC)); + suspend = (0 == (bcma_read32(pi->d11core, + D11REGOFFS(maccontrol)) & + MCTL_EN_MAC)); if (!suspend) wlapi_suspend_mac_and_wait(pi->sh->physhim); @@ -2193,7 +2173,8 @@ void wlc_phy_ant_rxdiv_set(struct brcms_phy_pub *ppi, u8 val) if (!pi->sh->clk) return; - suspend = (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC)); + suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) & + MCTL_EN_MAC)); if (!suspend) wlapi_suspend_mac_and_wait(pi->sh->physhim); @@ -2411,8 +2392,8 @@ wlc_phy_noise_sample_request(struct brcms_phy_pub *pih, u8 reason, u8 ch) wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0); wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0); - OR_REG(&pi->regs->maccommand, - MCMD_BG_NOISE); + bcma_set32(pi->d11core, D11REGOFFS(maccommand), + MCMD_BG_NOISE); } else { wlapi_suspend_mac_and_wait(pi->sh->physhim); wlc_lcnphy_deaf_mode(pi, (bool) 0); @@ -2430,8 +2411,8 @@ wlc_phy_noise_sample_request(struct brcms_phy_pub *pih, u8 reason, u8 ch) wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0); wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0); - OR_REG(&pi->regs->maccommand, - MCMD_BG_NOISE); + bcma_set32(pi->d11core, D11REGOFFS(maccommand), + MCMD_BG_NOISE); } else { struct phy_iq_est est[PHY_CORE_MAX]; u32 cmplx_pwr[PHY_CORE_MAX]; @@ -2924,29 +2905,29 @@ void wlc_lcnphy_epa_switch(struct brcms_phy *pi, bool mode) mod_phy_reg(pi, 0x44c, (0x1 << 2), (1) << 2); } - ai_corereg(pi->sh->sih, SI_CC_IDX, - offsetof(struct chipcregs, gpiocontrol), - ~0x0, 0x0); - ai_corereg(pi->sh->sih, SI_CC_IDX, - offsetof(struct chipcregs, gpioout), 0x40, - 0x40); - ai_corereg(pi->sh->sih, SI_CC_IDX, - offsetof(struct chipcregs, gpioouten), 0x40, - 0x40); + ai_cc_reg(pi->sh->sih, + offsetof(struct chipcregs, gpiocontrol), + ~0x0, 0x0); + ai_cc_reg(pi->sh->sih, + offsetof(struct chipcregs, gpioout), + 0x40, 0x40); + ai_cc_reg(pi->sh->sih, + offsetof(struct chipcregs, gpioouten), + 0x40, 0x40); } else { mod_phy_reg(pi, 0x44c, (0x1 << 2), (0) << 2); mod_phy_reg(pi, 0x44d, (0x1 << 2), (0) << 2); - ai_corereg(pi->sh->sih, SI_CC_IDX, - offsetof(struct chipcregs, gpioout), 0x40, - 0x00); - ai_corereg(pi->sh->sih, SI_CC_IDX, - offsetof(struct chipcregs, gpioouten), 0x40, - 0x0); - ai_corereg(pi->sh->sih, SI_CC_IDX, - offsetof(struct chipcregs, gpiocontrol), - ~0x0, 0x40); + ai_cc_reg(pi->sh->sih, + offsetof(struct chipcregs, gpioout), + 0x40, 0x00); + ai_cc_reg(pi->sh->sih, + offsetof(struct chipcregs, gpioouten), + 0x40, 0x0); + ai_cc_reg(pi->sh->sih, + offsetof(struct chipcregs, gpiocontrol), + ~0x0, 0x40); } } } diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_hal.h b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_hal.h index 96e15163222b..e34a71e7d242 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_hal.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_hal.h @@ -166,7 +166,6 @@ struct shared_phy_params { struct phy_shim_info *physhim; uint unit; uint corerev; - uint buscorerev; u16 vid; u16 did; uint chip; @@ -175,7 +174,6 @@ struct shared_phy_params { uint sromrev; uint boardtype; uint boardrev; - uint boardvendor; u32 boardflags; u32 boardflags2; }; @@ -183,7 +181,7 @@ struct shared_phy_params { extern struct shared_phy *wlc_phy_shared_attach(struct shared_phy_params *shp); extern struct brcms_phy_pub *wlc_phy_attach(struct shared_phy *sh, - struct d11regs __iomem *regs, + struct bcma_device *d11core, int bandtype, struct wiphy *wiphy); extern void wlc_phy_detach(struct brcms_phy_pub *ppi); diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_int.h b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_int.h index 5f9478b1c993..af00e2c2b266 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_int.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_int.h @@ -503,10 +503,8 @@ struct shared_phy { uint sromrev; uint boardtype; uint boardrev; - uint boardvendor; u32 boardflags; u32 boardflags2; - uint buscorerev; uint fast_timer; uint slow_timer; uint glacial_timer; @@ -559,7 +557,7 @@ struct brcms_phy { } u; bool user_txpwr_at_rfport; - struct d11regs __iomem *regs; + struct bcma_device *d11core; struct brcms_phy *next; struct brcms_phy_pub pubpi; @@ -1090,7 +1088,7 @@ extern void wlc_phy_table_write_nphy(struct brcms_phy *pi, u32, u32, u32, #define BRCMS_PHY_WAR_PR51571(pi) \ if (NREV_LT((pi)->pubpi.phy_rev, 3)) \ - (void)R_REG(&(pi)->regs->maccontrol) + (void)bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) extern void wlc_phy_cal_perical_nphy_run(struct brcms_phy *pi, u8 caltype); extern void wlc_phy_aci_reset_nphy(struct brcms_phy *pi); diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c index a63aa99d9810..ce8562aa5db0 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c @@ -1603,7 +1603,7 @@ wlc_lcnphy_set_chanspec_tweaks(struct brcms_phy *pi, u16 chanspec) si_pmu_pllupd(pi->sh->sih); write_phy_reg(pi, 0x942, 0); wlc_lcnphy_txrx_spur_avoidance_mode(pi, false); - pi_lcn->lcnphy_spurmod = 0; + pi_lcn->lcnphy_spurmod = false; mod_phy_reg(pi, 0x424, (0xff << 8), (0x1b) << 8); write_phy_reg(pi, 0x425, 0x5907); @@ -1616,7 +1616,7 @@ wlc_lcnphy_set_chanspec_tweaks(struct brcms_phy *pi, u16 chanspec) write_phy_reg(pi, 0x942, 0); wlc_lcnphy_txrx_spur_avoidance_mode(pi, true); - pi_lcn->lcnphy_spurmod = 0; + pi_lcn->lcnphy_spurmod = false; mod_phy_reg(pi, 0x424, (0xff << 8), (0x1f) << 8); write_phy_reg(pi, 0x425, 0x590a); @@ -2325,7 +2325,7 @@ static s8 wlc_lcnphy_tempcompensated_txpwrctrl(struct brcms_phy *pi) { s8 index, delta_brd, delta_temp, new_index, tempcorrx; s16 manp, meas_temp, temp_diff; - bool neg = 0; + bool neg = false; u16 temp; struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; @@ -2348,7 +2348,7 @@ static s8 wlc_lcnphy_tempcompensated_txpwrctrl(struct brcms_phy *pi) manp = LCNPHY_TEMPSENSE(pi_lcn->lcnphy_rawtempsense); temp_diff = manp - meas_temp; if (temp_diff < 0) { - neg = 1; + neg = true; temp_diff = -temp_diff; } @@ -2813,10 +2813,8 @@ static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi) u16 SAVE_jtag_auxpga = read_radio_reg(pi, RADIO_2064_REG0FF) & 0x10; u16 SAVE_iqadc_aux_en = read_radio_reg(pi, RADIO_2064_REG11F) & 4; idleTssi = read_phy_reg(pi, 0x4ab); - suspend = - (0 == - (R_REG(&((struct brcms_phy *) pi)->regs->maccontrol) & - MCTL_EN_MAC)); + suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) & + MCTL_EN_MAC)); if (!suspend) wlapi_suspend_mac_and_wait(pi->sh->physhim); wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF); @@ -2890,7 +2888,8 @@ static void wlc_lcnphy_vbat_temp_sense_setup(struct brcms_phy *pi, u8 mode) for (i = 0; i < 14; i++) values_to_save[i] = read_phy_reg(pi, tempsense_phy_regs[i]); - suspend = (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC)); + suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) & + MCTL_EN_MAC)); if (!suspend) wlapi_suspend_mac_and_wait(pi->sh->physhim); save_txpwrCtrlEn = read_radio_reg(pi, 0x4a4); @@ -3016,8 +3015,8 @@ static void wlc_lcnphy_tx_pwr_ctrl_init(struct brcms_phy_pub *ppi) bool suspend; struct brcms_phy *pi = (struct brcms_phy *) ppi; - suspend = - (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC)); + suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) & + MCTL_EN_MAC)); if (!suspend) wlapi_suspend_mac_and_wait(pi->sh->physhim); @@ -3535,15 +3534,17 @@ wlc_lcnphy_samp_cap(struct brcms_phy *pi, int clip_detect_algo, u16 thresh, timer = 0; old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da); - curval1 = R_REG(&pi->regs->psm_corectlsts); + curval1 = bcma_read16(pi->d11core, D11REGOFFS(psm_corectlsts)); ptr[130] = 0; - W_REG(&pi->regs->psm_corectlsts, ((1 << 6) | curval1)); + bcma_write16(pi->d11core, D11REGOFFS(psm_corectlsts), + ((1 << 6) | curval1)); - W_REG(&pi->regs->smpl_clct_strptr, 0x7E00); - W_REG(&pi->regs->smpl_clct_stpptr, 0x8000); + bcma_write16(pi->d11core, D11REGOFFS(smpl_clct_strptr), 0x7E00); + bcma_write16(pi->d11core, D11REGOFFS(smpl_clct_stpptr), 0x8000); udelay(20); - curval2 = R_REG(&pi->regs->psm_phy_hdr_param); - W_REG(&pi->regs->psm_phy_hdr_param, curval2 | 0x30); + curval2 = bcma_read16(pi->d11core, D11REGOFFS(psm_phy_hdr_param)); + bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param), + curval2 | 0x30); write_phy_reg(pi, 0x555, 0x0); write_phy_reg(pi, 0x5a6, 0x5); @@ -3560,19 +3561,19 @@ wlc_lcnphy_samp_cap(struct brcms_phy *pi, int clip_detect_algo, u16 thresh, sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da); write_phy_reg(pi, 0x6da, (u32) (sslpnCalibClkEnCtrl | 0x2008)); - stpptr = R_REG(&pi->regs->smpl_clct_stpptr); - curptr = R_REG(&pi->regs->smpl_clct_curptr); + stpptr = bcma_read16(pi->d11core, D11REGOFFS(smpl_clct_stpptr)); + curptr = bcma_read16(pi->d11core, D11REGOFFS(smpl_clct_curptr)); do { udelay(10); - curptr = R_REG(&pi->regs->smpl_clct_curptr); + curptr = bcma_read16(pi->d11core, D11REGOFFS(smpl_clct_curptr)); timer++; } while ((curptr != stpptr) && (timer < 500)); - W_REG(&pi->regs->psm_phy_hdr_param, 0x2); + bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param), 0x2); strptr = 0x7E00; - W_REG(&pi->regs->tplatewrptr, strptr); + bcma_write32(pi->d11core, D11REGOFFS(tplatewrptr), strptr); while (strptr < 0x8000) { - val = R_REG(&pi->regs->tplatewrdata); + val = bcma_read32(pi->d11core, D11REGOFFS(tplatewrdata)); imag = ((val >> 16) & 0x3ff); real = ((val) & 0x3ff); if (imag > 511) @@ -3597,8 +3598,8 @@ wlc_lcnphy_samp_cap(struct brcms_phy *pi, int clip_detect_algo, u16 thresh, } write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl); - W_REG(&pi->regs->psm_phy_hdr_param, curval2); - W_REG(&pi->regs->psm_corectlsts, curval1); + bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param), curval2); + bcma_write16(pi->d11core, D11REGOFFS(psm_corectlsts), curval1); } static void @@ -3681,8 +3682,8 @@ wlc_lcnphy_a1(struct brcms_phy *pi, int cal_type, int num_levels, wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16); udelay(20); for (phy_c8 = 0; phy_c7 != 0 && phy_c8 < num_levels; phy_c8++) { - phy_c23 = 1; - phy_c22 = 0; + phy_c23 = true; + phy_c22 = false; switch (cal_type) { case 0: phy_c10 = 511; @@ -3700,18 +3701,18 @@ wlc_lcnphy_a1(struct brcms_phy *pi, int cal_type, int num_levels, phy_c9 = read_phy_reg(pi, 0x93d); phy_c9 = 2 * phy_c9; - phy_c24 = 0; + phy_c24 = false; phy_c5 = 7; - phy_c25 = 1; + phy_c25 = true; while (1) { write_radio_reg(pi, RADIO_2064_REG026, (phy_c5 & 0x7) | ((phy_c5 & 0x7) << 4)); udelay(50); - phy_c22 = 0; + phy_c22 = false; ptr[130] = 0; wlc_lcnphy_samp_cap(pi, 1, phy_c9, &ptr[0], 2); if (ptr[130] == 1) - phy_c22 = 1; + phy_c22 = true; if (phy_c22) phy_c5 -= 1; if ((phy_c22 != phy_c24) && (!phy_c25)) @@ -3721,7 +3722,7 @@ wlc_lcnphy_a1(struct brcms_phy *pi, int cal_type, int num_levels, if (phy_c5 <= 0 || phy_c5 >= 7) break; phy_c24 = phy_c22; - phy_c25 = 0; + phy_c25 = false; } if (phy_c5 < 0) @@ -3772,10 +3773,10 @@ wlc_lcnphy_a1(struct brcms_phy *pi, int cal_type, int num_levels, phy_c13 = phy_c11; phy_c14 = phy_c12; } - phy_c23 = 0; + phy_c23 = false; } } - phy_c23 = 1; + phy_c23 = true; phy_c15 = phy_c13; phy_c16 = phy_c14; phy_c7 = phy_c7 >> 1; @@ -3965,12 +3966,12 @@ s16 wlc_lcnphy_tempsense_new(struct brcms_phy *pi, bool mode) { u16 tempsenseval1, tempsenseval2; s16 avg = 0; - bool suspend = 0; + bool suspend = false; if (mode == 1) { - suspend = - (0 == - (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC)); + suspend = (0 == (bcma_read32(pi->d11core, + D11REGOFFS(maccontrol)) & + MCTL_EN_MAC)); if (!suspend) wlapi_suspend_mac_and_wait(pi->sh->physhim); wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE); @@ -4007,14 +4008,14 @@ u16 wlc_lcnphy_tempsense(struct brcms_phy *pi, bool mode) { u16 tempsenseval1, tempsenseval2; s32 avg = 0; - bool suspend = 0; + bool suspend = false; u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; if (mode == 1) { - suspend = - (0 == - (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC)); + suspend = (0 == (bcma_read32(pi->d11core, + D11REGOFFS(maccontrol)) & + MCTL_EN_MAC)); if (!suspend) wlapi_suspend_mac_and_wait(pi->sh->physhim); wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE); @@ -4075,12 +4076,12 @@ s8 wlc_lcnphy_vbatsense(struct brcms_phy *pi, bool mode) { u16 vbatsenseval; s32 avg = 0; - bool suspend = 0; + bool suspend = false; if (mode == 1) { - suspend = - (0 == - (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC)); + suspend = (0 == (bcma_read32(pi->d11core, + D11REGOFFS(maccontrol)) & + MCTL_EN_MAC)); if (!suspend) wlapi_suspend_mac_and_wait(pi->sh->physhim); wlc_lcnphy_vbat_temp_sense_setup(pi, VBATSENSE); @@ -4127,8 +4128,8 @@ static void wlc_lcnphy_glacial_timer_based_cal(struct brcms_phy *pi) s8 index; u16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; - suspend = - (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC)); + suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) & + MCTL_EN_MAC)); if (!suspend) wlapi_suspend_mac_and_wait(pi->sh->physhim); wlc_lcnphy_deaf_mode(pi, true); @@ -4166,8 +4167,8 @@ static void wlc_lcnphy_periodic_cal(struct brcms_phy *pi) pi_lcn->lcnphy_full_cal_channel = CHSPEC_CHANNEL(pi->radio_chanspec); index = pi_lcn->lcnphy_current_index; - suspend = - (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC)); + suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) & + MCTL_EN_MAC)); if (!suspend) { wlapi_bmac_write_shm(pi->sh->physhim, M_CTS_DURATION, 10000); wlapi_suspend_mac_and_wait(pi->sh->physhim); diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c index ec9b56639d54..a16f1ab292fd 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c @@ -17802,7 +17802,7 @@ static void wlc_phy_txpwrctrl_pwr_setup_nphy(struct brcms_phy *pi) if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12)) { wlapi_bmac_mctrl(pi->sh->physhim, MCTL_PHYLOCK, MCTL_PHYLOCK); - (void)R_REG(&pi->regs->maccontrol); + (void)bcma_read32(pi->d11core, D11REGOFFS(maccontrol)); udelay(1); } @@ -17953,7 +17953,7 @@ static void wlc_phy_txpwrctrl_pwr_setup_nphy(struct brcms_phy *pi) if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12)) { wlapi_bmac_mctrl(pi->sh->physhim, MCTL_PHYLOCK, MCTL_PHYLOCK); - (void)R_REG(&pi->regs->maccontrol); + (void)bcma_read32(pi->d11core, D11REGOFFS(maccontrol)); udelay(1); } @@ -19447,8 +19447,6 @@ void wlc_phy_init_nphy(struct brcms_phy *pi) u8 tx_pwr_ctrl_state; bool do_nphy_cal = false; uint core; - uint origidx, intr_val; - struct d11regs __iomem *regs; u32 d11_clk_ctl_st; bool do_rssi_cal = false; @@ -19462,25 +19460,21 @@ void wlc_phy_init_nphy(struct brcms_phy *pi) (pi->sh->chippkg == BCM4718_PKG_ID))) { if ((pi->sh->boardflags & BFL_EXTLNA) && (CHSPEC_IS2G(pi->radio_chanspec))) - ai_corereg(pi->sh->sih, SI_CC_IDX, - offsetof(struct chipcregs, chipcontrol), - 0x40, 0x40); + ai_cc_reg(pi->sh->sih, + offsetof(struct chipcregs, chipcontrol), + 0x40, 0x40); } if ((pi->nphy_gband_spurwar2_en) && CHSPEC_IS2G(pi->radio_chanspec) && CHSPEC_IS40(pi->radio_chanspec)) { - regs = (struct d11regs __iomem *) - ai_switch_core(pi->sh->sih, - D11_CORE_ID, &origidx, - &intr_val); - d11_clk_ctl_st = R_REG(®s->clk_ctl_st); - AND_REG(®s->clk_ctl_st, - ~(CCS_FORCEHT | CCS_HTAREQ)); + d11_clk_ctl_st = bcma_read32(pi->d11core, + D11REGOFFS(clk_ctl_st)); + bcma_mask32(pi->d11core, D11REGOFFS(clk_ctl_st), + ~(CCS_FORCEHT | CCS_HTAREQ)); - W_REG(®s->clk_ctl_st, d11_clk_ctl_st); - - ai_restore_core(pi->sh->sih, origidx, intr_val); + bcma_write32(pi->d11core, D11REGOFFS(clk_ctl_st), + d11_clk_ctl_st); } pi->use_int_tx_iqlo_cal_nphy = @@ -19885,7 +19879,8 @@ void wlc_phy_rxcore_setstate_nphy(struct brcms_phy_pub *pih, u8 rxcore_bitmask) if (!pi->sh->clk) return; - suspend = (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC)); + suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) & + MCTL_EN_MAC)); if (!suspend) wlapi_suspend_mac_and_wait(pi->sh->physhim); @@ -21263,28 +21258,28 @@ wlc_phy_chanspec_nphy_setup(struct brcms_phy *pi, u16 chanspec, val = read_phy_reg(pi, 0x09) & NPHY_BandControl_currentBand; if (CHSPEC_IS5G(chanspec) && !val) { - val = R_REG(&pi->regs->psm_phy_hdr_param); - W_REG(&pi->regs->psm_phy_hdr_param, + val = bcma_read16(pi->d11core, D11REGOFFS(psm_phy_hdr_param)); + bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param), (val | MAC_PHY_FORCE_CLK)); or_phy_reg(pi, (NPHY_TO_BPHY_OFF + BPHY_BB_CONFIG), (BBCFG_RESETCCA | BBCFG_RESETRX)); - W_REG(&pi->regs->psm_phy_hdr_param, val); + bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param), val); or_phy_reg(pi, 0x09, NPHY_BandControl_currentBand); } else if (!CHSPEC_IS5G(chanspec) && val) { and_phy_reg(pi, 0x09, ~NPHY_BandControl_currentBand); - val = R_REG(&pi->regs->psm_phy_hdr_param); - W_REG(&pi->regs->psm_phy_hdr_param, + val = bcma_read16(pi->d11core, D11REGOFFS(psm_phy_hdr_param)); + bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param), (val | MAC_PHY_FORCE_CLK)); and_phy_reg(pi, (NPHY_TO_BPHY_OFF + BPHY_BB_CONFIG), (u16) (~(BBCFG_RESETCCA | BBCFG_RESETRX))); - W_REG(&pi->regs->psm_phy_hdr_param, val); + bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param), val); } write_phy_reg(pi, 0x1ce, ci->PHY_BW1a); @@ -21342,24 +21337,23 @@ wlc_phy_chanspec_nphy_setup(struct brcms_phy *pi, u16 chanspec, spuravoid = 1; wlapi_bmac_core_phypll_ctl(pi->sh->physhim, false); - si_pmu_spuravoid(pi->sh->sih, spuravoid); + si_pmu_spuravoid_pllupdate(pi->sh->sih, spuravoid); wlapi_bmac_core_phypll_ctl(pi->sh->physhim, true); if ((pi->sh->chip == BCM43224_CHIP_ID) || (pi->sh->chip == BCM43225_CHIP_ID)) { - if (spuravoid == 1) { - - W_REG(&pi->regs->tsf_clk_frac_l, - 0x5341); - W_REG(&pi->regs->tsf_clk_frac_h, - 0x8); + bcma_write16(pi->d11core, + D11REGOFFS(tsf_clk_frac_l), + 0x5341); + bcma_write16(pi->d11core, + D11REGOFFS(tsf_clk_frac_h), 0x8); } else { - - W_REG(&pi->regs->tsf_clk_frac_l, - 0x8889); - W_REG(&pi->regs->tsf_clk_frac_h, - 0x8); + bcma_write16(pi->d11core, + D11REGOFFS(tsf_clk_frac_l), + 0x8889); + bcma_write16(pi->d11core, + D11REGOFFS(tsf_clk_frac_h), 0x8); } } @@ -21499,13 +21493,13 @@ void wlc_phy_antsel_init(struct brcms_phy_pub *ppi, bool lut_init) ai_gpiocontrol(pi->sh->sih, mask, mask, GPIO_DRV_PRIORITY); - mc = R_REG(&pi->regs->maccontrol); + mc = bcma_read32(pi->d11core, D11REGOFFS(maccontrol)); mc &= ~MCTL_GPOUT_SEL_MASK; - W_REG(&pi->regs->maccontrol, mc); + bcma_write32(pi->d11core, D11REGOFFS(maccontrol), mc); - OR_REG(&pi->regs->psm_gpio_oe, mask); + bcma_set16(pi->d11core, D11REGOFFS(psm_gpio_oe), mask); - AND_REG(&pi->regs->psm_gpio_out, ~mask); + bcma_mask16(pi->d11core, D11REGOFFS(psm_gpio_out), ~mask); if (lut_init) { write_phy_reg(pi, 0xf8, 0x02d8); @@ -21522,9 +21516,8 @@ u16 wlc_phy_classifier_nphy(struct brcms_phy *pi, u16 mask, u16 val) bool suspended = false; if (D11REV_IS(pi->sh->corerev, 16)) { - suspended = - (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC) ? - false : true; + suspended = (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) & + MCTL_EN_MAC) ? false : true; if (!suspended) wlapi_suspend_mac_and_wait(pi->sh->physhim); } @@ -25383,7 +25376,8 @@ static void wlc_phy_a4(struct brcms_phy *pi, bool full_cal) if (pi->nphy_papd_skip == 1) return; - phy_b3 = (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC)); + phy_b3 = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) & + MCTL_EN_MAC)); if (!phy_b3) wlapi_suspend_mac_and_wait(pi->sh->physhim); @@ -28357,7 +28351,7 @@ void wlc_phy_txpower_recalc_target_nphy(struct brcms_phy *pi) if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12)) { wlapi_bmac_mctrl(pi->sh->physhim, MCTL_PHYLOCK, MCTL_PHYLOCK); - (void)R_REG(&pi->regs->maccontrol); + (void)bcma_read32(pi->d11core, D11REGOFFS(maccontrol)); udelay(1); } diff --git a/drivers/net/wireless/brcm80211/brcmsmac/pmu.c b/drivers/net/wireless/brcm80211/brcmsmac/pmu.c index 12ba575f5785..4931d29d077b 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/pmu.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/pmu.c @@ -115,10 +115,10 @@ static void si_pmu_res_masks(struct si_pub *sih, u32 * pmin, u32 * pmax) uint rsrcs; /* # resources */ - rsrcs = (sih->pmucaps & PCAP_RC_MASK) >> PCAP_RC_SHIFT; + rsrcs = (ai_get_pmucaps(sih) & PCAP_RC_MASK) >> PCAP_RC_SHIFT; /* determine min/max rsrc masks */ - switch (sih->chip) { + switch (ai_get_chip_id(sih)) { case BCM43224_CHIP_ID: case BCM43225_CHIP_ID: /* ??? */ @@ -139,75 +139,84 @@ static void si_pmu_res_masks(struct si_pub *sih, u32 * pmin, u32 * pmax) *pmax = max_mask; } -static void -si_pmu_spuravoid_pllupdate(struct si_pub *sih, struct chipcregs __iomem *cc, - u8 spuravoid) +void si_pmu_spuravoid_pllupdate(struct si_pub *sih, u8 spuravoid) { u32 tmp = 0; + struct bcma_device *core; - switch (sih->chip) { + /* switch to chipc */ + core = ai_findcore(sih, BCMA_CORE_CHIPCOMMON, 0); + + switch (ai_get_chip_id(sih)) { case BCM43224_CHIP_ID: case BCM43225_CHIP_ID: if (spuravoid == 1) { - W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL0); - W_REG(&cc->pllcontrol_data, 0x11500010); - W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL1); - W_REG(&cc->pllcontrol_data, 0x000C0C06); - W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL2); - W_REG(&cc->pllcontrol_data, 0x0F600a08); - W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL3); - W_REG(&cc->pllcontrol_data, 0x00000000); - W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL4); - W_REG(&cc->pllcontrol_data, 0x2001E920); - W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL5); - W_REG(&cc->pllcontrol_data, 0x88888815); + bcma_write32(core, CHIPCREGOFFS(pllcontrol_addr), + PMU1_PLL0_PLLCTL0); + bcma_write32(core, CHIPCREGOFFS(pllcontrol_data), + 0x11500010); + bcma_write32(core, CHIPCREGOFFS(pllcontrol_addr), + PMU1_PLL0_PLLCTL1); + bcma_write32(core, CHIPCREGOFFS(pllcontrol_data), + 0x000C0C06); + bcma_write32(core, CHIPCREGOFFS(pllcontrol_addr), + PMU1_PLL0_PLLCTL2); + bcma_write32(core, CHIPCREGOFFS(pllcontrol_data), + 0x0F600a08); + bcma_write32(core, CHIPCREGOFFS(pllcontrol_addr), + PMU1_PLL0_PLLCTL3); + bcma_write32(core, CHIPCREGOFFS(pllcontrol_data), + 0x00000000); + bcma_write32(core, CHIPCREGOFFS(pllcontrol_addr), + PMU1_PLL0_PLLCTL4); + bcma_write32(core, CHIPCREGOFFS(pllcontrol_data), + 0x2001E920); + bcma_write32(core, CHIPCREGOFFS(pllcontrol_addr), + PMU1_PLL0_PLLCTL5); + bcma_write32(core, CHIPCREGOFFS(pllcontrol_data), + 0x88888815); } else { - W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL0); - W_REG(&cc->pllcontrol_data, 0x11100010); - W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL1); - W_REG(&cc->pllcontrol_data, 0x000c0c06); - W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL2); - W_REG(&cc->pllcontrol_data, 0x03000a08); - W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL3); - W_REG(&cc->pllcontrol_data, 0x00000000); - W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL4); - W_REG(&cc->pllcontrol_data, 0x200005c0); - W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL5); - W_REG(&cc->pllcontrol_data, 0x88888815); + bcma_write32(core, CHIPCREGOFFS(pllcontrol_addr), + PMU1_PLL0_PLLCTL0); + bcma_write32(core, CHIPCREGOFFS(pllcontrol_data), + 0x11100010); + bcma_write32(core, CHIPCREGOFFS(pllcontrol_addr), + PMU1_PLL0_PLLCTL1); + bcma_write32(core, CHIPCREGOFFS(pllcontrol_data), + 0x000c0c06); + bcma_write32(core, CHIPCREGOFFS(pllcontrol_addr), + PMU1_PLL0_PLLCTL2); + bcma_write32(core, CHIPCREGOFFS(pllcontrol_data), + 0x03000a08); + bcma_write32(core, CHIPCREGOFFS(pllcontrol_addr), + PMU1_PLL0_PLLCTL3); + bcma_write32(core, CHIPCREGOFFS(pllcontrol_data), + 0x00000000); + bcma_write32(core, CHIPCREGOFFS(pllcontrol_addr), + PMU1_PLL0_PLLCTL4); + bcma_write32(core, CHIPCREGOFFS(pllcontrol_data), + 0x200005c0); + bcma_write32(core, CHIPCREGOFFS(pllcontrol_addr), + PMU1_PLL0_PLLCTL5); + bcma_write32(core, CHIPCREGOFFS(pllcontrol_data), + 0x88888815); } tmp = 1 << 10; break; - W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL0); - W_REG(&cc->pllcontrol_data, 0x11100008); - W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL1); - W_REG(&cc->pllcontrol_data, 0x0c000c06); - W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL2); - W_REG(&cc->pllcontrol_data, 0x03000a08); - W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL3); - W_REG(&cc->pllcontrol_data, 0x00000000); - W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL4); - W_REG(&cc->pllcontrol_data, 0x200005c0); - W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL5); - W_REG(&cc->pllcontrol_data, 0x88888855); - - tmp = 1 << 10; - break; - default: /* bail out */ return; } - tmp |= R_REG(&cc->pmucontrol); - W_REG(&cc->pmucontrol, tmp); + bcma_set32(core, CHIPCREGOFFS(pmucontrol), tmp); } u16 si_pmu_fast_pwrup_delay(struct si_pub *sih) { uint delay = PMU_MAX_TRANSITION_DLY; - switch (sih->chip) { + switch (ai_get_chip_id(sih)) { case BCM43224_CHIP_ID: case BCM43225_CHIP_ID: case BCM4313_CHIP_ID: @@ -220,54 +229,35 @@ u16 si_pmu_fast_pwrup_delay(struct si_pub *sih) return (u16) delay; } -void si_pmu_sprom_enable(struct si_pub *sih, bool enable) -{ - struct chipcregs __iomem *cc; - uint origidx; - - /* Remember original core before switch to chipc */ - origidx = ai_coreidx(sih); - cc = ai_setcoreidx(sih, SI_CC_IDX); - - /* Return to original core */ - ai_setcoreidx(sih, origidx); -} - /* Read/write a chipcontrol reg */ u32 si_pmu_chipcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val) { - ai_corereg(sih, SI_CC_IDX, offsetof(struct chipcregs, chipcontrol_addr), - ~0, reg); - return ai_corereg(sih, SI_CC_IDX, - offsetof(struct chipcregs, chipcontrol_data), mask, - val); + ai_cc_reg(sih, offsetof(struct chipcregs, chipcontrol_addr), ~0, reg); + return ai_cc_reg(sih, offsetof(struct chipcregs, chipcontrol_data), + mask, val); } /* Read/write a regcontrol reg */ u32 si_pmu_regcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val) { - ai_corereg(sih, SI_CC_IDX, offsetof(struct chipcregs, regcontrol_addr), - ~0, reg); - return ai_corereg(sih, SI_CC_IDX, - offsetof(struct chipcregs, regcontrol_data), mask, - val); + ai_cc_reg(sih, offsetof(struct chipcregs, regcontrol_addr), ~0, reg); + return ai_cc_reg(sih, offsetof(struct chipcregs, regcontrol_data), + mask, val); } /* Read/write a pllcontrol reg */ u32 si_pmu_pllcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val) { - ai_corereg(sih, SI_CC_IDX, offsetof(struct chipcregs, pllcontrol_addr), - ~0, reg); - return ai_corereg(sih, SI_CC_IDX, - offsetof(struct chipcregs, pllcontrol_data), mask, - val); + ai_cc_reg(sih, offsetof(struct chipcregs, pllcontrol_addr), ~0, reg); + return ai_cc_reg(sih, offsetof(struct chipcregs, pllcontrol_data), + mask, val); } /* PMU PLL update */ void si_pmu_pllupd(struct si_pub *sih) { - ai_corereg(sih, SI_CC_IDX, offsetof(struct chipcregs, pmucontrol), - PCTL_PLL_PLLCTL_UPD, PCTL_PLL_PLLCTL_UPD); + ai_cc_reg(sih, offsetof(struct chipcregs, pmucontrol), + PCTL_PLL_PLLCTL_UPD, PCTL_PLL_PLLCTL_UPD); } /* query alp/xtal clock frequency */ @@ -276,10 +266,10 @@ u32 si_pmu_alp_clock(struct si_pub *sih) u32 clock = ALP_CLOCK; /* bail out with default */ - if (!(sih->cccaps & CC_CAP_PMU)) + if (!(ai_get_cccaps(sih) & CC_CAP_PMU)) return clock; - switch (sih->chip) { + switch (ai_get_chip_id(sih)) { case BCM43224_CHIP_ID: case BCM43225_CHIP_ID: case BCM4313_CHIP_ID: @@ -293,95 +283,29 @@ u32 si_pmu_alp_clock(struct si_pub *sih) return clock; } -void si_pmu_spuravoid(struct si_pub *sih, u8 spuravoid) -{ - struct chipcregs __iomem *cc; - uint origidx, intr_val; - - /* Remember original core before switch to chipc */ - cc = (struct chipcregs __iomem *) - ai_switch_core(sih, CC_CORE_ID, &origidx, &intr_val); - - /* update the pll changes */ - si_pmu_spuravoid_pllupdate(sih, cc, spuravoid); - - /* Return to original core */ - ai_restore_core(sih, origidx, intr_val); -} - /* initialize PMU */ void si_pmu_init(struct si_pub *sih) { - struct chipcregs __iomem *cc; - uint origidx; + struct bcma_device *core; - /* Remember original core before switch to chipc */ - origidx = ai_coreidx(sih); - cc = ai_setcoreidx(sih, SI_CC_IDX); - - if (sih->pmurev == 1) - AND_REG(&cc->pmucontrol, ~PCTL_NOILP_ON_WAIT); - else if (sih->pmurev >= 2) - OR_REG(&cc->pmucontrol, PCTL_NOILP_ON_WAIT); + /* select chipc */ + core = ai_findcore(sih, BCMA_CORE_CHIPCOMMON, 0); - /* Return to original core */ - ai_setcoreidx(sih, origidx); -} - -/* initialize PMU chip controls and other chip level stuff */ -void si_pmu_chip_init(struct si_pub *sih) -{ - uint origidx; - - /* Gate off SPROM clock and chip select signals */ - si_pmu_sprom_enable(sih, false); - - /* Remember original core */ - origidx = ai_coreidx(sih); - - /* Return to original core */ - ai_setcoreidx(sih, origidx); -} - -/* initialize PMU switch/regulators */ -void si_pmu_swreg_init(struct si_pub *sih) -{ -} - -/* initialize PLL */ -void si_pmu_pll_init(struct si_pub *sih, uint xtalfreq) -{ - struct chipcregs __iomem *cc; - uint origidx; - - /* Remember original core before switch to chipc */ - origidx = ai_coreidx(sih); - cc = ai_setcoreidx(sih, SI_CC_IDX); - - switch (sih->chip) { - case BCM4313_CHIP_ID: - case BCM43224_CHIP_ID: - case BCM43225_CHIP_ID: - /* ??? */ - break; - default: - break; - } - - /* Return to original core */ - ai_setcoreidx(sih, origidx); + if (ai_get_pmurev(sih) == 1) + bcma_mask32(core, CHIPCREGOFFS(pmucontrol), + ~PCTL_NOILP_ON_WAIT); + else if (ai_get_pmurev(sih) >= 2) + bcma_set32(core, CHIPCREGOFFS(pmucontrol), PCTL_NOILP_ON_WAIT); } /* initialize PMU resources */ void si_pmu_res_init(struct si_pub *sih) { - struct chipcregs __iomem *cc; - uint origidx; + struct bcma_device *core; u32 min_mask = 0, max_mask = 0; - /* Remember original core before switch to chipc */ - origidx = ai_coreidx(sih); - cc = ai_setcoreidx(sih, SI_CC_IDX); + /* select to chipc */ + core = ai_findcore(sih, BCMA_CORE_CHIPCOMMON, 0); /* Determine min/max rsrc masks */ si_pmu_res_masks(sih, &min_mask, &max_mask); @@ -391,55 +315,50 @@ void si_pmu_res_init(struct si_pub *sih) /* Program max resource mask */ if (max_mask) - W_REG(&cc->max_res_mask, max_mask); + bcma_write32(core, CHIPCREGOFFS(max_res_mask), max_mask); /* Program min resource mask */ if (min_mask) - W_REG(&cc->min_res_mask, min_mask); + bcma_write32(core, CHIPCREGOFFS(min_res_mask), min_mask); /* Add some delay; allow resources to come up and settle. */ mdelay(2); - - /* Return to original core */ - ai_setcoreidx(sih, origidx); } u32 si_pmu_measure_alpclk(struct si_pub *sih) { - struct chipcregs __iomem *cc; - uint origidx; + struct bcma_device *core; u32 alp_khz; - if (sih->pmurev < 10) + if (ai_get_pmurev(sih) < 10) return 0; /* Remember original core before switch to chipc */ - origidx = ai_coreidx(sih); - cc = ai_setcoreidx(sih, SI_CC_IDX); + core = ai_findcore(sih, BCMA_CORE_CHIPCOMMON, 0); - if (R_REG(&cc->pmustatus) & PST_EXTLPOAVAIL) { + if (bcma_read32(core, CHIPCREGOFFS(pmustatus)) & PST_EXTLPOAVAIL) { u32 ilp_ctr, alp_hz; /* * Enable the reg to measure the freq, * in case it was disabled before */ - W_REG(&cc->pmu_xtalfreq, - 1U << PMU_XTALFREQ_REG_MEASURE_SHIFT); + bcma_write32(core, CHIPCREGOFFS(pmu_xtalfreq), + 1U << PMU_XTALFREQ_REG_MEASURE_SHIFT); /* Delay for well over 4 ILP clocks */ udelay(1000); /* Read the latched number of ALP ticks per 4 ILP ticks */ - ilp_ctr = - R_REG(&cc->pmu_xtalfreq) & PMU_XTALFREQ_REG_ILPCTR_MASK; + ilp_ctr = bcma_read32(core, CHIPCREGOFFS(pmu_xtalfreq)) & + PMU_XTALFREQ_REG_ILPCTR_MASK; /* * Turn off the PMU_XTALFREQ_REG_MEASURE_SHIFT * bit to save power */ - W_REG(&cc->pmu_xtalfreq, 0); + bcma_write32(core, CHIPCREGOFFS(pmu_xtalfreq), 0); /* Calculate ALP frequency */ alp_hz = (ilp_ctr * EXT_ILP_HZ) / 4; @@ -452,8 +371,5 @@ u32 si_pmu_measure_alpclk(struct si_pub *sih) } else alp_khz = 0; - /* Return to original core */ - ai_setcoreidx(sih, origidx); - return alp_khz; } diff --git a/drivers/net/wireless/brcm80211/brcmsmac/pmu.h b/drivers/net/wireless/brcm80211/brcmsmac/pmu.h index 3a08c620640e..3e39c5e0f9ff 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/pmu.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/pmu.h @@ -26,13 +26,10 @@ extern u32 si_pmu_chipcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val); extern u32 si_pmu_regcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val); extern u32 si_pmu_alp_clock(struct si_pub *sih); extern void si_pmu_pllupd(struct si_pub *sih); -extern void si_pmu_spuravoid(struct si_pub *sih, u8 spuravoid); +extern void si_pmu_spuravoid_pllupdate(struct si_pub *sih, u8 spuravoid); extern u32 si_pmu_pllcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val); extern void si_pmu_init(struct si_pub *sih); -extern void si_pmu_chip_init(struct si_pub *sih); -extern void si_pmu_pll_init(struct si_pub *sih, u32 xtalfreq); extern void si_pmu_res_init(struct si_pub *sih); -extern void si_pmu_swreg_init(struct si_pub *sih); extern u32 si_pmu_measure_alpclk(struct si_pub *sih); #endif /* _BRCM_PMU_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/pub.h b/drivers/net/wireless/brcm80211/brcmsmac/pub.h index 21ccf3a03987..f0038ad7d7bf 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/pub.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/pub.h @@ -17,6 +17,7 @@ #ifndef _BRCM_PUB_H_ #define _BRCM_PUB_H_ +#include <linux/bcma/bcma.h> #include <brcmu_wifi.h> #include "types.h" #include "defs.h" @@ -530,9 +531,8 @@ struct brcms_antselcfg { /* common functions for every port */ extern struct brcms_c_info * -brcms_c_attach(struct brcms_info *wl, u16 vendor, u16 device, uint unit, - bool piomode, void __iomem *regsva, struct pci_dev *btparam, - uint *perr); +brcms_c_attach(struct brcms_info *wl, struct bcma_device *core, uint unit, + bool piomode, uint *perr); extern uint brcms_c_detach(struct brcms_c_info *wlc); extern int brcms_c_up(struct brcms_c_info *wlc); extern uint brcms_c_down(struct brcms_c_info *wlc); diff --git a/drivers/net/wireless/brcm80211/brcmsmac/srom.c b/drivers/net/wireless/brcm80211/brcmsmac/srom.c index b6987ea9fc68..61092156755e 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/srom.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/srom.c @@ -586,17 +586,6 @@ static const struct brcms_sromvar perpath_pci_sromvars[] = { * shared between devices. */ static u8 brcms_srom_crc8_table[CRC8_TABLE_SIZE]; -static u8 __iomem * -srom_window_address(struct si_pub *sih, u8 __iomem *curmap) -{ - if (sih->ccrev < 32) - return curmap + PCI_BAR0_SPROM_OFFSET; - if (sih->cccaps & CC_CAP_SROM) - return curmap + PCI_16KB0_CCREGS_OFFSET + CC_SROM_OTP; - - return NULL; -} - static uint mask_shift(u16 mask) { uint i; @@ -779,17 +768,27 @@ _initvars_srom_pci(u8 sromrev, u16 *srom, struct list_head *var_list) * Return 0 on success, nonzero on error. */ static int -sprom_read_pci(struct si_pub *sih, u8 __iomem *sprom, uint wordoff, - u16 *buf, uint nwords, bool check_crc) +sprom_read_pci(struct si_pub *sih, u16 *buf, uint nwords, bool check_crc) { int err = 0; uint i; u8 *bbuf = (u8 *)buf; /* byte buffer */ uint nbytes = nwords << 1; + struct bcma_device *core; + uint sprom_offset; + + /* determine core to read */ + if (ai_get_ccrev(sih) < 32) { + core = ai_findcore(sih, BCMA_CORE_80211, 0); + sprom_offset = PCI_BAR0_SPROM_OFFSET; + } else { + core = ai_findcore(sih, BCMA_CORE_CHIPCOMMON, 0); + sprom_offset = CHIPCREGOFFS(sromotp); + } /* read the sprom in bytes */ for (i = 0; i < nbytes; i++) - bbuf[i] = readb(sprom+i); + bbuf[i] = bcma_read8(core, sprom_offset+i); if (buf[0] == 0xffff) /* @@ -851,10 +850,9 @@ static int otp_read_pci(struct si_pub *sih, u16 *buf, uint nwords) * Initialize nonvolatile variable table from sprom. * Return 0 on success, nonzero on error. */ -static int initvars_srom_pci(struct si_pub *sih, void __iomem *curmap) +int srom_var_init(struct si_pub *sih) { u16 *srom; - u8 __iomem *sromwindow; u8 sromrev = 0; u32 sr; int err = 0; @@ -866,12 +864,9 @@ static int initvars_srom_pci(struct si_pub *sih, void __iomem *curmap) if (!srom) return -ENOMEM; - sromwindow = srom_window_address(sih, curmap); - crc8_populate_lsb(brcms_srom_crc8_table, SROM_CRC8_POLY); if (ai_is_sprom_available(sih)) { - err = sprom_read_pci(sih, sromwindow, 0, srom, - SROM4_WORDS, true); + err = sprom_read_pci(sih, srom, SROM4_WORDS, true); if (err == 0) /* srom read and passed crc */ @@ -921,21 +916,6 @@ void srom_free_vars(struct si_pub *sih) kfree(entry); } } -/* - * Initialize local vars from the right source for this platform. - * Return 0 on success, nonzero on error. - */ -int srom_var_init(struct si_pub *sih, void __iomem *curmap) -{ - uint len; - - len = 0; - - if (curmap != NULL) - return initvars_srom_pci(sih, curmap); - - return -EINVAL; -} /* * Search the name=value vars for a specific one and return its value. diff --git a/drivers/net/wireless/brcm80211/brcmsmac/srom.h b/drivers/net/wireless/brcm80211/brcmsmac/srom.h index c81df9798e50..f2a58f262c99 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/srom.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/srom.h @@ -20,7 +20,7 @@ #include "types.h" /* Prototypes */ -extern int srom_var_init(struct si_pub *sih, void __iomem *curmap); +extern int srom_var_init(struct si_pub *sih); extern void srom_free_vars(struct si_pub *sih); extern int srom_read(struct si_pub *sih, uint bus, void *curmap, diff --git a/drivers/net/wireless/brcm80211/brcmsmac/types.h b/drivers/net/wireless/brcm80211/brcmsmac/types.h index 27a814b07462..e11ae83111e4 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/types.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/types.h @@ -250,66 +250,18 @@ do { \ wiphy_err(dev, "%s: " fmt, __func__, ##args); \ } while (0) -/* - * Register access macros. - * - * These macro's take a pointer to the address to read as one of their - * arguments. The macro itself deduces the size of the IO transaction (u8, u16 - * or u32). Advantage of this approach in combination with using a struct to - * define the registers in a register block, is that access size and access - * location are defined in only one spot. This reduces the risk of the - * programmer trying to use an unsupported transaction size on a register. - * - */ - -#define R_REG(r) \ - ({ \ - __typeof(*(r)) __osl_v; \ - switch (sizeof(*(r))) { \ - case sizeof(u8): \ - __osl_v = readb((u8 __iomem *)(r)); \ - break; \ - case sizeof(u16): \ - __osl_v = readw((u16 __iomem *)(r)); \ - break; \ - case sizeof(u32): \ - __osl_v = readl((u32 __iomem *)(r)); \ - break; \ - } \ - __osl_v; \ - }) - -#define W_REG(r, v) do { \ - switch (sizeof(*(r))) { \ - case sizeof(u8): \ - writeb((u8)((v) & 0xFF), (u8 __iomem *)(r)); \ - break; \ - case sizeof(u16): \ - writew((u16)((v) & 0xFFFF), (u16 __iomem *)(r)); \ - break; \ - case sizeof(u32): \ - writel((u32)(v), (u32 __iomem *)(r)); \ - break; \ - } \ - } while (0) - #ifdef CONFIG_BCM47XX /* * bcm4716 (which includes 4717 & 4718), plus 4706 on PCIe can reorder * transactions. As a fix, a read after write is performed on certain places * in the code. Older chips and the newer 5357 family don't require this fix. */ -#define W_REG_FLUSH(r, v) ({ W_REG((r), (v)); (void)R_REG(r); }) +#define bcma_wflush16(c, o, v) \ + ({ bcma_write16(c, o, v); (void)bcma_read16(c, o); }) #else -#define W_REG_FLUSH(r, v) W_REG((r), (v)) +#define bcma_wflush16(c, o, v) bcma_write16(c, o, v) #endif /* CONFIG_BCM47XX */ -#define AND_REG(r, v) W_REG((r), R_REG(r) & (v)) -#define OR_REG(r, v) W_REG((r), R_REG(r) | (v)) - -#define SET_REG(r, mask, val) \ - W_REG((r), ((R_REG(r) & ~(mask)) | (val))) - /* multi-bool data type: set of bools, mbool is true if any is set */ /* set one bool */ diff --git a/drivers/net/wireless/brcm80211/include/chipcommon.h b/drivers/net/wireless/brcm80211/include/chipcommon.h index fefabc39e646..f96834a7c055 100644 --- a/drivers/net/wireless/brcm80211/include/chipcommon.h +++ b/drivers/net/wireless/brcm80211/include/chipcommon.h @@ -19,6 +19,8 @@ #include "defs.h" /* for PAD macro */ +#define CHIPCREGOFFS(field) offsetof(struct chipcregs, field) + struct chipcregs { u32 chipid; /* 0x0 */ u32 capabilities; diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index 5441ad195119..89e9d3a78c3c 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c @@ -656,6 +656,9 @@ static const struct pcmcia_device_id hostap_cs_ids[] = { "Addtron", "AWP-100 Wireless PCMCIA", "Version 01.02", 0xe6ec52ce, 0x08649af2, 0x4b74baa0), PCMCIA_DEVICE_PROD_ID123( + "Canon", "Wireless LAN CF Card K30225", "Version 01.00", + 0x96ef6fe2, 0x263fcbab, 0xa57adb8c), + PCMCIA_DEVICE_PROD_ID123( "D", "Link DWL-650 11Mbps WLAN Card", "Version 01.02", 0x71b18589, 0xb6f1b0ab, 0x4b74baa0), PCMCIA_DEVICE_PROD_ID123( diff --git a/drivers/net/wireless/iwlegacy/common.c b/drivers/net/wireless/iwlegacy/common.c index 7e2924f332a7..881ba043770a 100644 --- a/drivers/net/wireless/iwlegacy/common.c +++ b/drivers/net/wireless/iwlegacy/common.c @@ -2786,9 +2786,8 @@ il_tx_queue_alloc(struct il_priv *il, struct il_tx_queue *txq, u32 id) /* Driver ilate data, only for Tx (not command) queues, * not shared with device. */ if (id != il->cmd_queue) { - txq->txb = - kzalloc(sizeof(txq->txb[0]) * TFD_QUEUE_SIZE_MAX, - GFP_KERNEL); + txq->txb = kcalloc(TFD_QUEUE_SIZE_MAX, sizeof(txq->txb[0]), + GFP_KERNEL); if (!txq->txb) { IL_ERR("kmalloc for auxiliary BD " "structures failed\n"); diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index 57703d5209d7..ae08498dfcad 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -102,12 +102,28 @@ config IWLWIFI_DEVICE_TRACING occur. endmenu -config IWLWIFI_DEVICE_SVTOOL - bool "iwlwifi device svtool support" +config IWLWIFI_DEVICE_TESTMODE + def_bool y depends on IWLWIFI - select NL80211_TESTMODE + depends on NL80211_TESTMODE help - This option enables the svtool support for iwlwifi device through - NL80211_TESTMODE. svtool is a software validation tool that runs in - the user space and interacts with the device in the kernel space - through the generic netlink message via NL80211_TESTMODE channel. + This option enables the testmode support for iwlwifi device through + NL80211_TESTMODE. This provide the capabilities of enable user space + validation applications to interacts with the device through the + generic netlink message via NL80211_TESTMODE channel. + +config IWLWIFI_P2P + bool "iwlwifi experimental P2P support" + depends on IWLWIFI + help + This option enables experimental P2P support for some devices + based on microcode support. Since P2P support is still under + development, this option may even enable it for some devices + now that turn out to not support it in the future due to + microcode restrictions. + + To determine if your microcode supports the experimental P2P + offered by this option, check if the driver advertises AP + support when it is loaded. + + Say Y only if you want to experiment with P2P. diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index a7ab280994c8..9dc84a7354db 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -1,7 +1,7 @@ # WIFI obj-$(CONFIG_IWLWIFI) += iwlwifi.o iwlwifi-objs := iwl-agn.o iwl-agn-rs.o iwl-mac80211.o -iwlwifi-objs += iwl-agn-ucode.o iwl-agn-tx.o +iwlwifi-objs += iwl-ucode.o iwl-agn-tx.o iwlwifi-objs += iwl-agn-lib.o iwl-agn-calib.o iwl-io.o iwlwifi-objs += iwl-agn-tt.o iwl-agn-sta.o iwl-agn-rx.o @@ -18,7 +18,7 @@ iwlwifi-objs += iwl-trans-pcie.o iwl-trans-pcie-rx.o iwl-trans-pcie-tx.o iwlwifi-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o iwlwifi-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o -iwlwifi-$(CONFIG_IWLWIFI_DEVICE_SVTOOL) += iwl-sv-open.o +iwlwifi-$(CONFIG_IWLWIFI_DEVICE_TESTMODE) += iwl-testmode.o CFLAGS_iwl-devtrace.o := -I$(src) diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index e12b48c2cff6..8d3bad7ea5d3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -147,16 +147,7 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv) iwl1000_set_ct_threshold(priv); /* Set initial sensitivity parameters */ - /* Set initial calibration set */ hw_params(priv).sens = &iwl1000_sensitivity; - hw_params(priv).calib_init_cfg = - BIT(IWL_CALIB_XTAL) | - BIT(IWL_CALIB_LO) | - BIT(IWL_CALIB_TX_IQ) | - BIT(IWL_CALIB_TX_IQ_PERD) | - BIT(IWL_CALIB_BASE_BAND); - if (priv->cfg->need_dc_calib) - hw_params(priv).calib_init_cfg |= BIT(IWL_CALIB_DC); return 0; } @@ -191,6 +182,7 @@ static struct iwl_base_params iwl1000_base_params = { .chain_noise_scale = 1000, .wd_timeout = IWL_DEF_WD_TIMEOUT, .max_event_log_size = 128, + .wd_disable = true, }; static struct iwl_ht_params iwl1000_ht_params = { .ht_greenfield_support = true, diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index b3193571ed07..0c4688d95b65 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -143,17 +143,7 @@ static int iwl2000_hw_set_hw_params(struct iwl_priv *priv) iwl2000_set_ct_threshold(priv); /* Set initial sensitivity parameters */ - /* Set initial calibration set */ hw_params(priv).sens = &iwl2000_sensitivity; - hw_params(priv).calib_init_cfg = - BIT(IWL_CALIB_XTAL) | - BIT(IWL_CALIB_LO) | - BIT(IWL_CALIB_TX_IQ) | - BIT(IWL_CALIB_BASE_BAND); - if (priv->cfg->need_dc_calib) - hw_params(priv).calib_rt_cfg |= IWL_CALIB_CFG_DC_IDX; - if (priv->cfg->need_temp_offset_calib) - hw_params(priv).calib_init_cfg |= BIT(IWL_CALIB_TEMP_OFFSET); return 0; } @@ -258,7 +248,6 @@ static struct iwl_bt_params iwl2030_bt_params = { .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ .lib = &iwl2000_lib, \ .base_params = &iwl2000_base_params, \ - .need_dc_calib = true, \ .need_temp_offset_calib = true, \ .temp_offset_v2 = true, \ .led_mode = IWL_LED_RF_STATE, \ @@ -286,7 +275,6 @@ struct iwl_cfg iwl2000_2bgn_d_cfg = { .lib = &iwl2030_lib, \ .base_params = &iwl2030_base_params, \ .bt_params = &iwl2030_bt_params, \ - .need_dc_calib = true, \ .need_temp_offset_calib = true, \ .temp_offset_v2 = true, \ .led_mode = IWL_LED_RF_STATE, \ @@ -308,7 +296,6 @@ struct iwl_cfg iwl2030_2bgn_cfg = { .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ .lib = &iwl2000_lib, \ .base_params = &iwl2000_base_params, \ - .need_dc_calib = true, \ .need_temp_offset_calib = true, \ .temp_offset_v2 = true, \ .led_mode = IWL_LED_RF_STATE, \ @@ -338,7 +325,6 @@ struct iwl_cfg iwl105_bgn_d_cfg = { .lib = &iwl2030_lib, \ .base_params = &iwl2030_base_params, \ .bt_params = &iwl2030_bt_params, \ - .need_dc_calib = true, \ .need_temp_offset_calib = true, \ .temp_offset_v2 = true, \ .led_mode = IWL_LED_RF_STATE, \ diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index c511c98a89a8..6706d7c10bd8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -134,10 +134,10 @@ static struct iwl_sensitivity_ranges iwl5150_sensitivity = { #define IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF (-5) -static s32 iwl_temp_calib_to_offset(struct iwl_priv *priv) +static s32 iwl_temp_calib_to_offset(struct iwl_shared *shrd) { u16 temperature, voltage; - __le16 *temp_calib = (__le16 *)iwl_eeprom_query_addr(priv, + __le16 *temp_calib = (__le16 *)iwl_eeprom_query_addr(shrd, EEPROM_KELVIN_TEMPERATURE); temperature = le16_to_cpu(temp_calib[0]); @@ -151,7 +151,7 @@ static void iwl5150_set_ct_threshold(struct iwl_priv *priv) { const s32 volt2temp_coef = IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF; s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD_LEGACY) - - iwl_temp_calib_to_offset(priv); + iwl_temp_calib_to_offset(priv->shrd); hw_params(priv).ct_kill_threshold = threshold * volt2temp_coef; } @@ -186,14 +186,7 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) iwl5000_set_ct_threshold(priv); /* Set initial sensitivity parameters */ - /* Set initial calibration set */ hw_params(priv).sens = &iwl5000_sensitivity; - hw_params(priv).calib_init_cfg = - BIT(IWL_CALIB_XTAL) | - BIT(IWL_CALIB_LO) | - BIT(IWL_CALIB_TX_IQ) | - BIT(IWL_CALIB_TX_IQ_PERD) | - BIT(IWL_CALIB_BASE_BAND); return 0; } @@ -222,14 +215,7 @@ static int iwl5150_hw_set_hw_params(struct iwl_priv *priv) iwl5150_set_ct_threshold(priv); /* Set initial sensitivity parameters */ - /* Set initial calibration set */ hw_params(priv).sens = &iwl5150_sensitivity; - hw_params(priv).calib_init_cfg = - BIT(IWL_CALIB_LO) | - BIT(IWL_CALIB_TX_IQ) | - BIT(IWL_CALIB_BASE_BAND); - if (priv->cfg->need_dc_calib) - hw_params(priv).calib_init_cfg |= BIT(IWL_CALIB_DC); return 0; } @@ -237,7 +223,7 @@ static int iwl5150_hw_set_hw_params(struct iwl_priv *priv) static void iwl5150_temperature(struct iwl_priv *priv) { u32 vt = 0; - s32 offset = iwl_temp_calib_to_offset(priv); + s32 offset = iwl_temp_calib_to_offset(priv->shrd); vt = le32_to_cpu(priv->statistics.common.temperature); vt = vt / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF + offset; @@ -364,6 +350,7 @@ static struct iwl_base_params iwl5000_base_params = { .wd_timeout = IWL_LONG_WD_TIMEOUT, .max_event_log_size = 512, .no_idle_support = true, + .wd_disable = true, }; static struct iwl_ht_params iwl5000_ht_params = { .ht_greenfield_support = true, @@ -433,7 +420,7 @@ struct iwl_cfg iwl5350_agn_cfg = { .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, \ .lib = &iwl5150_lib, \ .base_params = &iwl5000_base_params, \ - .need_dc_calib = true, \ + .no_xtal_calib = true, \ .led_mode = IWL_LED_BLINK, \ .internal_wimax_coex = true diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index ee3363fdf309..3e277b6774f1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -46,11 +46,12 @@ #include "iwl-cfg.h" /* Highest firmware API version supported */ -#define IWL6000_UCODE_API_MAX 4 +#define IWL6000_UCODE_API_MAX 6 #define IWL6050_UCODE_API_MAX 5 #define IWL6000G2_UCODE_API_MAX 6 /* Oldest version we won't warn about */ +#define IWL6000_UCODE_API_OK 4 #define IWL6000G2_UCODE_API_OK 5 /* Lowest firmware API version supported */ @@ -80,7 +81,7 @@ static void iwl6000_set_ct_threshold(struct iwl_priv *priv) static void iwl6050_additional_nic_config(struct iwl_priv *priv) { /* Indicate calibration version to uCode. */ - if (iwlagn_eeprom_calib_version(priv) >= 6) + if (iwl_eeprom_calib_version(priv->shrd) >= 6) iwl_set_bit(bus(priv), CSR_GP_DRIVER_REG, CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6); } @@ -88,7 +89,7 @@ static void iwl6050_additional_nic_config(struct iwl_priv *priv) static void iwl6150_additional_nic_config(struct iwl_priv *priv) { /* Indicate calibration version to uCode. */ - if (iwlagn_eeprom_calib_version(priv) >= 6) + if (iwl_eeprom_calib_version(priv->shrd) >= 6) iwl_set_bit(bus(priv), CSR_GP_DRIVER_REG, CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6); iwl_set_bit(bus(priv), CSR_GP_DRIVER_REG, @@ -164,17 +165,7 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) iwl6000_set_ct_threshold(priv); /* Set initial sensitivity parameters */ - /* Set initial calibration set */ hw_params(priv).sens = &iwl6000_sensitivity; - hw_params(priv).calib_init_cfg = - BIT(IWL_CALIB_XTAL) | - BIT(IWL_CALIB_LO) | - BIT(IWL_CALIB_TX_IQ) | - BIT(IWL_CALIB_BASE_BAND); - if (priv->cfg->need_dc_calib) - hw_params(priv).calib_rt_cfg |= IWL_CALIB_CFG_DC_IDX; - if (priv->cfg->need_temp_offset_calib) - hw_params(priv).calib_init_cfg |= BIT(IWL_CALIB_TEMP_OFFSET); return 0; } @@ -364,7 +355,6 @@ static struct iwl_bt_params iwl6000_bt_params = { .eeprom_calib_ver = EEPROM_6005_TX_POWER_VERSION, \ .lib = &iwl6000_lib, \ .base_params = &iwl6000_g2_base_params, \ - .need_dc_calib = true, \ .need_temp_offset_calib = true, \ .led_mode = IWL_LED_RF_STATE @@ -406,7 +396,6 @@ struct iwl_cfg iwl6005_2agn_d_cfg = { .lib = &iwl6030_lib, \ .base_params = &iwl6000_g2_base_params, \ .bt_params = &iwl6000_bt_params, \ - .need_dc_calib = true, \ .need_temp_offset_calib = true, \ .led_mode = IWL_LED_RF_STATE, \ .adv_pm = true \ @@ -469,6 +458,7 @@ struct iwl_cfg iwl130_bg_cfg = { #define IWL_DEVICE_6000i \ .fw_name_pre = IWL6000_FW_PRE, \ .ucode_api_max = IWL6000_UCODE_API_MAX, \ + .ucode_api_ok = IWL6000_UCODE_API_OK, \ .ucode_api_min = IWL6000_UCODE_API_MIN, \ .valid_tx_ant = ANT_BC, /* .cfg overwrite */ \ .valid_rx_ant = ANT_BC, /* .cfg overwrite */ \ @@ -506,7 +496,6 @@ struct iwl_cfg iwl6000i_2bg_cfg = { .eeprom_ver = EEPROM_6050_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION, \ .base_params = &iwl6050_base_params, \ - .need_dc_calib = true, \ .led_mode = IWL_LED_BLINK, \ .internal_wimax_coex = true @@ -530,7 +519,6 @@ struct iwl_cfg iwl6050_2abg_cfg = { .eeprom_ver = EEPROM_6150_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_6150_TX_POWER_VERSION, \ .base_params = &iwl6050_base_params, \ - .need_dc_calib = true, \ .led_mode = IWL_LED_BLINK, \ .internal_wimax_coex = true @@ -549,17 +537,17 @@ struct iwl_cfg iwl6000_3agn_cfg = { .name = "Intel(R) Centrino(R) Ultimate-N 6300 AGN", .fw_name_pre = IWL6000_FW_PRE, .ucode_api_max = IWL6000_UCODE_API_MAX, + .ucode_api_ok = IWL6000_UCODE_API_OK, .ucode_api_min = IWL6000_UCODE_API_MIN, .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION, .lib = &iwl6000_lib, .base_params = &iwl6000_base_params, .ht_params = &iwl6000_ht_params, - .need_dc_calib = true, .led_mode = IWL_LED_BLINK, }; -MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_OK)); MODULE_FIRMWARE(IWL6050_MODULE_FIRMWARE(IWL6050_UCODE_API_MAX)); MODULE_FIRMWARE(IWL6005_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX)); MODULE_FIRMWARE(IWL6030_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c index 03bac48558b2..16971a020297 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c @@ -82,56 +82,64 @@ struct statistics_general_data { u32 beacon_energy_c; }; -int iwl_send_calib_results(struct iwl_priv *priv) +int iwl_send_calib_results(struct iwl_trans *trans) { - int ret = 0; - int i = 0; - struct iwl_host_cmd hcmd = { .id = REPLY_PHY_CALIBRATION_CMD, .flags = CMD_SYNC, }; - - for (i = 0; i < IWL_CALIB_MAX; i++) { - if ((BIT(i) & hw_params(priv).calib_init_cfg) && - priv->calib_results[i].buf) { - hcmd.len[0] = priv->calib_results[i].buf_len; - hcmd.data[0] = priv->calib_results[i].buf; - hcmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY; - ret = iwl_trans_send_cmd(trans(priv), &hcmd); - if (ret) { - IWL_ERR(priv, "Error %d iteration %d\n", - ret, i); - break; - } + struct iwl_calib_result *res; + + list_for_each_entry(res, &trans->calib_results, list) { + int ret; + + hcmd.len[0] = res->cmd_len; + hcmd.data[0] = &res->hdr; + hcmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY; + ret = iwl_trans_send_cmd(trans, &hcmd); + if (ret) { + IWL_ERR(trans, "Error %d on calib cmd %d\n", + ret, res->hdr.op_code); + return ret; } } - return ret; + return 0; } -int iwl_calib_set(struct iwl_calib_result *res, const u8 *buf, int len) +int iwl_calib_set(struct iwl_trans *trans, + const struct iwl_calib_hdr *cmd, int len) { - if (res->buf_len != len) { - kfree(res->buf); - res->buf = kzalloc(len, GFP_ATOMIC); - } - if (unlikely(res->buf == NULL)) + struct iwl_calib_result *res, *tmp; + + res = kmalloc(sizeof(*res) + len - sizeof(struct iwl_calib_hdr), + GFP_ATOMIC); + if (!res) return -ENOMEM; + memcpy(&res->hdr, cmd, len); + res->cmd_len = len; + + list_for_each_entry(tmp, &trans->calib_results, list) { + if (tmp->hdr.op_code == res->hdr.op_code) { + list_replace(&tmp->list, &res->list); + kfree(tmp); + return 0; + } + } + + /* wasn't in list already */ + list_add_tail(&res->list, &trans->calib_results); - res->buf_len = len; - memcpy(res->buf, buf, len); return 0; } -void iwl_calib_free_results(struct iwl_priv *priv) +void iwl_calib_free_results(struct iwl_trans *trans) { - int i; + struct iwl_calib_result *res, *tmp; - for (i = 0; i < IWL_CALIB_MAX; i++) { - kfree(priv->calib_results[i].buf); - priv->calib_results[i].buf = NULL; - priv->calib_results[i].buf_len = 0; + list_for_each_entry_safe(res, tmp, &trans->calib_results, list) { + list_del(&res->list); + kfree(res); } } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.h b/drivers/net/wireless/iwlwifi/iwl-agn-calib.h index a869fc9205d2..10275ce92bde 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-calib.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.h @@ -72,8 +72,4 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv); void iwl_init_sensitivity(struct iwl_priv *priv); void iwl_reset_run_time_calib(struct iwl_priv *priv); -int iwl_send_calib_results(struct iwl_priv *priv); -int iwl_calib_set(struct iwl_calib_result *res, const u8 *buf, int len); -void iwl_calib_free_results(struct iwl_priv *priv); - #endif /* __iwl_calib_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 0bc962217351..057f95233567 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -92,11 +92,11 @@ void iwlagn_temperature(struct iwl_priv *priv) iwl_tt_handler(priv); } -u16 iwlagn_eeprom_calib_version(struct iwl_priv *priv) +u16 iwl_eeprom_calib_version(struct iwl_shared *shrd) { struct iwl_eeprom_calib_hdr *hdr; - hdr = (struct iwl_eeprom_calib_hdr *)iwl_eeprom_query_addr(priv, + hdr = (struct iwl_eeprom_calib_hdr *)iwl_eeprom_query_addr(shrd, EEPROM_CALIB_ALL); return hdr->version; @@ -105,7 +105,7 @@ u16 iwlagn_eeprom_calib_version(struct iwl_priv *priv) /* * EEPROM */ -static u32 eeprom_indirect_address(const struct iwl_priv *priv, u32 address) +static u32 eeprom_indirect_address(const struct iwl_shared *shrd, u32 address) { u16 offset = 0; @@ -114,31 +114,31 @@ static u32 eeprom_indirect_address(const struct iwl_priv *priv, u32 address) switch (address & INDIRECT_TYPE_MSK) { case INDIRECT_HOST: - offset = iwl_eeprom_query16(priv, EEPROM_LINK_HOST); + offset = iwl_eeprom_query16(shrd, EEPROM_LINK_HOST); break; case INDIRECT_GENERAL: - offset = iwl_eeprom_query16(priv, EEPROM_LINK_GENERAL); + offset = iwl_eeprom_query16(shrd, EEPROM_LINK_GENERAL); break; case INDIRECT_REGULATORY: - offset = iwl_eeprom_query16(priv, EEPROM_LINK_REGULATORY); + offset = iwl_eeprom_query16(shrd, EEPROM_LINK_REGULATORY); break; case INDIRECT_TXP_LIMIT: - offset = iwl_eeprom_query16(priv, EEPROM_LINK_TXP_LIMIT); + offset = iwl_eeprom_query16(shrd, EEPROM_LINK_TXP_LIMIT); break; case INDIRECT_TXP_LIMIT_SIZE: - offset = iwl_eeprom_query16(priv, EEPROM_LINK_TXP_LIMIT_SIZE); + offset = iwl_eeprom_query16(shrd, EEPROM_LINK_TXP_LIMIT_SIZE); break; case INDIRECT_CALIBRATION: - offset = iwl_eeprom_query16(priv, EEPROM_LINK_CALIBRATION); + offset = iwl_eeprom_query16(shrd, EEPROM_LINK_CALIBRATION); break; case INDIRECT_PROCESS_ADJST: - offset = iwl_eeprom_query16(priv, EEPROM_LINK_PROCESS_ADJST); + offset = iwl_eeprom_query16(shrd, EEPROM_LINK_PROCESS_ADJST); break; case INDIRECT_OTHERS: - offset = iwl_eeprom_query16(priv, EEPROM_LINK_OTHERS); + offset = iwl_eeprom_query16(shrd, EEPROM_LINK_OTHERS); break; default: - IWL_ERR(priv, "illegal indirect type: 0x%X\n", + IWL_ERR(shrd->trans, "illegal indirect type: 0x%X\n", address & INDIRECT_TYPE_MSK); break; } @@ -147,11 +147,11 @@ static u32 eeprom_indirect_address(const struct iwl_priv *priv, u32 address) return (address & ADDRESS_MSK) + (offset << 1); } -const u8 *iwl_eeprom_query_addr(const struct iwl_priv *priv, size_t offset) +const u8 *iwl_eeprom_query_addr(const struct iwl_shared *shrd, size_t offset) { - u32 address = eeprom_indirect_address(priv, offset); - BUG_ON(address >= priv->cfg->base_params->eeprom_size); - return &priv->eeprom[address]; + u32 address = eeprom_indirect_address(shrd, offset); + BUG_ON(address >= shrd->priv->cfg->base_params->eeprom_size); + return &shrd->eeprom[address]; } struct iwl_mod_params iwlagn_mod_params = { @@ -934,57 +934,6 @@ u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant, u8 valid) return ant; } -/* notification wait support */ -void iwlagn_init_notification_wait(struct iwl_priv *priv, - struct iwl_notification_wait *wait_entry, - u8 cmd, - void (*fn)(struct iwl_priv *priv, - struct iwl_rx_packet *pkt, - void *data), - void *fn_data) -{ - wait_entry->fn = fn; - wait_entry->fn_data = fn_data; - wait_entry->cmd = cmd; - wait_entry->triggered = false; - wait_entry->aborted = false; - - spin_lock_bh(&priv->notif_wait_lock); - list_add(&wait_entry->list, &priv->notif_waits); - spin_unlock_bh(&priv->notif_wait_lock); -} - -int iwlagn_wait_notification(struct iwl_priv *priv, - struct iwl_notification_wait *wait_entry, - unsigned long timeout) -{ - int ret; - - ret = wait_event_timeout(priv->notif_waitq, - wait_entry->triggered || wait_entry->aborted, - timeout); - - spin_lock_bh(&priv->notif_wait_lock); - list_del(&wait_entry->list); - spin_unlock_bh(&priv->notif_wait_lock); - - if (wait_entry->aborted) - return -EIO; - - /* return value is always >= 0 */ - if (ret <= 0) - return -ETIMEDOUT; - return 0; -} - -void iwlagn_remove_notification(struct iwl_priv *priv, - struct iwl_notification_wait *wait_entry) -{ - spin_lock_bh(&priv->notif_wait_lock); - list_del(&wait_entry->list); - spin_unlock_bh(&priv->notif_wait_lock); -} - #ifdef CONFIG_PM_SLEEP static void iwlagn_convert_p1k(u16 *p1k, __le16 *out) { @@ -1208,7 +1157,7 @@ int iwlagn_suspend(struct iwl_priv *priv, * For QoS counters, we store the one to use next, so subtract 0x10 * since the uCode will add 0x10 before using the value. */ - for (i = 0; i < 8; i++) { + for (i = 0; i < IWL_MAX_TID_COUNT; i++) { seq = priv->shrd->tid_data[IWL_AP_ID][i].seq_number; seq -= 0x10; wakeup_filter_cmd.qos_seq[i] = cpu_to_le16(seq); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 359c47a4fcea..a23835a7797a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -298,7 +298,7 @@ static u8 rs_tl_add_packet(struct iwl_lq_sta *lq_data, } else return IWL_MAX_TID_COUNT; - if (unlikely(tid >= TID_MAX_LOAD_COUNT)) + if (unlikely(tid >= IWL_MAX_TID_COUNT)) return IWL_MAX_TID_COUNT; tl = &lq_data->load[tid]; @@ -352,7 +352,7 @@ static void rs_program_fix_rate(struct iwl_priv *priv, lq_sta->active_mimo2_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */ lq_sta->active_mimo3_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */ -#ifdef CONFIG_IWLWIFI_DEVICE_SVTOOL +#ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE /* testmode has higher priority to overwirte the fixed rate */ if (priv->tm_fixed_rate) lq_sta->dbg_fixed_rate = priv->tm_fixed_rate; @@ -379,7 +379,7 @@ static u32 rs_tl_get_load(struct iwl_lq_sta *lq_data, u8 tid) s32 index; struct iwl_traffic_load *tl = NULL; - if (tid >= TID_MAX_LOAD_COUNT) + if (tid >= IWL_MAX_TID_COUNT) return 0; tl = &(lq_data->load[tid]); @@ -444,11 +444,11 @@ static void rs_tl_turn_on_agg(struct iwl_priv *priv, u8 tid, struct iwl_lq_sta *lq_data, struct ieee80211_sta *sta) { - if (tid < TID_MAX_LOAD_COUNT) + if (tid < IWL_MAX_TID_COUNT) rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta); else - IWL_ERR(priv, "tid exceeds max load count: %d/%d\n", - tid, TID_MAX_LOAD_COUNT); + IWL_ERR(priv, "tid exceeds max TID count: %d/%d\n", + tid, IWL_MAX_TID_COUNT); } static inline int get_num_of_ant_from_rate(u32 rate_n_flags) @@ -1081,7 +1081,7 @@ done: if (sta && sta->supp_rates[sband->band]) rs_rate_scale_perform(priv, skb, sta, lq_sta); -#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_IWLWIFI_DEVICE_SVTOOL) +#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_IWLWIFI_DEVICE_TESTMODE) if ((priv->tm_fixed_rate) && (priv->tm_fixed_rate != lq_sta->dbg_fixed_rate)) rs_program_fix_rate(priv, lq_sta); @@ -2904,7 +2904,7 @@ void iwl_rs_rate_init(struct iwl_priv *priv, struct ieee80211_sta *sta, u8 sta_i if (sband->band == IEEE80211_BAND_5GHZ) lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; lq_sta->is_agg = 0; -#ifdef CONFIG_IWLWIFI_DEVICE_SVTOOL +#ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE priv->tm_fixed_rate = 0; #endif #ifdef CONFIG_MAC80211_DEBUGFS diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h index f4f6deb829ae..6675b3c816d9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h @@ -281,7 +281,6 @@ enum { #define TID_QUEUE_CELL_SPACING 50 /*mS */ #define TID_QUEUE_MAX_SIZE 20 #define TID_ROUND_VALUE 5 /* mS */ -#define TID_MAX_LOAD_COUNT 8 #define TID_MAX_TIME_DIFF ((TID_QUEUE_MAX_SIZE - 1) * TID_QUEUE_CELL_SPACING) #define TIME_WRAP_AROUND(x, y) (((y) > (x)) ? (y) - (x) : (0-(x)) + (y)) @@ -402,7 +401,7 @@ struct iwl_lq_sta { struct iwl_link_quality_cmd lq; struct iwl_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */ - struct iwl_traffic_load load[TID_MAX_LOAD_COUNT]; + struct iwl_traffic_load load[IWL_MAX_TID_COUNT]; u8 tx_agg_tid_en; #ifdef CONFIG_MAC80211_DEBUGFS struct dentry *rs_sta_dbgfs_scale_table_file; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c index fdb4c3786114..9001c23f27bb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c @@ -117,6 +117,7 @@ const char *get_cmd_string(u8 cmd) IWL_CMD(REPLY_WOWLAN_TKIP_PARAMS); IWL_CMD(REPLY_WOWLAN_KEK_KCK_MATERIAL); IWL_CMD(REPLY_WOWLAN_GET_STATUS); + IWL_CMD(REPLY_D3_CONFIG); default: return "UNKNOWN"; @@ -1130,9 +1131,9 @@ void iwl_setup_rx_handlers(struct iwl_priv *priv) priv->rx_handlers[REPLY_TX] = iwlagn_rx_reply_tx; /* set up notification wait support */ - spin_lock_init(&priv->notif_wait_lock); - INIT_LIST_HEAD(&priv->notif_waits); - init_waitqueue_head(&priv->notif_waitq); + spin_lock_init(&priv->shrd->notif_wait_lock); + INIT_LIST_HEAD(&priv->shrd->notif_waits); + init_waitqueue_head(&priv->shrd->notif_waitq); /* Set up BT Rx handlers */ if (priv->cfg->lib->bt_rx_handler_setup) @@ -1151,11 +1152,11 @@ int iwl_rx_dispatch(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb, * even if the RX handler consumes the RXB we have * access to it in the notification wait entry. */ - if (!list_empty(&priv->notif_waits)) { + if (!list_empty(&priv->shrd->notif_waits)) { struct iwl_notification_wait *w; - spin_lock(&priv->notif_wait_lock); - list_for_each_entry(w, &priv->notif_waits, list) { + spin_lock(&priv->shrd->notif_wait_lock); + list_for_each_entry(w, &priv->shrd->notif_waits, list) { if (w->cmd != pkt->hdr.cmd) continue; IWL_DEBUG_RX(priv, @@ -1164,11 +1165,11 @@ int iwl_rx_dispatch(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb, pkt->hdr.cmd); w->triggered = true; if (w->fn) - w->fn(priv, pkt, w->fn_data); + w->fn(trans(priv), pkt, w->fn_data); } - spin_unlock(&priv->notif_wait_lock); + spin_unlock(&priv->shrd->notif_wait_lock); - wake_up_all(&priv->notif_waitq); + wake_up_all(&priv->shrd->notif_waitq); } if (priv->pre_rx_handler) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index 8de97f5a1825..d21f535a3b4f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -60,7 +60,7 @@ static int iwlagn_disable_pan(struct iwl_priv *priv, u8 old_dev_type = send->dev_type; int ret; - iwlagn_init_notification_wait(priv, &disable_wait, + iwl_init_notification_wait(priv->shrd, &disable_wait, REPLY_WIPAN_DEACTIVATION_COMPLETE, NULL, NULL); @@ -74,9 +74,9 @@ static int iwlagn_disable_pan(struct iwl_priv *priv, if (ret) { IWL_ERR(priv, "Error disabling PAN (%d)\n", ret); - iwlagn_remove_notification(priv, &disable_wait); + iwl_remove_notification(priv->shrd, &disable_wait); } else { - ret = iwlagn_wait_notification(priv, &disable_wait, HZ); + ret = iwl_wait_notification(priv->shrd, &disable_wait, HZ); if (ret) IWL_ERR(priv, "Timed out waiting for PAN disable\n"); } @@ -529,6 +529,24 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) return 0; } +void iwlagn_config_ht40(struct ieee80211_conf *conf, + struct iwl_rxon_context *ctx) +{ + if (conf_is_ht40_minus(conf)) { + ctx->ht.extension_chan_offset = + IEEE80211_HT_PARAM_CHA_SEC_BELOW; + ctx->ht.is_40mhz = true; + } else if (conf_is_ht40_plus(conf)) { + ctx->ht.extension_chan_offset = + IEEE80211_HT_PARAM_CHA_SEC_ABOVE; + ctx->ht.is_40mhz = true; + } else { + ctx->ht.extension_chan_offset = + IEEE80211_HT_PARAM_CHA_SEC_NONE; + ctx->ht.is_40mhz = false; + } +} + int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) { struct iwl_priv *priv = hw->priv; @@ -590,19 +608,11 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) ctx->ht.enabled = conf_is_ht(conf); if (ctx->ht.enabled) { - if (conf_is_ht40_minus(conf)) { - ctx->ht.extension_chan_offset = - IEEE80211_HT_PARAM_CHA_SEC_BELOW; - ctx->ht.is_40mhz = true; - } else if (conf_is_ht40_plus(conf)) { - ctx->ht.extension_chan_offset = - IEEE80211_HT_PARAM_CHA_SEC_ABOVE; - ctx->ht.is_40mhz = true; - } else { - ctx->ht.extension_chan_offset = - IEEE80211_HT_PARAM_CHA_SEC_NONE; - ctx->ht.is_40mhz = false; - } + /* if HT40 is used, it should not change + * after associated except channel switch */ + if (!ctx->ht.is_40mhz || + !iwl_is_associated_ctx(ctx)) + iwlagn_config_ht40(conf, ctx); } else ctx->ht.is_40mhz = false; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c index 901fd9485d75..63d948d21c04 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c @@ -135,8 +135,8 @@ static u16 iwlagn_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) u16 size = (u16)sizeof(struct iwl_addsta_cmd); struct iwl_addsta_cmd *addsta = (struct iwl_addsta_cmd *)data; memcpy(addsta, cmd, size); - /* resrved in 5000 */ - addsta->rate_n_flags = cpu_to_le16(0); + /* resrved in agn */ + addsta->legacy_reserved = cpu_to_le16(0); return size; } @@ -1250,9 +1250,6 @@ int iwl_set_dynamic_key(struct iwl_priv *priv, switch (keyconf->cipher) { case WLAN_CIPHER_SUITE_TKIP: - keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; - keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; - if (sta) addr = sta->addr; else /* station mode case only */ @@ -1265,8 +1262,6 @@ int iwl_set_dynamic_key(struct iwl_priv *priv, seq.tkip.iv32, p1k, CMD_SYNC); break; case WLAN_CIPHER_SUITE_CCMP: - keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; - /* fall through */ case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: ret = iwlagn_send_sta_key(priv, keyconf, sta_id, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index a1a95d5f3923..81754cddba73 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -91,7 +91,10 @@ static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv, tx_cmd->tid_tspec = qc[0] & 0xf; tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK; } else { - tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; + if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) + tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; + else + tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK; } iwlagn_tx_cmd_protection(priv, info, fc, &tx_flags); @@ -148,7 +151,7 @@ static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv, if (ieee80211_is_data(fc)) { tx_cmd->initial_rate_index = 0; tx_cmd->tx_flags |= TX_CMD_FLG_STA_RATE_MSK; -#ifdef CONFIG_IWLWIFI_DEVICE_SVTOOL +#ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE if (priv->tm_fixed_rate) { /* * rate overwrite by testmode @@ -161,7 +164,8 @@ static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv, } #endif return; - } + } else if (ieee80211_is_back_req(fc)) + tx_cmd->tx_flags |= TX_CMD_FLG_STA_RATE_MSK; /** * If the current TX rate stored in mac80211 has the MCS bit set, it's diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index e235e84de8b4..f5fe42dbb3b0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -366,7 +366,7 @@ static void iwl_continuous_event_trace(struct iwl_priv *priv) u32 num_wraps; /* # times uCode wrapped to top of log */ u32 next_entry; /* index of next entry to be written by uCode */ - base = priv->device_pointers.error_event_table; + base = priv->shrd->device_pointers.error_event_table; if (iwlagn_hw_valid_rtc_data_addr(base)) { capacity = iwl_read_targ_mem(bus(priv), base); num_wraps = iwl_read_targ_mem(bus(priv), @@ -1036,6 +1036,9 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) priv->inst_evtlog_size = priv->cfg->base_params->max_event_log_size; priv->inst_errlog_ptr = pieces.inst_errlog_ptr; +#ifndef CONFIG_IWLWIFI_P2P + ucode_capa.flags &= ~IWL_UCODE_TLV_FLAGS_PAN; +#endif priv->new_scan_threshold_behaviour = !!(ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWSCAN); @@ -1057,7 +1060,6 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) priv->sta_key_max_num = STA_KEY_MAX_NUM; priv->shrd->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM; } - /* * figure out the offset of chain noise reset and gain commands * base on the size of standard phy calibration commands table size @@ -1232,14 +1234,14 @@ int iwl_alive_start(struct iwl_priv *priv) priv->bt_valid = IWLAGN_BT_VALID_ENABLE_FLAGS; priv->cur_rssi_ctx = NULL; - iwlagn_send_prio_tbl(priv); + iwl_send_prio_tbl(trans(priv)); /* FIXME: w/a to force change uCode BT state machine */ - ret = iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN, + ret = iwl_send_bt_env(trans(priv), IWL_BT_COEX_ENV_OPEN, BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); if (ret) return ret; - ret = iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_CLOSE, + ret = iwl_send_bt_env(trans(priv), IWL_BT_COEX_ENV_CLOSE, BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); if (ret) return ret; @@ -1575,6 +1577,8 @@ static int iwl_init_drv(struct iwl_priv *priv) mutex_init(&priv->shrd->mutex); + INIT_LIST_HEAD(&trans(priv)->calib_results); + priv->ieee_channels = NULL; priv->ieee_rates = NULL; priv->band = IEEE80211_BAND_2GHZ; @@ -1631,7 +1635,6 @@ err: static void iwl_uninit_drv(struct iwl_priv *priv) { - iwl_calib_free_results(priv); iwl_free_geos(priv); iwl_free_channel_map(priv); if (priv->tx_cmd_pool) @@ -1680,6 +1683,41 @@ static int iwl_set_hw_params(struct iwl_priv *priv) +static void iwl_debug_config(struct iwl_priv *priv) +{ + dev_printk(KERN_INFO, bus(priv)->dev, "CONFIG_IWLWIFI_DEBUG " +#ifdef CONFIG_IWLWIFI_DEBUG + "enabled\n"); +#else + "disabled\n"); +#endif + dev_printk(KERN_INFO, bus(priv)->dev, "CONFIG_IWLWIFI_DEBUGFS " +#ifdef CONFIG_IWLWIFI_DEBUGFS + "enabled\n"); +#else + "disabled\n"); +#endif + dev_printk(KERN_INFO, bus(priv)->dev, "CONFIG_IWLWIFI_DEVICE_TRACING " +#ifdef CONFIG_IWLWIFI_DEVICE_TRACING + "enabled\n"); +#else + "disabled\n"); +#endif + + dev_printk(KERN_INFO, bus(priv)->dev, "CONFIG_IWLWIFI_DEVICE_TESTMODE " +#ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE + "enabled\n"); +#else + "disabled\n"); +#endif + dev_printk(KERN_INFO, bus(priv)->dev, "CONFIG_IWLWIFI_P2P " +#ifdef CONFIG_IWLWIFI_P2P + "enabled\n"); +#else + "disabled\n"); +#endif +} + int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops, struct iwl_cfg *cfg) { @@ -1715,6 +1753,9 @@ int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops, SET_IEEE80211_DEV(hw, bus(priv)->dev); + /* what debugging capabilities we have */ + iwl_debug_config(priv); + IWL_DEBUG_INFO(priv, "*** LOAD DRIVER ***\n"); priv->cfg = cfg; @@ -1780,11 +1821,11 @@ int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops, goto out_free_eeprom; /* extract MAC Address */ - iwl_eeprom_get_mac(priv, priv->addresses[0].addr); + iwl_eeprom_get_mac(priv->shrd, priv->addresses[0].addr); IWL_DEBUG_INFO(priv, "MAC address: %pM\n", priv->addresses[0].addr); priv->hw->wiphy->addresses = priv->addresses; priv->hw->wiphy->n_addresses = 1; - num_mac = iwl_eeprom_query16(priv, EEPROM_NUM_MAC_ADDRESS); + num_mac = iwl_eeprom_query16(priv->shrd, EEPROM_NUM_MAC_ADDRESS); if (num_mac > 1) { memcpy(priv->addresses[1].addr, priv->addresses[0].addr, ETH_ALEN); @@ -1849,7 +1890,7 @@ out_destroy_workqueue: priv->shrd->workqueue = NULL; iwl_uninit_drv(priv); out_free_eeprom: - iwl_eeprom_free(priv); + iwl_eeprom_free(priv->shrd); out_free_trans: iwl_trans_free(trans(priv)); out_free_traffic_mem: @@ -1888,7 +1929,7 @@ void __devexit iwl_remove(struct iwl_priv * priv) iwl_dealloc_ucode(trans(priv)); - iwl_eeprom_free(priv); + iwl_eeprom_free(priv->shrd); /*netif_stop_queue(dev); */ flush_workqueue(priv->shrd->workqueue); @@ -1988,9 +2029,10 @@ MODULE_PARM_DESC(plcp_check, "Check plcp health (default: 1 [enabled])"); module_param_named(ack_check, iwlagn_mod_params.ack_check, bool, S_IRUGO); MODULE_PARM_DESC(ack_check, "Check ack health (default: 0 [disabled])"); -module_param_named(wd_disable, iwlagn_mod_params.wd_disable, bool, S_IRUGO); +module_param_named(wd_disable, iwlagn_mod_params.wd_disable, int, S_IRUGO); MODULE_PARM_DESC(wd_disable, - "Disable stuck queue watchdog timer (default: 0 [enabled])"); + "Disable stuck queue watchdog timer 0=system default, " + "1=disable, 2=enable (default: 0)"); /* * set bt_coex_active to true, uCode will do kill/defer diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index 5d8d2f445923..eb453ea41c41 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -101,13 +101,15 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, u32 changes); +void iwlagn_config_ht40(struct ieee80211_conf *conf, + struct iwl_rxon_context *ctx); /* uCode */ int iwlagn_rx_calib_result(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb, struct iwl_device_cmd *cmd); -int iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type); -void iwlagn_send_prio_tbl(struct iwl_priv *priv); +int iwl_send_bt_env(struct iwl_trans *trans, u8 action, u8 type); +void iwl_send_prio_tbl(struct iwl_trans *trans); int iwlagn_run_init_ucode(struct iwl_priv *priv); int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv, enum iwl_ucode_type ucode_type); @@ -115,7 +117,7 @@ int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv, /* lib */ int iwlagn_send_tx_power(struct iwl_priv *priv); void iwlagn_temperature(struct iwl_priv *priv); -u16 iwlagn_eeprom_calib_version(struct iwl_priv *priv); +u16 iwl_eeprom_calib_version(struct iwl_shared *shrd); int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control); void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control); int iwlagn_send_beacon_cmd(struct iwl_priv *priv); @@ -352,28 +354,12 @@ static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags) /* eeprom */ void iwl_eeprom_enhanced_txpower(struct iwl_priv *priv); -void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac); - -/* notification wait support */ -void __acquires(wait_entry) -iwlagn_init_notification_wait(struct iwl_priv *priv, - struct iwl_notification_wait *wait_entry, - u8 cmd, - void (*fn)(struct iwl_priv *priv, - struct iwl_rx_packet *pkt, - void *data), - void *fn_data); -int __must_check __releases(wait_entry) -iwlagn_wait_notification(struct iwl_priv *priv, - struct iwl_notification_wait *wait_entry, - unsigned long timeout); -void __releases(wait_entry) -iwlagn_remove_notification(struct iwl_priv *priv, - struct iwl_notification_wait *wait_entry); +void iwl_eeprom_get_mac(const struct iwl_shared *shrd, u8 *mac); + extern int iwlagn_init_alive_start(struct iwl_priv *priv); extern int iwl_alive_start(struct iwl_priv *priv); /* svtool */ -#ifdef CONFIG_IWLWIFI_DEVICE_SVTOOL +#ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE extern int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, int len); extern int iwlagn_mac_testmode_dump(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index f4eccf583775..265de39d394c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -109,10 +109,10 @@ enum { /* RX, TX, LEDs */ REPLY_TX = 0x1c, REPLY_LEDS_CMD = 0x48, - REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* for 4965 and up */ + REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* WiMAX coexistence */ - COEX_PRIORITY_TABLE_CMD = 0x5a, /* for 5000 series and up */ + COEX_PRIORITY_TABLE_CMD = 0x5a, COEX_MEDIUM_NOTIFICATION = 0x5b, COEX_EVENT_CMD = 0x5c, @@ -466,23 +466,27 @@ struct iwl_error_event_table { u32 frame_ptr; /* frame pointer */ u32 stack_ptr; /* stack pointer */ u32 hcmd; /* last host command header */ -#if 0 - /* no need to read the remainder, we don't use the values */ - u32 isr0; /* isr status register LMPM_NIC_ISR0: rxtx_flag */ - u32 isr1; /* isr status register LMPM_NIC_ISR1: host_flag */ - u32 isr2; /* isr status register LMPM_NIC_ISR2: enc_flag */ - u32 isr3; /* isr status register LMPM_NIC_ISR3: time_flag */ - u32 isr4; /* isr status register LMPM_NIC_ISR4: wico interrupt */ + u32 isr0; /* isr status register LMPM_NIC_ISR0: + * rxtx_flag */ + u32 isr1; /* isr status register LMPM_NIC_ISR1: + * host_flag */ + u32 isr2; /* isr status register LMPM_NIC_ISR2: + * enc_flag */ + u32 isr3; /* isr status register LMPM_NIC_ISR3: + * time_flag */ + u32 isr4; /* isr status register LMPM_NIC_ISR4: + * wico interrupt */ u32 isr_pref; /* isr status register LMPM_NIC_PREF_STAT */ u32 wait_event; /* wait event() caller address */ u32 l2p_control; /* L2pControlField */ u32 l2p_duration; /* L2pDurationField */ u32 l2p_mhvalid; /* L2pMhValidBits */ u32 l2p_addr_match; /* L2pAddrMatchStat */ - u32 lmpm_pmg_sel; /* indicate which clocks are turned on (LMPM_PMG_SEL) */ - u32 u_timestamp; /* indicate when the date and time of the compilation */ + u32 lmpm_pmg_sel; /* indicate which clocks are turned on + * (LMPM_PMG_SEL) */ + u32 u_timestamp; /* indicate when the date and time of the + * compilation */ u32 flow_handler; /* FH read/write pointers, RX credit */ -#endif } __packed; struct iwl_alive_resp { @@ -810,7 +814,7 @@ struct iwl_qosparam_cmd { #define IWLAGN_STATION_COUNT 16 #define IWL_INVALID_STATION 255 -#define IWL_MAX_TID_COUNT 9 +#define IWL_MAX_TID_COUNT 8 #define STA_FLG_TX_RATE_MSK cpu_to_le32(1 << 2) #define STA_FLG_PWR_SAVE_MSK cpu_to_le32(1 << 8) @@ -931,8 +935,7 @@ struct iwl_addsta_cmd { * corresponding to bit (e.g. bit 5 controls TID 5). * Set modify_mask bit STA_MODIFY_TID_DISABLE_TX to use this field. */ __le16 tid_disable_tx; - - __le16 rate_n_flags; /* 3945 only */ + __le16 legacy_reserved; /* TID for which to add block-ack support. * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ @@ -1162,8 +1165,7 @@ struct iwl_rx_mpdu_res_start { * * uCode handles retrying Tx when an ACK is expected but not received. * This includes trying lower data rates than the one requested in the Tx - * command, as set up by the REPLY_RATE_SCALE (for 3945) or - * REPLY_TX_LINK_QUALITY_CMD (agn). + * command, as set up by the REPLY_TX_LINK_QUALITY_CMD (agn). * * Driver sets up transmit power for various rates via REPLY_TX_PWR_TABLE_CMD. * This command must be executed after every RXON command, before Tx can occur. @@ -1175,25 +1177,9 @@ struct iwl_rx_mpdu_res_start { * 1: Use RTS/CTS protocol or CTS-to-self if spec allows it * before this frame. if CTS-to-self required check * RXON_FLG_SELF_CTS_EN status. - * unused in 3945/4965, used in 5000 series and after */ #define TX_CMD_FLG_PROT_REQUIRE_MSK cpu_to_le32(1 << 0) -/* - * 1: Use Request-To-Send protocol before this frame. - * Mutually exclusive vs. TX_CMD_FLG_CTS_MSK. - * used in 3945/4965, unused in 5000 series and after - */ -#define TX_CMD_FLG_RTS_MSK cpu_to_le32(1 << 1) - -/* - * 1: Transmit Clear-To-Send to self before this frame. - * Driver should set this for AUTH/DEAUTH/ASSOC-REQ/REASSOC mgmnt frames. - * Mutually exclusive vs. TX_CMD_FLG_RTS_MSK. - * used in 3945/4965, unused in 5000 series and after - */ -#define TX_CMD_FLG_CTS_MSK cpu_to_le32(1 << 2) - /* 1: Expect ACK from receiving station * 0: Don't expect ACK (MAC header's duration field s/b 0) * Set this for unicast frames, but not broadcast/multicast. */ @@ -1211,18 +1197,8 @@ struct iwl_rx_mpdu_res_start { * Set when Txing a block-ack request frame. Also set TX_CMD_FLG_ACK_MSK. */ #define TX_CMD_FLG_IMM_BA_RSP_MASK cpu_to_le32(1 << 6) -/* - * 1: Frame requires full Tx-Op protection. - * Set this if either RTS or CTS Tx Flag gets set. - * used in 3945/4965, unused in 5000 series and after - */ -#define TX_CMD_FLG_FULL_TXOP_PROT_MSK cpu_to_le32(1 << 7) - -/* Tx antenna selection field; used only for 3945, reserved (0) for agn devices. - * Set field to "0" to allow 3945 uCode to select antenna (normal usage). */ +/* Tx antenna selection field; reserved (0) for agn devices. */ #define TX_CMD_FLG_ANT_SEL_MSK cpu_to_le32(0xf00) -#define TX_CMD_FLG_ANT_A_MSK cpu_to_le32(1 << 8) -#define TX_CMD_FLG_ANT_B_MSK cpu_to_le32(1 << 9) /* 1: Ignore Bluetooth priority for this frame. * 0: Delay Tx until Bluetooth device is done (normal usage). */ @@ -1568,7 +1544,6 @@ struct iwl_compressed_ba_resp { __le64 bitmap; __le16 scd_flow; __le16 scd_ssn; - /* following only for 5000 series and up */ u8 txed; /* number of frames sent */ u8 txed_2_done; /* number of frames acked */ } __packed; @@ -1670,7 +1645,7 @@ struct iwl_link_qual_agg_params { /* * REPLY_TX_LINK_QUALITY_CMD = 0x4e (command, has simple generic response) * - * For agn devices only; 3945 uses REPLY_RATE_SCALE. + * For agn devices * * Each station in the agn device's internal station table has its own table * of 16 @@ -1919,7 +1894,7 @@ struct iwl_link_quality_cmd { /* * REPLY_BT_CONFIG = 0x9b (command, has simple generic response) * - * 3945 and agn devices support hardware handshake with Bluetooth device on + * agn devices support hardware handshake with Bluetooth device on * same platform. Bluetooth device alerts wireless device when it will Tx; * wireless device can delay or kill its own Tx to accommodate. */ @@ -2203,8 +2178,8 @@ struct iwl_spectrum_notification { struct iwl_powertable_cmd { __le16 flags; - u8 keep_alive_seconds; /* 3945 reserved */ - u8 debug_flags; /* 3945 reserved */ + u8 keep_alive_seconds; + u8 debug_flags; __le32 rx_data_timeout; __le32 tx_data_timeout; __le32 sleep_interval[IWL_POWER_VEC_SIZE]; @@ -2325,9 +2300,9 @@ struct iwl_scan_channel { /** * struct iwl_ssid_ie - directed scan network information element * - * Up to 20 of these may appear in REPLY_SCAN_CMD (Note: Only 4 are in - * 3945 SCAN api), selected by "type" bit field in struct iwl_scan_channel; - * each channel may select different ssids from among the 20 (4) entries. + * Up to 20 of these may appear in REPLY_SCAN_CMD, + * selected by "type" bit field in struct iwl_scan_channel; + * each channel may select different ssids from among the 20 entries. * SSID IEs get transmitted in reverse order of entry. */ struct iwl_ssid_ie { @@ -2336,7 +2311,6 @@ struct iwl_ssid_ie { u8 ssid[32]; } __packed; -#define PROBE_OPTION_MAX_3945 4 #define PROBE_OPTION_MAX 20 #define TX_CMD_LIFE_TIME_INFINITE cpu_to_le32(0xFFFFFFFF) #define IWL_GOOD_CRC_TH_DISABLED 0 @@ -2417,8 +2391,6 @@ struct iwl_scan_cmd { * channel */ __le32 suspend_time; /* pause scan this long (in "extended beacon * format") when returning to service chnl: - * 3945; 31:24 # beacons, 19:0 additional usec, - * 4965; 31:22 # beacons, 21:0 additional usec. */ __le32 flags; /* RXON_FLG_* */ __le32 filter_flags; /* RXON_FILTER_* */ @@ -2734,7 +2706,7 @@ struct statistics_div { struct statistics_general_common { __le32 temperature; /* radio temperature */ - __le32 temperature_m; /* for 5000 and up, this is radio voltage */ + __le32 temperature_m; /* radio voltage */ struct statistics_dbg dbg; __le32 sleep_time; __le32 slots_out; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index f9e9170e977a..3b6f48bfe0e3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -836,19 +836,6 @@ void iwl_print_rx_config_cmd(struct iwl_priv *priv, } #endif -static void iwlagn_abort_notification_waits(struct iwl_priv *priv) -{ - unsigned long flags; - struct iwl_notification_wait *wait_entry; - - spin_lock_irqsave(&priv->notif_wait_lock, flags); - list_for_each_entry(wait_entry, &priv->notif_waits, list) - wait_entry->aborted = true; - spin_unlock_irqrestore(&priv->notif_wait_lock, flags); - - wake_up_all(&priv->notif_waitq); -} - void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand) { unsigned int reload_msec; @@ -860,7 +847,7 @@ void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand) /* Cancel currently queued command. */ clear_bit(STATUS_HCMD_ACTIVE, &priv->shrd->status); - iwlagn_abort_notification_waits(priv); + iwl_abort_notification_waits(priv->shrd); /* Keep the restart process from trying to send host * commands by clearing the ready bit */ @@ -1505,11 +1492,23 @@ void iwl_setup_watchdog(struct iwl_priv *priv) { unsigned int timeout = priv->cfg->base_params->wd_timeout; - if (timeout && !iwlagn_mod_params.wd_disable) - mod_timer(&priv->watchdog, - jiffies + msecs_to_jiffies(IWL_WD_TICK(timeout))); - else - del_timer(&priv->watchdog); + if (!iwlagn_mod_params.wd_disable) { + /* use system default */ + if (timeout && !priv->cfg->base_params->wd_disable) + mod_timer(&priv->watchdog, + jiffies + + msecs_to_jiffies(IWL_WD_TICK(timeout))); + else + del_timer(&priv->watchdog); + } else { + /* module parameter overwrite default configuration */ + if (timeout && iwlagn_mod_params.wd_disable == 2) + mod_timer(&priv->watchdog, + jiffies + + msecs_to_jiffies(IWL_WD_TICK(timeout))); + else + del_timer(&priv->watchdog); + } } /** diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index fa47f75185df..6da53a36c1be 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -113,6 +113,7 @@ struct iwl_lib_ops { * @shadow_reg_enable: HW shadhow register bit * @no_idle_support: do not support idle mode * @hd_v2: v2 of enhanced sensitivity value, used for 2000 series and up + * wd_disable: disable watchdog timer */ struct iwl_base_params { int eeprom_size; @@ -134,6 +135,7 @@ struct iwl_base_params { const bool shadow_reg_enable; const bool no_idle_support; const bool hd_v2; + const bool wd_disable; }; /* * @advanced_bt_coexist: support advanced bt coexist @@ -184,8 +186,9 @@ struct iwl_ht_params { * @ht_params: point to ht patameters * @bt_params: pointer to bt parameters * @pa_type: used by 6000 series only to identify the type of Power Amplifier - * @need_dc_calib: need to perform init dc calibration * @need_temp_offset_calib: need to perform temperature offset calibration + * @no_xtal_calib: some devices do not need crystal calibration data, + * don't send it to those * @scan_antennas: available antenna for scan operation * @led_mode: 0=blinking, 1=On(RF On)/Off(RF Off) * @adv_pm: advance power management @@ -222,8 +225,8 @@ struct iwl_cfg { struct iwl_ht_params *ht_params; struct iwl_bt_params *bt_params; enum iwl_pa_type pa_type; /* if used set to IWL_PA_SYSTEM */ - const bool need_dc_calib; /* if used set to true */ const bool need_temp_offset_calib; /* if used set to true */ + const bool no_xtal_calib; u8 scan_rx_antennas[IEEE80211_NUM_BANDS]; enum iwl_led_mode led_mode; const bool adv_pm; diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 44a7bdd7ccfd..f8fc2393dd4c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -134,48 +134,43 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv) */ /* 0x0000000F - 0x00000001 */ -#define IWL_DL_INFO (1 << 0) -#define IWL_DL_MAC80211 (1 << 1) -#define IWL_DL_HCMD (1 << 2) -#define IWL_DL_STATE (1 << 3) +#define IWL_DL_INFO 0x00000001 +#define IWL_DL_MAC80211 0x00000002 +#define IWL_DL_HCMD 0x00000004 +#define IWL_DL_STATE 0x00000008 /* 0x000000F0 - 0x00000010 */ -#define IWL_DL_MACDUMP (1 << 4) -#define IWL_DL_HCMD_DUMP (1 << 5) -#define IWL_DL_EEPROM (1 << 6) -#define IWL_DL_RADIO (1 << 7) +#define IWL_DL_EEPROM 0x00000040 +#define IWL_DL_RADIO 0x00000080 /* 0x00000F00 - 0x00000100 */ -#define IWL_DL_POWER (1 << 8) -#define IWL_DL_TEMP (1 << 9) -/* reserved (1 << 10) */ -#define IWL_DL_SCAN (1 << 11) +#define IWL_DL_POWER 0x00000100 +#define IWL_DL_TEMP 0x00000200 +#define IWL_DL_SCAN 0x00000800 /* 0x0000F000 - 0x00001000 */ -#define IWL_DL_ASSOC (1 << 12) -#define IWL_DL_DROP (1 << 13) -/* reserved (1 << 14) */ -#define IWL_DL_COEX (1 << 15) +#define IWL_DL_ASSOC 0x00001000 +#define IWL_DL_DROP 0x00002000 +#define IWL_DL_COEX 0x00008000 /* 0x000F0000 - 0x00010000 */ -#define IWL_DL_FW (1 << 16) -#define IWL_DL_RF_KILL (1 << 17) -#define IWL_DL_FW_ERRORS (1 << 18) -#define IWL_DL_LED (1 << 19) +#define IWL_DL_FW 0x00010000 +#define IWL_DL_RF_KILL 0x00020000 +#define IWL_DL_FW_ERRORS 0x00040000 +#define IWL_DL_LED 0x00080000 /* 0x00F00000 - 0x00100000 */ -#define IWL_DL_RATE (1 << 20) -#define IWL_DL_CALIB (1 << 21) -#define IWL_DL_WEP (1 << 22) -#define IWL_DL_TX (1 << 23) +#define IWL_DL_RATE 0x00100000 +#define IWL_DL_CALIB 0x00200000 +#define IWL_DL_WEP 0x00400000 +#define IWL_DL_TX 0x00800000 /* 0x0F000000 - 0x01000000 */ -#define IWL_DL_RX (1 << 24) -#define IWL_DL_ISR (1 << 25) -#define IWL_DL_HT (1 << 26) +#define IWL_DL_RX 0x01000000 +#define IWL_DL_ISR 0x02000000 +#define IWL_DL_HT 0x04000000 /* 0xF0000000 - 0x10000000 */ -#define IWL_DL_11H (1 << 28) -#define IWL_DL_STATS (1 << 29) -#define IWL_DL_TX_REPLY (1 << 30) -#define IWL_DL_TX_QUEUES (1 << 31) +#define IWL_DL_11H 0x10000000 +#define IWL_DL_STATS 0x20000000 +#define IWL_DL_TX_REPLY 0x40000000 +#define IWL_DL_TX_QUEUES 0x80000000 #define IWL_DEBUG_INFO(p, f, a...) IWL_DEBUG(p, IWL_DL_INFO, f, ## a) #define IWL_DEBUG_MAC80211(p, f, a...) IWL_DEBUG(p, IWL_DL_MAC80211, f, ## a) -#define IWL_DEBUG_MACDUMP(p, f, a...) IWL_DEBUG(p, IWL_DL_MACDUMP, f, ## a) #define IWL_DEBUG_TEMP(p, f, a...) IWL_DEBUG(p, IWL_DL_TEMP, f, ## a) #define IWL_DEBUG_SCAN(p, f, a...) IWL_DEBUG(p, IWL_DL_SCAN, f, ## a) #define IWL_DEBUG_RX(p, f, a...) IWL_DEBUG(p, IWL_DL_RX, f, ## a) @@ -184,7 +179,6 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv) #define IWL_DEBUG_LED(p, f, a...) IWL_DEBUG(p, IWL_DL_LED, f, ## a) #define IWL_DEBUG_WEP(p, f, a...) IWL_DEBUG(p, IWL_DL_WEP, f, ## a) #define IWL_DEBUG_HC(p, f, a...) IWL_DEBUG(p, IWL_DL_HCMD, f, ## a) -#define IWL_DEBUG_HC_DUMP(p, f, a...) IWL_DEBUG(p, IWL_DL_HCMD_DUMP, f, ## a) #define IWL_DEBUG_EEPROM(p, f, a...) IWL_DEBUG(p, IWL_DL_EEPROM, f, ## a) #define IWL_DEBUG_CALIB(p, f, a...) IWL_DEBUG(p, IWL_DL_CALIB, f, ## a) #define IWL_DEBUG_FW(p, f, a...) IWL_DEBUG(p, IWL_DL_FW, f, ## a) @@ -206,8 +200,6 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv) #define IWL_DEBUG_STATS_LIMIT(p, f, a...) \ IWL_DEBUG_LIMIT(p, IWL_DL_STATS, f, ## a) #define IWL_DEBUG_TX_REPLY(p, f, a...) IWL_DEBUG(p, IWL_DL_TX_REPLY, f, ## a) -#define IWL_DEBUG_TX_REPLY_LIMIT(p, f, a...) \ - IWL_DEBUG_LIMIT(p, IWL_DL_TX_REPLY, f, ## a) #define IWL_DEBUG_TX_QUEUES(p, f, a...) IWL_DEBUG(p, IWL_DL_TX_QUEUES, f, ## a) #define IWL_DEBUG_RADIO(p, f, a...) IWL_DEBUG(p, IWL_DL_RADIO, f, ## a) #define IWL_DEBUG_POWER(p, f, a...) IWL_DEBUG(p, IWL_DL_POWER, f, ## a) diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 68b04f5b10ce..6bf6845e1a51 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -234,11 +234,12 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, /* default is to dump the entire data segment */ if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) { + struct iwl_trans *trans = trans(priv); priv->dbgfs_sram_offset = 0x800000; - if (priv->ucode_type == IWL_UCODE_INIT) - priv->dbgfs_sram_len = trans(priv)->ucode_init.data.len; + if (trans->shrd->ucode_type == IWL_UCODE_INIT) + priv->dbgfs_sram_len = trans->ucode_init.data.len; else - priv->dbgfs_sram_len = trans(priv)->ucode_rt.data.len; + priv->dbgfs_sram_len = trans->ucode_rt.data.len; } len = priv->dbgfs_sram_len; @@ -415,7 +416,7 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file, return -ENODATA; } - ptr = priv->eeprom; + ptr = priv->shrd->eeprom; if (!ptr) { IWL_ERR(priv, "Invalid EEPROM/OTP memory\n"); return -ENOMEM; @@ -427,7 +428,7 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file, IWL_ERR(priv, "Can not allocate Buffer\n"); return -ENOMEM; } - eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); + eeprom_ver = iwl_eeprom_query16(priv->shrd, EEPROM_VERSION); pos += scnprintf(buf + pos, buf_size - pos, "NVM Type: %s, " "version: 0x%x\n", (trans(priv)->nvm_device_type == NVM_DEVICE_TYPE_OTP) diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 556e4a2c19bc..69ecf6e2e658 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -60,11 +60,10 @@ struct iwl_tx_queue; /* Default noise level to report when noise measurement is not available. * This may be because we're: - * 1) Not associated (4965, no beacon statistics being sent to driver) + * 1) Not associated no beacon statistics being sent to driver) * 2) Scanning (noise measurement does not apply to associated channel) - * 3) Receiving CCK (3945 delivers noise info only for OFDM frames) * Use default noise value of -127 ... this is below the range of measurable - * Rx dBm for either 3945 or 4965, so it can indicate "unmeasurable" to user. + * Rx dBm for all agn devices, so it can indicate "unmeasurable" to user. * Also, -127 works better than 0 when averaging frames with/without * noise info (e.g. averaging might be done in app); measured dBm values are * always negative ... using a negative value as the default keeps all @@ -441,29 +440,6 @@ enum iwlagn_chain_noise_state { IWL_CHAIN_NOISE_DONE, }; - -/* - * enum iwl_calib - * defines the order in which results of initial calibrations - * should be sent to the runtime uCode - */ -enum iwl_calib { - IWL_CALIB_XTAL, - IWL_CALIB_DC, - IWL_CALIB_LO, - IWL_CALIB_TX_IQ, - IWL_CALIB_TX_IQ_PERD, - IWL_CALIB_BASE_BAND, - IWL_CALIB_TEMP_OFFSET, - IWL_CALIB_MAX -}; - -/* Opaque calibration results */ -struct iwl_calib_result { - void *buf; - size_t buf_len; -}; - /* Sensitivity calib data */ struct iwl_sensitivity_data { u32 auto_corr_ofdm; @@ -703,35 +679,6 @@ struct iwl_force_reset { */ #define IWLAGN_EXT_BEACON_TIME_POS 22 -/** - * struct iwl_notification_wait - notification wait entry - * @list: list head for global list - * @fn: function called with the notification - * @cmd: command ID - * - * This structure is not used directly, to wait for a - * notification declare it on the stack, and call - * iwlagn_init_notification_wait() with appropriate - * parameters. Then do whatever will cause the ucode - * to notify the driver, and to wait for that then - * call iwlagn_wait_notification(). - * - * Each notification is one-shot. If at some point we - * need to support multi-shot notifications (which - * can't be allocated on the stack) we need to modify - * the code for them. - */ -struct iwl_notification_wait { - struct list_head list; - - void (*fn)(struct iwl_priv *priv, struct iwl_rx_packet *pkt, - void *data); - void *fn_data; - - u8 cmd; - bool triggered, aborted; -}; - struct iwl_rxon_context { struct ieee80211_vif *vif; @@ -794,7 +741,7 @@ enum iwl_scan_type { IWL_SCAN_ROC, }; -#ifdef CONFIG_IWLWIFI_DEVICE_SVTOOL +#ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE struct iwl_testmode_trace { u32 buff_size; u32 total_size; @@ -804,6 +751,12 @@ struct iwl_testmode_trace { dma_addr_t dma_addr; bool trace_enabled; }; +struct iwl_testmode_sram { + u32 buff_size; + u32 num_chunks; + u8 *buff_addr; + bool sram_readed; +}; #endif struct iwl_wipan_noa_data { @@ -868,9 +821,6 @@ struct iwl_priv { s32 temperature; /* Celsius */ s32 last_temperature; - /* init calibration results */ - struct iwl_calib_result calib_results[IWL_CALIB_MAX]; - struct iwl_wipan_noa_data __rcu *noa_data; /* Scan related variables */ @@ -897,18 +847,12 @@ struct iwl_priv { u32 ucode_ver; /* version of ucode, copy of iwl_ucode.ver */ - enum iwl_ucode_type ucode_type; char firmware_name[25]; struct iwl_rxon_context contexts[NUM_IWL_RXON_CTX]; __le16 switch_channel; - struct { - u32 error_event_table; - u32 log_event_table; - } device_pointers; - u16 active_rate; u8 start_calib; @@ -942,10 +886,6 @@ struct iwl_priv { /* Indication if ieee80211_ops->open has been called */ u8 is_open; - /* eeprom -- this is in the card's little endian byte order */ - u8 *eeprom; - struct iwl_eeprom_calib_info *calib_info; - enum nl80211_iftype iw_mode; /* Last Rx'd beacon timestamp */ @@ -1001,10 +941,6 @@ struct iwl_priv { /* counts reply_tx error */ struct reply_tx_error_statistics reply_tx_stats; struct reply_agg_tx_error_statistics reply_agg_tx_stats; - /* notification wait support */ - struct list_head notif_waits; - spinlock_t notif_wait_lock; - wait_queue_head_t notif_waitq; /* remain-on-channel offload support */ struct ieee80211_channel *hw_roc_channel; @@ -1082,8 +1018,9 @@ struct iwl_priv { struct led_classdev led; unsigned long blink_on, blink_off; bool led_registered; -#ifdef CONFIG_IWLWIFI_DEVICE_SVTOOL +#ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE struct iwl_testmode_trace testmode_trace; + struct iwl_testmode_sram testmode_sram; u32 tm_fixed_rate; #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index dcada0827ea4..6fcc7d586b24 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -215,11 +215,11 @@ static int iwl_eeprom_verify_signature(struct iwl_trans *trans) return ret; } -u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset) +u16 iwl_eeprom_query16(const struct iwl_shared *shrd, size_t offset) { - if (!priv->eeprom) + if (!shrd->eeprom) return 0; - return (u16)priv->eeprom[offset] | ((u16)priv->eeprom[offset + 1] << 8); + return (u16)shrd->eeprom[offset] | ((u16)shrd->eeprom[offset + 1] << 8); } int iwl_eeprom_check_version(struct iwl_priv *priv) @@ -227,8 +227,8 @@ int iwl_eeprom_check_version(struct iwl_priv *priv) u16 eeprom_ver; u16 calib_ver; - eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); - calib_ver = iwlagn_eeprom_calib_version(priv); + eeprom_ver = iwl_eeprom_query16(priv->shrd, EEPROM_VERSION); + calib_ver = iwl_eeprom_calib_version(priv->shrd); if (eeprom_ver < priv->cfg->eeprom_ver || calib_ver < priv->cfg->eeprom_calib_ver) @@ -249,11 +249,12 @@ err: int iwl_eeprom_check_sku(struct iwl_priv *priv) { + struct iwl_shared *shrd = priv->shrd; u16 radio_cfg; if (!priv->cfg->sku) { /* not using sku overwrite */ - priv->cfg->sku = iwl_eeprom_query16(priv, EEPROM_SKU_CAP); + priv->cfg->sku = iwl_eeprom_query16(shrd, EEPROM_SKU_CAP); if (priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE && !priv->cfg->ht_params) { IWL_ERR(priv, "Invalid 11n configuration\n"); @@ -269,7 +270,7 @@ int iwl_eeprom_check_sku(struct iwl_priv *priv) if (!priv->cfg->valid_tx_ant && !priv->cfg->valid_rx_ant) { /* not using .cfg overwrite */ - radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG); + radio_cfg = iwl_eeprom_query16(shrd, EEPROM_RADIO_CONFIG); priv->cfg->valid_tx_ant = EEPROM_RF_CFG_TX_ANT_MSK(radio_cfg); priv->cfg->valid_rx_ant = EEPROM_RF_CFG_RX_ANT_MSK(radio_cfg); if (!priv->cfg->valid_tx_ant || !priv->cfg->valid_rx_ant) { @@ -289,9 +290,9 @@ int iwl_eeprom_check_sku(struct iwl_priv *priv) return 0; } -void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac) +void iwl_eeprom_get_mac(const struct iwl_shared *shrd, u8 *mac) { - const u8 *addr = iwl_eeprom_query_addr(priv, + const u8 *addr = iwl_eeprom_query_addr(shrd, EEPROM_MAC_ADDRESS); memcpy(mac, addr, ETH_ALEN); } @@ -582,6 +583,7 @@ iwl_eeprom_enh_txp_read_element(struct iwl_priv *priv, void iwl_eeprom_enhanced_txpower(struct iwl_priv *priv) { + struct iwl_shared *shrd = priv->shrd; struct iwl_eeprom_enhanced_txpwr *txp_array, *txp; int idx, entries; __le16 *txp_len; @@ -590,10 +592,10 @@ void iwl_eeprom_enhanced_txpower(struct iwl_priv *priv) BUILD_BUG_ON(sizeof(struct iwl_eeprom_enhanced_txpwr) != 8); /* the length is in 16-bit words, but we want entries */ - txp_len = (__le16 *) iwl_eeprom_query_addr(priv, EEPROM_TXP_SZ_OFFS); + txp_len = (__le16 *) iwl_eeprom_query_addr(shrd, EEPROM_TXP_SZ_OFFS); entries = le16_to_cpup(txp_len) * 2 / EEPROM_TXP_ENTRY_LEN; - txp_array = (void *) iwl_eeprom_query_addr(priv, EEPROM_TXP_OFFS); + txp_array = (void *) iwl_eeprom_query_addr(shrd, EEPROM_TXP_OFFS); for (idx = 0; idx < entries; idx++) { txp = &txp_array[idx]; @@ -646,12 +648,13 @@ void iwl_eeprom_enhanced_txpower(struct iwl_priv *priv) /** * iwl_eeprom_init - read EEPROM contents * - * Load the EEPROM contents from adapter into priv->eeprom + * Load the EEPROM contents from adapter into shrd->eeprom * * NOTE: This routine uses the non-debug IO access functions. */ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev) { + struct iwl_shared *shrd = priv->shrd; __le16 *e; u32 gp = iwl_read32(bus(priv), CSR_EEPROM_GP); int sz; @@ -666,12 +669,12 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev) /* allocate eeprom */ sz = priv->cfg->base_params->eeprom_size; IWL_DEBUG_EEPROM(priv, "NVM size = %d\n", sz); - priv->eeprom = kzalloc(sz, GFP_KERNEL); - if (!priv->eeprom) { + shrd->eeprom = kzalloc(sz, GFP_KERNEL); + if (!shrd->eeprom) { ret = -ENOMEM; goto alloc_err; } - e = (__le16 *)priv->eeprom; + e = (__le16 *)shrd->eeprom; iwl_apm_init(priv); @@ -746,7 +749,7 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev) IWL_DEBUG_EEPROM(priv, "NVM Type: %s, version: 0x%x\n", (trans(priv)->nvm_device_type == NVM_DEVICE_TYPE_OTP) ? "OTP" : "EEPROM", - iwl_eeprom_query16(priv, EEPROM_VERSION)); + iwl_eeprom_query16(shrd, EEPROM_VERSION)); ret = 0; done: @@ -754,17 +757,17 @@ done: err: if (ret) - iwl_eeprom_free(priv); + iwl_eeprom_free(priv->shrd); /* Reset chip to save power until we load uCode during "up". */ iwl_apm_stop(priv); alloc_err: return ret; } -void iwl_eeprom_free(struct iwl_priv *priv) +void iwl_eeprom_free(struct iwl_shared *shrd) { - kfree(priv->eeprom); - priv->eeprom = NULL; + kfree(shrd->eeprom); + shrd->eeprom = NULL; } static void iwl_init_band_reference(const struct iwl_priv *priv, @@ -772,49 +775,50 @@ static void iwl_init_band_reference(const struct iwl_priv *priv, const struct iwl_eeprom_channel **eeprom_ch_info, const u8 **eeprom_ch_index) { + struct iwl_shared *shrd = priv->shrd; u32 offset = priv->cfg->lib-> eeprom_ops.regulatory_bands[eep_band - 1]; switch (eep_band) { case 1: /* 2.4GHz band */ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_1); *eeprom_ch_info = (struct iwl_eeprom_channel *) - iwl_eeprom_query_addr(priv, offset); + iwl_eeprom_query_addr(shrd, offset); *eeprom_ch_index = iwl_eeprom_band_1; break; case 2: /* 4.9GHz band */ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_2); *eeprom_ch_info = (struct iwl_eeprom_channel *) - iwl_eeprom_query_addr(priv, offset); + iwl_eeprom_query_addr(shrd, offset); *eeprom_ch_index = iwl_eeprom_band_2; break; case 3: /* 5.2GHz band */ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_3); *eeprom_ch_info = (struct iwl_eeprom_channel *) - iwl_eeprom_query_addr(priv, offset); + iwl_eeprom_query_addr(shrd, offset); *eeprom_ch_index = iwl_eeprom_band_3; break; case 4: /* 5.5GHz band */ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_4); *eeprom_ch_info = (struct iwl_eeprom_channel *) - iwl_eeprom_query_addr(priv, offset); + iwl_eeprom_query_addr(shrd, offset); *eeprom_ch_index = iwl_eeprom_band_4; break; case 5: /* 5.7GHz band */ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_5); *eeprom_ch_info = (struct iwl_eeprom_channel *) - iwl_eeprom_query_addr(priv, offset); + iwl_eeprom_query_addr(shrd, offset); *eeprom_ch_index = iwl_eeprom_band_5; break; case 6: /* 2.4GHz ht40 channels */ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_6); *eeprom_ch_info = (struct iwl_eeprom_channel *) - iwl_eeprom_query_addr(priv, offset); + iwl_eeprom_query_addr(shrd, offset); *eeprom_ch_index = iwl_eeprom_band_6; break; case 7: /* 5 GHz ht40 channels */ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_7); *eeprom_ch_info = (struct iwl_eeprom_channel *) - iwl_eeprom_query_addr(priv, offset); + iwl_eeprom_query_addr(shrd, offset); *eeprom_ch_index = iwl_eeprom_band_7; break; default: @@ -1064,7 +1068,7 @@ void iwl_rf_config(struct iwl_priv *priv) { u16 radio_cfg; - radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG); + radio_cfg = iwl_eeprom_query16(priv->shrd, EEPROM_RADIO_CONFIG); /* write radio config values to register */ if (EEPROM_RF_CFG_TYPE_MSK(radio_cfg) <= EEPROM_RF_CONFIG_TYPE_MAX) { diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index c94747e7299e..9fa937ec35e3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -66,6 +66,7 @@ #include <net/mac80211.h> struct iwl_priv; +struct iwl_shared; /* * EEPROM access time values: @@ -305,11 +306,11 @@ struct iwl_eeprom_ops { int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev); -void iwl_eeprom_free(struct iwl_priv *priv); +void iwl_eeprom_free(struct iwl_shared *shrd); int iwl_eeprom_check_version(struct iwl_priv *priv); int iwl_eeprom_check_sku(struct iwl_priv *priv); -const u8 *iwl_eeprom_query_addr(const struct iwl_priv *priv, size_t offset); -u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset); +const u8 *iwl_eeprom_query_addr(const struct iwl_shared *shrd, size_t offset); +u16 iwl_eeprom_query16(const struct iwl_shared *shrd, size_t offset); int iwl_init_channel_map(struct iwl_priv *priv); void iwl_free_channel_map(struct iwl_priv *priv); const struct iwl_channel_info *iwl_get_channel_info( diff --git a/drivers/net/wireless/iwlwifi/iwl-mac80211.c b/drivers/net/wireless/iwlwifi/iwl-mac80211.c index 05b1f0d2f387..e3944f4e4fd6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-mac80211.c +++ b/drivers/net/wireless/iwlwifi/iwl-mac80211.c @@ -427,7 +427,7 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw) iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE); - base = priv->device_pointers.error_event_table; + base = priv->shrd->device_pointers.error_event_table; if (iwlagn_hw_valid_rtc_data_addr(base)) { spin_lock_irqsave(&bus(priv)->reg_lock, flags); ret = iwl_grab_nic_access_silent(bus(priv)); @@ -481,15 +481,11 @@ static void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct iwl_priv *priv = hw->priv; - IWL_DEBUG_MACDUMP(priv, "enter\n"); - IWL_DEBUG_TX(priv, "dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate); if (iwlagn_tx_skb(priv, skb)) dev_kfree_skb_any(skb); - - IWL_DEBUG_MACDUMP(priv, "leave\n"); } static void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw, @@ -521,6 +517,17 @@ static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return -EOPNOTSUPP; } + switch (key->cipher) { + case WLAN_CIPHER_SUITE_TKIP: + key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; + /* fall through */ + case WLAN_CIPHER_SUITE_CCMP: + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + break; + default: + break; + } + /* * We could program these keys into the hardware as well, but we * don't expect much multicast traffic in IBSS and having keys @@ -804,21 +811,9 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, /* Configure HT40 channels */ ctx->ht.enabled = conf_is_ht(conf); - if (ctx->ht.enabled) { - if (conf_is_ht40_minus(conf)) { - ctx->ht.extension_chan_offset = - IEEE80211_HT_PARAM_CHA_SEC_BELOW; - ctx->ht.is_40mhz = true; - } else if (conf_is_ht40_plus(conf)) { - ctx->ht.extension_chan_offset = - IEEE80211_HT_PARAM_CHA_SEC_ABOVE; - ctx->ht.is_40mhz = true; - } else { - ctx->ht.extension_chan_offset = - IEEE80211_HT_PARAM_CHA_SEC_NONE; - ctx->ht.is_40mhz = false; - } - } else + if (ctx->ht.enabled) + iwlagn_config_ht40(conf, ctx); + else ctx->ht.is_40mhz = false; if ((le16_to_cpu(ctx->staging.channel) != ch)) @@ -1053,6 +1048,9 @@ static int iwlagn_mac_tx_sync(struct ieee80211_hw *hw, int ret; u8 sta_id; + if (ctx->ctxid != IWL_RXON_CTX_PAN) + return 0; + IWL_DEBUG_MAC80211(priv, "enter\n"); mutex_lock(&priv->shrd->mutex); @@ -1102,6 +1100,9 @@ static void iwlagn_mac_finish_tx_sync(struct ieee80211_hw *hw, struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; struct iwl_rxon_context *ctx = vif_priv->ctx; + if (ctx->ctxid != IWL_RXON_CTX_PAN) + return; + IWL_DEBUG_MAC80211(priv, "enter\n"); mutex_lock(&priv->shrd->mutex); diff --git a/drivers/net/wireless/iwlwifi/iwl-shared.h b/drivers/net/wireless/iwlwifi/iwl-shared.h index 1f7a93c67c45..29a7284aa3ef 100644 --- a/drivers/net/wireless/iwlwifi/iwl-shared.h +++ b/drivers/net/wireless/iwlwifi/iwl-shared.h @@ -97,6 +97,7 @@ struct iwl_cfg; struct iwl_bus; struct iwl_priv; +struct iwl_trans; struct iwl_sensitivity_ranges; struct iwl_trans_ops; @@ -120,7 +121,7 @@ extern struct iwl_mod_params iwlagn_mod_params; * @restart_fw: restart firmware, default = 1 * @plcp_check: enable plcp health check, default = true * @ack_check: disable ack health check, default = false - * @wd_disable: enable stuck queue check, default = false + * @wd_disable: enable stuck queue check, default = 0 * @bt_coex_active: enable bt coex, default = true * @led_mode: system default, default = 0 * @no_sleep_autoadjust: disable autoadjust, default = true @@ -141,7 +142,7 @@ struct iwl_mod_params { int restart_fw; bool plcp_check; bool ack_check; - bool wd_disable; + int wd_disable; bool bt_coex_active; int led_mode; bool no_sleep_autoadjust; @@ -174,7 +175,6 @@ struct iwl_mod_params { * @ct_kill_exit_threshold: when to reeable the device - in hw dependent unit * relevant for 1000, 6000 and up * @wd_timeout: TX queues watchdog timeout - * @calib_init_cfg: setup initial calibrations for the hw * @calib_rt_cfg: setup runtime calibrations for the hw * @struct iwl_sensitivity_ranges: range of sensitivity values */ @@ -195,7 +195,6 @@ struct iwl_hw_params { u32 ct_kill_exit_threshold; unsigned int wd_timeout; - u32 calib_init_cfg; u32 calib_rt_cfg; const struct iwl_sensitivity_ranges *sens; }; @@ -259,6 +258,52 @@ struct iwl_tid_data { }; /** + * enum iwl_ucode_type + * + * The type of ucode currently loaded on the hardware. + * + * @IWL_UCODE_NONE: No ucode loaded + * @IWL_UCODE_REGULAR: Normal runtime ucode + * @IWL_UCODE_INIT: Initial ucode + * @IWL_UCODE_WOWLAN: Wake on Wireless enabled ucode + */ +enum iwl_ucode_type { + IWL_UCODE_NONE, + IWL_UCODE_REGULAR, + IWL_UCODE_INIT, + IWL_UCODE_WOWLAN, +}; + +/** + * struct iwl_notification_wait - notification wait entry + * @list: list head for global list + * @fn: function called with the notification + * @cmd: command ID + * + * This structure is not used directly, to wait for a + * notification declare it on the stack, and call + * iwlagn_init_notification_wait() with appropriate + * parameters. Then do whatever will cause the ucode + * to notify the driver, and to wait for that then + * call iwlagn_wait_notification(). + * + * Each notification is one-shot. If at some point we + * need to support multi-shot notifications (which + * can't be allocated on the stack) we need to modify + * the code for them. + */ +struct iwl_notification_wait { + struct list_head list; + + void (*fn)(struct iwl_trans *trans, struct iwl_rx_packet *pkt, + void *data); + void *fn_data; + + u8 cmd; + bool triggered, aborted; +}; + +/** * struct iwl_shared - shared fields for all the layers of the driver * * @dbg_level_dev: dbg level set per device. Prevails on @@ -275,6 +320,11 @@ struct iwl_tid_data { * @sta_lock: protects the station table. * If lock and sta_lock are needed, lock must be acquired first. * @mutex: + * @ucode_type: indicator of loaded ucode image + * @notif_waits: things waiting for notification + * @notif_wait_lock: lock protecting notification + * @notif_waitq: head of notification wait queue + * @device_pointers: pointers to ucode event tables */ struct iwl_shared { #ifdef CONFIG_IWLWIFI_DEBUG @@ -302,6 +352,23 @@ struct iwl_shared { struct iwl_tid_data tid_data[IWLAGN_STATION_COUNT][IWL_MAX_TID_COUNT]; wait_queue_head_t wait_command_queue; + + /* eeprom -- this is in the card's little endian byte order */ + u8 *eeprom; + + /* ucode related variables */ + enum iwl_ucode_type ucode_type; + + /* notification wait support */ + struct list_head notif_waits; + spinlock_t notif_wait_lock; + wait_queue_head_t notif_waitq; + + struct { + u32 error_event_table; + u32 log_event_table; + } device_pointers; + }; /*Whatever _m is (iwl_trans, iwl_priv, iwl_bus, these macros will work */ @@ -445,6 +512,24 @@ bool iwl_check_for_ct_kill(struct iwl_priv *priv); void iwl_stop_sw_queue(struct iwl_priv *priv, u8 ac); void iwl_wake_sw_queue(struct iwl_priv *priv, u8 ac); +/* notification wait support */ +void iwl_abort_notification_waits(struct iwl_shared *shrd); +void __acquires(wait_entry) +iwl_init_notification_wait(struct iwl_shared *shrd, + struct iwl_notification_wait *wait_entry, + u8 cmd, + void (*fn)(struct iwl_trans *trans, + struct iwl_rx_packet *pkt, + void *data), + void *fn_data); +int __must_check __releases(wait_entry) +iwl_wait_notification(struct iwl_shared *shrd, + struct iwl_notification_wait *wait_entry, + unsigned long timeout); +void __releases(wait_entry) +iwl_remove_notification(struct iwl_shared *shrd, + struct iwl_notification_wait *wait_entry); + #ifdef CONFIG_IWLWIFI_DEBUGFS void iwl_reset_traffic_log(struct iwl_priv *priv); #endif /* CONFIG_IWLWIFI_DEBUGFS */ diff --git a/drivers/net/wireless/iwlwifi/iwl-sv-open.c b/drivers/net/wireless/iwlwifi/iwl-testmode.c index e3882d0cfc85..a874eb7b5f8e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sv-open.c +++ b/drivers/net/wireless/iwlwifi/iwl-testmode.c @@ -77,6 +77,7 @@ #include "iwl-agn.h" #include "iwl-testmode.h" #include "iwl-trans.h" +#include "iwl-bus.h" /* The TLVs used in the gnl message policy between the kernel module and * user space application. iwl_testmode_gnl_msg_policy is to be carried @@ -106,6 +107,13 @@ struct nla_policy iwl_testmode_gnl_msg_policy[IWL_TM_ATTR_MAX] = { [IWL_TM_ATTR_FIXRATE] = { .type = NLA_U32, }, [IWL_TM_ATTR_UCODE_OWNER] = { .type = NLA_U8, }, + + [IWL_TM_ATTR_SRAM_ADDR] = { .type = NLA_U32, }, + [IWL_TM_ATTR_SRAM_SIZE] = { .type = NLA_U32, }, + [IWL_TM_ATTR_SRAM_DUMP] = { .type = NLA_UNSPEC, }, + + [IWL_TM_ATTR_FW_VERSION] = { .type = NLA_U32, }, + [IWL_TM_ATTR_DEVICE_ID] = { .type = NLA_U32, }, }; /* @@ -177,6 +185,18 @@ void iwl_testmode_init(struct iwl_priv *priv) { priv->pre_rx_handler = iwl_testmode_ucode_rx_pkt; priv->testmode_trace.trace_enabled = false; + priv->testmode_sram.sram_readed = false; +} + +static void iwl_sram_cleanup(struct iwl_priv *priv) +{ + if (priv->testmode_sram.sram_readed) { + kfree(priv->testmode_sram.buff_addr); + priv->testmode_sram.buff_addr = NULL; + priv->testmode_sram.buff_size = 0; + priv->testmode_sram.num_chunks = 0; + priv->testmode_sram.sram_readed = false; + } } static void iwl_trace_cleanup(struct iwl_priv *priv) @@ -201,6 +221,7 @@ static void iwl_trace_cleanup(struct iwl_priv *priv) void iwl_testmode_cleanup(struct iwl_priv *priv) { iwl_trace_cleanup(priv); + iwl_sram_cleanup(priv); } /* @@ -276,7 +297,7 @@ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb) IWL_INFO(priv, "testmode register access command offset 0x%x\n", ofs); switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) { - case IWL_TM_CMD_APP2DEV_REG_READ32: + case IWL_TM_CMD_APP2DEV_DIRECT_REG_READ32: val32 = iwl_read32(bus(priv), ofs); IWL_INFO(priv, "32bit value to read 0x%x\n", val32); @@ -291,7 +312,7 @@ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb) IWL_DEBUG_INFO(priv, "Error sending msg : %d\n", status); break; - case IWL_TM_CMD_APP2DEV_REG_WRITE32: + case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32: if (!tb[IWL_TM_ATTR_REG_VALUE32]) { IWL_DEBUG_INFO(priv, "Error finding value to write\n"); @@ -302,7 +323,7 @@ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb) iwl_write32(bus(priv), ofs, val32); } break; - case IWL_TM_CMD_APP2DEV_REG_WRITE8: + case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8: if (!tb[IWL_TM_ATTR_REG_VALUE8]) { IWL_DEBUG_INFO(priv, "Error finding value to write\n"); return -ENOMSG; @@ -312,6 +333,32 @@ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb) iwl_write8(bus(priv), ofs, val8); } break; + case IWL_TM_CMD_APP2DEV_INDIRECT_REG_READ32: + val32 = iwl_read_prph(bus(priv), ofs); + IWL_INFO(priv, "32bit value to read 0x%x\n", val32); + + skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20); + if (!skb) { + IWL_DEBUG_INFO(priv, "Error allocating memory\n"); + return -ENOMEM; + } + NLA_PUT_U32(skb, IWL_TM_ATTR_REG_VALUE32, val32); + status = cfg80211_testmode_reply(skb); + if (status < 0) + IWL_DEBUG_INFO(priv, + "Error sending msg : %d\n", status); + break; + case IWL_TM_CMD_APP2DEV_INDIRECT_REG_WRITE32: + if (!tb[IWL_TM_ATTR_REG_VALUE32]) { + IWL_DEBUG_INFO(priv, + "Error finding value to write\n"); + return -ENOMSG; + } else { + val32 = nla_get_u32(tb[IWL_TM_ATTR_REG_VALUE32]); + IWL_INFO(priv, "32bit value to write 0x%x\n", val32); + iwl_write_prph(bus(priv), ofs, val32); + } + break; default: IWL_DEBUG_INFO(priv, "Unknown testmode register command ID\n"); return -ENOSYS; @@ -330,7 +377,7 @@ static int iwl_testmode_cfg_init_calib(struct iwl_priv *priv) struct iwl_notification_wait calib_wait; int ret; - iwlagn_init_notification_wait(priv, &calib_wait, + iwl_init_notification_wait(priv->shrd, &calib_wait, CALIBRATION_COMPLETE_NOTIFICATION, NULL, NULL); ret = iwlagn_init_alive_start(priv); @@ -340,14 +387,14 @@ static int iwl_testmode_cfg_init_calib(struct iwl_priv *priv) goto cfg_init_calib_error; } - ret = iwlagn_wait_notification(priv, &calib_wait, 2 * HZ); + ret = iwl_wait_notification(priv->shrd, &calib_wait, 2 * HZ); if (ret) IWL_DEBUG_INFO(priv, "Error detecting" " CALIBRATION_COMPLETE_NOTIFICATION: %d\n", ret); return ret; cfg_init_calib_error: - iwlagn_remove_notification(priv, &calib_wait); + iwl_remove_notification(priv->shrd, &calib_wait); return ret; } @@ -373,6 +420,8 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) struct sk_buff *skb; unsigned char *rsp_data_ptr = NULL; int status = 0, rsp_data_len = 0; + char buf[32], *ptr = NULL; + unsigned int num, devid; switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) { case IWL_TM_CMD_APP2DEV_GET_DEVICENAME: @@ -420,8 +469,23 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) "Error starting the device: %d\n", status); break; + case IWL_TM_CMD_APP2DEV_LOAD_WOWLAN_FW: + iwl_scan_cancel_timeout(priv, 200); + iwl_trans_stop_device(trans(priv)); + status = iwlagn_load_ucode_wait_alive(priv, IWL_UCODE_WOWLAN); + if (status) { + IWL_DEBUG_INFO(priv, + "Error loading WOWLAN ucode: %d\n", status); + break; + } + status = iwl_alive_start(priv); + if (status) + IWL_DEBUG_INFO(priv, + "Error starting the device: %d\n", status); + break; + case IWL_TM_CMD_APP2DEV_GET_EEPROM: - if (priv->eeprom) { + if (priv->shrd->eeprom) { skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, priv->cfg->base_params->eeprom_size + 20); if (!skb) { @@ -433,7 +497,7 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) IWL_TM_CMD_DEV2APP_EEPROM_RSP); NLA_PUT(skb, IWL_TM_ATTR_EEPROM, priv->cfg->base_params->eeprom_size, - priv->eeprom); + priv->shrd->eeprom); status = cfg80211_testmode_reply(skb); if (status < 0) IWL_DEBUG_INFO(priv, @@ -452,6 +516,43 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) priv->tm_fixed_rate = nla_get_u32(tb[IWL_TM_ATTR_FIXRATE]); break; + case IWL_TM_CMD_APP2DEV_GET_FW_VERSION: + IWL_INFO(priv, "uCode version raw: 0x%x\n", priv->ucode_ver); + + skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20); + if (!skb) { + IWL_DEBUG_INFO(priv, "Error allocating memory\n"); + return -ENOMEM; + } + NLA_PUT_U32(skb, IWL_TM_ATTR_FW_VERSION, priv->ucode_ver); + status = cfg80211_testmode_reply(skb); + if (status < 0) + IWL_DEBUG_INFO(priv, + "Error sending msg : %d\n", status); + break; + + case IWL_TM_CMD_APP2DEV_GET_DEVICE_ID: + bus_get_hw_id(bus(priv), buf, sizeof(buf)); + ptr = buf; + strsep(&ptr, ":"); + sscanf(strsep(&ptr, ":"), "%x", &num); + sscanf(strsep(&ptr, ":"), "%x", &devid); + IWL_INFO(priv, "Device ID = 0x%04x, SubDevice ID= 0x%04x\n", + num, devid); + devid |= (num << 16); + + skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20); + if (!skb) { + IWL_DEBUG_INFO(priv, "Error allocating memory\n"); + return -ENOMEM; + } + NLA_PUT_U32(skb, IWL_TM_ATTR_DEVICE_ID, devid); + status = cfg80211_testmode_reply(skb); + if (status < 0) + IWL_DEBUG_INFO(priv, + "Error sending msg : %d\n", status); + break; + default: IWL_DEBUG_INFO(priv, "Unknown testmode driver command ID\n"); return -ENOSYS; @@ -532,7 +633,7 @@ static int iwl_testmode_trace(struct ieee80211_hw *hw, struct nlattr **tb) } priv->testmode_trace.num_chunks = DIV_ROUND_UP(priv->testmode_trace.buff_size, - TRACE_CHUNK_SIZE); + DUMP_CHUNK_SIZE); break; case IWL_TM_CMD_APP2DEV_END_TRACE: @@ -564,15 +665,15 @@ static int iwl_testmode_trace_dump(struct ieee80211_hw *hw, struct nlattr **tb, idx = cb->args[4]; if (idx >= priv->testmode_trace.num_chunks) return -ENOENT; - length = TRACE_CHUNK_SIZE; + length = DUMP_CHUNK_SIZE; if (((idx + 1) == priv->testmode_trace.num_chunks) && - (priv->testmode_trace.buff_size % TRACE_CHUNK_SIZE)) + (priv->testmode_trace.buff_size % DUMP_CHUNK_SIZE)) length = priv->testmode_trace.buff_size % - TRACE_CHUNK_SIZE; + DUMP_CHUNK_SIZE; NLA_PUT(skb, IWL_TM_ATTR_TRACE_DUMP, length, priv->testmode_trace.trace_addr + - (TRACE_CHUNK_SIZE * idx)); + (DUMP_CHUNK_SIZE * idx)); idx++; cb->args[4] = idx; return 0; @@ -618,6 +719,110 @@ static int iwl_testmode_ownership(struct ieee80211_hw *hw, struct nlattr **tb) return 0; } +/* + * This function handles the user application commands for SRAM data dump + * + * It retrieves the mandatory fields IWL_TM_ATTR_SRAM_ADDR and + * IWL_TM_ATTR_SRAM_SIZE to decide the memory area for SRAM data reading + * + * Several error will be retured, -EBUSY if the SRAM data retrieved by + * previous command has not been delivered to userspace, or -ENOMSG if + * the mandatory fields (IWL_TM_ATTR_SRAM_ADDR,IWL_TM_ATTR_SRAM_SIZE) + * are missing, or -ENOMEM if the buffer allocation fails. + * + * Otherwise 0 is replied indicating the success of the SRAM reading. + * + * @hw: ieee80211_hw object that represents the device + * @tb: gnl message fields from the user space + */ +static int iwl_testmode_sram(struct ieee80211_hw *hw, struct nlattr **tb) +{ + struct iwl_priv *priv = hw->priv; + u32 base, ofs, size, maxsize; + + if (priv->testmode_sram.sram_readed) + return -EBUSY; + + if (!tb[IWL_TM_ATTR_SRAM_ADDR]) { + IWL_DEBUG_INFO(priv, "Error finding SRAM offset address\n"); + return -ENOMSG; + } + ofs = nla_get_u32(tb[IWL_TM_ATTR_SRAM_ADDR]); + if (!tb[IWL_TM_ATTR_SRAM_SIZE]) { + IWL_DEBUG_INFO(priv, "Error finding size for SRAM reading\n"); + return -ENOMSG; + } + size = nla_get_u32(tb[IWL_TM_ATTR_SRAM_SIZE]); + switch (priv->shrd->ucode_type) { + case IWL_UCODE_REGULAR: + maxsize = trans(priv)->ucode_rt.data.len; + break; + case IWL_UCODE_INIT: + maxsize = trans(priv)->ucode_init.data.len; + break; + case IWL_UCODE_WOWLAN: + maxsize = trans(priv)->ucode_wowlan.data.len; + break; + case IWL_UCODE_NONE: + IWL_DEBUG_INFO(priv, "Error, uCode does not been loaded\n"); + return -ENOSYS; + default: + IWL_DEBUG_INFO(priv, "Error, unsupported uCode type\n"); + return -ENOSYS; + } + if ((ofs + size) > maxsize) { + IWL_DEBUG_INFO(priv, "Invalid offset/size: out of range\n"); + return -EINVAL; + } + priv->testmode_sram.buff_size = (size / 4) * 4; + priv->testmode_sram.buff_addr = + kmalloc(priv->testmode_sram.buff_size, GFP_KERNEL); + if (priv->testmode_sram.buff_addr == NULL) { + IWL_DEBUG_INFO(priv, "Error allocating memory\n"); + return -ENOMEM; + } + base = 0x800000; + _iwl_read_targ_mem_words(bus(priv), base + ofs, + priv->testmode_sram.buff_addr, + priv->testmode_sram.buff_size / 4); + priv->testmode_sram.num_chunks = + DIV_ROUND_UP(priv->testmode_sram.buff_size, DUMP_CHUNK_SIZE); + priv->testmode_sram.sram_readed = true; + return 0; +} + +static int iwl_testmode_sram_dump(struct ieee80211_hw *hw, struct nlattr **tb, + struct sk_buff *skb, + struct netlink_callback *cb) +{ + struct iwl_priv *priv = hw->priv; + int idx, length; + + if (priv->testmode_sram.sram_readed) { + idx = cb->args[4]; + if (idx >= priv->testmode_sram.num_chunks) { + iwl_sram_cleanup(priv); + return -ENOENT; + } + length = DUMP_CHUNK_SIZE; + if (((idx + 1) == priv->testmode_sram.num_chunks) && + (priv->testmode_sram.buff_size % DUMP_CHUNK_SIZE)) + length = priv->testmode_sram.buff_size % + DUMP_CHUNK_SIZE; + + NLA_PUT(skb, IWL_TM_ATTR_SRAM_DUMP, length, + priv->testmode_sram.buff_addr + + (DUMP_CHUNK_SIZE * idx)); + idx++; + cb->args[4] = idx; + return 0; + } else + return -EFAULT; + + nla_put_failure: + return -ENOBUFS; +} + /* The testmode gnl message handler that takes the gnl message from the * user space and parses it per the policy iwl_testmode_gnl_msg_policy, then @@ -665,9 +870,11 @@ int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, int len) IWL_DEBUG_INFO(priv, "testmode cmd to uCode\n"); result = iwl_testmode_ucode(hw, tb); break; - case IWL_TM_CMD_APP2DEV_REG_READ32: - case IWL_TM_CMD_APP2DEV_REG_WRITE32: - case IWL_TM_CMD_APP2DEV_REG_WRITE8: + case IWL_TM_CMD_APP2DEV_DIRECT_REG_READ32: + case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32: + case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8: + case IWL_TM_CMD_APP2DEV_INDIRECT_REG_READ32: + case IWL_TM_CMD_APP2DEV_INDIRECT_REG_WRITE32: IWL_DEBUG_INFO(priv, "testmode cmd to register\n"); result = iwl_testmode_reg(hw, tb); break; @@ -677,6 +884,9 @@ int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, int len) case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW: case IWL_TM_CMD_APP2DEV_GET_EEPROM: case IWL_TM_CMD_APP2DEV_FIXRATE_REQ: + case IWL_TM_CMD_APP2DEV_LOAD_WOWLAN_FW: + case IWL_TM_CMD_APP2DEV_GET_FW_VERSION: + case IWL_TM_CMD_APP2DEV_GET_DEVICE_ID: IWL_DEBUG_INFO(priv, "testmode cmd to driver\n"); result = iwl_testmode_driver(hw, tb); break; @@ -693,6 +903,11 @@ int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, int len) result = iwl_testmode_ownership(hw, tb); break; + case IWL_TM_CMD_APP2DEV_READ_SRAM: + IWL_DEBUG_INFO(priv, "testmode sram read cmd to driver\n"); + result = iwl_testmode_sram(hw, tb); + break; + default: IWL_DEBUG_INFO(priv, "Unknown testmode command\n"); result = -ENOSYS; @@ -741,6 +956,10 @@ int iwlagn_mac_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb, IWL_DEBUG_INFO(priv, "uCode trace cmd to driver\n"); result = iwl_testmode_trace_dump(hw, tb, skb, cb); break; + case IWL_TM_CMD_APP2DEV_DUMP_SRAM: + IWL_DEBUG_INFO(priv, "testmode sram dump cmd to driver\n"); + result = iwl_testmode_sram_dump(hw, tb, skb, cb); + break; default: result = -EINVAL; break; diff --git a/drivers/net/wireless/iwlwifi/iwl-testmode.h b/drivers/net/wireless/iwlwifi/iwl-testmode.h index b980bda4b0f8..26138f110340 100644 --- a/drivers/net/wireless/iwlwifi/iwl-testmode.h +++ b/drivers/net/wireless/iwlwifi/iwl-testmode.h @@ -76,9 +76,9 @@ * the actual uCode host command ID is carried with * IWL_TM_ATTR_UCODE_CMD_ID * - * @IWL_TM_CMD_APP2DEV_REG_READ32: - * @IWL_TM_CMD_APP2DEV_REG_WRITE32: - * @IWL_TM_CMD_APP2DEV_REG_WRITE8: + * @IWL_TM_CMD_APP2DEV_DIRECT_REG_READ32: + * @IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32: + * @IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8: * commands from user applicaiton to access register * * @IWL_TM_CMD_APP2DEV_GET_DEVICENAME: retrieve device name @@ -103,16 +103,30 @@ * @IWL_TM_CMD_DEV2APP_EEPROM_RSP: * commands from kernel space to carry the eeprom response * to user application + * * @IWL_TM_CMD_APP2DEV_OWNERSHIP: * commands from user application to own change the ownership of the uCode * if application has the ownership, the only host command from * testmode will deliver to uCode. Default owner is driver + * + * @IWL_TM_CMD_APP2DEV_INDIRECT_REG_READ32: + * @IWL_TM_CMD_APP2DEV_INDIRECT_REG_WRITE32: + * commands from user applicaiton to indirectly access peripheral register + * + * @IWL_TM_CMD_APP2DEV_READ_SRAM: + * @IWL_TM_CMD_APP2DEV_DUMP_SRAM: + * commands from user applicaiton to read data in sram + * + * @IWL_TM_CMD_APP2DEV_LOAD_WOWLAN_FW: load Weak On Wireless LAN uCode image + * @IWL_TM_CMD_APP2DEV_GET_FW_VERSION: retrieve uCode version + * @IWL_TM_CMD_APP2DEV_GET_DEVICE_ID: retrieve ID information in device + * */ enum iwl_tm_cmd_t { IWL_TM_CMD_APP2DEV_UCODE = 1, - IWL_TM_CMD_APP2DEV_REG_READ32 = 2, - IWL_TM_CMD_APP2DEV_REG_WRITE32 = 3, - IWL_TM_CMD_APP2DEV_REG_WRITE8 = 4, + IWL_TM_CMD_APP2DEV_DIRECT_REG_READ32 = 2, + IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32 = 3, + IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8 = 4, IWL_TM_CMD_APP2DEV_GET_DEVICENAME = 5, IWL_TM_CMD_APP2DEV_LOAD_INIT_FW = 6, IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB = 7, @@ -126,7 +140,14 @@ enum iwl_tm_cmd_t { IWL_TM_CMD_DEV2APP_UCODE_RX_PKT = 15, IWL_TM_CMD_DEV2APP_EEPROM_RSP = 16, IWL_TM_CMD_APP2DEV_OWNERSHIP = 17, - IWL_TM_CMD_MAX = 18, + IWL_TM_CMD_APP2DEV_INDIRECT_REG_READ32 = 18, + IWL_TM_CMD_APP2DEV_INDIRECT_REG_WRITE32 = 19, + IWL_TM_CMD_APP2DEV_READ_SRAM = 20, + IWL_TM_CMD_APP2DEV_DUMP_SRAM = 21, + IWL_TM_CMD_APP2DEV_LOAD_WOWLAN_FW = 22, + IWL_TM_CMD_APP2DEV_GET_FW_VERSION = 23, + IWL_TM_CMD_APP2DEV_GET_DEVICE_ID = 24, + IWL_TM_CMD_MAX = 25, }; /* @@ -196,6 +217,26 @@ enum iwl_tm_cmd_t { * When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_OWNERSHIP, * The mandatory fields are: * IWL_TM_ATTR_UCODE_OWNER for the new owner + * + * @IWL_TM_ATTR_SRAM_ADDR: + * @IWL_TM_ATTR_SRAM_SIZE: + * When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_READ_SRAM, + * The mandatory fields are: + * IWL_TM_ATTR_SRAM_ADDR for the address in sram + * IWL_TM_ATTR_SRAM_SIZE for the buffer size of data reading + * + * @IWL_TM_ATTR_SRAM_DUMP: + * When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_DUMP_SRAM, + * IWL_TM_ATTR_SRAM_DUMP for the data in sram + * + * @IWL_TM_ATTR_FW_VERSION: + * When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_GET_FW_VERSION, + * IWL_TM_ATTR_FW_VERSION for the uCode version + * + * @IWL_TM_ATTR_DEVICE_ID: + * When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_GET_DEVICE_ID, + * IWL_TM_ATTR_DEVICE_ID for the device ID information + * */ enum iwl_tm_attr_t { IWL_TM_ATTR_NOT_APPLICABLE = 0, @@ -213,7 +254,12 @@ enum iwl_tm_attr_t { IWL_TM_ATTR_TRACE_DUMP = 12, IWL_TM_ATTR_FIXRATE = 13, IWL_TM_ATTR_UCODE_OWNER = 14, - IWL_TM_ATTR_MAX = 15, + IWL_TM_ATTR_SRAM_ADDR = 15, + IWL_TM_ATTR_SRAM_SIZE = 16, + IWL_TM_ATTR_SRAM_DUMP = 17, + IWL_TM_ATTR_FW_VERSION = 18, + IWL_TM_ATTR_DEVICE_ID = 19, + IWL_TM_ATTR_MAX = 20, }; /* uCode trace buffer */ @@ -221,6 +267,8 @@ enum iwl_tm_attr_t { #define TRACE_BUFF_SIZE_MIN 0x20000 #define TRACE_BUFF_SIZE_DEF TRACE_BUFF_SIZE_MIN #define TRACE_BUFF_PADD 0x2000 -#define TRACE_CHUNK_SIZE (PAGE_SIZE - 1024) + +/* Maximum data size of each dump it packet */ +#define DUMP_CHUNK_SIZE (PAGE_SIZE - 1024) #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c index ee126f844a5c..2ee00e0f39d3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c @@ -594,8 +594,8 @@ static void iwl_dump_nic_error_log(struct iwl_trans *trans) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - base = priv->device_pointers.error_event_table; - if (priv->ucode_type == IWL_UCODE_INIT) { + base = trans->shrd->device_pointers.error_event_table; + if (trans->shrd->ucode_type == IWL_UCODE_INIT) { if (!base) base = priv->init_errlog_ptr; } else { @@ -607,7 +607,7 @@ static void iwl_dump_nic_error_log(struct iwl_trans *trans) IWL_ERR(trans, "Not valid error log pointer 0x%08X for %s uCode\n", base, - (priv->ucode_type == IWL_UCODE_INIT) + (trans->shrd->ucode_type == IWL_UCODE_INIT) ? "Init" : "RT"); return; } @@ -648,6 +648,21 @@ static void iwl_dump_nic_error_log(struct iwl_trans *trans) IWL_ERR(trans, "0x%08X | hw version\n", table.hw_ver); IWL_ERR(trans, "0x%08X | board version\n", table.brd_ver); IWL_ERR(trans, "0x%08X | hcmd\n", table.hcmd); + + IWL_ERR(trans, "0x%08X | isr0\n", table.isr0); + IWL_ERR(trans, "0x%08X | isr1\n", table.isr1); + IWL_ERR(trans, "0x%08X | isr2\n", table.isr2); + IWL_ERR(trans, "0x%08X | isr3\n", table.isr3); + IWL_ERR(trans, "0x%08X | isr4\n", table.isr4); + IWL_ERR(trans, "0x%08X | isr_pref\n", table.isr_pref); + IWL_ERR(trans, "0x%08X | wait_event\n", table.wait_event); + IWL_ERR(trans, "0x%08X | l2p_control\n", table.l2p_control); + IWL_ERR(trans, "0x%08X | l2p_duration\n", table.l2p_duration); + IWL_ERR(trans, "0x%08X | l2p_mhvalid\n", table.l2p_mhvalid); + IWL_ERR(trans, "0x%08X | l2p_addr_match\n", table.l2p_addr_match); + IWL_ERR(trans, "0x%08X | lmpm_pmg_sel\n", table.lmpm_pmg_sel); + IWL_ERR(trans, "0x%08X | timestamp\n", table.u_timestamp); + IWL_ERR(trans, "0x%08X | flow_handler\n", table.flow_handler); } /** @@ -709,8 +724,8 @@ static int iwl_print_event_log(struct iwl_trans *trans, u32 start_idx, if (num_events == 0) return pos; - base = priv->device_pointers.log_event_table; - if (priv->ucode_type == IWL_UCODE_INIT) { + base = trans->shrd->device_pointers.log_event_table; + if (trans->shrd->ucode_type == IWL_UCODE_INIT) { if (!base) base = priv->init_evtlog_ptr; } else { @@ -823,8 +838,8 @@ int iwl_dump_nic_event_log(struct iwl_trans *trans, bool full_log, size_t bufsz = 0; struct iwl_priv *priv = priv(trans); - base = priv->device_pointers.log_event_table; - if (priv->ucode_type == IWL_UCODE_INIT) { + base = trans->shrd->device_pointers.log_event_table; + if (trans->shrd->ucode_type == IWL_UCODE_INIT) { logsize = priv->init_evtlog_size; if (!base) base = priv->init_evtlog_ptr; @@ -838,7 +853,7 @@ int iwl_dump_nic_event_log(struct iwl_trans *trans, bool full_log, IWL_ERR(trans, "Invalid event log pointer 0x%08X for %s uCode\n", base, - (priv->ucode_type == IWL_UCODE_INIT) + (trans->shrd->ucode_type == IWL_UCODE_INIT) ? "Init" : "RT"); return -EINVAL; } diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c index 5954fdfd60dd..3cf62c363bc0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c @@ -1100,13 +1100,21 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, hdr->seq_ctrl = hdr->seq_ctrl & cpu_to_le16(IEEE80211_SCTL_FRAG); hdr->seq_ctrl |= cpu_to_le16(seq_number); - seq_number += 0x10; /* aggregation is on for this <sta,tid> */ if (info->flags & IEEE80211_TX_CTL_AMPDU) { - WARN_ON_ONCE(tid_data->agg.state != IWL_AGG_ON); + if (WARN_ON_ONCE(tid_data->agg.state != IWL_AGG_ON)) { + IWL_ERR(trans, "TX_CTL_AMPDU while not in AGG:" + " Tx flags = 0x%08x, agg.state = %d", + info->flags, tid_data->agg.state); + IWL_ERR(trans, "sta_id = %d, tid = %d " + "txq_id = %d, seq_num = %d", sta_id, + tid, tid_data->agg.txq_id, + seq_number >> 4); + } txq_id = tid_data->agg.txq_id; is_agg = true; } + seq_number += 0x10; } /* Copy MAC header from skb into command buffer */ @@ -1197,9 +1205,7 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, iwl_print_hex_dump(trans, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len); /* Set up entry for this TFD in Tx byte-count array */ - if (is_agg) - iwl_trans_txq_update_byte_cnt_tbl(trans, txq, - le16_to_cpu(tx_cmd->len)); + iwl_trans_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len)); dma_sync_single_for_device(bus(trans)->dev, txcmd_phys, firstlen, DMA_BIDIRECTIONAL); @@ -1365,6 +1371,7 @@ static void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int sta_id, int tid, static void iwl_trans_pcie_free(struct iwl_trans *trans) { + iwl_calib_free_results(trans); iwl_trans_pcie_tx_free(trans); iwl_trans_pcie_rx_free(trans); free_irq(bus(trans)->irq, trans); diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 50227ebc0ee2..f94a6ee5f82f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -220,11 +220,12 @@ struct fw_img { struct fw_desc data; /* firmware data image */ }; -enum iwl_ucode_type { - IWL_UCODE_NONE, - IWL_UCODE_REGULAR, - IWL_UCODE_INIT, - IWL_UCODE_WOWLAN, +/* Opaque calibration results */ +struct iwl_calib_result { + struct list_head list; + size_t cmd_len; + struct iwl_calib_hdr hdr; + /* data follows */ }; /** @@ -236,6 +237,8 @@ enum iwl_ucode_type { * @ucode_rt: run time ucode image * @ucode_init: init ucode image * @ucode_wowlan: wake on wireless ucode image (optional) + * @nvm_device_type: indicates OTP or eeprom + * @calib_results: list head for init calibration results */ struct iwl_trans { const struct iwl_trans_ops *ops; @@ -250,6 +253,9 @@ struct iwl_trans { /* eeprom related variables */ int nvm_device_type; + /* init calibration results */ + struct list_head calib_results; + /* pointer to trans specific struct */ /*Ensure that this pointer will always be aligned to sizeof pointer */ char trans_specific[0] __attribute__((__aligned__(sizeof(void *)))); @@ -386,4 +392,9 @@ int iwl_alloc_fw_desc(struct iwl_bus *bus, struct fw_desc *desc, const void *data, size_t len); void iwl_dealloc_ucode(struct iwl_trans *trans); +int iwl_send_calib_results(struct iwl_trans *trans); +int iwl_calib_set(struct iwl_trans *trans, + const struct iwl_calib_hdr *cmd, int len); +void iwl_calib_free_results(struct iwl_trans *trans); + #endif /* __iwl_trans_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-ucode.c index 9ec315b31d45..0577212ad3f3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-ucode.c @@ -122,7 +122,7 @@ int iwl_alloc_fw_desc(struct iwl_bus *bus, struct fw_desc *desc, /* * ucode */ -static int iwlagn_load_section(struct iwl_trans *trans, const char *name, +static int iwl_load_section(struct iwl_trans *trans, const char *name, struct fw_desc *image, u32 dst_addr) { struct iwl_bus *bus = bus(trans); @@ -188,7 +188,7 @@ static inline struct fw_img *iwl_get_ucode_image(struct iwl_trans *trans, return NULL; } -static int iwlagn_load_given_ucode(struct iwl_trans *trans, +static int iwl_load_given_ucode(struct iwl_trans *trans, enum iwl_ucode_type ucode_type) { int ret = 0; @@ -201,36 +201,36 @@ static int iwlagn_load_given_ucode(struct iwl_trans *trans, return -EINVAL; } - ret = iwlagn_load_section(trans, "INST", &image->code, + ret = iwl_load_section(trans, "INST", &image->code, IWLAGN_RTC_INST_LOWER_BOUND); if (ret) return ret; - return iwlagn_load_section(trans, "DATA", &image->data, + return iwl_load_section(trans, "DATA", &image->data, IWLAGN_RTC_DATA_LOWER_BOUND); } /* * Calibration */ -static int iwlagn_set_Xtal_calib(struct iwl_priv *priv) +static int iwl_set_Xtal_calib(struct iwl_priv *priv) { struct iwl_calib_xtal_freq_cmd cmd; __le16 *xtal_calib = - (__le16 *)iwl_eeprom_query_addr(priv, EEPROM_XTAL); + (__le16 *)iwl_eeprom_query_addr(priv->shrd, EEPROM_XTAL); iwl_set_calib_hdr(&cmd.hdr, IWL_PHY_CALIBRATE_CRYSTAL_FRQ_CMD); cmd.cap_pin1 = le16_to_cpu(xtal_calib[0]); cmd.cap_pin2 = le16_to_cpu(xtal_calib[1]); - return iwl_calib_set(&priv->calib_results[IWL_CALIB_XTAL], - (u8 *)&cmd, sizeof(cmd)); + return iwl_calib_set(trans(priv), (void *)&cmd, sizeof(cmd)); } -static int iwlagn_set_temperature_offset_calib(struct iwl_priv *priv) +static int iwl_set_temperature_offset_calib(struct iwl_priv *priv) { struct iwl_calib_temperature_offset_cmd cmd; __le16 *offset_calib = - (__le16 *)iwl_eeprom_query_addr(priv, EEPROM_RAW_TEMPERATURE); + (__le16 *)iwl_eeprom_query_addr(priv->shrd, + EEPROM_RAW_TEMPERATURE); memset(&cmd, 0, sizeof(cmd)); iwl_set_calib_hdr(&cmd.hdr, IWL_PHY_CALIBRATE_TEMP_OFFSET_CMD); @@ -240,22 +240,22 @@ static int iwlagn_set_temperature_offset_calib(struct iwl_priv *priv) IWL_DEBUG_CALIB(priv, "Radio sensor offset: %d\n", le16_to_cpu(cmd.radio_sensor_offset)); - return iwl_calib_set(&priv->calib_results[IWL_CALIB_TEMP_OFFSET], - (u8 *)&cmd, sizeof(cmd)); + return iwl_calib_set(trans(priv), (void *)&cmd, sizeof(cmd)); } -static int iwlagn_set_temperature_offset_calib_v2(struct iwl_priv *priv) +static int iwl_set_temperature_offset_calib_v2(struct iwl_priv *priv) { struct iwl_calib_temperature_offset_v2_cmd cmd; - __le16 *offset_calib_high = (__le16 *)iwl_eeprom_query_addr(priv, + __le16 *offset_calib_high = (__le16 *)iwl_eeprom_query_addr(priv->shrd, EEPROM_KELVIN_TEMPERATURE); __le16 *offset_calib_low = - (__le16 *)iwl_eeprom_query_addr(priv, EEPROM_RAW_TEMPERATURE); + (__le16 *)iwl_eeprom_query_addr(priv->shrd, + EEPROM_RAW_TEMPERATURE); struct iwl_eeprom_calib_hdr *hdr; memset(&cmd, 0, sizeof(cmd)); iwl_set_calib_hdr(&cmd.hdr, IWL_PHY_CALIBRATE_TEMP_OFFSET_CMD); - hdr = (struct iwl_eeprom_calib_hdr *)iwl_eeprom_query_addr(priv, + hdr = (struct iwl_eeprom_calib_hdr *)iwl_eeprom_query_addr(priv->shrd, EEPROM_CALIB_ALL); memcpy(&cmd.radio_sensor_offset_high, offset_calib_high, sizeof(*offset_calib_high)); @@ -276,11 +276,10 @@ static int iwlagn_set_temperature_offset_calib_v2(struct iwl_priv *priv) IWL_DEBUG_CALIB(priv, "Voltage Ref: %d\n", le16_to_cpu(cmd.burntVoltageRef)); - return iwl_calib_set(&priv->calib_results[IWL_CALIB_TEMP_OFFSET], - (u8 *)&cmd, sizeof(cmd)); + return iwl_calib_set(trans(priv), (void *)&cmd, sizeof(cmd)); } -static int iwlagn_send_calib_cfg(struct iwl_priv *priv) +static int iwl_send_calib_cfg(struct iwl_trans *trans) { struct iwl_calib_cfg_cmd calib_cfg_cmd; struct iwl_host_cmd cmd = { @@ -296,7 +295,7 @@ static int iwlagn_send_calib_cfg(struct iwl_priv *priv) calib_cfg_cmd.ucd_calib_cfg.flags = IWL_CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_MSK; - return iwl_trans_send_cmd(trans(priv), &cmd); + return iwl_trans_send_cmd(trans, &cmd); } int iwlagn_rx_calib_result(struct iwl_priv *priv, @@ -306,37 +305,14 @@ int iwlagn_rx_calib_result(struct iwl_priv *priv, struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_calib_hdr *hdr = (struct iwl_calib_hdr *)pkt->u.raw; int len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; - int index; /* reduce the size of the length field itself */ len -= 4; - /* Define the order in which the results will be sent to the runtime - * uCode. iwl_send_calib_results sends them in a row according to - * their index. We sort them here - */ - switch (hdr->op_code) { - case IWL_PHY_CALIBRATE_DC_CMD: - index = IWL_CALIB_DC; - break; - case IWL_PHY_CALIBRATE_LO_CMD: - index = IWL_CALIB_LO; - break; - case IWL_PHY_CALIBRATE_TX_IQ_CMD: - index = IWL_CALIB_TX_IQ; - break; - case IWL_PHY_CALIBRATE_TX_IQ_PERD_CMD: - index = IWL_CALIB_TX_IQ_PERD; - break; - case IWL_PHY_CALIBRATE_BASE_BAND_CMD: - index = IWL_CALIB_BASE_BAND; - break; - default: - IWL_ERR(priv, "Unknown calibration notification %d\n", - hdr->op_code); - return -1; - } - iwl_calib_set(&priv->calib_results[index], pkt->u.raw, len); + if (iwl_calib_set(trans(priv), hdr, len)) + IWL_ERR(priv, "Failed to record calibration data %d\n", + hdr->op_code); + return 0; } @@ -352,14 +328,14 @@ int iwlagn_init_alive_start(struct iwl_priv *priv) * no need to close the envlope since we are going * to load the runtime uCode later. */ - ret = iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN, + ret = iwl_send_bt_env(trans(priv), IWL_BT_COEX_ENV_OPEN, BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); if (ret) return ret; } - ret = iwlagn_send_calib_cfg(priv); + ret = iwl_send_calib_cfg(trans(priv)); if (ret) return ret; @@ -369,15 +345,15 @@ int iwlagn_init_alive_start(struct iwl_priv *priv) */ if (priv->cfg->need_temp_offset_calib) { if (priv->cfg->temp_offset_v2) - return iwlagn_set_temperature_offset_calib_v2(priv); + return iwl_set_temperature_offset_calib_v2(priv); else - return iwlagn_set_temperature_offset_calib(priv); + return iwl_set_temperature_offset_calib(priv); } return 0; } -static int iwlagn_send_wimax_coex(struct iwl_priv *priv) +static int iwl_send_wimax_coex(struct iwl_priv *priv) { struct iwl_wimax_coex_cmd coex_cmd; @@ -405,7 +381,7 @@ static int iwlagn_send_wimax_coex(struct iwl_priv *priv) sizeof(coex_cmd), &coex_cmd); } -static const u8 iwlagn_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = { +static const u8 iwl_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = { ((BT_COEX_PRIO_TBL_PRIO_BYPASS << IWL_BT_COEX_PRIO_TBL_PRIO_POS) | (0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)), ((BT_COEX_PRIO_TBL_PRIO_BYPASS << IWL_BT_COEX_PRIO_TBL_PRIO_POS) | @@ -427,42 +403,42 @@ static const u8 iwlagn_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = { 0, 0, 0, 0, 0, 0, 0 }; -void iwlagn_send_prio_tbl(struct iwl_priv *priv) +void iwl_send_prio_tbl(struct iwl_trans *trans) { struct iwl_bt_coex_prio_table_cmd prio_tbl_cmd; - memcpy(prio_tbl_cmd.prio_tbl, iwlagn_bt_prio_tbl, - sizeof(iwlagn_bt_prio_tbl)); - if (iwl_trans_send_cmd_pdu(trans(priv), + memcpy(prio_tbl_cmd.prio_tbl, iwl_bt_prio_tbl, + sizeof(iwl_bt_prio_tbl)); + if (iwl_trans_send_cmd_pdu(trans, REPLY_BT_COEX_PRIO_TABLE, CMD_SYNC, sizeof(prio_tbl_cmd), &prio_tbl_cmd)) - IWL_ERR(priv, "failed to send BT prio tbl command\n"); + IWL_ERR(trans, "failed to send BT prio tbl command\n"); } -int iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type) +int iwl_send_bt_env(struct iwl_trans *trans, u8 action, u8 type) { struct iwl_bt_coex_prot_env_cmd env_cmd; int ret; env_cmd.action = action; env_cmd.type = type; - ret = iwl_trans_send_cmd_pdu(trans(priv), + ret = iwl_trans_send_cmd_pdu(trans, REPLY_BT_COEX_PROT_ENV, CMD_SYNC, sizeof(env_cmd), &env_cmd); if (ret) - IWL_ERR(priv, "failed to send BT env command\n"); + IWL_ERR(trans, "failed to send BT env command\n"); return ret; } -static int iwlagn_alive_notify(struct iwl_priv *priv) +static int iwl_alive_notify(struct iwl_priv *priv) { struct iwl_rxon_context *ctx; int ret; if (!priv->tx_cmd_pool) priv->tx_cmd_pool = - kmem_cache_create("iwlagn_dev_cmd", + kmem_cache_create("iwl_dev_cmd", sizeof(struct iwl_device_cmd), sizeof(void *), 0, NULL); @@ -473,15 +449,17 @@ static int iwlagn_alive_notify(struct iwl_priv *priv) for_each_context(priv, ctx) ctx->last_tx_rejected = false; - ret = iwlagn_send_wimax_coex(priv); + ret = iwl_send_wimax_coex(priv); if (ret) return ret; - ret = iwlagn_set_Xtal_calib(priv); - if (ret) - return ret; + if (!priv->cfg->no_xtal_calib) { + ret = iwl_set_Xtal_calib(priv); + if (ret) + return ret; + } - return iwl_send_calib_results(priv); + return iwl_send_calib_results(trans(priv)); } @@ -572,7 +550,7 @@ struct iwlagn_alive_data { u8 subtype; }; -static void iwlagn_alive_fn(struct iwl_priv *priv, +static void iwl_alive_fn(struct iwl_trans *trans, struct iwl_rx_packet *pkt, void *data) { @@ -581,20 +559,84 @@ static void iwlagn_alive_fn(struct iwl_priv *priv, palive = &pkt->u.alive_frame; - IWL_DEBUG_FW(priv, "Alive ucode status 0x%08X revision " + IWL_DEBUG_FW(trans, "Alive ucode status 0x%08X revision " "0x%01X 0x%01X\n", palive->is_valid, palive->ver_type, palive->ver_subtype); - priv->device_pointers.error_event_table = + trans->shrd->device_pointers.error_event_table = le32_to_cpu(palive->error_event_table_ptr); - priv->device_pointers.log_event_table = + trans->shrd->device_pointers.log_event_table = le32_to_cpu(palive->log_event_table_ptr); alive_data->subtype = palive->ver_subtype; alive_data->valid = palive->is_valid == UCODE_VALID_OK; } +/* notification wait support */ +void iwl_init_notification_wait(struct iwl_shared *shrd, + struct iwl_notification_wait *wait_entry, + u8 cmd, + void (*fn)(struct iwl_trans *trans, + struct iwl_rx_packet *pkt, + void *data), + void *fn_data) +{ + wait_entry->fn = fn; + wait_entry->fn_data = fn_data; + wait_entry->cmd = cmd; + wait_entry->triggered = false; + wait_entry->aborted = false; + + spin_lock_bh(&shrd->notif_wait_lock); + list_add(&wait_entry->list, &shrd->notif_waits); + spin_unlock_bh(&shrd->notif_wait_lock); +} + +int iwl_wait_notification(struct iwl_shared *shrd, + struct iwl_notification_wait *wait_entry, + unsigned long timeout) +{ + int ret; + + ret = wait_event_timeout(shrd->notif_waitq, + wait_entry->triggered || wait_entry->aborted, + timeout); + + spin_lock_bh(&shrd->notif_wait_lock); + list_del(&wait_entry->list); + spin_unlock_bh(&shrd->notif_wait_lock); + + if (wait_entry->aborted) + return -EIO; + + /* return value is always >= 0 */ + if (ret <= 0) + return -ETIMEDOUT; + return 0; +} + +void iwl_remove_notification(struct iwl_shared *shrd, + struct iwl_notification_wait *wait_entry) +{ + spin_lock_bh(&shrd->notif_wait_lock); + list_del(&wait_entry->list); + spin_unlock_bh(&shrd->notif_wait_lock); +} + +void iwl_abort_notification_waits(struct iwl_shared *shrd) +{ + unsigned long flags; + struct iwl_notification_wait *wait_entry; + + spin_lock_irqsave(&shrd->notif_wait_lock, flags); + list_for_each_entry(wait_entry, &shrd->notif_waits, list) + wait_entry->aborted = true; + spin_unlock_irqrestore(&shrd->notif_wait_lock, flags); + + wake_up_all(&shrd->notif_waitq); +} + #define UCODE_ALIVE_TIMEOUT HZ #define UCODE_CALIB_TIMEOUT (2*HZ) @@ -603,41 +645,43 @@ int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv, { struct iwl_notification_wait alive_wait; struct iwlagn_alive_data alive_data; + struct iwl_trans *trans = trans(priv); int ret; enum iwl_ucode_type old_type; - ret = iwl_trans_start_device(trans(priv)); + ret = iwl_trans_start_device(trans); if (ret) return ret; - iwlagn_init_notification_wait(priv, &alive_wait, REPLY_ALIVE, - iwlagn_alive_fn, &alive_data); + iwl_init_notification_wait(trans->shrd, &alive_wait, REPLY_ALIVE, + iwl_alive_fn, &alive_data); - old_type = priv->ucode_type; - priv->ucode_type = ucode_type; + old_type = trans->shrd->ucode_type; + trans->shrd->ucode_type = ucode_type; - ret = iwlagn_load_given_ucode(trans(priv), ucode_type); + ret = iwl_load_given_ucode(trans, ucode_type); if (ret) { - priv->ucode_type = old_type; - iwlagn_remove_notification(priv, &alive_wait); + trans->shrd->ucode_type = old_type; + iwl_remove_notification(trans->shrd, &alive_wait); return ret; } - iwl_trans_kick_nic(trans(priv)); + iwl_trans_kick_nic(trans); /* * Some things may run in the background now, but we * just wait for the ALIVE notification here. */ - ret = iwlagn_wait_notification(priv, &alive_wait, UCODE_ALIVE_TIMEOUT); + ret = iwl_wait_notification(trans->shrd, &alive_wait, + UCODE_ALIVE_TIMEOUT); if (ret) { - priv->ucode_type = old_type; + trans->shrd->ucode_type = old_type; return ret; } if (!alive_data.valid) { IWL_ERR(priv, "Loaded ucode is not valid!\n"); - priv->ucode_type = old_type; + trans->shrd->ucode_type = old_type; return -EIO; } @@ -647,9 +691,9 @@ int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv, * skip it for WoWLAN. */ if (ucode_type != IWL_UCODE_WOWLAN) { - ret = iwl_verify_ucode(trans(priv), ucode_type); + ret = iwl_verify_ucode(trans, ucode_type); if (ret) { - priv->ucode_type = old_type; + trans->shrd->ucode_type = old_type; return ret; } @@ -657,11 +701,11 @@ int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv, msleep(5); } - ret = iwlagn_alive_notify(priv); + ret = iwl_alive_notify(priv); if (ret) { IWL_WARN(priv, "Could not complete ALIVE transition: %d\n", ret); - priv->ucode_type = old_type; + trans->shrd->ucode_type = old_type; return ret; } @@ -679,10 +723,10 @@ int iwlagn_run_init_ucode(struct iwl_priv *priv) if (!trans(priv)->ucode_init.code.len) return 0; - if (priv->ucode_type != IWL_UCODE_NONE) + if (priv->shrd->ucode_type != IWL_UCODE_NONE) return 0; - iwlagn_init_notification_wait(priv, &calib_wait, + iwl_init_notification_wait(priv->shrd, &calib_wait, CALIBRATION_COMPLETE_NOTIFICATION, NULL, NULL); @@ -699,12 +743,13 @@ int iwlagn_run_init_ucode(struct iwl_priv *priv) * Some things may run in the background now, but we * just wait for the calibration complete notification. */ - ret = iwlagn_wait_notification(priv, &calib_wait, UCODE_CALIB_TIMEOUT); + ret = iwl_wait_notification(priv->shrd, &calib_wait, + UCODE_CALIB_TIMEOUT); goto out; error: - iwlagn_remove_notification(priv, &calib_wait); + iwl_remove_notification(priv->shrd, &calib_wait); out: /* Whatever happened, stop the device */ iwl_trans_stop_device(trans(priv)); diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index 98a179f98ea1..1f868b166d10 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -91,11 +91,11 @@ static struct iwm_conf def_iwm_conf = { .mac_addr = {0x00, 0x02, 0xb3, 0x01, 0x02, 0x03}, }; -static int modparam_reset; +static bool modparam_reset; module_param_named(reset, modparam_reset, bool, 0644); MODULE_PARM_DESC(reset, "reset on firmware errors (default 0 [not reset])"); -static int modparam_wimax_enable = 1; +static bool modparam_wimax_enable = true; module_param_named(wimax_enable, modparam_wimax_enable, bool, 0644); MODULE_PARM_DESC(wimax_enable, "Enable wimax core (default 1 [wimax enabled])"); @@ -130,7 +130,7 @@ static void iwm_disconnect_work(struct work_struct *work) iwm_invalidate_mlme_profile(iwm); clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status); - iwm->umac_profile_active = 0; + iwm->umac_profile_active = false; memset(iwm->bssid, 0, ETH_ALEN); iwm->channel = 0; diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index a414768f40f1..7d708f4395f3 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -660,7 +660,7 @@ static int iwm_mlme_profile_invalidate(struct iwm_priv *iwm, u8 *buf, clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status); clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status); - iwm->umac_profile_active = 0; + iwm->umac_profile_active = false; memset(iwm->bssid, 0, ETH_ALEN); iwm->channel = 0; @@ -735,7 +735,7 @@ static int iwm_mlme_update_sta_table(struct iwm_priv *iwm, u8 *buf, umac_sta->mac_addr, umac_sta->flags & UMAC_STA_FLAG_QOS); - sta->valid = 1; + sta->valid = true; sta->qos = umac_sta->flags & UMAC_STA_FLAG_QOS; sta->color = GET_VAL8(umac_sta->sta_id, LMAC_STA_COLOR); memcpy(sta->addr, umac_sta->mac_addr, ETH_ALEN); @@ -750,12 +750,12 @@ static int iwm_mlme_update_sta_table(struct iwm_priv *iwm, u8 *buf, sta = &iwm->sta_table[GET_VAL8(umac_sta->sta_id, LMAC_STA_ID)]; if (!memcmp(sta->addr, umac_sta->mac_addr, ETH_ALEN)) - sta->valid = 0; + sta->valid = false; break; case UMAC_OPCODE_CLEAR_ALL: for (i = 0; i < IWM_STA_TABLE_NUM; i++) - iwm->sta_table[i].valid = 0; + iwm->sta_table[i].valid = false; break; default: @@ -1203,7 +1203,7 @@ static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf, switch (hdr->oid) { case UMAC_WIFI_IF_CMD_SET_PROFILE: - iwm->umac_profile_active = 1; + iwm->umac_profile_active = true; break; default: break; @@ -1363,7 +1363,7 @@ static int iwm_rx_handle_nonwifi(struct iwm_priv *iwm, u8 *buf, */ list_for_each_entry(cmd, &iwm->nonwifi_pending_cmd, pending) if (cmd->seq_num == seq_num) { - cmd->resp_received = 1; + cmd->resp_received = true; cmd->buf.len = buf_size; memcpy(cmd->buf.hdr, buf, buf_size); wake_up_interruptible(&iwm->nonwifi_queue); diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index e26935179861..3f7bf4d912b6 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -859,7 +859,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev) * Most of the libertas cards can do unaligned register access, but some * weird ones cannot. That's especially true for the CF8305 card. */ - card->align_regs = 0; + card->align_regs = false; card->model = get_model(p_dev->manf_id, p_dev->card_id); if (card->model == MODEL_UNKNOWN) { @@ -871,7 +871,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev) /* Check if we have a current silicon */ prod_id = if_cs_read8(card, IF_CS_PRODUCT_ID); if (card->model == MODEL_8305) { - card->align_regs = 1; + card->align_regs = true; if (prod_id < IF_CS_CF8305_B1_REV) { pr_err("8305 rev B0 and older are not supported\n"); ret = -ENODEV; diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index 728baa445259..50b1ee7721e9 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c @@ -1291,7 +1291,6 @@ static struct spi_driver libertas_spi_driver = { .remove = __devexit_p(libertas_spi_remove), .driver = { .name = "libertas_spi", - .bus = &spi_bus_type, .owner = THIS_MODULE, .pm = &if_spi_pm_ops, }, diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c index ceb51b6e6702..a03457292c88 100644 --- a/drivers/net/wireless/libertas_tf/main.c +++ b/drivers/net/wireless/libertas_tf/main.c @@ -719,11 +719,11 @@ void lbtf_bcn_sent(struct lbtf_private *priv) return; if (skb_queue_empty(&priv->bc_ps_buf)) { - bool tx_buff_bc = 0; + bool tx_buff_bc = false; while ((skb = ieee80211_get_buffered_bc(priv->hw, priv->vif))) { skb_queue_tail(&priv->bc_ps_buf, skb); - tx_buff_bc = 1; + tx_buff_bc = true; } if (tx_buff_bc) { ieee80211_stop_queues(priv->hw); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 6cf6d6d25e21..4b9e730d2c8a 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -37,7 +37,8 @@ MODULE_AUTHOR("Jouni Malinen"); MODULE_DESCRIPTION("Software simulator of 802.11 radio(s) for mac80211"); MODULE_LICENSE("GPL"); -int wmediumd_pid; +static u32 wmediumd_pid; + static int radios = 2; module_param(radios, int, 0444); MODULE_PARM_DESC(radios, "Number of simulated radios"); @@ -665,7 +666,7 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { bool ack; struct ieee80211_tx_info *txi; - int _pid; + u32 _pid; mac80211_hwsim_monitor_rx(hw, skb); @@ -676,7 +677,7 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb) } /* wmediumd mode check */ - _pid = wmediumd_pid; + _pid = ACCESS_ONCE(wmediumd_pid); if (_pid) return mac80211_hwsim_tx_frame_nl(hw, skb, _pid); @@ -707,7 +708,7 @@ static int mac80211_hwsim_start(struct ieee80211_hw *hw) { struct mac80211_hwsim_data *data = hw->priv; wiphy_debug(hw->wiphy, "%s\n", __func__); - data->started = 1; + data->started = true; return 0; } @@ -715,7 +716,7 @@ static int mac80211_hwsim_start(struct ieee80211_hw *hw) static void mac80211_hwsim_stop(struct ieee80211_hw *hw) { struct mac80211_hwsim_data *data = hw->priv; - data->started = 0; + data->started = false; del_timer(&data->beacon_timer); wiphy_debug(hw->wiphy, "%s\n", __func__); } @@ -764,7 +765,7 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, struct ieee80211_hw *hw = arg; struct sk_buff *skb; struct ieee80211_tx_info *info; - int _pid; + u32 _pid; hwsim_check_magic(vif); @@ -781,7 +782,7 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, mac80211_hwsim_monitor_rx(hw, skb); /* wmediumd mode check */ - _pid = wmediumd_pid; + _pid = ACCESS_ONCE(wmediumd_pid); if (_pid) return mac80211_hwsim_tx_frame_nl(hw, skb, _pid); @@ -1254,7 +1255,7 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif) struct hwsim_vif_priv *vp = (void *)vif->drv_priv; struct sk_buff *skb; struct ieee80211_pspoll *pspoll; - int _pid; + u32 _pid; if (!vp->assoc) return; @@ -1275,7 +1276,7 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif) memcpy(pspoll->ta, mac, ETH_ALEN); /* wmediumd mode check */ - _pid = wmediumd_pid; + _pid = ACCESS_ONCE(wmediumd_pid); if (_pid) return mac80211_hwsim_tx_frame_nl(data->hw, skb, _pid); @@ -1292,7 +1293,7 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, struct hwsim_vif_priv *vp = (void *)vif->drv_priv; struct sk_buff *skb; struct ieee80211_hdr *hdr; - int _pid; + u32 _pid; if (!vp->assoc) return; @@ -1314,7 +1315,7 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, memcpy(hdr->addr3, vp->bssid, ETH_ALEN); /* wmediumd mode check */ - _pid = wmediumd_pid; + _pid = ACCESS_ONCE(wmediumd_pid); if (_pid) return mac80211_hwsim_tx_frame_nl(data->hw, skb, _pid); @@ -1634,8 +1635,6 @@ static int hwsim_init_netlink(void) int rc; printk(KERN_INFO "mac80211_hwsim: initializing netlink\n"); - wmediumd_pid = 0; - rc = genl_register_family_with_ops(&hwsim_genl_family, hwsim_ops, ARRAY_SIZE(hwsim_ops)); if (rc) diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index e9ab9a3fbe9c..787dbe2aa408 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -120,10 +120,11 @@ mwifiex_cfg80211_del_key(struct wiphy *wiphy, struct net_device *netdev, static int mwifiex_cfg80211_set_tx_power(struct wiphy *wiphy, enum nl80211_tx_power_setting type, - int dbm) + int mbm) { struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); struct mwifiex_power_cfg power_cfg; + int dbm = MBM_TO_DBM(mbm); if (type == NL80211_TX_POWER_FIXED) { power_cfg.is_power_auto = 0; @@ -750,17 +751,13 @@ mwifiex_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); - if (priv->disconnect) - return -EBUSY; - - priv->disconnect = 1; if (mwifiex_deauthenticate(priv, NULL)) return -EFAULT; wiphy_dbg(wiphy, "info: successfully disconnected from %pM:" " reason code %d\n", priv->cfg_bssid, reason_code); - queue_work(priv->workqueue, &priv->cfg_workqueue); + memset(priv->cfg_bssid, 0, ETH_ALEN); return 0; } @@ -980,27 +977,32 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); int ret = 0; - if (priv->assoc_request) - return -EBUSY; - if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { wiphy_err(wiphy, "received infra assoc request " "when station is in ibss mode\n"); goto done; } - priv->assoc_request = -EINPROGRESS; - wiphy_dbg(wiphy, "info: Trying to associate to %s and bssid %pM\n", (char *) sme->ssid, sme->bssid); ret = mwifiex_cfg80211_assoc(priv, sme->ssid_len, sme->ssid, sme->bssid, priv->bss_mode, sme->channel, sme, 0); - - priv->assoc_request = 1; done: - priv->assoc_result = ret; - queue_work(priv->workqueue, &priv->cfg_workqueue); + if (!ret) { + cfg80211_connect_result(priv->netdev, priv->cfg_bssid, NULL, 0, + NULL, 0, WLAN_STATUS_SUCCESS, + GFP_KERNEL); + dev_dbg(priv->adapter->dev, + "info: associated to bssid %pM successfully\n", + priv->cfg_bssid); + } else { + dev_dbg(priv->adapter->dev, + "info: association to bssid %pM failed\n", + priv->cfg_bssid); + memset(priv->cfg_bssid, 0, ETH_ALEN); + } + return ret; } @@ -1017,28 +1019,29 @@ mwifiex_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); int ret = 0; - if (priv->ibss_join_request) - return -EBUSY; - if (priv->bss_mode != NL80211_IFTYPE_ADHOC) { wiphy_err(wiphy, "request to join ibss received " "when station is not in ibss mode\n"); goto done; } - priv->ibss_join_request = -EINPROGRESS; - wiphy_dbg(wiphy, "info: trying to join to %s and bssid %pM\n", (char *) params->ssid, params->bssid); ret = mwifiex_cfg80211_assoc(priv, params->ssid_len, params->ssid, params->bssid, priv->bss_mode, params->channel, NULL, params->privacy); - - priv->ibss_join_request = 1; done: - priv->ibss_join_result = ret; - queue_work(priv->workqueue, &priv->cfg_workqueue); + if (!ret) { + cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid, GFP_KERNEL); + dev_dbg(priv->adapter->dev, + "info: joined/created adhoc network with bssid" + " %pM successfully\n", priv->cfg_bssid); + } else { + dev_dbg(priv->adapter->dev, + "info: failed creating/joining adhoc network\n"); + } + return ret; } @@ -1053,17 +1056,12 @@ mwifiex_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) { struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); - if (priv->disconnect) - return -EBUSY; - - priv->disconnect = 1; - wiphy_dbg(wiphy, "info: disconnecting from essid %pM\n", priv->cfg_bssid); if (mwifiex_deauthenticate(priv, NULL)) return -EFAULT; - queue_work(priv->workqueue, &priv->cfg_workqueue); + memset(priv->cfg_bssid, 0, ETH_ALEN); return 0; } @@ -1080,15 +1078,42 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_scan_request *request) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + int i; + struct ieee80211_channel *chan; wiphy_dbg(wiphy, "info: received scan request on %s\n", dev->name); - if (priv->scan_request && priv->scan_request != request) - return -EBUSY; - priv->scan_request = request; - queue_work(priv->workqueue, &priv->cfg_workqueue); + priv->user_scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg), + GFP_KERNEL); + if (!priv->user_scan_cfg) { + dev_err(priv->adapter->dev, "failed to alloc scan_req\n"); + return -ENOMEM; + } + for (i = 0; i < request->n_ssids; i++) { + memcpy(priv->user_scan_cfg->ssid_list[i].ssid, + request->ssids[i].ssid, request->ssids[i].ssid_len); + priv->user_scan_cfg->ssid_list[i].max_len = + request->ssids[i].ssid_len; + } + for (i = 0; i < request->n_channels; i++) { + chan = request->channels[i]; + priv->user_scan_cfg->chan_list[i].chan_number = chan->hw_value; + priv->user_scan_cfg->chan_list[i].radio_type = chan->band; + + if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) + priv->user_scan_cfg->chan_list[i].scan_type = + MWIFIEX_SCAN_TYPE_PASSIVE; + else + priv->user_scan_cfg->chan_list[i].scan_type = + MWIFIEX_SCAN_TYPE_ACTIVE; + + priv->user_scan_cfg->chan_list[i].scan_time = 0; + } + if (mwifiex_set_user_scan_ioctl(priv, priv->user_scan_cfg)) + return -EFAULT; + return 0; } @@ -1294,10 +1319,6 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev) priv->media_connected = false; - cancel_work_sync(&priv->cfg_workqueue); - flush_workqueue(priv->workqueue); - destroy_workqueue(priv->workqueue); - priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; return 0; @@ -1375,9 +1396,6 @@ int mwifiex_register_cfg80211(struct mwifiex_private *priv) memcpy(wdev->wiphy->perm_addr, priv->curr_addr, ETH_ALEN); wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; - /* We are using custom domains */ - wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; - /* Reserve space for bss band information */ wdev->wiphy->bss_priv_size = sizeof(u8); @@ -1406,100 +1424,3 @@ int mwifiex_register_cfg80211(struct mwifiex_private *priv) return ret; } - -/* - * This function handles the result of different pending network operations. - * - * The following operations are handled and CFG802.11 subsystem is - * notified accordingly - - * - Scan request completion - * - Association request completion - * - IBSS join request completion - * - Disconnect request completion - */ -void -mwifiex_cfg80211_results(struct work_struct *work) -{ - struct mwifiex_private *priv = - container_of(work, struct mwifiex_private, cfg_workqueue); - struct mwifiex_user_scan_cfg *scan_req; - int ret = 0, i; - struct ieee80211_channel *chan; - - if (priv->scan_request) { - scan_req = kzalloc(sizeof(struct mwifiex_user_scan_cfg), - GFP_KERNEL); - if (!scan_req) { - dev_err(priv->adapter->dev, "failed to alloc " - "scan_req\n"); - return; - } - for (i = 0; i < priv->scan_request->n_ssids; i++) { - memcpy(scan_req->ssid_list[i].ssid, - priv->scan_request->ssids[i].ssid, - priv->scan_request->ssids[i].ssid_len); - scan_req->ssid_list[i].max_len = - priv->scan_request->ssids[i].ssid_len; - } - for (i = 0; i < priv->scan_request->n_channels; i++) { - chan = priv->scan_request->channels[i]; - scan_req->chan_list[i].chan_number = chan->hw_value; - scan_req->chan_list[i].radio_type = chan->band; - if (chan->flags & IEEE80211_CHAN_DISABLED) - scan_req->chan_list[i].scan_type = - MWIFIEX_SCAN_TYPE_PASSIVE; - else - scan_req->chan_list[i].scan_type = - MWIFIEX_SCAN_TYPE_ACTIVE; - scan_req->chan_list[i].scan_time = 0; - } - if (mwifiex_set_user_scan_ioctl(priv, scan_req)) - ret = -EFAULT; - priv->scan_result_status = ret; - dev_dbg(priv->adapter->dev, "info: %s: sending scan results\n", - __func__); - cfg80211_scan_done(priv->scan_request, - (priv->scan_result_status < 0)); - priv->scan_request = NULL; - kfree(scan_req); - } - - if (priv->assoc_request == 1) { - if (!priv->assoc_result) { - cfg80211_connect_result(priv->netdev, priv->cfg_bssid, - NULL, 0, NULL, 0, - WLAN_STATUS_SUCCESS, - GFP_KERNEL); - dev_dbg(priv->adapter->dev, - "info: associated to bssid %pM successfully\n", - priv->cfg_bssid); - } else { - dev_dbg(priv->adapter->dev, - "info: association to bssid %pM failed\n", - priv->cfg_bssid); - memset(priv->cfg_bssid, 0, ETH_ALEN); - } - priv->assoc_request = 0; - priv->assoc_result = 0; - } - - if (priv->ibss_join_request == 1) { - if (!priv->ibss_join_result) { - cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid, - GFP_KERNEL); - dev_dbg(priv->adapter->dev, - "info: joined/created adhoc network with bssid" - " %pM successfully\n", priv->cfg_bssid); - } else { - dev_dbg(priv->adapter->dev, - "info: failed creating/joining adhoc network\n"); - } - priv->ibss_join_request = 0; - priv->ibss_join_result = 0; - } - - if (priv->disconnect) { - memset(priv->cfg_bssid, 0, ETH_ALEN); - priv->disconnect = 0; - } -} diff --git a/drivers/net/wireless/mwifiex/cfg80211.h b/drivers/net/wireless/mwifiex/cfg80211.h index 8d010f2500c5..76c76c60438b 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.h +++ b/drivers/net/wireless/mwifiex/cfg80211.h @@ -26,5 +26,4 @@ int mwifiex_register_cfg80211(struct mwifiex_private *); -void mwifiex_cfg80211_results(struct work_struct *work); #endif diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index ac278156d390..6e0a3eaecf70 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -939,7 +939,6 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter) { struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL; unsigned long cmd_flags; - unsigned long cmd_pending_q_flags; unsigned long scan_pending_q_flags; uint16_t cancel_scan_cmd = false; @@ -949,12 +948,9 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter) cmd_node = adapter->curr_cmd; cmd_node->wait_q_enabled = false; cmd_node->cmd_flag |= CMD_F_CANCELED; - spin_lock_irqsave(&adapter->cmd_pending_q_lock, - cmd_pending_q_flags); - list_del(&cmd_node->list); - spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, - cmd_pending_q_flags); mwifiex_insert_cmd_to_free_q(adapter, cmd_node); + mwifiex_complete_cmd(adapter, adapter->curr_cmd); + adapter->curr_cmd = NULL; spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); } @@ -981,7 +977,6 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter) spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); } adapter->cmd_wait_q.status = -1; - mwifiex_complete_cmd(adapter, adapter->curr_cmd); } /* diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 26940455255b..244c728ef9dc 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -283,6 +283,45 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) } /* + * This function sets trans_start per tx_queue + */ +void mwifiex_set_trans_start(struct net_device *dev) +{ + int i; + + for (i = 0; i < dev->num_tx_queues; i++) + netdev_get_tx_queue(dev, i)->trans_start = jiffies; + + dev->trans_start = jiffies; +} + +/* + * This function wakes up all queues in net_device + */ +void mwifiex_wake_up_net_dev_queue(struct net_device *netdev, + struct mwifiex_adapter *adapter) +{ + unsigned long dev_queue_flags; + + spin_lock_irqsave(&adapter->queue_lock, dev_queue_flags); + netif_tx_wake_all_queues(netdev); + spin_unlock_irqrestore(&adapter->queue_lock, dev_queue_flags); +} + +/* + * This function stops all queues in net_device + */ +void mwifiex_stop_net_dev_queue(struct net_device *netdev, + struct mwifiex_adapter *adapter) +{ + unsigned long dev_queue_flags; + + spin_lock_irqsave(&adapter->queue_lock, dev_queue_flags); + netif_tx_stop_all_queues(netdev); + spin_unlock_irqrestore(&adapter->queue_lock, dev_queue_flags); +} + +/* * This function releases the lock variables and frees the locks and * associated locks. */ @@ -359,6 +398,7 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter) spin_lock_init(&adapter->int_lock); spin_lock_init(&adapter->main_proc_lock); spin_lock_init(&adapter->mwifiex_cmd_lock); + spin_lock_init(&adapter->queue_lock); for (i = 0; i < adapter->priv_num; i++) { if (adapter->priv[i]) { priv = adapter->priv[i]; diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 67e6db7d672d..84be196188cc 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -401,7 +401,7 @@ mwifiex_fill_buffer(struct sk_buff *skb) static int mwifiex_open(struct net_device *dev) { - netif_start_queue(dev); + netif_tx_start_all_queues(dev); return 0; } @@ -465,8 +465,8 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) atomic_inc(&priv->adapter->tx_pending); if (atomic_read(&priv->adapter->tx_pending) >= MAX_TX_PENDING) { - netif_stop_queue(priv->netdev); - dev->trans_start = jiffies; + mwifiex_set_trans_start(dev); + mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter); } queue_work(priv->adapter->workqueue, &priv->adapter->main_work); @@ -533,7 +533,7 @@ mwifiex_tx_timeout(struct net_device *dev) dev_err(priv->adapter->dev, "%lu : Tx timeout, bss_index=%d\n", jiffies, priv->bss_index); - dev->trans_start = jiffies; + mwifiex_set_trans_start(dev); priv->num_tx_timeout++; } @@ -586,8 +586,6 @@ void mwifiex_init_priv_params(struct mwifiex_private *priv, priv->media_connected = false; memset(&priv->nick_name, 0, sizeof(priv->nick_name)); priv->num_tx_timeout = 0; - priv->workqueue = create_singlethread_workqueue("cfg80211_wq"); - INIT_WORK(&priv->cfg_workqueue, mwifiex_cfg80211_results); memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN); } @@ -793,7 +791,8 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem) priv = adapter->priv[i]; if (priv && priv->netdev) { if (!netif_queue_stopped(priv->netdev)) - netif_stop_queue(priv->netdev); + mwifiex_stop_net_dev_queue(priv->netdev, + adapter); if (netif_carrier_ok(priv->netdev)) netif_carrier_off(priv->netdev); } diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 3861a617c0e1..9207fc64641e 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -453,15 +453,8 @@ struct mwifiex_private { u8 scan_pending_on_block; u8 report_scan_result; struct cfg80211_scan_request *scan_request; - int scan_result_status; - int assoc_request; - u16 assoc_result; - int ibss_join_request; - u16 ibss_join_result; - bool disconnect; + struct mwifiex_user_scan_cfg *user_scan_cfg; u8 cfg_bssid[6]; - struct workqueue_struct *workqueue; - struct work_struct cfg_workqueue; u8 country_code[IEEE80211_COUNTRY_STRING_LEN]; struct wps wps; u8 scan_block; @@ -655,10 +648,19 @@ struct mwifiex_adapter { struct mwifiex_wait_queue cmd_wait_q; u8 scan_wait_q_woken; struct cmd_ctrl_node *cmd_queued; + spinlock_t queue_lock; /* lock for tx queues */ }; int mwifiex_init_lock_list(struct mwifiex_adapter *adapter); +void mwifiex_set_trans_start(struct net_device *dev); + +void mwifiex_stop_net_dev_queue(struct net_device *netdev, + struct mwifiex_adapter *adapter); + +void mwifiex_wake_up_net_dev_queue(struct net_device *netdev, + struct mwifiex_adapter *adapter); + int mwifiex_init_fw(struct mwifiex_adapter *adapter); int mwifiex_init_fw_complete(struct mwifiex_adapter *adapter); diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index a2f32008f9a8..405350940a45 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -386,7 +386,7 @@ static int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter) card->txbd_ring_vbase = kzalloc(card->txbd_ring_size, GFP_KERNEL); if (!card->txbd_ring_vbase) { dev_err(adapter->dev, "Unable to allocate buffer for txbd ring.\n"); - return -1; + return -ENOMEM; } card->txbd_ring_pbase = virt_to_phys(card->txbd_ring_vbase); @@ -476,7 +476,7 @@ static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter) if (!card->rxbd_ring_vbase) { dev_err(adapter->dev, "Unable to allocate buffer for " "rxbd_ring.\n"); - return -1; + return -ENOMEM; } card->rxbd_ring_pbase = virt_to_phys(card->rxbd_ring_vbase); @@ -569,7 +569,7 @@ static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter) if (!card->evtbd_ring_vbase) { dev_err(adapter->dev, "Unable to allocate buffer. " "Terminating download\n"); - return -1; + return -ENOMEM; } card->evtbd_ring_pbase = virt_to_phys(card->evtbd_ring_vbase); @@ -1231,15 +1231,13 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter, if (rdptr >= MWIFIEX_MAX_EVT_BD) { dev_err(adapter->dev, "event_complete: Invalid rdptr 0x%x\n", rdptr); - ret = -EINVAL; - goto done; + return -EINVAL; } /* Read the event ring write pointer set by firmware */ if (mwifiex_read_reg(adapter, REG_EVTBD_WRPTR, &wrptr)) { dev_err(adapter->dev, "event_complete: failed to read REG_EVTBD_WRPTR\n"); - ret = -1; - goto done; + return -1; } if (!card->evt_buf_list[rdptr]) { @@ -1268,15 +1266,9 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter, /* Write the event ring read pointer in to REG_EVTBD_RDPTR */ if (mwifiex_write_reg(adapter, REG_EVTBD_RDPTR, card->evtbd_rdptr)) { dev_err(adapter->dev, "event_complete: failed to read REG_EVTBD_RDPTR\n"); - ret = -1; - goto done; + return -1; } -done: - /* Free the buffer for failure case */ - if (ret && skb) - dev_kfree_skb_any(skb); - dev_dbg(adapter->dev, "info: Check Events Again\n"); ret = mwifiex_pcie_process_event_ready(adapter); diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index b8b9d37b01a9..e2e715666bca 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -1391,11 +1391,8 @@ int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv, { int status; - priv->adapter->scan_wait_q_woken = false; - status = mwifiex_scan_networks(priv, scan_req); - if (!status) - status = mwifiex_wait_queue_complete(priv->adapter); + queue_work(priv->adapter->workqueue, &priv->adapter->main_work); return status; } @@ -1796,6 +1793,14 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, up(&priv->async_sem); } + if (priv->user_scan_cfg) { + dev_dbg(priv->adapter->dev, "info: %s: sending scan " + "results\n", __func__); + cfg80211_scan_done(priv->scan_request, 0); + priv->scan_request = NULL; + kfree(priv->user_scan_cfg); + priv->user_scan_cfg = NULL; + } } else { /* Get scan command from scan_pending_q and put to cmd_pending_q */ diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index 702452b505c3..d39d8457f252 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -1087,7 +1087,7 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, (adapter->ioport | 0x1000 | (card->mpa_rx.ports << 4)) + card->mpa_rx.start_port, 1)) - return -1; + goto error; curr_ptr = card->mpa_rx.buf; @@ -1130,12 +1130,29 @@ rx_curr_single: if (mwifiex_sdio_card_to_host(adapter, &pkt_type, skb->data, skb->len, adapter->ioport + port)) - return -1; + goto error; mwifiex_decode_rx_packet(adapter, skb, pkt_type); } return 0; + +error: + if (MP_RX_AGGR_IN_PROGRESS(card)) { + /* Multiport-aggregation transfer failed - cleanup */ + for (pind = 0; pind < card->mpa_rx.pkt_cnt; pind++) { + /* copy pkt to deaggr buf */ + skb_deaggr = card->mpa_rx.skb_arr[pind]; + dev_kfree_skb_any(skb_deaggr); + } + MP_RX_AGGR_BUF_RESET(card); + } + + if (f_do_rx_cur) + /* Single transfer pending. Free curr buff also */ + dev_kfree_skb_any(skb); + + return -1; } /* @@ -1271,7 +1288,6 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) dev_dbg(adapter->dev, "info: CFG reg val =%x\n", cr); - dev_kfree_skb_any(skb); return -1; } } diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index f204810e8338..d7aa21da84d0 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -115,18 +115,17 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv) if (adapter->num_cmd_timeout && adapter->curr_cmd) return; priv->media_connected = false; - if (!priv->disconnect) { - priv->disconnect = 1; - dev_dbg(adapter->dev, "info: successfully disconnected from" - " %pM: reason code %d\n", priv->cfg_bssid, - WLAN_REASON_DEAUTH_LEAVING); - cfg80211_disconnected(priv->netdev, - WLAN_REASON_DEAUTH_LEAVING, NULL, 0, - GFP_KERNEL); - queue_work(priv->workqueue, &priv->cfg_workqueue); + dev_dbg(adapter->dev, "info: successfully disconnected from" + " %pM: reason code %d\n", priv->cfg_bssid, + WLAN_REASON_DEAUTH_LEAVING); + if (priv->bss_mode == NL80211_IFTYPE_STATION) { + cfg80211_disconnected(priv->netdev, WLAN_REASON_DEAUTH_LEAVING, + NULL, 0, GFP_KERNEL); } + memset(priv->cfg_bssid, 0, ETH_ALEN); + if (!netif_queue_stopped(priv->netdev)) - netif_stop_queue(priv->netdev); + mwifiex_stop_net_dev_queue(priv->netdev, adapter); if (netif_carrier_ok(priv->netdev)) netif_carrier_off(priv->netdev); /* Reset wireless stats signal info */ @@ -201,7 +200,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) if (!netif_carrier_ok(priv->netdev)) netif_carrier_on(priv->netdev); if (netif_queue_stopped(priv->netdev)) - netif_wake_queue(priv->netdev); + mwifiex_wake_up_net_dev_queue(priv->netdev, adapter); break; case EVENT_DEAUTHENTICATED: @@ -292,7 +291,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) priv->adhoc_is_link_sensed = false; mwifiex_clean_txrx(priv); if (!netif_queue_stopped(priv->netdev)) - netif_stop_queue(priv->netdev); + mwifiex_stop_net_dev_queue(priv->netdev, adapter); if (netif_carrier_ok(priv->netdev)) netif_carrier_off(priv->netdev); break; diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index 4b6f5539657d..6d990c798a20 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -234,7 +234,7 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, "associating...\n"); if (!netif_queue_stopped(priv->netdev)) - netif_stop_queue(priv->netdev); + mwifiex_stop_net_dev_queue(priv->netdev, adapter); /* Clear any past association response stored for * application retrieval */ @@ -265,7 +265,7 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, ret = mwifiex_check_network_compatibility(priv, bss_desc); if (!netif_queue_stopped(priv->netdev)) - netif_stop_queue(priv->netdev); + mwifiex_stop_net_dev_queue(priv->netdev, adapter); if (!ret) { dev_dbg(adapter->dev, "info: network found in scan" diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c index a206f412875f..d9274a1b77ac 100644 --- a/drivers/net/wireless/mwifiex/txrx.c +++ b/drivers/net/wireless/mwifiex/txrx.c @@ -134,7 +134,7 @@ int mwifiex_write_data_complete(struct mwifiex_adapter *adapter, if (!priv) goto done; - priv->netdev->trans_start = jiffies; + mwifiex_set_trans_start(priv->netdev); if (!status) { priv->stats.tx_packets++; priv->stats.tx_bytes += skb->len; @@ -152,7 +152,8 @@ int mwifiex_write_data_complete(struct mwifiex_adapter *adapter, if ((GET_BSS_ROLE(tpriv) == MWIFIEX_BSS_ROLE_STA) && (tpriv->media_connected)) { if (netif_queue_stopped(tpriv->netdev)) - netif_wake_queue(tpriv->netdev); + mwifiex_wake_up_net_dev_queue(tpriv->netdev, + adapter); } } done: diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 995695c28d5c..e75d5c8d62cc 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -31,7 +31,7 @@ #define MWL8K_VERSION "0.12" /* Module parameters */ -static unsigned ap_mode_default; +static bool ap_mode_default; module_param(ap_mode_default, bool, 0); MODULE_PARM_DESC(ap_mode_default, "Set to 1 to make ap mode the default instead of sta mode"); @@ -738,10 +738,10 @@ static int mwl8k_load_firmware(struct ieee80211_hw *hw) ready_code = ioread32(priv->regs + MWL8K_HIU_INT_CODE); if (ready_code == MWL8K_FWAP_READY) { - priv->ap_fw = 1; + priv->ap_fw = true; break; } else if (ready_code == MWL8K_FWSTA_READY) { - priv->ap_fw = 0; + priv->ap_fw = false; break; } @@ -5517,8 +5517,8 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv) INIT_LIST_HEAD(&priv->vif_list); /* Set default radio state and preamble */ - priv->radio_on = 0; - priv->radio_short_preamble = 0; + priv->radio_on = false; + priv->radio_short_preamble = false; /* Finalize join worker */ INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker); diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index b52acc4b4086..9fb77d0319f5 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -121,7 +121,7 @@ module_param(orinoco_debug, int, 0644); MODULE_PARM_DESC(orinoco_debug, "Debug level"); #endif -static int suppress_linkstatus; /* = 0 */ +static bool suppress_linkstatus; /* = 0 */ module_param(suppress_linkstatus, bool, 0644); MODULE_PARM_DESC(suppress_linkstatus, "Don't log link status changes"); diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index db4d9a02f264..af2ca1a9c7d3 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -27,7 +27,7 @@ #include "p54.h" #include "lmac.h" -static int modparam_nohwcrypt; +static bool modparam_nohwcrypt; module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>"); diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index 2d5cf5ba319b..7faed62c6378 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c @@ -700,7 +700,6 @@ static int __devexit p54spi_remove(struct spi_device *spi) static struct spi_driver p54spi_driver = { .driver = { .name = "p54spi", - .bus = &spi_bus_type, .owner = THIS_MODULE, }, diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c index bc2ba80c47bb..4e44b1af119a 100644 --- a/drivers/net/wireless/prism54/isl_ioctl.c +++ b/drivers/net/wireless/prism54/isl_ioctl.c @@ -2493,323 +2493,7 @@ prism54_set_mac_address(struct net_device *ndev, void *addr) return ret; } -/* Note: currently, use hostapd ioctl from the Host AP driver for WPA - * support. This is to be replaced with Linux wireless extensions once they - * get WPA support. */ - -/* Note II: please leave all this together as it will be easier to remove later, - * once wireless extensions add WPA support -mcgrof */ - -/* PRISM54_HOSTAPD ioctl() cmd: */ -enum { - PRISM2_SET_ENCRYPTION = 6, - PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12, - PRISM2_HOSTAPD_MLME = 13, - PRISM2_HOSTAPD_SCAN_REQ = 14, -}; - #define PRISM54_SET_WPA SIOCIWFIRSTPRIV+12 -#define PRISM54_HOSTAPD SIOCIWFIRSTPRIV+25 -#define PRISM54_DROP_UNENCRYPTED SIOCIWFIRSTPRIV+26 - -#define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024 -#define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \ - offsetof(struct prism2_hostapd_param, u.generic_elem.data) - -/* Maximum length for algorithm names (-1 for nul termination) - * used in ioctl() */ -#define HOSTAP_CRYPT_ALG_NAME_LEN 16 - -struct prism2_hostapd_param { - u32 cmd; - u8 sta_addr[ETH_ALEN]; - union { - struct { - u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN]; - u32 flags; - u32 err; - u8 idx; - u8 seq[8]; /* sequence counter (set: RX, get: TX) */ - u16 key_len; - u8 key[0]; - } crypt; - struct { - u8 len; - u8 data[0]; - } generic_elem; - struct { -#define MLME_STA_DEAUTH 0 -#define MLME_STA_DISASSOC 1 - u16 cmd; - u16 reason_code; - } mlme; - struct { - u8 ssid_len; - u8 ssid[32]; - } scan_req; - } u; -}; - - -static int -prism2_ioctl_set_encryption(struct net_device *dev, - struct prism2_hostapd_param *param, - int param_len) -{ - islpci_private *priv = netdev_priv(dev); - int rvalue = 0, force = 0; - int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0; - union oid_res_t r; - - /* with the new API, it's impossible to get a NULL pointer. - * New version of iwconfig set the IW_ENCODE_NOKEY flag - * when no key is given, but older versions don't. */ - - if (param->u.crypt.key_len > 0) { - /* we have a key to set */ - int index = param->u.crypt.idx; - int current_index; - struct obj_key key = { DOT11_PRIV_TKIP, 0, "" }; - - /* get the current key index */ - rvalue = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r); - current_index = r.u; - /* Verify that the key is not marked as invalid */ - if (!(param->u.crypt.flags & IW_ENCODE_NOKEY)) { - key.length = param->u.crypt.key_len > sizeof (param->u.crypt.key) ? - sizeof (param->u.crypt.key) : param->u.crypt.key_len; - memcpy(key.key, param->u.crypt.key, key.length); - if (key.length == 32) - /* we want WPA-PSK */ - key.type = DOT11_PRIV_TKIP; - if ((index < 0) || (index > 3)) - /* no index provided use the current one */ - index = current_index; - - /* now send the key to the card */ - rvalue |= - mgt_set_request(priv, DOT11_OID_DEFKEYX, index, - &key); - } - /* - * If a valid key is set, encryption should be enabled - * (user may turn it off later). - * This is also how "iwconfig ethX key on" works - */ - if ((index == current_index) && (key.length > 0)) - force = 1; - } else { - int index = (param->u.crypt.flags & IW_ENCODE_INDEX) - 1; - if ((index >= 0) && (index <= 3)) { - /* we want to set the key index */ - rvalue |= - mgt_set_request(priv, DOT11_OID_DEFKEYID, 0, - &index); - } else { - if (!(param->u.crypt.flags & IW_ENCODE_MODE)) { - /* we cannot do anything. Complain. */ - return -EINVAL; - } - } - } - /* now read the flags */ - if (param->u.crypt.flags & IW_ENCODE_DISABLED) { - /* Encoding disabled, - * authen = DOT11_AUTH_OS; - * invoke = 0; - * exunencrypt = 0; */ - } - if (param->u.crypt.flags & IW_ENCODE_OPEN) - /* Encode but accept non-encoded packets. No auth */ - invoke = 1; - if ((param->u.crypt.flags & IW_ENCODE_RESTRICTED) || force) { - /* Refuse non-encoded packets. Auth */ - authen = DOT11_AUTH_BOTH; - invoke = 1; - exunencrypt = 1; - } - /* do the change if requested */ - if ((param->u.crypt.flags & IW_ENCODE_MODE) || force) { - rvalue |= - mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen); - rvalue |= - mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &invoke); - rvalue |= - mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, - &exunencrypt); - } - return rvalue; -} - -static int -prism2_ioctl_set_generic_element(struct net_device *ndev, - struct prism2_hostapd_param *param, - int param_len) -{ - islpci_private *priv = netdev_priv(ndev); - int max_len, len, alen, ret=0; - struct obj_attachment *attach; - - len = param->u.generic_elem.len; - max_len = param_len - PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN; - if (max_len < 0 || max_len < len) - return -EINVAL; - - alen = sizeof(*attach) + len; - attach = kzalloc(alen, GFP_KERNEL); - if (attach == NULL) - return -ENOMEM; - -#define WLAN_FC_TYPE_MGMT 0 -#define WLAN_FC_STYPE_ASSOC_REQ 0 -#define WLAN_FC_STYPE_REASSOC_REQ 2 - - /* Note: endianness is covered by mgt_set_varlen */ - - attach->type = (WLAN_FC_TYPE_MGMT << 2) | - (WLAN_FC_STYPE_ASSOC_REQ << 4); - attach->id = -1; - attach->size = len; - memcpy(attach->data, param->u.generic_elem.data, len); - - ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, len); - - if (ret == 0) { - attach->type = (WLAN_FC_TYPE_MGMT << 2) | - (WLAN_FC_STYPE_REASSOC_REQ << 4); - - ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, len); - - if (ret == 0) - printk(KERN_DEBUG "%s: WPA IE Attachment was set\n", - ndev->name); - } - - kfree(attach); - return ret; - -} - -static int -prism2_ioctl_mlme(struct net_device *dev, struct prism2_hostapd_param *param) -{ - return -EOPNOTSUPP; -} - -static int -prism2_ioctl_scan_req(struct net_device *ndev, - struct prism2_hostapd_param *param) -{ - islpci_private *priv = netdev_priv(ndev); - struct iw_request_info info; - int i, rvalue; - struct obj_bsslist *bsslist; - u32 noise = 0; - char *extra = ""; - char *current_ev = "foo"; - union oid_res_t r; - - if (islpci_get_state(priv) < PRV_STATE_INIT) { - /* device is not ready, fail gently */ - return 0; - } - - /* first get the noise value. We will use it to report the link quality */ - rvalue = mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r); - noise = r.u; - - /* Ask the device for a list of known bss. We can report at most - * IW_MAX_AP=64 to the range struct. But the device won't repport anything - * if you change the value of IWMAX_BSS=24. - */ - rvalue |= mgt_get_request(priv, DOT11_OID_BSSLIST, 0, NULL, &r); - bsslist = r.ptr; - - info.cmd = PRISM54_HOSTAPD; - info.flags = 0; - - /* ok now, scan the list and translate its info */ - for (i = 0; i < min(IW_MAX_AP, (int) bsslist->nr); i++) - current_ev = prism54_translate_bss(ndev, &info, current_ev, - extra + IW_SCAN_MAX_DATA, - &(bsslist->bsslist[i]), - noise); - kfree(bsslist); - - return rvalue; -} - -static int -prism54_hostapd(struct net_device *ndev, struct iw_point *p) -{ - struct prism2_hostapd_param *param; - int ret = 0; - u32 uwrq; - - printk(KERN_DEBUG "prism54_hostapd - len=%d\n", p->length); - if (p->length < sizeof(struct prism2_hostapd_param) || - p->length > PRISM2_HOSTAPD_MAX_BUF_SIZE || !p->pointer) - return -EINVAL; - - param = memdup_user(p->pointer, p->length); - if (IS_ERR(param)) - return PTR_ERR(param); - - switch (param->cmd) { - case PRISM2_SET_ENCRYPTION: - printk(KERN_DEBUG "%s: Caught WPA supplicant set encryption request\n", - ndev->name); - ret = prism2_ioctl_set_encryption(ndev, param, p->length); - break; - case PRISM2_HOSTAPD_SET_GENERIC_ELEMENT: - printk(KERN_DEBUG "%s: Caught WPA supplicant set WPA IE request\n", - ndev->name); - ret = prism2_ioctl_set_generic_element(ndev, param, - p->length); - break; - case PRISM2_HOSTAPD_MLME: - printk(KERN_DEBUG "%s: Caught WPA supplicant MLME request\n", - ndev->name); - ret = prism2_ioctl_mlme(ndev, param); - break; - case PRISM2_HOSTAPD_SCAN_REQ: - printk(KERN_DEBUG "%s: Caught WPA supplicant scan request\n", - ndev->name); - ret = prism2_ioctl_scan_req(ndev, param); - break; - case PRISM54_SET_WPA: - printk(KERN_DEBUG "%s: Caught WPA supplicant wpa init request\n", - ndev->name); - uwrq = 1; - ret = prism54_set_wpa(ndev, NULL, &uwrq, NULL); - break; - case PRISM54_DROP_UNENCRYPTED: - printk(KERN_DEBUG "%s: Caught WPA drop unencrypted request\n", - ndev->name); -#if 0 - uwrq = 0x01; - mgt_set(priv, DOT11_OID_EXUNENCRYPTED, &uwrq); - down_write(&priv->mib_sem); - mgt_commit(priv); - up_write(&priv->mib_sem); -#endif - /* Not necessary, as set_wpa does it, should we just do it here though? */ - ret = 0; - break; - default: - printk(KERN_DEBUG "%s: Caught a WPA supplicant request that is not supported\n", - ndev->name); - ret = -EOPNOTSUPP; - break; - } - - if (ret == 0 && copy_to_user(p->pointer, param, p->length)) - ret = -EFAULT; - - kfree(param); - - return ret; -} static int prism54_set_wpa(struct net_device *ndev, struct iw_request_info *info, @@ -3223,20 +2907,3 @@ const struct iw_handler_def prism54_handler_def = { .private_args = (struct iw_priv_args *) prism54_private_args, .get_wireless_stats = prism54_get_wireless_stats, }; - -/* For wpa_supplicant */ - -int -prism54_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) -{ - struct iwreq *wrq = (struct iwreq *) rq; - int ret = -1; - switch (cmd) { - case PRISM54_HOSTAPD: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - ret = prism54_hostapd(ndev, &wrq->u.data); - return ret; - } - return -EOPNOTSUPP; -} diff --git a/drivers/net/wireless/prism54/isl_ioctl.h b/drivers/net/wireless/prism54/isl_ioctl.h index bcfbfb9281d2..a34bceb6e3cd 100644 --- a/drivers/net/wireless/prism54/isl_ioctl.h +++ b/drivers/net/wireless/prism54/isl_ioctl.h @@ -43,8 +43,6 @@ void prism54_wpa_bss_ie_clean(islpci_private *priv); int prism54_set_mac_address(struct net_device *, void *); -int prism54_ioctl(struct net_device *, struct ifreq *, int); - extern const struct iw_handler_def prism54_handler_def; #endif /* _ISL_IOCTL_H */ diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c index 8a3cf4fe376f..5970ff6f40cc 100644 --- a/drivers/net/wireless/prism54/islpci_dev.c +++ b/drivers/net/wireless/prism54/islpci_dev.c @@ -804,7 +804,6 @@ static const struct ethtool_ops islpci_ethtool_ops = { static const struct net_device_ops islpci_netdev_ops = { .ndo_open = islpci_open, .ndo_stop = islpci_close, - .ndo_do_ioctl = prism54_ioctl, .ndo_start_xmit = islpci_eth_transmit, .ndo_tx_timeout = islpci_eth_tx_timeout, .ndo_set_mac_address = prism54_set_mac_address, diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 53c5f878f61d..de7d41f21a69 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -39,7 +39,7 @@ /* * Allow hardware encryption to be disabled. */ -static int modparam_nohwcrypt; +static bool modparam_nohwcrypt; module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 1ba079dffb11..e5df380d4fbe 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1203,8 +1203,10 @@ void rt2800_config_filter(struct rt2x00_dev *rt2x00dev, !(filter_flags & FIF_CONTROL)); rt2x00_set_field32(®, RX_FILTER_CFG_DROP_PSPOLL, !(filter_flags & FIF_PSPOLL)); - rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BA, 1); - rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BAR, 0); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BA, + !(filter_flags & FIF_CONTROL)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BAR, + !(filter_flags & FIF_CONTROL)); rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CNTL, !(filter_flags & FIF_CONTROL)); rt2800_register_write(rt2x00dev, RX_FILTER_CFG, reg); diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index da48c8ac27bd..4941a1a23219 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -50,7 +50,7 @@ /* * Allow hardware encryption to be disabled. */ -static int modparam_nohwcrypt = 0; +static bool modparam_nohwcrypt = false; module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 377876315b8d..b1df1a774948 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -45,7 +45,7 @@ /* * Allow hardware encryption to be disabled. */ -static int modparam_nohwcrypt; +static bool modparam_nohwcrypt; module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index edd317fa7c0a..c3e1aa7c1a80 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -831,11 +831,11 @@ static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev, if (spec->supported_rates & SUPPORT_RATE_OFDM) num_rates += 8; - channels = kzalloc(sizeof(*channels) * spec->num_channels, GFP_KERNEL); + channels = kcalloc(spec->num_channels, sizeof(*channels), GFP_KERNEL); if (!channels) return -ENOMEM; - rates = kzalloc(sizeof(*rates) * num_rates, GFP_KERNEL); + rates = kcalloc(num_rates, sizeof(*rates), GFP_KERNEL); if (!rates) goto exit_free_channels; diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index bf0acff07807..ede3c58e6783 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -160,7 +160,7 @@ void rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) exit_fail: rt2x00queue_pause_queue(queue); exit_free_skb: - dev_kfree_skb_any(skb); + ieee80211_free_txskb(hw, skb); } EXPORT_SYMBOL_GPL(rt2x00mac_tx); diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index bf55b4a311e3..e0c6d117429d 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -41,7 +41,7 @@ /* * Allow hardware encryption to be disabled. */ -static int modparam_nohwcrypt = 0; +static bool modparam_nohwcrypt = false; module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index cfb19dbb0a67..1c69c737086d 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -40,7 +40,7 @@ /* * Allow hardware encryption to be disabled. */ -static int modparam_nohwcrypt; +static bool modparam_nohwcrypt; module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c index a13ecfce4825..74c021436704 100644 --- a/drivers/net/wireless/rtlwifi/base.c +++ b/drivers/net/wireless/rtlwifi/base.c @@ -396,7 +396,7 @@ void rtl_init_rfkill(struct ieee80211_hw *hw) u8 valid = 0; /*set init state to on */ - rtlpriv->rfkill.rfkill_state = 1; + rtlpriv->rfkill.rfkill_state = true; wiphy_rfkill_set_hw_state(hw->wiphy, 0); radio_state = rtlpriv->cfg->ops->radio_onoff_checking(hw, &valid); @@ -448,12 +448,11 @@ int rtl_init_core(struct ieee80211_hw *hw) /* <4> locks */ mutex_init(&rtlpriv->locks.conf_mutex); - spin_lock_init(&rtlpriv->locks.ips_lock); + mutex_init(&rtlpriv->locks.ps_mutex); spin_lock_init(&rtlpriv->locks.irq_th_lock); spin_lock_init(&rtlpriv->locks.h2c_lock); spin_lock_init(&rtlpriv->locks.rf_ps_lock); spin_lock_init(&rtlpriv->locks.rf_lock); - spin_lock_init(&rtlpriv->locks.lps_lock); spin_lock_init(&rtlpriv->locks.waitq_lock); spin_lock_init(&rtlpriv->locks.cck_and_rw_pagea_lock); diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index b6683a247b51..39e0907a3c4e 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -78,7 +78,7 @@ static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw) u8 init_aspm; ppsc->reg_rfps_level = 0; - ppsc->support_aspm = 0; + ppsc->support_aspm = false; /*Update PCI ASPM setting */ ppsc->const_amdpci_aspm = rtlpci->const_amdpci_aspm; @@ -570,9 +570,9 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio) if (ieee80211_is_nullfunc(fc)) { if (ieee80211_has_pm(fc)) { rtlpriv->mac80211.offchan_delay = true; - rtlpriv->psc.state_inap = 1; + rtlpriv->psc.state_inap = true; } else { - rtlpriv->psc.state_inap = 0; + rtlpriv->psc.state_inap = false; } } @@ -610,7 +610,7 @@ tx_status_ok: if (((rtlpriv->link_info.num_rx_inperiod + rtlpriv->link_info.num_tx_inperiod) > 8) || (rtlpriv->link_info.num_rx_inperiod > 2)) { - tasklet_schedule(&rtlpriv->works.ips_leave_tasklet); + schedule_work(&rtlpriv->works.lps_leave_work); } } @@ -736,7 +736,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) if (((rtlpriv->link_info.num_rx_inperiod + rtlpriv->link_info.num_tx_inperiod) > 8) || (rtlpriv->link_info.num_rx_inperiod > 2)) { - tasklet_schedule(&rtlpriv->works.ips_leave_tasklet); + schedule_work(&rtlpriv->works.lps_leave_work); } dev_kfree_skb_any(skb); @@ -780,6 +780,7 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id) unsigned long flags; u32 inta = 0; u32 intb = 0; + irqreturn_t ret = IRQ_HANDLED; spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); @@ -787,8 +788,10 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id) rtlpriv->cfg->ops->interrupt_recognized(hw, &inta, &intb); /*Shared IRQ or HW disappared */ - if (!inta || inta == 0xffff) + if (!inta || inta == 0xffff) { + ret = IRQ_NONE; goto done; + } /*<1> beacon related */ if (inta & rtlpriv->cfg->maps[RTL_IMR_TBDOK]) { @@ -892,7 +895,7 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id) done: spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); - return IRQ_HANDLED; + return ret; } static void _rtl_pci_irq_tasklet(struct ieee80211_hw *hw) @@ -900,11 +903,6 @@ static void _rtl_pci_irq_tasklet(struct ieee80211_hw *hw) _rtl_pci_tx_chk_waitq(hw); } -static void _rtl_pci_ips_leave_tasklet(struct ieee80211_hw *hw) -{ - rtl_lps_leave(hw); -} - static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -942,6 +940,15 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw) return; } +static void rtl_lps_leave_work_callback(struct work_struct *work) +{ + struct rtl_works *rtlworks = + container_of(work, struct rtl_works, lps_leave_work); + struct ieee80211_hw *hw = rtlworks->hw; + + rtl_lps_leave(hw); +} + static void _rtl_pci_init_trx_var(struct ieee80211_hw *hw) { struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); @@ -1003,9 +1010,7 @@ static void _rtl_pci_init_struct(struct ieee80211_hw *hw, tasklet_init(&rtlpriv->works.irq_prepare_bcn_tasklet, (void (*)(unsigned long))_rtl_pci_prepare_bcn_tasklet, (unsigned long)hw); - tasklet_init(&rtlpriv->works.ips_leave_tasklet, - (void (*)(unsigned long))_rtl_pci_ips_leave_tasklet, - (unsigned long)hw); + INIT_WORK(&rtlpriv->works.lps_leave_work, rtl_lps_leave_work_callback); } static int _rtl_pci_init_tx_ring(struct ieee80211_hw *hw, @@ -1475,7 +1480,7 @@ static void rtl_pci_deinit(struct ieee80211_hw *hw) synchronize_irq(rtlpci->pdev->irq); tasklet_kill(&rtlpriv->works.irq_tasklet); - tasklet_kill(&rtlpriv->works.ips_leave_tasklet); + cancel_work_sync(&rtlpriv->works.lps_leave_work); flush_workqueue(rtlpriv->works.rtl_wq); destroy_workqueue(rtlpriv->works.rtl_wq); @@ -1550,7 +1555,7 @@ static void rtl_pci_stop(struct ieee80211_hw *hw) set_hal_stop(rtlhal); rtlpriv->cfg->ops->disable_interrupt(hw); - tasklet_kill(&rtlpriv->works.ips_leave_tasklet); + cancel_work_sync(&rtlpriv->works.lps_leave_work); spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flags); while (ppsc->rfchange_inprogress) { diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c index 55c8e50f45fd..a14a68b24635 100644 --- a/drivers/net/wireless/rtlwifi/ps.c +++ b/drivers/net/wireless/rtlwifi/ps.c @@ -241,7 +241,7 @@ void rtl_ips_nic_on(struct ieee80211_hw *hw) if (mac->opmode != NL80211_IFTYPE_STATION) return; - spin_lock(&rtlpriv->locks.ips_lock); + mutex_lock(&rtlpriv->locks.ps_mutex); if (ppsc->inactiveps) { rtstate = ppsc->rfpwr_state; @@ -257,7 +257,7 @@ void rtl_ips_nic_on(struct ieee80211_hw *hw) } } - spin_unlock(&rtlpriv->locks.ips_lock); + mutex_unlock(&rtlpriv->locks.ps_mutex); } /*for FW LPS*/ @@ -395,7 +395,7 @@ void rtl_lps_enter(struct ieee80211_hw *hw) if (mac->link_state != MAC80211_LINKED) return; - spin_lock_irq(&rtlpriv->locks.lps_lock); + mutex_lock(&rtlpriv->locks.ps_mutex); /* Idle for a while if we connect to AP a while ago. */ if (mac->cnt_after_linked >= 2) { @@ -407,7 +407,7 @@ void rtl_lps_enter(struct ieee80211_hw *hw) } } - spin_unlock_irq(&rtlpriv->locks.lps_lock); + mutex_unlock(&rtlpriv->locks.ps_mutex); } /*Leave the leisure power save mode.*/ @@ -416,9 +416,8 @@ void rtl_lps_leave(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - unsigned long flags; - spin_lock_irqsave(&rtlpriv->locks.lps_lock, flags); + mutex_lock(&rtlpriv->locks.ps_mutex); if (ppsc->fwctrl_lps) { if (ppsc->dot11_psmode != EACTIVE) { @@ -439,7 +438,7 @@ void rtl_lps_leave(struct ieee80211_hw *hw) rtl_lps_set_psmode(hw, EACTIVE); } } - spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flags); + mutex_unlock(&rtlpriv->locks.ps_mutex); } /* For sw LPS*/ @@ -540,9 +539,9 @@ void rtl_swlps_rf_awake(struct ieee80211_hw *hw) RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); } - spin_lock_irq(&rtlpriv->locks.lps_lock); + mutex_lock(&rtlpriv->locks.ps_mutex); rtl_ps_set_rf_state(hw, ERFON, RF_CHANGE_BY_PS); - spin_unlock_irq(&rtlpriv->locks.lps_lock); + mutex_unlock(&rtlpriv->locks.ps_mutex); } void rtl_swlps_rfon_wq_callback(void *data) @@ -575,9 +574,9 @@ void rtl_swlps_rf_sleep(struct ieee80211_hw *hw) if (rtlpriv->link_info.busytraffic) return; - spin_lock_irq(&rtlpriv->locks.lps_lock); + mutex_lock(&rtlpriv->locks.ps_mutex); rtl_ps_set_rf_state(hw, ERFSLEEP, RF_CHANGE_BY_PS); - spin_unlock_irq(&rtlpriv->locks.lps_lock); + mutex_unlock(&rtlpriv->locks.ps_mutex); if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM && !RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) { diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c index fa393dfe136c..931d97979b04 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c @@ -262,10 +262,10 @@ int rtl92c_download_fw(struct ieee80211_hw *hw) u32 fwsize; enum version_8192c version = rtlhal->version; - pr_info("Loading firmware file %s\n", rtlpriv->cfg->fw_name); if (!rtlhal->pfirmware) return 1; + pr_info("Loading firmware file %s\n", rtlpriv->cfg->fw_name); pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware; pfwdata = (u8 *) rtlhal->pfirmware; fwsize = rtlhal->fwsize; diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c index 592a10ac5929..3b585aadabfc 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c @@ -569,7 +569,7 @@ static bool _rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw, } case ERFSLEEP:{ if (ppsc->rfpwr_state == ERFOFF) - break; + return false; for (queue_id = 0, i = 0; queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) { ring = &pcipriv->dev.tx_ring[queue_id]; diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c index f2aa33dc4d78..89ef6982ce50 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c @@ -98,9 +98,9 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw) rtl8192ce_bt_reg_init(hw); - rtlpriv->dm.dm_initialgain_enable = 1; + rtlpriv->dm.dm_initialgain_enable = true; rtlpriv->dm.dm_flag = 0; - rtlpriv->dm.disable_framebursting = 0; + rtlpriv->dm.disable_framebursting = false; rtlpriv->dm.thermalvalue = 0; rtlpci->transmit_config = CFENDFORM | BIT(12) | BIT(13); diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c index 4ed973a3aa17..124cf633861c 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c @@ -2436,7 +2436,7 @@ bool rtl92cu_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid) "%x\n", ppsc->hwradiooff, e_rfpowerstate_toset)); } if (actuallyset) { - ppsc->hwradiooff = 1; + ppsc->hwradiooff = true; if (e_rfpowerstate_toset == ERFON) { if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) && RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM)) diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c index 72852900df84..e49cf2244c75 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c @@ -548,7 +548,7 @@ static bool _rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw, break; case ERFSLEEP: if (ppsc->rfpwr_state == ERFOFF) - break; + return false; for (queue_id = 0, i = 0; queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) { ring = &pcipriv->dev.tx_ring[queue_id]; diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c index 94a3e1706158..3527c7957b45 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c @@ -57,9 +57,9 @@ static int rtl92cu_init_sw_vars(struct ieee80211_hw *hw) const struct firmware *firmware; int err; - rtlpriv->dm.dm_initialgain_enable = 1; + rtlpriv->dm.dm_initialgain_enable = true; rtlpriv->dm.dm_flag = 0; - rtlpriv->dm.disable_framebursting = 0; + rtlpriv->dm.disable_framebursting = false; rtlpriv->dm.thermalvalue = 0; rtlpriv->dbg.global_debuglevel = rtlpriv->cfg->mod_params->debug; rtlpriv->rtlhal.pfirmware = vmalloc(0x4000); diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c index 3ac7af1c5509..0883349e1c83 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c @@ -3374,7 +3374,7 @@ bool rtl92d_phy_set_rf_power_state(struct ieee80211_hw *hw, break; case ERFSLEEP: if (ppsc->rfpwr_state == ERFOFF) - break; + return false; for (queue_id = 0, i = 0; queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) { diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/sw.c b/drivers/net/wireless/rtlwifi/rtl8192de/sw.c index 149493f4c25c..7911c9c87085 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/sw.c @@ -99,9 +99,9 @@ static int rtl92d_init_sw_vars(struct ieee80211_hw *hw) rtlpriv->dm.dm_initialgain_enable = true; rtlpriv->dm.dm_flag = 0; - rtlpriv->dm.disable_framebursting = 0; + rtlpriv->dm.disable_framebursting = false; rtlpriv->dm.thermalvalue = 0; - rtlpriv->dm.useramask = 1; + rtlpriv->dm.useramask = true; /* dual mac */ if (rtlpriv->rtlhal.current_bandtype == BAND_ON_5G) diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/phy.c b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c index f27171af979c..f10ac1ad9087 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c @@ -602,7 +602,7 @@ bool rtl92s_phy_set_rf_power_state(struct ieee80211_hw *hw, } case ERFSLEEP: if (ppsc->rfpwr_state == ERFOFF) - break; + return false; for (queue_id = 0, i = 0; queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) { diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c index 92f49d522c56..78723cf59491 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c @@ -98,9 +98,9 @@ static int rtl92s_init_sw_vars(struct ieee80211_hw *hw) int err = 0; u16 earlyrxthreshold = 7; - rtlpriv->dm.dm_initialgain_enable = 1; + rtlpriv->dm.dm_initialgain_enable = true; rtlpriv->dm.dm_flag = 0; - rtlpriv->dm.disable_framebursting = 0; + rtlpriv->dm.disable_framebursting = false; rtlpriv->dm.thermalvalue = 0; rtlpriv->dm.useramask = true; diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index f3c132b55d42..9b7d60c0bf80 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -1488,7 +1488,7 @@ struct rtl_intf_ops { struct rtl_mod_params { /* default: 0 = using hardware encryption */ - int sw_crypto; + bool sw_crypto; /* default: 0 = DBG_EMERG (0)*/ int debug; @@ -1544,14 +1544,13 @@ struct rtl_hal_cfg { struct rtl_locks { /* mutex */ struct mutex conf_mutex; + struct mutex ps_mutex; /*spin lock */ - spinlock_t ips_lock; spinlock_t irq_th_lock; spinlock_t h2c_lock; spinlock_t rf_ps_lock; spinlock_t rf_lock; - spinlock_t lps_lock; spinlock_t waitq_lock; /*Dual mac*/ @@ -1576,7 +1575,8 @@ struct rtl_works { /* For SW LPS */ struct delayed_work ps_work; struct delayed_work ps_rfon_wq; - struct tasklet_struct ips_leave_tasklet; + + struct work_struct lps_leave_work; }; struct rtl_debug { diff --git a/drivers/net/wireless/wl1251/spi.c b/drivers/net/wireless/wl1251/spi.c index eaa5f9556200..6248c354fc5c 100644 --- a/drivers/net/wireless/wl1251/spi.c +++ b/drivers/net/wireless/wl1251/spi.c @@ -319,7 +319,6 @@ static int __devexit wl1251_spi_remove(struct spi_device *spi) static struct spi_driver wl1251_spi_driver = { .driver = { .name = DRIVER_NAME, - .bus = &spi_bus_type, .owner = THIS_MODULE, }, diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig index 3fe388b87c2e..af08c8609c63 100644 --- a/drivers/net/wireless/wl12xx/Kconfig +++ b/drivers/net/wireless/wl12xx/Kconfig @@ -42,16 +42,6 @@ config WL12XX_SDIO If you choose to build a module, it'll be called wl12xx_sdio. Say N if unsure. -config WL12XX_SDIO_TEST - tristate "TI wl12xx SDIO testing support" - depends on WL12XX && MMC && WL12XX_SDIO - default n - ---help--- - This module adds support for the SDIO bus testing with the - TI wl12xx chipsets. You probably don't want this unless you are - testing a new hardware platform. Select this if you want to test the - SDIO bus which is connected to the wl12xx chip. - config WL12XX_PLATFORM_DATA bool depends on WL12XX_SDIO != n || WL1251_SDIO != n diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile index 621b3483ca2c..fe67262ba19f 100644 --- a/drivers/net/wireless/wl12xx/Makefile +++ b/drivers/net/wireless/wl12xx/Makefile @@ -3,14 +3,11 @@ wl12xx-objs = main.o cmd.o io.o event.o tx.o rx.o ps.o acx.o \ wl12xx_spi-objs = spi.o wl12xx_sdio-objs = sdio.o -wl12xx_sdio_test-objs = sdio_test.o wl12xx-$(CONFIG_NL80211_TESTMODE) += testmode.o obj-$(CONFIG_WL12XX) += wl12xx.o obj-$(CONFIG_WL12XX_SPI) += wl12xx_spi.o obj-$(CONFIG_WL12XX_SDIO) += wl12xx_sdio.o -obj-$(CONFIG_WL12XX_SDIO_TEST) += wl12xx_sdio_test.o - # small builtin driver bit obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx_platform_data.o diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index ca044a743191..7537c401a448 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c @@ -29,11 +29,12 @@ #include <linux/slab.h> #include "wl12xx.h" +#include "debug.h" #include "wl12xx_80211.h" #include "reg.h" #include "ps.h" -int wl1271_acx_wake_up_conditions(struct wl1271 *wl) +int wl1271_acx_wake_up_conditions(struct wl1271 *wl, struct wl12xx_vif *wlvif) { struct acx_wake_up_condition *wake_up; int ret; @@ -46,7 +47,7 @@ int wl1271_acx_wake_up_conditions(struct wl1271 *wl) goto out; } - wake_up->role_id = wl->role_id; + wake_up->role_id = wlvif->role_id; wake_up->wake_up_event = wl->conf.conn.wake_up_event; wake_up->listen_interval = wl->conf.conn.listen_interval; @@ -84,7 +85,8 @@ out: return ret; } -int wl1271_acx_tx_power(struct wl1271 *wl, int power) +int wl1271_acx_tx_power(struct wl1271 *wl, struct wl12xx_vif *wlvif, + int power) { struct acx_current_tx_power *acx; int ret; @@ -100,7 +102,7 @@ int wl1271_acx_tx_power(struct wl1271 *wl, int power) goto out; } - acx->role_id = wl->role_id; + acx->role_id = wlvif->role_id; acx->current_tx_power = power * 10; ret = wl1271_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx)); @@ -114,7 +116,7 @@ out: return ret; } -int wl1271_acx_feature_cfg(struct wl1271 *wl) +int wl1271_acx_feature_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif) { struct acx_feature_config *feature; int ret; @@ -128,7 +130,7 @@ int wl1271_acx_feature_cfg(struct wl1271 *wl) } /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */ - feature->role_id = wl->role_id; + feature->role_id = wlvif->role_id; feature->data_flow_options = 0; feature->options = 0; @@ -184,33 +186,8 @@ out: return ret; } -int wl1271_acx_pd_threshold(struct wl1271 *wl) -{ - struct acx_packet_detection *pd; - int ret; - - wl1271_debug(DEBUG_ACX, "acx data pd threshold"); - - pd = kzalloc(sizeof(*pd), GFP_KERNEL); - if (!pd) { - ret = -ENOMEM; - goto out; - } - - pd->threshold = cpu_to_le32(wl->conf.rx.packet_detection_threshold); - - ret = wl1271_cmd_configure(wl, ACX_PD_THRESHOLD, pd, sizeof(*pd)); - if (ret < 0) { - wl1271_warning("failed to set pd threshold: %d", ret); - goto out; - } - -out: - kfree(pd); - return ret; -} - -int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time) +int wl1271_acx_slot(struct wl1271 *wl, struct wl12xx_vif *wlvif, + enum acx_slot_type slot_time) { struct acx_slot *slot; int ret; @@ -223,7 +200,7 @@ int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time) goto out; } - slot->role_id = wl->role_id; + slot->role_id = wlvif->role_id; slot->wone_index = STATION_WONE_INDEX; slot->slot_time = slot_time; @@ -238,8 +215,8 @@ out: return ret; } -int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable, - void *mc_list, u32 mc_list_len) +int wl1271_acx_group_address_tbl(struct wl1271 *wl, struct wl12xx_vif *wlvif, + bool enable, void *mc_list, u32 mc_list_len) { struct acx_dot11_grp_addr_tbl *acx; int ret; @@ -253,7 +230,7 @@ int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable, } /* MAC filtering */ - acx->role_id = wl->role_id; + acx->role_id = wlvif->role_id; acx->enabled = enable; acx->num_groups = mc_list_len; memcpy(acx->mac_table, mc_list, mc_list_len * ETH_ALEN); @@ -270,7 +247,8 @@ out: return ret; } -int wl1271_acx_service_period_timeout(struct wl1271 *wl) +int wl1271_acx_service_period_timeout(struct wl1271 *wl, + struct wl12xx_vif *wlvif) { struct acx_rx_timeout *rx_timeout; int ret; @@ -283,7 +261,7 @@ int wl1271_acx_service_period_timeout(struct wl1271 *wl) wl1271_debug(DEBUG_ACX, "acx service period timeout"); - rx_timeout->role_id = wl->role_id; + rx_timeout->role_id = wlvif->role_id; rx_timeout->ps_poll_timeout = cpu_to_le16(wl->conf.rx.ps_poll_timeout); rx_timeout->upsd_timeout = cpu_to_le16(wl->conf.rx.upsd_timeout); @@ -300,7 +278,8 @@ out: return ret; } -int wl1271_acx_rts_threshold(struct wl1271 *wl, u32 rts_threshold) +int wl1271_acx_rts_threshold(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u32 rts_threshold) { struct acx_rts_threshold *rts; int ret; @@ -320,7 +299,7 @@ int wl1271_acx_rts_threshold(struct wl1271 *wl, u32 rts_threshold) goto out; } - rts->role_id = wl->role_id; + rts->role_id = wlvif->role_id; rts->threshold = cpu_to_le16((u16)rts_threshold); ret = wl1271_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts)); @@ -363,7 +342,8 @@ out: return ret; } -int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter) +int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, struct wl12xx_vif *wlvif, + bool enable_filter) { struct acx_beacon_filter_option *beacon_filter = NULL; int ret = 0; @@ -380,7 +360,7 @@ int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter) goto out; } - beacon_filter->role_id = wl->role_id; + beacon_filter->role_id = wlvif->role_id; beacon_filter->enable = enable_filter; /* @@ -401,7 +381,8 @@ out: return ret; } -int wl1271_acx_beacon_filter_table(struct wl1271 *wl) +int wl1271_acx_beacon_filter_table(struct wl1271 *wl, + struct wl12xx_vif *wlvif) { struct acx_beacon_filter_ie_table *ie_table; int i, idx = 0; @@ -417,7 +398,7 @@ int wl1271_acx_beacon_filter_table(struct wl1271 *wl) } /* configure default beacon pass-through rules */ - ie_table->role_id = wl->role_id; + ie_table->role_id = wlvif->role_id; ie_table->num_ie = 0; for (i = 0; i < wl->conf.conn.bcn_filt_ie_count; i++) { struct conf_bcn_filt_rule *r = &(wl->conf.conn.bcn_filt_ie[i]); @@ -458,7 +439,8 @@ out: #define ACX_CONN_MONIT_DISABLE_VALUE 0xffffffff -int wl1271_acx_conn_monit_params(struct wl1271 *wl, bool enable) +int wl1271_acx_conn_monit_params(struct wl1271 *wl, struct wl12xx_vif *wlvif, + bool enable) { struct acx_conn_monit_params *acx; u32 threshold = ACX_CONN_MONIT_DISABLE_VALUE; @@ -479,7 +461,7 @@ int wl1271_acx_conn_monit_params(struct wl1271 *wl, bool enable) timeout = wl->conf.conn.bss_lose_timeout; } - acx->role_id = wl->role_id; + acx->role_id = wlvif->role_id; acx->synch_fail_thold = cpu_to_le32(threshold); acx->bss_lose_timeout = cpu_to_le32(timeout); @@ -582,7 +564,7 @@ out: return ret; } -int wl1271_acx_bcn_dtim_options(struct wl1271 *wl) +int wl1271_acx_bcn_dtim_options(struct wl1271 *wl, struct wl12xx_vif *wlvif) { struct acx_beacon_broadcast *bb; int ret; @@ -595,7 +577,7 @@ int wl1271_acx_bcn_dtim_options(struct wl1271 *wl) goto out; } - bb->role_id = wl->role_id; + bb->role_id = wlvif->role_id; bb->beacon_rx_timeout = cpu_to_le16(wl->conf.conn.beacon_rx_timeout); bb->broadcast_timeout = cpu_to_le16(wl->conf.conn.broadcast_timeout); bb->rx_broadcast_in_ps = wl->conf.conn.rx_broadcast_in_ps; @@ -612,7 +594,7 @@ out: return ret; } -int wl1271_acx_aid(struct wl1271 *wl, u16 aid) +int wl1271_acx_aid(struct wl1271 *wl, struct wl12xx_vif *wlvif, u16 aid) { struct acx_aid *acx_aid; int ret; @@ -625,7 +607,7 @@ int wl1271_acx_aid(struct wl1271 *wl, u16 aid) goto out; } - acx_aid->role_id = wl->role_id; + acx_aid->role_id = wlvif->role_id; acx_aid->aid = cpu_to_le16(aid); ret = wl1271_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid)); @@ -668,7 +650,8 @@ out: return ret; } -int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble) +int wl1271_acx_set_preamble(struct wl1271 *wl, struct wl12xx_vif *wlvif, + enum acx_preamble_type preamble) { struct acx_preamble *acx; int ret; @@ -681,7 +664,7 @@ int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble) goto out; } - acx->role_id = wl->role_id; + acx->role_id = wlvif->role_id; acx->preamble = preamble; ret = wl1271_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx)); @@ -695,7 +678,7 @@ out: return ret; } -int wl1271_acx_cts_protect(struct wl1271 *wl, +int wl1271_acx_cts_protect(struct wl1271 *wl, struct wl12xx_vif *wlvif, enum acx_ctsprotect_type ctsprotect) { struct acx_ctsprotect *acx; @@ -709,7 +692,7 @@ int wl1271_acx_cts_protect(struct wl1271 *wl, goto out; } - acx->role_id = wl->role_id; + acx->role_id = wlvif->role_id; acx->ctsprotect = ctsprotect; ret = wl1271_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx)); @@ -739,7 +722,7 @@ int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats) return 0; } -int wl1271_acx_sta_rate_policies(struct wl1271 *wl) +int wl1271_acx_sta_rate_policies(struct wl1271 *wl, struct wl12xx_vif *wlvif) { struct acx_rate_policy *acx; struct conf_tx_rate_class *c = &wl->conf.tx.sta_rc_conf; @@ -755,11 +738,11 @@ int wl1271_acx_sta_rate_policies(struct wl1271 *wl) } wl1271_debug(DEBUG_ACX, "basic_rate: 0x%x, full_rate: 0x%x", - wl->basic_rate, wl->rate_set); + wlvif->basic_rate, wlvif->rate_set); /* configure one basic rate class */ - acx->rate_policy_idx = cpu_to_le32(ACX_TX_BASIC_RATE); - acx->rate_policy.enabled_rates = cpu_to_le32(wl->basic_rate); + acx->rate_policy_idx = cpu_to_le32(wlvif->sta.basic_rate_idx); + acx->rate_policy.enabled_rates = cpu_to_le32(wlvif->basic_rate); acx->rate_policy.short_retry_limit = c->short_retry_limit; acx->rate_policy.long_retry_limit = c->long_retry_limit; acx->rate_policy.aflags = c->aflags; @@ -771,8 +754,8 @@ int wl1271_acx_sta_rate_policies(struct wl1271 *wl) } /* configure one AP supported rate class */ - acx->rate_policy_idx = cpu_to_le32(ACX_TX_AP_FULL_RATE); - acx->rate_policy.enabled_rates = cpu_to_le32(wl->rate_set); + acx->rate_policy_idx = cpu_to_le32(wlvif->sta.ap_rate_idx); + acx->rate_policy.enabled_rates = cpu_to_le32(wlvif->rate_set); acx->rate_policy.short_retry_limit = c->short_retry_limit; acx->rate_policy.long_retry_limit = c->long_retry_limit; acx->rate_policy.aflags = c->aflags; @@ -788,7 +771,7 @@ int wl1271_acx_sta_rate_policies(struct wl1271 *wl) * (p2p packets should always go out with OFDM rates, even * if we are currently connected to 11b AP) */ - acx->rate_policy_idx = cpu_to_le32(ACX_TX_BASIC_RATE_P2P); + acx->rate_policy_idx = cpu_to_le32(wlvif->sta.p2p_rate_idx); acx->rate_policy.enabled_rates = cpu_to_le32(CONF_TX_RATE_MASK_BASIC_P2P); acx->rate_policy.short_retry_limit = c->short_retry_limit; @@ -839,8 +822,8 @@ out: return ret; } -int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max, - u8 aifsn, u16 txop) +int wl1271_acx_ac_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u8 ac, u8 cw_min, u16 cw_max, u8 aifsn, u16 txop) { struct acx_ac_cfg *acx; int ret = 0; @@ -855,7 +838,7 @@ int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max, goto out; } - acx->role_id = wl->role_id; + acx->role_id = wlvif->role_id; acx->ac = ac; acx->cw_min = cw_min; acx->cw_max = cpu_to_le16(cw_max); @@ -873,7 +856,8 @@ out: return ret; } -int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type, +int wl1271_acx_tid_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u8 queue_id, u8 channel_type, u8 tsid, u8 ps_scheme, u8 ack_policy, u32 apsd_conf0, u32 apsd_conf1) { @@ -889,7 +873,7 @@ int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type, goto out; } - acx->role_id = wl->role_id; + acx->role_id = wlvif->role_id; acx->queue_id = queue_id; acx->channel_type = channel_type; acx->tsid = tsid; @@ -1098,7 +1082,8 @@ out: return ret; } -int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable) +int wl1271_acx_bet_enable(struct wl1271 *wl, struct wl12xx_vif *wlvif, + bool enable) { struct wl1271_acx_bet_enable *acx = NULL; int ret = 0; @@ -1114,7 +1099,7 @@ int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable) goto out; } - acx->role_id = wl->role_id; + acx->role_id = wlvif->role_id; acx->enable = enable ? CONF_BET_MODE_ENABLE : CONF_BET_MODE_DISABLE; acx->max_consecutive = wl->conf.conn.bet_max_consecutive; @@ -1129,7 +1114,8 @@ out: return ret; } -int wl1271_acx_arp_ip_filter(struct wl1271 *wl, u8 enable, __be32 address) +int wl1271_acx_arp_ip_filter(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u8 enable, __be32 address) { struct wl1271_acx_arp_filter *acx; int ret; @@ -1142,7 +1128,7 @@ int wl1271_acx_arp_ip_filter(struct wl1271 *wl, u8 enable, __be32 address) goto out; } - acx->role_id = wl->role_id; + acx->role_id = wlvif->role_id; acx->version = ACX_IPV4_VERSION; acx->enable = enable; @@ -1189,7 +1175,8 @@ out: return ret; } -int wl1271_acx_keep_alive_mode(struct wl1271 *wl, bool enable) +int wl1271_acx_keep_alive_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, + bool enable) { struct wl1271_acx_keep_alive_mode *acx = NULL; int ret = 0; @@ -1202,7 +1189,7 @@ int wl1271_acx_keep_alive_mode(struct wl1271 *wl, bool enable) goto out; } - acx->role_id = wl->role_id; + acx->role_id = wlvif->role_id; acx->enabled = enable; ret = wl1271_cmd_configure(wl, ACX_KEEP_ALIVE_MODE, acx, sizeof(*acx)); @@ -1216,7 +1203,8 @@ out: return ret; } -int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid) +int wl1271_acx_keep_alive_config(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u8 index, u8 tpl_valid) { struct wl1271_acx_keep_alive_config *acx = NULL; int ret = 0; @@ -1229,7 +1217,7 @@ int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid) goto out; } - acx->role_id = wl->role_id; + acx->role_id = wlvif->role_id; acx->period = cpu_to_le32(wl->conf.conn.keep_alive_interval); acx->index = index; acx->tpl_validation = tpl_valid; @@ -1247,8 +1235,8 @@ out: return ret; } -int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable, - s16 thold, u8 hyst) +int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, struct wl12xx_vif *wlvif, + bool enable, s16 thold, u8 hyst) { struct wl1271_acx_rssi_snr_trigger *acx = NULL; int ret = 0; @@ -1261,9 +1249,9 @@ int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable, goto out; } - wl->last_rssi_event = -1; + wlvif->last_rssi_event = -1; - acx->role_id = wl->role_id; + acx->role_id = wlvif->role_id; acx->pacing = cpu_to_le16(wl->conf.roam_trigger.trigger_pacing); acx->metric = WL1271_ACX_TRIG_METRIC_RSSI_BEACON; acx->type = WL1271_ACX_TRIG_TYPE_EDGE; @@ -1288,7 +1276,8 @@ out: return ret; } -int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl) +int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl, + struct wl12xx_vif *wlvif) { struct wl1271_acx_rssi_snr_avg_weights *acx = NULL; struct conf_roam_trigger_settings *c = &wl->conf.roam_trigger; @@ -1302,7 +1291,7 @@ int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl) goto out; } - acx->role_id = wl->role_id; + acx->role_id = wlvif->role_id; acx->rssi_beacon = c->avg_weight_rssi_beacon; acx->rssi_data = c->avg_weight_rssi_data; acx->snr_beacon = c->avg_weight_snr_beacon; @@ -1367,6 +1356,7 @@ out: } int wl1271_acx_set_ht_information(struct wl1271 *wl, + struct wl12xx_vif *wlvif, u16 ht_operation_mode) { struct wl1271_acx_ht_information *acx; @@ -1380,7 +1370,7 @@ int wl1271_acx_set_ht_information(struct wl1271 *wl, goto out; } - acx->role_id = wl->role_id; + acx->role_id = wlvif->role_id; acx->ht_protection = (u8)(ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION); acx->rifs_mode = 0; @@ -1402,7 +1392,8 @@ out: } /* Configure BA session initiator/receiver parameters setting in the FW. */ -int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl) +int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl, + struct wl12xx_vif *wlvif) { struct wl1271_acx_ba_initiator_policy *acx; int ret; @@ -1416,7 +1407,7 @@ int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl) } /* set for the current role */ - acx->role_id = wl->role_id; + acx->role_id = wlvif->role_id; acx->tid_bitmap = wl->conf.ht.tx_ba_tid_bitmap; acx->win_size = wl->conf.ht.tx_ba_win_size; acx->inactivity_timeout = wl->conf.ht.inactivity_timeout; @@ -1494,7 +1485,8 @@ out: return ret; } -int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, bool enable) +int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif, + bool enable) { struct wl1271_acx_ps_rx_streaming *rx_streaming; u32 conf_queues, enable_queues; @@ -1523,7 +1515,7 @@ int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, bool enable) if (!(conf_queues & BIT(i))) continue; - rx_streaming->role_id = wl->role_id; + rx_streaming->role_id = wlvif->role_id; rx_streaming->tid = i; rx_streaming->enable = enable_queues & BIT(i); rx_streaming->period = wl->conf.rx_streaming.interval; @@ -1542,7 +1534,7 @@ out: return ret; } -int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl) +int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl, struct wl12xx_vif *wlvif) { struct wl1271_acx_ap_max_tx_retry *acx = NULL; int ret; @@ -1553,7 +1545,7 @@ int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl) if (!acx) return -ENOMEM; - acx->role_id = wl->role_id; + acx->role_id = wlvif->role_id; acx->max_tx_retry = cpu_to_le16(wl->conf.tx.max_tx_retries); ret = wl1271_cmd_configure(wl, ACX_MAX_TX_FAILURE, acx, sizeof(*acx)); @@ -1567,7 +1559,7 @@ out: return ret; } -int wl1271_acx_config_ps(struct wl1271 *wl) +int wl12xx_acx_config_ps(struct wl1271 *wl, struct wl12xx_vif *wlvif) { struct wl1271_acx_config_ps *config_ps; int ret; @@ -1582,7 +1574,7 @@ int wl1271_acx_config_ps(struct wl1271 *wl) config_ps->exit_retries = wl->conf.conn.psm_exit_retries; config_ps->enter_retries = wl->conf.conn.psm_entry_retries; - config_ps->null_data_rate = cpu_to_le32(wl->basic_rate); + config_ps->null_data_rate = cpu_to_le32(wlvif->basic_rate); ret = wl1271_cmd_configure(wl, ACX_CONFIG_PS, config_ps, sizeof(*config_ps)); diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h index e3f93b4b3429..69892b40c2df 100644 --- a/drivers/net/wireless/wl12xx/acx.h +++ b/drivers/net/wireless/wl12xx/acx.h @@ -171,13 +171,6 @@ struct acx_rx_msdu_lifetime { __le32 lifetime; } __packed; -struct acx_packet_detection { - struct acx_header header; - - __le32 threshold; -} __packed; - - enum acx_slot_type { SLOT_TIME_LONG = 0, SLOT_TIME_SHORT = 1, @@ -654,11 +647,6 @@ struct acx_rate_class { u8 reserved; }; -#define ACX_TX_BASIC_RATE 0 -#define ACX_TX_AP_FULL_RATE 1 -#define ACX_TX_BASIC_RATE_P2P 2 -#define ACX_TX_AP_MODE_MGMT_RATE 4 -#define ACX_TX_AP_MODE_BCST_RATE 5 struct acx_rate_policy { struct acx_header header; @@ -1234,39 +1222,48 @@ enum { }; -int wl1271_acx_wake_up_conditions(struct wl1271 *wl); +int wl1271_acx_wake_up_conditions(struct wl1271 *wl, + struct wl12xx_vif *wlvif); int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth); -int wl1271_acx_tx_power(struct wl1271 *wl, int power); -int wl1271_acx_feature_cfg(struct wl1271 *wl); +int wl1271_acx_tx_power(struct wl1271 *wl, struct wl12xx_vif *wlvif, + int power); +int wl1271_acx_feature_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif); int wl1271_acx_mem_map(struct wl1271 *wl, struct acx_header *mem_map, size_t len); int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl); -int wl1271_acx_pd_threshold(struct wl1271 *wl); -int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time); -int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable, - void *mc_list, u32 mc_list_len); -int wl1271_acx_service_period_timeout(struct wl1271 *wl); -int wl1271_acx_rts_threshold(struct wl1271 *wl, u32 rts_threshold); +int wl1271_acx_slot(struct wl1271 *wl, struct wl12xx_vif *wlvif, + enum acx_slot_type slot_time); +int wl1271_acx_group_address_tbl(struct wl1271 *wl, struct wl12xx_vif *wlvif, + bool enable, void *mc_list, u32 mc_list_len); +int wl1271_acx_service_period_timeout(struct wl1271 *wl, + struct wl12xx_vif *wlvif); +int wl1271_acx_rts_threshold(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u32 rts_threshold); int wl1271_acx_dco_itrim_params(struct wl1271 *wl); -int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter); -int wl1271_acx_beacon_filter_table(struct wl1271 *wl); -int wl1271_acx_conn_monit_params(struct wl1271 *wl, bool enable); +int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, struct wl12xx_vif *wlvif, + bool enable_filter); +int wl1271_acx_beacon_filter_table(struct wl1271 *wl, + struct wl12xx_vif *wlvif); +int wl1271_acx_conn_monit_params(struct wl1271 *wl, struct wl12xx_vif *wlvif, + bool enable); int wl1271_acx_sg_enable(struct wl1271 *wl, bool enable); int wl12xx_acx_sg_cfg(struct wl1271 *wl); int wl1271_acx_cca_threshold(struct wl1271 *wl); -int wl1271_acx_bcn_dtim_options(struct wl1271 *wl); -int wl1271_acx_aid(struct wl1271 *wl, u16 aid); +int wl1271_acx_bcn_dtim_options(struct wl1271 *wl, struct wl12xx_vif *wlvif); +int wl1271_acx_aid(struct wl1271 *wl, struct wl12xx_vif *wlvif, u16 aid); int wl1271_acx_event_mbox_mask(struct wl1271 *wl, u32 event_mask); -int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble); -int wl1271_acx_cts_protect(struct wl1271 *wl, +int wl1271_acx_set_preamble(struct wl1271 *wl, struct wl12xx_vif *wlvif, + enum acx_preamble_type preamble); +int wl1271_acx_cts_protect(struct wl1271 *wl, struct wl12xx_vif *wlvif, enum acx_ctsprotect_type ctsprotect); int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats); -int wl1271_acx_sta_rate_policies(struct wl1271 *wl); +int wl1271_acx_sta_rate_policies(struct wl1271 *wl, struct wl12xx_vif *wlvif); int wl1271_acx_ap_rate_policy(struct wl1271 *wl, struct conf_tx_rate_class *c, u8 idx); -int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max, - u8 aifsn, u16 txop); -int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type, +int wl1271_acx_ac_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u8 ac, u8 cw_min, u16 cw_max, u8 aifsn, u16 txop); +int wl1271_acx_tid_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u8 queue_id, u8 channel_type, u8 tsid, u8 ps_scheme, u8 ack_policy, u32 apsd_conf0, u32 apsd_conf1); int wl1271_acx_frag_threshold(struct wl1271 *wl, u32 frag_threshold); @@ -1276,26 +1273,34 @@ int wl1271_acx_init_mem_config(struct wl1271 *wl); int wl1271_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap); int wl1271_acx_init_rx_interrupt(struct wl1271 *wl); int wl1271_acx_smart_reflex(struct wl1271 *wl); -int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable); -int wl1271_acx_arp_ip_filter(struct wl1271 *wl, u8 enable, __be32 address); +int wl1271_acx_bet_enable(struct wl1271 *wl, struct wl12xx_vif *wlvif, + bool enable); +int wl1271_acx_arp_ip_filter(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u8 enable, __be32 address); int wl1271_acx_pm_config(struct wl1271 *wl); -int wl1271_acx_keep_alive_mode(struct wl1271 *wl, bool enable); -int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid); -int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable, - s16 thold, u8 hyst); -int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl); +int wl1271_acx_keep_alive_mode(struct wl1271 *wl, struct wl12xx_vif *vif, + bool enable); +int wl1271_acx_keep_alive_config(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u8 index, u8 tpl_valid); +int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, struct wl12xx_vif *wlvif, + bool enable, s16 thold, u8 hyst); +int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl, + struct wl12xx_vif *wlvif); int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, struct ieee80211_sta_ht_cap *ht_cap, bool allow_ht_operation, u8 hlid); int wl1271_acx_set_ht_information(struct wl1271 *wl, + struct wl12xx_vif *wlvif, u16 ht_operation_mode); -int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl); +int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl, + struct wl12xx_vif *wlvif); int wl12xx_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn, bool enable, u8 peer_hlid); int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime); -int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, bool enable); -int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl); -int wl1271_acx_config_ps(struct wl1271 *wl); +int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif, + bool enable); +int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl, struct wl12xx_vif *wlvif); +int wl12xx_acx_config_ps(struct wl1271 *wl, struct wl12xx_vif *wlvif); int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr); int wl1271_acx_fm_coex(struct wl1271 *wl); int wl12xx_acx_set_rate_mgmt_params(struct wl1271 *wl); diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c index 681337914976..8f9cf5a816ea 100644 --- a/drivers/net/wireless/wl12xx/boot.c +++ b/drivers/net/wireless/wl12xx/boot.c @@ -25,6 +25,7 @@ #include <linux/wl12xx.h> #include <linux/export.h> +#include "debug.h" #include "acx.h" #include "reg.h" #include "boot.h" @@ -347,6 +348,9 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) nvs_ptr += 3; for (i = 0; i < burst_len; i++) { + if (nvs_ptr + 3 >= (u8 *) wl->nvs + nvs_len) + goto out_badnvs; + val = (nvs_ptr[0] | (nvs_ptr[1] << 8) | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); @@ -358,6 +362,9 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) nvs_ptr += 4; dest_addr += 4; } + + if (nvs_ptr >= (u8 *) wl->nvs + nvs_len) + goto out_badnvs; } /* @@ -369,6 +376,10 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) */ nvs_ptr = (u8 *)wl->nvs + ALIGN(nvs_ptr - (u8 *)wl->nvs + 7, 4); + + if (nvs_ptr >= (u8 *) wl->nvs + nvs_len) + goto out_badnvs; + nvs_len -= nvs_ptr - (u8 *)wl->nvs; /* Now we must set the partition correctly */ @@ -384,6 +395,10 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) kfree(nvs_aligned); return 0; + +out_badnvs: + wl1271_error("nvs data is malformed"); + return -EILSEQ; } static void wl1271_boot_enable_interrupts(struct wl1271 *wl) diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index a52299e548fa..e0d217979485 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -29,6 +29,7 @@ #include <linux/slab.h> #include "wl12xx.h" +#include "debug.h" #include "reg.h" #include "io.h" #include "acx.h" @@ -120,6 +121,11 @@ int wl1271_cmd_general_parms(struct wl1271 *wl) if (!wl->nvs) return -ENODEV; + if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) { + wl1271_warning("FEM index from INI out of bounds"); + return -EINVAL; + } + gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL); if (!gen_parms) return -ENOMEM; @@ -143,6 +149,12 @@ int wl1271_cmd_general_parms(struct wl1271 *wl) gp->tx_bip_fem_manufacturer = gen_parms->general_params.tx_bip_fem_manufacturer; + if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) { + wl1271_warning("FEM index from FW out of bounds"); + ret = -EINVAL; + goto out; + } + wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n", answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer); @@ -162,6 +174,11 @@ int wl128x_cmd_general_parms(struct wl1271 *wl) if (!wl->nvs) return -ENODEV; + if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) { + wl1271_warning("FEM index from ini out of bounds"); + return -EINVAL; + } + gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL); if (!gen_parms) return -ENOMEM; @@ -186,6 +203,12 @@ int wl128x_cmd_general_parms(struct wl1271 *wl) gp->tx_bip_fem_manufacturer = gen_parms->general_params.tx_bip_fem_manufacturer; + if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) { + wl1271_warning("FEM index from FW out of bounds"); + ret = -EINVAL; + goto out; + } + wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n", answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer); @@ -358,7 +381,8 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask) return 0; } -int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 role_type, u8 *role_id) +int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 *addr, u8 role_type, + u8 *role_id) { struct wl12xx_cmd_role_enable *cmd; int ret; @@ -381,7 +405,7 @@ int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 role_type, u8 *role_id) goto out_free; } - memcpy(cmd->mac_address, wl->mac_addr, ETH_ALEN); + memcpy(cmd->mac_address, addr, ETH_ALEN); cmd->role_type = role_type; ret = wl1271_cmd_send(wl, CMD_ROLE_ENABLE, cmd, sizeof(*cmd), 0); @@ -433,37 +457,41 @@ out: return ret; } -static int wl12xx_allocate_link(struct wl1271 *wl, u8 *hlid) +int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid) { u8 link = find_first_zero_bit(wl->links_map, WL12XX_MAX_LINKS); if (link >= WL12XX_MAX_LINKS) return -EBUSY; __set_bit(link, wl->links_map); + __set_bit(link, wlvif->links_map); *hlid = link; return 0; } -static void wl12xx_free_link(struct wl1271 *wl, u8 *hlid) +void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid) { if (*hlid == WL12XX_INVALID_LINK_ID) return; __clear_bit(*hlid, wl->links_map); + __clear_bit(*hlid, wlvif->links_map); *hlid = WL12XX_INVALID_LINK_ID; } -static int wl12xx_get_new_session_id(struct wl1271 *wl) +static int wl12xx_get_new_session_id(struct wl1271 *wl, + struct wl12xx_vif *wlvif) { - if (wl->session_counter >= SESSION_COUNTER_MAX) - wl->session_counter = 0; + if (wlvif->session_counter >= SESSION_COUNTER_MAX) + wlvif->session_counter = 0; - wl->session_counter++; + wlvif->session_counter++; - return wl->session_counter; + return wlvif->session_counter; } -int wl12xx_cmd_role_start_dev(struct wl1271 *wl) +static int wl12xx_cmd_role_start_dev(struct wl1271 *wl, + struct wl12xx_vif *wlvif) { struct wl12xx_cmd_role_start *cmd; int ret; @@ -474,20 +502,20 @@ int wl12xx_cmd_role_start_dev(struct wl1271 *wl) goto out; } - wl1271_debug(DEBUG_CMD, "cmd role start dev %d", wl->dev_role_id); + wl1271_debug(DEBUG_CMD, "cmd role start dev %d", wlvif->dev_role_id); - cmd->role_id = wl->dev_role_id; - if (wl->band == IEEE80211_BAND_5GHZ) + cmd->role_id = wlvif->dev_role_id; + if (wlvif->band == IEEE80211_BAND_5GHZ) cmd->band = WL12XX_BAND_5GHZ; - cmd->channel = wl->channel; + cmd->channel = wlvif->channel; - if (wl->dev_hlid == WL12XX_INVALID_LINK_ID) { - ret = wl12xx_allocate_link(wl, &wl->dev_hlid); + if (wlvif->dev_hlid == WL12XX_INVALID_LINK_ID) { + ret = wl12xx_allocate_link(wl, wlvif, &wlvif->dev_hlid); if (ret) goto out_free; } - cmd->device.hlid = wl->dev_hlid; - cmd->device.session = wl->session_counter; + cmd->device.hlid = wlvif->dev_hlid; + cmd->device.session = wlvif->session_counter; wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d", cmd->role_id, cmd->device.hlid, cmd->device.session); @@ -502,9 +530,7 @@ int wl12xx_cmd_role_start_dev(struct wl1271 *wl) err_hlid: /* clear links on error */ - __clear_bit(wl->dev_hlid, wl->links_map); - wl->dev_hlid = WL12XX_INVALID_LINK_ID; - + wl12xx_free_link(wl, wlvif, &wlvif->dev_hlid); out_free: kfree(cmd); @@ -513,12 +539,13 @@ out: return ret; } -int wl12xx_cmd_role_stop_dev(struct wl1271 *wl) +static int wl12xx_cmd_role_stop_dev(struct wl1271 *wl, + struct wl12xx_vif *wlvif) { struct wl12xx_cmd_role_stop *cmd; int ret; - if (WARN_ON(wl->dev_hlid == WL12XX_INVALID_LINK_ID)) + if (WARN_ON(wlvif->dev_hlid == WL12XX_INVALID_LINK_ID)) return -EINVAL; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); @@ -529,7 +556,7 @@ int wl12xx_cmd_role_stop_dev(struct wl1271 *wl) wl1271_debug(DEBUG_CMD, "cmd role stop dev"); - cmd->role_id = wl->dev_role_id; + cmd->role_id = wlvif->dev_role_id; cmd->disc_type = DISCONNECT_IMMEDIATE; cmd->reason = cpu_to_le16(WLAN_REASON_UNSPECIFIED); @@ -545,7 +572,7 @@ int wl12xx_cmd_role_stop_dev(struct wl1271 *wl) goto out_free; } - wl12xx_free_link(wl, &wl->dev_hlid); + wl12xx_free_link(wl, wlvif, &wlvif->dev_hlid); out_free: kfree(cmd); @@ -554,8 +581,9 @@ out: return ret; } -int wl12xx_cmd_role_start_sta(struct wl1271 *wl) +int wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif) { + struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); struct wl12xx_cmd_role_start *cmd; int ret; @@ -565,33 +593,33 @@ int wl12xx_cmd_role_start_sta(struct wl1271 *wl) goto out; } - wl1271_debug(DEBUG_CMD, "cmd role start sta %d", wl->role_id); + wl1271_debug(DEBUG_CMD, "cmd role start sta %d", wlvif->role_id); - cmd->role_id = wl->role_id; - if (wl->band == IEEE80211_BAND_5GHZ) + cmd->role_id = wlvif->role_id; + if (wlvif->band == IEEE80211_BAND_5GHZ) cmd->band = WL12XX_BAND_5GHZ; - cmd->channel = wl->channel; - cmd->sta.basic_rate_set = cpu_to_le32(wl->basic_rate_set); - cmd->sta.beacon_interval = cpu_to_le16(wl->beacon_int); + cmd->channel = wlvif->channel; + cmd->sta.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set); + cmd->sta.beacon_interval = cpu_to_le16(wlvif->beacon_int); cmd->sta.ssid_type = WL12XX_SSID_TYPE_ANY; - cmd->sta.ssid_len = wl->ssid_len; - memcpy(cmd->sta.ssid, wl->ssid, wl->ssid_len); - memcpy(cmd->sta.bssid, wl->bssid, ETH_ALEN); - cmd->sta.local_rates = cpu_to_le32(wl->rate_set); + cmd->sta.ssid_len = wlvif->ssid_len; + memcpy(cmd->sta.ssid, wlvif->ssid, wlvif->ssid_len); + memcpy(cmd->sta.bssid, vif->bss_conf.bssid, ETH_ALEN); + cmd->sta.local_rates = cpu_to_le32(wlvif->rate_set); - if (wl->sta_hlid == WL12XX_INVALID_LINK_ID) { - ret = wl12xx_allocate_link(wl, &wl->sta_hlid); + if (wlvif->sta.hlid == WL12XX_INVALID_LINK_ID) { + ret = wl12xx_allocate_link(wl, wlvif, &wlvif->sta.hlid); if (ret) goto out_free; } - cmd->sta.hlid = wl->sta_hlid; - cmd->sta.session = wl12xx_get_new_session_id(wl); - cmd->sta.remote_rates = cpu_to_le32(wl->rate_set); + cmd->sta.hlid = wlvif->sta.hlid; + cmd->sta.session = wl12xx_get_new_session_id(wl, wlvif); + cmd->sta.remote_rates = cpu_to_le32(wlvif->rate_set); wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d " "basic_rate_set: 0x%x, remote_rates: 0x%x", - wl->role_id, cmd->sta.hlid, cmd->sta.session, - wl->basic_rate_set, wl->rate_set); + wlvif->role_id, cmd->sta.hlid, cmd->sta.session, + wlvif->basic_rate_set, wlvif->rate_set); ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0); if (ret < 0) { @@ -603,7 +631,7 @@ int wl12xx_cmd_role_start_sta(struct wl1271 *wl) err_hlid: /* clear links on error. */ - wl12xx_free_link(wl, &wl->sta_hlid); + wl12xx_free_link(wl, wlvif, &wlvif->sta.hlid); out_free: kfree(cmd); @@ -613,12 +641,12 @@ out: } /* use this function to stop ibss as well */ -int wl12xx_cmd_role_stop_sta(struct wl1271 *wl) +int wl12xx_cmd_role_stop_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif) { struct wl12xx_cmd_role_stop *cmd; int ret; - if (WARN_ON(wl->sta_hlid == WL12XX_INVALID_LINK_ID)) + if (WARN_ON(wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)) return -EINVAL; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); @@ -627,9 +655,9 @@ int wl12xx_cmd_role_stop_sta(struct wl1271 *wl) goto out; } - wl1271_debug(DEBUG_CMD, "cmd role stop sta %d", wl->role_id); + wl1271_debug(DEBUG_CMD, "cmd role stop sta %d", wlvif->role_id); - cmd->role_id = wl->role_id; + cmd->role_id = wlvif->role_id; cmd->disc_type = DISCONNECT_IMMEDIATE; cmd->reason = cpu_to_le16(WLAN_REASON_UNSPECIFIED); @@ -639,7 +667,7 @@ int wl12xx_cmd_role_stop_sta(struct wl1271 *wl) goto out_free; } - wl12xx_free_link(wl, &wl->sta_hlid); + wl12xx_free_link(wl, wlvif, &wlvif->sta.hlid); out_free: kfree(cmd); @@ -648,16 +676,17 @@ out: return ret; } -int wl12xx_cmd_role_start_ap(struct wl1271 *wl) +int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif) { struct wl12xx_cmd_role_start *cmd; - struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf; + struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; int ret; - wl1271_debug(DEBUG_CMD, "cmd role start ap %d", wl->role_id); + wl1271_debug(DEBUG_CMD, "cmd role start ap %d", wlvif->role_id); /* trying to use hidden SSID with an old hostapd version */ - if (wl->ssid_len == 0 && !bss_conf->hidden_ssid) { + if (wlvif->ssid_len == 0 && !bss_conf->hidden_ssid) { wl1271_error("got a null SSID from beacon/bss"); ret = -EINVAL; goto out; @@ -669,30 +698,30 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl) goto out; } - ret = wl12xx_allocate_link(wl, &wl->ap_global_hlid); + ret = wl12xx_allocate_link(wl, wlvif, &wlvif->ap.global_hlid); if (ret < 0) goto out_free; - ret = wl12xx_allocate_link(wl, &wl->ap_bcast_hlid); + ret = wl12xx_allocate_link(wl, wlvif, &wlvif->ap.bcast_hlid); if (ret < 0) goto out_free_global; - cmd->role_id = wl->role_id; + cmd->role_id = wlvif->role_id; cmd->ap.aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period); cmd->ap.bss_index = WL1271_AP_BSS_INDEX; - cmd->ap.global_hlid = wl->ap_global_hlid; - cmd->ap.broadcast_hlid = wl->ap_bcast_hlid; - cmd->ap.basic_rate_set = cpu_to_le32(wl->basic_rate_set); - cmd->ap.beacon_interval = cpu_to_le16(wl->beacon_int); + cmd->ap.global_hlid = wlvif->ap.global_hlid; + cmd->ap.broadcast_hlid = wlvif->ap.bcast_hlid; + cmd->ap.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set); + cmd->ap.beacon_interval = cpu_to_le16(wlvif->beacon_int); cmd->ap.dtim_interval = bss_conf->dtim_period; cmd->ap.beacon_expiry = WL1271_AP_DEF_BEACON_EXP; - cmd->channel = wl->channel; + cmd->channel = wlvif->channel; if (!bss_conf->hidden_ssid) { /* take the SSID from the beacon for backward compatibility */ cmd->ap.ssid_type = WL12XX_SSID_TYPE_PUBLIC; - cmd->ap.ssid_len = wl->ssid_len; - memcpy(cmd->ap.ssid, wl->ssid, wl->ssid_len); + cmd->ap.ssid_len = wlvif->ssid_len; + memcpy(cmd->ap.ssid, wlvif->ssid, wlvif->ssid_len); } else { cmd->ap.ssid_type = WL12XX_SSID_TYPE_HIDDEN; cmd->ap.ssid_len = bss_conf->ssid_len; @@ -701,7 +730,7 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl) cmd->ap.local_rates = cpu_to_le32(0xffffffff); - switch (wl->band) { + switch (wlvif->band) { case IEEE80211_BAND_2GHZ: cmd->band = RADIO_BAND_2_4GHZ; break; @@ -709,7 +738,7 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl) cmd->band = RADIO_BAND_5GHZ; break; default: - wl1271_warning("ap start - unknown band: %d", (int)wl->band); + wl1271_warning("ap start - unknown band: %d", (int)wlvif->band); cmd->band = RADIO_BAND_2_4GHZ; break; } @@ -723,10 +752,10 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl) goto out_free; out_free_bcast: - wl12xx_free_link(wl, &wl->ap_bcast_hlid); + wl12xx_free_link(wl, wlvif, &wlvif->ap.bcast_hlid); out_free_global: - wl12xx_free_link(wl, &wl->ap_global_hlid); + wl12xx_free_link(wl, wlvif, &wlvif->ap.global_hlid); out_free: kfree(cmd); @@ -735,7 +764,7 @@ out: return ret; } -int wl12xx_cmd_role_stop_ap(struct wl1271 *wl) +int wl12xx_cmd_role_stop_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif) { struct wl12xx_cmd_role_stop *cmd; int ret; @@ -746,9 +775,9 @@ int wl12xx_cmd_role_stop_ap(struct wl1271 *wl) goto out; } - wl1271_debug(DEBUG_CMD, "cmd role stop ap %d", wl->role_id); + wl1271_debug(DEBUG_CMD, "cmd role stop ap %d", wlvif->role_id); - cmd->role_id = wl->role_id; + cmd->role_id = wlvif->role_id; ret = wl1271_cmd_send(wl, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0); if (ret < 0) { @@ -756,8 +785,8 @@ int wl12xx_cmd_role_stop_ap(struct wl1271 *wl) goto out_free; } - wl12xx_free_link(wl, &wl->ap_bcast_hlid); - wl12xx_free_link(wl, &wl->ap_global_hlid); + wl12xx_free_link(wl, wlvif, &wlvif->ap.bcast_hlid); + wl12xx_free_link(wl, wlvif, &wlvif->ap.global_hlid); out_free: kfree(cmd); @@ -766,10 +795,11 @@ out: return ret; } -int wl12xx_cmd_role_start_ibss(struct wl1271 *wl) +int wl12xx_cmd_role_start_ibss(struct wl1271 *wl, struct wl12xx_vif *wlvif) { + struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); struct wl12xx_cmd_role_start *cmd; - struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf; + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; int ret; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); @@ -778,35 +808,36 @@ int wl12xx_cmd_role_start_ibss(struct wl1271 *wl) goto out; } - wl1271_debug(DEBUG_CMD, "cmd role start ibss %d", wl->role_id); + wl1271_debug(DEBUG_CMD, "cmd role start ibss %d", wlvif->role_id); - cmd->role_id = wl->role_id; - if (wl->band == IEEE80211_BAND_5GHZ) + cmd->role_id = wlvif->role_id; + if (wlvif->band == IEEE80211_BAND_5GHZ) cmd->band = WL12XX_BAND_5GHZ; - cmd->channel = wl->channel; - cmd->ibss.basic_rate_set = cpu_to_le32(wl->basic_rate_set); - cmd->ibss.beacon_interval = cpu_to_le16(wl->beacon_int); + cmd->channel = wlvif->channel; + cmd->ibss.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set); + cmd->ibss.beacon_interval = cpu_to_le16(wlvif->beacon_int); cmd->ibss.dtim_interval = bss_conf->dtim_period; cmd->ibss.ssid_type = WL12XX_SSID_TYPE_ANY; - cmd->ibss.ssid_len = wl->ssid_len; - memcpy(cmd->ibss.ssid, wl->ssid, wl->ssid_len); - memcpy(cmd->ibss.bssid, wl->bssid, ETH_ALEN); - cmd->sta.local_rates = cpu_to_le32(wl->rate_set); + cmd->ibss.ssid_len = wlvif->ssid_len; + memcpy(cmd->ibss.ssid, wlvif->ssid, wlvif->ssid_len); + memcpy(cmd->ibss.bssid, vif->bss_conf.bssid, ETH_ALEN); + cmd->sta.local_rates = cpu_to_le32(wlvif->rate_set); - if (wl->sta_hlid == WL12XX_INVALID_LINK_ID) { - ret = wl12xx_allocate_link(wl, &wl->sta_hlid); + if (wlvif->sta.hlid == WL12XX_INVALID_LINK_ID) { + ret = wl12xx_allocate_link(wl, wlvif, &wlvif->sta.hlid); if (ret) goto out_free; } - cmd->ibss.hlid = wl->sta_hlid; - cmd->ibss.remote_rates = cpu_to_le32(wl->rate_set); + cmd->ibss.hlid = wlvif->sta.hlid; + cmd->ibss.remote_rates = cpu_to_le32(wlvif->rate_set); wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d " "basic_rate_set: 0x%x, remote_rates: 0x%x", - wl->role_id, cmd->sta.hlid, cmd->sta.session, - wl->basic_rate_set, wl->rate_set); + wlvif->role_id, cmd->sta.hlid, cmd->sta.session, + wlvif->basic_rate_set, wlvif->rate_set); - wl1271_debug(DEBUG_CMD, "wl->bssid = %pM", wl->bssid); + wl1271_debug(DEBUG_CMD, "vif->bss_conf.bssid = %pM", + vif->bss_conf.bssid); ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0); if (ret < 0) { @@ -818,7 +849,7 @@ int wl12xx_cmd_role_start_ibss(struct wl1271 *wl) err_hlid: /* clear links on error. */ - wl12xx_free_link(wl, &wl->sta_hlid); + wl12xx_free_link(wl, wlvif, &wlvif->sta.hlid); out_free: kfree(cmd); @@ -962,7 +993,8 @@ out: return ret; } -int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode) +int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u8 ps_mode) { struct wl1271_cmd_ps_params *ps_params = NULL; int ret = 0; @@ -975,7 +1007,7 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode) goto out; } - ps_params->role_id = wl->role_id; + ps_params->role_id = wlvif->role_id; ps_params->ps_mode = ps_mode; ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params, @@ -1030,7 +1062,7 @@ out: return ret; } -int wl1271_cmd_build_null_data(struct wl1271 *wl) +int wl12xx_cmd_build_null_data(struct wl1271 *wl, struct wl12xx_vif *wlvif) { struct sk_buff *skb = NULL; int size; @@ -1038,11 +1070,12 @@ int wl1271_cmd_build_null_data(struct wl1271 *wl) int ret = -ENOMEM; - if (wl->bss_type == BSS_TYPE_IBSS) { + if (wlvif->bss_type == BSS_TYPE_IBSS) { size = sizeof(struct wl12xx_null_data_template); ptr = NULL; } else { - skb = ieee80211_nullfunc_get(wl->hw, wl->vif); + skb = ieee80211_nullfunc_get(wl->hw, + wl12xx_wlvif_to_vif(wlvif)); if (!skb) goto out; size = skb->len; @@ -1050,7 +1083,7 @@ int wl1271_cmd_build_null_data(struct wl1271 *wl) } ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, ptr, size, 0, - wl->basic_rate); + wlvif->basic_rate); out: dev_kfree_skb(skb); @@ -1061,19 +1094,21 @@ out: } -int wl1271_cmd_build_klv_null_data(struct wl1271 *wl) +int wl12xx_cmd_build_klv_null_data(struct wl1271 *wl, + struct wl12xx_vif *wlvif) { + struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); struct sk_buff *skb = NULL; int ret = -ENOMEM; - skb = ieee80211_nullfunc_get(wl->hw, wl->vif); + skb = ieee80211_nullfunc_get(wl->hw, vif); if (!skb) goto out; ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV, skb->data, skb->len, CMD_TEMPL_KLV_IDX_NULL_DATA, - wl->basic_rate); + wlvif->basic_rate); out: dev_kfree_skb(skb); @@ -1084,32 +1119,35 @@ out: } -int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid) +int wl1271_cmd_build_ps_poll(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u16 aid) { + struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); struct sk_buff *skb; int ret = 0; - skb = ieee80211_pspoll_get(wl->hw, wl->vif); + skb = ieee80211_pspoll_get(wl->hw, vif); if (!skb) goto out; ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, skb->data, - skb->len, 0, wl->basic_rate_set); + skb->len, 0, wlvif->basic_rate_set); out: dev_kfree_skb(skb); return ret; } -int wl1271_cmd_build_probe_req(struct wl1271 *wl, +int wl1271_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, const u8 *ssid, size_t ssid_len, const u8 *ie, size_t ie_len, u8 band) { + struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); struct sk_buff *skb; int ret; u32 rate; - skb = ieee80211_probereq_get(wl->hw, wl->vif, ssid, ssid_len, + skb = ieee80211_probereq_get(wl->hw, vif, ssid, ssid_len, ie, ie_len); if (!skb) { ret = -ENOMEM; @@ -1118,7 +1156,7 @@ int wl1271_cmd_build_probe_req(struct wl1271 *wl, wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len); - rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]); + rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); if (band == IEEE80211_BAND_2GHZ) ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, skb->data, skb->len, 0, rate); @@ -1132,20 +1170,22 @@ out: } struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, + struct wl12xx_vif *wlvif, struct sk_buff *skb) { + struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); int ret; u32 rate; if (!skb) - skb = ieee80211_ap_probereq_get(wl->hw, wl->vif); + skb = ieee80211_ap_probereq_get(wl->hw, vif); if (!skb) goto out; wl1271_dump(DEBUG_SCAN, "AP PROBE REQ: ", skb->data, skb->len); - rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[wl->band]); - if (wl->band == IEEE80211_BAND_2GHZ) + rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[wlvif->band]); + if (wlvif->band == IEEE80211_BAND_2GHZ) ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, skb->data, skb->len, 0, rate); else @@ -1159,9 +1199,11 @@ out: return skb; } -int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, __be32 ip_addr) +int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif, + __be32 ip_addr) { int ret; + struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); struct wl12xx_arp_rsp_template tmpl; struct ieee80211_hdr_3addr *hdr; struct arphdr *arp_hdr; @@ -1173,8 +1215,8 @@ int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, __be32 ip_addr) hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA | IEEE80211_FCTL_TODS); - memcpy(hdr->addr1, wl->vif->bss_conf.bssid, ETH_ALEN); - memcpy(hdr->addr2, wl->vif->addr, ETH_ALEN); + memcpy(hdr->addr1, vif->bss_conf.bssid, ETH_ALEN); + memcpy(hdr->addr2, vif->addr, ETH_ALEN); memset(hdr->addr3, 0xff, ETH_ALEN); /* llc layer */ @@ -1190,25 +1232,26 @@ int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, __be32 ip_addr) arp_hdr->ar_op = cpu_to_be16(ARPOP_REPLY); /* arp payload */ - memcpy(tmpl.sender_hw, wl->vif->addr, ETH_ALEN); + memcpy(tmpl.sender_hw, vif->addr, ETH_ALEN); tmpl.sender_ip = ip_addr; ret = wl1271_cmd_template_set(wl, CMD_TEMPL_ARP_RSP, &tmpl, sizeof(tmpl), 0, - wl->basic_rate); + wlvif->basic_rate); return ret; } -int wl1271_build_qos_null_data(struct wl1271 *wl) +int wl1271_build_qos_null_data(struct wl1271 *wl, struct ieee80211_vif *vif) { + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); struct ieee80211_qos_hdr template; memset(&template, 0, sizeof(template)); - memcpy(template.addr1, wl->bssid, ETH_ALEN); - memcpy(template.addr2, wl->mac_addr, ETH_ALEN); - memcpy(template.addr3, wl->bssid, ETH_ALEN); + memcpy(template.addr1, vif->bss_conf.bssid, ETH_ALEN); + memcpy(template.addr2, vif->addr, ETH_ALEN); + memcpy(template.addr3, vif->bss_conf.bssid, ETH_ALEN); template.frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_NULLFUNC | @@ -1219,7 +1262,7 @@ int wl1271_build_qos_null_data(struct wl1271 *wl) return wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, &template, sizeof(template), 0, - wl->basic_rate); + wlvif->basic_rate); } int wl12xx_cmd_set_default_wep_key(struct wl1271 *wl, u8 id, u8 hlid) @@ -1253,7 +1296,8 @@ out: return ret; } -int wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, +int wl1271_cmd_set_sta_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u16 action, u8 id, u8 key_type, u8 key_size, const u8 *key, const u8 *addr, u32 tx_seq_32, u16 tx_seq_16) { @@ -1261,7 +1305,7 @@ int wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, int ret = 0; /* hlid might have already been deleted */ - if (wl->sta_hlid == WL12XX_INVALID_LINK_ID) + if (wlvif->sta.hlid == WL12XX_INVALID_LINK_ID) return 0; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); @@ -1270,7 +1314,7 @@ int wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, goto out; } - cmd->hlid = wl->sta_hlid; + cmd->hlid = wlvif->sta.hlid; if (key_type == KEY_WEP) cmd->lid_key_type = WEP_DEFAULT_LID_TYPE; @@ -1321,9 +1365,10 @@ out: * TODO: merge with sta/ibss into 1 set_key function. * note there are slight diffs */ -int wl1271_cmd_set_ap_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, - u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32, - u16 tx_seq_16) +int wl1271_cmd_set_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u16 action, u8 id, u8 key_type, + u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32, + u16 tx_seq_16) { struct wl1271_cmd_set_keys *cmd; int ret = 0; @@ -1333,7 +1378,7 @@ int wl1271_cmd_set_ap_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, if (!cmd) return -ENOMEM; - if (hlid == wl->ap_bcast_hlid) { + if (hlid == wlvif->ap.bcast_hlid) { if (key_type == KEY_WEP) lid_type = WEP_DEFAULT_LID_TYPE; else @@ -1411,7 +1456,8 @@ out: return ret; } -int wl12xx_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid) +int wl12xx_cmd_add_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif, + struct ieee80211_sta *sta, u8 hlid) { struct wl12xx_cmd_add_peer *cmd; int i, ret; @@ -1438,13 +1484,13 @@ int wl12xx_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid) else cmd->psd_type[i] = WL1271_PSD_LEGACY; - sta_rates = sta->supp_rates[wl->band]; + sta_rates = sta->supp_rates[wlvif->band]; if (sta->ht_cap.ht_supported) sta_rates |= sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET; cmd->supported_rates = cpu_to_le32(wl1271_tx_enabled_rates_get(wl, sta_rates, - wl->band)); + wlvif->band)); wl1271_debug(DEBUG_CMD, "new peer rates=0x%x queues=0x%x", cmd->supported_rates, sta->uapsd_queues); @@ -1584,12 +1630,13 @@ out: return ret; } -static int wl12xx_cmd_roc(struct wl1271 *wl, u8 role_id) +static int wl12xx_cmd_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u8 role_id) { struct wl12xx_cmd_roc *cmd; int ret = 0; - wl1271_debug(DEBUG_CMD, "cmd roc %d (%d)", wl->channel, role_id); + wl1271_debug(DEBUG_CMD, "cmd roc %d (%d)", wlvif->channel, role_id); if (WARN_ON(role_id == WL12XX_INVALID_ROLE_ID)) return -EINVAL; @@ -1601,8 +1648,8 @@ static int wl12xx_cmd_roc(struct wl1271 *wl, u8 role_id) } cmd->role_id = role_id; - cmd->channel = wl->channel; - switch (wl->band) { + cmd->channel = wlvif->channel; + switch (wlvif->band) { case IEEE80211_BAND_2GHZ: cmd->band = RADIO_BAND_2_4GHZ; break; @@ -1610,7 +1657,7 @@ static int wl12xx_cmd_roc(struct wl1271 *wl, u8 role_id) cmd->band = RADIO_BAND_5GHZ; break; default: - wl1271_error("roc - unknown band: %d", (int)wl->band); + wl1271_error("roc - unknown band: %d", (int)wlvif->band); ret = -EINVAL; goto out_free; } @@ -1657,14 +1704,14 @@ out: return ret; } -int wl12xx_roc(struct wl1271 *wl, u8 role_id) +int wl12xx_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id) { int ret = 0; if (WARN_ON(test_bit(role_id, wl->roc_map))) return 0; - ret = wl12xx_cmd_roc(wl, role_id); + ret = wl12xx_cmd_roc(wl, wlvif, role_id); if (ret < 0) goto out; @@ -1753,3 +1800,50 @@ out_free: out: return ret; } + +/* start dev role and roc on its channel */ +int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif) +{ + int ret; + + if (WARN_ON(!(wlvif->bss_type == BSS_TYPE_STA_BSS || + wlvif->bss_type == BSS_TYPE_IBSS))) + return -EINVAL; + + ret = wl12xx_cmd_role_start_dev(wl, wlvif); + if (ret < 0) + goto out; + + ret = wl12xx_roc(wl, wlvif, wlvif->dev_role_id); + if (ret < 0) + goto out_stop; + + return 0; + +out_stop: + wl12xx_cmd_role_stop_dev(wl, wlvif); +out: + return ret; +} + +/* croc dev hlid, and stop the role */ +int wl12xx_stop_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif) +{ + int ret; + + if (WARN_ON(!(wlvif->bss_type == BSS_TYPE_STA_BSS || + wlvif->bss_type == BSS_TYPE_IBSS))) + return -EINVAL; + + if (test_bit(wlvif->dev_role_id, wl->roc_map)) { + ret = wl12xx_croc(wl, wlvif->dev_role_id); + if (ret < 0) + goto out; + } + + ret = wl12xx_cmd_role_stop_dev(wl, wlvif); + if (ret < 0) + goto out; +out: + return ret; +} diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h index b7bd42769aa7..3f7d0b93c24d 100644 --- a/drivers/net/wireless/wl12xx/cmd.h +++ b/drivers/net/wireless/wl12xx/cmd.h @@ -36,45 +36,54 @@ int wl128x_cmd_general_parms(struct wl1271 *wl); int wl1271_cmd_radio_parms(struct wl1271 *wl); int wl128x_cmd_radio_parms(struct wl1271 *wl); int wl1271_cmd_ext_radio_parms(struct wl1271 *wl); -int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 role_type, u8 *role_id); +int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 *addr, u8 role_type, + u8 *role_id); int wl12xx_cmd_role_disable(struct wl1271 *wl, u8 *role_id); -int wl12xx_cmd_role_start_dev(struct wl1271 *wl); -int wl12xx_cmd_role_stop_dev(struct wl1271 *wl); -int wl12xx_cmd_role_start_sta(struct wl1271 *wl); -int wl12xx_cmd_role_stop_sta(struct wl1271 *wl); -int wl12xx_cmd_role_start_ap(struct wl1271 *wl); -int wl12xx_cmd_role_stop_ap(struct wl1271 *wl); -int wl12xx_cmd_role_start_ibss(struct wl1271 *wl); +int wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif); +int wl12xx_cmd_role_stop_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif); +int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif); +int wl12xx_cmd_role_stop_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif); +int wl12xx_cmd_role_start_ibss(struct wl1271 *wl, struct wl12xx_vif *wlvif); +int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif); +int wl12xx_stop_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif); int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer); int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len); int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len); int wl1271_cmd_data_path(struct wl1271 *wl, bool enable); -int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode); +int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u8 ps_mode); int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer, size_t len); int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, void *buf, size_t buf_len, int index, u32 rates); -int wl1271_cmd_build_null_data(struct wl1271 *wl); -int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid); -int wl1271_cmd_build_probe_req(struct wl1271 *wl, +int wl12xx_cmd_build_null_data(struct wl1271 *wl, struct wl12xx_vif *wlvif); +int wl1271_cmd_build_ps_poll(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u16 aid); +int wl1271_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, const u8 *ssid, size_t ssid_len, const u8 *ie, size_t ie_len, u8 band); struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, + struct wl12xx_vif *wlvif, struct sk_buff *skb); -int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, __be32 ip_addr); -int wl1271_build_qos_null_data(struct wl1271 *wl); -int wl1271_cmd_build_klv_null_data(struct wl1271 *wl); +int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif, + __be32 ip_addr); +int wl1271_build_qos_null_data(struct wl1271 *wl, struct ieee80211_vif *vif); +int wl12xx_cmd_build_klv_null_data(struct wl1271 *wl, + struct wl12xx_vif *wlvif); int wl12xx_cmd_set_default_wep_key(struct wl1271 *wl, u8 id, u8 hlid); -int wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, +int wl1271_cmd_set_sta_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u16 action, u8 id, u8 key_type, u8 key_size, const u8 *key, const u8 *addr, u32 tx_seq_32, u16 tx_seq_16); -int wl1271_cmd_set_ap_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, +int wl1271_cmd_set_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u16 action, u8 id, u8 key_type, u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32, u16 tx_seq_16); int wl12xx_cmd_set_peer_state(struct wl1271 *wl, u8 hlid); -int wl12xx_roc(struct wl1271 *wl, u8 role_id); +int wl12xx_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id); int wl12xx_croc(struct wl1271 *wl, u8 role_id); -int wl12xx_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid); +int wl12xx_cmd_add_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif, + struct ieee80211_sta *sta, u8 hlid); int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid); int wl12xx_cmd_config_fwlog(struct wl1271 *wl); int wl12xx_cmd_start_fwlog(struct wl1271 *wl); @@ -82,6 +91,9 @@ int wl12xx_cmd_stop_fwlog(struct wl1271 *wl); int wl12xx_cmd_channel_switch(struct wl1271 *wl, struct ieee80211_channel_switch *ch_switch); int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl); +int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u8 *hlid); +void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid); enum wl1271_commands { CMD_INTERROGATE = 1, /*use this to read information elements*/ diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h index 04bb8fbf93f9..1bcfb017058d 100644 --- a/drivers/net/wireless/wl12xx/conf.h +++ b/drivers/net/wireless/wl12xx/conf.h @@ -440,6 +440,10 @@ struct conf_rx_settings { CONF_HW_BIT_RATE_36MBPS | CONF_HW_BIT_RATE_48MBPS | \ CONF_HW_BIT_RATE_54MBPS) +#define CONF_TX_CCK_RATES (CONF_HW_BIT_RATE_1MBPS | \ + CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS | \ + CONF_HW_BIT_RATE_11MBPS) + #define CONF_TX_OFDM_RATES (CONF_HW_BIT_RATE_6MBPS | \ CONF_HW_BIT_RATE_12MBPS | CONF_HW_BIT_RATE_24MBPS | \ CONF_HW_BIT_RATE_36MBPS | CONF_HW_BIT_RATE_48MBPS | \ diff --git a/drivers/net/wireless/wl12xx/debug.h b/drivers/net/wireless/wl12xx/debug.h new file mode 100644 index 000000000000..b85fd8c41e8f --- /dev/null +++ b/drivers/net/wireless/wl12xx/debug.h @@ -0,0 +1,101 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2011 Texas Instruments. All rights reserved. + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Luciano Coelho <coelho@ti.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __DEBUG_H__ +#define __DEBUG_H__ + +#include <linux/bitops.h> +#include <linux/printk.h> + +#define DRIVER_NAME "wl12xx" +#define DRIVER_PREFIX DRIVER_NAME ": " + +enum { + DEBUG_NONE = 0, + DEBUG_IRQ = BIT(0), + DEBUG_SPI = BIT(1), + DEBUG_BOOT = BIT(2), + DEBUG_MAILBOX = BIT(3), + DEBUG_TESTMODE = BIT(4), + DEBUG_EVENT = BIT(5), + DEBUG_TX = BIT(6), + DEBUG_RX = BIT(7), + DEBUG_SCAN = BIT(8), + DEBUG_CRYPT = BIT(9), + DEBUG_PSM = BIT(10), + DEBUG_MAC80211 = BIT(11), + DEBUG_CMD = BIT(12), + DEBUG_ACX = BIT(13), + DEBUG_SDIO = BIT(14), + DEBUG_FILTERS = BIT(15), + DEBUG_ADHOC = BIT(16), + DEBUG_AP = BIT(17), + DEBUG_MASTER = (DEBUG_ADHOC | DEBUG_AP), + DEBUG_ALL = ~0, +}; + +extern u32 wl12xx_debug_level; + +#define DEBUG_DUMP_LIMIT 1024 + +#define wl1271_error(fmt, arg...) \ + pr_err(DRIVER_PREFIX "ERROR " fmt "\n", ##arg) + +#define wl1271_warning(fmt, arg...) \ + pr_warning(DRIVER_PREFIX "WARNING " fmt "\n", ##arg) + +#define wl1271_notice(fmt, arg...) \ + pr_info(DRIVER_PREFIX fmt "\n", ##arg) + +#define wl1271_info(fmt, arg...) \ + pr_info(DRIVER_PREFIX fmt "\n", ##arg) + +#define wl1271_debug(level, fmt, arg...) \ + do { \ + if (level & wl12xx_debug_level) \ + pr_debug(DRIVER_PREFIX fmt "\n", ##arg); \ + } while (0) + +/* TODO: use pr_debug_hex_dump when it becomes available */ +#define wl1271_dump(level, prefix, buf, len) \ + do { \ + if (level & wl12xx_debug_level) \ + print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ + DUMP_PREFIX_OFFSET, 16, 1, \ + buf, \ + min_t(size_t, len, DEBUG_DUMP_LIMIT), \ + 0); \ + } while (0) + +#define wl1271_dump_ascii(level, prefix, buf, len) \ + do { \ + if (level & wl12xx_debug_level) \ + print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ + DUMP_PREFIX_OFFSET, 16, 1, \ + buf, \ + min_t(size_t, len, DEBUG_DUMP_LIMIT), \ + true); \ + } while (0) + +#endif /* __DEBUG_H__ */ diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c index 3999fd528302..15eb3a9c30ca 100644 --- a/drivers/net/wireless/wl12xx/debugfs.c +++ b/drivers/net/wireless/wl12xx/debugfs.c @@ -27,6 +27,7 @@ #include <linux/slab.h> #include "wl12xx.h" +#include "debug.h" #include "acx.h" #include "ps.h" #include "io.h" @@ -316,12 +317,19 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf, { struct wl1271 *wl = file->private_data; int res = 0; - char buf[1024]; + ssize_t ret; + char *buf; + +#define DRIVER_STATE_BUF_LEN 1024 + + buf = kmalloc(DRIVER_STATE_BUF_LEN, GFP_KERNEL); + if (!buf) + return -ENOMEM; mutex_lock(&wl->mutex); #define DRIVER_STATE_PRINT(x, fmt) \ - (res += scnprintf(buf + res, sizeof(buf) - res,\ + (res += scnprintf(buf + res, DRIVER_STATE_BUF_LEN - res,\ #x " = " fmt "\n", wl->x)) #define DRIVER_STATE_PRINT_LONG(x) DRIVER_STATE_PRINT(x, "%ld") @@ -346,29 +354,14 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf, DRIVER_STATE_PRINT_INT(tx_results_count); DRIVER_STATE_PRINT_LHEX(flags); DRIVER_STATE_PRINT_INT(tx_blocks_freed); - DRIVER_STATE_PRINT_INT(tx_security_last_seq_lsb); DRIVER_STATE_PRINT_INT(rx_counter); - DRIVER_STATE_PRINT_INT(session_counter); DRIVER_STATE_PRINT_INT(state); - DRIVER_STATE_PRINT_INT(bss_type); DRIVER_STATE_PRINT_INT(channel); - DRIVER_STATE_PRINT_HEX(rate_set); - DRIVER_STATE_PRINT_HEX(basic_rate_set); - DRIVER_STATE_PRINT_HEX(basic_rate); DRIVER_STATE_PRINT_INT(band); - DRIVER_STATE_PRINT_INT(beacon_int); - DRIVER_STATE_PRINT_INT(psm_entry_retry); - DRIVER_STATE_PRINT_INT(ps_poll_failures); DRIVER_STATE_PRINT_INT(power_level); - DRIVER_STATE_PRINT_INT(rssi_thold); - DRIVER_STATE_PRINT_INT(last_rssi_event); DRIVER_STATE_PRINT_INT(sg_enabled); DRIVER_STATE_PRINT_INT(enable_11a); DRIVER_STATE_PRINT_INT(noise); - DRIVER_STATE_PRINT_LHEX(ap_hlid_map[0]); - DRIVER_STATE_PRINT_INT(last_tx_hlid); - DRIVER_STATE_PRINT_INT(ba_support); - DRIVER_STATE_PRINT_HEX(ba_rx_bitmap); DRIVER_STATE_PRINT_HEX(ap_fw_ps_map); DRIVER_STATE_PRINT_LHEX(ap_ps_map); DRIVER_STATE_PRINT_HEX(quirks); @@ -387,10 +380,13 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf, #undef DRIVER_STATE_PRINT_LHEX #undef DRIVER_STATE_PRINT_STR #undef DRIVER_STATE_PRINT +#undef DRIVER_STATE_BUF_LEN mutex_unlock(&wl->mutex); - return simple_read_from_buffer(user_buf, count, ppos, buf, res); + ret = simple_read_from_buffer(user_buf, count, ppos, buf, res); + kfree(buf); + return ret; } static const struct file_operations driver_state_ops = { @@ -399,6 +395,115 @@ static const struct file_operations driver_state_ops = { .llseek = default_llseek, }; +static ssize_t vifs_state_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wl1271 *wl = file->private_data; + struct wl12xx_vif *wlvif; + int ret, res = 0; + const int buf_size = 4096; + char *buf; + char tmp_buf[64]; + + buf = kzalloc(buf_size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + mutex_lock(&wl->mutex); + +#define VIF_STATE_PRINT(x, fmt) \ + (res += scnprintf(buf + res, buf_size - res, \ + #x " = " fmt "\n", wlvif->x)) + +#define VIF_STATE_PRINT_LONG(x) VIF_STATE_PRINT(x, "%ld") +#define VIF_STATE_PRINT_INT(x) VIF_STATE_PRINT(x, "%d") +#define VIF_STATE_PRINT_STR(x) VIF_STATE_PRINT(x, "%s") +#define VIF_STATE_PRINT_LHEX(x) VIF_STATE_PRINT(x, "0x%lx") +#define VIF_STATE_PRINT_LLHEX(x) VIF_STATE_PRINT(x, "0x%llx") +#define VIF_STATE_PRINT_HEX(x) VIF_STATE_PRINT(x, "0x%x") + +#define VIF_STATE_PRINT_NSTR(x, len) \ + do { \ + memset(tmp_buf, 0, sizeof(tmp_buf)); \ + memcpy(tmp_buf, wlvif->x, \ + min_t(u8, len, sizeof(tmp_buf) - 1)); \ + res += scnprintf(buf + res, buf_size - res, \ + #x " = %s\n", tmp_buf); \ + } while (0) + + wl12xx_for_each_wlvif(wl, wlvif) { + VIF_STATE_PRINT_INT(role_id); + VIF_STATE_PRINT_INT(bss_type); + VIF_STATE_PRINT_LHEX(flags); + VIF_STATE_PRINT_INT(p2p); + VIF_STATE_PRINT_INT(dev_role_id); + VIF_STATE_PRINT_INT(dev_hlid); + + if (wlvif->bss_type == BSS_TYPE_STA_BSS || + wlvif->bss_type == BSS_TYPE_IBSS) { + VIF_STATE_PRINT_INT(sta.hlid); + VIF_STATE_PRINT_INT(sta.ba_rx_bitmap); + VIF_STATE_PRINT_INT(sta.basic_rate_idx); + VIF_STATE_PRINT_INT(sta.ap_rate_idx); + VIF_STATE_PRINT_INT(sta.p2p_rate_idx); + } else { + VIF_STATE_PRINT_INT(ap.global_hlid); + VIF_STATE_PRINT_INT(ap.bcast_hlid); + VIF_STATE_PRINT_LHEX(ap.sta_hlid_map[0]); + VIF_STATE_PRINT_INT(ap.mgmt_rate_idx); + VIF_STATE_PRINT_INT(ap.bcast_rate_idx); + VIF_STATE_PRINT_INT(ap.ucast_rate_idx[0]); + VIF_STATE_PRINT_INT(ap.ucast_rate_idx[1]); + VIF_STATE_PRINT_INT(ap.ucast_rate_idx[2]); + VIF_STATE_PRINT_INT(ap.ucast_rate_idx[3]); + } + VIF_STATE_PRINT_INT(last_tx_hlid); + VIF_STATE_PRINT_LHEX(links_map[0]); + VIF_STATE_PRINT_NSTR(ssid, wlvif->ssid_len); + VIF_STATE_PRINT_INT(band); + VIF_STATE_PRINT_INT(channel); + VIF_STATE_PRINT_HEX(bitrate_masks[0]); + VIF_STATE_PRINT_HEX(bitrate_masks[1]); + VIF_STATE_PRINT_HEX(basic_rate_set); + VIF_STATE_PRINT_HEX(basic_rate); + VIF_STATE_PRINT_HEX(rate_set); + VIF_STATE_PRINT_INT(beacon_int); + VIF_STATE_PRINT_INT(default_key); + VIF_STATE_PRINT_INT(aid); + VIF_STATE_PRINT_INT(session_counter); + VIF_STATE_PRINT_INT(ps_poll_failures); + VIF_STATE_PRINT_INT(psm_entry_retry); + VIF_STATE_PRINT_INT(power_level); + VIF_STATE_PRINT_INT(rssi_thold); + VIF_STATE_PRINT_INT(last_rssi_event); + VIF_STATE_PRINT_INT(ba_support); + VIF_STATE_PRINT_INT(ba_allowed); + VIF_STATE_PRINT_LLHEX(tx_security_seq); + VIF_STATE_PRINT_INT(tx_security_last_seq_lsb); + } + +#undef VIF_STATE_PRINT_INT +#undef VIF_STATE_PRINT_LONG +#undef VIF_STATE_PRINT_HEX +#undef VIF_STATE_PRINT_LHEX +#undef VIF_STATE_PRINT_LLHEX +#undef VIF_STATE_PRINT_STR +#undef VIF_STATE_PRINT_NSTR +#undef VIF_STATE_PRINT + + mutex_unlock(&wl->mutex); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, res); + kfree(buf); + return ret; +} + +static const struct file_operations vifs_state_ops = { + .read = vifs_state_read, + .open = wl1271_open_file_generic, + .llseek = default_llseek, +}; + static ssize_t dtim_interval_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -520,6 +625,7 @@ static ssize_t rx_streaming_interval_write(struct file *file, size_t count, loff_t *ppos) { struct wl1271 *wl = file->private_data; + struct wl12xx_vif *wlvif; unsigned long value; int ret; @@ -543,7 +649,9 @@ static ssize_t rx_streaming_interval_write(struct file *file, if (ret < 0) goto out; - wl1271_recalc_rx_streaming(wl); + wl12xx_for_each_wlvif_sta(wl, wlvif) { + wl1271_recalc_rx_streaming(wl, wlvif); + } wl1271_ps_elp_sleep(wl); out: @@ -572,6 +680,7 @@ static ssize_t rx_streaming_always_write(struct file *file, size_t count, loff_t *ppos) { struct wl1271 *wl = file->private_data; + struct wl12xx_vif *wlvif; unsigned long value; int ret; @@ -595,7 +704,9 @@ static ssize_t rx_streaming_always_write(struct file *file, if (ret < 0) goto out; - wl1271_recalc_rx_streaming(wl); + wl12xx_for_each_wlvif_sta(wl, wlvif) { + wl1271_recalc_rx_streaming(wl, wlvif); + } wl1271_ps_elp_sleep(wl); out: @@ -624,6 +735,7 @@ static ssize_t beacon_filtering_write(struct file *file, size_t count, loff_t *ppos) { struct wl1271 *wl = file->private_data; + struct wl12xx_vif *wlvif; char buf[10]; size_t len; unsigned long value; @@ -646,7 +758,9 @@ static ssize_t beacon_filtering_write(struct file *file, if (ret < 0) goto out; - ret = wl1271_acx_beacon_filter_opt(wl, !!value); + wl12xx_for_each_wlvif(wl, wlvif) { + ret = wl1271_acx_beacon_filter_opt(wl, wlvif, !!value); + } wl1271_ps_elp_sleep(wl); out: @@ -770,6 +884,7 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl, DEBUGFS_ADD(gpio_power, rootdir); DEBUGFS_ADD(start_recovery, rootdir); DEBUGFS_ADD(driver_state, rootdir); + DEBUGFS_ADD(vifs_state, rootdir); DEBUGFS_ADD(dtim_interval, rootdir); DEBUGFS_ADD(beacon_interval, rootdir); DEBUGFS_ADD(beacon_filtering, rootdir); diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c index 674ad2a9e409..00ce794eebae 100644 --- a/drivers/net/wireless/wl12xx/event.c +++ b/drivers/net/wireless/wl12xx/event.c @@ -22,6 +22,7 @@ */ #include "wl12xx.h" +#include "debug.h" #include "reg.h" #include "io.h" #include "event.h" @@ -31,12 +32,16 @@ void wl1271_pspoll_work(struct work_struct *work) { + struct ieee80211_vif *vif; + struct wl12xx_vif *wlvif; struct delayed_work *dwork; struct wl1271 *wl; int ret; dwork = container_of(work, struct delayed_work, work); - wl = container_of(dwork, struct wl1271, pspoll_work); + wlvif = container_of(dwork, struct wl12xx_vif, pspoll_work); + vif = container_of((void *)wlvif, struct ieee80211_vif, drv_priv); + wl = wlvif->wl; wl1271_debug(DEBUG_EVENT, "pspoll work"); @@ -45,10 +50,10 @@ void wl1271_pspoll_work(struct work_struct *work) if (unlikely(wl->state == WL1271_STATE_OFF)) goto out; - if (!test_and_clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags)) + if (!test_and_clear_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags)) goto out; - if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) + if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) goto out; /* @@ -60,31 +65,33 @@ void wl1271_pspoll_work(struct work_struct *work) if (ret < 0) goto out; - wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, wl->basic_rate, true); + wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE, + wlvif->basic_rate, true); wl1271_ps_elp_sleep(wl); out: mutex_unlock(&wl->mutex); }; -static void wl1271_event_pspoll_delivery_fail(struct wl1271 *wl) +static void wl1271_event_pspoll_delivery_fail(struct wl1271 *wl, + struct wl12xx_vif *wlvif) { int delay = wl->conf.conn.ps_poll_recovery_period; int ret; - wl->ps_poll_failures++; - if (wl->ps_poll_failures == 1) + wlvif->ps_poll_failures++; + if (wlvif->ps_poll_failures == 1) wl1271_info("AP with dysfunctional ps-poll, " "trying to work around it."); /* force active mode receive data from the AP */ - if (test_bit(WL1271_FLAG_PSM, &wl->flags)) { - ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, - wl->basic_rate, true); + if (test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) { + ret = wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE, + wlvif->basic_rate, true); if (ret < 0) return; - set_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags); - ieee80211_queue_delayed_work(wl->hw, &wl->pspoll_work, + set_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags); + ieee80211_queue_delayed_work(wl->hw, &wlvif->pspoll_work, msecs_to_jiffies(delay)); } @@ -97,6 +104,7 @@ static void wl1271_event_pspoll_delivery_fail(struct wl1271 *wl) } static int wl1271_event_ps_report(struct wl1271 *wl, + struct wl12xx_vif *wlvif, struct event_mailbox *mbox, bool *beacon_loss) { @@ -109,41 +117,37 @@ static int wl1271_event_ps_report(struct wl1271 *wl, case EVENT_ENTER_POWER_SAVE_FAIL: wl1271_debug(DEBUG_PSM, "PSM entry failed"); - if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) { + if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) { /* remain in active mode */ - wl->psm_entry_retry = 0; + wlvif->psm_entry_retry = 0; break; } - if (wl->psm_entry_retry < total_retries) { - wl->psm_entry_retry++; - ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, - wl->basic_rate, true); + if (wlvif->psm_entry_retry < total_retries) { + wlvif->psm_entry_retry++; + ret = wl1271_ps_set_mode(wl, wlvif, + STATION_POWER_SAVE_MODE, + wlvif->basic_rate, true); } else { wl1271_info("No ack to nullfunc from AP."); - wl->psm_entry_retry = 0; + wlvif->psm_entry_retry = 0; *beacon_loss = true; } break; case EVENT_ENTER_POWER_SAVE_SUCCESS: - wl->psm_entry_retry = 0; - - /* enable beacon filtering */ - ret = wl1271_acx_beacon_filter_opt(wl, true); - if (ret < 0) - break; + wlvif->psm_entry_retry = 0; /* * BET has only a minor effect in 5GHz and masks * channel switch IEs, so we only enable BET on 2.4GHz */ - if (wl->band == IEEE80211_BAND_2GHZ) + if (wlvif->band == IEEE80211_BAND_2GHZ) /* enable beacon early termination */ - ret = wl1271_acx_bet_enable(wl, true); + ret = wl1271_acx_bet_enable(wl, wlvif, true); - if (wl->ps_compl) { - complete(wl->ps_compl); - wl->ps_compl = NULL; + if (wlvif->ps_compl) { + complete(wlvif->ps_compl); + wlvif->ps_compl = NULL; } break; default: @@ -154,39 +158,44 @@ static int wl1271_event_ps_report(struct wl1271 *wl, } static void wl1271_event_rssi_trigger(struct wl1271 *wl, + struct wl12xx_vif *wlvif, struct event_mailbox *mbox) { + struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); enum nl80211_cqm_rssi_threshold_event event; s8 metric = mbox->rssi_snr_trigger_metric[0]; wl1271_debug(DEBUG_EVENT, "RSSI trigger metric: %d", metric); - if (metric <= wl->rssi_thold) + if (metric <= wlvif->rssi_thold) event = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW; else event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH; - if (event != wl->last_rssi_event) - ieee80211_cqm_rssi_notify(wl->vif, event, GFP_KERNEL); - wl->last_rssi_event = event; + if (event != wlvif->last_rssi_event) + ieee80211_cqm_rssi_notify(vif, event, GFP_KERNEL); + wlvif->last_rssi_event = event; } -static void wl1271_stop_ba_event(struct wl1271 *wl) +static void wl1271_stop_ba_event(struct wl1271 *wl, struct wl12xx_vif *wlvif) { - if (wl->bss_type != BSS_TYPE_AP_BSS) { - if (!wl->ba_rx_bitmap) + struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); + + if (wlvif->bss_type != BSS_TYPE_AP_BSS) { + if (!wlvif->sta.ba_rx_bitmap) return; - ieee80211_stop_rx_ba_session(wl->vif, wl->ba_rx_bitmap, - wl->bssid); + ieee80211_stop_rx_ba_session(vif, wlvif->sta.ba_rx_bitmap, + vif->bss_conf.bssid); } else { - int i; + u8 hlid; struct wl1271_link *lnk; - for (i = WL1271_AP_STA_HLID_START; i < AP_MAX_LINKS; i++) { - lnk = &wl->links[i]; - if (!wl1271_is_active_sta(wl, i) || !lnk->ba_bitmap) + for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, + WL12XX_MAX_LINKS) { + lnk = &wl->links[hlid]; + if (!lnk->ba_bitmap) continue; - ieee80211_stop_rx_ba_session(wl->vif, + ieee80211_stop_rx_ba_session(vif, lnk->ba_bitmap, lnk->addr); } @@ -196,14 +205,23 @@ static void wl1271_stop_ba_event(struct wl1271 *wl) static void wl12xx_event_soft_gemini_sense(struct wl1271 *wl, u8 enable) { + struct ieee80211_vif *vif; + struct wl12xx_vif *wlvif; + if (enable) { /* disable dynamic PS when requested by the firmware */ - ieee80211_disable_dyn_ps(wl->vif); + wl12xx_for_each_wlvif_sta(wl, wlvif) { + vif = wl12xx_wlvif_to_vif(wlvif); + ieee80211_disable_dyn_ps(vif); + } set_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags); } else { - ieee80211_enable_dyn_ps(wl->vif); clear_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags); - wl1271_recalc_rx_streaming(wl); + wl12xx_for_each_wlvif_sta(wl, wlvif) { + vif = wl12xx_wlvif_to_vif(wlvif); + ieee80211_enable_dyn_ps(vif); + wl1271_recalc_rx_streaming(wl, wlvif); + } } } @@ -217,10 +235,11 @@ static void wl1271_event_mbox_dump(struct event_mailbox *mbox) static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) { + struct ieee80211_vif *vif; + struct wl12xx_vif *wlvif; int ret; u32 vector; bool beacon_loss = false; - bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); bool disconnect_sta = false; unsigned long sta_bitmap = 0; @@ -234,7 +253,7 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) wl1271_debug(DEBUG_EVENT, "status: 0x%x", mbox->scheduled_scan_status); - wl1271_scan_stm(wl); + wl1271_scan_stm(wl, wl->scan_vif); } if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) { @@ -253,8 +272,7 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) } } - if (vector & SOFT_GEMINI_SENSE_EVENT_ID && - wl->bss_type == BSS_TYPE_STA_BSS) + if (vector & SOFT_GEMINI_SENSE_EVENT_ID) wl12xx_event_soft_gemini_sense(wl, mbox->soft_gemini_sense_info); @@ -267,40 +285,54 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) * BSS_LOSE_EVENT, beacon loss has to be reported to the stack. * */ - if ((vector & BSS_LOSE_EVENT_ID) && !is_ap) { + if (vector & BSS_LOSE_EVENT_ID) { + /* TODO: check for multi-role */ wl1271_info("Beacon loss detected."); /* indicate to the stack, that beacons have been lost */ beacon_loss = true; } - if ((vector & PS_REPORT_EVENT_ID) && !is_ap) { + if (vector & PS_REPORT_EVENT_ID) { wl1271_debug(DEBUG_EVENT, "PS_REPORT_EVENT"); - ret = wl1271_event_ps_report(wl, mbox, &beacon_loss); - if (ret < 0) - return ret; + wl12xx_for_each_wlvif_sta(wl, wlvif) { + ret = wl1271_event_ps_report(wl, wlvif, + mbox, &beacon_loss); + if (ret < 0) + return ret; + } } - if ((vector & PSPOLL_DELIVERY_FAILURE_EVENT_ID) && !is_ap) - wl1271_event_pspoll_delivery_fail(wl); + if (vector & PSPOLL_DELIVERY_FAILURE_EVENT_ID) + wl12xx_for_each_wlvif_sta(wl, wlvif) { + wl1271_event_pspoll_delivery_fail(wl, wlvif); + } if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) { + /* TODO: check actual multi-role support */ wl1271_debug(DEBUG_EVENT, "RSSI_SNR_TRIGGER_0_EVENT"); - if (wl->vif) - wl1271_event_rssi_trigger(wl, mbox); + wl12xx_for_each_wlvif_sta(wl, wlvif) { + wl1271_event_rssi_trigger(wl, wlvif, mbox); + } } - if ((vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID)) { + if (vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID) { + u8 role_id = mbox->role_id; wl1271_debug(DEBUG_EVENT, "BA_SESSION_RX_CONSTRAINT_EVENT_ID. " - "ba_allowed = 0x%x", mbox->rx_ba_allowed); + "ba_allowed = 0x%x, role_id=%d", + mbox->rx_ba_allowed, role_id); - wl->ba_allowed = !!mbox->rx_ba_allowed; + wl12xx_for_each_wlvif(wl, wlvif) { + if (role_id != 0xff && role_id != wlvif->role_id) + continue; - if (wl->vif && !wl->ba_allowed) - wl1271_stop_ba_event(wl); + wlvif->ba_allowed = !!mbox->rx_ba_allowed; + if (!wlvif->ba_allowed) + wl1271_stop_ba_event(wl, wlvif); + } } - if ((vector & CHANNEL_SWITCH_COMPLETE_EVENT_ID) && !is_ap) { + if (vector & CHANNEL_SWITCH_COMPLETE_EVENT_ID) { wl1271_debug(DEBUG_EVENT, "CHANNEL_SWITCH_COMPLETE_EVENT_ID. " "status = 0x%x", mbox->channel_switch_status); @@ -309,50 +341,65 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) * 1) channel switch complete with status=0 * 2) channel switch failed status=1 */ - if (test_and_clear_bit(WL1271_FLAG_CS_PROGRESS, &wl->flags) && - (wl->vif)) - ieee80211_chswitch_done(wl->vif, - mbox->channel_switch_status ? false : true); + + /* TODO: configure only the relevant vif */ + wl12xx_for_each_wlvif_sta(wl, wlvif) { + struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); + bool success; + + if (!test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, + &wl->flags)) + continue; + + success = mbox->channel_switch_status ? false : true; + ieee80211_chswitch_done(vif, success); + } } if ((vector & DUMMY_PACKET_EVENT_ID)) { wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID"); - if (wl->vif) - wl1271_tx_dummy_packet(wl); + wl1271_tx_dummy_packet(wl); } /* * "TX retries exceeded" has a different meaning according to mode. * In AP mode the offending station is disconnected. */ - if ((vector & MAX_TX_RETRY_EVENT_ID) && is_ap) { + if (vector & MAX_TX_RETRY_EVENT_ID) { wl1271_debug(DEBUG_EVENT, "MAX_TX_RETRY_EVENT_ID"); sta_bitmap |= le16_to_cpu(mbox->sta_tx_retry_exceeded); disconnect_sta = true; } - if ((vector & INACTIVE_STA_EVENT_ID) && is_ap) { + if (vector & INACTIVE_STA_EVENT_ID) { wl1271_debug(DEBUG_EVENT, "INACTIVE_STA_EVENT_ID"); sta_bitmap |= le16_to_cpu(mbox->sta_aging_status); disconnect_sta = true; } - if (is_ap && disconnect_sta) { + if (disconnect_sta) { u32 num_packets = wl->conf.tx.max_tx_retries; struct ieee80211_sta *sta; const u8 *addr; int h; - for (h = find_first_bit(&sta_bitmap, AP_MAX_LINKS); - h < AP_MAX_LINKS; - h = find_next_bit(&sta_bitmap, AP_MAX_LINKS, h+1)) { - if (!wl1271_is_active_sta(wl, h)) + for_each_set_bit(h, &sta_bitmap, WL12XX_MAX_LINKS) { + bool found = false; + /* find the ap vif connected to this sta */ + wl12xx_for_each_wlvif_ap(wl, wlvif) { + if (!test_bit(h, wlvif->ap.sta_hlid_map)) + continue; + found = true; + break; + } + if (!found) continue; + vif = wl12xx_wlvif_to_vif(wlvif); addr = wl->links[h].addr; rcu_read_lock(); - sta = ieee80211_find_sta(wl->vif, addr); + sta = ieee80211_find_sta(vif, addr); if (sta) { wl1271_debug(DEBUG_EVENT, "remove sta %d", h); ieee80211_report_low_ack(sta, num_packets); @@ -361,8 +408,11 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) } } - if (wl->vif && beacon_loss) - ieee80211_connection_loss(wl->vif); + if (beacon_loss) + wl12xx_for_each_wlvif_sta(wl, wlvif) { + vif = wl12xx_wlvif_to_vif(wlvif); + ieee80211_connection_loss(vif); + } return 0; } diff --git a/drivers/net/wireless/wl12xx/event.h b/drivers/net/wireless/wl12xx/event.h index 49c1a0ede5b1..1d878ba47bf4 100644 --- a/drivers/net/wireless/wl12xx/event.h +++ b/drivers/net/wireless/wl12xx/event.h @@ -132,7 +132,4 @@ void wl1271_event_mbox_config(struct wl1271 *wl); int wl1271_event_handle(struct wl1271 *wl, u8 mbox); void wl1271_pspoll_work(struct work_struct *work); -/* Functions from main.c */ -bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid); - #endif diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c index 04db64c94e9a..ca7ee59e4505 100644 --- a/drivers/net/wireless/wl12xx/init.c +++ b/drivers/net/wireless/wl12xx/init.c @@ -25,6 +25,7 @@ #include <linux/module.h> #include <linux/slab.h> +#include "debug.h" #include "init.h" #include "wl12xx_80211.h" #include "acx.h" @@ -33,7 +34,7 @@ #include "tx.h" #include "io.h" -int wl1271_sta_init_templates_config(struct wl1271 *wl) +int wl1271_init_templates_config(struct wl1271 *wl) { int ret, i; @@ -64,7 +65,7 @@ int wl1271_sta_init_templates_config(struct wl1271 *wl) ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, NULL, sizeof - (struct wl12xx_qos_null_data_template), + (struct ieee80211_qos_hdr), 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; @@ -88,10 +89,33 @@ int wl1271_sta_init_templates_config(struct wl1271 *wl) if (ret < 0) return ret; + /* + * Put very large empty placeholders for all templates. These + * reserve memory for later. + */ + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_AP_PROBE_RESPONSE, NULL, + WL1271_CMD_TEMPL_MAX_SIZE, + 0, WL1271_RATE_AUTOMATIC); + if (ret < 0) + return ret; + + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_AP_BEACON, NULL, + WL1271_CMD_TEMPL_MAX_SIZE, + 0, WL1271_RATE_AUTOMATIC); + if (ret < 0) + return ret; + + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_DEAUTH_AP, NULL, + sizeof + (struct wl12xx_disconn_template), + 0, WL1271_RATE_AUTOMATIC); + if (ret < 0) + return ret; + for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) { ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV, NULL, - WL1271_CMD_TEMPL_DFLT_SIZE, i, - WL1271_RATE_AUTOMATIC); + sizeof(struct ieee80211_qos_hdr), + i, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; } @@ -99,7 +123,8 @@ int wl1271_sta_init_templates_config(struct wl1271 *wl) return 0; } -static int wl1271_ap_init_deauth_template(struct wl1271 *wl) +static int wl1271_ap_init_deauth_template(struct wl1271 *wl, + struct wl12xx_vif *wlvif) { struct wl12xx_disconn_template *tmpl; int ret; @@ -114,7 +139,7 @@ static int wl1271_ap_init_deauth_template(struct wl1271 *wl) tmpl->header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_DEAUTH); - rate = wl1271_tx_min_rate_get(wl, wl->basic_rate_set); + rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); ret = wl1271_cmd_template_set(wl, CMD_TEMPL_DEAUTH_AP, tmpl, sizeof(*tmpl), 0, rate); @@ -123,8 +148,10 @@ out: return ret; } -static int wl1271_ap_init_null_template(struct wl1271 *wl) +static int wl1271_ap_init_null_template(struct wl1271 *wl, + struct ieee80211_vif *vif) { + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); struct ieee80211_hdr_3addr *nullfunc; int ret; u32 rate; @@ -141,10 +168,10 @@ static int wl1271_ap_init_null_template(struct wl1271 *wl) /* nullfunc->addr1 is filled by FW */ - memcpy(nullfunc->addr2, wl->mac_addr, ETH_ALEN); - memcpy(nullfunc->addr3, wl->mac_addr, ETH_ALEN); + memcpy(nullfunc->addr2, vif->addr, ETH_ALEN); + memcpy(nullfunc->addr3, vif->addr, ETH_ALEN); - rate = wl1271_tx_min_rate_get(wl, wl->basic_rate_set); + rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, nullfunc, sizeof(*nullfunc), 0, rate); @@ -153,8 +180,10 @@ out: return ret; } -static int wl1271_ap_init_qos_null_template(struct wl1271 *wl) +static int wl1271_ap_init_qos_null_template(struct wl1271 *wl, + struct ieee80211_vif *vif) { + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); struct ieee80211_qos_hdr *qosnull; int ret; u32 rate; @@ -171,10 +200,10 @@ static int wl1271_ap_init_qos_null_template(struct wl1271 *wl) /* qosnull->addr1 is filled by FW */ - memcpy(qosnull->addr2, wl->mac_addr, ETH_ALEN); - memcpy(qosnull->addr3, wl->mac_addr, ETH_ALEN); + memcpy(qosnull->addr2, vif->addr, ETH_ALEN); + memcpy(qosnull->addr3, vif->addr, ETH_ALEN); - rate = wl1271_tx_min_rate_get(wl, wl->basic_rate_set); + rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, qosnull, sizeof(*qosnull), 0, rate); @@ -183,49 +212,6 @@ out: return ret; } -static int wl1271_ap_init_templates_config(struct wl1271 *wl) -{ - int ret; - - /* - * Put very large empty placeholders for all templates. These - * reserve memory for later. - */ - ret = wl1271_cmd_template_set(wl, CMD_TEMPL_AP_PROBE_RESPONSE, NULL, - WL1271_CMD_TEMPL_MAX_SIZE, - 0, WL1271_RATE_AUTOMATIC); - if (ret < 0) - return ret; - - ret = wl1271_cmd_template_set(wl, CMD_TEMPL_AP_BEACON, NULL, - WL1271_CMD_TEMPL_MAX_SIZE, - 0, WL1271_RATE_AUTOMATIC); - if (ret < 0) - return ret; - - ret = wl1271_cmd_template_set(wl, CMD_TEMPL_DEAUTH_AP, NULL, - sizeof - (struct wl12xx_disconn_template), - 0, WL1271_RATE_AUTOMATIC); - if (ret < 0) - return ret; - - ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, NULL, - sizeof(struct wl12xx_null_data_template), - 0, WL1271_RATE_AUTOMATIC); - if (ret < 0) - return ret; - - ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, NULL, - sizeof - (struct wl12xx_qos_null_data_template), - 0, WL1271_RATE_AUTOMATIC); - if (ret < 0) - return ret; - - return 0; -} - static int wl12xx_init_rx_config(struct wl1271 *wl) { int ret; @@ -237,39 +223,37 @@ static int wl12xx_init_rx_config(struct wl1271 *wl) return 0; } -int wl1271_init_phy_config(struct wl1271 *wl) +static int wl12xx_init_phy_vif_config(struct wl1271 *wl, + struct wl12xx_vif *wlvif) { int ret; - ret = wl1271_acx_pd_threshold(wl); - if (ret < 0) - return ret; - - ret = wl1271_acx_slot(wl, DEFAULT_SLOT_TIME); + ret = wl1271_acx_slot(wl, wlvif, DEFAULT_SLOT_TIME); if (ret < 0) return ret; - ret = wl1271_acx_service_period_timeout(wl); + ret = wl1271_acx_service_period_timeout(wl, wlvif); if (ret < 0) return ret; - ret = wl1271_acx_rts_threshold(wl, wl->hw->wiphy->rts_threshold); + ret = wl1271_acx_rts_threshold(wl, wlvif, wl->hw->wiphy->rts_threshold); if (ret < 0) return ret; return 0; } -static int wl1271_init_beacon_filter(struct wl1271 *wl) +static int wl1271_init_sta_beacon_filter(struct wl1271 *wl, + struct wl12xx_vif *wlvif) { int ret; - /* disable beacon filtering at this stage */ - ret = wl1271_acx_beacon_filter_opt(wl, false); + ret = wl1271_acx_beacon_filter_table(wl, wlvif); if (ret < 0) return ret; - ret = wl1271_acx_beacon_filter_table(wl); + /* enable beacon filtering */ + ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true); if (ret < 0) return ret; @@ -302,11 +286,12 @@ int wl1271_init_energy_detection(struct wl1271 *wl) return 0; } -static int wl1271_init_beacon_broadcast(struct wl1271 *wl) +static int wl1271_init_beacon_broadcast(struct wl1271 *wl, + struct wl12xx_vif *wlvif) { int ret; - ret = wl1271_acx_bcn_dtim_options(wl); + ret = wl1271_acx_bcn_dtim_options(wl, wlvif); if (ret < 0) return ret; @@ -327,36 +312,13 @@ static int wl12xx_init_fwlog(struct wl1271 *wl) return 0; } -static int wl1271_sta_hw_init(struct wl1271 *wl) +/* generic sta initialization (non vif-specific) */ +static int wl1271_sta_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif) { int ret; - if (wl->chip.id != CHIP_ID_1283_PG20) { - ret = wl1271_cmd_ext_radio_parms(wl); - if (ret < 0) - return ret; - } - /* PS config */ - ret = wl1271_acx_config_ps(wl); - if (ret < 0) - return ret; - - ret = wl1271_sta_init_templates_config(wl); - if (ret < 0) - return ret; - - ret = wl1271_acx_group_address_tbl(wl, true, NULL, 0); - if (ret < 0) - return ret; - - /* Initialize connection monitoring thresholds */ - ret = wl1271_acx_conn_monit_params(wl, false); - if (ret < 0) - return ret; - - /* Beacon filtering */ - ret = wl1271_init_beacon_filter(wl); + ret = wl12xx_acx_config_ps(wl, wlvif); if (ret < 0) return ret; @@ -365,103 +327,61 @@ static int wl1271_sta_hw_init(struct wl1271 *wl) if (ret < 0) return ret; - /* Beacons and broadcast settings */ - ret = wl1271_init_beacon_broadcast(wl); - if (ret < 0) - return ret; - - /* Configure for ELP power saving */ - ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP); - if (ret < 0) - return ret; - - /* Configure rssi/snr averaging weights */ - ret = wl1271_acx_rssi_snr_avg_weights(wl); - if (ret < 0) - return ret; - - ret = wl1271_acx_sta_rate_policies(wl); - if (ret < 0) - return ret; - - ret = wl12xx_acx_mem_cfg(wl); - if (ret < 0) - return ret; - - /* Configure the FW logger */ - ret = wl12xx_init_fwlog(wl); + ret = wl1271_acx_sta_rate_policies(wl, wlvif); if (ret < 0) return ret; return 0; } -static int wl1271_sta_hw_init_post_mem(struct wl1271 *wl) +static int wl1271_sta_hw_init_post_mem(struct wl1271 *wl, + struct ieee80211_vif *vif) { + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); int ret, i; /* disable all keep-alive templates */ for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) { - ret = wl1271_acx_keep_alive_config(wl, i, + ret = wl1271_acx_keep_alive_config(wl, wlvif, i, ACX_KEEP_ALIVE_TPL_INVALID); if (ret < 0) return ret; } /* disable the keep-alive feature */ - ret = wl1271_acx_keep_alive_mode(wl, false); + ret = wl1271_acx_keep_alive_mode(wl, wlvif, false); if (ret < 0) return ret; return 0; } -static int wl1271_ap_hw_init(struct wl1271 *wl) +/* generic ap initialization (non vif-specific) */ +static int wl1271_ap_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif) { int ret; - ret = wl1271_ap_init_templates_config(wl); - if (ret < 0) - return ret; - - /* Configure for power always on */ - ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM); - if (ret < 0) - return ret; - - ret = wl1271_init_ap_rates(wl); - if (ret < 0) - return ret; - - ret = wl1271_acx_ap_max_tx_retry(wl); - if (ret < 0) - return ret; - - ret = wl12xx_acx_mem_cfg(wl); - if (ret < 0) - return ret; - - /* initialize Tx power */ - ret = wl1271_acx_tx_power(wl, wl->power_level); + ret = wl1271_init_ap_rates(wl, wlvif); if (ret < 0) return ret; return 0; } -int wl1271_ap_init_templates(struct wl1271 *wl) +int wl1271_ap_init_templates(struct wl1271 *wl, struct ieee80211_vif *vif) { + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); int ret; - ret = wl1271_ap_init_deauth_template(wl); + ret = wl1271_ap_init_deauth_template(wl, wlvif); if (ret < 0) return ret; - ret = wl1271_ap_init_null_template(wl); + ret = wl1271_ap_init_null_template(wl, vif); if (ret < 0) return ret; - ret = wl1271_ap_init_qos_null_template(wl); + ret = wl1271_ap_init_qos_null_template(wl, vif); if (ret < 0) return ret; @@ -469,43 +389,45 @@ int wl1271_ap_init_templates(struct wl1271 *wl) * when operating as AP we want to receive external beacons for * configuring ERP protection. */ - ret = wl1271_acx_beacon_filter_opt(wl, false); + ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false); if (ret < 0) return ret; return 0; } -static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl) +static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl, + struct ieee80211_vif *vif) { - return wl1271_ap_init_templates(wl); + return wl1271_ap_init_templates(wl, vif); } -int wl1271_init_ap_rates(struct wl1271 *wl) +int wl1271_init_ap_rates(struct wl1271 *wl, struct wl12xx_vif *wlvif) { int i, ret; struct conf_tx_rate_class rc; u32 supported_rates; - wl1271_debug(DEBUG_AP, "AP basic rate set: 0x%x", wl->basic_rate_set); + wl1271_debug(DEBUG_AP, "AP basic rate set: 0x%x", + wlvif->basic_rate_set); - if (wl->basic_rate_set == 0) + if (wlvif->basic_rate_set == 0) return -EINVAL; - rc.enabled_rates = wl->basic_rate_set; + rc.enabled_rates = wlvif->basic_rate_set; rc.long_retry_limit = 10; rc.short_retry_limit = 10; rc.aflags = 0; - ret = wl1271_acx_ap_rate_policy(wl, &rc, ACX_TX_AP_MODE_MGMT_RATE); + ret = wl1271_acx_ap_rate_policy(wl, &rc, wlvif->ap.mgmt_rate_idx); if (ret < 0) return ret; /* use the min basic rate for AP broadcast/multicast */ - rc.enabled_rates = wl1271_tx_min_rate_get(wl, wl->basic_rate_set); + rc.enabled_rates = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); rc.short_retry_limit = 10; rc.long_retry_limit = 10; rc.aflags = 0; - ret = wl1271_acx_ap_rate_policy(wl, &rc, ACX_TX_AP_MODE_BCST_RATE); + ret = wl1271_acx_ap_rate_policy(wl, &rc, wlvif->ap.bcast_rate_idx); if (ret < 0) return ret; @@ -513,7 +435,7 @@ int wl1271_init_ap_rates(struct wl1271 *wl) * If the basic rates contain OFDM rates, use OFDM only * rates for unicast TX as well. Else use all supported rates. */ - if ((wl->basic_rate_set & CONF_TX_OFDM_RATES)) + if ((wlvif->basic_rate_set & CONF_TX_OFDM_RATES)) supported_rates = CONF_TX_OFDM_RATES; else supported_rates = CONF_TX_AP_ENABLED_RATES; @@ -527,7 +449,8 @@ int wl1271_init_ap_rates(struct wl1271 *wl) rc.short_retry_limit = 10; rc.long_retry_limit = 10; rc.aflags = 0; - ret = wl1271_acx_ap_rate_policy(wl, &rc, i); + ret = wl1271_acx_ap_rate_policy(wl, &rc, + wlvif->ap.ucast_rate_idx[i]); if (ret < 0) return ret; } @@ -535,24 +458,23 @@ int wl1271_init_ap_rates(struct wl1271 *wl) return 0; } -static int wl1271_set_ba_policies(struct wl1271 *wl) +static int wl1271_set_ba_policies(struct wl1271 *wl, struct wl12xx_vif *wlvif) { /* Reset the BA RX indicators */ - wl->ba_rx_bitmap = 0; - wl->ba_allowed = true; + wlvif->ba_allowed = true; wl->ba_rx_session_count = 0; /* BA is supported in STA/AP modes */ - if (wl->bss_type != BSS_TYPE_AP_BSS && - wl->bss_type != BSS_TYPE_STA_BSS) { - wl->ba_support = false; + if (wlvif->bss_type != BSS_TYPE_AP_BSS && + wlvif->bss_type != BSS_TYPE_STA_BSS) { + wlvif->ba_support = false; return 0; } - wl->ba_support = true; + wlvif->ba_support = true; /* 802.11n initiator BA session setting */ - return wl12xx_acx_set_ba_initiator_policy(wl); + return wl12xx_acx_set_ba_initiator_policy(wl, wlvif); } int wl1271_chip_specific_init(struct wl1271 *wl) @@ -562,7 +484,7 @@ int wl1271_chip_specific_init(struct wl1271 *wl) if (wl->chip.id == CHIP_ID_1283_PG20) { u32 host_cfg_bitmap = HOST_IF_CFG_RX_FIFO_ENABLE; - if (wl->quirks & WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT) + if (!(wl->quirks & WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT)) /* Enable SDIO padding */ host_cfg_bitmap |= HOST_IF_CFG_TX_PAD_TO_SDIO_BLK; @@ -575,39 +497,186 @@ out: return ret; } +/* vif-specifc initialization */ +static int wl12xx_init_sta_role(struct wl1271 *wl, struct wl12xx_vif *wlvif) +{ + int ret; -int wl1271_hw_init(struct wl1271 *wl) + ret = wl1271_acx_group_address_tbl(wl, wlvif, true, NULL, 0); + if (ret < 0) + return ret; + + /* Initialize connection monitoring thresholds */ + ret = wl1271_acx_conn_monit_params(wl, wlvif, false); + if (ret < 0) + return ret; + + /* Beacon filtering */ + ret = wl1271_init_sta_beacon_filter(wl, wlvif); + if (ret < 0) + return ret; + + /* Beacons and broadcast settings */ + ret = wl1271_init_beacon_broadcast(wl, wlvif); + if (ret < 0) + return ret; + + /* Configure rssi/snr averaging weights */ + ret = wl1271_acx_rssi_snr_avg_weights(wl, wlvif); + if (ret < 0) + return ret; + + return 0; +} + +/* vif-specific intialization */ +static int wl12xx_init_ap_role(struct wl1271 *wl, struct wl12xx_vif *wlvif) { + int ret; + + ret = wl1271_acx_ap_max_tx_retry(wl, wlvif); + if (ret < 0) + return ret; + + /* initialize Tx power */ + ret = wl1271_acx_tx_power(wl, wlvif, wlvif->power_level); + if (ret < 0) + return ret; + + return 0; +} + +int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif) +{ + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); struct conf_tx_ac_category *conf_ac; struct conf_tx_tid *conf_tid; + bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); int ret, i; - bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); - if (wl->chip.id == CHIP_ID_1283_PG20) - ret = wl128x_cmd_general_parms(wl); - else - ret = wl1271_cmd_general_parms(wl); + /* + * consider all existing roles before configuring psm. + * TODO: reconfigure on interface removal. + */ + if (!wl->ap_count) { + if (is_ap) { + /* Configure for power always on */ + ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM); + if (ret < 0) + return ret; + } else if (!wl->sta_count) { + /* Configure for ELP power saving */ + ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP); + if (ret < 0) + return ret; + } + } + + /* Mode specific init */ + if (is_ap) { + ret = wl1271_ap_hw_init(wl, wlvif); + if (ret < 0) + return ret; + + ret = wl12xx_init_ap_role(wl, wlvif); + if (ret < 0) + return ret; + } else { + ret = wl1271_sta_hw_init(wl, wlvif); + if (ret < 0) + return ret; + + ret = wl12xx_init_sta_role(wl, wlvif); + if (ret < 0) + return ret; + } + + wl12xx_init_phy_vif_config(wl, wlvif); + + /* Default TID/AC configuration */ + BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count); + for (i = 0; i < wl->conf.tx.tid_conf_count; i++) { + conf_ac = &wl->conf.tx.ac_conf[i]; + ret = wl1271_acx_ac_cfg(wl, wlvif, conf_ac->ac, + conf_ac->cw_min, conf_ac->cw_max, + conf_ac->aifsn, conf_ac->tx_op_limit); + if (ret < 0) + return ret; + + conf_tid = &wl->conf.tx.tid_conf[i]; + ret = wl1271_acx_tid_cfg(wl, wlvif, + conf_tid->queue_id, + conf_tid->channel_type, + conf_tid->tsid, + conf_tid->ps_scheme, + conf_tid->ack_policy, + conf_tid->apsd_conf[0], + conf_tid->apsd_conf[1]); + if (ret < 0) + return ret; + } + + /* Configure HW encryption */ + ret = wl1271_acx_feature_cfg(wl, wlvif); if (ret < 0) return ret; - if (wl->chip.id == CHIP_ID_1283_PG20) - ret = wl128x_cmd_radio_parms(wl); + /* Mode specific init - post mem init */ + if (is_ap) + ret = wl1271_ap_hw_init_post_mem(wl, vif); else - ret = wl1271_cmd_radio_parms(wl); + ret = wl1271_sta_hw_init_post_mem(wl, vif); + + if (ret < 0) + return ret; + + /* Configure initiator BA sessions policies */ + ret = wl1271_set_ba_policies(wl, wlvif); if (ret < 0) return ret; + return 0; +} + +int wl1271_hw_init(struct wl1271 *wl) +{ + int ret; + + if (wl->chip.id == CHIP_ID_1283_PG20) { + ret = wl128x_cmd_general_parms(wl); + if (ret < 0) + return ret; + ret = wl128x_cmd_radio_parms(wl); + if (ret < 0) + return ret; + } else { + ret = wl1271_cmd_general_parms(wl); + if (ret < 0) + return ret; + ret = wl1271_cmd_radio_parms(wl); + if (ret < 0) + return ret; + ret = wl1271_cmd_ext_radio_parms(wl); + if (ret < 0) + return ret; + } + /* Chip-specific init */ ret = wl1271_chip_specific_init(wl); if (ret < 0) return ret; - /* Mode specific init */ - if (is_ap) - ret = wl1271_ap_hw_init(wl); - else - ret = wl1271_sta_hw_init(wl); + /* Init templates */ + ret = wl1271_init_templates_config(wl); + if (ret < 0) + return ret; + + ret = wl12xx_acx_mem_cfg(wl); + if (ret < 0) + return ret; + /* Configure the FW logger */ + ret = wl12xx_init_fwlog(wl); if (ret < 0) return ret; @@ -626,11 +695,6 @@ int wl1271_hw_init(struct wl1271 *wl) if (ret < 0) goto out_free_memmap; - /* PHY layer config */ - ret = wl1271_init_phy_config(wl); - if (ret < 0) - goto out_free_memmap; - ret = wl1271_acx_dco_itrim_params(wl); if (ret < 0) goto out_free_memmap; @@ -655,61 +719,20 @@ int wl1271_hw_init(struct wl1271 *wl) if (ret < 0) goto out_free_memmap; - /* Default TID/AC configuration */ - BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count); - for (i = 0; i < wl->conf.tx.tid_conf_count; i++) { - conf_ac = &wl->conf.tx.ac_conf[i]; - ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min, - conf_ac->cw_max, conf_ac->aifsn, - conf_ac->tx_op_limit); - if (ret < 0) - goto out_free_memmap; - - conf_tid = &wl->conf.tx.tid_conf[i]; - ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id, - conf_tid->channel_type, - conf_tid->tsid, - conf_tid->ps_scheme, - conf_tid->ack_policy, - conf_tid->apsd_conf[0], - conf_tid->apsd_conf[1]); - if (ret < 0) - goto out_free_memmap; - } - /* Enable data path */ ret = wl1271_cmd_data_path(wl, 1); if (ret < 0) goto out_free_memmap; - /* Configure HW encryption */ - ret = wl1271_acx_feature_cfg(wl); - if (ret < 0) - goto out_free_memmap; - /* configure PM */ ret = wl1271_acx_pm_config(wl); if (ret < 0) goto out_free_memmap; - /* Mode specific init - post mem init */ - if (is_ap) - ret = wl1271_ap_hw_init_post_mem(wl); - else - ret = wl1271_sta_hw_init_post_mem(wl); - - if (ret < 0) - goto out_free_memmap; - ret = wl12xx_acx_set_rate_mgmt_params(wl); if (ret < 0) goto out_free_memmap; - /* Configure initiator BA sessions policies */ - ret = wl1271_set_ba_policies(wl); - if (ret < 0) - goto out_free_memmap; - /* configure hangover */ ret = wl12xx_acx_config_hangover(wl); if (ret < 0) diff --git a/drivers/net/wireless/wl12xx/init.h b/drivers/net/wireless/wl12xx/init.h index 3a3c230fd292..2da0f404ef6e 100644 --- a/drivers/net/wireless/wl12xx/init.h +++ b/drivers/net/wireless/wl12xx/init.h @@ -27,13 +27,13 @@ #include "wl12xx.h" int wl1271_hw_init_power_auth(struct wl1271 *wl); -int wl1271_sta_init_templates_config(struct wl1271 *wl); -int wl1271_init_phy_config(struct wl1271 *wl); +int wl1271_init_templates_config(struct wl1271 *wl); int wl1271_init_pta(struct wl1271 *wl); int wl1271_init_energy_detection(struct wl1271 *wl); int wl1271_chip_specific_init(struct wl1271 *wl); int wl1271_hw_init(struct wl1271 *wl); -int wl1271_init_ap_rates(struct wl1271 *wl); -int wl1271_ap_init_templates(struct wl1271 *wl); +int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif); +int wl1271_init_ap_rates(struct wl1271 *wl, struct wl12xx_vif *wlvif); +int wl1271_ap_init_templates(struct wl1271 *wl, struct ieee80211_vif *vif); #endif diff --git a/drivers/net/wireless/wl12xx/io.c b/drivers/net/wireless/wl12xx/io.c index c2da66f45046..079ad380e8ff 100644 --- a/drivers/net/wireless/wl12xx/io.c +++ b/drivers/net/wireless/wl12xx/io.c @@ -24,8 +24,10 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/spi/spi.h> +#include <linux/interrupt.h> #include "wl12xx.h" +#include "debug.h" #include "wl12xx_80211.h" #include "io.h" #include "tx.h" @@ -46,7 +48,7 @@ bool wl1271_set_block_size(struct wl1271 *wl) { if (wl->if_ops->set_block_size) { - wl->if_ops->set_block_size(wl, WL12XX_BUS_BLOCK_SIZE); + wl->if_ops->set_block_size(wl->dev, WL12XX_BUS_BLOCK_SIZE); return true; } @@ -55,12 +57,12 @@ bool wl1271_set_block_size(struct wl1271 *wl) void wl1271_disable_interrupts(struct wl1271 *wl) { - wl->if_ops->disable_irq(wl); + disable_irq(wl->irq); } void wl1271_enable_interrupts(struct wl1271 *wl) { - wl->if_ops->enable_irq(wl); + enable_irq(wl->irq); } /* Set the SPI partitions to access the chip addresses @@ -128,13 +130,13 @@ EXPORT_SYMBOL_GPL(wl1271_set_partition); void wl1271_io_reset(struct wl1271 *wl) { if (wl->if_ops->reset) - wl->if_ops->reset(wl); + wl->if_ops->reset(wl->dev); } void wl1271_io_init(struct wl1271 *wl) { if (wl->if_ops->init) - wl->if_ops->init(wl); + wl->if_ops->init(wl->dev); } void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val) diff --git a/drivers/net/wireless/wl12xx/io.h b/drivers/net/wireless/wl12xx/io.h index e839341dfafe..d398cbcea986 100644 --- a/drivers/net/wireless/wl12xx/io.h +++ b/drivers/net/wireless/wl12xx/io.h @@ -51,23 +51,17 @@ void wl1271_enable_interrupts(struct wl1271 *wl); void wl1271_io_reset(struct wl1271 *wl); void wl1271_io_init(struct wl1271 *wl); -static inline struct device *wl1271_wl_to_dev(struct wl1271 *wl) -{ - return wl->if_ops->dev(wl); -} - - /* Raw target IO, address is not translated */ static inline void wl1271_raw_write(struct wl1271 *wl, int addr, void *buf, size_t len, bool fixed) { - wl->if_ops->write(wl, addr, buf, len, fixed); + wl->if_ops->write(wl->dev, addr, buf, len, fixed); } static inline void wl1271_raw_read(struct wl1271 *wl, int addr, void *buf, size_t len, bool fixed) { - wl->if_ops->read(wl, addr, buf, len, fixed); + wl->if_ops->read(wl->dev, addr, buf, len, fixed); } static inline u32 wl1271_raw_read32(struct wl1271 *wl, int addr) @@ -155,13 +149,13 @@ static inline void wl1271_write32(struct wl1271 *wl, int addr, u32 val) static inline void wl1271_power_off(struct wl1271 *wl) { - wl->if_ops->power(wl, false); + wl->if_ops->power(wl->dev, false); clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); } static inline int wl1271_power_on(struct wl1271 *wl) { - int ret = wl->if_ops->power(wl, true); + int ret = wl->if_ops->power(wl->dev, true); if (ret == 0) set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); @@ -176,15 +170,10 @@ u16 wl1271_top_reg_read(struct wl1271 *wl, int addr); int wl1271_set_partition(struct wl1271 *wl, struct wl1271_partition_set *p); +bool wl1271_set_block_size(struct wl1271 *wl); + /* Functions from wl1271_main.c */ -int wl1271_register_hw(struct wl1271 *wl); -void wl1271_unregister_hw(struct wl1271 *wl); -int wl1271_init_ieee80211(struct wl1271 *wl); -struct ieee80211_hw *wl1271_alloc_hw(void); -int wl1271_free_hw(struct wl1271 *wl); -irqreturn_t wl1271_irq(int irq, void *data); -bool wl1271_set_block_size(struct wl1271 *wl); int wl1271_tx_dummy_packet(struct wl1271 *wl); #endif diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 884f82b63219..c3058419e227 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -32,8 +32,10 @@ #include <linux/slab.h> #include <linux/wl12xx.h> #include <linux/sched.h> +#include <linux/interrupt.h> #include "wl12xx.h" +#include "debug.h" #include "wl12xx_80211.h" #include "reg.h" #include "io.h" @@ -377,42 +379,30 @@ static char *fwlog_param; static bool bug_on_recovery; static void __wl1271_op_remove_interface(struct wl1271 *wl, + struct ieee80211_vif *vif, bool reset_tx_queues); -static void wl1271_free_ap_keys(struct wl1271 *wl); - - -static void wl1271_device_release(struct device *dev) -{ - -} - -static struct platform_device wl1271_device = { - .name = "wl1271", - .id = -1, - - /* device model insists to have a release function */ - .dev = { - .release = wl1271_device_release, - }, -}; +static void wl1271_op_stop(struct ieee80211_hw *hw); +static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif); static DEFINE_MUTEX(wl_list_mutex); static LIST_HEAD(wl_list); -static int wl1271_check_operstate(struct wl1271 *wl, unsigned char operstate) +static int wl1271_check_operstate(struct wl1271 *wl, struct wl12xx_vif *wlvif, + unsigned char operstate) { int ret; + if (operstate != IF_OPER_UP) return 0; - if (test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) + if (test_and_set_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags)) return 0; - ret = wl12xx_cmd_set_peer_state(wl, wl->sta_hlid); + ret = wl12xx_cmd_set_peer_state(wl, wlvif->sta.hlid); if (ret < 0) return ret; - wl12xx_croc(wl, wl->role_id); + wl12xx_croc(wl, wlvif->role_id); wl1271_info("Association completed."); return 0; @@ -426,6 +416,7 @@ static int wl1271_dev_notify(struct notifier_block *me, unsigned long what, struct ieee80211_hw *hw; struct wl1271 *wl; struct wl1271 *wl_temp; + struct wl12xx_vif *wlvif; int ret = 0; /* Check that this notification is for us. */ @@ -459,17 +450,18 @@ static int wl1271_dev_notify(struct notifier_block *me, unsigned long what, if (wl->state == WL1271_STATE_OFF) goto out; - if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) - goto out; - - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out; + wl12xx_for_each_wlvif_sta(wl, wlvif) { + if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) + continue; - wl1271_check_operstate(wl, dev->operstate); + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; - wl1271_ps_elp_sleep(wl); + wl1271_check_operstate(wl, wlvif, dev->operstate); + wl1271_ps_elp_sleep(wl); + } out: mutex_unlock(&wl->mutex); @@ -498,19 +490,20 @@ static int wl1271_reg_notify(struct wiphy *wiphy, return 0; } -static int wl1271_set_rx_streaming(struct wl1271 *wl, bool enable) +static int wl1271_set_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif, + bool enable) { int ret = 0; /* we should hold wl->mutex */ - ret = wl1271_acx_ps_rx_streaming(wl, enable); + ret = wl1271_acx_ps_rx_streaming(wl, wlvif, enable); if (ret < 0) goto out; if (enable) - set_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags); + set_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags); else - clear_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags); + clear_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags); out: return ret; } @@ -519,25 +512,25 @@ out: * this function is being called when the rx_streaming interval * has beed changed or rx_streaming should be disabled */ -int wl1271_recalc_rx_streaming(struct wl1271 *wl) +int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif) { int ret = 0; int period = wl->conf.rx_streaming.interval; /* don't reconfigure if rx_streaming is disabled */ - if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags)) + if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags)) goto out; /* reconfigure/disable according to new streaming_period */ if (period && - test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) && + test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) && (wl->conf.rx_streaming.always || test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags))) - ret = wl1271_set_rx_streaming(wl, true); + ret = wl1271_set_rx_streaming(wl, wlvif, true); else { - ret = wl1271_set_rx_streaming(wl, false); + ret = wl1271_set_rx_streaming(wl, wlvif, false); /* don't cancel_work_sync since we might deadlock */ - del_timer_sync(&wl->rx_streaming_timer); + del_timer_sync(&wlvif->rx_streaming_timer); } out: return ret; @@ -546,13 +539,14 @@ out: static void wl1271_rx_streaming_enable_work(struct work_struct *work) { int ret; - struct wl1271 *wl = - container_of(work, struct wl1271, rx_streaming_enable_work); + struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif, + rx_streaming_enable_work); + struct wl1271 *wl = wlvif->wl; mutex_lock(&wl->mutex); - if (test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags) || - !test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) || + if (test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags) || + !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) || (!wl->conf.rx_streaming.always && !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags))) goto out; @@ -564,12 +558,12 @@ static void wl1271_rx_streaming_enable_work(struct work_struct *work) if (ret < 0) goto out; - ret = wl1271_set_rx_streaming(wl, true); + ret = wl1271_set_rx_streaming(wl, wlvif, true); if (ret < 0) goto out_sleep; /* stop it after some time of inactivity */ - mod_timer(&wl->rx_streaming_timer, + mod_timer(&wlvif->rx_streaming_timer, jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration)); out_sleep: @@ -581,19 +575,20 @@ out: static void wl1271_rx_streaming_disable_work(struct work_struct *work) { int ret; - struct wl1271 *wl = - container_of(work, struct wl1271, rx_streaming_disable_work); + struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif, + rx_streaming_disable_work); + struct wl1271 *wl = wlvif->wl; mutex_lock(&wl->mutex); - if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags)) + if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags)) goto out; ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) goto out; - ret = wl1271_set_rx_streaming(wl, false); + ret = wl1271_set_rx_streaming(wl, wlvif, false); if (ret) goto out_sleep; @@ -605,8 +600,9 @@ out: static void wl1271_rx_streaming_timer(unsigned long data) { - struct wl1271 *wl = (struct wl1271 *)data; - ieee80211_queue_work(wl->hw, &wl->rx_streaming_disable_work); + struct wl12xx_vif *wlvif = (struct wl12xx_vif *)data; + struct wl1271 *wl = wlvif->wl; + ieee80211_queue_work(wl->hw, &wlvif->rx_streaming_disable_work); } static void wl1271_conf_init(struct wl1271 *wl) @@ -645,9 +641,7 @@ static void wl1271_conf_init(struct wl1271 *wl) static int wl1271_plt_init(struct wl1271 *wl) { - struct conf_tx_ac_category *conf_ac; - struct conf_tx_tid *conf_tid; - int ret, i; + int ret; if (wl->chip.id == CHIP_ID_1283_PG20) ret = wl128x_cmd_general_parms(wl); @@ -676,74 +670,14 @@ static int wl1271_plt_init(struct wl1271 *wl) if (ret < 0) return ret; - ret = wl1271_sta_init_templates_config(wl); - if (ret < 0) - return ret; - ret = wl1271_acx_init_mem_config(wl); if (ret < 0) return ret; - /* PHY layer config */ - ret = wl1271_init_phy_config(wl); - if (ret < 0) - goto out_free_memmap; - - ret = wl1271_acx_dco_itrim_params(wl); - if (ret < 0) - goto out_free_memmap; - - /* Initialize connection monitoring thresholds */ - ret = wl1271_acx_conn_monit_params(wl, false); - if (ret < 0) - goto out_free_memmap; - - /* Bluetooth WLAN coexistence */ - ret = wl1271_init_pta(wl); - if (ret < 0) - goto out_free_memmap; - - /* FM WLAN coexistence */ - ret = wl1271_acx_fm_coex(wl); - if (ret < 0) - goto out_free_memmap; - - /* Energy detection */ - ret = wl1271_init_energy_detection(wl); - if (ret < 0) - goto out_free_memmap; - ret = wl12xx_acx_mem_cfg(wl); if (ret < 0) goto out_free_memmap; - /* Default fragmentation threshold */ - ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold); - if (ret < 0) - goto out_free_memmap; - - /* Default TID/AC configuration */ - BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count); - for (i = 0; i < wl->conf.tx.tid_conf_count; i++) { - conf_ac = &wl->conf.tx.ac_conf[i]; - ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min, - conf_ac->cw_max, conf_ac->aifsn, - conf_ac->tx_op_limit); - if (ret < 0) - goto out_free_memmap; - - conf_tid = &wl->conf.tx.tid_conf[i]; - ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id, - conf_tid->channel_type, - conf_tid->tsid, - conf_tid->ps_scheme, - conf_tid->ack_policy, - conf_tid->apsd_conf[0], - conf_tid->apsd_conf[1]); - if (ret < 0) - goto out_free_memmap; - } - /* Enable data path */ ret = wl1271_cmd_data_path(wl, 1); if (ret < 0) @@ -768,14 +702,12 @@ static int wl1271_plt_init(struct wl1271 *wl) return ret; } -static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_pkts) +static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, + struct wl12xx_vif *wlvif, + u8 hlid, u8 tx_pkts) { bool fw_ps, single_sta; - /* only regulate station links */ - if (hlid < WL1271_AP_STA_HLID_START) - return; - fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); single_sta = (wl->active_sta_count == 1); @@ -784,7 +716,7 @@ static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_pkts) * packets in FW or if the STA is awake. */ if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS) - wl1271_ps_link_end(wl, hlid); + wl12xx_ps_link_end(wl, wlvif, hlid); /* * Start high-level PS if the STA is asleep with enough blocks in FW. @@ -792,24 +724,14 @@ static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_pkts) * case FW-memory congestion is not a problem. */ else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS) - wl1271_ps_link_start(wl, hlid, true); -} - -bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid) -{ - int id; - - /* global/broadcast "stations" are always active */ - if (hlid < WL1271_AP_STA_HLID_START) - return true; - - id = hlid - WL1271_AP_STA_HLID_START; - return test_bit(id, wl->ap_hlid_map); + wl12xx_ps_link_start(wl, wlvif, hlid, true); } static void wl12xx_irq_update_links_status(struct wl1271 *wl, + struct wl12xx_vif *wlvif, struct wl12xx_fw_status *status) { + struct wl1271_link *lnk; u32 cur_fw_ps_map; u8 hlid, cnt; @@ -825,25 +747,22 @@ static void wl12xx_irq_update_links_status(struct wl1271 *wl, wl->ap_fw_ps_map = cur_fw_ps_map; } - for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) { - if (!wl1271_is_active_sta(wl, hlid)) - continue; - - cnt = status->tx_lnk_free_pkts[hlid] - - wl->links[hlid].prev_freed_pkts; + for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS) { + lnk = &wl->links[hlid]; + cnt = status->tx_lnk_free_pkts[hlid] - lnk->prev_freed_pkts; - wl->links[hlid].prev_freed_pkts = - status->tx_lnk_free_pkts[hlid]; - wl->links[hlid].allocated_pkts -= cnt; + lnk->prev_freed_pkts = status->tx_lnk_free_pkts[hlid]; + lnk->allocated_pkts -= cnt; - wl12xx_irq_ps_regulate_link(wl, hlid, - wl->links[hlid].allocated_pkts); + wl12xx_irq_ps_regulate_link(wl, wlvif, hlid, + lnk->allocated_pkts); } } static void wl12xx_fw_status(struct wl1271 *wl, struct wl12xx_fw_status *status) { + struct wl12xx_vif *wlvif; struct timespec ts; u32 old_tx_blk_count = wl->tx_blocks_available; int avail, freed_blocks; @@ -898,8 +817,9 @@ static void wl12xx_fw_status(struct wl1271 *wl, clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); /* for AP update num of allocated TX blocks per link and ps status */ - if (wl->bss_type == BSS_TYPE_AP_BSS) - wl12xx_irq_update_links_status(wl, status); + wl12xx_for_each_wlvif_ap(wl, wlvif) { + wl12xx_irq_update_links_status(wl, wlvif, status); + } /* update the host-chipset time offset */ getnstimeofday(&ts); @@ -932,7 +852,7 @@ static void wl1271_netstack_work(struct work_struct *work) #define WL1271_IRQ_MAX_LOOPS 256 -irqreturn_t wl1271_irq(int irq, void *cookie) +static irqreturn_t wl1271_irq(int irq, void *cookie) { int ret; u32 intr; @@ -1054,7 +974,6 @@ out: return IRQ_HANDLED; } -EXPORT_SYMBOL_GPL(wl1271_irq); static int wl1271_fetch_firmware(struct wl1271 *wl) { @@ -1069,10 +988,10 @@ static int wl1271_fetch_firmware(struct wl1271 *wl) wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name); - ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl)); + ret = request_firmware(&fw, fw_name, wl->dev); if (ret < 0) { - wl1271_error("could not get firmware: %d", ret); + wl1271_error("could not get firmware %s: %d", fw_name, ret); return ret; } @@ -1107,10 +1026,11 @@ static int wl1271_fetch_nvs(struct wl1271 *wl) const struct firmware *fw; int ret; - ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl)); + ret = request_firmware(&fw, WL12XX_NVS_NAME, wl->dev); if (ret < 0) { - wl1271_error("could not get nvs file: %d", ret); + wl1271_error("could not get nvs file %s: %d", WL12XX_NVS_NAME, + ret); return ret; } @@ -1217,11 +1137,13 @@ static void wl1271_recovery_work(struct work_struct *work) { struct wl1271 *wl = container_of(work, struct wl1271, recovery_work); + struct wl12xx_vif *wlvif; + struct ieee80211_vif *vif; mutex_lock(&wl->mutex); if (wl->state != WL1271_STATE_ON) - goto out; + goto out_unlock; /* Avoid a recursive recovery */ set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags); @@ -1238,9 +1160,12 @@ static void wl1271_recovery_work(struct work_struct *work) * in the firmware during recovery. This doens't hurt if the network is * not encrypted. */ - if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) || - test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) - wl->tx_security_seq += WL1271_TX_SQN_POST_RECOVERY_PADDING; + wl12xx_for_each_wlvif(wl, wlvif) { + if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) || + test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) + wlvif->tx_security_seq += + WL1271_TX_SQN_POST_RECOVERY_PADDING; + } /* Prevent spurious TX during FW restart */ ieee80211_stop_queues(wl->hw); @@ -1251,7 +1176,14 @@ static void wl1271_recovery_work(struct work_struct *work) } /* reboot the chipset */ - __wl1271_op_remove_interface(wl, false); + while (!list_empty(&wl->wlvif_list)) { + wlvif = list_first_entry(&wl->wlvif_list, + struct wl12xx_vif, list); + vif = wl12xx_wlvif_to_vif(wlvif); + __wl1271_op_remove_interface(wl, vif, false); + } + mutex_unlock(&wl->mutex); + wl1271_op_stop(wl->hw); clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags); @@ -1262,8 +1194,8 @@ static void wl1271_recovery_work(struct work_struct *work) * to restart the HW. */ ieee80211_wake_queues(wl->hw); - -out: + return; +out_unlock: mutex_unlock(&wl->mutex); } @@ -1318,7 +1250,16 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) /* 0. read chip id from CHIP_ID */ wl->chip.id = wl1271_read32(wl, CHIP_ID_B); - /* 1. check if chip id is valid */ + /* + * For wl127x based devices we could use the default block + * size (512 bytes), but due to a bug in the sdio driver, we + * need to set it explicitly after the chip is powered on. To + * simplify the code and since the performance impact is + * negligible, we use the same block size for all different + * chip types. + */ + if (!wl1271_set_block_size(wl)) + wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT; switch (wl->chip.id) { case CHIP_ID_1271_PG10: @@ -1328,7 +1269,9 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) ret = wl1271_setup(wl); if (ret < 0) goto out; + wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT; break; + case CHIP_ID_1271_PG20: wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)", wl->chip.id); @@ -1336,7 +1279,9 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) ret = wl1271_setup(wl); if (ret < 0) goto out; + wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT; break; + case CHIP_ID_1283_PG20: wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)", wl->chip.id); @@ -1344,9 +1289,6 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) ret = wl1271_setup(wl); if (ret < 0) goto out; - - if (wl1271_set_block_size(wl)) - wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT; break; case CHIP_ID_1283_PG10: default: @@ -1389,8 +1331,6 @@ int wl1271_plt_start(struct wl1271 *wl) goto out; } - wl->bss_type = BSS_TYPE_STA_BSS; - while (retries) { retries--; ret = wl1271_chip_wakeup(wl); @@ -1482,33 +1422,34 @@ int wl1271_plt_stop(struct wl1271 *wl) static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct wl1271 *wl = hw->priv; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_vif *vif = info->control.vif; + struct wl12xx_vif *wlvif = NULL; unsigned long flags; int q, mapping; - u8 hlid = 0; + u8 hlid; + + if (vif) + wlvif = wl12xx_vif_to_data(vif); mapping = skb_get_queue_mapping(skb); q = wl1271_tx_get_queue(mapping); - if (wl->bss_type == BSS_TYPE_AP_BSS) - hlid = wl12xx_tx_get_hlid_ap(wl, skb); + hlid = wl12xx_tx_get_hlid(wl, wlvif, skb); spin_lock_irqsave(&wl->wl_lock, flags); /* queue the packet */ - if (wl->bss_type == BSS_TYPE_AP_BSS) { - if (!wl1271_is_active_sta(wl, hlid)) { - wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", - hlid, q); - dev_kfree_skb(skb); - goto out; - } - - wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q); - skb_queue_tail(&wl->links[hlid].tx_queue[q], skb); - } else { - skb_queue_tail(&wl->tx_queue[q], skb); + if (hlid == WL12XX_INVALID_LINK_ID || + (wlvif && !test_bit(hlid, wlvif->links_map))) { + wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q); + ieee80211_free_txskb(hw, skb); + goto out; } + wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q); + skb_queue_tail(&wl->links[hlid].tx_queue[q], skb); + wl->tx_queue_count[q]++; /* @@ -1609,13 +1550,14 @@ static struct notifier_block wl1271_dev_notifier = { }; #ifdef CONFIG_PM -static int wl1271_configure_suspend_sta(struct wl1271 *wl) +static int wl1271_configure_suspend_sta(struct wl1271 *wl, + struct wl12xx_vif *wlvif) { int ret = 0; mutex_lock(&wl->mutex); - if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) + if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) goto out_unlock; ret = wl1271_ps_elp_wakeup(wl); @@ -1623,12 +1565,12 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl) goto out_unlock; /* enter psm if needed*/ - if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) { + if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) { DECLARE_COMPLETION_ONSTACK(compl); - wl->ps_compl = &compl; - ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, - wl->basic_rate, true); + wlvif->ps_compl = &compl; + ret = wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE, + wlvif->basic_rate, true); if (ret < 0) goto out_sleep; @@ -1638,42 +1580,43 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl) ret = wait_for_completion_timeout( &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT)); + + mutex_lock(&wl->mutex); if (ret <= 0) { wl1271_warning("couldn't enter ps mode!"); ret = -EBUSY; - goto out; + goto out_cleanup; } - /* take mutex again, and wakeup */ - mutex_lock(&wl->mutex); - ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) - goto out_unlock; + goto out_cleanup; } out_sleep: wl1271_ps_elp_sleep(wl); +out_cleanup: + wlvif->ps_compl = NULL; out_unlock: mutex_unlock(&wl->mutex); -out: return ret; } -static int wl1271_configure_suspend_ap(struct wl1271 *wl) +static int wl1271_configure_suspend_ap(struct wl1271 *wl, + struct wl12xx_vif *wlvif) { int ret = 0; mutex_lock(&wl->mutex); - if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) + if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) goto out_unlock; ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) goto out_unlock; - ret = wl1271_acx_beacon_filter_opt(wl, true); + ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true); wl1271_ps_elp_sleep(wl); out_unlock: @@ -1682,20 +1625,22 @@ out_unlock: } -static int wl1271_configure_suspend(struct wl1271 *wl) +static int wl1271_configure_suspend(struct wl1271 *wl, + struct wl12xx_vif *wlvif) { - if (wl->bss_type == BSS_TYPE_STA_BSS) - return wl1271_configure_suspend_sta(wl); - if (wl->bss_type == BSS_TYPE_AP_BSS) - return wl1271_configure_suspend_ap(wl); + if (wlvif->bss_type == BSS_TYPE_STA_BSS) + return wl1271_configure_suspend_sta(wl, wlvif); + if (wlvif->bss_type == BSS_TYPE_AP_BSS) + return wl1271_configure_suspend_ap(wl, wlvif); return 0; } -static void wl1271_configure_resume(struct wl1271 *wl) +static void wl1271_configure_resume(struct wl1271 *wl, + struct wl12xx_vif *wlvif) { int ret; - bool is_sta = wl->bss_type == BSS_TYPE_STA_BSS; - bool is_ap = wl->bss_type == BSS_TYPE_AP_BSS; + bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS; + bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS; if (!is_sta && !is_ap) return; @@ -1707,11 +1652,11 @@ static void wl1271_configure_resume(struct wl1271 *wl) if (is_sta) { /* exit psm if it wasn't configured */ - if (!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) - wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, - wl->basic_rate, true); + if (!test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) + wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE, + wlvif->basic_rate, true); } else if (is_ap) { - wl1271_acx_beacon_filter_opt(wl, false); + wl1271_acx_beacon_filter_opt(wl, wlvif, false); } wl1271_ps_elp_sleep(wl); @@ -1723,16 +1668,19 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wow) { struct wl1271 *wl = hw->priv; + struct wl12xx_vif *wlvif; int ret; wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow); WARN_ON(!wow || !wow->any); wl->wow_enabled = true; - ret = wl1271_configure_suspend(wl); - if (ret < 0) { - wl1271_warning("couldn't prepare device to suspend"); - return ret; + wl12xx_for_each_wlvif(wl, wlvif) { + ret = wl1271_configure_suspend(wl, wlvif); + if (ret < 0) { + wl1271_warning("couldn't prepare device to suspend"); + return ret; + } } /* flush any remaining work */ wl1271_debug(DEBUG_MAC80211, "flushing remaining works"); @@ -1751,7 +1699,9 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw, wl1271_enable_interrupts(wl); flush_work(&wl->tx_work); - flush_delayed_work(&wl->pspoll_work); + wl12xx_for_each_wlvif(wl, wlvif) { + flush_delayed_work(&wlvif->pspoll_work); + } flush_delayed_work(&wl->elp_work); return 0; @@ -1760,6 +1710,7 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw, static int wl1271_op_resume(struct ieee80211_hw *hw) { struct wl1271 *wl = hw->priv; + struct wl12xx_vif *wlvif; unsigned long flags; bool run_irq_work = false; @@ -1783,7 +1734,9 @@ static int wl1271_op_resume(struct ieee80211_hw *hw) wl1271_irq(0, wl); wl1271_enable_interrupts(wl); } - wl1271_configure_resume(wl); + wl12xx_for_each_wlvif(wl, wlvif) { + wl1271_configure_resume(wl, wlvif); + } wl->wow_enabled = false; return 0; @@ -1810,20 +1763,119 @@ static int wl1271_op_start(struct ieee80211_hw *hw) static void wl1271_op_stop(struct ieee80211_hw *hw) { + struct wl1271 *wl = hw->priv; + int i; + wl1271_debug(DEBUG_MAC80211, "mac80211 stop"); + + mutex_lock(&wl->mutex); + if (wl->state == WL1271_STATE_OFF) { + mutex_unlock(&wl->mutex); + return; + } + /* + * this must be before the cancel_work calls below, so that the work + * functions don't perform further work. + */ + wl->state = WL1271_STATE_OFF; + mutex_unlock(&wl->mutex); + + mutex_lock(&wl_list_mutex); + list_del(&wl->list); + mutex_unlock(&wl_list_mutex); + + wl1271_disable_interrupts(wl); + wl1271_flush_deferred_work(wl); + cancel_delayed_work_sync(&wl->scan_complete_work); + cancel_work_sync(&wl->netstack_work); + cancel_work_sync(&wl->tx_work); + cancel_delayed_work_sync(&wl->elp_work); + + /* let's notify MAC80211 about the remaining pending TX frames */ + wl12xx_tx_reset(wl, true); + mutex_lock(&wl->mutex); + + wl1271_power_off(wl); + + wl->band = IEEE80211_BAND_2GHZ; + + wl->rx_counter = 0; + wl->power_level = WL1271_DEFAULT_POWER_LEVEL; + wl->tx_blocks_available = 0; + wl->tx_allocated_blocks = 0; + wl->tx_results_count = 0; + wl->tx_packets_count = 0; + wl->time_offset = 0; + wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT; + wl->ap_fw_ps_map = 0; + wl->ap_ps_map = 0; + wl->sched_scanning = false; + memset(wl->roles_map, 0, sizeof(wl->roles_map)); + memset(wl->links_map, 0, sizeof(wl->links_map)); + memset(wl->roc_map, 0, sizeof(wl->roc_map)); + wl->active_sta_count = 0; + + /* The system link is always allocated */ + __set_bit(WL12XX_SYSTEM_HLID, wl->links_map); + + /* + * this is performed after the cancel_work calls and the associated + * mutex_lock, so that wl1271_op_add_interface does not accidentally + * get executed before all these vars have been reset. + */ + wl->flags = 0; + + wl->tx_blocks_freed = 0; + + for (i = 0; i < NUM_TX_QUEUES; i++) { + wl->tx_pkts_freed[i] = 0; + wl->tx_allocated_pkts[i] = 0; + } + + wl1271_debugfs_reset(wl); + + kfree(wl->fw_status); + wl->fw_status = NULL; + kfree(wl->tx_res_if); + wl->tx_res_if = NULL; + kfree(wl->target_mem_map); + wl->target_mem_map = NULL; + + mutex_unlock(&wl->mutex); +} + +static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx) +{ + u8 policy = find_first_zero_bit(wl->rate_policies_map, + WL12XX_MAX_RATE_POLICIES); + if (policy >= WL12XX_MAX_RATE_POLICIES) + return -EBUSY; + + __set_bit(policy, wl->rate_policies_map); + *idx = policy; + return 0; +} + +static void wl12xx_free_rate_policy(struct wl1271 *wl, u8 *idx) +{ + if (WARN_ON(*idx >= WL12XX_MAX_RATE_POLICIES)) + return; + + __clear_bit(*idx, wl->rate_policies_map); + *idx = WL12XX_MAX_RATE_POLICIES; } -static u8 wl12xx_get_role_type(struct wl1271 *wl) +static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif) { - switch (wl->bss_type) { + switch (wlvif->bss_type) { case BSS_TYPE_AP_BSS: - if (wl->p2p) + if (wlvif->p2p) return WL1271_ROLE_P2P_GO; else return WL1271_ROLE_AP; case BSS_TYPE_STA_BSS: - if (wl->p2p) + if (wlvif->p2p) return WL1271_ROLE_P2P_CL; else return WL1271_ROLE_STA; @@ -1832,78 +1884,95 @@ static u8 wl12xx_get_role_type(struct wl1271 *wl) return WL1271_ROLE_IBSS; default: - wl1271_error("invalid bss_type: %d", wl->bss_type); + wl1271_error("invalid bss_type: %d", wlvif->bss_type); } return WL12XX_INVALID_ROLE_TYPE; } -static int wl1271_op_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) +static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif) { - struct wl1271 *wl = hw->priv; - struct wiphy *wiphy = hw->wiphy; - int retries = WL1271_BOOT_RETRIES; - int ret = 0; - u8 role_type; - bool booted = false; - - wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", - ieee80211_vif_type_p2p(vif), vif->addr); - - mutex_lock(&wl->mutex); - if (wl->vif) { - wl1271_debug(DEBUG_MAC80211, - "multiple vifs are not supported yet"); - ret = -EBUSY; - goto out; - } + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + int i; - /* - * in some very corner case HW recovery scenarios its possible to - * get here before __wl1271_op_remove_interface is complete, so - * opt out if that is the case. - */ - if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) { - ret = -EBUSY; - goto out; - } + /* clear everything but the persistent data */ + memset(wlvif, 0, offsetof(struct wl12xx_vif, persistent)); switch (ieee80211_vif_type_p2p(vif)) { case NL80211_IFTYPE_P2P_CLIENT: - wl->p2p = 1; + wlvif->p2p = 1; /* fall-through */ case NL80211_IFTYPE_STATION: - wl->bss_type = BSS_TYPE_STA_BSS; - wl->set_bss_type = BSS_TYPE_STA_BSS; + wlvif->bss_type = BSS_TYPE_STA_BSS; break; case NL80211_IFTYPE_ADHOC: - wl->bss_type = BSS_TYPE_IBSS; - wl->set_bss_type = BSS_TYPE_STA_BSS; + wlvif->bss_type = BSS_TYPE_IBSS; break; case NL80211_IFTYPE_P2P_GO: - wl->p2p = 1; + wlvif->p2p = 1; /* fall-through */ case NL80211_IFTYPE_AP: - wl->bss_type = BSS_TYPE_AP_BSS; + wlvif->bss_type = BSS_TYPE_AP_BSS; break; default: - ret = -EOPNOTSUPP; - goto out; + wlvif->bss_type = MAX_BSS_TYPE; + return -EOPNOTSUPP; } - role_type = wl12xx_get_role_type(wl); - if (role_type == WL12XX_INVALID_ROLE_TYPE) { - ret = -EINVAL; - goto out; + wlvif->role_id = WL12XX_INVALID_ROLE_ID; + wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID; + wlvif->dev_hlid = WL12XX_INVALID_LINK_ID; + + if (wlvif->bss_type == BSS_TYPE_STA_BSS || + wlvif->bss_type == BSS_TYPE_IBSS) { + /* init sta/ibss data */ + wlvif->sta.hlid = WL12XX_INVALID_LINK_ID; + wl12xx_allocate_rate_policy(wl, &wlvif->sta.basic_rate_idx); + wl12xx_allocate_rate_policy(wl, &wlvif->sta.ap_rate_idx); + wl12xx_allocate_rate_policy(wl, &wlvif->sta.p2p_rate_idx); + } else { + /* init ap data */ + wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID; + wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID; + wl12xx_allocate_rate_policy(wl, &wlvif->ap.mgmt_rate_idx); + wl12xx_allocate_rate_policy(wl, &wlvif->ap.bcast_rate_idx); + for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++) + wl12xx_allocate_rate_policy(wl, + &wlvif->ap.ucast_rate_idx[i]); } - memcpy(wl->mac_addr, vif->addr, ETH_ALEN); - if (wl->state != WL1271_STATE_OFF) { - wl1271_error("cannot start because not in off state: %d", - wl->state); - ret = -EBUSY; - goto out; - } + wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate; + wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5; + wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC; + wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC; + wlvif->rate_set = CONF_TX_RATE_MASK_BASIC; + wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT; + + /* + * mac80211 configures some values globally, while we treat them + * per-interface. thus, on init, we have to copy them from wl + */ + wlvif->band = wl->band; + wlvif->channel = wl->channel; + wlvif->power_level = wl->power_level; + + INIT_WORK(&wlvif->rx_streaming_enable_work, + wl1271_rx_streaming_enable_work); + INIT_WORK(&wlvif->rx_streaming_disable_work, + wl1271_rx_streaming_disable_work); + INIT_DELAYED_WORK(&wlvif->pspoll_work, wl1271_pspoll_work); + INIT_LIST_HEAD(&wlvif->list); + + setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer, + (unsigned long) wlvif); + return 0; +} + +static bool wl12xx_init_fw(struct wl1271 *wl) +{ + int retries = WL1271_BOOT_RETRIES; + bool booted = false; + struct wiphy *wiphy = wl->hw->wiphy; + int ret; while (retries) { retries--; @@ -1915,25 +1984,6 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, if (ret < 0) goto power_off; - if (wl->bss_type == BSS_TYPE_STA_BSS || - wl->bss_type == BSS_TYPE_IBSS) { - /* - * The device role is a special role used for - * rx and tx frames prior to association (as - * the STA role can get packets only from - * its associated bssid) - */ - ret = wl12xx_cmd_role_enable(wl, - WL1271_ROLE_DEVICE, - &wl->dev_role_id); - if (ret < 0) - goto irq_disable; - } - - ret = wl12xx_cmd_role_enable(wl, role_type, &wl->role_id); - if (ret < 0) - goto irq_disable; - ret = wl1271_hw_init(wl); if (ret < 0) goto irq_disable; @@ -1964,9 +2014,6 @@ power_off: goto out; } - wl->vif = vif; - wl->state = WL1271_STATE_ON; - set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags); wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str); /* update hw/fw version info in wiphy struct */ @@ -1984,7 +2031,110 @@ power_off: wl1271_debug(DEBUG_MAC80211, "11a is %ssupported", wl->enable_11a ? "" : "not "); + wl->state = WL1271_STATE_ON; out: + return booted; +} + +static int wl1271_op_add_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct wl1271 *wl = hw->priv; + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + int ret = 0; + u8 role_type; + bool booted = false; + + wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", + ieee80211_vif_type_p2p(vif), vif->addr); + + mutex_lock(&wl->mutex); + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out_unlock; + + if (wl->vif) { + wl1271_debug(DEBUG_MAC80211, + "multiple vifs are not supported yet"); + ret = -EBUSY; + goto out; + } + + /* + * in some very corner case HW recovery scenarios its possible to + * get here before __wl1271_op_remove_interface is complete, so + * opt out if that is the case. + */ + if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags) || + test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) { + ret = -EBUSY; + goto out; + } + + ret = wl12xx_init_vif_data(wl, vif); + if (ret < 0) + goto out; + + wlvif->wl = wl; + role_type = wl12xx_get_role_type(wl, wlvif); + if (role_type == WL12XX_INVALID_ROLE_TYPE) { + ret = -EINVAL; + goto out; + } + + /* + * TODO: after the nvs issue will be solved, move this block + * to start(), and make sure here the driver is ON. + */ + if (wl->state == WL1271_STATE_OFF) { + /* + * we still need this in order to configure the fw + * while uploading the nvs + */ + memcpy(wl->mac_addr, vif->addr, ETH_ALEN); + + booted = wl12xx_init_fw(wl); + if (!booted) { + ret = -EINVAL; + goto out; + } + } + + if (wlvif->bss_type == BSS_TYPE_STA_BSS || + wlvif->bss_type == BSS_TYPE_IBSS) { + /* + * The device role is a special role used for + * rx and tx frames prior to association (as + * the STA role can get packets only from + * its associated bssid) + */ + ret = wl12xx_cmd_role_enable(wl, vif->addr, + WL1271_ROLE_DEVICE, + &wlvif->dev_role_id); + if (ret < 0) + goto out; + } + + ret = wl12xx_cmd_role_enable(wl, vif->addr, + role_type, &wlvif->role_id); + if (ret < 0) + goto out; + + ret = wl1271_init_vif_specific(wl, vif); + if (ret < 0) + goto out; + + wl->vif = vif; + list_add(&wlvif->list, &wl->wlvif_list); + set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags); + + if (wlvif->bss_type == BSS_TYPE_AP_BSS) + wl->ap_count++; + else + wl->sta_count++; +out: + wl1271_ps_elp_sleep(wl); +out_unlock: mutex_unlock(&wl->mutex); mutex_lock(&wl_list_mutex); @@ -1996,29 +2146,34 @@ out: } static void __wl1271_op_remove_interface(struct wl1271 *wl, + struct ieee80211_vif *vif, bool reset_tx_queues) { - int ret, i; + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + int i, ret; wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface"); + if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) + return; + + wl->vif = NULL; + /* because of hardware recovery, we may get here twice */ if (wl->state != WL1271_STATE_ON) return; wl1271_info("down"); - mutex_lock(&wl_list_mutex); - list_del(&wl->list); - mutex_unlock(&wl_list_mutex); - /* enable dyn ps just in case (if left on due to fw crash etc) */ - if (wl->bss_type == BSS_TYPE_STA_BSS) - ieee80211_enable_dyn_ps(wl->vif); + if (wlvif->bss_type == BSS_TYPE_STA_BSS) + ieee80211_enable_dyn_ps(vif); - if (wl->scan.state != WL1271_SCAN_STATE_IDLE) { + if (wl->scan.state != WL1271_SCAN_STATE_IDLE && + wl->scan_vif == vif) { wl->scan.state = WL1271_SCAN_STATE_IDLE; memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); + wl->scan_vif = NULL; wl->scan.req = NULL; ieee80211_scan_completed(wl->hw, true); } @@ -2029,13 +2184,13 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, if (ret < 0) goto deinit; - if (wl->bss_type == BSS_TYPE_STA_BSS) { - ret = wl12xx_cmd_role_disable(wl, &wl->dev_role_id); + if (wlvif->bss_type == BSS_TYPE_STA_BSS) { + ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id); if (ret < 0) goto deinit; } - ret = wl12xx_cmd_role_disable(wl, &wl->role_id); + ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id); if (ret < 0) goto deinit; @@ -2043,120 +2198,82 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, } deinit: /* clear all hlids (except system_hlid) */ - wl->sta_hlid = WL12XX_INVALID_LINK_ID; - wl->dev_hlid = WL12XX_INVALID_LINK_ID; - wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID; - wl->ap_global_hlid = WL12XX_INVALID_LINK_ID; + wlvif->dev_hlid = WL12XX_INVALID_LINK_ID; + + if (wlvif->bss_type == BSS_TYPE_STA_BSS || + wlvif->bss_type == BSS_TYPE_IBSS) { + wlvif->sta.hlid = WL12XX_INVALID_LINK_ID; + wl12xx_free_rate_policy(wl, &wlvif->sta.basic_rate_idx); + wl12xx_free_rate_policy(wl, &wlvif->sta.ap_rate_idx); + wl12xx_free_rate_policy(wl, &wlvif->sta.p2p_rate_idx); + } else { + wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID; + wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID; + wl12xx_free_rate_policy(wl, &wlvif->ap.mgmt_rate_idx); + wl12xx_free_rate_policy(wl, &wlvif->ap.bcast_rate_idx); + for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++) + wl12xx_free_rate_policy(wl, + &wlvif->ap.ucast_rate_idx[i]); + } - /* - * this must be before the cancel_work calls below, so that the work - * functions don't perform further work. - */ - wl->state = WL1271_STATE_OFF; + wl12xx_tx_reset_wlvif(wl, wlvif); + wl1271_free_ap_keys(wl, wlvif); + if (wl->last_wlvif == wlvif) + wl->last_wlvif = NULL; + list_del(&wlvif->list); + memset(wlvif->ap.sta_hlid_map, 0, sizeof(wlvif->ap.sta_hlid_map)); + wlvif->role_id = WL12XX_INVALID_ROLE_ID; + wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID; + + if (wlvif->bss_type == BSS_TYPE_AP_BSS) + wl->ap_count--; + else + wl->sta_count--; mutex_unlock(&wl->mutex); - - wl1271_disable_interrupts(wl); - wl1271_flush_deferred_work(wl); - cancel_delayed_work_sync(&wl->scan_complete_work); - cancel_work_sync(&wl->netstack_work); - cancel_work_sync(&wl->tx_work); - del_timer_sync(&wl->rx_streaming_timer); - cancel_work_sync(&wl->rx_streaming_enable_work); - cancel_work_sync(&wl->rx_streaming_disable_work); - cancel_delayed_work_sync(&wl->pspoll_work); - cancel_delayed_work_sync(&wl->elp_work); + del_timer_sync(&wlvif->rx_streaming_timer); + cancel_work_sync(&wlvif->rx_streaming_enable_work); + cancel_work_sync(&wlvif->rx_streaming_disable_work); + cancel_delayed_work_sync(&wlvif->pspoll_work); mutex_lock(&wl->mutex); - - /* let's notify MAC80211 about the remaining pending TX frames */ - wl1271_tx_reset(wl, reset_tx_queues); - wl1271_power_off(wl); - - memset(wl->bssid, 0, ETH_ALEN); - memset(wl->ssid, 0, IEEE80211_MAX_SSID_LEN + 1); - wl->ssid_len = 0; - wl->bss_type = MAX_BSS_TYPE; - wl->set_bss_type = MAX_BSS_TYPE; - wl->p2p = 0; - wl->band = IEEE80211_BAND_2GHZ; - - wl->rx_counter = 0; - wl->psm_entry_retry = 0; - wl->power_level = WL1271_DEFAULT_POWER_LEVEL; - wl->tx_blocks_available = 0; - wl->tx_allocated_blocks = 0; - wl->tx_results_count = 0; - wl->tx_packets_count = 0; - wl->time_offset = 0; - wl->session_counter = 0; - wl->rate_set = CONF_TX_RATE_MASK_BASIC; - wl->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate; - wl->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5; - wl->vif = NULL; - wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT; - wl1271_free_ap_keys(wl); - memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map)); - wl->ap_fw_ps_map = 0; - wl->ap_ps_map = 0; - wl->sched_scanning = false; - wl->role_id = WL12XX_INVALID_ROLE_ID; - wl->dev_role_id = WL12XX_INVALID_ROLE_ID; - memset(wl->roles_map, 0, sizeof(wl->roles_map)); - memset(wl->links_map, 0, sizeof(wl->links_map)); - memset(wl->roc_map, 0, sizeof(wl->roc_map)); - wl->active_sta_count = 0; - - /* The system link is always allocated */ - __set_bit(WL12XX_SYSTEM_HLID, wl->links_map); - - /* - * this is performed after the cancel_work calls and the associated - * mutex_lock, so that wl1271_op_add_interface does not accidentally - * get executed before all these vars have been reset. - */ - wl->flags = 0; - - wl->tx_blocks_freed = 0; - - for (i = 0; i < NUM_TX_QUEUES; i++) { - wl->tx_pkts_freed[i] = 0; - wl->tx_allocated_pkts[i] = 0; - } - - wl1271_debugfs_reset(wl); - - kfree(wl->fw_status); - wl->fw_status = NULL; - kfree(wl->tx_res_if); - wl->tx_res_if = NULL; - kfree(wl->target_mem_map); - wl->target_mem_map = NULL; } static void wl1271_op_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct wl1271 *wl = hw->priv; + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + struct wl12xx_vif *iter; mutex_lock(&wl->mutex); + + if (wl->state == WL1271_STATE_OFF || + !test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) + goto out; + /* * wl->vif can be null here if someone shuts down the interface * just when hardware recovery has been started. */ - if (wl->vif) { - WARN_ON(wl->vif != vif); - __wl1271_op_remove_interface(wl, true); - } + wl12xx_for_each_wlvif(wl, iter) { + if (iter != wlvif) + continue; + __wl1271_op_remove_interface(wl, vif, true); + break; + } + WARN_ON(iter != wlvif); +out: mutex_unlock(&wl->mutex); cancel_work_sync(&wl->recovery_work); } -static int wl1271_join(struct wl1271 *wl, bool set_assoc) +static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif, + bool set_assoc) { int ret; - bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS); + bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS); /* * One of the side effects of the JOIN command is that is clears @@ -2167,20 +2284,20 @@ static int wl1271_join(struct wl1271 *wl, bool set_assoc) * Keep the below message for now, unless it starts bothering * users who really like to roam a lot :) */ - if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) + if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) wl1271_info("JOIN while associated."); if (set_assoc) - set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags); + set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags); if (is_ibss) - ret = wl12xx_cmd_role_start_ibss(wl); + ret = wl12xx_cmd_role_start_ibss(wl, wlvif); else - ret = wl12xx_cmd_role_start_sta(wl); + ret = wl12xx_cmd_role_start_sta(wl, wlvif); if (ret < 0) goto out; - if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) + if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) goto out; /* @@ -2189,19 +2306,20 @@ static int wl1271_join(struct wl1271 *wl, bool set_assoc) * the join. The acx_aid starts the keep-alive process, and the order * of the commands below is relevant. */ - ret = wl1271_acx_keep_alive_mode(wl, true); + ret = wl1271_acx_keep_alive_mode(wl, wlvif, true); if (ret < 0) goto out; - ret = wl1271_acx_aid(wl, wl->aid); + ret = wl1271_acx_aid(wl, wlvif, wlvif->aid); if (ret < 0) goto out; - ret = wl1271_cmd_build_klv_null_data(wl); + ret = wl12xx_cmd_build_klv_null_data(wl, wlvif); if (ret < 0) goto out; - ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA, + ret = wl1271_acx_keep_alive_config(wl, wlvif, + CMD_TEMPL_KLV_IDX_NULL_DATA, ACX_KEEP_ALIVE_TPL_VALID); if (ret < 0) goto out; @@ -2210,34 +2328,34 @@ out: return ret; } -static int wl1271_unjoin(struct wl1271 *wl) +static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif) { int ret; - if (test_and_clear_bit(WL1271_FLAG_CS_PROGRESS, &wl->flags)) { + if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) { + struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); + wl12xx_cmd_stop_channel_switch(wl); - ieee80211_chswitch_done(wl->vif, false); + ieee80211_chswitch_done(vif, false); } /* to stop listening to a channel, we disconnect */ - ret = wl12xx_cmd_role_stop_sta(wl); + ret = wl12xx_cmd_role_stop_sta(wl, wlvif); if (ret < 0) goto out; - memset(wl->bssid, 0, ETH_ALEN); - /* reset TX security counters on a clean disconnect */ - wl->tx_security_last_seq_lsb = 0; - wl->tx_security_seq = 0; + wlvif->tx_security_last_seq_lsb = 0; + wlvif->tx_security_seq = 0; out: return ret; } -static void wl1271_set_band_rate(struct wl1271 *wl) +static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif) { - wl->basic_rate_set = wl->bitrate_masks[wl->band]; - wl->rate_set = wl->basic_rate_set; + wlvif->basic_rate_set = wlvif->bitrate_masks[wlvif->band]; + wlvif->rate_set = wlvif->basic_rate_set; } static bool wl12xx_is_roc(struct wl1271 *wl) @@ -2251,27 +2369,25 @@ static bool wl12xx_is_roc(struct wl1271 *wl) return true; } -static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle) +static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif, + bool idle) { int ret; if (idle) { /* no need to croc if we weren't busy (e.g. during boot) */ if (wl12xx_is_roc(wl)) { - ret = wl12xx_croc(wl, wl->dev_role_id); - if (ret < 0) - goto out; - - ret = wl12xx_cmd_role_stop_dev(wl); + ret = wl12xx_stop_dev(wl, wlvif); if (ret < 0) goto out; } - wl->rate_set = wl1271_tx_min_rate_get(wl, wl->basic_rate_set); - ret = wl1271_acx_sta_rate_policies(wl); + wlvif->rate_set = + wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); + ret = wl1271_acx_sta_rate_policies(wl, wlvif); if (ret < 0) goto out; ret = wl1271_acx_keep_alive_config( - wl, CMD_TEMPL_KLV_IDX_NULL_DATA, + wl, wlvif, CMD_TEMPL_KLV_IDX_NULL_DATA, ACX_KEEP_ALIVE_TPL_INVALID); if (ret < 0) goto out; @@ -2283,11 +2399,7 @@ static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle) ieee80211_sched_scan_stopped(wl->hw); } - ret = wl12xx_cmd_role_start_dev(wl); - if (ret < 0) - goto out; - - ret = wl12xx_roc(wl, wl->dev_role_id); + ret = wl12xx_start_dev(wl, wlvif); if (ret < 0) goto out; clear_bit(WL1271_FLAG_IDLE, &wl->flags); @@ -2297,61 +2409,22 @@ out: return ret; } -static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) +static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif, + struct ieee80211_conf *conf, u32 changed) { - struct wl1271 *wl = hw->priv; - struct ieee80211_conf *conf = &hw->conf; - int channel, ret = 0; - bool is_ap; + bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); + int channel, ret; channel = ieee80211_frequency_to_channel(conf->channel->center_freq); - wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s" - " changed 0x%x", - channel, - conf->flags & IEEE80211_CONF_PS ? "on" : "off", - conf->power_level, - conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use", - changed); - - /* - * mac80211 will go to idle nearly immediately after transmitting some - * frames, such as the deauth. To make sure those frames reach the air, - * wait here until the TX queue is fully flushed. - */ - if ((changed & IEEE80211_CONF_CHANGE_IDLE) && - (conf->flags & IEEE80211_CONF_IDLE)) - wl1271_tx_flush(wl); - - mutex_lock(&wl->mutex); - - if (unlikely(wl->state == WL1271_STATE_OFF)) { - /* we support configuring the channel and band while off */ - if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) { - wl->band = conf->channel->band; - wl->channel = channel; - } - - if ((changed & IEEE80211_CONF_CHANGE_POWER)) - wl->power_level = conf->power_level; - - goto out; - } - - is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); - - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - /* if the channel changes while joined, join again */ if (changed & IEEE80211_CONF_CHANGE_CHANNEL && - ((wl->band != conf->channel->band) || - (wl->channel != channel))) { + ((wlvif->band != conf->channel->band) || + (wlvif->channel != channel))) { /* send all pending packets */ wl1271_tx_work_locked(wl); - wl->band = conf->channel->band; - wl->channel = channel; + wlvif->band = conf->channel->band; + wlvif->channel = channel; if (!is_ap) { /* @@ -2360,24 +2433,27 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) * possible rate for the band as a fixed rate for * association frames and other control messages. */ - if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) - wl1271_set_band_rate(wl); + if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) + wl1271_set_band_rate(wl, wlvif); - wl->basic_rate = - wl1271_tx_min_rate_get(wl, wl->basic_rate_set); - ret = wl1271_acx_sta_rate_policies(wl); + wlvif->basic_rate = + wl1271_tx_min_rate_get(wl, + wlvif->basic_rate_set); + ret = wl1271_acx_sta_rate_policies(wl, wlvif); if (ret < 0) wl1271_warning("rate policy for channel " "failed %d", ret); - if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) { + if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, + &wlvif->flags)) { if (wl12xx_is_roc(wl)) { /* roaming */ - ret = wl12xx_croc(wl, wl->dev_role_id); + ret = wl12xx_croc(wl, + wlvif->dev_role_id); if (ret < 0) - goto out_sleep; + return ret; } - ret = wl1271_join(wl, false); + ret = wl1271_join(wl, wlvif, false); if (ret < 0) wl1271_warning("cmd join on channel " "failed %d", ret); @@ -2389,64 +2465,112 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) */ if (wl12xx_is_roc(wl) && !(conf->flags & IEEE80211_CONF_IDLE)) { - ret = wl12xx_croc(wl, wl->dev_role_id); + ret = wl12xx_stop_dev(wl, wlvif); if (ret < 0) - goto out_sleep; + return ret; - ret = wl12xx_roc(wl, wl->dev_role_id); + ret = wl12xx_start_dev(wl, wlvif); if (ret < 0) - wl1271_warning("roc failed %d", - ret); + return ret; } } } } - if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) { - ret = wl1271_sta_handle_idle(wl, - conf->flags & IEEE80211_CONF_IDLE); - if (ret < 0) - wl1271_warning("idle mode change failed %d", ret); - } - /* * if mac80211 changes the PSM mode, make sure the mode is not * incorrectly changed after the pspoll failure active window. */ if (changed & IEEE80211_CONF_CHANGE_PS) - clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags); + clear_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags); if (conf->flags & IEEE80211_CONF_PS && - !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) { - set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags); + !test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) { + set_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags); /* * We enter PSM only if we're already associated. * If we're not, we'll enter it when joining an SSID, * through the bss_info_changed() hook. */ - if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) { + if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) { wl1271_debug(DEBUG_PSM, "psm enabled"); - ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, - wl->basic_rate, true); + ret = wl1271_ps_set_mode(wl, wlvif, + STATION_POWER_SAVE_MODE, + wlvif->basic_rate, true); } } else if (!(conf->flags & IEEE80211_CONF_PS) && - test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) { + test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) { wl1271_debug(DEBUG_PSM, "psm disabled"); - clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags); + clear_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags); - if (test_bit(WL1271_FLAG_PSM, &wl->flags)) - ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, - wl->basic_rate, true); + if (test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) + ret = wl1271_ps_set_mode(wl, wlvif, + STATION_ACTIVE_MODE, + wlvif->basic_rate, true); } - if (conf->power_level != wl->power_level) { - ret = wl1271_acx_tx_power(wl, conf->power_level); + if (conf->power_level != wlvif->power_level) { + ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level); if (ret < 0) - goto out_sleep; + return ret; + + wlvif->power_level = conf->power_level; + } + + return 0; +} + +static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) +{ + struct wl1271 *wl = hw->priv; + struct wl12xx_vif *wlvif; + struct ieee80211_conf *conf = &hw->conf; + int channel, ret = 0; + + channel = ieee80211_frequency_to_channel(conf->channel->center_freq); + + wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s" + " changed 0x%x", + channel, + conf->flags & IEEE80211_CONF_PS ? "on" : "off", + conf->power_level, + conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use", + changed); + + /* + * mac80211 will go to idle nearly immediately after transmitting some + * frames, such as the deauth. To make sure those frames reach the air, + * wait here until the TX queue is fully flushed. + */ + if ((changed & IEEE80211_CONF_CHANGE_IDLE) && + (conf->flags & IEEE80211_CONF_IDLE)) + wl1271_tx_flush(wl); + + mutex_lock(&wl->mutex); + + /* we support configuring the channel and band even while off */ + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { + wl->band = conf->channel->band; + wl->channel = channel; + } + if (changed & IEEE80211_CONF_CHANGE_POWER) wl->power_level = conf->power_level; + + if (unlikely(wl->state == WL1271_STATE_OFF)) + goto out; + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + /* configure each interface */ + wl12xx_for_each_wlvif(wl, wlvif) { + ret = wl12xx_config_vif(wl, wlvif, conf, changed); + if (ret < 0) + goto out_sleep; } out_sleep: @@ -2509,6 +2633,8 @@ static void wl1271_op_configure_filter(struct ieee80211_hw *hw, { struct wl1271_filter_params *fp = (void *)(unsigned long)multicast; struct wl1271 *wl = hw->priv; + struct wl12xx_vif *wlvif; + int ret; wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x" @@ -2526,15 +2652,20 @@ static void wl1271_op_configure_filter(struct ieee80211_hw *hw, if (ret < 0) goto out; - if (wl->bss_type != BSS_TYPE_AP_BSS) { - if (*total & FIF_ALLMULTI) - ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0); - else if (fp) - ret = wl1271_acx_group_address_tbl(wl, fp->enabled, - fp->mc_list, - fp->mc_list_length); - if (ret < 0) - goto out_sleep; + wl12xx_for_each_wlvif(wl, wlvif) { + if (wlvif->bss_type != BSS_TYPE_AP_BSS) { + if (*total & FIF_ALLMULTI) + ret = wl1271_acx_group_address_tbl(wl, wlvif, + false, + NULL, 0); + else if (fp) + ret = wl1271_acx_group_address_tbl(wl, wlvif, + fp->enabled, + fp->mc_list, + fp->mc_list_length); + if (ret < 0) + goto out_sleep; + } } /* @@ -2551,9 +2682,10 @@ out: kfree(fp); } -static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type, - u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32, - u16 tx_seq_16) +static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u8 id, u8 key_type, u8 key_size, + const u8 *key, u8 hlid, u32 tx_seq_32, + u16 tx_seq_16) { struct wl1271_ap_key *ap_key; int i; @@ -2568,10 +2700,10 @@ static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type, * an existing key. */ for (i = 0; i < MAX_NUM_KEYS; i++) { - if (wl->recorded_ap_keys[i] == NULL) + if (wlvif->ap.recorded_keys[i] == NULL) break; - if (wl->recorded_ap_keys[i]->id == id) { + if (wlvif->ap.recorded_keys[i]->id == id) { wl1271_warning("trying to record key replacement"); return -EINVAL; } @@ -2592,21 +2724,21 @@ static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type, ap_key->tx_seq_32 = tx_seq_32; ap_key->tx_seq_16 = tx_seq_16; - wl->recorded_ap_keys[i] = ap_key; + wlvif->ap.recorded_keys[i] = ap_key; return 0; } -static void wl1271_free_ap_keys(struct wl1271 *wl) +static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif) { int i; for (i = 0; i < MAX_NUM_KEYS; i++) { - kfree(wl->recorded_ap_keys[i]); - wl->recorded_ap_keys[i] = NULL; + kfree(wlvif->ap.recorded_keys[i]); + wlvif->ap.recorded_keys[i] = NULL; } } -static int wl1271_ap_init_hwenc(struct wl1271 *wl) +static int wl1271_ap_init_hwenc(struct wl1271 *wl, struct wl12xx_vif *wlvif) { int i, ret = 0; struct wl1271_ap_key *key; @@ -2614,15 +2746,15 @@ static int wl1271_ap_init_hwenc(struct wl1271 *wl) for (i = 0; i < MAX_NUM_KEYS; i++) { u8 hlid; - if (wl->recorded_ap_keys[i] == NULL) + if (wlvif->ap.recorded_keys[i] == NULL) break; - key = wl->recorded_ap_keys[i]; + key = wlvif->ap.recorded_keys[i]; hlid = key->hlid; if (hlid == WL12XX_INVALID_LINK_ID) - hlid = wl->ap_bcast_hlid; + hlid = wlvif->ap.bcast_hlid; - ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE, + ret = wl1271_cmd_set_ap_key(wl, wlvif, KEY_ADD_OR_REPLACE, key->id, key->key_type, key->key_size, key->key, hlid, key->tx_seq_32, @@ -2635,23 +2767,24 @@ static int wl1271_ap_init_hwenc(struct wl1271 *wl) } if (wep_key_added) { - ret = wl12xx_cmd_set_default_wep_key(wl, wl->default_key, - wl->ap_bcast_hlid); + ret = wl12xx_cmd_set_default_wep_key(wl, wlvif->default_key, + wlvif->ap.bcast_hlid); if (ret < 0) goto out; } out: - wl1271_free_ap_keys(wl); + wl1271_free_ap_keys(wl, wlvif); return ret; } -static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, +static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u16 action, u8 id, u8 key_type, u8 key_size, const u8 *key, u32 tx_seq_32, u16 tx_seq_16, struct ieee80211_sta *sta) { int ret; - bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); + bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); if (is_ap) { struct wl1271_station *wl_sta; @@ -2661,10 +2794,10 @@ static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, wl_sta = (struct wl1271_station *)sta->drv_priv; hlid = wl_sta->hlid; } else { - hlid = wl->ap_bcast_hlid; + hlid = wlvif->ap.bcast_hlid; } - if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) { + if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) { /* * We do not support removing keys after AP shutdown. * Pretend we do to make mac80211 happy. @@ -2672,12 +2805,12 @@ static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, if (action != KEY_ADD_OR_REPLACE) return 0; - ret = wl1271_record_ap_key(wl, id, + ret = wl1271_record_ap_key(wl, wlvif, id, key_type, key_size, key, hlid, tx_seq_32, tx_seq_16); } else { - ret = wl1271_cmd_set_ap_key(wl, action, + ret = wl1271_cmd_set_ap_key(wl, wlvif, action, id, key_type, key_size, key, hlid, tx_seq_32, tx_seq_16); @@ -2718,10 +2851,10 @@ static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, /* don't remove key if hlid was already deleted */ if (action == KEY_REMOVE && - wl->sta_hlid == WL12XX_INVALID_LINK_ID) + wlvif->sta.hlid == WL12XX_INVALID_LINK_ID) return 0; - ret = wl1271_cmd_set_sta_key(wl, action, + ret = wl1271_cmd_set_sta_key(wl, wlvif, action, id, key_type, key_size, key, addr, tx_seq_32, tx_seq_16); @@ -2731,8 +2864,8 @@ static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, /* the default WEP key needs to be configured at least once */ if (key_type == KEY_WEP) { ret = wl12xx_cmd_set_default_wep_key(wl, - wl->default_key, - wl->sta_hlid); + wlvif->default_key, + wlvif->sta.hlid); if (ret < 0) return ret; } @@ -2747,6 +2880,7 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_key_conf *key_conf) { struct wl1271 *wl = hw->priv; + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); int ret; u32 tx_seq_32 = 0; u16 tx_seq_16 = 0; @@ -2782,20 +2916,20 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, key_type = KEY_TKIP; key_conf->hw_key_idx = key_conf->keyidx; - tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq); - tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq); + tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq); + tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq); break; case WLAN_CIPHER_SUITE_CCMP: key_type = KEY_AES; - key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; - tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq); - tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq); + key_conf->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE; + tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq); + tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq); break; case WL1271_CIPHER_SUITE_GEM: key_type = KEY_GEM; - tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq); - tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq); + tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq); + tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq); break; default: wl1271_error("Unknown key algo 0x%x", key_conf->cipher); @@ -2806,7 +2940,7 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, switch (cmd) { case SET_KEY: - ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE, + ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE, key_conf->keyidx, key_type, key_conf->keylen, key_conf->key, tx_seq_32, tx_seq_16, sta); @@ -2817,7 +2951,7 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, break; case DISABLE_KEY: - ret = wl1271_set_key(wl, KEY_REMOVE, + ret = wl1271_set_key(wl, wlvif, KEY_REMOVE, key_conf->keyidx, key_type, key_conf->keylen, key_conf->key, 0, 0, sta); @@ -2847,6 +2981,8 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw, struct cfg80211_scan_request *req) { struct wl1271 *wl = hw->priv; + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + int ret; u8 *ssid = NULL; size_t len = 0; @@ -2876,16 +3012,15 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw, /* cancel ROC before scanning */ if (wl12xx_is_roc(wl)) { - if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) { + if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) { /* don't allow scanning right now */ ret = -EBUSY; goto out_sleep; } - wl12xx_croc(wl, wl->dev_role_id); - wl12xx_cmd_role_stop_dev(wl); + wl12xx_stop_dev(wl, wlvif); } - ret = wl1271_scan(hw->priv, ssid, len, req); + ret = wl1271_scan(hw->priv, vif, ssid, len, req); out_sleep: wl1271_ps_elp_sleep(wl); out: @@ -2921,6 +3056,7 @@ static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw, } wl->scan.state = WL1271_SCAN_STATE_IDLE; memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); + wl->scan_vif = NULL; wl->scan.req = NULL; ieee80211_scan_completed(wl->hw, true); @@ -2938,6 +3074,7 @@ static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw, struct ieee80211_sched_scan_ies *ies) { struct wl1271 *wl = hw->priv; + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); int ret; wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start"); @@ -2948,11 +3085,11 @@ static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw, if (ret < 0) goto out; - ret = wl1271_scan_sched_scan_config(wl, req, ies); + ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies); if (ret < 0) goto out_sleep; - ret = wl1271_scan_sched_scan_start(wl); + ret = wl1271_scan_sched_scan_start(wl, wlvif); if (ret < 0) goto out_sleep; @@ -3017,6 +3154,7 @@ out: static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) { struct wl1271 *wl = hw->priv; + struct wl12xx_vif *wlvif; int ret = 0; mutex_lock(&wl->mutex); @@ -3030,10 +3168,11 @@ static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) if (ret < 0) goto out; - ret = wl1271_acx_rts_threshold(wl, value); - if (ret < 0) - wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret); - + wl12xx_for_each_wlvif(wl, wlvif) { + ret = wl1271_acx_rts_threshold(wl, wlvif, value); + if (ret < 0) + wl1271_warning("set rts threshold failed: %d", ret); + } wl1271_ps_elp_sleep(wl); out: @@ -3042,9 +3181,10 @@ out: return ret; } -static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb, +static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb, int offset) { + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); u8 ssid_len; const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset, skb->len - offset); @@ -3060,8 +3200,8 @@ static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb, return -EINVAL; } - wl->ssid_len = ssid_len; - memcpy(wl->ssid, ptr+2, ssid_len); + wlvif->ssid_len = ssid_len; + memcpy(wlvif->ssid, ptr+2, ssid_len); return 0; } @@ -3096,18 +3236,40 @@ static void wl12xx_remove_vendor_ie(struct sk_buff *skb, skb_trim(skb, skb->len - len); } -static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, - u8 *probe_rsp_data, - size_t probe_rsp_len, - u32 rates) +static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates, + struct ieee80211_vif *vif) { - struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf; + struct sk_buff *skb; + int ret; + + skb = ieee80211_proberesp_get(wl->hw, vif); + if (!skb) + return -EOPNOTSUPP; + + ret = wl1271_cmd_template_set(wl, + CMD_TEMPL_AP_PROBE_RESPONSE, + skb->data, + skb->len, 0, + rates); + + dev_kfree_skb(skb); + return ret; +} + +static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl, + struct ieee80211_vif *vif, + u8 *probe_rsp_data, + size_t probe_rsp_len, + u32 rates) +{ + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE]; int ssid_ie_offset, ie_offset, templ_len; const u8 *ptr; /* no need to change probe response if the SSID is set correctly */ - if (wl->ssid_len > 0) + if (wlvif->ssid_len > 0) return wl1271_cmd_template_set(wl, CMD_TEMPL_AP_PROBE_RESPONSE, probe_rsp_data, @@ -3153,16 +3315,18 @@ static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, } static int wl1271_bss_erp_info_changed(struct wl1271 *wl, + struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, u32 changed) { + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); int ret = 0; if (changed & BSS_CHANGED_ERP_SLOT) { if (bss_conf->use_short_slot) - ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT); + ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT); else - ret = wl1271_acx_slot(wl, SLOT_TIME_LONG); + ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG); if (ret < 0) { wl1271_warning("Set slot time failed %d", ret); goto out; @@ -3171,16 +3335,18 @@ static int wl1271_bss_erp_info_changed(struct wl1271 *wl, if (changed & BSS_CHANGED_ERP_PREAMBLE) { if (bss_conf->use_short_preamble) - wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT); + wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT); else - wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG); + wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG); } if (changed & BSS_CHANGED_ERP_CTS_PROT) { if (bss_conf->use_cts_prot) - ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE); + ret = wl1271_acx_cts_protect(wl, wlvif, + CTSPROTECT_ENABLE); else - ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE); + ret = wl1271_acx_cts_protect(wl, wlvif, + CTSPROTECT_DISABLE); if (ret < 0) { wl1271_warning("Set ctsprotect failed %d", ret); goto out; @@ -3196,14 +3362,23 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl, struct ieee80211_bss_conf *bss_conf, u32 changed) { - bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); int ret = 0; if ((changed & BSS_CHANGED_BEACON_INT)) { wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d", bss_conf->beacon_int); - wl->beacon_int = bss_conf->beacon_int; + wlvif->beacon_int = bss_conf->beacon_int; + } + + if ((changed & BSS_CHANGED_AP_PROBE_RESP) && is_ap) { + u32 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); + if (!wl1271_ap_set_probe_resp_tmpl(wl, rate, vif)) { + wl1271_debug(DEBUG_AP, "probe response updated"); + set_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags); + } } if ((changed & BSS_CHANGED_BEACON)) { @@ -3214,17 +3389,19 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl, struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif); u16 tmpl_id; - if (!beacon) + if (!beacon) { + ret = -EINVAL; goto out; + } wl1271_debug(DEBUG_MASTER, "beacon updated"); - ret = wl1271_ssid_set(wl, beacon, ieoffset); + ret = wl1271_ssid_set(vif, beacon, ieoffset); if (ret < 0) { dev_kfree_skb(beacon); goto out; } - min_rate = wl1271_tx_min_rate_get(wl, wl->basic_rate_set); + min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON : CMD_TEMPL_BEACON; ret = wl1271_cmd_template_set(wl, tmpl_id, @@ -3236,6 +3413,13 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl, goto out; } + /* + * In case we already have a probe-resp beacon set explicitly + * by usermode, don't use the beacon data. + */ + if (test_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags)) + goto end_bcn; + /* remove TIM ie from probe response */ wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset); @@ -3254,7 +3438,7 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl, hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP); if (is_ap) - ret = wl1271_ap_set_probe_resp_tmpl(wl, + ret = wl1271_ap_set_probe_resp_tmpl_legacy(wl, vif, beacon->data, beacon->len, min_rate); @@ -3264,12 +3448,15 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl, beacon->data, beacon->len, 0, min_rate); +end_bcn: dev_kfree_skb(beacon); if (ret < 0) goto out; } out: + if (ret != 0) + wl1271_error("beacon info change failed: %d", ret); return ret; } @@ -3279,23 +3466,24 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl, struct ieee80211_bss_conf *bss_conf, u32 changed) { + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); int ret = 0; if ((changed & BSS_CHANGED_BASIC_RATES)) { u32 rates = bss_conf->basic_rates; - wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates, - wl->band); - wl->basic_rate = wl1271_tx_min_rate_get(wl, - wl->basic_rate_set); + wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates, + wlvif->band); + wlvif->basic_rate = wl1271_tx_min_rate_get(wl, + wlvif->basic_rate_set); - ret = wl1271_init_ap_rates(wl); + ret = wl1271_init_ap_rates(wl, wlvif); if (ret < 0) { wl1271_error("AP rate policy change failed %d", ret); goto out; } - ret = wl1271_ap_init_templates(wl); + ret = wl1271_ap_init_templates(wl, vif); if (ret < 0) goto out; } @@ -3306,38 +3494,40 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl, if ((changed & BSS_CHANGED_BEACON_ENABLED)) { if (bss_conf->enable_beacon) { - if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) { - ret = wl12xx_cmd_role_start_ap(wl); + if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) { + ret = wl12xx_cmd_role_start_ap(wl, wlvif); if (ret < 0) goto out; - ret = wl1271_ap_init_hwenc(wl); + ret = wl1271_ap_init_hwenc(wl, wlvif); if (ret < 0) goto out; - set_bit(WL1271_FLAG_AP_STARTED, &wl->flags); + set_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags); wl1271_debug(DEBUG_AP, "started AP"); } } else { - if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) { - ret = wl12xx_cmd_role_stop_ap(wl); + if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) { + ret = wl12xx_cmd_role_stop_ap(wl, wlvif); if (ret < 0) goto out; - clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags); + clear_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags); + clear_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, + &wlvif->flags); wl1271_debug(DEBUG_AP, "stopped AP"); } } } - ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed); + ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed); if (ret < 0) goto out; /* Handle HT information change */ if ((changed & BSS_CHANGED_HT) && (bss_conf->channel_type != NL80211_CHAN_NO_HT)) { - ret = wl1271_acx_set_ht_information(wl, + ret = wl1271_acx_set_ht_information(wl, wlvif, bss_conf->ht_operation_mode); if (ret < 0) { wl1271_warning("Set ht information failed %d", ret); @@ -3355,8 +3545,9 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, struct ieee80211_bss_conf *bss_conf, u32 changed) { + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); bool do_join = false, set_assoc = false; - bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS); + bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS); bool ibss_joined = false; u32 sta_rate_set = 0; int ret; @@ -3373,14 +3564,13 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, if (changed & BSS_CHANGED_IBSS) { if (bss_conf->ibss_joined) { - set_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags); + set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags); ibss_joined = true; } else { - if (test_and_clear_bit(WL1271_FLAG_IBSS_JOINED, - &wl->flags)) { - wl1271_unjoin(wl); - wl12xx_cmd_role_start_dev(wl); - wl12xx_roc(wl, wl->dev_role_id); + if (test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED, + &wlvif->flags)) { + wl1271_unjoin(wl, wlvif); + wl12xx_start_dev(wl, wlvif); } } } @@ -3396,46 +3586,40 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s", bss_conf->enable_beacon ? "enabled" : "disabled"); - if (bss_conf->enable_beacon) - wl->set_bss_type = BSS_TYPE_IBSS; - else - wl->set_bss_type = BSS_TYPE_STA_BSS; do_join = true; } + if (changed & BSS_CHANGED_IDLE) { + ret = wl1271_sta_handle_idle(wl, wlvif, bss_conf->idle); + if (ret < 0) + wl1271_warning("idle mode change failed %d", ret); + } + if ((changed & BSS_CHANGED_CQM)) { bool enable = false; if (bss_conf->cqm_rssi_thold) enable = true; - ret = wl1271_acx_rssi_snr_trigger(wl, enable, + ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable, bss_conf->cqm_rssi_thold, bss_conf->cqm_rssi_hyst); if (ret < 0) goto out; - wl->rssi_thold = bss_conf->cqm_rssi_thold; + wlvif->rssi_thold = bss_conf->cqm_rssi_thold; } - if ((changed & BSS_CHANGED_BSSID) && - /* - * Now we know the correct bssid, so we send a new join command - * and enable the BSSID filter - */ - memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) { - memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN); - - if (!is_zero_ether_addr(wl->bssid)) { - ret = wl1271_cmd_build_null_data(wl); + if (changed & BSS_CHANGED_BSSID) + if (!is_zero_ether_addr(bss_conf->bssid)) { + ret = wl12xx_cmd_build_null_data(wl, wlvif); if (ret < 0) goto out; - ret = wl1271_build_qos_null_data(wl); + ret = wl1271_build_qos_null_data(wl, vif); if (ret < 0) goto out; /* Need to update the BSSID (for filtering etc) */ do_join = true; } - } if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) { rcu_read_lock(); @@ -3459,26 +3643,28 @@ sta_not_found: if (bss_conf->assoc) { u32 rates; int ieoffset; - wl->aid = bss_conf->aid; + wlvif->aid = bss_conf->aid; set_assoc = true; - wl->ps_poll_failures = 0; + wlvif->ps_poll_failures = 0; /* * use basic rates from AP, and determine lowest rate * to use with control frames. */ rates = bss_conf->basic_rates; - wl->basic_rate_set = + wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates, - wl->band); - wl->basic_rate = - wl1271_tx_min_rate_get(wl, wl->basic_rate_set); + wlvif->band); + wlvif->basic_rate = + wl1271_tx_min_rate_get(wl, + wlvif->basic_rate_set); if (sta_rate_set) - wl->rate_set = wl1271_tx_enabled_rates_get(wl, + wlvif->rate_set = + wl1271_tx_enabled_rates_get(wl, sta_rate_set, - wl->band); - ret = wl1271_acx_sta_rate_policies(wl); + wlvif->band); + ret = wl1271_acx_sta_rate_policies(wl, wlvif); if (ret < 0) goto out; @@ -3488,53 +3674,56 @@ sta_not_found: * updates it by itself when the first beacon is * received after a join. */ - ret = wl1271_cmd_build_ps_poll(wl, wl->aid); + ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid); if (ret < 0) goto out; /* * Get a template for hardware connection maintenance */ - dev_kfree_skb(wl->probereq); - wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL); + dev_kfree_skb(wlvif->probereq); + wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl, + wlvif, + NULL); ieoffset = offsetof(struct ieee80211_mgmt, u.probe_req.variable); - wl1271_ssid_set(wl, wl->probereq, ieoffset); + wl1271_ssid_set(vif, wlvif->probereq, ieoffset); /* enable the connection monitoring feature */ - ret = wl1271_acx_conn_monit_params(wl, true); + ret = wl1271_acx_conn_monit_params(wl, wlvif, true); if (ret < 0) goto out; } else { /* use defaults when not associated */ bool was_assoc = - !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED, - &wl->flags); + !!test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED, + &wlvif->flags); bool was_ifup = - !!test_and_clear_bit(WL1271_FLAG_STA_STATE_SENT, - &wl->flags); - wl->aid = 0; + !!test_and_clear_bit(WLVIF_FLAG_STA_STATE_SENT, + &wlvif->flags); + wlvif->aid = 0; /* free probe-request template */ - dev_kfree_skb(wl->probereq); - wl->probereq = NULL; + dev_kfree_skb(wlvif->probereq); + wlvif->probereq = NULL; /* re-enable dynamic ps - just in case */ - ieee80211_enable_dyn_ps(wl->vif); + ieee80211_enable_dyn_ps(vif); /* revert back to minimum rates for the current band */ - wl1271_set_band_rate(wl); - wl->basic_rate = - wl1271_tx_min_rate_get(wl, wl->basic_rate_set); - ret = wl1271_acx_sta_rate_policies(wl); + wl1271_set_band_rate(wl, wlvif); + wlvif->basic_rate = + wl1271_tx_min_rate_get(wl, + wlvif->basic_rate_set); + ret = wl1271_acx_sta_rate_policies(wl, wlvif); if (ret < 0) goto out; /* disable connection monitor features */ - ret = wl1271_acx_conn_monit_params(wl, false); + ret = wl1271_acx_conn_monit_params(wl, wlvif, false); /* Disable the keep-alive feature */ - ret = wl1271_acx_keep_alive_mode(wl, false); + ret = wl1271_acx_keep_alive_mode(wl, wlvif, false); if (ret < 0) goto out; @@ -3546,7 +3735,7 @@ sta_not_found: * no IF_OPER_UP notification. */ if (!was_ifup) { - ret = wl12xx_croc(wl, wl->role_id); + ret = wl12xx_croc(wl, wlvif->role_id); if (ret < 0) goto out; } @@ -3555,17 +3744,16 @@ sta_not_found: * roaming on the same channel. until we will * have a better flow...) */ - if (test_bit(wl->dev_role_id, wl->roc_map)) { - ret = wl12xx_croc(wl, wl->dev_role_id); + if (test_bit(wlvif->dev_role_id, wl->roc_map)) { + ret = wl12xx_croc(wl, + wlvif->dev_role_id); if (ret < 0) goto out; } - wl1271_unjoin(wl); - if (!(conf_flags & IEEE80211_CONF_IDLE)) { - wl12xx_cmd_role_start_dev(wl); - wl12xx_roc(wl, wl->dev_role_id); - } + wl1271_unjoin(wl, wlvif); + if (!(conf_flags & IEEE80211_CONF_IDLE)) + wl12xx_start_dev(wl, wlvif); } } } @@ -3576,27 +3764,28 @@ sta_not_found: if (bss_conf->ibss_joined) { u32 rates = bss_conf->basic_rates; - wl->basic_rate_set = + wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates, - wl->band); - wl->basic_rate = - wl1271_tx_min_rate_get(wl, wl->basic_rate_set); + wlvif->band); + wlvif->basic_rate = + wl1271_tx_min_rate_get(wl, + wlvif->basic_rate_set); /* by default, use 11b + OFDM rates */ - wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES; - ret = wl1271_acx_sta_rate_policies(wl); + wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES; + ret = wl1271_acx_sta_rate_policies(wl, wlvif); if (ret < 0) goto out; } } - ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed); + ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed); if (ret < 0) goto out; if (changed & BSS_CHANGED_ARP_FILTER) { __be32 addr = bss_conf->arp_addr_list[0]; - WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS); + WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS); if (bss_conf->arp_addr_cnt == 1 && bss_conf->arp_filter_enabled) { @@ -3606,24 +3795,24 @@ sta_not_found: * isn't being set (when sending), so we have to * reconfigure the template upon every ip change. */ - ret = wl1271_cmd_build_arp_rsp(wl, addr); + ret = wl1271_cmd_build_arp_rsp(wl, wlvif, addr); if (ret < 0) { wl1271_warning("build arp rsp failed: %d", ret); goto out; } - ret = wl1271_acx_arp_ip_filter(wl, + ret = wl1271_acx_arp_ip_filter(wl, wlvif, ACX_ARP_FILTER_ARP_FILTERING, addr); } else - ret = wl1271_acx_arp_ip_filter(wl, 0, addr); + ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr); if (ret < 0) goto out; } if (do_join) { - ret = wl1271_join(wl, set_assoc); + ret = wl1271_join(wl, wlvif, set_assoc); if (ret < 0) { wl1271_warning("cmd join failed %d", ret); goto out; @@ -3631,35 +3820,31 @@ sta_not_found: /* ROC until connected (after EAPOL exchange) */ if (!is_ibss) { - ret = wl12xx_roc(wl, wl->role_id); + ret = wl12xx_roc(wl, wlvif, wlvif->role_id); if (ret < 0) goto out; - wl1271_check_operstate(wl, + wl1271_check_operstate(wl, wlvif, ieee80211_get_operstate(vif)); } /* * stop device role if started (we might already be in * STA role). TODO: make it better. */ - if (wl->dev_role_id != WL12XX_INVALID_ROLE_ID) { - ret = wl12xx_croc(wl, wl->dev_role_id); - if (ret < 0) - goto out; - - ret = wl12xx_cmd_role_stop_dev(wl); + if (wlvif->dev_role_id != WL12XX_INVALID_ROLE_ID) { + ret = wl12xx_stop_dev(wl, wlvif); if (ret < 0) goto out; } /* If we want to go in PSM but we're not there yet */ - if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) && - !test_bit(WL1271_FLAG_PSM, &wl->flags)) { + if (test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags) && + !test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) { enum wl1271_cmd_ps_mode mode; mode = STATION_POWER_SAVE_MODE; - ret = wl1271_ps_set_mode(wl, mode, - wl->basic_rate, + ret = wl1271_ps_set_mode(wl, wlvif, mode, + wlvif->basic_rate, true); if (ret < 0) goto out; @@ -3673,7 +3858,7 @@ sta_not_found: ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap, true, - wl->sta_hlid); + wlvif->sta.hlid); if (ret < 0) { wl1271_warning("Set ht cap true failed %d", ret); @@ -3685,7 +3870,7 @@ sta_not_found: ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap, false, - wl->sta_hlid); + wlvif->sta.hlid); if (ret < 0) { wl1271_warning("Set ht cap false failed %d", ret); @@ -3697,7 +3882,7 @@ sta_not_found: /* Handle HT information change. Done after join. */ if ((changed & BSS_CHANGED_HT) && (bss_conf->channel_type != NL80211_CHAN_NO_HT)) { - ret = wl1271_acx_set_ht_information(wl, + ret = wl1271_acx_set_ht_information(wl, wlvif, bss_conf->ht_operation_mode); if (ret < 0) { wl1271_warning("Set ht information failed %d", ret); @@ -3715,7 +3900,8 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, u32 changed) { struct wl1271 *wl = hw->priv; - bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); int ret; wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x", @@ -3726,6 +3912,9 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, if (unlikely(wl->state == WL1271_STATE_OFF)) goto out; + if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))) + goto out; + ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) goto out; @@ -3746,6 +3935,7 @@ static int wl1271_op_conf_tx(struct ieee80211_hw *hw, const struct ieee80211_tx_queue_params *params) { struct wl1271 *wl = hw->priv; + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); u8 ps_scheme; int ret = 0; @@ -3792,13 +3982,13 @@ static int wl1271_op_conf_tx(struct ieee80211_hw *hw, * the txop is confed in units of 32us by the mac80211, * we need us */ - ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue), + ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue), params->cw_min, params->cw_max, params->aifs, params->txop << 5); if (ret < 0) goto out_sleep; - ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue), + ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue), CONF_CHANNEL_TYPE_EDCF, wl1271_tx_get_queue(queue), ps_scheme, CONF_ACK_POLICY_LEGACY, @@ -3861,43 +4051,43 @@ static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx, } static int wl1271_allocate_sta(struct wl1271 *wl, - struct ieee80211_sta *sta, - u8 *hlid) + struct wl12xx_vif *wlvif, + struct ieee80211_sta *sta) { struct wl1271_station *wl_sta; - int id; + int ret; + - id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS); - if (id >= AP_MAX_STATIONS) { + if (wl->active_sta_count >= AP_MAX_STATIONS) { wl1271_warning("could not allocate HLID - too much stations"); return -EBUSY; } wl_sta = (struct wl1271_station *)sta->drv_priv; - set_bit(id, wl->ap_hlid_map); - wl_sta->hlid = WL1271_AP_STA_HLID_START + id; - *hlid = wl_sta->hlid; + ret = wl12xx_allocate_link(wl, wlvif, &wl_sta->hlid); + if (ret < 0) { + wl1271_warning("could not allocate HLID - too many links"); + return -EBUSY; + } + + set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map); memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN); wl->active_sta_count++; return 0; } -void wl1271_free_sta(struct wl1271 *wl, u8 hlid) +void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid) { - int id = hlid - WL1271_AP_STA_HLID_START; - - if (hlid < WL1271_AP_STA_HLID_START) + if (!test_bit(hlid, wlvif->ap.sta_hlid_map)) return; - if (!test_bit(id, wl->ap_hlid_map)) - return; - - clear_bit(id, wl->ap_hlid_map); + clear_bit(hlid, wlvif->ap.sta_hlid_map); memset(wl->links[hlid].addr, 0, ETH_ALEN); wl->links[hlid].ba_bitmap = 0; wl1271_tx_reset_link_queues(wl, hlid); __clear_bit(hlid, &wl->ap_ps_map); __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); + wl12xx_free_link(wl, wlvif, &hlid); wl->active_sta_count--; } @@ -3906,6 +4096,8 @@ static int wl1271_op_sta_add(struct ieee80211_hw *hw, struct ieee80211_sta *sta) { struct wl1271 *wl = hw->priv; + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + struct wl1271_station *wl_sta; int ret = 0; u8 hlid; @@ -3914,20 +4106,23 @@ static int wl1271_op_sta_add(struct ieee80211_hw *hw, if (unlikely(wl->state == WL1271_STATE_OFF)) goto out; - if (wl->bss_type != BSS_TYPE_AP_BSS) + if (wlvif->bss_type != BSS_TYPE_AP_BSS) goto out; wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid); - ret = wl1271_allocate_sta(wl, sta, &hlid); + ret = wl1271_allocate_sta(wl, wlvif, sta); if (ret < 0) goto out; + wl_sta = (struct wl1271_station *)sta->drv_priv; + hlid = wl_sta->hlid; + ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) goto out_free_sta; - ret = wl12xx_cmd_add_peer(wl, sta, hlid); + ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid); if (ret < 0) goto out_sleep; @@ -3944,7 +4139,7 @@ out_sleep: out_free_sta: if (ret < 0) - wl1271_free_sta(wl, hlid); + wl1271_free_sta(wl, wlvif, hlid); out: mutex_unlock(&wl->mutex); @@ -3956,6 +4151,7 @@ static int wl1271_op_sta_remove(struct ieee80211_hw *hw, struct ieee80211_sta *sta) { struct wl1271 *wl = hw->priv; + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); struct wl1271_station *wl_sta; int ret = 0, id; @@ -3964,14 +4160,14 @@ static int wl1271_op_sta_remove(struct ieee80211_hw *hw, if (unlikely(wl->state == WL1271_STATE_OFF)) goto out; - if (wl->bss_type != BSS_TYPE_AP_BSS) + if (wlvif->bss_type != BSS_TYPE_AP_BSS) goto out; wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid); wl_sta = (struct wl1271_station *)sta->drv_priv; - id = wl_sta->hlid - WL1271_AP_STA_HLID_START; - if (WARN_ON(!test_bit(id, wl->ap_hlid_map))) + id = wl_sta->hlid; + if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map))) goto out; ret = wl1271_ps_elp_wakeup(wl); @@ -3982,7 +4178,7 @@ static int wl1271_op_sta_remove(struct ieee80211_hw *hw, if (ret < 0) goto out_sleep; - wl1271_free_sta(wl, wl_sta->hlid); + wl1271_free_sta(wl, wlvif, wl_sta->hlid); out_sleep: wl1271_ps_elp_sleep(wl); @@ -3999,6 +4195,7 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw, u8 buf_size) { struct wl1271 *wl = hw->priv; + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); int ret; u8 hlid, *ba_bitmap; @@ -4016,10 +4213,10 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw, goto out; } - if (wl->bss_type == BSS_TYPE_STA_BSS) { - hlid = wl->sta_hlid; - ba_bitmap = &wl->ba_rx_bitmap; - } else if (wl->bss_type == BSS_TYPE_AP_BSS) { + if (wlvif->bss_type == BSS_TYPE_STA_BSS) { + hlid = wlvif->sta.hlid; + ba_bitmap = &wlvif->sta.ba_rx_bitmap; + } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) { struct wl1271_station *wl_sta; wl_sta = (struct wl1271_station *)sta->drv_priv; @@ -4039,7 +4236,7 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw, switch (action) { case IEEE80211_AMPDU_RX_START: - if (!wl->ba_support || !wl->ba_allowed) { + if (!wlvif->ba_support || !wlvif->ba_allowed) { ret = -ENOTSUPP; break; } @@ -4108,8 +4305,9 @@ static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const struct cfg80211_bitrate_mask *mask) { + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); struct wl1271 *wl = hw->priv; - int i; + int i, ret = 0; wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x", mask->control[NL80211_BAND_2GHZ].legacy, @@ -4118,19 +4316,39 @@ static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw, mutex_lock(&wl->mutex); for (i = 0; i < IEEE80211_NUM_BANDS; i++) - wl->bitrate_masks[i] = + wlvif->bitrate_masks[i] = wl1271_tx_enabled_rates_get(wl, mask->control[i].legacy, i); + + if (unlikely(wl->state == WL1271_STATE_OFF)) + goto out; + + if (wlvif->bss_type == BSS_TYPE_STA_BSS && + !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) { + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + wl1271_set_band_rate(wl, wlvif); + wlvif->basic_rate = + wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); + ret = wl1271_acx_sta_rate_policies(wl, wlvif); + + wl1271_ps_elp_sleep(wl); + } +out: mutex_unlock(&wl->mutex); - return 0; + return ret; } static void wl12xx_op_channel_switch(struct ieee80211_hw *hw, struct ieee80211_channel_switch *ch_switch) { struct wl1271 *wl = hw->priv; + struct wl12xx_vif *wlvif; int ret; wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch"); @@ -4138,19 +4356,24 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw, mutex_lock(&wl->mutex); if (unlikely(wl->state == WL1271_STATE_OFF)) { - mutex_unlock(&wl->mutex); - ieee80211_chswitch_done(wl->vif, false); - return; + wl12xx_for_each_wlvif_sta(wl, wlvif) { + struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); + ieee80211_chswitch_done(vif, false); + } + goto out; } ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) goto out; - ret = wl12xx_cmd_channel_switch(wl, ch_switch); + /* TODO: change mac80211 to pass vif as param */ + wl12xx_for_each_wlvif_sta(wl, wlvif) { + ret = wl12xx_cmd_channel_switch(wl, ch_switch); - if (!ret) - set_bit(WL1271_FLAG_CS_PROGRESS, &wl->flags); + if (!ret) + set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags); + } wl1271_ps_elp_sleep(wl); @@ -4170,10 +4393,6 @@ static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw) /* packets are considered pending if in the TX queue or the FW */ ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0); - - /* the above is appropriate for STA mode for PS purposes */ - WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS); - out: mutex_unlock(&wl->mutex); @@ -4604,7 +4823,7 @@ static struct bin_attribute fwlog_attr = { .read = wl1271_sysfs_read_fwlog, }; -int wl1271_register_hw(struct wl1271 *wl) +static int wl1271_register_hw(struct wl1271 *wl) { int ret; @@ -4645,9 +4864,8 @@ int wl1271_register_hw(struct wl1271 *wl) return 0; } -EXPORT_SYMBOL_GPL(wl1271_register_hw); -void wl1271_unregister_hw(struct wl1271 *wl) +static void wl1271_unregister_hw(struct wl1271 *wl) { if (wl->state == WL1271_STATE_PLT) __wl1271_plt_stop(wl); @@ -4657,9 +4875,8 @@ void wl1271_unregister_hw(struct wl1271 *wl) wl->mac80211_registered = false; } -EXPORT_SYMBOL_GPL(wl1271_unregister_hw); -int wl1271_init_ieee80211(struct wl1271 *wl) +static int wl1271_init_ieee80211(struct wl1271 *wl) { static const u32 cipher_suites[] = { WLAN_CIPHER_SUITE_WEP40, @@ -4736,27 +4953,33 @@ int wl1271_init_ieee80211(struct wl1271 *wl) wl->hw->wiphy->reg_notifier = wl1271_reg_notify; - SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl)); + /* the FW answers probe-requests in AP-mode */ + wl->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; + wl->hw->wiphy->probe_resp_offload = + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P; + + SET_IEEE80211_DEV(wl->hw, wl->dev); wl->hw->sta_data_size = sizeof(struct wl1271_station); + wl->hw->vif_data_size = sizeof(struct wl12xx_vif); wl->hw->max_rx_aggregation_subframes = 8; return 0; } -EXPORT_SYMBOL_GPL(wl1271_init_ieee80211); #define WL1271_DEFAULT_CHANNEL 0 -struct ieee80211_hw *wl1271_alloc_hw(void) +static struct ieee80211_hw *wl1271_alloc_hw(void) { struct ieee80211_hw *hw; - struct platform_device *plat_dev = NULL; struct wl1271 *wl; int i, j, ret; unsigned int order; - BUILD_BUG_ON(AP_MAX_LINKS > WL12XX_MAX_LINKS); + BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS); hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops); if (!hw) { @@ -4765,41 +4988,26 @@ struct ieee80211_hw *wl1271_alloc_hw(void) goto err_hw_alloc; } - plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL); - if (!plat_dev) { - wl1271_error("could not allocate platform_device"); - ret = -ENOMEM; - goto err_plat_alloc; - } - wl = hw->priv; memset(wl, 0, sizeof(*wl)); INIT_LIST_HEAD(&wl->list); + INIT_LIST_HEAD(&wl->wlvif_list); wl->hw = hw; - wl->plat_dev = plat_dev; - - for (i = 0; i < NUM_TX_QUEUES; i++) - skb_queue_head_init(&wl->tx_queue[i]); for (i = 0; i < NUM_TX_QUEUES; i++) - for (j = 0; j < AP_MAX_LINKS; j++) + for (j = 0; j < WL12XX_MAX_LINKS; j++) skb_queue_head_init(&wl->links[j].tx_queue[i]); skb_queue_head_init(&wl->deferred_rx_queue); skb_queue_head_init(&wl->deferred_tx_queue); INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work); - INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work); INIT_WORK(&wl->netstack_work, wl1271_netstack_work); INIT_WORK(&wl->tx_work, wl1271_tx_work); INIT_WORK(&wl->recovery_work, wl1271_recovery_work); INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work); - INIT_WORK(&wl->rx_streaming_enable_work, - wl1271_rx_streaming_enable_work); - INIT_WORK(&wl->rx_streaming_disable_work, - wl1271_rx_streaming_disable_work); wl->freezable_wq = create_freezable_workqueue("wl12xx_wq"); if (!wl->freezable_wq) { @@ -4808,41 +5016,21 @@ struct ieee80211_hw *wl1271_alloc_hw(void) } wl->channel = WL1271_DEFAULT_CHANNEL; - wl->beacon_int = WL1271_DEFAULT_BEACON_INT; - wl->default_key = 0; wl->rx_counter = 0; - wl->psm_entry_retry = 0; wl->power_level = WL1271_DEFAULT_POWER_LEVEL; - wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC; - wl->basic_rate = CONF_TX_RATE_MASK_BASIC; - wl->rate_set = CONF_TX_RATE_MASK_BASIC; wl->band = IEEE80211_BAND_2GHZ; wl->vif = NULL; wl->flags = 0; wl->sg_enabled = true; wl->hw_pg_ver = -1; - wl->bss_type = MAX_BSS_TYPE; - wl->set_bss_type = MAX_BSS_TYPE; - wl->last_tx_hlid = 0; wl->ap_ps_map = 0; wl->ap_fw_ps_map = 0; wl->quirks = 0; wl->platform_quirks = 0; wl->sched_scanning = false; - wl->tx_security_seq = 0; - wl->tx_security_last_seq_lsb = 0; wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT; - wl->role_id = WL12XX_INVALID_ROLE_ID; wl->system_hlid = WL12XX_SYSTEM_HLID; - wl->sta_hlid = WL12XX_INVALID_LINK_ID; - wl->dev_role_id = WL12XX_INVALID_ROLE_ID; - wl->dev_hlid = WL12XX_INVALID_LINK_ID; - wl->session_counter = 0; - wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID; - wl->ap_global_hlid = WL12XX_INVALID_LINK_ID; wl->active_sta_count = 0; - setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer, - (unsigned long) wl); wl->fwlog_size = 0; init_waitqueue_head(&wl->fwlog_waitq); @@ -4860,8 +5048,6 @@ struct ieee80211_hw *wl1271_alloc_hw(void) /* Apply default driver configuration. */ wl1271_conf_init(wl); - wl->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate; - wl->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5; order = get_order(WL1271_AGGR_BUFFER_SIZE); wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order); @@ -4883,49 +5069,8 @@ struct ieee80211_hw *wl1271_alloc_hw(void) goto err_dummy_packet; } - /* Register platform device */ - ret = platform_device_register(wl->plat_dev); - if (ret) { - wl1271_error("couldn't register platform device"); - goto err_fwlog; - } - dev_set_drvdata(&wl->plat_dev->dev, wl); - - /* Create sysfs file to control bt coex state */ - ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state); - if (ret < 0) { - wl1271_error("failed to create sysfs file bt_coex_state"); - goto err_platform; - } - - /* Create sysfs file to get HW PG version */ - ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver); - if (ret < 0) { - wl1271_error("failed to create sysfs file hw_pg_ver"); - goto err_bt_coex_state; - } - - /* Create sysfs file for the FW log */ - ret = device_create_bin_file(&wl->plat_dev->dev, &fwlog_attr); - if (ret < 0) { - wl1271_error("failed to create sysfs file fwlog"); - goto err_hw_pg_ver; - } - return hw; -err_hw_pg_ver: - device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver); - -err_bt_coex_state: - device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state); - -err_platform: - platform_device_unregister(wl->plat_dev); - -err_fwlog: - free_page((unsigned long)wl->fwlog); - err_dummy_packet: dev_kfree_skb(wl->dummy_packet); @@ -4937,18 +5082,14 @@ err_wq: err_hw: wl1271_debugfs_exit(wl); - kfree(plat_dev); - -err_plat_alloc: ieee80211_free_hw(hw); err_hw_alloc: return ERR_PTR(ret); } -EXPORT_SYMBOL_GPL(wl1271_alloc_hw); -int wl1271_free_hw(struct wl1271 *wl) +static int wl1271_free_hw(struct wl1271 *wl) { /* Unblock any fwlog readers */ mutex_lock(&wl->mutex); @@ -4956,17 +5097,15 @@ int wl1271_free_hw(struct wl1271 *wl) wake_up_interruptible_all(&wl->fwlog_waitq); mutex_unlock(&wl->mutex); - device_remove_bin_file(&wl->plat_dev->dev, &fwlog_attr); + device_remove_bin_file(wl->dev, &fwlog_attr); - device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver); + device_remove_file(wl->dev, &dev_attr_hw_pg_ver); - device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state); - platform_device_unregister(wl->plat_dev); + device_remove_file(wl->dev, &dev_attr_bt_coex_state); free_page((unsigned long)wl->fwlog); dev_kfree_skb(wl->dummy_packet); free_pages((unsigned long)wl->aggr_buf, get_order(WL1271_AGGR_BUFFER_SIZE)); - kfree(wl->plat_dev); wl1271_debugfs_exit(wl); @@ -4983,7 +5122,174 @@ int wl1271_free_hw(struct wl1271 *wl) return 0; } -EXPORT_SYMBOL_GPL(wl1271_free_hw); + +static irqreturn_t wl12xx_hardirq(int irq, void *cookie) +{ + struct wl1271 *wl = cookie; + unsigned long flags; + + wl1271_debug(DEBUG_IRQ, "IRQ"); + + /* complete the ELP completion */ + spin_lock_irqsave(&wl->wl_lock, flags); + set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags); + if (wl->elp_compl) { + complete(wl->elp_compl); + wl->elp_compl = NULL; + } + + if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) { + /* don't enqueue a work right now. mark it as pending */ + set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags); + wl1271_debug(DEBUG_IRQ, "should not enqueue work"); + disable_irq_nosync(wl->irq); + pm_wakeup_event(wl->dev, 0); + spin_unlock_irqrestore(&wl->wl_lock, flags); + return IRQ_HANDLED; + } + spin_unlock_irqrestore(&wl->wl_lock, flags); + + return IRQ_WAKE_THREAD; +} + +static int __devinit wl12xx_probe(struct platform_device *pdev) +{ + struct wl12xx_platform_data *pdata = pdev->dev.platform_data; + struct ieee80211_hw *hw; + struct wl1271 *wl; + unsigned long irqflags; + int ret = -ENODEV; + + hw = wl1271_alloc_hw(); + if (IS_ERR(hw)) { + wl1271_error("can't allocate hw"); + ret = PTR_ERR(hw); + goto out; + } + + wl = hw->priv; + wl->irq = platform_get_irq(pdev, 0); + wl->ref_clock = pdata->board_ref_clock; + wl->tcxo_clock = pdata->board_tcxo_clock; + wl->platform_quirks = pdata->platform_quirks; + wl->set_power = pdata->set_power; + wl->dev = &pdev->dev; + wl->if_ops = pdata->ops; + + platform_set_drvdata(pdev, wl); + + if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) + irqflags = IRQF_TRIGGER_RISING; + else + irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT; + + ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wl1271_irq, + irqflags, + pdev->name, wl); + if (ret < 0) { + wl1271_error("request_irq() failed: %d", ret); + goto out_free_hw; + } + + ret = enable_irq_wake(wl->irq); + if (!ret) { + wl->irq_wake_enabled = true; + device_init_wakeup(wl->dev, 1); + if (pdata->pwr_in_suspend) + hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY; + + } + disable_irq(wl->irq); + + ret = wl1271_init_ieee80211(wl); + if (ret) + goto out_irq; + + ret = wl1271_register_hw(wl); + if (ret) + goto out_irq; + + /* Create sysfs file to control bt coex state */ + ret = device_create_file(wl->dev, &dev_attr_bt_coex_state); + if (ret < 0) { + wl1271_error("failed to create sysfs file bt_coex_state"); + goto out_irq; + } + + /* Create sysfs file to get HW PG version */ + ret = device_create_file(wl->dev, &dev_attr_hw_pg_ver); + if (ret < 0) { + wl1271_error("failed to create sysfs file hw_pg_ver"); + goto out_bt_coex_state; + } + + /* Create sysfs file for the FW log */ + ret = device_create_bin_file(wl->dev, &fwlog_attr); + if (ret < 0) { + wl1271_error("failed to create sysfs file fwlog"); + goto out_hw_pg_ver; + } + + return 0; + +out_hw_pg_ver: + device_remove_file(wl->dev, &dev_attr_hw_pg_ver); + +out_bt_coex_state: + device_remove_file(wl->dev, &dev_attr_bt_coex_state); + +out_irq: + free_irq(wl->irq, wl); + +out_free_hw: + wl1271_free_hw(wl); + +out: + return ret; +} + +static int __devexit wl12xx_remove(struct platform_device *pdev) +{ + struct wl1271 *wl = platform_get_drvdata(pdev); + + if (wl->irq_wake_enabled) { + device_init_wakeup(wl->dev, 0); + disable_irq_wake(wl->irq); + } + wl1271_unregister_hw(wl); + free_irq(wl->irq, wl); + wl1271_free_hw(wl); + + return 0; +} + +static const struct platform_device_id wl12xx_id_table[] __devinitconst = { + { "wl12xx", 0 }, + { } /* Terminating Entry */ +}; +MODULE_DEVICE_TABLE(platform, wl12xx_id_table); + +static struct platform_driver wl12xx_driver = { + .probe = wl12xx_probe, + .remove = __devexit_p(wl12xx_remove), + .id_table = wl12xx_id_table, + .driver = { + .name = "wl12xx_driver", + .owner = THIS_MODULE, + } +}; + +static int __init wl12xx_init(void) +{ + return platform_driver_register(&wl12xx_driver); +} +module_init(wl12xx_init); + +static void __exit wl12xx_exit(void) +{ + platform_driver_unregister(&wl12xx_driver); +} +module_exit(wl12xx_exit); u32 wl12xx_debug_level = DEBUG_NONE; EXPORT_SYMBOL_GPL(wl12xx_debug_level); diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c index c15ebf2efd40..a7a11088dd31 100644 --- a/drivers/net/wireless/wl12xx/ps.c +++ b/drivers/net/wireless/wl12xx/ps.c @@ -25,6 +25,7 @@ #include "ps.h" #include "io.h" #include "tx.h" +#include "debug.h" #define WL1271_WAKEUP_TIMEOUT 500 @@ -32,6 +33,7 @@ void wl1271_elp_work(struct work_struct *work) { struct delayed_work *dwork; struct wl1271 *wl; + struct wl12xx_vif *wlvif; dwork = container_of(work, struct delayed_work, work); wl = container_of(dwork, struct wl1271, elp_work); @@ -47,11 +49,15 @@ void wl1271_elp_work(struct work_struct *work) if (unlikely(!test_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags))) goto out; - if (test_bit(WL1271_FLAG_IN_ELP, &wl->flags) || - (!test_bit(WL1271_FLAG_PSM, &wl->flags) && - !test_bit(WL1271_FLAG_IDLE, &wl->flags))) + if (test_bit(WL1271_FLAG_IN_ELP, &wl->flags)) goto out; + wl12xx_for_each_wlvif(wl, wlvif) { + if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags) && + !test_bit(WL1271_FLAG_IDLE, &wl->flags)) + goto out; + } + wl1271_debug(DEBUG_PSM, "chip to elp"); wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); set_bit(WL1271_FLAG_IN_ELP, &wl->flags); @@ -65,13 +71,17 @@ out: /* Routines to toggle sleep mode while in ELP */ void wl1271_ps_elp_sleep(struct wl1271 *wl) { + struct wl12xx_vif *wlvif; + /* we shouldn't get consecutive sleep requests */ if (WARN_ON(test_and_set_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags))) return; - if (!test_bit(WL1271_FLAG_PSM, &wl->flags) && - !test_bit(WL1271_FLAG_IDLE, &wl->flags)) - return; + wl12xx_for_each_wlvif(wl, wlvif) { + if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags) && + !test_bit(WL1271_FLAG_IDLE, &wl->flags)) + return; + } ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, msecs_to_jiffies(ELP_ENTRY_DELAY)); @@ -143,8 +153,8 @@ out: return 0; } -int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode, - u32 rates, bool send) +int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, + enum wl1271_cmd_ps_mode mode, u32 rates, bool send) { int ret; @@ -152,39 +162,34 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode, case STATION_POWER_SAVE_MODE: wl1271_debug(DEBUG_PSM, "entering psm"); - ret = wl1271_acx_wake_up_conditions(wl); + ret = wl1271_acx_wake_up_conditions(wl, wlvif); if (ret < 0) { wl1271_error("couldn't set wake up conditions"); return ret; } - ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE); + ret = wl1271_cmd_ps_mode(wl, wlvif, STATION_POWER_SAVE_MODE); if (ret < 0) return ret; - set_bit(WL1271_FLAG_PSM, &wl->flags); + set_bit(WLVIF_FLAG_PSM, &wlvif->flags); break; case STATION_ACTIVE_MODE: default: wl1271_debug(DEBUG_PSM, "leaving psm"); /* disable beacon early termination */ - if (wl->band == IEEE80211_BAND_2GHZ) { - ret = wl1271_acx_bet_enable(wl, false); + if (wlvif->band == IEEE80211_BAND_2GHZ) { + ret = wl1271_acx_bet_enable(wl, wlvif, false); if (ret < 0) return ret; } - /* disable beacon filtering */ - ret = wl1271_acx_beacon_filter_opt(wl, false); - if (ret < 0) - return ret; - - ret = wl1271_cmd_ps_mode(wl, STATION_ACTIVE_MODE); + ret = wl1271_cmd_ps_mode(wl, wlvif, STATION_ACTIVE_MODE); if (ret < 0) return ret; - clear_bit(WL1271_FLAG_PSM, &wl->flags); + clear_bit(WLVIF_FLAG_PSM, &wlvif->flags); break; } @@ -223,9 +228,11 @@ static void wl1271_ps_filter_frames(struct wl1271 *wl, u8 hlid) wl1271_handle_tx_low_watermark(wl); } -void wl1271_ps_link_start(struct wl1271 *wl, u8 hlid, bool clean_queues) +void wl12xx_ps_link_start(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u8 hlid, bool clean_queues) { struct ieee80211_sta *sta; + struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); if (test_bit(hlid, &wl->ap_ps_map)) return; @@ -235,7 +242,7 @@ void wl1271_ps_link_start(struct wl1271 *wl, u8 hlid, bool clean_queues) clean_queues); rcu_read_lock(); - sta = ieee80211_find_sta(wl->vif, wl->links[hlid].addr); + sta = ieee80211_find_sta(vif, wl->links[hlid].addr); if (!sta) { wl1271_error("could not find sta %pM for starting ps", wl->links[hlid].addr); @@ -253,9 +260,10 @@ void wl1271_ps_link_start(struct wl1271 *wl, u8 hlid, bool clean_queues) __set_bit(hlid, &wl->ap_ps_map); } -void wl1271_ps_link_end(struct wl1271 *wl, u8 hlid) +void wl12xx_ps_link_end(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid) { struct ieee80211_sta *sta; + struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); if (!test_bit(hlid, &wl->ap_ps_map)) return; @@ -265,7 +273,7 @@ void wl1271_ps_link_end(struct wl1271 *wl, u8 hlid) __clear_bit(hlid, &wl->ap_ps_map); rcu_read_lock(); - sta = ieee80211_find_sta(wl->vif, wl->links[hlid].addr); + sta = ieee80211_find_sta(vif, wl->links[hlid].addr); if (!sta) { wl1271_error("could not find sta %pM for ending ps", wl->links[hlid].addr); diff --git a/drivers/net/wireless/wl12xx/ps.h b/drivers/net/wireless/wl12xx/ps.h index 25eb9bc9b628..a12052f02026 100644 --- a/drivers/net/wireless/wl12xx/ps.h +++ b/drivers/net/wireless/wl12xx/ps.h @@ -27,13 +27,14 @@ #include "wl12xx.h" #include "acx.h" -int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode, - u32 rates, bool send); +int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, + enum wl1271_cmd_ps_mode mode, u32 rates, bool send); void wl1271_ps_elp_sleep(struct wl1271 *wl); int wl1271_ps_elp_wakeup(struct wl1271 *wl); void wl1271_elp_work(struct work_struct *work); -void wl1271_ps_link_start(struct wl1271 *wl, u8 hlid, bool clean_queues); -void wl1271_ps_link_end(struct wl1271 *wl, u8 hlid); +void wl12xx_ps_link_start(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u8 hlid, bool clean_queues); +void wl12xx_ps_link_end(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid); #define WL1271_PS_COMPLETE_TIMEOUT 500 diff --git a/drivers/net/wireless/wl12xx/reg.h b/drivers/net/wireless/wl12xx/reg.h index 3f570f397586..df34d5977b98 100644 --- a/drivers/net/wireless/wl12xx/reg.h +++ b/drivers/net/wireless/wl12xx/reg.h @@ -408,7 +408,7 @@ /* Firmware image load chunk size */ -#define CHUNK_SIZE 512 +#define CHUNK_SIZE 16384 /* Firmware image header size */ #define FW_HDR_SIZE 8 diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c index dee4cfe9ccc1..4fbd2a722ffa 100644 --- a/drivers/net/wireless/wl12xx/rx.c +++ b/drivers/net/wireless/wl12xx/rx.c @@ -25,9 +25,11 @@ #include <linux/sched.h> #include "wl12xx.h" +#include "debug.h" #include "acx.h" #include "reg.h" #include "rx.h" +#include "tx.h" #include "io.h" static u8 wl12xx_rx_get_mem_block(struct wl12xx_fw_status *status, @@ -96,7 +98,7 @@ static void wl1271_rx_status(struct wl1271 *wl, } static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, - bool unaligned) + bool unaligned, u8 *hlid) { struct wl1271_rx_descriptor *desc; struct sk_buff *skb; @@ -159,6 +161,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, * payload aligned to 4 bytes. */ memcpy(buf, data + sizeof(*desc), length - sizeof(*desc)); + *hlid = desc->hlid; hdr = (struct ieee80211_hdr *)skb->data; if (ieee80211_is_beacon(hdr->frame_control)) @@ -169,10 +172,10 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon); seq_num = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; - wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s seq %d", skb, + wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s seq %d hlid %d", skb, skb->len - desc->pad_len, beacon ? "beacon" : "", - seq_num); + seq_num, *hlid); skb_trim(skb, skb->len - desc->pad_len); @@ -185,6 +188,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status) { struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map; + unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0}; u32 buf_size; u32 fw_rx_counter = status->fw_rx_counter & NUM_RX_PKT_DESC_MOD_MASK; u32 drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK; @@ -192,8 +196,7 @@ void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status) u32 mem_block; u32 pkt_length; u32 pkt_offset; - bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); - bool had_data = false; + u8 hlid; bool unaligned = false; while (drv_rx_counter != fw_rx_counter) { @@ -253,8 +256,15 @@ void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status) */ if (wl1271_rx_handle_data(wl, wl->aggr_buf + pkt_offset, - pkt_length, unaligned) == 1) - had_data = true; + pkt_length, unaligned, + &hlid) == 1) { + if (hlid < WL12XX_MAX_LINKS) + __set_bit(hlid, active_hlids); + else + WARN(1, + "hlid exceeded WL12XX_MAX_LINKS " + "(%d)\n", hlid); + } wl->rx_counter++; drv_rx_counter++; @@ -270,17 +280,5 @@ void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status) if (wl->quirks & WL12XX_QUIRK_END_OF_TRANSACTION) wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter); - if (!is_ap && wl->conf.rx_streaming.interval && had_data && - (wl->conf.rx_streaming.always || - test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags))) { - u32 timeout = wl->conf.rx_streaming.duration; - - /* restart rx streaming */ - if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags)) - ieee80211_queue_work(wl->hw, - &wl->rx_streaming_enable_work); - - mod_timer(&wl->rx_streaming_timer, - jiffies + msecs_to_jiffies(timeout)); - } + wl12xx_rearm_rx_streaming(wl, active_hlids); } diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c index fc29c671cf3b..8599dab1fe2a 100644 --- a/drivers/net/wireless/wl12xx/scan.c +++ b/drivers/net/wireless/wl12xx/scan.c @@ -24,6 +24,7 @@ #include <linux/ieee80211.h> #include "wl12xx.h" +#include "debug.h" #include "cmd.h" #include "scan.h" #include "acx.h" @@ -34,6 +35,8 @@ void wl1271_scan_complete_work(struct work_struct *work) { struct delayed_work *dwork; struct wl1271 *wl; + struct ieee80211_vif *vif; + struct wl12xx_vif *wlvif; int ret; bool is_sta, is_ibss; @@ -50,28 +53,31 @@ void wl1271_scan_complete_work(struct work_struct *work) if (wl->scan.state == WL1271_SCAN_STATE_IDLE) goto out; + vif = wl->scan_vif; + wlvif = wl12xx_vif_to_data(vif); + wl->scan.state = WL1271_SCAN_STATE_IDLE; memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); wl->scan.req = NULL; + wl->scan_vif = NULL; ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) goto out; - if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) { + if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) { /* restore hardware connection monitoring template */ - wl1271_cmd_build_ap_probe_req(wl, wl->probereq); + wl1271_cmd_build_ap_probe_req(wl, wlvif, wlvif->probereq); } /* return to ROC if needed */ - is_sta = (wl->bss_type == BSS_TYPE_STA_BSS); - is_ibss = (wl->bss_type == BSS_TYPE_IBSS); - if (((is_sta && !test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) || - (is_ibss && !test_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags))) && - !test_bit(wl->dev_role_id, wl->roc_map)) { + is_sta = (wlvif->bss_type == BSS_TYPE_STA_BSS); + is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS); + if (((is_sta && !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) || + (is_ibss && !test_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags))) && + !test_bit(wlvif->dev_role_id, wl->roc_map)) { /* restore remain on channel */ - wl12xx_cmd_role_start_dev(wl); - wl12xx_roc(wl, wl->dev_role_id); + wl12xx_start_dev(wl, wlvif); } wl1271_ps_elp_sleep(wl); @@ -155,9 +161,11 @@ static int wl1271_get_scan_channels(struct wl1271 *wl, #define WL1271_NOTHING_TO_SCAN 1 -static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band, - bool passive, u32 basic_rate) +static int wl1271_scan_send(struct wl1271 *wl, struct ieee80211_vif *vif, + enum ieee80211_band band, + bool passive, u32 basic_rate) { + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); struct wl1271_cmd_scan *cmd; struct wl1271_cmd_trigger_scan_to *trigger; int ret; @@ -177,11 +185,11 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band, if (passive) scan_options |= WL1271_SCAN_OPT_PASSIVE; - if (WARN_ON(wl->role_id == WL12XX_INVALID_ROLE_ID)) { + if (WARN_ON(wlvif->role_id == WL12XX_INVALID_ROLE_ID)) { ret = -EINVAL; goto out; } - cmd->params.role_id = wl->role_id; + cmd->params.role_id = wlvif->role_id; cmd->params.scan_options = cpu_to_le16(scan_options); cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req, @@ -194,7 +202,6 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band, cmd->params.tx_rate = cpu_to_le32(basic_rate); cmd->params.n_probe_reqs = wl->conf.scan.num_probe_reqs; - cmd->params.tx_rate = cpu_to_le32(basic_rate); cmd->params.tid_trigger = 0; cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG; @@ -208,11 +215,11 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band, memcpy(cmd->params.ssid, wl->scan.ssid, wl->scan.ssid_len); } - memcpy(cmd->addr, wl->mac_addr, ETH_ALEN); + memcpy(cmd->addr, vif->addr, ETH_ALEN); - ret = wl1271_cmd_build_probe_req(wl, wl->scan.ssid, wl->scan.ssid_len, - wl->scan.req->ie, wl->scan.req->ie_len, - band); + ret = wl1271_cmd_build_probe_req(wl, wlvif, wl->scan.ssid, + wl->scan.ssid_len, wl->scan.req->ie, + wl->scan.req->ie_len, band); if (ret < 0) { wl1271_error("PROBE request template failed"); goto out; @@ -241,11 +248,12 @@ out: return ret; } -void wl1271_scan_stm(struct wl1271 *wl) +void wl1271_scan_stm(struct wl1271 *wl, struct ieee80211_vif *vif) { + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); int ret = 0; enum ieee80211_band band; - u32 rate; + u32 rate, mask; switch (wl->scan.state) { case WL1271_SCAN_STATE_IDLE: @@ -253,47 +261,59 @@ void wl1271_scan_stm(struct wl1271 *wl) case WL1271_SCAN_STATE_2GHZ_ACTIVE: band = IEEE80211_BAND_2GHZ; - rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]); - ret = wl1271_scan_send(wl, band, false, rate); + mask = wlvif->bitrate_masks[band]; + if (wl->scan.req->no_cck) { + mask &= ~CONF_TX_CCK_RATES; + if (!mask) + mask = CONF_TX_RATE_MASK_BASIC_P2P; + } + rate = wl1271_tx_min_rate_get(wl, mask); + ret = wl1271_scan_send(wl, vif, band, false, rate); if (ret == WL1271_NOTHING_TO_SCAN) { wl->scan.state = WL1271_SCAN_STATE_2GHZ_PASSIVE; - wl1271_scan_stm(wl); + wl1271_scan_stm(wl, vif); } break; case WL1271_SCAN_STATE_2GHZ_PASSIVE: band = IEEE80211_BAND_2GHZ; - rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]); - ret = wl1271_scan_send(wl, band, true, rate); + mask = wlvif->bitrate_masks[band]; + if (wl->scan.req->no_cck) { + mask &= ~CONF_TX_CCK_RATES; + if (!mask) + mask = CONF_TX_RATE_MASK_BASIC_P2P; + } + rate = wl1271_tx_min_rate_get(wl, mask); + ret = wl1271_scan_send(wl, vif, band, true, rate); if (ret == WL1271_NOTHING_TO_SCAN) { if (wl->enable_11a) wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE; else wl->scan.state = WL1271_SCAN_STATE_DONE; - wl1271_scan_stm(wl); + wl1271_scan_stm(wl, vif); } break; case WL1271_SCAN_STATE_5GHZ_ACTIVE: band = IEEE80211_BAND_5GHZ; - rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]); - ret = wl1271_scan_send(wl, band, false, rate); + rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); + ret = wl1271_scan_send(wl, vif, band, false, rate); if (ret == WL1271_NOTHING_TO_SCAN) { wl->scan.state = WL1271_SCAN_STATE_5GHZ_PASSIVE; - wl1271_scan_stm(wl); + wl1271_scan_stm(wl, vif); } break; case WL1271_SCAN_STATE_5GHZ_PASSIVE: band = IEEE80211_BAND_5GHZ; - rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]); - ret = wl1271_scan_send(wl, band, true, rate); + rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); + ret = wl1271_scan_send(wl, vif, band, true, rate); if (ret == WL1271_NOTHING_TO_SCAN) { wl->scan.state = WL1271_SCAN_STATE_DONE; - wl1271_scan_stm(wl); + wl1271_scan_stm(wl, vif); } break; @@ -317,7 +337,8 @@ void wl1271_scan_stm(struct wl1271 *wl) } } -int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, +int wl1271_scan(struct wl1271 *wl, struct ieee80211_vif *vif, + const u8 *ssid, size_t ssid_len, struct cfg80211_scan_request *req) { /* @@ -338,6 +359,7 @@ int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, wl->scan.ssid_len = 0; } + wl->scan_vif = vif; wl->scan.req = req; memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); @@ -346,7 +368,7 @@ int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, msecs_to_jiffies(WL1271_SCAN_TIMEOUT)); - wl1271_scan_stm(wl); + wl1271_scan_stm(wl, vif); return 0; } @@ -550,6 +572,9 @@ wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl, * so they're used in probe requests. */ for (i = 0; i < req->n_ssids; i++) { + if (!req->ssids[i].ssid_len) + continue; + for (j = 0; j < cmd->n_ssids; j++) if (!memcmp(req->ssids[i].ssid, cmd->ssids[j].ssid, @@ -585,6 +610,7 @@ out: } int wl1271_scan_sched_scan_config(struct wl1271 *wl, + struct wl12xx_vif *wlvif, struct cfg80211_sched_scan_request *req, struct ieee80211_sched_scan_ies *ies) { @@ -631,7 +657,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl, } if (!force_passive && cfg->active[0]) { - ret = wl1271_cmd_build_probe_req(wl, req->ssids[0].ssid, + ret = wl1271_cmd_build_probe_req(wl, wlvif, req->ssids[0].ssid, req->ssids[0].ssid_len, ies->ie[IEEE80211_BAND_2GHZ], ies->len[IEEE80211_BAND_2GHZ], @@ -643,7 +669,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl, } if (!force_passive && cfg->active[1]) { - ret = wl1271_cmd_build_probe_req(wl, req->ssids[0].ssid, + ret = wl1271_cmd_build_probe_req(wl, wlvif, req->ssids[0].ssid, req->ssids[0].ssid_len, ies->ie[IEEE80211_BAND_5GHZ], ies->len[IEEE80211_BAND_5GHZ], @@ -667,14 +693,14 @@ out: return ret; } -int wl1271_scan_sched_scan_start(struct wl1271 *wl) +int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif) { struct wl1271_cmd_sched_scan_start *start; int ret = 0; wl1271_debug(DEBUG_CMD, "cmd periodic scan start"); - if (wl->bss_type != BSS_TYPE_STA_BSS) + if (wlvif->bss_type != BSS_TYPE_STA_BSS) return -EOPNOTSUPP; if (!test_bit(WL1271_FLAG_IDLE, &wl->flags)) diff --git a/drivers/net/wireless/wl12xx/scan.h b/drivers/net/wireless/wl12xx/scan.h index 92115156522f..a7ed43dc08c9 100644 --- a/drivers/net/wireless/wl12xx/scan.h +++ b/drivers/net/wireless/wl12xx/scan.h @@ -26,18 +26,20 @@ #include "wl12xx.h" -int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, +int wl1271_scan(struct wl1271 *wl, struct ieee80211_vif *vif, + const u8 *ssid, size_t ssid_len, struct cfg80211_scan_request *req); int wl1271_scan_stop(struct wl1271 *wl); int wl1271_scan_build_probe_req(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, const u8 *ie, size_t ie_len, u8 band); -void wl1271_scan_stm(struct wl1271 *wl); +void wl1271_scan_stm(struct wl1271 *wl, struct ieee80211_vif *vif); void wl1271_scan_complete_work(struct work_struct *work); int wl1271_scan_sched_scan_config(struct wl1271 *wl, + struct wl12xx_vif *wlvif, struct cfg80211_sched_scan_request *req, struct ieee80211_sched_scan_ies *ies); -int wl1271_scan_sched_scan_start(struct wl1271 *wl); +int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif); void wl1271_scan_sched_scan_stop(struct wl1271 *wl); void wl1271_scan_sched_scan_results(struct wl1271 *wl); diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c index 516a8980723c..468a50553fac 100644 --- a/drivers/net/wireless/wl12xx/sdio.c +++ b/drivers/net/wireless/wl12xx/sdio.c @@ -24,6 +24,7 @@ #include <linux/irq.h> #include <linux/module.h> #include <linux/vmalloc.h> +#include <linux/platform_device.h> #include <linux/mmc/sdio_func.h> #include <linux/mmc/sdio_ids.h> #include <linux/mmc/card.h> @@ -44,107 +45,67 @@ #define SDIO_DEVICE_ID_TI_WL1271 0x4076 #endif +struct wl12xx_sdio_glue { + struct device *dev; + struct platform_device *core; +}; + static const struct sdio_device_id wl1271_devices[] __devinitconst = { { SDIO_DEVICE(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271) }, {} }; MODULE_DEVICE_TABLE(sdio, wl1271_devices); -static void wl1271_sdio_set_block_size(struct wl1271 *wl, unsigned int blksz) -{ - sdio_claim_host(wl->if_priv); - sdio_set_block_size(wl->if_priv, blksz); - sdio_release_host(wl->if_priv); -} - -static inline struct sdio_func *wl_to_func(struct wl1271 *wl) -{ - return wl->if_priv; -} - -static struct device *wl1271_sdio_wl_to_dev(struct wl1271 *wl) -{ - return &(wl_to_func(wl)->dev); -} - -static irqreturn_t wl1271_hardirq(int irq, void *cookie) +static void wl1271_sdio_set_block_size(struct device *child, + unsigned int blksz) { - struct wl1271 *wl = cookie; - unsigned long flags; + struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent); + struct sdio_func *func = dev_to_sdio_func(glue->dev); - wl1271_debug(DEBUG_IRQ, "IRQ"); - - /* complete the ELP completion */ - spin_lock_irqsave(&wl->wl_lock, flags); - set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags); - if (wl->elp_compl) { - complete(wl->elp_compl); - wl->elp_compl = NULL; - } - - if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) { - /* don't enqueue a work right now. mark it as pending */ - set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags); - wl1271_debug(DEBUG_IRQ, "should not enqueue work"); - disable_irq_nosync(wl->irq); - pm_wakeup_event(wl1271_sdio_wl_to_dev(wl), 0); - spin_unlock_irqrestore(&wl->wl_lock, flags); - return IRQ_HANDLED; - } - spin_unlock_irqrestore(&wl->wl_lock, flags); - - return IRQ_WAKE_THREAD; -} - -static void wl1271_sdio_disable_interrupts(struct wl1271 *wl) -{ - disable_irq(wl->irq); -} - -static void wl1271_sdio_enable_interrupts(struct wl1271 *wl) -{ - enable_irq(wl->irq); + sdio_claim_host(func); + sdio_set_block_size(func, blksz); + sdio_release_host(func); } -static void wl1271_sdio_raw_read(struct wl1271 *wl, int addr, void *buf, +static void wl12xx_sdio_raw_read(struct device *child, int addr, void *buf, size_t len, bool fixed) { int ret; - struct sdio_func *func = wl_to_func(wl); + struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent); + struct sdio_func *func = dev_to_sdio_func(glue->dev); if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) { ((u8 *)buf)[0] = sdio_f0_readb(func, addr, &ret); - wl1271_debug(DEBUG_SDIO, "sdio read 52 addr 0x%x, byte 0x%02x", - addr, ((u8 *)buf)[0]); + dev_dbg(child->parent, "sdio read 52 addr 0x%x, byte 0x%02x\n", + addr, ((u8 *)buf)[0]); } else { if (fixed) ret = sdio_readsb(func, buf, addr, len); else ret = sdio_memcpy_fromio(func, buf, addr, len); - wl1271_debug(DEBUG_SDIO, "sdio read 53 addr 0x%x, %zu bytes", - addr, len); - wl1271_dump_ascii(DEBUG_SDIO, "data: ", buf, len); + dev_dbg(child->parent, "sdio read 53 addr 0x%x, %zu bytes\n", + addr, len); } if (ret) - wl1271_error("sdio read failed (%d)", ret); + dev_err(child->parent, "sdio read failed (%d)\n", ret); } -static void wl1271_sdio_raw_write(struct wl1271 *wl, int addr, void *buf, +static void wl12xx_sdio_raw_write(struct device *child, int addr, void *buf, size_t len, bool fixed) { int ret; - struct sdio_func *func = wl_to_func(wl); + struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent); + struct sdio_func *func = dev_to_sdio_func(glue->dev); if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) { sdio_f0_writeb(func, ((u8 *)buf)[0], addr, &ret); - wl1271_debug(DEBUG_SDIO, "sdio write 52 addr 0x%x, byte 0x%02x", - addr, ((u8 *)buf)[0]); + dev_dbg(child->parent, "sdio write 52 addr 0x%x, byte 0x%02x\n", + addr, ((u8 *)buf)[0]); } else { - wl1271_debug(DEBUG_SDIO, "sdio write 53 addr 0x%x, %zu bytes", - addr, len); - wl1271_dump_ascii(DEBUG_SDIO, "data: ", buf, len); + dev_dbg(child->parent, "sdio write 53 addr 0x%x, %zu bytes\n", + addr, len); if (fixed) ret = sdio_writesb(func, addr, buf, len); @@ -153,13 +114,13 @@ static void wl1271_sdio_raw_write(struct wl1271 *wl, int addr, void *buf, } if (ret) - wl1271_error("sdio write failed (%d)", ret); + dev_err(child->parent, "sdio write failed (%d)\n", ret); } -static int wl1271_sdio_power_on(struct wl1271 *wl) +static int wl12xx_sdio_power_on(struct wl12xx_sdio_glue *glue) { - struct sdio_func *func = wl_to_func(wl); int ret; + struct sdio_func *func = dev_to_sdio_func(glue->dev); /* If enabled, tell runtime PM not to power off the card */ if (pm_runtime_enabled(&func->dev)) { @@ -180,10 +141,10 @@ out: return ret; } -static int wl1271_sdio_power_off(struct wl1271 *wl) +static int wl12xx_sdio_power_off(struct wl12xx_sdio_glue *glue) { - struct sdio_func *func = wl_to_func(wl); int ret; + struct sdio_func *func = dev_to_sdio_func(glue->dev); sdio_disable_func(func); sdio_release_host(func); @@ -200,46 +161,43 @@ static int wl1271_sdio_power_off(struct wl1271 *wl) return ret; } -static int wl1271_sdio_set_power(struct wl1271 *wl, bool enable) +static int wl12xx_sdio_set_power(struct device *child, bool enable) { + struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent); + if (enable) - return wl1271_sdio_power_on(wl); + return wl12xx_sdio_power_on(glue); else - return wl1271_sdio_power_off(wl); + return wl12xx_sdio_power_off(glue); } static struct wl1271_if_operations sdio_ops = { - .read = wl1271_sdio_raw_read, - .write = wl1271_sdio_raw_write, - .power = wl1271_sdio_set_power, - .dev = wl1271_sdio_wl_to_dev, - .enable_irq = wl1271_sdio_enable_interrupts, - .disable_irq = wl1271_sdio_disable_interrupts, + .read = wl12xx_sdio_raw_read, + .write = wl12xx_sdio_raw_write, + .power = wl12xx_sdio_set_power, .set_block_size = wl1271_sdio_set_block_size, }; static int __devinit wl1271_probe(struct sdio_func *func, const struct sdio_device_id *id) { - struct ieee80211_hw *hw; - const struct wl12xx_platform_data *wlan_data; - struct wl1271 *wl; - unsigned long irqflags; + struct wl12xx_platform_data *wlan_data; + struct wl12xx_sdio_glue *glue; + struct resource res[1]; mmc_pm_flag_t mmcflags; - int ret; + int ret = -ENOMEM; /* We are only able to handle the wlan function */ if (func->num != 0x02) return -ENODEV; - hw = wl1271_alloc_hw(); - if (IS_ERR(hw)) - return PTR_ERR(hw); - - wl = hw->priv; + glue = kzalloc(sizeof(*glue), GFP_KERNEL); + if (!glue) { + dev_err(&func->dev, "can't allocate glue\n"); + goto out; + } - wl->if_priv = func; - wl->if_ops = &sdio_ops; + glue->dev = &func->dev; /* Grab access to FN0 for ELP reg. */ func->card->quirks |= MMC_QUIRK_LENIENT_FN0; @@ -250,80 +208,79 @@ static int __devinit wl1271_probe(struct sdio_func *func, wlan_data = wl12xx_get_platform_data(); if (IS_ERR(wlan_data)) { ret = PTR_ERR(wlan_data); - wl1271_error("missing wlan platform data: %d", ret); - goto out_free; + dev_err(glue->dev, "missing wlan platform data: %d\n", ret); + goto out_free_glue; } - wl->irq = wlan_data->irq; - wl->ref_clock = wlan_data->board_ref_clock; - wl->tcxo_clock = wlan_data->board_tcxo_clock; - wl->platform_quirks = wlan_data->platform_quirks; + /* if sdio can keep power while host is suspended, enable wow */ + mmcflags = sdio_get_host_pm_caps(func); + dev_dbg(glue->dev, "sdio PM caps = 0x%x\n", mmcflags); - if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) - irqflags = IRQF_TRIGGER_RISING; - else - irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT; - - ret = request_threaded_irq(wl->irq, wl1271_hardirq, wl1271_irq, - irqflags, - DRIVER_NAME, wl); - if (ret < 0) { - wl1271_error("request_irq() failed: %d", ret); - goto out_free; - } + if (mmcflags & MMC_PM_KEEP_POWER) + wlan_data->pwr_in_suspend = true; + + wlan_data->ops = &sdio_ops; - ret = enable_irq_wake(wl->irq); - if (!ret) { - wl->irq_wake_enabled = true; - device_init_wakeup(wl1271_sdio_wl_to_dev(wl), 1); + sdio_set_drvdata(func, glue); - /* if sdio can keep power while host is suspended, enable wow */ - mmcflags = sdio_get_host_pm_caps(func); - wl1271_debug(DEBUG_SDIO, "sdio PM caps = 0x%x", mmcflags); + /* Tell PM core that we don't need the card to be powered now */ + pm_runtime_put_noidle(&func->dev); - if (mmcflags & MMC_PM_KEEP_POWER) - hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY; + glue->core = platform_device_alloc("wl12xx", -1); + if (!glue->core) { + dev_err(glue->dev, "can't allocate platform_device"); + ret = -ENOMEM; + goto out_free_glue; } - disable_irq(wl->irq); - ret = wl1271_init_ieee80211(wl); - if (ret) - goto out_irq; + glue->core->dev.parent = &func->dev; - ret = wl1271_register_hw(wl); - if (ret) - goto out_irq; + memset(res, 0x00, sizeof(res)); - sdio_set_drvdata(func, wl); + res[0].start = wlan_data->irq; + res[0].flags = IORESOURCE_IRQ; + res[0].name = "irq"; - /* Tell PM core that we don't need the card to be powered now */ - pm_runtime_put_noidle(&func->dev); + ret = platform_device_add_resources(glue->core, res, ARRAY_SIZE(res)); + if (ret) { + dev_err(glue->dev, "can't add resources\n"); + goto out_dev_put; + } + ret = platform_device_add_data(glue->core, wlan_data, + sizeof(*wlan_data)); + if (ret) { + dev_err(glue->dev, "can't add platform data\n"); + goto out_dev_put; + } + + ret = platform_device_add(glue->core); + if (ret) { + dev_err(glue->dev, "can't add platform device\n"); + goto out_dev_put; + } return 0; - out_irq: - free_irq(wl->irq, wl); +out_dev_put: + platform_device_put(glue->core); - out_free: - wl1271_free_hw(wl); +out_free_glue: + kfree(glue); +out: return ret; } static void __devexit wl1271_remove(struct sdio_func *func) { - struct wl1271 *wl = sdio_get_drvdata(func); + struct wl12xx_sdio_glue *glue = sdio_get_drvdata(func); /* Undo decrement done above in wl1271_probe */ pm_runtime_get_noresume(&func->dev); - wl1271_unregister_hw(wl); - if (wl->irq_wake_enabled) { - device_init_wakeup(wl1271_sdio_wl_to_dev(wl), 0); - disable_irq_wake(wl->irq); - } - free_irq(wl->irq, wl); - wl1271_free_hw(wl); + platform_device_del(glue->core); + platform_device_put(glue->core); + kfree(glue); } #ifdef CONFIG_PM @@ -332,20 +289,21 @@ static int wl1271_suspend(struct device *dev) /* Tell MMC/SDIO core it's OK to power down the card * (if it isn't already), but not to remove it completely */ struct sdio_func *func = dev_to_sdio_func(dev); - struct wl1271 *wl = sdio_get_drvdata(func); + struct wl12xx_sdio_glue *glue = sdio_get_drvdata(func); + struct wl1271 *wl = platform_get_drvdata(glue->core); mmc_pm_flag_t sdio_flags; int ret = 0; - wl1271_debug(DEBUG_MAC80211, "wl1271 suspend. wow_enabled: %d", - wl->wow_enabled); + dev_dbg(dev, "wl1271 suspend. wow_enabled: %d\n", + wl->wow_enabled); /* check whether sdio should keep power */ if (wl->wow_enabled) { sdio_flags = sdio_get_host_pm_caps(func); if (!(sdio_flags & MMC_PM_KEEP_POWER)) { - wl1271_error("can't keep power while host " - "is suspended"); + dev_err(dev, "can't keep power while host " + "is suspended\n"); ret = -EINVAL; goto out; } @@ -353,7 +311,7 @@ static int wl1271_suspend(struct device *dev) /* keep power while host suspended */ ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); if (ret) { - wl1271_error("error while trying to keep power"); + dev_err(dev, "error while trying to keep power\n"); goto out; } @@ -367,9 +325,10 @@ out: static int wl1271_resume(struct device *dev) { struct sdio_func *func = dev_to_sdio_func(dev); - struct wl1271 *wl = sdio_get_drvdata(func); + struct wl12xx_sdio_glue *glue = sdio_get_drvdata(func); + struct wl1271 *wl = platform_get_drvdata(glue->core); - wl1271_debug(DEBUG_MAC80211, "wl1271 resume"); + dev_dbg(dev, "wl1271 resume\n"); if (wl->wow_enabled) { /* claim back host */ sdio_claim_host(func); diff --git a/drivers/net/wireless/wl12xx/sdio_test.c b/drivers/net/wireless/wl12xx/sdio_test.c deleted file mode 100644 index f25d5d9212e7..000000000000 --- a/drivers/net/wireless/wl12xx/sdio_test.c +++ /dev/null @@ -1,543 +0,0 @@ -/* - * SDIO testing driver for wl12xx - * - * Copyright (C) 2010 Nokia Corporation - * - * Contact: Roger Quadros <roger.quadros@nokia.com> - * - * wl12xx read/write routines taken from the main module - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include <linux/irq.h> -#include <linux/module.h> -#include <linux/crc7.h> -#include <linux/vmalloc.h> -#include <linux/mmc/sdio_func.h> -#include <linux/mmc/sdio_ids.h> -#include <linux/mmc/card.h> -#include <linux/mmc/host.h> -#include <linux/gpio.h> -#include <linux/wl12xx.h> -#include <linux/kthread.h> -#include <linux/firmware.h> -#include <linux/pm_runtime.h> - -#include "wl12xx.h" -#include "io.h" -#include "boot.h" - -#ifndef SDIO_VENDOR_ID_TI -#define SDIO_VENDOR_ID_TI 0x0097 -#endif - -#ifndef SDIO_DEVICE_ID_TI_WL1271 -#define SDIO_DEVICE_ID_TI_WL1271 0x4076 -#endif - -static bool rx, tx; - -module_param(rx, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(rx, "Perform rx test. Default (0). " - "This test continuously reads data from the SDIO device.\n"); - -module_param(tx, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(tx, "Perform tx test. Default (0). " - "This test continuously writes data to the SDIO device.\n"); - -struct wl1271_test { - struct wl1271 wl; - struct task_struct *test_task; -}; - -static const struct sdio_device_id wl1271_devices[] = { - { SDIO_DEVICE(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271) }, - {} -}; - -static inline struct sdio_func *wl_to_func(struct wl1271 *wl) -{ - return wl->if_priv; -} - -static struct device *wl1271_sdio_wl_to_dev(struct wl1271 *wl) -{ - return &(wl_to_func(wl)->dev); -} - -static void wl1271_sdio_raw_read(struct wl1271 *wl, int addr, void *buf, - size_t len, bool fixed) -{ - int ret = 0; - struct sdio_func *func = wl_to_func(wl); - - if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) { - ((u8 *)buf)[0] = sdio_f0_readb(func, addr, &ret); - wl1271_debug(DEBUG_SDIO, "sdio read 52 addr 0x%x, byte 0x%02x", - addr, ((u8 *)buf)[0]); - } else { - if (fixed) - ret = sdio_readsb(func, buf, addr, len); - else - ret = sdio_memcpy_fromio(func, buf, addr, len); - - wl1271_debug(DEBUG_SDIO, "sdio read 53 addr 0x%x, %zu bytes", - addr, len); - wl1271_dump_ascii(DEBUG_SDIO, "data: ", buf, len); - } - - if (ret) - wl1271_error("sdio read failed (%d)", ret); -} - -static void wl1271_sdio_raw_write(struct wl1271 *wl, int addr, void *buf, - size_t len, bool fixed) -{ - int ret = 0; - struct sdio_func *func = wl_to_func(wl); - - if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) { - sdio_f0_writeb(func, ((u8 *)buf)[0], addr, &ret); - wl1271_debug(DEBUG_SDIO, "sdio write 52 addr 0x%x, byte 0x%02x", - addr, ((u8 *)buf)[0]); - } else { - wl1271_debug(DEBUG_SDIO, "sdio write 53 addr 0x%x, %zu bytes", - addr, len); - wl1271_dump_ascii(DEBUG_SDIO, "data: ", buf, len); - - if (fixed) - ret = sdio_writesb(func, addr, buf, len); - else - ret = sdio_memcpy_toio(func, addr, buf, len); - } - if (ret) - wl1271_error("sdio write failed (%d)", ret); - -} - -static int wl1271_sdio_set_power(struct wl1271 *wl, bool enable) -{ - struct sdio_func *func = wl_to_func(wl); - int ret; - - /* Let the SDIO stack handle wlan_enable control, so we - * keep host claimed while wlan is in use to keep wl1271 - * alive. - */ - if (enable) { - /* Power up the card */ - ret = pm_runtime_get_sync(&func->dev); - if (ret < 0) - goto out; - - /* Runtime PM might be disabled, power up the card manually */ - ret = mmc_power_restore_host(func->card->host); - if (ret < 0) - goto out; - - sdio_claim_host(func); - sdio_enable_func(func); - } else { - sdio_disable_func(func); - sdio_release_host(func); - - /* Runtime PM might be disabled, power off the card manually */ - ret = mmc_power_save_host(func->card->host); - if (ret < 0) - goto out; - - /* Power down the card */ - ret = pm_runtime_put_sync(&func->dev); - } - -out: - return ret; -} - -static void wl1271_sdio_disable_interrupts(struct wl1271 *wl) -{ -} - -static void wl1271_sdio_enable_interrupts(struct wl1271 *wl) -{ -} - - -static struct wl1271_if_operations sdio_ops = { - .read = wl1271_sdio_raw_read, - .write = wl1271_sdio_raw_write, - .power = wl1271_sdio_set_power, - .dev = wl1271_sdio_wl_to_dev, - .enable_irq = wl1271_sdio_enable_interrupts, - .disable_irq = wl1271_sdio_disable_interrupts, -}; - -static void wl1271_fw_wakeup(struct wl1271 *wl) -{ - u32 elp_reg; - - elp_reg = ELPCTRL_WAKE_UP; - wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg); -} - -static int wl1271_fetch_firmware(struct wl1271 *wl) -{ - const struct firmware *fw; - int ret; - - if (wl->chip.id == CHIP_ID_1283_PG20) - ret = request_firmware(&fw, WL128X_FW_NAME, - wl1271_wl_to_dev(wl)); - else - ret = request_firmware(&fw, WL127X_FW_NAME, - wl1271_wl_to_dev(wl)); - - if (ret < 0) { - wl1271_error("could not get firmware: %d", ret); - return ret; - } - - if (fw->size % 4) { - wl1271_error("firmware size is not multiple of 32 bits: %zu", - fw->size); - ret = -EILSEQ; - goto out; - } - - wl->fw_len = fw->size; - wl->fw = vmalloc(wl->fw_len); - - if (!wl->fw) { - wl1271_error("could not allocate memory for the firmware"); - ret = -ENOMEM; - goto out; - } - - memcpy(wl->fw, fw->data, wl->fw_len); - - ret = 0; - -out: - release_firmware(fw); - - return ret; -} - -static int wl1271_fetch_nvs(struct wl1271 *wl) -{ - const struct firmware *fw; - int ret; - - ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl)); - - if (ret < 0) { - wl1271_error("could not get nvs file: %d", ret); - return ret; - } - - wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL); - - if (!wl->nvs) { - wl1271_error("could not allocate memory for the nvs file"); - ret = -ENOMEM; - goto out; - } - - wl->nvs_len = fw->size; - -out: - release_firmware(fw); - - return ret; -} - -static int wl1271_chip_wakeup(struct wl1271 *wl) -{ - struct wl1271_partition_set partition; - int ret; - - msleep(WL1271_PRE_POWER_ON_SLEEP); - ret = wl1271_power_on(wl); - if (ret) - return ret; - - msleep(WL1271_POWER_ON_SLEEP); - - /* We don't need a real memory partition here, because we only want - * to use the registers at this point. */ - memset(&partition, 0, sizeof(partition)); - partition.reg.start = REGISTERS_BASE; - partition.reg.size = REGISTERS_DOWN_SIZE; - wl1271_set_partition(wl, &partition); - - /* ELP module wake up */ - wl1271_fw_wakeup(wl); - - /* whal_FwCtrl_BootSm() */ - - /* 0. read chip id from CHIP_ID */ - wl->chip.id = wl1271_read32(wl, CHIP_ID_B); - - /* 1. check if chip id is valid */ - - switch (wl->chip.id) { - case CHIP_ID_1271_PG10: - wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete", - wl->chip.id); - break; - case CHIP_ID_1271_PG20: - wl1271_notice("chip id 0x%x (1271 PG20)", - wl->chip.id); - break; - case CHIP_ID_1283_PG20: - wl1271_notice("chip id 0x%x (1283 PG20)", - wl->chip.id); - break; - case CHIP_ID_1283_PG10: - default: - wl1271_warning("unsupported chip id: 0x%x", wl->chip.id); - return -ENODEV; - } - - return ret; -} - -static struct wl1271_partition_set part_down = { - .mem = { - .start = 0x00000000, - .size = 0x000177c0 - }, - .reg = { - .start = REGISTERS_BASE, - .size = 0x00008800 - }, - .mem2 = { - .start = 0x00000000, - .size = 0x00000000 - }, - .mem3 = { - .start = 0x00000000, - .size = 0x00000000 - }, -}; - -static int tester(void *data) -{ - struct wl1271 *wl = data; - struct sdio_func *func = wl_to_func(wl); - struct device *pdev = &func->dev; - int ret = 0; - bool rx_started = 0; - bool tx_started = 0; - uint8_t *tx_buf, *rx_buf; - int test_size = PAGE_SIZE; - u32 addr = 0; - struct wl1271_partition_set partition; - - /* We assume chip is powered up and firmware fetched */ - - memcpy(&partition, &part_down, sizeof(partition)); - partition.mem.start = addr; - wl1271_set_partition(wl, &partition); - - tx_buf = kmalloc(test_size, GFP_KERNEL); - rx_buf = kmalloc(test_size, GFP_KERNEL); - if (!tx_buf || !rx_buf) { - dev_err(pdev, - "Could not allocate memory. Test will not run.\n"); - ret = -ENOMEM; - goto free; - } - - memset(tx_buf, 0x5a, test_size); - - /* write something in data area so we can read it back */ - wl1271_write(wl, addr, tx_buf, test_size, false); - - while (!kthread_should_stop()) { - if (rx && !rx_started) { - dev_info(pdev, "starting rx test\n"); - rx_started = 1; - } else if (!rx && rx_started) { - dev_info(pdev, "stopping rx test\n"); - rx_started = 0; - } - - if (tx && !tx_started) { - dev_info(pdev, "starting tx test\n"); - tx_started = 1; - } else if (!tx && tx_started) { - dev_info(pdev, "stopping tx test\n"); - tx_started = 0; - } - - if (rx_started) - wl1271_read(wl, addr, rx_buf, test_size, false); - - if (tx_started) - wl1271_write(wl, addr, tx_buf, test_size, false); - - if (!rx_started && !tx_started) - msleep(100); - } - -free: - kfree(tx_buf); - kfree(rx_buf); - return ret; -} - -static int __devinit wl1271_probe(struct sdio_func *func, - const struct sdio_device_id *id) -{ - const struct wl12xx_platform_data *wlan_data; - struct wl1271 *wl; - struct wl1271_test *wl_test; - int ret = 0; - - /* wl1271 has 2 sdio functions we handle just the wlan part */ - if (func->num != 0x02) - return -ENODEV; - - wl_test = kzalloc(sizeof(struct wl1271_test), GFP_KERNEL); - if (!wl_test) { - dev_err(&func->dev, "Could not allocate memory\n"); - return -ENOMEM; - } - - wl = &wl_test->wl; - - wl->if_priv = func; - wl->if_ops = &sdio_ops; - - /* Grab access to FN0 for ELP reg. */ - func->card->quirks |= MMC_QUIRK_LENIENT_FN0; - - /* Use block mode for transferring over one block size of data */ - func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; - - wlan_data = wl12xx_get_platform_data(); - if (IS_ERR(wlan_data)) { - ret = PTR_ERR(wlan_data); - dev_err(&func->dev, "missing wlan platform data: %d\n", ret); - goto out_free; - } - - wl->irq = wlan_data->irq; - wl->ref_clock = wlan_data->board_ref_clock; - wl->tcxo_clock = wlan_data->board_tcxo_clock; - - sdio_set_drvdata(func, wl_test); - - /* power up the device */ - ret = wl1271_chip_wakeup(wl); - if (ret) { - dev_err(&func->dev, "could not wake up chip\n"); - goto out_free; - } - - if (wl->fw == NULL) { - ret = wl1271_fetch_firmware(wl); - if (ret < 0) { - dev_err(&func->dev, "firmware fetch error\n"); - goto out_off; - } - } - - /* fetch NVS */ - if (wl->nvs == NULL) { - ret = wl1271_fetch_nvs(wl); - if (ret < 0) { - dev_err(&func->dev, "NVS fetch error\n"); - goto out_off; - } - } - - ret = wl1271_load_firmware(wl); - if (ret < 0) { - dev_err(&func->dev, "firmware load error: %d\n", ret); - goto out_free; - } - - dev_info(&func->dev, "initialized\n"); - - /* I/O testing will be done in the tester thread */ - - wl_test->test_task = kthread_run(tester, wl, "sdio_tester"); - if (IS_ERR(wl_test->test_task)) { - dev_err(&func->dev, "unable to create kernel thread\n"); - ret = PTR_ERR(wl_test->test_task); - goto out_free; - } - - return 0; - -out_off: - /* power off the chip */ - wl1271_power_off(wl); - -out_free: - kfree(wl_test); - return ret; -} - -static void __devexit wl1271_remove(struct sdio_func *func) -{ - struct wl1271_test *wl_test = sdio_get_drvdata(func); - - /* stop the I/O test thread */ - kthread_stop(wl_test->test_task); - - /* power off the chip */ - wl1271_power_off(&wl_test->wl); - - vfree(wl_test->wl.fw); - wl_test->wl.fw = NULL; - kfree(wl_test->wl.nvs); - wl_test->wl.nvs = NULL; - - kfree(wl_test); -} - -static struct sdio_driver wl1271_sdio_driver = { - .name = "wl12xx_sdio_test", - .id_table = wl1271_devices, - .probe = wl1271_probe, - .remove = __devexit_p(wl1271_remove), -}; - -static int __init wl1271_init(void) -{ - int ret; - - ret = sdio_register_driver(&wl1271_sdio_driver); - if (ret < 0) - pr_err("failed to register sdio driver: %d\n", ret); - - return ret; -} -module_init(wl1271_init); - -static void __exit wl1271_exit(void) -{ - sdio_unregister_driver(&wl1271_sdio_driver); -} -module_exit(wl1271_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Roger Quadros <roger.quadros@nokia.com>"); - diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c index 0f9718677860..92caa7ce6053 100644 --- a/drivers/net/wireless/wl12xx/spi.c +++ b/drivers/net/wireless/wl12xx/spi.c @@ -27,6 +27,7 @@ #include <linux/crc7.h> #include <linux/spi/spi.h> #include <linux/wl12xx.h> +#include <linux/platform_device.h> #include <linux/slab.h> #include "wl12xx.h" @@ -69,35 +70,22 @@ #define WSPI_MAX_NUM_OF_CHUNKS (WL1271_AGGR_BUFFER_SIZE / WSPI_MAX_CHUNK_SIZE) -static inline struct spi_device *wl_to_spi(struct wl1271 *wl) -{ - return wl->if_priv; -} - -static struct device *wl1271_spi_wl_to_dev(struct wl1271 *wl) -{ - return &(wl_to_spi(wl)->dev); -} - -static void wl1271_spi_disable_interrupts(struct wl1271 *wl) -{ - disable_irq(wl->irq); -} - -static void wl1271_spi_enable_interrupts(struct wl1271 *wl) -{ - enable_irq(wl->irq); -} +struct wl12xx_spi_glue { + struct device *dev; + struct platform_device *core; +}; -static void wl1271_spi_reset(struct wl1271 *wl) +static void wl12xx_spi_reset(struct device *child) { + struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent); u8 *cmd; struct spi_transfer t; struct spi_message m; cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); if (!cmd) { - wl1271_error("could not allocate cmd for spi reset"); + dev_err(child->parent, + "could not allocate cmd for spi reset\n"); return; } @@ -110,21 +98,22 @@ static void wl1271_spi_reset(struct wl1271 *wl) t.len = WSPI_INIT_CMD_LEN; spi_message_add_tail(&t, &m); - spi_sync(wl_to_spi(wl), &m); + spi_sync(to_spi_device(glue->dev), &m); - wl1271_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); kfree(cmd); } -static void wl1271_spi_init(struct wl1271 *wl) +static void wl12xx_spi_init(struct device *child) { + struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent); u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd; struct spi_transfer t; struct spi_message m; cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); if (!cmd) { - wl1271_error("could not allocate cmd for spi init"); + dev_err(child->parent, + "could not allocate cmd for spi init\n"); return; } @@ -165,15 +154,16 @@ static void wl1271_spi_init(struct wl1271 *wl) t.len = WSPI_INIT_CMD_LEN; spi_message_add_tail(&t, &m); - spi_sync(wl_to_spi(wl), &m); - wl1271_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN); + spi_sync(to_spi_device(glue->dev), &m); kfree(cmd); } #define WL1271_BUSY_WORD_TIMEOUT 1000 -static int wl1271_spi_read_busy(struct wl1271 *wl) +static int wl12xx_spi_read_busy(struct device *child) { + struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent); + struct wl1271 *wl = dev_get_drvdata(child); struct spi_transfer t[1]; struct spi_message m; u32 *busy_buf; @@ -194,20 +184,22 @@ static int wl1271_spi_read_busy(struct wl1271 *wl) t[0].len = sizeof(u32); t[0].cs_change = true; spi_message_add_tail(&t[0], &m); - spi_sync(wl_to_spi(wl), &m); + spi_sync(to_spi_device(glue->dev), &m); if (*busy_buf & 0x1) return 0; } /* The SPI bus is unresponsive, the read failed. */ - wl1271_error("SPI read busy-word timeout!\n"); + dev_err(child->parent, "SPI read busy-word timeout!\n"); return -ETIMEDOUT; } -static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf, +static void wl12xx_spi_raw_read(struct device *child, int addr, void *buf, size_t len, bool fixed) { + struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent); + struct wl1271 *wl = dev_get_drvdata(child); struct spi_transfer t[2]; struct spi_message m; u32 *busy_buf; @@ -243,10 +235,10 @@ static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf, t[1].cs_change = true; spi_message_add_tail(&t[1], &m); - spi_sync(wl_to_spi(wl), &m); + spi_sync(to_spi_device(glue->dev), &m); if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1) && - wl1271_spi_read_busy(wl)) { + wl12xx_spi_read_busy(child)) { memset(buf, 0, chunk_len); return; } @@ -259,10 +251,7 @@ static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf, t[0].cs_change = true; spi_message_add_tail(&t[0], &m); - spi_sync(wl_to_spi(wl), &m); - - wl1271_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd)); - wl1271_dump(DEBUG_SPI, "spi_read buf <- ", buf, chunk_len); + spi_sync(to_spi_device(glue->dev), &m); if (!fixed) addr += chunk_len; @@ -271,9 +260,10 @@ static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf, } } -static void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf, - size_t len, bool fixed) +static void wl12xx_spi_raw_write(struct device *child, int addr, void *buf, + size_t len, bool fixed) { + struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent); struct spi_transfer t[2 * WSPI_MAX_NUM_OF_CHUNKS]; struct spi_message m; u32 commands[WSPI_MAX_NUM_OF_CHUNKS]; @@ -308,9 +298,6 @@ static void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf, t[i].len = chunk_len; spi_message_add_tail(&t[i++], &m); - wl1271_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); - wl1271_dump(DEBUG_SPI, "spi_write buf -> ", buf, chunk_len); - if (!fixed) addr += chunk_len; buf += chunk_len; @@ -318,72 +305,41 @@ static void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf, cmd++; } - spi_sync(wl_to_spi(wl), &m); -} - -static irqreturn_t wl1271_hardirq(int irq, void *cookie) -{ - struct wl1271 *wl = cookie; - unsigned long flags; - - wl1271_debug(DEBUG_IRQ, "IRQ"); - - /* complete the ELP completion */ - spin_lock_irqsave(&wl->wl_lock, flags); - set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags); - if (wl->elp_compl) { - complete(wl->elp_compl); - wl->elp_compl = NULL; - } - spin_unlock_irqrestore(&wl->wl_lock, flags); - - return IRQ_WAKE_THREAD; -} - -static int wl1271_spi_set_power(struct wl1271 *wl, bool enable) -{ - if (wl->set_power) - wl->set_power(enable); - - return 0; + spi_sync(to_spi_device(glue->dev), &m); } static struct wl1271_if_operations spi_ops = { - .read = wl1271_spi_raw_read, - .write = wl1271_spi_raw_write, - .reset = wl1271_spi_reset, - .init = wl1271_spi_init, - .power = wl1271_spi_set_power, - .dev = wl1271_spi_wl_to_dev, - .enable_irq = wl1271_spi_enable_interrupts, - .disable_irq = wl1271_spi_disable_interrupts, + .read = wl12xx_spi_raw_read, + .write = wl12xx_spi_raw_write, + .reset = wl12xx_spi_reset, + .init = wl12xx_spi_init, .set_block_size = NULL, }; static int __devinit wl1271_probe(struct spi_device *spi) { + struct wl12xx_spi_glue *glue; struct wl12xx_platform_data *pdata; - struct ieee80211_hw *hw; - struct wl1271 *wl; - unsigned long irqflags; - int ret; + struct resource res[1]; + int ret = -ENOMEM; pdata = spi->dev.platform_data; if (!pdata) { - wl1271_error("no platform data"); + dev_err(&spi->dev, "no platform data\n"); return -ENODEV; } - hw = wl1271_alloc_hw(); - if (IS_ERR(hw)) - return PTR_ERR(hw); + pdata->ops = &spi_ops; - wl = hw->priv; + glue = kzalloc(sizeof(*glue), GFP_KERNEL); + if (!glue) { + dev_err(&spi->dev, "can't allocate glue\n"); + goto out; + } - dev_set_drvdata(&spi->dev, wl); - wl->if_priv = spi; + glue->dev = &spi->dev; - wl->if_ops = &spi_ops; + spi_set_drvdata(spi, glue); /* This is the only SPI value that we need to set here, the rest * comes from the board-peripherals file */ @@ -391,69 +347,61 @@ static int __devinit wl1271_probe(struct spi_device *spi) ret = spi_setup(spi); if (ret < 0) { - wl1271_error("spi_setup failed"); - goto out_free; + dev_err(glue->dev, "spi_setup failed\n"); + goto out_free_glue; } - wl->set_power = pdata->set_power; - if (!wl->set_power) { - wl1271_error("set power function missing in platform data"); - ret = -ENODEV; - goto out_free; + glue->core = platform_device_alloc("wl12xx", -1); + if (!glue->core) { + dev_err(glue->dev, "can't allocate platform_device\n"); + ret = -ENOMEM; + goto out_free_glue; } - wl->ref_clock = pdata->board_ref_clock; - wl->tcxo_clock = pdata->board_tcxo_clock; - wl->platform_quirks = pdata->platform_quirks; + glue->core->dev.parent = &spi->dev; - if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) - irqflags = IRQF_TRIGGER_RISING; - else - irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT; + memset(res, 0x00, sizeof(res)); - wl->irq = spi->irq; - if (wl->irq < 0) { - wl1271_error("irq missing in platform data"); - ret = -ENODEV; - goto out_free; - } + res[0].start = spi->irq; + res[0].flags = IORESOURCE_IRQ; + res[0].name = "irq"; - ret = request_threaded_irq(wl->irq, wl1271_hardirq, wl1271_irq, - irqflags, - DRIVER_NAME, wl); - if (ret < 0) { - wl1271_error("request_irq() failed: %d", ret); - goto out_free; + ret = platform_device_add_resources(glue->core, res, ARRAY_SIZE(res)); + if (ret) { + dev_err(glue->dev, "can't add resources\n"); + goto out_dev_put; } - disable_irq(wl->irq); - - ret = wl1271_init_ieee80211(wl); - if (ret) - goto out_irq; + ret = platform_device_add_data(glue->core, pdata, sizeof(*pdata)); + if (ret) { + dev_err(glue->dev, "can't add platform data\n"); + goto out_dev_put; + } - ret = wl1271_register_hw(wl); - if (ret) - goto out_irq; + ret = platform_device_add(glue->core); + if (ret) { + dev_err(glue->dev, "can't register platform device\n"); + goto out_dev_put; + } return 0; - out_irq: - free_irq(wl->irq, wl); - - out_free: - wl1271_free_hw(wl); +out_dev_put: + platform_device_put(glue->core); +out_free_glue: + kfree(glue); +out: return ret; } static int __devexit wl1271_remove(struct spi_device *spi) { - struct wl1271 *wl = dev_get_drvdata(&spi->dev); + struct wl12xx_spi_glue *glue = spi_get_drvdata(spi); - wl1271_unregister_hw(wl); - free_irq(wl->irq, wl); - wl1271_free_hw(wl); + platform_device_del(glue->core); + platform_device_put(glue->core); + kfree(glue); return 0; } @@ -462,7 +410,6 @@ static int __devexit wl1271_remove(struct spi_device *spi) static struct spi_driver wl1271_spi_driver = { .driver = { .name = "wl1271_spi", - .bus = &spi_bus_type, .owner = THIS_MODULE, }, diff --git a/drivers/net/wireless/wl12xx/testmode.c b/drivers/net/wireless/wl12xx/testmode.c index 4ae8effaee22..25093c0cb0ed 100644 --- a/drivers/net/wireless/wl12xx/testmode.c +++ b/drivers/net/wireless/wl12xx/testmode.c @@ -26,8 +26,10 @@ #include <net/genetlink.h> #include "wl12xx.h" +#include "debug.h" #include "acx.h" #include "reg.h" +#include "ps.h" #define WL1271_TM_MAX_DATA_LENGTH 1024 @@ -36,6 +38,7 @@ enum wl1271_tm_commands { WL1271_TM_CMD_TEST, WL1271_TM_CMD_INTERROGATE, WL1271_TM_CMD_CONFIGURE, + WL1271_TM_CMD_NVS_PUSH, /* Not in use. Keep to not break ABI */ WL1271_TM_CMD_SET_PLT_MODE, WL1271_TM_CMD_RECOVER, @@ -87,31 +90,47 @@ static int wl1271_tm_cmd_test(struct wl1271 *wl, struct nlattr *tb[]) return -EMSGSIZE; mutex_lock(&wl->mutex); - ret = wl1271_cmd_test(wl, buf, buf_len, answer); - mutex_unlock(&wl->mutex); + if (wl->state == WL1271_STATE_OFF) { + ret = -EINVAL; + goto out; + } + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + ret = wl1271_cmd_test(wl, buf, buf_len, answer); if (ret < 0) { wl1271_warning("testmode cmd test failed: %d", ret); - return ret; + goto out_sleep; } if (answer) { len = nla_total_size(buf_len); skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, len); - if (!skb) - return -ENOMEM; + if (!skb) { + ret = -ENOMEM; + goto out_sleep; + } NLA_PUT(skb, WL1271_TM_ATTR_DATA, buf_len, buf); ret = cfg80211_testmode_reply(skb); if (ret < 0) - return ret; + goto out_sleep; } - return 0; +out_sleep: + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); + + return ret; nla_put_failure: kfree_skb(skb); - return -EMSGSIZE; + ret = -EMSGSIZE; + goto out_sleep; } static int wl1271_tm_cmd_interrogate(struct wl1271 *wl, struct nlattr *tb[]) @@ -128,33 +147,53 @@ static int wl1271_tm_cmd_interrogate(struct wl1271 *wl, struct nlattr *tb[]) ie_id = nla_get_u8(tb[WL1271_TM_ATTR_IE_ID]); + mutex_lock(&wl->mutex); + + if (wl->state == WL1271_STATE_OFF) { + ret = -EINVAL; + goto out; + } + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) - return -ENOMEM; + if (!cmd) { + ret = -ENOMEM; + goto out_sleep; + } - mutex_lock(&wl->mutex); ret = wl1271_cmd_interrogate(wl, ie_id, cmd, sizeof(*cmd)); - mutex_unlock(&wl->mutex); - if (ret < 0) { wl1271_warning("testmode cmd interrogate failed: %d", ret); - kfree(cmd); - return ret; + goto out_free; } skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, sizeof(*cmd)); if (!skb) { - kfree(cmd); - return -ENOMEM; + ret = -ENOMEM; + goto out_free; } NLA_PUT(skb, WL1271_TM_ATTR_DATA, sizeof(*cmd), cmd); + ret = cfg80211_testmode_reply(skb); + if (ret < 0) + goto out_free; + +out_free: + kfree(cmd); +out_sleep: + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); - return 0; + return ret; nla_put_failure: kfree_skb(skb); - return -EMSGSIZE; + ret = -EMSGSIZE; + goto out_free; } static int wl1271_tm_cmd_configure(struct wl1271 *wl, struct nlattr *tb[]) diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index bad9e29d49b0..4508ccd78328 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -26,22 +26,24 @@ #include <linux/etherdevice.h> #include "wl12xx.h" +#include "debug.h" #include "io.h" #include "reg.h" #include "ps.h" #include "tx.h" #include "event.h" -static int wl1271_set_default_wep_key(struct wl1271 *wl, u8 id) +static int wl1271_set_default_wep_key(struct wl1271 *wl, + struct wl12xx_vif *wlvif, u8 id) { int ret; - bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); + bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); if (is_ap) ret = wl12xx_cmd_set_default_wep_key(wl, id, - wl->ap_bcast_hlid); + wlvif->ap.bcast_hlid); else - ret = wl12xx_cmd_set_default_wep_key(wl, id, wl->sta_hlid); + ret = wl12xx_cmd_set_default_wep_key(wl, id, wlvif->sta.hlid); if (ret < 0) return ret; @@ -76,7 +78,8 @@ static void wl1271_free_tx_id(struct wl1271 *wl, int id) } static int wl1271_tx_update_filters(struct wl1271 *wl, - struct sk_buff *skb) + struct wl12xx_vif *wlvif, + struct sk_buff *skb) { struct ieee80211_hdr *hdr; int ret; @@ -92,15 +95,11 @@ static int wl1271_tx_update_filters(struct wl1271 *wl, if (!ieee80211_is_auth(hdr->frame_control)) return 0; - if (wl->dev_hlid != WL12XX_INVALID_LINK_ID) + if (wlvif->dev_hlid != WL12XX_INVALID_LINK_ID) goto out; wl1271_debug(DEBUG_CMD, "starting device role for roaming"); - ret = wl12xx_cmd_role_start_dev(wl); - if (ret < 0) - goto out; - - ret = wl12xx_roc(wl, wl->dev_role_id); + ret = wl12xx_start_dev(wl, wlvif); if (ret < 0) goto out; out: @@ -123,18 +122,16 @@ static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl, wl1271_acx_set_inconnection_sta(wl, hdr->addr1); } -static void wl1271_tx_regulate_link(struct wl1271 *wl, u8 hlid) +static void wl1271_tx_regulate_link(struct wl1271 *wl, + struct wl12xx_vif *wlvif, + u8 hlid) { bool fw_ps, single_sta; u8 tx_pkts; - /* only regulate station links */ - if (hlid < WL1271_AP_STA_HLID_START) + if (WARN_ON(!test_bit(hlid, wlvif->links_map))) return; - if (WARN_ON(!wl1271_is_active_sta(wl, hlid))) - return; - fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); tx_pkts = wl->links[hlid].allocated_pkts; single_sta = (wl->active_sta_count == 1); @@ -146,7 +143,7 @@ static void wl1271_tx_regulate_link(struct wl1271 *wl, u8 hlid) * case FW-memory congestion is not a problem. */ if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS) - wl1271_ps_link_start(wl, hlid, true); + wl12xx_ps_link_start(wl, wlvif, hlid, true); } bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb) @@ -154,7 +151,8 @@ bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb) return wl->dummy_packet == skb; } -u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct sk_buff *skb) +u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif, + struct sk_buff *skb) { struct ieee80211_tx_info *control = IEEE80211_SKB_CB(skb); @@ -167,49 +165,51 @@ u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct sk_buff *skb) } else { struct ieee80211_hdr *hdr; - if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) + if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) return wl->system_hlid; hdr = (struct ieee80211_hdr *)skb->data; if (ieee80211_is_mgmt(hdr->frame_control)) - return wl->ap_global_hlid; + return wlvif->ap.global_hlid; else - return wl->ap_bcast_hlid; + return wlvif->ap.bcast_hlid; } } -static u8 wl1271_tx_get_hlid(struct wl1271 *wl, struct sk_buff *skb) +u8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif, + struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - if (wl12xx_is_dummy_packet(wl, skb)) + if (!wlvif || wl12xx_is_dummy_packet(wl, skb)) return wl->system_hlid; - if (wl->bss_type == BSS_TYPE_AP_BSS) - return wl12xx_tx_get_hlid_ap(wl, skb); + if (wlvif->bss_type == BSS_TYPE_AP_BSS) + return wl12xx_tx_get_hlid_ap(wl, wlvif, skb); - wl1271_tx_update_filters(wl, skb); + wl1271_tx_update_filters(wl, wlvif, skb); - if ((test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) || - test_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags)) && + if ((test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) || + test_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags)) && !ieee80211_is_auth(hdr->frame_control) && !ieee80211_is_assoc_req(hdr->frame_control)) - return wl->sta_hlid; + return wlvif->sta.hlid; else - return wl->dev_hlid; + return wlvif->dev_hlid; } static unsigned int wl12xx_calc_packet_alignment(struct wl1271 *wl, unsigned int packet_length) { - if (wl->quirks & WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT) - return ALIGN(packet_length, WL12XX_BUS_BLOCK_SIZE); - else + if (wl->quirks & WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT) return ALIGN(packet_length, WL1271_TX_ALIGN_TO); + else + return ALIGN(packet_length, WL12XX_BUS_BLOCK_SIZE); } -static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, - u32 buf_offset, u8 hlid) +static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif, + struct sk_buff *skb, u32 extra, u32 buf_offset, + u8 hlid) { struct wl1271_tx_hw_descr *desc; u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra; @@ -217,6 +217,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, u32 total_blocks; int id, ret = -EBUSY, ac; u32 spare_blocks = wl->tx_spare_blocks; + bool is_dummy = false; if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE) return -EAGAIN; @@ -231,8 +232,10 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, len = wl12xx_calc_packet_alignment(wl, total_len); /* in case of a dummy packet, use default amount of spare mem blocks */ - if (unlikely(wl12xx_is_dummy_packet(wl, skb))) + if (unlikely(wl12xx_is_dummy_packet(wl, skb))) { + is_dummy = true; spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT; + } total_blocks = (len + TX_HW_BLOCK_SIZE - 1) / TX_HW_BLOCK_SIZE + spare_blocks; @@ -257,8 +260,9 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); wl->tx_allocated_pkts[ac]++; - if (wl->bss_type == BSS_TYPE_AP_BSS && - hlid >= WL1271_AP_STA_HLID_START) + if (!is_dummy && wlvif && + wlvif->bss_type == BSS_TYPE_AP_BSS && + test_bit(hlid, wlvif->ap.sta_hlid_map)) wl->links[hlid].allocated_pkts++; ret = 0; @@ -273,15 +277,16 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, return ret; } -static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, - u32 extra, struct ieee80211_tx_info *control, - u8 hlid) +static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif, + struct sk_buff *skb, u32 extra, + struct ieee80211_tx_info *control, u8 hlid) { struct timespec ts; struct wl1271_tx_hw_descr *desc; int aligned_len, ac, rate_idx; s64 hosttime; - u16 tx_attr; + u16 tx_attr = 0; + bool is_dummy; desc = (struct wl1271_tx_hw_descr *) skb->data; @@ -298,7 +303,8 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, hosttime = (timespec_to_ns(&ts) >> 10); desc->start_time = cpu_to_le32(hosttime - wl->time_offset); - if (wl->bss_type != BSS_TYPE_AP_BSS) + is_dummy = wl12xx_is_dummy_packet(wl, skb); + if (is_dummy || !wlvif || wlvif->bss_type != BSS_TYPE_AP_BSS) desc->life_time = cpu_to_le16(TX_HW_MGMT_PKT_LIFETIME_TU); else desc->life_time = cpu_to_le16(TX_HW_AP_MODE_PKT_LIFETIME_TU); @@ -307,39 +313,42 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); desc->tid = skb->priority; - if (wl12xx_is_dummy_packet(wl, skb)) { + if (is_dummy) { /* * FW expects the dummy packet to have an invalid session id - * any session id that is different than the one set in the join */ - tx_attr = ((~wl->session_counter) << + tx_attr = (SESSION_COUNTER_INVALID << TX_HW_ATTR_OFST_SESSION_COUNTER) & TX_HW_ATTR_SESSION_COUNTER; tx_attr |= TX_HW_ATTR_TX_DUMMY_REQ; - } else { + } else if (wlvif) { /* configure the tx attributes */ - tx_attr = - wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER; + tx_attr = wlvif->session_counter << + TX_HW_ATTR_OFST_SESSION_COUNTER; } desc->hlid = hlid; - - if (wl->bss_type != BSS_TYPE_AP_BSS) { + if (is_dummy || !wlvif) + rate_idx = 0; + else if (wlvif->bss_type != BSS_TYPE_AP_BSS) { /* if the packets are destined for AP (have a STA entry) send them with AP rate policies, otherwise use default basic rates */ - if (control->control.sta) - rate_idx = ACX_TX_AP_FULL_RATE; + if (control->flags & IEEE80211_TX_CTL_NO_CCK_RATE) + rate_idx = wlvif->sta.p2p_rate_idx; + else if (control->control.sta) + rate_idx = wlvif->sta.ap_rate_idx; else - rate_idx = ACX_TX_BASIC_RATE; + rate_idx = wlvif->sta.basic_rate_idx; } else { - if (hlid == wl->ap_global_hlid) - rate_idx = ACX_TX_AP_MODE_MGMT_RATE; - else if (hlid == wl->ap_bcast_hlid) - rate_idx = ACX_TX_AP_MODE_BCST_RATE; + if (hlid == wlvif->ap.global_hlid) + rate_idx = wlvif->ap.mgmt_rate_idx; + else if (hlid == wlvif->ap.bcast_hlid) + rate_idx = wlvif->ap.bcast_rate_idx; else - rate_idx = ac; + rate_idx = wlvif->ap.ucast_rate_idx[ac]; } tx_attr |= rate_idx << TX_HW_ATTR_OFST_RATE_POLICY; @@ -379,20 +388,24 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, } /* caller must hold wl->mutex */ -static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, - u32 buf_offset) +static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif, + struct sk_buff *skb, u32 buf_offset) { struct ieee80211_tx_info *info; u32 extra = 0; int ret = 0; u32 total_len; u8 hlid; + bool is_dummy; if (!skb) return -EINVAL; info = IEEE80211_SKB_CB(skb); + /* TODO: handle dummy packets on multi-vifs */ + is_dummy = wl12xx_is_dummy_packet(wl, skb); + if (info->control.hw_key && info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) extra = WL1271_TKIP_IV_SPACE; @@ -405,29 +418,28 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, is_wep = (cipher == WLAN_CIPHER_SUITE_WEP40) || (cipher == WLAN_CIPHER_SUITE_WEP104); - if (unlikely(is_wep && wl->default_key != idx)) { - ret = wl1271_set_default_wep_key(wl, idx); + if (unlikely(is_wep && wlvif->default_key != idx)) { + ret = wl1271_set_default_wep_key(wl, wlvif, idx); if (ret < 0) return ret; - wl->default_key = idx; + wlvif->default_key = idx; } } - - hlid = wl1271_tx_get_hlid(wl, skb); + hlid = wl12xx_tx_get_hlid(wl, wlvif, skb); if (hlid == WL12XX_INVALID_LINK_ID) { wl1271_error("invalid hlid. dropping skb 0x%p", skb); return -EINVAL; } - ret = wl1271_tx_allocate(wl, skb, extra, buf_offset, hlid); + ret = wl1271_tx_allocate(wl, wlvif, skb, extra, buf_offset, hlid); if (ret < 0) return ret; - wl1271_tx_fill_hdr(wl, skb, extra, info, hlid); + wl1271_tx_fill_hdr(wl, wlvif, skb, extra, info, hlid); - if (wl->bss_type == BSS_TYPE_AP_BSS) { + if (!is_dummy && wlvif && wlvif->bss_type == BSS_TYPE_AP_BSS) { wl1271_tx_ap_update_inconnection_sta(wl, skb); - wl1271_tx_regulate_link(wl, hlid); + wl1271_tx_regulate_link(wl, wlvif, hlid); } /* @@ -444,7 +456,7 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len); /* Revert side effects in the dummy packet skb, so it can be reused */ - if (wl12xx_is_dummy_packet(wl, skb)) + if (is_dummy) skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); return total_len; @@ -522,19 +534,18 @@ static struct sk_buff_head *wl1271_select_queue(struct wl1271 *wl, return &queues[q]; } -static struct sk_buff *wl1271_sta_skb_dequeue(struct wl1271 *wl) +static struct sk_buff *wl12xx_lnk_skb_dequeue(struct wl1271 *wl, + struct wl1271_link *lnk) { - struct sk_buff *skb = NULL; + struct sk_buff *skb; unsigned long flags; struct sk_buff_head *queue; - queue = wl1271_select_queue(wl, wl->tx_queue); + queue = wl1271_select_queue(wl, lnk->tx_queue); if (!queue) - goto out; + return NULL; skb = skb_dequeue(queue); - -out: if (skb) { int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); spin_lock_irqsave(&wl->wl_lock, flags); @@ -545,43 +556,33 @@ out: return skb; } -static struct sk_buff *wl1271_ap_skb_dequeue(struct wl1271 *wl) +static struct sk_buff *wl12xx_vif_skb_dequeue(struct wl1271 *wl, + struct wl12xx_vif *wlvif) { struct sk_buff *skb = NULL; - unsigned long flags; int i, h, start_hlid; - struct sk_buff_head *queue; /* start from the link after the last one */ - start_hlid = (wl->last_tx_hlid + 1) % AP_MAX_LINKS; + start_hlid = (wlvif->last_tx_hlid + 1) % WL12XX_MAX_LINKS; /* dequeue according to AC, round robin on each link */ - for (i = 0; i < AP_MAX_LINKS; i++) { - h = (start_hlid + i) % AP_MAX_LINKS; + for (i = 0; i < WL12XX_MAX_LINKS; i++) { + h = (start_hlid + i) % WL12XX_MAX_LINKS; /* only consider connected stations */ - if (h >= WL1271_AP_STA_HLID_START && - !test_bit(h - WL1271_AP_STA_HLID_START, wl->ap_hlid_map)) + if (!test_bit(h, wlvif->links_map)) continue; - queue = wl1271_select_queue(wl, wl->links[h].tx_queue); - if (!queue) + skb = wl12xx_lnk_skb_dequeue(wl, &wl->links[h]); + if (!skb) continue; - skb = skb_dequeue(queue); - if (skb) - break; + wlvif->last_tx_hlid = h; + break; } - if (skb) { - int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); - wl->last_tx_hlid = h; - spin_lock_irqsave(&wl->wl_lock, flags); - wl->tx_queue_count[q]--; - spin_unlock_irqrestore(&wl->wl_lock, flags); - } else { - wl->last_tx_hlid = 0; - } + if (!skb) + wlvif->last_tx_hlid = 0; return skb; } @@ -589,12 +590,32 @@ static struct sk_buff *wl1271_ap_skb_dequeue(struct wl1271 *wl) static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl) { unsigned long flags; + struct wl12xx_vif *wlvif = wl->last_wlvif; struct sk_buff *skb = NULL; - if (wl->bss_type == BSS_TYPE_AP_BSS) - skb = wl1271_ap_skb_dequeue(wl); - else - skb = wl1271_sta_skb_dequeue(wl); + if (wlvif) { + wl12xx_for_each_wlvif_continue(wl, wlvif) { + skb = wl12xx_vif_skb_dequeue(wl, wlvif); + if (skb) { + wl->last_wlvif = wlvif; + break; + } + } + } + + /* do another pass */ + if (!skb) { + wl12xx_for_each_wlvif(wl, wlvif) { + skb = wl12xx_vif_skb_dequeue(wl, wlvif); + if (skb) { + wl->last_wlvif = wlvif; + break; + } + } + } + + if (!skb) + skb = wl12xx_lnk_skb_dequeue(wl, &wl->links[wl->system_hlid]); if (!skb && test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) { @@ -610,21 +631,21 @@ static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl) return skb; } -static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb) +static void wl1271_skb_queue_head(struct wl1271 *wl, struct wl12xx_vif *wlvif, + struct sk_buff *skb) { unsigned long flags; int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); if (wl12xx_is_dummy_packet(wl, skb)) { set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags); - } else if (wl->bss_type == BSS_TYPE_AP_BSS) { - u8 hlid = wl1271_tx_get_hlid(wl, skb); + } else { + u8 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb); skb_queue_head(&wl->links[hlid].tx_queue[q], skb); /* make sure we dequeue the same packet next time */ - wl->last_tx_hlid = (hlid + AP_MAX_LINKS - 1) % AP_MAX_LINKS; - } else { - skb_queue_head(&wl->tx_queue[q], skb); + wlvif->last_tx_hlid = (hlid + WL12XX_MAX_LINKS - 1) % + WL12XX_MAX_LINKS; } spin_lock_irqsave(&wl->wl_lock, flags); @@ -639,29 +660,71 @@ static bool wl1271_tx_is_data_present(struct sk_buff *skb) return ieee80211_is_data_present(hdr->frame_control); } +void wl12xx_rearm_rx_streaming(struct wl1271 *wl, unsigned long *active_hlids) +{ + struct wl12xx_vif *wlvif; + u32 timeout; + u8 hlid; + + if (!wl->conf.rx_streaming.interval) + return; + + if (!wl->conf.rx_streaming.always && + !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)) + return; + + timeout = wl->conf.rx_streaming.duration; + wl12xx_for_each_wlvif_sta(wl, wlvif) { + bool found = false; + for_each_set_bit(hlid, active_hlids, WL12XX_MAX_LINKS) { + if (test_bit(hlid, wlvif->links_map)) { + found = true; + break; + } + } + + if (!found) + continue; + + /* enable rx streaming */ + if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags)) + ieee80211_queue_work(wl->hw, + &wlvif->rx_streaming_enable_work); + + mod_timer(&wlvif->rx_streaming_timer, + jiffies + msecs_to_jiffies(timeout)); + } +} + void wl1271_tx_work_locked(struct wl1271 *wl) { + struct wl12xx_vif *wlvif; struct sk_buff *skb; + struct wl1271_tx_hw_descr *desc; u32 buf_offset = 0; bool sent_packets = false; - bool had_data = false; - bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); + unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0}; int ret; if (unlikely(wl->state == WL1271_STATE_OFF)) return; while ((skb = wl1271_skb_dequeue(wl))) { - if (wl1271_tx_is_data_present(skb)) - had_data = true; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + bool has_data = false; - ret = wl1271_prepare_tx_frame(wl, skb, buf_offset); + wlvif = NULL; + if (!wl12xx_is_dummy_packet(wl, skb) && info->control.vif) + wlvif = wl12xx_vif_to_data(info->control.vif); + + has_data = wlvif && wl1271_tx_is_data_present(skb); + ret = wl1271_prepare_tx_frame(wl, wlvif, skb, buf_offset); if (ret == -EAGAIN) { /* * Aggregation buffer is full. * Flush buffer and try again. */ - wl1271_skb_queue_head(wl, skb); + wl1271_skb_queue_head(wl, wlvif, skb); wl1271_write(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, buf_offset, true); sent_packets = true; @@ -672,16 +735,27 @@ void wl1271_tx_work_locked(struct wl1271 *wl) * Firmware buffer is full. * Queue back last skb, and stop aggregating. */ - wl1271_skb_queue_head(wl, skb); + wl1271_skb_queue_head(wl, wlvif, skb); /* No work left, avoid scheduling redundant tx work */ set_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); goto out_ack; } else if (ret < 0) { - dev_kfree_skb(skb); + if (wl12xx_is_dummy_packet(wl, skb)) + /* + * fw still expects dummy packet, + * so re-enqueue it + */ + wl1271_skb_queue_head(wl, wlvif, skb); + else + ieee80211_free_txskb(wl->hw, skb); goto out_ack; } buf_offset += ret; wl->tx_packets_count++; + if (has_data) { + desc = (struct wl1271_tx_hw_descr *) skb->data; + __set_bit(desc->hlid, active_hlids); + } } out_ack: @@ -701,19 +775,7 @@ out_ack: wl1271_handle_tx_low_watermark(wl); } - if (!is_ap && wl->conf.rx_streaming.interval && had_data && - (wl->conf.rx_streaming.always || - test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags))) { - u32 timeout = wl->conf.rx_streaming.duration; - - /* enable rx streaming */ - if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags)) - ieee80211_queue_work(wl->hw, - &wl->rx_streaming_enable_work); - - mod_timer(&wl->rx_streaming_timer, - jiffies + msecs_to_jiffies(timeout)); - } + wl12xx_rearm_rx_streaming(wl, active_hlids); } void wl1271_tx_work(struct work_struct *work) @@ -737,6 +799,8 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl, struct wl1271_tx_hw_res_descr *result) { struct ieee80211_tx_info *info; + struct ieee80211_vif *vif; + struct wl12xx_vif *wlvif; struct sk_buff *skb; int id = result->id; int rate = -1; @@ -756,11 +820,16 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl, return; } + /* info->control is valid as long as we don't update info->status */ + vif = info->control.vif; + wlvif = wl12xx_vif_to_data(vif); + /* update the TX status info */ if (result->status == TX_SUCCESS) { if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) info->flags |= IEEE80211_TX_STAT_ACK; - rate = wl1271_rate_to_idx(result->rate_class_index, wl->band); + rate = wl1271_rate_to_idx(result->rate_class_index, + wlvif->band); retries = result->ack_failures; } else if (result->status == TX_RETRY_EXCEEDED) { wl->stats.excessive_retries++; @@ -783,14 +852,14 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl, info->control.hw_key->cipher == WLAN_CIPHER_SUITE_CCMP || info->control.hw_key->cipher == WL1271_CIPHER_SUITE_GEM)) { u8 fw_lsb = result->tx_security_sequence_number_lsb; - u8 cur_lsb = wl->tx_security_last_seq_lsb; + u8 cur_lsb = wlvif->tx_security_last_seq_lsb; /* * update security sequence number, taking care of potential * wrap-around */ - wl->tx_security_seq += (fw_lsb - cur_lsb + 256) % 256; - wl->tx_security_last_seq_lsb = fw_lsb; + wlvif->tx_security_seq += (fw_lsb - cur_lsb) & 0xff; + wlvif->tx_security_last_seq_lsb = fw_lsb; } /* remove private header from packet */ @@ -886,39 +955,30 @@ void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid) } /* caller must hold wl->mutex and TX must be stopped */ -void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues) +void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif) { int i; - struct sk_buff *skb; - struct ieee80211_tx_info *info; /* TX failure */ - if (wl->bss_type == BSS_TYPE_AP_BSS) { - for (i = 0; i < AP_MAX_LINKS; i++) { - wl1271_free_sta(wl, i); - wl1271_tx_reset_link_queues(wl, i); - wl->links[i].allocated_pkts = 0; - wl->links[i].prev_freed_pkts = 0; - } - - wl->last_tx_hlid = 0; - } else { - for (i = 0; i < NUM_TX_QUEUES; i++) { - while ((skb = skb_dequeue(&wl->tx_queue[i]))) { - wl1271_debug(DEBUG_TX, "freeing skb 0x%p", - skb); - - if (!wl12xx_is_dummy_packet(wl, skb)) { - info = IEEE80211_SKB_CB(skb); - info->status.rates[0].idx = -1; - info->status.rates[0].count = 0; - ieee80211_tx_status_ni(wl->hw, skb); - } - } - } + for_each_set_bit(i, wlvif->links_map, WL12XX_MAX_LINKS) { + if (wlvif->bss_type == BSS_TYPE_AP_BSS) + wl1271_free_sta(wl, wlvif, i); + else + wlvif->sta.ba_rx_bitmap = 0; - wl->ba_rx_bitmap = 0; + wl1271_tx_reset_link_queues(wl, i); + wl->links[i].allocated_pkts = 0; + wl->links[i].prev_freed_pkts = 0; } + wlvif->last_tx_hlid = 0; + +} +/* caller must hold wl->mutex and TX must be stopped */ +void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues) +{ + int i; + struct sk_buff *skb; + struct ieee80211_tx_info *info; for (i = 0; i < NUM_TX_QUEUES; i++) wl->tx_queue_count[i] = 0; diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h index dc4f09adf088..2dbb24e6d541 100644 --- a/drivers/net/wireless/wl12xx/tx.h +++ b/drivers/net/wireless/wl12xx/tx.h @@ -206,18 +206,23 @@ static inline int wl1271_tx_total_queue_count(struct wl1271 *wl) void wl1271_tx_work(struct work_struct *work); void wl1271_tx_work_locked(struct wl1271 *wl); void wl1271_tx_complete(struct wl1271 *wl); -void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues); +void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif); +void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues); void wl1271_tx_flush(struct wl1271 *wl); u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band); u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set, enum ieee80211_band rate_band); u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set); -u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct sk_buff *skb); +u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif, + struct sk_buff *skb); +u8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif, + struct sk_buff *skb); void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid); void wl1271_handle_tx_low_watermark(struct wl1271 *wl); bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb); +void wl12xx_rearm_rx_streaming(struct wl1271 *wl, unsigned long *active_hlids); /* from main.c */ -void wl1271_free_sta(struct wl1271 *wl, u8 hlid); +void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid); #endif diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 1ec90fc7505e..d21f71ff6f64 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -35,83 +35,6 @@ #include "conf.h" #include "ini.h" -#define DRIVER_NAME "wl1271" -#define DRIVER_PREFIX DRIVER_NAME ": " - -/* - * FW versions support BA 11n - * versions marks x.x.x.50-60.x - */ -#define WL12XX_BA_SUPPORT_FW_COST_VER2_START 50 -#define WL12XX_BA_SUPPORT_FW_COST_VER2_END 60 - -enum { - DEBUG_NONE = 0, - DEBUG_IRQ = BIT(0), - DEBUG_SPI = BIT(1), - DEBUG_BOOT = BIT(2), - DEBUG_MAILBOX = BIT(3), - DEBUG_TESTMODE = BIT(4), - DEBUG_EVENT = BIT(5), - DEBUG_TX = BIT(6), - DEBUG_RX = BIT(7), - DEBUG_SCAN = BIT(8), - DEBUG_CRYPT = BIT(9), - DEBUG_PSM = BIT(10), - DEBUG_MAC80211 = BIT(11), - DEBUG_CMD = BIT(12), - DEBUG_ACX = BIT(13), - DEBUG_SDIO = BIT(14), - DEBUG_FILTERS = BIT(15), - DEBUG_ADHOC = BIT(16), - DEBUG_AP = BIT(17), - DEBUG_MASTER = (DEBUG_ADHOC | DEBUG_AP), - DEBUG_ALL = ~0, -}; - -extern u32 wl12xx_debug_level; - -#define DEBUG_DUMP_LIMIT 1024 - -#define wl1271_error(fmt, arg...) \ - pr_err(DRIVER_PREFIX "ERROR " fmt "\n", ##arg) - -#define wl1271_warning(fmt, arg...) \ - pr_warning(DRIVER_PREFIX "WARNING " fmt "\n", ##arg) - -#define wl1271_notice(fmt, arg...) \ - pr_info(DRIVER_PREFIX fmt "\n", ##arg) - -#define wl1271_info(fmt, arg...) \ - pr_info(DRIVER_PREFIX fmt "\n", ##arg) - -#define wl1271_debug(level, fmt, arg...) \ - do { \ - if (level & wl12xx_debug_level) \ - pr_debug(DRIVER_PREFIX fmt "\n", ##arg); \ - } while (0) - -/* TODO: use pr_debug_hex_dump when it will be available */ -#define wl1271_dump(level, prefix, buf, len) \ - do { \ - if (level & wl12xx_debug_level) \ - print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ - DUMP_PREFIX_OFFSET, 16, 1, \ - buf, \ - min_t(size_t, len, DEBUG_DUMP_LIMIT), \ - 0); \ - } while (0) - -#define wl1271_dump_ascii(level, prefix, buf, len) \ - do { \ - if (level & wl12xx_debug_level) \ - print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ - DUMP_PREFIX_OFFSET, 16, 1, \ - buf, \ - min_t(size_t, len, DEBUG_DUMP_LIMIT), \ - true); \ - } while (0) - #define WL127X_FW_NAME "ti-connectivity/wl127x-fw-3.bin" #define WL128X_FW_NAME "ti-connectivity/wl128x-fw-3.bin" @@ -142,16 +65,12 @@ extern u32 wl12xx_debug_level; #define WL12XX_INVALID_ROLE_ID 0xff #define WL12XX_INVALID_LINK_ID 0xff +#define WL12XX_MAX_RATE_POLICIES 16 + /* Defined by FW as 0. Will not be freed or allocated. */ #define WL12XX_SYSTEM_HLID 0 /* - * TODO: we currently don't support multirole. remove - * this constant from the code when we do. - */ -#define WL1271_AP_STA_HLID_START 3 - -/* * When in AP-mode, we allow (at least) this number of packets * to be transmitted to FW for a STA in PS-mode. Only when packets are * present in the FW buffers it will wake the sleeping STA. We want to put @@ -236,13 +155,6 @@ struct wl1271_stats { #define AP_MAX_STATIONS 8 -/* Broadcast and Global links + system link + links to stations */ -/* - * TODO: when WL1271_AP_STA_HLID_START is no longer constant, change all - * the places that use this. - */ -#define AP_MAX_LINKS (AP_MAX_STATIONS + WL1271_AP_STA_HLID_START) - /* FW status registers */ struct wl12xx_fw_status { __le32 intr; @@ -299,17 +211,14 @@ struct wl1271_scan { }; struct wl1271_if_operations { - void (*read)(struct wl1271 *wl, int addr, void *buf, size_t len, + void (*read)(struct device *child, int addr, void *buf, size_t len, bool fixed); - void (*write)(struct wl1271 *wl, int addr, void *buf, size_t len, + void (*write)(struct device *child, int addr, void *buf, size_t len, bool fixed); - void (*reset)(struct wl1271 *wl); - void (*init)(struct wl1271 *wl); - int (*power)(struct wl1271 *wl, bool enable); - struct device* (*dev)(struct wl1271 *wl); - void (*enable_irq)(struct wl1271 *wl); - void (*disable_irq)(struct wl1271 *wl); - void (*set_block_size) (struct wl1271 *wl, unsigned int blksz); + void (*reset)(struct device *child); + void (*init)(struct device *child); + int (*power)(struct device *child, bool enable); + void (*set_block_size) (struct device *child, unsigned int blksz); }; #define MAX_NUM_KEYS 14 @@ -326,29 +235,33 @@ struct wl1271_ap_key { }; enum wl12xx_flags { - WL1271_FLAG_STA_ASSOCIATED, - WL1271_FLAG_IBSS_JOINED, WL1271_FLAG_GPIO_POWER, WL1271_FLAG_TX_QUEUE_STOPPED, WL1271_FLAG_TX_PENDING, WL1271_FLAG_IN_ELP, WL1271_FLAG_ELP_REQUESTED, - WL1271_FLAG_PSM, - WL1271_FLAG_PSM_REQUESTED, WL1271_FLAG_IRQ_RUNNING, WL1271_FLAG_IDLE, - WL1271_FLAG_PSPOLL_FAILURE, - WL1271_FLAG_STA_STATE_SENT, WL1271_FLAG_FW_TX_BUSY, - WL1271_FLAG_AP_STARTED, - WL1271_FLAG_IF_INITIALIZED, WL1271_FLAG_DUMMY_PACKET_PENDING, WL1271_FLAG_SUSPENDED, WL1271_FLAG_PENDING_WORK, WL1271_FLAG_SOFT_GEMINI, - WL1271_FLAG_RX_STREAMING_STARTED, WL1271_FLAG_RECOVERY_IN_PROGRESS, - WL1271_FLAG_CS_PROGRESS, +}; + +enum wl12xx_vif_flags { + WLVIF_FLAG_INITIALIZED, + WLVIF_FLAG_STA_ASSOCIATED, + WLVIF_FLAG_IBSS_JOINED, + WLVIF_FLAG_AP_STARTED, + WLVIF_FLAG_PSM, + WLVIF_FLAG_PSM_REQUESTED, + WLVIF_FLAG_STA_STATE_SENT, + WLVIF_FLAG_RX_STREAMING_STARTED, + WLVIF_FLAG_PSPOLL_FAILURE, + WLVIF_FLAG_CS_PROGRESS, + WLVIF_FLAG_AP_PROBE_RESP_SET, }; struct wl1271_link { @@ -366,10 +279,11 @@ struct wl1271_link { }; struct wl1271 { - struct platform_device *plat_dev; struct ieee80211_hw *hw; bool mac80211_registered; + struct device *dev; + void *if_priv; struct wl1271_if_operations *if_ops; @@ -399,25 +313,20 @@ struct wl1271 { s8 hw_pg_ver; - u8 bssid[ETH_ALEN]; u8 mac_addr[ETH_ALEN]; - u8 bss_type; - u8 set_bss_type; - u8 p2p; /* we are using p2p role */ - u8 ssid[IEEE80211_MAX_SSID_LEN + 1]; - u8 ssid_len; int channel; - u8 role_id; - u8 dev_role_id; u8 system_hlid; - u8 sta_hlid; - u8 dev_hlid; - u8 ap_global_hlid; - u8 ap_bcast_hlid; unsigned long links_map[BITS_TO_LONGS(WL12XX_MAX_LINKS)]; unsigned long roles_map[BITS_TO_LONGS(WL12XX_MAX_ROLES)]; unsigned long roc_map[BITS_TO_LONGS(WL12XX_MAX_ROLES)]; + unsigned long rate_policies_map[ + BITS_TO_LONGS(WL12XX_MAX_RATE_POLICIES)]; + + struct list_head wlvif_list; + + u8 sta_count; + u8 ap_count; struct wl1271_acx_mem_map *target_mem_map; @@ -440,11 +349,7 @@ struct wl1271 { /* Time-offset between host and chipset clocks */ s64 time_offset; - /* Session counter for the chipset */ - int session_counter; - /* Frames scheduled for transmission, not handled yet */ - struct sk_buff_head tx_queue[NUM_TX_QUEUES]; int tx_queue_count[NUM_TX_QUEUES]; long stopped_queues_map; @@ -462,17 +367,6 @@ struct wl1271 { struct sk_buff *tx_frames[ACX_TX_DESCRIPTORS]; int tx_frames_cnt; - /* - * Security sequence number - * bits 0-15: lower 16 bits part of sequence number - * bits 16-47: higher 32 bits part of sequence number - * bits 48-63: not in use - */ - u64 tx_security_seq; - - /* 8 bits of the last sequence number in use */ - u8 tx_security_last_seq_lsb; - /* FW Rx counter */ u32 rx_counter; @@ -507,59 +401,21 @@ struct wl1271 { u32 mbox_ptr[2]; /* Are we currently scanning */ + struct ieee80211_vif *scan_vif; struct wl1271_scan scan; struct delayed_work scan_complete_work; bool sched_scanning; - /* probe-req template for the current AP */ - struct sk_buff *probereq; - - /* Our association ID */ - u16 aid; - - /* - * currently configured rate set: - * bits 0-15 - 802.11abg rates - * bits 16-23 - 802.11n MCS index mask - * support only 1 stream, thus only 8 bits for the MCS rates (0-7). - */ - u32 basic_rate_set; - u32 basic_rate; - u32 rate_set; - u32 bitrate_masks[IEEE80211_NUM_BANDS]; - /* The current band */ enum ieee80211_band band; - /* Beaconing interval (needed for ad-hoc) */ - u32 beacon_int; - - /* Default key (for WEP) */ - u32 default_key; - - /* Rx Streaming */ - struct work_struct rx_streaming_enable_work; - struct work_struct rx_streaming_disable_work; - struct timer_list rx_streaming_timer; - struct completion *elp_compl; - struct completion *ps_compl; struct delayed_work elp_work; - struct delayed_work pspoll_work; - - /* counter for ps-poll delivery failures */ - int ps_poll_failures; - - /* retry counter for PSM entries */ - u8 psm_entry_retry; /* in dBm */ int power_level; - int rssi_thold; - int last_rssi_event; - struct wl1271_stats stats; __le32 buffer_32; @@ -583,20 +439,9 @@ struct wl1271 { /* Most recently reported noise in dBm */ s8 noise; - /* map for HLIDs of associated stations - when operating in AP mode */ - unsigned long ap_hlid_map[BITS_TO_LONGS(AP_MAX_STATIONS)]; - - /* recoreded keys for AP-mode - set here before AP startup */ - struct wl1271_ap_key *recorded_ap_keys[MAX_NUM_KEYS]; - /* bands supported by this instance of wl12xx */ struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS]; - /* RX BA constraint value */ - bool ba_support; - u8 ba_rx_bitmap; - bool ba_allowed; - int tcxo_clock; /* @@ -610,10 +455,7 @@ struct wl1271 { * AP-mode - links indexed by HLID. The global and broadcast links * are always active. */ - struct wl1271_link links[AP_MAX_LINKS]; - - /* the hlid of the link where the last transmitted skb came from */ - int last_tx_hlid; + struct wl1271_link links[WL12XX_MAX_LINKS]; /* AP-mode - a bitmap of links currently in PS mode according to FW */ u32 ap_fw_ps_map; @@ -632,21 +474,173 @@ struct wl1271 { /* AP-mode - number of currently connected stations */ int active_sta_count; + + /* last wlvif we transmitted from */ + struct wl12xx_vif *last_wlvif; }; struct wl1271_station { u8 hlid; }; +struct wl12xx_vif { + struct wl1271 *wl; + struct list_head list; + unsigned long flags; + u8 bss_type; + u8 p2p; /* we are using p2p role */ + u8 role_id; + + /* sta/ibss specific */ + u8 dev_role_id; + u8 dev_hlid; + + union { + struct { + u8 hlid; + u8 ba_rx_bitmap; + + u8 basic_rate_idx; + u8 ap_rate_idx; + u8 p2p_rate_idx; + } sta; + struct { + u8 global_hlid; + u8 bcast_hlid; + + /* HLIDs bitmap of associated stations */ + unsigned long sta_hlid_map[BITS_TO_LONGS( + WL12XX_MAX_LINKS)]; + + /* recoreded keys - set here before AP startup */ + struct wl1271_ap_key *recorded_keys[MAX_NUM_KEYS]; + + u8 mgmt_rate_idx; + u8 bcast_rate_idx; + u8 ucast_rate_idx[CONF_TX_MAX_AC_COUNT]; + } ap; + }; + + /* the hlid of the last transmitted skb */ + int last_tx_hlid; + + unsigned long links_map[BITS_TO_LONGS(WL12XX_MAX_LINKS)]; + + u8 ssid[IEEE80211_MAX_SSID_LEN + 1]; + u8 ssid_len; + + /* The current band */ + enum ieee80211_band band; + int channel; + + u32 bitrate_masks[IEEE80211_NUM_BANDS]; + u32 basic_rate_set; + + /* + * currently configured rate set: + * bits 0-15 - 802.11abg rates + * bits 16-23 - 802.11n MCS index mask + * support only 1 stream, thus only 8 bits for the MCS rates (0-7). + */ + u32 basic_rate; + u32 rate_set; + + /* probe-req template for the current AP */ + struct sk_buff *probereq; + + /* Beaconing interval (needed for ad-hoc) */ + u32 beacon_int; + + /* Default key (for WEP) */ + u32 default_key; + + /* Our association ID */ + u16 aid; + + /* Session counter for the chipset */ + int session_counter; + + struct completion *ps_compl; + struct delayed_work pspoll_work; + + /* counter for ps-poll delivery failures */ + int ps_poll_failures; + + /* retry counter for PSM entries */ + u8 psm_entry_retry; + + /* in dBm */ + int power_level; + + int rssi_thold; + int last_rssi_event; + + /* RX BA constraint value */ + bool ba_support; + bool ba_allowed; + + /* Rx Streaming */ + struct work_struct rx_streaming_enable_work; + struct work_struct rx_streaming_disable_work; + struct timer_list rx_streaming_timer; + + /* + * This struct must be last! + * data that has to be saved acrossed reconfigs (e.g. recovery) + * should be declared in this struct. + */ + struct { + u8 persistent[0]; + /* + * Security sequence number + * bits 0-15: lower 16 bits part of sequence number + * bits 16-47: higher 32 bits part of sequence number + * bits 48-63: not in use + */ + u64 tx_security_seq; + + /* 8 bits of the last sequence number in use */ + u8 tx_security_last_seq_lsb; + }; +}; + +static inline struct wl12xx_vif *wl12xx_vif_to_data(struct ieee80211_vif *vif) +{ + return (struct wl12xx_vif *)vif->drv_priv; +} + +static inline +struct ieee80211_vif *wl12xx_wlvif_to_vif(struct wl12xx_vif *wlvif) +{ + return container_of((void *)wlvif, struct ieee80211_vif, drv_priv); +} + +#define wl12xx_for_each_wlvif(wl, wlvif) \ + list_for_each_entry(wlvif, &wl->wlvif_list, list) + +#define wl12xx_for_each_wlvif_continue(wl, wlvif) \ + list_for_each_entry_continue(wlvif, &wl->wlvif_list, list) + +#define wl12xx_for_each_wlvif_bss_type(wl, wlvif, _bss_type) \ + wl12xx_for_each_wlvif(wl, wlvif) \ + if (wlvif->bss_type == _bss_type) + +#define wl12xx_for_each_wlvif_sta(wl, wlvif) \ + wl12xx_for_each_wlvif_bss_type(wl, wlvif, BSS_TYPE_STA_BSS) + +#define wl12xx_for_each_wlvif_ap(wl, wlvif) \ + wl12xx_for_each_wlvif_bss_type(wl, wlvif, BSS_TYPE_AP_BSS) + int wl1271_plt_start(struct wl1271 *wl); int wl1271_plt_stop(struct wl1271 *wl); -int wl1271_recalc_rx_streaming(struct wl1271 *wl); +int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif); void wl12xx_queue_recovery_work(struct wl1271 *wl); size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen); #define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */ -#define SESSION_COUNTER_MAX 7 /* maximum value for the session counter */ +#define SESSION_COUNTER_MAX 6 /* maximum value for the session counter */ +#define SESSION_COUNTER_INVALID 7 /* used with dummy_packet */ #define WL1271_DEFAULT_POWER_LEVEL 0 @@ -669,8 +663,8 @@ size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen); /* Each RX/TX transaction requires an end-of-transaction transfer */ #define WL12XX_QUIRK_END_OF_TRANSACTION BIT(0) -/* WL128X requires aggregated packets to be aligned to the SDIO block size */ -#define WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT BIT(2) +/* wl127x and SPI don't support SDIO block size alignment */ +#define WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT BIT(2) /* Older firmwares did not implement the FW logger over bus feature */ #define WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED BIT(4) diff --git a/drivers/net/wireless/wl12xx/wl12xx_80211.h b/drivers/net/wireless/wl12xx/wl12xx_80211.h index f7971d3b0898..8f0ffaf62309 100644 --- a/drivers/net/wireless/wl12xx/wl12xx_80211.h +++ b/drivers/net/wireless/wl12xx/wl12xx_80211.h @@ -116,11 +116,6 @@ struct wl12xx_ps_poll_template { u8 ta[ETH_ALEN]; } __packed; -struct wl12xx_qos_null_data_template { - struct ieee80211_header header; - __le16 qos_ctl; -} __packed; - struct wl12xx_arp_rsp_template { struct ieee80211_hdr_3addr hdr; diff --git a/drivers/net/wireless/wl12xx/wl12xx_platform_data.c b/drivers/net/wireless/wl12xx/wl12xx_platform_data.c index 973b11060a8f..3c96b332184e 100644 --- a/drivers/net/wireless/wl12xx/wl12xx_platform_data.c +++ b/drivers/net/wireless/wl12xx/wl12xx_platform_data.c @@ -2,7 +2,7 @@ #include <linux/err.h> #include <linux/wl12xx.h> -static const struct wl12xx_platform_data *platform_data; +static struct wl12xx_platform_data *platform_data; int __init wl12xx_set_platform_data(const struct wl12xx_platform_data *data) { @@ -18,7 +18,7 @@ int __init wl12xx_set_platform_data(const struct wl12xx_platform_data *data) return 0; } -const struct wl12xx_platform_data *wl12xx_get_platform_data(void) +struct wl12xx_platform_data *wl12xx_get_platform_data(void) { if (!platform_data) return ERR_PTR(-ENODEV); |