From f0832f137c21d130998a0f97f97ac01a2d97210b Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 16 Apr 2008 16:34:47 -0700 Subject: iwlwifi: HW dependent run time calibration This patch does several things: 1) rename CONFIG_IWL4965_SENSITIVITY to IWL4965_RUN_TIME_CALIB which is better semantic 2) move all the run time calibration to a new file: iwl-calib.c 3) simplify the sensitivity calibration flow and make it HW dependent 4) make the chain noise calibration flow HW dependent Signed-off-by: Emmanuel Grumbach Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/Kconfig | 19 +- drivers/net/wireless/iwlwifi/Makefile | 1 + drivers/net/wireless/iwlwifi/iwl-4965-commands.h | 8 +- drivers/net/wireless/iwlwifi/iwl-4965.c | 870 +++-------------------- drivers/net/wireless/iwlwifi/iwl-4965.h | 68 +- drivers/net/wireless/iwlwifi/iwl-calib.c | 778 ++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-calib.h | 104 +++ drivers/net/wireless/iwlwifi/iwl-core.h | 7 + drivers/net/wireless/iwlwifi/iwl4965-base.c | 18 +- 9 files changed, 1054 insertions(+), 819 deletions(-) create mode 100644 drivers/net/wireless/iwlwifi/iwl-calib.c create mode 100644 drivers/net/wireless/iwlwifi/iwl-calib.h (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index d5b7a76fcaa..a5fdd0f21a7 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -15,6 +15,15 @@ config IWLWIFI_LEDS bool default n +config IWLWIFI_RUN_TIME_CALIB + bool + depends on IWLCORE + default n + ---help--- + This option will enable run time calibration for the iwlwifi driver. + These calibrations are Sensitivity and Chain Noise. + + config IWLWIFI_RFKILL boolean "IWLWIFI RF kill support" depends on IWLCORE @@ -68,12 +77,14 @@ config IWL4965_SPECTRUM_MEASUREMENT ---help--- This option will enable spectrum measurement for the iwl4965 driver. -config IWL4965_SENSITIVITY - bool "Enable Sensitivity Calibration in iwl4965 driver" +config IWL4965_RUN_TIME_CALIB + bool "Enable run time Calibration for 4965 NIC" + select IWLWIFI_RUN_TIME_CALIB depends on IWL4965 + default y ---help--- - This option will enable sensitivity calibration for the iwl4965 - driver. + This option will enable run time calibration for the iwl4965 driver. + These calibrations are Sensitivity and Chain Noise. If unsure, say yes config IWLWIFI_DEBUG bool "Enable full debugging output in iwl4965 driver" diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index ec6187b75c3..7bc569be4ba 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -3,6 +3,7 @@ iwlcore-objs := iwl-core.o iwl-eeprom.o iwl-hcmd.o iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o iwlcore-$(CONFIG_IWLWIFI_LEDS) += iwl-led.o iwlcore-$(CONFIG_IWLWIFI_RFKILL) += iwl-rfkill.o +iwlcore-$(CONFIG_IWLWIFI_RUN_TIME_CALIB) += iwl-calib.o obj-$(CONFIG_IWL3945) += iwl3945.o iwl3945-objs := iwl3945-base.o iwl-3945.o iwl-3945-rs.o diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-commands.h b/drivers/net/wireless/iwlwifi/iwl-4965-commands.h index 3bcd107e2d7..c03c04fe14c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-commands.h @@ -2559,7 +2559,7 @@ struct iwl4965_missed_beacon_notif { */ /* - * Table entries in SENSITIVITY_CMD (struct iwl4965_sensitivity_cmd) + * Table entries in SENSITIVITY_CMD (struct iwl_sensitivity_cmd) */ #define HD_TABLE_SIZE (11) /* number of entries */ #define HD_MIN_ENERGY_CCK_DET_INDEX (0) /* table indexes */ @@ -2574,18 +2574,18 @@ struct iwl4965_missed_beacon_notif { #define HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX (9) #define HD_OFDM_ENERGY_TH_IN_INDEX (10) -/* Control field in struct iwl4965_sensitivity_cmd */ +/* Control field in struct iwl_sensitivity_cmd */ #define SENSITIVITY_CMD_CONTROL_DEFAULT_TABLE __constant_cpu_to_le16(0) #define SENSITIVITY_CMD_CONTROL_WORK_TABLE __constant_cpu_to_le16(1) /** - * struct iwl4965_sensitivity_cmd + * struct iwl_sensitivity_cmd * @control: (1) updates working table, (0) updates default table * @table: energy threshold values, use HD_* as index into table * * Always use "1" in "control" to update uCode's working table and DSP. */ -struct iwl4965_sensitivity_cmd { +struct iwl_sensitivity_cmd { __le16 control; /* always use "1" */ __le16 table[HD_TABLE_SIZE]; /* use HD_* as index */ } __attribute__ ((packed)); diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 17f629fb96f..be4cc5ffa74 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -43,6 +43,7 @@ #include "iwl-core.h" #include "iwl-io.h" #include "iwl-helpers.h" +#include "iwl-calib.h" /* module parameters */ static struct iwl_mod_params iwl4965_mod_params = { @@ -1032,418 +1033,15 @@ void iwl4965_rf_kill_ct_config(struct iwl_priv *priv) IWL_DEBUG_INFO("REPLY_CT_KILL_CONFIG_CMD succeeded\n"); } -#ifdef CONFIG_IWL4965_SENSITIVITY - -/* "false alarms" are signals that our DSP tries to lock onto, - * but then determines that they are either noise, or transmissions - * from a distant wireless network (also "noise", really) that get - * "stepped on" by stronger transmissions within our own network. - * This algorithm attempts to set a sensitivity level that is high - * enough to receive all of our own network traffic, but not so - * high that our DSP gets too busy trying to lock onto non-network - * activity/noise. */ -static int iwl4965_sens_energy_cck(struct iwl_priv *priv, - u32 norm_fa, - u32 rx_enable_time, - struct statistics_general_data *rx_info) -{ - u32 max_nrg_cck = 0; - int i = 0; - u8 max_silence_rssi = 0; - u32 silence_ref = 0; - u8 silence_rssi_a = 0; - u8 silence_rssi_b = 0; - u8 silence_rssi_c = 0; - u32 val; - - /* "false_alarms" values below are cross-multiplications to assess the - * numbers of false alarms within the measured period of actual Rx - * (Rx is off when we're txing), vs the min/max expected false alarms - * (some should be expected if rx is sensitive enough) in a - * hypothetical listening period of 200 time units (TU), 204.8 msec: - * - * MIN_FA/fixed-time < false_alarms/actual-rx-time < MAX_FA/beacon-time - * - * */ - u32 false_alarms = norm_fa * 200 * 1024; - u32 max_false_alarms = MAX_FA_CCK * rx_enable_time; - u32 min_false_alarms = MIN_FA_CCK * rx_enable_time; - struct iwl4965_sensitivity_data *data = NULL; - - data = &(priv->sensitivity_data); - - data->nrg_auto_corr_silence_diff = 0; - - /* Find max silence rssi among all 3 receivers. - * This is background noise, which may include transmissions from other - * networks, measured during silence before our network's beacon */ - silence_rssi_a = (u8)((rx_info->beacon_silence_rssi_a & - ALL_BAND_FILTER) >> 8); - silence_rssi_b = (u8)((rx_info->beacon_silence_rssi_b & - ALL_BAND_FILTER) >> 8); - silence_rssi_c = (u8)((rx_info->beacon_silence_rssi_c & - ALL_BAND_FILTER) >> 8); - - val = max(silence_rssi_b, silence_rssi_c); - max_silence_rssi = max(silence_rssi_a, (u8) val); - - /* Store silence rssi in 20-beacon history table */ - data->nrg_silence_rssi[data->nrg_silence_idx] = max_silence_rssi; - data->nrg_silence_idx++; - if (data->nrg_silence_idx >= NRG_NUM_PREV_STAT_L) - data->nrg_silence_idx = 0; - - /* Find max silence rssi across 20 beacon history */ - for (i = 0; i < NRG_NUM_PREV_STAT_L; i++) { - val = data->nrg_silence_rssi[i]; - silence_ref = max(silence_ref, val); - } - IWL_DEBUG_CALIB("silence a %u, b %u, c %u, 20-bcn max %u\n", - silence_rssi_a, silence_rssi_b, silence_rssi_c, - silence_ref); - - /* Find max rx energy (min value!) among all 3 receivers, - * measured during beacon frame. - * Save it in 10-beacon history table. */ - i = data->nrg_energy_idx; - val = min(rx_info->beacon_energy_b, rx_info->beacon_energy_c); - data->nrg_value[i] = min(rx_info->beacon_energy_a, val); - - data->nrg_energy_idx++; - if (data->nrg_energy_idx >= 10) - data->nrg_energy_idx = 0; - - /* Find min rx energy (max value) across 10 beacon history. - * This is the minimum signal level that we want to receive well. - * Add backoff (margin so we don't miss slightly lower energy frames). - * This establishes an upper bound (min value) for energy threshold. */ - max_nrg_cck = data->nrg_value[0]; - for (i = 1; i < 10; i++) - max_nrg_cck = (u32) max(max_nrg_cck, (data->nrg_value[i])); - max_nrg_cck += 6; - - IWL_DEBUG_CALIB("rx energy a %u, b %u, c %u, 10-bcn max/min %u\n", - rx_info->beacon_energy_a, rx_info->beacon_energy_b, - rx_info->beacon_energy_c, max_nrg_cck - 6); - - /* Count number of consecutive beacons with fewer-than-desired - * false alarms. */ - if (false_alarms < min_false_alarms) - data->num_in_cck_no_fa++; - else - data->num_in_cck_no_fa = 0; - IWL_DEBUG_CALIB("consecutive bcns with few false alarms = %u\n", - data->num_in_cck_no_fa); - - /* If we got too many false alarms this time, reduce sensitivity */ - if (false_alarms > max_false_alarms) { - IWL_DEBUG_CALIB("norm FA %u > max FA %u\n", - false_alarms, max_false_alarms); - IWL_DEBUG_CALIB("... reducing sensitivity\n"); - data->nrg_curr_state = IWL_FA_TOO_MANY; - - if (data->auto_corr_cck > AUTO_CORR_MAX_TH_CCK) { - /* Store for "fewer than desired" on later beacon */ - data->nrg_silence_ref = silence_ref; - - /* increase energy threshold (reduce nrg value) - * to decrease sensitivity */ - if (data->nrg_th_cck > (NRG_MAX_CCK + NRG_STEP_CCK)) - data->nrg_th_cck = data->nrg_th_cck - - NRG_STEP_CCK; - } - - /* increase auto_corr values to decrease sensitivity */ - if (data->auto_corr_cck < AUTO_CORR_MAX_TH_CCK) - data->auto_corr_cck = AUTO_CORR_MAX_TH_CCK + 1; - else { - val = data->auto_corr_cck + AUTO_CORR_STEP_CCK; - data->auto_corr_cck = min((u32)AUTO_CORR_MAX_CCK, val); - } - val = data->auto_corr_cck_mrc + AUTO_CORR_STEP_CCK; - data->auto_corr_cck_mrc = min((u32)AUTO_CORR_MAX_CCK_MRC, val); - - /* Else if we got fewer than desired, increase sensitivity */ - } else if (false_alarms < min_false_alarms) { - data->nrg_curr_state = IWL_FA_TOO_FEW; - - /* Compare silence level with silence level for most recent - * healthy number or too many false alarms */ - data->nrg_auto_corr_silence_diff = (s32)data->nrg_silence_ref - - (s32)silence_ref; - - IWL_DEBUG_CALIB("norm FA %u < min FA %u, silence diff %d\n", - false_alarms, min_false_alarms, - data->nrg_auto_corr_silence_diff); - - /* Increase value to increase sensitivity, but only if: - * 1a) previous beacon did *not* have *too many* false alarms - * 1b) AND there's a significant difference in Rx levels - * from a previous beacon with too many, or healthy # FAs - * OR 2) We've seen a lot of beacons (100) with too few - * false alarms */ - if ((data->nrg_prev_state != IWL_FA_TOO_MANY) && - ((data->nrg_auto_corr_silence_diff > NRG_DIFF) || - (data->num_in_cck_no_fa > MAX_NUMBER_CCK_NO_FA))) { - - IWL_DEBUG_CALIB("... increasing sensitivity\n"); - /* Increase nrg value to increase sensitivity */ - val = data->nrg_th_cck + NRG_STEP_CCK; - data->nrg_th_cck = min((u32)NRG_MIN_CCK, val); - - /* Decrease auto_corr values to increase sensitivity */ - val = data->auto_corr_cck - AUTO_CORR_STEP_CCK; - data->auto_corr_cck = max((u32)AUTO_CORR_MIN_CCK, val); - - val = data->auto_corr_cck_mrc - AUTO_CORR_STEP_CCK; - data->auto_corr_cck_mrc = - max((u32)AUTO_CORR_MIN_CCK_MRC, val); - - } else - IWL_DEBUG_CALIB("... but not changing sensitivity\n"); - - /* Else we got a healthy number of false alarms, keep status quo */ - } else { - IWL_DEBUG_CALIB(" FA in safe zone\n"); - data->nrg_curr_state = IWL_FA_GOOD_RANGE; - - /* Store for use in "fewer than desired" with later beacon */ - data->nrg_silence_ref = silence_ref; - - /* If previous beacon had too many false alarms, - * give it some extra margin by reducing sensitivity again - * (but don't go below measured energy of desired Rx) */ - if (IWL_FA_TOO_MANY == data->nrg_prev_state) { - IWL_DEBUG_CALIB("... increasing margin\n"); - data->nrg_th_cck -= NRG_MARGIN; - } - } - - /* Make sure the energy threshold does not go above the measured - * energy of the desired Rx signals (reduced by backoff margin), - * or else we might start missing Rx frames. - * Lower value is higher energy, so we use max()! - */ - data->nrg_th_cck = max(max_nrg_cck, data->nrg_th_cck); - IWL_DEBUG_CALIB("new nrg_th_cck %u\n", data->nrg_th_cck); - - data->nrg_prev_state = data->nrg_curr_state; - - return 0; -} - - -static int iwl4965_sens_auto_corr_ofdm(struct iwl_priv *priv, - u32 norm_fa, - u32 rx_enable_time) -{ - u32 val; - u32 false_alarms = norm_fa * 200 * 1024; - u32 max_false_alarms = MAX_FA_OFDM * rx_enable_time; - u32 min_false_alarms = MIN_FA_OFDM * rx_enable_time; - struct iwl4965_sensitivity_data *data = NULL; - - data = &(priv->sensitivity_data); - - /* If we got too many false alarms this time, reduce sensitivity */ - if (false_alarms > max_false_alarms) { - - IWL_DEBUG_CALIB("norm FA %u > max FA %u)\n", - false_alarms, max_false_alarms); - - val = data->auto_corr_ofdm + AUTO_CORR_STEP_OFDM; - data->auto_corr_ofdm = - min((u32)AUTO_CORR_MAX_OFDM, val); - - val = data->auto_corr_ofdm_mrc + AUTO_CORR_STEP_OFDM; - data->auto_corr_ofdm_mrc = - min((u32)AUTO_CORR_MAX_OFDM_MRC, val); - - val = data->auto_corr_ofdm_x1 + AUTO_CORR_STEP_OFDM; - data->auto_corr_ofdm_x1 = - min((u32)AUTO_CORR_MAX_OFDM_X1, val); - - val = data->auto_corr_ofdm_mrc_x1 + AUTO_CORR_STEP_OFDM; - data->auto_corr_ofdm_mrc_x1 = - min((u32)AUTO_CORR_MAX_OFDM_MRC_X1, val); - } - - /* Else if we got fewer than desired, increase sensitivity */ - else if (false_alarms < min_false_alarms) { - - IWL_DEBUG_CALIB("norm FA %u < min FA %u\n", - false_alarms, min_false_alarms); - - val = data->auto_corr_ofdm - AUTO_CORR_STEP_OFDM; - data->auto_corr_ofdm = - max((u32)AUTO_CORR_MIN_OFDM, val); - - val = data->auto_corr_ofdm_mrc - AUTO_CORR_STEP_OFDM; - data->auto_corr_ofdm_mrc = - max((u32)AUTO_CORR_MIN_OFDM_MRC, val); - - val = data->auto_corr_ofdm_x1 - AUTO_CORR_STEP_OFDM; - data->auto_corr_ofdm_x1 = - max((u32)AUTO_CORR_MIN_OFDM_X1, val); - - val = data->auto_corr_ofdm_mrc_x1 - AUTO_CORR_STEP_OFDM; - data->auto_corr_ofdm_mrc_x1 = - max((u32)AUTO_CORR_MIN_OFDM_MRC_X1, val); - } - - else - IWL_DEBUG_CALIB("min FA %u < norm FA %u < max FA %u OK\n", - min_false_alarms, false_alarms, max_false_alarms); - - return 0; -} - -static int iwl4965_sensitivity_callback(struct iwl_priv *priv, - struct iwl_cmd *cmd, struct sk_buff *skb) -{ - /* We didn't cache the SKB; let the caller free it */ - return 1; -} - -/* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */ -static int iwl4965_sensitivity_write(struct iwl_priv *priv, u8 flags) -{ - struct iwl4965_sensitivity_cmd cmd ; - struct iwl4965_sensitivity_data *data = NULL; - struct iwl_host_cmd cmd_out = { - .id = SENSITIVITY_CMD, - .len = sizeof(struct iwl4965_sensitivity_cmd), - .meta.flags = flags, - .data = &cmd, - }; - int ret; - - data = &(priv->sensitivity_data); - - memset(&cmd, 0, sizeof(cmd)); - - cmd.table[HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX] = - cpu_to_le16((u16)data->auto_corr_ofdm); - cmd.table[HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX] = - cpu_to_le16((u16)data->auto_corr_ofdm_mrc); - cmd.table[HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX] = - cpu_to_le16((u16)data->auto_corr_ofdm_x1); - cmd.table[HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX] = - cpu_to_le16((u16)data->auto_corr_ofdm_mrc_x1); - - cmd.table[HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX] = - cpu_to_le16((u16)data->auto_corr_cck); - cmd.table[HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX] = - cpu_to_le16((u16)data->auto_corr_cck_mrc); - - cmd.table[HD_MIN_ENERGY_CCK_DET_INDEX] = - cpu_to_le16((u16)data->nrg_th_cck); - cmd.table[HD_MIN_ENERGY_OFDM_DET_INDEX] = - cpu_to_le16((u16)data->nrg_th_ofdm); - - cmd.table[HD_BARKER_CORR_TH_ADD_MIN_INDEX] = - __constant_cpu_to_le16(190); - cmd.table[HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX] = - __constant_cpu_to_le16(390); - cmd.table[HD_OFDM_ENERGY_TH_IN_INDEX] = - __constant_cpu_to_le16(62); - - IWL_DEBUG_CALIB("ofdm: ac %u mrc %u x1 %u mrc_x1 %u thresh %u\n", - data->auto_corr_ofdm, data->auto_corr_ofdm_mrc, - data->auto_corr_ofdm_x1, data->auto_corr_ofdm_mrc_x1, - data->nrg_th_ofdm); - - IWL_DEBUG_CALIB("cck: ac %u mrc %u thresh %u\n", - data->auto_corr_cck, data->auto_corr_cck_mrc, - data->nrg_th_cck); - - /* Update uCode's "work" table, and copy it to DSP */ - cmd.control = SENSITIVITY_CMD_CONTROL_WORK_TABLE; - - if (flags & CMD_ASYNC) - cmd_out.meta.u.callback = iwl4965_sensitivity_callback; - - /* Don't send command to uCode if nothing has changed */ - if (!memcmp(&cmd.table[0], &(priv->sensitivity_tbl[0]), - sizeof(u16)*HD_TABLE_SIZE)) { - IWL_DEBUG_CALIB("No change in SENSITIVITY_CMD\n"); - return 0; - } - - /* Copy table for comparison next time */ - memcpy(&(priv->sensitivity_tbl[0]), &(cmd.table[0]), - sizeof(u16)*HD_TABLE_SIZE); - - ret = iwl_send_cmd(priv, &cmd_out); - if (ret) - IWL_ERROR("SENSITIVITY_CMD failed\n"); - - return ret; -} - -void iwl4965_init_sensitivity(struct iwl_priv *priv, u8 flags, u8 force) -{ - struct iwl4965_sensitivity_data *data = NULL; - int i; - int ret = 0; - - IWL_DEBUG_CALIB("Start iwl4965_init_sensitivity\n"); - - if (force) - memset(&(priv->sensitivity_tbl[0]), 0, - sizeof(u16)*HD_TABLE_SIZE); - - /* Clear driver's sensitivity algo data */ - data = &(priv->sensitivity_data); - memset(data, 0, sizeof(struct iwl4965_sensitivity_data)); - - data->num_in_cck_no_fa = 0; - data->nrg_curr_state = IWL_FA_TOO_MANY; - data->nrg_prev_state = IWL_FA_TOO_MANY; - data->nrg_silence_ref = 0; - data->nrg_silence_idx = 0; - data->nrg_energy_idx = 0; - - for (i = 0; i < 10; i++) - data->nrg_value[i] = 0; - - for (i = 0; i < NRG_NUM_PREV_STAT_L; i++) - data->nrg_silence_rssi[i] = 0; - - data->auto_corr_ofdm = 90; - data->auto_corr_ofdm_mrc = 170; - data->auto_corr_ofdm_x1 = 105; - data->auto_corr_ofdm_mrc_x1 = 220; - data->auto_corr_cck = AUTO_CORR_CCK_MIN_VAL_DEF; - data->auto_corr_cck_mrc = 200; - data->nrg_th_cck = 100; - data->nrg_th_ofdm = 100; - - data->last_bad_plcp_cnt_ofdm = 0; - data->last_fa_cnt_ofdm = 0; - data->last_bad_plcp_cnt_cck = 0; - data->last_fa_cnt_cck = 0; - - /* Clear prior Sensitivity command data to force send to uCode */ - if (force) - memset(&(priv->sensitivity_tbl[0]), 0, - sizeof(u16)*HD_TABLE_SIZE); - - ret |= iwl4965_sensitivity_write(priv, flags); - IWL_DEBUG_CALIB("<chain_noise_data); - data = &(priv->chain_noise_data); if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) { struct iwl4965_calibration_cmd cmd; @@ -1452,357 +1050,76 @@ void iwl4965_chain_noise_reset(struct iwl_priv *priv) cmd.diff_gain_a = 0; cmd.diff_gain_b = 0; cmd.diff_gain_c = 0; - iwl_send_cmd_pdu_async(priv, REPLY_PHY_CALIBRATION_CMD, - sizeof(cmd), &cmd, NULL); - msleep(4); + if (iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, + sizeof(cmd), &cmd)) + IWL_ERROR("Could not send REPLY_PHY_CALIBRATION_CMD\n"); data->state = IWL_CHAIN_NOISE_ACCUMULATE; IWL_DEBUG_CALIB("Run chain_noise_calibrate\n"); } - return; } -/* - * Accumulate 20 beacons of signal and noise statistics for each of - * 3 receivers/antennas/rx-chains, then figure out: - * 1) Which antennas are connected. - * 2) Differential rx gain settings to balance the 3 receivers. - */ -static void iwl4965_noise_calibration(struct iwl_priv *priv, - struct iwl4965_notif_statistics *stat_resp) +static void iwl4965_gain_computation(struct iwl_priv *priv, + u32 *average_noise, + u16 min_average_noise_antenna_i, + u32 min_average_noise) { - struct iwl4965_chain_noise_data *data = NULL; - int ret = 0; - - u32 chain_noise_a; - u32 chain_noise_b; - u32 chain_noise_c; - u32 chain_sig_a; - u32 chain_sig_b; - u32 chain_sig_c; - u32 average_sig[NUM_RX_CHAINS] = {INITIALIZATION_VALUE}; - u32 average_noise[NUM_RX_CHAINS] = {INITIALIZATION_VALUE}; - u32 max_average_sig; - u16 max_average_sig_antenna_i; - u32 min_average_noise = MIN_AVERAGE_NOISE_MAX_VALUE; - u16 min_average_noise_antenna_i = INITIALIZATION_VALUE; - u16 i = 0; - u16 chan_num = INITIALIZATION_VALUE; - u32 band = INITIALIZATION_VALUE; - u32 active_chains = 0; - unsigned long flags; - struct statistics_rx_non_phy *rx_info = &(stat_resp->rx.general); - - data = &(priv->chain_noise_data); + int i, ret; + struct iwl_chain_noise_data *data = &priv->chain_noise_data; - /* Accumulate just the first 20 beacons after the first association, - * then we're done forever. */ - if (data->state != IWL_CHAIN_NOISE_ACCUMULATE) { - if (data->state == IWL_CHAIN_NOISE_ALIVE) - IWL_DEBUG_CALIB("Wait for noise calib reset\n"); - return; - } - - spin_lock_irqsave(&priv->lock, flags); - if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) { - IWL_DEBUG_CALIB(" << Interference data unavailable\n"); - spin_unlock_irqrestore(&priv->lock, flags); - return; - } - - band = (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) ? 0 : 1; - chan_num = le16_to_cpu(priv->staging_rxon.channel); - - /* Make sure we accumulate data for just the associated channel - * (even if scanning). */ - if ((chan_num != (le32_to_cpu(stat_resp->flag) >> 16)) || - ((STATISTICS_REPLY_FLG_BAND_24G_MSK == - (stat_resp->flag & STATISTICS_REPLY_FLG_BAND_24G_MSK)) && band)) { - IWL_DEBUG_CALIB("Stats not from chan=%d, band=%d\n", - chan_num, band); - spin_unlock_irqrestore(&priv->lock, flags); - return; - } - - /* Accumulate beacon statistics values across 20 beacons */ - chain_noise_a = le32_to_cpu(rx_info->beacon_silence_rssi_a) & - IN_BAND_FILTER; - chain_noise_b = le32_to_cpu(rx_info->beacon_silence_rssi_b) & - IN_BAND_FILTER; - chain_noise_c = le32_to_cpu(rx_info->beacon_silence_rssi_c) & - IN_BAND_FILTER; - - chain_sig_a = le32_to_cpu(rx_info->beacon_rssi_a) & IN_BAND_FILTER; - chain_sig_b = le32_to_cpu(rx_info->beacon_rssi_b) & IN_BAND_FILTER; - chain_sig_c = le32_to_cpu(rx_info->beacon_rssi_c) & IN_BAND_FILTER; + data->delta_gain_code[min_average_noise_antenna_i] = 0; - spin_unlock_irqrestore(&priv->lock, flags); + for (i = 0; i < NUM_RX_CHAINS; i++) { + s32 delta_g = 0; - data->beacon_count++; - - data->chain_noise_a = (chain_noise_a + data->chain_noise_a); - data->chain_noise_b = (chain_noise_b + data->chain_noise_b); - data->chain_noise_c = (chain_noise_c + data->chain_noise_c); - - data->chain_signal_a = (chain_sig_a + data->chain_signal_a); - data->chain_signal_b = (chain_sig_b + data->chain_signal_b); - data->chain_signal_c = (chain_sig_c + data->chain_signal_c); - - IWL_DEBUG_CALIB("chan=%d, band=%d, beacon=%d\n", chan_num, band, - data->beacon_count); - IWL_DEBUG_CALIB("chain_sig: a %d b %d c %d\n", - chain_sig_a, chain_sig_b, chain_sig_c); - IWL_DEBUG_CALIB("chain_noise: a %d b %d c %d\n", - chain_noise_a, chain_noise_b, chain_noise_c); - - /* If this is the 20th beacon, determine: - * 1) Disconnected antennas (using signal strengths) - * 2) Differential gain (using silence noise) to balance receivers */ - if (data->beacon_count == CAL_NUM_OF_BEACONS) { - - /* Analyze signal for disconnected antenna */ - average_sig[0] = (data->chain_signal_a) / CAL_NUM_OF_BEACONS; - average_sig[1] = (data->chain_signal_b) / CAL_NUM_OF_BEACONS; - average_sig[2] = (data->chain_signal_c) / CAL_NUM_OF_BEACONS; - - if (average_sig[0] >= average_sig[1]) { - max_average_sig = average_sig[0]; - max_average_sig_antenna_i = 0; - active_chains = (1 << max_average_sig_antenna_i); - } else { - max_average_sig = average_sig[1]; - max_average_sig_antenna_i = 1; - active_chains = (1 << max_average_sig_antenna_i); - } - - if (average_sig[2] >= max_average_sig) { - max_average_sig = average_sig[2]; - max_average_sig_antenna_i = 2; - active_chains = (1 << max_average_sig_antenna_i); - } - - IWL_DEBUG_CALIB("average_sig: a %d b %d c %d\n", - average_sig[0], average_sig[1], average_sig[2]); - IWL_DEBUG_CALIB("max_average_sig = %d, antenna %d\n", - max_average_sig, max_average_sig_antenna_i); - - /* Compare signal strengths for all 3 receivers. */ - for (i = 0; i < NUM_RX_CHAINS; i++) { - if (i != max_average_sig_antenna_i) { - s32 rssi_delta = (max_average_sig - - average_sig[i]); - - /* If signal is very weak, compared with - * strongest, mark it as disconnected. */ - if (rssi_delta > MAXIMUM_ALLOWED_PATHLOSS) - data->disconn_array[i] = 1; - else - active_chains |= (1 << i); - IWL_DEBUG_CALIB("i = %d rssiDelta = %d " - "disconn_array[i] = %d\n", - i, rssi_delta, data->disconn_array[i]); - } - } - - /*If both chains A & B are disconnected - - * connect B and leave A as is */ - if (data->disconn_array[CHAIN_A] && - data->disconn_array[CHAIN_B]) { - data->disconn_array[CHAIN_B] = 0; - active_chains |= (1 << CHAIN_B); - IWL_DEBUG_CALIB("both A & B chains are disconnected! " - "W/A - declare B as connected\n"); - } - - IWL_DEBUG_CALIB("active_chains (bitwise) = 0x%x\n", - active_chains); - - /* Save for use within RXON, TX, SCAN commands, etc. */ - priv->valid_antenna = active_chains; - - /* Analyze noise for rx balance */ - average_noise[0] = ((data->chain_noise_a)/CAL_NUM_OF_BEACONS); - average_noise[1] = ((data->chain_noise_b)/CAL_NUM_OF_BEACONS); - average_noise[2] = ((data->chain_noise_c)/CAL_NUM_OF_BEACONS); - - for (i = 0; i < NUM_RX_CHAINS; i++) { - if (!(data->disconn_array[i]) && - (average_noise[i] <= min_average_noise)) { - /* This means that chain i is active and has - * lower noise values so far: */ - min_average_noise = average_noise[i]; - min_average_noise_antenna_i = i; - } - } - - data->delta_gain_code[min_average_noise_antenna_i] = 0; - - IWL_DEBUG_CALIB("average_noise: a %d b %d c %d\n", - average_noise[0], average_noise[1], - average_noise[2]); - - IWL_DEBUG_CALIB("min_average_noise = %d, antenna %d\n", - min_average_noise, min_average_noise_antenna_i); - - for (i = 0; i < NUM_RX_CHAINS; i++) { - s32 delta_g = 0; - - if (!(data->disconn_array[i]) && - (data->delta_gain_code[i] == + if (!(data->disconn_array[i]) && + (data->delta_gain_code[i] == CHAIN_NOISE_DELTA_GAIN_INIT_VAL)) { - delta_g = average_noise[i] - min_average_noise; - data->delta_gain_code[i] = (u8)((delta_g * - 10) / 15); - if (CHAIN_NOISE_MAX_DELTA_GAIN_CODE < - data->delta_gain_code[i]) - data->delta_gain_code[i] = - CHAIN_NOISE_MAX_DELTA_GAIN_CODE; - - data->delta_gain_code[i] = - (data->delta_gain_code[i] | (1 << 2)); - } else - data->delta_gain_code[i] = 0; - } - IWL_DEBUG_CALIB("delta_gain_codes: a %d b %d c %d\n", - data->delta_gain_code[0], - data->delta_gain_code[1], - data->delta_gain_code[2]); - - /* Differential gain gets sent to uCode only once */ - if (!data->radio_write) { - struct iwl4965_calibration_cmd cmd; - data->radio_write = 1; - - memset(&cmd, 0, sizeof(cmd)); - cmd.opCode = PHY_CALIBRATE_DIFF_GAIN_CMD; - cmd.diff_gain_a = data->delta_gain_code[0]; - cmd.diff_gain_b = data->delta_gain_code[1]; - cmd.diff_gain_c = data->delta_gain_code[2]; - ret = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, - sizeof(cmd), &cmd); - if (ret) - IWL_DEBUG_CALIB("fail sending cmd " - "REPLY_PHY_CALIBRATION_CMD \n"); - - /* TODO we might want recalculate - * rx_chain in rxon cmd */ - - /* Mark so we run this algo only once! */ - data->state = IWL_CHAIN_NOISE_CALIBRATED; + delta_g = average_noise[i] - min_average_noise; + data->delta_gain_code[i] = (u8)((delta_g * 10) / 15); + data->delta_gain_code[i] = + min(data->delta_gain_code[i], + (u8) CHAIN_NOISE_MAX_DELTA_GAIN_CODE); + + data->delta_gain_code[i] = + (data->delta_gain_code[i] | (1 << 2)); + } else { + data->delta_gain_code[i] = 0; } - data->chain_noise_a = 0; - data->chain_noise_b = 0; - data->chain_noise_c = 0; - data->chain_signal_a = 0; - data->chain_signal_b = 0; - data->chain_signal_c = 0; - data->beacon_count = 0; - } - return; -} - -static void iwl4965_sensitivity_calibration(struct iwl_priv *priv, - struct iwl4965_notif_statistics *resp) -{ - u32 rx_enable_time; - u32 fa_cck; - u32 fa_ofdm; - u32 bad_plcp_cck; - u32 bad_plcp_ofdm; - u32 norm_fa_ofdm; - u32 norm_fa_cck; - struct iwl4965_sensitivity_data *data = NULL; - struct statistics_rx_non_phy *rx_info = &(resp->rx.general); - struct statistics_rx *statistics = &(resp->rx); - unsigned long flags; - struct statistics_general_data statis; - int ret; - - data = &(priv->sensitivity_data); - - if (!iwl_is_associated(priv)) { - IWL_DEBUG_CALIB("<< - not associated\n"); - return; - } - - spin_lock_irqsave(&priv->lock, flags); - if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) { - IWL_DEBUG_CALIB("<< invalid data.\n"); - spin_unlock_irqrestore(&priv->lock, flags); - return; - } - - /* Extract Statistics: */ - rx_enable_time = le32_to_cpu(rx_info->channel_load); - fa_cck = le32_to_cpu(statistics->cck.false_alarm_cnt); - fa_ofdm = le32_to_cpu(statistics->ofdm.false_alarm_cnt); - bad_plcp_cck = le32_to_cpu(statistics->cck.plcp_err); - bad_plcp_ofdm = le32_to_cpu(statistics->ofdm.plcp_err); - - statis.beacon_silence_rssi_a = - le32_to_cpu(statistics->general.beacon_silence_rssi_a); - statis.beacon_silence_rssi_b = - le32_to_cpu(statistics->general.beacon_silence_rssi_b); - statis.beacon_silence_rssi_c = - le32_to_cpu(statistics->general.beacon_silence_rssi_c); - statis.beacon_energy_a = - le32_to_cpu(statistics->general.beacon_energy_a); - statis.beacon_energy_b = - le32_to_cpu(statistics->general.beacon_energy_b); - statis.beacon_energy_c = - le32_to_cpu(statistics->general.beacon_energy_c); - - spin_unlock_irqrestore(&priv->lock, flags); - - IWL_DEBUG_CALIB("rx_enable_time = %u usecs\n", rx_enable_time); - - if (!rx_enable_time) { - IWL_DEBUG_CALIB("<< RX Enable Time == 0! \n"); - return; - } - - /* These statistics increase monotonically, and do not reset - * at each beacon. Calculate difference from last value, or just - * use the new statistics value if it has reset or wrapped around. */ - if (data->last_bad_plcp_cnt_cck > bad_plcp_cck) - data->last_bad_plcp_cnt_cck = bad_plcp_cck; - else { - bad_plcp_cck -= data->last_bad_plcp_cnt_cck; - data->last_bad_plcp_cnt_cck += bad_plcp_cck; - } - - if (data->last_bad_plcp_cnt_ofdm > bad_plcp_ofdm) - data->last_bad_plcp_cnt_ofdm = bad_plcp_ofdm; - else { - bad_plcp_ofdm -= data->last_bad_plcp_cnt_ofdm; - data->last_bad_plcp_cnt_ofdm += bad_plcp_ofdm; } + IWL_DEBUG_CALIB("delta_gain_codes: a %d b %d c %d\n", + data->delta_gain_code[0], + data->delta_gain_code[1], + data->delta_gain_code[2]); - if (data->last_fa_cnt_ofdm > fa_ofdm) - data->last_fa_cnt_ofdm = fa_ofdm; - else { - fa_ofdm -= data->last_fa_cnt_ofdm; - data->last_fa_cnt_ofdm += fa_ofdm; - } + /* Differential gain gets sent to uCode only once */ + if (!data->radio_write) { + struct iwl4965_calibration_cmd cmd; + data->radio_write = 1; - if (data->last_fa_cnt_cck > fa_cck) - data->last_fa_cnt_cck = fa_cck; - else { - fa_cck -= data->last_fa_cnt_cck; - data->last_fa_cnt_cck += fa_cck; + memset(&cmd, 0, sizeof(cmd)); + cmd.opCode = PHY_CALIBRATE_DIFF_GAIN_CMD; + cmd.diff_gain_a = data->delta_gain_code[0]; + cmd.diff_gain_b = data->delta_gain_code[1]; + cmd.diff_gain_c = data->delta_gain_code[2]; + ret = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, + sizeof(cmd), &cmd); + if (ret) + IWL_DEBUG_CALIB("fail sending cmd " + "REPLY_PHY_CALIBRATION_CMD \n"); + + /* TODO we might want recalculate + * rx_chain in rxon cmd */ + + /* Mark so we run this algo only once! */ + data->state = IWL_CHAIN_NOISE_CALIBRATED; } - - /* Total aborted signal locks */ - norm_fa_ofdm = fa_ofdm + bad_plcp_ofdm; - norm_fa_cck = fa_cck + bad_plcp_cck; - - IWL_DEBUG_CALIB("cck: fa %u badp %u ofdm: fa %u badp %u\n", fa_cck, - bad_plcp_cck, fa_ofdm, bad_plcp_ofdm); - - iwl4965_sens_auto_corr_ofdm(priv, norm_fa_ofdm, rx_enable_time); - iwl4965_sens_energy_cck(priv, norm_fa_cck, rx_enable_time, &statis); - ret = iwl4965_sensitivity_write(priv, CMD_ASYNC); - - return; + data->chain_noise_a = 0; + data->chain_noise_b = 0; + data->chain_noise_c = 0; + data->chain_signal_a = 0; + data->chain_signal_b = 0; + data->chain_signal_c = 0; + data->beacon_count = 0; } static void iwl4965_bg_sensitivity_work(struct work_struct *work) @@ -1819,21 +1136,15 @@ static void iwl4965_bg_sensitivity_work(struct work_struct *work) } if (priv->start_calib) { - iwl4965_noise_calibration(priv, &priv->statistics); - - if (priv->sensitivity_data.state == - IWL_SENS_CALIB_NEED_REINIT) { - iwl4965_init_sensitivity(priv, CMD_ASYNC, 0); - priv->sensitivity_data.state = IWL_SENS_CALIB_ALLOWED; - } else - iwl4965_sensitivity_calibration(priv, - &priv->statistics); + iwl_chain_noise_calibration(priv, &priv->statistics); + + iwl_sensitivity_calibration(priv, &priv->statistics); } mutex_unlock(&priv->mutex); return; } -#endif /*CONFIG_IWL4965_SENSITIVITY*/ +#endif /*CONFIG_IWL4965_RUN_TIME_CALIB*/ static void iwl4965_bg_txpower_work(struct work_struct *work) { @@ -1932,15 +1243,15 @@ int iwl4965_alive_notify(struct iwl_priv *priv) spin_lock_irqsave(&priv->lock, flags); -#ifdef CONFIG_IWL4965_SENSITIVITY +#ifdef CONFIG_IWL4965_RUN_TIME_CALIB memset(&(priv->sensitivity_data), 0, - sizeof(struct iwl4965_sensitivity_data)); + sizeof(struct iwl_sensitivity_data)); memset(&(priv->chain_noise_data), 0, - sizeof(struct iwl4965_chain_noise_data)); + sizeof(struct iwl_chain_noise_data)); for (i = 0; i < NUM_RX_CHAINS; i++) priv->chain_noise_data.delta_gain_code[i] = CHAIN_NOISE_DELTA_GAIN_INIT_VAL; -#endif /* CONFIG_IWL4965_SENSITIVITY*/ +#endif /* CONFIG_IWL4965_RUN_TIME_CALIB*/ ret = iwl_grab_nic_access(priv); if (ret) { spin_unlock_irqrestore(&priv->lock, flags); @@ -2013,6 +1324,31 @@ int iwl4965_alive_notify(struct iwl_priv *priv) return ret; } +#ifdef CONFIG_IWL4965_RUN_TIME_CALIB +static struct iwl_sensitivity_ranges iwl4965_sensitivity = { + .min_nrg_cck = 97, + .max_nrg_cck = 0, + + .auto_corr_min_ofdm = 85, + .auto_corr_min_ofdm_mrc = 170, + .auto_corr_min_ofdm_x1 = 105, + .auto_corr_min_ofdm_mrc_x1 = 220, + + .auto_corr_max_ofdm = 120, + .auto_corr_max_ofdm_mrc = 210, + .auto_corr_max_ofdm_x1 = 140, + .auto_corr_max_ofdm_mrc_x1 = 270, + + .auto_corr_min_cck = 125, + .auto_corr_max_cck = 200, + .auto_corr_min_cck_mrc = 200, + .auto_corr_max_cck_mrc = 400, + + .nrg_th_cck = 100, + .nrg_th_ofdm = 100, +}; +#endif + /** * iwl4965_hw_set_hw_params * @@ -2044,6 +1380,9 @@ int iwl4965_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.rx_chains_num = 2; priv->hw_params.valid_tx_ant = (IWL_ANTENNA_MAIN | IWL_ANTENNA_AUX); priv->hw_params.valid_rx_ant = (IWL_ANTENNA_MAIN | IWL_ANTENNA_AUX); +#ifdef CONFIG_IWL4965_RUN_TIME_CALIB + priv->hw_params.sens = &iwl4965_sensitivity; +#endif return 0; } @@ -3202,7 +2541,7 @@ void iwl4965_set_rxon_chain(struct iwl_priv *priv) /* Tell uCode which antennas are actually connected. * Before first association, we assume all antennas are connected. - * Just after first association, iwl4965_noise_calibration() + * Just after first association, iwl_chain_noise_calibration() * checks which antennas actually *are* connected. */ priv->staging_rxon.rx_chain |= cpu_to_le16(priv->valid_antenna << RXON_RX_CHAIN_VALID_POS); @@ -3412,7 +2751,7 @@ void iwl4965_hw_rx_statistics(struct iwl_priv *priv, struct iwl4965_rx_mem_buffe if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) && (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) { iwl4965_rx_calc_noise(priv); -#ifdef CONFIG_IWL4965_SENSITIVITY +#ifdef CONFIG_IWL4965_RUN_TIME_CALIB queue_work(priv->workqueue, &priv->sensitivity_work); #endif } @@ -4139,7 +3478,7 @@ static void iwl4965_rx_missed_beacon_notif(struct iwl_priv *priv, struct iwl4965_rx_mem_buffer *rxb) { -#ifdef CONFIG_IWL4965_SENSITIVITY +#ifdef CONFIG_IWL4965_RUN_TIME_CALIB struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; struct iwl4965_missed_beacon_notif *missed_beacon; @@ -4150,11 +3489,10 @@ static void iwl4965_rx_missed_beacon_notif(struct iwl_priv *priv, le32_to_cpu(missed_beacon->total_missed_becons), le32_to_cpu(missed_beacon->num_recvd_beacons), le32_to_cpu(missed_beacon->num_expected_beacons)); - priv->sensitivity_data.state = IWL_SENS_CALIB_NEED_REINIT; - if (unlikely(!test_bit(STATUS_SCANNING, &priv->status))) - queue_work(priv->workqueue, &priv->sensitivity_work); + if (!test_bit(STATUS_SCANNING, &priv->status)) + iwl_init_sensitivity(priv); } -#endif /*CONFIG_IWL4965_SENSITIVITY*/ +#endif /*CONFIG_IWL4965_RUN_TIME_CALIB*/ } #ifdef CONFIG_IWL4965_HT @@ -4930,7 +4268,7 @@ void iwl4965_hw_rx_handler_setup(struct iwl_priv *priv) void iwl4965_hw_setup_deferred_work(struct iwl_priv *priv) { INIT_WORK(&priv->txpower_work, iwl4965_bg_txpower_work); -#ifdef CONFIG_IWL4965_SENSITIVITY +#ifdef CONFIG_IWL4965_RUN_TIME_CALIB INIT_WORK(&priv->sensitivity_work, iwl4965_bg_sensitivity_work); #endif init_timer(&priv->statistics_periodic); @@ -4952,6 +4290,10 @@ static struct iwl_hcmd_ops iwl4965_hcmd = { static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = { .enqueue_hcmd = iwl4965_enqueue_hcmd, +#ifdef CONFIG_IWL4965_RUN_TIME_CALIB + .chain_noise_reset = iwl4965_chain_noise_reset, + .gain_computation = iwl4965_gain_computation, +#endif }; static struct iwl_lib_ops iwl4965_lib = { diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h index 581b98556c8..d728dd837e9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965.h @@ -566,6 +566,29 @@ struct iwl4965_ibss_seq { struct list_head list; }; +struct iwl_sensitivity_ranges { + u16 min_nrg_cck; + u16 max_nrg_cck; + + u16 nrg_th_cck; + u16 nrg_th_ofdm; + + u16 auto_corr_min_ofdm; + u16 auto_corr_min_ofdm_mrc; + u16 auto_corr_min_ofdm_x1; + u16 auto_corr_min_ofdm_mrc_x1; + + u16 auto_corr_max_ofdm; + u16 auto_corr_max_ofdm_mrc; + u16 auto_corr_max_ofdm_x1; + u16 auto_corr_max_ofdm_mrc_x1; + + u16 auto_corr_max_cck; + u16 auto_corr_max_cck_mrc; + u16 auto_corr_min_cck; + u16 auto_corr_min_cck_mrc; +}; + /** * struct iwl_hw_params * @max_txq_num: Max # Tx queues supported @@ -576,6 +599,7 @@ struct iwl4965_ibss_seq { * @max_rxq_log: Log-base-2 of max_rxq_size * @max_stations: * @bcast_sta_id: + * @struct iwl_sensitivity_ranges: range of sensitivity values */ struct iwl_hw_params { u16 max_txq_num; @@ -590,6 +614,9 @@ struct iwl_hw_params { u32 max_pkt_size; u8 max_stations; u8 bcast_sta_id; +#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB + const struct iwl_sensitivity_ranges *sens; +#endif }; #define HT_SHORT_GI_20MHZ_ONLY (1 << 0) @@ -732,9 +759,6 @@ extern void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, extern void iwl4965_set_rxon_chain(struct iwl_priv *priv); extern int iwl4965_alive_notify(struct iwl_priv *priv); extern void iwl4965_update_rate_scaling(struct iwl_priv *priv, u8 mode); -extern void iwl4965_chain_noise_reset(struct iwl_priv *priv); -extern void iwl4965_init_sensitivity(struct iwl_priv *priv, u8 flags, - u8 force); extern void iwl4965_rf_kill_ct_config(struct iwl_priv *priv); extern void iwl4965_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, @@ -818,23 +842,8 @@ struct iwl4965_lq_mngr { #define MAX_FA_CCK 50 #define MIN_FA_CCK 5 -#define NRG_MIN_CCK 97 -#define NRG_MAX_CCK 0 - -#define AUTO_CORR_MIN_OFDM 85 -#define AUTO_CORR_MIN_OFDM_MRC 170 -#define AUTO_CORR_MIN_OFDM_X1 105 -#define AUTO_CORR_MIN_OFDM_MRC_X1 220 -#define AUTO_CORR_MAX_OFDM 120 -#define AUTO_CORR_MAX_OFDM_MRC 210 -#define AUTO_CORR_MAX_OFDM_X1 140 -#define AUTO_CORR_MAX_OFDM_MRC_X1 270 #define AUTO_CORR_STEP_OFDM 1 -#define AUTO_CORR_MIN_CCK (125) -#define AUTO_CORR_MAX_CCK (200) -#define AUTO_CORR_MIN_CCK_MRC 200 -#define AUTO_CORR_MAX_CCK_MRC 400 #define AUTO_CORR_STEP_CCK 3 #define AUTO_CORR_MAX_TH_CCK 160 @@ -865,11 +874,6 @@ enum iwl4965_chain_noise_state { IWL_CHAIN_NOISE_CALIBRATED = 2, }; -enum iwl4965_sensitivity_state { - IWL_SENS_CALIB_ALLOWED = 0, - IWL_SENS_CALIB_NEED_REINIT = 1, -}; - enum iwl4965_calib_enabled_state { IWL_CALIB_DISABLED = 0, /* must be 0 */ IWL_CALIB_ENABLED = 1, @@ -884,8 +888,9 @@ struct statistics_general_data { u32 beacon_energy_c; }; +#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB /* Sensitivity calib data */ -struct iwl4965_sensitivity_data { +struct iwl_sensitivity_data { u32 auto_corr_ofdm; u32 auto_corr_ofdm_mrc; u32 auto_corr_ofdm_x1; @@ -909,12 +914,10 @@ struct iwl4965_sensitivity_data { s32 nrg_auto_corr_silence_diff; u32 num_in_cck_no_fa; u32 nrg_th_ofdm; - - u8 state; }; /* Chain noise (differential Rx gain) calib data */ -struct iwl4965_chain_noise_data { +struct iwl_chain_noise_data { u8 state; u16 beacon_count; u32 chain_noise_a; @@ -927,6 +930,7 @@ struct iwl4965_chain_noise_data { u8 delta_gain_code[NUM_RX_CHAINS]; u8 radio_write; }; +#endif /* CONFIG_IWLWIFI_RUN_TIME_CALIB */ #define EEPROM_SEM_TIMEOUT 10 /* milliseconds */ #define EEPROM_SEM_RETRY_LIMIT 1000 /* number of attempts (not time) */ @@ -1051,12 +1055,12 @@ struct iwl_priv { u8 assoc_station_added; u8 use_ant_b_for_management_frame; /* Tx antenna selection */ u8 valid_antenna; /* Bit mask of antennas actually connected */ -#ifdef CONFIG_IWL4965_SENSITIVITY - struct iwl4965_sensitivity_data sensitivity_data; - struct iwl4965_chain_noise_data chain_noise_data; u8 start_calib; +#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB + struct iwl_sensitivity_data sensitivity_data; + struct iwl_chain_noise_data chain_noise_data; __le16 sensitivity_tbl[HD_TABLE_SIZE]; -#endif /*CONFIG_IWL4965_SENSITIVITY*/ +#endif /*CONFIG_IWLWIFI_RUN_TIME_CALIB*/ #ifdef CONFIG_IWL4965_HT struct iwl_ht_info current_ht_config; @@ -1206,7 +1210,7 @@ struct iwl_priv { #endif /* CONFIG_IWLWIFI_DEBUG */ struct work_struct txpower_work; -#ifdef CONFIG_IWL4965_SENSITIVITY +#ifdef CONFIG_IWL4965_RUN_TIME_CALIB struct work_struct sensitivity_work; #endif struct timer_list statistics_periodic; diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c new file mode 100644 index 00000000000..16213b05ed9 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -0,0 +1,778 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Tomas Winkler + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#include +#include + +#include "iwl-4965.h" +#include "iwl-core.h" +#include "iwl-calib.h" +#include "iwl-eeprom.h" + +/* "false alarms" are signals that our DSP tries to lock onto, + * but then determines that they are either noise, or transmissions + * from a distant wireless network (also "noise", really) that get + * "stepped on" by stronger transmissions within our own network. + * This algorithm attempts to set a sensitivity level that is high + * enough to receive all of our own network traffic, but not so + * high that our DSP gets too busy trying to lock onto non-network + * activity/noise. */ +static int iwl_sens_energy_cck(struct iwl_priv *priv, + u32 norm_fa, + u32 rx_enable_time, + struct statistics_general_data *rx_info) +{ + u32 max_nrg_cck = 0; + int i = 0; + u8 max_silence_rssi = 0; + u32 silence_ref = 0; + u8 silence_rssi_a = 0; + u8 silence_rssi_b = 0; + u8 silence_rssi_c = 0; + u32 val; + + /* "false_alarms" values below are cross-multiplications to assess the + * numbers of false alarms within the measured period of actual Rx + * (Rx is off when we're txing), vs the min/max expected false alarms + * (some should be expected if rx is sensitive enough) in a + * hypothetical listening period of 200 time units (TU), 204.8 msec: + * + * MIN_FA/fixed-time < false_alarms/actual-rx-time < MAX_FA/beacon-time + * + * */ + u32 false_alarms = norm_fa * 200 * 1024; + u32 max_false_alarms = MAX_FA_CCK * rx_enable_time; + u32 min_false_alarms = MIN_FA_CCK * rx_enable_time; + struct iwl_sensitivity_data *data = NULL; + const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens; + + data = &(priv->sensitivity_data); + + data->nrg_auto_corr_silence_diff = 0; + + /* Find max silence rssi among all 3 receivers. + * This is background noise, which may include transmissions from other + * networks, measured during silence before our network's beacon */ + silence_rssi_a = (u8)((rx_info->beacon_silence_rssi_a & + ALL_BAND_FILTER) >> 8); + silence_rssi_b = (u8)((rx_info->beacon_silence_rssi_b & + ALL_BAND_FILTER) >> 8); + silence_rssi_c = (u8)((rx_info->beacon_silence_rssi_c & + ALL_BAND_FILTER) >> 8); + + val = max(silence_rssi_b, silence_rssi_c); + max_silence_rssi = max(silence_rssi_a, (u8) val); + + /* Store silence rssi in 20-beacon history table */ + data->nrg_silence_rssi[data->nrg_silence_idx] = max_silence_rssi; + data->nrg_silence_idx++; + if (data->nrg_silence_idx >= NRG_NUM_PREV_STAT_L) + data->nrg_silence_idx = 0; + + /* Find max silence rssi across 20 beacon history */ + for (i = 0; i < NRG_NUM_PREV_STAT_L; i++) { + val = data->nrg_silence_rssi[i]; + silence_ref = max(silence_ref, val); + } + IWL_DEBUG_CALIB("silence a %u, b %u, c %u, 20-bcn max %u\n", + silence_rssi_a, silence_rssi_b, silence_rssi_c, + silence_ref); + + /* Find max rx energy (min value!) among all 3 receivers, + * measured during beacon frame. + * Save it in 10-beacon history table. */ + i = data->nrg_energy_idx; + val = min(rx_info->beacon_energy_b, rx_info->beacon_energy_c); + data->nrg_value[i] = min(rx_info->beacon_energy_a, val); + + data->nrg_energy_idx++; + if (data->nrg_energy_idx >= 10) + data->nrg_energy_idx = 0; + + /* Find min rx energy (max value) across 10 beacon history. + * This is the minimum signal level that we want to receive well. + * Add backoff (margin so we don't miss slightly lower energy frames). + * This establishes an upper bound (min value) for energy threshold. */ + max_nrg_cck = data->nrg_value[0]; + for (i = 1; i < 10; i++) + max_nrg_cck = (u32) max(max_nrg_cck, (data->nrg_value[i])); + max_nrg_cck += 6; + + IWL_DEBUG_CALIB("rx energy a %u, b %u, c %u, 10-bcn max/min %u\n", + rx_info->beacon_energy_a, rx_info->beacon_energy_b, + rx_info->beacon_energy_c, max_nrg_cck - 6); + + /* Count number of consecutive beacons with fewer-than-desired + * false alarms. */ + if (false_alarms < min_false_alarms) + data->num_in_cck_no_fa++; + else + data->num_in_cck_no_fa = 0; + IWL_DEBUG_CALIB("consecutive bcns with few false alarms = %u\n", + data->num_in_cck_no_fa); + + /* If we got too many false alarms this time, reduce sensitivity */ + if ((false_alarms > max_false_alarms) && + (data->auto_corr_cck > AUTO_CORR_MAX_TH_CCK)) { + IWL_DEBUG_CALIB("norm FA %u > max FA %u\n", + false_alarms, max_false_alarms); + IWL_DEBUG_CALIB("... reducing sensitivity\n"); + data->nrg_curr_state = IWL_FA_TOO_MANY; + /* Store for "fewer than desired" on later beacon */ + data->nrg_silence_ref = silence_ref; + + /* increase energy threshold (reduce nrg value) + * to decrease sensitivity */ + if (data->nrg_th_cck > + (ranges->max_nrg_cck + NRG_STEP_CCK)) + data->nrg_th_cck = data->nrg_th_cck + - NRG_STEP_CCK; + else + data->nrg_th_cck = ranges->max_nrg_cck; + /* Else if we got fewer than desired, increase sensitivity */ + } else if (false_alarms < min_false_alarms) { + data->nrg_curr_state = IWL_FA_TOO_FEW; + + /* Compare silence level with silence level for most recent + * healthy number or too many false alarms */ + data->nrg_auto_corr_silence_diff = (s32)data->nrg_silence_ref - + (s32)silence_ref; + + IWL_DEBUG_CALIB("norm FA %u < min FA %u, silence diff %d\n", + false_alarms, min_false_alarms, + data->nrg_auto_corr_silence_diff); + + /* Increase value to increase sensitivity, but only if: + * 1a) previous beacon did *not* have *too many* false alarms + * 1b) AND there's a significant difference in Rx levels + * from a previous beacon with too many, or healthy # FAs + * OR 2) We've seen a lot of beacons (100) with too few + * false alarms */ + if ((data->nrg_prev_state != IWL_FA_TOO_MANY) && + ((data->nrg_auto_corr_silence_diff > NRG_DIFF) || + (data->num_in_cck_no_fa > MAX_NUMBER_CCK_NO_FA))) { + + IWL_DEBUG_CALIB("... increasing sensitivity\n"); + /* Increase nrg value to increase sensitivity */ + val = data->nrg_th_cck + NRG_STEP_CCK; + data->nrg_th_cck = min((u32)ranges->min_nrg_cck, val); + } else { + IWL_DEBUG_CALIB("... but not changing sensitivity\n"); + } + + /* Else we got a healthy number of false alarms, keep status quo */ + } else { + IWL_DEBUG_CALIB(" FA in safe zone\n"); + data->nrg_curr_state = IWL_FA_GOOD_RANGE; + + /* Store for use in "fewer than desired" with later beacon */ + data->nrg_silence_ref = silence_ref; + + /* If previous beacon had too many false alarms, + * give it some extra margin by reducing sensitivity again + * (but don't go below measured energy of desired Rx) */ + if (IWL_FA_TOO_MANY == data->nrg_prev_state) { + IWL_DEBUG_CALIB("... increasing margin\n"); + if (data->nrg_th_cck > (max_nrg_cck + NRG_MARGIN)) + data->nrg_th_cck -= NRG_MARGIN; + else + data->nrg_th_cck = max_nrg_cck; + } + } + + /* Make sure the energy threshold does not go above the measured + * energy of the desired Rx signals (reduced by backoff margin), + * or else we might start missing Rx frames. + * Lower value is higher energy, so we use max()! + */ + data->nrg_th_cck = max(max_nrg_cck, data->nrg_th_cck); + IWL_DEBUG_CALIB("new nrg_th_cck %u\n", data->nrg_th_cck); + + data->nrg_prev_state = data->nrg_curr_state; + + /* Auto-correlation CCK algorithm */ + if (false_alarms > min_false_alarms) { + + /* increase auto_corr values to decrease sensitivity + * so the DSP won't be disturbed by the noise + */ + if (data->auto_corr_cck < AUTO_CORR_MAX_TH_CCK) + data->auto_corr_cck = AUTO_CORR_MAX_TH_CCK + 1; + else { + val = data->auto_corr_cck + AUTO_CORR_STEP_CCK; + data->auto_corr_cck = + min((u32)ranges->auto_corr_max_cck, val); + } + val = data->auto_corr_cck_mrc + AUTO_CORR_STEP_CCK; + data->auto_corr_cck_mrc = + min((u32)ranges->auto_corr_max_cck_mrc, val); + } else if ((false_alarms < min_false_alarms) && + ((data->nrg_auto_corr_silence_diff > NRG_DIFF) || + (data->num_in_cck_no_fa > MAX_NUMBER_CCK_NO_FA))) { + + /* Decrease auto_corr values to increase sensitivity */ + val = data->auto_corr_cck - AUTO_CORR_STEP_CCK; + data->auto_corr_cck = + max((u32)ranges->auto_corr_min_cck, val); + val = data->auto_corr_cck_mrc - AUTO_CORR_STEP_CCK; + data->auto_corr_cck_mrc = + max((u32)ranges->auto_corr_min_cck_mrc, val); + } + + return 0; +} + + +static int iwl_sens_auto_corr_ofdm(struct iwl_priv *priv, + u32 norm_fa, + u32 rx_enable_time) +{ + u32 val; + u32 false_alarms = norm_fa * 200 * 1024; + u32 max_false_alarms = MAX_FA_OFDM * rx_enable_time; + u32 min_false_alarms = MIN_FA_OFDM * rx_enable_time; + struct iwl_sensitivity_data *data = NULL; + const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens; + + data = &(priv->sensitivity_data); + + /* If we got too many false alarms this time, reduce sensitivity */ + if (false_alarms > max_false_alarms) { + + IWL_DEBUG_CALIB("norm FA %u > max FA %u)\n", + false_alarms, max_false_alarms); + + val = data->auto_corr_ofdm + AUTO_CORR_STEP_OFDM; + data->auto_corr_ofdm = + min((u32)ranges->auto_corr_max_ofdm, val); + + val = data->auto_corr_ofdm_mrc + AUTO_CORR_STEP_OFDM; + data->auto_corr_ofdm_mrc = + min((u32)ranges->auto_corr_max_ofdm_mrc, val); + + val = data->auto_corr_ofdm_x1 + AUTO_CORR_STEP_OFDM; + data->auto_corr_ofdm_x1 = + min((u32)ranges->auto_corr_max_ofdm_x1, val); + + val = data->auto_corr_ofdm_mrc_x1 + AUTO_CORR_STEP_OFDM; + data->auto_corr_ofdm_mrc_x1 = + min((u32)ranges->auto_corr_max_ofdm_mrc_x1, val); + } + + /* Else if we got fewer than desired, increase sensitivity */ + else if (false_alarms < min_false_alarms) { + + IWL_DEBUG_CALIB("norm FA %u < min FA %u\n", + false_alarms, min_false_alarms); + + val = data->auto_corr_ofdm - AUTO_CORR_STEP_OFDM; + data->auto_corr_ofdm = + max((u32)ranges->auto_corr_min_ofdm, val); + + val = data->auto_corr_ofdm_mrc - AUTO_CORR_STEP_OFDM; + data->auto_corr_ofdm_mrc = + max((u32)ranges->auto_corr_min_ofdm_mrc, val); + + val = data->auto_corr_ofdm_x1 - AUTO_CORR_STEP_OFDM; + data->auto_corr_ofdm_x1 = + max((u32)ranges->auto_corr_min_ofdm_x1, val); + + val = data->auto_corr_ofdm_mrc_x1 - AUTO_CORR_STEP_OFDM; + data->auto_corr_ofdm_mrc_x1 = + max((u32)ranges->auto_corr_min_ofdm_mrc_x1, val); + } else { + IWL_DEBUG_CALIB("min FA %u < norm FA %u < max FA %u OK\n", + min_false_alarms, false_alarms, max_false_alarms); + } + return 0; +} + +/* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */ +static int iwl_sensitivity_write(struct iwl_priv *priv) +{ + int ret = 0; + struct iwl_sensitivity_cmd cmd ; + struct iwl_sensitivity_data *data = NULL; + struct iwl_host_cmd cmd_out = { + .id = SENSITIVITY_CMD, + .len = sizeof(struct iwl_sensitivity_cmd), + .meta.flags = CMD_ASYNC, + .data = &cmd, + }; + + data = &(priv->sensitivity_data); + + memset(&cmd, 0, sizeof(cmd)); + + cmd.table[HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX] = + cpu_to_le16((u16)data->auto_corr_ofdm); + cmd.table[HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX] = + cpu_to_le16((u16)data->auto_corr_ofdm_mrc); + cmd.table[HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX] = + cpu_to_le16((u16)data->auto_corr_ofdm_x1); + cmd.table[HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX] = + cpu_to_le16((u16)data->auto_corr_ofdm_mrc_x1); + + cmd.table[HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX] = + cpu_to_le16((u16)data->auto_corr_cck); + cmd.table[HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX] = + cpu_to_le16((u16)data->auto_corr_cck_mrc); + + cmd.table[HD_MIN_ENERGY_CCK_DET_INDEX] = + cpu_to_le16((u16)data->nrg_th_cck); + cmd.table[HD_MIN_ENERGY_OFDM_DET_INDEX] = + cpu_to_le16((u16)data->nrg_th_ofdm); + + cmd.table[HD_BARKER_CORR_TH_ADD_MIN_INDEX] = + __constant_cpu_to_le16(190); + cmd.table[HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX] = + __constant_cpu_to_le16(390); + cmd.table[HD_OFDM_ENERGY_TH_IN_INDEX] = + __constant_cpu_to_le16(62); + + IWL_DEBUG_CALIB("ofdm: ac %u mrc %u x1 %u mrc_x1 %u thresh %u\n", + data->auto_corr_ofdm, data->auto_corr_ofdm_mrc, + data->auto_corr_ofdm_x1, data->auto_corr_ofdm_mrc_x1, + data->nrg_th_ofdm); + + IWL_DEBUG_CALIB("cck: ac %u mrc %u thresh %u\n", + data->auto_corr_cck, data->auto_corr_cck_mrc, + data->nrg_th_cck); + + /* Update uCode's "work" table, and copy it to DSP */ + cmd.control = SENSITIVITY_CMD_CONTROL_WORK_TABLE; + + /* Don't send command to uCode if nothing has changed */ + if (!memcmp(&cmd.table[0], &(priv->sensitivity_tbl[0]), + sizeof(u16)*HD_TABLE_SIZE)) { + IWL_DEBUG_CALIB("No change in SENSITIVITY_CMD\n"); + return 0; + } + + /* Copy table for comparison next time */ + memcpy(&(priv->sensitivity_tbl[0]), &(cmd.table[0]), + sizeof(u16)*HD_TABLE_SIZE); + + ret = iwl_send_cmd(priv, &cmd_out); + if (ret) + IWL_ERROR("SENSITIVITY_CMD failed\n"); + + return ret; +} + +void iwl_init_sensitivity(struct iwl_priv *priv) +{ + int ret = 0; + int i; + struct iwl_sensitivity_data *data = NULL; + const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens; + + IWL_DEBUG_CALIB("Start iwl_init_sensitivity\n"); + + /* Clear driver's sensitivity algo data */ + data = &(priv->sensitivity_data); + + if (ranges == NULL) + /* can happen if IWLWIFI_RUN_TIME_CALIB is selected + * but no IWLXXXX_RUN_TIME_CALIB for specific is selected */ + return; + + memset(data, 0, sizeof(struct iwl_sensitivity_data)); + + data->num_in_cck_no_fa = 0; + data->nrg_curr_state = IWL_FA_TOO_MANY; + data->nrg_prev_state = IWL_FA_TOO_MANY; + data->nrg_silence_ref = 0; + data->nrg_silence_idx = 0; + data->nrg_energy_idx = 0; + + for (i = 0; i < 10; i++) + data->nrg_value[i] = 0; + + for (i = 0; i < NRG_NUM_PREV_STAT_L; i++) + data->nrg_silence_rssi[i] = 0; + + data->auto_corr_ofdm = 90; + data->auto_corr_ofdm_mrc = ranges->auto_corr_min_ofdm_mrc; + data->auto_corr_ofdm_x1 = ranges->auto_corr_min_ofdm_x1; + data->auto_corr_ofdm_mrc_x1 = ranges->auto_corr_min_ofdm_mrc_x1; + data->auto_corr_cck = AUTO_CORR_CCK_MIN_VAL_DEF; + data->auto_corr_cck_mrc = ranges->auto_corr_min_cck_mrc; + data->nrg_th_cck = ranges->nrg_th_cck; + data->nrg_th_ofdm = ranges->nrg_th_ofdm; + + data->last_bad_plcp_cnt_ofdm = 0; + data->last_fa_cnt_ofdm = 0; + data->last_bad_plcp_cnt_cck = 0; + data->last_fa_cnt_cck = 0; + + ret |= iwl_sensitivity_write(priv); + IWL_DEBUG_CALIB("<rx.general); + struct statistics_rx *statistics = &(resp->rx); + unsigned long flags; + struct statistics_general_data statis; + + data = &(priv->sensitivity_data); + + if (!iwl_is_associated(priv)) { + IWL_DEBUG_CALIB("<< - not associated\n"); + return; + } + + spin_lock_irqsave(&priv->lock, flags); + if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) { + IWL_DEBUG_CALIB("<< invalid data.\n"); + spin_unlock_irqrestore(&priv->lock, flags); + return; + } + + /* Extract Statistics: */ + rx_enable_time = le32_to_cpu(rx_info->channel_load); + fa_cck = le32_to_cpu(statistics->cck.false_alarm_cnt); + fa_ofdm = le32_to_cpu(statistics->ofdm.false_alarm_cnt); + bad_plcp_cck = le32_to_cpu(statistics->cck.plcp_err); + bad_plcp_ofdm = le32_to_cpu(statistics->ofdm.plcp_err); + + statis.beacon_silence_rssi_a = + le32_to_cpu(statistics->general.beacon_silence_rssi_a); + statis.beacon_silence_rssi_b = + le32_to_cpu(statistics->general.beacon_silence_rssi_b); + statis.beacon_silence_rssi_c = + le32_to_cpu(statistics->general.beacon_silence_rssi_c); + statis.beacon_energy_a = + le32_to_cpu(statistics->general.beacon_energy_a); + statis.beacon_energy_b = + le32_to_cpu(statistics->general.beacon_energy_b); + statis.beacon_energy_c = + le32_to_cpu(statistics->general.beacon_energy_c); + + spin_unlock_irqrestore(&priv->lock, flags); + + IWL_DEBUG_CALIB("rx_enable_time = %u usecs\n", rx_enable_time); + + if (!rx_enable_time) { + IWL_DEBUG_CALIB("<< RX Enable Time == 0! \n"); + return; + } + + /* These statistics increase monotonically, and do not reset + * at each beacon. Calculate difference from last value, or just + * use the new statistics value if it has reset or wrapped around. */ + if (data->last_bad_plcp_cnt_cck > bad_plcp_cck) + data->last_bad_plcp_cnt_cck = bad_plcp_cck; + else { + bad_plcp_cck -= data->last_bad_plcp_cnt_cck; + data->last_bad_plcp_cnt_cck += bad_plcp_cck; + } + + if (data->last_bad_plcp_cnt_ofdm > bad_plcp_ofdm) + data->last_bad_plcp_cnt_ofdm = bad_plcp_ofdm; + else { + bad_plcp_ofdm -= data->last_bad_plcp_cnt_ofdm; + data->last_bad_plcp_cnt_ofdm += bad_plcp_ofdm; + } + + if (data->last_fa_cnt_ofdm > fa_ofdm) + data->last_fa_cnt_ofdm = fa_ofdm; + else { + fa_ofdm -= data->last_fa_cnt_ofdm; + data->last_fa_cnt_ofdm += fa_ofdm; + } + + if (data->last_fa_cnt_cck > fa_cck) + data->last_fa_cnt_cck = fa_cck; + else { + fa_cck -= data->last_fa_cnt_cck; + data->last_fa_cnt_cck += fa_cck; + } + + /* Total aborted signal locks */ + norm_fa_ofdm = fa_ofdm + bad_plcp_ofdm; + norm_fa_cck = fa_cck + bad_plcp_cck; + + IWL_DEBUG_CALIB("cck: fa %u badp %u ofdm: fa %u badp %u\n", fa_cck, + bad_plcp_cck, fa_ofdm, bad_plcp_ofdm); + + iwl_sens_auto_corr_ofdm(priv, norm_fa_ofdm, rx_enable_time); + iwl_sens_energy_cck(priv, norm_fa_cck, rx_enable_time, &statis); + iwl_sensitivity_write(priv); + + return; +} +EXPORT_SYMBOL(iwl_sensitivity_calibration); + +/* + * Accumulate 20 beacons of signal and noise statistics for each of + * 3 receivers/antennas/rx-chains, then figure out: + * 1) Which antennas are connected. + * 2) Differential rx gain settings to balance the 3 receivers. + */ +void iwl_chain_noise_calibration(struct iwl_priv *priv, + struct iwl4965_notif_statistics *stat_resp) +{ + struct iwl_chain_noise_data *data = NULL; + + u32 chain_noise_a; + u32 chain_noise_b; + u32 chain_noise_c; + u32 chain_sig_a; + u32 chain_sig_b; + u32 chain_sig_c; + u32 average_sig[NUM_RX_CHAINS] = {INITIALIZATION_VALUE}; + u32 average_noise[NUM_RX_CHAINS] = {INITIALIZATION_VALUE}; + u32 max_average_sig; + u16 max_average_sig_antenna_i; + u32 min_average_noise = MIN_AVERAGE_NOISE_MAX_VALUE; + u16 min_average_noise_antenna_i = INITIALIZATION_VALUE; + u16 i = 0; + u16 rxon_chnum = INITIALIZATION_VALUE; + u16 stat_chnum = INITIALIZATION_VALUE; + u8 rxon_band24; + u8 stat_band24; + u32 active_chains = 0; + u8 num_tx_chains; + unsigned long flags; + struct statistics_rx_non_phy *rx_info = &(stat_resp->rx.general); + + data = &(priv->chain_noise_data); + + /* Accumulate just the first 20 beacons after the first association, + * then we're done forever. */ + if (data->state != IWL_CHAIN_NOISE_ACCUMULATE) { + if (data->state == IWL_CHAIN_NOISE_ALIVE) + IWL_DEBUG_CALIB("Wait for noise calib reset\n"); + return; + } + + spin_lock_irqsave(&priv->lock, flags); + if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) { + IWL_DEBUG_CALIB(" << Interference data unavailable\n"); + spin_unlock_irqrestore(&priv->lock, flags); + return; + } + + rxon_band24 = !!(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK); + rxon_chnum = le16_to_cpu(priv->staging_rxon.channel); + stat_band24 = !!(stat_resp->flag & STATISTICS_REPLY_FLG_BAND_24G_MSK); + stat_chnum = le32_to_cpu(stat_resp->flag) >> 16; + + /* Make sure we accumulate data for just the associated channel + * (even if scanning). */ + if ((rxon_chnum != stat_chnum) || (rxon_band24 != stat_band24)) { + IWL_DEBUG_CALIB("Stats not from chan=%d, band24=%d\n", + rxon_chnum, rxon_band24); + spin_unlock_irqrestore(&priv->lock, flags); + return; + } + + /* Accumulate beacon statistics values across 20 beacons */ + chain_noise_a = le32_to_cpu(rx_info->beacon_silence_rssi_a) & + IN_BAND_FILTER; + chain_noise_b = le32_to_cpu(rx_info->beacon_silence_rssi_b) & + IN_BAND_FILTER; + chain_noise_c = le32_to_cpu(rx_info->beacon_silence_rssi_c) & + IN_BAND_FILTER; + + chain_sig_a = le32_to_cpu(rx_info->beacon_rssi_a) & IN_BAND_FILTER; + chain_sig_b = le32_to_cpu(rx_info->beacon_rssi_b) & IN_BAND_FILTER; + chain_sig_c = le32_to_cpu(rx_info->beacon_rssi_c) & IN_BAND_FILTER; + + spin_unlock_irqrestore(&priv->lock, flags); + + data->beacon_count++; + + data->chain_noise_a = (chain_noise_a + data->chain_noise_a); + data->chain_noise_b = (chain_noise_b + data->chain_noise_b); + data->chain_noise_c = (chain_noise_c + data->chain_noise_c); + + data->chain_signal_a = (chain_sig_a + data->chain_signal_a); + data->chain_signal_b = (chain_sig_b + data->chain_signal_b); + data->chain_signal_c = (chain_sig_c + data->chain_signal_c); + + IWL_DEBUG_CALIB("chan=%d, band24=%d, beacon=%d\n", + rxon_chnum, rxon_band24, data->beacon_count); + IWL_DEBUG_CALIB("chain_sig: a %d b %d c %d\n", + chain_sig_a, chain_sig_b, chain_sig_c); + IWL_DEBUG_CALIB("chain_noise: a %d b %d c %d\n", + chain_noise_a, chain_noise_b, chain_noise_c); + + /* If this is the 20th beacon, determine: + * 1) Disconnected antennas (using signal strengths) + * 2) Differential gain (using silence noise) to balance receivers */ + if (data->beacon_count != CAL_NUM_OF_BEACONS) + return; + + /* Analyze signal for disconnected antenna */ + average_sig[0] = (data->chain_signal_a) / CAL_NUM_OF_BEACONS; + average_sig[1] = (data->chain_signal_b) / CAL_NUM_OF_BEACONS; + average_sig[2] = (data->chain_signal_c) / CAL_NUM_OF_BEACONS; + + if (average_sig[0] >= average_sig[1]) { + max_average_sig = average_sig[0]; + max_average_sig_antenna_i = 0; + active_chains = (1 << max_average_sig_antenna_i); + } else { + max_average_sig = average_sig[1]; + max_average_sig_antenna_i = 1; + active_chains = (1 << max_average_sig_antenna_i); + } + + if (average_sig[2] >= max_average_sig) { + max_average_sig = average_sig[2]; + max_average_sig_antenna_i = 2; + active_chains = (1 << max_average_sig_antenna_i); + } + + IWL_DEBUG_CALIB("average_sig: a %d b %d c %d\n", + average_sig[0], average_sig[1], average_sig[2]); + IWL_DEBUG_CALIB("max_average_sig = %d, antenna %d\n", + max_average_sig, max_average_sig_antenna_i); + + /* Compare signal strengths for all 3 receivers. */ + for (i = 0; i < NUM_RX_CHAINS; i++) { + if (i != max_average_sig_antenna_i) { + s32 rssi_delta = (max_average_sig - average_sig[i]); + + /* If signal is very weak, compared with + * strongest, mark it as disconnected. */ + if (rssi_delta > MAXIMUM_ALLOWED_PATHLOSS) + data->disconn_array[i] = 1; + else + active_chains |= (1 << i); + IWL_DEBUG_CALIB("i = %d rssiDelta = %d " + "disconn_array[i] = %d\n", + i, rssi_delta, data->disconn_array[i]); + } + } + + num_tx_chains = 0; + for (i = 0; i < NUM_RX_CHAINS; i++) { + /* loops on all the bits of + * priv->hw_setting.valid_tx_ant */ + u8 ant_msk = (1 << i); + if (!(priv->hw_params.valid_tx_ant & ant_msk)) + continue; + + num_tx_chains++; + if (data->disconn_array[i] == 0) + /* there is a Tx antenna connected */ + break; + if (num_tx_chains == priv->hw_params.tx_chains_num && + data->disconn_array[i]) { + /* This is the last TX antenna and is also + * disconnected connect it anyway */ + data->disconn_array[i] = 0; + active_chains |= ant_msk; + IWL_DEBUG_CALIB("All Tx chains are disconnected W/A - " + "declare %d as connected\n", i); + break; + } + } + + IWL_DEBUG_CALIB("active_chains (bitwise) = 0x%x\n", + active_chains); + + /* Save for use within RXON, TX, SCAN commands, etc. */ + priv->valid_antenna = active_chains; + + /* Analyze noise for rx balance */ + average_noise[0] = ((data->chain_noise_a)/CAL_NUM_OF_BEACONS); + average_noise[1] = ((data->chain_noise_b)/CAL_NUM_OF_BEACONS); + average_noise[2] = ((data->chain_noise_c)/CAL_NUM_OF_BEACONS); + + for (i = 0; i < NUM_RX_CHAINS; i++) { + if (!(data->disconn_array[i]) && + (average_noise[i] <= min_average_noise)) { + /* This means that chain i is active and has + * lower noise values so far: */ + min_average_noise = average_noise[i]; + min_average_noise_antenna_i = i; + } + } + + IWL_DEBUG_CALIB("average_noise: a %d b %d c %d\n", + average_noise[0], average_noise[1], + average_noise[2]); + + IWL_DEBUG_CALIB("min_average_noise = %d, antenna %d\n", + min_average_noise, min_average_noise_antenna_i); + + priv->cfg->ops->utils->gain_computation(priv, average_noise, + min_average_noise_antenna_i, min_average_noise); +} +EXPORT_SYMBOL(iwl_chain_noise_calibration); + diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.h b/drivers/net/wireless/iwlwifi/iwl-calib.h new file mode 100644 index 00000000000..c3a3db31199 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-calib.h @@ -0,0 +1,104 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Tomas Winkler + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ +#ifndef __iwl_calib_h__ +#define __iwl_calib_h__ + +#include +#include +#include + +#include +#include "iwl-eeprom.h" +#include "iwl-core.h" +#include "iwl-4965.h" + +#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB +void iwl_chain_noise_calibration(struct iwl_priv *priv, + struct iwl4965_notif_statistics *stat_resp); +void iwl_sensitivity_calibration(struct iwl_priv *priv, + struct iwl4965_notif_statistics *resp); + +void iwl_init_sensitivity(struct iwl_priv *priv); + +static inline void iwl_chain_noise_reset(struct iwl_priv *priv) +{ + if (priv->cfg->ops->utils->chain_noise_reset) + priv->cfg->ops->utils->chain_noise_reset(priv); +} +#else +static inline void iwl_chain_noise_calibration(struct iwl_priv *priv, + struct iwl4965_notif_statistics *stat_resp) +{ +} +static inline void iwl_sensitivity_calibration(struct iwl_priv *priv, + struct iwl4965_notif_statistics *resp) +{ +} +static inline void iwl_init_sensitivity(struct iwl_priv *priv) +{ +} +static inline void iwl_chain_noise_reset(struct iwl_priv *priv) +{ +} +#endif + +#endif /* __iwl_calib_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 7193d97630d..dcbd411a476 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -87,6 +87,13 @@ struct iwl_hcmd_ops { }; struct iwl_hcmd_utils_ops { int (*enqueue_hcmd)(struct iwl_priv *priv, struct iwl_host_cmd *cmd); +#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB + void (*gain_computation)(struct iwl_priv *priv, + u32 *average_noise, + u16 min_average_noise_antennat_i, + u32 min_average_noise); + void (*chain_noise_reset)(struct iwl_priv *priv); +#endif }; struct iwl_lib_ops { diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 883b42f7e99..8a68ff4323d 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -51,6 +51,7 @@ #include "iwl-io.h" #include "iwl-helpers.h" #include "iwl-sta.h" +#include "iwl-calib.h" static int iwl4965_tx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl4965_tx_queue *txq); @@ -795,14 +796,6 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) /* station table will be cleared */ priv->assoc_station_added = 0; -#ifdef CONFIG_IWL4965_SENSITIVITY - priv->sensitivity_data.state = IWL_SENS_CALIB_NEED_REINIT; - if (!priv->error_recovering) - priv->start_calib = 0; - - iwl4965_init_sensitivity(priv, CMD_ASYNC, 1); -#endif /* CONFIG_IWL4965_SENSITIVITY */ - /* If we are currently associated and the new config requires * an RXON_ASSOC and the new config wants the associated mask enabled, * we must clear the associated from the active configuration @@ -846,13 +839,10 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) iwlcore_clear_stations_table(priv); -#ifdef CONFIG_IWL4965_SENSITIVITY if (!priv->error_recovering) priv->start_calib = 0; - priv->sensitivity_data.state = IWL_SENS_CALIB_NEED_REINIT; - iwl4965_init_sensitivity(priv, CMD_ASYNC, 1); -#endif /* CONFIG_IWL4965_SENSITIVITY */ + iwl_init_sensitivity(priv); memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); @@ -6040,11 +6030,9 @@ static void iwl4965_post_associate(struct iwl_priv *priv) iwl4965_sequence_reset(priv); -#ifdef CONFIG_IWL4965_SENSITIVITY /* Enable Rx differential gain and sensitivity calibrations */ - iwl4965_chain_noise_reset(priv); + iwl_chain_noise_reset(priv); priv->start_calib = 1; -#endif /* CONFIG_IWL4965_SENSITIVITY */ if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) priv->assoc_station_added = 1; -- cgit v1.2.3-70-g09d2 From 947b13a7ccd31d8adbf41f466d6a1c770461596a Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 16 Apr 2008 16:34:48 -0700 Subject: iwlwifi: move find station to iwl-sta.c This patch move iwl_find_station into iwl-sta.c file Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 4 +-- drivers/net/wireless/iwlwifi/iwl-4965.c | 40 +++-------------------------- drivers/net/wireless/iwlwifi/iwl-4965.h | 4 +-- drivers/net/wireless/iwlwifi/iwl-sta.c | 35 +++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl4965-base.c | 10 ++++---- 5 files changed, 48 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index b608e1ca8b4..557912af1ff 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -2190,7 +2190,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && !lq_sta->ibss_sta_added) { - u8 sta_id = iwl4965_hw_find_station(priv, hdr->addr1); + u8 sta_id = iwl_find_station(priv, hdr->addr1); DECLARE_MAC_BUF(mac); if (sta_id == IWL_INVALID_STATION) { @@ -2268,7 +2268,7 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, lq_sta->ibss_sta_added = 0; if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { - u8 sta_id = iwl4965_hw_find_station(priv, sta->addr); + u8 sta_id = iwl_find_station(priv, sta->addr); DECLARE_MAC_BUF(mac); /* for IBSS the call are from tasklet */ diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index be4cc5ffa74..f318c50a1a8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -492,38 +492,6 @@ int iwl4965_hw_rxq_stop(struct iwl_priv *priv) return 0; } -u8 iwl4965_hw_find_station(struct iwl_priv *priv, const u8 *addr) -{ - int i; - int start = 0; - int ret = IWL_INVALID_STATION; - unsigned long flags; - DECLARE_MAC_BUF(mac); - - if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) || - (priv->iw_mode == IEEE80211_IF_TYPE_AP)) - start = IWL_STA_ID; - - if (is_broadcast_ether_addr(addr)) - return priv->hw_params.bcast_sta_id; - - spin_lock_irqsave(&priv->sta_lock, flags); - for (i = start; i < priv->hw_params.max_stations; i++) - if ((priv->stations[i].used) && - (!compare_ether_addr - (priv->stations[i].sta.sta.addr, addr))) { - ret = i; - goto out; - } - - IWL_DEBUG_ASSOC_LIMIT("can not find STA %s total %d\n", - print_mac(mac, addr), priv->num_stations); - - out: - spin_unlock_irqrestore(&priv->sta_lock, flags); - return ret; -} - static int iwl4965_nic_set_pwr_src(struct iwl_priv *priv, int pwr_max) { int ret; @@ -3125,7 +3093,7 @@ static void iwl4965_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) static void iwl4965_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr) { /* FIXME: need locking over ps_status ??? */ - u8 sta_id = iwl4965_hw_find_station(priv, addr); + u8 sta_id = iwl_find_station(priv, addr); if (sta_id != IWL_INVALID_STATION) { u8 sta_awake = priv->stations[sta_id]. @@ -4112,7 +4080,7 @@ static int iwl4965_mac_ht_tx_agg_start(struct ieee80211_hw *hw, const u8 *da, IWL_WARNING("%s on da = %s tid = %d\n", __func__, print_mac(mac, da), tid); - sta_id = iwl4965_hw_find_station(priv, da); + sta_id = iwl_find_station(priv, da); if (sta_id == IWL_INVALID_STATION) return -ENXIO; @@ -4171,7 +4139,7 @@ static int iwl4965_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, const u8 *da, else return -EINVAL; - sta_id = iwl4965_hw_find_station(priv, da); + sta_id = iwl_find_station(priv, da); if (sta_id == IWL_INVALID_STATION) return -ENXIO; @@ -4221,7 +4189,7 @@ int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, IWL_DEBUG_HT("A-MPDU action on da=%s tid=%d ", print_mac(mac, addr), tid); - sta_id = iwl4965_hw_find_station(priv, addr); + sta_id = iwl_find_station(priv, addr); switch (action) { case IEEE80211_AMPDU_RX_START: IWL_DEBUG_HT("start Rx\n"); diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h index d728dd837e9..b51243f4693 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965.h @@ -733,14 +733,14 @@ extern void iwl4965_disable_events(struct iwl_priv *priv); extern int iwl4965_get_temperature(const struct iwl_priv *priv); /** - * iwl4965_hw_find_station - Find station id for a given BSSID + * iwl_find_station - Find station id for a given BSSID * @bssid: MAC address of station ID to find * * NOTE: This should not be hardware specific but the code has * not yet been merged into a single common layer for managing the * station tables. */ -extern u8 iwl4965_hw_find_station(struct iwl_priv *priv, const u8 *bssid); +extern u8 iwl_find_station(struct iwl_priv *priv, const u8 *bssid); extern int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel); extern int iwl4965_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index); diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index e4fdfaa2b9b..fa463ce6399 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -28,6 +28,7 @@ *****************************************************************************/ #include +#include #include "iwl-eeprom.h" #include "iwl-4965.h" @@ -38,6 +39,40 @@ #include "iwl-4965.h" #include "iwl-sta.h" +u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr) +{ + int i; + int start = 0; + int ret = IWL_INVALID_STATION; + unsigned long flags; + DECLARE_MAC_BUF(mac); + + if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) || + (priv->iw_mode == IEEE80211_IF_TYPE_AP)) + start = IWL_STA_ID; + + if (is_broadcast_ether_addr(addr)) + return priv->hw_params.bcast_sta_id; + + spin_lock_irqsave(&priv->sta_lock, flags); + for (i = start; i < priv->hw_params.max_stations; i++) + if (priv->stations[i].used && + (!compare_ether_addr(priv->stations[i].sta.sta.addr, + addr))) { + ret = i; + goto out; + } + + IWL_DEBUG_ASSOC_LIMIT("can not find STA %s total %d\n", + print_mac(mac, addr), priv->num_stations); + + out: + spin_unlock_irqrestore(&priv->sta_lock, flags); + return ret; +} +EXPORT_SYMBOL(iwl_find_station); + + int iwl_get_free_ucode_key_index(struct iwl_priv *priv) { int i; diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 8a68ff4323d..c8cbf70600d 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -2076,7 +2076,7 @@ static int iwl4965_get_sta_id(struct iwl_priv *priv, /* If we are an AP, then find the station, or use BCAST */ case IEEE80211_IF_TYPE_AP: - sta_id = iwl4965_hw_find_station(priv, hdr->addr1); + sta_id = iwl_find_station(priv, hdr->addr1); if (sta_id != IWL_INVALID_STATION) return sta_id; return priv->hw_params.bcast_sta_id; @@ -2084,7 +2084,7 @@ static int iwl4965_get_sta_id(struct iwl_priv *priv, /* If this frame is going out to an IBSS network, find the station, * or create a new station table entry */ case IEEE80211_IF_TYPE_IBSS: - sta_id = iwl4965_hw_find_station(priv, hdr->addr1); + sta_id = iwl_find_station(priv, hdr->addr1); if (sta_id != IWL_INVALID_STATION) return sta_id; @@ -2778,7 +2778,7 @@ static inline int iwl4965_get_ra_sta_id(struct iwl_priv *priv, return IWL_AP_ID; else { u8 *da = ieee80211_get_DA(hdr); - return iwl4965_hw_find_station(priv, da); + return iwl_find_station(priv, da); } } @@ -6768,7 +6768,7 @@ static void iwl4965_mac_update_tkip_key(struct ieee80211_hw *hw, IWL_DEBUG_MAC80211("enter\n"); - sta_id = iwl4965_hw_find_station(priv, addr); + sta_id = iwl_find_station(priv, addr); if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_MAC80211("leave - %s not in station map.\n", print_mac(mac, addr)); @@ -6824,7 +6824,7 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, /* only support pairwise keys */ return -EOPNOTSUPP; - sta_id = iwl4965_hw_find_station(priv, addr); + sta_id = iwl_find_station(priv, addr); if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_MAC80211("leave - %s not in station map.\n", print_mac(mac, addr)); -- cgit v1.2.3-70-g09d2 From 6f4083aadd57e3da12fa4e67fcadaec23138a315 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 16 Apr 2008 16:34:49 -0700 Subject: iwlwifi: cleanup set_pwr_src This patch cleans up semantic of set_pwr_src set_pwr_src is now part of apm handlers group in iwlcore Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 27 ++++++++++++++++----------- drivers/net/wireless/iwlwifi/iwl-4965.h | 5 +++++ drivers/net/wireless/iwlwifi/iwl-core.h | 3 +++ drivers/net/wireless/iwlwifi/iwl-csr.h | 9 ++++----- 4 files changed, 28 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index f318c50a1a8..69a355bbb97 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -492,7 +492,7 @@ int iwl4965_hw_rxq_stop(struct iwl_priv *priv) return 0; } -static int iwl4965_nic_set_pwr_src(struct iwl_priv *priv, int pwr_max) +static int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src) { int ret; unsigned long flags; @@ -504,20 +504,21 @@ static int iwl4965_nic_set_pwr_src(struct iwl_priv *priv, int pwr_max) return ret; } - if (!pwr_max) { + if (src == IWL_PWR_SRC_VAUX) { u32 val; - ret = pci_read_config_dword(priv->pci_dev, PCI_POWER_SOURCE, - &val); + &val); - if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT) + if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT) { iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, - APMG_PS_CTRL_VAL_PWR_SRC_VAUX, - ~APMG_PS_CTRL_MSK_PWR_SRC); - } else + APMG_PS_CTRL_VAL_PWR_SRC_VAUX, + ~APMG_PS_CTRL_MSK_PWR_SRC); + } + } else { iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, - APMG_PS_CTRL_VAL_PWR_SRC_VMAIN, - ~APMG_PS_CTRL_MSK_PWR_SRC); + APMG_PS_CTRL_VAL_PWR_SRC_VMAIN, + ~APMG_PS_CTRL_MSK_PWR_SRC); + } iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); @@ -747,7 +748,8 @@ int iwl4965_hw_nic_init(struct iwl_priv *priv) IWL_DEBUG_INFO("HW Revision ID = 0x%X\n", rev_id); - iwl4965_nic_set_pwr_src(priv, 1); + rc = priv->cfg->ops->lib->apm_ops.set_pwr_src(priv, IWL_PWR_SRC_VMAIN); + spin_lock_irqsave(&priv->lock, flags); if ((rev_id & 0x80) == 0x80 && (rev_id & 0x7f) < 8) { @@ -4272,6 +4274,9 @@ static struct iwl_lib_ops iwl4965_lib = { .is_valid_rtc_data_addr = iwl4965_hw_valid_rtc_data_addr, .alive_notify = iwl4965_alive_notify, .load_ucode = iwl4965_load_bsm, + .apm_ops = { + .set_pwr_src = iwl4965_set_pwr_src, + }, .eeprom_ops = { .verify_signature = iwlcore_eeprom_verify_signature, .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h index b51243f4693..2c26d020103 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965.h @@ -252,6 +252,11 @@ struct iwl4965_clip_group { /* Power management (not Tx power) structures */ +enum iwl_pwr_src { + IWL_PWR_SRC_VMAIN, + IWL_PWR_SRC_VAUX, +}; + struct iwl4965_power_vec_entry { struct iwl4965_powertable_cmd cmd; u8 no_dtim; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index dcbd411a476..51f61fb844f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -115,6 +115,9 @@ struct iwl_lib_ops { int (*load_ucode)(struct iwl_priv *priv); /* rfkill */ void (*radio_kill_sw)(struct iwl_priv *priv, int disable_radio); + struct { + int (*set_pwr_src)(struct iwl_priv *priv, enum iwl_pwr_src src); + } apm_ops; /* eeprom operations (as defined in iwl-eeprom.h) */ struct iwl_eeprom_ops eeprom_ops; }; diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index 12725796ea5..a59f48b02f0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -170,6 +170,10 @@ #define CSR49_FH_INT_TX_MASK (CSR_FH_INT_BIT_TX_CHNL1 | \ CSR_FH_INT_BIT_TX_CHNL0) +/* GPIO */ +#define CSR_GPIO_IN_BIT_AUX_POWER (0x00000200) +#define CSR_GPIO_IN_VAL_VAUX_PWR_SRC (0x00000000) +#define CSR_GPIO_IN_VAL_VMAIN_PWR_SRC (0x00000200) /* RESET */ #define CSR_RESET_REG_FLAG_NEVO_RESET (0x00000001) @@ -206,11 +210,6 @@ #define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED (0x00000004) #define CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT (0x00000008) -/* GPIO */ -#define CSR_GPIO_IN_BIT_AUX_POWER (0x00000200) -#define CSR_GPIO_IN_VAL_VAUX_PWR_SRC (0x00000000) -#define CSR_GPIO_IN_VAL_VMAIN_PWR_SRC CSR_GPIO_IN_BIT_AUX_POWER - /* GI Chicken Bits */ #define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000) #define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER (0x20000000) -- cgit v1.2.3-70-g09d2 From 1c014420583564ac09e3b67006f2e7050861e66b Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Thu, 17 Apr 2008 19:41:02 +0200 Subject: mac80211: Replace ieee80211_tx_control->key_idx with ieee80211_key_conf The hw_key_idx inside the ieee80211_key_conf structure does not provide all the information drivers might need to perform hardware encryption. This is in particular true for rt2x00 who needs to know the key algorithm and whether it is a shared or pairwise key. By passing the ieee80211_key_conf pointer it assures us that drivers can make full use of all information that it should know about a particular key. Additionally this patch updates all drivers to grab the hw_key_idx from the ieee80211_key_conf structure. v2: Removed bogus u16 cast v3: Add warning about ieee80211_tx_control pointers v4: Update warning about ieee80211_tx_control pointers Signed-off-by: Ivo van Doorn Acked-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 2 +- drivers/net/wireless/b43/xmit.c | 2 +- drivers/net/wireless/b43legacy/xmit.c | 2 +- drivers/net/wireless/iwlwifi/iwl3945-base.c | 7 ++++--- drivers/net/wireless/iwlwifi/iwl4965-base.c | 6 +++--- include/net/mac80211.h | 19 +++++++++++++++---- net/mac80211/wep.c | 2 +- net/mac80211/wpa.c | 8 ++++---- 8 files changed, 30 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 4e5c8fc3520..3854619f351 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -1319,7 +1319,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, pktlen = skb->len; if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) { - keyidx = ctl->key_idx; + keyidx = ctl->hw_key->hw_key_idx; pktlen += ctl->icv_len; } diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 19aefbfb2c9..88491947a20 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -235,7 +235,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, plcp_fragment_len = fragment_len + FCS_LEN; if (use_encryption) { - u8 key_idx = (u16) (txctl->key_idx); + u8 key_idx = txctl->hw_key->hw_key_idx; struct b43_key *key; int wlhdr_len; size_t iv_len; diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c index dcad2491a60..fc83dab6e2c 100644 --- a/drivers/net/wireless/b43legacy/xmit.c +++ b/drivers/net/wireless/b43legacy/xmit.c @@ -232,7 +232,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, plcp_fragment_len = fragment_len + FCS_LEN; if (use_encryption) { - u8 key_idx = (u16)(txctl->key_idx); + u8 key_idx = txctl->hw_key->hw_key_idx; struct b43legacy_key *key; int wlhdr_len; size_t iv_len; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 13925b627e3..7bdffa9cfea 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2391,7 +2391,8 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl3945_priv *priv, struct sk_buff *skb_frag, int last_frag) { - struct iwl3945_hw_key *keyinfo = &priv->stations[ctl->key_idx].keyinfo; + struct iwl3945_hw_key *keyinfo = + &priv->stations[ctl->hw_key->hw_key_idx].keyinfo; switch (keyinfo->alg) { case ALG_CCMP: @@ -2414,7 +2415,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl3945_priv *priv, case ALG_WEP: cmd->cmd.tx.sec_ctl = TX_CMD_SEC_WEP | - (ctl->key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT; + (ctl->hw_key->hw_key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT; if (keyinfo->keylen == 13) cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128; @@ -2422,7 +2423,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl3945_priv *priv, memcpy(&cmd->cmd.tx.key[3], keyinfo->key, keyinfo->keylen); IWL_DEBUG_TX("Configuring packet for WEP encryption " - "with key %d\n", ctl->key_idx); + "with key %d\n", ctl->hw_key->hw_key_idx); break; default: diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index c8cbf70600d..e43ea5377d8 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -1926,7 +1926,7 @@ static void iwl4965_build_tx_cmd_hwcrypto(struct iwl_priv *priv, struct iwl_wep_key *wepkey; int keyidx = 0; - BUG_ON(ctl->key_idx > 3); + BUG_ON(ctl->hw_key->hw_key_idx > 3); switch (keyinfo->alg) { case ALG_CCMP: @@ -1945,11 +1945,11 @@ static void iwl4965_build_tx_cmd_hwcrypto(struct iwl_priv *priv, break; case ALG_WEP: - wepkey = &priv->wep_keys[ctl->key_idx]; + wepkey = &priv->wep_keys[ctl->hw_key->hw_key_idx]; cmd->cmd.tx.sec_ctl = 0; if (priv->default_wep_key) { /* the WEP key was sent as static */ - keyidx = ctl->key_idx; + keyidx = ctl->hw_key->hw_key_idx; memcpy(&cmd->cmd.tx.key[3], wepkey->key, wepkey->key_size); if (wepkey->key_size == WEP_KEY_LEN_128) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 4a80d74975e..27ef9f761ac 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -286,8 +286,17 @@ enum mac80211_tx_control_flags { /* Transmit control fields. This data structure is passed to low-level driver * with each TX frame. The low-level driver is responsible for configuring - * the hardware to use given values (depending on what is supported). */ - + * the hardware to use given values (depending on what is supported). + * + * NOTE: Be careful with using the pointers outside of the ieee80211_ops->tx() + * context (i.e. when defering the work to a workqueue). + * The vif pointer is valid until the it has been removed with the + * ieee80211_ops->remove_interface() callback funtion. + * The hw_key pointer is valid until it has been removed with the + * ieee80211_ops->set_key() callback function. + * The tx_rate and alt_retry_rate pointers are valid until the phy is + * deregistered. + */ struct ieee80211_tx_control { struct ieee80211_vif *vif; struct ieee80211_rate *tx_rate; @@ -298,9 +307,11 @@ struct ieee80211_tx_control { /* retry rate for the last retries */ struct ieee80211_rate *alt_retry_rate; + /* Key used for hardware encryption + * NULL if IEEE80211_TXCTL_DO_NOT_ENCRYPT is set */ + struct ieee80211_key_conf *hw_key; + u32 flags; /* tx control flags defined above */ - u8 key_idx; /* keyidx from hw->set_key(), undefined if - * IEEE80211_TXCTL_DO_NOT_ENCRYPT is set */ u8 retry_limit; /* 1 = only first attempt, 2 = one retry, .. * This could be used when set_retry_limit * is not implemented by the driver */ diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index affcecd78c1..3cbae42ec50 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c @@ -337,7 +337,7 @@ static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) if (ieee80211_wep_encrypt(tx->local, skb, tx->key)) return -1; } else { - tx->control->key_idx = tx->key->conf.hw_key_idx; + tx->control->hw_key = &tx->key->conf; if (tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) { if (!ieee80211_wep_add_iv(tx->local, skb, tx->key)) return -1; diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 45709ada8fe..42f3654e1c5 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -228,7 +228,7 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, 0x7f), (u8) key->u.tkip.iv16); - tx->control->key_idx = tx->key->conf.hw_key_idx; + tx->control->hw_key = &tx->key->conf; return 0; } @@ -256,7 +256,7 @@ ieee80211_crypto_tkip_encrypt(struct ieee80211_tx_data *tx) !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) && !wpa_test) { /* hwaccel - with no need for preallocated room for IV/ICV */ - tx->control->key_idx = tx->key->conf.hw_key_idx; + tx->control->hw_key = &tx->key->conf; return TX_CONTINUE; } @@ -478,7 +478,7 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { /* hwaccel - with preallocated room for CCMP header */ - tx->control->key_idx = key->conf.hw_key_idx; + tx->control->hw_key = &tx->key->conf; return 0; } @@ -505,7 +505,7 @@ ieee80211_crypto_ccmp_encrypt(struct ieee80211_tx_data *tx) !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { /* hwaccel - with no need for preallocated room for CCMP " * header or MIC fields */ - tx->control->key_idx = tx->key->conf.hw_key_idx; + tx->control->hw_key = &tx->key->conf; return TX_CONTINUE; } -- cgit v1.2.3-70-g09d2 From 3ec47732a0be038f15a0b8d852a4e4ff9c5b0196 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 17 Apr 2008 16:03:36 -0700 Subject: iwlwifi: HW crypto acceleration fixes This patch fixes several issues in security: 1) the uCode doesn't know about TKIP-MMIC failure, if uCode set RX_RES_STATUS_BAD_ICV_MIC, it means ICV failure: drop the packet silently. 2) do not allocate room in the key table of the uCode is the set_key call is a replacement of an old key 3) check the keyidx of the key in the uCode before removing it upon disable_key call Signed-off-by: Emmanuel Grumbach Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 53 +++++++++++++++++++++++++++-- drivers/net/wireless/iwlwifi/iwl-4965.h | 3 -- drivers/net/wireless/iwlwifi/iwl-sta.c | 53 ++++++++++++++++++++++++----- drivers/net/wireless/iwlwifi/iwl-sta.h | 3 +- drivers/net/wireless/iwlwifi/iwl4965-base.c | 41 +--------------------- 5 files changed, 98 insertions(+), 55 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 69a355bbb97..ddcd1b23254 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2871,6 +2871,53 @@ static void iwl_update_rx_stats(struct iwl_priv *priv, u16 fc, u16 len) priv->rx_stats[idx].bytes += len; } +/* + * returns non-zero if packet should be dropped + */ +static int iwl4965_set_decrypted_flag(struct iwl_priv *priv, + struct ieee80211_hdr *hdr, + u32 decrypt_res, + struct ieee80211_rx_status *stats) +{ + u16 fc = le16_to_cpu(hdr->frame_control); + + if (priv->active_rxon.filter_flags & RXON_FILTER_DIS_DECRYPT_MSK) + return 0; + + if (!(fc & IEEE80211_FCTL_PROTECTED)) + return 0; + + IWL_DEBUG_RX("decrypt_res:0x%x\n", decrypt_res); + switch (decrypt_res & RX_RES_STATUS_SEC_TYPE_MSK) { + case RX_RES_STATUS_SEC_TYPE_TKIP: + /* The uCode has got a bad phase 1 Key, pushes the packet. + * Decryption will be done in SW. */ + if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == + RX_RES_STATUS_BAD_KEY_TTAK) + break; + + if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == + RX_RES_STATUS_BAD_ICV_MIC) { + /* bad ICV, the packet is destroyed since the + * decryption is inplace, drop it */ + IWL_DEBUG_RX("Packet destroyed\n"); + return -1; + } + case RX_RES_STATUS_SEC_TYPE_WEP: + case RX_RES_STATUS_SEC_TYPE_CCMP: + if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == + RX_RES_STATUS_DECRYPT_OK) { + IWL_DEBUG_RX("hw decrypt successfully!!!\n"); + stats->flag |= RX_FLAG_DECRYPTED; + } + break; + + default: + break; + } + return 0; +} + static u32 iwl4965_translate_rx_status(u32 decrypt_in) { u32 decrypt_out = 0; @@ -3000,8 +3047,10 @@ static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data, stats->flag = 0; hdr = (struct ieee80211_hdr *)rxb->skb->data; - if (!priv->cfg->mod_params->sw_crypto) - iwl4965_set_decrypted_flag(priv, rxb->skb, ampdu_status, stats); + /* in case of HW accelerated crypto and bad decryption, drop */ + if (!priv->cfg->mod_params->sw_crypto && + iwl4965_set_decrypted_flag(priv, hdr, ampdu_status, stats)) + return; if (priv->add_radiotap) iwl4965_add_radiotap(priv, rxb->skb, rx_start, stats, ampdu_status); diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h index 2c26d020103..ca2ce27ee7f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965.h @@ -673,9 +673,6 @@ extern unsigned int iwl4965_fill_beacon_frame(struct iwl_priv *priv, const u8 *dest, int left); extern int iwl4965_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl4965_rx_queue *q); -extern void iwl4965_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb, - u32 decrypt_res, - struct ieee80211_rx_status *stats); extern __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr); int iwl4965_init_geos(struct iwl_priv *priv); void iwl4965_free_geos(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index fa463ce6399..d39ac1cffb5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -207,10 +207,14 @@ static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv, memcpy(&priv->stations[sta_id].sta.key.key[3], keyconf->key, keyconf->keylen); - priv->stations[sta_id].sta.key.key_offset = + if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK) + == STA_KEY_FLG_NO_ENC) + priv->stations[sta_id].sta.key.key_offset = iwl_get_free_ucode_key_index(priv); - priv->stations[sta_id].sta.key.key_flags = key_flags; + /* else, we are overriding an existing key => no need to allocated room + * in uCode. */ + priv->stations[sta_id].sta.key.key_flags = key_flags; priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; @@ -249,8 +253,13 @@ static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv, memcpy(priv->stations[sta_id].sta.key.key, keyconf->key, keyconf->keylen); - priv->stations[sta_id].sta.key.key_offset = - iwl_get_free_ucode_key_index(priv); + if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK) + == STA_KEY_FLG_NO_ENC) + priv->stations[sta_id].sta.key.key_offset = + iwl_get_free_ucode_key_index(priv); + /* else, we are overriding an existing key => no need to allocated room + * in uCode. */ + priv->stations[sta_id].sta.key.key_flags = key_flags; priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; @@ -278,8 +287,13 @@ static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv, priv->stations[sta_id].keyinfo.alg = keyconf->alg; priv->stations[sta_id].keyinfo.conf = keyconf; priv->stations[sta_id].keyinfo.keylen = 16; - priv->stations[sta_id].sta.key.key_offset = + + if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK) + == STA_KEY_FLG_NO_ENC) + priv->stations[sta_id].sta.key.key_offset = iwl_get_free_ucode_key_index(priv); + /* else, we are overriding an existing key => no need to allocated room + * in uCode. */ /* This copy is acutally not needed: we get the key with each TX */ memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, 16); @@ -291,13 +305,31 @@ static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv, return ret; } -int iwl_remove_dynamic_key(struct iwl_priv *priv, u8 sta_id) +int iwl_remove_dynamic_key(struct iwl_priv *priv, + struct ieee80211_key_conf *keyconf, + u8 sta_id) { unsigned long flags; + int ret = 0; + u16 key_flags; + u8 keyidx; priv->key_mapping_key = 0; spin_lock_irqsave(&priv->sta_lock, flags); + key_flags = le16_to_cpu(priv->stations[sta_id].sta.key.key_flags); + keyidx = (key_flags >> STA_KEY_FLG_KEYID_POS) & 0x3; + + if (keyconf->keyidx != keyidx) { + /* We need to remove a key with index different that the one + * in the uCode. This means that the key we need to remove has + * been replaced by another one with different index. + * Don't do anything and return ok + */ + spin_unlock_irqrestore(&priv->sta_lock, flags); + return 0; + } + if (!test_and_clear_bit(priv->stations[sta_id].sta.key.key_offset, &priv->ucode_key_table)) IWL_ERROR("index %d not used in uCode key table.\n", @@ -306,13 +338,16 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv, u8 sta_id) sizeof(struct iwl4965_hw_key)); memset(&priv->stations[sta_id].sta.key, 0, sizeof(struct iwl4965_keyinfo)); - priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC; + priv->stations[sta_id].sta.key.key_flags = + STA_KEY_FLG_NO_ENC | STA_KEY_FLG_INVALID; + priv->stations[sta_id].sta.key.key_offset = WEP_INVALID_OFFSET; priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; - spin_unlock_irqrestore(&priv->sta_lock, flags); IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n"); - return iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, 0); + ret = iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, 0); + spin_unlock_irqrestore(&priv->sta_lock, flags); + return ret; } int iwl_set_dynamic_key(struct iwl_priv *priv, diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h index 44f272ecc82..89558356a59 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.h +++ b/drivers/net/wireless/iwlwifi/iwl-sta.h @@ -43,7 +43,8 @@ int iwl_remove_default_wep_key(struct iwl_priv *priv, struct ieee80211_key_conf *key); int iwl_set_default_wep_key(struct iwl_priv *priv, struct ieee80211_key_conf *key); -int iwl_remove_dynamic_key(struct iwl_priv *priv, u8 sta_id); int iwl_set_dynamic_key(struct iwl_priv *priv, struct ieee80211_key_conf *key, u8 sta_id); +int iwl_remove_dynamic_key(struct iwl_priv *priv, + struct ieee80211_key_conf *key, u8 sta_id); #endif /* __iwl_sta_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index e43ea5377d8..50f12a6133e 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -2456,45 +2456,6 @@ void iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio) return; } -void iwl4965_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb, - u32 decrypt_res, struct ieee80211_rx_status *stats) -{ - u16 fc = - le16_to_cpu(((struct ieee80211_hdr *)skb->data)->frame_control); - - if (priv->active_rxon.filter_flags & RXON_FILTER_DIS_DECRYPT_MSK) - return; - - if (!(fc & IEEE80211_FCTL_PROTECTED)) - return; - - IWL_DEBUG_RX("decrypt_res:0x%x\n", decrypt_res); - switch (decrypt_res & RX_RES_STATUS_SEC_TYPE_MSK) { - case RX_RES_STATUS_SEC_TYPE_TKIP: - /* The uCode has got a bad phase 1 Key, pushes the packet. - * Decryption will be done in SW. */ - if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == - RX_RES_STATUS_BAD_KEY_TTAK) - break; - - if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == - RX_RES_STATUS_BAD_ICV_MIC) - stats->flag |= RX_FLAG_MMIC_ERROR; - case RX_RES_STATUS_SEC_TYPE_WEP: - case RX_RES_STATUS_SEC_TYPE_CCMP: - if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == - RX_RES_STATUS_DECRYPT_OK) { - IWL_DEBUG_RX("hw decrypt successfully!!!\n"); - stats->flag |= RX_FLAG_DECRYPTED; - } - break; - - default: - break; - } -} - - #define IWL_PACKET_RETRY_TIME HZ int iwl4965_is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header) @@ -6861,7 +6822,7 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (is_default_wep_key) ret = iwl_remove_default_wep_key(priv, key); else - ret = iwl_remove_dynamic_key(priv, sta_id); + ret = iwl_remove_dynamic_key(priv, key, sta_id); IWL_DEBUG_MAC80211("disable hwcrypto key\n"); break; -- cgit v1.2.3-70-g09d2 From fe07aa7acd9ec221d4440a38ffc9a58776cb34bc Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Thu, 17 Apr 2008 16:03:37 -0700 Subject: iwlwifi: arranging aggregation actions This patch makes some renaming of the ampdu_action functions inside iwlwifi, and adds checks for correct station id in Rx flows Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 70 +++++++++++++++++---------------- 1 file changed, 37 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index ddcd1b23254..890dfa44c1e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -4063,10 +4063,15 @@ void iwl4965_set_ht_add_station(struct iwl_priv *priv, u8 index, return; } -static void iwl4965_sta_modify_add_ba_tid(struct iwl_priv *priv, - int sta_id, int tid, u16 ssn) +static int iwl4965_rx_agg_start(struct iwl_priv *priv, + const u8 *addr, int tid, u16 ssn) { unsigned long flags; + int sta_id; + + sta_id = iwl_find_station(priv, addr); + if (sta_id == IWL_INVALID_STATION) + return -ENXIO; spin_lock_irqsave(&priv->sta_lock, flags); priv->stations[sta_id].sta.station_flags_msk = 0; @@ -4076,13 +4081,19 @@ static void iwl4965_sta_modify_add_ba_tid(struct iwl_priv *priv, priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; spin_unlock_irqrestore(&priv->sta_lock, flags); - iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC); + return iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, + CMD_ASYNC); } -static void iwl4965_sta_modify_del_ba_tid(struct iwl_priv *priv, - int sta_id, int tid) +static int iwl4965_rx_agg_stop(struct iwl_priv *priv, + const u8 *addr, int tid) { unsigned long flags; + int sta_id; + + sta_id = iwl_find_station(priv, addr); + if (sta_id == IWL_INVALID_STATION) + return -ENXIO; spin_lock_irqsave(&priv->sta_lock, flags); priv->stations[sta_id].sta.station_flags_msk = 0; @@ -4091,7 +4102,8 @@ static void iwl4965_sta_modify_del_ba_tid(struct iwl_priv *priv, priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; spin_unlock_irqrestore(&priv->sta_lock, flags); - iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC); + return iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, + CMD_ASYNC); } /* @@ -4110,8 +4122,8 @@ static int iwl4965_txq_ctx_activate_free(struct iwl_priv *priv) return -1; } -static int iwl4965_mac_ht_tx_agg_start(struct ieee80211_hw *hw, const u8 *da, - u16 tid, u16 *start_seq_num) +static int iwl4965_tx_agg_start(struct ieee80211_hw *hw, const u8 *ra, + u16 tid, u16 *start_seq_num) { struct iwl_priv *priv = hw->priv; int sta_id; @@ -4128,10 +4140,10 @@ static int iwl4965_mac_ht_tx_agg_start(struct ieee80211_hw *hw, const u8 *da, else return -EINVAL; - IWL_WARNING("%s on da = %s tid = %d\n", - __func__, print_mac(mac, da), tid); + IWL_WARNING("%s on ra = %s tid = %d\n", + __func__, print_mac(mac, ra), tid); - sta_id = iwl_find_station(priv, da); + sta_id = iwl_find_station(priv, ra); if (sta_id == IWL_INVALID_STATION) return -ENXIO; @@ -4160,7 +4172,7 @@ static int iwl4965_mac_ht_tx_agg_start(struct ieee80211_hw *hw, const u8 *da, if (tid_data->tfds_in_queue == 0) { printk(KERN_ERR "HW queue is empty\n"); tid_data->agg.state = IWL_AGG_ON; - ieee80211_start_tx_ba_cb_irqsafe(hw, da, tid); + ieee80211_start_tx_ba_cb_irqsafe(hw, ra, tid); } else { IWL_DEBUG_HT("HW queue is NOT empty: %d packets in HW queue\n", tid_data->tfds_in_queue); @@ -4169,10 +4181,8 @@ static int iwl4965_mac_ht_tx_agg_start(struct ieee80211_hw *hw, const u8 *da, return ret; } -static int iwl4965_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, const u8 *da, - u16 tid) +static int iwl4965_tx_agg_stop(struct ieee80211_hw *hw, const u8 *ra, u16 tid) { - struct iwl_priv *priv = hw->priv; int tx_fifo_id, txq_id, sta_id, ssn = -1; struct iwl4965_tid_data *tid_data; @@ -4180,8 +4190,8 @@ static int iwl4965_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, const u8 *da, unsigned long flags; DECLARE_MAC_BUF(mac); - if (!da) { - IWL_ERROR("da = NULL\n"); + if (!ra) { + IWL_ERROR("ra = NULL\n"); return -EINVAL; } @@ -4190,7 +4200,7 @@ static int iwl4965_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, const u8 *da, else return -EINVAL; - sta_id = iwl_find_station(priv, da); + sta_id = iwl_find_station(priv, ra); if (sta_id == IWL_INVALID_STATION) return -ENXIO; @@ -4212,7 +4222,7 @@ static int iwl4965_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, const u8 *da, return 0; } - IWL_DEBUG_HT("HW queue empty\n");; + IWL_DEBUG_HT("HW queue is empty\n"); priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF; spin_lock_irqsave(&priv->lock, flags); @@ -4222,10 +4232,7 @@ static int iwl4965_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, const u8 *da, if (ret) return ret; - ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, da, tid); - - IWL_DEBUG_INFO("iwl4965_mac_ht_tx_agg_stop on da=%s tid=%d\n", - print_mac(mac, da), tid); + ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, ra, tid); return 0; } @@ -4235,27 +4242,24 @@ int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, const u8 *addr, u16 tid, u16 *ssn) { struct iwl_priv *priv = hw->priv; - int sta_id; DECLARE_MAC_BUF(mac); - IWL_DEBUG_HT("A-MPDU action on da=%s tid=%d ", - print_mac(mac, addr), tid); - sta_id = iwl_find_station(priv, addr); + IWL_DEBUG_HT("A-MPDU action on addr %s tid %d\n", + print_mac(mac, addr), tid); + switch (action) { case IEEE80211_AMPDU_RX_START: IWL_DEBUG_HT("start Rx\n"); - iwl4965_sta_modify_add_ba_tid(priv, sta_id, tid, *ssn); - break; + return iwl4965_rx_agg_start(priv, addr, tid, *ssn); case IEEE80211_AMPDU_RX_STOP: IWL_DEBUG_HT("stop Rx\n"); - iwl4965_sta_modify_del_ba_tid(priv, sta_id, tid); - break; + return iwl4965_rx_agg_stop(priv, addr, tid); case IEEE80211_AMPDU_TX_START: IWL_DEBUG_HT("start Tx\n"); - return iwl4965_mac_ht_tx_agg_start(hw, addr, tid, ssn); + return iwl4965_tx_agg_start(hw, addr, tid, ssn); case IEEE80211_AMPDU_TX_STOP: IWL_DEBUG_HT("stop Tx\n"); - return iwl4965_mac_ht_tx_agg_stop(hw, addr, tid); + return iwl4965_tx_agg_stop(hw, addr, tid); default: IWL_DEBUG_HT("unknown\n"); return -EINVAL; -- cgit v1.2.3-70-g09d2 From a693f187facbf25925bbcf201db88c5384468646 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 17 Apr 2008 16:03:38 -0700 Subject: iwlwifi: define ANA_PLL values in iwl-csr.h This patch defines ANA_PLL values in iwl-csr.h Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 2 +- drivers/net/wireless/iwlwifi/iwl-csr.h | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index d3406830c8e..8464397f781 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -1229,7 +1229,7 @@ int iwl3945_hw_nic_init(struct iwl3945_priv *priv) iwl3945_power_init_handle(priv); spin_lock_irqsave(&priv->lock, flags); - iwl3945_set_bit(priv, CSR_ANA_PLL_CFG, (1 << 24)); + iwl3945_set_bit(priv, CSR_ANA_PLL_CFG, CSR39_ANA_PLL_CFG_VAL); iwl3945_set_bit(priv, CSR_GIO_CHICKEN_BITS, CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index a59f48b02f0..82c7445d292 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -95,8 +95,7 @@ #define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100) #define CSR_LED_REG (CSR_BASE+0x094) -/* Analog phase-lock-loop configuration (3945 only) - * Set bit 24. */ +/* Analog phase-lock-loop configuration */ #define CSR_ANA_PLL_CFG (CSR_BASE+0x20c) /* * Indicates hardware rev, to determine CCK backoff for txpower calculation. @@ -219,6 +218,10 @@ #define CSR_LED_REG_TRUN_ON (0x78) #define CSR_LED_REG_TRUN_OFF (0x38) +/* ANA_PLL */ +#define CSR39_ANA_PLL_CFG_VAL (0x01000000) +#define CSR50_ANA_PLL_CFG_VAL (0x00880300) + /*=== HBUS (Host-side Bus) ===*/ #define HBUS_BASE (0x400) /* -- cgit v1.2.3-70-g09d2 From 079a253383c711d388adce527b57bd09297ee83c Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 17 Apr 2008 16:03:39 -0700 Subject: iwlwifi: export int iwl4965_set_pwr_src This handler is universal for most of the HW Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 2 +- drivers/net/wireless/iwlwifi/iwl-4965.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 890dfa44c1e..2b9471f1686 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -492,7 +492,7 @@ int iwl4965_hw_rxq_stop(struct iwl_priv *priv) return 0; } -static int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src) +int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src) { int ret; unsigned long flags; diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h index ca2ce27ee7f..78381f287de 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965.h @@ -674,6 +674,8 @@ extern unsigned int iwl4965_fill_beacon_frame(struct iwl_priv *priv, extern int iwl4965_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl4965_rx_queue *q); extern __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr); +int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src); + int iwl4965_init_geos(struct iwl_priv *priv); void iwl4965_free_geos(struct iwl_priv *priv); -- cgit v1.2.3-70-g09d2 From 2afc49015db927fea7bc6ca33c0a60bf5d7c2c5f Mon Sep 17 00:00:00 2001 From: "Larry.Finger@lwfinger.net" Date: Sat, 19 Apr 2008 16:24:09 +0200 Subject: ssb: Allow reading of 440-byte SPROM that is not rev 4 The current code checks for the special signature that signifies a revision 4 SPROM. Now that a rev. 8 SPROM with a 440-byte length has been found that may not have any special code, this check could be relaxed. With this patch, if the CRC is incorrect for a 256-byte SPROM, the code will immediately check for a 440-byte SPROM. If there is still a CRC error, the size is set to 440 bytes, which allows dumping of most of any 512-byte SPROM if one is encountered. Signed-off-by: Larry Finger Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/ssb/pci.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index 57c4ccfab1e..f883dcfffe0 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -510,17 +510,15 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus, sprom_do_read(bus, buf); err = sprom_check_crc(buf, bus->sprom_size); if (err) { - /* check for rev 4 sprom - has special signature */ - if (buf[32] == 0x5372) { - kfree(buf); - buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16), - GFP_KERNEL); - if (!buf) - goto out; - bus->sprom_size = SSB_SPROMSIZE_WORDS_R4; - sprom_do_read(bus, buf); - err = sprom_check_crc(buf, bus->sprom_size); - } + /* try for a 440 byte SPROM - revision 4 and higher */ + kfree(buf); + buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16), + GFP_KERNEL); + if (!buf) + goto out; + bus->sprom_size = SSB_SPROMSIZE_WORDS_R4; + sprom_do_read(bus, buf); + err = sprom_check_crc(buf, bus->sprom_size); if (err) ssb_printk(KERN_WARNING PFX "WARNING: Invalid" " SPROM CRC (corrupt SPROM)\n"); -- cgit v1.2.3-70-g09d2 From f5eda47f45e90dfa38e25d569b9ac84ba94f8301 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 20 Apr 2008 16:03:32 +0200 Subject: b43: Rewrite LO calibration algorithm This patch distributes the Local Oscillator calibration bursts over time, so that calibration only happens when it's actually needed. Currently we periodically perform a recalibration of the whole table. The table is huge and this takes lots of time. Additionally only small bits of the table are actually needed at a given time. So instead of maintaining a huge table with all possible calibration values, we create dynamic calibration settings that a) We only calibrate when they are actually needed. b) Are cached for some time until they expire. So a recalibration might happen if we need a calibration setting that's not cached, or if the active calibration setting expires. Currently the expire timeout is set to 30 seconds. We may raise that in future. This patch reduces overall memory consumption by nuking the huge static calibration tables. This patch has been tested on several 4306, 4311 and 4318 flavours. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/debugfs.c | 77 ++-- drivers/net/wireless/b43/debugfs.h | 1 + drivers/net/wireless/b43/lo.c | 721 +++++++++++++------------------------ drivers/net/wireless/b43/lo.h | 115 +++--- drivers/net/wireless/b43/main.c | 26 +- drivers/net/wireless/b43/main.h | 3 + drivers/net/wireless/b43/phy.c | 123 ++----- drivers/net/wireless/b43/phy.h | 16 +- 8 files changed, 396 insertions(+), 686 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/debugfs.c b/drivers/net/wireless/b43/debugfs.c index 7fca2ebc747..210e2789c1c 100644 --- a/drivers/net/wireless/b43/debugfs.c +++ b/drivers/net/wireless/b43/debugfs.c @@ -270,24 +270,22 @@ static int restart_write_file(struct b43_wldev *dev, return err; } -static ssize_t append_lo_table(ssize_t count, char *buf, const size_t bufsize, - struct b43_loctl table[B43_NR_BB][B43_NR_RF]) +static unsigned long calc_expire_secs(unsigned long now, + unsigned long time, + unsigned long expire) { - unsigned int i, j; - struct b43_loctl *ctl; - - for (i = 0; i < B43_NR_BB; i++) { - for (j = 0; j < B43_NR_RF; j++) { - ctl = &(table[i][j]); - fappend("(bbatt %2u, rfatt %2u) -> " - "(I %+3d, Q %+3d, Used: %d, Calibrated: %d)\n", - i, j, ctl->i, ctl->q, - ctl->used, - b43_loctl_is_calibrated(ctl)); - } + expire = time + expire; + + if (time_after(now, expire)) + return 0; /* expired */ + if (expire < now) { + /* jiffies wrapped */ + expire -= MAX_JIFFY_OFFSET; + now -= MAX_JIFFY_OFFSET; } + B43_WARN_ON(expire < now); - return count; + return (expire - now) / HZ; } static ssize_t loctls_read_file(struct b43_wldev *dev, @@ -296,27 +294,45 @@ static ssize_t loctls_read_file(struct b43_wldev *dev, ssize_t count = 0; struct b43_txpower_lo_control *lo; int i, err = 0; + struct b43_lo_calib *cal; + unsigned long now = jiffies; + struct b43_phy *phy = &dev->phy; - if (dev->phy.type != B43_PHYTYPE_G) { + if (phy->type != B43_PHYTYPE_G) { fappend("Device is not a G-PHY\n"); err = -ENODEV; goto out; } - lo = dev->phy.lo_control; + lo = phy->lo_control; fappend("-- Local Oscillator calibration data --\n\n"); - fappend("Measured: %d, Rebuild: %d, HW-power-control: %d\n", - lo->lo_measured, - lo->rebuild, + fappend("HW-power-control enabled: %d\n", dev->phy.hardware_power_control); - fappend("TX Bias: 0x%02X, TX Magn: 0x%02X\n", - lo->tx_bias, lo->tx_magn); - fappend("Power Vector: 0x%08X%08X\n", + fappend("TX Bias: 0x%02X, TX Magn: 0x%02X (expire in %lu sec)\n", + lo->tx_bias, lo->tx_magn, + calc_expire_secs(now, lo->txctl_measured_time, + B43_LO_TXCTL_EXPIRE)); + fappend("Power Vector: 0x%08X%08X (expires in %lu sec)\n", (unsigned int)((lo->power_vector & 0xFFFFFFFF00000000ULL) >> 32), - (unsigned int)(lo->power_vector & 0x00000000FFFFFFFFULL)); - fappend("\nControl table WITH PADMIX:\n"); - count = append_lo_table(count, buf, bufsize, lo->with_padmix); - fappend("\nControl table WITHOUT PADMIX:\n"); - count = append_lo_table(count, buf, bufsize, lo->no_padmix); + (unsigned int)(lo->power_vector & 0x00000000FFFFFFFFULL), + calc_expire_secs(now, lo->pwr_vec_read_time, + B43_LO_PWRVEC_EXPIRE)); + + fappend("\nCalibrated settings:\n"); + list_for_each_entry(cal, &lo->calib_list, list) { + bool active; + + active = (b43_compare_bbatt(&cal->bbatt, &phy->bbatt) && + b43_compare_rfatt(&cal->rfatt, &phy->rfatt)); + fappend("BB(%d), RF(%d,%d) -> I=%d, Q=%d " + "(expires in %lu sec)%s\n", + cal->bbatt.att, + cal->rfatt.att, cal->rfatt.with_padmix, + cal->ctl.i, cal->ctl.q, + calc_expire_secs(now, cal->calib_time, + B43_LO_CALIB_EXPIRE), + active ? " ACTIVE" : ""); + } + fappend("\nUsed RF attenuation values: Value(WithPadmix flag)\n"); for (i = 0; i < lo->rfatt_list.len; i++) { fappend("%u(%d), ", @@ -351,7 +367,7 @@ static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf, struct b43_dfs_file *dfile; ssize_t uninitialized_var(ret); char *buf; - const size_t bufsize = 1024 * 128; + const size_t bufsize = 1024 * 16; /* 16 kiB buffer */ const size_t buforder = get_order(bufsize); int err = 0; @@ -380,8 +396,6 @@ static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf, err = -ENOMEM; goto out_unlock; } - /* Sparse warns about the following memset, because it has a big - * size value. That warning is bogus, so I will ignore it. --mb */ memset(buf, 0, bufsize); if (dfops->take_irqlock) { spin_lock_irq(&dev->wl->irq_lock); @@ -523,6 +537,7 @@ static void b43_add_dynamic_debug(struct b43_wldev *dev) add_dyn_dbg("debug_dmaverbose", B43_DBG_DMAVERBOSE, 0); add_dyn_dbg("debug_pwork_fast", B43_DBG_PWORK_FAST, 0); add_dyn_dbg("debug_pwork_stop", B43_DBG_PWORK_STOP, 0); + add_dyn_dbg("debug_lo", B43_DBG_LO, 0); #undef add_dyn_dbg } diff --git a/drivers/net/wireless/b43/debugfs.h b/drivers/net/wireless/b43/debugfs.h index 6eebe858db5..c75cff4151d 100644 --- a/drivers/net/wireless/b43/debugfs.h +++ b/drivers/net/wireless/b43/debugfs.h @@ -10,6 +10,7 @@ enum b43_dyndbg { /* Dynamic debugging features */ B43_DBG_DMAVERBOSE, B43_DBG_PWORK_FAST, B43_DBG_PWORK_STOP, + B43_DBG_LO, __B43_NR_DYNDBG, }; diff --git a/drivers/net/wireless/b43/lo.c b/drivers/net/wireless/b43/lo.c index d890f366a23..4edee6da2b8 100644 --- a/drivers/net/wireless/b43/lo.c +++ b/drivers/net/wireless/b43/lo.c @@ -36,10 +36,22 @@ #include -/* Define to 1 to always calibrate all possible LO control pairs. - * This is a workaround until we fix the partial LO calibration optimization. */ -#define B43_CALIB_ALL_LOCTLS 1 +static struct b43_lo_calib * b43_find_lo_calib(struct b43_txpower_lo_control *lo, + const struct b43_bbatt *bbatt, + const struct b43_rfatt *rfatt) +{ + struct b43_lo_calib *c; + + list_for_each_entry(c, &lo->calib_list, list) { + if (!b43_compare_bbatt(&c->bbatt, bbatt)) + continue; + if (!b43_compare_rfatt(&c->rfatt, rfatt)) + continue; + return c; + } + return NULL; +} /* Write the LocalOscillator Control (adjust) value-pair. */ static void b43_lo_write(struct b43_wldev *dev, struct b43_loctl *control) @@ -64,183 +76,6 @@ static void b43_lo_write(struct b43_wldev *dev, struct b43_loctl *control) b43_phy_write(dev, reg, value); } -static int assert_rfatt_and_bbatt(const struct b43_rfatt *rfatt, - const struct b43_bbatt *bbatt, - struct b43_wldev *dev) -{ - int err = 0; - - /* Check the attenuation values against the LO control array sizes. */ - if (unlikely(rfatt->att >= B43_NR_RF)) { - b43err(dev->wl, "rfatt(%u) >= size of LO array\n", rfatt->att); - err = -EINVAL; - } - if (unlikely(bbatt->att >= B43_NR_BB)) { - b43err(dev->wl, "bbatt(%u) >= size of LO array\n", bbatt->att); - err = -EINVAL; - } - - return err; -} - -#if !B43_CALIB_ALL_LOCTLS -static -struct b43_loctl *b43_get_lo_g_ctl_nopadmix(struct b43_wldev *dev, - const struct b43_rfatt *rfatt, - const struct b43_bbatt *bbatt) -{ - struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; - - if (assert_rfatt_and_bbatt(rfatt, bbatt, dev)) - return &(lo->no_padmix[0][0]); /* Just prevent a crash */ - return &(lo->no_padmix[bbatt->att][rfatt->att]); -} -#endif /* !B43_CALIB_ALL_LOCTLS */ - -struct b43_loctl *b43_get_lo_g_ctl(struct b43_wldev *dev, - const struct b43_rfatt *rfatt, - const struct b43_bbatt *bbatt) -{ - struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; - - if (assert_rfatt_and_bbatt(rfatt, bbatt, dev)) - return &(lo->no_padmix[0][0]); /* Just prevent a crash */ - if (rfatt->with_padmix) - return &(lo->with_padmix[bbatt->att][rfatt->att]); - return &(lo->no_padmix[bbatt->att][rfatt->att]); -} - -/* Call a function for every possible LO control value-pair. */ -static void b43_call_for_each_loctl(struct b43_wldev *dev, - void (*func) (struct b43_wldev *, - struct b43_loctl *)) -{ - struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *ctl = phy->lo_control; - int i, j; - - for (i = 0; i < B43_NR_BB; i++) { - for (j = 0; j < B43_NR_RF; j++) - func(dev, &(ctl->with_padmix[i][j])); - } - for (i = 0; i < B43_NR_BB; i++) { - for (j = 0; j < B43_NR_RF; j++) - func(dev, &(ctl->no_padmix[i][j])); - } -} - -static u16 lo_b_r15_loop(struct b43_wldev *dev) -{ - int i; - u16 ret = 0; - - for (i = 0; i < 10; i++) { - b43_phy_write(dev, 0x0015, 0xAFA0); - udelay(1); - b43_phy_write(dev, 0x0015, 0xEFA0); - udelay(10); - b43_phy_write(dev, 0x0015, 0xFFA0); - udelay(40); - ret += b43_phy_read(dev, 0x002C); - } - - return ret; -} - -void b43_lo_b_measure(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - u16 regstack[12] = { 0 }; - u16 mls; - u16 fval; - int i, j; - - regstack[0] = b43_phy_read(dev, 0x0015); - regstack[1] = b43_radio_read16(dev, 0x0052) & 0xFFF0; - - if (phy->radio_ver == 0x2053) { - regstack[2] = b43_phy_read(dev, 0x000A); - regstack[3] = b43_phy_read(dev, 0x002A); - regstack[4] = b43_phy_read(dev, 0x0035); - regstack[5] = b43_phy_read(dev, 0x0003); - regstack[6] = b43_phy_read(dev, 0x0001); - regstack[7] = b43_phy_read(dev, 0x0030); - - regstack[8] = b43_radio_read16(dev, 0x0043); - regstack[9] = b43_radio_read16(dev, 0x007A); - regstack[10] = b43_read16(dev, 0x03EC); - regstack[11] = b43_radio_read16(dev, 0x0052) & 0x00F0; - - b43_phy_write(dev, 0x0030, 0x00FF); - b43_write16(dev, 0x03EC, 0x3F3F); - b43_phy_write(dev, 0x0035, regstack[4] & 0xFF7F); - b43_radio_write16(dev, 0x007A, regstack[9] & 0xFFF0); - } - b43_phy_write(dev, 0x0015, 0xB000); - b43_phy_write(dev, 0x002B, 0x0004); - - if (phy->radio_ver == 0x2053) { - b43_phy_write(dev, 0x002B, 0x0203); - b43_phy_write(dev, 0x002A, 0x08A3); - } - - phy->minlowsig[0] = 0xFFFF; - - for (i = 0; i < 4; i++) { - b43_radio_write16(dev, 0x0052, regstack[1] | i); - lo_b_r15_loop(dev); - } - for (i = 0; i < 10; i++) { - b43_radio_write16(dev, 0x0052, regstack[1] | i); - mls = lo_b_r15_loop(dev) / 10; - if (mls < phy->minlowsig[0]) { - phy->minlowsig[0] = mls; - phy->minlowsigpos[0] = i; - } - } - b43_radio_write16(dev, 0x0052, regstack[1] | phy->minlowsigpos[0]); - - phy->minlowsig[1] = 0xFFFF; - - for (i = -4; i < 5; i += 2) { - for (j = -4; j < 5; j += 2) { - if (j < 0) - fval = (0x0100 * i) + j + 0x0100; - else - fval = (0x0100 * i) + j; - b43_phy_write(dev, 0x002F, fval); - mls = lo_b_r15_loop(dev) / 10; - if (mls < phy->minlowsig[1]) { - phy->minlowsig[1] = mls; - phy->minlowsigpos[1] = fval; - } - } - } - phy->minlowsigpos[1] += 0x0101; - - b43_phy_write(dev, 0x002F, phy->minlowsigpos[1]); - if (phy->radio_ver == 0x2053) { - b43_phy_write(dev, 0x000A, regstack[2]); - b43_phy_write(dev, 0x002A, regstack[3]); - b43_phy_write(dev, 0x0035, regstack[4]); - b43_phy_write(dev, 0x0003, regstack[5]); - b43_phy_write(dev, 0x0001, regstack[6]); - b43_phy_write(dev, 0x0030, regstack[7]); - - b43_radio_write16(dev, 0x0043, regstack[8]); - b43_radio_write16(dev, 0x007A, regstack[9]); - - b43_radio_write16(dev, 0x0052, - (b43_radio_read16(dev, 0x0052) & 0x000F) - | regstack[11]); - - b43_write16(dev, 0x03EC, regstack[10]); - } - b43_phy_write(dev, 0x0015, regstack[0]); -} - static u16 lo_measure_feedthrough(struct b43_wldev *dev, u16 lna, u16 pga, u16 trsw_rx) { @@ -438,48 +273,26 @@ static void lo_measure_txctl_values(struct b43_wldev *dev) b43_radio_write16(dev, 0x52, b43_radio_read16(dev, 0x52) & 0xFFF0); /* TX bias == 0 */ } + lo->txctl_measured_time = jiffies; } static void lo_read_power_vector(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; struct b43_txpower_lo_control *lo = phy->lo_control; - u16 i; + int i; u64 tmp; u64 power_vector = 0; - int rf_offset, bb_offset; - struct b43_loctl *loctl; for (i = 0; i < 8; i += 2) { tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x310 + i); - /* Clear the top byte. We get holes in the bitmap... */ - tmp &= 0xFF; power_vector |= (tmp << (i * 8)); /* Clear the vector on the device. */ b43_shm_write16(dev, B43_SHM_SHARED, 0x310 + i, 0); } - if (power_vector) lo->power_vector = power_vector; - power_vector = lo->power_vector; - - for (i = 0; i < 64; i++) { - if (power_vector & ((u64) 1ULL << i)) { - /* Now figure out which b43_loctl corresponds - * to this bit. - */ - rf_offset = i / lo->rfatt_list.len; - bb_offset = i % lo->rfatt_list.len; //FIXME? - loctl = - b43_get_lo_g_ctl(dev, - &lo->rfatt_list.list[rf_offset], - &lo->bbatt_list.list[bb_offset]); - /* And mark it as "used", as the device told us - * through the bitmap it is using it. - */ - loctl->used = 1; - } - } + lo->pwr_vec_read_time = jiffies; } /* 802.11/LO/GPHY/MeasuringGains */ @@ -609,8 +422,6 @@ static void lo_measure_setup(struct b43_wldev *dev, b43_phy_write(dev, B43_PHY_CCK(0x16), 0x410); b43_phy_write(dev, B43_PHY_CCK(0x17), 0x820); } - if (!lo->rebuild && b43_has_hardware_pctl(phy)) - lo_read_power_vector(dev); if (phy->rev >= 2) { sav->phy_analogover = b43_phy_read(dev, B43_PHY_ANALOGOVER); sav->phy_analogoverval = @@ -691,8 +502,12 @@ static void lo_measure_setup(struct b43_wldev *dev, b43_radio_read16(dev, 0x51); /* dummy read */ if (phy->type == B43_PHYTYPE_G) b43_phy_write(dev, B43_PHY_CCK(0x2F), 0); - if (lo->rebuild) + + /* Re-measure the txctl values, if needed. */ + if (time_before(lo->txctl_measured_time, + jiffies - B43_LO_TXCTL_EXPIRE)) lo_measure_txctl_values(dev); + if (phy->type == B43_PHYTYPE_G && phy->rev >= 3) { b43_phy_write(dev, B43_PHY_LO_MASK, 0xC078); } else { @@ -707,7 +522,6 @@ static void lo_measure_restore(struct b43_wldev *dev, struct lo_g_saved_values *sav) { struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; u16 tmp; if (phy->rev >= 2) { @@ -722,14 +536,6 @@ static void lo_measure_restore(struct b43_wldev *dev, tmp = (phy->pga_gain | 0xEFA0); b43_phy_write(dev, B43_PHY_PGACTL, tmp); } - if (b43_has_hardware_pctl(phy)) { - b43_gphy_dc_lt_init(dev); - } else { - if (lo->rebuild) - b43_lo_g_adjust_to(dev, 3, 2, 0); - else - b43_lo_g_adjust(dev); - } if (phy->type == B43_PHYTYPE_G) { if (phy->rev >= 3) b43_phy_write(dev, B43_PHY_CCK(0x2E), 0xC078); @@ -793,7 +599,6 @@ static int lo_probe_possible_loctls(struct b43_wldev *dev, struct b43_lo_g_statemachine *d) { struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; struct b43_loctl test_loctl; struct b43_loctl orig_loctl; struct b43_loctl prev_loctl = { @@ -852,7 +657,7 @@ static int lo_probe_possible_loctls(struct b43_wldev *dev, found_lower = 1; d->lowest_feedth = feedth; if ((d->nr_measured < 2) && - (!has_loopback_gain(phy) || lo->rebuild)) + !has_loopback_gain(phy)) break; } } @@ -874,7 +679,6 @@ static void lo_probe_loctls_statemachine(struct b43_wldev *dev, int *max_rx_gain) { struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; struct b43_lo_g_statemachine d; u16 feedth; int found_lower; @@ -883,18 +687,18 @@ static void lo_probe_loctls_statemachine(struct b43_wldev *dev, d.nr_measured = 0; d.state_val_multiplier = 1; - if (has_loopback_gain(phy) && !lo->rebuild) + if (has_loopback_gain(phy)) d.state_val_multiplier = 3; memcpy(&d.min_loctl, loctl, sizeof(struct b43_loctl)); - if (has_loopback_gain(phy) && lo->rebuild) + if (has_loopback_gain(phy)) max_repeat = 4; do { b43_lo_write(dev, &d.min_loctl); feedth = lo_measure_feedthrough(dev, phy->lna_gain, phy->pga_gain, phy->trsw_rx_gain); - if (!lo->rebuild && feedth < 0x258) { + if (feedth < 0x258) { if (feedth >= 0x12C) *max_rx_gain += 6; else @@ -944,278 +748,188 @@ static void lo_probe_loctls_statemachine(struct b43_wldev *dev, } while (++repeat_cnt < max_repeat); } -#if B43_CALIB_ALL_LOCTLS -static const struct b43_rfatt b43_full_rfatt_list_items[] = { - { .att = 0, .with_padmix = 0, }, - { .att = 1, .with_padmix = 0, }, - { .att = 2, .with_padmix = 0, }, - { .att = 3, .with_padmix = 0, }, - { .att = 4, .with_padmix = 0, }, - { .att = 5, .with_padmix = 0, }, - { .att = 6, .with_padmix = 0, }, - { .att = 7, .with_padmix = 0, }, - { .att = 8, .with_padmix = 0, }, - { .att = 9, .with_padmix = 0, }, - { .att = 10, .with_padmix = 0, }, - { .att = 11, .with_padmix = 0, }, - { .att = 12, .with_padmix = 0, }, - { .att = 13, .with_padmix = 0, }, - { .att = 14, .with_padmix = 0, }, - { .att = 15, .with_padmix = 0, }, - { .att = 0, .with_padmix = 1, }, - { .att = 1, .with_padmix = 1, }, - { .att = 2, .with_padmix = 1, }, - { .att = 3, .with_padmix = 1, }, - { .att = 4, .with_padmix = 1, }, - { .att = 5, .with_padmix = 1, }, - { .att = 6, .with_padmix = 1, }, - { .att = 7, .with_padmix = 1, }, - { .att = 8, .with_padmix = 1, }, - { .att = 9, .with_padmix = 1, }, - { .att = 10, .with_padmix = 1, }, - { .att = 11, .with_padmix = 1, }, - { .att = 12, .with_padmix = 1, }, - { .att = 13, .with_padmix = 1, }, - { .att = 14, .with_padmix = 1, }, - { .att = 15, .with_padmix = 1, }, -}; -static const struct b43_rfatt_list b43_full_rfatt_list = { - .list = b43_full_rfatt_list_items, - .len = ARRAY_SIZE(b43_full_rfatt_list_items), -}; - -static const struct b43_bbatt b43_full_bbatt_list_items[] = { - { .att = 0, }, - { .att = 1, }, - { .att = 2, }, - { .att = 3, }, - { .att = 4, }, - { .att = 5, }, - { .att = 6, }, - { .att = 7, }, - { .att = 8, }, - { .att = 9, }, - { .att = 10, }, - { .att = 11, }, -}; -static const struct b43_bbatt_list b43_full_bbatt_list = { - .list = b43_full_bbatt_list_items, - .len = ARRAY_SIZE(b43_full_bbatt_list_items), -}; -#endif /* B43_CALIB_ALL_LOCTLS */ - -static void lo_measure(struct b43_wldev *dev) +static +struct b43_lo_calib * b43_calibrate_lo_setting(struct b43_wldev *dev, + const struct b43_bbatt *bbatt, + const struct b43_rfatt *rfatt) { struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; struct b43_loctl loctl = { .i = 0, .q = 0, }; - struct b43_loctl *ploctl; int max_rx_gain; - int rfidx, bbidx; - const struct b43_bbatt_list *bbatt_list; - const struct b43_rfatt_list *rfatt_list; - + struct b43_lo_calib *cal; + struct lo_g_saved_values uninitialized_var(saved_regs); /* Values from the "TXCTL Register and Value Table" */ u16 txctl_reg; u16 txctl_value; u16 pad_mix_gain; - bbatt_list = &lo->bbatt_list; - rfatt_list = &lo->rfatt_list; -#if B43_CALIB_ALL_LOCTLS - bbatt_list = &b43_full_bbatt_list; - rfatt_list = &b43_full_rfatt_list; -#endif + saved_regs.old_channel = phy->channel; + b43_mac_suspend(dev); + lo_measure_setup(dev, &saved_regs); txctl_reg = lo_txctl_register_table(dev, &txctl_value, &pad_mix_gain); - for (rfidx = 0; rfidx < rfatt_list->len; rfidx++) { - - b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43) - & 0xFFF0) | - rfatt_list->list[rfidx].att); - b43_radio_write16(dev, txctl_reg, - (b43_radio_read16(dev, txctl_reg) - & ~txctl_value) - | (rfatt_list->list[rfidx].with_padmix ? - txctl_value : 0)); - - for (bbidx = 0; bbidx < bbatt_list->len; bbidx++) { - if (lo->rebuild) { -#if B43_CALIB_ALL_LOCTLS - ploctl = b43_get_lo_g_ctl(dev, - &rfatt_list->list[rfidx], - &bbatt_list->list[bbidx]); -#else - ploctl = b43_get_lo_g_ctl_nopadmix(dev, - &rfatt_list-> - list[rfidx], - &bbatt_list-> - list[bbidx]); -#endif - } else { - ploctl = b43_get_lo_g_ctl(dev, - &rfatt_list->list[rfidx], - &bbatt_list->list[bbidx]); - if (!ploctl->used) - continue; - } - memcpy(&loctl, ploctl, sizeof(loctl)); - loctl.i = 0; - loctl.q = 0; - - max_rx_gain = rfatt_list->list[rfidx].att * 2; - max_rx_gain += bbatt_list->list[bbidx].att / 2; - if (rfatt_list->list[rfidx].with_padmix) - max_rx_gain -= pad_mix_gain; - if (has_loopback_gain(phy)) - max_rx_gain += phy->max_lb_gain; - lo_measure_gain_values(dev, max_rx_gain, - has_loopback_gain(phy)); - - b43_phy_set_baseband_attenuation(dev, - bbatt_list->list[bbidx].att); - lo_probe_loctls_statemachine(dev, &loctl, &max_rx_gain); - if (phy->type == B43_PHYTYPE_B) { - loctl.i++; - loctl.q++; - } - b43_loctl_set_calibrated(&loctl, 1); - memcpy(ploctl, &loctl, sizeof(loctl)); - } - } -} - -#if B43_DEBUG -static void do_validate_loctl(struct b43_wldev *dev, struct b43_loctl *control) -{ - const int is_initializing = (b43_status(dev) == B43_STAT_UNINIT); - int i = control->i; - int q = control->q; + b43_radio_write16(dev, 0x43, + (b43_radio_read16(dev, 0x43) & 0xFFF0) + | rfatt->att); + b43_radio_write16(dev, txctl_reg, + (b43_radio_read16(dev, txctl_reg) & ~txctl_value) + | (rfatt->with_padmix) ? txctl_value : 0); - if (b43_loctl_is_calibrated(control)) { - if ((abs(i) > 16) || (abs(q) > 16)) - goto error; - } else { - if (control->used) - goto error; - if (dev->phy.lo_control->rebuild) { - control->i = 0; - control->q = 0; - if ((i != B43_LOCTL_POISON) || - (q != B43_LOCTL_POISON)) - goto error; - } + max_rx_gain = rfatt->att * 2; + max_rx_gain += bbatt->att / 2; + if (rfatt->with_padmix) + max_rx_gain -= pad_mix_gain; + if (has_loopback_gain(phy)) + max_rx_gain += phy->max_lb_gain; + lo_measure_gain_values(dev, max_rx_gain, + has_loopback_gain(phy)); + + b43_phy_set_baseband_attenuation(dev, bbatt->att); + lo_probe_loctls_statemachine(dev, &loctl, &max_rx_gain); + + lo_measure_restore(dev, &saved_regs); + b43_mac_enable(dev); + + if (b43_debug(dev, B43_DBG_LO)) { + b43dbg(dev->wl, "LO: Calibrated for BB(%u), RF(%u,%u) " + "=> I=%d Q=%d\n", + bbatt->att, rfatt->att, rfatt->with_padmix, + loctl.i, loctl.q); } - if (is_initializing && control->used) - goto error; - - return; -error: - b43err(dev->wl, "LO control pair validation failed " - "(I: %d, Q: %d, used %u, calib: %u, initing: %d)\n", - i, q, control->used, - b43_loctl_is_calibrated(control), - is_initializing); -} -static void validate_all_loctls(struct b43_wldev *dev) -{ - b43_call_for_each_loctl(dev, do_validate_loctl); -} - -static void do_reset_calib(struct b43_wldev *dev, struct b43_loctl *control) -{ - if (dev->phy.lo_control->rebuild || - control->used) { - b43_loctl_set_calibrated(control, 0); - control->i = B43_LOCTL_POISON; - control->q = B43_LOCTL_POISON; + cal = kmalloc(sizeof(*cal), GFP_KERNEL); + if (!cal) { + b43warn(dev->wl, "LO calib: out of memory\n"); + return NULL; } + memcpy(&cal->bbatt, bbatt, sizeof(*bbatt)); + memcpy(&cal->rfatt, rfatt, sizeof(*rfatt)); + memcpy(&cal->ctl, &loctl, sizeof(loctl)); + cal->calib_time = jiffies; + INIT_LIST_HEAD(&cal->list); + + return cal; } -static void reset_all_loctl_calibration_states(struct b43_wldev *dev) +/* Get a calibrated LO setting for the given attenuation values. + * Might return a NULL pointer under OOM! */ +static +struct b43_lo_calib * b43_get_calib_lo_settings(struct b43_wldev *dev, + const struct b43_bbatt *bbatt, + const struct b43_rfatt *rfatt) { - b43_call_for_each_loctl(dev, do_reset_calib); + struct b43_txpower_lo_control *lo = dev->phy.lo_control; + struct b43_lo_calib *c; + + c = b43_find_lo_calib(lo, bbatt, rfatt); + if (c) + return c; + /* Not in the list of calibrated LO settings. + * Calibrate it now. */ + c = b43_calibrate_lo_setting(dev, bbatt, rfatt); + if (!c) + return NULL; + list_add(&c->list, &lo->calib_list); + + return c; } -#else /* B43_DEBUG */ -static inline void validate_all_loctls(struct b43_wldev *dev) { } -static inline void reset_all_loctl_calibration_states(struct b43_wldev *dev) { } -#endif /* B43_DEBUG */ - -void b43_lo_g_measure(struct b43_wldev *dev) +void b43_gphy_dc_lt_init(struct b43_wldev *dev, bool update_all) { struct b43_phy *phy = &dev->phy; - struct lo_g_saved_values uninitialized_var(sav); - - B43_WARN_ON((phy->type != B43_PHYTYPE_B) && - (phy->type != B43_PHYTYPE_G)); - - sav.old_channel = phy->channel; - lo_measure_setup(dev, &sav); - reset_all_loctl_calibration_states(dev); - lo_measure(dev); - lo_measure_restore(dev, &sav); - - validate_all_loctls(dev); + struct b43_txpower_lo_control *lo = phy->lo_control; + int i; + int rf_offset, bb_offset; + const struct b43_rfatt *rfatt; + const struct b43_bbatt *bbatt; + u64 power_vector; + bool table_changed = 0; - phy->lo_control->lo_measured = 1; - phy->lo_control->rebuild = 0; -} + BUILD_BUG_ON(B43_DC_LT_SIZE != 32); + B43_WARN_ON(lo->rfatt_list.len * lo->bbatt_list.len > 64); -#if B43_DEBUG -static void validate_loctl_calibration(struct b43_wldev *dev, - struct b43_loctl *loctl, - struct b43_rfatt *rfatt, - struct b43_bbatt *bbatt) -{ - if (b43_loctl_is_calibrated(loctl)) - return; - if (!dev->phy.lo_control->lo_measured) { - /* On init we set the attenuation values before we - * calibrated the LO. I guess that's OK. */ - return; + power_vector = lo->power_vector; + if (!update_all && !power_vector) + return; /* Nothing to do. */ + + /* Suspend the MAC now to avoid continuous suspend/enable + * cycles in the loop. */ + b43_mac_suspend(dev); + + for (i = 0; i < B43_DC_LT_SIZE * 2; i++) { + struct b43_lo_calib *cal; + int idx; + u16 val; + + if (!update_all && !(power_vector & (((u64)1ULL) << i))) + continue; + /* Update the table entry for this power_vector bit. + * The table rows are RFatt entries and columns are BBatt. */ + bb_offset = i / lo->rfatt_list.len; + rf_offset = i % lo->rfatt_list.len; + bbatt = &(lo->bbatt_list.list[bb_offset]); + rfatt = &(lo->rfatt_list.list[rf_offset]); + + cal = b43_calibrate_lo_setting(dev, bbatt, rfatt); + if (!cal) { + b43warn(dev->wl, "LO: Could not " + "calibrate DC table entry\n"); + continue; + } + /*FIXME: Is Q really in the low nibble? */ + val = (u8)(cal->ctl.q); + val |= ((u8)(cal->ctl.i)) << 4; + kfree(cal); + + /* Get the index into the hardware DC LT. */ + idx = i / 2; + /* Change the table in memory. */ + if (i % 2) { + /* Change the high byte. */ + lo->dc_lt[idx] = (lo->dc_lt[idx] & 0x00FF) + | ((val & 0x00FF) << 8); + } else { + /* Change the low byte. */ + lo->dc_lt[idx] = (lo->dc_lt[idx] & 0xFF00) + | (val & 0x00FF); + } + table_changed = 1; } - b43err(dev->wl, "Adjusting Local Oscillator to an uncalibrated " - "control pair: rfatt=%u,%spadmix bbatt=%u\n", - rfatt->att, - (rfatt->with_padmix) ? "" : "no-", - bbatt->att); -} -#else -static inline void validate_loctl_calibration(struct b43_wldev *dev, - struct b43_loctl *loctl, - struct b43_rfatt *rfatt, - struct b43_bbatt *bbatt) -{ + if (table_changed) { + /* The table changed in memory. Update the hardware table. */ + for (i = 0; i < B43_DC_LT_SIZE; i++) + b43_phy_write(dev, 0x3A0 + i, lo->dc_lt[i]); + } + b43_mac_enable(dev); } -#endif -static inline void fixup_rfatt_for_txcontrol(struct b43_rfatt *rf, - u8 tx_control) +/* Fixup the RF attenuation value for the case where we are + * using the PAD mixer. */ +static inline void b43_lo_fixup_rfatt(struct b43_rfatt *rf) { - if (tx_control & B43_TXCTL_TXMIX) { - if (rf->att < 5) - rf->att = 4; - } + if (!rf->with_padmix) + return; + if ((rf->att != 1) && (rf->att != 2) && (rf->att != 3)) + rf->att = 4; } void b43_lo_g_adjust(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; + struct b43_lo_calib *cal; struct b43_rfatt rf; - struct b43_loctl *loctl; memcpy(&rf, &phy->rfatt, sizeof(rf)); - fixup_rfatt_for_txcontrol(&rf, phy->tx_control); + b43_lo_fixup_rfatt(&rf); - loctl = b43_get_lo_g_ctl(dev, &rf, &phy->bbatt); - validate_loctl_calibration(dev, loctl, &rf, &phy->bbatt); - b43_lo_write(dev, loctl); + cal = b43_get_calib_lo_settings(dev, &phy->bbatt, &rf); + if (!cal) + return; + b43_lo_write(dev, &cal->ctl); } void b43_lo_g_adjust_to(struct b43_wldev *dev, @@ -1223,39 +937,102 @@ void b43_lo_g_adjust_to(struct b43_wldev *dev, { struct b43_rfatt rf; struct b43_bbatt bb; - struct b43_loctl *loctl; + struct b43_lo_calib *cal; memset(&rf, 0, sizeof(rf)); memset(&bb, 0, sizeof(bb)); rf.att = rfatt; bb.att = bbatt; - fixup_rfatt_for_txcontrol(&rf, tx_control); - loctl = b43_get_lo_g_ctl(dev, &rf, &bb); - validate_loctl_calibration(dev, loctl, &rf, &bb); - b43_lo_write(dev, loctl); + b43_lo_fixup_rfatt(&rf); + cal = b43_get_calib_lo_settings(dev, &bb, &rf); + if (!cal) + return; + b43_lo_write(dev, &cal->ctl); } -static void do_mark_unused(struct b43_wldev *dev, struct b43_loctl *control) +/* Periodic LO maintanance work */ +void b43_lo_g_maintanance_work(struct b43_wldev *dev) { - control->used = 0; + struct b43_phy *phy = &dev->phy; + struct b43_txpower_lo_control *lo = phy->lo_control; + unsigned long now; + unsigned long expire; + struct b43_lo_calib *cal, *tmp; + bool current_item_expired = 0; + bool hwpctl; + + if (!lo) + return; + now = jiffies; + hwpctl = b43_has_hardware_pctl(phy); + + if (hwpctl) { + /* Read the power vector and update it, if needed. */ + expire = now - B43_LO_PWRVEC_EXPIRE; + if (time_before(lo->pwr_vec_read_time, expire)) { + lo_read_power_vector(dev); + b43_gphy_dc_lt_init(dev, 0); + } + //FIXME Recalc the whole DC table from time to time? + } + + if (hwpctl) + return; + /* Search for expired LO settings. Remove them. + * Recalibrate the current setting, if expired. */ + expire = now - B43_LO_CALIB_EXPIRE; + list_for_each_entry_safe(cal, tmp, &lo->calib_list, list) { + if (!time_before(cal->calib_time, expire)) + continue; + /* This item expired. */ + if (b43_compare_bbatt(&cal->bbatt, &phy->bbatt) && + b43_compare_rfatt(&cal->rfatt, &phy->rfatt)) { + B43_WARN_ON(current_item_expired); + current_item_expired = 1; + } + if (b43_debug(dev, B43_DBG_LO)) { + b43dbg(dev->wl, "LO: Item BB(%u), RF(%u,%u), " + "I=%d, Q=%d expired\n", + cal->bbatt.att, cal->rfatt.att, + cal->rfatt.with_padmix, + cal->ctl.i, cal->ctl.q); + } + list_del(&cal->list); + kfree(cal); + } + if (current_item_expired || unlikely(list_empty(&lo->calib_list))) { + /* Recalibrate currently used LO setting. */ + if (b43_debug(dev, B43_DBG_LO)) + b43dbg(dev->wl, "LO: Recalibrating current LO setting\n"); + cal = b43_calibrate_lo_setting(dev, &phy->bbatt, &phy->rfatt); + if (cal) { + list_add(&cal->list, &lo->calib_list); + b43_lo_write(dev, &cal->ctl); + } else + b43warn(dev->wl, "Failed to recalibrate current LO setting\n"); + } } -void b43_lo_g_ctl_mark_all_unused(struct b43_wldev *dev) +void b43_lo_g_cleanup(struct b43_wldev *dev) { - struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; + struct b43_txpower_lo_control *lo = dev->phy.lo_control; + struct b43_lo_calib *cal, *tmp; - b43_call_for_each_loctl(dev, do_mark_unused); - lo->rebuild = 1; + if (!lo) + return; + list_for_each_entry_safe(cal, tmp, &lo->calib_list, list) { + list_del(&cal->list); + kfree(cal); + } } -void b43_lo_g_ctl_mark_cur_used(struct b43_wldev *dev) +/* LO Initialization */ +void b43_lo_g_init(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; - struct b43_rfatt rf; - memcpy(&rf, &phy->rfatt, sizeof(rf)); - fixup_rfatt_for_txcontrol(&rf, phy->tx_control); - - b43_get_lo_g_ctl(dev, &rf, &phy->bbatt)->used = 1; + if (b43_has_hardware_pctl(phy)) { + lo_read_power_vector(dev); + b43_gphy_dc_lt_init(dev, 1); + } } diff --git a/drivers/net/wireless/b43/lo.h b/drivers/net/wireless/b43/lo.h index 455615d1f8c..1da321cabc1 100644 --- a/drivers/net/wireless/b43/lo.h +++ b/drivers/net/wireless/b43/lo.h @@ -10,82 +10,63 @@ struct b43_loctl { /* Control values. */ s8 i; s8 q; - /* "Used by hardware" flag. */ - bool used; -#ifdef CONFIG_B43_DEBUG - /* Is this lo-control-array entry calibrated? */ - bool calibrated; -#endif }; - /* Debugging: Poison value for i and q values. */ #define B43_LOCTL_POISON 111 -/* loctl->calibrated debugging mechanism */ -#ifdef CONFIG_B43_DEBUG -static inline void b43_loctl_set_calibrated(struct b43_loctl *loctl, - bool calibrated) -{ - loctl->calibrated = calibrated; -} -static inline bool b43_loctl_is_calibrated(struct b43_loctl *loctl) -{ - return loctl->calibrated; -} -#else -static inline void b43_loctl_set_calibrated(struct b43_loctl *loctl, - bool calibrated) -{ -} -static inline bool b43_loctl_is_calibrated(struct b43_loctl *loctl) -{ - return 1; -} -#endif - -/* TX Power LO Control Array. - * Value-pairs to adjust the LocalOscillator are stored - * in this structure. - * There are two different set of values. One for "Flag is Set" - * and one for "Flag is Unset". - * By "Flag" the flag in struct b43_rfatt is meant. - * The Value arrays are two-dimensional. The first index - * is the baseband attenuation and the second index - * is the radio attenuation. - * Use b43_get_lo_g_ctl() to retrieve a value from the lists. - */ +/* This struct holds calibrated LO settings for a set of + * Baseband and RF attenuation settings. */ +struct b43_lo_calib { + /* The set of attenuation values this set of LO + * control values is calibrated for. */ + struct b43_bbatt bbatt; + struct b43_rfatt rfatt; + /* The set of control values for the LO. */ + struct b43_loctl ctl; + /* The time when these settings were calibrated (in jiffies) */ + unsigned long calib_time; + /* List. */ + struct list_head list; +}; + +/* Size of the DC Lookup Table in 16bit words. */ +#define B43_DC_LT_SIZE 32 + +/* Local Oscillator calibration information */ struct b43_txpower_lo_control { -#define B43_NR_BB 12 -#define B43_NR_RF 16 - /* LO Control values, with PAD Mixer */ - struct b43_loctl with_padmix[B43_NR_BB][B43_NR_RF]; - /* LO Control values, without PAD Mixer */ - struct b43_loctl no_padmix[B43_NR_BB][B43_NR_RF]; - - /* Flag to indicate a complete rebuild of the two tables above - * to the LO measuring code. */ - bool rebuild; - - /* Lists of valid RF and BB attenuation values for this device. */ + /* Lists of RF and BB attenuation values for this device. + * Used for building hardware power control tables. */ struct b43_rfatt_list rfatt_list; struct b43_bbatt_list bbatt_list; + /* The DC Lookup Table is cached in memory here. + * Note that this is only used for Hardware Power Control. */ + u16 dc_lt[B43_DC_LT_SIZE]; + + /* List of calibrated control values (struct b43_lo_calib). */ + struct list_head calib_list; + /* Last time the power vector was read (jiffies). */ + unsigned long pwr_vec_read_time; + /* Last time the txctl values were measured (jiffies). */ + unsigned long txctl_measured_time; + /* Current TX Bias value */ u8 tx_bias; /* Current TX Magnification Value (if used by the device) */ u8 tx_magn; - /* GPHY LO is measured. */ - bool lo_measured; - /* Saved device PowerVector */ u64 power_vector; }; -/* Measure the BPHY Local Oscillator. */ -void b43_lo_b_measure(struct b43_wldev *dev); -/* Measure the BPHY/GPHY Local Oscillator. */ -void b43_lo_g_measure(struct b43_wldev *dev); +/* Calibration expire timeouts. + * Timeouts must be multiple of 15 seconds. To make sure + * the item really expired when the 15 second timer hits, we + * subtract two additional seconds from the timeout. */ +#define B43_LO_CALIB_EXPIRE (HZ * (30 - 2)) +#define B43_LO_PWRVEC_EXPIRE (HZ * (30 - 2)) +#define B43_LO_TXCTL_EXPIRE (HZ * (180 - 4)) + /* Adjust the Local Oscillator to the saved attenuation * and txctl values. @@ -95,18 +76,10 @@ void b43_lo_g_adjust(struct b43_wldev *dev); void b43_lo_g_adjust_to(struct b43_wldev *dev, u16 rfatt, u16 bbatt, u16 tx_control); -/* Mark all possible b43_lo_g_ctl as "unused" */ -void b43_lo_g_ctl_mark_all_unused(struct b43_wldev *dev); -/* Mark the b43_lo_g_ctl corresponding to the current - * attenuation values as used. - */ -void b43_lo_g_ctl_mark_cur_used(struct b43_wldev *dev); +void b43_gphy_dc_lt_init(struct b43_wldev *dev, bool update_all); -/* Get a reference to a LO Control value pair in the - * TX Power LO Control Array. - */ -struct b43_loctl *b43_get_lo_g_ctl(struct b43_wldev *dev, - const struct b43_rfatt *rfatt, - const struct b43_bbatt *bbatt); +void b43_lo_g_maintanance_work(struct b43_wldev *dev); +void b43_lo_g_cleanup(struct b43_wldev *dev); +void b43_lo_g_init(struct b43_wldev *dev); #endif /* B43_LO_H_ */ diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 8fdba9415c0..e3d8555d4a9 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -2308,7 +2308,7 @@ static void b43_gpio_cleanup(struct b43_wldev *dev) } /* http://bcm-specs.sipsolutions.net/EnableMac */ -static void b43_mac_enable(struct b43_wldev *dev) +void b43_mac_enable(struct b43_wldev *dev) { dev->mac_suspended--; B43_WARN_ON(dev->mac_suspended < 0); @@ -2331,7 +2331,7 @@ static void b43_mac_enable(struct b43_wldev *dev) } /* http://bcm-specs.sipsolutions.net/SuspendMAC */ -static void b43_mac_suspend(struct b43_wldev *dev) +void b43_mac_suspend(struct b43_wldev *dev) { int i; u32 tmp; @@ -2503,6 +2503,7 @@ static void b43_chip_exit(struct b43_wldev *dev) { b43_radio_turn_off(dev, 1); b43_gpio_cleanup(dev); + b43_lo_g_cleanup(dev); /* firmware is released later */ } @@ -2609,28 +2610,12 @@ err_gpio_clean: return err; } -static void b43_periodic_every120sec(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - - if (phy->type != B43_PHYTYPE_G || phy->rev < 2) - return; - - b43_mac_suspend(dev); - b43_lo_g_measure(dev); - b43_mac_enable(dev); - if (b43_has_hardware_pctl(phy)) - b43_lo_g_ctl_mark_all_unused(dev); -} - static void b43_periodic_every60sec(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; if (phy->type != B43_PHYTYPE_G) return; - if (!b43_has_hardware_pctl(phy)) - b43_lo_g_ctl_mark_all_unused(dev); if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) { b43_mac_suspend(dev); b43_calc_nrssi_slope(dev); @@ -2682,6 +2667,7 @@ static void b43_periodic_every15sec(struct b43_wldev *dev) } } b43_phy_xmitpower(dev); //FIXME: unless scanning? + b43_lo_g_maintanance_work(dev); //TODO for APHY (temperature?) atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT); @@ -2693,8 +2679,6 @@ static void do_periodic_work(struct b43_wldev *dev) unsigned int state; state = dev->periodic_state; - if (state % 8 == 0) - b43_periodic_every120sec(dev); if (state % 4 == 0) b43_periodic_every60sec(dev); if (state % 2 == 0) @@ -3668,8 +3652,8 @@ static void setup_struct_phy_for_init(struct b43_wldev *dev, lo = phy->lo_control; if (lo) { memset(lo, 0, sizeof(*(phy->lo_control))); - lo->rebuild = 1; lo->tx_bias = 0xFF; + INIT_LIST_HEAD(&lo->calib_list); } phy->max_lb_gain = 0; phy->trsw_rx_gain = 0; diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h index 5230aeca78b..dad23c42b42 100644 --- a/drivers/net/wireless/b43/main.h +++ b/drivers/net/wireless/b43/main.h @@ -114,4 +114,7 @@ void b43_controller_restart(struct b43_wldev *dev, const char *reason); #define B43_PS_ASLEEP (1 << 3) /* Force device asleep */ void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags); +void b43_mac_suspend(struct b43_wldev *dev); +void b43_mac_enable(struct b43_wldev *dev); + #endif /* B43_MAIN_H_ */ diff --git a/drivers/net/wireless/b43/phy.c b/drivers/net/wireless/b43/phy.c index de024dc0371..fd1f301748c 100644 --- a/drivers/net/wireless/b43/phy.c +++ b/drivers/net/wireless/b43/phy.c @@ -145,8 +145,7 @@ static void generate_rfatt_list(struct b43_wldev *dev, {.att = 9,.with_padmix = 1,}, }; - if ((phy->type == B43_PHYTYPE_A && phy->rev < 5) || - (phy->type == B43_PHYTYPE_G && phy->rev < 6)) { + if (!b43_has_hardware_pctl(phy)) { /* Software pctl */ list->list = rfatt_0; list->len = ARRAY_SIZE(rfatt_0); @@ -158,7 +157,7 @@ static void generate_rfatt_list(struct b43_wldev *dev, /* Hardware pctl */ list->list = rfatt_1; list->len = ARRAY_SIZE(rfatt_1); - list->min_val = 2; + list->min_val = 0; list->max_val = 14; return; } @@ -346,6 +345,7 @@ void b43_set_txpower_g(struct b43_wldev *dev, /* Save the values for later */ phy->tx_control = tx_control; memcpy(&phy->rfatt, rfatt, sizeof(*rfatt)); + phy->rfatt.with_padmix = !!(tx_control & B43_TXCTL_TXMIX); memcpy(&phy->bbatt, bbatt, sizeof(*bbatt)); if (b43_debug(dev, B43_DBG_XMITPOWER)) { @@ -559,11 +559,6 @@ static void b43_gphy_gain_lt_init(struct b43_wldev *dev) u16 tmp; u8 rf, bb; - if (!lo->lo_measured) { - b43_phy_write(dev, 0x3FF, 0); - return; - } - for (rf = 0; rf < lo->rfatt_list.len; rf++) { for (bb = 0; bb < lo->bbatt_list.len; bb++) { if (nr_written >= 0x40) @@ -581,42 +576,6 @@ static void b43_gphy_gain_lt_init(struct b43_wldev *dev) } } -/* GPHY_DC_Lookup_Table */ -void b43_gphy_dc_lt_init(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; - struct b43_loctl *loctl0; - struct b43_loctl *loctl1; - int i; - int rf_offset, bb_offset; - u16 tmp; - - for (i = 0; i < lo->rfatt_list.len + lo->bbatt_list.len; i += 2) { - rf_offset = i / lo->rfatt_list.len; - bb_offset = i % lo->rfatt_list.len; - - loctl0 = b43_get_lo_g_ctl(dev, &lo->rfatt_list.list[rf_offset], - &lo->bbatt_list.list[bb_offset]); - if (i + 1 < lo->rfatt_list.len * lo->bbatt_list.len) { - rf_offset = (i + 1) / lo->rfatt_list.len; - bb_offset = (i + 1) % lo->rfatt_list.len; - - loctl1 = - b43_get_lo_g_ctl(dev, - &lo->rfatt_list.list[rf_offset], - &lo->bbatt_list.list[bb_offset]); - } else - loctl1 = loctl0; - - tmp = ((u16) loctl0->q & 0xF); - tmp |= ((u16) loctl0->i & 0xF) << 4; - tmp |= ((u16) loctl1->q & 0xF) << 8; - tmp |= ((u16) loctl1->i & 0xF) << 12; //FIXME? - b43_phy_write(dev, 0x3A0 + (i / 2), tmp); - } -} - static void hardware_pctl_init_aphy(struct b43_wldev *dev) { //TODO @@ -643,7 +602,7 @@ static void hardware_pctl_init_gphy(struct b43_wldev *dev) b43_phy_write(dev, 0x0801, b43_phy_read(dev, 0x0801) & 0xFFBF); - b43_gphy_dc_lt_init(dev); + b43_gphy_dc_lt_init(dev, 1); } /* HardwarePowerControl init for A and G PHY */ @@ -967,7 +926,7 @@ static void b43_phy_initb2(struct b43_wldev *dev) b43_phy_write(dev, 0x0032, 0x00CA); b43_phy_write(dev, 0x0032, 0x00CC); b43_phy_write(dev, 0x0035, 0x07C2); - b43_lo_b_measure(dev); +//XXX won't trigger b43_lo_b_measure(dev); b43_phy_write(dev, 0x0026, 0xCC00); if (phy->radio_ver != 0x2050) b43_phy_write(dev, 0x0026, 0xCE00); @@ -1017,7 +976,7 @@ static void b43_phy_initb4(struct b43_wldev *dev) b43_phy_write(dev, 0x0032, 0x00E0); b43_phy_write(dev, 0x0035, 0x07C2); - b43_lo_b_measure(dev); +//XXX won't trigger b43_lo_b_measure(dev); b43_phy_write(dev, 0x0026, 0xCC00); if (phy->radio_ver == 0x2050) @@ -1259,19 +1218,9 @@ static void b43_phy_initb6(struct b43_wldev *dev) b43_phy_write(dev, 0x0002, (b43_phy_read(dev, 0x0002) & 0xFFC0) | 0x0004); } - if (phy->type == B43_PHYTYPE_B) { - b43_write16(dev, 0x03E6, 0x8140); - b43_phy_write(dev, 0x0016, 0x0410); - b43_phy_write(dev, 0x0017, 0x0820); - b43_phy_write(dev, 0x0062, 0x0007); - b43_radio_init2050(dev); - b43_lo_g_measure(dev); - if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) { - b43_calc_nrssi_slope(dev); - b43_calc_nrssi_threshold(dev); - } - b43_phy_init_pctl(dev); - } else if (phy->type == B43_PHYTYPE_G) + if (phy->type == B43_PHYTYPE_B) + B43_WARN_ON(1); + else if (phy->type == B43_PHYTYPE_G) b43_write16(dev, 0x03E6, 0x0); } @@ -1534,34 +1483,31 @@ static void b43_phy_initg(struct b43_wldev *dev) else b43_radio_write16(dev, 0x0078, phy->initval); } - if (phy->lo_control->tx_bias == 0xFF) { - b43_lo_g_measure(dev); + b43_lo_g_init(dev); + if (has_tx_magnification(phy)) { + b43_radio_write16(dev, 0x52, + (b43_radio_read16(dev, 0x52) & 0xFF00) + | phy->lo_control->tx_bias | phy-> + lo_control->tx_magn); } else { - if (has_tx_magnification(phy)) { - b43_radio_write16(dev, 0x52, - (b43_radio_read16(dev, 0x52) & 0xFF00) - | phy->lo_control->tx_bias | phy-> - lo_control->tx_magn); - } else { - b43_radio_write16(dev, 0x52, - (b43_radio_read16(dev, 0x52) & 0xFFF0) - | phy->lo_control->tx_bias); - } - if (phy->rev >= 6) { - b43_phy_write(dev, B43_PHY_CCK(0x36), - (b43_phy_read(dev, B43_PHY_CCK(0x36)) - & 0x0FFF) | (phy->lo_control-> - tx_bias << 12)); - } - if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) - b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8075); - else - b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x807F); - if (phy->rev < 2) - b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x101); - else - b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x202); + b43_radio_write16(dev, 0x52, + (b43_radio_read16(dev, 0x52) & 0xFFF0) + | phy->lo_control->tx_bias); } + if (phy->rev >= 6) { + b43_phy_write(dev, B43_PHY_CCK(0x36), + (b43_phy_read(dev, B43_PHY_CCK(0x36)) + & 0x0FFF) | (phy->lo_control-> + tx_bias << 12)); + } + if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) + b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8075); + else + b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x807F); + if (phy->rev < 2) + b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x101); + else + b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x202); if (phy->gmode || phy->rev >= 2) { b43_lo_g_adjust(dev); b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078); @@ -1821,10 +1767,8 @@ void b43_phy_xmitpower(struct b43_wldev *dev) bbatt_delta -= 4 * rfatt_delta; /* So do we finally need to adjust something? */ - if ((rfatt_delta == 0) && (bbatt_delta == 0)) { - b43_lo_g_ctl_mark_cur_used(dev); + if ((rfatt_delta == 0) && (bbatt_delta == 0)) return; - } /* Calculate the new attenuation values. */ bbatt = phy->bbatt.att; @@ -1870,7 +1814,6 @@ void b43_phy_xmitpower(struct b43_wldev *dev) b43_radio_lock(dev); b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control); - b43_lo_g_ctl_mark_cur_used(dev); b43_radio_unlock(dev); b43_phy_unlock(dev); break; diff --git a/drivers/net/wireless/b43/phy.h b/drivers/net/wireless/b43/phy.h index 6d165d82217..4aab1090352 100644 --- a/drivers/net/wireless/b43/phy.h +++ b/drivers/net/wireless/b43/phy.h @@ -225,7 +225,6 @@ int b43_phy_init(struct b43_wldev *dev); void b43_set_rx_antenna(struct b43_wldev *dev, int antenna); void b43_phy_xmitpower(struct b43_wldev *dev); -void b43_gphy_dc_lt_init(struct b43_wldev *dev); /* Returns the boolean whether the board has HardwarePowerControl */ bool b43_has_hardware_pctl(struct b43_phy *phy); @@ -252,6 +251,14 @@ struct b43_rfatt_list { u8 max_val; }; +/* Returns true, if the values are the same. */ +static inline bool b43_compare_rfatt(const struct b43_rfatt *a, + const struct b43_rfatt *b) +{ + return ((a->att == b->att) && + (a->with_padmix == b->with_padmix)); +} + /* Baseband Attenuation */ struct b43_bbatt { u8 att; /* Attenuation value */ @@ -265,6 +272,13 @@ struct b43_bbatt_list { u8 max_val; }; +/* Returns true, if the values are the same. */ +static inline bool b43_compare_bbatt(const struct b43_bbatt *a, + const struct b43_bbatt *b) +{ + return (a->att == b->att); +} + /* tx_control bits. */ #define B43_TXCTL_PA3DB 0x40 /* PA Gain 3dB */ #define B43_TXCTL_PA2DB 0x20 /* PA Gain 2dB */ -- cgit v1.2.3-70-g09d2 From f4440e8a47e216adfe32d96a35bef6d13d498b58 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 20 Apr 2008 16:23:26 +0200 Subject: b43: Remove some dead code This patch removes some dead code from the driver. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/lo.c | 6 +- drivers/net/wireless/b43/phy.c | 121 ----------------------------------------- 2 files changed, 2 insertions(+), 125 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/lo.c b/drivers/net/wireless/b43/lo.c index 4edee6da2b8..4ce1e356120 100644 --- a/drivers/net/wireless/b43/lo.c +++ b/drivers/net/wireless/b43/lo.c @@ -58,7 +58,6 @@ static void b43_lo_write(struct b43_wldev *dev, struct b43_loctl *control) { struct b43_phy *phy = &dev->phy; u16 value; - u16 reg; if (B43_DEBUG) { if (unlikely(abs(control->i) > 16 || abs(control->q) > 16)) { @@ -68,12 +67,11 @@ static void b43_lo_write(struct b43_wldev *dev, struct b43_loctl *control) return; } } + B43_WARN_ON(phy->type != B43_PHYTYPE_G); value = (u8) (control->q); value |= ((u8) (control->i)) << 8; - - reg = (phy->type == B43_PHYTYPE_B) ? 0x002F : B43_PHY_LO_CTL; - b43_phy_write(dev, reg, value); + b43_phy_write(dev, B43_PHY_LO_CTL, value); } static u16 lo_measure_feedthrough(struct b43_wldev *dev, diff --git a/drivers/net/wireless/b43/phy.c b/drivers/net/wireless/b43/phy.c index fd1f301748c..8b3c24da8db 100644 --- a/drivers/net/wireless/b43/phy.c +++ b/drivers/net/wireless/b43/phy.c @@ -890,109 +890,6 @@ static void b43_phy_inita(struct b43_wldev *dev) } } -static void b43_phy_initb2(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - u16 offset, val; - - b43_write16(dev, 0x03EC, 0x3F22); - b43_phy_write(dev, 0x0020, 0x301C); - b43_phy_write(dev, 0x0026, 0x0000); - b43_phy_write(dev, 0x0030, 0x00C6); - b43_phy_write(dev, 0x0088, 0x3E00); - val = 0x3C3D; - for (offset = 0x0089; offset < 0x00A7; offset++) { - b43_phy_write(dev, offset, val); - val -= 0x0202; - } - b43_phy_write(dev, 0x03E4, 0x3000); - b43_radio_selectchannel(dev, phy->channel, 0); - if (phy->radio_ver != 0x2050) { - b43_radio_write16(dev, 0x0075, 0x0080); - b43_radio_write16(dev, 0x0079, 0x0081); - } - b43_radio_write16(dev, 0x0050, 0x0020); - b43_radio_write16(dev, 0x0050, 0x0023); - if (phy->radio_ver == 0x2050) { - b43_radio_write16(dev, 0x0050, 0x0020); - b43_radio_write16(dev, 0x005A, 0x0070); - b43_radio_write16(dev, 0x005B, 0x007B); - b43_radio_write16(dev, 0x005C, 0x00B0); - b43_radio_write16(dev, 0x007A, 0x000F); - b43_phy_write(dev, 0x0038, 0x0677); - b43_radio_init2050(dev); - } - b43_phy_write(dev, 0x0014, 0x0080); - b43_phy_write(dev, 0x0032, 0x00CA); - b43_phy_write(dev, 0x0032, 0x00CC); - b43_phy_write(dev, 0x0035, 0x07C2); -//XXX won't trigger b43_lo_b_measure(dev); - b43_phy_write(dev, 0x0026, 0xCC00); - if (phy->radio_ver != 0x2050) - b43_phy_write(dev, 0x0026, 0xCE00); - b43_write16(dev, B43_MMIO_CHANNEL_EXT, 0x1000); - b43_phy_write(dev, 0x002A, 0x88A3); - if (phy->radio_ver != 0x2050) - b43_phy_write(dev, 0x002A, 0x88C2); - b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control); - b43_phy_init_pctl(dev); -} - -static void b43_phy_initb4(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - u16 offset, val; - - b43_write16(dev, 0x03EC, 0x3F22); - b43_phy_write(dev, 0x0020, 0x301C); - b43_phy_write(dev, 0x0026, 0x0000); - b43_phy_write(dev, 0x0030, 0x00C6); - b43_phy_write(dev, 0x0088, 0x3E00); - val = 0x3C3D; - for (offset = 0x0089; offset < 0x00A7; offset++) { - b43_phy_write(dev, offset, val); - val -= 0x0202; - } - b43_phy_write(dev, 0x03E4, 0x3000); - b43_radio_selectchannel(dev, phy->channel, 0); - if (phy->radio_ver != 0x2050) { - b43_radio_write16(dev, 0x0075, 0x0080); - b43_radio_write16(dev, 0x0079, 0x0081); - } - b43_radio_write16(dev, 0x0050, 0x0020); - b43_radio_write16(dev, 0x0050, 0x0023); - if (phy->radio_ver == 0x2050) { - b43_radio_write16(dev, 0x0050, 0x0020); - b43_radio_write16(dev, 0x005A, 0x0070); - b43_radio_write16(dev, 0x005B, 0x007B); - b43_radio_write16(dev, 0x005C, 0x00B0); - b43_radio_write16(dev, 0x007A, 0x000F); - b43_phy_write(dev, 0x0038, 0x0677); - b43_radio_init2050(dev); - } - b43_phy_write(dev, 0x0014, 0x0080); - b43_phy_write(dev, 0x0032, 0x00CA); - if (phy->radio_ver == 0x2050) - b43_phy_write(dev, 0x0032, 0x00E0); - b43_phy_write(dev, 0x0035, 0x07C2); - -//XXX won't trigger b43_lo_b_measure(dev); - - b43_phy_write(dev, 0x0026, 0xCC00); - if (phy->radio_ver == 0x2050) - b43_phy_write(dev, 0x0026, 0xCE00); - b43_write16(dev, B43_MMIO_CHANNEL_EXT, 0x1100); - b43_phy_write(dev, 0x002A, 0x88A3); - if (phy->radio_ver == 0x2050) - b43_phy_write(dev, 0x002A, 0x88C2); - b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control); - if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) { - b43_calc_nrssi_slope(dev); - b43_calc_nrssi_threshold(dev); - } - b43_phy_init_pctl(dev); -} - static void b43_phy_initb5(struct b43_wldev *dev) { struct ssb_bus *bus = dev->dev->bus; @@ -1950,24 +1847,6 @@ int b43_phy_init(struct b43_wldev *dev) else unsupported = 1; break; - case B43_PHYTYPE_B: - switch (phy->rev) { - case 2: - b43_phy_initb2(dev); - break; - case 4: - b43_phy_initb4(dev); - break; - case 5: - b43_phy_initb5(dev); - break; - case 6: - b43_phy_initb6(dev); - break; - default: - unsupported = 1; - } - break; case B43_PHYTYPE_G: b43_phy_initg(dev); break; -- cgit v1.2.3-70-g09d2 From 5da4b55f78fb2ed40926b775d4f7c791594ecbd7 Mon Sep 17 00:00:00 2001 From: Mohamed Abbas Date: Mon, 21 Apr 2008 15:41:51 -0700 Subject: iwlwifi: Add power level support Add power level support Signed-off-by: Mohamed Abbas Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/Makefile | 2 +- drivers/net/wireless/iwlwifi/iwl-4965-commands.h | 1 + drivers/net/wireless/iwlwifi/iwl-4965.c | 15 +- drivers/net/wireless/iwlwifi/iwl-4965.h | 29 +- drivers/net/wireless/iwlwifi/iwl-core.c | 3 + drivers/net/wireless/iwlwifi/iwl-core.h | 3 + drivers/net/wireless/iwlwifi/iwl-power.c | 423 +++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-power.h | 76 ++++ drivers/net/wireless/iwlwifi/iwl4965-base.c | 217 ++---------- 9 files changed, 543 insertions(+), 226 deletions(-) create mode 100644 drivers/net/wireless/iwlwifi/iwl-power.c create mode 100644 drivers/net/wireless/iwlwifi/iwl-power.h (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 7bc569be4ba..e2c05f5346e 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -1,5 +1,5 @@ obj-$(CONFIG_IWLCORE) += iwlcore.o -iwlcore-objs := iwl-core.o iwl-eeprom.o iwl-hcmd.o +iwlcore-objs := iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.o iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o iwlcore-$(CONFIG_IWLWIFI_LEDS) += iwl-led.o iwlcore-$(CONFIG_IWLWIFI_RFKILL) += iwl-rfkill.o diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-commands.h b/drivers/net/wireless/iwlwifi/iwl-4965-commands.h index c03c04fe14c..b2fa58d2d17 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-commands.h @@ -1853,6 +1853,7 @@ struct iwl4965_spectrum_notification { #define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK __constant_cpu_to_le16(1 << 0) #define IWL_POWER_SLEEP_OVER_DTIM_MSK __constant_cpu_to_le16(1 << 2) #define IWL_POWER_PCI_PM_MSK __constant_cpu_to_le16(1 << 3) +#define IWL_POWER_FAST_PD __constant_cpu_to_le16(1 << 4) struct iwl4965_powertable_cmd { __le16 flags; diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 2b9471f1686..d051aac558f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -702,8 +702,6 @@ int iwl4965_hw_nic_init(struct iwl_priv *priv) u32 val; u8 val_link; - iwl4965_power_init_handle(priv); - /* nic_init */ spin_lock_irqsave(&priv->lock, flags); @@ -1433,6 +1431,17 @@ int iwl4965_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl4965_tx_queue *txq) return 0; } +/* set card power command */ +static int iwl4965_set_power(struct iwl_priv *priv, + void *cmd) +{ + int ret = 0; + + ret = iwl_send_cmd_pdu_async(priv, POWER_TABLE_CMD, + sizeof(struct iwl4965_powertable_cmd), + cmd, NULL); + return ret; +} int iwl4965_hw_reg_set_txpower(struct iwl_priv *priv, s8 power) { IWL_ERROR("TODO: Implement iwl4965_hw_reg_set_txpower!\n"); @@ -4336,6 +4345,8 @@ static struct iwl_lib_ops iwl4965_lib = { .release_semaphore = iwlcore_eeprom_release_semaphore, }, .radio_kill_sw = iwl4965_radio_kill_sw, + .set_power = iwl4965_set_power, + .update_chain_flags = iwl4965_update_chain_flags, }; static struct iwl_ops iwl4965_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h index 78381f287de..0550d12e5c6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965.h @@ -44,6 +44,7 @@ #include "iwl-prph.h" #include "iwl-debug.h" #include "iwl-led.h" +#include "iwl-power.h" /* configuration for the iwl4965 */ extern struct iwl_cfg iwl4965_agn_cfg; @@ -257,31 +258,6 @@ enum iwl_pwr_src { IWL_PWR_SRC_VAUX, }; -struct iwl4965_power_vec_entry { - struct iwl4965_powertable_cmd cmd; - u8 no_dtim; -}; -#define IWL_POWER_RANGE_0 (0) -#define IWL_POWER_RANGE_1 (1) - -#define IWL_POWER_MODE_CAM 0x00 /* Continuously Aware Mode, always on */ -#define IWL_POWER_INDEX_3 0x03 -#define IWL_POWER_INDEX_5 0x05 -#define IWL_POWER_AC 0x06 -#define IWL_POWER_BATTERY 0x07 -#define IWL_POWER_LIMIT 0x07 -#define IWL_POWER_MASK 0x0F -#define IWL_POWER_ENABLED 0x10 -#define IWL_POWER_LEVEL(x) ((x) & IWL_POWER_MASK) - -struct iwl4965_power_mgr { - spinlock_t lock; - struct iwl4965_power_vec_entry pwr_range_0[IWL_POWER_AC]; - struct iwl4965_power_vec_entry pwr_range_1[IWL_POWER_AC]; - u8 active_index; - u32 dtim_val; -}; - #define IEEE80211_DATA_LEN 2304 #define IEEE80211_4ADDR_LEN 30 #define IEEE80211_HLEN (IEEE80211_4ADDR_LEN) @@ -674,6 +650,7 @@ extern unsigned int iwl4965_fill_beacon_frame(struct iwl_priv *priv, extern int iwl4965_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl4965_rx_queue *q); extern __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr); +extern void iwl4965_update_chain_flags(struct iwl_priv *priv); int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src); int iwl4965_init_geos(struct iwl_priv *priv); @@ -1100,7 +1077,7 @@ struct iwl_priv { u64 bytes; } tx_stats[3], rx_stats[3]; - struct iwl4965_power_mgr power_data; + struct iwl_power_mgr power_data; struct iwl4965_notif_statistics statistics; unsigned long last_statistics_time; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 2dfd982d7d1..c336b1991f1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -37,6 +37,7 @@ struct iwl_priv; /* FIXME: remove */ #include "iwl-4965.h" /* FIXME: remove */ #include "iwl-core.h" #include "iwl-rfkill.h" +#include "iwl-power.h" MODULE_DESCRIPTION("iwl core"); @@ -263,8 +264,10 @@ int iwlcore_low_level_notify(struct iwl_priv *priv, if (ret) IWL_ERROR("Unable to initialize RFKILL system. " "Ignoring error: %d\n", ret); + iwl_power_initialize(priv); break; case IWLCORE_START_EVT: + iwl_power_update_mode(priv, 1); break; case IWLCORE_STOP_EVT: break; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 51f61fb844f..3d113dce899 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -118,6 +118,9 @@ struct iwl_lib_ops { struct { int (*set_pwr_src)(struct iwl_priv *priv, enum iwl_pwr_src src); } apm_ops; + /* power */ + int (*set_power)(struct iwl_priv *priv, void *cmd); + void (*update_chain_flags)(struct iwl_priv *priv); /* eeprom operations (as defined in iwl-eeprom.h) */ struct iwl_eeprom_ops eeprom_ops; }; diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c new file mode 100644 index 00000000000..a242628465a --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -0,0 +1,423 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project, as well + * as portions of the ieee80211 subsystem header files. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + *****************************************************************************/ + + +#include +#include +#include +#include + +#include + +#include "iwl-eeprom.h" +#include "iwl-4965.h" +#include "iwl-core.h" +#include "iwl-4965-commands.h" +#include "iwl-debug.h" +#include "iwl-power.h" +#include "iwl-helpers.h" + +/* + * Setting power level allow the card to go to sleep when not busy + * there are three factor that decide the power level to go to, they + * are list here with its priority + * 1- critical_power_setting this will be set according to card temperature. + * 2- system_power_setting this will be set by system PM manager. + * 3- user_power_setting this will be set by user either by writing to sys or + * mac80211 + * + * if system_power_setting and user_power_setting is set to auto + * the power level will be decided according to association status and battery + * status. + * + */ + +#define MSEC_TO_USEC 1024 +#define IWL_POWER_RANGE_0_MAX (2) +#define IWL_POWER_RANGE_1_MAX (10) + + +#define NOSLP __constant_cpu_to_le16(0), 0, 0 +#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0 +#define SLP_TOUT(T) __constant_cpu_to_le32((T) * MSEC_TO_USEC) +#define SLP_VEC(X0, X1, X2, X3, X4) {__constant_cpu_to_le32(X0), \ + __constant_cpu_to_le32(X1), \ + __constant_cpu_to_le32(X2), \ + __constant_cpu_to_le32(X3), \ + __constant_cpu_to_le32(X4)} + +#define IWL_POWER_ON_BATTERY IWL_POWER_INDEX_5 +#define IWL_POWER_ON_AC_DISASSOC IWL_POWER_MODE_CAM +#define IWL_POWER_ON_AC_ASSOC IWL_POWER_MODE_CAM + + +#define IWL_CT_KILL_TEMPERATURE 110 +#define IWL_MIN_POWER_TEMPERATURE 100 +#define IWL_REDUCED_POWER_TEMPERATURE 95 + +/* default power management (not Tx power) table values */ +/* for tim 0-10 */ +static struct iwl_power_vec_entry range_0[IWL_POWER_AC] = { + {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, + {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0}, + {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0}, + {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 2, 2, 2, 0xFF)}, 0}, + {{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 2, 4, 4, 0xFF)}, 1}, + {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 2, 4, 6, 0xFF)}, 2} +}; + + +/* for tim = 3-10 */ +static struct iwl_power_vec_entry range_1[IWL_POWER_AC] = { + {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, + {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0}, + {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 3, 4, 7)}, 0}, + {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 4, 6, 7, 9)}, 0}, + {{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 4, 6, 9, 10)}, 1}, + {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 7, 10, 10)}, 2} +}; + +/* for tim > 11 */ +static struct iwl_power_vec_entry range_2[IWL_POWER_AC] = { + {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, + {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 0xFF)}, 0}, + {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(2, 4, 6, 7, 0xFF)}, 0}, + {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0}, + {{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0}, + {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(4, 7, 10, 10, 0xFF)}, 0} +}; + +/* decide the right power level according to association status + * and battery status + */ +static u16 iwl_get_auto_power_mode(struct iwl_priv *priv) +{ + u16 mode = priv->power_data.user_power_setting; + + switch (priv->power_data.user_power_setting) { + case IWL_POWER_AUTO: + /* if running on battery */ + if (priv->power_data.is_battery_active) + mode = IWL_POWER_ON_BATTERY; + else if (iwl_is_associated(priv)) + mode = IWL_POWER_ON_AC_ASSOC; + else + mode = IWL_POWER_ON_AC_DISASSOC; + break; + case IWL_POWER_BATTERY: + mode = IWL_POWER_INDEX_3; + break; + case IWL_POWER_AC: + mode = IWL_POWER_MODE_CAM; + break; + } + return mode; +} + +/* initialize to default */ +static int iwl_power_init_handle(struct iwl_priv *priv) +{ + int ret = 0, i; + struct iwl_power_mgr *pow_data; + int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_AC; + u16 pci_pm; + + IWL_DEBUG_POWER("Initialize power \n"); + + pow_data = &(priv->power_data); + + memset(pow_data, 0, sizeof(*pow_data)); + + memcpy(&pow_data->pwr_range_0[0], &range_0[0], size); + memcpy(&pow_data->pwr_range_1[0], &range_1[0], size); + memcpy(&pow_data->pwr_range_2[0], &range_2[0], size); + + ret = pci_read_config_word(priv->pci_dev, + PCI_LINK_CTRL, &pci_pm); + if (ret != 0) + return 0; + else { + struct iwl4965_powertable_cmd *cmd; + + IWL_DEBUG_POWER("adjust power command flags\n"); + + for (i = 0; i < IWL_POWER_AC; i++) { + cmd = &pow_data->pwr_range_0[i].cmd; + + if (pci_pm & 0x1) + cmd->flags &= ~IWL_POWER_PCI_PM_MSK; + else + cmd->flags |= IWL_POWER_PCI_PM_MSK; + } + } + return ret; +} + +/* adjust power command according to dtim period and power level*/ +static int iwl_update_power_command(struct iwl_priv *priv, + struct iwl4965_powertable_cmd *cmd, + u16 mode) +{ + int ret = 0, i; + u8 skip; + u32 max_sleep = 0; + struct iwl_power_vec_entry *range; + u8 period = 0; + struct iwl_power_mgr *pow_data; + + if (mode > IWL_POWER_INDEX_5) { + IWL_DEBUG_POWER("Error invalid power mode \n"); + return -1; + } + pow_data = &(priv->power_data); + + if (pow_data->dtim_period <= IWL_POWER_RANGE_0_MAX) + range = &pow_data->pwr_range_0[0]; + else if (pow_data->dtim_period <= IWL_POWER_RANGE_1_MAX) + range = &pow_data->pwr_range_1[0]; + else + range = &pow_data->pwr_range_2[0]; + + period = pow_data->dtim_period; + memcpy(cmd, &range[mode].cmd, sizeof(struct iwl4965_powertable_cmd)); + + if (period == 0) { + period = 1; + skip = 0; + } else + skip = range[mode].no_dtim; + + if (skip == 0) { + max_sleep = period; + cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK; + } else { + __le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]; + max_sleep = le32_to_cpu(slp_itrvl); + if (max_sleep == 0xFF) + max_sleep = period * (skip + 1); + else if (max_sleep > period) + max_sleep = (le32_to_cpu(slp_itrvl) / period) * period; + cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK; + } + + for (i = 0; i < IWL_POWER_VEC_SIZE; i++) { + if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep) + cmd->sleep_interval[i] = cpu_to_le32(max_sleep); + } + + IWL_DEBUG_POWER("Flags value = 0x%08X\n", cmd->flags); + IWL_DEBUG_POWER("Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout)); + IWL_DEBUG_POWER("Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout)); + IWL_DEBUG_POWER("Sleep interval vector = { %d , %d , %d , %d , %d }\n", + le32_to_cpu(cmd->sleep_interval[0]), + le32_to_cpu(cmd->sleep_interval[1]), + le32_to_cpu(cmd->sleep_interval[2]), + le32_to_cpu(cmd->sleep_interval[3]), + le32_to_cpu(cmd->sleep_interval[4])); + + return ret; +} + + +/* + * calucaute the final power mode index + */ +int iwl_power_update_mode(struct iwl_priv *priv, u8 refresh) +{ + struct iwl_power_mgr *setting = &(priv->power_data); + int ret = 0; + u16 uninitialized_var(final_mode); + + /* If on battery, set to 3, + * if plugged into AC power, set to CAM ("continuously aware mode"), + * else user level */ + + switch (setting->system_power_setting) { + case IWL_POWER_AUTO: + final_mode = iwl_get_auto_power_mode(priv); + break; + case IWL_POWER_BATTERY: + final_mode = IWL_POWER_INDEX_3; + break; + case IWL_POWER_AC: + final_mode = IWL_POWER_MODE_CAM; + break; + default: + final_mode = setting->system_power_setting; + } + + if (setting->critical_power_setting > final_mode) + final_mode = setting->critical_power_setting; + + /* driver only support CAM for non STA network */ + if (priv->iw_mode != IEEE80211_IF_TYPE_STA) + final_mode = IWL_POWER_MODE_CAM; + + if (!iwl_is_rfkill(priv) && !setting->power_disabled && + ((setting->power_mode != final_mode) || refresh)) { + struct iwl4965_powertable_cmd cmd; + + if (final_mode != IWL_POWER_MODE_CAM) + set_bit(STATUS_POWER_PMI, &priv->status); + + iwl_update_power_command(priv, &cmd, final_mode); + cmd.keep_alive_beacons = 0; + + if (final_mode == IWL_POWER_INDEX_5) + cmd.flags |= IWL_POWER_FAST_PD; + + if (priv->cfg->ops->lib->set_power) + ret = priv->cfg->ops->lib->set_power(priv, &cmd); + + if (final_mode == IWL_POWER_MODE_CAM) + clear_bit(STATUS_POWER_PMI, &priv->status); + else + set_bit(STATUS_POWER_PMI, &priv->status); + + if (priv->cfg->ops->lib->update_chain_flags) + priv->cfg->ops->lib->update_chain_flags(priv); + + if (!ret) + setting->power_mode = final_mode; + } + + return ret; +} +EXPORT_SYMBOL(iwl_power_update_mode); + +/* Allow other iwl code to disable/enable power management active + * this will be usefull for rate scale to disable PM during heavy + * Tx/Rx activities + */ +int iwl_power_disable_management(struct iwl_priv *priv) +{ + u16 prev_mode; + int ret = 0; + + if (priv->power_data.power_disabled) + return -EBUSY; + + prev_mode = priv->power_data.user_power_setting; + priv->power_data.user_power_setting = IWL_POWER_MODE_CAM; + ret = iwl_power_update_mode(priv, 0); + priv->power_data.power_disabled = 1; + priv->power_data.user_power_setting = prev_mode; + + return ret; +} +EXPORT_SYMBOL(iwl_power_disable_management); + +/* Allow other iwl code to disable/enable power management active + * this will be usefull for rate scale to disable PM during hight + * valume activities + */ +int iwl_power_enable_management(struct iwl_priv *priv) +{ + int ret = 0; + + priv->power_data.power_disabled = 0; + ret = iwl_power_update_mode(priv, 0); + return ret; +} +EXPORT_SYMBOL(iwl_power_enable_management); + +/* set user_power_setting */ +int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode) +{ + int ret = 0; + + if (mode > IWL_POWER_LIMIT) + return -EINVAL; + + priv->power_data.user_power_setting = mode; + + ret = iwl_power_update_mode(priv, 0); + + return ret; +} +EXPORT_SYMBOL(iwl_power_set_user_mode); + + +/* set system_power_setting. This should be set by over all + * PM application. + */ +int iwl_power_set_system_mode(struct iwl_priv *priv, u16 mode) +{ + int ret = 0; + + if (mode > IWL_POWER_LIMIT) + return -EINVAL; + + priv->power_data.system_power_setting = mode; + + ret = iwl_power_update_mode(priv, 0); + + return ret; +} +EXPORT_SYMBOL(iwl_power_set_system_mode); + +/* initilize to default */ +void iwl_power_initialize(struct iwl_priv *priv) +{ + + iwl_power_init_handle(priv); + priv->power_data.user_power_setting = IWL_POWER_AUTO; + priv->power_data.power_disabled = 0; + priv->power_data.system_power_setting = IWL_POWER_AUTO; + priv->power_data.is_battery_active = 0; + priv->power_data.power_disabled = 0; + priv->power_data.critical_power_setting = 0; +} +EXPORT_SYMBOL(iwl_power_initialize); + +/* set critical_power_setting according to temperature value */ +int iwl_power_temperature_change(struct iwl_priv *priv) +{ + int ret = 0; + u16 new_critical = priv->power_data.critical_power_setting; + s32 temperature = KELVIN_TO_CELSIUS(priv->last_temperature); + + if (temperature > IWL_CT_KILL_TEMPERATURE) + return 0; + else if (temperature > IWL_MIN_POWER_TEMPERATURE) + new_critical = IWL_POWER_INDEX_5; + else if (temperature > IWL_REDUCED_POWER_TEMPERATURE) + new_critical = IWL_POWER_INDEX_3; + else + new_critical = IWL_POWER_MODE_CAM; + + if (new_critical != priv->power_data.critical_power_setting) + priv->power_data.critical_power_setting = new_critical; + + if (priv->power_data.critical_power_setting > + priv->power_data.power_mode) + ret = iwl_power_update_mode(priv, 0); + + return ret; +} +EXPORT_SYMBOL(iwl_power_temperature_change); diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h new file mode 100644 index 00000000000..aad2784ca2e --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-power.h @@ -0,0 +1,76 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project, as well + * as portions of the ieee80211 subsystem header files. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + *****************************************************************************/ +#ifndef __iwl_power_setting_h__ +#define __iwl_power_setting_h__ + +#include +#include "iwl-4965-commands.h" + +struct iwl_priv; + +#define IWL_POWER_MODE_CAM 0x00 /* Continuously Aware Mode, always on */ +#define IWL_POWER_INDEX_3 0x03 +#define IWL_POWER_INDEX_5 0x05 +#define IWL_POWER_AC 0x06 +#define IWL_POWER_BATTERY 0x07 +#define IWL_POWER_AUTO 0x08 +#define IWL_POWER_LIMIT 0x08 +#define IWL_POWER_MASK 0x0F +#define IWL_POWER_ENABLED 0x10 + +/* Power management (not Tx power) structures */ + +struct iwl_power_vec_entry { + struct iwl4965_powertable_cmd cmd; + u8 no_dtim; +}; + +struct iwl_power_mgr { + spinlock_t lock; + struct iwl_power_vec_entry pwr_range_0[IWL_POWER_AC]; + struct iwl_power_vec_entry pwr_range_1[IWL_POWER_AC]; + struct iwl_power_vec_entry pwr_range_2[IWL_POWER_AC]; + u32 dtim_period; + /* final power level that used to calculate final power command */ + u8 power_mode; + u8 user_power_setting; /* set by user through mac80211 or sysfs */ + u8 system_power_setting; /* set by kernel syatem tools */ + u8 critical_power_setting; /* set if driver over heated */ + u8 is_battery_active; /* DC/AC power */ + u8 power_disabled; /* flag to disable using power saving level */ +}; + +int iwl_power_update_mode(struct iwl_priv *priv, u8 refresh); +int iwl_power_disable_management(struct iwl_priv *priv); +int iwl_power_enable_management(struct iwl_priv *priv); +int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode); +int iwl_power_set_system_mode(struct iwl_priv *priv, u16 mode); +void iwl_power_initialize(struct iwl_priv *priv); +int iwl_power_temperature_change(struct iwl_priv *priv); + +#endif /* __iwl_power_setting_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 50f12a6133e..6cb54580fe6 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -879,6 +879,13 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) return 0; } +void iwl4965_update_chain_flags(struct iwl_priv *priv) +{ + + iwl4965_set_rxon_chain(priv); + iwl4965_commit_rxon(priv); +} + static int iwl4965_send_bt_config(struct iwl_priv *priv) { struct iwl4965_bt_cmd bt_cmd = { @@ -1366,184 +1373,6 @@ static void iwl4965_activate_qos(struct iwl_priv *priv, u8 force) } } -/* - * Power management (not Tx power!) functions - */ -#define MSEC_TO_USEC 1024 - -#define NOSLP __constant_cpu_to_le16(0), 0, 0 -#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0 -#define SLP_TIMEOUT(T) __constant_cpu_to_le32((T) * MSEC_TO_USEC) -#define SLP_VEC(X0, X1, X2, X3, X4) {__constant_cpu_to_le32(X0), \ - __constant_cpu_to_le32(X1), \ - __constant_cpu_to_le32(X2), \ - __constant_cpu_to_le32(X3), \ - __constant_cpu_to_le32(X4)} - - -/* default power management (not Tx power) table values */ -/* for tim 0-10 */ -static struct iwl4965_power_vec_entry range_0[IWL_POWER_AC] = { - {{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, - {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0}, - {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300), SLP_VEC(2, 4, 6, 7, 7)}, 0}, - {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(100), SLP_VEC(2, 6, 9, 9, 10)}, 0}, - {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(25), SLP_VEC(2, 7, 9, 9, 10)}, 1}, - {{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25), SLP_VEC(4, 7, 10, 10, 10)}, 1} -}; - -/* for tim > 10 */ -static struct iwl4965_power_vec_entry range_1[IWL_POWER_AC] = { - {{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, - {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), - SLP_VEC(1, 2, 3, 4, 0xFF)}, 0}, - {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300), - SLP_VEC(2, 4, 6, 7, 0xFF)}, 0}, - {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(100), - SLP_VEC(2, 6, 9, 9, 0xFF)}, 0}, - {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(25), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0}, - {{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25), - SLP_VEC(4, 7, 10, 10, 0xFF)}, 0} -}; - -int iwl4965_power_init_handle(struct iwl_priv *priv) -{ - int rc = 0, i; - struct iwl4965_power_mgr *pow_data; - int size = sizeof(struct iwl4965_power_vec_entry) * IWL_POWER_AC; - u16 pci_pm; - - IWL_DEBUG_POWER("Initialize power \n"); - - pow_data = &(priv->power_data); - - memset(pow_data, 0, sizeof(*pow_data)); - - pow_data->active_index = IWL_POWER_RANGE_0; - pow_data->dtim_val = 0xffff; - - memcpy(&pow_data->pwr_range_0[0], &range_0[0], size); - memcpy(&pow_data->pwr_range_1[0], &range_1[0], size); - - rc = pci_read_config_word(priv->pci_dev, PCI_LINK_CTRL, &pci_pm); - if (rc != 0) - return 0; - else { - struct iwl4965_powertable_cmd *cmd; - - IWL_DEBUG_POWER("adjust power command flags\n"); - - for (i = 0; i < IWL_POWER_AC; i++) { - cmd = &pow_data->pwr_range_0[i].cmd; - - if (pci_pm & 0x1) - cmd->flags &= ~IWL_POWER_PCI_PM_MSK; - else - cmd->flags |= IWL_POWER_PCI_PM_MSK; - } - } - return rc; -} - -static int iwl4965_update_power_cmd(struct iwl_priv *priv, - struct iwl4965_powertable_cmd *cmd, u32 mode) -{ - int rc = 0, i; - u8 skip; - u32 max_sleep = 0; - struct iwl4965_power_vec_entry *range; - u8 period = 0; - struct iwl4965_power_mgr *pow_data; - - if (mode > IWL_POWER_INDEX_5) { - IWL_DEBUG_POWER("Error invalid power mode \n"); - return -1; - } - pow_data = &(priv->power_data); - - if (pow_data->active_index == IWL_POWER_RANGE_0) - range = &pow_data->pwr_range_0[0]; - else - range = &pow_data->pwr_range_1[1]; - - memcpy(cmd, &range[mode].cmd, sizeof(struct iwl4965_powertable_cmd)); - -#ifdef IWL_MAC80211_DISABLE - if (priv->assoc_network != NULL) { - unsigned long flags; - - period = priv->assoc_network->tim.tim_period; - } -#endif /*IWL_MAC80211_DISABLE */ - skip = range[mode].no_dtim; - - if (period == 0) { - period = 1; - skip = 0; - } - - if (skip == 0) { - max_sleep = period; - cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK; - } else { - __le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]; - max_sleep = (le32_to_cpu(slp_itrvl) / period) * period; - cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK; - } - - for (i = 0; i < IWL_POWER_VEC_SIZE; i++) { - if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep) - cmd->sleep_interval[i] = cpu_to_le32(max_sleep); - } - - IWL_DEBUG_POWER("Flags value = 0x%08X\n", cmd->flags); - IWL_DEBUG_POWER("Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout)); - IWL_DEBUG_POWER("Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout)); - IWL_DEBUG_POWER("Sleep interval vector = { %d , %d , %d , %d , %d }\n", - le32_to_cpu(cmd->sleep_interval[0]), - le32_to_cpu(cmd->sleep_interval[1]), - le32_to_cpu(cmd->sleep_interval[2]), - le32_to_cpu(cmd->sleep_interval[3]), - le32_to_cpu(cmd->sleep_interval[4])); - - return rc; -} - -static int iwl4965_send_power_mode(struct iwl_priv *priv, u32 mode) -{ - u32 uninitialized_var(final_mode); - int rc; - struct iwl4965_powertable_cmd cmd; - - /* If on battery, set to 3, - * if plugged into AC power, set to CAM ("continuously aware mode"), - * else user level */ - switch (mode) { - case IWL_POWER_BATTERY: - final_mode = IWL_POWER_INDEX_3; - break; - case IWL_POWER_AC: - final_mode = IWL_POWER_MODE_CAM; - break; - default: - final_mode = mode; - break; - } - - cmd.keep_alive_beacons = 0; - - iwl4965_update_power_cmd(priv, &cmd, final_mode); - - rc = iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, sizeof(cmd), &cmd); - - if (final_mode == IWL_POWER_MODE_CAM) - clear_bit(STATUS_POWER_PMI, &priv->status); - else - set_bit(STATUS_POWER_PMI, &priv->status); - - return rc; -} - int iwl4965_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header) { /* Filter incoming packets to determine if they are targeted toward @@ -5304,8 +5133,6 @@ static void iwl4965_alive_start(struct iwl_priv *priv) priv->active_rate = priv->rates_mask; priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK; - iwl4965_send_power_mode(priv, IWL_POWER_LEVEL(priv->power_mode)); - if (iwl_is_associated(priv)) { struct iwl4965_rxon_cmd *active_rxon = (struct iwl4965_rxon_cmd *)(&priv->active_rxon); @@ -5838,6 +5665,8 @@ static void iwl4965_bg_request_scan(struct work_struct *data) direct_mask, (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); + scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK | + RXON_FILTER_BCON_AWARE_MSK); cmd.len += le16_to_cpu(scan->tx_cmd.len) + scan->channel_count * sizeof(struct iwl4965_scan_channel); cmd.data = scan; @@ -6000,6 +5829,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv) iwl4965_activate_qos(priv, 0); + iwl_power_update_mode(priv, 0); /* we have just associated, don't start scan too early */ priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN; } @@ -6990,6 +6820,8 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw) iwl4965_commit_rxon(priv); } + iwl_power_update_mode(priv, 0); + /* Per mac80211.h: This is only used in IBSS mode... */ if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) { @@ -7321,20 +7153,11 @@ static ssize_t store_power_level(struct device *d, goto out; } - if ((mode < 1) || (mode > IWL_POWER_LIMIT) || (mode == IWL_POWER_AC)) - mode = IWL_POWER_AC; - else - mode |= IWL_POWER_ENABLED; - - if (mode != priv->power_mode) { - rc = iwl4965_send_power_mode(priv, IWL_POWER_LEVEL(mode)); - if (rc) { - IWL_DEBUG_MAC80211("failed setting power mode.\n"); - goto out; - } - priv->power_mode = mode; + rc = iwl_power_set_user_mode(priv, mode); + if (rc) { + IWL_DEBUG_MAC80211("failed setting power mode.\n"); + goto out; } - rc = count; out: @@ -7364,7 +7187,7 @@ static ssize_t show_power_level(struct device *d, struct device_attribute *attr, char *buf) { struct iwl_priv *priv = dev_get_drvdata(d); - int level = IWL_POWER_LEVEL(priv->power_mode); + int level = priv->power_data.power_mode; char *p = buf; p += sprintf(p, "%d ", level); @@ -7382,14 +7205,14 @@ static ssize_t show_power_level(struct device *d, timeout_duration[level - 1] / 1000, period_duration[level - 1] / 1000); } - +/* if (!(priv->power_mode & IWL_POWER_ENABLED)) p += sprintf(p, " OFF\n"); else p += sprintf(p, " \n"); - +*/ + p += sprintf(p, " \n"); return (p - buf + 1); - } static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level, -- cgit v1.2.3-70-g09d2 From 073d3f5f1b3b6512eb82a3d40c84dedb14dc6f73 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Mon, 21 Apr 2008 15:41:52 -0700 Subject: iwlwifi: changing EEPROM layout handling This patch 1. changes the current EEPROM handling through a single HW struct layout representation, to more general approach, treating the EEPROM image as a flat bytes array, handling this image through ops functions and offsets. 2. Eeprom is dynamically allocated accroding HW type Signed-off-by: Tomas Winkler Signed-off-by: Ron Rindjunsky Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-hw.h | 3 + drivers/net/wireless/iwlwifi/iwl-4965.c | 62 +++++++---- drivers/net/wireless/iwlwifi/iwl-4965.h | 9 +- drivers/net/wireless/iwlwifi/iwl-core.h | 1 + drivers/net/wireless/iwlwifi/iwl-eeprom.c | 101 ++++++++++++------ drivers/net/wireless/iwlwifi/iwl-eeprom.h | 155 +++++++++++----------------- drivers/net/wireless/iwlwifi/iwl4965-base.c | 5 +- 7 files changed, 188 insertions(+), 148 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h index 1a66b508a8e..855a006c5e5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h @@ -69,6 +69,9 @@ #ifndef __iwl_4965_hw_h__ #define __iwl_4965_hw_h__ +/* EERPROM */ +#define IWL4965_EEPROM_IMG_SIZE 1024 + /* * uCode queue management definitions ... * Queue #4 is the command queue for 3945 and 4965; map it to Tx FIFO chnl 4. diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index d051aac558f..7886596b62c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -699,8 +699,9 @@ int iwl4965_hw_nic_init(struct iwl_priv *priv) unsigned long flags; struct iwl4965_rx_queue *rxq = &priv->rxq; u8 rev_id; - u32 val; u8 val_link; + u16 sku_cap; + u32 val; /* nic_init */ spin_lock_irqsave(&priv->lock, flags); @@ -759,7 +760,8 @@ int iwl4965_hw_nic_init(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); - if (priv->eeprom.calib_version < EEPROM_TX_POWER_VERSION_NEW) { + if (iwl_eeprom_query16(priv, EEPROM_4965_CALIB_VERSION_OFFSET) < + EEPROM_4965_TX_POWER_VERSION) { IWL_ERROR("Older EEPROM detected! Aborting.\n"); return -EINVAL; } @@ -816,6 +818,10 @@ int iwl4965_hw_nic_init(struct iwl_priv *priv) rxq->need_update = 1; iwl4965_rx_queue_update_write_ptr(priv, rxq); + /* init the txpower calibration pointer */ + priv->calib_info = (struct iwl_eeprom_calib_info *) + iwl_eeprom_query_addr(priv, EEPROM_4965_CALIB_TXPOWER_OFFSET); + spin_unlock_irqrestore(&priv->lock, flags); /* Allocate and init all Tx and Command queues */ @@ -823,10 +829,11 @@ int iwl4965_hw_nic_init(struct iwl_priv *priv) if (rc) return rc; - if (priv->eeprom.sku_cap & EEPROM_SKU_CAP_SW_RF_KILL_ENABLE) + sku_cap = iwl_eeprom_query16(priv, EEPROM_SKU_CAP); + if (sku_cap & EEPROM_SKU_CAP_SW_RF_KILL_ENABLE) IWL_DEBUG_RF_KILL("SW RF KILL supported in EEPROM.\n"); - if (priv->eeprom.sku_cap & EEPROM_SKU_CAP_HW_RF_KILL_ENABLE) + if (sku_cap & EEPROM_SKU_CAP_HW_RF_KILL_ENABLE) IWL_DEBUG_RF_KILL("HW RF KILL supported in EEPROM.\n"); set_bit(STATUS_INIT, &priv->status); @@ -1542,11 +1549,11 @@ static u32 iwl4965_get_sub_band(const struct iwl_priv *priv, u32 channel) s32 b = -1; for (b = 0; b < EEPROM_TX_POWER_BANDS; b++) { - if (priv->eeprom.calib_info.band_info[b].ch_from == 0) + if (priv->calib_info->band_info[b].ch_from == 0) continue; - if ((channel >= priv->eeprom.calib_info.band_info[b].ch_from) - && (channel <= priv->eeprom.calib_info.band_info[b].ch_to)) + if ((channel >= priv->calib_info->band_info[b].ch_from) + && (channel <= priv->calib_info->band_info[b].ch_to)) break; } @@ -1574,14 +1581,14 @@ static s32 iwl4965_interpolate_value(s32 x, s32 x1, s32 y1, s32 x2, s32 y2) * in channel number. */ static int iwl4965_interpolate_chan(struct iwl_priv *priv, u32 channel, - struct iwl4965_eeprom_calib_ch_info *chan_info) + struct iwl_eeprom_calib_ch_info *chan_info) { s32 s = -1; u32 c; u32 m; - const struct iwl4965_eeprom_calib_measure *m1; - const struct iwl4965_eeprom_calib_measure *m2; - struct iwl4965_eeprom_calib_measure *omeas; + const struct iwl_eeprom_calib_measure *m1; + const struct iwl_eeprom_calib_measure *m2; + struct iwl_eeprom_calib_measure *omeas; u32 ch_i1; u32 ch_i2; @@ -1591,8 +1598,8 @@ static int iwl4965_interpolate_chan(struct iwl_priv *priv, u32 channel, return -1; } - ch_i1 = priv->eeprom.calib_info.band_info[s].ch1.ch_num; - ch_i2 = priv->eeprom.calib_info.band_info[s].ch2.ch_num; + ch_i1 = priv->calib_info->band_info[s].ch1.ch_num; + ch_i2 = priv->calib_info->band_info[s].ch2.ch_num; chan_info->ch_num = (u8) channel; IWL_DEBUG_TXPOWER("channel %d subband %d factory cal ch %d & %d\n", @@ -1600,9 +1607,9 @@ static int iwl4965_interpolate_chan(struct iwl_priv *priv, u32 channel, for (c = 0; c < EEPROM_TX_POWER_TX_CHAINS; c++) { for (m = 0; m < EEPROM_TX_POWER_MEASUREMENTS; m++) { - m1 = &(priv->eeprom.calib_info.band_info[s].ch1. + m1 = &(priv->calib_info->band_info[s].ch1. measurements[c][m]); - m2 = &(priv->eeprom.calib_info.band_info[s].ch2. + m2 = &(priv->calib_info->band_info[s].ch2. measurements[c][m]); omeas = &(chan_info->measurements[c][m]); @@ -1921,8 +1928,8 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, int i; int c; const struct iwl_channel_info *ch_info = NULL; - struct iwl4965_eeprom_calib_ch_info ch_eeprom_info; - const struct iwl4965_eeprom_calib_measure *measurement; + struct iwl_eeprom_calib_ch_info ch_eeprom_info; + const struct iwl_eeprom_calib_measure *measurement; s16 voltage; s32 init_voltage; s32 voltage_compensation; @@ -1979,9 +1986,9 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, /* hardware txpower limits ... * saturation (clipping distortion) txpowers are in half-dBm */ if (band) - saturation_power = priv->eeprom.calib_info.saturation_power24; + saturation_power = priv->calib_info->saturation_power24; else - saturation_power = priv->eeprom.calib_info.saturation_power52; + saturation_power = priv->calib_info->saturation_power52; if (saturation_power < IWL_TX_POWER_SATURATION_MIN || saturation_power > IWL_TX_POWER_SATURATION_MAX) { @@ -2011,7 +2018,7 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, iwl4965_interpolate_chan(priv, channel, &ch_eeprom_info); /* calculate tx gain adjustment based on power supply voltage */ - voltage = priv->eeprom.calib_info.voltage; + voltage = priv->calib_info->voltage; init_voltage = (s32)le32_to_cpu(priv->card_alive_init.voltage); voltage_compensation = iwl4965_get_voltage_compensation(voltage, init_voltage); @@ -2467,14 +2474,14 @@ int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr, static void iwl4965_hw_card_show_info(struct iwl_priv *priv) { - u16 hw_version = priv->eeprom.board_revision_4965; + u16 hw_version = iwl_eeprom_query16(priv, EEPROM_4965_BOARD_REVISION); IWL_DEBUG_INFO("4965ABGN HW Version %u.%u.%u\n", ((hw_version >> 8) & 0x0F), ((hw_version >> 8) >> 4), (hw_version & 0x00FF)); IWL_DEBUG_INFO("4965ABGN PBA Number %.16s\n", - priv->eeprom.board_pba_number_4965); + &priv->eeprom[EEPROM_4965_BOARD_PBA]); } #define IWL_TX_CRC_SIZE 4 @@ -4340,9 +4347,19 @@ static struct iwl_lib_ops iwl4965_lib = { .set_pwr_src = iwl4965_set_pwr_src, }, .eeprom_ops = { + .regulatory_bands = { + EEPROM_REGULATORY_BAND_1_CHANNELS, + EEPROM_REGULATORY_BAND_2_CHANNELS, + EEPROM_REGULATORY_BAND_3_CHANNELS, + EEPROM_REGULATORY_BAND_4_CHANNELS, + EEPROM_REGULATORY_BAND_5_CHANNELS, + EEPROM_4965_REGULATORY_BAND_24_FAT_CHANNELS, + EEPROM_4965_REGULATORY_BAND_52_FAT_CHANNELS + }, .verify_signature = iwlcore_eeprom_verify_signature, .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, .release_semaphore = iwlcore_eeprom_release_semaphore, + .query_addr = iwlcore_eeprom_query_addr, }, .radio_kill_sw = iwl4965_radio_kill_sw, .set_power = iwl4965_set_power, @@ -4359,6 +4376,7 @@ struct iwl_cfg iwl4965_agn_cfg = { .name = "4965AGN", .fw_name = "iwlwifi-4965" IWL4965_UCODE_API ".ucode", .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, + .eeprom_size = IWL4965_EEPROM_IMG_SIZE, .ops = &iwl4965_ops, .mod_params = &iwl4965_mod_params, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h index 0550d12e5c6..35a67cdf707 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965.h @@ -200,9 +200,9 @@ enum { struct iwl_channel_info { struct iwl4965_channel_tgd_info tgd; struct iwl4965_channel_tgh_info tgh; - struct iwl4965_eeprom_channel eeprom; /* EEPROM regulatory limit */ - struct iwl4965_eeprom_channel fat_eeprom; /* EEPROM regulatory limit for - * FAT channel */ + struct iwl_eeprom_channel eeprom; /* EEPROM regulatory limit */ + struct iwl_eeprom_channel fat_eeprom; /* EEPROM regulatory limit for + * FAT channel */ u8 channel; /* channel number */ u8 flags; /* flags copied from EEPROM */ @@ -1122,7 +1122,8 @@ struct iwl_priv { struct list_head ibss_mac_hash[IWL_IBSS_MAC_HASH_SIZE]; /* eeprom */ - struct iwl4965_eeprom eeprom; + u8 *eeprom; + struct iwl_eeprom_calib_info *calib_info; enum ieee80211_if_types iw_mode; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 3d113dce899..79e97935bbb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -146,6 +146,7 @@ struct iwl_cfg { const char *name; const char *fw_name; unsigned int sku; + int eeprom_size; const struct iwl_ops *ops; const struct iwl_mod_params *mod_params; }; diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index a07d5dcb7ab..a436f877882 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -193,6 +193,12 @@ void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv) } EXPORT_SYMBOL(iwlcore_eeprom_release_semaphore); +const u8 *iwlcore_eeprom_query_addr(const struct iwl_priv *priv, size_t offset) +{ + BUG_ON(offset >= priv->cfg->eeprom_size); + return &priv->eeprom[offset]; +} +EXPORT_SYMBOL(iwlcore_eeprom_query_addr); /** * iwl_eeprom_init - read EEPROM contents @@ -203,30 +209,35 @@ EXPORT_SYMBOL(iwlcore_eeprom_release_semaphore); */ int iwl_eeprom_init(struct iwl_priv *priv) { - u16 *e = (u16 *)&priv->eeprom; + u16 *e; u32 gp = iwl_read32(priv, CSR_EEPROM_GP); u32 r; - int sz = sizeof(priv->eeprom); + int sz = priv->cfg->eeprom_size; int ret; int i; u16 addr; - /* The EEPROM structure has several padding buffers within it - * and when adding new EEPROM maps is subject to programmer errors - * which may be very difficult to identify without explicitly - * checking the resulting size of the eeprom map. */ - BUILD_BUG_ON(sizeof(priv->eeprom) != IWL_EEPROM_IMAGE_SIZE); + /* allocate eeprom */ + priv->eeprom = kzalloc(sz, GFP_KERNEL); + if (!priv->eeprom) { + ret = -ENOMEM; + goto alloc_err; + } + e = (u16 *)priv->eeprom; - if ((gp & CSR_EEPROM_GP_VALID_MSK) == CSR_EEPROM_GP_BAD_SIGNATURE) { + ret = priv->cfg->ops->lib->eeprom_ops.verify_signature(priv); + if (ret < 0) { IWL_ERROR("EEPROM not found, EEPROM_GP=0x%08x", gp); - return -ENOENT; + ret = -ENOENT; + goto err; } /* Make sure driver (instead of uCode) is allowed to read EEPROM */ ret = priv->cfg->ops->lib->eeprom_ops.acquire_semaphore(priv); if (ret < 0) { IWL_ERROR("Failed to acquire EEPROM semaphore.\n"); - return -ENOENT; + ret = -ENOENT; + goto err; } /* eeprom is an array of 16bit values */ @@ -250,61 +261,93 @@ int iwl_eeprom_init(struct iwl_priv *priv) e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16)); } ret = 0; - done: priv->cfg->ops->lib->eeprom_ops.release_semaphore(priv); +err: + if (ret) + kfree(priv->eeprom); +alloc_err: return ret; } EXPORT_SYMBOL(iwl_eeprom_init); +void iwl_eeprom_free(struct iwl_priv *priv) +{ + if(priv->eeprom) + kfree(priv->eeprom); + priv->eeprom = NULL; +} +EXPORT_SYMBOL(iwl_eeprom_free); + + +const u8 *iwl_eeprom_query_addr(const struct iwl_priv *priv, size_t offset) +{ + return priv->cfg->ops->lib->eeprom_ops.query_addr(priv, offset); +} +EXPORT_SYMBOL(iwl_eeprom_query_addr); + +u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset) +{ + return (u16)priv->eeprom[offset] | ((u16)priv->eeprom[offset + 1] << 8); +} +EXPORT_SYMBOL(iwl_eeprom_query16); void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac) { - memcpy(mac, priv->eeprom.mac_address, 6); + const u8 *addr = priv->cfg->ops->lib->eeprom_ops.query_addr(priv, + EEPROM_MAC_ADDRESS); + memcpy(mac, addr, ETH_ALEN); } EXPORT_SYMBOL(iwl_eeprom_get_mac); static void iwl_init_band_reference(const struct iwl_priv *priv, - int band, - int *eeprom_ch_count, - const struct iwl4965_eeprom_channel - **eeprom_ch_info, - const u8 **eeprom_ch_index) + int eep_band, int *eeprom_ch_count, + const struct iwl_eeprom_channel **eeprom_ch_info, + const u8 **eeprom_ch_index) { - switch (band) { + u32 offset = priv->cfg->ops->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 = priv->eeprom.band_1_channels; + *eeprom_ch_info = (struct iwl_eeprom_channel *) + iwl_eeprom_query_addr(priv, 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 = priv->eeprom.band_2_channels; + *eeprom_ch_info = (struct iwl_eeprom_channel *) + iwl_eeprom_query_addr(priv, 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 = priv->eeprom.band_3_channels; + *eeprom_ch_info = (struct iwl_eeprom_channel *) + iwl_eeprom_query_addr(priv, 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 = priv->eeprom.band_4_channels; + *eeprom_ch_info = (struct iwl_eeprom_channel *) + iwl_eeprom_query_addr(priv, 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 = priv->eeprom.band_5_channels; + *eeprom_ch_info = (struct iwl_eeprom_channel *) + iwl_eeprom_query_addr(priv, offset); *eeprom_ch_index = iwl_eeprom_band_5; break; case 6: /* 2.4GHz FAT channels */ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_6); - *eeprom_ch_info = priv->eeprom.band_24_channels; + *eeprom_ch_info = (struct iwl_eeprom_channel *) + iwl_eeprom_query_addr(priv, offset); *eeprom_ch_index = iwl_eeprom_band_6; break; case 7: /* 5 GHz FAT channels */ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_7); - *eeprom_ch_info = priv->eeprom.band_52_channels; + *eeprom_ch_info = (struct iwl_eeprom_channel *) + iwl_eeprom_query_addr(priv, offset); *eeprom_ch_index = iwl_eeprom_band_7; break; default: @@ -323,7 +366,7 @@ static void iwl_init_band_reference(const struct iwl_priv *priv, */ static int iwl4965_set_fat_chan_info(struct iwl_priv *priv, enum ieee80211_band band, u16 channel, - const struct iwl4965_eeprom_channel *eeprom_ch, + const struct iwl_eeprom_channel *eeprom_ch, u8 fat_extension_channel) { struct iwl_channel_info *ch_info; @@ -372,7 +415,7 @@ int iwl_init_channel_map(struct iwl_priv *priv) { int eeprom_ch_count = 0; const u8 *eeprom_ch_index = NULL; - const struct iwl4965_eeprom_channel *eeprom_ch_info = NULL; + const struct iwl_eeprom_channel *eeprom_ch_info = NULL; int band, ch; struct iwl_channel_info *ch_info; @@ -381,9 +424,9 @@ int iwl_init_channel_map(struct iwl_priv *priv) return 0; } - if (priv->eeprom.version < 0x2f) { + if (iwl_eeprom_query16(priv, EEPROM_VERSION) < 0x2f) { IWL_WARNING("Unsupported EEPROM version: 0x%04X\n", - priv->eeprom.version); + iwl_eeprom_query16(priv, EEPROM_VERSION)); return -EINVAL; } diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index bd0a042ca77..26a73e918c5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -116,7 +116,7 @@ enum { /* *regulatory* channel data format in eeprom, one for each channel. * There are separate entries for FAT (40 MHz) vs. normal (20 MHz) channels. */ -struct iwl4965_eeprom_channel { +struct iwl_eeprom_channel { u8 flags; /* EEPROM_CHANNEL_* flags copied from EEPROM */ s8 max_power_avg; /* max power (dBm) on this chnl, limit 31 */ } __attribute__ ((packed)); @@ -131,17 +131,19 @@ struct iwl4965_eeprom_channel { * each of 3 target output levels */ #define EEPROM_TX_POWER_MEASUREMENTS (3) -#define EEPROM_4965_TX_POWER_VERSION (2) - -/* 4965 driver does not work with txpower calibration version < 5. - * Look for this in calib_version member of struct iwl4965_eeprom. */ -#define EEPROM_TX_POWER_VERSION_NEW (5) +/* 4965 Specific */ +/* 4965 driver does not work with txpower calibration version < 5 */ +#define EEPROM_4965_TX_POWER_VERSION (5) +#define EEPROM_4965_CALIB_VERSION_OFFSET (2*0xB6) /* 2 bytes */ +#define EEPROM_4965_CALIB_TXPOWER_OFFSET (2*0xE8) /* 48 bytes */ +#define EEPROM_4965_BOARD_REVISION (2*0x4F) /* 2 bytes */ +#define EEPROM_4965_BOARD_PBA (2*0x56+1) /* 9 bytes */ /* 2.4 GHz */ extern const u8 iwl_eeprom_band_1[14]; /* - * 4965 factory calibration data for one txpower level, on one channel, + * factory calibration data for one txpower level, on one channel, * measured on one of the 2 tx chains (radio transmitter and associated * antenna). EEPROM contains: * @@ -154,7 +156,7 @@ extern const u8 iwl_eeprom_band_1[14]; * * 4) RF power amplifier detector level measurement (not used). */ -struct iwl4965_eeprom_calib_measure { +struct iwl_eeprom_calib_measure { u8 temperature; /* Device temperature (Celsius) */ u8 gain_idx; /* Index into gain table */ u8 actual_pow; /* Measured RF output power, half-dBm */ @@ -163,22 +165,22 @@ struct iwl4965_eeprom_calib_measure { /* - * 4965 measurement set for one channel. EEPROM contains: + * measurement set for one channel. EEPROM contains: * * 1) Channel number measured * * 2) Measurements for each of 3 power levels for each of 2 radio transmitters * (a.k.a. "tx chains") (6 measurements altogether) */ -struct iwl4965_eeprom_calib_ch_info { +struct iwl_eeprom_calib_ch_info { u8 ch_num; - struct iwl4965_eeprom_calib_measure + struct iwl_eeprom_calib_measure measurements[EEPROM_TX_POWER_TX_CHAINS] [EEPROM_TX_POWER_MEASUREMENTS]; } __attribute__ ((packed)); /* - * 4965 txpower subband info. + * txpower subband info. * * For each frequency subband, EEPROM contains the following: * @@ -187,16 +189,16 @@ struct iwl4965_eeprom_calib_ch_info { * * 2) Sample measurement sets for 2 channels close to the range endpoints. */ -struct iwl4965_eeprom_calib_subband_info { +struct iwl_eeprom_calib_subband_info { u8 ch_from; /* channel number of lowest channel in subband */ u8 ch_to; /* channel number of highest channel in subband */ - struct iwl4965_eeprom_calib_ch_info ch1; - struct iwl4965_eeprom_calib_ch_info ch2; + struct iwl_eeprom_calib_ch_info ch1; + struct iwl_eeprom_calib_ch_info ch2; } __attribute__ ((packed)); /* - * 4965 txpower calibration info. EEPROM contains: + * txpower calibration info. EEPROM contains: * * 1) Factory-measured saturation power levels (maximum levels at which * tx power amplifier can output a signal without too much distortion). @@ -212,55 +214,45 @@ struct iwl4965_eeprom_calib_subband_info { * characteristics of the analog radio circuitry vary with frequency. * * Not all sets need to be filled with data; - * struct iwl4965_eeprom_calib_subband_info contains range of channels + * struct iwl_eeprom_calib_subband_info contains range of channels * (0 if unused) for each set of data. */ -struct iwl4965_eeprom_calib_info { +struct iwl_eeprom_calib_info { u8 saturation_power24; /* half-dBm (e.g. "34" = 17 dBm) */ u8 saturation_power52; /* half-dBm */ s16 voltage; /* signed */ - struct iwl4965_eeprom_calib_subband_info + struct iwl_eeprom_calib_subband_info band_info[EEPROM_TX_POWER_BANDS]; } __attribute__ ((packed)); - -/* - * 4965 EEPROM map - */ -struct iwl4965_eeprom { - u8 reserved0[16]; - u16 device_id; /* abs.ofs: 16 */ - u8 reserved1[2]; - u16 pmc; /* abs.ofs: 20 */ - u8 reserved2[20]; - u8 mac_address[6]; /* abs.ofs: 42 */ - u8 reserved3[58]; - u16 board_revision; /* abs.ofs: 106 */ - u8 reserved4[11]; - u8 board_pba_number[9]; /* abs.ofs: 119 */ - u8 reserved5[8]; - u16 version; /* abs.ofs: 136 */ - u8 sku_cap; /* abs.ofs: 138 */ - u8 leds_mode; /* abs.ofs: 139 */ - u16 oem_mode; - u16 wowlan_mode; /* abs.ofs: 142 */ - u16 leds_time_interval; /* abs.ofs: 144 */ - u8 leds_off_time; /* abs.ofs: 146 */ - u8 leds_on_time; /* abs.ofs: 147 */ - u8 almgor_m_version; /* abs.ofs: 148 */ - u8 antenna_switch_type; /* abs.ofs: 149 */ - u8 reserved6[8]; - u16 board_revision_4965; /* abs.ofs: 158 */ - u8 reserved7[13]; - u8 board_pba_number_4965[9]; /* abs.ofs: 173 */ - u8 reserved8[10]; - u8 sku_id[4]; /* abs.ofs: 192 */ +#define ADDRESS_MSK 0x0000FFFF +#define INDIRECT_TYPE_MSK 0x000F0000 +#define INDIRECT_HOST 0x00010000 +#define INDIRECT_GENERAL 0x00020000 +#define INDIRECT_REGULATORY 0x00030000 +#define INDIRECT_CALIBRATION 0x00040000 +#define INDIRECT_PROCESS_ADJST 0x00050000 +#define INDIRECT_OTHERS 0x00060000 +#define INDIRECT_ADDRESS 0x00100000 + +/* General */ +#define EEPROM_DEVICE_ID (2*0x08) /* 2 bytes */ +#define EEPROM_MAC_ADDRESS (2*0x15) /* 6 bytes */ +#define EEPROM_BOARD_REVISION (2*0x35) /* 2 bytes */ +#define EEPROM_BOARD_PBA_NUMBER (2*0x3B+1) /* 9 bytes */ +#define EEPROM_VERSION (2*0x44) /* 2 bytes */ +#define EEPROM_SKU_CAP (2*0x45) /* 1 bytes */ +#define EEPROM_LEDS_MODE (2*0x45+1) /* 1 bytes */ +#define EEPROM_OEM_MODE (2*0x46) /* 2 bytes */ +#define EEPROM_WOWLAN_MODE (2*0x47) /* 2 bytes */ +#define EEPROM_3945_M_VERSION (2*0x4A) /* 1 bytes */ +#define EEPROM_ANTENNA_SWITCH_TYPE (2*0x4A+1) /* 1 bytes */ /* * Per-channel regulatory data. * - * Each channel that *might* be supported by 3945 or 4965 has a fixed location + * Each channel that *might* be supported by iwl has a fixed location * in EEPROM containing EEPROM_CHANNEL_* usage flags (LSB) and max regulatory * txpower (MSB). * @@ -269,40 +261,38 @@ struct iwl4965_eeprom { * * 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 */ - u16 band_1_count; /* abs.ofs: 196 */ - struct iwl4965_eeprom_channel band_1_channels[14]; /* abs.ofs: 196 */ +#define EEPROM_REGULATORY_SKU_ID (2*0x60) /* 4 bytes */ +#define EEPROM_REGULATORY_BAND_1 (2*0x62) /* 2 bytes */ +#define EEPROM_REGULATORY_BAND_1_CHANNELS (2*0x63) /* 28 bytes */ /* * 4.9 GHz channels 183, 184, 185, 187, 188, 189, 192, 196, * 5.0 GHz channels 7, 8, 11, 12, 16 * (4915-5080MHz) (none of these is ever supported) */ - u16 band_2_count; /* abs.ofs: 226 */ - struct iwl4965_eeprom_channel band_2_channels[13]; /* abs.ofs: 228 */ +#define EEPROM_REGULATORY_BAND_2 (2*0x71) /* 2 bytes */ +#define EEPROM_REGULATORY_BAND_2_CHANNELS (2*0x72) /* 26 bytes */ /* * 5.2 GHz channels 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64 * (5170-5320MHz) */ - u16 band_3_count; /* abs.ofs: 254 */ - struct iwl4965_eeprom_channel band_3_channels[12]; /* abs.ofs: 256 */ +#define EEPROM_REGULATORY_BAND_3 (2*0x7F) /* 2 bytes */ +#define EEPROM_REGULATORY_BAND_3_CHANNELS (2*0x80) /* 24 bytes */ /* * 5.5 GHz channels 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 * (5500-5700MHz) */ - u16 band_4_count; /* abs.ofs: 280 */ - struct iwl4965_eeprom_channel band_4_channels[11]; /* abs.ofs: 282 */ +#define EEPROM_REGULATORY_BAND_4 (2*0x8C) /* 2 bytes */ +#define EEPROM_REGULATORY_BAND_4_CHANNELS (2*0x8D) /* 22 bytes */ /* * 5.7 GHz channels 145, 149, 153, 157, 161, 165 * (5725-5825MHz) */ - u16 band_5_count; /* abs.ofs: 304 */ - struct iwl4965_eeprom_channel band_5_channels[6]; /* abs.ofs: 306 */ - - u8 reserved10[2]; - +#define EEPROM_REGULATORY_BAND_5 (2*0x98) /* 2 bytes */ +#define EEPROM_REGULATORY_BAND_5_CHANNELS (2*0x99) /* 12 bytes */ /* * 2.4 GHz FAT channels 1 (5), 2 (6), 3 (7), 4 (8), 5 (9), 6 (10), 7 (11) @@ -319,52 +309,33 @@ struct iwl4965_eeprom { * * NOTE: 4965 does not support FAT channels on 2.4 GHz. */ - struct iwl4965_eeprom_channel band_24_channels[7]; /* abs.ofs: 320 */ - u8 reserved11[2]; +#define EEPROM_4965_REGULATORY_BAND_24_FAT_CHANNELS (2*0xA0) /* 14 bytes */ /* * 5.2 GHz FAT channels 36 (40), 44 (48), 52 (56), 60 (64), * 100 (104), 108 (112), 116 (120), 124 (128), 132 (136), 149 (153), 157 (161) */ - struct iwl4965_eeprom_channel band_52_channels[11]; /* abs.ofs: 336 */ - u8 reserved12[6]; - -/* - * 4965 driver requires txpower calibration format version 5 or greater. - * Driver does not work with txpower calibration version < 5. - * This value is simply a 16-bit number, no major/minor versions here. - */ - u16 calib_version; /* abs.ofs: 364 */ - u8 reserved13[2]; - u8 reserved14[96]; /* abs.ofs: 368 */ - -/* - * 4965 Txpower calibration data. - */ - struct iwl4965_eeprom_calib_info calib_info; /* abs.ofs: 464 */ - - u8 reserved16[140]; /* fill out to full 1024 byte block */ - - -} __attribute__ ((packed)); - -#define IWL_EEPROM_IMAGE_SIZE 1024 - -/* End of EEPROM */ +#define EEPROM_4965_REGULATORY_BAND_52_FAT_CHANNELS (2*0xA8) /* 22 bytes */ struct iwl_eeprom_ops { + const u32 regulatory_bands[7]; int (*verify_signature) (struct iwl_priv *priv); int (*acquire_semaphore) (struct iwl_priv *priv); void (*release_semaphore) (struct iwl_priv *priv); + const u8* (*query_addr) (const struct iwl_priv *priv, size_t offset); }; void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac); int iwl_eeprom_init(struct iwl_priv *priv); +void iwl_eeprom_free(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); int iwlcore_eeprom_verify_signature(struct iwl_priv *priv); int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv); void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv); +const u8 *iwlcore_eeprom_query_addr(const struct iwl_priv *priv, size_t offset); int iwl_init_channel_map(struct iwl_priv *priv); void iwl_free_channel_map(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 6cb54580fe6..c5ac82c4aeb 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -7550,7 +7550,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e /* Device-specific setup */ if (priv->cfg->ops->lib->set_hw_params(priv)) { IWL_ERROR("failed to set hw parameters\n"); - goto out_iounmap; + goto out_free_eeprom; } /******************* @@ -7611,6 +7611,8 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group); out_unset_hw_params: iwl4965_unset_hw_params(priv); + out_free_eeprom: + iwl_eeprom_free(priv); out_iounmap: pci_iounmap(pdev, priv->hw_base); out_pci_release_regions: @@ -7674,6 +7676,7 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) iwl4965_unset_hw_params(priv); iwlcore_clear_stations_table(priv); + iwl_eeprom_free(priv); /*netif_stop_queue(dev); */ -- cgit v1.2.3-70-g09d2 From 099b40b743df80372236ba1df9796f59ba297b1d Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Mon, 21 Apr 2008 15:41:53 -0700 Subject: iwlwifi: expanding HW parameters control This patch adds several parameters to priv.hw_params, for better control over HW capabilities variants Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-hw.h | 6 ++---- drivers/net/wireless/iwlwifi/iwl-4965.c | 15 ++++++++++++--- drivers/net/wireless/iwlwifi/iwl-4965.h | 25 +++++++++++++++++++++---- drivers/net/wireless/iwlwifi/iwl4965-base.c | 14 +++++++------- 4 files changed, 42 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h index 855a006c5e5..0c132b93d90 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h @@ -134,10 +134,8 @@ #define RTC_DATA_LOWER_BOUND (0x800000) #define IWL49_RTC_DATA_UPPER_BOUND (0x80A000) -#define IWL49_RTC_INST_SIZE \ - (IWL49_RTC_INST_UPPER_BOUND - RTC_INST_LOWER_BOUND) -#define IWL49_RTC_DATA_SIZE \ - (IWL49_RTC_DATA_UPPER_BOUND - RTC_DATA_LOWER_BOUND) +#define IWL49_RTC_INST_SIZE (IWL49_RTC_INST_UPPER_BOUND - RTC_INST_LOWER_BOUND) +#define IWL49_RTC_DATA_SIZE (IWL49_RTC_DATA_UPPER_BOUND - RTC_DATA_LOWER_BOUND) #define IWL_MAX_INST_SIZE IWL49_RTC_INST_SIZE #define IWL_MAX_DATA_SIZE IWL49_RTC_DATA_SIZE diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 7886596b62c..9b3a745b66b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -999,7 +999,8 @@ void iwl4965_rf_kill_ct_config(struct iwl_priv *priv) temp_th = CELSIUS_TO_KELVIN(TM_CT_KILL_THRESHOLD); crit_temperature = ((temp_th * (R3-R1))/CT_LIMIT_CONST) + R2; - cmd.critical_temperature_R = cpu_to_le32(crit_temperature); + cmd.critical_temperature_R = + cpu_to_le32(priv->hw_params.ct_kill_threshold); ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD, sizeof(cmd), &cmd); if (ret) @@ -1340,6 +1341,7 @@ int iwl4965_hw_set_hw_params(struct iwl_priv *priv) } priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues; + priv->hw_params.sw_crypto = priv->cfg->mod_params->sw_crypto; priv->hw_params.tx_cmd_len = sizeof(struct iwl4965_tx_cmd); priv->hw_params.max_rxq_size = RX_QUEUE_SIZE; priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG; @@ -1351,10 +1353,17 @@ int iwl4965_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.max_stations = IWL4965_STATION_COUNT; priv->hw_params.bcast_sta_id = IWL4965_BROADCAST_ID; + priv->hw_params.max_data_size = IWL49_RTC_DATA_SIZE; + priv->hw_params.max_inst_size = IWL49_RTC_INST_SIZE; + priv->hw_params.max_bsm_size = BSM_SRAM_SIZE; + priv->hw_params.fat_channel = BIT(IEEE80211_BAND_5GHZ); + priv->hw_params.tx_chains_num = 2; priv->hw_params.rx_chains_num = 2; priv->hw_params.valid_tx_ant = (IWL_ANTENNA_MAIN | IWL_ANTENNA_AUX); priv->hw_params.valid_rx_ant = (IWL_ANTENNA_MAIN | IWL_ANTENNA_AUX); + priv->hw_params.ct_kill_threshold = CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD); + #ifdef CONFIG_IWL4965_RUN_TIME_CALIB priv->hw_params.sens = &iwl4965_sensitivity; #endif @@ -3064,7 +3073,7 @@ static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data, hdr = (struct ieee80211_hdr *)rxb->skb->data; /* in case of HW accelerated crypto and bad decryption, drop */ - if (!priv->cfg->mod_params->sw_crypto && + if (!priv->hw_params.sw_crypto && iwl4965_set_decrypted_flag(priv, hdr, ampdu_status, stats)) return; @@ -3122,7 +3131,7 @@ void iwl4965_init_ht_hw_capab(struct iwl_priv *priv, ht_info->ht_supported = 1; - if (band == IEEE80211_BAND_5GHZ) { + if (priv->hw_params.fat_channel & BIT(band)) { ht_info->cap |= (u16)IEEE80211_HT_CAP_SUP_WIDTH; ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_40; ht_info->supp_mcs_set[4] = 0x01; diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h index 35a67cdf707..31f5447b797 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965.h @@ -55,6 +55,8 @@ extern struct iwl_cfg iwl4965_agn_cfg; * This number will also appear in << 8 position of 1st dword of uCode file */ #define IWL4965_UCODE_API "-1" +/* CT-KILL constants */ +#define CT_KILL_THRESHOLD 110 /* in Celsius */ /* Default noise level to report when noise measurement is not available. * This may be because we're: @@ -570,16 +572,25 @@ struct iwl_sensitivity_ranges { u16 auto_corr_min_cck_mrc; }; + +#define IWL_FAT_CHANNEL_52 BIT(IEEE80211_BAND_5GHZ) + /** * struct iwl_hw_params * @max_txq_num: Max # Tx queues supported * @tx_cmd_len: Size of Tx command (but not including frame itself) - * @tx_ant_num: Number of TX antennas + * @tx/rx_chains_num: Number of TX/RX chains + * @valid_tx/rx_ant: usable antennas * @max_rxq_size: Max # Rx frames in Rx queue (must be power-of-2) - * @rx_buffer_size: * @max_rxq_log: Log-base-2 of max_rxq_size + * @rx_buf_size: Rx buffer size * @max_stations: * @bcast_sta_id: + * @fat_channel: is 40MHz width possible in band 2.4 + * BIT(IEEE80211_BAND_5GHZ) BIT(IEEE80211_BAND_5GHZ) + * @sw_crypto: 0 for hw, 1 for sw + * @max_xxx_size: for ucode uses + * @ct_kill_threshold: temperature threshold * @struct iwl_sensitivity_ranges: range of sensitivity values */ struct iwl_hw_params { @@ -595,13 +606,19 @@ struct iwl_hw_params { u32 max_pkt_size; u8 max_stations; u8 bcast_sta_id; + u8 fat_channel; + u8 sw_crypto; + u32 max_inst_size; + u32 max_data_size; + u32 max_bsm_size; + u32 ct_kill_threshold; /* value in hw-dependent units */ #ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB const struct iwl_sensitivity_ranges *sens; #endif }; -#define HT_SHORT_GI_20MHZ_ONLY (1 << 0) -#define HT_SHORT_GI_40MHZ_ONLY (1 << 1) +#define HT_SHORT_GI_20MHZ_ONLY (1 << 0) +#define HT_SHORT_GI_40MHZ_ONLY (1 << 1) #define IWL_RX_HDR(x) ((struct iwl4965_rx_frame_hdr *)(\ diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index c5ac82c4aeb..b223087b087 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -828,7 +828,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) le16_to_cpu(priv->staging_rxon.channel), print_mac(mac, priv->staging_rxon.bssid_addr)); - iwl4965_set_rxon_hwcrypto(priv, !priv->cfg->mod_params->sw_crypto); + iwl4965_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto); /* Apply the new configuration */ rc = iwl_send_cmd_pdu(priv, REPLY_RXON, sizeof(struct iwl4965_rxon_cmd), &priv->staging_rxon); @@ -4855,34 +4855,34 @@ static int iwl4965_read_ucode(struct iwl_priv *priv) } /* Verify that uCode images will fit in card's SRAM */ - if (inst_size > IWL_MAX_INST_SIZE) { + if (inst_size > priv->hw_params.max_inst_size) { IWL_DEBUG_INFO("uCode instr len %d too large to fit in\n", inst_size); ret = -EINVAL; goto err_release; } - if (data_size > IWL_MAX_DATA_SIZE) { + if (data_size > priv->hw_params.max_data_size) { IWL_DEBUG_INFO("uCode data len %d too large to fit in\n", data_size); ret = -EINVAL; goto err_release; } - if (init_size > IWL_MAX_INST_SIZE) { + if (init_size > priv->hw_params.max_inst_size) { IWL_DEBUG_INFO ("uCode init instr len %d too large to fit in\n", init_size); ret = -EINVAL; goto err_release; } - if (init_data_size > IWL_MAX_DATA_SIZE) { + if (init_data_size > priv->hw_params.max_data_size) { IWL_DEBUG_INFO ("uCode init data len %d too large to fit in\n", init_data_size); ret = -EINVAL; goto err_release; } - if (boot_size > IWL_MAX_BSM_SIZE) { + if (boot_size > priv->hw_params.max_bsm_size) { IWL_DEBUG_INFO ("uCode boot instr len %d too large to fit in\n", boot_size); @@ -6606,7 +6606,7 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, IWL_DEBUG_MAC80211("enter\n"); - if (priv->cfg->mod_params->sw_crypto) { + if (priv->hw_params.sw_crypto) { IWL_DEBUG_MAC80211("leave - hwcrypto disabled\n"); return -EOPNOTSUPP; } -- cgit v1.2.3-70-g09d2 From 82c78925eef1edc7bf96816074eae1ee59047d9a Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Mon, 21 Apr 2008 15:41:54 -0700 Subject: iwlwifi: remove includes to net/ieee80211.h this patch removes remaining includes to net/ieee80211.h Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 1 - drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 1 - 2 files changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index 85c22641542..e51eeeff699 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index 557912af1ff..e20c9385c35 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include -- cgit v1.2.3-70-g09d2 From 9e5b806ce3f3943964d3f95415a21223c1983933 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 21 Apr 2008 15:41:55 -0700 Subject: iwlwifi: remove uneeded callback This patch removes callbacks that can be replaced by the generic one. Signed-off-by: Emmanuel Grumbach Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl4965-base.c | 42 +---------------------------- 1 file changed, 1 insertion(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index b223087b087..11339efa273 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -941,13 +941,6 @@ static int iwl4965_send_scan_abort(struct iwl_priv *priv) return rc; } -static int iwl4965_card_state_sync_callback(struct iwl_priv *priv, - struct iwl_cmd *cmd, - struct sk_buff *skb) -{ - return 1; -} - /* * CARD_STATE_CMD * @@ -967,40 +960,9 @@ static int iwl4965_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_fla .meta.flags = meta_flag, }; - if (meta_flag & CMD_ASYNC) - cmd.meta.u.callback = iwl4965_card_state_sync_callback; - return iwl_send_cmd(priv, &cmd); } -static int iwl4965_add_sta_sync_callback(struct iwl_priv *priv, - struct iwl_cmd *cmd, struct sk_buff *skb) -{ - struct iwl4965_rx_packet *res = NULL; - - if (!skb) { - IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n"); - return 1; - } - - res = (struct iwl4965_rx_packet *)skb->data; - if (res->hdr.flags & IWL_CMD_FAILED_MSK) { - IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n", - res->hdr.flags); - return 1; - } - - switch (res->u.add_sta.status) { - case ADD_STA_SUCCESS_MSK: - break; - default: - break; - } - - /* We didn't cache the SKB; let the caller free it */ - return 1; -} - int iwl4965_send_add_station(struct iwl_priv *priv, struct iwl4965_addsta_cmd *sta, u8 flags) { @@ -1013,9 +975,7 @@ int iwl4965_send_add_station(struct iwl_priv *priv, .data = sta, }; - if (flags & CMD_ASYNC) - cmd.meta.u.callback = iwl4965_add_sta_sync_callback; - else + if (!(flags & CMD_ASYNC)) cmd.meta.flags |= CMD_WANT_SKB; rc = iwl_send_cmd(priv, &cmd); -- cgit v1.2.3-70-g09d2 From fe7c4040c3d8b7de521e9a48ae583580f8e31127 Mon Sep 17 00:00:00 2001 From: Guy Cohen Date: Mon, 21 Apr 2008 15:41:56 -0700 Subject: iwlwifi: remove support for Narrow Channel (10Mhz) Setting Narrow Channel bit in the scan command caused the device not to send probe request on all the channels Signed-off-by: Guy Cohen Signed-off-by: Emmanuel Grumbach Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945-hw.h | 2 +- drivers/net/wireless/iwlwifi/iwl-3945.h | 5 ----- drivers/net/wireless/iwlwifi/iwl-4965.h | 5 ----- drivers/net/wireless/iwlwifi/iwl-eeprom.c | 6 ++---- drivers/net/wireless/iwlwifi/iwl-eeprom.h | 2 +- drivers/net/wireless/iwlwifi/iwl3945-base.c | 6 +----- drivers/net/wireless/iwlwifi/iwl4965-base.c | 3 --- 7 files changed, 5 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h index ad612a8719f..8821c26992f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h @@ -126,7 +126,7 @@ enum { EEPROM_CHANNEL_ACTIVE = (1 << 3), /* active scanning allowed */ EEPROM_CHANNEL_RADAR = (1 << 4), /* radar detection required */ EEPROM_CHANNEL_WIDE = (1 << 5), /* 20 MHz channel okay */ - EEPROM_CHANNEL_NARROW = (1 << 6), /* 10 MHz channel (not used) */ + /* Bit 6 Reserved (was Narrow Channel) */ EEPROM_CHANNEL_DFS = (1 << 7), /* dynamic freq selection candidate */ }; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index c7695a215a3..fb96c62ad0f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -924,11 +924,6 @@ static inline int is_channel_valid(const struct iwl3945_channel_info *ch_info) return (ch_info->flags & EEPROM_CHANNEL_VALID) ? 1 : 0; } -static inline int is_channel_narrow(const struct iwl3945_channel_info *ch_info) -{ - return (ch_info->flags & EEPROM_CHANNEL_NARROW) ? 1 : 0; -} - static inline int is_channel_radar(const struct iwl3945_channel_info *ch_info) { return (ch_info->flags & EEPROM_CHANNEL_RADAR) ? 1 : 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h index 31f5447b797..07209f85cb5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965.h @@ -1227,11 +1227,6 @@ static inline int is_channel_valid(const struct iwl_channel_info *ch_info) return (ch_info->flags & EEPROM_CHANNEL_VALID) ? 1 : 0; } -static inline int is_channel_narrow(const struct iwl_channel_info *ch_info) -{ - return (ch_info->flags & EEPROM_CHANNEL_NARROW) ? 1 : 0; -} - static inline int is_channel_radar(const struct iwl_channel_info *ch_info) { return (ch_info->flags & EEPROM_CHANNEL_RADAR) ? 1 : 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index a436f877882..efd48ca27a8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -377,7 +377,7 @@ static int iwl4965_set_fat_chan_info(struct iwl_priv *priv, if (!is_channel_valid(ch_info)) return -1; - IWL_DEBUG_INFO("FAT Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x" + IWL_DEBUG_INFO("FAT Ch. %d [%sGHz] %s%s%s%s%s(0x%02x" " %ddBm): Ad-Hoc %ssupported\n", ch_info->channel, is_channel_a_band(ch_info) ? @@ -386,7 +386,6 @@ static int iwl4965_set_fat_chan_info(struct iwl_priv *priv, CHECK_AND_PRINT(ACTIVE), CHECK_AND_PRINT(RADAR), CHECK_AND_PRINT(WIDE), - CHECK_AND_PRINT(NARROW), CHECK_AND_PRINT(DFS), eeprom_ch->flags, eeprom_ch->max_power_avg, @@ -490,7 +489,7 @@ int iwl_init_channel_map(struct iwl_priv *priv) ch_info->scan_power = eeprom_ch_info[ch].max_power_avg; ch_info->min_power = 0; - IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s%s(0x%02x" + IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x" " %ddBm): Ad-Hoc %ssupported\n", ch_info->channel, is_channel_a_band(ch_info) ? @@ -500,7 +499,6 @@ int iwl_init_channel_map(struct iwl_priv *priv) CHECK_AND_PRINT_I(ACTIVE), CHECK_AND_PRINT_I(RADAR), CHECK_AND_PRINT_I(WIDE), - CHECK_AND_PRINT_I(NARROW), CHECK_AND_PRINT_I(DFS), eeprom_ch_info[ch].flags, eeprom_ch_info[ch].max_power_avg, diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 26a73e918c5..d5768146d02 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -106,7 +106,7 @@ enum { EEPROM_CHANNEL_ACTIVE = (1 << 3), /* active scanning allowed */ EEPROM_CHANNEL_RADAR = (1 << 4), /* radar detection required */ EEPROM_CHANNEL_WIDE = (1 << 5), /* 20 MHz channel okay */ - EEPROM_CHANNEL_NARROW = (1 << 6), /* 10 MHz channel (not used) */ + /* Bit 6 Reserved (was Narrow Channel) */ EEPROM_CHANNEL_DFS = (1 << 7), /* dynamic freq selection candidate */ }; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 7bdffa9cfea..67fd267c99c 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -4841,7 +4841,7 @@ static int iwl3945_init_channel_map(struct iwl3945_priv *priv) ch_info->scan_power = eeprom_ch_info[ch].max_power_avg; ch_info->min_power = 0; - IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s%s(0x%02x" + IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x" " %ddBm): Ad-Hoc %ssupported\n", ch_info->channel, is_channel_a_band(ch_info) ? @@ -4851,7 +4851,6 @@ static int iwl3945_init_channel_map(struct iwl3945_priv *priv) CHECK_AND_PRINT(ACTIVE), CHECK_AND_PRINT(RADAR), CHECK_AND_PRINT(WIDE), - CHECK_AND_PRINT(NARROW), CHECK_AND_PRINT(DFS), eeprom_ch_info[ch].flags, eeprom_ch_info[ch].max_power_avg, @@ -4987,9 +4986,6 @@ static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv, if (scan_ch->type & 1) scan_ch->type |= (direct_mask << 1); - if (is_channel_narrow(ch_info)) - scan_ch->type |= (1 << 7); - scan_ch->active_dwell = cpu_to_le16(active_dwell); scan_ch->passive_dwell = cpu_to_le16(passive_dwell); diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 11339efa273..6309f08c3a1 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -4392,9 +4392,6 @@ static int iwl4965_get_channels_for_scan(struct iwl_priv *priv, if (scan_ch->type & 1) scan_ch->type |= (direct_mask << 1); - if (is_channel_narrow(ch_info)) - scan_ch->type |= (1 << 7); - scan_ch->active_dwell = cpu_to_le16(active_dwell); scan_ch->passive_dwell = cpu_to_le16(passive_dwell); -- cgit v1.2.3-70-g09d2 From b73cdf27e0f412bcd01802287bb9710e6b74fca5 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 21 Apr 2008 15:41:58 -0700 Subject: iwlwifi: CT-Kill configuration fix This patch fixes the configuration of CT-Kill. Signed-off-by: Assaf Krauss Signed-off-by: Emmanuel Grumbach Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 26 +++++--------------------- 1 file changed, 5 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 9b3a745b66b..91cc03f76e1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -969,15 +969,9 @@ static void iwl4965_bg_statistics_periodic(unsigned long data) iwl_send_statistics_request(priv, CMD_ASYNC); } -#define CT_LIMIT_CONST 259 -#define TM_CT_KILL_THRESHOLD 110 - void iwl4965_rf_kill_ct_config(struct iwl_priv *priv) { struct iwl4965_ct_kill_config cmd; - u32 R1, R2, R3; - u32 temp_th; - u32 crit_temperature; unsigned long flags; int ret = 0; @@ -986,27 +980,17 @@ void iwl4965_rf_kill_ct_config(struct iwl_priv *priv) CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); spin_unlock_irqrestore(&priv->lock, flags); - if (priv->statistics.flag & STATISTICS_REPLY_FLG_FAT_MODE_MSK) { - R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[1]); - R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[1]); - R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[1]); - } else { - R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[0]); - R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[0]); - R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[0]); - } - - temp_th = CELSIUS_TO_KELVIN(TM_CT_KILL_THRESHOLD); - - crit_temperature = ((temp_th * (R3-R1))/CT_LIMIT_CONST) + R2; cmd.critical_temperature_R = - cpu_to_le32(priv->hw_params.ct_kill_threshold); + cpu_to_le32(priv->hw_params.ct_kill_threshold); + ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD, sizeof(cmd), &cmd); if (ret) IWL_ERROR("REPLY_CT_KILL_CONFIG_CMD failed\n"); else - IWL_DEBUG_INFO("REPLY_CT_KILL_CONFIG_CMD succeeded\n"); + IWL_DEBUG_INFO("REPLY_CT_KILL_CONFIG_CMD succeeded, " + "critical temperature is %d\n", + cmd.critical_temperature_R); } #ifdef CONFIG_IWL4965_RUN_TIME_CALIB -- cgit v1.2.3-70-g09d2 From cc2a8ea82ef869532cb7764b9eac30338773fe88 Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Mon, 21 Apr 2008 15:41:59 -0700 Subject: iwlwifi: support 64 bit DMA masks This patch adds consistent DMA masks for 64 bit Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl4965-base.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 6309f08c3a1..028523af010 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -7440,13 +7440,19 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e pci_set_master(pdev); - err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + err = pci_set_dma_mask(pdev, DMA_64BIT_MASK); if (!err) - err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); + if (err) { + err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (!err) + err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + /* both attempts failed: */ if (err) { - printk(KERN_WARNING DRV_NAME - ": No suitable DMA available.\n"); + printk(KERN_WARNING "%s: No suitable DMA available.\n", + DRV_NAME); goto out_pci_disable_device; + } } err = pci_request_regions(pdev, DRV_NAME); -- cgit v1.2.3-70-g09d2 From d1141dfb3ab5545491e3aa15b7f0d7330a186281 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 21 Apr 2008 15:42:00 -0700 Subject: iwlwifi: HT IE in probe request clean up This patch cleans up the scan flow. This patch cleans up the insertion of the HT IE in the probe request. Signed-off-by: Emmanuel Grumbach Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl4965-base.c | 182 +++++++++++++++------------- 1 file changed, 101 insertions(+), 81 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 028523af010..4bfc670e878 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -99,7 +99,7 @@ __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr) return NULL; } -static const struct ieee80211_supported_band *iwl4965_get_hw_mode( +static const struct ieee80211_supported_band *iwl_get_hw_mode( struct iwl_priv *priv, enum ieee80211_band band) { return priv->hw->wiphy->bands[band]; @@ -1166,6 +1166,91 @@ static u16 iwl4965_supported_rate_to_ie(u8 *ie, u16 supported_rate, return ret_rates; } +#ifdef CONFIG_IWL4965_HT +static void iwl4965_ht_conf(struct iwl_priv *priv, + struct ieee80211_bss_conf *bss_conf) +{ + struct ieee80211_ht_info *ht_conf = bss_conf->ht_conf; + struct ieee80211_ht_bss_info *ht_bss_conf = bss_conf->ht_bss_conf; + struct iwl_ht_info *iwl_conf = &priv->current_ht_config; + + IWL_DEBUG_MAC80211("enter: \n"); + + iwl_conf->is_ht = bss_conf->assoc_ht; + + if (!iwl_conf->is_ht) + return; + + priv->ps_mode = (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2); + + if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20) + iwl_conf->sgf |= 0x1; + if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40) + iwl_conf->sgf |= 0x2; + + iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD); + iwl_conf->max_amsdu_size = + !!(ht_conf->cap & IEEE80211_HT_CAP_MAX_AMSDU); + + iwl_conf->supported_chan_width = + !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH); + iwl_conf->extension_chan_offset = + ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_SEC_OFFSET; + /* If no above or below channel supplied disable FAT channel */ + if (iwl_conf->extension_chan_offset != IWL_EXT_CHANNEL_OFFSET_ABOVE && + iwl_conf->extension_chan_offset != IWL_EXT_CHANNEL_OFFSET_BELOW) + iwl_conf->supported_chan_width = 0; + + iwl_conf->tx_mimo_ps_mode = + (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2); + memcpy(iwl_conf->supp_mcs_set, ht_conf->supp_mcs_set, 16); + + iwl_conf->control_channel = ht_bss_conf->primary_channel; + iwl_conf->tx_chan_width = + !!(ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_WIDTH); + iwl_conf->ht_protection = + ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_HT_PROTECTION; + iwl_conf->non_GF_STA_present = + !!(ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_NON_GF_STA_PRSNT); + + IWL_DEBUG_MAC80211("control channel %d\n", iwl_conf->control_channel); + IWL_DEBUG_MAC80211("leave\n"); +} + +static void iwl_ht_cap_to_ie(const struct ieee80211_supported_band *sband, + u8 *pos, int *left) +{ + struct ieee80211_ht_cap *ht_cap; + + if (!sband || !sband->ht_info.ht_supported) + return; + + if (*left < sizeof(struct ieee80211_ht_cap)) + return; + + *pos++ = sizeof(struct ieee80211_ht_cap); + ht_cap = (struct ieee80211_ht_cap *) pos; + + ht_cap->cap_info = cpu_to_le16(sband->ht_info.cap); + memcpy(ht_cap->supp_mcs_set, sband->ht_info.supp_mcs_set, 16); + ht_cap->ampdu_params_info = + (sband->ht_info.ampdu_factor & IEEE80211_HT_CAP_AMPDU_FACTOR) | + ((sband->ht_info.ampdu_density << 2) & + IEEE80211_HT_CAP_AMPDU_DENSITY); + *left -= sizeof(struct ieee80211_ht_cap); +} +#else +static inline void iwl4965_ht_conf(struct iwl_priv *priv, + struct ieee80211_bss_conf *bss_conf) +{ +} +static void iwl_ht_cap_to_ie(const struct ieee80211_supported_band *sband, + u8 *pos, int *left) +{ +} +#endif + + /** * iwl4965_fill_probe_req - fill in all required fields and IE for probe request */ @@ -1177,10 +1262,8 @@ static u16 iwl4965_fill_probe_req(struct iwl_priv *priv, int len = 0; u8 *pos = NULL; u16 active_rates, ret_rates, cck_rates, active_rate_basic; -#ifdef CONFIG_IWL4965_HT const struct ieee80211_supported_band *sband = - iwl4965_get_hw_mode(priv, band); -#endif /* CONFIG_IWL4965_HT */ + iwl_get_hw_mode(priv, band); /* Make sure there is enough space for the probe request, * two mandatory IEs and the data */ @@ -1263,24 +1346,19 @@ static u16 iwl4965_fill_probe_req(struct iwl_priv *priv, if (*pos > 0) len += 2 + *pos; -#ifdef CONFIG_IWL4965_HT - if (sband && sband->ht_info.ht_supported) { - struct ieee80211_ht_cap *ht_cap; - pos += (*pos) + 1; - *pos++ = WLAN_EID_HT_CAPABILITY; - *pos++ = sizeof(struct ieee80211_ht_cap); - ht_cap = (struct ieee80211_ht_cap *)pos; - ht_cap->cap_info = cpu_to_le16(sband->ht_info.cap); - memcpy(ht_cap->supp_mcs_set, sband->ht_info.supp_mcs_set, 16); - ht_cap->ampdu_params_info =(sband->ht_info.ampdu_factor & - IEEE80211_HT_CAP_AMPDU_FACTOR) | - ((sband->ht_info.ampdu_density << 2) & - IEEE80211_HT_CAP_AMPDU_DENSITY); - len += 2 + sizeof(struct ieee80211_ht_cap); - } -#endif /*CONFIG_IWL4965_HT */ - fill_end: + /* fill in HT IE */ + left -= 2; + if (left < 0) + return 0; + + *pos++ = WLAN_EID_HT_CAPABILITY; + *pos = 0; + + iwl_ht_cap_to_ie(sband, pos, &left); + + if (*pos > 0) + len += 2 + *pos; return (u16)len; } @@ -2146,7 +2224,7 @@ static void iwl4965_set_rate(struct iwl_priv *priv) struct ieee80211_rate *rate; int i; - hw = iwl4965_get_hw_mode(priv, priv->band); + hw = iwl_get_hw_mode(priv, priv->band); if (!hw) { IWL_ERROR("Failed to set rate: unable to get hw mode\n"); return; @@ -4360,7 +4438,7 @@ static int iwl4965_get_channels_for_scan(struct iwl_priv *priv, u16 active_dwell = 0; int added, i; - sband = iwl4965_get_hw_mode(priv, band); + sband = iwl_get_hw_mode(priv, band); if (!sband) return 0; @@ -6328,64 +6406,6 @@ static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw, } - -#ifdef CONFIG_IWL4965_HT -static void iwl4965_ht_conf(struct iwl_priv *priv, - struct ieee80211_bss_conf *bss_conf) -{ - struct ieee80211_ht_info *ht_conf = bss_conf->ht_conf; - struct ieee80211_ht_bss_info *ht_bss_conf = bss_conf->ht_bss_conf; - struct iwl_ht_info *iwl_conf = &priv->current_ht_config; - - IWL_DEBUG_MAC80211("enter: \n"); - - iwl_conf->is_ht = bss_conf->assoc_ht; - - if (!iwl_conf->is_ht) - return; - - priv->ps_mode = (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2); - - if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20) - iwl_conf->sgf |= 0x1; - if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40) - iwl_conf->sgf |= 0x2; - - iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD); - iwl_conf->max_amsdu_size = - !!(ht_conf->cap & IEEE80211_HT_CAP_MAX_AMSDU); - - iwl_conf->supported_chan_width = - !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH); - iwl_conf->extension_chan_offset = - ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_SEC_OFFSET; - /* If no above or below channel supplied disable FAT channel */ - if (iwl_conf->extension_chan_offset != IWL_EXT_CHANNEL_OFFSET_ABOVE && - iwl_conf->extension_chan_offset != IWL_EXT_CHANNEL_OFFSET_BELOW) - iwl_conf->supported_chan_width = 0; - - iwl_conf->tx_mimo_ps_mode = - (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2); - memcpy(iwl_conf->supp_mcs_set, ht_conf->supp_mcs_set, 16); - - iwl_conf->control_channel = ht_bss_conf->primary_channel; - iwl_conf->tx_chan_width = - !!(ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_WIDTH); - iwl_conf->ht_protection = - ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_HT_PROTECTION; - iwl_conf->non_GF_STA_present = - !!(ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_NON_GF_STA_PRSNT); - - IWL_DEBUG_MAC80211("control channel %d\n", iwl_conf->control_channel); - IWL_DEBUG_MAC80211("leave\n"); -} -#else -static inline void iwl4965_ht_conf(struct iwl_priv *priv, - struct ieee80211_bss_conf *bss_conf) -{ -} -#endif - #define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6) static void iwl4965_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, -- cgit v1.2.3-70-g09d2 From fde0db310fd4979e0d8e6ba009975d23cc7e65ac Mon Sep 17 00:00:00 2001 From: Guy Cohen Date: Mon, 21 Apr 2008 15:42:01 -0700 Subject: iwlwifi: HT antenna/chains overhaul 1. This patch restructures rate scale algorithm to support SISO, MIMO2, MIMO3 2. It adds support for detailed valid TX and RX antennas settings 3. It removes few unesfull antenna definitions Signed-off-by: Guy Cohen Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-commands.h | 9 +- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 337 +++++++++++------------ drivers/net/wireless/iwlwifi/iwl-4965-rs.h | 85 ++++-- drivers/net/wireless/iwlwifi/iwl-4965.c | 57 ++-- drivers/net/wireless/iwlwifi/iwl-4965.h | 15 +- drivers/net/wireless/iwlwifi/iwl-calib.c | 3 +- drivers/net/wireless/iwlwifi/iwl4965-base.c | 39 --- 7 files changed, 262 insertions(+), 283 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-commands.h b/drivers/net/wireless/iwlwifi/iwl-4965-commands.h index b2fa58d2d17..7ffae05a930 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-commands.h @@ -269,10 +269,11 @@ struct iwl_cmd_header { * 10 B active, A inactive * 11 Both active */ -#define RATE_MCS_ANT_POS 14 -#define RATE_MCS_ANT_A_MSK 0x04000 -#define RATE_MCS_ANT_B_MSK 0x08000 -#define RATE_MCS_ANT_AB_MSK 0x0C000 +#define RATE_MCS_ANT_POS 14 +#define RATE_MCS_ANT_A_MSK 0x04000 +#define RATE_MCS_ANT_B_MSK 0x08000 +#define RATE_MCS_ANT_C_MSK 0x10000 +#define RATE_MCS_ANT_ABC_MSK 0x1C000 /** diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index e20c9385c35..31a0451f7a4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -87,8 +87,8 @@ struct iwl4965_rate_scale_data { * one for "active", and one for "search". */ struct iwl4965_scale_tbl_info { - enum iwl4965_table_type lq_type; - enum iwl4965_antenna_type antenna_type; + enum iwl_table_type lq_type; + u8 ant_type; u8 is_SGI; /* 1 = short guard interval */ u8 is_fat; /* 1 = 40 MHz channel width */ u8 is_dup; /* 1 = duplicated data streams */ @@ -146,7 +146,8 @@ struct iwl4965_lq_sta { u32 supp_rates; u16 active_rate; u16 active_siso_rate; - u16 active_mimo_rate; + u16 active_mimo2_rate; + u16 active_mimo3_rate; u16 active_rate_basic; struct iwl_link_quality_cmd lq; @@ -170,7 +171,8 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, struct net_device *dev, struct ieee80211_hdr *hdr, struct sta_info *sta); -static void rs_fill_link_cmd(struct iwl4965_lq_sta *lq_sta, +static void rs_fill_link_cmd(const struct iwl_priv *priv, + struct iwl4965_lq_sta *lq_sta, struct iwl4965_rate *tx_mcs, struct iwl_link_quality_cmd *tbl); @@ -189,6 +191,7 @@ static void rs_dbgfs_set_mcs(struct iwl4965_lq_sta *lq_sta, * 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 60 MBits * "G" is the only table that supports CCK (the first 4 rates). */ +/*FIXME:RS:need to spearate tables for MIMO2/MIMO3*/ static s32 expected_tpt_A[IWL_RATE_COUNT] = { 0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186, 186 }; @@ -373,6 +376,13 @@ static void rs_tl_turn_on_agg(struct iwl_priv *priv, u8 tid, #endif /* CONFIG_IWLWIFI_HT */ +static inline int get_num_of_ant_from_mcs(u32 mcs) +{ + return (!!(mcs & RATE_MCS_ANT_A_MSK) + + !!(mcs & RATE_MCS_ANT_B_MSK) + + !!(mcs & RATE_MCS_ANT_C_MSK)); +} + /** * rs_collect_tx_data - Update the success/failure sliding window * @@ -466,31 +476,28 @@ static void rs_mcs_from_tbl(struct iwl4965_rate *mcs_rate, if (index >= IWL_FIRST_CCK_RATE && index <= IWL_LAST_CCK_RATE) mcs_rate->rate_n_flags |= RATE_MCS_CCK_MSK; - } else if (is_siso(tbl->lq_type)) { - if (index > IWL_LAST_OFDM_RATE) + } else if (is_Ht(tbl->lq_type)) { + if (index > IWL_LAST_OFDM_RATE) { + IWL_ERROR("invalid HT rate index %d\n", index); index = IWL_LAST_OFDM_RATE; - mcs_rate->rate_n_flags = iwl4965_rates[index].plcp_siso | - RATE_MCS_HT_MSK; + } + mcs_rate->rate_n_flags = RATE_MCS_HT_MSK; + + if (is_siso(tbl->lq_type)) + mcs_rate->rate_n_flags |= + iwl4965_rates[index].plcp_siso; + else if (is_mimo2(tbl->lq_type)) + mcs_rate->rate_n_flags |= + iwl4965_rates[index].plcp_mimo2; + else + mcs_rate->rate_n_flags |= + iwl4965_rates[index].plcp_mimo3; } else { - if (index > IWL_LAST_OFDM_RATE) - index = IWL_LAST_OFDM_RATE; - mcs_rate->rate_n_flags = iwl4965_rates[index].plcp_mimo | - RATE_MCS_HT_MSK; + IWL_ERROR("Invalid tbl->lq_type %d\n", tbl->lq_type); } - switch (tbl->antenna_type) { - case ANT_BOTH: - mcs_rate->rate_n_flags |= RATE_MCS_ANT_AB_MSK; - break; - case ANT_MAIN: - mcs_rate->rate_n_flags |= RATE_MCS_ANT_A_MSK; - break; - case ANT_AUX: - mcs_rate->rate_n_flags |= RATE_MCS_ANT_B_MSK; - break; - case ANT_NONE: - break; - } + mcs_rate->rate_n_flags |= ((tbl->ant_type << RATE_MCS_ANT_POS) & + RATE_MCS_ANT_ABC_MSK); if (is_legacy(tbl->lq_type)) return; @@ -520,69 +527,31 @@ static int rs_get_tbl_info_from_mcs(const struct iwl4965_rate *mcs_rate, struct iwl4965_scale_tbl_info *tbl, int *rate_idx) { - int index; - u32 ant_msk; + u32 ant_msk = (mcs_rate->rate_n_flags & RATE_MCS_ANT_ABC_MSK); + u8 num_of_ant = get_num_of_ant_from_mcs(ant_msk); - index = iwl4965_hwrate_to_plcp_idx(mcs_rate->rate_n_flags); + *rate_idx = iwl4965_hwrate_to_plcp_idx(mcs_rate->rate_n_flags); - if (index == IWL_RATE_INVALID) { + if (*rate_idx == IWL_RATE_INVALID) { *rate_idx = -1; return -EINVAL; } tbl->is_SGI = 0; /* default legacy setup */ tbl->is_fat = 0; tbl->is_dup = 0; - tbl->antenna_type = ANT_BOTH; /* default MIMO setup */ + tbl->ant_type = (ant_msk >> RATE_MCS_ANT_POS); + tbl->lq_type = LQ_NONE; /* legacy rate format */ if (!(mcs_rate->rate_n_flags & RATE_MCS_HT_MSK)) { - ant_msk = (mcs_rate->rate_n_flags & RATE_MCS_ANT_AB_MSK); - - if (ant_msk == RATE_MCS_ANT_AB_MSK) - tbl->lq_type = LQ_NONE; - else { - + if (num_of_ant == 1) { if (band == IEEE80211_BAND_5GHZ) tbl->lq_type = LQ_A; else tbl->lq_type = LQ_G; - - if (mcs_rate->rate_n_flags & RATE_MCS_ANT_A_MSK) - tbl->antenna_type = ANT_MAIN; - else - tbl->antenna_type = ANT_AUX; - } - *rate_idx = index; - - /* HT rate format, SISO (might be 20 MHz legacy or 40 MHz fat width) */ - } else if (iwl4965_rate_get_rate(mcs_rate->rate_n_flags) - <= IWL_RATE_SISO_60M_PLCP) { - tbl->lq_type = LQ_SISO; - - ant_msk = (mcs_rate->rate_n_flags & RATE_MCS_ANT_AB_MSK); - if (ant_msk == RATE_MCS_ANT_AB_MSK) - tbl->lq_type = LQ_NONE; - else { - if (mcs_rate->rate_n_flags & RATE_MCS_ANT_A_MSK) - tbl->antenna_type = ANT_MAIN; - else - tbl->antenna_type = ANT_AUX; } - if (mcs_rate->rate_n_flags & RATE_MCS_SGI_MSK) - tbl->is_SGI = 1; - - if ((mcs_rate->rate_n_flags & RATE_MCS_FAT_MSK) || - (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK)) - tbl->is_fat = 1; - - if (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK) - tbl->is_dup = 1; - - *rate_idx = index; - - /* HT rate format, MIMO (might be 20 MHz legacy or 40 MHz fat width) */ + /* HT rate format */ } else { - tbl->lq_type = LQ_MIMO; if (mcs_rate->rate_n_flags & RATE_MCS_SGI_MSK) tbl->is_SGI = 1; @@ -592,23 +561,32 @@ static int rs_get_tbl_info_from_mcs(const struct iwl4965_rate *mcs_rate, if (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK) tbl->is_dup = 1; - *rate_idx = index; + + /* SISO */ + if (iwl4965_rate_get_rate(mcs_rate->rate_n_flags) + <= IWL_RATE_SISO_60M_PLCP) { + + if (num_of_ant == 1) + tbl->lq_type = LQ_SISO; /*else NONE*/ + /* MIMO2 */ + } else if (iwl4965_rate_get_rate(mcs_rate->rate_n_flags) + <= IWL_RATE_MIMO2_60M_PLCP) { + if (num_of_ant == 2) + tbl->lq_type = LQ_MIMO2; + /* MIMO3 */ + } else { + if (num_of_ant == 3) + tbl->lq_type = LQ_MIMO3; + } } return 0; } - +/* FIXME:RS: need to toggle also ANT_C, and also AB,AC,BC */ static inline void rs_toggle_antenna(struct iwl4965_rate *new_rate, struct iwl4965_scale_tbl_info *tbl) { - if (tbl->antenna_type == ANT_AUX) { - tbl->antenna_type = ANT_MAIN; - new_rate->rate_n_flags &= ~RATE_MCS_ANT_B_MSK; - new_rate->rate_n_flags |= RATE_MCS_ANT_A_MSK; - } else { - tbl->antenna_type = ANT_AUX; - new_rate->rate_n_flags &= ~RATE_MCS_ANT_A_MSK; - new_rate->rate_n_flags |= RATE_MCS_ANT_B_MSK; - } + tbl->ant_type ^= ANT_AB; + new_rate->rate_n_flags ^= (RATE_MCS_ANT_A_MSK|RATE_MCS_ANT_B_MSK); } static inline u8 rs_use_green(struct iwl_priv *priv, @@ -631,7 +609,7 @@ static inline u8 rs_use_green(struct iwl_priv *priv, */ static void rs_get_supported_rates(struct iwl4965_lq_sta *lq_sta, struct ieee80211_hdr *hdr, - enum iwl4965_table_type rate_type, + enum iwl_table_type rate_type, u16 *data_rate) { if (is_legacy(rate_type)) @@ -639,8 +617,10 @@ static void rs_get_supported_rates(struct iwl4965_lq_sta *lq_sta, else { if (is_siso(rate_type)) *data_rate = lq_sta->active_siso_rate; + else if (is_mimo2(rate_type)) + *data_rate = lq_sta->active_mimo2_rate; else - *data_rate = lq_sta->active_mimo_rate; + *data_rate = lq_sta->active_mimo3_rate; } if (hdr && is_multicast_ether_addr(hdr->addr1) && @@ -725,9 +705,8 @@ static void rs_get_lower_rate(struct iwl4965_lq_sta *lq_sta, else tbl->lq_type = LQ_G; - if ((tbl->antenna_type == ANT_BOTH) || - (tbl->antenna_type == ANT_NONE)) - tbl->antenna_type = ANT_MAIN; + if (num_of_ant(tbl->ant_type > 1)) + tbl->ant_type = ANT_A;/*FIXME:RS*/ tbl->is_fat = 0; tbl->is_SGI = 0; @@ -821,13 +800,6 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, table = &lq_sta->lq; active_index = lq_sta->active_tbl; - /* Get mac80211 antenna info */ - lq_sta->antenna = - (lq_sta->valid_antenna & local->hw.conf.antenna_sel_tx); - if (!lq_sta->antenna) - lq_sta->antenna = lq_sta->valid_antenna; - - /* Ignore mac80211 antenna info for now */ lq_sta->antenna = lq_sta->valid_antenna; curr_tbl = &(lq_sta->lq_info[active_index]); @@ -857,8 +829,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, !!(tx_resp->control.flags & IEEE80211_TXCTL_40_MHZ_WIDTH)) || (tbl_type.is_dup ^ !!(tx_resp->control.flags & IEEE80211_TXCTL_DUP_DATA)) || - (tbl_type.antenna_type ^ - tx_resp->control.antenna_sel_tx) || + (tbl_type.ant_type ^ tx_resp->control.antenna_sel_tx) || (!!(tx_mcs.rate_n_flags & RATE_MCS_HT_MSK) ^ !!(tx_resp->control.flags & IEEE80211_TXCTL_OFDM_HT)) || (!!(tx_mcs.rate_n_flags & RATE_MCS_GF_MSK) ^ @@ -882,7 +853,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, /* If type matches "search" table, * add failure to "search" history */ if ((tbl_type.lq_type == search_tbl->lq_type) && - (tbl_type.antenna_type == search_tbl->antenna_type) && + (tbl_type.ant_type == search_tbl->ant_type) && (tbl_type.is_SGI == search_tbl->is_SGI)) { if (search_tbl->expected_tpt) tpt = search_tbl->expected_tpt[rs_index]; @@ -893,7 +864,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, /* Else if type matches "current/active" table, * add failure to "current/active" history */ } else if ((tbl_type.lq_type == curr_tbl->lq_type) && - (tbl_type.antenna_type == curr_tbl->antenna_type) && + (tbl_type.ant_type == curr_tbl->ant_type) && (tbl_type.is_SGI == curr_tbl->is_SGI)) { if (curr_tbl->expected_tpt) tpt = curr_tbl->expected_tpt[rs_index]; @@ -928,7 +899,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, /* If type matches "search" table, * add final tx status to "search" history */ if ((tbl_type.lq_type == search_tbl->lq_type) && - (tbl_type.antenna_type == search_tbl->antenna_type) && + (tbl_type.ant_type == search_tbl->ant_type) && (tbl_type.is_SGI == search_tbl->is_SGI)) { if (search_tbl->expected_tpt) tpt = search_tbl->expected_tpt[rs_index]; @@ -944,7 +915,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, /* Else if type matches "current/active" table, * add final tx status to "current/active" history */ } else if ((tbl_type.lq_type == curr_tbl->lq_type) && - (tbl_type.antenna_type == curr_tbl->antenna_type) && + (tbl_type.ant_type == curr_tbl->ant_type) && (tbl_type.is_SGI == curr_tbl->is_SGI)) { if (curr_tbl->expected_tpt) tpt = curr_tbl->expected_tpt[rs_index]; @@ -981,26 +952,18 @@ out: return; } -static u8 rs_is_ant_connected(u8 valid_antenna, - enum iwl4965_antenna_type antenna_type) +static inline u8 rs_is_ant_connected(u8 valid_antenna, u8 ant_type) { - if (antenna_type == ANT_AUX) - return ((valid_antenna & 0x2) ? 1:0); - else if (antenna_type == ANT_MAIN) - return ((valid_antenna & 0x1) ? 1:0); - else if (antenna_type == ANT_BOTH) - return ((valid_antenna & 0x3) == 0x3); - - return 1; + return ((ant_type & valid_antenna) == ant_type); } -static u8 rs_is_other_ant_connected(u8 valid_antenna, - enum iwl4965_antenna_type antenna_type) +/*FIXME:RS: this function should be replaced*/ +static u8 rs_is_other_ant_connected(u8 valid_antenna, u8 ant_type) { - if (antenna_type == ANT_AUX) - return rs_is_ant_connected(valid_antenna, ANT_MAIN); + if (ant_type == ANT_B) + return rs_is_ant_connected(valid_antenna, ANT_A); else - return rs_is_ant_connected(valid_antenna, ANT_AUX); + return rs_is_ant_connected(valid_antenna, ANT_B); return 0; } @@ -1054,7 +1017,7 @@ static void rs_get_expected_tpt_table(struct iwl4965_lq_sta *lq_sta, else tbl->expected_tpt = expected_tpt_siso20MHz; - } else if (is_mimo(tbl->lq_type)) { + } else if (is_mimo(tbl->lq_type)) { /* FIXME:need to separate mimo2/3 */ if (tbl->is_fat && !lq_sta->is_dup) if (tbl->is_SGI) tbl->expected_tpt = expected_tpt_mimo40MHzSGI; @@ -1171,21 +1134,22 @@ static s32 rs_get_best_rate(struct iwl_priv *priv, } #endif /* CONFIG_IWL4965_HT */ +/*FIXME:RS:this function should be replaced*/ static inline u8 rs_is_both_ant_supp(u8 valid_antenna) { - return (rs_is_ant_connected(valid_antenna, ANT_BOTH)); + return (rs_is_ant_connected(valid_antenna, ANT_AB)); } /* * Set up search table for MIMO */ -static int rs_switch_to_mimo(struct iwl_priv *priv, +#ifdef CONFIG_IWL4965_HT +static int rs_switch_to_mimo2(struct iwl_priv *priv, struct iwl4965_lq_sta *lq_sta, struct ieee80211_conf *conf, struct sta_info *sta, struct iwl4965_scale_tbl_info *tbl, int index) { -#ifdef CONFIG_IWL4965_HT u16 rate_mask; s32 rate; s8 is_green = lq_sta->is_green; @@ -1195,7 +1159,7 @@ static int rs_switch_to_mimo(struct iwl_priv *priv, return -1; IWL_DEBUG_HT("LQ: try to switch to MIMO\n"); - tbl->lq_type = LQ_MIMO; + tbl->lq_type = LQ_MIMO2; rs_get_supported_rates(lq_sta, NULL, tbl->lq_type, &rate_mask); @@ -1203,7 +1167,7 @@ static int rs_switch_to_mimo(struct iwl_priv *priv, return -1; /* Need both Tx chains/antennas to support MIMO */ - if (!rs_is_both_ant_supp(lq_sta->antenna)) + if (!rs_is_both_ant_supp(priv->hw_params.valid_tx_ant)) return -1; tbl->is_dup = lq_sta->is_dup; @@ -1236,10 +1200,17 @@ static int rs_switch_to_mimo(struct iwl_priv *priv, IWL_DEBUG_HT("LQ: Switch to new mcs %X index is green %X\n", tbl->current_rate.rate_n_flags, is_green); return 0; +} #else +static int rs_switch_to_mimo2(struct iwl_priv *priv, + struct iwl4965_lq_sta *lq_sta, + struct ieee80211_conf *conf, + struct sta_info *sta, + struct iwl4965_scale_tbl_info *tbl, int index) +{ return -1; -#endif /*CONFIG_IWL4965_HT */ } +#endif /*CONFIG_IWL4965_HT */ /* * Set up search table for SISO @@ -1313,7 +1284,6 @@ static int rs_move_legacy_other(struct iwl_priv *priv, struct sta_info *sta, int index) { - int ret = 0; struct iwl4965_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); struct iwl4965_scale_tbl_info *search_tbl = @@ -1322,6 +1292,8 @@ static int rs_move_legacy_other(struct iwl_priv *priv, u32 sz = (sizeof(struct iwl4965_scale_tbl_info) - (sizeof(struct iwl4965_rate_scale_data) * IWL_RATE_COUNT)); u8 start_action = tbl->action; + u8 valid_tx_ant = priv->hw_params.valid_tx_ant; + int ret = 0; for (; ;) { switch (tbl->action) { @@ -1336,8 +1308,8 @@ static int rs_move_legacy_other(struct iwl_priv *priv, break; /* Don't change antenna if other one is not connected */ - if (!rs_is_other_ant_connected(lq_sta->antenna, - tbl->antenna_type)) + if (!rs_is_other_ant_connected(valid_tx_ant, + tbl->ant_type)) break; /* Set up search table to try other antenna */ @@ -1366,16 +1338,17 @@ static int rs_move_legacy_other(struct iwl_priv *priv, } break; - case IWL_LEGACY_SWITCH_MIMO: + case IWL_LEGACY_SWITCH_MIMO2: IWL_DEBUG_HT("LQ: Legacy switch MIMO\n"); /* Set up search table to try MIMO */ memcpy(search_tbl, tbl, sz); - search_tbl->lq_type = LQ_MIMO; + search_tbl->lq_type = LQ_MIMO2; search_tbl->is_SGI = 0; search_tbl->is_fat = 0; - search_tbl->antenna_type = ANT_BOTH; - ret = rs_switch_to_mimo(priv, lq_sta, conf, sta, + search_tbl->ant_type = ANT_AB;/*FIXME:RS*/ + /*FIXME:RS:need to check ant validity*/ + ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta, search_tbl, index); if (!ret) { lq_sta->search_better_tbl = 1; @@ -1385,7 +1358,7 @@ static int rs_move_legacy_other(struct iwl_priv *priv, break; } tbl->action++; - if (tbl->action > IWL_LEGACY_SWITCH_MIMO) + if (tbl->action > IWL_LEGACY_SWITCH_MIMO2) tbl->action = IWL_LEGACY_SWITCH_ANTENNA; if (tbl->action == start_action) @@ -1396,7 +1369,7 @@ static int rs_move_legacy_other(struct iwl_priv *priv, out: tbl->action++; - if (tbl->action > IWL_LEGACY_SWITCH_MIMO) + if (tbl->action > IWL_LEGACY_SWITCH_MIMO2) tbl->action = IWL_LEGACY_SWITCH_ANTENNA; return 0; @@ -1411,7 +1384,6 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, struct sta_info *sta, int index) { - int ret; u8 is_green = lq_sta->is_green; struct iwl4965_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); @@ -1421,6 +1393,8 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, u32 sz = (sizeof(struct iwl4965_scale_tbl_info) - (sizeof(struct iwl4965_rate_scale_data) * IWL_RATE_COUNT)); u8 start_action = tbl->action; + u8 valid_tx_ant = priv->hw_params.valid_tx_ant; + int ret; for (;;) { lq_sta->action_counter++; @@ -1430,26 +1404,26 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, search_tbl->lq_type = LQ_NONE; if (window->success_ratio >= IWL_RS_GOOD_RATIO) break; - if (!rs_is_other_ant_connected(lq_sta->antenna, - tbl->antenna_type)) + if (!rs_is_other_ant_connected(valid_tx_ant, + tbl->ant_type)) break; memcpy(search_tbl, tbl, sz); - search_tbl->action = IWL_SISO_SWITCH_MIMO; + search_tbl->action = IWL_SISO_SWITCH_MIMO2; rs_toggle_antenna(&(search_tbl->current_rate), search_tbl); lq_sta->search_better_tbl = 1; goto out; - case IWL_SISO_SWITCH_MIMO: - IWL_DEBUG_HT("LQ: SISO SWITCH TO MIMO FROM SISO\n"); + case IWL_SISO_SWITCH_MIMO2: + IWL_DEBUG_HT("LQ: SISO SWITCH TO MIMO2 FROM SISO\n"); memcpy(search_tbl, tbl, sz); - search_tbl->lq_type = LQ_MIMO; + search_tbl->lq_type = LQ_MIMO2; search_tbl->is_SGI = 0; search_tbl->is_fat = 0; - search_tbl->antenna_type = ANT_BOTH; - ret = rs_switch_to_mimo(priv, lq_sta, conf, sta, + search_tbl->ant_type = ANT_AB; /*FIXME:RS*/ + ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta, search_tbl, index); if (!ret) { lq_sta->search_better_tbl = 1; @@ -1530,10 +1504,11 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv, search_tbl->lq_type = LQ_SISO; search_tbl->is_SGI = 0; search_tbl->is_fat = 0; + /*FIXME:RS:need to check ant validity + C*/ if (tbl->action == IWL_MIMO_SWITCH_ANTENNA_A) - search_tbl->antenna_type = ANT_MAIN; + search_tbl->ant_type = ANT_A; else - search_tbl->antenna_type = ANT_AUX; + search_tbl->ant_type = ANT_B; ret = rs_switch_to_siso(priv, lq_sta, conf, sta, search_tbl, index); @@ -1548,8 +1523,6 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv, /* Set up new search table for MIMO */ memcpy(search_tbl, tbl, sz); - search_tbl->lq_type = LQ_MIMO; - search_tbl->antenna_type = ANT_BOTH; search_tbl->action = 0; if (search_tbl->is_SGI) search_tbl->is_SGI = 0; @@ -1563,7 +1536,7 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv, * and it's working well, there's no need to look * for a better type of modulation! */ - if ((tbl->lq_type == LQ_MIMO) && + if ((tbl->lq_type == LQ_MIMO2) && (tbl->is_SGI)) { s32 tpt = lq_sta->last_tpt / 100; if (((!tbl->is_fat) && @@ -1830,7 +1803,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, /* Set up new rate table in uCode, if needed */ if (update_lq) { rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green); - rs_fill_link_cmd(lq_sta, &mcs_rate, &lq_sta->lq); + rs_fill_link_cmd(priv, lq_sta, &mcs_rate, &lq_sta->lq); iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); } goto out; @@ -1995,7 +1968,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, /* Replace uCode's rate table for the destination station. */ if (update_lq) { rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green); - rs_fill_link_cmd(lq_sta, &mcs_rate, &lq_sta->lq); + rs_fill_link_cmd(priv, lq_sta, &mcs_rate, &lq_sta->lq); iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); } @@ -2034,7 +2007,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, IWL_DEBUG_HT("Switch current mcs: %X index: %d\n", tbl->current_rate.rate_n_flags, index); - rs_fill_link_cmd(lq_sta, &tbl->current_rate, + rs_fill_link_cmd(priv, lq_sta, &tbl->current_rate, &lq_sta->lq); iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); } @@ -2133,6 +2106,7 @@ static void rs_initialize_lq(struct iwl_priv *priv, if ((i < 0) || (i >= IWL_RATE_COUNT)) i = 0; + /* FIXME:RS: This is also wrong in 4965 */ mcs_rate.rate_n_flags = iwl4965_rates[i].plcp ; mcs_rate.rate_n_flags |= RATE_MCS_ANT_B_MSK; mcs_rate.rate_n_flags &= ~RATE_MCS_ANT_A_MSK; @@ -2140,15 +2114,15 @@ static void rs_initialize_lq(struct iwl_priv *priv, if (i >= IWL_FIRST_CCK_RATE && i <= IWL_LAST_CCK_RATE) mcs_rate.rate_n_flags |= RATE_MCS_CCK_MSK; - tbl->antenna_type = ANT_AUX; + tbl->ant_type = ANT_B; rs_get_tbl_info_from_mcs(&mcs_rate, priv->band, tbl, &rate_idx); - if (!rs_is_ant_connected(priv->valid_antenna, tbl->antenna_type)) + if (!rs_is_ant_connected(priv->hw_params.valid_tx_ant, tbl->ant_type)) rs_toggle_antenna(&mcs_rate, tbl); rs_mcs_from_tbl(&mcs_rate, tbl, rate_idx, use_green); tbl->current_rate.rate_n_flags = mcs_rate.rate_n_flags; rs_get_expected_tpt_table(lq_sta, tbl); - rs_fill_link_cmd(lq_sta, &mcs_rate, &lq_sta->lq); + rs_fill_link_cmd(NULL, lq_sta, &mcs_rate, &lq_sta->lq); iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); out: return; @@ -2300,8 +2274,6 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; lq_sta->is_dup = 0; - lq_sta->valid_antenna = priv->valid_antenna; - lq_sta->antenna = priv->antenna; lq_sta->is_green = rs_use_green(priv, conf); lq_sta->active_rate = priv->active_rate; lq_sta->active_rate &= ~(0x1000); @@ -2312,23 +2284,33 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, * active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3), * supp_rates[] does not; shift to convert format, force 9 MBits off. */ - lq_sta->active_siso_rate = (priv->current_ht_config.supp_mcs_set[0] << 1); + lq_sta->active_siso_rate = + priv->current_ht_config.supp_mcs_set[0] << 1; lq_sta->active_siso_rate |= - (priv->current_ht_config.supp_mcs_set[0] & 0x1); + priv->current_ht_config.supp_mcs_set[0] & 0x1; lq_sta->active_siso_rate &= ~((u16)0x2); - lq_sta->active_siso_rate = - lq_sta->active_siso_rate << IWL_FIRST_OFDM_RATE; + lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE; /* Same here */ - lq_sta->active_mimo_rate = (priv->current_ht_config.supp_mcs_set[1] << 1); - lq_sta->active_mimo_rate |= - (priv->current_ht_config.supp_mcs_set[1] & 0x1); - lq_sta->active_mimo_rate &= ~((u16)0x2); - lq_sta->active_mimo_rate = - lq_sta->active_mimo_rate << IWL_FIRST_OFDM_RATE; - IWL_DEBUG_HT("SISO RATE 0x%X MIMO RATE 0x%X\n", + lq_sta->active_mimo2_rate = + priv->current_ht_config.supp_mcs_set[1] << 1; + lq_sta->active_mimo2_rate |= + priv->current_ht_config.supp_mcs_set[1] & 0x1; + lq_sta->active_mimo2_rate &= ~((u16)0x2); + lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE; + + lq_sta->active_mimo3_rate = + priv->current_ht_config.supp_mcs_set[2] << 1; + lq_sta->active_mimo3_rate |= + priv->current_ht_config.supp_mcs_set[2] & 0x1; + lq_sta->active_mimo3_rate &= ~((u16)0x2); + lq_sta->active_mimo3_rate <<= IWL_FIRST_OFDM_RATE; + + IWL_DEBUG_HT("SISO RATE %X MIMO2 RATE %X MIMO3 RATE %X\n", lq_sta->active_siso_rate, - lq_sta->active_mimo_rate); + lq_sta->active_mimo2_rate, + lq_sta->active_mimo3_rate); + /* as default allow aggregation for all tids */ lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID; #endif /*CONFIG_IWL4965_HT*/ @@ -2342,9 +2324,10 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, rs_initialize_lq(priv, conf, sta); } -static void rs_fill_link_cmd(struct iwl4965_lq_sta *lq_sta, - struct iwl4965_rate *tx_mcs, - struct iwl_link_quality_cmd *lq_cmd) +static void rs_fill_link_cmd(const struct iwl_priv *priv, + struct iwl4965_lq_sta *lq_sta, + struct iwl4965_rate *tx_mcs, + struct iwl_link_quality_cmd *lq_cmd) { int index = 0; int rate_idx; @@ -2376,7 +2359,8 @@ static void rs_fill_link_cmd(struct iwl4965_lq_sta *lq_sta, cpu_to_le32(tx_mcs->rate_n_flags); new_rate.rate_n_flags = tx_mcs->rate_n_flags; - if (is_mimo(tbl_type.lq_type) || (tbl_type.antenna_type == ANT_MAIN)) + /*FIXME:RS*/ + if (is_mimo(tbl_type.lq_type) || (tbl_type.ant_type == ANT_A)) lq_cmd->general_params.single_stream_ant_msk = LINK_QUAL_ANT_A_MSK; else @@ -2396,7 +2380,9 @@ static void rs_fill_link_cmd(struct iwl4965_lq_sta *lq_sta, if (ant_toggle_count < NUM_TRY_BEFORE_ANTENNA_TOGGLE) ant_toggle_count++; - else { + else if (priv && rs_is_other_ant_connected( + priv->hw_params.valid_tx_ant, + tbl_type.ant_type)) { rs_toggle_antenna(&new_rate, &tbl_type); ant_toggle_count = 1; } @@ -2429,7 +2415,9 @@ static void rs_fill_link_cmd(struct iwl4965_lq_sta *lq_sta, if (is_legacy(tbl_type.lq_type)) { if (ant_toggle_count < NUM_TRY_BEFORE_ANTENNA_TOGGLE) ant_toggle_count++; - else { + else if (priv && rs_is_other_ant_connected( + priv->hw_params.valid_tx_ant, + tbl_type.ant_type)) { rs_toggle_antenna(&new_rate, &tbl_type); ant_toggle_count = 1; } @@ -2536,13 +2524,14 @@ static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file, lq_sta->active_rate = 0x0FFF; /* 1 - 54 MBits, includes CCK */ lq_sta->active_siso_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */ - lq_sta->active_mimo_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */ + 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 */ IWL_DEBUG_RATE("sta_id %d rate 0x%X\n", lq_sta->lq.sta_id, lq_sta->dbg_fixed.rate_n_flags); if (lq_sta->dbg_fixed.rate_n_flags) { - rs_fill_link_cmd(lq_sta, &lq_sta->dbg_fixed, &lq_sta->lq); + rs_fill_link_cmd(NULL, lq_sta, &lq_sta->dbg_fixed, &lq_sta->lq); iwl_send_lq_cmd(lq_sta->drv, &lq_sta->lq, CMD_ASYNC); } @@ -2703,7 +2692,7 @@ int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) lq_sta = (void *)sta->rate_ctrl_priv; lq_type = lq_sta->lq_info[lq_sta->active_tbl].lq_type; - antenna = lq_sta->lq_info[lq_sta->active_tbl].antenna_type; + antenna = lq_sta->lq_info[lq_sta->active_tbl].ant_type; if (is_legacy(lq_type)) i = IWL_RATE_54M_INDEX; diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.h b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h index 866e378aa38..f6793203515 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h @@ -32,7 +32,8 @@ struct iwl4965_rate_info { u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */ u8 plcp_siso; /* uCode API: IWL_RATE_SISO_6M_PLCP, etc. */ - u8 plcp_mimo; /* uCode API: IWL_RATE_MIMO_6M_PLCP, etc. */ + u8 plcp_mimo2; /* uCode API: IWL_RATE_MIMO2_6M_PLCP, etc. */ + u8 plcp_mimo3; /* uCode API: IWL_RATE_MIMO3_6M_PLCP, etc. */ u8 ieee; /* MAC header: IWL_RATE_6M_IEEE, etc. */ u8 prev_ieee; /* previous rate in IEEE speeds */ u8 next_ieee; /* next rate in IEEE speeds */ @@ -60,9 +61,9 @@ enum { IWL_RATE_48M_INDEX, IWL_RATE_54M_INDEX, IWL_RATE_60M_INDEX, - IWL_RATE_COUNT, + IWL_RATE_COUNT, /*FIXME:RS:change to IWL_RATE_INDEX_COUNT,*/ IWL_RATE_INVM_INDEX = IWL_RATE_COUNT, - IWL_RATE_INVALID = IWL_RATE_INVM_INDEX + IWL_RATE_INVALID = IWL_RATE_COUNT, }; enum { @@ -97,11 +98,13 @@ enum { IWL_RATE_36M_PLCP = 11, IWL_RATE_48M_PLCP = 1, IWL_RATE_54M_PLCP = 3, - IWL_RATE_60M_PLCP = 3, + IWL_RATE_60M_PLCP = 3,/*FIXME:RS:should be removed*/ IWL_RATE_1M_PLCP = 10, IWL_RATE_2M_PLCP = 20, IWL_RATE_5M_PLCP = 55, IWL_RATE_11M_PLCP = 110, + /*FIXME:RS:change to IWL_RATE_LEGACY_??M_PLCP */ + /*FIXME:RS:add IWL_RATE_LEGACY_INVM_PLCP = 0,*/ }; /* 4965 uCode API values for OFDM high-throughput (HT) bit rates */ @@ -114,16 +117,25 @@ enum { IWL_RATE_SISO_48M_PLCP = 5, IWL_RATE_SISO_54M_PLCP = 6, IWL_RATE_SISO_60M_PLCP = 7, - IWL_RATE_MIMO_6M_PLCP = 0x8, - IWL_RATE_MIMO_12M_PLCP = 0x9, - IWL_RATE_MIMO_18M_PLCP = 0xa, - IWL_RATE_MIMO_24M_PLCP = 0xb, - IWL_RATE_MIMO_36M_PLCP = 0xc, - IWL_RATE_MIMO_48M_PLCP = 0xd, - IWL_RATE_MIMO_54M_PLCP = 0xe, - IWL_RATE_MIMO_60M_PLCP = 0xf, + IWL_RATE_MIMO2_6M_PLCP = 0x8, + IWL_RATE_MIMO2_12M_PLCP = 0x9, + IWL_RATE_MIMO2_18M_PLCP = 0xa, + IWL_RATE_MIMO2_24M_PLCP = 0xb, + IWL_RATE_MIMO2_36M_PLCP = 0xc, + IWL_RATE_MIMO2_48M_PLCP = 0xd, + IWL_RATE_MIMO2_54M_PLCP = 0xe, + IWL_RATE_MIMO2_60M_PLCP = 0xf, + IWL_RATE_MIMO3_6M_PLCP = 0x10, + IWL_RATE_MIMO3_12M_PLCP = 0x11, + IWL_RATE_MIMO3_18M_PLCP = 0x12, + IWL_RATE_MIMO3_24M_PLCP = 0x13, + IWL_RATE_MIMO3_36M_PLCP = 0x14, + IWL_RATE_MIMO3_48M_PLCP = 0x15, + IWL_RATE_MIMO3_54M_PLCP = 0x16, + IWL_RATE_MIMO3_60M_PLCP = 0x17, IWL_RATE_SISO_INVM_PLCP, - IWL_RATE_MIMO_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP, + IWL_RATE_MIMO2_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP, + IWL_RATE_MIMO3_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP, }; /* MAC header values for bit rates */ @@ -196,11 +208,11 @@ enum { /* possible actions when in legacy mode */ #define IWL_LEGACY_SWITCH_ANTENNA 0 #define IWL_LEGACY_SWITCH_SISO 1 -#define IWL_LEGACY_SWITCH_MIMO 2 +#define IWL_LEGACY_SWITCH_MIMO2 2 /* possible actions when in siso mode */ #define IWL_SISO_SWITCH_ANTENNA 0 -#define IWL_SISO_SWITCH_MIMO 1 +#define IWL_SISO_SWITCH_MIMO2 1 #define IWL_SISO_SWITCH_GI 2 /* possible actions when in mimo mode */ @@ -208,6 +220,10 @@ enum { #define IWL_MIMO_SWITCH_ANTENNA_B 1 #define IWL_MIMO_SWITCH_GI 2 +/*FIXME:RS:separate MIMO2/3 transitions*/ + +/*FIXME:RS:add posible acctions for MIMO3*/ + #define IWL_ACTION_LIMIT 3 /* # possible actions */ #define LQ_SIZE 2 /* 2 mode tables: "Active" and "Search" */ @@ -226,29 +242,40 @@ enum { extern const struct iwl4965_rate_info iwl4965_rates[IWL_RATE_COUNT]; -enum iwl4965_table_type { +enum iwl_table_type { LQ_NONE, LQ_G, /* legacy types */ LQ_A, LQ_SISO, /* high-throughput types */ - LQ_MIMO, + LQ_MIMO2, + LQ_MIMO3, LQ_MAX, }; #define is_legacy(tbl) (((tbl) == LQ_G) || ((tbl) == LQ_A)) -#define is_siso(tbl) (((tbl) == LQ_SISO)) -#define is_mimo(tbl) (((tbl) == LQ_MIMO)) +#define is_siso(tbl) ((tbl) == LQ_SISO) +#define is_mimo2(tbl) ((tbl) == LQ_MIMO2) +#define is_mimo3(tbl) ((tbl) == LQ_MIMO3) +#define is_mimo(tbl) (is_mimo2(tbl) || is_mimo3(tbl)) #define is_Ht(tbl) (is_siso(tbl) || is_mimo(tbl)) -#define is_a_band(tbl) (((tbl) == LQ_A)) -#define is_g_and(tbl) (((tbl) == LQ_G)) - -/* 4965 has 2 antennas/chains for Tx (but 3 for Rx) */ -enum iwl4965_antenna_type { - ANT_NONE, - ANT_MAIN, - ANT_AUX, - ANT_BOTH, -}; +#define is_a_band(tbl) ((tbl) == LQ_A) +#define is_g_and(tbl) ((tbl) == LQ_G) + +#define ANT_NONE 0x0 +#define ANT_A BIT(0) +#define ANT_B BIT(1) +#define ANT_AB (ANT_A | ANT_B) +#define ANT_C BIT(2) +#define ANT_AC (ANT_A | ANT_C) +#define ANT_BC (ANT_B | ANT_C) +#define ANT_ABC (ANT_AB | ANT_C) + +static inline u8 num_of_ant(u8 mask) +{ + return !!((mask) & ANT_A) + + !!((mask) & ANT_B) + + !!((mask) & ANT_C); +} static inline u8 iwl4965_get_prev_ieee_rate(u8 rate_index) { diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 91cc03f76e1..2c5bfa4f048 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -58,7 +58,8 @@ static void iwl4965_hw_card_show_info(struct iwl_priv *priv); #define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np) \ [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \ IWL_RATE_SISO_##s##M_PLCP, \ - IWL_RATE_MIMO_##s##M_PLCP, \ + IWL_RATE_MIMO2_##s##M_PLCP,\ + IWL_RATE_MIMO3_##s##M_PLCP,\ IWL_RATE_##r##M_IEEE, \ IWL_RATE_##ip##M_INDEX, \ IWL_RATE_##in##M_INDEX, \ @@ -89,6 +90,7 @@ const struct iwl4965_rate_info iwl4965_rates[IWL_RATE_COUNT] = { IWL_DECLARE_RATE_INFO(48, 48, 36, 54, 36, 54, 36, 54), /* 48mbps */ IWL_DECLARE_RATE_INFO(54, 54, 48, INV, 48, INV, 48, INV),/* 54mbps */ IWL_DECLARE_RATE_INFO(60, 60, 48, INV, 48, INV, 48, INV),/* 60mbps */ + /* FIXME:RS: ^^ should be INV (legacy) */ }; #ifdef CONFIG_IWL4965_HT @@ -265,7 +267,6 @@ static int iwl4965_init_drv(struct iwl_priv *priv) int ret; int i; - priv->antenna = (enum iwl4965_antenna)priv->cfg->mod_params->antenna; priv->retry_rate = 1; priv->ibss_beacon = NULL; @@ -305,7 +306,6 @@ static int iwl4965_init_drv(struct iwl_priv *priv) priv->iw_mode = IEEE80211_IF_TYPE_STA; priv->use_ant_b_for_management_frame = 1; /* start with ant B */ - priv->valid_antenna = 0x7; /* assume all 3 connected */ priv->ps_mode = IWL_MIMO_PS_NONE; /* Choose which receivers/antennas to use */ @@ -361,18 +361,20 @@ static int is_fat_channel(__le32 rxon_flags) (rxon_flags & RXON_FLG_CHANNEL_MODE_MIXED_MSK); } -static u8 is_single_stream(struct iwl_priv *priv) -{ #ifdef CONFIG_IWL4965_HT - if (!priv->current_ht_config.is_ht || - (priv->current_ht_config.supp_mcs_set[1] == 0) || - (priv->ps_mode == IWL_MIMO_PS_STATIC)) - return 1; +static u8 is_single_rx_stream(struct iwl_priv *priv) +{ + return !priv->current_ht_config.is_ht || + ((priv->current_ht_config.supp_mcs_set[1] == 0) && + (priv->current_ht_config.supp_mcs_set[2] == 0)) || + priv->ps_mode == IWL_MIMO_PS_STATIC; +} #else +static inline u8 is_single_rx_stream(struct iwl_priv *priv) +{ return 1; -#endif /*CONFIG_IWL4965_HT */ - return 0; } +#endif /*CONFIG_IWL4965_HT */ int iwl4965_hwrate_to_plcp_idx(u32 rate_n_flags) { @@ -382,8 +384,8 @@ int iwl4965_hwrate_to_plcp_idx(u32 rate_n_flags) if (rate_n_flags & RATE_MCS_HT_MSK) { idx = (rate_n_flags & 0xff); - if (idx >= IWL_RATE_MIMO_6M_PLCP) - idx = idx - IWL_RATE_MIMO_6M_PLCP; + if (idx >= IWL_RATE_MIMO2_6M_PLCP) + idx = idx - IWL_RATE_MIMO2_6M_PLCP; idx += IWL_FIRST_OFDM_RATE; /* skip 9M not supported in ht*/ @@ -411,7 +413,7 @@ void iwl4965_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, int rate_index; control->antenna_sel_tx = - ((rate_n_flags & RATE_MCS_ANT_AB_MSK) >> RATE_MCS_ANT_POS); + ((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS); if (rate_n_flags & RATE_MCS_HT_MSK) control->flags |= IEEE80211_TXCTL_OFDM_HT; if (rate_n_flags & RATE_MCS_GF_MSK) @@ -441,7 +443,7 @@ void iwl4965_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, static int iwl4965_get_rx_chain_counter(struct iwl_priv *priv, u8 *idle_state, u8 *rx_state) { - u8 is_single = is_single_stream(priv); + u8 is_single = is_single_rx_stream(priv); u8 is_cam = test_bit(STATUS_POWER_PMI, &priv->status) ? 0 : 1; /* # of Rx chains to use when expecting MIMO. */ @@ -1344,8 +1346,8 @@ int iwl4965_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.tx_chains_num = 2; priv->hw_params.rx_chains_num = 2; - priv->hw_params.valid_tx_ant = (IWL_ANTENNA_MAIN | IWL_ANTENNA_AUX); - priv->hw_params.valid_rx_ant = (IWL_ANTENNA_MAIN | IWL_ANTENNA_AUX); + priv->hw_params.valid_tx_ant = ANT_A | ANT_B; + priv->hw_params.valid_rx_ant = ANT_A | ANT_B; priv->hw_params.ct_kill_threshold = CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD); #ifdef CONFIG_IWL4965_RUN_TIME_CALIB @@ -2512,7 +2514,7 @@ static void iwl4965_txq_update_byte_cnt_tbl(struct iwl_priv *priv, */ void iwl4965_set_rxon_chain(struct iwl_priv *priv) { - u8 is_single = is_single_stream(priv); + u8 is_single = is_single_rx_stream(priv); u8 idle_state, rx_state; priv->staging_rxon.rx_chain = 0; @@ -2523,7 +2525,8 @@ void iwl4965_set_rxon_chain(struct iwl_priv *priv) * Just after first association, iwl_chain_noise_calibration() * checks which antennas actually *are* connected. */ priv->staging_rxon.rx_chain |= - cpu_to_le16(priv->valid_antenna << RXON_RX_CHAIN_VALID_POS); + cpu_to_le16(priv->hw_params.valid_rx_ant << + RXON_RX_CHAIN_VALID_POS); /* How many receivers should we use? */ iwl4965_get_rx_chain_counter(priv, &idle_state, &rx_state); @@ -3106,7 +3109,7 @@ static int iwl4965_calc_rssi(struct iwl4965_rx_phy_res *rx_resp) #ifdef CONFIG_IWL4965_HT -void iwl4965_init_ht_hw_capab(struct iwl_priv *priv, +void iwl4965_init_ht_hw_capab(const struct iwl_priv *priv, struct ieee80211_ht_info *ht_info, enum ieee80211_band band) { @@ -3132,7 +3135,10 @@ void iwl4965_init_ht_hw_capab(struct iwl_priv *priv, ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF; ht_info->supp_mcs_set[0] = 0xFF; - ht_info->supp_mcs_set[1] = 0xFF; + if (priv->hw_params.tx_chains_num >= 2) + ht_info->supp_mcs_set[1] = 0xFF; + if (priv->hw_params.tx_chains_num >= 3) + ht_info->supp_mcs_set[2] = 0xFF; } #endif /* CONFIG_IWL4965_HT */ @@ -3910,8 +3916,7 @@ void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) rate_flags |= RATE_MCS_CCK_MSK; /* Use Tx antenna B only */ - rate_flags |= RATE_MCS_ANT_B_MSK; - rate_flags &= ~RATE_MCS_ANT_A_MSK; + rate_flags |= RATE_MCS_ANT_B_MSK; /*FIXME:RS*/ link_cmd.rs_table[i].rate_n_flags = iwl4965_hw_set_rate_n_flags(iwl4965_rates[r].plcp, rate_flags); @@ -4016,11 +4021,13 @@ void iwl4965_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) iwl4965_set_rxon_chain(priv); - IWL_DEBUG_ASSOC("supported HT rate 0x%X %X " + IWL_DEBUG_ASSOC("supported HT rate 0x%X 0x%X 0x%X " "rxon flags 0x%X operation mode :0x%X " "extension channel offset 0x%x " "control chan %d\n", - ht_info->supp_mcs_set[0], ht_info->supp_mcs_set[1], + ht_info->supp_mcs_set[0], + ht_info->supp_mcs_set[1], + ht_info->supp_mcs_set[2], le32_to_cpu(rxon->flags), ht_info->ht_protection, ht_info->extension_chan_offset, ht_info->control_channel); diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h index 07209f85cb5..6df51cca228 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965.h @@ -71,12 +71,6 @@ extern struct iwl_cfg iwl4965_agn_cfg; * averages within an s8's (used in some apps) range of negative values. */ #define IWL_NOISE_MEAS_NOT_AVAILABLE (-127) -enum iwl4965_antenna { - IWL_ANTENNA_DIVERSITY, - IWL_ANTENNA_MAIN, - IWL_ANTENNA_AUX -}; - /* * RTS threshold here is total size [2347] minus 4 FCS bytes * Per spec: @@ -763,9 +757,9 @@ extern void iwl4965_hwrate_to_tx_control(struct iwl_priv *priv, struct ieee80211_tx_control *control); #ifdef CONFIG_IWL4965_HT -void iwl4965_init_ht_hw_capab(struct iwl_priv *priv, - struct ieee80211_ht_info *ht_info, - enum ieee80211_band band); +extern void iwl4965_init_ht_hw_capab(const struct iwl_priv *priv, + struct ieee80211_ht_info *ht_info, + enum ieee80211_band band); void iwl4965_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info); void iwl4965_set_ht_add_station(struct iwl_priv *priv, u8 index, @@ -776,7 +770,7 @@ int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, int iwl4965_check_empty_hw_queue(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id); #else -static inline void iwl4965_init_ht_hw_capab(struct iwl_priv *priv, +static inline void iwl4965_init_ht_hw_capab(const struct iwl_priv *priv, struct ieee80211_ht_info *ht_info, enum ieee80211_band band) {} @@ -1052,7 +1046,6 @@ struct iwl_priv { u8 assoc_station_added; u8 use_ant_b_for_management_frame; /* Tx antenna selection */ - u8 valid_antenna; /* Bit mask of antennas actually connected */ u8 start_calib; #ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB struct iwl_sensitivity_data sensitivity_data; diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index 16213b05ed9..59bbd7c9636 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -747,7 +747,8 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, active_chains); /* Save for use within RXON, TX, SCAN commands, etc. */ - priv->valid_antenna = active_chains; + /*priv->valid_antenna = active_chains;*/ + /*FIXME: should be reflected in RX chains in RXON */ /* Analyze noise for rx balance */ average_noise[0] = ((data->chain_noise_a)/CAL_NUM_OF_BEACONS); diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 4bfc670e878..1f5e7e6fa68 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -7242,44 +7242,6 @@ static ssize_t show_statistics(struct device *d, static DEVICE_ATTR(statistics, S_IRUGO, show_statistics, NULL); -static ssize_t show_antenna(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - - if (!iwl_is_alive(priv)) - return -EAGAIN; - - return sprintf(buf, "%d\n", priv->antenna); -} - -static ssize_t store_antenna(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - int ant; - struct iwl_priv *priv = dev_get_drvdata(d); - - if (count == 0) - return 0; - - if (sscanf(buf, "%1i", &ant) != 1) { - IWL_DEBUG_INFO("not in hex or decimal form.\n"); - return count; - } - - if ((ant >= 0) && (ant <= 2)) { - IWL_DEBUG_INFO("Setting antenna select to %d.\n", ant); - priv->antenna = (enum iwl4965_antenna)ant; - } else - IWL_DEBUG_INFO("Bad antenna select value %d.\n", ant); - - - return count; -} - -static DEVICE_ATTR(antenna, S_IWUSR | S_IRUGO, show_antenna, store_antenna); - static ssize_t show_status(struct device *d, struct device_attribute *attr, char *buf) { @@ -7362,7 +7324,6 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv) } static struct attribute *iwl4965_sysfs_entries[] = { - &dev_attr_antenna.attr, &dev_attr_channels.attr, &dev_attr_dump_errors.attr, &dev_attr_dump_events.attr, -- cgit v1.2.3-70-g09d2 From 91238714affef7603446207ad03a594d95d2eb9d Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 23 Apr 2008 17:14:53 -0700 Subject: iwlwifi: add apm init handler This patch add apm init handler to iwlcore handler Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 93 +++++++++++++++-------------- drivers/net/wireless/iwlwifi/iwl-core.h | 2 + drivers/net/wireless/iwlwifi/iwl4965-base.c | 18 ++---- 3 files changed, 56 insertions(+), 57 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 2c5bfa4f048..b8c72159b59 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -694,62 +694,71 @@ static int iwl4965_txq_ctx_reset(struct iwl_priv *priv) error_kw: return rc; } - -int iwl4965_hw_nic_init(struct iwl_priv *priv) +static int iwl4965_apm_init(struct iwl_priv *priv) { - int rc; unsigned long flags; - struct iwl4965_rx_queue *rxq = &priv->rxq; - u8 rev_id; - u8 val_link; - u16 sku_cap; - u32 val; + int ret = 0; - /* nic_init */ spin_lock_irqsave(&priv->lock, flags); - iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, - CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); + CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); + /* set "initialization complete" bit to move adapter + * D0U* --> D0A* state */ iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - rc = iwl_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); - if (rc < 0) { - spin_unlock_irqrestore(&priv->lock, flags); - IWL_DEBUG_INFO("Failed to init the card\n"); - return rc; - } - rc = iwl_grab_nic_access(priv); - if (rc) { - spin_unlock_irqrestore(&priv->lock, flags); - return rc; + /* wait for clock stabilization */ + ret = iwl_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + if (ret < 0) { + IWL_DEBUG_INFO("Failed to init the card\n"); + goto out; } - iwl_read_prph(priv, APMG_CLK_CTRL_REG); + ret = iwl_grab_nic_access(priv); + if (ret) + goto out; + /* enable DMA */ iwl_write_prph(priv, APMG_CLK_CTRL_REG, APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT); - iwl_read_prph(priv, APMG_CLK_CTRL_REG); udelay(20); iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, - APMG_PCIDEV_STT_VAL_L1_ACT_DIS); + APMG_PCIDEV_STT_VAL_L1_ACT_DIS); iwl_release_nic_access(priv); +out: + spin_unlock_irqrestore(&priv->lock, flags); + return ret; +} + +int iwl4965_hw_nic_init(struct iwl_priv *priv) +{ + unsigned long flags; + struct iwl4965_rx_queue *rxq = &priv->rxq; + u8 rev_id; + u8 val_link; + u32 val; + int ret; + + /* nic_init */ + priv->cfg->ops->lib->apm_ops.init(priv); + + spin_lock_irqsave(&priv->lock, flags); iwl_write32(priv, CSR_INT_COALESCING, 512 / 32); spin_unlock_irqrestore(&priv->lock, flags); /* Determine HW type */ - rc = pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &rev_id); - if (rc) - return rc; + ret = pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &rev_id); + if (ret) + return ret; IWL_DEBUG_INFO("HW Revision ID = 0x%X\n", rev_id); - rc = priv->cfg->ops->lib->apm_ops.set_pwr_src(priv, IWL_PWR_SRC_VMAIN); + ret = priv->cfg->ops->lib->apm_ops.set_pwr_src(priv, IWL_PWR_SRC_VMAIN); spin_lock_irqsave(&priv->lock, flags); @@ -782,11 +791,11 @@ int iwl4965_hw_nic_init(struct iwl_priv *priv) CSR49_HW_IF_CONFIG_REG_BIT_RADIO_SI | CSR49_HW_IF_CONFIG_REG_BIT_MAC_SI); - rc = iwl_grab_nic_access(priv); - if (rc < 0) { + ret = iwl_grab_nic_access(priv); + if (ret < 0) { spin_unlock_irqrestore(&priv->lock, flags); IWL_DEBUG_INFO("Failed to init the card\n"); - return rc; + return ret; } iwl_read_prph(priv, APMG_PS_CTRL_REG); @@ -803,8 +812,8 @@ int iwl4965_hw_nic_init(struct iwl_priv *priv) /* Allocate the RX queue, or reset if it is already allocated */ if (!rxq->bd) { - rc = iwl4965_rx_queue_alloc(priv); - if (rc) { + ret = iwl4965_rx_queue_alloc(priv); + if (ret) { IWL_ERROR("Unable to initialize Rx queue\n"); return -ENOMEM; } @@ -827,16 +836,9 @@ int iwl4965_hw_nic_init(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); /* Allocate and init all Tx and Command queues */ - rc = iwl4965_txq_ctx_reset(priv); - if (rc) - return rc; - - sku_cap = iwl_eeprom_query16(priv, EEPROM_SKU_CAP); - if (sku_cap & EEPROM_SKU_CAP_SW_RF_KILL_ENABLE) - IWL_DEBUG_RF_KILL("SW RF KILL supported in EEPROM.\n"); - - if (sku_cap & EEPROM_SKU_CAP_HW_RF_KILL_ENABLE) - IWL_DEBUG_RF_KILL("HW RF KILL supported in EEPROM.\n"); + ret = iwl4965_txq_ctx_reset(priv); + if (ret) + return ret; set_bit(STATUS_INIT, &priv->status); @@ -4344,6 +4346,7 @@ static struct iwl_lib_ops iwl4965_lib = { .alive_notify = iwl4965_alive_notify, .load_ucode = iwl4965_load_bsm, .apm_ops = { + .init = iwl4965_apm_init, .set_pwr_src = iwl4965_set_pwr_src, }, .eeprom_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 79e97935bbb..edda2ff92f7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -115,7 +115,9 @@ struct iwl_lib_ops { int (*load_ucode)(struct iwl_priv *priv); /* rfkill */ void (*radio_kill_sw)(struct iwl_priv *priv, int disable_radio); + /* power management */ struct { + int (*init)(struct iwl_priv *priv); int (*set_pwr_src)(struct iwl_priv *priv, enum iwl_pwr_src src); } apm_ops; /* power */ diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 1f5e7e6fa68..c837503c1e0 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -7462,21 +7462,15 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e printk(KERN_INFO DRV_NAME ": Detected Intel Wireless WiFi Link %s\n", priv->cfg->name); - /***************** - * 4. Read EEPROM - *****************/ - /* nic init */ - iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, - CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); - - iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - err = iwl_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + /* amp init */ + err = priv->cfg->ops->lib->apm_ops.init(priv); if (err < 0) { - IWL_DEBUG_INFO("Failed to init the card\n"); + IWL_DEBUG_INFO("Failed to init APMG\n"); goto out_iounmap; } + /***************** + * 4. Read EEPROM + *****************/ /* Read the EEPROM */ err = iwl_eeprom_init(priv); if (err) { -- cgit v1.2.3-70-g09d2 From b661c8190e91c0baeebf813fec7ff8e99e155a54 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 23 Apr 2008 17:14:54 -0700 Subject: iwlwifi: add iwl_hw_detect function to iwl core This patch add iwl_hw_detect function to iwl core Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 10 +--------- drivers/net/wireless/iwlwifi/iwl-4965.h | 3 +++ drivers/net/wireless/iwlwifi/iwl-core.c | 9 +++++++++ drivers/net/wireless/iwlwifi/iwl-core.h | 1 + drivers/net/wireless/iwlwifi/iwl-csr.h | 5 +++++ drivers/net/wireless/iwlwifi/iwl4965-base.c | 4 +++- 6 files changed, 22 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index b8c72159b59..d1ddbf34b7f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -739,7 +739,6 @@ int iwl4965_hw_nic_init(struct iwl_priv *priv) { unsigned long flags; struct iwl4965_rx_queue *rxq = &priv->rxq; - u8 rev_id; u8 val_link; u32 val; int ret; @@ -751,18 +750,11 @@ int iwl4965_hw_nic_init(struct iwl_priv *priv) iwl_write32(priv, CSR_INT_COALESCING, 512 / 32); spin_unlock_irqrestore(&priv->lock, flags); - /* Determine HW type */ - ret = pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &rev_id); - if (ret) - return ret; - - IWL_DEBUG_INFO("HW Revision ID = 0x%X\n", rev_id); - ret = priv->cfg->ops->lib->apm_ops.set_pwr_src(priv, IWL_PWR_SRC_VMAIN); spin_lock_irqsave(&priv->lock, flags); - if ((rev_id & 0x80) == 0x80 && (rev_id & 0x7f) < 8) { + if ((priv->rev_id & 0x80) == 0x80 && (priv->rev_id & 0x7f) < 8) { pci_read_config_dword(priv->pci_dev, PCI_REG_WUM8, &val); /* Enable No Snoop field */ pci_write_config_dword(priv->pci_dev, PCI_REG_WUM8, diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h index 6df51cca228..1ab4e2ecf79 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965.h @@ -1003,6 +1003,9 @@ struct iwl_priv { /* pci hardware address support */ void __iomem *hw_base; + u32 hw_rev; + u32 hw_wa_rev; + u8 rev_id; /* uCode images, save to reload in case of failure */ struct fw_desc ucode_code; /* runtime inst */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index c336b1991f1..68de1a4700a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -36,6 +36,7 @@ struct iwl_priv; /* FIXME: remove */ #include "iwl-eeprom.h" #include "iwl-4965.h" /* FIXME: remove */ #include "iwl-core.h" +#include "iwl-io.h" #include "iwl-rfkill.h" #include "iwl-power.h" @@ -73,6 +74,14 @@ out: } EXPORT_SYMBOL(iwl_alloc_all); +void iwl_hw_detect(struct iwl_priv *priv) +{ + priv->hw_rev = _iwl_read32(priv, CSR_HW_REV); + priv->hw_wa_rev = _iwl_read32(priv, CSR_HW_REV_WA_REG); + pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &priv->rev_id); +} +EXPORT_SYMBOL(iwl_hw_detect); + /** * iwlcore_clear_stations_table - Clear the driver's station table * diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index edda2ff92f7..eff076e3521 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -159,6 +159,7 @@ struct iwl_cfg { struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg, struct ieee80211_ops *hw_ops); +void iwl_hw_detect(struct iwl_priv *priv); void iwlcore_clear_stations_table(struct iwl_priv *priv); void iwlcore_reset_qos(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index 82c7445d292..df9949ad3f6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -194,6 +194,11 @@ #define CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW (0x08000000) +/* HW REV */ +#define CSR_HW_REV_TYPE_MSK (0x00000F0) +#define CSR_HW_REV_TYPE_3945 (0x00000D0) +#define CSR_HW_REV_TYPE_4965 (0x0000000) + /* EEPROM REG */ #define CSR_EEPROM_REG_READ_VALID_MSK (0x00000001) #define CSR_EEPROM_REG_BIT_CMD (0x00000002) diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index c837503c1e0..368fc9a9c2b 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -7459,8 +7459,10 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e (unsigned long long) pci_resource_len(pdev, 0)); IWL_DEBUG_INFO("pci_resource_base = %p\n", priv->hw_base); + iwl_hw_detect(priv); printk(KERN_INFO DRV_NAME - ": Detected Intel Wireless WiFi Link %s\n", priv->cfg->name); + ": Detected Intel Wireless WiFi Link %s REV=0x%X\n", + priv->cfg->name, priv->hw_rev); /* amp init */ err = priv->cfg->ops->lib->apm_ops.init(priv); -- cgit v1.2.3-70-g09d2 From 8614f360bdc7db8d35609a9c771601f1d45539e5 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 23 Apr 2008 17:14:55 -0700 Subject: iwlwifi: check eeprom version in pci probe time This patch move eeprom version checking into pci probe stage Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 32 +++++++++++++++++++++++------ drivers/net/wireless/iwlwifi/iwl-eeprom.c | 11 +++++----- drivers/net/wireless/iwlwifi/iwl-eeprom.h | 3 +++ drivers/net/wireless/iwlwifi/iwl4965-base.c | 4 ++++ 4 files changed, 38 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index d1ddbf34b7f..a41a83a5f81 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -494,6 +494,31 @@ int iwl4965_hw_rxq_stop(struct iwl_priv *priv) return 0; } +/* + * EEPROM handlers + */ + +static int iwl4965_eeprom_check_version(struct iwl_priv *priv) +{ + u16 eeprom_ver; + u16 calib_ver; + + eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); + + calib_ver = iwl_eeprom_query16(priv, EEPROM_4965_CALIB_VERSION_OFFSET); + + if (eeprom_ver < EEPROM_4965_EEPROM_VERSION || + calib_ver < EEPROM_4965_TX_POWER_VERSION) + goto err; + + return 0; +err: + IWL_ERROR("Unsuported EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n", + eeprom_ver, EEPROM_4965_EEPROM_VERSION, + calib_ver, EEPROM_4965_TX_POWER_VERSION); + return -EINVAL; + +} int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src) { int ret; @@ -763,12 +788,6 @@ int iwl4965_hw_nic_init(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); - if (iwl_eeprom_query16(priv, EEPROM_4965_CALIB_VERSION_OFFSET) < - EEPROM_4965_TX_POWER_VERSION) { - IWL_ERROR("Older EEPROM detected! Aborting.\n"); - return -EINVAL; - } - pci_read_config_byte(priv->pci_dev, PCI_LINK_CTRL, &val_link); /* disable L1 entry -- workaround for pre-B1 */ @@ -4354,6 +4373,7 @@ static struct iwl_lib_ops iwl4965_lib = { .verify_signature = iwlcore_eeprom_verify_signature, .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, .release_semaphore = iwlcore_eeprom_release_semaphore, + .check_version = iwl4965_eeprom_check_version, .query_addr = iwlcore_eeprom_query_addr, }, .radio_kill_sw = iwl4965_radio_kill_sw, diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index efd48ca27a8..8bec0e32f1f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -279,6 +279,11 @@ void iwl_eeprom_free(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_eeprom_free); +int iwl_eeprom_check_version(struct iwl_priv *priv) +{ + return priv->cfg->ops->lib->eeprom_ops.check_version(priv); +} +EXPORT_SYMBOL(iwl_eeprom_check_version); const u8 *iwl_eeprom_query_addr(const struct iwl_priv *priv, size_t offset) { @@ -423,12 +428,6 @@ int iwl_init_channel_map(struct iwl_priv *priv) return 0; } - if (iwl_eeprom_query16(priv, EEPROM_VERSION) < 0x2f) { - IWL_WARNING("Unsupported EEPROM version: 0x%04X\n", - iwl_eeprom_query16(priv, EEPROM_VERSION)); - return -EINVAL; - } - IWL_DEBUG_INFO("Initializing regulatory info from EEPROM\n"); priv->channel_count = diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index d5768146d02..57fb89d5621 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -134,6 +134,7 @@ struct iwl_eeprom_channel { /* 4965 Specific */ /* 4965 driver does not work with txpower calibration version < 5 */ #define EEPROM_4965_TX_POWER_VERSION (5) +#define EEPROM_4965_EEPROM_VERSION (0x2f) #define EEPROM_4965_CALIB_VERSION_OFFSET (2*0xB6) /* 2 bytes */ #define EEPROM_4965_CALIB_TXPOWER_OFFSET (2*0xE8) /* 48 bytes */ #define EEPROM_4965_BOARD_REVISION (2*0x4F) /* 2 bytes */ @@ -322,6 +323,7 @@ struct iwl_eeprom_ops { int (*verify_signature) (struct iwl_priv *priv); int (*acquire_semaphore) (struct iwl_priv *priv); void (*release_semaphore) (struct iwl_priv *priv); + int (*check_version) (struct iwl_priv *priv); const u8* (*query_addr) (const struct iwl_priv *priv, size_t offset); }; @@ -329,6 +331,7 @@ struct iwl_eeprom_ops { void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac); int iwl_eeprom_init(struct iwl_priv *priv); void iwl_eeprom_free(struct iwl_priv *priv); +int iwl_eeprom_check_version(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); diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 368fc9a9c2b..c532584b11e 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -7479,6 +7479,10 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e IWL_ERROR("Unable to init EEPROM\n"); goto out_iounmap; } + err = iwl_eeprom_check_version(priv); + if (err) + goto out_iounmap; + /* MAC Address location in EEPROM same for 3945/4965 */ iwl_eeprom_get_mac(priv, priv->mac_addr); IWL_DEBUG_INFO("MAC address: %s\n", print_mac(mac, priv->mac_addr)); -- cgit v1.2.3-70-g09d2 From 399f490067992715044cbf2be1923e2f613b2e18 Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Wed, 23 Apr 2008 17:14:56 -0700 Subject: iwlwifi: handle shared memory This patch generalize the use of shared memory, as size of this memory is now allocated and freed by handlers, and also changes the location of those actions for better resource management Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 36 +++++++++++++++++++---------- drivers/net/wireless/iwlwifi/iwl-core.h | 4 +++- drivers/net/wireless/iwlwifi/iwl4965-base.c | 23 ++++++++---------- 3 files changed, 36 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index a41a83a5f81..e80f6022cf4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -276,18 +276,6 @@ static int iwl4965_init_drv(struct iwl_priv *priv) spin_lock_init(&priv->hcmd_lock); spin_lock_init(&priv->lq_mngr.lock); - priv->shared_virt = pci_alloc_consistent(priv->pci_dev, - sizeof(struct iwl4965_shared), - &priv->shared_phys); - - if (!priv->shared_virt) { - ret = -ENOMEM; - goto err; - } - - memset(priv->shared_virt, 0, sizeof(struct iwl4965_shared)); - - for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) INIT_LIST_HEAD(&priv->ibss_mac_hash[i]); @@ -2492,6 +2480,28 @@ static void iwl4965_hw_card_show_info(struct iwl_priv *priv) &priv->eeprom[EEPROM_4965_BOARD_PBA]); } +static int iwl4965_alloc_shared_mem(struct iwl_priv *priv) +{ + priv->shared_virt = pci_alloc_consistent(priv->pci_dev, + sizeof(struct iwl4965_shared), + &priv->shared_phys); + if (!priv->shared_virt) + return -ENOMEM; + + memset(priv->shared_virt, 0, sizeof(struct iwl4965_shared)); + + return 0; +} + +static void iwl4965_free_shared_mem(struct iwl_priv *priv) +{ + if (priv->shared_virt) + pci_free_consistent(priv->pci_dev, + sizeof(struct iwl4965_shared), + priv->shared_virt, + priv->shared_phys); +} + #define IWL_TX_CRC_SIZE 4 #define IWL_TX_DELIMITER_SIZE 4 @@ -4351,6 +4361,8 @@ static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = { static struct iwl_lib_ops iwl4965_lib = { .init_drv = iwl4965_init_drv, .set_hw_params = iwl4965_hw_set_hw_params, + .alloc_shared_mem = iwl4965_alloc_shared_mem, + .free_shared_mem = iwl4965_free_shared_mem, .txq_update_byte_cnt_tbl = iwl4965_txq_update_byte_cnt_tbl, .hw_nic_init = iwl4965_hw_nic_init, .is_valid_rtc_data_addr = iwl4965_hw_valid_rtc_data_addr, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index eff076e3521..e94aea3cba7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -101,7 +101,9 @@ struct iwl_lib_ops { int (*init_drv)(struct iwl_priv *priv); /* set hw dependant perameters */ int (*set_hw_params)(struct iwl_priv *priv); - + /* ucode shared memory */ + int (*alloc_shared_mem)(struct iwl_priv *priv); + void (*free_shared_mem)(struct iwl_priv *priv); void (*txq_update_byte_cnt_tbl)(struct iwl_priv *priv, struct iwl4965_tx_queue *txq, u16 byte_cnt); diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index c532584b11e..783f722f3c3 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -1128,15 +1128,6 @@ static int iwl4965_send_beacon_cmd(struct iwl_priv *priv) * ******************************************************************************/ -static void iwl4965_unset_hw_params(struct iwl_priv *priv) -{ - if (priv->shared_virt) - pci_free_consistent(priv->pci_dev, - sizeof(struct iwl4965_shared), - priv->shared_virt, - priv->shared_phys); -} - /** * iwl4965_supported_rate_to_ie - fill in the supported rate in IE field * @@ -5298,6 +5289,7 @@ static void __iwl4965_down(struct iwl_priv *priv) iwl4965_hw_nic_stop_master(priv); iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); iwl4965_hw_nic_reset(priv); + priv->cfg->ops->lib->free_shared_mem(priv); exit: memset(&priv->card_alive, 0, sizeof(struct iwl4965_alive_resp)); @@ -5359,6 +5351,12 @@ static int __iwl4965_up(struct iwl_priv *priv) iwl_rfkill_set_hw_state(priv); iwl_write32(priv, CSR_INT, 0xFFFFFFFF); + ret = priv->cfg->ops->lib->alloc_shared_mem(priv); + if (ret) { + IWL_ERROR("Unable to allocate shared memory\n"); + return ret; + } + ret = priv->cfg->ops->lib->hw_nic_init(priv); if (ret) { IWL_ERROR("Unable to init nic\n"); @@ -7503,7 +7501,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e err = iwl_setup(priv); if (err) - goto out_unset_hw_params; + goto out_free_eeprom; /* At this point both hw and priv are initialized. */ /********************************** @@ -7529,7 +7527,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e err = sysfs_create_group(&pdev->dev.kobj, &iwl4965_attribute_group); if (err) { IWL_ERROR("failed to create sysfs device attributes\n"); - goto out_unset_hw_params; + goto out_free_eeprom; } err = iwl_dbgfs_register(priv, DRV_NAME); @@ -7553,8 +7551,6 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e out_remove_sysfs: sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group); - out_unset_hw_params: - iwl4965_unset_hw_params(priv); out_free_eeprom: iwl_eeprom_free(priv); out_iounmap: @@ -7618,7 +7614,6 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) iwl4965_rx_queue_free(priv, &priv->rxq); iwl4965_hw_txq_ctx_free(priv); - iwl4965_unset_hw_params(priv); iwlcore_clear_stations_table(priv); iwl_eeprom_free(priv); -- cgit v1.2.3-70-g09d2 From 39e885049d9d5e6a65bb2543f82e136c02c253b5 Mon Sep 17 00:00:00 2001 From: Guy Cohen Date: Wed, 23 Apr 2008 17:14:57 -0700 Subject: iwlwifi: TLC modifications 1. Merge TLC fixes from AP support code 2. Remove struct iwl4965_rate 3. Misc code restructuring Signed-off-by: Guy Cohen Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 434 +++++++++++++--------------- drivers/net/wireless/iwlwifi/iwl4965-base.c | 31 +- 2 files changed, 221 insertions(+), 244 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index 31a0451f7a4..7c55aa9a2ba 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -64,10 +64,6 @@ static u8 rs_ht_to_legacy[] = { IWL_RATE_48M_INDEX, IWL_RATE_54M_INDEX }; -struct iwl4965_rate { - u32 rate_n_flags; -} __attribute__ ((packed)); - /** * struct iwl4965_rate_scale_data -- tx success history for one rate */ @@ -94,7 +90,7 @@ struct iwl4965_scale_tbl_info { u8 is_dup; /* 1 = duplicated data streams */ u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */ s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */ - struct iwl4965_rate current_rate; /* rate_n_flags, uCode API format */ + u32 current_rate; /* rate_n_flags, uCode API format */ struct iwl4965_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */ }; @@ -144,7 +140,7 @@ struct iwl4965_lq_sta { /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */ u32 supp_rates; - u16 active_rate; + u16 active_legacy_rate; u16 active_siso_rate; u16 active_mimo2_rate; u16 active_mimo3_rate; @@ -162,7 +158,7 @@ struct iwl4965_lq_sta { #ifdef CONFIG_IWL4965_HT struct dentry *rs_sta_dbgfs_tx_agg_tid_en_file; #endif - struct iwl4965_rate dbg_fixed; + u32 dbg_fixed_rate; struct iwl_priv *drv; #endif }; @@ -173,16 +169,16 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, struct sta_info *sta); static void rs_fill_link_cmd(const struct iwl_priv *priv, struct iwl4965_lq_sta *lq_sta, - struct iwl4965_rate *tx_mcs, + u32 rate_n_flags, struct iwl_link_quality_cmd *tbl); #ifdef CONFIG_MAC80211_DEBUGFS static void rs_dbgfs_set_mcs(struct iwl4965_lq_sta *lq_sta, - struct iwl4965_rate *mcs, int index); + u32 *rate_n_flags, int index); #else static void rs_dbgfs_set_mcs(struct iwl4965_lq_sta *lq_sta, - struct iwl4965_rate *mcs, int index) + u32 *rate_n_flags, int index) {} #endif @@ -232,7 +228,7 @@ static s32 expected_tpt_mimo40MHzSGI[IWL_RATE_COUNT] = { 0, 0, 0, 0, 131, 131, 191, 222, 242, 270, 284, 289, 293 }; -static inline u8 iwl4965_rate_get_rate(u32 rate_n_flags) +static inline u8 rs_extract_rate(u32 rate_n_flags) { return (u8)(rate_n_flags & 0xFF); } @@ -376,11 +372,11 @@ static void rs_tl_turn_on_agg(struct iwl_priv *priv, u8 tid, #endif /* CONFIG_IWLWIFI_HT */ -static inline int get_num_of_ant_from_mcs(u32 mcs) +static inline int get_num_of_ant_from_rate(u32 rate_n_flags) { - return (!!(mcs & RATE_MCS_ANT_A_MSK) + - !!(mcs & RATE_MCS_ANT_B_MSK) + - !!(mcs & RATE_MCS_ANT_C_MSK)); + return (!!(rate_n_flags & RATE_MCS_ANT_A_MSK) + + !!(rate_n_flags & RATE_MCS_ANT_B_MSK) + + !!(rate_n_flags & RATE_MCS_ANT_C_MSK)); } /** @@ -395,8 +391,7 @@ static int rs_collect_tx_data(struct iwl4965_rate_scale_data *windows, int successes) { struct iwl4965_rate_scale_data *window = NULL; - u64 mask; - u8 win_size = IWL_RATE_MAX_WINDOW; + static const u64 mask = (((u64)1) << (IWL_RATE_MAX_WINDOW - 1)); s32 fail_count; if (scale_index < 0 || scale_index >= IWL_RATE_COUNT) @@ -414,14 +409,14 @@ static int rs_collect_tx_data(struct iwl4965_rate_scale_data *windows, * we keep these bitmaps!). */ while (retries > 0) { - if (window->counter >= win_size) { - window->counter = win_size - 1; - mask = 1; - mask = (mask << (win_size - 1)); + if (window->counter >= IWL_RATE_MAX_WINDOW) { + + /* remove earliest */ + window->counter = IWL_RATE_MAX_WINDOW - 1; + if (window->data & mask) { window->data &= ~mask; - window->success_counter = - window->success_counter - 1; + window->success_counter--; } } @@ -431,10 +426,9 @@ static int rs_collect_tx_data(struct iwl4965_rate_scale_data *windows, /* Shift bitmap by one frame (throw away oldest history), * OR in "1", and increment "success" if this * frame was successful. */ - mask = window->data; - window->data = (mask << 1); + window->data <<= 1;; if (successes > 0) { - window->success_counter = window->success_counter + 1; + window->success_counter++; window->data |= 0x1; successes--; } @@ -467,70 +461,72 @@ static int rs_collect_tx_data(struct iwl4965_rate_scale_data *windows, /* * Fill uCode API rate_n_flags field, based on "search" or "active" table. */ -static void rs_mcs_from_tbl(struct iwl4965_rate *mcs_rate, - struct iwl4965_scale_tbl_info *tbl, - int index, u8 use_green) +/* FIXME:RS:remove this function and put the flags statically in the table */ +static u32 rate_n_flags_from_tbl(struct iwl4965_scale_tbl_info *tbl, + int index, u8 use_green) { + u32 rate_n_flags = 0; + if (is_legacy(tbl->lq_type)) { - mcs_rate->rate_n_flags = iwl4965_rates[index].plcp; + rate_n_flags = iwl4965_rates[index].plcp; if (index >= IWL_FIRST_CCK_RATE && index <= IWL_LAST_CCK_RATE) - mcs_rate->rate_n_flags |= RATE_MCS_CCK_MSK; + rate_n_flags |= RATE_MCS_CCK_MSK; } else if (is_Ht(tbl->lq_type)) { if (index > IWL_LAST_OFDM_RATE) { IWL_ERROR("invalid HT rate index %d\n", index); index = IWL_LAST_OFDM_RATE; } - mcs_rate->rate_n_flags = RATE_MCS_HT_MSK; + rate_n_flags = RATE_MCS_HT_MSK; if (is_siso(tbl->lq_type)) - mcs_rate->rate_n_flags |= - iwl4965_rates[index].plcp_siso; + rate_n_flags |= iwl4965_rates[index].plcp_siso; else if (is_mimo2(tbl->lq_type)) - mcs_rate->rate_n_flags |= - iwl4965_rates[index].plcp_mimo2; + rate_n_flags |= iwl4965_rates[index].plcp_mimo2; else - mcs_rate->rate_n_flags |= - iwl4965_rates[index].plcp_mimo3; + rate_n_flags |= iwl4965_rates[index].plcp_mimo3; } else { IWL_ERROR("Invalid tbl->lq_type %d\n", tbl->lq_type); } - mcs_rate->rate_n_flags |= ((tbl->ant_type << RATE_MCS_ANT_POS) & + rate_n_flags |= ((tbl->ant_type << RATE_MCS_ANT_POS) & RATE_MCS_ANT_ABC_MSK); - if (is_legacy(tbl->lq_type)) - return; - - if (tbl->is_fat) { - if (tbl->is_dup) - mcs_rate->rate_n_flags |= RATE_MCS_DUP_MSK; - else - mcs_rate->rate_n_flags |= RATE_MCS_FAT_MSK; - } - if (tbl->is_SGI) - mcs_rate->rate_n_flags |= RATE_MCS_SGI_MSK; - - if (use_green) { - mcs_rate->rate_n_flags |= RATE_MCS_GF_MSK; - if (is_siso(tbl->lq_type)) - mcs_rate->rate_n_flags &= ~RATE_MCS_SGI_MSK; + if (is_Ht(tbl->lq_type)) { + if (tbl->is_fat) { + if (tbl->is_dup) + rate_n_flags |= RATE_MCS_DUP_MSK; + else + rate_n_flags |= RATE_MCS_FAT_MSK; + } + if (tbl->is_SGI) + rate_n_flags |= RATE_MCS_SGI_MSK; + + if (use_green) { + rate_n_flags |= RATE_MCS_GF_MSK; + if (is_siso(tbl->lq_type) && tbl->is_SGI) { + rate_n_flags &= ~RATE_MCS_SGI_MSK; + IWL_ERROR("GF was set with SGI:SISO\n"); + } + } } + return rate_n_flags; } /* * Interpret uCode API's rate_n_flags format, * fill "search" or "active" tx mode table. */ -static int rs_get_tbl_info_from_mcs(const struct iwl4965_rate *mcs_rate, +static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags, enum ieee80211_band band, struct iwl4965_scale_tbl_info *tbl, int *rate_idx) { - u32 ant_msk = (mcs_rate->rate_n_flags & RATE_MCS_ANT_ABC_MSK); - u8 num_of_ant = get_num_of_ant_from_mcs(ant_msk); + u32 ant_msk = (rate_n_flags & RATE_MCS_ANT_ABC_MSK); + u8 num_of_ant = get_num_of_ant_from_rate(rate_n_flags); + u8 mcs; - *rate_idx = iwl4965_hwrate_to_plcp_idx(mcs_rate->rate_n_flags); + *rate_idx = iwl4965_hwrate_to_plcp_idx(rate_n_flags); if (*rate_idx == IWL_RATE_INVALID) { *rate_idx = -1; @@ -543,7 +539,7 @@ static int rs_get_tbl_info_from_mcs(const struct iwl4965_rate *mcs_rate, tbl->lq_type = LQ_NONE; /* legacy rate format */ - if (!(mcs_rate->rate_n_flags & RATE_MCS_HT_MSK)) { + if (!(rate_n_flags & RATE_MCS_HT_MSK)) { if (num_of_ant == 1) { if (band == IEEE80211_BAND_5GHZ) tbl->lq_type = LQ_A; @@ -552,25 +548,24 @@ static int rs_get_tbl_info_from_mcs(const struct iwl4965_rate *mcs_rate, } /* HT rate format */ } else { - if (mcs_rate->rate_n_flags & RATE_MCS_SGI_MSK) + if (rate_n_flags & RATE_MCS_SGI_MSK) tbl->is_SGI = 1; - if ((mcs_rate->rate_n_flags & RATE_MCS_FAT_MSK) || - (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK)) + if ((rate_n_flags & RATE_MCS_FAT_MSK) || + (rate_n_flags & RATE_MCS_DUP_MSK)) tbl->is_fat = 1; - if (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK) + if (rate_n_flags & RATE_MCS_DUP_MSK) tbl->is_dup = 1; - /* SISO */ - if (iwl4965_rate_get_rate(mcs_rate->rate_n_flags) - <= IWL_RATE_SISO_60M_PLCP) { + mcs = rs_extract_rate(rate_n_flags); + /* SISO */ + if (mcs <= IWL_RATE_SISO_60M_PLCP) { if (num_of_ant == 1) tbl->lq_type = LQ_SISO; /*else NONE*/ /* MIMO2 */ - } else if (iwl4965_rate_get_rate(mcs_rate->rate_n_flags) - <= IWL_RATE_MIMO2_60M_PLCP) { + } else if (mcs <= IWL_RATE_MIMO2_60M_PLCP) { if (num_of_ant == 2) tbl->lq_type = LQ_MIMO2; /* MIMO3 */ @@ -582,13 +577,14 @@ static int rs_get_tbl_info_from_mcs(const struct iwl4965_rate *mcs_rate, return 0; } /* FIXME:RS: need to toggle also ANT_C, and also AB,AC,BC */ -static inline void rs_toggle_antenna(struct iwl4965_rate *new_rate, +static inline void rs_toggle_antenna(u32 *rate_n_flags, struct iwl4965_scale_tbl_info *tbl) { tbl->ant_type ^= ANT_AB; - new_rate->rate_n_flags ^= (RATE_MCS_ANT_A_MSK|RATE_MCS_ANT_B_MSK); + *rate_n_flags ^= (RATE_MCS_ANT_A_MSK|RATE_MCS_ANT_B_MSK); } +/* FIXME:RS: in 4965 we don't use greenfield at all */ static inline u8 rs_use_green(struct iwl_priv *priv, struct ieee80211_conf *conf) { @@ -596,8 +592,9 @@ static inline u8 rs_use_green(struct iwl_priv *priv, return ((conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) && priv->current_ht_config.is_green_field && !priv->current_ht_config.non_GF_STA_present); -#endif /* CONFIG_IWL4965_HT */ +#else return 0; +#endif /* CONFIG_IWL4965_HT */ } /** @@ -613,7 +610,7 @@ static void rs_get_supported_rates(struct iwl4965_lq_sta *lq_sta, u16 *data_rate) { if (is_legacy(rate_type)) - *data_rate = lq_sta->active_rate; + *data_rate = lq_sta->active_legacy_rate; else { if (is_siso(rate_type)) *data_rate = lq_sta->active_siso_rate; @@ -684,9 +681,9 @@ static u16 rs_get_adjacent_rate(u8 index, u16 rate_mask, int rate_type) return (high << 8) | low; } -static void rs_get_lower_rate(struct iwl4965_lq_sta *lq_sta, +static u32 rs_get_lower_rate(struct iwl4965_lq_sta *lq_sta, struct iwl4965_scale_tbl_info *tbl, u8 scale_index, - u8 ht_possible, struct iwl4965_rate *mcs_rate) + u8 ht_possible) { s32 low; u16 rate_mask; @@ -726,17 +723,18 @@ static void rs_get_lower_rate(struct iwl4965_lq_sta *lq_sta, /* If we switched from HT to legacy, check current rate */ if (switch_to_legacy && (rate_mask & (1 << scale_index))) { - rs_mcs_from_tbl(mcs_rate, tbl, scale_index, is_green); - return; + low = scale_index; + goto out; } high_low = rs_get_adjacent_rate(scale_index, rate_mask, tbl->lq_type); low = high_low & 0xff; - if (low != IWL_RATE_INVALID) - rs_mcs_from_tbl(mcs_rate, tbl, low, is_green); - else - rs_mcs_from_tbl(mcs_rate, tbl, scale_index, is_green); + if (low == IWL_RATE_INVALID) + low = scale_index; + +out: + return rate_n_flags_from_tbl(tbl, low, is_green); } /* @@ -758,7 +756,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, struct ieee80211_hw *hw = local_to_hw(local); struct iwl4965_rate_scale_data *window = NULL; struct iwl4965_rate_scale_data *search_win = NULL; - struct iwl4965_rate tx_mcs; + u32 tx_rate; struct iwl4965_scale_tbl_info tbl_type; struct iwl4965_scale_tbl_info *curr_tbl, *search_tbl; u8 active_index = 0; @@ -817,8 +815,8 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, * to check "search" mode, or a prior "search" mode after we've moved * to a new "search" mode (which might become the new "active" mode). */ - tx_mcs.rate_n_flags = le32_to_cpu(table->rs_table[0].rate_n_flags); - rs_get_tbl_info_from_mcs(&tx_mcs, priv->band, &tbl_type, &rs_index); + tx_rate = le32_to_cpu(table->rs_table[0].rate_n_flags); + rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type, &rs_index); if (priv->band == IEEE80211_BAND_5GHZ) rs_index -= IWL_FIRST_OFDM_RATE; @@ -830,14 +828,13 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, (tbl_type.is_dup ^ !!(tx_resp->control.flags & IEEE80211_TXCTL_DUP_DATA)) || (tbl_type.ant_type ^ tx_resp->control.antenna_sel_tx) || - (!!(tx_mcs.rate_n_flags & RATE_MCS_HT_MSK) ^ + (!!(tx_rate & RATE_MCS_HT_MSK) ^ !!(tx_resp->control.flags & IEEE80211_TXCTL_OFDM_HT)) || - (!!(tx_mcs.rate_n_flags & RATE_MCS_GF_MSK) ^ + (!!(tx_rate & RATE_MCS_GF_MSK) ^ !!(tx_resp->control.flags & IEEE80211_TXCTL_GREEN_FIELD)) || (hw->wiphy->bands[priv->band]->bitrates[rs_index].bitrate != tx_resp->control.tx_rate->bitrate)) { - IWL_DEBUG_RATE("initial rate does not match 0x%x\n", - tx_mcs.rate_n_flags); + IWL_DEBUG_RATE("initial rate does not match 0x%x\n", tx_rate); goto out; } @@ -845,9 +842,8 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, while (retries) { /* Look up the rate and other info used for each tx attempt. * Each tx attempt steps one entry deeper in the rate table. */ - tx_mcs.rate_n_flags = - le32_to_cpu(table->rs_table[index].rate_n_flags); - rs_get_tbl_info_from_mcs(&tx_mcs, priv->band, + tx_rate = le32_to_cpu(table->rs_table[index].rate_n_flags); + rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type, &rs_index); /* If type matches "search" table, @@ -887,8 +883,8 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, * if Tx was successful first try, use original rate, * else look up the rate that was, finally, successful. */ - tx_mcs.rate_n_flags = le32_to_cpu(table->rs_table[index].rate_n_flags); - rs_get_tbl_info_from_mcs(&tx_mcs, priv->band, &tbl_type, &rs_index); + tx_rate = le32_to_cpu(table->rs_table[index].rate_n_flags); + rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type, &rs_index); /* Update frame history window with "success" if Tx got ACKed ... */ if (tx_resp->flags & IEEE80211_TX_STATUS_ACK) @@ -1158,11 +1154,6 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, !sta->ht_info.ht_supported) return -1; - IWL_DEBUG_HT("LQ: try to switch to MIMO\n"); - tbl->lq_type = LQ_MIMO2; - rs_get_supported_rates(lq_sta, NULL, tbl->lq_type, - &rate_mask); - if (priv->current_ht_config.tx_mimo_ps_mode == IWL_MIMO_PS_STATIC) return -1; @@ -1170,14 +1161,20 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, if (!rs_is_both_ant_supp(priv->hw_params.valid_tx_ant)) return -1; + IWL_DEBUG_HT("LQ: try to switch to MIMO2\n"); + + tbl->lq_type = LQ_MIMO2; tbl->is_dup = lq_sta->is_dup; tbl->action = 0; + rate_mask = lq_sta->active_mimo2_rate; + if (priv->current_ht_config.supported_chan_width - == IWL_CHANNEL_WIDTH_40MHZ) + == IWL_CHANNEL_WIDTH_40MHZ) tbl->is_fat = 1; else tbl->is_fat = 0; + /* FIXME: - don't toggle SGI here if (tbl->is_fat) { if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY) tbl->is_SGI = 1; @@ -1187,18 +1184,23 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, tbl->is_SGI = 1; else tbl->is_SGI = 0; + */ rs_get_expected_tpt_table(lq_sta, tbl); rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index, index); - IWL_DEBUG_HT("LQ: MIMO best rate %d mask %X\n", rate, rate_mask); - if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) + IWL_DEBUG_HT("LQ: MIMO2 best rate %d mask %X\n", rate, rate_mask); + + if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) { + IWL_DEBUG_HT("Can't switch with index %d rate mask %x\n", + rate, rate_mask); return -1; - rs_mcs_from_tbl(&tbl->current_rate, tbl, rate, is_green); + } + tbl->current_rate = rate_n_flags_from_tbl(tbl, rate, is_green); IWL_DEBUG_HT("LQ: Switch to new mcs %X index is green %X\n", - tbl->current_rate.rate_n_flags, is_green); + tbl->current_rate, is_green); return 0; } #else @@ -1226,16 +1228,16 @@ static int rs_switch_to_siso(struct iwl_priv *priv, u8 is_green = lq_sta->is_green; s32 rate; - IWL_DEBUG_HT("LQ: try to switch to SISO\n"); if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) || !sta->ht_info.ht_supported) return -1; + IWL_DEBUG_HT("LQ: try to switch to SISO\n"); + tbl->is_dup = lq_sta->is_dup; tbl->lq_type = LQ_SISO; tbl->action = 0; - rs_get_supported_rates(lq_sta, NULL, tbl->lq_type, - &rate_mask); + rate_mask = lq_sta->active_siso_rate; if (priv->current_ht_config.supported_chan_width == IWL_CHANNEL_WIDTH_40MHZ) @@ -1243,6 +1245,7 @@ static int rs_switch_to_siso(struct iwl_priv *priv, else tbl->is_fat = 0; + /* FIXME: - don't toggle SGI here if (tbl->is_fat) { if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY) tbl->is_SGI = 1; @@ -1252,9 +1255,10 @@ static int rs_switch_to_siso(struct iwl_priv *priv, tbl->is_SGI = 1; else tbl->is_SGI = 0; + */ if (is_green) - tbl->is_SGI = 0; + tbl->is_SGI = 0; /*11n spec: no SGI in SISO+Greenfield*/ rs_get_expected_tpt_table(lq_sta, tbl); rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index, index); @@ -1265,9 +1269,9 @@ static int rs_switch_to_siso(struct iwl_priv *priv, rate, rate_mask); return -1; } - rs_mcs_from_tbl(&tbl->current_rate, tbl, rate, is_green); + tbl->current_rate = rate_n_flags_from_tbl(tbl, rate, is_green); IWL_DEBUG_HT("LQ: Switch to new mcs %X index is green %X\n", - tbl->current_rate.rate_n_flags, is_green); + tbl->current_rate, is_green); return 0; #else return -1; @@ -1298,12 +1302,13 @@ static int rs_move_legacy_other(struct iwl_priv *priv, for (; ;) { switch (tbl->action) { case IWL_LEGACY_SWITCH_ANTENNA: - IWL_DEBUG_HT("LQ Legacy switch Antenna\n"); + IWL_DEBUG_HT("LQ Legacy toggle Antenna\n"); search_tbl->lq_type = LQ_NONE; lq_sta->action_counter++; /* Don't change antenna if success has been great */ + /*FIXME:RS:not sure this is really needed*/ if (window->success_ratio >= IWL_RS_GOOD_RATIO) break; @@ -1315,7 +1320,7 @@ static int rs_move_legacy_other(struct iwl_priv *priv, /* Set up search table to try other antenna */ memcpy(search_tbl, tbl, sz); - rs_toggle_antenna(&(search_tbl->current_rate), + rs_toggle_antenna(&search_tbl->current_rate, search_tbl); rs_get_expected_tpt_table(lq_sta, search_tbl); lq_sta->search_better_tbl = 1; @@ -1326,9 +1331,7 @@ static int rs_move_legacy_other(struct iwl_priv *priv, /* Set up search table to try SISO */ memcpy(search_tbl, tbl, sz); - search_tbl->lq_type = LQ_SISO; search_tbl->is_SGI = 0; - search_tbl->is_fat = 0; ret = rs_switch_to_siso(priv, lq_sta, conf, sta, search_tbl, index); if (!ret) { @@ -1339,13 +1342,11 @@ static int rs_move_legacy_other(struct iwl_priv *priv, break; case IWL_LEGACY_SWITCH_MIMO2: - IWL_DEBUG_HT("LQ: Legacy switch MIMO\n"); + IWL_DEBUG_HT("LQ: Legacy switch to MIMO2\n"); /* Set up search table to try MIMO */ memcpy(search_tbl, tbl, sz); - search_tbl->lq_type = LQ_MIMO2; search_tbl->is_SGI = 0; - search_tbl->is_fat = 0; search_tbl->ant_type = ANT_AB;/*FIXME:RS*/ /*FIXME:RS:need to check ant validity*/ ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta, @@ -1400,8 +1401,8 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, lq_sta->action_counter++; switch (tbl->action) { case IWL_SISO_SWITCH_ANTENNA: - IWL_DEBUG_HT("LQ: SISO SWITCH ANTENNA SISO\n"); - search_tbl->lq_type = LQ_NONE; + IWL_DEBUG_HT("LQ: SISO toggle Antenna\n"); + /*FIXME:RS: is this really needed for SISO?*/ if (window->success_ratio >= IWL_RS_GOOD_RATIO) break; if (!rs_is_other_ant_connected(valid_tx_ant, @@ -1409,19 +1410,16 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, break; memcpy(search_tbl, tbl, sz); - search_tbl->action = IWL_SISO_SWITCH_MIMO2; - rs_toggle_antenna(&(search_tbl->current_rate), + rs_toggle_antenna(&search_tbl->current_rate, search_tbl); lq_sta->search_better_tbl = 1; goto out; case IWL_SISO_SWITCH_MIMO2: - IWL_DEBUG_HT("LQ: SISO SWITCH TO MIMO2 FROM SISO\n"); + IWL_DEBUG_HT("LQ: SISO switch to MIMO\n"); memcpy(search_tbl, tbl, sz); - search_tbl->lq_type = LQ_MIMO2; search_tbl->is_SGI = 0; - search_tbl->is_fat = 0; search_tbl->ant_type = ANT_AB; /*FIXME:RS*/ ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta, search_tbl, index); @@ -1431,29 +1429,25 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, } break; case IWL_SISO_SWITCH_GI: - IWL_DEBUG_HT("LQ: SISO SWITCH TO GI\n"); + IWL_DEBUG_HT("LQ: SISO toggle SGI/NGI\n"); memcpy(search_tbl, tbl, sz); - search_tbl->action = 0; - if (search_tbl->is_SGI) - search_tbl->is_SGI = 0; - else if (!is_green) - search_tbl->is_SGI = 1; - else - break; - lq_sta->search_better_tbl = 1; - if ((tbl->lq_type == LQ_SISO) && - (tbl->is_SGI)) { - s32 tpt = lq_sta->last_tpt / 100; - if (((!tbl->is_fat) && - (tpt >= expected_tpt_siso20MHz[index])) || - ((tbl->is_fat) && - (tpt >= expected_tpt_siso40MHz[index]))) - lq_sta->search_better_tbl = 0; + if (is_green) { + if (!tbl->is_SGI) + break; + else + IWL_ERROR("SGI was set in GF+SISO\n"); } + search_tbl->is_SGI = !tbl->is_SGI; rs_get_expected_tpt_table(lq_sta, search_tbl); - rs_mcs_from_tbl(&search_tbl->current_rate, - search_tbl, index, is_green); + if (tbl->is_SGI) { + s32 tpt = lq_sta->last_tpt / 100; + if (tpt >= search_tbl->expected_tpt[index]) + break; + } + search_tbl->current_rate = rate_n_flags_from_tbl( + search_tbl, index, is_green); + lq_sta->search_better_tbl = 1; goto out; } tbl->action++; @@ -1496,15 +1490,12 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv, switch (tbl->action) { case IWL_MIMO_SWITCH_ANTENNA_A: case IWL_MIMO_SWITCH_ANTENNA_B: - IWL_DEBUG_HT("LQ: MIMO SWITCH TO SISO\n"); - + IWL_DEBUG_HT("LQ: MIMO2 switch to SISO\n"); /* Set up new search table for SISO */ memcpy(search_tbl, tbl, sz); - search_tbl->lq_type = LQ_SISO; - search_tbl->is_SGI = 0; - search_tbl->is_fat = 0; - /*FIXME:RS:need to check ant validity + C*/ + + /*FIXME:RS:need to check ant validity + C*/ if (tbl->action == IWL_MIMO_SWITCH_ANTENNA_A) search_tbl->ant_type = ANT_A; else @@ -1519,35 +1510,26 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv, break; case IWL_MIMO_SWITCH_GI: - IWL_DEBUG_HT("LQ: MIMO SWITCH TO GI\n"); + IWL_DEBUG_HT("LQ: MIMO toggle SGI/NGI\n"); /* Set up new search table for MIMO */ memcpy(search_tbl, tbl, sz); - search_tbl->action = 0; - if (search_tbl->is_SGI) - search_tbl->is_SGI = 0; - else - search_tbl->is_SGI = 1; - lq_sta->search_better_tbl = 1; - + search_tbl->is_SGI = !tbl->is_SGI; + rs_get_expected_tpt_table(lq_sta, search_tbl); /* * If active table already uses the fastest possible * modulation (dual stream with short guard interval), * and it's working well, there's no need to look * for a better type of modulation! */ - if ((tbl->lq_type == LQ_MIMO2) && - (tbl->is_SGI)) { + if (tbl->is_SGI) { s32 tpt = lq_sta->last_tpt / 100; - if (((!tbl->is_fat) && - (tpt >= expected_tpt_mimo20MHz[index])) || - ((tbl->is_fat) && - (tpt >= expected_tpt_mimo40MHz[index]))) - lq_sta->search_better_tbl = 0; + if (tpt >= search_tbl->expected_tpt[index]) + break; } - rs_get_expected_tpt_table(lq_sta, search_tbl); - rs_mcs_from_tbl(&search_tbl->current_rate, - search_tbl, index, is_green); + search_tbl->current_rate = rate_n_flags_from_tbl( + search_tbl, index, is_green); + lq_sta->search_better_tbl = 1; goto out; } @@ -1677,7 +1659,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, struct iwl4965_lq_sta *lq_sta; struct iwl4965_scale_tbl_info *tbl, *tbl1; u16 rate_scale_index_msk = 0; - struct iwl4965_rate mcs_rate; + u32 rate; u8 is_green = 0; u8 active_tbl = 0; u8 done_search = 0; @@ -1802,8 +1784,8 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, /* Set up new rate table in uCode, if needed */ if (update_lq) { - rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green); - rs_fill_link_cmd(priv, lq_sta, &mcs_rate, &lq_sta->lq); + rate = rate_n_flags_from_tbl(tbl, index, is_green); + rs_fill_link_cmd(priv, lq_sta, rate, &lq_sta->lq); iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); } goto out; @@ -1847,7 +1829,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, /* Revert to "active" rate and throughput info */ index = iwl4965_hwrate_to_plcp_idx( - tbl->current_rate.rate_n_flags); + tbl->current_rate); current_tpt = lq_sta->last_tpt; /* Need to set up a new rate table in uCode */ @@ -1967,8 +1949,8 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, lq_update: /* Replace uCode's rate table for the destination station. */ if (update_lq) { - rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green); - rs_fill_link_cmd(priv, lq_sta, &mcs_rate, &lq_sta->lq); + rate = rate_n_flags_from_tbl(tbl, index, is_green); + rs_fill_link_cmd(priv, lq_sta, rate, &lq_sta->lq); iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); } @@ -2003,11 +1985,11 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, /* Use new "search" start rate */ index = iwl4965_hwrate_to_plcp_idx( - tbl->current_rate.rate_n_flags); + tbl->current_rate); IWL_DEBUG_HT("Switch current mcs: %X index: %d\n", - tbl->current_rate.rate_n_flags, index); - rs_fill_link_cmd(priv, lq_sta, &tbl->current_rate, + tbl->current_rate, index); + rs_fill_link_cmd(priv, lq_sta, tbl->current_rate, &lq_sta->lq); iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); } @@ -2058,7 +2040,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, } out: - rs_mcs_from_tbl(&tbl->current_rate, tbl, index, is_green); + tbl->current_rate = rate_n_flags_from_tbl(tbl, index, is_green); i = index; sta->last_txrate_idx = i; @@ -2084,7 +2066,7 @@ static void rs_initialize_lq(struct iwl_priv *priv, u8 active_tbl = 0; int rate_idx; u8 use_green = rs_use_green(priv, conf); - struct iwl4965_rate mcs_rate; + u32 rate; if (!sta || !sta->rate_ctrl_priv) goto out; @@ -2107,22 +2089,22 @@ static void rs_initialize_lq(struct iwl_priv *priv, i = 0; /* FIXME:RS: This is also wrong in 4965 */ - mcs_rate.rate_n_flags = iwl4965_rates[i].plcp ; - mcs_rate.rate_n_flags |= RATE_MCS_ANT_B_MSK; - mcs_rate.rate_n_flags &= ~RATE_MCS_ANT_A_MSK; + rate = iwl4965_rates[i].plcp; + rate |= RATE_MCS_ANT_B_MSK; + rate &= ~RATE_MCS_ANT_A_MSK; if (i >= IWL_FIRST_CCK_RATE && i <= IWL_LAST_CCK_RATE) - mcs_rate.rate_n_flags |= RATE_MCS_CCK_MSK; + rate |= RATE_MCS_CCK_MSK; tbl->ant_type = ANT_B; - rs_get_tbl_info_from_mcs(&mcs_rate, priv->band, tbl, &rate_idx); + rs_get_tbl_info_from_mcs(rate, priv->band, tbl, &rate_idx); if (!rs_is_ant_connected(priv->hw_params.valid_tx_ant, tbl->ant_type)) - rs_toggle_antenna(&mcs_rate, tbl); + rs_toggle_antenna(&rate, tbl); - rs_mcs_from_tbl(&mcs_rate, tbl, rate_idx, use_green); - tbl->current_rate.rate_n_flags = mcs_rate.rate_n_flags; + rate = rate_n_flags_from_tbl(tbl, rate_idx, use_green); + tbl->current_rate = rate; rs_get_expected_tpt_table(lq_sta, tbl); - rs_fill_link_cmd(NULL, lq_sta, &mcs_rate, &lq_sta->lq); + rs_fill_link_cmd(NULL, lq_sta, rate, &lq_sta->lq); iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); out: return; @@ -2275,8 +2257,7 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, lq_sta->is_dup = 0; lq_sta->is_green = rs_use_green(priv, conf); - lq_sta->active_rate = priv->active_rate; - lq_sta->active_rate &= ~(0x1000); + lq_sta->active_legacy_rate = priv->active_rate & ~(0x1000); lq_sta->active_rate_basic = priv->active_rate_basic; lq_sta->band = priv->band; #ifdef CONFIG_IWL4965_HT @@ -2326,7 +2307,7 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, static void rs_fill_link_cmd(const struct iwl_priv *priv, struct iwl4965_lq_sta *lq_sta, - struct iwl4965_rate *tx_mcs, + u32 new_rate, struct iwl_link_quality_cmd *lq_cmd) { int index = 0; @@ -2334,14 +2315,13 @@ static void rs_fill_link_cmd(const struct iwl_priv *priv, int repeat_rate = 0; u8 ant_toggle_count = 0; u8 use_ht_possible = 1; - struct iwl4965_rate new_rate; struct iwl4965_scale_tbl_info tbl_type = { 0 }; /* Override starting rate (index 0) if needed for debug purposes */ - rs_dbgfs_set_mcs(lq_sta, tx_mcs, index); + rs_dbgfs_set_mcs(lq_sta, &new_rate, index); - /* Interpret rate_n_flags */ - rs_get_tbl_info_from_mcs(tx_mcs, lq_sta->band, + /* Interpret new_rate (rate_n_flags) */ + rs_get_tbl_info_from_mcs(new_rate, lq_sta->band, &tbl_type, &rate_idx); /* How many times should we repeat the initial rate? */ @@ -2355,9 +2335,7 @@ static void rs_fill_link_cmd(const struct iwl_priv *priv, is_mimo(tbl_type.lq_type) ? 1 : 0; /* Fill 1st table entry (index 0) */ - lq_cmd->rs_table[index].rate_n_flags = - cpu_to_le32(tx_mcs->rate_n_flags); - new_rate.rate_n_flags = tx_mcs->rate_n_flags; + lq_cmd->rs_table[index].rate_n_flags = cpu_to_le32(new_rate); /*FIXME:RS*/ if (is_mimo(tbl_type.lq_type) || (tbl_type.ant_type == ANT_A)) @@ -2393,12 +2371,12 @@ static void rs_fill_link_cmd(const struct iwl_priv *priv, /* Fill next table entry */ lq_cmd->rs_table[index].rate_n_flags = - cpu_to_le32(new_rate.rate_n_flags); + cpu_to_le32(new_rate); repeat_rate--; index++; } - rs_get_tbl_info_from_mcs(&new_rate, lq_sta->band, &tbl_type, + rs_get_tbl_info_from_mcs(new_rate, lq_sta->band, &tbl_type, &rate_idx); /* Indicate to uCode which entries might be MIMO. @@ -2408,8 +2386,8 @@ static void rs_fill_link_cmd(const struct iwl_priv *priv, lq_cmd->general_params.mimo_delimiter = index; /* Get next rate */ - rs_get_lower_rate(lq_sta, &tbl_type, rate_idx, - use_ht_possible, &new_rate); + new_rate = rs_get_lower_rate(lq_sta, &tbl_type, rate_idx, + use_ht_possible); /* How many times should we repeat the next rate? */ if (is_legacy(tbl_type.lq_type)) { @@ -2433,8 +2411,7 @@ static void rs_fill_link_cmd(const struct iwl_priv *priv, rs_dbgfs_set_mcs(lq_sta, &new_rate, index); /* Fill next table entry */ - lq_cmd->rs_table[index].rate_n_flags = - cpu_to_le32(new_rate.rate_n_flags); + lq_cmd->rs_table[index].rate_n_flags = cpu_to_le32(new_rate); index++; repeat_rate--; @@ -2483,25 +2460,21 @@ static int open_file_generic(struct inode *inode, struct file *file) return 0; } static void rs_dbgfs_set_mcs(struct iwl4965_lq_sta *lq_sta, - struct iwl4965_rate *mcs, int index) + u32 *rate_n_flags, int index) { - u32 base_rate; - - if (lq_sta->band == IEEE80211_BAND_5GHZ) - base_rate = 0x800D; - else - base_rate = 0x820A; - - if (lq_sta->dbg_fixed.rate_n_flags) { - if (index < 12) - mcs->rate_n_flags = lq_sta->dbg_fixed.rate_n_flags; - else - mcs->rate_n_flags = base_rate; + if (lq_sta->dbg_fixed_rate) { + if (index < 12) { + *rate_n_flags = lq_sta->dbg_fixed_rate; + } else { + if (lq_sta->band == IEEE80211_BAND_5GHZ) + *rate_n_flags = 0x800D; + else + *rate_n_flags = 0x820A; + } IWL_DEBUG_RATE("Fixed rate ON\n"); - return; + } else { + IWL_DEBUG_RATE("Fixed rate OFF\n"); } - - IWL_DEBUG_RATE("Fixed rate OFF\n"); } static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file, @@ -2518,20 +2491,21 @@ static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file, return -EFAULT; if (sscanf(buf, "%x", &parsed_rate) == 1) - lq_sta->dbg_fixed.rate_n_flags = parsed_rate; + lq_sta->dbg_fixed_rate = parsed_rate; else - lq_sta->dbg_fixed.rate_n_flags = 0; + lq_sta->dbg_fixed_rate = 0; - lq_sta->active_rate = 0x0FFF; /* 1 - 54 MBits, includes CCK */ - lq_sta->active_siso_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */ - 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 */ + lq_sta->active_legacy_rate = 0x0FFF; /* 1 - 54 MBits, includes CCK */ + lq_sta->active_siso_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */ + 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 */ IWL_DEBUG_RATE("sta_id %d rate 0x%X\n", - lq_sta->lq.sta_id, lq_sta->dbg_fixed.rate_n_flags); + lq_sta->lq.sta_id, lq_sta->dbg_fixed_rate); - if (lq_sta->dbg_fixed.rate_n_flags) { - rs_fill_link_cmd(NULL, lq_sta, &lq_sta->dbg_fixed, &lq_sta->lq); + if (lq_sta->dbg_fixed_rate) { + rs_fill_link_cmd(NULL, lq_sta, lq_sta->dbg_fixed_rate, + &lq_sta->lq); iwl_send_lq_cmd(lq_sta->drv, &lq_sta->lq, CMD_ASYNC); } @@ -2550,9 +2524,9 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, desc += sprintf(buff+desc, "sta_id %d\n", lq_sta->lq.sta_id); desc += sprintf(buff+desc, "failed=%d success=%d rate=0%X\n", lq_sta->total_failed, lq_sta->total_success, - lq_sta->active_rate); + lq_sta->active_legacy_rate); desc += sprintf(buff+desc, "fixed rate 0x%X\n", - lq_sta->dbg_fixed.rate_n_flags); + lq_sta->dbg_fixed_rate); desc += sprintf(buff+desc, "general:" "flags=0x%X mimo-d=%d s-ant0x%x d-ant=0x%x\n", lq_sta->lq.general_params.flags, @@ -2602,7 +2576,7 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file, lq_sta->lq_info[i].is_SGI, lq_sta->lq_info[i].is_fat, lq_sta->lq_info[i].is_dup, - lq_sta->lq_info[i].current_rate.rate_n_flags); + lq_sta->lq_info[i].current_rate); for (j = 0; j < IWL_RATE_COUNT; j++) { desc += sprintf(buff+desc, "counter=%d success=%d %%=%d\n", diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 783f722f3c3..3452cc66242 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -1073,17 +1073,29 @@ unsigned int iwl4965_fill_beacon_frame(struct iwl_priv *priv, return priv->ibss_beacon->len; } -static u8 iwl4965_rate_get_lowest_plcp(int rate_mask) +static u8 iwl4965_rate_get_lowest_plcp(struct iwl_priv *priv) { - u8 i; + int i; + int rate_mask; + + /* Set rate mask*/ + if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) + rate_mask = priv->active_rate_basic & 0xF; + else + rate_mask = priv->active_rate_basic & 0xFF0; + /* Find lowest valid rate */ for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID; - i = iwl4965_rates[i].next_ieee) { + i = iwl4965_rates[i].next_ieee) { if (rate_mask & (1 << i)) return iwl4965_rates[i].plcp; } - return IWL_RATE_INVALID; + /* No valid rate was found. Assign the lowest one */ + if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) + return IWL_RATE_1M_PLCP; + else + return IWL_RATE_6M_PLCP; } static int iwl4965_send_beacon_cmd(struct iwl_priv *priv) @@ -1101,16 +1113,7 @@ static int iwl4965_send_beacon_cmd(struct iwl_priv *priv) return -ENOMEM; } - if (!(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)) { - rate = iwl4965_rate_get_lowest_plcp(priv->active_rate_basic & - 0xFF0); - if (rate == IWL_INVALID_RATE) - rate = IWL_RATE_6M_PLCP; - } else { - rate = iwl4965_rate_get_lowest_plcp(priv->active_rate_basic & 0xF); - if (rate == IWL_INVALID_RATE) - rate = IWL_RATE_1M_PLCP; - } + rate = iwl4965_rate_get_lowest_plcp(priv); frame_size = iwl4965_hw_get_beacon_cmd(priv, frame, rate); -- cgit v1.2.3-70-g09d2 From eecd6e5705fdea75c354559339a2b1f22ec400a0 Mon Sep 17 00:00:00 2001 From: Guy Cohen Date: Wed, 23 Apr 2008 17:14:58 -0700 Subject: iwlwifi: rate scale module cleanups This patch does following changes 1. rs_get_expected_tpt_table: changed get to set 2. changed IWL_DEBUG_HT to IWL_DEBUG_RATE as appropriate 3. changed rs_get_supported_rates to be returning value function Signed-off-by: Guy Cohen Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 101 ++++++++++++++--------------- 1 file changed, 49 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index 7c55aa9a2ba..4063534b64c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -604,25 +604,23 @@ static inline u8 rs_use_green(struct iwl_priv *priv, * basic available rates. * */ -static void rs_get_supported_rates(struct iwl4965_lq_sta *lq_sta, +static u16 rs_get_supported_rates(struct iwl4965_lq_sta *lq_sta, struct ieee80211_hdr *hdr, - enum iwl_table_type rate_type, - u16 *data_rate) + enum iwl_table_type rate_type) { - if (is_legacy(rate_type)) - *data_rate = lq_sta->active_legacy_rate; - else { + if (hdr && is_multicast_ether_addr(hdr->addr1) && + lq_sta->active_rate_basic) + return lq_sta->active_rate_basic; + + if (is_legacy(rate_type)) { + return lq_sta->active_legacy_rate; + } else { if (is_siso(rate_type)) - *data_rate = lq_sta->active_siso_rate; + return lq_sta->active_siso_rate; else if (is_mimo2(rate_type)) - *data_rate = lq_sta->active_mimo2_rate; + return lq_sta->active_mimo2_rate; else - *data_rate = lq_sta->active_mimo3_rate; - } - - if (hdr && is_multicast_ether_addr(hdr->addr1) && - lq_sta->active_rate_basic) { - *data_rate = lq_sta->active_rate_basic; + return lq_sta->active_mimo3_rate; } } @@ -709,7 +707,7 @@ static u32 rs_get_lower_rate(struct iwl4965_lq_sta *lq_sta, tbl->is_SGI = 0; } - rs_get_supported_rates(lq_sta, NULL, tbl->lq_type, &rate_mask); + rate_mask = rs_get_supported_rates(lq_sta, NULL, tbl->lq_type); /* Mask with station rate restriction */ if (is_legacy(tbl->lq_type)) { @@ -975,7 +973,7 @@ static u8 rs_is_other_ant_connected(u8 valid_antenna, u8 ant_type) static void rs_set_stay_in_table(u8 is_legacy, struct iwl4965_lq_sta *lq_sta) { - IWL_DEBUG_HT("we are staying in the same table\n"); + IWL_DEBUG_RATE("we are staying in the same table\n"); lq_sta->stay_in_tbl = 1; /* only place this gets set */ if (is_legacy) { lq_sta->table_count_limit = IWL_LEGACY_TABLE_COUNT; @@ -994,7 +992,7 @@ static void rs_set_stay_in_table(u8 is_legacy, /* * Find correct throughput table for given mode of modulation */ -static void rs_get_expected_tpt_table(struct iwl4965_lq_sta *lq_sta, +static void rs_set_expected_tpt_table(struct iwl4965_lq_sta *lq_sta, struct iwl4965_scale_tbl_info *tbl) { if (is_legacy(tbl->lq_type)) { @@ -1161,7 +1159,7 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, if (!rs_is_both_ant_supp(priv->hw_params.valid_tx_ant)) return -1; - IWL_DEBUG_HT("LQ: try to switch to MIMO2\n"); + IWL_DEBUG_RATE("LQ: try to switch to MIMO2\n"); tbl->lq_type = LQ_MIMO2; tbl->is_dup = lq_sta->is_dup; @@ -1186,20 +1184,20 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, tbl->is_SGI = 0; */ - rs_get_expected_tpt_table(lq_sta, tbl); + rs_set_expected_tpt_table(lq_sta, tbl); rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index, index); - IWL_DEBUG_HT("LQ: MIMO2 best rate %d mask %X\n", rate, rate_mask); + IWL_DEBUG_RATE("LQ: MIMO2 best rate %d mask %X\n", rate, rate_mask); if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) { - IWL_DEBUG_HT("Can't switch with index %d rate mask %x\n", + IWL_DEBUG_RATE("Can't switch with index %d rate mask %x\n", rate, rate_mask); return -1; } tbl->current_rate = rate_n_flags_from_tbl(tbl, rate, is_green); - IWL_DEBUG_HT("LQ: Switch to new mcs %X index is green %X\n", + IWL_DEBUG_RATE("LQ: Switch to new mcs %X index is green %X\n", tbl->current_rate, is_green); return 0; } @@ -1232,7 +1230,7 @@ static int rs_switch_to_siso(struct iwl_priv *priv, !sta->ht_info.ht_supported) return -1; - IWL_DEBUG_HT("LQ: try to switch to SISO\n"); + IWL_DEBUG_RATE("LQ: try to switch to SISO\n"); tbl->is_dup = lq_sta->is_dup; tbl->lq_type = LQ_SISO; @@ -1260,17 +1258,17 @@ static int rs_switch_to_siso(struct iwl_priv *priv, if (is_green) tbl->is_SGI = 0; /*11n spec: no SGI in SISO+Greenfield*/ - rs_get_expected_tpt_table(lq_sta, tbl); + rs_set_expected_tpt_table(lq_sta, tbl); rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index, index); - IWL_DEBUG_HT("LQ: get best rate %d mask %X\n", rate, rate_mask); + IWL_DEBUG_RATE("LQ: get best rate %d mask %X\n", rate, rate_mask); if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) { - IWL_DEBUG_HT("can not switch with index %d rate mask %x\n", + IWL_DEBUG_RATE("can not switch with index %d rate mask %x\n", rate, rate_mask); return -1; } tbl->current_rate = rate_n_flags_from_tbl(tbl, rate, is_green); - IWL_DEBUG_HT("LQ: Switch to new mcs %X index is green %X\n", + IWL_DEBUG_RATE("LQ: Switch to new mcs %X index is green %X\n", tbl->current_rate, is_green); return 0; #else @@ -1302,7 +1300,7 @@ static int rs_move_legacy_other(struct iwl_priv *priv, for (; ;) { switch (tbl->action) { case IWL_LEGACY_SWITCH_ANTENNA: - IWL_DEBUG_HT("LQ Legacy toggle Antenna\n"); + IWL_DEBUG_RATE("LQ Legacy toggle Antenna\n"); search_tbl->lq_type = LQ_NONE; lq_sta->action_counter++; @@ -1322,12 +1320,12 @@ static int rs_move_legacy_other(struct iwl_priv *priv, rs_toggle_antenna(&search_tbl->current_rate, search_tbl); - rs_get_expected_tpt_table(lq_sta, search_tbl); + rs_set_expected_tpt_table(lq_sta, search_tbl); lq_sta->search_better_tbl = 1; goto out; case IWL_LEGACY_SWITCH_SISO: - IWL_DEBUG_HT("LQ: Legacy switch to SISO\n"); + IWL_DEBUG_RATE("LQ: Legacy switch to SISO\n"); /* Set up search table to try SISO */ memcpy(search_tbl, tbl, sz); @@ -1342,7 +1340,7 @@ static int rs_move_legacy_other(struct iwl_priv *priv, break; case IWL_LEGACY_SWITCH_MIMO2: - IWL_DEBUG_HT("LQ: Legacy switch to MIMO2\n"); + IWL_DEBUG_RATE("LQ: Legacy switch to MIMO2\n"); /* Set up search table to try MIMO */ memcpy(search_tbl, tbl, sz); @@ -1401,7 +1399,7 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, lq_sta->action_counter++; switch (tbl->action) { case IWL_SISO_SWITCH_ANTENNA: - IWL_DEBUG_HT("LQ: SISO toggle Antenna\n"); + IWL_DEBUG_RATE("LQ: SISO toggle Antenna\n"); /*FIXME:RS: is this really needed for SISO?*/ if (window->success_ratio >= IWL_RS_GOOD_RATIO) break; @@ -1417,7 +1415,7 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, goto out; case IWL_SISO_SWITCH_MIMO2: - IWL_DEBUG_HT("LQ: SISO switch to MIMO\n"); + IWL_DEBUG_RATE("LQ: SISO switch to MIMO\n"); memcpy(search_tbl, tbl, sz); search_tbl->is_SGI = 0; search_tbl->ant_type = ANT_AB; /*FIXME:RS*/ @@ -1429,7 +1427,7 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, } break; case IWL_SISO_SWITCH_GI: - IWL_DEBUG_HT("LQ: SISO toggle SGI/NGI\n"); + IWL_DEBUG_RATE("LQ: SISO toggle SGI/NGI\n"); memcpy(search_tbl, tbl, sz); if (is_green) { @@ -1439,7 +1437,7 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, IWL_ERROR("SGI was set in GF+SISO\n"); } search_tbl->is_SGI = !tbl->is_SGI; - rs_get_expected_tpt_table(lq_sta, search_tbl); + rs_set_expected_tpt_table(lq_sta, search_tbl); if (tbl->is_SGI) { s32 tpt = lq_sta->last_tpt / 100; if (tpt >= search_tbl->expected_tpt[index]) @@ -1490,7 +1488,7 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv, switch (tbl->action) { case IWL_MIMO_SWITCH_ANTENNA_A: case IWL_MIMO_SWITCH_ANTENNA_B: - IWL_DEBUG_HT("LQ: MIMO2 switch to SISO\n"); + IWL_DEBUG_RATE("LQ: MIMO2 switch to SISO\n"); /* Set up new search table for SISO */ memcpy(search_tbl, tbl, sz); @@ -1510,12 +1508,12 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv, break; case IWL_MIMO_SWITCH_GI: - IWL_DEBUG_HT("LQ: MIMO toggle SGI/NGI\n"); + IWL_DEBUG_RATE("LQ: MIMO toggle SGI/NGI\n"); /* Set up new search table for MIMO */ memcpy(search_tbl, tbl, sz); search_tbl->is_SGI = !tbl->is_SGI; - rs_get_expected_tpt_table(lq_sta, search_tbl); + rs_set_expected_tpt_table(lq_sta, search_tbl); /* * If active table already uses the fastest possible * modulation (dual stream with short guard interval), @@ -1593,7 +1591,7 @@ static void rs_stay_in_table(struct iwl4965_lq_sta *lq_sta) (lq_sta->total_success > lq_sta->max_success_limit) || ((!lq_sta->search_better_tbl) && (lq_sta->flush_timer) && (flush_interval_passed))) { - IWL_DEBUG_HT("LQ: stay is expired %d %d %d\n:", + IWL_DEBUG_RATE("LQ: stay is expired %d %d %d\n:", lq_sta->total_failed, lq_sta->total_success, flush_interval_passed); @@ -1616,7 +1614,7 @@ static void rs_stay_in_table(struct iwl4965_lq_sta *lq_sta) lq_sta->table_count_limit) { lq_sta->table_count = 0; - IWL_DEBUG_HT("LQ: stay in table clear win\n"); + IWL_DEBUG_RATE("LQ: stay in table clear win\n"); for (i = 0; i < IWL_RATE_COUNT; i++) rs_rate_scale_clear_window( &(tbl->win[i])); @@ -1715,8 +1713,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, tbl->lq_type); /* rates available for this association, and for modulation mode */ - rs_get_supported_rates(lq_sta, hdr, tbl->lq_type, - &rate_mask); + rate_mask = rs_get_supported_rates(lq_sta, hdr, tbl->lq_type); IWL_DEBUG_RATE("mask 0x%04X \n", rate_mask); @@ -1756,7 +1753,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, /* Get expected throughput table and history window for current rate */ if (!tbl->expected_tpt) - rs_get_expected_tpt_table(lq_sta, tbl); + rs_set_expected_tpt_table(lq_sta, tbl); window = &(tbl->win[index]); @@ -1806,7 +1803,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, if ((window->success_ratio > success_limit) || (window->average_tpt > lq_sta->last_tpt)) { if (!is_legacy(tbl->lq_type)) { - IWL_DEBUG_HT("LQ: we are switching to HT" + IWL_DEBUG_RATE("LQ: we are switching to HT" " rate suc %d current tpt %d" " old tpt %d\n", window->success_ratio, @@ -1834,7 +1831,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, /* Need to set up a new rate table in uCode */ update_lq = 1; - IWL_DEBUG_HT("XXY GO BACK TO OLD TABLE\n"); + IWL_DEBUG_RATE("XXY GO BACK TO OLD TABLE\n"); } /* Either way, we've made a decision; modulation mode @@ -1942,7 +1939,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, break; } - IWL_DEBUG_HT("choose rate scale index %d action %d low %d " + IWL_DEBUG_RATE("choose rate scale index %d action %d low %d " "high %d type %d\n", index, scale_action, low, high, tbl->lq_type); @@ -1987,7 +1984,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, index = iwl4965_hwrate_to_plcp_idx( tbl->current_rate); - IWL_DEBUG_HT("Switch current mcs: %X index: %d\n", + IWL_DEBUG_RATE("Switch current mcs: %X index: %d\n", tbl->current_rate, index); rs_fill_link_cmd(priv, lq_sta, tbl->current_rate, &lq_sta->lq); @@ -2006,7 +2003,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, #endif (lq_sta->action_counter >= 1)) { lq_sta->action_counter = 0; - IWL_DEBUG_HT("LQ: STAY in legacy table\n"); + IWL_DEBUG_RATE("LQ: STAY in legacy table\n"); rs_set_stay_in_table(1, lq_sta); } @@ -2019,7 +2016,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) && (lq_sta->tx_agg_tid_en & (1 << tid)) && (tid != MAX_TID_COUNT)) { - IWL_DEBUG_HT("try to aggregate tid %d\n", tid); + IWL_DEBUG_RATE("try to aggregate tid %d\n", tid); rs_tl_turn_on_agg(priv, tid, lq_sta, sta); } #endif /*CONFIG_IWL4965_HT */ @@ -2103,7 +2100,7 @@ static void rs_initialize_lq(struct iwl_priv *priv, rate = rate_n_flags_from_tbl(tbl, rate_idx, use_green); tbl->current_rate = rate; - rs_get_expected_tpt_table(lq_sta, tbl); + rs_set_expected_tpt_table(lq_sta, tbl); rs_fill_link_cmd(NULL, lq_sta, rate, &lq_sta->lq); iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); out: @@ -2227,7 +2224,7 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, DECLARE_MAC_BUF(mac); /* for IBSS the call are from tasklet */ - IWL_DEBUG_HT("LQ: ADD station %s\n", + IWL_DEBUG_RATE("LQ: ADD station %s\n", print_mac(mac, sta->addr)); if (sta_id == IWL_INVALID_STATION) { @@ -2287,7 +2284,7 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, lq_sta->active_mimo3_rate &= ~((u16)0x2); lq_sta->active_mimo3_rate <<= IWL_FIRST_OFDM_RATE; - IWL_DEBUG_HT("SISO RATE %X MIMO2 RATE %X MIMO3 RATE %X\n", + IWL_DEBUG_RATE("SISO RATE %X MIMO2 RATE %X MIMO3 RATE %X\n", lq_sta->active_siso_rate, lq_sta->active_mimo2_rate, lq_sta->active_mimo3_rate); -- cgit v1.2.3-70-g09d2 From aade00cee60d8a2b1682b6804664049d7a369ac2 Mon Sep 17 00:00:00 2001 From: Guy Cohen Date: Wed, 23 Apr 2008 17:14:59 -0700 Subject: iwlwifi: rate scale restructure toggle_antenna functions This patch add support for toggeling of A/B/C and AB/BC/AC antennas Signed-off-by: Guy Cohen Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 172 +++++++++++++++-------------- 1 file changed, 91 insertions(+), 81 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index 4063534b64c..1ad62568558 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -43,7 +43,7 @@ #define RS_NAME "iwl-4965-rs" -#define NUM_TRY_BEFORE_ANTENNA_TOGGLE 1 +#define NUM_TRY_BEFORE_ANT_TOGGLE 1 #define IWL_NUMBER_TRY 1 #define IWL_HT_NUMBER_TRY 3 @@ -64,6 +64,17 @@ static u8 rs_ht_to_legacy[] = { IWL_RATE_48M_INDEX, IWL_RATE_54M_INDEX }; +static const u8 ant_toggle_lookup[] = { + /*ANT_NONE -> */ ANT_NONE, + /*ANT_A -> */ ANT_B, + /*ANT_B -> */ ANT_C, + /*ANT_AB -> */ ANT_BC, + /*ANT_C -> */ ANT_A, + /*ANT_AC -> */ ANT_AB, + /*ANT_BC -> */ ANT_AC, + /*ANT_ABC -> */ ANT_ABC, +}; + /** * struct iwl4965_rate_scale_data -- tx success history for one rate */ @@ -131,8 +142,6 @@ struct iwl4965_lq_sta { u32 flush_timer; /* time staying in mode before new search */ u8 action_counter; /* # mode-switch actions tried */ - u8 antenna; - u8 valid_antenna; u8 is_green; u8 is_dup; enum ieee80211_band band; @@ -243,6 +252,11 @@ static void rs_rate_scale_clear_window(struct iwl4965_rate_scale_data *window) window->stamp = 0; } +static inline u8 rs_is_valid_ant(u8 valid_antenna, u8 ant_type) +{ + return ((ant_type & valid_antenna) == ant_type); +} + #ifdef CONFIG_IWL4965_HT /* * removes the old data from the statistics. All data that is older than @@ -576,12 +590,33 @@ static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags, } return 0; } -/* FIXME:RS: need to toggle also ANT_C, and also AB,AC,BC */ -static inline void rs_toggle_antenna(u32 *rate_n_flags, - struct iwl4965_scale_tbl_info *tbl) + +/* switch to another antenna/antennas and return 1 */ +/* if no other valid antenna found, return 0 */ +static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags, + struct iwl4965_scale_tbl_info *tbl) { - tbl->ant_type ^= ANT_AB; - *rate_n_flags ^= (RATE_MCS_ANT_A_MSK|RATE_MCS_ANT_B_MSK); + u8 new_ant_type; + + if (!tbl->ant_type || tbl->ant_type > ANT_ABC) + return 0; + + if (!rs_is_valid_ant(valid_ant, tbl->ant_type)) + return 0; + + new_ant_type = ant_toggle_lookup[tbl->ant_type]; + + while ((new_ant_type != tbl->ant_type) && + !rs_is_valid_ant(valid_ant, new_ant_type)) + new_ant_type = ant_toggle_lookup[new_ant_type]; + + if (new_ant_type == tbl->ant_type) + return 0; + + tbl->ant_type = new_ant_type; + *rate_n_flags &= ~RATE_MCS_ANT_ABC_MSK; + *rate_n_flags |= new_ant_type << RATE_MCS_ANT_POS; + return 1; } /* FIXME:RS: in 4965 we don't use greenfield at all */ @@ -796,8 +831,6 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, table = &lq_sta->lq; active_index = lq_sta->active_tbl; - lq_sta->antenna = lq_sta->valid_antenna; - curr_tbl = &(lq_sta->lq_info[active_index]); search_tbl = &(lq_sta->lq_info[(1 - active_index)]); window = (struct iwl4965_rate_scale_data *) @@ -946,22 +979,6 @@ out: return; } -static inline u8 rs_is_ant_connected(u8 valid_antenna, u8 ant_type) -{ - return ((ant_type & valid_antenna) == ant_type); -} - -/*FIXME:RS: this function should be replaced*/ -static u8 rs_is_other_ant_connected(u8 valid_antenna, u8 ant_type) -{ - if (ant_type == ANT_B) - return rs_is_ant_connected(valid_antenna, ANT_A); - else - return rs_is_ant_connected(valid_antenna, ANT_B); - - return 0; -} - /* * Begin a period of staying with a selected modulation mode. * Set "stay_in_tbl" flag to prevent any mode switches. @@ -1128,12 +1145,6 @@ static s32 rs_get_best_rate(struct iwl_priv *priv, } #endif /* CONFIG_IWL4965_HT */ -/*FIXME:RS:this function should be replaced*/ -static inline u8 rs_is_both_ant_supp(u8 valid_antenna) -{ - return (rs_is_ant_connected(valid_antenna, ANT_AB)); -} - /* * Set up search table for MIMO */ @@ -1156,7 +1167,7 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, return -1; /* Need both Tx chains/antennas to support MIMO */ - if (!rs_is_both_ant_supp(priv->hw_params.valid_tx_ant)) + if (priv->hw_params.tx_chains_num < 2) return -1; IWL_DEBUG_RATE("LQ: try to switch to MIMO2\n"); @@ -1302,7 +1313,6 @@ static int rs_move_legacy_other(struct iwl_priv *priv, case IWL_LEGACY_SWITCH_ANTENNA: IWL_DEBUG_RATE("LQ Legacy toggle Antenna\n"); - search_tbl->lq_type = LQ_NONE; lq_sta->action_counter++; /* Don't change antenna if success has been great */ @@ -1310,19 +1320,15 @@ static int rs_move_legacy_other(struct iwl_priv *priv, if (window->success_ratio >= IWL_RS_GOOD_RATIO) break; - /* Don't change antenna if other one is not connected */ - if (!rs_is_other_ant_connected(valid_tx_ant, - tbl->ant_type)) - break; - /* Set up search table to try other antenna */ memcpy(search_tbl, tbl, sz); - rs_toggle_antenna(&search_tbl->current_rate, - search_tbl); - rs_set_expected_tpt_table(lq_sta, search_tbl); - lq_sta->search_better_tbl = 1; - goto out; + if (rs_toggle_antenna(valid_tx_ant, + &search_tbl->current_rate, search_tbl)) { + rs_set_expected_tpt_table(lq_sta, search_tbl); + lq_sta->search_better_tbl = 1; + goto out; + } case IWL_LEGACY_SWITCH_SISO: IWL_DEBUG_RATE("LQ: Legacy switch to SISO\n"); @@ -1403,16 +1409,13 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, /*FIXME:RS: is this really needed for SISO?*/ if (window->success_ratio >= IWL_RS_GOOD_RATIO) break; - if (!rs_is_other_ant_connected(valid_tx_ant, - tbl->ant_type)) - break; memcpy(search_tbl, tbl, sz); - rs_toggle_antenna(&search_tbl->current_rate, - search_tbl); - lq_sta->search_better_tbl = 1; - - goto out; + if (rs_toggle_antenna(valid_tx_ant, + &search_tbl->current_rate, search_tbl)) { + lq_sta->search_better_tbl = 1; + goto out; + } case IWL_SISO_SWITCH_MIMO2: IWL_DEBUG_RATE("LQ: SISO switch to MIMO\n"); @@ -1473,7 +1476,6 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv, struct sta_info *sta, int index) { - int ret; s8 is_green = lq_sta->is_green; struct iwl4965_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); @@ -1482,6 +1484,8 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv, u32 sz = (sizeof(struct iwl4965_scale_tbl_info) - (sizeof(struct iwl4965_rate_scale_data) * IWL_RATE_COUNT)); u8 start_action = tbl->action; + /*u8 valid_tx_ant = priv->hw_params.valid_tx_ant;*/ + int ret; for (;;) { lq_sta->action_counter++; @@ -2057,13 +2061,14 @@ static void rs_initialize_lq(struct iwl_priv *priv, struct ieee80211_conf *conf, struct sta_info *sta) { - int i; struct iwl4965_lq_sta *lq_sta; struct iwl4965_scale_tbl_info *tbl; - u8 active_tbl = 0; int rate_idx; - u8 use_green = rs_use_green(priv, conf); + int i; u32 rate; + u8 use_green = rs_use_green(priv, conf); + u8 active_tbl = 0; + u8 valid_tx_ant; if (!sta || !sta->rate_ctrl_priv) goto out; @@ -2075,6 +2080,8 @@ static void rs_initialize_lq(struct iwl_priv *priv, (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)) goto out; + valid_tx_ant = priv->hw_params.valid_tx_ant; + if (!lq_sta->search_better_tbl) active_tbl = lq_sta->active_tbl; else @@ -2095,8 +2102,8 @@ static void rs_initialize_lq(struct iwl_priv *priv, tbl->ant_type = ANT_B; rs_get_tbl_info_from_mcs(rate, priv->band, tbl, &rate_idx); - if (!rs_is_ant_connected(priv->hw_params.valid_tx_ant, tbl->ant_type)) - rs_toggle_antenna(&rate, tbl); + if (!rs_is_valid_ant(valid_tx_ant, tbl->ant_type)) + rs_toggle_antenna(valid_tx_ant, &rate, tbl); rate = rate_n_flags_from_tbl(tbl, rate_idx, use_green); tbl->current_rate = rate; @@ -2307,26 +2314,29 @@ static void rs_fill_link_cmd(const struct iwl_priv *priv, u32 new_rate, struct iwl_link_quality_cmd *lq_cmd) { + struct iwl4965_scale_tbl_info tbl_type; int index = 0; int rate_idx; int repeat_rate = 0; - u8 ant_toggle_count = 0; + u8 ant_toggle_cnt = 0; u8 use_ht_possible = 1; - struct iwl4965_scale_tbl_info tbl_type = { 0 }; + u8 valid_tx_ant = 0; /* Override starting rate (index 0) if needed for debug purposes */ rs_dbgfs_set_mcs(lq_sta, &new_rate, index); /* Interpret new_rate (rate_n_flags) */ + memset(&tbl_type, 0, sizeof(tbl_type)); rs_get_tbl_info_from_mcs(new_rate, lq_sta->band, &tbl_type, &rate_idx); /* How many times should we repeat the initial rate? */ if (is_legacy(tbl_type.lq_type)) { - ant_toggle_count = 1; + ant_toggle_cnt = 1; repeat_rate = IWL_NUMBER_TRY; - } else + } else { repeat_rate = IWL_HT_NUMBER_TRY; + } lq_cmd->general_params.mimo_delimiter = is_mimo(tbl_type.lq_type) ? 1 : 0; @@ -2345,6 +2355,9 @@ static void rs_fill_link_cmd(const struct iwl_priv *priv, index++; repeat_rate--; + if (priv) + valid_tx_ant = priv->hw_params.valid_tx_ant; + /* Fill rest of rate table */ while (index < LINK_QUAL_MAX_RETRY_NUM) { /* Repeat initial/next rate. @@ -2352,16 +2365,13 @@ static void rs_fill_link_cmd(const struct iwl_priv *priv, * For HT IWL_HT_NUMBER_TRY == 3, this executes twice. */ while (repeat_rate > 0 && (index < LINK_QUAL_MAX_RETRY_NUM)) { if (is_legacy(tbl_type.lq_type)) { - if (ant_toggle_count < - NUM_TRY_BEFORE_ANTENNA_TOGGLE) - ant_toggle_count++; - else if (priv && rs_is_other_ant_connected( - priv->hw_params.valid_tx_ant, - tbl_type.ant_type)) { - rs_toggle_antenna(&new_rate, &tbl_type); - ant_toggle_count = 1; - } - } + if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE) + ant_toggle_cnt++; + else if (priv && + rs_toggle_antenna(valid_tx_ant, + &new_rate, &tbl_type)) + ant_toggle_cnt = 1; +} /* Override next rate if needed for debug purposes */ rs_dbgfs_set_mcs(lq_sta, &new_rate, index); @@ -2388,17 +2398,17 @@ static void rs_fill_link_cmd(const struct iwl_priv *priv, /* How many times should we repeat the next rate? */ if (is_legacy(tbl_type.lq_type)) { - if (ant_toggle_count < NUM_TRY_BEFORE_ANTENNA_TOGGLE) - ant_toggle_count++; - else if (priv && rs_is_other_ant_connected( - priv->hw_params.valid_tx_ant, - tbl_type.ant_type)) { - rs_toggle_antenna(&new_rate, &tbl_type); - ant_toggle_count = 1; - } + if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE) + ant_toggle_cnt++; + else if (priv && + rs_toggle_antenna(valid_tx_ant, + &new_rate, &tbl_type)) + ant_toggle_cnt = 1; + repeat_rate = IWL_NUMBER_TRY; - } else + } else { repeat_rate = IWL_HT_NUMBER_TRY; + } /* Don't allow HT rates after next pass. * rs_get_lower_rate() will change type to LQ_A or LQ_G. */ -- cgit v1.2.3-70-g09d2 From 3195cdb7424b4207f6903f1f3ddadcab49fa22f2 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 23 Apr 2008 17:15:00 -0700 Subject: iwlwifi: reorganize TX RX constatns This patch moves TX/RX constants in 4969 headers Signed-off-by: Tomas Winkler Signed-off-by: Emmanuel Grumbach Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-commands.h | 8 ++++++++ drivers/net/wireless/iwlwifi/iwl-4965.c | 3 --- drivers/net/wireless/iwlwifi/iwl-4965.h | 7 +++++-- 3 files changed, 13 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-commands.h b/drivers/net/wireless/iwlwifi/iwl-4965-commands.h index 7ffae05a930..6b2d6bfec1e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-commands.h @@ -1100,6 +1100,14 @@ struct iwl4965_rx_mpdu_res_start { #define TX_CMD_SEC_SHIFT 6 #define TX_CMD_SEC_KEY128 0x08 +/* + * security overhead sizes + */ +#define WEP_IV_LEN 4 +#define WEP_ICV_LEN 4 +#define CCMP_MIC_LEN 8 +#define TKIP_ICV_LEN 4 + /* * 4965 uCode updates these Tx attempt count values in host DRAM. * Used for managing Tx retries when expecting block-acks. diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index e80f6022cf4..f5796b78f2d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2502,9 +2502,6 @@ static void iwl4965_free_shared_mem(struct iwl_priv *priv) priv->shared_phys); } -#define IWL_TX_CRC_SIZE 4 -#define IWL_TX_DELIMITER_SIZE 4 - /** * iwl4965_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array */ diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h index 1ab4e2ecf79..e3572636e59 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965.h @@ -803,8 +803,8 @@ struct iwl4965_kw { #define IWL_EXT_CHANNEL_OFFSET_RESERVE1 2 #define IWL_EXT_CHANNEL_OFFSET_BELOW 3 -#define NRG_NUM_PREV_STAT_L 20 -#define NUM_RX_CHAINS (3) +#define IWL_TX_CRC_SIZE 4 +#define IWL_TX_DELIMITER_SIZE 4 #define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000 @@ -854,6 +854,9 @@ struct iwl4965_lq_mngr { #define IN_BAND_FILTER 0xFF #define MIN_AVERAGE_NOISE_MAX_VALUE 0xFFFFFFFF +#define NRG_NUM_PREV_STAT_L 20 +#define NUM_RX_CHAINS 3 + enum iwl4965_false_alarm_state { IWL_FA_TOO_MANY = 0, IWL_FA_TOO_FEW = 1, -- cgit v1.2.3-70-g09d2 From 69fdb3090846de1cdc4fcb4f7e74533f5acbfa98 Mon Sep 17 00:00:00 2001 From: Guy Cohen Date: Wed, 23 Apr 2008 17:15:01 -0700 Subject: iwlwifi: rs fix wrong parenthesizing in rs_get_lower_rate function Signed-off-by: Guy Cohen Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index 1ad62568558..469c143297e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -735,7 +735,7 @@ static u32 rs_get_lower_rate(struct iwl4965_lq_sta *lq_sta, else tbl->lq_type = LQ_G; - if (num_of_ant(tbl->ant_type > 1)) + if (num_of_ant(tbl->ant_type) > 1) tbl->ant_type = ANT_A;/*FIXME:RS*/ tbl->is_fat = 0; -- cgit v1.2.3-70-g09d2 From f935a6daa07ac78a35d1513fc61c88774b628a4c Mon Sep 17 00:00:00 2001 From: Guy Cohen Date: Wed, 23 Apr 2008 17:15:02 -0700 Subject: iwlwifi: rate sacaling fixes 1. Fixing support for tx in antenna C 2. Enable stay_in_column expiration after 2 seconds Signed-off-by: Guy Cohen Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-hw.h | 4 ++-- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 25 +++++++++++++------------ 2 files changed, 15 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h index 0c132b93d90..4f45093ab3b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h @@ -1356,9 +1356,9 @@ static inline u8 iwl4965_hw_get_rate(__le32 rate_n_flags) { return le32_to_cpu(rate_n_flags) & 0xFF; } -static inline u16 iwl4965_hw_get_rate_n_flags(__le32 rate_n_flags) +static inline u32 iwl4965_hw_get_rate_n_flags(__le32 rate_n_flags) { - return le32_to_cpu(rate_n_flags) & 0xFFFF; + return le32_to_cpu(rate_n_flags) & 0x1FFFF; } static inline __le32 iwl4965_hw_set_rate_n_flags(u8 rate, u16 flags) { diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index 469c143297e..5129d57ed59 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -620,17 +620,21 @@ static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags, } /* FIXME:RS: in 4965 we don't use greenfield at all */ -static inline u8 rs_use_green(struct iwl_priv *priv, - struct ieee80211_conf *conf) +/* FIXME:RS: don't use greenfield for now in TX */ +/* #ifdef CONFIG_IWL4965_HT */ +#if 0 +static inline u8 rs_use_green(struct iwl_priv *priv, struct ieee80211_conf *conf) { -#ifdef CONFIG_IWL4965_HT return ((conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) && priv->current_ht_config.is_green_field && !priv->current_ht_config.non_GF_STA_present); +} #else +static inline u8 rs_use_green(struct iwl_priv *priv, struct ieee80211_conf *conf) +{ return 0; -#endif /* CONFIG_IWL4965_HT */ } +#endif /* CONFIG_IWL4965_HT */ /** * rs_get_supported_rates - get the available rates @@ -1058,7 +1062,7 @@ static void rs_set_expected_tpt_table(struct iwl4965_lq_sta *lq_sta, static s32 rs_get_best_rate(struct iwl_priv *priv, struct iwl4965_lq_sta *lq_sta, struct iwl4965_scale_tbl_info *tbl, /* "search" */ - u16 rate_mask, s8 index, s8 rate) + u16 rate_mask, s8 index) { /* "active" values */ struct iwl4965_scale_tbl_info *active_tbl = @@ -1071,6 +1075,7 @@ static s32 rs_get_best_rate(struct iwl_priv *priv, s32 new_rate, high, low, start_hi; u16 high_low; + s8 rate = index; new_rate = high = low = start_hi = IWL_RATE_INVALID; @@ -1197,7 +1202,7 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, rs_set_expected_tpt_table(lq_sta, tbl); - rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index, index); + rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index); IWL_DEBUG_RATE("LQ: MIMO2 best rate %d mask %X\n", rate, rate_mask); @@ -1270,7 +1275,7 @@ static int rs_switch_to_siso(struct iwl_priv *priv, tbl->is_SGI = 0; /*11n spec: no SGI in SISO+Greenfield*/ rs_set_expected_tpt_table(lq_sta, tbl); - rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index, index); + rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index); IWL_DEBUG_RATE("LQ: get best rate %d mask %X\n", rate, rate_mask); if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) { @@ -1284,7 +1289,6 @@ static int rs_switch_to_siso(struct iwl_priv *priv, return 0; #else return -1; - #endif /*CONFIG_IWL4965_HT */ } @@ -1311,7 +1315,7 @@ static int rs_move_legacy_other(struct iwl_priv *priv, for (; ;) { switch (tbl->action) { case IWL_LEGACY_SWITCH_ANTENNA: - IWL_DEBUG_RATE("LQ Legacy toggle Antenna\n"); + IWL_DEBUG_RATE("LQ: Legacy toggle Antenna\n"); lq_sta->action_counter++; @@ -1580,9 +1584,6 @@ static void rs_stay_in_table(struct iwl4965_lq_sta *lq_sta) (unsigned long)(lq_sta->flush_timer + IWL_RATE_SCALE_FLUSH_INTVL)); - /* For now, disable the elapsed time criterion */ - flush_interval_passed = 0; - /* * Check if we should allow search for new modulation mode. * If many frames have failed or succeeded, or we've used -- cgit v1.2.3-70-g09d2 From 07bc28ed87424af13f622b7c4e2a1bff06112d94 Mon Sep 17 00:00:00 2001 From: Guy Cohen Date: Wed, 23 Apr 2008 17:15:03 -0700 Subject: iwlwifi: more RS improvements Main changes: 1. no need to re-calculate expected_tpt when only toggling antenna 2. changing the code to be more strict on input and status of variables 3. enhanced debug prints 4. move to search table only if improving tpt (don't move if SR is improved but tpt is not) Signed-off-by: Guy Cohen Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 121 +++++++++++++--------------- drivers/net/wireless/iwlwifi/iwl4965-base.c | 2 +- 2 files changed, 57 insertions(+), 66 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index 5129d57ed59..c8c54b14920 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -178,8 +178,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, struct sta_info *sta); static void rs_fill_link_cmd(const struct iwl_priv *priv, struct iwl4965_lq_sta *lq_sta, - u32 rate_n_flags, - struct iwl_link_quality_cmd *tbl); + u32 rate_n_flags); #ifdef CONFIG_MAC80211_DEBUGFS @@ -1320,7 +1319,6 @@ static int rs_move_legacy_other(struct iwl_priv *priv, lq_sta->action_counter++; /* Don't change antenna if success has been great */ - /*FIXME:RS:not sure this is really needed*/ if (window->success_ratio >= IWL_RS_GOOD_RATIO) break; @@ -1329,7 +1327,6 @@ static int rs_move_legacy_other(struct iwl_priv *priv, if (rs_toggle_antenna(valid_tx_ant, &search_tbl->current_rate, search_tbl)) { - rs_set_expected_tpt_table(lq_sta, search_tbl); lq_sta->search_better_tbl = 1; goto out; } @@ -1410,7 +1407,6 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, switch (tbl->action) { case IWL_SISO_SWITCH_ANTENNA: IWL_DEBUG_RATE("LQ: SISO toggle Antenna\n"); - /*FIXME:RS: is this really needed for SISO?*/ if (window->success_ratio >= IWL_RS_GOOD_RATIO) break; @@ -1738,27 +1734,16 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, if (!rate_scale_index_msk) rate_scale_index_msk = rate_mask; - /* If current rate is no longer supported on current association, - * or user changed preferences for rates, find a new supported rate. */ - if (index < 0 || !((1 << index) & rate_scale_index_msk)) { - index = IWL_INVALID_VALUE; - update_lq = 1; - - /* get the highest available rate */ - for (i = 0; i <= IWL_RATE_COUNT; i++) { - if ((1 << i) & rate_scale_index_msk) - index = i; - } - - if (index == IWL_INVALID_VALUE) { - IWL_WARNING("Can not find a suitable rate\n"); - return; - } + if (!((1 << index) & rate_scale_index_msk)) { + IWL_ERROR("Current Rate is not valid\n"); + return; } /* Get expected throughput table and history window for current rate */ - if (!tbl->expected_tpt) - rs_set_expected_tpt_table(lq_sta, tbl); + if (!tbl->expected_tpt) { + IWL_ERROR("tbl->expected_tpt is NULL\n"); + return; + } window = &(tbl->win[index]); @@ -1770,10 +1755,9 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, * in current association (use new rate found above). */ fail_count = window->counter - window->success_counter; - if (((fail_count < IWL_RATE_MIN_FAILURE_TH) && - (window->success_counter < IWL_RATE_MIN_SUCCESS_TH)) - || (tbl->expected_tpt == NULL)) { - IWL_DEBUG_RATE("LQ: still below TH succ %d total %d " + if ((fail_count < IWL_RATE_MIN_FAILURE_TH) && + (window->success_counter < IWL_RATE_MIN_SUCCESS_TH)) { + IWL_DEBUG_RATE("LQ: still below TH. succ=%d total=%d " "for index %d\n", window->success_counter, window->counter, index); @@ -1784,44 +1768,51 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, * or search for a new one? */ rs_stay_in_table(lq_sta); - /* Set up new rate table in uCode, if needed */ - if (update_lq) { - rate = rate_n_flags_from_tbl(tbl, index, is_green); - rs_fill_link_cmd(priv, lq_sta, rate, &lq_sta->lq); - iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); - } goto out; /* Else we have enough samples; calculate estimate of * actual average throughput */ - } else - window->average_tpt = ((window->success_ratio * + } else { + /*FIXME:RS remove this else if we don't get this error*/ + if (window->average_tpt != ((window->success_ratio * + tbl->expected_tpt[index] + 64) / 128)) { + IWL_ERROR("expected_tpt should have been calculated" + " by now\n"); + window->average_tpt = ((window->success_ratio * tbl->expected_tpt[index] + 64) / 128); + } + } /* If we are searching for better modulation mode, check success. */ if (lq_sta->search_better_tbl) { - int success_limit = IWL_RATE_SCALE_SWITCH; /* If good success, continue using the "search" mode; * no need to send new link quality command, since we're * continuing to use the setup that we've been trying. */ - if ((window->success_ratio > success_limit) || - (window->average_tpt > lq_sta->last_tpt)) { - if (!is_legacy(tbl->lq_type)) { - IWL_DEBUG_RATE("LQ: we are switching to HT" - " rate suc %d current tpt %d" - " old tpt %d\n", - window->success_ratio, - window->average_tpt, - lq_sta->last_tpt); + if (window->average_tpt > lq_sta->last_tpt) { + + IWL_DEBUG_RATE("LQ: SWITCHING TO CURRENT TABLE " + "suc=%d cur-tpt=%d old-tpt=%d\n", + window->success_ratio, + window->average_tpt, + lq_sta->last_tpt); + + if (!is_legacy(tbl->lq_type)) lq_sta->enable_counter = 1; - } + /* Swap tables; "search" becomes "active" */ lq_sta->active_tbl = active_tbl; current_tpt = window->average_tpt; /* Else poor success; go back to mode in "active" table */ } else { + + IWL_DEBUG_RATE("LQ: GOING BACK TO THE OLD TABLE " + "suc=%d cur-tpt=%d old-tpt=%d\n", + window->success_ratio, + window->average_tpt, + lq_sta->last_tpt); + /* Nullify "search" table */ tbl->lq_type = LQ_NONE; @@ -1836,7 +1827,6 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, /* Need to set up a new rate table in uCode */ update_lq = 1; - IWL_DEBUG_RATE("XXY GO BACK TO OLD TABLE\n"); } /* Either way, we've made a decision; modulation mode @@ -1952,7 +1942,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, /* Replace uCode's rate table for the destination station. */ if (update_lq) { rate = rate_n_flags_from_tbl(tbl, index, is_green); - rs_fill_link_cmd(priv, lq_sta, rate, &lq_sta->lq); + rs_fill_link_cmd(priv, lq_sta, rate); iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); } @@ -1991,8 +1981,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, IWL_DEBUG_RATE("Switch current mcs: %X index: %d\n", tbl->current_rate, index); - rs_fill_link_cmd(priv, lq_sta, tbl->current_rate, - &lq_sta->lq); + rs_fill_link_cmd(priv, lq_sta, tbl->current_rate); iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); } @@ -2109,7 +2098,7 @@ static void rs_initialize_lq(struct iwl_priv *priv, rate = rate_n_flags_from_tbl(tbl, rate_idx, use_green); tbl->current_rate = rate; rs_set_expected_tpt_table(lq_sta, tbl); - rs_fill_link_cmd(NULL, lq_sta, rate, &lq_sta->lq); + rs_fill_link_cmd(NULL, lq_sta, rate); iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); out: return; @@ -2220,7 +2209,7 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, for (i = 0; i < IWL_RATE_COUNT; i++) rs_rate_scale_clear_window(&(lq_sta->lq_info[j].win[i])); - IWL_DEBUG_RATE("rate scale global init\n"); + IWL_DEBUG_RATE("LQ: *** rate scale global init ***\n"); /* TODO: what is a good starting rate for STA? About middle? Maybe not * the lowest or the highest rate.. Could consider using RSSI from * previous packets? Need to have IEEE 802.1X auth succeed immediately @@ -2292,11 +2281,15 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, lq_sta->active_mimo3_rate &= ~((u16)0x2); lq_sta->active_mimo3_rate <<= IWL_FIRST_OFDM_RATE; - IWL_DEBUG_RATE("SISO RATE %X MIMO2 RATE %X MIMO3 RATE %X\n", + IWL_DEBUG_RATE("SISO-RATE=%X MIMO2-RATE=%X MIMO3-RATE=%X\n", lq_sta->active_siso_rate, lq_sta->active_mimo2_rate, lq_sta->active_mimo3_rate); + /* These values will be overriden later */ + lq_sta->lq.general_params.single_stream_ant_msk = ANT_A; + lq_sta->lq.general_params.dual_stream_ant_msk = ANT_AB; + /* as default allow aggregation for all tids */ lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID; #endif /*CONFIG_IWL4965_HT*/ @@ -2312,8 +2305,7 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, static void rs_fill_link_cmd(const struct iwl_priv *priv, struct iwl4965_lq_sta *lq_sta, - u32 new_rate, - struct iwl_link_quality_cmd *lq_cmd) + u32 new_rate) { struct iwl4965_scale_tbl_info tbl_type; int index = 0; @@ -2322,6 +2314,7 @@ static void rs_fill_link_cmd(const struct iwl_priv *priv, u8 ant_toggle_cnt = 0; u8 use_ht_possible = 1; u8 valid_tx_ant = 0; + struct iwl_link_quality_cmd *lq_cmd = &lq_sta->lq; /* Override starting rate (index 0) if needed for debug purposes */ rs_dbgfs_set_mcs(lq_sta, &new_rate, index); @@ -2345,13 +2338,13 @@ static void rs_fill_link_cmd(const struct iwl_priv *priv, /* Fill 1st table entry (index 0) */ lq_cmd->rs_table[index].rate_n_flags = cpu_to_le32(new_rate); - /*FIXME:RS*/ - if (is_mimo(tbl_type.lq_type) || (tbl_type.ant_type == ANT_A)) - lq_cmd->general_params.single_stream_ant_msk - = LINK_QUAL_ANT_A_MSK; - else - lq_cmd->general_params.single_stream_ant_msk - = LINK_QUAL_ANT_B_MSK; + if (num_of_ant(tbl_type.ant_type) == 1) { + lq_cmd->general_params.single_stream_ant_msk = + tbl_type.ant_type; + } else if (num_of_ant(tbl_type.ant_type) == 2) { + lq_cmd->general_params.dual_stream_ant_msk = + tbl_type.ant_type; + } /* otherwise we don't modify the existing value */ index++; repeat_rate--; @@ -2425,7 +2418,6 @@ static void rs_fill_link_cmd(const struct iwl_priv *priv, repeat_rate--; } - lq_cmd->general_params.dual_stream_ant_msk = 3; lq_cmd->agg_params.agg_dis_start_th = 3; lq_cmd->agg_params.agg_time_limit = cpu_to_le16(4000); } @@ -2512,8 +2504,7 @@ static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file, lq_sta->lq.sta_id, lq_sta->dbg_fixed_rate); if (lq_sta->dbg_fixed_rate) { - rs_fill_link_cmd(NULL, lq_sta, lq_sta->dbg_fixed_rate, - &lq_sta->lq); + rs_fill_link_cmd(NULL, lq_sta, lq_sta->dbg_fixed_rate); iwl_send_lq_cmd(lq_sta->drv, &lq_sta->lq, CMD_ASYNC); } diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 3452cc66242..89b0950f02f 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -2047,7 +2047,7 @@ static int iwl4965_tx_skb(struct iwl_priv *priv, goto drop; } - IWL_DEBUG_RATE("station Id %d\n", sta_id); + IWL_DEBUG_TX("station Id %d\n", sta_id); qc = ieee80211_get_qos_ctrl(hdr); if (qc) { -- cgit v1.2.3-70-g09d2 From 038669e49c30867956a7fa0d06c6e0e72bb38fa8 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 23 Apr 2008 17:15:04 -0700 Subject: iwlwifi: clean up register names and defines This patch cleans up and renames some of the SCD registers. It move SCD definitions into iwl-prhp.h file Signed-off-by: Emmanuel Grumbach Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-hw.h | 298 +-------------------------- drivers/net/wireless/iwlwifi/iwl-4965.c | 66 +++--- drivers/net/wireless/iwlwifi/iwl-prph.h | 310 ++++++++++++++++++++++++++--- 3 files changed, 320 insertions(+), 354 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h index 4f45093ab3b..38627040ad5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h @@ -1072,286 +1072,6 @@ enum { (IWL_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) | \ IWL_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl)) - -/********************* START TX SCHEDULER *************************************/ - -/** - * 4965 Tx Scheduler - * - * The Tx Scheduler selects the next frame to be transmitted, chosing TFDs - * (Transmit Frame Descriptors) from up to 16 circular Tx queues resident in - * host DRAM. It steers each frame's Tx command (which contains the frame - * data) into one of up to 7 prioritized Tx DMA FIFO channels within the - * device. A queue maps to only one (selectable by driver) Tx DMA channel, - * but one DMA channel may take input from several queues. - * - * Tx DMA channels have dedicated purposes. For 4965, they are used as follows: - * - * 0 -- EDCA BK (background) frames, lowest priority - * 1 -- EDCA BE (best effort) frames, normal priority - * 2 -- EDCA VI (video) frames, higher priority - * 3 -- EDCA VO (voice) and management frames, highest priority - * 4 -- Commands (e.g. RXON, etc.) - * 5 -- HCCA short frames - * 6 -- HCCA long frames - * 7 -- not used by driver (device-internal only) - * - * Driver should normally map queues 0-6 to Tx DMA/FIFO channels 0-6. - * In addition, driver can map queues 7-15 to Tx DMA/FIFO channels 0-3 to - * support 11n aggregation via EDCA DMA channels. - * - * The driver sets up each queue to work in one of two modes: - * - * 1) Scheduler-Ack, in which the scheduler automatically supports a - * block-ack (BA) window of up to 64 TFDs. In this mode, each queue - * contains TFDs for a unique combination of Recipient Address (RA) - * and Traffic Identifier (TID), that is, traffic of a given - * Quality-Of-Service (QOS) priority, destined for a single station. - * - * In scheduler-ack mode, the scheduler keeps track of the Tx status of - * each frame within the BA window, including whether it's been transmitted, - * and whether it's been acknowledged by the receiving station. The device - * automatically processes block-acks received from the receiving STA, - * and reschedules un-acked frames to be retransmitted (successful - * Tx completion may end up being out-of-order). - * - * The driver must maintain the queue's Byte Count table in host DRAM - * (struct iwl4965_sched_queue_byte_cnt_tbl) for this mode. - * This mode does not support fragmentation. - * - * 2) FIFO (a.k.a. non-Scheduler-ACK), in which each TFD is processed in order. - * The device may automatically retry Tx, but will retry only one frame - * at a time, until receiving ACK from receiving station, or reaching - * retry limit and giving up. - * - * The command queue (#4) must use this mode! - * This mode does not require use of the Byte Count table in host DRAM. - * - * Driver controls scheduler operation via 3 means: - * 1) Scheduler registers - * 2) Shared scheduler data base in internal 4956 SRAM - * 3) Shared data in host DRAM - * - * Initialization: - * - * When loading, driver should allocate memory for: - * 1) 16 TFD circular buffers, each with space for (typically) 256 TFDs. - * 2) 16 Byte Count circular buffers in 16 KBytes contiguous memory - * (1024 bytes for each queue). - * - * After receiving "Alive" response from uCode, driver must initialize - * the scheduler (especially for queue #4, the command queue, otherwise - * the driver can't issue commands!): - */ - -/** - * Max Tx window size is the max number of contiguous TFDs that the scheduler - * can keep track of at one time when creating block-ack chains of frames. - * Note that "64" matches the number of ack bits in a block-ack packet. - * Driver should use SCD_WIN_SIZE and SCD_FRAME_LIMIT values to initialize - * SCD_CONTEXT_QUEUE_OFFSET(x) values. - */ -#define SCD_WIN_SIZE 64 -#define SCD_FRAME_LIMIT 64 - -/* SCD registers are internal, must be accessed via HBUS_TARG_PRPH regs */ -#define SCD_START_OFFSET 0xa02c00 - -/* - * 4965 tells driver SRAM address for internal scheduler structs via this reg. - * Value is valid only after "Alive" response from uCode. - */ -#define SCD_SRAM_BASE_ADDR (SCD_START_OFFSET + 0x0) - -/* - * Driver may need to update queue-empty bits after changing queue's - * write and read pointers (indexes) during (re-)initialization (i.e. when - * scheduler is not tracking what's happening). - * Bit fields: - * 31-16: Write mask -- 1: update empty bit, 0: don't change empty bit - * 15-00: Empty state, one for each queue -- 1: empty, 0: non-empty - * NOTE: This register is not used by Linux driver. - */ -#define SCD_EMPTY_BITS (SCD_START_OFFSET + 0x4) - -/* - * Physical base address of array of byte count (BC) circular buffers (CBs). - * Each Tx queue has a BC CB in host DRAM to support Scheduler-ACK mode. - * This register points to BC CB for queue 0, must be on 1024-byte boundary. - * Others are spaced by 1024 bytes. - * Each BC CB is 2 bytes * (256 + 64) = 740 bytes, followed by 384 bytes pad. - * (Index into a queue's BC CB) = (index into queue's TFD CB) = (SSN & 0xff). - * Bit fields: - * 25-00: Byte Count CB physical address [35:10], must be 1024-byte aligned. - */ -#define SCD_DRAM_BASE_ADDR (SCD_START_OFFSET + 0x10) - -/* - * Enables any/all Tx DMA/FIFO channels. - * Scheduler generates requests for only the active channels. - * Set this to 0xff to enable all 8 channels (normal usage). - * Bit fields: - * 7- 0: Enable (1), disable (0), one bit for each channel 0-7 - */ -#define SCD_TXFACT (SCD_START_OFFSET + 0x1c) - -/* Mask to enable contiguous Tx DMA/FIFO channels between "lo" and "hi". */ -#define SCD_TXFACT_REG_TXFIFO_MASK(lo, hi) \ - ((1 << (hi)) | ((1 << (hi)) - (1 << (lo)))) - -/* - * Queue (x) Write Pointers (indexes, really!), one for each Tx queue. - * Initialized and updated by driver as new TFDs are added to queue. - * NOTE: If using Block Ack, index must correspond to frame's - * Start Sequence Number; index = (SSN & 0xff) - * NOTE: Alternative to HBUS_TARG_WRPTR, which is what Linux driver uses? - */ -#define SCD_QUEUE_WRPTR(x) (SCD_START_OFFSET + 0x24 + (x) * 4) - -/* - * Queue (x) Read Pointers (indexes, really!), one for each Tx queue. - * For FIFO mode, index indicates next frame to transmit. - * For Scheduler-ACK mode, index indicates first frame in Tx window. - * Initialized by driver, updated by scheduler. - */ -#define SCD_QUEUE_RDPTR(x) (SCD_START_OFFSET + 0x64 + (x) * 4) - -/* - * Select which queues work in chain mode (1) vs. not (0). - * Use chain mode to build chains of aggregated frames. - * Bit fields: - * 31-16: Reserved - * 15-00: Mode, one bit for each queue -- 1: Chain mode, 0: one-at-a-time - * NOTE: If driver sets up queue for chain mode, it should be also set up - * Scheduler-ACK mode as well, via SCD_QUEUE_STATUS_BITS(x). - */ -#define SCD_QUEUECHAIN_SEL (SCD_START_OFFSET + 0xd0) - -/* - * Select which queues interrupt driver when scheduler increments - * a queue's read pointer (index). - * Bit fields: - * 31-16: Reserved - * 15-00: Interrupt enable, one bit for each queue -- 1: enabled, 0: disabled - * NOTE: This functionality is apparently a no-op; driver relies on interrupts - * from Rx queue to read Tx command responses and update Tx queues. - */ -#define SCD_INTERRUPT_MASK (SCD_START_OFFSET + 0xe4) - -/* - * Queue search status registers. One for each queue. - * Sets up queue mode and assigns queue to Tx DMA channel. - * Bit fields: - * 19-10: Write mask/enable bits for bits 0-9 - * 9: Driver should init to "0" - * 8: Scheduler-ACK mode (1), non-Scheduler-ACK (i.e. FIFO) mode (0). - * Driver should init to "1" for aggregation mode, or "0" otherwise. - * 7-6: Driver should init to "0" - * 5: Window Size Left; indicates whether scheduler can request - * another TFD, based on window size, etc. Driver should init - * this bit to "1" for aggregation mode, or "0" for non-agg. - * 4-1: Tx FIFO to use (range 0-7). - * 0: Queue is active (1), not active (0). - * Other bits should be written as "0" - * - * NOTE: If enabling Scheduler-ACK mode, chain mode should also be enabled - * via SCD_QUEUECHAIN_SEL. - */ -#define SCD_QUEUE_STATUS_BITS(x) (SCD_START_OFFSET + 0x104 + (x) * 4) - -/* Bit field positions */ -#define SCD_QUEUE_STTS_REG_POS_ACTIVE (0) -#define SCD_QUEUE_STTS_REG_POS_TXF (1) -#define SCD_QUEUE_STTS_REG_POS_WSL (5) -#define SCD_QUEUE_STTS_REG_POS_SCD_ACK (8) - -/* Write masks */ -#define SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN (10) -#define SCD_QUEUE_STTS_REG_MSK (0x0007FC00) - -/** - * 4965 internal SRAM structures for scheduler, shared with driver ... - * - * Driver should clear and initialize the following areas after receiving - * "Alive" response from 4965 uCode, i.e. after initial - * uCode load, or after a uCode load done for error recovery: - * - * SCD_CONTEXT_DATA_OFFSET (size 128 bytes) - * SCD_TX_STTS_BITMAP_OFFSET (size 256 bytes) - * SCD_TRANSLATE_TBL_OFFSET (size 32 bytes) - * - * Driver accesses SRAM via HBUS_TARG_MEM_* registers. - * Driver reads base address of this scheduler area from SCD_SRAM_BASE_ADDR. - * All OFFSET values must be added to this base address. - */ - -/* - * Queue context. One 8-byte entry for each of 16 queues. - * - * Driver should clear this entire area (size 0x80) to 0 after receiving - * "Alive" notification from uCode. Additionally, driver should init - * each queue's entry as follows: - * - * LS Dword bit fields: - * 0-06: Max Tx window size for Scheduler-ACK. Driver should init to 64. - * - * MS Dword bit fields: - * 16-22: Frame limit. Driver should init to 10 (0xa). - * - * Driver should init all other bits to 0. - * - * Init must be done after driver receives "Alive" response from 4965 uCode, - * and when setting up queue for aggregation. - */ -#define SCD_CONTEXT_DATA_OFFSET 0x380 -#define SCD_CONTEXT_QUEUE_OFFSET(x) (SCD_CONTEXT_DATA_OFFSET + ((x) * 8)) - -#define SCD_QUEUE_CTX_REG1_WIN_SIZE_POS (0) -#define SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK (0x0000007F) -#define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS (16) -#define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK (0x007F0000) - -/* - * Tx Status Bitmap - * - * Driver should clear this entire area (size 0x100) to 0 after receiving - * "Alive" notification from uCode. Area is used only by device itself; - * no other support (besides clearing) is required from driver. - */ -#define SCD_TX_STTS_BITMAP_OFFSET 0x400 - -/* - * RAxTID to queue translation mapping. - * - * When queue is in Scheduler-ACK mode, frames placed in a that queue must be - * for only one combination of receiver address (RA) and traffic ID (TID), i.e. - * one QOS priority level destined for one station (for this wireless link, - * not final destination). The SCD_TRANSLATE_TABLE area provides 16 16-bit - * mappings, one for each of the 16 queues. If queue is not in Scheduler-ACK - * mode, the device ignores the mapping value. - * - * Bit fields, for each 16-bit map: - * 15-9: Reserved, set to 0 - * 8-4: Index into device's station table for recipient station - * 3-0: Traffic ID (tid), range 0-15 - * - * Driver should clear this entire area (size 32 bytes) to 0 after receiving - * "Alive" notification from uCode. To update a 16-bit map value, driver - * must read a dword-aligned value from device SRAM, replace the 16-bit map - * value of interest, and write the dword value back into device SRAM. - */ -#define SCD_TRANSLATE_TBL_OFFSET 0x500 - -/* Find translation table dword to read/write for given queue */ -#define SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \ - ((SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffffffc) - -#define SCD_TXFIFO_POS_TID (0) -#define SCD_TXFIFO_POS_RA (4) -#define SCD_QUEUE_RA_TID_MAP_RATID_MSK (0x01FF) - -/*********************** END TX SCHEDULER *************************************/ - static inline u8 iwl4965_hw_get_rate(__le32 rate_n_flags) { return le32_to_cpu(rate_n_flags) & 0xFF; @@ -1386,11 +1106,11 @@ static inline __le32 iwl4965_hw_set_rate_n_flags(u8 rate, u16 flags) * up to 7 DMA channels (FIFOs). Each Tx queue is supported by a circular array * in DRAM containing 256 Transmit Frame Descriptors (TFDs). */ -#define IWL4965_MAX_WIN_SIZE 64 -#define IWL4965_QUEUE_SIZE 256 -#define IWL4965_NUM_FIFOS 7 -#define IWL4965_MAX_NUM_QUEUES 16 - +#define IWL49_MAX_WIN_SIZE 64 +#define IWL49_QUEUE_SIZE 256 +#define IWL49_NUM_FIFOS 7 +#define IWL49_CMD_FIFO_NUM 4 +#define IWL49_NUM_QUEUES 16 /** * struct iwl4965_tfd_frame_data @@ -1521,10 +1241,10 @@ struct iwl4965_queue_byte_cnt_entry { * 4965 assumes tables are separated by 1024 bytes. */ struct iwl4965_sched_queue_byte_cnt_tbl { - struct iwl4965_queue_byte_cnt_entry tfd_offset[IWL4965_QUEUE_SIZE + - IWL4965_MAX_WIN_SIZE]; + struct iwl4965_queue_byte_cnt_entry tfd_offset[IWL49_QUEUE_SIZE + + IWL49_MAX_WIN_SIZE]; u8 dont_care[1024 - - (IWL4965_QUEUE_SIZE + IWL4965_MAX_WIN_SIZE) * + (IWL49_QUEUE_SIZE + IWL49_MAX_WIN_SIZE) * sizeof(__le16)]; } __attribute__ ((packed)); @@ -1554,7 +1274,7 @@ struct iwl4965_sched_queue_byte_cnt_tbl { */ struct iwl4965_shared { struct iwl4965_sched_queue_byte_cnt_tbl - queues_byte_cnt_tbls[IWL4965_MAX_NUM_QUEUES]; + queues_byte_cnt_tbls[IWL49_NUM_QUEUES]; __le32 rb_closed; /* __le32 rb_closed_stts_rb_num:12; */ diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index f5796b78f2d..2b21edb757b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -47,7 +47,7 @@ /* module parameters */ static struct iwl_mod_params iwl4965_mod_params = { - .num_of_queues = IWL4965_MAX_NUM_QUEUES, + .num_of_queues = IWL49_NUM_QUEUES, .enable_qos = 1, .amsdu_size_8K = 1, /* the rest are 0 by default */ @@ -1164,11 +1164,11 @@ static void iwl4965_tx_queue_set_status(struct iwl_priv *priv, /* Set up and activate */ iwl_write_prph(priv, IWL49_SCD_QUEUE_STATUS_BITS(txq_id), - (active << SCD_QUEUE_STTS_REG_POS_ACTIVE) | - (tx_fifo_id << SCD_QUEUE_STTS_REG_POS_TXF) | - (scd_retry << SCD_QUEUE_STTS_REG_POS_WSL) | - (scd_retry << SCD_QUEUE_STTS_REG_POS_SCD_ACK) | - SCD_QUEUE_STTS_REG_MSK); + (active << IWL49_SCD_QUEUE_STTS_REG_POS_ACTIVE) | + (tx_fifo_id << IWL49_SCD_QUEUE_STTS_REG_POS_TXF) | + (scd_retry << IWL49_SCD_QUEUE_STTS_REG_POS_WSL) | + (scd_retry << IWL49_SCD_QUEUE_STTS_REG_POS_SCD_ACK) | + IWL49_SCD_QUEUE_STTS_REG_MSK); txq->sched_retry = scd_retry; @@ -1182,7 +1182,7 @@ static const u16 default_queue_to_tx_fifo[] = { IWL_TX_FIFO_AC2, IWL_TX_FIFO_AC1, IWL_TX_FIFO_AC0, - IWL_CMD_FIFO_NUM, + IWL49_CMD_FIFO_NUM, IWL_TX_FIFO_HCCA_1, IWL_TX_FIFO_HCCA_2 }; @@ -1223,10 +1223,10 @@ int iwl4965_alive_notify(struct iwl_priv *priv) /* Clear 4965's internal Tx Scheduler data base */ priv->scd_base_addr = iwl_read_prph(priv, IWL49_SCD_SRAM_BASE_ADDR); - a = priv->scd_base_addr + SCD_CONTEXT_DATA_OFFSET; - for (; a < priv->scd_base_addr + SCD_TX_STTS_BITMAP_OFFSET; a += 4) + a = priv->scd_base_addr + IWL49_SCD_CONTEXT_DATA_OFFSET; + for (; a < priv->scd_base_addr + IWL49_SCD_TX_STTS_BITMAP_OFFSET; a += 4) iwl_write_targ_mem(priv, a, 0); - for (; a < priv->scd_base_addr + SCD_TRANSLATE_TBL_OFFSET; a += 4) + for (; a < priv->scd_base_addr + IWL49_SCD_TRANSLATE_TBL_OFFSET; a += 4) iwl_write_targ_mem(priv, a, 0); for (; a < sizeof(u16) * priv->hw_params.max_txq_num; a += 4) iwl_write_targ_mem(priv, a, 0); @@ -1248,18 +1248,18 @@ int iwl4965_alive_notify(struct iwl_priv *priv) /* Max Tx Window size for Scheduler-ACK mode */ iwl_write_targ_mem(priv, priv->scd_base_addr + - SCD_CONTEXT_QUEUE_OFFSET(i), - (SCD_WIN_SIZE << - SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) & - SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK); + IWL49_SCD_CONTEXT_QUEUE_OFFSET(i), + (SCD_WIN_SIZE << + IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) & + IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK); /* Frame limit */ iwl_write_targ_mem(priv, priv->scd_base_addr + - SCD_CONTEXT_QUEUE_OFFSET(i) + - sizeof(u32), - (SCD_FRAME_LIMIT << - SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) & - SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK); + IWL49_SCD_CONTEXT_QUEUE_OFFSET(i) + + sizeof(u32), + (SCD_FRAME_LIMIT << + IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) & + IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK); } iwl_write_prph(priv, IWL49_SCD_INTERRUPT_MASK, @@ -1320,10 +1320,10 @@ static struct iwl_sensitivity_ranges iwl4965_sensitivity = { int iwl4965_hw_set_hw_params(struct iwl_priv *priv) { - if ((priv->cfg->mod_params->num_of_queues > IWL4965_MAX_NUM_QUEUES) || + if ((priv->cfg->mod_params->num_of_queues > IWL49_NUM_QUEUES) || (priv->cfg->mod_params->num_of_queues < IWL_MIN_NUM_QUEUES)) { IWL_ERROR("invalid queues_num, should be between %d and %d\n", - IWL_MIN_NUM_QUEUES, IWL4965_MAX_NUM_QUEUES); + IWL_MIN_NUM_QUEUES, IWL49_NUM_QUEUES); return -EINVAL; } @@ -2520,9 +2520,9 @@ static void iwl4965_txq_update_byte_cnt_tbl(struct iwl_priv *priv, tfd_offset[txq->q.write_ptr], byte_cnt, len); /* If within first 64 entries, duplicate at end */ - if (txq->q.write_ptr < IWL4965_MAX_WIN_SIZE) + if (txq->q.write_ptr < IWL49_MAX_WIN_SIZE) IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. - tfd_offset[IWL4965_QUEUE_SIZE + txq->q.write_ptr], + tfd_offset[IWL49_QUEUE_SIZE + txq->q.write_ptr], byte_cnt, len); } @@ -3646,8 +3646,8 @@ static void iwl4965_tx_queue_stop_scheduler(struct iwl_priv *priv, * the SCD_ACT_EN bit is the write-enable mask for the ACTIVE bit. */ iwl_write_prph(priv, IWL49_SCD_QUEUE_STATUS_BITS(txq_id), - (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)| - (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN)); + (0 << IWL49_SCD_QUEUE_STTS_REG_POS_ACTIVE)| + (1 << IWL49_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN)); } /** @@ -3812,10 +3812,10 @@ static int iwl4965_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid, u32 tbl_dw; u16 scd_q2ratid; - scd_q2ratid = ra_tid & SCD_QUEUE_RA_TID_MAP_RATID_MSK; + scd_q2ratid = ra_tid & IWL49_SCD_QUEUE_RA_TID_MAP_RATID_MSK; tbl_dw_addr = priv->scd_base_addr + - SCD_TRANSLATE_TBL_OFFSET_QUEUE(txq_id); + IWL49_SCD_TRANSLATE_TBL_OFFSET_QUEUE(txq_id); tbl_dw = iwl_read_targ_mem(priv, tbl_dw_addr); @@ -3877,14 +3877,14 @@ static int iwl4965_tx_queue_agg_enable(struct iwl_priv *priv, int txq_id, /* Set up Tx window size and frame limit for this queue */ iwl_write_targ_mem(priv, - priv->scd_base_addr + SCD_CONTEXT_QUEUE_OFFSET(txq_id), - (SCD_WIN_SIZE << SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) & - SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK); + priv->scd_base_addr + IWL49_SCD_CONTEXT_QUEUE_OFFSET(txq_id), + (SCD_WIN_SIZE << IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) & + IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK); iwl_write_targ_mem(priv, priv->scd_base_addr + - SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32), - (SCD_FRAME_LIMIT << SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) - & SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK); + IWL49_SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32), + (SCD_FRAME_LIMIT << IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) + & IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK); iwl_set_bits_prph(priv, IWL49_SCD_INTERRUPT_MASK, (1 << txq_id)); diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index c9cf8eef1a9..acac629386e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -239,40 +239,284 @@ #define ALM_SCD_SBYP_MODE_1_REG (ALM_SCD_BASE + 0x02C) #define ALM_SCD_SBYP_MODE_2_REG (ALM_SCD_BASE + 0x030) +/** + * Tx Scheduler + * + * The Tx Scheduler selects the next frame to be transmitted, chosing TFDs + * (Transmit Frame Descriptors) from up to 16 circular Tx queues resident in + * host DRAM. It steers each frame's Tx command (which contains the frame + * data) into one of up to 7 prioritized Tx DMA FIFO channels within the + * device. A queue maps to only one (selectable by driver) Tx DMA channel, + * but one DMA channel may take input from several queues. + * + * Tx DMA channels have dedicated purposes. For 4965, they are used as follows: + * + * 0 -- EDCA BK (background) frames, lowest priority + * 1 -- EDCA BE (best effort) frames, normal priority + * 2 -- EDCA VI (video) frames, higher priority + * 3 -- EDCA VO (voice) and management frames, highest priority + * 4 -- Commands (e.g. RXON, etc.) + * 5 -- HCCA short frames + * 6 -- HCCA long frames + * 7 -- not used by driver (device-internal only) + * + * Driver should normally map queues 0-6 to Tx DMA/FIFO channels 0-6. + * In addition, driver can map queues 7-15 to Tx DMA/FIFO channels 0-3 to + * support 11n aggregation via EDCA DMA channels. + * + * The driver sets up each queue to work in one of two modes: + * + * 1) Scheduler-Ack, in which the scheduler automatically supports a + * block-ack (BA) window of up to 64 TFDs. In this mode, each queue + * contains TFDs for a unique combination of Recipient Address (RA) + * and Traffic Identifier (TID), that is, traffic of a given + * Quality-Of-Service (QOS) priority, destined for a single station. + * + * In scheduler-ack mode, the scheduler keeps track of the Tx status of + * each frame within the BA window, including whether it's been transmitted, + * and whether it's been acknowledged by the receiving station. The device + * automatically processes block-acks received from the receiving STA, + * and reschedules un-acked frames to be retransmitted (successful + * Tx completion may end up being out-of-order). + * + * The driver must maintain the queue's Byte Count table in host DRAM + * (struct iwl4965_sched_queue_byte_cnt_tbl) for this mode. + * This mode does not support fragmentation. + * + * 2) FIFO (a.k.a. non-Scheduler-ACK), in which each TFD is processed in order. + * The device may automatically retry Tx, but will retry only one frame + * at a time, until receiving ACK from receiving station, or reaching + * retry limit and giving up. + * + * The command queue (#4) must use this mode! + * This mode does not require use of the Byte Count table in host DRAM. + * + * Driver controls scheduler operation via 3 means: + * 1) Scheduler registers + * 2) Shared scheduler data base in internal 4956 SRAM + * 3) Shared data in host DRAM + * + * Initialization: + * + * When loading, driver should allocate memory for: + * 1) 16 TFD circular buffers, each with space for (typically) 256 TFDs. + * 2) 16 Byte Count circular buffers in 16 KBytes contiguous memory + * (1024 bytes for each queue). + * + * After receiving "Alive" response from uCode, driver must initialize + * the scheduler (especially for queue #4, the command queue, otherwise + * the driver can't issue commands!): + */ + +/** + * Max Tx window size is the max number of contiguous TFDs that the scheduler + * can keep track of at one time when creating block-ack chains of frames. + * Note that "64" matches the number of ack bits in a block-ack packet. + * Driver should use SCD_WIN_SIZE and SCD_FRAME_LIMIT values to initialize + * IWL49_SCD_CONTEXT_QUEUE_OFFSET(x) values. + */ +#define SCD_WIN_SIZE 64 +#define SCD_FRAME_LIMIT 64 + +/* SCD registers are internal, must be accessed via HBUS_TARG_PRPH regs */ +#define IWL49_SCD_START_OFFSET 0xa02c00 + +/* + * 4965 tells driver SRAM address for internal scheduler structs via this reg. + * Value is valid only after "Alive" response from uCode. + */ +#define IWL49_SCD_SRAM_BASE_ADDR (IWL49_SCD_START_OFFSET + 0x0) + +/* + * Driver may need to update queue-empty bits after changing queue's + * write and read pointers (indexes) during (re-)initialization (i.e. when + * scheduler is not tracking what's happening). + * Bit fields: + * 31-16: Write mask -- 1: update empty bit, 0: don't change empty bit + * 15-00: Empty state, one for each queue -- 1: empty, 0: non-empty + * NOTE: This register is not used by Linux driver. + */ +#define IWL49_SCD_EMPTY_BITS (IWL49_SCD_START_OFFSET + 0x4) + +/* + * Physical base address of array of byte count (BC) circular buffers (CBs). + * Each Tx queue has a BC CB in host DRAM to support Scheduler-ACK mode. + * This register points to BC CB for queue 0, must be on 1024-byte boundary. + * Others are spaced by 1024 bytes. + * Each BC CB is 2 bytes * (256 + 64) = 740 bytes, followed by 384 bytes pad. + * (Index into a queue's BC CB) = (index into queue's TFD CB) = (SSN & 0xff). + * Bit fields: + * 25-00: Byte Count CB physical address [35:10], must be 1024-byte aligned. + */ +#define IWL49_SCD_DRAM_BASE_ADDR (IWL49_SCD_START_OFFSET + 0x10) + +/* + * Enables any/all Tx DMA/FIFO channels. + * Scheduler generates requests for only the active channels. + * Set this to 0xff to enable all 8 channels (normal usage). + * Bit fields: + * 7- 0: Enable (1), disable (0), one bit for each channel 0-7 + */ +#define IWL49_SCD_TXFACT (IWL49_SCD_START_OFFSET + 0x1c) + +/* Mask to enable contiguous Tx DMA/FIFO channels between "lo" and "hi". */ +#define SCD_TXFACT_REG_TXFIFO_MASK(lo, hi) \ + ((1 << (hi)) | ((1 << (hi)) - (1 << (lo)))) + +/* + * Queue (x) Write Pointers (indexes, really!), one for each Tx queue. + * Initialized and updated by driver as new TFDs are added to queue. + * NOTE: If using Block Ack, index must correspond to frame's + * Start Sequence Number; index = (SSN & 0xff) + * NOTE: Alternative to HBUS_TARG_WRPTR, which is what Linux driver uses? + */ +#define IWL49_SCD_QUEUE_WRPTR(x) (IWL49_SCD_START_OFFSET + 0x24 + (x) * 4) + +/* + * Queue (x) Read Pointers (indexes, really!), one for each Tx queue. + * For FIFO mode, index indicates next frame to transmit. + * For Scheduler-ACK mode, index indicates first frame in Tx window. + * Initialized by driver, updated by scheduler. + */ +#define IWL49_SCD_QUEUE_RDPTR(x) (IWL49_SCD_START_OFFSET + 0x64 + (x) * 4) + +/* + * Select which queues work in chain mode (1) vs. not (0). + * Use chain mode to build chains of aggregated frames. + * Bit fields: + * 31-16: Reserved + * 15-00: Mode, one bit for each queue -- 1: Chain mode, 0: one-at-a-time + * NOTE: If driver sets up queue for chain mode, it should be also set up + * Scheduler-ACK mode as well, via SCD_QUEUE_STATUS_BITS(x). + */ +#define IWL49_SCD_QUEUECHAIN_SEL (IWL49_SCD_START_OFFSET + 0xd0) + +/* + * Select which queues interrupt driver when scheduler increments + * a queue's read pointer (index). + * Bit fields: + * 31-16: Reserved + * 15-00: Interrupt enable, one bit for each queue -- 1: enabled, 0: disabled + * NOTE: This functionality is apparently a no-op; driver relies on interrupts + * from Rx queue to read Tx command responses and update Tx queues. + */ +#define IWL49_SCD_INTERRUPT_MASK (IWL49_SCD_START_OFFSET + 0xe4) + +/* + * Queue search status registers. One for each queue. + * Sets up queue mode and assigns queue to Tx DMA channel. + * Bit fields: + * 19-10: Write mask/enable bits for bits 0-9 + * 9: Driver should init to "0" + * 8: Scheduler-ACK mode (1), non-Scheduler-ACK (i.e. FIFO) mode (0). + * Driver should init to "1" for aggregation mode, or "0" otherwise. + * 7-6: Driver should init to "0" + * 5: Window Size Left; indicates whether scheduler can request + * another TFD, based on window size, etc. Driver should init + * this bit to "1" for aggregation mode, or "0" for non-agg. + * 4-1: Tx FIFO to use (range 0-7). + * 0: Queue is active (1), not active (0). + * Other bits should be written as "0" + * + * NOTE: If enabling Scheduler-ACK mode, chain mode should also be enabled + * via SCD_QUEUECHAIN_SEL. + */ +#define IWL49_SCD_QUEUE_STATUS_BITS(x)\ + (IWL49_SCD_START_OFFSET + 0x104 + (x) * 4) + +/* Bit field positions */ +#define IWL49_SCD_QUEUE_STTS_REG_POS_ACTIVE (0) +#define IWL49_SCD_QUEUE_STTS_REG_POS_TXF (1) +#define IWL49_SCD_QUEUE_STTS_REG_POS_WSL (5) +#define IWL49_SCD_QUEUE_STTS_REG_POS_SCD_ACK (8) + +/* Write masks */ +#define IWL49_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN (10) +#define IWL49_SCD_QUEUE_STTS_REG_MSK (0x0007FC00) + +/** + * 4965 internal SRAM structures for scheduler, shared with driver ... + * + * Driver should clear and initialize the following areas after receiving + * "Alive" response from 4965 uCode, i.e. after initial + * uCode load, or after a uCode load done for error recovery: + * + * SCD_CONTEXT_DATA_OFFSET (size 128 bytes) + * SCD_TX_STTS_BITMAP_OFFSET (size 256 bytes) + * SCD_TRANSLATE_TBL_OFFSET (size 32 bytes) + * + * Driver accesses SRAM via HBUS_TARG_MEM_* registers. + * Driver reads base address of this scheduler area from SCD_SRAM_BASE_ADDR. + * All OFFSET values must be added to this base address. + */ + +/* + * Queue context. One 8-byte entry for each of 16 queues. + * + * Driver should clear this entire area (size 0x80) to 0 after receiving + * "Alive" notification from uCode. Additionally, driver should init + * each queue's entry as follows: + * + * LS Dword bit fields: + * 0-06: Max Tx window size for Scheduler-ACK. Driver should init to 64. + * + * MS Dword bit fields: + * 16-22: Frame limit. Driver should init to 10 (0xa). + * + * Driver should init all other bits to 0. + * + * Init must be done after driver receives "Alive" response from 4965 uCode, + * and when setting up queue for aggregation. + */ +#define IWL49_SCD_CONTEXT_DATA_OFFSET 0x380 +#define IWL49_SCD_CONTEXT_QUEUE_OFFSET(x) \ + (IWL49_SCD_CONTEXT_DATA_OFFSET + ((x) * 8)) + +#define IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_POS (0) +#define IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK (0x0000007F) +#define IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS (16) +#define IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK (0x007F0000) + /* - * 4965 Tx Scheduler registers. - * Details are documented in iwl-4965-hw.h + * Tx Status Bitmap + * + * Driver should clear this entire area (size 0x100) to 0 after receiving + * "Alive" notification from uCode. Area is used only by device itself; + * no other support (besides clearing) is required from driver. */ -#define IWL49_SCD_BASE (PRPH_BASE + 0xa02c00) - -#define IWL49_SCD_SRAM_BASE_ADDR (IWL49_SCD_BASE + 0x0) -#define IWL49_SCD_EMPTY_BITS (IWL49_SCD_BASE + 0x4) -#define IWL49_SCD_DRAM_BASE_ADDR (IWL49_SCD_BASE + 0x10) -#define IWL49_SCD_AIT (IWL49_SCD_BASE + 0x18) -#define IWL49_SCD_TXFACT (IWL49_SCD_BASE + 0x1c) -#define IWL49_SCD_QUEUE_WRPTR(x) (IWL49_SCD_BASE + 0x24 + (x) * 4) -#define IWL49_SCD_QUEUE_RDPTR(x) (IWL49_SCD_BASE + 0x64 + (x) * 4) -#define IWL49_SCD_SETQUEUENUM (IWL49_SCD_BASE + 0xa4) -#define IWL49_SCD_SET_TXSTAT_TXED (IWL49_SCD_BASE + 0xa8) -#define IWL49_SCD_SET_TXSTAT_DONE (IWL49_SCD_BASE + 0xac) -#define IWL49_SCD_SET_TXSTAT_NOT_SCHD (IWL49_SCD_BASE + 0xb0) -#define IWL49_SCD_DECREASE_CREDIT (IWL49_SCD_BASE + 0xb4) -#define IWL49_SCD_DECREASE_SCREDIT (IWL49_SCD_BASE + 0xb8) -#define IWL49_SCD_LOAD_CREDIT (IWL49_SCD_BASE + 0xbc) -#define IWL49_SCD_LOAD_SCREDIT (IWL49_SCD_BASE + 0xc0) -#define IWL49_SCD_BAR (IWL49_SCD_BASE + 0xc4) -#define IWL49_SCD_BAR_DW0 (IWL49_SCD_BASE + 0xc8) -#define IWL49_SCD_BAR_DW1 (IWL49_SCD_BASE + 0xcc) -#define IWL49_SCD_QUEUECHAIN_SEL (IWL49_SCD_BASE + 0xd0) -#define IWL49_SCD_QUERY_REQ (IWL49_SCD_BASE + 0xd8) -#define IWL49_SCD_QUERY_RES (IWL49_SCD_BASE + 0xdc) -#define IWL49_SCD_PENDING_FRAMES (IWL49_SCD_BASE + 0xe0) -#define IWL49_SCD_INTERRUPT_MASK (IWL49_SCD_BASE + 0xe4) -#define IWL49_SCD_INTERRUPT_THRESHOLD (IWL49_SCD_BASE + 0xe8) -#define IWL49_SCD_QUERY_MIN_FRAME_SIZE (IWL49_SCD_BASE + 0x100) -#define IWL49_SCD_QUEUE_STATUS_BITS(x) (IWL49_SCD_BASE + 0x104 + (x) * 4) - -/* SP SCD */ +#define IWL49_SCD_TX_STTS_BITMAP_OFFSET 0x400 + +/* + * RAxTID to queue translation mapping. + * + * When queue is in Scheduler-ACK mode, frames placed in a that queue must be + * for only one combination of receiver address (RA) and traffic ID (TID), i.e. + * one QOS priority level destined for one station (for this wireless link, + * not final destination). The SCD_TRANSLATE_TABLE area provides 16 16-bit + * mappings, one for each of the 16 queues. If queue is not in Scheduler-ACK + * mode, the device ignores the mapping value. + * + * Bit fields, for each 16-bit map: + * 15-9: Reserved, set to 0 + * 8-4: Index into device's station table for recipient station + * 3-0: Traffic ID (tid), range 0-15 + * + * Driver should clear this entire area (size 32 bytes) to 0 after receiving + * "Alive" notification from uCode. To update a 16-bit map value, driver + * must read a dword-aligned value from device SRAM, replace the 16-bit map + * value of interest, and write the dword value back into device SRAM. + */ +#define IWL49_SCD_TRANSLATE_TBL_OFFSET 0x500 + +/* Find translation table dword to read/write for given queue */ +#define IWL49_SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \ + ((IWL49_SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffffffc) + +#define IWL49_SCD_TXFIFO_POS_TID (0) +#define IWL49_SCD_TXFIFO_POS_RA (4) +#define IWL49_SCD_QUEUE_RA_TID_MAP_RATID_MSK (0x01FF) + +/* 5000 SCD */ #define IWL50_SCD_BASE (PRPH_BASE + 0xa02c00) #define IWL50_SCD_SRAM_BASE_ADDR (IWL50_SCD_BASE + 0x0) @@ -287,4 +531,6 @@ #define IWL50_SCD_INTERRUPT_MASK (IWL50_SCD_BASE + 0x108) #define IWL50_SCD_QUEUE_STATUS_BITS(x) (IWL50_SCD_BASE + 0x10c + (x) * 4) +/*********************** END TX SCHEDULER *************************************/ + #endif /* __iwl_prph_h__ */ -- cgit v1.2.3-70-g09d2 From c7de35cd1c8b135398899f42475fa8e9d672d46e Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Wed, 23 Apr 2008 17:15:05 -0700 Subject: iwlwifi: unify init driver flow This patch does the following: 1 - moving init_drv from handler to regular function call 2 - move the init driver flow from iwl4965 to iwlcore, thus unify it to all iwl family as a single flow 3 - move some general purpose functions from iwl4965 to iwlcore Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 245 +---------------- drivers/net/wireless/iwlwifi/iwl-4965.h | 1 - drivers/net/wireless/iwlwifi/iwl-core.c | 412 +++++++++++++++++++++++++++- drivers/net/wireless/iwlwifi/iwl-core.h | 9 +- drivers/net/wireless/iwlwifi/iwl4965-base.c | 175 +----------- 5 files changed, 421 insertions(+), 421 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 2b21edb757b..93f4cdbae0f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -55,44 +55,6 @@ static struct iwl_mod_params iwl4965_mod_params = { static void iwl4965_hw_card_show_info(struct iwl_priv *priv); -#define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np) \ - [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \ - IWL_RATE_SISO_##s##M_PLCP, \ - IWL_RATE_MIMO2_##s##M_PLCP,\ - IWL_RATE_MIMO3_##s##M_PLCP,\ - IWL_RATE_##r##M_IEEE, \ - IWL_RATE_##ip##M_INDEX, \ - IWL_RATE_##in##M_INDEX, \ - IWL_RATE_##rp##M_INDEX, \ - IWL_RATE_##rn##M_INDEX, \ - IWL_RATE_##pp##M_INDEX, \ - IWL_RATE_##np##M_INDEX } - -/* - * Parameter order: - * rate, ht rate, prev rate, next rate, prev tgg rate, next tgg rate - * - * If there isn't a valid next or previous rate then INV is used which - * maps to IWL_RATE_INVALID - * - */ -const struct iwl4965_rate_info iwl4965_rates[IWL_RATE_COUNT] = { - IWL_DECLARE_RATE_INFO(1, INV, INV, 2, INV, 2, INV, 2), /* 1mbps */ - IWL_DECLARE_RATE_INFO(2, INV, 1, 5, 1, 5, 1, 5), /* 2mbps */ - IWL_DECLARE_RATE_INFO(5, INV, 2, 6, 2, 11, 2, 11), /*5.5mbps */ - IWL_DECLARE_RATE_INFO(11, INV, 9, 12, 9, 12, 5, 18), /* 11mbps */ - IWL_DECLARE_RATE_INFO(6, 6, 5, 9, 5, 11, 5, 11), /* 6mbps */ - IWL_DECLARE_RATE_INFO(9, 6, 6, 11, 6, 11, 5, 11), /* 9mbps */ - IWL_DECLARE_RATE_INFO(12, 12, 11, 18, 11, 18, 11, 18), /* 12mbps */ - IWL_DECLARE_RATE_INFO(18, 18, 12, 24, 12, 24, 11, 24), /* 18mbps */ - IWL_DECLARE_RATE_INFO(24, 24, 18, 36, 18, 36, 18, 36), /* 24mbps */ - IWL_DECLARE_RATE_INFO(36, 36, 24, 48, 24, 48, 24, 48), /* 36mbps */ - IWL_DECLARE_RATE_INFO(48, 48, 36, 54, 36, 54, 36, 54), /* 48mbps */ - IWL_DECLARE_RATE_INFO(54, 54, 48, INV, 48, INV, 48, INV),/* 54mbps */ - IWL_DECLARE_RATE_INFO(60, 60, 48, INV, 48, INV, 48, INV),/* 60mbps */ - /* FIXME:RS: ^^ should be INV (legacy) */ -}; - #ifdef CONFIG_IWL4965_HT static const u16 default_tid_to_tx_fifo[] = { @@ -262,108 +224,12 @@ static int iwl4965_load_bsm(struct iwl_priv *priv) return 0; } -static int iwl4965_init_drv(struct iwl_priv *priv) -{ - int ret; - int i; - - priv->retry_rate = 1; - priv->ibss_beacon = NULL; - - spin_lock_init(&priv->lock); - spin_lock_init(&priv->power_data.lock); - spin_lock_init(&priv->sta_lock); - spin_lock_init(&priv->hcmd_lock); - spin_lock_init(&priv->lq_mngr.lock); - - for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) - INIT_LIST_HEAD(&priv->ibss_mac_hash[i]); - - INIT_LIST_HEAD(&priv->free_frames); - - mutex_init(&priv->mutex); - - /* Clear the driver's (not device's) station table */ - iwlcore_clear_stations_table(priv); - - priv->data_retry_limit = -1; - priv->ieee_channels = NULL; - priv->ieee_rates = NULL; - priv->band = IEEE80211_BAND_2GHZ; - - priv->iw_mode = IEEE80211_IF_TYPE_STA; - - priv->use_ant_b_for_management_frame = 1; /* start with ant B */ - priv->ps_mode = IWL_MIMO_PS_NONE; - - /* Choose which receivers/antennas to use */ - iwl4965_set_rxon_chain(priv); - - iwlcore_reset_qos(priv); - - priv->qos_data.qos_active = 0; - priv->qos_data.qos_cap.val = 0; - - iwlcore_set_rxon_channel(priv, IEEE80211_BAND_2GHZ, 6); - - priv->rates_mask = IWL_RATES_MASK; - /* If power management is turned on, default to AC mode */ - priv->power_mode = IWL_POWER_AC; - priv->user_txpower_limit = IWL_DEFAULT_TX_POWER; - - ret = iwl_init_channel_map(priv); - if (ret) { - IWL_ERROR("initializing regulatory failed: %d\n", ret); - goto err; - } - - ret = iwl4965_init_geos(priv); - if (ret) { - IWL_ERROR("initializing geos failed: %d\n", ret); - goto err_free_channel_map; - } - - ret = ieee80211_register_hw(priv->hw); - if (ret) { - IWL_ERROR("Failed to register network device (error %d)\n", - ret); - goto err_free_geos; - } - - priv->hw->conf.beacon_int = 100; - priv->mac80211_registered = 1; - - return 0; - -err_free_geos: - iwl4965_free_geos(priv); -err_free_channel_map: - iwl_free_channel_map(priv); -err: - return ret; -} - static int is_fat_channel(__le32 rxon_flags) { return (rxon_flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) || (rxon_flags & RXON_FLG_CHANNEL_MODE_MIXED_MSK); } -#ifdef CONFIG_IWL4965_HT -static u8 is_single_rx_stream(struct iwl_priv *priv) -{ - return !priv->current_ht_config.is_ht || - ((priv->current_ht_config.supp_mcs_set[1] == 0) && - (priv->current_ht_config.supp_mcs_set[2] == 0)) || - priv->ps_mode == IWL_MIMO_PS_STATIC; -} -#else -static inline u8 is_single_rx_stream(struct iwl_priv *priv) -{ - return 1; -} -#endif /*CONFIG_IWL4965_HT */ - int iwl4965_hwrate_to_plcp_idx(u32 rate_n_flags) { int idx = 0; @@ -422,41 +288,6 @@ void iwl4965_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, &priv->bands[IEEE80211_BAND_2GHZ].bitrates[rate_index]; } -/* - * Determine how many receiver/antenna chains to use. - * More provides better reception via diversity. Fewer saves power. - * MIMO (dual stream) requires at least 2, but works better with 3. - * This does not determine *which* chains to use, just how many. - */ -static int iwl4965_get_rx_chain_counter(struct iwl_priv *priv, - u8 *idle_state, u8 *rx_state) -{ - u8 is_single = is_single_rx_stream(priv); - u8 is_cam = test_bit(STATUS_POWER_PMI, &priv->status) ? 0 : 1; - - /* # of Rx chains to use when expecting MIMO. */ - if (is_single || (!is_cam && (priv->ps_mode == IWL_MIMO_PS_STATIC))) - *rx_state = 2; - else - *rx_state = 3; - - /* # Rx chains when idling and maybe trying to save power */ - switch (priv->ps_mode) { - case IWL_MIMO_PS_STATIC: - case IWL_MIMO_PS_DYNAMIC: - *idle_state = (is_cam) ? 2 : 1; - break; - case IWL_MIMO_PS_NONE: - *idle_state = (is_cam) ? *rx_state : 1; - break; - default: - *idle_state = 1; - break; - } - - return 0; -} - int iwl4965_hw_rxq_stop(struct iwl_priv *priv) { int rc; @@ -2526,44 +2357,6 @@ static void iwl4965_txq_update_byte_cnt_tbl(struct iwl_priv *priv, byte_cnt, len); } -/** - * iwl4965_set_rxon_chain - Set up Rx chain usage in "staging" RXON image - * - * Selects how many and which Rx receivers/antennas/chains to use. - * This should not be used for scan command ... it puts data in wrong place. - */ -void iwl4965_set_rxon_chain(struct iwl_priv *priv) -{ - u8 is_single = is_single_rx_stream(priv); - u8 idle_state, rx_state; - - priv->staging_rxon.rx_chain = 0; - rx_state = idle_state = 3; - - /* Tell uCode which antennas are actually connected. - * Before first association, we assume all antennas are connected. - * Just after first association, iwl_chain_noise_calibration() - * checks which antennas actually *are* connected. */ - priv->staging_rxon.rx_chain |= - cpu_to_le16(priv->hw_params.valid_rx_ant << - RXON_RX_CHAIN_VALID_POS); - - /* How many receivers should we use? */ - iwl4965_get_rx_chain_counter(priv, &idle_state, &rx_state); - priv->staging_rxon.rx_chain |= - cpu_to_le16(rx_state << RXON_RX_CHAIN_MIMO_CNT_POS); - priv->staging_rxon.rx_chain |= - cpu_to_le16(idle_state << RXON_RX_CHAIN_CNT_POS); - - if (!is_single && (rx_state >= 2) && - !test_bit(STATUS_POWER_PMI, &priv->status)) - priv->staging_rxon.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK; - else - priv->staging_rxon.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK; - - IWL_DEBUG_ASSOC("rx chain %X\n", priv->staging_rxon.rx_chain); -} - /** * sign_extend - Sign extend a value using specified bit as sign-bit * @@ -3127,41 +2920,6 @@ static int iwl4965_calc_rssi(struct iwl4965_rx_phy_res *rx_resp) return (max_rssi - agc - IWL_RSSI_OFFSET); } -#ifdef CONFIG_IWL4965_HT - -void iwl4965_init_ht_hw_capab(const struct iwl_priv *priv, - struct ieee80211_ht_info *ht_info, - enum ieee80211_band band) -{ - ht_info->cap = 0; - memset(ht_info->supp_mcs_set, 0, 16); - - ht_info->ht_supported = 1; - - if (priv->hw_params.fat_channel & BIT(band)) { - ht_info->cap |= (u16)IEEE80211_HT_CAP_SUP_WIDTH; - ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_40; - ht_info->supp_mcs_set[4] = 0x01; - } - ht_info->cap |= (u16)IEEE80211_HT_CAP_GRN_FLD; - ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_20; - ht_info->cap |= (u16)(IEEE80211_HT_CAP_MIMO_PS & - (IWL_MIMO_PS_NONE << 2)); - - if (priv->cfg->mod_params->amsdu_size_8K) - ht_info->cap |= (u16)IEEE80211_HT_CAP_MAX_AMSDU; - - ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF; - ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF; - - ht_info->supp_mcs_set[0] = 0xFF; - if (priv->hw_params.tx_chains_num >= 2) - ht_info->supp_mcs_set[1] = 0xFF; - if (priv->hw_params.tx_chains_num >= 3) - ht_info->supp_mcs_set[2] = 0xFF; -} -#endif /* CONFIG_IWL4965_HT */ - static void iwl4965_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) { unsigned long flags; @@ -4039,7 +3797,7 @@ void iwl4965_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) rxon->flags |= cpu_to_le32(val << RXON_FLG_HT_OPERATING_MODE_POS); - iwl4965_set_rxon_chain(priv); + iwl_set_rxon_chain(priv); IWL_DEBUG_ASSOC("supported HT rate 0x%X 0x%X 0x%X " "rxon flags 0x%X operation mode :0x%X " @@ -4356,7 +4114,6 @@ static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = { }; static struct iwl_lib_ops iwl4965_lib = { - .init_drv = iwl4965_init_drv, .set_hw_params = iwl4965_hw_set_hw_params, .alloc_shared_mem = iwl4965_alloc_shared_mem, .free_shared_mem = iwl4965_free_shared_mem, diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h index e3572636e59..3b730647553 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965.h @@ -748,7 +748,6 @@ extern int iwl4965_tx_queue_update_wr_ptr(struct iwl_priv *priv, u16 byte_cnt); extern void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap); -extern void iwl4965_set_rxon_chain(struct iwl_priv *priv); extern int iwl4965_alive_notify(struct iwl_priv *priv); extern void iwl4965_update_rate_scaling(struct iwl_priv *priv, u8 mode); extern void iwl4965_rf_kill_ct_config(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 68de1a4700a..ca32fb3b9e1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -51,6 +51,45 @@ u32 iwl_debug_level; EXPORT_SYMBOL(iwl_debug_level); #endif +#define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np) \ + [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \ + IWL_RATE_SISO_##s##M_PLCP, \ + IWL_RATE_MIMO2_##s##M_PLCP,\ + IWL_RATE_MIMO3_##s##M_PLCP,\ + IWL_RATE_##r##M_IEEE, \ + IWL_RATE_##ip##M_INDEX, \ + IWL_RATE_##in##M_INDEX, \ + IWL_RATE_##rp##M_INDEX, \ + IWL_RATE_##rn##M_INDEX, \ + IWL_RATE_##pp##M_INDEX, \ + IWL_RATE_##np##M_INDEX } + +/* + * Parameter order: + * rate, ht rate, prev rate, next rate, prev tgg rate, next tgg rate + * + * If there isn't a valid next or previous rate then INV is used which + * maps to IWL_RATE_INVALID + * + */ +const struct iwl4965_rate_info iwl4965_rates[IWL_RATE_COUNT] = { + IWL_DECLARE_RATE_INFO(1, INV, INV, 2, INV, 2, INV, 2), /* 1mbps */ + IWL_DECLARE_RATE_INFO(2, INV, 1, 5, 1, 5, 1, 5), /* 2mbps */ + IWL_DECLARE_RATE_INFO(5, INV, 2, 6, 2, 11, 2, 11), /*5.5mbps */ + IWL_DECLARE_RATE_INFO(11, INV, 9, 12, 9, 12, 5, 18), /* 11mbps */ + IWL_DECLARE_RATE_INFO(6, 6, 5, 9, 5, 11, 5, 11), /* 6mbps */ + IWL_DECLARE_RATE_INFO(9, 6, 6, 11, 6, 11, 5, 11), /* 9mbps */ + IWL_DECLARE_RATE_INFO(12, 12, 11, 18, 11, 18, 11, 18), /* 12mbps */ + IWL_DECLARE_RATE_INFO(18, 18, 12, 24, 12, 24, 11, 24), /* 18mbps */ + IWL_DECLARE_RATE_INFO(24, 24, 18, 36, 18, 36, 18, 36), /* 24mbps */ + IWL_DECLARE_RATE_INFO(36, 36, 24, 48, 24, 48, 24, 48), /* 36mbps */ + IWL_DECLARE_RATE_INFO(48, 48, 36, 54, 36, 54, 36, 54), /* 48mbps */ + IWL_DECLARE_RATE_INFO(54, 54, 48, INV, 48, INV, 48, INV),/* 54mbps */ + IWL_DECLARE_RATE_INFO(60, 60, 48, INV, 48, INV, 48, INV),/* 60mbps */ + /* FIXME:RS: ^^ should be INV (legacy) */ +}; +EXPORT_SYMBOL(iwl4965_rates); + /* This function both allocates and initializes hw and priv. */ struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg, struct ieee80211_ops *hw_ops) @@ -100,7 +139,7 @@ void iwlcore_clear_stations_table(struct iwl_priv *priv) } EXPORT_SYMBOL(iwlcore_clear_stations_table); -void iwlcore_reset_qos(struct iwl_priv *priv) +void iwl_reset_qos(struct iwl_priv *priv) { u16 cw_min = 15; u16 cw_max = 1023; @@ -186,7 +225,289 @@ void iwlcore_reset_qos(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } -EXPORT_SYMBOL(iwlcore_reset_qos); +EXPORT_SYMBOL(iwl_reset_qos); + +#ifdef CONFIG_IWL4965_HT +static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, + struct ieee80211_ht_info *ht_info, + enum ieee80211_band band) +{ + ht_info->cap = 0; + memset(ht_info->supp_mcs_set, 0, 16); + + ht_info->ht_supported = 1; + + if (priv->hw_params.fat_channel & BIT(band)) { + ht_info->cap |= (u16)IEEE80211_HT_CAP_SUP_WIDTH; + ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_40; + ht_info->supp_mcs_set[4] = 0x01; + } + ht_info->cap |= (u16)IEEE80211_HT_CAP_GRN_FLD; + ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_20; + ht_info->cap |= (u16)(IEEE80211_HT_CAP_MIMO_PS & + (IWL_MIMO_PS_NONE << 2)); + + if (priv->cfg->mod_params->amsdu_size_8K) + ht_info->cap |= (u16)IEEE80211_HT_CAP_MAX_AMSDU; + + ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF; + ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF; + + ht_info->supp_mcs_set[0] = 0xFF; + if (priv->hw_params.tx_chains_num >= 2) + ht_info->supp_mcs_set[1] = 0xFF; + if (priv->hw_params.tx_chains_num >= 3) + ht_info->supp_mcs_set[2] = 0xFF; +} +#endif /* CONFIG_IWL4965_HT */ + +static void iwlcore_init_hw_rates(struct iwl_priv *priv, + struct ieee80211_rate *rates) +{ + int i; + + for (i = 0; i < IWL_RATE_COUNT; i++) { + rates[i].bitrate = iwl4965_rates[i].ieee * 5; + rates[i].hw_value = i; /* Rate scaling will work on indexes */ + rates[i].hw_value_short = i; + rates[i].flags = 0; + if ((i > IWL_LAST_OFDM_RATE) || (i < IWL_FIRST_OFDM_RATE)) { + /* + * If CCK != 1M then set short preamble rate flag. + */ + rates[i].flags |= + (iwl4965_rates[i].plcp == IWL_RATE_1M_PLCP) ? + 0 : IEEE80211_RATE_SHORT_PREAMBLE; + } + } +} + +/** + * iwlcore_init_geos - Initialize mac80211's geo/channel info based from eeprom + */ +static int iwlcore_init_geos(struct iwl_priv *priv) +{ + struct iwl_channel_info *ch; + struct ieee80211_supported_band *sband; + struct ieee80211_channel *channels; + struct ieee80211_channel *geo_ch; + struct ieee80211_rate *rates; + int i = 0; + + if (priv->bands[IEEE80211_BAND_2GHZ].n_bitrates || + priv->bands[IEEE80211_BAND_5GHZ].n_bitrates) { + IWL_DEBUG_INFO("Geography modes already initialized.\n"); + set_bit(STATUS_GEO_CONFIGURED, &priv->status); + return 0; + } + + channels = kzalloc(sizeof(struct ieee80211_channel) * + priv->channel_count, GFP_KERNEL); + if (!channels) + return -ENOMEM; + + rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_RATE_COUNT + 1)), + GFP_KERNEL); + if (!rates) { + kfree(channels); + return -ENOMEM; + } + + /* 5.2GHz channels start after the 2.4GHz channels */ + sband = &priv->bands[IEEE80211_BAND_5GHZ]; + sband->channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)]; + /* just OFDM */ + sband->bitrates = &rates[IWL_FIRST_OFDM_RATE]; + sband->n_bitrates = IWL_RATE_COUNT - IWL_FIRST_OFDM_RATE; + + iwlcore_init_ht_hw_capab(priv, &sband->ht_info, IEEE80211_BAND_5GHZ); + + sband = &priv->bands[IEEE80211_BAND_2GHZ]; + sband->channels = channels; + /* OFDM & CCK */ + sband->bitrates = rates; + sband->n_bitrates = IWL_RATE_COUNT; + + iwlcore_init_ht_hw_capab(priv, &sband->ht_info, IEEE80211_BAND_2GHZ); + + priv->ieee_channels = channels; + priv->ieee_rates = rates; + + iwlcore_init_hw_rates(priv, rates); + + for (i = 0; i < priv->channel_count; i++) { + ch = &priv->channel_info[i]; + + /* FIXME: might be removed if scan is OK */ + if (!is_channel_valid(ch)) + continue; + + if (is_channel_a_band(ch)) + sband = &priv->bands[IEEE80211_BAND_5GHZ]; + else + sband = &priv->bands[IEEE80211_BAND_2GHZ]; + + geo_ch = &sband->channels[sband->n_channels++]; + + geo_ch->center_freq = + ieee80211_channel_to_frequency(ch->channel); + geo_ch->max_power = ch->max_power_avg; + geo_ch->max_antenna_gain = 0xff; + geo_ch->hw_value = ch->channel; + + if (is_channel_valid(ch)) { + if (!(ch->flags & EEPROM_CHANNEL_IBSS)) + geo_ch->flags |= IEEE80211_CHAN_NO_IBSS; + + if (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) + geo_ch->flags |= IEEE80211_CHAN_PASSIVE_SCAN; + + if (ch->flags & EEPROM_CHANNEL_RADAR) + geo_ch->flags |= IEEE80211_CHAN_RADAR; + + if (ch->max_power_avg > priv->max_channel_txpower_limit) + priv->max_channel_txpower_limit = + ch->max_power_avg; + } else { + geo_ch->flags |= IEEE80211_CHAN_DISABLED; + } + + /* Save flags for reg domain usage */ + geo_ch->orig_flags = geo_ch->flags; + + IWL_DEBUG_INFO("Channel %d Freq=%d[%sGHz] %s flag=0%X\n", + ch->channel, geo_ch->center_freq, + is_channel_a_band(ch) ? "5.2" : "2.4", + geo_ch->flags & IEEE80211_CHAN_DISABLED ? + "restricted" : "valid", + geo_ch->flags); + } + + if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) && + priv->cfg->sku & IWL_SKU_A) { + printk(KERN_INFO DRV_NAME + ": Incorrectly detected BG card as ABG. Please send " + "your PCI ID 0x%04X:0x%04X to maintainer.\n", + priv->pci_dev->device, priv->pci_dev->subsystem_device); + priv->cfg->sku &= ~IWL_SKU_A; + } + + printk(KERN_INFO DRV_NAME + ": Tunable channels: %d 802.11bg, %d 802.11a channels\n", + priv->bands[IEEE80211_BAND_2GHZ].n_channels, + priv->bands[IEEE80211_BAND_5GHZ].n_channels); + + if (priv->bands[IEEE80211_BAND_2GHZ].n_channels) + priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = + &priv->bands[IEEE80211_BAND_2GHZ]; + if (priv->bands[IEEE80211_BAND_5GHZ].n_channels) + priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = + &priv->bands[IEEE80211_BAND_5GHZ]; + + set_bit(STATUS_GEO_CONFIGURED, &priv->status); + + return 0; +} + +/* + * iwlcore_free_geos - undo allocations in iwlcore_init_geos + */ +void iwlcore_free_geos(struct iwl_priv *priv) +{ + kfree(priv->ieee_channels); + kfree(priv->ieee_rates); + clear_bit(STATUS_GEO_CONFIGURED, &priv->status); +} +EXPORT_SYMBOL(iwlcore_free_geos); + +#ifdef CONFIG_IWL4965_HT +static u8 is_single_rx_stream(struct iwl_priv *priv) +{ + return !priv->current_ht_config.is_ht || + ((priv->current_ht_config.supp_mcs_set[1] == 0) && + (priv->current_ht_config.supp_mcs_set[2] == 0)) || + priv->ps_mode == IWL_MIMO_PS_STATIC; +} +#else +static inline u8 is_single_rx_stream(struct iwl_priv *priv) +{ + return 1; +} +#endif /*CONFIG_IWL4965_HT */ + +/* + * Determine how many receiver/antenna chains to use. + * More provides better reception via diversity. Fewer saves power. + * MIMO (dual stream) requires at least 2, but works better with 3. + * This does not determine *which* chains to use, just how many. + */ +static int iwlcore_get_rx_chain_counter(struct iwl_priv *priv, + u8 *idle_state, u8 *rx_state) +{ + u8 is_single = is_single_rx_stream(priv); + u8 is_cam = test_bit(STATUS_POWER_PMI, &priv->status) ? 0 : 1; + + /* # of Rx chains to use when expecting MIMO. */ + if (is_single || (!is_cam && (priv->ps_mode == IWL_MIMO_PS_STATIC))) + *rx_state = 2; + else + *rx_state = 3; + + /* # Rx chains when idling and maybe trying to save power */ + switch (priv->ps_mode) { + case IWL_MIMO_PS_STATIC: + case IWL_MIMO_PS_DYNAMIC: + *idle_state = (is_cam) ? 2 : 1; + break; + case IWL_MIMO_PS_NONE: + *idle_state = (is_cam) ? *rx_state : 1; + break; + default: + *idle_state = 1; + break; + } + + return 0; +} + +/** + * iwl_set_rxon_chain - Set up Rx chain usage in "staging" RXON image + * + * Selects how many and which Rx receivers/antennas/chains to use. + * This should not be used for scan command ... it puts data in wrong place. + */ +void iwl_set_rxon_chain(struct iwl_priv *priv) +{ + u8 is_single = is_single_rx_stream(priv); + u8 idle_state, rx_state; + + priv->staging_rxon.rx_chain = 0; + rx_state = idle_state = 3; + + /* Tell uCode which antennas are actually connected. + * Before first association, we assume all antennas are connected. + * Just after first association, iwl_chain_noise_calibration() + * checks which antennas actually *are* connected. */ + priv->staging_rxon.rx_chain |= + cpu_to_le16(priv->hw_params.valid_rx_ant << + RXON_RX_CHAIN_VALID_POS); + + /* How many receivers should we use? */ + iwlcore_get_rx_chain_counter(priv, &idle_state, &rx_state); + priv->staging_rxon.rx_chain |= + cpu_to_le16(rx_state << RXON_RX_CHAIN_MIMO_CNT_POS); + priv->staging_rxon.rx_chain |= + cpu_to_le16(idle_state << RXON_RX_CHAIN_CNT_POS); + + if (!is_single && (rx_state >= 2) && + !test_bit(STATUS_POWER_PMI, &priv->status)) + priv->staging_rxon.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK; + else + priv->staging_rxon.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK; + + IWL_DEBUG_ASSOC("rx chain %X\n", priv->staging_rxon.rx_chain); +} +EXPORT_SYMBOL(iwl_set_rxon_chain); /** * iwlcore_set_rxon_channel - Set the phymode and channel values in staging RXON @@ -198,7 +519,7 @@ EXPORT_SYMBOL(iwlcore_reset_qos); * NOTE: Does not commit to the hardware; it sets appropriate bit fields * in the staging RXON flag structure based on the phymode */ -int iwlcore_set_rxon_channel(struct iwl_priv *priv, +int iwl_set_rxon_channel(struct iwl_priv *priv, enum ieee80211_band band, u16 channel) { @@ -224,7 +545,7 @@ int iwlcore_set_rxon_channel(struct iwl_priv *priv, return 0; } -EXPORT_SYMBOL(iwlcore_set_rxon_channel); +EXPORT_SYMBOL(iwl_set_rxon_channel); static void iwlcore_init_hw(struct iwl_priv *priv) { @@ -251,11 +572,92 @@ static void iwlcore_init_hw(struct iwl_priv *priv) #endif /* CONFIG_IWL4965_HT */ } +static int iwlcore_init_drv(struct iwl_priv *priv) +{ + int ret; + int i; + + priv->retry_rate = 1; + priv->ibss_beacon = NULL; + + spin_lock_init(&priv->lock); + spin_lock_init(&priv->power_data.lock); + spin_lock_init(&priv->sta_lock); + spin_lock_init(&priv->hcmd_lock); + spin_lock_init(&priv->lq_mngr.lock); + + for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) + INIT_LIST_HEAD(&priv->ibss_mac_hash[i]); + + INIT_LIST_HEAD(&priv->free_frames); + + mutex_init(&priv->mutex); + + /* Clear the driver's (not device's) station table */ + iwlcore_clear_stations_table(priv); + + priv->data_retry_limit = -1; + priv->ieee_channels = NULL; + priv->ieee_rates = NULL; + priv->band = IEEE80211_BAND_2GHZ; + + priv->iw_mode = IEEE80211_IF_TYPE_STA; + + priv->use_ant_b_for_management_frame = 1; /* start with ant B */ + priv->ps_mode = IWL_MIMO_PS_NONE; + + /* Choose which receivers/antennas to use */ + iwl_set_rxon_chain(priv); + + iwl_reset_qos(priv); + + priv->qos_data.qos_active = 0; + priv->qos_data.qos_cap.val = 0; + + iwl_set_rxon_channel(priv, IEEE80211_BAND_2GHZ, 6); + + priv->rates_mask = IWL_RATES_MASK; + /* If power management is turned on, default to AC mode */ + priv->power_mode = IWL_POWER_AC; + priv->user_txpower_limit = IWL_DEFAULT_TX_POWER; + + ret = iwl_init_channel_map(priv); + if (ret) { + IWL_ERROR("initializing regulatory failed: %d\n", ret); + goto err; + } + + ret = iwlcore_init_geos(priv); + if (ret) { + IWL_ERROR("initializing geos failed: %d\n", ret); + goto err_free_channel_map; + } + + ret = ieee80211_register_hw(priv->hw); + if (ret) { + IWL_ERROR("Failed to register network device (error %d)\n", + ret); + goto err_free_geos; + } + + priv->hw->conf.beacon_int = 100; + priv->mac80211_registered = 1; + + return 0; + +err_free_geos: + iwlcore_free_geos(priv); +err_free_channel_map: + iwl_free_channel_map(priv); +err: + return ret; +} + int iwl_setup(struct iwl_priv *priv) { int ret = 0; iwlcore_init_hw(priv); - ret = priv->cfg->ops->lib->init_drv(priv); + ret = iwlcore_init_drv(priv); return ret; } EXPORT_SYMBOL(iwl_setup); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index e94aea3cba7..e18940dbd13 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -97,8 +97,6 @@ struct iwl_hcmd_utils_ops { }; struct iwl_lib_ops { - /* iwlwifi driver (priv) init */ - int (*init_drv)(struct iwl_priv *priv); /* set hw dependant perameters */ int (*set_hw_params)(struct iwl_priv *priv); /* ucode shared memory */ @@ -164,11 +162,12 @@ struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg, void iwl_hw_detect(struct iwl_priv *priv); void iwlcore_clear_stations_table(struct iwl_priv *priv); -void iwlcore_reset_qos(struct iwl_priv *priv); -int iwlcore_set_rxon_channel(struct iwl_priv *priv, +void iwl_reset_qos(struct iwl_priv *priv); +void iwl_set_rxon_chain(struct iwl_priv *priv); +int iwl_set_rxon_channel(struct iwl_priv *priv, enum ieee80211_band band, u16 channel); - +void iwlcore_free_geos(struct iwl_priv *priv); int iwl_setup(struct iwl_priv *priv); /***************************************************** diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 89b0950f02f..e24527313ab 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -882,7 +882,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) void iwl4965_update_chain_flags(struct iwl_priv *priv) { - iwl4965_set_rxon_chain(priv); + iwl_set_rxon_chain(priv); iwl4965_commit_rxon(priv); } @@ -1735,7 +1735,7 @@ static void iwl4965_connection_init_rx_config(struct iwl_priv *priv) memcpy(priv->staging_rxon.wlap_bssid_addr, priv->mac_addr, ETH_ALEN); priv->staging_rxon.ofdm_ht_single_stream_basic_rates = 0xff; priv->staging_rxon.ofdm_ht_dual_stream_basic_rates = 0xff; - iwl4965_set_rxon_chain(priv); + iwl_set_rxon_chain(priv); } static int iwl4965_set_mode(struct iwl_priv *priv, int mode) @@ -4496,163 +4496,6 @@ static int iwl4965_get_channels_for_scan(struct iwl_priv *priv, return added; } -static void iwl4965_init_hw_rates(struct iwl_priv *priv, - struct ieee80211_rate *rates) -{ - int i; - - for (i = 0; i < IWL_RATE_COUNT; i++) { - rates[i].bitrate = iwl4965_rates[i].ieee * 5; - rates[i].hw_value = i; /* Rate scaling will work on indexes */ - rates[i].hw_value_short = i; - rates[i].flags = 0; - if ((i > IWL_LAST_OFDM_RATE) || (i < IWL_FIRST_OFDM_RATE)) { - /* - * If CCK != 1M then set short preamble rate flag. - */ - rates[i].flags |= - (iwl4965_rates[i].plcp == IWL_RATE_1M_PLCP) ? - 0 : IEEE80211_RATE_SHORT_PREAMBLE; - } - } -} - -/** - * iwl4965_init_geos - Initialize mac80211's geo/channel info based from eeprom - */ -int iwl4965_init_geos(struct iwl_priv *priv) -{ - struct iwl_channel_info *ch; - struct ieee80211_supported_band *sband; - struct ieee80211_channel *channels; - struct ieee80211_channel *geo_ch; - struct ieee80211_rate *rates; - int i = 0; - - if (priv->bands[IEEE80211_BAND_2GHZ].n_bitrates || - priv->bands[IEEE80211_BAND_5GHZ].n_bitrates) { - IWL_DEBUG_INFO("Geography modes already initialized.\n"); - set_bit(STATUS_GEO_CONFIGURED, &priv->status); - return 0; - } - - channels = kzalloc(sizeof(struct ieee80211_channel) * - priv->channel_count, GFP_KERNEL); - if (!channels) - return -ENOMEM; - - rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_RATE_COUNT + 1)), - GFP_KERNEL); - if (!rates) { - kfree(channels); - return -ENOMEM; - } - - /* 5.2GHz channels start after the 2.4GHz channels */ - sband = &priv->bands[IEEE80211_BAND_5GHZ]; - sband->channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)]; - /* just OFDM */ - sband->bitrates = &rates[IWL_FIRST_OFDM_RATE]; - sband->n_bitrates = IWL_RATE_COUNT - IWL_FIRST_OFDM_RATE; - - iwl4965_init_ht_hw_capab(priv, &sband->ht_info, IEEE80211_BAND_5GHZ); - - sband = &priv->bands[IEEE80211_BAND_2GHZ]; - sband->channels = channels; - /* OFDM & CCK */ - sband->bitrates = rates; - sband->n_bitrates = IWL_RATE_COUNT; - - iwl4965_init_ht_hw_capab(priv, &sband->ht_info, IEEE80211_BAND_2GHZ); - - priv->ieee_channels = channels; - priv->ieee_rates = rates; - - iwl4965_init_hw_rates(priv, rates); - - for (i = 0; i < priv->channel_count; i++) { - ch = &priv->channel_info[i]; - - /* FIXME: might be removed if scan is OK */ - if (!is_channel_valid(ch)) - continue; - - if (is_channel_a_band(ch)) - sband = &priv->bands[IEEE80211_BAND_5GHZ]; - else - sband = &priv->bands[IEEE80211_BAND_2GHZ]; - - geo_ch = &sband->channels[sband->n_channels++]; - - geo_ch->center_freq = ieee80211_channel_to_frequency(ch->channel); - geo_ch->max_power = ch->max_power_avg; - geo_ch->max_antenna_gain = 0xff; - geo_ch->hw_value = ch->channel; - - if (is_channel_valid(ch)) { - if (!(ch->flags & EEPROM_CHANNEL_IBSS)) - geo_ch->flags |= IEEE80211_CHAN_NO_IBSS; - - if (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) - geo_ch->flags |= IEEE80211_CHAN_PASSIVE_SCAN; - - if (ch->flags & EEPROM_CHANNEL_RADAR) - geo_ch->flags |= IEEE80211_CHAN_RADAR; - - if (ch->max_power_avg > priv->max_channel_txpower_limit) - priv->max_channel_txpower_limit = - ch->max_power_avg; - } else { - geo_ch->flags |= IEEE80211_CHAN_DISABLED; - } - - /* Save flags for reg domain usage */ - geo_ch->orig_flags = geo_ch->flags; - - IWL_DEBUG_INFO("Channel %d Freq=%d[%sGHz] %s flag=0%X\n", - ch->channel, geo_ch->center_freq, - is_channel_a_band(ch) ? "5.2" : "2.4", - geo_ch->flags & IEEE80211_CHAN_DISABLED ? - "restricted" : "valid", - geo_ch->flags); - } - - if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) && - priv->cfg->sku & IWL_SKU_A) { - printk(KERN_INFO DRV_NAME - ": Incorrectly detected BG card as ABG. Please send " - "your PCI ID 0x%04X:0x%04X to maintainer.\n", - priv->pci_dev->device, priv->pci_dev->subsystem_device); - priv->cfg->sku &= ~IWL_SKU_A; - } - - printk(KERN_INFO DRV_NAME - ": Tunable channels: %d 802.11bg, %d 802.11a channels\n", - priv->bands[IEEE80211_BAND_2GHZ].n_channels, - priv->bands[IEEE80211_BAND_5GHZ].n_channels); - - if (priv->bands[IEEE80211_BAND_2GHZ].n_channels) - priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = - &priv->bands[IEEE80211_BAND_2GHZ]; - if (priv->bands[IEEE80211_BAND_5GHZ].n_channels) - priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = - &priv->bands[IEEE80211_BAND_5GHZ]; - - set_bit(STATUS_GEO_CONFIGURED, &priv->status); - - return 0; -} - -/* - * iwl4965_free_geos - undo allocations in iwl4965_init_geos - */ -void iwl4965_free_geos(struct iwl_priv *priv) -{ - kfree(priv->ieee_channels); - kfree(priv->ieee_rates); - clear_bit(STATUS_GEO_CONFIGURED, &priv->status); -} - /****************************************************************************** * * uCode download functions @@ -5807,7 +5650,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv) if (priv->current_ht_config.is_ht) iwl4965_set_rxon_ht(priv, &priv->current_ht_config); #endif /* CONFIG_IWL4965_HT*/ - iwl4965_set_rxon_chain(priv); + iwl_set_rxon_chain(priv); priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id); IWL_DEBUG_ASSOC("assoc id %d beacon interval %d\n", @@ -6153,7 +5996,7 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co priv->staging_rxon.flags = 0; #endif /* CONFIG_IWL4965_HT */ - iwlcore_set_rxon_channel(priv, conf->channel->band, + iwl_set_rxon_channel(priv, conf->channel->band, ieee80211_frequency_to_channel(conf->channel->center_freq)); iwl4965_set_flags_for_phymode(priv, conf->channel->band); @@ -6225,7 +6068,7 @@ static void iwl4965_config_ap(struct iwl_priv *priv) IWL_WARNING("REPLY_RXON_TIMING failed - " "Attempting to continue.\n"); - iwl4965_set_rxon_chain(priv); + iwl_set_rxon_chain(priv); /* FIXME: what should be the assoc_id for AP? */ priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id); @@ -6437,7 +6280,7 @@ static void iwl4965_bss_info_changed(struct ieee80211_hw *hw, if (changes & BSS_CHANGED_HT) { IWL_DEBUG_MAC80211("HT %d\n", bss_conf->assoc_ht); iwl4965_ht_conf(priv, bss_conf); - iwl4965_set_rxon_chain(priv); + iwl_set_rxon_chain(priv); } if (changes & BSS_CHANGED_ASSOC) { @@ -6761,7 +6604,7 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw) spin_unlock_irqrestore(&priv->lock, flags); #endif /* CONFIG_IWL4965_HT */ - iwlcore_reset_qos(priv); + iwl_reset_qos(priv); cancel_delayed_work(&priv->post_associate); @@ -6848,7 +6691,7 @@ static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk IWL_DEBUG_MAC80211("leave\n"); spin_unlock_irqrestore(&priv->lock, flags); - iwlcore_reset_qos(priv); + iwl_reset_qos(priv); queue_work(priv->workqueue, &priv->post_associate.work); @@ -7636,7 +7479,7 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) pci_set_drvdata(pdev, NULL); iwl_free_channel_map(priv); - iwl4965_free_geos(priv); + iwlcore_free_geos(priv); if (priv->ibss_beacon) dev_kfree_skb(priv->ibss_beacon); -- cgit v1.2.3-70-g09d2 From 11bf925aa31f72b9a88b2dca47f3c2e06c42dbac Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Wed, 23 Apr 2008 17:15:06 -0700 Subject: iwlwifi: iwl-sta redundant includes clean up This patch cleans unnecessary includes in iwl-sta.[hc] Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-sta.c | 2 -- drivers/net/wireless/iwlwifi/iwl-sta.h | 8 -------- 2 files changed, 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index d39ac1cffb5..2eee59824df 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -36,8 +36,6 @@ #include "iwl-sta.h" #include "iwl-io.h" #include "iwl-helpers.h" -#include "iwl-4965.h" -#include "iwl-sta.h" u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr) { diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h index 89558356a59..38b1b0a9884 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.h +++ b/drivers/net/wireless/iwlwifi/iwl-sta.h @@ -29,14 +29,6 @@ #ifndef __iwl_sta_h__ #define __iwl_sta_h__ -#include - -#include "iwl-eeprom.h" -#include "iwl-core.h" -#include "iwl-4965.h" -#include "iwl-io.h" -#include "iwl-helpers.h" - int iwl_get_free_ucode_key_index(struct iwl_priv *priv); int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty); int iwl_remove_default_wep_key(struct iwl_priv *priv, -- cgit v1.2.3-70-g09d2 From 4b52c39dc6fa4ffa598c778e72850f9a8ccca584 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 23 Apr 2008 17:15:07 -0700 Subject: iwlwifi: move Flow Handlers define to iwl-fh.h This patch moves Flow Handlers define to a new file iwl-fh.h Signed-off-by: Emmanuel Grumbach Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-hw.h | 288 +-------------------- drivers/net/wireless/iwlwifi/iwl-4965.c | 14 +- drivers/net/wireless/iwlwifi/iwl-fh.h | 391 +++++++++++++++++++++++++++++ 3 files changed, 400 insertions(+), 293 deletions(-) create mode 100644 drivers/net/wireless/iwlwifi/iwl-fh.h (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h index 38627040ad5..bea03f68267 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h @@ -69,6 +69,8 @@ #ifndef __iwl_4965_hw_h__ #define __iwl_4965_hw_h__ +#include "iwl-fh.h" + /* EERPROM */ #define IWL4965_EEPROM_IMG_SIZE 1024 @@ -786,292 +788,6 @@ enum { /********************* END TXPOWER *****************************************/ -/****************************/ -/* Flow Handler Definitions */ -/****************************/ - -/** - * This I/O area is directly read/writable by driver (e.g. Linux uses writel()) - * Addresses are offsets from device's PCI hardware base address. - */ -#define FH_MEM_LOWER_BOUND (0x1000) -#define FH_MEM_UPPER_BOUND (0x1EF0) - -/** - * Keep-Warm (KW) buffer base address. - * - * Driver must allocate a 4KByte buffer that is used by 4965 for keeping the - * host DRAM powered on (via dummy accesses to DRAM) to maintain low-latency - * DRAM access when 4965 is Txing or Rxing. The dummy accesses prevent host - * from going into a power-savings mode that would cause higher DRAM latency, - * and possible data over/under-runs, before all Tx/Rx is complete. - * - * Driver loads IWL_FH_KW_MEM_ADDR_REG with the physical address (bits 35:4) - * of the buffer, which must be 4K aligned. Once this is set up, the 4965 - * automatically invokes keep-warm accesses when normal accesses might not - * be sufficient to maintain fast DRAM response. - * - * Bit fields: - * 31-0: Keep-warm buffer physical base address [35:4], must be 4K aligned - */ -#define IWL_FH_KW_MEM_ADDR_REG (FH_MEM_LOWER_BOUND + 0x97C) - - -/** - * TFD Circular Buffers Base (CBBC) addresses - * - * 4965 has 16 base pointer registers, one for each of 16 host-DRAM-resident - * circular buffers (CBs/queues) containing Transmit Frame Descriptors (TFDs) - * (see struct iwl_tfd_frame). These 16 pointer registers are offset by 0x04 - * bytes from one another. Each TFD circular buffer in DRAM must be 256-byte - * aligned (address bits 0-7 must be 0). - * - * Bit fields in each pointer register: - * 27-0: TFD CB physical base address [35:8], must be 256-byte aligned - */ -#define FH_MEM_CBBC_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0x9D0) -#define FH_MEM_CBBC_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xA10) - -/* Find TFD CB base pointer for given queue (range 0-15). */ -#define FH_MEM_CBBC_QUEUE(x) (FH_MEM_CBBC_LOWER_BOUND + (x) * 0x4) - - -/** - * Rx SRAM Control and Status Registers (RSCSR) - * - * These registers provide handshake between driver and 4965 for the Rx queue - * (this queue handles *all* command responses, notifications, Rx data, etc. - * sent from 4965 uCode to host driver). Unlike Tx, there is only one Rx - * queue, and only one Rx DMA/FIFO channel. Also unlike Tx, which can - * concatenate up to 20 DRAM buffers to form a Tx frame, each Receive Buffer - * Descriptor (RBD) points to only one Rx Buffer (RB); there is a 1:1 - * mapping between RBDs and RBs. - * - * Driver must allocate host DRAM memory for the following, and set the - * physical address of each into 4965 registers: - * - * 1) Receive Buffer Descriptor (RBD) circular buffer (CB), typically with 256 - * entries (although any power of 2, up to 4096, is selectable by driver). - * Each entry (1 dword) points to a receive buffer (RB) of consistent size - * (typically 4K, although 8K or 16K are also selectable by driver). - * Driver sets up RB size and number of RBDs in the CB via Rx config - * register FH_MEM_RCSR_CHNL0_CONFIG_REG. - * - * Bit fields within one RBD: - * 27-0: Receive Buffer physical address bits [35:8], 256-byte aligned - * - * Driver sets physical address [35:8] of base of RBD circular buffer - * into FH_RSCSR_CHNL0_RBDCB_BASE_REG [27:0]. - * - * 2) Rx status buffer, 8 bytes, in which 4965 indicates which Rx Buffers - * (RBs) have been filled, via a "write pointer", actually the index of - * the RB's corresponding RBD within the circular buffer. Driver sets - * physical address [35:4] into FH_RSCSR_CHNL0_STTS_WPTR_REG [31:0]. - * - * Bit fields in lower dword of Rx status buffer (upper dword not used - * by driver; see struct iwl4965_shared, val0): - * 31-12: Not used by driver - * 11- 0: Index of last filled Rx buffer descriptor - * (4965 writes, driver reads this value) - * - * As the driver prepares Receive Buffers (RBs) for 4965 to fill, driver must - * enter pointers to these RBs into contiguous RBD circular buffer entries, - * and update the 4965's "write" index register, FH_RSCSR_CHNL0_RBDCB_WPTR_REG. - * - * This "write" index corresponds to the *next* RBD that the driver will make - * available, i.e. one RBD past the tail of the ready-to-fill RBDs within - * the circular buffer. This value should initially be 0 (before preparing any - * RBs), should be 8 after preparing the first 8 RBs (for example), and must - * wrap back to 0 at the end of the circular buffer (but don't wrap before - * "read" index has advanced past 1! See below). - * NOTE: 4965 EXPECTS THE WRITE INDEX TO BE INCREMENTED IN MULTIPLES OF 8. - * - * As the 4965 fills RBs (referenced from contiguous RBDs within the circular - * buffer), it updates the Rx status buffer in host DRAM, 2) described above, - * to tell the driver the index of the latest filled RBD. The driver must - * read this "read" index from DRAM after receiving an Rx interrupt from 4965. - * - * The driver must also internally keep track of a third index, which is the - * next RBD to process. When receiving an Rx interrupt, driver should process - * all filled but unprocessed RBs up to, but not including, the RB - * corresponding to the "read" index. For example, if "read" index becomes "1", - * driver may process the RB pointed to by RBD 0. Depending on volume of - * traffic, there may be many RBs to process. - * - * If read index == write index, 4965 thinks there is no room to put new data. - * Due to this, the maximum number of filled RBs is 255, instead of 256. To - * be safe, make sure that there is a gap of at least 2 RBDs between "write" - * and "read" indexes; that is, make sure that there are no more than 254 - * buffers waiting to be filled. - */ -#define FH_MEM_RSCSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xBC0) -#define FH_MEM_RSCSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xC00) -#define FH_MEM_RSCSR_CHNL0 (FH_MEM_RSCSR_LOWER_BOUND) - -/** - * Physical base address of 8-byte Rx Status buffer. - * Bit fields: - * 31-0: Rx status buffer physical base address [35:4], must 16-byte aligned. - */ -#define FH_RSCSR_CHNL0_STTS_WPTR_REG (FH_MEM_RSCSR_CHNL0) - -/** - * Physical base address of Rx Buffer Descriptor Circular Buffer. - * Bit fields: - * 27-0: RBD CD physical base address [35:8], must be 256-byte aligned. - */ -#define FH_RSCSR_CHNL0_RBDCB_BASE_REG (FH_MEM_RSCSR_CHNL0 + 0x004) - -/** - * Rx write pointer (index, really!). - * Bit fields: - * 11-0: Index of driver's most recent prepared-to-be-filled RBD, + 1. - * NOTE: For 256-entry circular buffer, use only bits [7:0]. - */ -#define FH_RSCSR_CHNL0_RBDCB_WPTR_REG (FH_MEM_RSCSR_CHNL0 + 0x008) -#define FH_RSCSR_CHNL0_WPTR (FH_RSCSR_CHNL0_RBDCB_WPTR_REG) - - -/** - * Rx Config/Status Registers (RCSR) - * Rx Config Reg for channel 0 (only channel used) - * - * Driver must initialize FH_MEM_RCSR_CHNL0_CONFIG_REG as follows for - * normal operation (see bit fields). - * - * Clearing FH_MEM_RCSR_CHNL0_CONFIG_REG to 0 turns off Rx DMA. - * Driver should poll FH_MEM_RSSR_RX_STATUS_REG for - * FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE (bit 24) before continuing. - * - * Bit fields: - * 31-30: Rx DMA channel enable: '00' off/pause, '01' pause at end of frame, - * '10' operate normally - * 29-24: reserved - * 23-20: # RBDs in circular buffer = 2^value; use "8" for 256 RBDs (normal), - * min "5" for 32 RBDs, max "12" for 4096 RBDs. - * 19-18: reserved - * 17-16: size of each receive buffer; '00' 4K (normal), '01' 8K, - * '10' 12K, '11' 16K. - * 15-14: reserved - * 13-12: IRQ destination; '00' none, '01' host driver (normal operation) - * 11- 4: timeout for closing Rx buffer and interrupting host (units 32 usec) - * typical value 0x10 (about 1/2 msec) - * 3- 0: reserved - */ -#define FH_MEM_RCSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xC00) -#define FH_MEM_RCSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xCC0) -#define FH_MEM_RCSR_CHNL0 (FH_MEM_RCSR_LOWER_BOUND) - -#define FH_MEM_RCSR_CHNL0_CONFIG_REG (FH_MEM_RCSR_CHNL0) - -#define FH_RCSR_CHNL0_RX_CONFIG_RB_TIMEOUT_MASK (0x00000FF0) /* bit 4-11 */ -#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_MASK (0x00001000) /* bit 12 */ -#define FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MASK (0x00008000) /* bit 15 */ -#define FH_RCSR_CHNL0_RX_CONFIG_RB_SIZE_MASK (0x00030000) /* bits 16-17 */ -#define FH_RCSR_CHNL0_RX_CONFIG_RBDBC_SIZE_MASK (0x00F00000) /* bits 20-23 */ -#define FH_RCSR_CHNL0_RX_CONFIG_DMA_CHNL_EN_MASK (0xC0000000) /* bits 30-31 */ - -#define FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT (20) -#define FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_BITSHIFT (4) -#define RX_RB_TIMEOUT (0x10) - -#define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_VAL (0x00000000) -#define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_EOF_VAL (0x40000000) -#define FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL (0x80000000) - -#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K (0x00000000) -#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K (0x00010000) -#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_12K (0x00020000) -#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_16K (0x00030000) - -#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_NO_INT_VAL (0x00000000) -#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL (0x00001000) - - -/** - * Rx Shared Status Registers (RSSR) - * - * After stopping Rx DMA channel (writing 0 to FH_MEM_RCSR_CHNL0_CONFIG_REG), - * driver must poll FH_MEM_RSSR_RX_STATUS_REG until Rx channel is idle. - * - * Bit fields: - * 24: 1 = Channel 0 is idle - * - * FH_MEM_RSSR_SHARED_CTRL_REG and FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV contain - * default values that should not be altered by the driver. - */ -#define FH_MEM_RSSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xC40) -#define FH_MEM_RSSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xD00) - -#define FH_MEM_RSSR_SHARED_CTRL_REG (FH_MEM_RSSR_LOWER_BOUND) -#define FH_MEM_RSSR_RX_STATUS_REG (FH_MEM_RSSR_LOWER_BOUND + 0x004) -#define FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV (FH_MEM_RSSR_LOWER_BOUND + 0x008) - -#define FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE (0x01000000) - - -/** - * Transmit DMA Channel Control/Status Registers (TCSR) - * - * 4965 has one configuration register for each of 8 Tx DMA/FIFO channels - * supported in hardware (don't confuse these with the 16 Tx queues in DRAM, - * which feed the DMA/FIFO channels); config regs are separated by 0x20 bytes. - * - * To use a Tx DMA channel, driver must initialize its - * IWL_FH_TCSR_CHNL_TX_CONFIG_REG(chnl) with: - * - * IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | - * IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL - * - * All other bits should be 0. - * - * Bit fields: - * 31-30: Tx DMA channel enable: '00' off/pause, '01' pause at end of frame, - * '10' operate normally - * 29- 4: Reserved, set to "0" - * 3: Enable internal DMA requests (1, normal operation), disable (0) - * 2- 0: Reserved, set to "0" - */ -#define IWL_FH_TCSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xD00) -#define IWL_FH_TCSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xE60) - -/* Find Control/Status reg for given Tx DMA/FIFO channel */ -#define IWL_FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \ - (IWL_FH_TCSR_LOWER_BOUND + 0x20 * _chnl) - -#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL (0x00000000) -#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL (0x00000008) - -#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE (0x00000000) -#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE_EOF (0x40000000) -#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE (0x80000000) - -/** - * Tx Shared Status Registers (TSSR) - * - * After stopping Tx DMA channel (writing 0 to - * IWL_FH_TCSR_CHNL_TX_CONFIG_REG(chnl)), driver must poll - * IWL_FH_TSSR_TX_STATUS_REG until selected Tx channel is idle - * (channel's buffers empty | no pending requests). - * - * Bit fields: - * 31-24: 1 = Channel buffers empty (channel 7:0) - * 23-16: 1 = No pending requests (channel 7:0) - */ -#define IWL_FH_TSSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xEA0) -#define IWL_FH_TSSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xEC0) - -#define IWL_FH_TSSR_TX_STATUS_REG (IWL_FH_TSSR_LOWER_BOUND + 0x010) - -#define IWL_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) \ - ((1 << (_chnl)) << 24) -#define IWL_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl) \ - ((1 << (_chnl)) << 16) - -#define IWL_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(_chnl) \ - (IWL_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) | \ - IWL_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl)) - static inline u8 iwl4965_hw_get_rate(__le32 rate_n_flags) { return le32_to_cpu(rate_n_flags) & 0xFF; diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 93f4cdbae0f..99c08ea6ddf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -435,7 +435,7 @@ static int iwl4965_kw_init(struct iwl_priv *priv) if (rc) goto out; - iwl_write_direct32(priv, IWL_FH_KW_MEM_ADDR_REG, + iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma_addr >> 4); iwl_release_nic_access(priv); out: @@ -726,9 +726,9 @@ void iwl4965_hw_txq_ctx_stop(struct iwl_priv *priv) } iwl_write_direct32(priv, - IWL_FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), 0x0); - iwl_poll_direct_bit(priv, IWL_FH_TSSR_TX_STATUS_REG, - IWL_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE + FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), 0x0); + iwl_poll_direct_bit(priv, FH_TSSR_TX_STATUS_REG, + FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE (txq_id), 200); iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); @@ -2256,9 +2256,9 @@ int iwl4965_hw_tx_queue_init(struct iwl_priv *priv, struct iwl4965_tx_queue *txq /* Enable DMA channel, using same id as for TFD queue */ iwl_write_direct32( - priv, IWL_FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), - IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | - IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL); + priv, FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL); iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h new file mode 100644 index 00000000000..944642450d3 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -0,0 +1,391 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +/****************************/ +/* Flow Handler Definitions */ +/****************************/ + +/** + * This I/O area is directly read/writable by driver (e.g. Linux uses writel()) + * Addresses are offsets from device's PCI hardware base address. + */ +#define FH_MEM_LOWER_BOUND (0x1000) +#define FH_MEM_UPPER_BOUND (0x1EF0) + +/** + * Keep-Warm (KW) buffer base address. + * + * Driver must allocate a 4KByte buffer that is used by 4965 for keeping the + * host DRAM powered on (via dummy accesses to DRAM) to maintain low-latency + * DRAM access when 4965 is Txing or Rxing. The dummy accesses prevent host + * from going into a power-savings mode that would cause higher DRAM latency, + * and possible data over/under-runs, before all Tx/Rx is complete. + * + * Driver loads FH_KW_MEM_ADDR_REG with the physical address (bits 35:4) + * of the buffer, which must be 4K aligned. Once this is set up, the 4965 + * automatically invokes keep-warm accesses when normal accesses might not + * be sufficient to maintain fast DRAM response. + * + * Bit fields: + * 31-0: Keep-warm buffer physical base address [35:4], must be 4K aligned + */ +#define FH_KW_MEM_ADDR_REG (FH_MEM_LOWER_BOUND + 0x97C) + + +/** + * TFD Circular Buffers Base (CBBC) addresses + * + * 4965 has 16 base pointer registers, one for each of 16 host-DRAM-resident + * circular buffers (CBs/queues) containing Transmit Frame Descriptors (TFDs) + * (see struct iwl_tfd_frame). These 16 pointer registers are offset by 0x04 + * bytes from one another. Each TFD circular buffer in DRAM must be 256-byte + * aligned (address bits 0-7 must be 0). + * + * Bit fields in each pointer register: + * 27-0: TFD CB physical base address [35:8], must be 256-byte aligned + */ +#define FH_MEM_CBBC_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0x9D0) +#define FH_MEM_CBBC_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xA10) + +/* Find TFD CB base pointer for given queue (range 0-15). */ +#define FH_MEM_CBBC_QUEUE(x) (FH_MEM_CBBC_LOWER_BOUND + (x) * 0x4) + + +/** + * Rx SRAM Control and Status Registers (RSCSR) + * + * These registers provide handshake between driver and 4965 for the Rx queue + * (this queue handles *all* command responses, notifications, Rx data, etc. + * sent from 4965 uCode to host driver). Unlike Tx, there is only one Rx + * queue, and only one Rx DMA/FIFO channel. Also unlike Tx, which can + * concatenate up to 20 DRAM buffers to form a Tx frame, each Receive Buffer + * Descriptor (RBD) points to only one Rx Buffer (RB); there is a 1:1 + * mapping between RBDs and RBs. + * + * Driver must allocate host DRAM memory for the following, and set the + * physical address of each into 4965 registers: + * + * 1) Receive Buffer Descriptor (RBD) circular buffer (CB), typically with 256 + * entries (although any power of 2, up to 4096, is selectable by driver). + * Each entry (1 dword) points to a receive buffer (RB) of consistent size + * (typically 4K, although 8K or 16K are also selectable by driver). + * Driver sets up RB size and number of RBDs in the CB via Rx config + * register FH_MEM_RCSR_CHNL0_CONFIG_REG. + * + * Bit fields within one RBD: + * 27-0: Receive Buffer physical address bits [35:8], 256-byte aligned + * + * Driver sets physical address [35:8] of base of RBD circular buffer + * into FH_RSCSR_CHNL0_RBDCB_BASE_REG [27:0]. + * + * 2) Rx status buffer, 8 bytes, in which 4965 indicates which Rx Buffers + * (RBs) have been filled, via a "write pointer", actually the index of + * the RB's corresponding RBD within the circular buffer. Driver sets + * physical address [35:4] into FH_RSCSR_CHNL0_STTS_WPTR_REG [31:0]. + * + * Bit fields in lower dword of Rx status buffer (upper dword not used + * by driver; see struct iwl4965_shared, val0): + * 31-12: Not used by driver + * 11- 0: Index of last filled Rx buffer descriptor + * (4965 writes, driver reads this value) + * + * As the driver prepares Receive Buffers (RBs) for 4965 to fill, driver must + * enter pointers to these RBs into contiguous RBD circular buffer entries, + * and update the 4965's "write" index register, + * FH_RSCSR_CHNL0_RBDCB_WPTR_REG. + * + * This "write" index corresponds to the *next* RBD that the driver will make + * available, i.e. one RBD past the tail of the ready-to-fill RBDs within + * the circular buffer. This value should initially be 0 (before preparing any + * RBs), should be 8 after preparing the first 8 RBs (for example), and must + * wrap back to 0 at the end of the circular buffer (but don't wrap before + * "read" index has advanced past 1! See below). + * NOTE: 4965 EXPECTS THE WRITE INDEX TO BE INCREMENTED IN MULTIPLES OF 8. + * + * As the 4965 fills RBs (referenced from contiguous RBDs within the circular + * buffer), it updates the Rx status buffer in host DRAM, 2) described above, + * to tell the driver the index of the latest filled RBD. The driver must + * read this "read" index from DRAM after receiving an Rx interrupt from 4965. + * + * The driver must also internally keep track of a third index, which is the + * next RBD to process. When receiving an Rx interrupt, driver should process + * all filled but unprocessed RBs up to, but not including, the RB + * corresponding to the "read" index. For example, if "read" index becomes "1", + * driver may process the RB pointed to by RBD 0. Depending on volume of + * traffic, there may be many RBs to process. + * + * If read index == write index, 4965 thinks there is no room to put new data. + * Due to this, the maximum number of filled RBs is 255, instead of 256. To + * be safe, make sure that there is a gap of at least 2 RBDs between "write" + * and "read" indexes; that is, make sure that there are no more than 254 + * buffers waiting to be filled. + */ +#define FH_MEM_RSCSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xBC0) +#define FH_MEM_RSCSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xC00) +#define FH_MEM_RSCSR_CHNL0 (FH_MEM_RSCSR_LOWER_BOUND) + +/** + * Physical base address of 8-byte Rx Status buffer. + * Bit fields: + * 31-0: Rx status buffer physical base address [35:4], must 16-byte aligned. + */ +#define FH_RSCSR_CHNL0_STTS_WPTR_REG (FH_MEM_RSCSR_CHNL0) + +/** + * Physical base address of Rx Buffer Descriptor Circular Buffer. + * Bit fields: + * 27-0: RBD CD physical base address [35:8], must be 256-byte aligned. + */ +#define FH_RSCSR_CHNL0_RBDCB_BASE_REG (FH_MEM_RSCSR_CHNL0 + 0x004) + +/** + * Rx write pointer (index, really!). + * Bit fields: + * 11-0: Index of driver's most recent prepared-to-be-filled RBD, + 1. + * NOTE: For 256-entry circular buffer, use only bits [7:0]. + */ +#define FH_RSCSR_CHNL0_RBDCB_WPTR_REG (FH_MEM_RSCSR_CHNL0 + 0x008) +#define FH_RSCSR_CHNL0_WPTR (FH_RSCSR_CHNL0_RBDCB_WPTR_REG) + + +/** + * Rx Config/Status Registers (RCSR) + * Rx Config Reg for channel 0 (only channel used) + * + * Driver must initialize FH_MEM_RCSR_CHNL0_CONFIG_REG as follows for + * normal operation (see bit fields). + * + * Clearing FH_MEM_RCSR_CHNL0_CONFIG_REG to 0 turns off Rx DMA. + * Driver should poll FH_MEM_RSSR_RX_STATUS_REG for + * FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE (bit 24) before continuing. + * + * Bit fields: + * 31-30: Rx DMA channel enable: '00' off/pause, '01' pause at end of frame, + * '10' operate normally + * 29-24: reserved + * 23-20: # RBDs in circular buffer = 2^value; use "8" for 256 RBDs (normal), + * min "5" for 32 RBDs, max "12" for 4096 RBDs. + * 19-18: reserved + * 17-16: size of each receive buffer; '00' 4K (normal), '01' 8K, + * '10' 12K, '11' 16K. + * 15-14: reserved + * 13-12: IRQ destination; '00' none, '01' host driver (normal operation) + * 11- 4: timeout for closing Rx buffer and interrupting host (units 32 usec) + * typical value 0x10 (about 1/2 msec) + * 3- 0: reserved + */ +#define FH_MEM_RCSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xC00) +#define FH_MEM_RCSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xCC0) +#define FH_MEM_RCSR_CHNL0 (FH_MEM_RCSR_LOWER_BOUND) + +#define FH_MEM_RCSR_CHNL0_CONFIG_REG (FH_MEM_RCSR_CHNL0) + +#define FH_RCSR_CHNL0_RX_CONFIG_RB_TIMEOUT_MSK (0x00000FF0) /* bits 4-11 */ +#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_MSK (0x00001000) /* bits 12 */ +#define FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MSK (0x00008000) /* bit 15 */ +#define FH_RCSR_CHNL0_RX_CONFIG_RB_SIZE_MSK (0x00030000) /* bits 16-17 */ +#define FH_RCSR_CHNL0_RX_CONFIG_RBDBC_SIZE_MSK (0x00F00000) /* bits 20-23 */ +#define FH_RCSR_CHNL0_RX_CONFIG_DMA_CHNL_EN_MSK (0xC0000000) /* bits 30-31*/ + +#define FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT (20) +#define FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_BITSHIFT (4) +#define RX_RB_TIMEOUT (0x10) + +#define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_VAL (0x00000000) +#define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_EOF_VAL (0x40000000) +#define FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL (0x80000000) + +#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K (0x00000000) +#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K (0x00010000) +#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_12K (0x00020000) +#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_16K (0x00030000) + +#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_NO_INT_VAL (0x00000000) +#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL (0x00001000) + + +/** + * Rx Shared Status Registers (RSSR) + * + * After stopping Rx DMA channel (writing 0 to + * FH_MEM_RCSR_CHNL0_CONFIG_REG), driver must poll + * FH_MEM_RSSR_RX_STATUS_REG until Rx channel is idle. + * + * Bit fields: + * 24: 1 = Channel 0 is idle + * + * FH_MEM_RSSR_SHARED_CTRL_REG and FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV + * contain default values that should not be altered by the driver. + */ +#define FH_MEM_RSSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xC40) +#define FH_MEM_RSSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xD00) + +#define FH_MEM_RSSR_SHARED_CTRL_REG (FH_MEM_RSSR_LOWER_BOUND) +#define FH_MEM_RSSR_RX_STATUS_REG (FH_MEM_RSSR_LOWER_BOUND + 0x004) +#define FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV\ + (FH_MEM_RSSR_LOWER_BOUND + 0x008) + +#define FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE (0x01000000) + + +/** + * Transmit DMA Channel Control/Status Registers (TCSR) + * + * 4965 has one configuration register for each of 8 Tx DMA/FIFO channels + * supported in hardware (don't confuse these with the 16 Tx queues in DRAM, + * which feed the DMA/FIFO channels); config regs are separated by 0x20 bytes. + * + * To use a Tx DMA channel, driver must initialize its + * FH_TCSR_CHNL_TX_CONFIG_REG(chnl) with: + * + * FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | + * FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL + * + * All other bits should be 0. + * + * Bit fields: + * 31-30: Tx DMA channel enable: '00' off/pause, '01' pause at end of frame, + * '10' operate normally + * 29- 4: Reserved, set to "0" + * 3: Enable internal DMA requests (1, normal operation), disable (0) + * 2- 0: Reserved, set to "0" + */ +#define FH_TCSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xD00) +#define FH_TCSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xE60) + +/* Find Control/Status reg for given Tx DMA/FIFO channel */ +#define FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \ + (FH_TCSR_LOWER_BOUND + 0x20 * _chnl) + +#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL (0x00000000) +#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL (0x00000008) + +#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE (0x00000000) +#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE_EOF (0x40000000) +#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE (0x80000000) + +#define FH_TCSR_CHNL_NUM (7) + +#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_EMPTY (0x00000000) +#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_WAIT (0x00002000) +#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID (0x00000003) + +#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_NOINT (0x00000000) +#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD (0x00100000) +#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD (0x00200000) + +#define FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM (20) +#define FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX (12) +#define FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \ + (FH_TCSR_LOWER_BOUND + 0x20 * _chnl) +#define FH_TCSR_CHNL_TX_CREDIT_REG(_chnl) \ + (FH_TCSR_LOWER_BOUND + 0x20 * _chnl + 0x4) +#define FH_TCSR_CHNL_TX_BUF_STS_REG(_chnl) \ + (FH_TCSR_LOWER_BOUND + 0x20 * _chnl + 0x8) + +/** + * Tx Shared Status Registers (TSSR) + * + * After stopping Tx DMA channel (writing 0 to + * FH_TCSR_CHNL_TX_CONFIG_REG(chnl)), driver must poll + * FH_TSSR_TX_STATUS_REG until selected Tx channel is idle + * (channel's buffers empty | no pending requests). + * + * Bit fields: + * 31-24: 1 = Channel buffers empty (channel 7:0) + * 23-16: 1 = No pending requests (channel 7:0) + */ +#define FH_TSSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xEA0) +#define FH_TSSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xEC0) + +#define FH_TSSR_TX_STATUS_REG (FH_TSSR_LOWER_BOUND + 0x010) + +#define FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) ((1 << (_chnl)) << 24) +#define FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl) ((1 << (_chnl)) << 16) + +#define FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(_chnl) \ + (FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) | \ + FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl)) + + + +#define FH_REGS_LOWER_BOUND (0x1000) +#define FH_REGS_UPPER_BOUND (0x2000) + +/* Tx service channels */ +#define FH_SRVC_CHNL (9) +#define FH_SRVC_LOWER_BOUND (FH_REGS_LOWER_BOUND + 0x9C8) +#define FH_SRVC_UPPER_BOUND (FH_REGS_LOWER_BOUND + 0x9D0) +#define FH_SRVC_CHNL_SRAM_ADDR_REG(_chnl) \ + (FH_SRVC_LOWER_BOUND + ((_chnl) - 9) * 0x4) + +/* TFDB Area - TFDs buffer table */ +#define FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK (0xFFFFFFFF) +#define FH_TFDIB_LOWER_BOUND (FH_REGS_LOWER_BOUND + 0x900) +#define FH_TFDIB_UPPER_BOUND (FH_REGS_LOWER_BOUND + 0x958) +#define FH_TFDIB_CTRL0_REG(_chnl) (FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl)) +#define FH_TFDIB_CTRL1_REG(_chnl) (FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl) + 0x4) + +/* TCSR: tx_config register values */ +#define FH_RSCSR_FRAME_SIZE_MSK (0x00003FFF) /* bits 0-13 */ + -- cgit v1.2.3-70-g09d2 From f93d65feb3dc48fe5e285fa5a35dacea3601835f Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 23 Apr 2008 17:15:08 -0700 Subject: iwlwifi: 3945 remove unused SCD definitions This patch remove SCD definitions form iwl-3945-hw.h The values from iwl-prph.h are used Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945-hw.h | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h index 8821c26992f..644bd9e0805 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h @@ -289,17 +289,6 @@ struct iwl3945_eeprom { #define PCI_REG_WUM8 0x0E8 #define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT (0x80000000) -/* SCD (3945 Tx Frame Scheduler) */ -#define SCD_BASE (CSR_BASE + 0x2E00) - -#define SCD_MODE_REG (SCD_BASE + 0x000) -#define SCD_ARASTAT_REG (SCD_BASE + 0x004) -#define SCD_TXFACT_REG (SCD_BASE + 0x010) -#define SCD_TXF4MF_REG (SCD_BASE + 0x014) -#define SCD_TXF5MF_REG (SCD_BASE + 0x020) -#define SCD_SBYP_MODE_1_REG (SCD_BASE + 0x02C) -#define SCD_SBYP_MODE_2_REG (SCD_BASE + 0x030) - /*=== FH (data Flow Handler) ===*/ #define FH_BASE (0x800) -- cgit v1.2.3-70-g09d2 From e40ac414c0130358f9eb068f4993a37f013621be Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 25 Apr 2008 21:10:54 +0200 Subject: b43: Don't disable IRQs in mac_suspend This patch removes the IRQ-disable from mac_suspend. The main advantage of this is to get rid of the IRQ-sync call in mac_suspend. We need to remove the MAC suspend bit from the IRQ service mask, as otherwise the IRQ handler would race with us. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/b43.h | 3 +-- drivers/net/wireless/b43/main.c | 13 ------------- 2 files changed, 1 insertion(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 37783cdd301..7d034df250b 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -410,8 +410,7 @@ enum { #define B43_IRQ_TIMEOUT 0x80000000 #define B43_IRQ_ALL 0xFFFFFFFF -#define B43_IRQ_MASKTEMPLATE (B43_IRQ_MAC_SUSPENDED | \ - B43_IRQ_TBTT_INDI | \ +#define B43_IRQ_MASKTEMPLATE (B43_IRQ_TBTT_INDI | \ B43_IRQ_ATIM_END | \ B43_IRQ_PMQ | \ B43_IRQ_MAC_TXERR | \ diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index e3d8555d4a9..cf546e367d3 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -2322,11 +2322,6 @@ void b43_mac_enable(struct b43_wldev *dev) b43_read32(dev, B43_MMIO_MACCTL); b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); b43_power_saving_ctl_bits(dev, 0); - - /* Re-enable IRQs. */ - spin_lock_irq(&dev->wl->irq_lock); - b43_interrupt_enable(dev, dev->irq_savedstate); - spin_unlock_irq(&dev->wl->irq_lock); } } @@ -2340,14 +2335,6 @@ void b43_mac_suspend(struct b43_wldev *dev) B43_WARN_ON(dev->mac_suspended < 0); if (dev->mac_suspended == 0) { - /* Mask IRQs before suspending MAC. Otherwise - * the MAC stays busy and won't suspend. */ - spin_lock_irq(&dev->wl->irq_lock); - tmp = b43_interrupt_disable(dev, B43_IRQ_ALL); - spin_unlock_irq(&dev->wl->irq_lock); - b43_synchronize_irq(dev); - dev->irq_savedstate = tmp; - b43_power_saving_ctl_bits(dev, B43_PS_AWAKE); b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL) -- cgit v1.2.3-70-g09d2 From 2d9ccf842905063f774c28f329ac5ab3a84d3571 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 21 Apr 2008 18:59:48 +0200 Subject: rt2x00: Support hardware RTS and CTS-to-self frames If the driver has set the set_rts_threshold() callback function to mac80211 it is capable of generating RTS and CTS-to-self frames inside the hardware and rt2x00lib doesn't have to create them in software. Only rt2800pci and rt2800usb support this feature. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00mac.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index c206b509207..e46d406637f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -118,11 +118,16 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, * create and queue that frame first. But make sure we have * at least enough entries available to send this CTS/RTS * frame as well as the data frame. + * Note that when the driver has set the set_rts_threshold() + * callback function it doesn't need software generation of + * neither RTS or CTS-to-self frames and handles everything + * inside the hardware. */ frame_control = le16_to_cpu(ieee80211hdr->frame_control); if (!is_rts_frame(frame_control) && !is_cts_frame(frame_control) && (control->flags & (IEEE80211_TXCTL_USE_RTS_CTS | - IEEE80211_TXCTL_USE_CTS_PROTECT))) { + IEEE80211_TXCTL_USE_CTS_PROTECT)) && + !rt2x00dev->ops->hw->set_rts_threshold) { if (rt2x00queue_available(queue) <= 1) { ieee80211_stop_queue(rt2x00dev->hw, control->queue); return NETDEV_TX_BUSY; -- cgit v1.2.3-70-g09d2 From 62e70cf8568151a41e8525ddf0e56c0380a71cfd Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 21 Apr 2008 18:59:54 +0200 Subject: rt2x00: Remove DRIVER_SUPPORT_MIXED_INTERFACES A lot more is needed to support mixed interfaces then just this flag, such things need new redesigns in rt2x00lib to actually make it happen. So far there doesn't exist a Ralink chipset that can handle it, so we might as well remove the flag for now and see what should be done whenever a device appears that can handle it. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00.h | 1 - drivers/net/wireless/rt2x00/rt2x00mac.c | 11 +++++------ 2 files changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 57bdc153952..7a23b00c689 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -621,7 +621,6 @@ enum rt2x00_flags { /* * Driver features */ - DRIVER_SUPPORT_MIXED_INTERFACES, DRIVER_REQUIRE_FIRMWARE, DRIVER_REQUIRE_BEACON_GUARD, DRIVER_REQUIRE_ATIM_QUEUE, diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index e46d406637f..e078e0ad0d0 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -201,13 +201,12 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, return -ENODEV; /* - * When we don't support mixed interfaces (a combination - * of sta and ap virtual interfaces) then we can only - * add this interface when the rival interface count is 0. + * We don't support mixed combinations of sta and ap virtual + * interfaces. We can only add this interface when the rival + * interface count is 0. */ - if (!test_bit(DRIVER_SUPPORT_MIXED_INTERFACES, &rt2x00dev->flags) && - ((conf->type == IEEE80211_IF_TYPE_AP && rt2x00dev->intf_sta_count) || - (conf->type != IEEE80211_IF_TYPE_AP && rt2x00dev->intf_ap_count))) + if ((conf->type == IEEE80211_IF_TYPE_AP && rt2x00dev->intf_sta_count) || + (conf->type != IEEE80211_IF_TYPE_AP && rt2x00dev->intf_ap_count)) return -ENOBUFS; /* -- cgit v1.2.3-70-g09d2 From e58c6aca99357d7f85f18e0b661d8c5a87f926a9 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 21 Apr 2008 19:00:47 +0200 Subject: rt2x00: Use rt2x00 queue numbering Use the rt2x00 queue enumeration as much as possible, removing the usage of the mac80211 queue numbering wherever it is possible. This makes it easier for mac80211 to change it queue identification scheme without having to deal with big changes in the rt2x00 code. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 32 +++++++++---------------- drivers/net/wireless/rt2x00/rt2500pci.c | 35 ++++++++++----------------- drivers/net/wireless/rt2x00/rt2500usb.c | 12 +++------- drivers/net/wireless/rt2x00/rt2x00.h | 9 ++++--- drivers/net/wireless/rt2x00/rt2x00dev.c | 3 +-- drivers/net/wireless/rt2x00/rt2x00mac.c | 13 +++++----- drivers/net/wireless/rt2x00/rt2x00pci.c | 2 +- drivers/net/wireless/rt2x00/rt2x00queue.c | 6 ++--- drivers/net/wireless/rt2x00/rt2x00queue.h | 40 ++++++++++++++++++++----------- drivers/net/wireless/rt2x00/rt2x00usb.c | 2 +- drivers/net/wireless/rt2x00/rt61pci.c | 27 +++++++-------------- drivers/net/wireless/rt2x00/rt73usb.c | 15 ++++-------- 12 files changed, 80 insertions(+), 116 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 560b9c73c0b..705bc2d41dc 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1055,11 +1055,11 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, * TX data initialization */ static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, - const unsigned int queue) + const enum data_queue_qid queue) { u32 reg; - if (queue == RT2X00_BCN_QUEUE_BEACON) { + if (queue == QID_BEACON) { rt2x00pci_register_read(rt2x00dev, CSR14, ®); if (!rt2x00_get_field32(reg, CSR14_BEACON_GEN)) { rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); @@ -1071,12 +1071,9 @@ static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, } rt2x00pci_register_read(rt2x00dev, TXCSR0, ®); - rt2x00_set_field32(®, TXCSR0_KICK_PRIO, - (queue == IEEE80211_TX_QUEUE_DATA0)); - rt2x00_set_field32(®, TXCSR0_KICK_TX, - (queue == IEEE80211_TX_QUEUE_DATA1)); - rt2x00_set_field32(®, TXCSR0_KICK_ATIM, - (queue == RT2X00_BCN_QUEUE_ATIM)); + rt2x00_set_field32(®, TXCSR0_KICK_PRIO, (queue == QID_AC_BE)); + rt2x00_set_field32(®, TXCSR0_KICK_TX, (queue == QID_AC_BK)); + rt2x00_set_field32(®, TXCSR0_KICK_ATIM, (queue == QID_ATIM)); rt2x00pci_register_write(rt2x00dev, TXCSR0, reg); } @@ -1120,7 +1117,7 @@ static void rt2400pci_fill_rxdone(struct queue_entry *entry, * Interrupt functions. */ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, - const enum ieee80211_tx_queue queue_idx) + const enum data_queue_qid queue_idx) { struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, queue_idx); struct queue_entry_priv_pci_tx *priv_tx; @@ -1187,19 +1184,19 @@ static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance) * 3 - Atim ring transmit done interrupt. */ if (rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING)) - rt2400pci_txdone(rt2x00dev, RT2X00_BCN_QUEUE_ATIM); + rt2400pci_txdone(rt2x00dev, QID_ATIM); /* * 4 - Priority ring transmit done interrupt. */ if (rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING)) - rt2400pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_DATA0); + rt2400pci_txdone(rt2x00dev, QID_AC_BE); /* * 5 - Tx ring transmit done interrupt. */ if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING)) - rt2400pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_DATA1); + rt2400pci_txdone(rt2x00dev, QID_AC_BK); return IRQ_HANDLED; } @@ -1520,21 +1517,14 @@ static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); rt2x00pci_register_write(rt2x00dev, CSR14, reg); - /* - * mac80211 doesn't provide the control->queue variable - * for beacons. Set our own queue identification so - * it can be used during descriptor initialization. - */ - control->queue = RT2X00_BCN_QUEUE_BEACON; - rt2x00lib_write_tx_desc(rt2x00dev, skb, control); - /* * Enable beacon generation. * Write entire beacon with descriptor to register, * and kick the beacon generator. */ + rt2x00lib_write_tx_desc(rt2x00dev, skb, control); memcpy(priv_tx->data, skb->data, skb->len); - rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, control->queue); + rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON); return 0; } diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index a5ed54b6926..0d53c75d55d 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -317,8 +317,7 @@ static void rt2500pci_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00intf_conf *conf, const unsigned int flags) { - struct data_queue *queue = - rt2x00queue_get_queue(rt2x00dev, RT2X00_BCN_QUEUE_BEACON); + struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, QID_BEACON); unsigned int bcn_preload; u32 reg; @@ -1210,11 +1209,11 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, * TX data initialization */ static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, - const unsigned int queue) + const enum data_queue_qid queue) { u32 reg; - if (queue == RT2X00_BCN_QUEUE_BEACON) { + if (queue == QID_BEACON) { rt2x00pci_register_read(rt2x00dev, CSR14, ®); if (!rt2x00_get_field32(reg, CSR14_BEACON_GEN)) { rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); @@ -1226,12 +1225,9 @@ static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, } rt2x00pci_register_read(rt2x00dev, TXCSR0, ®); - rt2x00_set_field32(®, TXCSR0_KICK_PRIO, - (queue == IEEE80211_TX_QUEUE_DATA0)); - rt2x00_set_field32(®, TXCSR0_KICK_TX, - (queue == IEEE80211_TX_QUEUE_DATA1)); - rt2x00_set_field32(®, TXCSR0_KICK_ATIM, - (queue == RT2X00_BCN_QUEUE_ATIM)); + rt2x00_set_field32(®, TXCSR0_KICK_PRIO, (queue == QID_AC_BE)); + rt2x00_set_field32(®, TXCSR0_KICK_TX, (queue == QID_AC_BK)); + rt2x00_set_field32(®, TXCSR0_KICK_ATIM, (queue == QID_ATIM)); rt2x00pci_register_write(rt2x00dev, TXCSR0, reg); } @@ -1276,7 +1272,7 @@ static void rt2500pci_fill_rxdone(struct queue_entry *entry, * Interrupt functions. */ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev, - const enum ieee80211_tx_queue queue_idx) + const enum data_queue_qid queue_idx) { struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, queue_idx); struct queue_entry_priv_pci_tx *priv_tx; @@ -1343,19 +1339,19 @@ static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance) * 3 - Atim ring transmit done interrupt. */ if (rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING)) - rt2500pci_txdone(rt2x00dev, RT2X00_BCN_QUEUE_ATIM); + rt2500pci_txdone(rt2x00dev, QID_ATIM); /* * 4 - Priority ring transmit done interrupt. */ if (rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING)) - rt2500pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_DATA0); + rt2500pci_txdone(rt2x00dev, QID_AC_BE); /* * 5 - Tx ring transmit done interrupt. */ if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING)) - rt2500pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_DATA1); + rt2500pci_txdone(rt2x00dev, QID_AC_BK); return IRQ_HANDLED; } @@ -1833,21 +1829,14 @@ static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); rt2x00pci_register_write(rt2x00dev, CSR14, reg); - /* - * mac80211 doesn't provide the control->queue variable - * for beacons. Set our own queue identification so - * it can be used during descriptor initialization. - */ - control->queue = RT2X00_BCN_QUEUE_BEACON; - rt2x00lib_write_tx_desc(rt2x00dev, skb, control); - /* * Enable beacon generation. * Write entire beacon with descriptor to register, * and kick the beacon generator. */ + rt2x00lib_write_tx_desc(rt2x00dev, skb, control); memcpy(priv_tx->data, skb->data, skb->len); - rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, control->queue); + rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON); return 0; } diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index fdbd0ef2be4..0dac1f5b5c4 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1094,11 +1094,11 @@ static int rt2500usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev, * TX data initialization */ static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, - const unsigned int queue) + const enum data_queue_qid queue) { u16 reg; - if (queue != RT2X00_BCN_QUEUE_BEACON) + if (queue != QID_BEACON) return; rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®); @@ -1720,12 +1720,6 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw, rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 0); rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); - /* - * mac80211 doesn't provide the control->queue variable - * for beacons. Set our own queue identification so - * it can be used during descriptor initialization. - */ - control->queue = RT2X00_BCN_QUEUE_BEACON; rt2x00lib_write_tx_desc(rt2x00dev, skb, control); /* @@ -1757,7 +1751,7 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw, /* * Enable beacon generation. */ - rt2500usb_kick_tx_queue(rt2x00dev, control->queue); + rt2500usb_kick_tx_queue(rt2x00dev, QID_BEACON); return 0; } diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 7a23b00c689..d85553f6351 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -548,7 +548,7 @@ struct rt2x00lib_ops { int (*get_tx_data_len) (struct rt2x00_dev *rt2x00dev, struct sk_buff *skb); void (*kick_tx_queue) (struct rt2x00_dev *rt2x00dev, - const unsigned int queue); + const enum data_queue_qid queue); /* * RX control handlers @@ -927,13 +927,12 @@ static inline u16 get_duration_res(const unsigned int size, const u8 rate) } /** - * rt2x00queue_get_queue - Convert mac80211 queue index to rt2x00 queue + * rt2x00queue_get_queue - Convert queue index to queue pointer * @rt2x00dev: Pointer to &struct rt2x00_dev. - * @queue: mac80211/rt2x00 queue index - * (see &enum ieee80211_tx_queue and &enum rt2x00_bcn_queue). + * @queue: rt2x00 queue index (see &enum data_queue_qid). */ struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev, - const unsigned int queue); + const enum data_queue_qid queue); /** * rt2x00queue_get_entry - Get queue entry where the given index points to. diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 8d8657fb64d..b1a324dead5 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -687,8 +687,7 @@ void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev, * Beacons and probe responses require the tsf timestamp * to be inserted into the frame. */ - if (control->queue == RT2X00_BCN_QUEUE_BEACON || - is_probe_resp(frame_control)) + if (txdesc.queue == QID_BEACON || is_probe_resp(frame_control)) __set_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc.flags); /* diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index e078e0ad0d0..d4ceab7646e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -81,6 +81,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, { struct rt2x00_dev *rt2x00dev = hw->priv; struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data; + enum data_queue_qid qid = mac80211_queue_to_qid(control->queue); struct data_queue *queue; struct skb_frame_desc *skbdesc; u16 frame_control; @@ -101,14 +102,13 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, */ if (control->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM && test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags)) - queue = rt2x00queue_get_queue(rt2x00dev, RT2X00_BCN_QUEUE_ATIM); + queue = rt2x00queue_get_queue(rt2x00dev, QID_ATIM); else - queue = rt2x00queue_get_queue(rt2x00dev, control->queue); + queue = rt2x00queue_get_queue(rt2x00dev, qid); if (unlikely(!queue)) { ERROR(rt2x00dev, "Attempt to send packet over invalid queue %d.\n" - "Please file bug report to %s.\n", - control->queue, DRV_PROJECT); + "Please file bug report to %s.\n", qid, DRV_PROJECT); dev_kfree_skb_any(skb); return NETDEV_TX_OK; } @@ -154,7 +154,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, ieee80211_stop_queue(rt2x00dev->hw, control->queue); if (rt2x00dev->ops->lib->kick_tx_queue) - rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, control->queue); + rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, qid); return NETDEV_TX_OK; } @@ -187,8 +187,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, { struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_intf *intf = vif_to_intf(conf->vif); - struct data_queue *queue = - rt2x00queue_get_queue(rt2x00dev, RT2X00_BCN_QUEUE_BEACON); + struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, QID_BEACON); struct queue_entry *entry = NULL; unsigned int i; diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index 7867ec64bd2..9e5d94e44c5 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -53,7 +53,7 @@ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev, ERROR(rt2x00dev, "Arrived at non-free entry in the non-full queue %d.\n" "Please file bug report to %s.\n", - control->queue, DRV_PROJECT); + entry->queue->qid, DRV_PROJECT); return -EINVAL; } diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 659e9f44c40..e5b861f8416 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -30,7 +30,7 @@ #include "rt2x00lib.h" struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev, - const unsigned int queue) + const enum data_queue_qid queue) { int atim = test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags); @@ -40,9 +40,9 @@ struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev, if (!rt2x00dev->bcn) return NULL; - if (queue == RT2X00_BCN_QUEUE_BEACON) + if (queue == QID_BEACON) return &rt2x00dev->bcn[0]; - else if (queue == RT2X00_BCN_QUEUE_ATIM && atim) + else if (queue == QID_ATIM && atim) return &rt2x00dev->bcn[1]; return NULL; diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 7027c9f47d3..29fe2652555 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -54,6 +54,17 @@ /** * enum data_queue_qid: Queue identification + * + * @QID_AC_BE: AC BE queue + * @QID_AC_BK: AC BK queue + * @QID_AC_VI: AC VI queue + * @QID_AC_VO: AC VO queue + * @QID_HCCA: HCCA queue + * @QID_MGMT: MGMT queue (prio queue) + * @QID_RX: RX queue + * @QID_OTHER: None of the above (don't use, only present for completeness) + * @QID_BEACON: Beacon queue (value unspecified, don't send it to device) + * @QID_ATIM: Atim queue (value unspeficied, don't send it to device) */ enum data_queue_qid { QID_AC_BE = 0, @@ -64,22 +75,25 @@ enum data_queue_qid { QID_MGMT = 13, QID_RX = 14, QID_OTHER = 15, + QID_BEACON, + QID_ATIM, }; /** - * enum rt2x00_bcn_queue: Beacon queue index - * - * Start counting with a high offset, this because this enumeration - * supplements &enum ieee80211_tx_queue and we should prevent value - * conflicts. - * - * @RT2X00_BCN_QUEUE_BEACON: Beacon queue - * @RT2X00_BCN_QUEUE_ATIM: Atim queue (sends frame after beacon) + * mac80211_queue_to_qid - Convert mac80211 queue to rt2x00 qid + * @queue: mac80211 queue. */ -enum rt2x00_bcn_queue { - RT2X00_BCN_QUEUE_BEACON = 100, - RT2X00_BCN_QUEUE_ATIM = 101, -}; +static inline enum data_queue_qid mac80211_queue_to_qid(unsigned int queue) +{ + /* Regular TX queues are mapped directly */ + if (queue < NUM_TX_DATA_QUEUES) + return queue; + else if (queue == IEEE80211_TX_QUEUE_BEACON) + return QID_BEACON; + else if (queue == IEEE80211_TX_QUEUE_AFTER_BEACON) + return QID_ATIM; + return QID_OTHER; +} /** * enum skb_frame_desc_flags: Flags for &struct skb_frame_desc @@ -105,7 +119,6 @@ enum skb_frame_desc_flags { * of the scope of the skb->data pointer. * @data_len: Length of the frame data. * @desc_len: Length of the frame descriptor. - * @entry: The entry to which this sk buffer belongs. */ struct skb_frame_desc { @@ -240,7 +253,6 @@ struct txentry_desc { * encryption or decryption. The entry should only be touched after * the device has signaled it is done with it. */ - enum queue_entry_flags { ENTRY_BCN_ASSIGNED, ENTRY_OWNER_DEVICE_DATA, diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 5a331674dcb..47f96b34087 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -186,7 +186,7 @@ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, ERROR(rt2x00dev, "Arrived at non-free entry in the non-full queue %d.\n" "Please file bug report to %s.\n", - control->queue, DRV_PROJECT); + entry->queue->qid, DRV_PROJECT); return -EINVAL; } diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index ae12dcdd3c2..98af4d26583 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1591,11 +1591,11 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, * TX data initialization */ static void rt61pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, - const unsigned int queue) + const enum data_queue_qid queue) { u32 reg; - if (queue == RT2X00_BCN_QUEUE_BEACON) { + if (queue == QID_BEACON) { /* * For Wi-Fi faily generated beacons between participating * stations. Set TBTT phase adaptive adjustment step to 8us. @@ -1613,14 +1613,10 @@ static void rt61pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, } rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, ®); - rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC0, - (queue == IEEE80211_TX_QUEUE_DATA0)); - rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC1, - (queue == IEEE80211_TX_QUEUE_DATA1)); - rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC2, - (queue == IEEE80211_TX_QUEUE_DATA2)); - rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC3, - (queue == IEEE80211_TX_QUEUE_DATA3)); + rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC0, (queue == QID_AC_BE)); + rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC1, (queue == QID_AC_BK)); + rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC2, (queue == QID_AC_VI)); + rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC3, (queue == QID_AC_VO)); rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg); } @@ -2411,22 +2407,15 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); - /* - * mac80211 doesn't provide the control->queue variable - * for beacons. Set our own queue identification so - * it can be used during descriptor initialization. - */ - control->queue = RT2X00_BCN_QUEUE_BEACON; - rt2x00lib_write_tx_desc(rt2x00dev, skb, control); - /* * Write entire beacon with descriptor to register, * and kick the beacon generator. */ + rt2x00lib_write_tx_desc(rt2x00dev, skb, control); beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx); rt2x00pci_register_multiwrite(rt2x00dev, beacon_base, skb->data, skb->len); - rt61pci_kick_tx_queue(rt2x00dev, control->queue); + rt61pci_kick_tx_queue(rt2x00dev, QID_BEACON); return 0; } diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index da19a3a91f4..a6419c90077 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1331,11 +1331,11 @@ static int rt73usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev, * TX data initialization */ static void rt73usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, - const unsigned int queue) + const enum data_queue_qid queue) { u32 reg; - if (queue != RT2X00_BCN_QUEUE_BEACON) + if (queue != QID_BEACON) return; /* @@ -2000,24 +2000,17 @@ static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); - /* - * mac80211 doesn't provide the control->queue variable - * for beacons. Set our own queue identification so - * it can be used during descriptor initialization. - */ - control->queue = RT2X00_BCN_QUEUE_BEACON; - rt2x00lib_write_tx_desc(rt2x00dev, skb, control); - /* * Write entire beacon with descriptor to register, * and kick the beacon generator. */ + rt2x00lib_write_tx_desc(rt2x00dev, skb, control); beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx); timeout = REGISTER_TIMEOUT * (skb->len / sizeof(u32)); rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE, USB_VENDOR_REQUEST_OUT, beacon_base, 0, skb->data, skb->len, timeout); - rt73usb_kick_tx_queue(rt2x00dev, control->queue); + rt73usb_kick_tx_queue(rt2x00dev, QID_BEACON); return 0; } -- cgit v1.2.3-70-g09d2 From bd394a74a0e81efb15feaa8d7d10a0eaa8f4bf07 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 21 Apr 2008 19:01:58 +0200 Subject: rt2x00: Add helper macros Add some helper macro's to help determining the the timeout for USB register access. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2500usb.c | 8 ++++---- drivers/net/wireless/rt2x00/rt2x00usb.c | 2 +- drivers/net/wireless/rt2x00/rt2x00usb.h | 19 ++++++++++++++++--- drivers/net/wireless/rt2x00/rt73usb.c | 18 ++++++++---------- 4 files changed, 29 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 0dac1f5b5c4..80b34d47114 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -76,10 +76,10 @@ static inline void rt2500usb_register_multiread(struct rt2x00_dev *rt2x00dev, const unsigned int offset, void *value, const u16 length) { - int timeout = REGISTER_TIMEOUT * (length / sizeof(u16)); rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ, USB_VENDOR_REQUEST_IN, offset, - value, length, timeout); + value, length, + REGISTER_TIMEOUT16(length)); } static inline void rt2500usb_register_write(struct rt2x00_dev *rt2x00dev, @@ -106,10 +106,10 @@ static inline void rt2500usb_register_multiwrite(struct rt2x00_dev *rt2x00dev, const unsigned int offset, void *value, const u16 length) { - int timeout = REGISTER_TIMEOUT * (length / sizeof(u16)); rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE, USB_VENDOR_REQUEST_OUT, offset, - value, length, timeout); + value, length, + REGISTER_TIMEOUT16(length)); } static u16 rt2500usb_bbp_check(struct rt2x00_dev *rt2x00dev) diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 47f96b34087..98aafc2d584 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -344,7 +344,7 @@ void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev) struct data_queue *queue; unsigned int i; - rt2x00usb_vendor_request_sw(rt2x00dev, USB_RX_CONTROL, 0x0000, 0x0000, + rt2x00usb_vendor_request_sw(rt2x00dev, USB_RX_CONTROL, 0, 0, REGISTER_TIMEOUT); /* diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index 11e55180cba..1efaaae0463 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h @@ -47,6 +47,20 @@ #define REGISTER_TIMEOUT 500 #define REGISTER_TIMEOUT_FIRMWARE 1000 +/** + * REGISTER_TIMEOUT16 - Determine the timeout for 16bit register access + * @__datalen: Data length + */ +#define REGISTER_TIMEOUT16(__datalen) \ + ( REGISTER_TIMEOUT * ((__datalen) / sizeof(u16)) ) + +/** + * REGISTER_TIMEOUT32 - Determine the timeout for 32bit register access + * @__datalen: Data length + */ +#define REGISTER_TIMEOUT32(__datalen) \ + ( REGISTER_TIMEOUT * ((__datalen) / sizeof(u32)) ) + /* * Cache size */ @@ -187,11 +201,10 @@ static inline int rt2x00usb_vendor_request_sw(struct rt2x00_dev *rt2x00dev, static inline int rt2x00usb_eeprom_read(struct rt2x00_dev *rt2x00dev, __le16 *eeprom, const u16 lenght) { - int timeout = REGISTER_TIMEOUT * (lenght / sizeof(u16)); - return rt2x00usb_vendor_request(rt2x00dev, USB_EEPROM_READ, USB_VENDOR_REQUEST_IN, 0, 0, - eeprom, lenght, timeout); + eeprom, lenght, + REGISTER_TIMEOUT16(lenght)); } /* diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index a6419c90077..351d95c4f50 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -74,10 +74,10 @@ static inline void rt73usb_register_multiread(struct rt2x00_dev *rt2x00dev, const unsigned int offset, void *value, const u32 length) { - int timeout = REGISTER_TIMEOUT * (length / sizeof(u32)); rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ, USB_VENDOR_REQUEST_IN, offset, - value, length, timeout); + value, length, + REGISTER_TIMEOUT32(length)); } static inline void rt73usb_register_write(struct rt2x00_dev *rt2x00dev, @@ -102,10 +102,10 @@ static inline void rt73usb_register_multiwrite(struct rt2x00_dev *rt2x00dev, const unsigned int offset, void *value, const u32 length) { - int timeout = REGISTER_TIMEOUT * (length / sizeof(u32)); rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE, USB_VENDOR_REQUEST_OUT, offset, - value, length, timeout); + value, length, + REGISTER_TIMEOUT32(length)); } static u32 rt73usb_bbp_check(struct rt2x00_dev *rt2x00dev) @@ -876,7 +876,6 @@ static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev, void *data, char *ptr = data; char *cache; int buflen; - int timeout; /* * Wait for stable hardware. @@ -907,14 +906,14 @@ static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev, void *data, for (i = 0; i < len; i += CSR_CACHE_SIZE_FIRMWARE) { buflen = min_t(int, len - i, CSR_CACHE_SIZE_FIRMWARE); - timeout = REGISTER_TIMEOUT * (buflen / sizeof(u32)); memcpy(cache, ptr, buflen); rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE, USB_VENDOR_REQUEST_OUT, FIRMWARE_IMAGE_BASE + i, 0, - cache, buflen, timeout); + cache, buflen, + REGISTER_TIMEOUT32(buflen)); ptr += buflen; } @@ -1966,7 +1965,6 @@ static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, struct rt2x00_intf *intf = vif_to_intf(control->vif); struct skb_frame_desc *skbdesc; unsigned int beacon_base; - unsigned int timeout; u32 reg; if (unlikely(!intf->beacon)) @@ -2006,10 +2004,10 @@ static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, */ rt2x00lib_write_tx_desc(rt2x00dev, skb, control); beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx); - timeout = REGISTER_TIMEOUT * (skb->len / sizeof(u32)); rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE, USB_VENDOR_REQUEST_OUT, beacon_base, 0, - skb->data, skb->len, timeout); + skb->data, skb->len, + REGISTER_TIMEOUT32(skb->len)); rt73usb_kick_tx_queue(rt2x00dev, QID_BEACON); return 0; -- cgit v1.2.3-70-g09d2 From 9a46d44eda55ad87a727fe351b0ab27c23d4555c Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 21 Apr 2008 19:02:17 +0200 Subject: rt2x00: Fix kernel-doc Add missing kernel-doc variables for structures/functions. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00.h | 6 +++--- drivers/net/wireless/rt2x00/rt2x00pci.h | 6 ++++-- drivers/net/wireless/rt2x00/rt2x00usb.h | 6 +++--- 3 files changed, 10 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index d85553f6351..92656d09cff 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -404,7 +404,7 @@ static inline struct rt2x00_intf* vif_to_intf(struct ieee80211_vif *vif) * @supported_rates: Rate types which are supported (CCK, OFDM). * @num_channels: Number of supported channels. This is used as array size * for @tx_power_a, @tx_power_bg and @channels. - * channels: Device/chipset specific channel values (See &struct rf_channel). + * @channels: Device/chipset specific channel values (See &struct rf_channel). * @tx_power_a: TX power values for all 5.2GHz channels (may be NULL). * @tx_power_bg: TX power values for all 2.4GHz channels (may be NULL). * @tx_power_default: Default TX power value to use when either @@ -936,7 +936,7 @@ struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev, /** * rt2x00queue_get_entry - Get queue entry where the given index points to. - * @rt2x00dev: Pointer to &struct rt2x00_dev. + * @queue: Pointer to &struct data_queue from where we obtain the entry. * @index: Index identifier for obtaining the correct index. */ struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue, @@ -945,7 +945,7 @@ struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue, /** * rt2x00queue_index_inc - Index incrementation function * @queue: Queue (&struct data_queue) to perform the action on. - * @action: Index type (&enum queue_index) to perform the action on. + * @index: Index type (&enum queue_index) to perform the action on. * * This function will increase the requested index on the queue, * it will grab the appropriate locks and handle queue overflow events by diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h index 9d1cdb99431..2b0ef17bba6 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.h +++ b/drivers/net/wireless/rt2x00/rt2x00pci.h @@ -98,8 +98,9 @@ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev, * struct queue_entry_priv_pci_rx: Per RX entry PCI specific information * * @desc: Pointer to device descriptor. + * @desc_dma: DMA pointer to @desc. * @data: Pointer to device's entry memory. - * @dma: DMA pointer to &data. + * @data_dma: DMA pointer to &data. */ struct queue_entry_priv_pci_rx { __le32 *desc; @@ -113,8 +114,9 @@ struct queue_entry_priv_pci_rx { * struct queue_entry_priv_pci_tx: Per TX entry PCI specific information * * @desc: Pointer to device descriptor + * @desc_dma: DMA pointer to @desc. * @data: Pointer to device's entry memory. - * @dma: DMA pointer to &data. + * @data_dma: DMA pointer to &data. * @control: mac80211 control structure used to transmit data. */ struct queue_entry_priv_pci_tx { diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index 1efaaae0463..4da9eb376eb 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h @@ -199,12 +199,12 @@ static inline int rt2x00usb_vendor_request_sw(struct rt2x00_dev *rt2x00dev, * kmalloc for correct handling inside the kernel USB layer. */ static inline int rt2x00usb_eeprom_read(struct rt2x00_dev *rt2x00dev, - __le16 *eeprom, const u16 lenght) + __le16 *eeprom, const u16 length) { return rt2x00usb_vendor_request(rt2x00dev, USB_EEPROM_READ, USB_VENDOR_REQUEST_IN, 0, 0, - eeprom, lenght, - REGISTER_TIMEOUT16(lenght)); + eeprom, length, + REGISTER_TIMEOUT16(length)); } /* -- cgit v1.2.3-70-g09d2 From 5b28d3c156472cfb713fafecdf398739d22a0738 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 21 Apr 2008 19:02:35 +0200 Subject: rt2x00: Release rt2x00 2.1.5 Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 92656d09cff..48a9af47921 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -44,7 +44,7 @@ /* * Module information. */ -#define DRV_VERSION "2.1.4" +#define DRV_VERSION "2.1.5" #define DRV_PROJECT "http://rt2x00.serialmonkey.com" /* -- cgit v1.2.3-70-g09d2 From b0692f2ff308f2645a43b415393d934eb939cc6c Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 24 Apr 2008 11:55:18 -0700 Subject: iwlwifi: move verify_ucode functions to iwl-core This patch moves verify_ucode functions to iwl-core. Signed-off-by: Emmanuel Grumbach Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 134 ++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-core.h | 1 + drivers/net/wireless/iwlwifi/iwl4965-base.c | 144 +--------------------------- 3 files changed, 137 insertions(+), 142 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index ca32fb3b9e1..8c8b51dea57 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -704,3 +704,137 @@ int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags) } EXPORT_SYMBOL(iwl_send_statistics_request); +/** + * iwl_verify_inst_sparse - verify runtime uCode image in card vs. host, + * using sample data 100 bytes apart. If these sample points are good, + * it's a pretty good bet that everything between them is good, too. + */ +static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len) +{ + u32 val; + int ret = 0; + u32 errcnt = 0; + u32 i; + + IWL_DEBUG_INFO("ucode inst image size is %u\n", len); + + ret = iwl_grab_nic_access(priv); + if (ret) + return ret; + + for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) { + /* read data comes through single port, auto-incr addr */ + /* NOTE: Use the debugless read so we don't flood kernel log + * if IWL_DL_IO is set */ + iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, + i + RTC_INST_LOWER_BOUND); + val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); + if (val != le32_to_cpu(*image)) { + ret = -EIO; + errcnt++; + if (errcnt >= 3) + break; + } + } + + iwl_release_nic_access(priv); + + return ret; +} + +/** + * iwlcore_verify_inst_full - verify runtime uCode image in card vs. host, + * looking at all data. + */ +static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 *image, + u32 len) +{ + u32 val; + u32 save_len = len; + int ret = 0; + u32 errcnt; + + IWL_DEBUG_INFO("ucode inst image size is %u\n", len); + + ret = iwl_grab_nic_access(priv); + if (ret) + return ret; + + iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, RTC_INST_LOWER_BOUND); + + errcnt = 0; + for (; len > 0; len -= sizeof(u32), image++) { + /* read data comes through single port, auto-incr addr */ + /* NOTE: Use the debugless read so we don't flood kernel log + * if IWL_DL_IO is set */ + val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); + if (val != le32_to_cpu(*image)) { + IWL_ERROR("uCode INST section is invalid at " + "offset 0x%x, is 0x%x, s/b 0x%x\n", + save_len - len, val, le32_to_cpu(*image)); + ret = -EIO; + errcnt++; + if (errcnt >= 20) + break; + } + } + + iwl_release_nic_access(priv); + + if (!errcnt) + IWL_DEBUG_INFO + ("ucode image in INSTRUCTION memory is good\n"); + + return ret; +} + +/** + * iwl_verify_ucode - determine which instruction image is in SRAM, + * and verify its contents + */ +int iwl_verify_ucode(struct iwl_priv *priv) +{ + __le32 *image; + u32 len; + int ret; + + /* Try bootstrap */ + image = (__le32 *)priv->ucode_boot.v_addr; + len = priv->ucode_boot.len; + ret = iwlcore_verify_inst_sparse(priv, image, len); + if (!ret) { + IWL_DEBUG_INFO("Bootstrap uCode is good in inst SRAM\n"); + return 0; + } + + /* Try initialize */ + image = (__le32 *)priv->ucode_init.v_addr; + len = priv->ucode_init.len; + ret = iwlcore_verify_inst_sparse(priv, image, len); + if (!ret) { + IWL_DEBUG_INFO("Initialize uCode is good in inst SRAM\n"); + return 0; + } + + /* Try runtime/protocol */ + image = (__le32 *)priv->ucode_code.v_addr; + len = priv->ucode_code.len; + ret = iwlcore_verify_inst_sparse(priv, image, len); + if (!ret) { + IWL_DEBUG_INFO("Runtime uCode is good in inst SRAM\n"); + return 0; + } + + IWL_ERROR("NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n"); + + /* Since nothing seems to match, show first several data entries in + * instruction SRAM, so maybe visual inspection will give a clue. + * Selection of bootstrap image (vs. other images) is arbitrary. */ + image = (__le32 *)priv->ucode_boot.v_addr; + len = priv->ucode_boot.len; + ret = iwl_verify_inst_full(priv, image, len); + + return ret; +} +EXPORT_SYMBOL(iwl_verify_ucode); + diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index e18940dbd13..8196ef7303a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -253,6 +253,7 @@ enum iwlcore_card_notify { int iwlcore_low_level_notify(struct iwl_priv *priv, enum iwlcore_card_notify notify); extern int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags); +extern int iwl_verify_ucode(struct iwl_priv *priv); int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_link_quality_cmd *lq, u8 flags); diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index e24527313ab..011f6114c33 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -4512,146 +4512,6 @@ static void iwl4965_dealloc_ucode_pci(struct iwl_priv *priv) iwl_free_fw_desc(priv->pci_dev, &priv->ucode_boot); } -/** - * iwl4965_verify_inst_full - verify runtime uCode image in card vs. host, - * looking at all data. - */ -static int iwl4965_verify_inst_full(struct iwl_priv *priv, __le32 *image, - u32 len) -{ - u32 val; - u32 save_len = len; - int rc = 0; - u32 errcnt; - - IWL_DEBUG_INFO("ucode inst image size is %u\n", len); - - rc = iwl_grab_nic_access(priv); - if (rc) - return rc; - - iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, RTC_INST_LOWER_BOUND); - - errcnt = 0; - for (; len > 0; len -= sizeof(u32), image++) { - /* read data comes through single port, auto-incr addr */ - /* NOTE: Use the debugless read so we don't flood kernel log - * if IWL_DL_IO is set */ - val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); - if (val != le32_to_cpu(*image)) { - IWL_ERROR("uCode INST section is invalid at " - "offset 0x%x, is 0x%x, s/b 0x%x\n", - save_len - len, val, le32_to_cpu(*image)); - rc = -EIO; - errcnt++; - if (errcnt >= 20) - break; - } - } - - iwl_release_nic_access(priv); - - if (!errcnt) - IWL_DEBUG_INFO - ("ucode image in INSTRUCTION memory is good\n"); - - return rc; -} - - -/** - * iwl4965_verify_inst_sparse - verify runtime uCode image in card vs. host, - * using sample data 100 bytes apart. If these sample points are good, - * it's a pretty good bet that everything between them is good, too. - */ -static int iwl4965_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len) -{ - u32 val; - int rc = 0; - u32 errcnt = 0; - u32 i; - - IWL_DEBUG_INFO("ucode inst image size is %u\n", len); - - rc = iwl_grab_nic_access(priv); - if (rc) - return rc; - - for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) { - /* read data comes through single port, auto-incr addr */ - /* NOTE: Use the debugless read so we don't flood kernel log - * if IWL_DL_IO is set */ - iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, - i + RTC_INST_LOWER_BOUND); - val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); - if (val != le32_to_cpu(*image)) { -#if 0 /* Enable this if you want to see details */ - IWL_ERROR("uCode INST section is invalid at " - "offset 0x%x, is 0x%x, s/b 0x%x\n", - i, val, *image); -#endif - rc = -EIO; - errcnt++; - if (errcnt >= 3) - break; - } - } - - iwl_release_nic_access(priv); - - return rc; -} - - -/** - * iwl4965_verify_ucode - determine which instruction image is in SRAM, - * and verify its contents - */ -static int iwl4965_verify_ucode(struct iwl_priv *priv) -{ - __le32 *image; - u32 len; - int rc = 0; - - /* Try bootstrap */ - image = (__le32 *)priv->ucode_boot.v_addr; - len = priv->ucode_boot.len; - rc = iwl4965_verify_inst_sparse(priv, image, len); - if (rc == 0) { - IWL_DEBUG_INFO("Bootstrap uCode is good in inst SRAM\n"); - return 0; - } - - /* Try initialize */ - image = (__le32 *)priv->ucode_init.v_addr; - len = priv->ucode_init.len; - rc = iwl4965_verify_inst_sparse(priv, image, len); - if (rc == 0) { - IWL_DEBUG_INFO("Initialize uCode is good in inst SRAM\n"); - return 0; - } - - /* Try runtime/protocol */ - image = (__le32 *)priv->ucode_code.v_addr; - len = priv->ucode_code.len; - rc = iwl4965_verify_inst_sparse(priv, image, len); - if (rc == 0) { - IWL_DEBUG_INFO("Runtime uCode is good in inst SRAM\n"); - return 0; - } - - IWL_ERROR("NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n"); - - /* Since nothing seems to match, show first several data entries in - * instruction SRAM, so maybe visual inspection will give a clue. - * Selection of bootstrap image (vs. other images) is arbitrary. */ - image = (__le32 *)priv->ucode_boot.v_addr; - len = priv->ucode_boot.len; - rc = iwl4965_verify_inst_full(priv, image, len); - - return rc; -} - static void iwl4965_nic_start(struct iwl_priv *priv) { /* Remove all resets to allow NIC to operate */ @@ -4927,7 +4787,7 @@ static void iwl4965_init_alive_start(struct iwl_priv *priv) /* Bootstrap uCode has loaded initialize uCode ... verify inst image. * This is a paranoid check, because we would not have gotten the * "initialize" alive if code weren't properly loaded. */ - if (iwl4965_verify_ucode(priv)) { + if (iwl_verify_ucode(priv)) { /* Runtime instruction load was bad; * take it all the way back down so we can try again */ IWL_DEBUG_INFO("Bad \"initialize\" uCode load.\n"); @@ -4975,7 +4835,7 @@ static void iwl4965_alive_start(struct iwl_priv *priv) /* Initialize uCode has loaded Runtime uCode ... verify inst image. * This is a paranoid check, because we would not have gotten the * "runtime" alive if code weren't properly loaded. */ - if (iwl4965_verify_ucode(priv)) { + if (iwl_verify_ucode(priv)) { /* Runtime instruction load was bad; * take it all the way back down so we can try again */ IWL_DEBUG_INFO("Bad runtime uCode load.\n"); -- cgit v1.2.3-70-g09d2 From a395b92024d9b8f9403c06f9ea8d425f1883d7d8 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 24 Apr 2008 11:55:19 -0700 Subject: iwlwifi: remove 49 prefix from general CSR values This patch change CSR49_ to CSR_ for values used in other HW Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl-csr.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 99c08ea6ddf..b1b7363bfdd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -618,8 +618,8 @@ int iwl4965_hw_nic_init(struct iwl_priv *priv) iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, CSR49_HW_IF_CONFIG_REG_BIT_4965_R | - CSR49_HW_IF_CONFIG_REG_BIT_RADIO_SI | - CSR49_HW_IF_CONFIG_REG_BIT_MAC_SI); + CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | + CSR_HW_IF_CONFIG_REG_BIT_MAC_SI); ret = iwl_grab_nic_access(priv); if (ret < 0) { diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index df9949ad3f6..f8de32b1d42 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -106,9 +106,9 @@ /* Bits for CSR_HW_IF_CONFIG_REG */ #define CSR49_HW_IF_CONFIG_REG_BIT_4965_R (0x00000010) -#define CSR49_HW_IF_CONFIG_REG_MSK_BOARD_VER (0x00000C00) -#define CSR49_HW_IF_CONFIG_REG_BIT_MAC_SI (0x00000100) -#define CSR49_HW_IF_CONFIG_REG_BIT_RADIO_SI (0x00000200) +#define CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER (0x00000C00) +#define CSR_HW_IF_CONFIG_REG_BIT_MAC_SI (0x00000100) +#define CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI (0x00000200) #define CSR39_HW_IF_CONFIG_REG_BIT_3945_MB (0x00000100) #define CSR39_HW_IF_CONFIG_REG_BIT_3945_MM (0x00000200) -- cgit v1.2.3-70-g09d2 From d4789efe5627858c212753bbac4316198f819486 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 24 Apr 2008 11:55:20 -0700 Subject: iwlwifi: move hw_rx_handler_setup to iwl-4965.c This patch moves hw_rx_handler_setup to iwl-4965.c Signed-off-by: Emmanuel Grumbach Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 3 ++- drivers/net/wireless/iwlwifi/iwl-4965.h | 1 - drivers/net/wireless/iwlwifi/iwl-core.h | 2 ++ drivers/net/wireless/iwlwifi/iwl4965-base.c | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index b1b7363bfdd..258777366d2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -4065,7 +4065,7 @@ int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, #endif /* CONFIG_IWL4965_HT */ /* Set up 4965-specific Rx frame reply handlers */ -void iwl4965_hw_rx_handler_setup(struct iwl_priv *priv) +static void iwl4965_rx_handler_setup(struct iwl_priv *priv) { /* Legacy Rx frames */ priv->rx_handlers[REPLY_RX] = iwl4965_rx_reply_rx; @@ -4119,6 +4119,7 @@ static struct iwl_lib_ops iwl4965_lib = { .free_shared_mem = iwl4965_free_shared_mem, .txq_update_byte_cnt_tbl = iwl4965_txq_update_byte_cnt_tbl, .hw_nic_init = iwl4965_hw_nic_init, + .rx_handler_setup = iwl4965_rx_handler_setup, .is_valid_rtc_data_addr = iwl4965_hw_valid_rtc_data_addr, .alive_notify = iwl4965_alive_notify, .load_ucode = iwl4965_load_bsm, diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h index 3b730647553..7b7c6207c93 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965.h @@ -693,7 +693,6 @@ extern u8 iwl4965_sync_station(struct iwl_priv *priv, int sta_id, * iwl4965_mac_ <-- mac80211 callback * ****************************************************************************/ -extern void iwl4965_hw_rx_handler_setup(struct iwl_priv *priv); extern void iwl4965_hw_setup_deferred_work(struct iwl_priv *priv); extern void iwl4965_hw_cancel_deferred_work(struct iwl_priv *priv); extern int iwl4965_hw_rxq_stop(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 8196ef7303a..fc0c2765f13 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -105,6 +105,8 @@ struct iwl_lib_ops { void (*txq_update_byte_cnt_tbl)(struct iwl_priv *priv, struct iwl4965_tx_queue *txq, u16 byte_cnt); + /* setup Rx handler */ + void (*rx_handler_setup)(struct iwl_priv *priv); /* nic init */ int (*hw_nic_init)(struct iwl_priv *priv); /* alive notification */ diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 011f6114c33..fbd82d80cad 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -3237,7 +3237,7 @@ static void iwl4965_setup_rx_handlers(struct iwl_priv *priv) priv->rx_handlers[REPLY_TX] = iwl4965_rx_reply_tx; /* Set up hardware specific Rx handlers */ - iwl4965_hw_rx_handler_setup(priv); + priv->cfg->ops->lib->rx_handler_setup(priv); } /** -- cgit v1.2.3-70-g09d2 From e4d18d817f0ffc830bce57906b2a7dd9e713c388 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 24 Apr 2008 11:55:21 -0700 Subject: iwlwifi: remove unnecessary apmg settings This patch remove settings of APMG_PS_CTRL_VAL_RESET_REQ from 4965 this should be used only for 3945 Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 258777366d2..a98f00f7da4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -621,19 +621,6 @@ int iwl4965_hw_nic_init(struct iwl_priv *priv) CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | CSR_HW_IF_CONFIG_REG_BIT_MAC_SI); - ret = iwl_grab_nic_access(priv); - if (ret < 0) { - spin_unlock_irqrestore(&priv->lock, flags); - IWL_DEBUG_INFO("Failed to init the card\n"); - return ret; - } - - iwl_read_prph(priv, APMG_PS_CTRL_REG); - iwl_set_bits_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ); - udelay(5); - iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ); - - iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); iwl4965_hw_card_show_info(priv); -- cgit v1.2.3-70-g09d2 From 694cc56dbb818fe689f721fb53452eb5ad3f8e9a Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 24 Apr 2008 11:55:22 -0700 Subject: iwlwifi: wrapping nic configuration in iwl core handler This patch wraps nic hw configuration in a iwl core handler Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 57 +++++++++++++++++++------------ drivers/net/wireless/iwlwifi/iwl-core.h | 1 + drivers/net/wireless/iwlwifi/iwl-eeprom.h | 12 +++++++ 3 files changed, 48 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index a98f00f7da4..8aaac16a45f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -579,22 +579,13 @@ out: return ret; } -int iwl4965_hw_nic_init(struct iwl_priv *priv) + +static void iwl4965_nic_config(struct iwl_priv *priv) { unsigned long flags; - struct iwl4965_rx_queue *rxq = &priv->rxq; - u8 val_link; u32 val; - int ret; - - /* nic_init */ - priv->cfg->ops->lib->apm_ops.init(priv); - - spin_lock_irqsave(&priv->lock, flags); - iwl_write32(priv, CSR_INT_COALESCING, 512 / 32); - spin_unlock_irqrestore(&priv->lock, flags); - - ret = priv->cfg->ops->lib->apm_ops.set_pwr_src(priv, IWL_PWR_SRC_VMAIN); + u16 radio_cfg; + u8 val_link; spin_lock_irqsave(&priv->lock, flags); @@ -605,24 +596,49 @@ int iwl4965_hw_nic_init(struct iwl_priv *priv) val & ~(1 << 11)); } - spin_unlock_irqrestore(&priv->lock, flags); - pci_read_config_byte(priv->pci_dev, PCI_LINK_CTRL, &val_link); /* disable L1 entry -- workaround for pre-B1 */ pci_write_config_byte(priv->pci_dev, PCI_LINK_CTRL, val_link & ~0x02); - spin_lock_irqsave(&priv->lock, flags); + radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG); - /* set CSR_HW_CONFIG_REG for uCode use */ + /* write radio config values to register */ + if (EEPROM_RF_CFG_TYPE_MSK(radio_cfg) == EEPROM_4965_RF_CFG_TYPE_MAX) + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + EEPROM_RF_CFG_TYPE_MSK(radio_cfg) | + EEPROM_RF_CFG_STEP_MSK(radio_cfg) | + EEPROM_RF_CFG_DASH_MSK(radio_cfg)); + /* set CSR_HW_CONFIG_REG for uCode use */ iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR49_HW_IF_CONFIG_REG_BIT_4965_R | CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | CSR_HW_IF_CONFIG_REG_BIT_MAC_SI); + priv->calib_info = (struct iwl_eeprom_calib_info *) + iwl_eeprom_query_addr(priv, EEPROM_4965_CALIB_TXPOWER_OFFSET); + + spin_unlock_irqrestore(&priv->lock, flags); +} + + +int iwl4965_hw_nic_init(struct iwl_priv *priv) +{ + unsigned long flags; + struct iwl4965_rx_queue *rxq = &priv->rxq; + int ret; + + /* nic_init */ + priv->cfg->ops->lib->apm_ops.init(priv); + + spin_lock_irqsave(&priv->lock, flags); + iwl_write32(priv, CSR_INT_COALESCING, 512 / 32); spin_unlock_irqrestore(&priv->lock, flags); + ret = priv->cfg->ops->lib->apm_ops.set_pwr_src(priv, IWL_PWR_SRC_VMAIN); + + priv->cfg->ops->lib->apm_ops.config(priv); + iwl4965_hw_card_show_info(priv); /* end nic_init */ @@ -646,10 +662,6 @@ int iwl4965_hw_nic_init(struct iwl_priv *priv) rxq->need_update = 1; iwl4965_rx_queue_update_write_ptr(priv, rxq); - /* init the txpower calibration pointer */ - priv->calib_info = (struct iwl_eeprom_calib_info *) - iwl_eeprom_query_addr(priv, EEPROM_4965_CALIB_TXPOWER_OFFSET); - spin_unlock_irqrestore(&priv->lock, flags); /* Allocate and init all Tx and Command queues */ @@ -4112,6 +4124,7 @@ static struct iwl_lib_ops iwl4965_lib = { .load_ucode = iwl4965_load_bsm, .apm_ops = { .init = iwl4965_apm_init, + .config = iwl4965_nic_config, .set_pwr_src = iwl4965_set_pwr_src, }, .eeprom_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index fc0c2765f13..369f1821584 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -120,6 +120,7 @@ struct iwl_lib_ops { /* power management */ struct { int (*init)(struct iwl_priv *priv); + void (*config)(struct iwl_priv *priv); int (*set_pwr_src)(struct iwl_priv *priv, enum iwl_pwr_src src); } apm_ops; /* power */ diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 57fb89d5621..0c42e5a1288 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -247,9 +247,21 @@ struct iwl_eeprom_calib_info { #define EEPROM_LEDS_MODE (2*0x45+1) /* 1 bytes */ #define EEPROM_OEM_MODE (2*0x46) /* 2 bytes */ #define EEPROM_WOWLAN_MODE (2*0x47) /* 2 bytes */ +#define EEPROM_RADIO_CONFIG (2*0x48) /* 2 bytes */ #define EEPROM_3945_M_VERSION (2*0x4A) /* 1 bytes */ #define EEPROM_ANTENNA_SWITCH_TYPE (2*0x4A+1) /* 1 bytes */ +/* The following masks are to be applied on EEPROM_RADIO_CONFIG */ +#define EEPROM_RF_CFG_TYPE_MSK(x) (x & 0x3) /* bits 0-1 */ +#define EEPROM_RF_CFG_STEP_MSK(x) ((x >> 2) & 0x3) /* bits 2-3 */ +#define EEPROM_RF_CFG_DASH_MSK(x) ((x >> 4) & 0x3) /* bits 4-5 */ +#define EEPROM_RF_CFG_PNUM_MSK(x) ((x >> 6) & 0x3) /* bits 6-7 */ +#define EEPROM_RF_CFG_TX_ANT_MSK(x) ((x >> 8) & 0xF) /* bits 8-11 */ +#define EEPROM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */ + +#define EEPROM_3945_RF_CFG_TYPE_MAX 0x0 +#define EEPROM_4965_RF_CFG_TYPE_MAX 0x1 + /* * Per-channel regulatory data. * -- cgit v1.2.3-70-g09d2 From 5a6a256e195380c062100dffad15f984656772c2 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 24 Apr 2008 11:55:23 -0700 Subject: iwlwifi-5000: adding initial recognition for the 5000 family This patch adds initial support for recognizing the iwl 5000 family of NICs ID Signed-off-by: Tomas Winkler Signed-off-by: Ron Rindjunsky Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/Kconfig | 8 +++ drivers/net/wireless/iwlwifi/Makefile | 5 ++ drivers/net/wireless/iwlwifi/iwl-4965.h | 3 + drivers/net/wireless/iwlwifi/iwl-5000-hw.h | 79 ++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-5000.c | 93 +++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl4965-base.c | 5 ++ 6 files changed, 193 insertions(+) create mode 100644 drivers/net/wireless/iwlwifi/iwl-5000-hw.h create mode 100644 drivers/net/wireless/iwlwifi/iwl-5000.c (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index a5fdd0f21a7..2bc7a9bfc56 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -112,6 +112,14 @@ config IWLWIFI_DEBUG as the debug information can assist others in helping you resolve any problems you may encounter. +config IWL5000 + bool "Intel Wireless WiFi 5000AGN" + depends on IWL4965 + ---help--- + This option enables support for Intel Wireless WiFi Link 5000AGN Family + Dependency on 4965 is temporary + + config IWLWIFI_DEBUGFS bool "Iwlwifi debugfs support" depends on IWLCORE && IWLWIFI_DEBUG && MAC80211_DEBUGFS diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index e2c05f5346e..b0b2b5ebfa6 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -12,3 +12,8 @@ iwl3945-$(CONFIG_IWL3945_LEDS) += iwl-3945-led.o obj-$(CONFIG_IWL4965) += iwl4965.o iwl4965-objs := iwl4965-base.o iwl-4965.o iwl-4965-rs.o iwl-sta.o +ifeq ($(CONFIG_IWL5000),y) + iwl4965-objs += iwl-5000.o +endif + + diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h index 7b7c6207c93..78fe8b73169 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965.h @@ -48,6 +48,9 @@ /* configuration for the iwl4965 */ extern struct iwl_cfg iwl4965_agn_cfg; +extern struct iwl_cfg iwl5300_agn_cfg; +extern struct iwl_cfg iwl5100_agn_cfg; +extern struct iwl_cfg iwl5350_agn_cfg; /* Change firmware file name, using "-" and incrementing number, * *only* when uCode interface or architecture changes so that it diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h new file mode 100644 index 00000000000..72a266581ae --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h @@ -0,0 +1,79 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ +/* + * Please use this file (iwl-5000-hw.h) only for hardware-related definitions. + * Use iwl-5000-commands.h for uCode API definitions. + */ + +#ifndef __iwl_5000_hw_h__ +#define __iwl_5000_hw_h__ + + +#define IWL50_MAX_WIN_SIZE 64 +#define IWL50_QUEUE_SIZE 256 +#define IWL50_CMD_FIFO_NUM 7 +#define IWL50_NUM_QUEUES 20 +#define IWL50_BACK_QUEUE_FIRST_ID 10 + +#endif /* __iwl_5000_hw_h__ */ + diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c new file mode 100644 index 00000000000..2314e31fc78 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -0,0 +1,93 @@ +/****************************************************************************** + * + * Copyright(c) 2007-2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "iwl-eeprom.h" +#include "iwl-4965.h" +#include "iwl-core.h" +#include "iwl-io.h" +#include "iwl-helpers.h" +#include "iwl-5000-hw.h" + +#define IWL5000_UCODE_API "-1" + +static struct iwl_mod_params iwl50_mod_params = { + .num_of_queues = IWL50_NUM_QUEUES, + .enable_qos = 1, + .amsdu_size_8K = 1, + /* the rest are 0 by default */ +}; + + +struct iwl_cfg iwl5300_agn_cfg = { + .name = "5300AGN", + .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode", + .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, + .mod_params = &iwl50_mod_params, +}; + +struct iwl_cfg iwl5100_agn_cfg = { + .name = "5100AGN", + .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode", + .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, + .mod_params = &iwl50_mod_params, +}; + +struct iwl_cfg iwl5350_agn_cfg = { + .name = "5350AGN", + .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode", + .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, + .mod_params = &iwl50_mod_params, +}; + +module_param_named(disable50, iwl50_mod_params.disable, int, 0444); +MODULE_PARM_DESC(disable50, + "manually disable the 50XX radio (default 0 [radio on])"); +module_param_named(swcrypto50, iwl50_mod_params.sw_crypto, bool, 0444); +MODULE_PARM_DESC(swcrypto50, + "using software crypto engine (default 0 [hardware])\n"); +module_param_named(debug50, iwl50_mod_params.debug, int, 0444); +MODULE_PARM_DESC(debug50, "50XX debug output mask"); +module_param_named(queues_num50, iwl50_mod_params.num_of_queues, int, 0444); +MODULE_PARM_DESC(queues_num50, "number of hw queues in 50xx series"); +module_param_named(qos_enable50, iwl50_mod_params.enable_qos, int, 0444); +MODULE_PARM_DESC(qos_enable50, "enable all 50XX QoS functionality"); +module_param_named(amsdu_size_8K50, iwl50_mod_params.amsdu_size_8K, int, 0444); +MODULE_PARM_DESC(amsdu_size_8K50, "enable 8K amsdu size in 50XX series"); + + diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index fbd82d80cad..ea8b9756643 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -7389,6 +7389,11 @@ static int iwl4965_pci_resume(struct pci_dev *pdev) static struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x4229, PCI_ANY_ID, iwl4965_agn_cfg)}, {IWL_PCI_DEVICE(0x4230, PCI_ANY_ID, iwl4965_agn_cfg)}, +#ifdef CONFIG_IWL5000 + {IWL_PCI_DEVICE(0x4235, PCI_ANY_ID, iwl5300_agn_cfg)}, + {IWL_PCI_DEVICE(0x4232, PCI_ANY_ID, iwl5100_agn_cfg)}, + {IWL_PCI_DEVICE(0x423A, PCI_ANY_ID, iwl5350_agn_cfg)}, +#endif /* CONFIG_IWL5000 */ {0} }; MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids); -- cgit v1.2.3-70-g09d2 From da8dec29d7928dcc4ddf6b41d7c4c9cef522c9df Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 24 Apr 2008 11:55:24 -0700 Subject: iwlwifi-5000: add ops infrastructure for 5000 This patch adds handler framework for 5000 family HW Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 2314e31fc78..3dd0b12b155 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -46,6 +46,26 @@ #define IWL5000_UCODE_API "-1" +static struct iwl_hcmd_ops iwl5000_hcmd = { +}; + +static struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = { +}; + +static struct iwl_lib_ops iwl5000_lib = { + .eeprom_ops = { + .verify_signature = iwlcore_eeprom_verify_signature, + .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, + .release_semaphore = iwlcore_eeprom_release_semaphore, + }, +}; + +static struct iwl_ops iwl5000_ops = { + .lib = &iwl5000_lib, + .hcmd = &iwl5000_hcmd, + .utils = &iwl5000_hcmd_utils, +}; + static struct iwl_mod_params iwl50_mod_params = { .num_of_queues = IWL50_NUM_QUEUES, .enable_qos = 1, @@ -58,6 +78,7 @@ struct iwl_cfg iwl5300_agn_cfg = { .name = "5300AGN", .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode", .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, + .ops = &iwl5000_ops, .mod_params = &iwl50_mod_params, }; @@ -65,6 +86,7 @@ struct iwl_cfg iwl5100_agn_cfg = { .name = "5100AGN", .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode", .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, + .ops = &iwl5000_ops, .mod_params = &iwl50_mod_params, }; @@ -72,6 +94,7 @@ struct iwl_cfg iwl5350_agn_cfg = { .name = "5350AGN", .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode", .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, + .ops = &iwl5000_ops, .mod_params = &iwl50_mod_params, }; -- cgit v1.2.3-70-g09d2 From 30d59260d54686681e36d3055ff58c58ca3617da Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 24 Apr 2008 11:55:25 -0700 Subject: iwlwifi-5000: add apm_init handler for 5000 HW family This patch adds apm_init handler for 5000 HW family Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 43 +++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 3dd0b12b155..32c591c0865 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -46,6 +46,46 @@ #define IWL5000_UCODE_API "-1" +static int iwl5000_apm_init(struct iwl_priv *priv) +{ + int ret = 0; + + iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, + CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); + + iwl_set_bit(priv, CSR_ANA_PLL_CFG, CSR50_ANA_PLL_CFG_VAL); + + /* set "initialization complete" bit to move adapter + * D0U* --> D0A* state */ + iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + + /* wait for clock stabilization */ + ret = iwl_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + if (ret < 0) { + IWL_DEBUG_INFO("Failed to init the card\n"); + return ret; + } + + ret = iwl_grab_nic_access(priv); + if (ret) + return ret; + + /* enable DMA */ + iwl_write_prph(priv, APMG_CLK_EN_REG, + APMG_CLK_VAL_DMA_CLK_RQT); + + udelay(20); + + iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, + APMG_PCIDEV_STT_VAL_L1_ACT_DIS); + + iwl_release_nic_access(priv); + + return ret; +} + static struct iwl_hcmd_ops iwl5000_hcmd = { }; @@ -53,6 +93,9 @@ static struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = { }; static struct iwl_lib_ops iwl5000_lib = { + .apm_ops = { + .init = iwl5000_apm_init, + }, .eeprom_ops = { .verify_signature = iwlcore_eeprom_verify_signature, .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, -- cgit v1.2.3-70-g09d2 From 88acbd3b32692ae786019ce642c6150b355f4b1e Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 24 Apr 2008 11:55:26 -0700 Subject: iwlwifi-5000: use iwl4965_set_pwr_src in 5000 This patch makes use of iwl4965_set_pwr_src in 5000 HW family Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 32c591c0865..58a35cb2d78 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -95,6 +95,7 @@ static struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = { static struct iwl_lib_ops iwl5000_lib = { .apm_ops = { .init = iwl5000_apm_init, + .set_pwr_src = iwl4965_set_pwr_src, }, .eeprom_ops = { .verify_signature = iwlcore_eeprom_verify_signature, -- cgit v1.2.3-70-g09d2 From 25ae3986d7ed4303fabc883a87b74956bd59c22c Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 24 Apr 2008 11:55:27 -0700 Subject: iwlwifi-5000: EEPROM settings for 5000 This patch adds eeprom handlers and values for 5000 HW family Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000-hw.h | 3 ++ drivers/net/wireless/iwlwifi/iwl-5000.c | 62 ++++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-eeprom.h | 30 +++++++++++++++ 3 files changed, 95 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h index 72a266581ae..5cf8a684b3e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h @@ -68,6 +68,9 @@ #ifndef __iwl_5000_hw_h__ #define __iwl_5000_hw_h__ +/* EERPROM */ +#define IWL_5000_EEPROM_IMG_SIZE 2048 + #define IWL50_MAX_WIN_SIZE 64 #define IWL50_QUEUE_SIZE 256 diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 58a35cb2d78..91b3e563bbe 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -86,6 +86,55 @@ static int iwl5000_apm_init(struct iwl_priv *priv) return ret; } +/* + * EEPROM + */ +static u32 eeprom_indirect_address(const struct iwl_priv *priv, u32 address) +{ + u16 offset = 0; + + if ((address & INDIRECT_ADDRESS) == 0) + return address; + + switch (address & INDIRECT_TYPE_MSK) { + case INDIRECT_HOST: + offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_HOST); + break; + case INDIRECT_GENERAL: + offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_GENERAL); + break; + case INDIRECT_REGULATORY: + offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_REGULATORY); + break; + case INDIRECT_CALIBRATION: + offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_CALIBRATION); + break; + case INDIRECT_PROCESS_ADJST: + offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_PROCESS_ADJST); + break; + case INDIRECT_OTHERS: + offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_OTHERS); + break; + default: + IWL_ERROR("illegal indirect type: 0x%X\n", + address & INDIRECT_TYPE_MSK); + break; + } + + /* translate the offset from words to byte */ + return (address & ADDRESS_MSK) + (offset << 1); +} + +static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, + size_t offset) +{ + u32 address = eeprom_indirect_address(priv, offset); + BUG_ON(address >= priv->cfg->eeprom_size); + return &priv->eeprom[address]; +} + + + static struct iwl_hcmd_ops iwl5000_hcmd = { }; @@ -98,9 +147,19 @@ static struct iwl_lib_ops iwl5000_lib = { .set_pwr_src = iwl4965_set_pwr_src, }, .eeprom_ops = { + .regulatory_bands = { + EEPROM_5000_REG_BAND_1_CHANNELS, + EEPROM_5000_REG_BAND_2_CHANNELS, + EEPROM_5000_REG_BAND_3_CHANNELS, + EEPROM_5000_REG_BAND_4_CHANNELS, + EEPROM_5000_REG_BAND_5_CHANNELS, + EEPROM_5000_REG_BAND_24_FAT_CHANNELS, + EEPROM_5000_REG_BAND_52_FAT_CHANNELS + }, .verify_signature = iwlcore_eeprom_verify_signature, .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, .release_semaphore = iwlcore_eeprom_release_semaphore, + .query_addr = iwl5000_eeprom_query_addr, }, }; @@ -123,6 +182,7 @@ struct iwl_cfg iwl5300_agn_cfg = { .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode", .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl5000_ops, + .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, .mod_params = &iwl50_mod_params, }; @@ -131,6 +191,7 @@ struct iwl_cfg iwl5100_agn_cfg = { .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode", .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl5000_ops, + .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, .mod_params = &iwl50_mod_params, }; @@ -139,6 +200,7 @@ struct iwl_cfg iwl5350_agn_cfg = { .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode", .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl5000_ops, + .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, .mod_params = &iwl50_mod_params, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 0c42e5a1288..56e0a07b818 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -140,6 +140,36 @@ struct iwl_eeprom_channel { #define EEPROM_4965_BOARD_REVISION (2*0x4F) /* 2 bytes */ #define EEPROM_4965_BOARD_PBA (2*0x56+1) /* 9 bytes */ +/*5000 calibrations */ +#define EEPROM_5000_CALIB_ALL (INDIRECT_ADDRESS | INDIRECT_CALIBRATION) + +/* 5000 links */ +#define EEPROM_5000_LINK_HOST (2*0x64) +#define EEPROM_5000_LINK_GENERAL (2*0x65) +#define EEPROM_5000_LINK_REGULATORY (2*0x66) +#define EEPROM_5000_LINK_CALIBRATION (2*0x67) +#define EEPROM_5000_LINK_PROCESS_ADJST (2*0x68) +#define EEPROM_5000_LINK_OTHERS (2*0x69) + +/* 5000 regulatory - indirect access */ +#define EEPROM_5000_REG_SKU_ID ((0x02)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 4 bytes */ +#define EEPROM_5000_REG_BAND_1_CHANNELS ((0x08)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 28 bytes */ +#define EEPROM_5000_REG_BAND_2_CHANNELS ((0x26)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 26 bytes */ +#define EEPROM_5000_REG_BAND_3_CHANNELS ((0x42)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 24 bytes */ +#define EEPROM_5000_REG_BAND_4_CHANNELS ((0x5C)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 22 bytes */ +#define EEPROM_5000_REG_BAND_5_CHANNELS ((0x74)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 12 bytes */ +#define EEPROM_5000_REG_BAND_24_FAT_CHANNELS ((0x82)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 14 bytes */ +#define EEPROM_5000_REG_BAND_52_FAT_CHANNELS ((0x92)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 22 bytes */ + + /* 2.4 GHz */ extern const u8 iwl_eeprom_band_1[14]; -- cgit v1.2.3-70-g09d2 From fdd3e8a4ff96d03121b21946bfa684f3b5d783c6 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 24 Apr 2008 11:55:28 -0700 Subject: iwlwifi-5000: adding iwl5000 HW parameters This patch adds iwl 5000 HW parameters Signed-off-by: Tomas Winkler Signed-off-by: Ron Rindjunsky Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-commands.h | 2 + drivers/net/wireless/iwlwifi/iwl-5000-hw.h | 47 ++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-5000.c | 51 +++++++++++++++++++++++- 3 files changed, 99 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-commands.h b/drivers/net/wireless/iwlwifi/iwl-4965-commands.h index 6b2d6bfec1e..d0e3f35d498 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-commands.h @@ -712,6 +712,8 @@ struct iwl4965_qosparam_cmd { #define IWL_STA_ID 2 #define IWL4965_BROADCAST_ID 31 #define IWL4965_STATION_COUNT 32 +#define IWL5000_BROADCAST_ID 15 +#define IWL5000_STATION_COUNT 16 #define IWL_STATION_COUNT 32 /* MAX(3945,4965)*/ #define IWL_INVALID_STATION 255 diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h index 5cf8a684b3e..31592fb8ddf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h @@ -68,6 +68,11 @@ #ifndef __iwl_5000_hw_h__ #define __iwl_5000_hw_h__ +#define IWL50_RTC_INST_UPPER_BOUND (0x020000) +#define IWL50_RTC_DATA_UPPER_BOUND (0x80C000) +#define IWL50_RTC_INST_SIZE (IWL50_RTC_INST_UPPER_BOUND - RTC_INST_LOWER_BOUND) +#define IWL50_RTC_DATA_SIZE (IWL50_RTC_DATA_UPPER_BOUND - RTC_DATA_LOWER_BOUND) + /* EERPROM */ #define IWL_5000_EEPROM_IMG_SIZE 2048 @@ -78,5 +83,47 @@ #define IWL50_NUM_QUEUES 20 #define IWL50_BACK_QUEUE_FIRST_ID 10 +/* Fixed (non-configurable) rx data from phy */ + +/* Base physical address of iwl5000_shared is provided to SCD_DRAM_BASE_ADDR + * and &iwl5000_shared.val0 is provided to FH_RSCSR_CHNL0_STTS_WPTR_REG */ +struct iwl5000_sched_queue_byte_cnt_tbl { + struct iwl4965_queue_byte_cnt_entry tfd_offset[IWL50_QUEUE_SIZE + + IWL50_MAX_WIN_SIZE]; +} __attribute__ ((packed)); + +struct iwl5000_shared { + struct iwl5000_sched_queue_byte_cnt_tbl + queues_byte_cnt_tbls[IWL50_NUM_QUEUES]; + __le32 rb_closed; + + /* __le32 rb_closed_stts_rb_num:12; */ +#define IWL_rb_closed_stts_rb_num_POS 0 +#define IWL_rb_closed_stts_rb_num_LEN 12 +#define IWL_rb_closed_stts_rb_num_SYM rb_closed + /* __le32 rsrv1:4; */ + /* __le32 rb_closed_stts_rx_frame_num:12; */ +#define IWL_rb_closed_stts_rx_frame_num_POS 16 +#define IWL_rb_closed_stts_rx_frame_num_LEN 12 +#define IWL_rb_closed_stts_rx_frame_num_SYM rb_closed + /* __le32 rsrv2:4; */ + + __le32 frm_finished; + /* __le32 frame_finished_stts_rb_num:12; */ +#define IWL_frame_finished_stts_rb_num_POS 0 +#define IWL_frame_finished_stts_rb_num_LEN 12 +#define IWL_frame_finished_stts_rb_num_SYM frm_finished + /* __le32 rsrv3:4; */ + /* __le32 frame_finished_stts_rx_frame_num:12; */ +#define IWL_frame_finished_stts_rx_frame_num_POS 16 +#define IWL_frame_finished_stts_rx_frame_num_LEN 12 +#define IWL_frame_finished_stts_rx_frame_num_SYM frm_finished + /* __le32 rsrv4:4; */ + + __le32 padding1; /* so that allocation will be aligned to 16B */ + __le32 padding2; +} __attribute__ ((packed)); + + #endif /* __iwl_5000_hw_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 91b3e563bbe..545970b0caa 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -133,8 +133,56 @@ static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, return &priv->eeprom[address]; } +static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) +{ + if ((priv->cfg->mod_params->num_of_queues > IWL50_NUM_QUEUES) || + (priv->cfg->mod_params->num_of_queues < IWL_MIN_NUM_QUEUES)) { + IWL_ERROR("invalid queues_num, should be between %d and %d\n", + IWL_MIN_NUM_QUEUES, IWL50_NUM_QUEUES); + return -EINVAL; + } - + priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues; + priv->hw_params.sw_crypto = priv->cfg->mod_params->sw_crypto; + priv->hw_params.tx_cmd_len = sizeof(struct iwl4965_tx_cmd); + priv->hw_params.max_rxq_size = RX_QUEUE_SIZE; + priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG; + if (priv->cfg->mod_params->amsdu_size_8K) + priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_8K; + else + priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_4K; + priv->hw_params.max_pkt_size = priv->hw_params.rx_buf_size - 256; + priv->hw_params.max_stations = IWL5000_STATION_COUNT; + priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID; + priv->hw_params.max_data_size = IWL50_RTC_DATA_SIZE; + priv->hw_params.max_inst_size = IWL50_RTC_INST_SIZE; + priv->hw_params.max_bsm_size = BSM_SRAM_SIZE; + priv->hw_params.fat_channel = BIT(IEEE80211_BAND_2GHZ) | + BIT(IEEE80211_BAND_5GHZ); + + switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { + case CSR_HW_REV_TYPE_5100: + case CSR_HW_REV_TYPE_5150: + priv->hw_params.tx_chains_num = 1; + priv->hw_params.rx_chains_num = 2; + /* FIXME: move to ANT_A, ANT_B, ANT_C enum */ + priv->hw_params.valid_tx_ant = IWL_ANTENNA_MAIN; + priv->hw_params.valid_rx_ant = (IWL_ANTENNA_MAIN | + IWL_ANTENNA_AUX); + break; + case CSR_HW_REV_TYPE_5300: + case CSR_HW_REV_TYPE_5350: + priv->hw_params.tx_chains_num = 3; + priv->hw_params.rx_chains_num = 3; + /* FIXME: move to ANT_A, ANT_B, ANT_C enum */ + priv->hw_params.valid_tx_ant = (IWL_ANTENNA_MAIN | + IWL_ANTENNA_AUX | 0x04); + priv->hw_params.valid_rx_ant = (IWL_ANTENNA_MAIN | + IWL_ANTENNA_AUX | 0x04); + break; + } + return 0; +} static struct iwl_hcmd_ops iwl5000_hcmd = { }; @@ -142,6 +190,7 @@ static struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = { }; static struct iwl_lib_ops iwl5000_lib = { + .set_hw_params = iwl5000_hw_set_hw_params, .apm_ops = { .init = iwl5000_apm_init, .set_pwr_src = iwl4965_set_pwr_src, -- cgit v1.2.3-70-g09d2 From c031bf806fef4854b02266a4105f55ed31f2d1a8 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 24 Apr 2008 11:55:29 -0700 Subject: iwlwifi-5000: update the CT-Kill value for 5000 series This patch upadtes the CT-Kill value for 5000 series. Signed-off-by: Assaf Krauss Signed-off-by: Emmanuel Grumbach Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 545970b0caa..7c42bbffff5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -181,6 +181,21 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) IWL_ANTENNA_AUX | 0x04); break; } + + switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { + case CSR_HW_REV_TYPE_5100: + case CSR_HW_REV_TYPE_5300: + /* 5X00 wants in Celsius */ + priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD; + break; + case CSR_HW_REV_TYPE_5150: + case CSR_HW_REV_TYPE_5350: + /* 5X50 wants in Kelvin */ + priv->hw_params.ct_kill_threshold = + CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD); + break; + } + return 0; } static struct iwl_hcmd_ops iwl5000_hcmd = { -- cgit v1.2.3-70-g09d2 From 33fd503346ad86bd7470a0f8c4c3080393d14233 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 24 Apr 2008 11:55:30 -0700 Subject: iwlwifi-5000: add run time calibrations for 5000 This patch adds support for run time calibrations for the 5000 family HW. Those calibrations are sensitivity calibration, and chain noise calibration. Signed-off-by: Emmanuel Grumbach Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/Kconfig | 9 ++ drivers/net/wireless/iwlwifi/iwl-4965-commands.h | 31 +++++++ drivers/net/wireless/iwlwifi/iwl-5000.c | 101 +++++++++++++++++++++++ 3 files changed, 141 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index 2bc7a9bfc56..cc0006900b3 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -119,6 +119,15 @@ config IWL5000 This option enables support for Intel Wireless WiFi Link 5000AGN Family Dependency on 4965 is temporary +config IWL5000_RUN_TIME_CALIB + bool "Enable run time Calibration for 5000 NIC" + select IWLWIFI_RUN_TIME_CALIB + depends on IWL5000 + default y + ---help--- + This option will enable run time calibration for the iwl5000 driver. + These calibrations are Sensitivity and Chain Noise. If unsure, say yes + config IWLWIFI_DEBUGFS bool "Iwlwifi debugfs support" diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-commands.h b/drivers/net/wireless/iwlwifi/iwl-4965-commands.h index d0e3f35d498..a5c33f35417 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-commands.h @@ -2671,6 +2671,37 @@ struct iwl4965_calibration_cmd { u8 reserved1; } __attribute__ ((packed)); +/* Phy calibration command for 5000 series */ + +enum { + IWL5000_PHY_CALIBRATE_DC_CMD = 8, + IWL5000_PHY_CALIBRATE_LO_CMD = 9, + IWL5000_PHY_CALIBRATE_RX_BB_CMD = 10, + IWL5000_PHY_CALIBRATE_TX_IQ_CMD = 11, + IWL5000_PHY_CALIBRATE_RX_IQ_CMD = 12, + IWL5000_PHY_CALIBRATION_NOISE_CMD = 13, + IWL5000_PHY_CALIBRATE_AGC_TABLE_CMD = 14, + IWL5000_PHY_CALIBRATE_CRYSTAL_FRQ_CMD = 15, + IWL5000_PHY_CALIBRATE_BASE_BAND_CMD = 16, + IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD = 18, + IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD = 19, +}; + +struct iwl5000_calibration_chain_noise_reset_cmd { + u8 op_code; /* IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD */ + u8 flags; /* not used */ + __le16 reserved; +} __attribute__ ((packed)); + +struct iwl5000_calibration_chain_noise_gain_cmd { + u8 op_code; /* IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD */ + u8 flags; /* not used */ + __le16 reserved; + u8 delta_gain_1; + u8 delta_gain_2; + __le16 reserved1; +} __attribute__ ((packed)); + /****************************************************************************** * (12) * Miscellaneous Commands: diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 7c42bbffff5..1a18ac187cb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -125,6 +125,100 @@ static u32 eeprom_indirect_address(const struct iwl_priv *priv, u32 address) return (address & ADDRESS_MSK) + (offset << 1); } +#ifdef CONFIG_IWL5000_RUN_TIME_CALIB + +static void iwl5000_gain_computation(struct iwl_priv *priv, + u32 average_noise[NUM_RX_CHAINS], + u16 min_average_noise_antenna_i, + u32 min_average_noise) +{ + int i; + s32 delta_g; + struct iwl_chain_noise_data *data = &priv->chain_noise_data; + + /* Find Gain Code for the antennas B and C */ + for (i = 1; i < NUM_RX_CHAINS; i++) { + if ((data->disconn_array[i])) { + data->delta_gain_code[i] = 0; + continue; + } + delta_g = (1000 * ((s32)average_noise[0] - + (s32)average_noise[i])) / 1500; + /* bound gain by 2 bits value max, 3rd bit is sign */ + data->delta_gain_code[i] = + min(abs(delta_g), CHAIN_NOISE_MAX_DELTA_GAIN_CODE); + + if (delta_g < 0) + /* set negative sign */ + data->delta_gain_code[i] |= (1 << 2); + } + + IWL_DEBUG_CALIB("Delta gains: ANT_B = %d ANT_C = %d\n", + data->delta_gain_code[1], data->delta_gain_code[2]); + + if (!data->radio_write) { + struct iwl5000_calibration_chain_noise_gain_cmd cmd; + memset(&cmd, 0, sizeof(cmd)); + + cmd.op_code = IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD; + cmd.delta_gain_1 = data->delta_gain_code[1]; + cmd.delta_gain_2 = data->delta_gain_code[2]; + iwl_send_cmd_pdu_async(priv, REPLY_PHY_CALIBRATION_CMD, + sizeof(cmd), &cmd, NULL); + + data->radio_write = 1; + data->state = IWL_CHAIN_NOISE_CALIBRATED; + } + + data->chain_noise_a = 0; + data->chain_noise_b = 0; + data->chain_noise_c = 0; + data->chain_signal_a = 0; + data->chain_signal_b = 0; + data->chain_signal_c = 0; + data->beacon_count = 0; +} + +static void iwl5000_chain_noise_reset(struct iwl_priv *priv) +{ + struct iwl_chain_noise_data *data = &priv->chain_noise_data; + + if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) { + struct iwl5000_calibration_chain_noise_reset_cmd cmd; + + memset(&cmd, 0, sizeof(cmd)); + cmd.op_code = IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD; + if (iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, + sizeof(cmd), &cmd)) + IWL_ERROR("Could not send REPLY_PHY_CALIBRATION_CMD\n"); + data->state = IWL_CHAIN_NOISE_ACCUMULATE; + IWL_DEBUG_CALIB("Run chain_noise_calibrate\n"); + } +} + +static struct iwl_sensitivity_ranges iwl5000_sensitivity = { + .min_nrg_cck = 95, + .max_nrg_cck = 0, + .auto_corr_min_ofdm = 90, + .auto_corr_min_ofdm_mrc = 170, + .auto_corr_min_ofdm_x1 = 120, + .auto_corr_min_ofdm_mrc_x1 = 240, + + .auto_corr_max_ofdm = 120, + .auto_corr_max_ofdm_mrc = 210, + .auto_corr_max_ofdm_x1 = 155, + .auto_corr_max_ofdm_mrc_x1 = 290, + + .auto_corr_min_cck = 125, + .auto_corr_max_cck = 200, + .auto_corr_min_cck_mrc = 170, + .auto_corr_max_cck_mrc = 400, + .nrg_th_cck = 95, + .nrg_th_ofdm = 95, +}; + +#endif /* CONFIG_IWL5000_RUN_TIME_CALIB */ + static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, size_t offset) { @@ -159,6 +253,9 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.max_bsm_size = BSM_SRAM_SIZE; priv->hw_params.fat_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); +#ifdef CONFIG_IWL5000_RUN_TIME_CALIB + priv->hw_params.sens = &iwl5000_sensitivity; +#endif switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { case CSR_HW_REV_TYPE_5100: @@ -202,6 +299,10 @@ static struct iwl_hcmd_ops iwl5000_hcmd = { }; static struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = { +#ifdef CONFIG_IWL5000_RUN_TIME_CALIB + .gain_computation = iwl5000_gain_computation, + .chain_noise_reset = iwl5000_chain_noise_reset, +#endif }; static struct iwl_lib_ops iwl5000_lib = { -- cgit v1.2.3-70-g09d2 From 1179f18df9fa3449ae6011042df50d9b9b012814 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 24 Apr 2008 11:55:31 -0700 Subject: iwlwifi-5000: adjust antennas names in 5000 HW family This patch use new defines for antennas Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 1a18ac187cb..8bccd9056bf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -263,19 +263,15 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.tx_chains_num = 1; priv->hw_params.rx_chains_num = 2; /* FIXME: move to ANT_A, ANT_B, ANT_C enum */ - priv->hw_params.valid_tx_ant = IWL_ANTENNA_MAIN; - priv->hw_params.valid_rx_ant = (IWL_ANTENNA_MAIN | - IWL_ANTENNA_AUX); + priv->hw_params.valid_tx_ant = ANT_A; + priv->hw_params.valid_rx_ant = ANT_AB; break; case CSR_HW_REV_TYPE_5300: case CSR_HW_REV_TYPE_5350: priv->hw_params.tx_chains_num = 3; priv->hw_params.rx_chains_num = 3; - /* FIXME: move to ANT_A, ANT_B, ANT_C enum */ - priv->hw_params.valid_tx_ant = (IWL_ANTENNA_MAIN | - IWL_ANTENNA_AUX | 0x04); - priv->hw_params.valid_rx_ant = (IWL_ANTENNA_MAIN | - IWL_ANTENNA_AUX | 0x04); + priv->hw_params.valid_tx_ant = ANT_ABC; + priv->hw_params.valid_rx_ant = ANT_ABC; break; } -- cgit v1.2.3-70-g09d2 From fcf623df17197adf10e22ddeba90c56504edce0f Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 24 Apr 2008 11:55:32 -0700 Subject: iwlwifi-5000: Add HW REV of 5000 HW family This patch adds values fo CSR_HW_REV for 5000 HW family Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-csr.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index f8de32b1d42..9d6e5d2072d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -198,6 +198,11 @@ #define CSR_HW_REV_TYPE_MSK (0x00000F0) #define CSR_HW_REV_TYPE_3945 (0x00000D0) #define CSR_HW_REV_TYPE_4965 (0x0000000) +#define CSR_HW_REV_TYPE_5300 (0x0000020) +#define CSR_HW_REV_TYPE_5350 (0x0000030) +#define CSR_HW_REV_TYPE_5100 (0x0000050) +#define CSR_HW_REV_TYPE_5150 (0x0000040) +#define CSR_HW_REV_TYPE_NONE (0x00000F0) /* EEPROM REG */ #define CSR_EEPROM_REG_READ_VALID_MSK (0x00000001) -- cgit v1.2.3-70-g09d2 From d4100dd985dcc13cc7bd1712ce10dea51b7c8261 Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Thu, 24 Apr 2008 11:55:33 -0700 Subject: iwlwifi-5000: add iwl 5000 shared memory handlers This patch fills the needed handlers for shared memory for iwl 5000 family Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 8bccd9056bf..8e2a6a5749a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -291,6 +291,29 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) return 0; } + +static int iwl5000_alloc_shared_mem(struct iwl_priv *priv) +{ + priv->shared_virt = pci_alloc_consistent(priv->pci_dev, + sizeof(struct iwl5000_shared), + &priv->shared_phys); + if (!priv->shared_virt) + return -ENOMEM; + + memset(priv->shared_virt, 0, sizeof(struct iwl5000_shared)); + + return 0; +} + +static void iwl5000_free_shared_mem(struct iwl_priv *priv) +{ + if (priv->shared_virt) + pci_free_consistent(priv->pci_dev, + sizeof(struct iwl5000_shared), + priv->shared_virt, + priv->shared_phys); +} + static struct iwl_hcmd_ops iwl5000_hcmd = { }; @@ -303,6 +326,8 @@ static struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = { static struct iwl_lib_ops iwl5000_lib = { .set_hw_params = iwl5000_hw_set_hw_params, + .alloc_shared_mem = iwl5000_alloc_shared_mem, + .free_shared_mem = iwl5000_free_shared_mem, .apm_ops = { .init = iwl5000_apm_init, .set_pwr_src = iwl4965_set_pwr_src, -- cgit v1.2.3-70-g09d2 From 7839fc03862704677902be2d63c0482fee3deae3 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 24 Apr 2008 11:55:34 -0700 Subject: iwlwifi-5000: update the byte count in SCD This patch udpates the byte count of the frame in the registers of the scheduler. This patch also moves two defines in iwl-4965.h to a more appropriate area in the file. Signed-off-by: Emmanuel Grumbach Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000-hw.h | 4 +++ drivers/net/wireless/iwlwifi/iwl-5000.c | 49 ++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h index 31592fb8ddf..9e557ce315b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h @@ -83,6 +83,10 @@ #define IWL50_NUM_QUEUES 20 #define IWL50_BACK_QUEUE_FIRST_ID 10 +#define IWL_sta_id_POS 12 +#define IWL_sta_id_LEN 4 +#define IWL_sta_id_SYM val + /* Fixed (non-configurable) rx data from phy */ /* Base physical address of iwl5000_shared is provided to SCD_DRAM_BASE_ADDR diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 8e2a6a5749a..1e63b497471 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -314,6 +314,54 @@ static void iwl5000_free_shared_mem(struct iwl_priv *priv) priv->shared_phys); } +/** + * iwl5000_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array + */ +static void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv, + struct iwl4965_tx_queue *txq, + u16 byte_cnt) +{ + struct iwl5000_shared *shared_data = priv->shared_virt; + int txq_id = txq->q.id; + u8 sec_ctl = 0; + u8 sta = 0; + int len; + + len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE; + + if (txq_id != IWL_CMD_QUEUE_NUM) { + sta = txq->cmd[txq->q.write_ptr].cmd.tx.sta_id; + sec_ctl = txq->cmd[txq->q.write_ptr].cmd.tx.sec_ctl; + + switch (sec_ctl & TX_CMD_SEC_MSK) { + case TX_CMD_SEC_CCM: + len += CCMP_MIC_LEN; + break; + case TX_CMD_SEC_TKIP: + len += TKIP_ICV_LEN; + break; + case TX_CMD_SEC_WEP: + len += WEP_IV_LEN + WEP_ICV_LEN; + break; + } + } + + IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. + tfd_offset[txq->q.write_ptr], byte_cnt, len); + + IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. + tfd_offset[txq->q.write_ptr], sta_id, sta); + + if (txq->q.write_ptr < IWL50_MAX_WIN_SIZE) { + IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. + tfd_offset[IWL50_QUEUE_SIZE + txq->q.write_ptr], + byte_cnt, len); + IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. + tfd_offset[IWL50_QUEUE_SIZE + txq->q.write_ptr], + sta_id, sta); + } +} + static struct iwl_hcmd_ops iwl5000_hcmd = { }; @@ -328,6 +376,7 @@ static struct iwl_lib_ops iwl5000_lib = { .set_hw_params = iwl5000_hw_set_hw_params, .alloc_shared_mem = iwl5000_alloc_shared_mem, .free_shared_mem = iwl5000_free_shared_mem, + .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, .apm_ops = { .init = iwl5000_apm_init, .set_pwr_src = iwl4965_set_pwr_src, -- cgit v1.2.3-70-g09d2 From f1f6941500602504fa9cd97294bfb3df7f22384f Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 24 Apr 2008 11:55:35 -0700 Subject: iwlwifi-5000: add eeprom check version handler This patch adds implementation for eeprom check version handler for 5000 HW Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 29 +++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-eeprom.h | 4 ++++ 2 files changed, 33 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 1e63b497471..d8e3dd70423 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -125,6 +125,33 @@ static u32 eeprom_indirect_address(const struct iwl_priv *priv, u32 address) return (address & ADDRESS_MSK) + (offset << 1); } +static int iwl5000_eeprom_check_version(struct iwl_priv *priv) +{ + u16 eeprom_ver; + struct iwl_eeprom_calib_hdr { + u8 version; + u8 pa_type; + u16 voltage; + } *hdr; + + eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); + + hdr = (struct iwl_eeprom_calib_hdr *)iwl_eeprom_query_addr(priv, + EEPROM_5000_CALIB_ALL); + + if (eeprom_ver < EEPROM_5000_EEPROM_VERSION || + hdr->version < EEPROM_5000_TX_POWER_VERSION) + goto err; + + return 0; +err: + IWL_ERROR("Unsuported EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n", + eeprom_ver, EEPROM_5000_EEPROM_VERSION, + hdr->version, EEPROM_5000_TX_POWER_VERSION); + return -EINVAL; + +} + #ifdef CONFIG_IWL5000_RUN_TIME_CALIB static void iwl5000_gain_computation(struct iwl_priv *priv, @@ -179,6 +206,7 @@ static void iwl5000_gain_computation(struct iwl_priv *priv, data->beacon_count = 0; } + static void iwl5000_chain_noise_reset(struct iwl_priv *priv) { struct iwl_chain_noise_data *data = &priv->chain_noise_data; @@ -394,6 +422,7 @@ static struct iwl_lib_ops iwl5000_lib = { .verify_signature = iwlcore_eeprom_verify_signature, .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, .release_semaphore = iwlcore_eeprom_release_semaphore, + .check_version = iwl5000_eeprom_check_version, .query_addr = iwl5000_eeprom_query_addr, }, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 56e0a07b818..06ed30044a4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -140,6 +140,10 @@ struct iwl_eeprom_channel { #define EEPROM_4965_BOARD_REVISION (2*0x4F) /* 2 bytes */ #define EEPROM_4965_BOARD_PBA (2*0x56+1) /* 9 bytes */ +/* 5000 Specific */ +#define EEPROM_5000_TX_POWER_VERSION (4) +#define EEPROM_5000_EEPROM_VERSION (0x11A) + /*5000 calibrations */ #define EEPROM_5000_CALIB_ALL (INDIRECT_ADDRESS | INDIRECT_CALIBRATION) -- cgit v1.2.3-70-g09d2 From e86fe9f64d7cc3da9f445f3d0a2c5fd265fcd445 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 24 Apr 2008 11:55:36 -0700 Subject: iwlwifi-5000: add nic config handler for 5000 HW This patch adds nic config handler for 5000 HW Family Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 33 +++++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-eeprom.h | 1 + 2 files changed, 34 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index d8e3dd70423..df628353667 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -86,6 +86,38 @@ static int iwl5000_apm_init(struct iwl_priv *priv) return ret; } +static void iwl5000_nic_init(struct iwl_priv *priv) +{ + unsigned long flags; + u16 radio_cfg; + u8 val_link; + + spin_lock_irqsave(&priv->lock, flags); + + pci_read_config_byte(priv->pci_dev, PCI_LINK_CTRL, &val_link); + + /* disable L1 entry -- workaround for pre-B1 */ + pci_write_config_byte(priv->pci_dev, PCI_LINK_CTRL, val_link & ~0x02); + + radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG); + + /* write radio config values to register */ + if (EEPROM_RF_CFG_TYPE_MSK(radio_cfg) < EEPROM_5000_RF_CFG_TYPE_MAX) + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + EEPROM_RF_CFG_TYPE_MSK(radio_cfg) | + EEPROM_RF_CFG_STEP_MSK(radio_cfg) | + EEPROM_RF_CFG_DASH_MSK(radio_cfg)); + + /* set CSR_HW_CONFIG_REG for uCode use */ + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | + CSR_HW_IF_CONFIG_REG_BIT_MAC_SI); + + spin_unlock_irqrestore(&priv->lock, flags); +} + + + /* * EEPROM */ @@ -407,6 +439,7 @@ static struct iwl_lib_ops iwl5000_lib = { .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, .apm_ops = { .init = iwl5000_apm_init, + .config = iwl5000_nic_init, .set_pwr_src = iwl4965_set_pwr_src, }, .eeprom_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 06ed30044a4..dc1f027c66a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -295,6 +295,7 @@ struct iwl_eeprom_calib_info { #define EEPROM_3945_RF_CFG_TYPE_MAX 0x0 #define EEPROM_4965_RF_CFG_TYPE_MAX 0x1 +#define EEPROM_5000_RF_CFG_TYPE_MAX 0x3 /* * Per-channel regulatory data. -- cgit v1.2.3-70-g09d2 From 5a36ba0e412a0e12a8bf2648a075226c1dd7870d Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 24 Apr 2008 11:55:37 -0700 Subject: iwlwifi: rename iwl-4965-commands to iwl-commands.h This patch renames iwl-4965-commands to iwl-commands.h Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-commands.h | 2759 ---------------------- drivers/net/wireless/iwlwifi/iwl-4965-hw.h | 4 +- drivers/net/wireless/iwlwifi/iwl-4965.h | 2 +- drivers/net/wireless/iwlwifi/iwl-commands.h | 2759 ++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-eeprom.c | 2 +- drivers/net/wireless/iwlwifi/iwl-power.c | 2 +- drivers/net/wireless/iwlwifi/iwl-power.h | 2 +- 7 files changed, 2765 insertions(+), 2765 deletions(-) delete mode 100644 drivers/net/wireless/iwlwifi/iwl-4965-commands.h create mode 100644 drivers/net/wireless/iwlwifi/iwl-commands.h (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-commands.h b/drivers/net/wireless/iwlwifi/iwl-4965-commands.h deleted file mode 100644 index a5c33f35417..00000000000 --- a/drivers/net/wireless/iwlwifi/iwl-4965-commands.h +++ /dev/null @@ -1,2759 +0,0 @@ -/****************************************************************************** - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, - * USA - * - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * Contact Information: - * James P. Ketrenos - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - *****************************************************************************/ -/* - * Please use this file (iwl-4965-commands.h) only for uCode API definitions. - * Please use iwl-4965-hw.h for hardware-related definitions. - * Please use iwl-4965.h for driver implementation definitions. - */ - -#ifndef __iwl4965_commands_h__ -#define __iwl4965_commands_h__ - -enum { - REPLY_ALIVE = 0x1, - REPLY_ERROR = 0x2, - - /* RXON and QOS commands */ - REPLY_RXON = 0x10, - REPLY_RXON_ASSOC = 0x11, - REPLY_QOS_PARAM = 0x13, - REPLY_RXON_TIMING = 0x14, - - /* Multi-Station support */ - REPLY_ADD_STA = 0x18, - REPLY_REMOVE_STA = 0x19, /* not used */ - REPLY_REMOVE_ALL_STA = 0x1a, /* not used */ - - /* Security */ - REPLY_WEPKEY = 0x20, - - /* RX, TX, LEDs */ - REPLY_TX = 0x1c, - REPLY_RATE_SCALE = 0x47, /* 3945 only */ - REPLY_LEDS_CMD = 0x48, - REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* 4965 only */ - - /* 802.11h related */ - RADAR_NOTIFICATION = 0x70, /* not used */ - REPLY_QUIET_CMD = 0x71, /* not used */ - REPLY_CHANNEL_SWITCH = 0x72, - CHANNEL_SWITCH_NOTIFICATION = 0x73, - REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74, - SPECTRUM_MEASURE_NOTIFICATION = 0x75, - - /* Power Management */ - POWER_TABLE_CMD = 0x77, - PM_SLEEP_NOTIFICATION = 0x7A, - PM_DEBUG_STATISTIC_NOTIFIC = 0x7B, - - /* Scan commands and notifications */ - REPLY_SCAN_CMD = 0x80, - REPLY_SCAN_ABORT_CMD = 0x81, - SCAN_START_NOTIFICATION = 0x82, - SCAN_RESULTS_NOTIFICATION = 0x83, - SCAN_COMPLETE_NOTIFICATION = 0x84, - - /* IBSS/AP commands */ - BEACON_NOTIFICATION = 0x90, - REPLY_TX_BEACON = 0x91, - WHO_IS_AWAKE_NOTIFICATION = 0x94, /* not used */ - - /* Miscellaneous commands */ - QUIET_NOTIFICATION = 0x96, /* not used */ - REPLY_TX_PWR_TABLE_CMD = 0x97, - MEASURE_ABORT_NOTIFICATION = 0x99, /* not used */ - - /* Bluetooth device coexistance config command */ - REPLY_BT_CONFIG = 0x9b, - - /* Statistics */ - REPLY_STATISTICS_CMD = 0x9c, - STATISTICS_NOTIFICATION = 0x9d, - - /* RF-KILL commands and notifications */ - REPLY_CARD_STATE_CMD = 0xa0, - CARD_STATE_NOTIFICATION = 0xa1, - - /* Missed beacons notification */ - MISSED_BEACONS_NOTIFICATION = 0xa2, - - REPLY_CT_KILL_CONFIG_CMD = 0xa4, - SENSITIVITY_CMD = 0xa8, - REPLY_PHY_CALIBRATION_CMD = 0xb0, - REPLY_RX_PHY_CMD = 0xc0, - REPLY_RX_MPDU_CMD = 0xc1, - REPLY_RX = 0xc3, - REPLY_COMPRESSED_BA = 0xc5, - REPLY_MAX = 0xff -}; - -/****************************************************************************** - * (0) - * Commonly used structures and definitions: - * Command header, rate_n_flags, txpower - * - *****************************************************************************/ - -/* iwl_cmd_header flags value */ -#define IWL_CMD_FAILED_MSK 0x40 - -/** - * struct iwl_cmd_header - * - * This header format appears in the beginning of each command sent from the - * driver, and each response/notification received from uCode. - */ -struct iwl_cmd_header { - u8 cmd; /* Command ID: REPLY_RXON, etc. */ - u8 flags; /* IWL_CMD_* */ - /* - * The driver sets up the sequence number to values of its chosing. - * uCode does not use this value, but passes it back to the driver - * when sending the response to each driver-originated command, so - * the driver can match the response to the command. Since the values - * don't get used by uCode, the driver may set up an arbitrary format. - * - * There is one exception: uCode sets bit 15 when it originates - * the response/notification, i.e. when the response/notification - * is not a direct response to a command sent by the driver. For - * example, uCode issues REPLY_3945_RX when it sends a received frame - * to the driver; it is not a direct response to any driver command. - * - * The Linux driver uses the following format: - * - * 0:7 index/position within Tx queue - * 8:13 Tx queue selection - * 14:14 driver sets this to indicate command is in the 'huge' - * storage at the end of the command buffers, i.e. scan cmd - * 15:15 uCode sets this in uCode-originated response/notification - */ - __le16 sequence; - - /* command or response/notification data follows immediately */ - u8 data[0]; -} __attribute__ ((packed)); - -/** - * 4965 rate_n_flags bit fields - * - * rate_n_flags format is used in following 4965 commands: - * REPLY_RX (response only) - * REPLY_TX (both command and response) - * REPLY_TX_LINK_QUALITY_CMD - * - * High-throughput (HT) rate format for bits 7:0 (bit 8 must be "1"): - * 2-0: 0) 6 Mbps - * 1) 12 Mbps - * 2) 18 Mbps - * 3) 24 Mbps - * 4) 36 Mbps - * 5) 48 Mbps - * 6) 54 Mbps - * 7) 60 Mbps - * - * 3: 0) Single stream (SISO) - * 1) Dual stream (MIMO) - * - * 5: Value of 0x20 in bits 7:0 indicates 6 Mbps FAT duplicate data - * - * Legacy OFDM rate format for bits 7:0 (bit 8 must be "0", bit 9 "0"): - * 3-0: 0xD) 6 Mbps - * 0xF) 9 Mbps - * 0x5) 12 Mbps - * 0x7) 18 Mbps - * 0x9) 24 Mbps - * 0xB) 36 Mbps - * 0x1) 48 Mbps - * 0x3) 54 Mbps - * - * Legacy CCK rate format for bits 7:0 (bit 8 must be "0", bit 9 "1"): - * 3-0: 10) 1 Mbps - * 20) 2 Mbps - * 55) 5.5 Mbps - * 110) 11 Mbps - */ -#define RATE_MCS_CODE_MSK 0x7 -#define RATE_MCS_MIMO_POS 3 -#define RATE_MCS_MIMO_MSK 0x8 -#define RATE_MCS_HT_DUP_POS 5 -#define RATE_MCS_HT_DUP_MSK 0x20 - -/* Bit 8: (1) HT format, (0) legacy format in bits 7:0 */ -#define RATE_MCS_FLAGS_POS 8 -#define RATE_MCS_HT_POS 8 -#define RATE_MCS_HT_MSK 0x100 - -/* Bit 9: (1) CCK, (0) OFDM. HT (bit 8) must be "0" for this bit to be valid */ -#define RATE_MCS_CCK_POS 9 -#define RATE_MCS_CCK_MSK 0x200 - -/* Bit 10: (1) Use Green Field preamble */ -#define RATE_MCS_GF_POS 10 -#define RATE_MCS_GF_MSK 0x400 - -/* Bit 11: (1) Use 40Mhz FAT chnl width, (0) use 20 MHz legacy chnl width */ -#define RATE_MCS_FAT_POS 11 -#define RATE_MCS_FAT_MSK 0x800 - -/* Bit 12: (1) Duplicate data on both 20MHz chnls. FAT (bit 11) must be set. */ -#define RATE_MCS_DUP_POS 12 -#define RATE_MCS_DUP_MSK 0x1000 - -/* Bit 13: (1) Short guard interval (0.4 usec), (0) normal GI (0.8 usec) */ -#define RATE_MCS_SGI_POS 13 -#define RATE_MCS_SGI_MSK 0x2000 - -/** - * rate_n_flags Tx antenna masks (4965 has 2 transmitters): - * bit14:15 01 B inactive, A active - * 10 B active, A inactive - * 11 Both active - */ -#define RATE_MCS_ANT_POS 14 -#define RATE_MCS_ANT_A_MSK 0x04000 -#define RATE_MCS_ANT_B_MSK 0x08000 -#define RATE_MCS_ANT_C_MSK 0x10000 -#define RATE_MCS_ANT_ABC_MSK 0x1C000 - - -/** - * struct iwl4965_tx_power - txpower format used in REPLY_SCAN_CMD - * - * Scan uses only one transmitter, so only one analog/dsp gain pair is needed. - */ -struct iwl4965_tx_power { - u8 tx_gain; /* gain for analog radio */ - u8 dsp_atten; /* gain for DSP */ -} __attribute__ ((packed)); - -#define POWER_TABLE_NUM_ENTRIES 33 -#define POWER_TABLE_NUM_HT_OFDM_ENTRIES 32 -#define POWER_TABLE_CCK_ENTRY 32 - -/** - * union iwl4965_tx_power_dual_stream - * - * Host format used for REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH - * Use __le32 version (struct tx_power_dual_stream) when building command. - * - * Driver provides radio gain and DSP attenuation settings to device in pairs, - * one value for each transmitter chain. The first value is for transmitter A, - * second for transmitter B. - * - * For SISO bit rates, both values in a pair should be identical. - * For MIMO rates, one value may be different from the other, - * in order to balance the Tx output between the two transmitters. - * - * See more details in doc for TXPOWER in iwl-4965-hw.h. - */ -union iwl4965_tx_power_dual_stream { - struct { - u8 radio_tx_gain[2]; - u8 dsp_predis_atten[2]; - } s; - u32 dw; -}; - -/** - * struct tx_power_dual_stream - * - * Table entries in REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH - * - * Same format as iwl_tx_power_dual_stream, but __le32 - */ -struct tx_power_dual_stream { - __le32 dw; -} __attribute__ ((packed)); - -/** - * struct iwl4965_tx_power_db - * - * Entire table within REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH - */ -struct iwl4965_tx_power_db { - struct tx_power_dual_stream power_tbl[POWER_TABLE_NUM_ENTRIES]; -} __attribute__ ((packed)); - - -/****************************************************************************** - * (0a) - * Alive and Error Commands & Responses: - * - *****************************************************************************/ - -#define UCODE_VALID_OK __constant_cpu_to_le32(0x1) -#define INITIALIZE_SUBTYPE (9) - -/* - * ("Initialize") REPLY_ALIVE = 0x1 (response only, not a command) - * - * uCode issues this "initialize alive" notification once the initialization - * uCode image has completed its work, and is ready to load the runtime image. - * This is the *first* "alive" notification that the driver will receive after - * rebooting uCode; the "initialize" alive is indicated by subtype field == 9. - * - * See comments documenting "BSM" (bootstrap state machine). - * - * For 4965, this notification contains important calibration data for - * calculating txpower settings: - * - * 1) Power supply voltage indication. The voltage sensor outputs higher - * values for lower voltage, and vice versa. - * - * 2) Temperature measurement parameters, for each of two channel widths - * (20 MHz and 40 MHz) supported by the radios. Temperature sensing - * is done via one of the receiver chains, and channel width influences - * the results. - * - * 3) Tx gain compensation to balance 4965's 2 Tx chains for MIMO operation, - * for each of 5 frequency ranges. - */ -struct iwl4965_init_alive_resp { - u8 ucode_minor; - u8 ucode_major; - __le16 reserved1; - u8 sw_rev[8]; - u8 ver_type; - u8 ver_subtype; /* "9" for initialize alive */ - __le16 reserved2; - __le32 log_event_table_ptr; - __le32 error_event_table_ptr; - __le32 timestamp; - __le32 is_valid; - - /* calibration values from "initialize" uCode */ - __le32 voltage; /* signed, higher value is lower voltage */ - __le32 therm_r1[2]; /* signed, 1st for normal, 2nd for FAT channel*/ - __le32 therm_r2[2]; /* signed */ - __le32 therm_r3[2]; /* signed */ - __le32 therm_r4[2]; /* signed */ - __le32 tx_atten[5][2]; /* signed MIMO gain comp, 5 freq groups, - * 2 Tx chains */ -} __attribute__ ((packed)); - - -/** - * REPLY_ALIVE = 0x1 (response only, not a command) - * - * uCode issues this "alive" notification once the runtime image is ready - * to receive commands from the driver. This is the *second* "alive" - * notification that the driver will receive after rebooting uCode; - * this "alive" is indicated by subtype field != 9. - * - * See comments documenting "BSM" (bootstrap state machine). - * - * This response includes two pointers to structures within the device's - * data SRAM (access via HBUS_TARG_MEM_* regs) that are useful for debugging: - * - * 1) log_event_table_ptr indicates base of the event log. This traces - * a 256-entry history of uCode execution within a circular buffer. - * Its header format is: - * - * __le32 log_size; log capacity (in number of entries) - * __le32 type; (1) timestamp with each entry, (0) no timestamp - * __le32 wraps; # times uCode has wrapped to top of circular buffer - * __le32 write_index; next circular buffer entry that uCode would fill - * - * The header is followed by the circular buffer of log entries. Entries - * with timestamps have the following format: - * - * __le32 event_id; range 0 - 1500 - * __le32 timestamp; low 32 bits of TSF (of network, if associated) - * __le32 data; event_id-specific data value - * - * Entries without timestamps contain only event_id and data. - * - * 2) error_event_table_ptr indicates base of the error log. This contains - * information about any uCode error that occurs. For 4965, the format - * of the error log is: - * - * __le32 valid; (nonzero) valid, (0) log is empty - * __le32 error_id; type of error - * __le32 pc; program counter - * __le32 blink1; branch link - * __le32 blink2; branch link - * __le32 ilink1; interrupt link - * __le32 ilink2; interrupt link - * __le32 data1; error-specific data - * __le32 data2; error-specific data - * __le32 line; source code line of error - * __le32 bcon_time; beacon timer - * __le32 tsf_low; network timestamp function timer - * __le32 tsf_hi; network timestamp function timer - * - * The Linux driver can print both logs to the system log when a uCode error - * occurs. - */ -struct iwl4965_alive_resp { - u8 ucode_minor; - u8 ucode_major; - __le16 reserved1; - u8 sw_rev[8]; - u8 ver_type; - u8 ver_subtype; /* not "9" for runtime alive */ - __le16 reserved2; - __le32 log_event_table_ptr; /* SRAM address for event log */ - __le32 error_event_table_ptr; /* SRAM address for error log */ - __le32 timestamp; - __le32 is_valid; -} __attribute__ ((packed)); - - -union tsf { - u8 byte[8]; - __le16 word[4]; - __le32 dw[2]; -}; - -/* - * REPLY_ERROR = 0x2 (response only, not a command) - */ -struct iwl4965_error_resp { - __le32 error_type; - u8 cmd_id; - u8 reserved1; - __le16 bad_cmd_seq_num; - __le32 error_info; - union tsf timestamp; -} __attribute__ ((packed)); - -/****************************************************************************** - * (1) - * RXON Commands & Responses: - * - *****************************************************************************/ - -/* - * Rx config defines & structure - */ -/* rx_config device types */ -enum { - RXON_DEV_TYPE_AP = 1, - RXON_DEV_TYPE_ESS = 3, - RXON_DEV_TYPE_IBSS = 4, - RXON_DEV_TYPE_SNIFFER = 6, -}; - - -#define RXON_RX_CHAIN_DRIVER_FORCE_MSK __constant_cpu_to_le16(0x1 << 0) -#define RXON_RX_CHAIN_VALID_MSK __constant_cpu_to_le16(0x7 << 1) -#define RXON_RX_CHAIN_VALID_POS (1) -#define RXON_RX_CHAIN_FORCE_SEL_MSK __constant_cpu_to_le16(0x7 << 4) -#define RXON_RX_CHAIN_FORCE_SEL_POS (4) -#define RXON_RX_CHAIN_FORCE_MIMO_SEL_MSK __constant_cpu_to_le16(0x7 << 7) -#define RXON_RX_CHAIN_FORCE_MIMO_SEL_POS (7) -#define RXON_RX_CHAIN_CNT_MSK __constant_cpu_to_le16(0x3 << 10) -#define RXON_RX_CHAIN_CNT_POS (10) -#define RXON_RX_CHAIN_MIMO_CNT_MSK __constant_cpu_to_le16(0x3 << 12) -#define RXON_RX_CHAIN_MIMO_CNT_POS (12) -#define RXON_RX_CHAIN_MIMO_FORCE_MSK __constant_cpu_to_le16(0x1 << 14) -#define RXON_RX_CHAIN_MIMO_FORCE_POS (14) - -/* rx_config flags */ -/* band & modulation selection */ -#define RXON_FLG_BAND_24G_MSK __constant_cpu_to_le32(1 << 0) -#define RXON_FLG_CCK_MSK __constant_cpu_to_le32(1 << 1) -/* auto detection enable */ -#define RXON_FLG_AUTO_DETECT_MSK __constant_cpu_to_le32(1 << 2) -/* TGg protection when tx */ -#define RXON_FLG_TGG_PROTECT_MSK __constant_cpu_to_le32(1 << 3) -/* cck short slot & preamble */ -#define RXON_FLG_SHORT_SLOT_MSK __constant_cpu_to_le32(1 << 4) -#define RXON_FLG_SHORT_PREAMBLE_MSK __constant_cpu_to_le32(1 << 5) -/* antenna selection */ -#define RXON_FLG_DIS_DIV_MSK __constant_cpu_to_le32(1 << 7) -#define RXON_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0x0f00) -#define RXON_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8) -#define RXON_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9) -/* radar detection enable */ -#define RXON_FLG_RADAR_DETECT_MSK __constant_cpu_to_le32(1 << 12) -#define RXON_FLG_TGJ_NARROW_BAND_MSK __constant_cpu_to_le32(1 << 13) -/* rx response to host with 8-byte TSF -* (according to ON_AIR deassertion) */ -#define RXON_FLG_TSF2HOST_MSK __constant_cpu_to_le32(1 << 15) - - -/* HT flags */ -#define RXON_FLG_CTRL_CHANNEL_LOC_POS (22) -#define RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK __constant_cpu_to_le32(0x1 << 22) - -#define RXON_FLG_HT_OPERATING_MODE_POS (23) - -#define RXON_FLG_HT_PROT_MSK __constant_cpu_to_le32(0x1 << 23) -#define RXON_FLG_FAT_PROT_MSK __constant_cpu_to_le32(0x2 << 23) - -#define RXON_FLG_CHANNEL_MODE_POS (25) -#define RXON_FLG_CHANNEL_MODE_MSK __constant_cpu_to_le32(0x3 << 25) -#define RXON_FLG_CHANNEL_MODE_PURE_40_MSK __constant_cpu_to_le32(0x1 << 25) -#define RXON_FLG_CHANNEL_MODE_MIXED_MSK __constant_cpu_to_le32(0x2 << 25) - -/* rx_config filter flags */ -/* accept all data frames */ -#define RXON_FILTER_PROMISC_MSK __constant_cpu_to_le32(1 << 0) -/* pass control & management to host */ -#define RXON_FILTER_CTL2HOST_MSK __constant_cpu_to_le32(1 << 1) -/* accept multi-cast */ -#define RXON_FILTER_ACCEPT_GRP_MSK __constant_cpu_to_le32(1 << 2) -/* don't decrypt uni-cast frames */ -#define RXON_FILTER_DIS_DECRYPT_MSK __constant_cpu_to_le32(1 << 3) -/* don't decrypt multi-cast frames */ -#define RXON_FILTER_DIS_GRP_DECRYPT_MSK __constant_cpu_to_le32(1 << 4) -/* STA is associated */ -#define RXON_FILTER_ASSOC_MSK __constant_cpu_to_le32(1 << 5) -/* transfer to host non bssid beacons in associated state */ -#define RXON_FILTER_BCON_AWARE_MSK __constant_cpu_to_le32(1 << 6) - -/** - * REPLY_RXON = 0x10 (command, has simple generic response) - * - * RXON tunes the radio tuner to a service channel, and sets up a number - * of parameters that are used primarily for Rx, but also for Tx operations. - * - * NOTE: When tuning to a new channel, driver must set the - * RXON_FILTER_ASSOC_MSK to 0. This will clear station-dependent - * info within the device, including the station tables, tx retry - * rate tables, and txpower tables. Driver must build a new station - * table and txpower table before transmitting anything on the RXON - * channel. - * - * NOTE: All RXONs wipe clean the internal txpower table. Driver must - * issue a new REPLY_TX_PWR_TABLE_CMD after each REPLY_RXON (0x10), - * regardless of whether RXON_FILTER_ASSOC_MSK is set. - */ -struct iwl4965_rxon_cmd { - u8 node_addr[6]; - __le16 reserved1; - u8 bssid_addr[6]; - __le16 reserved2; - u8 wlap_bssid_addr[6]; - __le16 reserved3; - u8 dev_type; - u8 air_propagation; - __le16 rx_chain; - u8 ofdm_basic_rates; - u8 cck_basic_rates; - __le16 assoc_id; - __le32 flags; - __le32 filter_flags; - __le16 channel; - u8 ofdm_ht_single_stream_basic_rates; - u8 ofdm_ht_dual_stream_basic_rates; -} __attribute__ ((packed)); - -/* - * REPLY_RXON_ASSOC = 0x11 (command, has simple generic response) - */ -struct iwl4965_rxon_assoc_cmd { - __le32 flags; - __le32 filter_flags; - u8 ofdm_basic_rates; - u8 cck_basic_rates; - u8 ofdm_ht_single_stream_basic_rates; - u8 ofdm_ht_dual_stream_basic_rates; - __le16 rx_chain_select_flags; - __le16 reserved; -} __attribute__ ((packed)); - -/* - * REPLY_RXON_TIMING = 0x14 (command, has simple generic response) - */ -struct iwl4965_rxon_time_cmd { - union tsf timestamp; - __le16 beacon_interval; - __le16 atim_window; - __le32 beacon_init_val; - __le16 listen_interval; - __le16 reserved; -} __attribute__ ((packed)); - -/* - * REPLY_CHANNEL_SWITCH = 0x72 (command, has simple generic response) - */ -struct iwl4965_channel_switch_cmd { - u8 band; - u8 expect_beacon; - __le16 channel; - __le32 rxon_flags; - __le32 rxon_filter_flags; - __le32 switch_time; - struct iwl4965_tx_power_db tx_power; -} __attribute__ ((packed)); - -/* - * CHANNEL_SWITCH_NOTIFICATION = 0x73 (notification only, not a command) - */ -struct iwl4965_csa_notification { - __le16 band; - __le16 channel; - __le32 status; /* 0 - OK, 1 - fail */ -} __attribute__ ((packed)); - -/****************************************************************************** - * (2) - * Quality-of-Service (QOS) Commands & Responses: - * - *****************************************************************************/ - -/** - * struct iwl_ac_qos -- QOS timing params for REPLY_QOS_PARAM - * One for each of 4 EDCA access categories in struct iwl_qosparam_cmd - * - * @cw_min: Contention window, start value in numbers of slots. - * Should be a power-of-2, minus 1. Device's default is 0x0f. - * @cw_max: Contention window, max value in numbers of slots. - * Should be a power-of-2, minus 1. Device's default is 0x3f. - * @aifsn: Number of slots in Arbitration Interframe Space (before - * performing random backoff timing prior to Tx). Device default 1. - * @edca_txop: Length of Tx opportunity, in uSecs. Device default is 0. - * - * Device will automatically increase contention window by (2*CW) + 1 for each - * transmission retry. Device uses cw_max as a bit mask, ANDed with new CW - * value, to cap the CW value. - */ -struct iwl4965_ac_qos { - __le16 cw_min; - __le16 cw_max; - u8 aifsn; - u8 reserved1; - __le16 edca_txop; -} __attribute__ ((packed)); - -/* QoS flags defines */ -#define QOS_PARAM_FLG_UPDATE_EDCA_MSK __constant_cpu_to_le32(0x01) -#define QOS_PARAM_FLG_TGN_MSK __constant_cpu_to_le32(0x02) -#define QOS_PARAM_FLG_TXOP_TYPE_MSK __constant_cpu_to_le32(0x10) - -/* Number of Access Categories (AC) (EDCA), queues 0..3 */ -#define AC_NUM 4 - -/* - * REPLY_QOS_PARAM = 0x13 (command, has simple generic response) - * - * This command sets up timings for each of the 4 prioritized EDCA Tx FIFOs - * 0: Background, 1: Best Effort, 2: Video, 3: Voice. - */ -struct iwl4965_qosparam_cmd { - __le32 qos_flags; - struct iwl4965_ac_qos ac[AC_NUM]; -} __attribute__ ((packed)); - -/****************************************************************************** - * (3) - * Add/Modify Stations Commands & Responses: - * - *****************************************************************************/ -/* - * Multi station support - */ - -/* Special, dedicated locations within device's station table */ -#define IWL_AP_ID 0 -#define IWL_MULTICAST_ID 1 -#define IWL_STA_ID 2 -#define IWL4965_BROADCAST_ID 31 -#define IWL4965_STATION_COUNT 32 -#define IWL5000_BROADCAST_ID 15 -#define IWL5000_STATION_COUNT 16 - -#define IWL_STATION_COUNT 32 /* MAX(3945,4965)*/ -#define IWL_INVALID_STATION 255 - -#define STA_FLG_PWR_SAVE_MSK __constant_cpu_to_le32(1 << 8); -#define STA_FLG_RTS_MIMO_PROT_MSK __constant_cpu_to_le32(1 << 17) -#define STA_FLG_AGG_MPDU_8US_MSK __constant_cpu_to_le32(1 << 18) -#define STA_FLG_MAX_AGG_SIZE_POS (19) -#define STA_FLG_MAX_AGG_SIZE_MSK __constant_cpu_to_le32(3 << 19) -#define STA_FLG_FAT_EN_MSK __constant_cpu_to_le32(1 << 21) -#define STA_FLG_MIMO_DIS_MSK __constant_cpu_to_le32(1 << 22) -#define STA_FLG_AGG_MPDU_DENSITY_POS (23) -#define STA_FLG_AGG_MPDU_DENSITY_MSK __constant_cpu_to_le32(7 << 23) - -/* Use in mode field. 1: modify existing entry, 0: add new station entry */ -#define STA_CONTROL_MODIFY_MSK 0x01 - -/* key flags __le16*/ -#define STA_KEY_FLG_ENCRYPT_MSK __constant_cpu_to_le16(0x0007) -#define STA_KEY_FLG_NO_ENC __constant_cpu_to_le16(0x0000) -#define STA_KEY_FLG_WEP __constant_cpu_to_le16(0x0001) -#define STA_KEY_FLG_CCMP __constant_cpu_to_le16(0x0002) -#define STA_KEY_FLG_TKIP __constant_cpu_to_le16(0x0003) - -#define STA_KEY_FLG_KEYID_POS 8 -#define STA_KEY_FLG_INVALID __constant_cpu_to_le16(0x0800) -/* wep key is either from global key (0) or from station info array (1) */ -#define STA_KEY_FLG_MAP_KEY_MSK __constant_cpu_to_le16(0x0008) - -/* wep key in STA: 5-bytes (0) or 13-bytes (1) */ -#define STA_KEY_FLG_KEY_SIZE_MSK __constant_cpu_to_le16(0x1000) -#define STA_KEY_MULTICAST_MSK __constant_cpu_to_le16(0x4000) -#define STA_KEY_MAX_NUM 8 - -/* Flags indicate whether to modify vs. don't change various station params */ -#define STA_MODIFY_KEY_MASK 0x01 -#define STA_MODIFY_TID_DISABLE_TX 0x02 -#define STA_MODIFY_TX_RATE_MSK 0x04 -#define STA_MODIFY_ADDBA_TID_MSK 0x08 -#define STA_MODIFY_DELBA_TID_MSK 0x10 - -/* Receiver address (actually, Rx station's index into station table), - * combined with Traffic ID (QOS priority), in format used by Tx Scheduler */ -#define BUILD_RAxTID(sta_id, tid) (((sta_id) << 4) + (tid)) - -struct iwl4965_keyinfo { - __le16 key_flags; - u8 tkip_rx_tsc_byte2; /* TSC[2] for key mix ph1 detection */ - u8 reserved1; - __le16 tkip_rx_ttak[5]; /* 10-byte unicast TKIP TTAK */ - u8 key_offset; - u8 reserved2; - u8 key[16]; /* 16-byte unicast decryption key */ -} __attribute__ ((packed)); - -/** - * struct sta_id_modify - * @addr[ETH_ALEN]: station's MAC address - * @sta_id: index of station in uCode's station table - * @modify_mask: STA_MODIFY_*, 1: modify, 0: don't change - * - * Driver selects unused table index when adding new station, - * or the index to a pre-existing station entry when modifying that station. - * Some indexes have special purposes (IWL_AP_ID, index 0, is for AP). - * - * modify_mask flags select which parameters to modify vs. leave alone. - */ -struct sta_id_modify { - u8 addr[ETH_ALEN]; - __le16 reserved1; - u8 sta_id; - u8 modify_mask; - __le16 reserved2; -} __attribute__ ((packed)); - -/* - * REPLY_ADD_STA = 0x18 (command) - * - * The device contains an internal table of per-station information, - * with info on security keys, aggregation parameters, and Tx rates for - * initial Tx attempt and any retries (4965 uses REPLY_TX_LINK_QUALITY_CMD, - * 3945 uses REPLY_RATE_SCALE to set up rate tables). - * - * REPLY_ADD_STA sets up the table entry for one station, either creating - * a new entry, or modifying a pre-existing one. - * - * NOTE: RXON command (without "associated" bit set) wipes the station table - * clean. Moving into RF_KILL state does this also. Driver must set up - * new station table before transmitting anything on the RXON channel - * (except active scans or active measurements; those commands carry - * their own txpower/rate setup data). - * - * When getting started on a new channel, driver must set up the - * IWL_BROADCAST_ID entry (last entry in the table). For a client - * station in a BSS, once an AP is selected, driver sets up the AP STA - * in the IWL_AP_ID entry (1st entry in the table). BROADCAST and AP - * are all that are needed for a BSS client station. If the device is - * used as AP, or in an IBSS network, driver must set up station table - * entries for all STAs in network, starting with index IWL_STA_ID. - */ -struct iwl4965_addsta_cmd { - u8 mode; /* 1: modify existing, 0: add new station */ - u8 reserved[3]; - struct sta_id_modify sta; - struct iwl4965_keyinfo key; - __le32 station_flags; /* STA_FLG_* */ - __le32 station_flags_msk; /* STA_FLG_* */ - - /* bit field to disable (1) or enable (0) Tx for Traffic ID (TID) - * 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 reserved1; - - /* TID for which to add block-ack support. - * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ - u8 add_immediate_ba_tid; - - /* TID for which to remove block-ack support. - * Set modify_mask bit STA_MODIFY_DELBA_TID_MSK to use this field. */ - u8 remove_immediate_ba_tid; - - /* Starting Sequence Number for added block-ack support. - * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ - __le16 add_immediate_ba_ssn; - - __le32 reserved2; -} __attribute__ ((packed)); - -#define ADD_STA_SUCCESS_MSK 0x1 -#define ADD_STA_NO_ROOM_IN_TABLE 0x2 -#define ADD_STA_NO_BLOCK_ACK_RESOURCE 0x4 -#define ADD_STA_MODIFY_NON_EXIST_STA 0x8 -/* - * REPLY_ADD_STA = 0x18 (response) - */ -struct iwl4965_add_sta_resp { - u8 status; /* ADD_STA_* */ -} __attribute__ ((packed)); - -/* - * REPLY_WEP_KEY = 0x20 - */ -struct iwl_wep_key { - u8 key_index; - u8 key_offset; - u8 reserved1[2]; - u8 key_size; - u8 reserved2[3]; - u8 key[16]; -} __attribute__ ((packed)); - -struct iwl_wep_cmd { - u8 num_keys; - u8 global_key_type; - u8 flags; - u8 reserved; - struct iwl_wep_key key[0]; -} __attribute__ ((packed)); - -#define WEP_KEY_WEP_TYPE 1 -#define WEP_KEYS_MAX 4 -#define WEP_INVALID_OFFSET 0xff -#define WEP_KEY_LEN_128 13 - -/****************************************************************************** - * (4) - * Rx Responses: - * - *****************************************************************************/ - -struct iwl4965_rx_frame_stats { - u8 phy_count; - u8 id; - u8 rssi; - u8 agc; - __le16 sig_avg; - __le16 noise_diff; - u8 payload[0]; -} __attribute__ ((packed)); - -struct iwl4965_rx_frame_hdr { - __le16 channel; - __le16 phy_flags; - u8 reserved1; - u8 rate; - __le16 len; - u8 payload[0]; -} __attribute__ ((packed)); - -#define RX_RES_STATUS_NO_CRC32_ERROR __constant_cpu_to_le32(1 << 0) -#define RX_RES_STATUS_NO_RXE_OVERFLOW __constant_cpu_to_le32(1 << 1) - -#define RX_RES_PHY_FLAGS_BAND_24_MSK __constant_cpu_to_le16(1 << 0) -#define RX_RES_PHY_FLAGS_MOD_CCK_MSK __constant_cpu_to_le16(1 << 1) -#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK __constant_cpu_to_le16(1 << 2) -#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK __constant_cpu_to_le16(1 << 3) -#define RX_RES_PHY_FLAGS_ANTENNA_MSK __constant_cpu_to_le16(0xf0) - -#define RX_RES_STATUS_SEC_TYPE_MSK (0x7 << 8) -#define RX_RES_STATUS_SEC_TYPE_NONE (0x0 << 8) -#define RX_RES_STATUS_SEC_TYPE_WEP (0x1 << 8) -#define RX_RES_STATUS_SEC_TYPE_CCMP (0x2 << 8) -#define RX_RES_STATUS_SEC_TYPE_TKIP (0x3 << 8) -#define RX_RES_STATUS_SEC_TYPE_ERR (0x7 << 8) - -#define RX_RES_STATUS_STATION_FOUND (1<<6) -#define RX_RES_STATUS_NO_STATION_INFO_MISMATCH (1<<7) - -#define RX_RES_STATUS_DECRYPT_TYPE_MSK (0x3 << 11) -#define RX_RES_STATUS_NOT_DECRYPT (0x0 << 11) -#define RX_RES_STATUS_DECRYPT_OK (0x3 << 11) -#define RX_RES_STATUS_BAD_ICV_MIC (0x1 << 11) -#define RX_RES_STATUS_BAD_KEY_TTAK (0x2 << 11) - -#define RX_MPDU_RES_STATUS_ICV_OK (0x20) -#define RX_MPDU_RES_STATUS_MIC_OK (0x40) -#define RX_MPDU_RES_STATUS_TTAK_OK (1 << 7) -#define RX_MPDU_RES_STATUS_DEC_DONE_MSK (0x800) - -struct iwl4965_rx_frame_end { - __le32 status; - __le64 timestamp; - __le32 beacon_timestamp; -} __attribute__ ((packed)); - -/* - * REPLY_3945_RX = 0x1b (response only, not a command) - * - * NOTE: DO NOT dereference from casts to this structure - * It is provided only for calculating minimum data set size. - * The actual offsets of the hdr and end are dynamic based on - * stats.phy_count - */ -struct iwl4965_rx_frame { - struct iwl4965_rx_frame_stats stats; - struct iwl4965_rx_frame_hdr hdr; - struct iwl4965_rx_frame_end end; -} __attribute__ ((packed)); - -/* Fixed (non-configurable) rx data from phy */ -#define RX_PHY_FLAGS_ANTENNAE_OFFSET (4) -#define RX_PHY_FLAGS_ANTENNAE_MASK (0x70) -#define IWL_AGC_DB_MASK (0x3f80) /* MASK(7,13) */ -#define IWL_AGC_DB_POS (7) -struct iwl4965_rx_non_cfg_phy { - __le16 ant_selection; /* ant A bit 4, ant B bit 5, ant C bit 6 */ - __le16 agc_info; /* agc code 0:6, agc dB 7:13, reserved 14:15 */ - u8 rssi_info[6]; /* we use even entries, 0/2/4 for A/B/C rssi */ - u8 pad[0]; -} __attribute__ ((packed)); - -/* - * REPLY_RX = 0xc3 (response only, not a command) - * Used only for legacy (non 11n) frames. - */ -#define RX_RES_PHY_CNT 14 -struct iwl4965_rx_phy_res { - u8 non_cfg_phy_cnt; /* non configurable DSP phy data byte count */ - u8 cfg_phy_cnt; /* configurable DSP phy data byte count */ - u8 stat_id; /* configurable DSP phy data set ID */ - u8 reserved1; - __le64 timestamp; /* TSF at on air rise */ - __le32 beacon_time_stamp; /* beacon at on-air rise */ - __le16 phy_flags; /* general phy flags: band, modulation, ... */ - __le16 channel; /* channel number */ - __le16 non_cfg_phy[RX_RES_PHY_CNT]; /* upto 14 phy entries */ - __le32 reserved2; - __le32 rate_n_flags; /* RATE_MCS_* */ - __le16 byte_count; /* frame's byte-count */ - __le16 reserved3; -} __attribute__ ((packed)); - -struct iwl4965_rx_mpdu_res_start { - __le16 byte_count; - __le16 reserved; -} __attribute__ ((packed)); - - -/****************************************************************************** - * (5) - * Tx Commands & Responses: - * - * Driver must place each REPLY_TX command into one of the prioritized Tx - * queues in host DRAM, shared between driver and device (see comments for - * SCD registers and Tx/Rx Queues). When the device's Tx scheduler and uCode - * are preparing to transmit, the device pulls the Tx command over the PCI - * bus via one of the device's Tx DMA channels, to fill an internal FIFO - * from which data will be transmitted. - * - * uCode handles all timing and protocol related to control frames - * (RTS/CTS/ACK), based on flags in the Tx command. uCode and Tx scheduler - * handle reception of block-acks; uCode updates the host driver via - * REPLY_COMPRESSED_BA (4965). - * - * 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 (4965). - * - * 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. - *****************************************************************************/ - -/* REPLY_TX Tx flags field */ - -/* 1: Use Request-To-Send protocol before this frame. - * Mutually exclusive vs. TX_CMD_FLG_CTS_MSK. */ -#define TX_CMD_FLG_RTS_MSK __constant_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. */ -#define TX_CMD_FLG_CTS_MSK __constant_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. */ -#define TX_CMD_FLG_ACK_MSK __constant_cpu_to_le32(1 << 3) - -/* For 4965: - * 1: Use rate scale table (see REPLY_TX_LINK_QUALITY_CMD). - * Tx command's initial_rate_index indicates first rate to try; - * uCode walks through table for additional Tx attempts. - * 0: Use Tx rate/MCS from Tx command's rate_n_flags field. - * This rate will be used for all Tx attempts; it will not be scaled. */ -#define TX_CMD_FLG_STA_RATE_MSK __constant_cpu_to_le32(1 << 4) - -/* 1: Expect immediate block-ack. - * Set when Txing a block-ack request frame. Also set TX_CMD_FLG_ACK_MSK. */ -#define TX_CMD_FLG_IMM_BA_RSP_MASK __constant_cpu_to_le32(1 << 6) - -/* 1: Frame requires full Tx-Op protection. - * Set this if either RTS or CTS Tx Flag gets set. */ -#define TX_CMD_FLG_FULL_TXOP_PROT_MSK __constant_cpu_to_le32(1 << 7) - -/* Tx antenna selection field; used only for 3945, reserved (0) for 4965. - * Set field to "0" to allow 3945 uCode to select antenna (normal usage). */ -#define TX_CMD_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0xf00) -#define TX_CMD_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8) -#define TX_CMD_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9) - -/* 1: Ignore Bluetooth priority for this frame. - * 0: Delay Tx until Bluetooth device is done (normal usage). */ -#define TX_CMD_FLG_BT_DIS_MSK __constant_cpu_to_le32(1 << 12) - -/* 1: uCode overrides sequence control field in MAC header. - * 0: Driver provides sequence control field in MAC header. - * Set this for management frames, non-QOS data frames, non-unicast frames, - * and also in Tx command embedded in REPLY_SCAN_CMD for active scans. */ -#define TX_CMD_FLG_SEQ_CTL_MSK __constant_cpu_to_le32(1 << 13) - -/* 1: This frame is non-last MPDU; more fragments are coming. - * 0: Last fragment, or not using fragmentation. */ -#define TX_CMD_FLG_MORE_FRAG_MSK __constant_cpu_to_le32(1 << 14) - -/* 1: uCode calculates and inserts Timestamp Function (TSF) in outgoing frame. - * 0: No TSF required in outgoing frame. - * Set this for transmitting beacons and probe responses. */ -#define TX_CMD_FLG_TSF_MSK __constant_cpu_to_le32(1 << 16) - -/* 1: Driver inserted 2 bytes pad after the MAC header, for (required) dword - * alignment of frame's payload data field. - * 0: No pad - * Set this for MAC headers with 26 or 30 bytes, i.e. those with QOS or ADDR4 - * field (but not both). Driver must align frame data (i.e. data following - * MAC header) to DWORD boundary. */ -#define TX_CMD_FLG_MH_PAD_MSK __constant_cpu_to_le32(1 << 20) - -/* accelerate aggregation support - * 0 - no CCMP encryption; 1 - CCMP encryption */ -#define TX_CMD_FLG_AGG_CCMP_MSK __constant_cpu_to_le32(1 << 22) - -/* HCCA-AP - disable duration overwriting. */ -#define TX_CMD_FLG_DUR_MSK __constant_cpu_to_le32(1 << 25) - - -/* - * TX command security control - */ -#define TX_CMD_SEC_WEP 0x01 -#define TX_CMD_SEC_CCM 0x02 -#define TX_CMD_SEC_TKIP 0x03 -#define TX_CMD_SEC_MSK 0x03 -#define TX_CMD_SEC_SHIFT 6 -#define TX_CMD_SEC_KEY128 0x08 - -/* - * security overhead sizes - */ -#define WEP_IV_LEN 4 -#define WEP_ICV_LEN 4 -#define CCMP_MIC_LEN 8 -#define TKIP_ICV_LEN 4 - -/* - * 4965 uCode updates these Tx attempt count values in host DRAM. - * Used for managing Tx retries when expecting block-acks. - * Driver should set these fields to 0. - */ -struct iwl4965_dram_scratch { - u8 try_cnt; /* Tx attempts */ - u8 bt_kill_cnt; /* Tx attempts blocked by Bluetooth device */ - __le16 reserved; -} __attribute__ ((packed)); - -/* - * REPLY_TX = 0x1c (command) - */ -struct iwl4965_tx_cmd { - /* - * MPDU byte count: - * MAC header (24/26/30/32 bytes) + 2 bytes pad if 26/30 header size, - * + 8 byte IV for CCM or TKIP (not used for WEP) - * + Data payload - * + 8-byte MIC (not used for CCM/WEP) - * NOTE: Does not include Tx command bytes, post-MAC pad bytes, - * MIC (CCM) 8 bytes, ICV (WEP/TKIP/CKIP) 4 bytes, CRC 4 bytes.i - * Range: 14-2342 bytes. - */ - __le16 len; - - /* - * MPDU or MSDU byte count for next frame. - * Used for fragmentation and bursting, but not 11n aggregation. - * Same as "len", but for next frame. Set to 0 if not applicable. - */ - __le16 next_frame_len; - - __le32 tx_flags; /* TX_CMD_FLG_* */ - - /* 4965's uCode may modify this field of the Tx command (in host DRAM!). - * Driver must also set dram_lsb_ptr and dram_msb_ptr in this cmd. */ - struct iwl4965_dram_scratch scratch; - - /* Rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is cleared. */ - __le32 rate_n_flags; /* RATE_MCS_* */ - - /* Index of destination station in uCode's station table */ - u8 sta_id; - - /* Type of security encryption: CCM or TKIP */ - u8 sec_ctl; /* TX_CMD_SEC_* */ - - /* - * Index into rate table (see REPLY_TX_LINK_QUALITY_CMD) for initial - * Tx attempt, if TX_CMD_FLG_STA_RATE_MSK is set. Normally "0" for - * data frames, this field may be used to selectively reduce initial - * rate (via non-0 value) for special frames (e.g. management), while - * still supporting rate scaling for all frames. - */ - u8 initial_rate_index; - u8 reserved; - u8 key[16]; - __le16 next_frame_flags; - __le16 reserved2; - union { - __le32 life_time; - __le32 attempt; - } stop_time; - - /* Host DRAM physical address pointer to "scratch" in this command. - * Must be dword aligned. "0" in dram_lsb_ptr disables usage. */ - __le32 dram_lsb_ptr; - u8 dram_msb_ptr; - - u8 rts_retry_limit; /*byte 50 */ - u8 data_retry_limit; /*byte 51 */ - u8 tid_tspec; - union { - __le16 pm_frame_timeout; - __le16 attempt_duration; - } timeout; - - /* - * Duration of EDCA burst Tx Opportunity, in 32-usec units. - * Set this if txop time is not specified by HCCA protocol (e.g. by AP). - */ - __le16 driver_txop; - - /* - * MAC header goes here, followed by 2 bytes padding if MAC header - * length is 26 or 30 bytes, followed by payload data - */ - u8 payload[0]; - struct ieee80211_hdr hdr[0]; -} __attribute__ ((packed)); - -/* TX command response is sent after *all* transmission attempts. - * - * NOTES: - * - * TX_STATUS_FAIL_NEXT_FRAG - * - * If the fragment flag in the MAC header for the frame being transmitted - * is set and there is insufficient time to transmit the next frame, the - * TX status will be returned with 'TX_STATUS_FAIL_NEXT_FRAG'. - * - * TX_STATUS_FIFO_UNDERRUN - * - * Indicates the host did not provide bytes to the FIFO fast enough while - * a TX was in progress. - * - * TX_STATUS_FAIL_MGMNT_ABORT - * - * This status is only possible if the ABORT ON MGMT RX parameter was - * set to true with the TX command. - * - * If the MSB of the status parameter is set then an abort sequence is - * required. This sequence consists of the host activating the TX Abort - * control line, and then waiting for the TX Abort command response. This - * indicates that a the device is no longer in a transmit state, and that the - * command FIFO has been cleared. The host must then deactivate the TX Abort - * control line. Receiving is still allowed in this case. - */ -enum { - TX_STATUS_SUCCESS = 0x01, - TX_STATUS_DIRECT_DONE = 0x02, - TX_STATUS_FAIL_SHORT_LIMIT = 0x82, - TX_STATUS_FAIL_LONG_LIMIT = 0x83, - TX_STATUS_FAIL_FIFO_UNDERRUN = 0x84, - TX_STATUS_FAIL_MGMNT_ABORT = 0x85, - TX_STATUS_FAIL_NEXT_FRAG = 0x86, - TX_STATUS_FAIL_LIFE_EXPIRE = 0x87, - TX_STATUS_FAIL_DEST_PS = 0x88, - TX_STATUS_FAIL_ABORTED = 0x89, - TX_STATUS_FAIL_BT_RETRY = 0x8a, - TX_STATUS_FAIL_STA_INVALID = 0x8b, - TX_STATUS_FAIL_FRAG_DROPPED = 0x8c, - TX_STATUS_FAIL_TID_DISABLE = 0x8d, - TX_STATUS_FAIL_FRAME_FLUSHED = 0x8e, - TX_STATUS_FAIL_INSUFFICIENT_CF_POLL = 0x8f, - TX_STATUS_FAIL_TX_LOCKED = 0x90, - TX_STATUS_FAIL_NO_BEACON_ON_RADAR = 0x91, -}; - -#define TX_PACKET_MODE_REGULAR 0x0000 -#define TX_PACKET_MODE_BURST_SEQ 0x0100 -#define TX_PACKET_MODE_BURST_FIRST 0x0200 - -enum { - TX_POWER_PA_NOT_ACTIVE = 0x0, -}; - -enum { - TX_STATUS_MSK = 0x000000ff, /* bits 0:7 */ - TX_STATUS_DELAY_MSK = 0x00000040, - TX_STATUS_ABORT_MSK = 0x00000080, - TX_PACKET_MODE_MSK = 0x0000ff00, /* bits 8:15 */ - TX_FIFO_NUMBER_MSK = 0x00070000, /* bits 16:18 */ - TX_RESERVED = 0x00780000, /* bits 19:22 */ - TX_POWER_PA_DETECT_MSK = 0x7f800000, /* bits 23:30 */ - TX_ABORT_REQUIRED_MSK = 0x80000000, /* bits 31:31 */ -}; - -/* ******************************* - * TX aggregation status - ******************************* */ - -enum { - AGG_TX_STATE_TRANSMITTED = 0x00, - AGG_TX_STATE_UNDERRUN_MSK = 0x01, - AGG_TX_STATE_BT_PRIO_MSK = 0x02, - AGG_TX_STATE_FEW_BYTES_MSK = 0x04, - AGG_TX_STATE_ABORT_MSK = 0x08, - AGG_TX_STATE_LAST_SENT_TTL_MSK = 0x10, - AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK = 0x20, - AGG_TX_STATE_LAST_SENT_BT_KILL_MSK = 0x40, - AGG_TX_STATE_SCD_QUERY_MSK = 0x80, - AGG_TX_STATE_TEST_BAD_CRC32_MSK = 0x100, - AGG_TX_STATE_RESPONSE_MSK = 0x1ff, - AGG_TX_STATE_DUMP_TX_MSK = 0x200, - AGG_TX_STATE_DELAY_TX_MSK = 0x400 -}; - -#define AGG_TX_STATE_LAST_SENT_MSK \ -(AGG_TX_STATE_LAST_SENT_TTL_MSK | \ - AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK | \ - AGG_TX_STATE_LAST_SENT_BT_KILL_MSK) - -/* # tx attempts for first frame in aggregation */ -#define AGG_TX_STATE_TRY_CNT_POS 12 -#define AGG_TX_STATE_TRY_CNT_MSK 0xf000 - -/* Command ID and sequence number of Tx command for this frame */ -#define AGG_TX_STATE_SEQ_NUM_POS 16 -#define AGG_TX_STATE_SEQ_NUM_MSK 0xffff0000 - -/* - * REPLY_TX = 0x1c (response) - * - * This response may be in one of two slightly different formats, indicated - * by the frame_count field: - * - * 1) No aggregation (frame_count == 1). This reports Tx results for - * a single frame. Multiple attempts, at various bit rates, may have - * been made for this frame. - * - * 2) Aggregation (frame_count > 1). This reports Tx results for - * 2 or more frames that used block-acknowledge. All frames were - * transmitted at same rate. Rate scaling may have been used if first - * frame in this new agg block failed in previous agg block(s). - * - * Note that, for aggregation, ACK (block-ack) status is not delivered here; - * block-ack has not been received by the time the 4965 records this status. - * This status relates to reasons the tx might have been blocked or aborted - * within the sending station (this 4965), rather than whether it was - * received successfully by the destination station. - */ -struct iwl4965_tx_resp { - u8 frame_count; /* 1 no aggregation, >1 aggregation */ - u8 bt_kill_count; /* # blocked by bluetooth (unused for agg) */ - u8 failure_rts; /* # failures due to unsuccessful RTS */ - u8 failure_frame; /* # failures due to no ACK (unused for agg) */ - - /* For non-agg: Rate at which frame was successful. - * For agg: Rate at which all frames were transmitted. */ - __le32 rate_n_flags; /* RATE_MCS_* */ - - /* For non-agg: RTS + CTS + frame tx attempts time + ACK. - * For agg: RTS + CTS + aggregation tx time + block-ack time. */ - __le16 wireless_media_time; /* uSecs */ - - __le16 reserved; - __le32 pa_power1; /* RF power amplifier measurement (not used) */ - __le32 pa_power2; - - /* - * For non-agg: frame status TX_STATUS_* - * For agg: status of 1st frame, AGG_TX_STATE_*; other frame status - * fields follow this one, up to frame_count. - * Bit fields: - * 11- 0: AGG_TX_STATE_* status code - * 15-12: Retry count for 1st frame in aggregation (retries - * occur if tx failed for this frame when it was a - * member of a previous aggregation block). If rate - * scaling is used, retry count indicates the rate - * table entry used for all frames in the new agg. - * 31-16: Sequence # for this frame's Tx cmd (not SSN!) - */ - __le32 status; /* TX status (for aggregation status of 1st frame) */ -} __attribute__ ((packed)); - -struct agg_tx_status { - __le16 status; - __le16 sequence; -} __attribute__ ((packed)); - -struct iwl4965_tx_resp_agg { - u8 frame_count; /* 1 no aggregation, >1 aggregation */ - u8 reserved1; - u8 failure_rts; - u8 failure_frame; - __le32 rate_n_flags; - __le16 wireless_media_time; - __le16 reserved3; - __le32 pa_power1; - __le32 pa_power2; - struct agg_tx_status status; /* TX status (for aggregation status */ - /* of 1st frame) */ -} __attribute__ ((packed)); - -/* - * REPLY_COMPRESSED_BA = 0xc5 (response only, not a command) - * - * Reports Block-Acknowledge from recipient station - */ -struct iwl4965_compressed_ba_resp { - __le32 sta_addr_lo32; - __le16 sta_addr_hi16; - __le16 reserved; - - /* Index of recipient (BA-sending) station in uCode's station table */ - u8 sta_id; - u8 tid; - __le16 seq_ctl; - __le64 bitmap; - __le16 scd_flow; - __le16 scd_ssn; -} __attribute__ ((packed)); - -/* - * REPLY_TX_PWR_TABLE_CMD = 0x97 (command, has simple generic response) - * - * See details under "TXPOWER" in iwl-4965-hw.h. - */ -struct iwl4965_txpowertable_cmd { - u8 band; /* 0: 5 GHz, 1: 2.4 GHz */ - u8 reserved; - __le16 channel; - struct iwl4965_tx_power_db tx_power; -} __attribute__ ((packed)); - -/*RS_NEW_API: only TLC_RTS remains and moved to bit 0 */ -#define LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK (1 << 0) - -/* # of EDCA prioritized tx fifos */ -#define LINK_QUAL_AC_NUM AC_NUM - -/* # entries in rate scale table to support Tx retries */ -#define LINK_QUAL_MAX_RETRY_NUM 16 - -/* Tx antenna selection values */ -#define LINK_QUAL_ANT_A_MSK (1 << 0) -#define LINK_QUAL_ANT_B_MSK (1 << 1) -#define LINK_QUAL_ANT_MSK (LINK_QUAL_ANT_A_MSK|LINK_QUAL_ANT_B_MSK) - - -/** - * struct iwl_link_qual_general_params - * - * Used in REPLY_TX_LINK_QUALITY_CMD - */ -struct iwl_link_qual_general_params { - u8 flags; - - /* No entries at or above this (driver chosen) index contain MIMO */ - u8 mimo_delimiter; - - /* Best single antenna to use for single stream (legacy, SISO). */ - u8 single_stream_ant_msk; /* LINK_QUAL_ANT_* */ - - /* Best antennas to use for MIMO (unused for 4965, assumes both). */ - u8 dual_stream_ant_msk; /* LINK_QUAL_ANT_* */ - - /* - * If driver needs to use different initial rates for different - * EDCA QOS access categories (as implemented by tx fifos 0-3), - * this table will set that up, by indicating the indexes in the - * rs_table[LINK_QUAL_MAX_RETRY_NUM] rate table at which to start. - * Otherwise, driver should set all entries to 0. - * - * Entry usage: - * 0 = Background, 1 = Best Effort (normal), 2 = Video, 3 = Voice - * TX FIFOs above 3 use same value (typically 0) as TX FIFO 3. - */ - u8 start_rate_index[LINK_QUAL_AC_NUM]; -} __attribute__ ((packed)); - -/** - * struct iwl_link_qual_agg_params - * - * Used in REPLY_TX_LINK_QUALITY_CMD - */ -struct iwl_link_qual_agg_params { - - /* Maximum number of uSec in aggregation. - * Driver should set this to 4000 (4 milliseconds). */ - __le16 agg_time_limit; - - /* - * Number of Tx retries allowed for a frame, before that frame will - * no longer be considered for the start of an aggregation sequence - * (scheduler will then try to tx it as single frame). - * Driver should set this to 3. - */ - u8 agg_dis_start_th; - - /* - * Maximum number of frames in aggregation. - * 0 = no limit (default). 1 = no aggregation. - * Other values = max # frames in aggregation. - */ - u8 agg_frame_cnt_limit; - - __le32 reserved; -} __attribute__ ((packed)); - -/* - * REPLY_TX_LINK_QUALITY_CMD = 0x4e (command, has simple generic response) - * - * For 4965 only; 3945 uses REPLY_RATE_SCALE. - * - * Each station in the 4965's internal station table has its own table of 16 - * Tx rates and modulation modes (e.g. legacy/SISO/MIMO) for retrying Tx when - * an ACK is not received. This command replaces the entire table for - * one station. - * - * NOTE: Station must already be in 4965's station table. Use REPLY_ADD_STA. - * - * The rate scaling procedures described below work well. Of course, other - * procedures are possible, and may work better for particular environments. - * - * - * FILLING THE RATE TABLE - * - * Given a particular initial rate and mode, as determined by the rate - * scaling algorithm described below, the Linux driver uses the following - * formula to fill the rs_table[LINK_QUAL_MAX_RETRY_NUM] rate table in the - * Link Quality command: - * - * - * 1) If using High-throughput (HT) (SISO or MIMO) initial rate: - * a) Use this same initial rate for first 3 entries. - * b) Find next lower available rate using same mode (SISO or MIMO), - * use for next 3 entries. If no lower rate available, switch to - * legacy mode (no FAT channel, no MIMO, no short guard interval). - * c) If using MIMO, set command's mimo_delimiter to number of entries - * using MIMO (3 or 6). - * d) After trying 2 HT rates, switch to legacy mode (no FAT channel, - * no MIMO, no short guard interval), at the next lower bit rate - * (e.g. if second HT bit rate was 54, try 48 legacy), and follow - * legacy procedure for remaining table entries. - * - * 2) If using legacy initial rate: - * a) Use the initial rate for only one entry. - * b) For each following entry, reduce the rate to next lower available - * rate, until reaching the lowest available rate. - * c) When reducing rate, also switch antenna selection. - * d) Once lowest available rate is reached, repeat this rate until - * rate table is filled (16 entries), switching antenna each entry. - * - * - * ACCUMULATING HISTORY - * - * The rate scaling algorithm for 4965, as implemented in Linux driver, uses - * two sets of frame Tx success history: One for the current/active modulation - * mode, and one for a speculative/search mode that is being attempted. If the - * speculative mode turns out to be more effective (i.e. actual transfer - * rate is better), then the driver continues to use the speculative mode - * as the new current active mode. - * - * Each history set contains, separately for each possible rate, data for a - * sliding window of the 62 most recent tx attempts at that rate. The data - * includes a shifting bitmap of success(1)/failure(0), and sums of successful - * and attempted frames, from which the driver can additionally calculate a - * success ratio (success / attempted) and number of failures - * (attempted - success), and control the size of the window (attempted). - * The driver uses the bit map to remove successes from the success sum, as - * the oldest tx attempts fall out of the window. - * - * When the 4965 makes multiple tx attempts for a given frame, each attempt - * might be at a different rate, and have different modulation characteristics - * (e.g. antenna, fat channel, short guard interval), as set up in the rate - * scaling table in the Link Quality command. The driver must determine - * which rate table entry was used for each tx attempt, to determine which - * rate-specific history to update, and record only those attempts that - * match the modulation characteristics of the history set. - * - * When using block-ack (aggregation), all frames are transmitted at the same - * rate, since there is no per-attempt acknowledgement from the destination - * station. The Tx response struct iwl_tx_resp indicates the Tx rate in - * rate_n_flags field. After receiving a block-ack, the driver can update - * history for the entire block all at once. - * - * - * FINDING BEST STARTING RATE: - * - * When working with a selected initial modulation mode (see below), the - * driver attempts to find a best initial rate. The initial rate is the - * first entry in the Link Quality command's rate table. - * - * 1) Calculate actual throughput (success ratio * expected throughput, see - * table below) for current initial rate. Do this only if enough frames - * have been attempted to make the value meaningful: at least 6 failed - * tx attempts, or at least 8 successes. If not enough, don't try rate - * scaling yet. - * - * 2) Find available rates adjacent to current initial rate. Available means: - * a) supported by hardware && - * b) supported by association && - * c) within any constraints selected by user - * - * 3) Gather measured throughputs for adjacent rates. These might not have - * enough history to calculate a throughput. That's okay, we might try - * using one of them anyway! - * - * 4) Try decreasing rate if, for current rate: - * a) success ratio is < 15% || - * b) lower adjacent rate has better measured throughput || - * c) higher adjacent rate has worse throughput, and lower is unmeasured - * - * As a sanity check, if decrease was determined above, leave rate - * unchanged if: - * a) lower rate unavailable - * b) success ratio at current rate > 85% (very good) - * c) current measured throughput is better than expected throughput - * of lower rate (under perfect 100% tx conditions, see table below) - * - * 5) Try increasing rate if, for current rate: - * a) success ratio is < 15% || - * b) both adjacent rates' throughputs are unmeasured (try it!) || - * b) higher adjacent rate has better measured throughput || - * c) lower adjacent rate has worse throughput, and higher is unmeasured - * - * As a sanity check, if increase was determined above, leave rate - * unchanged if: - * a) success ratio at current rate < 70%. This is not particularly - * good performance; higher rate is sure to have poorer success. - * - * 6) Re-evaluate the rate after each tx frame. If working with block- - * acknowledge, history and statistics may be calculated for the entire - * block (including prior history that fits within the history windows), - * before re-evaluation. - * - * FINDING BEST STARTING MODULATION MODE: - * - * After working with a modulation mode for a "while" (and doing rate scaling), - * the driver searches for a new initial mode in an attempt to improve - * throughput. The "while" is measured by numbers of attempted frames: - * - * For legacy mode, search for new mode after: - * 480 successful frames, or 160 failed frames - * For high-throughput modes (SISO or MIMO), search for new mode after: - * 4500 successful frames, or 400 failed frames - * - * Mode switch possibilities are (3 for each mode): - * - * For legacy: - * Change antenna, try SISO (if HT association), try MIMO (if HT association) - * For SISO: - * Change antenna, try MIMO, try shortened guard interval (SGI) - * For MIMO: - * Try SISO antenna A, SISO antenna B, try shortened guard interval (SGI) - * - * When trying a new mode, use the same bit rate as the old/current mode when - * trying antenna switches and shortened guard interval. When switching to - * SISO from MIMO or legacy, or to MIMO from SISO or legacy, use a rate - * for which the expected throughput (under perfect conditions) is about the - * same or slightly better than the actual measured throughput delivered by - * the old/current mode. - * - * Actual throughput can be estimated by multiplying the expected throughput - * by the success ratio (successful / attempted tx frames). Frame size is - * not considered in this calculation; it assumes that frame size will average - * out to be fairly consistent over several samples. The following are - * metric values for expected throughput assuming 100% success ratio. - * Only G band has support for CCK rates: - * - * RATE: 1 2 5 11 6 9 12 18 24 36 48 54 60 - * - * G: 7 13 35 58 40 57 72 98 121 154 177 186 186 - * A: 0 0 0 0 40 57 72 98 121 154 177 186 186 - * SISO 20MHz: 0 0 0 0 42 42 76 102 124 159 183 193 202 - * SGI SISO 20MHz: 0 0 0 0 46 46 82 110 132 168 192 202 211 - * MIMO 20MHz: 0 0 0 0 74 74 123 155 179 214 236 244 251 - * SGI MIMO 20MHz: 0 0 0 0 81 81 131 164 188 222 243 251 257 - * SISO 40MHz: 0 0 0 0 77 77 127 160 184 220 242 250 257 - * SGI SISO 40MHz: 0 0 0 0 83 83 135 169 193 229 250 257 264 - * MIMO 40MHz: 0 0 0 0 123 123 182 214 235 264 279 285 289 - * SGI MIMO 40MHz: 0 0 0 0 131 131 191 222 242 270 284 289 293 - * - * After the new mode has been tried for a short while (minimum of 6 failed - * frames or 8 successful frames), compare success ratio and actual throughput - * estimate of the new mode with the old. If either is better with the new - * mode, continue to use the new mode. - * - * Continue comparing modes until all 3 possibilities have been tried. - * If moving from legacy to HT, try all 3 possibilities from the new HT - * mode. After trying all 3, a best mode is found. Continue to use this mode - * for the longer "while" described above (e.g. 480 successful frames for - * legacy), and then repeat the search process. - * - */ -struct iwl_link_quality_cmd { - - /* Index of destination/recipient station in uCode's station table */ - u8 sta_id; - u8 reserved1; - __le16 control; /* not used */ - struct iwl_link_qual_general_params general_params; - struct iwl_link_qual_agg_params agg_params; - - /* - * Rate info; when using rate-scaling, Tx command's initial_rate_index - * specifies 1st Tx rate attempted, via index into this table. - * 4965 works its way through table when retrying Tx. - */ - struct { - __le32 rate_n_flags; /* RATE_MCS_*, IWL_RATE_* */ - } rs_table[LINK_QUAL_MAX_RETRY_NUM]; - __le32 reserved2; -} __attribute__ ((packed)); - -/* - * REPLY_BT_CONFIG = 0x9b (command, has simple generic response) - * - * 3945 and 4965 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 accomodate. - */ -struct iwl4965_bt_cmd { - u8 flags; - u8 lead_time; - u8 max_kill; - u8 reserved; - __le32 kill_ack_mask; - __le32 kill_cts_mask; -} __attribute__ ((packed)); - -/****************************************************************************** - * (6) - * Spectrum Management (802.11h) Commands, Responses, Notifications: - * - *****************************************************************************/ - -/* - * Spectrum Management - */ -#define MEASUREMENT_FILTER_FLAG (RXON_FILTER_PROMISC_MSK | \ - RXON_FILTER_CTL2HOST_MSK | \ - RXON_FILTER_ACCEPT_GRP_MSK | \ - RXON_FILTER_DIS_DECRYPT_MSK | \ - RXON_FILTER_DIS_GRP_DECRYPT_MSK | \ - RXON_FILTER_ASSOC_MSK | \ - RXON_FILTER_BCON_AWARE_MSK) - -struct iwl4965_measure_channel { - __le32 duration; /* measurement duration in extended beacon - * format */ - u8 channel; /* channel to measure */ - u8 type; /* see enum iwl4965_measure_type */ - __le16 reserved; -} __attribute__ ((packed)); - -/* - * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (command) - */ -struct iwl4965_spectrum_cmd { - __le16 len; /* number of bytes starting from token */ - u8 token; /* token id */ - u8 id; /* measurement id -- 0 or 1 */ - u8 origin; /* 0 = TGh, 1 = other, 2 = TGk */ - u8 periodic; /* 1 = periodic */ - __le16 path_loss_timeout; - __le32 start_time; /* start time in extended beacon format */ - __le32 reserved2; - __le32 flags; /* rxon flags */ - __le32 filter_flags; /* rxon filter flags */ - __le16 channel_count; /* minimum 1, maximum 10 */ - __le16 reserved3; - struct iwl4965_measure_channel channels[10]; -} __attribute__ ((packed)); - -/* - * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (response) - */ -struct iwl4965_spectrum_resp { - u8 token; - u8 id; /* id of the prior command replaced, or 0xff */ - __le16 status; /* 0 - command will be handled - * 1 - cannot handle (conflicts with another - * measurement) */ -} __attribute__ ((packed)); - -enum iwl4965_measurement_state { - IWL_MEASUREMENT_START = 0, - IWL_MEASUREMENT_STOP = 1, -}; - -enum iwl4965_measurement_status { - IWL_MEASUREMENT_OK = 0, - IWL_MEASUREMENT_CONCURRENT = 1, - IWL_MEASUREMENT_CSA_CONFLICT = 2, - IWL_MEASUREMENT_TGH_CONFLICT = 3, - /* 4-5 reserved */ - IWL_MEASUREMENT_STOPPED = 6, - IWL_MEASUREMENT_TIMEOUT = 7, - IWL_MEASUREMENT_PERIODIC_FAILED = 8, -}; - -#define NUM_ELEMENTS_IN_HISTOGRAM 8 - -struct iwl4965_measurement_histogram { - __le32 ofdm[NUM_ELEMENTS_IN_HISTOGRAM]; /* in 0.8usec counts */ - __le32 cck[NUM_ELEMENTS_IN_HISTOGRAM]; /* in 1usec counts */ -} __attribute__ ((packed)); - -/* clear channel availability counters */ -struct iwl4965_measurement_cca_counters { - __le32 ofdm; - __le32 cck; -} __attribute__ ((packed)); - -enum iwl4965_measure_type { - IWL_MEASURE_BASIC = (1 << 0), - IWL_MEASURE_CHANNEL_LOAD = (1 << 1), - IWL_MEASURE_HISTOGRAM_RPI = (1 << 2), - IWL_MEASURE_HISTOGRAM_NOISE = (1 << 3), - IWL_MEASURE_FRAME = (1 << 4), - /* bits 5:6 are reserved */ - IWL_MEASURE_IDLE = (1 << 7), -}; - -/* - * SPECTRUM_MEASURE_NOTIFICATION = 0x75 (notification only, not a command) - */ -struct iwl4965_spectrum_notification { - u8 id; /* measurement id -- 0 or 1 */ - u8 token; - u8 channel_index; /* index in measurement channel list */ - u8 state; /* 0 - start, 1 - stop */ - __le32 start_time; /* lower 32-bits of TSF */ - u8 band; /* 0 - 5.2GHz, 1 - 2.4GHz */ - u8 channel; - u8 type; /* see enum iwl4965_measurement_type */ - u8 reserved1; - /* NOTE: cca_ofdm, cca_cck, basic_type, and histogram are only only - * valid if applicable for measurement type requested. */ - __le32 cca_ofdm; /* cca fraction time in 40Mhz clock periods */ - __le32 cca_cck; /* cca fraction time in 44Mhz clock periods */ - __le32 cca_time; /* channel load time in usecs */ - u8 basic_type; /* 0 - bss, 1 - ofdm preamble, 2 - - * unidentified */ - u8 reserved2[3]; - struct iwl4965_measurement_histogram histogram; - __le32 stop_time; /* lower 32-bits of TSF */ - __le32 status; /* see iwl4965_measurement_status */ -} __attribute__ ((packed)); - -/****************************************************************************** - * (7) - * Power Management Commands, Responses, Notifications: - * - *****************************************************************************/ - -/** - * struct iwl4965_powertable_cmd - Power Table Command - * @flags: See below: - * - * POWER_TABLE_CMD = 0x77 (command, has simple generic response) - * - * PM allow: - * bit 0 - '0' Driver not allow power management - * '1' Driver allow PM (use rest of parameters) - * uCode send sleep notifications: - * bit 1 - '0' Don't send sleep notification - * '1' send sleep notification (SEND_PM_NOTIFICATION) - * Sleep over DTIM - * bit 2 - '0' PM have to walk up every DTIM - * '1' PM could sleep over DTIM till listen Interval. - * PCI power managed - * bit 3 - '0' (PCI_LINK_CTRL & 0x1) - * '1' !(PCI_LINK_CTRL & 0x1) - * Force sleep Modes - * bit 31/30- '00' use both mac/xtal sleeps - * '01' force Mac sleep - * '10' force xtal sleep - * '11' Illegal set - * - * NOTE: if sleep_interval[SLEEP_INTRVL_TABLE_SIZE-1] > DTIM period then - * ucode assume sleep over DTIM is allowed and we don't need to wakeup - * for every DTIM. - */ -#define IWL_POWER_VEC_SIZE 5 - -#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK __constant_cpu_to_le16(1 << 0) -#define IWL_POWER_SLEEP_OVER_DTIM_MSK __constant_cpu_to_le16(1 << 2) -#define IWL_POWER_PCI_PM_MSK __constant_cpu_to_le16(1 << 3) -#define IWL_POWER_FAST_PD __constant_cpu_to_le16(1 << 4) - -struct iwl4965_powertable_cmd { - __le16 flags; - u8 keep_alive_seconds; - u8 debug_flags; - __le32 rx_data_timeout; - __le32 tx_data_timeout; - __le32 sleep_interval[IWL_POWER_VEC_SIZE]; - __le32 keep_alive_beacons; -} __attribute__ ((packed)); - -/* - * PM_SLEEP_NOTIFICATION = 0x7A (notification only, not a command) - * 3945 and 4965 identical. - */ -struct iwl4965_sleep_notification { - u8 pm_sleep_mode; - u8 pm_wakeup_src; - __le16 reserved; - __le32 sleep_time; - __le32 tsf_low; - __le32 bcon_timer; -} __attribute__ ((packed)); - -/* Sleep states. 3945 and 4965 identical. */ -enum { - IWL_PM_NO_SLEEP = 0, - IWL_PM_SLP_MAC = 1, - IWL_PM_SLP_FULL_MAC_UNASSOCIATE = 2, - IWL_PM_SLP_FULL_MAC_CARD_STATE = 3, - IWL_PM_SLP_PHY = 4, - IWL_PM_SLP_REPENT = 5, - IWL_PM_WAKEUP_BY_TIMER = 6, - IWL_PM_WAKEUP_BY_DRIVER = 7, - IWL_PM_WAKEUP_BY_RFKILL = 8, - /* 3 reserved */ - IWL_PM_NUM_OF_MODES = 12, -}; - -/* - * REPLY_CARD_STATE_CMD = 0xa0 (command, has simple generic response) - */ -#define CARD_STATE_CMD_DISABLE 0x00 /* Put card to sleep */ -#define CARD_STATE_CMD_ENABLE 0x01 /* Wake up card */ -#define CARD_STATE_CMD_HALT 0x02 /* Power down permanently */ -struct iwl4965_card_state_cmd { - __le32 status; /* CARD_STATE_CMD_* request new power state */ -} __attribute__ ((packed)); - -/* - * CARD_STATE_NOTIFICATION = 0xa1 (notification only, not a command) - */ -struct iwl4965_card_state_notif { - __le32 flags; -} __attribute__ ((packed)); - -#define HW_CARD_DISABLED 0x01 -#define SW_CARD_DISABLED 0x02 -#define RF_CARD_DISABLED 0x04 -#define RXON_CARD_DISABLED 0x10 - -struct iwl4965_ct_kill_config { - __le32 reserved; - __le32 critical_temperature_M; - __le32 critical_temperature_R; -} __attribute__ ((packed)); - -/****************************************************************************** - * (8) - * Scan Commands, Responses, Notifications: - * - *****************************************************************************/ - -/** - * struct iwl4965_scan_channel - entry in REPLY_SCAN_CMD channel table - * - * One for each channel in the scan list. - * Each channel can independently select: - * 1) SSID for directed active scans - * 2) Txpower setting (for rate specified within Tx command) - * 3) How long to stay on-channel (behavior may be modified by quiet_time, - * quiet_plcp_th, good_CRC_th) - * - * To avoid uCode errors, make sure the following are true (see comments - * under struct iwl4965_scan_cmd about max_out_time and quiet_time): - * 1) If using passive_dwell (i.e. passive_dwell != 0): - * active_dwell <= passive_dwell (< max_out_time if max_out_time != 0) - * 2) quiet_time <= active_dwell - * 3) If restricting off-channel time (i.e. max_out_time !=0): - * passive_dwell < max_out_time - * active_dwell < max_out_time - */ -struct iwl4965_scan_channel { - /* - * type is defined as: - * 0:0 1 = active, 0 = passive - * 1:4 SSID direct bit map; if a bit is set, then corresponding - * SSID IE is transmitted in probe request. - * 5:7 reserved - */ - u8 type; - u8 channel; /* band is selected by iwl4965_scan_cmd "flags" field */ - struct iwl4965_tx_power tpc; - __le16 active_dwell; /* in 1024-uSec TU (time units), typ 5-50 */ - __le16 passive_dwell; /* in 1024-uSec TU (time units), typ 20-500 */ -} __attribute__ ((packed)); - -/** - * struct iwl4965_ssid_ie - directed scan network information element - * - * Up to 4 of these may appear in REPLY_SCAN_CMD, selected by "type" field - * in struct iwl4965_scan_channel; each channel may select different ssids from - * among the 4 entries. SSID IEs get transmitted in reverse order of entry. - */ -struct iwl4965_ssid_ie { - u8 id; - u8 len; - u8 ssid[32]; -} __attribute__ ((packed)); - -#define PROBE_OPTION_MAX 0x4 -#define TX_CMD_LIFE_TIME_INFINITE __constant_cpu_to_le32(0xFFFFFFFF) -#define IWL_GOOD_CRC_TH __constant_cpu_to_le16(1) -#define IWL_MAX_SCAN_SIZE 1024 - -/* - * REPLY_SCAN_CMD = 0x80 (command) - * - * The hardware scan command is very powerful; the driver can set it up to - * maintain (relatively) normal network traffic while doing a scan in the - * background. The max_out_time and suspend_time control the ratio of how - * long the device stays on an associated network channel ("service channel") - * vs. how long it's away from the service channel, i.e. tuned to other channels - * for scanning. - * - * max_out_time is the max time off-channel (in usec), and suspend_time - * is how long (in "extended beacon" format) that the scan is "suspended" - * after returning to the service channel. That is, suspend_time is the - * time that we stay on the service channel, doing normal work, between - * scan segments. The driver may set these parameters differently to support - * scanning when associated vs. not associated, and light vs. heavy traffic - * loads when associated. - * - * After receiving this command, the device's scan engine does the following; - * - * 1) Sends SCAN_START notification to driver - * 2) Checks to see if it has time to do scan for one channel - * 3) Sends NULL packet, with power-save (PS) bit set to 1, - * to tell AP that we're going off-channel - * 4) Tunes to first channel in scan list, does active or passive scan - * 5) Sends SCAN_RESULT notification to driver - * 6) Checks to see if it has time to do scan on *next* channel in list - * 7) Repeats 4-6 until it no longer has time to scan the next channel - * before max_out_time expires - * 8) Returns to service channel - * 9) Sends NULL packet with PS=0 to tell AP that we're back - * 10) Stays on service channel until suspend_time expires - * 11) Repeats entire process 2-10 until list is complete - * 12) Sends SCAN_COMPLETE notification - * - * For fast, efficient scans, the scan command also has support for staying on - * a channel for just a short time, if doing active scanning and getting no - * responses to the transmitted probe request. This time is controlled by - * quiet_time, and the number of received packets below which a channel is - * considered "quiet" is controlled by quiet_plcp_threshold. - * - * For active scanning on channels that have regulatory restrictions against - * blindly transmitting, the scan can listen before transmitting, to make sure - * that there is already legitimate activity on the channel. If enough - * packets are cleanly received on the channel (controlled by good_CRC_th, - * typical value 1), the scan engine starts transmitting probe requests. - * - * Driver must use separate scan commands for 2.4 vs. 5 GHz bands. - * - * To avoid uCode errors, see timing restrictions described under - * struct iwl4965_scan_channel. - */ -struct iwl4965_scan_cmd { - __le16 len; - u8 reserved0; - u8 channel_count; /* # channels in channel list */ - __le16 quiet_time; /* dwell only this # millisecs on quiet channel - * (only for active scan) */ - __le16 quiet_plcp_th; /* quiet chnl is < this # pkts (typ. 1) */ - __le16 good_CRC_th; /* passive -> active promotion threshold */ - __le16 rx_chain; /* RXON_RX_CHAIN_* */ - __le32 max_out_time; /* max usec to be away from associated (service) - * 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_* */ - - /* For active scans (set to all-0s for passive scans). - * Does not include payload. Must specify Tx rate; no rate scaling. */ - struct iwl4965_tx_cmd tx_cmd; - - /* For directed active scans (set to all-0s otherwise) */ - struct iwl4965_ssid_ie direct_scan[PROBE_OPTION_MAX]; - - /* - * Probe request frame, followed by channel list. - * - * Size of probe request frame is specified by byte count in tx_cmd. - * Channel list follows immediately after probe request frame. - * Number of channels in list is specified by channel_count. - * Each channel in list is of type: - * - * struct iwl4965_scan_channel channels[0]; - * - * NOTE: Only one band of channels can be scanned per pass. You - * must not mix 2.4GHz channels and 5.2GHz channels, and you must wait - * for one scan to complete (i.e. receive SCAN_COMPLETE_NOTIFICATION) - * before requesting another scan. - */ - u8 data[0]; -} __attribute__ ((packed)); - -/* Can abort will notify by complete notification with abort status. */ -#define CAN_ABORT_STATUS __constant_cpu_to_le32(0x1) -/* complete notification statuses */ -#define ABORT_STATUS 0x2 - -/* - * REPLY_SCAN_CMD = 0x80 (response) - */ -struct iwl4965_scanreq_notification { - __le32 status; /* 1: okay, 2: cannot fulfill request */ -} __attribute__ ((packed)); - -/* - * SCAN_START_NOTIFICATION = 0x82 (notification only, not a command) - */ -struct iwl4965_scanstart_notification { - __le32 tsf_low; - __le32 tsf_high; - __le32 beacon_timer; - u8 channel; - u8 band; - u8 reserved[2]; - __le32 status; -} __attribute__ ((packed)); - -#define SCAN_OWNER_STATUS 0x1; -#define MEASURE_OWNER_STATUS 0x2; - -#define NUMBER_OF_STATISTICS 1 /* first __le32 is good CRC */ -/* - * SCAN_RESULTS_NOTIFICATION = 0x83 (notification only, not a command) - */ -struct iwl4965_scanresults_notification { - u8 channel; - u8 band; - u8 reserved[2]; - __le32 tsf_low; - __le32 tsf_high; - __le32 statistics[NUMBER_OF_STATISTICS]; -} __attribute__ ((packed)); - -/* - * SCAN_COMPLETE_NOTIFICATION = 0x84 (notification only, not a command) - */ -struct iwl4965_scancomplete_notification { - u8 scanned_channels; - u8 status; - u8 reserved; - u8 last_channel; - __le32 tsf_low; - __le32 tsf_high; -} __attribute__ ((packed)); - - -/****************************************************************************** - * (9) - * IBSS/AP Commands and Notifications: - * - *****************************************************************************/ - -/* - * BEACON_NOTIFICATION = 0x90 (notification only, not a command) - */ -struct iwl4965_beacon_notif { - struct iwl4965_tx_resp beacon_notify_hdr; - __le32 low_tsf; - __le32 high_tsf; - __le32 ibss_mgr_status; -} __attribute__ ((packed)); - -/* - * REPLY_TX_BEACON = 0x91 (command, has simple generic response) - */ -struct iwl4965_tx_beacon_cmd { - struct iwl4965_tx_cmd tx; - __le16 tim_idx; - u8 tim_size; - u8 reserved1; - struct ieee80211_hdr frame[0]; /* beacon frame */ -} __attribute__ ((packed)); - -/****************************************************************************** - * (10) - * Statistics Commands and Notifications: - * - *****************************************************************************/ - -#define IWL_TEMP_CONVERT 260 - -#define SUP_RATE_11A_MAX_NUM_CHANNELS 8 -#define SUP_RATE_11B_MAX_NUM_CHANNELS 4 -#define SUP_RATE_11G_MAX_NUM_CHANNELS 12 - -/* Used for passing to driver number of successes and failures per rate */ -struct rate_histogram { - union { - __le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS]; - __le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS]; - __le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS]; - } success; - union { - __le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS]; - __le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS]; - __le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS]; - } failed; -} __attribute__ ((packed)); - -/* statistics command response */ - -struct statistics_rx_phy { - __le32 ina_cnt; - __le32 fina_cnt; - __le32 plcp_err; - __le32 crc32_err; - __le32 overrun_err; - __le32 early_overrun_err; - __le32 crc32_good; - __le32 false_alarm_cnt; - __le32 fina_sync_err_cnt; - __le32 sfd_timeout; - __le32 fina_timeout; - __le32 unresponded_rts; - __le32 rxe_frame_limit_overrun; - __le32 sent_ack_cnt; - __le32 sent_cts_cnt; - __le32 sent_ba_rsp_cnt; - __le32 dsp_self_kill; - __le32 mh_format_err; - __le32 re_acq_main_rssi_sum; - __le32 reserved3; -} __attribute__ ((packed)); - -struct statistics_rx_ht_phy { - __le32 plcp_err; - __le32 overrun_err; - __le32 early_overrun_err; - __le32 crc32_good; - __le32 crc32_err; - __le32 mh_format_err; - __le32 agg_crc32_good; - __le32 agg_mpdu_cnt; - __le32 agg_cnt; - __le32 reserved2; -} __attribute__ ((packed)); - -struct statistics_rx_non_phy { - __le32 bogus_cts; /* CTS received when not expecting CTS */ - __le32 bogus_ack; /* ACK received when not expecting ACK */ - __le32 non_bssid_frames; /* number of frames with BSSID that - * doesn't belong to the STA BSSID */ - __le32 filtered_frames; /* count frames that were dumped in the - * filtering process */ - __le32 non_channel_beacons; /* beacons with our bss id but not on - * our serving channel */ - __le32 channel_beacons; /* beacons with our bss id and in our - * serving channel */ - __le32 num_missed_bcon; /* number of missed beacons */ - __le32 adc_rx_saturation_time; /* count in 0.8us units the time the - * ADC was in saturation */ - __le32 ina_detection_search_time;/* total time (in 0.8us) searched - * for INA */ - __le32 beacon_silence_rssi_a; /* RSSI silence after beacon frame */ - __le32 beacon_silence_rssi_b; /* RSSI silence after beacon frame */ - __le32 beacon_silence_rssi_c; /* RSSI silence after beacon frame */ - __le32 interference_data_flag; /* flag for interference data - * availability. 1 when data is - * available. */ - __le32 channel_load; /* counts RX Enable time in uSec */ - __le32 dsp_false_alarms; /* DSP false alarm (both OFDM - * and CCK) counter */ - __le32 beacon_rssi_a; - __le32 beacon_rssi_b; - __le32 beacon_rssi_c; - __le32 beacon_energy_a; - __le32 beacon_energy_b; - __le32 beacon_energy_c; -} __attribute__ ((packed)); - -struct statistics_rx { - struct statistics_rx_phy ofdm; - struct statistics_rx_phy cck; - struct statistics_rx_non_phy general; - struct statistics_rx_ht_phy ofdm_ht; -} __attribute__ ((packed)); - -struct statistics_tx_non_phy_agg { - __le32 ba_timeout; - __le32 ba_reschedule_frames; - __le32 scd_query_agg_frame_cnt; - __le32 scd_query_no_agg; - __le32 scd_query_agg; - __le32 scd_query_mismatch; - __le32 frame_not_ready; - __le32 underrun; - __le32 bt_prio_kill; - __le32 rx_ba_rsp_cnt; - __le32 reserved2; - __le32 reserved3; -} __attribute__ ((packed)); - -struct statistics_tx { - __le32 preamble_cnt; - __le32 rx_detected_cnt; - __le32 bt_prio_defer_cnt; - __le32 bt_prio_kill_cnt; - __le32 few_bytes_cnt; - __le32 cts_timeout; - __le32 ack_timeout; - __le32 expected_ack_cnt; - __le32 actual_ack_cnt; - __le32 dump_msdu_cnt; - __le32 burst_abort_next_frame_mismatch_cnt; - __le32 burst_abort_missing_next_frame_cnt; - __le32 cts_timeout_collision; - __le32 ack_or_ba_timeout_collision; - struct statistics_tx_non_phy_agg agg; -} __attribute__ ((packed)); - -struct statistics_dbg { - __le32 burst_check; - __le32 burst_count; - __le32 reserved[4]; -} __attribute__ ((packed)); - -struct statistics_div { - __le32 tx_on_a; - __le32 tx_on_b; - __le32 exec_time; - __le32 probe_time; - __le32 reserved1; - __le32 reserved2; -} __attribute__ ((packed)); - -struct statistics_general { - __le32 temperature; - __le32 temperature_m; - struct statistics_dbg dbg; - __le32 sleep_time; - __le32 slots_out; - __le32 slots_idle; - __le32 ttl_timestamp; - struct statistics_div div; - __le32 rx_enable_counter; - __le32 reserved1; - __le32 reserved2; - __le32 reserved3; -} __attribute__ ((packed)); - -/* - * REPLY_STATISTICS_CMD = 0x9c, - * 3945 and 4965 identical. - * - * This command triggers an immediate response containing uCode statistics. - * The response is in the same format as STATISTICS_NOTIFICATION 0x9d, below. - * - * If the CLEAR_STATS configuration flag is set, uCode will clear its - * internal copy of the statistics (counters) after issuing the response. - * This flag does not affect STATISTICS_NOTIFICATIONs after beacons (see below). - * - * If the DISABLE_NOTIF configuration flag is set, uCode will not issue - * STATISTICS_NOTIFICATIONs after received beacons (see below). This flag - * does not affect the response to the REPLY_STATISTICS_CMD 0x9c itself. - */ -#define IWL_STATS_CONF_CLEAR_STATS __constant_cpu_to_le32(0x1) /* see above */ -#define IWL_STATS_CONF_DISABLE_NOTIF __constant_cpu_to_le32(0x2)/* see above */ -struct iwl4965_statistics_cmd { - __le32 configuration_flags; /* IWL_STATS_CONF_* */ -} __attribute__ ((packed)); - -/* - * STATISTICS_NOTIFICATION = 0x9d (notification only, not a command) - * - * By default, uCode issues this notification after receiving a beacon - * while associated. To disable this behavior, set DISABLE_NOTIF flag in the - * REPLY_STATISTICS_CMD 0x9c, above. - * - * Statistics counters continue to increment beacon after beacon, but are - * cleared when changing channels or when driver issues REPLY_STATISTICS_CMD - * 0x9c with CLEAR_STATS bit set (see above). - * - * uCode also issues this notification during scans. uCode clears statistics - * appropriately so that each notification contains statistics for only the - * one channel that has just been scanned. - */ -#define STATISTICS_REPLY_FLG_BAND_24G_MSK __constant_cpu_to_le32(0x2) -#define STATISTICS_REPLY_FLG_FAT_MODE_MSK __constant_cpu_to_le32(0x8) -struct iwl4965_notif_statistics { - __le32 flag; - struct statistics_rx rx; - struct statistics_tx tx; - struct statistics_general general; -} __attribute__ ((packed)); - - -/* - * MISSED_BEACONS_NOTIFICATION = 0xa2 (notification only, not a command) - */ -/* if ucode missed CONSECUTIVE_MISSED_BCONS_TH beacons in a row, - * then this notification will be sent. */ -#define CONSECUTIVE_MISSED_BCONS_TH 20 - -struct iwl4965_missed_beacon_notif { - __le32 consequtive_missed_beacons; - __le32 total_missed_becons; - __le32 num_expected_beacons; - __le32 num_recvd_beacons; -} __attribute__ ((packed)); - - -/****************************************************************************** - * (11) - * Rx Calibration Commands: - * - * With the uCode used for open source drivers, most Tx calibration (except - * for Tx Power) and most Rx calibration is done by uCode during the - * "initialize" phase of uCode boot. Driver must calibrate only: - * - * 1) Tx power (depends on temperature), described elsewhere - * 2) Receiver gain balance (optimize MIMO, and detect disconnected antennas) - * 3) Receiver sensitivity (to optimize signal detection) - * - *****************************************************************************/ - -/** - * SENSITIVITY_CMD = 0xa8 (command, has simple generic response) - * - * This command sets up the Rx signal detector for a sensitivity level that - * is high enough to lock onto all signals within the associated network, - * but low enough to ignore signals that are below a certain threshold, so as - * not to have too many "false alarms". False alarms are signals that the - * Rx DSP tries to lock onto, but then discards after determining that they - * are noise. - * - * The optimum number of false alarms is between 5 and 50 per 200 TUs - * (200 * 1024 uSecs, i.e. 204.8 milliseconds) of actual Rx time (i.e. - * time listening, not transmitting). Driver must adjust sensitivity so that - * the ratio of actual false alarms to actual Rx time falls within this range. - * - * While associated, uCode delivers STATISTICS_NOTIFICATIONs after each - * received beacon. These provide information to the driver to analyze the - * sensitivity. Don't analyze statistics that come in from scanning, or any - * other non-associated-network source. Pertinent statistics include: - * - * From "general" statistics (struct statistics_rx_non_phy): - * - * (beacon_energy_[abc] & 0x0FF00) >> 8 (unsigned, higher value is lower level) - * Measure of energy of desired signal. Used for establishing a level - * below which the device does not detect signals. - * - * (beacon_silence_rssi_[abc] & 0x0FF00) >> 8 (unsigned, units in dB) - * Measure of background noise in silent period after beacon. - * - * channel_load - * uSecs of actual Rx time during beacon period (varies according to - * how much time was spent transmitting). - * - * From "cck" and "ofdm" statistics (struct statistics_rx_phy), separately: - * - * false_alarm_cnt - * Signal locks abandoned early (before phy-level header). - * - * plcp_err - * Signal locks abandoned late (during phy-level header). - * - * NOTE: Both false_alarm_cnt and plcp_err increment monotonically from - * beacon to beacon, i.e. each value is an accumulation of all errors - * before and including the latest beacon. Values will wrap around to 0 - * after counting up to 2^32 - 1. Driver must differentiate vs. - * previous beacon's values to determine # false alarms in the current - * beacon period. - * - * Total number of false alarms = false_alarms + plcp_errs - * - * For OFDM, adjust the following table entries in struct iwl_sensitivity_cmd - * (notice that the start points for OFDM are at or close to settings for - * maximum sensitivity): - * - * START / MIN / MAX - * HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX 90 / 85 / 120 - * HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX 170 / 170 / 210 - * HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX 105 / 105 / 140 - * HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX 220 / 220 / 270 - * - * If actual rate of OFDM false alarms (+ plcp_errors) is too high - * (greater than 50 for each 204.8 msecs listening), reduce sensitivity - * by *adding* 1 to all 4 of the table entries above, up to the max for - * each entry. Conversely, if false alarm rate is too low (less than 5 - * for each 204.8 msecs listening), *subtract* 1 from each entry to - * increase sensitivity. - * - * For CCK sensitivity, keep track of the following: - * - * 1). 20-beacon history of maximum background noise, indicated by - * (beacon_silence_rssi_[abc] & 0x0FF00), units in dB, across the - * 3 receivers. For any given beacon, the "silence reference" is - * the maximum of last 60 samples (20 beacons * 3 receivers). - * - * 2). 10-beacon history of strongest signal level, as indicated - * by (beacon_energy_[abc] & 0x0FF00) >> 8, across the 3 receivers, - * i.e. the strength of the signal through the best receiver at the - * moment. These measurements are "upside down", with lower values - * for stronger signals, so max energy will be *minimum* value. - * - * Then for any given beacon, the driver must determine the *weakest* - * of the strongest signals; this is the minimum level that needs to be - * successfully detected, when using the best receiver at the moment. - * "Max cck energy" is the maximum (higher value means lower energy!) - * of the last 10 minima. Once this is determined, driver must add - * a little margin by adding "6" to it. - * - * 3). Number of consecutive beacon periods with too few false alarms. - * Reset this to 0 at the first beacon period that falls within the - * "good" range (5 to 50 false alarms per 204.8 milliseconds rx). - * - * Then, adjust the following CCK table entries in struct iwl_sensitivity_cmd - * (notice that the start points for CCK are at maximum sensitivity): - * - * START / MIN / MAX - * HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX 125 / 125 / 200 - * HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX 200 / 200 / 400 - * HD_MIN_ENERGY_CCK_DET_INDEX 100 / 0 / 100 - * - * If actual rate of CCK false alarms (+ plcp_errors) is too high - * (greater than 50 for each 204.8 msecs listening), method for reducing - * sensitivity is: - * - * 1) *Add* 3 to value in HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX, - * up to max 400. - * - * 2) If current value in HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX is < 160, - * sensitivity has been reduced a significant amount; bring it up to - * a moderate 161. Otherwise, *add* 3, up to max 200. - * - * 3) a) If current value in HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX is > 160, - * sensitivity has been reduced only a moderate or small amount; - * *subtract* 2 from value in HD_MIN_ENERGY_CCK_DET_INDEX, - * down to min 0. Otherwise (if gain has been significantly reduced), - * don't change the HD_MIN_ENERGY_CCK_DET_INDEX value. - * - * b) Save a snapshot of the "silence reference". - * - * If actual rate of CCK false alarms (+ plcp_errors) is too low - * (less than 5 for each 204.8 msecs listening), method for increasing - * sensitivity is used only if: - * - * 1a) Previous beacon did not have too many false alarms - * 1b) AND difference between previous "silence reference" and current - * "silence reference" (prev - current) is 2 or more, - * OR 2) 100 or more consecutive beacon periods have had rate of - * less than 5 false alarms per 204.8 milliseconds rx time. - * - * Method for increasing sensitivity: - * - * 1) *Subtract* 3 from value in HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX, - * down to min 125. - * - * 2) *Subtract* 3 from value in HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX, - * down to min 200. - * - * 3) *Add* 2 to value in HD_MIN_ENERGY_CCK_DET_INDEX, up to max 100. - * - * If actual rate of CCK false alarms (+ plcp_errors) is within good range - * (between 5 and 50 for each 204.8 msecs listening): - * - * 1) Save a snapshot of the silence reference. - * - * 2) If previous beacon had too many CCK false alarms (+ plcp_errors), - * give some extra margin to energy threshold by *subtracting* 8 - * from value in HD_MIN_ENERGY_CCK_DET_INDEX. - * - * For all cases (too few, too many, good range), make sure that the CCK - * detection threshold (energy) is below the energy level for robust - * detection over the past 10 beacon periods, the "Max cck energy". - * Lower values mean higher energy; this means making sure that the value - * in HD_MIN_ENERGY_CCK_DET_INDEX is at or *above* "Max cck energy". - * - * Driver should set the following entries to fixed values: - * - * HD_MIN_ENERGY_OFDM_DET_INDEX 100 - * HD_BARKER_CORR_TH_ADD_MIN_INDEX 190 - * HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX 390 - * HD_OFDM_ENERGY_TH_IN_INDEX 62 - */ - -/* - * Table entries in SENSITIVITY_CMD (struct iwl_sensitivity_cmd) - */ -#define HD_TABLE_SIZE (11) /* number of entries */ -#define HD_MIN_ENERGY_CCK_DET_INDEX (0) /* table indexes */ -#define HD_MIN_ENERGY_OFDM_DET_INDEX (1) -#define HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX (2) -#define HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX (3) -#define HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX (4) -#define HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX (5) -#define HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX (6) -#define HD_BARKER_CORR_TH_ADD_MIN_INDEX (7) -#define HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX (8) -#define HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX (9) -#define HD_OFDM_ENERGY_TH_IN_INDEX (10) - -/* Control field in struct iwl_sensitivity_cmd */ -#define SENSITIVITY_CMD_CONTROL_DEFAULT_TABLE __constant_cpu_to_le16(0) -#define SENSITIVITY_CMD_CONTROL_WORK_TABLE __constant_cpu_to_le16(1) - -/** - * struct iwl_sensitivity_cmd - * @control: (1) updates working table, (0) updates default table - * @table: energy threshold values, use HD_* as index into table - * - * Always use "1" in "control" to update uCode's working table and DSP. - */ -struct iwl_sensitivity_cmd { - __le16 control; /* always use "1" */ - __le16 table[HD_TABLE_SIZE]; /* use HD_* as index */ -} __attribute__ ((packed)); - - -/** - * REPLY_PHY_CALIBRATION_CMD = 0xb0 (command, has simple generic response) - * - * This command sets the relative gains of 4965's 3 radio receiver chains. - * - * After the first association, driver should accumulate signal and noise - * statistics from the STATISTICS_NOTIFICATIONs that follow the first 20 - * beacons from the associated network (don't collect statistics that come - * in from scanning, or any other non-network source). - * - * DISCONNECTED ANTENNA: - * - * Driver should determine which antennas are actually connected, by comparing - * average beacon signal levels for the 3 Rx chains. Accumulate (add) the - * following values over 20 beacons, one accumulator for each of the chains - * a/b/c, from struct statistics_rx_non_phy: - * - * beacon_rssi_[abc] & 0x0FF (unsigned, units in dB) - * - * Find the strongest signal from among a/b/c. Compare the other two to the - * strongest. If any signal is more than 15 dB (times 20, unless you - * divide the accumulated values by 20) below the strongest, the driver - * considers that antenna to be disconnected, and should not try to use that - * antenna/chain for Rx or Tx. If both A and B seem to be disconnected, - * driver should declare the stronger one as connected, and attempt to use it - * (A and B are the only 2 Tx chains!). - * - * - * RX BALANCE: - * - * Driver should balance the 3 receivers (but just the ones that are connected - * to antennas, see above) for gain, by comparing the average signal levels - * detected during the silence after each beacon (background noise). - * Accumulate (add) the following values over 20 beacons, one accumulator for - * each of the chains a/b/c, from struct statistics_rx_non_phy: - * - * beacon_silence_rssi_[abc] & 0x0FF (unsigned, units in dB) - * - * Find the weakest background noise level from among a/b/c. This Rx chain - * will be the reference, with 0 gain adjustment. Attenuate other channels by - * finding noise difference: - * - * (accum_noise[i] - accum_noise[reference]) / 30 - * - * The "30" adjusts the dB in the 20 accumulated samples to units of 1.5 dB. - * For use in diff_gain_[abc] fields of struct iwl_calibration_cmd, the - * driver should limit the difference results to a range of 0-3 (0-4.5 dB), - * and set bit 2 to indicate "reduce gain". The value for the reference - * (weakest) chain should be "0". - * - * diff_gain_[abc] bit fields: - * 2: (1) reduce gain, (0) increase gain - * 1-0: amount of gain, units of 1.5 dB - */ - -/* "Differential Gain" opcode used in REPLY_PHY_CALIBRATION_CMD. */ -#define PHY_CALIBRATE_DIFF_GAIN_CMD (7) - -struct iwl4965_calibration_cmd { - u8 opCode; /* PHY_CALIBRATE_DIFF_GAIN_CMD (7) */ - u8 flags; /* not used */ - __le16 reserved; - s8 diff_gain_a; /* see above */ - s8 diff_gain_b; - s8 diff_gain_c; - u8 reserved1; -} __attribute__ ((packed)); - -/* Phy calibration command for 5000 series */ - -enum { - IWL5000_PHY_CALIBRATE_DC_CMD = 8, - IWL5000_PHY_CALIBRATE_LO_CMD = 9, - IWL5000_PHY_CALIBRATE_RX_BB_CMD = 10, - IWL5000_PHY_CALIBRATE_TX_IQ_CMD = 11, - IWL5000_PHY_CALIBRATE_RX_IQ_CMD = 12, - IWL5000_PHY_CALIBRATION_NOISE_CMD = 13, - IWL5000_PHY_CALIBRATE_AGC_TABLE_CMD = 14, - IWL5000_PHY_CALIBRATE_CRYSTAL_FRQ_CMD = 15, - IWL5000_PHY_CALIBRATE_BASE_BAND_CMD = 16, - IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD = 18, - IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD = 19, -}; - -struct iwl5000_calibration_chain_noise_reset_cmd { - u8 op_code; /* IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD */ - u8 flags; /* not used */ - __le16 reserved; -} __attribute__ ((packed)); - -struct iwl5000_calibration_chain_noise_gain_cmd { - u8 op_code; /* IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD */ - u8 flags; /* not used */ - __le16 reserved; - u8 delta_gain_1; - u8 delta_gain_2; - __le16 reserved1; -} __attribute__ ((packed)); - -/****************************************************************************** - * (12) - * Miscellaneous Commands: - * - *****************************************************************************/ - -/* - * LEDs Command & Response - * REPLY_LEDS_CMD = 0x48 (command, has simple generic response) - * - * For each of 3 possible LEDs (Activity/Link/Tech, selected by "id" field), - * this command turns it on or off, or sets up a periodic blinking cycle. - */ -struct iwl4965_led_cmd { - __le32 interval; /* "interval" in uSec */ - u8 id; /* 1: Activity, 2: Link, 3: Tech */ - u8 off; /* # intervals off while blinking; - * "0", with >0 "on" value, turns LED on */ - u8 on; /* # intervals on while blinking; - * "0", regardless of "off", turns LED off */ - u8 reserved; -} __attribute__ ((packed)); - -/****************************************************************************** - * (13) - * Union of all expected notifications/responses: - * - *****************************************************************************/ - -struct iwl4965_rx_packet { - __le32 len; - struct iwl_cmd_header hdr; - union { - struct iwl4965_alive_resp alive_frame; - struct iwl4965_rx_frame rx_frame; - struct iwl4965_tx_resp tx_resp; - struct iwl4965_spectrum_notification spectrum_notif; - struct iwl4965_csa_notification csa_notif; - struct iwl4965_error_resp err_resp; - struct iwl4965_card_state_notif card_state_notif; - struct iwl4965_beacon_notif beacon_status; - struct iwl4965_add_sta_resp add_sta; - struct iwl4965_sleep_notification sleep_notif; - struct iwl4965_spectrum_resp spectrum; - struct iwl4965_notif_statistics stats; - struct iwl4965_compressed_ba_resp compressed_ba; - struct iwl4965_missed_beacon_notif missed_beacon; - __le32 status; - u8 raw[0]; - } u; -} __attribute__ ((packed)); - -#define IWL_RX_FRAME_SIZE (4 + sizeof(struct iwl4965_rx_frame)) - -#endif /* __iwl4965_commands_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h index bea03f68267..6dbdc0eec76 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h @@ -62,7 +62,7 @@ *****************************************************************************/ /* * Please use this file (iwl-4965-hw.h) only for hardware-related definitions. - * Use iwl-4965-commands.h for uCode API definitions. + * Use iwl-commands.h for uCode API definitions. * Use iwl-4965.h for driver implementation definitions. */ @@ -98,7 +98,7 @@ #define IWL_RSSI_OFFSET 44 -#include "iwl-4965-commands.h" +#include "iwl-commands.h" #define PCI_LINK_CTRL 0x0F0 #define PCI_POWER_SOURCE 0x0C8 diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h index 78fe8b73169..d556c2ffd8d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965.h @@ -25,7 +25,7 @@ *****************************************************************************/ /* * Please use this file (iwl-4965.h) for driver implementation definitions. - * Please use iwl-4965-commands.h for uCode API definitions. + * Please use iwl-commands.h for uCode API definitions. * Please use iwl-4965-hw.h for hardware-related definitions. */ diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h new file mode 100644 index 00000000000..25950551b1b --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -0,0 +1,2759 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ +/* + * Please use this file (iwl-commands.h) only for uCode API definitions. + * Please use iwl-4965-hw.h for hardware-related definitions. + * Please use iwl-4965.h for driver implementation definitions. + */ + +#ifndef __iwl4965_commands_h__ +#define __iwl4965_commands_h__ + +enum { + REPLY_ALIVE = 0x1, + REPLY_ERROR = 0x2, + + /* RXON and QOS commands */ + REPLY_RXON = 0x10, + REPLY_RXON_ASSOC = 0x11, + REPLY_QOS_PARAM = 0x13, + REPLY_RXON_TIMING = 0x14, + + /* Multi-Station support */ + REPLY_ADD_STA = 0x18, + REPLY_REMOVE_STA = 0x19, /* not used */ + REPLY_REMOVE_ALL_STA = 0x1a, /* not used */ + + /* Security */ + REPLY_WEPKEY = 0x20, + + /* RX, TX, LEDs */ + REPLY_TX = 0x1c, + REPLY_RATE_SCALE = 0x47, /* 3945 only */ + REPLY_LEDS_CMD = 0x48, + REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* 4965 only */ + + /* 802.11h related */ + RADAR_NOTIFICATION = 0x70, /* not used */ + REPLY_QUIET_CMD = 0x71, /* not used */ + REPLY_CHANNEL_SWITCH = 0x72, + CHANNEL_SWITCH_NOTIFICATION = 0x73, + REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74, + SPECTRUM_MEASURE_NOTIFICATION = 0x75, + + /* Power Management */ + POWER_TABLE_CMD = 0x77, + PM_SLEEP_NOTIFICATION = 0x7A, + PM_DEBUG_STATISTIC_NOTIFIC = 0x7B, + + /* Scan commands and notifications */ + REPLY_SCAN_CMD = 0x80, + REPLY_SCAN_ABORT_CMD = 0x81, + SCAN_START_NOTIFICATION = 0x82, + SCAN_RESULTS_NOTIFICATION = 0x83, + SCAN_COMPLETE_NOTIFICATION = 0x84, + + /* IBSS/AP commands */ + BEACON_NOTIFICATION = 0x90, + REPLY_TX_BEACON = 0x91, + WHO_IS_AWAKE_NOTIFICATION = 0x94, /* not used */ + + /* Miscellaneous commands */ + QUIET_NOTIFICATION = 0x96, /* not used */ + REPLY_TX_PWR_TABLE_CMD = 0x97, + MEASURE_ABORT_NOTIFICATION = 0x99, /* not used */ + + /* Bluetooth device coexistance config command */ + REPLY_BT_CONFIG = 0x9b, + + /* Statistics */ + REPLY_STATISTICS_CMD = 0x9c, + STATISTICS_NOTIFICATION = 0x9d, + + /* RF-KILL commands and notifications */ + REPLY_CARD_STATE_CMD = 0xa0, + CARD_STATE_NOTIFICATION = 0xa1, + + /* Missed beacons notification */ + MISSED_BEACONS_NOTIFICATION = 0xa2, + + REPLY_CT_KILL_CONFIG_CMD = 0xa4, + SENSITIVITY_CMD = 0xa8, + REPLY_PHY_CALIBRATION_CMD = 0xb0, + REPLY_RX_PHY_CMD = 0xc0, + REPLY_RX_MPDU_CMD = 0xc1, + REPLY_RX = 0xc3, + REPLY_COMPRESSED_BA = 0xc5, + REPLY_MAX = 0xff +}; + +/****************************************************************************** + * (0) + * Commonly used structures and definitions: + * Command header, rate_n_flags, txpower + * + *****************************************************************************/ + +/* iwl_cmd_header flags value */ +#define IWL_CMD_FAILED_MSK 0x40 + +/** + * struct iwl_cmd_header + * + * This header format appears in the beginning of each command sent from the + * driver, and each response/notification received from uCode. + */ +struct iwl_cmd_header { + u8 cmd; /* Command ID: REPLY_RXON, etc. */ + u8 flags; /* IWL_CMD_* */ + /* + * The driver sets up the sequence number to values of its chosing. + * uCode does not use this value, but passes it back to the driver + * when sending the response to each driver-originated command, so + * the driver can match the response to the command. Since the values + * don't get used by uCode, the driver may set up an arbitrary format. + * + * There is one exception: uCode sets bit 15 when it originates + * the response/notification, i.e. when the response/notification + * is not a direct response to a command sent by the driver. For + * example, uCode issues REPLY_3945_RX when it sends a received frame + * to the driver; it is not a direct response to any driver command. + * + * The Linux driver uses the following format: + * + * 0:7 index/position within Tx queue + * 8:13 Tx queue selection + * 14:14 driver sets this to indicate command is in the 'huge' + * storage at the end of the command buffers, i.e. scan cmd + * 15:15 uCode sets this in uCode-originated response/notification + */ + __le16 sequence; + + /* command or response/notification data follows immediately */ + u8 data[0]; +} __attribute__ ((packed)); + +/** + * 4965 rate_n_flags bit fields + * + * rate_n_flags format is used in following 4965 commands: + * REPLY_RX (response only) + * REPLY_TX (both command and response) + * REPLY_TX_LINK_QUALITY_CMD + * + * High-throughput (HT) rate format for bits 7:0 (bit 8 must be "1"): + * 2-0: 0) 6 Mbps + * 1) 12 Mbps + * 2) 18 Mbps + * 3) 24 Mbps + * 4) 36 Mbps + * 5) 48 Mbps + * 6) 54 Mbps + * 7) 60 Mbps + * + * 3: 0) Single stream (SISO) + * 1) Dual stream (MIMO) + * + * 5: Value of 0x20 in bits 7:0 indicates 6 Mbps FAT duplicate data + * + * Legacy OFDM rate format for bits 7:0 (bit 8 must be "0", bit 9 "0"): + * 3-0: 0xD) 6 Mbps + * 0xF) 9 Mbps + * 0x5) 12 Mbps + * 0x7) 18 Mbps + * 0x9) 24 Mbps + * 0xB) 36 Mbps + * 0x1) 48 Mbps + * 0x3) 54 Mbps + * + * Legacy CCK rate format for bits 7:0 (bit 8 must be "0", bit 9 "1"): + * 3-0: 10) 1 Mbps + * 20) 2 Mbps + * 55) 5.5 Mbps + * 110) 11 Mbps + */ +#define RATE_MCS_CODE_MSK 0x7 +#define RATE_MCS_MIMO_POS 3 +#define RATE_MCS_MIMO_MSK 0x8 +#define RATE_MCS_HT_DUP_POS 5 +#define RATE_MCS_HT_DUP_MSK 0x20 + +/* Bit 8: (1) HT format, (0) legacy format in bits 7:0 */ +#define RATE_MCS_FLAGS_POS 8 +#define RATE_MCS_HT_POS 8 +#define RATE_MCS_HT_MSK 0x100 + +/* Bit 9: (1) CCK, (0) OFDM. HT (bit 8) must be "0" for this bit to be valid */ +#define RATE_MCS_CCK_POS 9 +#define RATE_MCS_CCK_MSK 0x200 + +/* Bit 10: (1) Use Green Field preamble */ +#define RATE_MCS_GF_POS 10 +#define RATE_MCS_GF_MSK 0x400 + +/* Bit 11: (1) Use 40Mhz FAT chnl width, (0) use 20 MHz legacy chnl width */ +#define RATE_MCS_FAT_POS 11 +#define RATE_MCS_FAT_MSK 0x800 + +/* Bit 12: (1) Duplicate data on both 20MHz chnls. FAT (bit 11) must be set. */ +#define RATE_MCS_DUP_POS 12 +#define RATE_MCS_DUP_MSK 0x1000 + +/* Bit 13: (1) Short guard interval (0.4 usec), (0) normal GI (0.8 usec) */ +#define RATE_MCS_SGI_POS 13 +#define RATE_MCS_SGI_MSK 0x2000 + +/** + * rate_n_flags Tx antenna masks (4965 has 2 transmitters): + * bit14:15 01 B inactive, A active + * 10 B active, A inactive + * 11 Both active + */ +#define RATE_MCS_ANT_POS 14 +#define RATE_MCS_ANT_A_MSK 0x04000 +#define RATE_MCS_ANT_B_MSK 0x08000 +#define RATE_MCS_ANT_C_MSK 0x10000 +#define RATE_MCS_ANT_ABC_MSK 0x1C000 + + +/** + * struct iwl4965_tx_power - txpower format used in REPLY_SCAN_CMD + * + * Scan uses only one transmitter, so only one analog/dsp gain pair is needed. + */ +struct iwl4965_tx_power { + u8 tx_gain; /* gain for analog radio */ + u8 dsp_atten; /* gain for DSP */ +} __attribute__ ((packed)); + +#define POWER_TABLE_NUM_ENTRIES 33 +#define POWER_TABLE_NUM_HT_OFDM_ENTRIES 32 +#define POWER_TABLE_CCK_ENTRY 32 + +/** + * union iwl4965_tx_power_dual_stream + * + * Host format used for REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH + * Use __le32 version (struct tx_power_dual_stream) when building command. + * + * Driver provides radio gain and DSP attenuation settings to device in pairs, + * one value for each transmitter chain. The first value is for transmitter A, + * second for transmitter B. + * + * For SISO bit rates, both values in a pair should be identical. + * For MIMO rates, one value may be different from the other, + * in order to balance the Tx output between the two transmitters. + * + * See more details in doc for TXPOWER in iwl-4965-hw.h. + */ +union iwl4965_tx_power_dual_stream { + struct { + u8 radio_tx_gain[2]; + u8 dsp_predis_atten[2]; + } s; + u32 dw; +}; + +/** + * struct tx_power_dual_stream + * + * Table entries in REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH + * + * Same format as iwl_tx_power_dual_stream, but __le32 + */ +struct tx_power_dual_stream { + __le32 dw; +} __attribute__ ((packed)); + +/** + * struct iwl4965_tx_power_db + * + * Entire table within REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH + */ +struct iwl4965_tx_power_db { + struct tx_power_dual_stream power_tbl[POWER_TABLE_NUM_ENTRIES]; +} __attribute__ ((packed)); + + +/****************************************************************************** + * (0a) + * Alive and Error Commands & Responses: + * + *****************************************************************************/ + +#define UCODE_VALID_OK __constant_cpu_to_le32(0x1) +#define INITIALIZE_SUBTYPE (9) + +/* + * ("Initialize") REPLY_ALIVE = 0x1 (response only, not a command) + * + * uCode issues this "initialize alive" notification once the initialization + * uCode image has completed its work, and is ready to load the runtime image. + * This is the *first* "alive" notification that the driver will receive after + * rebooting uCode; the "initialize" alive is indicated by subtype field == 9. + * + * See comments documenting "BSM" (bootstrap state machine). + * + * For 4965, this notification contains important calibration data for + * calculating txpower settings: + * + * 1) Power supply voltage indication. The voltage sensor outputs higher + * values for lower voltage, and vice versa. + * + * 2) Temperature measurement parameters, for each of two channel widths + * (20 MHz and 40 MHz) supported by the radios. Temperature sensing + * is done via one of the receiver chains, and channel width influences + * the results. + * + * 3) Tx gain compensation to balance 4965's 2 Tx chains for MIMO operation, + * for each of 5 frequency ranges. + */ +struct iwl4965_init_alive_resp { + u8 ucode_minor; + u8 ucode_major; + __le16 reserved1; + u8 sw_rev[8]; + u8 ver_type; + u8 ver_subtype; /* "9" for initialize alive */ + __le16 reserved2; + __le32 log_event_table_ptr; + __le32 error_event_table_ptr; + __le32 timestamp; + __le32 is_valid; + + /* calibration values from "initialize" uCode */ + __le32 voltage; /* signed, higher value is lower voltage */ + __le32 therm_r1[2]; /* signed, 1st for normal, 2nd for FAT channel*/ + __le32 therm_r2[2]; /* signed */ + __le32 therm_r3[2]; /* signed */ + __le32 therm_r4[2]; /* signed */ + __le32 tx_atten[5][2]; /* signed MIMO gain comp, 5 freq groups, + * 2 Tx chains */ +} __attribute__ ((packed)); + + +/** + * REPLY_ALIVE = 0x1 (response only, not a command) + * + * uCode issues this "alive" notification once the runtime image is ready + * to receive commands from the driver. This is the *second* "alive" + * notification that the driver will receive after rebooting uCode; + * this "alive" is indicated by subtype field != 9. + * + * See comments documenting "BSM" (bootstrap state machine). + * + * This response includes two pointers to structures within the device's + * data SRAM (access via HBUS_TARG_MEM_* regs) that are useful for debugging: + * + * 1) log_event_table_ptr indicates base of the event log. This traces + * a 256-entry history of uCode execution within a circular buffer. + * Its header format is: + * + * __le32 log_size; log capacity (in number of entries) + * __le32 type; (1) timestamp with each entry, (0) no timestamp + * __le32 wraps; # times uCode has wrapped to top of circular buffer + * __le32 write_index; next circular buffer entry that uCode would fill + * + * The header is followed by the circular buffer of log entries. Entries + * with timestamps have the following format: + * + * __le32 event_id; range 0 - 1500 + * __le32 timestamp; low 32 bits of TSF (of network, if associated) + * __le32 data; event_id-specific data value + * + * Entries without timestamps contain only event_id and data. + * + * 2) error_event_table_ptr indicates base of the error log. This contains + * information about any uCode error that occurs. For 4965, the format + * of the error log is: + * + * __le32 valid; (nonzero) valid, (0) log is empty + * __le32 error_id; type of error + * __le32 pc; program counter + * __le32 blink1; branch link + * __le32 blink2; branch link + * __le32 ilink1; interrupt link + * __le32 ilink2; interrupt link + * __le32 data1; error-specific data + * __le32 data2; error-specific data + * __le32 line; source code line of error + * __le32 bcon_time; beacon timer + * __le32 tsf_low; network timestamp function timer + * __le32 tsf_hi; network timestamp function timer + * + * The Linux driver can print both logs to the system log when a uCode error + * occurs. + */ +struct iwl4965_alive_resp { + u8 ucode_minor; + u8 ucode_major; + __le16 reserved1; + u8 sw_rev[8]; + u8 ver_type; + u8 ver_subtype; /* not "9" for runtime alive */ + __le16 reserved2; + __le32 log_event_table_ptr; /* SRAM address for event log */ + __le32 error_event_table_ptr; /* SRAM address for error log */ + __le32 timestamp; + __le32 is_valid; +} __attribute__ ((packed)); + + +union tsf { + u8 byte[8]; + __le16 word[4]; + __le32 dw[2]; +}; + +/* + * REPLY_ERROR = 0x2 (response only, not a command) + */ +struct iwl4965_error_resp { + __le32 error_type; + u8 cmd_id; + u8 reserved1; + __le16 bad_cmd_seq_num; + __le32 error_info; + union tsf timestamp; +} __attribute__ ((packed)); + +/****************************************************************************** + * (1) + * RXON Commands & Responses: + * + *****************************************************************************/ + +/* + * Rx config defines & structure + */ +/* rx_config device types */ +enum { + RXON_DEV_TYPE_AP = 1, + RXON_DEV_TYPE_ESS = 3, + RXON_DEV_TYPE_IBSS = 4, + RXON_DEV_TYPE_SNIFFER = 6, +}; + + +#define RXON_RX_CHAIN_DRIVER_FORCE_MSK __constant_cpu_to_le16(0x1 << 0) +#define RXON_RX_CHAIN_VALID_MSK __constant_cpu_to_le16(0x7 << 1) +#define RXON_RX_CHAIN_VALID_POS (1) +#define RXON_RX_CHAIN_FORCE_SEL_MSK __constant_cpu_to_le16(0x7 << 4) +#define RXON_RX_CHAIN_FORCE_SEL_POS (4) +#define RXON_RX_CHAIN_FORCE_MIMO_SEL_MSK __constant_cpu_to_le16(0x7 << 7) +#define RXON_RX_CHAIN_FORCE_MIMO_SEL_POS (7) +#define RXON_RX_CHAIN_CNT_MSK __constant_cpu_to_le16(0x3 << 10) +#define RXON_RX_CHAIN_CNT_POS (10) +#define RXON_RX_CHAIN_MIMO_CNT_MSK __constant_cpu_to_le16(0x3 << 12) +#define RXON_RX_CHAIN_MIMO_CNT_POS (12) +#define RXON_RX_CHAIN_MIMO_FORCE_MSK __constant_cpu_to_le16(0x1 << 14) +#define RXON_RX_CHAIN_MIMO_FORCE_POS (14) + +/* rx_config flags */ +/* band & modulation selection */ +#define RXON_FLG_BAND_24G_MSK __constant_cpu_to_le32(1 << 0) +#define RXON_FLG_CCK_MSK __constant_cpu_to_le32(1 << 1) +/* auto detection enable */ +#define RXON_FLG_AUTO_DETECT_MSK __constant_cpu_to_le32(1 << 2) +/* TGg protection when tx */ +#define RXON_FLG_TGG_PROTECT_MSK __constant_cpu_to_le32(1 << 3) +/* cck short slot & preamble */ +#define RXON_FLG_SHORT_SLOT_MSK __constant_cpu_to_le32(1 << 4) +#define RXON_FLG_SHORT_PREAMBLE_MSK __constant_cpu_to_le32(1 << 5) +/* antenna selection */ +#define RXON_FLG_DIS_DIV_MSK __constant_cpu_to_le32(1 << 7) +#define RXON_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0x0f00) +#define RXON_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8) +#define RXON_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9) +/* radar detection enable */ +#define RXON_FLG_RADAR_DETECT_MSK __constant_cpu_to_le32(1 << 12) +#define RXON_FLG_TGJ_NARROW_BAND_MSK __constant_cpu_to_le32(1 << 13) +/* rx response to host with 8-byte TSF +* (according to ON_AIR deassertion) */ +#define RXON_FLG_TSF2HOST_MSK __constant_cpu_to_le32(1 << 15) + + +/* HT flags */ +#define RXON_FLG_CTRL_CHANNEL_LOC_POS (22) +#define RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK __constant_cpu_to_le32(0x1 << 22) + +#define RXON_FLG_HT_OPERATING_MODE_POS (23) + +#define RXON_FLG_HT_PROT_MSK __constant_cpu_to_le32(0x1 << 23) +#define RXON_FLG_FAT_PROT_MSK __constant_cpu_to_le32(0x2 << 23) + +#define RXON_FLG_CHANNEL_MODE_POS (25) +#define RXON_FLG_CHANNEL_MODE_MSK __constant_cpu_to_le32(0x3 << 25) +#define RXON_FLG_CHANNEL_MODE_PURE_40_MSK __constant_cpu_to_le32(0x1 << 25) +#define RXON_FLG_CHANNEL_MODE_MIXED_MSK __constant_cpu_to_le32(0x2 << 25) + +/* rx_config filter flags */ +/* accept all data frames */ +#define RXON_FILTER_PROMISC_MSK __constant_cpu_to_le32(1 << 0) +/* pass control & management to host */ +#define RXON_FILTER_CTL2HOST_MSK __constant_cpu_to_le32(1 << 1) +/* accept multi-cast */ +#define RXON_FILTER_ACCEPT_GRP_MSK __constant_cpu_to_le32(1 << 2) +/* don't decrypt uni-cast frames */ +#define RXON_FILTER_DIS_DECRYPT_MSK __constant_cpu_to_le32(1 << 3) +/* don't decrypt multi-cast frames */ +#define RXON_FILTER_DIS_GRP_DECRYPT_MSK __constant_cpu_to_le32(1 << 4) +/* STA is associated */ +#define RXON_FILTER_ASSOC_MSK __constant_cpu_to_le32(1 << 5) +/* transfer to host non bssid beacons in associated state */ +#define RXON_FILTER_BCON_AWARE_MSK __constant_cpu_to_le32(1 << 6) + +/** + * REPLY_RXON = 0x10 (command, has simple generic response) + * + * RXON tunes the radio tuner to a service channel, and sets up a number + * of parameters that are used primarily for Rx, but also for Tx operations. + * + * NOTE: When tuning to a new channel, driver must set the + * RXON_FILTER_ASSOC_MSK to 0. This will clear station-dependent + * info within the device, including the station tables, tx retry + * rate tables, and txpower tables. Driver must build a new station + * table and txpower table before transmitting anything on the RXON + * channel. + * + * NOTE: All RXONs wipe clean the internal txpower table. Driver must + * issue a new REPLY_TX_PWR_TABLE_CMD after each REPLY_RXON (0x10), + * regardless of whether RXON_FILTER_ASSOC_MSK is set. + */ +struct iwl4965_rxon_cmd { + u8 node_addr[6]; + __le16 reserved1; + u8 bssid_addr[6]; + __le16 reserved2; + u8 wlap_bssid_addr[6]; + __le16 reserved3; + u8 dev_type; + u8 air_propagation; + __le16 rx_chain; + u8 ofdm_basic_rates; + u8 cck_basic_rates; + __le16 assoc_id; + __le32 flags; + __le32 filter_flags; + __le16 channel; + u8 ofdm_ht_single_stream_basic_rates; + u8 ofdm_ht_dual_stream_basic_rates; +} __attribute__ ((packed)); + +/* + * REPLY_RXON_ASSOC = 0x11 (command, has simple generic response) + */ +struct iwl4965_rxon_assoc_cmd { + __le32 flags; + __le32 filter_flags; + u8 ofdm_basic_rates; + u8 cck_basic_rates; + u8 ofdm_ht_single_stream_basic_rates; + u8 ofdm_ht_dual_stream_basic_rates; + __le16 rx_chain_select_flags; + __le16 reserved; +} __attribute__ ((packed)); + +/* + * REPLY_RXON_TIMING = 0x14 (command, has simple generic response) + */ +struct iwl4965_rxon_time_cmd { + union tsf timestamp; + __le16 beacon_interval; + __le16 atim_window; + __le32 beacon_init_val; + __le16 listen_interval; + __le16 reserved; +} __attribute__ ((packed)); + +/* + * REPLY_CHANNEL_SWITCH = 0x72 (command, has simple generic response) + */ +struct iwl4965_channel_switch_cmd { + u8 band; + u8 expect_beacon; + __le16 channel; + __le32 rxon_flags; + __le32 rxon_filter_flags; + __le32 switch_time; + struct iwl4965_tx_power_db tx_power; +} __attribute__ ((packed)); + +/* + * CHANNEL_SWITCH_NOTIFICATION = 0x73 (notification only, not a command) + */ +struct iwl4965_csa_notification { + __le16 band; + __le16 channel; + __le32 status; /* 0 - OK, 1 - fail */ +} __attribute__ ((packed)); + +/****************************************************************************** + * (2) + * Quality-of-Service (QOS) Commands & Responses: + * + *****************************************************************************/ + +/** + * struct iwl_ac_qos -- QOS timing params for REPLY_QOS_PARAM + * One for each of 4 EDCA access categories in struct iwl_qosparam_cmd + * + * @cw_min: Contention window, start value in numbers of slots. + * Should be a power-of-2, minus 1. Device's default is 0x0f. + * @cw_max: Contention window, max value in numbers of slots. + * Should be a power-of-2, minus 1. Device's default is 0x3f. + * @aifsn: Number of slots in Arbitration Interframe Space (before + * performing random backoff timing prior to Tx). Device default 1. + * @edca_txop: Length of Tx opportunity, in uSecs. Device default is 0. + * + * Device will automatically increase contention window by (2*CW) + 1 for each + * transmission retry. Device uses cw_max as a bit mask, ANDed with new CW + * value, to cap the CW value. + */ +struct iwl4965_ac_qos { + __le16 cw_min; + __le16 cw_max; + u8 aifsn; + u8 reserved1; + __le16 edca_txop; +} __attribute__ ((packed)); + +/* QoS flags defines */ +#define QOS_PARAM_FLG_UPDATE_EDCA_MSK __constant_cpu_to_le32(0x01) +#define QOS_PARAM_FLG_TGN_MSK __constant_cpu_to_le32(0x02) +#define QOS_PARAM_FLG_TXOP_TYPE_MSK __constant_cpu_to_le32(0x10) + +/* Number of Access Categories (AC) (EDCA), queues 0..3 */ +#define AC_NUM 4 + +/* + * REPLY_QOS_PARAM = 0x13 (command, has simple generic response) + * + * This command sets up timings for each of the 4 prioritized EDCA Tx FIFOs + * 0: Background, 1: Best Effort, 2: Video, 3: Voice. + */ +struct iwl4965_qosparam_cmd { + __le32 qos_flags; + struct iwl4965_ac_qos ac[AC_NUM]; +} __attribute__ ((packed)); + +/****************************************************************************** + * (3) + * Add/Modify Stations Commands & Responses: + * + *****************************************************************************/ +/* + * Multi station support + */ + +/* Special, dedicated locations within device's station table */ +#define IWL_AP_ID 0 +#define IWL_MULTICAST_ID 1 +#define IWL_STA_ID 2 +#define IWL4965_BROADCAST_ID 31 +#define IWL4965_STATION_COUNT 32 +#define IWL5000_BROADCAST_ID 15 +#define IWL5000_STATION_COUNT 16 + +#define IWL_STATION_COUNT 32 /* MAX(3945,4965)*/ +#define IWL_INVALID_STATION 255 + +#define STA_FLG_PWR_SAVE_MSK __constant_cpu_to_le32(1 << 8); +#define STA_FLG_RTS_MIMO_PROT_MSK __constant_cpu_to_le32(1 << 17) +#define STA_FLG_AGG_MPDU_8US_MSK __constant_cpu_to_le32(1 << 18) +#define STA_FLG_MAX_AGG_SIZE_POS (19) +#define STA_FLG_MAX_AGG_SIZE_MSK __constant_cpu_to_le32(3 << 19) +#define STA_FLG_FAT_EN_MSK __constant_cpu_to_le32(1 << 21) +#define STA_FLG_MIMO_DIS_MSK __constant_cpu_to_le32(1 << 22) +#define STA_FLG_AGG_MPDU_DENSITY_POS (23) +#define STA_FLG_AGG_MPDU_DENSITY_MSK __constant_cpu_to_le32(7 << 23) + +/* Use in mode field. 1: modify existing entry, 0: add new station entry */ +#define STA_CONTROL_MODIFY_MSK 0x01 + +/* key flags __le16*/ +#define STA_KEY_FLG_ENCRYPT_MSK __constant_cpu_to_le16(0x0007) +#define STA_KEY_FLG_NO_ENC __constant_cpu_to_le16(0x0000) +#define STA_KEY_FLG_WEP __constant_cpu_to_le16(0x0001) +#define STA_KEY_FLG_CCMP __constant_cpu_to_le16(0x0002) +#define STA_KEY_FLG_TKIP __constant_cpu_to_le16(0x0003) + +#define STA_KEY_FLG_KEYID_POS 8 +#define STA_KEY_FLG_INVALID __constant_cpu_to_le16(0x0800) +/* wep key is either from global key (0) or from station info array (1) */ +#define STA_KEY_FLG_MAP_KEY_MSK __constant_cpu_to_le16(0x0008) + +/* wep key in STA: 5-bytes (0) or 13-bytes (1) */ +#define STA_KEY_FLG_KEY_SIZE_MSK __constant_cpu_to_le16(0x1000) +#define STA_KEY_MULTICAST_MSK __constant_cpu_to_le16(0x4000) +#define STA_KEY_MAX_NUM 8 + +/* Flags indicate whether to modify vs. don't change various station params */ +#define STA_MODIFY_KEY_MASK 0x01 +#define STA_MODIFY_TID_DISABLE_TX 0x02 +#define STA_MODIFY_TX_RATE_MSK 0x04 +#define STA_MODIFY_ADDBA_TID_MSK 0x08 +#define STA_MODIFY_DELBA_TID_MSK 0x10 + +/* Receiver address (actually, Rx station's index into station table), + * combined with Traffic ID (QOS priority), in format used by Tx Scheduler */ +#define BUILD_RAxTID(sta_id, tid) (((sta_id) << 4) + (tid)) + +struct iwl4965_keyinfo { + __le16 key_flags; + u8 tkip_rx_tsc_byte2; /* TSC[2] for key mix ph1 detection */ + u8 reserved1; + __le16 tkip_rx_ttak[5]; /* 10-byte unicast TKIP TTAK */ + u8 key_offset; + u8 reserved2; + u8 key[16]; /* 16-byte unicast decryption key */ +} __attribute__ ((packed)); + +/** + * struct sta_id_modify + * @addr[ETH_ALEN]: station's MAC address + * @sta_id: index of station in uCode's station table + * @modify_mask: STA_MODIFY_*, 1: modify, 0: don't change + * + * Driver selects unused table index when adding new station, + * or the index to a pre-existing station entry when modifying that station. + * Some indexes have special purposes (IWL_AP_ID, index 0, is for AP). + * + * modify_mask flags select which parameters to modify vs. leave alone. + */ +struct sta_id_modify { + u8 addr[ETH_ALEN]; + __le16 reserved1; + u8 sta_id; + u8 modify_mask; + __le16 reserved2; +} __attribute__ ((packed)); + +/* + * REPLY_ADD_STA = 0x18 (command) + * + * The device contains an internal table of per-station information, + * with info on security keys, aggregation parameters, and Tx rates for + * initial Tx attempt and any retries (4965 uses REPLY_TX_LINK_QUALITY_CMD, + * 3945 uses REPLY_RATE_SCALE to set up rate tables). + * + * REPLY_ADD_STA sets up the table entry for one station, either creating + * a new entry, or modifying a pre-existing one. + * + * NOTE: RXON command (without "associated" bit set) wipes the station table + * clean. Moving into RF_KILL state does this also. Driver must set up + * new station table before transmitting anything on the RXON channel + * (except active scans or active measurements; those commands carry + * their own txpower/rate setup data). + * + * When getting started on a new channel, driver must set up the + * IWL_BROADCAST_ID entry (last entry in the table). For a client + * station in a BSS, once an AP is selected, driver sets up the AP STA + * in the IWL_AP_ID entry (1st entry in the table). BROADCAST and AP + * are all that are needed for a BSS client station. If the device is + * used as AP, or in an IBSS network, driver must set up station table + * entries for all STAs in network, starting with index IWL_STA_ID. + */ +struct iwl4965_addsta_cmd { + u8 mode; /* 1: modify existing, 0: add new station */ + u8 reserved[3]; + struct sta_id_modify sta; + struct iwl4965_keyinfo key; + __le32 station_flags; /* STA_FLG_* */ + __le32 station_flags_msk; /* STA_FLG_* */ + + /* bit field to disable (1) or enable (0) Tx for Traffic ID (TID) + * 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 reserved1; + + /* TID for which to add block-ack support. + * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ + u8 add_immediate_ba_tid; + + /* TID for which to remove block-ack support. + * Set modify_mask bit STA_MODIFY_DELBA_TID_MSK to use this field. */ + u8 remove_immediate_ba_tid; + + /* Starting Sequence Number for added block-ack support. + * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ + __le16 add_immediate_ba_ssn; + + __le32 reserved2; +} __attribute__ ((packed)); + +#define ADD_STA_SUCCESS_MSK 0x1 +#define ADD_STA_NO_ROOM_IN_TABLE 0x2 +#define ADD_STA_NO_BLOCK_ACK_RESOURCE 0x4 +#define ADD_STA_MODIFY_NON_EXIST_STA 0x8 +/* + * REPLY_ADD_STA = 0x18 (response) + */ +struct iwl4965_add_sta_resp { + u8 status; /* ADD_STA_* */ +} __attribute__ ((packed)); + +/* + * REPLY_WEP_KEY = 0x20 + */ +struct iwl_wep_key { + u8 key_index; + u8 key_offset; + u8 reserved1[2]; + u8 key_size; + u8 reserved2[3]; + u8 key[16]; +} __attribute__ ((packed)); + +struct iwl_wep_cmd { + u8 num_keys; + u8 global_key_type; + u8 flags; + u8 reserved; + struct iwl_wep_key key[0]; +} __attribute__ ((packed)); + +#define WEP_KEY_WEP_TYPE 1 +#define WEP_KEYS_MAX 4 +#define WEP_INVALID_OFFSET 0xff +#define WEP_KEY_LEN_128 13 + +/****************************************************************************** + * (4) + * Rx Responses: + * + *****************************************************************************/ + +struct iwl4965_rx_frame_stats { + u8 phy_count; + u8 id; + u8 rssi; + u8 agc; + __le16 sig_avg; + __le16 noise_diff; + u8 payload[0]; +} __attribute__ ((packed)); + +struct iwl4965_rx_frame_hdr { + __le16 channel; + __le16 phy_flags; + u8 reserved1; + u8 rate; + __le16 len; + u8 payload[0]; +} __attribute__ ((packed)); + +#define RX_RES_STATUS_NO_CRC32_ERROR __constant_cpu_to_le32(1 << 0) +#define RX_RES_STATUS_NO_RXE_OVERFLOW __constant_cpu_to_le32(1 << 1) + +#define RX_RES_PHY_FLAGS_BAND_24_MSK __constant_cpu_to_le16(1 << 0) +#define RX_RES_PHY_FLAGS_MOD_CCK_MSK __constant_cpu_to_le16(1 << 1) +#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK __constant_cpu_to_le16(1 << 2) +#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK __constant_cpu_to_le16(1 << 3) +#define RX_RES_PHY_FLAGS_ANTENNA_MSK __constant_cpu_to_le16(0xf0) + +#define RX_RES_STATUS_SEC_TYPE_MSK (0x7 << 8) +#define RX_RES_STATUS_SEC_TYPE_NONE (0x0 << 8) +#define RX_RES_STATUS_SEC_TYPE_WEP (0x1 << 8) +#define RX_RES_STATUS_SEC_TYPE_CCMP (0x2 << 8) +#define RX_RES_STATUS_SEC_TYPE_TKIP (0x3 << 8) +#define RX_RES_STATUS_SEC_TYPE_ERR (0x7 << 8) + +#define RX_RES_STATUS_STATION_FOUND (1<<6) +#define RX_RES_STATUS_NO_STATION_INFO_MISMATCH (1<<7) + +#define RX_RES_STATUS_DECRYPT_TYPE_MSK (0x3 << 11) +#define RX_RES_STATUS_NOT_DECRYPT (0x0 << 11) +#define RX_RES_STATUS_DECRYPT_OK (0x3 << 11) +#define RX_RES_STATUS_BAD_ICV_MIC (0x1 << 11) +#define RX_RES_STATUS_BAD_KEY_TTAK (0x2 << 11) + +#define RX_MPDU_RES_STATUS_ICV_OK (0x20) +#define RX_MPDU_RES_STATUS_MIC_OK (0x40) +#define RX_MPDU_RES_STATUS_TTAK_OK (1 << 7) +#define RX_MPDU_RES_STATUS_DEC_DONE_MSK (0x800) + +struct iwl4965_rx_frame_end { + __le32 status; + __le64 timestamp; + __le32 beacon_timestamp; +} __attribute__ ((packed)); + +/* + * REPLY_3945_RX = 0x1b (response only, not a command) + * + * NOTE: DO NOT dereference from casts to this structure + * It is provided only for calculating minimum data set size. + * The actual offsets of the hdr and end are dynamic based on + * stats.phy_count + */ +struct iwl4965_rx_frame { + struct iwl4965_rx_frame_stats stats; + struct iwl4965_rx_frame_hdr hdr; + struct iwl4965_rx_frame_end end; +} __attribute__ ((packed)); + +/* Fixed (non-configurable) rx data from phy */ +#define RX_PHY_FLAGS_ANTENNAE_OFFSET (4) +#define RX_PHY_FLAGS_ANTENNAE_MASK (0x70) +#define IWL_AGC_DB_MASK (0x3f80) /* MASK(7,13) */ +#define IWL_AGC_DB_POS (7) +struct iwl4965_rx_non_cfg_phy { + __le16 ant_selection; /* ant A bit 4, ant B bit 5, ant C bit 6 */ + __le16 agc_info; /* agc code 0:6, agc dB 7:13, reserved 14:15 */ + u8 rssi_info[6]; /* we use even entries, 0/2/4 for A/B/C rssi */ + u8 pad[0]; +} __attribute__ ((packed)); + +/* + * REPLY_RX = 0xc3 (response only, not a command) + * Used only for legacy (non 11n) frames. + */ +#define RX_RES_PHY_CNT 14 +struct iwl4965_rx_phy_res { + u8 non_cfg_phy_cnt; /* non configurable DSP phy data byte count */ + u8 cfg_phy_cnt; /* configurable DSP phy data byte count */ + u8 stat_id; /* configurable DSP phy data set ID */ + u8 reserved1; + __le64 timestamp; /* TSF at on air rise */ + __le32 beacon_time_stamp; /* beacon at on-air rise */ + __le16 phy_flags; /* general phy flags: band, modulation, ... */ + __le16 channel; /* channel number */ + __le16 non_cfg_phy[RX_RES_PHY_CNT]; /* upto 14 phy entries */ + __le32 reserved2; + __le32 rate_n_flags; /* RATE_MCS_* */ + __le16 byte_count; /* frame's byte-count */ + __le16 reserved3; +} __attribute__ ((packed)); + +struct iwl4965_rx_mpdu_res_start { + __le16 byte_count; + __le16 reserved; +} __attribute__ ((packed)); + + +/****************************************************************************** + * (5) + * Tx Commands & Responses: + * + * Driver must place each REPLY_TX command into one of the prioritized Tx + * queues in host DRAM, shared between driver and device (see comments for + * SCD registers and Tx/Rx Queues). When the device's Tx scheduler and uCode + * are preparing to transmit, the device pulls the Tx command over the PCI + * bus via one of the device's Tx DMA channels, to fill an internal FIFO + * from which data will be transmitted. + * + * uCode handles all timing and protocol related to control frames + * (RTS/CTS/ACK), based on flags in the Tx command. uCode and Tx scheduler + * handle reception of block-acks; uCode updates the host driver via + * REPLY_COMPRESSED_BA (4965). + * + * 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 (4965). + * + * 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. + *****************************************************************************/ + +/* REPLY_TX Tx flags field */ + +/* 1: Use Request-To-Send protocol before this frame. + * Mutually exclusive vs. TX_CMD_FLG_CTS_MSK. */ +#define TX_CMD_FLG_RTS_MSK __constant_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. */ +#define TX_CMD_FLG_CTS_MSK __constant_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. */ +#define TX_CMD_FLG_ACK_MSK __constant_cpu_to_le32(1 << 3) + +/* For 4965: + * 1: Use rate scale table (see REPLY_TX_LINK_QUALITY_CMD). + * Tx command's initial_rate_index indicates first rate to try; + * uCode walks through table for additional Tx attempts. + * 0: Use Tx rate/MCS from Tx command's rate_n_flags field. + * This rate will be used for all Tx attempts; it will not be scaled. */ +#define TX_CMD_FLG_STA_RATE_MSK __constant_cpu_to_le32(1 << 4) + +/* 1: Expect immediate block-ack. + * Set when Txing a block-ack request frame. Also set TX_CMD_FLG_ACK_MSK. */ +#define TX_CMD_FLG_IMM_BA_RSP_MASK __constant_cpu_to_le32(1 << 6) + +/* 1: Frame requires full Tx-Op protection. + * Set this if either RTS or CTS Tx Flag gets set. */ +#define TX_CMD_FLG_FULL_TXOP_PROT_MSK __constant_cpu_to_le32(1 << 7) + +/* Tx antenna selection field; used only for 3945, reserved (0) for 4965. + * Set field to "0" to allow 3945 uCode to select antenna (normal usage). */ +#define TX_CMD_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0xf00) +#define TX_CMD_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8) +#define TX_CMD_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9) + +/* 1: Ignore Bluetooth priority for this frame. + * 0: Delay Tx until Bluetooth device is done (normal usage). */ +#define TX_CMD_FLG_BT_DIS_MSK __constant_cpu_to_le32(1 << 12) + +/* 1: uCode overrides sequence control field in MAC header. + * 0: Driver provides sequence control field in MAC header. + * Set this for management frames, non-QOS data frames, non-unicast frames, + * and also in Tx command embedded in REPLY_SCAN_CMD for active scans. */ +#define TX_CMD_FLG_SEQ_CTL_MSK __constant_cpu_to_le32(1 << 13) + +/* 1: This frame is non-last MPDU; more fragments are coming. + * 0: Last fragment, or not using fragmentation. */ +#define TX_CMD_FLG_MORE_FRAG_MSK __constant_cpu_to_le32(1 << 14) + +/* 1: uCode calculates and inserts Timestamp Function (TSF) in outgoing frame. + * 0: No TSF required in outgoing frame. + * Set this for transmitting beacons and probe responses. */ +#define TX_CMD_FLG_TSF_MSK __constant_cpu_to_le32(1 << 16) + +/* 1: Driver inserted 2 bytes pad after the MAC header, for (required) dword + * alignment of frame's payload data field. + * 0: No pad + * Set this for MAC headers with 26 or 30 bytes, i.e. those with QOS or ADDR4 + * field (but not both). Driver must align frame data (i.e. data following + * MAC header) to DWORD boundary. */ +#define TX_CMD_FLG_MH_PAD_MSK __constant_cpu_to_le32(1 << 20) + +/* accelerate aggregation support + * 0 - no CCMP encryption; 1 - CCMP encryption */ +#define TX_CMD_FLG_AGG_CCMP_MSK __constant_cpu_to_le32(1 << 22) + +/* HCCA-AP - disable duration overwriting. */ +#define TX_CMD_FLG_DUR_MSK __constant_cpu_to_le32(1 << 25) + + +/* + * TX command security control + */ +#define TX_CMD_SEC_WEP 0x01 +#define TX_CMD_SEC_CCM 0x02 +#define TX_CMD_SEC_TKIP 0x03 +#define TX_CMD_SEC_MSK 0x03 +#define TX_CMD_SEC_SHIFT 6 +#define TX_CMD_SEC_KEY128 0x08 + +/* + * security overhead sizes + */ +#define WEP_IV_LEN 4 +#define WEP_ICV_LEN 4 +#define CCMP_MIC_LEN 8 +#define TKIP_ICV_LEN 4 + +/* + * 4965 uCode updates these Tx attempt count values in host DRAM. + * Used for managing Tx retries when expecting block-acks. + * Driver should set these fields to 0. + */ +struct iwl4965_dram_scratch { + u8 try_cnt; /* Tx attempts */ + u8 bt_kill_cnt; /* Tx attempts blocked by Bluetooth device */ + __le16 reserved; +} __attribute__ ((packed)); + +/* + * REPLY_TX = 0x1c (command) + */ +struct iwl4965_tx_cmd { + /* + * MPDU byte count: + * MAC header (24/26/30/32 bytes) + 2 bytes pad if 26/30 header size, + * + 8 byte IV for CCM or TKIP (not used for WEP) + * + Data payload + * + 8-byte MIC (not used for CCM/WEP) + * NOTE: Does not include Tx command bytes, post-MAC pad bytes, + * MIC (CCM) 8 bytes, ICV (WEP/TKIP/CKIP) 4 bytes, CRC 4 bytes.i + * Range: 14-2342 bytes. + */ + __le16 len; + + /* + * MPDU or MSDU byte count for next frame. + * Used for fragmentation and bursting, but not 11n aggregation. + * Same as "len", but for next frame. Set to 0 if not applicable. + */ + __le16 next_frame_len; + + __le32 tx_flags; /* TX_CMD_FLG_* */ + + /* 4965's uCode may modify this field of the Tx command (in host DRAM!). + * Driver must also set dram_lsb_ptr and dram_msb_ptr in this cmd. */ + struct iwl4965_dram_scratch scratch; + + /* Rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is cleared. */ + __le32 rate_n_flags; /* RATE_MCS_* */ + + /* Index of destination station in uCode's station table */ + u8 sta_id; + + /* Type of security encryption: CCM or TKIP */ + u8 sec_ctl; /* TX_CMD_SEC_* */ + + /* + * Index into rate table (see REPLY_TX_LINK_QUALITY_CMD) for initial + * Tx attempt, if TX_CMD_FLG_STA_RATE_MSK is set. Normally "0" for + * data frames, this field may be used to selectively reduce initial + * rate (via non-0 value) for special frames (e.g. management), while + * still supporting rate scaling for all frames. + */ + u8 initial_rate_index; + u8 reserved; + u8 key[16]; + __le16 next_frame_flags; + __le16 reserved2; + union { + __le32 life_time; + __le32 attempt; + } stop_time; + + /* Host DRAM physical address pointer to "scratch" in this command. + * Must be dword aligned. "0" in dram_lsb_ptr disables usage. */ + __le32 dram_lsb_ptr; + u8 dram_msb_ptr; + + u8 rts_retry_limit; /*byte 50 */ + u8 data_retry_limit; /*byte 51 */ + u8 tid_tspec; + union { + __le16 pm_frame_timeout; + __le16 attempt_duration; + } timeout; + + /* + * Duration of EDCA burst Tx Opportunity, in 32-usec units. + * Set this if txop time is not specified by HCCA protocol (e.g. by AP). + */ + __le16 driver_txop; + + /* + * MAC header goes here, followed by 2 bytes padding if MAC header + * length is 26 or 30 bytes, followed by payload data + */ + u8 payload[0]; + struct ieee80211_hdr hdr[0]; +} __attribute__ ((packed)); + +/* TX command response is sent after *all* transmission attempts. + * + * NOTES: + * + * TX_STATUS_FAIL_NEXT_FRAG + * + * If the fragment flag in the MAC header for the frame being transmitted + * is set and there is insufficient time to transmit the next frame, the + * TX status will be returned with 'TX_STATUS_FAIL_NEXT_FRAG'. + * + * TX_STATUS_FIFO_UNDERRUN + * + * Indicates the host did not provide bytes to the FIFO fast enough while + * a TX was in progress. + * + * TX_STATUS_FAIL_MGMNT_ABORT + * + * This status is only possible if the ABORT ON MGMT RX parameter was + * set to true with the TX command. + * + * If the MSB of the status parameter is set then an abort sequence is + * required. This sequence consists of the host activating the TX Abort + * control line, and then waiting for the TX Abort command response. This + * indicates that a the device is no longer in a transmit state, and that the + * command FIFO has been cleared. The host must then deactivate the TX Abort + * control line. Receiving is still allowed in this case. + */ +enum { + TX_STATUS_SUCCESS = 0x01, + TX_STATUS_DIRECT_DONE = 0x02, + TX_STATUS_FAIL_SHORT_LIMIT = 0x82, + TX_STATUS_FAIL_LONG_LIMIT = 0x83, + TX_STATUS_FAIL_FIFO_UNDERRUN = 0x84, + TX_STATUS_FAIL_MGMNT_ABORT = 0x85, + TX_STATUS_FAIL_NEXT_FRAG = 0x86, + TX_STATUS_FAIL_LIFE_EXPIRE = 0x87, + TX_STATUS_FAIL_DEST_PS = 0x88, + TX_STATUS_FAIL_ABORTED = 0x89, + TX_STATUS_FAIL_BT_RETRY = 0x8a, + TX_STATUS_FAIL_STA_INVALID = 0x8b, + TX_STATUS_FAIL_FRAG_DROPPED = 0x8c, + TX_STATUS_FAIL_TID_DISABLE = 0x8d, + TX_STATUS_FAIL_FRAME_FLUSHED = 0x8e, + TX_STATUS_FAIL_INSUFFICIENT_CF_POLL = 0x8f, + TX_STATUS_FAIL_TX_LOCKED = 0x90, + TX_STATUS_FAIL_NO_BEACON_ON_RADAR = 0x91, +}; + +#define TX_PACKET_MODE_REGULAR 0x0000 +#define TX_PACKET_MODE_BURST_SEQ 0x0100 +#define TX_PACKET_MODE_BURST_FIRST 0x0200 + +enum { + TX_POWER_PA_NOT_ACTIVE = 0x0, +}; + +enum { + TX_STATUS_MSK = 0x000000ff, /* bits 0:7 */ + TX_STATUS_DELAY_MSK = 0x00000040, + TX_STATUS_ABORT_MSK = 0x00000080, + TX_PACKET_MODE_MSK = 0x0000ff00, /* bits 8:15 */ + TX_FIFO_NUMBER_MSK = 0x00070000, /* bits 16:18 */ + TX_RESERVED = 0x00780000, /* bits 19:22 */ + TX_POWER_PA_DETECT_MSK = 0x7f800000, /* bits 23:30 */ + TX_ABORT_REQUIRED_MSK = 0x80000000, /* bits 31:31 */ +}; + +/* ******************************* + * TX aggregation status + ******************************* */ + +enum { + AGG_TX_STATE_TRANSMITTED = 0x00, + AGG_TX_STATE_UNDERRUN_MSK = 0x01, + AGG_TX_STATE_BT_PRIO_MSK = 0x02, + AGG_TX_STATE_FEW_BYTES_MSK = 0x04, + AGG_TX_STATE_ABORT_MSK = 0x08, + AGG_TX_STATE_LAST_SENT_TTL_MSK = 0x10, + AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK = 0x20, + AGG_TX_STATE_LAST_SENT_BT_KILL_MSK = 0x40, + AGG_TX_STATE_SCD_QUERY_MSK = 0x80, + AGG_TX_STATE_TEST_BAD_CRC32_MSK = 0x100, + AGG_TX_STATE_RESPONSE_MSK = 0x1ff, + AGG_TX_STATE_DUMP_TX_MSK = 0x200, + AGG_TX_STATE_DELAY_TX_MSK = 0x400 +}; + +#define AGG_TX_STATE_LAST_SENT_MSK \ +(AGG_TX_STATE_LAST_SENT_TTL_MSK | \ + AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK | \ + AGG_TX_STATE_LAST_SENT_BT_KILL_MSK) + +/* # tx attempts for first frame in aggregation */ +#define AGG_TX_STATE_TRY_CNT_POS 12 +#define AGG_TX_STATE_TRY_CNT_MSK 0xf000 + +/* Command ID and sequence number of Tx command for this frame */ +#define AGG_TX_STATE_SEQ_NUM_POS 16 +#define AGG_TX_STATE_SEQ_NUM_MSK 0xffff0000 + +/* + * REPLY_TX = 0x1c (response) + * + * This response may be in one of two slightly different formats, indicated + * by the frame_count field: + * + * 1) No aggregation (frame_count == 1). This reports Tx results for + * a single frame. Multiple attempts, at various bit rates, may have + * been made for this frame. + * + * 2) Aggregation (frame_count > 1). This reports Tx results for + * 2 or more frames that used block-acknowledge. All frames were + * transmitted at same rate. Rate scaling may have been used if first + * frame in this new agg block failed in previous agg block(s). + * + * Note that, for aggregation, ACK (block-ack) status is not delivered here; + * block-ack has not been received by the time the 4965 records this status. + * This status relates to reasons the tx might have been blocked or aborted + * within the sending station (this 4965), rather than whether it was + * received successfully by the destination station. + */ +struct iwl4965_tx_resp { + u8 frame_count; /* 1 no aggregation, >1 aggregation */ + u8 bt_kill_count; /* # blocked by bluetooth (unused for agg) */ + u8 failure_rts; /* # failures due to unsuccessful RTS */ + u8 failure_frame; /* # failures due to no ACK (unused for agg) */ + + /* For non-agg: Rate at which frame was successful. + * For agg: Rate at which all frames were transmitted. */ + __le32 rate_n_flags; /* RATE_MCS_* */ + + /* For non-agg: RTS + CTS + frame tx attempts time + ACK. + * For agg: RTS + CTS + aggregation tx time + block-ack time. */ + __le16 wireless_media_time; /* uSecs */ + + __le16 reserved; + __le32 pa_power1; /* RF power amplifier measurement (not used) */ + __le32 pa_power2; + + /* + * For non-agg: frame status TX_STATUS_* + * For agg: status of 1st frame, AGG_TX_STATE_*; other frame status + * fields follow this one, up to frame_count. + * Bit fields: + * 11- 0: AGG_TX_STATE_* status code + * 15-12: Retry count for 1st frame in aggregation (retries + * occur if tx failed for this frame when it was a + * member of a previous aggregation block). If rate + * scaling is used, retry count indicates the rate + * table entry used for all frames in the new agg. + * 31-16: Sequence # for this frame's Tx cmd (not SSN!) + */ + __le32 status; /* TX status (for aggregation status of 1st frame) */ +} __attribute__ ((packed)); + +struct agg_tx_status { + __le16 status; + __le16 sequence; +} __attribute__ ((packed)); + +struct iwl4965_tx_resp_agg { + u8 frame_count; /* 1 no aggregation, >1 aggregation */ + u8 reserved1; + u8 failure_rts; + u8 failure_frame; + __le32 rate_n_flags; + __le16 wireless_media_time; + __le16 reserved3; + __le32 pa_power1; + __le32 pa_power2; + struct agg_tx_status status; /* TX status (for aggregation status */ + /* of 1st frame) */ +} __attribute__ ((packed)); + +/* + * REPLY_COMPRESSED_BA = 0xc5 (response only, not a command) + * + * Reports Block-Acknowledge from recipient station + */ +struct iwl4965_compressed_ba_resp { + __le32 sta_addr_lo32; + __le16 sta_addr_hi16; + __le16 reserved; + + /* Index of recipient (BA-sending) station in uCode's station table */ + u8 sta_id; + u8 tid; + __le16 seq_ctl; + __le64 bitmap; + __le16 scd_flow; + __le16 scd_ssn; +} __attribute__ ((packed)); + +/* + * REPLY_TX_PWR_TABLE_CMD = 0x97 (command, has simple generic response) + * + * See details under "TXPOWER" in iwl-4965-hw.h. + */ +struct iwl4965_txpowertable_cmd { + u8 band; /* 0: 5 GHz, 1: 2.4 GHz */ + u8 reserved; + __le16 channel; + struct iwl4965_tx_power_db tx_power; +} __attribute__ ((packed)); + +/*RS_NEW_API: only TLC_RTS remains and moved to bit 0 */ +#define LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK (1 << 0) + +/* # of EDCA prioritized tx fifos */ +#define LINK_QUAL_AC_NUM AC_NUM + +/* # entries in rate scale table to support Tx retries */ +#define LINK_QUAL_MAX_RETRY_NUM 16 + +/* Tx antenna selection values */ +#define LINK_QUAL_ANT_A_MSK (1 << 0) +#define LINK_QUAL_ANT_B_MSK (1 << 1) +#define LINK_QUAL_ANT_MSK (LINK_QUAL_ANT_A_MSK|LINK_QUAL_ANT_B_MSK) + + +/** + * struct iwl_link_qual_general_params + * + * Used in REPLY_TX_LINK_QUALITY_CMD + */ +struct iwl_link_qual_general_params { + u8 flags; + + /* No entries at or above this (driver chosen) index contain MIMO */ + u8 mimo_delimiter; + + /* Best single antenna to use for single stream (legacy, SISO). */ + u8 single_stream_ant_msk; /* LINK_QUAL_ANT_* */ + + /* Best antennas to use for MIMO (unused for 4965, assumes both). */ + u8 dual_stream_ant_msk; /* LINK_QUAL_ANT_* */ + + /* + * If driver needs to use different initial rates for different + * EDCA QOS access categories (as implemented by tx fifos 0-3), + * this table will set that up, by indicating the indexes in the + * rs_table[LINK_QUAL_MAX_RETRY_NUM] rate table at which to start. + * Otherwise, driver should set all entries to 0. + * + * Entry usage: + * 0 = Background, 1 = Best Effort (normal), 2 = Video, 3 = Voice + * TX FIFOs above 3 use same value (typically 0) as TX FIFO 3. + */ + u8 start_rate_index[LINK_QUAL_AC_NUM]; +} __attribute__ ((packed)); + +/** + * struct iwl_link_qual_agg_params + * + * Used in REPLY_TX_LINK_QUALITY_CMD + */ +struct iwl_link_qual_agg_params { + + /* Maximum number of uSec in aggregation. + * Driver should set this to 4000 (4 milliseconds). */ + __le16 agg_time_limit; + + /* + * Number of Tx retries allowed for a frame, before that frame will + * no longer be considered for the start of an aggregation sequence + * (scheduler will then try to tx it as single frame). + * Driver should set this to 3. + */ + u8 agg_dis_start_th; + + /* + * Maximum number of frames in aggregation. + * 0 = no limit (default). 1 = no aggregation. + * Other values = max # frames in aggregation. + */ + u8 agg_frame_cnt_limit; + + __le32 reserved; +} __attribute__ ((packed)); + +/* + * REPLY_TX_LINK_QUALITY_CMD = 0x4e (command, has simple generic response) + * + * For 4965 only; 3945 uses REPLY_RATE_SCALE. + * + * Each station in the 4965's internal station table has its own table of 16 + * Tx rates and modulation modes (e.g. legacy/SISO/MIMO) for retrying Tx when + * an ACK is not received. This command replaces the entire table for + * one station. + * + * NOTE: Station must already be in 4965's station table. Use REPLY_ADD_STA. + * + * The rate scaling procedures described below work well. Of course, other + * procedures are possible, and may work better for particular environments. + * + * + * FILLING THE RATE TABLE + * + * Given a particular initial rate and mode, as determined by the rate + * scaling algorithm described below, the Linux driver uses the following + * formula to fill the rs_table[LINK_QUAL_MAX_RETRY_NUM] rate table in the + * Link Quality command: + * + * + * 1) If using High-throughput (HT) (SISO or MIMO) initial rate: + * a) Use this same initial rate for first 3 entries. + * b) Find next lower available rate using same mode (SISO or MIMO), + * use for next 3 entries. If no lower rate available, switch to + * legacy mode (no FAT channel, no MIMO, no short guard interval). + * c) If using MIMO, set command's mimo_delimiter to number of entries + * using MIMO (3 or 6). + * d) After trying 2 HT rates, switch to legacy mode (no FAT channel, + * no MIMO, no short guard interval), at the next lower bit rate + * (e.g. if second HT bit rate was 54, try 48 legacy), and follow + * legacy procedure for remaining table entries. + * + * 2) If using legacy initial rate: + * a) Use the initial rate for only one entry. + * b) For each following entry, reduce the rate to next lower available + * rate, until reaching the lowest available rate. + * c) When reducing rate, also switch antenna selection. + * d) Once lowest available rate is reached, repeat this rate until + * rate table is filled (16 entries), switching antenna each entry. + * + * + * ACCUMULATING HISTORY + * + * The rate scaling algorithm for 4965, as implemented in Linux driver, uses + * two sets of frame Tx success history: One for the current/active modulation + * mode, and one for a speculative/search mode that is being attempted. If the + * speculative mode turns out to be more effective (i.e. actual transfer + * rate is better), then the driver continues to use the speculative mode + * as the new current active mode. + * + * Each history set contains, separately for each possible rate, data for a + * sliding window of the 62 most recent tx attempts at that rate. The data + * includes a shifting bitmap of success(1)/failure(0), and sums of successful + * and attempted frames, from which the driver can additionally calculate a + * success ratio (success / attempted) and number of failures + * (attempted - success), and control the size of the window (attempted). + * The driver uses the bit map to remove successes from the success sum, as + * the oldest tx attempts fall out of the window. + * + * When the 4965 makes multiple tx attempts for a given frame, each attempt + * might be at a different rate, and have different modulation characteristics + * (e.g. antenna, fat channel, short guard interval), as set up in the rate + * scaling table in the Link Quality command. The driver must determine + * which rate table entry was used for each tx attempt, to determine which + * rate-specific history to update, and record only those attempts that + * match the modulation characteristics of the history set. + * + * When using block-ack (aggregation), all frames are transmitted at the same + * rate, since there is no per-attempt acknowledgement from the destination + * station. The Tx response struct iwl_tx_resp indicates the Tx rate in + * rate_n_flags field. After receiving a block-ack, the driver can update + * history for the entire block all at once. + * + * + * FINDING BEST STARTING RATE: + * + * When working with a selected initial modulation mode (see below), the + * driver attempts to find a best initial rate. The initial rate is the + * first entry in the Link Quality command's rate table. + * + * 1) Calculate actual throughput (success ratio * expected throughput, see + * table below) for current initial rate. Do this only if enough frames + * have been attempted to make the value meaningful: at least 6 failed + * tx attempts, or at least 8 successes. If not enough, don't try rate + * scaling yet. + * + * 2) Find available rates adjacent to current initial rate. Available means: + * a) supported by hardware && + * b) supported by association && + * c) within any constraints selected by user + * + * 3) Gather measured throughputs for adjacent rates. These might not have + * enough history to calculate a throughput. That's okay, we might try + * using one of them anyway! + * + * 4) Try decreasing rate if, for current rate: + * a) success ratio is < 15% || + * b) lower adjacent rate has better measured throughput || + * c) higher adjacent rate has worse throughput, and lower is unmeasured + * + * As a sanity check, if decrease was determined above, leave rate + * unchanged if: + * a) lower rate unavailable + * b) success ratio at current rate > 85% (very good) + * c) current measured throughput is better than expected throughput + * of lower rate (under perfect 100% tx conditions, see table below) + * + * 5) Try increasing rate if, for current rate: + * a) success ratio is < 15% || + * b) both adjacent rates' throughputs are unmeasured (try it!) || + * b) higher adjacent rate has better measured throughput || + * c) lower adjacent rate has worse throughput, and higher is unmeasured + * + * As a sanity check, if increase was determined above, leave rate + * unchanged if: + * a) success ratio at current rate < 70%. This is not particularly + * good performance; higher rate is sure to have poorer success. + * + * 6) Re-evaluate the rate after each tx frame. If working with block- + * acknowledge, history and statistics may be calculated for the entire + * block (including prior history that fits within the history windows), + * before re-evaluation. + * + * FINDING BEST STARTING MODULATION MODE: + * + * After working with a modulation mode for a "while" (and doing rate scaling), + * the driver searches for a new initial mode in an attempt to improve + * throughput. The "while" is measured by numbers of attempted frames: + * + * For legacy mode, search for new mode after: + * 480 successful frames, or 160 failed frames + * For high-throughput modes (SISO or MIMO), search for new mode after: + * 4500 successful frames, or 400 failed frames + * + * Mode switch possibilities are (3 for each mode): + * + * For legacy: + * Change antenna, try SISO (if HT association), try MIMO (if HT association) + * For SISO: + * Change antenna, try MIMO, try shortened guard interval (SGI) + * For MIMO: + * Try SISO antenna A, SISO antenna B, try shortened guard interval (SGI) + * + * When trying a new mode, use the same bit rate as the old/current mode when + * trying antenna switches and shortened guard interval. When switching to + * SISO from MIMO or legacy, or to MIMO from SISO or legacy, use a rate + * for which the expected throughput (under perfect conditions) is about the + * same or slightly better than the actual measured throughput delivered by + * the old/current mode. + * + * Actual throughput can be estimated by multiplying the expected throughput + * by the success ratio (successful / attempted tx frames). Frame size is + * not considered in this calculation; it assumes that frame size will average + * out to be fairly consistent over several samples. The following are + * metric values for expected throughput assuming 100% success ratio. + * Only G band has support for CCK rates: + * + * RATE: 1 2 5 11 6 9 12 18 24 36 48 54 60 + * + * G: 7 13 35 58 40 57 72 98 121 154 177 186 186 + * A: 0 0 0 0 40 57 72 98 121 154 177 186 186 + * SISO 20MHz: 0 0 0 0 42 42 76 102 124 159 183 193 202 + * SGI SISO 20MHz: 0 0 0 0 46 46 82 110 132 168 192 202 211 + * MIMO 20MHz: 0 0 0 0 74 74 123 155 179 214 236 244 251 + * SGI MIMO 20MHz: 0 0 0 0 81 81 131 164 188 222 243 251 257 + * SISO 40MHz: 0 0 0 0 77 77 127 160 184 220 242 250 257 + * SGI SISO 40MHz: 0 0 0 0 83 83 135 169 193 229 250 257 264 + * MIMO 40MHz: 0 0 0 0 123 123 182 214 235 264 279 285 289 + * SGI MIMO 40MHz: 0 0 0 0 131 131 191 222 242 270 284 289 293 + * + * After the new mode has been tried for a short while (minimum of 6 failed + * frames or 8 successful frames), compare success ratio and actual throughput + * estimate of the new mode with the old. If either is better with the new + * mode, continue to use the new mode. + * + * Continue comparing modes until all 3 possibilities have been tried. + * If moving from legacy to HT, try all 3 possibilities from the new HT + * mode. After trying all 3, a best mode is found. Continue to use this mode + * for the longer "while" described above (e.g. 480 successful frames for + * legacy), and then repeat the search process. + * + */ +struct iwl_link_quality_cmd { + + /* Index of destination/recipient station in uCode's station table */ + u8 sta_id; + u8 reserved1; + __le16 control; /* not used */ + struct iwl_link_qual_general_params general_params; + struct iwl_link_qual_agg_params agg_params; + + /* + * Rate info; when using rate-scaling, Tx command's initial_rate_index + * specifies 1st Tx rate attempted, via index into this table. + * 4965 works its way through table when retrying Tx. + */ + struct { + __le32 rate_n_flags; /* RATE_MCS_*, IWL_RATE_* */ + } rs_table[LINK_QUAL_MAX_RETRY_NUM]; + __le32 reserved2; +} __attribute__ ((packed)); + +/* + * REPLY_BT_CONFIG = 0x9b (command, has simple generic response) + * + * 3945 and 4965 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 accomodate. + */ +struct iwl4965_bt_cmd { + u8 flags; + u8 lead_time; + u8 max_kill; + u8 reserved; + __le32 kill_ack_mask; + __le32 kill_cts_mask; +} __attribute__ ((packed)); + +/****************************************************************************** + * (6) + * Spectrum Management (802.11h) Commands, Responses, Notifications: + * + *****************************************************************************/ + +/* + * Spectrum Management + */ +#define MEASUREMENT_FILTER_FLAG (RXON_FILTER_PROMISC_MSK | \ + RXON_FILTER_CTL2HOST_MSK | \ + RXON_FILTER_ACCEPT_GRP_MSK | \ + RXON_FILTER_DIS_DECRYPT_MSK | \ + RXON_FILTER_DIS_GRP_DECRYPT_MSK | \ + RXON_FILTER_ASSOC_MSK | \ + RXON_FILTER_BCON_AWARE_MSK) + +struct iwl4965_measure_channel { + __le32 duration; /* measurement duration in extended beacon + * format */ + u8 channel; /* channel to measure */ + u8 type; /* see enum iwl4965_measure_type */ + __le16 reserved; +} __attribute__ ((packed)); + +/* + * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (command) + */ +struct iwl4965_spectrum_cmd { + __le16 len; /* number of bytes starting from token */ + u8 token; /* token id */ + u8 id; /* measurement id -- 0 or 1 */ + u8 origin; /* 0 = TGh, 1 = other, 2 = TGk */ + u8 periodic; /* 1 = periodic */ + __le16 path_loss_timeout; + __le32 start_time; /* start time in extended beacon format */ + __le32 reserved2; + __le32 flags; /* rxon flags */ + __le32 filter_flags; /* rxon filter flags */ + __le16 channel_count; /* minimum 1, maximum 10 */ + __le16 reserved3; + struct iwl4965_measure_channel channels[10]; +} __attribute__ ((packed)); + +/* + * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (response) + */ +struct iwl4965_spectrum_resp { + u8 token; + u8 id; /* id of the prior command replaced, or 0xff */ + __le16 status; /* 0 - command will be handled + * 1 - cannot handle (conflicts with another + * measurement) */ +} __attribute__ ((packed)); + +enum iwl4965_measurement_state { + IWL_MEASUREMENT_START = 0, + IWL_MEASUREMENT_STOP = 1, +}; + +enum iwl4965_measurement_status { + IWL_MEASUREMENT_OK = 0, + IWL_MEASUREMENT_CONCURRENT = 1, + IWL_MEASUREMENT_CSA_CONFLICT = 2, + IWL_MEASUREMENT_TGH_CONFLICT = 3, + /* 4-5 reserved */ + IWL_MEASUREMENT_STOPPED = 6, + IWL_MEASUREMENT_TIMEOUT = 7, + IWL_MEASUREMENT_PERIODIC_FAILED = 8, +}; + +#define NUM_ELEMENTS_IN_HISTOGRAM 8 + +struct iwl4965_measurement_histogram { + __le32 ofdm[NUM_ELEMENTS_IN_HISTOGRAM]; /* in 0.8usec counts */ + __le32 cck[NUM_ELEMENTS_IN_HISTOGRAM]; /* in 1usec counts */ +} __attribute__ ((packed)); + +/* clear channel availability counters */ +struct iwl4965_measurement_cca_counters { + __le32 ofdm; + __le32 cck; +} __attribute__ ((packed)); + +enum iwl4965_measure_type { + IWL_MEASURE_BASIC = (1 << 0), + IWL_MEASURE_CHANNEL_LOAD = (1 << 1), + IWL_MEASURE_HISTOGRAM_RPI = (1 << 2), + IWL_MEASURE_HISTOGRAM_NOISE = (1 << 3), + IWL_MEASURE_FRAME = (1 << 4), + /* bits 5:6 are reserved */ + IWL_MEASURE_IDLE = (1 << 7), +}; + +/* + * SPECTRUM_MEASURE_NOTIFICATION = 0x75 (notification only, not a command) + */ +struct iwl4965_spectrum_notification { + u8 id; /* measurement id -- 0 or 1 */ + u8 token; + u8 channel_index; /* index in measurement channel list */ + u8 state; /* 0 - start, 1 - stop */ + __le32 start_time; /* lower 32-bits of TSF */ + u8 band; /* 0 - 5.2GHz, 1 - 2.4GHz */ + u8 channel; + u8 type; /* see enum iwl4965_measurement_type */ + u8 reserved1; + /* NOTE: cca_ofdm, cca_cck, basic_type, and histogram are only only + * valid if applicable for measurement type requested. */ + __le32 cca_ofdm; /* cca fraction time in 40Mhz clock periods */ + __le32 cca_cck; /* cca fraction time in 44Mhz clock periods */ + __le32 cca_time; /* channel load time in usecs */ + u8 basic_type; /* 0 - bss, 1 - ofdm preamble, 2 - + * unidentified */ + u8 reserved2[3]; + struct iwl4965_measurement_histogram histogram; + __le32 stop_time; /* lower 32-bits of TSF */ + __le32 status; /* see iwl4965_measurement_status */ +} __attribute__ ((packed)); + +/****************************************************************************** + * (7) + * Power Management Commands, Responses, Notifications: + * + *****************************************************************************/ + +/** + * struct iwl4965_powertable_cmd - Power Table Command + * @flags: See below: + * + * POWER_TABLE_CMD = 0x77 (command, has simple generic response) + * + * PM allow: + * bit 0 - '0' Driver not allow power management + * '1' Driver allow PM (use rest of parameters) + * uCode send sleep notifications: + * bit 1 - '0' Don't send sleep notification + * '1' send sleep notification (SEND_PM_NOTIFICATION) + * Sleep over DTIM + * bit 2 - '0' PM have to walk up every DTIM + * '1' PM could sleep over DTIM till listen Interval. + * PCI power managed + * bit 3 - '0' (PCI_LINK_CTRL & 0x1) + * '1' !(PCI_LINK_CTRL & 0x1) + * Force sleep Modes + * bit 31/30- '00' use both mac/xtal sleeps + * '01' force Mac sleep + * '10' force xtal sleep + * '11' Illegal set + * + * NOTE: if sleep_interval[SLEEP_INTRVL_TABLE_SIZE-1] > DTIM period then + * ucode assume sleep over DTIM is allowed and we don't need to wakeup + * for every DTIM. + */ +#define IWL_POWER_VEC_SIZE 5 + +#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK __constant_cpu_to_le16(1 << 0) +#define IWL_POWER_SLEEP_OVER_DTIM_MSK __constant_cpu_to_le16(1 << 2) +#define IWL_POWER_PCI_PM_MSK __constant_cpu_to_le16(1 << 3) +#define IWL_POWER_FAST_PD __constant_cpu_to_le16(1 << 4) + +struct iwl4965_powertable_cmd { + __le16 flags; + u8 keep_alive_seconds; + u8 debug_flags; + __le32 rx_data_timeout; + __le32 tx_data_timeout; + __le32 sleep_interval[IWL_POWER_VEC_SIZE]; + __le32 keep_alive_beacons; +} __attribute__ ((packed)); + +/* + * PM_SLEEP_NOTIFICATION = 0x7A (notification only, not a command) + * 3945 and 4965 identical. + */ +struct iwl4965_sleep_notification { + u8 pm_sleep_mode; + u8 pm_wakeup_src; + __le16 reserved; + __le32 sleep_time; + __le32 tsf_low; + __le32 bcon_timer; +} __attribute__ ((packed)); + +/* Sleep states. 3945 and 4965 identical. */ +enum { + IWL_PM_NO_SLEEP = 0, + IWL_PM_SLP_MAC = 1, + IWL_PM_SLP_FULL_MAC_UNASSOCIATE = 2, + IWL_PM_SLP_FULL_MAC_CARD_STATE = 3, + IWL_PM_SLP_PHY = 4, + IWL_PM_SLP_REPENT = 5, + IWL_PM_WAKEUP_BY_TIMER = 6, + IWL_PM_WAKEUP_BY_DRIVER = 7, + IWL_PM_WAKEUP_BY_RFKILL = 8, + /* 3 reserved */ + IWL_PM_NUM_OF_MODES = 12, +}; + +/* + * REPLY_CARD_STATE_CMD = 0xa0 (command, has simple generic response) + */ +#define CARD_STATE_CMD_DISABLE 0x00 /* Put card to sleep */ +#define CARD_STATE_CMD_ENABLE 0x01 /* Wake up card */ +#define CARD_STATE_CMD_HALT 0x02 /* Power down permanently */ +struct iwl4965_card_state_cmd { + __le32 status; /* CARD_STATE_CMD_* request new power state */ +} __attribute__ ((packed)); + +/* + * CARD_STATE_NOTIFICATION = 0xa1 (notification only, not a command) + */ +struct iwl4965_card_state_notif { + __le32 flags; +} __attribute__ ((packed)); + +#define HW_CARD_DISABLED 0x01 +#define SW_CARD_DISABLED 0x02 +#define RF_CARD_DISABLED 0x04 +#define RXON_CARD_DISABLED 0x10 + +struct iwl4965_ct_kill_config { + __le32 reserved; + __le32 critical_temperature_M; + __le32 critical_temperature_R; +} __attribute__ ((packed)); + +/****************************************************************************** + * (8) + * Scan Commands, Responses, Notifications: + * + *****************************************************************************/ + +/** + * struct iwl4965_scan_channel - entry in REPLY_SCAN_CMD channel table + * + * One for each channel in the scan list. + * Each channel can independently select: + * 1) SSID for directed active scans + * 2) Txpower setting (for rate specified within Tx command) + * 3) How long to stay on-channel (behavior may be modified by quiet_time, + * quiet_plcp_th, good_CRC_th) + * + * To avoid uCode errors, make sure the following are true (see comments + * under struct iwl4965_scan_cmd about max_out_time and quiet_time): + * 1) If using passive_dwell (i.e. passive_dwell != 0): + * active_dwell <= passive_dwell (< max_out_time if max_out_time != 0) + * 2) quiet_time <= active_dwell + * 3) If restricting off-channel time (i.e. max_out_time !=0): + * passive_dwell < max_out_time + * active_dwell < max_out_time + */ +struct iwl4965_scan_channel { + /* + * type is defined as: + * 0:0 1 = active, 0 = passive + * 1:4 SSID direct bit map; if a bit is set, then corresponding + * SSID IE is transmitted in probe request. + * 5:7 reserved + */ + u8 type; + u8 channel; /* band is selected by iwl4965_scan_cmd "flags" field */ + struct iwl4965_tx_power tpc; + __le16 active_dwell; /* in 1024-uSec TU (time units), typ 5-50 */ + __le16 passive_dwell; /* in 1024-uSec TU (time units), typ 20-500 */ +} __attribute__ ((packed)); + +/** + * struct iwl4965_ssid_ie - directed scan network information element + * + * Up to 4 of these may appear in REPLY_SCAN_CMD, selected by "type" field + * in struct iwl4965_scan_channel; each channel may select different ssids from + * among the 4 entries. SSID IEs get transmitted in reverse order of entry. + */ +struct iwl4965_ssid_ie { + u8 id; + u8 len; + u8 ssid[32]; +} __attribute__ ((packed)); + +#define PROBE_OPTION_MAX 0x4 +#define TX_CMD_LIFE_TIME_INFINITE __constant_cpu_to_le32(0xFFFFFFFF) +#define IWL_GOOD_CRC_TH __constant_cpu_to_le16(1) +#define IWL_MAX_SCAN_SIZE 1024 + +/* + * REPLY_SCAN_CMD = 0x80 (command) + * + * The hardware scan command is very powerful; the driver can set it up to + * maintain (relatively) normal network traffic while doing a scan in the + * background. The max_out_time and suspend_time control the ratio of how + * long the device stays on an associated network channel ("service channel") + * vs. how long it's away from the service channel, i.e. tuned to other channels + * for scanning. + * + * max_out_time is the max time off-channel (in usec), and suspend_time + * is how long (in "extended beacon" format) that the scan is "suspended" + * after returning to the service channel. That is, suspend_time is the + * time that we stay on the service channel, doing normal work, between + * scan segments. The driver may set these parameters differently to support + * scanning when associated vs. not associated, and light vs. heavy traffic + * loads when associated. + * + * After receiving this command, the device's scan engine does the following; + * + * 1) Sends SCAN_START notification to driver + * 2) Checks to see if it has time to do scan for one channel + * 3) Sends NULL packet, with power-save (PS) bit set to 1, + * to tell AP that we're going off-channel + * 4) Tunes to first channel in scan list, does active or passive scan + * 5) Sends SCAN_RESULT notification to driver + * 6) Checks to see if it has time to do scan on *next* channel in list + * 7) Repeats 4-6 until it no longer has time to scan the next channel + * before max_out_time expires + * 8) Returns to service channel + * 9) Sends NULL packet with PS=0 to tell AP that we're back + * 10) Stays on service channel until suspend_time expires + * 11) Repeats entire process 2-10 until list is complete + * 12) Sends SCAN_COMPLETE notification + * + * For fast, efficient scans, the scan command also has support for staying on + * a channel for just a short time, if doing active scanning and getting no + * responses to the transmitted probe request. This time is controlled by + * quiet_time, and the number of received packets below which a channel is + * considered "quiet" is controlled by quiet_plcp_threshold. + * + * For active scanning on channels that have regulatory restrictions against + * blindly transmitting, the scan can listen before transmitting, to make sure + * that there is already legitimate activity on the channel. If enough + * packets are cleanly received on the channel (controlled by good_CRC_th, + * typical value 1), the scan engine starts transmitting probe requests. + * + * Driver must use separate scan commands for 2.4 vs. 5 GHz bands. + * + * To avoid uCode errors, see timing restrictions described under + * struct iwl4965_scan_channel. + */ +struct iwl4965_scan_cmd { + __le16 len; + u8 reserved0; + u8 channel_count; /* # channels in channel list */ + __le16 quiet_time; /* dwell only this # millisecs on quiet channel + * (only for active scan) */ + __le16 quiet_plcp_th; /* quiet chnl is < this # pkts (typ. 1) */ + __le16 good_CRC_th; /* passive -> active promotion threshold */ + __le16 rx_chain; /* RXON_RX_CHAIN_* */ + __le32 max_out_time; /* max usec to be away from associated (service) + * 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_* */ + + /* For active scans (set to all-0s for passive scans). + * Does not include payload. Must specify Tx rate; no rate scaling. */ + struct iwl4965_tx_cmd tx_cmd; + + /* For directed active scans (set to all-0s otherwise) */ + struct iwl4965_ssid_ie direct_scan[PROBE_OPTION_MAX]; + + /* + * Probe request frame, followed by channel list. + * + * Size of probe request frame is specified by byte count in tx_cmd. + * Channel list follows immediately after probe request frame. + * Number of channels in list is specified by channel_count. + * Each channel in list is of type: + * + * struct iwl4965_scan_channel channels[0]; + * + * NOTE: Only one band of channels can be scanned per pass. You + * must not mix 2.4GHz channels and 5.2GHz channels, and you must wait + * for one scan to complete (i.e. receive SCAN_COMPLETE_NOTIFICATION) + * before requesting another scan. + */ + u8 data[0]; +} __attribute__ ((packed)); + +/* Can abort will notify by complete notification with abort status. */ +#define CAN_ABORT_STATUS __constant_cpu_to_le32(0x1) +/* complete notification statuses */ +#define ABORT_STATUS 0x2 + +/* + * REPLY_SCAN_CMD = 0x80 (response) + */ +struct iwl4965_scanreq_notification { + __le32 status; /* 1: okay, 2: cannot fulfill request */ +} __attribute__ ((packed)); + +/* + * SCAN_START_NOTIFICATION = 0x82 (notification only, not a command) + */ +struct iwl4965_scanstart_notification { + __le32 tsf_low; + __le32 tsf_high; + __le32 beacon_timer; + u8 channel; + u8 band; + u8 reserved[2]; + __le32 status; +} __attribute__ ((packed)); + +#define SCAN_OWNER_STATUS 0x1; +#define MEASURE_OWNER_STATUS 0x2; + +#define NUMBER_OF_STATISTICS 1 /* first __le32 is good CRC */ +/* + * SCAN_RESULTS_NOTIFICATION = 0x83 (notification only, not a command) + */ +struct iwl4965_scanresults_notification { + u8 channel; + u8 band; + u8 reserved[2]; + __le32 tsf_low; + __le32 tsf_high; + __le32 statistics[NUMBER_OF_STATISTICS]; +} __attribute__ ((packed)); + +/* + * SCAN_COMPLETE_NOTIFICATION = 0x84 (notification only, not a command) + */ +struct iwl4965_scancomplete_notification { + u8 scanned_channels; + u8 status; + u8 reserved; + u8 last_channel; + __le32 tsf_low; + __le32 tsf_high; +} __attribute__ ((packed)); + + +/****************************************************************************** + * (9) + * IBSS/AP Commands and Notifications: + * + *****************************************************************************/ + +/* + * BEACON_NOTIFICATION = 0x90 (notification only, not a command) + */ +struct iwl4965_beacon_notif { + struct iwl4965_tx_resp beacon_notify_hdr; + __le32 low_tsf; + __le32 high_tsf; + __le32 ibss_mgr_status; +} __attribute__ ((packed)); + +/* + * REPLY_TX_BEACON = 0x91 (command, has simple generic response) + */ +struct iwl4965_tx_beacon_cmd { + struct iwl4965_tx_cmd tx; + __le16 tim_idx; + u8 tim_size; + u8 reserved1; + struct ieee80211_hdr frame[0]; /* beacon frame */ +} __attribute__ ((packed)); + +/****************************************************************************** + * (10) + * Statistics Commands and Notifications: + * + *****************************************************************************/ + +#define IWL_TEMP_CONVERT 260 + +#define SUP_RATE_11A_MAX_NUM_CHANNELS 8 +#define SUP_RATE_11B_MAX_NUM_CHANNELS 4 +#define SUP_RATE_11G_MAX_NUM_CHANNELS 12 + +/* Used for passing to driver number of successes and failures per rate */ +struct rate_histogram { + union { + __le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS]; + __le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS]; + __le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS]; + } success; + union { + __le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS]; + __le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS]; + __le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS]; + } failed; +} __attribute__ ((packed)); + +/* statistics command response */ + +struct statistics_rx_phy { + __le32 ina_cnt; + __le32 fina_cnt; + __le32 plcp_err; + __le32 crc32_err; + __le32 overrun_err; + __le32 early_overrun_err; + __le32 crc32_good; + __le32 false_alarm_cnt; + __le32 fina_sync_err_cnt; + __le32 sfd_timeout; + __le32 fina_timeout; + __le32 unresponded_rts; + __le32 rxe_frame_limit_overrun; + __le32 sent_ack_cnt; + __le32 sent_cts_cnt; + __le32 sent_ba_rsp_cnt; + __le32 dsp_self_kill; + __le32 mh_format_err; + __le32 re_acq_main_rssi_sum; + __le32 reserved3; +} __attribute__ ((packed)); + +struct statistics_rx_ht_phy { + __le32 plcp_err; + __le32 overrun_err; + __le32 early_overrun_err; + __le32 crc32_good; + __le32 crc32_err; + __le32 mh_format_err; + __le32 agg_crc32_good; + __le32 agg_mpdu_cnt; + __le32 agg_cnt; + __le32 reserved2; +} __attribute__ ((packed)); + +struct statistics_rx_non_phy { + __le32 bogus_cts; /* CTS received when not expecting CTS */ + __le32 bogus_ack; /* ACK received when not expecting ACK */ + __le32 non_bssid_frames; /* number of frames with BSSID that + * doesn't belong to the STA BSSID */ + __le32 filtered_frames; /* count frames that were dumped in the + * filtering process */ + __le32 non_channel_beacons; /* beacons with our bss id but not on + * our serving channel */ + __le32 channel_beacons; /* beacons with our bss id and in our + * serving channel */ + __le32 num_missed_bcon; /* number of missed beacons */ + __le32 adc_rx_saturation_time; /* count in 0.8us units the time the + * ADC was in saturation */ + __le32 ina_detection_search_time;/* total time (in 0.8us) searched + * for INA */ + __le32 beacon_silence_rssi_a; /* RSSI silence after beacon frame */ + __le32 beacon_silence_rssi_b; /* RSSI silence after beacon frame */ + __le32 beacon_silence_rssi_c; /* RSSI silence after beacon frame */ + __le32 interference_data_flag; /* flag for interference data + * availability. 1 when data is + * available. */ + __le32 channel_load; /* counts RX Enable time in uSec */ + __le32 dsp_false_alarms; /* DSP false alarm (both OFDM + * and CCK) counter */ + __le32 beacon_rssi_a; + __le32 beacon_rssi_b; + __le32 beacon_rssi_c; + __le32 beacon_energy_a; + __le32 beacon_energy_b; + __le32 beacon_energy_c; +} __attribute__ ((packed)); + +struct statistics_rx { + struct statistics_rx_phy ofdm; + struct statistics_rx_phy cck; + struct statistics_rx_non_phy general; + struct statistics_rx_ht_phy ofdm_ht; +} __attribute__ ((packed)); + +struct statistics_tx_non_phy_agg { + __le32 ba_timeout; + __le32 ba_reschedule_frames; + __le32 scd_query_agg_frame_cnt; + __le32 scd_query_no_agg; + __le32 scd_query_agg; + __le32 scd_query_mismatch; + __le32 frame_not_ready; + __le32 underrun; + __le32 bt_prio_kill; + __le32 rx_ba_rsp_cnt; + __le32 reserved2; + __le32 reserved3; +} __attribute__ ((packed)); + +struct statistics_tx { + __le32 preamble_cnt; + __le32 rx_detected_cnt; + __le32 bt_prio_defer_cnt; + __le32 bt_prio_kill_cnt; + __le32 few_bytes_cnt; + __le32 cts_timeout; + __le32 ack_timeout; + __le32 expected_ack_cnt; + __le32 actual_ack_cnt; + __le32 dump_msdu_cnt; + __le32 burst_abort_next_frame_mismatch_cnt; + __le32 burst_abort_missing_next_frame_cnt; + __le32 cts_timeout_collision; + __le32 ack_or_ba_timeout_collision; + struct statistics_tx_non_phy_agg agg; +} __attribute__ ((packed)); + +struct statistics_dbg { + __le32 burst_check; + __le32 burst_count; + __le32 reserved[4]; +} __attribute__ ((packed)); + +struct statistics_div { + __le32 tx_on_a; + __le32 tx_on_b; + __le32 exec_time; + __le32 probe_time; + __le32 reserved1; + __le32 reserved2; +} __attribute__ ((packed)); + +struct statistics_general { + __le32 temperature; + __le32 temperature_m; + struct statistics_dbg dbg; + __le32 sleep_time; + __le32 slots_out; + __le32 slots_idle; + __le32 ttl_timestamp; + struct statistics_div div; + __le32 rx_enable_counter; + __le32 reserved1; + __le32 reserved2; + __le32 reserved3; +} __attribute__ ((packed)); + +/* + * REPLY_STATISTICS_CMD = 0x9c, + * 3945 and 4965 identical. + * + * This command triggers an immediate response containing uCode statistics. + * The response is in the same format as STATISTICS_NOTIFICATION 0x9d, below. + * + * If the CLEAR_STATS configuration flag is set, uCode will clear its + * internal copy of the statistics (counters) after issuing the response. + * This flag does not affect STATISTICS_NOTIFICATIONs after beacons (see below). + * + * If the DISABLE_NOTIF configuration flag is set, uCode will not issue + * STATISTICS_NOTIFICATIONs after received beacons (see below). This flag + * does not affect the response to the REPLY_STATISTICS_CMD 0x9c itself. + */ +#define IWL_STATS_CONF_CLEAR_STATS __constant_cpu_to_le32(0x1) /* see above */ +#define IWL_STATS_CONF_DISABLE_NOTIF __constant_cpu_to_le32(0x2)/* see above */ +struct iwl4965_statistics_cmd { + __le32 configuration_flags; /* IWL_STATS_CONF_* */ +} __attribute__ ((packed)); + +/* + * STATISTICS_NOTIFICATION = 0x9d (notification only, not a command) + * + * By default, uCode issues this notification after receiving a beacon + * while associated. To disable this behavior, set DISABLE_NOTIF flag in the + * REPLY_STATISTICS_CMD 0x9c, above. + * + * Statistics counters continue to increment beacon after beacon, but are + * cleared when changing channels or when driver issues REPLY_STATISTICS_CMD + * 0x9c with CLEAR_STATS bit set (see above). + * + * uCode also issues this notification during scans. uCode clears statistics + * appropriately so that each notification contains statistics for only the + * one channel that has just been scanned. + */ +#define STATISTICS_REPLY_FLG_BAND_24G_MSK __constant_cpu_to_le32(0x2) +#define STATISTICS_REPLY_FLG_FAT_MODE_MSK __constant_cpu_to_le32(0x8) +struct iwl4965_notif_statistics { + __le32 flag; + struct statistics_rx rx; + struct statistics_tx tx; + struct statistics_general general; +} __attribute__ ((packed)); + + +/* + * MISSED_BEACONS_NOTIFICATION = 0xa2 (notification only, not a command) + */ +/* if ucode missed CONSECUTIVE_MISSED_BCONS_TH beacons in a row, + * then this notification will be sent. */ +#define CONSECUTIVE_MISSED_BCONS_TH 20 + +struct iwl4965_missed_beacon_notif { + __le32 consequtive_missed_beacons; + __le32 total_missed_becons; + __le32 num_expected_beacons; + __le32 num_recvd_beacons; +} __attribute__ ((packed)); + + +/****************************************************************************** + * (11) + * Rx Calibration Commands: + * + * With the uCode used for open source drivers, most Tx calibration (except + * for Tx Power) and most Rx calibration is done by uCode during the + * "initialize" phase of uCode boot. Driver must calibrate only: + * + * 1) Tx power (depends on temperature), described elsewhere + * 2) Receiver gain balance (optimize MIMO, and detect disconnected antennas) + * 3) Receiver sensitivity (to optimize signal detection) + * + *****************************************************************************/ + +/** + * SENSITIVITY_CMD = 0xa8 (command, has simple generic response) + * + * This command sets up the Rx signal detector for a sensitivity level that + * is high enough to lock onto all signals within the associated network, + * but low enough to ignore signals that are below a certain threshold, so as + * not to have too many "false alarms". False alarms are signals that the + * Rx DSP tries to lock onto, but then discards after determining that they + * are noise. + * + * The optimum number of false alarms is between 5 and 50 per 200 TUs + * (200 * 1024 uSecs, i.e. 204.8 milliseconds) of actual Rx time (i.e. + * time listening, not transmitting). Driver must adjust sensitivity so that + * the ratio of actual false alarms to actual Rx time falls within this range. + * + * While associated, uCode delivers STATISTICS_NOTIFICATIONs after each + * received beacon. These provide information to the driver to analyze the + * sensitivity. Don't analyze statistics that come in from scanning, or any + * other non-associated-network source. Pertinent statistics include: + * + * From "general" statistics (struct statistics_rx_non_phy): + * + * (beacon_energy_[abc] & 0x0FF00) >> 8 (unsigned, higher value is lower level) + * Measure of energy of desired signal. Used for establishing a level + * below which the device does not detect signals. + * + * (beacon_silence_rssi_[abc] & 0x0FF00) >> 8 (unsigned, units in dB) + * Measure of background noise in silent period after beacon. + * + * channel_load + * uSecs of actual Rx time during beacon period (varies according to + * how much time was spent transmitting). + * + * From "cck" and "ofdm" statistics (struct statistics_rx_phy), separately: + * + * false_alarm_cnt + * Signal locks abandoned early (before phy-level header). + * + * plcp_err + * Signal locks abandoned late (during phy-level header). + * + * NOTE: Both false_alarm_cnt and plcp_err increment monotonically from + * beacon to beacon, i.e. each value is an accumulation of all errors + * before and including the latest beacon. Values will wrap around to 0 + * after counting up to 2^32 - 1. Driver must differentiate vs. + * previous beacon's values to determine # false alarms in the current + * beacon period. + * + * Total number of false alarms = false_alarms + plcp_errs + * + * For OFDM, adjust the following table entries in struct iwl_sensitivity_cmd + * (notice that the start points for OFDM are at or close to settings for + * maximum sensitivity): + * + * START / MIN / MAX + * HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX 90 / 85 / 120 + * HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX 170 / 170 / 210 + * HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX 105 / 105 / 140 + * HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX 220 / 220 / 270 + * + * If actual rate of OFDM false alarms (+ plcp_errors) is too high + * (greater than 50 for each 204.8 msecs listening), reduce sensitivity + * by *adding* 1 to all 4 of the table entries above, up to the max for + * each entry. Conversely, if false alarm rate is too low (less than 5 + * for each 204.8 msecs listening), *subtract* 1 from each entry to + * increase sensitivity. + * + * For CCK sensitivity, keep track of the following: + * + * 1). 20-beacon history of maximum background noise, indicated by + * (beacon_silence_rssi_[abc] & 0x0FF00), units in dB, across the + * 3 receivers. For any given beacon, the "silence reference" is + * the maximum of last 60 samples (20 beacons * 3 receivers). + * + * 2). 10-beacon history of strongest signal level, as indicated + * by (beacon_energy_[abc] & 0x0FF00) >> 8, across the 3 receivers, + * i.e. the strength of the signal through the best receiver at the + * moment. These measurements are "upside down", with lower values + * for stronger signals, so max energy will be *minimum* value. + * + * Then for any given beacon, the driver must determine the *weakest* + * of the strongest signals; this is the minimum level that needs to be + * successfully detected, when using the best receiver at the moment. + * "Max cck energy" is the maximum (higher value means lower energy!) + * of the last 10 minima. Once this is determined, driver must add + * a little margin by adding "6" to it. + * + * 3). Number of consecutive beacon periods with too few false alarms. + * Reset this to 0 at the first beacon period that falls within the + * "good" range (5 to 50 false alarms per 204.8 milliseconds rx). + * + * Then, adjust the following CCK table entries in struct iwl_sensitivity_cmd + * (notice that the start points for CCK are at maximum sensitivity): + * + * START / MIN / MAX + * HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX 125 / 125 / 200 + * HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX 200 / 200 / 400 + * HD_MIN_ENERGY_CCK_DET_INDEX 100 / 0 / 100 + * + * If actual rate of CCK false alarms (+ plcp_errors) is too high + * (greater than 50 for each 204.8 msecs listening), method for reducing + * sensitivity is: + * + * 1) *Add* 3 to value in HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX, + * up to max 400. + * + * 2) If current value in HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX is < 160, + * sensitivity has been reduced a significant amount; bring it up to + * a moderate 161. Otherwise, *add* 3, up to max 200. + * + * 3) a) If current value in HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX is > 160, + * sensitivity has been reduced only a moderate or small amount; + * *subtract* 2 from value in HD_MIN_ENERGY_CCK_DET_INDEX, + * down to min 0. Otherwise (if gain has been significantly reduced), + * don't change the HD_MIN_ENERGY_CCK_DET_INDEX value. + * + * b) Save a snapshot of the "silence reference". + * + * If actual rate of CCK false alarms (+ plcp_errors) is too low + * (less than 5 for each 204.8 msecs listening), method for increasing + * sensitivity is used only if: + * + * 1a) Previous beacon did not have too many false alarms + * 1b) AND difference between previous "silence reference" and current + * "silence reference" (prev - current) is 2 or more, + * OR 2) 100 or more consecutive beacon periods have had rate of + * less than 5 false alarms per 204.8 milliseconds rx time. + * + * Method for increasing sensitivity: + * + * 1) *Subtract* 3 from value in HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX, + * down to min 125. + * + * 2) *Subtract* 3 from value in HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX, + * down to min 200. + * + * 3) *Add* 2 to value in HD_MIN_ENERGY_CCK_DET_INDEX, up to max 100. + * + * If actual rate of CCK false alarms (+ plcp_errors) is within good range + * (between 5 and 50 for each 204.8 msecs listening): + * + * 1) Save a snapshot of the silence reference. + * + * 2) If previous beacon had too many CCK false alarms (+ plcp_errors), + * give some extra margin to energy threshold by *subtracting* 8 + * from value in HD_MIN_ENERGY_CCK_DET_INDEX. + * + * For all cases (too few, too many, good range), make sure that the CCK + * detection threshold (energy) is below the energy level for robust + * detection over the past 10 beacon periods, the "Max cck energy". + * Lower values mean higher energy; this means making sure that the value + * in HD_MIN_ENERGY_CCK_DET_INDEX is at or *above* "Max cck energy". + * + * Driver should set the following entries to fixed values: + * + * HD_MIN_ENERGY_OFDM_DET_INDEX 100 + * HD_BARKER_CORR_TH_ADD_MIN_INDEX 190 + * HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX 390 + * HD_OFDM_ENERGY_TH_IN_INDEX 62 + */ + +/* + * Table entries in SENSITIVITY_CMD (struct iwl_sensitivity_cmd) + */ +#define HD_TABLE_SIZE (11) /* number of entries */ +#define HD_MIN_ENERGY_CCK_DET_INDEX (0) /* table indexes */ +#define HD_MIN_ENERGY_OFDM_DET_INDEX (1) +#define HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX (2) +#define HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX (3) +#define HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX (4) +#define HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX (5) +#define HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX (6) +#define HD_BARKER_CORR_TH_ADD_MIN_INDEX (7) +#define HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX (8) +#define HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX (9) +#define HD_OFDM_ENERGY_TH_IN_INDEX (10) + +/* Control field in struct iwl_sensitivity_cmd */ +#define SENSITIVITY_CMD_CONTROL_DEFAULT_TABLE __constant_cpu_to_le16(0) +#define SENSITIVITY_CMD_CONTROL_WORK_TABLE __constant_cpu_to_le16(1) + +/** + * struct iwl_sensitivity_cmd + * @control: (1) updates working table, (0) updates default table + * @table: energy threshold values, use HD_* as index into table + * + * Always use "1" in "control" to update uCode's working table and DSP. + */ +struct iwl_sensitivity_cmd { + __le16 control; /* always use "1" */ + __le16 table[HD_TABLE_SIZE]; /* use HD_* as index */ +} __attribute__ ((packed)); + + +/** + * REPLY_PHY_CALIBRATION_CMD = 0xb0 (command, has simple generic response) + * + * This command sets the relative gains of 4965's 3 radio receiver chains. + * + * After the first association, driver should accumulate signal and noise + * statistics from the STATISTICS_NOTIFICATIONs that follow the first 20 + * beacons from the associated network (don't collect statistics that come + * in from scanning, or any other non-network source). + * + * DISCONNECTED ANTENNA: + * + * Driver should determine which antennas are actually connected, by comparing + * average beacon signal levels for the 3 Rx chains. Accumulate (add) the + * following values over 20 beacons, one accumulator for each of the chains + * a/b/c, from struct statistics_rx_non_phy: + * + * beacon_rssi_[abc] & 0x0FF (unsigned, units in dB) + * + * Find the strongest signal from among a/b/c. Compare the other two to the + * strongest. If any signal is more than 15 dB (times 20, unless you + * divide the accumulated values by 20) below the strongest, the driver + * considers that antenna to be disconnected, and should not try to use that + * antenna/chain for Rx or Tx. If both A and B seem to be disconnected, + * driver should declare the stronger one as connected, and attempt to use it + * (A and B are the only 2 Tx chains!). + * + * + * RX BALANCE: + * + * Driver should balance the 3 receivers (but just the ones that are connected + * to antennas, see above) for gain, by comparing the average signal levels + * detected during the silence after each beacon (background noise). + * Accumulate (add) the following values over 20 beacons, one accumulator for + * each of the chains a/b/c, from struct statistics_rx_non_phy: + * + * beacon_silence_rssi_[abc] & 0x0FF (unsigned, units in dB) + * + * Find the weakest background noise level from among a/b/c. This Rx chain + * will be the reference, with 0 gain adjustment. Attenuate other channels by + * finding noise difference: + * + * (accum_noise[i] - accum_noise[reference]) / 30 + * + * The "30" adjusts the dB in the 20 accumulated samples to units of 1.5 dB. + * For use in diff_gain_[abc] fields of struct iwl_calibration_cmd, the + * driver should limit the difference results to a range of 0-3 (0-4.5 dB), + * and set bit 2 to indicate "reduce gain". The value for the reference + * (weakest) chain should be "0". + * + * diff_gain_[abc] bit fields: + * 2: (1) reduce gain, (0) increase gain + * 1-0: amount of gain, units of 1.5 dB + */ + +/* "Differential Gain" opcode used in REPLY_PHY_CALIBRATION_CMD. */ +#define PHY_CALIBRATE_DIFF_GAIN_CMD (7) + +struct iwl4965_calibration_cmd { + u8 opCode; /* PHY_CALIBRATE_DIFF_GAIN_CMD (7) */ + u8 flags; /* not used */ + __le16 reserved; + s8 diff_gain_a; /* see above */ + s8 diff_gain_b; + s8 diff_gain_c; + u8 reserved1; +} __attribute__ ((packed)); + +/* Phy calibration command for 5000 series */ + +enum { + IWL5000_PHY_CALIBRATE_DC_CMD = 8, + IWL5000_PHY_CALIBRATE_LO_CMD = 9, + IWL5000_PHY_CALIBRATE_RX_BB_CMD = 10, + IWL5000_PHY_CALIBRATE_TX_IQ_CMD = 11, + IWL5000_PHY_CALIBRATE_RX_IQ_CMD = 12, + IWL5000_PHY_CALIBRATION_NOISE_CMD = 13, + IWL5000_PHY_CALIBRATE_AGC_TABLE_CMD = 14, + IWL5000_PHY_CALIBRATE_CRYSTAL_FRQ_CMD = 15, + IWL5000_PHY_CALIBRATE_BASE_BAND_CMD = 16, + IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD = 18, + IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD = 19, +}; + +struct iwl5000_calibration_chain_noise_reset_cmd { + u8 op_code; /* IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD */ + u8 flags; /* not used */ + __le16 reserved; +} __attribute__ ((packed)); + +struct iwl5000_calibration_chain_noise_gain_cmd { + u8 op_code; /* IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD */ + u8 flags; /* not used */ + __le16 reserved; + u8 delta_gain_1; + u8 delta_gain_2; + __le16 reserved1; +} __attribute__ ((packed)); + +/****************************************************************************** + * (12) + * Miscellaneous Commands: + * + *****************************************************************************/ + +/* + * LEDs Command & Response + * REPLY_LEDS_CMD = 0x48 (command, has simple generic response) + * + * For each of 3 possible LEDs (Activity/Link/Tech, selected by "id" field), + * this command turns it on or off, or sets up a periodic blinking cycle. + */ +struct iwl4965_led_cmd { + __le32 interval; /* "interval" in uSec */ + u8 id; /* 1: Activity, 2: Link, 3: Tech */ + u8 off; /* # intervals off while blinking; + * "0", with >0 "on" value, turns LED on */ + u8 on; /* # intervals on while blinking; + * "0", regardless of "off", turns LED off */ + u8 reserved; +} __attribute__ ((packed)); + +/****************************************************************************** + * (13) + * Union of all expected notifications/responses: + * + *****************************************************************************/ + +struct iwl4965_rx_packet { + __le32 len; + struct iwl_cmd_header hdr; + union { + struct iwl4965_alive_resp alive_frame; + struct iwl4965_rx_frame rx_frame; + struct iwl4965_tx_resp tx_resp; + struct iwl4965_spectrum_notification spectrum_notif; + struct iwl4965_csa_notification csa_notif; + struct iwl4965_error_resp err_resp; + struct iwl4965_card_state_notif card_state_notif; + struct iwl4965_beacon_notif beacon_status; + struct iwl4965_add_sta_resp add_sta; + struct iwl4965_sleep_notification sleep_notif; + struct iwl4965_spectrum_resp spectrum; + struct iwl4965_notif_statistics stats; + struct iwl4965_compressed_ba_resp compressed_ba; + struct iwl4965_missed_beacon_notif missed_beacon; + __le32 status; + u8 raw[0]; + } u; +} __attribute__ ((packed)); + +#define IWL_RX_FRAME_SIZE (4 + sizeof(struct iwl4965_rx_frame)) + +#endif /* __iwl4965_commands_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 8bec0e32f1f..5b2746eeb4a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -68,7 +68,7 @@ #include -#include "iwl-4965-commands.h" +#include "iwl-commands.h" #include "iwl-4965.h" #include "iwl-core.h" #include "iwl-debug.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index a242628465a..db7f65a5ac2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -37,7 +37,7 @@ #include "iwl-eeprom.h" #include "iwl-4965.h" #include "iwl-core.h" -#include "iwl-4965-commands.h" +#include "iwl-commands.h" #include "iwl-debug.h" #include "iwl-power.h" #include "iwl-helpers.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h index aad2784ca2e..b066724a1c2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/drivers/net/wireless/iwlwifi/iwl-power.h @@ -29,7 +29,7 @@ #define __iwl_power_setting_h__ #include -#include "iwl-4965-commands.h" +#include "iwl-commands.h" struct iwl_priv; -- cgit v1.2.3-70-g09d2 From 3e0d4cb12f6fd97193a455b49125398b2231c87c Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 24 Apr 2008 11:55:38 -0700 Subject: iwlwifi: rename iwl-4965.h to iwl-dev.h This patch renames iwl-4965.h to iwl-dev.h Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-hw.h | 2 +- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 2 +- drivers/net/wireless/iwlwifi/iwl-4965-rs.h | 2 +- drivers/net/wireless/iwlwifi/iwl-4965.c | 2 +- drivers/net/wireless/iwlwifi/iwl-4965.h | 1260 --------------------------- drivers/net/wireless/iwlwifi/iwl-5000.c | 2 +- drivers/net/wireless/iwlwifi/iwl-calib.c | 2 +- drivers/net/wireless/iwlwifi/iwl-calib.h | 2 +- drivers/net/wireless/iwlwifi/iwl-commands.h | 2 +- drivers/net/wireless/iwlwifi/iwl-core.c | 2 +- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 2 +- drivers/net/wireless/iwlwifi/iwl-dev.h | 1260 +++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-eeprom.c | 2 +- drivers/net/wireless/iwlwifi/iwl-hcmd.c | 2 +- drivers/net/wireless/iwlwifi/iwl-led.c | 2 +- drivers/net/wireless/iwlwifi/iwl-power.c | 2 +- drivers/net/wireless/iwlwifi/iwl-rfkill.c | 2 +- drivers/net/wireless/iwlwifi/iwl-sta.c | 2 +- drivers/net/wireless/iwlwifi/iwl4965-base.c | 2 +- 19 files changed, 1277 insertions(+), 1277 deletions(-) delete mode 100644 drivers/net/wireless/iwlwifi/iwl-4965.h create mode 100644 drivers/net/wireless/iwlwifi/iwl-dev.h (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h index 6dbdc0eec76..29749e2a8ff 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h @@ -63,7 +63,7 @@ /* * Please use this file (iwl-4965-hw.h) only for hardware-related definitions. * Use iwl-commands.h for uCode API definitions. - * Use iwl-4965.h for driver implementation definitions. + * Use iwl-dev.h for driver implementation definitions. */ #ifndef __iwl_4965_hw_h__ diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index c8c54b14920..67356d9a0c5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -37,7 +37,7 @@ #include "../net/mac80211/rate.h" -#include "iwl-4965.h" +#include "iwl-dev.h" #include "iwl-core.h" #include "iwl-helpers.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.h b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h index f6793203515..7ea2041a22e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h @@ -27,7 +27,7 @@ #ifndef __iwl_4965_rs_h__ #define __iwl_4965_rs_h__ -#include "iwl-4965.h" +#include "iwl-dev.h" struct iwl4965_rate_info { u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */ diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 8aaac16a45f..9546582e983 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -39,7 +39,7 @@ #include #include "iwl-eeprom.h" -#include "iwl-4965.h" +#include "iwl-dev.h" #include "iwl-core.h" #include "iwl-io.h" #include "iwl-helpers.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h deleted file mode 100644 index d556c2ffd8d..00000000000 --- a/drivers/net/wireless/iwlwifi/iwl-4965.h +++ /dev/null @@ -1,1260 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - * Contact Information: - * James P. Ketrenos - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - *****************************************************************************/ -/* - * Please use this file (iwl-4965.h) for driver implementation definitions. - * Please use iwl-commands.h for uCode API definitions. - * Please use iwl-4965-hw.h for hardware-related definitions. - */ - -#ifndef __iwl_4965_h__ -#define __iwl_4965_h__ - -#include /* for struct pci_device_id */ -#include -#include - -#define DRV_NAME "iwl4965" -#include "iwl-rfkill.h" -#include "iwl-eeprom.h" -#include "iwl-4965-hw.h" -#include "iwl-csr.h" -#include "iwl-prph.h" -#include "iwl-debug.h" -#include "iwl-led.h" -#include "iwl-power.h" - -/* configuration for the iwl4965 */ -extern struct iwl_cfg iwl4965_agn_cfg; -extern struct iwl_cfg iwl5300_agn_cfg; -extern struct iwl_cfg iwl5100_agn_cfg; -extern struct iwl_cfg iwl5350_agn_cfg; - -/* Change firmware file name, using "-" and incrementing number, - * *only* when uCode interface or architecture changes so that it - * is not compatible with earlier drivers. - * This number will also appear in << 8 position of 1st dword of uCode file */ -#define IWL4965_UCODE_API "-1" - -/* CT-KILL constants */ -#define CT_KILL_THRESHOLD 110 /* in Celsius */ - -/* 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) - * 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. - * 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 - * averages within an s8's (used in some apps) range of negative values. */ -#define IWL_NOISE_MEAS_NOT_AVAILABLE (-127) - -/* - * RTS threshold here is total size [2347] minus 4 FCS bytes - * Per spec: - * a value of 0 means RTS on all data/management packets - * a value > max MSDU size means no RTS - * else RTS for data/management frames where MPDU is larger - * than RTS value. - */ -#define DEFAULT_RTS_THRESHOLD 2347U -#define MIN_RTS_THRESHOLD 0U -#define MAX_RTS_THRESHOLD 2347U -#define MAX_MSDU_SIZE 2304U -#define MAX_MPDU_SIZE 2346U -#define DEFAULT_BEACON_INTERVAL 100U -#define DEFAULT_SHORT_RETRY_LIMIT 7U -#define DEFAULT_LONG_RETRY_LIMIT 4U - -struct iwl4965_rx_mem_buffer { - dma_addr_t dma_addr; - struct sk_buff *skb; - struct list_head list; -}; - -/* - * Generic queue structure - * - * Contains common data for Rx and Tx queues - */ -struct iwl4965_queue { - int n_bd; /* number of BDs in this queue */ - int write_ptr; /* 1-st empty entry (index) host_w*/ - int read_ptr; /* last used entry (index) host_r*/ - dma_addr_t dma_addr; /* physical addr for BD's */ - int n_window; /* safe queue window */ - u32 id; - int low_mark; /* low watermark, resume queue if free - * space more than this */ - int high_mark; /* high watermark, stop queue if free - * space less than this */ -} __attribute__ ((packed)); - -#define MAX_NUM_OF_TBS (20) - -/* One for each TFD */ -struct iwl4965_tx_info { - struct ieee80211_tx_status status; - struct sk_buff *skb[MAX_NUM_OF_TBS]; -}; - -/** - * struct iwl4965_tx_queue - Tx Queue for DMA - * @q: generic Rx/Tx queue descriptor - * @bd: base of circular buffer of TFDs - * @cmd: array of command/Tx buffers - * @dma_addr_cmd: physical address of cmd/tx buffer array - * @txb: array of per-TFD driver data - * @need_update: indicates need to update read/write index - * @sched_retry: indicates queue is high-throughput aggregation (HT AGG) enabled - * - * A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame - * descriptors) and required locking structures. - */ -struct iwl4965_tx_queue { - struct iwl4965_queue q; - struct iwl4965_tfd_frame *bd; - struct iwl_cmd *cmd; - dma_addr_t dma_addr_cmd; - struct iwl4965_tx_info *txb; - int need_update; - int sched_retry; - int active; -}; - -#define IWL_NUM_SCAN_RATES (2) - -struct iwl4965_channel_tgd_info { - u8 type; - s8 max_power; -}; - -struct iwl4965_channel_tgh_info { - s64 last_radar_time; -}; - -/* current Tx power values to use, one for each rate for each channel. - * requested power is limited by: - * -- regulatory EEPROM limits for this channel - * -- hardware capabilities (clip-powers) - * -- spectrum management - * -- user preference (e.g. iwconfig) - * when requested power is set, base power index must also be set. */ -struct iwl4965_channel_power_info { - struct iwl4965_tx_power tpc; /* actual radio and DSP gain settings */ - s8 power_table_index; /* actual (compenst'd) index into gain table */ - s8 base_power_index; /* gain index for power at factory temp. */ - s8 requested_power; /* power (dBm) requested for this chnl/rate */ -}; - -/* current scan Tx power values to use, one for each scan rate for each - * channel. */ -struct iwl4965_scan_power_info { - struct iwl4965_tx_power tpc; /* actual radio and DSP gain settings */ - s8 power_table_index; /* actual (compenst'd) index into gain table */ - s8 requested_power; /* scan pwr (dBm) requested for chnl/rate */ -}; - -/* For fat_extension_channel */ -enum { - HT_IE_EXT_CHANNEL_NONE = 0, - HT_IE_EXT_CHANNEL_ABOVE, - HT_IE_EXT_CHANNEL_INVALID, - HT_IE_EXT_CHANNEL_BELOW, - HT_IE_EXT_CHANNEL_MAX -}; - -/* - * One for each channel, holds all channel setup data - * Some of the fields (e.g. eeprom and flags/max_power_avg) are redundant - * with one another! - */ -#define IWL4965_MAX_RATE (33) - -struct iwl_channel_info { - struct iwl4965_channel_tgd_info tgd; - struct iwl4965_channel_tgh_info tgh; - struct iwl_eeprom_channel eeprom; /* EEPROM regulatory limit */ - struct iwl_eeprom_channel fat_eeprom; /* EEPROM regulatory limit for - * FAT channel */ - - u8 channel; /* channel number */ - u8 flags; /* flags copied from EEPROM */ - s8 max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */ - s8 curr_txpow; /* (dBm) regulatory/spectrum/user (not h/w) limit */ - s8 min_power; /* always 0 */ - s8 scan_power; /* (dBm) regul. eeprom, direct scans, any rate */ - - u8 group_index; /* 0-4, maps channel to group1/2/3/4/5 */ - u8 band_index; /* 0-4, maps channel to band1/2/3/4/5 */ - enum ieee80211_band band; - - /* Radio/DSP gain settings for each "normal" data Tx rate. - * These include, in addition to RF and DSP gain, a few fields for - * remembering/modifying gain settings (indexes). */ - struct iwl4965_channel_power_info power_info[IWL4965_MAX_RATE]; - - /* FAT channel info */ - s8 fat_max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */ - s8 fat_curr_txpow; /* (dBm) regulatory/spectrum/user (not h/w) */ - s8 fat_min_power; /* always 0 */ - s8 fat_scan_power; /* (dBm) eeprom, direct scans, any rate */ - u8 fat_flags; /* flags copied from EEPROM */ - u8 fat_extension_channel; /* HT_IE_EXT_CHANNEL_* */ - - /* Radio/DSP gain settings for each scan rate, for directed scans. */ - struct iwl4965_scan_power_info scan_pwr_info[IWL_NUM_SCAN_RATES]; -}; - -struct iwl4965_clip_group { - /* maximum power level to prevent clipping for each rate, derived by - * us from this band's saturation power in EEPROM */ - const s8 clip_powers[IWL_MAX_RATES]; -}; - -#include "iwl-4965-rs.h" - -#define IWL_TX_FIFO_AC0 0 -#define IWL_TX_FIFO_AC1 1 -#define IWL_TX_FIFO_AC2 2 -#define IWL_TX_FIFO_AC3 3 -#define IWL_TX_FIFO_HCCA_1 5 -#define IWL_TX_FIFO_HCCA_2 6 -#define IWL_TX_FIFO_NONE 7 - -/* Minimum number of queues. MAX_NUM is defined in hw specific files */ -#define IWL_MIN_NUM_QUEUES 4 - -/* Power management (not Tx power) structures */ - -enum iwl_pwr_src { - IWL_PWR_SRC_VMAIN, - IWL_PWR_SRC_VAUX, -}; - -#define IEEE80211_DATA_LEN 2304 -#define IEEE80211_4ADDR_LEN 30 -#define IEEE80211_HLEN (IEEE80211_4ADDR_LEN) -#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN) - -struct iwl4965_frame { - union { - struct ieee80211_hdr frame; - struct iwl4965_tx_beacon_cmd beacon; - u8 raw[IEEE80211_FRAME_LEN]; - u8 cmd[360]; - } u; - struct list_head list; -}; - -#define SEQ_TO_QUEUE(x) ((x >> 8) & 0xbf) -#define QUEUE_TO_SEQ(x) ((x & 0xbf) << 8) -#define SEQ_TO_INDEX(x) ((u8)(x & 0xff)) -#define INDEX_TO_SEQ(x) ((u8)(x & 0xff)) -#define SEQ_HUGE_FRAME (0x4000) -#define SEQ_RX_FRAME __constant_cpu_to_le16(0x8000) -#define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4) -#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ) -#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4) - -enum { - /* CMD_SIZE_NORMAL = 0, */ - CMD_SIZE_HUGE = (1 << 0), - /* CMD_SYNC = 0, */ - CMD_ASYNC = (1 << 1), - /* CMD_NO_SKB = 0, */ - CMD_WANT_SKB = (1 << 2), -}; - -struct iwl_cmd; -struct iwl_priv; - -struct iwl_cmd_meta { - struct iwl_cmd_meta *source; - union { - struct sk_buff *skb; - int (*callback)(struct iwl_priv *priv, - struct iwl_cmd *cmd, struct sk_buff *skb); - } __attribute__ ((packed)) u; - - /* The CMD_SIZE_HUGE flag bit indicates that the command - * structure is stored at the end of the shared queue memory. */ - u32 flags; - -} __attribute__ ((packed)); - -/** - * struct iwl_cmd - * - * For allocation of the command and tx queues, this establishes the overall - * size of the largest command we send to uCode, except for a scan command - * (which is relatively huge; space is allocated separately). - */ -struct iwl_cmd { - struct iwl_cmd_meta meta; /* driver data */ - struct iwl_cmd_header hdr; /* uCode API */ - union { - struct iwl4965_addsta_cmd addsta; - struct iwl4965_led_cmd led; - u32 flags; - u8 val8; - u16 val16; - u32 val32; - struct iwl4965_bt_cmd bt; - struct iwl4965_rxon_time_cmd rxon_time; - struct iwl4965_powertable_cmd powertable; - struct iwl4965_qosparam_cmd qosparam; - struct iwl4965_tx_cmd tx; - struct iwl4965_tx_beacon_cmd tx_beacon; - struct iwl4965_rxon_assoc_cmd rxon_assoc; - u8 *indirect; - u8 payload[360]; - } __attribute__ ((packed)) cmd; -} __attribute__ ((packed)); - -struct iwl_host_cmd { - u8 id; - u16 len; - struct iwl_cmd_meta meta; - const void *data; -}; - -#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_cmd) - \ - sizeof(struct iwl_cmd_meta)) - -/* - * RX related structures and functions - */ -#define RX_FREE_BUFFERS 64 -#define RX_LOW_WATERMARK 8 - -#define SUP_RATE_11A_MAX_NUM_CHANNELS 8 -#define SUP_RATE_11B_MAX_NUM_CHANNELS 4 -#define SUP_RATE_11G_MAX_NUM_CHANNELS 12 - -/** - * struct iwl4965_rx_queue - Rx queue - * @processed: Internal index to last handled Rx packet - * @read: Shared index to newest available Rx buffer - * @write: Shared index to oldest written Rx packet - * @free_count: Number of pre-allocated buffers in rx_free - * @rx_free: list of free SKBs for use - * @rx_used: List of Rx buffers with no SKB - * @need_update: flag to indicate we need to update read/write index - * - * NOTE: rx_free and rx_used are used as a FIFO for iwl4965_rx_mem_buffers - */ -struct iwl4965_rx_queue { - __le32 *bd; - dma_addr_t dma_addr; - struct iwl4965_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS]; - struct iwl4965_rx_mem_buffer *queue[RX_QUEUE_SIZE]; - u32 processed; - u32 read; - u32 write; - u32 free_count; - struct list_head rx_free; - struct list_head rx_used; - int need_update; - spinlock_t lock; -}; - -#define IWL_SUPPORTED_RATES_IE_LEN 8 - -#define SCAN_INTERVAL 100 - -#define MAX_A_CHANNELS 252 -#define MIN_A_CHANNELS 7 - -#define MAX_B_CHANNELS 14 -#define MIN_B_CHANNELS 1 - -#define MAX_TID_COUNT 9 - -#define IWL_INVALID_RATE 0xFF -#define IWL_INVALID_VALUE -1 - -#ifdef CONFIG_IWL4965_HT -/** - * struct iwl4965_ht_agg -- aggregation status while waiting for block-ack - * @txq_id: Tx queue used for Tx attempt - * @frame_count: # frames attempted by Tx command - * @wait_for_ba: Expect block-ack before next Tx reply - * @start_idx: Index of 1st Transmit Frame Descriptor (TFD) in Tx window - * @bitmap0: Low order bitmap, one bit for each frame pending ACK in Tx window - * @bitmap1: High order, one bit for each frame pending ACK in Tx window - * @rate_n_flags: Rate at which Tx was attempted - * - * If REPLY_TX indicates that aggregation was attempted, driver must wait - * for block ack (REPLY_COMPRESSED_BA). This struct stores tx reply info - * until block ack arrives. - */ -struct iwl4965_ht_agg { - u16 txq_id; - u16 frame_count; - u16 wait_for_ba; - u16 start_idx; - u64 bitmap; - u32 rate_n_flags; -#define IWL_AGG_OFF 0 -#define IWL_AGG_ON 1 -#define IWL_EMPTYING_HW_QUEUE_ADDBA 2 -#define IWL_EMPTYING_HW_QUEUE_DELBA 3 - u8 state; -}; - -#endif /* CONFIG_IWL4965_HT */ - -struct iwl4965_tid_data { - u16 seq_number; - u16 tfds_in_queue; -#ifdef CONFIG_IWL4965_HT - struct iwl4965_ht_agg agg; -#endif /* CONFIG_IWL4965_HT */ -}; - -struct iwl4965_hw_key { - enum ieee80211_key_alg alg; - int keylen; - u8 keyidx; - struct ieee80211_key_conf *conf; - u8 key[32]; -}; - -union iwl4965_ht_rate_supp { - u16 rates; - struct { - u8 siso_rate; - u8 mimo_rate; - }; -}; - -#ifdef CONFIG_IWL4965_HT -#define CFG_HT_RX_AMPDU_FACTOR_DEF (0x3) -#define CFG_HT_MPDU_DENSITY_2USEC (0x5) -#define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_2USEC - -struct iwl_ht_info { - /* self configuration data */ - u8 is_ht; - u8 supported_chan_width; - u16 tx_mimo_ps_mode; - u8 is_green_field; - u8 sgf; /* HT_SHORT_GI_* short guard interval */ - u8 max_amsdu_size; - u8 ampdu_factor; - u8 mpdu_density; - u8 supp_mcs_set[16]; - /* BSS related data */ - u8 control_channel; - u8 extension_chan_offset; - u8 tx_chan_width; - u8 ht_protection; - u8 non_GF_STA_present; -}; -#endif /*CONFIG_IWL4965_HT */ - -union iwl4965_qos_capabity { - struct { - u8 edca_count:4; /* bit 0-3 */ - u8 q_ack:1; /* bit 4 */ - u8 queue_request:1; /* bit 5 */ - u8 txop_request:1; /* bit 6 */ - u8 reserved:1; /* bit 7 */ - } q_AP; - struct { - u8 acvo_APSD:1; /* bit 0 */ - u8 acvi_APSD:1; /* bit 1 */ - u8 ac_bk_APSD:1; /* bit 2 */ - u8 ac_be_APSD:1; /* bit 3 */ - u8 q_ack:1; /* bit 4 */ - u8 max_len:2; /* bit 5-6 */ - u8 more_data_ack:1; /* bit 7 */ - } q_STA; - u8 val; -}; - -/* QoS structures */ -struct iwl4965_qos_info { - int qos_enable; - int qos_active; - union iwl4965_qos_capabity qos_cap; - struct iwl4965_qosparam_cmd def_qos_parm; -}; - -#define STA_PS_STATUS_WAKE 0 -#define STA_PS_STATUS_SLEEP 1 - -struct iwl4965_station_entry { - struct iwl4965_addsta_cmd sta; - struct iwl4965_tid_data tid[MAX_TID_COUNT]; - u8 used; - u8 ps_status; - struct iwl4965_hw_key keyinfo; -}; - -/* one for each uCode image (inst/data, boot/init/runtime) */ -struct fw_desc { - void *v_addr; /* access by driver */ - dma_addr_t p_addr; /* access by card's busmaster DMA */ - u32 len; /* bytes */ -}; - -/* uCode file layout */ -struct iwl4965_ucode { - __le32 ver; /* major/minor/subminor */ - __le32 inst_size; /* bytes of runtime instructions */ - __le32 data_size; /* bytes of runtime data */ - __le32 init_size; /* bytes of initialization instructions */ - __le32 init_data_size; /* bytes of initialization data */ - __le32 boot_size; /* bytes of bootstrap instructions */ - u8 data[0]; /* data in same order as "size" elements */ -}; - -#define IWL_IBSS_MAC_HASH_SIZE 32 - -struct iwl4965_ibss_seq { - u8 mac[ETH_ALEN]; - u16 seq_num; - u16 frag_num; - unsigned long packet_time; - struct list_head list; -}; - -struct iwl_sensitivity_ranges { - u16 min_nrg_cck; - u16 max_nrg_cck; - - u16 nrg_th_cck; - u16 nrg_th_ofdm; - - u16 auto_corr_min_ofdm; - u16 auto_corr_min_ofdm_mrc; - u16 auto_corr_min_ofdm_x1; - u16 auto_corr_min_ofdm_mrc_x1; - - u16 auto_corr_max_ofdm; - u16 auto_corr_max_ofdm_mrc; - u16 auto_corr_max_ofdm_x1; - u16 auto_corr_max_ofdm_mrc_x1; - - u16 auto_corr_max_cck; - u16 auto_corr_max_cck_mrc; - u16 auto_corr_min_cck; - u16 auto_corr_min_cck_mrc; -}; - - -#define IWL_FAT_CHANNEL_52 BIT(IEEE80211_BAND_5GHZ) - -/** - * struct iwl_hw_params - * @max_txq_num: Max # Tx queues supported - * @tx_cmd_len: Size of Tx command (but not including frame itself) - * @tx/rx_chains_num: Number of TX/RX chains - * @valid_tx/rx_ant: usable antennas - * @max_rxq_size: Max # Rx frames in Rx queue (must be power-of-2) - * @max_rxq_log: Log-base-2 of max_rxq_size - * @rx_buf_size: Rx buffer size - * @max_stations: - * @bcast_sta_id: - * @fat_channel: is 40MHz width possible in band 2.4 - * BIT(IEEE80211_BAND_5GHZ) BIT(IEEE80211_BAND_5GHZ) - * @sw_crypto: 0 for hw, 1 for sw - * @max_xxx_size: for ucode uses - * @ct_kill_threshold: temperature threshold - * @struct iwl_sensitivity_ranges: range of sensitivity values - */ -struct iwl_hw_params { - u16 max_txq_num; - u16 tx_cmd_len; - u8 tx_chains_num; - u8 rx_chains_num; - u8 valid_tx_ant; - u8 valid_rx_ant; - u16 max_rxq_size; - u16 max_rxq_log; - u32 rx_buf_size; - u32 max_pkt_size; - u8 max_stations; - u8 bcast_sta_id; - u8 fat_channel; - u8 sw_crypto; - u32 max_inst_size; - u32 max_data_size; - u32 max_bsm_size; - u32 ct_kill_threshold; /* value in hw-dependent units */ -#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB - const struct iwl_sensitivity_ranges *sens; -#endif -}; - -#define HT_SHORT_GI_20MHZ_ONLY (1 << 0) -#define HT_SHORT_GI_40MHZ_ONLY (1 << 1) - - -#define IWL_RX_HDR(x) ((struct iwl4965_rx_frame_hdr *)(\ - x->u.rx_frame.stats.payload + \ - x->u.rx_frame.stats.phy_count)) -#define IWL_RX_END(x) ((struct iwl4965_rx_frame_end *)(\ - IWL_RX_HDR(x)->payload + \ - le16_to_cpu(IWL_RX_HDR(x)->len))) -#define IWL_RX_STATS(x) (&x->u.rx_frame.stats) -#define IWL_RX_DATA(x) (IWL_RX_HDR(x)->payload) - - -/****************************************************************************** - * - * Functions implemented in iwl-base.c which are forward declared here - * for use by iwl-*.c - * - *****************************************************************************/ -struct iwl4965_addsta_cmd; -extern int iwl4965_send_add_station(struct iwl_priv *priv, - struct iwl4965_addsta_cmd *sta, u8 flags); -extern u8 iwl4965_add_station_flags(struct iwl_priv *priv, const u8 *addr, - int is_ap, u8 flags, void *ht_data); -extern int iwl4965_is_network_packet(struct iwl_priv *priv, - struct ieee80211_hdr *header); -extern int iwl4965_power_init_handle(struct iwl_priv *priv); -extern void iwl4965_handle_data_packet_monitor(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb, - void *data, short len, - struct ieee80211_rx_status *stats, - u16 phy_flags); -extern int iwl4965_is_duplicate_packet(struct iwl_priv *priv, - struct ieee80211_hdr *header); -extern int iwl4965_rx_queue_alloc(struct iwl_priv *priv); -extern void iwl4965_rx_queue_reset(struct iwl_priv *priv, - struct iwl4965_rx_queue *rxq); -extern int iwl4965_calc_db_from_ratio(int sig_ratio); -extern int iwl4965_calc_sig_qual(int rssi_dbm, int noise_dbm); -extern int iwl4965_tx_queue_init(struct iwl_priv *priv, - struct iwl4965_tx_queue *txq, int count, u32 id); -extern void iwl4965_rx_replenish(void *data); -extern void iwl4965_tx_queue_free(struct iwl_priv *priv, struct iwl4965_tx_queue *txq); -extern unsigned int iwl4965_fill_beacon_frame(struct iwl_priv *priv, - struct ieee80211_hdr *hdr, - const u8 *dest, int left); -extern int iwl4965_rx_queue_update_write_ptr(struct iwl_priv *priv, - struct iwl4965_rx_queue *q); -extern __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr); -extern void iwl4965_update_chain_flags(struct iwl_priv *priv); -int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src); - -int iwl4965_init_geos(struct iwl_priv *priv); -void iwl4965_free_geos(struct iwl_priv *priv); - -extern const u8 iwl4965_broadcast_addr[ETH_ALEN]; -int iwl4965_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd); - -/* - * Currently used by iwl-3945-rs... look at restructuring so that it doesn't - * call this... todo... fix that. -*/ -extern u8 iwl4965_sync_station(struct iwl_priv *priv, int sta_id, - u16 tx_rate, u8 flags); - -/****************************************************************************** - * - * Functions implemented in iwl-[34]*.c which are forward declared here - * for use by iwl-base.c - * - * NOTE: The implementation of these functions are hardware specific - * which is why they are in the hardware specific files (vs. iwl-base.c) - * - * Naming convention -- - * iwl4965_ <-- Its part of iwlwifi (should be changed to iwl4965_) - * iwl4965_hw_ <-- Hardware specific (implemented in iwl-XXXX.c by all HW) - * iwlXXXX_ <-- Hardware specific (implemented in iwl-XXXX.c for XXXX) - * iwl4965_bg_ <-- Called from work queue context - * iwl4965_mac_ <-- mac80211 callback - * - ****************************************************************************/ -extern void iwl4965_hw_setup_deferred_work(struct iwl_priv *priv); -extern void iwl4965_hw_cancel_deferred_work(struct iwl_priv *priv); -extern int iwl4965_hw_rxq_stop(struct iwl_priv *priv); -extern int iwl4965_hw_set_hw_params(struct iwl_priv *priv); -extern int iwl4965_hw_nic_init(struct iwl_priv *priv); -extern int iwl4965_hw_nic_stop_master(struct iwl_priv *priv); -extern void iwl4965_hw_txq_ctx_free(struct iwl_priv *priv); -extern void iwl4965_hw_txq_ctx_stop(struct iwl_priv *priv); -extern int iwl4965_hw_nic_reset(struct iwl_priv *priv); -extern int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *tfd, - dma_addr_t addr, u16 len); -extern int iwl4965_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl4965_tx_queue *txq); -extern int iwl4965_hw_get_temperature(struct iwl_priv *priv); -extern int iwl4965_hw_tx_queue_init(struct iwl_priv *priv, - struct iwl4965_tx_queue *txq); -extern unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, - struct iwl4965_frame *frame, u8 rate); -extern int iwl4965_hw_get_rx_read(struct iwl_priv *priv); -extern void iwl4965_hw_build_tx_cmd_rate(struct iwl_priv *priv, - struct iwl_cmd *cmd, - struct ieee80211_tx_control *ctrl, - struct ieee80211_hdr *hdr, - int sta_id, int tx_id); -extern int iwl4965_hw_reg_send_txpower(struct iwl_priv *priv); -extern int iwl4965_hw_reg_set_txpower(struct iwl_priv *priv, s8 power); -extern void iwl4965_hw_rx_statistics(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb); -extern void iwl4965_disable_events(struct iwl_priv *priv); -extern int iwl4965_get_temperature(const struct iwl_priv *priv); - -/** - * iwl_find_station - Find station id for a given BSSID - * @bssid: MAC address of station ID to find - * - * NOTE: This should not be hardware specific but the code has - * not yet been merged into a single common layer for managing the - * station tables. - */ -extern u8 iwl_find_station(struct iwl_priv *priv, const u8 *bssid); - -extern int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel); -extern int iwl4965_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index); -extern int iwl4965_queue_space(const struct iwl4965_queue *q); -struct iwl_priv; - -extern void iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio); -/* - * Forward declare iwl-4965.c functions for iwl-base.c - */ -extern int iwl4965_tx_queue_update_wr_ptr(struct iwl_priv *priv, - struct iwl4965_tx_queue *txq, - u16 byte_cnt); -extern void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, - int is_ap); -extern int iwl4965_alive_notify(struct iwl_priv *priv); -extern void iwl4965_update_rate_scaling(struct iwl_priv *priv, u8 mode); -extern void iwl4965_rf_kill_ct_config(struct iwl_priv *priv); -extern void iwl4965_hwrate_to_tx_control(struct iwl_priv *priv, - u32 rate_n_flags, - struct ieee80211_tx_control *control); - -#ifdef CONFIG_IWL4965_HT -extern void iwl4965_init_ht_hw_capab(const struct iwl_priv *priv, - struct ieee80211_ht_info *ht_info, - enum ieee80211_band band); -void iwl4965_set_rxon_ht(struct iwl_priv *priv, - struct iwl_ht_info *ht_info); -void iwl4965_set_ht_add_station(struct iwl_priv *priv, u8 index, - struct ieee80211_ht_info *sta_ht_inf); -int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, - enum ieee80211_ampdu_mlme_action action, - const u8 *addr, u16 tid, u16 *ssn); -int iwl4965_check_empty_hw_queue(struct iwl_priv *priv, int sta_id, - u8 tid, int txq_id); -#else -static inline void iwl4965_init_ht_hw_capab(const struct iwl_priv *priv, - struct ieee80211_ht_info *ht_info, - enum ieee80211_band band) {} - -#endif /*CONFIG_IWL4965_HT */ -/* Structures, enum, and defines specific to the 4965 */ - -#define IWL4965_KW_SIZE 0x1000 /*4k */ - -struct iwl4965_kw { - dma_addr_t dma_addr; - void *v_addr; - size_t size; -}; - -#define IWL_CHANNEL_WIDTH_20MHZ 0 -#define IWL_CHANNEL_WIDTH_40MHZ 1 - -#define IWL_MIMO_PS_STATIC 0 -#define IWL_MIMO_PS_NONE 3 -#define IWL_MIMO_PS_DYNAMIC 1 -#define IWL_MIMO_PS_INVALID 2 - -#define IWL_OPERATION_MODE_AUTO 0 -#define IWL_OPERATION_MODE_HT_ONLY 1 -#define IWL_OPERATION_MODE_MIXED 2 -#define IWL_OPERATION_MODE_20MHZ 3 - -#define IWL_EXT_CHANNEL_OFFSET_NONE 0 -#define IWL_EXT_CHANNEL_OFFSET_ABOVE 1 -#define IWL_EXT_CHANNEL_OFFSET_RESERVE1 2 -#define IWL_EXT_CHANNEL_OFFSET_BELOW 3 - -#define IWL_TX_CRC_SIZE 4 -#define IWL_TX_DELIMITER_SIZE 4 - -#define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000 - -struct iwl4965_lq_mngr { - spinlock_t lock; - s32 max_window_size; - s32 *expected_tpt; - u8 *next_higher_rate; - u8 *next_lower_rate; - unsigned long stamp; - unsigned long stamp_last; - u32 flush_time; - u32 tx_packets; - u8 lq_ready; -}; - -/* Sensitivity and chain noise calibration */ -#define INTERFERENCE_DATA_AVAILABLE __constant_cpu_to_le32(1) -#define INITIALIZATION_VALUE 0xFFFF -#define CAL_NUM_OF_BEACONS 20 -#define MAXIMUM_ALLOWED_PATHLOSS 15 - -#define CHAIN_NOISE_MAX_DELTA_GAIN_CODE 3 - -#define MAX_FA_OFDM 50 -#define MIN_FA_OFDM 5 -#define MAX_FA_CCK 50 -#define MIN_FA_CCK 5 - -#define AUTO_CORR_STEP_OFDM 1 - -#define AUTO_CORR_STEP_CCK 3 -#define AUTO_CORR_MAX_TH_CCK 160 - -#define NRG_DIFF 2 -#define NRG_STEP_CCK 2 -#define NRG_MARGIN 8 -#define MAX_NUMBER_CCK_NO_FA 100 - -#define AUTO_CORR_CCK_MIN_VAL_DEF (125) - -#define CHAIN_A 0 -#define CHAIN_B 1 -#define CHAIN_C 2 -#define CHAIN_NOISE_DELTA_GAIN_INIT_VAL 4 -#define ALL_BAND_FILTER 0xFF00 -#define IN_BAND_FILTER 0xFF -#define MIN_AVERAGE_NOISE_MAX_VALUE 0xFFFFFFFF - -#define NRG_NUM_PREV_STAT_L 20 -#define NUM_RX_CHAINS 3 - -enum iwl4965_false_alarm_state { - IWL_FA_TOO_MANY = 0, - IWL_FA_TOO_FEW = 1, - IWL_FA_GOOD_RANGE = 2, -}; - -enum iwl4965_chain_noise_state { - IWL_CHAIN_NOISE_ALIVE = 0, /* must be 0 */ - IWL_CHAIN_NOISE_ACCUMULATE = 1, - IWL_CHAIN_NOISE_CALIBRATED = 2, -}; - -enum iwl4965_calib_enabled_state { - IWL_CALIB_DISABLED = 0, /* must be 0 */ - IWL_CALIB_ENABLED = 1, -}; - -struct statistics_general_data { - u32 beacon_silence_rssi_a; - u32 beacon_silence_rssi_b; - u32 beacon_silence_rssi_c; - u32 beacon_energy_a; - u32 beacon_energy_b; - u32 beacon_energy_c; -}; - -#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB -/* Sensitivity calib data */ -struct iwl_sensitivity_data { - u32 auto_corr_ofdm; - u32 auto_corr_ofdm_mrc; - u32 auto_corr_ofdm_x1; - u32 auto_corr_ofdm_mrc_x1; - u32 auto_corr_cck; - u32 auto_corr_cck_mrc; - - u32 last_bad_plcp_cnt_ofdm; - u32 last_fa_cnt_ofdm; - u32 last_bad_plcp_cnt_cck; - u32 last_fa_cnt_cck; - - u32 nrg_curr_state; - u32 nrg_prev_state; - u32 nrg_value[10]; - u8 nrg_silence_rssi[NRG_NUM_PREV_STAT_L]; - u32 nrg_silence_ref; - u32 nrg_energy_idx; - u32 nrg_silence_idx; - u32 nrg_th_cck; - s32 nrg_auto_corr_silence_diff; - u32 num_in_cck_no_fa; - u32 nrg_th_ofdm; -}; - -/* Chain noise (differential Rx gain) calib data */ -struct iwl_chain_noise_data { - u8 state; - u16 beacon_count; - u32 chain_noise_a; - u32 chain_noise_b; - u32 chain_noise_c; - u32 chain_signal_a; - u32 chain_signal_b; - u32 chain_signal_c; - u8 disconn_array[NUM_RX_CHAINS]; - u8 delta_gain_code[NUM_RX_CHAINS]; - u8 radio_write; -}; -#endif /* CONFIG_IWLWIFI_RUN_TIME_CALIB */ - -#define EEPROM_SEM_TIMEOUT 10 /* milliseconds */ -#define EEPROM_SEM_RETRY_LIMIT 1000 /* number of attempts (not time) */ - - -#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT - -enum { - MEASUREMENT_READY = (1 << 0), - MEASUREMENT_ACTIVE = (1 << 1), -}; - -#endif - -#define IWL_MAX_NUM_QUEUES 20 /* FIXME: do dynamic allocation */ - -struct iwl_priv { - - /* ieee device used by generic ieee processing code */ - struct ieee80211_hw *hw; - struct ieee80211_channel *ieee_channels; - struct ieee80211_rate *ieee_rates; - struct iwl_cfg *cfg; - - /* temporary frame storage list */ - struct list_head free_frames; - int frames_count; - - enum ieee80211_band band; - int alloc_rxb_skb; - bool add_radiotap; - - void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb); - - struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS]; - -#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT - /* spectrum measurement report caching */ - struct iwl4965_spectrum_notification measure_report; - u8 measurement_status; -#endif - /* ucode beacon time */ - u32 ucode_beacon_time; - - /* we allocate array of iwl4965_channel_info for NIC's valid channels. - * Access via channel # using indirect index array */ - struct iwl_channel_info *channel_info; /* channel info array */ - u8 channel_count; /* # of channels */ - - /* each calibration channel group in the EEPROM has a derived - * clip setting for each rate. */ - const struct iwl4965_clip_group clip_groups[5]; - - /* thermal calibration */ - s32 temperature; /* degrees Kelvin */ - s32 last_temperature; - - /* Scan related variables */ - unsigned long last_scan_jiffies; - unsigned long next_scan_jiffies; - unsigned long scan_start; - unsigned long scan_pass_start; - unsigned long scan_start_tsf; - int scan_bands; - int one_direct_scan; - u8 direct_ssid_len; - u8 direct_ssid[IW_ESSID_MAX_SIZE]; - struct iwl4965_scan_cmd *scan; - - /* spinlock */ - spinlock_t lock; /* protect general shared data */ - spinlock_t hcmd_lock; /* protect hcmd */ - struct mutex mutex; - - /* basic pci-network driver stuff */ - struct pci_dev *pci_dev; - - /* pci hardware address support */ - void __iomem *hw_base; - u32 hw_rev; - u32 hw_wa_rev; - u8 rev_id; - - /* uCode images, save to reload in case of failure */ - struct fw_desc ucode_code; /* runtime inst */ - struct fw_desc ucode_data; /* runtime data original */ - struct fw_desc ucode_data_backup; /* runtime data save/restore */ - struct fw_desc ucode_init; /* initialization inst */ - struct fw_desc ucode_init_data; /* initialization data */ - struct fw_desc ucode_boot; /* bootstrap inst */ - - - struct iwl4965_rxon_time_cmd rxon_timing; - - /* We declare this const so it can only be - * changed via explicit cast within the - * routines that actually update the physical - * hardware */ - const struct iwl4965_rxon_cmd active_rxon; - struct iwl4965_rxon_cmd staging_rxon; - - int error_recovering; - struct iwl4965_rxon_cmd recovery_rxon; - - /* 1st responses from initialize and runtime uCode images. - * 4965's initialize alive response contains some calibration data. */ - struct iwl4965_init_alive_resp card_alive_init; - struct iwl4965_alive_resp card_alive; -#ifdef CONFIG_IWLWIFI_RFKILL - struct iwl_rfkill_mngr rfkill_mngr; -#endif - -#ifdef CONFIG_IWLWIFI_LEDS - struct iwl4965_led led[IWL_LED_TRG_MAX]; - unsigned long last_blink_time; - u8 last_blink_rate; - u8 allow_blinking; - u64 led_tpt; -#endif - - u16 active_rate; - u16 active_rate_basic; - - u8 assoc_station_added; - u8 use_ant_b_for_management_frame; /* Tx antenna selection */ - u8 start_calib; -#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB - struct iwl_sensitivity_data sensitivity_data; - struct iwl_chain_noise_data chain_noise_data; - __le16 sensitivity_tbl[HD_TABLE_SIZE]; -#endif /*CONFIG_IWLWIFI_RUN_TIME_CALIB*/ - -#ifdef CONFIG_IWL4965_HT - struct iwl_ht_info current_ht_config; -#endif - u8 last_phy_res[100]; - - /* Rate scaling data */ - struct iwl4965_lq_mngr lq_mngr; - - /* Rate scaling data */ - s8 data_retry_limit; - u8 retry_rate; - - wait_queue_head_t wait_command_queue; - - int activity_timer_active; - - /* Rx and Tx DMA processing queues */ - struct iwl4965_rx_queue rxq; - struct iwl4965_tx_queue txq[IWL_MAX_NUM_QUEUES]; - unsigned long txq_ctx_active_msk; - struct iwl4965_kw kw; /* keep warm address */ - u32 scd_base_addr; /* scheduler sram base address */ - - unsigned long status; - - int last_rx_rssi; /* From Rx packet statisitics */ - int last_rx_noise; /* From beacon statistics */ - - /* counts mgmt, ctl, and data packets */ - struct traffic_stats { - u32 cnt; - u64 bytes; - } tx_stats[3], rx_stats[3]; - - struct iwl_power_mgr power_data; - - struct iwl4965_notif_statistics statistics; - unsigned long last_statistics_time; - - /* context information */ - u8 essid[IW_ESSID_MAX_SIZE]; - u8 essid_len; - u16 rates_mask; - - u32 power_mode; - u32 antenna; - u8 bssid[ETH_ALEN]; - u16 rts_threshold; - u8 mac_addr[ETH_ALEN]; - - /*station table variables */ - spinlock_t sta_lock; - int num_stations; - struct iwl4965_station_entry stations[IWL_STATION_COUNT]; - struct iwl_wep_key wep_keys[WEP_KEYS_MAX]; - u8 default_wep_key; - u8 key_mapping_key; - unsigned long ucode_key_table; - - /* Indication if ieee80211_ops->open has been called */ - u8 is_open; - - u8 mac80211_registered; - - u32 notif_missed_beacons; - - /* Rx'd packet timing information */ - u32 last_beacon_time; - u64 last_tsf; - - /* Duplicate packet detection */ - u16 last_seq_num; - u16 last_frag_num; - unsigned long last_packet_time; - - /* Hash table for finding stations in IBSS network */ - struct list_head ibss_mac_hash[IWL_IBSS_MAC_HASH_SIZE]; - - /* eeprom */ - u8 *eeprom; - struct iwl_eeprom_calib_info *calib_info; - - enum ieee80211_if_types iw_mode; - - struct sk_buff *ibss_beacon; - - /* Last Rx'd beacon timestamp */ - u64 timestamp; - u16 beacon_int; - struct ieee80211_vif *vif; - - struct iwl_hw_params hw_params; - /* driver/uCode shared Tx Byte Counts and Rx status */ - void *shared_virt; - /* Physical Pointer to Tx Byte Counts and Rx status */ - dma_addr_t shared_phys; - - /* Current association information needed to configure the - * hardware */ - u16 assoc_id; - u16 assoc_capability; - u8 ps_mode; - - struct iwl4965_qos_info qos_data; - - struct workqueue_struct *workqueue; - - struct work_struct up; - struct work_struct restart; - struct work_struct calibrated_work; - struct work_struct scan_completed; - struct work_struct rx_replenish; - struct work_struct rf_kill; - struct work_struct abort_scan; - struct work_struct update_link_led; - struct work_struct auth_work; - struct work_struct report_work; - struct work_struct request_scan; - struct work_struct beacon_update; - - struct tasklet_struct irq_tasklet; - - struct delayed_work init_alive_start; - struct delayed_work alive_start; - struct delayed_work activity_timer; - struct delayed_work thermal_periodic; - struct delayed_work gather_stats; - struct delayed_work scan_check; - struct delayed_work post_associate; - -#define IWL_DEFAULT_TX_POWER 0x0F - s8 user_txpower_limit; - s8 max_channel_txpower_limit; - -#ifdef CONFIG_PM - u32 pm_state[16]; -#endif - -#ifdef CONFIG_IWLWIFI_DEBUG - /* debugging info */ - u32 framecnt_to_us; - atomic_t restrict_refcnt; -#ifdef CONFIG_IWLWIFI_DEBUGFS - /* debugfs */ - struct iwl_debugfs *dbgfs; -#endif /* CONFIG_IWLWIFI_DEBUGFS */ -#endif /* CONFIG_IWLWIFI_DEBUG */ - - struct work_struct txpower_work; -#ifdef CONFIG_IWL4965_RUN_TIME_CALIB - struct work_struct sensitivity_work; -#endif - struct timer_list statistics_periodic; -}; /*iwl_priv */ - -static inline int iwl_is_associated(struct iwl_priv *priv) -{ - return (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0; -} - -static inline int is_channel_valid(const struct iwl_channel_info *ch_info) -{ - if (ch_info == NULL) - return 0; - return (ch_info->flags & EEPROM_CHANNEL_VALID) ? 1 : 0; -} - -static inline int is_channel_radar(const struct iwl_channel_info *ch_info) -{ - return (ch_info->flags & EEPROM_CHANNEL_RADAR) ? 1 : 0; -} - -static inline u8 is_channel_a_band(const struct iwl_channel_info *ch_info) -{ - return ch_info->band == IEEE80211_BAND_5GHZ; -} - -static inline u8 is_channel_bg_band(const struct iwl_channel_info *ch_info) -{ - return ch_info->band == IEEE80211_BAND_2GHZ; -} - -static inline int is_channel_passive(const struct iwl_channel_info *ch) -{ - return (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) ? 1 : 0; -} - -static inline int is_channel_ibss(const struct iwl_channel_info *ch) -{ - return ((ch->flags & EEPROM_CHANNEL_IBSS)) ? 1 : 0; -} - -extern const struct iwl_channel_info *iwl_get_channel_info( - const struct iwl_priv *priv, enum ieee80211_band band, u16 channel); - -/* Requires full declaration of iwl_priv before including */ - -#endif /* __iwl4965_4965_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index df628353667..0d8ef63f871 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -38,7 +38,7 @@ #include #include "iwl-eeprom.h" -#include "iwl-4965.h" +#include "iwl-dev.h" #include "iwl-core.h" #include "iwl-io.h" #include "iwl-helpers.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index 59bbd7c9636..1289d4c91ab 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -63,7 +63,7 @@ #include #include -#include "iwl-4965.h" +#include "iwl-dev.h" #include "iwl-core.h" #include "iwl-calib.h" #include "iwl-eeprom.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.h b/drivers/net/wireless/iwlwifi/iwl-calib.h index c3a3db31199..933b0b0a797 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.h +++ b/drivers/net/wireless/iwlwifi/iwl-calib.h @@ -69,7 +69,7 @@ #include #include "iwl-eeprom.h" #include "iwl-core.h" -#include "iwl-4965.h" +#include "iwl-dev.h" #ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB void iwl_chain_noise_calibration(struct iwl_priv *priv, diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 25950551b1b..5afa7b79b59 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -63,7 +63,7 @@ /* * Please use this file (iwl-commands.h) only for uCode API definitions. * Please use iwl-4965-hw.h for hardware-related definitions. - * Please use iwl-4965.h for driver implementation definitions. + * Please use iwl-dev.h for driver implementation definitions. */ #ifndef __iwl4965_commands_h__ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 8c8b51dea57..27e5f496bc1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -34,7 +34,7 @@ struct iwl_priv; /* FIXME: remove */ #include "iwl-debug.h" #include "iwl-eeprom.h" -#include "iwl-4965.h" /* FIXME: remove */ +#include "iwl-dev.h" /* FIXME: remove */ #include "iwl-core.h" #include "iwl-io.h" #include "iwl-rfkill.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 9a30e1df311..30914453de1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -34,7 +34,7 @@ #include -#include "iwl-4965.h" +#include "iwl-dev.h" #include "iwl-debug.h" #include "iwl-core.h" #include "iwl-io.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h new file mode 100644 index 00000000000..78aba21bc18 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -0,0 +1,1260 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ +/* + * Please use this file (iwl-dev.h) for driver implementation definitions. + * Please use iwl-commands.h for uCode API definitions. + * Please use iwl-4965-hw.h for hardware-related definitions. + */ + +#ifndef __iwl_4965_h__ +#define __iwl_4965_h__ + +#include /* for struct pci_device_id */ +#include +#include + +#define DRV_NAME "iwl4965" +#include "iwl-rfkill.h" +#include "iwl-eeprom.h" +#include "iwl-4965-hw.h" +#include "iwl-csr.h" +#include "iwl-prph.h" +#include "iwl-debug.h" +#include "iwl-led.h" +#include "iwl-power.h" + +/* configuration for the iwl4965 */ +extern struct iwl_cfg iwl4965_agn_cfg; +extern struct iwl_cfg iwl5300_agn_cfg; +extern struct iwl_cfg iwl5100_agn_cfg; +extern struct iwl_cfg iwl5350_agn_cfg; + +/* Change firmware file name, using "-" and incrementing number, + * *only* when uCode interface or architecture changes so that it + * is not compatible with earlier drivers. + * This number will also appear in << 8 position of 1st dword of uCode file */ +#define IWL4965_UCODE_API "-1" + +/* CT-KILL constants */ +#define CT_KILL_THRESHOLD 110 /* in Celsius */ + +/* 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) + * 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. + * 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 + * averages within an s8's (used in some apps) range of negative values. */ +#define IWL_NOISE_MEAS_NOT_AVAILABLE (-127) + +/* + * RTS threshold here is total size [2347] minus 4 FCS bytes + * Per spec: + * a value of 0 means RTS on all data/management packets + * a value > max MSDU size means no RTS + * else RTS for data/management frames where MPDU is larger + * than RTS value. + */ +#define DEFAULT_RTS_THRESHOLD 2347U +#define MIN_RTS_THRESHOLD 0U +#define MAX_RTS_THRESHOLD 2347U +#define MAX_MSDU_SIZE 2304U +#define MAX_MPDU_SIZE 2346U +#define DEFAULT_BEACON_INTERVAL 100U +#define DEFAULT_SHORT_RETRY_LIMIT 7U +#define DEFAULT_LONG_RETRY_LIMIT 4U + +struct iwl4965_rx_mem_buffer { + dma_addr_t dma_addr; + struct sk_buff *skb; + struct list_head list; +}; + +/* + * Generic queue structure + * + * Contains common data for Rx and Tx queues + */ +struct iwl4965_queue { + int n_bd; /* number of BDs in this queue */ + int write_ptr; /* 1-st empty entry (index) host_w*/ + int read_ptr; /* last used entry (index) host_r*/ + dma_addr_t dma_addr; /* physical addr for BD's */ + int n_window; /* safe queue window */ + u32 id; + int low_mark; /* low watermark, resume queue if free + * space more than this */ + int high_mark; /* high watermark, stop queue if free + * space less than this */ +} __attribute__ ((packed)); + +#define MAX_NUM_OF_TBS (20) + +/* One for each TFD */ +struct iwl4965_tx_info { + struct ieee80211_tx_status status; + struct sk_buff *skb[MAX_NUM_OF_TBS]; +}; + +/** + * struct iwl4965_tx_queue - Tx Queue for DMA + * @q: generic Rx/Tx queue descriptor + * @bd: base of circular buffer of TFDs + * @cmd: array of command/Tx buffers + * @dma_addr_cmd: physical address of cmd/tx buffer array + * @txb: array of per-TFD driver data + * @need_update: indicates need to update read/write index + * @sched_retry: indicates queue is high-throughput aggregation (HT AGG) enabled + * + * A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame + * descriptors) and required locking structures. + */ +struct iwl4965_tx_queue { + struct iwl4965_queue q; + struct iwl4965_tfd_frame *bd; + struct iwl_cmd *cmd; + dma_addr_t dma_addr_cmd; + struct iwl4965_tx_info *txb; + int need_update; + int sched_retry; + int active; +}; + +#define IWL_NUM_SCAN_RATES (2) + +struct iwl4965_channel_tgd_info { + u8 type; + s8 max_power; +}; + +struct iwl4965_channel_tgh_info { + s64 last_radar_time; +}; + +/* current Tx power values to use, one for each rate for each channel. + * requested power is limited by: + * -- regulatory EEPROM limits for this channel + * -- hardware capabilities (clip-powers) + * -- spectrum management + * -- user preference (e.g. iwconfig) + * when requested power is set, base power index must also be set. */ +struct iwl4965_channel_power_info { + struct iwl4965_tx_power tpc; /* actual radio and DSP gain settings */ + s8 power_table_index; /* actual (compenst'd) index into gain table */ + s8 base_power_index; /* gain index for power at factory temp. */ + s8 requested_power; /* power (dBm) requested for this chnl/rate */ +}; + +/* current scan Tx power values to use, one for each scan rate for each + * channel. */ +struct iwl4965_scan_power_info { + struct iwl4965_tx_power tpc; /* actual radio and DSP gain settings */ + s8 power_table_index; /* actual (compenst'd) index into gain table */ + s8 requested_power; /* scan pwr (dBm) requested for chnl/rate */ +}; + +/* For fat_extension_channel */ +enum { + HT_IE_EXT_CHANNEL_NONE = 0, + HT_IE_EXT_CHANNEL_ABOVE, + HT_IE_EXT_CHANNEL_INVALID, + HT_IE_EXT_CHANNEL_BELOW, + HT_IE_EXT_CHANNEL_MAX +}; + +/* + * One for each channel, holds all channel setup data + * Some of the fields (e.g. eeprom and flags/max_power_avg) are redundant + * with one another! + */ +#define IWL4965_MAX_RATE (33) + +struct iwl_channel_info { + struct iwl4965_channel_tgd_info tgd; + struct iwl4965_channel_tgh_info tgh; + struct iwl_eeprom_channel eeprom; /* EEPROM regulatory limit */ + struct iwl_eeprom_channel fat_eeprom; /* EEPROM regulatory limit for + * FAT channel */ + + u8 channel; /* channel number */ + u8 flags; /* flags copied from EEPROM */ + s8 max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */ + s8 curr_txpow; /* (dBm) regulatory/spectrum/user (not h/w) limit */ + s8 min_power; /* always 0 */ + s8 scan_power; /* (dBm) regul. eeprom, direct scans, any rate */ + + u8 group_index; /* 0-4, maps channel to group1/2/3/4/5 */ + u8 band_index; /* 0-4, maps channel to band1/2/3/4/5 */ + enum ieee80211_band band; + + /* Radio/DSP gain settings for each "normal" data Tx rate. + * These include, in addition to RF and DSP gain, a few fields for + * remembering/modifying gain settings (indexes). */ + struct iwl4965_channel_power_info power_info[IWL4965_MAX_RATE]; + + /* FAT channel info */ + s8 fat_max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */ + s8 fat_curr_txpow; /* (dBm) regulatory/spectrum/user (not h/w) */ + s8 fat_min_power; /* always 0 */ + s8 fat_scan_power; /* (dBm) eeprom, direct scans, any rate */ + u8 fat_flags; /* flags copied from EEPROM */ + u8 fat_extension_channel; /* HT_IE_EXT_CHANNEL_* */ + + /* Radio/DSP gain settings for each scan rate, for directed scans. */ + struct iwl4965_scan_power_info scan_pwr_info[IWL_NUM_SCAN_RATES]; +}; + +struct iwl4965_clip_group { + /* maximum power level to prevent clipping for each rate, derived by + * us from this band's saturation power in EEPROM */ + const s8 clip_powers[IWL_MAX_RATES]; +}; + +#include "iwl-4965-rs.h" + +#define IWL_TX_FIFO_AC0 0 +#define IWL_TX_FIFO_AC1 1 +#define IWL_TX_FIFO_AC2 2 +#define IWL_TX_FIFO_AC3 3 +#define IWL_TX_FIFO_HCCA_1 5 +#define IWL_TX_FIFO_HCCA_2 6 +#define IWL_TX_FIFO_NONE 7 + +/* Minimum number of queues. MAX_NUM is defined in hw specific files */ +#define IWL_MIN_NUM_QUEUES 4 + +/* Power management (not Tx power) structures */ + +enum iwl_pwr_src { + IWL_PWR_SRC_VMAIN, + IWL_PWR_SRC_VAUX, +}; + +#define IEEE80211_DATA_LEN 2304 +#define IEEE80211_4ADDR_LEN 30 +#define IEEE80211_HLEN (IEEE80211_4ADDR_LEN) +#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN) + +struct iwl4965_frame { + union { + struct ieee80211_hdr frame; + struct iwl4965_tx_beacon_cmd beacon; + u8 raw[IEEE80211_FRAME_LEN]; + u8 cmd[360]; + } u; + struct list_head list; +}; + +#define SEQ_TO_QUEUE(x) ((x >> 8) & 0xbf) +#define QUEUE_TO_SEQ(x) ((x & 0xbf) << 8) +#define SEQ_TO_INDEX(x) ((u8)(x & 0xff)) +#define INDEX_TO_SEQ(x) ((u8)(x & 0xff)) +#define SEQ_HUGE_FRAME (0x4000) +#define SEQ_RX_FRAME __constant_cpu_to_le16(0x8000) +#define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4) +#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ) +#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4) + +enum { + /* CMD_SIZE_NORMAL = 0, */ + CMD_SIZE_HUGE = (1 << 0), + /* CMD_SYNC = 0, */ + CMD_ASYNC = (1 << 1), + /* CMD_NO_SKB = 0, */ + CMD_WANT_SKB = (1 << 2), +}; + +struct iwl_cmd; +struct iwl_priv; + +struct iwl_cmd_meta { + struct iwl_cmd_meta *source; + union { + struct sk_buff *skb; + int (*callback)(struct iwl_priv *priv, + struct iwl_cmd *cmd, struct sk_buff *skb); + } __attribute__ ((packed)) u; + + /* The CMD_SIZE_HUGE flag bit indicates that the command + * structure is stored at the end of the shared queue memory. */ + u32 flags; + +} __attribute__ ((packed)); + +/** + * struct iwl_cmd + * + * For allocation of the command and tx queues, this establishes the overall + * size of the largest command we send to uCode, except for a scan command + * (which is relatively huge; space is allocated separately). + */ +struct iwl_cmd { + struct iwl_cmd_meta meta; /* driver data */ + struct iwl_cmd_header hdr; /* uCode API */ + union { + struct iwl4965_addsta_cmd addsta; + struct iwl4965_led_cmd led; + u32 flags; + u8 val8; + u16 val16; + u32 val32; + struct iwl4965_bt_cmd bt; + struct iwl4965_rxon_time_cmd rxon_time; + struct iwl4965_powertable_cmd powertable; + struct iwl4965_qosparam_cmd qosparam; + struct iwl4965_tx_cmd tx; + struct iwl4965_tx_beacon_cmd tx_beacon; + struct iwl4965_rxon_assoc_cmd rxon_assoc; + u8 *indirect; + u8 payload[360]; + } __attribute__ ((packed)) cmd; +} __attribute__ ((packed)); + +struct iwl_host_cmd { + u8 id; + u16 len; + struct iwl_cmd_meta meta; + const void *data; +}; + +#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_cmd) - \ + sizeof(struct iwl_cmd_meta)) + +/* + * RX related structures and functions + */ +#define RX_FREE_BUFFERS 64 +#define RX_LOW_WATERMARK 8 + +#define SUP_RATE_11A_MAX_NUM_CHANNELS 8 +#define SUP_RATE_11B_MAX_NUM_CHANNELS 4 +#define SUP_RATE_11G_MAX_NUM_CHANNELS 12 + +/** + * struct iwl4965_rx_queue - Rx queue + * @processed: Internal index to last handled Rx packet + * @read: Shared index to newest available Rx buffer + * @write: Shared index to oldest written Rx packet + * @free_count: Number of pre-allocated buffers in rx_free + * @rx_free: list of free SKBs for use + * @rx_used: List of Rx buffers with no SKB + * @need_update: flag to indicate we need to update read/write index + * + * NOTE: rx_free and rx_used are used as a FIFO for iwl4965_rx_mem_buffers + */ +struct iwl4965_rx_queue { + __le32 *bd; + dma_addr_t dma_addr; + struct iwl4965_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS]; + struct iwl4965_rx_mem_buffer *queue[RX_QUEUE_SIZE]; + u32 processed; + u32 read; + u32 write; + u32 free_count; + struct list_head rx_free; + struct list_head rx_used; + int need_update; + spinlock_t lock; +}; + +#define IWL_SUPPORTED_RATES_IE_LEN 8 + +#define SCAN_INTERVAL 100 + +#define MAX_A_CHANNELS 252 +#define MIN_A_CHANNELS 7 + +#define MAX_B_CHANNELS 14 +#define MIN_B_CHANNELS 1 + +#define MAX_TID_COUNT 9 + +#define IWL_INVALID_RATE 0xFF +#define IWL_INVALID_VALUE -1 + +#ifdef CONFIG_IWL4965_HT +/** + * struct iwl4965_ht_agg -- aggregation status while waiting for block-ack + * @txq_id: Tx queue used for Tx attempt + * @frame_count: # frames attempted by Tx command + * @wait_for_ba: Expect block-ack before next Tx reply + * @start_idx: Index of 1st Transmit Frame Descriptor (TFD) in Tx window + * @bitmap0: Low order bitmap, one bit for each frame pending ACK in Tx window + * @bitmap1: High order, one bit for each frame pending ACK in Tx window + * @rate_n_flags: Rate at which Tx was attempted + * + * If REPLY_TX indicates that aggregation was attempted, driver must wait + * for block ack (REPLY_COMPRESSED_BA). This struct stores tx reply info + * until block ack arrives. + */ +struct iwl4965_ht_agg { + u16 txq_id; + u16 frame_count; + u16 wait_for_ba; + u16 start_idx; + u64 bitmap; + u32 rate_n_flags; +#define IWL_AGG_OFF 0 +#define IWL_AGG_ON 1 +#define IWL_EMPTYING_HW_QUEUE_ADDBA 2 +#define IWL_EMPTYING_HW_QUEUE_DELBA 3 + u8 state; +}; + +#endif /* CONFIG_IWL4965_HT */ + +struct iwl4965_tid_data { + u16 seq_number; + u16 tfds_in_queue; +#ifdef CONFIG_IWL4965_HT + struct iwl4965_ht_agg agg; +#endif /* CONFIG_IWL4965_HT */ +}; + +struct iwl4965_hw_key { + enum ieee80211_key_alg alg; + int keylen; + u8 keyidx; + struct ieee80211_key_conf *conf; + u8 key[32]; +}; + +union iwl4965_ht_rate_supp { + u16 rates; + struct { + u8 siso_rate; + u8 mimo_rate; + }; +}; + +#ifdef CONFIG_IWL4965_HT +#define CFG_HT_RX_AMPDU_FACTOR_DEF (0x3) +#define CFG_HT_MPDU_DENSITY_2USEC (0x5) +#define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_2USEC + +struct iwl_ht_info { + /* self configuration data */ + u8 is_ht; + u8 supported_chan_width; + u16 tx_mimo_ps_mode; + u8 is_green_field; + u8 sgf; /* HT_SHORT_GI_* short guard interval */ + u8 max_amsdu_size; + u8 ampdu_factor; + u8 mpdu_density; + u8 supp_mcs_set[16]; + /* BSS related data */ + u8 control_channel; + u8 extension_chan_offset; + u8 tx_chan_width; + u8 ht_protection; + u8 non_GF_STA_present; +}; +#endif /*CONFIG_IWL4965_HT */ + +union iwl4965_qos_capabity { + struct { + u8 edca_count:4; /* bit 0-3 */ + u8 q_ack:1; /* bit 4 */ + u8 queue_request:1; /* bit 5 */ + u8 txop_request:1; /* bit 6 */ + u8 reserved:1; /* bit 7 */ + } q_AP; + struct { + u8 acvo_APSD:1; /* bit 0 */ + u8 acvi_APSD:1; /* bit 1 */ + u8 ac_bk_APSD:1; /* bit 2 */ + u8 ac_be_APSD:1; /* bit 3 */ + u8 q_ack:1; /* bit 4 */ + u8 max_len:2; /* bit 5-6 */ + u8 more_data_ack:1; /* bit 7 */ + } q_STA; + u8 val; +}; + +/* QoS structures */ +struct iwl4965_qos_info { + int qos_enable; + int qos_active; + union iwl4965_qos_capabity qos_cap; + struct iwl4965_qosparam_cmd def_qos_parm; +}; + +#define STA_PS_STATUS_WAKE 0 +#define STA_PS_STATUS_SLEEP 1 + +struct iwl4965_station_entry { + struct iwl4965_addsta_cmd sta; + struct iwl4965_tid_data tid[MAX_TID_COUNT]; + u8 used; + u8 ps_status; + struct iwl4965_hw_key keyinfo; +}; + +/* one for each uCode image (inst/data, boot/init/runtime) */ +struct fw_desc { + void *v_addr; /* access by driver */ + dma_addr_t p_addr; /* access by card's busmaster DMA */ + u32 len; /* bytes */ +}; + +/* uCode file layout */ +struct iwl4965_ucode { + __le32 ver; /* major/minor/subminor */ + __le32 inst_size; /* bytes of runtime instructions */ + __le32 data_size; /* bytes of runtime data */ + __le32 init_size; /* bytes of initialization instructions */ + __le32 init_data_size; /* bytes of initialization data */ + __le32 boot_size; /* bytes of bootstrap instructions */ + u8 data[0]; /* data in same order as "size" elements */ +}; + +#define IWL_IBSS_MAC_HASH_SIZE 32 + +struct iwl4965_ibss_seq { + u8 mac[ETH_ALEN]; + u16 seq_num; + u16 frag_num; + unsigned long packet_time; + struct list_head list; +}; + +struct iwl_sensitivity_ranges { + u16 min_nrg_cck; + u16 max_nrg_cck; + + u16 nrg_th_cck; + u16 nrg_th_ofdm; + + u16 auto_corr_min_ofdm; + u16 auto_corr_min_ofdm_mrc; + u16 auto_corr_min_ofdm_x1; + u16 auto_corr_min_ofdm_mrc_x1; + + u16 auto_corr_max_ofdm; + u16 auto_corr_max_ofdm_mrc; + u16 auto_corr_max_ofdm_x1; + u16 auto_corr_max_ofdm_mrc_x1; + + u16 auto_corr_max_cck; + u16 auto_corr_max_cck_mrc; + u16 auto_corr_min_cck; + u16 auto_corr_min_cck_mrc; +}; + + +#define IWL_FAT_CHANNEL_52 BIT(IEEE80211_BAND_5GHZ) + +/** + * struct iwl_hw_params + * @max_txq_num: Max # Tx queues supported + * @tx_cmd_len: Size of Tx command (but not including frame itself) + * @tx/rx_chains_num: Number of TX/RX chains + * @valid_tx/rx_ant: usable antennas + * @max_rxq_size: Max # Rx frames in Rx queue (must be power-of-2) + * @max_rxq_log: Log-base-2 of max_rxq_size + * @rx_buf_size: Rx buffer size + * @max_stations: + * @bcast_sta_id: + * @fat_channel: is 40MHz width possible in band 2.4 + * BIT(IEEE80211_BAND_5GHZ) BIT(IEEE80211_BAND_5GHZ) + * @sw_crypto: 0 for hw, 1 for sw + * @max_xxx_size: for ucode uses + * @ct_kill_threshold: temperature threshold + * @struct iwl_sensitivity_ranges: range of sensitivity values + */ +struct iwl_hw_params { + u16 max_txq_num; + u16 tx_cmd_len; + u8 tx_chains_num; + u8 rx_chains_num; + u8 valid_tx_ant; + u8 valid_rx_ant; + u16 max_rxq_size; + u16 max_rxq_log; + u32 rx_buf_size; + u32 max_pkt_size; + u8 max_stations; + u8 bcast_sta_id; + u8 fat_channel; + u8 sw_crypto; + u32 max_inst_size; + u32 max_data_size; + u32 max_bsm_size; + u32 ct_kill_threshold; /* value in hw-dependent units */ +#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB + const struct iwl_sensitivity_ranges *sens; +#endif +}; + +#define HT_SHORT_GI_20MHZ_ONLY (1 << 0) +#define HT_SHORT_GI_40MHZ_ONLY (1 << 1) + + +#define IWL_RX_HDR(x) ((struct iwl4965_rx_frame_hdr *)(\ + x->u.rx_frame.stats.payload + \ + x->u.rx_frame.stats.phy_count)) +#define IWL_RX_END(x) ((struct iwl4965_rx_frame_end *)(\ + IWL_RX_HDR(x)->payload + \ + le16_to_cpu(IWL_RX_HDR(x)->len))) +#define IWL_RX_STATS(x) (&x->u.rx_frame.stats) +#define IWL_RX_DATA(x) (IWL_RX_HDR(x)->payload) + + +/****************************************************************************** + * + * Functions implemented in iwl-base.c which are forward declared here + * for use by iwl-*.c + * + *****************************************************************************/ +struct iwl4965_addsta_cmd; +extern int iwl4965_send_add_station(struct iwl_priv *priv, + struct iwl4965_addsta_cmd *sta, u8 flags); +extern u8 iwl4965_add_station_flags(struct iwl_priv *priv, const u8 *addr, + int is_ap, u8 flags, void *ht_data); +extern int iwl4965_is_network_packet(struct iwl_priv *priv, + struct ieee80211_hdr *header); +extern int iwl4965_power_init_handle(struct iwl_priv *priv); +extern void iwl4965_handle_data_packet_monitor(struct iwl_priv *priv, + struct iwl4965_rx_mem_buffer *rxb, + void *data, short len, + struct ieee80211_rx_status *stats, + u16 phy_flags); +extern int iwl4965_is_duplicate_packet(struct iwl_priv *priv, + struct ieee80211_hdr *header); +extern int iwl4965_rx_queue_alloc(struct iwl_priv *priv); +extern void iwl4965_rx_queue_reset(struct iwl_priv *priv, + struct iwl4965_rx_queue *rxq); +extern int iwl4965_calc_db_from_ratio(int sig_ratio); +extern int iwl4965_calc_sig_qual(int rssi_dbm, int noise_dbm); +extern int iwl4965_tx_queue_init(struct iwl_priv *priv, + struct iwl4965_tx_queue *txq, int count, u32 id); +extern void iwl4965_rx_replenish(void *data); +extern void iwl4965_tx_queue_free(struct iwl_priv *priv, struct iwl4965_tx_queue *txq); +extern unsigned int iwl4965_fill_beacon_frame(struct iwl_priv *priv, + struct ieee80211_hdr *hdr, + const u8 *dest, int left); +extern int iwl4965_rx_queue_update_write_ptr(struct iwl_priv *priv, + struct iwl4965_rx_queue *q); +extern __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr); +extern void iwl4965_update_chain_flags(struct iwl_priv *priv); +int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src); + +int iwl4965_init_geos(struct iwl_priv *priv); +void iwl4965_free_geos(struct iwl_priv *priv); + +extern const u8 iwl4965_broadcast_addr[ETH_ALEN]; +int iwl4965_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd); + +/* + * Currently used by iwl-3945-rs... look at restructuring so that it doesn't + * call this... todo... fix that. +*/ +extern u8 iwl4965_sync_station(struct iwl_priv *priv, int sta_id, + u16 tx_rate, u8 flags); + +/****************************************************************************** + * + * Functions implemented in iwl-[34]*.c which are forward declared here + * for use by iwl-base.c + * + * NOTE: The implementation of these functions are hardware specific + * which is why they are in the hardware specific files (vs. iwl-base.c) + * + * Naming convention -- + * iwl4965_ <-- Its part of iwlwifi (should be changed to iwl4965_) + * iwl4965_hw_ <-- Hardware specific (implemented in iwl-XXXX.c by all HW) + * iwlXXXX_ <-- Hardware specific (implemented in iwl-XXXX.c for XXXX) + * iwl4965_bg_ <-- Called from work queue context + * iwl4965_mac_ <-- mac80211 callback + * + ****************************************************************************/ +extern void iwl4965_hw_setup_deferred_work(struct iwl_priv *priv); +extern void iwl4965_hw_cancel_deferred_work(struct iwl_priv *priv); +extern int iwl4965_hw_rxq_stop(struct iwl_priv *priv); +extern int iwl4965_hw_set_hw_params(struct iwl_priv *priv); +extern int iwl4965_hw_nic_init(struct iwl_priv *priv); +extern int iwl4965_hw_nic_stop_master(struct iwl_priv *priv); +extern void iwl4965_hw_txq_ctx_free(struct iwl_priv *priv); +extern void iwl4965_hw_txq_ctx_stop(struct iwl_priv *priv); +extern int iwl4965_hw_nic_reset(struct iwl_priv *priv); +extern int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *tfd, + dma_addr_t addr, u16 len); +extern int iwl4965_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl4965_tx_queue *txq); +extern int iwl4965_hw_get_temperature(struct iwl_priv *priv); +extern int iwl4965_hw_tx_queue_init(struct iwl_priv *priv, + struct iwl4965_tx_queue *txq); +extern unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, + struct iwl4965_frame *frame, u8 rate); +extern int iwl4965_hw_get_rx_read(struct iwl_priv *priv); +extern void iwl4965_hw_build_tx_cmd_rate(struct iwl_priv *priv, + struct iwl_cmd *cmd, + struct ieee80211_tx_control *ctrl, + struct ieee80211_hdr *hdr, + int sta_id, int tx_id); +extern int iwl4965_hw_reg_send_txpower(struct iwl_priv *priv); +extern int iwl4965_hw_reg_set_txpower(struct iwl_priv *priv, s8 power); +extern void iwl4965_hw_rx_statistics(struct iwl_priv *priv, + struct iwl4965_rx_mem_buffer *rxb); +extern void iwl4965_disable_events(struct iwl_priv *priv); +extern int iwl4965_get_temperature(const struct iwl_priv *priv); + +/** + * iwl_find_station - Find station id for a given BSSID + * @bssid: MAC address of station ID to find + * + * NOTE: This should not be hardware specific but the code has + * not yet been merged into a single common layer for managing the + * station tables. + */ +extern u8 iwl_find_station(struct iwl_priv *priv, const u8 *bssid); + +extern int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel); +extern int iwl4965_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index); +extern int iwl4965_queue_space(const struct iwl4965_queue *q); +struct iwl_priv; + +extern void iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio); +/* + * Forward declare iwl-4965.c functions for iwl-base.c + */ +extern int iwl4965_tx_queue_update_wr_ptr(struct iwl_priv *priv, + struct iwl4965_tx_queue *txq, + u16 byte_cnt); +extern void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, + int is_ap); +extern int iwl4965_alive_notify(struct iwl_priv *priv); +extern void iwl4965_update_rate_scaling(struct iwl_priv *priv, u8 mode); +extern void iwl4965_rf_kill_ct_config(struct iwl_priv *priv); +extern void iwl4965_hwrate_to_tx_control(struct iwl_priv *priv, + u32 rate_n_flags, + struct ieee80211_tx_control *control); + +#ifdef CONFIG_IWL4965_HT +extern void iwl4965_init_ht_hw_capab(const struct iwl_priv *priv, + struct ieee80211_ht_info *ht_info, + enum ieee80211_band band); +void iwl4965_set_rxon_ht(struct iwl_priv *priv, + struct iwl_ht_info *ht_info); +void iwl4965_set_ht_add_station(struct iwl_priv *priv, u8 index, + struct ieee80211_ht_info *sta_ht_inf); +int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, + enum ieee80211_ampdu_mlme_action action, + const u8 *addr, u16 tid, u16 *ssn); +int iwl4965_check_empty_hw_queue(struct iwl_priv *priv, int sta_id, + u8 tid, int txq_id); +#else +static inline void iwl4965_init_ht_hw_capab(const struct iwl_priv *priv, + struct ieee80211_ht_info *ht_info, + enum ieee80211_band band) {} + +#endif /*CONFIG_IWL4965_HT */ +/* Structures, enum, and defines specific to the 4965 */ + +#define IWL4965_KW_SIZE 0x1000 /*4k */ + +struct iwl4965_kw { + dma_addr_t dma_addr; + void *v_addr; + size_t size; +}; + +#define IWL_CHANNEL_WIDTH_20MHZ 0 +#define IWL_CHANNEL_WIDTH_40MHZ 1 + +#define IWL_MIMO_PS_STATIC 0 +#define IWL_MIMO_PS_NONE 3 +#define IWL_MIMO_PS_DYNAMIC 1 +#define IWL_MIMO_PS_INVALID 2 + +#define IWL_OPERATION_MODE_AUTO 0 +#define IWL_OPERATION_MODE_HT_ONLY 1 +#define IWL_OPERATION_MODE_MIXED 2 +#define IWL_OPERATION_MODE_20MHZ 3 + +#define IWL_EXT_CHANNEL_OFFSET_NONE 0 +#define IWL_EXT_CHANNEL_OFFSET_ABOVE 1 +#define IWL_EXT_CHANNEL_OFFSET_RESERVE1 2 +#define IWL_EXT_CHANNEL_OFFSET_BELOW 3 + +#define IWL_TX_CRC_SIZE 4 +#define IWL_TX_DELIMITER_SIZE 4 + +#define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000 + +struct iwl4965_lq_mngr { + spinlock_t lock; + s32 max_window_size; + s32 *expected_tpt; + u8 *next_higher_rate; + u8 *next_lower_rate; + unsigned long stamp; + unsigned long stamp_last; + u32 flush_time; + u32 tx_packets; + u8 lq_ready; +}; + +/* Sensitivity and chain noise calibration */ +#define INTERFERENCE_DATA_AVAILABLE __constant_cpu_to_le32(1) +#define INITIALIZATION_VALUE 0xFFFF +#define CAL_NUM_OF_BEACONS 20 +#define MAXIMUM_ALLOWED_PATHLOSS 15 + +#define CHAIN_NOISE_MAX_DELTA_GAIN_CODE 3 + +#define MAX_FA_OFDM 50 +#define MIN_FA_OFDM 5 +#define MAX_FA_CCK 50 +#define MIN_FA_CCK 5 + +#define AUTO_CORR_STEP_OFDM 1 + +#define AUTO_CORR_STEP_CCK 3 +#define AUTO_CORR_MAX_TH_CCK 160 + +#define NRG_DIFF 2 +#define NRG_STEP_CCK 2 +#define NRG_MARGIN 8 +#define MAX_NUMBER_CCK_NO_FA 100 + +#define AUTO_CORR_CCK_MIN_VAL_DEF (125) + +#define CHAIN_A 0 +#define CHAIN_B 1 +#define CHAIN_C 2 +#define CHAIN_NOISE_DELTA_GAIN_INIT_VAL 4 +#define ALL_BAND_FILTER 0xFF00 +#define IN_BAND_FILTER 0xFF +#define MIN_AVERAGE_NOISE_MAX_VALUE 0xFFFFFFFF + +#define NRG_NUM_PREV_STAT_L 20 +#define NUM_RX_CHAINS 3 + +enum iwl4965_false_alarm_state { + IWL_FA_TOO_MANY = 0, + IWL_FA_TOO_FEW = 1, + IWL_FA_GOOD_RANGE = 2, +}; + +enum iwl4965_chain_noise_state { + IWL_CHAIN_NOISE_ALIVE = 0, /* must be 0 */ + IWL_CHAIN_NOISE_ACCUMULATE = 1, + IWL_CHAIN_NOISE_CALIBRATED = 2, +}; + +enum iwl4965_calib_enabled_state { + IWL_CALIB_DISABLED = 0, /* must be 0 */ + IWL_CALIB_ENABLED = 1, +}; + +struct statistics_general_data { + u32 beacon_silence_rssi_a; + u32 beacon_silence_rssi_b; + u32 beacon_silence_rssi_c; + u32 beacon_energy_a; + u32 beacon_energy_b; + u32 beacon_energy_c; +}; + +#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB +/* Sensitivity calib data */ +struct iwl_sensitivity_data { + u32 auto_corr_ofdm; + u32 auto_corr_ofdm_mrc; + u32 auto_corr_ofdm_x1; + u32 auto_corr_ofdm_mrc_x1; + u32 auto_corr_cck; + u32 auto_corr_cck_mrc; + + u32 last_bad_plcp_cnt_ofdm; + u32 last_fa_cnt_ofdm; + u32 last_bad_plcp_cnt_cck; + u32 last_fa_cnt_cck; + + u32 nrg_curr_state; + u32 nrg_prev_state; + u32 nrg_value[10]; + u8 nrg_silence_rssi[NRG_NUM_PREV_STAT_L]; + u32 nrg_silence_ref; + u32 nrg_energy_idx; + u32 nrg_silence_idx; + u32 nrg_th_cck; + s32 nrg_auto_corr_silence_diff; + u32 num_in_cck_no_fa; + u32 nrg_th_ofdm; +}; + +/* Chain noise (differential Rx gain) calib data */ +struct iwl_chain_noise_data { + u8 state; + u16 beacon_count; + u32 chain_noise_a; + u32 chain_noise_b; + u32 chain_noise_c; + u32 chain_signal_a; + u32 chain_signal_b; + u32 chain_signal_c; + u8 disconn_array[NUM_RX_CHAINS]; + u8 delta_gain_code[NUM_RX_CHAINS]; + u8 radio_write; +}; +#endif /* CONFIG_IWLWIFI_RUN_TIME_CALIB */ + +#define EEPROM_SEM_TIMEOUT 10 /* milliseconds */ +#define EEPROM_SEM_RETRY_LIMIT 1000 /* number of attempts (not time) */ + + +#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT + +enum { + MEASUREMENT_READY = (1 << 0), + MEASUREMENT_ACTIVE = (1 << 1), +}; + +#endif + +#define IWL_MAX_NUM_QUEUES 20 /* FIXME: do dynamic allocation */ + +struct iwl_priv { + + /* ieee device used by generic ieee processing code */ + struct ieee80211_hw *hw; + struct ieee80211_channel *ieee_channels; + struct ieee80211_rate *ieee_rates; + struct iwl_cfg *cfg; + + /* temporary frame storage list */ + struct list_head free_frames; + int frames_count; + + enum ieee80211_band band; + int alloc_rxb_skb; + bool add_radiotap; + + void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv, + struct iwl4965_rx_mem_buffer *rxb); + + struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS]; + +#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT + /* spectrum measurement report caching */ + struct iwl4965_spectrum_notification measure_report; + u8 measurement_status; +#endif + /* ucode beacon time */ + u32 ucode_beacon_time; + + /* we allocate array of iwl4965_channel_info for NIC's valid channels. + * Access via channel # using indirect index array */ + struct iwl_channel_info *channel_info; /* channel info array */ + u8 channel_count; /* # of channels */ + + /* each calibration channel group in the EEPROM has a derived + * clip setting for each rate. */ + const struct iwl4965_clip_group clip_groups[5]; + + /* thermal calibration */ + s32 temperature; /* degrees Kelvin */ + s32 last_temperature; + + /* Scan related variables */ + unsigned long last_scan_jiffies; + unsigned long next_scan_jiffies; + unsigned long scan_start; + unsigned long scan_pass_start; + unsigned long scan_start_tsf; + int scan_bands; + int one_direct_scan; + u8 direct_ssid_len; + u8 direct_ssid[IW_ESSID_MAX_SIZE]; + struct iwl4965_scan_cmd *scan; + + /* spinlock */ + spinlock_t lock; /* protect general shared data */ + spinlock_t hcmd_lock; /* protect hcmd */ + struct mutex mutex; + + /* basic pci-network driver stuff */ + struct pci_dev *pci_dev; + + /* pci hardware address support */ + void __iomem *hw_base; + u32 hw_rev; + u32 hw_wa_rev; + u8 rev_id; + + /* uCode images, save to reload in case of failure */ + struct fw_desc ucode_code; /* runtime inst */ + struct fw_desc ucode_data; /* runtime data original */ + struct fw_desc ucode_data_backup; /* runtime data save/restore */ + struct fw_desc ucode_init; /* initialization inst */ + struct fw_desc ucode_init_data; /* initialization data */ + struct fw_desc ucode_boot; /* bootstrap inst */ + + + struct iwl4965_rxon_time_cmd rxon_timing; + + /* We declare this const so it can only be + * changed via explicit cast within the + * routines that actually update the physical + * hardware */ + const struct iwl4965_rxon_cmd active_rxon; + struct iwl4965_rxon_cmd staging_rxon; + + int error_recovering; + struct iwl4965_rxon_cmd recovery_rxon; + + /* 1st responses from initialize and runtime uCode images. + * 4965's initialize alive response contains some calibration data. */ + struct iwl4965_init_alive_resp card_alive_init; + struct iwl4965_alive_resp card_alive; +#ifdef CONFIG_IWLWIFI_RFKILL + struct iwl_rfkill_mngr rfkill_mngr; +#endif + +#ifdef CONFIG_IWLWIFI_LEDS + struct iwl4965_led led[IWL_LED_TRG_MAX]; + unsigned long last_blink_time; + u8 last_blink_rate; + u8 allow_blinking; + u64 led_tpt; +#endif + + u16 active_rate; + u16 active_rate_basic; + + u8 assoc_station_added; + u8 use_ant_b_for_management_frame; /* Tx antenna selection */ + u8 start_calib; +#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB + struct iwl_sensitivity_data sensitivity_data; + struct iwl_chain_noise_data chain_noise_data; + __le16 sensitivity_tbl[HD_TABLE_SIZE]; +#endif /*CONFIG_IWLWIFI_RUN_TIME_CALIB*/ + +#ifdef CONFIG_IWL4965_HT + struct iwl_ht_info current_ht_config; +#endif + u8 last_phy_res[100]; + + /* Rate scaling data */ + struct iwl4965_lq_mngr lq_mngr; + + /* Rate scaling data */ + s8 data_retry_limit; + u8 retry_rate; + + wait_queue_head_t wait_command_queue; + + int activity_timer_active; + + /* Rx and Tx DMA processing queues */ + struct iwl4965_rx_queue rxq; + struct iwl4965_tx_queue txq[IWL_MAX_NUM_QUEUES]; + unsigned long txq_ctx_active_msk; + struct iwl4965_kw kw; /* keep warm address */ + u32 scd_base_addr; /* scheduler sram base address */ + + unsigned long status; + + int last_rx_rssi; /* From Rx packet statisitics */ + int last_rx_noise; /* From beacon statistics */ + + /* counts mgmt, ctl, and data packets */ + struct traffic_stats { + u32 cnt; + u64 bytes; + } tx_stats[3], rx_stats[3]; + + struct iwl_power_mgr power_data; + + struct iwl4965_notif_statistics statistics; + unsigned long last_statistics_time; + + /* context information */ + u8 essid[IW_ESSID_MAX_SIZE]; + u8 essid_len; + u16 rates_mask; + + u32 power_mode; + u32 antenna; + u8 bssid[ETH_ALEN]; + u16 rts_threshold; + u8 mac_addr[ETH_ALEN]; + + /*station table variables */ + spinlock_t sta_lock; + int num_stations; + struct iwl4965_station_entry stations[IWL_STATION_COUNT]; + struct iwl_wep_key wep_keys[WEP_KEYS_MAX]; + u8 default_wep_key; + u8 key_mapping_key; + unsigned long ucode_key_table; + + /* Indication if ieee80211_ops->open has been called */ + u8 is_open; + + u8 mac80211_registered; + + u32 notif_missed_beacons; + + /* Rx'd packet timing information */ + u32 last_beacon_time; + u64 last_tsf; + + /* Duplicate packet detection */ + u16 last_seq_num; + u16 last_frag_num; + unsigned long last_packet_time; + + /* Hash table for finding stations in IBSS network */ + struct list_head ibss_mac_hash[IWL_IBSS_MAC_HASH_SIZE]; + + /* eeprom */ + u8 *eeprom; + struct iwl_eeprom_calib_info *calib_info; + + enum ieee80211_if_types iw_mode; + + struct sk_buff *ibss_beacon; + + /* Last Rx'd beacon timestamp */ + u64 timestamp; + u16 beacon_int; + struct ieee80211_vif *vif; + + struct iwl_hw_params hw_params; + /* driver/uCode shared Tx Byte Counts and Rx status */ + void *shared_virt; + /* Physical Pointer to Tx Byte Counts and Rx status */ + dma_addr_t shared_phys; + + /* Current association information needed to configure the + * hardware */ + u16 assoc_id; + u16 assoc_capability; + u8 ps_mode; + + struct iwl4965_qos_info qos_data; + + struct workqueue_struct *workqueue; + + struct work_struct up; + struct work_struct restart; + struct work_struct calibrated_work; + struct work_struct scan_completed; + struct work_struct rx_replenish; + struct work_struct rf_kill; + struct work_struct abort_scan; + struct work_struct update_link_led; + struct work_struct auth_work; + struct work_struct report_work; + struct work_struct request_scan; + struct work_struct beacon_update; + + struct tasklet_struct irq_tasklet; + + struct delayed_work init_alive_start; + struct delayed_work alive_start; + struct delayed_work activity_timer; + struct delayed_work thermal_periodic; + struct delayed_work gather_stats; + struct delayed_work scan_check; + struct delayed_work post_associate; + +#define IWL_DEFAULT_TX_POWER 0x0F + s8 user_txpower_limit; + s8 max_channel_txpower_limit; + +#ifdef CONFIG_PM + u32 pm_state[16]; +#endif + +#ifdef CONFIG_IWLWIFI_DEBUG + /* debugging info */ + u32 framecnt_to_us; + atomic_t restrict_refcnt; +#ifdef CONFIG_IWLWIFI_DEBUGFS + /* debugfs */ + struct iwl_debugfs *dbgfs; +#endif /* CONFIG_IWLWIFI_DEBUGFS */ +#endif /* CONFIG_IWLWIFI_DEBUG */ + + struct work_struct txpower_work; +#ifdef CONFIG_IWL4965_RUN_TIME_CALIB + struct work_struct sensitivity_work; +#endif + struct timer_list statistics_periodic; +}; /*iwl_priv */ + +static inline int iwl_is_associated(struct iwl_priv *priv) +{ + return (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0; +} + +static inline int is_channel_valid(const struct iwl_channel_info *ch_info) +{ + if (ch_info == NULL) + return 0; + return (ch_info->flags & EEPROM_CHANNEL_VALID) ? 1 : 0; +} + +static inline int is_channel_radar(const struct iwl_channel_info *ch_info) +{ + return (ch_info->flags & EEPROM_CHANNEL_RADAR) ? 1 : 0; +} + +static inline u8 is_channel_a_band(const struct iwl_channel_info *ch_info) +{ + return ch_info->band == IEEE80211_BAND_5GHZ; +} + +static inline u8 is_channel_bg_band(const struct iwl_channel_info *ch_info) +{ + return ch_info->band == IEEE80211_BAND_2GHZ; +} + +static inline int is_channel_passive(const struct iwl_channel_info *ch) +{ + return (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) ? 1 : 0; +} + +static inline int is_channel_ibss(const struct iwl_channel_info *ch) +{ + return ((ch->flags & EEPROM_CHANNEL_IBSS)) ? 1 : 0; +} + +extern const struct iwl_channel_info *iwl_get_channel_info( + const struct iwl_priv *priv, enum ieee80211_band band, u16 channel); + +/* Requires full declaration of iwl_priv before including */ + +#endif /* __iwl4965_4965_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 5b2746eeb4a..fa306601a55 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -69,7 +69,7 @@ #include #include "iwl-commands.h" -#include "iwl-4965.h" +#include "iwl-dev.h" #include "iwl-core.h" #include "iwl-debug.h" #include "iwl-eeprom.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index fdb27f1cdc0..acb5a8abd78 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -31,7 +31,7 @@ #include #include -#include "iwl-4965.h" /* FIXME: remove */ +#include "iwl-dev.h" /* FIXME: remove */ #include "iwl-debug.h" #include "iwl-eeprom.h" #include "iwl-core.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 03fdf5b434a..aa6ad18494c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -39,7 +39,7 @@ #include #include -#include "iwl-4965.h" +#include "iwl-dev.h" #include "iwl-core.h" #include "iwl-io.h" #include "iwl-helpers.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index db7f65a5ac2..2e71803e09b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -35,7 +35,7 @@ #include #include "iwl-eeprom.h" -#include "iwl-4965.h" +#include "iwl-dev.h" #include "iwl-core.h" #include "iwl-commands.h" #include "iwl-debug.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.c b/drivers/net/wireless/iwlwifi/iwl-rfkill.c index 5980a5621cb..59c8a716bd9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rfkill.c +++ b/drivers/net/wireless/iwlwifi/iwl-rfkill.c @@ -33,7 +33,7 @@ #include #include "iwl-eeprom.h" -#include "iwl-4965.h" +#include "iwl-dev.h" #include "iwl-core.h" #include "iwl-helpers.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 2eee59824df..31b37a1a643 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -31,7 +31,7 @@ #include #include "iwl-eeprom.h" -#include "iwl-4965.h" +#include "iwl-dev.h" #include "iwl-core.h" #include "iwl-sta.h" #include "iwl-io.h" diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index ea8b9756643..f887a4e54ba 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -46,7 +46,7 @@ #include #include "iwl-eeprom.h" -#include "iwl-4965.h" +#include "iwl-dev.h" #include "iwl-core.h" #include "iwl-io.h" #include "iwl-helpers.h" -- cgit v1.2.3-70-g09d2 From 57ffc589a92424f9def74fe0d49b2f7763ff07fd Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 29 Apr 2008 17:18:59 +0200 Subject: mac80211: clean up get_tx_stats callback The callback takes a ieee80211_tx_queue_stats with a contained array of ieee80211_tx_queue_stats_data, remove the former, rename the latter to ieee80211_tx_queue_stats and make tx_stats() take the array directly. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/adm8211.c | 7 +++---- drivers/net/wireless/ath5k/base.c | 8 ++++---- drivers/net/wireless/ath5k/base.h | 3 ++- drivers/net/wireless/b43/dma.c | 8 +++----- drivers/net/wireless/b43/pio.c | 8 +++----- drivers/net/wireless/b43legacy/dma.c | 8 +++----- drivers/net/wireless/b43legacy/pio.c | 8 +++----- drivers/net/wireless/iwlwifi/iwl3945-base.c | 6 +++--- drivers/net/wireless/iwlwifi/iwl4965-base.c | 6 +++--- drivers/net/wireless/p54/p54.h | 2 +- drivers/net/wireless/p54/p54common.c | 24 ++++++++++-------------- drivers/net/wireless/rt2x00/rt2x00mac.c | 6 +++--- include/net/mac80211.h | 13 ++++--------- 13 files changed, 45 insertions(+), 62 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 5c0d2b08275..d93a1de77eb 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -306,11 +306,10 @@ static int adm8211_get_tx_stats(struct ieee80211_hw *dev, struct ieee80211_tx_queue_stats *stats) { struct adm8211_priv *priv = dev->priv; - struct ieee80211_tx_queue_stats_data *data = &stats->data[0]; - data->len = priv->cur_tx - priv->dirty_tx; - data->limit = priv->tx_ring_size - 2; - data->count = priv->dirty_tx; + stats[0].len = priv->cur_tx - priv->dirty_tx; + stats[0].limit = priv->tx_ring_size - 2; + stats[0].count = priv->dirty_tx; return 0; } diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 3854619f351..3201c160434 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -1335,7 +1335,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, spin_lock_bh(&txq->lock); list_add_tail(&bf->list, &txq->q); - sc->tx_stats.data[txq->qnum].len++; + sc->tx_stats[txq->qnum].len++; if (txq->link == NULL) /* is this first packet? */ ath5k_hw_put_tx_buf(ah, txq->qnum, bf->daddr); else /* no, so only link it */ @@ -1566,7 +1566,7 @@ ath5k_txq_drainq(struct ath5k_softc *sc, struct ath5k_txq *txq) ath5k_txbuf_free(sc, bf); spin_lock_bh(&sc->txbuflock); - sc->tx_stats.data[txq->qnum].len--; + sc->tx_stats[txq->qnum].len--; list_move_tail(&bf->list, &sc->txbuf); sc->txbuf_len++; spin_unlock_bh(&sc->txbuflock); @@ -1979,10 +1979,10 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) } ieee80211_tx_status(sc->hw, skb, &txs); - sc->tx_stats.data[txq->qnum].count++; + sc->tx_stats[txq->qnum].count++; spin_lock(&sc->txbuflock); - sc->tx_stats.data[txq->qnum].len--; + sc->tx_stats[txq->qnum].len--; list_move_tail(&bf->list, &sc->txbuf); sc->txbuf_len++; spin_unlock(&sc->txbuflock); diff --git a/drivers/net/wireless/ath5k/base.h b/drivers/net/wireless/ath5k/base.h index 3a975589301..ecb17495488 100644 --- a/drivers/net/wireless/ath5k/base.h +++ b/drivers/net/wireless/ath5k/base.h @@ -92,7 +92,8 @@ struct ath5k_softc { struct pci_dev *pdev; /* for dma mapping */ void __iomem *iobase; /* address of the device */ struct mutex lock; /* dev-level lock */ - struct ieee80211_tx_queue_stats tx_stats; + /* FIXME: how many does it really need? */ + struct ieee80211_tx_queue_stats tx_stats[16]; struct ieee80211_low_level_stats ll_stats; struct ieee80211_hw *hw; /* IEEE 802.11 common */ struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 6dcbb3c87e7..f50e2014ffb 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -1427,18 +1427,16 @@ void b43_dma_get_tx_stats(struct b43_wldev *dev, { const int nr_queues = dev->wl->hw->queues; struct b43_dmaring *ring; - struct ieee80211_tx_queue_stats_data *data; unsigned long flags; int i; for (i = 0; i < nr_queues; i++) { - data = &(stats->data[i]); ring = select_ring_by_priority(dev, i); spin_lock_irqsave(&ring->lock, flags); - data->len = ring->used_slots / SLOTS_PER_PACKET; - data->limit = ring->nr_slots / SLOTS_PER_PACKET; - data->count = ring->nr_tx_packets; + stats[i].len = ring->used_slots / SLOTS_PER_PACKET; + stats[i].limit = ring->nr_slots / SLOTS_PER_PACKET; + stats[i].count = ring->nr_tx_packets; spin_unlock_irqrestore(&ring->lock, flags); } } diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index fcacafb0434..08c8a087f30 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -611,18 +611,16 @@ void b43_pio_get_tx_stats(struct b43_wldev *dev, { const int nr_queues = dev->wl->hw->queues; struct b43_pio_txqueue *q; - struct ieee80211_tx_queue_stats_data *data; unsigned long flags; int i; for (i = 0; i < nr_queues; i++) { - data = &(stats->data[i]); q = select_queue_by_priority(dev, i); spin_lock_irqsave(&q->lock, flags); - data->len = B43_PIO_MAX_NR_TXPACKETS - q->free_packet_slots; - data->limit = B43_PIO_MAX_NR_TXPACKETS; - data->count = q->nr_tx_packets; + stats[i].len = B43_PIO_MAX_NR_TXPACKETS - q->free_packet_slots; + stats[i].limit = B43_PIO_MAX_NR_TXPACKETS; + stats[i].count = q->nr_tx_packets; spin_unlock_irqrestore(&q->lock, flags); } } diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c index c990f87b107..d6686f713b6 100644 --- a/drivers/net/wireless/b43legacy/dma.c +++ b/drivers/net/wireless/b43legacy/dma.c @@ -1455,18 +1455,16 @@ void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev, { const int nr_queues = dev->wl->hw->queues; struct b43legacy_dmaring *ring; - struct ieee80211_tx_queue_stats_data *data; unsigned long flags; int i; for (i = 0; i < nr_queues; i++) { - data = &(stats->data[i]); ring = priority_to_txring(dev, i); spin_lock_irqsave(&ring->lock, flags); - data->len = ring->used_slots / SLOTS_PER_PACKET; - data->limit = ring->nr_slots / SLOTS_PER_PACKET; - data->count = ring->nr_tx_packets; + stats[i].len = ring->used_slots / SLOTS_PER_PACKET; + stats[i].limit = ring->nr_slots / SLOTS_PER_PACKET; + stats[i].count = ring->nr_tx_packets; spin_unlock_irqrestore(&ring->lock, flags); } } diff --git a/drivers/net/wireless/b43legacy/pio.c b/drivers/net/wireless/b43legacy/pio.c index bcdd54eb2ed..8d3d27d3cd6 100644 --- a/drivers/net/wireless/b43legacy/pio.c +++ b/drivers/net/wireless/b43legacy/pio.c @@ -525,13 +525,11 @@ void b43legacy_pio_get_tx_stats(struct b43legacy_wldev *dev, { struct b43legacy_pio *pio = &dev->pio; struct b43legacy_pioqueue *queue; - struct ieee80211_tx_queue_stats_data *data; queue = pio->queue1; - data = &(stats->data[0]); - data->len = B43legacy_PIO_MAXTXPACKETS - queue->nr_txfree; - data->limit = B43legacy_PIO_MAXTXPACKETS; - data->count = queue->nr_tx_packets; + stats[0].len = B43legacy_PIO_MAXTXPACKETS - queue->nr_txfree; + stats[0].limit = B43legacy_PIO_MAXTXPACKETS; + stats[0].count = queue->nr_tx_packets; } static void pio_rx_error(struct b43legacy_pioqueue *queue, diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 67fd267c99c..bad367cfbee 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -7217,9 +7217,9 @@ static int iwl3945_mac_get_tx_stats(struct ieee80211_hw *hw, q = &txq->q; avail = iwl3945_queue_space(q); - stats->data[i].len = q->n_window - avail; - stats->data[i].limit = q->n_window - q->high_mark; - stats->data[i].count = q->n_window; + stats[i].len = q->n_window - avail; + stats[i].limit = q->n_window - q->high_mark; + stats[i].count = q->n_window; } spin_unlock_irqrestore(&priv->lock, flags); diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index f887a4e54ba..64cb905cdae 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -6420,9 +6420,9 @@ static int iwl4965_mac_get_tx_stats(struct ieee80211_hw *hw, q = &txq->q; avail = iwl4965_queue_space(q); - stats->data[i].len = q->n_window - avail; - stats->data[i].limit = q->n_window - q->high_mark; - stats->data[i].count = q->n_window; + stats[i].len = q->n_window - avail; + stats[i].limit = q->n_window - q->high_mark; + stats[i].count = q->n_window; } spin_unlock_irqrestore(&priv->lock, flags); diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 06d2c67f4c8..c6f27b9022f 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -64,7 +64,7 @@ struct p54_common { unsigned int tx_hdr_len; void *cached_vdcf; unsigned int fw_var; - struct ieee80211_tx_queue_stats tx_stats; + struct ieee80211_tx_queue_stats tx_stats[4]; }; int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb); diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 63f9badf3f5..59a26978f87 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -146,10 +146,10 @@ void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) if (priv->fw_var >= 0x300) { /* Firmware supports QoS, use it! */ - priv->tx_stats.data[0].limit = 3; - priv->tx_stats.data[1].limit = 4; - priv->tx_stats.data[2].limit = 3; - priv->tx_stats.data[3].limit = 1; + priv->tx_stats[0].limit = 3; + priv->tx_stats[1].limit = 4; + priv->tx_stats[2].limit = 3; + priv->tx_stats[3].limit = 1; dev->queues = 4; } } @@ -379,7 +379,7 @@ static void inline p54_wake_free_queues(struct ieee80211_hw *dev) * But, what if some are full? */ for (i = 0; i < dev->queues; i++) - if (priv->tx_stats.data[i].len < priv->tx_stats.data[i].limit) + if (priv->tx_stats[i].len < priv->tx_stats[i].limit) ieee80211_wake_queue(dev, i); } @@ -417,8 +417,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) memcpy(&status.control, range->control, sizeof(status.control)); kfree(range->control); - priv->tx_stats.data[status.control.queue].len--; - + priv->tx_stats[status.control.queue].len--; entry_hdr = (struct p54_control_hdr *) entry->data; entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data; if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0) @@ -555,7 +554,7 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb, struct ieee80211_tx_control *control) { - struct ieee80211_tx_queue_stats_data *current_queue; + struct ieee80211_tx_queue_stats *current_queue; struct p54_common *priv = dev->priv; struct p54_control_hdr *hdr; struct p54_tx_control_allocdata *txhdr; @@ -563,7 +562,7 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb, size_t padding, len; u8 rate; - current_queue = &priv->tx_stats.data[control->queue]; + current_queue = &priv->tx_stats[control->queue]; if (unlikely(current_queue->len > current_queue->limit)) return NETDEV_TX_BUSY; current_queue->len++; @@ -967,11 +966,8 @@ static int p54_get_tx_stats(struct ieee80211_hw *dev, struct ieee80211_tx_queue_stats *stats) { struct p54_common *priv = dev->priv; - unsigned int i; - for (i = 0; i < dev->queues; i++) - memcpy(&stats->data[i], &priv->tx_stats.data[i], - sizeof(stats->data[i])); + memcpy(stats, &priv->tx_stats, sizeof(stats[0]) * dev->queues); return 0; } @@ -1008,7 +1004,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) dev->channel_change_time = 1000; /* TODO: find actual value */ dev->max_rssi = 127; - priv->tx_stats.data[0].limit = 5; + priv->tx_stats[0].limit = 5; dev->queues = 1; dev->extra_tx_headroom = sizeof(struct p54_control_hdr) + 4 + diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index d4ceab7646e..7bc5129484f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -457,9 +457,9 @@ int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw, unsigned int i; for (i = 0; i < hw->queues; i++) { - stats->data[i].len = rt2x00dev->tx[i].length; - stats->data[i].limit = rt2x00dev->tx[i].limit; - stats->data[i].count = rt2x00dev->tx[i].count; + stats[i].len = rt2x00dev->tx[i].length; + stats[i].limit = rt2x00dev->tx[i].limit; + stats[i].count = rt2x00dev->tx[i].count; } return 0; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 740c11ca066..346a7563ef0 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -117,13 +117,13 @@ struct ieee80211_tx_queue_params { }; /** - * struct ieee80211_tx_queue_stats_data - transmit queue statistics + * struct ieee80211_tx_queue_stats - transmit queue statistics * * @len: number of packets in queue * @limit: queue length limit * @count: number of frames sent */ -struct ieee80211_tx_queue_stats_data { +struct ieee80211_tx_queue_stats { unsigned int len; unsigned int limit; unsigned int count; @@ -165,10 +165,6 @@ enum ieee80211_tx_queue { NUM_TX_DATA_QUEUES_AMPDU = 16 }; -struct ieee80211_tx_queue_stats { - struct ieee80211_tx_queue_stats_data data[NUM_TX_DATA_QUEUES_AMPDU]; -}; - struct ieee80211_low_level_stats { unsigned int dot11ACKFailureCount; unsigned int dot11RTSFailureCount; @@ -1083,9 +1079,8 @@ enum ieee80211_ampdu_mlme_action { * @get_tx_stats: Get statistics of the current TX queue status. This is used * to get number of currently queued packets (queue length), maximum queue * size (limit), and total number of packets sent using each TX queue - * (count). This information is used for WMM to find out which TX - * queues have room for more packets and by hostapd to provide - * statistics about the current queueing state to external programs. + * (count). The 'stats' pointer points to an array that has hw->queues + + * hw->ampdu_queues items. * * @get_tsf: Get the current TSF timer value from firmware/hardware. Currently, * this is only used for IBSS mode debugging and, as such, is not a -- cgit v1.2.3-70-g09d2 From 36fc6757fe711def63ea3686bf6ed475d714e114 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 29 Apr 2008 17:19:00 +0200 Subject: mac80211: remove queue info from ieee80211_tx_status The queue info in struct ieee80211_tx_status is never used. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl4965-base.c | 7 ------- drivers/net/wireless/rt2x00/rt2x00dev.c | 3 --- include/net/mac80211.h | 4 ---- 3 files changed, 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 64cb905cdae..5363be7a305 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -2522,8 +2522,6 @@ static void iwl4965_txstatus_to_ieee(struct iwl_priv *priv, tx_sta->status.ack_signal = 0; tx_sta->status.excessive_retries = 0; - tx_sta->status.queue_length = 0; - tx_sta->status.queue_number = 0; if (in_interrupt()) ieee80211_tx_status_irqsafe(priv->hw, @@ -2659,8 +2657,6 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv, tx_status = &(priv->txq[txq_id].txb[idx].status); tx_status->retry_count = tx_resp->failure_frame; - tx_status->queue_number = status & 0xff; - tx_status->queue_length = tx_resp->failure_rts; tx_status->control.flags &= ~IEEE80211_TXCTL_AMPDU; tx_status->flags = iwl4965_is_tx_success(status)? IEEE80211_TX_STATUS_ACK : 0; @@ -2820,9 +2816,6 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, tx_status = &(txq->txb[txq->q.read_ptr].status); tx_status->retry_count = tx_resp->failure_frame; - tx_status->queue_number = status; - tx_status->queue_length = tx_resp->bt_kill_count; - tx_status->queue_length |= tx_resp->failure_rts; tx_status->flags = iwl4965_is_tx_success(status) ? IEEE80211_TX_STATUS_ACK : 0; iwl4965_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags), diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index b1a324dead5..9929b15e28b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -525,9 +525,6 @@ void rt2x00lib_txdone(struct queue_entry *entry, rt2x00dev->low_level_stats.dot11ACKFailureCount++; } - tx_status.queue_length = entry->queue->limit; - tx_status.queue_number = tx_status.control.queue; - if (tx_status.control.flags & IEEE80211_TXCTL_USE_RTS_CTS) { if (success) rt2x00dev->low_level_stats.dot11RTSSuccessCount++; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 346a7563ef0..ef701d6fd66 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -417,8 +417,6 @@ enum ieee80211_tx_status_flags { * @ampdu_ack_map: block ack bit map for the aggregation. * relevant only if IEEE80211_TX_STATUS_AMPDU was set. * @ack_signal: signal strength of the ACK frame - * @queue_length: ?? REMOVE - * @queue_number: ?? REMOVE */ struct ieee80211_tx_status { struct ieee80211_tx_control control; @@ -428,8 +426,6 @@ struct ieee80211_tx_status { u8 ampdu_ack_len; u64 ampdu_ack_map; int ack_signal; - int queue_length; - int queue_number; }; /** -- cgit v1.2.3-70-g09d2 From e100bb64bf7cdeae7f742a65ee1985649a7fd1b4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 30 Apr 2008 18:51:21 +0200 Subject: mac80211: QoS related cleanups This * makes the queue number passed to drivers a u16 (as it will be with skb_get_queue_mapping) * removes the useless queue number defines * splits hw->queues into hw->queues/ampdu_queues * removes the debugfs files for per-queue counters * removes some dead QoS code * removes the beacon queue configuration for IBSS so that the drivers now never get a queue number bigger than (hw->queues + hw->ampdu_queues - 1) for tx and only in the range 0..hw->queues-1 for conf_tx. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 3 +- drivers/net/wireless/b43legacy/main.c | 3 +- drivers/net/wireless/iwlwifi/iwl-core.c | 2 +- drivers/net/wireless/iwlwifi/iwl3945-base.c | 2 +- drivers/net/wireless/iwlwifi/iwl4965-base.c | 2 +- drivers/net/wireless/p54/p54common.c | 2 +- drivers/net/wireless/rt2x00/rt2400pci.c | 5 +- drivers/net/wireless/rt2x00/rt2x00.h | 2 +- drivers/net/wireless/rt2x00/rt2x00mac.c | 2 +- drivers/net/wireless/rt2x00/rt2x00queue.h | 7 +- include/net/mac80211.h | 66 ++++++--------- net/mac80211/debugfs.c | 43 ---------- net/mac80211/debugfs_sta.c | 38 --------- net/mac80211/ieee80211_i.h | 8 +- net/mac80211/main.c | 5 ++ net/mac80211/mlme.c | 23 ++---- net/mac80211/rx.c | 5 -- net/mac80211/sta_info.c | 2 +- net/mac80211/wme.c | 120 ++++++++++++---------------- 19 files changed, 100 insertions(+), 240 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index cf546e367d3..c6e79a15d3c 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -2996,8 +2996,7 @@ static void b43_qos_update_work(struct work_struct *work) mutex_unlock(&wl->mutex); } -static int b43_op_conf_tx(struct ieee80211_hw *hw, - int _queue, +static int b43_op_conf_tx(struct ieee80211_hw *hw, u16 _queue, const struct ieee80211_tx_queue_params *params) { struct b43_wl *wl = hw_to_b43_wl(hw); diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 14a5eea2573..1ccc51e90a8 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -2383,8 +2383,7 @@ out: return NETDEV_TX_OK; } -static int b43legacy_op_conf_tx(struct ieee80211_hw *hw, - int queue, +static int b43legacy_op_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params) { return 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 27e5f496bc1..c4b5c1a100f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -568,7 +568,7 @@ static void iwlcore_init_hw(struct iwl_priv *priv) hw->queues = 4; #ifdef CONFIG_IWL4965_HT /* Enhanced value; more queues, to support 11n aggregation */ - hw->queues = 16; + hw->ampdu_queues = 12; #endif /* CONFIG_IWL4965_HT */ } diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index bad367cfbee..7040cde8bc2 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -7143,7 +7143,7 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return rc; } -static int iwl3945_mac_conf_tx(struct ieee80211_hw *hw, int queue, +static int iwl3945_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params) { struct iwl3945_priv *priv = hw->priv; diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 5363be7a305..4406fc72d88 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -6339,7 +6339,7 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return ret; } -static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, int queue, +static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params) { struct iwl_priv *priv = hw->priv; diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 59a26978f87..34b91ccd8ae 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -935,7 +935,7 @@ static void p54_configure_filter(struct ieee80211_hw *dev, } } -static int p54_conf_tx(struct ieee80211_hw *dev, int queue, +static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue, const struct ieee80211_tx_queue_params *params) { struct p54_common *priv = dev->priv; diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 705bc2d41dc..247fbbfb0f2 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1442,8 +1442,7 @@ static int rt2400pci_set_retry_limit(struct ieee80211_hw *hw, return 0; } -static int rt2400pci_conf_tx(struct ieee80211_hw *hw, - int queue, +static int rt2400pci_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params) { struct rt2x00_dev *rt2x00dev = hw->priv; @@ -1453,7 +1452,7 @@ static int rt2400pci_conf_tx(struct ieee80211_hw *hw, * per queue. So by default we only configure the TX queue, * and ignore all other configurations. */ - if (queue != IEEE80211_TX_QUEUE_DATA0) + if (queue != 0) return -EINVAL; if (rt2x00mac_conf_tx(hw, queue, params)) diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 48a9af47921..79bd9c9f896 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -997,7 +997,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, u32 changes); -int rt2x00mac_conf_tx(struct ieee80211_hw *hw, int queue, +int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params); /* diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 7bc5129484f..767e0ffce04 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -517,7 +517,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, } EXPORT_SYMBOL_GPL(rt2x00mac_bss_info_changed); -int rt2x00mac_conf_tx(struct ieee80211_hw *hw, int queue_idx, +int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, const struct ieee80211_tx_queue_params *params) { struct rt2x00_dev *rt2x00dev = hw->priv; diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 29fe2652555..d1707a7ca41 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -86,12 +86,9 @@ enum data_queue_qid { static inline enum data_queue_qid mac80211_queue_to_qid(unsigned int queue) { /* Regular TX queues are mapped directly */ - if (queue < NUM_TX_DATA_QUEUES) + if (queue < 4) return queue; - else if (queue == IEEE80211_TX_QUEUE_BEACON) - return QID_BEACON; - else if (queue == IEEE80211_TX_QUEUE_AFTER_BEACON) - return QID_ATIM; + WARN_ON(1); return QID_OTHER; } diff --git a/include/net/mac80211.h b/include/net/mac80211.h index ef701d6fd66..75a34609eed 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -97,6 +97,18 @@ struct ieee80211_ht_bss_info { u8 bss_op_mode; /* use IEEE80211_HT_IE_ */ }; +/** + * enum ieee80211_max_queues - maximum number of queues + * + * @IEEE80211_MAX_QUEUES: Maximum number of regular device queues. + * @IEEE80211_MAX_AMPDU_QUEUES: Maximum number of queues usable + * for A-MPDU operation. + */ +enum ieee80211_max_queues { + IEEE80211_MAX_QUEUES = 16, + IEEE80211_MAX_AMPDU_QUEUES = 16, +}; + /** * struct ieee80211_tx_queue_params - transmit queue configuration * @@ -129,42 +141,6 @@ struct ieee80211_tx_queue_stats { unsigned int count; }; -/** - * enum ieee80211_tx_queue - transmit queue number - * - * These constants are used with some callbacks that take a - * queue number to set parameters for a queue. - * - * @IEEE80211_TX_QUEUE_DATA0: data queue 0 - * @IEEE80211_TX_QUEUE_DATA1: data queue 1 - * @IEEE80211_TX_QUEUE_DATA2: data queue 2 - * @IEEE80211_TX_QUEUE_DATA3: data queue 3 - * @IEEE80211_TX_QUEUE_DATA4: data queue 4 - * @IEEE80211_TX_QUEUE_SVP: ?? - * @NUM_TX_DATA_QUEUES: number of data queues - * @IEEE80211_TX_QUEUE_AFTER_BEACON: transmit queue for frames to be - * sent after a beacon - * @IEEE80211_TX_QUEUE_BEACON: transmit queue for beacon frames - * @NUM_TX_DATA_QUEUES_AMPDU: adding more queues for A-MPDU - */ -enum ieee80211_tx_queue { - IEEE80211_TX_QUEUE_DATA0, - IEEE80211_TX_QUEUE_DATA1, - IEEE80211_TX_QUEUE_DATA2, - IEEE80211_TX_QUEUE_DATA3, - IEEE80211_TX_QUEUE_DATA4, - IEEE80211_TX_QUEUE_SVP, - - NUM_TX_DATA_QUEUES, - -/* due to stupidity in the sub-ioctl userspace interface, the items in - * this struct need to have fixed values. As soon as it is removed, we can - * fix these entries. */ - IEEE80211_TX_QUEUE_AFTER_BEACON = 6, - IEEE80211_TX_QUEUE_BEACON = 7, - NUM_TX_DATA_QUEUES_AMPDU = 16 -}; - struct ieee80211_low_level_stats { unsigned int dot11ACKFailureCount; unsigned int dot11RTSFailureCount; @@ -315,7 +291,7 @@ struct ieee80211_tx_control { * position represents antenna number used */ u8 icv_len; /* length of the ICV/MIC field in octets */ u8 iv_len; /* length of the IV field in octets */ - u8 queue; /* hardware queue to use for this frame; + u16 queue; /* hardware queue to use for this frame; * 0 = highest, hw->queues-1 = lowest */ u16 aid; /* Station AID */ int type; /* internal */ @@ -772,7 +748,14 @@ enum ieee80211_hw_flags { * @max_noise: like @max_rssi, but for the noise value. * * @queues: number of available hardware transmit queues for - * data packets. WMM/QoS requires at least four. + * data packets. WMM/QoS requires at least four, these + * queues need to have configurable access parameters. + * + * @ampdu_queues: number of available hardware transmit queues + * for A-MPDU packets, these have no access parameters + * because they're used only for A-MPDU frames. Note that + * mac80211 will not currently use any of the regular queues + * for aggregation. * * @rate_control_algorithm: rate control algorithm for this hardware. * If unset (NULL), the default algorithm will be used. Must be @@ -791,7 +774,7 @@ struct ieee80211_hw { unsigned int extra_tx_headroom; int channel_change_time; int vif_data_size; - u8 queues; + u16 queues, ampdu_queues; s8 max_rssi; s8 max_signal; s8 max_noise; @@ -1069,8 +1052,7 @@ enum ieee80211_ampdu_mlme_action { * of assocaited station or AP. * * @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max), - * bursting) for a hardware TX queue. The @queue parameter uses the - * %IEEE80211_TX_QUEUE_* constants. Must be atomic. + * bursting) for a hardware TX queue. Must be atomic. * * @get_tx_stats: Get statistics of the current TX queue status. This is used * to get number of currently queued packets (queue length), maximum queue @@ -1150,7 +1132,7 @@ struct ieee80211_ops { u32 short_retry, u32 long_retr); void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum sta_notify_cmd, const u8 *addr); - int (*conf_tx)(struct ieee80211_hw *hw, int queue, + int (*conf_tx)(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params); int (*get_tx_stats)(struct ieee80211_hw *hw, struct ieee80211_tx_queue_stats *stats); diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 1cccbfd781f..d20d90eead1 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -197,45 +197,6 @@ DEBUGFS_STATS_FILE(rx_handlers_fragments, 20, "%u", DEBUGFS_STATS_FILE(tx_status_drop, 20, "%u", local->tx_status_drop); -static ssize_t stats_wme_rx_queue_read(struct file *file, - char __user *userbuf, - size_t count, loff_t *ppos) -{ - struct ieee80211_local *local = file->private_data; - char buf[NUM_RX_DATA_QUEUES*15], *p = buf; - int i; - - for (i = 0; i < NUM_RX_DATA_QUEUES; i++) - p += scnprintf(p, sizeof(buf)+buf-p, - "%u\n", local->wme_rx_queue[i]); - - return simple_read_from_buffer(userbuf, count, ppos, buf, p-buf); -} - -static const struct file_operations stats_wme_rx_queue_ops = { - .read = stats_wme_rx_queue_read, - .open = mac80211_open_file_generic, -}; - -static ssize_t stats_wme_tx_queue_read(struct file *file, - char __user *userbuf, - size_t count, loff_t *ppos) -{ - struct ieee80211_local *local = file->private_data; - char buf[NUM_TX_DATA_QUEUES*15], *p = buf; - int i; - - for (i = 0; i < NUM_TX_DATA_QUEUES; i++) - p += scnprintf(p, sizeof(buf)+buf-p, - "%u\n", local->wme_tx_queue[i]); - - return simple_read_from_buffer(userbuf, count, ppos, buf, p-buf); -} - -static const struct file_operations stats_wme_tx_queue_ops = { - .read = stats_wme_tx_queue_read, - .open = mac80211_open_file_generic, -}; #endif DEBUGFS_DEVSTATS_FILE(dot11ACKFailureCount); @@ -303,8 +264,6 @@ void debugfs_hw_add(struct ieee80211_local *local) DEBUGFS_STATS_ADD(rx_expand_skb_head2); DEBUGFS_STATS_ADD(rx_handlers_fragments); DEBUGFS_STATS_ADD(tx_status_drop); - DEBUGFS_STATS_ADD(wme_tx_queue); - DEBUGFS_STATS_ADD(wme_rx_queue); #endif DEBUGFS_STATS_ADD(dot11ACKFailureCount); DEBUGFS_STATS_ADD(dot11RTSFailureCount); @@ -356,8 +315,6 @@ void debugfs_hw_del(struct ieee80211_local *local) DEBUGFS_STATS_DEL(rx_expand_skb_head2); DEBUGFS_STATS_DEL(rx_handlers_fragments); DEBUGFS_STATS_DEL(tx_status_drop); - DEBUGFS_STATS_DEL(wme_tx_queue); - DEBUGFS_STATS_DEL(wme_rx_queue); #endif DEBUGFS_STATS_DEL(dot11ACKFailureCount); DEBUGFS_STATS_DEL(dot11RTSFailureCount); diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 6d47a1d31b3..676a93202ff 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -123,36 +123,6 @@ static ssize_t sta_last_seq_ctrl_read(struct file *file, char __user *userbuf, } STA_OPS(last_seq_ctrl); -#ifdef CONFIG_MAC80211_DEBUG_COUNTERS -static ssize_t sta_wme_rx_queue_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - char buf[15*NUM_RX_DATA_QUEUES], *p = buf; - int i; - struct sta_info *sta = file->private_data; - for (i = 0; i < NUM_RX_DATA_QUEUES; i++) - p += scnprintf(p, sizeof(buf)+buf-p, "%u ", - sta->wme_rx_queue[i]); - p += scnprintf(p, sizeof(buf)+buf-p, "\n"); - return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); -} -STA_OPS(wme_rx_queue); - -static ssize_t sta_wme_tx_queue_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - char buf[15*NUM_TX_DATA_QUEUES], *p = buf; - int i; - struct sta_info *sta = file->private_data; - for (i = 0; i < NUM_TX_DATA_QUEUES; i++) - p += scnprintf(p, sizeof(buf)+buf-p, "%u ", - sta->wme_tx_queue[i]); - p += scnprintf(p, sizeof(buf)+buf-p, "\n"); - return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); -} -STA_OPS(wme_tx_queue); -#endif - static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { @@ -293,10 +263,6 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) DEBUGFS_ADD(num_ps_buf_frames); DEBUGFS_ADD(inactive_ms); DEBUGFS_ADD(last_seq_ctrl); -#ifdef CONFIG_MAC80211_DEBUG_COUNTERS - DEBUGFS_ADD(wme_rx_queue); - DEBUGFS_ADD(wme_tx_queue); -#endif DEBUGFS_ADD(agg_status); } @@ -306,10 +272,6 @@ void ieee80211_sta_debugfs_remove(struct sta_info *sta) DEBUGFS_DEL(num_ps_buf_frames); DEBUGFS_DEL(inactive_ms); DEBUGFS_DEL(last_seq_ctrl); -#ifdef CONFIG_MAC80211_DEBUG_COUNTERS - DEBUGFS_DEL(wme_rx_queue); - DEBUGFS_DEL(wme_tx_queue); -#endif DEBUGFS_DEL(agg_status); debugfs_remove(sta->debugfs.dir); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index cabdc1439d5..d82ed20a344 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -610,8 +610,8 @@ struct ieee80211_local { struct sta_info *sta_hash[STA_HASH_SIZE]; struct timer_list sta_cleanup; - unsigned long state[NUM_TX_DATA_QUEUES_AMPDU]; - struct ieee80211_tx_stored_packet pending_packet[NUM_TX_DATA_QUEUES_AMPDU]; + unsigned long state[IEEE80211_MAX_AMPDU_QUEUES + IEEE80211_MAX_AMPDU_QUEUES]; + struct ieee80211_tx_stored_packet pending_packet[IEEE80211_MAX_AMPDU_QUEUES + IEEE80211_MAX_AMPDU_QUEUES]; struct tasklet_struct tx_pending_tasklet; /* number of interfaces with corresponding IFF_ flags */ @@ -705,8 +705,6 @@ struct ieee80211_local { unsigned int rx_expand_skb_head2; unsigned int rx_handlers_fragments; unsigned int tx_status_drop; - unsigned int wme_rx_queue[NUM_RX_DATA_QUEUES]; - unsigned int wme_tx_queue[NUM_RX_DATA_QUEUES]; #define I802_DEBUG_INC(c) (c)++ #else /* CONFIG_MAC80211_DEBUG_COUNTERS */ #define I802_DEBUG_INC(c) do { } while (0) @@ -764,8 +762,6 @@ struct ieee80211_local { struct dentry *rx_expand_skb_head2; struct dentry *rx_handlers_fragments; struct dentry *tx_status_drop; - struct dentry *wme_tx_queue; - struct dentry *wme_rx_queue; #endif struct dentry *dot11ACKFailureCount; struct dentry *dot11RTSFailureCount; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index e19be27a3de..55e76117da9 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -1745,6 +1745,11 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) goto fail_wep; } + if (hw->queues > IEEE80211_MAX_QUEUES) + hw->queues = IEEE80211_MAX_QUEUES; + if (hw->ampdu_queues > IEEE80211_MAX_AMPDU_QUEUES) + hw->ampdu_queues = IEEE80211_MAX_AMPDU_QUEUES; + ieee80211_install_qdisc(local->mdev); /* add one default STA interface */ diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index e860d0bacea..55b85ae5bc1 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -257,19 +257,8 @@ static void ieee80211_sta_def_wmm_params(struct net_device *dev, qparam.cw_max = 1023; qparam.txop = 0; - for (i = IEEE80211_TX_QUEUE_DATA0; i < NUM_TX_DATA_QUEUES; i++) - local->ops->conf_tx(local_to_hw(local), - i + IEEE80211_TX_QUEUE_DATA0, - &qparam); - - if (ibss) { - /* IBSS uses different parameters for Beacon sending */ - qparam.cw_min++; - qparam.cw_min *= 2; - qparam.cw_min--; - local->ops->conf_tx(local_to_hw(local), - IEEE80211_TX_QUEUE_BEACON, &qparam); - } + for (i = 0; i < local_to_hw(local)->queues; i++) + local->ops->conf_tx(local_to_hw(local), i, &qparam); } } @@ -306,23 +295,23 @@ static void ieee80211_sta_wmm_params(struct net_device *dev, switch (aci) { case 1: - queue = IEEE80211_TX_QUEUE_DATA3; + queue = 3; if (acm) local->wmm_acm |= BIT(0) | BIT(3); break; case 2: - queue = IEEE80211_TX_QUEUE_DATA1; + queue = 1; if (acm) local->wmm_acm |= BIT(4) | BIT(5); break; case 3: - queue = IEEE80211_TX_QUEUE_DATA0; + queue = 0; if (acm) local->wmm_acm |= BIT(6) | BIT(7); break; case 0: default: - queue = IEEE80211_TX_QUEUE_DATA2; + queue = 2; if (acm) local->wmm_acm |= BIT(1) | BIT(2); break; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 02f436a8606..e8b89c89e87 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -275,11 +275,6 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx) } } - I802_DEBUG_INC(rx->local->wme_rx_queue[tid]); - /* only a debug counter, sta might not be assigned properly yet */ - if (rx->sta) - I802_DEBUG_INC(rx->sta->wme_rx_queue[tid]); - rx->queue = tid; /* Set skb->priority to 1d tag if highest order bit of TID is not set. * For now, set skb->priority to 0 for other cases. */ diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 7d4fe4a5292..631943e8af8 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -257,7 +257,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, * sta_rx_agg_session_timer_expired for useage */ sta->timer_to_tid[i] = i; /* tid to tx queue: initialize according to HW (0 is valid) */ - sta->tid_to_tx_q[i] = local->hw.queues; + sta->tid_to_tx_q[i] = local->hw.queues + local->hw.ampdu_queues; /* rx */ sta->ampdu_mlme.tid_state_rx[i] = HT_AGG_STATE_IDLE; sta->ampdu_mlme.tid_rx[i] = NULL; diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 64faa3dc488..5eddf1f32ed 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -19,16 +19,22 @@ #include "wme.h" /* maximum number of hardware queues we support. */ -#define TC_80211_MAX_QUEUES 16 +#define QD_MAX_QUEUES (IEEE80211_MAX_AMPDU_QUEUES + IEEE80211_MAX_QUEUES) +/* current number of hardware queues we support. */ +#define QD_NUM(hw) ((hw)->queues + (hw)->ampdu_queues) +/* + * Default mapping in classifier to work with default + * queue setup. + */ const int ieee802_1d_to_ac[8] = { 2, 3, 3, 2, 1, 1, 0, 0 }; struct ieee80211_sched_data { - unsigned long qdisc_pool[BITS_TO_LONGS(TC_80211_MAX_QUEUES)]; + unsigned long qdisc_pool[BITS_TO_LONGS(QD_MAX_QUEUES)]; struct tcf_proto *filter_list; - struct Qdisc *queues[TC_80211_MAX_QUEUES]; - struct sk_buff_head requeued[TC_80211_MAX_QUEUES]; + struct Qdisc *queues[QD_MAX_QUEUES]; + struct sk_buff_head requeued[QD_MAX_QUEUES]; }; static const char llc_ip_hdr[8] = {0xAA, 0xAA, 0x3, 0, 0, 0, 0x08, 0}; @@ -95,7 +101,7 @@ static inline int wme_downgrade_ac(struct sk_buff *skb) /* positive return value indicates which queue to use * negative return value indicates to drop the frame */ -static inline int classify80211(struct sk_buff *skb, struct Qdisc *qd) +static int classify80211(struct sk_buff *skb, struct Qdisc *qd) { struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; @@ -106,7 +112,7 @@ static inline int classify80211(struct sk_buff *skb, struct Qdisc *qd) if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)) { /* management frames go on AC_VO queue, but are sent * without QoS control fields */ - return IEEE80211_TX_QUEUE_DATA0; + return 0; } if (0 /* injected */) { @@ -141,14 +147,16 @@ static inline int classify80211(struct sk_buff *skb, struct Qdisc *qd) static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) { struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr); + struct ieee80211_hw *hw = &local->hw; struct ieee80211_sched_data *q = qdisc_priv(qd); struct ieee80211_tx_packet_data *pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; unsigned short fc = le16_to_cpu(hdr->frame_control); struct Qdisc *qdisc; - int err, queue; struct sta_info *sta; + int err; + u16 queue; u8 tid; if (pkt_data->flags & IEEE80211_TXPD_REQUEUE) { @@ -158,7 +166,7 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) tid = skb->priority & QOS_CONTROL_TAG1D_MASK; if (sta) { int ampdu_queue = sta->tid_to_tx_q[tid]; - if ((ampdu_queue < local->hw.queues) && + if ((ampdu_queue < QD_NUM(hw)) && test_bit(ampdu_queue, q->qdisc_pool)) { queue = ampdu_queue; pkt_data->flags |= IEEE80211_TXPD_AMPDU; @@ -174,6 +182,9 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) queue = classify80211(skb, qd); + if (unlikely(queue >= local->hw.queues)) + queue = local->hw.queues - 1; + /* now we know the 1d priority, fill in the QoS header if there is one */ if (WLAN_FC_IS_QOS_DATA(fc)) { @@ -193,8 +204,8 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) sta = sta_info_get(local, hdr->addr1); if (sta) { int ampdu_queue = sta->tid_to_tx_q[tid]; - if ((ampdu_queue < local->hw.queues) && - test_bit(ampdu_queue, q->qdisc_pool)) { + if ((ampdu_queue < QD_NUM(hw)) && + test_bit(ampdu_queue, q->qdisc_pool)) { queue = ampdu_queue; pkt_data->flags |= IEEE80211_TXPD_AMPDU; } else { @@ -205,17 +216,6 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) rcu_read_unlock(); } - if (unlikely(queue >= local->hw.queues)) { -#if 0 - if (net_ratelimit()) { - printk(KERN_DEBUG "%s - queue=%d (hw does not " - "support) -> %d\n", - __func__, queue, local->hw.queues - 1); - } -#endif - queue = local->hw.queues - 1; - } - if (unlikely(queue < 0)) { kfree_skb(skb); err = NET_XMIT_DROP; @@ -270,7 +270,7 @@ static struct sk_buff *wme_qdiscop_dequeue(struct Qdisc* qd) int queue; /* check all the h/w queues in numeric/priority order */ - for (queue = 0; queue < hw->queues; queue++) { + for (queue = 0; queue < QD_NUM(hw); queue++) { /* see if there is room in this hardware queue */ if ((test_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue])) || @@ -308,7 +308,7 @@ static void wme_qdiscop_reset(struct Qdisc* qd) /* QUESTION: should we have some hardware flush functionality here? */ - for (queue = 0; queue < hw->queues; queue++) { + for (queue = 0; queue < QD_NUM(hw); queue++) { skb_queue_purge(&q->requeued[queue]); qdisc_reset(q->queues[queue]); } @@ -326,7 +326,7 @@ static void wme_qdiscop_destroy(struct Qdisc* qd) tcf_destroy_chain(q->filter_list); q->filter_list = NULL; - for (queue=0; queue < hw->queues; queue++) { + for (queue = 0; queue < QD_NUM(hw); queue++) { skb_queue_purge(&q->requeued[queue]); qdisc_destroy(q->queues[queue]); q->queues[queue] = &noop_qdisc; @@ -337,17 +337,6 @@ static void wme_qdiscop_destroy(struct Qdisc* qd) /* called whenever parameters are updated on existing qdisc */ static int wme_qdiscop_tune(struct Qdisc *qd, struct nlattr *opt) { -/* struct ieee80211_sched_data *q = qdisc_priv(qd); -*/ - /* check our options block is the right size */ - /* copy any options to our local structure */ -/* Ignore options block for now - always use static mapping - struct tc_ieee80211_qopt *qopt = nla_data(opt); - - if (opt->nla_len < nla_attr_size(sizeof(*qopt))) - return -EINVAL; - memcpy(q->tag2queue, qopt->tag2queue, sizeof(qopt->tag2queue)); -*/ return 0; } @@ -358,7 +347,7 @@ static int wme_qdiscop_init(struct Qdisc *qd, struct nlattr *opt) struct ieee80211_sched_data *q = qdisc_priv(qd); struct net_device *dev = qd->dev; struct ieee80211_local *local; - int queues; + struct ieee80211_hw *hw; int err = 0, i; /* check that device is a mac80211 device */ @@ -366,29 +355,26 @@ static int wme_qdiscop_init(struct Qdisc *qd, struct nlattr *opt) dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid) return -EINVAL; - /* check this device is an ieee80211 master type device */ - if (dev->type != ARPHRD_IEEE80211) + local = wdev_priv(dev->ieee80211_ptr); + hw = &local->hw; + + /* only allow on master dev */ + if (dev != local->mdev) return -EINVAL; - /* check that there is no qdisc currently attached to device - * this ensures that we will be the root qdisc. (I can't find a better - * way to test this explicitly) */ - if (dev->qdisc_sleeping != &noop_qdisc) + /* ensure that we are root qdisc */ + if (qd->parent != TC_H_ROOT) return -EINVAL; if (qd->flags & TCQ_F_INGRESS) return -EINVAL; - local = wdev_priv(dev->ieee80211_ptr); - queues = local->hw.queues; - /* if options were passed in, set them */ - if (opt) { + if (opt) err = wme_qdiscop_tune(qd, opt); - } /* create child queues */ - for (i = 0; i < queues; i++) { + for (i = 0; i < QD_NUM(hw); i++) { skb_queue_head_init(&q->requeued[i]); q->queues[i] = qdisc_create_dflt(qd->dev, &pfifo_qdisc_ops, qd->handle); @@ -398,8 +384,8 @@ static int wme_qdiscop_init(struct Qdisc *qd, struct nlattr *opt) } } - /* reserve all legacy QoS queues */ - for (i = 0; i < min(IEEE80211_TX_QUEUE_DATA4, queues); i++) + /* non-aggregation queues: reserve/mark as used */ + for (i = 0; i < local->hw.queues; i++) set_bit(i, q->qdisc_pool); return err; @@ -407,16 +393,6 @@ static int wme_qdiscop_init(struct Qdisc *qd, struct nlattr *opt) static int wme_qdiscop_dump(struct Qdisc *qd, struct sk_buff *skb) { -/* struct ieee80211_sched_data *q = qdisc_priv(qd); - unsigned char *p = skb->tail; - struct tc_ieee80211_qopt opt; - - memcpy(&opt.tag2queue, q->tag2queue, TC_80211_MAX_TAG + 1); - NLA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt); -*/ return skb->len; -/* -nla_put_failure: - skb_trim(skb, p - skb->data);*/ return -1; } @@ -429,7 +405,7 @@ static int wme_classop_graft(struct Qdisc *qd, unsigned long arg, struct ieee80211_hw *hw = &local->hw; unsigned long queue = arg - 1; - if (queue >= hw->queues) + if (queue >= QD_NUM(hw)) return -EINVAL; if (!new) @@ -453,7 +429,7 @@ wme_classop_leaf(struct Qdisc *qd, unsigned long arg) struct ieee80211_hw *hw = &local->hw; unsigned long queue = arg - 1; - if (queue >= hw->queues) + if (queue >= QD_NUM(hw)) return NULL; return q->queues[queue]; @@ -466,7 +442,7 @@ static unsigned long wme_classop_get(struct Qdisc *qd, u32 classid) struct ieee80211_hw *hw = &local->hw; unsigned long queue = TC_H_MIN(classid); - if (queue - 1 >= hw->queues) + if (queue - 1 >= QD_NUM(hw)) return 0; return queue; @@ -492,7 +468,7 @@ static int wme_classop_change(struct Qdisc *qd, u32 handle, u32 parent, struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr); struct ieee80211_hw *hw = &local->hw; - if (cl - 1 > hw->queues) + if (cl - 1 > QD_NUM(hw)) return -ENOENT; /* TODO: put code to program hardware queue parameters here, @@ -509,7 +485,7 @@ static int wme_classop_delete(struct Qdisc *qd, unsigned long cl) struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr); struct ieee80211_hw *hw = &local->hw; - if (cl - 1 > hw->queues) + if (cl - 1 > QD_NUM(hw)) return -ENOENT; return 0; } @@ -522,7 +498,7 @@ static int wme_classop_dump_class(struct Qdisc *qd, unsigned long cl, struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr); struct ieee80211_hw *hw = &local->hw; - if (cl - 1 > hw->queues) + if (cl - 1 > QD_NUM(hw)) return -ENOENT; tcm->tcm_handle = TC_H_MIN(cl); tcm->tcm_parent = qd->handle; @@ -540,7 +516,7 @@ static void wme_classop_walk(struct Qdisc *qd, struct qdisc_walker *arg) if (arg->stop) return; - for (queue = 0; queue < hw->queues; queue++) { + for (queue = 0; queue < QD_NUM(hw); queue++) { if (arg->count < arg->skip) { arg->count++; continue; @@ -657,10 +633,13 @@ int ieee80211_ht_agg_queue_add(struct ieee80211_local *local, DECLARE_MAC_BUF(mac); /* prepare the filter and save it for the SW queue - * matching the recieved HW queue */ + * matching the received HW queue */ + + if (!local->hw.ampdu_queues) + return -EPERM; /* try to get a Qdisc from the pool */ - for (i = IEEE80211_TX_QUEUE_BEACON; i < local->hw.queues; i++) + for (i = local->hw.queues; i < QD_NUM(&local->hw); i++) if (!test_and_set_bit(i, q->qdisc_pool)) { ieee80211_stop_queue(local_to_hw(local), i); sta->tid_to_tx_q[tid] = i; @@ -689,13 +668,14 @@ void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local, struct sta_info *sta, u16 tid, u8 requeue) { + struct ieee80211_hw *hw = &local->hw; struct ieee80211_sched_data *q = qdisc_priv(local->mdev->qdisc_sleeping); int agg_queue = sta->tid_to_tx_q[tid]; /* return the qdisc to the pool */ clear_bit(agg_queue, q->qdisc_pool); - sta->tid_to_tx_q[tid] = local->hw.queues; + sta->tid_to_tx_q[tid] = QD_NUM(hw); if (requeue) ieee80211_requeue(local, agg_queue); -- cgit v1.2.3-70-g09d2 From 5f505d90250c136e1cf63e3ae85e7d3ff3077c1d Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Wed, 30 Apr 2008 10:50:07 +0200 Subject: libertas: debug output tweaks for lbs_thread * make debug output match the variable name * always report that lbs_remove_rtap() has has been exited Signed-off-by: Holger Schurig Acked-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 406f54d4095..b1c9f3383d7 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -702,7 +702,7 @@ static int lbs_thread(void *data) if (shouldsleep) { lbs_deb_thread("sleeping, connect_status %d, " - "ps_mode %d, ps_state %d\n", + "psmode %d, psstate %d\n", priv->connect_status, priv->psmode, priv->psstate); spin_unlock_irq(&priv->driver_lock); @@ -1532,10 +1532,11 @@ static void lbs_remove_rtap(struct lbs_private *priv) { lbs_deb_enter(LBS_DEB_MAIN); if (priv->rtap_net_dev == NULL) - return; + goto out; unregister_netdev(priv->rtap_net_dev); free_netdev(priv->rtap_net_dev); priv->rtap_net_dev = NULL; +out: lbs_deb_leave(LBS_DEB_MAIN); } -- cgit v1.2.3-70-g09d2 From a63e5cb22fcc8590abc7d5050118a6d3589ed95f Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Wed, 30 Apr 2008 10:50:39 +0200 Subject: libertas: make some functions void They don't return anything meaningfull and no-one cares about their results. Signed-off-by: Holger Schurig Acked-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.h | 2 +- drivers/net/wireless/libertas/decl.h | 4 ++-- drivers/net/wireless/libertas/main.c | 12 ++++-------- 3 files changed, 7 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h index 3dfc2d43c22..4295bc61366 100644 --- a/drivers/net/wireless/libertas/cmd.h +++ b/drivers/net/wireless/libertas/cmd.h @@ -44,7 +44,7 @@ int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan); int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria); int lbs_suspend(struct lbs_private *priv); -int lbs_resume(struct lbs_private *priv); +void lbs_resume(struct lbs_private *priv); int lbs_cmd_802_11_inactivity_timeout(struct lbs_private *priv, uint16_t cmd_action, uint16_t *timeout); diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index b652fa301e1..0632b09655d 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h @@ -64,9 +64,9 @@ void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str); struct chan_freq_power *lbs_get_region_cfp_table(u8 region, int *cfp_no); struct lbs_private *lbs_add_card(void *card, struct device *dmdev); -int lbs_remove_card(struct lbs_private *priv); +void lbs_remove_card(struct lbs_private *priv); int lbs_start_card(struct lbs_private *priv); -int lbs_stop_card(struct lbs_private *priv); +void lbs_stop_card(struct lbs_private *priv); void lbs_host_to_card_done(struct lbs_private *priv); int lbs_update_channel(struct lbs_private *priv); diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index b1c9f3383d7..223ab3a14a1 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -889,7 +889,7 @@ int lbs_suspend(struct lbs_private *priv) } EXPORT_SYMBOL_GPL(lbs_suspend); -int lbs_resume(struct lbs_private *priv) +void lbs_resume(struct lbs_private *priv) { lbs_deb_enter(LBS_DEB_FW); @@ -905,7 +905,6 @@ int lbs_resume(struct lbs_private *priv) netif_device_attach(priv->mesh_dev); lbs_deb_leave(LBS_DEB_FW); - return 0; } EXPORT_SYMBOL_GPL(lbs_resume); @@ -1155,7 +1154,7 @@ done: EXPORT_SYMBOL_GPL(lbs_add_card); -int lbs_remove_card(struct lbs_private *priv) +void lbs_remove_card(struct lbs_private *priv) { struct net_device *dev = priv->dev; union iwreq_data wrqu; @@ -1190,7 +1189,6 @@ int lbs_remove_card(struct lbs_private *priv) free_netdev(dev); lbs_deb_leave(LBS_DEB_MAIN); - return 0; } EXPORT_SYMBOL_GPL(lbs_remove_card); @@ -1261,10 +1259,9 @@ done: EXPORT_SYMBOL_GPL(lbs_start_card); -int lbs_stop_card(struct lbs_private *priv) +void lbs_stop_card(struct lbs_private *priv) { struct net_device *dev = priv->dev; - int ret = -1; struct cmd_ctrl_node *cmdnode; unsigned long flags; @@ -1289,8 +1286,7 @@ int lbs_stop_card(struct lbs_private *priv) unregister_netdev(dev); - lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret); - return ret; + lbs_deb_leave(LBS_DEB_MAIN); } EXPORT_SYMBOL_GPL(lbs_stop_card); -- cgit v1.2.3-70-g09d2 From 652e3f208619dfe75867349d6164afe735eaf159 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Wed, 30 Apr 2008 10:51:15 +0200 Subject: libertas: allow removal of card at any time This fixes several problems I had: * when removing the card while the card was scanning or associtating, it could happen that destroy_workqueue() stuck and didn't return. * make sure the command function doesn't run while we remove the list of pending commands * for still unknown reason, I had calls to lbs_stop_card() with priv==NULL Signed-off-by: Holger Schurig Acked-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/main.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 223ab3a14a1..0be89573716 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1166,8 +1166,8 @@ void lbs_remove_card(struct lbs_private *priv) dev = priv->dev; - cancel_delayed_work(&priv->scan_work); - cancel_delayed_work(&priv->assoc_work); + cancel_delayed_work_sync(&priv->scan_work); + cancel_delayed_work_sync(&priv->assoc_work); destroy_workqueue(priv->work_thread); if (priv->psmode == LBS802_11POWERMODEMAX_PSP) { @@ -1267,6 +1267,9 @@ void lbs_stop_card(struct lbs_private *priv) lbs_deb_enter(LBS_DEB_MAIN); + if (!priv) + goto out; + netif_stop_queue(priv->dev); netif_carrier_off(priv->dev); @@ -1276,6 +1279,7 @@ void lbs_stop_card(struct lbs_private *priv) device_remove_file(&dev->dev, &dev_attr_lbs_mesh); /* Flush pending command nodes */ + del_timer_sync(&priv->command_timer); spin_lock_irqsave(&priv->driver_lock, flags); list_for_each_entry(cmdnode, &priv->cmdpendingq, list) { cmdnode->result = -ENOENT; @@ -1286,6 +1290,7 @@ void lbs_stop_card(struct lbs_private *priv) unregister_netdev(dev); +out: lbs_deb_leave(LBS_DEB_MAIN); } EXPORT_SYMBOL_GPL(lbs_stop_card); -- cgit v1.2.3-70-g09d2 From 3a4d3af700b3d78904775d9a9efe0858b5e1e955 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 21 Apr 2008 19:01:40 +0200 Subject: rt2x00: Clarify supported chipsets in Kconfig As reported by Filipus Klutiero , the rt2x00 Kconfig entries should be updated with specific chipset notifications. This cleans up Kconfig by explicitly mentioning the supported chipsets for each drivers, and uses the same chipset family names as mentioned on the Ralink website. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/Kconfig | 55 +++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index ab1029e7988..0ace7614942 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -5,12 +5,16 @@ config RT2X00 This will enable the experimental support for the Ralink drivers, developed in the rt2x00 project . - These drivers will make use of the mac80211 stack. + These drivers make use of the mac80211 stack. When building one of the individual drivers, the rt2x00 library will also be created. That library (when the driver is built as a module) will be called "rt2x00lib.ko". + Additionally PCI and USB libraries will also be build depending + on the types of drivers being selected, these libraries will be + called "rt2x00pci.ko" and "rt2x00usb.ko". + if RT2X00 config RT2X00_LIB @@ -40,26 +44,27 @@ config RT2X00_LIB_LEDS depends on RT2X00_LIB config RT2400PCI - tristate "Ralink rt2400 pci/pcmcia support" + tristate "Ralink rt2400 (PCI/PCMCIA) support" depends on PCI select RT2X00_LIB_PCI select EEPROM_93CX6 ---help--- - This is an experimental driver for the Ralink rt2400 wireless chip. + This adds support for rt2400 wireless chipset family. + Supported chips: RT2460. When compiled as a module, this driver will be called "rt2400pci.ko". config RT2400PCI_RFKILL - bool "RT2400 rfkill support" + bool "Ralink rt2400 rfkill support" depends on RT2400PCI select RT2X00_LIB_RFKILL ---help--- - This adds support for integrated rt2400 devices that feature a + This adds support for integrated rt2400 hardware that features a hardware button to control the radio state. This feature depends on the RF switch subsystem rfkill. config RT2400PCI_LEDS - bool "RT2400 leds support" + bool "Ralink rt2400 leds support" depends on RT2400PCI select LEDS_CLASS select RT2X00_LIB_LEDS @@ -67,26 +72,27 @@ config RT2400PCI_LEDS This adds support for led triggers provided my mac80211. config RT2500PCI - tristate "Ralink rt2500 pci/pcmcia support" + tristate "Ralink rt2500 (PCI/PCMCIA) support" depends on PCI select RT2X00_LIB_PCI select EEPROM_93CX6 ---help--- - This is an experimental driver for the Ralink rt2500 wireless chip. + This adds support for rt2500 wireless chipset family. + Supported chips: RT2560. When compiled as a module, this driver will be called "rt2500pci.ko". config RT2500PCI_RFKILL - bool "RT2500 rfkill support" + bool "Ralink rt2500 rfkill support" depends on RT2500PCI select RT2X00_LIB_RFKILL ---help--- - This adds support for integrated rt2500 devices that feature a + This adds support for integrated rt2500 hardware that features a hardware button to control the radio state. This feature depends on the RF switch subsystem rfkill. config RT2500PCI_LEDS - bool "RT2500 leds support" + bool "Ralink rt2500 leds support" depends on RT2500PCI select LEDS_CLASS select RT2X00_LIB_LEDS @@ -94,28 +100,29 @@ config RT2500PCI_LEDS This adds support for led triggers provided my mac80211. config RT61PCI - tristate "Ralink rt61 pci/pcmcia support" + tristate "Ralink rt2501/rt61 (PCI/PCMCIA) support" depends on PCI select RT2X00_LIB_PCI select RT2X00_LIB_FIRMWARE select CRC_ITU_T select EEPROM_93CX6 ---help--- - This is an experimental driver for the Ralink rt61 wireless chip. + This adds support for rt2501 wireless chipset family. + Supported chips: RT2561, RT2561S & RT2661. When compiled as a module, this driver will be called "rt61pci.ko". config RT61PCI_RFKILL - bool "RT61 rfkill support" + bool "Ralink rt2501/rt61 rfkill support" depends on RT61PCI select RT2X00_LIB_RFKILL ---help--- - This adds support for integrated rt61 devices that feature a + This adds support for integrated rt61 hardware that features a hardware button to control the radio state. This feature depends on the RF switch subsystem rfkill. config RT61PCI_LEDS - bool "RT61 leds support" + bool "Ralink rt2501/rt61 leds support" depends on RT61PCI select LEDS_CLASS select RT2X00_LIB_LEDS @@ -123,16 +130,17 @@ config RT61PCI_LEDS This adds support for led triggers provided my mac80211. config RT2500USB - tristate "Ralink rt2500 usb support" + tristate "Ralink rt2500 (USB) support" depends on USB select RT2X00_LIB_USB ---help--- - This is an experimental driver for the Ralink rt2500 wireless chip. + This adds support for rt2500 wireless chipset family. + Supported chips: RT2571 & RT2572. When compiled as a module, this driver will be called "rt2500usb.ko". config RT2500USB_LEDS - bool "RT2500 leds support" + bool "Ralink rt2500 leds support" depends on RT2500USB select LEDS_CLASS select RT2X00_LIB_LEDS @@ -140,18 +148,19 @@ config RT2500USB_LEDS This adds support for led triggers provided my mac80211. config RT73USB - tristate "Ralink rt73 usb support" + tristate "Ralink rt2501/rt73 (USB) support" depends on USB select RT2X00_LIB_USB select RT2X00_LIB_FIRMWARE select CRC_ITU_T ---help--- - This is an experimental driver for the Ralink rt73 wireless chip. + This adds support for rt2501 wireless chipset family. + Supported chips: RT2571W, RT2573 & RT2671. When compiled as a module, this driver will be called "rt73usb.ko". config RT73USB_LEDS - bool "RT73 leds support" + bool "Ralink rt2501/rt73 leds support" depends on RT73USB select LEDS_CLASS select RT2X00_LIB_LEDS @@ -164,7 +173,7 @@ config RT2X00_LIB_DEBUGFS ---help--- Enable creation of debugfs files for the rt2x00 drivers. These debugfs files support both reading and writing of the - most important register types of the rt2x00 devices. + most important register types of the rt2x00 hardware. config RT2X00_DEBUG bool "Ralink debug output" -- cgit v1.2.3-70-g09d2 From 3df5ee60f1ee559b1417397461891f8b483e8089 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Thu, 1 May 2008 17:07:32 -0400 Subject: wireless: fix warning introduced by "mac80211: QoS related cleanups" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit net/mac80211/wme.c: In function ‘wme_qdiscop_enqueue’: net/mac80211/wme.c:219: warning: comparison is always false due to limited range of data type drivers/net/wireless/p54/p54common.c: In function ‘p54_conf_tx’: drivers/net/wireless/p54/p54common.c:947: warning: comparison is always false due to limited range of data type Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 2 +- net/mac80211/wme.c | 23 +++++++++-------------- 2 files changed, 10 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 34b91ccd8ae..33d608a60d7 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -944,7 +944,7 @@ static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue, vdcf = (struct p54_tx_control_vdcf *)(((struct p54_control_hdr *) ((void *)priv->cached_vdcf + priv->tx_hdr_len))->data); - if ((params) && !((queue < 0) || (queue > 4))) { + if ((params) && !(queue > 4)) { P54_SET_QUEUE(vdcf->queue[queue], params->aifs, params->cw_min, params->cw_max, params->txop); } else diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 5eddf1f32ed..b1e20ca03ff 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -216,20 +216,15 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) rcu_read_unlock(); } - if (unlikely(queue < 0)) { - kfree_skb(skb); - err = NET_XMIT_DROP; - } else { - tid = skb->priority & QOS_CONTROL_TAG1D_MASK; - pkt_data->queue = (unsigned int) queue; - qdisc = q->queues[queue]; - err = qdisc->enqueue(skb, qdisc); - if (err == NET_XMIT_SUCCESS) { - qd->q.qlen++; - qd->bstats.bytes += skb->len; - qd->bstats.packets++; - return NET_XMIT_SUCCESS; - } + tid = skb->priority & QOS_CONTROL_TAG1D_MASK; + pkt_data->queue = (unsigned int) queue; + qdisc = q->queues[queue]; + err = qdisc->enqueue(skb, qdisc); + if (err == NET_XMIT_SUCCESS) { + qd->q.qlen++; + qd->bstats.bytes += skb->len; + qd->bstats.packets++; + return NET_XMIT_SUCCESS; } qd->qstats.drops++; return err; -- cgit v1.2.3-70-g09d2 From 988f7b5789ccf5cfed14c72e28573a49f0cb4809 Mon Sep 17 00:00:00 2001 From: "venkatesh.pallipadi@intel.com" Date: Tue, 18 Mar 2008 17:00:22 -0700 Subject: x86: PAT export resource_wc in pci sysfs For the ranges with IORESOURCE_PREFETCH, export a new resource_wc interface in pci /sysfs along with resource (which is uncached). Signed-off-by: Venkatesh Pallipadi Signed-off-by: Suresh Siddha Acked-by: Jesse Barnes Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner --- Documentation/filesystems/sysfs-pci.txt | 1 + drivers/pci/pci-sysfs.c | 84 ++++++++++++++++++++++++--------- include/linux/pci.h | 1 + 3 files changed, 64 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/Documentation/filesystems/sysfs-pci.txt b/Documentation/filesystems/sysfs-pci.txt index 5daa2aaec2c..68ef48839c0 100644 --- a/Documentation/filesystems/sysfs-pci.txt +++ b/Documentation/filesystems/sysfs-pci.txt @@ -36,6 +36,7 @@ files, each with their own function. local_cpus nearby CPU mask (cpumask, ro) resource PCI resource host addresses (ascii, ro) resource0..N PCI resource N, if present (binary, mmap) + resource0_wc..N_wc PCI WC map resource N, if prefetchable (binary, mmap) rom PCI ROM resource, if present (binary, ro) subsystem_device PCI subsystem device (ascii, ro) subsystem_vendor PCI subsystem vendor (ascii, ro) diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 271d41cc05a..9ec7d3977a8 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -489,13 +489,14 @@ pci_mmap_legacy_mem(struct kobject *kobj, struct bin_attribute *attr, * @kobj: kobject for mapping * @attr: struct bin_attribute for the file being mapped * @vma: struct vm_area_struct passed into the mmap + * @write_combine: 1 for write_combine mapping * * Use the regular PCI mapping routines to map a PCI resource into userspace. * FIXME: write combining? maybe automatic for prefetchable regions? */ static int pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr, - struct vm_area_struct *vma) + struct vm_area_struct *vma, int write_combine) { struct pci_dev *pdev = to_pci_dev(container_of(kobj, struct device, kobj)); @@ -518,7 +519,21 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr, vma->vm_pgoff += start >> PAGE_SHIFT; mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io; - return pci_mmap_page_range(pdev, vma, mmap_type, 0); + return pci_mmap_page_range(pdev, vma, mmap_type, write_combine); +} + +static int +pci_mmap_resource_uc(struct kobject *kobj, struct bin_attribute *attr, + struct vm_area_struct *vma) +{ + return pci_mmap_resource(kobj, attr, vma, 0); +} + +static int +pci_mmap_resource_wc(struct kobject *kobj, struct bin_attribute *attr, + struct vm_area_struct *vma) +{ + return pci_mmap_resource(kobj, attr, vma, 1); } /** @@ -541,9 +556,46 @@ pci_remove_resource_files(struct pci_dev *pdev) sysfs_remove_bin_file(&pdev->dev.kobj, res_attr); kfree(res_attr); } + + res_attr = pdev->res_attr_wc[i]; + if (res_attr) { + sysfs_remove_bin_file(&pdev->dev.kobj, res_attr); + kfree(res_attr); + } } } +static int pci_create_attr(struct pci_dev *pdev, int num, int write_combine) +{ + /* allocate attribute structure, piggyback attribute name */ + int name_len = write_combine ? 13 : 10; + struct bin_attribute *res_attr; + int retval; + + res_attr = kzalloc(sizeof(*res_attr) + name_len, GFP_ATOMIC); + if (res_attr) { + char *res_attr_name = (char *)(res_attr + 1); + + if (write_combine) { + pdev->res_attr_wc[num] = res_attr; + sprintf(res_attr_name, "resource%d_wc", num); + res_attr->mmap = pci_mmap_resource_wc; + } else { + pdev->res_attr[num] = res_attr; + sprintf(res_attr_name, "resource%d", num); + res_attr->mmap = pci_mmap_resource_uc; + } + res_attr->attr.name = res_attr_name; + res_attr->attr.mode = S_IRUSR | S_IWUSR; + res_attr->size = pci_resource_len(pdev, num); + res_attr->private = &pdev->resource[num]; + retval = sysfs_create_bin_file(&pdev->dev.kobj, res_attr); + } else + retval = -ENOMEM; + + return retval; +} + /** * pci_create_resource_files - create resource files in sysfs for @dev * @dev: dev in question @@ -557,31 +609,19 @@ static int pci_create_resource_files(struct pci_dev *pdev) /* Expose the PCI resources from this device as files */ for (i = 0; i < PCI_ROM_RESOURCE; i++) { - struct bin_attribute *res_attr; /* skip empty resources */ if (!pci_resource_len(pdev, i)) continue; - /* allocate attribute structure, piggyback attribute name */ - res_attr = kzalloc(sizeof(*res_attr) + 10, GFP_ATOMIC); - if (res_attr) { - char *res_attr_name = (char *)(res_attr + 1); - - pdev->res_attr[i] = res_attr; - sprintf(res_attr_name, "resource%d", i); - res_attr->attr.name = res_attr_name; - res_attr->attr.mode = S_IRUSR | S_IWUSR; - res_attr->size = pci_resource_len(pdev, i); - res_attr->mmap = pci_mmap_resource; - res_attr->private = &pdev->resource[i]; - retval = sysfs_create_bin_file(&pdev->dev.kobj, res_attr); - if (retval) { - pci_remove_resource_files(pdev); - return retval; - } - } else { - return -ENOMEM; + retval = pci_create_attr(pdev, i, 0); + /* for prefetchable resources, create a WC mappable file */ + if (!retval && pdev->resource[i].flags & IORESOURCE_PREFETCH) + retval = pci_create_attr(pdev, i, 1); + + if (retval) { + pci_remove_resource_files(pdev); + return retval; } } return 0; diff --git a/include/linux/pci.h b/include/linux/pci.h index 509159bcd4e..d18b1dd49fa 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -206,6 +206,7 @@ struct pci_dev { struct bin_attribute *rom_attr; /* attribute descriptor for sysfs ROM entry */ int rom_attr_enabled; /* has display of the rom attribute been enabled? */ struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */ + struct bin_attribute *res_attr_wc[DEVICE_COUNT_RESOURCE]; /* sysfs file for WC mapping of resources */ #ifdef CONFIG_PCI_MSI struct list_head msi_list; #endif -- cgit v1.2.3-70-g09d2 From aa134f1b09df6beaa4d031a50d5fda1f3cebce6c Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Tue, 8 Apr 2008 10:49:03 +0200 Subject: x86: iommu: use symbolic constants, not hardcoded numbers Move symbolic constants into gart.h, and use them instead of hardcoded constant. Signed-off-by: Pavel Machek Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner --- arch/x86/kernel/pci-gart_64.c | 10 +++++----- drivers/char/agp/amd64-agp.c | 25 +++---------------------- include/asm-x86/gart.h | 21 +++++++++++++++++++++ 3 files changed, 29 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/arch/x86/kernel/pci-gart_64.c b/arch/x86/kernel/pci-gart_64.c index c07455d1695..bffcf455c85 100644 --- a/arch/x86/kernel/pci-gart_64.c +++ b/arch/x86/kernel/pci-gart_64.c @@ -598,13 +598,13 @@ static __init int init_k8_gatt(struct agp_kern_info *info) dev = k8_northbridges[i]; gatt_reg = __pa(gatt) >> 12; gatt_reg <<= 4; - pci_write_config_dword(dev, 0x98, gatt_reg); - pci_read_config_dword(dev, 0x90, &ctl); + pci_write_config_dword(dev, AMD64_GARTTABLEBASE, gatt_reg); + pci_read_config_dword(dev, AMD64_GARTAPERTURECTL, &ctl); - ctl |= 1; - ctl &= ~((1<<4) | (1<<5)); + ctl |= GARTEN; + ctl &= ~(DISGARTCPU | DISGARTIO); - pci_write_config_dword(dev, 0x90, ctl); + pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, ctl); } flush_gart(); diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index d8200ac8f8c..25d64224cdb 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c @@ -16,28 +16,9 @@ #include /* PAGE_SIZE */ #include #include +#include #include "agp.h" -/* PTE bits. */ -#define GPTE_VALID 1 -#define GPTE_COHERENT 2 - -/* Aperture control register bits. */ -#define GARTEN (1<<0) -#define DISGARTCPU (1<<4) -#define DISGARTIO (1<<5) - -/* GART cache control register bits. */ -#define INVGART (1<<0) -#define GARTPTEERR (1<<1) - -/* K8 On-cpu GART registers */ -#define AMD64_GARTAPERTURECTL 0x90 -#define AMD64_GARTAPERTUREBASE 0x94 -#define AMD64_GARTTABLEBASE 0x98 -#define AMD64_GARTCACHECTL 0x9c -#define AMD64_GARTEN (1<<0) - /* NVIDIA K8 registers */ #define NVIDIA_X86_64_0_APBASE 0x10 #define NVIDIA_X86_64_1_APBASE1 0x50 @@ -165,7 +146,7 @@ static int amd64_fetch_size(void) * In a multiprocessor x86-64 system, this function gets * called once for each CPU. */ -static u64 amd64_configure (struct pci_dev *hammer, u64 gatt_table) +static u64 amd64_configure(struct pci_dev *hammer, u64 gatt_table) { u64 aperturebase; u32 tmp; @@ -181,7 +162,7 @@ static u64 amd64_configure (struct pci_dev *hammer, u64 gatt_table) addr >>= 12; tmp = (u32) addr<<4; tmp &= ~0xf; - pci_write_config_dword (hammer, AMD64_GARTTABLEBASE, tmp); + pci_write_config_dword(hammer, AMD64_GARTTABLEBASE, tmp); /* Enable GART translation for this hammer. */ pci_read_config_dword(hammer, AMD64_GARTAPERTURECTL, &tmp); diff --git a/include/asm-x86/gart.h b/include/asm-x86/gart.h index 90958ed993f..248e5778e92 100644 --- a/include/asm-x86/gart.h +++ b/include/asm-x86/gart.h @@ -5,6 +5,7 @@ extern void pci_iommu_shutdown(void); extern void no_iommu_init(void); extern int force_iommu, no_iommu; extern int iommu_detected; +extern int agp_amd64_init(void); #ifdef CONFIG_GART_IOMMU extern void gart_iommu_init(void); extern void gart_iommu_shutdown(void); @@ -31,4 +32,24 @@ static inline void gart_iommu_shutdown(void) #endif +/* PTE bits. */ +#define GPTE_VALID 1 +#define GPTE_COHERENT 2 + +/* Aperture control register bits. */ +#define GARTEN (1<<0) +#define DISGARTCPU (1<<4) +#define DISGARTIO (1<<5) + +/* GART cache control register bits. */ +#define INVGART (1<<0) +#define GARTPTEERR (1<<1) + +/* K8 On-cpu GART registers */ +#define AMD64_GARTAPERTURECTL 0x90 +#define AMD64_GARTAPERTUREBASE 0x94 +#define AMD64_GARTTABLEBASE 0x98 +#define AMD64_GARTCACHECTL 0x9c +#define AMD64_GARTEN (1<<0) + #endif -- cgit v1.2.3-70-g09d2 From 1edc1ab3f68168ec6815e6d630f38948a6da005a Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Sun, 13 Apr 2008 01:11:41 -0700 Subject: x86: agp_gart size checking for buggy device while looking at Rafael J. Wysocki's system boot log, I found a funny printout: Node 0: aperture @ de000000 size 32 MB Aperture too small (32 MB) AGP bridge at 00:04:00 Aperture from AGP @ de000000 size 4096 MB (APSIZE 0) Aperture too small (0 MB) Your BIOS doesn't leave a aperture memory hole Please enable the IOMMU option in the BIOS setup This costs you 64 MB of RAM Mapping aperture over 65536 KB of RAM @ 4000000 ... agpgart: Detected AGP bridge 20 agpgart: Aperture pointing to RAM agpgart: Aperture from AGP @ de000000 size 4096 MB agpgart: Aperture too small (0 MB) agpgart: No usable aperture found. agpgart: Consider rebooting with iommu=memaper=2 to get a good aperture. it means BIOS allocated the correct gart on the NB and AGP bridge, but because a bug in the silicon (the agp bridge reports the wrong order, it wants 4G instead) the kernel will reject that allocation. Also, because the size is only 32MB, and we try to get another 64M for gart, late fix_northbridge can not revert that change because it still reads the wrong size from agp bridge. So try to double check the order value from the agp bridge, before calling aperture_valid(). [ mingo@elte.hu: 32-bit fix. ] Signed-off-by: Yinghai Lu Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner --- arch/x86/kernel/aperture_64.c | 14 ++++++++++++++ drivers/char/agp/amd64-agp.c | 11 +++++++++++ 2 files changed, 25 insertions(+) (limited to 'drivers') diff --git a/arch/x86/kernel/aperture_64.c b/arch/x86/kernel/aperture_64.c index 479926d9e00..2e93b3132df 100644 --- a/arch/x86/kernel/aperture_64.c +++ b/arch/x86/kernel/aperture_64.c @@ -138,6 +138,7 @@ static __u32 __init read_agp(int num, int slot, int func, int cap, u32 *order) int nbits; u32 aper_low, aper_hi; u64 aper; + u32 old_order; printk(KERN_INFO "AGP bridge at %02x:%02x:%02x\n", num, slot, func); apsizereg = read_pci_config_16(num, slot, func, cap + 0x14); @@ -146,6 +147,9 @@ static __u32 __init read_agp(int num, int slot, int func, int cap, u32 *order) return 0; } + /* old_order could be the value from NB gart setting */ + old_order = *order; + apsize = apsizereg & 0xfff; /* Some BIOS use weird encodings not in the AGPv3 table. */ if (apsize & 0xff) @@ -159,6 +163,16 @@ static __u32 __init read_agp(int num, int slot, int func, int cap, u32 *order) aper_hi = read_pci_config(num, slot, func, 0x14); aper = (aper_low & ~((1<<22)-1)) | ((u64)aper_hi << 32); + /* + * On some sick chips, APSIZE is 0. It means it wants 4G + * so let double check that order, and lets trust AMD NB settings: + */ + if (aper + (32UL<<(20 + *order)) > 0x100000000UL) { + printk(KERN_INFO "Aperture size %u MB (APSIZE %x) is not right, using settings from NB\n", + 32 << *order, apsizereg); + *order = old_order; + } + printk(KERN_INFO "Aperture from AGP @ %Lx size %u MB (APSIZE %x)\n", aper, 32 << *order, apsizereg); diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index 25d64224cdb..9e3939db76e 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c @@ -312,6 +312,17 @@ static __devinit int fix_northbridge(struct pci_dev *nb, struct pci_dev *agp, pci_read_config_dword(agp, 0x10, &aper_low); pci_read_config_dword(agp, 0x14, &aper_hi); aper = (aper_low & ~((1<<22)-1)) | ((u64)aper_hi << 32); + + /* + * On some sick chips APSIZE is 0. This means it wants 4G + * so let double check that order, and lets trust the AMD NB settings + */ + if (aper + (32ULL<<(20 + order)) > 0x100000000ULL) { + printk(KERN_INFO "Aperture size %u MB is not right, using settings from NB\n", + 32 << order); + order = nb_order; + } + printk(KERN_INFO PFX "Aperture from AGP @ %Lx size %u MB\n", aper, 32 << order); if (order < 0 || !aperture_valid(aper, (32*1024*1024)< Date: Sun, 13 Apr 2008 18:42:31 -0700 Subject: x86: checking aperture size order some systems are using 32M for gart and agp when memory is less than 4G. Kernel will reject and try to allcate another 64M that is not needed, and we will waste 64M of perfectly good RAM. this patch adds a workaround by checking aper_base/order between NB and agp bridge. If they are the same, and memory size is less than 4G, it will allow it. Signed-off-by: Yinghai Lu Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner --- arch/x86/kernel/aperture_64.c | 47 ++++++++++++++++++++++++++++++++----------- drivers/char/agp/amd64-agp.c | 12 +++++------ 2 files changed, 41 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/arch/x86/kernel/aperture_64.c b/arch/x86/kernel/aperture_64.c index 2e93b3132df..8c325b7f2d9 100644 --- a/arch/x86/kernel/aperture_64.c +++ b/arch/x86/kernel/aperture_64.c @@ -83,7 +83,7 @@ static u32 __init allocate_aperture(void) return (u32)__pa(p); } -static int __init aperture_valid(u64 aper_base, u32 aper_size) +static int __init aperture_valid(u64 aper_base, u32 aper_size, u32 min_size) { if (!aper_base) return 0; @@ -96,8 +96,9 @@ static int __init aperture_valid(u64 aper_base, u32 aper_size) printk(KERN_ERR "Aperture pointing to e820 RAM. Ignoring.\n"); return 0; } - if (aper_size < 64*1024*1024) { - printk(KERN_ERR "Aperture too small (%d MB)\n", aper_size>>20); + if (aper_size < min_size) { + printk(KERN_ERR "Aperture too small (%d MB) than (%d MB)\n", + aper_size>>20, min_size>>20); return 0; } @@ -167,7 +168,9 @@ static __u32 __init read_agp(int num, int slot, int func, int cap, u32 *order) * On some sick chips, APSIZE is 0. It means it wants 4G * so let double check that order, and lets trust AMD NB settings: */ - if (aper + (32UL<<(20 + *order)) > 0x100000000UL) { + printk(KERN_INFO "Aperture from AGP @ %Lx old size %u MB\n", + aper, 32 << old_order); + if (aper + (32ULL<<(20 + *order)) > 0x100000000ULL) { printk(KERN_INFO "Aperture size %u MB (APSIZE %x) is not right, using settings from NB\n", 32 << *order, apsizereg); *order = old_order; @@ -176,7 +179,7 @@ static __u32 __init read_agp(int num, int slot, int func, int cap, u32 *order) printk(KERN_INFO "Aperture from AGP @ %Lx size %u MB (APSIZE %x)\n", aper, 32 << *order, apsizereg); - if (!aperture_valid(aper, (32*1024*1024) << *order)) + if (!aperture_valid(aper, (32*1024*1024) << *order, 32<<20)) return 0; return (u32)aper; } @@ -302,8 +305,8 @@ void __init early_gart_iommu_check(void) fix = 1; if (gart_fix_e820 && !fix && aper_enabled) { - if (e820_any_mapped(aper_base, aper_base + aper_size, - E820_RAM)) { + if (!e820_all_mapped(aper_base, aper_base + aper_size, + E820_RESERVED)) { /* reserved it, so we can resuse it in second kernel */ printk(KERN_INFO "update e820 for GART\n"); add_memory_region(aper_base, aper_size, E820_RESERVED); @@ -324,8 +327,11 @@ void __init early_gart_iommu_check(void) } +static int __initdata printed_gart_size_msg; + void __init gart_iommu_hole_init(void) { + u32 agp_aper_base = 0, agp_aper_order = 0; u32 aper_size, aper_alloc = 0, aper_order = 0, last_aper_order = 0; u64 aper_base, last_aper_base = 0; int fix, num, valid_agp = 0; @@ -337,6 +343,9 @@ void __init gart_iommu_hole_init(void) printk(KERN_INFO "Checking aperture...\n"); + if (!fallback_aper_force) + agp_aper_base = search_agp_bridge(&agp_aper_order, &valid_agp); + fix = 0; node = 0; for (num = 24; num < 32; num++) { @@ -355,9 +364,21 @@ void __init gart_iommu_hole_init(void) node, aper_base, aper_size >> 20); node++; - if (!aperture_valid(aper_base, aper_size)) { - fix = 1; - break; + if (!aperture_valid(aper_base, aper_size, 64<<20)) { + if (valid_agp && agp_aper_base && + agp_aper_base == aper_base && + agp_aper_order == aper_order) { + /* the same between two setting from NB and agp */ + if (!no_iommu && end_pfn > MAX_DMA32_PFN && !printed_gart_size_msg) { + printk(KERN_ERR "you are using iommu with agp, but GART size is less than 64M\n"); + printk(KERN_ERR "please increase GART size in your BIOS setup\n"); + printk(KERN_ERR "if BIOS doesn't have that option, contact your HW vendor!\n"); + printed_gart_size_msg = 1; + } + } else { + fix = 1; + break; + } } if ((last_aper_order && aper_order != last_aper_order) || @@ -378,8 +399,10 @@ void __init gart_iommu_hole_init(void) return; } - if (!fallback_aper_force) - aper_alloc = search_agp_bridge(&aper_order, &valid_agp); + if (!fallback_aper_force) { + aper_alloc = agp_aper_base; + aper_order = agp_aper_order; + } if (aper_alloc) { /* Got the aperture from the AGP bridge */ diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index 9e3939db76e..9c24470a825 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c @@ -245,11 +245,7 @@ static int __devinit aperture_valid(u64 aper, u32 size) printk(KERN_ERR PFX "No aperture\n"); return 0; } - if (size < 32*1024*1024) { - printk(KERN_ERR PFX "Aperture too small (%d MB)\n", size>>20); - return 0; - } - if ((u64)aper + size > 0x100000000ULL) { + if ((u64)aper + size > 0x100000000ULL) { printk(KERN_ERR PFX "Aperture out of bounds\n"); return 0; } @@ -257,6 +253,10 @@ static int __devinit aperture_valid(u64 aper, u32 size) printk(KERN_ERR PFX "Aperture pointing to RAM\n"); return 0; } + if (size < 32*1024*1024) { + printk(KERN_ERR PFX "Aperture too small (%d MB)\n", size>>20); + return 0; + } /* Request the Aperture. This catches cases when someone else already put a mapping in there - happens with some very broken BIOS @@ -317,7 +317,7 @@ static __devinit int fix_northbridge(struct pci_dev *nb, struct pci_dev *agp, * On some sick chips APSIZE is 0. This means it wants 4G * so let double check that order, and lets trust the AMD NB settings */ - if (aper + (32ULL<<(20 + order)) > 0x100000000ULL) { + if (order >=0 && aper + (32ULL<<(20 + order)) > 0x100000000ULL) { printk(KERN_INFO "Aperture size %u MB is not right, using settings from NB\n", 32 << order); order = nb_order; -- cgit v1.2.3-70-g09d2 From 3bb6fbf9969a8bbe4892968659239273d092e78a Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Tue, 15 Apr 2008 12:43:57 +0200 Subject: x86 gart: factor out common code Cleanup gart handling on amd64 a bit: move common code into enable_gart_translation , and use symbolic register names where appropriate. Signed-off-by: Pavel Machek Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner --- arch/x86/kernel/pci-gart_64.c | 23 ++++++----------------- drivers/char/agp/amd64-agp.c | 29 +++++++++-------------------- include/asm-x86/gart.h | 17 +++++++++++++++++ 3 files changed, 32 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/arch/x86/kernel/pci-gart_64.c b/arch/x86/kernel/pci-gart_64.c index bffcf455c85..1f99b62ff61 100644 --- a/arch/x86/kernel/pci-gart_64.c +++ b/arch/x86/kernel/pci-gart_64.c @@ -533,8 +533,8 @@ static __init unsigned read_aperture(struct pci_dev *dev, u32 *size) unsigned aper_size = 0, aper_base_32, aper_order; u64 aper_base; - pci_read_config_dword(dev, 0x94, &aper_base_32); - pci_read_config_dword(dev, 0x90, &aper_order); + pci_read_config_dword(dev, AMD64_GARTAPERTUREBASE, &aper_base_32); + pci_read_config_dword(dev, AMD64_GARTAPERTURECTL, &aper_order); aper_order = (aper_order >> 1) & 7; aper_base = aper_base_32 & 0x7fff; @@ -592,19 +592,8 @@ static __init int init_k8_gatt(struct agp_kern_info *info) agp_gatt_table = gatt; for (i = 0; i < num_k8_northbridges; i++) { - u32 gatt_reg; - u32 ctl; - dev = k8_northbridges[i]; - gatt_reg = __pa(gatt) >> 12; - gatt_reg <<= 4; - pci_write_config_dword(dev, AMD64_GARTTABLEBASE, gatt_reg); - pci_read_config_dword(dev, AMD64_GARTAPERTURECTL, &ctl); - - ctl |= GARTEN; - ctl &= ~(DISGARTCPU | DISGARTIO); - - pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, ctl); + enable_gart_translation(dev, __pa(gatt)); } flush_gart(); @@ -648,11 +637,11 @@ void gart_iommu_shutdown(void) u32 ctl; dev = k8_northbridges[i]; - pci_read_config_dword(dev, 0x90, &ctl); + pci_read_config_dword(dev, AMD64_GARTAPERTURECTL, &ctl); - ctl &= ~1; + ctl &= ~GARTEN; - pci_write_config_dword(dev, 0x90, ctl); + pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, ctl); } } diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index 9c24470a825..e3c7ea07f57 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c @@ -150,25 +150,14 @@ static u64 amd64_configure(struct pci_dev *hammer, u64 gatt_table) { u64 aperturebase; u32 tmp; - u64 addr, aper_base; + u64 aper_base; /* Address to map to */ - pci_read_config_dword (hammer, AMD64_GARTAPERTUREBASE, &tmp); + pci_read_config_dword(hammer, AMD64_GARTAPERTUREBASE, &tmp); aperturebase = tmp << 25; aper_base = (aperturebase & PCI_BASE_ADDRESS_MEM_MASK); - /* address of the mappings table */ - addr = (u64) gatt_table; - addr >>= 12; - tmp = (u32) addr<<4; - tmp &= ~0xf; - pci_write_config_dword(hammer, AMD64_GARTTABLEBASE, tmp); - - /* Enable GART translation for this hammer. */ - pci_read_config_dword(hammer, AMD64_GARTAPERTURECTL, &tmp); - tmp |= GARTEN; - tmp &= ~(DISGARTCPU | DISGARTIO); - pci_write_config_dword(hammer, AMD64_GARTAPERTURECTL, tmp); + enable_gart_translation(hammer, gatt_table); return aper_base; } @@ -207,9 +196,9 @@ static void amd64_cleanup(void) for (i = 0; i < num_k8_northbridges; i++) { struct pci_dev *dev = k8_northbridges[i]; /* disable gart translation */ - pci_read_config_dword (dev, AMD64_GARTAPERTURECTL, &tmp); + pci_read_config_dword(dev, AMD64_GARTAPERTURECTL, &tmp); tmp &= ~AMD64_GARTEN; - pci_write_config_dword (dev, AMD64_GARTAPERTURECTL, tmp); + pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, tmp); } } @@ -289,9 +278,9 @@ static __devinit int fix_northbridge(struct pci_dev *nb, struct pci_dev *agp, u32 nb_order, nb_base; u16 apsize; - pci_read_config_dword(nb, 0x90, &nb_order); + pci_read_config_dword(nb, AMD64_GARTAPERTURECTL, &nb_order); nb_order = (nb_order >> 1) & 7; - pci_read_config_dword(nb, 0x94, &nb_base); + pci_read_config_dword(nb, AMD64_GARTAPERTUREBASE, &nb_base); nb_aper = nb_base << 25; if (aperture_valid(nb_aper, (32*1024*1024)<> 25); + pci_write_config_dword(nb, AMD64_GARTAPERTURECTL, order << 1); + pci_write_config_dword(nb, AMD64_GARTAPERTUREBASE, aper >> 25); return 0; } diff --git a/include/asm-x86/gart.h b/include/asm-x86/gart.h index 248e5778e92..6f22786d2f0 100644 --- a/include/asm-x86/gart.h +++ b/include/asm-x86/gart.h @@ -52,4 +52,21 @@ static inline void gart_iommu_shutdown(void) #define AMD64_GARTCACHECTL 0x9c #define AMD64_GARTEN (1<<0) +static inline void enable_gart_translation(struct pci_dev *dev, u64 addr) +{ + u32 tmp, ctl; + + /* address of the mappings table */ + addr >>= 12; + tmp = (u32) addr<<4; + tmp &= ~0xf; + pci_write_config_dword(dev, AMD64_GARTTABLEBASE, tmp); + + /* Enable GART translation for this hammer. */ + pci_read_config_dword(dev, AMD64_GARTAPERTURECTL, &ctl); + ctl |= GARTEN; + ctl &= ~(DISGARTCPU | DISGARTIO); + pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, ctl); +} + #endif -- cgit v1.2.3-70-g09d2 From 8e2691658f4cd2e24beacb6dcba3c33b2ff10593 Mon Sep 17 00:00:00 2001 From: Paulius Zaleckas Date: Wed, 7 May 2008 02:20:36 +0300 Subject: axnet_cs: use netstats in net_device structure Use net_device_stats from net_device structure instead of local. Signed-off-by: Paulius Zaleckas Signed-off-by: Jeff Garzik --- drivers/net/pcmcia/axnet_cs.c | 70 +++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index ce95c5d168f..d7018ff9e17 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -1021,7 +1021,7 @@ static void ei_tx_timeout(struct net_device *dev) int txsr, isr, tickssofar = jiffies - dev->trans_start; unsigned long flags; - ei_local->stat.tx_errors++; + dev->stats.tx_errors++; spin_lock_irqsave(&ei_local->page_lock, flags); txsr = inb(e8390_base+EN0_TSR); @@ -1032,7 +1032,7 @@ static void ei_tx_timeout(struct net_device *dev) dev->name, (txsr & ENTSR_ABT) ? "excess collisions." : (isr) ? "lost interrupt?" : "cable problem?", txsr, isr, tickssofar); - if (!isr && !ei_local->stat.tx_packets) + if (!isr && !dev->stats.tx_packets) { /* The 8390 probably hasn't gotten on the cable yet. */ ei_local->interface_num ^= 1; /* Try a different xcvr. */ @@ -1122,7 +1122,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); outb_p(ENISR_ALL, e8390_base + EN0_IMR); spin_unlock_irqrestore(&ei_local->page_lock, flags); - ei_local->stat.tx_errors++; + dev->stats.tx_errors++; return 1; } @@ -1170,7 +1170,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&ei_local->page_lock, flags); dev_kfree_skb (skb); - ei_local->stat.tx_bytes += send_length; + dev->stats.tx_bytes += send_length; return 0; } @@ -1262,9 +1262,9 @@ static irqreturn_t ax_interrupt(int irq, void *dev_id) if (interrupts & ENISR_COUNTERS) { - ei_local->stat.rx_frame_errors += inb_p(e8390_base + EN0_COUNTER0); - ei_local->stat.rx_crc_errors += inb_p(e8390_base + EN0_COUNTER1); - ei_local->stat.rx_missed_errors+= inb_p(e8390_base + EN0_COUNTER2); + dev->stats.rx_frame_errors += inb_p(e8390_base + EN0_COUNTER0); + dev->stats.rx_crc_errors += inb_p(e8390_base + EN0_COUNTER1); + dev->stats.rx_missed_errors+= inb_p(e8390_base + EN0_COUNTER2); } } @@ -1309,7 +1309,6 @@ static irqreturn_t ax_interrupt(int irq, void *dev_id) static void ei_tx_err(struct net_device *dev) { long e8390_base = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); unsigned char txsr = inb_p(e8390_base+EN0_TSR); unsigned char tx_was_aborted = txsr & (ENTSR_ABT+ENTSR_FU); @@ -1332,10 +1331,10 @@ static void ei_tx_err(struct net_device *dev) ei_tx_intr(dev); else { - ei_local->stat.tx_errors++; - if (txsr & ENTSR_CRS) ei_local->stat.tx_carrier_errors++; - if (txsr & ENTSR_CDH) ei_local->stat.tx_heartbeat_errors++; - if (txsr & ENTSR_OWC) ei_local->stat.tx_window_errors++; + dev->stats.tx_errors++; + if (txsr & ENTSR_CRS) dev->stats.tx_carrier_errors++; + if (txsr & ENTSR_CDH) dev->stats.tx_heartbeat_errors++; + if (txsr & ENTSR_OWC) dev->stats.tx_window_errors++; } } @@ -1397,25 +1396,25 @@ static void ei_tx_intr(struct net_device *dev) /* Minimize Tx latency: update the statistics after we restart TXing. */ if (status & ENTSR_COL) - ei_local->stat.collisions++; + dev->stats.collisions++; if (status & ENTSR_PTX) - ei_local->stat.tx_packets++; + dev->stats.tx_packets++; else { - ei_local->stat.tx_errors++; + dev->stats.tx_errors++; if (status & ENTSR_ABT) { - ei_local->stat.tx_aborted_errors++; - ei_local->stat.collisions += 16; + dev->stats.tx_aborted_errors++; + dev->stats.collisions += 16; } if (status & ENTSR_CRS) - ei_local->stat.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; if (status & ENTSR_FU) - ei_local->stat.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; if (status & ENTSR_CDH) - ei_local->stat.tx_heartbeat_errors++; + dev->stats.tx_heartbeat_errors++; if (status & ENTSR_OWC) - ei_local->stat.tx_window_errors++; + dev->stats.tx_window_errors++; } netif_wake_queue(dev); } @@ -1476,8 +1475,8 @@ static void ei_receive(struct net_device *dev) printk(KERN_DEBUG "%s: bogus packet size: %d, status=%#2x nxpg=%#2x.\n", dev->name, rx_frame.count, rx_frame.status, rx_frame.next); - ei_local->stat.rx_errors++; - ei_local->stat.rx_length_errors++; + dev->stats.rx_errors++; + dev->stats.rx_length_errors++; } else if ((pkt_stat & 0x0F) == ENRSR_RXOK) { @@ -1489,7 +1488,7 @@ static void ei_receive(struct net_device *dev) if (ei_debug > 1) printk(KERN_DEBUG "%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, pkt_len); - ei_local->stat.rx_dropped++; + dev->stats.rx_dropped++; break; } else @@ -1500,10 +1499,10 @@ static void ei_receive(struct net_device *dev) skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); dev->last_rx = jiffies; - ei_local->stat.rx_packets++; - ei_local->stat.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; if (pkt_stat & ENRSR_PHY) - ei_local->stat.multicast++; + dev->stats.multicast++; } } else @@ -1512,10 +1511,10 @@ static void ei_receive(struct net_device *dev) printk(KERN_DEBUG "%s: bogus packet: status=%#2x nxpg=%#2x size=%d\n", dev->name, rx_frame.status, rx_frame.next, rx_frame.count); - ei_local->stat.rx_errors++; + dev->stats.rx_errors++; /* NB: The NIC counts CRC, frame and missed errors. */ if (pkt_stat & ENRSR_FO) - ei_local->stat.rx_fifo_errors++; + dev->stats.rx_fifo_errors++; } next_frame = rx_frame.next; @@ -1550,7 +1549,6 @@ static void ei_rx_overrun(struct net_device *dev) axnet_dev_t *info = PRIV(dev); long e8390_base = dev->base_addr; unsigned char was_txing, must_resend = 0; - struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); /* * Record whether a Tx was in progress and then issue the @@ -1561,7 +1559,7 @@ static void ei_rx_overrun(struct net_device *dev) if (ei_debug > 1) printk(KERN_DEBUG "%s: Receiver overrun.\n", dev->name); - ei_local->stat.rx_over_errors++; + dev->stats.rx_over_errors++; /* * Wait a full Tx time (1.2ms) + some guard time, NS says 1.6ms total. @@ -1622,16 +1620,16 @@ static struct net_device_stats *get_stats(struct net_device *dev) /* If the card is stopped, just return the present stats. */ if (!netif_running(dev)) - return &ei_local->stat; + return &dev->stats; spin_lock_irqsave(&ei_local->page_lock,flags); /* Read the counter registers, assuming we are in page 0. */ - ei_local->stat.rx_frame_errors += inb_p(ioaddr + EN0_COUNTER0); - ei_local->stat.rx_crc_errors += inb_p(ioaddr + EN0_COUNTER1); - ei_local->stat.rx_missed_errors+= inb_p(ioaddr + EN0_COUNTER2); + dev->stats.rx_frame_errors += inb_p(ioaddr + EN0_COUNTER0); + dev->stats.rx_crc_errors += inb_p(ioaddr + EN0_COUNTER1); + dev->stats.rx_missed_errors+= inb_p(ioaddr + EN0_COUNTER2); spin_unlock_irqrestore(&ei_local->page_lock, flags); - return &ei_local->stat; + return &dev->stats; } /* -- cgit v1.2.3-70-g09d2 From 244d74ff209b635c10aac2a8fa5249a2a2c8d9d9 Mon Sep 17 00:00:00 2001 From: Paulius Zaleckas Date: Wed, 7 May 2008 02:20:40 +0300 Subject: lib8390: use netstats in net_device structure Use net_device_stats from net_device structure instead of local. Signed-off-by: Paulius Zaleckas Signed-off-by: Jeff Garzik --- drivers/net/lib8390.c | 70 +++++++++++++++++++++++++-------------------------- 1 file changed, 35 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/net/lib8390.c b/drivers/net/lib8390.c index 0c5447dac03..72ffbeb829c 100644 --- a/drivers/net/lib8390.c +++ b/drivers/net/lib8390.c @@ -265,7 +265,7 @@ static void ei_tx_timeout(struct net_device *dev) int txsr, isr, tickssofar = jiffies - dev->trans_start; unsigned long flags; - ei_local->stat.tx_errors++; + dev->stats.tx_errors++; spin_lock_irqsave(&ei_local->page_lock, flags); txsr = ei_inb(e8390_base+EN0_TSR); @@ -276,7 +276,7 @@ static void ei_tx_timeout(struct net_device *dev) dev->name, (txsr & ENTSR_ABT) ? "excess collisions." : (isr) ? "lost interrupt?" : "cable problem?", txsr, isr, tickssofar); - if (!isr && !ei_local->stat.tx_packets) + if (!isr && !dev->stats.tx_packets) { /* The 8390 probably hasn't gotten on the cable yet. */ ei_local->interface_num ^= 1; /* Try a different xcvr. */ @@ -374,7 +374,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) ei_outb_p(ENISR_ALL, e8390_base + EN0_IMR); spin_unlock(&ei_local->page_lock); enable_irq_lockdep_irqrestore(dev->irq, &flags); - ei_local->stat.tx_errors++; + dev->stats.tx_errors++; return 1; } @@ -417,7 +417,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) enable_irq_lockdep_irqrestore(dev->irq, &flags); dev_kfree_skb (skb); - ei_local->stat.tx_bytes += send_length; + dev->stats.tx_bytes += send_length; return 0; } @@ -493,9 +493,9 @@ static irqreturn_t __ei_interrupt(int irq, void *dev_id) if (interrupts & ENISR_COUNTERS) { - ei_local->stat.rx_frame_errors += ei_inb_p(e8390_base + EN0_COUNTER0); - ei_local->stat.rx_crc_errors += ei_inb_p(e8390_base + EN0_COUNTER1); - ei_local->stat.rx_missed_errors+= ei_inb_p(e8390_base + EN0_COUNTER2); + dev->stats.rx_frame_errors += ei_inb_p(e8390_base + EN0_COUNTER0); + dev->stats.rx_crc_errors += ei_inb_p(e8390_base + EN0_COUNTER1); + dev->stats.rx_missed_errors+= ei_inb_p(e8390_base + EN0_COUNTER2); ei_outb_p(ENISR_COUNTERS, e8390_base + EN0_ISR); /* Ack intr. */ } @@ -578,10 +578,10 @@ static void ei_tx_err(struct net_device *dev) ei_tx_intr(dev); else { - ei_local->stat.tx_errors++; - if (txsr & ENTSR_CRS) ei_local->stat.tx_carrier_errors++; - if (txsr & ENTSR_CDH) ei_local->stat.tx_heartbeat_errors++; - if (txsr & ENTSR_OWC) ei_local->stat.tx_window_errors++; + dev->stats.tx_errors++; + if (txsr & ENTSR_CRS) dev->stats.tx_carrier_errors++; + if (txsr & ENTSR_CDH) dev->stats.tx_heartbeat_errors++; + if (txsr & ENTSR_OWC) dev->stats.tx_window_errors++; } } @@ -645,25 +645,25 @@ static void ei_tx_intr(struct net_device *dev) /* Minimize Tx latency: update the statistics after we restart TXing. */ if (status & ENTSR_COL) - ei_local->stat.collisions++; + dev->stats.collisions++; if (status & ENTSR_PTX) - ei_local->stat.tx_packets++; + dev->stats.tx_packets++; else { - ei_local->stat.tx_errors++; + dev->stats.tx_errors++; if (status & ENTSR_ABT) { - ei_local->stat.tx_aborted_errors++; - ei_local->stat.collisions += 16; + dev->stats.tx_aborted_errors++; + dev->stats.collisions += 16; } if (status & ENTSR_CRS) - ei_local->stat.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; if (status & ENTSR_FU) - ei_local->stat.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; if (status & ENTSR_CDH) - ei_local->stat.tx_heartbeat_errors++; + dev->stats.tx_heartbeat_errors++; if (status & ENTSR_OWC) - ei_local->stat.tx_window_errors++; + dev->stats.tx_window_errors++; } netif_wake_queue(dev); } @@ -730,7 +730,7 @@ static void ei_receive(struct net_device *dev) && rx_frame.next != next_frame + 1 - num_rx_pages) { ei_local->current_page = rxing_page; ei_outb(ei_local->current_page-1, e8390_base+EN0_BOUNDARY); - ei_local->stat.rx_errors++; + dev->stats.rx_errors++; continue; } @@ -740,8 +740,8 @@ static void ei_receive(struct net_device *dev) printk(KERN_DEBUG "%s: bogus packet size: %d, status=%#2x nxpg=%#2x.\n", dev->name, rx_frame.count, rx_frame.status, rx_frame.next); - ei_local->stat.rx_errors++; - ei_local->stat.rx_length_errors++; + dev->stats.rx_errors++; + dev->stats.rx_length_errors++; } else if ((pkt_stat & 0x0F) == ENRSR_RXOK) { @@ -753,7 +753,7 @@ static void ei_receive(struct net_device *dev) if (ei_debug > 1) printk(KERN_DEBUG "%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, pkt_len); - ei_local->stat.rx_dropped++; + dev->stats.rx_dropped++; break; } else @@ -764,10 +764,10 @@ static void ei_receive(struct net_device *dev) skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); dev->last_rx = jiffies; - ei_local->stat.rx_packets++; - ei_local->stat.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; if (pkt_stat & ENRSR_PHY) - ei_local->stat.multicast++; + dev->stats.multicast++; } } else @@ -776,10 +776,10 @@ static void ei_receive(struct net_device *dev) printk(KERN_DEBUG "%s: bogus packet: status=%#2x nxpg=%#2x size=%d\n", dev->name, rx_frame.status, rx_frame.next, rx_frame.count); - ei_local->stat.rx_errors++; + dev->stats.rx_errors++; /* NB: The NIC counts CRC, frame and missed errors. */ if (pkt_stat & ENRSR_FO) - ei_local->stat.rx_fifo_errors++; + dev->stats.rx_fifo_errors++; } next_frame = rx_frame.next; @@ -827,7 +827,7 @@ static void ei_rx_overrun(struct net_device *dev) if (ei_debug > 1) printk(KERN_DEBUG "%s: Receiver overrun.\n", dev->name); - ei_local->stat.rx_over_errors++; + dev->stats.rx_over_errors++; /* * Wait a full Tx time (1.2ms) + some guard time, NS says 1.6ms total. @@ -889,16 +889,16 @@ static struct net_device_stats *get_stats(struct net_device *dev) /* If the card is stopped, just return the present stats. */ if (!netif_running(dev)) - return &ei_local->stat; + return &dev->stats; spin_lock_irqsave(&ei_local->page_lock,flags); /* Read the counter registers, assuming we are in page 0. */ - ei_local->stat.rx_frame_errors += ei_inb_p(ioaddr + EN0_COUNTER0); - ei_local->stat.rx_crc_errors += ei_inb_p(ioaddr + EN0_COUNTER1); - ei_local->stat.rx_missed_errors+= ei_inb_p(ioaddr + EN0_COUNTER2); + dev->stats.rx_frame_errors += ei_inb_p(ioaddr + EN0_COUNTER0); + dev->stats.rx_crc_errors += ei_inb_p(ioaddr + EN0_COUNTER1); + dev->stats.rx_missed_errors+= ei_inb_p(ioaddr + EN0_COUNTER2); spin_unlock_irqrestore(&ei_local->page_lock, flags); - return &ei_local->stat; + return &dev->stats; } /* -- cgit v1.2.3-70-g09d2 From ad0e8a4c15d82d55a731056eeef1288bf7e1c4dc Mon Sep 17 00:00:00 2001 From: Paulius Zaleckas Date: Wed, 7 May 2008 02:20:45 +0300 Subject: 8390.h: remove net_device_stats Remove no longer used net_device_stats. Should be applied to mainline only after applying previous two patches. Signed-off-by: Paulius Zaleckas Signed-off-by: Jeff Garzik --- drivers/net/8390.h | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/8390.h b/drivers/net/8390.h index 04ddec0f4c6..cf020d45aea 100644 --- a/drivers/net/8390.h +++ b/drivers/net/8390.h @@ -69,7 +69,6 @@ struct ei_device { unsigned char reg0; /* Register '0' in a WD8013 */ unsigned char reg5; /* Register '5' in a WD8013 */ unsigned char saved_irq; /* Original dev->irq value. */ - struct net_device_stats stat; /* The new statistics table. */ u32 *reg_offset; /* Register mapping table */ spinlock_t page_lock; /* Page register locks */ unsigned long priv; /* Private field to store bus IDs etc. */ -- cgit v1.2.3-70-g09d2 From 237225f70f159b607382b5ffcd86f36fc8915cfd Mon Sep 17 00:00:00 2001 From: Paulius Zaleckas Date: Mon, 5 May 2008 16:05:17 +0300 Subject: 8139cp: use netstats in net_device structure Use net_device_stats from net_device structure instead of local. Signed-off-by: Paulius Zaleckas Signed-off-by: Jeff Garzik --- drivers/net/8139cp.c | 43 +++++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index a453eda834d..934db350e33 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -340,7 +340,6 @@ struct cp_private { u32 rx_config; u16 cpcmd; - struct net_device_stats net_stats; struct cp_extra_stats cp_stats; unsigned rx_head ____cacheline_aligned; @@ -457,8 +456,8 @@ static inline void cp_rx_skb (struct cp_private *cp, struct sk_buff *skb, { skb->protocol = eth_type_trans (skb, cp->dev); - cp->net_stats.rx_packets++; - cp->net_stats.rx_bytes += skb->len; + cp->dev->stats.rx_packets++; + cp->dev->stats.rx_bytes += skb->len; cp->dev->last_rx = jiffies; #if CP_VLAN_TAG_USED @@ -477,17 +476,17 @@ static void cp_rx_err_acct (struct cp_private *cp, unsigned rx_tail, printk (KERN_DEBUG "%s: rx err, slot %d status 0x%x len %d\n", cp->dev->name, rx_tail, status, len); - cp->net_stats.rx_errors++; + cp->dev->stats.rx_errors++; if (status & RxErrFrame) - cp->net_stats.rx_frame_errors++; + cp->dev->stats.rx_frame_errors++; if (status & RxErrCRC) - cp->net_stats.rx_crc_errors++; + cp->dev->stats.rx_crc_errors++; if ((status & RxErrRunt) || (status & RxErrLong)) - cp->net_stats.rx_length_errors++; + cp->dev->stats.rx_length_errors++; if ((status & (FirstFrag | LastFrag)) != (FirstFrag | LastFrag)) - cp->net_stats.rx_length_errors++; + cp->dev->stats.rx_length_errors++; if (status & RxErrFIFO) - cp->net_stats.rx_fifo_errors++; + cp->dev->stats.rx_fifo_errors++; } static inline unsigned int cp_rx_csum_ok (u32 status) @@ -539,7 +538,7 @@ rx_status_loop: * that RX fragments are never encountered */ cp_rx_err_acct(cp, rx_tail, status, len); - cp->net_stats.rx_dropped++; + dev->stats.rx_dropped++; cp->cp_stats.rx_frags++; goto rx_next; } @@ -556,7 +555,7 @@ rx_status_loop: buflen = cp->rx_buf_sz + RX_OFFSET; new_skb = dev_alloc_skb (buflen); if (!new_skb) { - cp->net_stats.rx_dropped++; + dev->stats.rx_dropped++; goto rx_next; } @@ -710,20 +709,20 @@ static void cp_tx (struct cp_private *cp) if (netif_msg_tx_err(cp)) printk(KERN_DEBUG "%s: tx err, status 0x%x\n", cp->dev->name, status); - cp->net_stats.tx_errors++; + cp->dev->stats.tx_errors++; if (status & TxOWC) - cp->net_stats.tx_window_errors++; + cp->dev->stats.tx_window_errors++; if (status & TxMaxCol) - cp->net_stats.tx_aborted_errors++; + cp->dev->stats.tx_aborted_errors++; if (status & TxLinkFail) - cp->net_stats.tx_carrier_errors++; + cp->dev->stats.tx_carrier_errors++; if (status & TxFIFOUnder) - cp->net_stats.tx_fifo_errors++; + cp->dev->stats.tx_fifo_errors++; } else { - cp->net_stats.collisions += + cp->dev->stats.collisions += ((status >> TxColCntShift) & TxColCntMask); - cp->net_stats.tx_packets++; - cp->net_stats.tx_bytes += skb->len; + cp->dev->stats.tx_packets++; + cp->dev->stats.tx_bytes += skb->len; if (netif_msg_tx_done(cp)) printk(KERN_DEBUG "%s: tx done, slot %d\n", cp->dev->name, tx_tail); } @@ -956,7 +955,7 @@ static void cp_set_rx_mode (struct net_device *dev) static void __cp_get_stats(struct cp_private *cp) { /* only lower 24 bits valid; write any value to clear */ - cp->net_stats.rx_missed_errors += (cpr32 (RxMissed) & 0xffffff); + cp->dev->stats.rx_missed_errors += (cpr32 (RxMissed) & 0xffffff); cpw32 (RxMissed, 0); } @@ -971,7 +970,7 @@ static struct net_device_stats *cp_get_stats(struct net_device *dev) __cp_get_stats(cp); spin_unlock_irqrestore(&cp->lock, flags); - return &cp->net_stats; + return &dev->stats; } static void cp_stop_hw (struct cp_private *cp) @@ -1142,7 +1141,7 @@ static void cp_clean_rings (struct cp_private *cp) PCI_DMA_TODEVICE); if (le32_to_cpu(desc->opts1) & LastFrag) dev_kfree_skb(skb); - cp->net_stats.tx_dropped++; + cp->dev->stats.tx_dropped++; } } -- cgit v1.2.3-70-g09d2 From e1eac92e4cea32b5254d0b835de16d11e589502c Mon Sep 17 00:00:00 2001 From: Paulius Zaleckas Date: Mon, 5 May 2008 16:24:21 +0300 Subject: 8139too: use netstats in net_device structure Use net_device_stats from net_device structure instead of local. Signed-off-by: Paulius Zaleckas Signed-off-by: Jeff Garzik --- drivers/net/8139too.c | 53 +++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 53bd903d232..b23a00c5b84 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -574,7 +574,6 @@ struct rtl8139_private { u32 msg_enable; struct napi_struct napi; struct net_device *dev; - struct net_device_stats stats; unsigned char *rx_ring; unsigned int cur_rx; /* RX buf index of next pkt */ @@ -1711,7 +1710,7 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); } else { dev_kfree_skb(skb); - tp->stats.tx_dropped++; + dev->stats.tx_dropped++; return 0; } @@ -1762,27 +1761,27 @@ static void rtl8139_tx_interrupt (struct net_device *dev, if (netif_msg_tx_err(tp)) printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", dev->name, txstatus); - tp->stats.tx_errors++; + dev->stats.tx_errors++; if (txstatus & TxAborted) { - tp->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; RTL_W32 (TxConfig, TxClearAbt); RTL_W16 (IntrStatus, TxErr); wmb(); } if (txstatus & TxCarrierLost) - tp->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; if (txstatus & TxOutOfWindow) - tp->stats.tx_window_errors++; + dev->stats.tx_window_errors++; } else { if (txstatus & TxUnderrun) { /* Add 64 to the Tx FIFO threshold. */ if (tp->tx_flag < 0x00300000) tp->tx_flag += 0x00020000; - tp->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; } - tp->stats.collisions += (txstatus >> 24) & 15; - tp->stats.tx_bytes += txstatus & 0x7ff; - tp->stats.tx_packets++; + dev->stats.collisions += (txstatus >> 24) & 15; + dev->stats.tx_bytes += txstatus & 0x7ff; + dev->stats.tx_packets++; } dirty_tx++; @@ -1818,7 +1817,7 @@ static void rtl8139_rx_err (u32 rx_status, struct net_device *dev, if (netif_msg_rx_err (tp)) printk(KERN_DEBUG "%s: Ethernet frame had errors, status %8.8x.\n", dev->name, rx_status); - tp->stats.rx_errors++; + dev->stats.rx_errors++; if (!(rx_status & RxStatusOK)) { if (rx_status & RxTooLong) { DPRINTK ("%s: Oversized Ethernet frame, status %4.4x!\n", @@ -1826,11 +1825,11 @@ static void rtl8139_rx_err (u32 rx_status, struct net_device *dev, /* A.C.: The chip hangs here. */ } if (rx_status & (RxBadSymbol | RxBadAlign)) - tp->stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; if (rx_status & (RxRunt | RxTooLong)) - tp->stats.rx_length_errors++; + dev->stats.rx_length_errors++; if (rx_status & RxCRCErr) - tp->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; } else { tp->xstats.rx_lost_in_ring++; } @@ -1913,9 +1912,9 @@ static void rtl8139_isr_ack(struct rtl8139_private *tp) /* Clear out errors and receive interrupts */ if (likely(status != 0)) { if (unlikely(status & (RxFIFOOver | RxOverflow))) { - tp->stats.rx_errors++; + tp->dev->stats.rx_errors++; if (status & RxFIFOOver) - tp->stats.rx_fifo_errors++; + tp->dev->stats.rx_fifo_errors++; } RTL_W16_F (IntrStatus, RxAckBits); } @@ -2016,8 +2015,8 @@ no_early_rx: skb->protocol = eth_type_trans (skb, dev); dev->last_rx = jiffies; - tp->stats.rx_bytes += pkt_size; - tp->stats.rx_packets++; + dev->stats.rx_bytes += pkt_size; + dev->stats.rx_packets++; netif_receive_skb (skb); } else { @@ -2025,7 +2024,7 @@ no_early_rx: printk (KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name); - tp->stats.rx_dropped++; + dev->stats.rx_dropped++; } received++; @@ -2072,7 +2071,7 @@ static void rtl8139_weird_interrupt (struct net_device *dev, assert (ioaddr != NULL); /* Update the error count. */ - tp->stats.rx_missed_errors += RTL_R32 (RxMissed); + dev->stats.rx_missed_errors += RTL_R32 (RxMissed); RTL_W32 (RxMissed, 0); if ((status & RxUnderrun) && link_changed && @@ -2082,12 +2081,12 @@ static void rtl8139_weird_interrupt (struct net_device *dev, } if (status & (RxUnderrun | RxErr)) - tp->stats.rx_errors++; + dev->stats.rx_errors++; if (status & PCSTimeout) - tp->stats.rx_length_errors++; + dev->stats.rx_length_errors++; if (status & RxUnderrun) - tp->stats.rx_fifo_errors++; + dev->stats.rx_fifo_errors++; if (status & PCIErr) { u16 pci_cmd_status; pci_read_config_word (tp->pci_dev, PCI_STATUS, &pci_cmd_status); @@ -2227,7 +2226,7 @@ static int rtl8139_close (struct net_device *dev) RTL_W16 (IntrMask, 0); /* Update the error counts. */ - tp->stats.rx_missed_errors += RTL_R32 (RxMissed); + dev->stats.rx_missed_errors += RTL_R32 (RxMissed); RTL_W32 (RxMissed, 0); spin_unlock_irqrestore (&tp->lock, flags); @@ -2472,12 +2471,12 @@ static struct net_device_stats *rtl8139_get_stats (struct net_device *dev) if (netif_running(dev)) { spin_lock_irqsave (&tp->lock, flags); - tp->stats.rx_missed_errors += RTL_R32 (RxMissed); + dev->stats.rx_missed_errors += RTL_R32 (RxMissed); RTL_W32 (RxMissed, 0); spin_unlock_irqrestore (&tp->lock, flags); } - return &tp->stats; + return &dev->stats; } /* Set or clear the multicast filter for this adaptor. @@ -2561,7 +2560,7 @@ static int rtl8139_suspend (struct pci_dev *pdev, pm_message_t state) RTL_W8 (ChipCmd, 0); /* Update the error counts. */ - tp->stats.rx_missed_errors += RTL_R32 (RxMissed); + dev->stats.rx_missed_errors += RTL_R32 (RxMissed); RTL_W32 (RxMissed, 0); spin_unlock_irqrestore (&tp->lock, flags); -- cgit v1.2.3-70-g09d2 From 2e8d31d574e26ded7688fb1f5c6a2349c9d427d1 Mon Sep 17 00:00:00 2001 From: Paulius Zaleckas Date: Wed, 30 Apr 2008 01:08:26 +0300 Subject: 3c574_cs: use netstats in net_device structure Use net_device_stats from net_device structure instead of local. Signed-off-by: Paulius Zaleckas Signed-off-by: Jeff Garzik --- drivers/net/pcmcia/3c574_cs.c | 47 +++++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index 3b78a3819bb..7112fd5e0e1 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -208,7 +208,6 @@ enum Window4 { /* Window 4: Xcvr/media bits. */ struct el3_private { struct pcmcia_device *p_dev; dev_node_t node; - struct net_device_stats stats; u16 advertising, partner; /* NWay media advertisement */ unsigned char phys; /* MII device address */ unsigned int autoselect:1, default_media:3; /* Read from the EEPROM/Wn3_Config. */ @@ -741,12 +740,11 @@ static int el3_open(struct net_device *dev) static void el3_tx_timeout(struct net_device *dev) { - struct el3_private *lp = netdev_priv(dev); unsigned int ioaddr = dev->base_addr; printk(KERN_NOTICE "%s: Transmit timed out!\n", dev->name); dump_status(dev); - lp->stats.tx_errors++; + dev->stats.tx_errors++; dev->trans_start = jiffies; /* Issue TX_RESET and TX_START commands. */ tc574_wait_for_completion(dev, TxReset); @@ -756,7 +754,6 @@ static void el3_tx_timeout(struct net_device *dev) static void pop_tx_status(struct net_device *dev) { - struct el3_private *lp = netdev_priv(dev); unsigned int ioaddr = dev->base_addr; int i; @@ -772,7 +769,7 @@ static void pop_tx_status(struct net_device *dev) DEBUG(1, "%s: transmit error: status 0x%02x\n", dev->name, tx_status); outw(TxEnable, ioaddr + EL3_CMD); - lp->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; } outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */ } @@ -987,7 +984,7 @@ static struct net_device_stats *el3_get_stats(struct net_device *dev) update_stats(dev); spin_unlock_irqrestore(&lp->window_lock, flags); } - return &lp->stats; + return &dev->stats; } /* Update statistics. @@ -996,7 +993,6 @@ static struct net_device_stats *el3_get_stats(struct net_device *dev) */ static void update_stats(struct net_device *dev) { - struct el3_private *lp = netdev_priv(dev); unsigned int ioaddr = dev->base_addr; u8 rx, tx, up; @@ -1008,15 +1004,15 @@ static void update_stats(struct net_device *dev) /* Unlike the 3c509 we need not turn off stats updates while reading. */ /* Switch to the stats window, and read everything. */ EL3WINDOW(6); - lp->stats.tx_carrier_errors += inb(ioaddr + 0); - lp->stats.tx_heartbeat_errors += inb(ioaddr + 1); + dev->stats.tx_carrier_errors += inb(ioaddr + 0); + dev->stats.tx_heartbeat_errors += inb(ioaddr + 1); /* Multiple collisions. */ inb(ioaddr + 2); - lp->stats.collisions += inb(ioaddr + 3); - lp->stats.tx_window_errors += inb(ioaddr + 4); - lp->stats.rx_fifo_errors += inb(ioaddr + 5); - lp->stats.tx_packets += inb(ioaddr + 6); + dev->stats.collisions += inb(ioaddr + 3); + dev->stats.tx_window_errors += inb(ioaddr + 4); + dev->stats.rx_fifo_errors += inb(ioaddr + 5); + dev->stats.tx_packets += inb(ioaddr + 6); up = inb(ioaddr + 9); - lp->stats.tx_packets += (up&0x30) << 4; + dev->stats.tx_packets += (up&0x30) << 4; /* Rx packets */ inb(ioaddr + 7); /* Tx deferrals */ inb(ioaddr + 8); rx = inw(ioaddr + 10); @@ -1026,14 +1022,13 @@ static void update_stats(struct net_device *dev) /* BadSSD */ inb(ioaddr + 12); up = inb(ioaddr + 13); - lp->stats.tx_bytes += tx + ((up & 0xf0) << 12); + dev->stats.tx_bytes += tx + ((up & 0xf0) << 12); EL3WINDOW(1); } static int el3_rx(struct net_device *dev, int worklimit) { - struct el3_private *lp = netdev_priv(dev); unsigned int ioaddr = dev->base_addr; short rx_status; @@ -1043,14 +1038,14 @@ static int el3_rx(struct net_device *dev, int worklimit) (--worklimit >= 0)) { if (rx_status & 0x4000) { /* Error, update stats. */ short error = rx_status & 0x3800; - lp->stats.rx_errors++; + dev->stats.rx_errors++; switch (error) { - case 0x0000: lp->stats.rx_over_errors++; break; - case 0x0800: lp->stats.rx_length_errors++; break; - case 0x1000: lp->stats.rx_frame_errors++; break; - case 0x1800: lp->stats.rx_length_errors++; break; - case 0x2000: lp->stats.rx_frame_errors++; break; - case 0x2800: lp->stats.rx_crc_errors++; break; + case 0x0000: dev->stats.rx_over_errors++; break; + case 0x0800: dev->stats.rx_length_errors++; break; + case 0x1000: dev->stats.rx_frame_errors++; break; + case 0x1800: dev->stats.rx_length_errors++; break; + case 0x2000: dev->stats.rx_frame_errors++; break; + case 0x2800: dev->stats.rx_crc_errors++; break; } } else { short pkt_len = rx_status & 0x7ff; @@ -1067,12 +1062,12 @@ static int el3_rx(struct net_device *dev, int worklimit) skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; } else { DEBUG(1, "%s: couldn't allocate a sk_buff of" " size %d.\n", dev->name, pkt_len); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; } } tc574_wait_for_completion(dev, RxDiscard); -- cgit v1.2.3-70-g09d2 From cd65284f6ec482622d2b30cd9996712d830ba228 Mon Sep 17 00:00:00 2001 From: Paulius Zaleckas Date: Wed, 30 Apr 2008 01:20:20 +0300 Subject: 3c589_cs: use netstats in net_device structure Use net_device_stats from net_device structure instead of local. Signed-off-by: Paulius Zaleckas Signed-off-by: Jeff Garzik --- drivers/net/pcmcia/3c589_cs.c | 49 +++++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index 1b1abb19c91..549a6455842 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -107,7 +107,6 @@ enum RxFilter { struct el3_private { struct pcmcia_device *p_dev; dev_node_t node; - struct net_device_stats stats; /* For transceiver monitoring */ struct timer_list media; u16 media_status; @@ -566,12 +565,11 @@ static int el3_open(struct net_device *dev) static void el3_tx_timeout(struct net_device *dev) { - struct el3_private *lp = netdev_priv(dev); unsigned int ioaddr = dev->base_addr; printk(KERN_WARNING "%s: Transmit timed out!\n", dev->name); dump_status(dev); - lp->stats.tx_errors++; + dev->stats.tx_errors++; dev->trans_start = jiffies; /* Issue TX_RESET and TX_START commands. */ tc589_wait_for_completion(dev, TxReset); @@ -581,7 +579,6 @@ static void el3_tx_timeout(struct net_device *dev) static void pop_tx_status(struct net_device *dev) { - struct el3_private *lp = netdev_priv(dev); unsigned int ioaddr = dev->base_addr; int i; @@ -596,7 +593,7 @@ static void pop_tx_status(struct net_device *dev) DEBUG(1, "%s: transmit error: status 0x%02x\n", dev->name, tx_status); outw(TxEnable, ioaddr + EL3_CMD); - lp->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; } outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */ } @@ -614,7 +611,7 @@ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_lock_irqsave(&priv->lock, flags); - priv->stats.tx_bytes += skb->len; + dev->stats.tx_bytes += skb->len; /* Put out the doubleword header... */ outw(skb->len, ioaddr + TX_FIFO); @@ -764,7 +761,7 @@ static void media_check(unsigned long arg) outw(StatsDisable, ioaddr + EL3_CMD); errs = inb(ioaddr + 0); outw(StatsEnable, ioaddr + EL3_CMD); - lp->stats.tx_carrier_errors += errs; + dev->stats.tx_carrier_errors += errs; if (errs || (lp->media_status & 0x0010)) media |= 0x0010; } @@ -814,7 +811,7 @@ static struct net_device_stats *el3_get_stats(struct net_device *dev) update_stats(dev); spin_unlock_irqrestore(&lp->lock, flags); } - return &lp->stats; + return &dev->stats; } /* @@ -827,7 +824,6 @@ static struct net_device_stats *el3_get_stats(struct net_device *dev) */ static void update_stats(struct net_device *dev) { - struct el3_private *lp = netdev_priv(dev); unsigned int ioaddr = dev->base_addr; DEBUG(2, "%s: updating the statistics.\n", dev->name); @@ -835,13 +831,13 @@ static void update_stats(struct net_device *dev) outw(StatsDisable, ioaddr + EL3_CMD); /* Switch to the stats window, and read everything. */ EL3WINDOW(6); - lp->stats.tx_carrier_errors += inb(ioaddr + 0); - lp->stats.tx_heartbeat_errors += inb(ioaddr + 1); + dev->stats.tx_carrier_errors += inb(ioaddr + 0); + dev->stats.tx_heartbeat_errors += inb(ioaddr + 1); /* Multiple collisions. */ inb(ioaddr + 2); - lp->stats.collisions += inb(ioaddr + 3); - lp->stats.tx_window_errors += inb(ioaddr + 4); - lp->stats.rx_fifo_errors += inb(ioaddr + 5); - lp->stats.tx_packets += inb(ioaddr + 6); + dev->stats.collisions += inb(ioaddr + 3); + dev->stats.tx_window_errors += inb(ioaddr + 4); + dev->stats.rx_fifo_errors += inb(ioaddr + 5); + dev->stats.tx_packets += inb(ioaddr + 6); /* Rx packets */ inb(ioaddr + 7); /* Tx deferrals */ inb(ioaddr + 8); /* Rx octets */ inw(ioaddr + 10); @@ -854,7 +850,6 @@ static void update_stats(struct net_device *dev) static int el3_rx(struct net_device *dev) { - struct el3_private *lp = netdev_priv(dev); unsigned int ioaddr = dev->base_addr; int worklimit = 32; short rx_status; @@ -865,14 +860,14 @@ static int el3_rx(struct net_device *dev) (--worklimit >= 0)) { if (rx_status & 0x4000) { /* Error, update stats. */ short error = rx_status & 0x3800; - lp->stats.rx_errors++; + dev->stats.rx_errors++; switch (error) { - case 0x0000: lp->stats.rx_over_errors++; break; - case 0x0800: lp->stats.rx_length_errors++; break; - case 0x1000: lp->stats.rx_frame_errors++; break; - case 0x1800: lp->stats.rx_length_errors++; break; - case 0x2000: lp->stats.rx_frame_errors++; break; - case 0x2800: lp->stats.rx_crc_errors++; break; + case 0x0000: dev->stats.rx_over_errors++; break; + case 0x0800: dev->stats.rx_length_errors++; break; + case 0x1000: dev->stats.rx_frame_errors++; break; + case 0x1800: dev->stats.rx_length_errors++; break; + case 0x2000: dev->stats.rx_frame_errors++; break; + case 0x2800: dev->stats.rx_crc_errors++; break; } } else { short pkt_len = rx_status & 0x7ff; @@ -889,12 +884,12 @@ static int el3_rx(struct net_device *dev) skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; } else { DEBUG(1, "%s: couldn't allocate a sk_buff of" " size %d.\n", dev->name, pkt_len); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; } } /* Pop the top of the Rx FIFO */ @@ -929,7 +924,7 @@ static int el3_close(struct net_device *dev) DEBUG(1, "%s: shutting down ethercard.\n", dev->name); if (pcmcia_dev_present(link)) { - /* Turn off statistics ASAP. We update lp->stats below. */ + /* Turn off statistics ASAP. We update dev->stats below. */ outw(StatsDisable, ioaddr + EL3_CMD); /* Disable the receiver and transmitter. */ -- cgit v1.2.3-70-g09d2 From de0561c43550f78cd837a24179f1859817f24578 Mon Sep 17 00:00:00 2001 From: Paulius Zaleckas Date: Wed, 30 Apr 2008 01:49:15 +0300 Subject: 6pack: use netstats in net_device structure Use net_device_stats from net_device structure instead of local. Kill sp_get_stats function, because by default it is used identical internal_stats function from net/core/dev.c Signed-off-by: Paulius Zaleckas Signed-off-by: Jeff Garzik --- drivers/net/hamradio/6pack.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index 9d5721287d6..06ad9f302b5 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -99,9 +99,6 @@ struct sixpack { unsigned int rx_count; unsigned int rx_count_cooked; - /* 6pack interface statistics. */ - struct net_device_stats stats; - int mtu; /* Our mtu (to spot changes!) */ int buffsize; /* Max buffers sizes */ @@ -237,7 +234,7 @@ static void sp_encaps(struct sixpack *sp, unsigned char *icp, int len) return; out_drop: - sp->stats.tx_dropped++; + sp->dev->stats.tx_dropped++; netif_start_queue(sp->dev); if (net_ratelimit()) printk(KERN_DEBUG "%s: %s - dropped.\n", sp->dev->name, msg); @@ -252,7 +249,7 @@ static int sp_xmit(struct sk_buff *skb, struct net_device *dev) spin_lock_bh(&sp->lock); /* We were not busy, so we are now... :-) */ netif_stop_queue(dev); - sp->stats.tx_bytes += skb->len; + dev->stats.tx_bytes += skb->len; sp_encaps(sp, skb->data, skb->len); spin_unlock_bh(&sp->lock); @@ -298,12 +295,6 @@ static int sp_header(struct sk_buff *skb, struct net_device *dev, return 0; } -static struct net_device_stats *sp_get_stats(struct net_device *dev) -{ - struct sixpack *sp = netdev_priv(dev); - return &sp->stats; -} - static int sp_set_mac_address(struct net_device *dev, void *addr) { struct sockaddr_ax25 *sa = addr; @@ -338,7 +329,6 @@ static void sp_setup(struct net_device *dev) dev->destructor = free_netdev; dev->stop = sp_close; - dev->get_stats = sp_get_stats; dev->set_mac_address = sp_set_mac_address; dev->hard_header_len = AX25_MAX_HEADER_LEN; dev->header_ops = &sp_header_ops; @@ -370,7 +360,7 @@ static void sp_bump(struct sixpack *sp, char cmd) count = sp->rcount + 1; - sp->stats.rx_bytes += count; + sp->dev->stats.rx_bytes += count; if ((skb = dev_alloc_skb(count)) == NULL) goto out_mem; @@ -382,12 +372,12 @@ static void sp_bump(struct sixpack *sp, char cmd) skb->protocol = ax25_type_trans(skb, sp->dev); netif_rx(skb); sp->dev->last_rx = jiffies; - sp->stats.rx_packets++; + sp->dev->stats.rx_packets++; return; out_mem: - sp->stats.rx_dropped++; + sp->dev->stats.rx_dropped++; } @@ -436,7 +426,7 @@ static void sixpack_write_wakeup(struct tty_struct *tty) if (sp->xleft <= 0) { /* Now serial buffer is almost free & we can start * transmission of another packet */ - sp->stats.tx_packets++; + sp->dev->stats.tx_packets++; clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); sp->tx_enable = 0; netif_wake_queue(sp->dev); @@ -484,7 +474,7 @@ static void sixpack_receive_buf(struct tty_struct *tty, count--; if (fp && *fp++) { if (!test_and_set_bit(SIXPF_ERROR, &sp->flags)) - sp->stats.rx_errors++; + sp->dev->stats.rx_errors++; continue; } } -- cgit v1.2.3-70-g09d2 From 966e37bca6a84299e0c3ed13e741db9c6e0b0f92 Mon Sep 17 00:00:00 2001 From: Paulius Zaleckas Date: Wed, 30 Apr 2008 02:03:55 +0300 Subject: acenic: use netstats in net_device structure Use net_device_stats from net_device structure instead of local. No need to memset it to 0, because it is allocated by kzalloc. Signed-off-by: Paulius Zaleckas Signed-off-by: Jeff Garzik --- drivers/net/acenic.c | 21 ++++++++------------- drivers/net/acenic.h | 1 - 2 files changed, 8 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index 6c192650d34..e4483de84e7 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -1457,11 +1457,6 @@ static int __devinit ace_init(struct net_device *dev) ace_set_txprd(regs, ap, 0); writel(0, ®s->RxRetCsm); - /* - * Zero the stats before starting the interface - */ - memset(&ap->stats, 0, sizeof(ap->stats)); - /* * Enable DMA engine now. * If we do this sooner, Mckinley box pukes. @@ -2041,8 +2036,8 @@ static void ace_rx_int(struct net_device *dev, u32 rxretprd, u32 rxretcsm) netif_rx(skb); dev->last_rx = jiffies; - ap->stats.rx_packets++; - ap->stats.rx_bytes += retdesc->size; + dev->stats.rx_packets++; + dev->stats.rx_bytes += retdesc->size; idx = (idx + 1) % RX_RETURN_RING_ENTRIES; } @@ -2090,8 +2085,8 @@ static inline void ace_tx_int(struct net_device *dev, } if (skb) { - ap->stats.tx_packets++; - ap->stats.tx_bytes += skb->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; dev_kfree_skb_irq(skb); info->skb = NULL; } @@ -2863,11 +2858,11 @@ static struct net_device_stats *ace_get_stats(struct net_device *dev) struct ace_mac_stats __iomem *mac_stats = (struct ace_mac_stats __iomem *)ap->regs->Stats; - ap->stats.rx_missed_errors = readl(&mac_stats->drop_space); - ap->stats.multicast = readl(&mac_stats->kept_mc); - ap->stats.collisions = readl(&mac_stats->coll); + dev->stats.rx_missed_errors = readl(&mac_stats->drop_space); + dev->stats.multicast = readl(&mac_stats->kept_mc); + dev->stats.collisions = readl(&mac_stats->coll); - return &ap->stats; + return &dev->stats; } diff --git a/drivers/net/acenic.h b/drivers/net/acenic.h index 60ed1837fa8..4487f32759a 100644 --- a/drivers/net/acenic.h +++ b/drivers/net/acenic.h @@ -693,7 +693,6 @@ struct ace_private __attribute__ ((aligned (SMP_CACHE_BYTES))); u32 last_tx, last_std_rx, last_mini_rx; #endif - struct net_device_stats stats; int pci_using_dac; }; -- cgit v1.2.3-70-g09d2 From aa50911ade012470f3c6fe8f7f7868bfd328a4c2 Mon Sep 17 00:00:00 2001 From: Paulius Zaleckas Date: Tue, 29 Apr 2008 11:58:42 +0300 Subject: 3c523: use netstats in net_device structure Use net_device_stats from net_device structure instead of local. Signed-off-by: Paulius Zaleckas Signed-off-by: Jeff Garzik --- drivers/net/3c523.c | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c index 239fc42fb8d..dc6e474229b 100644 --- a/drivers/net/3c523.c +++ b/drivers/net/3c523.c @@ -202,7 +202,6 @@ static void elmc_xmt_int(struct net_device *dev); static void elmc_rnr_int(struct net_device *dev); struct priv { - struct net_device_stats stats; unsigned long base; char *memtop; unsigned long mapped_start; /* Start of ioremap */ @@ -989,18 +988,18 @@ static void elmc_rcv_int(struct net_device *dev) skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; - p->stats.rx_packets++; - p->stats.rx_bytes += totlen; + dev->stats.rx_packets++; + dev->stats.rx_bytes += totlen; } else { - p->stats.rx_dropped++; + dev->stats.rx_dropped++; } } else { printk(KERN_WARNING "%s: received oversized frame.\n", dev->name); - p->stats.rx_dropped++; + dev->stats.rx_dropped++; } } else { /* frame !(ok), only with 'save-bad-frames' */ printk(KERN_WARNING "%s: oops! rfd-error-status: %04x\n", dev->name, status); - p->stats.rx_errors++; + dev->stats.rx_errors++; } p->rfd_top->status = 0; p->rfd_top->last = RFD_SUSP; @@ -1018,7 +1017,7 @@ static void elmc_rnr_int(struct net_device *dev) { struct priv *p = (struct priv *) dev->priv; - p->stats.rx_errors++; + dev->stats.rx_errors++; WAIT_4_SCB_CMD(); /* wait for the last cmd */ p->scb->cmd = RUC_ABORT; /* usually the RU is in the 'no resource'-state .. abort it now. */ @@ -1046,24 +1045,24 @@ static void elmc_xmt_int(struct net_device *dev) printk(KERN_WARNING "%s: strange .. xmit-int without a 'COMPLETE'\n", dev->name); } if (status & STAT_OK) { - p->stats.tx_packets++; - p->stats.collisions += (status & TCMD_MAXCOLLMASK); + dev->stats.tx_packets++; + dev->stats.collisions += (status & TCMD_MAXCOLLMASK); } else { - p->stats.tx_errors++; + dev->stats.tx_errors++; if (status & TCMD_LATECOLL) { printk(KERN_WARNING "%s: late collision detected.\n", dev->name); - p->stats.collisions++; + dev->stats.collisions++; } else if (status & TCMD_NOCARRIER) { - p->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; printk(KERN_WARNING "%s: no carrier detected.\n", dev->name); } else if (status & TCMD_LOSTCTS) { printk(KERN_WARNING "%s: loss of CTS detected.\n", dev->name); } else if (status & TCMD_UNDERRUN) { - p->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; printk(KERN_WARNING "%s: DMA underrun detected.\n", dev->name); } else if (status & TCMD_MAXCOLL) { printk(KERN_WARNING "%s: Max. collisions exceeded.\n", dev->name); - p->stats.collisions += 16; + dev->stats.collisions += 16; } } @@ -1215,12 +1214,12 @@ static struct net_device_stats *elmc_get_stats(struct net_device *dev) ovrn = p->scb->ovrn_errs; p->scb->ovrn_errs -= ovrn; - p->stats.rx_crc_errors += crc; - p->stats.rx_fifo_errors += ovrn; - p->stats.rx_frame_errors += aln; - p->stats.rx_dropped += rsc; + dev->stats.rx_crc_errors += crc; + dev->stats.rx_fifo_errors += ovrn; + dev->stats.rx_frame_errors += aln; + dev->stats.rx_dropped += rsc; - return &p->stats; + return &dev->stats; } /******************************************************** -- cgit v1.2.3-70-g09d2 From 4711c841e4547a41f596bcf6c97473bc6a15126d Mon Sep 17 00:00:00 2001 From: Paulius Zaleckas Date: Tue, 29 Apr 2008 12:09:38 +0300 Subject: 3c527: use netstats in net_device structure Use net_device_stats from net_device structure instead of local. Signed-off-by: Paulius Zaleckas Signed-off-by: Jeff Garzik --- drivers/net/3c527.c | 45 +++++++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c index fae295b6809..6aca0c640f1 100644 --- a/drivers/net/3c527.c +++ b/drivers/net/3c527.c @@ -158,7 +158,6 @@ struct mc32_local int slot; u32 base; - struct net_device_stats net_stats; volatile struct mc32_mailbox *rx_box; volatile struct mc32_mailbox *tx_box; volatile struct mc32_mailbox *exec_box; @@ -1093,24 +1092,24 @@ static void mc32_update_stats(struct net_device *dev) u32 rx_errors=0; - rx_errors+=lp->net_stats.rx_crc_errors +=st->rx_crc_errors; + rx_errors+=dev->stats.rx_crc_errors +=st->rx_crc_errors; st->rx_crc_errors=0; - rx_errors+=lp->net_stats.rx_fifo_errors +=st->rx_overrun_errors; + rx_errors+=dev->stats.rx_fifo_errors +=st->rx_overrun_errors; st->rx_overrun_errors=0; - rx_errors+=lp->net_stats.rx_frame_errors +=st->rx_alignment_errors; + rx_errors+=dev->stats.rx_frame_errors +=st->rx_alignment_errors; st->rx_alignment_errors=0; - rx_errors+=lp->net_stats.rx_length_errors+=st->rx_tooshort_errors; + rx_errors+=dev->stats.rx_length_errors+=st->rx_tooshort_errors; st->rx_tooshort_errors=0; - rx_errors+=lp->net_stats.rx_missed_errors+=st->rx_outofresource_errors; + rx_errors+=dev->stats.rx_missed_errors+=st->rx_outofresource_errors; st->rx_outofresource_errors=0; - lp->net_stats.rx_errors=rx_errors; + dev->stats.rx_errors=rx_errors; /* Number of packets which saw one collision */ - lp->net_stats.collisions+=st->dataC[10]; + dev->stats.collisions+=st->dataC[10]; st->dataC[10]=0; /* Number of packets which saw 2--15 collisions */ - lp->net_stats.collisions+=st->dataC[11]; + dev->stats.collisions+=st->dataC[11]; st->dataC[11]=0; } @@ -1178,7 +1177,7 @@ static void mc32_rx_ring(struct net_device *dev) skb=dev_alloc_skb(length+2); if(skb==NULL) { - lp->net_stats.rx_dropped++; + dev->stats.rx_dropped++; goto dropped; } @@ -1189,8 +1188,8 @@ static void mc32_rx_ring(struct net_device *dev) skb->protocol=eth_type_trans(skb,dev); dev->last_rx = jiffies; - lp->net_stats.rx_packets++; - lp->net_stats.rx_bytes += length; + dev->stats.rx_packets++; + dev->stats.rx_bytes += length; netif_rx(skb); } @@ -1253,34 +1252,34 @@ static void mc32_tx_ring(struct net_device *dev) /* Not COMPLETED */ break; } - lp->net_stats.tx_packets++; + dev->stats.tx_packets++; if(!(np->status & (1<<6))) /* Not COMPLETED_OK */ { - lp->net_stats.tx_errors++; + dev->stats.tx_errors++; switch(np->status&0x0F) { case 1: - lp->net_stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; break; /* Max collisions */ case 2: - lp->net_stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; break; case 3: - lp->net_stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; break; case 4: - lp->net_stats.tx_window_errors++; + dev->stats.tx_window_errors++; break; /* CTS Lost */ case 5: - lp->net_stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; break; /* Transmit timeout */ } } /* Packets are sent in order - this is basically a FIFO queue of buffers matching the card ring */ - lp->net_stats.tx_bytes+=lp->tx_ring[t].skb->len; + dev->stats.tx_bytes+=lp->tx_ring[t].skb->len; dev_kfree_skb_irq(lp->tx_ring[t].skb); lp->tx_ring[t].skb=NULL; atomic_inc(&lp->tx_count); @@ -1367,7 +1366,7 @@ static irqreturn_t mc32_interrupt(int irq, void *dev_id) case 6: /* Out of RX buffers stat */ /* Must restart rx */ - lp->net_stats.rx_dropped++; + dev->stats.rx_dropped++; mc32_rx_ring(dev); mc32_start_transceiver(dev); break; @@ -1489,10 +1488,8 @@ static int mc32_close(struct net_device *dev) static struct net_device_stats *mc32_get_stats(struct net_device *dev) { - struct mc32_local *lp = netdev_priv(dev); - mc32_update_stats(dev); - return &lp->net_stats; + return &dev->stats; } -- cgit v1.2.3-70-g09d2 From 94f9d298ce215dada7ceaeb03e62f61d754d5705 Mon Sep 17 00:00:00 2001 From: Paulius Zaleckas Date: Tue, 29 Apr 2008 12:44:20 +0300 Subject: 3c359: use netstats in net_device structure Use net_device_stats from net_device structure instead of local. Kill xl_get_stats function, because by default it is used identical internal_stats function from net/core/dev.c Signed-off-by: Paulius Zaleckas Signed-off-by: Jeff Garzik --- drivers/net/tokenring/3c359.c | 20 ++++++-------------- drivers/net/tokenring/3c359.h | 2 -- 2 files changed, 6 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c index 45208a0e69a..7766cde0d63 100644 --- a/drivers/net/tokenring/3c359.c +++ b/drivers/net/tokenring/3c359.c @@ -132,7 +132,6 @@ static void xl_dn_comp(struct net_device *dev); static int xl_close(struct net_device *dev); static void xl_set_rx_mode(struct net_device *dev); static irqreturn_t xl_interrupt(int irq, void *dev_id); -static struct net_device_stats * xl_get_stats(struct net_device *dev); static int xl_set_mac_address(struct net_device *dev, void *addr) ; static void xl_arb_cmd(struct net_device *dev); static void xl_asb_cmd(struct net_device *dev) ; @@ -343,7 +342,6 @@ static int __devinit xl_probe(struct pci_dev *pdev, dev->stop=&xl_close; dev->do_ioctl=NULL; dev->set_multicast_list=&xl_set_rx_mode; - dev->get_stats=&xl_get_stats ; dev->set_mac_address=&xl_set_mac_address ; SET_NETDEV_DEV(dev, &pdev->dev); @@ -921,7 +919,7 @@ static void xl_rx(struct net_device *dev) adv_rx_ring(dev) ; adv_rx_ring(dev) ; /* One more time just for luck :) */ - xl_priv->xl_stats.rx_dropped++ ; + dev->stats.rx_dropped++ ; writel(ACK_INTERRUPT | UPCOMPACK | LATCH_ACK , xl_mmio + MMIO_COMMAND) ; return ; @@ -957,7 +955,7 @@ static void xl_rx(struct net_device *dev) if (skb==NULL) { /* Still need to fix the rx ring */ printk(KERN_WARNING "%s: dev_alloc_skb failed in rx, single buffer \n",dev->name) ; adv_rx_ring(dev) ; - xl_priv->xl_stats.rx_dropped++ ; + dev->stats.rx_dropped++ ; writel(ACK_INTERRUPT | UPCOMPACK | LATCH_ACK , xl_mmio + MMIO_COMMAND) ; return ; } @@ -971,8 +969,8 @@ static void xl_rx(struct net_device *dev) xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr = cpu_to_le32(pci_map_single(xl_priv->pdev,skb->data,xl_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE)); xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfraglen = cpu_to_le32(xl_priv->pkt_buf_sz) | RXUPLASTFRAG; adv_rx_ring(dev) ; - xl_priv->xl_stats.rx_packets++ ; - xl_priv->xl_stats.rx_bytes += frame_length ; + dev->stats.rx_packets++ ; + dev->stats.rx_bytes += frame_length ; netif_rx(skb2) ; } /* if multiple buffers */ @@ -1182,8 +1180,8 @@ static int xl_xmit(struct sk_buff *skb, struct net_device *dev) txd->buffer = cpu_to_le32(pci_map_single(xl_priv->pdev, skb->data, skb->len, PCI_DMA_TODEVICE)); txd->buffer_length = cpu_to_le32(skb->len) | TXDNFRAGLAST; xl_priv->tx_ring_skb[tx_head] = skb ; - xl_priv->xl_stats.tx_packets++ ; - xl_priv->xl_stats.tx_bytes += skb->len ; + dev->stats.tx_packets++ ; + dev->stats.tx_bytes += skb->len ; /* * Set the nextptr of the previous descriptor equal to this descriptor, add XL_TX_RING_SIZE -1 @@ -1463,12 +1461,6 @@ static void xl_srb_bh(struct net_device *dev) return ; } -static struct net_device_stats * xl_get_stats(struct net_device *dev) -{ - struct xl_private *xl_priv = netdev_priv(dev); - return (struct net_device_stats *) &xl_priv->xl_stats; -} - static int xl_set_mac_address (struct net_device *dev, void *addr) { struct sockaddr *saddr = addr ; diff --git a/drivers/net/tokenring/3c359.h b/drivers/net/tokenring/3c359.h index b880cba0f6f..0f8b4ec8695 100644 --- a/drivers/net/tokenring/3c359.h +++ b/drivers/net/tokenring/3c359.h @@ -273,8 +273,6 @@ struct xl_private { struct wait_queue *srb_wait; volatile int asb_queued; - struct net_device_stats xl_stats ; - u16 mac_buffer ; u16 xl_lan_status ; u8 xl_ring_speed ; -- cgit v1.2.3-70-g09d2 From 3f8cb098859bbea29d7b3765a3102e4a6bf81b85 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Tue, 13 May 2008 01:41:28 -0400 Subject: drivers/net/lib8390: fix warning, trim trailing whitespace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix drivers/net/lib8390.c: In function ‘ei_tx_err’: drivers/net/lib8390.c:556: warning: unused variable ‘ei_local’ drivers/net/lib8390.c: In function ‘ei_rx_overrun’: drivers/net/lib8390.c:819: warning: unused variable ‘ei_local’ and also trim whitespace. Signed-off-by: Jeff Garzik --- drivers/net/lib8390.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/lib8390.c b/drivers/net/lib8390.c index 72ffbeb829c..ed495275b57 100644 --- a/drivers/net/lib8390.c +++ b/drivers/net/lib8390.c @@ -150,19 +150,19 @@ static void __NS8390_init(struct net_device *dev, int startp); * card means that approach caused horrible problems like losing serial data * at 38400 baud on some chips. Remember many 8390 nics on PCI were ISA * chips with FPGA front ends. - * + * * Ok the logic behind the 8390 is very simple: - * + * * Things to know * - IRQ delivery is asynchronous to the PCI bus * - Blocking the local CPU IRQ via spin locks was too slow * - The chip has register windows needing locking work - * + * * So the path was once (I say once as people appear to have changed it * in the mean time and it now looks rather bogus if the changes to use * disable_irq_nosync_irqsave are disabling the local IRQ) - * - * + * + * * Take the page lock * Mask the IRQ on chip * Disable the IRQ (but not mask locally- someone seems to have @@ -170,22 +170,22 @@ static void __NS8390_init(struct net_device *dev, int startp); * [This must be _nosync as the page lock may otherwise * deadlock us] * Drop the page lock and turn IRQs back on - * + * * At this point an existing IRQ may still be running but we can't * get a new one - * + * * Take the lock (so we know the IRQ has terminated) but don't mask * the IRQs on the processor * Set irqlock [for debug] - * + * * Transmit (slow as ****) - * + * * re-enable the IRQ - * - * + * + * * We have to use disable_irq because otherwise you will get delayed * interrupts on the APIC bus deadlocking the transmit path. - * + * * Quite hairy but the chip simply wasn't designed for SMP and you can't * even ACK an interrupt without risking corrupting other parallel * activities on the chip." [lkml, 25 Jul 2007] @@ -553,7 +553,6 @@ static void __ei_poll(struct net_device *dev) static void ei_tx_err(struct net_device *dev) { unsigned long e8390_base = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); unsigned char txsr = ei_inb_p(e8390_base+EN0_TSR); unsigned char tx_was_aborted = txsr & (ENTSR_ABT+ENTSR_FU); @@ -816,7 +815,6 @@ static void ei_rx_overrun(struct net_device *dev) { unsigned long e8390_base = dev->base_addr; unsigned char was_txing, must_resend = 0; - struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); /* * Record whether a Tx was in progress and then issue the -- cgit v1.2.3-70-g09d2 From 7d2e3cb7000b883a8e489485ac249be572fe17b1 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Tue, 13 May 2008 01:41:58 -0400 Subject: [netdrvr] Trim trailing whitespace for several drivers Signed-off-by: Jeff Garzik --- drivers/net/cpmac.c | 2 +- drivers/net/dm9000.c | 6 +++--- drivers/net/gianfar.c | 2 +- drivers/net/natsemi.c | 4 ++-- drivers/net/niu.h | 2 +- drivers/net/pcnet32.c | 6 +++--- drivers/net/qla3xxx.c | 4 ++-- drivers/net/s2io.c | 4 ++-- drivers/net/s2io.h | 2 +- drivers/net/sb1250-mac.c | 2 +- drivers/net/sis190.c | 2 +- drivers/net/sis900.c | 2 +- drivers/net/sky2.c | 2 +- drivers/net/spider_net.c | 4 ++-- drivers/net/tsi108_eth.c | 4 ++-- drivers/net/ucc_geth_ethtool.c | 4 ++-- 16 files changed, 26 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c index 2b5740b3d18..ae07100bb93 100644 --- a/drivers/net/cpmac.c +++ b/drivers/net/cpmac.c @@ -708,7 +708,7 @@ static void cpmac_tx_timeout(struct net_device *dev) spin_unlock(&priv->lock); if (netif_msg_tx_err(priv) && net_ratelimit()) printk(KERN_WARNING "%s: transmit timeout\n", dev->name); - /* + /* * FIXME: waking up random queue is not the best thing to * do... on the other hand why we got here at all? */ diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index e6fe2614ea6..12b4626102e 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -696,7 +696,7 @@ dm9000_probe(struct platform_device *pdev) if (!is_valid_ether_addr(ndev->dev_addr)) { /* try reading from mac */ - + mac_src = "chip"; for (i = 0; i < 6; i++) ndev->dev_addr[i] = ior(db, i+DM9000_PAR); @@ -746,7 +746,7 @@ dm9000_open(struct net_device *dev) dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n"); irqflags = DEFAULT_TRIGGER; } - + irqflags |= IRQF_SHARED; if (request_irq(dev->irq, &dm9000_interrupt, irqflags, dev->name, dev)) @@ -1089,7 +1089,7 @@ static int dm9000_wait_eeprom(board_info_t *db) /* The DM9000 data sheets say we should be able to * poll the ERRE bit in EPCR to wait for the EEPROM * operation. From testing several chips, this bit - * does not seem to work. + * does not seem to work. * * We attempt to use the bit, but fall back to the * timeout (which is why we do not return an error diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 587afe7be68..642dc633b44 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -925,7 +925,7 @@ rx_irq_fail: tx_irq_fail: free_irq(priv->interruptError, dev); err_irq_fail: -err_rxalloc_fail: +err_rxalloc_fail: rx_skb_fail: free_skb_resources(priv); tx_skb_fail: diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index 46119bb3770..b238ed0e8ac 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -664,7 +664,7 @@ static ssize_t natsemi_show_##_name(struct device *dev, \ NATSEMI_ATTR(dspcfg_workaround); static ssize_t natsemi_show_dspcfg_workaround(struct device *dev, - struct device_attribute *attr, + struct device_attribute *attr, char *buf) { struct netdev_private *np = netdev_priv(to_net_dev(dev)); @@ -687,7 +687,7 @@ static ssize_t natsemi_set_dspcfg_workaround(struct device *dev, || !strncmp("0", buf, count - 1)) new_setting = 0; else - return count; + return count; spin_lock_irqsave(&np->lock, flags); diff --git a/drivers/net/niu.h b/drivers/net/niu.h index 97ffbe137bc..101a3f1a8ec 100644 --- a/drivers/net/niu.h +++ b/drivers/net/niu.h @@ -281,7 +281,7 @@ #define XMAC_ADDR1 0x000a8UL #define XMAC_ADDR1_ADDR1 0x000000000000ffffULL -#define XMAC_ADDR2 0x000b0UL +#define XMAC_ADDR2 0x000b0UL #define XMAC_ADDR2_ADDR2 0x000000000000ffffULL #define XMAC_ADDR_CMPEN 0x00208UL diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 4eb322e5273..d0d5585114b 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -2006,7 +2006,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) err_free_ring: pcnet32_free_ring(dev); err_free_consistent: - pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block), + pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block), lp->init_block, lp->init_dma_addr); err_free_netdev: free_netdev(dev); @@ -3006,7 +3006,7 @@ static void __devexit pcnet32_remove_one(struct pci_dev *pdev) unregister_netdev(dev); pcnet32_free_ring(dev); release_region(dev->base_addr, PCNET32_TOTAL_SIZE); - pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block), + pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block), lp->init_block, lp->init_dma_addr); free_netdev(dev); pci_disable_device(pdev); @@ -3089,7 +3089,7 @@ static void __exit pcnet32_cleanup_module(void) unregister_netdev(pcnet32_dev); pcnet32_free_ring(pcnet32_dev); release_region(pcnet32_dev->base_addr, PCNET32_TOTAL_SIZE); - pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block), + pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block), lp->init_block, lp->init_dma_addr); free_netdev(pcnet32_dev); pcnet32_dev = next_dev; diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c index b7f7b2227d5..5f608780c3e 100644 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -1437,9 +1437,9 @@ static void ql_phy_start_neg_ex(struct ql3_adapter *qdev) reg &= ~PHY_GIG_ALL_PARAMS; if(portConfiguration & PORT_CONFIG_1000MB_SPEED) { - if(portConfiguration & PORT_CONFIG_FULL_DUPLEX_ENABLED) + if(portConfiguration & PORT_CONFIG_FULL_DUPLEX_ENABLED) reg |= PHY_GIG_ADV_1000F; - else + else reg |= PHY_GIG_ADV_1000H; } diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 523478ebfd6..75bde647583 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -2547,7 +2547,7 @@ static int fill_rx_buffers(struct ring_info *ring) if (block_no) rxd_index += (block_no * ring->rxd_count); - if ((block_no == block_no1) && + if ((block_no == block_no1) && (off == ring->rx_curr_get_info.offset) && (rxdp->Host_Control)) { DBG_PRINT(INTR_DBG, "%s: Get and Put", @@ -2593,7 +2593,7 @@ static int fill_rx_buffers(struct ring_info *ring) first_rxdp->Control_1 |= RXD_OWN_XENA; } stats->mem_alloc_fail_cnt++; - + return -ENOMEM ; } stats->mem_allocated += skb->truesize; diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 0709ebae913..58229dcbf5e 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -747,7 +747,7 @@ struct ring_info { /* interface MTU value */ unsigned mtu; - + /* Buffer Address store. */ struct buffAdd **ba; diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index 888b7dec986..29519902517 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -1063,7 +1063,7 @@ static void sbmac_netpoll(struct net_device *netdev) ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_RX_CH0), sc->sbm_imr); #else - __raw_writeq((M_MAC_INT_CHANNEL << S_MAC_TX_CH0) | + __raw_writeq((M_MAC_INT_CHANNEL << S_MAC_TX_CH0) | (M_MAC_INT_CHANNEL << S_MAC_RX_CH0), sc->sbm_imr); #endif } diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index abc63b0663b..3fe01763760 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -1656,7 +1656,7 @@ static inline void sis190_init_rxfilter(struct net_device *dev) SIS_PCI_COMMIT(); } -static int __devinit sis190_get_mac_addr(struct pci_dev *pdev, +static int __devinit sis190_get_mac_addr(struct pci_dev *pdev, struct net_device *dev) { int rc; diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index ec95e493ac1..fa3a460f8e2 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -1766,7 +1766,7 @@ static int sis900_rx(struct net_device *net_dev) skb = sis_priv->rx_skbuff[entry]; net_dev->stats.rx_dropped++; goto refill_rx_ring; - } + } /* This situation should never happen, but due to some unknow bugs, it is possible that diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index f226bcac7d1..4b0f0335877 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -3369,7 +3369,7 @@ static void sky2_led(struct sky2_port *sky2, enum led_mode mode) gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg); } else - gm_phy_write(hw, port, PHY_MARV_LED_OVER, + gm_phy_write(hw, port, PHY_MARV_LED_OVER, PHY_M_LED_MO_DUP(mode) | PHY_M_LED_MO_10(mode) | PHY_M_LED_MO_100(mode) | diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 47767160627..00aa0b108cb 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -1704,7 +1704,7 @@ spider_net_poll_controller(struct net_device *netdev) * * spider_net_enable_interrupt enables several interrupts */ -static void +static void spider_net_enable_interrupts(struct spider_net_card *card) { spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK, @@ -1721,7 +1721,7 @@ spider_net_enable_interrupts(struct spider_net_card *card) * * spider_net_disable_interrupts disables all the interrupts */ -static void +static void spider_net_disable_interrupts(struct spider_net_card *card) { spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK, 0); diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c index 6017d5267d0..c028facd934 100644 --- a/drivers/net/tsi108_eth.c +++ b/drivers/net/tsi108_eth.c @@ -1526,7 +1526,7 @@ static int tsi108_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) struct tsi108_prv_data *data = netdev_priv(dev); unsigned long flags; int rc; - + spin_lock_irqsave(&data->txlock, flags); rc = mii_ethtool_gset(&data->mii_if, cmd); spin_unlock_irqrestore(&data->txlock, flags); @@ -1543,7 +1543,7 @@ static int tsi108_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) spin_lock_irqsave(&data->txlock, flags); rc = mii_ethtool_sset(&data->mii_if, cmd); spin_unlock_irqrestore(&data->txlock, flags); - + return rc; } diff --git a/drivers/net/ucc_geth_ethtool.c b/drivers/net/ucc_geth_ethtool.c index 9a9622c13e2..33200038a14 100644 --- a/drivers/net/ucc_geth_ethtool.c +++ b/drivers/net/ucc_geth_ethtool.c @@ -5,7 +5,7 @@ * * Author: Li Yang * - * Limitation: + * Limitation: * Can only get/set setttings of the first queue. * Need to re-open the interface manually after changing some paramters. * @@ -165,7 +165,7 @@ uec_set_pauseparam(struct net_device *netdev, ugeth->ug_info->receiveFlowControl = pause->rx_pause; ugeth->ug_info->transmitFlowControl = pause->tx_pause; - + if (ugeth->phydev->autoneg) { if (netif_running(netdev)) { /* FIXME: automatically restart */ -- cgit v1.2.3-70-g09d2 From 54ef0ec22a39071a4e7fbedd201cecac9ac6e8a7 Mon Sep 17 00:00:00 2001 From: Becky Bruce Date: Fri, 2 May 2008 14:40:38 -0500 Subject: [POWERPC] Delete unused fec_8xx net driver This driver has been superseded by fs_enet and is no longer in use. Signed-off-by: Becky Bruce Signed-off-by: Kumar Gala --- drivers/net/Kconfig | 1 - drivers/net/Makefile | 1 - drivers/net/fec_8xx/Kconfig | 20 - drivers/net/fec_8xx/Makefile | 12 - drivers/net/fec_8xx/fec_8xx-netta.c | 151 ----- drivers/net/fec_8xx/fec_8xx.h | 220 ------ drivers/net/fec_8xx/fec_main.c | 1264 ----------------------------------- drivers/net/fec_8xx/fec_mii.c | 418 ------------ 8 files changed, 2087 deletions(-) delete mode 100644 drivers/net/fec_8xx/Kconfig delete mode 100644 drivers/net/fec_8xx/Makefile delete mode 100644 drivers/net/fec_8xx/fec_8xx-netta.c delete mode 100644 drivers/net/fec_8xx/fec_8xx.h delete mode 100644 drivers/net/fec_8xx/fec_main.c delete mode 100644 drivers/net/fec_8xx/fec_mii.c (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index d27f54a2df7..009e8fdcfe5 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1884,7 +1884,6 @@ config NE_H8300 Say Y here if you want to use the NE2000 compatible controller on the Renesas H8/300 processor. -source "drivers/net/fec_8xx/Kconfig" source "drivers/net/fs_enet/Kconfig" endif # NET_ETHERNET diff --git a/drivers/net/Makefile b/drivers/net/Makefile index dcbfe842115..9010e58da0f 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -217,7 +217,6 @@ obj-$(CONFIG_SMC91X) += smc91x.o obj-$(CONFIG_SMC911X) += smc911x.o obj-$(CONFIG_BFIN_MAC) += bfin_mac.o obj-$(CONFIG_DM9000) += dm9000.o -obj-$(CONFIG_FEC_8XX) += fec_8xx/ obj-$(CONFIG_PASEMI_MAC) += pasemi_mac_driver.o pasemi_mac_driver-objs := pasemi_mac.o pasemi_mac_ethtool.o obj-$(CONFIG_MLX4_CORE) += mlx4/ diff --git a/drivers/net/fec_8xx/Kconfig b/drivers/net/fec_8xx/Kconfig deleted file mode 100644 index afb34ded26e..00000000000 --- a/drivers/net/fec_8xx/Kconfig +++ /dev/null @@ -1,20 +0,0 @@ -config FEC_8XX - tristate "Motorola 8xx FEC driver" - depends on 8XX - select MII - -config FEC_8XX_GENERIC_PHY - bool "Support any generic PHY" - depends on FEC_8XX - default y - -config FEC_8XX_DM9161_PHY - bool "Support DM9161 PHY" - depends on FEC_8XX - default n - -config FEC_8XX_LXT971_PHY - bool "Support LXT971/LXT972 PHY" - depends on FEC_8XX - default n - diff --git a/drivers/net/fec_8xx/Makefile b/drivers/net/fec_8xx/Makefile deleted file mode 100644 index 70c54f8c48e..00000000000 --- a/drivers/net/fec_8xx/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# -# Makefile for the Motorola 8xx FEC ethernet controller -# - -obj-$(CONFIG_FEC_8XX) += fec_8xx.o - -fec_8xx-objs := fec_main.o fec_mii.o - -# the platform instantatiation objects -ifeq ($(CONFIG_NETTA),y) -fec_8xx-objs += fec_8xx-netta.o -endif diff --git a/drivers/net/fec_8xx/fec_8xx-netta.c b/drivers/net/fec_8xx/fec_8xx-netta.c deleted file mode 100644 index 79deee222e2..00000000000 --- a/drivers/net/fec_8xx/fec_8xx-netta.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * FEC instantatiation file for NETTA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "fec_8xx.h" - -/*************************************************/ - -static struct fec_platform_info fec1_info = { - .fec_no = 0, - .use_mdio = 1, - .phy_addr = 8, - .fec_irq = SIU_LEVEL1, - .phy_irq = CPM_IRQ_OFFSET + CPMVEC_PIO_PC6, - .rx_ring = 128, - .tx_ring = 16, - .rx_copybreak = 240, - .use_napi = 1, - .napi_weight = 17, -}; - -static struct fec_platform_info fec2_info = { - .fec_no = 1, - .use_mdio = 1, - .phy_addr = 2, - .fec_irq = SIU_LEVEL3, - .phy_irq = CPM_IRQ_OFFSET + CPMVEC_PIO_PC7, - .rx_ring = 128, - .tx_ring = 16, - .rx_copybreak = 240, - .use_napi = 1, - .napi_weight = 17, -}; - -static struct net_device *fec1_dev; -static struct net_device *fec2_dev; - -/* XXX custom u-boot & Linux startup needed */ -extern const char *__fw_getenv(const char *var); - -/* access ports */ -#define setbits32(_addr, _v) __fec_out32(&(_addr), __fec_in32(&(_addr)) | (_v)) -#define clrbits32(_addr, _v) __fec_out32(&(_addr), __fec_in32(&(_addr)) & ~(_v)) - -#define setbits16(_addr, _v) __fec_out16(&(_addr), __fec_in16(&(_addr)) | (_v)) -#define clrbits16(_addr, _v) __fec_out16(&(_addr), __fec_in16(&(_addr)) & ~(_v)) - -int fec_8xx_platform_init(void) -{ - immap_t *immap = (immap_t *)IMAP_ADDR; - bd_t *bd = (bd_t *) __res; - const char *s; - char *e; - int i; - - /* use MDC for MII */ - setbits16(immap->im_ioport.iop_pdpar, 0x0080); - clrbits16(immap->im_ioport.iop_pddir, 0x0080); - - /* configure FEC1 pins */ - setbits16(immap->im_ioport.iop_papar, 0xe810); - setbits16(immap->im_ioport.iop_padir, 0x0810); - clrbits16(immap->im_ioport.iop_padir, 0xe000); - - setbits32(immap->im_cpm.cp_pbpar, 0x00000001); - clrbits32(immap->im_cpm.cp_pbdir, 0x00000001); - - setbits32(immap->im_cpm.cp_cptr, 0x00000100); - clrbits32(immap->im_cpm.cp_cptr, 0x00000050); - - clrbits16(immap->im_ioport.iop_pcpar, 0x0200); - clrbits16(immap->im_ioport.iop_pcdir, 0x0200); - clrbits16(immap->im_ioport.iop_pcso, 0x0200); - setbits16(immap->im_ioport.iop_pcint, 0x0200); - - /* configure FEC2 pins */ - setbits32(immap->im_cpm.cp_pepar, 0x00039620); - setbits32(immap->im_cpm.cp_pedir, 0x00039620); - setbits32(immap->im_cpm.cp_peso, 0x00031000); - clrbits32(immap->im_cpm.cp_peso, 0x00008620); - - setbits32(immap->im_cpm.cp_cptr, 0x00000080); - clrbits32(immap->im_cpm.cp_cptr, 0x00000028); - - clrbits16(immap->im_ioport.iop_pcpar, 0x0200); - clrbits16(immap->im_ioport.iop_pcdir, 0x0200); - clrbits16(immap->im_ioport.iop_pcso, 0x0200); - setbits16(immap->im_ioport.iop_pcint, 0x0200); - - /* fill up */ - fec1_info.sys_clk = bd->bi_intfreq; - fec2_info.sys_clk = bd->bi_intfreq; - - s = __fw_getenv("ethaddr"); - if (s != NULL) { - for (i = 0; i < 6; i++) { - fec1_info.macaddr[i] = simple_strtoul(s, &e, 16); - if (*e) - s = e + 1; - } - } - - s = __fw_getenv("eth1addr"); - if (s != NULL) { - for (i = 0; i < 6; i++) { - fec2_info.macaddr[i] = simple_strtoul(s, &e, 16); - if (*e) - s = e + 1; - } - } - - fec_8xx_init_one(&fec1_info, &fec1_dev); - fec_8xx_init_one(&fec2_info, &fec2_dev); - - return fec1_dev != NULL && fec2_dev != NULL ? 0 : -1; -} - -void fec_8xx_platform_cleanup(void) -{ - if (fec2_dev != NULL) - fec_8xx_cleanup_one(fec2_dev); - - if (fec1_dev != NULL) - fec_8xx_cleanup_one(fec1_dev); -} diff --git a/drivers/net/fec_8xx/fec_8xx.h b/drivers/net/fec_8xx/fec_8xx.h deleted file mode 100644 index f3b1c6fbba8..00000000000 --- a/drivers/net/fec_8xx/fec_8xx.h +++ /dev/null @@ -1,220 +0,0 @@ -#ifndef FEC_8XX_H -#define FEC_8XX_H - -#include -#include - -#include - -/* HW info */ - -/* CRC polynomium used by the FEC for the multicast group filtering */ -#define FEC_CRC_POLY 0x04C11DB7 - -#define MII_ADVERTISE_HALF (ADVERTISE_100HALF | \ - ADVERTISE_10HALF | ADVERTISE_CSMA) -#define MII_ADVERTISE_ALL (ADVERTISE_100FULL | \ - ADVERTISE_10FULL | MII_ADVERTISE_HALF) - -/* Interrupt events/masks. -*/ -#define FEC_ENET_HBERR 0x80000000U /* Heartbeat error */ -#define FEC_ENET_BABR 0x40000000U /* Babbling receiver */ -#define FEC_ENET_BABT 0x20000000U /* Babbling transmitter */ -#define FEC_ENET_GRA 0x10000000U /* Graceful stop complete */ -#define FEC_ENET_TXF 0x08000000U /* Full frame transmitted */ -#define FEC_ENET_TXB 0x04000000U /* A buffer was transmitted */ -#define FEC_ENET_RXF 0x02000000U /* Full frame received */ -#define FEC_ENET_RXB 0x01000000U /* A buffer was received */ -#define FEC_ENET_MII 0x00800000U /* MII interrupt */ -#define FEC_ENET_EBERR 0x00400000U /* SDMA bus error */ - -#define FEC_ECNTRL_PINMUX 0x00000004 -#define FEC_ECNTRL_ETHER_EN 0x00000002 -#define FEC_ECNTRL_RESET 0x00000001 - -#define FEC_RCNTRL_BC_REJ 0x00000010 -#define FEC_RCNTRL_PROM 0x00000008 -#define FEC_RCNTRL_MII_MODE 0x00000004 -#define FEC_RCNTRL_DRT 0x00000002 -#define FEC_RCNTRL_LOOP 0x00000001 - -#define FEC_TCNTRL_FDEN 0x00000004 -#define FEC_TCNTRL_HBC 0x00000002 -#define FEC_TCNTRL_GTS 0x00000001 - -/* values for MII phy_status */ - -#define PHY_CONF_ANE 0x0001 /* 1 auto-negotiation enabled */ -#define PHY_CONF_LOOP 0x0002 /* 1 loopback mode enabled */ -#define PHY_CONF_SPMASK 0x00f0 /* mask for speed */ -#define PHY_CONF_10HDX 0x0010 /* 10 Mbit half duplex supported */ -#define PHY_CONF_10FDX 0x0020 /* 10 Mbit full duplex supported */ -#define PHY_CONF_100HDX 0x0040 /* 100 Mbit half duplex supported */ -#define PHY_CONF_100FDX 0x0080 /* 100 Mbit full duplex supported */ - -#define PHY_STAT_LINK 0x0100 /* 1 up - 0 down */ -#define PHY_STAT_FAULT 0x0200 /* 1 remote fault */ -#define PHY_STAT_ANC 0x0400 /* 1 auto-negotiation complete */ -#define PHY_STAT_SPMASK 0xf000 /* mask for speed */ -#define PHY_STAT_10HDX 0x1000 /* 10 Mbit half duplex selected */ -#define PHY_STAT_10FDX 0x2000 /* 10 Mbit full duplex selected */ -#define PHY_STAT_100HDX 0x4000 /* 100 Mbit half duplex selected */ -#define PHY_STAT_100FDX 0x8000 /* 100 Mbit full duplex selected */ - -typedef struct phy_info { - unsigned int id; - const char *name; - void (*startup) (struct net_device * dev); - void (*shutdown) (struct net_device * dev); - void (*ack_int) (struct net_device * dev); -} phy_info_t; - -/* The FEC stores dest/src/type, data, and checksum for receive packets. - */ -#define MAX_MTU 1508 /* Allow fullsized pppoe packets over VLAN */ -#define MIN_MTU 46 /* this is data size */ -#define CRC_LEN 4 - -#define PKT_MAXBUF_SIZE (MAX_MTU+ETH_HLEN+CRC_LEN) -#define PKT_MINBUF_SIZE (MIN_MTU+ETH_HLEN+CRC_LEN) - -/* Must be a multiple of 4 */ -#define PKT_MAXBLR_SIZE ((PKT_MAXBUF_SIZE+3) & ~3) -/* This is needed so that invalidate_xxx wont invalidate too much */ -#define ENET_RX_FRSIZE L1_CACHE_ALIGN(PKT_MAXBUF_SIZE) - -/* platform interface */ - -struct fec_platform_info { - int fec_no; /* FEC index */ - int use_mdio; /* use external MII */ - int phy_addr; /* the phy address */ - int fec_irq, phy_irq; /* the irq for the controller */ - int rx_ring, tx_ring; /* number of buffers on rx */ - int sys_clk; /* system clock */ - __u8 macaddr[6]; /* mac address */ - int rx_copybreak; /* limit we copy small frames */ - int use_napi; /* use NAPI */ - int napi_weight; /* NAPI weight */ -}; - -/* forward declaration */ -struct fec; - -struct fec_enet_private { - spinlock_t lock; /* during all ops except TX pckt processing */ - spinlock_t tx_lock; /* during fec_start_xmit and fec_tx */ - struct net_device *dev; - struct napi_struct napi; - int fecno; - struct fec *fecp; - const struct fec_platform_info *fpi; - int rx_ring, tx_ring; - dma_addr_t ring_mem_addr; - void *ring_base; - struct sk_buff **rx_skbuff; - struct sk_buff **tx_skbuff; - cbd_t *rx_bd_base; /* Address of Rx and Tx buffers. */ - cbd_t *tx_bd_base; - cbd_t *dirty_tx; /* ring entries to be free()ed. */ - cbd_t *cur_rx; - cbd_t *cur_tx; - int tx_free; - struct net_device_stats stats; - struct timer_list phy_timer_list; - const struct phy_info *phy; - unsigned int fec_phy_speed; - __u32 msg_enable; - struct mii_if_info mii_if; -}; - -/***************************************************************************/ - -void fec_restart(struct net_device *dev, int duplex, int speed); -void fec_stop(struct net_device *dev); - -/***************************************************************************/ - -int fec_mii_read(struct net_device *dev, int phy_id, int location); -void fec_mii_write(struct net_device *dev, int phy_id, int location, int value); - -int fec_mii_phy_id_detect(struct net_device *dev); -void fec_mii_startup(struct net_device *dev); -void fec_mii_shutdown(struct net_device *dev); -void fec_mii_ack_int(struct net_device *dev); - -void fec_mii_link_status_change_check(struct net_device *dev, int init_media); - -/***************************************************************************/ - -#define FEC1_NO 0x00 -#define FEC2_NO 0x01 -#define FEC3_NO 0x02 - -int fec_8xx_init_one(const struct fec_platform_info *fpi, - struct net_device **devp); -int fec_8xx_cleanup_one(struct net_device *dev); - -/***************************************************************************/ - -#define DRV_MODULE_NAME "fec_8xx" -#define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "0.1" -#define DRV_MODULE_RELDATE "May 6, 2004" - -/***************************************************************************/ - -int fec_8xx_platform_init(void); -void fec_8xx_platform_cleanup(void); - -/***************************************************************************/ - -/* FEC access macros */ -#if defined(CONFIG_8xx) -/* for a 8xx __raw_xxx's are sufficient */ -#define __fec_out32(addr, x) __raw_writel(x, addr) -#define __fec_out16(addr, x) __raw_writew(x, addr) -#define __fec_in32(addr) __raw_readl(addr) -#define __fec_in16(addr) __raw_readw(addr) -#else -/* for others play it safe */ -#define __fec_out32(addr, x) out_be32(addr, x) -#define __fec_out16(addr, x) out_be16(addr, x) -#define __fec_in32(addr) in_be32(addr) -#define __fec_in16(addr) in_be16(addr) -#endif - -/* write */ -#define FW(_fecp, _reg, _v) __fec_out32(&(_fecp)->fec_ ## _reg, (_v)) - -/* read */ -#define FR(_fecp, _reg) __fec_in32(&(_fecp)->fec_ ## _reg) - -/* set bits */ -#define FS(_fecp, _reg, _v) FW(_fecp, _reg, FR(_fecp, _reg) | (_v)) - -/* clear bits */ -#define FC(_fecp, _reg, _v) FW(_fecp, _reg, FR(_fecp, _reg) & ~(_v)) - -/* buffer descriptor access macros */ - -/* write */ -#define CBDW_SC(_cbd, _sc) __fec_out16(&(_cbd)->cbd_sc, (_sc)) -#define CBDW_DATLEN(_cbd, _datlen) __fec_out16(&(_cbd)->cbd_datlen, (_datlen)) -#define CBDW_BUFADDR(_cbd, _bufaddr) __fec_out32(&(_cbd)->cbd_bufaddr, (_bufaddr)) - -/* read */ -#define CBDR_SC(_cbd) __fec_in16(&(_cbd)->cbd_sc) -#define CBDR_DATLEN(_cbd) __fec_in16(&(_cbd)->cbd_datlen) -#define CBDR_BUFADDR(_cbd) __fec_in32(&(_cbd)->cbd_bufaddr) - -/* set bits */ -#define CBDS_SC(_cbd, _sc) CBDW_SC(_cbd, CBDR_SC(_cbd) | (_sc)) - -/* clear bits */ -#define CBDC_SC(_cbd, _sc) CBDW_SC(_cbd, CBDR_SC(_cbd) & ~(_sc)) - -/***************************************************************************/ - -#endif diff --git a/drivers/net/fec_8xx/fec_main.c b/drivers/net/fec_8xx/fec_main.c deleted file mode 100644 index ca8d2e83ab0..00000000000 --- a/drivers/net/fec_8xx/fec_main.c +++ /dev/null @@ -1,1264 +0,0 @@ -/* - * Fast Ethernet Controller (FEC) driver for Motorola MPC8xx. - * - * Copyright (c) 2003 Intracom S.A. - * by Pantelis Antoniou - * - * Heavily based on original FEC driver by Dan Malek - * and modifications by Joakim Tjernlund - * - * Released under the GPL - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "fec_8xx.h" - -/*************************************************/ - -#define FEC_MAX_MULTICAST_ADDRS 64 - -/*************************************************/ - -static char version[] __devinitdata = - DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")" "\n"; - -MODULE_AUTHOR("Pantelis Antoniou "); -MODULE_DESCRIPTION("Motorola 8xx FEC ethernet driver"); -MODULE_LICENSE("GPL"); - -int fec_8xx_debug = -1; /* -1 == use FEC_8XX_DEF_MSG_ENABLE as value */ -module_param(fec_8xx_debug, int, 0); -MODULE_PARM_DESC(fec_8xx_debug, - "FEC 8xx bitmapped debugging message enable value"); - - -/*************************************************/ - -/* - * Delay to wait for FEC reset command to complete (in us) - */ -#define FEC_RESET_DELAY 50 - -/*****************************************************************************************/ - -static void fec_whack_reset(fec_t * fecp) -{ - int i; - - /* - * Whack a reset. We should wait for this. - */ - FW(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET); - for (i = 0; - (FR(fecp, ecntrl) & FEC_ECNTRL_RESET) != 0 && i < FEC_RESET_DELAY; - i++) - udelay(1); - - if (i == FEC_RESET_DELAY) - printk(KERN_WARNING "FEC Reset timeout!\n"); - -} - -/****************************************************************************/ - -/* - * Transmitter timeout. - */ -#define TX_TIMEOUT (2*HZ) - -/****************************************************************************/ - -/* - * Returns the CRC needed when filling in the hash table for - * multicast group filtering - * pAddr must point to a MAC address (6 bytes) - */ -static __u32 fec_mulicast_calc_crc(char *pAddr) -{ - u8 byte; - int byte_count; - int bit_count; - __u32 crc = 0xffffffff; - u8 msb; - - for (byte_count = 0; byte_count < 6; byte_count++) { - byte = pAddr[byte_count]; - for (bit_count = 0; bit_count < 8; bit_count++) { - msb = crc >> 31; - crc <<= 1; - if (msb ^ (byte & 0x1)) { - crc ^= FEC_CRC_POLY; - } - byte >>= 1; - } - } - return (crc); -} - -/* - * Set or clear the multicast filter for this adaptor. - * Skeleton taken from sunlance driver. - * The CPM Ethernet implementation allows Multicast as well as individual - * MAC address filtering. Some of the drivers check to make sure it is - * a group multicast address, and discard those that are not. I guess I - * will do the same for now, but just remove the test if you want - * individual filtering as well (do the upper net layers want or support - * this kind of feature?). - */ -static void fec_set_multicast_list(struct net_device *dev) -{ - struct fec_enet_private *fep = netdev_priv(dev); - fec_t *fecp = fep->fecp; - struct dev_mc_list *pmc; - __u32 crc; - int temp; - __u32 csrVal; - int hash_index; - __u32 hthi, htlo; - unsigned long flags; - - - if ((dev->flags & IFF_PROMISC) != 0) { - - spin_lock_irqsave(&fep->lock, flags); - FS(fecp, r_cntrl, FEC_RCNTRL_PROM); - spin_unlock_irqrestore(&fep->lock, flags); - - /* - * Log any net taps. - */ - printk(KERN_WARNING DRV_MODULE_NAME - ": %s: Promiscuous mode enabled.\n", dev->name); - return; - - } - - if ((dev->flags & IFF_ALLMULTI) != 0 || - dev->mc_count > FEC_MAX_MULTICAST_ADDRS) { - /* - * Catch all multicast addresses, set the filter to all 1's. - */ - hthi = 0xffffffffU; - htlo = 0xffffffffU; - } else { - hthi = 0; - htlo = 0; - - /* - * Now populate the hash table - */ - for (pmc = dev->mc_list; pmc != NULL; pmc = pmc->next) { - crc = fec_mulicast_calc_crc(pmc->dmi_addr); - temp = (crc & 0x3f) >> 1; - hash_index = ((temp & 0x01) << 4) | - ((temp & 0x02) << 2) | - ((temp & 0x04)) | - ((temp & 0x08) >> 2) | - ((temp & 0x10) >> 4); - csrVal = (1 << hash_index); - if (crc & 1) - hthi |= csrVal; - else - htlo |= csrVal; - } - } - - spin_lock_irqsave(&fep->lock, flags); - FC(fecp, r_cntrl, FEC_RCNTRL_PROM); - FW(fecp, hash_table_high, hthi); - FW(fecp, hash_table_low, htlo); - spin_unlock_irqrestore(&fep->lock, flags); -} - -static int fec_set_mac_address(struct net_device *dev, void *addr) -{ - struct sockaddr *mac = addr; - struct fec_enet_private *fep = netdev_priv(dev); - struct fec *fecp = fep->fecp; - int i; - __u32 addrhi, addrlo; - unsigned long flags; - - /* Get pointer to SCC area in parameter RAM. */ - for (i = 0; i < 6; i++) - dev->dev_addr[i] = mac->sa_data[i]; - - /* - * Set station address. - */ - addrhi = ((__u32) dev->dev_addr[0] << 24) | - ((__u32) dev->dev_addr[1] << 16) | - ((__u32) dev->dev_addr[2] << 8) | - (__u32) dev->dev_addr[3]; - addrlo = ((__u32) dev->dev_addr[4] << 24) | - ((__u32) dev->dev_addr[5] << 16); - - spin_lock_irqsave(&fep->lock, flags); - FW(fecp, addr_low, addrhi); - FW(fecp, addr_high, addrlo); - spin_unlock_irqrestore(&fep->lock, flags); - - return 0; -} - -/* - * This function is called to start or restart the FEC during a link - * change. This only happens when switching between half and full - * duplex. - */ -void fec_restart(struct net_device *dev, int duplex, int speed) -{ -#ifdef CONFIG_DUET - immap_t *immap = (immap_t *) IMAP_ADDR; - __u32 cptr; -#endif - struct fec_enet_private *fep = netdev_priv(dev); - struct fec *fecp = fep->fecp; - const struct fec_platform_info *fpi = fep->fpi; - cbd_t *bdp; - struct sk_buff *skb; - int i; - __u32 addrhi, addrlo; - - fec_whack_reset(fep->fecp); - - /* - * Set station address. - */ - addrhi = ((__u32) dev->dev_addr[0] << 24) | - ((__u32) dev->dev_addr[1] << 16) | - ((__u32) dev->dev_addr[2] << 8) | - (__u32) dev->dev_addr[3]; - addrlo = ((__u32) dev->dev_addr[4] << 24) | - ((__u32) dev->dev_addr[5] << 16); - FW(fecp, addr_low, addrhi); - FW(fecp, addr_high, addrlo); - - /* - * Reset all multicast. - */ - FW(fecp, hash_table_high, 0); - FW(fecp, hash_table_low, 0); - - /* - * Set maximum receive buffer size. - */ - FW(fecp, r_buff_size, PKT_MAXBLR_SIZE); - FW(fecp, r_hash, PKT_MAXBUF_SIZE); - - /* - * Set receive and transmit descriptor base. - */ - FW(fecp, r_des_start, iopa((__u32) (fep->rx_bd_base))); - FW(fecp, x_des_start, iopa((__u32) (fep->tx_bd_base))); - - fep->dirty_tx = fep->cur_tx = fep->tx_bd_base; - fep->tx_free = fep->tx_ring; - fep->cur_rx = fep->rx_bd_base; - - /* - * Reset SKB receive buffers - */ - for (i = 0; i < fep->rx_ring; i++) { - if ((skb = fep->rx_skbuff[i]) == NULL) - continue; - fep->rx_skbuff[i] = NULL; - dev_kfree_skb(skb); - } - - /* - * Initialize the receive buffer descriptors. - */ - for (i = 0, bdp = fep->rx_bd_base; i < fep->rx_ring; i++, bdp++) { - skb = dev_alloc_skb(ENET_RX_FRSIZE); - if (skb == NULL) { - printk(KERN_WARNING DRV_MODULE_NAME - ": %s Memory squeeze, unable to allocate skb\n", - dev->name); - fep->stats.rx_dropped++; - break; - } - fep->rx_skbuff[i] = skb; - skb->dev = dev; - CBDW_BUFADDR(bdp, dma_map_single(NULL, skb->data, - L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), - DMA_FROM_DEVICE)); - CBDW_DATLEN(bdp, 0); /* zero */ - CBDW_SC(bdp, BD_ENET_RX_EMPTY | - ((i < fep->rx_ring - 1) ? 0 : BD_SC_WRAP)); - } - /* - * if we failed, fillup remainder - */ - for (; i < fep->rx_ring; i++, bdp++) { - fep->rx_skbuff[i] = NULL; - CBDW_SC(bdp, (i < fep->rx_ring - 1) ? 0 : BD_SC_WRAP); - } - - /* - * Reset SKB transmit buffers. - */ - for (i = 0; i < fep->tx_ring; i++) { - if ((skb = fep->tx_skbuff[i]) == NULL) - continue; - fep->tx_skbuff[i] = NULL; - dev_kfree_skb(skb); - } - - /* - * ...and the same for transmit. - */ - for (i = 0, bdp = fep->tx_bd_base; i < fep->tx_ring; i++, bdp++) { - fep->tx_skbuff[i] = NULL; - CBDW_BUFADDR(bdp, virt_to_bus(NULL)); - CBDW_DATLEN(bdp, 0); - CBDW_SC(bdp, (i < fep->tx_ring - 1) ? 0 : BD_SC_WRAP); - } - - /* - * Enable big endian and don't care about SDMA FC. - */ - FW(fecp, fun_code, 0x78000000); - - /* - * Set MII speed. - */ - FW(fecp, mii_speed, fep->fec_phy_speed); - - /* - * Clear any outstanding interrupt. - */ - FW(fecp, ievent, 0xffc0); - FW(fecp, ivec, (fpi->fec_irq / 2) << 29); - - /* - * adjust to speed (only for DUET & RMII) - */ -#ifdef CONFIG_DUET - cptr = in_be32(&immap->im_cpm.cp_cptr); - switch (fpi->fec_no) { - case 0: - /* - * check if in RMII mode - */ - if ((cptr & 0x100) == 0) - break; - - if (speed == 10) - cptr |= 0x0000010; - else if (speed == 100) - cptr &= ~0x0000010; - break; - case 1: - /* - * check if in RMII mode - */ - if ((cptr & 0x80) == 0) - break; - - if (speed == 10) - cptr |= 0x0000008; - else if (speed == 100) - cptr &= ~0x0000008; - break; - default: - break; - } - out_be32(&immap->im_cpm.cp_cptr, cptr); -#endif - - FW(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ - /* - * adjust to duplex mode - */ - if (duplex) { - FC(fecp, r_cntrl, FEC_RCNTRL_DRT); - FS(fecp, x_cntrl, FEC_TCNTRL_FDEN); /* FD enable */ - } else { - FS(fecp, r_cntrl, FEC_RCNTRL_DRT); - FC(fecp, x_cntrl, FEC_TCNTRL_FDEN); /* FD disable */ - } - - /* - * Enable interrupts we wish to service. - */ - FW(fecp, imask, FEC_ENET_TXF | FEC_ENET_TXB | - FEC_ENET_RXF | FEC_ENET_RXB); - - /* - * And last, enable the transmit and receive processing. - */ - FW(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN); - FW(fecp, r_des_active, 0x01000000); -} - -void fec_stop(struct net_device *dev) -{ - struct fec_enet_private *fep = netdev_priv(dev); - fec_t *fecp = fep->fecp; - struct sk_buff *skb; - int i; - - if ((FR(fecp, ecntrl) & FEC_ECNTRL_ETHER_EN) == 0) - return; /* already down */ - - FW(fecp, x_cntrl, 0x01); /* Graceful transmit stop */ - for (i = 0; ((FR(fecp, ievent) & 0x10000000) == 0) && - i < FEC_RESET_DELAY; i++) - udelay(1); - - if (i == FEC_RESET_DELAY) - printk(KERN_WARNING DRV_MODULE_NAME - ": %s FEC timeout on graceful transmit stop\n", - dev->name); - /* - * Disable FEC. Let only MII interrupts. - */ - FW(fecp, imask, 0); - FW(fecp, ecntrl, ~FEC_ECNTRL_ETHER_EN); - - /* - * Reset SKB transmit buffers. - */ - for (i = 0; i < fep->tx_ring; i++) { - if ((skb = fep->tx_skbuff[i]) == NULL) - continue; - fep->tx_skbuff[i] = NULL; - dev_kfree_skb(skb); - } - - /* - * Reset SKB receive buffers - */ - for (i = 0; i < fep->rx_ring; i++) { - if ((skb = fep->rx_skbuff[i]) == NULL) - continue; - fep->rx_skbuff[i] = NULL; - dev_kfree_skb(skb); - } -} - -/* common receive function */ -static int fec_enet_rx_common(struct fec_enet_private *ep, - struct net_device *dev, int budget) -{ - fec_t *fecp = fep->fecp; - const struct fec_platform_info *fpi = fep->fpi; - cbd_t *bdp; - struct sk_buff *skb, *skbn, *skbt; - int received = 0; - __u16 pkt_len, sc; - int curidx; - - /* - * First, grab all of the stats for the incoming packet. - * These get messed up if we get called due to a busy condition. - */ - bdp = fep->cur_rx; - - /* clear RX status bits for napi*/ - if (fpi->use_napi) - FW(fecp, ievent, FEC_ENET_RXF | FEC_ENET_RXB); - - while (((sc = CBDR_SC(bdp)) & BD_ENET_RX_EMPTY) == 0) { - - curidx = bdp - fep->rx_bd_base; - - /* - * Since we have allocated space to hold a complete frame, - * the last indicator should be set. - */ - if ((sc & BD_ENET_RX_LAST) == 0) - printk(KERN_WARNING DRV_MODULE_NAME - ": %s rcv is not +last\n", - dev->name); - - /* - * Check for errors. - */ - if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_CL | - BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) { - fep->stats.rx_errors++; - /* Frame too long or too short. */ - if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) - fep->stats.rx_length_errors++; - /* Frame alignment */ - if (sc & (BD_ENET_RX_NO | BD_ENET_RX_CL)) - fep->stats.rx_frame_errors++; - /* CRC Error */ - if (sc & BD_ENET_RX_CR) - fep->stats.rx_crc_errors++; - /* FIFO overrun */ - if (sc & BD_ENET_RX_OV) - fep->stats.rx_crc_errors++; - - skbn = fep->rx_skbuff[curidx]; - BUG_ON(skbn == NULL); - - } else { - skb = fep->rx_skbuff[curidx]; - BUG_ON(skb == NULL); - - /* - * Process the incoming frame. - */ - fep->stats.rx_packets++; - pkt_len = CBDR_DATLEN(bdp) - 4; /* remove CRC */ - fep->stats.rx_bytes += pkt_len + 4; - - if (pkt_len <= fpi->rx_copybreak) { - /* +2 to make IP header L1 cache aligned */ - skbn = dev_alloc_skb(pkt_len + 2); - if (skbn != NULL) { - skb_reserve(skbn, 2); /* align IP header */ - skb_copy_from_linear_data(skb, - skbn->data, - pkt_len); - /* swap */ - skbt = skb; - skb = skbn; - skbn = skbt; - } - } else - skbn = dev_alloc_skb(ENET_RX_FRSIZE); - - if (skbn != NULL) { - skb_put(skb, pkt_len); /* Make room */ - skb->protocol = eth_type_trans(skb, dev); - received++; - if (!fpi->use_napi) - netif_rx(skb); - else - netif_receive_skb(skb); - } else { - printk(KERN_WARNING DRV_MODULE_NAME - ": %s Memory squeeze, dropping packet.\n", - dev->name); - fep->stats.rx_dropped++; - skbn = skb; - } - } - - fep->rx_skbuff[curidx] = skbn; - CBDW_BUFADDR(bdp, dma_map_single(NULL, skbn->data, - L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), - DMA_FROM_DEVICE)); - CBDW_DATLEN(bdp, 0); - CBDW_SC(bdp, (sc & ~BD_ENET_RX_STATS) | BD_ENET_RX_EMPTY); - - /* - * Update BD pointer to next entry. - */ - if ((sc & BD_ENET_RX_WRAP) == 0) - bdp++; - else - bdp = fep->rx_bd_base; - - /* - * Doing this here will keep the FEC running while we process - * incoming frames. On a heavily loaded network, we should be - * able to keep up at the expense of system resources. - */ - FW(fecp, r_des_active, 0x01000000); - - if (received >= budget) - break; - - } - - fep->cur_rx = bdp; - - if (fpi->use_napi) { - if (received < budget) { - netif_rx_complete(dev, &fep->napi); - - /* enable RX interrupt bits */ - FS(fecp, imask, FEC_ENET_RXF | FEC_ENET_RXB); - } - } - - return received; -} - -static void fec_enet_tx(struct net_device *dev) -{ - struct fec_enet_private *fep = netdev_priv(dev); - cbd_t *bdp; - struct sk_buff *skb; - int dirtyidx, do_wake; - __u16 sc; - - spin_lock(&fep->lock); - bdp = fep->dirty_tx; - - do_wake = 0; - while (((sc = CBDR_SC(bdp)) & BD_ENET_TX_READY) == 0) { - - dirtyidx = bdp - fep->tx_bd_base; - - if (fep->tx_free == fep->tx_ring) - break; - - skb = fep->tx_skbuff[dirtyidx]; - - /* - * Check for errors. - */ - if (sc & (BD_ENET_TX_HB | BD_ENET_TX_LC | - BD_ENET_TX_RL | BD_ENET_TX_UN | BD_ENET_TX_CSL)) { - fep->stats.tx_errors++; - if (sc & BD_ENET_TX_HB) /* No heartbeat */ - fep->stats.tx_heartbeat_errors++; - if (sc & BD_ENET_TX_LC) /* Late collision */ - fep->stats.tx_window_errors++; - if (sc & BD_ENET_TX_RL) /* Retrans limit */ - fep->stats.tx_aborted_errors++; - if (sc & BD_ENET_TX_UN) /* Underrun */ - fep->stats.tx_fifo_errors++; - if (sc & BD_ENET_TX_CSL) /* Carrier lost */ - fep->stats.tx_carrier_errors++; - } else - fep->stats.tx_packets++; - - if (sc & BD_ENET_TX_READY) - printk(KERN_WARNING DRV_MODULE_NAME - ": %s HEY! Enet xmit interrupt and TX_READY.\n", - dev->name); - - /* - * Deferred means some collisions occurred during transmit, - * but we eventually sent the packet OK. - */ - if (sc & BD_ENET_TX_DEF) - fep->stats.collisions++; - - /* - * Free the sk buffer associated with this last transmit. - */ - dev_kfree_skb_irq(skb); - fep->tx_skbuff[dirtyidx] = NULL; - - /* - * Update pointer to next buffer descriptor to be transmitted. - */ - if ((sc & BD_ENET_TX_WRAP) == 0) - bdp++; - else - bdp = fep->tx_bd_base; - - /* - * Since we have freed up a buffer, the ring is no longer - * full. - */ - if (!fep->tx_free++) - do_wake = 1; - } - - fep->dirty_tx = bdp; - - spin_unlock(&fep->lock); - - if (do_wake && netif_queue_stopped(dev)) - netif_wake_queue(dev); -} - -/* - * The interrupt handler. - * This is called from the MPC core interrupt. - */ -static irqreturn_t -fec_enet_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct fec_enet_private *fep; - const struct fec_platform_info *fpi; - fec_t *fecp; - __u32 int_events; - __u32 int_events_napi; - - if (unlikely(dev == NULL)) - return IRQ_NONE; - - fep = netdev_priv(dev); - fecp = fep->fecp; - fpi = fep->fpi; - - /* - * Get the interrupt events that caused us to be here. - */ - while ((int_events = FR(fecp, ievent) & FR(fecp, imask)) != 0) { - - if (!fpi->use_napi) - FW(fecp, ievent, int_events); - else { - int_events_napi = int_events & ~(FEC_ENET_RXF | FEC_ENET_RXB); - FW(fecp, ievent, int_events_napi); - } - - if ((int_events & (FEC_ENET_HBERR | FEC_ENET_BABR | - FEC_ENET_BABT | FEC_ENET_EBERR)) != 0) - printk(KERN_WARNING DRV_MODULE_NAME - ": %s FEC ERROR(s) 0x%x\n", - dev->name, int_events); - - if ((int_events & FEC_ENET_RXF) != 0) { - if (!fpi->use_napi) - fec_enet_rx_common(fep, dev, ~0); - else { - if (netif_rx_schedule_prep(dev, &fep->napi)) { - /* disable rx interrupts */ - FC(fecp, imask, FEC_ENET_RXF | FEC_ENET_RXB); - __netif_rx_schedule(dev, &fep->napi); - } else { - printk(KERN_ERR DRV_MODULE_NAME - ": %s driver bug! interrupt while in poll!\n", - dev->name); - FC(fecp, imask, FEC_ENET_RXF | FEC_ENET_RXB); - } - } - } - - if ((int_events & FEC_ENET_TXF) != 0) - fec_enet_tx(dev); - } - - return IRQ_HANDLED; -} - -/* This interrupt occurs when the PHY detects a link change. */ -static irqreturn_t -fec_mii_link_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct fec_enet_private *fep; - const struct fec_platform_info *fpi; - - if (unlikely(dev == NULL)) - return IRQ_NONE; - - fep = netdev_priv(dev); - fpi = fep->fpi; - - if (!fpi->use_mdio) - return IRQ_NONE; - - /* - * Acknowledge the interrupt if possible. If we have not - * found the PHY yet we can't process or acknowledge the - * interrupt now. Instead we ignore this interrupt for now, - * which we can do since it is edge triggered. It will be - * acknowledged later by fec_enet_open(). - */ - if (!fep->phy) - return IRQ_NONE; - - fec_mii_ack_int(dev); - fec_mii_link_status_change_check(dev, 0); - - return IRQ_HANDLED; -} - - -/**********************************************************************************/ - -static int fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct fec_enet_private *fep = netdev_priv(dev); - fec_t *fecp = fep->fecp; - cbd_t *bdp; - int curidx; - unsigned long flags; - - spin_lock_irqsave(&fep->tx_lock, flags); - - /* - * Fill in a Tx ring entry - */ - bdp = fep->cur_tx; - - if (!fep->tx_free || (CBDR_SC(bdp) & BD_ENET_TX_READY)) { - netif_stop_queue(dev); - spin_unlock_irqrestore(&fep->tx_lock, flags); - - /* - * Ooops. All transmit buffers are full. Bail out. - * This should not happen, since the tx queue should be stopped. - */ - printk(KERN_WARNING DRV_MODULE_NAME - ": %s tx queue full!.\n", dev->name); - return 1; - } - - curidx = bdp - fep->tx_bd_base; - /* - * Clear all of the status flags. - */ - CBDC_SC(bdp, BD_ENET_TX_STATS); - - /* - * Save skb pointer. - */ - fep->tx_skbuff[curidx] = skb; - - fep->stats.tx_bytes += skb->len; - - /* - * Push the data cache so the CPM does not get stale memory data. - */ - CBDW_BUFADDR(bdp, dma_map_single(NULL, skb->data, - skb->len, DMA_TO_DEVICE)); - CBDW_DATLEN(bdp, skb->len); - - dev->trans_start = jiffies; - - /* - * If this was the last BD in the ring, start at the beginning again. - */ - if ((CBDR_SC(bdp) & BD_ENET_TX_WRAP) == 0) - fep->cur_tx++; - else - fep->cur_tx = fep->tx_bd_base; - - if (!--fep->tx_free) - netif_stop_queue(dev); - - /* - * Trigger transmission start - */ - CBDS_SC(bdp, BD_ENET_TX_READY | BD_ENET_TX_INTR | - BD_ENET_TX_LAST | BD_ENET_TX_TC); - FW(fecp, x_des_active, 0x01000000); - - spin_unlock_irqrestore(&fep->tx_lock, flags); - - return 0; -} - -static void fec_timeout(struct net_device *dev) -{ - struct fec_enet_private *fep = netdev_priv(dev); - - fep->stats.tx_errors++; - - if (fep->tx_free) - netif_wake_queue(dev); - - /* check link status again */ - fec_mii_link_status_change_check(dev, 0); -} - -static int fec_enet_open(struct net_device *dev) -{ - struct fec_enet_private *fep = netdev_priv(dev); - const struct fec_platform_info *fpi = fep->fpi; - unsigned long flags; - - napi_enable(&fep->napi); - - /* Install our interrupt handler. */ - if (request_irq(fpi->fec_irq, fec_enet_interrupt, 0, "fec", dev) != 0) { - printk(KERN_ERR DRV_MODULE_NAME - ": %s Could not allocate FEC IRQ!", dev->name); - napi_disable(&fep->napi); - return -EINVAL; - } - - /* Install our phy interrupt handler */ - if (fpi->phy_irq != -1 && - request_irq(fpi->phy_irq, fec_mii_link_interrupt, 0, "fec-phy", - dev) != 0) { - printk(KERN_ERR DRV_MODULE_NAME - ": %s Could not allocate PHY IRQ!", dev->name); - free_irq(fpi->fec_irq, dev); - napi_disable(&fep->napi); - return -EINVAL; - } - - if (fpi->use_mdio) { - fec_mii_startup(dev); - netif_carrier_off(dev); - fec_mii_link_status_change_check(dev, 1); - } else { - spin_lock_irqsave(&fep->lock, flags); - fec_restart(dev, 1, 100); /* XXX this sucks */ - spin_unlock_irqrestore(&fep->lock, flags); - - netif_carrier_on(dev); - netif_start_queue(dev); - } - return 0; -} - -static int fec_enet_close(struct net_device *dev) -{ - struct fec_enet_private *fep = netdev_priv(dev); - const struct fec_platform_info *fpi = fep->fpi; - unsigned long flags; - - netif_stop_queue(dev); - napi_disable(&fep->napi); - netif_carrier_off(dev); - - if (fpi->use_mdio) - fec_mii_shutdown(dev); - - spin_lock_irqsave(&fep->lock, flags); - fec_stop(dev); - spin_unlock_irqrestore(&fep->lock, flags); - - /* release any irqs */ - if (fpi->phy_irq != -1) - free_irq(fpi->phy_irq, dev); - free_irq(fpi->fec_irq, dev); - - return 0; -} - -static struct net_device_stats *fec_enet_get_stats(struct net_device *dev) -{ - struct fec_enet_private *fep = netdev_priv(dev); - return &fep->stats; -} - -static int fec_enet_poll(struct napi_struct *napi, int budget) -{ - struct fec_enet_private *fep = container_of(napi, struct fec_enet_private, napi); - struct net_device *dev = fep->dev; - - return fec_enet_rx_common(fep, dev, budget); -} - -/*************************************************************************/ - -static void fec_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) -{ - strcpy(info->driver, DRV_MODULE_NAME); - strcpy(info->version, DRV_MODULE_VERSION); -} - -static int fec_get_regs_len(struct net_device *dev) -{ - return sizeof(fec_t); -} - -static void fec_get_regs(struct net_device *dev, struct ethtool_regs *regs, - void *p) -{ - struct fec_enet_private *fep = netdev_priv(dev); - unsigned long flags; - - if (regs->len < sizeof(fec_t)) - return; - - regs->version = 0; - spin_lock_irqsave(&fep->lock, flags); - memcpy_fromio(p, fep->fecp, sizeof(fec_t)); - spin_unlock_irqrestore(&fep->lock, flags); -} - -static int fec_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct fec_enet_private *fep = netdev_priv(dev); - unsigned long flags; - int rc; - - spin_lock_irqsave(&fep->lock, flags); - rc = mii_ethtool_gset(&fep->mii_if, cmd); - spin_unlock_irqrestore(&fep->lock, flags); - - return rc; -} - -static int fec_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct fec_enet_private *fep = netdev_priv(dev); - unsigned long flags; - int rc; - - spin_lock_irqsave(&fep->lock, flags); - rc = mii_ethtool_sset(&fep->mii_if, cmd); - spin_unlock_irqrestore(&fep->lock, flags); - - return rc; -} - -static int fec_nway_reset(struct net_device *dev) -{ - struct fec_enet_private *fep = netdev_priv(dev); - return mii_nway_restart(&fep->mii_if); -} - -static __u32 fec_get_msglevel(struct net_device *dev) -{ - struct fec_enet_private *fep = netdev_priv(dev); - return fep->msg_enable; -} - -static void fec_set_msglevel(struct net_device *dev, __u32 value) -{ - struct fec_enet_private *fep = netdev_priv(dev); - fep->msg_enable = value; -} - -static const struct ethtool_ops fec_ethtool_ops = { - .get_drvinfo = fec_get_drvinfo, - .get_regs_len = fec_get_regs_len, - .get_settings = fec_get_settings, - .set_settings = fec_set_settings, - .nway_reset = fec_nway_reset, - .get_link = ethtool_op_get_link, - .get_msglevel = fec_get_msglevel, - .set_msglevel = fec_set_msglevel, - .set_tx_csum = ethtool_op_set_tx_csum, /* local! */ - .set_sg = ethtool_op_set_sg, - .get_regs = fec_get_regs, -}; - -static int fec_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct fec_enet_private *fep = netdev_priv(dev); - struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&rq->ifr_data; - unsigned long flags; - int rc; - - if (!netif_running(dev)) - return -EINVAL; - - spin_lock_irqsave(&fep->lock, flags); - rc = generic_mii_ioctl(&fep->mii_if, mii, cmd, NULL); - spin_unlock_irqrestore(&fep->lock, flags); - return rc; -} - -int fec_8xx_init_one(const struct fec_platform_info *fpi, - struct net_device **devp) -{ - immap_t *immap = (immap_t *) IMAP_ADDR; - static int fec_8xx_version_printed = 0; - struct net_device *dev = NULL; - struct fec_enet_private *fep = NULL; - fec_t *fecp = NULL; - int i; - int err = 0; - int registered = 0; - __u32 siel; - - *devp = NULL; - - switch (fpi->fec_no) { - case 0: - fecp = &((immap_t *) IMAP_ADDR)->im_cpm.cp_fec; - break; -#ifdef CONFIG_DUET - case 1: - fecp = &((immap_t *) IMAP_ADDR)->im_cpm.cp_fec2; - break; -#endif - default: - return -EINVAL; - } - - if (fec_8xx_version_printed++ == 0) - printk(KERN_INFO "%s", version); - - i = sizeof(*fep) + (sizeof(struct sk_buff **) * - (fpi->rx_ring + fpi->tx_ring)); - - dev = alloc_etherdev(i); - if (!dev) { - err = -ENOMEM; - goto err; - } - - fep = netdev_priv(dev); - fep->dev = dev; - - /* partial reset of FEC */ - fec_whack_reset(fecp); - - /* point rx_skbuff, tx_skbuff */ - fep->rx_skbuff = (struct sk_buff **)&fep[1]; - fep->tx_skbuff = fep->rx_skbuff + fpi->rx_ring; - - fep->fecp = fecp; - fep->fpi = fpi; - - /* init locks */ - spin_lock_init(&fep->lock); - spin_lock_init(&fep->tx_lock); - - /* - * Set the Ethernet address. - */ - for (i = 0; i < 6; i++) - dev->dev_addr[i] = fpi->macaddr[i]; - - fep->ring_base = dma_alloc_coherent(NULL, - (fpi->tx_ring + fpi->rx_ring) * - sizeof(cbd_t), &fep->ring_mem_addr, - GFP_KERNEL); - if (fep->ring_base == NULL) { - printk(KERN_ERR DRV_MODULE_NAME - ": %s dma alloc failed.\n", dev->name); - err = -ENOMEM; - goto err; - } - - /* - * Set receive and transmit descriptor base. - */ - fep->rx_bd_base = fep->ring_base; - fep->tx_bd_base = fep->rx_bd_base + fpi->rx_ring; - - /* initialize ring size variables */ - fep->tx_ring = fpi->tx_ring; - fep->rx_ring = fpi->rx_ring; - - /* SIU interrupt */ - if (fpi->phy_irq != -1 && - (fpi->phy_irq >= SIU_IRQ0 && fpi->phy_irq < SIU_LEVEL7)) { - - siel = in_be32(&immap->im_siu_conf.sc_siel); - if ((fpi->phy_irq & 1) == 0) - siel |= (0x80000000 >> fpi->phy_irq); - else - siel &= ~(0x80000000 >> (fpi->phy_irq & ~1)); - out_be32(&immap->im_siu_conf.sc_siel, siel); - } - - /* - * The FEC Ethernet specific entries in the device structure. - */ - dev->open = fec_enet_open; - dev->hard_start_xmit = fec_enet_start_xmit; - dev->tx_timeout = fec_timeout; - dev->watchdog_timeo = TX_TIMEOUT; - dev->stop = fec_enet_close; - dev->get_stats = fec_enet_get_stats; - dev->set_multicast_list = fec_set_multicast_list; - dev->set_mac_address = fec_set_mac_address; - netif_napi_add(dev, &fec->napi, - fec_enet_poll, fpi->napi_weight); - - dev->ethtool_ops = &fec_ethtool_ops; - dev->do_ioctl = fec_ioctl; - - fep->fec_phy_speed = - ((((fpi->sys_clk + 4999999) / 2500000) / 2) & 0x3F) << 1; - - init_timer(&fep->phy_timer_list); - - /* partial reset of FEC so that only MII works */ - FW(fecp, mii_speed, fep->fec_phy_speed); - FW(fecp, ievent, 0xffc0); - FW(fecp, ivec, (fpi->fec_irq / 2) << 29); - FW(fecp, imask, 0); - FW(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ - FW(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN); - - netif_carrier_off(dev); - - err = register_netdev(dev); - if (err != 0) - goto err; - registered = 1; - - if (fpi->use_mdio) { - fep->mii_if.dev = dev; - fep->mii_if.mdio_read = fec_mii_read; - fep->mii_if.mdio_write = fec_mii_write; - fep->mii_if.phy_id_mask = 0x1f; - fep->mii_if.reg_num_mask = 0x1f; - fep->mii_if.phy_id = fec_mii_phy_id_detect(dev); - } - - *devp = dev; - - return 0; - - err: - if (dev != NULL) { - if (fecp != NULL) - fec_whack_reset(fecp); - - if (registered) - unregister_netdev(dev); - - if (fep != NULL) { - if (fep->ring_base) - dma_free_coherent(NULL, - (fpi->tx_ring + - fpi->rx_ring) * - sizeof(cbd_t), fep->ring_base, - fep->ring_mem_addr); - } - free_netdev(dev); - } - return err; -} - -int fec_8xx_cleanup_one(struct net_device *dev) -{ - struct fec_enet_private *fep = netdev_priv(dev); - fec_t *fecp = fep->fecp; - const struct fec_platform_info *fpi = fep->fpi; - - fec_whack_reset(fecp); - - unregister_netdev(dev); - - dma_free_coherent(NULL, (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t), - fep->ring_base, fep->ring_mem_addr); - - free_netdev(dev); - - return 0; -} - -/**************************************************************************************/ -/**************************************************************************************/ -/**************************************************************************************/ - -static int __init fec_8xx_init(void) -{ - return fec_8xx_platform_init(); -} - -static void __exit fec_8xx_cleanup(void) -{ - fec_8xx_platform_cleanup(); -} - -/**************************************************************************************/ -/**************************************************************************************/ -/**************************************************************************************/ - -module_init(fec_8xx_init); -module_exit(fec_8xx_cleanup); diff --git a/drivers/net/fec_8xx/fec_mii.c b/drivers/net/fec_8xx/fec_mii.c deleted file mode 100644 index 3b6ca29d31f..00000000000 --- a/drivers/net/fec_8xx/fec_mii.c +++ /dev/null @@ -1,418 +0,0 @@ -/* - * Fast Ethernet Controller (FEC) driver for Motorola MPC8xx. - * - * Copyright (c) 2003 Intracom S.A. - * by Pantelis Antoniou - * - * Heavily based on original FEC driver by Dan Malek - * and modifications by Joakim Tjernlund - * - * Released under the GPL - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -/*************************************************/ - -#include "fec_8xx.h" - -/*************************************************/ - -/* Make MII read/write commands for the FEC. -*/ -#define mk_mii_read(REG) (0x60020000 | ((REG & 0x1f) << 18)) -#define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | (VAL & 0xffff)) -#define mk_mii_end 0 - -/*************************************************/ - -/* XXX both FECs use the MII interface of FEC1 */ -static DEFINE_SPINLOCK(fec_mii_lock); - -#define FEC_MII_LOOPS 10000 - -int fec_mii_read(struct net_device *dev, int phy_id, int location) -{ - struct fec_enet_private *fep = netdev_priv(dev); - fec_t *fecp; - int i, ret = -1; - unsigned long flags; - - /* XXX MII interface is only connected to FEC1 */ - fecp = &((immap_t *) IMAP_ADDR)->im_cpm.cp_fec; - - spin_lock_irqsave(&fec_mii_lock, flags); - - if ((FR(fecp, r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) { - FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ - FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN); - FW(fecp, ievent, FEC_ENET_MII); - } - - /* Add PHY address to register command. */ - FW(fecp, mii_speed, fep->fec_phy_speed); - FW(fecp, mii_data, (phy_id << 23) | mk_mii_read(location)); - - for (i = 0; i < FEC_MII_LOOPS; i++) - if ((FR(fecp, ievent) & FEC_ENET_MII) != 0) - break; - - if (i < FEC_MII_LOOPS) { - FW(fecp, ievent, FEC_ENET_MII); - ret = FR(fecp, mii_data) & 0xffff; - } - - spin_unlock_irqrestore(&fec_mii_lock, flags); - - return ret; -} - -void fec_mii_write(struct net_device *dev, int phy_id, int location, int value) -{ - struct fec_enet_private *fep = netdev_priv(dev); - fec_t *fecp; - unsigned long flags; - int i; - - /* XXX MII interface is only connected to FEC1 */ - fecp = &((immap_t *) IMAP_ADDR)->im_cpm.cp_fec; - - spin_lock_irqsave(&fec_mii_lock, flags); - - if ((FR(fecp, r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) { - FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ - FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN); - FW(fecp, ievent, FEC_ENET_MII); - } - - /* Add PHY address to register command. */ - FW(fecp, mii_speed, fep->fec_phy_speed); /* always adapt mii speed */ - FW(fecp, mii_data, (phy_id << 23) | mk_mii_write(location, value)); - - for (i = 0; i < FEC_MII_LOOPS; i++) - if ((FR(fecp, ievent) & FEC_ENET_MII) != 0) - break; - - if (i < FEC_MII_LOOPS) - FW(fecp, ievent, FEC_ENET_MII); - - spin_unlock_irqrestore(&fec_mii_lock, flags); -} - -/*************************************************/ - -#ifdef CONFIG_FEC_8XX_GENERIC_PHY - -/* - * Generic PHY support. - * Should work for all PHYs, but link change is detected by polling - */ - -static void generic_timer_callback(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - struct fec_enet_private *fep = netdev_priv(dev); - - fep->phy_timer_list.expires = jiffies + HZ / 2; - - add_timer(&fep->phy_timer_list); - - fec_mii_link_status_change_check(dev, 0); -} - -static void generic_startup(struct net_device *dev) -{ - struct fec_enet_private *fep = netdev_priv(dev); - - fep->phy_timer_list.expires = jiffies + HZ / 2; /* every 500ms */ - fep->phy_timer_list.data = (unsigned long)dev; - fep->phy_timer_list.function = generic_timer_callback; - add_timer(&fep->phy_timer_list); -} - -static void generic_shutdown(struct net_device *dev) -{ - struct fec_enet_private *fep = netdev_priv(dev); - - del_timer_sync(&fep->phy_timer_list); -} - -#endif - -#ifdef CONFIG_FEC_8XX_DM9161_PHY - -/* ------------------------------------------------------------------------- */ -/* The Davicom DM9161 is used on the NETTA board */ - -/* register definitions */ - -#define MII_DM9161_ACR 16 /* Aux. Config Register */ -#define MII_DM9161_ACSR 17 /* Aux. Config/Status Register */ -#define MII_DM9161_10TCSR 18 /* 10BaseT Config/Status Reg. */ -#define MII_DM9161_INTR 21 /* Interrupt Register */ -#define MII_DM9161_RECR 22 /* Receive Error Counter Reg. */ -#define MII_DM9161_DISCR 23 /* Disconnect Counter Register */ - -static void dm9161_startup(struct net_device *dev) -{ - struct fec_enet_private *fep = netdev_priv(dev); - - fec_mii_write(dev, fep->mii_if.phy_id, MII_DM9161_INTR, 0x0000); -} - -static void dm9161_ack_int(struct net_device *dev) -{ - struct fec_enet_private *fep = netdev_priv(dev); - - fec_mii_read(dev, fep->mii_if.phy_id, MII_DM9161_INTR); -} - -static void dm9161_shutdown(struct net_device *dev) -{ - struct fec_enet_private *fep = netdev_priv(dev); - - fec_mii_write(dev, fep->mii_if.phy_id, MII_DM9161_INTR, 0x0f00); -} - -#endif - -#ifdef CONFIG_FEC_8XX_LXT971_PHY - -/* Support for LXT971/972 PHY */ - -#define MII_LXT971_PCR 16 /* Port Control Register */ -#define MII_LXT971_SR2 17 /* Status Register 2 */ -#define MII_LXT971_IER 18 /* Interrupt Enable Register */ -#define MII_LXT971_ISR 19 /* Interrupt Status Register */ -#define MII_LXT971_LCR 20 /* LED Control Register */ -#define MII_LXT971_TCR 30 /* Transmit Control Register */ - -static void lxt971_startup(struct net_device *dev) -{ - struct fec_enet_private *fep = netdev_priv(dev); - - fec_mii_write(dev, fep->mii_if.phy_id, MII_LXT971_IER, 0x00F2); -} - -static void lxt971_ack_int(struct net_device *dev) -{ - struct fec_enet_private *fep = netdev_priv(dev); - - fec_mii_read(dev, fep->mii_if.phy_id, MII_LXT971_ISR); -} - -static void lxt971_shutdown(struct net_device *dev) -{ - struct fec_enet_private *fep = netdev_priv(dev); - - fec_mii_write(dev, fep->mii_if.phy_id, MII_LXT971_IER, 0x0000); -} -#endif - -/**********************************************************************************/ - -static const struct phy_info phy_info[] = { -#ifdef CONFIG_FEC_8XX_DM9161_PHY - { - .id = 0x00181b88, - .name = "DM9161", - .startup = dm9161_startup, - .ack_int = dm9161_ack_int, - .shutdown = dm9161_shutdown, - }, -#endif -#ifdef CONFIG_FEC_8XX_LXT971_PHY - { - .id = 0x0001378e, - .name = "LXT971/972", - .startup = lxt971_startup, - .ack_int = lxt971_ack_int, - .shutdown = lxt971_shutdown, - }, -#endif -#ifdef CONFIG_FEC_8XX_GENERIC_PHY - { - .id = 0, - .name = "GENERIC", - .startup = generic_startup, - .shutdown = generic_shutdown, - }, -#endif -}; - -/**********************************************************************************/ - -int fec_mii_phy_id_detect(struct net_device *dev) -{ - struct fec_enet_private *fep = netdev_priv(dev); - const struct fec_platform_info *fpi = fep->fpi; - int i, r, start, end, phytype, physubtype; - const struct phy_info *phy; - int phy_hwid, phy_id; - - /* if no MDIO */ - if (fpi->use_mdio == 0) - return -1; - - phy_hwid = -1; - fep->phy = NULL; - - /* auto-detect? */ - if (fpi->phy_addr == -1) { - start = 0; - end = 32; - } else { /* direct */ - start = fpi->phy_addr; - end = start + 1; - } - - for (phy_id = start; phy_id < end; phy_id++) { - r = fec_mii_read(dev, phy_id, MII_PHYSID1); - if (r == -1 || (phytype = (r & 0xffff)) == 0xffff) - continue; - r = fec_mii_read(dev, phy_id, MII_PHYSID2); - if (r == -1 || (physubtype = (r & 0xffff)) == 0xffff) - continue; - phy_hwid = (phytype << 16) | physubtype; - if (phy_hwid != -1) - break; - } - - if (phy_hwid == -1) { - printk(KERN_ERR DRV_MODULE_NAME - ": %s No PHY detected!\n", dev->name); - return -1; - } - - for (i = 0, phy = phy_info; i < ARRAY_SIZE(phy_info); i++, phy++) - if (phy->id == (phy_hwid >> 4) || phy->id == 0) - break; - - if (i >= ARRAY_SIZE(phy_info)) { - printk(KERN_ERR DRV_MODULE_NAME - ": %s PHY id 0x%08x is not supported!\n", - dev->name, phy_hwid); - return -1; - } - - fep->phy = phy; - - printk(KERN_INFO DRV_MODULE_NAME - ": %s Phy @ 0x%x, type %s (0x%08x)\n", - dev->name, phy_id, fep->phy->name, phy_hwid); - - return phy_id; -} - -void fec_mii_startup(struct net_device *dev) -{ - struct fec_enet_private *fep = netdev_priv(dev); - const struct fec_platform_info *fpi = fep->fpi; - - if (!fpi->use_mdio || fep->phy == NULL) - return; - - if (fep->phy->startup == NULL) - return; - - (*fep->phy->startup) (dev); -} - -void fec_mii_shutdown(struct net_device *dev) -{ - struct fec_enet_private *fep = netdev_priv(dev); - const struct fec_platform_info *fpi = fep->fpi; - - if (!fpi->use_mdio || fep->phy == NULL) - return; - - if (fep->phy->shutdown == NULL) - return; - - (*fep->phy->shutdown) (dev); -} - -void fec_mii_ack_int(struct net_device *dev) -{ - struct fec_enet_private *fep = netdev_priv(dev); - const struct fec_platform_info *fpi = fep->fpi; - - if (!fpi->use_mdio || fep->phy == NULL) - return; - - if (fep->phy->ack_int == NULL) - return; - - (*fep->phy->ack_int) (dev); -} - -/* helper function */ -static int mii_negotiated(struct mii_if_info *mii) -{ - int advert, lpa, val; - - if (!mii_link_ok(mii)) - return 0; - - val = (*mii->mdio_read) (mii->dev, mii->phy_id, MII_BMSR); - if ((val & BMSR_ANEGCOMPLETE) == 0) - return 0; - - advert = (*mii->mdio_read) (mii->dev, mii->phy_id, MII_ADVERTISE); - lpa = (*mii->mdio_read) (mii->dev, mii->phy_id, MII_LPA); - - return mii_nway_result(advert & lpa); -} - -void fec_mii_link_status_change_check(struct net_device *dev, int init_media) -{ - struct fec_enet_private *fep = netdev_priv(dev); - unsigned int media; - unsigned long flags; - - if (mii_check_media(&fep->mii_if, netif_msg_link(fep), init_media) == 0) - return; - - media = mii_negotiated(&fep->mii_if); - - if (netif_carrier_ok(dev)) { - spin_lock_irqsave(&fep->lock, flags); - fec_restart(dev, !!(media & ADVERTISE_FULL), - (media & (ADVERTISE_100FULL | ADVERTISE_100HALF)) ? - 100 : 10); - spin_unlock_irqrestore(&fep->lock, flags); - - netif_start_queue(dev); - } else { - netif_stop_queue(dev); - - spin_lock_irqsave(&fep->lock, flags); - fec_stop(dev); - spin_unlock_irqrestore(&fep->lock, flags); - - } -} -- cgit v1.2.3-70-g09d2 From 140b932f8cb6cced10b96860651a198b1b89cbb9 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Thu, 24 Apr 2008 23:16:00 +1000 Subject: [POWERPC] Create modalias file in sysfs for of_platform bus Create /sys/bus/of_platform/devices/*/modalias file to allow autoloading of modules. Modalias files are already present for many other bus types. This adds also a newline to the devspec files. Also create a devspec file for mac-io devices. They were created as a side effect. Use correct buffer size for mac-io modalias buffer. Tested on iBook1 and Efika. Signed-off-by: Olaf Hering Signed-off-by: Paul Mackerras --- drivers/macintosh/macio_sysfs.c | 12 +++++++++++- drivers/of/device.c | 36 ++++++++++++++++++++---------------- drivers/of/platform.c | 3 +++ 3 files changed, 34 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/macintosh/macio_sysfs.c b/drivers/macintosh/macio_sysfs.c index 112e5ef728f..9e9453b5842 100644 --- a/drivers/macintosh/macio_sysfs.c +++ b/drivers/macintosh/macio_sysfs.c @@ -44,7 +44,7 @@ static ssize_t modalias_show (struct device *dev, struct device_attribute *attr, struct of_device *ofdev = to_of_device(dev); int len; - len = of_device_get_modalias(ofdev, buf, PAGE_SIZE); + len = of_device_get_modalias(ofdev, buf, PAGE_SIZE - 2); buf[len] = '\n'; buf[len+1] = 0; @@ -52,6 +52,15 @@ static ssize_t modalias_show (struct device *dev, struct device_attribute *attr, return len+1; } +static ssize_t devspec_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct of_device *ofdev; + + ofdev = to_of_device(dev); + return sprintf(buf, "%s\n", ofdev->node->full_name); +} + macio_config_of_attr (name, "%s\n"); macio_config_of_attr (type, "%s\n"); @@ -60,5 +69,6 @@ struct device_attribute macio_dev_attrs[] = { __ATTR_RO(type), __ATTR_RO(compatible), __ATTR_RO(modalias), + __ATTR_RO(devspec), __ATTR_NULL }; diff --git a/drivers/of/device.c b/drivers/of/device.c index 29681c4b700..8fbfeee53c1 100644 --- a/drivers/of/device.c +++ b/drivers/of/device.c @@ -48,16 +48,32 @@ void of_dev_put(struct of_device *dev) } EXPORT_SYMBOL(of_dev_put); -static ssize_t dev_show_devspec(struct device *dev, +static ssize_t devspec_show(struct device *dev, struct device_attribute *attr, char *buf) { struct of_device *ofdev; ofdev = to_of_device(dev); - return sprintf(buf, "%s", ofdev->node->full_name); + return sprintf(buf, "%s\n", ofdev->node->full_name); } -static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL); +static ssize_t modalias_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct of_device *ofdev = to_of_device(dev); + ssize_t len = 0; + + len = of_device_get_modalias(ofdev, buf, PAGE_SIZE - 2); + buf[len] = '\n'; + buf[len+1] = 0; + return len+1; +} + +struct device_attribute of_platform_device_attrs[] = { + __ATTR_RO(devspec), + __ATTR_RO(modalias), + __ATTR_NULL +}; /** * of_release_dev - free an of device structure when all users of it are finished. @@ -78,25 +94,13 @@ EXPORT_SYMBOL(of_release_dev); int of_device_register(struct of_device *ofdev) { - int rc; - BUG_ON(ofdev->node == NULL); - - rc = device_register(&ofdev->dev); - if (rc) - return rc; - - rc = device_create_file(&ofdev->dev, &dev_attr_devspec); - if (rc) - device_unregister(&ofdev->dev); - - return rc; + return device_register(&ofdev->dev); } EXPORT_SYMBOL(of_device_register); void of_device_unregister(struct of_device *ofdev) { - device_remove_file(&ofdev->dev, &dev_attr_devspec); device_unregister(&ofdev->dev); } EXPORT_SYMBOL(of_device_unregister); diff --git a/drivers/of/platform.c b/drivers/of/platform.c index ca09a63a64d..298de0f95d7 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -17,6 +17,8 @@ #include #include +extern struct device_attribute of_platform_device_attrs[]; + static int of_platform_bus_match(struct device *dev, struct device_driver *drv) { struct of_device *of_dev = to_of_device(dev); @@ -103,6 +105,7 @@ int of_bus_type_init(struct bus_type *bus, const char *name) bus->suspend = of_platform_device_suspend; bus->resume = of_platform_device_resume; bus->shutdown = of_platform_device_shutdown; + bus->dev_attrs = of_platform_device_attrs; return bus_register(bus); } -- cgit v1.2.3-70-g09d2 From 1c8950ff87de950a3b6ccfb26650fc0a56278836 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 8 May 2008 14:27:17 +1000 Subject: [POWERPC] Make cpus_in_xmon static and remove extern mess from hvc_console.c This is a little messier than I'd like because xmon.h only exists on powerpc and we can't have a static inline and an extern declaration visible at the same time. Signed-off-by: Michael Ellerman Signed-off-by: Paul Mackerras --- arch/powerpc/xmon/xmon.c | 7 ++++++- drivers/char/hvc_console.c | 8 +------- drivers/char/hvc_console.h | 10 ++++++++++ include/asm-powerpc/xmon.h | 4 ++++ 4 files changed, 21 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index 95f24c9822b..6726da07c06 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -54,7 +54,7 @@ #define skipbl xmon_skipbl #ifdef CONFIG_SMP -cpumask_t cpus_in_xmon = CPU_MASK_NONE; +static cpumask_t cpus_in_xmon = CPU_MASK_NONE; static unsigned long xmon_taken = 1; static int xmon_owner; static int xmon_gate; @@ -327,6 +327,11 @@ static void release_output_lock(void) { xmon_speaker = 0; } + +int cpus_are_in_xmon(void) +{ + return !cpus_empty(cpus_in_xmon); +} #endif static int xmon_core(struct pt_regs *regs, int fromipi) diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index 44160d5ebca..2f9759d625c 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -675,12 +675,6 @@ static int hvc_poll(struct hvc_struct *hp) return poll_mask; } -#if defined(CONFIG_XMON) && defined(CONFIG_SMP) -extern cpumask_t cpus_in_xmon; -#else -static const cpumask_t cpus_in_xmon = CPU_MASK_NONE; -#endif - /* * This kthread is either polling or interrupt driven. This is determined by * calling hvc_poll() who determines whether a console adapter support @@ -698,7 +692,7 @@ static int khvcd(void *unused) hvc_kicked = 0; try_to_freeze(); wmb(); - if (cpus_empty(cpus_in_xmon)) { + if (!cpus_are_in_xmon()) { spin_lock(&hvc_structs_lock); list_for_each_entry(hp, &hvc_structs, next) { poll_mask |= hvc_poll(hp); diff --git a/drivers/char/hvc_console.h b/drivers/char/hvc_console.h index 8c59818050e..42ffb17e15d 100644 --- a/drivers/char/hvc_console.h +++ b/drivers/char/hvc_console.h @@ -60,4 +60,14 @@ extern struct hvc_struct * __devinit hvc_alloc(uint32_t vtermno, int irq, /* remove a vterm from hvc tty operation (modele_exit or hotplug remove) */ extern int __devexit hvc_remove(struct hvc_struct *hp); + +#if defined(CONFIG_XMON) && defined(CONFIG_SMP) +#include +#else +static inline int cpus_are_in_xmon(void) +{ + return 0; +} +#endif + #endif // HVC_CONSOLE_H diff --git a/include/asm-powerpc/xmon.h b/include/asm-powerpc/xmon.h index d83da3cbd08..5eb8e599e5c 100644 --- a/include/asm-powerpc/xmon.h +++ b/include/asm-powerpc/xmon.h @@ -25,5 +25,9 @@ static inline void xmon_setup(void) { }; static inline void xmon_register_spus(struct list_head *list) { }; #endif +#if defined(CONFIG_XMON) && defined(CONFIG_SMP) +extern int cpus_are_in_xmon(void); +#endif + #endif /* __KERNEL __ */ #endif /* __ASM_POWERPC_XMON_H */ -- cgit v1.2.3-70-g09d2 From 88787d2842b6e6ff9bdc218445209c5e3c84d6fa Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 13 May 2008 21:05:50 -0700 Subject: wireless: fix "iwlwifi: unify init driver flow" drivers/net/wireless/iwlwifi/iwl-core.c: In function 'iwlcore_init_geos': drivers/net/wireless/iwlwifi/iwl-core.c:323: error: implicit declaration of function 'iwlcore_init_ht_hw_capab' This (or something like it) should be folded into the base patch to avoid breaking bisection, please. Cc: Ron Rindjunsky Cc: Tomas Winkler Cc: Stephen Rothwell Signed-off-by: Andrew Morton Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index c4b5c1a100f..55e3d139f42 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -259,6 +259,12 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, if (priv->hw_params.tx_chains_num >= 3) ht_info->supp_mcs_set[2] = 0xFF; } +#else +static inline void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, + struct ieee80211_ht_info *ht_info, + enum ieee80211_band band) +{ +} #endif /* CONFIG_IWL4965_HT */ static void iwlcore_init_hw_rates(struct iwl_priv *priv, -- cgit v1.2.3-70-g09d2 From cdbf0846e2dd5f122f3910d0e2a305fab337744b Mon Sep 17 00:00:00 2001 From: Harvey Harrison Date: Fri, 2 May 2008 13:47:48 -0700 Subject: b43: replace limit_value macro with clamp_val kernel-provided clamp_val is identical, delete the private limit_value helper. Signed-off-by: Harvey Harrison Cc: Michael Buesch Cc: "John W. Linville" Signed-off-by: Andrew Morton Signed-off-by: John W. Linville --- drivers/net/wireless/b43/b43.h | 16 ---------------- drivers/net/wireless/b43/lo.c | 4 ++-- drivers/net/wireless/b43/main.c | 8 ++++---- drivers/net/wireless/b43/phy.c | 24 ++++++++++++------------ 4 files changed, 18 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 7d034df250b..0c2bc061e8f 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -939,22 +939,6 @@ static inline bool __b43_warn_on_dummy(bool x) { return x; } # define B43_WARN_ON(x) __b43_warn_on_dummy(unlikely(!!(x))) #endif -/** Limit a value between two limits */ -#ifdef limit_value -# undef limit_value -#endif -#define limit_value(value, min, max) \ - ({ \ - typeof(value) __value = (value); \ - typeof(value) __min = (min); \ - typeof(value) __max = (max); \ - if (__value < __min) \ - __value = __min; \ - else if (__value > __max) \ - __value = __max; \ - __value; \ - }) - /* Convert an integer to a Q5.2 value */ #define INT_TO_Q52(i) ((i) << 2) /* Convert a Q5.2 value to an integer (precision loss!) */ diff --git a/drivers/net/wireless/b43/lo.c b/drivers/net/wireless/b43/lo.c index 4ce1e356120..9c854d6aae3 100644 --- a/drivers/net/wireless/b43/lo.c +++ b/drivers/net/wireless/b43/lo.c @@ -199,7 +199,7 @@ static void lo_measure_txctl_values(struct b43_wldev *dev) if (lb_gain > 10) { radio_pctl_reg = 0; pga = abs(10 - lb_gain) / 6; - pga = limit_value(pga, 0, 15); + pga = clamp_val(pga, 0, 15); } else { int cmp_val; int tmp; @@ -321,7 +321,7 @@ static void lo_measure_gain_values(struct b43_wldev *dev, phy->lna_lod_gain = 1; trsw_rx_gain -= 8; } - trsw_rx_gain = limit_value(trsw_rx_gain, 0, 0x2D); + trsw_rx_gain = clamp_val(trsw_rx_gain, 0, 0x2D); phy->pga_gain = trsw_rx_gain / 3; if (phy->pga_gain >= 5) { phy->pga_gain -= 5; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index c6e79a15d3c..7c23aa8705c 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1182,10 +1182,10 @@ static void handle_irq_noise(struct b43_wldev *dev) /* Get the noise samples. */ B43_WARN_ON(dev->noisecalc.nr_samples >= 8); i = dev->noisecalc.nr_samples; - noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); - noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); - noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); - noise[3] = limit_value(noise[3], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); + noise[0] = clamp_val(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); + noise[1] = clamp_val(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); + noise[2] = clamp_val(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); + noise[3] = clamp_val(noise[3], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); dev->noisecalc.samples[i][0] = phy->nrssi_lt[noise[0]]; dev->noisecalc.samples[i][1] = phy->nrssi_lt[noise[1]]; dev->noisecalc.samples[i][2] = phy->nrssi_lt[noise[2]]; diff --git a/drivers/net/wireless/b43/phy.c b/drivers/net/wireless/b43/phy.c index 8b3c24da8db..6378c266549 100644 --- a/drivers/net/wireless/b43/phy.c +++ b/drivers/net/wireless/b43/phy.c @@ -1415,7 +1415,7 @@ static void b43_phy_initg(struct b43_wldev *dev) * the value 0x7FFFFFFF here. I think that is some weird * compiler optimization in the original driver. * Essentially, what we do here is resetting all NRSSI LT - * entries to -32 (see the limit_value() in nrssi_hw_update()) + * entries to -32 (see the clamp_val() in nrssi_hw_update()) */ b43_nrssi_hw_update(dev, 0xFFFF); //FIXME? b43_calc_nrssi_threshold(dev); @@ -1477,13 +1477,13 @@ static s8 b43_phy_estimate_power_out(struct b43_wldev *dev, s8 tssi) switch (phy->type) { case B43_PHYTYPE_A: tmp += 0x80; - tmp = limit_value(tmp, 0x00, 0xFF); + tmp = clamp_val(tmp, 0x00, 0xFF); dbm = phy->tssi2dbm[tmp]; //TODO: There's a FIXME on the specs break; case B43_PHYTYPE_B: case B43_PHYTYPE_G: - tmp = limit_value(tmp, 0x00, 0x3F); + tmp = clamp_val(tmp, 0x00, 0x3F); dbm = phy->tssi2dbm[tmp]; break; default: @@ -1542,8 +1542,8 @@ void b43_put_attenuation_into_ranges(struct b43_wldev *dev, break; } - *_rfatt = limit_value(rfatt, rf_min, rf_max); - *_bbatt = limit_value(bbatt, bb_min, bb_max); + *_rfatt = clamp_val(rfatt, rf_min, rf_max); + *_bbatt = clamp_val(bbatt, bb_min, bb_max); } /* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */ @@ -1638,7 +1638,7 @@ void b43_phy_xmitpower(struct b43_wldev *dev) /* Get desired power (in Q5.2) */ desired_pwr = INT_TO_Q52(phy->power_level); /* And limit it. max_pwr already is Q5.2 */ - desired_pwr = limit_value(desired_pwr, 0, max_pwr); + desired_pwr = clamp_val(desired_pwr, 0, max_pwr); if (b43_debug(dev, B43_DBG_XMITPOWER)) { b43dbg(dev->wl, "Current TX power output: " Q52_FMT @@ -1748,7 +1748,7 @@ static inline f = q; i++; } while (delta >= 2); - entry[index] = limit_value(b43_tssi2dbm_ad(m1 * f, 8192), -127, 128); + entry[index] = clamp_val(b43_tssi2dbm_ad(m1 * f, 8192), -127, 128); return 0; } @@ -2274,7 +2274,7 @@ void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val) for (i = 0; i < 64; i++) { tmp = b43_nrssi_hw_read(dev, i); tmp -= val; - tmp = limit_value(tmp, -32, 31); + tmp = clamp_val(tmp, -32, 31); b43_nrssi_hw_write(dev, i, tmp); } } @@ -2291,7 +2291,7 @@ void b43_nrssi_mem_update(struct b43_wldev *dev) tmp = (i - delta) * phy->nrssislope; tmp /= 0x10000; tmp += 0x3A; - tmp = limit_value(tmp, 0, 0x3F); + tmp = clamp_val(tmp, 0, 0x3F); phy->nrssi_lt[i] = tmp; } } @@ -2728,7 +2728,7 @@ void b43_calc_nrssi_threshold(struct b43_wldev *dev) } else threshold = phy->nrssi[1] - 5; - threshold = limit_value(threshold, 0, 0x3E); + threshold = clamp_val(threshold, 0, 0x3E); b43_phy_read(dev, 0x0020); /* dummy read */ b43_phy_write(dev, 0x0020, (((u16) threshold) << 8) | 0x001C); @@ -2779,7 +2779,7 @@ void b43_calc_nrssi_threshold(struct b43_wldev *dev) else a += 32; a = a >> 6; - a = limit_value(a, -31, 31); + a = clamp_val(a, -31, 31); b = b * (phy->nrssi[1] - phy->nrssi[0]); b += (phy->nrssi[0] << 6); @@ -2788,7 +2788,7 @@ void b43_calc_nrssi_threshold(struct b43_wldev *dev) else b += 32; b = b >> 6; - b = limit_value(b, -31, 31); + b = clamp_val(b, -31, 31); tmp_u16 = b43_phy_read(dev, 0x048A) & 0xF000; tmp_u16 |= ((u32) b & 0x0000003F); -- cgit v1.2.3-70-g09d2 From ca21614d4c7a176d3723ac211873020b3722dbda Mon Sep 17 00:00:00 2001 From: Harvey Harrison Date: Fri, 2 May 2008 13:47:49 -0700 Subject: b43legacy: replace limit_value macro with clamp_val kernel-provided clamp_val is identical, delete the private limit_value helper. Signed-off-by: Harvey Harrison Cc: Michael Buesch Cc: "John W. Linville" Signed-off-by: Andrew Morton Signed-off-by: John W. Linville --- drivers/net/wireless/b43legacy/b43legacy.h | 17 ----------------- drivers/net/wireless/b43legacy/main.c | 8 ++++---- drivers/net/wireless/b43legacy/phy.c | 14 +++++++------- drivers/net/wireless/b43legacy/radio.c | 12 ++++++------ 4 files changed, 17 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h index ded3cd31b3d..c40078e1fff 100644 --- a/drivers/net/wireless/b43legacy/b43legacy.h +++ b/drivers/net/wireless/b43legacy/b43legacy.h @@ -823,23 +823,6 @@ void b43legacydbg(struct b43legacy_wl *wl, const char *fmt, ...) # define b43legacydbg(wl, fmt...) do { /* nothing */ } while (0) #endif /* DEBUG */ - -/** Limit a value between two limits */ -#ifdef limit_value -# undef limit_value -#endif -#define limit_value(value, min, max) \ - ({ \ - typeof(value) __value = (value); \ - typeof(value) __min = (min); \ - typeof(value) __max = (max); \ - if (__value < __min) \ - __value = __min; \ - else if (__value > __max) \ - __value = __max; \ - __value; \ - }) - /* Macros for printing a value in Q5.2 format */ #define Q52_FMT "%u.%u" #define Q52_ARG(q52) ((q52) / 4), (((q52) & 3) * 100 / 4) diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 1ccc51e90a8..d3820dce3c4 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -846,10 +846,10 @@ static void handle_irq_noise(struct b43legacy_wldev *dev) /* Get the noise samples. */ B43legacy_WARN_ON(dev->noisecalc.nr_samples >= 8); i = dev->noisecalc.nr_samples; - noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); - noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); - noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); - noise[3] = limit_value(noise[3], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); + noise[0] = clamp_val(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); + noise[1] = clamp_val(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); + noise[2] = clamp_val(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); + noise[3] = clamp_val(noise[3], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); dev->noisecalc.samples[i][0] = phy->nrssi_lt[noise[0]]; dev->noisecalc.samples[i][1] = phy->nrssi_lt[noise[1]]; dev->noisecalc.samples[i][2] = phy->nrssi_lt[noise[2]]; diff --git a/drivers/net/wireless/b43legacy/phy.c b/drivers/net/wireless/b43legacy/phy.c index 8e5c09b8187..768cccb9b1b 100644 --- a/drivers/net/wireless/b43legacy/phy.c +++ b/drivers/net/wireless/b43legacy/phy.c @@ -1088,7 +1088,7 @@ static void b43legacy_phy_initg(struct b43legacy_wldev *dev) * the value 0x7FFFFFFF here. I think that is some weird * compiler optimization in the original driver. * Essentially, what we do here is resetting all NRSSI LT - * entries to -32 (see the limit_value() in nrssi_hw_update()) + * entries to -32 (see the clamp_val() in nrssi_hw_update()) */ b43legacy_nrssi_hw_update(dev, 0xFFFF); b43legacy_calc_nrssi_threshold(dev); @@ -1756,7 +1756,7 @@ static s8 b43legacy_phy_estimate_power_out(struct b43legacy_wldev *dev, s8 tssi) switch (phy->type) { case B43legacy_PHYTYPE_B: case B43legacy_PHYTYPE_G: - tmp = limit_value(tmp, 0x00, 0x3F); + tmp = clamp_val(tmp, 0x00, 0x3F); dbm = phy->tssi2dbm[tmp]; break; default: @@ -1859,7 +1859,7 @@ void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev) /* find the desired power in Q5.2 - power_level is in dBm * and limit it - max_pwr is already in Q5.2 */ - desired_pwr = limit_value(phy->power_level << 2, 0, max_pwr); + desired_pwr = clamp_val(phy->power_level << 2, 0, max_pwr); if (b43legacy_debug(dev, B43legacy_DBG_XMITPOWER)) b43legacydbg(dev->wl, "Current TX power output: " Q52_FMT " dBm, Desired TX power output: " Q52_FMT @@ -1905,7 +1905,7 @@ void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev) radio_attenuation++; } } - baseband_attenuation = limit_value(baseband_attenuation, 0, 11); + baseband_attenuation = clamp_val(baseband_attenuation, 0, 11); txpower = phy->txctl1; if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) { @@ -1933,8 +1933,8 @@ void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev) } /* Save the control values */ phy->txctl1 = txpower; - baseband_attenuation = limit_value(baseband_attenuation, 0, 11); - radio_attenuation = limit_value(radio_attenuation, 0, 9); + baseband_attenuation = clamp_val(baseband_attenuation, 0, 11); + radio_attenuation = clamp_val(radio_attenuation, 0, 9); phy->rfatt = radio_attenuation; phy->bbatt = baseband_attenuation; @@ -1979,7 +1979,7 @@ s8 b43legacy_tssi2dbm_entry(s8 entry [], u8 index, s16 pab0, s16 pab1, s16 pab2) f = q; i++; } while (delta >= 2); - entry[index] = limit_value(b43legacy_tssi2dbm_ad(m1 * f, 8192), + entry[index] = clamp_val(b43legacy_tssi2dbm_ad(m1 * f, 8192), -127, 128); return 0; } diff --git a/drivers/net/wireless/b43legacy/radio.c b/drivers/net/wireless/b43legacy/radio.c index 955832e8654..2df545cfad1 100644 --- a/drivers/net/wireless/b43legacy/radio.c +++ b/drivers/net/wireless/b43legacy/radio.c @@ -357,7 +357,7 @@ void b43legacy_nrssi_hw_update(struct b43legacy_wldev *dev, u16 val) for (i = 0; i < 64; i++) { tmp = b43legacy_nrssi_hw_read(dev, i); tmp -= val; - tmp = limit_value(tmp, -32, 31); + tmp = clamp_val(tmp, -32, 31); b43legacy_nrssi_hw_write(dev, i, tmp); } } @@ -375,7 +375,7 @@ void b43legacy_nrssi_mem_update(struct b43legacy_wldev *dev) tmp = (i - delta) * phy->nrssislope; tmp /= 0x10000; tmp += 0x3A; - tmp = limit_value(tmp, 0, 0x3F); + tmp = clamp_val(tmp, 0, 0x3F); phy->nrssi_lt[i] = tmp; } } @@ -839,7 +839,7 @@ void b43legacy_calc_nrssi_threshold(struct b43legacy_wldev *dev) } else threshold = phy->nrssi[1] - 5; - threshold = limit_value(threshold, 0, 0x3E); + threshold = clamp_val(threshold, 0, 0x3E); b43legacy_phy_read(dev, 0x0020); /* dummy read */ b43legacy_phy_write(dev, 0x0020, (((u16)threshold) << 8) | 0x001C); @@ -892,7 +892,7 @@ void b43legacy_calc_nrssi_threshold(struct b43legacy_wldev *dev) else a += 32; a = a >> 6; - a = limit_value(a, -31, 31); + a = clamp_val(a, -31, 31); b = b * (phy->nrssi[1] - phy->nrssi[0]); b += (phy->nrssi[0] << 6); @@ -901,7 +901,7 @@ void b43legacy_calc_nrssi_threshold(struct b43legacy_wldev *dev) else b += 32; b = b >> 6; - b = limit_value(b, -31, 31); + b = clamp_val(b, -31, 31); tmp_u16 = b43legacy_phy_read(dev, 0x048A) & 0xF000; tmp_u16 |= ((u32)b & 0x0000003F); @@ -1905,7 +1905,7 @@ void b43legacy_radio_set_txpower_a(struct b43legacy_wldev *dev, u16 txpower) u16 dac; u16 ilt; - txpower = limit_value(txpower, 0, 63); + txpower = clamp_val(txpower, 0, 63); pamp = b43legacy_get_txgain_freq_power_amp(txpower); pamp <<= 5; -- cgit v1.2.3-70-g09d2 From 07346f81e87d6e4cca7ae9adfa711d0c61c87b56 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 3 May 2008 01:02:02 +0200 Subject: mac80211: proper STA info locking As discussed earlier, we can unify locking in struct sta_info and use just a single spinlock protecting all members of the structure that need protection. Many don't, but one of the especially bad ones is the 'flags' member that can currently be clobbered when RX and TX is being processed on different CPUs at the same time. Because having four spinlocks for different, mostly exclusive parts of a single structure is overkill, this patch also kills the ampdu and mesh plink spinlocks and uses just a single one for everything. Because none of the spinlocks are nested, this is safe. It remains to be seen whether or not we should make the sta flags use atomic bit operations instead, for now though this is a safe thing and using atomic operations instead will be very simple using the new static inline functions this patch introduces for accessing sta->flags. Since spin_lock_bh() is used with this lock, there shouldn't be any contention even if aggregation is enabled at around the same time as both requires frame transmission/reception which is in a bh context. Signed-off-by: Johannes Berg Cc: Tomas Winkler Cc: Ron Rindjunsky Cc: Luis Carlos Cobo Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 4 +- net/mac80211/cfg.c | 2 + net/mac80211/debugfs_sta.c | 15 ++--- net/mac80211/key.c | 4 +- net/mac80211/main.c | 31 ++++++----- net/mac80211/mesh_plink.c | 88 +++++++++++++++--------------- net/mac80211/mlme.c | 38 ++++++------- net/mac80211/rx.c | 17 +++--- net/mac80211/sta_info.c | 14 ++--- net/mac80211/sta_info.h | 72 +++++++++++++++++++++--- net/mac80211/tx.c | 21 +++---- 11 files changed, 181 insertions(+), 125 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index 67356d9a0c5..e3444c4ea1a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -360,9 +360,9 @@ static void rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv, unsigned long state; DECLARE_MAC_BUF(mac); - spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_lock_bh(&sta->lock); state = sta->ampdu_mlme.tid_state_tx[tid]; - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_unlock_bh(&sta->lock); if (state == HT_AGG_STATE_IDLE && rs_tl_get_load(lq_data, tid) > IWL_AGG_LOAD_THRESHOLD) { diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 699d97b8de5..3cef80dcd0e 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -602,6 +602,7 @@ static void sta_apply_parameters(struct ieee80211_local *local, */ if (params->station_flags & STATION_FLAG_CHANGED) { + spin_lock_bh(&sta->lock); sta->flags &= ~WLAN_STA_AUTHORIZED; if (params->station_flags & STATION_FLAG_AUTHORIZED) sta->flags |= WLAN_STA_AUTHORIZED; @@ -613,6 +614,7 @@ static void sta_apply_parameters(struct ieee80211_local *local, sta->flags &= ~WLAN_STA_WME; if (params->station_flags & STATION_FLAG_WME) sta->flags |= WLAN_STA_WME; + spin_unlock_bh(&sta->lock); } /* diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 676a93202ff..1f00273d99c 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -74,14 +74,15 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf, { char buf[100]; struct sta_info *sta = file->private_data; + u32 staflags = get_sta_flags(sta); int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s", - sta->flags & WLAN_STA_AUTH ? "AUTH\n" : "", - sta->flags & WLAN_STA_ASSOC ? "ASSOC\n" : "", - sta->flags & WLAN_STA_PS ? "PS\n" : "", - sta->flags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "", - sta->flags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "", - sta->flags & WLAN_STA_WME ? "WME\n" : "", - sta->flags & WLAN_STA_WDS ? "WDS\n" : ""); + staflags & WLAN_STA_AUTH ? "AUTH\n" : "", + staflags & WLAN_STA_ASSOC ? "ASSOC\n" : "", + staflags & WLAN_STA_PS ? "PS\n" : "", + staflags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "", + staflags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "", + staflags & WLAN_STA_WME ? "WME\n" : "", + staflags & WLAN_STA_WDS ? "WDS\n" : ""); return simple_read_from_buffer(userbuf, count, ppos, buf, res); } STA_OPS(flags); diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 88b211af7c1..d4893bd1775 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -321,7 +321,7 @@ void ieee80211_key_link(struct ieee80211_key *key, * some hardware cannot handle TKIP with QoS, so * we indicate whether QoS could be in use. */ - if (sta->flags & WLAN_STA_WME) + if (test_sta_flags(sta, WLAN_STA_WME)) key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA; /* @@ -342,7 +342,7 @@ void ieee80211_key_link(struct ieee80211_key *key, /* same here, the AP could be using QoS */ ap = sta_info_get(key->local, key->sdata->u.sta.bssid); if (ap) { - if (ap->flags & WLAN_STA_WME) + if (test_sta_flags(ap, WLAN_STA_WME)) key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA; } diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 55e76117da9..f277407f0f5 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -346,6 +346,7 @@ static int ieee80211_open(struct net_device *dev) goto err_del_interface; } + /* no locking required since STA is not live yet */ sta->flags |= WLAN_STA_AUTHORIZED; res = sta_info_insert(sta); @@ -588,7 +589,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) return -ENOENT; } - spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_lock_bh(&sta->lock); /* we have tried too many times, receiver does not want A-MPDU */ if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) { @@ -691,7 +692,7 @@ start_ba_err: spin_unlock_bh(&local->mdev->queue_lock); ret = -EBUSY; start_ba_exit: - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_unlock_bh(&sta->lock); rcu_read_unlock(); return ret; } @@ -719,7 +720,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, /* check if the TID is in aggregation */ state = &sta->ampdu_mlme.tid_state_tx[tid]; - spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_lock_bh(&sta->lock); if (*state != HT_AGG_STATE_OPERATIONAL) { ret = -ENOENT; @@ -749,7 +750,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, } stop_BA_exit: - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_unlock_bh(&sta->lock); rcu_read_unlock(); return ret; } @@ -778,12 +779,12 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) } state = &sta->ampdu_mlme.tid_state_tx[tid]; - spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_lock_bh(&sta->lock); if (!(*state & HT_ADDBA_REQUESTED_MSK)) { printk(KERN_DEBUG "addBA was not requested yet, state is %d\n", *state); - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_unlock_bh(&sta->lock); rcu_read_unlock(); return; } @@ -796,7 +797,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid); ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); } - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_unlock_bh(&sta->lock); rcu_read_unlock(); } EXPORT_SYMBOL(ieee80211_start_tx_ba_cb); @@ -830,10 +831,10 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) } state = &sta->ampdu_mlme.tid_state_tx[tid]; - spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_lock_bh(&sta->lock); if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) { printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n"); - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_unlock_bh(&sta->lock); rcu_read_unlock(); return; } @@ -860,7 +861,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) sta->ampdu_mlme.addba_req_num[tid] = 0; kfree(sta->ampdu_mlme.tid_tx[tid]); sta->ampdu_mlme.tid_tx[tid] = NULL; - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_unlock_bh(&sta->lock); rcu_read_unlock(); } @@ -1315,7 +1316,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, * packet. If the STA went to power save mode, this will happen * happen when it wakes up for the next time. */ - sta->flags |= WLAN_STA_CLEAR_PS_FILT; + set_sta_flags(sta, WLAN_STA_CLEAR_PS_FILT); /* * This code races in the following way: @@ -1347,7 +1348,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, * can be unknown, for example with different interrupt status * bits. */ - if (sta->flags & WLAN_STA_PS && + if (test_sta_flags(sta, WLAN_STA_PS) && skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) { ieee80211_remove_tx_extra(local, sta->key, skb, &status->control); @@ -1355,7 +1356,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, return; } - if (!(sta->flags & WLAN_STA_PS) && + if (!test_sta_flags(sta, WLAN_STA_PS) && !(status->control.flags & IEEE80211_TXCTL_REQUEUE)) { /* Software retry the packet once */ status->control.flags |= IEEE80211_TXCTL_REQUEUE; @@ -1370,7 +1371,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, "queue_len=%d PS=%d @%lu\n", wiphy_name(local->hw.wiphy), skb_queue_len(&sta->tx_filtered), - !!(sta->flags & WLAN_STA_PS), jiffies); + !!test_sta_flags(sta, WLAN_STA_PS), jiffies); dev_kfree_skb(skb); } @@ -1399,7 +1400,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, struct sta_info *sta; sta = sta_info_get(local, hdr->addr1); if (sta) { - if (sta->flags & WLAN_STA_PS) { + if (test_sta_flags(sta, WLAN_STA_PS)) { /* * The STA is in power save mode, so assume * that this TX packet failed because of that. diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 37f0c2b94ae..9efeb1f0702 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -79,7 +79,7 @@ void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata) * * @sta: mes peer link to restart * - * Locking: this function must be called holding sta->plink_lock + * Locking: this function must be called holding sta->lock */ static inline void mesh_plink_fsm_restart(struct sta_info *sta) { @@ -105,7 +105,7 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, if (!sta) return NULL; - sta->flags |= WLAN_STA_AUTHORIZED; + sta->flags = WLAN_STA_AUTHORIZED; sta->supp_rates[local->hw.conf.channel->band] = rates; return sta; @@ -118,7 +118,7 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, * * All mesh paths with this peer as next hop will be flushed * - * Locking: the caller must hold sta->plink_lock + * Locking: the caller must hold sta->lock */ static void __mesh_plink_deactivate(struct sta_info *sta) { @@ -139,9 +139,9 @@ static void __mesh_plink_deactivate(struct sta_info *sta) */ void mesh_plink_deactivate(struct sta_info *sta) { - spin_lock_bh(&sta->plink_lock); + spin_lock_bh(&sta->lock); __mesh_plink_deactivate(sta); - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); } static int mesh_plink_frame_tx(struct net_device *dev, @@ -270,10 +270,10 @@ static void mesh_plink_timer(unsigned long data) */ sta = (struct sta_info *) data; - spin_lock_bh(&sta->plink_lock); + spin_lock_bh(&sta->lock); if (sta->ignore_plink_timer) { sta->ignore_plink_timer = false; - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); return; } mpl_dbg("Mesh plink timer for %s fired on state %d\n", @@ -298,7 +298,7 @@ static void mesh_plink_timer(unsigned long data) rand % sta->plink_timeout; ++sta->plink_retries; mod_plink_timer(sta, sta->plink_timeout); - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(dev, PLINK_OPEN, sta->addr, llid, 0, 0); break; @@ -311,7 +311,7 @@ static void mesh_plink_timer(unsigned long data) reason = cpu_to_le16(MESH_CONFIRM_TIMEOUT); sta->plink_state = PLINK_HOLDING; mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, plid, reason); break; @@ -319,10 +319,10 @@ static void mesh_plink_timer(unsigned long data) /* holding timer */ del_timer(&sta->plink_timer); mesh_plink_fsm_restart(sta); - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); break; default: - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); break; } } @@ -344,16 +344,16 @@ int mesh_plink_open(struct sta_info *sta) DECLARE_MAC_BUF(mac); #endif - spin_lock_bh(&sta->plink_lock); + spin_lock_bh(&sta->lock); get_random_bytes(&llid, 2); sta->llid = llid; if (sta->plink_state != PLINK_LISTEN) { - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); return -EBUSY; } sta->plink_state = PLINK_OPN_SNT; mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata)); - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mpl_dbg("Mesh plink: starting establishment with %s\n", print_mac(mac, sta->addr)); @@ -367,10 +367,10 @@ void mesh_plink_block(struct sta_info *sta) DECLARE_MAC_BUF(mac); #endif - spin_lock_bh(&sta->plink_lock); + spin_lock_bh(&sta->lock); __mesh_plink_deactivate(sta); sta->plink_state = PLINK_BLOCKED; - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); } int mesh_plink_close(struct sta_info *sta) @@ -383,14 +383,14 @@ int mesh_plink_close(struct sta_info *sta) mpl_dbg("Mesh plink: closing link with %s\n", print_mac(mac, sta->addr)); - spin_lock_bh(&sta->plink_lock); + spin_lock_bh(&sta->lock); sta->reason = cpu_to_le16(MESH_LINK_CANCELLED); reason = sta->reason; if (sta->plink_state == PLINK_LISTEN || sta->plink_state == PLINK_BLOCKED) { mesh_plink_fsm_restart(sta); - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); return 0; } else if (sta->plink_state == PLINK_ESTAB) { __mesh_plink_deactivate(sta); @@ -402,7 +402,7 @@ int mesh_plink_close(struct sta_info *sta) sta->plink_state = PLINK_HOLDING; llid = sta->llid; plid = sta->plid; - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(sta->sdata->dev, PLINK_CLOSE, sta->addr, llid, plid, reason); return 0; @@ -490,7 +490,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, /* avoid warning */ break; } - spin_lock_bh(&sta->plink_lock); + spin_lock_bh(&sta->lock); } else if (!sta) { /* ftype == PLINK_OPEN */ u64 rates; @@ -512,9 +512,9 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, return; } event = OPN_ACPT; - spin_lock_bh(&sta->plink_lock); + spin_lock_bh(&sta->lock); } else { - spin_lock_bh(&sta->plink_lock); + spin_lock_bh(&sta->lock); switch (ftype) { case PLINK_OPEN: if (!mesh_plink_free_count(sdata) || @@ -551,7 +551,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, break; default: mpl_dbg("Mesh plink: unknown frame subtype\n"); - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); rcu_read_unlock(); return; } @@ -568,7 +568,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, switch (event) { case CLS_ACPT: mesh_plink_fsm_restart(sta); - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); break; case OPN_ACPT: sta->plink_state = PLINK_OPN_RCVD; @@ -576,14 +576,14 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, get_random_bytes(&llid, 2); sta->llid = llid; mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata)); - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(dev, PLINK_OPEN, sta->addr, llid, 0, 0); mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid, plid, 0); break; default: - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); break; } break; @@ -603,7 +603,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, sta->ignore_plink_timer = true; llid = sta->llid; - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, plid, reason); break; @@ -612,7 +612,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, sta->plink_state = PLINK_OPN_RCVD; sta->plid = plid; llid = sta->llid; - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid, plid, 0); break; @@ -622,10 +622,10 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, dot11MeshConfirmTimeout(sdata))) sta->ignore_plink_timer = true; - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); break; default: - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); break; } break; @@ -645,13 +645,13 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, sta->ignore_plink_timer = true; llid = sta->llid; - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, plid, reason); break; case OPN_ACPT: llid = sta->llid; - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid, plid, 0); break; @@ -659,12 +659,12 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, del_timer(&sta->plink_timer); sta->plink_state = PLINK_ESTAB; mesh_plink_inc_estab_count(sdata); - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mpl_dbg("Mesh plink with %s ESTABLISHED\n", print_mac(mac, sta->addr)); break; default: - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); break; } break; @@ -684,7 +684,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, sta->ignore_plink_timer = true; llid = sta->llid; - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, plid, reason); break; @@ -692,14 +692,14 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, del_timer(&sta->plink_timer); sta->plink_state = PLINK_ESTAB; mesh_plink_inc_estab_count(sdata); - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mpl_dbg("Mesh plink with %s ESTABLISHED\n", print_mac(mac, sta->addr)); mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid, plid, 0); break; default: - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); break; } break; @@ -713,18 +713,18 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, sta->plink_state = PLINK_HOLDING; llid = sta->llid; mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, plid, reason); break; case OPN_ACPT: llid = sta->llid; - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid, plid, 0); break; default: - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); break; } break; @@ -734,7 +734,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, if (del_timer(&sta->plink_timer)) sta->ignore_plink_timer = 1; mesh_plink_fsm_restart(sta); - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); break; case OPN_ACPT: case CNF_ACPT: @@ -742,19 +742,19 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, case CNF_RJCT: llid = sta->llid; reason = sta->reason; - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, plid, reason); break; default: - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); } break; default: /* should not get here, PLINK_BLOCKED is dealt with at the * beggining of the function */ - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); break; } diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 108c6fc42fe..6c4b27be35d 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1241,7 +1241,7 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev, /* examine state machine */ - spin_lock_bh(&sta->ampdu_mlme.ampdu_rx); + spin_lock_bh(&sta->lock); if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_IDLE) { #ifdef CONFIG_MAC80211_HT_DEBUG @@ -1308,7 +1308,7 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev, tid_agg_rx->stored_mpdu_num = 0; status = WLAN_STATUS_SUCCESS; end: - spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); + spin_unlock_bh(&sta->lock); end_no_lock: ieee80211_send_addba_resp(sta->sdata->dev, sta->addr, tid, @@ -1340,10 +1340,10 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev, state = &sta->ampdu_mlme.tid_state_tx[tid]; - spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_lock_bh(&sta->lock); if (!(*state & HT_ADDBA_REQUESTED_MSK)) { - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_unlock_bh(&sta->lock); printk(KERN_DEBUG "state not HT_ADDBA_REQUESTED_MSK:" "%d\n", *state); goto addba_resp_exit; @@ -1351,7 +1351,7 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev, if (mgmt->u.action.u.addba_resp.dialog_token != sta->ampdu_mlme.tid_tx[tid]->dialog_token) { - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_unlock_bh(&sta->lock); #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ @@ -1375,7 +1375,7 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev, ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); } - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_unlock_bh(&sta->lock); printk(KERN_DEBUG "recipient accepted agg: tid %d \n", tid); } else { printk(KERN_DEBUG "recipient rejected agg: tid %d \n", tid); @@ -1383,7 +1383,7 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev, sta->ampdu_mlme.addba_req_num[tid]++; /* this will allow the state check in stop_BA_session */ *state = HT_AGG_STATE_OPERATIONAL; - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_unlock_bh(&sta->lock); ieee80211_stop_tx_ba_session(hw, sta->addr, tid, WLAN_BACK_INITIATOR); } @@ -1453,17 +1453,17 @@ void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid, } /* check if TID is in operational state */ - spin_lock_bh(&sta->ampdu_mlme.ampdu_rx); + spin_lock_bh(&sta->lock); if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL) { - spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); + spin_unlock_bh(&sta->lock); rcu_read_unlock(); return; } sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_REQ_STOP_BA_MSK | (initiator << HT_AGG_STATE_INITIATOR_SHIFT); - spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); + spin_unlock_bh(&sta->lock); /* stop HW Rx aggregation. ampdu_action existence * already verified in session init so we add the BUG_ON */ @@ -1540,10 +1540,10 @@ static void ieee80211_sta_process_delba(struct net_device *dev, ieee80211_sta_stop_rx_ba_session(dev, sta->addr, tid, WLAN_BACK_INITIATOR, 0); else { /* WLAN_BACK_RECIPIENT */ - spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_lock_bh(&sta->lock); sta->ampdu_mlme.tid_state_tx[tid] = HT_AGG_STATE_OPERATIONAL; - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_unlock_bh(&sta->lock); ieee80211_stop_tx_ba_session(&local->hw, sta->addr, tid, WLAN_BACK_RECIPIENT); } @@ -1580,9 +1580,9 @@ void sta_addba_resp_timer_expired(unsigned long data) state = &sta->ampdu_mlme.tid_state_tx[tid]; /* check if the TID waits for addBA response */ - spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_lock_bh(&sta->lock); if (!(*state & HT_ADDBA_REQUESTED_MSK)) { - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_unlock_bh(&sta->lock); *state = HT_AGG_STATE_IDLE; printk(KERN_DEBUG "timer expired on tid %d but we are not " "expecting addBA response there", tid); @@ -1593,7 +1593,7 @@ void sta_addba_resp_timer_expired(unsigned long data) /* go through the state check in stop_BA_session */ *state = HT_AGG_STATE_OPERATIONAL; - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_unlock_bh(&sta->lock); ieee80211_stop_tx_ba_session(hw, temp_sta->addr, tid, WLAN_BACK_INITIATOR); @@ -1984,8 +1984,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, * to between the sta_info_alloc() and sta_info_insert() above. */ - sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP | - WLAN_STA_AUTHORIZED; + set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP | + WLAN_STA_AUTHORIZED); rates = 0; basic_rates = 0; @@ -2044,7 +2044,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, rate_control_rate_init(sta, local); if (elems.wmm_param) { - sta->flags |= WLAN_STA_WME; + set_sta_flags(sta, WLAN_STA_WME); rcu_read_unlock(); ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param, elems.wmm_param_len); @@ -4237,7 +4237,7 @@ struct sta_info *ieee80211_ibss_add_sta(struct net_device *dev, if (!sta) return NULL; - sta->flags |= WLAN_STA_AUTHORIZED; + set_sta_flags(sta, WLAN_STA_AUTHORIZED); sta->supp_rates[local->hw.conf.channel->band] = sdata->u.sta.supp_rates_bits[local->hw.conf.channel->band]; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index e8b89c89e87..b399e09ec7a 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -479,7 +479,7 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL && (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)) && rx->sdata->vif.type != IEEE80211_IF_TYPE_IBSS && - (!rx->sta || !(rx->sta->flags & WLAN_STA_ASSOC)))) { + (!rx->sta || !test_sta_flags(rx->sta, WLAN_STA_ASSOC)))) { if ((!(rx->fc & IEEE80211_FCTL_FROMDS) && !(rx->fc & IEEE80211_FCTL_TODS) && (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) @@ -630,8 +630,7 @@ static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta) if (sdata->bss) atomic_inc(&sdata->bss->num_sta_ps); - sta->flags |= WLAN_STA_PS; - sta->flags &= ~WLAN_STA_PSPOLL; + set_and_clear_sta_flags(sta, WLAN_STA_PS, WLAN_STA_PSPOLL); #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "%s: STA %s aid %d enters power save mode\n", dev->name, print_mac(mac, sta->addr), sta->aid); @@ -652,7 +651,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) if (sdata->bss) atomic_dec(&sdata->bss->num_sta_ps); - sta->flags &= ~(WLAN_STA_PS | WLAN_STA_PSPOLL); + clear_sta_flags(sta, WLAN_STA_PS | WLAN_STA_PSPOLL); if (!skb_queue_empty(&sta->ps_tx_buf)) sta_info_clear_tim_bit(sta); @@ -727,9 +726,10 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) if (!(rx->fc & IEEE80211_FCTL_MOREFRAGS)) { /* Change STA power saving mode only in the end of a frame * exchange sequence */ - if ((sta->flags & WLAN_STA_PS) && !(rx->fc & IEEE80211_FCTL_PM)) + if (test_sta_flags(sta, WLAN_STA_PS) && + !(rx->fc & IEEE80211_FCTL_PM)) rx->sent_ps_buffered += ap_sta_ps_end(dev, sta); - else if (!(sta->flags & WLAN_STA_PS) && + else if (!test_sta_flags(sta, WLAN_STA_PS) && (rx->fc & IEEE80211_FCTL_PM)) ap_sta_ps_start(dev, sta); } @@ -983,7 +983,7 @@ ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx) * Tell TX path to send one frame even though the STA may * still remain is PS mode after this frame exchange. */ - rx->sta->flags |= WLAN_STA_PSPOLL; + set_sta_flags(rx->sta, WLAN_STA_PSPOLL); #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "STA %s aid %d: PS Poll (entries after %d)\n", @@ -1046,7 +1046,8 @@ ieee80211_rx_h_remove_qos_control(struct ieee80211_rx_data *rx) static int ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx) { - if (unlikely(!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED))) { + if (unlikely(!rx->sta || + !test_sta_flags(rx->sta, WLAN_STA_AUTHORIZED))) { #ifdef CONFIG_MAC80211_DEBUG if (net_ratelimit()) printk(KERN_DEBUG "%s: dropped frame " diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 631943e8af8..baf5e474688 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -202,14 +202,12 @@ void sta_info_destroy(struct sta_info *sta) dev_kfree_skb_any(skb); for (i = 0; i < STA_TID_NUM; i++) { - spin_lock_bh(&sta->ampdu_mlme.ampdu_rx); + spin_lock_bh(&sta->lock); if (sta->ampdu_mlme.tid_rx[i]) del_timer_sync(&sta->ampdu_mlme.tid_rx[i]->session_timer); - spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); - spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); if (sta->ampdu_mlme.tid_tx[i]) del_timer_sync(&sta->ampdu_mlme.tid_tx[i]->addba_resp_timer); - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_unlock_bh(&sta->lock); } __sta_info_free(local, sta); @@ -236,6 +234,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, if (!sta) return NULL; + spin_lock_init(&sta->lock); + memcpy(sta->addr, addr, ETH_ALEN); sta->local = local; sta->sdata = sdata; @@ -249,8 +249,6 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, return NULL; } - spin_lock_init(&sta->ampdu_mlme.ampdu_rx); - spin_lock_init(&sta->ampdu_mlme.ampdu_tx); for (i = 0; i < STA_TID_NUM; i++) { /* timer_to_tid must be initialized with identity mapping to * enable session_timer's data differentiation. refer to @@ -276,7 +274,6 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, #ifdef CONFIG_MAC80211_MESH sta->plink_state = PLINK_LISTEN; - spin_lock_init(&sta->plink_lock); init_timer(&sta->plink_timer); #endif @@ -437,8 +434,7 @@ void __sta_info_unlink(struct sta_info **sta) list_del(&(*sta)->list); - if ((*sta)->flags & WLAN_STA_PS) { - (*sta)->flags &= ~WLAN_STA_PS; + if (test_and_clear_sta_flags(*sta, WLAN_STA_PS)) { if (sdata->bss) atomic_dec(&sdata->bss->num_sta_ps); __sta_info_clear_tim_bit(sdata->bss, *sta); diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index f8c95bc9659..97a61c39ad9 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -129,23 +129,19 @@ enum plink_state { * * @tid_state_rx: TID's state in Rx session state machine. * @tid_rx: aggregation info for Rx per TID - * @ampdu_rx: for locking sections in aggregation Rx flow * @tid_state_tx: TID's state in Tx session state machine. * @tid_tx: aggregation info for Tx per TID * @addba_req_num: number of times addBA request has been sent. - * @ampdu_tx: for locking sectionsi in aggregation Tx flow * @dialog_token_allocator: dialog token enumerator for each new session; */ struct sta_ampdu_mlme { /* rx */ u8 tid_state_rx[STA_TID_NUM]; struct tid_ampdu_rx *tid_rx[STA_TID_NUM]; - spinlock_t ampdu_rx; /* tx */ u8 tid_state_tx[STA_TID_NUM]; struct tid_ampdu_tx *tid_tx[STA_TID_NUM]; u8 addba_req_num[STA_TID_NUM]; - spinlock_t ampdu_tx; u8 dialog_token_allocator; }; @@ -177,6 +173,8 @@ struct sta_ampdu_mlme { * @rx_bytes: Number of bytes received from this STA * @supp_rates: Bitmap of supported rates (per band) * @ht_info: HT capabilities of this STA + * @lock: used for locking all fields that require locking, see comments + * in the header file. */ struct sta_info { /* General information, mostly static */ @@ -187,6 +185,7 @@ struct sta_info { struct ieee80211_key *key; struct rate_control_ref *rate_ctrl; void *rate_ctrl_priv; + spinlock_t lock; struct ieee80211_ht_info ht_info; u64 supp_rates[IEEE80211_NUM_BANDS]; u8 addr[ETH_ALEN]; @@ -199,7 +198,7 @@ struct sta_info { */ u8 pin_status; - /* frequently updated information, needs locking? */ + /* frequently updated information, locked with lock spinlock */ u32 flags; /* @@ -251,7 +250,7 @@ struct sta_info { int channel_use_raw; /* - * Aggregation information, comes with own locking. + * Aggregation information, locked with lock. */ struct sta_ampdu_mlme ampdu_mlme; u8 timer_to_tid[STA_TID_NUM]; /* identity mapping to ID timers */ @@ -270,9 +269,6 @@ struct sta_info { enum plink_state plink_state; u32 plink_timeout; struct timer_list plink_timer; - spinlock_t plink_lock; /* For peer_state reads / updates and other - updates in the structure. Ensures robust - transitions for the peerlink FSM */ #endif #ifdef CONFIG_MAC80211_DEBUGFS @@ -299,6 +295,64 @@ static inline enum plink_state sta_plink_state(struct sta_info *sta) return PLINK_LISTEN; } +static inline void set_sta_flags(struct sta_info *sta, const u32 flags) +{ + spin_lock_bh(&sta->lock); + sta->flags |= flags; + spin_unlock_bh(&sta->lock); +} + +static inline void clear_sta_flags(struct sta_info *sta, const u32 flags) +{ + spin_lock_bh(&sta->lock); + sta->flags &= ~flags; + spin_unlock_bh(&sta->lock); +} + +static inline void set_and_clear_sta_flags(struct sta_info *sta, + const u32 set, const u32 clear) +{ + spin_lock_bh(&sta->lock); + sta->flags |= set; + sta->flags &= ~clear; + spin_unlock_bh(&sta->lock); +} + +static inline u32 test_sta_flags(struct sta_info *sta, const u32 flags) +{ + u32 ret; + + spin_lock_bh(&sta->lock); + ret = sta->flags & flags; + spin_unlock_bh(&sta->lock); + + return ret; +} + +static inline u32 test_and_clear_sta_flags(struct sta_info *sta, + const u32 flags) +{ + u32 ret; + + spin_lock_bh(&sta->lock); + ret = sta->flags & flags; + sta->flags &= ~flags; + spin_unlock_bh(&sta->lock); + + return ret; +} + +static inline u32 get_sta_flags(struct sta_info *sta) +{ + u32 ret; + + spin_lock_bh(&sta->lock); + ret = sta->flags; + spin_unlock_bh(&sta->lock); + + return ret; +} + /* Maximum number of concurrently registered stations */ #define MAX_STA_COUNT 2007 diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 3a03d7807c3..5f31a6233e1 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -256,7 +256,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) if (tx->flags & IEEE80211_TX_PS_BUFFERED) return TX_CONTINUE; - sta_flags = tx->sta ? tx->sta->flags : 0; + sta_flags = tx->sta ? get_sta_flags(tx->sta) : 0; if (likely(tx->flags & IEEE80211_TX_UNICAST)) { if (unlikely(!(sta_flags & WLAN_STA_ASSOC) && @@ -391,6 +391,7 @@ static ieee80211_tx_result ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) { struct sta_info *sta = tx->sta; + u32 staflags; DECLARE_MAC_BUF(mac); if (unlikely(!sta || @@ -398,8 +399,10 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) (tx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP))) return TX_CONTINUE; - if (unlikely((sta->flags & WLAN_STA_PS) && - !(sta->flags & WLAN_STA_PSPOLL))) { + staflags = get_sta_flags(sta); + + if (unlikely((staflags & WLAN_STA_PS) && + !(staflags & WLAN_STA_PSPOLL))) { struct ieee80211_tx_packet_data *pkt_data; #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "STA %s aid %d: PS buffer (entries " @@ -430,13 +433,13 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) return TX_QUEUED; } #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - else if (unlikely(sta->flags & WLAN_STA_PS)) { + else if (unlikely(test_sta_flags(sta, WLAN_STA_PS))) { printk(KERN_DEBUG "%s: STA %s in PS mode, but pspoll " "set -> send frame\n", tx->dev->name, print_mac(mac, sta->addr)); } #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - sta->flags &= ~WLAN_STA_PSPOLL; + clear_sta_flags(sta, WLAN_STA_PSPOLL); return TX_CONTINUE; } @@ -697,7 +700,7 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && (tx->rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) && tx->sdata->bss_conf.use_short_preamble && - (!tx->sta || (tx->sta->flags & WLAN_STA_SHORT_PREAMBLE))) { + (!tx->sta || test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE))) { tx->control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE; } @@ -1025,10 +1028,8 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, if (!tx->sta) control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT; - else if (tx->sta->flags & WLAN_STA_CLEAR_PS_FILT) { + else if (test_and_clear_sta_flags(tx->sta, WLAN_STA_CLEAR_PS_FILT)) control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT; - tx->sta->flags &= ~WLAN_STA_CLEAR_PS_FILT; - } hdrlen = ieee80211_get_hdrlen(tx->fc); if (skb->len > hdrlen + sizeof(rfc1042_header) + 2) { @@ -1486,7 +1487,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, rcu_read_lock(); sta = sta_info_get(local, hdr.addr1); if (sta) - sta_flags = sta->flags; + sta_flags = get_sta_flags(sta); rcu_read_unlock(); } -- cgit v1.2.3-70-g09d2 From 0d0b2c1c49814ee54f1b4efd2c715a7465219ede Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Sun, 4 May 2008 14:48:18 +0300 Subject: iwlwifi: map A-MPDU HW queue to mac80211 A-MPDU SW queue This patch maps A-MPDU HW queue to mac80211 SW queue scheme (as introduced in patch "mac80211: QoS related cleanups"), when trying to perform ieee80211_wake_queue. Signed-off-by: Ron Rindjunsky Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 5 ++++- drivers/net/wireless/iwlwifi/iwl4965-base.c | 23 +++++++++++------------ 2 files changed, 15 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 9546582e983..70c0455b622 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -3547,13 +3547,16 @@ static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv, * block-ack window (we assume that they've been successfully * transmitted ... if not, it's too late anyway). */ if (txq->q.read_ptr != (ba_resp_scd_ssn & 0xff)) { + /* calculate mac80211 ampdu sw queue to wake */ + int ampdu_q = + scd_flow - IWL_BACK_QUEUE_FIRST_ID + priv->hw->queues; int freed = iwl4965_tx_queue_reclaim(priv, scd_flow, index); priv->stations[ba_resp->sta_id]. tid[ba_resp->tid].tfds_in_queue -= freed; if (iwl4965_queue_space(&txq->q) > txq->q.low_mark && priv->mac80211_registered && agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) - ieee80211_wake_queue(priv->hw, scd_flow); + ieee80211_wake_queue(priv->hw, ampdu_q); iwl4965_check_empty_hw_queue(priv, ba_resp->sta_id, ba_resp->tid, scd_flow); } diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 4406fc72d88..54534270d46 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -2568,12 +2568,6 @@ int iwl4965_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) nfreed++; } -/* if (iwl4965_queue_space(q) > q->low_mark && (txq_id >= 0) && - (txq_id != IWL_CMD_QUEUE_NUM) && - priv->mac80211_registered) - ieee80211_wake_queue(priv->hw, txq_id); */ - - return nfreed; } @@ -2797,7 +2791,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, } if (txq->q.read_ptr != (scd_ssn & 0xff)) { - int freed; + int freed, ampdu_q; index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd); IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn " "%d index %d\n", scd_ssn , index); @@ -2806,9 +2800,15 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, if (iwl4965_queue_space(&txq->q) > txq->q.low_mark && txq_id >= 0 && priv->mac80211_registered && - agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) - ieee80211_wake_queue(priv->hw, txq_id); - + agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) { + /* calculate mac80211 ampdu sw queue to wake */ + ampdu_q = txq_id - IWL_BACK_QUEUE_FIRST_ID + + priv->hw->queues; + if (agg->state == IWL_AGG_OFF) + ieee80211_wake_queue(priv->hw, txq_id); + else + ieee80211_wake_queue(priv->hw, ampdu_q); + } iwl4965_check_empty_hw_queue(priv, sta_id, tid, txq_id); } } else { @@ -2833,8 +2833,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, if (tid != MAX_TID_COUNT) priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; if (iwl4965_queue_space(&txq->q) > txq->q.low_mark && - (txq_id >= 0) && - priv->mac80211_registered) + (txq_id >= 0) && priv->mac80211_registered) ieee80211_wake_queue(priv->hw, txq_id); if (tid != MAX_TID_COUNT) iwl4965_check_empty_hw_queue(priv, sta_id, tid, txq_id); -- cgit v1.2.3-70-g09d2 From a55360e458551b0add4ec147ef786d71e163bf50 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Mon, 5 May 2008 10:22:28 +0800 Subject: iwlwifi: move RX code to iwl-rx.c This patch moves partialy rx code into iwl-rx.c as part of iwlcore. The second part of the code can be merged only with moving of tx code as well. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/Makefile | 1 + drivers/net/wireless/iwlwifi/iwl-4965.c | 25 +- drivers/net/wireless/iwlwifi/iwl-core.h | 16 + drivers/net/wireless/iwlwifi/iwl-dev.h | 26 +- drivers/net/wireless/iwlwifi/iwl-rx.c | 371 +++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl4965-base.c | 545 ++++++---------------------- 6 files changed, 517 insertions(+), 467 deletions(-) create mode 100644 drivers/net/wireless/iwlwifi/iwl-rx.c (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index b0b2b5ebfa6..0211a7f7147 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -1,5 +1,6 @@ obj-$(CONFIG_IWLCORE) += iwlcore.o iwlcore-objs := iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.o +iwlcore-objs += iwl-rx.o iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o iwlcore-$(CONFIG_IWLWIFI_LEDS) += iwl-led.o iwlcore-$(CONFIG_IWLWIFI_RFKILL) += iwl-rfkill.o diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 70c0455b622..773bb3229cf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -372,7 +372,7 @@ int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src) return ret; } -static int iwl4965_rx_init(struct iwl_priv *priv, struct iwl4965_rx_queue *rxq) +static int iwl4965_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) { int ret; unsigned long flags; @@ -625,7 +625,7 @@ static void iwl4965_nic_config(struct iwl_priv *priv) int iwl4965_hw_nic_init(struct iwl_priv *priv) { unsigned long flags; - struct iwl4965_rx_queue *rxq = &priv->rxq; + struct iwl_rx_queue *rxq = &priv->rxq; int ret; /* nic_init */ @@ -645,22 +645,22 @@ int iwl4965_hw_nic_init(struct iwl_priv *priv) /* Allocate the RX queue, or reset if it is already allocated */ if (!rxq->bd) { - ret = iwl4965_rx_queue_alloc(priv); + ret = iwl_rx_queue_alloc(priv); if (ret) { IWL_ERROR("Unable to initialize Rx queue\n"); return -ENOMEM; } } else - iwl4965_rx_queue_reset(priv, rxq); + iwl_rx_queue_reset(priv, rxq); - iwl4965_rx_replenish(priv); + iwl_rx_replenish(priv); iwl4965_rx_init(priv, rxq); spin_lock_irqsave(&priv->lock, flags); rxq->need_update = 1; - iwl4965_rx_queue_update_write_ptr(priv, rxq); + iwl_rx_queue_update_write_ptr(priv, rxq); spin_unlock_irqrestore(&priv->lock, flags); @@ -2516,7 +2516,8 @@ static void iwl4965_rx_calc_noise(struct iwl_priv *priv) priv->last_rx_noise); } -void iwl4965_hw_rx_statistics(struct iwl_priv *priv, struct iwl4965_rx_mem_buffer *rxb) +void iwl4965_hw_rx_statistics(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) { struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; int change; @@ -2803,7 +2804,7 @@ static u32 iwl4965_translate_rx_status(u32 decrypt_in) static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data, int include_phy, - struct iwl4965_rx_mem_buffer *rxb, + struct iwl_rx_mem_buffer *rxb, struct ieee80211_rx_status *stats) { struct iwl4965_rx_packet *pkt = (struct iwl4965_rx_packet *)rxb->skb->data; @@ -3109,7 +3110,7 @@ static inline void iwl4965_dbg_report_frame(struct iwl_priv *priv, /* Called for REPLY_RX (legacy ABG frames), or * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */ static void iwl4965_rx_reply_rx(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb) + struct iwl_rx_mem_buffer *rxb) { struct ieee80211_hdr *header; struct ieee80211_rx_status rx_status; @@ -3278,7 +3279,7 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv, /* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD). * This will be used later in iwl4965_rx_reply_rx() for REPLY_RX_MPDU_CMD. */ static void iwl4965_rx_reply_rx_phy(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb) + struct iwl_rx_mem_buffer *rxb) { struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; priv->last_phy_res[0] = 1; @@ -3286,7 +3287,7 @@ static void iwl4965_rx_reply_rx_phy(struct iwl_priv *priv, sizeof(struct iwl4965_rx_phy_res)); } static void iwl4965_rx_missed_beacon_notif(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb) + struct iwl_rx_mem_buffer *rxb) { #ifdef CONFIG_IWL4965_RUN_TIME_CALIB @@ -3495,7 +3496,7 @@ static inline int iwl4965_queue_dec_wrap(int index, int n_bd) * of frames sent via aggregation. */ static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb) + struct iwl_rx_mem_buffer *rxb) { struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; struct iwl4965_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 369f1821584..2356cadc1de 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -173,6 +173,21 @@ int iwl_set_rxon_channel(struct iwl_priv *priv, void iwlcore_free_geos(struct iwl_priv *priv); int iwl_setup(struct iwl_priv *priv); +/***************************************************** +* RX +******************************************************/ +void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq); +int iwl_rx_queue_alloc(struct iwl_priv *priv); +void iwl_rx_handle(struct iwl_priv *priv); +int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, + struct iwl_rx_queue *q); +void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq); +void iwl_rx_replenish(struct iwl_priv *priv); +/* FIXME: remove when TX is moved to iwl core */ +int iwl_rx_queue_restock(struct iwl_priv *priv); +int iwl_rx_queue_space(const struct iwl_rx_queue *q); +void iwl_rx_allocate(struct iwl_priv *priv); + /***************************************************** * S e n d i n g H o s t C o m m a n d s * *****************************************************/ @@ -265,4 +280,5 @@ static inline int iwl_send_rxon_assoc(struct iwl_priv *priv) return priv->cfg->ops->hcmd->rxon_assoc(priv); } + #endif /* __iwl_core_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 78aba21bc18..1d80ad79114 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -91,7 +91,7 @@ extern struct iwl_cfg iwl5350_agn_cfg; #define DEFAULT_SHORT_RETRY_LIMIT 7U #define DEFAULT_LONG_RETRY_LIMIT 4U -struct iwl4965_rx_mem_buffer { +struct iwl_rx_mem_buffer { dma_addr_t dma_addr; struct sk_buff *skb; struct list_head list; @@ -358,7 +358,7 @@ struct iwl_host_cmd { #define SUP_RATE_11G_MAX_NUM_CHANNELS 12 /** - * struct iwl4965_rx_queue - Rx queue + * struct iwl_rx_queue - Rx queue * @processed: Internal index to last handled Rx packet * @read: Shared index to newest available Rx buffer * @write: Shared index to oldest written Rx packet @@ -367,13 +367,13 @@ struct iwl_host_cmd { * @rx_used: List of Rx buffers with no SKB * @need_update: flag to indicate we need to update read/write index * - * NOTE: rx_free and rx_used are used as a FIFO for iwl4965_rx_mem_buffers + * NOTE: rx_free and rx_used are used as a FIFO for iwl_rx_mem_buffers */ -struct iwl4965_rx_queue { +struct iwl_rx_queue { __le32 *bd; dma_addr_t dma_addr; - struct iwl4965_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS]; - struct iwl4965_rx_mem_buffer *queue[RX_QUEUE_SIZE]; + struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS]; + struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE]; u32 processed; u32 read; u32 write; @@ -643,26 +643,20 @@ extern int iwl4965_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header); extern int iwl4965_power_init_handle(struct iwl_priv *priv); extern void iwl4965_handle_data_packet_monitor(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb, + struct iwl_rx_mem_buffer *rxb, void *data, short len, struct ieee80211_rx_status *stats, u16 phy_flags); extern int iwl4965_is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header); -extern int iwl4965_rx_queue_alloc(struct iwl_priv *priv); -extern void iwl4965_rx_queue_reset(struct iwl_priv *priv, - struct iwl4965_rx_queue *rxq); extern int iwl4965_calc_db_from_ratio(int sig_ratio); extern int iwl4965_calc_sig_qual(int rssi_dbm, int noise_dbm); extern int iwl4965_tx_queue_init(struct iwl_priv *priv, struct iwl4965_tx_queue *txq, int count, u32 id); -extern void iwl4965_rx_replenish(void *data); extern void iwl4965_tx_queue_free(struct iwl_priv *priv, struct iwl4965_tx_queue *txq); extern unsigned int iwl4965_fill_beacon_frame(struct iwl_priv *priv, struct ieee80211_hdr *hdr, const u8 *dest, int left); -extern int iwl4965_rx_queue_update_write_ptr(struct iwl_priv *priv, - struct iwl4965_rx_queue *q); extern __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr); extern void iwl4965_update_chain_flags(struct iwl_priv *priv); int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src); @@ -722,7 +716,7 @@ extern void iwl4965_hw_build_tx_cmd_rate(struct iwl_priv *priv, extern int iwl4965_hw_reg_send_txpower(struct iwl_priv *priv); extern int iwl4965_hw_reg_set_txpower(struct iwl_priv *priv, s8 power); extern void iwl4965_hw_rx_statistics(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb); + struct iwl_rx_mem_buffer *rxb); extern void iwl4965_disable_events(struct iwl_priv *priv); extern int iwl4965_get_temperature(const struct iwl_priv *priv); @@ -960,7 +954,7 @@ struct iwl_priv { bool add_radiotap; void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb); + struct iwl_rx_mem_buffer *rxb); struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS]; @@ -1077,7 +1071,7 @@ struct iwl_priv { int activity_timer_active; /* Rx and Tx DMA processing queues */ - struct iwl4965_rx_queue rxq; + struct iwl_rx_queue rxq; struct iwl4965_tx_queue txq[IWL_MAX_NUM_QUEUES]; unsigned long txq_ctx_active_msk; struct iwl4965_kw kw; /* keep warm address */ diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c new file mode 100644 index 00000000000..667b592e6ad --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -0,0 +1,371 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project, as well + * as portions of the ieee80211 subsystem header files. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#include +#include "iwl-eeprom.h" +#include "iwl-dev.h" +#include "iwl-core.h" +#include "iwl-sta.h" +#include "iwl-io.h" +#include "iwl-helpers.h" +/************************** RX-FUNCTIONS ****************************/ +/* + * Rx theory of operation + * + * Driver allocates a circular buffer of Receive Buffer Descriptors (RBDs), + * each of which point to Receive Buffers to be filled by the NIC. These get + * used not only for Rx frames, but for any command response or notification + * from the NIC. The driver and NIC manage the Rx buffers by means + * of indexes into the circular buffer. + * + * Rx Queue Indexes + * The host/firmware share two index registers for managing the Rx buffers. + * + * The READ index maps to the first position that the firmware may be writing + * to -- the driver can read up to (but not including) this position and get + * good data. + * The READ index is managed by the firmware once the card is enabled. + * + * The WRITE index maps to the last position the driver has read from -- the + * position preceding WRITE is the last slot the firmware can place a packet. + * + * The queue is empty (no good data) if WRITE = READ - 1, and is full if + * WRITE = READ. + * + * During initialization, the host sets up the READ queue position to the first + * INDEX position, and WRITE to the last (READ - 1 wrapped) + * + * When the firmware places a packet in a buffer, it will advance the READ index + * and fire the RX interrupt. The driver can then query the READ index and + * process as many packets as possible, moving the WRITE index forward as it + * resets the Rx queue buffers with new memory. + * + * The management in the driver is as follows: + * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free. When + * iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled + * to replenish the iwl->rxq->rx_free. + * + In iwl_rx_replenish (scheduled) if 'processed' != 'read' then the + * iwl->rxq is replenished and the READ INDEX is updated (updating the + * 'processed' and 'read' driver indexes as well) + * + A received packet is processed and handed to the kernel network stack, + * detached from the iwl->rxq. The driver 'processed' index is updated. + * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free + * list. If there are no allocated buffers in iwl->rxq->rx_free, the READ + * INDEX is not incremented and iwl->status(RX_STALLED) is set. If there + * were enough free buffers and RX_STALLED is set it is cleared. + * + * + * Driver sequence: + * + * iwl_rx_queue_alloc() Allocates rx_free + * iwl_rx_replenish() Replenishes rx_free list from rx_used, and calls + * iwl_rx_queue_restock + * iwl_rx_queue_restock() Moves available buffers from rx_free into Rx + * queue, updates firmware pointers, and updates + * the WRITE index. If insufficient rx_free buffers + * are available, schedules iwl_rx_replenish + * + * -- enable interrupts -- + * ISR - iwl_rx() Detach iwl_rx_mem_buffers from pool up to the + * READ INDEX, detaching the SKB from the pool. + * Moves the packet buffer from queue to rx_used. + * Calls iwl_rx_queue_restock to refill any empty + * slots. + * ... + * + */ + +/** + * iwl_rx_queue_space - Return number of free slots available in queue. + */ +int iwl_rx_queue_space(const struct iwl_rx_queue *q) +{ + int s = q->read - q->write; + if (s <= 0) + s += RX_QUEUE_SIZE; + /* keep some buffer to not confuse full and empty queue */ + s -= 2; + if (s < 0) + s = 0; + return s; +} +EXPORT_SYMBOL(iwl_rx_queue_space); + +/** + * iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue + */ +int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q) +{ + u32 reg = 0; + int ret = 0; + unsigned long flags; + + spin_lock_irqsave(&q->lock, flags); + + if (q->need_update == 0) + goto exit_unlock; + + /* If power-saving is in use, make sure device is awake */ + if (test_bit(STATUS_POWER_PMI, &priv->status)) { + reg = iwl_read32(priv, CSR_UCODE_DRV_GP1); + + if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { + iwl_set_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + goto exit_unlock; + } + + ret = iwl_grab_nic_access(priv); + if (ret) + goto exit_unlock; + + /* Device expects a multiple of 8 */ + iwl_write_direct32(priv, FH_RSCSR_CHNL0_WPTR, + q->write & ~0x7); + iwl_release_nic_access(priv); + + /* Else device is assumed to be awake */ + } else + /* Device expects a multiple of 8 */ + iwl_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7); + + + q->need_update = 0; + + exit_unlock: + spin_unlock_irqrestore(&q->lock, flags); + return ret; +} +EXPORT_SYMBOL(iwl_rx_queue_update_write_ptr); +/** + * iwl_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr + */ +static inline __le32 iwl_dma_addr2rbd_ptr(struct iwl_priv *priv, + dma_addr_t dma_addr) +{ + return cpu_to_le32((u32)(dma_addr >> 8)); +} + +/** + * iwl_rx_queue_restock - refill RX queue from pre-allocated pool + * + * If there are slots in the RX queue that need to be restocked, + * and we have free pre-allocated buffers, fill the ranks as much + * as we can, pulling from rx_free. + * + * This moves the 'write' index forward to catch up with 'processed', and + * also updates the memory address in the firmware to reference the new + * target buffer. + */ +int iwl_rx_queue_restock(struct iwl_priv *priv) +{ + struct iwl_rx_queue *rxq = &priv->rxq; + struct list_head *element; + struct iwl_rx_mem_buffer *rxb; + unsigned long flags; + int write; + int ret = 0; + + spin_lock_irqsave(&rxq->lock, flags); + write = rxq->write & ~0x7; + while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) { + /* Get next free Rx buffer, remove from free list */ + element = rxq->rx_free.next; + rxb = list_entry(element, struct iwl_rx_mem_buffer, list); + list_del(element); + + /* Point to Rx buffer via next RBD in circular buffer */ + rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(priv, rxb->dma_addr); + rxq->queue[rxq->write] = rxb; + rxq->write = (rxq->write + 1) & RX_QUEUE_MASK; + rxq->free_count--; + } + spin_unlock_irqrestore(&rxq->lock, flags); + /* If the pre-allocated buffer pool is dropping low, schedule to + * refill it */ + if (rxq->free_count <= RX_LOW_WATERMARK) + queue_work(priv->workqueue, &priv->rx_replenish); + + + /* If we've added more space for the firmware to place data, tell it. + * Increment device's write pointer in multiples of 8. */ + if ((write != (rxq->write & ~0x7)) + || (abs(rxq->write - rxq->read) > 7)) { + spin_lock_irqsave(&rxq->lock, flags); + rxq->need_update = 1; + spin_unlock_irqrestore(&rxq->lock, flags); + ret = iwl_rx_queue_update_write_ptr(priv, rxq); + } + + return ret; +} +EXPORT_SYMBOL(iwl_rx_queue_restock); + + +/** + * iwl_rx_replenish - Move all used packet from rx_used to rx_free + * + * When moving to rx_free an SKB is allocated for the slot. + * + * Also restock the Rx queue via iwl_rx_queue_restock. + * This is called as a scheduled work item (except for during initialization) + */ +void iwl_rx_allocate(struct iwl_priv *priv) +{ + struct iwl_rx_queue *rxq = &priv->rxq; + struct list_head *element; + struct iwl_rx_mem_buffer *rxb; + unsigned long flags; + spin_lock_irqsave(&rxq->lock, flags); + while (!list_empty(&rxq->rx_used)) { + element = rxq->rx_used.next; + rxb = list_entry(element, struct iwl_rx_mem_buffer, list); + + /* Alloc a new receive buffer */ + rxb->skb = alloc_skb(priv->hw_params.rx_buf_size, + __GFP_NOWARN | GFP_ATOMIC); + if (!rxb->skb) { + if (net_ratelimit()) + printk(KERN_CRIT DRV_NAME + ": Can not allocate SKB buffers\n"); + /* We don't reschedule replenish work here -- we will + * call the restock method and if it still needs + * more buffers it will schedule replenish */ + break; + } + priv->alloc_rxb_skb++; + list_del(element); + + /* Get physical address of RB/SKB */ + rxb->dma_addr = + pci_map_single(priv->pci_dev, rxb->skb->data, + priv->hw_params.rx_buf_size, PCI_DMA_FROMDEVICE); + list_add_tail(&rxb->list, &rxq->rx_free); + rxq->free_count++; + } + spin_unlock_irqrestore(&rxq->lock, flags); +} +EXPORT_SYMBOL(iwl_rx_allocate); + +void iwl_rx_replenish(struct iwl_priv *priv) +{ + unsigned long flags; + + iwl_rx_allocate(priv); + + spin_lock_irqsave(&priv->lock, flags); + iwl_rx_queue_restock(priv); + spin_unlock_irqrestore(&priv->lock, flags); +} +EXPORT_SYMBOL(iwl_rx_replenish); + + +/* Assumes that the skb field of the buffers in 'pool' is kept accurate. + * If an SKB has been detached, the POOL needs to have its SKB set to NULL + * This free routine walks the list of POOL entries and if SKB is set to + * non NULL it is unmapped and freed + */ +void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq) +{ + int i; + for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) { + if (rxq->pool[i].skb != NULL) { + pci_unmap_single(priv->pci_dev, + rxq->pool[i].dma_addr, + priv->hw_params.rx_buf_size, + PCI_DMA_FROMDEVICE); + dev_kfree_skb(rxq->pool[i].skb); + } + } + + pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd, + rxq->dma_addr); + rxq->bd = NULL; +} +EXPORT_SYMBOL(iwl_rx_queue_free); + +int iwl_rx_queue_alloc(struct iwl_priv *priv) +{ + struct iwl_rx_queue *rxq = &priv->rxq; + struct pci_dev *dev = priv->pci_dev; + int i; + + spin_lock_init(&rxq->lock); + INIT_LIST_HEAD(&rxq->rx_free); + INIT_LIST_HEAD(&rxq->rx_used); + + /* Alloc the circular buffer of Read Buffer Descriptors (RBDs) */ + rxq->bd = pci_alloc_consistent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr); + if (!rxq->bd) + return -ENOMEM; + + /* Fill the rx_used queue with _all_ of the Rx buffers */ + for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) + list_add_tail(&rxq->pool[i].list, &rxq->rx_used); + + /* Set us so that we have processed and used all buffers, but have + * not restocked the Rx queue with fresh buffers */ + rxq->read = rxq->write = 0; + rxq->free_count = 0; + rxq->need_update = 0; + return 0; +} +EXPORT_SYMBOL(iwl_rx_queue_alloc); + +void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq) +{ + unsigned long flags; + int i; + spin_lock_irqsave(&rxq->lock, flags); + INIT_LIST_HEAD(&rxq->rx_free); + INIT_LIST_HEAD(&rxq->rx_used); + /* Fill the rx_used queue with _all_ of the Rx buffers */ + for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) { + /* In the reset function, these buffers may have been allocated + * to an SKB, so we need to unmap and free potential storage */ + if (rxq->pool[i].skb != NULL) { + pci_unmap_single(priv->pci_dev, + rxq->pool[i].dma_addr, + priv->hw_params.rx_buf_size, + PCI_DMA_FROMDEVICE); + priv->alloc_rxb_skb--; + dev_kfree_skb(rxq->pool[i].skb); + rxq->pool[i].skb = NULL; + } + list_add_tail(&rxq->pool[i].list, &rxq->rx_used); + } + + /* Set us so that we have processed and used all buffers, but have + * not restocked the Rx queue with fresh buffers */ + rxq->read = rxq->write = 0; + rxq->free_count = 0; + spin_unlock_irqrestore(&rxq->lock, flags); +} +EXPORT_SYMBOL(iwl_rx_queue_reset); + diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 54534270d46..aa0393589da 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -2736,7 +2736,7 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv, * iwl4965_rx_reply_tx - Handle standard (non-aggregation) Tx response */ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb) + struct iwl_rx_mem_buffer *rxb) { struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; u16 sequence = le16_to_cpu(pkt->hdr.sequence); @@ -2849,7 +2849,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, static void iwl4965_rx_reply_alive(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb) + struct iwl_rx_mem_buffer *rxb) { struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; struct iwl4965_alive_resp *palive; @@ -2885,7 +2885,7 @@ static void iwl4965_rx_reply_alive(struct iwl_priv *priv, } static void iwl4965_rx_reply_add_sta(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb) + struct iwl_rx_mem_buffer *rxb) { struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; @@ -2894,7 +2894,7 @@ static void iwl4965_rx_reply_add_sta(struct iwl_priv *priv, } static void iwl4965_rx_reply_error(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb) + struct iwl_rx_mem_buffer *rxb) { struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; @@ -2909,7 +2909,7 @@ static void iwl4965_rx_reply_error(struct iwl_priv *priv, #define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x -static void iwl4965_rx_csa(struct iwl_priv *priv, struct iwl4965_rx_mem_buffer *rxb) +static void iwl4965_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; struct iwl4965_rxon_cmd *rxon = (void *)&priv->active_rxon; @@ -2921,7 +2921,7 @@ static void iwl4965_rx_csa(struct iwl_priv *priv, struct iwl4965_rx_mem_buffer * } static void iwl4965_rx_spectrum_measure_notif(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb) + struct iwl_rx_mem_buffer *rxb) { #ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; @@ -2939,7 +2939,7 @@ static void iwl4965_rx_spectrum_measure_notif(struct iwl_priv *priv, } static void iwl4965_rx_pm_sleep_notif(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb) + struct iwl_rx_mem_buffer *rxb) { #ifdef CONFIG_IWLWIFI_DEBUG struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; @@ -2950,7 +2950,7 @@ static void iwl4965_rx_pm_sleep_notif(struct iwl_priv *priv, } static void iwl4965_rx_pm_debug_statistics_notif(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb) + struct iwl_rx_mem_buffer *rxb) { struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; IWL_DEBUG_RADIO("Dumping %d bytes of unhandled " @@ -2985,7 +2985,7 @@ static void iwl4965_bg_beacon_update(struct work_struct *work) } static void iwl4965_rx_beacon_notif(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb) + struct iwl_rx_mem_buffer *rxb) { #ifdef CONFIG_IWLWIFI_DEBUG struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; @@ -3008,7 +3008,7 @@ static void iwl4965_rx_beacon_notif(struct iwl_priv *priv, /* Service response to REPLY_SCAN_CMD (0x80) */ static void iwl4965_rx_reply_scan(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb) + struct iwl_rx_mem_buffer *rxb) { #ifdef CONFIG_IWLWIFI_DEBUG struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; @@ -3021,7 +3021,7 @@ static void iwl4965_rx_reply_scan(struct iwl_priv *priv, /* Service SCAN_START_NOTIFICATION (0x82) */ static void iwl4965_rx_scan_start_notif(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb) + struct iwl_rx_mem_buffer *rxb) { struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; struct iwl4965_scanstart_notification *notif = @@ -3038,7 +3038,7 @@ static void iwl4965_rx_scan_start_notif(struct iwl_priv *priv, /* Service SCAN_RESULTS_NOTIFICATION (0x83) */ static void iwl4965_rx_scan_results_notif(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb) + struct iwl_rx_mem_buffer *rxb) { struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; struct iwl4965_scanresults_notification *notif = @@ -3063,7 +3063,7 @@ static void iwl4965_rx_scan_results_notif(struct iwl_priv *priv, /* Service SCAN_COMPLETE_NOTIFICATION (0x84) */ static void iwl4965_rx_scan_complete_notif(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb) + struct iwl_rx_mem_buffer *rxb) { struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; struct iwl4965_scancomplete_notification *scan_notif = (void *)pkt->u.raw; @@ -3121,7 +3121,7 @@ reschedule: /* Handle notification from uCode that card's power state is changing * due to software, hardware, or critical temperature RFKILL */ static void iwl4965_rx_card_state_notif(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb) + struct iwl_rx_mem_buffer *rxb) { struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags); @@ -3241,7 +3241,7 @@ static void iwl4965_setup_rx_handlers(struct iwl_priv *priv) * if the callback returns 1 */ static void iwl4965_tx_cmd_complete(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb) + struct iwl_rx_mem_buffer *rxb) { struct iwl4965_rx_packet *pkt = (struct iwl4965_rx_packet *)rxb->skb->data; u16 sequence = le16_to_cpu(pkt->hdr.sequence); @@ -3278,438 +3278,28 @@ static void iwl4965_tx_cmd_complete(struct iwl_priv *priv, } } -/************************** RX-FUNCTIONS ****************************/ -/* - * Rx theory of operation - * - * Driver allocates a circular buffer of Receive Buffer Descriptors (RBDs), - * each of which point to Receive Buffers to be filled by 4965. These get - * used not only for Rx frames, but for any command response or notification - * from the 4965. The driver and 4965 manage the Rx buffers by means - * of indexes into the circular buffer. - * - * Rx Queue Indexes - * The host/firmware share two index registers for managing the Rx buffers. - * - * The READ index maps to the first position that the firmware may be writing - * to -- the driver can read up to (but not including) this position and get - * good data. - * The READ index is managed by the firmware once the card is enabled. - * - * The WRITE index maps to the last position the driver has read from -- the - * position preceding WRITE is the last slot the firmware can place a packet. - * - * The queue is empty (no good data) if WRITE = READ - 1, and is full if - * WRITE = READ. - * - * During initialization, the host sets up the READ queue position to the first - * INDEX position, and WRITE to the last (READ - 1 wrapped) - * - * When the firmware places a packet in a buffer, it will advance the READ index - * and fire the RX interrupt. The driver can then query the READ index and - * process as many packets as possible, moving the WRITE index forward as it - * resets the Rx queue buffers with new memory. - * - * The management in the driver is as follows: - * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free. When - * iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled - * to replenish the iwl->rxq->rx_free. - * + In iwl4965_rx_replenish (scheduled) if 'processed' != 'read' then the - * iwl->rxq is replenished and the READ INDEX is updated (updating the - * 'processed' and 'read' driver indexes as well) - * + A received packet is processed and handed to the kernel network stack, - * detached from the iwl->rxq. The driver 'processed' index is updated. - * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free - * list. If there are no allocated buffers in iwl->rxq->rx_free, the READ - * INDEX is not incremented and iwl->status(RX_STALLED) is set. If there - * were enough free buffers and RX_STALLED is set it is cleared. - * - * - * Driver sequence: - * - * iwl4965_rx_queue_alloc() Allocates rx_free - * iwl4965_rx_replenish() Replenishes rx_free list from rx_used, and calls - * iwl4965_rx_queue_restock - * iwl4965_rx_queue_restock() Moves available buffers from rx_free into Rx - * queue, updates firmware pointers, and updates - * the WRITE index. If insufficient rx_free buffers - * are available, schedules iwl4965_rx_replenish - * - * -- enable interrupts -- - * ISR - iwl4965_rx() Detach iwl4965_rx_mem_buffers from pool up to the - * READ INDEX, detaching the SKB from the pool. - * Moves the packet buffer from queue to rx_used. - * Calls iwl4965_rx_queue_restock to refill any empty - * slots. - * ... - * - */ - -/** - * iwl4965_rx_queue_space - Return number of free slots available in queue. - */ -static int iwl4965_rx_queue_space(const struct iwl4965_rx_queue *q) -{ - int s = q->read - q->write; - if (s <= 0) - s += RX_QUEUE_SIZE; - /* keep some buffer to not confuse full and empty queue */ - s -= 2; - if (s < 0) - s = 0; - return s; -} - -/** - * iwl4965_rx_queue_update_write_ptr - Update the write pointer for the RX queue - */ -int iwl4965_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl4965_rx_queue *q) -{ - u32 reg = 0; - int rc = 0; - unsigned long flags; - - spin_lock_irqsave(&q->lock, flags); - - if (q->need_update == 0) - goto exit_unlock; - - /* If power-saving is in use, make sure device is awake */ - if (test_bit(STATUS_POWER_PMI, &priv->status)) { - reg = iwl_read32(priv, CSR_UCODE_DRV_GP1); - - if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { - iwl_set_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - goto exit_unlock; - } - - rc = iwl_grab_nic_access(priv); - if (rc) - goto exit_unlock; - - /* Device expects a multiple of 8 */ - iwl_write_direct32(priv, FH_RSCSR_CHNL0_WPTR, - q->write & ~0x7); - iwl_release_nic_access(priv); - - /* Else device is assumed to be awake */ - } else - /* Device expects a multiple of 8 */ - iwl_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7); - - - q->need_update = 0; - - exit_unlock: - spin_unlock_irqrestore(&q->lock, flags); - return rc; -} - -/** - * iwl4965_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr - */ -static inline __le32 iwl4965_dma_addr2rbd_ptr(struct iwl_priv *priv, - dma_addr_t dma_addr) -{ - return cpu_to_le32((u32)(dma_addr >> 8)); -} - - -/** - * iwl4965_rx_queue_restock - refill RX queue from pre-allocated pool - * - * If there are slots in the RX queue that need to be restocked, - * and we have free pre-allocated buffers, fill the ranks as much - * as we can, pulling from rx_free. - * - * This moves the 'write' index forward to catch up with 'processed', and - * also updates the memory address in the firmware to reference the new - * target buffer. - */ -static int iwl4965_rx_queue_restock(struct iwl_priv *priv) -{ - struct iwl4965_rx_queue *rxq = &priv->rxq; - struct list_head *element; - struct iwl4965_rx_mem_buffer *rxb; - unsigned long flags; - int write, rc; - - spin_lock_irqsave(&rxq->lock, flags); - write = rxq->write & ~0x7; - while ((iwl4965_rx_queue_space(rxq) > 0) && (rxq->free_count)) { - /* Get next free Rx buffer, remove from free list */ - element = rxq->rx_free.next; - rxb = list_entry(element, struct iwl4965_rx_mem_buffer, list); - list_del(element); - - /* Point to Rx buffer via next RBD in circular buffer */ - rxq->bd[rxq->write] = iwl4965_dma_addr2rbd_ptr(priv, rxb->dma_addr); - rxq->queue[rxq->write] = rxb; - rxq->write = (rxq->write + 1) & RX_QUEUE_MASK; - rxq->free_count--; - } - spin_unlock_irqrestore(&rxq->lock, flags); - /* If the pre-allocated buffer pool is dropping low, schedule to - * refill it */ - if (rxq->free_count <= RX_LOW_WATERMARK) - queue_work(priv->workqueue, &priv->rx_replenish); - - - /* If we've added more space for the firmware to place data, tell it. - * Increment device's write pointer in multiples of 8. */ - if ((write != (rxq->write & ~0x7)) - || (abs(rxq->write - rxq->read) > 7)) { - spin_lock_irqsave(&rxq->lock, flags); - rxq->need_update = 1; - spin_unlock_irqrestore(&rxq->lock, flags); - rc = iwl4965_rx_queue_update_write_ptr(priv, rxq); - if (rc) - return rc; - } - - return 0; -} - -/** - * iwl4965_rx_replenish - Move all used packet from rx_used to rx_free - * - * When moving to rx_free an SKB is allocated for the slot. - * - * Also restock the Rx queue via iwl4965_rx_queue_restock. - * This is called as a scheduled work item (except for during initialization) - */ -static void iwl4965_rx_allocate(struct iwl_priv *priv) -{ - struct iwl4965_rx_queue *rxq = &priv->rxq; - struct list_head *element; - struct iwl4965_rx_mem_buffer *rxb; - unsigned long flags; - spin_lock_irqsave(&rxq->lock, flags); - while (!list_empty(&rxq->rx_used)) { - element = rxq->rx_used.next; - rxb = list_entry(element, struct iwl4965_rx_mem_buffer, list); - - /* Alloc a new receive buffer */ - rxb->skb = - alloc_skb(priv->hw_params.rx_buf_size, - __GFP_NOWARN | GFP_ATOMIC); - if (!rxb->skb) { - if (net_ratelimit()) - printk(KERN_CRIT DRV_NAME - ": Can not allocate SKB buffers\n"); - /* We don't reschedule replenish work here -- we will - * call the restock method and if it still needs - * more buffers it will schedule replenish */ - break; - } - priv->alloc_rxb_skb++; - list_del(element); - - /* Get physical address of RB/SKB */ - rxb->dma_addr = - pci_map_single(priv->pci_dev, rxb->skb->data, - priv->hw_params.rx_buf_size, PCI_DMA_FROMDEVICE); - list_add_tail(&rxb->list, &rxq->rx_free); - rxq->free_count++; - } - spin_unlock_irqrestore(&rxq->lock, flags); -} - /* * this should be called while priv->lock is locked */ -static void __iwl4965_rx_replenish(void *data) -{ - struct iwl_priv *priv = data; - - iwl4965_rx_allocate(priv); - iwl4965_rx_queue_restock(priv); -} - - -void iwl4965_rx_replenish(void *data) -{ - struct iwl_priv *priv = data; - unsigned long flags; - - iwl4965_rx_allocate(priv); - - spin_lock_irqsave(&priv->lock, flags); - iwl4965_rx_queue_restock(priv); - spin_unlock_irqrestore(&priv->lock, flags); -} - -/* Assumes that the skb field of the buffers in 'pool' is kept accurate. - * If an SKB has been detached, the POOL needs to have its SKB set to NULL - * This free routine walks the list of POOL entries and if SKB is set to - * non NULL it is unmapped and freed - */ -static void iwl4965_rx_queue_free(struct iwl_priv *priv, struct iwl4965_rx_queue *rxq) -{ - int i; - for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) { - if (rxq->pool[i].skb != NULL) { - pci_unmap_single(priv->pci_dev, - rxq->pool[i].dma_addr, - priv->hw_params.rx_buf_size, - PCI_DMA_FROMDEVICE); - dev_kfree_skb(rxq->pool[i].skb); - } - } - - pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd, - rxq->dma_addr); - rxq->bd = NULL; -} - -int iwl4965_rx_queue_alloc(struct iwl_priv *priv) -{ - struct iwl4965_rx_queue *rxq = &priv->rxq; - struct pci_dev *dev = priv->pci_dev; - int i; - - spin_lock_init(&rxq->lock); - INIT_LIST_HEAD(&rxq->rx_free); - INIT_LIST_HEAD(&rxq->rx_used); - - /* Alloc the circular buffer of Read Buffer Descriptors (RBDs) */ - rxq->bd = pci_alloc_consistent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr); - if (!rxq->bd) - return -ENOMEM; - - /* Fill the rx_used queue with _all_ of the Rx buffers */ - for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) - list_add_tail(&rxq->pool[i].list, &rxq->rx_used); - - /* Set us so that we have processed and used all buffers, but have - * not restocked the Rx queue with fresh buffers */ - rxq->read = rxq->write = 0; - rxq->free_count = 0; - rxq->need_update = 0; - return 0; -} - -void iwl4965_rx_queue_reset(struct iwl_priv *priv, struct iwl4965_rx_queue *rxq) -{ - unsigned long flags; - int i; - spin_lock_irqsave(&rxq->lock, flags); - INIT_LIST_HEAD(&rxq->rx_free); - INIT_LIST_HEAD(&rxq->rx_used); - /* Fill the rx_used queue with _all_ of the Rx buffers */ - for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) { - /* In the reset function, these buffers may have been allocated - * to an SKB, so we need to unmap and free potential storage */ - if (rxq->pool[i].skb != NULL) { - pci_unmap_single(priv->pci_dev, - rxq->pool[i].dma_addr, - priv->hw_params.rx_buf_size, - PCI_DMA_FROMDEVICE); - priv->alloc_rxb_skb--; - dev_kfree_skb(rxq->pool[i].skb); - rxq->pool[i].skb = NULL; - } - list_add_tail(&rxq->pool[i].list, &rxq->rx_used); - } - - /* Set us so that we have processed and used all buffers, but have - * not restocked the Rx queue with fresh buffers */ - rxq->read = rxq->write = 0; - rxq->free_count = 0; - spin_unlock_irqrestore(&rxq->lock, flags); -} - -/* Convert linear signal-to-noise ratio into dB */ -static u8 ratio2dB[100] = { -/* 0 1 2 3 4 5 6 7 8 9 */ - 0, 0, 6, 10, 12, 14, 16, 17, 18, 19, /* 00 - 09 */ - 20, 21, 22, 22, 23, 23, 24, 25, 26, 26, /* 10 - 19 */ - 26, 26, 26, 27, 27, 28, 28, 28, 29, 29, /* 20 - 29 */ - 29, 30, 30, 30, 31, 31, 31, 31, 32, 32, /* 30 - 39 */ - 32, 32, 32, 33, 33, 33, 33, 33, 34, 34, /* 40 - 49 */ - 34, 34, 34, 34, 35, 35, 35, 35, 35, 35, /* 50 - 59 */ - 36, 36, 36, 36, 36, 36, 36, 37, 37, 37, /* 60 - 69 */ - 37, 37, 37, 37, 37, 38, 38, 38, 38, 38, /* 70 - 79 */ - 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, /* 80 - 89 */ - 39, 39, 39, 39, 39, 40, 40, 40, 40, 40 /* 90 - 99 */ -}; - -/* Calculates a relative dB value from a ratio of linear - * (i.e. not dB) signal levels. - * Conversion assumes that levels are voltages (20*log), not powers (10*log). */ -int iwl4965_calc_db_from_ratio(int sig_ratio) +static void __iwl_rx_replenish(struct iwl_priv *priv) { - /* 1000:1 or higher just report as 60 dB */ - if (sig_ratio >= 1000) - return 60; - - /* 100:1 or higher, divide by 10 and use table, - * add 20 dB to make up for divide by 10 */ - if (sig_ratio >= 100) - return (20 + (int)ratio2dB[sig_ratio/10]); - - /* We shouldn't see this */ - if (sig_ratio < 1) - return 0; - - /* Use table for ratios 1:1 - 99:1 */ - return (int)ratio2dB[sig_ratio]; + iwl_rx_allocate(priv); + iwl_rx_queue_restock(priv); } -#define PERFECT_RSSI (-20) /* dBm */ -#define WORST_RSSI (-95) /* dBm */ -#define RSSI_RANGE (PERFECT_RSSI - WORST_RSSI) - -/* Calculate an indication of rx signal quality (a percentage, not dBm!). - * See http://www.ces.clemson.edu/linux/signal_quality.shtml for info - * about formulas used below. */ -int iwl4965_calc_sig_qual(int rssi_dbm, int noise_dbm) -{ - int sig_qual; - int degradation = PERFECT_RSSI - rssi_dbm; - - /* If we get a noise measurement, use signal-to-noise ratio (SNR) - * as indicator; formula is (signal dbm - noise dbm). - * SNR at or above 40 is a great signal (100%). - * Below that, scale to fit SNR of 0 - 40 dB within 0 - 100% indicator. - * Weakest usable signal is usually 10 - 15 dB SNR. */ - if (noise_dbm) { - if (rssi_dbm - noise_dbm >= 40) - return 100; - else if (rssi_dbm < noise_dbm) - return 0; - sig_qual = ((rssi_dbm - noise_dbm) * 5) / 2; - - /* Else use just the signal level. - * This formula is a least squares fit of data points collected and - * compared with a reference system that had a percentage (%) display - * for signal quality. */ - } else - sig_qual = (100 * (RSSI_RANGE * RSSI_RANGE) - degradation * - (15 * RSSI_RANGE + 62 * degradation)) / - (RSSI_RANGE * RSSI_RANGE); - - if (sig_qual > 100) - sig_qual = 100; - else if (sig_qual < 1) - sig_qual = 0; - - return sig_qual; -} /** - * iwl4965_rx_handle - Main entry function for receiving responses from uCode + * iwl_rx_handle - Main entry function for receiving responses from uCode * * Uses the priv->rx_handlers callback function array to invoke * the appropriate handlers, including command responses, * frame-received notifications, and other notifications. */ -static void iwl4965_rx_handle(struct iwl_priv *priv) +void iwl_rx_handle(struct iwl_priv *priv) { - struct iwl4965_rx_mem_buffer *rxb; + struct iwl_rx_mem_buffer *rxb; struct iwl4965_rx_packet *pkt; - struct iwl4965_rx_queue *rxq = &priv->rxq; + struct iwl_rx_queue *rxq = &priv->rxq; u32 r, i; int reclaim; unsigned long flags; @@ -3725,7 +3315,7 @@ static void iwl4965_rx_handle(struct iwl_priv *priv) if (i == r) IWL_DEBUG(IWL_DL_RX | IWL_DL_ISR, "r = %d, i = %d\n", r, i); - if (iwl4965_rx_queue_space(rxq) > (RX_QUEUE_SIZE / 2)) + if (iwl_rx_queue_space(rxq) > (RX_QUEUE_SIZE / 2)) fill_rx = 1; while (i != r) { @@ -3804,7 +3394,7 @@ static void iwl4965_rx_handle(struct iwl_priv *priv) count++; if (count >= 8) { priv->rxq.read = i; - __iwl4965_rx_replenish(priv); + __iwl_rx_replenish(priv); count = 0; } } @@ -3812,7 +3402,84 @@ static void iwl4965_rx_handle(struct iwl_priv *priv) /* Backtrack one entry */ priv->rxq.read = i; - iwl4965_rx_queue_restock(priv); + iwl_rx_queue_restock(priv); +} +/* Convert linear signal-to-noise ratio into dB */ +static u8 ratio2dB[100] = { +/* 0 1 2 3 4 5 6 7 8 9 */ + 0, 0, 6, 10, 12, 14, 16, 17, 18, 19, /* 00 - 09 */ + 20, 21, 22, 22, 23, 23, 24, 25, 26, 26, /* 10 - 19 */ + 26, 26, 26, 27, 27, 28, 28, 28, 29, 29, /* 20 - 29 */ + 29, 30, 30, 30, 31, 31, 31, 31, 32, 32, /* 30 - 39 */ + 32, 32, 32, 33, 33, 33, 33, 33, 34, 34, /* 40 - 49 */ + 34, 34, 34, 34, 35, 35, 35, 35, 35, 35, /* 50 - 59 */ + 36, 36, 36, 36, 36, 36, 36, 37, 37, 37, /* 60 - 69 */ + 37, 37, 37, 37, 37, 38, 38, 38, 38, 38, /* 70 - 79 */ + 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, /* 80 - 89 */ + 39, 39, 39, 39, 39, 40, 40, 40, 40, 40 /* 90 - 99 */ +}; + +/* Calculates a relative dB value from a ratio of linear + * (i.e. not dB) signal levels. + * Conversion assumes that levels are voltages (20*log), not powers (10*log). */ +int iwl4965_calc_db_from_ratio(int sig_ratio) +{ + /* 1000:1 or higher just report as 60 dB */ + if (sig_ratio >= 1000) + return 60; + + /* 100:1 or higher, divide by 10 and use table, + * add 20 dB to make up for divide by 10 */ + if (sig_ratio >= 100) + return (20 + (int)ratio2dB[sig_ratio/10]); + + /* We shouldn't see this */ + if (sig_ratio < 1) + return 0; + + /* Use table for ratios 1:1 - 99:1 */ + return (int)ratio2dB[sig_ratio]; +} + +#define PERFECT_RSSI (-20) /* dBm */ +#define WORST_RSSI (-95) /* dBm */ +#define RSSI_RANGE (PERFECT_RSSI - WORST_RSSI) + +/* Calculate an indication of rx signal quality (a percentage, not dBm!). + * See http://www.ces.clemson.edu/linux/signal_quality.shtml for info + * about formulas used below. */ +int iwl4965_calc_sig_qual(int rssi_dbm, int noise_dbm) +{ + int sig_qual; + int degradation = PERFECT_RSSI - rssi_dbm; + + /* If we get a noise measurement, use signal-to-noise ratio (SNR) + * as indicator; formula is (signal dbm - noise dbm). + * SNR at or above 40 is a great signal (100%). + * Below that, scale to fit SNR of 0 - 40 dB within 0 - 100% indicator. + * Weakest usable signal is usually 10 - 15 dB SNR. */ + if (noise_dbm) { + if (rssi_dbm - noise_dbm >= 40) + return 100; + else if (rssi_dbm < noise_dbm) + return 0; + sig_qual = ((rssi_dbm - noise_dbm) * 5) / 2; + + /* Else use just the signal level. + * This formula is a least squares fit of data points collected and + * compared with a reference system that had a percentage (%) display + * for signal quality. */ + } else + sig_qual = (100 * (RSSI_RANGE * RSSI_RANGE) - degradation * + (15 * RSSI_RANGE + 62 * degradation)) / + (RSSI_RANGE * RSSI_RANGE); + + if (sig_qual > 100) + sig_qual = 100; + else if (sig_qual < 1) + sig_qual = 0; + + return sig_qual; } /** @@ -4248,7 +3915,7 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv) /* uCode wakes up after power-down sleep */ if (inta & CSR_INT_BIT_WAKEUP) { IWL_DEBUG_ISR("Wakeup interrupt\n"); - iwl4965_rx_queue_update_write_ptr(priv, &priv->rxq); + iwl_rx_queue_update_write_ptr(priv, &priv->rxq); iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[0]); iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[1]); iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[2]); @@ -4263,7 +3930,7 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv) * Rx "responses" (frame-received notification), and other * notifications from uCode come through here*/ if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { - iwl4965_rx_handle(priv); + iwl_rx_handle(priv); handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); } @@ -5452,7 +5119,7 @@ static void iwl4965_bg_rx_replenish(struct work_struct *data) return; mutex_lock(&priv->mutex); - iwl4965_rx_replenish(priv); + iwl_rx_replenish(priv); mutex_unlock(&priv->mutex); } @@ -7309,7 +6976,7 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) iwl4965_dealloc_ucode_pci(priv); if (priv->rxq.bd) - iwl4965_rx_queue_free(priv, &priv->rxq); + iwl_rx_queue_free(priv, &priv->rxq); iwl4965_hw_txq_ctx_free(priv); iwlcore_clear_stations_table(priv); -- cgit v1.2.3-70-g09d2 From 5a835353fb3c68a3da3badcc485614cdfc6e6109 Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Mon, 5 May 2008 10:22:29 +0800 Subject: iwlwifi-5000: rename iwl5000_init_nic to iwl5000_init_config Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 0d8ef63f871..83ed69dfac6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -86,7 +86,7 @@ static int iwl5000_apm_init(struct iwl_priv *priv) return ret; } -static void iwl5000_nic_init(struct iwl_priv *priv) +static void iwl5000_nic_config(struct iwl_priv *priv) { unsigned long flags; u16 radio_cfg; @@ -439,7 +439,7 @@ static struct iwl_lib_ops iwl5000_lib = { .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, .apm_ops = { .init = iwl5000_apm_init, - .config = iwl5000_nic_init, + .config = iwl5000_nic_config, .set_pwr_src = iwl4965_set_pwr_src, }, .eeprom_ops = { -- cgit v1.2.3-70-g09d2 From 6b9b34389c2fdb8618fe2c686b6872d26562fd07 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Mon, 5 May 2008 10:22:30 +0800 Subject: iwlwifi: don't override association channel with control channel This patch fixes override of association channel with HT control channel. The scenario is currently happening because disassociation flow doesn't clean previous association information (such as is_ht and control channel). Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 773bb3229cf..6eca75717f3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -3775,10 +3775,10 @@ void iwl4965_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) RXON_FLG_CHANNEL_MODE_PURE_40_MSK); if (le16_to_cpu(rxon->channel) != ht_info->control_channel) { - IWL_DEBUG_ASSOC("control diff than current %d %d\n", + IWL_ERROR("control diff than current %d %d\n", le16_to_cpu(rxon->channel), ht_info->control_channel); - rxon->channel = cpu_to_le16(ht_info->control_channel); + WARN_ON(1); return; } -- cgit v1.2.3-70-g09d2 From 6def9761f72501e638e79eebcd70afea12a3a93d Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Mon, 5 May 2008 10:22:31 +0800 Subject: iwlwifi: remove 4965 from station_entry This patch removes 4965 mark form the station entry structure. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 10 +++++----- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 2 +- drivers/net/wireless/iwlwifi/iwl-dev.h | 18 +++++++++--------- drivers/net/wireless/iwlwifi/iwl-sta.c | 2 +- drivers/net/wireless/iwlwifi/iwl4965-base.c | 8 ++++---- 5 files changed, 20 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 6eca75717f3..bd9d5ff7392 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -3333,7 +3333,7 @@ static void iwl4965_sta_modify_enable_tid_tx(struct iwl_priv *priv, * ACK vs. not. This gets sent to mac80211, then to rate scaling algo. */ static int iwl4965_tx_status_reply_compressed_ba(struct iwl_priv *priv, - struct iwl4965_ht_agg *agg, + struct iwl_ht_agg *agg, struct iwl4965_compressed_ba_resp* ba_resp) @@ -3450,7 +3450,7 @@ int iwl4965_check_empty_hw_queue(struct iwl_priv *priv, int sta_id, { struct iwl4965_queue *q = &priv->txq[txq_id].q; u8 *addr = priv->stations[sta_id].sta.sta.addr; - struct iwl4965_tid_data *tid_data = &priv->stations[sta_id].tid[tid]; + struct iwl_tid_data *tid_data = &priv->stations[sta_id].tid[tid]; switch (priv->stations[sta_id].tid[tid].agg.state) { case IWL_EMPTYING_HW_QUEUE_DELBA: @@ -3502,7 +3502,7 @@ static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv, struct iwl4965_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba; int index; struct iwl4965_tx_queue *txq = NULL; - struct iwl4965_ht_agg *agg; + struct iwl_ht_agg *agg; DECLARE_MAC_BUF(mac); /* "flow" corresponds to Tx queue */ @@ -3929,7 +3929,7 @@ static int iwl4965_tx_agg_start(struct ieee80211_hw *hw, const u8 *ra, int ssn = -1; int ret = 0; unsigned long flags; - struct iwl4965_tid_data *tid_data; + struct iwl_tid_data *tid_data; DECLARE_MAC_BUF(mac); if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo))) @@ -3982,7 +3982,7 @@ static int iwl4965_tx_agg_stop(struct ieee80211_hw *hw, const u8 *ra, u16 tid) { struct iwl_priv *priv = hw->priv; int tx_fifo_id, txq_id, sta_id, ssn = -1; - struct iwl4965_tid_data *tid_data; + struct iwl_tid_data *tid_data; int ret, write_ptr, read_ptr; unsigned long flags; DECLARE_MAC_BUF(mac); diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 30914453de1..37b52e63739 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -206,7 +206,7 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct iwl_priv *priv = (struct iwl_priv *)file->private_data; - struct iwl4965_station_entry *station; + struct iwl_station_entry *station; int max_sta = priv->hw_params.max_stations; char *buf; int i, j, pos = 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 1d80ad79114..07eff75786b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -401,7 +401,7 @@ struct iwl_rx_queue { #ifdef CONFIG_IWL4965_HT /** - * struct iwl4965_ht_agg -- aggregation status while waiting for block-ack + * struct iwl_ht_agg -- aggregation status while waiting for block-ack * @txq_id: Tx queue used for Tx attempt * @frame_count: # frames attempted by Tx command * @wait_for_ba: Expect block-ack before next Tx reply @@ -414,7 +414,7 @@ struct iwl_rx_queue { * for block ack (REPLY_COMPRESSED_BA). This struct stores tx reply info * until block ack arrives. */ -struct iwl4965_ht_agg { +struct iwl_ht_agg { u16 txq_id; u16 frame_count; u16 wait_for_ba; @@ -430,15 +430,15 @@ struct iwl4965_ht_agg { #endif /* CONFIG_IWL4965_HT */ -struct iwl4965_tid_data { +struct iwl_tid_data { u16 seq_number; u16 tfds_in_queue; #ifdef CONFIG_IWL4965_HT - struct iwl4965_ht_agg agg; + struct iwl_ht_agg agg; #endif /* CONFIG_IWL4965_HT */ }; -struct iwl4965_hw_key { +struct iwl_hw_key { enum ieee80211_key_alg alg; int keylen; u8 keyidx; @@ -510,12 +510,12 @@ struct iwl4965_qos_info { #define STA_PS_STATUS_WAKE 0 #define STA_PS_STATUS_SLEEP 1 -struct iwl4965_station_entry { +struct iwl_station_entry { struct iwl4965_addsta_cmd sta; - struct iwl4965_tid_data tid[MAX_TID_COUNT]; + struct iwl_tid_data tid[MAX_TID_COUNT]; u8 used; u8 ps_status; - struct iwl4965_hw_key keyinfo; + struct iwl_hw_key keyinfo; }; /* one for each uCode image (inst/data, boot/init/runtime) */ @@ -1107,7 +1107,7 @@ struct iwl_priv { /*station table variables */ spinlock_t sta_lock; int num_stations; - struct iwl4965_station_entry stations[IWL_STATION_COUNT]; + struct iwl_station_entry stations[IWL_STATION_COUNT]; struct iwl_wep_key wep_keys[WEP_KEYS_MAX]; u8 default_wep_key; u8 key_mapping_key; diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 31b37a1a643..0148d49e0b5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -333,7 +333,7 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv, IWL_ERROR("index %d not used in uCode key table.\n", priv->stations[sta_id].sta.key.key_offset); memset(&priv->stations[sta_id].keyinfo, 0, - sizeof(struct iwl4965_hw_key)); + sizeof(struct iwl_hw_key)); memset(&priv->stations[sta_id].sta.key, 0, sizeof(struct iwl4965_keyinfo)); priv->stations[sta_id].sta.key.key_flags = diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index aa0393589da..50757ff66ba 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -433,7 +433,7 @@ u8 iwl4965_add_station_flags(struct iwl_priv *priv, const u8 *addr, { int i; int index = IWL_INVALID_STATION; - struct iwl4965_station_entry *station; + struct iwl_station_entry *station; unsigned long flags_spin; DECLARE_MAC_BUF(mac); @@ -1783,7 +1783,7 @@ static void iwl4965_build_tx_cmd_hwcrypto(struct iwl_priv *priv, struct sk_buff *skb_frag, int sta_id) { - struct iwl4965_hw_key *keyinfo = &priv->stations[sta_id].keyinfo; + struct iwl_hw_key *keyinfo = &priv->stations[sta_id].keyinfo; struct iwl_wep_key *wepkey; int keyidx = 0; @@ -2617,7 +2617,7 @@ static inline u32 iwl4965_get_scd_ssn(struct iwl4965_tx_resp *tx_resp) * iwl4965_tx_status_reply_tx - Handle Tx rspnse for frames in aggregation queue */ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv, - struct iwl4965_ht_agg *agg, + struct iwl_ht_agg *agg, struct iwl4965_tx_resp_agg *tx_resp, u16 start_idx) { @@ -2775,7 +2775,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, if (txq->sched_retry) { const u32 scd_ssn = iwl4965_get_scd_ssn(tx_resp); - struct iwl4965_ht_agg *agg = NULL; + struct iwl_ht_agg *agg = NULL; if (!qc) return; -- cgit v1.2.3-70-g09d2 From 8dd266ef4eb51d034fa1c5f9307a9ff07547d8e6 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Mon, 5 May 2008 10:22:32 +0800 Subject: iwlwifi: debugfs EEPROM dump This patch adds EEPROM dump in debugfs. Signed-off-by: Tomas Winkler Signed-off-by: Abhijeet Kolekar Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-debug.h | 1 + drivers/net/wireless/iwlwifi/iwl-debugfs.c | 42 ++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index c60724c21db..7e68d24114f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -57,6 +57,7 @@ struct iwl_debugfs { struct dentry *dir_data; struct dir_data_files{ struct dentry *file_sram; + struct dentry *file_eeprom; struct dentry *file_stations; struct dentry *file_rx_statistics; struct dentry *file_tx_statistics; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 37b52e63739..ad25806dfaf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -277,8 +277,48 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, return ret; } +static ssize_t iwl_dbgfs_eeprom_read(struct file *file, + char __user *user_buf, + size_t count, + loff_t *ppos) +{ + ssize_t ret; + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + int pos = 0, ofs = 0, buf_size = 0; + const u8 *ptr; + char *buf; + size_t eeprom_len = priv->cfg->eeprom_size; + buf_size = 4 * eeprom_len + 256; + + if (eeprom_len % 16) { + IWL_ERROR("EEPROM size is not multiple of 16.\n"); + return -ENODATA; + } + + /* 4 characters for byte 0xYY */ + buf = kzalloc(buf_size, GFP_KERNEL); + if (!buf) { + IWL_ERROR("Can not allocate Buffer\n"); + return -ENOMEM; + } + + ptr = priv->eeprom; + for (ofs = 0 ; ofs < eeprom_len ; ofs += 16) { + pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x ", ofs); + hex_dump_to_buffer(ptr + ofs, 16 , 16, 2, buf + pos, + buf_size - pos, 0); + pos += strlen(buf); + if (buf_size - pos > 0) + buf[pos++] = '\n'; + } + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} DEBUGFS_READ_WRITE_FILE_OPS(sram); +DEBUGFS_READ_FILE_OPS(eeprom); DEBUGFS_READ_FILE_OPS(stations); DEBUGFS_READ_FILE_OPS(rx_statistics); DEBUGFS_READ_FILE_OPS(tx_statistics); @@ -304,6 +344,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) } DEBUGFS_ADD_DIR(data, dbgfs->dir_drv); + DEBUGFS_ADD_FILE(eeprom, data); DEBUGFS_ADD_FILE(sram, data); DEBUGFS_ADD_FILE(stations, data); DEBUGFS_ADD_FILE(rx_statistics, data); @@ -327,6 +368,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) if (!(priv->dbgfs)) return; + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_eeprom); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_rx_statistics); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_tx_statistics); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sram); -- cgit v1.2.3-70-g09d2 From db11d6343aa14ab61258bfad9178042d4be49333 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Mon, 5 May 2008 10:22:33 +0800 Subject: iwlwifi: remove 4965 from rx_packet This patch removes 4965 mark from rx_packet. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 16 ++++----- drivers/net/wireless/iwlwifi/iwl-commands.h | 2 +- drivers/net/wireless/iwlwifi/iwl-hcmd.c | 4 +-- drivers/net/wireless/iwlwifi/iwl4965-base.c | 56 ++++++++++++++--------------- 4 files changed, 39 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index bd9d5ff7392..f7e267e30ce 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2519,7 +2519,7 @@ static void iwl4965_rx_calc_noise(struct iwl_priv *priv) void iwl4965_hw_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; int change; s32 temp; @@ -2807,7 +2807,7 @@ static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data, struct iwl_rx_mem_buffer *rxb, struct ieee80211_rx_status *stats) { - struct iwl4965_rx_packet *pkt = (struct iwl4965_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl4965_rx_phy_res *rx_start = (include_phy) ? (struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) : NULL; struct ieee80211_hdr *hdr; @@ -2964,7 +2964,7 @@ static void iwl4965_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr) * proper operation with 4965. */ static void iwl4965_dbg_report_frame(struct iwl_priv *priv, - struct iwl4965_rx_packet *pkt, + struct iwl_rx_packet *pkt, struct ieee80211_hdr *header, int group100) { u32 to_us; @@ -3098,7 +3098,7 @@ static void iwl4965_dbg_report_frame(struct iwl_priv *priv, } #else static inline void iwl4965_dbg_report_frame(struct iwl_priv *priv, - struct iwl4965_rx_packet *pkt, + struct iwl_rx_packet *pkt, struct ieee80211_hdr *header, int group100) { @@ -3114,7 +3114,7 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv, { struct ieee80211_hdr *header; struct ieee80211_rx_status rx_status; - struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; /* Use phy data (Rx signal strength, etc.) contained within * this rx packet for legacy frames, * or phy data cached from REPLY_RX_PHY_CMD for HT frames. */ @@ -3281,7 +3281,7 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv, static void iwl4965_rx_reply_rx_phy(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; priv->last_phy_res[0] = 1; memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]), sizeof(struct iwl4965_rx_phy_res)); @@ -3291,7 +3291,7 @@ static void iwl4965_rx_missed_beacon_notif(struct iwl_priv *priv, { #ifdef CONFIG_IWL4965_RUN_TIME_CALIB - struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl4965_missed_beacon_notif *missed_beacon; missed_beacon = &pkt->u.missed_beacon; @@ -3498,7 +3498,7 @@ static inline int iwl4965_queue_dec_wrap(int index, int n_bd) static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl4965_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba; int index; struct iwl4965_tx_queue *txq = NULL; diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 5afa7b79b59..e5449b8c335 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -2731,7 +2731,7 @@ struct iwl4965_led_cmd { * *****************************************************************************/ -struct iwl4965_rx_packet { +struct iwl_rx_packet { __le32 len; struct iwl_cmd_header hdr; union { diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index acb5a8abd78..0412adf6ef8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -101,7 +101,7 @@ EXPORT_SYMBOL(get_cmd_string); static int iwl_generic_cmd_callback(struct iwl_priv *priv, struct iwl_cmd *cmd, struct sk_buff *skb) { - struct iwl4965_rx_packet *pkt = NULL; + struct iwl_rx_packet *pkt = NULL; if (!skb) { IWL_ERROR("Error: Response NULL in %s.\n", @@ -109,7 +109,7 @@ static int iwl_generic_cmd_callback(struct iwl_priv *priv, return 1; } - pkt = (struct iwl4965_rx_packet *)skb->data; + pkt = (struct iwl_rx_packet *)skb->data; if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERROR("Bad return from %s (0x%08X)\n", get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags); diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 50757ff66ba..5b9cbbd197f 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -902,8 +902,8 @@ static int iwl4965_send_bt_config(struct iwl_priv *priv) static int iwl4965_send_scan_abort(struct iwl_priv *priv) { - int rc = 0; - struct iwl4965_rx_packet *res; + int ret = 0; + struct iwl_rx_packet *res; struct iwl_host_cmd cmd = { .id = REPLY_SCAN_ABORT_CMD, .meta.flags = CMD_WANT_SKB, @@ -917,13 +917,13 @@ static int iwl4965_send_scan_abort(struct iwl_priv *priv) return 0; } - rc = iwl_send_cmd_sync(priv, &cmd); - if (rc) { + ret = iwl_send_cmd_sync(priv, &cmd); + if (ret) { clear_bit(STATUS_SCAN_ABORTING, &priv->status); - return rc; + return ret; } - res = (struct iwl4965_rx_packet *)cmd.meta.u.skb->data; + res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; if (res->u.status != CAN_ABORT_STATUS) { /* The scan abort will return 1 for success or * 2 for "failure". A failure condition can be @@ -938,7 +938,7 @@ static int iwl4965_send_scan_abort(struct iwl_priv *priv) dev_kfree_skb_any(cmd.meta.u.skb); - return rc; + return ret; } /* @@ -966,7 +966,7 @@ static int iwl4965_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_fla int iwl4965_send_add_station(struct iwl_priv *priv, struct iwl4965_addsta_cmd *sta, u8 flags) { - struct iwl4965_rx_packet *res = NULL; + struct iwl_rx_packet *res = NULL; int rc = 0; struct iwl_host_cmd cmd = { .id = REPLY_ADD_STA, @@ -983,7 +983,7 @@ int iwl4965_send_add_station(struct iwl_priv *priv, if (rc || (flags & CMD_ASYNC)) return rc; - res = (struct iwl4965_rx_packet *)cmd.meta.u.skb->data; + res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; if (res->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n", res->hdr.flags); @@ -2441,7 +2441,7 @@ static int iwl4965_get_measurement(struct iwl_priv *priv, u8 type) { struct iwl4965_spectrum_cmd spectrum; - struct iwl4965_rx_packet *res; + struct iwl_rx_packet *res; struct iwl_host_cmd cmd = { .id = REPLY_SPECTRUM_MEASUREMENT_CMD, .data = (void *)&spectrum, @@ -2486,7 +2486,7 @@ static int iwl4965_get_measurement(struct iwl_priv *priv, if (rc) return rc; - res = (struct iwl4965_rx_packet *)cmd.meta.u.skb->data; + res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; if (res->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERROR("Bad return from REPLY_RX_ON_ASSOC command\n"); rc = -EIO; @@ -2738,7 +2738,7 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv, static void iwl4965_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; u16 sequence = le16_to_cpu(pkt->hdr.sequence); int txq_id = SEQ_TO_QUEUE(sequence); int index = SEQ_TO_INDEX(sequence); @@ -2851,7 +2851,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, static void iwl4965_rx_reply_alive(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl4965_alive_resp *palive; struct delayed_work *pwork; @@ -2887,7 +2887,7 @@ static void iwl4965_rx_reply_alive(struct iwl_priv *priv, static void iwl4965_rx_reply_add_sta(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; IWL_DEBUG_RX("Received REPLY_ADD_STA: 0x%02X\n", pkt->u.status); return; @@ -2896,7 +2896,7 @@ static void iwl4965_rx_reply_add_sta(struct iwl_priv *priv, static void iwl4965_rx_reply_error(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; IWL_ERROR("Error Reply type 0x%08X cmd %s (0x%02X) " "seq 0x%04X ser 0x%08X\n", @@ -2911,7 +2911,7 @@ static void iwl4965_rx_reply_error(struct iwl_priv *priv, static void iwl4965_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl4965_rxon_cmd *rxon = (void *)&priv->active_rxon; struct iwl4965_csa_notification *csa = &(pkt->u.csa_notif); IWL_DEBUG_11H("CSA notif: channel %d, status %d\n", @@ -2924,7 +2924,7 @@ static void iwl4965_rx_spectrum_measure_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { #ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT - struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl4965_spectrum_notification *report = &(pkt->u.spectrum_notif); if (!report->state) { @@ -2942,7 +2942,7 @@ static void iwl4965_rx_pm_sleep_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { #ifdef CONFIG_IWLWIFI_DEBUG - struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl4965_sleep_notification *sleep = &(pkt->u.sleep_notif); IWL_DEBUG_RX("sleep mode: %d, src: %d\n", sleep->pm_sleep_mode, sleep->pm_wakeup_src); @@ -2952,7 +2952,7 @@ static void iwl4965_rx_pm_sleep_notif(struct iwl_priv *priv, static void iwl4965_rx_pm_debug_statistics_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; IWL_DEBUG_RADIO("Dumping %d bytes of unhandled " "notification for %s:\n", le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd)); @@ -2988,7 +2988,7 @@ static void iwl4965_rx_beacon_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { #ifdef CONFIG_IWLWIFI_DEBUG - struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl4965_beacon_notif *beacon = &(pkt->u.beacon_status); u8 rate = iwl4965_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags); @@ -3011,7 +3011,7 @@ static void iwl4965_rx_reply_scan(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { #ifdef CONFIG_IWLWIFI_DEBUG - struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl4965_scanreq_notification *notif = (struct iwl4965_scanreq_notification *)pkt->u.raw; @@ -3023,7 +3023,7 @@ static void iwl4965_rx_reply_scan(struct iwl_priv *priv, static void iwl4965_rx_scan_start_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl4965_scanstart_notification *notif = (struct iwl4965_scanstart_notification *)pkt->u.raw; priv->scan_start_tsf = le32_to_cpu(notif->tsf_low); @@ -3040,7 +3040,7 @@ static void iwl4965_rx_scan_start_notif(struct iwl_priv *priv, static void iwl4965_rx_scan_results_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl4965_scanresults_notification *notif = (struct iwl4965_scanresults_notification *)pkt->u.raw; @@ -3065,7 +3065,7 @@ static void iwl4965_rx_scan_results_notif(struct iwl_priv *priv, static void iwl4965_rx_scan_complete_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl4965_scancomplete_notification *scan_notif = (void *)pkt->u.raw; IWL_DEBUG_SCAN("Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n", @@ -3123,7 +3123,7 @@ reschedule: static void iwl4965_rx_card_state_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags); unsigned long status = priv->status; @@ -3243,7 +3243,7 @@ static void iwl4965_setup_rx_handlers(struct iwl_priv *priv) static void iwl4965_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl4965_rx_packet *pkt = (struct iwl4965_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; u16 sequence = le16_to_cpu(pkt->hdr.sequence); int txq_id = SEQ_TO_QUEUE(sequence); int index = SEQ_TO_INDEX(sequence); @@ -3298,7 +3298,7 @@ static void __iwl_rx_replenish(struct iwl_priv *priv) void iwl_rx_handle(struct iwl_priv *priv) { struct iwl_rx_mem_buffer *rxb; - struct iwl4965_rx_packet *pkt; + struct iwl_rx_packet *pkt; struct iwl_rx_queue *rxq = &priv->rxq; u32 r, i; int reclaim; @@ -3331,7 +3331,7 @@ void iwl_rx_handle(struct iwl_priv *priv) pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr, priv->hw_params.rx_buf_size, PCI_DMA_FROMDEVICE); - pkt = (struct iwl4965_rx_packet *)rxb->skb->data; + pkt = (struct iwl_rx_packet *)rxb->skb->data; /* Reclaim a command buffer only if this packet is a response * to a (driver-originated) command. -- cgit v1.2.3-70-g09d2 From 133636deffc86809f59a0c8b768408d13237a9a2 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Mon, 5 May 2008 10:22:34 +0800 Subject: iwlwifi: generalize iwl4965_send_add_station function This patch moves iwl4965_send_add_station to iwlcore under new name iwl_send_add_sta. Function uses build command handler in order to support multiple HWs. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 28 ++++++++++++--- drivers/net/wireless/iwlwifi/iwl-commands.h | 46 ++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-core.h | 1 + drivers/net/wireless/iwlwifi/iwl-dev.h | 10 +++--- drivers/net/wireless/iwlwifi/iwl-sta.c | 54 ++++++++++++++++++++++++++--- drivers/net/wireless/iwlwifi/iwl4965-base.c | 51 ++------------------------- 6 files changed, 127 insertions(+), 63 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index f7e267e30ce..0644e22fe78 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2931,7 +2931,7 @@ static void iwl4965_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; spin_unlock_irqrestore(&priv->sta_lock, flags); - iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC); + iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); } static void iwl4965_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr) @@ -3323,7 +3323,7 @@ static void iwl4965_sta_modify_enable_tid_tx(struct iwl_priv *priv, priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; spin_unlock_irqrestore(&priv->sta_lock, flags); - iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC); + iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); } /** @@ -3878,7 +3878,7 @@ static int iwl4965_rx_agg_start(struct iwl_priv *priv, priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; spin_unlock_irqrestore(&priv->sta_lock, flags); - return iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, + return iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); } @@ -3899,7 +3899,7 @@ static int iwl4965_rx_agg_stop(struct iwl_priv *priv, priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; spin_unlock_irqrestore(&priv->sta_lock, flags); - return iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, + return iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); } @@ -4064,9 +4064,26 @@ int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, } return 0; } - #endif /* CONFIG_IWL4965_HT */ + +static u16 iwl4965_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) +{ + struct iwl4965_addsta_cmd *addsta = (struct iwl4965_addsta_cmd *)data; + addsta->mode = cmd->mode; + memcpy(&addsta->sta, &cmd->sta, sizeof(struct sta_id_modify)); + memcpy(&addsta->key, &cmd->key, sizeof(struct iwl4965_keyinfo)); + addsta->station_flags = cmd->station_flags; + addsta->station_flags_msk = cmd->station_flags_msk; + addsta->tid_disable_tx = cmd->tid_disable_tx; + addsta->add_immediate_ba_tid = cmd->add_immediate_ba_tid; + addsta->remove_immediate_ba_tid = cmd->remove_immediate_ba_tid; + addsta->add_immediate_ba_ssn = cmd->add_immediate_ba_ssn; + addsta->reserved1 = __constant_cpu_to_le16(0); + addsta->reserved2 = __constant_cpu_to_le32(0); + + return (u16)sizeof(struct iwl4965_addsta_cmd); +} /* Set up 4965-specific Rx frame reply handlers */ static void iwl4965_rx_handler_setup(struct iwl_priv *priv) { @@ -4110,6 +4127,7 @@ static struct iwl_hcmd_ops iwl4965_hcmd = { static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = { .enqueue_hcmd = iwl4965_enqueue_hcmd, + .build_addsta_hcmd = iwl4965_build_addsta_hcmd, #ifdef CONFIG_IWL4965_RUN_TIME_CALIB .chain_noise_reset = iwl4965_chain_noise_reset, .gain_computation = iwl4965_gain_computation, diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index e5449b8c335..d16a853f376 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -769,6 +769,20 @@ struct iwl4965_keyinfo { u8 key[16]; /* 16-byte unicast decryption key */ } __attribute__ ((packed)); +/* 5000 */ +struct iwl_keyinfo { + __le16 key_flags; + u8 tkip_rx_tsc_byte2; /* TSC[2] for key mix ph1 detection */ + u8 reserved1; + __le16 tkip_rx_ttak[5]; /* 10-byte unicast TKIP TTAK */ + u8 key_offset; + u8 reserved2; + u8 key[16]; /* 16-byte unicast decryption key */ + __le64 tx_secur_seq_cnt; + __le64 hw_tkip_mic_rx_key; + __le64 hw_tkip_mic_tx_key; +} __attribute__ ((packed)); + /** * struct sta_id_modify * @addr[ETH_ALEN]: station's MAC address @@ -844,6 +858,38 @@ struct iwl4965_addsta_cmd { __le32 reserved2; } __attribute__ ((packed)); +/* 5000 */ +struct iwl_addsta_cmd { + u8 mode; /* 1: modify existing, 0: add new station */ + u8 reserved[3]; + struct sta_id_modify sta; + struct iwl_keyinfo key; + __le32 station_flags; /* STA_FLG_* */ + __le32 station_flags_msk; /* STA_FLG_* */ + + /* bit field to disable (1) or enable (0) Tx for Traffic ID (TID) + * 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 reserved1; + + /* TID for which to add block-ack support. + * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ + u8 add_immediate_ba_tid; + + /* TID for which to remove block-ack support. + * Set modify_mask bit STA_MODIFY_DELBA_TID_MSK to use this field. */ + u8 remove_immediate_ba_tid; + + /* Starting Sequence Number for added block-ack support. + * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ + __le16 add_immediate_ba_ssn; + + __le32 reserved2; +} __attribute__ ((packed)); + + #define ADD_STA_SUCCESS_MSK 0x1 #define ADD_STA_NO_ROOM_IN_TABLE 0x2 #define ADD_STA_NO_BLOCK_ACK_RESOURCE 0x4 diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 2356cadc1de..df27ee65015 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -87,6 +87,7 @@ struct iwl_hcmd_ops { }; struct iwl_hcmd_utils_ops { int (*enqueue_hcmd)(struct iwl_priv *priv, struct iwl_host_cmd *cmd); + u16 (*build_addsta_hcmd)(const struct iwl_addsta_cmd *cmd, u8 *data); #ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB void (*gain_computation)(struct iwl_priv *priv, u32 *average_noise, diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 07eff75786b..4786194c045 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -319,7 +319,7 @@ struct iwl_cmd { struct iwl_cmd_meta meta; /* driver data */ struct iwl_cmd_header hdr; /* uCode API */ union { - struct iwl4965_addsta_cmd addsta; + struct iwl_addsta_cmd addsta; struct iwl4965_led_cmd led; u32 flags; u8 val8; @@ -511,7 +511,7 @@ struct iwl4965_qos_info { #define STA_PS_STATUS_SLEEP 1 struct iwl_station_entry { - struct iwl4965_addsta_cmd sta; + struct iwl_addsta_cmd sta; struct iwl_tid_data tid[MAX_TID_COUNT]; u8 used; u8 ps_status; @@ -634,9 +634,9 @@ struct iwl_hw_params { * for use by iwl-*.c * *****************************************************************************/ -struct iwl4965_addsta_cmd; -extern int iwl4965_send_add_station(struct iwl_priv *priv, - struct iwl4965_addsta_cmd *sta, u8 flags); +struct iwl_addsta_cmd; +extern int iwl_send_add_sta(struct iwl_priv *priv, + struct iwl_addsta_cmd *sta, u8 flags); extern u8 iwl4965_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags, void *ht_data); extern int iwl4965_is_network_packet(struct iwl_priv *priv, diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 0148d49e0b5..34f54244ed2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -70,6 +70,52 @@ u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr) } EXPORT_SYMBOL(iwl_find_station); +int iwl_send_add_sta(struct iwl_priv *priv, + struct iwl_addsta_cmd *sta, u8 flags) +{ + struct iwl_rx_packet *res = NULL; + int ret = 0; + u8 data[sizeof(*sta)]; + struct iwl_host_cmd cmd = { + .id = REPLY_ADD_STA, + .meta.flags = flags, + .data = data, + }; + + if (!(flags & CMD_ASYNC)) + cmd.meta.flags |= CMD_WANT_SKB; + + cmd.len = priv->cfg->ops->utils->build_addsta_hcmd(sta, data); + ret = iwl_send_cmd(priv, &cmd); + + if (ret || (flags & CMD_ASYNC)) + return ret; + + res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n", + res->hdr.flags); + ret = -EIO; + } + + if (ret == 0) { + switch (res->u.add_sta.status) { + case ADD_STA_SUCCESS_MSK: + IWL_DEBUG_INFO("REPLY_ADD_STA PASSED\n"); + break; + default: + ret = -EIO; + IWL_WARNING("REPLY_ADD_STA failed\n"); + break; + } + } + + priv->alloc_rxb_skb--; + dev_kfree_skb_any(cmd.meta.u.skb); + + return ret; +} +EXPORT_SYMBOL(iwl_send_add_sta); int iwl_get_free_ucode_key_index(struct iwl_priv *priv) { @@ -216,8 +262,7 @@ static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv, priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; - ret = iwl4965_send_add_station(priv, - &priv->stations[sta_id].sta, CMD_ASYNC); + ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); spin_unlock_irqrestore(&priv->sta_lock, flags); @@ -265,8 +310,7 @@ static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv, spin_unlock_irqrestore(&priv->sta_lock, flags); IWL_DEBUG_INFO("hwcrypto: modify ucode station key info\n"); - return iwl4965_send_add_station(priv, - &priv->stations[sta_id].sta, CMD_ASYNC); + return iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); } static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv, @@ -343,7 +387,7 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv, priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n"); - ret = iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, 0); + ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, 0); spin_unlock_irqrestore(&priv->sta_lock, flags); return ret; } diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 5b9cbbd197f..8427bc9a9bb 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -476,7 +476,7 @@ u8 iwl4965_add_station_flags(struct iwl_priv *priv, const u8 *addr, priv->num_stations++; /* Set up the REPLY_ADD_STA command to send to device */ - memset(&station->sta, 0, sizeof(struct iwl4965_addsta_cmd)); + memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd)); memcpy(station->sta.sta.addr, addr, ETH_ALEN); station->sta.mode = 0; station->sta.sta.sta_id = index; @@ -493,7 +493,7 @@ u8 iwl4965_add_station_flags(struct iwl_priv *priv, const u8 *addr, spin_unlock_irqrestore(&priv->sta_lock, flags_spin); /* Add station to device's station table */ - iwl4965_send_add_station(priv, &station->sta, flags); + iwl_send_add_sta(priv, &station->sta, flags); return index; } @@ -963,51 +963,6 @@ static int iwl4965_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_fla return iwl_send_cmd(priv, &cmd); } -int iwl4965_send_add_station(struct iwl_priv *priv, - struct iwl4965_addsta_cmd *sta, u8 flags) -{ - struct iwl_rx_packet *res = NULL; - int rc = 0; - struct iwl_host_cmd cmd = { - .id = REPLY_ADD_STA, - .len = sizeof(struct iwl4965_addsta_cmd), - .meta.flags = flags, - .data = sta, - }; - - if (!(flags & CMD_ASYNC)) - cmd.meta.flags |= CMD_WANT_SKB; - - rc = iwl_send_cmd(priv, &cmd); - - if (rc || (flags & CMD_ASYNC)) - return rc; - - res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; - if (res->hdr.flags & IWL_CMD_FAILED_MSK) { - IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n", - res->hdr.flags); - rc = -EIO; - } - - if (rc == 0) { - switch (res->u.add_sta.status) { - case ADD_STA_SUCCESS_MSK: - IWL_DEBUG_INFO("REPLY_ADD_STA PASSED\n"); - break; - default: - rc = -EIO; - IWL_WARNING("REPLY_ADD_STA failed\n"); - break; - } - } - - priv->alloc_rxb_skb--; - dev_kfree_skb_any(cmd.meta.u.skb); - - return rc; -} - static void iwl4965_clear_free_frames(struct iwl_priv *priv) { struct list_head *element; @@ -5927,7 +5882,7 @@ static void iwl4965_mac_update_tkip_key(struct ieee80211_hw *hw, priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; - iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC); + iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); spin_unlock_irqrestore(&priv->sta_lock, flags); -- cgit v1.2.3-70-g09d2 From 2469bf2e9938eef3c6ab0951985b050ff1f8c94f Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Mon, 5 May 2008 10:22:35 +0800 Subject: iwlwifi-5000: add build_addsta_hcmd handler for 5000 HW This patch adds iwl5000_build_addsta_hcmd handler. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 83ed69dfac6..f9c22741308 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -422,10 +422,19 @@ static void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv, } } +static u16 iwl5000_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) +{ + u16 size = (u16)sizeof(struct iwl_addsta_cmd); + memcpy(data, cmd, size); + return size; +} + + static struct iwl_hcmd_ops iwl5000_hcmd = { }; static struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = { + .build_addsta_hcmd = iwl5000_build_addsta_hcmd, #ifdef CONFIG_IWL5000_RUN_TIME_CALIB .gain_computation = iwl5000_gain_computation, .chain_noise_reset = iwl5000_chain_noise_reset, -- cgit v1.2.3-70-g09d2 From bf403db8a2f5580a5eb355a109d29b9287ca51e1 Mon Sep 17 00:00:00 2001 From: Ester Kummer Date: Mon, 5 May 2008 10:22:40 +0800 Subject: iwlwifi: move per driverdebug_level to per device This patch ports the debug_level to iwl_priv and changes the format of the debug prints. Signed-off-by: Ester Kummer Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 32 +++++++++++++++++-------- drivers/net/wireless/iwlwifi/iwl-4965.c | 13 ++++++----- drivers/net/wireless/iwlwifi/iwl-debug.h | 20 ++++------------ drivers/net/wireless/iwlwifi/iwl-dev.h | 18 +++++++++++++++ drivers/net/wireless/iwlwifi/iwl4965-base.c | 36 ++++++++++++++++++----------- 5 files changed, 75 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index e3444c4ea1a..5baa000c788 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -662,7 +662,8 @@ static u16 rs_get_supported_rates(struct iwl4965_lq_sta *lq_sta, } } -static u16 rs_get_adjacent_rate(u8 index, u16 rate_mask, int rate_type) +static u16 rs_get_adjacent_rate(struct iwl_priv *priv, u8 index, u16 rate_mask, + int rate_type) { u8 high = IWL_RATE_INVALID; u8 low = IWL_RATE_INVALID; @@ -763,7 +764,8 @@ static u32 rs_get_lower_rate(struct iwl4965_lq_sta *lq_sta, goto out; } - high_low = rs_get_adjacent_rate(scale_index, rate_mask, tbl->lq_type); + high_low = rs_get_adjacent_rate(lq_sta->drv, scale_index, rate_mask, + tbl->lq_type); low = high_low & 0xff; if (low == IWL_RATE_INVALID) @@ -990,7 +992,7 @@ out: * These control how long we stay using same modulation mode before * searching for a new mode. */ -static void rs_set_stay_in_table(u8 is_legacy, +static void rs_set_stay_in_table(struct iwl_priv *priv, u8 is_legacy, struct iwl4965_lq_sta *lq_sta) { IWL_DEBUG_RATE("we are staying in the same table\n"); @@ -1079,7 +1081,8 @@ static s32 rs_get_best_rate(struct iwl_priv *priv, new_rate = high = low = start_hi = IWL_RATE_INVALID; for (; ;) { - high_low = rs_get_adjacent_rate(rate, rate_mask, tbl->lq_type); + high_low = rs_get_adjacent_rate(priv, rate, rate_mask, + tbl->lq_type); low = high_low & 0xff; high = (high_low >> 8) & 0xff; @@ -1565,7 +1568,9 @@ static void rs_stay_in_table(struct iwl4965_lq_sta *lq_sta) int i; int active_tbl; int flush_interval_passed = 0; + struct iwl_priv *priv; + priv = lq_sta->drv; active_tbl = lq_sta->active_tbl; tbl = &(lq_sta->lq_info[active_tbl]); @@ -1838,7 +1843,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, /* (Else) not in search of better modulation mode, try for better * starting rate, while staying in this mode. */ - high_low = rs_get_adjacent_rate(index, rate_scale_index_msk, + high_low = rs_get_adjacent_rate(priv, index, rate_scale_index_msk, tbl->lq_type); low = high_low & 0xff; high = (high_low >> 8) & 0xff; @@ -1998,7 +2003,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, (lq_sta->action_counter >= 1)) { lq_sta->action_counter = 0; IWL_DEBUG_RATE("LQ: STAY in legacy table\n"); - rs_set_stay_in_table(1, lq_sta); + rs_set_stay_in_table(priv, 1, lq_sta); } /* If we're in an HT mode, and all 3 mode switch actions @@ -2015,7 +2020,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, } #endif /*CONFIG_IWL4965_HT */ lq_sta->action_counter = 0; - rs_set_stay_in_table(0, lq_sta); + rs_set_stay_in_table(priv, 0, lq_sta); } /* @@ -2169,11 +2174,13 @@ out: rcu_read_unlock(); } -static void *rs_alloc_sta(void *priv, gfp_t gfp) +static void *rs_alloc_sta(void *priv_rate, gfp_t gfp) { struct iwl4965_lq_sta *lq_sta; + struct iwl_priv *priv; int i, j; + priv = (struct iwl_priv *)priv_rate; IWL_DEBUG_RATE("create station rate scale window\n"); lq_sta = kzalloc(sizeof(struct iwl4965_lq_sta), gfp); @@ -2443,10 +2450,12 @@ static void rs_clear(void *priv_rate) IWL_DEBUG_RATE("leave\n"); } -static void rs_free_sta(void *priv, void *priv_sta) +static void rs_free_sta(void *priv_rate, void *priv_sta) { struct iwl4965_lq_sta *lq_sta = priv_sta; + struct iwl_priv *priv; + priv = (struct iwl_priv *)priv_rate; IWL_DEBUG_RATE("enter\n"); kfree(lq_sta); IWL_DEBUG_RATE("leave\n"); @@ -2462,6 +2471,9 @@ static int open_file_generic(struct inode *inode, struct file *file) static void rs_dbgfs_set_mcs(struct iwl4965_lq_sta *lq_sta, u32 *rate_n_flags, int index) { + struct iwl_priv *priv; + + priv = lq_sta->drv; if (lq_sta->dbg_fixed_rate) { if (index < 12) { *rate_n_flags = lq_sta->dbg_fixed_rate; @@ -2481,10 +2493,12 @@ static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { struct iwl4965_lq_sta *lq_sta = file->private_data; + struct iwl_priv *priv; char buf[64]; int buf_size; u32 parsed_rate; + priv = lq_sta->drv; memset(buf, 0, sizeof(buf)); buf_size = min(count, sizeof(buf) - 1); if (copy_from_user(buf, user_buf, buf_size)) diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 0644e22fe78..b4f2c3c8954 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2743,7 +2743,7 @@ static int iwl4965_set_decrypted_flag(struct iwl_priv *priv, return 0; } -static u32 iwl4965_translate_rx_status(u32 decrypt_in) +static u32 iwl4965_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in) { u32 decrypt_out = 0; @@ -2855,7 +2855,7 @@ static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data, if (!include_phy) { /* New status scheme, need to translate */ ampdu_status_legacy = ampdu_status; - ampdu_status = iwl4965_translate_rx_status(ampdu_status); + ampdu_status = iwl4965_translate_rx_status(priv, ampdu_status); } /* start from MAC */ @@ -2887,7 +2887,8 @@ static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data, } /* Calc max signal level (dBm) among 3 possible receivers */ -static int iwl4965_calc_rssi(struct iwl4965_rx_phy_res *rx_resp) +static int iwl4965_calc_rssi(struct iwl_priv *priv, + struct iwl4965_rx_phy_res *rx_resp) { /* data from PHY/DSP regarding signal strength, etc., * contents are always there, not configurable by host. */ @@ -2991,7 +2992,7 @@ static void iwl4965_dbg_report_frame(struct iwl_priv *priv, struct iwl4965_rx_frame_end *rx_end = IWL_RX_END(pkt); u8 *data = IWL_RX_DATA(pkt); - if (likely(!(iwl_debug_level & IWL_DL_RX))) + if (likely(!(priv->debug_level & IWL_DL_RX))) return; /* MAC header */ @@ -3094,7 +3095,7 @@ static void iwl4965_dbg_report_frame(struct iwl_priv *priv, } } if (print_dump) - iwl_print_hex_dump(IWL_DL_RX, data, length); + iwl_print_hex_dump(priv, IWL_DL_RX, data, length); } #else static inline void iwl4965_dbg_report_frame(struct iwl_priv *priv, @@ -3187,7 +3188,7 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv, priv->ucode_beacon_time = le32_to_cpu(rx_start->beacon_time_stamp); /* Find max signal strength (dBm) among 3 antenna/receiver chains */ - rx_status.ssi = iwl4965_calc_rssi(rx_start); + rx_status.ssi = iwl4965_calc_rssi(priv, rx_start); /* Meaningful noise values are available only from beacon statistics, * which are gathered only when associated, and indicate noise diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 7e68d24114f..14d95dd0e14 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -32,24 +32,15 @@ #ifdef CONFIG_IWLWIFI_DEBUG extern u32 iwl_debug_level; #define IWL_DEBUG(level, fmt, args...) \ -do { if (iwl_debug_level & (level)) \ - printk(KERN_ERR DRV_NAME": %c %s " fmt, \ +do { if (priv->debug_level & (level)) \ + dev_printk(KERN_ERR, &(priv->hw->wiphy->dev), "%c %s " fmt, \ in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0) #define IWL_DEBUG_LIMIT(level, fmt, args...) \ -do { if ((iwl_debug_level & (level)) && net_ratelimit()) \ - printk(KERN_ERR DRV_NAME": %c %s " fmt, \ +do { if ((priv->debug_level & (level)) && net_ratelimit()) \ + dev_printk(KERN_ERR, &(priv->hw->wiphy->dev), "%c %s " fmt, \ in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0) -static inline void iwl_print_hex_dump(int level, void *p, u32 len) -{ - if (!(iwl_debug_level & level)) - return; - - print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1, - p, len, 1); -} - #ifdef CONFIG_IWLWIFI_DEBUGFS struct iwl_debugfs { const char *name; @@ -77,9 +68,6 @@ static inline void IWL_DEBUG(int level, const char *fmt, ...) static inline void IWL_DEBUG_LIMIT(int level, const char *fmt, ...) { } -static inline void iwl_print_hex_dump(int level, void *p, u32 len) -{ -} #endif /* CONFIG_IWLWIFI_DEBUG */ diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 4786194c045..0a37ff4d98b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1194,6 +1194,7 @@ struct iwl_priv { #ifdef CONFIG_IWLWIFI_DEBUG /* debugging info */ + u32 debug_level; u32 framecnt_to_us; atomic_t restrict_refcnt; #ifdef CONFIG_IWLWIFI_DEBUGFS @@ -1246,6 +1247,23 @@ static inline int is_channel_ibss(const struct iwl_channel_info *ch) return ((ch->flags & EEPROM_CHANNEL_IBSS)) ? 1 : 0; } +#ifdef CONFIG_IWLWIFI_DEBUG +static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level, + void *p, u32 len) +{ + if (!(priv->debug_level & level)) + return; + + print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1, + p, len, 1); +} +#else +static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level, + void *p, u32 len) +{ +} +#endif + extern const struct iwl_channel_info *iwl_get_channel_info( const struct iwl_priv *priv, enum ieee80211_band band, u16 channel); diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 8427bc9a9bb..9f51d3a61f3 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -145,6 +145,7 @@ static const char *iwl4965_escape_essid(const char *essid, u8 essid_len) return escaped; } + /*************** DMA-QUEUE-GENERAL-FUNCTIONS ***** * DMA services * @@ -1914,7 +1915,7 @@ static int iwl4965_get_sta_id(struct iwl_priv *priv, IWL_DEBUG_DROP("Station %s not in station map. " "Defaulting to broadcast...\n", print_mac(mac, hdr->addr1)); - iwl_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); + iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); return priv->hw_params.bcast_sta_id; default: @@ -2130,10 +2131,10 @@ static int iwl4965_tx_skb(struct iwl_priv *priv, txq->need_update = 0; } - iwl_print_hex_dump(IWL_DL_TX, out_cmd->cmd.payload, + iwl_print_hex_dump(priv, IWL_DL_TX, out_cmd->cmd.payload, sizeof(out_cmd->cmd.tx)); - iwl_print_hex_dump(IWL_DL_TX, (u8 *)out_cmd->cmd.tx.hdr, + iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)out_cmd->cmd.tx.hdr, ieee80211_get_hdrlen(fc)); /* Set up entry for this TFD in Tx byte-count array */ @@ -2911,7 +2912,7 @@ static void iwl4965_rx_pm_debug_statistics_notif(struct iwl_priv *priv, IWL_DEBUG_RADIO("Dumping %d bytes of unhandled " "notification for %s:\n", le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd)); - iwl_print_hex_dump(IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len)); + iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len)); } static void iwl4965_bg_beacon_update(struct work_struct *work) @@ -3484,12 +3485,13 @@ static int iwl4965_tx_queue_update_write_ptr(struct iwl_priv *priv, } #ifdef CONFIG_IWLWIFI_DEBUG -static void iwl4965_print_rx_config_cmd(struct iwl4965_rxon_cmd *rxon) +static void iwl4965_print_rx_config_cmd(struct iwl_priv *priv) { + struct iwl4965_rxon_cmd *rxon = &priv->staging_rxon; DECLARE_MAC_BUF(mac); IWL_DEBUG_RADIO("RX CONFIG:\n"); - iwl_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); + iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); IWL_DEBUG_RADIO("u16 channel: 0x%x\n", le16_to_cpu(rxon->channel)); IWL_DEBUG_RADIO("u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags)); IWL_DEBUG_RADIO("u32 filter_flags: 0x%08x\n", @@ -3715,10 +3717,10 @@ static void iwl4965_irq_handle_error(struct iwl_priv *priv) clear_bit(STATUS_HCMD_ACTIVE, &priv->status); #ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & IWL_DL_FW_ERRORS) { + if (priv->debug_level & IWL_DL_FW_ERRORS) { iwl4965_dump_nic_error_log(priv); iwl4965_dump_nic_event_log(priv); - iwl4965_print_rx_config_cmd(&priv->staging_rxon); + iwl4965_print_rx_config_cmd(priv); } #endif @@ -3782,7 +3784,7 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv) iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh); #ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & IWL_DL_ISR) { + if (priv->debug_level & IWL_DL_ISR) { /* just for debug */ inta_mask = iwl_read32(priv, CSR_INT_MASK); IWL_DEBUG_ISR("inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", @@ -3816,7 +3818,7 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv) } #ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & (IWL_DL_ISR)) { + if (priv->debug_level & (IWL_DL_ISR)) { /* NIC fires this, but we don't use it, redundant with WAKEUP */ if (inta & CSR_INT_BIT_SCD) IWL_DEBUG_ISR("Scheduler finished to transmit " @@ -3909,7 +3911,7 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv) iwl4965_enable_interrupts(priv); #ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & (IWL_DL_ISR)) { + if (priv->debug_level & (IWL_DL_ISR)) { inta = iwl_read32(priv, CSR_INT); inta_mask = iwl_read32(priv, CSR_INT_MASK); inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); @@ -6049,6 +6051,9 @@ static int iwl4965_mac_get_tx_stats(struct ieee80211_hw *hw, static int iwl4965_mac_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats) { + struct iwl_priv *priv = hw->priv; + + priv = hw->priv; IWL_DEBUG_MAC80211("enter\n"); IWL_DEBUG_MAC80211("leave\n"); @@ -6057,6 +6062,9 @@ static int iwl4965_mac_get_stats(struct ieee80211_hw *hw, static u64 iwl4965_mac_get_tsf(struct ieee80211_hw *hw) { + struct iwl_priv *priv; + + priv = hw->priv; IWL_DEBUG_MAC80211("enter\n"); IWL_DEBUG_MAC80211("leave\n"); @@ -6706,7 +6714,9 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e /* Disabling hardware scan means that mac80211 will perform scans * "the hard way", rather than using device's scan. */ if (cfg->mod_params->disable_hw_scan) { - IWL_DEBUG_INFO("Disabling hw_scan\n"); + if (cfg->mod_params->debug & IWL_DL_INFO) + dev_printk(KERN_DEBUG, &(pdev->dev), + "Disabling hw_scan\n"); iwl4965_hw_ops.hw_scan = NULL; } @@ -6725,7 +6735,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e priv->pci_dev = pdev; #ifdef CONFIG_IWLWIFI_DEBUG - iwl_debug_level = priv->cfg->mod_params->debug; + priv->debug_level = priv->cfg->mod_params->debug; atomic_set(&priv->restrict_refcnt, 0); #endif -- cgit v1.2.3-70-g09d2 From 47c5196e4a340667d8d92053380ecca24ed45a9b Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Mon, 5 May 2008 10:22:41 +0800 Subject: iwlwifi: move iwl4965_set_rxon_ht into iwlcore This patch moves iwl4965_set_rxon_ht to iwlcore under name iwl_set_rxon_ht. It also moves collateral changes iwl_is_channel_extension and iwl_is_fat_tx_allowed. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 99 +---------------------------- drivers/net/wireless/iwlwifi/iwl-core.c | 99 +++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-core.h | 3 + drivers/net/wireless/iwlwifi/iwl-dev.h | 2 - drivers/net/wireless/iwlwifi/iwl4965-base.c | 6 +- 5 files changed, 105 insertions(+), 104 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index b4f2c3c8954..bc988c3b678 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -3719,103 +3719,6 @@ void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) #ifdef CONFIG_IWL4965_HT -static u8 iwl4965_is_channel_extension(struct iwl_priv *priv, - enum ieee80211_band band, - u16 channel, u8 extension_chan_offset) -{ - const struct iwl_channel_info *ch_info; - - ch_info = iwl_get_channel_info(priv, band, channel); - if (!is_channel_valid(ch_info)) - return 0; - - if (extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_NONE) - return 0; - - if ((ch_info->fat_extension_channel == extension_chan_offset) || - (ch_info->fat_extension_channel == HT_IE_EXT_CHANNEL_MAX)) - return 1; - - return 0; -} - -static u8 iwl4965_is_fat_tx_allowed(struct iwl_priv *priv, - struct ieee80211_ht_info *sta_ht_inf) -{ - struct iwl_ht_info *iwl_ht_conf = &priv->current_ht_config; - - if ((!iwl_ht_conf->is_ht) || - (iwl_ht_conf->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ) || - (iwl_ht_conf->extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_NONE)) - return 0; - - if (sta_ht_inf) { - if ((!sta_ht_inf->ht_supported) || - (!(sta_ht_inf->cap & IEEE80211_HT_CAP_SUP_WIDTH))) - return 0; - } - - return (iwl4965_is_channel_extension(priv, priv->band, - iwl_ht_conf->control_channel, - iwl_ht_conf->extension_chan_offset)); -} - -void iwl4965_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) -{ - struct iwl4965_rxon_cmd *rxon = &priv->staging_rxon; - u32 val; - - if (!ht_info->is_ht) - return; - - /* Set up channel bandwidth: 20 MHz only, or 20/40 mixed if fat ok */ - if (iwl4965_is_fat_tx_allowed(priv, NULL)) - rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED_MSK; - else - rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK | - RXON_FLG_CHANNEL_MODE_PURE_40_MSK); - - if (le16_to_cpu(rxon->channel) != ht_info->control_channel) { - IWL_ERROR("control diff than current %d %d\n", - le16_to_cpu(rxon->channel), - ht_info->control_channel); - WARN_ON(1); - return; - } - - /* Note: control channel is opposite of extension channel */ - switch (ht_info->extension_chan_offset) { - case IWL_EXT_CHANNEL_OFFSET_ABOVE: - rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); - break; - case IWL_EXT_CHANNEL_OFFSET_BELOW: - rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; - break; - case IWL_EXT_CHANNEL_OFFSET_NONE: - default: - rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK; - break; - } - - val = ht_info->ht_protection; - - rxon->flags |= cpu_to_le32(val << RXON_FLG_HT_OPERATING_MODE_POS); - - iwl_set_rxon_chain(priv); - - IWL_DEBUG_ASSOC("supported HT rate 0x%X 0x%X 0x%X " - "rxon flags 0x%X operation mode :0x%X " - "extension channel offset 0x%x " - "control chan %d\n", - ht_info->supp_mcs_set[0], - ht_info->supp_mcs_set[1], - ht_info->supp_mcs_set[2], - le32_to_cpu(rxon->flags), ht_info->ht_protection, - ht_info->extension_chan_offset, - ht_info->control_channel); - return; -} - void iwl4965_set_ht_add_station(struct iwl_priv *priv, u8 index, struct ieee80211_ht_info *sta_ht_inf) { @@ -3851,7 +3754,7 @@ void iwl4965_set_ht_add_station(struct iwl_priv *priv, u8 index, sta_flags |= cpu_to_le32( (u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS); - if (iwl4965_is_fat_tx_allowed(priv, sta_ht_inf)) + if (iwl_is_fat_tx_allowed(priv, sta_ht_inf)) sta_flags |= STA_FLG_FAT_EN_MSK; else sta_flags &= ~STA_FLG_FAT_EN_MSK; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 55e3d139f42..2ff27a01cf6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -434,6 +434,105 @@ static u8 is_single_rx_stream(struct iwl_priv *priv) (priv->current_ht_config.supp_mcs_set[2] == 0)) || priv->ps_mode == IWL_MIMO_PS_STATIC; } +static u8 iwl_is_channel_extension(struct iwl_priv *priv, + enum ieee80211_band band, + u16 channel, u8 extension_chan_offset) +{ + const struct iwl_channel_info *ch_info; + + ch_info = iwl_get_channel_info(priv, band, channel); + if (!is_channel_valid(ch_info)) + return 0; + + if (extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_NONE) + return 0; + + if ((ch_info->fat_extension_channel == extension_chan_offset) || + (ch_info->fat_extension_channel == HT_IE_EXT_CHANNEL_MAX)) + return 1; + + return 0; +} + +u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, + struct ieee80211_ht_info *sta_ht_inf) +{ + struct iwl_ht_info *iwl_ht_conf = &priv->current_ht_config; + + if ((!iwl_ht_conf->is_ht) || + (iwl_ht_conf->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ) || + (iwl_ht_conf->extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_NONE)) + return 0; + + if (sta_ht_inf) { + if ((!sta_ht_inf->ht_supported) || + (!(sta_ht_inf->cap & IEEE80211_HT_CAP_SUP_WIDTH))) + return 0; + } + + return iwl_is_channel_extension(priv, priv->band, + iwl_ht_conf->control_channel, + iwl_ht_conf->extension_chan_offset); +} +EXPORT_SYMBOL(iwl_is_fat_tx_allowed); + +void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) +{ + struct iwl4965_rxon_cmd *rxon = &priv->staging_rxon; + u32 val; + + if (!ht_info->is_ht) + return; + + /* Set up channel bandwidth: 20 MHz only, or 20/40 mixed if fat ok */ + if (iwl_is_fat_tx_allowed(priv, NULL)) + rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED_MSK; + else + rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK | + RXON_FLG_CHANNEL_MODE_PURE_40_MSK); + + if (le16_to_cpu(rxon->channel) != ht_info->control_channel) { + IWL_DEBUG_ASSOC("control diff than current %d %d\n", + le16_to_cpu(rxon->channel), + ht_info->control_channel); + rxon->channel = cpu_to_le16(ht_info->control_channel); + return; + } + + /* Note: control channel is opposite of extension channel */ + switch (ht_info->extension_chan_offset) { + case IWL_EXT_CHANNEL_OFFSET_ABOVE: + rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); + break; + case IWL_EXT_CHANNEL_OFFSET_BELOW: + rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; + break; + case IWL_EXT_CHANNEL_OFFSET_NONE: + default: + rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK; + break; + } + + val = ht_info->ht_protection; + + rxon->flags |= cpu_to_le32(val << RXON_FLG_HT_OPERATING_MODE_POS); + + iwl_set_rxon_chain(priv); + + IWL_DEBUG_ASSOC("supported HT rate 0x%X 0x%X 0x%X " + "rxon flags 0x%X operation mode :0x%X " + "extension channel offset 0x%x " + "control chan %d\n", + ht_info->supp_mcs_set[0], + ht_info->supp_mcs_set[1], + ht_info->supp_mcs_set[2], + le32_to_cpu(rxon->flags), ht_info->ht_protection, + ht_info->extension_chan_offset, + ht_info->control_channel); + return; +} +EXPORT_SYMBOL(iwl_set_rxon_ht); + #else static inline u8 is_single_rx_stream(struct iwl_priv *priv) { diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index df27ee65015..12418061ab7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -173,6 +173,9 @@ int iwl_set_rxon_channel(struct iwl_priv *priv, u16 channel); void iwlcore_free_geos(struct iwl_priv *priv); int iwl_setup(struct iwl_priv *priv); +void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info); +u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, + struct ieee80211_ht_info *sta_ht_inf); /***************************************************** * RX diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 0a37ff4d98b..23cae4c1345 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -454,7 +454,6 @@ union iwl4965_ht_rate_supp { }; }; -#ifdef CONFIG_IWL4965_HT #define CFG_HT_RX_AMPDU_FACTOR_DEF (0x3) #define CFG_HT_MPDU_DENSITY_2USEC (0x5) #define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_2USEC @@ -477,7 +476,6 @@ struct iwl_ht_info { u8 ht_protection; u8 non_GF_STA_present; }; -#endif /*CONFIG_IWL4965_HT */ union iwl4965_qos_capabity { struct { diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 9f51d3a61f3..ad45249454f 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -2783,9 +2783,9 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, tx_resp->failure_frame); IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); +#ifdef CONFIG_IWL4965_HT if (index != -1) { int freed = iwl4965_tx_queue_reclaim(priv, txq_id, index); -#ifdef CONFIG_IWL4965_HT if (tid != MAX_TID_COUNT) priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; if (iwl4965_queue_space(&txq->q) > txq->q.low_mark && @@ -2793,9 +2793,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, ieee80211_wake_queue(priv->hw, txq_id); if (tid != MAX_TID_COUNT) iwl4965_check_empty_hw_queue(priv, sta_id, tid, txq_id); -#endif } -#ifdef CONFIG_IWL4965_HT } #endif /* CONFIG_IWL4965_HT */ @@ -5124,7 +5122,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv) #ifdef CONFIG_IWL4965_HT if (priv->current_ht_config.is_ht) - iwl4965_set_rxon_ht(priv, &priv->current_ht_config); + iwl_set_rxon_ht(priv, &priv->current_ht_config); #endif /* CONFIG_IWL4965_HT*/ iwl_set_rxon_chain(priv); priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id); -- cgit v1.2.3-70-g09d2 From 5a676bbeaf9e534b75286f2294ec57a4c544f1d2 Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Mon, 5 May 2008 10:22:42 +0800 Subject: iwlwifi: create disable SCD Tx FIFOs handler This patch moves disabeling Tx FIFOs in NIC SCD to seperate handlers in 4965 and 5000 cards. Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 40 +++++++++++++++++++++------------ drivers/net/wireless/iwlwifi/iwl-5000.c | 22 ++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-core.h | 2 ++ 3 files changed, 50 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index bc988c3b678..9e6f3e33ab6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -470,6 +470,27 @@ static void iwl4965_kw_free(struct iwl_priv *priv) } } +static int iwl4965_disable_tx_fifo(struct iwl_priv *priv) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&priv->lock, flags); + + ret = iwl_grab_nic_access(priv); + if (unlikely(ret)) { + IWL_ERROR("Tx fifo reset failed"); + spin_unlock_irqrestore(&priv->lock, flags); + return ret; + } + + iwl_write_prph(priv, IWL49_SCD_TXFACT, 0); + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + /** * iwl4965_txq_ctx_reset - Reset TX queue context * Destroys all DMA structures and initialise them again @@ -481,7 +502,6 @@ static int iwl4965_txq_ctx_reset(struct iwl_priv *priv) { int rc = 0; int txq_id, slots_num; - unsigned long flags; iwl4965_kw_free(priv); @@ -495,19 +515,10 @@ static int iwl4965_txq_ctx_reset(struct iwl_priv *priv) goto error_kw; } - spin_lock_irqsave(&priv->lock, flags); - - rc = iwl_grab_nic_access(priv); - if (unlikely(rc)) { - IWL_ERROR("TX reset failed"); - spin_unlock_irqrestore(&priv->lock, flags); + /* Turn off all Tx DMA fifos */ + rc = priv->cfg->ops->lib->disable_tx_fifo(priv); + if (unlikely(rc)) goto error_reset; - } - - /* Turn off all Tx DMA channels */ - iwl_write_prph(priv, IWL49_SCD_TXFACT, 0); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->lock, flags); /* Tell 4965 where to find the keep-warm buffer */ rc = iwl4965_kw_init(priv); @@ -538,6 +549,7 @@ static int iwl4965_txq_ctx_reset(struct iwl_priv *priv) error_kw: return rc; } + static int iwl4965_apm_init(struct iwl_priv *priv) { unsigned long flags; @@ -621,7 +633,6 @@ static void iwl4965_nic_config(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } - int iwl4965_hw_nic_init(struct iwl_priv *priv) { unsigned long flags; @@ -4044,6 +4055,7 @@ static struct iwl_lib_ops iwl4965_lib = { .free_shared_mem = iwl4965_free_shared_mem, .txq_update_byte_cnt_tbl = iwl4965_txq_update_byte_cnt_tbl, .hw_nic_init = iwl4965_hw_nic_init, + .disable_tx_fifo = iwl4965_disable_tx_fifo, .rx_handler_setup = iwl4965_rx_handler_setup, .is_valid_rtc_data_addr = iwl4965_hw_valid_rtc_data_addr, .alive_notify = iwl4965_alive_notify, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index f9c22741308..feffcafe149 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -430,6 +430,27 @@ static u16 iwl5000_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) } +static int iwl5000_disable_tx_fifo(struct iwl_priv *priv) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&priv->lock, flags); + + ret = iwl_grab_nic_access(priv); + if (unlikely(ret)) { + IWL_ERROR("Tx fifo reset failed"); + spin_unlock_irqrestore(&priv->lock, flags); + return ret; + } + + iwl_write_prph(priv, IWL50_SCD_TXFACT, 0); + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + static struct iwl_hcmd_ops iwl5000_hcmd = { }; @@ -446,6 +467,7 @@ static struct iwl_lib_ops iwl5000_lib = { .alloc_shared_mem = iwl5000_alloc_shared_mem, .free_shared_mem = iwl5000_free_shared_mem, .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, + .disable_tx_fifo = iwl5000_disable_tx_fifo, .apm_ops = { .init = iwl5000_apm_init, .config = iwl5000_nic_config, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 12418061ab7..c29f8b34712 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -110,6 +110,8 @@ struct iwl_lib_ops { void (*rx_handler_setup)(struct iwl_priv *priv); /* nic init */ int (*hw_nic_init)(struct iwl_priv *priv); + /* nic Tx fifo handling */ + int (*disable_tx_fifo)(struct iwl_priv *priv); /* alive notification */ int (*alive_notify)(struct iwl_priv *priv); /* check validity of rtc data address */ -- cgit v1.2.3-70-g09d2 From 1053d35f4ed6876ad9d3a14cdae363db0a7e9b0a Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Mon, 5 May 2008 10:22:43 +0800 Subject: iwlwifi: move NIC init and Tx queues init to iwlcore This patch does the following: 1 - change hw_nic_init from a handler to a function 2 - move hw_nic_init function to iwlcore 3 - open a new file - iwl-tx.c 4 - move all Tx queues initialization (part of NIC init) to iwl-tx.c 5 - move iwl_rx_init, previously as part of the NIC init, to iwl-rx.c 6 - iwl4965_tfd_frame rename to iwl_tfd_frame Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/Makefile | 2 +- drivers/net/wireless/iwlwifi/iwl-4965-hw.h | 10 +- drivers/net/wireless/iwlwifi/iwl-4965.c | 339 +------------------------ drivers/net/wireless/iwlwifi/iwl-core.c | 95 +++++++ drivers/net/wireless/iwlwifi/iwl-core.h | 17 +- drivers/net/wireless/iwlwifi/iwl-dev.h | 10 +- drivers/net/wireless/iwlwifi/iwl-rx.c | 52 ++++ drivers/net/wireless/iwlwifi/iwl-tx.c | 374 ++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl4965-base.c | 177 +------------ 9 files changed, 550 insertions(+), 526 deletions(-) create mode 100644 drivers/net/wireless/iwlwifi/iwl-tx.c (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 0211a7f7147..85c8bf62d59 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -1,6 +1,6 @@ obj-$(CONFIG_IWLCORE) += iwlcore.o iwlcore-objs := iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.o -iwlcore-objs += iwl-rx.o +iwlcore-objs += iwl-rx.o iwl-tx.o iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o iwlcore-$(CONFIG_IWLWIFI_LEDS) += iwl-led.o iwlcore-$(CONFIG_IWLWIFI_RFKILL) += iwl-rfkill.o diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h index 29749e2a8ff..ee55b283226 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h @@ -829,7 +829,7 @@ static inline __le32 iwl4965_hw_set_rate_n_flags(u8 rate, u16 flags) #define IWL49_NUM_QUEUES 16 /** - * struct iwl4965_tfd_frame_data + * struct iwl_tfd_frame_data * * Describes up to 2 buffers containing (contiguous) portions of a Tx frame. * Each buffer must be on dword boundary. @@ -848,7 +848,7 @@ static inline __le32 iwl4965_hw_set_rate_n_flags(u8 rate, u16 flags) * 31-20: Tx buffer 2 length (bytes) * 19- 0: Tx buffer 2 address bits [35:16] */ -struct iwl4965_tfd_frame_data { +struct iwl_tfd_frame_data { __le32 tb1_addr; __le32 val1; @@ -878,7 +878,7 @@ struct iwl4965_tfd_frame_data { /** - * struct iwl4965_tfd_frame + * struct iwl_tfd_frame * * Transmit Frame Descriptor (TFD) * @@ -905,7 +905,7 @@ struct iwl4965_tfd_frame_data { * * A maximum of 255 (not 256!) TFDs may be on a queue waiting for Tx. */ -struct iwl4965_tfd_frame { +struct iwl_tfd_frame { __le32 val0; /* __le32 rsvd1:24; */ /* __le32 num_tbs:5; */ @@ -914,7 +914,7 @@ struct iwl4965_tfd_frame { #define IWL_num_tbs_SYM val0 /* __le32 rsvd2:1; */ /* __le32 padding:2; */ - struct iwl4965_tfd_frame_data pa[10]; + struct iwl_tfd_frame_data pa[10]; __le32 reserved; } __attribute__ ((packed)); diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 9e6f3e33ab6..319ffe747a7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -53,8 +53,6 @@ static struct iwl_mod_params iwl4965_mod_params = { /* the rest are 0 by default */ }; -static void iwl4965_hw_card_show_info(struct iwl_priv *priv); - #ifdef CONFIG_IWL4965_HT static const u16 default_tid_to_tx_fifo[] = { @@ -372,104 +370,6 @@ int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src) return ret; } -static int iwl4965_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) -{ - int ret; - unsigned long flags; - unsigned int rb_size; - - spin_lock_irqsave(&priv->lock, flags); - ret = iwl_grab_nic_access(priv); - if (ret) { - spin_unlock_irqrestore(&priv->lock, flags); - return ret; - } - - if (priv->cfg->mod_params->amsdu_size_8K) - rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K; - else - rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K; - - /* Stop Rx DMA */ - iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); - - /* Reset driver's Rx queue write index */ - iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0); - - /* Tell device where to find RBD circular buffer in DRAM */ - iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG, - rxq->dma_addr >> 8); - - /* Tell device where in DRAM to update its Rx status */ - iwl_write_direct32(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG, - (priv->shared_phys + - offsetof(struct iwl4965_shared, rb_closed)) >> 4); - - /* Enable Rx DMA, enable host interrupt, Rx buffer size 4k, 256 RBDs */ - iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, - FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL | - FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL | - rb_size | - /* 0x10 << 4 | */ - (RX_QUEUE_SIZE_LOG << - FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT)); - - /* - * iwl_write32(priv,CSR_INT_COAL_REG,0); - */ - - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->lock, flags); - - return 0; -} - -/* Tell 4965 where to find the "keep warm" buffer */ -static int iwl4965_kw_init(struct iwl_priv *priv) -{ - unsigned long flags; - int rc; - - spin_lock_irqsave(&priv->lock, flags); - rc = iwl_grab_nic_access(priv); - if (rc) - goto out; - - iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, - priv->kw.dma_addr >> 4); - iwl_release_nic_access(priv); -out: - spin_unlock_irqrestore(&priv->lock, flags); - return rc; -} - -static int iwl4965_kw_alloc(struct iwl_priv *priv) -{ - struct pci_dev *dev = priv->pci_dev; - struct iwl4965_kw *kw = &priv->kw; - - kw->size = IWL4965_KW_SIZE; /* TBW need set somewhere else */ - kw->v_addr = pci_alloc_consistent(dev, kw->size, &kw->dma_addr); - if (!kw->v_addr) - return -ENOMEM; - - return 0; -} - -/** - * iwl4965_kw_free - Free the "keep warm" buffer - */ -static void iwl4965_kw_free(struct iwl_priv *priv) -{ - struct pci_dev *dev = priv->pci_dev; - struct iwl4965_kw *kw = &priv->kw; - - if (kw->v_addr) { - pci_free_consistent(dev, kw->size, kw->v_addr, kw->dma_addr); - memset(kw, 0, sizeof(*kw)); - } -} - static int iwl4965_disable_tx_fifo(struct iwl_priv *priv) { unsigned long flags; @@ -491,65 +391,6 @@ static int iwl4965_disable_tx_fifo(struct iwl_priv *priv) return 0; } -/** - * iwl4965_txq_ctx_reset - Reset TX queue context - * Destroys all DMA structures and initialise them again - * - * @param priv - * @return error code - */ -static int iwl4965_txq_ctx_reset(struct iwl_priv *priv) -{ - int rc = 0; - int txq_id, slots_num; - - iwl4965_kw_free(priv); - - /* Free all tx/cmd queues and keep-warm buffer */ - iwl4965_hw_txq_ctx_free(priv); - - /* Alloc keep-warm buffer */ - rc = iwl4965_kw_alloc(priv); - if (rc) { - IWL_ERROR("Keep Warm allocation failed"); - goto error_kw; - } - - /* Turn off all Tx DMA fifos */ - rc = priv->cfg->ops->lib->disable_tx_fifo(priv); - if (unlikely(rc)) - goto error_reset; - - /* Tell 4965 where to find the keep-warm buffer */ - rc = iwl4965_kw_init(priv); - if (rc) { - IWL_ERROR("kw_init failed\n"); - goto error_reset; - } - - /* Alloc and init all (default 16) Tx queues, - * including the command queue (#4) */ - for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) { - slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ? - TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; - rc = iwl4965_tx_queue_init(priv, &priv->txq[txq_id], slots_num, - txq_id); - if (rc) { - IWL_ERROR("Tx %d queue init failed\n", txq_id); - goto error; - } - } - - return rc; - - error: - iwl4965_hw_txq_ctx_free(priv); - error_reset: - iwl4965_kw_free(priv); - error_kw: - return rc; -} - static int iwl4965_apm_init(struct iwl_priv *priv) { unsigned long flags; @@ -633,58 +474,6 @@ static void iwl4965_nic_config(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } -int iwl4965_hw_nic_init(struct iwl_priv *priv) -{ - unsigned long flags; - struct iwl_rx_queue *rxq = &priv->rxq; - int ret; - - /* nic_init */ - priv->cfg->ops->lib->apm_ops.init(priv); - - spin_lock_irqsave(&priv->lock, flags); - iwl_write32(priv, CSR_INT_COALESCING, 512 / 32); - spin_unlock_irqrestore(&priv->lock, flags); - - ret = priv->cfg->ops->lib->apm_ops.set_pwr_src(priv, IWL_PWR_SRC_VMAIN); - - priv->cfg->ops->lib->apm_ops.config(priv); - - iwl4965_hw_card_show_info(priv); - - /* end nic_init */ - - /* Allocate the RX queue, or reset if it is already allocated */ - if (!rxq->bd) { - ret = iwl_rx_queue_alloc(priv); - if (ret) { - IWL_ERROR("Unable to initialize Rx queue\n"); - return -ENOMEM; - } - } else - iwl_rx_queue_reset(priv, rxq); - - iwl_rx_replenish(priv); - - iwl4965_rx_init(priv, rxq); - - spin_lock_irqsave(&priv->lock, flags); - - rxq->need_update = 1; - iwl_rx_queue_update_write_ptr(priv, rxq); - - spin_unlock_irqrestore(&priv->lock, flags); - - /* Allocate and init all Tx and Command queues */ - ret = iwl4965_txq_ctx_reset(priv); - if (ret) - return ret; - - set_bit(STATUS_INIT, &priv->status); - - return 0; -} - int iwl4965_hw_nic_stop_master(struct iwl_priv *priv) { int rc = 0; @@ -745,7 +534,7 @@ void iwl4965_hw_txq_ctx_stop(struct iwl_priv *priv) } /* Deallocate memory for all Tx queues */ - iwl4965_hw_txq_ctx_free(priv); + iwl_hw_txq_ctx_free(priv); } int iwl4965_hw_nic_reset(struct iwl_priv *priv) @@ -1199,82 +988,6 @@ int iwl4965_hw_set_hw_params(struct iwl_priv *priv) return 0; } -/** - * iwl4965_hw_txq_ctx_free - Free TXQ Context - * - * Destroy all TX DMA queues and structures - */ -void iwl4965_hw_txq_ctx_free(struct iwl_priv *priv) -{ - int txq_id; - - /* Tx queues */ - for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) - iwl4965_tx_queue_free(priv, &priv->txq[txq_id]); - - /* Keep-warm buffer */ - iwl4965_kw_free(priv); -} - -/** - * iwl4965_hw_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr] - * - * Does NOT advance any TFD circular buffer read/write indexes - * Does NOT free the TFD itself (which is within circular buffer) - */ -int iwl4965_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl4965_tx_queue *txq) -{ - struct iwl4965_tfd_frame *bd_tmp = (struct iwl4965_tfd_frame *)&txq->bd[0]; - struct iwl4965_tfd_frame *bd = &bd_tmp[txq->q.read_ptr]; - struct pci_dev *dev = priv->pci_dev; - int i; - int counter = 0; - int index, is_odd; - - /* Host command buffers stay mapped in memory, nothing to clean */ - if (txq->q.id == IWL_CMD_QUEUE_NUM) - return 0; - - /* Sanity check on number of chunks */ - counter = IWL_GET_BITS(*bd, num_tbs); - if (counter > MAX_NUM_OF_TBS) { - IWL_ERROR("Too many chunks: %i\n", counter); - /* @todo issue fatal error, it is quite serious situation */ - return 0; - } - - /* Unmap chunks, if any. - * TFD info for odd chunks is different format than for even chunks. */ - for (i = 0; i < counter; i++) { - index = i / 2; - is_odd = i & 0x1; - - if (is_odd) - pci_unmap_single( - dev, - IWL_GET_BITS(bd->pa[index], tb2_addr_lo16) | - (IWL_GET_BITS(bd->pa[index], - tb2_addr_hi20) << 16), - IWL_GET_BITS(bd->pa[index], tb2_len), - PCI_DMA_TODEVICE); - - else if (i > 0) - pci_unmap_single(dev, - le32_to_cpu(bd->pa[index].tb1_addr), - IWL_GET_BITS(bd->pa[index], tb1_len), - PCI_DMA_TODEVICE); - - /* Free SKB, if any, for this chunk */ - if (txq->txb[txq->q.read_ptr].skb[i]) { - struct sk_buff *skb = txq->txb[txq->q.read_ptr].skb[i]; - - dev_kfree_skb(skb); - txq->txb[txq->q.read_ptr].skb[i] = NULL; - } - } - return 0; -} - /* set card power command */ static int iwl4965_set_power(struct iwl_priv *priv, void *cmd) @@ -2240,46 +1953,11 @@ unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, return (sizeof(*tx_beacon_cmd) + frame_size); } -/* - * Tell 4965 where to find circular buffer of Tx Frame Descriptors for - * given Tx queue, and enable the DMA channel used for that queue. - * - * 4965 supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA - * channels supported in hardware. - */ -int iwl4965_hw_tx_queue_init(struct iwl_priv *priv, struct iwl4965_tx_queue *txq) -{ - int rc; - unsigned long flags; - int txq_id = txq->q.id; - - spin_lock_irqsave(&priv->lock, flags); - rc = iwl_grab_nic_access(priv); - if (rc) { - spin_unlock_irqrestore(&priv->lock, flags); - return rc; - } - - /* Circular buffer (TFD queue in DRAM) physical base address */ - iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id), - txq->q.dma_addr >> 8); - - /* Enable DMA channel, using same id as for TFD queue */ - iwl_write_direct32( - priv, FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), - FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | - FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->lock, flags); - - return 0; -} - int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr, dma_addr_t addr, u16 len) { int index, is_odd; - struct iwl4965_tfd_frame *tfd = ptr; + struct iwl_tfd_frame *tfd = ptr; u32 num_tbs = IWL_GET_BITS(*tfd, num_tbs); /* Each TFD can point to a maximum 20 Tx buffers */ @@ -2309,18 +1987,6 @@ int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr, return 0; } -static void iwl4965_hw_card_show_info(struct iwl_priv *priv) -{ - u16 hw_version = iwl_eeprom_query16(priv, EEPROM_4965_BOARD_REVISION); - - IWL_DEBUG_INFO("4965ABGN HW Version %u.%u.%u\n", - ((hw_version >> 8) & 0x0F), - ((hw_version >> 8) >> 4), (hw_version & 0x00FF)); - - IWL_DEBUG_INFO("4965ABGN PBA Number %.16s\n", - &priv->eeprom[EEPROM_4965_BOARD_PBA]); -} - static int iwl4965_alloc_shared_mem(struct iwl_priv *priv) { priv->shared_virt = pci_alloc_consistent(priv->pci_dev, @@ -4054,7 +3720,6 @@ static struct iwl_lib_ops iwl4965_lib = { .alloc_shared_mem = iwl4965_alloc_shared_mem, .free_shared_mem = iwl4965_free_shared_mem, .txq_update_byte_cnt_tbl = iwl4965_txq_update_byte_cnt_tbl, - .hw_nic_init = iwl4965_hw_nic_init, .disable_tx_fifo = iwl4965_disable_tx_fifo, .rx_handler_setup = iwl4965_rx_handler_setup, .is_valid_rtc_data_addr = iwl4965_hw_valid_rtc_data_addr, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 2ff27a01cf6..4ba860741f8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -121,6 +121,101 @@ void iwl_hw_detect(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_hw_detect); +/* Tell nic where to find the "keep warm" buffer */ +int iwl_kw_init(struct iwl_priv *priv) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&priv->lock, flags); + ret = iwl_grab_nic_access(priv); + if (ret) + goto out; + + iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, + priv->kw.dma_addr >> 4); + iwl_release_nic_access(priv); +out: + spin_unlock_irqrestore(&priv->lock, flags); + return ret; +} + +int iwl_kw_alloc(struct iwl_priv *priv) +{ + struct pci_dev *dev = priv->pci_dev; + struct iwl4965_kw *kw = &priv->kw; + + kw->size = IWL4965_KW_SIZE; /* TBW need set somewhere else */ + kw->v_addr = pci_alloc_consistent(dev, kw->size, &kw->dma_addr); + if (!kw->v_addr) + return -ENOMEM; + + return 0; +} + +/** + * iwl_kw_free - Free the "keep warm" buffer + */ +void iwl_kw_free(struct iwl_priv *priv) +{ + struct pci_dev *dev = priv->pci_dev; + struct iwl4965_kw *kw = &priv->kw; + + if (kw->v_addr) { + pci_free_consistent(dev, kw->size, kw->v_addr, kw->dma_addr); + memset(kw, 0, sizeof(*kw)); + } +} + +int iwl_hw_nic_init(struct iwl_priv *priv) +{ + unsigned long flags; + struct iwl_rx_queue *rxq = &priv->rxq; + int ret; + + /* nic_init */ + priv->cfg->ops->lib->apm_ops.init(priv); + + spin_lock_irqsave(&priv->lock, flags); + iwl_write32(priv, CSR_INT_COALESCING, 512 / 32); + spin_unlock_irqrestore(&priv->lock, flags); + + ret = priv->cfg->ops->lib->apm_ops.set_pwr_src(priv, IWL_PWR_SRC_VMAIN); + + priv->cfg->ops->lib->apm_ops.config(priv); + + /* Allocate the RX queue, or reset if it is already allocated */ + if (!rxq->bd) { + ret = iwl_rx_queue_alloc(priv); + if (ret) { + IWL_ERROR("Unable to initialize Rx queue\n"); + return -ENOMEM; + } + } else + iwl_rx_queue_reset(priv, rxq); + + iwl_rx_replenish(priv); + + iwl_rx_init(priv, rxq); + + spin_lock_irqsave(&priv->lock, flags); + + rxq->need_update = 1; + iwl_rx_queue_update_write_ptr(priv, rxq); + + spin_unlock_irqrestore(&priv->lock, flags); + + /* Allocate and init all Tx and Command queues */ + ret = iwl_txq_ctx_reset(priv); + if (ret) + return ret; + + set_bit(STATUS_INIT, &priv->status); + + return 0; +} +EXPORT_SYMBOL(iwl_hw_nic_init); + /** * iwlcore_clear_stations_table - Clear the driver's station table * diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index c29f8b34712..3a75dc6e35a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -108,8 +108,6 @@ struct iwl_lib_ops { u16 byte_cnt); /* setup Rx handler */ void (*rx_handler_setup)(struct iwl_priv *priv); - /* nic init */ - int (*hw_nic_init)(struct iwl_priv *priv); /* nic Tx fifo handling */ int (*disable_tx_fifo)(struct iwl_priv *priv); /* alive notification */ @@ -178,6 +176,12 @@ int iwl_setup(struct iwl_priv *priv); void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info); u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, struct ieee80211_ht_info *sta_ht_inf); +int iwl_hw_nic_init(struct iwl_priv *priv); + +/* "keep warm" functions */ +int iwl_kw_init(struct iwl_priv *priv); +int iwl_kw_alloc(struct iwl_priv *priv); +void iwl_kw_free(struct iwl_priv *priv); /***************************************************** * RX @@ -189,11 +193,20 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q); void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq); void iwl_rx_replenish(struct iwl_priv *priv); +int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq); /* FIXME: remove when TX is moved to iwl core */ int iwl_rx_queue_restock(struct iwl_priv *priv); int iwl_rx_queue_space(const struct iwl_rx_queue *q); void iwl_rx_allocate(struct iwl_priv *priv); +/***************************************************** +* TX +******************************************************/ +int iwl_txq_ctx_reset(struct iwl_priv *priv); +/* FIXME: remove when free Tx is fully merged into iwlcore */ +int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl4965_tx_queue *txq); +void iwl_hw_txq_ctx_free(struct iwl_priv *priv); + /***************************************************** * S e n d i n g H o s t C o m m a n d s * *****************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 23cae4c1345..e730583d88c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -138,7 +138,7 @@ struct iwl4965_tx_info { */ struct iwl4965_tx_queue { struct iwl4965_queue q; - struct iwl4965_tfd_frame *bd; + struct iwl_tfd_frame *bd; struct iwl_cmd *cmd; dma_addr_t dma_addr_cmd; struct iwl4965_tx_info *txb; @@ -649,9 +649,6 @@ extern int iwl4965_is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header); extern int iwl4965_calc_db_from_ratio(int sig_ratio); extern int iwl4965_calc_sig_qual(int rssi_dbm, int noise_dbm); -extern int iwl4965_tx_queue_init(struct iwl_priv *priv, - struct iwl4965_tx_queue *txq, int count, u32 id); -extern void iwl4965_tx_queue_free(struct iwl_priv *priv, struct iwl4965_tx_queue *txq); extern unsigned int iwl4965_fill_beacon_frame(struct iwl_priv *priv, struct ieee80211_hdr *hdr, const u8 *dest, int left); @@ -692,17 +689,12 @@ extern void iwl4965_hw_setup_deferred_work(struct iwl_priv *priv); extern void iwl4965_hw_cancel_deferred_work(struct iwl_priv *priv); extern int iwl4965_hw_rxq_stop(struct iwl_priv *priv); extern int iwl4965_hw_set_hw_params(struct iwl_priv *priv); -extern int iwl4965_hw_nic_init(struct iwl_priv *priv); extern int iwl4965_hw_nic_stop_master(struct iwl_priv *priv); -extern void iwl4965_hw_txq_ctx_free(struct iwl_priv *priv); extern void iwl4965_hw_txq_ctx_stop(struct iwl_priv *priv); extern int iwl4965_hw_nic_reset(struct iwl_priv *priv); extern int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *tfd, dma_addr_t addr, u16 len); -extern int iwl4965_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl4965_tx_queue *txq); extern int iwl4965_hw_get_temperature(struct iwl_priv *priv); -extern int iwl4965_hw_tx_queue_init(struct iwl_priv *priv, - struct iwl4965_tx_queue *txq); extern unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, struct iwl4965_frame *frame, u8 rate); extern int iwl4965_hw_get_rx_read(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 667b592e6ad..171751e417d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -369,3 +369,55 @@ void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq) } EXPORT_SYMBOL(iwl_rx_queue_reset); +int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) +{ + int ret; + unsigned long flags; + unsigned int rb_size; + + spin_lock_irqsave(&priv->lock, flags); + ret = iwl_grab_nic_access(priv); + if (ret) { + spin_unlock_irqrestore(&priv->lock, flags); + return ret; + } + + if (priv->cfg->mod_params->amsdu_size_8K) + rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K; + else + rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K; + + /* Stop Rx DMA */ + iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); + + /* Reset driver's Rx queue write index */ + iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0); + + /* Tell device where to find RBD circular buffer in DRAM */ + iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG, + rxq->dma_addr >> 8); + + /* Tell device where in DRAM to update its Rx status */ + iwl_write_direct32(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG, + (priv->shared_phys + + offsetof(struct iwl4965_shared, rb_closed)) >> 4); + + /* Enable Rx DMA, enable host interrupt, Rx buffer size 4k, 256 RBDs */ + iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, + FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL | + FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL | + rb_size | + /* 0x10 << 4 | */ + (RX_QUEUE_SIZE_LOG << + FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT)); + + /* + * iwl_write32(priv,CSR_INT_COAL_REG,0); + */ + + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c new file mode 100644 index 00000000000..ade247e6310 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -0,0 +1,374 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project, as well + * as portions of the ieee80211 subsystem header files. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#include +#include "iwl-eeprom.h" +#include "iwl-dev.h" +#include "iwl-core.h" +#include "iwl-sta.h" +#include "iwl-io.h" +#include "iwl-helpers.h" + +/** + * iwl_hw_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr] + * + * Does NOT advance any TFD circular buffer read/write indexes + * Does NOT free the TFD itself (which is within circular buffer) + */ +int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl4965_tx_queue *txq) +{ + struct iwl_tfd_frame *bd_tmp = (struct iwl_tfd_frame *)&txq->bd[0]; + struct iwl_tfd_frame *bd = &bd_tmp[txq->q.read_ptr]; + struct pci_dev *dev = priv->pci_dev; + int i; + int counter = 0; + int index, is_odd; + + /* Host command buffers stay mapped in memory, nothing to clean */ + if (txq->q.id == IWL_CMD_QUEUE_NUM) + return 0; + + /* Sanity check on number of chunks */ + counter = IWL_GET_BITS(*bd, num_tbs); + if (counter > MAX_NUM_OF_TBS) { + IWL_ERROR("Too many chunks: %i\n", counter); + /* @todo issue fatal error, it is quite serious situation */ + return 0; + } + + /* Unmap chunks, if any. + * TFD info for odd chunks is different format than for even chunks. */ + for (i = 0; i < counter; i++) { + index = i / 2; + is_odd = i & 0x1; + + if (is_odd) + pci_unmap_single( + dev, + IWL_GET_BITS(bd->pa[index], tb2_addr_lo16) | + (IWL_GET_BITS(bd->pa[index], + tb2_addr_hi20) << 16), + IWL_GET_BITS(bd->pa[index], tb2_len), + PCI_DMA_TODEVICE); + + else if (i > 0) + pci_unmap_single(dev, + le32_to_cpu(bd->pa[index].tb1_addr), + IWL_GET_BITS(bd->pa[index], tb1_len), + PCI_DMA_TODEVICE); + + /* Free SKB, if any, for this chunk */ + if (txq->txb[txq->q.read_ptr].skb[i]) { + struct sk_buff *skb = txq->txb[txq->q.read_ptr].skb[i]; + + dev_kfree_skb(skb); + txq->txb[txq->q.read_ptr].skb[i] = NULL; + } + } + return 0; +} +EXPORT_SYMBOL(iwl_hw_txq_free_tfd); + +/** + * iwl_tx_queue_free - Deallocate DMA queue. + * @txq: Transmit queue to deallocate. + * + * Empty queue by removing and destroying all BD's. + * Free all buffers. + * 0-fill, but do not free "txq" descriptor structure. + */ +static void iwl_tx_queue_free(struct iwl_priv *priv, + struct iwl4965_tx_queue *txq) +{ + struct iwl4965_queue *q = &txq->q; + struct pci_dev *dev = priv->pci_dev; + int len; + + if (q->n_bd == 0) + return; + + /* first, empty all BD's */ + for (; q->write_ptr != q->read_ptr; + q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) + iwl_hw_txq_free_tfd(priv, txq); + + len = sizeof(struct iwl_cmd) * q->n_window; + if (q->id == IWL_CMD_QUEUE_NUM) + len += IWL_MAX_SCAN_SIZE; + + /* De-alloc array of command/tx buffers */ + pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd); + + /* De-alloc circular buffer of TFDs */ + if (txq->q.n_bd) + pci_free_consistent(dev, sizeof(struct iwl_tfd_frame) * + txq->q.n_bd, txq->bd, txq->q.dma_addr); + + /* De-alloc array of per-TFD driver data */ + kfree(txq->txb); + txq->txb = NULL; + + /* 0-fill queue descriptor structure */ + memset(txq, 0, sizeof(*txq)); +} + +/** + * iwl_hw_txq_ctx_free - Free TXQ Context + * + * Destroy all TX DMA queues and structures + */ +void iwl_hw_txq_ctx_free(struct iwl_priv *priv) +{ + int txq_id; + + /* Tx queues */ + for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) + iwl_tx_queue_free(priv, &priv->txq[txq_id]); + + /* Keep-warm buffer */ + iwl_kw_free(priv); +} +EXPORT_SYMBOL(iwl_hw_txq_ctx_free); + +/** + * iwl_queue_init - Initialize queue's high/low-water and read/write indexes + */ +static int iwl_queue_init(struct iwl_priv *priv, struct iwl4965_queue *q, + int count, int slots_num, u32 id) +{ + q->n_bd = count; + q->n_window = slots_num; + q->id = id; + + /* count must be power-of-two size, otherwise iwl_queue_inc_wrap + * and iwl_queue_dec_wrap are broken. */ + BUG_ON(!is_power_of_2(count)); + + /* slots_num must be power-of-two size, otherwise + * get_cmd_index is broken. */ + BUG_ON(!is_power_of_2(slots_num)); + + q->low_mark = q->n_window / 4; + if (q->low_mark < 4) + q->low_mark = 4; + + q->high_mark = q->n_window / 8; + if (q->high_mark < 2) + q->high_mark = 2; + + q->write_ptr = q->read_ptr = 0; + + return 0; +} + +/** + * iwl_tx_queue_alloc - Alloc driver data and TFD CB for one Tx/cmd queue + */ +static int iwl_tx_queue_alloc(struct iwl_priv *priv, + struct iwl4965_tx_queue *txq, u32 id) +{ + struct pci_dev *dev = priv->pci_dev; + + /* Driver private data, only for Tx (not command) queues, + * not shared with device. */ + if (id != IWL_CMD_QUEUE_NUM) { + txq->txb = kmalloc(sizeof(txq->txb[0]) * + TFD_QUEUE_SIZE_MAX, GFP_KERNEL); + if (!txq->txb) { + IWL_ERROR("kmalloc for auxiliary BD " + "structures failed\n"); + goto error; + } + } else + txq->txb = NULL; + + /* Circular buffer of transmit frame descriptors (TFDs), + * shared with device */ + txq->bd = pci_alloc_consistent(dev, + sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX, + &txq->q.dma_addr); + + if (!txq->bd) { + IWL_ERROR("pci_alloc_consistent(%zd) failed\n", + sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX); + goto error; + } + txq->q.id = id; + + return 0; + + error: + kfree(txq->txb); + txq->txb = NULL; + + return -ENOMEM; +} + +/* + * Tell nic where to find circular buffer of Tx Frame Descriptors for + * given Tx queue, and enable the DMA channel used for that queue. + * + * 4965 supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA + * channels supported in hardware. + */ +static int iwl_hw_tx_queue_init(struct iwl_priv *priv, + struct iwl4965_tx_queue *txq) +{ + int rc; + unsigned long flags; + int txq_id = txq->q.id; + + spin_lock_irqsave(&priv->lock, flags); + rc = iwl_grab_nic_access(priv); + if (rc) { + spin_unlock_irqrestore(&priv->lock, flags); + return rc; + } + + /* Circular buffer (TFD queue in DRAM) physical base address */ + iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id), + txq->q.dma_addr >> 8); + + /* Enable DMA channel, using same id as for TFD queue */ + iwl_write_direct32( + priv, FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL); + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +/** + * iwl_tx_queue_init - Allocate and initialize one tx/cmd queue + */ +static int iwl_tx_queue_init(struct iwl_priv *priv, + struct iwl4965_tx_queue *txq, + int slots_num, u32 txq_id) +{ + struct pci_dev *dev = priv->pci_dev; + int len; + int rc = 0; + + /* + * Alloc buffer array for commands (Tx or other types of commands). + * For the command queue (#4), allocate command space + one big + * command for scan, since scan command is very huge; the system will + * not have two scans at the same time, so only one is needed. + * For normal Tx queues (all other queues), no super-size command + * space is needed. + */ + len = sizeof(struct iwl_cmd) * slots_num; + if (txq_id == IWL_CMD_QUEUE_NUM) + len += IWL_MAX_SCAN_SIZE; + txq->cmd = pci_alloc_consistent(dev, len, &txq->dma_addr_cmd); + if (!txq->cmd) + return -ENOMEM; + + /* Alloc driver data array and TFD circular buffer */ + rc = iwl_tx_queue_alloc(priv, txq, txq_id); + if (rc) { + pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd); + + return -ENOMEM; + } + txq->need_update = 0; + + /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise + * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */ + BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1)); + + /* Initialize queue's high/low-water marks, and head/tail indexes */ + iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id); + + /* Tell device where to find queue */ + iwl_hw_tx_queue_init(priv, txq); + + return 0; +} + +/** + * iwl_txq_ctx_reset - Reset TX queue context + * Destroys all DMA structures and initialise them again + * + * @param priv + * @return error code + */ +int iwl_txq_ctx_reset(struct iwl_priv *priv) +{ + int ret = 0; + int txq_id, slots_num; + + iwl_kw_free(priv); + + /* Free all tx/cmd queues and keep-warm buffer */ + iwl_hw_txq_ctx_free(priv); + + /* Alloc keep-warm buffer */ + ret = iwl_kw_alloc(priv); + if (ret) { + IWL_ERROR("Keep Warm allocation failed"); + goto error_kw; + } + + /* Turn off all Tx DMA fifos */ + ret = priv->cfg->ops->lib->disable_tx_fifo(priv); + if (unlikely(ret)) + goto error_reset; + + /* Tell nic where to find the keep-warm buffer */ + ret = iwl_kw_init(priv); + if (ret) { + IWL_ERROR("kw_init failed\n"); + goto error_reset; + } + + /* Alloc and init all (default 16) Tx queues, + * including the command queue (#4) */ + for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) { + slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ? + TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; + ret = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num, + txq_id); + if (ret) { + IWL_ERROR("Tx %d queue init failed\n", txq_id); + goto error; + } + } + + return ret; + + error: + iwl_hw_txq_ctx_free(priv); + error_reset: + iwl_kw_free(priv); + error_kw: + return ret; +} diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index ad45249454f..8d06cf1a319 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -207,173 +207,6 @@ static inline u8 get_cmd_index(struct iwl4965_queue *q, u32 index, int is_huge) return index & (q->n_window - 1); } -/** - * iwl4965_queue_init - Initialize queue's high/low-water and read/write indexes - */ -static int iwl4965_queue_init(struct iwl_priv *priv, struct iwl4965_queue *q, - int count, int slots_num, u32 id) -{ - q->n_bd = count; - q->n_window = slots_num; - q->id = id; - - /* count must be power-of-two size, otherwise iwl_queue_inc_wrap - * and iwl_queue_dec_wrap are broken. */ - BUG_ON(!is_power_of_2(count)); - - /* slots_num must be power-of-two size, otherwise - * get_cmd_index is broken. */ - BUG_ON(!is_power_of_2(slots_num)); - - q->low_mark = q->n_window / 4; - if (q->low_mark < 4) - q->low_mark = 4; - - q->high_mark = q->n_window / 8; - if (q->high_mark < 2) - q->high_mark = 2; - - q->write_ptr = q->read_ptr = 0; - - return 0; -} - -/** - * iwl4965_tx_queue_alloc - Alloc driver data and TFD CB for one Tx/cmd queue - */ -static int iwl4965_tx_queue_alloc(struct iwl_priv *priv, - struct iwl4965_tx_queue *txq, u32 id) -{ - struct pci_dev *dev = priv->pci_dev; - - /* Driver private data, only for Tx (not command) queues, - * not shared with device. */ - if (id != IWL_CMD_QUEUE_NUM) { - txq->txb = kmalloc(sizeof(txq->txb[0]) * - TFD_QUEUE_SIZE_MAX, GFP_KERNEL); - if (!txq->txb) { - IWL_ERROR("kmalloc for auxiliary BD " - "structures failed\n"); - goto error; - } - } else - txq->txb = NULL; - - /* Circular buffer of transmit frame descriptors (TFDs), - * shared with device */ - txq->bd = pci_alloc_consistent(dev, - sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX, - &txq->q.dma_addr); - - if (!txq->bd) { - IWL_ERROR("pci_alloc_consistent(%zd) failed\n", - sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX); - goto error; - } - txq->q.id = id; - - return 0; - - error: - if (txq->txb) { - kfree(txq->txb); - txq->txb = NULL; - } - - return -ENOMEM; -} - -/** - * iwl4965_tx_queue_init - Allocate and initialize one tx/cmd queue - */ -int iwl4965_tx_queue_init(struct iwl_priv *priv, - struct iwl4965_tx_queue *txq, int slots_num, u32 txq_id) -{ - struct pci_dev *dev = priv->pci_dev; - int len; - int rc = 0; - - /* - * Alloc buffer array for commands (Tx or other types of commands). - * For the command queue (#4), allocate command space + one big - * command for scan, since scan command is very huge; the system will - * not have two scans at the same time, so only one is needed. - * For normal Tx queues (all other queues), no super-size command - * space is needed. - */ - len = sizeof(struct iwl_cmd) * slots_num; - if (txq_id == IWL_CMD_QUEUE_NUM) - len += IWL_MAX_SCAN_SIZE; - txq->cmd = pci_alloc_consistent(dev, len, &txq->dma_addr_cmd); - if (!txq->cmd) - return -ENOMEM; - - /* Alloc driver data array and TFD circular buffer */ - rc = iwl4965_tx_queue_alloc(priv, txq, txq_id); - if (rc) { - pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd); - - return -ENOMEM; - } - txq->need_update = 0; - - /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise - * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */ - BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1)); - - /* Initialize queue's high/low-water marks, and head/tail indexes */ - iwl4965_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id); - - /* Tell device where to find queue */ - iwl4965_hw_tx_queue_init(priv, txq); - - return 0; -} - -/** - * iwl4965_tx_queue_free - Deallocate DMA queue. - * @txq: Transmit queue to deallocate. - * - * Empty queue by removing and destroying all BD's. - * Free all buffers. - * 0-fill, but do not free "txq" descriptor structure. - */ -void iwl4965_tx_queue_free(struct iwl_priv *priv, struct iwl4965_tx_queue *txq) -{ - struct iwl4965_queue *q = &txq->q; - struct pci_dev *dev = priv->pci_dev; - int len; - - if (q->n_bd == 0) - return; - - /* first, empty all BD's */ - for (; q->write_ptr != q->read_ptr; - q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) - iwl4965_hw_txq_free_tfd(priv, txq); - - len = sizeof(struct iwl_cmd) * q->n_window; - if (q->id == IWL_CMD_QUEUE_NUM) - len += IWL_MAX_SCAN_SIZE; - - /* De-alloc array of command/tx buffers */ - pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd); - - /* De-alloc circular buffer of TFDs */ - if (txq->q.n_bd) - pci_free_consistent(dev, sizeof(struct iwl4965_tfd_frame) * - txq->q.n_bd, txq->bd, txq->q.dma_addr); - - /* De-alloc array of per-TFD driver data */ - if (txq->txb) { - kfree(txq->txb); - txq->txb = NULL; - } - - /* 0-fill queue descriptor structure */ - memset(txq, 0, sizeof(*txq)); -} - const u8 iwl4965_broadcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; /*************** STATION TABLE MANAGEMENT **** @@ -516,7 +349,7 @@ int iwl4965_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) { struct iwl4965_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; struct iwl4965_queue *q = &txq->q; - struct iwl4965_tfd_frame *tfd; + struct iwl_tfd_frame *tfd; u32 *control_flags; struct iwl_cmd *out_cmd; u32 idx; @@ -1931,7 +1764,7 @@ static int iwl4965_tx_skb(struct iwl_priv *priv, struct sk_buff *skb, struct ieee80211_tx_control *ctl) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct iwl4965_tfd_frame *tfd; + struct iwl_tfd_frame *tfd; u32 *control_flags; int txq_id = ctl->queue; struct iwl4965_tx_queue *txq = NULL; @@ -2515,7 +2348,7 @@ int iwl4965_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) if (txq_id != IWL_CMD_QUEUE_NUM) { iwl4965_txstatus_to_ieee(priv, &(txq->txb[txq->q.read_ptr])); - iwl4965_hw_txq_free_tfd(priv, txq); + iwl_hw_txq_free_tfd(priv, txq); } else if (nfreed > 1) { IWL_ERROR("HCMD skipped: index (%d) %d %d\n", index, q->write_ptr, q->read_ptr); @@ -4677,7 +4510,7 @@ static int __iwl4965_up(struct iwl_priv *priv) return ret; } - ret = priv->cfg->ops->lib->hw_nic_init(priv); + ret = iwl_hw_nic_init(priv); if (ret) { IWL_ERROR("Unable to init nic\n"); return ret; @@ -6940,7 +6773,7 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) if (priv->rxq.bd) iwl_rx_queue_free(priv, &priv->rxq); - iwl4965_hw_txq_ctx_free(priv); + iwl_hw_txq_ctx_free(priv); iwlcore_clear_stations_table(priv); iwl_eeprom_free(priv); -- cgit v1.2.3-70-g09d2 From 27aaba0ca099461badb496bf7cde5ab5cdc89b98 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Mon, 5 May 2008 10:22:44 +0800 Subject: iwlwifi: compile iwl-sta into iwlcore This patch moves iwl-sta into iwl-core. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/Makefile | 4 ++-- drivers/net/wireless/iwlwifi/iwl-sta.c | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 85c8bf62d59..5c73eede719 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -1,6 +1,6 @@ obj-$(CONFIG_IWLCORE) += iwlcore.o iwlcore-objs := iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.o -iwlcore-objs += iwl-rx.o iwl-tx.o +iwlcore-objs += iwl-rx.o iwl-tx.o iwl-sta.o iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o iwlcore-$(CONFIG_IWLWIFI_LEDS) += iwl-led.o iwlcore-$(CONFIG_IWLWIFI_RFKILL) += iwl-rfkill.o @@ -11,7 +11,7 @@ iwl3945-objs := iwl3945-base.o iwl-3945.o iwl-3945-rs.o iwl3945-$(CONFIG_IWL3945_LEDS) += iwl-3945-led.o obj-$(CONFIG_IWL4965) += iwl4965.o -iwl4965-objs := iwl4965-base.o iwl-4965.o iwl-4965-rs.o iwl-sta.o +iwl4965-objs := iwl4965-base.o iwl-4965.o iwl-4965-rs.o ifeq ($(CONFIG_IWL5000),y) iwl4965-objs += iwl-5000.o diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 34f54244ed2..f2267047d10 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -170,6 +170,7 @@ int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty) else return 0; } +EXPORT_SYMBOL(iwl_send_static_wepkey_cmd); int iwl_remove_default_wep_key(struct iwl_priv *priv, struct ieee80211_key_conf *keyconf) @@ -190,6 +191,7 @@ int iwl_remove_default_wep_key(struct iwl_priv *priv, return ret; } +EXPORT_SYMBOL(iwl_remove_default_wep_key); int iwl_set_default_wep_key(struct iwl_priv *priv, struct ieee80211_key_conf *keyconf) @@ -217,6 +219,7 @@ int iwl_set_default_wep_key(struct iwl_priv *priv, return ret; } +EXPORT_SYMBOL(iwl_set_default_wep_key); static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv, struct ieee80211_key_conf *keyconf, @@ -391,6 +394,7 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv, spin_unlock_irqrestore(&priv->sta_lock, flags); return ret; } +EXPORT_SYMBOL(iwl_remove_dynamic_key); int iwl_set_dynamic_key(struct iwl_priv *priv, struct ieee80211_key_conf *key, u8 sta_id) @@ -416,6 +420,7 @@ int iwl_set_dynamic_key(struct iwl_priv *priv, return ret; } +EXPORT_SYMBOL(iwl_set_dynamic_key); #ifdef CONFIG_IWLWIFI_DEBUG static void iwl_dump_lq_cmd(struct iwl_priv *priv, -- cgit v1.2.3-70-g09d2 From f3ccc08c8cdeb784087348e67f41a779c787fa0e Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 5 May 2008 10:22:45 +0800 Subject: iwlwifi: move iwl4965_init_alive_start to iwl-4965.c This patch moves iwl_4965_init_alive_start to iwl-4965.c. Signed-off-by: Emmanuel Grumbach Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 97 ++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-core.h | 2 + drivers/net/wireless/iwlwifi/iwl4965-base.c | 101 +--------------------------- 3 files changed, 100 insertions(+), 100 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 319ffe747a7..f56b9a91d78 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -222,6 +222,102 @@ static int iwl4965_load_bsm(struct iwl_priv *priv) return 0; } +/** + * iwl4965_set_ucode_ptrs - Set uCode address location + * + * Tell initialization uCode where to find runtime uCode. + * + * BSM registers initially contain pointers to initialization uCode. + * We need to replace them to load runtime uCode inst and data, + * and to save runtime data when powering down. + */ +static int iwl4965_set_ucode_ptrs(struct iwl_priv *priv) +{ + dma_addr_t pinst; + dma_addr_t pdata; + unsigned long flags; + int ret = 0; + + /* bits 35:4 for 4965 */ + pinst = priv->ucode_code.p_addr >> 4; + pdata = priv->ucode_data_backup.p_addr >> 4; + + spin_lock_irqsave(&priv->lock, flags); + ret = iwl_grab_nic_access(priv); + if (ret) { + spin_unlock_irqrestore(&priv->lock, flags); + return ret; + } + + /* Tell bootstrap uCode where to find image to load */ + iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst); + iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata); + iwl_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG, + priv->ucode_data.len); + + /* Inst bytecount must be last to set up, bit 31 signals uCode + * that all new ptr/size info is in place */ + iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, + priv->ucode_code.len | BSM_DRAM_INST_LOAD); + iwl_release_nic_access(priv); + + spin_unlock_irqrestore(&priv->lock, flags); + + IWL_DEBUG_INFO("Runtime uCode pointers are set.\n"); + + return ret; +} + +/** + * iwl4965_init_alive_start - Called after REPLY_ALIVE notification received + * + * Called after REPLY_ALIVE notification received from "initialize" uCode. + * + * The 4965 "initialize" ALIVE reply contains calibration data for: + * Voltage, temperature, and MIMO tx gain correction, now stored in priv + * (3945 does not contain this data). + * + * Tell "initialize" uCode to go ahead and load the runtime uCode. +*/ +static void iwl4965_init_alive_start(struct iwl_priv *priv) +{ + /* Check alive response for "valid" sign from uCode */ + if (priv->card_alive_init.is_valid != UCODE_VALID_OK) { + /* We had an error bringing up the hardware, so take it + * all the way back down so we can try again */ + IWL_DEBUG_INFO("Initialize Alive failed.\n"); + goto restart; + } + + /* Bootstrap uCode has loaded initialize uCode ... verify inst image. + * This is a paranoid check, because we would not have gotten the + * "initialize" alive if code weren't properly loaded. */ + if (iwl_verify_ucode(priv)) { + /* Runtime instruction load was bad; + * take it all the way back down so we can try again */ + IWL_DEBUG_INFO("Bad \"initialize\" uCode load.\n"); + goto restart; + } + + /* Calculate temperature */ + priv->temperature = iwl4965_get_temperature(priv); + + /* Send pointers to protocol/runtime uCode image ... init code will + * load and launch runtime uCode, which will send us another "Alive" + * notification. */ + IWL_DEBUG_INFO("Initialization Alive received.\n"); + if (iwl4965_set_ucode_ptrs(priv)) { + /* Runtime instruction load won't happen; + * take it all the way back down so we can try again */ + IWL_DEBUG_INFO("Couldn't set up uCode pointers.\n"); + goto restart; + } + return; + +restart: + queue_work(priv->workqueue, &priv->restart); +} + static int is_fat_channel(__le32 rxon_flags) { return (rxon_flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) || @@ -3724,6 +3820,7 @@ static struct iwl_lib_ops iwl4965_lib = { .rx_handler_setup = iwl4965_rx_handler_setup, .is_valid_rtc_data_addr = iwl4965_hw_valid_rtc_data_addr, .alive_notify = iwl4965_alive_notify, + .init_alive_start = iwl4965_init_alive_start, .load_ucode = iwl4965_load_bsm, .apm_ops = { .init = iwl4965_apm_init, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 3a75dc6e35a..08eccdefd72 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -110,6 +110,8 @@ struct iwl_lib_ops { void (*rx_handler_setup)(struct iwl_priv *priv); /* nic Tx fifo handling */ int (*disable_tx_fifo)(struct iwl_priv *priv); + /* alive notification after init uCode load */ + void (*init_alive_start)(struct iwl_priv *priv); /* alive notification */ int (*alive_notify)(struct iwl_priv *priv); /* check validity of rtc data address */ diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 8d06cf1a319..2e976c3881e 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -4162,105 +4162,6 @@ static int iwl4965_read_ucode(struct iwl_priv *priv) return ret; } - -/** - * iwl4965_set_ucode_ptrs - Set uCode address location - * - * Tell initialization uCode where to find runtime uCode. - * - * BSM registers initially contain pointers to initialization uCode. - * We need to replace them to load runtime uCode inst and data, - * and to save runtime data when powering down. - */ -static int iwl4965_set_ucode_ptrs(struct iwl_priv *priv) -{ - dma_addr_t pinst; - dma_addr_t pdata; - int rc = 0; - unsigned long flags; - - /* bits 35:4 for 4965 */ - pinst = priv->ucode_code.p_addr >> 4; - pdata = priv->ucode_data_backup.p_addr >> 4; - - spin_lock_irqsave(&priv->lock, flags); - rc = iwl_grab_nic_access(priv); - if (rc) { - spin_unlock_irqrestore(&priv->lock, flags); - return rc; - } - - /* Tell bootstrap uCode where to find image to load */ - iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst); - iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata); - iwl_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG, - priv->ucode_data.len); - - /* Inst bytecount must be last to set up, bit 31 signals uCode - * that all new ptr/size info is in place */ - iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, - priv->ucode_code.len | BSM_DRAM_INST_LOAD); - - iwl_release_nic_access(priv); - - spin_unlock_irqrestore(&priv->lock, flags); - - IWL_DEBUG_INFO("Runtime uCode pointers are set.\n"); - - return rc; -} - -/** - * iwl4965_init_alive_start - Called after REPLY_ALIVE notification received - * - * Called after REPLY_ALIVE notification received from "initialize" uCode. - * - * The 4965 "initialize" ALIVE reply contains calibration data for: - * Voltage, temperature, and MIMO tx gain correction, now stored in priv - * (3945 does not contain this data). - * - * Tell "initialize" uCode to go ahead and load the runtime uCode. -*/ -static void iwl4965_init_alive_start(struct iwl_priv *priv) -{ - /* Check alive response for "valid" sign from uCode */ - if (priv->card_alive_init.is_valid != UCODE_VALID_OK) { - /* We had an error bringing up the hardware, so take it - * all the way back down so we can try again */ - IWL_DEBUG_INFO("Initialize Alive failed.\n"); - goto restart; - } - - /* Bootstrap uCode has loaded initialize uCode ... verify inst image. - * This is a paranoid check, because we would not have gotten the - * "initialize" alive if code weren't properly loaded. */ - if (iwl_verify_ucode(priv)) { - /* Runtime instruction load was bad; - * take it all the way back down so we can try again */ - IWL_DEBUG_INFO("Bad \"initialize\" uCode load.\n"); - goto restart; - } - - /* Calculate temperature */ - priv->temperature = iwl4965_get_temperature(priv); - - /* Send pointers to protocol/runtime uCode image ... init code will - * load and launch runtime uCode, which will send us another "Alive" - * notification. */ - IWL_DEBUG_INFO("Initialization Alive received.\n"); - if (iwl4965_set_ucode_ptrs(priv)) { - /* Runtime instruction load won't happen; - * take it all the way back down so we can try again */ - IWL_DEBUG_INFO("Couldn't set up uCode pointers.\n"); - goto restart; - } - return; - - restart: - queue_work(priv->workqueue, &priv->restart); -} - - /** * iwl4965_alive_start - called after REPLY_ALIVE notification received * from protocol/runtime uCode (initialization uCode's @@ -4586,7 +4487,7 @@ static void iwl4965_bg_init_alive_start(struct work_struct *data) return; mutex_lock(&priv->mutex); - iwl4965_init_alive_start(priv); + priv->cfg->ops->lib->init_alive_start(priv); mutex_unlock(&priv->mutex); } -- cgit v1.2.3-70-g09d2 From 4419e39b6041b213e49bb13fd40fb267de0eb568 Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Mon, 5 May 2008 10:22:47 +0800 Subject: iwlwifi : Set monitor mode for 4965 The patch leverages mac80211 configure_filter to enable iwl4965 monitor mode. Signed-off-by: Abhijeet Kolekar Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 11 ++++++++- drivers/net/wireless/iwlwifi/iwl-dev.h | 1 + drivers/net/wireless/iwlwifi/iwl4965-base.c | 36 ++++++++++++++++++++++++++++- 3 files changed, 46 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index f56b9a91d78..866a93e3de9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2617,7 +2617,9 @@ static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data, rx_start->byte_count = amsdu->byte_count; rx_end = (__le32 *) (((u8 *) hdr) + len); } - if (len > priv->hw_params.max_pkt_size || len < 16) { + /* In monitor mode allow 802.11 ACk frames (10 bytes) */ + if (len > priv->hw_params.max_pkt_size || + len < ((priv->iw_mode == IEEE80211_IF_TYPE_MNTR) ? 10 : 16)) { IWL_WARNING("byte count out of range [16,4K] : %d\n", len); return; } @@ -2989,6 +2991,13 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv, rx_status.ssi, rx_status.noise, rx_status.signal, (unsigned long long)rx_status.mactime); + + if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { + iwl4965_handle_data_packet(priv, 1, include_phy, + rxb, &rx_status); + return; + } + network_packet = iwl4965_is_network_packet(priv, header); if (network_packet) { priv->last_rx_rssi = rx_status.ssi; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index e730583d88c..25dce14c87d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1163,6 +1163,7 @@ struct iwl_priv { struct work_struct report_work; struct work_struct request_scan; struct work_struct beacon_update; + struct work_struct set_monitor; struct tasklet_struct irq_tasklet; diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 2e976c3881e..88f3554c0fb 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -4539,6 +4539,24 @@ static void iwl4965_bg_rf_kill(struct work_struct *work) mutex_unlock(&priv->mutex); } +static void iwl4965_bg_set_monitor(struct work_struct *work) +{ + struct iwl_priv *priv = container_of(work, + struct iwl_priv, set_monitor); + + IWL_DEBUG(IWL_DL_STATE, "setting monitor mode\n"); + + mutex_lock(&priv->mutex); + + if (!iwl_is_ready(priv)) + IWL_DEBUG(IWL_DL_STATE, "leave - not ready\n"); + else + if (iwl4965_set_mode(priv, IEEE80211_IF_TYPE_MNTR) != 0) + IWL_ERROR("iwl4965_set_mode() failed\n"); + + mutex_unlock(&priv->mutex); +} + #define IWL_SCAN_CHECK_WATCHDOG (7 * HZ) static void iwl4965_bg_scan_check(struct work_struct *data) @@ -5428,7 +5446,22 @@ static void iwl4965_configure_filter(struct ieee80211_hw *hw, * XXX: dummy * see also iwl4965_connection_init_rx_config */ - *total_flags = 0; + struct iwl_priv *priv = hw->priv; + int new_flags = 0; + if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) { + if (*total_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) { + IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n", + IEEE80211_IF_TYPE_MNTR, + changed_flags, *total_flags); + /* queue work 'cuz mac80211 is holding a lock which + * prevents us from issuing (synchronous) f/w cmds */ + queue_work(priv->workqueue, &priv->set_monitor); + new_flags &= FIF_PROMISC_IN_BSS | + FIF_OTHER_BSS | + FIF_ALLMULTI; + } + } + *total_flags = new_flags; } static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw, @@ -6359,6 +6392,7 @@ static void iwl4965_setup_deferred_work(struct iwl_priv *priv) INIT_WORK(&priv->abort_scan, iwl4965_bg_abort_scan); INIT_WORK(&priv->rf_kill, iwl4965_bg_rf_kill); INIT_WORK(&priv->beacon_update, iwl4965_bg_beacon_update); + INIT_WORK(&priv->set_monitor, iwl4965_bg_set_monitor); INIT_DELAYED_WORK(&priv->post_associate, iwl4965_bg_post_associate); INIT_DELAYED_WORK(&priv->init_alive_start, iwl4965_bg_init_alive_start); INIT_DELAYED_WORK(&priv->alive_start, iwl4965_bg_alive_start); -- cgit v1.2.3-70-g09d2 From 5ec0397679f1c1606199cfd6f3e24351891c60c3 Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Mon, 5 May 2008 10:22:48 +0800 Subject: iwlwifi : Set monitor mode for 3945 The patch leverages mac80211 configure_filter to enable iwl3945 monitor mode. Signed-off-by: Abhijeet Kolekar Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.h | 1 + drivers/net/wireless/iwlwifi/iwl3945-base.c | 36 ++++++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index fb96c62ad0f..9fdc1405e85 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -886,6 +886,7 @@ struct iwl3945_priv { struct work_struct report_work; struct work_struct request_scan; struct work_struct beacon_update; + struct work_struct set_monitor; struct tasklet_struct irq_tasklet; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 7040cde8bc2..f021eba41e6 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -6144,6 +6144,24 @@ static void iwl3945_bg_rf_kill(struct work_struct *work) mutex_unlock(&priv->mutex); } +static void iwl3945_bg_set_monitor(struct work_struct *work) +{ + struct iwl3945_priv *priv = container_of(work, + struct iwl3945_priv, set_monitor); + + IWL_DEBUG(IWL_DL_STATE, "setting monitor mode\n"); + + mutex_lock(&priv->mutex); + + if (!iwl3945_is_ready(priv)) + IWL_DEBUG(IWL_DL_STATE, "leave - not ready\n"); + else + if (iwl3945_set_mode(priv, IEEE80211_IF_TYPE_MNTR) != 0) + IWL_ERROR("iwl3945_set_mode() failed\n"); + + mutex_unlock(&priv->mutex); +} + #define IWL_SCAN_CHECK_WATCHDOG (7 * HZ) static void iwl3945_bg_scan_check(struct work_struct *data) @@ -6996,7 +7014,22 @@ static void iwl3945_configure_filter(struct ieee80211_hw *hw, * XXX: dummy * see also iwl3945_connection_init_rx_config */ - *total_flags = 0; + struct iwl3945_priv *priv = hw->priv; + int new_flags = 0; + if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) { + if (*total_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) { + IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n", + IEEE80211_IF_TYPE_MNTR, + changed_flags, *total_flags); + /* queue work 'cuz mac80211 is holding a lock which + * prevents us from issuing (synchronous) f/w cmds */ + queue_work(priv->workqueue, &priv->set_monitor); + new_flags &= FIF_PROMISC_IN_BSS | + FIF_OTHER_BSS | + FIF_ALLMULTI; + } + } + *total_flags = new_flags; } static void iwl3945_mac_remove_interface(struct ieee80211_hw *hw, @@ -7872,6 +7905,7 @@ static void iwl3945_setup_deferred_work(struct iwl3945_priv *priv) INIT_WORK(&priv->abort_scan, iwl3945_bg_abort_scan); INIT_WORK(&priv->rf_kill, iwl3945_bg_rf_kill); INIT_WORK(&priv->beacon_update, iwl3945_bg_beacon_update); + INIT_WORK(&priv->set_monitor, iwl3945_bg_set_monitor); INIT_DELAYED_WORK(&priv->post_associate, iwl3945_bg_post_associate); INIT_DELAYED_WORK(&priv->init_alive_start, iwl3945_bg_init_alive_start); INIT_DELAYED_WORK(&priv->alive_start, iwl3945_bg_alive_start); -- cgit v1.2.3-70-g09d2 From d67f5489d8d9be09bc8e1615ec6c57c3120a731d Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Mon, 5 May 2008 10:22:49 +0800 Subject: iwlwifi: handle shared memory Rx index access This patch splits ucode's and driver's shared memory Rx index access to match 4965 and 5000 offsets. Signed-off-by: Ron Rindjunsky Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 5 ++++- drivers/net/wireless/iwlwifi/iwl-5000.c | 9 +++++++++ drivers/net/wireless/iwlwifi/iwl-core.h | 1 + drivers/net/wireless/iwlwifi/iwl-dev.h | 2 +- drivers/net/wireless/iwlwifi/iwl-rx.c | 3 +-- drivers/net/wireless/iwlwifi/iwl4965-base.c | 2 +- 6 files changed, 17 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 866a93e3de9..a475ecea900 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2006,7 +2006,7 @@ void iwl4965_hw_build_tx_cmd_rate(struct iwl_priv *priv, tx->rate_n_flags = iwl4965_hw_set_rate_n_flags(rate_plcp, rate_flags); } -int iwl4965_hw_get_rx_read(struct iwl_priv *priv) +static int iwl4965_shared_mem_rx_idx(struct iwl_priv *priv) { struct iwl4965_shared *s = priv->shared_virt; return le32_to_cpu(s->rb_closed) & 0xFFF; @@ -2093,6 +2093,8 @@ static int iwl4965_alloc_shared_mem(struct iwl_priv *priv) memset(priv->shared_virt, 0, sizeof(struct iwl4965_shared)); + priv->rb_closed_offset = offsetof(struct iwl4965_shared, rb_closed); + return 0; } @@ -3824,6 +3826,7 @@ static struct iwl_lib_ops iwl4965_lib = { .set_hw_params = iwl4965_hw_set_hw_params, .alloc_shared_mem = iwl4965_alloc_shared_mem, .free_shared_mem = iwl4965_free_shared_mem, + .shared_mem_rx_idx = iwl4965_shared_mem_rx_idx, .txq_update_byte_cnt_tbl = iwl4965_txq_update_byte_cnt_tbl, .disable_tx_fifo = iwl4965_disable_tx_fifo, .rx_handler_setup = iwl4965_rx_handler_setup, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index feffcafe149..d6b91f7e0b1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -362,6 +362,8 @@ static int iwl5000_alloc_shared_mem(struct iwl_priv *priv) memset(priv->shared_virt, 0, sizeof(struct iwl5000_shared)); + priv->rb_closed_offset = offsetof(struct iwl5000_shared, rb_closed); + return 0; } @@ -374,6 +376,12 @@ static void iwl5000_free_shared_mem(struct iwl_priv *priv) priv->shared_phys); } +static int iwl5000_shared_mem_rx_idx(struct iwl_priv *priv) +{ + struct iwl5000_shared *s = priv->shared_virt; + return le32_to_cpu(s->rb_closed) & 0xFFF; +} + /** * iwl5000_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array */ @@ -466,6 +474,7 @@ static struct iwl_lib_ops iwl5000_lib = { .set_hw_params = iwl5000_hw_set_hw_params, .alloc_shared_mem = iwl5000_alloc_shared_mem, .free_shared_mem = iwl5000_free_shared_mem, + .shared_mem_rx_idx = iwl5000_shared_mem_rx_idx, .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, .disable_tx_fifo = iwl5000_disable_tx_fifo, .apm_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 08eccdefd72..77428db6a21 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -103,6 +103,7 @@ struct iwl_lib_ops { /* ucode shared memory */ int (*alloc_shared_mem)(struct iwl_priv *priv); void (*free_shared_mem)(struct iwl_priv *priv); + int (*shared_mem_rx_idx)(struct iwl_priv *priv); void (*txq_update_byte_cnt_tbl)(struct iwl_priv *priv, struct iwl4965_tx_queue *txq, u16 byte_cnt); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 25dce14c87d..1683bee800d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -697,7 +697,6 @@ extern int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *tfd, extern int iwl4965_hw_get_temperature(struct iwl_priv *priv); extern unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, struct iwl4965_frame *frame, u8 rate); -extern int iwl4965_hw_get_rx_read(struct iwl_priv *priv); extern void iwl4965_hw_build_tx_cmd_rate(struct iwl_priv *priv, struct iwl_cmd *cmd, struct ieee80211_tx_control *ctrl, @@ -1138,6 +1137,7 @@ struct iwl_priv { struct iwl_hw_params hw_params; /* driver/uCode shared Tx Byte Counts and Rx status */ void *shared_virt; + int rb_closed_offset; /* Physical Pointer to Tx Byte Counts and Rx status */ dma_addr_t shared_phys; diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 171751e417d..a2eb90d40b7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -399,8 +399,7 @@ int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) /* Tell device where in DRAM to update its Rx status */ iwl_write_direct32(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG, - (priv->shared_phys + - offsetof(struct iwl4965_shared, rb_closed)) >> 4); + (priv->shared_phys + priv->rb_closed_offset) >> 4); /* Enable Rx DMA, enable host interrupt, Rx buffer size 4k, 256 RBDs */ iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 88f3554c0fb..09f2a6383d2 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -3095,7 +3095,7 @@ void iwl_rx_handle(struct iwl_priv *priv) /* uCode's read index (stored in shared DRAM) indicates the last Rx * buffer that the driver may process (last buffer filled by ucode). */ - r = iwl4965_hw_get_rx_read(priv); + r = priv->cfg->ops->lib->shared_mem_rx_idx(priv); i = rxq->read; /* Rx interrupt, but nothing sent from uCode */ -- cgit v1.2.3-70-g09d2 From 164669032ecbf7c9a3bc78adad4e13ee486e975c Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Mon, 5 May 2008 10:22:50 +0800 Subject: iwlwifi: remove 4965 prefix from iwl4965_kw and iwl4965_tx_queue This patch removes the 4965 prefix to form iwl_kw and iwl_tx_queue structs, as they are used mostly in iwlcore now. Signed-off-by: Ron Rindjunsky Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 6 +++--- drivers/net/wireless/iwlwifi/iwl-5000.c | 2 +- drivers/net/wireless/iwlwifi/iwl-core.c | 6 +++--- drivers/net/wireless/iwlwifi/iwl-core.h | 4 ++-- drivers/net/wireless/iwlwifi/iwl-dev.h | 14 +++++++------- drivers/net/wireless/iwlwifi/iwl-tx.c | 11 +++++------ drivers/net/wireless/iwlwifi/iwl4965-base.c | 14 +++++++------- 7 files changed, 28 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index a475ecea900..126ecf7023e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -880,7 +880,7 @@ static void iwl4965_set_wr_ptrs(struct iwl_priv *priv, int txq_id, u32 index) * NOTE: Acquire priv->lock before calling this function ! */ static void iwl4965_tx_queue_set_status(struct iwl_priv *priv, - struct iwl4965_tx_queue *txq, + struct iwl_tx_queue *txq, int tx_fifo_id, int scd_retry) { int txq_id = txq->q.id; @@ -2111,7 +2111,7 @@ static void iwl4965_free_shared_mem(struct iwl_priv *priv) * iwl4965_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array */ static void iwl4965_txq_update_byte_cnt_tbl(struct iwl_priv *priv, - struct iwl4965_tx_queue *txq, + struct iwl_tx_queue *txq, u16 byte_cnt) { int len; @@ -3286,7 +3286,7 @@ static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv, struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl4965_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba; int index; - struct iwl4965_tx_queue *txq = NULL; + struct iwl_tx_queue *txq = NULL; struct iwl_ht_agg *agg; DECLARE_MAC_BUF(mac); diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index d6b91f7e0b1..43b4d20467d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -386,7 +386,7 @@ static int iwl5000_shared_mem_rx_idx(struct iwl_priv *priv) * iwl5000_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array */ static void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv, - struct iwl4965_tx_queue *txq, + struct iwl_tx_queue *txq, u16 byte_cnt) { struct iwl5000_shared *shared_data = priv->shared_virt; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 4ba860741f8..aab0ee6d8af 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -143,9 +143,9 @@ out: int iwl_kw_alloc(struct iwl_priv *priv) { struct pci_dev *dev = priv->pci_dev; - struct iwl4965_kw *kw = &priv->kw; + struct iwl_kw *kw = &priv->kw; - kw->size = IWL4965_KW_SIZE; /* TBW need set somewhere else */ + kw->size = IWL_KW_SIZE; kw->v_addr = pci_alloc_consistent(dev, kw->size, &kw->dma_addr); if (!kw->v_addr) return -ENOMEM; @@ -159,7 +159,7 @@ int iwl_kw_alloc(struct iwl_priv *priv) void iwl_kw_free(struct iwl_priv *priv) { struct pci_dev *dev = priv->pci_dev; - struct iwl4965_kw *kw = &priv->kw; + struct iwl_kw *kw = &priv->kw; if (kw->v_addr) { pci_free_consistent(dev, kw->size, kw->v_addr, kw->dma_addr); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 77428db6a21..83fe0cbf6ae 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -105,7 +105,7 @@ struct iwl_lib_ops { void (*free_shared_mem)(struct iwl_priv *priv); int (*shared_mem_rx_idx)(struct iwl_priv *priv); void (*txq_update_byte_cnt_tbl)(struct iwl_priv *priv, - struct iwl4965_tx_queue *txq, + struct iwl_tx_queue *txq, u16 byte_cnt); /* setup Rx handler */ void (*rx_handler_setup)(struct iwl_priv *priv); @@ -207,7 +207,7 @@ void iwl_rx_allocate(struct iwl_priv *priv); ******************************************************/ int iwl_txq_ctx_reset(struct iwl_priv *priv); /* FIXME: remove when free Tx is fully merged into iwlcore */ -int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl4965_tx_queue *txq); +int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq); void iwl_hw_txq_ctx_free(struct iwl_priv *priv); /***************************************************** diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 1683bee800d..5dccc5a8fa9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -124,7 +124,7 @@ struct iwl4965_tx_info { }; /** - * struct iwl4965_tx_queue - Tx Queue for DMA + * struct iwl_tx_queue - Tx Queue for DMA * @q: generic Rx/Tx queue descriptor * @bd: base of circular buffer of TFDs * @cmd: array of command/Tx buffers @@ -136,7 +136,7 @@ struct iwl4965_tx_info { * A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame * descriptors) and required locking structures. */ -struct iwl4965_tx_queue { +struct iwl_tx_queue { struct iwl4965_queue q; struct iwl_tfd_frame *bd; struct iwl_cmd *cmd; @@ -729,7 +729,7 @@ extern void iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio); * Forward declare iwl-4965.c functions for iwl-base.c */ extern int iwl4965_tx_queue_update_wr_ptr(struct iwl_priv *priv, - struct iwl4965_tx_queue *txq, + struct iwl_tx_queue *txq, u16 byte_cnt); extern void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap); @@ -761,9 +761,9 @@ static inline void iwl4965_init_ht_hw_capab(const struct iwl_priv *priv, #endif /*CONFIG_IWL4965_HT */ /* Structures, enum, and defines specific to the 4965 */ -#define IWL4965_KW_SIZE 0x1000 /*4k */ +#define IWL_KW_SIZE 0x1000 /*4k */ -struct iwl4965_kw { +struct iwl_kw { dma_addr_t dma_addr; void *v_addr; size_t size; @@ -1061,9 +1061,9 @@ struct iwl_priv { /* Rx and Tx DMA processing queues */ struct iwl_rx_queue rxq; - struct iwl4965_tx_queue txq[IWL_MAX_NUM_QUEUES]; + struct iwl_tx_queue txq[IWL_MAX_NUM_QUEUES]; unsigned long txq_ctx_active_msk; - struct iwl4965_kw kw; /* keep warm address */ + struct iwl_kw kw; /* keep warm address */ u32 scd_base_addr; /* scheduler sram base address */ unsigned long status; diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index ade247e6310..a1e03ccd514 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -41,7 +41,7 @@ * Does NOT advance any TFD circular buffer read/write indexes * Does NOT free the TFD itself (which is within circular buffer) */ -int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl4965_tx_queue *txq) +int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) { struct iwl_tfd_frame *bd_tmp = (struct iwl_tfd_frame *)&txq->bd[0]; struct iwl_tfd_frame *bd = &bd_tmp[txq->q.read_ptr]; @@ -103,8 +103,7 @@ EXPORT_SYMBOL(iwl_hw_txq_free_tfd); * Free all buffers. * 0-fill, but do not free "txq" descriptor structure. */ -static void iwl_tx_queue_free(struct iwl_priv *priv, - struct iwl4965_tx_queue *txq) +static void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq) { struct iwl4965_queue *q = &txq->q; struct pci_dev *dev = priv->pci_dev; @@ -191,7 +190,7 @@ static int iwl_queue_init(struct iwl_priv *priv, struct iwl4965_queue *q, * iwl_tx_queue_alloc - Alloc driver data and TFD CB for one Tx/cmd queue */ static int iwl_tx_queue_alloc(struct iwl_priv *priv, - struct iwl4965_tx_queue *txq, u32 id) + struct iwl_tx_queue *txq, u32 id) { struct pci_dev *dev = priv->pci_dev; @@ -238,7 +237,7 @@ static int iwl_tx_queue_alloc(struct iwl_priv *priv, * channels supported in hardware. */ static int iwl_hw_tx_queue_init(struct iwl_priv *priv, - struct iwl4965_tx_queue *txq) + struct iwl_tx_queue *txq) { int rc; unsigned long flags; @@ -270,7 +269,7 @@ static int iwl_hw_tx_queue_init(struct iwl_priv *priv, * iwl_tx_queue_init - Allocate and initialize one tx/cmd queue */ static int iwl_tx_queue_init(struct iwl_priv *priv, - struct iwl4965_tx_queue *txq, + struct iwl_tx_queue *txq, int slots_num, u32 txq_id) { struct pci_dev *dev = priv->pci_dev; diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 09f2a6383d2..45bbce7f66a 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -54,7 +54,7 @@ #include "iwl-calib.h" static int iwl4965_tx_queue_update_write_ptr(struct iwl_priv *priv, - struct iwl4965_tx_queue *txq); + struct iwl_tx_queue *txq); /****************************************************************************** * @@ -347,7 +347,7 @@ u8 iwl4965_add_station_flags(struct iwl_priv *priv, const u8 *addr, */ int iwl4965_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) { - struct iwl4965_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; + struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; struct iwl4965_queue *q = &txq->q; struct iwl_tfd_frame *tfd; u32 *control_flags; @@ -1767,7 +1767,7 @@ static int iwl4965_tx_skb(struct iwl_priv *priv, struct iwl_tfd_frame *tfd; u32 *control_flags; int txq_id = ctl->queue; - struct iwl4965_tx_queue *txq = NULL; + struct iwl_tx_queue *txq = NULL; struct iwl4965_queue *q = NULL; dma_addr_t phys_addr; dma_addr_t txcmd_phys; @@ -2331,7 +2331,7 @@ static void iwl4965_txstatus_to_ieee(struct iwl_priv *priv, */ int iwl4965_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) { - struct iwl4965_tx_queue *txq = &priv->txq[txq_id]; + struct iwl_tx_queue *txq = &priv->txq[txq_id]; struct iwl4965_queue *q = &txq->q; int nfreed = 0; @@ -2531,7 +2531,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, u16 sequence = le16_to_cpu(pkt->hdr.sequence); int txq_id = SEQ_TO_QUEUE(sequence); int index = SEQ_TO_INDEX(sequence); - struct iwl4965_tx_queue *txq = &priv->txq[txq_id]; + struct iwl_tx_queue *txq = &priv->txq[txq_id]; struct ieee80211_tx_status *tx_status; struct iwl4965_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; u32 status = le32_to_cpu(tx_resp->status); @@ -3273,7 +3273,7 @@ int iwl4965_calc_sig_qual(int rssi_dbm, int noise_dbm) * iwl4965_tx_queue_update_write_ptr - Send new write index to hardware */ static int iwl4965_tx_queue_update_write_ptr(struct iwl_priv *priv, - struct iwl4965_tx_queue *txq) + struct iwl_tx_queue *txq) { u32 reg = 0; int rc = 0; @@ -5783,7 +5783,7 @@ static int iwl4965_mac_get_tx_stats(struct ieee80211_hw *hw, { struct iwl_priv *priv = hw->priv; int i, avail; - struct iwl4965_tx_queue *txq; + struct iwl_tx_queue *txq; struct iwl4965_queue *q; unsigned long flags; -- cgit v1.2.3-70-g09d2 From 1b73af8284c3fcbb65eefb9141237b7e45cedd21 Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Mon, 5 May 2008 10:22:51 +0800 Subject: iwlwifi: fix spinlock used before initialized The patch fixes spinlock priv->lock (apm_ops.init) is used before it has been initialized. Signed-off-by: Ron Rindjunsky Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 3 --- drivers/net/wireless/iwlwifi/iwl-core.c | 3 +-- 2 files changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 126ecf7023e..0b441383050 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -489,10 +489,8 @@ static int iwl4965_disable_tx_fifo(struct iwl_priv *priv) static int iwl4965_apm_init(struct iwl_priv *priv) { - unsigned long flags; int ret = 0; - spin_lock_irqsave(&priv->lock, flags); iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); @@ -524,7 +522,6 @@ static int iwl4965_apm_init(struct iwl_priv *priv) iwl_release_nic_access(priv); out: - spin_unlock_irqrestore(&priv->lock, flags); return ret; } diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index aab0ee6d8af..7759e63b2bc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -174,9 +174,8 @@ int iwl_hw_nic_init(struct iwl_priv *priv) int ret; /* nic_init */ - priv->cfg->ops->lib->apm_ops.init(priv); - spin_lock_irqsave(&priv->lock, flags); + priv->cfg->ops->lib->apm_ops.init(priv); iwl_write32(priv, CSR_INT_COALESCING, 512 / 32); spin_unlock_irqrestore(&priv->lock, flags); -- cgit v1.2.3-70-g09d2 From 5d9276daa4c489e9c37c0f0cda915ece632f3cf1 Mon Sep 17 00:00:00 2001 From: Paulius Zaleckas Date: Mon, 5 May 2008 22:38:34 +0300 Subject: airo: use netstats in net_device structure Use net_device_stats from net_device structure instead of local. Changed airo_read_stats function parameter to net_device. Signed-off-by: Paulius Zaleckas Signed-off-by: John W. Linville --- drivers/net/wireless/airo.c | 57 +++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 45f47c1c0a3..8a78283e860 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -1148,7 +1148,6 @@ static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm); static void airo_networks_free(struct airo_info *ai); struct airo_info { - struct net_device_stats stats; struct net_device *dev; struct list_head dev_list; /* Note, we can have MAX_FIDS outstanding. FIDs are 16-bits, so we @@ -1924,7 +1923,7 @@ static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) { if (npacks >= MAXTXQ - 1) { netif_stop_queue (dev); if (npacks > MAXTXQ) { - ai->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; return 1; } skb_queue_tail (&ai->txq, skb); @@ -2044,13 +2043,13 @@ static void get_tx_error(struct airo_info *ai, s32 fid) bap_read(ai, &status, 2, BAP0); } if (le16_to_cpu(status) & 2) /* Too many retries */ - ai->stats.tx_aborted_errors++; + ai->dev->stats.tx_aborted_errors++; if (le16_to_cpu(status) & 4) /* Transmit lifetime exceeded */ - ai->stats.tx_heartbeat_errors++; + ai->dev->stats.tx_heartbeat_errors++; if (le16_to_cpu(status) & 8) /* Aid fail */ { } if (le16_to_cpu(status) & 0x10) /* MAC disabled */ - ai->stats.tx_carrier_errors++; + ai->dev->stats.tx_carrier_errors++; if (le16_to_cpu(status) & 0x20) /* Association lost */ { } /* We produce a TXDROP event only for retry or lifetime @@ -2102,7 +2101,7 @@ static void airo_end_xmit(struct net_device *dev) { for (; i < MAX_FIDS / 2 && (priv->fids[i] & 0xffff0000); i++); } else { priv->fids[fid] &= 0xffff; - priv->stats.tx_window_errors++; + dev->stats.tx_window_errors++; } if (i < MAX_FIDS / 2) netif_wake_queue(dev); @@ -2128,7 +2127,7 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) { netif_stop_queue(dev); if (i == MAX_FIDS / 2) { - priv->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; return 1; } } @@ -2167,7 +2166,7 @@ static void airo_end_xmit11(struct net_device *dev) { for (; i < MAX_FIDS && (priv->fids[i] & 0xffff0000); i++); } else { priv->fids[fid] &= 0xffff; - priv->stats.tx_window_errors++; + dev->stats.tx_window_errors++; } if (i < MAX_FIDS) netif_wake_queue(dev); @@ -2199,7 +2198,7 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) { netif_stop_queue(dev); if (i == MAX_FIDS) { - priv->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; return 1; } } @@ -2219,8 +2218,9 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) { return 0; } -static void airo_read_stats(struct airo_info *ai) +static void airo_read_stats(struct net_device *dev) { + struct airo_info *ai = dev->priv; StatsRid stats_rid; __le32 *vals = stats_rid.vals; @@ -2232,23 +2232,24 @@ static void airo_read_stats(struct airo_info *ai) readStatsRid(ai, &stats_rid, RID_STATS, 0); up(&ai->sem); - ai->stats.rx_packets = le32_to_cpu(vals[43]) + le32_to_cpu(vals[44]) + + dev->stats.rx_packets = le32_to_cpu(vals[43]) + le32_to_cpu(vals[44]) + le32_to_cpu(vals[45]); - ai->stats.tx_packets = le32_to_cpu(vals[39]) + le32_to_cpu(vals[40]) + + dev->stats.tx_packets = le32_to_cpu(vals[39]) + le32_to_cpu(vals[40]) + le32_to_cpu(vals[41]); - ai->stats.rx_bytes = le32_to_cpu(vals[92]); - ai->stats.tx_bytes = le32_to_cpu(vals[91]); - ai->stats.rx_errors = le32_to_cpu(vals[0]) + le32_to_cpu(vals[2]) + + dev->stats.rx_bytes = le32_to_cpu(vals[92]); + dev->stats.tx_bytes = le32_to_cpu(vals[91]); + dev->stats.rx_errors = le32_to_cpu(vals[0]) + le32_to_cpu(vals[2]) + le32_to_cpu(vals[3]) + le32_to_cpu(vals[4]); - ai->stats.tx_errors = le32_to_cpu(vals[42]) + ai->stats.tx_fifo_errors; - ai->stats.multicast = le32_to_cpu(vals[43]); - ai->stats.collisions = le32_to_cpu(vals[89]); + dev->stats.tx_errors = le32_to_cpu(vals[42]) + + dev->stats.tx_fifo_errors; + dev->stats.multicast = le32_to_cpu(vals[43]); + dev->stats.collisions = le32_to_cpu(vals[89]); /* detailed rx_errors: */ - ai->stats.rx_length_errors = le32_to_cpu(vals[3]); - ai->stats.rx_crc_errors = le32_to_cpu(vals[4]); - ai->stats.rx_frame_errors = le32_to_cpu(vals[2]); - ai->stats.rx_fifo_errors = le32_to_cpu(vals[0]); + dev->stats.rx_length_errors = le32_to_cpu(vals[3]); + dev->stats.rx_crc_errors = le32_to_cpu(vals[4]); + dev->stats.rx_frame_errors = le32_to_cpu(vals[2]); + dev->stats.rx_fifo_errors = le32_to_cpu(vals[0]); } static struct net_device_stats *airo_get_stats(struct net_device *dev) @@ -2261,10 +2262,10 @@ static struct net_device_stats *airo_get_stats(struct net_device *dev) set_bit(JOB_STATS, &local->jobs); wake_up_interruptible(&local->thr_wait); } else - airo_read_stats(local); + airo_read_stats(dev); } - return &local->stats; + return &dev->stats; } static void airo_set_promisc(struct airo_info *ai) { @@ -3092,7 +3093,7 @@ static int airo_thread(void *data) { else if (test_bit(JOB_XMIT11, &ai->jobs)) airo_end_xmit11(dev); else if (test_bit(JOB_STATS, &ai->jobs)) - airo_read_stats(ai); + airo_read_stats(dev); else if (test_bit(JOB_WSTATS, &ai->jobs)) airo_read_wireless_stats(ai); else if (test_bit(JOB_PROMISC, &ai->jobs)) @@ -3288,7 +3289,7 @@ static irqreturn_t airo_interrupt(int irq, void *dev_id) skb = dev_alloc_skb( len + hdrlen + 2 + 2 ); if ( !skb ) { - apriv->stats.rx_dropped++; + dev->stats.rx_dropped++; goto badrx; } skb_reserve(skb, 2); /* This way the IP header is aligned */ @@ -3556,7 +3557,7 @@ static void mpi_receive_802_3(struct airo_info *ai) skb = dev_alloc_skb(len); if (!skb) { - ai->stats.rx_dropped++; + ai->dev->stats.rx_dropped++; goto badrx; } buffer = skb_put(skb,len); @@ -3649,7 +3650,7 @@ void mpi_receive_802_11 (struct airo_info *ai) skb = dev_alloc_skb( len + hdrlen + 2 ); if ( !skb ) { - ai->stats.rx_dropped++; + ai->dev->stats.rx_dropped++; goto badrx; } buffer = (u16*)skb_put (skb, len + hdrlen); -- cgit v1.2.3-70-g09d2 From 8cf769c6dcb7b83d380f20d2873ac20ec7a734b1 Mon Sep 17 00:00:00 2001 From: Ester Kummer Date: Tue, 6 May 2008 11:05:11 +0800 Subject: iwlwifi: move debug_level to sysfs/bus/pci/devices This patch ports the debug_level from sysfs/bus/pci/drivers/iwl4965 to /sys/class/net/wlanX/device/debug_level Signed-off-by: Ester Kummer Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/Kconfig | 4 ++-- drivers/net/wireless/iwlwifi/iwl-core.c | 5 ----- drivers/net/wireless/iwlwifi/iwl-debug.h | 1 - drivers/net/wireless/iwlwifi/iwl4965-base.c | 31 ++++++++++++++--------------- 4 files changed, 17 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index cc0006900b3..193e48f3ed5 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -97,13 +97,13 @@ config IWLWIFI_DEBUG control which debug output is sent to the kernel log by setting the value in - /sys/bus/pci/drivers/${DRIVER}/debug_level + /sys/class/net/wlan0/device/debug_level This entry will only exist if this option is enabled. To set a value, simply echo an 8-byte hex value to the same file: - % echo 0x43fff > /sys/bus/pci/drivers/${DRIVER}/debug_level + % echo 0x43fff > /sys/class/net/wlan0/device/debug_level You can find the list of debug mask values in: drivers/net/wireless/iwlwifi/iwl-4965-debug.h diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 7759e63b2bc..27e56b89d94 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -46,11 +46,6 @@ MODULE_VERSION(IWLWIFI_VERSION); MODULE_AUTHOR(DRV_COPYRIGHT); MODULE_LICENSE("GPL"); -#ifdef CONFIG_IWLWIFI_DEBUG -u32 iwl_debug_level; -EXPORT_SYMBOL(iwl_debug_level); -#endif - #define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np) \ [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \ IWL_RATE_SISO_##s##M_PLCP, \ diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 14d95dd0e14..2f24594c5fe 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -30,7 +30,6 @@ #define __iwl_debug_h__ #ifdef CONFIG_IWLWIFI_DEBUG -extern u32 iwl_debug_level; #define IWL_DEBUG(level, fmt, args...) \ do { if (priv->debug_level & (level)) \ dev_printk(KERN_ERR, &(priv->hw->wiphy->dev), "%c %s " fmt, \ diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 45bbce7f66a..7902d90d58c 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -5963,13 +5963,18 @@ static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk * See the level definitions in iwl for details. */ -static ssize_t show_debug_level(struct device_driver *d, char *buf) +static ssize_t show_debug_level(struct device *d, + struct device_attribute *attr, char *buf) { - return sprintf(buf, "0x%08X\n", iwl_debug_level); + struct iwl_priv *priv = d->driver_data; + + return sprintf(buf, "0x%08X\n", priv->debug_level); } -static ssize_t store_debug_level(struct device_driver *d, +static ssize_t store_debug_level(struct device *d, + struct device_attribute *attr, const char *buf, size_t count) { + struct iwl_priv *priv = d->driver_data; char *p = (char *)buf; u32 val; @@ -5978,13 +5983,14 @@ static ssize_t store_debug_level(struct device_driver *d, printk(KERN_INFO DRV_NAME ": %s is not in hex or decimal form.\n", buf); else - iwl_debug_level = val; + priv->debug_level = val; return strnlen(buf, count); } -static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, - show_debug_level, store_debug_level); +static DEVICE_ATTR(debug_level, S_IWUSR | S_IRUGO, + show_debug_level, store_debug_level); + #endif /* CONFIG_IWLWIFI_DEBUG */ @@ -6431,6 +6437,9 @@ static struct attribute *iwl4965_sysfs_entries[] = { &dev_attr_status.attr, &dev_attr_temperature.attr, &dev_attr_tx_power.attr, +#ifdef CONFIG_IWLWIFI_DEBUG + &dev_attr_debug_level.attr, +#endif NULL }; @@ -6817,13 +6826,6 @@ static int __init iwl4965_init(void) IWL_ERROR("Unable to initialize PCI module\n"); goto error_register; } -#ifdef CONFIG_IWLWIFI_DEBUG - ret = driver_create_file(&iwl_driver.driver, &driver_attr_debug_level); - if (ret) { - IWL_ERROR("Unable to create driver sysfs file\n"); - goto error_debug; - } -#endif return ret; @@ -6838,9 +6840,6 @@ error_register: static void __exit iwl4965_exit(void) { -#ifdef CONFIG_IWLWIFI_DEBUG - driver_remove_file(&iwl_driver.driver, &driver_attr_debug_level); -#endif pci_unregister_driver(&iwl_driver); iwl4965_rate_control_unregister(); } -- cgit v1.2.3-70-g09d2 From f3d67999348776638644fd0035ee465261cc8c68 Mon Sep 17 00:00:00 2001 From: Ester Kummer Date: Tue, 6 May 2008 11:05:12 +0800 Subject: iwlwifi: update levels of debug prints This patch updates the levels of debug prints, leaving only one level in each debug print. It was anoying and caused unnecessary prints on hot path. Signed-off-by: Ester Kummer Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl4965-base.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 7902d90d58c..901d9cf9ad7 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -2715,8 +2715,8 @@ static void iwl4965_rx_spectrum_measure_notif(struct iwl_priv *priv, struct iwl4965_spectrum_notification *report = &(pkt->u.spectrum_notif); if (!report->state) { - IWL_DEBUG(IWL_DL_11H | IWL_DL_INFO, - "Spectrum Measure Notification: Start\n"); + IWL_DEBUG(IWL_DL_11H, + "Spectrum Measure Notification: Start\n"); return; } @@ -3100,7 +3100,7 @@ void iwl_rx_handle(struct iwl_priv *priv) /* Rx interrupt, but nothing sent from uCode */ if (i == r) - IWL_DEBUG(IWL_DL_RX | IWL_DL_ISR, "r = %d, i = %d\n", r, i); + IWL_DEBUG(IWL_DL_RX, "r = %d, i = %d\n", r, i); if (iwl_rx_queue_space(rxq) > (RX_QUEUE_SIZE / 2)) fill_rx = 1; @@ -3137,13 +3137,12 @@ void iwl_rx_handle(struct iwl_priv *priv) * handle those that need handling via function in * rx_handlers table. See iwl4965_setup_rx_handlers() */ if (priv->rx_handlers[pkt->hdr.cmd]) { - IWL_DEBUG(IWL_DL_HOST_COMMAND | IWL_DL_RX | IWL_DL_ISR, - "r = %d, i = %d, %s, 0x%02x\n", r, i, - get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); + IWL_DEBUG(IWL_DL_RX, "r = %d, i = %d, %s, 0x%02x\n", r, + i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); priv->rx_handlers[pkt->hdr.cmd] (priv, rxb); } else { /* No handling needed */ - IWL_DEBUG(IWL_DL_HOST_COMMAND | IWL_DL_RX | IWL_DL_ISR, + IWL_DEBUG(IWL_DL_RX, "r %d i %d No handler needed for %s, 0x%02x\n", r, i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); @@ -3562,7 +3561,7 @@ static void iwl4965_irq_handle_error(struct iwl_priv *priv) clear_bit(STATUS_READY, &priv->status); if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) { - IWL_DEBUG(IWL_DL_INFO | IWL_DL_FW_ERRORS, + IWL_DEBUG(IWL_DL_FW_ERRORS, "Restarting adapter due to uCode error.\n"); if (iwl_is_associated(priv)) { @@ -3670,8 +3669,7 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv) CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) hw_rf_kill = 1; - IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL | IWL_DL_ISR, - "RF_KILL bit toggled to %s.\n", + IWL_DEBUG(IWL_DL_RF_KILL, "RF_KILL bit toggled to %s.\n", hw_rf_kill ? "disable radio":"enable radio"); /* Queue restart only if RF_KILL switch was set to "kill" @@ -4516,7 +4514,7 @@ static void iwl4965_bg_rf_kill(struct work_struct *work) mutex_lock(&priv->mutex); if (!iwl_is_rfkill(priv)) { - IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL, + IWL_DEBUG(IWL_DL_RF_KILL, "HW and/or SW RF Kill no longer active, restarting " "device\n"); if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) @@ -4570,9 +4568,9 @@ static void iwl4965_bg_scan_check(struct work_struct *data) mutex_lock(&priv->mutex); if (test_bit(STATUS_SCANNING, &priv->status) || test_bit(STATUS_SCAN_ABORTING, &priv->status)) { - IWL_DEBUG(IWL_DL_INFO | IWL_DL_SCAN, - "Scan completion watchdog resetting adapter (%dms)\n", - jiffies_to_msecs(IWL_SCAN_CHECK_WATCHDOG)); + IWL_DEBUG(IWL_DL_SCAN, "Scan completion watchdog resetting " + "adapter (%dms)\n", + jiffies_to_msecs(IWL_SCAN_CHECK_WATCHDOG)); if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) iwl4965_send_scan_abort(priv); @@ -4973,7 +4971,7 @@ static void iwl4965_bg_scan_completed(struct work_struct *work) struct iwl_priv *priv = container_of(work, struct iwl_priv, scan_completed); - IWL_DEBUG(IWL_DL_INFO | IWL_DL_SCAN, "SCAN complete scan\n"); + IWL_DEBUG(IWL_DL_SCAN, "SCAN complete scan\n"); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; @@ -6830,7 +6828,6 @@ static int __init iwl4965_init(void) return ret; #ifdef CONFIG_IWLWIFI_DEBUG -error_debug: pci_unregister_driver(&iwl_driver); #endif error_register: -- cgit v1.2.3-70-g09d2 From bc6f59bc9b2f494ca1b018622f1fbd25933bc920 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 6 May 2008 11:05:13 +0800 Subject: iwlwifi: add device sysfs version entry This patch adds sysfs version file that displays ucode version and type. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl4965-base.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 901d9cf9ad7..7708b19ca0c 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -5993,6 +5993,25 @@ static DEVICE_ATTR(debug_level, S_IWUSR | S_IRUGO, #endif /* CONFIG_IWLWIFI_DEBUG */ +static ssize_t show_version(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = d->driver_data; + struct iwl4965_alive_resp *palive = &priv->card_alive; + + if (palive->is_valid) + return sprintf(buf, "fw version: 0x%01X.0x%01X.0x%01X.0x%01X\n" + "fw type: 0x%01X 0x%01X\n", + palive->ucode_major, palive->ucode_minor, + palive->sw_rev[0], palive->sw_rev[1], + palive->ver_type, palive->ver_subtype); + + else + return sprintf(buf, "fw not loaded\n"); +} + +static DEVICE_ATTR(version, S_IWUSR | S_IRUGO, show_version, NULL); + static ssize_t show_temperature(struct device *d, struct device_attribute *attr, char *buf) { @@ -6438,6 +6457,7 @@ static struct attribute *iwl4965_sysfs_entries[] = { #ifdef CONFIG_IWLWIFI_DEBUG &dev_attr_debug_level.attr, #endif + &dev_attr_version.attr, NULL }; -- cgit v1.2.3-70-g09d2 From 3a1081e84b0008de8171a95f2c0fff8489af4300 Mon Sep 17 00:00:00 2001 From: Ester Kummer Date: Tue, 6 May 2008 11:05:14 +0800 Subject: iwlwifi: adding parameter of fw_restart This patch adds a module parameter of fw_restart which determine if the uCode will be restarted or not in case of error. Signed-off-by: Ester Kummer Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 4 +++- drivers/net/wireless/iwlwifi/iwl-5000.c | 5 +++-- drivers/net/wireless/iwlwifi/iwl-core.h | 1 + drivers/net/wireless/iwlwifi/iwl4965-base.c | 4 +++- 4 files changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 0b441383050..b7036e01145 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -50,6 +50,7 @@ static struct iwl_mod_params iwl4965_mod_params = { .num_of_queues = IWL49_NUM_QUEUES, .enable_qos = 1, .amsdu_size_8K = 1, + .restart_fw = 1, /* the rest are 0 by default */ }; @@ -3892,4 +3893,5 @@ module_param_named(qos_enable, iwl4965_mod_params.enable_qos, int, 0444); MODULE_PARM_DESC(qos_enable, "enable all QoS functionality"); module_param_named(amsdu_size_8K, iwl4965_mod_params.amsdu_size_8K, int, 0444); MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size"); - +module_param_named(fw_restart4965, iwl4965_mod_params.restart_fw, int, 0444); +MODULE_PARM_DESC(fw_restart4965, "restart firmware in case of error"); diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 43b4d20467d..b5e28b81179 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -510,6 +510,7 @@ static struct iwl_mod_params iwl50_mod_params = { .num_of_queues = IWL50_NUM_QUEUES, .enable_qos = 1, .amsdu_size_8K = 1, + .restart_fw = 1, /* the rest are 0 by default */ }; @@ -555,5 +556,5 @@ module_param_named(qos_enable50, iwl50_mod_params.enable_qos, int, 0444); MODULE_PARM_DESC(qos_enable50, "enable all 50XX QoS functionality"); module_param_named(amsdu_size_8K50, iwl50_mod_params.amsdu_size_8K, int, 0444); MODULE_PARM_DESC(amsdu_size_8K50, "enable 8K amsdu size in 50XX series"); - - +module_param_named(fw_restart50, iwl50_mod_params.restart_fw, int, 0444); +MODULE_PARM_DESC(fw_restart50, "restart firmware in case of error"); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 83fe0cbf6ae..e139c8ffa9a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -149,6 +149,7 @@ struct iwl_mod_params { int enable_qos; /* def: 1 = use quality of service */ int amsdu_size_8K; /* def: 1 = enable 8K amsdu size */ int antenna; /* def: 0 = both antennas (use diversity) */ + int restart_fw; /* def: 1 = restart firmware */ }; struct iwl_cfg { diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 7708b19ca0c..55ca752ae9e 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -3569,7 +3569,8 @@ static void iwl4965_irq_handle_error(struct iwl_priv *priv) sizeof(priv->recovery_rxon)); priv->error_recovering = 1; } - queue_work(priv->workqueue, &priv->restart); + if (priv->cfg->mod_params->restart_fw) + queue_work(priv->workqueue, &priv->restart); } } @@ -6847,6 +6848,7 @@ static int __init iwl4965_init(void) return ret; + #ifdef CONFIG_IWLWIFI_DEBUG pci_unregister_driver(&iwl_driver); #endif -- cgit v1.2.3-70-g09d2 From 15dbf1b7b7b6ba6e5159dde60e111f617b2c54ea Mon Sep 17 00:00:00 2001 From: Bill Moss Date: Tue, 6 May 2008 11:05:15 +0800 Subject: iwl3945: do not delay hardware scan if it is a direct scan iwl3945 <---> mac80211 <----> wpa_supplicant <---> NetworkManager When a hardware scan is completed and another scan is requested in less than two seconds, iwlwifi will not do the second scan and will pass the error code -EAGAIN back to mac80211 where it quickly dies. The error code is not passed along to the calling program wpa_supplicant. After a timeout, wpa_supplicant will just give up but it will not know why the scan failed. This is a weakness in the design. I ran into this issue when I was trying to figure out why it takes more an a minute for NetworkManager to connect after Networking has been disabled and then re-enabled. I found a good deal of unnecessary work being done because mac80211 requests authentication when the interface is not configured, the ANY mode. I created an experimental passive (NOTANY) mode for mac80211 to eliminate this case. Then NetworkManager became so fast that I ran into the iwlwifi 2 second delay next scan issue which we are discussing. The patch resolves the problem by bypassing the delay if the scan request is a direct scan. It should do less harm to the hardware. Signed-off-by: Bill Moss Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index f021eba41e6..4baa185ba50 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -7087,9 +7087,10 @@ static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) rc = -EAGAIN; goto out_unlock; } - /* if we just finished scan ask for delay */ - if (priv->last_scan_jiffies && time_after(priv->last_scan_jiffies + - IWL_DELAY_NEXT_SCAN, jiffies)) { + /* if we just finished scan ask for delay for a broadcast scan */ + if ((len == 0) && priv->last_scan_jiffies && + time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN, + jiffies)) { rc = -EAGAIN; goto out_unlock; } -- cgit v1.2.3-70-g09d2 From 06a5223d68a7c48bf72a05aad533ea0e8a3453be Mon Sep 17 00:00:00 2001 From: Paulius Zaleckas Date: Tue, 6 May 2008 14:44:08 +0300 Subject: arlan: use netstats in net_device structure Use net_device_stats from net_device structure instead of local. Signed-off-by: Paulius Zaleckas Signed-off-by: John W. Linville --- drivers/net/wireless/arlan-main.c | 40 +++++++++++++++++++-------------------- drivers/net/wireless/arlan.h | 1 - 2 files changed, 20 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c index dbdfc9e39d2..dec5e874a54 100644 --- a/drivers/net/wireless/arlan-main.c +++ b/drivers/net/wireless/arlan-main.c @@ -125,7 +125,7 @@ static inline int arlan_drop_tx(struct net_device *dev) { struct arlan_private *priv = netdev_priv(dev); - priv->stats.tx_errors++; + dev->stats.tx_errors++; if (priv->Conf->tx_delay_ms) { priv->tx_done_delayed = jiffies + priv->Conf->tx_delay_ms * HZ / 1000 + 1; @@ -1269,7 +1269,7 @@ static void arlan_tx_done_interrupt(struct net_device *dev, int status) { IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk("arlan intr: transmit OK\n"); - priv->stats.tx_packets++; + dev->stats.tx_packets++; priv->bad = 0; priv->reset = 0; priv->retransmissions = 0; @@ -1496,7 +1496,7 @@ static void arlan_rx_interrupt(struct net_device *dev, u_char rxStatus, u_short if (skb == NULL) { printk(KERN_ERR "%s: Memory squeeze, dropping packet.\n", dev->name); - priv->stats.rx_dropped++; + dev->stats.rx_dropped++; break; } skb_reserve(skb, 2); @@ -1536,14 +1536,14 @@ static void arlan_rx_interrupt(struct net_device *dev, u_char rxStatus, u_short } netif_rx(skb); dev->last_rx = jiffies; - priv->stats.rx_packets++; - priv->stats.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; } break; default: printk(KERN_ERR "arlan intr: received unknown status\n"); - priv->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; break; } ARLAN_DEBUG_EXIT("arlan_rx_interrupt"); @@ -1719,23 +1719,23 @@ static struct net_device_stats *arlan_statistics(struct net_device *dev) /* Update the statistics from the device registers. */ - READSHM(priv->stats.collisions, arlan->numReTransmissions, u_int); - READSHM(priv->stats.rx_crc_errors, arlan->numCRCErrors, u_int); - READSHM(priv->stats.rx_dropped, arlan->numFramesDiscarded, u_int); - READSHM(priv->stats.rx_fifo_errors, arlan->numRXBufferOverflows, u_int); - READSHM(priv->stats.rx_frame_errors, arlan->numReceiveFramesLost, u_int); - READSHM(priv->stats.rx_over_errors, arlan->numRXOverruns, u_int); - READSHM(priv->stats.rx_packets, arlan->numDatagramsReceived, u_int); - READSHM(priv->stats.tx_aborted_errors, arlan->numAbortErrors, u_int); - READSHM(priv->stats.tx_carrier_errors, arlan->numStatusTimeouts, u_int); - READSHM(priv->stats.tx_dropped, arlan->numDatagramsDiscarded, u_int); - READSHM(priv->stats.tx_fifo_errors, arlan->numTXUnderruns, u_int); - READSHM(priv->stats.tx_packets, arlan->numDatagramsTransmitted, u_int); - READSHM(priv->stats.tx_window_errors, arlan->numHoldOffs, u_int); + READSHM(dev->stats.collisions, arlan->numReTransmissions, u_int); + READSHM(dev->stats.rx_crc_errors, arlan->numCRCErrors, u_int); + READSHM(dev->stats.rx_dropped, arlan->numFramesDiscarded, u_int); + READSHM(dev->stats.rx_fifo_errors, arlan->numRXBufferOverflows, u_int); + READSHM(dev->stats.rx_frame_errors, arlan->numReceiveFramesLost, u_int); + READSHM(dev->stats.rx_over_errors, arlan->numRXOverruns, u_int); + READSHM(dev->stats.rx_packets, arlan->numDatagramsReceived, u_int); + READSHM(dev->stats.tx_aborted_errors, arlan->numAbortErrors, u_int); + READSHM(dev->stats.tx_carrier_errors, arlan->numStatusTimeouts, u_int); + READSHM(dev->stats.tx_dropped, arlan->numDatagramsDiscarded, u_int); + READSHM(dev->stats.tx_fifo_errors, arlan->numTXUnderruns, u_int); + READSHM(dev->stats.tx_packets, arlan->numDatagramsTransmitted, u_int); + READSHM(dev->stats.tx_window_errors, arlan->numHoldOffs, u_int); ARLAN_DEBUG_EXIT("arlan_statistics"); - return &priv->stats; + return &dev->stats; } diff --git a/drivers/net/wireless/arlan.h b/drivers/net/wireless/arlan.h index 3ed1df75900..fb3ad51a1ca 100644 --- a/drivers/net/wireless/arlan.h +++ b/drivers/net/wireless/arlan.h @@ -330,7 +330,6 @@ struct TxParam #define TX_RING_SIZE 2 /* Information that need to be kept for each board. */ struct arlan_private { - struct net_device_stats stats; struct arlan_shmem __iomem * card; struct arlan_shmem * conf; -- cgit v1.2.3-70-g09d2 From 736bc924fe7183dd27182a9148e78f250c1637ee Mon Sep 17 00:00:00 2001 From: Paulius Zaleckas Date: Tue, 6 May 2008 23:50:30 +0300 Subject: atmel: use netstats in net_device structure Use net_device_stats from net_device structure instead of local. Kill atmel_get_stats function, because by default it is used identical internal_stats function from net/core/dev.c No need to memset stats to 0, because they are allocated by kzalloc. P.S. Someone should cleanup init_atmel_card function from unneeded initializations to 0/NULL. Out of scope for this patch. Signed-off-by: Paulius Zaleckas Signed-off-by: John W. Linville --- drivers/net/wireless/atmel.c | 46 +++++++++++++++++--------------------------- 1 file changed, 18 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index ef2da4023d6..f978a9d5190 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -433,7 +433,6 @@ struct atmel_private { struct net_device *dev; struct device *sys_dev; struct iw_statistics wstats; - struct net_device_stats stats; // device stats spinlock_t irqlock, timerlock; // spinlocks enum { BUS_TYPE_PCCARD, BUS_TYPE_PCI } bus_type; enum { @@ -694,9 +693,9 @@ static void tx_done_irq(struct atmel_private *priv) if (type == TX_PACKET_TYPE_DATA) { if (status == TX_STATUS_SUCCESS) - priv->stats.tx_packets++; + priv->dev->stats.tx_packets++; else - priv->stats.tx_errors++; + priv->dev->stats.tx_errors++; netif_wake_queue(priv->dev); } } @@ -792,13 +791,13 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) if (priv->card && priv->present_callback && !(*priv->present_callback)(priv->card)) { - priv->stats.tx_errors++; + dev->stats.tx_errors++; dev_kfree_skb(skb); return 0; } if (priv->station_state != STATION_STATE_READY) { - priv->stats.tx_errors++; + dev->stats.tx_errors++; dev_kfree_skb(skb); return 0; } @@ -815,7 +814,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) initial + 18 (+30-12) */ if (!(buff = find_tx_buff(priv, len + 18))) { - priv->stats.tx_dropped++; + dev->stats.tx_dropped++; spin_unlock_irqrestore(&priv->irqlock, flags); spin_unlock_bh(&priv->timerlock); netif_stop_queue(dev); @@ -851,7 +850,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) /* low bit of first byte of destination tells us if broadcast */ tx_update_descriptor(priv, *(skb->data) & 0x01, len + 18, buff, TX_PACKET_TYPE_DATA); dev->trans_start = jiffies; - priv->stats.tx_bytes += len; + dev->stats.tx_bytes += len; spin_unlock_irqrestore(&priv->irqlock, flags); spin_unlock_bh(&priv->timerlock); @@ -895,7 +894,7 @@ static void fast_rx_path(struct atmel_private *priv, } if (!(skb = dev_alloc_skb(msdu_size + 14))) { - priv->stats.rx_dropped++; + priv->dev->stats.rx_dropped++; return; } @@ -908,7 +907,7 @@ static void fast_rx_path(struct atmel_private *priv, crc = crc32_le(crc, skbp + 12, msdu_size); atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + 30 + msdu_size, 4); if ((crc ^ 0xffffffff) != netcrc) { - priv->stats.rx_crc_errors++; + priv->dev->stats.rx_crc_errors++; dev_kfree_skb(skb); return; } @@ -924,8 +923,8 @@ static void fast_rx_path(struct atmel_private *priv, skb->protocol = eth_type_trans(skb, priv->dev); skb->ip_summed = CHECKSUM_NONE; netif_rx(skb); - priv->stats.rx_bytes += 12 + msdu_size; - priv->stats.rx_packets++; + priv->dev->stats.rx_bytes += 12 + msdu_size; + priv->dev->stats.rx_packets++; } /* Test to see if the packet in card memory at packet_loc has a valid CRC @@ -991,7 +990,7 @@ static void frag_rx_path(struct atmel_private *priv, crc = crc32_le(crc, &priv->rx_buf[12], msdu_size); atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + msdu_size, 4); if ((crc ^ 0xffffffff) != netcrc) { - priv->stats.rx_crc_errors++; + priv->dev->stats.rx_crc_errors++; memset(priv->frag_source, 0xff, 6); } } @@ -1009,7 +1008,7 @@ static void frag_rx_path(struct atmel_private *priv, msdu_size); atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + msdu_size, 4); if ((crc ^ 0xffffffff) != netcrc) { - priv->stats.rx_crc_errors++; + priv->dev->stats.rx_crc_errors++; memset(priv->frag_source, 0xff, 6); more_frags = 1; /* don't send broken assembly */ } @@ -1021,7 +1020,7 @@ static void frag_rx_path(struct atmel_private *priv, if (!more_frags) { /* last one */ memset(priv->frag_source, 0xff, 6); if (!(skb = dev_alloc_skb(priv->frag_len + 14))) { - priv->stats.rx_dropped++; + priv->dev->stats.rx_dropped++; } else { skb_reserve(skb, 2); memcpy(skb_put(skb, priv->frag_len + 12), @@ -1031,8 +1030,8 @@ static void frag_rx_path(struct atmel_private *priv, skb->protocol = eth_type_trans(skb, priv->dev); skb->ip_summed = CHECKSUM_NONE; netif_rx(skb); - priv->stats.rx_bytes += priv->frag_len + 12; - priv->stats.rx_packets++; + priv->dev->stats.rx_bytes += priv->frag_len + 12; + priv->dev->stats.rx_packets++; } } } else @@ -1057,7 +1056,7 @@ static void rx_done_irq(struct atmel_private *priv) if (status == 0xc1) /* determined by experiment */ priv->wstats.discard.nwid++; else - priv->stats.rx_errors++; + priv->dev->stats.rx_errors++; goto next; } @@ -1065,7 +1064,7 @@ static void rx_done_irq(struct atmel_private *priv) rx_packet_loc = atmel_rmem16(priv, atmel_rx(priv, RX_DESC_MSDU_POS_OFFSET, priv->rx_desc_head)); if (msdu_size < 30) { - priv->stats.rx_errors++; + priv->dev->stats.rx_errors++; goto next; } @@ -1123,7 +1122,7 @@ static void rx_done_irq(struct atmel_private *priv) msdu_size -= 4; crc = crc32_le(crc, (unsigned char *)&priv->rx_buf, msdu_size); if ((crc ^ 0xffffffff) != (*((u32 *)&priv->rx_buf[msdu_size]))) { - priv->stats.rx_crc_errors++; + priv->dev->stats.rx_crc_errors++; goto next; } } @@ -1250,12 +1249,6 @@ static irqreturn_t service_interrupt(int irq, void *dev_id) } } -static struct net_device_stats *atmel_get_stats(struct net_device *dev) -{ - struct atmel_private *priv = netdev_priv(dev); - return &priv->stats; -} - static struct iw_statistics *atmel_get_wireless_stats(struct net_device *dev) { struct atmel_private *priv = netdev_priv(dev); @@ -1518,8 +1511,6 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port, priv->crc_ok_cnt = priv->crc_ko_cnt = 0; } else priv->probe_crc = 0; - memset(&priv->stats, 0, sizeof(priv->stats)); - memset(&priv->wstats, 0, sizeof(priv->wstats)); priv->last_qual = jiffies; priv->last_beacon_timestamp = 0; memset(priv->frag_source, 0xff, sizeof(priv->frag_source)); @@ -1568,7 +1559,6 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port, dev->change_mtu = atmel_change_mtu; dev->set_mac_address = atmel_set_mac_address; dev->hard_start_xmit = start_tx; - dev->get_stats = atmel_get_stats; dev->wireless_handlers = (struct iw_handler_def *)&atmel_handler_def; dev->do_ioctl = atmel_ioctl; dev->irq = irq; -- cgit v1.2.3-70-g09d2 From 84e6dc9acf6825f508feae9db6b7d695e64894e0 Mon Sep 17 00:00:00 2001 From: Bruno Randolf Date: Wed, 7 May 2008 11:46:02 +0200 Subject: zd1211rw: initial IBSS support this adds initial IBSS support for the zydas zd1211rw: convince driver that it can do IBSS mode. add mac80211 beacon_update callback. IBSS merge and TSF updates don't work yet, but it makes the driver usable in ad-hoc networks. Signed-off-by: Bruno Randolf Signed-off-by: John W. Linville --- drivers/net/wireless/zd1211rw/zd_mac.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 69c45ca9905..ee4331229f1 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -751,6 +751,7 @@ static int zd_op_add_interface(struct ieee80211_hw *hw, case IEEE80211_IF_TYPE_MNTR: case IEEE80211_IF_TYPE_MESH_POINT: case IEEE80211_IF_TYPE_STA: + case IEEE80211_IF_TYPE_IBSS: mac->type = conf->type; break; default: @@ -781,7 +782,8 @@ static int zd_op_config_interface(struct ieee80211_hw *hw, struct zd_mac *mac = zd_hw_mac(hw); int associated; - if (mac->type == IEEE80211_IF_TYPE_MESH_POINT) { + if (mac->type == IEEE80211_IF_TYPE_MESH_POINT || + mac->type == IEEE80211_IF_TYPE_IBSS) { associated = true; if (conf->beacon) { zd_mac_config_beacon(hw, conf->beacon); @@ -941,6 +943,18 @@ static void zd_op_bss_info_changed(struct ieee80211_hw *hw, } } +static int zd_op_beacon_update(struct ieee80211_hw *hw, + struct sk_buff *skb, + struct ieee80211_tx_control *ctl) +{ + struct zd_mac *mac = zd_hw_mac(hw); + zd_mac_config_beacon(hw, skb); + kfree_skb(skb); + zd_set_beacon_interval(&mac->chip, BCN_MODE_IBSS | + hw->conf.beacon_int); + return 0; +} + static const struct ieee80211_ops zd_ops = { .tx = zd_op_tx, .start = zd_op_start, @@ -951,6 +965,7 @@ static const struct ieee80211_ops zd_ops = { .config_interface = zd_op_config_interface, .configure_filter = zd_op_configure_filter, .bss_info_changed = zd_op_bss_info_changed, + .beacon_update = zd_op_beacon_update, }; struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf) -- cgit v1.2.3-70-g09d2 From 566bfe5a8bcde13188a356f77666f8115813cf31 Mon Sep 17 00:00:00 2001 From: Bruno Randolf Date: Thu, 8 May 2008 19:15:40 +0200 Subject: mac80211: use hardware flags for signal/noise units trying to clean up the signal/noise code. the previous code in mac80211 had confusing names for the related variables, did not have much definition of what units of signal and noise were provided and used implicit mechanisms from the wireless extensions. this patch introduces hardware capability flags to let the hardware specify clearly if it can provide signal and noise level values and which units it can provide. this also anticipates possible new units like RCPI in the future. for signal: IEEE80211_HW_SIGNAL_UNSPEC - unspecified, unknown, hw specific IEEE80211_HW_SIGNAL_DB - dB difference to unspecified reference point IEEE80211_HW_SIGNAL_DBM - dBm, difference to 1mW for noise we currently only have dBm: IEEE80211_HW_NOISE_DBM - dBm, difference to 1mW if IEEE80211_HW_SIGNAL_UNSPEC or IEEE80211_HW_SIGNAL_DB is used the driver has to provide the maximum value (max_signal) it reports in order for applications to make sense of the signal values. i tried my best to find out for each driver what it can provide and update it but i'm not sure (?) for some of them and used the more conservative guess in doubt. this can be fixed easily after this patch has been merged by changing the hardware flags of the driver. DRIVER SIGNAL MAX NOISE QUAL ----------------------------------------------------------------- adm8211 unspec(?) 100 n/a missing at76_usb unspec(?) (?) unused missing ath5k dBm dBm percent rssi b43legacy dBm dBm percent jssi(?) b43 dBm dBm percent jssi(?) iwl-3945 dBm dBm percent snr+more iwl-4965 dBm dBm percent snr+more p54 unspec 127 n/a missing rt2x00 dBm n/a percent rssi+tx/rx frame success rt2400 dBm n/a rt2500pci dBm n/a rt2500usb dBm n/a rt61pci dBm n/a rt73usb dBm n/a rtl8180 unspec(?) 65 n/a (?) rtl8187 unspec(?) 65 (?) noise(?) zd1211 dB(?) 100 n/a percent drivers/net/wireless/ath5k/base.c: Changes-licensed-under: 3-Clause-BSD Signed-off-by: Bruno Randolf Signed-off-by: John W. Linville --- drivers/net/wireless/adm8211.c | 7 +++-- drivers/net/wireless/ath5k/base.c | 23 +++----------- drivers/net/wireless/b43/main.c | 8 ++--- drivers/net/wireless/b43/xmit.c | 5 ++- drivers/net/wireless/b43legacy/main.c | 7 ++--- drivers/net/wireless/b43legacy/xmit.c | 4 +-- drivers/net/wireless/iwlwifi/iwl-3945.c | 18 +++++------ drivers/net/wireless/iwlwifi/iwl-4965.c | 12 ++++---- drivers/net/wireless/iwlwifi/iwl-core.c | 16 +++------- drivers/net/wireless/iwlwifi/iwl3945-base.c | 15 +++------ drivers/net/wireless/p54/p54common.c | 7 +++-- drivers/net/wireless/rt2x00/rt2400pci.c | 5 ++- drivers/net/wireless/rt2x00/rt2500pci.c | 6 ++-- drivers/net/wireless/rt2x00/rt2500usb.c | 6 ++-- drivers/net/wireless/rt2x00/rt2x00dev.c | 4 +-- drivers/net/wireless/rt2x00/rt61pci.c | 5 ++- drivers/net/wireless/rt2x00/rt73usb.c | 5 ++- drivers/net/wireless/rtl8180_dev.c | 9 +++--- drivers/net/wireless/rtl8187_dev.c | 10 +++--- drivers/net/wireless/zd1211rw/zd_mac.c | 12 ++++---- include/net/mac80211.h | 47 +++++++++++++++++++++-------- net/ieee80211/ieee80211_rx.c | 2 +- net/mac80211/debugfs_sta.c | 2 +- net/mac80211/ieee80211_i.h | 2 +- net/mac80211/main.c | 10 +++--- net/mac80211/mlme.c | 12 ++++---- net/mac80211/rx.c | 4 +-- net/mac80211/sta_info.h | 2 +- net/mac80211/wext.c | 28 ++++++++++++----- 29 files changed, 148 insertions(+), 145 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index d93a1de77eb..7af5d8851f6 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -445,9 +445,9 @@ static void adm8211_interrupt_rci(struct ieee80211_hw *dev) struct ieee80211_rx_status rx_status = {0}; if (priv->pdev->revision < ADM8211_REV_CA) - rx_status.ssi = rssi; + rx_status.signal = rssi; else - rx_status.ssi = 100 - rssi; + rx_status.signal = 100 - rssi; rx_status.rate_idx = rate; @@ -1893,9 +1893,10 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, dev->extra_tx_headroom = sizeof(struct adm8211_tx_hdr); /* dev->flags = IEEE80211_HW_RX_INCLUDES_FCS in promisc mode */ + dev->flags = IEEE80211_HW_SIGNAL_UNSPEC; dev->channel_change_time = 1000; - dev->max_rssi = 100; /* FIXME: find better value */ + dev->max_signal = 100; /* FIXME: find better value */ dev->queues = 1; /* ADM8211C supports more, maybe ADM8211B too */ diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 3201c160434..dd8adaddd7a 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -458,13 +458,11 @@ ath5k_pci_probe(struct pci_dev *pdev, /* Initialize driver private data */ SET_IEEE80211_DEV(hw, &pdev->dev); - hw->flags = IEEE80211_HW_RX_INCLUDES_FCS; + hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_NOISE_DBM; hw->extra_tx_headroom = 2; hw->channel_change_time = 5000; - /* these names are misleading */ - hw->max_rssi = -110; /* signal in dBm */ - hw->max_noise = -110; /* noise in dBm */ - hw->max_signal = 100; /* we will provide a percentage based on rssi */ sc = hw->priv; sc->hw = hw; sc->pdev = pdev; @@ -1893,20 +1891,9 @@ accept: rxs.freq = sc->curchan->center_freq; rxs.band = sc->curband->band; - /* - * signal quality: - * the names here are misleading and the usage of these - * values by iwconfig makes it even worse - */ - /* noise floor in dBm, from the last noise calibration */ rxs.noise = sc->ah->ah_noise_floor; - /* signal level in dBm */ - rxs.ssi = rxs.noise + rs.rs_rssi; - /* - * "signal" is actually displayed as Link Quality by iwconfig - * we provide a percentage based on rssi (assuming max rssi 64) - */ - rxs.signal = rs.rs_rssi * 100 / 64; + rxs.signal = rxs.noise + rs.rs_rssi; + rxs.qual = rs.rs_rssi * 100 / 64; rxs.antenna = rs.rs_antenna; rxs.rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate); diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 7c23aa8705c..fc23ba5309b 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4466,10 +4466,10 @@ static int b43_wireless_init(struct ssb_device *dev) /* fill hw info */ hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | - IEEE80211_HW_RX_INCLUDES_FCS; - hw->max_signal = 100; - hw->max_rssi = -110; - hw->max_noise = -110; + IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_NOISE_DBM; + hw->queues = b43_modparam_qos ? 4 : 1; SET_IEEE80211_DEV(hw, dev->dev); if (is_valid_ether_addr(sprom->et1mac)) diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 88491947a20..afce9338d83 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -581,12 +581,11 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) // and also find out what the maximum possible value is. // Fill status.ssi and status.signal fields. } else { - status.ssi = b43_rssi_postprocess(dev, rxhdr->jssi, + status.signal = b43_rssi_postprocess(dev, rxhdr->jssi, (phystat0 & B43_RX_PHYST0_OFDM), (phystat0 & B43_RX_PHYST0_GAINCTL), (phystat3 & B43_RX_PHYST3_TRSTATE)); - /* the next line looks wrong, but is what mac80211 wants */ - status.signal = (rxhdr->jssi * 100) / B43_RX_MAX_SSI; + status.qual = (rxhdr->jssi * 100) / B43_RX_MAX_SSI; } if (phystat0 & B43_RX_PHYST0_OFDM) diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index d3820dce3c4..7755c59e080 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -3718,10 +3718,9 @@ static int b43legacy_wireless_init(struct ssb_device *dev) /* fill hw info */ hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | - IEEE80211_HW_RX_INCLUDES_FCS; - hw->max_signal = 100; - hw->max_rssi = -110; - hw->max_noise = -110; + IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_NOISE_DBM; hw->queues = 1; /* FIXME: hardware has more queues */ SET_IEEE80211_DEV(hw, dev->dev); if (is_valid_ether_addr(sprom->et1mac)) diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c index fc83dab6e2c..bed9e041d6c 100644 --- a/drivers/net/wireless/b43legacy/xmit.c +++ b/drivers/net/wireless/b43legacy/xmit.c @@ -532,12 +532,12 @@ void b43legacy_rx(struct b43legacy_wldev *dev, } } - status.ssi = b43legacy_rssi_postprocess(dev, jssi, + status.signal = b43legacy_rssi_postprocess(dev, jssi, (phystat0 & B43legacy_RX_PHYST0_OFDM), (phystat0 & B43legacy_RX_PHYST0_GAINCTL), (phystat3 & B43legacy_RX_PHYST3_TRSTATE)); status.noise = dev->stats.link_noise; - status.signal = (jssi * 100) / B43legacy_RX_MAX_SSI; + status.qual = (jssi * 100) / B43legacy_RX_MAX_SSI; /* change to support A PHY */ if (phystat0 & B43legacy_RX_PHYST0_OFDM) status.rate_idx = b43legacy_plcp_get_bitrate_idx_ofdm(plcp, false); diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 8464397f781..d7beeff2642 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -520,7 +520,7 @@ static void iwl3945_add_radiotap(struct iwl3945_priv *priv, { /* First cache any information we need before we overwrite * the information provided in the skb from the hardware */ - s8 signal = stats->ssi; + s8 signal = stats->signal; s8 noise = 0; int rate = stats->rate_idx; u64 tsf = stats->mactime; @@ -693,7 +693,7 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, } /* Convert 3945's rssi indicator to dBm */ - rx_status.ssi = rx_stats->rssi - IWL_RSSI_OFFSET; + rx_status.signal = rx_stats->rssi - IWL_RSSI_OFFSET; /* Set default noise value to -127 */ if (priv->last_rx_noise == 0) @@ -712,21 +712,21 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, * Calculate rx_status.signal (quality indicator in %) based on SNR. */ if (rx_stats_noise_diff) { snr = rx_stats_sig_avg / rx_stats_noise_diff; - rx_status.noise = rx_status.ssi - + rx_status.noise = rx_status.signal - iwl3945_calc_db_from_ratio(snr); - rx_status.signal = iwl3945_calc_sig_qual(rx_status.ssi, + rx_status.qual = iwl3945_calc_sig_qual(rx_status.signal, rx_status.noise); /* If noise info not available, calculate signal quality indicator (%) * using just the dBm signal level. */ } else { rx_status.noise = priv->last_rx_noise; - rx_status.signal = iwl3945_calc_sig_qual(rx_status.ssi, 0); + rx_status.qual = iwl3945_calc_sig_qual(rx_status.signal, 0); } IWL_DEBUG_STATS("Rssi %d noise %d qual %d sig_avg %d noise_diff %d\n", - rx_status.ssi, rx_status.noise, rx_status.signal, + rx_status.signal, rx_status.noise, rx_status.qual, rx_stats_sig_avg, rx_stats_noise_diff); header = (struct ieee80211_hdr *)IWL_RX_DATA(pkt); @@ -736,8 +736,8 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, IWL_DEBUG_STATS_LIMIT("[%c] %d RSSI:%d Signal:%u, Noise:%u, Rate:%u\n", network_packet ? '*' : ' ', le16_to_cpu(rx_hdr->channel), - rx_status.ssi, rx_status.ssi, - rx_status.ssi, rx_status.rate_idx); + rx_status.signal, rx_status.signal, + rx_status.noise, rx_status.rate_idx); #ifdef CONFIG_IWL3945_DEBUG if (iwl3945_debug_level & (IWL_DL_RX)) @@ -748,7 +748,7 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, if (network_packet) { priv->last_beacon_time = le32_to_cpu(rx_end->beacon_timestamp); priv->last_tsf = le64_to_cpu(rx_end->timestamp); - priv->last_rx_rssi = rx_status.ssi; + priv->last_rx_rssi = rx_status.signal; priv->last_rx_noise = rx_status.noise; } diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index b7036e01145..45cbd7789bd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2362,7 +2362,7 @@ static void iwl4965_add_radiotap(struct iwl_priv *priv, struct ieee80211_rx_status *stats, u32 ampdu_status) { - s8 signal = stats->ssi; + s8 signal = stats->signal; s8 noise = 0; int rate = stats->rate_idx; u64 tsf = stats->mactime; @@ -2963,7 +2963,7 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv, priv->ucode_beacon_time = le32_to_cpu(rx_start->beacon_time_stamp); /* Find max signal strength (dBm) among 3 antenna/receiver chains */ - rx_status.ssi = iwl4965_calc_rssi(priv, rx_start); + rx_status.signal = iwl4965_calc_rssi(priv, rx_start); /* Meaningful noise values are available only from beacon statistics, * which are gathered only when associated, and indicate noise @@ -2972,11 +2972,11 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv, if (iwl_is_associated(priv) && !test_bit(STATUS_SCANNING, &priv->status)) { rx_status.noise = priv->last_rx_noise; - rx_status.signal = iwl4965_calc_sig_qual(rx_status.ssi, + rx_status.qual = iwl4965_calc_sig_qual(rx_status.signal, rx_status.noise); } else { rx_status.noise = IWL_NOISE_MEAS_NOT_AVAILABLE; - rx_status.signal = iwl4965_calc_sig_qual(rx_status.ssi, 0); + rx_status.qual = iwl4965_calc_sig_qual(rx_status.signal, 0); } /* Reset beacon noise level if not associated. */ @@ -2988,7 +2988,7 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv, iwl4965_dbg_report_frame(priv, pkt, header, 1); IWL_DEBUG_STATS_LIMIT("Rssi %d, noise %d, qual %d, TSF %llu\n", - rx_status.ssi, rx_status.noise, rx_status.signal, + rx_status.signal, rx_status.noise, rx_status.signal, (unsigned long long)rx_status.mactime); @@ -3000,7 +3000,7 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv, network_packet = iwl4965_is_network_packet(priv, header); if (network_packet) { - priv->last_rx_rssi = rx_status.ssi; + priv->last_rx_rssi = rx_status.signal; priv->last_beacon_time = priv->ucode_beacon_time; priv->last_tsf = le64_to_cpu(rx_start->timestamp); } diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 27e56b89d94..d3cbad2bf87 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -746,18 +746,10 @@ static void iwlcore_init_hw(struct iwl_priv *priv) struct ieee80211_hw *hw = priv->hw; hw->rate_control_algorithm = "iwl-4965-rs"; - /* Tell mac80211 and its clients (e.g. Wireless Extensions) - * the range of signal quality values that we'll provide. - * Negative values for level/noise indicate that we'll provide dBm. - * For WE, at least, non-0 values here *enable* display of values - * in app (iwconfig). */ - hw->max_rssi = -20; /* signal level, negative indicates dBm */ - hw->max_noise = -20; /* noise level, negative indicates dBm */ - hw->max_signal = 100; /* link quality indication (%) */ - - /* Tell mac80211 our Tx characteristics */ - hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE; - + /* Tell mac80211 our characteristics */ + hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_NOISE_DBM; /* Default value; 4 EDCA QOS priorities */ hw->queues = 4; #ifdef CONFIG_IWL4965_HT diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 4baa185ba50..c1234ff4fc9 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -8029,17 +8029,10 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e priv->ibss_beacon = NULL; - /* Tell mac80211 and its clients (e.g. Wireless Extensions) - * the range of signal quality values that we'll provide. - * Negative values for level/noise indicate that we'll provide dBm. - * For WE, at least, non-0 values here *enable* display of values - * in app (iwconfig). */ - hw->max_rssi = -20; /* signal level, negative indicates dBm */ - hw->max_noise = -20; /* noise level, negative indicates dBm */ - hw->max_signal = 100; /* link quality indication (%) */ - - /* Tell mac80211 our Tx characteristics */ - hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE; + /* Tell mac80211 our characteristics */ + hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_NOISE_DBM; /* 4 EDCA QOS priorities */ hw->queues = 4; diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 33d608a60d7..9cbef5bce0f 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -355,7 +355,7 @@ static void p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) struct ieee80211_rx_status rx_status = {0}; u16 freq = le16_to_cpu(hdr->freq); - rx_status.ssi = hdr->rssi; + rx_status.signal = hdr->rssi; /* XX correct? */ rx_status.rate_idx = hdr->rate & 0xf; rx_status.freq = freq; @@ -1000,9 +1000,10 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) skb_queue_head_init(&priv->tx_queue); dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz; dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | /* not sure */ - IEEE80211_HW_RX_INCLUDES_FCS; + IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_SIGNAL_UNSPEC; dev->channel_change_time = 1000; /* TODO: find actual value */ - dev->max_rssi = 127; + dev->max_signal = 127; priv->tx_stats[0].limit = 5; dev->queues = 1; diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 247fbbfb0f2..afa565c6362 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1361,10 +1361,9 @@ static void rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) /* * Initialize all hw fields. */ - rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; + rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_SIGNAL_DBM; rt2x00dev->hw->extra_tx_headroom = 0; - rt2x00dev->hw->max_signal = MAX_SIGNAL; - rt2x00dev->hw->max_rssi = MAX_RX_SSI; rt2x00dev->hw->queues = 2; SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev); diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 0d53c75d55d..c06f1b5e588 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1680,10 +1680,10 @@ static void rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) /* * Initialize all hw fields. */ - rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; + rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_SIGNAL_DBM; + rt2x00dev->hw->extra_tx_headroom = 0; - rt2x00dev->hw->max_signal = MAX_SIGNAL; - rt2x00dev->hw->max_rssi = MAX_RX_SSI; rt2x00dev->hw->queues = 2; SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev); diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 80b34d47114..88bafdf8f0f 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1587,10 +1587,10 @@ static void rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) rt2x00dev->hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_SIGNAL_DBM; + rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE; - rt2x00dev->hw->max_signal = MAX_SIGNAL; - rt2x00dev->hw->max_rssi = MAX_RX_SSI; rt2x00dev->hw->queues = 2; SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev); diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 9929b15e28b..f51a50b31e1 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -600,9 +600,9 @@ void rt2x00lib_rxdone(struct queue_entry *entry, rt2x00dev->link.qual.rx_success++; rx_status->rate_idx = idx; - rx_status->signal = + rx_status->qual = rt2x00lib_calculate_link_signal(rt2x00dev, rxdesc->rssi); - rx_status->ssi = rxdesc->rssi; + rx_status->signal = rxdesc->rssi; rx_status->flag = rxdesc->flags; rx_status->antenna = rt2x00dev->link.ant.active.rx; diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 98af4d26583..eaf23b90877 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2245,10 +2245,9 @@ static void rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) */ rt2x00dev->hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_SIGNAL_DBM; rt2x00dev->hw->extra_tx_headroom = 0; - rt2x00dev->hw->max_signal = MAX_SIGNAL; - rt2x00dev->hw->max_rssi = MAX_RX_SSI; rt2x00dev->hw->queues = 4; SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev); diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 351d95c4f50..51c5575ed02 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1830,10 +1830,9 @@ static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) */ rt2x00dev->hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_SIGNAL_DBM; rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE; - rt2x00dev->hw->max_signal = MAX_SIGNAL; - rt2x00dev->hw->max_rssi = MAX_RX_SSI; rt2x00dev->hw->queues = 4; SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev); diff --git a/drivers/net/wireless/rtl8180_dev.c b/drivers/net/wireless/rtl8180_dev.c index c181f23e930..c220998cee6 100644 --- a/drivers/net/wireless/rtl8180_dev.c +++ b/drivers/net/wireless/rtl8180_dev.c @@ -132,8 +132,8 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev) rx_status.antenna = (flags2 >> 15) & 1; /* TODO: improve signal/rssi reporting */ - rx_status.signal = flags2 & 0xFF; - rx_status.ssi = (flags2 >> 8) & 0x7F; + rx_status.qual = flags2 & 0xFF; + rx_status.signal = (flags2 >> 8) & 0x7F; /* XXX: is this correct? */ rx_status.rate_idx = (flags >> 20) & 0xF; rx_status.freq = dev->conf.channel->center_freq; @@ -894,9 +894,10 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev, dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_RX_INCLUDES_FCS; + IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_SIGNAL_UNSPEC; dev->queues = 1; - dev->max_rssi = 65; + dev->max_signal = 65; reg = rtl818x_ioread32(priv, &priv->map->TX_CONF); reg &= RTL818X_TX_CONF_HWVER_MASK; diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index d5787b37e1f..e14c8424868 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -261,8 +261,8 @@ static void rtl8187_rx_cb(struct urb *urb) } rx_status.antenna = (hdr->signal >> 7) & 1; - rx_status.signal = 64 - min(hdr->noise, (u8)64); - rx_status.ssi = signal; + rx_status.qual = 64 - min(hdr->noise, (u8)64); + rx_status.signal = signal; rx_status.rate_idx = rate; rx_status.freq = dev->conf.channel->center_freq; rx_status.band = dev->conf.channel->band; @@ -740,11 +740,11 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, priv->mode = IEEE80211_IF_TYPE_MNTR; dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_RX_INCLUDES_FCS; + IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_SIGNAL_UNSPEC; dev->extra_tx_headroom = sizeof(struct rtl8187_tx_hdr); dev->queues = 1; - dev->max_rssi = 65; - dev->max_signal = 64; + dev->max_signal = 65; eeprom.data = dev; eeprom.register_read = rtl8187_eeprom_register_read; diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index ee4331229f1..0c736735e21 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -638,7 +638,7 @@ static int filter_ack(struct ieee80211_hw *hw, struct ieee80211_hdr *rx_hdr, memset(&status, 0, sizeof(status)); status.flags = IEEE80211_TX_STATUS_ACK; - status.ack_signal = stats->ssi; + status.ack_signal = stats->signal; __skb_unlink(skb, q); tx_status(hw, skb, &status, 1); goto out; @@ -691,8 +691,8 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length) stats.freq = zd_channels[_zd_chip_get_channel(&mac->chip) - 1].center_freq; stats.band = IEEE80211_BAND_2GHZ; - stats.ssi = status->signal_strength; - stats.signal = zd_rx_qual_percent(buffer, + stats.signal = status->signal_strength; + stats.qual = zd_rx_qual_percent(buffer, length - sizeof(struct rx_status), status); @@ -997,10 +997,10 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf) hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &mac->band; hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE; - hw->max_rssi = 100; - hw->max_signal = 100; + IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | + IEEE80211_HW_SIGNAL_DB; + hw->max_signal = 100; hw->queues = 1; hw->extra_tx_headroom = sizeof(struct zd_ctrlset); diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 75a34609eed..909956c97c4 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -336,13 +336,16 @@ enum mac80211_rx_flags { * The low-level driver should provide this information (the subset * supported by hardware) to the 802.11 code with each received * frame. + * * @mactime: value in microseconds of the 64-bit Time Synchronization Function * (TSF) timer when the first data symbol (MPDU) arrived at the hardware. * @band: the active band when this frame was received * @freq: frequency the radio was tuned to when receiving this frame, in MHz - * @ssi: signal strength when receiving this frame - * @signal: used as 'qual' in statistics reporting - * @noise: PHY noise when receiving this frame + * @signal: signal strength when receiving this frame, either in dBm, in dB or + * unspecified depending on the hardware capabilities flags + * @IEEE80211_HW_SIGNAL_* + * @noise: noise when receiving this frame, in dBm. + * @qual: overall signal quality indication, in percent (0-100). * @antenna: antenna used * @rate_idx: index of data rate into band's supported rates * @flag: %RX_FLAG_* @@ -351,9 +354,9 @@ struct ieee80211_rx_status { u64 mactime; enum ieee80211_band band; int freq; - int ssi; int signal; int noise; + int qual; int antenna; int rate_idx; int flag; @@ -392,7 +395,8 @@ enum ieee80211_tx_status_flags { * relevant only if IEEE80211_TX_STATUS_AMPDU was set. * @ampdu_ack_map: block ack bit map for the aggregation. * relevant only if IEEE80211_TX_STATUS_AMPDU was set. - * @ack_signal: signal strength of the ACK frame + * @ack_signal: signal strength of the ACK frame either in dBm, dB or unspec + * depending on hardware capabilites flags @IEEE80211_HW_SIGNAL_* */ struct ieee80211_tx_status { struct ieee80211_tx_control control; @@ -703,6 +707,25 @@ enum ieee80211_tkip_key_type { * @IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE: * Hardware is not capable of receiving frames with short preamble on * the 2.4 GHz band. + * + * @IEEE80211_HW_SIGNAL_UNSPEC: + * Hardware can provide signal values but we don't know its units. We + * expect values between 0 and @max_signal. + * If possible please provide dB or dBm instead. + * + * @IEEE80211_HW_SIGNAL_DB: + * Hardware gives signal values in dB, decibel difference from an + * arbitrary, fixed reference. We expect values between 0 and @max_signal. + * If possible please provide dBm instead. + * + * @IEEE80211_HW_SIGNAL_DBM: + * Hardware gives signal values in dBm, decibel difference from + * one milliwatt. This is the preferred method since it is standardized + * between different devices. @max_signal does not need to be set. + * + * @IEEE80211_HW_NOISE_DBM: + * Hardware can provide noise (radio interference) values in units dBm, + * decibel difference from one milliwatt. */ enum ieee80211_hw_flags { IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE = 1<<0, @@ -710,6 +733,10 @@ enum ieee80211_hw_flags { IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING = 1<<2, IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE = 1<<3, IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE = 1<<4, + IEEE80211_HW_SIGNAL_UNSPEC = 1<<5, + IEEE80211_HW_SIGNAL_DB = 1<<6, + IEEE80211_HW_SIGNAL_DBM = 1<<7, + IEEE80211_HW_NOISE_DBM = 1<<8, }; /** @@ -740,12 +767,8 @@ enum ieee80211_hw_flags { * * @channel_change_time: time (in microseconds) it takes to change channels. * - * @max_rssi: Maximum value for ssi in RX information, use - * negative numbers for dBm and 0 to indicate no support. - * - * @max_signal: like @max_rssi, but for the signal value. - * - * @max_noise: like @max_rssi, but for the noise value. + * @max_signal: Maximum value for signal (rssi) in RX information, used + * only when @IEEE80211_HW_SIGNAL_UNSPEC or @IEEE80211_HW_SIGNAL_DB * * @queues: number of available hardware transmit queues for * data packets. WMM/QoS requires at least four, these @@ -775,9 +798,7 @@ struct ieee80211_hw { int channel_change_time; int vif_data_size; u16 queues, ampdu_queues; - s8 max_rssi; s8 max_signal; - s8 max_noise; }; /** diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c index 200ee1e6372..69dbc342a46 100644 --- a/net/ieee80211/ieee80211_rx.c +++ b/net/ieee80211/ieee80211_rx.c @@ -391,7 +391,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, wstats.updated = 0; if (rx_stats->mask & IEEE80211_STATMASK_RSSI) { - wstats.level = rx_stats->rssi; + wstats.level = rx_stats->signal; wstats.updated |= IW_QUAL_LEVEL_UPDATED; } else wstats.updated |= IW_QUAL_LEVEL_INVALID; diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 1f00273d99c..a2cc0284c9d 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -63,8 +63,8 @@ STA_FILE(tx_fragments, tx_fragments, LU); STA_FILE(tx_filtered, tx_filtered_count, LU); STA_FILE(tx_retry_failed, tx_retry_failed, LU); STA_FILE(tx_retry_count, tx_retry_count, LU); -STA_FILE(last_rssi, last_rssi, D); STA_FILE(last_signal, last_signal, D); +STA_FILE(last_qual, last_qual, D); STA_FILE(last_noise, last_noise, D); STA_FILE(channel_use, channel_use, D); STA_FILE(wep_weak_iv_count, wep_weak_iv_count, LU); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 173b7fcb302..ed0d9b35ae6 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -82,7 +82,7 @@ struct ieee80211_sta_bss { u16 capability; /* host byte order */ enum ieee80211_band band; int freq; - int rssi, signal, noise; + int signal, noise, qual; u8 *wpa_ie; size_t wpa_ie_len; u8 *rsn_ie; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index f277407f0f5..390df48dfd4 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -1702,13 +1702,13 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) local->hw.conf.beacon_int = 1000; - local->wstats_flags |= local->hw.max_rssi ? - IW_QUAL_LEVEL_UPDATED : IW_QUAL_LEVEL_INVALID; - local->wstats_flags |= local->hw.max_signal ? + local->wstats_flags |= local->hw.flags & (IEEE80211_HW_SIGNAL_UNSPEC | + IEEE80211_HW_SIGNAL_DB | + IEEE80211_HW_SIGNAL_DBM) ? IW_QUAL_QUAL_UPDATED : IW_QUAL_QUAL_INVALID; - local->wstats_flags |= local->hw.max_noise ? + local->wstats_flags |= local->hw.flags & IEEE80211_HW_NOISE_DBM ? IW_QUAL_NOISE_UPDATED : IW_QUAL_NOISE_INVALID; - if (local->hw.max_rssi < 0 || local->hw.max_noise < 0) + if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) local->wstats_flags |= IW_QUAL_DBM; result = sta_info_start(local); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 6c4b27be35d..dda30e98aa1 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1959,8 +1959,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, local->hw.conf.channel->center_freq, ifsta->ssid, ifsta->ssid_len); if (bss) { - sta->last_rssi = bss->rssi; sta->last_signal = bss->signal; + sta->last_qual = bss->qual; sta->last_noise = bss->noise; ieee80211_rx_bss_put(dev, bss); } @@ -2629,9 +2629,9 @@ static void ieee80211_rx_bss_info(struct net_device *dev, bss->timestamp = beacon_timestamp; bss->last_update = jiffies; - bss->rssi = rx_status->ssi; bss->signal = rx_status->signal; bss->noise = rx_status->noise; + bss->qual = rx_status->qual; if (!beacon && !bss->probe_resp) bss->probe_resp = true; @@ -3427,9 +3427,9 @@ static int ieee80211_sta_config_auth(struct net_device *dev, !ieee80211_sta_match_ssid(ifsta, bss->ssid, bss->ssid_len)) continue; - if (!selected || top_rssi < bss->rssi) { + if (!selected || top_rssi < bss->signal) { selected = bss; - top_rssi = bss->rssi; + top_rssi = bss->signal; } } if (selected) @@ -4060,8 +4060,8 @@ ieee80211_sta_scan_result(struct net_device *dev, memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVQUAL; - iwe.u.qual.qual = bss->signal; - iwe.u.qual.level = bss->rssi; + iwe.u.qual.qual = bss->qual; + iwe.u.qual.level = bss->signal; iwe.u.qual.noise = bss->noise; iwe.u.qual.updated = local->wstats_flags; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b399e09ec7a..474f13662c8 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -209,7 +209,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, cpu_to_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ); - rtfixed->antsignal = status->ssi; + rtfixed->antsignal = status->signal; rthdr->it_len = cpu_to_le16(rtap_len); } @@ -719,8 +719,8 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) sta->rx_fragments++; sta->rx_bytes += rx->skb->len; - sta->last_rssi = rx->status->ssi; sta->last_signal = rx->status->signal; + sta->last_qual = rx->status->qual; sta->last_noise = rx->status->noise; if (!(rx->fc & IEEE80211_FCTL_MOREFRAGS)) { diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 97a61c39ad9..e89cc165554 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -216,8 +216,8 @@ struct sta_info { * from this STA */ unsigned long rx_fragments; /* number of received MPDUs */ unsigned long rx_dropped; /* number of dropped MPDUs from this STA */ - int last_rssi; /* RSSI of last received frame from this STA */ int last_signal; /* signal of last received frame from this STA */ + int last_qual; /* qual of last received frame from this STA */ int last_noise; /* noise of last received frame from this STA */ /* last received seq/frag number from this STA (per RX queue) */ __le16 last_seq_ctrl[NUM_RX_DATA_QUEUES]; diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index 76e1de1dc73..6a342a9a40c 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -169,14 +169,26 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev, range->num_encoding_sizes = 2; range->max_encoding_tokens = NUM_DEFAULT_KEYS; - range->max_qual.qual = local->hw.max_signal; - range->max_qual.level = local->hw.max_rssi; - range->max_qual.noise = local->hw.max_noise; + if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC || + local->hw.flags & IEEE80211_HW_SIGNAL_DB) + range->max_qual.level = local->hw.max_signal; + else if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) + range->max_qual.level = -110; + else + range->max_qual.level = 0; + + if (local->hw.flags & IEEE80211_HW_NOISE_DBM) + range->max_qual.noise = -110; + else + range->max_qual.noise = 0; + + range->max_qual.qual = 100; range->max_qual.updated = local->wstats_flags; - range->avg_qual.qual = local->hw.max_signal/2; - range->avg_qual.level = 0; - range->avg_qual.noise = 0; + range->avg_qual.qual = 50; + /* not always true but better than nothing */ + range->avg_qual.level = range->max_qual.level / 2; + range->avg_qual.noise = range->max_qual.noise / 2; range->avg_qual.updated = local->wstats_flags; range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | @@ -996,8 +1008,8 @@ static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev wstats->qual.noise = 0; wstats->qual.updated = IW_QUAL_ALL_INVALID; } else { - wstats->qual.level = sta->last_rssi; - wstats->qual.qual = sta->last_signal; + wstats->qual.level = sta->last_signal; + wstats->qual.qual = sta->last_qual; wstats->qual.noise = sta->last_noise; wstats->qual.updated = local->wstats_flags; } -- cgit v1.2.3-70-g09d2 From 7a1d65235da829e6dc8938b82c991e40e278fc50 Mon Sep 17 00:00:00 2001 From: Huang Weiyi Date: Sat, 10 May 2008 11:12:31 +0200 Subject: b43: nphy.c remove duplicated include Remove duplicated include in drivers/net/wireless/b43/nphy.c Signed-off-by: Huang Weiyi Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/nphy.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/nphy.c b/drivers/net/wireless/b43/nphy.c index 8695eb22347..644eed993be 100644 --- a/drivers/net/wireless/b43/nphy.c +++ b/drivers/net/wireless/b43/nphy.c @@ -29,8 +29,6 @@ #include "nphy.h" #include "tables_nphy.h" -#include - void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna) {//TODO -- cgit v1.2.3-70-g09d2 From d6894b5be1d674a31a94ed8f057c9f7d98c53999 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Mon, 12 May 2008 21:16:44 -0400 Subject: ath5k: Fix loop variable initializations In ath5k_tasklet_rx, both status structures 'rxs' and 'rs' are initialized at the top of the tasklet, but not within the loop. If the loop is executed multiple times in the tasklet then the variables may see changes from previous packets. For TKIP, this results in 'Invalid Michael MIC' errors if two packets are processed in the tasklet: rxs.flag gets set to RX_DECRYPTED by mac80211 when it decrypts the first encrypted packet. The subsequent packet will have RX_DECRYPTED set upon entry to mac80211, so mac80211 will not try to decrypt it. We currently initialize all but two fields in the structures, so fix the other two. Signed-off-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 2 ++ drivers/net/wireless/ath5k/hw.c | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index dd8adaddd7a..c76ada17878 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -1785,6 +1785,8 @@ ath5k_tasklet_rx(unsigned long data) spin_lock(&sc->rxbuflock); do { + rxs.flag = 0; + if (unlikely(list_empty(&sc->rxbuf))) { ATH5K_WARN(sc, "empty rx buf pool\n"); break; diff --git a/drivers/net/wireless/ath5k/hw.c b/drivers/net/wireless/ath5k/hw.c index 5fb1ae6ad3e..77990b56860 100644 --- a/drivers/net/wireless/ath5k/hw.c +++ b/drivers/net/wireless/ath5k/hw.c @@ -4119,6 +4119,7 @@ static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah, rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1, AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP); rs->rs_status = 0; + rs->rs_phyerr = 0; /* * Key table status @@ -4145,7 +4146,7 @@ static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah, if (rx_status->rx_status_1 & AR5K_5210_RX_DESC_STATUS1_PHY_ERROR) { rs->rs_status |= AR5K_RXERR_PHY; - rs->rs_phyerr = AR5K_REG_MS(rx_status->rx_status_1, + rs->rs_phyerr |= AR5K_REG_MS(rx_status->rx_status_1, AR5K_5210_RX_DESC_STATUS1_PHY_ERROR); } @@ -4193,6 +4194,7 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah, rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1, AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP); rs->rs_status = 0; + rs->rs_phyerr = 0; /* * Key table status @@ -4215,7 +4217,7 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah, if (rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) { rs->rs_status |= AR5K_RXERR_PHY; - rs->rs_phyerr = AR5K_REG_MS(rx_err->rx_error_1, + rs->rs_phyerr |= AR5K_REG_MS(rx_err->rx_error_1, AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE); } -- cgit v1.2.3-70-g09d2 From 6dcdc19e4ba4e6a9ccd733fdb745ad062cf3ea0a Mon Sep 17 00:00:00 2001 From: Harvey Harrison Date: Tue, 13 May 2008 18:13:35 -0700 Subject: b43: use the bitrev helpers rather than rolling a private one The 4-bit reversal flip_4bit is replaced with the bitrev helper bitrev8 and a 4-bit shift. The B43_WARN is moved to the location where a register is read from for checking there. The other caller explicitly passes an array index which is guaranteed to be within range and so a B43_WARN is not added there. Signed-off-by: Harvey Harrison Reviewed-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy.c | 27 ++++++--------------------- 1 file changed, 6 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/phy.c b/drivers/net/wireless/b43/phy.c index 6378c266549..305d4cd6fd0 100644 --- a/drivers/net/wireless/b43/phy.c +++ b/drivers/net/wireless/b43/phy.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "b43.h" #include "phy.h" @@ -83,25 +84,9 @@ const u8 b43_radio_channel_codes_bg[] = { 72, 84, }; +#define bitrev4(tmp) (bitrev8(tmp) >> 4) static void b43_phy_initg(struct b43_wldev *dev); -/* Reverse the bits of a 4bit value. - * Example: 1101 is flipped 1011 - */ -static u16 flip_4bit(u16 value) -{ - u16 flipped = 0x0000; - - B43_WARN_ON(value & ~0x000F); - - flipped |= (value & 0x0001) << 3; - flipped |= (value & 0x0002) << 1; - flipped |= (value & 0x0004) >> 1; - flipped |= (value & 0x0008) >> 3; - - return flipped; -} - static void generate_rfatt_list(struct b43_wldev *dev, struct b43_rfatt_list *list) { @@ -2891,13 +2876,13 @@ b43_radio_interference_mitigation_enable(struct b43_wldev *dev, int mode) } radio_stacksave(0x0078); tmp = (b43_radio_read16(dev, 0x0078) & 0x001E); - flipped = flip_4bit(tmp); + B43_WARN_ON(tmp > 15); + flipped = bitrev4(tmp); if (flipped < 10 && flipped >= 8) flipped = 7; else if (flipped >= 10) flipped -= 3; - flipped = flip_4bit(flipped); - flipped = (flipped << 1) | 0x0020; + flipped = (bitrev4(flipped) << 1) | 0x0020; b43_radio_write16(dev, 0x0078, flipped); b43_calc_nrssi_threshold(dev); @@ -3530,7 +3515,7 @@ u16 b43_radio_init2050(struct b43_wldev *dev) tmp1 >>= 9; for (i = 0; i < 16; i++) { - radio78 = ((flip_4bit(i) << 1) | 0x20); + radio78 = (bitrev4(i) << 1) | 0x0020; b43_radio_write16(dev, 0x78, radio78); udelay(10); for (j = 0; j < 16; j++) { -- cgit v1.2.3-70-g09d2 From ef85ad541f9a6ccd3f89ec73f92b2d6f45a9d3e8 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Wed, 14 May 2008 16:27:18 +0200 Subject: libertas: remove lbs_get_data_rate() lbs_get_data_rate() gets called, but no-one uses it's result. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 32 -------------------------------- drivers/net/wireless/libertas/cmd.h | 1 - drivers/net/wireless/libertas/main.c | 12 +----------- 3 files changed, 1 insertion(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 6328b959387..c2dd43ece06 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -696,38 +696,6 @@ static int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv, return 0; } -/** - * @brief Get the current data rate - * - * @param priv A pointer to struct lbs_private structure - * - * @return The data rate on success, error on failure - */ -int lbs_get_data_rate(struct lbs_private *priv) -{ - struct cmd_ds_802_11_data_rate cmd; - int ret = -1; - - lbs_deb_enter(LBS_DEB_CMD); - - memset(&cmd, 0, sizeof(cmd)); - cmd.hdr.size = cpu_to_le16(sizeof(cmd)); - cmd.action = cpu_to_le16(CMD_ACT_GET_TX_RATE); - - ret = lbs_cmd_with_response(priv, CMD_802_11_DATA_RATE, &cmd); - if (ret) - goto out; - - lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) &cmd, sizeof (cmd)); - - ret = (int) lbs_fw_index_to_data_rate(cmd.rates[0]); - lbs_deb_cmd("DATA_RATE: current rate 0x%02x\n", ret); - -out: - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); - return ret; -} - /** * @brief Set the data rate * diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h index 4295bc61366..f4019c22adf 100644 --- a/drivers/net/wireless/libertas/cmd.h +++ b/drivers/net/wireless/libertas/cmd.h @@ -34,7 +34,6 @@ int lbs_update_hw_spec(struct lbs_private *priv); int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action, struct cmd_ds_mesh_access *cmd); -int lbs_get_data_rate(struct lbs_private *priv); int lbs_set_data_rate(struct lbs_private *priv, u8 rate); int lbs_get_channel(struct lbs_private *priv); diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 0be89573716..e333f14dce2 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -927,20 +927,10 @@ static int lbs_setup_firmware(struct lbs_private *priv) */ memset(priv->current_addr, 0xff, ETH_ALEN); ret = lbs_update_hw_spec(priv); - if (ret) { - ret = -1; + if (ret) goto done; - } lbs_set_mac_control(priv); - - ret = lbs_get_data_rate(priv); - if (ret < 0) { - ret = -1; - goto done; - } - - ret = 0; done: lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); return ret; -- cgit v1.2.3-70-g09d2 From 09e67ca2c523544e6b38aa570a5f62a0cf20b87b Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 16 May 2008 11:57:45 +1000 Subject: [POWERPC] Move of_device_get_modalias to drivers/of Commit 140b932f8cb6cced10b96860651a198b1b89cbb9 ("Create modalias file in sysfs for of_platform bus") needs this to avoid breaking the sparc builds. Just move the code and add whitespace around some binary operators. Signed-off-by: Stephen Rothwell Acked-by: David S. Miller Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/of_device.c | 48 ----------------------------------------- drivers/of/device.c | 48 +++++++++++++++++++++++++++++++++++++++++ include/asm-powerpc/of_device.h | 2 -- include/linux/of_device.h | 3 +++ 4 files changed, 51 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/arch/powerpc/kernel/of_device.c b/arch/powerpc/kernel/of_device.c index 5748ddb47d9..e9be908f199 100644 --- a/arch/powerpc/kernel/of_device.c +++ b/arch/powerpc/kernel/of_device.c @@ -89,54 +89,6 @@ struct of_device *of_device_alloc(struct device_node *np, } EXPORT_SYMBOL(of_device_alloc); -ssize_t of_device_get_modalias(struct of_device *ofdev, - char *str, ssize_t len) -{ - const char *compat; - int cplen, i; - ssize_t tsize, csize, repend; - - /* Name & Type */ - csize = snprintf(str, len, "of:N%sT%s", - ofdev->node->name, ofdev->node->type); - - /* Get compatible property if any */ - compat = of_get_property(ofdev->node, "compatible", &cplen); - if (!compat) - return csize; - - /* Find true end (we tolerate multiple \0 at the end */ - for (i=(cplen-1); i>=0 && !compat[i]; i--) - cplen--; - if (!cplen) - return csize; - cplen++; - - /* Check space (need cplen+1 chars including final \0) */ - tsize = csize + cplen; - repend = tsize; - - if (csize>=len) /* @ the limit, all is already filled */ - return tsize; - - if (tsize>=len) { /* limit compat list */ - cplen = len-csize-1; - repend = len; - } - - /* Copy and do char replacement */ - memcpy(&str[csize+1], compat, cplen); - for (i=csize; idev); } EXPORT_SYMBOL(of_device_unregister); + +ssize_t of_device_get_modalias(struct of_device *ofdev, + char *str, ssize_t len) +{ + const char *compat; + int cplen, i; + ssize_t tsize, csize, repend; + + /* Name & Type */ + csize = snprintf(str, len, "of:N%sT%s", + ofdev->node->name, ofdev->node->type); + + /* Get compatible property if any */ + compat = of_get_property(ofdev->node, "compatible", &cplen); + if (!compat) + return csize; + + /* Find true end (we tolerate multiple \0 at the end */ + for (i = (cplen - 1); i >= 0 && !compat[i]; i--) + cplen--; + if (!cplen) + return csize; + cplen++; + + /* Check space (need cplen+1 chars including final \0) */ + tsize = csize + cplen; + repend = tsize; + + if (csize >= len) /* @ the limit, all is already filled */ + return tsize; + + if (tsize >= len) { /* limit compat list */ + cplen = len - csize - 1; + repend = len; + } + + /* Copy and do char replacement */ + memcpy(&str[csize + 1], compat, cplen); + for (i = csize; i < repend; i++) { + char c = str[i]; + if (c == '\0') + str[i] = 'C'; + else if (c == ' ') + str[i] = '_'; + } + + return tsize; +} diff --git a/include/asm-powerpc/of_device.h b/include/asm-powerpc/of_device.h index 6526e139a46..3c123990ca2 100644 --- a/include/asm-powerpc/of_device.h +++ b/include/asm-powerpc/of_device.h @@ -21,8 +21,6 @@ extern struct of_device *of_device_alloc(struct device_node *np, const char *bus_id, struct device *parent); -extern ssize_t of_device_get_modalias(struct of_device *ofdev, - char *str, ssize_t len); extern int of_device_uevent(struct device *dev, struct kobj_uevent_env *env); diff --git a/include/linux/of_device.h b/include/linux/of_device.h index afe338217d9..d3a74e00a3e 100644 --- a/include/linux/of_device.h +++ b/include/linux/of_device.h @@ -24,4 +24,7 @@ static inline void of_device_free(struct of_device *dev) of_release_dev(&dev->dev); } +extern ssize_t of_device_get_modalias(struct of_device *ofdev, + char *str, ssize_t len); + #endif /* _LINUX_OF_DEVICE_H */ -- cgit v1.2.3-70-g09d2 From ea3e6c59266b783b103c0f42a8de5dbe565a43d4 Mon Sep 17 00:00:00 2001 From: Harvey Harrison Date: Mon, 5 May 2008 11:36:18 -0400 Subject: Input: replace remaining __FUNCTION__ occurrences __FUNCTION__ is gcc-specific, use __func__ Signed-off-by: Harvey Harrison Signed-off-by: Andrew Morton Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/iforce/iforce-usb.c | 6 +++--- drivers/input/joystick/xpad.c | 12 ++++++------ drivers/input/keyboard/lkkbd.c | 6 +++--- drivers/input/misc/ati_remote.c | 18 +++++++++--------- drivers/input/misc/ati_remote2.c | 18 +++++++++--------- drivers/input/misc/keyspan_remote.c | 20 ++++++++++---------- drivers/input/misc/powermate.c | 6 +++--- drivers/input/misc/yealink.c | 12 ++++++------ drivers/input/mouse/appletouch.c | 8 ++++---- drivers/input/tablet/acecad.c | 4 ++-- drivers/input/tablet/aiptek.c | 6 +++--- drivers/input/tablet/kbtab.c | 6 +++--- drivers/input/tablet/wacom_sys.c | 6 +++--- drivers/input/touchscreen/usbtouchscreen.c | 22 +++++++++++----------- 14 files changed, 75 insertions(+), 75 deletions(-) (limited to 'drivers') diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c index 7fb3cf81cfb..8f6a987ebb9 100644 --- a/drivers/input/joystick/iforce/iforce-usb.c +++ b/drivers/input/joystick/iforce/iforce-usb.c @@ -89,10 +89,10 @@ static void iforce_usb_irq(struct urb *urb) case -ESHUTDOWN: /* this urb is terminated, clean up */ dbg("%s - urb shutting down with status: %d", - __FUNCTION__, urb->status); + __func__, urb->status); return; default: - dbg("%s - urb has status of: %d", __FUNCTION__, urb->status); + dbg("%s - urb has status of: %d", __func__, urb->status); goto exit; } @@ -103,7 +103,7 @@ exit: status = usb_submit_urb (urb, GFP_ATOMIC); if (status) err ("%s - usb_submit_urb failed with result %d", - __FUNCTION__, status); + __func__, status); } static void iforce_usb_out(struct urb *urb) diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index b29e3affb80..87d3e7eabff 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -418,11 +418,11 @@ static void xpad_irq_in(struct urb *urb) case -ESHUTDOWN: /* this urb is terminated, clean up */ dbg("%s - urb shutting down with status: %d", - __FUNCTION__, status); + __func__, status); return; default: dbg("%s - nonzero urb status received: %d", - __FUNCTION__, status); + __func__, status); goto exit; } @@ -441,7 +441,7 @@ exit: retval = usb_submit_urb (urb, GFP_ATOMIC); if (retval) err ("%s - usb_submit_urb failed with result %d", - __FUNCTION__, retval); + __func__, retval); } static void xpad_bulk_out(struct urb *urb) @@ -477,11 +477,11 @@ static void xpad_irq_out(struct urb *urb) case -ESHUTDOWN: /* this urb is terminated, clean up */ dbg("%s - urb shutting down with status: %d", - __FUNCTION__, status); + __func__, status); return; default: dbg("%s - nonzero urb status received: %d", - __FUNCTION__, status); + __func__, status); goto exit; } @@ -489,7 +489,7 @@ exit: retval = usb_submit_urb(urb, GFP_ATOMIC); if (retval) err("%s - usb_submit_urb failed with result %d", - __FUNCTION__, retval); + __func__, retval); } static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) diff --git a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c index 32e2c2605d9..4730ef35c73 100644 --- a/drivers/input/keyboard/lkkbd.c +++ b/drivers/input/keyboard/lkkbd.c @@ -538,11 +538,11 @@ lkkbd_event (struct input_dev *dev, unsigned int type, unsigned int code, switch (code) { case SND_CLICK: if (value == 0) { - DBG ("%s: Deactivating key clicks\n", __FUNCTION__); + DBG ("%s: Deactivating key clicks\n", __func__); lk->serio->write (lk->serio, LK_CMD_DISABLE_KEYCLICK); lk->serio->write (lk->serio, LK_CMD_DISABLE_CTRCLICK); } else { - DBG ("%s: Activating key clicks\n", __FUNCTION__); + DBG ("%s: Activating key clicks\n", __func__); lk->serio->write (lk->serio, LK_CMD_ENABLE_KEYCLICK); lk->serio->write (lk->serio, volume_to_hw (lk->keyclick_volume)); lk->serio->write (lk->serio, LK_CMD_ENABLE_CTRCLICK); @@ -560,7 +560,7 @@ lkkbd_event (struct input_dev *dev, unsigned int type, unsigned int code, default: printk (KERN_ERR "%s (): Got unknown type %d, code %d, value %d\n", - __FUNCTION__, type, code, value); + __func__, type, code, value); } return -1; diff --git a/drivers/input/misc/ati_remote.c b/drivers/input/misc/ati_remote.c index f3b86c2b079..debfc1af9d9 100644 --- a/drivers/input/misc/ati_remote.c +++ b/drivers/input/misc/ati_remote.c @@ -330,7 +330,7 @@ static int ati_remote_open(struct input_dev *inputdev) ati_remote->irq_urb->dev = ati_remote->udev; if (usb_submit_urb(ati_remote->irq_urb, GFP_KERNEL)) { dev_err(&ati_remote->interface->dev, - "%s: usb_submit_urb failed!\n", __FUNCTION__); + "%s: usb_submit_urb failed!\n", __func__); return -EIO; } @@ -356,7 +356,7 @@ static void ati_remote_irq_out(struct urb *urb) if (urb->status) { dev_dbg(&ati_remote->interface->dev, "%s: status %d\n", - __FUNCTION__, urb->status); + __func__, urb->status); return; } @@ -601,17 +601,17 @@ static void ati_remote_irq_in(struct urb *urb) case -ENOENT: case -ESHUTDOWN: dev_dbg(&ati_remote->interface->dev, "%s: urb error status, unlink? \n", - __FUNCTION__); + __func__); return; default: /* error */ dev_dbg(&ati_remote->interface->dev, "%s: Nonzero urb status %d\n", - __FUNCTION__, urb->status); + __func__, urb->status); } retval = usb_submit_urb(urb, GFP_ATOMIC); if (retval) dev_err(&ati_remote->interface->dev, "%s: usb_submit_urb()=%d\n", - __FUNCTION__, retval); + __func__, retval); } /* @@ -734,7 +734,7 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de int err = -ENOMEM; if (iface_host->desc.bNumEndpoints != 2) { - err("%s: Unexpected desc.bNumEndpoints\n", __FUNCTION__); + err("%s: Unexpected desc.bNumEndpoints\n", __func__); return -ENODEV; } @@ -742,11 +742,11 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de endpoint_out = &iface_host->endpoint[1].desc; if (!usb_endpoint_is_int_in(endpoint_in)) { - err("%s: Unexpected endpoint_in\n", __FUNCTION__); + err("%s: Unexpected endpoint_in\n", __func__); return -ENODEV; } if (le16_to_cpu(endpoint_in->wMaxPacketSize) == 0) { - err("%s: endpoint_in message size==0? \n", __FUNCTION__); + err("%s: endpoint_in message size==0? \n", __func__); return -ENODEV; } @@ -814,7 +814,7 @@ static void ati_remote_disconnect(struct usb_interface *interface) ati_remote = usb_get_intfdata(interface); usb_set_intfdata(interface, NULL); if (!ati_remote) { - warn("%s - null device?\n", __FUNCTION__); + warn("%s - null device?\n", __func__); return; } diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c index f2709b82485..a7fabafbd94 100644 --- a/drivers/input/misc/ati_remote2.c +++ b/drivers/input/misc/ati_remote2.c @@ -137,14 +137,14 @@ static int ati_remote2_open(struct input_dev *idev) r = usb_submit_urb(ar2->urb[0], GFP_KERNEL); if (r) { dev_err(&ar2->intf[0]->dev, - "%s: usb_submit_urb() = %d\n", __FUNCTION__, r); + "%s: usb_submit_urb() = %d\n", __func__, r); return r; } r = usb_submit_urb(ar2->urb[1], GFP_KERNEL); if (r) { usb_kill_urb(ar2->urb[0]); dev_err(&ar2->intf[1]->dev, - "%s: usb_submit_urb() = %d\n", __FUNCTION__, r); + "%s: usb_submit_urb() = %d\n", __func__, r); return r; } @@ -294,17 +294,17 @@ static void ati_remote2_complete_mouse(struct urb *urb) case -ECONNRESET: case -ESHUTDOWN: dev_dbg(&ar2->intf[0]->dev, - "%s(): urb status = %d\n", __FUNCTION__, urb->status); + "%s(): urb status = %d\n", __func__, urb->status); return; default: dev_err(&ar2->intf[0]->dev, - "%s(): urb status = %d\n", __FUNCTION__, urb->status); + "%s(): urb status = %d\n", __func__, urb->status); } r = usb_submit_urb(urb, GFP_ATOMIC); if (r) dev_err(&ar2->intf[0]->dev, - "%s(): usb_submit_urb() = %d\n", __FUNCTION__, r); + "%s(): usb_submit_urb() = %d\n", __func__, r); } static void ati_remote2_complete_key(struct urb *urb) @@ -321,17 +321,17 @@ static void ati_remote2_complete_key(struct urb *urb) case -ECONNRESET: case -ESHUTDOWN: dev_dbg(&ar2->intf[1]->dev, - "%s(): urb status = %d\n", __FUNCTION__, urb->status); + "%s(): urb status = %d\n", __func__, urb->status); return; default: dev_err(&ar2->intf[1]->dev, - "%s(): urb status = %d\n", __FUNCTION__, urb->status); + "%s(): urb status = %d\n", __func__, urb->status); } r = usb_submit_urb(urb, GFP_ATOMIC); if (r) dev_err(&ar2->intf[1]->dev, - "%s(): usb_submit_urb() = %d\n", __FUNCTION__, r); + "%s(): usb_submit_urb() = %d\n", __func__, r); } static int ati_remote2_input_init(struct ati_remote2 *ar2) @@ -438,7 +438,7 @@ static int ati_remote2_setup(struct ati_remote2 *ar2) channel, 0x0, NULL, 0, USB_CTRL_SET_TIMEOUT); if (r) { dev_err(&ar2->udev->dev, "%s - failed to set channel due to error: %d\n", - __FUNCTION__, r); + __func__, r); return r; } diff --git a/drivers/input/misc/keyspan_remote.c b/drivers/input/misc/keyspan_remote.c index 952938a8e99..86afdd1fdf9 100644 --- a/drivers/input/misc/keyspan_remote.c +++ b/drivers/input/misc/keyspan_remote.c @@ -159,7 +159,7 @@ static int keyspan_load_tester(struct usb_keyspan* dev, int bits_needed) if (dev->data.pos >= dev->data.len) { dev_dbg(&dev->udev->dev, "%s - Error ran out of data. pos: %d, len: %d\n", - __FUNCTION__, dev->data.pos, dev->data.len); + __func__, dev->data.pos, dev->data.len); return -1; } @@ -267,7 +267,7 @@ static void keyspan_check_data(struct usb_keyspan *remote) remote->data.tester = remote->data.tester >> 6; remote->data.bits_left -= 6; } else { - err("%s - Unknown sequence found in system data.\n", __FUNCTION__); + err("%s - Unknown sequence found in system data.\n", __func__); remote->stage = 0; return; } @@ -286,7 +286,7 @@ static void keyspan_check_data(struct usb_keyspan *remote) remote->data.tester = remote->data.tester >> 6; remote->data.bits_left -= 6; } else { - err("%s - Unknown sequence found in button data.\n", __FUNCTION__); + err("%s - Unknown sequence found in button data.\n", __func__); remote->stage = 0; return; } @@ -302,7 +302,7 @@ static void keyspan_check_data(struct usb_keyspan *remote) remote->data.tester = remote->data.tester >> 6; remote->data.bits_left -= 6; } else { - err("%s - Error in message, invalid toggle.\n", __FUNCTION__); + err("%s - Error in message, invalid toggle.\n", __func__); remote->stage = 0; return; } @@ -317,7 +317,7 @@ static void keyspan_check_data(struct usb_keyspan *remote) dev_dbg(&remote->udev->dev, "%s found valid message: system: %d, button: %d, toggle: %d\n", - __FUNCTION__, message.system, message.button, message.toggle); + __func__, message.system, message.button, message.toggle); if (message.toggle != remote->toggle) { keyspan_report_button(remote, message.button, 1); @@ -341,7 +341,7 @@ static int keyspan_setup(struct usb_device* dev) 0x11, 0x40, 0x5601, 0x0, NULL, 0, 0); if (retval) { dev_dbg(&dev->dev, "%s - failed to set bit rate due to error: %d\n", - __FUNCTION__, retval); + __func__, retval); return(retval); } @@ -349,7 +349,7 @@ static int keyspan_setup(struct usb_device* dev) 0x44, 0x40, 0x0, 0x0, NULL, 0, 0); if (retval) { dev_dbg(&dev->dev, "%s - failed to set resume sensitivity due to error: %d\n", - __FUNCTION__, retval); + __func__, retval); return(retval); } @@ -357,11 +357,11 @@ static int keyspan_setup(struct usb_device* dev) 0x22, 0x40, 0x0, 0x0, NULL, 0, 0); if (retval) { dev_dbg(&dev->dev, "%s - failed to turn receive on due to error: %d\n", - __FUNCTION__, retval); + __func__, retval); return(retval); } - dev_dbg(&dev->dev, "%s - Setup complete.\n", __FUNCTION__); + dev_dbg(&dev->dev, "%s - Setup complete.\n", __func__); return(retval); } @@ -397,7 +397,7 @@ static void keyspan_irq_recv(struct urb *urb) resubmit: retval = usb_submit_urb(urb, GFP_ATOMIC); if (retval) - err ("%s - usb_submit_urb failed with result: %d", __FUNCTION__, retval); + err ("%s - usb_submit_urb failed with result: %d", __func__, retval); } static int keyspan_open(struct input_dev *dev) diff --git a/drivers/input/misc/powermate.c b/drivers/input/misc/powermate.c index 7a7b8c7b963..a53c4885fba 100644 --- a/drivers/input/misc/powermate.c +++ b/drivers/input/misc/powermate.c @@ -96,10 +96,10 @@ static void powermate_irq(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); + dbg("%s - urb shutting down with status: %d", __func__, urb->status); return; default: - dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); + dbg("%s - nonzero urb status received: %d", __func__, urb->status); goto exit; } @@ -112,7 +112,7 @@ exit: retval = usb_submit_urb (urb, GFP_ATOMIC); if (retval) err ("%s - usb_submit_urb failed with result %d", - __FUNCTION__, retval); + __func__, retval); } /* Decide if we need to issue a control message and do so. Must be called with pm->lock taken */ diff --git a/drivers/input/misc/yealink.c b/drivers/input/misc/yealink.c index 46279ef2b64..8a949e7d8f4 100644 --- a/drivers/input/misc/yealink.c +++ b/drivers/input/misc/yealink.c @@ -427,7 +427,7 @@ static void urb_irq_callback(struct urb *urb) int ret; if (urb->status) - err("%s - urb status %d", __FUNCTION__, urb->status); + err("%s - urb status %d", __func__, urb->status); switch (yld->irq_data->cmd) { case CMD_KEYPRESS: @@ -449,7 +449,7 @@ static void urb_irq_callback(struct urb *urb) ret = usb_submit_urb(yld->urb_ctl, GFP_ATOMIC); if (ret) - err("%s - usb_submit_urb failed %d", __FUNCTION__, ret); + err("%s - usb_submit_urb failed %d", __func__, ret); } static void urb_ctl_callback(struct urb *urb) @@ -458,7 +458,7 @@ static void urb_ctl_callback(struct urb *urb) int ret; if (urb->status) - err("%s - urb status %d", __FUNCTION__, urb->status); + err("%s - urb status %d", __func__, urb->status); switch (yld->ctl_data->cmd) { case CMD_KEYPRESS: @@ -473,7 +473,7 @@ static void urb_ctl_callback(struct urb *urb) } if (ret) - err("%s - usb_submit_urb failed %d", __FUNCTION__, ret); + err("%s - usb_submit_urb failed %d", __func__, ret); } /******************************************************************************* @@ -505,7 +505,7 @@ static int input_open(struct input_dev *dev) struct yealink_dev *yld = input_get_drvdata(dev); int i, ret; - dbg("%s", __FUNCTION__); + dbg("%s", __func__); /* force updates to device */ for (i = 0; imaster); i++) @@ -521,7 +521,7 @@ static int input_open(struct input_dev *dev) yld->ctl_data->sum = 0x100-CMD_INIT-10; if ((ret = usb_submit_urb(yld->urb_ctl, GFP_KERNEL)) != 0) { dbg("%s - usb_submit_urb failed with result %d", - __FUNCTION__, ret); + __func__, ret); return ret; } return 0; diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c index 8dd3942f302..32c29400f87 100644 --- a/drivers/input/mouse/appletouch.c +++ b/drivers/input/mouse/appletouch.c @@ -287,7 +287,7 @@ static void atp_reinit(struct work_struct *work) retval = usb_submit_urb(dev->urb, GFP_ATOMIC); if (retval) { err("%s - usb_submit_urb failed with result %d", - __FUNCTION__, retval); + __func__, retval); } } @@ -379,11 +379,11 @@ static void atp_complete(struct urb* urb) case -ESHUTDOWN: /* This urb is terminated, clean up */ dbg("%s - urb shutting down with status: %d", - __FUNCTION__, urb->status); + __func__, urb->status); return; default: dbg("%s - nonzero urb status received: %d", - __FUNCTION__, urb->status); + __func__, urb->status); goto exit; } @@ -565,7 +565,7 @@ exit: retval = usb_submit_urb(dev->urb, GFP_ATOMIC); if (retval) { err("%s - usb_submit_urb failed with result %d", - __FUNCTION__, retval); + __func__, retval); } } diff --git a/drivers/input/tablet/acecad.c b/drivers/input/tablet/acecad.c index b973d0ef6d1..570e0e83ac4 100644 --- a/drivers/input/tablet/acecad.c +++ b/drivers/input/tablet/acecad.c @@ -73,10 +73,10 @@ static void usb_acecad_irq(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); + dbg("%s - urb shutting down with status: %d", __func__, urb->status); return; default: - dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); + dbg("%s - nonzero urb status received: %d", __func__, urb->status); goto resubmit; } diff --git a/drivers/input/tablet/aiptek.c b/drivers/input/tablet/aiptek.c index 55c1134d613..8f037a1d44a 100644 --- a/drivers/input/tablet/aiptek.c +++ b/drivers/input/tablet/aiptek.c @@ -449,12 +449,12 @@ static void aiptek_irq(struct urb *urb) case -ESHUTDOWN: /* This urb is terminated, clean up */ dbg("%s - urb shutting down with status: %d", - __FUNCTION__, urb->status); + __func__, urb->status); return; default: dbg("%s - nonzero urb status received: %d", - __FUNCTION__, urb->status); + __func__, urb->status); goto exit; } @@ -813,7 +813,7 @@ exit: retval = usb_submit_urb(urb, GFP_ATOMIC); if (retval != 0) { err("%s - usb_submit_urb failed with result %d", - __FUNCTION__, retval); + __func__, retval); } } diff --git a/drivers/input/tablet/kbtab.c b/drivers/input/tablet/kbtab.c index f23f5a97fb3..d89112fa6e6 100644 --- a/drivers/input/tablet/kbtab.c +++ b/drivers/input/tablet/kbtab.c @@ -56,10 +56,10 @@ static void kbtab_irq(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); + dbg("%s - urb shutting down with status: %d", __func__, urb->status); return; default: - dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); + dbg("%s - nonzero urb status received: %d", __func__, urb->status); goto exit; } @@ -88,7 +88,7 @@ static void kbtab_irq(struct urb *urb) retval = usb_submit_urb (urb, GFP_ATOMIC); if (retval) err ("%s - usb_submit_urb failed with result %d", - __FUNCTION__, retval); + __func__, retval); } static struct usb_device_id kbtab_ids[] = { diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c index 71cc0c14079..5fbc463baf5 100644 --- a/drivers/input/tablet/wacom_sys.c +++ b/drivers/input/tablet/wacom_sys.c @@ -56,10 +56,10 @@ static void wacom_sys_irq(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); + dbg("%s - urb shutting down with status: %d", __func__, urb->status); return; default: - dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); + dbg("%s - nonzero urb status received: %d", __func__, urb->status); goto exit; } @@ -74,7 +74,7 @@ static void wacom_sys_irq(struct urb *urb) retval = usb_submit_urb (urb, GFP_ATOMIC); if (retval) err ("%s - usb_submit_urb failed with result %d", - __FUNCTION__, retval); + __func__, retval); } void wacom_report_key(void *wcombo, unsigned int key_type, int key_data) diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c index 3a0a8ca5707..792b2708a13 100644 --- a/drivers/input/touchscreen/usbtouchscreen.c +++ b/drivers/input/touchscreen/usbtouchscreen.c @@ -262,7 +262,7 @@ static int mtouch_init(struct usbtouch_usb *usbtouch) USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 1, 0, NULL, 0, USB_CTRL_SET_TIMEOUT); dbg("%s - usb_control_msg - MTOUCHUSB_RESET - bytes|err: %d", - __FUNCTION__, ret); + __func__, ret); if (ret < 0) return ret; msleep(150); @@ -273,7 +273,7 @@ static int mtouch_init(struct usbtouch_usb *usbtouch) USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 1, 1, NULL, 0, USB_CTRL_SET_TIMEOUT); dbg("%s - usb_control_msg - MTOUCHUSB_ASYNC_REPORT - bytes|err: %d", - __FUNCTION__, ret); + __func__, ret); if (ret >= 0) break; if (ret != -EPIPE) @@ -793,18 +793,18 @@ static void usbtouch_irq(struct urb *urb) case -ETIME: /* this urb is timing out */ dbg("%s - urb timed out - was the device unplugged?", - __FUNCTION__); + __func__); return; case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ dbg("%s - urb shutting down with status: %d", - __FUNCTION__, urb->status); + __func__, urb->status); return; default: dbg("%s - nonzero urb status received: %d", - __FUNCTION__, urb->status); + __func__, urb->status); goto exit; } @@ -814,7 +814,7 @@ exit: retval = usb_submit_urb(urb, GFP_ATOMIC); if (retval) err("%s - usb_submit_urb failed with result: %d", - __FUNCTION__, retval); + __func__, retval); } static int usbtouch_open(struct input_dev *input) @@ -883,7 +883,7 @@ static int usbtouch_probe(struct usb_interface *intf, usbtouch->irq = usb_alloc_urb(0, GFP_KERNEL); if (!usbtouch->irq) { - dbg("%s - usb_alloc_urb failed: usbtouch->irq", __FUNCTION__); + dbg("%s - usb_alloc_urb failed: usbtouch->irq", __func__); goto out_free_buffers; } @@ -939,14 +939,14 @@ static int usbtouch_probe(struct usb_interface *intf, if (type->init) { err = type->init(usbtouch); if (err) { - dbg("%s - type->init() failed, err: %d", __FUNCTION__, err); + dbg("%s - type->init() failed, err: %d", __func__, err); goto out_free_buffers; } } err = input_register_device(usbtouch->input); if (err) { - dbg("%s - input_register_device failed, err: %d", __FUNCTION__, err); + dbg("%s - input_register_device failed, err: %d", __func__, err); goto out_free_buffers; } @@ -966,12 +966,12 @@ static void usbtouch_disconnect(struct usb_interface *intf) { struct usbtouch_usb *usbtouch = usb_get_intfdata(intf); - dbg("%s - called", __FUNCTION__); + dbg("%s - called", __func__); if (!usbtouch) return; - dbg("%s - usbtouch is initialized, cleaning up", __FUNCTION__); + dbg("%s - usbtouch is initialized, cleaning up", __func__); usb_set_intfdata(intf, NULL); usb_kill_urb(usbtouch->irq); input_unregister_device(usbtouch->input); -- cgit v1.2.3-70-g09d2 From e34b9d2f46590e3be64466b4095118283745d050 Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Mon, 5 May 2008 11:36:41 -0400 Subject: Input: wacom - cleanup handling of tablet IDs Signed-off-by: Ping Cheng Signed-off-by: Dmitry Torokhov --- drivers/input/tablet/wacom_wac.c | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index 192513e1f04..bf3d9a8b2c1 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -56,7 +56,7 @@ static int wacom_penpartner_irq(struct wacom_wac *wacom, void *wcombo) static int wacom_pl_irq(struct wacom_wac *wacom, void *wcombo) { unsigned char *data = wacom->data; - int prox, id, pressure; + int prox, pressure; if (data[0] != 2) { dbg("wacom_pl_irq: received unknown report #%d", data[0]); @@ -65,7 +65,7 @@ static int wacom_pl_irq(struct wacom_wac *wacom, void *wcombo) prox = data[1] & 0x40; - id = ERASER_DEVICE_ID; + wacom->id[0] = ERASER_DEVICE_ID; if (prox) { pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1)); @@ -99,10 +99,10 @@ static int wacom_pl_irq(struct wacom_wac *wacom, void *wcombo) if (wacom->tool[1] != BTN_TOOL_RUBBER) { /* Unknown tool selected default to pen tool */ wacom->tool[1] = BTN_TOOL_PEN; - id = STYLUS_DEVICE_ID; + wacom->id[0] = STYLUS_DEVICE_ID; } wacom_report_key(wcombo, wacom->tool[1], prox); /* report in proximity for tool */ - wacom_report_abs(wcombo, ABS_MISC, id); /* report tool id */ + wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]); /* report tool id */ wacom_report_abs(wcombo, ABS_X, data[3] | (data[2] << 7) | ((data[1] & 0x03) << 14)); wacom_report_abs(wcombo, ABS_Y, data[6] | (data[5] << 7) | ((data[4] & 0x03) << 14)); wacom_report_abs(wcombo, ABS_PRESSURE, pressure); @@ -127,7 +127,6 @@ static int wacom_pl_irq(struct wacom_wac *wacom, void *wcombo) static int wacom_ptu_irq(struct wacom_wac *wacom, void *wcombo) { unsigned char *data = wacom->data; - int id; if (data[0] != 2) { printk(KERN_INFO "wacom_ptu_irq: received unknown report #%d\n", data[0]); @@ -137,13 +136,13 @@ static int wacom_ptu_irq(struct wacom_wac *wacom, void *wcombo) if (data[1] & 0x04) { wacom_report_key(wcombo, BTN_TOOL_RUBBER, data[1] & 0x20); wacom_report_key(wcombo, BTN_TOUCH, data[1] & 0x08); - id = ERASER_DEVICE_ID; + wacom->id[0] = ERASER_DEVICE_ID; } else { wacom_report_key(wcombo, BTN_TOOL_PEN, data[1] & 0x20); wacom_report_key(wcombo, BTN_TOUCH, data[1] & 0x01); - id = STYLUS_DEVICE_ID; + wacom->id[0] = STYLUS_DEVICE_ID; } - wacom_report_abs(wcombo, ABS_MISC, id); /* report tool id */ + wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]); /* report tool id */ wacom_report_abs(wcombo, ABS_X, wacom_le16_to_cpu(&data[2])); wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[4])); wacom_report_abs(wcombo, ABS_PRESSURE, wacom_le16_to_cpu(&data[6])); @@ -155,27 +154,26 @@ static int wacom_ptu_irq(struct wacom_wac *wacom, void *wcombo) static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo) { unsigned char *data = wacom->data; - int x, y, id, rw; + int x, y, rw; if (data[0] != 2) { dbg("wacom_graphire_irq: received unknown report #%d", data[0]); return 0; } - id = STYLUS_DEVICE_ID; - if ((data[1] & 0x80) && ((data[1] & 0x07) || data[2] || data[3] || data[4] - || data[5] || data[6] || (data[7] & 0x07))) { + if (data[1] & 0x80) { /* in prox and not a pad data */ switch ((data[1] >> 5) & 3) { case 0: /* Pen */ wacom->tool[0] = BTN_TOOL_PEN; + wacom->id[0] = STYLUS_DEVICE_ID; break; case 1: /* Rubber */ wacom->tool[0] = BTN_TOOL_RUBBER; - id = ERASER_DEVICE_ID; + wacom->id[0] = ERASER_DEVICE_ID; break; case 2: /* Mouse with wheel */ @@ -190,7 +188,7 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo) case 3: /* Mouse without wheel */ wacom->tool[0] = BTN_TOOL_MOUSE; - id = CURSOR_DEVICE_ID; + wacom->id[0] = CURSOR_DEVICE_ID; wacom_report_key(wcombo, BTN_LEFT, data[1] & 0x01); wacom_report_key(wcombo, BTN_RIGHT, data[1] & 0x02); if (wacom->features->type == WACOM_G4 || @@ -210,9 +208,9 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo) wacom_report_key(wcombo, BTN_STYLUS, data[1] & 0x02); wacom_report_key(wcombo, BTN_STYLUS2, data[1] & 0x04); } - wacom_report_abs(wcombo, ABS_MISC, id); /* report tool id */ + wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]); /* report tool id */ wacom_report_key(wcombo, wacom->tool[0], 1); - } else if (!(data[1] & 0x90)) { + } else if (wacom->id[0]) { wacom_report_abs(wcombo, ABS_X, 0); wacom_report_abs(wcombo, ABS_Y, 0); if (wacom->tool[0] == BTN_TOOL_MOUSE) { @@ -225,6 +223,7 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo) wacom_report_key(wcombo, BTN_STYLUS, 0); wacom_report_key(wcombo, BTN_STYLUS2, 0); } + wacom->id[0] = 0; wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */ wacom_report_key(wcombo, wacom->tool[0], 0); } @@ -234,13 +233,13 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo) case WACOM_G4: if (data[7] & 0xf8) { wacom_input_sync(wcombo); /* sync last event */ - wacom->id[1] = 1; + wacom->id[1] = PAD_DEVICE_ID; wacom_report_key(wcombo, BTN_0, (data[7] & 0x40)); wacom_report_key(wcombo, BTN_4, (data[7] & 0x80)); rw = ((data[7] & 0x18) >> 3) - ((data[7] & 0x20) >> 3); wacom_report_rel(wcombo, REL_WHEEL, rw); wacom_report_key(wcombo, BTN_TOOL_FINGER, 0xf0); - wacom_report_abs(wcombo, ABS_MISC, PAD_DEVICE_ID); + wacom_report_abs(wcombo, ABS_MISC, wacom->id[1]); wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0); } else if (wacom->id[1]) { wacom_input_sync(wcombo); /* sync last event */ @@ -255,14 +254,14 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo) case WACOM_MO: if ((data[7] & 0xf8) || (data[8] & 0xff)) { wacom_input_sync(wcombo); /* sync last event */ - wacom->id[1] = 1; + wacom->id[1] = PAD_DEVICE_ID; wacom_report_key(wcombo, BTN_0, (data[7] & 0x08)); wacom_report_key(wcombo, BTN_1, (data[7] & 0x20)); wacom_report_key(wcombo, BTN_4, (data[7] & 0x10)); wacom_report_key(wcombo, BTN_5, (data[7] & 0x40)); wacom_report_abs(wcombo, ABS_WHEEL, (data[8] & 0x7f)); wacom_report_key(wcombo, BTN_TOOL_FINGER, 0xf0); - wacom_report_abs(wcombo, ABS_MISC, PAD_DEVICE_ID); + wacom_report_abs(wcombo, ABS_MISC, wacom->id[1]); wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0); } else if (wacom->id[1]) { wacom_input_sync(wcombo); /* sync last event */ -- cgit v1.2.3-70-g09d2 From c6a3ead2ab5d82b549237c52a785b9f736e13463 Mon Sep 17 00:00:00 2001 From: Harvey Harrison Date: Mon, 5 May 2008 11:50:40 -0400 Subject: Input: wacom - make one-bit signed bitfields unsigned Otherwise it can only take the values 0/-1 which doesn't seem to have been intended. drivers/input/tablet/wacom.h:108:12: error: dubious one-bit signed bitfield Signed-off-by: Harvey Harrison Signed-off-by: Andrew Morton Signed-off-by: Dmitry Torokhov --- drivers/input/tablet/wacom.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/tablet/wacom.h b/drivers/input/tablet/wacom.h index 706619d06f7..ca62ec639f8 100644 --- a/drivers/input/tablet/wacom.h +++ b/drivers/input/tablet/wacom.h @@ -105,7 +105,7 @@ struct wacom { struct urb *irq; struct wacom_wac * wacom_wac; struct mutex lock; - int open:1; + unsigned int open:1; char phys[32]; }; -- cgit v1.2.3-70-g09d2 From 923104747d5c4d58762aa865f71d48d3beb73ae6 Mon Sep 17 00:00:00 2001 From: Harvey Harrison Date: Mon, 5 May 2008 11:50:59 -0400 Subject: Input: use clamp_val() macro in ff-memless.c Replace two opencoded nested min/max macros with clamp_val(). Signed-off-by: Harvey Harrison Signed-off-by: Andrew Morton Signed-off-by: Dmitry Torokhov --- drivers/input/ff-memless.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/ff-memless.c b/drivers/input/ff-memless.c index d226d935b0d..6790e975a98 100644 --- a/drivers/input/ff-memless.c +++ b/drivers/input/ff-memless.c @@ -247,9 +247,9 @@ static void ml_combine_effects(struct ff_effect *effect, * in s8, this should be changed to something more generic */ effect->u.ramp.start_level = - max(min(effect->u.ramp.start_level + x, 0x7f), -0x80); + clamp_val(effect->u.ramp.start_level + x, -0x80, 0x7f); effect->u.ramp.end_level = - max(min(effect->u.ramp.end_level + y, 0x7f), -0x80); + clamp_val(effect->u.ramp.end_level + y, -0x80, 0x7f); break; case FF_RUMBLE: -- cgit v1.2.3-70-g09d2 From d2fc60d6925574eeeadd037aa0f1378e07189a1a Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 5 May 2008 11:53:45 -0400 Subject: HWMON: hdaps - set up phys and bus type of input device Signed-off-by: Dmitry Torokhov --- drivers/hwmon/hdaps.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c index bab5fd2e4df..ea4fc657759 100644 --- a/drivers/hwmon/hdaps.c +++ b/drivers/hwmon/hdaps.c @@ -573,6 +573,8 @@ static int __init hdaps_init(void) /* initialize the input class */ idev = hdaps_idev->input; idev->name = "hdaps"; + idev->phys = "isa1600/input0"; + idev->id.bustype = BUS_ISA; idev->dev.parent = &pdev->dev; idev->evbit[0] = BIT_MASK(EV_ABS); input_set_abs_params(idev, ABS_X, -- cgit v1.2.3-70-g09d2 From 2e75f044c717b85f65d74c8c90624428ba31078c Mon Sep 17 00:00:00 2001 From: Rodney Lorrimar Date: Mon, 5 May 2008 11:59:00 -0400 Subject: Input: adbhid - fix capslock key state after suspend If the adbhid module parameter restore_capslock_events is used, sometimes capslock will get stuck down after resuming. My fix is to remember the capslock state before suspend and then ignore the first 'caps lock key down' message after resume if the capslock LED was on before suspending. Signed-off-by: Rodney Lorrimar Signed-off-by: Dmitry Torokhov --- drivers/macintosh/adbhid.c | 46 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c index ef4c117ea35..6e9afe26db8 100644 --- a/drivers/macintosh/adbhid.c +++ b/drivers/macintosh/adbhid.c @@ -219,11 +219,12 @@ struct adbhid { int flags; }; -#define FLAG_FN_KEY_PRESSED 0x00000001 -#define FLAG_POWER_FROM_FN 0x00000002 -#define FLAG_EMU_FWDEL_DOWN 0x00000004 -#define FLAG_CAPSLOCK_TRANSLATE 0x00000008 -#define FLAG_CAPSLOCK_DOWN 0x00000010 +#define FLAG_FN_KEY_PRESSED 0x00000001 +#define FLAG_POWER_FROM_FN 0x00000002 +#define FLAG_EMU_FWDEL_DOWN 0x00000004 +#define FLAG_CAPSLOCK_TRANSLATE 0x00000008 +#define FLAG_CAPSLOCK_DOWN 0x00000010 +#define FLAG_CAPSLOCK_IGNORE_NEXT 0x00000020 static struct adbhid *adbhid[16]; @@ -291,8 +292,15 @@ adbhid_input_keycode(int id, int scancode, int repeat) if (keycode == ADB_KEY_CAPSLOCK && !up_flag) { /* Key pressed, turning on the CapsLock LED. * The next 0xff will be interpreted as a release. */ - ahid->flags |= FLAG_CAPSLOCK_TRANSLATE + if (ahid->flags & FLAG_CAPSLOCK_IGNORE_NEXT) { + /* Throw away this key event if it happens + * just after resume. */ + ahid->flags &= ~FLAG_CAPSLOCK_IGNORE_NEXT; + return; + } else { + ahid->flags |= FLAG_CAPSLOCK_TRANSLATE | FLAG_CAPSLOCK_DOWN; + } } else if (scancode == 0xff) { /* Scancode 0xff usually signifies that the capslock * key was either pressed or released. */ @@ -681,6 +689,21 @@ static int adbhid_kbd_event(struct input_dev *dev, unsigned int type, unsigned i return -1; } +static void +adbhid_kbd_capslock_remember(void) +{ + struct adbhid *ahid; + int i; + + for (i = 1; i < 16; i++) { + ahid = adbhid[i]; + + if (ahid && ahid->id == ADB_KEYBOARD) + if (ahid->flags & FLAG_CAPSLOCK_TRANSLATE) + ahid->flags |= FLAG_CAPSLOCK_IGNORE_NEXT; + } +} + static int adb_message_handler(struct notifier_block *this, unsigned long code, void *x) { @@ -697,8 +720,17 @@ adb_message_handler(struct notifier_block *this, unsigned long code, void *x) } /* Stop pending led requests */ - while(leds_req_pending) + while (leds_req_pending) adb_poll(); + + /* After resume, and if the capslock LED is on, the PMU will + * send a "capslock down" key event. This confuses the + * restore_capslock_events logic. Remember if the capslock + * LED was on before suspend so the unwanted key event can + * be ignored after resume. */ + if (restore_capslock_events) + adbhid_kbd_capslock_remember(); + break; case ADB_MSG_POST_RESET: -- cgit v1.2.3-70-g09d2 From 5b7c407baa9501e49ebd3b6eac30cd4bcb60ca9d Mon Sep 17 00:00:00 2001 From: Rodney Lorrimar Date: Mon, 5 May 2008 11:59:24 -0400 Subject: Input: adbhid - capslock and power button fix If the adbhid module parameter restore_capslock_events is used, pressing the power button may confuse the capslock state. This is because the power button release scancode (0xff) is sometimes the same as the capslock press/release scancode. This fix adds yet another flag to track the state of the power button so that it works independently of capslock. Signed-off-by: Rodney Lorrimar Signed-off-by: Dmitry Torokhov --- drivers/macintosh/adbhid.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c index 6e9afe26db8..b7f41d3823a 100644 --- a/drivers/macintosh/adbhid.c +++ b/drivers/macintosh/adbhid.c @@ -225,6 +225,7 @@ struct adbhid { #define FLAG_CAPSLOCK_TRANSLATE 0x00000008 #define FLAG_CAPSLOCK_DOWN 0x00000010 #define FLAG_CAPSLOCK_IGNORE_NEXT 0x00000020 +#define FLAG_POWER_KEY_PRESSED 0x00000040 static struct adbhid *adbhid[16]; @@ -301,9 +302,11 @@ adbhid_input_keycode(int id, int scancode, int repeat) ahid->flags |= FLAG_CAPSLOCK_TRANSLATE | FLAG_CAPSLOCK_DOWN; } - } else if (scancode == 0xff) { + } else if (scancode == 0xff && + !(ahid->flags & FLAG_POWER_KEY_PRESSED)) { /* Scancode 0xff usually signifies that the capslock - * key was either pressed or released. */ + * key was either pressed or released, or that the + * power button was released. */ if (ahid->flags & FLAG_CAPSLOCK_TRANSLATE) { keycode = ADB_KEY_CAPSLOCK; if (ahid->flags & FLAG_CAPSLOCK_DOWN) { @@ -317,7 +320,7 @@ adbhid_input_keycode(int id, int scancode, int repeat) } } else { printk(KERN_INFO "Spurious caps lock event " - "(scancode 0xff)."); + "(scancode 0xff).\n"); } } } @@ -344,6 +347,12 @@ adbhid_input_keycode(int id, int scancode, int repeat) } break; case ADB_KEY_POWER: + /* Keep track of the power key state */ + if (up_flag) + ahid->flags &= ~FLAG_POWER_KEY_PRESSED; + else + ahid->flags |= FLAG_POWER_KEY_PRESSED; + /* Fn + Command will produce a bogus "power" keycode */ if (ahid->flags & FLAG_FN_KEY_PRESSED) { keycode = ADB_KEY_CMD; -- cgit v1.2.3-70-g09d2 From 7dce869f120cd7500e83850a6036dfeffcf77c57 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 5 May 2008 23:56:55 -0400 Subject: Input: appletouch - miscellaneous code cleanups This patch does some code cleanups in appletouch: * useless comment removal * make almost checkpatch clean * make sparse clean Signed-off-by: Sven Anders [jberg: most of the changes including removing much of the original patch] Signed-off-by: Johannes Berg Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/appletouch.c | 173 ++++++++++++++++++++++----------------- 1 file changed, 100 insertions(+), 73 deletions(-) (limited to 'drivers') diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c index 32c29400f87..814e90459b3 100644 --- a/drivers/input/mouse/appletouch.c +++ b/drivers/input/mouse/appletouch.c @@ -2,12 +2,13 @@ * Apple USB Touchpad (for post-February 2005 PowerBooks and MacBooks) driver * * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (C) 2005 Johannes Berg (johannes@sipsolutions.net) + * Copyright (C) 2005-2008 Johannes Berg (johannes@sipsolutions.net) * Copyright (C) 2005 Stelian Pop (stelian@popies.net) * Copyright (C) 2005 Frank Arnold (frank@scirocco-5v-turbo.de) * Copyright (C) 2005 Peter Osterlund (petero2@telia.com) * Copyright (C) 2005 Michael Hanselmann (linux-kernel@hansmi.ch) * Copyright (C) 2006 Nicolas Boichat (nicolas@boichat.ch) + * Copyright (C) 2007-2008 Sven Anders (anders@anduras.de) * * Thanks to Alex Harper for his inputs. * @@ -38,6 +39,8 @@ #define APPLE_VENDOR_ID 0x05AC /* These names come from Info.plist in AppleUSBTrackpad.kext */ + +/* PowerBooks Feb 2005 / iBooks */ #define FOUNTAIN_ANSI_PRODUCT_ID 0x020E #define FOUNTAIN_ISO_PRODUCT_ID 0x020F @@ -45,9 +48,10 @@ #define GEYSER1_TP_ONLY_PRODUCT_ID 0x030B -#define GEYSER_ANSI_PRODUCT_ID 0x0214 -#define GEYSER_ISO_PRODUCT_ID 0x0215 -#define GEYSER_JIS_PRODUCT_ID 0x0216 +/* PowerBooks Oct 2005 */ +#define GEYSER2_ANSI_PRODUCT_ID 0x0214 +#define GEYSER2_ISO_PRODUCT_ID 0x0215 +#define GEYSER2_JIS_PRODUCT_ID 0x0216 /* MacBook devices */ #define GEYSER3_ANSI_PRODUCT_ID 0x0217 @@ -55,13 +59,15 @@ #define GEYSER3_JIS_PRODUCT_ID 0x0219 /* - * Geyser IV: same as Geyser III according to Info.plist in AppleUSBTrackpad.kext + * Geyser IV: same as Geyser III according to Info.plist in OSX's + * AppleUSBTrackpad.kext * -> same IOClass (AppleUSBGrIIITrackpad), same acceleration tables */ -#define GEYSER4_ANSI_PRODUCT_ID 0x021A -#define GEYSER4_ISO_PRODUCT_ID 0x021B -#define GEYSER4_JIS_PRODUCT_ID 0x021C +#define GEYSER4_ANSI_PRODUCT_ID 0x021A +#define GEYSER4_ISO_PRODUCT_ID 0x021B +#define GEYSER4_JIS_PRODUCT_ID 0x021C +/* Macbook3,1 devices */ #define GEYSER4_HF_ANSI_PRODUCT_ID 0x0229 #define GEYSER4_HF_ISO_PRODUCT_ID 0x022A #define GEYSER4_HF_JIS_PRODUCT_ID 0x022B @@ -77,15 +83,16 @@ /* table of devices that work with this driver */ static struct usb_device_id atp_table [] = { + /* PowerBooks Feb 2005, iBooks G4 */ { ATP_DEVICE(FOUNTAIN_ANSI_PRODUCT_ID) }, { ATP_DEVICE(FOUNTAIN_ISO_PRODUCT_ID) }, { ATP_DEVICE(FOUNTAIN_TP_ONLY_PRODUCT_ID) }, { ATP_DEVICE(GEYSER1_TP_ONLY_PRODUCT_ID) }, /* PowerBooks Oct 2005 */ - { ATP_DEVICE(GEYSER_ANSI_PRODUCT_ID) }, - { ATP_DEVICE(GEYSER_ISO_PRODUCT_ID) }, - { ATP_DEVICE(GEYSER_JIS_PRODUCT_ID) }, + { ATP_DEVICE(GEYSER2_ANSI_PRODUCT_ID) }, + { ATP_DEVICE(GEYSER2_ISO_PRODUCT_ID) }, + { ATP_DEVICE(GEYSER2_JIS_PRODUCT_ID) }, /* Core Duo MacBook & MacBook Pro */ { ATP_DEVICE(GEYSER3_ANSI_PRODUCT_ID) }, @@ -97,6 +104,7 @@ static struct usb_device_id atp_table [] = { { ATP_DEVICE(GEYSER4_ISO_PRODUCT_ID) }, { ATP_DEVICE(GEYSER4_JIS_PRODUCT_ID) }, + /* Core2 Duo MacBook3,1 */ { ATP_DEVICE(GEYSER4_HF_ANSI_PRODUCT_ID) }, { ATP_DEVICE(GEYSER4_HF_ISO_PRODUCT_ID) }, { ATP_DEVICE(GEYSER4_HF_JIS_PRODUCT_ID) }, @@ -104,7 +112,7 @@ static struct usb_device_id atp_table [] = { /* Terminating entry */ { } }; -MODULE_DEVICE_TABLE (usb, atp_table); +MODULE_DEVICE_TABLE(usb, atp_table); /* * number of sensors. Note that only 16 instead of 26 X (horizontal) @@ -147,43 +155,45 @@ MODULE_DEVICE_TABLE (usb, atp_table); /* Structure to hold all of our device specific stuff */ struct atp { char phys[64]; - struct usb_device * udev; /* usb device */ - struct urb * urb; /* usb request block */ - signed char * data; /* transferred data */ - struct input_dev * input; /* input dev */ - unsigned char open; /* non-zero if opened */ - unsigned char valid; /* are the sensors valid ? */ - unsigned char size_detect_done; - unsigned char overflowwarn; /* overflow warning printed? */ + struct usb_device *udev; /* usb device */ + struct urb *urb; /* usb request block */ + signed char *data; /* transferred data */ + struct input_dev *input; /* input dev */ + bool open; + bool valid; /* are the samples valid? */ + bool size_detect_done; + bool overflow_warned; int x_old; /* last reported x/y, */ int y_old; /* used for smoothing */ - /* current value of the sensors */ signed char xy_cur[ATP_XSENSORS + ATP_YSENSORS]; - /* last value of the sensors */ signed char xy_old[ATP_XSENSORS + ATP_YSENSORS]; - /* accumulated sensors */ int xy_acc[ATP_XSENSORS + ATP_YSENSORS]; - int datalen; /* size of an USB urb transfer */ - int idlecount; /* number of empty packets */ - struct work_struct work; + int datalen; /* size of USB transfer */ + int idlecount; /* number of empty packets */ + struct work_struct work; }; #define dbg_dump(msg, tab) \ if (debug > 1) { \ - int i; \ - printk("appletouch: %s %lld", msg, (long long)jiffies); \ - for (i = 0; i < ATP_XSENSORS + ATP_YSENSORS; i++) \ - printk(" %02x", tab[i]); \ + int __i; \ + printk(KERN_DEBUG "appletouch: %s", msg); \ + for (__i = 0; __i < ATP_XSENSORS + ATP_YSENSORS; __i++) \ + printk(" %02x", tab[__i]); \ printk("\n"); \ } #define dprintk(format, a...) \ do { \ - if (debug) printk(KERN_DEBUG format, ##a); \ + if (debug) \ + printk(KERN_DEBUG format, ##a); \ } while (0) -MODULE_AUTHOR("Johannes Berg, Stelian Pop, Frank Arnold, Michael Hanselmann"); -MODULE_DESCRIPTION("Apple PowerBooks USB touchpad driver"); +MODULE_AUTHOR("Johannes Berg"); +MODULE_AUTHOR("Stelian Pop"); +MODULE_AUTHOR("Frank Arnold"); +MODULE_AUTHOR("Michael Hanselmann"); +MODULE_AUTHOR("Sven Anders"); +MODULE_DESCRIPTION("Apple PowerBook and MacBook USB touchpad driver"); MODULE_LICENSE("GPL"); /* @@ -191,9 +201,11 @@ MODULE_LICENSE("GPL"); */ static int threshold = ATP_THRESHOLD; module_param(threshold, int, 0644); -MODULE_PARM_DESC(threshold, "Discards any change in data from a sensor (trackpad has hundreds of these sensors) less than this value"); +MODULE_PARM_DESC(threshold, "Discard any change in data from a sensor" + " (the trackpad has many of these sensors)" + " less than this value."); -static int debug = 1; +static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Activate debugging output"); @@ -211,9 +223,9 @@ static inline int atp_is_geyser_2(struct atp *dev) { u16 productId = le16_to_cpu(dev->udev->descriptor.idProduct); - return (productId == GEYSER_ANSI_PRODUCT_ID) || - (productId == GEYSER_ISO_PRODUCT_ID) || - (productId == GEYSER_JIS_PRODUCT_ID); + return (productId == GEYSER2_ANSI_PRODUCT_ID) || + (productId == GEYSER2_ISO_PRODUCT_ID) || + (productId == GEYSER2_JIS_PRODUCT_ID); } static inline int atp_is_geyser_3(struct atp *dev) @@ -240,6 +252,7 @@ static int atp_geyser_init(struct usb_device *udev) { char data[8]; int size; + int i; size = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), ATP_GEYSER_MODE_READ_REQUEST_ID, @@ -248,8 +261,11 @@ static int atp_geyser_init(struct usb_device *udev) ATP_GEYSER_MODE_REQUEST_INDEX, &data, 8, 5000); if (size != 8) { - err("Could not do mode read request from device" - " (Geyser Raw mode)"); + dprintk("atp_geyser_init: read error\n"); + for (i = 0; i < 8; i++) + dprintk("appletouch[%d]: %d\n", i, data[i]); + + err("Failed to read mode from device."); return -EIO; } @@ -263,8 +279,11 @@ static int atp_geyser_init(struct usb_device *udev) ATP_GEYSER_MODE_REQUEST_INDEX, &data, 8, 5000); if (size != 8) { - err("Could not do mode write request to device" - " (Geyser Raw mode)"); + dprintk("atp_geyser_init: write error\n"); + for (i = 0; i < 8; i++) + dprintk("appletouch[%d]: %d\n", i, data[i]); + + err("Failed to request geyser raw mode"); return -EIO; } return 0; @@ -280,15 +299,15 @@ static void atp_reinit(struct work_struct *work) struct usb_device *udev = dev->udev; int retval; + dprintk("appletouch: putting appletouch to sleep (reinit)\n"); dev->idlecount = 0; atp_geyser_init(udev); retval = usb_submit_urb(dev->urb, GFP_ATOMIC); - if (retval) { - err("%s - usb_submit_urb failed with result %d", - __func__, retval); - } + if (retval) + err("atp_reinit: usb_submit_urb failed with error %d", + retval); } static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact, @@ -323,7 +342,8 @@ static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact, * * - Jason Parekh */ - if (i < 1 || (!is_increasing && xy_sensors[i - 1] < xy_sensors[i])) { + if (i < 1 || + (!is_increasing && xy_sensors[i - 1] < xy_sensors[i])) { (*fingers)++; is_increasing = 1; } else if (i > 0 && xy_sensors[i - 1] >= xy_sensors[i]) { @@ -331,11 +351,11 @@ static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact, } /* - * Subtracts threshold so a high sensor that just passes the threshold - * won't skew the calculated absolute coordinate. Fixes an issue - * where slowly moving the mouse would occassionaly jump a number of - * pixels (let me restate--slowly moving the mouse makes this issue - * most apparent). + * Subtracts threshold so a high sensor that just passes the + * threshold won't skew the calculated absolute coordinate. + * Fixes an issue where slowly moving the mouse would + * occasionally jump a number of pixels (slowly moving the + * finger makes this issue most apparent.) */ pcum += (xy_sensors[i] - threshold) * i; psum += (xy_sensors[i] - threshold); @@ -356,7 +376,7 @@ static inline void atp_report_fingers(struct input_dev *input, int fingers) input_report_key(input, BTN_TOOL_TRIPLETAP, fingers > 2); } -static void atp_complete(struct urb* urb) +static void atp_complete(struct urb *urb) { int x, y, x_z, y_z, x_f, y_f; int retval, i, j; @@ -368,22 +388,22 @@ static void atp_complete(struct urb* urb) /* success */ break; case -EOVERFLOW: - if(!dev->overflowwarn) { + if (!dev->overflow_warned) { printk(KERN_WARNING "appletouch: OVERFLOW with data " "length %d, actual length is %d\n", dev->datalen, dev->urb->actual_length); - dev->overflowwarn = 1; + dev->overflow_warned = true; } case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: /* This urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, urb->status); + dbg("atp_complete: urb shutting down with status: %d", + urb->status); return; default: - dbg("%s - nonzero urb status received: %d", - __func__, urb->status); + dbg("atp_complete: nonzero urb status received: %d", + urb->status); goto exit; } @@ -438,7 +458,7 @@ static void atp_complete(struct urb* urb) } else { for (i = 0; i < 8; i++) { /* X values */ - dev->xy_cur[i ] = dev->data[5 * i + 2]; + dev->xy_cur[i + 0] = dev->data[5 * i + 2]; dev->xy_cur[i + 8] = dev->data[5 * i + 4]; dev->xy_cur[i + 16] = dev->data[5 * i + 42]; if (i < 2) @@ -454,7 +474,7 @@ static void atp_complete(struct urb* urb) if (!dev->valid) { /* first sample */ - dev->valid = 1; + dev->valid = true; dev->x_old = dev->y_old = -1; memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old)); @@ -463,7 +483,8 @@ static void atp_complete(struct urb* urb) goto exit; /* 17" Powerbooks have extra X sensors */ - for (i = (atp_is_geyser_2(dev) ? 15 : 16); i < ATP_XSENSORS; i++) { + for (i = (atp_is_geyser_2(dev) ? 15 : 16); + i < ATP_XSENSORS; i++) { if (!dev->xy_cur[i]) continue; @@ -549,10 +570,14 @@ static void atp_complete(struct urb* urb) * work on Fountain touchpads. */ if (!atp_is_fountain(dev)) { + /* + * Button must not be pressed when entering suspend, + * otherwise we will never release the button. + */ if (!x && !y && !key) { dev->idlecount++; if (dev->idlecount == 10) { - dev->valid = 0; + dev->valid = false; schedule_work(&dev->work); /* Don't resubmit urb here, wait for reinit */ return; @@ -561,12 +586,11 @@ static void atp_complete(struct urb* urb) dev->idlecount = 0; } -exit: + exit: retval = usb_submit_urb(dev->urb, GFP_ATOMIC); - if (retval) { - err("%s - usb_submit_urb failed with result %d", - __func__, retval); - } + if (retval) + err("atp_complete: usb_submit_urb failed with result %d", + retval); } static int atp_open(struct input_dev *input) @@ -589,7 +613,8 @@ static void atp_close(struct input_dev *input) dev->open = 0; } -static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id) +static int atp_probe(struct usb_interface *iface, + const struct usb_device_id *id) { struct atp *dev; struct input_dev *input_dev; @@ -625,7 +650,7 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id dev->udev = udev; dev->input = input_dev; - dev->overflowwarn = 0; + dev->overflow_warned = false; if (atp_is_geyser_3(dev)) dev->datalen = 64; else if (atp_is_geyser_2(dev)) @@ -692,9 +717,11 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id * 17" models are detected later. */ input_set_abs_params(input_dev, ABS_X, 0, - (16 - 1) * ATP_XFACT - 1, ATP_FUZZ, 0); + (16 - 1) * ATP_XFACT - 1, + ATP_FUZZ, 0); input_set_abs_params(input_dev, ABS_Y, 0, - (ATP_YSENSORS - 1) * ATP_YFACT - 1, ATP_FUZZ, 0); + (ATP_YSENSORS - 1) * ATP_YFACT - 1, + ATP_FUZZ, 0); } input_set_abs_params(input_dev, ABS_PRESSURE, 0, ATP_PRESSURE, 0, 0); @@ -749,7 +776,7 @@ static int atp_suspend(struct usb_interface *iface, pm_message_t message) struct atp *dev = usb_get_intfdata(iface); usb_kill_urb(dev->urb); - dev->valid = 0; + dev->valid = false; return 0; } -- cgit v1.2.3-70-g09d2 From e9542dff390668f85dc8dca0ca019b27e4396f97 Mon Sep 17 00:00:00 2001 From: Sven Anders Date: Mon, 5 May 2008 23:57:10 -0400 Subject: Input: appletouch - simplify touchpad type detection This patch simplifies type detection and removes unnecessary code. Signed-off-by: Sven Anders [jberg: don't typedef, checkpatch clean, remove useless comments, ...] Signed-off-by: Johannes Berg Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/appletouch.c | 164 ++++++++++++++------------------------- 1 file changed, 57 insertions(+), 107 deletions(-) (limited to 'drivers') diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c index 814e90459b3..6867c914b02 100644 --- a/drivers/input/mouse/appletouch.c +++ b/drivers/input/mouse/appletouch.c @@ -35,79 +35,59 @@ #include #include -/* Apple has powerbooks which have the keyboard with different Product IDs */ -#define APPLE_VENDOR_ID 0x05AC - -/* These names come from Info.plist in AppleUSBTrackpad.kext */ - -/* PowerBooks Feb 2005 / iBooks */ -#define FOUNTAIN_ANSI_PRODUCT_ID 0x020E -#define FOUNTAIN_ISO_PRODUCT_ID 0x020F - -#define FOUNTAIN_TP_ONLY_PRODUCT_ID 0x030A - -#define GEYSER1_TP_ONLY_PRODUCT_ID 0x030B - -/* PowerBooks Oct 2005 */ -#define GEYSER2_ANSI_PRODUCT_ID 0x0214 -#define GEYSER2_ISO_PRODUCT_ID 0x0215 -#define GEYSER2_JIS_PRODUCT_ID 0x0216 - -/* MacBook devices */ -#define GEYSER3_ANSI_PRODUCT_ID 0x0217 -#define GEYSER3_ISO_PRODUCT_ID 0x0218 -#define GEYSER3_JIS_PRODUCT_ID 0x0219 - -/* - * Geyser IV: same as Geyser III according to Info.plist in OSX's - * AppleUSBTrackpad.kext - * -> same IOClass (AppleUSBGrIIITrackpad), same acceleration tables - */ -#define GEYSER4_ANSI_PRODUCT_ID 0x021A -#define GEYSER4_ISO_PRODUCT_ID 0x021B -#define GEYSER4_JIS_PRODUCT_ID 0x021C - -/* Macbook3,1 devices */ -#define GEYSER4_HF_ANSI_PRODUCT_ID 0x0229 -#define GEYSER4_HF_ISO_PRODUCT_ID 0x022A -#define GEYSER4_HF_JIS_PRODUCT_ID 0x022B +/* Type of touchpad */ +enum atp_touchpad_type { + ATP_FOUNTAIN, + ATP_GEYSER1, + ATP_GEYSER2, + ATP_GEYSER3, + ATP_GEYSER4 +}; -#define ATP_DEVICE(prod) \ +#define ATP_DEVICE(prod, type) \ +{ \ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ USB_DEVICE_ID_MATCH_INT_CLASS | \ USB_DEVICE_ID_MATCH_INT_PROTOCOL, \ - .idVendor = APPLE_VENDOR_ID, \ + .idVendor = 0x05ac, /* Apple */ \ .idProduct = (prod), \ .bInterfaceClass = 0x03, \ - .bInterfaceProtocol = 0x02 + .bInterfaceProtocol = 0x02, \ + .driver_info = ATP_ ## type, \ +} + +/* + * Table of devices (Product IDs) that work with this driver. + * (The names come from Info.plist in AppleUSBTrackpad.kext, + * According to Info.plist Geyser IV is the same as Geyser III.) + */ -/* table of devices that work with this driver */ static struct usb_device_id atp_table [] = { /* PowerBooks Feb 2005, iBooks G4 */ - { ATP_DEVICE(FOUNTAIN_ANSI_PRODUCT_ID) }, - { ATP_DEVICE(FOUNTAIN_ISO_PRODUCT_ID) }, - { ATP_DEVICE(FOUNTAIN_TP_ONLY_PRODUCT_ID) }, - { ATP_DEVICE(GEYSER1_TP_ONLY_PRODUCT_ID) }, + ATP_DEVICE(0x020e, FOUNTAIN), /* FOUNTAIN ANSI */ + ATP_DEVICE(0x020f, FOUNTAIN), /* FOUNTAIN ISO */ + ATP_DEVICE(0x030a, FOUNTAIN), /* FOUNTAIN TP ONLY */ + ATP_DEVICE(0x030b, GEYSER1), /* GEYSER 1 TP ONLY */ /* PowerBooks Oct 2005 */ - { ATP_DEVICE(GEYSER2_ANSI_PRODUCT_ID) }, - { ATP_DEVICE(GEYSER2_ISO_PRODUCT_ID) }, - { ATP_DEVICE(GEYSER2_JIS_PRODUCT_ID) }, + ATP_DEVICE(0x0214, GEYSER2), /* GEYSER 2 ANSI */ + ATP_DEVICE(0x0215, GEYSER2), /* GEYSER 2 ISO */ + ATP_DEVICE(0x0216, GEYSER2), /* GEYSER 2 JIS */ /* Core Duo MacBook & MacBook Pro */ - { ATP_DEVICE(GEYSER3_ANSI_PRODUCT_ID) }, - { ATP_DEVICE(GEYSER3_ISO_PRODUCT_ID) }, - { ATP_DEVICE(GEYSER3_JIS_PRODUCT_ID) }, + ATP_DEVICE(0x0217, GEYSER3), /* GEYSER 3 ANSI */ + ATP_DEVICE(0x0218, GEYSER3), /* GEYSER 3 ISO */ + ATP_DEVICE(0x0219, GEYSER3), /* GEYSER 3 JIS */ /* Core2 Duo MacBook & MacBook Pro */ - { ATP_DEVICE(GEYSER4_ANSI_PRODUCT_ID) }, - { ATP_DEVICE(GEYSER4_ISO_PRODUCT_ID) }, - { ATP_DEVICE(GEYSER4_JIS_PRODUCT_ID) }, + ATP_DEVICE(0x021a, GEYSER4), /* GEYSER 4 ANSI */ + ATP_DEVICE(0x021b, GEYSER4), /* GEYSER 4 ISO */ + ATP_DEVICE(0x021c, GEYSER4), /* GEYSER 4 JIS */ /* Core2 Duo MacBook3,1 */ - { ATP_DEVICE(GEYSER4_HF_ANSI_PRODUCT_ID) }, - { ATP_DEVICE(GEYSER4_HF_ISO_PRODUCT_ID) }, - { ATP_DEVICE(GEYSER4_HF_JIS_PRODUCT_ID) }, + ATP_DEVICE(0x0229, GEYSER4), /* GEYSER 4 HF ANSI */ + ATP_DEVICE(0x022a, GEYSER4), /* GEYSER 4 HF ISO */ + ATP_DEVICE(0x022b, GEYSER4), /* GEYSER 4 HF JIS */ /* Terminating entry */ { } @@ -132,9 +112,13 @@ MODULE_DEVICE_TABLE(usb, atp_table); * We try to keep the touchpad aspect ratio while still doing only simple * arithmetics. * The factors below give coordinates like: - * 0 <= x < 960 on 12" and 15" Powerbooks - * 0 <= x < 1600 on 17" Powerbooks - * 0 <= y < 646 + * + * 0 <= x < 960 on 12" and 15" Powerbooks + * 0 <= x < 1600 on 17" Powerbooks and 17" MacBook Pro + * 0 <= x < 1216 on MacBooks and 15" MacBook Pro + * + * 0 <= y < 646 on all Powerbooks + * 0 <= y < 774 on all MacBooks */ #define ATP_XFACT 64 #define ATP_YFACT 43 @@ -159,6 +143,7 @@ struct atp { struct urb *urb; /* usb request block */ signed char *data; /* transferred data */ struct input_dev *input; /* input dev */ + enum atp_touchpad_type type; /* type of touchpad */ bool open; bool valid; /* are the samples valid? */ bool size_detect_done; @@ -209,40 +194,6 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Activate debugging output"); -static inline int atp_is_fountain(struct atp *dev) -{ - u16 productId = le16_to_cpu(dev->udev->descriptor.idProduct); - - return productId == FOUNTAIN_ANSI_PRODUCT_ID || - productId == FOUNTAIN_ISO_PRODUCT_ID || - productId == FOUNTAIN_TP_ONLY_PRODUCT_ID; -} - -/* Checks if the device a Geyser 2 (ANSI, ISO, JIS) */ -static inline int atp_is_geyser_2(struct atp *dev) -{ - u16 productId = le16_to_cpu(dev->udev->descriptor.idProduct); - - return (productId == GEYSER2_ANSI_PRODUCT_ID) || - (productId == GEYSER2_ISO_PRODUCT_ID) || - (productId == GEYSER2_JIS_PRODUCT_ID); -} - -static inline int atp_is_geyser_3(struct atp *dev) -{ - u16 productId = le16_to_cpu(dev->udev->descriptor.idProduct); - - return (productId == GEYSER3_ANSI_PRODUCT_ID) || - (productId == GEYSER3_ISO_PRODUCT_ID) || - (productId == GEYSER3_JIS_PRODUCT_ID) || - (productId == GEYSER4_ANSI_PRODUCT_ID) || - (productId == GEYSER4_ISO_PRODUCT_ID) || - (productId == GEYSER4_JIS_PRODUCT_ID) || - (productId == GEYSER4_HF_ANSI_PRODUCT_ID) || - (productId == GEYSER4_HF_ISO_PRODUCT_ID) || - (productId == GEYSER4_HF_JIS_PRODUCT_ID); -} - /* * By default newer Geyser devices send standard USB HID mouse * packets (Report ID 2). This code changes device mode, so it @@ -416,7 +367,7 @@ static void atp_complete(struct urb *urb) } /* reorder the sensors values */ - if (atp_is_geyser_3(dev)) { + if (dev->type == ATP_GEYSER3 || dev->type == ATP_GEYSER4) { memset(dev->xy_cur, 0, sizeof(dev->xy_cur)); /* @@ -435,7 +386,7 @@ static void atp_complete(struct urb *urb) dev->xy_cur[ATP_XSENSORS + i] = dev->data[j + 1]; dev->xy_cur[ATP_XSENSORS + i + 1] = dev->data[j + 2]; } - } else if (atp_is_geyser_2(dev)) { + } else if (dev->type == ATP_GEYSER2) { memset(dev->xy_cur, 0, sizeof(dev->xy_cur)); /* @@ -479,17 +430,17 @@ static void atp_complete(struct urb *urb) memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old)); if (dev->size_detect_done || - atp_is_geyser_3(dev)) /* No 17" Macbooks (yet) */ + dev->type == ATP_GEYSER3) /* No 17" Macbooks (yet) */ goto exit; /* 17" Powerbooks have extra X sensors */ - for (i = (atp_is_geyser_2(dev) ? 15 : 16); + for (i = (dev->type == ATP_GEYSER2 ? 15 : 16); i < ATP_XSENSORS; i++) { if (!dev->xy_cur[i]) continue; printk(KERN_INFO "appletouch: 17\" model detected.\n"); - if (atp_is_geyser_2(dev)) + if (dev->type == ATP_GEYSER2) input_set_abs_params(dev->input, ABS_X, 0, (20 - 1) * ATP_XFACT - 1, @@ -569,7 +520,7 @@ static void atp_complete(struct urb *urb) * several hundred times a second. Re-initialization does not * work on Fountain touchpads. */ - if (!atp_is_fountain(dev)) { + if (dev->type != ATP_FOUNTAIN) { /* * Button must not be pressed when entering suspend, * otherwise we will never release the button. @@ -650,15 +601,14 @@ static int atp_probe(struct usb_interface *iface, dev->udev = udev; dev->input = input_dev; + dev->type = id->driver_info; dev->overflow_warned = false; - if (atp_is_geyser_3(dev)) - dev->datalen = 64; - else if (atp_is_geyser_2(dev)) - dev->datalen = 64; - else + if (dev->type == ATP_FOUNTAIN || dev->type == ATP_GEYSER1) dev->datalen = 81; + else + dev->datalen = 64; - if (!atp_is_fountain(dev)) { + if (dev->type != ATP_FOUNTAIN) { /* switch to raw sensor mode */ if (atp_geyser_init(udev)) goto err_free_devs; @@ -694,7 +644,7 @@ static int atp_probe(struct usb_interface *iface, set_bit(EV_ABS, input_dev->evbit); - if (atp_is_geyser_3(dev)) { + if (dev->type == ATP_GEYSER3 || dev->type == ATP_GEYSER4) { /* * MacBook have 20 X sensors, 10 Y sensors */ @@ -702,7 +652,7 @@ static int atp_probe(struct usb_interface *iface, ((20 - 1) * ATP_XFACT) - 1, ATP_FUZZ, 0); input_set_abs_params(input_dev, ABS_Y, 0, ((10 - 1) * ATP_YFACT) - 1, ATP_FUZZ, 0); - } else if (atp_is_geyser_2(dev)) { + } else if (dev->type == ATP_GEYSER2) { /* * Oct 2005 15" PowerBooks have 15 X sensors, 17" are detected * later. -- cgit v1.2.3-70-g09d2 From 2ff98147847de3d27d7aa174d58467d21fe372aa Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Tue, 6 May 2008 12:10:39 -0400 Subject: Input: hil_ptr - check return value of input_register_device() [dtor@mail.ru: also signal correct return value to callers] Signed-off-by: Andres Salomon Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/hil_ptr.c | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/input/mouse/hil_ptr.c b/drivers/input/mouse/hil_ptr.c index 27f88fbb713..e532c48410e 100644 --- a/drivers/input/mouse/hil_ptr.c +++ b/drivers/input/mouse/hil_ptr.c @@ -247,19 +247,24 @@ static void hil_ptr_disconnect(struct serio *serio) static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver) { - struct hil_ptr *ptr; - const char *txt; - unsigned int i, naxsets, btntype; - uint8_t did, *idd; - - if (!(ptr = kzalloc(sizeof(struct hil_ptr), GFP_KERNEL))) + struct hil_ptr *ptr; + const char *txt; + unsigned int i, naxsets, btntype; + uint8_t did, *idd; + int error; + + ptr = kzalloc(sizeof(struct hil_ptr), GFP_KERNEL); + if (!ptr) return -ENOMEM; ptr->dev = input_allocate_device(); - if (!ptr->dev) + if (!ptr->dev) { + error = -ENOMEM; goto bail0; + } - if (serio_open(serio, driver)) + error = serio_open(serio, driver); + if (error) goto bail1; serio_set_drvdata(serio, ptr); @@ -297,6 +302,7 @@ static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver) did = ptr->idd[0]; idd = ptr->idd + 1; txt = "unknown"; + if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_REL) { ptr->dev->evbit[0] = BIT_MASK(EV_REL); txt = "relative"; @@ -306,8 +312,11 @@ static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver) ptr->dev->evbit[0] = BIT_MASK(EV_ABS); txt = "absolute"; } - if (!ptr->dev->evbit[0]) + + if (!ptr->dev->evbit[0]) { + error = -ENODEV; goto bail2; + } ptr->nbtn = HIL_IDD_NUM_BUTTONS(idd); if (ptr->nbtn) @@ -380,13 +389,19 @@ static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver) ptr->dev->id.version = 0x0100; /* TODO: get from ptr->rsc */ ptr->dev->dev.parent = &serio->dev; - input_register_device(ptr->dev); + error = input_register_device(ptr->dev); + if (error) { + printk(KERN_INFO PREFIX "Unable to register input device\n"); + goto bail2; + } + printk(KERN_INFO "input: %s (%s), ID: %d\n", ptr->dev->name, (btntype == BTN_MOUSE) ? "HIL mouse":"HIL tablet or touchpad", did); return 0; + bail2: serio_close(serio); bail1: @@ -394,7 +409,7 @@ static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver) bail0: kfree(ptr); serio_set_drvdata(serio, NULL); - return -ENODEV; + return error; } static struct serio_device_id hil_ptr_ids[] = { -- cgit v1.2.3-70-g09d2 From 3e582db0783872a645f5236ef142be6579b300ad Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 6 May 2008 12:11:29 -0400 Subject: Input: gameport - remove rescan/reconnect facilities They have never been used and are unlikely to be used in the future so remove them altogether. Reported-by: Adrian Bunk Signed-off-by: Dmitry Torokhov --- drivers/input/gameport/gameport.c | 22 ---------------------- include/linux/gameport.h | 1 - 2 files changed, 23 deletions(-) (limited to 'drivers') diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index c5600ac5feb..078e4eed089 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -36,7 +36,6 @@ EXPORT_SYMBOL(__gameport_register_driver); EXPORT_SYMBOL(gameport_unregister_driver); EXPORT_SYMBOL(gameport_open); EXPORT_SYMBOL(gameport_close); -EXPORT_SYMBOL(gameport_rescan); EXPORT_SYMBOL(gameport_set_phys); EXPORT_SYMBOL(gameport_start_polling); EXPORT_SYMBOL(gameport_stop_polling); @@ -230,8 +229,6 @@ static void gameport_find_driver(struct gameport *gameport) */ enum gameport_event_type { - GAMEPORT_RESCAN, - GAMEPORT_RECONNECT, GAMEPORT_REGISTER_PORT, GAMEPORT_REGISTER_DRIVER, }; @@ -365,15 +362,6 @@ static void gameport_handle_event(void) gameport_add_port(event->object); break; - case GAMEPORT_RECONNECT: - gameport_reconnect_port(event->object); - break; - - case GAMEPORT_RESCAN: - gameport_disconnect_port(event->object); - gameport_find_driver(event->object); - break; - case GAMEPORT_REGISTER_DRIVER: gameport_add_driver(event->object); break; @@ -651,16 +639,6 @@ static void gameport_disconnect_port(struct gameport *gameport) device_release_driver(&gameport->dev); } -void gameport_rescan(struct gameport *gameport) -{ - gameport_queue_event(gameport, NULL, GAMEPORT_RESCAN); -} - -void gameport_reconnect(struct gameport *gameport) -{ - gameport_queue_event(gameport, NULL, GAMEPORT_RECONNECT); -} - /* * Submits register request to kgameportd for subsequent execution. * Note that port registration is always asynchronous. diff --git a/include/linux/gameport.h b/include/linux/gameport.h index afad9527284..f64e29c0ef3 100644 --- a/include/linux/gameport.h +++ b/include/linux/gameport.h @@ -68,7 +68,6 @@ struct gameport_driver { int gameport_open(struct gameport *gameport, struct gameport_driver *drv, int mode); void gameport_close(struct gameport *gameport); -void gameport_rescan(struct gameport *gameport); #if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) -- cgit v1.2.3-70-g09d2 From ccd3474569a101914444dc37cc108eec22578999 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 6 May 2008 12:11:39 -0400 Subject: Input: libps2 - remove delayed command execution Delayed command execution is not used by anyone so let's remove it. Reported-by: Adrian Bunk Signed-off-by: Dmitry Torokhov --- drivers/input/serio/libps2.c | 52 -------------------------------------------- include/linux/libps2.h | 1 - 2 files changed, 53 deletions(-) (limited to 'drivers') diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c index b819239d74d..2b304c22c20 100644 --- a/drivers/input/serio/libps2.c +++ b/drivers/input/serio/libps2.c @@ -26,15 +26,6 @@ MODULE_AUTHOR("Dmitry Torokhov "); MODULE_DESCRIPTION("PS/2 driver library"); MODULE_LICENSE("GPL"); -/* Work structure to schedule execution of a command */ -struct ps2work { - struct work_struct work; - struct ps2dev *ps2dev; - int command; - unsigned char param[0]; -}; - - /* * ps2_sendbyte() sends a byte to the device and waits for acknowledge. * It doesn't handle retransmission, though it could - because if there @@ -245,49 +236,6 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command) } EXPORT_SYMBOL(ps2_command); -/* - * ps2_execute_scheduled_command() sends a command, previously scheduled by - * ps2_schedule_command(), to a PS/2 device (keyboard, mouse, etc.) - */ - -static void ps2_execute_scheduled_command(struct work_struct *work) -{ - struct ps2work *ps2work = container_of(work, struct ps2work, work); - - ps2_command(ps2work->ps2dev, ps2work->param, ps2work->command); - kfree(ps2work); -} - -/* - * ps2_schedule_command() allows to schedule delayed execution of a PS/2 - * command and can be used to issue a command from an interrupt or softirq - * context. - */ - -int ps2_schedule_command(struct ps2dev *ps2dev, unsigned char *param, int command) -{ - struct ps2work *ps2work; - int send = (command >> 12) & 0xf; - int receive = (command >> 8) & 0xf; - - if (!(ps2work = kmalloc(sizeof(struct ps2work) + max(send, receive), GFP_ATOMIC))) - return -1; - - memset(ps2work, 0, sizeof(struct ps2work)); - ps2work->ps2dev = ps2dev; - ps2work->command = command; - memcpy(ps2work->param, param, send); - INIT_WORK(&ps2work->work, ps2_execute_scheduled_command); - - if (!schedule_work(&ps2work->work)) { - kfree(ps2work); - return -1; - } - - return 0; -} -EXPORT_SYMBOL(ps2_schedule_command); - /* * ps2_init() initializes ps2dev structure */ diff --git a/include/linux/libps2.h b/include/linux/libps2.h index f6f301e2b0f..afc41336910 100644 --- a/include/linux/libps2.h +++ b/include/linux/libps2.h @@ -43,7 +43,6 @@ void ps2_init(struct ps2dev *ps2dev, struct serio *serio); int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout); void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout); int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command); -int ps2_schedule_command(struct ps2dev *ps2dev, unsigned char *param, int command); int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data); int ps2_handle_response(struct ps2dev *ps2dev, unsigned char data); void ps2_cmd_aborted(struct ps2dev *ps2dev); -- cgit v1.2.3-70-g09d2 From 253b00f1e6619055d524188f254ccb951bffce5d Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 7 May 2008 11:15:23 -0400 Subject: Input: remove unused defines Remove unused to_dev, to_handler, to_handle from include/linux/input.h Move to_handle_h from include/linux/input.h to drivers/char/keyboard.c Signed-off-by: Joe Perches Signed-off-by: Andrew Morton Signed-off-by: Dmitry Torokhov --- drivers/char/keyboard.c | 2 ++ include/linux/input.h | 5 ----- 2 files changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 7f7e798c138..d0369e05490 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -46,6 +46,8 @@ extern void ctrl_alt_del(void); +#define to_handle_h(n) container_of(n, struct input_handle, h_node) + /* * Exported functions/variables */ diff --git a/include/linux/input.h b/include/linux/input.h index 28a094fcfe2..eff711d8a45 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -1213,11 +1213,6 @@ struct input_handle { struct list_head h_node; }; -#define to_dev(n) container_of(n, struct input_dev, node) -#define to_handler(n) container_of(n, struct input_handler, node) -#define to_handle(n) container_of(n, struct input_handle, d_node) -#define to_handle_h(n) container_of(n, struct input_handle, h_node) - struct input_dev *input_allocate_device(void); void input_free_device(struct input_dev *dev); -- cgit v1.2.3-70-g09d2 From 885c316d776b64728b4ed30e3af60d23c9e46825 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 7 May 2008 11:15:02 -0400 Subject: Input: add support for SuperH MigoR touchscreen This is V2 of the MigoR touch screen driver. The chip we interface to is unfortunately a custom designed microcontroller speaking some undocumented protocol over i2c. The board specific code is expected to register this device as an i2c chip using struct i2c_board_info [] and i2c_register_board_info(). [dtor@mail.ru: don't enable touchscreen if there are no users] Signed-off-by: Magnus Damm Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 11 ++ drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/migor_ts.c | 250 +++++++++++++++++++++++++++++++++++ 3 files changed, 262 insertions(+) create mode 100644 drivers/input/touchscreen/migor_ts.c (limited to 'drivers') diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 565ec711c2e..2cb4df0e0a7 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -146,6 +146,17 @@ config TOUCHSCREEN_PENMOUNT To compile this driver as a module, choose M here: the module will be called penmount. +config TOUCHSCREEN_MIGOR + tristate "Renesas MIGO-R touchscreen" + depends on SH_MIGOR && I2C + help + Say Y here to enable MIGO-R touchscreen support. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called migor_ts. + config TOUCHSCREEN_TOUCHRIGHT tristate "Touchright serial touchscreen" select SERIO diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 3c096d75651..30e86816cd4 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_TOUCHSCREEN_CORGI) += corgi_ts.o obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o +obj-$(CONFIG_TOUCHSCREEN_MIGOR) += migor_ts.o obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o diff --git a/drivers/input/touchscreen/migor_ts.c b/drivers/input/touchscreen/migor_ts.c new file mode 100644 index 00000000000..c1cd99d5898 --- /dev/null +++ b/drivers/input/touchscreen/migor_ts.c @@ -0,0 +1,250 @@ +/* + * Touch Screen driver for Renesas MIGO-R Platform + * + * Copyright (c) 2008 Magnus Damm + * Copyright (c) 2007 Ujjwal Pande , + * Kenati Technologies Pvt Ltd. + * + * This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This file 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 library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include + +#define EVENT_PENDOWN 1 +#define EVENT_REPEAT 2 +#define EVENT_PENUP 3 + +struct migor_ts_priv { + struct i2c_client *client; + struct input_dev *input; + struct delayed_work work; + int irq; +}; + +static const u_int8_t migor_ts_ena_seq[17] = { 0x33, 0x22, 0x11, + 0x01, 0x06, 0x07, }; +static const u_int8_t migor_ts_dis_seq[17] = { }; + +static void migor_ts_poscheck(struct work_struct *work) +{ + struct migor_ts_priv *priv = container_of(work, + struct migor_ts_priv, + work.work); + unsigned short xpos, ypos; + unsigned char event; + u_int8_t buf[16]; + + memset(buf, 0, sizeof(buf)); + + /* Set Index 0 */ + buf[0] = 0; + if (i2c_master_send(priv->client, buf, 1) != 1) { + dev_err(&priv->client->dev, "Unable to write i2c index\n"); + goto out; + } + + /* Now do Page Read */ + if (i2c_master_recv(priv->client, buf, sizeof(buf)) != sizeof(buf)) { + dev_err(&priv->client->dev, "Unable to read i2c page\n"); + goto out; + } + + ypos = ((buf[9] & 0x03) << 8 | buf[8]); + xpos = ((buf[11] & 0x03) << 8 | buf[10]); + event = buf[12]; + + if (event == EVENT_PENDOWN || event == EVENT_REPEAT) { + input_report_key(priv->input, BTN_TOUCH, 1); + input_report_abs(priv->input, ABS_X, ypos); /*X-Y swap*/ + input_report_abs(priv->input, ABS_Y, xpos); + input_sync(priv->input); + } else if (event == EVENT_PENUP) { + input_report_key(priv->input, BTN_TOUCH, 0); + input_sync(priv->input); + } + out: + enable_irq(priv->irq); +} + +static irqreturn_t migor_ts_isr(int irq, void *dev_id) +{ + struct migor_ts_priv *priv = dev_id; + + /* the touch screen controller chip is hooked up to the cpu + * using i2c and a single interrupt line. the interrupt line + * is pulled low whenever someone taps the screen. to deassert + * the interrupt line we need to acknowledge the interrupt by + * communicating with the controller over the slow i2c bus. + * + * we can't acknowledge from interrupt context since the i2c + * bus controller may sleep, so we just disable the interrupt + * here and handle the acknowledge using delayed work. + */ + + disable_irq_nosync(irq); + schedule_delayed_work(&priv->work, HZ / 20); + + return IRQ_HANDLED; +} + + +static int migor_ts_open(struct input_dev *dev) +{ + struct migor_ts_priv *priv = input_get_drvdata(dev); + struct i2c_client *client = priv->client; + int count; + + /* enable controller */ + count = i2c_master_send(client, migor_ts_ena_seq, + sizeof(migor_ts_ena_seq)); + if (count != sizeof(migor_ts_ena_seq)) { + dev_err(&client->dev, "Unable to enable touchscreen.\n"); + return -ENXIO; + } + + return 0; +} + +static void migor_ts_close(struct input_dev *dev) +{ + struct migor_ts_priv *priv = input_get_drvdata(dev); + struct i2c_client *client = priv->client; + + disable_irq(priv->irq); + + /* cancel pending work and wait for migor_ts_poscheck() to finish */ + if (cancel_delayed_work_sync(&priv->work)) { + /* + * if migor_ts_poscheck was canceled we need to enable IRQ + * here to balance disable done in migor_ts_isr. + */ + enable_irq(priv->irq); + } + + /* disable controller */ + i2c_master_send(client, migor_ts_dis_seq, sizeof(migor_ts_dis_seq)); + + enable_irq(priv->irq); +} + +static int migor_ts_probe(struct i2c_client *client, + const struct i2c_device_id *idp) +{ + struct migor_ts_priv *priv; + struct input_dev *input; + int error; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) { + dev_err(&client->dev, "failed to allocate driver data\n"); + error = -ENOMEM; + goto err0; + } + + dev_set_drvdata(&client->dev, priv); + + input = input_allocate_device(); + if (!input) { + dev_err(&client->dev, "Failed to allocate input device.\n"); + error = -ENOMEM; + goto err1; + } + + input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + + input_set_abs_params(input, ABS_X, 95, 955, 0, 0); + input_set_abs_params(input, ABS_Y, 85, 935, 0, 0); + + input->name = client->driver_name; + input->id.bustype = BUS_I2C; + input->dev.parent = &client->dev; + + input->open = migor_ts_open; + input->close = migor_ts_close; + + input_set_drvdata(input, priv); + + priv->client = client; + priv->input = input; + INIT_DELAYED_WORK(&priv->work, migor_ts_poscheck); + priv->irq = client->irq; + + error = input_register_device(input); + if (error) + goto err1; + + error = request_irq(priv->irq, migor_ts_isr, IRQF_TRIGGER_LOW, + client->driver_name, priv); + if (error) { + dev_err(&client->dev, "Unable to request touchscreen IRQ.\n"); + goto err2; + } + + return 0; + + err2: + input_unregister_device(input); + input = NULL; /* so we dont try to free it below */ + err1: + input_free_device(input); + kfree(priv); + err0: + dev_set_drvdata(&client->dev, NULL); + return error; +} + +static int migor_ts_remove(struct i2c_client *client) +{ + struct migor_ts_priv *priv = dev_get_drvdata(&client->dev); + + free_irq(priv->irq, priv); + input_unregister_device(priv->input); + kfree(priv); + + dev_set_drvdata(&client->dev, NULL); + + return 0; +} + +static struct i2c_driver migor_ts_driver = { + .driver = { + .name = "migor_ts", + }, + .probe = migor_ts_probe, + .remove = migor_ts_remove, +}; + +static int __init migor_ts_init(void) +{ + return i2c_add_driver(&migor_ts_driver); +} + +static void __exit migor_ts_exit(void) +{ + i2c_del_driver(&migor_ts_driver); +} + +MODULE_DESCRIPTION("MigoR Touchscreen driver"); +MODULE_AUTHOR("Magnus Damm "); +MODULE_LICENSE("GPL"); + +module_init(migor_ts_init); +module_exit(migor_ts_exit); -- cgit v1.2.3-70-g09d2 From a33466e31213cd7c46696160d3db78680b58f6a3 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 7 May 2008 16:30:15 -0400 Subject: Input: gpio-keys debouncing support Signed-off-by: Dmitry Baryshkov Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/gpio_keys.c | 89 +++++++++++++++++++++++++++++--------- include/linux/gpio_keys.h | 1 + 2 files changed, 70 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index bbd00c3fe98..be58730e636 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -26,23 +26,54 @@ #include +struct gpio_button_data { + struct gpio_keys_button *button; + struct input_dev *input; + struct timer_list timer; +}; + +struct gpio_keys_drvdata { + struct input_dev *input; + struct gpio_button_data data[0]; +}; + +static void gpio_keys_report_event(struct gpio_keys_button *button, + struct input_dev *input) +{ + unsigned int type = button->type ?: EV_KEY; + int state = (gpio_get_value(button->gpio) ? 1 : 0) ^ button->active_low; + + input_event(input, type, button->code, !!state); + input_sync(input); +} + +static void gpio_check_button(unsigned long _data) +{ + struct gpio_button_data *data = (struct gpio_button_data *)_data; + + gpio_keys_report_event(data->button, data->input); +} + static irqreturn_t gpio_keys_isr(int irq, void *dev_id) { - int i; struct platform_device *pdev = dev_id; struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; - struct input_dev *input = platform_get_drvdata(pdev); + struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev); + int i; for (i = 0; i < pdata->nbuttons; i++) { struct gpio_keys_button *button = &pdata->buttons[i]; - int gpio = button->gpio; - if (irq == gpio_to_irq(gpio)) { - unsigned int type = button->type ?: EV_KEY; - int state = (gpio_get_value(gpio) ? 1 : 0) ^ button->active_low; + if (irq == gpio_to_irq(button->gpio)) { + struct gpio_button_data *bdata = &ddata->data[i]; + + if (button->debounce_interval) + mod_timer(&bdata->timer, + jiffies + + msecs_to_jiffies(button->debounce_interval)); + else + gpio_keys_report_event(button, bdata->input); - input_event(input, type, button->code, !!state); - input_sync(input); return IRQ_HANDLED; } } @@ -53,17 +84,21 @@ static irqreturn_t gpio_keys_isr(int irq, void *dev_id) static int __devinit gpio_keys_probe(struct platform_device *pdev) { struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; + struct gpio_keys_drvdata *ddata; struct input_dev *input; int i, error; int wakeup = 0; + ddata = kzalloc(sizeof(struct gpio_keys_drvdata) + + pdata->nbuttons * sizeof(struct gpio_button_data), + GFP_KERNEL); input = input_allocate_device(); - if (!input) - return -ENOMEM; - - platform_set_drvdata(pdev, input); + if (!ddata || !input) { + error = -ENOMEM; + goto fail1; + } - input->evbit[0] = BIT_MASK(EV_KEY); + platform_set_drvdata(pdev, ddata); input->name = pdev->name; input->phys = "gpio-keys/input0"; @@ -74,16 +109,23 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) input->id.product = 0x0001; input->id.version = 0x0100; + ddata->input = input; + for (i = 0; i < pdata->nbuttons; i++) { struct gpio_keys_button *button = &pdata->buttons[i]; + struct gpio_button_data *bdata = &ddata->data[i]; int irq; unsigned int type = button->type ?: EV_KEY; + bdata->input = input; + setup_timer(&bdata->timer, + gpio_check_button, (unsigned long)bdata); + error = gpio_request(button->gpio, button->desc ?: "gpio_keys"); if (error < 0) { pr_err("gpio-keys: failed to request GPIO %d," " error %d\n", button->gpio, error); - goto fail; + goto fail2; } error = gpio_direction_input(button->gpio); @@ -92,7 +134,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) " direction for GPIO %d, error %d\n", button->gpio, error); gpio_free(button->gpio); - goto fail; + goto fail2; } irq = gpio_to_irq(button->gpio); @@ -102,7 +144,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) " for GPIO %d, error %d\n", button->gpio, error); gpio_free(button->gpio); - goto fail; + goto fail2; } error = request_irq(irq, gpio_keys_isr, @@ -114,7 +156,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) pr_err("gpio-keys: Unable to claim irq %d; error %d\n", irq, error); gpio_free(button->gpio); - goto fail; + goto fail2; } if (button->wakeup) @@ -127,21 +169,25 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) if (error) { pr_err("gpio-keys: Unable to register input device, " "error: %d\n", error); - goto fail; + goto fail2; } device_init_wakeup(&pdev->dev, wakeup); return 0; - fail: + fail2: while (--i >= 0) { free_irq(gpio_to_irq(pdata->buttons[i].gpio), pdev); + if (pdata->buttons[i].debounce_interval) + del_timer_sync(&ddata->data[i].timer); gpio_free(pdata->buttons[i].gpio); } platform_set_drvdata(pdev, NULL); + fail1: input_free_device(input); + kfree(ddata); return error; } @@ -149,7 +195,8 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) static int __devexit gpio_keys_remove(struct platform_device *pdev) { struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; - struct input_dev *input = platform_get_drvdata(pdev); + struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev); + struct input_dev *input = ddata->input; int i; device_init_wakeup(&pdev->dev, 0); @@ -157,6 +204,8 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev) for (i = 0; i < pdata->nbuttons; i++) { int irq = gpio_to_irq(pdata->buttons[i].gpio); free_irq(irq, pdev); + if (pdata->buttons[i].debounce_interval) + del_timer_sync(&ddata->data[i].timer); gpio_free(pdata->buttons[i].gpio); } diff --git a/include/linux/gpio_keys.h b/include/linux/gpio_keys.h index c6d3a9de563..ec6ecd74781 100644 --- a/include/linux/gpio_keys.h +++ b/include/linux/gpio_keys.h @@ -9,6 +9,7 @@ struct gpio_keys_button { char *desc; int type; /* input event type (EV_KEY, EV_SW) */ int wakeup; /* configure the button as a wake-up source */ + int debounce_interval; /* debounce ticks interval in msecs */ }; struct gpio_keys_platform_data { -- cgit v1.2.3-70-g09d2 From 9a120bc570627342c17befaa6af9b0a556dfda48 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 16 May 2008 22:17:45 -0700 Subject: bnx2: Allow phy reset to be skipped during chip reset. Andy Gospodarek found that netconsole would panic when resetting bnx2 devices. >From Andy: "The issue is the bnx2_set_link in bnx2_init_nic will print a link-status message before we are fully initialized and ready to start polling. Polling is currently disabled in this state, but since the __LINK_STATE_RX_SCHED is overloaded to not only try and disable polling but also to make the system aware there is something waiting to be polled, we really have to fix this in drivers. The problematic call is the one to netif_rx_complete as it tries to remove an entry from the poll_list when there isn't one." While this netconsole problem should be fixed separately, we really should not reset the PHY when changing ring sizes, MTU, or other similar settings. The PHY reset causes several seconds of unnecessary link disruptions. Signed-off-by: Michael Chan Acked-by: Andy Gospodarek Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 50 +++++++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 4b46e68183e..934c2bfc464 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -1875,7 +1875,7 @@ bnx2_setup_phy(struct bnx2 *bp, u8 port) } static int -bnx2_init_5709s_phy(struct bnx2 *bp) +bnx2_init_5709s_phy(struct bnx2 *bp, int reset_phy) { u32 val; @@ -1890,7 +1890,8 @@ bnx2_init_5709s_phy(struct bnx2 *bp) bnx2_write_phy(bp, MII_BNX2_AER_AER, MII_BNX2_AER_AER_AN_MMD); bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0); - bnx2_reset_phy(bp); + if (reset_phy) + bnx2_reset_phy(bp); bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_SERDES_DIG); @@ -1924,11 +1925,12 @@ bnx2_init_5709s_phy(struct bnx2 *bp) } static int -bnx2_init_5708s_phy(struct bnx2 *bp) +bnx2_init_5708s_phy(struct bnx2 *bp, int reset_phy) { u32 val; - bnx2_reset_phy(bp); + if (reset_phy) + bnx2_reset_phy(bp); bp->mii_up1 = BCM5708S_UP1; @@ -1981,9 +1983,10 @@ bnx2_init_5708s_phy(struct bnx2 *bp) } static int -bnx2_init_5706s_phy(struct bnx2 *bp) +bnx2_init_5706s_phy(struct bnx2 *bp, int reset_phy) { - bnx2_reset_phy(bp); + if (reset_phy) + bnx2_reset_phy(bp); bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT; @@ -2018,11 +2021,12 @@ bnx2_init_5706s_phy(struct bnx2 *bp) } static int -bnx2_init_copper_phy(struct bnx2 *bp) +bnx2_init_copper_phy(struct bnx2 *bp, int reset_phy) { u32 val; - bnx2_reset_phy(bp); + if (reset_phy) + bnx2_reset_phy(bp); if (bp->phy_flags & BNX2_PHY_FLAG_CRC_FIX) { bnx2_write_phy(bp, 0x18, 0x0c00); @@ -2070,7 +2074,7 @@ bnx2_init_copper_phy(struct bnx2 *bp) static int -bnx2_init_phy(struct bnx2 *bp) +bnx2_init_phy(struct bnx2 *bp, int reset_phy) { u32 val; int rc = 0; @@ -2096,14 +2100,14 @@ bnx2_init_phy(struct bnx2 *bp) if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) { if (CHIP_NUM(bp) == CHIP_NUM_5706) - rc = bnx2_init_5706s_phy(bp); + rc = bnx2_init_5706s_phy(bp, reset_phy); else if (CHIP_NUM(bp) == CHIP_NUM_5708) - rc = bnx2_init_5708s_phy(bp); + rc = bnx2_init_5708s_phy(bp, reset_phy); else if (CHIP_NUM(bp) == CHIP_NUM_5709) - rc = bnx2_init_5709s_phy(bp); + rc = bnx2_init_5709s_phy(bp, reset_phy); } else { - rc = bnx2_init_copper_phy(bp); + rc = bnx2_init_copper_phy(bp, reset_phy); } setup_phy: @@ -4873,7 +4877,7 @@ bnx2_reset_nic(struct bnx2 *bp, u32 reset_code) } static int -bnx2_init_nic(struct bnx2 *bp) +bnx2_init_nic(struct bnx2 *bp, int reset_phy) { int rc; @@ -4881,7 +4885,7 @@ bnx2_init_nic(struct bnx2 *bp) return rc; spin_lock_bh(&bp->phy_lock); - bnx2_init_phy(bp); + bnx2_init_phy(bp, reset_phy); bnx2_set_link(bp); if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) bnx2_remote_phy_event(bp); @@ -5269,7 +5273,7 @@ bnx2_test_loopback(struct bnx2 *bp) bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET); spin_lock_bh(&bp->phy_lock); - bnx2_init_phy(bp); + bnx2_init_phy(bp, 1); spin_unlock_bh(&bp->phy_lock); if (bnx2_run_loopback(bp, BNX2_MAC_LOOPBACK)) rc |= BNX2_MAC_LOOPBACK_FAILED; @@ -5659,7 +5663,7 @@ bnx2_open(struct net_device *dev) return rc; } - rc = bnx2_init_nic(bp); + rc = bnx2_init_nic(bp, 1); if (rc) { bnx2_napi_disable(bp); @@ -5691,7 +5695,7 @@ bnx2_open(struct net_device *dev) bnx2_setup_int_mode(bp, 1); - rc = bnx2_init_nic(bp); + rc = bnx2_init_nic(bp, 0); if (!rc) rc = bnx2_request_irq(bp); @@ -5727,7 +5731,7 @@ bnx2_reset_task(struct work_struct *work) bp->in_reset_task = 1; bnx2_netif_stop(bp); - bnx2_init_nic(bp); + bnx2_init_nic(bp, 1); atomic_set(&bp->intr_sem, 1); bnx2_netif_start(bp); @@ -6421,7 +6425,7 @@ bnx2_set_coalesce(struct net_device *dev, struct ethtool_coalesce *coal) if (netif_running(bp->dev)) { bnx2_netif_stop(bp); - bnx2_init_nic(bp); + bnx2_init_nic(bp, 0); bnx2_netif_start(bp); } @@ -6464,7 +6468,7 @@ bnx2_change_ring_size(struct bnx2 *bp, u32 rx, u32 tx) rc = bnx2_alloc_mem(bp); if (rc) return rc; - bnx2_init_nic(bp); + bnx2_init_nic(bp, 0); bnx2_netif_start(bp); } return 0; @@ -6732,7 +6736,7 @@ bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf) bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET); } else { - bnx2_init_nic(bp); + bnx2_init_nic(bp, 1); bnx2_netif_start(bp); } @@ -7619,7 +7623,7 @@ bnx2_resume(struct pci_dev *pdev) bnx2_set_power_state(bp, PCI_D0); netif_device_attach(dev); - bnx2_init_nic(bp); + bnx2_init_nic(bp, 1); bnx2_netif_start(bp); return 0; } -- cgit v1.2.3-70-g09d2 From 6ff2da49c8a68320c2564006c94a492db58de5cd Mon Sep 17 00:00:00 2001 From: Wendy Xiong Date: Fri, 16 May 2008 22:18:21 -0700 Subject: bnx2: Add EEH PCI recovery. Add PCI recovery functions to the driver. The initial pci state is also saved so the the MSI state can be restored during PCI recovery. Signed-off-by: Wendy Xiong Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) (limited to 'drivers') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 934c2bfc464..2589b99a859 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -7119,6 +7119,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) } pci_set_master(pdev); + pci_save_state(pdev); bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM); if (bp->pm_cap == 0) { @@ -7628,6 +7629,92 @@ bnx2_resume(struct pci_dev *pdev) return 0; } +/** + * bnx2_io_error_detected - called when PCI error is detected + * @pdev: Pointer to PCI device + * @state: The current pci connection state + * + * This function is called after a PCI bus error affecting + * this device has been detected. + */ +static pci_ers_result_t bnx2_io_error_detected(struct pci_dev *pdev, + pci_channel_state_t state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct bnx2 *bp = netdev_priv(dev); + + rtnl_lock(); + netif_device_detach(dev); + + if (netif_running(dev)) { + bnx2_netif_stop(bp); + del_timer_sync(&bp->timer); + bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET); + } + + pci_disable_device(pdev); + rtnl_unlock(); + + /* Request a slot slot reset. */ + return PCI_ERS_RESULT_NEED_RESET; +} + +/** + * bnx2_io_slot_reset - called after the pci bus has been reset. + * @pdev: Pointer to PCI device + * + * Restart the card from scratch, as if from a cold-boot. + */ +static pci_ers_result_t bnx2_io_slot_reset(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct bnx2 *bp = netdev_priv(dev); + + rtnl_lock(); + if (pci_enable_device(pdev)) { + dev_err(&pdev->dev, + "Cannot re-enable PCI device after reset.\n"); + rtnl_unlock(); + return PCI_ERS_RESULT_DISCONNECT; + } + pci_set_master(pdev); + pci_restore_state(pdev); + + if (netif_running(dev)) { + bnx2_set_power_state(bp, PCI_D0); + bnx2_init_nic(bp, 1); + } + + rtnl_unlock(); + return PCI_ERS_RESULT_RECOVERED; +} + +/** + * bnx2_io_resume - called when traffic can start flowing again. + * @pdev: Pointer to PCI device + * + * This callback is called when the error recovery driver tells us that + * its OK to resume normal operation. + */ +static void bnx2_io_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct bnx2 *bp = netdev_priv(dev); + + rtnl_lock(); + if (netif_running(dev)) + bnx2_netif_start(bp); + + netif_device_attach(dev); + rtnl_unlock(); +} + +static struct pci_error_handlers bnx2_err_handler = { + .error_detected = bnx2_io_error_detected, + .slot_reset = bnx2_io_slot_reset, + .resume = bnx2_io_resume, +}; + static struct pci_driver bnx2_pci_driver = { .name = DRV_MODULE_NAME, .id_table = bnx2_pci_tbl, @@ -7635,6 +7722,7 @@ static struct pci_driver bnx2_pci_driver = { .remove = __devexit_p(bnx2_remove_one), .suspend = bnx2_suspend, .resume = bnx2_resume, + .err_handler = &bnx2_err_handler, }; static int __init bnx2_init(void) -- cgit v1.2.3-70-g09d2 From d89cb6af41559a601e9cfe081d34de07945b0d8b Mon Sep 17 00:00:00 2001 From: Benjamin Li Date: Fri, 16 May 2008 22:18:57 -0700 Subject: bnx2: Remove the rx_offset field from the bnx2 structure. The rx_offset field is set to a constant value and initialized only once. By replacing all references to the rx_offset field, we can eliminate rx_offset from the bnx2 structure. This will save 4 bytes for every bnx2 instance. [Added parentheses to the definition of BNX2_RX_OFFSET, as noted by Ben Hutchings.] Signed-off-by: Benjamin Li Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 19 +++++++++---------- drivers/net/bnx2.h | 2 +- 2 files changed, 10 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 2589b99a859..2180922550e 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -2624,7 +2624,7 @@ bnx2_reuse_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, struct sk_buff *skb, pci_dma_sync_single_for_device(bp->pdev, pci_unmap_addr(cons_rx_buf, mapping), - bp->rx_offset + RX_COPY_THRESH, PCI_DMA_FROMDEVICE); + BNX2_RX_OFFSET + RX_COPY_THRESH, PCI_DMA_FROMDEVICE); bnapi->rx_prod_bseq += bp->rx_buf_use_size; @@ -2662,7 +2662,7 @@ bnx2_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, struct sk_buff *skb, return err; } - skb_reserve(skb, bp->rx_offset); + skb_reserve(skb, BNX2_RX_OFFSET); pci_unmap_single(bp->pdev, dma_addr, bp->rx_buf_use_size, PCI_DMA_FROMDEVICE); @@ -2777,7 +2777,7 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) dma_addr = pci_unmap_addr(rx_buf, mapping); pci_dma_sync_single_for_cpu(bp->pdev, dma_addr, - bp->rx_offset + RX_COPY_THRESH, PCI_DMA_FROMDEVICE); + BNX2_RX_OFFSET + RX_COPY_THRESH, PCI_DMA_FROMDEVICE); rx_hdr = (struct l2_fhdr *) skb->data; len = rx_hdr->l2_fhdr_pkt_len; @@ -2815,7 +2815,8 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) } /* aligned copy */ - skb_copy_from_linear_data_offset(skb, bp->rx_offset - 2, + skb_copy_from_linear_data_offset(skb, + BNX2_RX_OFFSET - 2, new_skb->data, len + 2); skb_reserve(new_skb, 2); skb_put(new_skb, len); @@ -4754,7 +4755,7 @@ bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size) u32 rx_size, rx_space, jumbo_size; /* 8 for CRC and VLAN */ - rx_size = bp->dev->mtu + ETH_HLEN + bp->rx_offset + 8; + rx_size = bp->dev->mtu + ETH_HLEN + BNX2_RX_OFFSET + 8; rx_space = SKB_DATA_ALIGN(rx_size + BNX2_RX_ALIGN) + NET_SKB_PAD + sizeof(struct skb_shared_info); @@ -4774,14 +4775,14 @@ bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size) bp->rx_max_pg_ring = bnx2_find_max_ring(jumbo_size, MAX_RX_PG_RINGS); bp->rx_max_pg_ring_idx = (bp->rx_max_pg_ring * RX_DESC_CNT) - 1; - rx_size = RX_COPY_THRESH + bp->rx_offset; + rx_size = RX_COPY_THRESH + BNX2_RX_OFFSET; bp->rx_copy_thresh = 0; } bp->rx_buf_use_size = rx_size; /* hw alignment */ bp->rx_buf_size = bp->rx_buf_use_size + BNX2_RX_ALIGN; - bp->rx_jumbo_thresh = rx_size - bp->rx_offset; + bp->rx_jumbo_thresh = rx_size - BNX2_RX_OFFSET; bp->rx_ring_size = size; bp->rx_max_ring = bnx2_find_max_ring(size, MAX_RX_RINGS); bp->rx_max_ring_idx = (bp->rx_max_ring * RX_DESC_CNT) - 1; @@ -5225,7 +5226,7 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode) rx_skb = rx_buf->skb; rx_hdr = (struct l2_fhdr *) rx_skb->data; - skb_reserve(rx_skb, bp->rx_offset); + skb_reserve(rx_skb, BNX2_RX_OFFSET); pci_dma_sync_single_for_cpu(bp->pdev, pci_unmap_addr(rx_buf, mapping), @@ -7306,8 +7307,6 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) bp->mac_addr[4] = (u8) (reg >> 8); bp->mac_addr[5] = (u8) reg; - bp->rx_offset = sizeof(struct l2_fhdr) + 2; - bp->tx_ring_size = MAX_TX_DESC_CNT; bnx2_set_rx_ring_size(bp, 255); diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index 1eaf5bb3d9c..601bafffe8b 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -309,6 +309,7 @@ struct l2_fhdr { #endif }; +#define BNX2_RX_OFFSET (sizeof(struct l2_fhdr) + 2) /* * l2_context definition @@ -6627,7 +6628,6 @@ struct bnx2 { struct vlan_group *vlgrp; #endif - u32 rx_offset; u32 rx_buf_use_size; /* useable size */ u32 rx_buf_size; /* with alignment */ u32 rx_copy_thresh; -- cgit v1.2.3-70-g09d2 From 601d3d18b2c1e4c197aa3cd902fb77bd99c41f10 Mon Sep 17 00:00:00 2001 From: Benjamin Li Date: Fri, 16 May 2008 22:19:35 -0700 Subject: bnx2: Rename RX_COPY_THRESH to BNX2_RX_COPY_THRESH. To make the bnx2 code more consistent, all instances of RX_COPY_THRESH have been changed to BNX2_RX_COPY_THRESH. Signed-off-by: Benjamin Li Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 9 +++++---- drivers/net/bnx2.h | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 2180922550e..1534eed4c35 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -2624,7 +2624,7 @@ bnx2_reuse_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, struct sk_buff *skb, pci_dma_sync_single_for_device(bp->pdev, pci_unmap_addr(cons_rx_buf, mapping), - BNX2_RX_OFFSET + RX_COPY_THRESH, PCI_DMA_FROMDEVICE); + BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH, PCI_DMA_FROMDEVICE); bnapi->rx_prod_bseq += bp->rx_buf_use_size; @@ -2777,7 +2777,8 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) dma_addr = pci_unmap_addr(rx_buf, mapping); pci_dma_sync_single_for_cpu(bp->pdev, dma_addr, - BNX2_RX_OFFSET + RX_COPY_THRESH, PCI_DMA_FROMDEVICE); + BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH, + PCI_DMA_FROMDEVICE); rx_hdr = (struct l2_fhdr *) skb->data; len = rx_hdr->l2_fhdr_pkt_len; @@ -4760,7 +4761,7 @@ bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size) rx_space = SKB_DATA_ALIGN(rx_size + BNX2_RX_ALIGN) + NET_SKB_PAD + sizeof(struct skb_shared_info); - bp->rx_copy_thresh = RX_COPY_THRESH; + bp->rx_copy_thresh = BNX2_RX_COPY_THRESH; bp->rx_pg_ring_size = 0; bp->rx_max_pg_ring = 0; bp->rx_max_pg_ring_idx = 0; @@ -4775,7 +4776,7 @@ bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size) bp->rx_max_pg_ring = bnx2_find_max_ring(jumbo_size, MAX_RX_PG_RINGS); bp->rx_max_pg_ring_idx = (bp->rx_max_pg_ring * RX_DESC_CNT) - 1; - rx_size = RX_COPY_THRESH + BNX2_RX_OFFSET; + rx_size = BNX2_RX_COPY_THRESH + BNX2_RX_OFFSET; bp->rx_copy_thresh = 0; } diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index 601bafffe8b..16020a10bf4 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -6413,7 +6413,7 @@ struct l2_fhdr { #define MAX_ETHERNET_PACKET_SIZE 1514 #define MAX_ETHERNET_JUMBO_PACKET_SIZE 9014 -#define RX_COPY_THRESH 128 +#define BNX2_RX_COPY_THRESH 128 #define BNX2_MISC_ENABLE_DEFAULT 0x17ffffff -- cgit v1.2.3-70-g09d2 From 10343cca2bad3f9fdad214385bed0a9aadf4ffd4 Mon Sep 17 00:00:00 2001 From: Benjamin Li Date: Fri, 16 May 2008 22:20:27 -0700 Subject: bnx2: Pre-initialize struct cpu_reg. Instead of assigning values for the struct cpu_reg's at runtime, we already know these values at compile time. Therefore, we can use designated initializers, to initialize these structures and not have to incur this assignment cost at run-time. Signed-off-by: Benjamin Li Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 78 ++++--------------------------------------------- drivers/net/bnx2_fw.h | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 72 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 1534eed4c35..e1787a1e1e7 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -3219,7 +3219,7 @@ load_rv2p_fw(struct bnx2 *bp, __le32 *rv2p_code, u32 rv2p_code_len, } static int -load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw) +load_cpu_fw(struct bnx2 *bp, const struct cpu_reg *cpu_reg, struct fw_info *fw) { u32 offset; u32 val; @@ -3303,7 +3303,6 @@ load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw) static int bnx2_init_cpus(struct bnx2 *bp) { - struct cpu_reg cpu_reg; struct fw_info *fw; int rc, rv2p_len; void *text, *rv2p; @@ -3339,122 +3338,57 @@ bnx2_init_cpus(struct bnx2 *bp) load_rv2p_fw(bp, text, rc /* == len */, RV2P_PROC2); /* Initialize the RX Processor. */ - cpu_reg.mode = BNX2_RXP_CPU_MODE; - cpu_reg.mode_value_halt = BNX2_RXP_CPU_MODE_SOFT_HALT; - cpu_reg.mode_value_sstep = BNX2_RXP_CPU_MODE_STEP_ENA; - cpu_reg.state = BNX2_RXP_CPU_STATE; - cpu_reg.state_value_clear = 0xffffff; - cpu_reg.gpr0 = BNX2_RXP_CPU_REG_FILE; - cpu_reg.evmask = BNX2_RXP_CPU_EVENT_MASK; - cpu_reg.pc = BNX2_RXP_CPU_PROGRAM_COUNTER; - cpu_reg.inst = BNX2_RXP_CPU_INSTRUCTION; - cpu_reg.bp = BNX2_RXP_CPU_HW_BREAKPOINT; - cpu_reg.spad_base = BNX2_RXP_SCRATCH; - cpu_reg.mips_view_base = 0x8000000; - if (CHIP_NUM(bp) == CHIP_NUM_5709) fw = &bnx2_rxp_fw_09; else fw = &bnx2_rxp_fw_06; fw->text = text; - rc = load_cpu_fw(bp, &cpu_reg, fw); + rc = load_cpu_fw(bp, &cpu_reg_rxp, fw); if (rc) goto init_cpu_err; /* Initialize the TX Processor. */ - cpu_reg.mode = BNX2_TXP_CPU_MODE; - cpu_reg.mode_value_halt = BNX2_TXP_CPU_MODE_SOFT_HALT; - cpu_reg.mode_value_sstep = BNX2_TXP_CPU_MODE_STEP_ENA; - cpu_reg.state = BNX2_TXP_CPU_STATE; - cpu_reg.state_value_clear = 0xffffff; - cpu_reg.gpr0 = BNX2_TXP_CPU_REG_FILE; - cpu_reg.evmask = BNX2_TXP_CPU_EVENT_MASK; - cpu_reg.pc = BNX2_TXP_CPU_PROGRAM_COUNTER; - cpu_reg.inst = BNX2_TXP_CPU_INSTRUCTION; - cpu_reg.bp = BNX2_TXP_CPU_HW_BREAKPOINT; - cpu_reg.spad_base = BNX2_TXP_SCRATCH; - cpu_reg.mips_view_base = 0x8000000; - if (CHIP_NUM(bp) == CHIP_NUM_5709) fw = &bnx2_txp_fw_09; else fw = &bnx2_txp_fw_06; fw->text = text; - rc = load_cpu_fw(bp, &cpu_reg, fw); + rc = load_cpu_fw(bp, &cpu_reg_txp, fw); if (rc) goto init_cpu_err; /* Initialize the TX Patch-up Processor. */ - cpu_reg.mode = BNX2_TPAT_CPU_MODE; - cpu_reg.mode_value_halt = BNX2_TPAT_CPU_MODE_SOFT_HALT; - cpu_reg.mode_value_sstep = BNX2_TPAT_CPU_MODE_STEP_ENA; - cpu_reg.state = BNX2_TPAT_CPU_STATE; - cpu_reg.state_value_clear = 0xffffff; - cpu_reg.gpr0 = BNX2_TPAT_CPU_REG_FILE; - cpu_reg.evmask = BNX2_TPAT_CPU_EVENT_MASK; - cpu_reg.pc = BNX2_TPAT_CPU_PROGRAM_COUNTER; - cpu_reg.inst = BNX2_TPAT_CPU_INSTRUCTION; - cpu_reg.bp = BNX2_TPAT_CPU_HW_BREAKPOINT; - cpu_reg.spad_base = BNX2_TPAT_SCRATCH; - cpu_reg.mips_view_base = 0x8000000; - if (CHIP_NUM(bp) == CHIP_NUM_5709) fw = &bnx2_tpat_fw_09; else fw = &bnx2_tpat_fw_06; fw->text = text; - rc = load_cpu_fw(bp, &cpu_reg, fw); + rc = load_cpu_fw(bp, &cpu_reg_tpat, fw); if (rc) goto init_cpu_err; /* Initialize the Completion Processor. */ - cpu_reg.mode = BNX2_COM_CPU_MODE; - cpu_reg.mode_value_halt = BNX2_COM_CPU_MODE_SOFT_HALT; - cpu_reg.mode_value_sstep = BNX2_COM_CPU_MODE_STEP_ENA; - cpu_reg.state = BNX2_COM_CPU_STATE; - cpu_reg.state_value_clear = 0xffffff; - cpu_reg.gpr0 = BNX2_COM_CPU_REG_FILE; - cpu_reg.evmask = BNX2_COM_CPU_EVENT_MASK; - cpu_reg.pc = BNX2_COM_CPU_PROGRAM_COUNTER; - cpu_reg.inst = BNX2_COM_CPU_INSTRUCTION; - cpu_reg.bp = BNX2_COM_CPU_HW_BREAKPOINT; - cpu_reg.spad_base = BNX2_COM_SCRATCH; - cpu_reg.mips_view_base = 0x8000000; - if (CHIP_NUM(bp) == CHIP_NUM_5709) fw = &bnx2_com_fw_09; else fw = &bnx2_com_fw_06; fw->text = text; - rc = load_cpu_fw(bp, &cpu_reg, fw); + rc = load_cpu_fw(bp, &cpu_reg_com, fw); if (rc) goto init_cpu_err; /* Initialize the Command Processor. */ - cpu_reg.mode = BNX2_CP_CPU_MODE; - cpu_reg.mode_value_halt = BNX2_CP_CPU_MODE_SOFT_HALT; - cpu_reg.mode_value_sstep = BNX2_CP_CPU_MODE_STEP_ENA; - cpu_reg.state = BNX2_CP_CPU_STATE; - cpu_reg.state_value_clear = 0xffffff; - cpu_reg.gpr0 = BNX2_CP_CPU_REG_FILE; - cpu_reg.evmask = BNX2_CP_CPU_EVENT_MASK; - cpu_reg.pc = BNX2_CP_CPU_PROGRAM_COUNTER; - cpu_reg.inst = BNX2_CP_CPU_INSTRUCTION; - cpu_reg.bp = BNX2_CP_CPU_HW_BREAKPOINT; - cpu_reg.spad_base = BNX2_CP_SCRATCH; - cpu_reg.mips_view_base = 0x8000000; - if (CHIP_NUM(bp) == CHIP_NUM_5709) fw = &bnx2_cp_fw_09; else fw = &bnx2_cp_fw_06; fw->text = text; - rc = load_cpu_fw(bp, &cpu_reg, fw); + rc = load_cpu_fw(bp, &cpu_reg_cp, fw); init_cpu_err: vfree(text); diff --git a/drivers/net/bnx2_fw.h b/drivers/net/bnx2_fw.h index 3b839d4626f..e4b1de43556 100644 --- a/drivers/net/bnx2_fw.h +++ b/drivers/net/bnx2_fw.h @@ -886,6 +886,23 @@ static struct fw_info bnx2_com_fw_06 = { .rodata = bnx2_COM_b06FwRodata, }; +/* Initialized Values for the Completion Processor. */ +static const struct cpu_reg cpu_reg_com = { + .mode = BNX2_COM_CPU_MODE, + .mode_value_halt = BNX2_COM_CPU_MODE_SOFT_HALT, + .mode_value_sstep = BNX2_COM_CPU_MODE_STEP_ENA, + .state = BNX2_COM_CPU_STATE, + .state_value_clear = 0xffffff, + .gpr0 = BNX2_COM_CPU_REG_FILE, + .evmask = BNX2_COM_CPU_EVENT_MASK, + .pc = BNX2_COM_CPU_PROGRAM_COUNTER, + .inst = BNX2_COM_CPU_INSTRUCTION, + .bp = BNX2_COM_CPU_HW_BREAKPOINT, + .spad_base = BNX2_COM_SCRATCH, + .mips_view_base = 0x8000000, +}; + + static u8 bnx2_CP_b06FwText[] = { 0x9d, 0xbc, 0x0d, 0x78, 0x13, 0xe7, 0x99, 0x2e, 0x7c, 0xcf, 0x48, 0xb2, 0x65, 0x5b, 0xb6, 0xc7, 0xb6, 0x0c, 0x22, 0x65, 0x41, 0x83, 0x47, 0x20, @@ -2167,6 +2184,22 @@ static struct fw_info bnx2_cp_fw_06 = { .rodata = bnx2_CP_b06FwRodata, }; +/* Initialized Values the Command Processor. */ +static const struct cpu_reg cpu_reg_cp = { + .mode = BNX2_CP_CPU_MODE, + .mode_value_halt = BNX2_CP_CPU_MODE_SOFT_HALT, + .mode_value_sstep = BNX2_CP_CPU_MODE_STEP_ENA, + .state = BNX2_CP_CPU_STATE, + .state_value_clear = 0xffffff, + .gpr0 = BNX2_CP_CPU_REG_FILE, + .evmask = BNX2_CP_CPU_EVENT_MASK, + .pc = BNX2_CP_CPU_PROGRAM_COUNTER, + .inst = BNX2_CP_CPU_INSTRUCTION, + .bp = BNX2_CP_CPU_HW_BREAKPOINT, + .spad_base = BNX2_CP_SCRATCH, + .mips_view_base = 0x8000000, +}; + static u8 bnx2_RXP_b06FwText[] = { 0xec, 0x5b, 0x5d, 0x70, 0x5c, 0xd7, 0x5d, 0xff, 0xdf, 0xb3, 0x2b, 0x69, 0x2d, 0x4b, 0xf2, 0x95, 0xbc, 0x71, 0x56, 0xa9, 0x92, 0xec, 0x5a, 0x57, @@ -2946,6 +2979,22 @@ static struct fw_info bnx2_rxp_fw_06 = { .rodata = bnx2_RXP_b06FwRodata, }; +/* Initialized Values for the RX Processor. */ +static const struct cpu_reg cpu_reg_rxp = { + .mode = BNX2_RXP_CPU_MODE, + .mode_value_halt = BNX2_RXP_CPU_MODE_SOFT_HALT, + .mode_value_sstep = BNX2_RXP_CPU_MODE_STEP_ENA, + .state = BNX2_RXP_CPU_STATE, + .state_value_clear = 0xffffff, + .gpr0 = BNX2_RXP_CPU_REG_FILE, + .evmask = BNX2_RXP_CPU_EVENT_MASK, + .pc = BNX2_RXP_CPU_PROGRAM_COUNTER, + .inst = BNX2_RXP_CPU_INSTRUCTION, + .bp = BNX2_RXP_CPU_HW_BREAKPOINT, + .spad_base = BNX2_RXP_SCRATCH, + .mips_view_base = 0x8000000, +}; + static u8 bnx2_rv2p_proc1[] = { /* Date: 12/07/2007 15:02 */ 0xd5, 0x56, 0x41, 0x6b, 0x13, 0x51, 0x10, 0x9e, 0xdd, 0x6c, 0xbb, 0xdb, @@ -3651,6 +3700,22 @@ static struct fw_info bnx2_tpat_fw_06 = { .rodata = bnx2_TPAT_b06FwRodata, }; +/* Initialized Values for the TX Patch-up Processor. */ +static const struct cpu_reg cpu_reg_tpat = { + .mode = BNX2_TPAT_CPU_MODE, + .mode_value_halt = BNX2_TPAT_CPU_MODE_SOFT_HALT, + .mode_value_sstep = BNX2_TPAT_CPU_MODE_STEP_ENA, + .state = BNX2_TPAT_CPU_STATE, + .state_value_clear = 0xffffff, + .gpr0 = BNX2_TPAT_CPU_REG_FILE, + .evmask = BNX2_TPAT_CPU_EVENT_MASK, + .pc = BNX2_TPAT_CPU_PROGRAM_COUNTER, + .inst = BNX2_TPAT_CPU_INSTRUCTION, + .bp = BNX2_TPAT_CPU_HW_BREAKPOINT, + .spad_base = BNX2_TPAT_SCRATCH, + .mips_view_base = 0x8000000, +}; + static u8 bnx2_TXP_b06FwText[] = { 0xad, 0x7b, 0x7f, 0x70, 0x9b, 0x75, 0x7a, 0xe7, 0xe7, 0xd5, 0x0f, 0x5b, 0xb2, 0x65, 0x59, 0x0e, 0x4a, 0x90, 0x77, 0xbd, 0x8d, 0x5e, 0xf4, 0xca, @@ -4531,3 +4596,18 @@ static struct fw_info bnx2_txp_fw_06 = { .rodata = bnx2_TXP_b06FwRodata, }; +/* Initialized Values for the TX Processor. */ +static const struct cpu_reg cpu_reg_txp = { + .mode = BNX2_TXP_CPU_MODE, + .mode_value_halt = BNX2_TXP_CPU_MODE_SOFT_HALT, + .mode_value_sstep = BNX2_TXP_CPU_MODE_STEP_ENA, + .state = BNX2_TXP_CPU_STATE, + .state_value_clear = 0xffffff, + .gpr0 = BNX2_TXP_CPU_REG_FILE, + .evmask = BNX2_TXP_CPU_EVENT_MASK, + .pc = BNX2_TXP_CPU_PROGRAM_COUNTER, + .inst = BNX2_TXP_CPU_INSTRUCTION, + .bp = BNX2_TXP_CPU_HW_BREAKPOINT, + .spad_base = BNX2_TXP_SCRATCH, + .mips_view_base = 0x8000000, +}; -- cgit v1.2.3-70-g09d2 From 236ae64063faf7d3398b4f9a889421b0d27a69d2 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 16 May 2008 22:20:59 -0700 Subject: bnx2: Update version to 1.7.6. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index e1787a1e1e7..b32d22762b9 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -56,8 +56,8 @@ #define DRV_MODULE_NAME "bnx2" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "1.7.5" -#define DRV_MODULE_RELDATE "April 29, 2008" +#define DRV_MODULE_VERSION "1.7.6" +#define DRV_MODULE_RELDATE "May 16, 2008" #define RUN_AT(x) (jiffies + (x)) -- cgit v1.2.3-70-g09d2 From 3db633ee352bfe20d4a2b0c3c8a46ce31a6c7149 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Thu, 15 May 2008 09:21:02 -0600 Subject: i2c: cdev lock_kernel() pushdown Signed-off-by: Jonathan Corbet --- drivers/i2c/i2c-dev.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index d34c14c81c2..006a5857256 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -34,6 +34,7 @@ #include #include #include +#include #include static struct i2c_driver i2cdev_driver; @@ -441,14 +442,20 @@ static int i2cdev_open(struct inode *inode, struct file *file) struct i2c_client *client; struct i2c_adapter *adap; struct i2c_dev *i2c_dev; + int ret = 0; + lock_kernel(); i2c_dev = i2c_dev_get_by_minor(minor); - if (!i2c_dev) - return -ENODEV; + if (!i2c_dev) { + ret = -ENODEV; + goto out; + } adap = i2c_get_adapter(i2c_dev->adap->nr); - if (!adap) - return -ENODEV; + if (!adap) { + ret = -ENODEV; + goto out; + } /* This creates an anonymous i2c_client, which may later be * pointed to some address using I2C_SLAVE or I2C_SLAVE_FORCE. @@ -460,7 +467,8 @@ static int i2cdev_open(struct inode *inode, struct file *file) client = kzalloc(sizeof(*client), GFP_KERNEL); if (!client) { i2c_put_adapter(adap); - return -ENOMEM; + ret = -ENOMEM; + goto out; } snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr); client->driver = &i2cdev_driver; @@ -468,7 +476,9 @@ static int i2cdev_open(struct inode *inode, struct file *file) client->adapter = adap; file->private_data = client; - return 0; +out: + unlock_kernel(); + return ret; } static int i2cdev_release(struct inode *inode, struct file *file) -- cgit v1.2.3-70-g09d2 From 0911810755fc9f15659cc3cb43912633b90027a0 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Thu, 15 May 2008 09:21:33 -0600 Subject: cosa: cdev lock_kernel() pushdown Signed-off-by: Jonathan Corbet --- drivers/net/wan/cosa.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c index b0fce1387ea..5827324e9d9 100644 --- a/drivers/net/wan/cosa.c +++ b/drivers/net/wan/cosa.c @@ -92,6 +92,7 @@ #include #include #include +#include #undef COSA_SLOW_IO /* for testing purposes only */ @@ -970,15 +971,21 @@ static int cosa_open(struct inode *inode, struct file *file) struct channel_data *chan; unsigned long flags; int n; + int ret = 0; + lock_kernel(); if ((n=iminor(file->f_path.dentry->d_inode)>>CARD_MINOR_BITS) - >= nr_cards) - return -ENODEV; + >= nr_cards) { + ret = -ENODEV; + goto out; + } cosa = cosa_cards+n; if ((n=iminor(file->f_path.dentry->d_inode) - & ((1<= cosa->nchannels) - return -ENODEV; + & ((1<= cosa->nchannels) { + ret = -ENODEV; + goto out; + } chan = cosa->chan + n; file->private_data = chan; @@ -987,7 +994,8 @@ static int cosa_open(struct inode *inode, struct file *file) if (chan->usage < 0) { /* in netdev mode */ spin_unlock_irqrestore(&cosa->lock, flags); - return -EBUSY; + ret = -EBUSY; + goto out; } cosa->usage++; chan->usage++; @@ -996,7 +1004,9 @@ static int cosa_open(struct inode *inode, struct file *file) chan->setup_rx = chrdev_setup_rx; chan->rx_done = chrdev_rx_done; spin_unlock_irqrestore(&cosa->lock, flags); - return 0; +out: + unlock_kernel(); + return ret; } static int cosa_release(struct inode *inode, struct file *file) -- cgit v1.2.3-70-g09d2 From 0bec0bba7a507bdaf07312fcabdc00b5576abb32 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Thu, 15 May 2008 09:25:03 -0600 Subject: pcmcia: cdev lock_kernel() pushdown Signed-off-by: Jonathan Corbet --- drivers/pcmcia/pcmcia_ioctl.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c index 5f186abca10..138396ef5be 100644 --- a/drivers/pcmcia/pcmcia_ioctl.c +++ b/drivers/pcmcia/pcmcia_ioctl.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #define IN_CARD_SERVICES @@ -397,20 +398,27 @@ static int ds_open(struct inode *inode, struct file *file) struct pcmcia_socket *s; user_info_t *user; static int warning_printed = 0; + int ret = 0; ds_dbg(0, "ds_open(socket %d)\n", i); + lock_kernel(); s = pcmcia_get_socket_by_nr(i); - if (!s) - return -ENODEV; + if (!s) { + ret = -ENODEV; + goto out; + } s = pcmcia_get_socket(s); - if (!s) - return -ENODEV; + if (!s) { + ret = -ENODEV; + goto out; + } if ((file->f_flags & O_ACCMODE) != O_RDONLY) { if (s->pcmcia_state.busy) { pcmcia_put_socket(s); - return -EBUSY; + ret = -EBUSY; + goto out; } else s->pcmcia_state.busy = 1; @@ -419,7 +427,8 @@ static int ds_open(struct inode *inode, struct file *file) user = kmalloc(sizeof(user_info_t), GFP_KERNEL); if (!user) { pcmcia_put_socket(s); - return -ENOMEM; + ret = -ENOMEM; + goto out; } user->event_tail = user->event_head = 0; user->next = s->user; @@ -441,7 +450,9 @@ static int ds_open(struct inode *inode, struct file *file) if (s->pcmcia_state.present) queue_event(user, CS_EVENT_CARD_INSERTION); - return 0; +out: + unlock_kernel(); + return ret; } /* ds_open */ /*====================================================================*/ -- cgit v1.2.3-70-g09d2 From 82524746c27fa418c250a56dd7606b9d3fc79826 Mon Sep 17 00:00:00 2001 From: Franck Bui-Huu Date: Mon, 12 May 2008 21:21:05 +0200 Subject: rcu: split list.h and move rcu-protected lists into rculist.h Move rcu-protected lists from list.h into a new header file rculist.h. This is done because list are a very used primitive structure all over the kernel and it's currently impossible to include other header files in this list.h without creating some circular dependencies. For example, list.h implements rcu-protected list and uses rcu_dereference() without including rcupdate.h. It actually compiles because users of rcu_dereference() are macros. Others RCU functions could be used too but aren't probably because of this. Therefore this patch creates rculist.h which includes rcupdates without to many changes/troubles. Signed-off-by: Franck Bui-Huu Acked-by: Paul E. McKenney Acked-by: Josh Triplett Signed-off-by: Andrew Morton Signed-off-by: Ingo Molnar --- arch/ia64/sn/kernel/irq.c | 1 + crypto/async_tx/async_tx.c | 1 + drivers/infiniband/hw/ipath/ipath_verbs.c | 1 + drivers/infiniband/hw/ipath/ipath_verbs_mcast.c | 3 +- drivers/net/macvlan.c | 2 +- include/linux/dcache.h | 1 + include/linux/list.h | 367 ---------------------- include/linux/rculist.h | 396 ++++++++++++++++++++++++ kernel/pid.c | 1 + lib/textsearch.c | 1 + net/802/psnap.c | 1 + net/8021q/vlan.c | 1 + net/bridge/br_fdb.c | 1 + net/bridge/br_stp.c | 1 + net/netlabel/netlabel_domainhash.c | 3 +- 15 files changed, 409 insertions(+), 372 deletions(-) create mode 100644 include/linux/rculist.h (limited to 'drivers') diff --git a/arch/ia64/sn/kernel/irq.c b/arch/ia64/sn/kernel/irq.c index 53351c3cd7b..96c31b4180c 100644 --- a/arch/ia64/sn/kernel/irq.c +++ b/arch/ia64/sn/kernel/irq.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/crypto/async_tx/async_tx.c b/crypto/async_tx/async_tx.c index c6e772fc5cc..095c798d317 100644 --- a/crypto/async_tx/async_tx.c +++ b/crypto/async_tx/async_tx.c @@ -23,6 +23,7 @@ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * */ +#include #include #include diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c index e0ec540042b..5d830d87ebc 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.c +++ b/drivers/infiniband/hw/ipath/ipath_verbs.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "ipath_kernel.h" #include "ipath_verbs.h" diff --git a/drivers/infiniband/hw/ipath/ipath_verbs_mcast.c b/drivers/infiniband/hw/ipath/ipath_verbs_mcast.c index 9e5abf9c309..d73e3223287 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs_mcast.c +++ b/drivers/infiniband/hw/ipath/ipath_verbs_mcast.c @@ -31,8 +31,7 @@ * SOFTWARE. */ -#include -#include +#include #include "ipath_verbs.h" diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index c36a03ae9bf..860d75d81f8 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 2a6639407c8..1f5cebf10a2 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -3,6 +3,7 @@ #include #include +#include #include #include #include diff --git a/include/linux/list.h b/include/linux/list.h index 08cf4f65188..139ec41d9c2 100644 --- a/include/linux/list.h +++ b/include/linux/list.h @@ -84,65 +84,6 @@ static inline void list_add_tail(struct list_head *new, struct list_head *head) __list_add(new, head->prev, head); } -/* - * Insert a new entry between two known consecutive entries. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_add_rcu(struct list_head * new, - struct list_head * prev, struct list_head * next) -{ - new->next = next; - new->prev = prev; - smp_wmb(); - next->prev = new; - prev->next = new; -} - -/** - * list_add_rcu - add a new entry to rcu-protected list - * @new: new entry to be added - * @head: list head to add it after - * - * Insert a new entry after the specified head. - * This is good for implementing stacks. - * - * The caller must take whatever precautions are necessary - * (such as holding appropriate locks) to avoid racing - * with another list-mutation primitive, such as list_add_rcu() - * or list_del_rcu(), running on this same list. - * However, it is perfectly legal to run concurrently with - * the _rcu list-traversal primitives, such as - * list_for_each_entry_rcu(). - */ -static inline void list_add_rcu(struct list_head *new, struct list_head *head) -{ - __list_add_rcu(new, head, head->next); -} - -/** - * list_add_tail_rcu - add a new entry to rcu-protected list - * @new: new entry to be added - * @head: list head to add it before - * - * Insert a new entry before the specified head. - * This is useful for implementing queues. - * - * The caller must take whatever precautions are necessary - * (such as holding appropriate locks) to avoid racing - * with another list-mutation primitive, such as list_add_tail_rcu() - * or list_del_rcu(), running on this same list. - * However, it is perfectly legal to run concurrently with - * the _rcu list-traversal primitives, such as - * list_for_each_entry_rcu(). - */ -static inline void list_add_tail_rcu(struct list_head *new, - struct list_head *head) -{ - __list_add_rcu(new, head->prev, head); -} - /* * Delete a list entry by making the prev/next entries * point to each other. @@ -173,36 +114,6 @@ static inline void list_del(struct list_head *entry) extern void list_del(struct list_head *entry); #endif -/** - * list_del_rcu - deletes entry from list without re-initialization - * @entry: the element to delete from the list. - * - * Note: list_empty() on entry does not return true after this, - * the entry is in an undefined state. It is useful for RCU based - * lockfree traversal. - * - * In particular, it means that we can not poison the forward - * pointers that may still be used for walking the list. - * - * The caller must take whatever precautions are necessary - * (such as holding appropriate locks) to avoid racing - * with another list-mutation primitive, such as list_del_rcu() - * or list_add_rcu(), running on this same list. - * However, it is perfectly legal to run concurrently with - * the _rcu list-traversal primitives, such as - * list_for_each_entry_rcu(). - * - * Note that the caller is not permitted to immediately free - * the newly deleted entry. Instead, either synchronize_rcu() - * or call_rcu() must be used to defer freeing until an RCU - * grace period has elapsed. - */ -static inline void list_del_rcu(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - entry->prev = LIST_POISON2; -} - /** * list_replace - replace old entry by new one * @old : the element to be replaced @@ -226,25 +137,6 @@ static inline void list_replace_init(struct list_head *old, INIT_LIST_HEAD(old); } -/** - * list_replace_rcu - replace old entry by new one - * @old : the element to be replaced - * @new : the new element to insert - * - * The @old entry will be replaced with the @new entry atomically. - * Note: @old should not be empty. - */ -static inline void list_replace_rcu(struct list_head *old, - struct list_head *new) -{ - new->next = old->next; - new->prev = old->prev; - smp_wmb(); - new->next->prev = new; - new->prev->next = new; - old->prev = LIST_POISON2; -} - /** * list_del_init - deletes entry from list and reinitialize it. * @entry: the element to delete from the list. @@ -368,62 +260,6 @@ static inline void list_splice_init(struct list_head *list, } } -/** - * list_splice_init_rcu - splice an RCU-protected list into an existing list. - * @list: the RCU-protected list to splice - * @head: the place in the list to splice the first list into - * @sync: function to sync: synchronize_rcu(), synchronize_sched(), ... - * - * @head can be RCU-read traversed concurrently with this function. - * - * Note that this function blocks. - * - * Important note: the caller must take whatever action is necessary to - * prevent any other updates to @head. In principle, it is possible - * to modify the list as soon as sync() begins execution. - * If this sort of thing becomes necessary, an alternative version - * based on call_rcu() could be created. But only if -really- - * needed -- there is no shortage of RCU API members. - */ -static inline void list_splice_init_rcu(struct list_head *list, - struct list_head *head, - void (*sync)(void)) -{ - struct list_head *first = list->next; - struct list_head *last = list->prev; - struct list_head *at = head->next; - - if (list_empty(head)) - return; - - /* "first" and "last" tracking list, so initialize it. */ - - INIT_LIST_HEAD(list); - - /* - * At this point, the list body still points to the source list. - * Wait for any readers to finish using the list before splicing - * the list body into the new list. Any new readers will see - * an empty list. - */ - - sync(); - - /* - * Readers are finished with the source list, so perform splice. - * The order is important if the new list is global and accessible - * to concurrent RCU readers. Note that RCU readers are not - * permitted to traverse the prev pointers without excluding - * this function. - */ - - last->next = at; - smp_wmb(); - head->next = first; - first->prev = head; - at->prev = last; -} - /** * list_entry - get the struct for this entry * @ptr: the &struct list_head pointer. @@ -629,57 +465,6 @@ static inline void list_splice_init_rcu(struct list_head *list, &pos->member != (head); \ pos = n, n = list_entry(n->member.prev, typeof(*n), member)) -/** - * list_for_each_rcu - iterate over an rcu-protected list - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - * - * This list-traversal primitive may safely run concurrently with - * the _rcu list-mutation primitives such as list_add_rcu() - * as long as the traversal is guarded by rcu_read_lock(). - */ -#define list_for_each_rcu(pos, head) \ - for (pos = rcu_dereference((head)->next); \ - prefetch(pos->next), pos != (head); \ - pos = rcu_dereference(pos->next)) - -#define __list_for_each_rcu(pos, head) \ - for (pos = rcu_dereference((head)->next); \ - pos != (head); \ - pos = rcu_dereference(pos->next)) - -/** - * list_for_each_entry_rcu - iterate over rcu list of given type - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * This list-traversal primitive may safely run concurrently with - * the _rcu list-mutation primitives such as list_add_rcu() - * as long as the traversal is guarded by rcu_read_lock(). - */ -#define list_for_each_entry_rcu(pos, head, member) \ - for (pos = list_entry(rcu_dereference((head)->next), typeof(*pos), member); \ - prefetch(pos->member.next), &pos->member != (head); \ - pos = list_entry(rcu_dereference(pos->member.next), typeof(*pos), member)) - - -/** - * list_for_each_continue_rcu - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - * - * Iterate over an rcu-protected list, continuing after current point. - * - * This list-traversal primitive may safely run concurrently with - * the _rcu list-mutation primitives such as list_add_rcu() - * as long as the traversal is guarded by rcu_read_lock(). - */ -#define list_for_each_continue_rcu(pos, head) \ - for ((pos) = rcu_dereference((pos)->next); \ - prefetch((pos)->next), (pos) != (head); \ - (pos) = rcu_dereference((pos)->next)) - /* * Double linked lists with a single pointer list head. * Mostly useful for hash tables where the two pointer list head is @@ -730,31 +515,6 @@ static inline void hlist_del(struct hlist_node *n) n->pprev = LIST_POISON2; } -/** - * hlist_del_rcu - deletes entry from hash list without re-initialization - * @n: the element to delete from the hash list. - * - * Note: list_unhashed() on entry does not return true after this, - * the entry is in an undefined state. It is useful for RCU based - * lockfree traversal. - * - * In particular, it means that we can not poison the forward - * pointers that may still be used for walking the hash list. - * - * The caller must take whatever precautions are necessary - * (such as holding appropriate locks) to avoid racing - * with another list-mutation primitive, such as hlist_add_head_rcu() - * or hlist_del_rcu(), running on this same list. - * However, it is perfectly legal to run concurrently with - * the _rcu list-traversal primitives, such as - * hlist_for_each_entry(). - */ -static inline void hlist_del_rcu(struct hlist_node *n) -{ - __hlist_del(n); - n->pprev = LIST_POISON2; -} - static inline void hlist_del_init(struct hlist_node *n) { if (!hlist_unhashed(n)) { @@ -763,27 +523,6 @@ static inline void hlist_del_init(struct hlist_node *n) } } -/** - * hlist_replace_rcu - replace old entry by new one - * @old : the element to be replaced - * @new : the new element to insert - * - * The @old entry will be replaced with the @new entry atomically. - */ -static inline void hlist_replace_rcu(struct hlist_node *old, - struct hlist_node *new) -{ - struct hlist_node *next = old->next; - - new->next = next; - new->pprev = old->pprev; - smp_wmb(); - if (next) - new->next->pprev = &new->next; - *new->pprev = new; - old->pprev = LIST_POISON2; -} - static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) { struct hlist_node *first = h->first; @@ -794,38 +533,6 @@ static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) n->pprev = &h->first; } - -/** - * hlist_add_head_rcu - * @n: the element to add to the hash list. - * @h: the list to add to. - * - * Description: - * Adds the specified element to the specified hlist, - * while permitting racing traversals. - * - * The caller must take whatever precautions are necessary - * (such as holding appropriate locks) to avoid racing - * with another list-mutation primitive, such as hlist_add_head_rcu() - * or hlist_del_rcu(), running on this same list. - * However, it is perfectly legal to run concurrently with - * the _rcu list-traversal primitives, such as - * hlist_for_each_entry_rcu(), used to prevent memory-consistency - * problems on Alpha CPUs. Regardless of the type of CPU, the - * list-traversal primitive must be guarded by rcu_read_lock(). - */ -static inline void hlist_add_head_rcu(struct hlist_node *n, - struct hlist_head *h) -{ - struct hlist_node *first = h->first; - n->next = first; - n->pprev = &h->first; - smp_wmb(); - if (first) - first->pprev = &n->next; - h->first = n; -} - /* next must be != NULL */ static inline void hlist_add_before(struct hlist_node *n, struct hlist_node *next) @@ -847,63 +554,6 @@ static inline void hlist_add_after(struct hlist_node *n, next->next->pprev = &next->next; } -/** - * hlist_add_before_rcu - * @n: the new element to add to the hash list. - * @next: the existing element to add the new element before. - * - * Description: - * Adds the specified element to the specified hlist - * before the specified node while permitting racing traversals. - * - * The caller must take whatever precautions are necessary - * (such as holding appropriate locks) to avoid racing - * with another list-mutation primitive, such as hlist_add_head_rcu() - * or hlist_del_rcu(), running on this same list. - * However, it is perfectly legal to run concurrently with - * the _rcu list-traversal primitives, such as - * hlist_for_each_entry_rcu(), used to prevent memory-consistency - * problems on Alpha CPUs. - */ -static inline void hlist_add_before_rcu(struct hlist_node *n, - struct hlist_node *next) -{ - n->pprev = next->pprev; - n->next = next; - smp_wmb(); - next->pprev = &n->next; - *(n->pprev) = n; -} - -/** - * hlist_add_after_rcu - * @prev: the existing element to add the new element after. - * @n: the new element to add to the hash list. - * - * Description: - * Adds the specified element to the specified hlist - * after the specified node while permitting racing traversals. - * - * The caller must take whatever precautions are necessary - * (such as holding appropriate locks) to avoid racing - * with another list-mutation primitive, such as hlist_add_head_rcu() - * or hlist_del_rcu(), running on this same list. - * However, it is perfectly legal to run concurrently with - * the _rcu list-traversal primitives, such as - * hlist_for_each_entry_rcu(), used to prevent memory-consistency - * problems on Alpha CPUs. - */ -static inline void hlist_add_after_rcu(struct hlist_node *prev, - struct hlist_node *n) -{ - n->next = prev->next; - n->pprev = &prev->next; - smp_wmb(); - prev->next = n; - if (n->next) - n->next->pprev = &n->next; -} - #define hlist_entry(ptr, type, member) container_of(ptr,type,member) #define hlist_for_each(pos, head) \ @@ -964,21 +614,4 @@ static inline void hlist_add_after_rcu(struct hlist_node *prev, ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ pos = n) -/** - * hlist_for_each_entry_rcu - iterate over rcu list of given type - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_node to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the hlist_node within the struct. - * - * This list-traversal primitive may safely run concurrently with - * the _rcu list-mutation primitives such as hlist_add_head_rcu() - * as long as the traversal is guarded by rcu_read_lock(). - */ -#define hlist_for_each_entry_rcu(tpos, pos, head, member) \ - for (pos = rcu_dereference((head)->first); \ - pos && ({ prefetch(pos->next); 1;}) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = rcu_dereference(pos->next)) - #endif diff --git a/include/linux/rculist.h b/include/linux/rculist.h new file mode 100644 index 00000000000..aa9b3eb1568 --- /dev/null +++ b/include/linux/rculist.h @@ -0,0 +1,396 @@ +#ifndef _LINUX_RCULIST_H +#define _LINUX_RCULIST_H + +#ifdef __KERNEL__ + +/* + * RCU-protected list version + */ +#include + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add_rcu(struct list_head *new, + struct list_head *prev, struct list_head *next) +{ + new->next = next; + new->prev = prev; + smp_wmb(); + next->prev = new; + prev->next = new; +} + +/** + * list_add_rcu - add a new entry to rcu-protected list + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + * + * The caller must take whatever precautions are necessary + * (such as holding appropriate locks) to avoid racing + * with another list-mutation primitive, such as list_add_rcu() + * or list_del_rcu(), running on this same list. + * However, it is perfectly legal to run concurrently with + * the _rcu list-traversal primitives, such as + * list_for_each_entry_rcu(). + */ +static inline void list_add_rcu(struct list_head *new, struct list_head *head) +{ + __list_add_rcu(new, head, head->next); +} + +/** + * list_add_tail_rcu - add a new entry to rcu-protected list + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + * + * The caller must take whatever precautions are necessary + * (such as holding appropriate locks) to avoid racing + * with another list-mutation primitive, such as list_add_tail_rcu() + * or list_del_rcu(), running on this same list. + * However, it is perfectly legal to run concurrently with + * the _rcu list-traversal primitives, such as + * list_for_each_entry_rcu(). + */ +static inline void list_add_tail_rcu(struct list_head *new, + struct list_head *head) +{ + __list_add_rcu(new, head->prev, head); +} + +/** + * list_del_rcu - deletes entry from list without re-initialization + * @entry: the element to delete from the list. + * + * Note: list_empty() on entry does not return true after this, + * the entry is in an undefined state. It is useful for RCU based + * lockfree traversal. + * + * In particular, it means that we can not poison the forward + * pointers that may still be used for walking the list. + * + * The caller must take whatever precautions are necessary + * (such as holding appropriate locks) to avoid racing + * with another list-mutation primitive, such as list_del_rcu() + * or list_add_rcu(), running on this same list. + * However, it is perfectly legal to run concurrently with + * the _rcu list-traversal primitives, such as + * list_for_each_entry_rcu(). + * + * Note that the caller is not permitted to immediately free + * the newly deleted entry. Instead, either synchronize_rcu() + * or call_rcu() must be used to defer freeing until an RCU + * grace period has elapsed. + */ +static inline void list_del_rcu(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->prev = LIST_POISON2; +} + +/** + * list_replace_rcu - replace old entry by new one + * @old : the element to be replaced + * @new : the new element to insert + * + * The @old entry will be replaced with the @new entry atomically. + * Note: @old should not be empty. + */ +static inline void list_replace_rcu(struct list_head *old, + struct list_head *new) +{ + new->next = old->next; + new->prev = old->prev; + smp_wmb(); + new->next->prev = new; + new->prev->next = new; + old->prev = LIST_POISON2; +} + +/** + * list_splice_init_rcu - splice an RCU-protected list into an existing list. + * @list: the RCU-protected list to splice + * @head: the place in the list to splice the first list into + * @sync: function to sync: synchronize_rcu(), synchronize_sched(), ... + * + * @head can be RCU-read traversed concurrently with this function. + * + * Note that this function blocks. + * + * Important note: the caller must take whatever action is necessary to + * prevent any other updates to @head. In principle, it is possible + * to modify the list as soon as sync() begins execution. + * If this sort of thing becomes necessary, an alternative version + * based on call_rcu() could be created. But only if -really- + * needed -- there is no shortage of RCU API members. + */ +static inline void list_splice_init_rcu(struct list_head *list, + struct list_head *head, + void (*sync)(void)) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + struct list_head *at = head->next; + + if (list_empty(head)) + return; + + /* "first" and "last" tracking list, so initialize it. */ + + INIT_LIST_HEAD(list); + + /* + * At this point, the list body still points to the source list. + * Wait for any readers to finish using the list before splicing + * the list body into the new list. Any new readers will see + * an empty list. + */ + + sync(); + + /* + * Readers are finished with the source list, so perform splice. + * The order is important if the new list is global and accessible + * to concurrent RCU readers. Note that RCU readers are not + * permitted to traverse the prev pointers without excluding + * this function. + */ + + last->next = at; + smp_wmb(); + head->next = first; + first->prev = head; + at->prev = last; +} + +/** + * list_for_each_rcu - iterate over an rcu-protected list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + * + * This list-traversal primitive may safely run concurrently with + * the _rcu list-mutation primitives such as list_add_rcu() + * as long as the traversal is guarded by rcu_read_lock(). + */ +#define list_for_each_rcu(pos, head) \ + for (pos = (head)->next; \ + prefetch(rcu_dereference(pos)->next), pos != (head); \ + pos = pos->next) + +#define __list_for_each_rcu(pos, head) \ + for (pos = (head)->next; \ + rcu_dereference(pos) != (head); \ + pos = pos->next) + +/** + * list_for_each_safe_rcu + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + * + * Iterate over an rcu-protected list, safe against removal of list entry. + * + * This list-traversal primitive may safely run concurrently with + * the _rcu list-mutation primitives such as list_add_rcu() + * as long as the traversal is guarded by rcu_read_lock(). + */ +#define list_for_each_safe_rcu(pos, n, head) \ + for (pos = (head)->next; \ + n = rcu_dereference(pos)->next, pos != (head); \ + pos = n) + +/** + * list_for_each_entry_rcu - iterate over rcu list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * This list-traversal primitive may safely run concurrently with + * the _rcu list-mutation primitives such as list_add_rcu() + * as long as the traversal is guarded by rcu_read_lock(). + */ +#define list_for_each_entry_rcu(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member); \ + prefetch(rcu_dereference(pos)->member.next), \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + + +/** + * list_for_each_continue_rcu + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + * + * Iterate over an rcu-protected list, continuing after current point. + * + * This list-traversal primitive may safely run concurrently with + * the _rcu list-mutation primitives such as list_add_rcu() + * as long as the traversal is guarded by rcu_read_lock(). + */ +#define list_for_each_continue_rcu(pos, head) \ + for ((pos) = (pos)->next; \ + prefetch(rcu_dereference((pos))->next), (pos) != (head); \ + (pos) = (pos)->next) + +/** + * hlist_del_rcu - deletes entry from hash list without re-initialization + * @n: the element to delete from the hash list. + * + * Note: list_unhashed() on entry does not return true after this, + * the entry is in an undefined state. It is useful for RCU based + * lockfree traversal. + * + * In particular, it means that we can not poison the forward + * pointers that may still be used for walking the hash list. + * + * The caller must take whatever precautions are necessary + * (such as holding appropriate locks) to avoid racing + * with another list-mutation primitive, such as hlist_add_head_rcu() + * or hlist_del_rcu(), running on this same list. + * However, it is perfectly legal to run concurrently with + * the _rcu list-traversal primitives, such as + * hlist_for_each_entry(). + */ +static inline void hlist_del_rcu(struct hlist_node *n) +{ + __hlist_del(n); + n->pprev = LIST_POISON2; +} + +/** + * hlist_replace_rcu - replace old entry by new one + * @old : the element to be replaced + * @new : the new element to insert + * + * The @old entry will be replaced with the @new entry atomically. + */ +static inline void hlist_replace_rcu(struct hlist_node *old, + struct hlist_node *new) +{ + struct hlist_node *next = old->next; + + new->next = next; + new->pprev = old->pprev; + smp_wmb(); + if (next) + new->next->pprev = &new->next; + *new->pprev = new; + old->pprev = LIST_POISON2; +} + +/** + * hlist_add_head_rcu + * @n: the element to add to the hash list. + * @h: the list to add to. + * + * Description: + * Adds the specified element to the specified hlist, + * while permitting racing traversals. + * + * The caller must take whatever precautions are necessary + * (such as holding appropriate locks) to avoid racing + * with another list-mutation primitive, such as hlist_add_head_rcu() + * or hlist_del_rcu(), running on this same list. + * However, it is perfectly legal to run concurrently with + * the _rcu list-traversal primitives, such as + * hlist_for_each_entry_rcu(), used to prevent memory-consistency + * problems on Alpha CPUs. Regardless of the type of CPU, the + * list-traversal primitive must be guarded by rcu_read_lock(). + */ +static inline void hlist_add_head_rcu(struct hlist_node *n, + struct hlist_head *h) +{ + struct hlist_node *first = h->first; + n->next = first; + n->pprev = &h->first; + smp_wmb(); + if (first) + first->pprev = &n->next; + h->first = n; +} + +/** + * hlist_add_before_rcu + * @n: the new element to add to the hash list. + * @next: the existing element to add the new element before. + * + * Description: + * Adds the specified element to the specified hlist + * before the specified node while permitting racing traversals. + * + * The caller must take whatever precautions are necessary + * (such as holding appropriate locks) to avoid racing + * with another list-mutation primitive, such as hlist_add_head_rcu() + * or hlist_del_rcu(), running on this same list. + * However, it is perfectly legal to run concurrently with + * the _rcu list-traversal primitives, such as + * hlist_for_each_entry_rcu(), used to prevent memory-consistency + * problems on Alpha CPUs. + */ +static inline void hlist_add_before_rcu(struct hlist_node *n, + struct hlist_node *next) +{ + n->pprev = next->pprev; + n->next = next; + smp_wmb(); + next->pprev = &n->next; + *(n->pprev) = n; +} + +/** + * hlist_add_after_rcu + * @prev: the existing element to add the new element after. + * @n: the new element to add to the hash list. + * + * Description: + * Adds the specified element to the specified hlist + * after the specified node while permitting racing traversals. + * + * The caller must take whatever precautions are necessary + * (such as holding appropriate locks) to avoid racing + * with another list-mutation primitive, such as hlist_add_head_rcu() + * or hlist_del_rcu(), running on this same list. + * However, it is perfectly legal to run concurrently with + * the _rcu list-traversal primitives, such as + * hlist_for_each_entry_rcu(), used to prevent memory-consistency + * problems on Alpha CPUs. + */ +static inline void hlist_add_after_rcu(struct hlist_node *prev, + struct hlist_node *n) +{ + n->next = prev->next; + n->pprev = &prev->next; + smp_wmb(); + prev->next = n; + if (n->next) + n->next->pprev = &n->next; +} + +/** + * hlist_for_each_entry_rcu - iterate over rcu list of given type + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + * + * This list-traversal primitive may safely run concurrently with + * the _rcu list-mutation primitives such as hlist_add_head_rcu() + * as long as the traversal is guarded by rcu_read_lock(). + */ +#define hlist_for_each_entry_rcu(tpos, pos, head, member) \ + for (pos = (head)->first; \ + rcu_dereference(pos) && ({ prefetch(pos->next); 1; }) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; }); \ + pos = pos->next) + +#endif /* __KERNEL__ */ +#endif diff --git a/kernel/pid.c b/kernel/pid.c index 20d59fa2d49..30bd5d4b2ac 100644 --- a/kernel/pid.c +++ b/kernel/pid.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include diff --git a/lib/textsearch.c b/lib/textsearch.c index be8bda3862f..a3e500ad51d 100644 --- a/lib/textsearch.c +++ b/lib/textsearch.c @@ -97,6 +97,7 @@ #include #include #include +#include #include #include #include diff --git a/net/802/psnap.c b/net/802/psnap.c index 31128cb92a2..ea464393144 100644 --- a/net/802/psnap.c +++ b/net/802/psnap.c @@ -20,6 +20,7 @@ #include #include #include +#include static LIST_HEAD(snap_list); static DEFINE_SPINLOCK(snap_lock); diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 2a739adaa92..e7ddbfa0e02 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index 72c5976a5ce..142060f0205 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -15,6 +15,7 @@ #include #include +#include #include #include #include diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c index e38034aa56f..9e96ffcd29a 100644 --- a/net/bridge/br_stp.c +++ b/net/bridge/br_stp.c @@ -13,6 +13,7 @@ * 2 of the License, or (at your option) any later version. */ #include +#include #include "br_private.h" #include "br_private_stp.h" diff --git a/net/netlabel/netlabel_domainhash.c b/net/netlabel/netlabel_domainhash.c index 02c2f7c0b25..643c032a3a5 100644 --- a/net/netlabel/netlabel_domainhash.c +++ b/net/netlabel/netlabel_domainhash.c @@ -30,8 +30,7 @@ */ #include -#include -#include +#include #include #include #include -- cgit v1.2.3-70-g09d2 From 284d115ec9b70d7c38752d10ad393a198db07a4b Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 20 Apr 2008 17:32:16 +0100 Subject: [ARM] pxa: separate PXA25x and PXA27x UDC register definitions The PXA25x and PXA27x USB device controller register definitions are different. Currently, they live side by side in pxa-regs.h, but only one set is available depending on the setting of PXA25x or PXA27x. This means that if we build to support both PXA25x and PXA27x, the PXA27x definitions are unavailable, even to PXA27x specific code. Remove these definitions from pxa-regs.h, and place them in separate files. Include these files where appropriate. Note: according to the dependencies in drivers/usb/gadget/Kconfig, we do not support the UDC on PXA27x nor PXA3xx CPUs, so remove the platform devices from pxa27x.c and pxa3xx.c. Signed-off-by: Russell King --- arch/arm/mach-pxa/em-x270.c | 1 + arch/arm/mach-pxa/pxa27x.c | 2 +- arch/arm/mach-pxa/pxa3xx.c | 2 +- drivers/usb/gadget/pxa2xx_udc.c | 10 +- include/asm-arm/arch-pxa/pxa-regs.h | 412 ---------------------------------- include/asm-arm/arch-pxa/pxa25x-udc.h | 163 ++++++++++++++ include/asm-arm/arch-pxa/pxa27x-udc.h | 256 +++++++++++++++++++++ 7 files changed, 430 insertions(+), 416 deletions(-) create mode 100644 include/asm-arm/arch-pxa/pxa25x-udc.h create mode 100644 include/asm-arm/arch-pxa/pxa27x-udc.h (limited to 'drivers') diff --git a/arch/arm/mach-pxa/em-x270.c b/arch/arm/mach-pxa/em-x270.c index edc4f07a230..1269ac99150 100644 --- a/arch/arm/mach-pxa/em-x270.c +++ b/arch/arm/mach-pxa/em-x270.c @@ -24,6 +24,7 @@ #include #include +#include #include #include #include diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c index 7e945836e12..cdaf573e0f1 100644 --- a/arch/arm/mach-pxa/pxa27x.c +++ b/arch/arm/mach-pxa/pxa27x.c @@ -353,7 +353,7 @@ void __init pxa_set_i2c_power_info(struct i2c_pxa_platform_data *info) } static struct platform_device *devices[] __initdata = { - &pxa_device_udc, +/* &pxa_device_udc, The UDC driver is PXA25x only */ &pxa_device_ffuart, &pxa_device_btuart, &pxa_device_stuart, diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c index 644550bfa33..7fbe78649da 100644 --- a/arch/arm/mach-pxa/pxa3xx.c +++ b/arch/arm/mach-pxa/pxa3xx.c @@ -520,7 +520,7 @@ void __init pxa3xx_init_irq(void) */ static struct platform_device *devices[] __initdata = { - &pxa_device_udc, +/* &pxa_device_udc, The UDC driver is PXA25x only */ &pxa_device_ffuart, &pxa_device_btuart, &pxa_device_stuart, diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index 08f699b1fc5..63db96adc0b 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -46,19 +46,25 @@ #include #include #include +#include #include #include #include -#include #include #include #include -#include #include #include +/* + * This driver is PXA25x only. Grab the right register definitions. + */ +#ifdef CONFIG_ARCH_PXA +#include +#endif + #include diff --git a/include/asm-arm/arch-pxa/pxa-regs.h b/include/asm-arm/arch-pxa/pxa-regs.h index 4b2ea1e95c5..68d74287730 100644 --- a/include/asm-arm/arch-pxa/pxa-regs.h +++ b/include/asm-arm/arch-pxa/pxa-regs.h @@ -599,418 +599,6 @@ #define SMC_REG_BASE __REG(0x40500500) /* Secondary Modem Codec */ -/* - * USB Device Controller - * PXA25x and PXA27x USB device controller registers are different. - */ -#if defined(CONFIG_PXA25x) - -#define UDC_RES1 __REG(0x40600004) /* UDC Undocumented - Reserved1 */ -#define UDC_RES2 __REG(0x40600008) /* UDC Undocumented - Reserved2 */ -#define UDC_RES3 __REG(0x4060000C) /* UDC Undocumented - Reserved3 */ - -#define UDCCR __REG(0x40600000) /* UDC Control Register */ -#define UDCCR_UDE (1 << 0) /* UDC enable */ -#define UDCCR_UDA (1 << 1) /* UDC active */ -#define UDCCR_RSM (1 << 2) /* Device resume */ -#define UDCCR_RESIR (1 << 3) /* Resume interrupt request */ -#define UDCCR_SUSIR (1 << 4) /* Suspend interrupt request */ -#define UDCCR_SRM (1 << 5) /* Suspend/resume interrupt mask */ -#define UDCCR_RSTIR (1 << 6) /* Reset interrupt request */ -#define UDCCR_REM (1 << 7) /* Reset interrupt mask */ - -#define UDCCS0 __REG(0x40600010) /* UDC Endpoint 0 Control/Status Register */ -#define UDCCS0_OPR (1 << 0) /* OUT packet ready */ -#define UDCCS0_IPR (1 << 1) /* IN packet ready */ -#define UDCCS0_FTF (1 << 2) /* Flush Tx FIFO */ -#define UDCCS0_DRWF (1 << 3) /* Device remote wakeup feature */ -#define UDCCS0_SST (1 << 4) /* Sent stall */ -#define UDCCS0_FST (1 << 5) /* Force stall */ -#define UDCCS0_RNE (1 << 6) /* Receive FIFO no empty */ -#define UDCCS0_SA (1 << 7) /* Setup active */ - -/* Bulk IN - Endpoint 1,6,11 */ -#define UDCCS1 __REG(0x40600014) /* UDC Endpoint 1 (IN) Control/Status Register */ -#define UDCCS6 __REG(0x40600028) /* UDC Endpoint 6 (IN) Control/Status Register */ -#define UDCCS11 __REG(0x4060003C) /* UDC Endpoint 11 (IN) Control/Status Register */ - -#define UDCCS_BI_TFS (1 << 0) /* Transmit FIFO service */ -#define UDCCS_BI_TPC (1 << 1) /* Transmit packet complete */ -#define UDCCS_BI_FTF (1 << 2) /* Flush Tx FIFO */ -#define UDCCS_BI_TUR (1 << 3) /* Transmit FIFO underrun */ -#define UDCCS_BI_SST (1 << 4) /* Sent stall */ -#define UDCCS_BI_FST (1 << 5) /* Force stall */ -#define UDCCS_BI_TSP (1 << 7) /* Transmit short packet */ - -/* Bulk OUT - Endpoint 2,7,12 */ -#define UDCCS2 __REG(0x40600018) /* UDC Endpoint 2 (OUT) Control/Status Register */ -#define UDCCS7 __REG(0x4060002C) /* UDC Endpoint 7 (OUT) Control/Status Register */ -#define UDCCS12 __REG(0x40600040) /* UDC Endpoint 12 (OUT) Control/Status Register */ - -#define UDCCS_BO_RFS (1 << 0) /* Receive FIFO service */ -#define UDCCS_BO_RPC (1 << 1) /* Receive packet complete */ -#define UDCCS_BO_DME (1 << 3) /* DMA enable */ -#define UDCCS_BO_SST (1 << 4) /* Sent stall */ -#define UDCCS_BO_FST (1 << 5) /* Force stall */ -#define UDCCS_BO_RNE (1 << 6) /* Receive FIFO not empty */ -#define UDCCS_BO_RSP (1 << 7) /* Receive short packet */ - -/* Isochronous IN - Endpoint 3,8,13 */ -#define UDCCS3 __REG(0x4060001C) /* UDC Endpoint 3 (IN) Control/Status Register */ -#define UDCCS8 __REG(0x40600030) /* UDC Endpoint 8 (IN) Control/Status Register */ -#define UDCCS13 __REG(0x40600044) /* UDC Endpoint 13 (IN) Control/Status Register */ - -#define UDCCS_II_TFS (1 << 0) /* Transmit FIFO service */ -#define UDCCS_II_TPC (1 << 1) /* Transmit packet complete */ -#define UDCCS_II_FTF (1 << 2) /* Flush Tx FIFO */ -#define UDCCS_II_TUR (1 << 3) /* Transmit FIFO underrun */ -#define UDCCS_II_TSP (1 << 7) /* Transmit short packet */ - -/* Isochronous OUT - Endpoint 4,9,14 */ -#define UDCCS4 __REG(0x40600020) /* UDC Endpoint 4 (OUT) Control/Status Register */ -#define UDCCS9 __REG(0x40600034) /* UDC Endpoint 9 (OUT) Control/Status Register */ -#define UDCCS14 __REG(0x40600048) /* UDC Endpoint 14 (OUT) Control/Status Register */ - -#define UDCCS_IO_RFS (1 << 0) /* Receive FIFO service */ -#define UDCCS_IO_RPC (1 << 1) /* Receive packet complete */ -#define UDCCS_IO_ROF (1 << 2) /* Receive overflow */ -#define UDCCS_IO_DME (1 << 3) /* DMA enable */ -#define UDCCS_IO_RNE (1 << 6) /* Receive FIFO not empty */ -#define UDCCS_IO_RSP (1 << 7) /* Receive short packet */ - -/* Interrupt IN - Endpoint 5,10,15 */ -#define UDCCS5 __REG(0x40600024) /* UDC Endpoint 5 (Interrupt) Control/Status Register */ -#define UDCCS10 __REG(0x40600038) /* UDC Endpoint 10 (Interrupt) Control/Status Register */ -#define UDCCS15 __REG(0x4060004C) /* UDC Endpoint 15 (Interrupt) Control/Status Register */ - -#define UDCCS_INT_TFS (1 << 0) /* Transmit FIFO service */ -#define UDCCS_INT_TPC (1 << 1) /* Transmit packet complete */ -#define UDCCS_INT_FTF (1 << 2) /* Flush Tx FIFO */ -#define UDCCS_INT_TUR (1 << 3) /* Transmit FIFO underrun */ -#define UDCCS_INT_SST (1 << 4) /* Sent stall */ -#define UDCCS_INT_FST (1 << 5) /* Force stall */ -#define UDCCS_INT_TSP (1 << 7) /* Transmit short packet */ - -#define UFNRH __REG(0x40600060) /* UDC Frame Number Register High */ -#define UFNRL __REG(0x40600064) /* UDC Frame Number Register Low */ -#define UBCR2 __REG(0x40600068) /* UDC Byte Count Reg 2 */ -#define UBCR4 __REG(0x4060006c) /* UDC Byte Count Reg 4 */ -#define UBCR7 __REG(0x40600070) /* UDC Byte Count Reg 7 */ -#define UBCR9 __REG(0x40600074) /* UDC Byte Count Reg 9 */ -#define UBCR12 __REG(0x40600078) /* UDC Byte Count Reg 12 */ -#define UBCR14 __REG(0x4060007c) /* UDC Byte Count Reg 14 */ -#define UDDR0 __REG(0x40600080) /* UDC Endpoint 0 Data Register */ -#define UDDR1 __REG(0x40600100) /* UDC Endpoint 1 Data Register */ -#define UDDR2 __REG(0x40600180) /* UDC Endpoint 2 Data Register */ -#define UDDR3 __REG(0x40600200) /* UDC Endpoint 3 Data Register */ -#define UDDR4 __REG(0x40600400) /* UDC Endpoint 4 Data Register */ -#define UDDR5 __REG(0x406000A0) /* UDC Endpoint 5 Data Register */ -#define UDDR6 __REG(0x40600600) /* UDC Endpoint 6 Data Register */ -#define UDDR7 __REG(0x40600680) /* UDC Endpoint 7 Data Register */ -#define UDDR8 __REG(0x40600700) /* UDC Endpoint 8 Data Register */ -#define UDDR9 __REG(0x40600900) /* UDC Endpoint 9 Data Register */ -#define UDDR10 __REG(0x406000C0) /* UDC Endpoint 10 Data Register */ -#define UDDR11 __REG(0x40600B00) /* UDC Endpoint 11 Data Register */ -#define UDDR12 __REG(0x40600B80) /* UDC Endpoint 12 Data Register */ -#define UDDR13 __REG(0x40600C00) /* UDC Endpoint 13 Data Register */ -#define UDDR14 __REG(0x40600E00) /* UDC Endpoint 14 Data Register */ -#define UDDR15 __REG(0x406000E0) /* UDC Endpoint 15 Data Register */ - -#define UICR0 __REG(0x40600050) /* UDC Interrupt Control Register 0 */ - -#define UICR0_IM0 (1 << 0) /* Interrupt mask ep 0 */ -#define UICR0_IM1 (1 << 1) /* Interrupt mask ep 1 */ -#define UICR0_IM2 (1 << 2) /* Interrupt mask ep 2 */ -#define UICR0_IM3 (1 << 3) /* Interrupt mask ep 3 */ -#define UICR0_IM4 (1 << 4) /* Interrupt mask ep 4 */ -#define UICR0_IM5 (1 << 5) /* Interrupt mask ep 5 */ -#define UICR0_IM6 (1 << 6) /* Interrupt mask ep 6 */ -#define UICR0_IM7 (1 << 7) /* Interrupt mask ep 7 */ - -#define UICR1 __REG(0x40600054) /* UDC Interrupt Control Register 1 */ - -#define UICR1_IM8 (1 << 0) /* Interrupt mask ep 8 */ -#define UICR1_IM9 (1 << 1) /* Interrupt mask ep 9 */ -#define UICR1_IM10 (1 << 2) /* Interrupt mask ep 10 */ -#define UICR1_IM11 (1 << 3) /* Interrupt mask ep 11 */ -#define UICR1_IM12 (1 << 4) /* Interrupt mask ep 12 */ -#define UICR1_IM13 (1 << 5) /* Interrupt mask ep 13 */ -#define UICR1_IM14 (1 << 6) /* Interrupt mask ep 14 */ -#define UICR1_IM15 (1 << 7) /* Interrupt mask ep 15 */ - -#define USIR0 __REG(0x40600058) /* UDC Status Interrupt Register 0 */ - -#define USIR0_IR0 (1 << 0) /* Interrupt request ep 0 */ -#define USIR0_IR1 (1 << 1) /* Interrupt request ep 1 */ -#define USIR0_IR2 (1 << 2) /* Interrupt request ep 2 */ -#define USIR0_IR3 (1 << 3) /* Interrupt request ep 3 */ -#define USIR0_IR4 (1 << 4) /* Interrupt request ep 4 */ -#define USIR0_IR5 (1 << 5) /* Interrupt request ep 5 */ -#define USIR0_IR6 (1 << 6) /* Interrupt request ep 6 */ -#define USIR0_IR7 (1 << 7) /* Interrupt request ep 7 */ - -#define USIR1 __REG(0x4060005C) /* UDC Status Interrupt Register 1 */ - -#define USIR1_IR8 (1 << 0) /* Interrupt request ep 8 */ -#define USIR1_IR9 (1 << 1) /* Interrupt request ep 9 */ -#define USIR1_IR10 (1 << 2) /* Interrupt request ep 10 */ -#define USIR1_IR11 (1 << 3) /* Interrupt request ep 11 */ -#define USIR1_IR12 (1 << 4) /* Interrupt request ep 12 */ -#define USIR1_IR13 (1 << 5) /* Interrupt request ep 13 */ -#define USIR1_IR14 (1 << 6) /* Interrupt request ep 14 */ -#define USIR1_IR15 (1 << 7) /* Interrupt request ep 15 */ - -#elif defined(CONFIG_PXA27x) - -#define UDCCR __REG(0x40600000) /* UDC Control Register */ -#define UDCCR_OEN (1 << 31) /* On-the-Go Enable */ -#define UDCCR_AALTHNP (1 << 30) /* A-device Alternate Host Negotiation - Protocol Port Support */ -#define UDCCR_AHNP (1 << 29) /* A-device Host Negotiation Protocol - Support */ -#define UDCCR_BHNP (1 << 28) /* B-device Host Negotiation Protocol - Enable */ -#define UDCCR_DWRE (1 << 16) /* Device Remote Wake-up Enable */ -#define UDCCR_ACN (0x03 << 11) /* Active UDC configuration Number */ -#define UDCCR_ACN_S 11 -#define UDCCR_AIN (0x07 << 8) /* Active UDC interface Number */ -#define UDCCR_AIN_S 8 -#define UDCCR_AAISN (0x07 << 5) /* Active UDC Alternate Interface - Setting Number */ -#define UDCCR_AAISN_S 5 -#define UDCCR_SMAC (1 << 4) /* Switch Endpoint Memory to Active - Configuration */ -#define UDCCR_EMCE (1 << 3) /* Endpoint Memory Configuration - Error */ -#define UDCCR_UDR (1 << 2) /* UDC Resume */ -#define UDCCR_UDA (1 << 1) /* UDC Active */ -#define UDCCR_UDE (1 << 0) /* UDC Enable */ - -#define UDCICR0 __REG(0x40600004) /* UDC Interrupt Control Register0 */ -#define UDCICR1 __REG(0x40600008) /* UDC Interrupt Control Register1 */ -#define UDCICR_FIFOERR (1 << 1) /* FIFO Error interrupt for EP */ -#define UDCICR_PKTCOMPL (1 << 0) /* Packet Complete interrupt for EP */ - -#define UDC_INT_FIFOERROR (0x2) -#define UDC_INT_PACKETCMP (0x1) - -#define UDCICR_INT(n,intr) (((intr) & 0x03) << (((n) & 0x0F) * 2)) -#define UDCICR1_IECC (1 << 31) /* IntEn - Configuration Change */ -#define UDCICR1_IESOF (1 << 30) /* IntEn - Start of Frame */ -#define UDCICR1_IERU (1 << 29) /* IntEn - Resume */ -#define UDCICR1_IESU (1 << 28) /* IntEn - Suspend */ -#define UDCICR1_IERS (1 << 27) /* IntEn - Reset */ - -#define UDCISR0 __REG(0x4060000C) /* UDC Interrupt Status Register 0 */ -#define UDCISR1 __REG(0x40600010) /* UDC Interrupt Status Register 1 */ -#define UDCISR_INT(n,intr) (((intr) & 0x03) << (((n) & 0x0F) * 2)) -#define UDCISR1_IRCC (1 << 31) /* IntReq - Configuration Change */ -#define UDCISR1_IRSOF (1 << 30) /* IntReq - Start of Frame */ -#define UDCISR1_IRRU (1 << 29) /* IntReq - Resume */ -#define UDCISR1_IRSU (1 << 28) /* IntReq - Suspend */ -#define UDCISR1_IRRS (1 << 27) /* IntReq - Reset */ - -#define UDCFNR __REG(0x40600014) /* UDC Frame Number Register */ -#define UDCOTGICR __REG(0x40600018) /* UDC On-The-Go interrupt control */ -#define UDCOTGICR_IESF (1 << 24) /* OTG SET_FEATURE command recvd */ -#define UDCOTGICR_IEXR (1 << 17) /* Extra Transciever Interrupt - Rising Edge Interrupt Enable */ -#define UDCOTGICR_IEXF (1 << 16) /* Extra Transciever Interrupt - Falling Edge Interrupt Enable */ -#define UDCOTGICR_IEVV40R (1 << 9) /* OTG Vbus Valid 4.0V Rising Edge - Interrupt Enable */ -#define UDCOTGICR_IEVV40F (1 << 8) /* OTG Vbus Valid 4.0V Falling Edge - Interrupt Enable */ -#define UDCOTGICR_IEVV44R (1 << 7) /* OTG Vbus Valid 4.4V Rising Edge - Interrupt Enable */ -#define UDCOTGICR_IEVV44F (1 << 6) /* OTG Vbus Valid 4.4V Falling Edge - Interrupt Enable */ -#define UDCOTGICR_IESVR (1 << 5) /* OTG Session Valid Rising Edge - Interrupt Enable */ -#define UDCOTGICR_IESVF (1 << 4) /* OTG Session Valid Falling Edge - Interrupt Enable */ -#define UDCOTGICR_IESDR (1 << 3) /* OTG A-Device SRP Detect Rising - Edge Interrupt Enable */ -#define UDCOTGICR_IESDF (1 << 2) /* OTG A-Device SRP Detect Falling - Edge Interrupt Enable */ -#define UDCOTGICR_IEIDR (1 << 1) /* OTG ID Change Rising Edge - Interrupt Enable */ -#define UDCOTGICR_IEIDF (1 << 0) /* OTG ID Change Falling Edge - Interrupt Enable */ - -#define UP2OCR __REG(0x40600020) /* USB Port 2 Output Control register */ - -#define UP2OCR_CPVEN (1 << 0) /* Charge Pump Vbus Enable */ -#define UP2OCR_CPVPE (1 << 1) /* Charge Pump Vbus Pulse Enable */ -#define UP2OCR_DPPDE (1 << 2) /* Host Port 2 Transceiver D+ Pull Down Enable */ -#define UP2OCR_DMPDE (1 << 3) /* Host Port 2 Transceiver D- Pull Down Enable */ -#define UP2OCR_DPPUE (1 << 4) /* Host Port 2 Transceiver D+ Pull Up Enable */ -#define UP2OCR_DMPUE (1 << 5) /* Host Port 2 Transceiver D- Pull Up Enable */ -#define UP2OCR_DPPUBE (1 << 6) /* Host Port 2 Transceiver D+ Pull Up Bypass Enable */ -#define UP2OCR_DMPUBE (1 << 7) /* Host Port 2 Transceiver D- Pull Up Bypass Enable */ -#define UP2OCR_EXSP (1 << 8) /* External Transceiver Speed Control */ -#define UP2OCR_EXSUS (1 << 9) /* External Transceiver Speed Enable */ -#define UP2OCR_IDON (1 << 10) /* OTG ID Read Enable */ -#define UP2OCR_HXS (1 << 16) /* Host Port 2 Transceiver Output Select */ -#define UP2OCR_HXOE (1 << 17) /* Host Port 2 Transceiver Output Enable */ -#define UP2OCR_SEOS (1 << 24) /* Single-Ended Output Select */ - -#define UDCCSN(x) __REG2(0x40600100, (x) << 2) -#define UDCCSR0 __REG(0x40600100) /* UDC Control/Status register - Endpoint 0 */ -#define UDCCSR0_SA (1 << 7) /* Setup Active */ -#define UDCCSR0_RNE (1 << 6) /* Receive FIFO Not Empty */ -#define UDCCSR0_FST (1 << 5) /* Force Stall */ -#define UDCCSR0_SST (1 << 4) /* Sent Stall */ -#define UDCCSR0_DME (1 << 3) /* DMA Enable */ -#define UDCCSR0_FTF (1 << 2) /* Flush Transmit FIFO */ -#define UDCCSR0_IPR (1 << 1) /* IN Packet Ready */ -#define UDCCSR0_OPC (1 << 0) /* OUT Packet Complete */ - -#define UDCCSRA __REG(0x40600104) /* UDC Control/Status register - Endpoint A */ -#define UDCCSRB __REG(0x40600108) /* UDC Control/Status register - Endpoint B */ -#define UDCCSRC __REG(0x4060010C) /* UDC Control/Status register - Endpoint C */ -#define UDCCSRD __REG(0x40600110) /* UDC Control/Status register - Endpoint D */ -#define UDCCSRE __REG(0x40600114) /* UDC Control/Status register - Endpoint E */ -#define UDCCSRF __REG(0x40600118) /* UDC Control/Status register - Endpoint F */ -#define UDCCSRG __REG(0x4060011C) /* UDC Control/Status register - Endpoint G */ -#define UDCCSRH __REG(0x40600120) /* UDC Control/Status register - Endpoint H */ -#define UDCCSRI __REG(0x40600124) /* UDC Control/Status register - Endpoint I */ -#define UDCCSRJ __REG(0x40600128) /* UDC Control/Status register - Endpoint J */ -#define UDCCSRK __REG(0x4060012C) /* UDC Control/Status register - Endpoint K */ -#define UDCCSRL __REG(0x40600130) /* UDC Control/Status register - Endpoint L */ -#define UDCCSRM __REG(0x40600134) /* UDC Control/Status register - Endpoint M */ -#define UDCCSRN __REG(0x40600138) /* UDC Control/Status register - Endpoint N */ -#define UDCCSRP __REG(0x4060013C) /* UDC Control/Status register - Endpoint P */ -#define UDCCSRQ __REG(0x40600140) /* UDC Control/Status register - Endpoint Q */ -#define UDCCSRR __REG(0x40600144) /* UDC Control/Status register - Endpoint R */ -#define UDCCSRS __REG(0x40600148) /* UDC Control/Status register - Endpoint S */ -#define UDCCSRT __REG(0x4060014C) /* UDC Control/Status register - Endpoint T */ -#define UDCCSRU __REG(0x40600150) /* UDC Control/Status register - Endpoint U */ -#define UDCCSRV __REG(0x40600154) /* UDC Control/Status register - Endpoint V */ -#define UDCCSRW __REG(0x40600158) /* UDC Control/Status register - Endpoint W */ -#define UDCCSRX __REG(0x4060015C) /* UDC Control/Status register - Endpoint X */ - -#define UDCCSR_DPE (1 << 9) /* Data Packet Error */ -#define UDCCSR_FEF (1 << 8) /* Flush Endpoint FIFO */ -#define UDCCSR_SP (1 << 7) /* Short Packet Control/Status */ -#define UDCCSR_BNE (1 << 6) /* Buffer Not Empty (IN endpoints) */ -#define UDCCSR_BNF (1 << 6) /* Buffer Not Full (OUT endpoints) */ -#define UDCCSR_FST (1 << 5) /* Force STALL */ -#define UDCCSR_SST (1 << 4) /* Sent STALL */ -#define UDCCSR_DME (1 << 3) /* DMA Enable */ -#define UDCCSR_TRN (1 << 2) /* Tx/Rx NAK */ -#define UDCCSR_PC (1 << 1) /* Packet Complete */ -#define UDCCSR_FS (1 << 0) /* FIFO needs service */ - -#define UDCBCN(x) __REG2(0x40600200, (x)<<2) -#define UDCBCR0 __REG(0x40600200) /* Byte Count Register - EP0 */ -#define UDCBCRA __REG(0x40600204) /* Byte Count Register - EPA */ -#define UDCBCRB __REG(0x40600208) /* Byte Count Register - EPB */ -#define UDCBCRC __REG(0x4060020C) /* Byte Count Register - EPC */ -#define UDCBCRD __REG(0x40600210) /* Byte Count Register - EPD */ -#define UDCBCRE __REG(0x40600214) /* Byte Count Register - EPE */ -#define UDCBCRF __REG(0x40600218) /* Byte Count Register - EPF */ -#define UDCBCRG __REG(0x4060021C) /* Byte Count Register - EPG */ -#define UDCBCRH __REG(0x40600220) /* Byte Count Register - EPH */ -#define UDCBCRI __REG(0x40600224) /* Byte Count Register - EPI */ -#define UDCBCRJ __REG(0x40600228) /* Byte Count Register - EPJ */ -#define UDCBCRK __REG(0x4060022C) /* Byte Count Register - EPK */ -#define UDCBCRL __REG(0x40600230) /* Byte Count Register - EPL */ -#define UDCBCRM __REG(0x40600234) /* Byte Count Register - EPM */ -#define UDCBCRN __REG(0x40600238) /* Byte Count Register - EPN */ -#define UDCBCRP __REG(0x4060023C) /* Byte Count Register - EPP */ -#define UDCBCRQ __REG(0x40600240) /* Byte Count Register - EPQ */ -#define UDCBCRR __REG(0x40600244) /* Byte Count Register - EPR */ -#define UDCBCRS __REG(0x40600248) /* Byte Count Register - EPS */ -#define UDCBCRT __REG(0x4060024C) /* Byte Count Register - EPT */ -#define UDCBCRU __REG(0x40600250) /* Byte Count Register - EPU */ -#define UDCBCRV __REG(0x40600254) /* Byte Count Register - EPV */ -#define UDCBCRW __REG(0x40600258) /* Byte Count Register - EPW */ -#define UDCBCRX __REG(0x4060025C) /* Byte Count Register - EPX */ - -#define UDCDN(x) __REG2(0x40600300, (x)<<2) -#define PHYS_UDCDN(x) (0x40600300 + ((x)<<2)) -#define PUDCDN(x) (volatile u32 *)(io_p2v(PHYS_UDCDN((x)))) -#define UDCDR0 __REG(0x40600300) /* Data Register - EP0 */ -#define UDCDRA __REG(0x40600304) /* Data Register - EPA */ -#define UDCDRB __REG(0x40600308) /* Data Register - EPB */ -#define UDCDRC __REG(0x4060030C) /* Data Register - EPC */ -#define UDCDRD __REG(0x40600310) /* Data Register - EPD */ -#define UDCDRE __REG(0x40600314) /* Data Register - EPE */ -#define UDCDRF __REG(0x40600318) /* Data Register - EPF */ -#define UDCDRG __REG(0x4060031C) /* Data Register - EPG */ -#define UDCDRH __REG(0x40600320) /* Data Register - EPH */ -#define UDCDRI __REG(0x40600324) /* Data Register - EPI */ -#define UDCDRJ __REG(0x40600328) /* Data Register - EPJ */ -#define UDCDRK __REG(0x4060032C) /* Data Register - EPK */ -#define UDCDRL __REG(0x40600330) /* Data Register - EPL */ -#define UDCDRM __REG(0x40600334) /* Data Register - EPM */ -#define UDCDRN __REG(0x40600338) /* Data Register - EPN */ -#define UDCDRP __REG(0x4060033C) /* Data Register - EPP */ -#define UDCDRQ __REG(0x40600340) /* Data Register - EPQ */ -#define UDCDRR __REG(0x40600344) /* Data Register - EPR */ -#define UDCDRS __REG(0x40600348) /* Data Register - EPS */ -#define UDCDRT __REG(0x4060034C) /* Data Register - EPT */ -#define UDCDRU __REG(0x40600350) /* Data Register - EPU */ -#define UDCDRV __REG(0x40600354) /* Data Register - EPV */ -#define UDCDRW __REG(0x40600358) /* Data Register - EPW */ -#define UDCDRX __REG(0x4060035C) /* Data Register - EPX */ - -#define UDCCN(x) __REG2(0x40600400, (x)<<2) -#define UDCCRA __REG(0x40600404) /* Configuration register EPA */ -#define UDCCRB __REG(0x40600408) /* Configuration register EPB */ -#define UDCCRC __REG(0x4060040C) /* Configuration register EPC */ -#define UDCCRD __REG(0x40600410) /* Configuration register EPD */ -#define UDCCRE __REG(0x40600414) /* Configuration register EPE */ -#define UDCCRF __REG(0x40600418) /* Configuration register EPF */ -#define UDCCRG __REG(0x4060041C) /* Configuration register EPG */ -#define UDCCRH __REG(0x40600420) /* Configuration register EPH */ -#define UDCCRI __REG(0x40600424) /* Configuration register EPI */ -#define UDCCRJ __REG(0x40600428) /* Configuration register EPJ */ -#define UDCCRK __REG(0x4060042C) /* Configuration register EPK */ -#define UDCCRL __REG(0x40600430) /* Configuration register EPL */ -#define UDCCRM __REG(0x40600434) /* Configuration register EPM */ -#define UDCCRN __REG(0x40600438) /* Configuration register EPN */ -#define UDCCRP __REG(0x4060043C) /* Configuration register EPP */ -#define UDCCRQ __REG(0x40600440) /* Configuration register EPQ */ -#define UDCCRR __REG(0x40600444) /* Configuration register EPR */ -#define UDCCRS __REG(0x40600448) /* Configuration register EPS */ -#define UDCCRT __REG(0x4060044C) /* Configuration register EPT */ -#define UDCCRU __REG(0x40600450) /* Configuration register EPU */ -#define UDCCRV __REG(0x40600454) /* Configuration register EPV */ -#define UDCCRW __REG(0x40600458) /* Configuration register EPW */ -#define UDCCRX __REG(0x4060045C) /* Configuration register EPX */ - -#define UDCCONR_CN (0x03 << 25) /* Configuration Number */ -#define UDCCONR_CN_S (25) -#define UDCCONR_IN (0x07 << 22) /* Interface Number */ -#define UDCCONR_IN_S (22) -#define UDCCONR_AISN (0x07 << 19) /* Alternate Interface Number */ -#define UDCCONR_AISN_S (19) -#define UDCCONR_EN (0x0f << 15) /* Endpoint Number */ -#define UDCCONR_EN_S (15) -#define UDCCONR_ET (0x03 << 13) /* Endpoint Type: */ -#define UDCCONR_ET_S (13) -#define UDCCONR_ET_INT (0x03 << 13) /* Interrupt */ -#define UDCCONR_ET_BULK (0x02 << 13) /* Bulk */ -#define UDCCONR_ET_ISO (0x01 << 13) /* Isochronous */ -#define UDCCONR_ET_NU (0x00 << 13) /* Not used */ -#define UDCCONR_ED (1 << 12) /* Endpoint Direction */ -#define UDCCONR_MPS (0x3ff << 2) /* Maximum Packet Size */ -#define UDCCONR_MPS_S (2) -#define UDCCONR_DE (1 << 1) /* Double Buffering Enable */ -#define UDCCONR_EE (1 << 0) /* Endpoint Enable */ - - -#define UDC_INT_FIFOERROR (0x2) -#define UDC_INT_PACKETCMP (0x1) - -#define UDC_FNR_MASK (0x7ff) - -#define UDCCSR_WR_MASK (UDCCSR_DME|UDCCSR_FST) -#define UDC_BCR_MASK (0x3ff) -#endif - /* * Fast Infrared Communication Port */ diff --git a/include/asm-arm/arch-pxa/pxa25x-udc.h b/include/asm-arm/arch-pxa/pxa25x-udc.h new file mode 100644 index 00000000000..840305916b6 --- /dev/null +++ b/include/asm-arm/arch-pxa/pxa25x-udc.h @@ -0,0 +1,163 @@ +#ifndef _ASM_ARCH_PXA25X_UDC_H +#define _ASM_ARCH_PXA25X_UDC_H + +#ifdef _ASM_ARCH_PXA27X_UDC_H +#error You can't include both PXA25x and PXA27x UDC support +#endif + +#define UDC_RES1 __REG(0x40600004) /* UDC Undocumented - Reserved1 */ +#define UDC_RES2 __REG(0x40600008) /* UDC Undocumented - Reserved2 */ +#define UDC_RES3 __REG(0x4060000C) /* UDC Undocumented - Reserved3 */ + +#define UDCCR __REG(0x40600000) /* UDC Control Register */ +#define UDCCR_UDE (1 << 0) /* UDC enable */ +#define UDCCR_UDA (1 << 1) /* UDC active */ +#define UDCCR_RSM (1 << 2) /* Device resume */ +#define UDCCR_RESIR (1 << 3) /* Resume interrupt request */ +#define UDCCR_SUSIR (1 << 4) /* Suspend interrupt request */ +#define UDCCR_SRM (1 << 5) /* Suspend/resume interrupt mask */ +#define UDCCR_RSTIR (1 << 6) /* Reset interrupt request */ +#define UDCCR_REM (1 << 7) /* Reset interrupt mask */ + +#define UDCCS0 __REG(0x40600010) /* UDC Endpoint 0 Control/Status Register */ +#define UDCCS0_OPR (1 << 0) /* OUT packet ready */ +#define UDCCS0_IPR (1 << 1) /* IN packet ready */ +#define UDCCS0_FTF (1 << 2) /* Flush Tx FIFO */ +#define UDCCS0_DRWF (1 << 3) /* Device remote wakeup feature */ +#define UDCCS0_SST (1 << 4) /* Sent stall */ +#define UDCCS0_FST (1 << 5) /* Force stall */ +#define UDCCS0_RNE (1 << 6) /* Receive FIFO no empty */ +#define UDCCS0_SA (1 << 7) /* Setup active */ + +/* Bulk IN - Endpoint 1,6,11 */ +#define UDCCS1 __REG(0x40600014) /* UDC Endpoint 1 (IN) Control/Status Register */ +#define UDCCS6 __REG(0x40600028) /* UDC Endpoint 6 (IN) Control/Status Register */ +#define UDCCS11 __REG(0x4060003C) /* UDC Endpoint 11 (IN) Control/Status Register */ + +#define UDCCS_BI_TFS (1 << 0) /* Transmit FIFO service */ +#define UDCCS_BI_TPC (1 << 1) /* Transmit packet complete */ +#define UDCCS_BI_FTF (1 << 2) /* Flush Tx FIFO */ +#define UDCCS_BI_TUR (1 << 3) /* Transmit FIFO underrun */ +#define UDCCS_BI_SST (1 << 4) /* Sent stall */ +#define UDCCS_BI_FST (1 << 5) /* Force stall */ +#define UDCCS_BI_TSP (1 << 7) /* Transmit short packet */ + +/* Bulk OUT - Endpoint 2,7,12 */ +#define UDCCS2 __REG(0x40600018) /* UDC Endpoint 2 (OUT) Control/Status Register */ +#define UDCCS7 __REG(0x4060002C) /* UDC Endpoint 7 (OUT) Control/Status Register */ +#define UDCCS12 __REG(0x40600040) /* UDC Endpoint 12 (OUT) Control/Status Register */ + +#define UDCCS_BO_RFS (1 << 0) /* Receive FIFO service */ +#define UDCCS_BO_RPC (1 << 1) /* Receive packet complete */ +#define UDCCS_BO_DME (1 << 3) /* DMA enable */ +#define UDCCS_BO_SST (1 << 4) /* Sent stall */ +#define UDCCS_BO_FST (1 << 5) /* Force stall */ +#define UDCCS_BO_RNE (1 << 6) /* Receive FIFO not empty */ +#define UDCCS_BO_RSP (1 << 7) /* Receive short packet */ + +/* Isochronous IN - Endpoint 3,8,13 */ +#define UDCCS3 __REG(0x4060001C) /* UDC Endpoint 3 (IN) Control/Status Register */ +#define UDCCS8 __REG(0x40600030) /* UDC Endpoint 8 (IN) Control/Status Register */ +#define UDCCS13 __REG(0x40600044) /* UDC Endpoint 13 (IN) Control/Status Register */ + +#define UDCCS_II_TFS (1 << 0) /* Transmit FIFO service */ +#define UDCCS_II_TPC (1 << 1) /* Transmit packet complete */ +#define UDCCS_II_FTF (1 << 2) /* Flush Tx FIFO */ +#define UDCCS_II_TUR (1 << 3) /* Transmit FIFO underrun */ +#define UDCCS_II_TSP (1 << 7) /* Transmit short packet */ + +/* Isochronous OUT - Endpoint 4,9,14 */ +#define UDCCS4 __REG(0x40600020) /* UDC Endpoint 4 (OUT) Control/Status Register */ +#define UDCCS9 __REG(0x40600034) /* UDC Endpoint 9 (OUT) Control/Status Register */ +#define UDCCS14 __REG(0x40600048) /* UDC Endpoint 14 (OUT) Control/Status Register */ + +#define UDCCS_IO_RFS (1 << 0) /* Receive FIFO service */ +#define UDCCS_IO_RPC (1 << 1) /* Receive packet complete */ +#define UDCCS_IO_ROF (1 << 2) /* Receive overflow */ +#define UDCCS_IO_DME (1 << 3) /* DMA enable */ +#define UDCCS_IO_RNE (1 << 6) /* Receive FIFO not empty */ +#define UDCCS_IO_RSP (1 << 7) /* Receive short packet */ + +/* Interrupt IN - Endpoint 5,10,15 */ +#define UDCCS5 __REG(0x40600024) /* UDC Endpoint 5 (Interrupt) Control/Status Register */ +#define UDCCS10 __REG(0x40600038) /* UDC Endpoint 10 (Interrupt) Control/Status Register */ +#define UDCCS15 __REG(0x4060004C) /* UDC Endpoint 15 (Interrupt) Control/Status Register */ + +#define UDCCS_INT_TFS (1 << 0) /* Transmit FIFO service */ +#define UDCCS_INT_TPC (1 << 1) /* Transmit packet complete */ +#define UDCCS_INT_FTF (1 << 2) /* Flush Tx FIFO */ +#define UDCCS_INT_TUR (1 << 3) /* Transmit FIFO underrun */ +#define UDCCS_INT_SST (1 << 4) /* Sent stall */ +#define UDCCS_INT_FST (1 << 5) /* Force stall */ +#define UDCCS_INT_TSP (1 << 7) /* Transmit short packet */ + +#define UFNRH __REG(0x40600060) /* UDC Frame Number Register High */ +#define UFNRL __REG(0x40600064) /* UDC Frame Number Register Low */ +#define UBCR2 __REG(0x40600068) /* UDC Byte Count Reg 2 */ +#define UBCR4 __REG(0x4060006c) /* UDC Byte Count Reg 4 */ +#define UBCR7 __REG(0x40600070) /* UDC Byte Count Reg 7 */ +#define UBCR9 __REG(0x40600074) /* UDC Byte Count Reg 9 */ +#define UBCR12 __REG(0x40600078) /* UDC Byte Count Reg 12 */ +#define UBCR14 __REG(0x4060007c) /* UDC Byte Count Reg 14 */ +#define UDDR0 __REG(0x40600080) /* UDC Endpoint 0 Data Register */ +#define UDDR1 __REG(0x40600100) /* UDC Endpoint 1 Data Register */ +#define UDDR2 __REG(0x40600180) /* UDC Endpoint 2 Data Register */ +#define UDDR3 __REG(0x40600200) /* UDC Endpoint 3 Data Register */ +#define UDDR4 __REG(0x40600400) /* UDC Endpoint 4 Data Register */ +#define UDDR5 __REG(0x406000A0) /* UDC Endpoint 5 Data Register */ +#define UDDR6 __REG(0x40600600) /* UDC Endpoint 6 Data Register */ +#define UDDR7 __REG(0x40600680) /* UDC Endpoint 7 Data Register */ +#define UDDR8 __REG(0x40600700) /* UDC Endpoint 8 Data Register */ +#define UDDR9 __REG(0x40600900) /* UDC Endpoint 9 Data Register */ +#define UDDR10 __REG(0x406000C0) /* UDC Endpoint 10 Data Register */ +#define UDDR11 __REG(0x40600B00) /* UDC Endpoint 11 Data Register */ +#define UDDR12 __REG(0x40600B80) /* UDC Endpoint 12 Data Register */ +#define UDDR13 __REG(0x40600C00) /* UDC Endpoint 13 Data Register */ +#define UDDR14 __REG(0x40600E00) /* UDC Endpoint 14 Data Register */ +#define UDDR15 __REG(0x406000E0) /* UDC Endpoint 15 Data Register */ + +#define UICR0 __REG(0x40600050) /* UDC Interrupt Control Register 0 */ + +#define UICR0_IM0 (1 << 0) /* Interrupt mask ep 0 */ +#define UICR0_IM1 (1 << 1) /* Interrupt mask ep 1 */ +#define UICR0_IM2 (1 << 2) /* Interrupt mask ep 2 */ +#define UICR0_IM3 (1 << 3) /* Interrupt mask ep 3 */ +#define UICR0_IM4 (1 << 4) /* Interrupt mask ep 4 */ +#define UICR0_IM5 (1 << 5) /* Interrupt mask ep 5 */ +#define UICR0_IM6 (1 << 6) /* Interrupt mask ep 6 */ +#define UICR0_IM7 (1 << 7) /* Interrupt mask ep 7 */ + +#define UICR1 __REG(0x40600054) /* UDC Interrupt Control Register 1 */ + +#define UICR1_IM8 (1 << 0) /* Interrupt mask ep 8 */ +#define UICR1_IM9 (1 << 1) /* Interrupt mask ep 9 */ +#define UICR1_IM10 (1 << 2) /* Interrupt mask ep 10 */ +#define UICR1_IM11 (1 << 3) /* Interrupt mask ep 11 */ +#define UICR1_IM12 (1 << 4) /* Interrupt mask ep 12 */ +#define UICR1_IM13 (1 << 5) /* Interrupt mask ep 13 */ +#define UICR1_IM14 (1 << 6) /* Interrupt mask ep 14 */ +#define UICR1_IM15 (1 << 7) /* Interrupt mask ep 15 */ + +#define USIR0 __REG(0x40600058) /* UDC Status Interrupt Register 0 */ + +#define USIR0_IR0 (1 << 0) /* Interrupt request ep 0 */ +#define USIR0_IR1 (1 << 1) /* Interrupt request ep 1 */ +#define USIR0_IR2 (1 << 2) /* Interrupt request ep 2 */ +#define USIR0_IR3 (1 << 3) /* Interrupt request ep 3 */ +#define USIR0_IR4 (1 << 4) /* Interrupt request ep 4 */ +#define USIR0_IR5 (1 << 5) /* Interrupt request ep 5 */ +#define USIR0_IR6 (1 << 6) /* Interrupt request ep 6 */ +#define USIR0_IR7 (1 << 7) /* Interrupt request ep 7 */ + +#define USIR1 __REG(0x4060005C) /* UDC Status Interrupt Register 1 */ + +#define USIR1_IR8 (1 << 0) /* Interrupt request ep 8 */ +#define USIR1_IR9 (1 << 1) /* Interrupt request ep 9 */ +#define USIR1_IR10 (1 << 2) /* Interrupt request ep 10 */ +#define USIR1_IR11 (1 << 3) /* Interrupt request ep 11 */ +#define USIR1_IR12 (1 << 4) /* Interrupt request ep 12 */ +#define USIR1_IR13 (1 << 5) /* Interrupt request ep 13 */ +#define USIR1_IR14 (1 << 6) /* Interrupt request ep 14 */ +#define USIR1_IR15 (1 << 7) /* Interrupt request ep 15 */ + +#endif diff --git a/include/asm-arm/arch-pxa/pxa27x-udc.h b/include/asm-arm/arch-pxa/pxa27x-udc.h new file mode 100644 index 00000000000..9cf0b1f8811 --- /dev/null +++ b/include/asm-arm/arch-pxa/pxa27x-udc.h @@ -0,0 +1,256 @@ +#ifndef _ASM_ARCH_PXA27X_UDC_H +#define _ASM_ARCH_PXA27X_UDC_H + +#ifdef _ASM_ARCH_PXA25X_UDC_H +#error You can't include both PXA25x and PXA27x UDC support +#endif + +#define UDCCR __REG(0x40600000) /* UDC Control Register */ +#define UDCCR_OEN (1 << 31) /* On-the-Go Enable */ +#define UDCCR_AALTHNP (1 << 30) /* A-device Alternate Host Negotiation + Protocol Port Support */ +#define UDCCR_AHNP (1 << 29) /* A-device Host Negotiation Protocol + Support */ +#define UDCCR_BHNP (1 << 28) /* B-device Host Negotiation Protocol + Enable */ +#define UDCCR_DWRE (1 << 16) /* Device Remote Wake-up Enable */ +#define UDCCR_ACN (0x03 << 11) /* Active UDC configuration Number */ +#define UDCCR_ACN_S 11 +#define UDCCR_AIN (0x07 << 8) /* Active UDC interface Number */ +#define UDCCR_AIN_S 8 +#define UDCCR_AAISN (0x07 << 5) /* Active UDC Alternate Interface + Setting Number */ +#define UDCCR_AAISN_S 5 +#define UDCCR_SMAC (1 << 4) /* Switch Endpoint Memory to Active + Configuration */ +#define UDCCR_EMCE (1 << 3) /* Endpoint Memory Configuration + Error */ +#define UDCCR_UDR (1 << 2) /* UDC Resume */ +#define UDCCR_UDA (1 << 1) /* UDC Active */ +#define UDCCR_UDE (1 << 0) /* UDC Enable */ + +#define UDCICR0 __REG(0x40600004) /* UDC Interrupt Control Register0 */ +#define UDCICR1 __REG(0x40600008) /* UDC Interrupt Control Register1 */ +#define UDCICR_FIFOERR (1 << 1) /* FIFO Error interrupt for EP */ +#define UDCICR_PKTCOMPL (1 << 0) /* Packet Complete interrupt for EP */ + +#define UDC_INT_FIFOERROR (0x2) +#define UDC_INT_PACKETCMP (0x1) + +#define UDCICR_INT(n,intr) (((intr) & 0x03) << (((n) & 0x0F) * 2)) +#define UDCICR1_IECC (1 << 31) /* IntEn - Configuration Change */ +#define UDCICR1_IESOF (1 << 30) /* IntEn - Start of Frame */ +#define UDCICR1_IERU (1 << 29) /* IntEn - Resume */ +#define UDCICR1_IESU (1 << 28) /* IntEn - Suspend */ +#define UDCICR1_IERS (1 << 27) /* IntEn - Reset */ + +#define UDCISR0 __REG(0x4060000C) /* UDC Interrupt Status Register 0 */ +#define UDCISR1 __REG(0x40600010) /* UDC Interrupt Status Register 1 */ +#define UDCISR_INT(n,intr) (((intr) & 0x03) << (((n) & 0x0F) * 2)) +#define UDCISR1_IRCC (1 << 31) /* IntReq - Configuration Change */ +#define UDCISR1_IRSOF (1 << 30) /* IntReq - Start of Frame */ +#define UDCISR1_IRRU (1 << 29) /* IntReq - Resume */ +#define UDCISR1_IRSU (1 << 28) /* IntReq - Suspend */ +#define UDCISR1_IRRS (1 << 27) /* IntReq - Reset */ + +#define UDCFNR __REG(0x40600014) /* UDC Frame Number Register */ +#define UDCOTGICR __REG(0x40600018) /* UDC On-The-Go interrupt control */ +#define UDCOTGICR_IESF (1 << 24) /* OTG SET_FEATURE command recvd */ +#define UDCOTGICR_IEXR (1 << 17) /* Extra Transciever Interrupt + Rising Edge Interrupt Enable */ +#define UDCOTGICR_IEXF (1 << 16) /* Extra Transciever Interrupt + Falling Edge Interrupt Enable */ +#define UDCOTGICR_IEVV40R (1 << 9) /* OTG Vbus Valid 4.0V Rising Edge + Interrupt Enable */ +#define UDCOTGICR_IEVV40F (1 << 8) /* OTG Vbus Valid 4.0V Falling Edge + Interrupt Enable */ +#define UDCOTGICR_IEVV44R (1 << 7) /* OTG Vbus Valid 4.4V Rising Edge + Interrupt Enable */ +#define UDCOTGICR_IEVV44F (1 << 6) /* OTG Vbus Valid 4.4V Falling Edge + Interrupt Enable */ +#define UDCOTGICR_IESVR (1 << 5) /* OTG Session Valid Rising Edge + Interrupt Enable */ +#define UDCOTGICR_IESVF (1 << 4) /* OTG Session Valid Falling Edge + Interrupt Enable */ +#define UDCOTGICR_IESDR (1 << 3) /* OTG A-Device SRP Detect Rising + Edge Interrupt Enable */ +#define UDCOTGICR_IESDF (1 << 2) /* OTG A-Device SRP Detect Falling + Edge Interrupt Enable */ +#define UDCOTGICR_IEIDR (1 << 1) /* OTG ID Change Rising Edge + Interrupt Enable */ +#define UDCOTGICR_IEIDF (1 << 0) /* OTG ID Change Falling Edge + Interrupt Enable */ + +#define UP2OCR __REG(0x40600020) /* USB Port 2 Output Control register */ + +#define UP2OCR_CPVEN (1 << 0) /* Charge Pump Vbus Enable */ +#define UP2OCR_CPVPE (1 << 1) /* Charge Pump Vbus Pulse Enable */ +#define UP2OCR_DPPDE (1 << 2) /* Host Port 2 Transceiver D+ Pull Down Enable */ +#define UP2OCR_DMPDE (1 << 3) /* Host Port 2 Transceiver D- Pull Down Enable */ +#define UP2OCR_DPPUE (1 << 4) /* Host Port 2 Transceiver D+ Pull Up Enable */ +#define UP2OCR_DMPUE (1 << 5) /* Host Port 2 Transceiver D- Pull Up Enable */ +#define UP2OCR_DPPUBE (1 << 6) /* Host Port 2 Transceiver D+ Pull Up Bypass Enable */ +#define UP2OCR_DMPUBE (1 << 7) /* Host Port 2 Transceiver D- Pull Up Bypass Enable */ +#define UP2OCR_EXSP (1 << 8) /* External Transceiver Speed Control */ +#define UP2OCR_EXSUS (1 << 9) /* External Transceiver Speed Enable */ +#define UP2OCR_IDON (1 << 10) /* OTG ID Read Enable */ +#define UP2OCR_HXS (1 << 16) /* Host Port 2 Transceiver Output Select */ +#define UP2OCR_HXOE (1 << 17) /* Host Port 2 Transceiver Output Enable */ +#define UP2OCR_SEOS (1 << 24) /* Single-Ended Output Select */ + +#define UDCCSN(x) __REG2(0x40600100, (x) << 2) +#define UDCCSR0 __REG(0x40600100) /* UDC Control/Status register - Endpoint 0 */ +#define UDCCSR0_SA (1 << 7) /* Setup Active */ +#define UDCCSR0_RNE (1 << 6) /* Receive FIFO Not Empty */ +#define UDCCSR0_FST (1 << 5) /* Force Stall */ +#define UDCCSR0_SST (1 << 4) /* Sent Stall */ +#define UDCCSR0_DME (1 << 3) /* DMA Enable */ +#define UDCCSR0_FTF (1 << 2) /* Flush Transmit FIFO */ +#define UDCCSR0_IPR (1 << 1) /* IN Packet Ready */ +#define UDCCSR0_OPC (1 << 0) /* OUT Packet Complete */ + +#define UDCCSRA __REG(0x40600104) /* UDC Control/Status register - Endpoint A */ +#define UDCCSRB __REG(0x40600108) /* UDC Control/Status register - Endpoint B */ +#define UDCCSRC __REG(0x4060010C) /* UDC Control/Status register - Endpoint C */ +#define UDCCSRD __REG(0x40600110) /* UDC Control/Status register - Endpoint D */ +#define UDCCSRE __REG(0x40600114) /* UDC Control/Status register - Endpoint E */ +#define UDCCSRF __REG(0x40600118) /* UDC Control/Status register - Endpoint F */ +#define UDCCSRG __REG(0x4060011C) /* UDC Control/Status register - Endpoint G */ +#define UDCCSRH __REG(0x40600120) /* UDC Control/Status register - Endpoint H */ +#define UDCCSRI __REG(0x40600124) /* UDC Control/Status register - Endpoint I */ +#define UDCCSRJ __REG(0x40600128) /* UDC Control/Status register - Endpoint J */ +#define UDCCSRK __REG(0x4060012C) /* UDC Control/Status register - Endpoint K */ +#define UDCCSRL __REG(0x40600130) /* UDC Control/Status register - Endpoint L */ +#define UDCCSRM __REG(0x40600134) /* UDC Control/Status register - Endpoint M */ +#define UDCCSRN __REG(0x40600138) /* UDC Control/Status register - Endpoint N */ +#define UDCCSRP __REG(0x4060013C) /* UDC Control/Status register - Endpoint P */ +#define UDCCSRQ __REG(0x40600140) /* UDC Control/Status register - Endpoint Q */ +#define UDCCSRR __REG(0x40600144) /* UDC Control/Status register - Endpoint R */ +#define UDCCSRS __REG(0x40600148) /* UDC Control/Status register - Endpoint S */ +#define UDCCSRT __REG(0x4060014C) /* UDC Control/Status register - Endpoint T */ +#define UDCCSRU __REG(0x40600150) /* UDC Control/Status register - Endpoint U */ +#define UDCCSRV __REG(0x40600154) /* UDC Control/Status register - Endpoint V */ +#define UDCCSRW __REG(0x40600158) /* UDC Control/Status register - Endpoint W */ +#define UDCCSRX __REG(0x4060015C) /* UDC Control/Status register - Endpoint X */ + +#define UDCCSR_DPE (1 << 9) /* Data Packet Error */ +#define UDCCSR_FEF (1 << 8) /* Flush Endpoint FIFO */ +#define UDCCSR_SP (1 << 7) /* Short Packet Control/Status */ +#define UDCCSR_BNE (1 << 6) /* Buffer Not Empty (IN endpoints) */ +#define UDCCSR_BNF (1 << 6) /* Buffer Not Full (OUT endpoints) */ +#define UDCCSR_FST (1 << 5) /* Force STALL */ +#define UDCCSR_SST (1 << 4) /* Sent STALL */ +#define UDCCSR_DME (1 << 3) /* DMA Enable */ +#define UDCCSR_TRN (1 << 2) /* Tx/Rx NAK */ +#define UDCCSR_PC (1 << 1) /* Packet Complete */ +#define UDCCSR_FS (1 << 0) /* FIFO needs service */ + +#define UDCBCN(x) __REG2(0x40600200, (x)<<2) +#define UDCBCR0 __REG(0x40600200) /* Byte Count Register - EP0 */ +#define UDCBCRA __REG(0x40600204) /* Byte Count Register - EPA */ +#define UDCBCRB __REG(0x40600208) /* Byte Count Register - EPB */ +#define UDCBCRC __REG(0x4060020C) /* Byte Count Register - EPC */ +#define UDCBCRD __REG(0x40600210) /* Byte Count Register - EPD */ +#define UDCBCRE __REG(0x40600214) /* Byte Count Register - EPE */ +#define UDCBCRF __REG(0x40600218) /* Byte Count Register - EPF */ +#define UDCBCRG __REG(0x4060021C) /* Byte Count Register - EPG */ +#define UDCBCRH __REG(0x40600220) /* Byte Count Register - EPH */ +#define UDCBCRI __REG(0x40600224) /* Byte Count Register - EPI */ +#define UDCBCRJ __REG(0x40600228) /* Byte Count Register - EPJ */ +#define UDCBCRK __REG(0x4060022C) /* Byte Count Register - EPK */ +#define UDCBCRL __REG(0x40600230) /* Byte Count Register - EPL */ +#define UDCBCRM __REG(0x40600234) /* Byte Count Register - EPM */ +#define UDCBCRN __REG(0x40600238) /* Byte Count Register - EPN */ +#define UDCBCRP __REG(0x4060023C) /* Byte Count Register - EPP */ +#define UDCBCRQ __REG(0x40600240) /* Byte Count Register - EPQ */ +#define UDCBCRR __REG(0x40600244) /* Byte Count Register - EPR */ +#define UDCBCRS __REG(0x40600248) /* Byte Count Register - EPS */ +#define UDCBCRT __REG(0x4060024C) /* Byte Count Register - EPT */ +#define UDCBCRU __REG(0x40600250) /* Byte Count Register - EPU */ +#define UDCBCRV __REG(0x40600254) /* Byte Count Register - EPV */ +#define UDCBCRW __REG(0x40600258) /* Byte Count Register - EPW */ +#define UDCBCRX __REG(0x4060025C) /* Byte Count Register - EPX */ + +#define UDCDN(x) __REG2(0x40600300, (x)<<2) +#define PHYS_UDCDN(x) (0x40600300 + ((x)<<2)) +#define PUDCDN(x) (volatile u32 *)(io_p2v(PHYS_UDCDN((x)))) +#define UDCDR0 __REG(0x40600300) /* Data Register - EP0 */ +#define UDCDRA __REG(0x40600304) /* Data Register - EPA */ +#define UDCDRB __REG(0x40600308) /* Data Register - EPB */ +#define UDCDRC __REG(0x4060030C) /* Data Register - EPC */ +#define UDCDRD __REG(0x40600310) /* Data Register - EPD */ +#define UDCDRE __REG(0x40600314) /* Data Register - EPE */ +#define UDCDRF __REG(0x40600318) /* Data Register - EPF */ +#define UDCDRG __REG(0x4060031C) /* Data Register - EPG */ +#define UDCDRH __REG(0x40600320) /* Data Register - EPH */ +#define UDCDRI __REG(0x40600324) /* Data Register - EPI */ +#define UDCDRJ __REG(0x40600328) /* Data Register - EPJ */ +#define UDCDRK __REG(0x4060032C) /* Data Register - EPK */ +#define UDCDRL __REG(0x40600330) /* Data Register - EPL */ +#define UDCDRM __REG(0x40600334) /* Data Register - EPM */ +#define UDCDRN __REG(0x40600338) /* Data Register - EPN */ +#define UDCDRP __REG(0x4060033C) /* Data Register - EPP */ +#define UDCDRQ __REG(0x40600340) /* Data Register - EPQ */ +#define UDCDRR __REG(0x40600344) /* Data Register - EPR */ +#define UDCDRS __REG(0x40600348) /* Data Register - EPS */ +#define UDCDRT __REG(0x4060034C) /* Data Register - EPT */ +#define UDCDRU __REG(0x40600350) /* Data Register - EPU */ +#define UDCDRV __REG(0x40600354) /* Data Register - EPV */ +#define UDCDRW __REG(0x40600358) /* Data Register - EPW */ +#define UDCDRX __REG(0x4060035C) /* Data Register - EPX */ + +#define UDCCN(x) __REG2(0x40600400, (x)<<2) +#define UDCCRA __REG(0x40600404) /* Configuration register EPA */ +#define UDCCRB __REG(0x40600408) /* Configuration register EPB */ +#define UDCCRC __REG(0x4060040C) /* Configuration register EPC */ +#define UDCCRD __REG(0x40600410) /* Configuration register EPD */ +#define UDCCRE __REG(0x40600414) /* Configuration register EPE */ +#define UDCCRF __REG(0x40600418) /* Configuration register EPF */ +#define UDCCRG __REG(0x4060041C) /* Configuration register EPG */ +#define UDCCRH __REG(0x40600420) /* Configuration register EPH */ +#define UDCCRI __REG(0x40600424) /* Configuration register EPI */ +#define UDCCRJ __REG(0x40600428) /* Configuration register EPJ */ +#define UDCCRK __REG(0x4060042C) /* Configuration register EPK */ +#define UDCCRL __REG(0x40600430) /* Configuration register EPL */ +#define UDCCRM __REG(0x40600434) /* Configuration register EPM */ +#define UDCCRN __REG(0x40600438) /* Configuration register EPN */ +#define UDCCRP __REG(0x4060043C) /* Configuration register EPP */ +#define UDCCRQ __REG(0x40600440) /* Configuration register EPQ */ +#define UDCCRR __REG(0x40600444) /* Configuration register EPR */ +#define UDCCRS __REG(0x40600448) /* Configuration register EPS */ +#define UDCCRT __REG(0x4060044C) /* Configuration register EPT */ +#define UDCCRU __REG(0x40600450) /* Configuration register EPU */ +#define UDCCRV __REG(0x40600454) /* Configuration register EPV */ +#define UDCCRW __REG(0x40600458) /* Configuration register EPW */ +#define UDCCRX __REG(0x4060045C) /* Configuration register EPX */ + +#define UDCCONR_CN (0x03 << 25) /* Configuration Number */ +#define UDCCONR_CN_S (25) +#define UDCCONR_IN (0x07 << 22) /* Interface Number */ +#define UDCCONR_IN_S (22) +#define UDCCONR_AISN (0x07 << 19) /* Alternate Interface Number */ +#define UDCCONR_AISN_S (19) +#define UDCCONR_EN (0x0f << 15) /* Endpoint Number */ +#define UDCCONR_EN_S (15) +#define UDCCONR_ET (0x03 << 13) /* Endpoint Type: */ +#define UDCCONR_ET_S (13) +#define UDCCONR_ET_INT (0x03 << 13) /* Interrupt */ +#define UDCCONR_ET_BULK (0x02 << 13) /* Bulk */ +#define UDCCONR_ET_ISO (0x01 << 13) /* Isochronous */ +#define UDCCONR_ET_NU (0x00 << 13) /* Not used */ +#define UDCCONR_ED (1 << 12) /* Endpoint Direction */ +#define UDCCONR_MPS (0x3ff << 2) /* Maximum Packet Size */ +#define UDCCONR_MPS_S (2) +#define UDCCONR_DE (1 << 1) /* Double Buffering Enable */ +#define UDCCONR_EE (1 << 0) /* Endpoint Enable */ + + +#define UDC_INT_FIFOERROR (0x2) +#define UDC_INT_PACKETCMP (0x1) + +#define UDC_FNR_MASK (0x7ff) + +#define UDCCSR_WR_MASK (UDCCSR_DME|UDCCSR_FST) +#define UDC_BCR_MASK (0x3ff) + +#endif -- cgit v1.2.3-70-g09d2 From 7a6aedfac98c6d54ecf97ca1ffb1e6a1f3d26aea Mon Sep 17 00:00:00 2001 From: Mike Travis Date: Tue, 25 Mar 2008 15:06:53 -0700 Subject: [CPUFREQ] change cpu freq arrays to per_cpu variables Change cpufreq_policy and cpufreq_governor pointer tables from arrays to per_cpu variables in the cpufreq subsystem. Also some minor complaints from checkpatch.pl fixed. Based on: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86.git Signed-off-by: Mike Travis Signed-off-by: Dave Jones --- drivers/cpufreq/cpufreq.c | 45 ++++++++++++++++++++++------------------- drivers/cpufreq/cpufreq_stats.c | 24 +++++++++++----------- drivers/cpufreq/freq_table.c | 12 +++++------ 3 files changed, 42 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 7fce038fa57..6b73d163fa8 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -38,10 +38,10 @@ * also protects the cpufreq_cpu_data array. */ static struct cpufreq_driver *cpufreq_driver; -static struct cpufreq_policy *cpufreq_cpu_data[NR_CPUS]; +static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data); #ifdef CONFIG_HOTPLUG_CPU /* This one keeps track of the previously set governor of a removed CPU */ -static struct cpufreq_governor *cpufreq_cpu_governor[NR_CPUS]; +static DEFINE_PER_CPU(struct cpufreq_governor *, cpufreq_cpu_governor); #endif static DEFINE_SPINLOCK(cpufreq_driver_lock); @@ -135,7 +135,7 @@ struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu) struct cpufreq_policy *data; unsigned long flags; - if (cpu >= NR_CPUS) + if (cpu >= nr_cpu_ids) goto err_out; /* get the cpufreq driver */ @@ -149,7 +149,7 @@ struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu) /* get the CPU */ - data = cpufreq_cpu_data[cpu]; + data = per_cpu(cpufreq_cpu_data, cpu); if (!data) goto err_out_put_module; @@ -327,7 +327,7 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state) dprintk("notification %u of frequency transition to %u kHz\n", state, freqs->new); - policy = cpufreq_cpu_data[freqs->cpu]; + policy = per_cpu(cpufreq_cpu_data, freqs->cpu); switch (state) { case CPUFREQ_PRECHANGE: @@ -828,8 +828,8 @@ static int cpufreq_add_dev(struct sys_device *sys_dev) #ifdef CONFIG_SMP #ifdef CONFIG_HOTPLUG_CPU - if (cpufreq_cpu_governor[cpu]){ - policy->governor = cpufreq_cpu_governor[cpu]; + if (per_cpu(cpufreq_cpu_governor, cpu)) { + policy->governor = per_cpu(cpufreq_cpu_governor, cpu); dprintk("Restoring governor %s for cpu %d\n", policy->governor->name, cpu); } @@ -854,7 +854,7 @@ static int cpufreq_add_dev(struct sys_device *sys_dev) spin_lock_irqsave(&cpufreq_driver_lock, flags); managed_policy->cpus = policy->cpus; - cpufreq_cpu_data[cpu] = managed_policy; + per_cpu(cpufreq_cpu_data, cpu) = managed_policy; spin_unlock_irqrestore(&cpufreq_driver_lock, flags); dprintk("CPU already managed, adding link\n"); @@ -899,7 +899,7 @@ static int cpufreq_add_dev(struct sys_device *sys_dev) spin_lock_irqsave(&cpufreq_driver_lock, flags); for_each_cpu_mask(j, policy->cpus) { - cpufreq_cpu_data[j] = policy; + per_cpu(cpufreq_cpu_data, j) = policy; per_cpu(policy_cpu, j) = policy->cpu; } spin_unlock_irqrestore(&cpufreq_driver_lock, flags); @@ -946,7 +946,7 @@ static int cpufreq_add_dev(struct sys_device *sys_dev) err_out_unregister: spin_lock_irqsave(&cpufreq_driver_lock, flags); for_each_cpu_mask(j, policy->cpus) - cpufreq_cpu_data[j] = NULL; + per_cpu(cpufreq_cpu_data, j) = NULL; spin_unlock_irqrestore(&cpufreq_driver_lock, flags); kobject_put(&policy->kobj); @@ -989,7 +989,7 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev) dprintk("unregistering CPU %u\n", cpu); spin_lock_irqsave(&cpufreq_driver_lock, flags); - data = cpufreq_cpu_data[cpu]; + data = per_cpu(cpufreq_cpu_data, cpu); if (!data) { spin_unlock_irqrestore(&cpufreq_driver_lock, flags); @@ -997,7 +997,7 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev) unlock_policy_rwsem_write(cpu); return -EINVAL; } - cpufreq_cpu_data[cpu] = NULL; + per_cpu(cpufreq_cpu_data, cpu) = NULL; #ifdef CONFIG_SMP @@ -1019,19 +1019,19 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev) #ifdef CONFIG_SMP #ifdef CONFIG_HOTPLUG_CPU - cpufreq_cpu_governor[cpu] = data->governor; + per_cpu(cpufreq_cpu_governor, cpu) = data->governor; #endif /* if we have other CPUs still registered, we need to unlink them, * or else wait_for_completion below will lock up. Clean the - * cpufreq_cpu_data[] while holding the lock, and remove the sysfs - * links afterwards. + * per_cpu(cpufreq_cpu_data) while holding the lock, and remove + * the sysfs links afterwards. */ if (unlikely(cpus_weight(data->cpus) > 1)) { for_each_cpu_mask(j, data->cpus) { if (j == cpu) continue; - cpufreq_cpu_data[j] = NULL; + per_cpu(cpufreq_cpu_data, j) = NULL; } } @@ -1043,7 +1043,7 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev) continue; dprintk("removing link for cpu %u\n", j); #ifdef CONFIG_HOTPLUG_CPU - cpufreq_cpu_governor[j] = data->governor; + per_cpu(cpufreq_cpu_governor, j) = data->governor; #endif cpu_sys_dev = get_cpu_sysdev(j); sysfs_remove_link(&cpu_sys_dev->kobj, "cpufreq"); @@ -1153,7 +1153,7 @@ EXPORT_SYMBOL(cpufreq_quick_get); static unsigned int __cpufreq_get(unsigned int cpu) { - struct cpufreq_policy *policy = cpufreq_cpu_data[cpu]; + struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu); unsigned int ret_freq = 0; if (!cpufreq_driver->get) @@ -1822,16 +1822,19 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) cpufreq_driver = driver_data; spin_unlock_irqrestore(&cpufreq_driver_lock, flags); - ret = sysdev_driver_register(&cpu_sysdev_class,&cpufreq_sysdev_driver); + ret = sysdev_driver_register(&cpu_sysdev_class, + &cpufreq_sysdev_driver); if ((!ret) && !(cpufreq_driver->flags & CPUFREQ_STICKY)) { int i; ret = -ENODEV; /* check for at least one working CPU */ - for (i=0; iinit() calls failed, unregister */ if (ret) { diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index ae70d63a8b2..c0ff97d375d 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -43,7 +43,7 @@ struct cpufreq_stats { #endif }; -static struct cpufreq_stats *cpufreq_stats_table[NR_CPUS]; +static DEFINE_PER_CPU(struct cpufreq_stats *, cpufreq_stats_table); struct cpufreq_stats_attribute { struct attribute attr; @@ -58,7 +58,7 @@ cpufreq_stats_update (unsigned int cpu) cur_time = get_jiffies_64(); spin_lock(&cpufreq_stats_lock); - stat = cpufreq_stats_table[cpu]; + stat = per_cpu(cpufreq_stats_table, cpu); if (stat->time_in_state) stat->time_in_state[stat->last_index] = cputime64_add(stat->time_in_state[stat->last_index], @@ -71,11 +71,11 @@ cpufreq_stats_update (unsigned int cpu) static ssize_t show_total_trans(struct cpufreq_policy *policy, char *buf) { - struct cpufreq_stats *stat = cpufreq_stats_table[policy->cpu]; + struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu); if (!stat) return 0; return sprintf(buf, "%d\n", - cpufreq_stats_table[stat->cpu]->total_trans); + per_cpu(cpufreq_stats_table, stat->cpu)->total_trans); } static ssize_t @@ -83,7 +83,7 @@ show_time_in_state(struct cpufreq_policy *policy, char *buf) { ssize_t len = 0; int i; - struct cpufreq_stats *stat = cpufreq_stats_table[policy->cpu]; + struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu); if (!stat) return 0; cpufreq_stats_update(stat->cpu); @@ -101,7 +101,7 @@ show_trans_table(struct cpufreq_policy *policy, char *buf) ssize_t len = 0; int i, j; - struct cpufreq_stats *stat = cpufreq_stats_table[policy->cpu]; + struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu); if (!stat) return 0; cpufreq_stats_update(stat->cpu); @@ -170,7 +170,7 @@ freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq) static void cpufreq_stats_free_table(unsigned int cpu) { - struct cpufreq_stats *stat = cpufreq_stats_table[cpu]; + struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, cpu); struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); if (policy && policy->cpu == cpu) sysfs_remove_group(&policy->kobj, &stats_attr_group); @@ -178,7 +178,7 @@ static void cpufreq_stats_free_table(unsigned int cpu) kfree(stat->time_in_state); kfree(stat); } - cpufreq_stats_table[cpu] = NULL; + per_cpu(cpufreq_stats_table, cpu) = NULL; if (policy) cpufreq_cpu_put(policy); } @@ -192,7 +192,7 @@ cpufreq_stats_create_table (struct cpufreq_policy *policy, struct cpufreq_policy *data; unsigned int alloc_size; unsigned int cpu = policy->cpu; - if (cpufreq_stats_table[cpu]) + if (per_cpu(cpufreq_stats_table, cpu)) return -EBUSY; if ((stat = kzalloc(sizeof(struct cpufreq_stats), GFP_KERNEL)) == NULL) return -ENOMEM; @@ -207,7 +207,7 @@ cpufreq_stats_create_table (struct cpufreq_policy *policy, goto error_out; stat->cpu = cpu; - cpufreq_stats_table[cpu] = stat; + per_cpu(cpufreq_stats_table, cpu) = stat; for (i=0; table[i].frequency != CPUFREQ_TABLE_END; i++) { unsigned int freq = table[i].frequency; @@ -251,7 +251,7 @@ error_out: cpufreq_cpu_put(data); error_get_fail: kfree(stat); - cpufreq_stats_table[cpu] = NULL; + per_cpu(cpufreq_stats_table, cpu) = NULL; return ret; } @@ -284,7 +284,7 @@ cpufreq_stat_notifier_trans (struct notifier_block *nb, unsigned long val, if (val != CPUFREQ_POSTCHANGE) return 0; - stat = cpufreq_stats_table[freq->cpu]; + stat = per_cpu(cpufreq_stats_table, freq->cpu); if (!stat) return 0; diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c index ae6cd60d5c1..fe485c9515d 100644 --- a/drivers/cpufreq/freq_table.c +++ b/drivers/cpufreq/freq_table.c @@ -169,7 +169,7 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy, } EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target); -static struct cpufreq_frequency_table *show_table[NR_CPUS]; +static DEFINE_PER_CPU(struct cpufreq_frequency_table *, show_table); /** * show_available_freqs - show available frequencies for the specified CPU */ @@ -180,10 +180,10 @@ static ssize_t show_available_freqs (struct cpufreq_policy *policy, char *buf) ssize_t count = 0; struct cpufreq_frequency_table *table; - if (!show_table[cpu]) + if (!per_cpu(show_table, cpu)) return -ENODEV; - table = show_table[cpu]; + table = per_cpu(show_table, cpu); for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { if (table[i].frequency == CPUFREQ_ENTRY_INVALID) @@ -212,20 +212,20 @@ void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table, unsigned int cpu) { dprintk("setting show_table for cpu %u to %p\n", cpu, table); - show_table[cpu] = table; + per_cpu(show_table, cpu) = table; } EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_attr); void cpufreq_frequency_table_put_attr(unsigned int cpu) { dprintk("clearing show_table for cpu %u\n", cpu); - show_table[cpu] = NULL; + per_cpu(show_table, cpu) = NULL; } EXPORT_SYMBOL_GPL(cpufreq_frequency_table_put_attr); struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu) { - return show_table[cpu]; + return per_cpu(show_table, cpu); } EXPORT_SYMBOL_GPL(cpufreq_frequency_get_table); -- cgit v1.2.3-70-g09d2 From d1659fcc59b21ec442564fedb67a5ad371f82380 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 20 May 2008 12:17:39 -0400 Subject: Input: remove CVS keywords This patch removes CVS keywords that weren't updated for a long time from comments. Signed-off-by: Adrian Bunk Signed-off-by: Dmitry Torokhov --- Documentation/input/gameport-programming.txt | 2 -- Documentation/input/input.txt | 1 - Documentation/input/joystick-api.txt | 2 -- Documentation/input/joystick-parport.txt | 1 - Documentation/input/joystick.txt | 1 - drivers/input/evbug.c | 2 -- drivers/input/gameport/emu10k1-gp.c | 2 -- drivers/input/gameport/lightning.c | 2 -- drivers/input/gameport/ns558.c | 2 -- drivers/input/joystick/a3d.c | 2 -- drivers/input/joystick/amijoy.c | 2 -- drivers/input/joystick/cobra.c | 2 -- drivers/input/joystick/db9.c | 2 -- drivers/input/joystick/gf2k.c | 2 -- drivers/input/joystick/grip.c | 2 -- drivers/input/joystick/grip_mp.c | 2 -- drivers/input/joystick/guillemot.c | 2 -- drivers/input/joystick/iforce/iforce-ff.c | 2 -- drivers/input/joystick/iforce/iforce-main.c | 2 -- drivers/input/joystick/iforce/iforce-packets.c | 2 -- drivers/input/joystick/iforce/iforce-serio.c | 2 -- drivers/input/joystick/iforce/iforce-usb.c | 2 -- drivers/input/joystick/iforce/iforce.h | 2 -- drivers/input/joystick/interact.c | 2 -- drivers/input/joystick/joydump.c | 2 -- drivers/input/joystick/magellan.c | 2 -- drivers/input/joystick/spaceball.c | 2 -- drivers/input/joystick/spaceorb.c | 2 -- drivers/input/joystick/stinger.c | 2 -- drivers/input/joystick/tmdc.c | 2 -- drivers/input/joystick/turbografx.c | 2 -- drivers/input/joystick/twidjoy.c | 4 ---- drivers/input/joystick/warrior.c | 2 -- drivers/input/keyboard/amikbd.c | 2 -- drivers/input/keyboard/sunkbd.c | 2 -- drivers/input/keyboard/xtkbd.c | 2 -- drivers/input/mouse/inport.c | 2 -- drivers/input/mouse/logibm.c | 2 -- drivers/input/mouse/pc110pad.c | 2 -- drivers/input/mouse/sermouse.c | 2 -- drivers/input/serio/ct82c710.c | 2 -- drivers/input/serio/q40kbd.c | 2 -- drivers/input/serio/rpckbd.c | 2 -- drivers/input/touchscreen/gunze.c | 2 -- drivers/input/touchscreen/h3600_ts_input.c | 2 -- include/linux/joystick.h | 2 -- 46 files changed, 91 deletions(-) (limited to 'drivers') diff --git a/Documentation/input/gameport-programming.txt b/Documentation/input/gameport-programming.txt index 14e0a8b7022..03a74fc3b49 100644 --- a/Documentation/input/gameport-programming.txt +++ b/Documentation/input/gameport-programming.txt @@ -1,5 +1,3 @@ -$Id: gameport-programming.txt,v 1.3 2001/04/24 13:51:37 vojtech Exp $ - Programming gameport drivers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/Documentation/input/input.txt b/Documentation/input/input.txt index ff8cea0225f..686ee9932df 100644 --- a/Documentation/input/input.txt +++ b/Documentation/input/input.txt @@ -1,7 +1,6 @@ Linux Input drivers v1.0 (c) 1999-2001 Vojtech Pavlik Sponsored by SuSE - $Id: input.txt,v 1.8 2002/05/29 03:15:01 bradleym Exp $ ---------------------------------------------------------------------------- 0. Disclaimer diff --git a/Documentation/input/joystick-api.txt b/Documentation/input/joystick-api.txt index acbd32b8845..c507330740c 100644 --- a/Documentation/input/joystick-api.txt +++ b/Documentation/input/joystick-api.txt @@ -5,8 +5,6 @@ 7 Aug 1998 - $Id: joystick-api.txt,v 1.2 2001/05/08 21:21:23 vojtech Exp $ - 1. Initialization ~~~~~~~~~~~~~~~~~ diff --git a/Documentation/input/joystick-parport.txt b/Documentation/input/joystick-parport.txt index ede5f33daad..1c856f32ff2 100644 --- a/Documentation/input/joystick-parport.txt +++ b/Documentation/input/joystick-parport.txt @@ -2,7 +2,6 @@ (c) 1998-2000 Vojtech Pavlik (c) 1998 Andree Borrmann Sponsored by SuSE - $Id: joystick-parport.txt,v 1.6 2001/09/25 09:31:32 vojtech Exp $ ---------------------------------------------------------------------------- 0. Disclaimer diff --git a/Documentation/input/joystick.txt b/Documentation/input/joystick.txt index 389de9bd987..154d767b2ac 100644 --- a/Documentation/input/joystick.txt +++ b/Documentation/input/joystick.txt @@ -1,7 +1,6 @@ Linux Joystick driver v2.0.0 (c) 1996-2000 Vojtech Pavlik Sponsored by SuSE - $Id: joystick.txt,v 1.12 2002/03/03 12:13:07 jdeneux Exp $ ---------------------------------------------------------------------------- 0. Disclaimer diff --git a/drivers/input/evbug.c b/drivers/input/evbug.c index c21f2f12723..67754c776d8 100644 --- a/drivers/input/evbug.c +++ b/drivers/input/evbug.c @@ -1,6 +1,4 @@ /* - * $Id: evbug.c,v 1.10 2001/09/25 10:12:07 vojtech Exp $ - * * Copyright (c) 1999-2001 Vojtech Pavlik */ diff --git a/drivers/input/gameport/emu10k1-gp.c b/drivers/input/gameport/emu10k1-gp.c index 9793ac36d17..b04930f7ea7 100644 --- a/drivers/input/gameport/emu10k1-gp.c +++ b/drivers/input/gameport/emu10k1-gp.c @@ -1,6 +1,4 @@ /* - * $Id: emu10k1-gp.c,v 1.8 2002/01/22 20:40:46 vojtech Exp $ - * * Copyright (c) 2001 Vojtech Pavlik */ diff --git a/drivers/input/gameport/lightning.c b/drivers/input/gameport/lightning.c index 6b4d4561d46..06ad36ed348 100644 --- a/drivers/input/gameport/lightning.c +++ b/drivers/input/gameport/lightning.c @@ -1,6 +1,4 @@ /* - * $Id: lightning.c,v 1.20 2002/01/22 20:41:31 vojtech Exp $ - * * Copyright (c) 1998-2001 Vojtech Pavlik */ diff --git a/drivers/input/gameport/ns558.c b/drivers/input/gameport/ns558.c index 7b7a546323c..2b282cde4b8 100644 --- a/drivers/input/gameport/ns558.c +++ b/drivers/input/gameport/ns558.c @@ -1,6 +1,4 @@ /* - * $Id: ns558.c,v 1.43 2002/01/24 19:23:21 vojtech Exp $ - * * Copyright (c) 1999-2001 Vojtech Pavlik * Copyright (c) 1999 Brian Gerst */ diff --git a/drivers/input/joystick/a3d.c b/drivers/input/joystick/a3d.c index 52ba16f487c..92498d470b1 100644 --- a/drivers/input/joystick/a3d.c +++ b/drivers/input/joystick/a3d.c @@ -1,6 +1,4 @@ /* - * $Id: a3d.c,v 1.21 2002/01/22 20:11:50 vojtech Exp $ - * * Copyright (c) 1998-2001 Vojtech Pavlik */ diff --git a/drivers/input/joystick/amijoy.c b/drivers/input/joystick/amijoy.c index deb9f825f92..05022f07ec7 100644 --- a/drivers/input/joystick/amijoy.c +++ b/drivers/input/joystick/amijoy.c @@ -1,6 +1,4 @@ /* - * $Id: amijoy.c,v 1.13 2002/01/22 20:26:32 vojtech Exp $ - * * Copyright (c) 1998-2001 Vojtech Pavlik */ diff --git a/drivers/input/joystick/cobra.c b/drivers/input/joystick/cobra.c index 55646a6d89f..639b975a8ed 100644 --- a/drivers/input/joystick/cobra.c +++ b/drivers/input/joystick/cobra.c @@ -1,6 +1,4 @@ /* - * $Id: cobra.c,v 1.19 2002/01/22 20:26:52 vojtech Exp $ - * * Copyright (c) 1999-2001 Vojtech Pavlik */ diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c index 960e501c60c..52395948475 100644 --- a/drivers/input/joystick/db9.c +++ b/drivers/input/joystick/db9.c @@ -1,6 +1,4 @@ /* - * $Id: db9.c,v 1.13 2002/04/07 20:13:37 vojtech Exp $ - * * Copyright (c) 1999-2001 Vojtech Pavlik * * Based on the work of: diff --git a/drivers/input/joystick/gf2k.c b/drivers/input/joystick/gf2k.c index 1f6302c0eb3..cb6eef1f2d9 100644 --- a/drivers/input/joystick/gf2k.c +++ b/drivers/input/joystick/gf2k.c @@ -1,6 +1,4 @@ /* - * $Id: gf2k.c,v 1.19 2002/01/22 20:27:43 vojtech Exp $ - * * Copyright (c) 1998-2001 Vojtech Pavlik */ diff --git a/drivers/input/joystick/grip.c b/drivers/input/joystick/grip.c index fd3853ab1aa..684e07cfccc 100644 --- a/drivers/input/joystick/grip.c +++ b/drivers/input/joystick/grip.c @@ -1,6 +1,4 @@ /* - * $Id: grip.c,v 1.21 2002/01/22 20:27:57 vojtech Exp $ - * * Copyright (c) 1998-2001 Vojtech Pavlik */ diff --git a/drivers/input/joystick/grip_mp.c b/drivers/input/joystick/grip_mp.c index c57e21d68c0..8279481b16e 100644 --- a/drivers/input/joystick/grip_mp.c +++ b/drivers/input/joystick/grip_mp.c @@ -1,6 +1,4 @@ /* - * $Id: grip_mp.c,v 1.9 2002/07/20 19:28:45 bonnland Exp $ - * * Driver for the Gravis Grip Multiport, a gamepad "hub" that * connects up to four 9-pin digital gamepads/joysticks. * Driver tested on SMP and UP kernel versions 2.4.18-4 and 2.4.18-5. diff --git a/drivers/input/joystick/guillemot.c b/drivers/input/joystick/guillemot.c index aa6bfb3fb8c..25ec3fad9f2 100644 --- a/drivers/input/joystick/guillemot.c +++ b/drivers/input/joystick/guillemot.c @@ -1,6 +1,4 @@ /* - * $Id: guillemot.c,v 1.10 2002/01/22 20:28:12 vojtech Exp $ - * * Copyright (c) 2001 Vojtech Pavlik */ diff --git a/drivers/input/joystick/iforce/iforce-ff.c b/drivers/input/joystick/iforce/iforce-ff.c index f2a4381d0ab..7839b7b6fa9 100644 --- a/drivers/input/joystick/iforce/iforce-ff.c +++ b/drivers/input/joystick/iforce/iforce-ff.c @@ -1,6 +1,4 @@ /* - * $Id: iforce-ff.c,v 1.9 2002/02/02 19:28:35 jdeneux Exp $ - * * Copyright (c) 2000-2002 Vojtech Pavlik * Copyright (c) 2001-2002, 2007 Johann Deneux * diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c index a2517fa72eb..61ee6e38739 100644 --- a/drivers/input/joystick/iforce/iforce-main.c +++ b/drivers/input/joystick/iforce/iforce-main.c @@ -1,6 +1,4 @@ /* - * $Id: iforce-main.c,v 1.19 2002/07/07 10:22:50 jdeneux Exp $ - * * Copyright (c) 2000-2002 Vojtech Pavlik * Copyright (c) 2001-2002, 2007 Johann Deneux * diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c index 45c4939ced7..015b50aa76f 100644 --- a/drivers/input/joystick/iforce/iforce-packets.c +++ b/drivers/input/joystick/iforce/iforce-packets.c @@ -1,6 +1,4 @@ /* - * $Id: iforce-packets.c,v 1.16 2002/07/07 10:22:50 jdeneux Exp $ - * * Copyright (c) 2000-2002 Vojtech Pavlik * Copyright (c) 2001-2002, 2007 Johann Deneux * diff --git a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c index 7b4bc19cef2..46d5041d2d9 100644 --- a/drivers/input/joystick/iforce/iforce-serio.c +++ b/drivers/input/joystick/iforce/iforce-serio.c @@ -1,6 +1,4 @@ /* - * $Id: iforce-serio.c,v 1.4 2002/01/28 22:45:00 jdeneux Exp $ - * * Copyright (c) 2000-2001 Vojtech Pavlik * Copyright (c) 2001, 2007 Johann Deneux * diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c index 8f6a987ebb9..851cc4087c2 100644 --- a/drivers/input/joystick/iforce/iforce-usb.c +++ b/drivers/input/joystick/iforce/iforce-usb.c @@ -1,6 +1,4 @@ /* - * $Id: iforce-usb.c,v 1.16 2002/06/09 11:08:04 jdeneux Exp $ - * * Copyright (c) 2000-2002 Vojtech Pavlik * Copyright (c) 2001-2002, 2007 Johann Deneux * diff --git a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h index a964a7cfd21..f2d91f4028c 100644 --- a/drivers/input/joystick/iforce/iforce.h +++ b/drivers/input/joystick/iforce/iforce.h @@ -1,6 +1,4 @@ /* - * $Id: iforce.h,v 1.13 2002/07/07 10:22:50 jdeneux Exp $ - * * Copyright (c) 2000-2002 Vojtech Pavlik * Copyright (c) 2001-2002, 2007 Johann Deneux * diff --git a/drivers/input/joystick/interact.c b/drivers/input/joystick/interact.c index bc8ea95dfd0..8c3290b6820 100644 --- a/drivers/input/joystick/interact.c +++ b/drivers/input/joystick/interact.c @@ -1,6 +1,4 @@ /* - * $Id: interact.c,v 1.16 2002/01/22 20:28:25 vojtech Exp $ - * * Copyright (c) 2001 Vojtech Pavlik * * Based on the work of: diff --git a/drivers/input/joystick/joydump.c b/drivers/input/joystick/joydump.c index 88ec5a918f2..2a1b82c8b31 100644 --- a/drivers/input/joystick/joydump.c +++ b/drivers/input/joystick/joydump.c @@ -1,6 +1,4 @@ /* - * $Id: joydump.c,v 1.1 2002/01/23 06:56:16 jsimmons Exp $ - * * Copyright (c) 1996-2001 Vojtech Pavlik */ diff --git a/drivers/input/joystick/magellan.c b/drivers/input/joystick/magellan.c index 54e676948eb..40e40780747 100644 --- a/drivers/input/joystick/magellan.c +++ b/drivers/input/joystick/magellan.c @@ -1,6 +1,4 @@ /* - * $Id: magellan.c,v 1.16 2002/01/22 20:28:39 vojtech Exp $ - * * Copyright (c) 1999-2001 Vojtech Pavlik */ diff --git a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c index d4087fd4965..0cd9b29356a 100644 --- a/drivers/input/joystick/spaceball.c +++ b/drivers/input/joystick/spaceball.c @@ -1,6 +1,4 @@ /* - * $Id: spaceball.c,v 1.17 2002/01/22 20:29:03 vojtech Exp $ - * * Copyright (c) 1999-2001 Vojtech Pavlik * * Based on the work of: diff --git a/drivers/input/joystick/spaceorb.c b/drivers/input/joystick/spaceorb.c index f7ce4004f4b..a694bf8e557 100644 --- a/drivers/input/joystick/spaceorb.c +++ b/drivers/input/joystick/spaceorb.c @@ -1,6 +1,4 @@ /* - * $Id: spaceorb.c,v 1.15 2002/01/22 20:29:19 vojtech Exp $ - * * Copyright (c) 1999-2001 Vojtech Pavlik * * Based on the work of: diff --git a/drivers/input/joystick/stinger.c b/drivers/input/joystick/stinger.c index baa10b2f7ba..e0db9f5e4b4 100644 --- a/drivers/input/joystick/stinger.c +++ b/drivers/input/joystick/stinger.c @@ -1,6 +1,4 @@ /* - * $Id: stinger.c,v 1.10 2002/01/22 20:29:31 vojtech Exp $ - * * Copyright (c) 2000-2001 Vojtech Pavlik * Copyright (c) 2000 Mark Fletcher */ diff --git a/drivers/input/joystick/tmdc.c b/drivers/input/joystick/tmdc.c index 0feeb8acb53..60c37bcb938 100644 --- a/drivers/input/joystick/tmdc.c +++ b/drivers/input/joystick/tmdc.c @@ -1,6 +1,4 @@ /* - * $Id: tmdc.c,v 1.31 2002/01/22 20:29:52 vojtech Exp $ - * * Copyright (c) 1998-2001 Vojtech Pavlik * * Based on the work of: diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c index 989483f5316..b6f85986954 100644 --- a/drivers/input/joystick/turbografx.c +++ b/drivers/input/joystick/turbografx.c @@ -1,6 +1,4 @@ /* - * $Id: turbografx.c,v 1.14 2002/01/22 20:30:39 vojtech Exp $ - * * Copyright (c) 1998-2001 Vojtech Pavlik * * Based on the work of: diff --git a/drivers/input/joystick/twidjoy.c b/drivers/input/joystick/twidjoy.c index 1085c841fec..3f4ec73c955 100644 --- a/drivers/input/joystick/twidjoy.c +++ b/drivers/input/joystick/twidjoy.c @@ -1,8 +1,4 @@ /* - * $Id: twidjoy.c,v 1.5 2002/01/22 20:31:53 vojtech Exp $ - * - * derived from CVS-ID "stinger.c,v 1.5 2001/05/29 12:57:18 vojtech Exp" - * * Copyright (c) 2001 Arndt Schoenewald * Copyright (c) 2000-2001 Vojtech Pavlik * Copyright (c) 2000 Mark Fletcher diff --git a/drivers/input/joystick/warrior.c b/drivers/input/joystick/warrior.c index e928b6e3724..f72c83e15e6 100644 --- a/drivers/input/joystick/warrior.c +++ b/drivers/input/joystick/warrior.c @@ -1,6 +1,4 @@ /* - * $Id: warrior.c,v 1.14 2002/01/22 20:32:10 vojtech Exp $ - * * Copyright (c) 1999-2001 Vojtech Pavlik */ diff --git a/drivers/input/keyboard/amikbd.c b/drivers/input/keyboard/amikbd.c index 81bf7562aca..35149ec455a 100644 --- a/drivers/input/keyboard/amikbd.c +++ b/drivers/input/keyboard/amikbd.c @@ -1,6 +1,4 @@ /* - * $Id: amikbd.c,v 1.13 2002/02/01 16:02:24 vojtech Exp $ - * * Copyright (c) 2000-2001 Vojtech Pavlik * * Based on the work of: diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c index be0f5d19d02..9fce6d1e29b 100644 --- a/drivers/input/keyboard/sunkbd.c +++ b/drivers/input/keyboard/sunkbd.c @@ -1,6 +1,4 @@ /* - * $Id: sunkbd.c,v 1.14 2001/09/25 10:12:07 vojtech Exp $ - * * Copyright (c) 1999-2001 Vojtech Pavlik */ diff --git a/drivers/input/keyboard/xtkbd.c b/drivers/input/keyboard/xtkbd.c index 152a2c07050..37b01d777a4 100644 --- a/drivers/input/keyboard/xtkbd.c +++ b/drivers/input/keyboard/xtkbd.c @@ -1,6 +1,4 @@ /* - * $Id: xtkbd.c,v 1.11 2001/09/25 10:12:07 vojtech Exp $ - * * Copyright (c) 1999-2001 Vojtech Pavlik */ diff --git a/drivers/input/mouse/inport.c b/drivers/input/mouse/inport.c index 06c35fc553c..3827a22362d 100644 --- a/drivers/input/mouse/inport.c +++ b/drivers/input/mouse/inport.c @@ -1,6 +1,4 @@ /* - * $Id: inport.c,v 1.11 2001/09/25 10:12:07 vojtech Exp $ - * * Copyright (c) 1999-2001 Vojtech Pavlik * * Based on the work of: diff --git a/drivers/input/mouse/logibm.c b/drivers/input/mouse/logibm.c index 9ea895593b2..e2413113df2 100644 --- a/drivers/input/mouse/logibm.c +++ b/drivers/input/mouse/logibm.c @@ -1,6 +1,4 @@ /* - * $Id: logibm.c,v 1.11 2001/09/25 10:12:07 vojtech Exp $ - * * Copyright (c) 1999-2001 Vojtech Pavlik * * Based on the work of: diff --git a/drivers/input/mouse/pc110pad.c b/drivers/input/mouse/pc110pad.c index 61cff8374e6..fd09c8df81f 100644 --- a/drivers/input/mouse/pc110pad.c +++ b/drivers/input/mouse/pc110pad.c @@ -1,6 +1,4 @@ /* - * $Id: pc110pad.c,v 1.12 2001/09/25 10:12:07 vojtech Exp $ - * * Copyright (c) 2000-2001 Vojtech Pavlik * * Based on the work of: diff --git a/drivers/input/mouse/sermouse.c b/drivers/input/mouse/sermouse.c index ed917bfd086..17ff137b9bd 100644 --- a/drivers/input/mouse/sermouse.c +++ b/drivers/input/mouse/sermouse.c @@ -1,6 +1,4 @@ /* - * $Id: sermouse.c,v 1.17 2002/03/13 10:03:43 vojtech Exp $ - * * Copyright (c) 1999-2001 Vojtech Pavlik */ diff --git a/drivers/input/serio/ct82c710.c b/drivers/input/serio/ct82c710.c index 0d35018c23a..d1380fc72cc 100644 --- a/drivers/input/serio/ct82c710.c +++ b/drivers/input/serio/ct82c710.c @@ -1,6 +1,4 @@ /* - * $Id: ct82c710.c,v 1.11 2001/09/25 10:12:07 vojtech Exp $ - * * Copyright (c) 1999-2001 Vojtech Pavlik */ diff --git a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c index cb89aff2e16..eca125c8d53 100644 --- a/drivers/input/serio/q40kbd.c +++ b/drivers/input/serio/q40kbd.c @@ -1,6 +1,4 @@ /* - * $Id: q40kbd.c,v 1.12 2002/02/02 22:26:44 vojtech Exp $ - * * Copyright (c) 2000-2001 Vojtech Pavlik * * Based on the work of: diff --git a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c index 34c59d9c620..1567b778247 100644 --- a/drivers/input/serio/rpckbd.c +++ b/drivers/input/serio/rpckbd.c @@ -1,6 +1,4 @@ /* - * $Id: rpckbd.c,v 1.7 2001/09/25 10:12:07 vojtech Exp $ - * * Copyright (c) 2000-2001 Vojtech Pavlik * Copyright (c) 2002 Russell King */ diff --git a/drivers/input/touchscreen/gunze.c b/drivers/input/touchscreen/gunze.c index a48a15868c4..a54f90e02ab 100644 --- a/drivers/input/touchscreen/gunze.c +++ b/drivers/input/touchscreen/gunze.c @@ -1,6 +1,4 @@ /* - * $Id: gunze.c,v 1.12 2001/09/25 10:12:07 vojtech Exp $ - * * Copyright (c) 2000-2001 Vojtech Pavlik */ diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c index 28ae15ed12c..4f86081dc7f 100644 --- a/drivers/input/touchscreen/h3600_ts_input.c +++ b/drivers/input/touchscreen/h3600_ts_input.c @@ -1,6 +1,4 @@ /* - * $Id: h3600_ts_input.c,v 1.4 2002/01/23 06:39:37 jsimmons Exp $ - * * Copyright (c) 2001 "Crazy" James Simmons jsimmons@transvirtual.com * * Sponsored by Transvirtual Technology. diff --git a/include/linux/joystick.h b/include/linux/joystick.h index e2d3a18af45..b5e051295a6 100644 --- a/include/linux/joystick.h +++ b/include/linux/joystick.h @@ -2,8 +2,6 @@ #define _LINUX_JOYSTICK_H /* - * $Id: joystick.h,v 1.3 2000/11/30 11:07:05 vojtech Exp $ - * * Copyright (C) 1996-2000 Vojtech Pavlik * * Sponsored by SuSE -- cgit v1.2.3-70-g09d2 From 5a6e59991b82580c3ca00115603b85762ec76104 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 10 May 2008 13:41:32 +0200 Subject: rt2x00: trim skb_frame_desc to 32 bytes Remove frame_type from skb_frame_desc and pass it as argument to rt2x00debug_dump_frame(). Change data_len and desc_len to unsigned short to save another 4 bytes in skb_frame_desc. Note that this was the only location where the data_len and desc_len was not yet treated as unsigned short. This trim is required to help mac80211 with adding the TX control and TX status informtation into the skb->cb structure. When that happens, drivers will have approximately 40 bytes left to use freely. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00debug.c | 4 ++-- drivers/net/wireless/rt2x00/rt2x00dev.c | 13 ++++--------- drivers/net/wireless/rt2x00/rt2x00lib.h | 6 +++++- drivers/net/wireless/rt2x00/rt2x00queue.h | 7 ++----- 4 files changed, 13 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c index bfab3b8780d..bd92cb8e68e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c @@ -115,7 +115,7 @@ struct rt2x00debug_intf { }; void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, - struct sk_buff *skb) + enum rt2x00_dump_type type, struct sk_buff *skb) { struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf; struct skb_frame_desc *desc = get_skb_frame_desc(skb); @@ -148,7 +148,7 @@ void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, dump_hdr->chip_rt = cpu_to_le16(rt2x00dev->chip.rt); dump_hdr->chip_rf = cpu_to_le16(rt2x00dev->chip.rf); dump_hdr->chip_rev = cpu_to_le32(rt2x00dev->chip.rev); - dump_hdr->type = cpu_to_le16(desc->frame_type); + dump_hdr->type = cpu_to_le16(type); dump_hdr->queue_index = desc->entry->queue->qid; dump_hdr->entry_index = desc->entry->entry_idx; dump_hdr->timestamp_sec = cpu_to_le32(timestamp.tv_sec); diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 3a49c256789..ea130f2eb00 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -28,7 +28,6 @@ #include "rt2x00.h" #include "rt2x00lib.h" -#include "rt2x00dump.h" /* * Link tuning handlers @@ -540,11 +539,9 @@ void rt2x00lib_txdone(struct queue_entry *entry, * If send to mac80211, mac80211 will clean up the skb structure, * otherwise we have to do it ourself. */ - skbdesc = get_skb_frame_desc(entry->skb); - skbdesc->frame_type = DUMP_FRAME_TXDONE; - - rt2x00debug_dump_frame(rt2x00dev, entry->skb); + rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TXDONE, entry->skb); + skbdesc = get_skb_frame_desc(entry->skb); if (!(skbdesc->flags & FRAME_DESC_DRIVER_GENERATED)) ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb, &tx_status); @@ -610,8 +607,7 @@ void rt2x00lib_rxdone(struct queue_entry *entry, * Send frame to mac80211 & debugfs. * mac80211 will clean up the skb structure. */ - get_skb_frame_desc(entry->skb)->frame_type = DUMP_FRAME_RXDONE; - rt2x00debug_dump_frame(rt2x00dev, entry->skb); + rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb); ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb, rx_status); entry->skb = NULL; } @@ -752,8 +748,7 @@ void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev, * frame to the device, but we are going to push the * frame to debugfs here. */ - skbdesc->frame_type = DUMP_FRAME_TX; - rt2x00debug_dump_frame(rt2x00dev, skb); + rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TX, skb); } EXPORT_SYMBOL_GPL(rt2x00lib_write_tx_desc); diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 41ee02cd282..c4ce534e3cd 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -26,6 +26,8 @@ #ifndef RT2X00LIB_H #define RT2X00LIB_H +#include "rt2x00dump.h" + /* * Interval defines * Both the link tuner as the rfkill will be called once per second. @@ -128,7 +130,8 @@ static inline void rt2x00lib_free_firmware(struct rt2x00_dev *rt2x00dev) #ifdef CONFIG_RT2X00_LIB_DEBUGFS void rt2x00debug_register(struct rt2x00_dev *rt2x00dev); void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev); -void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb); +void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, + enum rt2x00_dump_type type, struct sk_buff *skb); #else static inline void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) { @@ -139,6 +142,7 @@ static inline void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev) } static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, + enum rt2x00_dump_type type, struct sk_buff *skb) { } diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index d1707a7ca41..c3493ed7f4c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -109,7 +109,6 @@ enum skb_frame_desc_flags { * this structure should not exceed the size of that array (48 bytes). * * @flags: Frame flags, see &enum skb_frame_desc_flags. - * @frame_type: Frame type, see &enum rt2x00_dump_type. * @data: Pointer to data part of frame (Start of ieee80211 header). * @desc: Pointer to descriptor part of the frame. * Note that this pointer could point to something outside @@ -121,14 +120,12 @@ enum skb_frame_desc_flags { struct skb_frame_desc { unsigned int flags; - unsigned int frame_type; + unsigned short data_len; + unsigned short desc_len; void *data; void *desc; - unsigned int data_len; - unsigned int desc_len; - struct queue_entry *entry; }; -- cgit v1.2.3-70-g09d2 From fb55f4d1fa252ba1e479284b79da1049d658c371 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 10 May 2008 13:42:06 +0200 Subject: rt2x00: Fix TX status reporting The tx_status enumeration was broken since the introduction of rt61pci. That driver uses different values to report the status of the tx action. This would lead to frames that were reported as success but actually failed to be send out, or frames that were neither successfull or failure which were reported as failure. Fix this by change the TX status reporting and more explicitely check for failure or success. Note that a third possibility is added "unknown". Not all hardware (USB) can report the actual TX status, for rt61pci some frames will receive this status because the TXdone handler is never called for those frames. This unknown will now be handled as neither success or failure, so we no longer increment the failure counter while this conclusion could not be determined from the real status of the frame. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 13 ++++++++++++- drivers/net/wireless/rt2x00/rt2500pci.c | 13 ++++++++++++- drivers/net/wireless/rt2x00/rt2x00dev.c | 24 +++++++++++------------- drivers/net/wireless/rt2x00/rt2x00queue.h | 20 ++++++++++++++++++-- drivers/net/wireless/rt2x00/rt2x00reg.h | 11 ----------- drivers/net/wireless/rt2x00/rt2x00usb.c | 11 ++++++++++- drivers/net/wireless/rt2x00/rt61pci.c | 15 +++++++++++++-- 7 files changed, 76 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index afa565c6362..69b1dbd1adf 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1137,7 +1137,18 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, /* * Obtain the status about this packet. */ - txdesc.status = rt2x00_get_field32(word, TXD_W0_RESULT); + txdesc.flags = 0; + switch (rt2x00_get_field32(word, TXD_W0_RESULT)) { + case 0: /* Success */ + case 1: /* Success with retry */ + __set_bit(TXDONE_SUCCESS, &txdesc.flags); + break; + case 2: /* Failure, excessive retries */ + __set_bit(TXDONE_EXCESSIVE_RETRY, &txdesc.flags); + /* Don't break, this is a failed frame! */ + default: /* Failure */ + __set_bit(TXDONE_FAILURE, &txdesc.flags); + } txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT); rt2x00pci_txdone(rt2x00dev, entry, &txdesc); diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index c06f1b5e588..aa195dab155 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1292,7 +1292,18 @@ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev, /* * Obtain the status about this packet. */ - txdesc.status = rt2x00_get_field32(word, TXD_W0_RESULT); + txdesc.flags = 0; + switch (rt2x00_get_field32(word, TXD_W0_RESULT)) { + case 0: /* Success */ + case 1: /* Success with retry */ + __set_bit(TXDONE_SUCCESS, &txdesc.flags); + break; + case 2: /* Failure, excessive retries */ + __set_bit(TXDONE_EXCESSIVE_RETRY, &txdesc.flags); + /* Don't break, this is a failed frame! */ + default: /* Failure */ + __set_bit(TXDONE_FAILURE, &txdesc.flags); + } txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT); rt2x00pci_txdone(rt2x00dev, entry, &txdesc); diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index ea130f2eb00..69da22cf085 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -496,38 +496,36 @@ void rt2x00lib_txdone(struct queue_entry *entry, struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct skb_frame_desc *skbdesc; struct ieee80211_tx_status tx_status; - int success = !!(txdesc->status == TX_SUCCESS || - txdesc->status == TX_SUCCESS_RETRY); - int fail = !!(txdesc->status == TX_FAIL_RETRY || - txdesc->status == TX_FAIL_INVALID || - txdesc->status == TX_FAIL_OTHER); /* * Update TX statistics. */ - rt2x00dev->link.qual.tx_success += success; - rt2x00dev->link.qual.tx_failed += txdesc->retry + fail; + rt2x00dev->link.qual.tx_success += + test_bit(TXDONE_SUCCESS, &txdesc->flags); + rt2x00dev->link.qual.tx_failed += + txdesc->retry + !!test_bit(TXDONE_FAILURE, &txdesc->flags); /* * Initialize TX status */ tx_status.flags = 0; tx_status.ack_signal = 0; - tx_status.excessive_retries = (txdesc->status == TX_FAIL_RETRY); + tx_status.excessive_retries = + test_bit(TXDONE_EXCESSIVE_RETRY, &txdesc->flags); tx_status.retry_count = txdesc->retry; memcpy(&tx_status.control, txdesc->control, sizeof(*txdesc->control)); if (!(tx_status.control.flags & IEEE80211_TXCTL_NO_ACK)) { - if (success) + if (test_bit(TXDONE_SUCCESS, &txdesc->flags)) tx_status.flags |= IEEE80211_TX_STATUS_ACK; - else + else if (test_bit(TXDONE_FAILURE, &txdesc->flags)) rt2x00dev->low_level_stats.dot11ACKFailureCount++; } if (tx_status.control.flags & IEEE80211_TXCTL_USE_RTS_CTS) { - if (success) + if (test_bit(TXDONE_SUCCESS, &txdesc->flags)) rt2x00dev->low_level_stats.dot11RTSSuccessCount++; - else + else if (test_bit(TXDONE_FAILURE, &txdesc->flags)) rt2x00dev->low_level_stats.dot11RTSFailureCount++; } @@ -546,7 +544,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb, &tx_status); else - dev_kfree_skb(entry->skb); + dev_kfree_skb_irq(entry->skb); entry->skb = NULL; } EXPORT_SYMBOL_GPL(rt2x00lib_txdone); diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index c3493ed7f4c..f361f784965 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -167,6 +167,22 @@ struct rxdone_entry_desc { int dev_flags; }; +/** + * enum txdone_entry_desc_flags: Flags for &struct txdone_entry_desc + * + * @TXDONE_UNKNOWN: Hardware could not determine success of transmission. + * @TXDONE_SUCCESS: Frame was successfully send + * @TXDONE_FAILURE: Frame was not successfully send + * @TXDONE_EXCESSIVE_RETRY: In addition to &TXDONE_FAILURE, the + * frame transmission failed due to excessive retries. + */ +enum txdone_entry_desc_flags { + TXDONE_UNKNOWN = 1 << 0, + TXDONE_SUCCESS = 1 << 1, + TXDONE_FAILURE = 1 << 2, + TXDONE_EXCESSIVE_RETRY = 1 << 3, +}; + /** * struct txdone_entry_desc: TX done entry descriptor * @@ -174,12 +190,12 @@ struct rxdone_entry_desc { * after the device is done with transmission. * * @control: Control structure which was used to transmit the frame. - * @status: TX status (See &enum tx_status). + * @flags: TX done flags (See &enum txdone_entry_desc_flags). * @retry: Retry count. */ struct txdone_entry_desc { struct ieee80211_tx_control *control; - int status; + unsigned long flags; int retry; }; diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h index 0325bed2fbf..3f255df58b7 100644 --- a/drivers/net/wireless/rt2x00/rt2x00reg.h +++ b/drivers/net/wireless/rt2x00/rt2x00reg.h @@ -26,17 +26,6 @@ #ifndef RT2X00REG_H #define RT2X00REG_H -/* - * TX result flags. - */ -enum tx_status { - TX_SUCCESS = 0, - TX_SUCCESS_RETRY = 1, - TX_FAIL_RETRY = 2, - TX_FAIL_INVALID = 3, - TX_FAIL_OTHER = 4, -}; - /* * Antenna values */ diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 98aafc2d584..caee65e8219 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -147,8 +147,17 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) /* * Obtain the status about this packet. + * Note that when the status is 0 it does not mean the + * frame was send out correctly. It only means the frame + * was succesfully pushed to the hardware, we have no + * way to determine the transmission status right now. + * (Only indirectly by looking at the failed TX counters + * in the register). */ - txdesc.status = !urb->status ? TX_SUCCESS : TX_FAIL_RETRY; + if (!urb->status) + __set_bit(TXDONE_UNKNOWN, &txdesc.flags); + else + __set_bit(TXDONE_FAILURE, &txdesc.flags); txdesc.retry = 0; txdesc.control = &priv_tx->control; diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index edddbf35bba..15191d6581b 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1764,7 +1764,8 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev) "TX status report missed for entry %d\n", entry_done->entry_idx); - txdesc.status = TX_FAIL_OTHER; + txdesc.flags = 0; + __set_bit(TXDONE_UNKNOWN, &txdesc.flags); txdesc.retry = 0; rt2x00pci_txdone(rt2x00dev, entry_done, &txdesc); @@ -1774,7 +1775,17 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev) /* * Obtain the status about this packet. */ - txdesc.status = rt2x00_get_field32(reg, STA_CSR4_TX_RESULT); + txdesc.flags = 0; + switch (rt2x00_get_field32(reg, STA_CSR4_TX_RESULT)) { + case 0: /* Success, maybe with retry */ + __set_bit(TXDONE_SUCCESS, &txdesc.flags); + break; + case 6: /* Failure, excessive retries */ + __set_bit(TXDONE_EXCESSIVE_RETRY, &txdesc.flags); + /* Don't break, this is a failed frame! */ + default: /* Failure */ + __set_bit(TXDONE_FAILURE, &txdesc.flags); + } txdesc.retry = rt2x00_get_field32(reg, STA_CSR4_RETRY_COUNT); rt2x00pci_txdone(rt2x00dev, entry, &txdesc); -- cgit v1.2.3-70-g09d2 From 61486e0f68d1f8966c09b734566a187d42d65c54 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 10 May 2008 13:42:31 +0200 Subject: rt2x00: Remove ieee80211_tx_control argument from write_tx_desc() Move the last remaining information details read from ieee80211_tx_control in the drivers to the txentry_desc structure. After this we can remove ieee80211_tx_control from the argument list for the callback function, which makes it easier when the control information is moved into skb->cb Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 6 ++---- drivers/net/wireless/rt2x00/rt2500pci.c | 7 ++----- drivers/net/wireless/rt2x00/rt2500usb.c | 7 +++---- drivers/net/wireless/rt2x00/rt2x00.h | 3 +-- drivers/net/wireless/rt2x00/rt2x00dev.c | 19 ++++++++++++++----- drivers/net/wireless/rt2x00/rt2x00queue.h | 14 ++++++++++---- drivers/net/wireless/rt2x00/rt61pci.c | 6 ++---- drivers/net/wireless/rt2x00/rt73usb.c | 6 ++---- 8 files changed, 36 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 69b1dbd1adf..fb02d118075 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1001,8 +1001,7 @@ static int rt2400pci_set_device_state(struct rt2x00_dev *rt2x00dev, */ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb, - struct txentry_desc *txdesc, - struct ieee80211_tx_control *control) + struct txentry_desc *txdesc) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); __le32 *txd = skbdesc->desc; @@ -1046,8 +1045,7 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, test_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs); rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, - !!(control->flags & - IEEE80211_TXCTL_LONG_RETRY_LIMIT)); ++ test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags)); rt2x00_desc_write(txd, 0, word); } diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index aa195dab155..1724ce90f8b 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1155,8 +1155,7 @@ static int rt2500pci_set_device_state(struct rt2x00_dev *rt2x00dev, */ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb, - struct txentry_desc *txdesc, - struct ieee80211_tx_control *control) + struct txentry_desc *txdesc) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); __le32 *txd = skbdesc->desc; @@ -1198,9 +1197,7 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W0_CIPHER_OWNER, 1); rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs); rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, - !!(control->flags & - IEEE80211_TXCTL_LONG_RETRY_LIMIT)); - rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len); + test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE); rt2x00_desc_write(txd, 0, word); } diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 88bafdf8f0f..7df06ece1b4 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1033,8 +1033,7 @@ static int rt2500usb_set_device_state(struct rt2x00_dev *rt2x00dev, */ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb, - struct txentry_desc *txdesc, - struct ieee80211_tx_control *control) + struct txentry_desc *txdesc) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); __le32 *txd = skbdesc->desc; @@ -1058,7 +1057,7 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_desc_write(txd, 2, word); rt2x00_desc_read(txd, 0, &word); - rt2x00_set_field32(&word, TXD_W0_RETRY_LIMIT, control->retry_limit); + rt2x00_set_field32(&word, TXD_W0_RETRY_LIMIT, txdesc->retry_limit); rt2x00_set_field32(&word, TXD_W0_MORE_FRAG, test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_ACK, @@ -1068,7 +1067,7 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W0_OFDM, test_bit(ENTRY_TXD_OFDM_RATE, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_NEW_SEQ, - !!(control->flags & IEEE80211_TXCTL_FIRST_FRAGMENT)); + test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs); rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len); rt2x00_set_field32(&word, TXD_W0_CIPHER, CIPHER_NONE); diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 79bd9c9f896..65614841f74 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -540,8 +540,7 @@ struct rt2x00lib_ops { */ void (*write_tx_desc) (struct rt2x00_dev *rt2x00dev, struct sk_buff *skb, - struct txentry_desc *txdesc, - struct ieee80211_tx_control *control); + struct txentry_desc *txdesc); int (*write_tx_data) (struct rt2x00_dev *rt2x00dev, struct data_queue *queue, struct sk_buff *skb, struct ieee80211_tx_control *control); diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 69da22cf085..e1368f70985 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -664,7 +664,12 @@ void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev, tx_rate = control->rts_cts_rate->hw_value; } - rate = rt2x00_get_rate(tx_rate); + /* + * Determine retry information. + */ + txdesc.retry_limit = control->retry_limit; + if (control->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT) + __set_bit(ENTRY_TXD_RETRY_MODE, &txdesc.flags); /* * Check if more fragments are pending @@ -686,16 +691,20 @@ void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev, * Set ifs to IFS_SIFS when the this is not the first fragment, * or this fragment came after RTS/CTS. */ - if ((seq_ctrl & IEEE80211_SCTL_FRAG) > 0 || - test_bit(ENTRY_TXD_RTS_FRAME, &txdesc.flags)) + if (test_bit(ENTRY_TXD_RTS_FRAME, &txdesc.flags)) { txdesc.ifs = IFS_SIFS; - else + } else if (control->flags & IEEE80211_TXCTL_FIRST_FRAGMENT) { + __set_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc.flags); txdesc.ifs = IFS_BACKOFF; + } else { + txdesc.ifs = IFS_SIFS; + } /* * PLCP setup * Length calculation depends on OFDM/CCK rate. */ + rate = rt2x00_get_rate(tx_rate); txdesc.signal = rate->plcp; txdesc.service = 0x04; @@ -733,7 +742,7 @@ void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev, txdesc.signal |= 0x08; } - rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, skb, &txdesc, control); + rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, skb, &txdesc); /* * Update queue entry. diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index f361f784965..3f7cfa9b7da 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -204,18 +204,22 @@ struct txdone_entry_desc { * * @ENTRY_TXD_RTS_FRAME: This frame is a RTS frame. * @ENTRY_TXD_OFDM_RATE: This frame is send out with an OFDM rate. + * @ENTRY_TXD_FIRST_FRAGMENT: This is the first frame. * @ENTRY_TXD_MORE_FRAG: This frame is followed by another fragment. * @ENTRY_TXD_REQ_TIMESTAMP: Require timestamp to be inserted. * @ENTRY_TXD_BURST: This frame belongs to the same burst event. * @ENTRY_TXD_ACK: An ACK is required for this frame. + * @ENTRY_TXD_RETRY_MODE: When set, the long retry count is used. */ enum txentry_desc_flags { ENTRY_TXD_RTS_FRAME, ENTRY_TXD_OFDM_RATE, + ENTRY_TXD_FIRST_FRAGMENT, ENTRY_TXD_MORE_FRAG, ENTRY_TXD_REQ_TIMESTAMP, ENTRY_TXD_BURST, ENTRY_TXD_ACK, + ENTRY_TXD_RETRY_MODE, }; /** @@ -229,6 +233,7 @@ enum txentry_desc_flags { * @length_low: PLCP length low word. * @signal: PLCP signal. * @service: PLCP service. + * @retry_limit: Max number of retries. * @aifs: AIFS value. * @ifs: IFS value. * @cw_min: cwmin value. @@ -244,10 +249,11 @@ struct txentry_desc { u16 signal; u16 service; - int aifs; - int ifs; - int cw_min; - int cw_max; + short retry_limit; + short aifs; + short ifs; + short cw_min; + short cw_max; }; /** diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 15191d6581b..5d690ee1bef 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1526,8 +1526,7 @@ static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev, */ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb, - struct txentry_desc *txdesc, - struct ieee80211_tx_control *control) + struct txentry_desc *txdesc) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); __le32 *txd = skbdesc->desc; @@ -1577,8 +1576,7 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, test_bit(ENTRY_TXD_OFDM_RATE, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs); rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, - !!(control->flags & - IEEE80211_TXCTL_LONG_RETRY_LIMIT)); + test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0); rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len); rt2x00_set_field32(&word, TXD_W0_BURST, diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 51c5575ed02..d98002cfe09 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1255,8 +1255,7 @@ static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev, */ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb, - struct txentry_desc *txdesc, - struct ieee80211_tx_control *control) + struct txentry_desc *txdesc) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); __le32 *txd = skbdesc->desc; @@ -1301,8 +1300,7 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, test_bit(ENTRY_TXD_OFDM_RATE, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs); rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, - !!(control->flags & - IEEE80211_TXCTL_LONG_RETRY_LIMIT)); + test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0); rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len); rt2x00_set_field32(&word, TXD_W0_BURST2, -- cgit v1.2.3-70-g09d2 From 61448f88078e813bbaaa58eb775d650c85e7d407 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Sat, 10 May 2008 13:43:33 +0200 Subject: rt2x00: Fix queue related oops in case of deselected mac80211 multi-queue feature. With the integration of the mac80211 multiqueue patches it has become possible that the mac80211 layer modifies the number of TX queues that is stored inside the ieee80211_hw structure, especially when multi-queue is not selected. The rt2x00 drivers are not well suited to handle that situation, as they allocate the queue structures before mac80211 has modified the number of queues it is going to use, and also expect the number of allocated queues to match the hardware implementation. Hence, ensure that rt2x00 maintains by itself the number of queues that the hardware supports, and, at the same time, making is not dependent on the preservation of contents inside a mac80211 structure. Signed-off-by: Gertjan van Wingerde Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 2 +- drivers/net/wireless/rt2x00/rt2400pci.h | 5 +++++ drivers/net/wireless/rt2x00/rt2500pci.c | 2 +- drivers/net/wireless/rt2x00/rt2500pci.h | 5 +++++ drivers/net/wireless/rt2x00/rt2500usb.c | 2 +- drivers/net/wireless/rt2x00/rt2500usb.h | 5 +++++ drivers/net/wireless/rt2x00/rt2x00.h | 1 + drivers/net/wireless/rt2x00/rt2x00dev.c | 5 +++++ drivers/net/wireless/rt2x00/rt2x00mac.c | 2 +- drivers/net/wireless/rt2x00/rt2x00queue.c | 8 ++++---- drivers/net/wireless/rt2x00/rt2x00queue.h | 2 +- drivers/net/wireless/rt2x00/rt61pci.c | 2 +- drivers/net/wireless/rt2x00/rt61pci.h | 5 +++++ drivers/net/wireless/rt2x00/rt73usb.c | 2 +- drivers/net/wireless/rt2x00/rt73usb.h | 5 +++++ 15 files changed, 42 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index fb02d118075..b4310d798f9 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1373,7 +1373,6 @@ static void rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_SIGNAL_DBM; rt2x00dev->hw->extra_tx_headroom = 0; - rt2x00dev->hw->queues = 2; SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev); SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, @@ -1620,6 +1619,7 @@ static const struct rt2x00_ops rt2400pci_ops = { .max_ap_intf = 1, .eeprom_size = EEPROM_SIZE, .rf_size = RF_SIZE, + .tx_queues = NUM_TX_QUEUES, .rx = &rt2400pci_queue_rx, .tx = &rt2400pci_queue_tx, .bcn = &rt2400pci_queue_bcn, diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h index a5210f9a336..e9aa326be9f 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.h +++ b/drivers/net/wireless/rt2x00/rt2400pci.h @@ -51,6 +51,11 @@ #define BBP_SIZE 0x0020 #define RF_SIZE 0x0010 +/* + * Number of TX queues. + */ +#define NUM_TX_QUEUES 2 + /* * Control/Status Registers(CSR). * Some values are set in TU, whereas 1 TU == 1024 us. diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 1724ce90f8b..54aaa8375a2 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1692,7 +1692,6 @@ static void rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) IEEE80211_HW_SIGNAL_DBM; rt2x00dev->hw->extra_tx_headroom = 0; - rt2x00dev->hw->queues = 2; SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev); SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, @@ -1933,6 +1932,7 @@ static const struct rt2x00_ops rt2500pci_ops = { .max_ap_intf = 1, .eeprom_size = EEPROM_SIZE, .rf_size = RF_SIZE, + .tx_queues = NUM_TX_QUEUES, .rx = &rt2500pci_queue_rx, .tx = &rt2500pci_queue_tx, .bcn = &rt2500pci_queue_bcn, diff --git a/drivers/net/wireless/rt2x00/rt2500pci.h b/drivers/net/wireless/rt2x00/rt2500pci.h index 13899550465..ea93b8f423a 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.h +++ b/drivers/net/wireless/rt2x00/rt2500pci.h @@ -62,6 +62,11 @@ #define BBP_SIZE 0x0040 #define RF_SIZE 0x0014 +/* + * Number of TX queues. + */ +#define NUM_TX_QUEUES 2 + /* * Control/Status Registers(CSR). * Some values are set in TU, whereas 1 TU == 1024 us. diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 7df06ece1b4..661cf3d7212 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1590,7 +1590,6 @@ static void rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) IEEE80211_HW_SIGNAL_DBM; rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE; - rt2x00dev->hw->queues = 2; SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev); SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, @@ -1826,6 +1825,7 @@ static const struct rt2x00_ops rt2500usb_ops = { .max_ap_intf = 1, .eeprom_size = EEPROM_SIZE, .rf_size = RF_SIZE, + .tx_queues = NUM_TX_QUEUES, .rx = &rt2500usb_queue_rx, .tx = &rt2500usb_queue_tx, .bcn = &rt2500usb_queue_bcn, diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h index a37a068d0c7..7d50098f0cc 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.h +++ b/drivers/net/wireless/rt2x00/rt2500usb.h @@ -62,6 +62,11 @@ #define BBP_SIZE 0x0060 #define RF_SIZE 0x0014 +/* + * Number of TX queues. + */ +#define NUM_TX_QUEUES 2 + /* * Control/Status Registers(CSR). * Some values are set in TU, whereas 1 TU == 1024 us. diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 65614841f74..6f7b34fac16 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -591,6 +591,7 @@ struct rt2x00_ops { const unsigned int max_ap_intf; const unsigned int eeprom_size; const unsigned int rf_size; + const unsigned int tx_queues; const struct data_queue_desc *rx; const struct data_queue_desc *tx; const struct data_queue_desc *bcn; diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index e1368f70985..46c377873f1 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -974,6 +974,11 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) if (status) return status; + /* + * Initialize HW fields. + */ + rt2x00dev->hw->queues = rt2x00dev->ops->tx_queues; + /* * Register HW. */ diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 767e0ffce04..c5cedb29b87 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -456,7 +456,7 @@ int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw, struct rt2x00_dev *rt2x00dev = hw->priv; unsigned int i; - for (i = 0; i < hw->queues; i++) { + for (i = 0; i < rt2x00dev->ops->tx_queues; i++) { stats[i].len = rt2x00dev->tx[i].length; stats[i].limit = rt2x00dev->tx[i].limit; stats[i].count = rt2x00dev->tx[i].count; diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index e5b861f8416..95f8dd3462f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -34,7 +34,7 @@ struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev, { int atim = test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags); - if (queue < rt2x00dev->hw->queues && rt2x00dev->tx) + if (queue < rt2x00dev->ops->tx_queues && rt2x00dev->tx) return &rt2x00dev->tx[queue]; if (!rt2x00dev->bcn) @@ -255,11 +255,11 @@ int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev) /* * We need the following queues: * RX: 1 - * TX: hw->queues + * TX: ops->tx_queues * Beacon: 1 * Atim: 1 (if required) */ - rt2x00dev->data_queues = 2 + rt2x00dev->hw->queues + req_atim; + rt2x00dev->data_queues = 2 + rt2x00dev->ops->tx_queues + req_atim; queue = kzalloc(rt2x00dev->data_queues * sizeof(*queue), GFP_KERNEL); if (!queue) { @@ -272,7 +272,7 @@ int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev) */ rt2x00dev->rx = queue; rt2x00dev->tx = &queue[1]; - rt2x00dev->bcn = &queue[1 + rt2x00dev->hw->queues]; + rt2x00dev->bcn = &queue[1 + rt2x00dev->ops->tx_queues]; /* * Initialize queue parameters. diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 3f7cfa9b7da..4bde98ba3c6 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -397,7 +397,7 @@ struct data_queue_desc { * the end of the TX queue array. */ #define tx_queue_end(__dev) \ - &(__dev)->tx[(__dev)->hw->queues] + &(__dev)->tx[(__dev)->ops->tx_queues] /** * queue_loop - Loop through the queues within a specific range (HELPER MACRO). diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 5d690ee1bef..68d2216131b 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2257,7 +2257,6 @@ static void rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_SIGNAL_DBM; rt2x00dev->hw->extra_tx_headroom = 0; - rt2x00dev->hw->queues = 4; SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev); SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, @@ -2489,6 +2488,7 @@ static const struct rt2x00_ops rt61pci_ops = { .max_ap_intf = 4, .eeprom_size = EEPROM_SIZE, .rf_size = RF_SIZE, + .tx_queues = NUM_TX_QUEUES, .rx = &rt61pci_queue_rx, .tx = &rt61pci_queue_tx, .bcn = &rt61pci_queue_bcn, diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h index 3511bba7ff6..c5a04b9329d 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.h +++ b/drivers/net/wireless/rt2x00/rt61pci.h @@ -53,6 +53,11 @@ #define BBP_SIZE 0x0080 #define RF_SIZE 0x0014 +/* + * Number of TX queues. + */ +#define NUM_TX_QUEUES 4 + /* * PCI registers. */ diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index d98002cfe09..2191d8b94a8 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1831,7 +1831,6 @@ static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_SIGNAL_DBM; rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE; - rt2x00dev->hw->queues = 4; SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev); SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, @@ -2079,6 +2078,7 @@ static const struct rt2x00_ops rt73usb_ops = { .max_ap_intf = 4, .eeprom_size = EEPROM_SIZE, .rf_size = RF_SIZE, + .tx_queues = NUM_TX_QUEUES, .rx = &rt73usb_queue_rx, .tx = &rt73usb_queue_tx, .bcn = &rt73usb_queue_bcn, diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h index 06d687425fe..25cdcc9bf7c 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.h +++ b/drivers/net/wireless/rt2x00/rt73usb.h @@ -53,6 +53,11 @@ #define BBP_SIZE 0x0080 #define RF_SIZE 0x0014 +/* + * Number of TX queues. + */ +#define NUM_TX_QUEUES 4 + /* * USB registers. */ -- cgit v1.2.3-70-g09d2 From 70a96109439cba0af0780ee1dc25ec7ed15f0bae Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 10 May 2008 13:43:38 +0200 Subject: rt2x00: Preserve descriptor information after memmove() Due to usage of memmove() in rt2x00usb the descriptor can become corrupted because it is being overwritten by the data part. Overall having the descriptor in front of the frame is a bad idea, we can however use the skb->cb array for this task, since that contains more then enough room to hold the entire descriptor and preserve the information long enough. After this we can also cleanup the alignment code a bit to make it work a bit more flexible to allow for all kinds of odd header lengths. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2500usb.c | 23 +++++-------- drivers/net/wireless/rt2x00/rt2x00usb.c | 60 +++++++++++++++++++++++---------- drivers/net/wireless/rt2x00/rt73usb.c | 26 ++++++-------- 3 files changed, 62 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 661cf3d7212..3be4c7ea8dd 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1129,20 +1129,22 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry, __le32 *rxd = (__le32 *)(entry->skb->data + (priv_rx->urb->actual_length - entry->queue->desc_size)); - unsigned int offset = entry->queue->desc_size + 2; u32 word0; u32 word1; /* - * Copy descriptor to the available headroom inside the skbuffer. + * Copy descriptor to the skb->cb array, this has 2 benefits: + * 1) Each descriptor word is 4 byte aligned. + * 2) Descriptor is safe from moving of frame data in rt2x00usb. */ - skb_push(entry->skb, offset); - memcpy(entry->skb->data, rxd, entry->queue->desc_size); - rxd = (__le32 *)entry->skb->data; + skbdesc->desc_len = + min_t(u16, entry->queue->desc_size, sizeof(entry->skb->cb)); + memcpy(entry->skb->cb, rxd, skbdesc->desc_len); + skbdesc->desc = entry->skb->cb; + rxd = (__le32 *)skbdesc->desc; /* - * The descriptor is now aligned to 4 bytes and thus it is - * now safe to read it on all architectures. + * It is now safe to read the descriptor on all architectures. */ rt2x00_desc_read(rxd, 0, &word0); rt2x00_desc_read(rxd, 1, &word1); @@ -1173,16 +1175,9 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry, /* * Adjust the skb memory window to the frame boundaries. */ - skb_pull(entry->skb, offset); skb_trim(entry->skb, rxdesc->size); - - /* - * Set descriptor and data pointer. - */ skbdesc->data = entry->skb->data; skbdesc->data_len = rxdesc->size; - skbdesc->desc = rxd; - skbdesc->desc_len = entry->queue->desc_size; } /* diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index caee65e8219..f72b3d07a42 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -246,22 +246,35 @@ static struct sk_buff* rt2x00usb_alloc_rxskb(struct data_queue *queue) { struct sk_buff *skb; unsigned int frame_size; + unsigned int reserved_size; /* - * As alignment we use 2 and not NET_IP_ALIGN because we need - * to be sure we have 2 bytes room in the head. (NET_IP_ALIGN - * can be 0 on some hardware). We use these 2 bytes for frame - * alignment later, we assume that the chance that - * header_size % 4 == 2 is bigger then header_size % 2 == 0 - * and thus optimize alignment by reserving the 2 bytes in - * advance. + * The frame size includes descriptor size, because the + * hardware directly receive the frame into the skbuffer. */ frame_size = queue->data_size + queue->desc_size; - skb = dev_alloc_skb(queue->desc_size + frame_size + 2); + + /* + * For the allocation we should keep a few things in mind: + * 1) 4byte alignment of 802.11 payload + * + * For (1) we need at most 4 bytes to guarentee the correct + * alignment. We are going to optimize the fact that the chance + * that the 802.11 header_size % 4 == 2 is much bigger then + * anything else. However since we need to move the frame up + * to 3 bytes to the front, which means we need to preallocate + * 6 bytes. + */ + reserved_size = 6; + + /* + * Allocate skbuffer. + */ + skb = dev_alloc_skb(frame_size + reserved_size); if (!skb) return NULL; - skb_reserve(skb, queue->desc_size + 2); + skb_reserve(skb, reserved_size); skb_put(skb, frame_size); return skb; @@ -274,7 +287,8 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) struct sk_buff *skb; struct skb_frame_desc *skbdesc; struct rxdone_entry_desc rxdesc; - int header_size; + unsigned int header_size; + unsigned int align; if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || !test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) @@ -298,19 +312,29 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) memset(&rxdesc, 0, sizeof(rxdesc)); rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc); + header_size = ieee80211_get_hdrlen_from_skb(entry->skb); + /* * The data behind the ieee80211 header must be - * aligned on a 4 byte boundary. + * aligned on a 4 byte boundary. We already reserved + * 2 bytes for header_size % 4 == 2 optimization. + * To determine the number of bytes which the data + * should be moved to the left, we must add these + * 2 bytes to the header_size. */ - header_size = ieee80211_get_hdrlen_from_skb(entry->skb); - if (header_size % 4 == 0) { - skb_push(entry->skb, 2); - memmove(entry->skb->data, entry->skb->data + 2, - entry->skb->len - 2); - skbdesc->data = entry->skb->data; - skb_trim(entry->skb,entry->skb->len - 2); + align = (header_size + 2) % 4; + + if (align) { + skb_push(entry->skb, align); + /* Move entire frame in 1 command */ + memmove(entry->skb->data, entry->skb->data + align, + rxdesc.size); } + /* Update data pointers, trim buffer to correct size */ + skbdesc->data = entry->skb->data; + skb_trim(entry->skb, rxdesc.size); + /* * Allocate a new sk buffer to replace the current one. * If allocation fails, we should drop the current frame diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 2191d8b94a8..1bcf8c132cd 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1403,20 +1403,22 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry, { struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); __le32 *rxd = (__le32 *)entry->skb->data; - unsigned int offset = entry->queue->desc_size + 2; u32 word0; u32 word1; /* - * Copy descriptor to the available headroom inside the skbuffer. + * Copy descriptor to the skb->cb array, this has 2 benefits: + * 1) Each descriptor word is 4 byte aligned. + * 2) Descriptor is safe from moving of frame data in rt2x00usb. */ - skb_push(entry->skb, offset); - memcpy(entry->skb->data, rxd, entry->queue->desc_size); - rxd = (__le32 *)entry->skb->data; + skbdesc->desc_len = + min_t(u16, entry->queue->desc_size, sizeof(entry->skb->cb)); + memcpy(entry->skb->cb, rxd, skbdesc->desc_len); + skbdesc->desc = entry->skb->cb; + rxd = (__le32 *)skbdesc->desc; /* - * The descriptor is now aligned to 4 bytes and thus it is - * now safe to read it on all architectures. + * It is now safe to read the descriptor on all architectures. */ rt2x00_desc_read(rxd, 0, &word0); rt2x00_desc_read(rxd, 1, &word1); @@ -1442,18 +1444,12 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry, rxdesc->dev_flags |= RXDONE_MY_BSS; /* - * Adjust the skb memory window to the frame boundaries. + * Set skb pointers, and update frame information. */ - skb_pull(entry->skb, offset + entry->queue->desc_size); + skb_pull(entry->skb, entry->queue->desc_size); skb_trim(entry->skb, rxdesc->size); - - /* - * Set descriptor and data pointer. - */ skbdesc->data = entry->skb->data; skbdesc->data_len = rxdesc->size; - skbdesc->desc = rxd; - skbdesc->desc_len = entry->queue->desc_size; } /* -- cgit v1.2.3-70-g09d2 From 4de36fe5abe077a4c65bf0b6a309865aa043e055 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Sat, 10 May 2008 13:44:14 +0200 Subject: rt2x00: Only initialize the minimum needed fields of PCI TX descriptors. In preparation of replacing the statically allocated data DMA buffers with DMA-mapped skb's we need to change the TXD handling of the PCI drivers, by moving the programming of the buffer address fields to the actual TXD writing at TX time, instead of at start-up time. Signed-off-by: Gertjan van Wingerde Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 15 ++++++--------- drivers/net/wireless/rt2x00/rt2500pci.c | 9 +++++---- drivers/net/wireless/rt2x00/rt61pci.c | 24 ++++++++++-------------- 3 files changed, 21 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index b4310d798f9..2c0cf394c78 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -643,15 +643,6 @@ static void rt2400pci_init_txentry(struct rt2x00_dev *rt2x00dev, struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data; u32 word; - rt2x00_desc_read(priv_tx->desc, 1, &word); - rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, priv_tx->data_dma); - rt2x00_desc_write(priv_tx->desc, 1, word); - - rt2x00_desc_read(priv_tx->desc, 2, &word); - rt2x00_set_field32(&word, TXD_W2_BUFFER_LENGTH, - entry->queue->data_size); - rt2x00_desc_write(priv_tx->desc, 2, word); - rt2x00_desc_read(priv_tx->desc, 0, &word); rt2x00_set_field32(&word, TXD_W0_VALID, 0); rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); @@ -1004,13 +995,19 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct txentry_desc *txdesc) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); + struct queue_entry_priv_pci_tx *entry_priv = skbdesc->entry->priv_data; __le32 *txd = skbdesc->desc; u32 word; /* * Start writing the descriptor words. */ + rt2x00_desc_read(entry_priv->desc, 1, &word); + rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, entry_priv->data_dma); + rt2x00_desc_write(entry_priv->desc, 1, word); + rt2x00_desc_read(txd, 2, &word); + rt2x00_set_field32(&word, TXD_W2_BUFFER_LENGTH, skbdesc->data_len); rt2x00_set_field32(&word, TXD_W2_DATABYTE_COUNT, skbdesc->data_len); rt2x00_desc_write(txd, 2, word); diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 54aaa8375a2..6c31c5db0ca 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -733,10 +733,6 @@ static void rt2500pci_init_txentry(struct rt2x00_dev *rt2x00dev, struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data; u32 word; - rt2x00_desc_read(priv_tx->desc, 1, &word); - rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, priv_tx->data_dma); - rt2x00_desc_write(priv_tx->desc, 1, word); - rt2x00_desc_read(priv_tx->desc, 0, &word); rt2x00_set_field32(&word, TXD_W0_VALID, 0); rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); @@ -1158,12 +1154,17 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct txentry_desc *txdesc) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); + struct queue_entry_priv_pci_tx *entry_priv = skbdesc->entry->priv_data; __le32 *txd = skbdesc->desc; u32 word; /* * Start writing the descriptor words. */ + rt2x00_desc_read(entry_priv->desc, 1, &word); + rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, entry_priv->data_dma); + rt2x00_desc_write(entry_priv->desc, 1, word); + rt2x00_desc_read(txd, 2, &word); rt2x00_set_field32(&word, TXD_W2_IV_OFFSET, IEEE80211_HEADER); rt2x00_set_field32(&word, TXD_W2_AIFS, txdesc->aifs); diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 68d2216131b..d8e681ec4bb 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1037,20 +1037,6 @@ static void rt61pci_init_txentry(struct rt2x00_dev *rt2x00dev, struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data; u32 word; - rt2x00_desc_read(priv_tx->desc, 1, &word); - rt2x00_set_field32(&word, TXD_W1_BUFFER_COUNT, 1); - rt2x00_desc_write(priv_tx->desc, 1, word); - - rt2x00_desc_read(priv_tx->desc, 5, &word); - rt2x00_set_field32(&word, TXD_W5_PID_TYPE, entry->queue->qid); - rt2x00_set_field32(&word, TXD_W5_PID_SUBTYPE, entry->entry_idx); - rt2x00_desc_write(priv_tx->desc, 5, word); - - rt2x00_desc_read(priv_tx->desc, 6, &word); - rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS, - priv_tx->data_dma); - rt2x00_desc_write(priv_tx->desc, 6, word); - rt2x00_desc_read(priv_tx->desc, 0, &word); rt2x00_set_field32(&word, TXD_W0_VALID, 0); rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); @@ -1529,6 +1515,7 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct txentry_desc *txdesc) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); + struct queue_entry_priv_pci_tx *entry_priv = skbdesc->entry->priv_data; __le32 *txd = skbdesc->desc; u32 word; @@ -1542,6 +1529,7 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max); rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER); rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, 1); + rt2x00_set_field32(&word, TXD_W1_BUFFER_COUNT, 1); rt2x00_desc_write(txd, 1, word); rt2x00_desc_read(txd, 2, &word); @@ -1552,11 +1540,19 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_desc_write(txd, 2, word); rt2x00_desc_read(txd, 5, &word); + rt2x00_set_field32(&word, TXD_W5_PID_TYPE, skbdesc->entry->queue->qid); + rt2x00_set_field32(&word, TXD_W5_PID_SUBTYPE, + skbdesc->entry->entry_idx); rt2x00_set_field32(&word, TXD_W5_TX_POWER, TXPOWER_TO_DEV(rt2x00dev->tx_power)); rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1); rt2x00_desc_write(txd, 5, word); + rt2x00_desc_read(txd, 6, &word); + rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS, + entry_priv->data_dma); + rt2x00_desc_write(txd, 6, word); + if (skbdesc->desc_len > TXINFO_SIZE) { rt2x00_desc_read(txd, 11, &word); rt2x00_set_field32(&word, TXD_W11_BUFFER_LENGTH0, skbdesc->data_len); -- cgit v1.2.3-70-g09d2 From 7050ec821c52826b63835dde54ee3d71c7db4262 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 10 May 2008 13:46:13 +0200 Subject: rt2x00: Split rt2x00lib_write_tx_desc() Split rt2x00lib_write_tx_desc() up into a TX descriptor initializor and TX descriptor writer. This split is required to properly allow mac80211 to move its tx_control structure into the skb->cb array. The rt2x00queue_create_tx_descriptor() function will read all tx control information and convert it into a rt2x00 TX descriptor information structure. After that function is complete, we have all information we needed from the tx control structure and are free to start writing into the skb->cb array for our own purposes. rt2x00queue_write_tx_descriptor() will be in charge of really sending the TX descriptor to the hardware and kicking the TX queue. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 11 ++- drivers/net/wireless/rt2x00/rt2500pci.c | 11 ++- drivers/net/wireless/rt2x00/rt2500usb.c | 11 ++- drivers/net/wireless/rt2x00/rt2x00.h | 42 ++++++-- drivers/net/wireless/rt2x00/rt2x00dev.c | 148 ---------------------------- drivers/net/wireless/rt2x00/rt2x00pci.c | 11 ++- drivers/net/wireless/rt2x00/rt2x00queue.c | 157 ++++++++++++++++++++++++++++++ drivers/net/wireless/rt2x00/rt2x00queue.h | 2 + drivers/net/wireless/rt2x00/rt2x00usb.c | 11 ++- drivers/net/wireless/rt2x00/rt61pci.c | 13 ++- drivers/net/wireless/rt2x00/rt73usb.c | 11 ++- 11 files changed, 265 insertions(+), 163 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 2c0cf394c78..d3d9b189fd8 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1492,12 +1492,21 @@ static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, struct rt2x00_intf *intf = vif_to_intf(control->vif); struct queue_entry_priv_pci_tx *priv_tx; struct skb_frame_desc *skbdesc; + struct txentry_desc txdesc; u32 reg; if (unlikely(!intf->beacon)) return -ENOBUFS; priv_tx = intf->beacon->priv_data; + /* + * Copy all TX descriptor information into txdesc, + * after that we are free to use the skb->cb array + * for our information. + */ + intf->beacon->skb = skb; + rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc, control); + /* * Fill in skb descriptor */ @@ -1525,8 +1534,8 @@ static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, * Write entire beacon with descriptor to register, * and kick the beacon generator. */ - rt2x00lib_write_tx_desc(rt2x00dev, skb, control); memcpy(priv_tx->data, skb->data, skb->len); + rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc); rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON); return 0; diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 6c31c5db0ca..7de7980738f 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1808,6 +1808,7 @@ static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, struct rt2x00_intf *intf = vif_to_intf(control->vif); struct queue_entry_priv_pci_tx *priv_tx; struct skb_frame_desc *skbdesc; + struct txentry_desc txdesc; u32 reg; if (unlikely(!intf->beacon)) @@ -1815,6 +1816,14 @@ static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, priv_tx = intf->beacon->priv_data; + /* + * Copy all TX descriptor information into txdesc, + * after that we are free to use the skb->cb array + * for our information. + */ + intf->beacon->skb = skb; + rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc, control); + /* * Fill in skb descriptor */ @@ -1842,8 +1851,8 @@ static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, * Write entire beacon with descriptor to register, * and kick the beacon generator. */ - rt2x00lib_write_tx_desc(rt2x00dev, skb, control); memcpy(priv_tx->data, skb->data, skb->len); + rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc); rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON); return 0; diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 3be4c7ea8dd..6fe713a1d75 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1676,6 +1676,7 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw, struct rt2x00_intf *intf = vif_to_intf(control->vif); struct queue_entry_priv_usb_bcn *priv_bcn; struct skb_frame_desc *skbdesc; + struct txentry_desc txdesc; int pipe = usb_sndbulkpipe(usb_dev, 1); int length; u16 reg; @@ -1685,6 +1686,14 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw, priv_bcn = intf->beacon->priv_data; + /* + * Copy all TX descriptor information into txdesc, + * after that we are free to use the skb->cb array + * for our information. + */ + intf->beacon->skb = skb; + rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc, control); + /* * Add the descriptor in front of the skb. */ @@ -1713,7 +1722,7 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw, rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 0); rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); - rt2x00lib_write_tx_desc(rt2x00dev, skb, control); + rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc); /* * USB devices cannot blindly pass the skb->len as the diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 6f7b34fac16..9c186d79c11 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -926,6 +926,41 @@ static inline u16 get_duration_res(const unsigned int size, const u8 rate) return ((size * 8 * 10) % rate); } +/** + * rt2x00queue_create_tx_descriptor - Create TX descriptor from mac80211 input + * @entry: The entry which will be used to transfer the TX frame. + * @txdesc: rt2x00 TX descriptor which will be initialized by this function. + * @control: mac80211 TX control structure from where we read the information. + * + * This function will initialize the &struct txentry_desc based on information + * from mac80211. This descriptor can then be used by rt2x00lib and the drivers + * to correctly initialize the hardware descriptor. + * Note that before calling this function the skb->cb array must be untouched + * by rt2x00lib. Only after this function completes will it be save to + * overwrite the skb->cb information. + * The reason for this is that mac80211 writes its own tx information into + * the skb->cb array, and this function will use that information to initialize + * the &struct txentry_desc structure. + */ +void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, + struct txentry_desc *txdesc, + struct ieee80211_tx_control *control); + +/** + * rt2x00queue_write_tx_descriptor - Write TX descriptor to hardware + * @entry: The entry which will be used to transfer the TX frame. + * @txdesc: TX descriptor which will be used to write hardware descriptor + * + * This function will write a TX descriptor initialized by + * &rt2x00queue_create_tx_descriptor to the hardware. After this call + * has completed the frame is now owned by the hardware, the hardware + * queue will have automatically be kicked unless this frame was generated + * by rt2x00lib, in which case the frame is "special" and must be kicked + * by the caller. + */ +void rt2x00queue_write_tx_descriptor(struct queue_entry *entry, + struct txentry_desc *txdesc); + /** * rt2x00queue_get_queue - Convert queue index to queue pointer * @rt2x00dev: Pointer to &struct rt2x00_dev. @@ -963,13 +998,6 @@ void rt2x00lib_txdone(struct queue_entry *entry, void rt2x00lib_rxdone(struct queue_entry *entry, struct rxdone_entry_desc *rxdesc); -/* - * TX descriptor initializer - */ -void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev, - struct sk_buff *skb, - struct ieee80211_tx_control *control); - /* * mac80211 handlers. */ diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 46c377873f1..171f445962d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -611,154 +611,6 @@ void rt2x00lib_rxdone(struct queue_entry *entry, } EXPORT_SYMBOL_GPL(rt2x00lib_rxdone); -/* - * TX descriptor initializer - */ -void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev, - struct sk_buff *skb, - struct ieee80211_tx_control *control) -{ - struct txentry_desc txdesc; - struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skbdesc->data; - const struct rt2x00_rate *rate; - int tx_rate; - int length; - int duration; - int residual; - u16 frame_control; - u16 seq_ctrl; - - memset(&txdesc, 0, sizeof(txdesc)); - - txdesc.queue = skbdesc->entry->queue->qid; - txdesc.cw_min = skbdesc->entry->queue->cw_min; - txdesc.cw_max = skbdesc->entry->queue->cw_max; - txdesc.aifs = skbdesc->entry->queue->aifs; - - /* - * Read required fields from ieee80211 header. - */ - frame_control = le16_to_cpu(hdr->frame_control); - seq_ctrl = le16_to_cpu(hdr->seq_ctrl); - - tx_rate = control->tx_rate->hw_value; - - /* - * Check whether this frame is to be acked - */ - if (!(control->flags & IEEE80211_TXCTL_NO_ACK)) - __set_bit(ENTRY_TXD_ACK, &txdesc.flags); - - /* - * Check if this is a RTS/CTS frame - */ - if (is_rts_frame(frame_control) || is_cts_frame(frame_control)) { - __set_bit(ENTRY_TXD_BURST, &txdesc.flags); - if (is_rts_frame(frame_control)) { - __set_bit(ENTRY_TXD_RTS_FRAME, &txdesc.flags); - __set_bit(ENTRY_TXD_ACK, &txdesc.flags); - } else - __clear_bit(ENTRY_TXD_ACK, &txdesc.flags); - if (control->rts_cts_rate) - tx_rate = control->rts_cts_rate->hw_value; - } - - /* - * Determine retry information. - */ - txdesc.retry_limit = control->retry_limit; - if (control->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT) - __set_bit(ENTRY_TXD_RETRY_MODE, &txdesc.flags); - - /* - * Check if more fragments are pending - */ - if (ieee80211_get_morefrag(hdr)) { - __set_bit(ENTRY_TXD_BURST, &txdesc.flags); - __set_bit(ENTRY_TXD_MORE_FRAG, &txdesc.flags); - } - - /* - * Beacons and probe responses require the tsf timestamp - * to be inserted into the frame. - */ - if (txdesc.queue == QID_BEACON || is_probe_resp(frame_control)) - __set_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc.flags); - - /* - * Determine with what IFS priority this frame should be send. - * Set ifs to IFS_SIFS when the this is not the first fragment, - * or this fragment came after RTS/CTS. - */ - if (test_bit(ENTRY_TXD_RTS_FRAME, &txdesc.flags)) { - txdesc.ifs = IFS_SIFS; - } else if (control->flags & IEEE80211_TXCTL_FIRST_FRAGMENT) { - __set_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc.flags); - txdesc.ifs = IFS_BACKOFF; - } else { - txdesc.ifs = IFS_SIFS; - } - - /* - * PLCP setup - * Length calculation depends on OFDM/CCK rate. - */ - rate = rt2x00_get_rate(tx_rate); - txdesc.signal = rate->plcp; - txdesc.service = 0x04; - - length = skbdesc->data_len + FCS_LEN; - if (rate->flags & DEV_RATE_OFDM) { - __set_bit(ENTRY_TXD_OFDM_RATE, &txdesc.flags); - - txdesc.length_high = (length >> 6) & 0x3f; - txdesc.length_low = length & 0x3f; - } else { - /* - * Convert length to microseconds. - */ - residual = get_duration_res(length, rate->bitrate); - duration = get_duration(length, rate->bitrate); - - if (residual != 0) { - duration++; - - /* - * Check if we need to set the Length Extension - */ - if (rate->bitrate == 110 && residual <= 30) - txdesc.service |= 0x80; - } - - txdesc.length_high = (duration >> 8) & 0xff; - txdesc.length_low = duration & 0xff; - - /* - * When preamble is enabled we should set the - * preamble bit for the signal. - */ - if (rt2x00_get_rate_preamble(tx_rate)) - txdesc.signal |= 0x08; - } - - rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, skb, &txdesc); - - /* - * Update queue entry. - */ - skbdesc->entry->skb = skb; - - /* - * The frame has been completely initialized and ready - * for sending to the device. The caller will push the - * frame to the device, but we are going to push the - * frame to debugfs here. - */ - rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TX, skb); -} -EXPORT_SYMBOL_GPL(rt2x00lib_write_tx_desc); - /* * Driver initialization handlers. */ diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index c17078eac19..a056b12fbd1 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -41,6 +41,7 @@ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data; struct skb_frame_desc *skbdesc; + struct txentry_desc txdesc; u32 word; if (rt2x00queue_full(queue)) @@ -57,6 +58,14 @@ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev, return -EINVAL; } + /* + * Copy all TX descriptor information into txdesc, + * after that we are free to use the skb->cb array + * for our information. + */ + entry->skb = skb; + rt2x00queue_create_tx_descriptor(entry, &txdesc, control); + /* * Fill in skb descriptor */ @@ -69,8 +78,8 @@ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev, memcpy(&priv_tx->control, control, sizeof(priv_tx->control)); memcpy(priv_tx->data, skb->data, skb->len); - rt2x00lib_write_tx_desc(rt2x00dev, skb, control); + rt2x00queue_write_tx_descriptor(entry, &txdesc); rt2x00queue_index_inc(queue, Q_INDEX); return 0; diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 95f8dd3462f..19c10629c76 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -29,6 +29,163 @@ #include "rt2x00.h" #include "rt2x00lib.h" +void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, + struct txentry_desc *txdesc, + struct ieee80211_tx_control *control) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data; + struct ieee80211_rate *rate = control->tx_rate; + const struct rt2x00_rate *hwrate; + unsigned int data_length; + unsigned int duration; + unsigned int residual; + u16 frame_control; + + memset(txdesc, 0, sizeof(*txdesc)); + + /* + * Initialize information from queue + */ + txdesc->queue = entry->queue->qid; + txdesc->cw_min = entry->queue->cw_min; + txdesc->cw_max = entry->queue->cw_max; + txdesc->aifs = entry->queue->aifs; + + /* Data length should be extended with 4 bytes for CRC */ + data_length = entry->skb->len + 4; + + /* + * Read required fields from ieee80211 header. + */ + frame_control = le16_to_cpu(hdr->frame_control); + + /* + * Check whether this frame is to be acked. + */ + if (!(control->flags & IEEE80211_TXCTL_NO_ACK)) + __set_bit(ENTRY_TXD_ACK, &txdesc->flags); + + /* + * Check if this is a RTS/CTS frame + */ + if (is_rts_frame(frame_control) || is_cts_frame(frame_control)) { + __set_bit(ENTRY_TXD_BURST, &txdesc->flags); + if (is_rts_frame(frame_control)) { + __set_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags); + __set_bit(ENTRY_TXD_ACK, &txdesc->flags); + } else { + __set_bit(ENTRY_TXD_CTS_FRAME, &txdesc->flags); + __clear_bit(ENTRY_TXD_ACK, &txdesc->flags); + } + if (control->rts_cts_rate) + rate = control->rts_cts_rate; + } + + /* + * Determine retry information. + */ + txdesc->retry_limit = control->retry_limit; + if (control->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT) + __set_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags); + + /* + * Check if more fragments are pending + */ + if (ieee80211_get_morefrag(hdr)) { + __set_bit(ENTRY_TXD_BURST, &txdesc->flags); + __set_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags); + } + + /* + * Beacons and probe responses require the tsf timestamp + * to be inserted into the frame. + */ + if (txdesc->queue == QID_BEACON || is_probe_resp(frame_control)) + __set_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags); + + /* + * Determine with what IFS priority this frame should be send. + * Set ifs to IFS_SIFS when the this is not the first fragment, + * or this fragment came after RTS/CTS. + */ + if (test_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags)) { + txdesc->ifs = IFS_SIFS; + } else if (control->flags & IEEE80211_TXCTL_FIRST_FRAGMENT) { + __set_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags); + txdesc->ifs = IFS_BACKOFF; + } else { + txdesc->ifs = IFS_SIFS; + } + + /* + * PLCP setup + * Length calculation depends on OFDM/CCK rate. + */ + hwrate = rt2x00_get_rate(rate->hw_value); + txdesc->signal = hwrate->plcp; + txdesc->service = 0x04; + + if (hwrate->flags & DEV_RATE_OFDM) { + __set_bit(ENTRY_TXD_OFDM_RATE, &txdesc->flags); + + txdesc->length_high = (data_length >> 6) & 0x3f; + txdesc->length_low = data_length & 0x3f; + } else { + /* + * Convert length to microseconds. + */ + residual = get_duration_res(data_length, hwrate->bitrate); + duration = get_duration(data_length, hwrate->bitrate); + + if (residual != 0) { + duration++; + + /* + * Check if we need to set the Length Extension + */ + if (hwrate->bitrate == 110 && residual <= 30) + txdesc->service |= 0x80; + } + + txdesc->length_high = (duration >> 8) & 0xff; + txdesc->length_low = duration & 0xff; + + /* + * When preamble is enabled we should set the + * preamble bit for the signal. + */ + if (rt2x00_get_rate_preamble(rate->hw_value)) + txdesc->signal |= 0x08; + } +} +EXPORT_SYMBOL_GPL(rt2x00queue_create_tx_descriptor); + +void rt2x00queue_write_tx_descriptor(struct queue_entry *entry, + struct txentry_desc *txdesc) +{ + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); + + rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, entry->skb, txdesc); + + /* + * All processing on the frame has been completed, this means + * it is now ready to be dumped to userspace through debugfs. + */ + rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TX, entry->skb); + + /* + * We are done writing the frame to the queue entry, + * if this entry is a RTS of CTS-to-self frame we are done, + * otherwise we need to kick the queue. + */ + if (rt2x00dev->ops->lib->kick_tx_queue && + !(skbdesc->flags & FRAME_DESC_DRIVER_GENERATED)) + rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, + entry->queue->qid); +} +EXPORT_SYMBOL_GPL(rt2x00queue_write_tx_descriptor); + struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev, const enum data_queue_qid queue) { diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 4bde98ba3c6..c6edc52873c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -203,6 +203,7 @@ struct txdone_entry_desc { * enum txentry_desc_flags: Status flags for TX entry descriptor * * @ENTRY_TXD_RTS_FRAME: This frame is a RTS frame. + * @ENTRY_TXD_CTS_FRAME: This frame is a CTS-to-self frame. * @ENTRY_TXD_OFDM_RATE: This frame is send out with an OFDM rate. * @ENTRY_TXD_FIRST_FRAGMENT: This is the first frame. * @ENTRY_TXD_MORE_FRAG: This frame is followed by another fragment. @@ -213,6 +214,7 @@ struct txdone_entry_desc { */ enum txentry_desc_flags { ENTRY_TXD_RTS_FRAME, + ENTRY_TXD_CTS_FRAME, ENTRY_TXD_OFDM_RATE, ENTRY_TXD_FIRST_FRAGMENT, ENTRY_TXD_MORE_FRAG, diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index f72b3d07a42..df6621025f4 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -186,6 +186,7 @@ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); struct queue_entry_priv_usb_tx *priv_tx = entry->priv_data; struct skb_frame_desc *skbdesc; + struct txentry_desc txdesc; u32 length; if (rt2x00queue_full(queue)) @@ -199,6 +200,14 @@ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, return -EINVAL; } + /* + * Copy all TX descriptor information into txdesc, + * after that we are free to use the skb->cb array + * for our information. + */ + entry->skb = skb; + rt2x00queue_create_tx_descriptor(entry, &txdesc, control); + /* * Add the descriptor in front of the skb. */ @@ -216,7 +225,7 @@ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, skbdesc->entry = entry; memcpy(&priv_tx->control, control, sizeof(priv_tx->control)); - rt2x00lib_write_tx_desc(rt2x00dev, skb, control); + rt2x00queue_write_tx_descriptor(entry, &txdesc); /* * USB devices cannot blindly pass the skb->len as the diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index d8e681ec4bb..d01d5f16bbc 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2361,18 +2361,27 @@ static u64 rt61pci_get_tsf(struct ieee80211_hw *hw) } static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *control) + struct ieee80211_tx_control *control) { struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_intf *intf = vif_to_intf(control->vif); struct queue_entry_priv_pci_tx *priv_tx; struct skb_frame_desc *skbdesc; + struct txentry_desc txdesc; unsigned int beacon_base; u32 reg; if (unlikely(!intf->beacon)) return -ENOBUFS; + /* + * Copy all TX descriptor information into txdesc, + * after that we are free to use the skb->cb array + * for our information. + */ + intf->beacon->skb = skb; + rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc, control); + priv_tx = intf->beacon->priv_data; memset(priv_tx->desc, 0, intf->beacon->queue->desc_size); @@ -2402,7 +2411,7 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, * Write entire beacon with descriptor to register, * and kick the beacon generator. */ - rt2x00lib_write_tx_desc(rt2x00dev, skb, control); + rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc); beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx); rt2x00pci_register_multiwrite(rt2x00dev, beacon_base, skbdesc->desc, skbdesc->desc_len); diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 1bcf8c132cd..bc44116a8a3 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1956,12 +1956,21 @@ static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_intf *intf = vif_to_intf(control->vif); struct skb_frame_desc *skbdesc; + struct txentry_desc txdesc; unsigned int beacon_base; u32 reg; if (unlikely(!intf->beacon)) return -ENOBUFS; + /* + * Copy all TX descriptor information into txdesc, + * after that we are free to use the skb->cb array + * for our information. + */ + intf->beacon->skb = skb; + rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc, control); + /* * Add the descriptor in front of the skb. */ @@ -1994,7 +2003,7 @@ static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, * Write entire beacon with descriptor to register, * and kick the beacon generator. */ - rt2x00lib_write_tx_desc(rt2x00dev, skb, control); + rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc); beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx); rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE, USB_VENDOR_REQUEST_OUT, beacon_base, 0, -- cgit v1.2.3-70-g09d2 From dec13b6bda600c7e7da993e634562873112af50b Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 10 May 2008 13:46:08 +0200 Subject: rt2x00: Remove redundant flags/dev_flags initializations the rxdesc structure is properly memsetted before passed to the driver. This means we don't have to reinitialize the flags and dev_flags fields in the drivers again. This will prevent problems when the rxdone handler is adding flags in a earlier status and will make the code look nicer when we are adding more read attributes in the rxdone handler in the driver. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 3 +-- drivers/net/wireless/rt2x00/rt2500pci.c | 2 -- drivers/net/wireless/rt2x00/rt2500usb.c | 2 -- drivers/net/wireless/rt2x00/rt61pci.c | 2 -- drivers/net/wireless/rt2x00/rt73usb.c | 2 -- 5 files changed, 1 insertion(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index d3d9b189fd8..a491ba5bb5c 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1087,7 +1087,6 @@ static void rt2400pci_fill_rxdone(struct queue_entry *entry, rt2x00_desc_read(priv_rx->desc, 2, &word2); rt2x00_desc_read(priv_rx->desc, 3, &word3); - rxdesc->flags = 0; if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR)) @@ -1103,7 +1102,7 @@ static void rt2400pci_fill_rxdone(struct queue_entry *entry, entry->queue->rt2x00dev->rssi_offset; rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); - rxdesc->dev_flags = RXDONE_SIGNAL_PLCP; + rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP; if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) rxdesc->dev_flags |= RXDONE_MY_BSS; } diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 7de7980738f..805781306dd 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1242,7 +1242,6 @@ static void rt2500pci_fill_rxdone(struct queue_entry *entry, rt2x00_desc_read(priv_rx->desc, 0, &word0); rt2x00_desc_read(priv_rx->desc, 2, &word2); - rxdesc->flags = 0; if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR)) @@ -1259,7 +1258,6 @@ static void rt2500pci_fill_rxdone(struct queue_entry *entry, entry->queue->rt2x00dev->rssi_offset; rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); - rxdesc->dev_flags = 0; if (rt2x00_get_field32(word0, RXD_W0_OFDM)) rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP; if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 6fe713a1d75..0bf9ab3da5e 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1149,7 +1149,6 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry, rt2x00_desc_read(rxd, 0, &word0); rt2x00_desc_read(rxd, 1, &word1); - rxdesc->flags = 0; if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR)) @@ -1166,7 +1165,6 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry, entry->queue->rt2x00dev->rssi_offset; rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); - rxdesc->dev_flags = 0; if (rt2x00_get_field32(word0, RXD_W0_OFDM)) rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP; if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index d01d5f16bbc..2e5e45cbd2e 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1668,7 +1668,6 @@ static void rt61pci_fill_rxdone(struct queue_entry *entry, rt2x00_desc_read(priv_rx->desc, 0, &word0); rt2x00_desc_read(priv_rx->desc, 1, &word1); - rxdesc->flags = 0; if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; @@ -1682,7 +1681,6 @@ static void rt61pci_fill_rxdone(struct queue_entry *entry, rxdesc->rssi = rt61pci_agc_to_rssi(entry->queue->rt2x00dev, word1); rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); - rxdesc->dev_flags = 0; if (rt2x00_get_field32(word0, RXD_W0_OFDM)) rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP; if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index bc44116a8a3..5d70dd840c1 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1423,7 +1423,6 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry, rt2x00_desc_read(rxd, 0, &word0); rt2x00_desc_read(rxd, 1, &word1); - rxdesc->flags = 0; if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; @@ -1437,7 +1436,6 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry, rxdesc->rssi = rt73usb_agc_to_rssi(entry->queue->rt2x00dev, word1); rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); - rxdesc->dev_flags = 0; if (rt2x00_get_field32(word0, RXD_W0_OFDM)) rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP; if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) -- cgit v1.2.3-70-g09d2 From b8be63ffa5dc44324e7f507997870fa3e4b17619 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 10 May 2008 13:46:03 +0200 Subject: rt2x00: Merge RX and TX entry private data With the pending removal of the tx_control structure we can merge the RX and TX entry private data structure in advance. This will temporarily increase the required memory for the queue, but that overhead will only be limited. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 78 ++++++++--------- drivers/net/wireless/rt2x00/rt2500pci.c | 72 ++++++++-------- drivers/net/wireless/rt2x00/rt2500usb.c | 33 ++++---- drivers/net/wireless/rt2x00/rt2x00pci.c | 89 +++++++------------- drivers/net/wireless/rt2x00/rt2x00pci.h | 22 +---- drivers/net/wireless/rt2x00/rt2x00usb.c | 144 +++++++++++++------------------- drivers/net/wireless/rt2x00/rt2x00usb.h | 17 +--- drivers/net/wireless/rt2x00/rt61pci.c | 69 ++++++++------- drivers/net/wireless/rt2x00/rt73usb.c | 6 +- 9 files changed, 223 insertions(+), 307 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index a491ba5bb5c..b11f445c747 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -620,39 +620,38 @@ static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev) static void rt2400pci_init_rxentry(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry) { - struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data; + struct queue_entry_priv_pci *entry_priv = entry->priv_data; u32 word; - rt2x00_desc_read(priv_rx->desc, 2, &word); + rt2x00_desc_read(entry_priv->desc, 2, &word); rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH, entry->queue->data_size); - rt2x00_desc_write(priv_rx->desc, 2, word); + rt2x00_desc_write(entry_priv->desc, 2, word); - rt2x00_desc_read(priv_rx->desc, 1, &word); - rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, priv_rx->data_dma); - rt2x00_desc_write(priv_rx->desc, 1, word); + rt2x00_desc_read(entry_priv->desc, 1, &word); + rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, entry_priv->data_dma); + rt2x00_desc_write(entry_priv->desc, 1, word); - rt2x00_desc_read(priv_rx->desc, 0, &word); + rt2x00_desc_read(entry_priv->desc, 0, &word); rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); - rt2x00_desc_write(priv_rx->desc, 0, word); + rt2x00_desc_write(entry_priv->desc, 0, word); } static void rt2400pci_init_txentry(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry) { - struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data; + struct queue_entry_priv_pci *entry_priv = entry->priv_data; u32 word; - rt2x00_desc_read(priv_tx->desc, 0, &word); + rt2x00_desc_read(entry_priv->desc, 0, &word); rt2x00_set_field32(&word, TXD_W0_VALID, 0); rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); - rt2x00_desc_write(priv_tx->desc, 0, word); + rt2x00_desc_write(entry_priv->desc, 0, word); } static int rt2400pci_init_queues(struct rt2x00_dev *rt2x00dev) { - struct queue_entry_priv_pci_rx *priv_rx; - struct queue_entry_priv_pci_tx *priv_tx; + struct queue_entry_priv_pci *entry_priv; u32 reg; /* @@ -665,28 +664,28 @@ static int rt2400pci_init_queues(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, TXCSR2_NUM_PRIO, rt2x00dev->tx[0].limit); rt2x00pci_register_write(rt2x00dev, TXCSR2, reg); - priv_tx = rt2x00dev->tx[1].entries[0].priv_data; + entry_priv = rt2x00dev->tx[1].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, TXCSR3, ®); rt2x00_set_field32(®, TXCSR3_TX_RING_REGISTER, - priv_tx->desc_dma); + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, TXCSR3, reg); - priv_tx = rt2x00dev->tx[0].entries[0].priv_data; + entry_priv = rt2x00dev->tx[0].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, TXCSR5, ®); rt2x00_set_field32(®, TXCSR5_PRIO_RING_REGISTER, - priv_tx->desc_dma); + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, TXCSR5, reg); - priv_tx = rt2x00dev->bcn[1].entries[0].priv_data; + entry_priv = rt2x00dev->bcn[1].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, TXCSR4, ®); rt2x00_set_field32(®, TXCSR4_ATIM_RING_REGISTER, - priv_tx->desc_dma); + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, TXCSR4, reg); - priv_tx = rt2x00dev->bcn[0].entries[0].priv_data; + entry_priv = rt2x00dev->bcn[0].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, TXCSR6, ®); rt2x00_set_field32(®, TXCSR6_BEACON_RING_REGISTER, - priv_tx->desc_dma); + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, TXCSR6, reg); rt2x00pci_register_read(rt2x00dev, RXCSR1, ®); @@ -694,9 +693,10 @@ static int rt2400pci_init_queues(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, RXCSR1_NUM_RXD, rt2x00dev->rx->limit); rt2x00pci_register_write(rt2x00dev, RXCSR1, reg); - priv_rx = rt2x00dev->rx->entries[0].priv_data; + entry_priv = rt2x00dev->rx->entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, RXCSR2, ®); - rt2x00_set_field32(®, RXCSR2_RX_RING_REGISTER, priv_rx->desc_dma); + rt2x00_set_field32(®, RXCSR2_RX_RING_REGISTER, + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, RXCSR2, reg); return 0; @@ -995,7 +995,7 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct txentry_desc *txdesc) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); - struct queue_entry_priv_pci_tx *entry_priv = skbdesc->entry->priv_data; + struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data; __le32 *txd = skbdesc->desc; u32 word; @@ -1078,14 +1078,14 @@ static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, static void rt2400pci_fill_rxdone(struct queue_entry *entry, struct rxdone_entry_desc *rxdesc) { - struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data; + struct queue_entry_priv_pci *entry_priv = entry->priv_data; u32 word0; u32 word2; u32 word3; - rt2x00_desc_read(priv_rx->desc, 0, &word0); - rt2x00_desc_read(priv_rx->desc, 2, &word2); - rt2x00_desc_read(priv_rx->desc, 3, &word3); + rt2x00_desc_read(entry_priv->desc, 0, &word0); + rt2x00_desc_read(entry_priv->desc, 2, &word2); + rt2x00_desc_read(entry_priv->desc, 3, &word3); if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; @@ -1114,15 +1114,15 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, const enum data_queue_qid queue_idx) { struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, queue_idx); - struct queue_entry_priv_pci_tx *priv_tx; + struct queue_entry_priv_pci *entry_priv; struct queue_entry *entry; struct txdone_entry_desc txdesc; u32 word; while (!rt2x00queue_empty(queue)) { entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); - priv_tx = entry->priv_data; - rt2x00_desc_read(priv_tx->desc, 0, &word); + entry_priv = entry->priv_data; + rt2x00_desc_read(entry_priv->desc, 0, &word); if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || !rt2x00_get_field32(word, TXD_W0_VALID)) @@ -1489,14 +1489,14 @@ static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, { struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_intf *intf = vif_to_intf(control->vif); - struct queue_entry_priv_pci_tx *priv_tx; + struct queue_entry_priv_pci *entry_priv; struct skb_frame_desc *skbdesc; struct txentry_desc txdesc; u32 reg; if (unlikely(!intf->beacon)) return -ENOBUFS; - priv_tx = intf->beacon->priv_data; + entry_priv = intf->beacon->priv_data; /* * Copy all TX descriptor information into txdesc, @@ -1514,7 +1514,7 @@ static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED; skbdesc->data = skb->data; skbdesc->data_len = skb->len; - skbdesc->desc = priv_tx->desc; + skbdesc->desc = entry_priv->desc; skbdesc->desc_len = intf->beacon->queue->desc_size; skbdesc->entry = intf->beacon; @@ -1533,7 +1533,7 @@ static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, * Write entire beacon with descriptor to register, * and kick the beacon generator. */ - memcpy(priv_tx->data, skb->data, skb->len); + memcpy(entry_priv->data, skb->data, skb->len); rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc); rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON); @@ -1594,28 +1594,28 @@ static const struct data_queue_desc rt2400pci_queue_rx = { .entry_num = RX_ENTRIES, .data_size = DATA_FRAME_SIZE, .desc_size = RXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_pci_rx), + .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct data_queue_desc rt2400pci_queue_tx = { .entry_num = TX_ENTRIES, .data_size = DATA_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_pci_tx), + .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct data_queue_desc rt2400pci_queue_bcn = { .entry_num = BEACON_ENTRIES, .data_size = MGMT_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_pci_tx), + .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct data_queue_desc rt2400pci_queue_atim = { .entry_num = ATIM_ENTRIES, .data_size = DATA_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_pci_tx), + .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct rt2x00_ops rt2400pci_ops = { diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 805781306dd..06e87cdff45 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -715,34 +715,33 @@ dynamic_cca_tune: static void rt2500pci_init_rxentry(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry) { - struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data; + struct queue_entry_priv_pci *entry_priv = entry->priv_data; u32 word; - rt2x00_desc_read(priv_rx->desc, 1, &word); - rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, priv_rx->data_dma); - rt2x00_desc_write(priv_rx->desc, 1, word); + rt2x00_desc_read(entry_priv->desc, 1, &word); + rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, entry_priv->data_dma); + rt2x00_desc_write(entry_priv->desc, 1, word); - rt2x00_desc_read(priv_rx->desc, 0, &word); + rt2x00_desc_read(entry_priv->desc, 0, &word); rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); - rt2x00_desc_write(priv_rx->desc, 0, word); + rt2x00_desc_write(entry_priv->desc, 0, word); } static void rt2500pci_init_txentry(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry) { - struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data; + struct queue_entry_priv_pci *entry_priv = entry->priv_data; u32 word; - rt2x00_desc_read(priv_tx->desc, 0, &word); + rt2x00_desc_read(entry_priv->desc, 0, &word); rt2x00_set_field32(&word, TXD_W0_VALID, 0); rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); - rt2x00_desc_write(priv_tx->desc, 0, word); + rt2x00_desc_write(entry_priv->desc, 0, word); } static int rt2500pci_init_queues(struct rt2x00_dev *rt2x00dev) { - struct queue_entry_priv_pci_rx *priv_rx; - struct queue_entry_priv_pci_tx *priv_tx; + struct queue_entry_priv_pci *entry_priv; u32 reg; /* @@ -755,28 +754,28 @@ static int rt2500pci_init_queues(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, TXCSR2_NUM_PRIO, rt2x00dev->tx[0].limit); rt2x00pci_register_write(rt2x00dev, TXCSR2, reg); - priv_tx = rt2x00dev->tx[1].entries[0].priv_data; + entry_priv = rt2x00dev->tx[1].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, TXCSR3, ®); rt2x00_set_field32(®, TXCSR3_TX_RING_REGISTER, - priv_tx->desc_dma); + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, TXCSR3, reg); - priv_tx = rt2x00dev->tx[0].entries[0].priv_data; + entry_priv = rt2x00dev->tx[0].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, TXCSR5, ®); rt2x00_set_field32(®, TXCSR5_PRIO_RING_REGISTER, - priv_tx->desc_dma); + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, TXCSR5, reg); - priv_tx = rt2x00dev->bcn[1].entries[0].priv_data; + entry_priv = rt2x00dev->bcn[1].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, TXCSR4, ®); rt2x00_set_field32(®, TXCSR4_ATIM_RING_REGISTER, - priv_tx->desc_dma); + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, TXCSR4, reg); - priv_tx = rt2x00dev->bcn[0].entries[0].priv_data; + entry_priv = rt2x00dev->bcn[0].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, TXCSR6, ®); rt2x00_set_field32(®, TXCSR6_BEACON_RING_REGISTER, - priv_tx->desc_dma); + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, TXCSR6, reg); rt2x00pci_register_read(rt2x00dev, RXCSR1, ®); @@ -784,9 +783,10 @@ static int rt2500pci_init_queues(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, RXCSR1_NUM_RXD, rt2x00dev->rx->limit); rt2x00pci_register_write(rt2x00dev, RXCSR1, reg); - priv_rx = rt2x00dev->rx->entries[0].priv_data; + entry_priv = rt2x00dev->rx->entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, RXCSR2, ®); - rt2x00_set_field32(®, RXCSR2_RX_RING_REGISTER, priv_rx->desc_dma); + rt2x00_set_field32(®, RXCSR2_RX_RING_REGISTER, + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, RXCSR2, reg); return 0; @@ -1154,7 +1154,7 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct txentry_desc *txdesc) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); - struct queue_entry_priv_pci_tx *entry_priv = skbdesc->entry->priv_data; + struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data; __le32 *txd = skbdesc->desc; u32 word; @@ -1235,12 +1235,12 @@ static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, static void rt2500pci_fill_rxdone(struct queue_entry *entry, struct rxdone_entry_desc *rxdesc) { - struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data; + struct queue_entry_priv_pci *entry_priv = entry->priv_data; u32 word0; u32 word2; - rt2x00_desc_read(priv_rx->desc, 0, &word0); - rt2x00_desc_read(priv_rx->desc, 2, &word2); + rt2x00_desc_read(entry_priv->desc, 0, &word0); + rt2x00_desc_read(entry_priv->desc, 2, &word2); if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; @@ -1271,15 +1271,15 @@ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev, const enum data_queue_qid queue_idx) { struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, queue_idx); - struct queue_entry_priv_pci_tx *priv_tx; + struct queue_entry_priv_pci *entry_priv; struct queue_entry *entry; struct txdone_entry_desc txdesc; u32 word; while (!rt2x00queue_empty(queue)) { entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); - priv_tx = entry->priv_data; - rt2x00_desc_read(priv_tx->desc, 0, &word); + entry_priv = entry->priv_data; + rt2x00_desc_read(entry_priv->desc, 0, &word); if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || !rt2x00_get_field32(word, TXD_W0_VALID)) @@ -1804,7 +1804,7 @@ static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, { struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_intf *intf = vif_to_intf(control->vif); - struct queue_entry_priv_pci_tx *priv_tx; + struct queue_entry_priv_pci *entry_priv; struct skb_frame_desc *skbdesc; struct txentry_desc txdesc; u32 reg; @@ -1812,7 +1812,7 @@ static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, if (unlikely(!intf->beacon)) return -ENOBUFS; - priv_tx = intf->beacon->priv_data; + entry_priv = intf->beacon->priv_data; /* * Copy all TX descriptor information into txdesc, @@ -1830,7 +1830,7 @@ static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED; skbdesc->data = skb->data; skbdesc->data_len = skb->len; - skbdesc->desc = priv_tx->desc; + skbdesc->desc = entry_priv->desc; skbdesc->desc_len = intf->beacon->queue->desc_size; skbdesc->entry = intf->beacon; @@ -1849,7 +1849,7 @@ static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, * Write entire beacon with descriptor to register, * and kick the beacon generator. */ - memcpy(priv_tx->data, skb->data, skb->len); + memcpy(entry_priv->data, skb->data, skb->len); rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc); rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON); @@ -1910,28 +1910,28 @@ static const struct data_queue_desc rt2500pci_queue_rx = { .entry_num = RX_ENTRIES, .data_size = DATA_FRAME_SIZE, .desc_size = RXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_pci_rx), + .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct data_queue_desc rt2500pci_queue_tx = { .entry_num = TX_ENTRIES, .data_size = DATA_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_pci_tx), + .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct data_queue_desc rt2500pci_queue_bcn = { .entry_num = BEACON_ENTRIES, .data_size = MGMT_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_pci_tx), + .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct data_queue_desc rt2500pci_queue_atim = { .entry_num = ATIM_ENTRIES, .data_size = DATA_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_pci_tx), + .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct rt2x00_ops rt2500pci_ops = { diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 0bf9ab3da5e..4122c5ebe7c 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1124,11 +1124,12 @@ static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, static void rt2500usb_fill_rxdone(struct queue_entry *entry, struct rxdone_entry_desc *rxdesc) { - struct queue_entry_priv_usb_rx *priv_rx = entry->priv_data; + struct queue_entry_priv_usb *entry_priv = entry->priv_data; struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); __le32 *rxd = (__le32 *)(entry->skb->data + - (priv_rx->urb->actual_length - entry->queue->desc_size)); + (entry_priv->urb->actual_length - + entry->queue->desc_size)); u32 word0; u32 word1; @@ -1184,7 +1185,7 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry, static void rt2500usb_beacondone(struct urb *urb) { struct queue_entry *entry = (struct queue_entry *)urb->context; - struct queue_entry_priv_usb_bcn *priv_bcn = entry->priv_data; + struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data; if (!test_bit(DEVICE_ENABLED_RADIO, &entry->queue->rt2x00dev->flags)) return; @@ -1195,9 +1196,9 @@ static void rt2500usb_beacondone(struct urb *urb) * Otherwise we should free the sk_buffer, the device * should be doing the rest of the work now. */ - if (priv_bcn->guardian_urb == urb) { - usb_submit_urb(priv_bcn->urb, GFP_ATOMIC); - } else if (priv_bcn->urb == urb) { + if (bcn_priv->guardian_urb == urb) { + usb_submit_urb(bcn_priv->urb, GFP_ATOMIC); + } else if (bcn_priv->urb == urb) { dev_kfree_skb(entry->skb); entry->skb = NULL; } @@ -1672,7 +1673,7 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw, struct rt2x00_dev *rt2x00dev = hw->priv; struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev); struct rt2x00_intf *intf = vif_to_intf(control->vif); - struct queue_entry_priv_usb_bcn *priv_bcn; + struct queue_entry_priv_usb_bcn *bcn_priv; struct skb_frame_desc *skbdesc; struct txentry_desc txdesc; int pipe = usb_sndbulkpipe(usb_dev, 1); @@ -1682,7 +1683,7 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw, if (unlikely(!intf->beacon)) return -ENOBUFS; - priv_bcn = intf->beacon->priv_data; + bcn_priv = intf->beacon->priv_data; /* * Copy all TX descriptor information into txdesc, @@ -1729,7 +1730,7 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw, */ length = rt2500usb_get_tx_data_len(rt2x00dev, skb); - usb_fill_bulk_urb(priv_bcn->urb, usb_dev, pipe, + usb_fill_bulk_urb(bcn_priv->urb, usb_dev, pipe, skb->data, length, rt2500usb_beacondone, intf->beacon); @@ -1738,15 +1739,15 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw, * We only need a single byte, so lets recycle * the 'flags' field we are not using for beacons. */ - priv_bcn->guardian_data = 0; - usb_fill_bulk_urb(priv_bcn->guardian_urb, usb_dev, pipe, - &priv_bcn->guardian_data, 1, rt2500usb_beacondone, + bcn_priv->guardian_data = 0; + usb_fill_bulk_urb(bcn_priv->guardian_urb, usb_dev, pipe, + &bcn_priv->guardian_data, 1, rt2500usb_beacondone, intf->beacon); /* * Send out the guardian byte. */ - usb_submit_urb(priv_bcn->guardian_urb, GFP_ATOMIC); + usb_submit_urb(bcn_priv->guardian_urb, GFP_ATOMIC); /* * Enable beacon generation. @@ -1797,14 +1798,14 @@ static const struct data_queue_desc rt2500usb_queue_rx = { .entry_num = RX_ENTRIES, .data_size = DATA_FRAME_SIZE, .desc_size = RXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_usb_rx), + .priv_size = sizeof(struct queue_entry_priv_usb), }; static const struct data_queue_desc rt2500usb_queue_tx = { .entry_num = TX_ENTRIES, .data_size = DATA_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_usb_tx), + .priv_size = sizeof(struct queue_entry_priv_usb), }; static const struct data_queue_desc rt2500usb_queue_bcn = { @@ -1818,7 +1819,7 @@ static const struct data_queue_desc rt2500usb_queue_atim = { .entry_num = ATIM_ENTRIES, .data_size = DATA_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_usb_tx), + .priv_size = sizeof(struct queue_entry_priv_usb), }; static const struct rt2x00_ops rt2500usb_ops = { diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index a056b12fbd1..fa7de41be04 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -39,7 +39,7 @@ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev, struct ieee80211_tx_control *control) { struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); - struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data; + struct queue_entry_priv_pci *entry_priv = entry->priv_data; struct skb_frame_desc *skbdesc; struct txentry_desc txdesc; u32 word; @@ -47,7 +47,7 @@ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev, if (rt2x00queue_full(queue)) return -EINVAL; - rt2x00_desc_read(priv_tx->desc, 0, &word); + rt2x00_desc_read(entry_priv->desc, 0, &word); if (rt2x00_get_field32(word, TXD_ENTRY_OWNER_NIC) || rt2x00_get_field32(word, TXD_ENTRY_VALID)) { @@ -72,12 +72,12 @@ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev, skbdesc = get_skb_frame_desc(skb); skbdesc->data = skb->data; skbdesc->data_len = skb->len; - skbdesc->desc = priv_tx->desc; + skbdesc->desc = entry_priv->desc; skbdesc->desc_len = queue->desc_size; skbdesc->entry = entry; - memcpy(&priv_tx->control, control, sizeof(priv_tx->control)); - memcpy(priv_tx->data, skb->data, skb->len); + memcpy(&entry_priv->control, control, sizeof(entry_priv->control)); + memcpy(entry_priv->data, skb->data, skb->len); rt2x00queue_write_tx_descriptor(entry, &txdesc); rt2x00queue_index_inc(queue, Q_INDEX); @@ -93,7 +93,7 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) { struct data_queue *queue = rt2x00dev->rx; struct queue_entry *entry; - struct queue_entry_priv_pci_rx *priv_rx; + struct queue_entry_priv_pci *entry_priv; struct ieee80211_hdr *hdr; struct skb_frame_desc *skbdesc; struct rxdone_entry_desc rxdesc; @@ -103,8 +103,8 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) while (1) { entry = rt2x00queue_get_entry(queue, Q_INDEX); - priv_rx = entry->priv_data; - rt2x00_desc_read(priv_rx->desc, 0, &word); + entry_priv = entry->priv_data; + rt2x00_desc_read(entry_priv->desc, 0, &word); if (rt2x00_get_field32(word, RXD_ENTRY_OWNER_NIC)) break; @@ -112,7 +112,7 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) memset(&rxdesc, 0, sizeof(rxdesc)); rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc); - hdr = (struct ieee80211_hdr *)priv_rx->data; + hdr = (struct ieee80211_hdr *)entry_priv->data; header_size = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)); @@ -132,7 +132,7 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) skb_reserve(entry->skb, align); memcpy(skb_put(entry->skb, rxdesc.size), - priv_rx->data, rxdesc.size); + entry_priv->data, rxdesc.size); /* * Fill in skb descriptor @@ -141,7 +141,7 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) memset(skbdesc, 0, sizeof(*skbdesc)); skbdesc->data = entry->skb->data; skbdesc->data_len = entry->skb->len; - skbdesc->desc = priv_rx->desc; + skbdesc->desc = entry_priv->desc; skbdesc->desc_len = queue->desc_size; skbdesc->entry = entry; @@ -152,7 +152,7 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) if (test_bit(DEVICE_ENABLED_RADIO, &queue->rt2x00dev->flags)) { rt2x00_set_field32(&word, RXD_ENTRY_OWNER_NIC, 1); - rt2x00_desc_write(priv_rx->desc, 0, word); + rt2x00_desc_write(entry_priv->desc, 0, word); } rt2x00queue_index_inc(queue, Q_INDEX); @@ -163,10 +163,10 @@ EXPORT_SYMBOL_GPL(rt2x00pci_rxdone); void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry, struct txdone_entry_desc *txdesc) { - struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data; + struct queue_entry_priv_pci *entry_priv = entry->priv_data; u32 word; - txdesc->control = &priv_tx->control; + txdesc->control = &entry_priv->control; rt2x00lib_txdone(entry, txdesc); /* @@ -174,10 +174,10 @@ void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry, */ entry->flags = 0; - rt2x00_desc_read(priv_tx->desc, 0, &word); + rt2x00_desc_read(entry_priv->desc, 0, &word); rt2x00_set_field32(&word, TXD_ENTRY_OWNER_NIC, 0); rt2x00_set_field32(&word, TXD_ENTRY_VALID, 0); - rt2x00_desc_write(priv_tx->desc, 0, word); + rt2x00_desc_write(entry_priv->desc, 0, word); rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE); @@ -187,7 +187,7 @@ void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry, * is reenabled when the txdone handler has finished. */ if (!rt2x00queue_full(entry->queue)) - ieee80211_wake_queue(rt2x00dev->hw, priv_tx->control.queue); + ieee80211_wake_queue(rt2x00dev->hw, entry_priv->control.queue); } EXPORT_SYMBOL_GPL(rt2x00pci_txdone); @@ -226,14 +226,9 @@ static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev, struct data_queue *queue) { struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev); - struct queue_entry_priv_pci_rx *priv_rx; - struct queue_entry_priv_pci_tx *priv_tx; + struct queue_entry_priv_pci *entry_priv; void *addr; dma_addr_t dma; - void *desc_addr; - dma_addr_t desc_dma; - void *data_addr; - dma_addr_t data_dma; unsigned int i; /* @@ -249,24 +244,11 @@ static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev, * Initialize all queue entries to contain valid addresses. */ for (i = 0; i < queue->limit; i++) { - desc_addr = desc_offset(queue, addr, i); - desc_dma = desc_offset(queue, dma, i); - data_addr = data_offset(queue, addr, i); - data_dma = data_offset(queue, dma, i); - - if (queue->qid == QID_RX) { - priv_rx = queue->entries[i].priv_data; - priv_rx->desc = desc_addr; - priv_rx->desc_dma = desc_dma; - priv_rx->data = data_addr; - priv_rx->data_dma = data_dma; - } else { - priv_tx = queue->entries[i].priv_data; - priv_tx->desc = desc_addr; - priv_tx->desc_dma = desc_dma; - priv_tx->data = data_addr; - priv_tx->data_dma = data_dma; - } + entry_priv = queue->entries[i].priv_data; + entry_priv->desc = desc_offset(queue, addr, i); + entry_priv->desc_dma = desc_offset(queue, dma, i); + entry_priv->data = data_offset(queue, addr, i); + entry_priv->data_dma = data_offset(queue, dma, i); } return 0; @@ -276,28 +258,13 @@ static void rt2x00pci_free_queue_dma(struct rt2x00_dev *rt2x00dev, struct data_queue *queue) { struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev); - struct queue_entry_priv_pci_rx *priv_rx; - struct queue_entry_priv_pci_tx *priv_tx; - void *data_addr; - dma_addr_t data_dma; - - if (queue->qid == QID_RX) { - priv_rx = queue->entries[0].priv_data; - data_addr = priv_rx->data; - data_dma = priv_rx->data_dma; - - priv_rx->data = NULL; - } else { - priv_tx = queue->entries[0].priv_data; - data_addr = priv_tx->data; - data_dma = priv_tx->data_dma; - - priv_tx->data = NULL; - } + struct queue_entry_priv_pci *entry_priv = + queue->entries[0].priv_data; - if (data_addr) + if (entry_priv->data) pci_free_consistent(pci_dev, dma_size(queue), - data_addr, data_dma); + entry_priv->data, entry_priv->data_dma); + entry_priv->data = NULL; } int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev) diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h index 2b0ef17bba6..557d15a888a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.h +++ b/drivers/net/wireless/rt2x00/rt2x00pci.h @@ -95,31 +95,15 @@ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev, struct ieee80211_tx_control *control); /** - * struct queue_entry_priv_pci_rx: Per RX entry PCI specific information - * - * @desc: Pointer to device descriptor. - * @desc_dma: DMA pointer to @desc. - * @data: Pointer to device's entry memory. - * @data_dma: DMA pointer to &data. - */ -struct queue_entry_priv_pci_rx { - __le32 *desc; - dma_addr_t desc_dma; - - void *data; - dma_addr_t data_dma; -}; - -/** - * struct queue_entry_priv_pci_tx: Per TX entry PCI specific information + * struct queue_entry_priv_pci: Per entry PCI specific information * * @desc: Pointer to device descriptor - * @desc_dma: DMA pointer to @desc. + * @desc_dma: DMA pointer to &desc. * @data: Pointer to device's entry memory. * @data_dma: DMA pointer to &data. * @control: mac80211 control structure used to transmit data. */ -struct queue_entry_priv_pci_tx { +struct queue_entry_priv_pci { __le32 *desc; dma_addr_t desc_dma; diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index df6621025f4..dcee1b4f152 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -129,7 +129,7 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) { struct queue_entry *entry = (struct queue_entry *)urb->context; struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; - struct queue_entry_priv_usb_tx *priv_tx = entry->priv_data; + struct queue_entry_priv_usb *entry_priv = entry->priv_data; struct txdone_entry_desc txdesc; __le32 *txd = (__le32 *)entry->skb->data; u32 word; @@ -159,7 +159,7 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) else __set_bit(TXDONE_FAILURE, &txdesc.flags); txdesc.retry = 0; - txdesc.control = &priv_tx->control; + txdesc.control = &entry_priv->control; rt2x00lib_txdone(entry, &txdesc); @@ -175,7 +175,7 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) * is reenabled when the txdone handler has finished. */ if (!rt2x00queue_full(entry->queue)) - ieee80211_wake_queue(rt2x00dev->hw, priv_tx->control.queue); + ieee80211_wake_queue(rt2x00dev->hw, entry_priv->control.queue); } int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, @@ -184,7 +184,7 @@ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, { struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev); struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); - struct queue_entry_priv_usb_tx *priv_tx = entry->priv_data; + struct queue_entry_priv_usb *entry_priv = entry->priv_data; struct skb_frame_desc *skbdesc; struct txentry_desc txdesc; u32 length; @@ -224,7 +224,7 @@ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, skbdesc->desc_len = queue->desc_size; skbdesc->entry = entry; - memcpy(&priv_tx->control, control, sizeof(priv_tx->control)); + memcpy(&entry_priv->control, control, sizeof(entry_priv->control)); rt2x00queue_write_tx_descriptor(entry, &txdesc); /* @@ -238,9 +238,9 @@ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, * Initialize URB and send the frame to the device. */ __set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); - usb_fill_bulk_urb(priv_tx->urb, usb_dev, usb_sndbulkpipe(usb_dev, 1), + usb_fill_bulk_urb(entry_priv->urb, usb_dev, usb_sndbulkpipe(usb_dev, 1), skb->data, length, rt2x00usb_interrupt_txdone, entry); - usb_submit_urb(priv_tx->urb, GFP_ATOMIC); + usb_submit_urb(entry_priv->urb, GFP_ATOMIC); rt2x00queue_index_inc(queue, Q_INDEX); @@ -380,10 +380,8 @@ skip_entry: */ void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev) { - struct queue_entry_priv_usb_rx *priv_rx; - struct queue_entry_priv_usb_tx *priv_tx; - struct queue_entry_priv_usb_bcn *priv_bcn; - struct data_queue *queue; + struct queue_entry_priv_usb *entry_priv; + struct queue_entry_priv_usb_bcn *bcn_priv; unsigned int i; rt2x00usb_vendor_request_sw(rt2x00dev, USB_RX_CONTROL, 0, 0, @@ -393,31 +391,17 @@ void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev) * Cancel all queues. */ for (i = 0; i < rt2x00dev->rx->limit; i++) { - priv_rx = rt2x00dev->rx->entries[i].priv_data; - usb_kill_urb(priv_rx->urb); - } - - tx_queue_for_each(rt2x00dev, queue) { - for (i = 0; i < queue->limit; i++) { - priv_tx = queue->entries[i].priv_data; - usb_kill_urb(priv_tx->urb); - } + entry_priv = rt2x00dev->rx->entries[i].priv_data; + usb_kill_urb(entry_priv->urb); } + /* + * Kill guardian urb. + */ for (i = 0; i < rt2x00dev->bcn->limit; i++) { - priv_bcn = rt2x00dev->bcn->entries[i].priv_data; - usb_kill_urb(priv_bcn->urb); - - if (priv_bcn->guardian_urb) - usb_kill_urb(priv_bcn->guardian_urb); - } - - if (!test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags)) - return; - - for (i = 0; i < rt2x00dev->bcn[1].limit; i++) { - priv_tx = rt2x00dev->bcn[1].entries[i].priv_data; - usb_kill_urb(priv_tx->urb); + bcn_priv = rt2x00dev->bcn->entries[i].priv_data; + if (bcn_priv->guardian_urb) + usb_kill_urb(bcn_priv->guardian_urb); } } EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio); @@ -429,15 +413,15 @@ void rt2x00usb_init_rxentry(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry) { struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev); - struct queue_entry_priv_usb_rx *priv_rx = entry->priv_data; + struct queue_entry_priv_usb *entry_priv = entry->priv_data; - usb_fill_bulk_urb(priv_rx->urb, usb_dev, + usb_fill_bulk_urb(entry_priv->urb, usb_dev, usb_rcvbulkpipe(usb_dev, 1), entry->skb->data, entry->skb->len, rt2x00usb_interrupt_rxdone, entry); __set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); - usb_submit_urb(priv_rx->urb, GFP_ATOMIC); + usb_submit_urb(entry_priv->urb, GFP_ATOMIC); } EXPORT_SYMBOL_GPL(rt2x00usb_init_rxentry); @@ -451,38 +435,31 @@ EXPORT_SYMBOL_GPL(rt2x00usb_init_txentry); static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev, struct data_queue *queue) { - struct queue_entry_priv_usb_rx *priv_rx; - struct queue_entry_priv_usb_tx *priv_tx; - struct queue_entry_priv_usb_bcn *priv_bcn; - struct urb *urb; - unsigned int guardian = - test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags); + struct queue_entry_priv_usb *entry_priv; + struct queue_entry_priv_usb_bcn *bcn_priv; unsigned int i; + for (i = 0; i < queue->limit; i++) { + entry_priv = queue->entries[i].priv_data; + entry_priv->urb = usb_alloc_urb(0, GFP_KERNEL); + if (!entry_priv->urb) + return -ENOMEM; + } + /* - * Allocate the URB's + * If this is not the beacon queue or + * no guardian byte was required for the beacon, + * then we are done. */ + if (rt2x00dev->bcn != queue || + !test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags)) + return 0; + for (i = 0; i < queue->limit; i++) { - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) + bcn_priv = queue->entries[i].priv_data; + bcn_priv->guardian_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!bcn_priv->guardian_urb) return -ENOMEM; - - if (queue->qid == QID_RX) { - priv_rx = queue->entries[i].priv_data; - priv_rx->urb = urb; - } else if (queue->qid == QID_MGMT && guardian) { - priv_bcn = queue->entries[i].priv_data; - priv_bcn->urb = urb; - - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) - return -ENOMEM; - - priv_bcn->guardian_urb = urb; - } else { - priv_tx = queue->entries[i].priv_data; - priv_tx->urb = urb; - } } return 0; @@ -491,38 +468,35 @@ static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev, static void rt2x00usb_free_urb(struct rt2x00_dev *rt2x00dev, struct data_queue *queue) { - struct queue_entry_priv_usb_rx *priv_rx; - struct queue_entry_priv_usb_tx *priv_tx; - struct queue_entry_priv_usb_bcn *priv_bcn; - struct urb *urb; - unsigned int guardian = - test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags); + struct queue_entry_priv_usb *entry_priv; + struct queue_entry_priv_usb_bcn *bcn_priv; unsigned int i; if (!queue->entries) return; for (i = 0; i < queue->limit; i++) { - if (queue->qid == QID_RX) { - priv_rx = queue->entries[i].priv_data; - urb = priv_rx->urb; - } else if (queue->qid == QID_MGMT && guardian) { - priv_bcn = queue->entries[i].priv_data; - - usb_kill_urb(priv_bcn->guardian_urb); - usb_free_urb(priv_bcn->guardian_urb); - - urb = priv_bcn->urb; - } else { - priv_tx = queue->entries[i].priv_data; - urb = priv_tx->urb; - } - - usb_kill_urb(urb); - usb_free_urb(urb); + entry_priv = queue->entries[i].priv_data; + usb_kill_urb(entry_priv->urb); + usb_free_urb(entry_priv->urb); if (queue->entries[i].skb) kfree_skb(queue->entries[i].skb); } + + /* + * If this is not the beacon queue or + * no guardian byte was required for the beacon, + * then we are done. + */ + if (rt2x00dev->bcn != queue || + !test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags)) + return; + + for (i = 0; i < queue->limit; i++) { + bcn_priv = queue->entries[i].priv_data; + usb_kill_urb(bcn_priv->guardian_urb); + usb_free_urb(bcn_priv->guardian_urb); + } } int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev) diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index 4da9eb376eb..15b404aa714 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h @@ -220,30 +220,21 @@ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, struct ieee80211_tx_control *control); /** - * struct queue_entry_priv_usb_rx: Per RX entry USB specific information - * - * @urb: Urb structure used for device communication. - */ -struct queue_entry_priv_usb_rx { - struct urb *urb; -}; - -/** - * struct queue_entry_priv_usb_tx: Per TX entry USB specific information + * struct queue_entry_priv_usb: Per entry USB specific information * * @urb: Urb structure used for device communication. * @control: mac80211 control structure used to transmit data. */ -struct queue_entry_priv_usb_tx { +struct queue_entry_priv_usb { struct urb *urb; struct ieee80211_tx_control control; }; /** - * struct queue_entry_priv_usb_tx: Per TX entry USB specific information + * struct queue_entry_priv_usb_bcn: Per TX entry USB specific information * - * The first section should match &struct queue_entry_priv_usb_tx exactly. + * The first section should match &struct queue_entry_priv_usb exactly. * rt2500usb can use this structure to send a guardian byte when working * with beacons. * diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 2e5e45cbd2e..7598b6e1578 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1018,35 +1018,34 @@ static int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev, void *data, static void rt61pci_init_rxentry(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry) { - struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data; + struct queue_entry_priv_pci *entry_priv = entry->priv_data; u32 word; - rt2x00_desc_read(priv_rx->desc, 5, &word); + rt2x00_desc_read(entry_priv->desc, 5, &word); rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS, - priv_rx->data_dma); - rt2x00_desc_write(priv_rx->desc, 5, word); + entry_priv->data_dma); + rt2x00_desc_write(entry_priv->desc, 5, word); - rt2x00_desc_read(priv_rx->desc, 0, &word); + rt2x00_desc_read(entry_priv->desc, 0, &word); rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); - rt2x00_desc_write(priv_rx->desc, 0, word); + rt2x00_desc_write(entry_priv->desc, 0, word); } static void rt61pci_init_txentry(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry) { - struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data; + struct queue_entry_priv_pci *entry_priv = entry->priv_data; u32 word; - rt2x00_desc_read(priv_tx->desc, 0, &word); + rt2x00_desc_read(entry_priv->desc, 0, &word); rt2x00_set_field32(&word, TXD_W0_VALID, 0); rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); - rt2x00_desc_write(priv_tx->desc, 0, word); + rt2x00_desc_write(entry_priv->desc, 0, word); } static int rt61pci_init_queues(struct rt2x00_dev *rt2x00dev) { - struct queue_entry_priv_pci_rx *priv_rx; - struct queue_entry_priv_pci_tx *priv_tx; + struct queue_entry_priv_pci *entry_priv; u32 reg; /* @@ -1068,28 +1067,28 @@ static int rt61pci_init_queues(struct rt2x00_dev *rt2x00dev) rt2x00dev->tx[0].desc_size / 4); rt2x00pci_register_write(rt2x00dev, TX_RING_CSR1, reg); - priv_tx = rt2x00dev->tx[0].entries[0].priv_data; + entry_priv = rt2x00dev->tx[0].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, AC0_BASE_CSR, ®); rt2x00_set_field32(®, AC0_BASE_CSR_RING_REGISTER, - priv_tx->desc_dma); + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, AC0_BASE_CSR, reg); - priv_tx = rt2x00dev->tx[1].entries[0].priv_data; + entry_priv = rt2x00dev->tx[1].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, AC1_BASE_CSR, ®); rt2x00_set_field32(®, AC1_BASE_CSR_RING_REGISTER, - priv_tx->desc_dma); + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, AC1_BASE_CSR, reg); - priv_tx = rt2x00dev->tx[2].entries[0].priv_data; + entry_priv = rt2x00dev->tx[2].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, AC2_BASE_CSR, ®); rt2x00_set_field32(®, AC2_BASE_CSR_RING_REGISTER, - priv_tx->desc_dma); + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, AC2_BASE_CSR, reg); - priv_tx = rt2x00dev->tx[3].entries[0].priv_data; + entry_priv = rt2x00dev->tx[3].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, AC3_BASE_CSR, ®); rt2x00_set_field32(®, AC3_BASE_CSR_RING_REGISTER, - priv_tx->desc_dma); + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, AC3_BASE_CSR, reg); rt2x00pci_register_read(rt2x00dev, RX_RING_CSR, ®); @@ -1099,10 +1098,10 @@ static int rt61pci_init_queues(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, RX_RING_CSR_RXD_WRITEBACK_SIZE, 4); rt2x00pci_register_write(rt2x00dev, RX_RING_CSR, reg); - priv_rx = rt2x00dev->rx->entries[0].priv_data; + entry_priv = rt2x00dev->rx->entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, RX_BASE_CSR, ®); rt2x00_set_field32(®, RX_BASE_CSR_RING_REGISTER, - priv_rx->desc_dma); + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, RX_BASE_CSR, reg); rt2x00pci_register_read(rt2x00dev, TX_DMA_DST_CSR, ®); @@ -1515,7 +1514,7 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct txentry_desc *txdesc) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); - struct queue_entry_priv_pci_tx *entry_priv = skbdesc->entry->priv_data; + struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data; __le32 *txd = skbdesc->desc; u32 word; @@ -1661,12 +1660,12 @@ static int rt61pci_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) static void rt61pci_fill_rxdone(struct queue_entry *entry, struct rxdone_entry_desc *rxdesc) { - struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data; + struct queue_entry_priv_pci *entry_priv = entry->priv_data; u32 word0; u32 word1; - rt2x00_desc_read(priv_rx->desc, 0, &word0); - rt2x00_desc_read(priv_rx->desc, 1, &word1); + rt2x00_desc_read(entry_priv->desc, 0, &word0); + rt2x00_desc_read(entry_priv->desc, 1, &word1); if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; @@ -1695,7 +1694,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev) struct data_queue *queue; struct queue_entry *entry; struct queue_entry *entry_done; - struct queue_entry_priv_pci_tx *priv_tx; + struct queue_entry_priv_pci *entry_priv; struct txdone_entry_desc txdesc; u32 word; u32 reg; @@ -1740,8 +1739,8 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev) continue; entry = &queue->entries[index]; - priv_tx = entry->priv_data; - rt2x00_desc_read(priv_tx->desc, 0, &word); + entry_priv = entry->priv_data; + rt2x00_desc_read(entry_priv->desc, 0, &word); if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || !rt2x00_get_field32(word, TXD_W0_VALID)) @@ -2363,7 +2362,7 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, { struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_intf *intf = vif_to_intf(control->vif); - struct queue_entry_priv_pci_tx *priv_tx; + struct queue_entry_priv_pci *entry_priv; struct skb_frame_desc *skbdesc; struct txentry_desc txdesc; unsigned int beacon_base; @@ -2380,8 +2379,8 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, intf->beacon->skb = skb; rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc, control); - priv_tx = intf->beacon->priv_data; - memset(priv_tx->desc, 0, intf->beacon->queue->desc_size); + entry_priv = intf->beacon->priv_data; + memset(entry_priv->desc, 0, intf->beacon->queue->desc_size); /* * Fill in skb descriptor @@ -2391,7 +2390,7 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED; skbdesc->data = skb->data; skbdesc->data_len = skb->len; - skbdesc->desc = priv_tx->desc; + skbdesc->desc = entry_priv->desc; skbdesc->desc_len = intf->beacon->queue->desc_size; skbdesc->entry = intf->beacon; @@ -2468,21 +2467,21 @@ static const struct data_queue_desc rt61pci_queue_rx = { .entry_num = RX_ENTRIES, .data_size = DATA_FRAME_SIZE, .desc_size = RXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_pci_rx), + .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct data_queue_desc rt61pci_queue_tx = { .entry_num = TX_ENTRIES, .data_size = DATA_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_pci_tx), + .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct data_queue_desc rt61pci_queue_bcn = { .entry_num = 4 * BEACON_ENTRIES, .data_size = 0, /* No DMA required for beacons */ .desc_size = TXINFO_SIZE, - .priv_size = sizeof(struct queue_entry_priv_pci_tx), + .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct rt2x00_ops rt61pci_ops = { diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 5d70dd840c1..e55bcbdfc1e 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2058,21 +2058,21 @@ static const struct data_queue_desc rt73usb_queue_rx = { .entry_num = RX_ENTRIES, .data_size = DATA_FRAME_SIZE, .desc_size = RXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_usb_rx), + .priv_size = sizeof(struct queue_entry_priv_usb), }; static const struct data_queue_desc rt73usb_queue_tx = { .entry_num = TX_ENTRIES, .data_size = DATA_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_usb_tx), + .priv_size = sizeof(struct queue_entry_priv_usb), }; static const struct data_queue_desc rt73usb_queue_bcn = { .entry_num = 4 * BEACON_ENTRIES, .data_size = MGMT_FRAME_SIZE, .desc_size = TXINFO_SIZE, - .priv_size = sizeof(struct queue_entry_priv_usb_tx), + .priv_size = sizeof(struct queue_entry_priv_usb), }; static const struct rt2x00_ops rt73usb_ops = { -- cgit v1.2.3-70-g09d2 From aade5102c5390280e7ae8a43e09b8995792f66d8 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 10 May 2008 13:45:58 +0200 Subject: rt2x00: Remove extra + Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index b11f445c747..4fcba9b4635 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1042,7 +1042,7 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, test_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs); rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, -+ test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags)); + test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags)); rt2x00_desc_write(txd, 0, word); } -- cgit v1.2.3-70-g09d2 From f9d1cf53cf9e934f15ce0371b5fd568407032ea2 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 10 May 2008 13:45:50 +0200 Subject: rt2x00: Release rt2x00 2.1.6 Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 9c186d79c11..1900d4c0e84 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -44,7 +44,7 @@ /* * Module information. */ -#define DRV_VERSION "2.1.5" +#define DRV_VERSION "2.1.6" #define DRV_PROJECT "http://rt2x00.serialmonkey.com" /* -- cgit v1.2.3-70-g09d2 From e37fc6e11c79899451e394319cff18cc53d6448d Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 20 May 2008 11:47:16 +0100 Subject: libertas: Increase priority of 'unknown command' warnings Using the deprecated lbs_prepare_and_send_command() function for a command which it doesn't understand is an error; complain loudly about it even when we're not debugging. The mesh stats bug, where we converted MESH_ACCESS to a direct command but accidentally missed one user which was still trying to do it through lbs_prepare_and_send_command(), would have been caught a lot quicker if we'd done this sooner. Such bugs aren't entirely unlikely in future too, as we convert more code to stop using this function. Signed-off-by: David Woodhouse Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 2 +- drivers/net/wireless/libertas/cmdresp.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index c2dd43ece06..bed68e9add0 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1452,7 +1452,7 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action); break; default: - lbs_deb_host("PREP_CMD: unknown command 0x%04x\n", cmd_no); + lbs_pr_err("PREP_CMD: unknown command 0x%04x\n", cmd_no); ret = -1; break; } diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 5abecb7673e..9e50fdd9481 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -376,8 +376,8 @@ static inline int handle_cmd_response(struct lbs_private *priv, break; default: - lbs_deb_host("CMD_RESP: unknown cmd response 0x%04x\n", - le16_to_cpu(resp->command)); + lbs_pr_err("CMD_RESP: unknown cmd response 0x%04x\n", + le16_to_cpu(resp->command)); break; } lbs_deb_leave(LBS_DEB_HOST); -- cgit v1.2.3-70-g09d2 From 75bf45a7b4ab81cfa5c5eab68b57bbfee8b8ede2 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 20 May 2008 13:32:45 +0100 Subject: libertas: fix multicast filtering on eth and msh interfaces We weren't properly handling multicast on the mesh interface. Fix that, which involves setting up the hardware to use the union of dev->mc_list for both eth%d and msh%d devices. This means we can't do it directly from ->set_multicast_list() because we'd need to lock the other device to read its list, and we can't do that because it might deadlock. So punt the actual work to keventd. Also, invoke the same when taking an interface down; for some reason the core calls ->set_multicast_list while IFF_UP is still set in dev->flags when we're taking it down, so its addresses don't get removed then. We also convert MAC_MULTICAST_ADR to a direct command while we're at it, removing one more entry from the big switch statement in the deprecated lbs_prepare_and_send_command() function. Signed-off-by: David Woodhouse Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 29 +----- drivers/net/wireless/libertas/cmdresp.c | 1 - drivers/net/wireless/libertas/dev.h | 2 + drivers/net/wireless/libertas/hostcmd.h | 2 +- drivers/net/wireless/libertas/main.c | 167 +++++++++++++++++++------------- 5 files changed, 105 insertions(+), 96 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index bed68e9add0..b494aba869c 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -746,28 +746,6 @@ out: return ret; } -static int lbs_cmd_mac_multicast_adr(struct lbs_private *priv, - struct cmd_ds_command *cmd, - u16 cmd_action) -{ - struct cmd_ds_mac_multicast_adr *pMCastAdr = &cmd->params.madr; - - lbs_deb_enter(LBS_DEB_CMD); - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_multicast_adr) + - S_DS_GEN); - cmd->command = cpu_to_le16(CMD_MAC_MULTICAST_ADR); - - lbs_deb_cmd("MULTICAST_ADR: setting %d addresses\n", pMCastAdr->nr_of_adrs); - pMCastAdr->action = cpu_to_le16(cmd_action); - pMCastAdr->nr_of_adrs = - cpu_to_le16((u16) priv->nr_of_multicastmacaddr); - memcpy(pMCastAdr->maclist, priv->multicastlist, - priv->nr_of_multicastmacaddr * ETH_ALEN); - - lbs_deb_leave(LBS_DEB_CMD); - return 0; -} - /** * @brief Get the radio channel * @@ -1247,8 +1225,7 @@ void lbs_set_mac_control(struct lbs_private *priv) cmd.action = cpu_to_le16(priv->mac_control); cmd.reserved = 0; - lbs_cmd_async(priv, CMD_MAC_CONTROL, - &cmd.hdr, sizeof(cmd)); + lbs_cmd_async(priv, CMD_MAC_CONTROL, &cmd.hdr, sizeof(cmd)); lbs_deb_leave(LBS_DEB_CMD); } @@ -1360,10 +1337,6 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, cmdptr, cmd_action); break; - case CMD_MAC_MULTICAST_ADR: - ret = lbs_cmd_mac_multicast_adr(priv, cmdptr, cmd_action); - break; - case CMD_802_11_MONITOR_MODE: ret = lbs_cmd_802_11_monitor_mode(cmdptr, cmd_action, pdata_buf); diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 9e50fdd9481..4c3c5ec16f9 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -316,7 +316,6 @@ static inline int handle_cmd_response(struct lbs_private *priv, break; - case CMD_RET(CMD_MAC_MULTICAST_ADR): case CMD_RET(CMD_802_11_RESET): case CMD_RET(CMD_802_11_AUTHENTICATE): case CMD_RET(CMD_802_11_BEACON_STOP): diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 0d9edb9b11f..e12ce650672 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -140,6 +140,8 @@ struct lbs_private { wait_queue_head_t waitq; struct workqueue_struct *work_thread; + struct work_struct mcast_work; + /** Scanning */ struct delayed_work scan_work; struct delayed_work assoc_work; diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index f29bc5bbda3..c36ab316223 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -219,6 +219,7 @@ struct cmd_ds_mac_control { }; struct cmd_ds_mac_multicast_adr { + struct cmd_header hdr; __le16 action; __le16 nr_of_adrs; u8 maclist[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE]; @@ -703,7 +704,6 @@ struct cmd_ds_command { struct cmd_ds_802_11_rf_antenna rant; struct cmd_ds_802_11_monitor_mode monitor; struct cmd_ds_802_11_rate_adapt_rateset rateset; - struct cmd_ds_mac_multicast_adr madr; struct cmd_ds_802_11_ad_hoc_join adj; struct cmd_ds_802_11_rssi rssi; struct cmd_ds_802_11_rssi_rsp rssirsp; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index e333f14dce2..a87febad8c2 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -446,6 +447,8 @@ static int lbs_mesh_stop(struct net_device *dev) spin_unlock_irq(&priv->driver_lock); + schedule_work(&priv->mcast_work); + lbs_deb_leave(LBS_DEB_MESH); return 0; } @@ -467,6 +470,8 @@ static int lbs_eth_stop(struct net_device *dev) netif_stop_queue(dev); spin_unlock_irq(&priv->driver_lock); + schedule_work(&priv->mcast_work); + lbs_deb_leave(LBS_DEB_NET); return 0; } @@ -563,89 +568,116 @@ done: return ret; } -static int lbs_copy_multicast_address(struct lbs_private *priv, - struct net_device *dev) + +static inline int mac_in_list(unsigned char *list, int list_len, + unsigned char *mac) { - int i = 0; - struct dev_mc_list *mcptr = dev->mc_list; + while (list_len) { + if (!memcmp(list, mac, ETH_ALEN)) + return 1; + list += ETH_ALEN; + list_len--; + } + return 0; +} + - for (i = 0; i < dev->mc_count; i++) { - memcpy(&priv->multicastlist[i], mcptr->dmi_addr, ETH_ALEN); - mcptr = mcptr->next; +static int lbs_add_mcast_addrs(struct cmd_ds_mac_multicast_adr *cmd, + struct net_device *dev, int nr_addrs) +{ + int i = nr_addrs; + struct dev_mc_list *mc_list; + DECLARE_MAC_BUF(mac); + + if ((dev->flags & (IFF_UP|IFF_MULTICAST)) != (IFF_UP|IFF_MULTICAST)) + return nr_addrs; + + netif_tx_lock_bh(dev); + for (mc_list = dev->mc_list; mc_list; mc_list = mc_list->next) { + if (mac_in_list(cmd->maclist, nr_addrs, mc_list->dmi_addr)) { + lbs_deb_net("mcast address %s:%s skipped\n", dev->name, + print_mac(mac, mc_list->dmi_addr)); + continue; + } + + if (i == MRVDRV_MAX_MULTICAST_LIST_SIZE) + break; + memcpy(&cmd->maclist[6*i], mc_list->dmi_addr, ETH_ALEN); + lbs_deb_net("mcast address %s:%s added to filter\n", dev->name, + print_mac(mac, mc_list->dmi_addr)); + i++; } + netif_tx_unlock_bh(dev); + if (mc_list) + return -EOVERFLOW; + return i; } -static void lbs_set_multicast_list(struct net_device *dev) +static void lbs_set_mcast_worker(struct work_struct *work) { - struct lbs_private *priv = dev->priv; - int old_mac_control; - DECLARE_MAC_BUF(mac); + struct lbs_private *priv = container_of(work, struct lbs_private, mcast_work); + struct cmd_ds_mac_multicast_adr mcast_cmd; + int dev_flags; + int nr_addrs; + int old_mac_control = priv->mac_control; lbs_deb_enter(LBS_DEB_NET); - old_mac_control = priv->mac_control; - - if (dev->flags & IFF_PROMISC) { - lbs_deb_net("enable promiscuous mode\n"); - priv->mac_control |= - CMD_ACT_MAC_PROMISCUOUS_ENABLE; - priv->mac_control &= - ~(CMD_ACT_MAC_ALL_MULTICAST_ENABLE | - CMD_ACT_MAC_MULTICAST_ENABLE); - } else { - /* Multicast */ - priv->mac_control &= - ~CMD_ACT_MAC_PROMISCUOUS_ENABLE; - - if (dev->flags & IFF_ALLMULTI || dev->mc_count > - MRVDRV_MAX_MULTICAST_LIST_SIZE) { - lbs_deb_net( "enabling all multicast\n"); - priv->mac_control |= - CMD_ACT_MAC_ALL_MULTICAST_ENABLE; - priv->mac_control &= - ~CMD_ACT_MAC_MULTICAST_ENABLE; - } else { - priv->mac_control &= - ~CMD_ACT_MAC_ALL_MULTICAST_ENABLE; - - if (!dev->mc_count) { - lbs_deb_net("no multicast addresses, " - "disabling multicast\n"); - priv->mac_control &= - ~CMD_ACT_MAC_MULTICAST_ENABLE; - } else { - int i; - - priv->mac_control |= - CMD_ACT_MAC_MULTICAST_ENABLE; - - priv->nr_of_multicastmacaddr = - lbs_copy_multicast_address(priv, dev); - - lbs_deb_net("multicast addresses: %d\n", - dev->mc_count); - - for (i = 0; i < dev->mc_count; i++) { - lbs_deb_net("Multicast address %d: %s\n", - i, print_mac(mac, - priv->multicastlist[i])); - } - /* send multicast addresses to firmware */ - lbs_prepare_and_send_command(priv, - CMD_MAC_MULTICAST_ADR, - CMD_ACT_SET, 0, 0, - NULL); - } - } + dev_flags = priv->dev->flags; + if (priv->mesh_dev) + dev_flags |= priv->mesh_dev->flags; + + if (dev_flags & IFF_PROMISC) { + priv->mac_control |= CMD_ACT_MAC_PROMISCUOUS_ENABLE; + priv->mac_control &= ~(CMD_ACT_MAC_ALL_MULTICAST_ENABLE | + CMD_ACT_MAC_MULTICAST_ENABLE); + goto out_set_mac_control; + } else if (dev_flags & IFF_ALLMULTI) { + do_allmulti: + priv->mac_control |= CMD_ACT_MAC_ALL_MULTICAST_ENABLE; + priv->mac_control &= ~(CMD_ACT_MAC_PROMISCUOUS_ENABLE | + CMD_ACT_MAC_MULTICAST_ENABLE); + goto out_set_mac_control; } + /* Once for priv->dev, again for priv->mesh_dev if it exists */ + nr_addrs = lbs_add_mcast_addrs(&mcast_cmd, priv->dev, 0); + if (nr_addrs >= 0 && priv->mesh_dev) + nr_addrs = lbs_add_mcast_addrs(&mcast_cmd, priv->mesh_dev, nr_addrs); + if (nr_addrs < 0) + goto do_allmulti; + + if (nr_addrs) { + int size = offsetof(struct cmd_ds_mac_multicast_adr, + maclist[6*nr_addrs]); + + mcast_cmd.action = cpu_to_le16(CMD_ACT_SET); + mcast_cmd.hdr.size = cpu_to_le16(size); + mcast_cmd.nr_of_adrs = cpu_to_le16(nr_addrs); + + lbs_cmd_async(priv, CMD_MAC_MULTICAST_ADR, &mcast_cmd.hdr, size); + + priv->mac_control |= CMD_ACT_MAC_MULTICAST_ENABLE; + } else + priv->mac_control &= ~CMD_ACT_MAC_MULTICAST_ENABLE; + + priv->mac_control &= ~(CMD_ACT_MAC_PROMISCUOUS_ENABLE | + CMD_ACT_MAC_ALL_MULTICAST_ENABLE); + out_set_mac_control: if (priv->mac_control != old_mac_control) lbs_set_mac_control(priv); lbs_deb_leave(LBS_DEB_NET); } +static void lbs_set_multicast_list(struct net_device *dev) +{ + struct lbs_private *priv = dev->priv; + + schedule_work(&priv->mcast_work); +} + /** * @brief This function handles the major jobs in the LBS driver. * It handles all events generated by firmware, RX data received @@ -1122,6 +1154,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) priv->work_thread = create_singlethread_workqueue("lbs_worker"); INIT_DELAYED_WORK(&priv->assoc_work, lbs_association_worker); INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker); + INIT_WORK(&priv->mcast_work, lbs_set_mcast_worker); INIT_WORK(&priv->sync_channel, lbs_sync_channel_worker); sprintf(priv->mesh_ssid, "mesh"); @@ -1158,6 +1191,7 @@ void lbs_remove_card(struct lbs_private *priv) cancel_delayed_work_sync(&priv->scan_work); cancel_delayed_work_sync(&priv->assoc_work); + cancel_work_sync(&priv->mcast_work); destroy_workqueue(priv->work_thread); if (priv->psmode == LBS802_11POWERMODEMAX_PSP) { @@ -1322,6 +1356,8 @@ static int lbs_add_mesh(struct lbs_private *priv) #ifdef WIRELESS_EXT mesh_dev->wireless_handlers = (struct iw_handler_def *)&mesh_handler_def; #endif + mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST; + mesh_dev->set_multicast_list = lbs_set_multicast_list; /* Register virtual mesh interface */ ret = register_netdev(mesh_dev); if (ret) { @@ -1554,7 +1590,6 @@ static int lbs_add_rtap(struct lbs_private *priv) rtap_dev->stop = lbs_rtap_stop; rtap_dev->get_stats = lbs_rtap_get_stats; rtap_dev->hard_start_xmit = lbs_rtap_hard_start_xmit; - rtap_dev->set_multicast_list = lbs_set_multicast_list; rtap_dev->priv = priv; ret = register_netdev(rtap_dev); -- cgit v1.2.3-70-g09d2 From edaea5ce05ca804cc55438c586ca2f947d49f56f Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Sat, 17 May 2008 00:55:10 -0700 Subject: libertas: Extend MESH_CONFIG command to access non-volatile configuration This patch is based on a patch from Shailendra Govardhan and Brian Cavagnolo. It extends the MESH_CONFIG command to configure non-volatile parameters on libertas devices that support them (e.g. OLPC Active Antenna). This patch only implements the driver/firmware interface. See http://dev.laptop.org/ticket/6823 for minimal testing results and known issues. Signed-off-by: Javier Cardona Signed-off-by: David Woodhouse Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/assoc.c | 6 ++-- drivers/net/wireless/libertas/cmd.c | 68 +++++++++++++++++++++++++++++------ drivers/net/wireless/libertas/cmd.h | 3 ++ drivers/net/wireless/libertas/defs.h | 10 ++++++ drivers/net/wireless/libertas/host.h | 17 +++++++++ drivers/net/wireless/libertas/main.c | 13 ++++--- drivers/net/wireless/libertas/types.h | 30 ++++++++++++++++ drivers/net/wireless/libertas/wext.c | 5 +-- 8 files changed, 132 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index c9c3640ce9f..953a44f750e 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -603,7 +603,8 @@ static int assoc_helper_channel(struct lbs_private *priv, /* Change mesh channel first; 21.p21 firmware won't let you change channel otherwise (even though it'll return an error to this */ - lbs_mesh_config(priv, 0, assoc_req->channel); + lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, + assoc_req->channel); } lbs_deb_assoc("ASSOC: channel: %d -> %d\n", @@ -642,7 +643,8 @@ static int assoc_helper_channel(struct lbs_private *priv, restore_mesh: if (priv->mesh_dev) - lbs_mesh_config(priv, 1, priv->curbssparams.channel); + lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, + priv->curbssparams.channel); done: lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index b494aba869c..7ccec987faa 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -4,6 +4,7 @@ */ #include +#include #include #include "host.h" #include "hostcmd.h" @@ -998,24 +999,69 @@ int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action, return ret; } -int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan) +int lbs_mesh_config_send(struct lbs_private *priv, + struct cmd_ds_mesh_config *cmd, + uint16_t action, uint16_t type) +{ + int ret; + + lbs_deb_enter(LBS_DEB_CMD); + + cmd->hdr.command = cpu_to_le16(CMD_MESH_CONFIG); + cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_mesh_config)); + cmd->hdr.result = 0; + + cmd->type = cpu_to_le16(type); + cmd->action = cpu_to_le16(action); + + ret = lbs_cmd_with_response(priv, CMD_MESH_CONFIG, cmd); + + lbs_deb_leave(LBS_DEB_CMD); + return ret; +} + +/* This function is the CMD_MESH_CONFIG legacy function. It only handles the + * START and STOP actions. The extended actions supported by CMD_MESH_CONFIG + * are all handled by preparing a struct cmd_ds_mesh_config and passing it to + * lbs_mesh_config_send. + */ +int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan) { struct cmd_ds_mesh_config cmd; + struct mrvl_meshie *ie; memset(&cmd, 0, sizeof(cmd)); - cmd.action = cpu_to_le16(enable); cmd.channel = cpu_to_le16(chan); - cmd.type = cpu_to_le16(priv->mesh_tlv); - cmd.hdr.size = cpu_to_le16(sizeof(cmd)); - - if (enable) { - cmd.length = cpu_to_le16(priv->mesh_ssid_len); - memcpy(cmd.data, priv->mesh_ssid, priv->mesh_ssid_len); + ie = (struct mrvl_meshie *)cmd.data; + + switch (action) { + case CMD_ACT_MESH_CONFIG_START: + ie->hdr.id = MFIE_TYPE_GENERIC; + ie->val.oui[0] = 0x00; + ie->val.oui[1] = 0x50; + ie->val.oui[2] = 0x43; + ie->val.type = MARVELL_MESH_IE_TYPE; + ie->val.subtype = MARVELL_MESH_IE_SUBTYPE; + ie->val.version = MARVELL_MESH_IE_VERSION; + ie->val.active_protocol_id = MARVELL_MESH_PROTO_ID_HWMP; + ie->val.active_metric_id = MARVELL_MESH_METRIC_ID; + ie->val.mesh_capability = MARVELL_MESH_CAPABILITY; + ie->val.mesh_id_len = priv->mesh_ssid_len; + memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len); + ie->hdr.len = sizeof(struct mrvl_meshie_val) - + IW_ESSID_MAX_SIZE + priv->mesh_ssid_len; + cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val)); + break; + case CMD_ACT_MESH_CONFIG_STOP: + break; + default: + return -1; } - lbs_deb_cmd("mesh config enable %d TLV %x channel %d SSID %s\n", - enable, priv->mesh_tlv, chan, + lbs_deb_cmd("mesh config action %d type %x channel %d SSID %s\n", + action, priv->mesh_tlv, chan, escape_essid(priv->mesh_ssid, priv->mesh_ssid_len)); - return lbs_cmd_with_response(priv, CMD_MESH_CONFIG, &cmd); + + return lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv); } static int lbs_cmd_bcn_ctrl(struct lbs_private * priv, diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h index f4019c22adf..00d290e2818 100644 --- a/drivers/net/wireless/libertas/cmd.h +++ b/drivers/net/wireless/libertas/cmd.h @@ -39,6 +39,9 @@ int lbs_set_data_rate(struct lbs_private *priv, u8 rate); int lbs_get_channel(struct lbs_private *priv); int lbs_set_channel(struct lbs_private *priv, u8 channel); +int lbs_mesh_config_send(struct lbs_private *priv, + struct cmd_ds_mesh_config *cmd, + uint16_t action, uint16_t type); int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan); int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria); diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index d3952011106..3793cb92296 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -170,6 +170,16 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in #define MARVELL_MESH_IE_LENGTH 9 +/* Values used to populate the struct mrvl_mesh_ie. The only time you need this + * is when enabling the mesh using CMD_MESH_CONFIG. + */ +#define MARVELL_MESH_IE_TYPE 4 +#define MARVELL_MESH_IE_SUBTYPE 0 +#define MARVELL_MESH_IE_VERSION 0 +#define MARVELL_MESH_PROTO_ID_HWMP 0 +#define MARVELL_MESH_METRIC_ID 0 +#define MARVELL_MESH_CAPABILITY 0 + /** INT status Bit Definition*/ #define MRVDRV_TX_DNLD_RDY 0x0001 #define MRVDRV_RX_UPLD_RDY 0x0002 diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index 3915c3144fa..c92e41b4faf 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -256,6 +256,23 @@ enum cmd_mesh_access_opts { CMD_ACT_MESH_GET_AUTOSTART_ENABLED, }; +/* Define actions and types for CMD_MESH_CONFIG */ +enum cmd_mesh_config_actions { + CMD_ACT_MESH_CONFIG_STOP = 0, + CMD_ACT_MESH_CONFIG_START, + CMD_ACT_MESH_CONFIG_SET, + CMD_ACT_MESH_CONFIG_GET, +}; + +enum cmd_mesh_config_types { + CMD_TYPE_MESH_SET_BOOTFLAG = 1, + CMD_TYPE_MESH_SET_BOOTTIME, + CMD_TYPE_MESH_SET_DEF_CHANNEL, + CMD_TYPE_MESH_SET_MESH_IE, + CMD_TYPE_MESH_GET_DEFAULTS, + CMD_TYPE_MESH_GET_MESH_IE, /* GET_DEFAULTS is superset of GET_MESHIE */ +}; + /** Card Event definition */ #define MACREG_INT_CODE_TX_PPA_FREE 0 #define MACREG_INT_CODE_TX_DMA_DONE 1 diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index a87febad8c2..01299c8ed27 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -344,14 +344,15 @@ static ssize_t lbs_mesh_set(struct device *dev, { struct lbs_private *priv = to_net_dev(dev)->priv; int enable; - int ret; + int ret, action = CMD_ACT_MESH_CONFIG_STOP; sscanf(buf, "%x", &enable); enable = !!enable; if (enable == !!priv->mesh_dev) return count; - - ret = lbs_mesh_config(priv, enable, priv->curbssparams.channel); + if (enable) + action = CMD_ACT_MESH_CONFIG_START; + ret = lbs_mesh_config(priv, action, priv->curbssparams.channel); if (ret) return ret; @@ -1257,9 +1258,11 @@ int lbs_start_card(struct lbs_private *priv) useful */ priv->mesh_tlv = 0x100 + 291; - if (lbs_mesh_config(priv, 1, priv->curbssparams.channel)) { + if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, + priv->curbssparams.channel)) { priv->mesh_tlv = 0x100 + 37; - if (lbs_mesh_config(priv, 1, priv->curbssparams.channel)) + if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, + priv->curbssparams.channel)) priv->mesh_tlv = 0; } if (priv->mesh_tlv) { diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h index 4031be42086..e0c2599da92 100644 --- a/drivers/net/wireless/libertas/types.h +++ b/drivers/net/wireless/libertas/types.h @@ -6,6 +6,8 @@ #include #include +#include +#include struct ieeetypes_cfparamset { u8 elementid; @@ -252,4 +254,32 @@ struct mrvlietypes_ledbhv { struct led_bhv ledbhv[1]; } __attribute__ ((packed)); +/* Meant to be packed as the value member of a struct ieee80211_info_element. + * Note that the len member of the ieee80211_info_element varies depending on + * the mesh_id_len */ +struct mrvl_meshie_val { + uint8_t oui[P80211_OUI_LEN]; + uint8_t type; + uint8_t subtype; + uint8_t version; + uint8_t active_protocol_id; + uint8_t active_metric_id; + uint8_t mesh_capability; + uint8_t mesh_id_len; + uint8_t mesh_id[IW_ESSID_MAX_SIZE]; +} __attribute__ ((packed)); + +struct mrvl_meshie { + struct ieee80211_info_element hdr; + struct mrvl_meshie_val val; +} __attribute__ ((packed)); + +struct mrvl_mesh_defaults { + __le32 bootflag; + uint8_t boottime; + uint8_t reserved; + __le16 channel; + struct mrvl_meshie meshie; +} __attribute__ ((packed)); + #endif diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 0973d015a52..d4b19f11b78 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -1002,7 +1002,7 @@ static int lbs_mesh_set_freq(struct net_device *dev, else if (priv->mode == IW_MODE_ADHOC) lbs_stop_adhoc_network(priv); } - lbs_mesh_config(priv, 1, fwrq->m); + lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, fwrq->m); lbs_update_channel(priv); ret = 0; @@ -2011,7 +2011,8 @@ static int lbs_mesh_set_essid(struct net_device *dev, priv->mesh_ssid_len = dwrq->length; } - lbs_mesh_config(priv, 1, priv->curbssparams.channel); + lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, + priv->curbssparams.channel); out: lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); return ret; -- cgit v1.2.3-70-g09d2 From 15dbaac03e862ee746310832c8d8d694dc0427ee Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Sat, 17 May 2008 21:01:24 -0700 Subject: libertas: sysfs interface for accessing non-volatile configuration This will create the following sysfs directories: /sys/class/net/mshX ... |-- boot_options | |-- bootflag | `-- boottime ... |-- mesh_ie | |-- capability | |-- mesh_id | |-- metric_id | `-- protocol_id Signed-off-by: Javier Cardona Signed-off-by: David Woodhouse Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/Makefile | 8 +- drivers/net/wireless/libertas/decl.h | 4 + drivers/net/wireless/libertas/defs.h | 4 +- drivers/net/wireless/libertas/main.c | 8 +- drivers/net/wireless/libertas/persistcfg.c | 408 +++++++++++++++++++++++++++++ 5 files changed, 423 insertions(+), 9 deletions(-) create mode 100644 drivers/net/wireless/libertas/persistcfg.c (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile index f0724e31adf..02080a3682a 100644 --- a/drivers/net/wireless/libertas/Makefile +++ b/drivers/net/wireless/libertas/Makefile @@ -1,9 +1,5 @@ -libertas-objs := main.o wext.o \ - rx.o tx.o cmd.o \ - cmdresp.o scan.o \ - 11d.o \ - debugfs.o \ - ethtool.o assoc.o +libertas-objs := main.o wext.o rx.o tx.o cmd.o cmdresp.o scan.o 11d.o \ + debugfs.o persistcfg.o ethtool.o assoc.o usb8xxx-objs += if_usb.o libertas_cs-objs += if_cs.o diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index 0632b09655d..a8ac974daca 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h @@ -60,6 +60,10 @@ void lbs_mac_event_disconnected(struct lbs_private *priv); void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str); +/* persistcfg.c */ +void lbs_persist_config_init(struct net_device *net); +void lbs_persist_config_remove(struct net_device *net); + /* main.c */ struct chan_freq_power *lbs_get_region_cfp_table(u8 region, int *cfp_no); diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index 3793cb92296..12e687550bc 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -40,6 +40,7 @@ #define LBS_DEB_THREAD 0x00100000 #define LBS_DEB_HEX 0x00200000 #define LBS_DEB_SDIO 0x00400000 +#define LBS_DEB_SYSFS 0x00800000 extern unsigned int lbs_debug; @@ -81,7 +82,8 @@ do { if ((lbs_debug & (grp)) == (grp)) \ #define lbs_deb_usbd(dev, fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usbd", "%s:" fmt, (dev)->bus_id, ##args) #define lbs_deb_cs(fmt, args...) LBS_DEB_LL(LBS_DEB_CS, " cs", fmt, ##args) #define lbs_deb_thread(fmt, args...) LBS_DEB_LL(LBS_DEB_THREAD, " thread", fmt, ##args) -#define lbs_deb_sdio(fmt, args...) LBS_DEB_LL(LBS_DEB_SDIO, " thread", fmt, ##args) +#define lbs_deb_sdio(fmt, args...) LBS_DEB_LL(LBS_DEB_SDIO, " sdio", fmt, ##args) +#define lbs_deb_sysfs(fmt, args...) LBS_DEB_LL(LBS_DEB_SYSFS, " sysfs", fmt, ##args) #define lbs_pr_info(format, args...) \ printk(KERN_INFO DRV_NAME": " format, ## args) diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 01299c8ed27..db246d0a1ed 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1302,8 +1302,9 @@ void lbs_stop_card(struct lbs_private *priv) lbs_debugfs_remove_one(priv); device_remove_file(&dev->dev, &dev_attr_lbs_rtap); - if (priv->mesh_tlv) + if (priv->mesh_tlv) { device_remove_file(&dev->dev, &dev_attr_lbs_mesh); + } /* Flush pending command nodes */ del_timer_sync(&priv->command_timer); @@ -1372,6 +1373,8 @@ static int lbs_add_mesh(struct lbs_private *priv) if (ret) goto err_unregister; + lbs_persist_config_init(mesh_dev); + /* Everything successful */ ret = 0; goto done; @@ -1398,8 +1401,9 @@ static void lbs_remove_mesh(struct lbs_private *priv) lbs_deb_enter(LBS_DEB_MESH); netif_stop_queue(mesh_dev); - netif_carrier_off(priv->mesh_dev); + netif_carrier_off(mesh_dev); sysfs_remove_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group); + lbs_persist_config_remove(mesh_dev); unregister_netdev(mesh_dev); priv->mesh_dev = NULL; free_netdev(mesh_dev); diff --git a/drivers/net/wireless/libertas/persistcfg.c b/drivers/net/wireless/libertas/persistcfg.c new file mode 100644 index 00000000000..baa66273889 --- /dev/null +++ b/drivers/net/wireless/libertas/persistcfg.c @@ -0,0 +1,408 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "host.h" +#include "decl.h" +#include "dev.h" +#include "wext.h" +#include "debugfs.h" +#include "scan.h" +#include "assoc.h" +#include "cmd.h" + +static int mesh_get_default_parameters(struct device *dev, + struct mrvl_mesh_defaults *defs) +{ + struct lbs_private *priv = to_net_dev(dev)->priv; + struct cmd_ds_mesh_config cmd; + int ret; + + memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config)); + ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_GET, + CMD_TYPE_MESH_GET_DEFAULTS); + + if (ret) + return -EOPNOTSUPP; + + memcpy(defs, &cmd.data[0], sizeof(struct mrvl_mesh_defaults)); + + return 0; +} + +/** + * @brief Get function for sysfs attribute bootflag + */ +static ssize_t bootflag_get(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mrvl_mesh_defaults defs; + int ret; + + ret = mesh_get_default_parameters(dev, &defs); + + if (ret) + return ret; + + return snprintf(buf, 12, "0x%x\n", le32_to_cpu(defs.bootflag)); +} + +/** + * @brief Set function for sysfs attribute bootflag + */ +static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct lbs_private *priv = to_net_dev(dev)->priv; + struct cmd_ds_mesh_config cmd; + uint32_t datum; + int ret; + + memset(&cmd, 0, sizeof(cmd)); + ret = sscanf(buf, "%x", &datum); + if (ret != 1) + return -EINVAL; + + *((__le32 *)&cmd.data[0]) = cpu_to_le32(!!datum); + cmd.length = cpu_to_le16(sizeof(uint32_t)); + ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, + CMD_TYPE_MESH_SET_BOOTFLAG); + if (ret) + return ret; + + return strlen(buf); +} + +/** + * @brief Get function for sysfs attribute boottime + */ +static ssize_t boottime_get(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mrvl_mesh_defaults defs; + int ret; + + ret = mesh_get_default_parameters(dev, &defs); + + if (ret) + return ret; + + return snprintf(buf, 12, "0x%x\n", defs.boottime); +} + +/** + * @brief Set function for sysfs attribute boottime + */ +static ssize_t boottime_set(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct lbs_private *priv = to_net_dev(dev)->priv; + struct cmd_ds_mesh_config cmd; + uint32_t datum; + int ret; + + memset(&cmd, 0, sizeof(cmd)); + ret = sscanf(buf, "%x", &datum); + if (ret != 1) + return -EINVAL; + + /* A too small boot time will result in the device booting into + * standalone (no-host) mode before the host can take control of it, + * so the change will be hard to revert. This may be a desired + * feature (e.g to configure a very fast boot time for devices that + * will not be attached to a host), but dangerous. So I'm enforcing a + * lower limit of 20 seconds: remove and recompile the driver if this + * does not work for you. + */ + datum = (datum < 20) ? 20 : datum; + cmd.data[0] = datum; + cmd.length = cpu_to_le16(sizeof(uint8_t)); + ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, + CMD_TYPE_MESH_SET_BOOTTIME); + if (ret) + return ret; + + return strlen(buf); +} + +/** + * @brief Get function for sysfs attribute mesh_id + */ +static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct mrvl_mesh_defaults defs; + int maxlen; + int ret; + + ret = mesh_get_default_parameters(dev, &defs); + + if (ret) + return ret; + + if (defs.meshie.val.mesh_id_len > IW_ESSID_MAX_SIZE) { + printk(KERN_ERR "Inconsistent mesh ID length"); + defs.meshie.val.mesh_id_len = IW_ESSID_MAX_SIZE; + } + + /* SSID not null terminated: reserve room for \0 + \n */ + maxlen = defs.meshie.val.mesh_id_len + 2; + maxlen = (PAGE_SIZE > maxlen) ? maxlen : PAGE_SIZE; + + defs.meshie.val.mesh_id[defs.meshie.val.mesh_id_len] = '\0'; + + return snprintf(buf, maxlen, "%s\n", defs.meshie.val.mesh_id); +} + +/** + * @brief Set function for sysfs attribute mesh_id + */ +static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct cmd_ds_mesh_config cmd; + struct mrvl_mesh_defaults defs; + struct mrvl_meshie *ie; + struct lbs_private *priv = to_net_dev(dev)->priv; + int len; + int ret; + + if (count < 2 || count > IW_ESSID_MAX_SIZE + 1) + return -EINVAL; + + memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config)); + ie = (struct mrvl_meshie *) &cmd.data[0]; + + /* fetch all other Information Element parameters */ + ret = mesh_get_default_parameters(dev, &defs); + + cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie)); + + /* transfer IE elements */ + memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie)); + + len = count - 1; + memcpy(ie->val.mesh_id, buf, len); + /* SSID len */ + ie->val.mesh_id_len = len; + /* IE len */ + ie->hdr.len = sizeof(struct mrvl_meshie_val) - IW_ESSID_MAX_SIZE + len; + + ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, + CMD_TYPE_MESH_SET_MESH_IE); + if (ret) + return ret; + + return strlen(buf); +} + +/** + * @brief Get function for sysfs attribute protocol_id + */ +static ssize_t protocol_id_get(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mrvl_mesh_defaults defs; + int ret; + + ret = mesh_get_default_parameters(dev, &defs); + + if (ret) + return ret; + + return snprintf(buf, 5, "%d\n", defs.meshie.val.active_protocol_id); +} + +/** + * @brief Set function for sysfs attribute protocol_id + */ +static ssize_t protocol_id_set(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct cmd_ds_mesh_config cmd; + struct mrvl_mesh_defaults defs; + struct mrvl_meshie *ie; + struct lbs_private *priv = to_net_dev(dev)->priv; + uint32_t datum; + int ret; + + memset(&cmd, 0, sizeof(cmd)); + ret = sscanf(buf, "%x", &datum); + if (ret != 1) + return -EINVAL; + + /* fetch all other Information Element parameters */ + ret = mesh_get_default_parameters(dev, &defs); + + cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie)); + + /* transfer IE elements */ + ie = (struct mrvl_meshie *) &cmd.data[0]; + memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie)); + /* update protocol id */ + ie->val.active_protocol_id = datum; + + ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, + CMD_TYPE_MESH_SET_MESH_IE); + if (ret) + return ret; + + return strlen(buf); +} + +/** + * @brief Get function for sysfs attribute metric_id + */ +static ssize_t metric_id_get(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mrvl_mesh_defaults defs; + int ret; + + ret = mesh_get_default_parameters(dev, &defs); + + if (ret) + return ret; + + return snprintf(buf, 5, "%d\n", defs.meshie.val.active_metric_id); +} + +/** + * @brief Set function for sysfs attribute metric_id + */ +static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct cmd_ds_mesh_config cmd; + struct mrvl_mesh_defaults defs; + struct mrvl_meshie *ie; + struct lbs_private *priv = to_net_dev(dev)->priv; + uint32_t datum; + int ret; + + memset(&cmd, 0, sizeof(cmd)); + ret = sscanf(buf, "%x", &datum); + if (ret != 1) + return -EINVAL; + + /* fetch all other Information Element parameters */ + ret = mesh_get_default_parameters(dev, &defs); + + cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie)); + + /* transfer IE elements */ + ie = (struct mrvl_meshie *) &cmd.data[0]; + memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie)); + /* update metric id */ + ie->val.active_metric_id = datum; + + ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, + CMD_TYPE_MESH_SET_MESH_IE); + if (ret) + return ret; + + return strlen(buf); +} + +/** + * @brief Get function for sysfs attribute capability + */ +static ssize_t capability_get(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mrvl_mesh_defaults defs; + int ret; + + ret = mesh_get_default_parameters(dev, &defs); + + if (ret) + return ret; + + return snprintf(buf, 5, "%d\n", defs.meshie.val.mesh_capability); +} + +/** + * @brief Set function for sysfs attribute capability + */ +static ssize_t capability_set(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct cmd_ds_mesh_config cmd; + struct mrvl_mesh_defaults defs; + struct mrvl_meshie *ie; + struct lbs_private *priv = to_net_dev(dev)->priv; + uint32_t datum; + int ret; + + memset(&cmd, 0, sizeof(cmd)); + ret = sscanf(buf, "%x", &datum); + if (ret != 1) + return -EINVAL; + + /* fetch all other Information Element parameters */ + ret = mesh_get_default_parameters(dev, &defs); + + cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie)); + + /* transfer IE elements */ + ie = (struct mrvl_meshie *) &cmd.data[0]; + memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie)); + /* update value */ + ie->val.mesh_capability = datum; + + ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, + CMD_TYPE_MESH_SET_MESH_IE); + if (ret) + return ret; + + return strlen(buf); +} + + +static DEVICE_ATTR(bootflag, 0644, bootflag_get, bootflag_set); +static DEVICE_ATTR(boottime, 0644, boottime_get, boottime_set); +static DEVICE_ATTR(mesh_id, 0644, mesh_id_get, mesh_id_set); +static DEVICE_ATTR(protocol_id, 0644, protocol_id_get, protocol_id_set); +static DEVICE_ATTR(metric_id, 0644, metric_id_get, metric_id_set); +static DEVICE_ATTR(capability, 0644, capability_get, capability_set); + +static struct attribute *boot_opts_attrs[] = { + &dev_attr_bootflag.attr, + &dev_attr_boottime.attr, + NULL +}; + +static struct attribute_group boot_opts_group = { + .name = "boot_options", + .attrs = boot_opts_attrs, +}; + +static struct attribute *mesh_ie_attrs[] = { + &dev_attr_mesh_id.attr, + &dev_attr_protocol_id.attr, + &dev_attr_metric_id.attr, + &dev_attr_capability.attr, + NULL +}; + +static struct attribute_group mesh_ie_group = { + .name = "mesh_ie", + .attrs = mesh_ie_attrs, +}; + +void lbs_persist_config_init(struct net_device *dev) +{ + int ret; + ret = sysfs_create_group(&(dev->dev.kobj), &boot_opts_group); + ret = sysfs_create_group(&(dev->dev.kobj), &mesh_ie_group); +} + +void lbs_persist_config_remove(struct net_device *dev) +{ + sysfs_remove_group(&(dev->dev.kobj), &boot_opts_group); + sysfs_remove_group(&(dev->dev.kobj), &mesh_ie_group); +} -- cgit v1.2.3-70-g09d2 From edf5dabfa86163d589041cccf607b41a7033e9b0 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 20 May 2008 16:43:31 +0100 Subject: libertas: Add reset_card() callback to hardware driver Signed-off-by: David Woodhouse Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/dev.h | 1 + drivers/net/wireless/libertas/main.c | 5 +++++ 2 files changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index e12ce650672..0a9fc513678 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -153,6 +153,7 @@ struct lbs_private { /** Hardware access */ int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb); + void (*reset_card) (struct lbs_private *priv); /* Wake On LAN */ uint32_t wol_criteria; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index db246d0a1ed..804da368416 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -787,6 +787,11 @@ static int lbs_thread(void *data) le16_to_cpu(cmdnode->cmdbuf->command)); lbs_complete_command(priv, cmdnode, -ETIMEDOUT); priv->nr_retries = 0; + if (priv->reset_card) { + spin_unlock_irq(&priv->driver_lock); + priv->reset_card(priv); + spin_lock_irq(&priv->driver_lock); + } } else { priv->cur_cmd = NULL; lbs_pr_info("requeueing command %x due to timeout (#%d)\n", -- cgit v1.2.3-70-g09d2 From b679aeb304e3070626750c15e043a40da0e942fc Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Tue, 20 May 2008 15:18:49 -0700 Subject: libertas: sysfs interface for accessing default mesh channel This will create the following entry: /sys/class/net/mshX -- boot_options | |-- ... | `-- channel ... ... which I overlooked on my previous patch. Signed-off-by: Javier Cardona Signed-off-by: David Woodhouse Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/persistcfg.c | 45 ++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/persistcfg.c b/drivers/net/wireless/libertas/persistcfg.c index baa66273889..6cf5e3949af 100644 --- a/drivers/net/wireless/libertas/persistcfg.c +++ b/drivers/net/wireless/libertas/persistcfg.c @@ -129,6 +129,49 @@ static ssize_t boottime_set(struct device *dev, return strlen(buf); } +/** + * @brief Get function for sysfs attribute channel + */ +static ssize_t channel_get(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mrvl_mesh_defaults defs; + int ret; + + ret = mesh_get_default_parameters(dev, &defs); + + if (ret) + return ret; + + return snprintf(buf, 12, "0x%x\n", le16_to_cpu(defs.channel)); +} + +/** + * @brief Set function for sysfs attribute channel + */ +static ssize_t channel_set(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct lbs_private *priv = to_net_dev(dev)->priv; + struct cmd_ds_mesh_config cmd; + uint16_t datum; + int ret; + + memset(&cmd, 0, sizeof(cmd)); + ret = sscanf(buf, "%hx", &datum); + if (ret != 1 || datum < 1 || datum > 11) + return -EINVAL; + + *((__le16 *)&cmd.data[0]) = cpu_to_le16(datum); + cmd.length = cpu_to_le16(sizeof(uint16_t)); + ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, + CMD_TYPE_MESH_SET_DEF_CHANNEL); + if (ret) + return ret; + + return strlen(buf); +} + /** * @brief Get function for sysfs attribute mesh_id */ @@ -365,6 +408,7 @@ static ssize_t capability_set(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR(bootflag, 0644, bootflag_get, bootflag_set); static DEVICE_ATTR(boottime, 0644, boottime_get, boottime_set); +static DEVICE_ATTR(channel, 0644, channel_get, channel_set); static DEVICE_ATTR(mesh_id, 0644, mesh_id_get, mesh_id_set); static DEVICE_ATTR(protocol_id, 0644, protocol_id_get, protocol_id_set); static DEVICE_ATTR(metric_id, 0644, metric_id_get, metric_id_set); @@ -373,6 +417,7 @@ static DEVICE_ATTR(capability, 0644, capability_get, capability_set); static struct attribute *boot_opts_attrs[] = { &dev_attr_bootflag.attr, &dev_attr_boottime.attr, + &dev_attr_channel.attr, NULL }; -- cgit v1.2.3-70-g09d2 From 57962f0b9d76487a660619f97c0aa811924274a0 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Wed, 14 May 2008 16:30:28 +0200 Subject: libertas: reduce command retry time [PATCH, take 2] libertas: reduce command retry time In the normal case, an unsuccessful command would be retried for 10*5 seconds, or 10*10 seconds in the worst case. This patch reduces this to 3*3 seconds, or 3*10 seconds in the worst case. I also reduced the time it takes to start a new command downloaded. Signed-off-by: Holger Schurig Acked-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 6 +++--- drivers/net/wireless/libertas/main.c | 20 +++++++++++--------- 2 files changed, 14 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 7ccec987faa..2d9bbcc0dd4 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1136,7 +1136,7 @@ static void lbs_submit_command(struct lbs_private *priv, struct cmd_header *cmd; uint16_t cmdsize; uint16_t command; - int timeo = 5 * HZ; + int timeo = 3 * HZ; int ret; lbs_deb_enter(LBS_DEB_HOST); @@ -1154,7 +1154,7 @@ static void lbs_submit_command(struct lbs_private *priv, /* These commands take longer */ if (command == CMD_802_11_SCAN || command == CMD_802_11_ASSOCIATE || command == CMD_802_11_AUTHENTICATE) - timeo = 10 * HZ; + timeo = 5 * HZ; lbs_deb_cmd("DNLD_CMD: command 0x%04x, seq %d, size %d\n", command, le16_to_cpu(cmd->seqnum), cmdsize); @@ -1166,7 +1166,7 @@ static void lbs_submit_command(struct lbs_private *priv, lbs_pr_info("DNLD_CMD: hw_host_to_card failed: %d\n", ret); /* Let the timer kick in and retry, and potentially reset the whole thing if the condition persists */ - timeo = HZ; + timeo = HZ/4; } /* Setup the timer after transmit command */ diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 804da368416..baafa44cfb3 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -782,9 +782,10 @@ static int lbs_thread(void *data) if (priv->cmd_timed_out && priv->cur_cmd) { struct cmd_ctrl_node *cmdnode = priv->cur_cmd; - if (++priv->nr_retries > 10) { - lbs_pr_info("Excessive timeouts submitting command %x\n", - le16_to_cpu(cmdnode->cmdbuf->command)); + if (++priv->nr_retries > 3) { + lbs_pr_info("Excessive timeouts submitting " + "command 0x%04x\n", + le16_to_cpu(cmdnode->cmdbuf->command)); lbs_complete_command(priv, cmdnode, -ETIMEDOUT); priv->nr_retries = 0; if (priv->reset_card) { @@ -794,8 +795,10 @@ static int lbs_thread(void *data) } } else { priv->cur_cmd = NULL; - lbs_pr_info("requeueing command %x due to timeout (#%d)\n", - le16_to_cpu(cmdnode->cmdbuf->command), priv->nr_retries); + lbs_pr_info("requeueing command 0x%04x due " + "to timeout (#%d)\n", + le16_to_cpu(cmdnode->cmdbuf->command), + priv->nr_retries); /* Stick it back at the _top_ of the pending queue for immediate resubmission */ @@ -986,12 +989,11 @@ static void command_timer_fn(unsigned long data) lbs_deb_enter(LBS_DEB_CMD); spin_lock_irqsave(&priv->driver_lock, flags); - if (!priv->cur_cmd) { - lbs_pr_info("Command timer expired; no pending command\n"); + if (!priv->cur_cmd) goto out; - } - lbs_pr_info("Command %x timed out\n", le16_to_cpu(priv->cur_cmd->cmdbuf->command)); + lbs_pr_info("command 0x%04x timed out\n", + le16_to_cpu(priv->cur_cmd->cmdbuf->command)); priv->cmd_timed_out = 1; wake_up_interruptible(&priv->waitq); -- cgit v1.2.3-70-g09d2 From 02883017607dfc60ff188980368adbe942823492 Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Thu, 15 May 2008 13:53:53 +0800 Subject: iwlwifi: changing irrelevant comment This patch changes an old eeprom comment in probe flow. Signed-off-by: Ron Rindjunsky Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl4965-base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 55ca752ae9e..d0f948d2cfa 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -6605,7 +6605,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e if (err) goto out_iounmap; - /* MAC Address location in EEPROM same for 3945/4965 */ + /* extract MAC Address */ iwl_eeprom_get_mac(priv, priv->mac_addr); IWL_DEBUG_INFO("MAC address: %s\n", print_mac(mac, priv->mac_addr)); SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr); -- cgit v1.2.3-70-g09d2 From 0b794d63c5db8d010d1584c694eba97f0391fca6 Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Thu, 15 May 2008 13:53:54 +0800 Subject: iwlwifi: remove iwl4965_nic_start function This patch moves the contant of iwl4965_nic_start to the only place it is being used. Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl4965-base.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index d0f948d2cfa..1a2d3768867 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -3958,13 +3958,6 @@ static void iwl4965_dealloc_ucode_pci(struct iwl_priv *priv) iwl_free_fw_desc(priv->pci_dev, &priv->ucode_boot); } -static void iwl4965_nic_start(struct iwl_priv *priv) -{ - /* Remove all resets to allow NIC to operate */ - iwl_write32(priv, CSR_RESET, 0); -} - - /** * iwl4965_read_ucode - Read uCode images from disk file. * @@ -4454,7 +4447,8 @@ static int __iwl4965_up(struct iwl_priv *priv) } /* start card; "initialize" will load runtime ucode */ - iwl4965_nic_start(priv); + /* Remove all resets to allow NIC to operate */ + iwl_write32(priv, CSR_RESET, 0); IWL_DEBUG_INFO(DRV_NAME " is coming up\n"); -- cgit v1.2.3-70-g09d2 From edcdf8b21ac920e06b4180246123fe43b022e020 Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Thu, 15 May 2008 13:53:55 +0800 Subject: mac80211: separate Tx and Rx MCS when configuring HT This patch follows the 11n spec in separation between Tx and Rx MCS capabilities. Up until now, when configuring the HT possible set of Tx MCS only Rx MCS were considered, assuming they are the same as the Tx MCS. This patch fixed this by looking at low level driver Tx capabilities. Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl4965-base.c | 14 +++-- include/linux/ieee80211.h | 18 ++++-- net/mac80211/main.c | 96 ++++++++++++++++++----------- 3 files changed, 83 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 1a2d3768867..c713b27ec65 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -3958,6 +3958,13 @@ static void iwl4965_dealloc_ucode_pci(struct iwl_priv *priv) iwl_free_fw_desc(priv->pci_dev, &priv->ucode_boot); } +static void iwl4965_nic_start(struct iwl_priv *priv) +{ + /* Remove all resets to allow NIC to operate */ + iwl_write32(priv, CSR_RESET, 0); +} + + /** * iwl4965_read_ucode - Read uCode images from disk file. * @@ -4447,8 +4454,7 @@ static int __iwl4965_up(struct iwl_priv *priv) } /* start card; "initialize" will load runtime ucode */ - /* Remove all resets to allow NIC to operate */ - iwl_write32(priv, CSR_RESET, 0); + iwl4965_nic_start(priv); IWL_DEBUG_INFO(DRV_NAME " is coming up\n"); @@ -6842,10 +6848,6 @@ static int __init iwl4965_init(void) return ret; - -#ifdef CONFIG_IWLWIFI_DEBUG - pci_unregister_driver(&iwl_driver); -#endif error_register: iwl4965_rate_control_unregister(); return ret; diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index a9102bc78b6..3c2ac0c37aa 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -306,8 +306,18 @@ struct ieee80211_ht_addt_info { #define IEEE80211_HT_CAP_SGI_40 0x0040 #define IEEE80211_HT_CAP_DELAY_BA 0x0400 #define IEEE80211_HT_CAP_MAX_AMSDU 0x0800 +/* 802.11n HT capability AMPDU settings */ #define IEEE80211_HT_CAP_AMPDU_FACTOR 0x03 #define IEEE80211_HT_CAP_AMPDU_DENSITY 0x1C +/* 802.11n HT capability MSC set */ +#define IEEE80211_SUPP_MCS_SET_UEQM 4 +#define IEEE80211_HT_CAP_MAX_STREAMS 4 +#define IEEE80211_SUPP_MCS_SET_LEN 10 +/* maximum streams the spec allows */ +#define IEEE80211_HT_CAP_MCS_TX_DEFINED 0x01 +#define IEEE80211_HT_CAP_MCS_TX_RX_DIFF 0x02 +#define IEEE80211_HT_CAP_MCS_TX_STREAMS 0x0C +#define IEEE80211_HT_CAP_MCS_TX_UEQM 0x10 /* 802.11n HT IE masks */ #define IEEE80211_HT_IE_CHA_SEC_OFFSET 0x03 #define IEEE80211_HT_IE_CHA_WIDTH 0x04 @@ -316,10 +326,10 @@ struct ieee80211_ht_addt_info { #define IEEE80211_HT_IE_NON_HT_STA_PRSNT 0x0010 /* MIMO Power Save Modes */ -#define WLAN_HT_CAP_MIMO_PS_STATIC 0 -#define WLAN_HT_CAP_MIMO_PS_DYNAMIC 1 -#define WLAN_HT_CAP_MIMO_PS_INVALID 2 -#define WLAN_HT_CAP_MIMO_PS_DISABLED 3 +#define WLAN_HT_CAP_MIMO_PS_STATIC 0 +#define WLAN_HT_CAP_MIMO_PS_DYNAMIC 1 +#define WLAN_HT_CAP_MIMO_PS_INVALID 2 +#define WLAN_HT_CAP_MIMO_PS_DISABLED 3 /* Authentication algorithms */ #define WLAN_AUTH_OPEN 0 diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 36016363d22..b0fddb7de54 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -35,8 +35,6 @@ #include "debugfs.h" #include "debugfs_netdev.h" -#define SUPP_MCS_SET_LEN 16 - /* * For seeing transmitted packets on monitor interfaces * we have a radiotap header too. @@ -1068,56 +1066,84 @@ u32 ieee80211_handle_ht(struct ieee80211_local *local, int enable_ht, struct ieee80211_supported_band *sband; struct ieee80211_ht_info ht_conf; struct ieee80211_ht_bss_info ht_bss_conf; - int i; u32 changed = 0; + int i; + u8 max_tx_streams = IEEE80211_HT_CAP_MAX_STREAMS; + u8 tx_mcs_set_cap; sband = local->hw.wiphy->bands[conf->channel->band]; + memset(&ht_conf, 0, sizeof(struct ieee80211_ht_info)); + memset(&ht_bss_conf, 0, sizeof(struct ieee80211_ht_bss_info)); + /* HT is not supported */ if (!sband->ht_info.ht_supported) { conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE; - return 0; + goto out; } - memset(&ht_conf, 0, sizeof(struct ieee80211_ht_info)); - memset(&ht_bss_conf, 0, sizeof(struct ieee80211_ht_bss_info)); - - if (enable_ht) { - if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)) + /* disable HT */ + if (!enable_ht) { + if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) changed |= BSS_CHANGED_HT; + conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE; + conf->ht_conf.ht_supported = 0; + goto out; + } - conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE; - ht_conf.ht_supported = 1; - ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap; - ht_conf.cap &= ~(IEEE80211_HT_CAP_MIMO_PS); - ht_conf.cap |= sband->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS; + if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)) + changed |= BSS_CHANGED_HT; - for (i = 0; i < SUPP_MCS_SET_LEN; i++) - ht_conf.supp_mcs_set[i] = - sband->ht_info.supp_mcs_set[i] & - req_ht_cap->supp_mcs_set[i]; + conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE; + ht_conf.ht_supported = 1; - ht_bss_conf.primary_channel = req_bss_cap->primary_channel; - ht_bss_conf.bss_cap = req_bss_cap->bss_cap; - ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode; + ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap; + ht_conf.cap &= ~(IEEE80211_HT_CAP_MIMO_PS); + ht_conf.cap |= sband->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS; + ht_bss_conf.primary_channel = req_bss_cap->primary_channel; + ht_bss_conf.bss_cap = req_bss_cap->bss_cap; + ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode; - ht_conf.ampdu_factor = req_ht_cap->ampdu_factor; - ht_conf.ampdu_density = req_ht_cap->ampdu_density; + ht_conf.ampdu_factor = req_ht_cap->ampdu_factor; + ht_conf.ampdu_density = req_ht_cap->ampdu_density; - /* if bss configuration changed store the new one */ - if (memcmp(&conf->ht_conf, &ht_conf, sizeof(ht_conf)) || - memcmp(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf))) { - changed |= BSS_CHANGED_HT; - memcpy(&conf->ht_conf, &ht_conf, sizeof(ht_conf)); - memcpy(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf)); - } - } else { - if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) - changed |= BSS_CHANGED_HT; - conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE; - } + /* Bits 96-100 */ + tx_mcs_set_cap = sband->ht_info.supp_mcs_set[12]; + /* configure suppoerted Tx MCS according to requested MCS + * (based in most cases on Rx capabilities of peer) and self + * Tx MCS capabilities (as defined by low level driver HW + * Tx capabilities) */ + if (!(tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_DEFINED)) + goto check_changed; + + /* Counting from 0 therfore + 1 */ + if (tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_RX_DIFF) + max_tx_streams = ((tx_mcs_set_cap & + IEEE80211_HT_CAP_MCS_TX_STREAMS) >> 2) + 1; + + for (i = 0; i < max_tx_streams; i++) + ht_conf.supp_mcs_set[i] = + sband->ht_info.supp_mcs_set[i] & + req_ht_cap->supp_mcs_set[i]; + + if (tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_UEQM) + for (i = IEEE80211_SUPP_MCS_SET_UEQM; + i < IEEE80211_SUPP_MCS_SET_LEN; i++) + ht_conf.supp_mcs_set[i] = + sband->ht_info.supp_mcs_set[i] & + req_ht_cap->supp_mcs_set[i]; + +check_changed: + /* if bss configuration changed store the new one */ + if (memcmp(&conf->ht_conf, &ht_conf, sizeof(ht_conf)) || + memcmp(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf))) { + changed |= BSS_CHANGED_HT; + memcpy(&conf->ht_conf, &ht_conf, sizeof(ht_conf)); + memcpy(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf)); + } +out: return changed; } -- cgit v1.2.3-70-g09d2 From 39130df32adf8272373c03c8c2499cd2a1b4c5cf Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Thu, 15 May 2008 13:53:56 +0800 Subject: iwlwifi: filling Tx MCS set This patch fills the needed data about HW capabilities in matters of possible HT Tx MCS. Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index d3cbad2bf87..a2f4f288375 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -317,24 +317,33 @@ void iwl_reset_qos(struct iwl_priv *priv) EXPORT_SYMBOL(iwl_reset_qos); #ifdef CONFIG_IWL4965_HT +#define MAX_BIT_RATE_40_MHZ 0x96; /* 150 Mbps */ +#define MAX_BIT_RATE_20_MHZ 0x48; /* 72 Mbps */ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, struct ieee80211_ht_info *ht_info, enum ieee80211_band band) { + u16 max_bit_rate = 0; + u8 rx_chains_num = priv->hw_params.rx_chains_num; + u8 tx_chains_num = priv->hw_params.tx_chains_num; + ht_info->cap = 0; memset(ht_info->supp_mcs_set, 0, 16); ht_info->ht_supported = 1; + ht_info->cap |= (u16)IEEE80211_HT_CAP_GRN_FLD; + ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_20; + ht_info->cap |= (u16)(IEEE80211_HT_CAP_MIMO_PS & + (IWL_MIMO_PS_NONE << 2)); + + max_bit_rate = MAX_BIT_RATE_20_MHZ; if (priv->hw_params.fat_channel & BIT(band)) { ht_info->cap |= (u16)IEEE80211_HT_CAP_SUP_WIDTH; ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_40; ht_info->supp_mcs_set[4] = 0x01; + max_bit_rate = MAX_BIT_RATE_40_MHZ; } - ht_info->cap |= (u16)IEEE80211_HT_CAP_GRN_FLD; - ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_20; - ht_info->cap |= (u16)(IEEE80211_HT_CAP_MIMO_PS & - (IWL_MIMO_PS_NONE << 2)); if (priv->cfg->mod_params->amsdu_size_8K) ht_info->cap |= (u16)IEEE80211_HT_CAP_MAX_AMSDU; @@ -343,10 +352,22 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF; ht_info->supp_mcs_set[0] = 0xFF; - if (priv->hw_params.tx_chains_num >= 2) + if (rx_chains_num >= 2) ht_info->supp_mcs_set[1] = 0xFF; - if (priv->hw_params.tx_chains_num >= 3) + if (rx_chains_num >= 3) ht_info->supp_mcs_set[2] = 0xFF; + + /* Highest supported Rx data rate */ + max_bit_rate *= rx_chains_num; + ht_info->supp_mcs_set[10] = (u8)(max_bit_rate & 0x00FF); + ht_info->supp_mcs_set[11] = (u8)((max_bit_rate & 0xFF00) >> 8); + + /* Tx MCS capabilities */ + ht_info->supp_mcs_set[12] = IEEE80211_HT_CAP_MCS_TX_DEFINED; + if (tx_chains_num != rx_chains_num) { + ht_info->supp_mcs_set[12] |= IEEE80211_HT_CAP_MCS_TX_RX_DIFF; + ht_info->supp_mcs_set[12] |= ((tx_chains_num - 1) << 2); + } } #else static inline void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, -- cgit v1.2.3-70-g09d2 From 443cfd457f780e40ceab7e00fbb6a56882848834 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 15 May 2008 13:53:57 +0800 Subject: iwlwifi: rename iwl4965_queue to iwl_queue This patch renames iwl4965_queue to iwl_queue. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 16 +++------------- drivers/net/wireless/iwlwifi/iwl-dev.h | 6 +++--- drivers/net/wireless/iwlwifi/iwl-tx.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl4965-base.c | 28 ++++++++++++++-------------- 4 files changed, 22 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 17847f981e1..2bb0075a807 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -3231,7 +3231,7 @@ static int iwl4965_tx_queue_agg_disable(struct iwl_priv *priv, u16 txq_id, int iwl4965_check_empty_hw_queue(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id) { - struct iwl4965_queue *q = &priv->txq[txq_id].q; + struct iwl_queue *q = &priv->txq[txq_id].q; u8 *addr = priv->stations[sta_id].sta.sta.addr; struct iwl_tid_data *tid_data = &priv->stations[sta_id].tid[tid]; @@ -3262,16 +3262,6 @@ int iwl4965_check_empty_hw_queue(struct iwl_priv *priv, int sta_id, return 0; } -/** - * iwl4965_queue_dec_wrap - Decrement queue index, wrap back to end if needed - * @index -- current index - * @n_bd -- total number of entries in queue (s/b power of 2) - */ -static inline int iwl4965_queue_dec_wrap(int index, int n_bd) -{ - return (index == 0) ? n_bd - 1 : index - 1; -} - /** * iwl4965_rx_reply_compressed_ba - Handler for REPLY_COMPRESSED_BA * @@ -3304,7 +3294,7 @@ static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv, agg = &priv->stations[ba_resp->sta_id].tid[ba_resp->tid].agg; /* Find index just before block-ack window */ - index = iwl4965_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd); + index = iwl_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd); /* TODO: Need to get this copy more safely - now good for debug */ @@ -3337,7 +3327,7 @@ static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv, int freed = iwl4965_tx_queue_reclaim(priv, scd_flow, index); priv->stations[ba_resp->sta_id]. tid[ba_resp->tid].tfds_in_queue -= freed; - if (iwl4965_queue_space(&txq->q) > txq->q.low_mark && + if (iwl_queue_space(&txq->q) > txq->q.low_mark && priv->mac80211_registered && agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) ieee80211_wake_queue(priv->hw, ampdu_q); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 5dccc5a8fa9..cf992240756 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -102,7 +102,7 @@ struct iwl_rx_mem_buffer { * * Contains common data for Rx and Tx queues */ -struct iwl4965_queue { +struct iwl_queue { int n_bd; /* number of BDs in this queue */ int write_ptr; /* 1-st empty entry (index) host_w*/ int read_ptr; /* last used entry (index) host_r*/ @@ -137,7 +137,7 @@ struct iwl4965_tx_info { * descriptors) and required locking structures. */ struct iwl_tx_queue { - struct iwl4965_queue q; + struct iwl_queue q; struct iwl_tfd_frame *bd; struct iwl_cmd *cmd; dma_addr_t dma_addr_cmd; @@ -721,7 +721,7 @@ extern u8 iwl_find_station(struct iwl_priv *priv, const u8 *bssid); extern int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel); extern int iwl4965_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index); -extern int iwl4965_queue_space(const struct iwl4965_queue *q); +extern int iwl_queue_space(const struct iwl_queue *q); struct iwl_priv; extern void iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio); diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index a1e03ccd514..870d257bded 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -105,7 +105,7 @@ EXPORT_SYMBOL(iwl_hw_txq_free_tfd); */ static void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq) { - struct iwl4965_queue *q = &txq->q; + struct iwl_queue *q = &txq->q; struct pci_dev *dev = priv->pci_dev; int len; @@ -158,7 +158,7 @@ EXPORT_SYMBOL(iwl_hw_txq_ctx_free); /** * iwl_queue_init - Initialize queue's high/low-water and read/write indexes */ -static int iwl_queue_init(struct iwl_priv *priv, struct iwl4965_queue *q, +static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q, int count, int slots_num, u32 id) { q->n_bd = count; diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index c713b27ec65..2e7e616a089 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -173,7 +173,7 @@ static const char *iwl4965_escape_essid(const char *essid, u8 essid_len) * See more detailed info in iwl-4965-hw.h. ***************************************************/ -int iwl4965_queue_space(const struct iwl4965_queue *q) +int iwl_queue_space(const struct iwl_queue *q) { int s = q->read_ptr - q->write_ptr; @@ -190,14 +190,14 @@ int iwl4965_queue_space(const struct iwl4965_queue *q) } -static inline int x2_queue_used(const struct iwl4965_queue *q, int i) +static inline int iwl_queue_used(const struct iwl_queue *q, int i) { return q->write_ptr > q->read_ptr ? (i >= q->read_ptr && i < q->write_ptr) : !(i < q->read_ptr && i >= q->write_ptr); } -static inline u8 get_cmd_index(struct iwl4965_queue *q, u32 index, int is_huge) +static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge) { /* This is for scan command, the big buffer at end of command array */ if (is_huge) @@ -348,7 +348,7 @@ u8 iwl4965_add_station_flags(struct iwl_priv *priv, const u8 *addr, int iwl4965_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) { struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; - struct iwl4965_queue *q = &txq->q; + struct iwl_queue *q = &txq->q; struct iwl_tfd_frame *tfd; u32 *control_flags; struct iwl_cmd *out_cmd; @@ -369,7 +369,7 @@ int iwl4965_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) return -EIO; } - if (iwl4965_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) { + if (iwl_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) { IWL_ERROR("No space for Tx\n"); return -ENOSPC; } @@ -1768,7 +1768,7 @@ static int iwl4965_tx_skb(struct iwl_priv *priv, u32 *control_flags; int txq_id = ctl->queue; struct iwl_tx_queue *txq = NULL; - struct iwl4965_queue *q = NULL; + struct iwl_queue *q = NULL; dma_addr_t phys_addr; dma_addr_t txcmd_phys; dma_addr_t scratch_phys; @@ -1981,7 +1981,7 @@ static int iwl4965_tx_skb(struct iwl_priv *priv, if (rc) return rc; - if ((iwl4965_queue_space(q) < q->high_mark) + if ((iwl_queue_space(q) < q->high_mark) && priv->mac80211_registered) { if (wait_write_ptr) { spin_lock_irqsave(&priv->lock, flags); @@ -2332,10 +2332,10 @@ static void iwl4965_txstatus_to_ieee(struct iwl_priv *priv, int iwl4965_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) { struct iwl_tx_queue *txq = &priv->txq[txq_id]; - struct iwl4965_queue *q = &txq->q; + struct iwl_queue *q = &txq->q; int nfreed = 0; - if ((index >= q->n_bd) || (x2_queue_used(q, index) == 0)) { + if ((index >= q->n_bd) || (iwl_queue_used(q, index) == 0)) { IWL_ERROR("Read index for DMA queue txq id (%d), index %d, " "is out of range [0-%d] %d %d.\n", txq_id, index, q->n_bd, q->write_ptr, q->read_ptr); @@ -2541,7 +2541,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, __le16 *qc; #endif - if ((index >= txq->q.n_bd) || (x2_queue_used(&txq->q, index) == 0)) { + if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) { IWL_ERROR("Read index for DMA queue txq_id (%d) index %d " "is out of range [0-%d] %d %d\n", txq_id, index, txq->q.n_bd, txq->q.write_ptr, @@ -2587,7 +2587,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, freed = iwl4965_tx_queue_reclaim(priv, txq_id, index); priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; - if (iwl4965_queue_space(&txq->q) > txq->q.low_mark && + if (iwl_queue_space(&txq->q) > txq->q.low_mark && txq_id >= 0 && priv->mac80211_registered && agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) { /* calculate mac80211 ampdu sw queue to wake */ @@ -2621,7 +2621,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, int freed = iwl4965_tx_queue_reclaim(priv, txq_id, index); if (tid != MAX_TID_COUNT) priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; - if (iwl4965_queue_space(&txq->q) > txq->q.low_mark && + if (iwl_queue_space(&txq->q) > txq->q.low_mark && (txq_id >= 0) && priv->mac80211_registered) ieee80211_wake_queue(priv->hw, txq_id); if (tid != MAX_TID_COUNT) @@ -5783,7 +5783,7 @@ static int iwl4965_mac_get_tx_stats(struct ieee80211_hw *hw, struct iwl_priv *priv = hw->priv; int i, avail; struct iwl_tx_queue *txq; - struct iwl4965_queue *q; + struct iwl_queue *q; unsigned long flags; IWL_DEBUG_MAC80211("enter\n"); @@ -5798,7 +5798,7 @@ static int iwl4965_mac_get_tx_stats(struct ieee80211_hw *hw, for (i = 0; i < AC_NUM; i++) { txq = &priv->txq[i]; q = &txq->q; - avail = iwl4965_queue_space(q); + avail = iwl_queue_space(q); stats[i].len = q->n_window - avail; stats[i].limit = q->n_window - q->high_mark; -- cgit v1.2.3-70-g09d2 From 8567c63e3385688b95658fe31b3ac8f4436b1b0f Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 15 May 2008 13:53:58 +0800 Subject: iwlwifi: rename iwl4965_tx_info to iwl_tx_info This patch renames iwl4965_tx_info to iwl_tx_info. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-dev.h | 4 ++-- drivers/net/wireless/iwlwifi/iwl4965-base.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index cf992240756..ae18a803d03 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -118,7 +118,7 @@ struct iwl_queue { #define MAX_NUM_OF_TBS (20) /* One for each TFD */ -struct iwl4965_tx_info { +struct iwl_tx_info { struct ieee80211_tx_status status; struct sk_buff *skb[MAX_NUM_OF_TBS]; }; @@ -141,7 +141,7 @@ struct iwl_tx_queue { struct iwl_tfd_frame *bd; struct iwl_cmd *cmd; dma_addr_t dma_addr_cmd; - struct iwl4965_tx_info *txb; + struct iwl_tx_info *txb; int need_update; int sched_retry; int active; diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 2e7e616a089..6e70405d441 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -1868,7 +1868,7 @@ static int iwl4965_tx_skb(struct iwl_priv *priv, idx = get_cmd_index(q, q->write_ptr, 0); /* Set up driver data for this TFD */ - memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl4965_tx_info)); + memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info)); txq->txb[q->write_ptr].skb[0] = skb; memcpy(&(txq->txb[q->write_ptr].status.control), ctl, sizeof(struct ieee80211_tx_control)); @@ -2306,7 +2306,7 @@ static int iwl4965_get_measurement(struct iwl_priv *priv, #endif static void iwl4965_txstatus_to_ieee(struct iwl_priv *priv, - struct iwl4965_tx_info *tx_sta) + struct iwl_tx_info *tx_sta) { tx_sta->status.ack_signal = 0; -- cgit v1.2.3-70-g09d2 From c1adf9fb31e31ee753d613bd5bc6aef9b762b747 Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Thu, 15 May 2008 13:53:59 +0800 Subject: iwlwifi: get_hw_cmd_size This patch introduces a new handler get_hw_cmd_size in hcmd_utils, which should adjust the size of the command sent to the microcode according to the current nic. It also changes the RXON flow to make usage of this new handler. The patch also adds iwl_rxon_cmd structure which is supperset for 5000 HW and 4965. Signed-off-by: Gregory Greenman Signed-off-by: Zhu Yi Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 15 +++++++++++++-- drivers/net/wireless/iwlwifi/iwl-5000.c | 7 +++++++ drivers/net/wireless/iwlwifi/iwl-commands.h | 26 ++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-core.c | 2 +- drivers/net/wireless/iwlwifi/iwl-core.h | 2 +- drivers/net/wireless/iwlwifi/iwl-dev.h | 6 +++--- drivers/net/wireless/iwlwifi/iwl4965-base.c | 25 ++++++++++++++----------- 7 files changed, 65 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 2bb0075a807..83876a07fe2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -1857,8 +1857,8 @@ static int iwl4965_send_rxon_assoc(struct iwl_priv *priv) { int ret = 0; struct iwl4965_rxon_assoc_cmd rxon_assoc; - const struct iwl4965_rxon_cmd *rxon1 = &priv->staging_rxon; - const struct iwl4965_rxon_cmd *rxon2 = &priv->active_rxon; + const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon; + const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon; if ((rxon1->flags == rxon2->flags) && (rxon1->filter_flags == rxon2->filter_flags) && @@ -3743,6 +3743,16 @@ int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, #endif /* CONFIG_IWL4965_HT */ +static u16 iwl4965_get_hcmd_size(u8 cmd_id, u16 len) +{ + switch (cmd_id) { + case REPLY_RXON: + return (u16) sizeof(struct iwl4965_rxon_cmd); + default: + return len; + } +} + static u16 iwl4965_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) { struct iwl4965_addsta_cmd *addsta = (struct iwl4965_addsta_cmd *)data; @@ -3802,6 +3812,7 @@ static struct iwl_hcmd_ops iwl4965_hcmd = { }; static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = { + .get_hcmd_size = iwl4965_get_hcmd_size, .enqueue_hcmd = iwl4965_enqueue_hcmd, .build_addsta_hcmd = iwl4965_build_addsta_hcmd, #ifdef CONFIG_IWL4965_RUN_TIME_CALIB diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index b5e28b81179..72d655c59fb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -459,10 +459,17 @@ static int iwl5000_disable_tx_fifo(struct iwl_priv *priv) return 0; } +/* Currently 5000 is the supperset of everything */ +static u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 len) +{ + return len; +} + static struct iwl_hcmd_ops iwl5000_hcmd = { }; static struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = { + .get_hcmd_size = iwl5000_get_hcmd_size, .build_addsta_hcmd = iwl5000_build_addsta_hcmd, #ifdef CONFIG_IWL5000_RUN_TIME_CALIB .gain_computation = iwl5000_gain_computation, diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index d16a853f376..350af1be6e3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -600,6 +600,32 @@ struct iwl4965_rxon_cmd { u8 ofdm_ht_dual_stream_basic_rates; } __attribute__ ((packed)); +/* 5000 HW just extend this cmmand */ +struct iwl_rxon_cmd { + u8 node_addr[6]; + __le16 reserved1; + u8 bssid_addr[6]; + __le16 reserved2; + u8 wlap_bssid_addr[6]; + __le16 reserved3; + u8 dev_type; + u8 air_propagation; + __le16 rx_chain; + u8 ofdm_basic_rates; + u8 cck_basic_rates; + __le16 assoc_id; + __le32 flags; + __le32 filter_flags; + __le16 channel; + u8 ofdm_ht_single_stream_basic_rates; + u8 ofdm_ht_dual_stream_basic_rates; + u8 ofdm_ht_triple_stream_basic_rates; + u8 reserved5; + __le16 acquisition_data; + __le16 reserved6; +} __attribute__ ((packed)); + + /* * REPLY_RXON_ASSOC = 0x11 (command, has simple generic response) */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index a2f4f288375..b800031ecca 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -588,7 +588,7 @@ EXPORT_SYMBOL(iwl_is_fat_tx_allowed); void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) { - struct iwl4965_rxon_cmd *rxon = &priv->staging_rxon; + struct iwl_rxon_cmd *rxon = &priv->staging_rxon; u32 val; if (!ht_info->is_ht) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index e139c8ffa9a..dcf1e562af3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -86,6 +86,7 @@ struct iwl_hcmd_ops { int (*rxon_assoc)(struct iwl_priv *priv); }; struct iwl_hcmd_utils_ops { + u16 (*get_hcmd_size)(u8 cmd_id, u16 len); int (*enqueue_hcmd)(struct iwl_priv *priv, struct iwl_host_cmd *cmd); u16 (*build_addsta_hcmd)(const struct iwl_addsta_cmd *cmd, u8 *data); #ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB @@ -303,5 +304,4 @@ static inline int iwl_send_rxon_assoc(struct iwl_priv *priv) return priv->cfg->ops->hcmd->rxon_assoc(priv); } - #endif /* __iwl_core_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index ae18a803d03..9a842fd047d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1009,11 +1009,11 @@ struct iwl_priv { * changed via explicit cast within the * routines that actually update the physical * hardware */ - const struct iwl4965_rxon_cmd active_rxon; - struct iwl4965_rxon_cmd staging_rxon; + const struct iwl_rxon_cmd active_rxon; + struct iwl_rxon_cmd staging_rxon; int error_recovering; - struct iwl4965_rxon_cmd recovery_rxon; + struct iwl_rxon_cmd recovery_rxon; /* 1st responses from initialize and runtime uCode images. * 4965's initialize alive response contains some calibration data. */ diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 6e70405d441..45b6b5234ee 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -353,11 +353,14 @@ int iwl4965_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) u32 *control_flags; struct iwl_cmd *out_cmd; u32 idx; - u16 fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr)); + u16 fix_size; dma_addr_t phys_addr; int ret; unsigned long flags; + cmd->len = priv->cfg->ops->utils->get_hcmd_size(cmd->id, cmd->len); + fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr)); + /* If any of the command structures end up being larger than * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then * we will need to increase the size of the TFD entries */ @@ -422,7 +425,7 @@ int iwl4965_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) static void iwl4965_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt) { - struct iwl4965_rxon_cmd *rxon = &priv->staging_rxon; + struct iwl_rxon_cmd *rxon = &priv->staging_rxon; if (hw_decrypt) rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK; @@ -470,7 +473,7 @@ static int iwl4965_rxon_add_station(struct iwl_priv *priv, * be #ifdef'd out once the driver is stable and folks aren't actively * making changes */ -static int iwl4965_check_rxon_cmd(struct iwl4965_rxon_cmd *rxon) +static int iwl4965_check_rxon_cmd(struct iwl_rxon_cmd *rxon) { int error = 0; int counter = 1; @@ -595,7 +598,7 @@ static int iwl4965_full_rxon_required(struct iwl_priv *priv) static int iwl4965_commit_rxon(struct iwl_priv *priv) { /* cast away the const for active_rxon in this function */ - struct iwl4965_rxon_cmd *active_rxon = (void *)&priv->active_rxon; + struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon; DECLARE_MAC_BUF(mac); int rc = 0; @@ -640,7 +643,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; rc = iwl_send_cmd_pdu(priv, REPLY_RXON, - sizeof(struct iwl4965_rxon_cmd), + sizeof(struct iwl_rxon_cmd), &priv->active_rxon); /* If the mask clearing failed then we set @@ -665,7 +668,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) iwl4965_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto); /* Apply the new configuration */ rc = iwl_send_cmd_pdu(priv, REPLY_RXON, - sizeof(struct iwl4965_rxon_cmd), &priv->staging_rxon); + sizeof(struct iwl_rxon_cmd), &priv->staging_rxon); if (rc) { IWL_ERROR("Error setting new configuration (%d).\n", rc); return rc; @@ -2699,7 +2702,7 @@ static void iwl4965_rx_reply_error(struct iwl_priv *priv, static void iwl4965_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - struct iwl4965_rxon_cmd *rxon = (void *)&priv->active_rxon; + struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon; struct iwl4965_csa_notification *csa = &(pkt->u.csa_notif); IWL_DEBUG_11H("CSA notif: channel %d, status %d\n", le16_to_cpu(csa->channel), le32_to_cpu(csa->status)); @@ -3317,7 +3320,7 @@ static int iwl4965_tx_queue_update_write_ptr(struct iwl_priv *priv, #ifdef CONFIG_IWLWIFI_DEBUG static void iwl4965_print_rx_config_cmd(struct iwl_priv *priv) { - struct iwl4965_rxon_cmd *rxon = &priv->staging_rxon; + struct iwl_rxon_cmd *rxon = &priv->staging_rxon; DECLARE_MAC_BUF(mac); IWL_DEBUG_RADIO("RX CONFIG:\n"); @@ -4213,8 +4216,8 @@ static void iwl4965_alive_start(struct iwl_priv *priv) priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK; if (iwl_is_associated(priv)) { - struct iwl4965_rxon_cmd *active_rxon = - (struct iwl4965_rxon_cmd *)(&priv->active_rxon); + struct iwl_rxon_cmd *active_rxon = + (struct iwl_rxon_cmd *)&priv->active_rxon; memcpy(&priv->staging_rxon, &priv->active_rxon, sizeof(priv->staging_rxon)); @@ -5021,7 +5024,7 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw) /* we should be verifying the device is ready to be opened */ mutex_lock(&priv->mutex); - memset(&priv->staging_rxon, 0, sizeof(struct iwl4965_rxon_cmd)); + memset(&priv->staging_rxon, 0, sizeof(struct iwl_rxon_cmd)); /* fetch ucode file from disk, alloc and copy to bus-master buffers ... * ucode filename and max sizes are card-specific. */ -- cgit v1.2.3-70-g09d2 From babcebfabbc3f52ba048495537baa9dffff080d4 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 15 May 2008 13:54:00 +0800 Subject: iwlwifi: remove 4965 from iwl4965_tx_queue_update_write_ptr This patch renames iwl4965_tx_queue_update_write_ptr to iwl_txq_update_write_ptr. This is a preparation for moving to iwl-tx.c. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl4965-base.c | 38 ++++++++++++++--------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 45b6b5234ee..0ad9558d6e8 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -53,7 +53,7 @@ #include "iwl-sta.h" #include "iwl-calib.h" -static int iwl4965_tx_queue_update_write_ptr(struct iwl_priv *priv, +static int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq); /****************************************************************************** @@ -417,7 +417,7 @@ int iwl4965_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) /* Increment and update queue's write index */ q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); - ret = iwl4965_tx_queue_update_write_ptr(priv, txq); + ret = iwl_txq_update_write_ptr(priv, txq); spin_unlock_irqrestore(&priv->hcmd_lock, flags); return ret ? ret : idx; @@ -1978,7 +1978,7 @@ static int iwl4965_tx_skb(struct iwl_priv *priv, /* Tell device the write index *just past* this latest filled TFD */ q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); - rc = iwl4965_tx_queue_update_write_ptr(priv, txq); + rc = iwl_txq_update_write_ptr(priv, txq); spin_unlock_irqrestore(&priv->lock, flags); if (rc) @@ -1989,7 +1989,7 @@ static int iwl4965_tx_skb(struct iwl_priv *priv, if (wait_write_ptr) { spin_lock_irqsave(&priv->lock, flags); txq->need_update = 1; - iwl4965_tx_queue_update_write_ptr(priv, txq); + iwl_txq_update_write_ptr(priv, txq); spin_unlock_irqrestore(&priv->lock, flags); } @@ -3272,17 +3272,17 @@ int iwl4965_calc_sig_qual(int rssi_dbm, int noise_dbm) } /** - * iwl4965_tx_queue_update_write_ptr - Send new write index to hardware + * iwl_txq_update_write_ptr - Send new write index to hardware */ -static int iwl4965_tx_queue_update_write_ptr(struct iwl_priv *priv, +static int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq) { u32 reg = 0; - int rc = 0; + int ret = 0; int txq_id = txq->q.id; if (txq->need_update == 0) - return rc; + return ret; /* if we're trying to save power */ if (test_bit(STATUS_POWER_PMI, &priv->status)) { @@ -3295,13 +3295,13 @@ static int iwl4965_tx_queue_update_write_ptr(struct iwl_priv *priv, IWL_DEBUG_INFO("Requesting wakeup, GP1 = 0x%x\n", reg); iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - return rc; + return ret; } /* restore this queue's parameters in nic hardware. */ - rc = iwl_grab_nic_access(priv); - if (rc) - return rc; + ret = iwl_grab_nic_access(priv); + if (ret) + return ret; iwl_write_direct32(priv, HBUS_TARG_WRPTR, txq->q.write_ptr | (txq_id << 8)); iwl_release_nic_access(priv); @@ -3314,7 +3314,7 @@ static int iwl4965_tx_queue_update_write_ptr(struct iwl_priv *priv, txq->need_update = 0; - return rc; + return ret; } #ifdef CONFIG_IWLWIFI_DEBUG @@ -3706,12 +3706,12 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv) if (inta & CSR_INT_BIT_WAKEUP) { IWL_DEBUG_ISR("Wakeup interrupt\n"); iwl_rx_queue_update_write_ptr(priv, &priv->rxq); - iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[0]); - iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[1]); - iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[2]); - iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[3]); - iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[4]); - iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[5]); + iwl_txq_update_write_ptr(priv, &priv->txq[0]); + iwl_txq_update_write_ptr(priv, &priv->txq[1]); + iwl_txq_update_write_ptr(priv, &priv->txq[2]); + iwl_txq_update_write_ptr(priv, &priv->txq[3]); + iwl_txq_update_write_ptr(priv, &priv->txq[4]); + iwl_txq_update_write_ptr(priv, &priv->txq[5]); handled |= CSR_INT_BIT_WAKEUP; } -- cgit v1.2.3-70-g09d2 From fcab423d716f923d6a7601ba33adf356bef83414 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 15 May 2008 13:54:01 +0800 Subject: iwlwifi: remove 4965 prefix from iwl4965_frame This patch removes 4965 from iwl4965_frame struct and handling functions. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 2 +- drivers/net/wireless/iwlwifi/iwl-dev.h | 4 ++-- drivers/net/wireless/iwlwifi/iwl4965-base.c | 20 ++++++++++---------- 3 files changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 83876a07fe2..922b0a195e9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2016,7 +2016,7 @@ int iwl4965_hw_get_temperature(struct iwl_priv *priv) } unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, - struct iwl4965_frame *frame, u8 rate) + struct iwl_frame *frame, u8 rate) { struct iwl4965_tx_beacon_cmd *tx_beacon_cmd; unsigned int frame_size; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 9a842fd047d..60a8f06225c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -262,7 +262,7 @@ enum iwl_pwr_src { #define IEEE80211_HLEN (IEEE80211_4ADDR_LEN) #define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN) -struct iwl4965_frame { +struct iwl_frame { union { struct ieee80211_hdr frame; struct iwl4965_tx_beacon_cmd beacon; @@ -696,7 +696,7 @@ extern int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *tfd, dma_addr_t addr, u16 len); extern int iwl4965_hw_get_temperature(struct iwl_priv *priv); extern unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, - struct iwl4965_frame *frame, u8 rate); + struct iwl_frame *frame, u8 rate); extern void iwl4965_hw_build_tx_cmd_rate(struct iwl_priv *priv, struct iwl_cmd *cmd, struct ieee80211_tx_control *ctrl, diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 0ad9558d6e8..1c45b6f49d5 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -800,7 +800,7 @@ static int iwl4965_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_fla return iwl_send_cmd(priv, &cmd); } -static void iwl4965_clear_free_frames(struct iwl_priv *priv) +static void iwl_clear_free_frames(struct iwl_priv *priv) { struct list_head *element; @@ -810,7 +810,7 @@ static void iwl4965_clear_free_frames(struct iwl_priv *priv) while (!list_empty(&priv->free_frames)) { element = priv->free_frames.next; list_del(element); - kfree(list_entry(element, struct iwl4965_frame, list)); + kfree(list_entry(element, struct iwl_frame, list)); priv->frames_count--; } @@ -821,9 +821,9 @@ static void iwl4965_clear_free_frames(struct iwl_priv *priv) } } -static struct iwl4965_frame *iwl4965_get_free_frame(struct iwl_priv *priv) +static struct iwl_frame *iwl_get_free_frame(struct iwl_priv *priv) { - struct iwl4965_frame *frame; + struct iwl_frame *frame; struct list_head *element; if (list_empty(&priv->free_frames)) { frame = kzalloc(sizeof(*frame), GFP_KERNEL); @@ -838,10 +838,10 @@ static struct iwl4965_frame *iwl4965_get_free_frame(struct iwl_priv *priv) element = priv->free_frames.next; list_del(element); - return list_entry(element, struct iwl4965_frame, list); + return list_entry(element, struct iwl_frame, list); } -static void iwl4965_free_frame(struct iwl_priv *priv, struct iwl4965_frame *frame) +static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame) { memset(frame, 0, sizeof(*frame)); list_add(&frame->list, &priv->free_frames); @@ -892,12 +892,12 @@ static u8 iwl4965_rate_get_lowest_plcp(struct iwl_priv *priv) static int iwl4965_send_beacon_cmd(struct iwl_priv *priv) { - struct iwl4965_frame *frame; + struct iwl_frame *frame; unsigned int frame_size; int rc; u8 rate; - frame = iwl4965_get_free_frame(priv); + frame = iwl_get_free_frame(priv); if (!frame) { IWL_ERROR("Could not obtain free frame buffer for beacon " @@ -912,7 +912,7 @@ static int iwl4965_send_beacon_cmd(struct iwl_priv *priv) rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size, &frame->u.cmd[0]); - iwl4965_free_frame(priv, frame); + iwl_free_frame(priv, frame); return rc; } @@ -4355,7 +4355,7 @@ static void __iwl4965_down(struct iwl_priv *priv) priv->ibss_beacon = NULL; /* clear out any free frames */ - iwl4965_clear_free_frames(priv); + iwl_clear_free_frames(priv); } static void iwl4965_down(struct iwl_priv *priv) -- cgit v1.2.3-70-g09d2 From 1826dcc094466a39c82d4370ccfba694be0bc05b Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 15 May 2008 13:54:02 +0800 Subject: iwlwifi: remove 4965 from iwl4965_rate_info This patch removes 4965 from iwl4965_rate_info structure and associated variables. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 27 ++++++++++++++------------- drivers/net/wireless/iwlwifi/iwl-4965-rs.h | 8 ++++---- drivers/net/wireless/iwlwifi/iwl-4965.c | 12 ++++++------ drivers/net/wireless/iwlwifi/iwl-core.c | 8 ++++---- drivers/net/wireless/iwlwifi/iwl4965-base.c | 6 +++--- 5 files changed, 31 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index 8e3660ebba7..e2123aba202 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -481,7 +481,7 @@ static u32 rate_n_flags_from_tbl(struct iwl4965_scale_tbl_info *tbl, u32 rate_n_flags = 0; if (is_legacy(tbl->lq_type)) { - rate_n_flags = iwl4965_rates[index].plcp; + rate_n_flags = iwl_rates[index].plcp; if (index >= IWL_FIRST_CCK_RATE && index <= IWL_LAST_CCK_RATE) rate_n_flags |= RATE_MCS_CCK_MSK; @@ -493,11 +493,11 @@ static u32 rate_n_flags_from_tbl(struct iwl4965_scale_tbl_info *tbl, rate_n_flags = RATE_MCS_HT_MSK; if (is_siso(tbl->lq_type)) - rate_n_flags |= iwl4965_rates[index].plcp_siso; + rate_n_flags |= iwl_rates[index].plcp_siso; else if (is_mimo2(tbl->lq_type)) - rate_n_flags |= iwl4965_rates[index].plcp_mimo2; + rate_n_flags |= iwl_rates[index].plcp_mimo2; else - rate_n_flags |= iwl4965_rates[index].plcp_mimo3; + rate_n_flags |= iwl_rates[index].plcp_mimo3; } else { IWL_ERROR("Invalid tbl->lq_type %d\n", tbl->lq_type); } @@ -697,7 +697,7 @@ static u16 rs_get_adjacent_rate(struct iwl_priv *priv, u8 index, u16 rate_mask, low = index; while (low != IWL_RATE_INVALID) { - low = iwl4965_rates[low].prev_rs; + low = iwl_rates[low].prev_rs; if (low == IWL_RATE_INVALID) break; if (rate_mask & (1 << low)) @@ -707,7 +707,7 @@ static u16 rs_get_adjacent_rate(struct iwl_priv *priv, u8 index, u16 rate_mask, high = index; while (high != IWL_RATE_INVALID) { - high = iwl4965_rates[high].next_rs; + high = iwl_rates[high].next_rs; if (high == IWL_RATE_INVALID) break; if (rate_mask & (1 << high)) @@ -2088,7 +2088,7 @@ static void rs_initialize_lq(struct iwl_priv *priv, i = 0; /* FIXME:RS: This is also wrong in 4965 */ - rate = iwl4965_rates[i].plcp; + rate = iwl_rates[i].plcp; rate |= RATE_MCS_ANT_B_MSK; rate &= ~RATE_MCS_ANT_A_MSK; @@ -2691,7 +2691,7 @@ int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) int active = lq_sta->active_tbl; cnt += - sprintf(&buf[cnt], " %2dMbs: ", iwl4965_rates[i].ieee / 2); + sprintf(&buf[cnt], " %2dMbs: ", iwl_rates[i].ieee / 2); mask = (1ULL << (IWL_RATE_MAX_WINDOW - 1)); for (j = 0; j < IWL_RATE_MAX_WINDOW; j++, mask >>= 1) @@ -2702,7 +2702,7 @@ int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) samples += lq_sta->lq_info[active].win[i].counter; good += lq_sta->lq_info[active].win[i].success_counter; success += lq_sta->lq_info[active].win[i].success_counter * - iwl4965_rates[i].ieee; + iwl_rates[i].ieee; if (lq_sta->lq_info[active].win[i].stamp) { int delta = @@ -2722,10 +2722,11 @@ int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) i = j; } - /* Display the average rate of all samples taken. - * - * NOTE: We multiply # of samples by 2 since the IEEE measurement - * added from iwl4965_rates is actually 2X the rate */ + /* + * Display the average rate of all samples taken. + * NOTE: We multiply # of samples by 2 since the IEEE measurement + * added from iwl_rates is actually 2X the rate. + */ if (samples) cnt += sprintf(&buf[cnt], "\nAverage rate is %3d.%02dMbs over last %4dms\n" diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.h b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h index 7ea2041a22e..1dd4124227a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h @@ -29,7 +29,7 @@ #include "iwl-dev.h" -struct iwl4965_rate_info { +struct iwl_rate_info { u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */ u8 plcp_siso; /* uCode API: IWL_RATE_SISO_6M_PLCP, etc. */ u8 plcp_mimo2; /* uCode API: IWL_RATE_MIMO2_6M_PLCP, etc. */ @@ -45,7 +45,7 @@ struct iwl4965_rate_info { /* * These serve as indexes into - * struct iwl4965_rate_info iwl4965_rates[IWL_RATE_COUNT]; + * struct iwl_rate_info iwl_rates[IWL_RATE_COUNT]; */ enum { IWL_RATE_1M_INDEX = 0, @@ -240,7 +240,7 @@ enum { #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)) -extern const struct iwl4965_rate_info iwl4965_rates[IWL_RATE_COUNT]; +extern const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT]; enum iwl_table_type { LQ_NONE, @@ -279,7 +279,7 @@ static inline u8 num_of_ant(u8 mask) static inline u8 iwl4965_get_prev_ieee_rate(u8 rate_index) { - u8 rate = iwl4965_rates[rate_index].prev_ieee; + u8 rate = iwl_rates[rate_index].prev_ieee; if (rate == IWL_RATE_INVALID) rate = rate_index; diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 922b0a195e9..1ec53a3848d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -345,8 +345,8 @@ int iwl4965_hwrate_to_plcp_idx(u32 rate_n_flags) /* 4965 legacy rate format, search for match in table */ } else { - for (idx = 0; idx < ARRAY_SIZE(iwl4965_rates); idx++) - if (iwl4965_rates[idx].plcp == (rate_n_flags & 0xFF)) + for (idx = 0; idx < ARRAY_SIZE(iwl_rates); idx++) + if (iwl_rates[idx].plcp == (rate_n_flags & 0xFF)) return idx; } @@ -1951,7 +1951,7 @@ void iwl4965_hw_build_tx_cmd_rate(struct iwl_priv *priv, u16 rate_flags = 0; int rate_idx = min(ctrl->tx_rate->hw_value & 0xffff, IWL_RATE_COUNT - 1); - rate_plcp = iwl4965_rates[rate_idx].plcp; + rate_plcp = iwl_rates[rate_idx].plcp; rts_retry_limit = (is_hcca) ? RTS_HCCA_RETRY_LIMIT : RTS_DFAULT_RETRY_LIMIT; @@ -2436,7 +2436,7 @@ static void iwl4965_add_radiotap(struct iwl_priv *priv, if (rate == -1) iwl4965_rt->rt_rate = 0; else - iwl4965_rt->rt_rate = iwl4965_rates[rate].ieee; + iwl4965_rt->rt_rate = iwl_rates[rate].ieee; /* * "antenna number" @@ -2848,7 +2848,7 @@ static void iwl4965_dbg_report_frame(struct iwl_priv *priv, if (unlikely(rate_idx == -1)) bitrate = 0; else - bitrate = iwl4965_rates[rate_idx].ieee / 2; + bitrate = iwl_rates[rate_idx].ieee / 2; /* print frame summary. * MAC addresses show just the last byte (for brevity), @@ -3473,7 +3473,7 @@ void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) rate_flags |= RATE_MCS_ANT_B_MSK; /*FIXME:RS*/ link_cmd.rs_table[i].rate_n_flags = - iwl4965_hw_set_rate_n_flags(iwl4965_rates[r].plcp, rate_flags); + iwl4965_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags); r = iwl4965_get_prev_ieee_rate(r); } diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index b800031ecca..8e411de9bda 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -67,7 +67,7 @@ MODULE_LICENSE("GPL"); * maps to IWL_RATE_INVALID * */ -const struct iwl4965_rate_info iwl4965_rates[IWL_RATE_COUNT] = { +const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = { IWL_DECLARE_RATE_INFO(1, INV, INV, 2, INV, 2, INV, 2), /* 1mbps */ IWL_DECLARE_RATE_INFO(2, INV, 1, 5, 1, 5, 1, 5), /* 2mbps */ IWL_DECLARE_RATE_INFO(5, INV, 2, 6, 2, 11, 2, 11), /*5.5mbps */ @@ -83,7 +83,7 @@ const struct iwl4965_rate_info iwl4965_rates[IWL_RATE_COUNT] = { IWL_DECLARE_RATE_INFO(60, 60, 48, INV, 48, INV, 48, INV),/* 60mbps */ /* FIXME:RS: ^^ should be INV (legacy) */ }; -EXPORT_SYMBOL(iwl4965_rates); +EXPORT_SYMBOL(iwl_rates); /* This function both allocates and initializes hw and priv. */ struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg, @@ -383,7 +383,7 @@ static void iwlcore_init_hw_rates(struct iwl_priv *priv, int i; for (i = 0; i < IWL_RATE_COUNT; i++) { - rates[i].bitrate = iwl4965_rates[i].ieee * 5; + rates[i].bitrate = iwl_rates[i].ieee * 5; rates[i].hw_value = i; /* Rate scaling will work on indexes */ rates[i].hw_value_short = i; rates[i].flags = 0; @@ -392,7 +392,7 @@ static void iwlcore_init_hw_rates(struct iwl_priv *priv, * If CCK != 1M then set short preamble rate flag. */ rates[i].flags |= - (iwl4965_rates[i].plcp == IWL_RATE_1M_PLCP) ? + (iwl_rates[i].plcp == IWL_RATE_1M_PLCP) ? 0 : IEEE80211_RATE_SHORT_PREAMBLE; } } diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 1c45b6f49d5..edde8142c13 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -878,9 +878,9 @@ static u8 iwl4965_rate_get_lowest_plcp(struct iwl_priv *priv) /* Find lowest valid rate */ for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID; - i = iwl4965_rates[i].next_ieee) { + i = iwl_rates[i].next_ieee) { if (rate_mask & (1 << i)) - return iwl4965_rates[i].plcp; + return iwl_rates[i].plcp; } /* No valid rate was found. Assign the lowest one */ @@ -939,7 +939,7 @@ static u16 iwl4965_supported_rate_to_ie(u8 *ie, u16 supported_rate, for (bit = 1, i = 0; i < IWL_RATE_COUNT; i++, bit <<= 1) { if (bit & supported_rate) { ret_rates |= bit; - rates[*cnt] = iwl4965_rates[i].ieee | + rates[*cnt] = iwl_rates[i].ieee | ((bit & basic_rate) ? 0x80 : 0x00); (*cnt)++; (*left)--; -- cgit v1.2.3-70-g09d2 From 57bd1bea485bf6f37ff365dec2203ba6467b41a1 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 15 May 2008 13:54:03 +0800 Subject: iwlwifi: move iwl_bcast_addr to iwlcore This patch renames iwl4965_broadcast_addr to iwl_bcast_addr and moves it to iwlcore. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 2 +- drivers/net/wireless/iwlwifi/iwl-core.c | 5 +++++ drivers/net/wireless/iwlwifi/iwl-dev.h | 2 +- drivers/net/wireless/iwlwifi/iwl4965-base.c | 11 +++++------ 4 files changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 1ec53a3848d..44215a7ab0a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2029,7 +2029,7 @@ unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, frame_size = iwl4965_fill_beacon_frame(priv, tx_beacon_cmd->frame, - iwl4965_broadcast_addr, + iwl_bcast_addr, sizeof(frame->u) - sizeof(*tx_beacon_cmd)); BUG_ON(frame_size > MAX_MPDU_SIZE); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 8e411de9bda..79e46c5a35a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -85,6 +85,11 @@ const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = { }; EXPORT_SYMBOL(iwl_rates); + +const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; +EXPORT_SYMBOL(iwl_bcast_addr); + + /* This function both allocates and initializes hw and priv. */ struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg, struct ieee80211_ops *hw_ops) diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 60a8f06225c..8809fe350b3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -659,7 +659,7 @@ int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src); int iwl4965_init_geos(struct iwl_priv *priv); void iwl4965_free_geos(struct iwl_priv *priv); -extern const u8 iwl4965_broadcast_addr[ETH_ALEN]; +extern const u8 iwl_bcast_addr[ETH_ALEN]; int iwl4965_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd); /* diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index edde8142c13..bb820f35d60 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -207,7 +207,6 @@ static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge) return index & (q->n_window - 1); } -const u8 iwl4965_broadcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; /*************** STATION TABLE MANAGEMENT **** * mac80211 should be examined to determine if sta_info is duplicating @@ -692,7 +691,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) } /* Add the broadcast address so we can send broadcast frames */ - if (iwl4965_rxon_add_station(priv, iwl4965_broadcast_addr, 0) == + if (iwl4965_rxon_add_station(priv, iwl_bcast_addr, 0) == IWL_INVALID_STATION) { IWL_ERROR("Error adding BROADCAST address for transmit.\n"); return -EIO; @@ -1059,9 +1058,9 @@ static u16 iwl4965_fill_probe_req(struct iwl_priv *priv, len += 24; frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); - memcpy(frame->da, iwl4965_broadcast_addr, ETH_ALEN); + memcpy(frame->da, iwl_bcast_addr, ETH_ALEN); memcpy(frame->sa, priv->mac_addr, ETH_ALEN); - memcpy(frame->bssid, iwl4965_broadcast_addr, ETH_ALEN); + memcpy(frame->bssid, iwl_bcast_addr, ETH_ALEN); frame->seq_ctrl = 0; /* fill in our indirect SSID IE */ @@ -4912,7 +4911,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv) /* clear out the station table */ iwlcore_clear_stations_table(priv); - iwl4965_rxon_add_station(priv, iwl4965_broadcast_addr, 0); + iwl4965_rxon_add_station(priv, iwl_bcast_addr, 0); iwl4965_rxon_add_station(priv, priv->bssid, 0); iwl4965_rate_scale_init(priv->hw, IWL_STA_ID); iwl4965_send_beacon_cmd(priv); @@ -5324,7 +5323,7 @@ static void iwl4965_config_ap(struct iwl_priv *priv) priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; iwl4965_commit_rxon(priv); iwl4965_activate_qos(priv, 1); - iwl4965_rxon_add_station(priv, iwl4965_broadcast_addr, 0); + iwl4965_rxon_add_station(priv, iwl_bcast_addr, 0); } iwl4965_send_beacon_cmd(priv); -- cgit v1.2.3-70-g09d2 From 4f40e4d9fb8fe028db9ba2a7b4d3ac7328f73bbc Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 15 May 2008 13:54:04 +0800 Subject: iwlwifi: move more station managment into iwl-sta.c This patch moves station management functions into iwl-sta.c (iwlcore). Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 4 +- drivers/net/wireless/iwlwifi/iwl-4965.c | 101 ----------- drivers/net/wireless/iwlwifi/iwl-dev.h | 8 +- drivers/net/wireless/iwlwifi/iwl-sta.c | 269 ++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-sta.h | 2 + drivers/net/wireless/iwlwifi/iwl4965-base.c | 178 +----------------- 6 files changed, 283 insertions(+), 279 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index e2123aba202..ce70f2b29b6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -2150,7 +2150,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_RATE("LQ: ADD station %s\n", print_mac(mac, hdr->addr1)); - sta_id = iwl4965_add_station_flags(priv, hdr->addr1, + sta_id = iwl_add_station_flags(priv, hdr->addr1, 0, CMD_ASYNC, NULL); } if ((sta_id != IWL_INVALID_STATION)) { @@ -2234,7 +2234,7 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_RATE("LQ: ADD station %s\n", print_mac(mac, sta->addr)); - sta_id = iwl4965_add_station_flags(priv, sta->addr, + sta_id = iwl_add_station_flags(priv, sta->addr, 0, CMD_ASYNC, NULL); } if ((sta_id != IWL_INVALID_STATION)) { diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 44215a7ab0a..aeaf5f78997 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -3433,109 +3433,8 @@ static int iwl4965_tx_queue_agg_enable(struct iwl_priv *priv, int txq_id, #endif /* CONFIG_IWL4965_HT */ -/** - * iwl4965_add_station - Initialize a station's hardware rate table - * - * The uCode's station table contains a table of fallback rates - * for automatic fallback during transmission. - * - * NOTE: This sets up a default set of values. These will be replaced later - * if the driver's iwl-4965-rs rate scaling algorithm is used, instead of - * rc80211_simple. - * - * NOTE: Run REPLY_ADD_STA command to set up station table entry, before - * calling this function (which runs REPLY_TX_LINK_QUALITY_CMD, - * which requires station table entry to exist). - */ -void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) -{ - int i, r; - struct iwl_link_quality_cmd link_cmd = { - .reserved1 = 0, - }; - u16 rate_flags; - - /* Set up the rate scaling to start at selected rate, fall back - * all the way down to 1M in IEEE order, and then spin on 1M */ - if (is_ap) - r = IWL_RATE_54M_INDEX; - else if (priv->band == IEEE80211_BAND_5GHZ) - r = IWL_RATE_6M_INDEX; - else - r = IWL_RATE_1M_INDEX; - - for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) { - rate_flags = 0; - if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE) - rate_flags |= RATE_MCS_CCK_MSK; - - /* Use Tx antenna B only */ - rate_flags |= RATE_MCS_ANT_B_MSK; /*FIXME:RS*/ - - link_cmd.rs_table[i].rate_n_flags = - iwl4965_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags); - r = iwl4965_get_prev_ieee_rate(r); - } - - link_cmd.general_params.single_stream_ant_msk = 2; - link_cmd.general_params.dual_stream_ant_msk = 3; - link_cmd.agg_params.agg_dis_start_th = 3; - link_cmd.agg_params.agg_time_limit = cpu_to_le16(4000); - - /* Update the rate scaling for control frame Tx to AP */ - link_cmd.sta_id = is_ap ? IWL_AP_ID : priv->hw_params.bcast_sta_id; - - iwl_send_cmd_pdu_async(priv, REPLY_TX_LINK_QUALITY_CMD, - sizeof(link_cmd), &link_cmd, NULL); -} #ifdef CONFIG_IWL4965_HT - -void iwl4965_set_ht_add_station(struct iwl_priv *priv, u8 index, - struct ieee80211_ht_info *sta_ht_inf) -{ - __le32 sta_flags; - u8 mimo_ps_mode; - - if (!sta_ht_inf || !sta_ht_inf->ht_supported) - goto done; - - mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2; - - sta_flags = priv->stations[index].sta.station_flags; - - sta_flags &= ~(STA_FLG_RTS_MIMO_PROT_MSK | STA_FLG_MIMO_DIS_MSK); - - switch (mimo_ps_mode) { - case WLAN_HT_CAP_MIMO_PS_STATIC: - sta_flags |= STA_FLG_MIMO_DIS_MSK; - break; - case WLAN_HT_CAP_MIMO_PS_DYNAMIC: - sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK; - break; - case WLAN_HT_CAP_MIMO_PS_DISABLED: - break; - default: - IWL_WARNING("Invalid MIMO PS mode %d", mimo_ps_mode); - break; - } - - sta_flags |= cpu_to_le32( - (u32)sta_ht_inf->ampdu_factor << STA_FLG_MAX_AGG_SIZE_POS); - - sta_flags |= cpu_to_le32( - (u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS); - - if (iwl_is_fat_tx_allowed(priv, sta_ht_inf)) - sta_flags |= STA_FLG_FAT_EN_MSK; - else - sta_flags &= ~STA_FLG_FAT_EN_MSK; - - priv->stations[index].sta.station_flags = sta_flags; - done: - return; -} - static int iwl4965_rx_agg_start(struct iwl_priv *priv, const u8 *addr, int tid, u16 ssn) { diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 8809fe350b3..565d7dc31a7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -635,8 +635,8 @@ struct iwl_hw_params { struct iwl_addsta_cmd; extern int iwl_send_add_sta(struct iwl_priv *priv, struct iwl_addsta_cmd *sta, u8 flags); -extern u8 iwl4965_add_station_flags(struct iwl_priv *priv, const u8 *addr, - int is_ap, u8 flags, void *ht_data); +u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, + u8 flags, struct ieee80211_ht_info *ht_info); extern int iwl4965_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header); extern int iwl4965_power_init_handle(struct iwl_priv *priv); @@ -731,8 +731,6 @@ extern void iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio); extern int iwl4965_tx_queue_update_wr_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq, u16 byte_cnt); -extern void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, - int is_ap); extern int iwl4965_alive_notify(struct iwl_priv *priv); extern void iwl4965_update_rate_scaling(struct iwl_priv *priv, u8 mode); extern void iwl4965_rf_kill_ct_config(struct iwl_priv *priv); @@ -746,8 +744,6 @@ extern void iwl4965_init_ht_hw_capab(const struct iwl_priv *priv, enum ieee80211_band band); void iwl4965_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info); -void iwl4965_set_ht_add_station(struct iwl_priv *priv, u8 index, - struct ieee80211_ht_info *sta_ht_inf); int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, enum ieee80211_ampdu_mlme_action action, const u8 *addr, u16 tid, u16 *ssn); diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index f2267047d10..c8e468fb3ca 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -117,6 +117,130 @@ int iwl_send_add_sta(struct iwl_priv *priv, } EXPORT_SYMBOL(iwl_send_add_sta); +#ifdef CONFIG_IWL4965_HT + +static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index, + struct ieee80211_ht_info *sta_ht_inf) +{ + __le32 sta_flags; + u8 mimo_ps_mode; + + if (!sta_ht_inf || !sta_ht_inf->ht_supported) + goto done; + + mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2; + + sta_flags = priv->stations[index].sta.station_flags; + + sta_flags &= ~(STA_FLG_RTS_MIMO_PROT_MSK | STA_FLG_MIMO_DIS_MSK); + + switch (mimo_ps_mode) { + case WLAN_HT_CAP_MIMO_PS_STATIC: + sta_flags |= STA_FLG_MIMO_DIS_MSK; + break; + case WLAN_HT_CAP_MIMO_PS_DYNAMIC: + sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK; + break; + case WLAN_HT_CAP_MIMO_PS_DISABLED: + break; + default: + IWL_WARNING("Invalid MIMO PS mode %d", mimo_ps_mode); + break; + } + + sta_flags |= cpu_to_le32( + (u32)sta_ht_inf->ampdu_factor << STA_FLG_MAX_AGG_SIZE_POS); + + sta_flags |= cpu_to_le32( + (u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS); + + if (iwl_is_fat_tx_allowed(priv, sta_ht_inf)) + sta_flags |= STA_FLG_FAT_EN_MSK; + else + sta_flags &= ~STA_FLG_FAT_EN_MSK; + + priv->stations[index].sta.station_flags = sta_flags; + done: + return; +} +#else +static inline void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index, + struct ieee80211_ht_info *sta_ht_info) +{ +} +#endif + +/** + * iwl_add_station_flags - Add station to tables in driver and device + */ +u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, + u8 flags, struct ieee80211_ht_info *ht_info) +{ + int i; + int index = IWL_INVALID_STATION; + struct iwl_station_entry *station; + unsigned long flags_spin; + DECLARE_MAC_BUF(mac); + + spin_lock_irqsave(&priv->sta_lock, flags_spin); + if (is_ap) + index = IWL_AP_ID; + else if (is_broadcast_ether_addr(addr)) + index = priv->hw_params.bcast_sta_id; + else + for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) { + if (!compare_ether_addr(priv->stations[i].sta.sta.addr, + addr)) { + index = i; + break; + } + + if (!priv->stations[i].used && + index == IWL_INVALID_STATION) + index = i; + } + + + /* These two conditions have the same outcome, but keep them separate + since they have different meanings */ + if (unlikely(index == IWL_INVALID_STATION)) { + spin_unlock_irqrestore(&priv->sta_lock, flags_spin); + return index; + } + + if (priv->stations[index].used && + !compare_ether_addr(priv->stations[index].sta.sta.addr, addr)) { + spin_unlock_irqrestore(&priv->sta_lock, flags_spin); + return index; + } + + + IWL_DEBUG_ASSOC("Add STA ID %d: %s\n", index, print_mac(mac, addr)); + station = &priv->stations[index]; + station->used = 1; + priv->num_stations++; + + /* Set up the REPLY_ADD_STA command to send to device */ + memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd)); + memcpy(station->sta.sta.addr, addr, ETH_ALEN); + station->sta.mode = 0; + station->sta.sta.sta_id = index; + station->sta.station_flags = 0; + + /* BCAST station and IBSS stations do not work in HT mode */ + if (index != priv->hw_params.bcast_sta_id && + priv->iw_mode != IEEE80211_IF_TYPE_IBSS) + iwl_set_ht_add_station(priv, index, ht_info); + + spin_unlock_irqrestore(&priv->sta_lock, flags_spin); + + /* Add station to device's station table */ + iwl_send_add_sta(priv, &station->sta, flags); + return index; + +} +EXPORT_SYMBOL(iwl_add_station_flags); + int iwl_get_free_ucode_key_index(struct iwl_priv *priv) { int i; @@ -470,3 +594,148 @@ int iwl_send_lq_cmd(struct iwl_priv *priv, } EXPORT_SYMBOL(iwl_send_lq_cmd); +/** + * iwl_sta_init_lq - Initialize a station's hardware rate table + * + * The uCode's station table contains a table of fallback rates + * for automatic fallback during transmission. + * + * NOTE: This sets up a default set of values. These will be replaced later + * if the driver's iwl-4965-rs rate scaling algorithm is used, instead of + * rc80211_simple. + * + * NOTE: Run REPLY_ADD_STA command to set up station table entry, before + * calling this function (which runs REPLY_TX_LINK_QUALITY_CMD, + * which requires station table entry to exist). + */ +static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap) +{ + int i, r; + struct iwl_link_quality_cmd link_cmd = { + .reserved1 = 0, + }; + u16 rate_flags; + + /* Set up the rate scaling to start at selected rate, fall back + * all the way down to 1M in IEEE order, and then spin on 1M */ + if (is_ap) + r = IWL_RATE_54M_INDEX; + else if (priv->band == IEEE80211_BAND_5GHZ) + r = IWL_RATE_6M_INDEX; + else + r = IWL_RATE_1M_INDEX; + + for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) { + rate_flags = 0; + if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE) + rate_flags |= RATE_MCS_CCK_MSK; + + /* Use Tx antenna B only */ + rate_flags |= RATE_MCS_ANT_B_MSK; /*FIXME:RS*/ + + link_cmd.rs_table[i].rate_n_flags = + iwl4965_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags); + r = iwl4965_get_prev_ieee_rate(r); + } + + link_cmd.general_params.single_stream_ant_msk = 2; + link_cmd.general_params.dual_stream_ant_msk = 3; + link_cmd.agg_params.agg_dis_start_th = 3; + link_cmd.agg_params.agg_time_limit = cpu_to_le16(4000); + + /* Update the rate scaling for control frame Tx to AP */ + link_cmd.sta_id = is_ap ? IWL_AP_ID : priv->hw_params.bcast_sta_id; + + iwl_send_cmd_pdu_async(priv, REPLY_TX_LINK_QUALITY_CMD, + sizeof(link_cmd), &link_cmd, NULL); +} +/** + * iwl_rxon_add_station - add station into station table. + * + * there is only one AP station with id= IWL_AP_ID + * NOTE: mutex must be held before calling this fnction + */ +int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) +{ + u8 sta_id; + + /* Add station to device's station table */ +#ifdef CONFIG_IWL4965_HT + struct ieee80211_conf *conf = &priv->hw->conf; + struct ieee80211_ht_info *cur_ht_config = &conf->ht_conf; + + if ((is_ap) && + (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) && + (priv->iw_mode == IEEE80211_IF_TYPE_STA)) + sta_id = iwl_add_station_flags(priv, addr, is_ap, + 0, cur_ht_config); + else +#endif /* CONFIG_IWL4965_HT */ + sta_id = iwl_add_station_flags(priv, addr, is_ap, + 0, NULL); + + /* Set up default rate scaling table in device's station table */ + iwl_sta_init_lq(priv, addr, is_ap); + + return sta_id; +} +EXPORT_SYMBOL(iwl_rxon_add_station); + + +/** + * iwl_get_sta_id - Find station's index within station table + * + * If new IBSS station, create new entry in station table + */ +int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) +{ + int sta_id; + u16 fc = le16_to_cpu(hdr->frame_control); + DECLARE_MAC_BUF(mac); + + /* If this frame is broadcast or management, use broadcast station id */ + if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) || + is_multicast_ether_addr(hdr->addr1)) + return priv->hw_params.bcast_sta_id; + + switch (priv->iw_mode) { + + /* If we are a client station in a BSS network, use the special + * AP station entry (that's the only station we communicate with) */ + case IEEE80211_IF_TYPE_STA: + return IWL_AP_ID; + + /* If we are an AP, then find the station, or use BCAST */ + case IEEE80211_IF_TYPE_AP: + sta_id = iwl_find_station(priv, hdr->addr1); + if (sta_id != IWL_INVALID_STATION) + return sta_id; + return priv->hw_params.bcast_sta_id; + + /* If this frame is going out to an IBSS network, find the station, + * or create a new station table entry */ + case IEEE80211_IF_TYPE_IBSS: + sta_id = iwl_find_station(priv, hdr->addr1); + if (sta_id != IWL_INVALID_STATION) + return sta_id; + + /* Create new station table entry */ + sta_id = iwl_add_station_flags(priv, hdr->addr1, + 0, CMD_ASYNC, NULL); + + if (sta_id != IWL_INVALID_STATION) + return sta_id; + + IWL_DEBUG_DROP("Station %s not in station map. " + "Defaulting to broadcast...\n", + print_mac(mac, hdr->addr1)); + iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); + return priv->hw_params.bcast_sta_id; + + default: + IWL_WARNING("Unknown mode of operation: %d", priv->iw_mode); + return priv->hw_params.bcast_sta_id; + } +} +EXPORT_SYMBOL(iwl_get_sta_id); + diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h index 38b1b0a9884..ee256430708 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.h +++ b/drivers/net/wireless/iwlwifi/iwl-sta.h @@ -39,4 +39,6 @@ int iwl_set_dynamic_key(struct iwl_priv *priv, struct ieee80211_key_conf *key, u8 sta_id); int iwl_remove_dynamic_key(struct iwl_priv *priv, struct ieee80211_key_conf *key, u8 sta_id); +int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap); +int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr); #endif /* __iwl_sta_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index bb820f35d60..88032ccc0ab 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -258,79 +258,6 @@ out: } #endif -/** - * iwl4965_add_station_flags - Add station to tables in driver and device - */ -u8 iwl4965_add_station_flags(struct iwl_priv *priv, const u8 *addr, - int is_ap, u8 flags, void *ht_data) -{ - int i; - int index = IWL_INVALID_STATION; - struct iwl_station_entry *station; - unsigned long flags_spin; - DECLARE_MAC_BUF(mac); - - spin_lock_irqsave(&priv->sta_lock, flags_spin); - if (is_ap) - index = IWL_AP_ID; - else if (is_broadcast_ether_addr(addr)) - index = priv->hw_params.bcast_sta_id; - else - for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) { - if (!compare_ether_addr(priv->stations[i].sta.sta.addr, - addr)) { - index = i; - break; - } - - if (!priv->stations[i].used && - index == IWL_INVALID_STATION) - index = i; - } - - - /* These two conditions have the same outcome, but keep them separate - since they have different meanings */ - if (unlikely(index == IWL_INVALID_STATION)) { - spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - return index; - } - - if (priv->stations[index].used && - !compare_ether_addr(priv->stations[index].sta.sta.addr, addr)) { - spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - return index; - } - - - IWL_DEBUG_ASSOC("Add STA ID %d: %s\n", index, print_mac(mac, addr)); - station = &priv->stations[index]; - station->used = 1; - priv->num_stations++; - - /* Set up the REPLY_ADD_STA command to send to device */ - memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd)); - memcpy(station->sta.sta.addr, addr, ETH_ALEN); - station->sta.mode = 0; - station->sta.sta.sta_id = index; - station->sta.station_flags = 0; - -#ifdef CONFIG_IWL4965_HT - /* BCAST station and IBSS stations do not work in HT mode */ - if (index != priv->hw_params.bcast_sta_id && - priv->iw_mode != IEEE80211_IF_TYPE_IBSS) - iwl4965_set_ht_add_station(priv, index, - (struct ieee80211_ht_info *) ht_data); -#endif /*CONFIG_IWL4965_HT*/ - - spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - - /* Add station to device's station table */ - iwl_send_add_sta(priv, &station->sta, flags); - return index; - -} - /*************** HOST COMMAND QUEUE FUNCTIONS *****/ @@ -433,38 +360,6 @@ static void iwl4965_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt) } -/** - * iwl4965_rxon_add_station - add station into station table. - * - * there is only one AP station with id= IWL_AP_ID - * NOTE: mutex must be held before calling this fnction - */ -static int iwl4965_rxon_add_station(struct iwl_priv *priv, - const u8 *addr, int is_ap) -{ - u8 sta_id; - - /* Add station to device's station table */ -#ifdef CONFIG_IWL4965_HT - struct ieee80211_conf *conf = &priv->hw->conf; - struct ieee80211_ht_info *cur_ht_config = &conf->ht_conf; - - if ((is_ap) && - (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) && - (priv->iw_mode == IEEE80211_IF_TYPE_STA)) - sta_id = iwl4965_add_station_flags(priv, addr, is_ap, - 0, cur_ht_config); - else -#endif /* CONFIG_IWL4965_HT */ - sta_id = iwl4965_add_station_flags(priv, addr, is_ap, - 0, NULL); - - /* Set up default rate scaling table in device's station table */ - iwl4965_add_station(priv, addr, is_ap); - - return sta_id; -} - /** * iwl4965_check_rxon_cmd - validate RXON structure is valid * @@ -691,7 +586,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) } /* Add the broadcast address so we can send broadcast frames */ - if (iwl4965_rxon_add_station(priv, iwl_bcast_addr, 0) == + if (iwl_rxon_add_station(priv, iwl_bcast_addr, 0) == IWL_INVALID_STATION) { IWL_ERROR("Error adding BROADCAST address for transmit.\n"); return -EIO; @@ -701,7 +596,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) * add the IWL_AP_ID to the station rate table */ if (iwl_is_associated(priv) && (priv->iw_mode == IEEE80211_IF_TYPE_STA)) { - if (iwl4965_rxon_add_station(priv, priv->active_rxon.bssid_addr, 1) + if (iwl_rxon_add_station(priv, priv->active_rxon.bssid_addr, 1) == IWL_INVALID_STATION) { IWL_ERROR("Error adding AP address for transmit.\n"); return -EIO; @@ -1702,63 +1597,6 @@ static void iwl_update_tx_stats(struct iwl_priv *priv, u16 fc, u16 len) priv->tx_stats[idx].cnt++; priv->tx_stats[idx].bytes += len; } -/** - * iwl4965_get_sta_id - Find station's index within station table - * - * If new IBSS station, create new entry in station table - */ -static int iwl4965_get_sta_id(struct iwl_priv *priv, - struct ieee80211_hdr *hdr) -{ - int sta_id; - u16 fc = le16_to_cpu(hdr->frame_control); - DECLARE_MAC_BUF(mac); - - /* If this frame is broadcast or management, use broadcast station id */ - if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) || - is_multicast_ether_addr(hdr->addr1)) - return priv->hw_params.bcast_sta_id; - - switch (priv->iw_mode) { - - /* If we are a client station in a BSS network, use the special - * AP station entry (that's the only station we communicate with) */ - case IEEE80211_IF_TYPE_STA: - return IWL_AP_ID; - - /* If we are an AP, then find the station, or use BCAST */ - case IEEE80211_IF_TYPE_AP: - sta_id = iwl_find_station(priv, hdr->addr1); - if (sta_id != IWL_INVALID_STATION) - return sta_id; - return priv->hw_params.bcast_sta_id; - - /* If this frame is going out to an IBSS network, find the station, - * or create a new station table entry */ - case IEEE80211_IF_TYPE_IBSS: - sta_id = iwl_find_station(priv, hdr->addr1); - if (sta_id != IWL_INVALID_STATION) - return sta_id; - - /* Create new station table entry */ - sta_id = iwl4965_add_station_flags(priv, hdr->addr1, - 0, CMD_ASYNC, NULL); - - if (sta_id != IWL_INVALID_STATION) - return sta_id; - - IWL_DEBUG_DROP("Station %s not in station map. " - "Defaulting to broadcast...\n", - print_mac(mac, hdr->addr1)); - iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); - return priv->hw_params.bcast_sta_id; - - default: - IWL_WARNING("Unknown mode of operation: %d", priv->iw_mode); - return priv->hw_params.bcast_sta_id; - } -} - /* * start REPLY_TX command process */ @@ -1829,7 +1667,7 @@ static int iwl4965_tx_skb(struct iwl_priv *priv, hdr_len = ieee80211_get_hdrlen(fc); /* Find (or create) index into station table for destination station */ - sta_id = iwl4965_get_sta_id(priv, hdr); + sta_id = iwl_get_sta_id(priv, hdr); if (sta_id == IWL_INVALID_STATION) { DECLARE_MAC_BUF(mac); @@ -3585,7 +3423,7 @@ static void iwl4965_error_recovery(struct iwl_priv *priv) priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; iwl4965_commit_rxon(priv); - iwl4965_rxon_add_station(priv, priv->bssid, 1); + iwl_rxon_add_station(priv, priv->bssid, 1); spin_lock_irqsave(&priv->lock, flags); priv->assoc_id = le16_to_cpu(priv->staging_rxon.assoc_id); @@ -4911,8 +4749,8 @@ static void iwl4965_post_associate(struct iwl_priv *priv) /* clear out the station table */ iwlcore_clear_stations_table(priv); - iwl4965_rxon_add_station(priv, iwl_bcast_addr, 0); - iwl4965_rxon_add_station(priv, priv->bssid, 0); + iwl_rxon_add_station(priv, iwl_bcast_addr, 0); + iwl_rxon_add_station(priv, priv->bssid, 0); iwl4965_rate_scale_init(priv->hw, IWL_STA_ID); iwl4965_send_beacon_cmd(priv); @@ -5323,7 +5161,7 @@ static void iwl4965_config_ap(struct iwl_priv *priv) priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; iwl4965_commit_rxon(priv); iwl4965_activate_qos(priv, 1); - iwl4965_rxon_add_station(priv, iwl_bcast_addr, 0); + iwl_rxon_add_station(priv, iwl_bcast_addr, 0); } iwl4965_send_beacon_cmd(priv); @@ -5412,7 +5250,7 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, else { rc = iwl4965_commit_rxon(priv); if ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && rc) - iwl4965_rxon_add_station( + iwl_rxon_add_station( priv, priv->active_rxon.bssid_addr, 1); } -- cgit v1.2.3-70-g09d2 From 83d527d9e8f9aff92cbd33f208f77c055dabb499 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 15 May 2008 13:54:05 +0800 Subject: iwlwifi: remove 4956 form iwl4965_tx_cmd This patch renames iwl4965_tx_cmd to iwl_tx_cmd and cleans collateral code. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 3 +-- drivers/net/wireless/iwlwifi/iwl-5000.c | 1 - drivers/net/wireless/iwlwifi/iwl-commands.h | 6 +++--- drivers/net/wireless/iwlwifi/iwl-dev.h | 4 +--- drivers/net/wireless/iwlwifi/iwl4965-base.c | 4 ++-- 5 files changed, 7 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index aeaf5f78997..02bbe04309a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -1053,7 +1053,6 @@ int iwl4965_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues; priv->hw_params.sw_crypto = priv->cfg->mod_params->sw_crypto; - priv->hw_params.tx_cmd_len = sizeof(struct iwl4965_tx_cmd); priv->hw_params.max_rxq_size = RX_QUEUE_SIZE; priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG; if (priv->cfg->mod_params->amsdu_size_8K) @@ -1943,7 +1942,7 @@ void iwl4965_hw_build_tx_cmd_rate(struct iwl_priv *priv, struct ieee80211_hdr *hdr, int sta_id, int is_hcca) { - struct iwl4965_tx_cmd *tx = &cmd->cmd.tx; + struct iwl_tx_cmd *tx = &cmd->cmd.tx; u8 rts_retry_limit = 0; u8 data_retry_limit = 0; u16 fc = le16_to_cpu(hdr->frame_control); diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 72d655c59fb..d155247d246 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -298,7 +298,6 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues; priv->hw_params.sw_crypto = priv->cfg->mod_params->sw_crypto; - priv->hw_params.tx_cmd_len = sizeof(struct iwl4965_tx_cmd); priv->hw_params.max_rxq_size = RX_QUEUE_SIZE; priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG; if (priv->cfg->mod_params->amsdu_size_8K) diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 350af1be6e3..dd84326c97d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -1196,7 +1196,7 @@ struct iwl4965_dram_scratch { /* * REPLY_TX = 0x1c (command) */ -struct iwl4965_tx_cmd { +struct iwl_tx_cmd { /* * MPDU byte count: * MAC header (24/26/30/32 bytes) + 2 bytes pad if 26/30 header size, @@ -2135,7 +2135,7 @@ struct iwl4965_scan_cmd { /* For active scans (set to all-0s for passive scans). * Does not include payload. Must specify Tx rate; no rate scaling. */ - struct iwl4965_tx_cmd tx_cmd; + struct iwl_tx_cmd tx_cmd; /* For directed active scans (set to all-0s otherwise) */ struct iwl4965_ssid_ie direct_scan[PROBE_OPTION_MAX]; @@ -2232,7 +2232,7 @@ struct iwl4965_beacon_notif { * REPLY_TX_BEACON = 0x91 (command, has simple generic response) */ struct iwl4965_tx_beacon_cmd { - struct iwl4965_tx_cmd tx; + struct iwl_tx_cmd tx; __le16 tim_idx; u8 tim_size; u8 reserved1; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 565d7dc31a7..ddb950ee25b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -329,7 +329,7 @@ struct iwl_cmd { struct iwl4965_rxon_time_cmd rxon_time; struct iwl4965_powertable_cmd powertable; struct iwl4965_qosparam_cmd qosparam; - struct iwl4965_tx_cmd tx; + struct iwl_tx_cmd tx; struct iwl4965_tx_beacon_cmd tx_beacon; struct iwl4965_rxon_assoc_cmd rxon_assoc; u8 *indirect; @@ -573,7 +573,6 @@ struct iwl_sensitivity_ranges { /** * struct iwl_hw_params * @max_txq_num: Max # Tx queues supported - * @tx_cmd_len: Size of Tx command (but not including frame itself) * @tx/rx_chains_num: Number of TX/RX chains * @valid_tx/rx_ant: usable antennas * @max_rxq_size: Max # Rx frames in Rx queue (must be power-of-2) @@ -590,7 +589,6 @@ struct iwl_sensitivity_ranges { */ struct iwl_hw_params { u16 max_txq_num; - u16 tx_cmd_len; u8 tx_chains_num; u8 rx_chains_num; u8 valid_tx_ant; diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 88032ccc0ab..6d5b58f88aa 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -1740,7 +1740,7 @@ static int iwl4965_tx_skb(struct iwl_priv *priv, * of the MAC header (device reads on dword boundaries). * We'll tell device about this padding later. */ - len = priv->hw_params.tx_cmd_len + + len = sizeof(struct iwl_tx_cmd) + sizeof(struct iwl_cmd_header) + hdr_len; len_org = len; @@ -1789,7 +1789,7 @@ static int iwl4965_tx_skb(struct iwl_priv *priv, iwl_update_tx_stats(priv, fc, len); scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) + - offsetof(struct iwl4965_tx_cmd, scratch); + offsetof(struct iwl_tx_cmd, scratch); out_cmd->cmd.tx.dram_lsb_ptr = cpu_to_le32(scratch_phys); out_cmd->cmd.tx.dram_msb_ptr = iwl_get_dma_hi_address(scratch_phys); -- cgit v1.2.3-70-g09d2 From 54dbb525e7b8580b86af352cf60b27cc889c2ae4 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 15 May 2008 13:54:06 +0800 Subject: iwlwifi: refactor ieee80211_get_qos_ctrl This patch refactors ieee80211_get_qos_ctrl function and its usage in iwlwifi drivers. Function is moved as inline into iwl-helpers.h. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 17 +++++----- drivers/net/wireless/iwlwifi/iwl-dev.h | 1 - drivers/net/wireless/iwlwifi/iwl-helpers.h | 19 +++++++++++ drivers/net/wireless/iwlwifi/iwl3945-base.c | 35 ++++++++------------ drivers/net/wireless/iwlwifi/iwl4965-base.c | 51 +++++++++++++---------------- 5 files changed, 63 insertions(+), 60 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index ce70f2b29b6..071c7b6ebef 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -282,14 +282,20 @@ static void rs_tl_rm_old_stats(struct iwl4965_traffic_load *tl, u32 curr_time) * increment traffic load value for tid and also remove * any old values if passed the certain time period */ -static void rs_tl_add_packet(struct iwl4965_lq_sta *lq_data, u8 tid) +static void rs_tl_add_packet(struct iwl4965_lq_sta *lq_data, + struct ieee80211_hdr *hdr) { u32 curr_time = jiffies_to_msecs(jiffies); u32 time_diff; s32 index; struct iwl4965_traffic_load *tl = NULL; + u16 fc = le16_to_cpu(hdr->frame_control); + u8 tid; - if (tid >= TID_MAX_LOAD_COUNT) + if (ieee80211_is_qos_data(fc)) { + u8 *qc = ieee80211_get_qos_ctrl(hdr, ieee80211_get_hdrlen(fc)); + tid = qc[0] & 0xf; + } else return; tl = &lq_data->load[tid]; @@ -1670,7 +1676,6 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, u16 high_low; #ifdef CONFIG_IWL4965_HT u8 tid = MAX_TID_COUNT; - __le16 *qc; #endif IWL_DEBUG_RATE("rate scale calculate new rate for skb\n"); @@ -1693,11 +1698,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv; #ifdef CONFIG_IWL4965_HT - qc = ieee80211_get_qos_ctrl(hdr); - if (qc) { - tid = (u8)(le16_to_cpu(*qc) & 0xf); - rs_tl_add_packet(lq_sta, tid); - } + rs_tl_add_packet(lq_sta, hdr); #endif /* * Select rate-scale / modulation-mode table to work with in diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index ddb950ee25b..7bd99f942f1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -650,7 +650,6 @@ extern int iwl4965_calc_sig_qual(int rssi_dbm, int noise_dbm); extern unsigned int iwl4965_fill_beacon_frame(struct iwl_priv *priv, struct ieee80211_hdr *hdr, const u8 *dest, int left); -extern __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr); extern void iwl4965_update_chain_flags(struct iwl_priv *priv); int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src); diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h index a443472bea6..e4c3f84f530 100644 --- a/drivers/net/wireless/iwlwifi/iwl-helpers.h +++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h @@ -235,6 +235,25 @@ static inline int ieee80211_is_reassoc_response(u16 fc) ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_RESP); } +static inline int ieee80211_is_qos_data(u16 fc) +{ + return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_QOS_DATA); +} +/** + * ieee80211_get_qos_ctrl - get pointer to the QoS control field + * + * This function returns the pointer to 802.11 header QoS field (2 bytes) + * This function doesn't check whether hdr is a QoS hdr, use with care + * @hdr: struct ieee80211_hdr *hdr + * @hdr_len: header length + */ + +static inline u8 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr, int hdr_len) +{ + return ((u8 *) hdr + hdr_len - QOS_CONTROL_LEN); +} + static inline int iwl_check_bits(unsigned long field, unsigned long mask) { return ((field & mask) == mask) ? 1 : 0; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index c1234ff4fc9..b8fb8d8d95f 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -102,16 +102,6 @@ MODULE_VERSION(DRV_VERSION); MODULE_AUTHOR(DRV_COPYRIGHT); MODULE_LICENSE("GPL"); -static __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr) -{ - u16 fc = le16_to_cpu(hdr->frame_control); - int hdr_len = ieee80211_get_hdrlen(fc); - - if ((fc & 0x00cc) == (IEEE80211_STYPE_QOS_DATA | IEEE80211_FTYPE_DATA)) - return (__le16 *) ((u8 *) hdr + hdr_len - QOS_CONTROL_LEN); - return NULL; -} - static const struct ieee80211_supported_band *iwl3945_get_band( struct iwl3945_priv *priv, enum ieee80211_band band) { @@ -2441,7 +2431,6 @@ static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv, struct ieee80211_hdr *hdr, int is_unicast, u8 std_id) { - __le16 *qc; u16 fc = le16_to_cpu(hdr->frame_control); __le32 tx_flags = cmd->cmd.tx.tx_flags; @@ -2462,12 +2451,13 @@ static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv, if (ieee80211_get_morefrag(hdr)) tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK; - qc = ieee80211_get_qos_ctrl(hdr); - if (qc) { - cmd->cmd.tx.tid_tspec = (u8) (le16_to_cpu(*qc) & 0xf); + if (ieee80211_is_qos_data(fc)) { + u8 *qc = ieee80211_get_qos_ctrl(hdr, ieee80211_get_hdrlen(fc)); + cmd->cmd.tx.tid_tspec = qc[0] & 0xf; tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK; - } else + } else { tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; + } if (ctrl->flags & IEEE80211_TXCTL_USE_RTS_CTS) { tx_flags |= TX_CMD_FLG_RTS_MSK; @@ -2568,13 +2558,15 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, dma_addr_t phys_addr; dma_addr_t txcmd_phys; struct iwl3945_cmd *out_cmd = NULL; - u16 len, idx, len_org; - u8 id, hdr_len, unicast; + u16 len, idx, len_org, hdr_len; + u8 id; + u8 unicast; u8 sta_id; + u8 tid = 0; u16 seq_number = 0; u16 fc; - __le16 *qc; u8 wait_write_ptr = 0; + u8 *qc = NULL; unsigned long flags; int rc; @@ -2632,9 +2624,9 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, IWL_DEBUG_RATE("station Id %d\n", sta_id); - qc = ieee80211_get_qos_ctrl(hdr); - if (qc) { - u8 tid = (u8)(le16_to_cpu(*qc) & 0xf); + if (ieee80211_is_qos_data(fc)) { + qc = ieee80211_get_qos_ctrl(hdr, hdr_len); + tid = qc[0] & 0xf; seq_number = priv->stations[sta_id].tid[tid].seq_number & IEEE80211_SCTL_SEQ; hdr->seq_ctrl = cpu_to_le16(seq_number) | @@ -2745,7 +2737,6 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, if (!ieee80211_get_morefrag(hdr)) { txq->need_update = 1; if (qc) { - u8 tid = (u8)(le16_to_cpu(*qc) & 0xf); priv->stations[sta_id].tid[tid].seq_number = seq_number; } } else { diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 6d5b58f88aa..e3f872e3381 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -89,16 +89,6 @@ MODULE_VERSION(DRV_VERSION); MODULE_AUTHOR(DRV_COPYRIGHT); MODULE_LICENSE("GPL"); -__le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr) -{ - u16 fc = le16_to_cpu(hdr->frame_control); - int hdr_len = ieee80211_get_hdrlen(fc); - - if ((fc & 0x00cc) == (IEEE80211_STYPE_QOS_DATA | IEEE80211_FTYPE_DATA)) - return (__le16 *) ((u8 *) hdr + hdr_len - QOS_CONTROL_LEN); - return NULL; -} - static const struct ieee80211_supported_band *iwl_get_hw_mode( struct iwl_priv *priv, enum ieee80211_band band) { @@ -1532,7 +1522,6 @@ static void iwl4965_build_tx_cmd_basic(struct iwl_priv *priv, struct ieee80211_hdr *hdr, int is_unicast, u8 std_id) { - __le16 *qc; u16 fc = le16_to_cpu(hdr->frame_control); __le32 tx_flags = cmd->cmd.tx.tx_flags; @@ -1557,12 +1546,13 @@ static void iwl4965_build_tx_cmd_basic(struct iwl_priv *priv, if (ieee80211_get_morefrag(hdr)) tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK; - qc = ieee80211_get_qos_ctrl(hdr); - if (qc) { - cmd->cmd.tx.tid_tspec = (u8) (le16_to_cpu(*qc) & 0xf); + if (ieee80211_is_qos_data(fc)) { + u8 *qc = ieee80211_get_qos_ctrl(hdr, ieee80211_get_hdrlen(fc)); + cmd->cmd.tx.tid_tspec = qc[0] & 0xf; tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK; - } else + } else { tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; + } if (ctrl->flags & IEEE80211_TXCTL_USE_RTS_CTS) { tx_flags |= TX_CMD_FLG_RTS_MSK; @@ -1614,12 +1604,15 @@ static int iwl4965_tx_skb(struct iwl_priv *priv, dma_addr_t scratch_phys; struct iwl_cmd *out_cmd = NULL; u16 len, idx, len_org; - u8 id, hdr_len, unicast; + u8 hdr_len; + u8 id; + u8 unicast; u8 sta_id; + u8 tid = 0; + u8 wait_write_ptr = 0; u16 seq_number = 0; u16 fc; - __le16 *qc; - u8 wait_write_ptr = 0; + u8 *qc = NULL; unsigned long flags; int rc; @@ -1678,9 +1671,9 @@ static int iwl4965_tx_skb(struct iwl_priv *priv, IWL_DEBUG_TX("station Id %d\n", sta_id); - qc = ieee80211_get_qos_ctrl(hdr); - if (qc) { - u8 tid = (u8)(le16_to_cpu(*qc) & 0xf); + if (ieee80211_is_qos_data(fc)) { + qc = ieee80211_get_qos_ctrl(hdr, hdr_len); + tid = qc[0] & 0xf; seq_number = priv->stations[sta_id].tid[tid].seq_number & IEEE80211_SCTL_SEQ; hdr->seq_ctrl = cpu_to_le16(seq_number) | @@ -1795,10 +1788,8 @@ static int iwl4965_tx_skb(struct iwl_priv *priv, if (!ieee80211_get_morefrag(hdr)) { txq->need_update = 1; - if (qc) { - u8 tid = (u8)(le16_to_cpu(*qc) & 0xf); + if (qc) priv->stations[sta_id].tid[tid].seq_number = seq_number; - } } else { wait_write_ptr = 1; txq->need_update = 0; @@ -2377,8 +2368,9 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, u32 status = le32_to_cpu(tx_resp->status); #ifdef CONFIG_IWL4965_HT int tid = MAX_TID_COUNT, sta_id = IWL_INVALID_STATION; + u16 fc; struct ieee80211_hdr *hdr; - __le16 *qc; + u8 *qc = NULL; #endif if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) { @@ -2391,10 +2383,11 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, #ifdef CONFIG_IWL4965_HT hdr = iwl4965_tx_queue_get_hdr(priv, txq_id, index); - qc = ieee80211_get_qos_ctrl(hdr); - - if (qc) - tid = le16_to_cpu(*qc) & 0xf; + fc = le16_to_cpu(hdr->frame_control); + if (ieee80211_is_qos_data(fc)) { + qc = ieee80211_get_qos_ctrl(hdr, ieee80211_get_hdrlen(fc)); + tid = qc[0] & 0xf; + } sta_id = iwl4965_get_ra_sta_id(priv, hdr); if (txq->sched_retry && unlikely(sta_id == IWL_INVALID_STATION)) { -- cgit v1.2.3-70-g09d2 From fd4abac54a7a7f1c0acad5ddc1fbf4af22f92569 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 15 May 2008 13:54:07 +0800 Subject: iwlwifi: move TX code into iwl-tx.c This patch moves the sending part of the TX code into iwl-tx.c including sending host commands. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 105 ----- drivers/net/wireless/iwlwifi/iwl-core.h | 9 +- drivers/net/wireless/iwlwifi/iwl-dev.h | 21 +- drivers/net/wireless/iwlwifi/iwl-hcmd.c | 4 +- drivers/net/wireless/iwlwifi/iwl-tx.c | 662 ++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl4965-base.c | 581 +----------------------- 6 files changed, 691 insertions(+), 691 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 02bbe04309a..8f0852d058e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -1933,76 +1933,6 @@ int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) return rc; } -#define RTS_HCCA_RETRY_LIMIT 3 -#define RTS_DFAULT_RETRY_LIMIT 60 - -void iwl4965_hw_build_tx_cmd_rate(struct iwl_priv *priv, - struct iwl_cmd *cmd, - struct ieee80211_tx_control *ctrl, - struct ieee80211_hdr *hdr, int sta_id, - int is_hcca) -{ - struct iwl_tx_cmd *tx = &cmd->cmd.tx; - u8 rts_retry_limit = 0; - u8 data_retry_limit = 0; - u16 fc = le16_to_cpu(hdr->frame_control); - u8 rate_plcp; - u16 rate_flags = 0; - int rate_idx = min(ctrl->tx_rate->hw_value & 0xffff, IWL_RATE_COUNT - 1); - - rate_plcp = iwl_rates[rate_idx].plcp; - - rts_retry_limit = (is_hcca) ? - RTS_HCCA_RETRY_LIMIT : RTS_DFAULT_RETRY_LIMIT; - - if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE)) - rate_flags |= RATE_MCS_CCK_MSK; - - - if (ieee80211_is_probe_response(fc)) { - data_retry_limit = 3; - if (data_retry_limit < rts_retry_limit) - rts_retry_limit = data_retry_limit; - } else - data_retry_limit = IWL_DEFAULT_TX_RETRY; - - if (priv->data_retry_limit != -1) - data_retry_limit = priv->data_retry_limit; - - - if (ieee80211_is_data(fc)) { - tx->initial_rate_index = 0; - tx->tx_flags |= TX_CMD_FLG_STA_RATE_MSK; - } else { - switch (fc & IEEE80211_FCTL_STYPE) { - case IEEE80211_STYPE_AUTH: - case IEEE80211_STYPE_DEAUTH: - case IEEE80211_STYPE_ASSOC_REQ: - case IEEE80211_STYPE_REASSOC_REQ: - if (tx->tx_flags & TX_CMD_FLG_RTS_MSK) { - tx->tx_flags &= ~TX_CMD_FLG_RTS_MSK; - tx->tx_flags |= TX_CMD_FLG_CTS_MSK; - } - break; - default: - break; - } - - /* Alternate between antenna A and B for successive frames */ - if (priv->use_ant_b_for_management_frame) { - priv->use_ant_b_for_management_frame = 0; - rate_flags |= RATE_MCS_ANT_B_MSK; - } else { - priv->use_ant_b_for_management_frame = 1; - rate_flags |= RATE_MCS_ANT_A_MSK; - } - } - - tx->rts_retry_limit = rts_retry_limit; - tx->data_retry_limit = data_retry_limit; - tx->rate_n_flags = iwl4965_hw_set_rate_n_flags(rate_plcp, rate_flags); -} - static int iwl4965_shared_mem_rx_idx(struct iwl_priv *priv) { struct iwl4965_shared *s = priv->shared_virt; @@ -2046,40 +1976,6 @@ unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, return (sizeof(*tx_beacon_cmd) + frame_size); } -int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr, - dma_addr_t addr, u16 len) -{ - int index, is_odd; - struct iwl_tfd_frame *tfd = ptr; - u32 num_tbs = IWL_GET_BITS(*tfd, num_tbs); - - /* Each TFD can point to a maximum 20 Tx buffers */ - if ((num_tbs >= MAX_NUM_OF_TBS) || (num_tbs < 0)) { - IWL_ERROR("Error can not send more than %d chunks\n", - MAX_NUM_OF_TBS); - return -EINVAL; - } - - index = num_tbs / 2; - is_odd = num_tbs & 0x1; - - if (!is_odd) { - tfd->pa[index].tb1_addr = cpu_to_le32(addr); - IWL_SET_BITS(tfd->pa[index], tb1_addr_hi, - iwl_get_dma_hi_address(addr)); - IWL_SET_BITS(tfd->pa[index], tb1_len, len); - } else { - IWL_SET_BITS(tfd->pa[index], tb2_addr_lo16, - (u32) (addr & 0xffff)); - IWL_SET_BITS(tfd->pa[index], tb2_addr_hi20, addr >> 16); - IWL_SET_BITS(tfd->pa[index], tb2_len, len); - } - - IWL_SET_BITS(*tfd, num_tbs, num_tbs + 1); - - return 0; -} - static int iwl4965_alloc_shared_mem(struct iwl_priv *priv) { priv->shared_virt = pci_alloc_consistent(priv->pci_dev, @@ -3711,7 +3607,6 @@ static struct iwl_hcmd_ops iwl4965_hcmd = { static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = { .get_hcmd_size = iwl4965_get_hcmd_size, - .enqueue_hcmd = iwl4965_enqueue_hcmd, .build_addsta_hcmd = iwl4965_build_addsta_hcmd, #ifdef CONFIG_IWL4965_RUN_TIME_CALIB .chain_noise_reset = iwl4965_chain_noise_reset, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index dcf1e562af3..b159fd3c93c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -87,7 +87,6 @@ struct iwl_hcmd_ops { }; struct iwl_hcmd_utils_ops { u16 (*get_hcmd_size)(u8 cmd_id, u16 len); - int (*enqueue_hcmd)(struct iwl_priv *priv, struct iwl_host_cmd *cmd); u16 (*build_addsta_hcmd)(const struct iwl_addsta_cmd *cmd, u8 *data); #ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB void (*gain_computation)(struct iwl_priv *priv, @@ -208,10 +207,14 @@ void iwl_rx_allocate(struct iwl_priv *priv); * TX ******************************************************/ int iwl_txq_ctx_reset(struct iwl_priv *priv); +int iwl_tx_skb(struct iwl_priv *priv, + struct sk_buff *skb, struct ieee80211_tx_control *ctl); /* FIXME: remove when free Tx is fully merged into iwlcore */ int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq); void iwl_hw_txq_ctx_free(struct iwl_priv *priv); - +int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *tfd, + dma_addr_t addr, u16 len); +int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq); /***************************************************** * S e n d i n g H o s t C o m m a n d s * *****************************************************/ @@ -227,6 +230,8 @@ int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len, int (*callback)(struct iwl_priv *priv, struct iwl_cmd *cmd, struct sk_buff *skb)); + +int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd); /*************** DRIVER STATUS FUNCTIONS *****/ #define STATUS_HCMD_ACTIVE 0 /* host command in progress */ diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 7bd99f942f1..4106efd194e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -689,8 +689,6 @@ extern int iwl4965_hw_set_hw_params(struct iwl_priv *priv); extern int iwl4965_hw_nic_stop_master(struct iwl_priv *priv); extern void iwl4965_hw_txq_ctx_stop(struct iwl_priv *priv); extern int iwl4965_hw_nic_reset(struct iwl_priv *priv); -extern int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *tfd, - dma_addr_t addr, u16 len); extern int iwl4965_hw_get_temperature(struct iwl_priv *priv); extern unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, struct iwl_frame *frame, u8 rate); @@ -719,6 +717,25 @@ extern u8 iwl_find_station(struct iwl_priv *priv, const u8 *bssid); extern int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel); extern int iwl4965_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index); extern int iwl_queue_space(const struct iwl_queue *q); +static inline int iwl_queue_used(const struct iwl_queue *q, int i) +{ + return q->write_ptr > q->read_ptr ? + (i >= q->read_ptr && i < q->write_ptr) : + !(i < q->read_ptr && i >= q->write_ptr); +} + + +static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge) +{ + /* This is for scan command, the big buffer at end of command array */ + if (is_huge) + return q->n_window; /* must be power of 2 */ + + /* Otherwise, use normal size buffers */ + return index & (q->n_window - 1); +} + + struct iwl_priv; extern void iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio); diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index 0412adf6ef8..dab4a0eff96 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -139,7 +139,7 @@ static int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd) if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return -EBUSY; - ret = priv->cfg->ops->utils->enqueue_hcmd(priv, cmd); + ret = iwl_enqueue_hcmd(priv, cmd); if (ret < 0) { IWL_ERROR("Error sending %s: enqueue_hcmd failed: %d\n", get_cmd_string(cmd->id), ret); @@ -170,7 +170,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) if (cmd->meta.flags & CMD_WANT_SKB) cmd->meta.source = &cmd->meta; - cmd_idx = priv->cfg->ops->utils->enqueue_hcmd(priv, cmd); + cmd_idx = iwl_enqueue_hcmd(priv, cmd); if (cmd_idx < 0) { ret = cmd_idx; IWL_ERROR("Error sending %s: enqueue_hcmd failed: %d\n", diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 870d257bded..a37ced58c66 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -27,6 +27,7 @@ * *****************************************************************************/ +#include #include #include "iwl-eeprom.h" #include "iwl-dev.h" @@ -95,6 +96,89 @@ int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) } EXPORT_SYMBOL(iwl_hw_txq_free_tfd); + +int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr, + dma_addr_t addr, u16 len) +{ + int index, is_odd; + struct iwl_tfd_frame *tfd = ptr; + u32 num_tbs = IWL_GET_BITS(*tfd, num_tbs); + + /* Each TFD can point to a maximum 20 Tx buffers */ + if ((num_tbs >= MAX_NUM_OF_TBS) || (num_tbs < 0)) { + IWL_ERROR("Error can not send more than %d chunks\n", + MAX_NUM_OF_TBS); + return -EINVAL; + } + + index = num_tbs / 2; + is_odd = num_tbs & 0x1; + + if (!is_odd) { + tfd->pa[index].tb1_addr = cpu_to_le32(addr); + IWL_SET_BITS(tfd->pa[index], tb1_addr_hi, + iwl_get_dma_hi_address(addr)); + IWL_SET_BITS(tfd->pa[index], tb1_len, len); + } else { + IWL_SET_BITS(tfd->pa[index], tb2_addr_lo16, + (u32) (addr & 0xffff)); + IWL_SET_BITS(tfd->pa[index], tb2_addr_hi20, addr >> 16); + IWL_SET_BITS(tfd->pa[index], tb2_len, len); + } + + IWL_SET_BITS(*tfd, num_tbs, num_tbs + 1); + + return 0; +} +EXPORT_SYMBOL(iwl_hw_txq_attach_buf_to_tfd); + +/** + * iwl_txq_update_write_ptr - Send new write index to hardware + */ +int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq) +{ + u32 reg = 0; + int ret = 0; + int txq_id = txq->q.id; + + if (txq->need_update == 0) + return ret; + + /* if we're trying to save power */ + if (test_bit(STATUS_POWER_PMI, &priv->status)) { + /* wake up nic if it's powered down ... + * uCode will wake up, and interrupt us again, so next + * time we'll skip this part. */ + reg = iwl_read32(priv, CSR_UCODE_DRV_GP1); + + if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { + IWL_DEBUG_INFO("Requesting wakeup, GP1 = 0x%x\n", reg); + iwl_set_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + return ret; + } + + /* restore this queue's parameters in nic hardware. */ + ret = iwl_grab_nic_access(priv); + if (ret) + return ret; + iwl_write_direct32(priv, HBUS_TARG_WRPTR, + txq->q.write_ptr | (txq_id << 8)); + iwl_release_nic_access(priv); + + /* else not in power-save mode, uCode will never sleep when we're + * trying to tx (during RFKILL, we're not trying to tx). */ + } else + iwl_write32(priv, HBUS_TARG_WRPTR, + txq->q.write_ptr | (txq_id << 8)); + + txq->need_update = 0; + + return ret; +} +EXPORT_SYMBOL(iwl_txq_update_write_ptr); + + /** * iwl_tx_queue_free - Deallocate DMA queue. * @txq: Transmit queue to deallocate. @@ -137,6 +221,47 @@ static void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq) memset(txq, 0, sizeof(*txq)); } +/*************** DMA-QUEUE-GENERAL-FUNCTIONS ***** + * DMA services + * + * Theory of operation + * + * A Tx or Rx queue resides in host DRAM, and is comprised of a circular buffer + * of buffer descriptors, each of which points to one or more data buffers for + * the device to read from or fill. Driver and device exchange status of each + * queue via "read" and "write" pointers. Driver keeps minimum of 2 empty + * entries in each circular buffer, to protect against confusing empty and full + * queue states. + * + * The device reads or writes the data in the queues via the device's several + * DMA/FIFO channels. Each queue is mapped to a single DMA channel. + * + * For Tx queue, there are low mark and high mark limits. If, after queuing + * the packet for Tx, free space become < low mark, Tx queue stopped. When + * reclaiming packets (on 'tx done IRQ), if free space become > high mark, + * Tx queue resumed. + * + * See more detailed info in iwl-4965-hw.h. + ***************************************************/ + +int iwl_queue_space(const struct iwl_queue *q) +{ + int s = q->read_ptr - q->write_ptr; + + if (q->read_ptr > q->write_ptr) + s -= q->n_bd; + + if (s <= 0) + s += q->n_window; + /* keep some reserve to not confuse empty and full situations */ + s -= 2; + if (s < 0) + s = 0; + return s; +} +EXPORT_SYMBOL(iwl_queue_space); + + /** * iwl_hw_txq_ctx_free - Free TXQ Context * @@ -371,3 +496,540 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv) error_kw: return ret; } + +/* + * handle build REPLY_TX command notification. + */ +static void iwl_tx_cmd_build_basic(struct iwl_priv *priv, + struct iwl_tx_cmd *tx_cmd, + struct ieee80211_tx_control *ctrl, + struct ieee80211_hdr *hdr, + int is_unicast, u8 std_id) +{ + u16 fc = le16_to_cpu(hdr->frame_control); + __le32 tx_flags = tx_cmd->tx_flags; + + tx_cmd->stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; + if (!(ctrl->flags & IEEE80211_TXCTL_NO_ACK)) { + tx_flags |= TX_CMD_FLG_ACK_MSK; + if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) + tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; + if (ieee80211_is_probe_response(fc) && + !(le16_to_cpu(hdr->seq_ctrl) & 0xf)) + tx_flags |= TX_CMD_FLG_TSF_MSK; + } else { + tx_flags &= (~TX_CMD_FLG_ACK_MSK); + tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; + } + + if (ieee80211_is_back_request(fc)) + tx_flags |= TX_CMD_FLG_ACK_MSK | TX_CMD_FLG_IMM_BA_RSP_MASK; + + + tx_cmd->sta_id = std_id; + if (ieee80211_get_morefrag(hdr)) + tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK; + + if (ieee80211_is_qos_data(fc)) { + u8 *qc = ieee80211_get_qos_ctrl(hdr, ieee80211_get_hdrlen(fc)); + 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 (ctrl->flags & IEEE80211_TXCTL_USE_RTS_CTS) { + tx_flags |= TX_CMD_FLG_RTS_MSK; + tx_flags &= ~TX_CMD_FLG_CTS_MSK; + } else if (ctrl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { + tx_flags &= ~TX_CMD_FLG_RTS_MSK; + tx_flags |= TX_CMD_FLG_CTS_MSK; + } + + if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK)) + tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK; + + tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK); + if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) { + if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ || + (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ) + tx_cmd->timeout.pm_frame_timeout = cpu_to_le16(3); + else + tx_cmd->timeout.pm_frame_timeout = cpu_to_le16(2); + } else { + tx_cmd->timeout.pm_frame_timeout = 0; + } + + tx_cmd->driver_txop = 0; + tx_cmd->tx_flags = tx_flags; + tx_cmd->next_frame_len = 0; +} + +#define RTS_HCCA_RETRY_LIMIT 3 +#define RTS_DFAULT_RETRY_LIMIT 60 + +static void iwl_tx_cmd_build_rate(struct iwl_priv *priv, + struct iwl_tx_cmd *tx_cmd, + struct ieee80211_tx_control *ctrl, + u16 fc, int sta_id, + int is_hcca) +{ + u8 rts_retry_limit = 0; + u8 data_retry_limit = 0; + u8 rate_plcp; + u16 rate_flags = 0; + int rate_idx = min(ctrl->tx_rate->hw_value & 0xffff, IWL_RATE_COUNT - 1); + + rate_plcp = iwl_rates[rate_idx].plcp; + + rts_retry_limit = (is_hcca) ? + RTS_HCCA_RETRY_LIMIT : RTS_DFAULT_RETRY_LIMIT; + + if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE)) + rate_flags |= RATE_MCS_CCK_MSK; + + + if (ieee80211_is_probe_response(fc)) { + data_retry_limit = 3; + if (data_retry_limit < rts_retry_limit) + rts_retry_limit = data_retry_limit; + } else + data_retry_limit = IWL_DEFAULT_TX_RETRY; + + if (priv->data_retry_limit != -1) + data_retry_limit = priv->data_retry_limit; + + + if (ieee80211_is_data(fc)) { + tx_cmd->initial_rate_index = 0; + tx_cmd->tx_flags |= TX_CMD_FLG_STA_RATE_MSK; + } else { + switch (fc & IEEE80211_FCTL_STYPE) { + case IEEE80211_STYPE_AUTH: + case IEEE80211_STYPE_DEAUTH: + case IEEE80211_STYPE_ASSOC_REQ: + case IEEE80211_STYPE_REASSOC_REQ: + if (tx_cmd->tx_flags & TX_CMD_FLG_RTS_MSK) { + tx_cmd->tx_flags &= ~TX_CMD_FLG_RTS_MSK; + tx_cmd->tx_flags |= TX_CMD_FLG_CTS_MSK; + } + break; + default: + break; + } + + /* Alternate between antenna A and B for successive frames */ + if (priv->use_ant_b_for_management_frame) { + priv->use_ant_b_for_management_frame = 0; + rate_flags |= RATE_MCS_ANT_B_MSK; + } else { + priv->use_ant_b_for_management_frame = 1; + rate_flags |= RATE_MCS_ANT_A_MSK; + } + } + + tx_cmd->rts_retry_limit = rts_retry_limit; + tx_cmd->data_retry_limit = data_retry_limit; + tx_cmd->rate_n_flags = iwl4965_hw_set_rate_n_flags(rate_plcp, rate_flags); +} + +static void iwl_tx_cmd_build_hwcrypto(struct iwl_priv *priv, + struct ieee80211_tx_control *ctl, + struct iwl_tx_cmd *tx_cmd, + struct sk_buff *skb_frag, + int sta_id) +{ + struct iwl_hw_key *keyinfo = &priv->stations[sta_id].keyinfo; + struct iwl_wep_key *wepkey; + int keyidx = 0; + + BUG_ON(ctl->hw_key->hw_key_idx > 3); + + switch (keyinfo->alg) { + case ALG_CCMP: + tx_cmd->sec_ctl = TX_CMD_SEC_CCM; + memcpy(tx_cmd->key, keyinfo->key, keyinfo->keylen); + if (ctl->flags & IEEE80211_TXCTL_AMPDU) + tx_cmd->tx_flags |= TX_CMD_FLG_AGG_CCMP_MSK; + IWL_DEBUG_TX("tx_cmd with aes hwcrypto\n"); + break; + + case ALG_TKIP: + tx_cmd->sec_ctl = TX_CMD_SEC_TKIP; + ieee80211_get_tkip_key(keyinfo->conf, skb_frag, + IEEE80211_TKIP_P2_KEY, tx_cmd->key); + IWL_DEBUG_TX("tx_cmd with tkip hwcrypto\n"); + break; + + case ALG_WEP: + wepkey = &priv->wep_keys[ctl->hw_key->hw_key_idx]; + tx_cmd->sec_ctl = 0; + if (priv->default_wep_key) { + /* the WEP key was sent as static */ + keyidx = ctl->hw_key->hw_key_idx; + memcpy(&tx_cmd->key[3], wepkey->key, + wepkey->key_size); + if (wepkey->key_size == WEP_KEY_LEN_128) + tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128; + } else { + /* the WEP key was sent as dynamic */ + keyidx = keyinfo->keyidx; + memcpy(&tx_cmd->key[3], keyinfo->key, + keyinfo->keylen); + if (keyinfo->keylen == WEP_KEY_LEN_128) + tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128; + } + + tx_cmd->sec_ctl |= (TX_CMD_SEC_WEP | + (keyidx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT); + + IWL_DEBUG_TX("Configuring packet for WEP encryption " + "with key %d\n", keyidx); + break; + + default: + printk(KERN_ERR "Unknown encode alg %d\n", keyinfo->alg); + break; + } +} + +static void iwl_update_tx_stats(struct iwl_priv *priv, u16 fc, u16 len) +{ + /* 0 - mgmt, 1 - cnt, 2 - data */ + int idx = (fc & IEEE80211_FCTL_FTYPE) >> 2; + priv->tx_stats[idx].cnt++; + priv->tx_stats[idx].bytes += len; +} + +/* + * start REPLY_TX command process + */ +int iwl_tx_skb(struct iwl_priv *priv, + struct sk_buff *skb, struct ieee80211_tx_control *ctl) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct iwl_tfd_frame *tfd; + u32 *control_flags; + int txq_id = ctl->queue; + struct iwl_tx_queue *txq = NULL; + struct iwl_queue *q = NULL; + dma_addr_t phys_addr; + dma_addr_t txcmd_phys; + dma_addr_t scratch_phys; + struct iwl_cmd *out_cmd = NULL; + struct iwl_tx_cmd *tx_cmd; + u16 len, idx, len_org; + u16 seq_number = 0; + u8 id, hdr_len, unicast; + u8 sta_id; + u16 fc; + u8 wait_write_ptr = 0; + u8 tid = 0; + u8 *qc = NULL; + unsigned long flags; + int ret; + + spin_lock_irqsave(&priv->lock, flags); + if (iwl_is_rfkill(priv)) { + IWL_DEBUG_DROP("Dropping - RF KILL\n"); + goto drop_unlock; + } + + if (!priv->vif) { + IWL_DEBUG_DROP("Dropping - !priv->vif\n"); + goto drop_unlock; + } + + if ((ctl->tx_rate->hw_value & 0xFF) == IWL_INVALID_RATE) { + IWL_ERROR("ERROR: No TX rate available.\n"); + goto drop_unlock; + } + + unicast = !is_multicast_ether_addr(hdr->addr1); + id = 0; + + fc = le16_to_cpu(hdr->frame_control); + +#ifdef CONFIG_IWLWIFI_DEBUG + if (ieee80211_is_auth(fc)) + IWL_DEBUG_TX("Sending AUTH frame\n"); + else if (ieee80211_is_assoc_request(fc)) + IWL_DEBUG_TX("Sending ASSOC frame\n"); + else if (ieee80211_is_reassoc_request(fc)) + IWL_DEBUG_TX("Sending REASSOC frame\n"); +#endif + + /* drop all data frame if we are not associated */ + if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && + (!iwl_is_associated(priv) || + ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && !priv->assoc_id) || + !priv->assoc_station_added)) { + IWL_DEBUG_DROP("Dropping - !iwl_is_associated\n"); + goto drop_unlock; + } + + spin_unlock_irqrestore(&priv->lock, flags); + + hdr_len = ieee80211_get_hdrlen(fc); + + /* Find (or create) index into station table for destination station */ + sta_id = iwl_get_sta_id(priv, hdr); + if (sta_id == IWL_INVALID_STATION) { + DECLARE_MAC_BUF(mac); + + IWL_DEBUG_DROP("Dropping - INVALID STATION: %s\n", + print_mac(mac, hdr->addr1)); + goto drop; + } + + IWL_DEBUG_TX("station Id %d\n", sta_id); + + if (ieee80211_is_qos_data(fc)) { + qc = ieee80211_get_qos_ctrl(hdr, hdr_len); + tid = qc[0] & 0xf; + seq_number = priv->stations[sta_id].tid[tid].seq_number & + IEEE80211_SCTL_SEQ; + hdr->seq_ctrl = cpu_to_le16(seq_number) | + (hdr->seq_ctrl & + __constant_cpu_to_le16(IEEE80211_SCTL_FRAG)); + seq_number += 0x10; +#ifdef CONFIG_IWL4965_HT + /* aggregation is on for this */ + if (ctl->flags & IEEE80211_TXCTL_AMPDU) + txq_id = priv->stations[sta_id].tid[tid].agg.txq_id; + priv->stations[sta_id].tid[tid].tfds_in_queue++; +#endif /* CONFIG_IWL4965_HT */ + } + + /* Descriptor for chosen Tx queue */ + txq = &priv->txq[txq_id]; + q = &txq->q; + + spin_lock_irqsave(&priv->lock, flags); + + /* Set up first empty TFD within this queue's circular TFD buffer */ + tfd = &txq->bd[q->write_ptr]; + memset(tfd, 0, sizeof(*tfd)); + control_flags = (u32 *) tfd; + idx = get_cmd_index(q, q->write_ptr, 0); + + /* Set up driver data for this TFD */ + memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info)); + txq->txb[q->write_ptr].skb[0] = skb; + memcpy(&(txq->txb[q->write_ptr].status.control), + ctl, sizeof(struct ieee80211_tx_control)); + + /* Set up first empty entry in queue's array of Tx/cmd buffers */ + out_cmd = &txq->cmd[idx]; + tx_cmd = &out_cmd->cmd.tx; + memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr)); + memset(tx_cmd, 0, sizeof(struct iwl_tx_cmd)); + + /* + * Set up the Tx-command (not MAC!) header. + * Store the chosen Tx queue and TFD index within the sequence field; + * after Tx, uCode's Tx response will return this value so driver can + * locate the frame within the tx queue and do post-tx processing. + */ + out_cmd->hdr.cmd = REPLY_TX; + out_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) | + INDEX_TO_SEQ(q->write_ptr))); + + /* Copy MAC header from skb into command buffer */ + memcpy(tx_cmd->hdr, hdr, hdr_len); + + /* + * Use the first empty entry in this queue's command buffer array + * to contain the Tx command and MAC header concatenated together + * (payload data will be in another buffer). + * Size of this varies, due to varying MAC header length. + * If end is not dword aligned, we'll have 2 extra bytes at the end + * of the MAC header (device reads on dword boundaries). + * We'll tell device about this padding later. + */ + len = sizeof(struct iwl_tx_cmd) + + sizeof(struct iwl_cmd_header) + hdr_len; + + len_org = len; + len = (len + 3) & ~3; + + if (len_org != len) + len_org = 1; + else + len_org = 0; + + /* Physical address of this Tx command's header (not MAC header!), + * within command buffer array. */ + txcmd_phys = txq->dma_addr_cmd + sizeof(struct iwl_cmd) * idx + + offsetof(struct iwl_cmd, hdr); + + /* Add buffer containing Tx command and MAC(!) header to TFD's + * first entry */ + iwl_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len); + + if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) + iwl_tx_cmd_build_hwcrypto(priv, ctl, tx_cmd, skb, sta_id); + + /* Set up TFD's 2nd entry to point directly to remainder of skb, + * if any (802.11 null frames have no payload). */ + len = skb->len - hdr_len; + if (len) { + phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len, + len, PCI_DMA_TODEVICE); + iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, len); + } + + /* Tell NIC about any 2-byte padding after MAC header */ + if (len_org) + tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK; + + /* Total # bytes to be transmitted */ + len = (u16)skb->len; + tx_cmd->len = cpu_to_le16(len); + /* TODO need this for burst mode later on */ + iwl_tx_cmd_build_basic(priv, tx_cmd, ctl, hdr, unicast, sta_id); + + /* set is_hcca to 0; it probably will never be implemented */ + iwl_tx_cmd_build_rate(priv, tx_cmd, ctl, fc, sta_id, 0); + + iwl_update_tx_stats(priv, fc, len); + + scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) + + offsetof(struct iwl_tx_cmd, scratch); + tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys); + tx_cmd->dram_msb_ptr = iwl_get_dma_hi_address(scratch_phys); + + if (!ieee80211_get_morefrag(hdr)) { + txq->need_update = 1; + if (qc) + priv->stations[sta_id].tid[tid].seq_number = seq_number; + } else { + wait_write_ptr = 1; + txq->need_update = 0; + } + + iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd)); + + iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len); + + /* Set up entry for this TFD in Tx byte-count array */ + priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq, len); + + /* Tell device the write index *just past* this latest filled TFD */ + q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); + ret = iwl_txq_update_write_ptr(priv, txq); + spin_unlock_irqrestore(&priv->lock, flags); + + if (ret) + return ret; + + if ((iwl_queue_space(q) < q->high_mark) + && priv->mac80211_registered) { + if (wait_write_ptr) { + spin_lock_irqsave(&priv->lock, flags); + txq->need_update = 1; + iwl_txq_update_write_ptr(priv, txq); + spin_unlock_irqrestore(&priv->lock, flags); + } + + ieee80211_stop_queue(priv->hw, ctl->queue); + } + + return 0; + +drop_unlock: + spin_unlock_irqrestore(&priv->lock, flags); +drop: + return -1; +} +EXPORT_SYMBOL(iwl_tx_skb); + +/*************** HOST COMMAND QUEUE FUNCTIONS *****/ + +/** + * iwl_enqueue_hcmd - enqueue a uCode command + * @priv: device private data point + * @cmd: a point to the ucode command structure + * + * The function returns < 0 values to indicate the operation is + * failed. On success, it turns the index (> 0) of command in the + * command queue. + */ +int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) +{ + struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; + struct iwl_queue *q = &txq->q; + struct iwl_tfd_frame *tfd; + u32 *control_flags; + struct iwl_cmd *out_cmd; + u32 idx; + u16 fix_size; + dma_addr_t phys_addr; + int ret; + unsigned long flags; + + cmd->len = priv->cfg->ops->utils->get_hcmd_size(cmd->id, cmd->len); + fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr)); + + /* If any of the command structures end up being larger than + * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then + * we will need to increase the size of the TFD entries */ + BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) && + !(cmd->meta.flags & CMD_SIZE_HUGE)); + + if (iwl_is_rfkill(priv)) { + IWL_DEBUG_INFO("Not sending command - RF KILL"); + return -EIO; + } + + if (iwl_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) { + IWL_ERROR("No space for Tx\n"); + return -ENOSPC; + } + + spin_lock_irqsave(&priv->hcmd_lock, flags); + + tfd = &txq->bd[q->write_ptr]; + memset(tfd, 0, sizeof(*tfd)); + + control_flags = (u32 *) tfd; + + idx = get_cmd_index(q, q->write_ptr, cmd->meta.flags & CMD_SIZE_HUGE); + out_cmd = &txq->cmd[idx]; + + out_cmd->hdr.cmd = cmd->id; + memcpy(&out_cmd->meta, &cmd->meta, sizeof(cmd->meta)); + memcpy(&out_cmd->cmd.payload, cmd->data, cmd->len); + + /* At this point, the out_cmd now has all of the incoming cmd + * information */ + + out_cmd->hdr.flags = 0; + out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) | + INDEX_TO_SEQ(q->write_ptr)); + if (out_cmd->meta.flags & CMD_SIZE_HUGE) + out_cmd->hdr.sequence |= cpu_to_le16(SEQ_HUGE_FRAME); + + phys_addr = txq->dma_addr_cmd + sizeof(txq->cmd[0]) * idx + + offsetof(struct iwl_cmd, hdr); + iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size); + + IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, " + "%d bytes at %d[%d]:%d\n", + get_cmd_string(out_cmd->hdr.cmd), + out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence), + fix_size, q->write_ptr, idx, IWL_CMD_QUEUE_NUM); + + txq->need_update = 1; + + /* Set up entry in queue's byte count circular buffer */ + priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq, 0); + + /* Increment and update queue's write index */ + q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); + ret = iwl_txq_update_write_ptr(priv, txq); + + spin_unlock_irqrestore(&priv->hcmd_lock, flags); + return ret ? ret : idx; +} + diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index e3f872e3381..dd2fd405530 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -53,8 +53,6 @@ #include "iwl-sta.h" #include "iwl-calib.h" -static int iwl_txq_update_write_ptr(struct iwl_priv *priv, - struct iwl_tx_queue *txq); /****************************************************************************** * @@ -135,69 +133,6 @@ static const char *iwl4965_escape_essid(const char *essid, u8 essid_len) return escaped; } - -/*************** DMA-QUEUE-GENERAL-FUNCTIONS ***** - * DMA services - * - * Theory of operation - * - * A Tx or Rx queue resides in host DRAM, and is comprised of a circular buffer - * of buffer descriptors, each of which points to one or more data buffers for - * the device to read from or fill. Driver and device exchange status of each - * queue via "read" and "write" pointers. Driver keeps minimum of 2 empty - * entries in each circular buffer, to protect against confusing empty and full - * queue states. - * - * The device reads or writes the data in the queues via the device's several - * DMA/FIFO channels. Each queue is mapped to a single DMA channel. - * - * For Tx queue, there are low mark and high mark limits. If, after queuing - * the packet for Tx, free space become < low mark, Tx queue stopped. When - * reclaiming packets (on 'tx done IRQ), if free space become > high mark, - * Tx queue resumed. - * - * The 4965 operates with up to 17 queues: One receive queue, one transmit - * queue (#4) for sending commands to the device firmware, and 15 other - * Tx queues that may be mapped to prioritized Tx DMA/FIFO channels. - * - * See more detailed info in iwl-4965-hw.h. - ***************************************************/ - -int iwl_queue_space(const struct iwl_queue *q) -{ - int s = q->read_ptr - q->write_ptr; - - if (q->read_ptr > q->write_ptr) - s -= q->n_bd; - - if (s <= 0) - s += q->n_window; - /* keep some reserve to not confuse empty and full situations */ - s -= 2; - if (s < 0) - s = 0; - return s; -} - - -static inline int iwl_queue_used(const struct iwl_queue *q, int i) -{ - return q->write_ptr > q->read_ptr ? - (i >= q->read_ptr && i < q->write_ptr) : - !(i < q->read_ptr && i >= q->write_ptr); -} - -static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge) -{ - /* This is for scan command, the big buffer at end of command array */ - if (is_huge) - return q->n_window; /* must be power of 2 */ - - /* Otherwise, use normal size buffers */ - return index & (q->n_window - 1); -} - - /*************** STATION TABLE MANAGEMENT **** * mac80211 should be examined to determine if sta_info is duplicating * the functionality provided here @@ -250,95 +185,6 @@ out: -/*************** HOST COMMAND QUEUE FUNCTIONS *****/ - -/** - * iwl4965_enqueue_hcmd - enqueue a uCode command - * @priv: device private data point - * @cmd: a point to the ucode command structure - * - * The function returns < 0 values to indicate the operation is - * failed. On success, it turns the index (> 0) of command in the - * command queue. - */ -int iwl4965_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) -{ - struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; - struct iwl_queue *q = &txq->q; - struct iwl_tfd_frame *tfd; - u32 *control_flags; - struct iwl_cmd *out_cmd; - u32 idx; - u16 fix_size; - dma_addr_t phys_addr; - int ret; - unsigned long flags; - - cmd->len = priv->cfg->ops->utils->get_hcmd_size(cmd->id, cmd->len); - fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr)); - - /* If any of the command structures end up being larger than - * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then - * we will need to increase the size of the TFD entries */ - BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) && - !(cmd->meta.flags & CMD_SIZE_HUGE)); - - if (iwl_is_rfkill(priv)) { - IWL_DEBUG_INFO("Not sending command - RF KILL"); - return -EIO; - } - - if (iwl_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) { - IWL_ERROR("No space for Tx\n"); - return -ENOSPC; - } - - spin_lock_irqsave(&priv->hcmd_lock, flags); - - tfd = &txq->bd[q->write_ptr]; - memset(tfd, 0, sizeof(*tfd)); - - control_flags = (u32 *) tfd; - - idx = get_cmd_index(q, q->write_ptr, cmd->meta.flags & CMD_SIZE_HUGE); - out_cmd = &txq->cmd[idx]; - - out_cmd->hdr.cmd = cmd->id; - memcpy(&out_cmd->meta, &cmd->meta, sizeof(cmd->meta)); - memcpy(&out_cmd->cmd.payload, cmd->data, cmd->len); - - /* At this point, the out_cmd now has all of the incoming cmd - * information */ - - out_cmd->hdr.flags = 0; - out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) | - INDEX_TO_SEQ(q->write_ptr)); - if (out_cmd->meta.flags & CMD_SIZE_HUGE) - out_cmd->hdr.sequence |= cpu_to_le16(SEQ_HUGE_FRAME); - - phys_addr = txq->dma_addr_cmd + sizeof(txq->cmd[0]) * idx + - offsetof(struct iwl_cmd, hdr); - iwl4965_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size); - - IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, " - "%d bytes at %d[%d]:%d\n", - get_cmd_string(out_cmd->hdr.cmd), - out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence), - fix_size, q->write_ptr, idx, IWL_CMD_QUEUE_NUM); - - txq->need_update = 1; - - /* Set up entry in queue's byte count circular buffer */ - priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq, 0); - - /* Increment and update queue's write index */ - q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); - ret = iwl_txq_update_write_ptr(priv, txq); - - spin_unlock_irqrestore(&priv->hcmd_lock, flags); - return ret ? ret : idx; -} - static void iwl4965_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt) { struct iwl_rxon_cmd *rxon = &priv->staging_rxon; @@ -1453,385 +1299,6 @@ static int iwl4965_set_mode(struct iwl_priv *priv, int mode) return 0; } -static void iwl4965_build_tx_cmd_hwcrypto(struct iwl_priv *priv, - struct ieee80211_tx_control *ctl, - struct iwl_cmd *cmd, - struct sk_buff *skb_frag, - int sta_id) -{ - struct iwl_hw_key *keyinfo = &priv->stations[sta_id].keyinfo; - struct iwl_wep_key *wepkey; - int keyidx = 0; - - BUG_ON(ctl->hw_key->hw_key_idx > 3); - - switch (keyinfo->alg) { - case ALG_CCMP: - cmd->cmd.tx.sec_ctl = TX_CMD_SEC_CCM; - memcpy(cmd->cmd.tx.key, keyinfo->key, keyinfo->keylen); - if (ctl->flags & IEEE80211_TXCTL_AMPDU) - cmd->cmd.tx.tx_flags |= TX_CMD_FLG_AGG_CCMP_MSK; - IWL_DEBUG_TX("tx_cmd with aes hwcrypto\n"); - break; - - case ALG_TKIP: - cmd->cmd.tx.sec_ctl = TX_CMD_SEC_TKIP; - ieee80211_get_tkip_key(keyinfo->conf, skb_frag, - IEEE80211_TKIP_P2_KEY, cmd->cmd.tx.key); - IWL_DEBUG_TX("tx_cmd with tkip hwcrypto\n"); - break; - - case ALG_WEP: - wepkey = &priv->wep_keys[ctl->hw_key->hw_key_idx]; - cmd->cmd.tx.sec_ctl = 0; - if (priv->default_wep_key) { - /* the WEP key was sent as static */ - keyidx = ctl->hw_key->hw_key_idx; - memcpy(&cmd->cmd.tx.key[3], wepkey->key, - wepkey->key_size); - if (wepkey->key_size == WEP_KEY_LEN_128) - cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128; - } else { - /* the WEP key was sent as dynamic */ - keyidx = keyinfo->keyidx; - memcpy(&cmd->cmd.tx.key[3], keyinfo->key, - keyinfo->keylen); - if (keyinfo->keylen == WEP_KEY_LEN_128) - cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128; - } - - cmd->cmd.tx.sec_ctl |= (TX_CMD_SEC_WEP | - (keyidx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT); - - IWL_DEBUG_TX("Configuring packet for WEP encryption " - "with key %d\n", keyidx); - break; - - default: - printk(KERN_ERR "Unknown encode alg %d\n", keyinfo->alg); - break; - } -} - -/* - * handle build REPLY_TX command notification. - */ -static void iwl4965_build_tx_cmd_basic(struct iwl_priv *priv, - struct iwl_cmd *cmd, - struct ieee80211_tx_control *ctrl, - struct ieee80211_hdr *hdr, - int is_unicast, u8 std_id) -{ - u16 fc = le16_to_cpu(hdr->frame_control); - __le32 tx_flags = cmd->cmd.tx.tx_flags; - - cmd->cmd.tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; - if (!(ctrl->flags & IEEE80211_TXCTL_NO_ACK)) { - tx_flags |= TX_CMD_FLG_ACK_MSK; - if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) - tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; - if (ieee80211_is_probe_response(fc) && - !(le16_to_cpu(hdr->seq_ctrl) & 0xf)) - tx_flags |= TX_CMD_FLG_TSF_MSK; - } else { - tx_flags &= (~TX_CMD_FLG_ACK_MSK); - tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; - } - - if (ieee80211_is_back_request(fc)) - tx_flags |= TX_CMD_FLG_ACK_MSK | TX_CMD_FLG_IMM_BA_RSP_MASK; - - - cmd->cmd.tx.sta_id = std_id; - if (ieee80211_get_morefrag(hdr)) - tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK; - - if (ieee80211_is_qos_data(fc)) { - u8 *qc = ieee80211_get_qos_ctrl(hdr, ieee80211_get_hdrlen(fc)); - cmd->cmd.tx.tid_tspec = qc[0] & 0xf; - tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK; - } else { - tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; - } - - if (ctrl->flags & IEEE80211_TXCTL_USE_RTS_CTS) { - tx_flags |= TX_CMD_FLG_RTS_MSK; - tx_flags &= ~TX_CMD_FLG_CTS_MSK; - } else if (ctrl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { - tx_flags &= ~TX_CMD_FLG_RTS_MSK; - tx_flags |= TX_CMD_FLG_CTS_MSK; - } - - if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK)) - tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK; - - tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK); - if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) { - if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ || - (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ) - cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(3); - else - cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(2); - } else { - cmd->cmd.tx.timeout.pm_frame_timeout = 0; - } - - cmd->cmd.tx.driver_txop = 0; - cmd->cmd.tx.tx_flags = tx_flags; - cmd->cmd.tx.next_frame_len = 0; -} -static void iwl_update_tx_stats(struct iwl_priv *priv, u16 fc, u16 len) -{ - /* 0 - mgmt, 1 - cnt, 2 - data */ - int idx = (fc & IEEE80211_FCTL_FTYPE) >> 2; - priv->tx_stats[idx].cnt++; - priv->tx_stats[idx].bytes += len; -} -/* - * start REPLY_TX command process - */ -static int iwl4965_tx_skb(struct iwl_priv *priv, - struct sk_buff *skb, struct ieee80211_tx_control *ctl) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct iwl_tfd_frame *tfd; - u32 *control_flags; - int txq_id = ctl->queue; - struct iwl_tx_queue *txq = NULL; - struct iwl_queue *q = NULL; - dma_addr_t phys_addr; - dma_addr_t txcmd_phys; - dma_addr_t scratch_phys; - struct iwl_cmd *out_cmd = NULL; - u16 len, idx, len_org; - u8 hdr_len; - u8 id; - u8 unicast; - u8 sta_id; - u8 tid = 0; - u8 wait_write_ptr = 0; - u16 seq_number = 0; - u16 fc; - u8 *qc = NULL; - unsigned long flags; - int rc; - - spin_lock_irqsave(&priv->lock, flags); - if (iwl_is_rfkill(priv)) { - IWL_DEBUG_DROP("Dropping - RF KILL\n"); - goto drop_unlock; - } - - if (!priv->vif) { - IWL_DEBUG_DROP("Dropping - !priv->vif\n"); - goto drop_unlock; - } - - if ((ctl->tx_rate->hw_value & 0xFF) == IWL_INVALID_RATE) { - IWL_ERROR("ERROR: No TX rate available.\n"); - goto drop_unlock; - } - - unicast = !is_multicast_ether_addr(hdr->addr1); - id = 0; - - fc = le16_to_cpu(hdr->frame_control); - -#ifdef CONFIG_IWLWIFI_DEBUG - if (ieee80211_is_auth(fc)) - IWL_DEBUG_TX("Sending AUTH frame\n"); - else if (ieee80211_is_assoc_request(fc)) - IWL_DEBUG_TX("Sending ASSOC frame\n"); - else if (ieee80211_is_reassoc_request(fc)) - IWL_DEBUG_TX("Sending REASSOC frame\n"); -#endif - - /* drop all data frame if we are not associated */ - if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && - (!iwl_is_associated(priv) || - ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && !priv->assoc_id) || - !priv->assoc_station_added)) { - IWL_DEBUG_DROP("Dropping - !iwl_is_associated\n"); - goto drop_unlock; - } - - spin_unlock_irqrestore(&priv->lock, flags); - - hdr_len = ieee80211_get_hdrlen(fc); - - /* Find (or create) index into station table for destination station */ - sta_id = iwl_get_sta_id(priv, hdr); - if (sta_id == IWL_INVALID_STATION) { - DECLARE_MAC_BUF(mac); - - IWL_DEBUG_DROP("Dropping - INVALID STATION: %s\n", - print_mac(mac, hdr->addr1)); - goto drop; - } - - IWL_DEBUG_TX("station Id %d\n", sta_id); - - if (ieee80211_is_qos_data(fc)) { - qc = ieee80211_get_qos_ctrl(hdr, hdr_len); - tid = qc[0] & 0xf; - seq_number = priv->stations[sta_id].tid[tid].seq_number & - IEEE80211_SCTL_SEQ; - hdr->seq_ctrl = cpu_to_le16(seq_number) | - (hdr->seq_ctrl & - __constant_cpu_to_le16(IEEE80211_SCTL_FRAG)); - seq_number += 0x10; -#ifdef CONFIG_IWL4965_HT - /* aggregation is on for this */ - if (ctl->flags & IEEE80211_TXCTL_AMPDU) - txq_id = priv->stations[sta_id].tid[tid].agg.txq_id; - priv->stations[sta_id].tid[tid].tfds_in_queue++; -#endif /* CONFIG_IWL4965_HT */ - } - - /* Descriptor for chosen Tx queue */ - txq = &priv->txq[txq_id]; - q = &txq->q; - - spin_lock_irqsave(&priv->lock, flags); - - /* Set up first empty TFD within this queue's circular TFD buffer */ - tfd = &txq->bd[q->write_ptr]; - memset(tfd, 0, sizeof(*tfd)); - control_flags = (u32 *) tfd; - idx = get_cmd_index(q, q->write_ptr, 0); - - /* Set up driver data for this TFD */ - memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info)); - txq->txb[q->write_ptr].skb[0] = skb; - memcpy(&(txq->txb[q->write_ptr].status.control), - ctl, sizeof(struct ieee80211_tx_control)); - - /* Set up first empty entry in queue's array of Tx/cmd buffers */ - out_cmd = &txq->cmd[idx]; - memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr)); - memset(&out_cmd->cmd.tx, 0, sizeof(out_cmd->cmd.tx)); - - /* - * Set up the Tx-command (not MAC!) header. - * Store the chosen Tx queue and TFD index within the sequence field; - * after Tx, uCode's Tx response will return this value so driver can - * locate the frame within the tx queue and do post-tx processing. - */ - out_cmd->hdr.cmd = REPLY_TX; - out_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) | - INDEX_TO_SEQ(q->write_ptr))); - - /* Copy MAC header from skb into command buffer */ - memcpy(out_cmd->cmd.tx.hdr, hdr, hdr_len); - - /* - * Use the first empty entry in this queue's command buffer array - * to contain the Tx command and MAC header concatenated together - * (payload data will be in another buffer). - * Size of this varies, due to varying MAC header length. - * If end is not dword aligned, we'll have 2 extra bytes at the end - * of the MAC header (device reads on dword boundaries). - * We'll tell device about this padding later. - */ - len = sizeof(struct iwl_tx_cmd) + - sizeof(struct iwl_cmd_header) + hdr_len; - - len_org = len; - len = (len + 3) & ~3; - - if (len_org != len) - len_org = 1; - else - len_org = 0; - - /* Physical address of this Tx command's header (not MAC header!), - * within command buffer array. */ - txcmd_phys = txq->dma_addr_cmd + sizeof(struct iwl_cmd) * idx + - offsetof(struct iwl_cmd, hdr); - - /* Add buffer containing Tx command and MAC(!) header to TFD's - * first entry */ - iwl4965_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len); - - if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) - iwl4965_build_tx_cmd_hwcrypto(priv, ctl, out_cmd, skb, sta_id); - - /* Set up TFD's 2nd entry to point directly to remainder of skb, - * if any (802.11 null frames have no payload). */ - len = skb->len - hdr_len; - if (len) { - phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len, - len, PCI_DMA_TODEVICE); - iwl4965_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, len); - } - - /* Tell 4965 about any 2-byte padding after MAC header */ - if (len_org) - out_cmd->cmd.tx.tx_flags |= TX_CMD_FLG_MH_PAD_MSK; - - /* Total # bytes to be transmitted */ - len = (u16)skb->len; - out_cmd->cmd.tx.len = cpu_to_le16(len); - - /* TODO need this for burst mode later on */ - iwl4965_build_tx_cmd_basic(priv, out_cmd, ctl, hdr, unicast, sta_id); - - /* set is_hcca to 0; it probably will never be implemented */ - iwl4965_hw_build_tx_cmd_rate(priv, out_cmd, ctl, hdr, sta_id, 0); - - iwl_update_tx_stats(priv, fc, len); - - scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) + - offsetof(struct iwl_tx_cmd, scratch); - out_cmd->cmd.tx.dram_lsb_ptr = cpu_to_le32(scratch_phys); - out_cmd->cmd.tx.dram_msb_ptr = iwl_get_dma_hi_address(scratch_phys); - - if (!ieee80211_get_morefrag(hdr)) { - txq->need_update = 1; - if (qc) - priv->stations[sta_id].tid[tid].seq_number = seq_number; - } else { - wait_write_ptr = 1; - txq->need_update = 0; - } - - iwl_print_hex_dump(priv, IWL_DL_TX, out_cmd->cmd.payload, - sizeof(out_cmd->cmd.tx)); - - iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)out_cmd->cmd.tx.hdr, - ieee80211_get_hdrlen(fc)); - - /* Set up entry for this TFD in Tx byte-count array */ - priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq, len); - - /* Tell device the write index *just past* this latest filled TFD */ - q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); - rc = iwl_txq_update_write_ptr(priv, txq); - spin_unlock_irqrestore(&priv->lock, flags); - - if (rc) - return rc; - - if ((iwl_queue_space(q) < q->high_mark) - && priv->mac80211_registered) { - if (wait_write_ptr) { - spin_lock_irqsave(&priv->lock, flags); - txq->need_update = 1; - iwl_txq_update_write_ptr(priv, txq); - spin_unlock_irqrestore(&priv->lock, flags); - } - - ieee80211_stop_queue(priv->hw, ctl->queue); - } - - return 0; - -drop_unlock: - spin_unlock_irqrestore(&priv->lock, flags); -drop: - return -1; -} - static void iwl4965_set_rate(struct iwl_priv *priv) { const struct ieee80211_supported_band *hw = NULL; @@ -3101,52 +2568,6 @@ int iwl4965_calc_sig_qual(int rssi_dbm, int noise_dbm) return sig_qual; } -/** - * iwl_txq_update_write_ptr - Send new write index to hardware - */ -static int iwl_txq_update_write_ptr(struct iwl_priv *priv, - struct iwl_tx_queue *txq) -{ - u32 reg = 0; - int ret = 0; - int txq_id = txq->q.id; - - if (txq->need_update == 0) - return ret; - - /* if we're trying to save power */ - if (test_bit(STATUS_POWER_PMI, &priv->status)) { - /* wake up nic if it's powered down ... - * uCode will wake up, and interrupt us again, so next - * time we'll skip this part. */ - reg = iwl_read32(priv, CSR_UCODE_DRV_GP1); - - if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { - IWL_DEBUG_INFO("Requesting wakeup, GP1 = 0x%x\n", reg); - iwl_set_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - return ret; - } - - /* restore this queue's parameters in nic hardware. */ - ret = iwl_grab_nic_access(priv); - if (ret) - return ret; - iwl_write_direct32(priv, HBUS_TARG_WRPTR, - txq->q.write_ptr | (txq_id << 8)); - iwl_release_nic_access(priv); - - /* else not in power-save mode, uCode will never sleep when we're - * trying to tx (during RFKILL, we're not trying to tx). */ - } else - iwl_write32(priv, HBUS_TARG_WRPTR, - txq->q.write_ptr | (txq_id << 8)); - - txq->need_update = 0; - - return ret; -} - #ifdef CONFIG_IWLWIFI_DEBUG static void iwl4965_print_rx_config_cmd(struct iwl_priv *priv) { @@ -4956,7 +4377,7 @@ static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, ctl->tx_rate->bitrate); - if (iwl4965_tx_skb(priv, skb, ctl)) + if (iwl_tx_skb(priv, skb, ctl)) dev_kfree_skb_any(skb); IWL_DEBUG_MAC80211("leave\n"); -- cgit v1.2.3-70-g09d2 From a98410139a2ef6553ae5d73bf12bb9a68d0b38b9 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 15 May 2008 13:54:08 +0800 Subject: iwlwifi: don't switch to SGI if not supported by AP This patch fixes SGI support. RS didn't look at the capabilities of the AP before switching to SGI, this should lead to a stall in the traffic with an AP that doesn't support SGI. Signed-off-by: Emmanuel Grumbach Signed-off-by: Guy Cohen Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 18 ++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-dev.h | 4 ++-- drivers/net/wireless/iwlwifi/iwl4965-base.c | 4 ++-- 3 files changed, 22 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index 071c7b6ebef..2adc2281c77 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -1439,6 +1439,15 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, } break; case IWL_SISO_SWITCH_GI: + if (!tbl->is_fat && + !(priv->current_ht_config.sgf & + HT_SHORT_GI_20MHZ)) + break; + if (tbl->is_fat && + !(priv->current_ht_config.sgf & + HT_SHORT_GI_40MHZ)) + break; + IWL_DEBUG_RATE("LQ: SISO toggle SGI/NGI\n"); memcpy(search_tbl, tbl, sz); @@ -1521,6 +1530,15 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv, break; case IWL_MIMO_SWITCH_GI: + if (!tbl->is_fat && + !(priv->current_ht_config.sgf & + HT_SHORT_GI_20MHZ)) + break; + if (tbl->is_fat && + !(priv->current_ht_config.sgf & + HT_SHORT_GI_40MHZ)) + break; + IWL_DEBUG_RATE("LQ: MIMO toggle SGI/NGI\n"); /* Set up new search table for MIMO */ diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 4106efd194e..7a54682a3d8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -610,8 +610,8 @@ struct iwl_hw_params { #endif }; -#define HT_SHORT_GI_20MHZ_ONLY (1 << 0) -#define HT_SHORT_GI_40MHZ_ONLY (1 << 1) +#define HT_SHORT_GI_20MHZ (1 << 0) +#define HT_SHORT_GI_40MHZ (1 << 1) #define IWL_RX_HDR(x) ((struct iwl4965_rx_frame_hdr *)(\ diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index dd2fd405530..a532a9e576d 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -700,9 +700,9 @@ static void iwl4965_ht_conf(struct iwl_priv *priv, priv->ps_mode = (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2); if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20) - iwl_conf->sgf |= 0x1; + iwl_conf->sgf |= HT_SHORT_GI_20MHZ; if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40) - iwl_conf->sgf |= 0x2; + iwl_conf->sgf |= HT_SHORT_GI_40MHZ; iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD); iwl_conf->max_amsdu_size = -- cgit v1.2.3-70-g09d2 From ccc038abe4cb00cf56aeae5b1df47fcc4ed4136c Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 15 May 2008 13:54:09 +0800 Subject: iwlwifi: clean up and bug fix for security This patch cleans up code in security. 1) uses the new pointer to ieee80211_key_conf passed with the tx_control. 2) resolves bug reported by Mirco Tischler (sends ADD_STA in ASYNC mode) 3) resolves bug reported by Volker Braun regarding dynamic WEP 4) drops a WEP packet which has been garbaged by firmware. This can happen upon rekeying. Signed-off-by: Emmanuel Grumbach Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 2 +- drivers/net/wireless/iwlwifi/iwl-dev.h | 1 - drivers/net/wireless/iwlwifi/iwl-sta.c | 25 ++++++++---------- drivers/net/wireless/iwlwifi/iwl-sta.h | 3 +++ drivers/net/wireless/iwlwifi/iwl-tx.c | 41 +++++++++-------------------- drivers/net/wireless/iwlwifi/iwl4965-base.c | 3 ++- 6 files changed, 29 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 8f0852d058e..52c7eae08d4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2389,6 +2389,7 @@ static int iwl4965_set_decrypted_flag(struct iwl_priv *priv, RX_RES_STATUS_BAD_KEY_TTAK) break; + case RX_RES_STATUS_SEC_TYPE_WEP: if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == RX_RES_STATUS_BAD_ICV_MIC) { /* bad ICV, the packet is destroyed since the @@ -2396,7 +2397,6 @@ static int iwl4965_set_decrypted_flag(struct iwl_priv *priv, IWL_DEBUG_RX("Packet destroyed\n"); return -1; } - case RX_RES_STATUS_SEC_TYPE_WEP: case RX_RES_STATUS_SEC_TYPE_CCMP: if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == RX_RES_STATUS_DECRYPT_OK) { diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 7a54682a3d8..305491ff9be 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -442,7 +442,6 @@ struct iwl_hw_key { enum ieee80211_key_alg alg; int keylen; u8 keyidx; - struct ieee80211_key_conf *conf; u8 key[32]; }; diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index c8e468fb3ca..99ee1e14e29 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -324,7 +324,7 @@ int iwl_set_default_wep_key(struct iwl_priv *priv, unsigned long flags; keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV; - keyconf->hw_key_idx = keyconf->keyidx; + keyconf->hw_key_idx = HW_KEY_DEFAULT; priv->stations[IWL_AP_ID].keyinfo.alg = ALG_WEP; spin_lock_irqsave(&priv->sta_lock, flags); @@ -354,7 +354,6 @@ static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv, int ret; keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV; - keyconf->hw_key_idx = keyconf->keyidx; key_flags |= (STA_KEY_FLG_WEP | STA_KEY_FLG_MAP_KEY_MSK); key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS); @@ -411,7 +410,6 @@ static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv, key_flags |= STA_KEY_MULTICAST_MSK; keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; - keyconf->hw_key_idx = keyconf->keyidx; spin_lock_irqsave(&priv->sta_lock, flags); priv->stations[sta_id].keyinfo.alg = keyconf->alg; @@ -449,12 +447,10 @@ static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv, keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; - keyconf->hw_key_idx = keyconf->keyidx; spin_lock_irqsave(&priv->sta_lock, flags); priv->stations[sta_id].keyinfo.alg = keyconf->alg; - priv->stations[sta_id].keyinfo.conf = keyconf; priv->stations[sta_id].keyinfo.keylen = 16; if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK) @@ -483,7 +479,7 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv, u16 key_flags; u8 keyidx; - priv->key_mapping_key = 0; + priv->key_mapping_key--; spin_lock_irqsave(&priv->sta_lock, flags); key_flags = le16_to_cpu(priv->stations[sta_id].sta.key.key_flags); @@ -514,31 +510,32 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv, priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n"); - ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, 0); + ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); spin_unlock_irqrestore(&priv->sta_lock, flags); return ret; } EXPORT_SYMBOL(iwl_remove_dynamic_key); int iwl_set_dynamic_key(struct iwl_priv *priv, - struct ieee80211_key_conf *key, u8 sta_id) + struct ieee80211_key_conf *keyconf, u8 sta_id) { int ret; - priv->key_mapping_key = 1; + priv->key_mapping_key++; + keyconf->hw_key_idx = HW_KEY_DYNAMIC; - switch (key->alg) { + switch (keyconf->alg) { case ALG_CCMP: - ret = iwl_set_ccmp_dynamic_key_info(priv, key, sta_id); + ret = iwl_set_ccmp_dynamic_key_info(priv, keyconf, sta_id); break; case ALG_TKIP: - ret = iwl_set_tkip_dynamic_key_info(priv, key, sta_id); + ret = iwl_set_tkip_dynamic_key_info(priv, keyconf, sta_id); break; case ALG_WEP: - ret = iwl_set_wep_dynamic_key_info(priv, key, sta_id); + ret = iwl_set_wep_dynamic_key_info(priv, keyconf, sta_id); break; default: - IWL_ERROR("Unknown alg: %s alg = %d\n", __func__, key->alg); + IWL_ERROR("Unknown alg: %s alg = %d\n", __func__, keyconf->alg); ret = -EINVAL; } diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h index ee256430708..b643546961f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.h +++ b/drivers/net/wireless/iwlwifi/iwl-sta.h @@ -29,6 +29,9 @@ #ifndef __iwl_sta_h__ #define __iwl_sta_h__ +#define HW_KEY_DYNAMIC 0 +#define HW_KEY_DEFAULT 1 + int iwl_get_free_ucode_key_index(struct iwl_priv *priv); int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty); int iwl_remove_default_wep_key(struct iwl_priv *priv, diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index a37ced58c66..f32cddabdf6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -639,16 +639,12 @@ static void iwl_tx_cmd_build_hwcrypto(struct iwl_priv *priv, struct sk_buff *skb_frag, int sta_id) { - struct iwl_hw_key *keyinfo = &priv->stations[sta_id].keyinfo; - struct iwl_wep_key *wepkey; - int keyidx = 0; + struct ieee80211_key_conf *keyconf = ctl->hw_key; - BUG_ON(ctl->hw_key->hw_key_idx > 3); - - switch (keyinfo->alg) { + switch (keyconf->alg) { case ALG_CCMP: tx_cmd->sec_ctl = TX_CMD_SEC_CCM; - memcpy(tx_cmd->key, keyinfo->key, keyinfo->keylen); + memcpy(tx_cmd->key, keyconf->key, keyconf->keylen); if (ctl->flags & IEEE80211_TXCTL_AMPDU) tx_cmd->tx_flags |= TX_CMD_FLG_AGG_CCMP_MSK; IWL_DEBUG_TX("tx_cmd with aes hwcrypto\n"); @@ -656,39 +652,26 @@ static void iwl_tx_cmd_build_hwcrypto(struct iwl_priv *priv, case ALG_TKIP: tx_cmd->sec_ctl = TX_CMD_SEC_TKIP; - ieee80211_get_tkip_key(keyinfo->conf, skb_frag, + ieee80211_get_tkip_key(keyconf, skb_frag, IEEE80211_TKIP_P2_KEY, tx_cmd->key); IWL_DEBUG_TX("tx_cmd with tkip hwcrypto\n"); break; case ALG_WEP: - wepkey = &priv->wep_keys[ctl->hw_key->hw_key_idx]; - tx_cmd->sec_ctl = 0; - if (priv->default_wep_key) { - /* the WEP key was sent as static */ - keyidx = ctl->hw_key->hw_key_idx; - memcpy(&tx_cmd->key[3], wepkey->key, - wepkey->key_size); - if (wepkey->key_size == WEP_KEY_LEN_128) - tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128; - } else { - /* the WEP key was sent as dynamic */ - keyidx = keyinfo->keyidx; - memcpy(&tx_cmd->key[3], keyinfo->key, - keyinfo->keylen); - if (keyinfo->keylen == WEP_KEY_LEN_128) - tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128; - } - tx_cmd->sec_ctl |= (TX_CMD_SEC_WEP | - (keyidx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT); + (keyconf->keyidx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT); + + if (keyconf->keylen == WEP_KEY_LEN_128) + tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128; + + memcpy(&tx_cmd->key[3], keyconf->key, keyconf->keylen); IWL_DEBUG_TX("Configuring packet for WEP encryption " - "with key %d\n", keyidx); + "with key %d\n", keyconf->keyidx); break; default: - printk(KERN_ERR "Unknown encode alg %d\n", keyinfo->alg); + printk(KERN_ERR "Unknown encode alg %d\n", keyconf->alg); break; } } diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index a532a9e576d..40616dbd26f 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -4951,7 +4951,8 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (cmd == SET_KEY) is_default_wep_key = !priv->key_mapping_key; else - is_default_wep_key = priv->default_wep_key; + is_default_wep_key = + (key->hw_key_idx == HW_KEY_DEFAULT); } switch (cmd) { -- cgit v1.2.3-70-g09d2 From 3647074973e70d0872b96ada27bbbb71fd1f628c Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Thu, 15 May 2008 13:54:10 +0800 Subject: iwlwifi: rename and move Tx queue activation/deactivation This patch moves iwl4965_txq_ctx_activate and iwl4965_txq_ctx_deactivate to iwl-dev.h and removes 4965 prefix from their names. Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 14 ++------------ drivers/net/wireless/iwlwifi/iwl-dev.h | 10 ++++++++++ 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 52c7eae08d4..f848a5b0f62 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -911,16 +911,6 @@ static const u16 default_queue_to_tx_fifo[] = { IWL_TX_FIFO_HCCA_2 }; -static inline void iwl4965_txq_ctx_activate(struct iwl_priv *priv, int txq_id) -{ - set_bit(txq_id, &priv->txq_ctx_active_msk); -} - -static inline void iwl4965_txq_ctx_deactivate(struct iwl_priv *priv, int txq_id) -{ - clear_bit(txq_id, &priv->txq_ctx_active_msk); -} - int iwl4965_alive_notify(struct iwl_priv *priv) { u32 a; @@ -998,7 +988,7 @@ int iwl4965_alive_notify(struct iwl_priv *priv) /* Map each Tx/cmd queue to its corresponding fifo */ for (i = 0; i < ARRAY_SIZE(default_queue_to_tx_fifo); i++) { int ac = default_queue_to_tx_fifo[i]; - iwl4965_txq_ctx_activate(priv, i); + iwl_txq_ctx_activate(priv, i); iwl4965_tx_queue_set_status(priv, &priv->txq[i], ac, 0); } @@ -3115,7 +3105,7 @@ static int iwl4965_tx_queue_agg_disable(struct iwl_priv *priv, u16 txq_id, iwl4965_set_wr_ptrs(priv, txq_id, ssn_idx); iwl_clear_bits_prph(priv, IWL49_SCD_INTERRUPT_MASK, (1 << txq_id)); - iwl4965_txq_ctx_deactivate(priv, txq_id); + iwl_txq_ctx_deactivate(priv, txq_id); iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0); iwl_release_nic_access(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 305491ff9be..533479e717a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1210,6 +1210,16 @@ struct iwl_priv { struct timer_list statistics_periodic; }; /*iwl_priv */ +static inline void iwl_txq_ctx_activate(struct iwl_priv *priv, int txq_id) +{ + set_bit(txq_id, &priv->txq_ctx_active_msk); +} + +static inline void iwl_txq_ctx_deactivate(struct iwl_priv *priv, int txq_id) +{ + clear_bit(txq_id, &priv->txq_ctx_active_msk); +} + static inline int iwl_is_associated(struct iwl_priv *priv) { return (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0; -- cgit v1.2.3-70-g09d2 From b600e4e1c5cd8928fef83bb983ab76c9a6f655bc Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Thu, 15 May 2008 13:54:11 +0800 Subject: iwlwifi: add rx_handlers stub for iwl5000 This patch adds rx_handler_setup stub to iwl5000. Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index d155247d246..00ad360fc5e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -464,6 +464,10 @@ static u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 len) return len; } +static void iwl5000_rx_handler_setup(struct iwl_priv *priv) +{ +} + static struct iwl_hcmd_ops iwl5000_hcmd = { }; @@ -483,6 +487,7 @@ static struct iwl_lib_ops iwl5000_lib = { .shared_mem_rx_idx = iwl5000_shared_mem_rx_idx, .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, .disable_tx_fifo = iwl5000_disable_tx_fifo, + .rx_handler_setup = iwl5000_rx_handler_setup, .apm_ops = { .init = iwl5000_apm_init, .config = iwl5000_nic_config, -- cgit v1.2.3-70-g09d2 From dbb983b70a4696666112591572ed49c48c58da26 Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Thu, 15 May 2008 13:54:12 +0800 Subject: iwlwifi: add ucode loaders for iwl5000 This patch adds ucode initialization handler and functions to load ucode for iwl5000 NIC. Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 134 ++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-dev.h | 8 ++ drivers/net/wireless/iwlwifi/iwl4965-base.c | 3 + 3 files changed, 145 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 00ad360fc5e..b6bdffc5a42 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -287,6 +287,139 @@ static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, return &priv->eeprom[address]; } +/* + * ucode + */ +static int iwl5000_load_section(struct iwl_priv *priv, + struct fw_desc *image, + u32 dst_addr) +{ + int ret = 0; + unsigned long flags; + + dma_addr_t phy_addr = image->p_addr; + u32 byte_cnt = image->len; + + spin_lock_irqsave(&priv->lock, flags); + ret = iwl_grab_nic_access(priv); + if (ret) { + spin_unlock_irqrestore(&priv->lock, flags); + return ret; + } + + iwl_write_direct32(priv, + FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL), + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE); + + iwl_write_direct32(priv, + FH_SRVC_CHNL_SRAM_ADDR_REG(FH_SRVC_CHNL), dst_addr); + + iwl_write_direct32(priv, + FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL), + phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK); + + /* FIME: write the MSB of the phy_addr in CTRL1 + * iwl_write_direct32(priv, + IWL_FH_TFDIB_CTRL1_REG(IWL_FH_SRVC_CHNL), + ((phy_addr & MSB_MSK) + << FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_count); + */ + iwl_write_direct32(priv, + FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL), byte_cnt); + iwl_write_direct32(priv, + FH_TCSR_CHNL_TX_BUF_STS_REG(FH_SRVC_CHNL), + 1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM | + 1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX | + FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID); + + iwl_write_direct32(priv, + FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL), + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL | + FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD); + + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + return 0; +} + +static int iwl5000_load_given_ucode(struct iwl_priv *priv, + struct fw_desc *inst_image, + struct fw_desc *data_image) +{ + int ret = 0; + + ret = iwl5000_load_section( + priv, inst_image, RTC_INST_LOWER_BOUND); + if (ret) + return ret; + + IWL_DEBUG_INFO("INST uCode section being loaded...\n"); + ret = wait_event_interruptible_timeout(priv->wait_command_queue, + priv->ucode_write_complete, 5 * HZ); + if (ret == -ERESTARTSYS) { + IWL_ERROR("Could not load the INST uCode section due " + "to interrupt\n"); + return ret; + } + if (!ret) { + IWL_ERROR("Could not load the INST uCode section\n"); + return -ETIMEDOUT; + } + + priv->ucode_write_complete = 0; + + ret = iwl5000_load_section( + priv, data_image, RTC_DATA_LOWER_BOUND); + if (ret) + return ret; + + IWL_DEBUG_INFO("DATA uCode section being loaded...\n"); + + ret = wait_event_interruptible_timeout(priv->wait_command_queue, + priv->ucode_write_complete, 5 * HZ); + if (ret == -ERESTARTSYS) { + IWL_ERROR("Could not load the INST uCode section due " + "to interrupt\n"); + return ret; + } else if (!ret) { + IWL_ERROR("Could not load the DATA uCode section\n"); + return -ETIMEDOUT; + } else + ret = 0; + + priv->ucode_write_complete = 0; + + return ret; +} + +static int iwl5000_load_ucode(struct iwl_priv *priv) +{ + int ret = 0; + + /* check whether init ucode should be loaded, or rather runtime ucode */ + if (priv->ucode_init.len && (priv->ucode_type == UCODE_NONE)) { + IWL_DEBUG_INFO("Init ucode found. Loading init ucode...\n"); + ret = iwl5000_load_given_ucode(priv, + &priv->ucode_init, &priv->ucode_init_data); + if (!ret) { + IWL_DEBUG_INFO("Init ucode load complete.\n"); + priv->ucode_type = UCODE_INIT; + } + } else { + IWL_DEBUG_INFO("Init ucode not found, or already loaded. " + "Loading runtime ucode...\n"); + ret = iwl5000_load_given_ucode(priv, + &priv->ucode_code, &priv->ucode_data); + if (!ret) { + IWL_DEBUG_INFO("Runtime ucode load complete.\n"); + priv->ucode_type = UCODE_RT; + } + } + + return ret; +} + static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) { if ((priv->cfg->mod_params->num_of_queues > IWL50_NUM_QUEUES) || @@ -488,6 +621,7 @@ static struct iwl_lib_ops iwl5000_lib = { .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, .disable_tx_fifo = iwl5000_disable_tx_fifo, .rx_handler_setup = iwl5000_rx_handler_setup, + .load_ucode = iwl5000_load_ucode, .apm_ops = { .init = iwl5000_apm_init, .config = iwl5000_nic_config, diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 533479e717a..b1ff0afd828 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -876,6 +876,12 @@ struct statistics_general_data { u32 beacon_energy_c; }; +enum ucode_type { + UCODE_NONE = 0, + UCODE_INIT, + UCODE_RT +}; + #ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB /* Sensitivity calib data */ struct iwl_sensitivity_data { @@ -1010,6 +1016,8 @@ struct iwl_priv { struct fw_desc ucode_init; /* initialization inst */ struct fw_desc ucode_init_data; /* initialization data */ struct fw_desc ucode_boot; /* bootstrap inst */ + enum ucode_type ucode_type; + u8 ucode_write_complete; /* the image write is complete */ struct iwl4965_rxon_time_cmd rxon_timing; diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 40616dbd26f..e06142d9da5 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -2978,6 +2978,9 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv) if (inta & CSR_INT_BIT_FH_TX) { IWL_DEBUG_ISR("Tx interrupt\n"); handled |= CSR_INT_BIT_FH_TX; + /* FH finished to write, send event */ + priv->ucode_write_complete = 1; + wake_up_interruptible(&priv->wait_command_queue); } if (inta & ~handled) -- cgit v1.2.3-70-g09d2 From 99da1b48fc77484aa8da85a45d9c3c1e00243659 Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Thu, 15 May 2008 13:54:13 +0800 Subject: iwlwifi: add ucode init flow handling for iwl5000 This patch adds all the handlers and functions needed for ucode initialization flow. Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 157 ++++++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-prph.h | 28 ++++++ 2 files changed, 185 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index b6bdffc5a42..5e818eedb0e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -46,6 +46,16 @@ #define IWL5000_UCODE_API "-1" +static const u16 iwl5000_default_queue_to_tx_fifo[] = { + IWL_TX_FIFO_AC3, + IWL_TX_FIFO_AC2, + IWL_TX_FIFO_AC1, + IWL_TX_FIFO_AC0, + IWL50_CMD_FIFO_NUM, + IWL_TX_FIFO_HCCA_1, + IWL_TX_FIFO_HCCA_2 +}; + static int iwl5000_apm_init(struct iwl_priv *priv) { int ret = 0; @@ -420,6 +430,151 @@ static int iwl5000_load_ucode(struct iwl_priv *priv) return ret; } +static void iwl5000_init_alive_start(struct iwl_priv *priv) +{ + int ret = 0; + + /* Check alive response for "valid" sign from uCode */ + if (priv->card_alive_init.is_valid != UCODE_VALID_OK) { + /* We had an error bringing up the hardware, so take it + * all the way back down so we can try again */ + IWL_DEBUG_INFO("Initialize Alive failed.\n"); + goto restart; + } + + /* initialize uCode was loaded... verify inst image. + * This is a paranoid check, because we would not have gotten the + * "initialize" alive if code weren't properly loaded. */ + if (iwl_verify_ucode(priv)) { + /* Runtime instruction load was bad; + * take it all the way back down so we can try again */ + IWL_DEBUG_INFO("Bad \"initialize\" uCode load.\n"); + goto restart; + } + + iwlcore_clear_stations_table(priv); + ret = priv->cfg->ops->lib->alive_notify(priv); + if (ret) { + IWL_WARNING("Could not complete ALIVE transition: %d\n", ret); + goto restart; + } + + return; + +restart: + /* real restart (first load init_ucode) */ + queue_work(priv->workqueue, &priv->restart); +} + +static void iwl5000_set_wr_ptrs(struct iwl_priv *priv, + int txq_id, u32 index) +{ + iwl_write_direct32(priv, HBUS_TARG_WRPTR, + (index & 0xff) | (txq_id << 8)); + iwl_write_prph(priv, IWL50_SCD_QUEUE_RDPTR(txq_id), index); +} + +static void iwl5000_tx_queue_set_status(struct iwl_priv *priv, + struct iwl_tx_queue *txq, + int tx_fifo_id, int scd_retry) +{ + int txq_id = txq->q.id; + int active = test_bit(txq_id, &priv->txq_ctx_active_msk)?1:0; + + iwl_write_prph(priv, IWL50_SCD_QUEUE_STATUS_BITS(txq_id), + (active << IWL50_SCD_QUEUE_STTS_REG_POS_ACTIVE) | + (tx_fifo_id << IWL50_SCD_QUEUE_STTS_REG_POS_TXF) | + (1 << IWL50_SCD_QUEUE_STTS_REG_POS_WSL) | + IWL50_SCD_QUEUE_STTS_REG_MSK); + + txq->sched_retry = scd_retry; + + IWL_DEBUG_INFO("%s %s Queue %d on AC %d\n", + active ? "Activate" : "Deactivate", + scd_retry ? "BA" : "AC", txq_id, tx_fifo_id); +} + +static int iwl5000_alive_notify(struct iwl_priv *priv) +{ + u32 a; + int i = 0; + unsigned long flags; + int ret; + + spin_lock_irqsave(&priv->lock, flags); + + ret = iwl_grab_nic_access(priv); + if (ret) { + spin_unlock_irqrestore(&priv->lock, flags); + return ret; + } + + priv->scd_base_addr = iwl_read_prph(priv, IWL50_SCD_SRAM_BASE_ADDR); + a = priv->scd_base_addr + IWL50_SCD_CONTEXT_DATA_OFFSET; + for (; a < priv->scd_base_addr + IWL50_SCD_TX_STTS_BITMAP_OFFSET; + a += 4) + iwl_write_targ_mem(priv, a, 0); + for (; a < priv->scd_base_addr + IWL50_SCD_TRANSLATE_TBL_OFFSET; + a += 4) + iwl_write_targ_mem(priv, a, 0); + for (; a < sizeof(u16) * priv->hw_params.max_txq_num; a += 4) + iwl_write_targ_mem(priv, a, 0); + + iwl_write_prph(priv, IWL50_SCD_DRAM_BASE_ADDR, + (priv->shared_phys + + offsetof(struct iwl5000_shared, queues_byte_cnt_tbls)) >> 10); + iwl_write_prph(priv, IWL50_SCD_QUEUECHAIN_SEL, + IWL50_SCD_QUEUECHAIN_SEL_ALL( + priv->hw_params.max_txq_num)); + iwl_write_prph(priv, IWL50_SCD_AGGR_SEL, 0); + + /* initiate the queues */ + for (i = 0; i < priv->hw_params.max_txq_num; i++) { + iwl_write_prph(priv, IWL50_SCD_QUEUE_RDPTR(i), 0); + iwl_write_direct32(priv, HBUS_TARG_WRPTR, 0 | (i << 8)); + iwl_write_targ_mem(priv, priv->scd_base_addr + + IWL50_SCD_CONTEXT_QUEUE_OFFSET(i), 0); + iwl_write_targ_mem(priv, priv->scd_base_addr + + IWL50_SCD_CONTEXT_QUEUE_OFFSET(i) + + sizeof(u32), + ((SCD_WIN_SIZE << + IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) & + IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) | + ((SCD_FRAME_LIMIT << + IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) & + IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK)); + } + + iwl_write_prph(priv, IWL50_SCD_INTERRUPT_MASK, + (1 << priv->hw_params.max_txq_num) - 1); + + iwl_write_prph(priv, IWL50_SCD_TXFACT, + SCD_TXFACT_REG_TXFIFO_MASK(0, 7)); + + iwl5000_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0); + /* map qos queues to fifos one-to-one */ + for (i = 0; i < ARRAY_SIZE(iwl5000_default_queue_to_tx_fifo); i++) { + int ac = iwl5000_default_queue_to_tx_fifo[i]; + iwl_txq_ctx_activate(priv, i); + iwl5000_tx_queue_set_status(priv, &priv->txq[i], ac, 0); + } + /* TODO - need to initialize those FIFOs inside the loop above, + * not only mark them as active */ + iwl_txq_ctx_activate(priv, 4); + iwl_txq_ctx_activate(priv, 7); + iwl_txq_ctx_activate(priv, 8); + iwl_txq_ctx_activate(priv, 9); + + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + /* Ask for statistics now, the uCode will send notification + * periodically after association */ + iwl_send_statistics_request(priv, CMD_ASYNC); + + return 0; +} + static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) { if ((priv->cfg->mod_params->num_of_queues > IWL50_NUM_QUEUES) || @@ -622,6 +777,8 @@ static struct iwl_lib_ops iwl5000_lib = { .disable_tx_fifo = iwl5000_disable_tx_fifo, .rx_handler_setup = iwl5000_rx_handler_setup, .load_ucode = iwl5000_load_ucode, + .init_alive_start = iwl5000_init_alive_start, + .alive_notify = iwl5000_alive_notify, .apm_ops = { .init = iwl5000_apm_init, .config = iwl5000_nic_config, diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index acac629386e..d6a04f65f35 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -517,6 +517,34 @@ #define IWL49_SCD_QUEUE_RA_TID_MAP_RATID_MSK (0x01FF) /* 5000 SCD */ +#define IWL50_SCD_QUEUE_STTS_REG_POS_TXF (0) +#define IWL50_SCD_QUEUE_STTS_REG_POS_ACTIVE (3) +#define IWL50_SCD_QUEUE_STTS_REG_POS_WSL (4) +#define IWL50_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN (19) +#define IWL50_SCD_QUEUE_STTS_REG_MSK (0x00FF0000) + +#define IWL50_SCD_QUEUE_CTX_REG1_CREDIT_POS (8) +#define IWL50_SCD_QUEUE_CTX_REG1_CREDIT_MSK (0x00FFFF00) +#define IWL50_SCD_QUEUE_CTX_REG1_SUPER_CREDIT_POS (24) +#define IWL50_SCD_QUEUE_CTX_REG1_SUPER_CREDIT_MSK (0xFF000000) +#define IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS (0) +#define IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK (0x0000007F) +#define IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS (16) +#define IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK (0x007F0000) + +#define IWL50_SCD_CONTEXT_DATA_OFFSET (0x600) +#define IWL50_SCD_TX_STTS_BITMAP_OFFSET (0x7B1) +#define IWL50_SCD_TRANSLATE_TBL_OFFSET (0x7E0) + +#define IWL50_SCD_CONTEXT_QUEUE_OFFSET(x)\ + (IWL50_SCD_CONTEXT_DATA_OFFSET + ((x) * 8)) + +#define IWL50_SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \ + ((IWL50_SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffc) + +#define IWL50_SCD_QUEUECHAIN_SEL_ALL(x) (((1<<(x)) - 1) &\ + (~(1< Date: Thu, 15 May 2008 13:54:14 +0800 Subject: iwlwifi: iwl5000 WiFi/WiMax coexistence This patch adds WiFi/WiMax coexistence to iwl5000. Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 12 +++++++ drivers/net/wireless/iwlwifi/iwl-commands.h | 54 +++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 5e818eedb0e..520c7eaf1b0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -494,6 +494,16 @@ static void iwl5000_tx_queue_set_status(struct iwl_priv *priv, scd_retry ? "BA" : "AC", txq_id, tx_fifo_id); } +static int iwl5000_send_wimax_coex(struct iwl_priv *priv) +{ + struct iwl_wimax_coex_cmd coex_cmd; + + memset(&coex_cmd, 0, sizeof(coex_cmd)); + + return iwl_send_cmd_pdu(priv, COEX_PRIORITY_TABLE_CMD, + sizeof(coex_cmd), &coex_cmd); +} + static int iwl5000_alive_notify(struct iwl_priv *priv) { u32 a; @@ -568,6 +578,8 @@ static int iwl5000_alive_notify(struct iwl_priv *priv) iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); + iwl5000_send_wimax_coex(priv); + /* Ask for statistics now, the uCode will send notification * periodically after association */ iwl_send_statistics_request(priv, CMD_ASYNC); diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index dd84326c97d..5b9e9bf0ac8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -93,6 +93,11 @@ enum { REPLY_LEDS_CMD = 0x48, REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* 4965 only */ + /* WiMAX coexistence */ + COEX_PRIORITY_TABLE_CMD = 0x5a, /*5000 only */ + COEX_MEDIUM_NOTIFICATION = 0x5b, + COEX_EVENT_CMD = 0x5c, + /* 802.11h related */ RADAR_NOTIFICATION = 0x70, /* not used */ REPLY_QUIET_CMD = 0x71, /* not used */ @@ -2797,6 +2802,55 @@ struct iwl4965_led_cmd { u8 reserved; } __attribute__ ((packed)); +/* + * Coexistence WIFI/WIMAX Command + * COEX_PRIORITY_TABLE_CMD = 0x5a + * + */ +enum { + COEX_UNASSOC_IDLE = 0, + COEX_UNASSOC_MANUAL_SCAN = 1, + COEX_UNASSOC_AUTO_SCAN = 2, + COEX_CALIBRATION = 3, + COEX_PERIODIC_CALIBRATION = 4, + COEX_CONNECTION_ESTAB = 5, + COEX_ASSOCIATED_IDLE = 6, + COEX_ASSOC_MANUAL_SCAN = 7, + COEX_ASSOC_AUTO_SCAN = 8, + COEX_ASSOC_ACTIVE_LEVEL = 9, + COEX_RF_ON = 10, + COEX_RF_OFF = 11, + COEX_STAND_ALONE_DEBUG = 12, + COEX_IPAN_ASSOC_LEVEL = 13, + COEX_RSRVD1 = 14, + COEX_RSRVD2 = 15, + COEX_NUM_OF_EVENTS = 16 +}; + +struct iwl_wimax_coex_event_entry { + u8 request_prio; + u8 win_medium_prio; + u8 reserved; + u8 flags; +} __attribute__ ((packed)); + +/* COEX flag masks */ + +/* Staion table is valid */ +#define COEX_FLAGS_STA_TABLE_VALID_MSK (0x1) +/* UnMask wakeup src at unassociated sleep */ +#define COEX_FLAGS_UNASSOC_WA_UNMASK_MSK (0x4) +/* UnMask wakeup src at associated sleep */ +#define COEX_FLAGS_ASSOC_WA_UNMASK_MSK (0x8) +/* Enable CoEx feature. */ +#define COEX_FLAGS_COEX_ENABLE_MSK (0x80) + +struct iwl_wimax_coex_cmd { + u8 flags; + u8 reserved[3]; + struct iwl_wimax_coex_event_entry sta_prio[COEX_NUM_OF_EVENTS]; +} __attribute__ ((packed)); + /****************************************************************************** * (13) * Union of all expected notifications/responses: -- cgit v1.2.3-70-g09d2 From da6833cb05cd76f4367fa7e4a783bf358c096faf Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 15 May 2008 13:54:15 +0800 Subject: iwlwifi: remove 4965 remainings in iwl-eeprom.c file The patch cleans up 4965 remaings from iwl-eeprom.c file. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-eeprom.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index fa306601a55..300ef8e7415 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -365,11 +365,11 @@ static void iwl_init_band_reference(const struct iwl_priv *priv, ? # x " " : "") /** - * iwl4965_set_fat_chan_info - Copy fat channel info into driver's priv. + * iwl_set_fat_chan_info - Copy fat channel info into driver's priv. * * Does not set up a command, or touch hardware. */ -static int iwl4965_set_fat_chan_info(struct iwl_priv *priv, +static int iwl_set_fat_chan_info(struct iwl_priv *priv, enum ieee80211_band band, u16 channel, const struct iwl_eeprom_channel *eeprom_ch, u8 fat_extension_channel) @@ -542,16 +542,16 @@ int iwl_init_channel_map(struct iwl_priv *priv) fat_extension_chan = HT_IE_EXT_CHANNEL_ABOVE; /* Set up driver's info for lower half */ - iwl4965_set_fat_chan_info(priv, ieeeband, - eeprom_ch_index[ch], - &(eeprom_ch_info[ch]), - fat_extension_chan); + iwl_set_fat_chan_info(priv, ieeeband, + eeprom_ch_index[ch], + &(eeprom_ch_info[ch]), + fat_extension_chan); /* Set up driver's info for upper half */ - iwl4965_set_fat_chan_info(priv, ieeeband, - (eeprom_ch_index[ch] + 4), - &(eeprom_ch_info[ch]), - HT_IE_EXT_CHANNEL_BELOW); + iwl_set_fat_chan_info(priv, ieeeband, + (eeprom_ch_index[ch] + 4), + &(eeprom_ch_info[ch]), + HT_IE_EXT_CHANNEL_BELOW); } } @@ -560,7 +560,7 @@ int iwl_init_channel_map(struct iwl_priv *priv) EXPORT_SYMBOL(iwl_init_channel_map); /* - * iwl_free_channel_map - undo allocations in iwl4965_init_channel_map + * iwl_free_channel_map - undo allocations in iwl_init_channel_map */ void iwl_free_channel_map(struct iwl_priv *priv) { -- cgit v1.2.3-70-g09d2 From 445c2dff409ef9de5d2f964d20917ab238fd266f Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 15 May 2008 13:54:16 +0800 Subject: iwlwifi: add debugfs to disable/enable run time calibration This patch adds functionality to debugfs to enable or disable chain noise or sensitivity calibrations. Signed-off-by: Tomas Winkler Signed-off-by: Emmanuel Grumbach Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-calib.c | 9 +++++++++ drivers/net/wireless/iwlwifi/iwl-calib.h | 4 +++- drivers/net/wireless/iwlwifi/iwl-debug.h | 9 ++++++++- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 20 +++++++++++++++++++- drivers/net/wireless/iwlwifi/iwl-dev.h | 6 +++++- 5 files changed, 44 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index 1289d4c91ab..beb9716165c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -426,6 +426,9 @@ void iwl_init_sensitivity(struct iwl_priv *priv) struct iwl_sensitivity_data *data = NULL; const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens; + if (priv->disable_sens_cal) + return; + IWL_DEBUG_CALIB("Start iwl_init_sensitivity\n"); /* Clear driver's sensitivity algo data */ @@ -486,6 +489,9 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv, unsigned long flags; struct statistics_general_data statis; + if (priv->disable_sens_cal) + return; + data = &(priv->sensitivity_data); if (!iwl_is_associated(priv)) { @@ -608,6 +614,9 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, unsigned long flags; struct statistics_rx_non_phy *rx_info = &(stat_resp->rx.general); + if (priv->disable_chain_noise_cal) + return; + data = &(priv->chain_noise_data); /* Accumulate just the first 20 beacons after the first association, diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.h b/drivers/net/wireless/iwlwifi/iwl-calib.h index 933b0b0a797..e690668f08a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.h +++ b/drivers/net/wireless/iwlwifi/iwl-calib.h @@ -81,7 +81,9 @@ void iwl_init_sensitivity(struct iwl_priv *priv); static inline void iwl_chain_noise_reset(struct iwl_priv *priv) { - if (priv->cfg->ops->utils->chain_noise_reset) + + if (!priv->disable_chain_noise_cal && + priv->cfg->ops->utils->chain_noise_reset) priv->cfg->ops->utils->chain_noise_reset(priv); } #else diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 2f24594c5fe..c3f8e90c5ba 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -45,13 +45,20 @@ struct iwl_debugfs { const char *name; struct dentry *dir_drv; struct dentry *dir_data; - struct dir_data_files{ + struct dentry *dir_rf; + struct dir_data_files { struct dentry *file_sram; struct dentry *file_eeprom; struct dentry *file_stations; struct dentry *file_rx_statistics; struct dentry *file_tx_statistics; } dbgfs_data_files; + struct dir_rf_files { +#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB + struct dentry *file_disable_sensitivity; + struct dentry *file_disable_chain_noise; +#endif /* CONFIG_IWLWIFI_RUN_TIME_CALIB */ + } dbgfs_rf_files; u32 sram_offset; u32 sram_len; }; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index ad25806dfaf..f7ec2009cdf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -55,6 +55,13 @@ goto err; \ } while (0) +#define DEBUGFS_ADD_BOOL(name, parent, ptr) do { \ + dbgfs->dbgfs_##parent##_files.file_##name = \ + debugfs_create_bool(#name, 0644, dbgfs->dir_##parent, ptr); \ + if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name)) \ + goto err; \ +} while (0) + #define DEBUGFS_REMOVE(name) do { \ debugfs_remove(name); \ name = NULL; \ @@ -344,12 +351,17 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) } DEBUGFS_ADD_DIR(data, dbgfs->dir_drv); + DEBUGFS_ADD_DIR(rf, dbgfs->dir_drv); DEBUGFS_ADD_FILE(eeprom, data); DEBUGFS_ADD_FILE(sram, data); DEBUGFS_ADD_FILE(stations, data); DEBUGFS_ADD_FILE(rx_statistics, data); DEBUGFS_ADD_FILE(tx_statistics, data); - +#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB + DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); + DEBUGFS_ADD_BOOL(disable_chain_noise, rf, + &priv->disable_chain_noise_cal); +#endif /* CONFIG_IWLWIFI_RUN_TIME_CALIB */ return 0; err: @@ -374,6 +386,11 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sram); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_stations); DEBUGFS_REMOVE(priv->dbgfs->dir_data); +#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise); +#endif /* CONFIG_IWLWIFI_RUN_TIME_CALIB */ + DEBUGFS_REMOVE(priv->dbgfs->dir_rf); DEBUGFS_REMOVE(priv->dbgfs->dir_drv); kfree(priv->dbgfs); priv->dbgfs = NULL; @@ -381,3 +398,4 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) EXPORT_SYMBOL(iwl_dbgfs_unregister); + diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index b1ff0afd828..820542bac44 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1212,9 +1212,13 @@ struct iwl_priv { #endif /* CONFIG_IWLWIFI_DEBUG */ struct work_struct txpower_work; +#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB + u32 disable_sens_cal; + u32 disable_chain_noise_cal; +#endif /* CONFIG_IWLWIFI_RUN_TIME_CALIB */ #ifdef CONFIG_IWL4965_RUN_TIME_CALIB struct work_struct sensitivity_work; -#endif +#endif /* CONFIG_IWL4965_RUN_TIME_CALIB */ struct timer_list statistics_periodic; }; /*iwl_priv */ -- cgit v1.2.3-70-g09d2 From 6ba879562289bcad537a2374754ef750307c7d32 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 15 May 2008 13:54:17 +0800 Subject: iwlwifi: refactor pci prob flow This patch refactores pci prob flow. It moves mac80211 registration to the end, otherwise there is a race between error path in pci_probe and mac_start. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 61 ++++++++++++++++------------- drivers/net/wireless/iwlwifi/iwl-core.h | 6 +-- drivers/net/wireless/iwlwifi/iwl-eeprom.c | 1 - drivers/net/wireless/iwlwifi/iwl4965-base.c | 31 +++++++++------ 4 files changed, 54 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 79e46c5a35a..21f481ef1ce 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -518,12 +518,6 @@ static int iwlcore_init_geos(struct iwl_priv *priv) priv->bands[IEEE80211_BAND_2GHZ].n_channels, priv->bands[IEEE80211_BAND_5GHZ].n_channels); - if (priv->bands[IEEE80211_BAND_2GHZ].n_channels) - priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = - &priv->bands[IEEE80211_BAND_2GHZ]; - if (priv->bands[IEEE80211_BAND_5GHZ].n_channels) - priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = - &priv->bands[IEEE80211_BAND_5GHZ]; set_bit(STATUS_GEO_CONFIGURED, &priv->status); @@ -533,13 +527,12 @@ static int iwlcore_init_geos(struct iwl_priv *priv) /* * iwlcore_free_geos - undo allocations in iwlcore_init_geos */ -void iwlcore_free_geos(struct iwl_priv *priv) +static void iwlcore_free_geos(struct iwl_priv *priv) { kfree(priv->ieee_channels); kfree(priv->ieee_rates); clear_bit(STATUS_GEO_CONFIGURED, &priv->status); } -EXPORT_SYMBOL(iwlcore_free_geos); #ifdef CONFIG_IWL4965_HT static u8 is_single_rx_stream(struct iwl_priv *priv) @@ -767,8 +760,9 @@ int iwl_set_rxon_channel(struct iwl_priv *priv, } EXPORT_SYMBOL(iwl_set_rxon_channel); -static void iwlcore_init_hw(struct iwl_priv *priv) +int iwl_setup_mac(struct iwl_priv *priv) { + int ret; struct ieee80211_hw *hw = priv->hw; hw->rate_control_algorithm = "iwl-4965-rs"; @@ -782,9 +776,29 @@ static void iwlcore_init_hw(struct iwl_priv *priv) /* Enhanced value; more queues, to support 11n aggregation */ hw->ampdu_queues = 12; #endif /* CONFIG_IWL4965_HT */ + + hw->conf.beacon_int = 100; + + if (priv->bands[IEEE80211_BAND_2GHZ].n_channels) + priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = + &priv->bands[IEEE80211_BAND_2GHZ]; + if (priv->bands[IEEE80211_BAND_5GHZ].n_channels) + priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = + &priv->bands[IEEE80211_BAND_5GHZ]; + + ret = ieee80211_register_hw(priv->hw); + if (ret) { + IWL_ERROR("Failed to register hw (error %d)\n", ret); + return ret; + } + priv->mac80211_registered = 1; + + return 0; } +EXPORT_SYMBOL(iwl_setup_mac); + -static int iwlcore_init_drv(struct iwl_priv *priv) +int iwl_init_drv(struct iwl_priv *priv) { int ret; int i; @@ -821,6 +835,9 @@ static int iwlcore_init_drv(struct iwl_priv *priv) /* Choose which receivers/antennas to use */ iwl_set_rxon_chain(priv); + if (priv->cfg->mod_params->enable_qos) + priv->qos_data.qos_enable = 1; + iwl_reset_qos(priv); priv->qos_data.qos_active = 0; @@ -845,34 +862,22 @@ static int iwlcore_init_drv(struct iwl_priv *priv) goto err_free_channel_map; } - ret = ieee80211_register_hw(priv->hw); - if (ret) { - IWL_ERROR("Failed to register network device (error %d)\n", - ret); - goto err_free_geos; - } - - priv->hw->conf.beacon_int = 100; - priv->mac80211_registered = 1; - return 0; -err_free_geos: - iwlcore_free_geos(priv); err_free_channel_map: iwl_free_channel_map(priv); err: return ret; } +EXPORT_SYMBOL(iwl_init_drv); + -int iwl_setup(struct iwl_priv *priv) +void iwl_uninit_drv(struct iwl_priv *priv) { - int ret = 0; - iwlcore_init_hw(priv); - ret = iwlcore_init_drv(priv); - return ret; + iwlcore_free_geos(priv); + iwl_free_channel_map(priv); } -EXPORT_SYMBOL(iwl_setup); +EXPORT_SYMBOL(iwl_uninit_drv); /* Low level driver call this function to update iwlcore with * driver status. diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index b159fd3c93c..774aa7c8a82 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -175,13 +175,13 @@ void iwl_set_rxon_chain(struct iwl_priv *priv); int iwl_set_rxon_channel(struct iwl_priv *priv, enum ieee80211_band band, u16 channel); -void iwlcore_free_geos(struct iwl_priv *priv); -int iwl_setup(struct iwl_priv *priv); void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info); u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, struct ieee80211_ht_info *sta_ht_inf); int iwl_hw_nic_init(struct iwl_priv *priv); - +int iwl_setup_mac(struct iwl_priv *priv); +int iwl_init_drv(struct iwl_priv *priv); +void iwl_uninit_drv(struct iwl_priv *priv); /* "keep warm" functions */ int iwl_kw_init(struct iwl_priv *priv); int iwl_kw_alloc(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 300ef8e7415..e559c19fd36 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -567,7 +567,6 @@ void iwl_free_channel_map(struct iwl_priv *priv) kfree(priv->channel_info); priv->channel_count = 0; } -EXPORT_SYMBOL(iwl_free_channel_map); /** * iwl_get_channel_info - Find driver's private channel info diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index e06142d9da5..05edde17830 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -5878,10 +5878,10 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e } /******************* - * 6. Setup hw/priv + * 6. Setup priv *******************/ - err = iwl_setup(priv); + err = iwl_init_drv(priv); if (err) goto out_free_eeprom; /* At this point both hw and priv are initialized. */ @@ -5896,9 +5896,6 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e IWL_DEBUG_INFO("Radio disabled.\n"); } - if (priv->cfg->mod_params->enable_qos) - priv->qos_data.qos_enable = 1; - /******************** * 8. Setup services ********************/ @@ -5909,14 +5906,9 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e err = sysfs_create_group(&pdev->dev.kobj, &iwl4965_attribute_group); if (err) { IWL_ERROR("failed to create sysfs device attributes\n"); - goto out_free_eeprom; + goto out_uninit_drv; } - err = iwl_dbgfs_register(priv, DRV_NAME); - if (err) { - IWL_ERROR("failed to create debugfs files\n"); - goto out_remove_sysfs; - } iwl4965_setup_deferred_work(priv); iwl4965_setup_rx_handlers(priv); @@ -5927,12 +5919,26 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e pci_save_state(pdev); pci_disable_device(pdev); + /********************************** + * 10. Setup and register mac80211 + **********************************/ + + err = iwl_setup_mac(priv); + if (err) + goto out_remove_sysfs; + + err = iwl_dbgfs_register(priv, DRV_NAME); + if (err) + IWL_ERROR("failed to create debugfs files\n"); + /* notify iwlcore to init */ iwlcore_low_level_notify(priv, IWLCORE_INIT_EVT); return 0; out_remove_sysfs: sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group); + out_uninit_drv: + iwl_uninit_drv(priv); out_free_eeprom: iwl_eeprom_free(priv); out_iounmap: @@ -6014,8 +6020,7 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); - iwl_free_channel_map(priv); - iwlcore_free_geos(priv); + iwl_uninit_drv(priv); if (priv->ibss_beacon) dev_kfree_skb(priv->ibss_beacon); -- cgit v1.2.3-70-g09d2 From 189a2b5942d62bd18e1e01772c4c784253f5dd16 Mon Sep 17 00:00:00 2001 From: Ester Kummer Date: Thu, 15 May 2008 13:54:18 +0800 Subject: iwlwifi: trigger event log from debugfs This patch adds a trigger for event log printing to debugfs. It removes the triger from sysfs. Signed-off-by: Ester Kummer Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 101 ++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-core.h | 8 ++ drivers/net/wireless/iwlwifi/iwl-debug.h | 1 + drivers/net/wireless/iwlwifi/iwl-debugfs.c | 32 ++++++++ drivers/net/wireless/iwlwifi/iwl4965-base.c | 114 +--------------------------- 5 files changed, 143 insertions(+), 113 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 21f481ef1ce..7e25ca45f67 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1055,3 +1055,104 @@ int iwl_verify_ucode(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_verify_ucode); + +#define EVENT_START_OFFSET (4 * sizeof(u32)) + +/** + * iwl_print_event_log - Dump error event log to syslog + * + * NOTE: Must be called with iwl4965_grab_nic_access() already obtained! + */ +void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, + u32 num_events, u32 mode) +{ + u32 i; + u32 base; /* SRAM byte address of event log header */ + u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */ + u32 ptr; /* SRAM byte address of log data */ + u32 ev, time, data; /* event log data */ + + if (num_events == 0) + return; + + base = le32_to_cpu(priv->card_alive.log_event_table_ptr); + + if (mode == 0) + event_size = 2 * sizeof(u32); + else + event_size = 3 * sizeof(u32); + + ptr = base + EVENT_START_OFFSET + (start_idx * event_size); + + /* "time" is actually "data" for mode 0 (no timestamp). + * place event id # at far right for easier visual parsing. */ + for (i = 0; i < num_events; i++) { + ev = iwl_read_targ_mem(priv, ptr); + ptr += sizeof(u32); + time = iwl_read_targ_mem(priv, ptr); + ptr += sizeof(u32); + if (mode == 0) + IWL_ERROR("0x%08x\t%04u\n", time, ev); /* data, ev */ + else { + data = iwl_read_targ_mem(priv, ptr); + ptr += sizeof(u32); + IWL_ERROR("%010u\t0x%08x\t%04u\n", time, data, ev); + } + } +} +EXPORT_SYMBOL(iwl_print_event_log); + + +void iwl_dump_nic_event_log(struct iwl_priv *priv) +{ + int rc; + u32 base; /* SRAM byte address of event log header */ + u32 capacity; /* event log capacity in # entries */ + u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */ + u32 num_wraps; /* # times uCode wrapped to top of log */ + u32 next_entry; /* index of next entry to be written by uCode */ + u32 size; /* # entries that we'll print */ + + base = le32_to_cpu(priv->card_alive.log_event_table_ptr); + if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { + IWL_ERROR("Invalid event log pointer 0x%08X\n", base); + return; + } + + rc = iwl_grab_nic_access(priv); + if (rc) { + IWL_WARNING("Can not read from adapter at this time.\n"); + return; + } + + /* event log header */ + capacity = iwl_read_targ_mem(priv, base); + mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32))); + num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32))); + next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32))); + + size = num_wraps ? capacity : next_entry; + + /* bail out if nothing in log */ + if (size == 0) { + IWL_ERROR("Start IWL Event Log Dump: nothing in log\n"); + iwl_release_nic_access(priv); + return; + } + + IWL_ERROR("Start IWL Event Log Dump: display count %d, wraps %d\n", + size, num_wraps); + + /* if uCode has wrapped back to top of log, start at the oldest entry, + * i.e the next one that uCode would fill. */ + if (num_wraps) + iwl_print_event_log(priv, next_entry, + capacity - next_entry, mode); + /* (then/else) start at top of log */ + iwl_print_event_log(priv, 0, next_entry, mode); + + iwl_release_nic_access(priv); +} +EXPORT_SYMBOL(iwl_dump_nic_event_log); + + diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 774aa7c8a82..a8d062f7b87 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -232,6 +232,14 @@ int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len, struct sk_buff *skb)); int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd); + +/***************************************************** +* Error Handling Debugging +******************************************************/ +void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, + u32 num_events, u32 mode); +void iwl_dump_nic_event_log(struct iwl_priv *priv); + /*************** DRIVER STATUS FUNCTIONS *****/ #define STATUS_HCMD_ACTIVE 0 /* host command in progress */ diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index c3f8e90c5ba..11de561c7bf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -52,6 +52,7 @@ struct iwl_debugfs { struct dentry *file_stations; struct dentry *file_rx_statistics; struct dentry *file_tx_statistics; + struct dentry *file_log_event; } dbgfs_data_files; struct dir_rf_files { #ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index f7ec2009cdf..c64e602bc9b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -92,6 +92,14 @@ static const struct file_operations iwl_dbgfs_##name##_ops = { \ .open = iwl_dbgfs_open_file_generic, \ }; +#define DEBUGFS_WRITE_FILE_OPS(name) \ + DEBUGFS_WRITE_FUNC(name); \ +static const struct file_operations iwl_dbgfs_##name##_ops = { \ + .write = iwl_dbgfs_##name##_write, \ + .open = iwl_dbgfs_open_file_generic, \ +}; + + #define DEBUGFS_READ_WRITE_FILE_OPS(name) \ DEBUGFS_READ_FUNC(name); \ DEBUGFS_WRITE_FUNC(name); \ @@ -324,7 +332,29 @@ static ssize_t iwl_dbgfs_eeprom_read(struct file *file, return ret; } +static ssize_t iwl_dbgfs_log_event_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = file->private_data; + u32 event_log_flag; + char buf[8]; + int buf_size; + + memset(buf, 0, sizeof(buf)); + buf_size = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + if (sscanf(buf, "%d", &event_log_flag) != 1) + return -EFAULT; + if (event_log_flag == 1) + iwl_dump_nic_event_log(priv); + + return count; +} + DEBUGFS_READ_WRITE_FILE_OPS(sram); +DEBUGFS_WRITE_FILE_OPS(log_event); DEBUGFS_READ_FILE_OPS(eeprom); DEBUGFS_READ_FILE_OPS(stations); DEBUGFS_READ_FILE_OPS(rx_statistics); @@ -354,6 +384,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_DIR(rf, dbgfs->dir_drv); DEBUGFS_ADD_FILE(eeprom, data); DEBUGFS_ADD_FILE(sram, data); + DEBUGFS_ADD_FILE(log_event, data); DEBUGFS_ADD_FILE(stations, data); DEBUGFS_ADD_FILE(rx_statistics, data); DEBUGFS_ADD_FILE(tx_statistics, data); @@ -384,6 +415,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_rx_statistics); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_tx_statistics); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sram); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_log_event); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_stations); DEBUGFS_REMOVE(priv->dbgfs->dir_data); #ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 05edde17830..48c59cbefb4 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -2692,103 +2692,6 @@ static void iwl4965_dump_nic_error_log(struct iwl_priv *priv) iwl_release_nic_access(priv); } -#define EVENT_START_OFFSET (4 * sizeof(u32)) - -/** - * iwl4965_print_event_log - Dump error event log to syslog - * - * NOTE: Must be called with iwl_grab_nic_access() already obtained! - */ -static void iwl4965_print_event_log(struct iwl_priv *priv, u32 start_idx, - u32 num_events, u32 mode) -{ - u32 i; - u32 base; /* SRAM byte address of event log header */ - u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */ - u32 ptr; /* SRAM byte address of log data */ - u32 ev, time, data; /* event log data */ - - if (num_events == 0) - return; - - base = le32_to_cpu(priv->card_alive.log_event_table_ptr); - - if (mode == 0) - event_size = 2 * sizeof(u32); - else - event_size = 3 * sizeof(u32); - - ptr = base + EVENT_START_OFFSET + (start_idx * event_size); - - /* "time" is actually "data" for mode 0 (no timestamp). - * place event id # at far right for easier visual parsing. */ - for (i = 0; i < num_events; i++) { - ev = iwl_read_targ_mem(priv, ptr); - ptr += sizeof(u32); - time = iwl_read_targ_mem(priv, ptr); - ptr += sizeof(u32); - if (mode == 0) - IWL_ERROR("0x%08x\t%04u\n", time, ev); /* data, ev */ - else { - data = iwl_read_targ_mem(priv, ptr); - ptr += sizeof(u32); - IWL_ERROR("%010u\t0x%08x\t%04u\n", time, data, ev); - } - } -} - -static void iwl4965_dump_nic_event_log(struct iwl_priv *priv) -{ - int rc; - u32 base; /* SRAM byte address of event log header */ - u32 capacity; /* event log capacity in # entries */ - u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */ - u32 num_wraps; /* # times uCode wrapped to top of log */ - u32 next_entry; /* index of next entry to be written by uCode */ - u32 size; /* # entries that we'll print */ - - base = le32_to_cpu(priv->card_alive.log_event_table_ptr); - if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { - IWL_ERROR("Invalid event log pointer 0x%08X\n", base); - return; - } - - rc = iwl_grab_nic_access(priv); - if (rc) { - IWL_WARNING("Can not read from adapter at this time.\n"); - return; - } - - /* event log header */ - capacity = iwl_read_targ_mem(priv, base); - mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32))); - num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32))); - next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32))); - - size = num_wraps ? capacity : next_entry; - - /* bail out if nothing in log */ - if (size == 0) { - IWL_ERROR("Start IWL Event Log Dump: nothing in log\n"); - iwl_release_nic_access(priv); - return; - } - - IWL_ERROR("Start IWL Event Log Dump: display count %d, wraps %d\n", - size, num_wraps); - - /* if uCode has wrapped back to top of log, start at the oldest entry, - * i.e the next one that uCode would fill. */ - if (num_wraps) - iwl4965_print_event_log(priv, next_entry, - capacity - next_entry, mode); - - /* (then/else) start at top of log */ - iwl4965_print_event_log(priv, 0, next_entry, mode); - - iwl_release_nic_access(priv); -} - /** * iwl4965_irq_handle_error - called for HW or SW error interrupt from card */ @@ -2803,7 +2706,7 @@ static void iwl4965_irq_handle_error(struct iwl_priv *priv) #ifdef CONFIG_IWLWIFI_DEBUG if (priv->debug_level & IWL_DL_FW_ERRORS) { iwl4965_dump_nic_error_log(priv); - iwl4965_dump_nic_event_log(priv); + iwl_dump_nic_event_log(priv); iwl4965_print_rx_config_cmd(priv); } #endif @@ -5640,20 +5543,6 @@ static ssize_t dump_error_log(struct device *d, static DEVICE_ATTR(dump_errors, S_IWUSR, NULL, dump_error_log); -static ssize_t dump_event_log(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - char *p = (char *)buf; - - if (p[0] == '1') - iwl4965_dump_nic_event_log((struct iwl_priv *)d->driver_data); - - return strnlen(buf, count); -} - -static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log); - /***************************************************************************** * * driver setup and teardown @@ -5700,7 +5589,6 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv) static struct attribute *iwl4965_sysfs_entries[] = { &dev_attr_channels.attr, &dev_attr_dump_errors.attr, - &dev_attr_dump_events.attr, &dev_attr_flags.attr, &dev_attr_filter_flags.attr, #ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT -- cgit v1.2.3-70-g09d2 From 36d6825b91bc492b65b6333c369cd96a2fc8c903 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 15 May 2008 12:55:26 +0200 Subject: mac80211: let drivers wake but not start queues Having drivers start queues is just confusing, their ->start() callback can block and do whatever is necessary, so let mac80211 start queues and have drivers wake queues when necessary (to get packets flowing again right away.) Signed-off-by: Johannes Berg Acked-by: David S. Miller Signed-off-by: John W. Linville --- drivers/net/wireless/adm8211.c | 2 +- drivers/net/wireless/ath5k/base.c | 2 +- drivers/net/wireless/b43/main.c | 1 - drivers/net/wireless/b43legacy/main.c | 1 - drivers/net/wireless/iwlwifi/iwl3945-base.c | 2 +- drivers/net/wireless/iwlwifi/iwl4965-base.c | 2 +- drivers/net/wireless/p54/p54common.c | 3 --- drivers/net/wireless/p54/p54pci.c | 2 +- drivers/net/wireless/rt2x00/rt2x00dev.c | 4 ++-- include/net/mac80211.h | 8 -------- net/mac80211/main.c | 8 +++++++- net/mac80211/util.c | 12 ------------ 12 files changed, 14 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 7af5d8851f6..79dfca546c8 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -2015,7 +2015,7 @@ static int adm8211_resume(struct pci_dev *pdev) if (priv->mode != IEEE80211_IF_TYPE_INVALID) { adm8211_start(dev); - ieee80211_start_queues(dev); + ieee80211_wake_queues(dev); } return 0; diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index c76ada17878..3f16ad66bdb 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -1599,7 +1599,7 @@ ath5k_txq_cleanup(struct ath5k_softc *sc) sc->txqs[i].link); } } - ieee80211_start_queues(sc->hw); /* XXX move to callers */ + ieee80211_wake_queues(sc->hw); /* XXX move to callers */ for (i = 0; i < ARRAY_SIZE(sc->txqs); i++) if (sc->txqs[i].setup) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index fc23ba5309b..9445a604a96 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3497,7 +3497,6 @@ static int b43_wireless_core_start(struct b43_wldev *dev) /* Start data flow (TX/RX). */ b43_mac_enable(dev); b43_interrupt_enable(dev, dev->irq_savedstate); - ieee80211_start_queues(dev->wl->hw); /* Start maintainance work */ b43_periodic_tasks_setup(dev); diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 7755c59e080..b05a507ed44 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -2794,7 +2794,6 @@ static int b43legacy_wireless_core_start(struct b43legacy_wldev *dev) /* Start data flow (TX/RX) */ b43legacy_mac_enable(dev); b43legacy_interrupt_enable(dev, dev->irq_savedstate); - ieee80211_start_queues(dev->wl->hw); /* Start maintenance work */ b43legacy_periodic_tasks_setup(dev); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index b8fb8d8d95f..54cde8a7b5f 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -5823,7 +5823,7 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv) if (iwl3945_is_rfkill(priv)) return; - ieee80211_start_queues(priv->hw); + ieee80211_wake_queues(priv->hw); priv->active_rate = priv->rates_mask; priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK; diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 48c59cbefb4..db4f606bad5 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -3367,7 +3367,7 @@ static void iwl4965_alive_start(struct iwl_priv *priv) if (iwl_is_rfkill(priv)) return; - ieee80211_start_queues(priv->hw); + ieee80211_wake_queues(priv->hw); priv->active_rate = priv->rates_mask; priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK; diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 9cbef5bce0f..3d35fe6a8f5 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -375,9 +375,6 @@ static void inline p54_wake_free_queues(struct ieee80211_hw *dev) struct p54_common *priv = dev->priv; int i; - /* ieee80211_start_queues is great if all queues are really empty. - * But, what if some are full? */ - for (i = 0; i < dev->queues; i++) if (priv->tx_stats[i].len < priv->tx_stats[i].limit) ieee80211_wake_queue(dev, i); diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index fa527723fbe..7dd4add4bf4 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -665,7 +665,7 @@ static int p54p_resume(struct pci_dev *pdev) if (priv->common.mode != IEEE80211_IF_TYPE_INVALID) { p54p_open(dev); - ieee80211_start_queues(dev); + ieee80211_wake_queues(dev); } return 0; diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 171f445962d..d341764e1b2 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -125,7 +125,7 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) /* * Start the TX queues. */ - ieee80211_start_queues(rt2x00dev->hw); + ieee80211_wake_queues(rt2x00dev->hw); return 0; } @@ -1186,7 +1186,7 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) * In that case we have disabled the TX queue and should * now enable it again */ - ieee80211_start_queues(rt2x00dev->hw); + ieee80211_wake_queues(rt2x00dev->hw); /* * During interface iteration we might have changed the diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 909956c97c4..f00fc76a734 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1566,14 +1566,6 @@ void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue); */ void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue); -/** - * ieee80211_start_queues - start all queues - * @hw: pointer to as obtained from ieee80211_alloc_hw(). - * - * Drivers should use this function instead of netif_start_queue. - */ -void ieee80211_start_queues(struct ieee80211_hw *hw); - /** * ieee80211_stop_queues - stop all queues * @hw: pointer as obtained from ieee80211_alloc_hw(). diff --git a/net/mac80211/main.c b/net/mac80211/main.c index b0fddb7de54..9761d9bd5a7 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -110,7 +110,13 @@ static int ieee80211_master_open(struct net_device *dev) break; } } - return res; + + if (res) + return res; + + netif_start_queue(local->mdev); + + return 0; } static int ieee80211_master_stop(struct net_device *dev) diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 9cd07e1031a..800c15aff6e 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -350,18 +350,6 @@ void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue) } EXPORT_SYMBOL(ieee80211_stop_queue); -void ieee80211_start_queues(struct ieee80211_hw *hw) -{ - struct ieee80211_local *local = hw_to_local(hw); - int i; - - for (i = 0; i < hw->queues + hw->ampdu_queues; i++) - clear_bit(IEEE80211_LINK_STATE_XOFF, &local->state[i]); - if (!ieee80211_qdisc_installed(local->mdev)) - netif_start_queue(local->mdev); -} -EXPORT_SYMBOL(ieee80211_start_queues); - void ieee80211_stop_queues(struct ieee80211_hw *hw) { int i; -- cgit v1.2.3-70-g09d2 From 2e92e6f2c50b4baf85cca968f0e6f1b5c0df7d39 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 15 May 2008 12:55:27 +0200 Subject: mac80211: use rate index in TX control This patch modifies struct ieee80211_tx_control to give band info and the rate index (instead of rate pointers) to drivers. This mostly serves to reduce the TX control structure size to make it fit into skb->cb so that the fragmentation code can put it there and we can think about passing it to drivers that way in the future. The rt2x00 driver update was done by Ivo, thanks. Signed-off-by: Ivo van Doorn Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/adm8211.c | 6 +- drivers/net/wireless/ath5k/base.c | 8 ++- drivers/net/wireless/b43/main.c | 2 +- drivers/net/wireless/b43/xmit.c | 13 ++-- drivers/net/wireless/b43legacy/xmit.c | 9 ++- drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 6 +- drivers/net/wireless/iwlwifi/iwl-3945.c | 7 +- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 12 ++-- drivers/net/wireless/iwlwifi/iwl-4965.c | 10 +-- drivers/net/wireless/iwlwifi/iwl-tx.c | 8 ++- drivers/net/wireless/iwlwifi/iwl3945-base.c | 4 +- drivers/net/wireless/iwlwifi/iwl4965-base.c | 2 +- drivers/net/wireless/p54/p54common.c | 2 +- drivers/net/wireless/rt2x00/rt2x00queue.c | 9 ++- drivers/net/wireless/rtl8180_dev.c | 19 +++-- drivers/net/wireless/rtl8187_dev.c | 10 +-- drivers/net/wireless/zd1211rw/zd_mac.c | 7 +- include/net/mac80211.h | 51 ++++++++++---- net/mac80211/ieee80211_i.h | 8 +-- net/mac80211/mlme.c | 6 +- net/mac80211/rate.c | 12 ++-- net/mac80211/rate.h | 25 +++---- net/mac80211/rc80211_pid_algo.c | 6 +- net/mac80211/tx.c | 104 ++++++++++++++++------------ net/mac80211/util.c | 10 ++- 25 files changed, 205 insertions(+), 151 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 79dfca546c8..22db664a58d 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -1693,10 +1693,10 @@ static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb, size_t payload_len, hdrlen; int plcp, dur, len, plcp_signal, short_preamble; struct ieee80211_hdr *hdr; + struct ieee80211_rate *txrate = ieee80211_get_tx_rate(dev, control); - short_preamble = !!(control->tx_rate->flags & - IEEE80211_TXCTL_SHORT_PREAMBLE); - plcp_signal = control->tx_rate->bitrate; + short_preamble = !!(txrate->flags & IEEE80211_TXCTL_SHORT_PREAMBLE); + plcp_signal = txrate->bitrate; hdr = (struct ieee80211_hdr *)skb->data; fc = le16_to_cpu(hdr->frame_control) & ~IEEE80211_FCTL_PROTECTED; diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 3f16ad66bdb..32ee351a765 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -1323,7 +1323,8 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, ret = ah->ah_setup_tx_desc(ah, ds, pktlen, ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL, - (sc->power_level * 2), ctl->tx_rate->hw_value, + (sc->power_level * 2), + ieee80211_get_tx_rate(sc->hw, ctl)->hw_value, ctl->retry_limit, keyidx, 0, flags, 0, 0); if (ret) goto err_unmap; @@ -2046,7 +2047,8 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, ret = ah->ah_setup_tx_desc(ah, ds, skb->len, ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_BEACON, (sc->power_level * 2), - ctl->tx_rate->hw_value, 1, AR5K_TXKEYIX_INVALID, + ieee80211_get_tx_rate(sc->hw, ctl)->hw_value, + 1, AR5K_TXKEYIX_INVALID, antenna, flags, 0, 0); if (ret) goto err_unmap; @@ -2654,7 +2656,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb, memmove(skb->data, skb->data+pad, hdrlen); } - sc->led_txrate = ctl->tx_rate->hw_value; + sc->led_txrate = ieee80211_get_tx_rate(hw, ctl)->hw_value; spin_lock_irqsave(&sc->txbuflock, flags); if (list_empty(&sc->txbuf)) { diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 9445a604a96..e428645352b 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1372,7 +1372,7 @@ static void b43_write_beacon_template(struct b43_wldev *dev, bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data); len = min((size_t) dev->wl->current_beacon->len, 0x200 - sizeof(struct b43_plcp_hdr6)); - rate = dev->wl->beacon_txctl.tx_rate->hw_value; + rate = ieee80211_get_tx_rate(dev->wl->hw, &dev->wl->beacon_txctl)->hw_value; b43_write_template_common(dev, (const u8 *)bcn, len, ram_offset, shm_size_offset, rate); diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index afce9338d83..9b682a3cf5e 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -201,13 +201,14 @@ int b43_generate_txhdr(struct b43_wldev *dev, u32 mac_ctl = 0; u16 phy_ctl = 0; u8 extra_ft = 0; + struct ieee80211_rate *txrate; memset(txhdr, 0, sizeof(*txhdr)); - WARN_ON(!txctl->tx_rate); - rate = txctl->tx_rate ? txctl->tx_rate->hw_value : B43_CCK_RATE_1MB; + txrate = ieee80211_get_tx_rate(dev->wl->hw, txctl); + rate = txrate ? txrate->hw_value : B43_CCK_RATE_1MB; rate_ofdm = b43_is_ofdm_rate(rate); - fbrate = txctl->alt_retry_rate ? : txctl->tx_rate; + fbrate = ieee80211_get_alt_retry_rate(dev->wl->hw, txctl) ? : txrate; rate_fb = fbrate->hw_value; rate_fb_ofdm = b43_is_ofdm_rate(rate_fb); @@ -336,9 +337,11 @@ int b43_generate_txhdr(struct b43_wldev *dev, int rts_rate, rts_rate_fb; int rts_rate_ofdm, rts_rate_fb_ofdm; struct b43_plcp_hdr6 *plcp; + struct ieee80211_rate *rts_cts_rate; - WARN_ON(!txctl->rts_cts_rate); - rts_rate = txctl->rts_cts_rate ? txctl->rts_cts_rate->hw_value : B43_CCK_RATE_1MB; + rts_cts_rate = ieee80211_get_rts_cts_rate(dev->wl->hw, txctl); + + rts_rate = rts_cts_rate ? rts_cts_rate->hw_value : B43_CCK_RATE_1MB; rts_rate_ofdm = b43_is_ofdm_rate(rts_rate); rts_rate_fb = b43_calc_fallback_rate(rts_rate); rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb); diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c index bed9e041d6c..55dc251bf51 100644 --- a/drivers/net/wireless/b43legacy/xmit.c +++ b/drivers/net/wireless/b43legacy/xmit.c @@ -201,15 +201,18 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, unsigned int plcp_fragment_len; u32 mac_ctl = 0; u16 phy_ctl = 0; + struct ieee80211_rate *tx_rate; wlhdr = (const struct ieee80211_hdr *)fragment_data; fctl = le16_to_cpu(wlhdr->frame_control); memset(txhdr, 0, sizeof(*txhdr)); - rate = txctl->tx_rate->hw_value; + tx_rate = ieee80211_get_tx_rate(dev->wl->hw, txctl); + + rate = tx_rate->hw_value; rate_ofdm = b43legacy_is_ofdm_rate(rate); - rate_fb = txctl->alt_retry_rate ? : txctl->tx_rate; + rate_fb = ieee80211_get_alt_retry_rate(dev->wl->hw, txctl) ? : tx_rate; rate_fb_ofdm = b43legacy_is_ofdm_rate(rate_fb->hw_value); txhdr->mac_frame_ctl = wlhdr->frame_control; @@ -312,7 +315,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, int rts_rate_ofdm; int rts_rate_fb_ofdm; - rts_rate = txctl->rts_cts_rate->hw_value; + rts_rate = ieee80211_get_rts_cts_rate(dev->wl->hw, txctl)->hw_value; rts_rate_ofdm = b43legacy_is_ofdm_rate(rts_rate); rts_rate_fb = b43legacy_calc_fallback_rate(rts_rate); rts_rate_fb_ofdm = b43legacy_is_ofdm_rate(rts_rate_fb); diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index e51eeeff699..f3ca02fe961 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -464,7 +464,7 @@ static void rs_tx_status(void *priv_rate, retries = tx_resp->retry_count; - first_index = tx_resp->control.tx_rate->hw_value; + first_index = sband->bitrates[tx_resp->control.tx_rate_idx].hw_value; if ((first_index < 0) || (first_index >= IWL_RATE_COUNT)) { IWL_DEBUG_RATE("leave: Rate out of bounds: %d\n", first_index); return; @@ -669,7 +669,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, is_multicast_ether_addr(hdr->addr1) || !sta || !sta->rate_ctrl_priv) { IWL_DEBUG_RATE("leave: No STA priv data to update!\n"); - sel->rate = rate_lowest(local, sband, sta); + sel->rate_idx = rate_lowest_index(local, sband, sta); rcu_read_unlock(); return; } @@ -813,7 +813,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, IWL_DEBUG_RATE("leave: %d\n", index); - sel->rate = &sband->bitrates[sta->txrate_idx]; + sel->rate_idx = sta->txrate_idx; } static struct rate_control_ops rs_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index ad4e7b74ca2..f8e691f88ab 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -331,7 +331,9 @@ static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv, tx_resp->rate, tx_resp->failure_frame); rate_idx = iwl3945_hwrate_to_plcp_idx(tx_resp->rate); - tx_status->control.tx_rate = &priv->ieee_rates[rate_idx]; + if (tx_status->control.band == IEEE80211_BAND_5GHZ) + rate_idx -= IWL_FIRST_OFDM_RATE; + tx_status->control.tx_rate_idx = rate_idx; IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); iwl3945_tx_queue_reclaim(priv, txq_id, index); @@ -962,7 +964,8 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl3945_priv *priv, struct ieee80211_hdr *hdr, int sta_id, int tx_id) { unsigned long flags; - u16 rate_index = min(ctrl->tx_rate->hw_value & 0xffff, IWL_RATE_COUNT - 1); + u16 hw_value = ieee80211_get_tx_rate(priv->hw, ctrl)->hw_value; + u16 rate_index = min(hw_value & 0xffff, IWL_RATE_COUNT - 1); u16 rate_mask; int rate; u8 rts_retry_limit; diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index 2adc2281c77..7993a1d8302 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -862,7 +862,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, if (priv->band == IEEE80211_BAND_5GHZ) rs_index -= IWL_FIRST_OFDM_RATE; - if ((tx_resp->control.tx_rate == NULL) || + if ((tx_resp->control.tx_rate_idx < 0) || (tbl_type.is_SGI ^ !!(tx_resp->control.flags & IEEE80211_TXCTL_SHORT_GI)) || (tbl_type.is_fat ^ @@ -875,7 +875,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, (!!(tx_rate & RATE_MCS_GF_MSK) ^ !!(tx_resp->control.flags & IEEE80211_TXCTL_GREEN_FIELD)) || (hw->wiphy->bands[priv->band]->bitrates[rs_index].bitrate != - tx_resp->control.tx_rate->bitrate)) { + hw->wiphy->bands[tx_resp->control.band]->bitrates[tx_resp->control.tx_rate_idx].bitrate)) { IWL_DEBUG_RATE("initial rate does not match 0x%x\n", tx_rate); goto out; } @@ -2154,7 +2154,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, fc = le16_to_cpu(hdr->frame_control); if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) || !sta || !sta->rate_ctrl_priv) { - sel->rate = rate_lowest(local, sband, sta); + sel->rate_idx = rate_lowest_index(local, sband, sta); goto out; } @@ -2184,11 +2184,13 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, done: if ((i < 0) || (i > IWL_RATE_COUNT)) { - sel->rate = rate_lowest(local, sband, sta); + sel->rate_idx = rate_lowest_index(local, sband, sta); goto out; } - sel->rate = &priv->ieee_rates[i]; + if (sband->band == IEEE80211_BAND_5GHZ) + i -= IWL_FIRST_OFDM_RATE; + sel->rate_idx = i; out: rcu_read_unlock(); } diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index f848a5b0f62..fb670b5cfeb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -373,14 +373,10 @@ void iwl4965_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, control->flags |= IEEE80211_TXCTL_DUP_DATA; if (rate_n_flags & RATE_MCS_SGI_MSK) control->flags |= IEEE80211_TXCTL_SHORT_GI; - /* since iwl4965_hwrate_to_plcp_idx is band indifferent, we always use - * IEEE80211_BAND_2GHZ band as it contains all the rates */ rate_index = iwl4965_hwrate_to_plcp_idx(rate_n_flags); - if (rate_index == -1) - control->tx_rate = NULL; - else - control->tx_rate = - &priv->bands[IEEE80211_BAND_2GHZ].bitrates[rate_index]; + if (control->band == IEEE80211_BAND_5GHZ) + rate_index -= IWL_FIRST_OFDM_RATE; + control->tx_rate_idx = rate_index; } int iwl4965_hw_rxq_stop(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index f32cddabdf6..4b5149c8c32 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -578,7 +578,10 @@ static void iwl_tx_cmd_build_rate(struct iwl_priv *priv, u8 data_retry_limit = 0; u8 rate_plcp; u16 rate_flags = 0; - int rate_idx = min(ctrl->tx_rate->hw_value & 0xffff, IWL_RATE_COUNT - 1); + int rate_idx; + + rate_idx = min(ieee80211_get_tx_rate(priv->hw, ctrl)->hw_value & 0xffff, + IWL_RATE_COUNT - 1); rate_plcp = iwl_rates[rate_idx].plcp; @@ -723,7 +726,8 @@ int iwl_tx_skb(struct iwl_priv *priv, goto drop_unlock; } - if ((ctl->tx_rate->hw_value & 0xFF) == IWL_INVALID_RATE) { + if ((ieee80211_get_tx_rate(priv->hw, ctl)->hw_value & 0xFF) == + IWL_INVALID_RATE) { IWL_ERROR("ERROR: No TX rate available.\n"); goto drop_unlock; } diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 54cde8a7b5f..a28b4c9f652 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2581,7 +2581,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, goto drop_unlock; } - if ((ctl->tx_rate->hw_value & 0xFF) == IWL_INVALID_RATE) { + if ((ieee80211_get_tx_rate(priv->hw, ctl)->hw_value & 0xFF) == IWL_INVALID_RATE) { IWL_ERROR("ERROR: No TX rate available.\n"); goto drop_unlock; } @@ -6694,7 +6694,7 @@ static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, } IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, - ctl->tx_rate->bitrate); + ieee80211_get_tx_rate(hw, ctl)->bitrate); if (iwl3945_tx_skb(priv, skb, ctl)) dev_kfree_skb_any(skb); diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index db4f606bad5..1fad6227aa5 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -4281,7 +4281,7 @@ static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, } IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, - ctl->tx_rate->bitrate); + ieee80211_get_tx_rate(hw, ctl)->bitrate); if (iwl_tx_skb(priv, skb, ctl)) dev_kfree_skb_any(skb); diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 3d35fe6a8f5..3ca9386561f 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -592,7 +592,7 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb, txhdr->padding2 = 0; /* TODO: add support for alternate retry TX rates */ - rate = control->tx_rate->hw_value; + rate = ieee80211_get_tx_rate(dev, control)->hw_value; if (control->flags & IEEE80211_TXCTL_SHORT_PREAMBLE) rate |= 0x10; if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 19c10629c76..5cf4c2f5926 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -33,8 +33,10 @@ void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, struct txentry_desc *txdesc, struct ieee80211_tx_control *control) { + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data; - struct ieee80211_rate *rate = control->tx_rate; + struct ieee80211_rate *rate = + ieee80211_get_tx_rate(rt2x00dev->hw, control); const struct rt2x00_rate *hwrate; unsigned int data_length; unsigned int duration; @@ -77,8 +79,9 @@ void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, __set_bit(ENTRY_TXD_CTS_FRAME, &txdesc->flags); __clear_bit(ENTRY_TXD_ACK, &txdesc->flags); } - if (control->rts_cts_rate) - rate = control->rts_cts_rate; + if (control->rts_cts_rate_idx >= 0) + rate = + ieee80211_get_rts_cts_rate(rt2x00dev->hw, control); } /* diff --git a/drivers/net/wireless/rtl8180_dev.c b/drivers/net/wireless/rtl8180_dev.c index c220998cee6..6263209b889 100644 --- a/drivers/net/wireless/rtl8180_dev.c +++ b/drivers/net/wireless/rtl8180_dev.c @@ -257,24 +257,21 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb, mapping = pci_map_single(priv->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); - BUG_ON(!control->tx_rate); - tx_flags = RTL8180_TX_DESC_FLAG_OWN | RTL8180_TX_DESC_FLAG_FS | RTL8180_TX_DESC_FLAG_LS | - (control->tx_rate->hw_value << 24) | skb->len; + (ieee80211_get_tx_rate(dev, control)->hw_value << 24) | + skb->len; if (priv->r8185) tx_flags |= RTL8180_TX_DESC_FLAG_DMA | RTL8180_TX_DESC_FLAG_NO_ENC; if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) { - BUG_ON(!control->rts_cts_rate); tx_flags |= RTL8180_TX_DESC_FLAG_RTS; - tx_flags |= control->rts_cts_rate->hw_value << 19; + tx_flags |= ieee80211_get_rts_cts_rate(dev, control)->hw_value << 19; } else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { - BUG_ON(!control->rts_cts_rate); tx_flags |= RTL8180_TX_DESC_FLAG_CTS; - tx_flags |= control->rts_cts_rate->hw_value << 19; + tx_flags |= ieee80211_get_rts_cts_rate(dev, control)->hw_value << 19; } *((struct ieee80211_tx_control **) skb->cb) = @@ -288,9 +285,9 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb, unsigned int remainder; plcp_len = DIV_ROUND_UP(16 * (skb->len + 4), - (control->tx_rate->bitrate * 2) / 10); + (ieee80211_get_tx_rate(dev, control)->bitrate * 2) / 10); remainder = (16 * (skb->len + 4)) % - ((control->tx_rate->bitrate * 2) / 10); + ((ieee80211_get_tx_rate(dev, control)->bitrate * 2) / 10); if (remainder > 0 && remainder <= 6) plcp_len |= 1 << 15; } @@ -303,8 +300,8 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb, entry->plcp_len = cpu_to_le16(plcp_len); entry->tx_buf = cpu_to_le32(mapping); entry->frame_len = cpu_to_le32(skb->len); - entry->flags2 = control->alt_retry_rate != NULL ? - control->alt_retry_rate->bitrate << 4 : 0; + entry->flags2 = control->alt_retry_rate_idx >= 0 ? + ieee80211_get_alt_retry_rate(dev, control)->bitrate << 4 : 0; entry->retry_limit = control->retry_limit; entry->flags = cpu_to_le32(tx_flags); __skb_queue_tail(&ring->queue, skb); diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index e14c8424868..86a09b49681 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -179,21 +179,17 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb, flags = skb->len; flags |= RTL8187_TX_FLAG_NO_ENCRYPT; - BUG_ON(!control->tx_rate); - - flags |= control->tx_rate->hw_value << 24; + flags |= ieee80211_get_tx_rate(dev, control)->hw_value << 24; if (ieee80211_get_morefrag((struct ieee80211_hdr *)skb->data)) flags |= RTL8187_TX_FLAG_MORE_FRAG; if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) { - BUG_ON(!control->rts_cts_rate); flags |= RTL8187_TX_FLAG_RTS; - flags |= control->rts_cts_rate->hw_value << 19; + flags |= ieee80211_get_rts_cts_rate(dev, control)->hw_value << 19; rts_dur = ieee80211_rts_duration(dev, priv->vif, skb->len, control); } else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { - BUG_ON(!control->rts_cts_rate); flags |= RTL8187_TX_FLAG_CTS; - flags |= control->rts_cts_rate->hw_value << 19; + flags |= ieee80211_get_rts_cts_rate(dev, control)->hw_value << 19; } hdr = (struct rtl8187_tx_hdr *)skb_push(skb, sizeof(*hdr)); diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 0c736735e21..99c508c09e5 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -523,14 +523,17 @@ static int fill_ctrlset(struct zd_mac *mac, struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; unsigned int frag_len = skb->len + FCS_LEN; unsigned int packet_length; + struct ieee80211_rate *txrate; struct zd_ctrlset *cs = (struct zd_ctrlset *) skb_push(skb, sizeof(struct zd_ctrlset)); ZD_ASSERT(frag_len <= 0xffff); - cs->modulation = control->tx_rate->hw_value; + txrate = ieee80211_get_tx_rate(mac->hw, control); + + cs->modulation = txrate->hw_value; if (control->flags & IEEE80211_TXCTL_SHORT_PREAMBLE) - cs->modulation = control->tx_rate->hw_value_short; + cs->modulation = txrate->hw_value_short; cs->tx_length = cpu_to_le16(frag_len); diff --git a/include/net/mac80211.h b/include/net/mac80211.h index f00fc76a734..0df91bea6c1 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -266,27 +266,26 @@ enum mac80211_tx_control_flags { * ieee80211_ops->remove_interface() callback funtion. * The hw_key pointer is valid until it has been removed with the * ieee80211_ops->set_key() callback function. - * The tx_rate and alt_retry_rate pointers are valid until the phy is - * deregistered. */ struct ieee80211_tx_control { - struct ieee80211_vif *vif; - struct ieee80211_rate *tx_rate; + u32 flags; /* tx control flags defined above */ + + s8 tx_rate_idx, /* Transmit rate (indexes registered rates) */ + rts_cts_rate_idx, /* Transmit rate for RTS/CTS frame */ + alt_retry_rate_idx; /* retry rate for the last retries */ - /* Transmit rate for RTS/CTS frame */ - struct ieee80211_rate *rts_cts_rate; + s8 retry_limit; /* 1 = only first attempt, 2 = one retry, .. + * This could be used when set_retry_limit + * is not implemented by the driver */ - /* retry rate for the last retries */ - struct ieee80211_rate *alt_retry_rate; + struct ieee80211_vif *vif; /* Key used for hardware encryption * NULL if IEEE80211_TXCTL_DO_NOT_ENCRYPT is set */ struct ieee80211_key_conf *hw_key; - u32 flags; /* tx control flags defined above */ - u8 retry_limit; /* 1 = only first attempt, 2 = one retry, .. - * This could be used when set_retry_limit - * is not implemented by the driver */ + enum ieee80211_band band; + u8 antenna_sel_tx; /* 0 = default/diversity, otherwise bit * position represents antenna number used */ u8 icv_len; /* length of the ICV/MIC field in octets */ @@ -298,6 +297,7 @@ struct ieee80211_tx_control { }; + /** * enum mac80211_rx_flags - receive flags * @@ -823,6 +823,33 @@ static inline void SET_IEEE80211_PERM_ADDR(struct ieee80211_hw *hw, u8 *addr) memcpy(hw->wiphy->perm_addr, addr, ETH_ALEN); } +static inline struct ieee80211_rate * +ieee80211_get_tx_rate(const struct ieee80211_hw *hw, + const struct ieee80211_tx_control *c) +{ + if (WARN_ON(c->tx_rate_idx < 0)) + return NULL; + return &hw->wiphy->bands[c->band]->bitrates[c->tx_rate_idx]; +} + +static inline struct ieee80211_rate * +ieee80211_get_rts_cts_rate(const struct ieee80211_hw *hw, + const struct ieee80211_tx_control *c) +{ + if (c->rts_cts_rate_idx < 0) + return NULL; + return &hw->wiphy->bands[c->band]->bitrates[c->rts_cts_rate_idx]; +} + +static inline struct ieee80211_rate * +ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw, + const struct ieee80211_tx_control *c) +{ + if (c->alt_retry_rate_idx < 0) + return NULL; + return &hw->wiphy->bands[c->band]->bitrates[c->alt_retry_rate_idx]; +} + /** * DOC: Hardware crypto acceleration * diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index ed0d9b35ae6..a4cccd1b7d5 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -159,11 +159,11 @@ struct ieee80211_tx_data { struct ieee80211_tx_control *control; struct ieee80211_channel *channel; - struct ieee80211_rate *rate; + s8 rate_idx; /* use this rate (if set) for last fragment; rate can * be set to lower rate for the first fragments, e.g., * when using CTS protection with IEEE 802.11g. */ - struct ieee80211_rate *last_frag_rate; + s8 last_frag_rate_idx; /* Extra fragments (in addition to the first fragment * in skb) */ @@ -225,9 +225,9 @@ struct ieee80211_tx_stored_packet { struct ieee80211_tx_control control; struct sk_buff *skb; struct sk_buff **extra_frag; - struct ieee80211_rate *last_frag_rate; + s8 last_frag_rate_idx; int num_extra_frag; - unsigned int last_frag_rate_ctrl_probe; + bool last_frag_rate_ctrl_probe; }; struct beacon_data { diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 7877d3b3f4c..604149369dc 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2406,15 +2406,15 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, memset(&control, 0, sizeof(control)); rate_control_get_rate(dev, sband, skb, &ratesel); - if (!ratesel.rate) { + if (ratesel.rate_idx < 0) { printk(KERN_DEBUG "%s: Failed to determine TX rate " "for IBSS beacon\n", dev->name); break; } control.vif = &sdata->vif; - control.tx_rate = ratesel.rate; + control.tx_rate_idx = ratesel.rate_idx; if (sdata->bss_conf.use_short_preamble && - ratesel.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) + sband->bitrates[ratesel.rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE) control.flags |= IEEE80211_TXCTL_SHORT_PREAMBLE; control.antenna_sel_tx = local->hw.conf.antenna_sel_tx; control.flags |= IEEE80211_TXCTL_NO_ACK; diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 841df93807f..0388c090dfe 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -176,20 +176,24 @@ void rate_control_get_rate(struct net_device *dev, rcu_read_lock(); sta = sta_info_get(local, hdr->addr1); - memset(sel, 0, sizeof(struct rate_selection)); + sel->rate_idx = -1; + sel->nonerp_idx = -1; + sel->probe_idx = -1; ref->ops->get_rate(ref->priv, dev, sband, skb, sel); + BUG_ON(sel->rate_idx < 0); + /* Select a non-ERP backup rate. */ - if (!sel->nonerp) { + if (sel->nonerp_idx < 0) { for (i = 0; i < sband->n_bitrates; i++) { struct ieee80211_rate *rate = &sband->bitrates[i]; - if (sel->rate->bitrate < rate->bitrate) + if (sband->bitrates[sel->rate_idx].bitrate < rate->bitrate) break; if (rate_supported(sta, sband->band, i) && !(rate->flags & IEEE80211_RATE_ERP_G)) - sel->nonerp = rate; + sel->nonerp_idx = i; } } diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index 5b45f33cb76..a29148dcca9 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h @@ -19,14 +19,15 @@ #include "ieee80211_i.h" #include "sta_info.h" -/* TODO: kdoc */ +/** + * struct rate_selection - rate selection for rate control algos + * @rate: selected transmission rate index + * @nonerp: Non-ERP rate to use instead if ERP cannot be used + * @probe: rate for probing (or -1) + * + */ struct rate_selection { - /* Selected transmission rate */ - struct ieee80211_rate *rate; - /* Non-ERP rate to use if mac80211 decides it cannot use an ERP rate */ - struct ieee80211_rate *nonerp; - /* probe with this rate, or NULL for no probing */ - struct ieee80211_rate *probe; + s8 rate_idx, nonerp_idx, probe_idx; }; struct rate_control_ops { @@ -138,7 +139,7 @@ static inline int rate_supported(struct sta_info *sta, return (sta == NULL || sta->supp_rates[band] & BIT(index)); } -static inline int +static inline s8 rate_lowest_index(struct ieee80211_local *local, struct ieee80211_supported_band *sband, struct sta_info *sta) @@ -155,14 +156,6 @@ rate_lowest_index(struct ieee80211_local *local, return 0; } -static inline struct ieee80211_rate * -rate_lowest(struct ieee80211_local *local, - struct ieee80211_supported_band *sband, - struct sta_info *sta) -{ - return &sband->bitrates[rate_lowest_index(local, sband, sta)]; -} - /* functions for rate control related to a device */ int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c index a849b745bdb..14cde36f507 100644 --- a/net/mac80211/rc80211_pid_algo.c +++ b/net/mac80211/rc80211_pid_algo.c @@ -266,7 +266,7 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev, /* Ignore all frames that were sent with a different rate than the rate * we currently advise mac80211 to use. */ - if (status->control.tx_rate != &sband->bitrates[sta->txrate_idx]) + if (status->control.tx_rate_idx != sta->txrate_idx) goto unlock; spinfo = sta->rate_ctrl_priv; @@ -330,7 +330,7 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev, fc = le16_to_cpu(hdr->frame_control); if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || is_multicast_ether_addr(hdr->addr1) || !sta) { - sel->rate = rate_lowest(local, sband, sta); + sel->rate_idx = rate_lowest_index(local, sband, sta); rcu_read_unlock(); return; } @@ -349,7 +349,7 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev, rcu_read_unlock(); - sel->rate = &sband->bitrates[rateidx]; + sel->rate_idx = rateidx; #ifdef CONFIG_MAC80211_DEBUGFS rate_control_pid_event_tx_rate( diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index aecec2a72b0..99c3860bc0e 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -91,11 +91,12 @@ static u16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr, int next_frag_len) { int rate, mrate, erp, dur, i; - struct ieee80211_rate *txrate = tx->rate; + struct ieee80211_rate *txrate; struct ieee80211_local *local = tx->local; struct ieee80211_supported_band *sband; - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + sband = local->hw.wiphy->bands[tx->channel->band]; + txrate = &sband->bitrates[tx->rate_idx]; erp = 0; if (tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) @@ -610,40 +611,40 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) struct rate_selection rsel; struct ieee80211_supported_band *sband; - sband = tx->local->hw.wiphy->bands[tx->local->hw.conf.channel->band]; + sband = tx->local->hw.wiphy->bands[tx->channel->band]; - if (likely(!tx->rate)) { + if (likely(tx->rate_idx < 0)) { rate_control_get_rate(tx->dev, sband, tx->skb, &rsel); - tx->rate = rsel.rate; - if (unlikely(rsel.probe)) { + tx->rate_idx = rsel.rate_idx; + if (unlikely(rsel.probe_idx >= 0)) { tx->control->flags |= IEEE80211_TXCTL_RATE_CTRL_PROBE; tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG; - tx->control->alt_retry_rate = tx->rate; - tx->rate = rsel.probe; + tx->control->alt_retry_rate_idx = tx->rate_idx; + tx->rate_idx = rsel.probe_idx; } else - tx->control->alt_retry_rate = NULL; + tx->control->alt_retry_rate_idx = -1; - if (!tx->rate) + if (unlikely(tx->rate_idx < 0)) return TX_DROP; } else - tx->control->alt_retry_rate = NULL; + tx->control->alt_retry_rate_idx = -1; if (tx->sdata->bss_conf.use_cts_prot && - (tx->flags & IEEE80211_TX_FRAGMENTED) && rsel.nonerp) { - tx->last_frag_rate = tx->rate; - if (rsel.probe) + (tx->flags & IEEE80211_TX_FRAGMENTED) && (rsel.nonerp_idx >= 0)) { + tx->last_frag_rate_idx = tx->rate_idx; + if (rsel.probe_idx >= 0) tx->flags &= ~IEEE80211_TX_PROBE_LAST_FRAG; else tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG; - tx->rate = rsel.nonerp; - tx->control->tx_rate = rsel.nonerp; + tx->rate_idx = rsel.nonerp_idx; + tx->control->tx_rate_idx = rsel.nonerp_idx; tx->control->flags &= ~IEEE80211_TXCTL_RATE_CTRL_PROBE; } else { - tx->last_frag_rate = tx->rate; - tx->control->tx_rate = tx->rate; + tx->last_frag_rate_idx = tx->rate_idx; + tx->control->tx_rate_idx = tx->rate_idx; } - tx->control->tx_rate = tx->rate; + tx->control->tx_rate_idx = tx->rate_idx; return TX_CONTINUE; } @@ -655,6 +656,9 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) u16 fc = le16_to_cpu(hdr->frame_control); u16 dur; struct ieee80211_tx_control *control = tx->control; + struct ieee80211_supported_band *sband; + + sband = tx->local->hw.wiphy->bands[tx->channel->band]; if (!control->retry_limit) { if (!is_multicast_ether_addr(hdr->addr1)) { @@ -681,14 +685,14 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) * frames. * TODO: The last fragment could still use multiple retry * rates. */ - control->alt_retry_rate = NULL; + control->alt_retry_rate_idx = -1; } /* Use CTS protection for unicast frames sent using extended rates if * there are associated non-ERP stations and RTS/CTS is not configured * for the frame. */ if ((tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) && - (tx->rate->flags & IEEE80211_RATE_ERP_G) && + (sband->bitrates[tx->rate_idx].flags & IEEE80211_RATE_ERP_G) && (tx->flags & IEEE80211_TX_UNICAST) && tx->sdata->bss_conf.use_cts_prot && !(control->flags & IEEE80211_TXCTL_USE_RTS_CTS)) @@ -698,7 +702,7 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) * short preambles at the selected rate and short preambles are * available on the network at the current point in time. */ if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && - (tx->rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) && + (sband->bitrates[tx->rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE) && tx->sdata->bss_conf.use_short_preamble && (!tx->sta || test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE))) { tx->control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE; @@ -715,32 +719,32 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) || (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) { struct ieee80211_supported_band *sband; - struct ieee80211_rate *rate, *baserate; + struct ieee80211_rate *rate; + s8 baserate = -1; int idx; - sband = tx->local->hw.wiphy->bands[ - tx->local->hw.conf.channel->band]; + sband = tx->local->hw.wiphy->bands[tx->channel->band]; /* Do not use multiple retry rates when using RTS/CTS */ - control->alt_retry_rate = NULL; + control->alt_retry_rate_idx = -1; /* Use min(data rate, max base rate) as CTS/RTS rate */ - rate = tx->rate; - baserate = NULL; + rate = &sband->bitrates[tx->rate_idx]; for (idx = 0; idx < sband->n_bitrates; idx++) { if (sband->bitrates[idx].bitrate > rate->bitrate) continue; if (tx->sdata->basic_rates & BIT(idx) && - (!baserate || - (baserate->bitrate < sband->bitrates[idx].bitrate))) - baserate = &sband->bitrates[idx]; + (baserate < 0 || + (sband->bitrates[baserate].bitrate + < sband->bitrates[idx].bitrate))) + baserate = idx; } - if (baserate) - control->rts_cts_rate = baserate; + if (baserate >= 0) + control->rts_cts_rate_idx = baserate; else - control->rts_cts_rate = &sband->bitrates[0]; + control->rts_cts_rate_idx = 0; } if (tx->sta) { @@ -768,7 +772,11 @@ ieee80211_tx_h_load_stats(struct ieee80211_tx_data *tx) struct sk_buff *skb = tx->skb; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; u32 load = 0, hdrtime; - struct ieee80211_rate *rate = tx->rate; + struct ieee80211_rate *rate; + struct ieee80211_supported_band *sband; + + sband = tx->local->hw.wiphy->bands[tx->channel->band]; + rate = &sband->bitrates[tx->rate_idx]; /* TODO: this could be part of tx_status handling, so that the number * of retries would be known; TX rate should in that case be stored @@ -803,7 +811,7 @@ ieee80211_tx_h_load_stats(struct ieee80211_tx_data *tx) for (i = 0; i < tx->num_extra_frag; i++) { load += 2 * hdrtime; load += tx->extra_frag[i]->len * - tx->rate->bitrate; + rate->bitrate; } } @@ -859,7 +867,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len); struct ieee80211_tx_control *control = tx->control; - sband = tx->local->hw.wiphy->bands[tx->local->hw.conf.channel->band]; + sband = tx->local->hw.wiphy->bands[tx->channel->band]; control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; tx->flags |= IEEE80211_TX_INJECTED; @@ -899,7 +907,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, r = &sband->bitrates[i]; if (r->bitrate == target_rate) { - tx->rate = r; + tx->rate_idx = i; break; } } @@ -1097,7 +1105,7 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, if (__ieee80211_queue_stopped(local, control->queue)) return IEEE80211_TX_FRAG_AGAIN; if (i == tx->num_extra_frag) { - control->tx_rate = tx->last_frag_rate; + control->tx_rate_idx = tx->last_frag_rate_idx; if (tx->flags & IEEE80211_TX_PROBE_LAST_FRAG) control->flags |= @@ -1155,6 +1163,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, sta = tx.sta; tx.channel = local->hw.conf.channel; + control->band = tx.channel->band; for (handler = ieee80211_tx_handlers; *handler != NULL; handler++) { @@ -1187,7 +1196,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, next_len = tx.extra_frag[i + 1]->len; } else { next_len = 0; - tx.rate = tx.last_frag_rate; + tx.rate_idx = tx.last_frag_rate_idx; } dur = ieee80211_duration(&tx, 0, next_len); hdr->duration_id = cpu_to_le16(dur); @@ -1224,7 +1233,7 @@ retry: store->skb = skb; store->extra_frag = tx.extra_frag; store->num_extra_frag = tx.num_extra_frag; - store->last_frag_rate = tx.last_frag_rate; + store->last_frag_rate_idx = tx.last_frag_rate_idx; store->last_frag_rate_ctrl_probe = !!(tx.flags & IEEE80211_TX_PROBE_LAST_FRAG); } @@ -1685,7 +1694,7 @@ void ieee80211_tx_pending(unsigned long data) tx.control = &store->control; tx.extra_frag = store->extra_frag; tx.num_extra_frag = store->num_extra_frag; - tx.last_frag_rate = store->last_frag_rate; + tx.last_frag_rate_idx = store->last_frag_rate_idx; tx.flags = 0; if (store->last_frag_rate_ctrl_probe) tx.flags |= IEEE80211_TX_PROBE_LAST_FRAG; @@ -1789,9 +1798,10 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, struct ieee80211_mgmt *mgmt; int *num_beacons; bool err = true; + enum ieee80211_band band = local->hw.conf.channel->band; u8 *pos; - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + sband = local->hw.wiphy->bands[band]; rcu_read_lock(); @@ -1885,8 +1895,9 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, } if (control) { + control->band = band; rate_control_get_rate(local->mdev, sband, skb, &rsel); - if (!rsel.rate) { + if (unlikely(rsel.rate_idx < 0)) { if (net_ratelimit()) { printk(KERN_DEBUG "%s: ieee80211_beacon_get: " "no rate found\n", @@ -1898,9 +1909,9 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, } control->vif = vif; - control->tx_rate = rsel.rate; + control->tx_rate_idx = rsel.rate_idx; if (sdata->bss_conf.use_short_preamble && - rsel.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) + sband->bitrates[rsel.rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE) control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE; control->antenna_sel_tx = local->hw.conf.antenna_sel_tx; control->flags |= IEEE80211_TXCTL_NO_ACK; @@ -2006,6 +2017,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, sta = tx.sta; tx.flags |= IEEE80211_TX_PS_BUFFERED; tx.channel = local->hw.conf.channel; + control->band = tx.channel->band; for (handler = ieee80211_tx_handlers; *handler != NULL; handler++) { res = (*handler)(&tx); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 800c15aff6e..65a34fddeb0 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -266,10 +266,13 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, bool short_preamble; int erp; u16 dur; + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; short_preamble = sdata->bss_conf.use_short_preamble; - rate = frame_txctl->rts_cts_rate; + rate = &sband->bitrates[frame_txctl->rts_cts_rate_idx]; erp = 0; if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) @@ -300,10 +303,13 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, bool short_preamble; int erp; u16 dur; + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; short_preamble = sdata->bss_conf.use_short_preamble; - rate = frame_txctl->rts_cts_rate; + rate = &sband->bitrates[frame_txctl->rts_cts_rate_idx]; erp = 0; if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) erp = rate->flags & IEEE80211_RATE_ERP_G; -- cgit v1.2.3-70-g09d2 From e039fa4a4195ac4ee895e6f3d1334beed63256fe Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 15 May 2008 12:55:29 +0200 Subject: mac80211: move TX info into skb->cb This patch converts mac80211 and all drivers to have transmit information and status in skb->cb rather than allocating extra memory for it and copying all the data around. To make it fit, a union is used where only data that is necessary for all steps is kept outside of the union. A number of fixes were done by Ivo, as well as the rt2x00 part of this patch. Signed-off-by: Ivo van Doorn Signed-off-by: Johannes Berg Acked-by: David S. Miller Signed-off-by: John W. Linville --- drivers/net/wireless/adm8211.c | 31 ++- drivers/net/wireless/adm8211.h | 1 - drivers/net/wireless/ath5k/base.c | 70 +++---- drivers/net/wireless/ath5k/base.h | 1 - drivers/net/wireless/b43/b43.h | 1 - drivers/net/wireless/b43/dma.c | 45 ++-- drivers/net/wireless/b43/dma.h | 3 +- drivers/net/wireless/b43/main.c | 33 ++- drivers/net/wireless/b43/pio.c | 36 ++-- drivers/net/wireless/b43/pio.h | 8 +- drivers/net/wireless/b43/xmit.c | 58 +++--- drivers/net/wireless/b43/xmit.h | 4 +- drivers/net/wireless/b43legacy/dma.c | 36 ++-- drivers/net/wireless/b43legacy/dma.h | 4 +- drivers/net/wireless/b43legacy/main.c | 12 +- drivers/net/wireless/b43legacy/pio.c | 19 +- drivers/net/wireless/b43legacy/pio.h | 4 +- drivers/net/wireless/b43legacy/xmit.c | 44 ++-- drivers/net/wireless/b43legacy/xmit.h | 2 +- drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 12 +- drivers/net/wireless/iwlwifi/iwl-3945.c | 24 +-- drivers/net/wireless/iwlwifi/iwl-3945.h | 3 +- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 49 +++-- drivers/net/wireless/iwlwifi/iwl-4965.c | 28 +-- drivers/net/wireless/iwlwifi/iwl-core.h | 3 +- drivers/net/wireless/iwlwifi/iwl-dev.h | 5 +- drivers/net/wireless/iwlwifi/iwl-tx.c | 40 ++-- drivers/net/wireless/iwlwifi/iwl3945-base.c | 48 ++--- drivers/net/wireless/iwlwifi/iwl4965-base.c | 52 ++--- drivers/net/wireless/p54/p54common.c | 90 ++++---- drivers/net/wireless/p54/p54common.h | 1 - drivers/net/wireless/rt2x00/rt2400pci.c | 8 +- drivers/net/wireless/rt2x00/rt2500pci.c | 8 +- drivers/net/wireless/rt2x00/rt2500usb.c | 9 +- drivers/net/wireless/rt2x00/rt2x00.h | 10 +- drivers/net/wireless/rt2x00/rt2x00dev.c | 49 +++-- drivers/net/wireless/rt2x00/rt2x00mac.c | 74 ++++--- drivers/net/wireless/rt2x00/rt2x00pci.c | 11 +- drivers/net/wireless/rt2x00/rt2x00pci.h | 6 +- drivers/net/wireless/rt2x00/rt2x00queue.c | 31 ++- drivers/net/wireless/rt2x00/rt2x00queue.h | 15 +- drivers/net/wireless/rt2x00/rt2x00usb.c | 12 +- drivers/net/wireless/rt2x00/rt2x00usb.h | 9 +- drivers/net/wireless/rt2x00/rt61pci.c | 8 +- drivers/net/wireless/rt2x00/rt73usb.c | 8 +- drivers/net/wireless/rtl8180_dev.c | 57 +++-- drivers/net/wireless/rtl8187.h | 6 - drivers/net/wireless/rtl8187_dev.c | 41 ++-- drivers/net/wireless/zd1211rw/zd_mac.c | 156 ++++---------- drivers/net/wireless/zd1211rw/zd_mac.h | 16 -- drivers/net/wireless/zd1211rw/zd_usb.c | 6 +- include/net/mac80211.h | 299 ++++++++++++--------------- net/mac80211/ieee80211_i.h | 18 +- net/mac80211/main.c | 128 ++++-------- net/mac80211/mlme.c | 30 +-- net/mac80211/rate.h | 8 +- net/mac80211/rc80211_pid.h | 4 +- net/mac80211/rc80211_pid_algo.c | 18 +- net/mac80211/rc80211_pid_debugfs.c | 8 +- net/mac80211/rx.c | 10 +- net/mac80211/sta_info.c | 6 +- net/mac80211/sta_info.h | 2 +- net/mac80211/tx.c | 310 ++++++++++++++-------------- net/mac80211/util.c | 10 +- net/mac80211/wep.c | 9 +- net/mac80211/wme.c | 22 +- net/mac80211/wpa.c | 65 +++--- 67 files changed, 980 insertions(+), 1274 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 22db664a58d..0ba55ba9395 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -324,7 +324,7 @@ static void adm8211_interrupt_tci(struct ieee80211_hw *dev) for (dirty_tx = priv->dirty_tx; priv->cur_tx - dirty_tx; dirty_tx++) { unsigned int entry = dirty_tx % priv->tx_ring_size; u32 status = le32_to_cpu(priv->tx_ring[entry].status); - struct ieee80211_tx_status tx_status; + struct ieee80211_tx_info *txi; struct adm8211_tx_ring_info *info; struct sk_buff *skb; @@ -334,24 +334,23 @@ static void adm8211_interrupt_tci(struct ieee80211_hw *dev) info = &priv->tx_buffers[entry]; skb = info->skb; + txi = IEEE80211_SKB_CB(skb); /* TODO: check TDES0_STATUS_TUF and TDES0_STATUS_TRO */ pci_unmap_single(priv->pdev, info->mapping, info->skb->len, PCI_DMA_TODEVICE); - memset(&tx_status, 0, sizeof(tx_status)); + memset(&txi->status, 0, sizeof(txi->status)); skb_pull(skb, sizeof(struct adm8211_tx_hdr)); memcpy(skb_push(skb, info->hdrlen), skb->cb, info->hdrlen); - memcpy(&tx_status.control, &info->tx_control, - sizeof(tx_status.control)); - if (!(tx_status.control.flags & IEEE80211_TXCTL_NO_ACK)) { + if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK)) { if (status & TDES0_STATUS_ES) - tx_status.excessive_retries = 1; + txi->status.excessive_retries = 1; else - tx_status.flags |= IEEE80211_TX_STATUS_ACK; + txi->flags |= IEEE80211_TX_STAT_ACK; } - ieee80211_tx_status_irqsafe(dev, skb, &tx_status); + ieee80211_tx_status_irqsafe(dev, skb); info->skb = NULL; } @@ -1638,7 +1637,6 @@ static void adm8211_calc_durations(int *dur, int *plcp, size_t payload_len, int /* Transmit skb w/adm8211_tx_hdr (802.11 header created by hardware) */ static void adm8211_tx_raw(struct ieee80211_hw *dev, struct sk_buff *skb, u16 plcp_signal, - struct ieee80211_tx_control *control, size_t hdrlen) { struct adm8211_priv *priv = dev->priv; @@ -1664,7 +1662,6 @@ static void adm8211_tx_raw(struct ieee80211_hw *dev, struct sk_buff *skb, priv->tx_buffers[entry].skb = skb; priv->tx_buffers[entry].mapping = mapping; - memcpy(&priv->tx_buffers[entry].tx_control, control, sizeof(*control)); priv->tx_buffers[entry].hdrlen = hdrlen; priv->tx_ring[entry].buffer1 = cpu_to_le32(mapping); @@ -1685,17 +1682,17 @@ static void adm8211_tx_raw(struct ieee80211_hw *dev, struct sk_buff *skb, } /* Put adm8211_tx_hdr on skb and transmit */ -static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb, - struct ieee80211_tx_control *control) +static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb) { struct adm8211_tx_hdr *txhdr; u16 fc; size_t payload_len, hdrlen; int plcp, dur, len, plcp_signal, short_preamble; struct ieee80211_hdr *hdr; - struct ieee80211_rate *txrate = ieee80211_get_tx_rate(dev, control); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_rate *txrate = ieee80211_get_tx_rate(dev, info); - short_preamble = !!(txrate->flags & IEEE80211_TXCTL_SHORT_PREAMBLE); + short_preamble = !!(txrate->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE); plcp_signal = txrate->bitrate; hdr = (struct ieee80211_hdr *)skb->data; @@ -1730,15 +1727,15 @@ static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb, if (short_preamble) txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_SHORT_PREAMBLE); - if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) + if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_RTS); if (fc & IEEE80211_FCTL_PROTECTED) txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_WEP_ENGINE); - txhdr->retry_limit = control->retry_limit; + txhdr->retry_limit = info->control.retry_limit; - adm8211_tx_raw(dev, skb, plcp_signal, control, hdrlen); + adm8211_tx_raw(dev, skb, plcp_signal, hdrlen); return NETDEV_TX_OK; } diff --git a/drivers/net/wireless/adm8211.h b/drivers/net/wireless/adm8211.h index 8d7c564b3b0..9b190ee26e9 100644 --- a/drivers/net/wireless/adm8211.h +++ b/drivers/net/wireless/adm8211.h @@ -443,7 +443,6 @@ struct adm8211_rx_ring_info { struct adm8211_tx_ring_info { struct sk_buff *skb; dma_addr_t mapping; - struct ieee80211_tx_control tx_control; size_t hdrlen; }; diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 32ee351a765..7d97934265d 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -167,8 +167,7 @@ static struct pci_driver ath5k_pci_driver = { /* * Prototypes - MAC 802.11 stack related functions */ -static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *ctl); +static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb); static int ath5k_reset(struct ieee80211_hw *hw); static int ath5k_start(struct ieee80211_hw *hw); static void ath5k_stop(struct ieee80211_hw *hw); @@ -196,8 +195,7 @@ static int ath5k_get_tx_stats(struct ieee80211_hw *hw, static u64 ath5k_get_tsf(struct ieee80211_hw *hw); static void ath5k_reset_tsf(struct ieee80211_hw *hw); static int ath5k_beacon_update(struct ieee80211_hw *hw, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl); + struct sk_buff *skb); static struct ieee80211_ops ath5k_hw_ops = { .tx = ath5k_tx, @@ -251,9 +249,7 @@ static void ath5k_desc_free(struct ath5k_softc *sc, static int ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf); static int ath5k_txbuf_setup(struct ath5k_softc *sc, - struct ath5k_buf *bf, - struct ieee80211_tx_control *ctl); - + struct ath5k_buf *bf); static inline void ath5k_txbuf_free(struct ath5k_softc *sc, struct ath5k_buf *bf) { @@ -289,8 +285,7 @@ static void ath5k_tx_processq(struct ath5k_softc *sc, static void ath5k_tasklet_tx(unsigned long data); /* Beacon handling */ static int ath5k_beacon_setup(struct ath5k_softc *sc, - struct ath5k_buf *bf, - struct ieee80211_tx_control *ctl); + struct ath5k_buf *bf); static void ath5k_beacon_send(struct ath5k_softc *sc); static void ath5k_beacon_config(struct ath5k_softc *sc); static void ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf); @@ -1295,37 +1290,36 @@ ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) } static int -ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, - struct ieee80211_tx_control *ctl) +ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) { struct ath5k_hw *ah = sc->ah; struct ath5k_txq *txq = sc->txq; struct ath5k_desc *ds = bf->desc; struct sk_buff *skb = bf->skb; + struct ieee80211_tx_info *info = (void*) skb->cb; unsigned int pktlen, flags, keyidx = AR5K_TXKEYIX_INVALID; int ret; flags = AR5K_TXDESC_INTREQ | AR5K_TXDESC_CLRDMASK; - bf->ctl = *ctl; + /* XXX endianness */ bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); - if (ctl->flags & IEEE80211_TXCTL_NO_ACK) + if (info->flags & IEEE80211_TX_CTL_NO_ACK) flags |= AR5K_TXDESC_NOACK; pktlen = skb->len; - if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) { - keyidx = ctl->hw_key->hw_key_idx; - pktlen += ctl->icv_len; + if (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT)) { + keyidx = info->control.hw_key->hw_key_idx; + pktlen += info->control.icv_len; } - ret = ah->ah_setup_tx_desc(ah, ds, pktlen, ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL, (sc->power_level * 2), - ieee80211_get_tx_rate(sc->hw, ctl)->hw_value, - ctl->retry_limit, keyidx, 0, flags, 0, 0); + ieee80211_get_tx_rate(sc->hw, info)->hw_value, + info->control.retry_limit, keyidx, 0, flags, 0, 0); if (ret) goto err_unmap; @@ -1927,11 +1921,11 @@ next: static void ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) { - struct ieee80211_tx_status txs = {}; struct ath5k_tx_status ts = {}; struct ath5k_buf *bf, *bf0; struct ath5k_desc *ds; struct sk_buff *skb; + struct ieee80211_tx_info *info; int ret; spin_lock(&txq->lock); @@ -1951,24 +1945,25 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) } skb = bf->skb; + info = (void*) skb->cb; bf->skb = NULL; + pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, PCI_DMA_TODEVICE); - txs.control = bf->ctl; - txs.retry_count = ts.ts_shortretry + ts.ts_longretry / 6; + info->status.retry_count = ts.ts_shortretry + ts.ts_longretry / 6; if (unlikely(ts.ts_status)) { sc->ll_stats.dot11ACKFailureCount++; if (ts.ts_status & AR5K_TXERR_XRETRY) - txs.excessive_retries = 1; + info->status.excessive_retries = 1; else if (ts.ts_status & AR5K_TXERR_FILT) - txs.flags |= IEEE80211_TX_STATUS_TX_FILTERED; + info->flags |= IEEE80211_TX_STAT_TX_FILTERED; } else { - txs.flags |= IEEE80211_TX_STATUS_ACK; - txs.ack_signal = ts.ts_rssi; + info->flags |= IEEE80211_TX_STAT_ACK; + info->status.ack_signal = ts.ts_rssi; } - ieee80211_tx_status(sc->hw, skb, &txs); + ieee80211_tx_status(sc->hw, skb); sc->tx_stats[txq->qnum].count++; spin_lock(&sc->txbuflock); @@ -2005,10 +2000,10 @@ ath5k_tasklet_tx(unsigned long data) * Setup the beacon frame for transmit. */ static int -ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, - struct ieee80211_tx_control *ctl) +ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) { struct sk_buff *skb = bf->skb; + struct ieee80211_tx_info *info = (void*) skb->cb; struct ath5k_hw *ah = sc->ah; struct ath5k_desc *ds; int ret, antenna = 0; @@ -2047,7 +2042,7 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, ret = ah->ah_setup_tx_desc(ah, ds, skb->len, ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_BEACON, (sc->power_level * 2), - ieee80211_get_tx_rate(sc->hw, ctl)->hw_value, + ieee80211_get_tx_rate(sc->hw, info)->hw_value, 1, AR5K_TXKEYIX_INVALID, antenna, flags, 0, 0); if (ret) @@ -2626,11 +2621,11 @@ ath5k_led_event(struct ath5k_softc *sc, int event) \********************/ static int -ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *ctl) +ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct ath5k_softc *sc = hw->priv; struct ath5k_buf *bf; + struct ieee80211_tx_info *info = (void*) skb->cb; unsigned long flags; int hdrlen; int pad; @@ -2656,13 +2651,13 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb, memmove(skb->data, skb->data+pad, hdrlen); } - sc->led_txrate = ieee80211_get_tx_rate(hw, ctl)->hw_value; + sc->led_txrate = ieee80211_get_tx_rate(hw, info)->hw_value; spin_lock_irqsave(&sc->txbuflock, flags); if (list_empty(&sc->txbuf)) { ATH5K_ERR(sc, "no further txbuf available, dropping packet\n"); spin_unlock_irqrestore(&sc->txbuflock, flags); - ieee80211_stop_queue(hw, ctl->queue); + ieee80211_stop_queue(hw, info->queue); return -1; } bf = list_first_entry(&sc->txbuf, struct ath5k_buf, list); @@ -2674,7 +2669,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb, bf->skb = skb; - if (ath5k_txbuf_setup(sc, bf, ctl)) { + if (ath5k_txbuf_setup(sc, bf)) { bf->skb = NULL; spin_lock_irqsave(&sc->txbuflock, flags); list_add_tail(&bf->list, &sc->txbuf); @@ -3052,8 +3047,7 @@ ath5k_reset_tsf(struct ieee80211_hw *hw) } static int -ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *ctl) +ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) { struct ath5k_softc *sc = hw->priv; int ret; @@ -3069,7 +3063,7 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, ath5k_txbuf_free(sc, sc->bbuf); sc->bbuf->skb = skb; - ret = ath5k_beacon_setup(sc, sc->bbuf, ctl); + ret = ath5k_beacon_setup(sc, sc->bbuf); if (ret) sc->bbuf->skb = NULL; else diff --git a/drivers/net/wireless/ath5k/base.h b/drivers/net/wireless/ath5k/base.h index ecb17495488..bb4b26d523a 100644 --- a/drivers/net/wireless/ath5k/base.h +++ b/drivers/net/wireless/ath5k/base.h @@ -60,7 +60,6 @@ struct ath5k_buf { dma_addr_t daddr; /* physical addr of desc */ struct sk_buff *skb; /* skbuff for buf */ dma_addr_t skbaddr;/* physical addr of skb data */ - struct ieee80211_tx_control ctl; }; /* diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 0c2bc061e8f..aa493830a82 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -733,7 +733,6 @@ struct b43_wl { /* The beacon we are currently using (AP or IBSS mode). * This beacon stuff is protected by the irq_lock. */ struct sk_buff *current_beacon; - struct ieee80211_tx_control beacon_txctl; bool beacon0_uploaded; bool beacon1_uploaded; struct work_struct beacon_update_trigger; diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index f50e2014ffb..aced9866d81 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -1131,10 +1131,10 @@ struct b43_dmaring *parse_cookie(struct b43_wldev *dev, u16 cookie, int *slot) } static int dma_tx_fragment(struct b43_dmaring *ring, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl) + struct sk_buff *skb) { const struct b43_dma_ops *ops = ring->ops; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); u8 *header; int slot, old_top_slot, old_used_slots; int err; @@ -1158,7 +1158,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring, header = &(ring->txhdr_cache[slot * hdrsize]); cookie = generate_cookie(ring, slot); err = b43_generate_txhdr(ring->dev, header, - skb->data, skb->len, ctl, cookie); + skb->data, skb->len, info, cookie); if (unlikely(err)) { ring->current_slot = old_top_slot; ring->used_slots = old_used_slots; @@ -1180,7 +1180,6 @@ static int dma_tx_fragment(struct b43_dmaring *ring, desc = ops->idx2desc(ring, slot, &meta); memset(meta, 0, sizeof(*meta)); - memcpy(&meta->txstat.control, ctl, sizeof(*ctl)); meta->skb = skb; meta->is_last_fragment = 1; @@ -1210,7 +1209,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring, ops->fill_descriptor(ring, desc, meta->dmaaddr, skb->len, 0, 1, 1); - if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) { + if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { /* Tell the firmware about the cookie of the last * mcast frame, so it can clear the more-data bit in it. */ b43_shm_write16(ring->dev, B43_SHM_SHARED, @@ -1281,16 +1280,16 @@ static struct b43_dmaring * select_ring_by_priority(struct b43_wldev *dev, return ring; } -int b43_dma_tx(struct b43_wldev *dev, - struct sk_buff *skb, struct ieee80211_tx_control *ctl) +int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) { struct b43_dmaring *ring; struct ieee80211_hdr *hdr; int err = 0; unsigned long flags; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); hdr = (struct ieee80211_hdr *)skb->data; - if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) { + if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { /* The multicast ring will be sent after the DTIM */ ring = dev->dma.tx_ring_mcast; /* Set the more-data bit. Ucode will clear it on @@ -1298,7 +1297,7 @@ int b43_dma_tx(struct b43_wldev *dev, hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); } else { /* Decide by priority where to put this frame. */ - ring = select_ring_by_priority(dev, ctl->queue); + ring = select_ring_by_priority(dev, info->queue); } spin_lock_irqsave(&ring->lock, flags); @@ -1316,9 +1315,9 @@ int b43_dma_tx(struct b43_wldev *dev, /* Assign the queue number to the ring (if not already done before) * so TX status handling can use it. The queue to ring mapping is * static, so we don't need to store it per frame. */ - ring->queue_prio = ctl->queue; + ring->queue_prio = info->queue; - err = dma_tx_fragment(ring, skb, ctl); + err = dma_tx_fragment(ring, skb); if (unlikely(err == -ENOKEY)) { /* Drop this packet, as we don't have the encryption key * anymore and must not transmit it unencrypted. */ @@ -1334,7 +1333,7 @@ int b43_dma_tx(struct b43_wldev *dev, if ((free_slots(ring) < SLOTS_PER_PACKET) || should_inject_overflow(ring)) { /* This TX ring is full. */ - ieee80211_stop_queue(dev->wl->hw, ctl->queue); + ieee80211_stop_queue(dev->wl->hw, info->queue); ring->stopped = 1; if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index); @@ -1377,13 +1376,19 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, b43_txhdr_size(dev), 1); if (meta->is_last_fragment) { - B43_WARN_ON(!meta->skb); - /* Call back to inform the ieee80211 subsystem about the - * status of the transmission. - * Some fields of txstat are already filled in dma_tx(). + struct ieee80211_tx_info *info; + + BUG_ON(!meta->skb); + + info = IEEE80211_SKB_CB(meta->skb); + + memset(&info->status, 0, sizeof(info->status)); + + /* + * Call back to inform the ieee80211 subsystem about + * the status of the transmission. */ - frame_succeed = b43_fill_txstatus_report( - &(meta->txstat), status); + frame_succeed = b43_fill_txstatus_report(info, status); #ifdef CONFIG_B43_DEBUG if (frame_succeed) ring->nr_succeed_tx_packets++; @@ -1391,8 +1396,8 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, ring->nr_failed_tx_packets++; ring->nr_total_packet_tries += status->frame_count; #endif /* DEBUG */ - ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb, - &(meta->txstat)); + ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb); + /* skb is freed by ieee80211_tx_status_irqsafe() */ meta->skb = NULL; } else { diff --git a/drivers/net/wireless/b43/dma.h b/drivers/net/wireless/b43/dma.h index 20acf885dba..d1eb5c0848a 100644 --- a/drivers/net/wireless/b43/dma.h +++ b/drivers/net/wireless/b43/dma.h @@ -181,7 +181,6 @@ struct b43_dmadesc_meta { dma_addr_t dmaaddr; /* ieee80211 TX status. Only used once per 802.11 frag. */ bool is_last_fragment; - struct ieee80211_tx_status txstat; }; struct b43_dmaring; @@ -285,7 +284,7 @@ void b43_dma_get_tx_stats(struct b43_wldev *dev, struct ieee80211_tx_queue_stats *stats); int b43_dma_tx(struct b43_wldev *dev, - struct sk_buff *skb, struct ieee80211_tx_control *ctl); + struct sk_buff *skb); void b43_dma_handle_txstatus(struct b43_wldev *dev, const struct b43_txstatus *status); diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index e428645352b..3622d76de1e 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1368,18 +1368,18 @@ static void b43_write_beacon_template(struct b43_wldev *dev, unsigned int rate; u16 ctl; int antenna; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(dev->wl->current_beacon); bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data); len = min((size_t) dev->wl->current_beacon->len, 0x200 - sizeof(struct b43_plcp_hdr6)); - rate = ieee80211_get_tx_rate(dev->wl->hw, &dev->wl->beacon_txctl)->hw_value; + rate = ieee80211_get_tx_rate(dev->wl->hw, info)->hw_value; b43_write_template_common(dev, (const u8 *)bcn, len, ram_offset, shm_size_offset, rate); /* Write the PHY TX control parameters. */ - antenna = b43_antenna_from_ieee80211(dev, - dev->wl->beacon_txctl.antenna_sel_tx); + antenna = b43_antenna_from_ieee80211(dev, info->antenna_sel_tx); antenna = b43_antenna_to_phyctl(antenna); ctl = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL); /* We can't send beacons with short preamble. Would get PHY errors. */ @@ -1613,8 +1613,7 @@ static void b43_beacon_update_trigger_work(struct work_struct *work) /* Asynchronously update the packet templates in template RAM. * Locking: Requires wl->irq_lock to be locked. */ -static void b43_update_templates(struct b43_wl *wl, struct sk_buff *beacon, - const struct ieee80211_tx_control *txctl) +static void b43_update_templates(struct b43_wl *wl, struct sk_buff *beacon) { /* This is the top half of the ansynchronous beacon update. * The bottom half is the beacon IRQ. @@ -1625,7 +1624,6 @@ static void b43_update_templates(struct b43_wl *wl, struct sk_buff *beacon, if (wl->current_beacon) dev_kfree_skb_any(wl->current_beacon); wl->current_beacon = beacon; - memcpy(&wl->beacon_txctl, txctl, sizeof(wl->beacon_txctl)); wl->beacon0_uploaded = 0; wl->beacon1_uploaded = 0; queue_work(wl->hw->workqueue, &wl->beacon_update_trigger); @@ -2813,8 +2811,7 @@ static int b43_rng_init(struct b43_wl *wl) } static int b43_op_tx(struct ieee80211_hw *hw, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl) + struct sk_buff *skb) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev = wl->current_dev; @@ -2836,9 +2833,9 @@ static int b43_op_tx(struct ieee80211_hw *hw, err = -ENODEV; if (likely(b43_status(dev) >= B43_STAT_STARTED)) { if (b43_using_pio_transfers(dev)) - err = b43_pio_tx(dev, skb, ctl); + err = b43_pio_tx(dev, skb); else - err = b43_dma_tx(dev, skb, ctl); + err = b43_dma_tx(dev, skb); } read_unlock_irqrestore(&wl->tx_lock, flags); @@ -3429,10 +3426,8 @@ static int b43_op_config_interface(struct ieee80211_hw *hw, if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) { B43_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP); b43_set_ssid(dev, conf->ssid, conf->ssid_len); - if (conf->beacon) { - b43_update_templates(wl, conf->beacon, - conf->beacon_control); - } + if (conf->beacon) + b43_update_templates(wl, conf->beacon); } b43_write_mac_bssid_templates(dev); } @@ -4118,31 +4113,29 @@ static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, int aid, int set) struct b43_wl *wl = hw_to_b43_wl(hw); struct sk_buff *beacon; unsigned long flags; - struct ieee80211_tx_control txctl; /* We could modify the existing beacon and set the aid bit in * the TIM field, but that would probably require resizing and * moving of data within the beacon template. * Simply request a new beacon and let mac80211 do the hard work. */ - beacon = ieee80211_beacon_get(hw, wl->vif, &txctl); + beacon = ieee80211_beacon_get(hw, wl->vif); if (unlikely(!beacon)) return -ENOMEM; spin_lock_irqsave(&wl->irq_lock, flags); - b43_update_templates(wl, beacon, &txctl); + b43_update_templates(wl, beacon); spin_unlock_irqrestore(&wl->irq_lock, flags); return 0; } static int b43_op_ibss_beacon_update(struct ieee80211_hw *hw, - struct sk_buff *beacon, - struct ieee80211_tx_control *ctl) + struct sk_buff *beacon) { struct b43_wl *wl = hw_to_b43_wl(hw); unsigned long flags; spin_lock_irqsave(&wl->irq_lock, flags); - b43_update_templates(wl, beacon, ctl); + b43_update_templates(wl, beacon); spin_unlock_irqrestore(&wl->irq_lock, flags); return 0; diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index 08c8a087f30..284786a94e7 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -446,29 +446,27 @@ static void pio_tx_frame_4byte_queue(struct b43_pio_txpacket *pack, } static int pio_tx_frame(struct b43_pio_txqueue *q, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl) + struct sk_buff *skb) { struct b43_pio_txpacket *pack; struct b43_txhdr txhdr; u16 cookie; int err; unsigned int hdrlen; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); B43_WARN_ON(list_empty(&q->packets_list)); pack = list_entry(q->packets_list.next, struct b43_pio_txpacket, list); - memset(&pack->txstat, 0, sizeof(pack->txstat)); - memcpy(&pack->txstat.control, ctl, sizeof(*ctl)); cookie = generate_cookie(q, pack); hdrlen = b43_txhdr_size(q->dev); err = b43_generate_txhdr(q->dev, (u8 *)&txhdr, skb->data, - skb->len, ctl, cookie); + skb->len, info, cookie); if (err) return err; - if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) { + if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { /* Tell the firmware about the cookie of the last * mcast frame, so it can clear the more-data bit in it. */ b43_shm_write16(q->dev, B43_SHM_SHARED, @@ -492,17 +490,18 @@ static int pio_tx_frame(struct b43_pio_txqueue *q, return 0; } -int b43_pio_tx(struct b43_wldev *dev, - struct sk_buff *skb, struct ieee80211_tx_control *ctl) +int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) { struct b43_pio_txqueue *q; struct ieee80211_hdr *hdr; unsigned long flags; unsigned int hdrlen, total_len; int err = 0; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); hdr = (struct ieee80211_hdr *)skb->data; - if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) { + + if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { /* The multicast queue will be sent after the DTIM. */ q = dev->pio.tx_queue_mcast; /* Set the frame More-Data bit. Ucode will clear it @@ -510,7 +509,7 @@ int b43_pio_tx(struct b43_wldev *dev, hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); } else { /* Decide by priority where to put this frame. */ - q = select_queue_by_priority(dev, ctl->queue); + q = select_queue_by_priority(dev, info->queue); } spin_lock_irqsave(&q->lock, flags); @@ -533,7 +532,7 @@ int b43_pio_tx(struct b43_wldev *dev, if (total_len > (q->buffer_size - q->buffer_used)) { /* Not enough memory on the queue. */ err = -EBUSY; - ieee80211_stop_queue(dev->wl->hw, ctl->queue); + ieee80211_stop_queue(dev->wl->hw, info->queue); q->stopped = 1; goto out_unlock; } @@ -541,9 +540,9 @@ int b43_pio_tx(struct b43_wldev *dev, /* Assign the queue number to the ring (if not already done before) * so TX status handling can use it. The mac80211-queue to b43-queue * mapping is static, so we don't need to store it per frame. */ - q->queue_prio = ctl->queue; + q->queue_prio = info->queue; - err = pio_tx_frame(q, skb, ctl); + err = pio_tx_frame(q, skb); if (unlikely(err == -ENOKEY)) { /* Drop this packet, as we don't have the encryption key * anymore and must not transmit it unencrypted. */ @@ -561,7 +560,7 @@ int b43_pio_tx(struct b43_wldev *dev, if (((q->buffer_size - q->buffer_used) < roundup(2 + 2 + 6, 4)) || (q->free_packet_slots == 0)) { /* The queue is full. */ - ieee80211_stop_queue(dev->wl->hw, ctl->queue); + ieee80211_stop_queue(dev->wl->hw, info->queue); q->stopped = 1; } @@ -578,6 +577,7 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev, struct b43_pio_txqueue *q; struct b43_pio_txpacket *pack = NULL; unsigned int total_len; + struct ieee80211_tx_info *info; q = parse_cookie(dev, status->cookie, &pack); if (unlikely(!q)) @@ -586,15 +586,17 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev, spin_lock(&q->lock); /* IRQs are already disabled. */ - b43_fill_txstatus_report(&(pack->txstat), status); + info = (void *)pack->skb; + memset(&info->status, 0, sizeof(info->status)); + + b43_fill_txstatus_report(info, status); total_len = pack->skb->len + b43_txhdr_size(dev); total_len = roundup(total_len, 4); q->buffer_used -= total_len; q->free_packet_slots += 1; - ieee80211_tx_status_irqsafe(dev->wl->hw, pack->skb, - &(pack->txstat)); + ieee80211_tx_status_irqsafe(dev->wl->hw, pack->skb); pack->skb = NULL; list_add(&pack->list, &q->packets_list); diff --git a/drivers/net/wireless/b43/pio.h b/drivers/net/wireless/b43/pio.h index e2ec676cc9e..6c174c91ca2 100644 --- a/drivers/net/wireless/b43/pio.h +++ b/drivers/net/wireless/b43/pio.h @@ -62,8 +62,6 @@ struct b43_pio_txpacket { struct b43_pio_txqueue *queue; /* The TX data packet. */ struct sk_buff *skb; - /* The status meta data. */ - struct ieee80211_tx_status txstat; /* Index in the (struct b43_pio_txqueue)->packets array. */ u8 index; @@ -167,8 +165,7 @@ int b43_pio_init(struct b43_wldev *dev); void b43_pio_stop(struct b43_wldev *dev); void b43_pio_free(struct b43_wldev *dev); -int b43_pio_tx(struct b43_wldev *dev, - struct sk_buff *skb, struct ieee80211_tx_control *ctl); +int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb); void b43_pio_handle_txstatus(struct b43_wldev *dev, const struct b43_txstatus *status); void b43_pio_get_tx_stats(struct b43_wldev *dev, @@ -193,8 +190,7 @@ static inline void b43_pio_stop(struct b43_wldev *dev) { } static inline int b43_pio_tx(struct b43_wldev *dev, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl) + struct sk_buff *skb) { return 0; } diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 9b682a3cf5e..f9e1cff2aec 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -185,14 +185,14 @@ int b43_generate_txhdr(struct b43_wldev *dev, u8 *_txhdr, const unsigned char *fragment_data, unsigned int fragment_len, - const struct ieee80211_tx_control *txctl, + const struct ieee80211_tx_info *info, u16 cookie) { struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr; const struct b43_phy *phy = &dev->phy; const struct ieee80211_hdr *wlhdr = (const struct ieee80211_hdr *)fragment_data; - int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)); + int use_encryption = (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT)); u16 fctl = le16_to_cpu(wlhdr->frame_control); struct ieee80211_rate *fbrate; u8 rate, rate_fb; @@ -205,10 +205,10 @@ int b43_generate_txhdr(struct b43_wldev *dev, memset(txhdr, 0, sizeof(*txhdr)); - txrate = ieee80211_get_tx_rate(dev->wl->hw, txctl); + txrate = ieee80211_get_tx_rate(dev->wl->hw, info); rate = txrate ? txrate->hw_value : B43_CCK_RATE_1MB; rate_ofdm = b43_is_ofdm_rate(rate); - fbrate = ieee80211_get_alt_retry_rate(dev->wl->hw, txctl) ? : txrate; + fbrate = ieee80211_get_alt_retry_rate(dev->wl->hw, info) ? : txrate; rate_fb = fbrate->hw_value; rate_fb_ofdm = b43_is_ofdm_rate(rate_fb); @@ -228,15 +228,13 @@ int b43_generate_txhdr(struct b43_wldev *dev, * use the original dur_id field. */ txhdr->dur_fb = wlhdr->duration_id; } else { - txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw, - txctl->vif, - fragment_len, - fbrate); + txhdr->dur_fb = ieee80211_generic_frame_duration( + dev->wl->hw, info->control.vif, fragment_len, fbrate); } plcp_fragment_len = fragment_len + FCS_LEN; if (use_encryption) { - u8 key_idx = txctl->hw_key->hw_key_idx; + u8 key_idx = info->control.hw_key->hw_key_idx; struct b43_key *key; int wlhdr_len; size_t iv_len; @@ -254,7 +252,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, } /* Hardware appends ICV. */ - plcp_fragment_len += txctl->icv_len; + plcp_fragment_len += info->control.icv_len; key_idx = b43_kidx_to_fw(dev, key_idx); mac_ctl |= (key_idx << B43_TXH_MAC_KEYIDX_SHIFT) & @@ -262,7 +260,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, mac_ctl |= (key->algorithm << B43_TXH_MAC_KEYALG_SHIFT) & B43_TXH_MAC_KEYALG; wlhdr_len = ieee80211_get_hdrlen(fctl); - iv_len = min((size_t) txctl->iv_len, + iv_len = min((size_t) info->control.iv_len, ARRAY_SIZE(txhdr->iv)); memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len); } @@ -293,10 +291,10 @@ int b43_generate_txhdr(struct b43_wldev *dev, phy_ctl |= B43_TXH_PHY_ENC_OFDM; else phy_ctl |= B43_TXH_PHY_ENC_CCK; - if (txctl->flags & IEEE80211_TXCTL_SHORT_PREAMBLE) + if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE) phy_ctl |= B43_TXH_PHY_SHORTPRMBL; - switch (b43_ieee80211_antenna_sanitize(dev, txctl->antenna_sel_tx)) { + switch (b43_ieee80211_antenna_sanitize(dev, info->antenna_sel_tx)) { case 0: /* Default */ phy_ctl |= B43_TXH_PHY_ANT01AUTO; break; @@ -317,21 +315,21 @@ int b43_generate_txhdr(struct b43_wldev *dev, } /* MAC control */ - if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK)) + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) mac_ctl |= B43_TXH_MAC_ACK; if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) && ((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL))) mac_ctl |= B43_TXH_MAC_HWSEQ; - if (txctl->flags & IEEE80211_TXCTL_FIRST_FRAGMENT) + if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) mac_ctl |= B43_TXH_MAC_STMSDU; if (phy->type == B43_PHYTYPE_A) mac_ctl |= B43_TXH_MAC_5GHZ; - if (txctl->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT) + if (info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT) mac_ctl |= B43_TXH_MAC_LONGFRAME; /* Generate the RTS or CTS-to-self frame */ - if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) || - (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) { + if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) || + (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) { unsigned int len; struct ieee80211_hdr *hdr; int rts_rate, rts_rate_fb; @@ -339,14 +337,14 @@ int b43_generate_txhdr(struct b43_wldev *dev, struct b43_plcp_hdr6 *plcp; struct ieee80211_rate *rts_cts_rate; - rts_cts_rate = ieee80211_get_rts_cts_rate(dev->wl->hw, txctl); + rts_cts_rate = ieee80211_get_rts_cts_rate(dev->wl->hw, info); rts_rate = rts_cts_rate ? rts_cts_rate->hw_value : B43_CCK_RATE_1MB; rts_rate_ofdm = b43_is_ofdm_rate(rts_rate); rts_rate_fb = b43_calc_fallback_rate(rts_rate); rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb); - if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { + if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { struct ieee80211_cts *cts; if (b43_is_old_txhdr_format(dev)) { @@ -356,9 +354,9 @@ int b43_generate_txhdr(struct b43_wldev *dev, cts = (struct ieee80211_cts *) (txhdr->new_format.rts_frame); } - ieee80211_ctstoself_get(dev->wl->hw, txctl->vif, + ieee80211_ctstoself_get(dev->wl->hw, info->control.vif, fragment_data, fragment_len, - txctl, cts); + info, cts); mac_ctl |= B43_TXH_MAC_SENDCTS; len = sizeof(struct ieee80211_cts); } else { @@ -371,9 +369,9 @@ int b43_generate_txhdr(struct b43_wldev *dev, rts = (struct ieee80211_rts *) (txhdr->new_format.rts_frame); } - ieee80211_rts_get(dev->wl->hw, txctl->vif, + ieee80211_rts_get(dev->wl->hw, info->control.vif, fragment_data, fragment_len, - txctl, rts); + info, rts); mac_ctl |= B43_TXH_MAC_SENDRTS; len = sizeof(struct ieee80211_rts); } @@ -687,27 +685,27 @@ void b43_handle_txstatus(struct b43_wldev *dev, /* Fill out the mac80211 TXstatus report based on the b43-specific * txstatus report data. This returns a boolean whether the frame was * successfully transmitted. */ -bool b43_fill_txstatus_report(struct ieee80211_tx_status *report, +bool b43_fill_txstatus_report(struct ieee80211_tx_info *report, const struct b43_txstatus *status) { bool frame_success = 1; if (status->acked) { /* The frame was ACKed. */ - report->flags |= IEEE80211_TX_STATUS_ACK; + report->flags |= IEEE80211_TX_STAT_ACK; } else { /* The frame was not ACKed... */ - if (!(report->control.flags & IEEE80211_TXCTL_NO_ACK)) { + if (!(report->flags & IEEE80211_TX_CTL_NO_ACK)) { /* ...but we expected an ACK. */ frame_success = 0; - report->excessive_retries = 1; + report->status.excessive_retries = 1; } } if (status->frame_count == 0) { /* The frame was not transmitted at all. */ - report->retry_count = 0; + report->status.retry_count = 0; } else - report->retry_count = status->frame_count - 1; + report->status.retry_count = status->frame_count - 1; return frame_success; } diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h index b05f44e0d62..0215faf4754 100644 --- a/drivers/net/wireless/b43/xmit.h +++ b/drivers/net/wireless/b43/xmit.h @@ -178,7 +178,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, u8 * txhdr, const unsigned char *fragment_data, unsigned int fragment_len, - const struct ieee80211_tx_control *txctl, u16 cookie); + const struct ieee80211_tx_info *txctl, u16 cookie); /* Transmit Status */ struct b43_txstatus { @@ -294,7 +294,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr); void b43_handle_txstatus(struct b43_wldev *dev, const struct b43_txstatus *status); -bool b43_fill_txstatus_report(struct ieee80211_tx_status *report, +bool b43_fill_txstatus_report(struct ieee80211_tx_info *report, const struct b43_txstatus *status); void b43_tx_suspend(struct b43_wldev *dev); diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c index d6686f713b6..c1c501d963b 100644 --- a/drivers/net/wireless/b43legacy/dma.c +++ b/drivers/net/wireless/b43legacy/dma.c @@ -1205,10 +1205,10 @@ struct b43legacy_dmaring *parse_cookie(struct b43legacy_wldev *dev, } static int dma_tx_fragment(struct b43legacy_dmaring *ring, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl) + struct sk_buff *skb) { const struct b43legacy_dma_ops *ops = ring->ops; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); u8 *header; int slot, old_top_slot, old_used_slots; int err; @@ -1231,7 +1231,7 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring, header = &(ring->txhdr_cache[slot * sizeof( struct b43legacy_txhdr_fw3)]); err = b43legacy_generate_txhdr(ring->dev, header, - skb->data, skb->len, ctl, + skb->data, skb->len, info, generate_cookie(ring, slot)); if (unlikely(err)) { ring->current_slot = old_top_slot; @@ -1255,7 +1255,6 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring, desc = ops->idx2desc(ring, slot, &meta); memset(meta, 0, sizeof(*meta)); - memcpy(&meta->txstat.control, ctl, sizeof(*ctl)); meta->skb = skb; meta->is_last_fragment = 1; @@ -1323,14 +1322,14 @@ int should_inject_overflow(struct b43legacy_dmaring *ring) } int b43legacy_dma_tx(struct b43legacy_wldev *dev, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl) + struct sk_buff *skb) { struct b43legacy_dmaring *ring; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int err = 0; unsigned long flags; - ring = priority_to_txring(dev, ctl->queue); + ring = priority_to_txring(dev, info->queue); spin_lock_irqsave(&ring->lock, flags); B43legacy_WARN_ON(!ring->tx); if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) { @@ -1343,7 +1342,7 @@ int b43legacy_dma_tx(struct b43legacy_wldev *dev, * That would be a mac80211 bug. */ B43legacy_BUG_ON(ring->stopped); - err = dma_tx_fragment(ring, skb, ctl); + err = dma_tx_fragment(ring, skb); if (unlikely(err == -ENOKEY)) { /* Drop this packet, as we don't have the encryption key * anymore and must not transmit it unencrypted. */ @@ -1401,26 +1400,29 @@ void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev, 1); if (meta->is_last_fragment) { - B43legacy_WARN_ON(!meta->skb); + struct ieee80211_tx_info *info; + BUG_ON(!meta->skb); + info = IEEE80211_SKB_CB(meta->skb); /* Call back to inform the ieee80211 subsystem about the * status of the transmission. * Some fields of txstat are already filled in dma_tx(). */ + + memset(&info->status, 0, sizeof(info->status)); + if (status->acked) { - meta->txstat.flags |= IEEE80211_TX_STATUS_ACK; + info->flags |= IEEE80211_TX_STAT_ACK; } else { - if (!(meta->txstat.control.flags - & IEEE80211_TXCTL_NO_ACK)) - meta->txstat.excessive_retries = 1; + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) + info->status.excessive_retries = 1; } if (status->frame_count == 0) { /* The frame was not transmitted at all. */ - meta->txstat.retry_count = 0; + info->status.retry_count = 0; } else - meta->txstat.retry_count = status->frame_count + info->status.retry_count = status->frame_count - 1; - ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb, - &(meta->txstat)); + ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb); /* skb is freed by ieee80211_tx_status_irqsafe() */ meta->skb = NULL; } else { diff --git a/drivers/net/wireless/b43legacy/dma.h b/drivers/net/wireless/b43legacy/dma.h index 2dd488c5be2..67537a7495f 100644 --- a/drivers/net/wireless/b43legacy/dma.h +++ b/drivers/net/wireless/b43legacy/dma.h @@ -195,7 +195,6 @@ struct b43legacy_dmadesc_meta { dma_addr_t dmaaddr; /* ieee80211 TX status. Only used once per 802.11 frag. */ bool is_last_fragment; - struct ieee80211_tx_status txstat; }; struct b43legacy_dmaring; @@ -297,8 +296,7 @@ void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev, struct ieee80211_tx_queue_stats *stats); int b43legacy_dma_tx(struct b43legacy_wldev *dev, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl); + struct sk_buff *skb); void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev, const struct b43legacy_txstatus *status); diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index b05a507ed44..f706ca65f15 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -2358,8 +2358,7 @@ static int b43legacy_rng_init(struct b43legacy_wl *wl) } static int b43legacy_op_tx(struct ieee80211_hw *hw, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl) + struct sk_buff *skb) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev = wl->current_dev; @@ -2373,10 +2372,10 @@ static int b43legacy_op_tx(struct ieee80211_hw *hw, /* DMA-TX is done without a global lock. */ if (b43legacy_using_pio(dev)) { spin_lock_irqsave(&wl->irq_lock, flags); - err = b43legacy_pio_tx(dev, skb, ctl); + err = b43legacy_pio_tx(dev, skb); spin_unlock_irqrestore(&wl->irq_lock, flags); } else - err = b43legacy_dma_tx(dev, skb, ctl); + err = b43legacy_dma_tx(dev, skb); out: if (unlikely(err)) return NETDEV_TX_BUSY; @@ -3409,7 +3408,7 @@ static int b43legacy_op_beacon_set_tim(struct ieee80211_hw *hw, * field, but that would probably require resizing and moving of data * within the beacon template. Simply request a new beacon and let * mac80211 do the hard work. */ - beacon = ieee80211_beacon_get(hw, wl->vif, NULL); + beacon = ieee80211_beacon_get(hw, wl->vif); if (unlikely(!beacon)) return -ENOMEM; spin_lock_irqsave(&wl->irq_lock, flags); @@ -3420,8 +3419,7 @@ static int b43legacy_op_beacon_set_tim(struct ieee80211_hw *hw, } static int b43legacy_op_ibss_beacon_update(struct ieee80211_hw *hw, - struct sk_buff *beacon, - struct ieee80211_tx_control *ctl) + struct sk_buff *beacon) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); unsigned long flags; diff --git a/drivers/net/wireless/b43legacy/pio.c b/drivers/net/wireless/b43legacy/pio.c index 8d3d27d3cd6..a86c7647fa2 100644 --- a/drivers/net/wireless/b43legacy/pio.c +++ b/drivers/net/wireless/b43legacy/pio.c @@ -196,7 +196,7 @@ static int pio_tx_write_fragment(struct b43legacy_pioqueue *queue, B43legacy_WARN_ON(skb_shinfo(skb)->nr_frags != 0); err = b43legacy_generate_txhdr(queue->dev, txhdr, skb->data, skb->len, - &packet->txstat.control, + IEEE80211_SKB_CB(skb), generate_cookie(queue, packet)); if (err) return err; @@ -463,8 +463,7 @@ err_destroy0: } int b43legacy_pio_tx(struct b43legacy_wldev *dev, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl) + struct sk_buff *skb) { struct b43legacy_pioqueue *queue = dev->pio.queue1; struct b43legacy_pio_txpacket *packet; @@ -476,9 +475,6 @@ int b43legacy_pio_tx(struct b43legacy_wldev *dev, list); packet->skb = skb; - memset(&packet->txstat, 0, sizeof(packet->txstat)); - memcpy(&packet->txstat.control, ctl, sizeof(*ctl)); - list_move_tail(&packet->list, &queue->txqueue); queue->nr_txfree--; queue->nr_tx_packets++; @@ -494,6 +490,7 @@ void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev, { struct b43legacy_pioqueue *queue; struct b43legacy_pio_txpacket *packet; + struct ieee80211_tx_info *info; queue = parse_cookie(dev, status->cookie, &packet); B43legacy_WARN_ON(!queue); @@ -505,11 +502,13 @@ void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev, queue->tx_devq_used -= (packet->skb->len + sizeof(struct b43legacy_txhdr_fw3)); + info = IEEE80211_SKB_CB(packet->skb); + memset(&info->status, 0, sizeof(info->status)); + if (status->acked) - packet->txstat.flags |= IEEE80211_TX_STATUS_ACK; - packet->txstat.retry_count = status->frame_count - 1; - ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb, - &(packet->txstat)); + info->flags |= IEEE80211_TX_STAT_ACK; + info->status.retry_count = status->frame_count - 1; + ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb); packet->skb = NULL; free_txpacket(packet, 1); diff --git a/drivers/net/wireless/b43legacy/pio.h b/drivers/net/wireless/b43legacy/pio.h index 5bfed0c4003..49310dfaf2d 100644 --- a/drivers/net/wireless/b43legacy/pio.h +++ b/drivers/net/wireless/b43legacy/pio.h @@ -41,7 +41,6 @@ struct b43legacy_xmitstatus; struct b43legacy_pio_txpacket { struct b43legacy_pioqueue *queue; struct sk_buff *skb; - struct ieee80211_tx_status txstat; struct list_head list; }; @@ -104,8 +103,7 @@ int b43legacy_pio_init(struct b43legacy_wldev *dev); void b43legacy_pio_free(struct b43legacy_wldev *dev); int b43legacy_pio_tx(struct b43legacy_wldev *dev, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl); + struct sk_buff *skb); void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev, const struct b43legacy_txstatus *status); void b43legacy_pio_get_tx_stats(struct b43legacy_wldev *dev, diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c index 55dc251bf51..82dc04d5944 100644 --- a/drivers/net/wireless/b43legacy/xmit.c +++ b/drivers/net/wireless/b43legacy/xmit.c @@ -188,11 +188,11 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, struct b43legacy_txhdr_fw3 *txhdr, const unsigned char *fragment_data, unsigned int fragment_len, - const struct ieee80211_tx_control *txctl, + const struct ieee80211_tx_info *info, u16 cookie) { const struct ieee80211_hdr *wlhdr; - int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)); + int use_encryption = (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT)); u16 fctl; u8 rate; struct ieee80211_rate *rate_fb; @@ -208,11 +208,11 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, memset(txhdr, 0, sizeof(*txhdr)); - tx_rate = ieee80211_get_tx_rate(dev->wl->hw, txctl); + tx_rate = ieee80211_get_tx_rate(dev->wl->hw, info); rate = tx_rate->hw_value; rate_ofdm = b43legacy_is_ofdm_rate(rate); - rate_fb = ieee80211_get_alt_retry_rate(dev->wl->hw, txctl) ? : tx_rate; + rate_fb = ieee80211_get_alt_retry_rate(dev->wl->hw, info) ? : tx_rate; rate_fb_ofdm = b43legacy_is_ofdm_rate(rate_fb->hw_value); txhdr->mac_frame_ctl = wlhdr->frame_control; @@ -228,14 +228,14 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, txhdr->dur_fb = wlhdr->duration_id; } else { txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw, - txctl->vif, + info->control.vif, fragment_len, rate_fb); } plcp_fragment_len = fragment_len + FCS_LEN; if (use_encryption) { - u8 key_idx = txctl->hw_key->hw_key_idx; + u8 key_idx = info->control.hw_key->hw_key_idx; struct b43legacy_key *key; int wlhdr_len; size_t iv_len; @@ -245,7 +245,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, if (key->enabled) { /* Hardware appends ICV. */ - plcp_fragment_len += txctl->icv_len; + plcp_fragment_len += info->control.icv_len; key_idx = b43legacy_kidx_to_fw(dev, key_idx); mac_ctl |= (key_idx << B43legacy_TX4_MAC_KEYIDX_SHIFT) & @@ -254,7 +254,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, B43legacy_TX4_MAC_KEYALG_SHIFT) & B43legacy_TX4_MAC_KEYALG; wlhdr_len = ieee80211_get_hdrlen(fctl); - iv_len = min((size_t)txctl->iv_len, + iv_len = min((size_t)info->control.iv_len, ARRAY_SIZE(txhdr->iv)); memcpy(txhdr->iv, ((u8 *)wlhdr) + wlhdr_len, iv_len); } else { @@ -278,7 +278,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, phy_ctl |= B43legacy_TX4_PHY_OFDM; if (dev->short_preamble) phy_ctl |= B43legacy_TX4_PHY_SHORTPRMBL; - switch (txctl->antenna_sel_tx) { + switch (info->antenna_sel_tx) { case 0: phy_ctl |= B43legacy_TX4_PHY_ANTLAST; break; @@ -293,21 +293,21 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, } /* MAC control */ - if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK)) + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) mac_ctl |= B43legacy_TX4_MAC_ACK; if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) && ((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL))) mac_ctl |= B43legacy_TX4_MAC_HWSEQ; - if (txctl->flags & IEEE80211_TXCTL_FIRST_FRAGMENT) + if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) mac_ctl |= B43legacy_TX4_MAC_STMSDU; if (rate_fb_ofdm) mac_ctl |= B43legacy_TX4_MAC_FALLBACKOFDM; - if (txctl->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT) + if (info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT) mac_ctl |= B43legacy_TX4_MAC_LONGFRAME; /* Generate the RTS or CTS-to-self frame */ - if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) || - (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) { + if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) || + (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) { unsigned int len; struct ieee80211_hdr *hdr; int rts_rate; @@ -315,26 +315,26 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, int rts_rate_ofdm; int rts_rate_fb_ofdm; - rts_rate = ieee80211_get_rts_cts_rate(dev->wl->hw, txctl)->hw_value; + rts_rate = ieee80211_get_rts_cts_rate(dev->wl->hw, info)->hw_value; rts_rate_ofdm = b43legacy_is_ofdm_rate(rts_rate); rts_rate_fb = b43legacy_calc_fallback_rate(rts_rate); rts_rate_fb_ofdm = b43legacy_is_ofdm_rate(rts_rate_fb); if (rts_rate_fb_ofdm) mac_ctl |= B43legacy_TX4_MAC_CTSFALLBACKOFDM; - if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { + if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { ieee80211_ctstoself_get(dev->wl->hw, - txctl->vif, + info->control.vif, fragment_data, - fragment_len, txctl, + fragment_len, info, (struct ieee80211_cts *) (txhdr->rts_frame)); mac_ctl |= B43legacy_TX4_MAC_SENDCTS; len = sizeof(struct ieee80211_cts); } else { ieee80211_rts_get(dev->wl->hw, - txctl->vif, - fragment_data, fragment_len, txctl, + info->control.vif, + fragment_data, fragment_len, info, (struct ieee80211_rts *) (txhdr->rts_frame)); mac_ctl |= B43legacy_TX4_MAC_SENDRTS; @@ -365,12 +365,12 @@ int b43legacy_generate_txhdr(struct b43legacy_wldev *dev, u8 *txhdr, const unsigned char *fragment_data, unsigned int fragment_len, - const struct ieee80211_tx_control *txctl, + const struct ieee80211_tx_info *info, u16 cookie) { return generate_txhdr_fw3(dev, (struct b43legacy_txhdr_fw3 *)txhdr, fragment_data, fragment_len, - txctl, cookie); + info, cookie); } static s8 b43legacy_rssi_postprocess(struct b43legacy_wldev *dev, diff --git a/drivers/net/wireless/b43legacy/xmit.h b/drivers/net/wireless/b43legacy/xmit.h index bab47928a0c..e56777e0fea 100644 --- a/drivers/net/wireless/b43legacy/xmit.h +++ b/drivers/net/wireless/b43legacy/xmit.h @@ -80,7 +80,7 @@ int b43legacy_generate_txhdr(struct b43legacy_wldev *dev, u8 *txhdr, const unsigned char *fragment_data, unsigned int fragment_len, - const struct ieee80211_tx_control *txctl, + const struct ieee80211_tx_info *info, u16 cookie); diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index f3ca02fe961..10c64bdb314 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -445,8 +445,7 @@ static int rs_adjust_next_rate(struct iwl3945_priv *priv, int rate) */ static void rs_tx_status(void *priv_rate, struct net_device *dev, - struct sk_buff *skb, - struct ieee80211_tx_status *tx_resp) + struct sk_buff *skb) { u8 retries, current_count; int scale_rate_index, first_index, last_index; @@ -457,14 +456,15 @@ static void rs_tx_status(void *priv_rate, struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct iwl3945_rs_sta *rs_sta; struct ieee80211_supported_band *sband; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); IWL_DEBUG_RATE("enter\n"); sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - retries = tx_resp->retry_count; - first_index = sband->bitrates[tx_resp->control.tx_rate_idx].hw_value; + retries = info->status.retry_count; + first_index = sband->bitrates[info->tx_rate_idx].hw_value; if ((first_index < 0) || (first_index >= IWL_RATE_COUNT)) { IWL_DEBUG_RATE("leave: Rate out of bounds: %d\n", first_index); return; @@ -525,11 +525,11 @@ static void rs_tx_status(void *priv_rate, /* Update the last index window with success/failure based on ACK */ IWL_DEBUG_RATE("Update rate %d with %s.\n", last_index, - (tx_resp->flags & IEEE80211_TX_STATUS_ACK) ? + (info->flags & IEEE80211_TX_STAT_ACK) ? "success" : "failure"); iwl3945_collect_tx_data(rs_sta, &rs_sta->win[last_index], - tx_resp->flags & IEEE80211_TX_STATUS_ACK, 1); + info->flags & IEEE80211_TX_STAT_ACK, 1); /* We updated the rate scale window -- if its been more than * flush_time since the last run, schedule the flush diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index f8e691f88ab..0ba6889dfd4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -283,8 +283,7 @@ static void iwl3945_tx_queue_reclaim(struct iwl3945_priv *priv, q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { tx_info = &txq->txb[txq->q.read_ptr]; - ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0], - &tx_info->status); + ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0]); tx_info->skb[0] = NULL; iwl3945_hw_txq_free_tfd(priv, txq); } @@ -306,7 +305,7 @@ static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv, int txq_id = SEQ_TO_QUEUE(sequence); int index = SEQ_TO_INDEX(sequence); struct iwl3945_tx_queue *txq = &priv->txq[txq_id]; - struct ieee80211_tx_status *tx_status; + struct ieee80211_tx_info *info; struct iwl3945_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; u32 status = le32_to_cpu(tx_resp->status); int rate_idx; @@ -319,21 +318,22 @@ static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv, return; } - tx_status = &(txq->txb[txq->q.read_ptr].status); + info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]); + memset(&info->status, 0, sizeof(info->status)); - tx_status->retry_count = tx_resp->failure_frame; + info->status.retry_count = tx_resp->failure_frame; /* tx_status->rts_retry_count = tx_resp->failure_rts; */ - tx_status->flags = ((status & TX_STATUS_MSK) == TX_STATUS_SUCCESS) ? - IEEE80211_TX_STATUS_ACK : 0; + info->flags |= ((status & TX_STATUS_MSK) == TX_STATUS_SUCCESS) ? + IEEE80211_TX_STAT_ACK : 0; IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) plcp rate %d retries %d\n", txq_id, iwl3945_get_tx_fail_reason(status), status, tx_resp->rate, tx_resp->failure_frame); rate_idx = iwl3945_hwrate_to_plcp_idx(tx_resp->rate); - if (tx_status->control.band == IEEE80211_BAND_5GHZ) + if (info->band == IEEE80211_BAND_5GHZ) rate_idx -= IWL_FIRST_OFDM_RATE; - tx_status->control.tx_rate_idx = rate_idx; + info->tx_rate_idx = rate_idx; IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); iwl3945_tx_queue_reclaim(priv, txq_id, index); @@ -960,11 +960,11 @@ u8 iwl3945_hw_find_station(struct iwl3945_priv *priv, const u8 *addr) */ void iwl3945_hw_build_tx_cmd_rate(struct iwl3945_priv *priv, struct iwl3945_cmd *cmd, - struct ieee80211_tx_control *ctrl, + struct ieee80211_tx_info *info, struct ieee80211_hdr *hdr, int sta_id, int tx_id) { unsigned long flags; - u16 hw_value = ieee80211_get_tx_rate(priv->hw, ctrl)->hw_value; + u16 hw_value = ieee80211_get_tx_rate(priv->hw, info)->hw_value; u16 rate_index = min(hw_value & 0xffff, IWL_RATE_COUNT - 1); u16 rate_mask; int rate; @@ -977,7 +977,7 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl3945_priv *priv, tx_flags = cmd->cmd.tx.tx_flags; /* We need to figure out how to get the sta->supp_rates while - * in this running context; perhaps encoding into ctrl->tx_rate? */ + * in this running context */ rate_mask = IWL_RATES_MASK; spin_lock_irqsave(&priv->sta_lock, flags); diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index 9fdc1405e85..835c5b4320e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -124,7 +124,6 @@ int iwl3945_x2_queue_used(const struct iwl3945_queue *q, int i); /* One for each TFD */ struct iwl3945_tx_info { - struct ieee80211_tx_status status; struct sk_buff *skb[MAX_NUM_OF_TBS]; }; @@ -645,7 +644,7 @@ extern unsigned int iwl3945_hw_get_beacon_cmd(struct iwl3945_priv *priv, extern int iwl3945_hw_get_rx_read(struct iwl3945_priv *priv); extern void iwl3945_hw_build_tx_cmd_rate(struct iwl3945_priv *priv, struct iwl3945_cmd *cmd, - struct ieee80211_tx_control *ctrl, + struct ieee80211_tx_info *info, struct ieee80211_hdr *hdr, int sta_id, int tx_id); extern int iwl3945_hw_reg_send_txpower(struct iwl3945_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index 7993a1d8302..f28b3cc272d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -785,8 +785,7 @@ out: * mac80211 sends us Tx status */ static void rs_tx_status(void *priv_rate, struct net_device *dev, - struct sk_buff *skb, - struct ieee80211_tx_status *tx_resp) + struct sk_buff *skb) { int status; u8 retries; @@ -798,6 +797,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, struct iwl_priv *priv = (struct iwl_priv *)priv_rate; struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_hw *hw = local_to_hw(local); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl4965_rate_scale_data *window = NULL; struct iwl4965_rate_scale_data *search_win = NULL; u32 tx_rate; @@ -813,11 +813,11 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, return; /* This packet was aggregated but doesn't carry rate scale info */ - if ((tx_resp->control.flags & IEEE80211_TXCTL_AMPDU) && - !(tx_resp->flags & IEEE80211_TX_STATUS_AMPDU)) + if ((info->flags & IEEE80211_TX_CTL_AMPDU) && + !(info->flags & IEEE80211_TX_STAT_AMPDU)) return; - retries = tx_resp->retry_count; + retries = info->status.retry_count; if (retries > 15) retries = 15; @@ -862,20 +862,20 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, if (priv->band == IEEE80211_BAND_5GHZ) rs_index -= IWL_FIRST_OFDM_RATE; - if ((tx_resp->control.tx_rate_idx < 0) || + if ((info->tx_rate_idx < 0) || (tbl_type.is_SGI ^ - !!(tx_resp->control.flags & IEEE80211_TXCTL_SHORT_GI)) || + !!(info->flags & IEEE80211_TX_CTL_SHORT_GI)) || (tbl_type.is_fat ^ - !!(tx_resp->control.flags & IEEE80211_TXCTL_40_MHZ_WIDTH)) || + !!(info->flags & IEEE80211_TX_CTL_40_MHZ_WIDTH)) || (tbl_type.is_dup ^ - !!(tx_resp->control.flags & IEEE80211_TXCTL_DUP_DATA)) || - (tbl_type.ant_type ^ tx_resp->control.antenna_sel_tx) || + !!(info->flags & IEEE80211_TX_CTL_DUP_DATA)) || + (tbl_type.ant_type ^ info->antenna_sel_tx) || (!!(tx_rate & RATE_MCS_HT_MSK) ^ - !!(tx_resp->control.flags & IEEE80211_TXCTL_OFDM_HT)) || + !!(info->flags & IEEE80211_TX_CTL_OFDM_HT)) || (!!(tx_rate & RATE_MCS_GF_MSK) ^ - !!(tx_resp->control.flags & IEEE80211_TXCTL_GREEN_FIELD)) || + !!(info->flags & IEEE80211_TX_CTL_GREEN_FIELD)) || (hw->wiphy->bands[priv->band]->bitrates[rs_index].bitrate != - hw->wiphy->bands[tx_resp->control.band]->bitrates[tx_resp->control.tx_rate_idx].bitrate)) { + hw->wiphy->bands[info->band]->bitrates[info->tx_rate_idx].bitrate)) { IWL_DEBUG_RATE("initial rate does not match 0x%x\n", tx_rate); goto out; } @@ -929,10 +929,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type, &rs_index); /* Update frame history window with "success" if Tx got ACKed ... */ - if (tx_resp->flags & IEEE80211_TX_STATUS_ACK) - status = 1; - else - status = 0; + status = !!(info->flags & IEEE80211_TX_STAT_ACK); /* If type matches "search" table, * add final tx status to "search" history */ @@ -943,10 +940,10 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, tpt = search_tbl->expected_tpt[rs_index]; else tpt = 0; - if (tx_resp->control.flags & IEEE80211_TXCTL_AMPDU) + if (info->flags & IEEE80211_TX_CTL_AMPDU) rs_collect_tx_data(search_win, rs_index, tpt, - tx_resp->ampdu_ack_len, - tx_resp->ampdu_ack_map); + info->status.ampdu_ack_len, + info->status.ampdu_ack_map); else rs_collect_tx_data(search_win, rs_index, tpt, 1, status); @@ -959,10 +956,10 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, tpt = curr_tbl->expected_tpt[rs_index]; else tpt = 0; - if (tx_resp->control.flags & IEEE80211_TXCTL_AMPDU) + if (info->flags & IEEE80211_TX_CTL_AMPDU) rs_collect_tx_data(window, rs_index, tpt, - tx_resp->ampdu_ack_len, - tx_resp->ampdu_ack_map); + info->status.ampdu_ack_len, + info->status.ampdu_ack_map); else rs_collect_tx_data(window, rs_index, tpt, 1, status); @@ -971,10 +968,10 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, /* If not searching for new mode, increment success/failed counter * ... these help determine when to start searching again */ if (lq_sta->stay_in_tbl) { - if (tx_resp->control.flags & IEEE80211_TXCTL_AMPDU) { - lq_sta->total_success += tx_resp->ampdu_ack_map; + if (info->flags & IEEE80211_TX_CTL_AMPDU) { + lq_sta->total_success += info->status.ampdu_ack_map; lq_sta->total_failed += - (tx_resp->ampdu_ack_len - tx_resp->ampdu_ack_map); + (info->status.ampdu_ack_len - info->status.ampdu_ack_map); } else { if (status) lq_sta->total_success++; diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index fb670b5cfeb..ca9ca92bb7f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -357,22 +357,22 @@ int iwl4965_hwrate_to_plcp_idx(u32 rate_n_flags) * translate ucode response to mac80211 tx status control values */ void iwl4965_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, - struct ieee80211_tx_control *control) + struct ieee80211_tx_info *control) { int rate_index; control->antenna_sel_tx = ((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS); if (rate_n_flags & RATE_MCS_HT_MSK) - control->flags |= IEEE80211_TXCTL_OFDM_HT; + control->flags |= IEEE80211_TX_CTL_OFDM_HT; if (rate_n_flags & RATE_MCS_GF_MSK) - control->flags |= IEEE80211_TXCTL_GREEN_FIELD; + control->flags |= IEEE80211_TX_CTL_GREEN_FIELD; if (rate_n_flags & RATE_MCS_FAT_MSK) - control->flags |= IEEE80211_TXCTL_40_MHZ_WIDTH; + control->flags |= IEEE80211_TX_CTL_40_MHZ_WIDTH; if (rate_n_flags & RATE_MCS_DUP_MSK) - control->flags |= IEEE80211_TXCTL_DUP_DATA; + control->flags |= IEEE80211_TX_CTL_DUP_DATA; if (rate_n_flags & RATE_MCS_SGI_MSK) - control->flags |= IEEE80211_TXCTL_SHORT_GI; + control->flags |= IEEE80211_TX_CTL_SHORT_GI; rate_index = iwl4965_hwrate_to_plcp_idx(rate_n_flags); if (control->band == IEEE80211_BAND_5GHZ) rate_index -= IWL_FIRST_OFDM_RATE; @@ -3007,7 +3007,7 @@ static int iwl4965_tx_status_reply_compressed_ba(struct iwl_priv *priv, u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); u64 bitmap; int successes = 0; - struct ieee80211_tx_status *tx_status; + struct ieee80211_tx_info *info; if (unlikely(!agg->wait_for_ba)) { IWL_ERROR("Received BA when not expected\n"); @@ -3045,13 +3045,13 @@ static int iwl4965_tx_status_reply_compressed_ba(struct iwl_priv *priv, agg->start_idx + i); } - tx_status = &priv->txq[scd_flow].txb[agg->start_idx].status; - tx_status->flags = IEEE80211_TX_STATUS_ACK; - tx_status->flags |= IEEE80211_TX_STATUS_AMPDU; - tx_status->ampdu_ack_map = successes; - tx_status->ampdu_ack_len = agg->frame_count; - iwl4965_hwrate_to_tx_control(priv, agg->rate_n_flags, - &tx_status->control); + info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb[0]); + memset(&info->status, 0, sizeof(info->status)); + info->flags = IEEE80211_TX_STAT_ACK; + info->flags |= IEEE80211_TX_STAT_AMPDU; + info->status.ampdu_ack_map = successes; + info->status.ampdu_ack_len = agg->frame_count; + iwl4965_hwrate_to_tx_control(priv, agg->rate_n_flags, info); IWL_DEBUG_TX_REPLY("Bitmap %llx\n", (unsigned long long)bitmap); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index a8d062f7b87..ad7422eadab 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -207,8 +207,7 @@ void iwl_rx_allocate(struct iwl_priv *priv); * TX ******************************************************/ int iwl_txq_ctx_reset(struct iwl_priv *priv); -int iwl_tx_skb(struct iwl_priv *priv, - struct sk_buff *skb, struct ieee80211_tx_control *ctl); +int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb); /* FIXME: remove when free Tx is fully merged into iwlcore */ int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq); void iwl_hw_txq_ctx_free(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 820542bac44..f7fd8ea6177 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -119,7 +119,6 @@ struct iwl_queue { /* One for each TFD */ struct iwl_tx_info { - struct ieee80211_tx_status status; struct sk_buff *skb[MAX_NUM_OF_TBS]; }; @@ -693,7 +692,7 @@ extern unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, struct iwl_frame *frame, u8 rate); extern void iwl4965_hw_build_tx_cmd_rate(struct iwl_priv *priv, struct iwl_cmd *cmd, - struct ieee80211_tx_control *ctrl, + struct ieee80211_tx_info *info, struct ieee80211_hdr *hdr, int sta_id, int tx_id); extern int iwl4965_hw_reg_send_txpower(struct iwl_priv *priv); @@ -749,7 +748,7 @@ extern void iwl4965_update_rate_scaling(struct iwl_priv *priv, u8 mode); extern void iwl4965_rf_kill_ct_config(struct iwl_priv *priv); extern void iwl4965_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, - struct ieee80211_tx_control *control); + struct ieee80211_tx_info *info); #ifdef CONFIG_IWL4965_HT extern void iwl4965_init_ht_hw_capab(const struct iwl_priv *priv, diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 4b5149c8c32..a61293ba3f6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -502,7 +502,7 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv) */ static void iwl_tx_cmd_build_basic(struct iwl_priv *priv, struct iwl_tx_cmd *tx_cmd, - struct ieee80211_tx_control *ctrl, + struct ieee80211_tx_info *info, struct ieee80211_hdr *hdr, int is_unicast, u8 std_id) { @@ -510,7 +510,7 @@ static void iwl_tx_cmd_build_basic(struct iwl_priv *priv, __le32 tx_flags = tx_cmd->tx_flags; tx_cmd->stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; - if (!(ctrl->flags & IEEE80211_TXCTL_NO_ACK)) { + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { tx_flags |= TX_CMD_FLG_ACK_MSK; if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; @@ -538,10 +538,10 @@ static void iwl_tx_cmd_build_basic(struct iwl_priv *priv, tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; } - if (ctrl->flags & IEEE80211_TXCTL_USE_RTS_CTS) { + if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { tx_flags |= TX_CMD_FLG_RTS_MSK; tx_flags &= ~TX_CMD_FLG_CTS_MSK; - } else if (ctrl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { + } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { tx_flags &= ~TX_CMD_FLG_RTS_MSK; tx_flags |= TX_CMD_FLG_CTS_MSK; } @@ -570,7 +570,7 @@ static void iwl_tx_cmd_build_basic(struct iwl_priv *priv, static void iwl_tx_cmd_build_rate(struct iwl_priv *priv, struct iwl_tx_cmd *tx_cmd, - struct ieee80211_tx_control *ctrl, + struct ieee80211_tx_info *info, u16 fc, int sta_id, int is_hcca) { @@ -580,7 +580,7 @@ static void iwl_tx_cmd_build_rate(struct iwl_priv *priv, u16 rate_flags = 0; int rate_idx; - rate_idx = min(ieee80211_get_tx_rate(priv->hw, ctrl)->hw_value & 0xffff, + rate_idx = min(ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xffff, IWL_RATE_COUNT - 1); rate_plcp = iwl_rates[rate_idx].plcp; @@ -637,18 +637,18 @@ static void iwl_tx_cmd_build_rate(struct iwl_priv *priv, } static void iwl_tx_cmd_build_hwcrypto(struct iwl_priv *priv, - struct ieee80211_tx_control *ctl, + struct ieee80211_tx_info *info, struct iwl_tx_cmd *tx_cmd, struct sk_buff *skb_frag, int sta_id) { - struct ieee80211_key_conf *keyconf = ctl->hw_key; + struct ieee80211_key_conf *keyconf = info->control.hw_key; switch (keyconf->alg) { case ALG_CCMP: tx_cmd->sec_ctl = TX_CMD_SEC_CCM; memcpy(tx_cmd->key, keyconf->key, keyconf->keylen); - if (ctl->flags & IEEE80211_TXCTL_AMPDU) + if (info->flags & IEEE80211_TX_CTL_AMPDU) tx_cmd->tx_flags |= TX_CMD_FLG_AGG_CCMP_MSK; IWL_DEBUG_TX("tx_cmd with aes hwcrypto\n"); break; @@ -690,13 +690,13 @@ static void iwl_update_tx_stats(struct iwl_priv *priv, u16 fc, u16 len) /* * start REPLY_TX command process */ -int iwl_tx_skb(struct iwl_priv *priv, - struct sk_buff *skb, struct ieee80211_tx_control *ctl) +int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl_tfd_frame *tfd; u32 *control_flags; - int txq_id = ctl->queue; + int txq_id = info->queue; struct iwl_tx_queue *txq = NULL; struct iwl_queue *q = NULL; dma_addr_t phys_addr; @@ -726,7 +726,7 @@ int iwl_tx_skb(struct iwl_priv *priv, goto drop_unlock; } - if ((ieee80211_get_tx_rate(priv->hw, ctl)->hw_value & 0xFF) == + if ((ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xFF) == IWL_INVALID_RATE) { IWL_ERROR("ERROR: No TX rate available.\n"); goto drop_unlock; @@ -782,7 +782,7 @@ int iwl_tx_skb(struct iwl_priv *priv, seq_number += 0x10; #ifdef CONFIG_IWL4965_HT /* aggregation is on for this */ - if (ctl->flags & IEEE80211_TXCTL_AMPDU) + if (info->flags & IEEE80211_TX_CTL_AMPDU) txq_id = priv->stations[sta_id].tid[tid].agg.txq_id; priv->stations[sta_id].tid[tid].tfds_in_queue++; #endif /* CONFIG_IWL4965_HT */ @@ -803,8 +803,6 @@ int iwl_tx_skb(struct iwl_priv *priv, /* Set up driver data for this TFD */ memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info)); txq->txb[q->write_ptr].skb[0] = skb; - memcpy(&(txq->txb[q->write_ptr].status.control), - ctl, sizeof(struct ieee80211_tx_control)); /* Set up first empty entry in queue's array of Tx/cmd buffers */ out_cmd = &txq->cmd[idx]; @@ -854,8 +852,8 @@ int iwl_tx_skb(struct iwl_priv *priv, * first entry */ iwl_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len); - if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) - iwl_tx_cmd_build_hwcrypto(priv, ctl, tx_cmd, skb, sta_id); + if (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT)) + iwl_tx_cmd_build_hwcrypto(priv, info, tx_cmd, skb, sta_id); /* Set up TFD's 2nd entry to point directly to remainder of skb, * if any (802.11 null frames have no payload). */ @@ -874,10 +872,10 @@ int iwl_tx_skb(struct iwl_priv *priv, len = (u16)skb->len; tx_cmd->len = cpu_to_le16(len); /* TODO need this for burst mode later on */ - iwl_tx_cmd_build_basic(priv, tx_cmd, ctl, hdr, unicast, sta_id); + iwl_tx_cmd_build_basic(priv, tx_cmd, info, hdr, unicast, sta_id); /* set is_hcca to 0; it probably will never be implemented */ - iwl_tx_cmd_build_rate(priv, tx_cmd, ctl, fc, sta_id, 0); + iwl_tx_cmd_build_rate(priv, tx_cmd, info, fc, sta_id, 0); iwl_update_tx_stats(priv, fc, len); @@ -919,7 +917,7 @@ int iwl_tx_skb(struct iwl_priv *priv, spin_unlock_irqrestore(&priv->lock, flags); } - ieee80211_stop_queue(priv->hw, ctl->queue); + ieee80211_stop_queue(priv->hw, info->queue); } return 0; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index a28b4c9f652..a740a1817d1 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2376,13 +2376,13 @@ static int iwl3945_set_mode(struct iwl3945_priv *priv, int mode) } static void iwl3945_build_tx_cmd_hwcrypto(struct iwl3945_priv *priv, - struct ieee80211_tx_control *ctl, + struct ieee80211_tx_info *info, struct iwl3945_cmd *cmd, struct sk_buff *skb_frag, int last_frag) { struct iwl3945_hw_key *keyinfo = - &priv->stations[ctl->hw_key->hw_key_idx].keyinfo; + &priv->stations[info->control.hw_key->hw_key_idx].keyinfo; switch (keyinfo->alg) { case ALG_CCMP: @@ -2405,7 +2405,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl3945_priv *priv, case ALG_WEP: cmd->cmd.tx.sec_ctl = TX_CMD_SEC_WEP | - (ctl->hw_key->hw_key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT; + (info->control.hw_key->hw_key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT; if (keyinfo->keylen == 13) cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128; @@ -2413,7 +2413,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl3945_priv *priv, memcpy(&cmd->cmd.tx.key[3], keyinfo->key, keyinfo->keylen); IWL_DEBUG_TX("Configuring packet for WEP encryption " - "with key %d\n", ctl->hw_key->hw_key_idx); + "with key %d\n", info->control.hw_key->hw_key_idx); break; default: @@ -2427,7 +2427,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl3945_priv *priv, */ static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv, struct iwl3945_cmd *cmd, - struct ieee80211_tx_control *ctrl, + struct ieee80211_tx_info *info, struct ieee80211_hdr *hdr, int is_unicast, u8 std_id) { @@ -2435,7 +2435,7 @@ static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv, __le32 tx_flags = cmd->cmd.tx.tx_flags; cmd->cmd.tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; - if (!(ctrl->flags & IEEE80211_TXCTL_NO_ACK)) { + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { tx_flags |= TX_CMD_FLG_ACK_MSK; if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; @@ -2459,10 +2459,10 @@ static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv, tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; } - if (ctrl->flags & IEEE80211_TXCTL_USE_RTS_CTS) { + if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { tx_flags |= TX_CMD_FLG_RTS_MSK; tx_flags &= ~TX_CMD_FLG_CTS_MSK; - } else if (ctrl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { + } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { tx_flags &= ~TX_CMD_FLG_RTS_MSK; tx_flags |= TX_CMD_FLG_CTS_MSK; } @@ -2546,13 +2546,13 @@ static int iwl3945_get_sta_id(struct iwl3945_priv *priv, struct ieee80211_hdr *h /* * start REPLY_TX command process */ -static int iwl3945_tx_skb(struct iwl3945_priv *priv, - struct sk_buff *skb, struct ieee80211_tx_control *ctl) +static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl3945_tfd_frame *tfd; u32 *control_flags; - int txq_id = ctl->queue; + int txq_id = info->queue; struct iwl3945_tx_queue *txq = NULL; struct iwl3945_queue *q = NULL; dma_addr_t phys_addr; @@ -2581,7 +2581,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, goto drop_unlock; } - if ((ieee80211_get_tx_rate(priv->hw, ctl)->hw_value & 0xFF) == IWL_INVALID_RATE) { + if ((ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xFF) == IWL_INVALID_RATE) { IWL_ERROR("ERROR: No TX rate available.\n"); goto drop_unlock; } @@ -2650,8 +2650,6 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, /* Set up driver data for this TFD */ memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl3945_tx_info)); txq->txb[q->write_ptr].skb[0] = skb; - memcpy(&(txq->txb[q->write_ptr].status.control), - ctl, sizeof(struct ieee80211_tx_control)); /* Init first empty entry in queue's array of Tx/cmd buffers */ out_cmd = &txq->cmd[idx]; @@ -2700,8 +2698,8 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, * first entry */ iwl3945_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len); - if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) - iwl3945_build_tx_cmd_hwcrypto(priv, ctl, out_cmd, skb, 0); + if (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT)) + iwl3945_build_tx_cmd_hwcrypto(priv, info, out_cmd, skb, 0); /* Set up TFD's 2nd entry to point directly to remainder of skb, * if any (802.11 null frames have no payload). */ @@ -2726,10 +2724,10 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, out_cmd->cmd.tx.len = cpu_to_le16(len); /* TODO need this for burst mode later on */ - iwl3945_build_tx_cmd_basic(priv, out_cmd, ctl, hdr, unicast, sta_id); + iwl3945_build_tx_cmd_basic(priv, out_cmd, info, hdr, unicast, sta_id); /* set is_hcca to 0; it probably will never be implemented */ - iwl3945_hw_build_tx_cmd_rate(priv, out_cmd, ctl, hdr, sta_id, 0); + iwl3945_hw_build_tx_cmd_rate(priv, out_cmd, info, hdr, sta_id, 0); out_cmd->cmd.tx.tx_flags &= ~TX_CMD_FLG_ANT_A_MSK; out_cmd->cmd.tx.tx_flags &= ~TX_CMD_FLG_ANT_B_MSK; @@ -2767,7 +2765,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, spin_unlock_irqrestore(&priv->lock, flags); } - ieee80211_stop_queue(priv->hw, ctl->queue); + ieee80211_stop_queue(priv->hw, info->queue); } return 0; @@ -3230,7 +3228,7 @@ static void iwl3945_bg_beacon_update(struct work_struct *work) struct sk_buff *beacon; /* Pull updated AP beacon from mac80211. will fail if not in AP mode */ - beacon = ieee80211_beacon_get(priv->hw, priv->vif, NULL); + beacon = ieee80211_beacon_get(priv->hw, priv->vif); if (!beacon) { IWL_ERROR("update beacon failed\n"); @@ -6681,8 +6679,7 @@ static void iwl3945_mac_stop(struct ieee80211_hw *hw) IWL_DEBUG_MAC80211("leave\n"); } -static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *ctl) +static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct iwl3945_priv *priv = hw->priv; @@ -6694,9 +6691,9 @@ static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, } IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, - ieee80211_get_tx_rate(hw, ctl)->bitrate); + ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate); - if (iwl3945_tx_skb(priv, skb, ctl)) + if (iwl3945_tx_skb(priv, skb)) dev_kfree_skb_any(skb); IWL_DEBUG_MAC80211("leave\n"); @@ -7333,8 +7330,7 @@ static void iwl3945_mac_reset_tsf(struct ieee80211_hw *hw) } -static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *control) +static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) { struct iwl3945_priv *priv = hw->priv; unsigned long flags; diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 1fad6227aa5..07c52b69d1e 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -1606,17 +1606,7 @@ static int iwl4965_get_measurement(struct iwl_priv *priv, static void iwl4965_txstatus_to_ieee(struct iwl_priv *priv, struct iwl_tx_info *tx_sta) { - - tx_sta->status.ack_signal = 0; - tx_sta->status.excessive_retries = 0; - - if (in_interrupt()) - ieee80211_tx_status_irqsafe(priv->hw, - tx_sta->skb[0], &(tx_sta->status)); - else - ieee80211_tx_status(priv->hw, - tx_sta->skb[0], &(tx_sta->status)); - + ieee80211_tx_status_irqsafe(priv->hw, tx_sta->skb[0]); tx_sta->skb[0] = NULL; } @@ -1710,7 +1700,7 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv, { u16 status; struct agg_tx_status *frame_status = &tx_resp->status; - struct ieee80211_tx_status *tx_status = NULL; + struct ieee80211_tx_info *info = NULL; struct ieee80211_hdr *hdr = NULL; int i, sh; int txq_id, idx; @@ -1736,14 +1726,14 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv, IWL_DEBUG_TX_REPLY("FrameCnt = %d, StartIdx=%d idx=%d\n", agg->frame_count, agg->start_idx, idx); - tx_status = &(priv->txq[txq_id].txb[idx].status); - tx_status->retry_count = tx_resp->failure_frame; - tx_status->control.flags &= ~IEEE80211_TXCTL_AMPDU; - tx_status->flags = iwl4965_is_tx_success(status)? - IEEE80211_TX_STATUS_ACK : 0; + info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]); + info->status.retry_count = tx_resp->failure_frame; + info->flags &= ~IEEE80211_TX_CTL_AMPDU; + info->flags |= iwl4965_is_tx_success(status)? + IEEE80211_TX_STAT_ACK : 0; iwl4965_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags), - &tx_status->control); + info); /* FIXME: code repetition end */ IWL_DEBUG_TX_REPLY("1 Frame 0x%x failure :%d\n", @@ -1830,7 +1820,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, int txq_id = SEQ_TO_QUEUE(sequence); int index = SEQ_TO_INDEX(sequence); struct iwl_tx_queue *txq = &priv->txq[txq_id]; - struct ieee80211_tx_status *tx_status; + struct ieee80211_tx_info *info; struct iwl4965_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; u32 status = le32_to_cpu(tx_resp->status); #ifdef CONFIG_IWL4965_HT @@ -1848,6 +1838,9 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, return; } + info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]); + memset(&info->status, 0, sizeof(info->status)); + #ifdef CONFIG_IWL4965_HT hdr = iwl4965_tx_queue_get_hdr(priv, txq_id, index); fc = le16_to_cpu(hdr->frame_control); @@ -1902,13 +1895,12 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, } } else { #endif /* CONFIG_IWL4965_HT */ - tx_status = &(txq->txb[txq->q.read_ptr].status); - tx_status->retry_count = tx_resp->failure_frame; - tx_status->flags = - iwl4965_is_tx_success(status) ? IEEE80211_TX_STATUS_ACK : 0; + info->status.retry_count = tx_resp->failure_frame; + info->flags |= + iwl4965_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0; iwl4965_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags), - &tx_status->control); + info); IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags 0x%x " "retries %d\n", txq_id, iwl4965_get_tx_fail_reason(status), @@ -2053,7 +2045,7 @@ static void iwl4965_bg_beacon_update(struct work_struct *work) struct sk_buff *beacon; /* Pull updated AP beacon from mac80211. will fail if not in AP mode */ - beacon = ieee80211_beacon_get(priv->hw, priv->vif, NULL); + beacon = ieee80211_beacon_get(priv->hw, priv->vif); if (!beacon) { IWL_ERROR("update beacon failed\n"); @@ -4268,8 +4260,7 @@ static void iwl4965_mac_stop(struct ieee80211_hw *hw) IWL_DEBUG_MAC80211("leave\n"); } -static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *ctl) +static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct iwl_priv *priv = hw->priv; @@ -4281,9 +4272,9 @@ static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, } IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, - ieee80211_get_tx_rate(hw, ctl)->bitrate); + ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate); - if (iwl_tx_skb(priv, skb, ctl)) + if (iwl_tx_skb(priv, skb)) dev_kfree_skb_any(skb); IWL_DEBUG_MAC80211("leave\n"); @@ -5065,8 +5056,7 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw) IWL_DEBUG_MAC80211("leave\n"); } -static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *control) +static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) { struct iwl_priv *priv = hw->priv; unsigned long flags; diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 3ca9386561f..850857932e2 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -394,7 +394,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) while (entry != (struct sk_buff *)&priv->tx_queue) { range = (struct memrecord *)&entry->cb; if (range->start_addr == addr) { - struct ieee80211_tx_status status; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry); struct p54_control_hdr *entry_hdr; struct p54_tx_control_allocdata *entry_data; int pad = 0; @@ -406,30 +406,23 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) last_addr = range->end_addr; __skb_unlink(entry, &priv->tx_queue); - if (!range->control) { - kfree_skb(entry); - break; - } - memset(&status, 0, sizeof(status)); - memcpy(&status.control, range->control, - sizeof(status.control)); - kfree(range->control); - priv->tx_stats[status.control.queue].len--; + memset(&info->status, 0, sizeof(info->status)); + priv->tx_stats[info->queue].len--; entry_hdr = (struct p54_control_hdr *) entry->data; entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data; if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0) pad = entry_data->align[0]; - if (!(status.control.flags & IEEE80211_TXCTL_NO_ACK)) { + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { if (!(payload->status & 0x01)) - status.flags |= IEEE80211_TX_STATUS_ACK; + info->flags |= IEEE80211_TX_STAT_ACK; else - status.excessive_retries = 1; + info->status.excessive_retries = 1; } - status.retry_count = payload->retries - 1; - status.ack_signal = le16_to_cpu(payload->ack_rssi); + info->status.retry_count = payload->retries - 1; + info->status.ack_signal = le16_to_cpu(payload->ack_rssi); skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data)); - ieee80211_tx_status_irqsafe(dev, entry, &status); + ieee80211_tx_status_irqsafe(dev, entry); break; } else last_addr = range->end_addr; @@ -494,13 +487,11 @@ EXPORT_SYMBOL_GPL(p54_rx); * allocated areas. */ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, - struct p54_control_hdr *data, u32 len, - struct ieee80211_tx_control *control) + struct p54_control_hdr *data, u32 len) { struct p54_common *priv = dev->priv; struct sk_buff *entry = priv->tx_queue.next; struct sk_buff *target_skb = NULL; - struct memrecord *range; u32 last_addr = priv->rx_start; u32 largest_hole = 0; u32 target_addr = priv->rx_start; @@ -512,7 +503,8 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, left = skb_queue_len(&priv->tx_queue); while (left--) { u32 hole_size; - range = (struct memrecord *)&entry->cb; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry); + struct memrecord *range = (void *)info->driver_data; hole_size = range->start_addr - last_addr; if (!target_skb && hole_size >= len) { target_skb = entry->prev; @@ -527,17 +519,18 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, target_skb = priv->tx_queue.prev; largest_hole = max(largest_hole, priv->rx_end - last_addr - len); if (!skb_queue_empty(&priv->tx_queue)) { - range = (struct memrecord *)&target_skb->cb; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(target_skb); + struct memrecord *range = (void *)info->driver_data; target_addr = range->end_addr; } } else largest_hole = max(largest_hole, priv->rx_end - last_addr); if (skb) { - range = (struct memrecord *)&skb->cb; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct memrecord *range = (void *)info->driver_data; range->start_addr = target_addr; range->end_addr = target_addr + len; - range->control = control; __skb_queue_after(&priv->tx_queue, target_skb, skb); if (largest_hole < IEEE80211_MAX_RTS_THRESHOLD + 0x170 + sizeof(struct p54_control_hdr)) @@ -548,32 +541,27 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, data->req_id = cpu_to_le32(target_addr + 0x70); } -static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb, - struct ieee80211_tx_control *control) +static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_queue_stats *current_queue; struct p54_common *priv = dev->priv; struct p54_control_hdr *hdr; struct p54_tx_control_allocdata *txhdr; - struct ieee80211_tx_control *control_copy; size_t padding, len; u8 rate; - current_queue = &priv->tx_stats[control->queue]; + current_queue = &priv->tx_stats[info->queue]; if (unlikely(current_queue->len > current_queue->limit)) return NETDEV_TX_BUSY; current_queue->len++; current_queue->count++; if (current_queue->len == current_queue->limit) - ieee80211_stop_queue(dev, control->queue); + ieee80211_stop_queue(dev, info->queue); padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3; len = skb->len; - control_copy = kmalloc(sizeof(*control), GFP_ATOMIC); - if (control_copy) - memcpy(control_copy, control, sizeof(*control)); - txhdr = (struct p54_tx_control_allocdata *) skb_push(skb, sizeof(*txhdr) + padding); hdr = (struct p54_control_hdr *) skb_push(skb, sizeof(*hdr)); @@ -583,35 +571,37 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb, else hdr->magic1 = cpu_to_le16(0x0010); hdr->len = cpu_to_le16(len); - hdr->type = (control->flags & IEEE80211_TXCTL_NO_ACK) ? 0 : cpu_to_le16(1); - hdr->retry1 = hdr->retry2 = control->retry_limit; - p54_assign_address(dev, skb, hdr, skb->len, control_copy); + hdr->type = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? 0 : cpu_to_le16(1); + hdr->retry1 = hdr->retry2 = info->control.retry_limit; memset(txhdr->wep_key, 0x0, 16); txhdr->padding = 0; txhdr->padding2 = 0; /* TODO: add support for alternate retry TX rates */ - rate = ieee80211_get_tx_rate(dev, control)->hw_value; - if (control->flags & IEEE80211_TXCTL_SHORT_PREAMBLE) + rate = ieee80211_get_tx_rate(dev, info)->hw_value; + if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE) rate |= 0x10; - if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) + if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) rate |= 0x40; - else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) + else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) rate |= 0x20; memset(txhdr->rateset, rate, 8); txhdr->wep_key_present = 0; txhdr->wep_key_len = 0; - txhdr->frame_type = cpu_to_le32(control->queue + 4); + txhdr->frame_type = cpu_to_le32(info->queue + 4); txhdr->magic4 = 0; - txhdr->antenna = (control->antenna_sel_tx == 0) ? - 2 : control->antenna_sel_tx - 1; + txhdr->antenna = (info->antenna_sel_tx == 0) ? + 2 : info->antenna_sel_tx - 1; txhdr->output_power = 0x7f; // HW Maximum - txhdr->magic5 = (control->flags & IEEE80211_TXCTL_NO_ACK) ? + txhdr->magic5 = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? 0 : ((rate > 0x3) ? cpu_to_le32(0x33) : cpu_to_le32(0x23)); if (padding) txhdr->align[0] = padding; + /* modifies skb->cb and with it info, so must be last! */ + p54_assign_address(dev, skb, hdr, skb->len); + priv->tx(dev, hdr, skb->len, 0); return 0; } @@ -634,7 +624,7 @@ static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type, filter = (struct p54_tx_control_filter *) hdr->data; hdr->magic1 = cpu_to_le16(0x8001); hdr->len = cpu_to_le16(sizeof(*filter)); - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*filter), NULL); + p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*filter)); hdr->type = cpu_to_le16(P54_CONTROL_TYPE_FILTER_SET); filter->filter_type = cpu_to_le16(filter_type); @@ -678,7 +668,7 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq) hdr->magic1 = cpu_to_le16(0x8001); hdr->len = cpu_to_le16(sizeof(*chan)); hdr->type = cpu_to_le16(P54_CONTROL_TYPE_CHANNEL_CHANGE); - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + payload_len, NULL); + p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + payload_len); chan->magic1 = cpu_to_le16(0x1); chan->magic2 = cpu_to_le16(0x0); @@ -751,7 +741,7 @@ static int p54_set_leds(struct ieee80211_hw *dev, int mode, int link, int act) hdr->magic1 = cpu_to_le16(0x8001); hdr->len = cpu_to_le16(sizeof(*led)); hdr->type = cpu_to_le16(P54_CONTROL_TYPE_LED); - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*led), NULL); + p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*led)); led = (struct p54_tx_control_led *) hdr->data; led->mode = cpu_to_le16(mode); @@ -801,7 +791,7 @@ static void p54_set_vdcf(struct ieee80211_hw *dev) hdr = (void *)priv->cached_vdcf + priv->tx_hdr_len; - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*vdcf), NULL); + p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*vdcf)); vdcf = (struct p54_tx_control_vdcf *) hdr->data; @@ -837,12 +827,8 @@ static void p54_stop(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; struct sk_buff *skb; - while ((skb = skb_dequeue(&priv->tx_queue))) { - struct memrecord *range = (struct memrecord *)&skb->cb; - if (range->control) - kfree(range->control); + while ((skb = skb_dequeue(&priv->tx_queue))) kfree_skb(skb); - } priv->stop(dev); priv->mode = IEEE80211_IF_TYPE_INVALID; } diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index c15b56e1d75..2245fcce92d 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -152,7 +152,6 @@ struct pda_pa_curve_data { struct memrecord { u32 start_addr; u32 end_addr; - struct ieee80211_tx_control *control; }; struct p54_eeprom_lm86 { diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 4fcba9b4635..900140d3b30 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1484,11 +1484,11 @@ static u64 rt2400pci_get_tsf(struct ieee80211_hw *hw) return tsf; } -static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *control) +static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) { struct rt2x00_dev *rt2x00dev = hw->priv; - struct rt2x00_intf *intf = vif_to_intf(control->vif); + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif); struct queue_entry_priv_pci *entry_priv; struct skb_frame_desc *skbdesc; struct txentry_desc txdesc; @@ -1504,7 +1504,7 @@ static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, * for our information. */ intf->beacon->skb = skb; - rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc, control); + rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc); /* * Fill in skb descriptor diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 06e87cdff45..673350953b8 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1799,11 +1799,11 @@ static u64 rt2500pci_get_tsf(struct ieee80211_hw *hw) return tsf; } -static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *control) +static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) { struct rt2x00_dev *rt2x00dev = hw->priv; - struct rt2x00_intf *intf = vif_to_intf(control->vif); + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif); struct queue_entry_priv_pci *entry_priv; struct skb_frame_desc *skbdesc; struct txentry_desc txdesc; @@ -1820,7 +1820,7 @@ static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, * for our information. */ intf->beacon->skb = skb; - rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc, control); + rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc); /* * Fill in skb descriptor diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 4122c5ebe7c..cca1504550d 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1666,13 +1666,12 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ -static int rt2500usb_beacon_update(struct ieee80211_hw *hw, - struct sk_buff *skb, - struct ieee80211_tx_control *control) +static int rt2500usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) { struct rt2x00_dev *rt2x00dev = hw->priv; struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev); - struct rt2x00_intf *intf = vif_to_intf(control->vif); + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif); struct queue_entry_priv_usb_bcn *bcn_priv; struct skb_frame_desc *skbdesc; struct txentry_desc txdesc; @@ -1691,7 +1690,7 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw, * for our information. */ intf->beacon->skb = skb; - rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc, control); + rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc); /* * Add the descriptor in front of the skb. diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 1900d4c0e84..5c7220ea46e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -542,8 +542,7 @@ struct rt2x00lib_ops { struct sk_buff *skb, struct txentry_desc *txdesc); int (*write_tx_data) (struct rt2x00_dev *rt2x00dev, - struct data_queue *queue, struct sk_buff *skb, - struct ieee80211_tx_control *control); + struct data_queue *queue, struct sk_buff *skb); int (*get_tx_data_len) (struct rt2x00_dev *rt2x00dev, struct sk_buff *skb); void (*kick_tx_queue) (struct rt2x00_dev *rt2x00dev, @@ -930,7 +929,6 @@ static inline u16 get_duration_res(const unsigned int size, const u8 rate) * rt2x00queue_create_tx_descriptor - Create TX descriptor from mac80211 input * @entry: The entry which will be used to transfer the TX frame. * @txdesc: rt2x00 TX descriptor which will be initialized by this function. - * @control: mac80211 TX control structure from where we read the information. * * This function will initialize the &struct txentry_desc based on information * from mac80211. This descriptor can then be used by rt2x00lib and the drivers @@ -943,8 +941,7 @@ static inline u16 get_duration_res(const unsigned int size, const u8 rate) * the &struct txentry_desc structure. */ void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, - struct txentry_desc *txdesc, - struct ieee80211_tx_control *control); + struct txentry_desc *txdesc); /** * rt2x00queue_write_tx_descriptor - Write TX descriptor to hardware @@ -1001,8 +998,7 @@ void rt2x00lib_rxdone(struct queue_entry *entry, /* * mac80211 handlers. */ -int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *control); +int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb); int rt2x00mac_start(struct ieee80211_hw *hw); void rt2x00mac_stop(struct ieee80211_hw *hw); int rt2x00mac_add_interface(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index d341764e1b2..69e233610c9 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -415,7 +415,6 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac, struct rt2x00_dev *rt2x00dev = data; struct rt2x00_intf *intf = vif_to_intf(vif); struct sk_buff *skb; - struct ieee80211_tx_control control; struct ieee80211_bss_conf conf; int delayed_flags; @@ -433,9 +432,9 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac, spin_unlock(&intf->lock); if (delayed_flags & DELAYED_UPDATE_BEACON) { - skb = ieee80211_beacon_get(rt2x00dev->hw, vif, &control); - if (skb && rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, - skb, &control)) + skb = ieee80211_beacon_get(rt2x00dev->hw, vif); + if (skb && + rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, skb)) dev_kfree_skb(skb); } @@ -494,8 +493,13 @@ void rt2x00lib_txdone(struct queue_entry *entry, struct txdone_entry_desc *txdesc) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; - struct skb_frame_desc *skbdesc; - struct ieee80211_tx_status tx_status; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); + + /* + * Send frame to debugfs immediately, after this call is completed + * we are going to overwrite the skb->cb array. + */ + rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TXDONE, entry->skb); /* * Update TX statistics. @@ -508,21 +512,20 @@ void rt2x00lib_txdone(struct queue_entry *entry, /* * Initialize TX status */ - tx_status.flags = 0; - tx_status.ack_signal = 0; - tx_status.excessive_retries = + memset(&tx_info->status, 0, sizeof(tx_info->status)); + tx_info->status.ack_signal = 0; + tx_info->status.excessive_retries = test_bit(TXDONE_EXCESSIVE_RETRY, &txdesc->flags); - tx_status.retry_count = txdesc->retry; - memcpy(&tx_status.control, txdesc->control, sizeof(*txdesc->control)); + tx_info->status.retry_count = txdesc->retry; - if (!(tx_status.control.flags & IEEE80211_TXCTL_NO_ACK)) { + if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) { if (test_bit(TXDONE_SUCCESS, &txdesc->flags)) - tx_status.flags |= IEEE80211_TX_STATUS_ACK; + tx_info->flags |= IEEE80211_TX_STAT_ACK; else if (test_bit(TXDONE_FAILURE, &txdesc->flags)) rt2x00dev->low_level_stats.dot11ACKFailureCount++; } - if (tx_status.control.flags & IEEE80211_TXCTL_USE_RTS_CTS) { + if (tx_info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { if (test_bit(TXDONE_SUCCESS, &txdesc->flags)) rt2x00dev->low_level_stats.dot11RTSSuccessCount++; else if (test_bit(TXDONE_FAILURE, &txdesc->flags)) @@ -530,19 +533,13 @@ void rt2x00lib_txdone(struct queue_entry *entry, } /* - * Send the tx_status to debugfs. Only send the status report - * to mac80211 when the frame originated from there. If this was - * a extra frame coming through a mac80211 library call (RTS/CTS) - * then we should not send the status report back. - * If send to mac80211, mac80211 will clean up the skb structure, - * otherwise we have to do it ourself. + * Only send the status report to mac80211 when TX status was + * requested by it. If this was a extra frame coming through + * a mac80211 library call (RTS/CTS) then we should not send the + * status report back. */ - rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TXDONE, entry->skb); - - skbdesc = get_skb_frame_desc(entry->skb); - if (!(skbdesc->flags & FRAME_DESC_DRIVER_GENERATED)) - ieee80211_tx_status_irqsafe(rt2x00dev->hw, - entry->skb, &tx_status); + if (tx_info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) + ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb); else dev_kfree_skb_irq(entry->skb); entry->skb = NULL; diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index c5cedb29b87..b5379b027b1 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -31,14 +31,15 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, struct data_queue *queue, - struct sk_buff *frag_skb, - struct ieee80211_tx_control *control) + struct sk_buff *frag_skb) { + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(frag_skb); struct skb_frame_desc *skbdesc; + struct ieee80211_tx_info *rts_info; struct sk_buff *skb; int size; - if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) + if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) size = sizeof(struct ieee80211_cts); else size = sizeof(struct ieee80211_rts); @@ -52,13 +53,33 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, skb_reserve(skb, rt2x00dev->hw->extra_tx_headroom); skb_put(skb, size); - if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) - ieee80211_ctstoself_get(rt2x00dev->hw, control->vif, - frag_skb->data, frag_skb->len, control, + /* + * Copy TX information over from original frame to + * RTS/CTS frame. Note that we set the no encryption flag + * since we don't want this frame to be encrypted. + * RTS frames should be acked, while CTS-to-self frames + * should not. The ready for TX flag is cleared to prevent + * it being automatically send when the descriptor is + * written to the hardware. + */ + memcpy(skb->cb, frag_skb->cb, sizeof(skb->cb)); + rts_info = IEEE80211_SKB_CB(skb); + rts_info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT; + rts_info->flags &= ~IEEE80211_TX_CTL_USE_CTS_PROTECT; + rts_info->flags &= ~IEEE80211_TX_CTL_REQ_TX_STATUS; + + if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) + rts_info->flags |= IEEE80211_TX_CTL_NO_ACK; + else + rts_info->flags &= ~IEEE80211_TX_CTL_NO_ACK; + + if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) + ieee80211_ctstoself_get(rt2x00dev->hw, tx_info->control.vif, + frag_skb->data, size, tx_info, (struct ieee80211_cts *)(skb->data)); else - ieee80211_rts_get(rt2x00dev->hw, control->vif, - frag_skb->data, frag_skb->len, control, + ieee80211_rts_get(rt2x00dev->hw, tx_info->control.vif, + frag_skb->data, size, tx_info, (struct ieee80211_rts *)(skb->data)); /* @@ -68,7 +89,7 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, memset(skbdesc, 0, sizeof(*skbdesc)); skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED; - if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, queue, skb, control)) { + if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, queue, skb)) { WARNING(rt2x00dev, "Failed to send RTS/CTS frame.\n"); return NETDEV_TX_BUSY; } @@ -76,14 +97,13 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, return NETDEV_TX_OK; } -int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *control) +int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct rt2x00_dev *rt2x00dev = hw->priv; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data; - enum data_queue_qid qid = mac80211_queue_to_qid(control->queue); + enum data_queue_qid qid = mac80211_queue_to_qid(tx_info->queue); struct data_queue *queue; - struct skb_frame_desc *skbdesc; u16 frame_control; /* @@ -100,7 +120,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, /* * Determine which queue to put packet on. */ - if (control->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM && + if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM && test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags)) queue = rt2x00queue_get_queue(rt2x00dev, QID_ATIM); else @@ -125,33 +145,27 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, */ frame_control = le16_to_cpu(ieee80211hdr->frame_control); if (!is_rts_frame(frame_control) && !is_cts_frame(frame_control) && - (control->flags & (IEEE80211_TXCTL_USE_RTS_CTS | - IEEE80211_TXCTL_USE_CTS_PROTECT)) && + (tx_info->flags & (IEEE80211_TX_CTL_USE_RTS_CTS | + IEEE80211_TX_CTL_USE_CTS_PROTECT)) && !rt2x00dev->ops->hw->set_rts_threshold) { if (rt2x00queue_available(queue) <= 1) { - ieee80211_stop_queue(rt2x00dev->hw, control->queue); + ieee80211_stop_queue(rt2x00dev->hw, tx_info->queue); return NETDEV_TX_BUSY; } - if (rt2x00mac_tx_rts_cts(rt2x00dev, queue, skb, control)) { - ieee80211_stop_queue(rt2x00dev->hw, control->queue); + if (rt2x00mac_tx_rts_cts(rt2x00dev, queue, skb)) { + ieee80211_stop_queue(rt2x00dev->hw, tx_info->queue); return NETDEV_TX_BUSY; } } - /* - * Initialize skb descriptor - */ - skbdesc = get_skb_frame_desc(skb); - memset(skbdesc, 0, sizeof(*skbdesc)); - - if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, queue, skb, control)) { - ieee80211_stop_queue(rt2x00dev->hw, control->queue); + if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, queue, skb)) { + ieee80211_stop_queue(rt2x00dev->hw, tx_info->queue); return NETDEV_TX_BUSY; } if (rt2x00queue_full(queue)) - ieee80211_stop_queue(rt2x00dev->hw, control->queue); + ieee80211_stop_queue(rt2x00dev->hw, tx_info->queue); if (rt2x00dev->ops->lib->kick_tx_queue) rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, qid); @@ -380,9 +394,7 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw, if (conf->type != IEEE80211_IF_TYPE_AP || !conf->beacon) return 0; - status = rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, - conf->beacon, - conf->beacon_control); + status = rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, conf->beacon); if (status) dev_kfree_skb(conf->beacon); diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index fa7de41be04..70a3d135f64 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -35,8 +35,7 @@ * TX data handlers. */ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev, - struct data_queue *queue, struct sk_buff *skb, - struct ieee80211_tx_control *control) + struct data_queue *queue, struct sk_buff *skb) { struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); struct queue_entry_priv_pci *entry_priv = entry->priv_data; @@ -64,19 +63,19 @@ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev, * for our information. */ entry->skb = skb; - rt2x00queue_create_tx_descriptor(entry, &txdesc, control); + rt2x00queue_create_tx_descriptor(entry, &txdesc); /* * Fill in skb descriptor */ skbdesc = get_skb_frame_desc(skb); + memset(skbdesc, 0, sizeof(*skbdesc)); skbdesc->data = skb->data; skbdesc->data_len = skb->len; skbdesc->desc = entry_priv->desc; skbdesc->desc_len = queue->desc_size; skbdesc->entry = entry; - memcpy(&entry_priv->control, control, sizeof(entry_priv->control)); memcpy(entry_priv->data, skb->data, skb->len); rt2x00queue_write_tx_descriptor(entry, &txdesc); @@ -164,9 +163,9 @@ void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry, struct txdone_entry_desc *txdesc) { struct queue_entry_priv_pci *entry_priv = entry->priv_data; + enum data_queue_qid qid = skb_get_queue_mapping(entry->skb); u32 word; - txdesc->control = &entry_priv->control; rt2x00lib_txdone(entry, txdesc); /* @@ -187,7 +186,7 @@ void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry, * is reenabled when the txdone handler has finished. */ if (!rt2x00queue_full(entry->queue)) - ieee80211_wake_queue(rt2x00dev->hw, entry_priv->control.queue); + ieee80211_wake_queue(rt2x00dev->hw, qid); } EXPORT_SYMBOL_GPL(rt2x00pci_txdone); diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h index 557d15a888a..37c851e442c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.h +++ b/drivers/net/wireless/rt2x00/rt2x00pci.h @@ -91,8 +91,7 @@ rt2x00pci_register_multiwrite(struct rt2x00_dev *rt2x00dev, * TX data handlers. */ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev, - struct data_queue *queue, struct sk_buff *skb, - struct ieee80211_tx_control *control); + struct data_queue *queue, struct sk_buff *skb); /** * struct queue_entry_priv_pci: Per entry PCI specific information @@ -101,7 +100,6 @@ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev, * @desc_dma: DMA pointer to &desc. * @data: Pointer to device's entry memory. * @data_dma: DMA pointer to &data. - * @control: mac80211 control structure used to transmit data. */ struct queue_entry_priv_pci { __le32 *desc; @@ -109,8 +107,6 @@ struct queue_entry_priv_pci { void *data; dma_addr_t data_dma; - - struct ieee80211_tx_control control; }; /** diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 5cf4c2f5926..e69ef4b1923 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -30,13 +30,13 @@ #include "rt2x00lib.h" void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, - struct txentry_desc *txdesc, - struct ieee80211_tx_control *control) + struct txentry_desc *txdesc) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data; struct ieee80211_rate *rate = - ieee80211_get_tx_rate(rt2x00dev->hw, control); + ieee80211_get_tx_rate(rt2x00dev->hw, tx_info); const struct rt2x00_rate *hwrate; unsigned int data_length; unsigned int duration; @@ -64,7 +64,7 @@ void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, /* * Check whether this frame is to be acked. */ - if (!(control->flags & IEEE80211_TXCTL_NO_ACK)) + if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) __set_bit(ENTRY_TXD_ACK, &txdesc->flags); /* @@ -72,23 +72,20 @@ void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, */ if (is_rts_frame(frame_control) || is_cts_frame(frame_control)) { __set_bit(ENTRY_TXD_BURST, &txdesc->flags); - if (is_rts_frame(frame_control)) { + if (is_rts_frame(frame_control)) __set_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags); - __set_bit(ENTRY_TXD_ACK, &txdesc->flags); - } else { + else __set_bit(ENTRY_TXD_CTS_FRAME, &txdesc->flags); - __clear_bit(ENTRY_TXD_ACK, &txdesc->flags); - } - if (control->rts_cts_rate_idx >= 0) + if (tx_info->control.rts_cts_rate_idx >= 0) rate = - ieee80211_get_rts_cts_rate(rt2x00dev->hw, control); + ieee80211_get_rts_cts_rate(rt2x00dev->hw, tx_info); } /* * Determine retry information. */ - txdesc->retry_limit = control->retry_limit; - if (control->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT) + txdesc->retry_limit = tx_info->control.retry_limit; + if (tx_info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT) __set_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags); /* @@ -113,7 +110,7 @@ void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, */ if (test_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags)) { txdesc->ifs = IFS_SIFS; - } else if (control->flags & IEEE80211_TXCTL_FIRST_FRAGMENT) { + } else if (tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) { __set_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags); txdesc->ifs = IFS_BACKOFF; } else { @@ -179,8 +176,10 @@ void rt2x00queue_write_tx_descriptor(struct queue_entry *entry, /* * We are done writing the frame to the queue entry, - * if this entry is a RTS of CTS-to-self frame we are done, - * otherwise we need to kick the queue. + * also kick the queue in case the correct flags are set, + * note that this will automatically filter beacons and + * RTS/CTS frames since those frames don't have this flag + * set. */ if (rt2x00dev->ops->lib->kick_tx_queue && !(skbdesc->flags & FRAME_DESC_DRIVER_GENERATED)) diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index c6edc52873c..f263fe422f8 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -105,8 +105,8 @@ enum skb_frame_desc_flags { /** * struct skb_frame_desc: Descriptor information for the skb buffer * - * This structure is placed over the skb->cb array, this means that - * this structure should not exceed the size of that array (48 bytes). + * This structure is placed over the driver_data array, this means that + * this structure should not exceed the size of that array (40 bytes). * * @flags: Frame flags, see &enum skb_frame_desc_flags. * @data: Pointer to data part of frame (Start of ieee80211 header). @@ -129,10 +129,15 @@ struct skb_frame_desc { struct queue_entry *entry; }; +/** + * get_skb_frame_desc - Obtain the rt2x00 frame descriptor from a sk_buff. + * @skb: &struct sk_buff from where we obtain the &struct skb_frame_desc + */ static inline struct skb_frame_desc* get_skb_frame_desc(struct sk_buff *skb) { - BUILD_BUG_ON(sizeof(struct skb_frame_desc) > sizeof(skb->cb)); - return (struct skb_frame_desc *)&skb->cb[0]; + BUILD_BUG_ON(sizeof(struct skb_frame_desc) > + IEEE80211_TX_INFO_DRIVER_DATA_SIZE); + return (struct skb_frame_desc *)&IEEE80211_SKB_CB(skb)->driver_data; } /** @@ -189,12 +194,10 @@ enum txdone_entry_desc_flags { * Summary of information that has been read from the TX frame descriptor * after the device is done with transmission. * - * @control: Control structure which was used to transmit the frame. * @flags: TX done flags (See &enum txdone_entry_desc_flags). * @retry: Retry count. */ struct txdone_entry_desc { - struct ieee80211_tx_control *control; unsigned long flags; int retry; }; diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index dcee1b4f152..52d12fdc0cc 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -129,9 +129,9 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) { struct queue_entry *entry = (struct queue_entry *)urb->context; struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; - struct queue_entry_priv_usb *entry_priv = entry->priv_data; struct txdone_entry_desc txdesc; __le32 *txd = (__le32 *)entry->skb->data; + enum data_queue_qid qid = skb_get_queue_mapping(entry->skb); u32 word; if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || @@ -159,7 +159,6 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) else __set_bit(TXDONE_FAILURE, &txdesc.flags); txdesc.retry = 0; - txdesc.control = &entry_priv->control; rt2x00lib_txdone(entry, &txdesc); @@ -175,12 +174,11 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) * is reenabled when the txdone handler has finished. */ if (!rt2x00queue_full(entry->queue)) - ieee80211_wake_queue(rt2x00dev->hw, entry_priv->control.queue); + ieee80211_wake_queue(rt2x00dev->hw, qid); } int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, - struct data_queue *queue, struct sk_buff *skb, - struct ieee80211_tx_control *control) + struct data_queue *queue, struct sk_buff *skb) { struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev); struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); @@ -206,7 +204,7 @@ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, * for our information. */ entry->skb = skb; - rt2x00queue_create_tx_descriptor(entry, &txdesc, control); + rt2x00queue_create_tx_descriptor(entry, &txdesc); /* * Add the descriptor in front of the skb. @@ -218,13 +216,13 @@ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, * Fill in skb descriptor */ skbdesc = get_skb_frame_desc(skb); + memset(skbdesc, 0, sizeof(*skbdesc)); skbdesc->data = skb->data + queue->desc_size; skbdesc->data_len = skb->len - queue->desc_size; skbdesc->desc = skb->data; skbdesc->desc_len = queue->desc_size; skbdesc->entry = entry; - memcpy(&entry_priv->control, control, sizeof(entry_priv->control)); rt2x00queue_write_tx_descriptor(entry, &txdesc); /* diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index 15b404aa714..26f53f868af 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h @@ -216,19 +216,15 @@ void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev); * TX data handlers. */ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, - struct data_queue *queue, struct sk_buff *skb, - struct ieee80211_tx_control *control); + struct data_queue *queue, struct sk_buff *skb); /** * struct queue_entry_priv_usb: Per entry USB specific information * * @urb: Urb structure used for device communication. - * @control: mac80211 control structure used to transmit data. */ struct queue_entry_priv_usb { struct urb *urb; - - struct ieee80211_tx_control control; }; /** @@ -239,15 +235,12 @@ struct queue_entry_priv_usb { * with beacons. * * @urb: Urb structure used for device communication. - * @control: mac80211 control structure used to transmit data. * @guardian_data: Set to 0, used for sending the guardian data. * @guardian_urb: Urb structure used to send the guardian data. */ struct queue_entry_priv_usb_bcn { struct urb *urb; - struct ieee80211_tx_control control; - unsigned int guardian_data; struct urb *guardian_urb; }; diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 7598b6e1578..e13ed5ced26 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2357,11 +2357,11 @@ static u64 rt61pci_get_tsf(struct ieee80211_hw *hw) return tsf; } -static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *control) +static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) { struct rt2x00_dev *rt2x00dev = hw->priv; - struct rt2x00_intf *intf = vif_to_intf(control->vif); + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif); struct queue_entry_priv_pci *entry_priv; struct skb_frame_desc *skbdesc; struct txentry_desc txdesc; @@ -2377,7 +2377,7 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, * for our information. */ intf->beacon->skb = skb; - rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc, control); + rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc); entry_priv = intf->beacon->priv_data; memset(entry_priv->desc, 0, intf->beacon->queue->desc_size); diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index e55bcbdfc1e..26c2e0a1a30 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1948,11 +1948,11 @@ static u64 rt73usb_get_tsf(struct ieee80211_hw *hw) #define rt73usb_get_tsf NULL #endif -static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *control) +static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) { struct rt2x00_dev *rt2x00dev = hw->priv; - struct rt2x00_intf *intf = vif_to_intf(control->vif); + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif); struct skb_frame_desc *skbdesc; struct txentry_desc txdesc; unsigned int beacon_base; @@ -1967,7 +1967,7 @@ static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, * for our information. */ intf->beacon->skb = skb; - rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc, control); + rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc); /* * Add the descriptor in front of the skb. diff --git a/drivers/net/wireless/rtl8180_dev.c b/drivers/net/wireless/rtl8180_dev.c index 6263209b889..4427bc9f78a 100644 --- a/drivers/net/wireless/rtl8180_dev.c +++ b/drivers/net/wireless/rtl8180_dev.c @@ -170,34 +170,29 @@ static void rtl8180_handle_tx(struct ieee80211_hw *dev, unsigned int prio) while (skb_queue_len(&ring->queue)) { struct rtl8180_tx_desc *entry = &ring->desc[ring->idx]; struct sk_buff *skb; - struct ieee80211_tx_status status; - struct ieee80211_tx_control *control; + struct ieee80211_tx_info *info; u32 flags = le32_to_cpu(entry->flags); if (flags & RTL8180_TX_DESC_FLAG_OWN) return; - memset(&status, 0, sizeof(status)); - ring->idx = (ring->idx + 1) % ring->entries; skb = __skb_dequeue(&ring->queue); pci_unmap_single(priv->pdev, le32_to_cpu(entry->tx_buf), skb->len, PCI_DMA_TODEVICE); - control = *((struct ieee80211_tx_control **)skb->cb); - if (control) - memcpy(&status.control, control, sizeof(*control)); - kfree(control); + info = IEEE80211_SKB_CB(skb); + memset(&info->status, 0, sizeof(info->status)); - if (!(status.control.flags & IEEE80211_TXCTL_NO_ACK)) { + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { if (flags & RTL8180_TX_DESC_FLAG_TX_OK) - status.flags = IEEE80211_TX_STATUS_ACK; + info->flags |= IEEE80211_TX_STAT_ACK; else - status.excessive_retries = 1; + info->status.excessive_retries = 1; } - status.retry_count = flags & 0xFF; + info->status.retry_count = flags & 0xFF; - ieee80211_tx_status_irqsafe(dev, skb, &status); + ieee80211_tx_status_irqsafe(dev, skb); if (ring->entries - skb_queue_len(&ring->queue) == 2) ieee80211_wake_queue(dev, prio); } @@ -238,9 +233,9 @@ static irqreturn_t rtl8180_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb, - struct ieee80211_tx_control *control) +static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct rtl8180_priv *priv = dev->priv; struct rtl8180_tx_ring *ring; struct rtl8180_tx_desc *entry; @@ -251,7 +246,7 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb, u16 plcp_len = 0; __le16 rts_duration = 0; - prio = control->queue; + prio = info->queue; ring = &priv->tx_ring[prio]; mapping = pci_map_single(priv->pdev, skb->data, @@ -259,35 +254,32 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb, tx_flags = RTL8180_TX_DESC_FLAG_OWN | RTL8180_TX_DESC_FLAG_FS | RTL8180_TX_DESC_FLAG_LS | - (ieee80211_get_tx_rate(dev, control)->hw_value << 24) | + (ieee80211_get_tx_rate(dev, info)->hw_value << 24) | skb->len; if (priv->r8185) tx_flags |= RTL8180_TX_DESC_FLAG_DMA | RTL8180_TX_DESC_FLAG_NO_ENC; - if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) { + if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { tx_flags |= RTL8180_TX_DESC_FLAG_RTS; - tx_flags |= ieee80211_get_rts_cts_rate(dev, control)->hw_value << 19; - } else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { + tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; + } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { tx_flags |= RTL8180_TX_DESC_FLAG_CTS; - tx_flags |= ieee80211_get_rts_cts_rate(dev, control)->hw_value << 19; + tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; } - *((struct ieee80211_tx_control **) skb->cb) = - kmemdup(control, sizeof(*control), GFP_ATOMIC); - - if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) + if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) rts_duration = ieee80211_rts_duration(dev, priv->vif, skb->len, - control); + info); if (!priv->r8185) { unsigned int remainder; plcp_len = DIV_ROUND_UP(16 * (skb->len + 4), - (ieee80211_get_tx_rate(dev, control)->bitrate * 2) / 10); + (ieee80211_get_tx_rate(dev, info)->bitrate * 2) / 10); remainder = (16 * (skb->len + 4)) % - ((ieee80211_get_tx_rate(dev, control)->bitrate * 2) / 10); + ((ieee80211_get_tx_rate(dev, info)->bitrate * 2) / 10); if (remainder > 0 && remainder <= 6) plcp_len |= 1 << 15; } @@ -300,13 +292,13 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb, entry->plcp_len = cpu_to_le16(plcp_len); entry->tx_buf = cpu_to_le32(mapping); entry->frame_len = cpu_to_le32(skb->len); - entry->flags2 = control->alt_retry_rate_idx >= 0 ? - ieee80211_get_alt_retry_rate(dev, control)->bitrate << 4 : 0; - entry->retry_limit = control->retry_limit; + entry->flags2 = info->control.alt_retry_rate_idx >= 0 ? + ieee80211_get_alt_retry_rate(dev, info)->bitrate << 4 : 0; + entry->retry_limit = info->control.retry_limit; entry->flags = cpu_to_le32(tx_flags); __skb_queue_tail(&ring->queue, skb); if (ring->entries - skb_queue_len(&ring->queue) < 2) - ieee80211_stop_queue(dev, control->queue); + ieee80211_stop_queue(dev, info->queue); spin_unlock_irqrestore(&priv->lock, flags); rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING, (1 << (prio + 4))); @@ -522,7 +514,6 @@ static void rtl8180_free_tx_ring(struct ieee80211_hw *dev, unsigned int prio) pci_unmap_single(priv->pdev, le32_to_cpu(entry->tx_buf), skb->len, PCI_DMA_TODEVICE); - kfree(*((struct ieee80211_tx_control **) skb->cb)); kfree_skb(skb); ring->idx = (ring->idx + 1) % ring->entries; } diff --git a/drivers/net/wireless/rtl8187.h b/drivers/net/wireless/rtl8187.h index 076d88b6db0..a0cfb666de0 100644 --- a/drivers/net/wireless/rtl8187.h +++ b/drivers/net/wireless/rtl8187.h @@ -44,12 +44,6 @@ struct rtl8187_rx_hdr { __le64 mac_time; } __attribute__((packed)); -struct rtl8187_tx_info { - struct ieee80211_tx_control *control; - struct urb *urb; - struct ieee80211_hw *dev; -}; - struct rtl8187_tx_hdr { __le32 flags; #define RTL8187_TX_FLAG_NO_ENCRYPT (1 << 15) diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index 86a09b49681..b581ef8a637 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -145,27 +145,22 @@ void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data) static void rtl8187_tx_cb(struct urb *urb) { - struct ieee80211_tx_status status; struct sk_buff *skb = (struct sk_buff *)urb->context; - struct rtl8187_tx_info *info = (struct rtl8187_tx_info *)skb->cb; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_hw *hw = info->driver_data[0]; - memset(&status, 0, sizeof(status)); - - usb_free_urb(info->urb); - if (info->control) - memcpy(&status.control, info->control, sizeof(status.control)); - kfree(info->control); + usb_free_urb(info->driver_data[1]); skb_pull(skb, sizeof(struct rtl8187_tx_hdr)); - status.flags |= IEEE80211_TX_STATUS_ACK; - ieee80211_tx_status_irqsafe(info->dev, skb, &status); + memset(&info->status, 0, sizeof(info->status)); + info->flags |= IEEE80211_TX_STAT_ACK; + ieee80211_tx_status_irqsafe(hw, skb); } -static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb, - struct ieee80211_tx_control *control) +static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) { struct rtl8187_priv *priv = dev->priv; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct rtl8187_tx_hdr *hdr; - struct rtl8187_tx_info *info; struct urb *urb; __le16 rts_dur = 0; u32 flags; @@ -179,29 +174,27 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb, flags = skb->len; flags |= RTL8187_TX_FLAG_NO_ENCRYPT; - flags |= ieee80211_get_tx_rate(dev, control)->hw_value << 24; + flags |= ieee80211_get_tx_rate(dev, info)->hw_value << 24; if (ieee80211_get_morefrag((struct ieee80211_hdr *)skb->data)) flags |= RTL8187_TX_FLAG_MORE_FRAG; - if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) { + if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { flags |= RTL8187_TX_FLAG_RTS; - flags |= ieee80211_get_rts_cts_rate(dev, control)->hw_value << 19; + flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; rts_dur = ieee80211_rts_duration(dev, priv->vif, - skb->len, control); - } else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { + skb->len, info); + } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { flags |= RTL8187_TX_FLAG_CTS; - flags |= ieee80211_get_rts_cts_rate(dev, control)->hw_value << 19; + flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; } hdr = (struct rtl8187_tx_hdr *)skb_push(skb, sizeof(*hdr)); hdr->flags = cpu_to_le32(flags); hdr->len = 0; hdr->rts_duration = rts_dur; - hdr->retry = cpu_to_le32(control->retry_limit << 8); + hdr->retry = cpu_to_le32(info->control.retry_limit << 8); - info = (struct rtl8187_tx_info *)skb->cb; - info->control = kmemdup(control, sizeof(*control), GFP_ATOMIC); - info->urb = urb; - info->dev = dev; + info->driver_data[0] = dev; + info->driver_data[1] = urb; usb_fill_bulk_urb(urb, priv->udev, usb_sndbulkpipe(priv->udev, 2), hdr, skb->len, rtl8187_tx_cb, skb); usb_submit_urb(urb, GFP_ATOMIC); diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 99c508c09e5..edb1aefb4ad 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -224,36 +224,6 @@ out: return r; } -/** - * clear_tx_skb_control_block - clears the control block of tx skbuffs - * @skb: a &struct sk_buff pointer - * - * This clears the control block of skbuff buffers, which were transmitted to - * the device. Notify that the function is not thread-safe, so prevent - * multiple calls. - */ -static void clear_tx_skb_control_block(struct sk_buff *skb) -{ - struct zd_tx_skb_control_block *cb = - (struct zd_tx_skb_control_block *)skb->cb; - - kfree(cb->control); - cb->control = NULL; -} - -/** - * kfree_tx_skb - frees a tx skbuff - * @skb: a &struct sk_buff pointer - * - * Frees the tx skbuff. Frees also the allocated control structure in the - * control block if necessary. - */ -static void kfree_tx_skb(struct sk_buff *skb) -{ - clear_tx_skb_control_block(skb); - dev_kfree_skb_any(skb); -} - static void zd_op_stop(struct ieee80211_hw *hw) { struct zd_mac *mac = zd_hw_mac(hw); @@ -276,40 +246,15 @@ static void zd_op_stop(struct ieee80211_hw *hw) while ((skb = skb_dequeue(ack_wait_queue))) - kfree_tx_skb(skb); -} - -/** - * init_tx_skb_control_block - initializes skb control block - * @skb: a &sk_buff pointer - * @dev: pointer to the mac80221 device - * @control: mac80211 tx control applying for the frame in @skb - * - * Initializes the control block of the skbuff to be transmitted. - */ -static int init_tx_skb_control_block(struct sk_buff *skb, - struct ieee80211_hw *hw, - struct ieee80211_tx_control *control) -{ - struct zd_tx_skb_control_block *cb = - (struct zd_tx_skb_control_block *)skb->cb; - - ZD_ASSERT(sizeof(*cb) <= sizeof(skb->cb)); - memset(cb, 0, sizeof(*cb)); - cb->hw= hw; - cb->control = kmalloc(sizeof(*control), GFP_ATOMIC); - if (cb->control == NULL) - return -ENOMEM; - memcpy(cb->control, control, sizeof(*control)); - - return 0; + dev_kfree_skb_any(skb); } /** * tx_status - reports tx status of a packet if required * @hw - a &struct ieee80211_hw pointer * @skb - a sk-buffer - * @status - the tx status of the packet without control information + * @flags: extra flags to set in the TX status info + * @ackssi: ACK signal strength * @success - True for successfull transmission of the frame * * This information calls ieee80211_tx_status_irqsafe() if required by the @@ -319,18 +264,17 @@ static int init_tx_skb_control_block(struct sk_buff *skb, * If no status information has been requested, the skb is freed. */ static void tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_status *status, - bool success) + u32 flags, int ackssi, bool success) { - struct zd_tx_skb_control_block *cb = (struct zd_tx_skb_control_block *) - skb->cb; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + memset(&info->status, 0, sizeof(info->status)); - ZD_ASSERT(cb->control != NULL); - memcpy(&status->control, cb->control, sizeof(status->control)); if (!success) - status->excessive_retries = 1; - clear_tx_skb_control_block(skb); - ieee80211_tx_status_irqsafe(hw, skb, status); + info->status.excessive_retries = 1; + info->flags |= flags; + info->status.ack_signal = ackssi; + ieee80211_tx_status_irqsafe(hw, skb); } /** @@ -345,15 +289,12 @@ void zd_mac_tx_failed(struct ieee80211_hw *hw) { struct sk_buff_head *q = &zd_hw_mac(hw)->ack_wait_queue; struct sk_buff *skb; - struct ieee80211_tx_status status; skb = skb_dequeue(q); if (skb == NULL) return; - memset(&status, 0, sizeof(status)); - - tx_status(hw, skb, &status, 0); + tx_status(hw, skb, 0, 0, 0); } /** @@ -368,28 +309,20 @@ void zd_mac_tx_failed(struct ieee80211_hw *hw) */ void zd_mac_tx_to_dev(struct sk_buff *skb, int error) { - struct zd_tx_skb_control_block *cb = - (struct zd_tx_skb_control_block *)skb->cb; - struct ieee80211_hw *hw = cb->hw; - - if (likely(cb->control)) { - skb_pull(skb, sizeof(struct zd_ctrlset)); - if (unlikely(error || - (cb->control->flags & IEEE80211_TXCTL_NO_ACK))) - { - struct ieee80211_tx_status status; - memset(&status, 0, sizeof(status)); - tx_status(hw, skb, &status, !error); - } else { - struct sk_buff_head *q = - &zd_hw_mac(hw)->ack_wait_queue; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_hw *hw = info->driver_data[0]; - skb_queue_tail(q, skb); - while (skb_queue_len(q) > ZD_MAC_MAX_ACK_WAITERS) - zd_mac_tx_failed(hw); - } + skb_pull(skb, sizeof(struct zd_ctrlset)); + if (unlikely(error || + (info->flags & IEEE80211_TX_CTL_NO_ACK))) { + tx_status(hw, skb, 0, 0, !error); } else { - kfree_tx_skb(skb); + struct sk_buff_head *q = + &zd_hw_mac(hw)->ack_wait_queue; + + skb_queue_tail(q, skb); + while (skb_queue_len(q) > ZD_MAC_MAX_ACK_WAITERS) + zd_mac_tx_failed(hw); } } @@ -454,7 +387,7 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, cs->control = 0; /* First fragment */ - if (flags & IEEE80211_TXCTL_FIRST_FRAGMENT) + if (flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) cs->control |= ZD_CS_NEED_RANDOM_BACKOFF; /* Multicast */ @@ -466,10 +399,10 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, (IEEE80211_FTYPE_CTL|IEEE80211_STYPE_PSPOLL)) cs->control |= ZD_CS_PS_POLL_FRAME; - if (flags & IEEE80211_TXCTL_USE_RTS_CTS) + if (flags & IEEE80211_TX_CTL_USE_RTS_CTS) cs->control |= ZD_CS_RTS; - if (flags & IEEE80211_TXCTL_USE_CTS_PROTECT) + if (flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) cs->control |= ZD_CS_SELF_CTS; /* FIXME: Management frame? */ @@ -516,8 +449,7 @@ void zd_mac_config_beacon(struct ieee80211_hw *hw, struct sk_buff *beacon) } static int fill_ctrlset(struct zd_mac *mac, - struct sk_buff *skb, - struct ieee80211_tx_control *control) + struct sk_buff *skb) { int r; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; @@ -526,18 +458,19 @@ static int fill_ctrlset(struct zd_mac *mac, struct ieee80211_rate *txrate; struct zd_ctrlset *cs = (struct zd_ctrlset *) skb_push(skb, sizeof(struct zd_ctrlset)); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); ZD_ASSERT(frag_len <= 0xffff); - txrate = ieee80211_get_tx_rate(mac->hw, control); + txrate = ieee80211_get_tx_rate(mac->hw, info); cs->modulation = txrate->hw_value; - if (control->flags & IEEE80211_TXCTL_SHORT_PREAMBLE) + if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE) cs->modulation = txrate->hw_value_short; cs->tx_length = cpu_to_le16(frag_len); - cs_set_control(mac, cs, hdr, control->flags); + cs_set_control(mac, cs, hdr, info->flags); packet_length = frag_len + sizeof(struct zd_ctrlset) + 10; ZD_ASSERT(packet_length <= 0xffff); @@ -582,24 +515,21 @@ static int fill_ctrlset(struct zd_mac *mac, * control block of the skbuff will be initialized. If necessary the incoming * mac80211 queues will be stopped. */ -static int zd_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *control) +static int zd_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct zd_mac *mac = zd_hw_mac(hw); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int r; - r = fill_ctrlset(mac, skb, control); + r = fill_ctrlset(mac, skb); if (r) return r; - r = init_tx_skb_control_block(skb, hw, control); - if (r) - return r; + info->driver_data[0] = hw; + r = zd_usb_tx(&mac->chip.usb, skb); - if (r) { - clear_tx_skb_control_block(skb); + if (r) return r; - } return 0; } @@ -637,13 +567,8 @@ static int filter_ack(struct ieee80211_hw *hw, struct ieee80211_hdr *rx_hdr, tx_hdr = (struct ieee80211_hdr *)skb->data; if (likely(!compare_ether_addr(tx_hdr->addr2, rx_hdr->addr1))) { - struct ieee80211_tx_status status; - - memset(&status, 0, sizeof(status)); - status.flags = IEEE80211_TX_STATUS_ACK; - status.ack_signal = stats->signal; __skb_unlink(skb, q); - tx_status(hw, skb, &status, 1); + tx_status(hw, skb, IEEE80211_TX_STAT_ACK, stats->signal, 1); goto out; } } @@ -947,8 +872,7 @@ static void zd_op_bss_info_changed(struct ieee80211_hw *hw, } static int zd_op_beacon_update(struct ieee80211_hw *hw, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl) + struct sk_buff *skb) { struct zd_mac *mac = zd_hw_mac(hw); zd_mac_config_beacon(hw, skb); diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h index 71170244d2c..18c1d56d3dd 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.h +++ b/drivers/net/wireless/zd1211rw/zd_mac.h @@ -149,22 +149,6 @@ struct housekeeping { struct delayed_work link_led_work; }; -/** - * struct zd_tx_skb_control_block - control block for tx skbuffs - * @control: &struct ieee80211_tx_control pointer - * @context: context pointer - * - * This structure is used to fill the cb field in an &sk_buff to transmit. - * The control field is NULL, if there is no requirement from the mac80211 - * stack to report about the packet ACK. This is the case if the flag - * IEEE80211_TXCTL_NO_ACK is not set in &struct ieee80211_tx_control. - */ -struct zd_tx_skb_control_block { - struct ieee80211_tx_control *control; - struct ieee80211_hw *hw; - void *context; -}; - #define ZD_MAC_STATS_BUFFER_SIZE 16 #define ZD_MAC_MAX_ACK_WAITERS 10 diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 12e24f04ddd..c8a0b34aecc 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -869,7 +869,7 @@ static void tx_urb_complete(struct urb *urb) { int r; struct sk_buff *skb; - struct zd_tx_skb_control_block *cb; + struct ieee80211_tx_info *info; struct zd_usb *usb; switch (urb->status) { @@ -893,8 +893,8 @@ free_urb: * grab 'usb' pointer before handing off the skb (since * it might be freed by zd_mac_tx_to_dev or mac80211) */ - cb = (struct zd_tx_skb_control_block *)skb->cb; - usb = &zd_hw_mac(cb->hw)->chip.usb; + info = IEEE80211_SKB_CB(skb); + usb = &zd_hw_mac(info->driver_data[0])->chip.usb; zd_mac_tx_to_dev(skb, urb->status); free_tx_urb(usb, urb); tx_dec_submitted_urbs(usb); diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 0df91bea6c1..54960b83db7 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -201,101 +201,127 @@ struct ieee80211_bss_conf { }; /** - * enum mac80211_tx_control_flags - flags to describe Tx configuration for - * the Tx frame - * - * These flags are used with the @flags member of &ieee80211_tx_control - * - * @IEEE80211_TXCTL_REQ_TX_STATUS: request TX status callback for this frame. - * @IEEE80211_TXCTL_DO_NOT_ENCRYPT: send this frame without encryption; - * e.g., for EAPOL frame - * @IEEE80211_TXCTL_USE_RTS_CTS: use RTS-CTS before sending frame - * @IEEE80211_TXCTL_USE_CTS_PROTECT: use CTS protection for the frame (e.g., - * for combined 802.11g / 802.11b networks) - * @IEEE80211_TXCTL_NO_ACK: tell the low level not to wait for an ack - * @IEEE80211_TXCTL_RATE_CTRL_PROBE - * @EEE80211_TXCTL_CLEAR_PS_FILT: clear powersave filter - * for destination station - * @IEEE80211_TXCTL_REQUEUE: - * @IEEE80211_TXCTL_FIRST_FRAGMENT: this is a first fragment of the frame - * @IEEE80211_TXCTL_LONG_RETRY_LIMIT: this frame should be send using the - * through set_retry_limit configured long - * retry value - * @IEEE80211_TXCTL_EAPOL_FRAME: internal to mac80211 - * @IEEE80211_TXCTL_SEND_AFTER_DTIM: send this frame after DTIM beacon - * @IEEE80211_TXCTL_AMPDU: this frame should be sent as part of an A-MPDU - * @IEEE80211_TXCTL_OFDM_HT: this frame can be sent in HT OFDM rates. number - * of streams when this flag is on can be extracted - * from antenna_sel_tx, so if 1 antenna is marked - * use SISO, 2 antennas marked use MIMO, n antennas - * marked use MIMO_n. - * @IEEE80211_TXCTL_GREEN_FIELD: use green field protection for this frame - * @IEEE80211_TXCTL_40_MHZ_WIDTH: send this frame using 40 Mhz channel width - * @IEEE80211_TXCTL_DUP_DATA: duplicate data frame on both 20 Mhz channels - * @IEEE80211_TXCTL_SHORT_GI: send this frame using short guard interval + * enum mac80211_tx_flags - flags to transmission information/status + * + * These flags are used with the @flags member of &ieee80211_tx_info + * + * @IEEE80211_TX_CTL_REQ_TX_STATUS: request TX status callback for this frame. + * @IEEE80211_TX_CTL_DO_NOT_ENCRYPT: send this frame without encryption; + * e.g., for EAPOL frame + * @IEEE80211_TX_CTL_USE_RTS_CTS: use RTS-CTS before sending frame + * @IEEE80211_TX_CTL_USE_CTS_PROTECT: use CTS protection for the frame (e.g., + * for combined 802.11g / 802.11b networks) + * @IEEE80211_TX_CTL_NO_ACK: tell the low level not to wait for an ack + * @IEEE80211_TX_CTL_RATE_CTRL_PROBE + * @IEEE80211_TX_CTL_CLEAR_PS_FILT: clear powersave filter for destination + * station + * @IEEE80211_TX_CTL_REQUEUE: + * @IEEE80211_TX_CTL_FIRST_FRAGMENT: this is a first fragment of the frame + * @IEEE80211_TX_CTL_LONG_RETRY_LIMIT: this frame should be send using the + * through set_retry_limit configured long retry value + * @IEEE80211_TX_CTL_EAPOL_FRAME: internal to mac80211 + * @IEEE80211_TX_CTL_SEND_AFTER_DTIM: send this frame after DTIM beacon + * @IEEE80211_TX_CTL_AMPDU: this frame should be sent as part of an A-MPDU + * @IEEE80211_TX_CTL_OFDM_HT: this frame can be sent in HT OFDM rates. number + * of streams when this flag is on can be extracted from antenna_sel_tx, + * so if 1 antenna is marked use SISO, 2 antennas marked use MIMO, n + * antennas marked use MIMO_n. + * @IEEE80211_TX_CTL_GREEN_FIELD: use green field protection for this frame + * @IEEE80211_TX_CTL_40_MHZ_WIDTH: send this frame using 40 Mhz channel width + * @IEEE80211_TX_CTL_DUP_DATA: duplicate data frame on both 20 Mhz channels + * @IEEE80211_TX_CTL_SHORT_GI: send this frame using short guard interval + * @IEEE80211_TX_STAT_TX_FILTERED: The frame was not transmitted + * because the destination STA was in powersave mode. + * @IEEE80211_TX_STAT_ACK: Frame was acknowledged + * @IEEE80211_TX_STAT_AMPDU: The frame was aggregated, so status + * is for the whole aggregation. */ enum mac80211_tx_control_flags { - IEEE80211_TXCTL_REQ_TX_STATUS = (1<<0), - IEEE80211_TXCTL_DO_NOT_ENCRYPT = (1<<1), - IEEE80211_TXCTL_USE_RTS_CTS = (1<<2), - IEEE80211_TXCTL_USE_CTS_PROTECT = (1<<3), - IEEE80211_TXCTL_NO_ACK = (1<<4), - IEEE80211_TXCTL_RATE_CTRL_PROBE = (1<<5), - IEEE80211_TXCTL_CLEAR_PS_FILT = (1<<6), - IEEE80211_TXCTL_REQUEUE = (1<<7), - IEEE80211_TXCTL_FIRST_FRAGMENT = (1<<8), - IEEE80211_TXCTL_SHORT_PREAMBLE = (1<<9), - IEEE80211_TXCTL_LONG_RETRY_LIMIT = (1<<10), - IEEE80211_TXCTL_EAPOL_FRAME = (1<<11), - IEEE80211_TXCTL_SEND_AFTER_DTIM = (1<<12), - IEEE80211_TXCTL_AMPDU = (1<<13), - IEEE80211_TXCTL_OFDM_HT = (1<<14), - IEEE80211_TXCTL_GREEN_FIELD = (1<<15), - IEEE80211_TXCTL_40_MHZ_WIDTH = (1<<16), - IEEE80211_TXCTL_DUP_DATA = (1<<17), - IEEE80211_TXCTL_SHORT_GI = (1<<18), + IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0), + IEEE80211_TX_CTL_DO_NOT_ENCRYPT = BIT(1), + IEEE80211_TX_CTL_USE_RTS_CTS = BIT(2), + IEEE80211_TX_CTL_USE_CTS_PROTECT = BIT(3), + IEEE80211_TX_CTL_NO_ACK = BIT(4), + IEEE80211_TX_CTL_RATE_CTRL_PROBE = BIT(5), + IEEE80211_TX_CTL_CLEAR_PS_FILT = BIT(6), + IEEE80211_TX_CTL_REQUEUE = BIT(7), + IEEE80211_TX_CTL_FIRST_FRAGMENT = BIT(8), + IEEE80211_TX_CTL_SHORT_PREAMBLE = BIT(9), + IEEE80211_TX_CTL_LONG_RETRY_LIMIT = BIT(10), + IEEE80211_TX_CTL_EAPOL_FRAME = BIT(11), + IEEE80211_TX_CTL_SEND_AFTER_DTIM = BIT(12), + IEEE80211_TX_CTL_AMPDU = BIT(13), + IEEE80211_TX_CTL_OFDM_HT = BIT(14), + IEEE80211_TX_CTL_GREEN_FIELD = BIT(15), + IEEE80211_TX_CTL_40_MHZ_WIDTH = BIT(16), + IEEE80211_TX_CTL_DUP_DATA = BIT(17), + IEEE80211_TX_CTL_SHORT_GI = BIT(18), + IEEE80211_TX_CTL_INJECTED = BIT(19), + IEEE80211_TX_STAT_TX_FILTERED = BIT(20), + IEEE80211_TX_STAT_ACK = BIT(21), + IEEE80211_TX_STAT_AMPDU = BIT(22), }; -/* Transmit control fields. This data structure is passed to low-level driver - * with each TX frame. The low-level driver is responsible for configuring - * the hardware to use given values (depending on what is supported). - * - * NOTE: Be careful with using the pointers outside of the ieee80211_ops->tx() - * context (i.e. when defering the work to a workqueue). - * The vif pointer is valid until the it has been removed with the - * ieee80211_ops->remove_interface() callback funtion. - * The hw_key pointer is valid until it has been removed with the - * ieee80211_ops->set_key() callback function. - */ -struct ieee80211_tx_control { - u32 flags; /* tx control flags defined above */ - - s8 tx_rate_idx, /* Transmit rate (indexes registered rates) */ - rts_cts_rate_idx, /* Transmit rate for RTS/CTS frame */ - alt_retry_rate_idx; /* retry rate for the last retries */ - - s8 retry_limit; /* 1 = only first attempt, 2 = one retry, .. - * This could be used when set_retry_limit - * is not implemented by the driver */ - struct ieee80211_vif *vif; - - /* Key used for hardware encryption - * NULL if IEEE80211_TXCTL_DO_NOT_ENCRYPT is set */ - struct ieee80211_key_conf *hw_key; +#define IEEE80211_TX_INFO_DRIVER_DATA_SIZE \ + (sizeof(((struct sk_buff *)0)->cb) - 8) +#define IEEE80211_TX_INFO_DRIVER_DATA_PTRS \ + (IEEE80211_TX_INFO_DRIVER_DATA_SIZE / sizeof(void *)) - enum ieee80211_band band; +/** + * struct ieee80211_tx_info - skb transmit information + * + * This structure is placed in skb->cb for three uses: + * (1) mac80211 TX control - mac80211 tells the driver what to do + * (2) driver internal use (if applicable) + * (3) TX status information - driver tells mac80211 what happened + * + * @flags: transmit info flags, defined above + * @retry_count: number of retries + * @excessive_retries: set to 1 if the frame was retried many times + * but not acknowledged + * @ampdu_ack_len: number of aggregated frames. + * relevant only if IEEE80211_TX_STATUS_AMPDU was set. + * @ampdu_ack_map: block ack bit map for the aggregation. + * relevant only if IEEE80211_TX_STATUS_AMPDU was set. + * @ack_signal: signal strength of the ACK frame + */ +struct ieee80211_tx_info { + /* common information */ + u32 flags; + u8 band; + s8 tx_rate_idx; + u8 antenna_sel_tx; - u8 antenna_sel_tx; /* 0 = default/diversity, otherwise bit - * position represents antenna number used */ - u8 icv_len; /* length of the ICV/MIC field in octets */ - u8 iv_len; /* length of the IV field in octets */ - u16 queue; /* hardware queue to use for this frame; - * 0 = highest, hw->queues-1 = lowest */ - u16 aid; /* Station AID */ - int type; /* internal */ + u8 queue; /* use skb_queue_mapping soon */ + + union { + struct { + struct ieee80211_vif *vif; + struct ieee80211_key_conf *hw_key; + unsigned long jiffies; + int ifindex; + u16 aid; + s8 rts_cts_rate_idx, alt_retry_rate_idx; + u8 retry_limit; + u8 icv_len; + u8 iv_len; + } control; + struct { + u64 ampdu_ack_map; + int ack_signal; + u8 retry_count; + bool excessive_retries; + u8 ampdu_ack_len; + } status; + void *driver_data[IEEE80211_TX_INFO_DRIVER_DATA_PTRS]; + }; }; +static inline struct ieee80211_tx_info *IEEE80211_SKB_CB(struct sk_buff *skb) +{ + return (struct ieee80211_tx_info *)skb->cb; +} /** @@ -362,52 +388,6 @@ struct ieee80211_rx_status { int flag; }; -/** - * enum ieee80211_tx_status_flags - transmit status flags - * - * Status flags to indicate various transmit conditions. - * - * @IEEE80211_TX_STATUS_TX_FILTERED: The frame was not transmitted - * because the destination STA was in powersave mode. - * @IEEE80211_TX_STATUS_ACK: Frame was acknowledged - * @IEEE80211_TX_STATUS_AMPDU: The frame was aggregated, so status - * is for the whole aggregation. - */ -enum ieee80211_tx_status_flags { - IEEE80211_TX_STATUS_TX_FILTERED = 1<<0, - IEEE80211_TX_STATUS_ACK = 1<<1, - IEEE80211_TX_STATUS_AMPDU = 1<<2, -}; - -/** - * struct ieee80211_tx_status - transmit status - * - * As much information as possible should be provided for each transmitted - * frame with ieee80211_tx_status(). - * - * @control: a copy of the &struct ieee80211_tx_control passed to the driver - * in the tx() callback. - * @flags: transmit status flags, defined above - * @retry_count: number of retries - * @excessive_retries: set to 1 if the frame was retried many times - * but not acknowledged - * @ampdu_ack_len: number of aggregated frames. - * relevant only if IEEE80211_TX_STATUS_AMPDU was set. - * @ampdu_ack_map: block ack bit map for the aggregation. - * relevant only if IEEE80211_TX_STATUS_AMPDU was set. - * @ack_signal: signal strength of the ACK frame either in dBm, dB or unspec - * depending on hardware capabilites flags @IEEE80211_HW_SIGNAL_* - */ -struct ieee80211_tx_status { - struct ieee80211_tx_control control; - u8 flags; - u8 retry_count; - bool excessive_retries; - u8 ampdu_ack_len; - u64 ampdu_ack_map; - int ack_signal; -}; - /** * enum ieee80211_conf_flags - configuration flags * @@ -563,7 +543,6 @@ struct ieee80211_if_conf { u8 *ssid; size_t ssid_len; struct sk_buff *beacon; - struct ieee80211_tx_control *beacon_control; }; /** @@ -825,7 +804,7 @@ static inline void SET_IEEE80211_PERM_ADDR(struct ieee80211_hw *hw, u8 *addr) static inline struct ieee80211_rate * ieee80211_get_tx_rate(const struct ieee80211_hw *hw, - const struct ieee80211_tx_control *c) + const struct ieee80211_tx_info *c) { if (WARN_ON(c->tx_rate_idx < 0)) return NULL; @@ -834,20 +813,20 @@ ieee80211_get_tx_rate(const struct ieee80211_hw *hw, static inline struct ieee80211_rate * ieee80211_get_rts_cts_rate(const struct ieee80211_hw *hw, - const struct ieee80211_tx_control *c) + const struct ieee80211_tx_info *c) { - if (c->rts_cts_rate_idx < 0) + if (c->control.rts_cts_rate_idx < 0) return NULL; - return &hw->wiphy->bands[c->band]->bitrates[c->rts_cts_rate_idx]; + return &hw->wiphy->bands[c->band]->bitrates[c->control.rts_cts_rate_idx]; } static inline struct ieee80211_rate * ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw, - const struct ieee80211_tx_control *c) + const struct ieee80211_tx_info *c) { - if (c->alt_retry_rate_idx < 0) + if (c->control.alt_retry_rate_idx < 0) return NULL; - return &hw->wiphy->bands[c->band]->bitrates[c->alt_retry_rate_idx]; + return &hw->wiphy->bands[c->band]->bitrates[c->control.alt_retry_rate_idx]; } /** @@ -1142,8 +1121,7 @@ enum ieee80211_ampdu_mlme_action { * that TX/RX_STOP can pass NULL for this parameter. */ struct ieee80211_ops { - int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *control); + int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb); int (*start)(struct ieee80211_hw *hw); void (*stop)(struct ieee80211_hw *hw); int (*add_interface)(struct ieee80211_hw *hw, @@ -1187,8 +1165,7 @@ struct ieee80211_ops { u64 (*get_tsf)(struct ieee80211_hw *hw); void (*reset_tsf)(struct ieee80211_hw *hw); int (*beacon_update)(struct ieee80211_hw *hw, - struct sk_buff *skb, - struct ieee80211_tx_control *control); + struct sk_buff *skb); int (*tx_last_beacon)(struct ieee80211_hw *hw); int (*ampdu_action)(struct ieee80211_hw *hw, enum ieee80211_ampdu_mlme_action action, @@ -1384,13 +1361,9 @@ void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, * * @hw: the hardware the frame was transmitted by * @skb: the frame that was transmitted, owned by mac80211 after this call - * @status: status information for this frame; the status pointer need not - * be valid after this function returns and is not freed by mac80211, - * it is recommended that it points to a stack area */ void ieee80211_tx_status(struct ieee80211_hw *hw, - struct sk_buff *skb, - struct ieee80211_tx_status *status); + struct sk_buff *skb); /** * ieee80211_tx_status_irqsafe - irq-safe transmit status callback @@ -1403,13 +1376,9 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, * * @hw: the hardware the frame was transmitted by * @skb: the frame that was transmitted, owned by mac80211 after this call - * @status: status information for this frame; the status pointer need not - * be valid after this function returns and is not freed by mac80211, - * it is recommended that it points to a stack area */ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, - struct sk_buff *skb, - struct ieee80211_tx_status *status); + struct sk_buff *skb); /** * ieee80211_beacon_get - beacon generation function @@ -1425,8 +1394,7 @@ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, * is responsible of freeing it. */ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_tx_control *control); + struct ieee80211_vif *vif); /** * ieee80211_rts_get - RTS frame generation function @@ -1434,7 +1402,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. * @frame: pointer to the frame that is going to be protected by the RTS. * @frame_len: the frame length (in octets). - * @frame_txctl: &struct ieee80211_tx_control of the frame. + * @frame_txctl: &struct ieee80211_tx_info of the frame. * @rts: The buffer where to store the RTS frame. * * If the RTS frames are generated by the host system (i.e., not in @@ -1444,7 +1412,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, */ void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const void *frame, size_t frame_len, - const struct ieee80211_tx_control *frame_txctl, + const struct ieee80211_tx_info *frame_txctl, struct ieee80211_rts *rts); /** @@ -1452,7 +1420,7 @@ void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, * @hw: pointer obtained from ieee80211_alloc_hw(). * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. * @frame_len: the length of the frame that is going to be protected by the RTS. - * @frame_txctl: &struct ieee80211_tx_control of the frame. + * @frame_txctl: &struct ieee80211_tx_info of the frame. * * If the RTS is generated in firmware, but the host system must provide * the duration field, the low-level driver uses this function to receive @@ -1460,7 +1428,7 @@ void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, */ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, struct ieee80211_vif *vif, size_t frame_len, - const struct ieee80211_tx_control *frame_txctl); + const struct ieee80211_tx_info *frame_txctl); /** * ieee80211_ctstoself_get - CTS-to-self frame generation function @@ -1468,7 +1436,7 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. * @frame: pointer to the frame that is going to be protected by the CTS-to-self. * @frame_len: the frame length (in octets). - * @frame_txctl: &struct ieee80211_tx_control of the frame. + * @frame_txctl: &struct ieee80211_tx_info of the frame. * @cts: The buffer where to store the CTS-to-self frame. * * If the CTS-to-self frames are generated by the host system (i.e., not in @@ -1479,7 +1447,7 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, void ieee80211_ctstoself_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const void *frame, size_t frame_len, - const struct ieee80211_tx_control *frame_txctl, + const struct ieee80211_tx_info *frame_txctl, struct ieee80211_cts *cts); /** @@ -1487,7 +1455,7 @@ void ieee80211_ctstoself_get(struct ieee80211_hw *hw, * @hw: pointer obtained from ieee80211_alloc_hw(). * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. * @frame_len: the length of the frame that is going to be protected by the CTS-to-self. - * @frame_txctl: &struct ieee80211_tx_control of the frame. + * @frame_txctl: &struct ieee80211_tx_info of the frame. * * If the CTS-to-self is generated in firmware, but the host system must provide * the duration field, the low-level driver uses this function to receive @@ -1496,7 +1464,7 @@ void ieee80211_ctstoself_get(struct ieee80211_hw *hw, __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, struct ieee80211_vif *vif, size_t frame_len, - const struct ieee80211_tx_control *frame_txctl); + const struct ieee80211_tx_info *frame_txctl); /** * ieee80211_generic_frame_duration - Calculate the duration field for a frame @@ -1535,8 +1503,7 @@ __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, * use common code for all beacons. */ struct sk_buff * -ieee80211_get_buffered_bc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_tx_control *control); +ieee80211_get_buffered_bc(struct ieee80211_hw *hw, struct ieee80211_vif *vif); /** * ieee80211_get_hdrlen_from_skb - get header length from data diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index a4cccd1b7d5..79a65b3ee02 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2,6 +2,7 @@ * Copyright 2002-2005, Instant802 Networks, Inc. * Copyright 2005, Devicescape Software, Inc. * Copyright 2006-2007 Jiri Benc + * Copyright 2007-2008 Johannes Berg * * 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 @@ -147,7 +148,6 @@ typedef unsigned __bitwise__ ieee80211_tx_result; #define IEEE80211_TX_UNICAST BIT(1) #define IEEE80211_TX_PS_BUFFERED BIT(2) #define IEEE80211_TX_PROBE_LAST_FRAG BIT(3) -#define IEEE80211_TX_INJECTED BIT(4) struct ieee80211_tx_data { struct sk_buff *skb; @@ -157,7 +157,6 @@ struct ieee80211_tx_data { struct sta_info *sta; struct ieee80211_key *key; - struct ieee80211_tx_control *control; struct ieee80211_channel *channel; s8 rate_idx; /* use this rate (if set) for last fragment; rate can @@ -207,22 +206,7 @@ struct ieee80211_rx_data { u16 tkip_iv16; }; -/* flags used in struct ieee80211_tx_packet_data.flags */ -#define IEEE80211_TXPD_REQ_TX_STATUS BIT(0) -#define IEEE80211_TXPD_DO_NOT_ENCRYPT BIT(1) -#define IEEE80211_TXPD_REQUEUE BIT(2) -#define IEEE80211_TXPD_EAPOL_FRAME BIT(3) -#define IEEE80211_TXPD_AMPDU BIT(4) -/* Stored in sk_buff->cb */ -struct ieee80211_tx_packet_data { - int ifindex; - unsigned long jiffies; - unsigned int flags; - u8 queue; -}; - struct ieee80211_tx_stored_packet { - struct ieee80211_tx_control control; struct sk_buff *skb; struct sk_buff **extra_frag; s8 last_frag_rate_idx; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 9761d9bd5a7..8f1ff7ef166 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -971,8 +971,7 @@ void ieee80211_if_setup(struct net_device *dev) /* everything else */ static int __ieee80211_if_config(struct net_device *dev, - struct sk_buff *beacon, - struct ieee80211_tx_control *control) + struct sk_buff *beacon) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); @@ -990,13 +989,11 @@ static int __ieee80211_if_config(struct net_device *dev, conf.ssid_len = sdata->u.sta.ssid_len; } else if (ieee80211_vif_is_mesh(&sdata->vif)) { conf.beacon = beacon; - conf.beacon_control = control; ieee80211_start_mesh(dev); } else if (sdata->vif.type == IEEE80211_IF_TYPE_AP) { conf.ssid = sdata->u.ap.ssid; conf.ssid_len = sdata->u.ap.ssid_len; conf.beacon = beacon; - conf.beacon_control = control; } return local->ops->config_interface(local_to_hw(local), &sdata->vif, &conf); @@ -1009,23 +1006,21 @@ int ieee80211_if_config(struct net_device *dev) if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT && (local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE)) return ieee80211_if_config_beacon(dev); - return __ieee80211_if_config(dev, NULL, NULL); + return __ieee80211_if_config(dev, NULL); } int ieee80211_if_config_beacon(struct net_device *dev) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_tx_control control; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct sk_buff *skb; if (!(local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE)) return 0; - skb = ieee80211_beacon_get(local_to_hw(local), &sdata->vif, - &control); + skb = ieee80211_beacon_get(local_to_hw(local), &sdata->vif); if (!skb) return -ENOMEM; - return __ieee80211_if_config(dev, skb, &control); + return __ieee80211_if_config(dev, skb); } int ieee80211_hw_config(struct ieee80211_local *local) @@ -1180,38 +1175,20 @@ void ieee80211_reset_erp_info(struct net_device *dev) } void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, - struct sk_buff *skb, - struct ieee80211_tx_status *status) + struct sk_buff *skb) { struct ieee80211_local *local = hw_to_local(hw); - struct ieee80211_tx_status *saved; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int tmp; skb->dev = local->mdev; - saved = kmalloc(sizeof(struct ieee80211_tx_status), GFP_ATOMIC); - if (unlikely(!saved)) { - if (net_ratelimit()) - printk(KERN_WARNING "%s: Not enough memory, " - "dropping tx status", skb->dev->name); - /* should be dev_kfree_skb_irq, but due to this function being - * named _irqsafe instead of just _irq we can't be sure that - * people won't call it from non-irq contexts */ - dev_kfree_skb_any(skb); - return; - } - memcpy(saved, status, sizeof(struct ieee80211_tx_status)); - /* copy pointer to saved status into skb->cb for use by tasklet */ - memcpy(skb->cb, &saved, sizeof(saved)); - skb->pkt_type = IEEE80211_TX_STATUS_MSG; - skb_queue_tail(status->control.flags & IEEE80211_TXCTL_REQ_TX_STATUS ? + skb_queue_tail(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS ? &local->skb_queue : &local->skb_queue_unreliable, skb); tmp = skb_queue_len(&local->skb_queue) + skb_queue_len(&local->skb_queue_unreliable); while (tmp > IEEE80211_IRQSAFE_QUEUE_LIMIT && (skb = skb_dequeue(&local->skb_queue_unreliable))) { - memcpy(&saved, skb->cb, sizeof(saved)); - kfree(saved); dev_kfree_skb_irq(skb); tmp--; I802_DEBUG_INC(local->tx_status_drop); @@ -1225,7 +1202,6 @@ static void ieee80211_tasklet_handler(unsigned long data) struct ieee80211_local *local = (struct ieee80211_local *) data; struct sk_buff *skb; struct ieee80211_rx_status rx_status; - struct ieee80211_tx_status *tx_status; struct ieee80211_ra_tid *ra_tid; while ((skb = skb_dequeue(&local->skb_queue)) || @@ -1240,12 +1216,8 @@ static void ieee80211_tasklet_handler(unsigned long data) __ieee80211_rx(local_to_hw(local), skb, &rx_status); break; case IEEE80211_TX_STATUS_MSG: - /* get pointer to saved status out of skb->cb */ - memcpy(&tx_status, skb->cb, sizeof(tx_status)); skb->pkt_type = 0; - ieee80211_tx_status(local_to_hw(local), - skb, tx_status); - kfree(tx_status); + ieee80211_tx_status(local_to_hw(local), skb); break; case IEEE80211_DELBA_MSG: ra_tid = (struct ieee80211_ra_tid *) &skb->cb; @@ -1274,24 +1246,15 @@ static void ieee80211_tasklet_handler(unsigned long data) * Also, tx_packet_data in cb is restored from tx_control. */ static void ieee80211_remove_tx_extra(struct ieee80211_local *local, struct ieee80211_key *key, - struct sk_buff *skb, - struct ieee80211_tx_control *control) + struct sk_buff *skb) { int hdrlen, iv_len, mic_len; - struct ieee80211_tx_packet_data *pkt_data; - - pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; - pkt_data->ifindex = vif_to_sdata(control->vif)->dev->ifindex; - pkt_data->flags = 0; - if (control->flags & IEEE80211_TXCTL_REQ_TX_STATUS) - pkt_data->flags |= IEEE80211_TXPD_REQ_TX_STATUS; - if (control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT) - pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT; - if (control->flags & IEEE80211_TXCTL_REQUEUE) - pkt_data->flags |= IEEE80211_TXPD_REQUEUE; - if (control->flags & IEEE80211_TXCTL_EAPOL_FRAME) - pkt_data->flags |= IEEE80211_TXPD_EAPOL_FRAME; - pkt_data->queue = control->queue; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + info->flags &= IEEE80211_TX_CTL_REQ_TX_STATUS | + IEEE80211_TX_CTL_DO_NOT_ENCRYPT | + IEEE80211_TX_CTL_REQUEUE | + IEEE80211_TX_CTL_EAPOL_FRAME; hdrlen = ieee80211_get_hdrlen_from_skb(skb); @@ -1338,9 +1301,10 @@ no_key: static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, struct sta_info *sta, - struct sk_buff *skb, - struct ieee80211_tx_status *status) + struct sk_buff *skb) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + sta->tx_filtered_count++; /* @@ -1382,18 +1346,16 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, */ if (test_sta_flags(sta, WLAN_STA_PS) && skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) { - ieee80211_remove_tx_extra(local, sta->key, skb, - &status->control); + ieee80211_remove_tx_extra(local, sta->key, skb); skb_queue_tail(&sta->tx_filtered, skb); return; } if (!test_sta_flags(sta, WLAN_STA_PS) && - !(status->control.flags & IEEE80211_TXCTL_REQUEUE)) { + !(info->flags & IEEE80211_TX_CTL_REQUEUE)) { /* Software retry the packet once */ - status->control.flags |= IEEE80211_TXCTL_REQUEUE; - ieee80211_remove_tx_extra(local, sta->key, skb, - &status->control); + info->flags |= IEEE80211_TX_CTL_REQUEUE; + ieee80211_remove_tx_extra(local, sta->key, skb); dev_queue_xmit(skb); return; } @@ -1407,28 +1369,20 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, dev_kfree_skb(skb); } -void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_status *status) +void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) { struct sk_buff *skb2; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); u16 frag, type; struct ieee80211_tx_status_rtap_hdr *rthdr; struct ieee80211_sub_if_data *sdata; struct net_device *prev_dev = NULL; - if (!status) { - printk(KERN_ERR - "%s: ieee80211_tx_status called with NULL status\n", - wiphy_name(local->hw.wiphy)); - dev_kfree_skb(skb); - return; - } - rcu_read_lock(); - if (status->excessive_retries) { + if (info->status.excessive_retries) { struct sta_info *sta; sta = sta_info_get(local, hdr->addr1); if (sta) { @@ -1437,27 +1391,23 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, * The STA is in power save mode, so assume * that this TX packet failed because of that. */ - status->excessive_retries = 0; - status->flags |= IEEE80211_TX_STATUS_TX_FILTERED; - ieee80211_handle_filtered_frame(local, sta, - skb, status); + ieee80211_handle_filtered_frame(local, sta, skb); rcu_read_unlock(); return; } } } - if (status->flags & IEEE80211_TX_STATUS_TX_FILTERED) { + if (info->flags & IEEE80211_TX_STAT_TX_FILTERED) { struct sta_info *sta; sta = sta_info_get(local, hdr->addr1); if (sta) { - ieee80211_handle_filtered_frame(local, sta, skb, - status); + ieee80211_handle_filtered_frame(local, sta, skb); rcu_read_unlock(); return; } } else - rate_control_tx_status(local->mdev, skb, status); + rate_control_tx_status(local->mdev, skb); rcu_read_unlock(); @@ -1471,14 +1421,14 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, frag = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG; type = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_FTYPE; - if (status->flags & IEEE80211_TX_STATUS_ACK) { + if (info->flags & IEEE80211_TX_STAT_ACK) { if (frag == 0) { local->dot11TransmittedFrameCount++; if (is_multicast_ether_addr(hdr->addr1)) local->dot11MulticastTransmittedFrameCount++; - if (status->retry_count > 0) + if (info->status.retry_count > 0) local->dot11RetryCount++; - if (status->retry_count > 1) + if (info->status.retry_count > 1) local->dot11MultipleRetryCount++; } @@ -1524,17 +1474,17 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) | (1 << IEEE80211_RADIOTAP_DATA_RETRIES)); - if (!(status->flags & IEEE80211_TX_STATUS_ACK) && + if (!(info->flags & IEEE80211_TX_STAT_ACK) && !is_multicast_ether_addr(hdr->addr1)) rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL); - if ((status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS) && - (status->control.flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) + if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) && + (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS); - else if (status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS) + else if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS); - rthdr->data_retries = status->retry_count; + rthdr->data_retries = info->status.retry_count; /* XXX: is this sufficient for BPF? */ skb_set_mac_header(skb, 0); @@ -1895,7 +1845,9 @@ static int __init ieee80211_init(void) struct sk_buff *skb; int ret; - BUILD_BUG_ON(sizeof(struct ieee80211_tx_packet_data) > sizeof(skb->cb)); + BUILD_BUG_ON(sizeof(struct ieee80211_tx_info) > sizeof(skb->cb)); + BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, driver_data) + + IEEE80211_TX_INFO_DRIVER_DATA_SIZE > sizeof(skb->cb)); ret = rc80211_pid_init(); if (ret) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 604149369dc..9a264379d7b 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -578,7 +578,7 @@ void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb, int encrypt) { struct ieee80211_sub_if_data *sdata; - struct ieee80211_tx_packet_data *pkt_data; + struct ieee80211_tx_info *info; sdata = IEEE80211_DEV_TO_SUB_IF(dev); skb->dev = sdata->local->mdev; @@ -586,11 +586,11 @@ void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb, skb_set_network_header(skb, 0); skb_set_transport_header(skb, 0); - pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; - memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data)); - pkt_data->ifindex = sdata->dev->ifindex; + info = IEEE80211_SKB_CB(skb); + memset(info, 0, sizeof(struct ieee80211_tx_info)); + info->control.ifindex = sdata->dev->ifindex; if (!encrypt) - pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT; + info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT; dev_queue_xmit(skb); } @@ -2314,7 +2314,7 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, int res, rates, i, j; struct sk_buff *skb; struct ieee80211_mgmt *mgmt; - struct ieee80211_tx_control control; + struct ieee80211_tx_info *control; struct rate_selection ratesel; u8 *pos; struct ieee80211_sub_if_data *sdata; @@ -2404,21 +2404,22 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, memcpy(pos, &bss->supp_rates[8], rates); } - memset(&control, 0, sizeof(control)); + control = IEEE80211_SKB_CB(skb); + rate_control_get_rate(dev, sband, skb, &ratesel); if (ratesel.rate_idx < 0) { printk(KERN_DEBUG "%s: Failed to determine TX rate " "for IBSS beacon\n", dev->name); break; } - control.vif = &sdata->vif; - control.tx_rate_idx = ratesel.rate_idx; + control->control.vif = &sdata->vif; + control->tx_rate_idx = ratesel.rate_idx; if (sdata->bss_conf.use_short_preamble && sband->bitrates[ratesel.rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE) - control.flags |= IEEE80211_TXCTL_SHORT_PREAMBLE; - control.antenna_sel_tx = local->hw.conf.antenna_sel_tx; - control.flags |= IEEE80211_TXCTL_NO_ACK; - control.retry_limit = 1; + control->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE; + control->antenna_sel_tx = local->hw.conf.antenna_sel_tx; + control->flags |= IEEE80211_TX_CTL_NO_ACK; + control->control.retry_limit = 1; ifsta->probe_resp = skb_copy(skb, GFP_ATOMIC); if (ifsta->probe_resp) { @@ -2433,8 +2434,7 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, } if (local->ops->beacon_update && - local->ops->beacon_update(local_to_hw(local), - skb, &control) == 0) { + local->ops->beacon_update(local_to_hw(local), skb) == 0) { printk(KERN_DEBUG "%s: Configured IBSS beacon " "template\n", dev->name); skb = NULL; diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index a29148dcca9..0ed9c8a2f56 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h @@ -34,8 +34,7 @@ struct rate_control_ops { struct module *module; const char *name; void (*tx_status)(void *priv, struct net_device *dev, - struct sk_buff *skb, - struct ieee80211_tx_status *status); + struct sk_buff *skb); void (*get_rate)(void *priv, struct net_device *dev, struct ieee80211_supported_band *band, struct sk_buff *skb, @@ -77,13 +76,12 @@ struct rate_control_ref *rate_control_get(struct rate_control_ref *ref); void rate_control_put(struct rate_control_ref *ref); static inline void rate_control_tx_status(struct net_device *dev, - struct sk_buff *skb, - struct ieee80211_tx_status *status) + struct sk_buff *skb) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct rate_control_ref *ref = local->rate_ctrl; - ref->ops->tx_status(ref->priv, dev, skb, status); + ref->ops->tx_status(ref->priv, dev, skb); } diff --git a/net/mac80211/rc80211_pid.h b/net/mac80211/rc80211_pid.h index 04afc13ed82..2078803d358 100644 --- a/net/mac80211/rc80211_pid.h +++ b/net/mac80211/rc80211_pid.h @@ -61,7 +61,7 @@ enum rc_pid_event_type { union rc_pid_event_data { /* RC_PID_EVENT_TX_STATUS */ struct { - struct ieee80211_tx_status tx_status; + struct ieee80211_tx_info tx_status; }; /* RC_PID_EVENT_TYPE_RATE_CHANGE */ /* RC_PID_EVENT_TYPE_TX_RATE */ @@ -158,7 +158,7 @@ struct rc_pid_debugfs_entries { }; void rate_control_pid_event_tx_status(struct rc_pid_event_buffer *buf, - struct ieee80211_tx_status *stat); + struct ieee80211_tx_info *stat); void rate_control_pid_event_rate_change(struct rc_pid_event_buffer *buf, int index, int rate); diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c index 14cde36f507..e8945413e4a 100644 --- a/net/mac80211/rc80211_pid_algo.c +++ b/net/mac80211/rc80211_pid_algo.c @@ -237,8 +237,7 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo, } static void rate_control_pid_tx_status(void *priv, struct net_device *dev, - struct sk_buff *skb, - struct ieee80211_tx_status *status) + struct sk_buff *skb) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; @@ -248,6 +247,7 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev, struct rc_pid_sta_info *spinfo; unsigned long period; struct ieee80211_supported_band *sband; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); rcu_read_lock(); @@ -266,28 +266,28 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev, /* Ignore all frames that were sent with a different rate than the rate * we currently advise mac80211 to use. */ - if (status->control.tx_rate_idx != sta->txrate_idx) + if (info->tx_rate_idx != sta->txrate_idx) goto unlock; spinfo = sta->rate_ctrl_priv; spinfo->tx_num_xmit++; #ifdef CONFIG_MAC80211_DEBUGFS - rate_control_pid_event_tx_status(&spinfo->events, status); + rate_control_pid_event_tx_status(&spinfo->events, info); #endif /* We count frames that totally failed to be transmitted as two bad * frames, those that made it out but had some retries as one good and * one bad frame. */ - if (status->excessive_retries) { + if (info->status.excessive_retries) { spinfo->tx_num_failed += 2; spinfo->tx_num_xmit++; - } else if (status->retry_count) { + } else if (info->status.retry_count) { spinfo->tx_num_failed++; spinfo->tx_num_xmit++; } - if (status->excessive_retries) { + if (info->status.excessive_retries) { sta->tx_retry_failed++; sta->tx_num_consecutive_failures++; sta->tx_num_mpdu_fail++; @@ -295,8 +295,8 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev, sta->tx_num_consecutive_failures = 0; sta->tx_num_mpdu_ok++; } - sta->tx_retry_count += status->retry_count; - sta->tx_num_mpdu_fail += status->retry_count; + sta->tx_retry_count += info->status.retry_count; + sta->tx_num_mpdu_fail += info->status.retry_count; /* Update PID controller state. */ period = (HZ * pinfo->sampling_period + 500) / 1000; diff --git a/net/mac80211/rc80211_pid_debugfs.c b/net/mac80211/rc80211_pid_debugfs.c index ff5c380f3c1..8121d3bc683 100644 --- a/net/mac80211/rc80211_pid_debugfs.c +++ b/net/mac80211/rc80211_pid_debugfs.c @@ -39,11 +39,11 @@ static void rate_control_pid_event(struct rc_pid_event_buffer *buf, } void rate_control_pid_event_tx_status(struct rc_pid_event_buffer *buf, - struct ieee80211_tx_status *stat) + struct ieee80211_tx_info *stat) { union rc_pid_event_data evd; - memcpy(&evd.tx_status, stat, sizeof(struct ieee80211_tx_status)); + memcpy(&evd.tx_status, stat, sizeof(struct ieee80211_tx_info)); rate_control_pid_event(buf, RC_PID_EVENT_TYPE_TX_STATUS, &evd); } @@ -167,8 +167,8 @@ static ssize_t rate_control_pid_events_read(struct file *file, char __user *buf, switch (ev->type) { case RC_PID_EVENT_TYPE_TX_STATUS: p += snprintf(pb + p, length - p, "tx_status %u %u", - ev->data.tx_status.excessive_retries, - ev->data.tx_status.retry_count); + ev->data.tx_status.status.excessive_retries, + ev->data.tx_status.status.retry_count); break; case RC_PID_EVENT_TYPE_RATE_CHANGE: p += snprintf(pb + p, length - p, "rate_change %d %d", diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index fa68305fd59..cf0de3b0fe2 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -714,7 +714,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) struct sk_buff *skb; int sent = 0; struct ieee80211_sub_if_data *sdata; - struct ieee80211_tx_packet_data *pkt_data; + struct ieee80211_tx_info *info; DECLARE_MAC_BUF(mac); sdata = sta->sdata; @@ -734,13 +734,13 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) /* Send all buffered frames to the station */ while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { - pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; + info = IEEE80211_SKB_CB(skb); sent++; - pkt_data->flags |= IEEE80211_TXPD_REQUEUE; + info->flags |= IEEE80211_TX_CTL_REQUEUE; dev_queue_xmit(skb); } while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { - pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; + info = IEEE80211_SKB_CB(skb); local->total_ps_buffered--; sent++; #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG @@ -748,7 +748,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) "since STA not sleeping anymore\n", dev->name, print_mac(mac, sta->addr), sta->aid); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - pkt_data->flags |= IEEE80211_TXPD_REQUEUE; + info->flags |= IEEE80211_TX_CTL_REQUEUE; dev_queue_xmit(skb); } diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index baf5e474688..ef3149324d5 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -511,20 +511,20 @@ static inline int sta_info_buffer_expired(struct ieee80211_local *local, struct sta_info *sta, struct sk_buff *skb) { - struct ieee80211_tx_packet_data *pkt_data; + struct ieee80211_tx_info *info; int timeout; if (!skb) return 0; - pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; + info = IEEE80211_SKB_CB(skb); /* Timeout: (2 * listen_interval * beacon_int * 1024 / 1000000) sec */ timeout = (sta->listen_interval * local->hw.conf.beacon_int * 32 / 15625) * HZ; if (timeout < STA_TX_BUFFER_EXPIRE) timeout = STA_TX_BUFFER_EXPIRE; - return time_after(jiffies, pkt_data->jiffies + timeout); + return time_after(jiffies, info->control.jiffies + timeout); } diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index e89cc165554..f592290e42b 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -32,7 +32,7 @@ * @WLAN_STA_WDS: Station is one of our WDS peers. * @WLAN_STA_PSPOLL: Station has just PS-polled us. * @WLAN_STA_CLEAR_PS_FILT: Clear PS filter in hardware (using the - * IEEE80211_TXCTL_CLEAR_PS_FILT control flag) when the next + * IEEE80211_TX_CTL_CLEAR_PS_FILT control flag) when the next * frame to this station is transmitted. */ enum ieee80211_sta_info_flags { diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 666158f02a8..ac9a4af7ad4 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -238,12 +238,12 @@ static ieee80211_tx_result ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG - struct sk_buff *skb = tx->skb; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); u32 sta_flags; - if (unlikely(tx->flags & IEEE80211_TX_INJECTED)) + if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED)) return TX_CONTINUE; if (unlikely(tx->local->sta_sw_scanning) && @@ -348,6 +348,8 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) static ieee80211_tx_result ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); + /* * broadcast/multicast frame * @@ -383,7 +385,7 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) } /* buffered in hardware */ - tx->control->flags |= IEEE80211_TXCTL_SEND_AFTER_DTIM; + info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM; return TX_CONTINUE; } @@ -392,6 +394,7 @@ static ieee80211_tx_result ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) { struct sta_info *sta = tx->sta; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); u32 staflags; DECLARE_MAC_BUF(mac); @@ -404,7 +407,6 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) if (unlikely((staflags & WLAN_STA_PS) && !(staflags & WLAN_STA_PSPOLL))) { - struct ieee80211_tx_packet_data *pkt_data; #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "STA %s aid %d: PS buffer (entries " "before %d)\n", @@ -428,8 +430,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) if (skb_queue_empty(&sta->ps_tx_buf)) sta_info_set_tim_bit(sta); - pkt_data = (struct ieee80211_tx_packet_data *)tx->skb->cb; - pkt_data->jiffies = jiffies; + info->control.jiffies = jiffies; skb_queue_tail(&sta->ps_tx_buf, tx->skb); return TX_QUEUED; } @@ -461,17 +462,18 @@ static ieee80211_tx_result ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) { struct ieee80211_key *key; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); u16 fc = tx->fc; - if (unlikely(tx->control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) + if (unlikely(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT)) tx->key = NULL; else if (tx->sta && (key = rcu_dereference(tx->sta->key))) tx->key = key; else if ((key = rcu_dereference(tx->sdata->default_key))) tx->key = key; else if (tx->sdata->drop_unencrypted && - !(tx->control->flags & IEEE80211_TXCTL_EAPOL_FRAME) && - !(tx->flags & IEEE80211_TX_INJECTED)) { + !(info->flags & IEEE80211_TX_CTL_EAPOL_FRAME) && + !(info->flags & IEEE80211_TX_CTL_INJECTED)) { I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted); return TX_DROP; } else @@ -500,7 +502,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) } if (!tx->key || !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) - tx->control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; + info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT; return TX_CONTINUE; } @@ -510,6 +512,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) { struct rate_selection rsel; struct ieee80211_supported_band *sband; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); sband = tx->local->hw.wiphy->bands[tx->channel->band]; @@ -517,18 +520,17 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) rate_control_get_rate(tx->dev, sband, tx->skb, &rsel); tx->rate_idx = rsel.rate_idx; if (unlikely(rsel.probe_idx >= 0)) { - tx->control->flags |= - IEEE80211_TXCTL_RATE_CTRL_PROBE; + info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG; - tx->control->alt_retry_rate_idx = tx->rate_idx; + info->control.alt_retry_rate_idx = tx->rate_idx; tx->rate_idx = rsel.probe_idx; } else - tx->control->alt_retry_rate_idx = -1; + info->control.alt_retry_rate_idx = -1; if (unlikely(tx->rate_idx < 0)) return TX_DROP; } else - tx->control->alt_retry_rate_idx = -1; + info->control.alt_retry_rate_idx = -1; if (tx->sdata->bss_conf.use_cts_prot && (tx->flags & IEEE80211_TX_FRAGMENTED) && (rsel.nonerp_idx >= 0)) { @@ -538,13 +540,13 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) else tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG; tx->rate_idx = rsel.nonerp_idx; - tx->control->tx_rate_idx = rsel.nonerp_idx; - tx->control->flags &= ~IEEE80211_TXCTL_RATE_CTRL_PROBE; + info->tx_rate_idx = rsel.nonerp_idx; + info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE; } else { tx->last_frag_rate_idx = tx->rate_idx; - tx->control->tx_rate_idx = tx->rate_idx; + info->tx_rate_idx = tx->rate_idx; } - tx->control->tx_rate_idx = tx->rate_idx; + info->tx_rate_idx = tx->rate_idx; return TX_CONTINUE; } @@ -555,28 +557,32 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; u16 fc = le16_to_cpu(hdr->frame_control); u16 dur; - struct ieee80211_tx_control *control = tx->control; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); struct ieee80211_supported_band *sband; sband = tx->local->hw.wiphy->bands[tx->channel->band]; - if (!control->retry_limit) { + if (tx->sta) + info->control.aid = tx->sta->aid; + + if (!info->control.retry_limit) { if (!is_multicast_ether_addr(hdr->addr1)) { - if (tx->skb->len + FCS_LEN > tx->local->rts_threshold + int len = min_t(int, tx->skb->len + FCS_LEN, + tx->local->fragmentation_threshold); + if (len > tx->local->rts_threshold && tx->local->rts_threshold < - IEEE80211_MAX_RTS_THRESHOLD) { - control->flags |= - IEEE80211_TXCTL_USE_RTS_CTS; - control->flags |= - IEEE80211_TXCTL_LONG_RETRY_LIMIT; - control->retry_limit = + IEEE80211_MAX_RTS_THRESHOLD) { + info->flags |= IEEE80211_TX_CTL_USE_RTS_CTS; + info->flags |= + IEEE80211_TX_CTL_LONG_RETRY_LIMIT; + info->control.retry_limit = tx->local->long_retry_limit; } else { - control->retry_limit = + info->control.retry_limit = tx->local->short_retry_limit; } } else { - control->retry_limit = 1; + info->control.retry_limit = 1; } } @@ -585,7 +591,7 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) * frames. * TODO: The last fragment could still use multiple retry * rates. */ - control->alt_retry_rate_idx = -1; + info->control.alt_retry_rate_idx = -1; } /* Use CTS protection for unicast frames sent using extended rates if @@ -595,8 +601,8 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) (sband->bitrates[tx->rate_idx].flags & IEEE80211_RATE_ERP_G) && (tx->flags & IEEE80211_TX_UNICAST) && tx->sdata->bss_conf.use_cts_prot && - !(control->flags & IEEE80211_TXCTL_USE_RTS_CTS)) - control->flags |= IEEE80211_TXCTL_USE_CTS_PROTECT; + !(info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)) + info->flags |= IEEE80211_TX_CTL_USE_CTS_PROTECT; /* Transmit data frames using short preambles if the driver supports * short preambles at the selected rate and short preambles are @@ -605,7 +611,7 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) (sband->bitrates[tx->rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE) && tx->sdata->bss_conf.use_short_preamble && (!tx->sta || test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE))) { - tx->control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE; + info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE; } /* Setup duration field for the first fragment of the frame. Duration @@ -616,8 +622,8 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) tx->extra_frag[0]->len : 0); hdr->duration_id = cpu_to_le16(dur); - if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) || - (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) { + if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) || + (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) { struct ieee80211_supported_band *sband; struct ieee80211_rate *rate; s8 baserate = -1; @@ -626,7 +632,7 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) sband = tx->local->hw.wiphy->bands[tx->channel->band]; /* Do not use multiple retry rates when using RTS/CTS */ - control->alt_retry_rate_idx = -1; + info->control.alt_retry_rate_idx = -1; /* Use min(data rate, max base rate) as CTS/RTS rate */ rate = &sband->bitrates[tx->rate_idx]; @@ -642,13 +648,13 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) } if (baserate >= 0) - control->rts_cts_rate_idx = baserate; + info->control.rts_cts_rate_idx = baserate; else - control->rts_cts_rate_idx = 0; + info->control.rts_cts_rate_idx = 0; } if (tx->sta) - control->aid = tx->sta->aid; + info->control.aid = tx->sta->aid; return TX_CONTINUE; } @@ -762,6 +768,7 @@ ieee80211_tx_h_stats(struct ieee80211_tx_data *tx) u32 load = 0, hdrtime; struct ieee80211_rate *rate; struct ieee80211_supported_band *sband; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); sband = tx->local->hw.wiphy->bands[tx->channel->band]; rate = &sband->bitrates[tx->rate_idx]; @@ -786,9 +793,9 @@ ieee80211_tx_h_stats(struct ieee80211_tx_data *tx) if (!is_multicast_ether_addr(hdr->addr1)) load += hdrtime; - if (tx->control->flags & IEEE80211_TXCTL_USE_RTS_CTS) + if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) load += 2 * hdrtime; - else if (tx->control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) + else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) load += hdrtime; /* TODO: optimise again */ @@ -839,6 +846,7 @@ static ieee80211_tx_handler ieee80211_tx_handlers[] = ieee80211_tx_h_rate_ctrl, ieee80211_tx_h_misc, ieee80211_tx_h_fragment, + /* handlers after fragment must be aware of tx info fragmentation! */ ieee80211_tx_h_encrypt, ieee80211_tx_h_stats, NULL @@ -867,12 +875,12 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, (struct ieee80211_radiotap_header *) skb->data; struct ieee80211_supported_band *sband; int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len); - struct ieee80211_tx_control *control = tx->control; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); sband = tx->local->hw.wiphy->bands[tx->channel->band]; - control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; - tx->flags |= IEEE80211_TX_INJECTED; + info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT; + info->flags |= IEEE80211_TX_CTL_INJECTED; tx->flags &= ~IEEE80211_TX_FRAGMENTED; /* @@ -920,7 +928,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, * radiotap uses 0 for 1st ant, mac80211 is 1 for * 1st ant */ - control->antenna_sel_tx = (*iterator.this_arg) + 1; + info->antenna_sel_tx = (*iterator.this_arg) + 1; break; #if 0 @@ -944,8 +952,8 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, skb_trim(skb, skb->len - FCS_LEN); } if (*iterator.this_arg & IEEE80211_RADIOTAP_F_WEP) - control->flags &= - ~IEEE80211_TXCTL_DO_NOT_ENCRYPT; + info->flags &= + ~IEEE80211_TX_CTL_DO_NOT_ENCRYPT; if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG) tx->flags |= IEEE80211_TX_FRAGMENTED; break; @@ -980,12 +988,12 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, static ieee80211_tx_result __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, struct sk_buff *skb, - struct net_device *dev, - struct ieee80211_tx_control *control) + struct net_device *dev) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_hdr *hdr; struct ieee80211_sub_if_data *sdata; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int hdrlen; @@ -994,7 +1002,7 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, tx->dev = dev; /* use original interface */ tx->local = local; tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev); - tx->control = control; + tx->channel = local->hw.conf.channel; /* * Set this flag (used below to indicate "automatic fragmentation"), * it will be cleared/left by radiotap as desired. @@ -1021,10 +1029,10 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, if (is_multicast_ether_addr(hdr->addr1)) { tx->flags &= ~IEEE80211_TX_UNICAST; - control->flags |= IEEE80211_TXCTL_NO_ACK; + info->flags |= IEEE80211_TX_CTL_NO_ACK; } else { tx->flags |= IEEE80211_TX_UNICAST; - control->flags &= ~IEEE80211_TXCTL_NO_ACK; + info->flags &= ~IEEE80211_TX_CTL_NO_ACK; } if (tx->flags & IEEE80211_TX_FRAGMENTED) { @@ -1037,16 +1045,16 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, } if (!tx->sta) - control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT; + info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; else if (test_and_clear_sta_flags(tx->sta, WLAN_STA_CLEAR_PS_FILT)) - control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT; + info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; hdrlen = ieee80211_get_hdrlen(tx->fc); if (skb->len > hdrlen + sizeof(rfc1042_header) + 2) { u8 *pos = &skb->data[hdrlen + sizeof(rfc1042_header)]; tx->ethertype = (pos[0] << 8) | pos[1]; } - control->flags |= IEEE80211_TXCTL_FIRST_FRAGMENT; + info->flags |= IEEE80211_TX_CTL_FIRST_FRAGMENT; return TX_CONTINUE; } @@ -1056,14 +1064,12 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, */ static int ieee80211_tx_prepare(struct ieee80211_tx_data *tx, struct sk_buff *skb, - struct net_device *mdev, - struct ieee80211_tx_control *control) + struct net_device *mdev) { - struct ieee80211_tx_packet_data *pkt_data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct net_device *dev; - pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; - dev = dev_get_by_index(&init_net, pkt_data->ifindex); + dev = dev_get_by_index(&init_net, info->control.ifindex); if (unlikely(dev && !is_ieee80211_device(dev, mdev))) { dev_put(dev); dev = NULL; @@ -1071,7 +1077,7 @@ static int ieee80211_tx_prepare(struct ieee80211_tx_data *tx, if (unlikely(!dev)) return -ENODEV; /* initialises tx with control */ - __ieee80211_tx_prepare(tx, skb, dev, control); + __ieee80211_tx_prepare(tx, skb, dev); dev_put(dev); return 0; } @@ -1079,7 +1085,7 @@ static int ieee80211_tx_prepare(struct ieee80211_tx_data *tx, static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, struct ieee80211_tx_data *tx) { - struct ieee80211_tx_control *control = tx->control; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int ret, i; if (!ieee80211_qdisc_installed(local->mdev) && @@ -1090,39 +1096,39 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, if (skb) { ieee80211_dump_frame(wiphy_name(local->hw.wiphy), "TX to low-level driver", skb); - ret = local->ops->tx(local_to_hw(local), skb, control); + ret = local->ops->tx(local_to_hw(local), skb); if (ret) return IEEE80211_TX_AGAIN; local->mdev->trans_start = jiffies; ieee80211_led_tx(local, 1); } if (tx->extra_frag) { - control->flags &= ~(IEEE80211_TXCTL_USE_RTS_CTS | - IEEE80211_TXCTL_USE_CTS_PROTECT | - IEEE80211_TXCTL_CLEAR_PS_FILT | - IEEE80211_TXCTL_FIRST_FRAGMENT); for (i = 0; i < tx->num_extra_frag; i++) { if (!tx->extra_frag[i]) continue; - if (__ieee80211_queue_stopped(local, control->queue)) + info = IEEE80211_SKB_CB(tx->extra_frag[i]); + info->flags &= ~(IEEE80211_TX_CTL_USE_RTS_CTS | + IEEE80211_TX_CTL_USE_CTS_PROTECT | + IEEE80211_TX_CTL_CLEAR_PS_FILT | + IEEE80211_TX_CTL_FIRST_FRAGMENT); + if (__ieee80211_queue_stopped(local, info->queue)) return IEEE80211_TX_FRAG_AGAIN; if (i == tx->num_extra_frag) { - control->tx_rate_idx = tx->last_frag_rate_idx; + info->tx_rate_idx = tx->last_frag_rate_idx; if (tx->flags & IEEE80211_TX_PROBE_LAST_FRAG) - control->flags |= - IEEE80211_TXCTL_RATE_CTRL_PROBE; + info->flags |= + IEEE80211_TX_CTL_RATE_CTRL_PROBE; else - control->flags &= - ~IEEE80211_TXCTL_RATE_CTRL_PROBE; + info->flags &= + ~IEEE80211_TX_CTL_RATE_CTRL_PROBE; } ieee80211_dump_frame(wiphy_name(local->hw.wiphy), "TX to low-level driver", tx->extra_frag[i]); ret = local->ops->tx(local_to_hw(local), - tx->extra_frag[i], - control); + tx->extra_frag[i]); if (ret) return IEEE80211_TX_FRAG_AGAIN; local->mdev->trans_start = jiffies; @@ -1135,17 +1141,18 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, return IEEE80211_TX_OK; } -static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, - struct ieee80211_tx_control *control) +static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct sta_info *sta; ieee80211_tx_handler *handler; struct ieee80211_tx_data tx; ieee80211_tx_result res = TX_DROP, res_prepare; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int ret, i; + int queue = info->queue; - WARN_ON(__ieee80211_queue_pending(local, control->queue)); + WARN_ON(__ieee80211_queue_pending(local, queue)); if (unlikely(skb->len < 10)) { dev_kfree_skb(skb); @@ -1155,7 +1162,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, rcu_read_lock(); /* initialises tx */ - res_prepare = __ieee80211_tx_prepare(&tx, skb, dev, control); + res_prepare = __ieee80211_tx_prepare(&tx, skb, dev); if (res_prepare == TX_DROP) { dev_kfree_skb(skb); @@ -1165,7 +1172,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, sta = tx.sta; tx.channel = local->hw.conf.channel; - control->band = tx.channel->band; + info->band = tx.channel->band; for (handler = ieee80211_tx_handlers; *handler != NULL; handler++) { @@ -1174,7 +1181,8 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, break; } - skb = tx.skb; /* handlers are allowed to change skb */ + if (WARN_ON(tx.skb != skb)) + goto drop; if (unlikely(res == TX_DROP)) { I802_DEBUG_INC(local->tx_handlers_drop); @@ -1209,12 +1217,12 @@ retry: ret = __ieee80211_tx(local, skb, &tx); if (ret) { struct ieee80211_tx_stored_packet *store = - &local->pending_packet[control->queue]; + &local->pending_packet[info->queue]; if (ret == IEEE80211_TX_FRAG_AGAIN) skb = NULL; set_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[control->queue]); + &local->state[queue]); smp_mb(); /* When the driver gets out of buffers during sending of * fragments and calls ieee80211_stop_queue, there is @@ -1225,13 +1233,11 @@ retry: * called with IEEE80211_LINK_STATE_PENDING. Prevent this by * continuing transmitting here when that situation is * possible to have happened. */ - if (!__ieee80211_queue_stopped(local, control->queue)) { + if (!__ieee80211_queue_stopped(local, queue)) { clear_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[control->queue]); + &local->state[queue]); goto retry; } - memcpy(&store->control, control, - sizeof(struct ieee80211_tx_control)); store->skb = skb; store->extra_frag = tx.extra_frag; store->num_extra_frag = tx.num_extra_frag; @@ -1258,21 +1264,14 @@ retry: int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct ieee80211_tx_control control; - struct ieee80211_tx_packet_data *pkt_data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct net_device *odev = NULL; struct ieee80211_sub_if_data *osdata; int headroom; int ret; - /* - * copy control out of the skb so other people can use skb->cb - */ - pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; - memset(&control, 0, sizeof(struct ieee80211_tx_control)); - - if (pkt_data->ifindex) - odev = dev_get_by_index(&init_net, pkt_data->ifindex); + if (info->control.ifindex) + odev = dev_get_by_index(&init_net, info->control.ifindex); if (unlikely(odev && !is_ieee80211_device(odev, dev))) { dev_put(odev); odev = NULL; @@ -1285,6 +1284,7 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, dev_kfree_skb(skb); return 0; } + osdata = IEEE80211_DEV_TO_SUB_IF(odev); headroom = osdata->local->tx_headroom + IEEE80211_ENCRYPT_HEADROOM; @@ -1296,21 +1296,8 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, } } - control.vif = &osdata->vif; - control.type = osdata->vif.type; - if (pkt_data->flags & IEEE80211_TXPD_REQ_TX_STATUS) - control.flags |= IEEE80211_TXCTL_REQ_TX_STATUS; - if (pkt_data->flags & IEEE80211_TXPD_DO_NOT_ENCRYPT) - control.flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; - if (pkt_data->flags & IEEE80211_TXPD_REQUEUE) - control.flags |= IEEE80211_TXCTL_REQUEUE; - if (pkt_data->flags & IEEE80211_TXPD_EAPOL_FRAME) - control.flags |= IEEE80211_TXCTL_EAPOL_FRAME; - if (pkt_data->flags & IEEE80211_TXPD_AMPDU) - control.flags |= IEEE80211_TXCTL_AMPDU; - control.queue = pkt_data->queue; - - ret = ieee80211_tx(odev, skb, &control); + info->control.vif = &osdata->vif; + ret = ieee80211_tx(odev, skb); dev_put(odev); return ret; @@ -1320,7 +1307,7 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_tx_packet_data *pkt_data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_radiotap_header *prthdr = (struct ieee80211_radiotap_header *)skb->data; u16 len_rthdr; @@ -1342,14 +1329,12 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb, skb->dev = local->mdev; - pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; - memset(pkt_data, 0, sizeof(*pkt_data)); /* needed because we set skb device to master */ - pkt_data->ifindex = dev->ifindex; + info->control.ifindex = dev->ifindex; - pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT; + info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT; /* Interfaces should always request a status report */ - pkt_data->flags |= IEEE80211_TXPD_REQ_TX_STATUS; + info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; /* * fix up the pointers accounting for the radiotap @@ -1393,7 +1378,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_tx_packet_data *pkt_data; + struct ieee80211_tx_info *info; struct ieee80211_sub_if_data *sdata; int ret = 1, head_need; u16 ethertype, hdrlen, meshhdrlen = 0, fc; @@ -1625,14 +1610,14 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, nh_pos += hdrlen; h_pos += hdrlen; - pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; - memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data)); - pkt_data->ifindex = dev->ifindex; + info = IEEE80211_SKB_CB(skb); + memset(info, 0, sizeof(*info)); + info->control.ifindex = dev->ifindex; if (ethertype == ETH_P_PAE) - pkt_data->flags |= IEEE80211_TXPD_EAPOL_FRAME; + info->flags |= IEEE80211_TX_CTL_EAPOL_FRAME; /* Interfaces should always request a status report */ - pkt_data->flags |= IEEE80211_TXPD_REQ_TX_STATUS; + info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; skb->dev = local->mdev; dev->stats.tx_packets++; @@ -1693,7 +1678,6 @@ void ieee80211_tx_pending(unsigned long data) continue; } store = &local->pending_packet[i]; - tx.control = &store->control; tx.extra_frag = store->extra_frag; tx.num_extra_frag = store->num_extra_frag; tx.last_frag_rate_idx = store->last_frag_rate_idx; @@ -1786,11 +1770,11 @@ static void ieee80211_beacon_add_tim(struct ieee80211_local *local, } struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_tx_control *control) + struct ieee80211_vif *vif) { struct ieee80211_local *local = hw_to_local(hw); struct sk_buff *skb; + struct ieee80211_tx_info *info; struct net_device *bdev; struct ieee80211_sub_if_data *sdata = NULL; struct ieee80211_if_ap *ap = NULL; @@ -1896,31 +1880,32 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, goto out; } - if (control) { - control->band = band; - rate_control_get_rate(local->mdev, sband, skb, &rsel); - if (unlikely(rsel.rate_idx < 0)) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: ieee80211_beacon_get: " - "no rate found\n", - wiphy_name(local->hw.wiphy)); - } - dev_kfree_skb(skb); - skb = NULL; - goto out; - } + info = IEEE80211_SKB_CB(skb); + + info->band = band; + rate_control_get_rate(local->mdev, sband, skb, &rsel); - control->vif = vif; - control->tx_rate_idx = rsel.rate_idx; - if (sdata->bss_conf.use_short_preamble && - sband->bitrates[rsel.rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE) - control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE; - control->antenna_sel_tx = local->hw.conf.antenna_sel_tx; - control->flags |= IEEE80211_TXCTL_NO_ACK; - control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; - control->retry_limit = 1; - control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT; + if (unlikely(rsel.rate_idx < 0)) { + if (net_ratelimit()) { + printk(KERN_DEBUG "%s: ieee80211_beacon_get: " + "no rate found\n", + wiphy_name(local->hw.wiphy)); + } + dev_kfree_skb(skb); + skb = NULL; + goto out; } + + info->control.vif = vif; + info->tx_rate_idx = rsel.rate_idx; + if (sdata->bss_conf.use_short_preamble && + sband->bitrates[rsel.rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE) + info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE; + info->antenna_sel_tx = local->hw.conf.antenna_sel_tx; + info->flags |= IEEE80211_TX_CTL_NO_ACK; + info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT; + info->control.retry_limit = 1; + info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; (*num_beacons)++; out: rcu_read_unlock(); @@ -1930,7 +1915,7 @@ EXPORT_SYMBOL(ieee80211_beacon_get); void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const void *frame, size_t frame_len, - const struct ieee80211_tx_control *frame_txctl, + const struct ieee80211_tx_info *frame_txctl, struct ieee80211_rts *rts) { const struct ieee80211_hdr *hdr = frame; @@ -1947,7 +1932,7 @@ EXPORT_SYMBOL(ieee80211_rts_get); void ieee80211_ctstoself_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const void *frame, size_t frame_len, - const struct ieee80211_tx_control *frame_txctl, + const struct ieee80211_tx_info *frame_txctl, struct ieee80211_cts *cts) { const struct ieee80211_hdr *hdr = frame; @@ -1963,8 +1948,7 @@ EXPORT_SYMBOL(ieee80211_ctstoself_get); struct sk_buff * ieee80211_get_buffered_bc(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_tx_control *control) + struct ieee80211_vif *vif) { struct ieee80211_local *local = hw_to_local(hw); struct sk_buff *skb; @@ -1976,6 +1960,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, struct ieee80211_sub_if_data *sdata; struct ieee80211_if_ap *bss = NULL; struct beacon_data *beacon; + struct ieee80211_tx_info *info; sdata = vif_to_sdata(vif); bdev = sdata->dev; @@ -1995,7 +1980,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, if (bss->dtim_count != 0) return NULL; /* send buffered bc/mc only after DTIM beacon */ - memset(control, 0, sizeof(*control)); + while (1) { skb = skb_dequeue(&bss->ps_bc_buf); if (!skb) @@ -2012,21 +1997,26 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, cpu_to_le16(IEEE80211_FCTL_MOREDATA); } - if (!ieee80211_tx_prepare(&tx, skb, local->mdev, control)) + if (!ieee80211_tx_prepare(&tx, skb, local->mdev)) break; dev_kfree_skb_any(skb); } + + info = IEEE80211_SKB_CB(skb); + sta = tx.sta; tx.flags |= IEEE80211_TX_PS_BUFFERED; tx.channel = local->hw.conf.channel; - control->band = tx.channel->band; + info->band = tx.channel->band; for (handler = ieee80211_tx_handlers; *handler != NULL; handler++) { res = (*handler)(&tx); if (res == TX_DROP || res == TX_QUEUED) break; } - skb = tx.skb; /* handlers are allowed to change skb */ + + if (WARN_ON(tx.skb != skb)) + return NULL; if (res == TX_DROP) { I802_DEBUG_INC(local->tx_handlers_drop); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 65a34fddeb0..d9109dee461 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -258,7 +258,7 @@ EXPORT_SYMBOL(ieee80211_generic_frame_duration); __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, struct ieee80211_vif *vif, size_t frame_len, - const struct ieee80211_tx_control *frame_txctl) + const struct ieee80211_tx_info *frame_txctl) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_rate *rate; @@ -272,7 +272,7 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, short_preamble = sdata->bss_conf.use_short_preamble; - rate = &sband->bitrates[frame_txctl->rts_cts_rate_idx]; + rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx]; erp = 0; if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) @@ -295,7 +295,7 @@ EXPORT_SYMBOL(ieee80211_rts_duration); __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, struct ieee80211_vif *vif, size_t frame_len, - const struct ieee80211_tx_control *frame_txctl) + const struct ieee80211_tx_info *frame_txctl) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_rate *rate; @@ -309,7 +309,7 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, short_preamble = sdata->bss_conf.use_short_preamble; - rate = &sband->bitrates[frame_txctl->rts_cts_rate_idx]; + rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx]; erp = 0; if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) erp = rate->flags & IEEE80211_RATE_ERP_G; @@ -317,7 +317,7 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, /* Data frame duration */ dur = ieee80211_frame_duration(local, frame_len, rate->bitrate, erp, short_preamble); - if (!(frame_txctl->flags & IEEE80211_TXCTL_NO_ACK)) { + if (!(frame_txctl->flags & IEEE80211_TX_CTL_NO_ACK)) { /* ACK duration */ dur += ieee80211_frame_duration(local, 10, rate->bitrate, erp, short_preamble); diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index 3cbae42ec50..1e7f03dd8f6 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c @@ -333,11 +333,16 @@ ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx) static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + info->control.iv_len = WEP_IV_LEN; + info->control.icv_len = WEP_ICV_LEN; + if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { + info->control.hw_key = &tx->key->conf; if (ieee80211_wep_encrypt(tx->local, skb, tx->key)) return -1; } else { - tx->control->hw_key = &tx->key->conf; if (tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) { if (!ieee80211_wep_add_iv(tx->local, skb, tx->key)) return -1; @@ -349,8 +354,6 @@ static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) ieee80211_tx_result ieee80211_crypto_wep_encrypt(struct ieee80211_tx_data *tx) { - tx->control->iv_len = WEP_IV_LEN; - tx->control->icv_len = WEP_ICV_LEN; ieee80211_tx_set_protected(tx); if (wep_encrypt_skb(tx, tx->skb) < 0) { diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index c87baf4ce97..477690f4dca 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -149,8 +149,7 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr); struct ieee80211_hw *hw = &local->hw; struct ieee80211_sched_data *q = qdisc_priv(qd); - struct ieee80211_tx_packet_data *pkt_data = - (struct ieee80211_tx_packet_data *) skb->cb; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; unsigned short fc = le16_to_cpu(hdr->frame_control); struct Qdisc *qdisc; @@ -158,8 +157,8 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) int err, queue; u8 tid; - if (pkt_data->flags & IEEE80211_TXPD_REQUEUE) { - queue = pkt_data->queue; + if (info->flags & IEEE80211_TX_CTL_REQUEUE) { + queue = info->queue; rcu_read_lock(); sta = sta_info_get(local, hdr->addr1); tid = skb->priority & QOS_CONTROL_TAG1D_MASK; @@ -168,9 +167,9 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) if ((ampdu_queue < QD_NUM(hw)) && test_bit(ampdu_queue, q->qdisc_pool)) { queue = ampdu_queue; - pkt_data->flags |= IEEE80211_TXPD_AMPDU; + info->flags |= IEEE80211_TX_CTL_AMPDU; } else { - pkt_data->flags &= ~IEEE80211_TXPD_AMPDU; + info->flags &= ~IEEE80211_TX_CTL_AMPDU; } } rcu_read_unlock(); @@ -206,9 +205,9 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) if ((ampdu_queue < QD_NUM(hw)) && test_bit(ampdu_queue, q->qdisc_pool)) { queue = ampdu_queue; - pkt_data->flags |= IEEE80211_TXPD_AMPDU; + info->flags |= IEEE80211_TX_CTL_AMPDU; } else { - pkt_data->flags &= ~IEEE80211_TXPD_AMPDU; + info->flags &= ~IEEE80211_TX_CTL_AMPDU; } } @@ -220,7 +219,7 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) err = NET_XMIT_DROP; } else { tid = skb->priority & QOS_CONTROL_TAG1D_MASK; - pkt_data->queue = (unsigned int) queue; + info->queue = (unsigned int) queue; qdisc = q->queues[queue]; err = qdisc->enqueue(skb, qdisc); if (err == NET_XMIT_SUCCESS) { @@ -241,13 +240,12 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) static int wme_qdiscop_requeue(struct sk_buff *skb, struct Qdisc* qd) { struct ieee80211_sched_data *q = qdisc_priv(qd); - struct ieee80211_tx_packet_data *pkt_data = - (struct ieee80211_tx_packet_data *) skb->cb; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct Qdisc *qdisc; int err; /* we recorded which queue to use earlier! */ - qdisc = q->queues[pkt_data->queue]; + qdisc = q->queues[info->queue]; if ((err = qdisc->ops->requeue(skb, qdisc)) == 0) { qd->q.qlen++; diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index d7304490d2e..d6635f6e561 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -183,15 +183,25 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) } -static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, - struct sk_buff *skb, int test) +static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_key *key = tx->key; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int hdrlen, len, tailneed; u16 fc; u8 *pos; + info->control.icv_len = TKIP_ICV_LEN; + info->control.iv_len = TKIP_IV_LEN; + + if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && + !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { + /* hwaccel - with no need for preallocated room for IV/ICV */ + info->control.hw_key = &tx->key->conf; + return TX_CONTINUE; + } + fc = le16_to_cpu(hdr->frame_control); hdrlen = ieee80211_get_hdrlen(fc); len = skb->len - hdrlen; @@ -228,7 +238,7 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, 0x7f), (u8) key->u.tkip.tx.iv16); - tx->control->hw_key = &tx->key->conf; + info->control.hw_key = &tx->key->conf; return 0; } @@ -246,28 +256,16 @@ ieee80211_tx_result ieee80211_crypto_tkip_encrypt(struct ieee80211_tx_data *tx) { struct sk_buff *skb = tx->skb; - int wpa_test = 0, test = 0; - tx->control->icv_len = TKIP_ICV_LEN; - tx->control->iv_len = TKIP_IV_LEN; ieee80211_tx_set_protected(tx); - if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && - !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) && - !wpa_test) { - /* hwaccel - with no need for preallocated room for IV/ICV */ - tx->control->hw_key = &tx->key->conf; - return TX_CONTINUE; - } - - if (tkip_encrypt_skb(tx, skb, test) < 0) + if (tkip_encrypt_skb(tx, skb) < 0) return TX_DROP; if (tx->extra_frag) { int i; for (i = 0; i < tx->num_extra_frag; i++) { - if (tkip_encrypt_skb(tx, tx->extra_frag[i], test) - < 0) + if (tkip_encrypt_skb(tx, tx->extra_frag[i]) < 0) return TX_DROP; } } @@ -429,16 +427,27 @@ static inline int ccmp_hdr2pn(u8 *pn, u8 *hdr) } -static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, - struct sk_buff *skb, int test) +static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_key *key = tx->key; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int hdrlen, len, tailneed; u16 fc; u8 *pos, *pn, *b_0, *aad, *scratch; int i; + info->control.icv_len = CCMP_MIC_LEN; + info->control.iv_len = CCMP_HDR_LEN; + + if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && + !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { + /* hwaccel - with no need for preallocated room for CCMP " + * header or MIC fields */ + info->control.hw_key = &tx->key->conf; + return TX_CONTINUE; + } + scratch = key->u.ccmp.tx_crypto_buf; b_0 = scratch + 3 * AES_BLOCK_LEN; aad = scratch + 4 * AES_BLOCK_LEN; @@ -478,7 +487,7 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { /* hwaccel - with preallocated room for CCMP header */ - tx->control->hw_key = &tx->key->conf; + info->control.hw_key = &tx->key->conf; return 0; } @@ -495,28 +504,16 @@ ieee80211_tx_result ieee80211_crypto_ccmp_encrypt(struct ieee80211_tx_data *tx) { struct sk_buff *skb = tx->skb; - int test = 0; - tx->control->icv_len = CCMP_MIC_LEN; - tx->control->iv_len = CCMP_HDR_LEN; ieee80211_tx_set_protected(tx); - if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && - !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { - /* hwaccel - with no need for preallocated room for CCMP " - * header or MIC fields */ - tx->control->hw_key = &tx->key->conf; - return TX_CONTINUE; - } - - if (ccmp_encrypt_skb(tx, skb, test) < 0) + if (ccmp_encrypt_skb(tx, skb) < 0) return TX_DROP; if (tx->extra_frag) { int i; for (i = 0; i < tx->num_extra_frag; i++) { - if (ccmp_encrypt_skb(tx, tx->extra_frag[i], test) - < 0) + if (ccmp_encrypt_skb(tx, tx->extra_frag[i]) < 0) return TX_DROP; } } -- cgit v1.2.3-70-g09d2 From a8c4ea7a10f3c45eee27efb3954c3e03c297f0a7 Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Fri, 16 May 2008 17:27:05 +0900 Subject: zd1211rw: Use DMA-aware buffer for usb transfer The zd1211rw driver uses unaligned stack buffer for USB control message. But it might cause stack corruption on non-coherent platform, such as MIPS. Use DMA-aware buffers for USB transfer. Signed-off-by: Atsushi Nemoto Signed-off-by: John W. Linville --- drivers/net/wireless/zd1211rw/zd_usb.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index c8a0b34aecc..6a51ae419e6 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -169,10 +169,11 @@ static int upload_code(struct usb_device *udev, if (flags & REBOOT) { u8 ret; + /* Use "DMA-aware" buffer. */ r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), USB_REQ_FIRMWARE_CONFIRM, USB_DIR_IN | USB_TYPE_VENDOR, - 0, 0, &ret, sizeof(ret), 5000 /* ms */); + 0, 0, p, sizeof(ret), 5000 /* ms */); if (r != sizeof(ret)) { dev_err(&udev->dev, "control request firmeware confirmation failed." @@ -181,6 +182,7 @@ static int upload_code(struct usb_device *udev, r = -ENODEV; goto error; } + ret = p[0]; if (ret & 0x80) { dev_err(&udev->dev, "Internal error while downloading." @@ -312,22 +314,31 @@ int zd_usb_read_fw(struct zd_usb *usb, zd_addr_t addr, u8 *data, u16 len) { int r; struct usb_device *udev = zd_usb_to_usbdev(usb); + u8 *buf; + /* Use "DMA-aware" buffer. */ + buf = kmalloc(len, GFP_KERNEL); + if (!buf) + return -ENOMEM; r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), USB_REQ_FIRMWARE_READ_DATA, USB_DIR_IN | 0x40, addr, 0, - data, len, 5000); + buf, len, 5000); if (r < 0) { dev_err(&udev->dev, "read over firmware interface failed: %d\n", r); - return r; + goto exit; } else if (r != len) { dev_err(&udev->dev, "incomplete read over firmware interface: %d/%d\n", r, len); - return -EIO; + r = -EIO; + goto exit; } - - return 0; + r = 0; + memcpy(data, buf, len); +exit: + kfree(buf); + return r; } #define urb_dev(urb) (&(urb)->dev->dev) -- cgit v1.2.3-70-g09d2 From e93048825face354ecb0cb3ac00190c764a44f45 Mon Sep 17 00:00:00 2001 From: "Larry.Finger@lwfinger.net" Date: Thu, 15 May 2008 14:07:36 -0500 Subject: b43: Fix typo in firmware file name for 802.11 cores with rev 13 When the patch for the BCM4311 rev 2 was prepared, I misread the specs and coded the wrong file name for the initvals firmware. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 3622d76de1e..ff5dce67faa 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1958,7 +1958,7 @@ static int b43_request_firmware(struct b43_wldev *dev) if ((rev >= 5) && (rev <= 10)) filename = "b0g0initvals5"; else if (rev >= 13) - filename = "lp0initvals13"; + filename = "b0g0initvals13"; else goto err_no_initvals; break; -- cgit v1.2.3-70-g09d2 From e2530083609148a7835b54c431f6b8956407c1f6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 17 May 2008 00:57:14 +0200 Subject: mac80211: use multi-queue master netdevice This patch updates mac80211 and drivers to be multi-queue aware and use that instead of the internal queue mapping. Also does a number of cleanups in various pieces of the code that fall out and reduces internal mac80211 state size. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 2 +- drivers/net/wireless/b43/dma.c | 7 ++- drivers/net/wireless/b43/pio.c | 8 +-- drivers/net/wireless/b43legacy/dma.c | 3 +- drivers/net/wireless/iwlwifi/iwl-tx.c | 4 +- drivers/net/wireless/iwlwifi/iwl3945-base.c | 4 +- drivers/net/wireless/p54/p54common.c | 8 +-- drivers/net/wireless/rt2x00/rt2x00mac.c | 10 +-- drivers/net/wireless/rt2x00/rt2x00queue.h | 13 ---- drivers/net/wireless/rtl8180_dev.c | 4 +- include/net/mac80211.h | 20 +++++- net/mac80211/Kconfig | 14 ++++- net/mac80211/Makefile | 2 +- net/mac80211/ieee80211_i.h | 16 +++-- net/mac80211/iface.c | 2 +- net/mac80211/main.c | 29 ++++++--- net/mac80211/sta_info.c | 2 +- net/mac80211/tx.c | 97 +++++++++++++---------------- net/mac80211/util.c | 29 ++++----- net/mac80211/wme.c | 14 ++--- net/mac80211/wme.h | 2 +- 21 files changed, 158 insertions(+), 132 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 7d97934265d..18e9422d26d 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -2657,7 +2657,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) if (list_empty(&sc->txbuf)) { ATH5K_ERR(sc, "no further txbuf available, dropping packet\n"); spin_unlock_irqrestore(&sc->txbuflock, flags); - ieee80211_stop_queue(hw, info->queue); + ieee80211_stop_queue(hw, skb_get_queue_mapping(skb)); return -1; } bf = list_first_entry(&sc->txbuf, struct ath5k_buf, list); diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index aced9866d81..b4eadd908be 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -1297,7 +1297,8 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); } else { /* Decide by priority where to put this frame. */ - ring = select_ring_by_priority(dev, info->queue); + ring = select_ring_by_priority( + dev, skb_get_queue_mapping(skb)); } spin_lock_irqsave(&ring->lock, flags); @@ -1315,7 +1316,7 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) /* Assign the queue number to the ring (if not already done before) * so TX status handling can use it. The queue to ring mapping is * static, so we don't need to store it per frame. */ - ring->queue_prio = info->queue; + ring->queue_prio = skb_get_queue_mapping(skb); err = dma_tx_fragment(ring, skb); if (unlikely(err == -ENOKEY)) { @@ -1333,7 +1334,7 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) if ((free_slots(ring) < SLOTS_PER_PACKET) || should_inject_overflow(ring)) { /* This TX ring is full. */ - ieee80211_stop_queue(dev->wl->hw, info->queue); + ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); ring->stopped = 1; if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index); diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index 284786a94e7..8b1555d95f1 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -509,7 +509,7 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); } else { /* Decide by priority where to put this frame. */ - q = select_queue_by_priority(dev, info->queue); + q = select_queue_by_priority(dev, skb_get_queue_mapping(skb)); } spin_lock_irqsave(&q->lock, flags); @@ -532,7 +532,7 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) if (total_len > (q->buffer_size - q->buffer_used)) { /* Not enough memory on the queue. */ err = -EBUSY; - ieee80211_stop_queue(dev->wl->hw, info->queue); + ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); q->stopped = 1; goto out_unlock; } @@ -540,7 +540,7 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) /* Assign the queue number to the ring (if not already done before) * so TX status handling can use it. The mac80211-queue to b43-queue * mapping is static, so we don't need to store it per frame. */ - q->queue_prio = info->queue; + q->queue_prio = skb_get_queue_mapping(skb); err = pio_tx_frame(q, skb); if (unlikely(err == -ENOKEY)) { @@ -560,7 +560,7 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) if (((q->buffer_size - q->buffer_used) < roundup(2 + 2 + 6, 4)) || (q->free_packet_slots == 0)) { /* The queue is full. */ - ieee80211_stop_queue(dev->wl->hw, info->queue); + ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); q->stopped = 1; } diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c index c1c501d963b..33cc256c5ba 100644 --- a/drivers/net/wireless/b43legacy/dma.c +++ b/drivers/net/wireless/b43legacy/dma.c @@ -1325,11 +1325,10 @@ int b43legacy_dma_tx(struct b43legacy_wldev *dev, struct sk_buff *skb) { struct b43legacy_dmaring *ring; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int err = 0; unsigned long flags; - ring = priority_to_txring(dev, info->queue); + ring = priority_to_txring(dev, skb_get_queue_mapping(skb)); spin_lock_irqsave(&ring->lock, flags); B43legacy_WARN_ON(!ring->tx); if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) { diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index a61293ba3f6..0ebab967d5e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -696,7 +696,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl_tfd_frame *tfd; u32 *control_flags; - int txq_id = info->queue; + int txq_id = skb_get_queue_mapping(skb); struct iwl_tx_queue *txq = NULL; struct iwl_queue *q = NULL; dma_addr_t phys_addr; @@ -917,7 +917,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) spin_unlock_irqrestore(&priv->lock, flags); } - ieee80211_stop_queue(priv->hw, info->queue); + ieee80211_stop_queue(priv->hw, skb_get_queue_mapping(skb)); } return 0; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index a740a1817d1..e0f52e26441 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2552,7 +2552,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb) struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl3945_tfd_frame *tfd; u32 *control_flags; - int txq_id = info->queue; + int txq_id = skb_get_queue_mapping(skb); struct iwl3945_tx_queue *txq = NULL; struct iwl3945_queue *q = NULL; dma_addr_t phys_addr; @@ -2765,7 +2765,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb) spin_unlock_irqrestore(&priv->lock, flags); } - ieee80211_stop_queue(priv->hw, info->queue); + ieee80211_stop_queue(priv->hw, skb_get_queue_mapping(skb)); } return 0; diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 850857932e2..91ac9208b77 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -407,7 +407,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) last_addr = range->end_addr; __skb_unlink(entry, &priv->tx_queue); memset(&info->status, 0, sizeof(info->status)); - priv->tx_stats[info->queue].len--; + priv->tx_stats[skb_get_queue_mapping(skb)].len--; entry_hdr = (struct p54_control_hdr *) entry->data; entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data; if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0) @@ -551,13 +551,13 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) size_t padding, len; u8 rate; - current_queue = &priv->tx_stats[info->queue]; + current_queue = &priv->tx_stats[skb_get_queue_mapping(skb)]; if (unlikely(current_queue->len > current_queue->limit)) return NETDEV_TX_BUSY; current_queue->len++; current_queue->count++; if (current_queue->len == current_queue->limit) - ieee80211_stop_queue(dev, info->queue); + ieee80211_stop_queue(dev, skb_get_queue_mapping(skb)); padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3; len = skb->len; @@ -589,7 +589,7 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) memset(txhdr->rateset, rate, 8); txhdr->wep_key_present = 0; txhdr->wep_key_len = 0; - txhdr->frame_type = cpu_to_le32(info->queue + 4); + txhdr->frame_type = cpu_to_le32(skb_get_queue_mapping(skb) + 4); txhdr->magic4 = 0; txhdr->antenna = (info->antenna_sel_tx == 0) ? 2 : info->antenna_sel_tx - 1; diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index b5379b027b1..c05e05b5888 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -102,7 +102,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) struct rt2x00_dev *rt2x00dev = hw->priv; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data; - enum data_queue_qid qid = mac80211_queue_to_qid(tx_info->queue); + enum data_queue_qid qid = skb_get_queue_mapping(skb); struct data_queue *queue; u16 frame_control; @@ -149,23 +149,23 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) IEEE80211_TX_CTL_USE_CTS_PROTECT)) && !rt2x00dev->ops->hw->set_rts_threshold) { if (rt2x00queue_available(queue) <= 1) { - ieee80211_stop_queue(rt2x00dev->hw, tx_info->queue); + ieee80211_stop_queue(rt2x00dev->hw, qid); return NETDEV_TX_BUSY; } if (rt2x00mac_tx_rts_cts(rt2x00dev, queue, skb)) { - ieee80211_stop_queue(rt2x00dev->hw, tx_info->queue); + ieee80211_stop_queue(rt2x00dev->hw, qid); return NETDEV_TX_BUSY; } } if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, queue, skb)) { - ieee80211_stop_queue(rt2x00dev->hw, tx_info->queue); + ieee80211_stop_queue(rt2x00dev->hw, qid); return NETDEV_TX_BUSY; } if (rt2x00queue_full(queue)) - ieee80211_stop_queue(rt2x00dev->hw, tx_info->queue); + ieee80211_stop_queue(rt2x00dev->hw, qid); if (rt2x00dev->ops->lib->kick_tx_queue) rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, qid); diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index f263fe422f8..4d00ced14cc 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -79,19 +79,6 @@ enum data_queue_qid { QID_ATIM, }; -/** - * mac80211_queue_to_qid - Convert mac80211 queue to rt2x00 qid - * @queue: mac80211 queue. - */ -static inline enum data_queue_qid mac80211_queue_to_qid(unsigned int queue) -{ - /* Regular TX queues are mapped directly */ - if (queue < 4) - return queue; - WARN_ON(1); - return QID_OTHER; -} - /** * enum skb_frame_desc_flags: Flags for &struct skb_frame_desc * diff --git a/drivers/net/wireless/rtl8180_dev.c b/drivers/net/wireless/rtl8180_dev.c index 4427bc9f78a..b7172a12c05 100644 --- a/drivers/net/wireless/rtl8180_dev.c +++ b/drivers/net/wireless/rtl8180_dev.c @@ -246,7 +246,7 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb) u16 plcp_len = 0; __le16 rts_duration = 0; - prio = info->queue; + prio = skb_get_queue_mapping(skb); ring = &priv->tx_ring[prio]; mapping = pci_map_single(priv->pdev, skb->data, @@ -298,7 +298,7 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb) entry->flags = cpu_to_le32(tx_flags); __skb_queue_tail(&ring->queue, skb); if (ring->entries - skb_queue_len(&ring->queue) < 2) - ieee80211_stop_queue(dev, info->queue); + ieee80211_stop_queue(dev, skb_get_queue_mapping(skb)); spin_unlock_irqrestore(&priv->lock, flags); rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING, (1 << (prio + 4))); diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 4df39eb9115..c80e3be8f79 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -293,7 +293,7 @@ struct ieee80211_tx_info { s8 tx_rate_idx; u8 antenna_sel_tx; - u8 queue; /* use skb_queue_mapping soon */ + /* 1 byte hole */ union { struct { @@ -802,6 +802,24 @@ static inline void SET_IEEE80211_PERM_ADDR(struct ieee80211_hw *hw, u8 *addr) memcpy(hw->wiphy->perm_addr, addr, ETH_ALEN); } +static inline int ieee80211_num_regular_queues(struct ieee80211_hw *hw) +{ +#ifdef CONFIG_MAC80211_QOS + return hw->queues; +#else + return 1; +#endif +} + +static inline int ieee80211_num_queues(struct ieee80211_hw *hw) +{ +#ifdef CONFIG_MAC80211_QOS + return hw->queues + hw->ampdu_queues; +#else + return 1; +#endif +} + static inline struct ieee80211_rate * ieee80211_get_tx_rate(const struct ieee80211_hw *hw, const struct ieee80211_tx_info *c) diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index a24b459dd45..590e00b2766 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -7,11 +7,23 @@ config MAC80211 select CRC32 select WIRELESS_EXT select CFG80211 - select NET_SCH_FIFO ---help--- This option enables the hardware independent IEEE 802.11 networking stack. +config MAC80211_QOS + def_bool y + depends on MAC80211 + depends on NET_SCHED + depends on NETDEVICES_MULTIQUEUE + +comment "QoS/HT support disabled" + depends on MAC80211 && !MAC80211_QOS +comment "QoS/HT support needs CONFIG_NET_SCHED" + depends on MAC80211 && !NET_SCHED +comment "QoS/HT support needs CONFIG_NETDEVICES_MULTIQUEUE" + depends on MAC80211 && !NETDEVICES_MULTIQUEUE + menu "Rate control algorithm selection" depends on MAC80211 != n diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 4e5847fd316..1d2a4e010e5 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -29,7 +29,7 @@ mac80211-y := \ event.o mac80211-$(CONFIG_MAC80211_LEDS) += led.o -mac80211-$(CONFIG_NET_SCHED) += wme.o +mac80211-$(CONFIG_MAC80211_QOS) += wme.o mac80211-$(CONFIG_MAC80211_DEBUGFS) += \ debugfs.o \ debugfs_sta.o \ diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 86a861251e8..7d614cdcefc 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -594,7 +594,7 @@ struct ieee80211_local { struct sta_info *sta_hash[STA_HASH_SIZE]; struct timer_list sta_cleanup; - unsigned long state[IEEE80211_MAX_QUEUES + IEEE80211_MAX_AMPDU_QUEUES]; + unsigned long queues_pending[BITS_TO_LONGS(IEEE80211_MAX_QUEUES)]; struct ieee80211_tx_stored_packet pending_packet[IEEE80211_MAX_QUEUES]; struct tasklet_struct tx_pending_tasklet; @@ -758,6 +758,15 @@ struct ieee80211_local { #endif }; +static inline int ieee80211_is_multiqueue(struct ieee80211_local *local) +{ +#ifdef CONFIG_MAC80211_QOS + return netif_is_multiqueue(local->mdev); +#else + return 0; +#endif +} + /* this struct represents 802.11n's RA/TID combination */ struct ieee80211_ra_tid { u8 ra[ETH_ALEN]; @@ -827,11 +836,6 @@ static inline struct ieee80211_hw *local_to_hw( return &local->hw; } -enum ieee80211_link_state_t { - IEEE80211_LINK_STATE_XOFF = 0, - IEEE80211_LINK_STATE_PENDING, -}; - struct sta_attribute { struct attribute attr; ssize_t (*show)(const struct sta_info *, char *buf); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 3c64e42eb12..98447270238 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -168,7 +168,7 @@ void ieee80211_if_set_type(struct net_device *dev, int type) ifsta->flags |= IEEE80211_STA_CREATE_IBSS | IEEE80211_STA_AUTO_BSSID_SEL | IEEE80211_STA_AUTO_CHANNEL_SEL; - if (sdata->local->hw.queues >= 4) + if (ieee80211_num_regular_queues(&sdata->local->hw) >= 4) ifsta->flags |= IEEE80211_STA_WMM_ENABLED; msdata = IEEE80211_DEV_TO_SUB_IF(sdata->local->mdev); diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 8f1ff7ef166..97d4a537ca2 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -1634,12 +1634,32 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (result < 0) return result; + /* + * We use the number of queues for feature tests (QoS, HT) internally + * so restrict them appropriately. + */ +#ifdef CONFIG_MAC80211_QOS + if (hw->queues > IEEE80211_MAX_QUEUES) + hw->queues = IEEE80211_MAX_QUEUES; + if (hw->ampdu_queues > IEEE80211_MAX_AMPDU_QUEUES) + hw->ampdu_queues = IEEE80211_MAX_AMPDU_QUEUES; + if (hw->queues < 4) + hw->ampdu_queues = 0; +#else + hw->queues = 1; + hw->ampdu_queues = 0; +#endif + /* for now, mdev needs sub_if_data :/ */ - mdev = alloc_netdev(sizeof(struct ieee80211_sub_if_data), - "wmaster%d", ether_setup); + mdev = alloc_netdev_mq(sizeof(struct ieee80211_sub_if_data), + "wmaster%d", ether_setup, + ieee80211_num_queues(hw)); if (!mdev) goto fail_mdev_alloc; + if (ieee80211_num_queues(hw) > 1) + mdev->features |= NETIF_F_MULTI_QUEUE; + sdata = IEEE80211_DEV_TO_SUB_IF(mdev); mdev->ieee80211_ptr = &sdata->wdev; sdata->wdev.wiphy = local->hw.wiphy; @@ -1728,11 +1748,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) goto fail_wep; } - if (hw->queues > IEEE80211_MAX_QUEUES) - hw->queues = IEEE80211_MAX_QUEUES; - if (hw->ampdu_queues > IEEE80211_MAX_AMPDU_QUEUES) - hw->ampdu_queues = IEEE80211_MAX_AMPDU_QUEUES; - ieee80211_install_qdisc(local->mdev); /* add one default STA interface */ diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index ef3149324d5..c24770cb02c 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -255,7 +255,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, * sta_rx_agg_session_timer_expired for useage */ sta->timer_to_tid[i] = i; /* tid to tx queue: initialize according to HW (0 is valid) */ - sta->tid_to_tx_q[i] = local->hw.queues + local->hw.ampdu_queues; + sta->tid_to_tx_q[i] = ieee80211_num_queues(&local->hw); /* rx */ sta->ampdu_mlme.tid_state_rx[i] = HT_AGG_STATE_IDLE; sta->ampdu_mlme.tid_rx[i] = NULL; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 6268bbca148..9273651d3d7 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -213,18 +213,6 @@ static u16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr, return dur; } -static inline int __ieee80211_queue_stopped(const struct ieee80211_local *local, - int queue) -{ - return test_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]); -} - -static inline int __ieee80211_queue_pending(const struct ieee80211_local *local, - int queue) -{ - return test_bit(IEEE80211_LINK_STATE_PENDING, &local->state[queue]); -} - static int inline is_ieee80211_device(struct net_device *dev, struct net_device *master) { @@ -680,7 +668,8 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) * etc. */ if (WARN_ON(tx->flags & IEEE80211_TX_CTL_AMPDU || - IEEE80211_SKB_CB(tx->skb)->queue >= tx->local->hw.queues)) + skb_get_queue_mapping(tx->skb) >= + ieee80211_num_regular_queues(&tx->local->hw))) return TX_DROP; first = tx->skb; @@ -1098,11 +1087,9 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int ret, i; - if (!ieee80211_qdisc_installed(local->mdev) && - __ieee80211_queue_stopped(local, 0)) { - netif_stop_queue(local->mdev); + if (netif_subqueue_stopped(local->mdev, skb)) return IEEE80211_TX_AGAIN; - } + if (skb) { ieee80211_dump_frame(wiphy_name(local->hw.wiphy), "TX to low-level driver", skb); @@ -1121,7 +1108,8 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, IEEE80211_TX_CTL_USE_CTS_PROTECT | IEEE80211_TX_CTL_CLEAR_PS_FILT | IEEE80211_TX_CTL_FIRST_FRAGMENT); - if (__ieee80211_queue_stopped(local, info->queue)) + if (netif_subqueue_stopped(local->mdev, + tx->extra_frag[i])) return IEEE80211_TX_FRAG_AGAIN; if (i == tx->num_extra_frag) { info->tx_rate_idx = tx->last_frag_rate_idx; @@ -1160,9 +1148,11 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb) ieee80211_tx_result res = TX_DROP, res_prepare; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int ret, i; - int queue = info->queue; + u16 queue; - WARN_ON(__ieee80211_queue_pending(local, queue)); + queue = skb_get_queue_mapping(skb); + + WARN_ON(test_bit(queue, local->queues_pending)); if (unlikely(skb->len < 10)) { dev_kfree_skb(skb); @@ -1233,28 +1223,28 @@ retry: * queues, there's no reason for a driver to reject * a frame there, warn and drop it. */ - if (WARN_ON(queue >= local->hw.queues)) + if (WARN_ON(queue >= ieee80211_num_regular_queues(&local->hw))) goto drop; store = &local->pending_packet[queue]; if (ret == IEEE80211_TX_FRAG_AGAIN) skb = NULL; - set_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[queue]); + set_bit(queue, local->queues_pending); smp_mb(); - /* When the driver gets out of buffers during sending of - * fragments and calls ieee80211_stop_queue, there is - * a small window between IEEE80211_LINK_STATE_XOFF and - * IEEE80211_LINK_STATE_PENDING flags are set. If a buffer + /* + * When the driver gets out of buffers during sending of + * fragments and calls ieee80211_stop_queue, the netif + * subqueue is stopped. There is, however, a small window + * in which the PENDING bit is not yet set. If a buffer * gets available in that window (i.e. driver calls * ieee80211_wake_queue), we would end up with ieee80211_tx - * called with IEEE80211_LINK_STATE_PENDING. Prevent this by + * called with the PENDING bit still set. Prevent this by * continuing transmitting here when that situation is - * possible to have happened. */ - if (!__ieee80211_queue_stopped(local, queue)) { - clear_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[queue]); + * possible to have happened. + */ + if (!__netif_subqueue_stopped(local->mdev, queue)) { + clear_bit(queue, local->queues_pending); goto retry; } store->skb = skb; @@ -1509,7 +1499,8 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, } /* receiver and we are QoS enabled, use a QoS type frame */ - if (sta_flags & WLAN_STA_WME && local->hw.queues >= 4) { + if (sta_flags & WLAN_STA_WME && + ieee80211_num_regular_queues(&local->hw) >= 4) { fc |= IEEE80211_STYPE_QOS_DATA; hdrlen += 2; } @@ -1661,41 +1652,51 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, return ret; } -/* helper functions for pending packets for when queues are stopped */ +/* + * ieee80211_clear_tx_pending may not be called in a context where + * it is possible that it packets could come in again. + */ void ieee80211_clear_tx_pending(struct ieee80211_local *local) { int i, j; struct ieee80211_tx_stored_packet *store; - for (i = 0; i < local->hw.queues; i++) { - if (!__ieee80211_queue_pending(local, i)) + for (i = 0; i < ieee80211_num_regular_queues(&local->hw); i++) { + if (!test_bit(i, local->queues_pending)) continue; store = &local->pending_packet[i]; kfree_skb(store->skb); for (j = 0; j < store->num_extra_frag; j++) kfree_skb(store->extra_frag[j]); kfree(store->extra_frag); - clear_bit(IEEE80211_LINK_STATE_PENDING, &local->state[i]); + clear_bit(i, local->queues_pending); } } +/* + * Transmit all pending packets. Called from tasklet, locks master device + * TX lock so that no new packets can come in. + */ void ieee80211_tx_pending(unsigned long data) { struct ieee80211_local *local = (struct ieee80211_local *)data; struct net_device *dev = local->mdev; struct ieee80211_tx_stored_packet *store; struct ieee80211_tx_data tx; - int i, ret, reschedule = 0; + int i, ret; netif_tx_lock_bh(dev); - for (i = 0; i < local->hw.queues; i++) { - if (__ieee80211_queue_stopped(local, i)) + for (i = 0; i < ieee80211_num_regular_queues(&local->hw); i++) { + /* Check that this queue is ok */ + if (__netif_subqueue_stopped(local->mdev, i)) continue; - if (!__ieee80211_queue_pending(local, i)) { - reschedule = 1; + + if (!test_bit(i, local->queues_pending)) { + ieee80211_wake_queue(&local->hw, i); continue; } + store = &local->pending_packet[i]; tx.extra_frag = store->extra_frag; tx.num_extra_frag = store->num_extra_frag; @@ -1708,19 +1709,11 @@ void ieee80211_tx_pending(unsigned long data) if (ret == IEEE80211_TX_FRAG_AGAIN) store->skb = NULL; } else { - clear_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[i]); - reschedule = 1; + clear_bit(i, local->queues_pending); + ieee80211_wake_queue(&local->hw, i); } } netif_tx_unlock_bh(dev); - if (reschedule) { - if (!ieee80211_qdisc_installed(dev)) { - if (!__ieee80211_queue_stopped(local, 0)) - netif_wake_queue(dev); - } else - netif_schedule(dev); - } } /* functions for drivers to get certain frames */ diff --git a/net/mac80211/util.c b/net/mac80211/util.c index d9109dee461..4f7180b287d 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -331,17 +331,15 @@ void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue) { struct ieee80211_local *local = hw_to_local(hw); - if (test_and_clear_bit(IEEE80211_LINK_STATE_XOFF, - &local->state[queue])) { - if (test_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[queue])) - tasklet_schedule(&local->tx_pending_tasklet); - else - if (!ieee80211_qdisc_installed(local->mdev)) { - if (queue == 0) - netif_wake_queue(local->mdev); - } else - __netif_schedule(local->mdev); + if (test_bit(queue, local->queues_pending)) { + tasklet_schedule(&local->tx_pending_tasklet); + } else { + if (ieee80211_is_multiqueue(local)) { + netif_wake_subqueue(local->mdev, queue); + } else { + WARN_ON(queue != 0); + netif_wake_queue(local->mdev); + } } } EXPORT_SYMBOL(ieee80211_wake_queue); @@ -350,9 +348,12 @@ void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue) { struct ieee80211_local *local = hw_to_local(hw); - if (!ieee80211_qdisc_installed(local->mdev) && queue == 0) + if (ieee80211_is_multiqueue(local)) { + netif_stop_subqueue(local->mdev, queue); + } else { + WARN_ON(queue != 0); netif_stop_queue(local->mdev); - set_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]); + } } EXPORT_SYMBOL(ieee80211_stop_queue); @@ -360,7 +361,7 @@ void ieee80211_stop_queues(struct ieee80211_hw *hw) { int i; - for (i = 0; i < hw->queues + hw->ampdu_queues; i++) + for (i = 0; i < ieee80211_num_queues(hw); i++) ieee80211_stop_queue(hw, i); } EXPORT_SYMBOL(ieee80211_stop_queues); diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 477690f4dca..14a9ff10a1e 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -158,7 +158,7 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) u8 tid; if (info->flags & IEEE80211_TX_CTL_REQUEUE) { - queue = info->queue; + queue = skb_get_queue_mapping(skb); rcu_read_lock(); sta = sta_info_get(local, hdr->addr1); tid = skb->priority & QOS_CONTROL_TAG1D_MASK; @@ -219,7 +219,7 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) err = NET_XMIT_DROP; } else { tid = skb->priority & QOS_CONTROL_TAG1D_MASK; - info->queue = (unsigned int) queue; + skb_set_queue_mapping(skb, queue); qdisc = q->queues[queue]; err = qdisc->enqueue(skb, qdisc); if (err == NET_XMIT_SUCCESS) { @@ -240,12 +240,11 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) static int wme_qdiscop_requeue(struct sk_buff *skb, struct Qdisc* qd) { struct ieee80211_sched_data *q = qdisc_priv(qd); - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct Qdisc *qdisc; int err; /* we recorded which queue to use earlier! */ - qdisc = q->queues[info->queue]; + qdisc = q->queues[skb_get_queue_mapping(skb)]; if ((err = qdisc->ops->requeue(skb, qdisc)) == 0) { qd->q.qlen++; @@ -269,11 +268,8 @@ static struct sk_buff *wme_qdiscop_dequeue(struct Qdisc* qd) /* check all the h/w queues in numeric/priority order */ for (queue = 0; queue < QD_NUM(hw); queue++) { /* see if there is room in this hardware queue */ - if ((test_bit(IEEE80211_LINK_STATE_XOFF, - &local->state[queue])) || - (test_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[queue])) || - (!test_bit(queue, q->qdisc_pool))) + if (__netif_subqueue_stopped(local->mdev, queue) || + !test_bit(queue, q->qdisc_pool)) continue; /* there is space - try and get a frame */ diff --git a/net/mac80211/wme.h b/net/mac80211/wme.h index fcc6b05508c..bbdb5334481 100644 --- a/net/mac80211/wme.h +++ b/net/mac80211/wme.h @@ -31,7 +31,7 @@ static inline int WLAN_FC_IS_QOS_DATA(u16 fc) return (fc & 0x8C) == 0x88; } -#ifdef CONFIG_NET_SCHED +#ifdef CONFIG_MAC80211_QOS void ieee80211_install_qdisc(struct net_device *dev); int ieee80211_qdisc_installed(struct net_device *dev); int ieee80211_ht_agg_queue_add(struct ieee80211_local *local, -- cgit v1.2.3-70-g09d2 From e48b0eeb0ab508021b654a45f332b30cac2163b9 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 17 May 2008 22:44:35 +0200 Subject: b43: Add hooks for firmware debugging This patch adds some hooks for firmware debugging. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/b43.h | 9 +++++ drivers/net/wireless/b43/main.c | 79 +++++++++++++++++++++++++++++++++++++---- 2 files changed, 81 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index aa493830a82..00468594b45 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -422,6 +422,12 @@ enum { B43_IRQ_RFKILL | \ B43_IRQ_TX_OK) +/* Debug-IRQ reasons. */ +#define B43_DEBUGIRQ_PANIC 0 /* The firmware panic'ed */ +#define B43_DEBUGIRQ_DUMP_SHM 1 /* Dump shared SHM */ +#define B43_DEBUGIRQ_DUMP_REGS 2 /* Dump the microcode registers */ +#define B43_DEBUGIRQ_ACK 0xFFFF /* The host writes that to ACK the IRQ */ + /* Device specific rate values. * The actual values defined here are (rate_in_mbps * 2). * Some code depends on this. Don't change it. */ @@ -765,6 +771,9 @@ struct b43_firmware { u16 rev; /* Firmware patchlevel */ u16 patch; + + /* Set to true, if we are using an opensource firmware. */ + bool opensource; }; /* Device (802.11 core) initialization status. */ diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index ff5dce67faa..656a1f04ad6 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1664,7 +1664,64 @@ static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int) static void handle_irq_ucode_debug(struct b43_wldev *dev) { - //TODO + unsigned int i, cnt; + u16 reason; + __le16 *buf; + + /* The proprietary firmware doesn't have this IRQ. */ + if (!dev->fw.opensource) + return; + + /* Microcode register 63 contains the debug-IRQ reason. */ + reason = b43_shm_read16(dev, B43_SHM_SCRATCH, 63); + switch (reason) { + case B43_DEBUGIRQ_PANIC: + /* The reason for the panic is in register 3. */ + reason = b43_shm_read16(dev, B43_SHM_SCRATCH, 3); + b43err(dev->wl, "Whoopsy, the microcode panic'ed! Reason: %u\n", + reason); + b43_controller_restart(dev, "Microcode panic"); + break; + case B43_DEBUGIRQ_DUMP_SHM: + if (!B43_DEBUG) + break; /* Only with driver debugging enabled. */ + buf = kmalloc(4096, GFP_ATOMIC); + if (!buf) { + b43dbg(dev->wl, "SHM-dump: Failed to allocate memory\n"); + goto out; + } + for (i = 0; i < 4096; i += 2) { + u16 tmp = b43_shm_read16(dev, B43_SHM_SHARED, i); + buf[i / 2] = cpu_to_le16(tmp); + } + b43info(dev->wl, "Shared memory dump:\n"); + print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, + 16, 2, buf, 4096, 1); + kfree(buf); + break; + case B43_DEBUGIRQ_DUMP_REGS: + if (!B43_DEBUG) + break; /* Only with driver debugging enabled. */ + b43info(dev->wl, "Microcode register dump:\n"); + for (i = 0, cnt = 0; i < 64; i++) { + u16 tmp = b43_shm_read16(dev, B43_SHM_SCRATCH, i); + if (cnt == 0) + printk(KERN_INFO); + printk("r%02u: 0x%04X ", i, tmp); + cnt++; + if (cnt == 6) { + printk("\n"); + cnt = 0; + } + } + printk("\n"); + break; + default: + b43dbg(dev->wl, "Debug-IRQ triggered for unknown reason: %u\n", + reason); + } +out: + b43_shm_write16(dev, B43_SHM_SCRATCH, 63, B43_DEBUGIRQ_ACK); } /* Interrupt handler bottom-half */ @@ -2122,14 +2179,22 @@ static int b43_upload_microcode(struct b43_wldev *dev) err = -EOPNOTSUPP; goto error; } - b43info(dev->wl, "Loading firmware version %u.%u " - "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", - fwrev, fwpatch, - (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF, - (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F); - dev->fw.rev = fwrev; dev->fw.patch = fwpatch; + dev->fw.opensource = (fwdate == 0xFFFF); + + if (dev->fw.opensource) { + /* Patchlevel info is encoded in the "time" field. */ + dev->fw.patch = fwtime; + b43info(dev->wl, "Loading OpenSource firmware version %u.%u\n", + dev->fw.rev, dev->fw.patch); + } else { + b43info(dev->wl, "Loading firmware version %u.%u " + "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", + fwrev, fwpatch, + (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF, + (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F); + } if (b43_is_old_txhdr_format(dev)) { b43warn(dev->wl, "You are using an old firmware image. " -- cgit v1.2.3-70-g09d2 From 6821783271aaf541504ff8a138184fcc83fa282b Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 17 May 2008 23:43:57 +0200 Subject: b43: Allow running without PCM firmware This patch adds code to allow running the device without PCM firmware loaded. Without PCM firmware we don't have hardware accelerated crypto on devices with a core rev <= 10. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/b43.h | 4 ++++ drivers/net/wireless/b43/main.c | 47 +++++++++++++++++++++++++++++++---------- 2 files changed, 40 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 00468594b45..f588dfa9c1d 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -774,6 +774,10 @@ struct b43_firmware { /* Set to true, if we are using an opensource firmware. */ bool opensource; + /* Set to true, if the core needs a PCM firmware, but + * we failed to load one. This is always false for + * core rev > 10, as these don't need PCM firmware. */ + bool pcm_request_failed; }; /* Device (802.11 core) initialization status. */ diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 656a1f04ad6..6011747bb3b 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1908,7 +1908,8 @@ static void b43_print_fw_helptext(struct b43_wl *wl, bool error) static int do_request_fw(struct b43_wldev *dev, const char *name, - struct b43_firmware_file *fw) + struct b43_firmware_file *fw, + bool silent) { char path[sizeof(modparam_fwpostfix) + 32]; const struct firmware *blob; @@ -1932,9 +1933,15 @@ static int do_request_fw(struct b43_wldev *dev, "b43%s/%s.fw", modparam_fwpostfix, name); err = request_firmware(&blob, path, dev->dev->dev); - if (err) { - b43err(dev->wl, "Firmware file \"%s\" not found " - "or load failed.\n", path); + if (err == -ENOENT) { + if (!silent) { + b43err(dev->wl, "Firmware file \"%s\" not found\n", + path); + } + return err; + } else if (err) { + b43err(dev->wl, "Firmware file \"%s\" request failed (err=%d)\n", + path, err); return err; } if (blob->size < sizeof(struct b43_fw_header)) @@ -1985,7 +1992,7 @@ static int b43_request_firmware(struct b43_wldev *dev) filename = "ucode13"; else goto err_no_ucode; - err = do_request_fw(dev, filename, &fw->ucode); + err = do_request_fw(dev, filename, &fw->ucode, 0); if (err) goto err_load; @@ -1996,8 +2003,13 @@ static int b43_request_firmware(struct b43_wldev *dev) filename = NULL; else goto err_no_pcm; - err = do_request_fw(dev, filename, &fw->pcm); - if (err) + fw->pcm_request_failed = 0; + err = do_request_fw(dev, filename, &fw->pcm, 1); + 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; + } else if (err) goto err_load; /* Get initvals */ @@ -2028,7 +2040,7 @@ static int b43_request_firmware(struct b43_wldev *dev) default: goto err_no_initvals; } - err = do_request_fw(dev, filename, &fw->initvals); + err = do_request_fw(dev, filename, &fw->initvals, 0); if (err) goto err_load; @@ -2062,7 +2074,7 @@ static int b43_request_firmware(struct b43_wldev *dev) default: goto err_no_initvals; } - err = do_request_fw(dev, filename, &fw->initvals_band); + err = do_request_fw(dev, filename, &fw->initvals_band, 0); if (err) goto err_load; @@ -2186,14 +2198,20 @@ static int b43_upload_microcode(struct b43_wldev *dev) if (dev->fw.opensource) { /* Patchlevel info is encoded in the "time" field. */ dev->fw.patch = fwtime; - b43info(dev->wl, "Loading OpenSource firmware version %u.%u\n", - dev->fw.rev, dev->fw.patch); + b43info(dev->wl, "Loading OpenSource firmware version %u.%u%s\n", + dev->fw.rev, dev->fw.patch, + dev->fw.pcm_request_failed ? " (Hardware crypto not supported)" : ""); } else { b43info(dev->wl, "Loading firmware version %u.%u " "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", fwrev, fwpatch, (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF, (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F); + if (dev->fw.pcm_request_failed) { + b43warn(dev->wl, "No \"pcm5.fw\" firmware file found. " + "Hardware accelerated cryptography is disabled.\n"); + b43_print_fw_helptext(dev->wl, 0); + } } if (b43_is_old_txhdr_format(dev)) { @@ -3358,6 +3376,13 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (!dev || b43_status(dev) < B43_STAT_INITIALIZED) goto out_unlock; + if (dev->fw.pcm_request_failed) { + /* We don't have firmware for the crypto engine. + * Must use software-crypto. */ + err = -EOPNOTSUPP; + goto out_unlock; + } + err = -EINVAL; switch (key->alg) { case ALG_WEP: -- cgit v1.2.3-70-g09d2 From afa83e239af58a93eddd10a7a43ac5618884db15 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Mon, 19 May 2008 23:51:37 +0200 Subject: b43: Add panic reason code that doesn't trigger restart Add a firmware panic reason code that doesn't trigger a restart. This is useful for firmware debugging and avoiding endless restart loops. We can use FWPANIC_DIE to halt the firmware at a well defined point. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/b43.h | 9 +++++++++ drivers/net/wireless/b43/main.c | 39 +++++++++++++++++++++++++++++++-------- 2 files changed, 40 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index f588dfa9c1d..f0041750355 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -422,12 +422,21 @@ enum { B43_IRQ_RFKILL | \ B43_IRQ_TX_OK) +/* The firmware register to fetch the debug-IRQ reason from. */ +#define B43_DEBUGIRQ_REASON_REG 63 /* Debug-IRQ reasons. */ #define B43_DEBUGIRQ_PANIC 0 /* The firmware panic'ed */ #define B43_DEBUGIRQ_DUMP_SHM 1 /* Dump shared SHM */ #define B43_DEBUGIRQ_DUMP_REGS 2 /* Dump the microcode registers */ #define B43_DEBUGIRQ_ACK 0xFFFF /* The host writes that to ACK the IRQ */ +/* The firmware register to fetch the panic reason from. */ +#define B43_FWPANIC_REASON_REG 3 +/* Firmware panic reason codes */ +#define B43_FWPANIC_DIE 0 /* Firmware died. Don't auto-restart it. */ +#define B43_FWPANIC_RESTART 1 /* Firmware died. Schedule a controller reset. */ + + /* Device specific rate values. * The actual values defined here are (rate_in_mbps * 2). * Some code depends on this. Don't change it. */ diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 6011747bb3b..e1dfb407467 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1662,6 +1662,30 @@ static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int) b43dbg(dev->wl, "Set beacon interval to %u\n", beacon_int); } +static void b43_handle_firmware_panic(struct b43_wldev *dev) +{ + u16 reason; + + /* Read the register that contains the reason code for the panic. */ + reason = b43_shm_read16(dev, B43_SHM_SCRATCH, B43_FWPANIC_REASON_REG); + b43err(dev->wl, "Whoopsy, firmware panic! Reason: %u\n", reason); + + switch (reason) { + default: + b43dbg(dev->wl, "The panic reason is unknown.\n"); + /* fallthrough */ + case B43_FWPANIC_DIE: + /* Do not restart the controller or firmware. + * The device is nonfunctional from now on. + * Restarting would result in this panic to trigger again, + * so we avoid that recursion. */ + break; + case B43_FWPANIC_RESTART: + b43_controller_restart(dev, "Microcode panic"); + break; + } +} + static void handle_irq_ucode_debug(struct b43_wldev *dev) { unsigned int i, cnt; @@ -1672,15 +1696,12 @@ static void handle_irq_ucode_debug(struct b43_wldev *dev) if (!dev->fw.opensource) return; - /* Microcode register 63 contains the debug-IRQ reason. */ - reason = b43_shm_read16(dev, B43_SHM_SCRATCH, 63); + /* Read the register that contains the reason code for this IRQ. */ + reason = b43_shm_read16(dev, B43_SHM_SCRATCH, B43_DEBUGIRQ_REASON_REG); + switch (reason) { case B43_DEBUGIRQ_PANIC: - /* The reason for the panic is in register 3. */ - reason = b43_shm_read16(dev, B43_SHM_SCRATCH, 3); - b43err(dev->wl, "Whoopsy, the microcode panic'ed! Reason: %u\n", - reason); - b43_controller_restart(dev, "Microcode panic"); + b43_handle_firmware_panic(dev); break; case B43_DEBUGIRQ_DUMP_SHM: if (!B43_DEBUG) @@ -1721,7 +1742,9 @@ static void handle_irq_ucode_debug(struct b43_wldev *dev) reason); } out: - b43_shm_write16(dev, B43_SHM_SCRATCH, 63, B43_DEBUGIRQ_ACK); + /* Acknowledge the debug-IRQ, so the firmware can continue. */ + b43_shm_write16(dev, B43_SHM_SCRATCH, + B43_DEBUGIRQ_REASON_REG, B43_DEBUGIRQ_ACK); } /* Interrupt handler bottom-half */ -- cgit v1.2.3-70-g09d2 From 53c068566dde708cb28a4dfc06ae3d7fd7434397 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Tue, 20 May 2008 00:24:36 +0200 Subject: b43: Add firmware markers support This adds support for firmware markers. With firmware markers it's easily possible to check whether the firmware runs some codepath or not. The driver will throw a message when the firmware executes a MARKER(x). Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/b43.h | 5 +++++ drivers/net/wireless/b43/main.c | 13 ++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index f0041750355..e919189919b 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -428,8 +428,13 @@ enum { #define B43_DEBUGIRQ_PANIC 0 /* The firmware panic'ed */ #define B43_DEBUGIRQ_DUMP_SHM 1 /* Dump shared SHM */ #define B43_DEBUGIRQ_DUMP_REGS 2 /* Dump the microcode registers */ +#define B43_DEBUGIRQ_MARKER 3 /* A "marker" was thrown by the firmware. */ #define B43_DEBUGIRQ_ACK 0xFFFF /* The host writes that to ACK the IRQ */ +/* The firmware register that contains the "marker" line. */ +#define B43_MARKER_ID_REG 2 +#define B43_MARKER_LINE_REG 3 + /* The firmware register to fetch the panic reason from. */ #define B43_FWPANIC_REASON_REG 3 /* Firmware panic reason codes */ diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index e1dfb407467..cbb317bb348 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1689,7 +1689,7 @@ static void b43_handle_firmware_panic(struct b43_wldev *dev) static void handle_irq_ucode_debug(struct b43_wldev *dev) { unsigned int i, cnt; - u16 reason; + u16 reason, marker_id, marker_line; __le16 *buf; /* The proprietary firmware doesn't have this IRQ. */ @@ -1737,6 +1737,17 @@ static void handle_irq_ucode_debug(struct b43_wldev *dev) } printk("\n"); break; + case B43_DEBUGIRQ_MARKER: + if (!B43_DEBUG) + break; /* Only with driver debugging enabled. */ + marker_id = b43_shm_read16(dev, B43_SHM_SCRATCH, + B43_MARKER_ID_REG); + marker_line = b43_shm_read16(dev, B43_SHM_SCRATCH, + B43_MARKER_LINE_REG); + b43info(dev->wl, "The firmware just executed the MARKER(%u) " + "at line number %u\n", + marker_id, marker_line); + break; default: b43dbg(dev->wl, "Debug-IRQ triggered for unknown reason: %u\n", reason); -- cgit v1.2.3-70-g09d2 From 0abbc78a0137fee60ef092f0b20a3d3d7e7e0cc2 Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Tue, 20 May 2008 16:27:17 +0200 Subject: x86, aperture_64: use symbolic constants Factor-out common aperture_valid code. Signed-off-by: Pavel Machek Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner --- arch/x86/kernel/aperture_64.c | 23 +---------------------- drivers/char/agp/amd64-agp.c | 22 ++++------------------ include/asm-x86/gart.h | 24 ++++++++++++++++++++++++ 3 files changed, 29 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/arch/x86/kernel/aperture_64.c b/arch/x86/kernel/aperture_64.c index 02f4dbaa4df..5373f7834d8 100644 --- a/arch/x86/kernel/aperture_64.c +++ b/arch/x86/kernel/aperture_64.c @@ -109,27 +109,6 @@ static u32 __init allocate_aperture(void) return (u32)__pa(p); } -static int __init aperture_valid(u64 aper_base, u32 aper_size, u32 min_size) -{ - if (!aper_base) - return 0; - - if (aper_base + aper_size > 0x100000000UL) { - printk(KERN_ERR "Aperture beyond 4GB. Ignoring.\n"); - return 0; - } - if (e820_any_mapped(aper_base, aper_base + aper_size, E820_RAM)) { - printk(KERN_ERR "Aperture pointing to e820 RAM. Ignoring.\n"); - return 0; - } - if (aper_size < min_size) { - printk(KERN_ERR "Aperture too small (%d MB) than (%d MB)\n", - aper_size>>20, min_size>>20); - return 0; - } - - return 1; -} /* Find a PCI capability */ static __u32 __init find_cap(int bus, int slot, int func, int cap) @@ -344,7 +323,7 @@ out: if (gart_fix_e820 && !fix && aper_enabled) { if (!e820_all_mapped(aper_base, aper_base + aper_size, E820_RESERVED)) { - /* reserved it, so we can resuse it in second kernel */ + /* reserve it, so we can reuse it in second kernel */ printk(KERN_INFO "update e820 for GART\n"); add_memory_region(aper_base, aper_size, E820_RESERVED); update_e820(); diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index e3c7ea07f57..f5af65ac8c7 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c @@ -228,24 +228,10 @@ static const struct agp_bridge_driver amd_8151_driver = { }; /* Some basic sanity checks for the aperture. */ -static int __devinit aperture_valid(u64 aper, u32 size) +static int __devinit agp_aperture_valid(u64 aper, u32 size) { - if (aper == 0) { - printk(KERN_ERR PFX "No aperture\n"); + if (!aperture_valid(aper, size, 32*1024*1024)) return 0; - } - if ((u64)aper + size > 0x100000000ULL) { - printk(KERN_ERR PFX "Aperture out of bounds\n"); - return 0; - } - if (e820_any_mapped(aper, aper + size, E820_RAM)) { - printk(KERN_ERR PFX "Aperture pointing to RAM\n"); - return 0; - } - if (size < 32*1024*1024) { - printk(KERN_ERR PFX "Aperture too small (%d MB)\n", size>>20); - return 0; - } /* Request the Aperture. This catches cases when someone else already put a mapping in there - happens with some very broken BIOS @@ -282,7 +268,7 @@ static __devinit int fix_northbridge(struct pci_dev *nb, struct pci_dev *agp, nb_order = (nb_order >> 1) & 7; pci_read_config_dword(nb, AMD64_GARTAPERTUREBASE, &nb_base); nb_aper = nb_base << 25; - if (aperture_valid(nb_aper, (32*1024*1024)< + extern void pci_iommu_shutdown(void); extern void no_iommu_init(void); extern int force_iommu, no_iommu; @@ -69,4 +71,26 @@ static inline void enable_gart_translation(struct pci_dev *dev, u64 addr) pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, ctl); } +static inline int aperture_valid(u64 aper_base, u32 aper_size, u32 min_size) +{ + if (!aper_base) + return 0; + + if (aper_base + aper_size > 0x100000000ULL) { + printk(KERN_ERR "Aperture beyond 4GB. Ignoring.\n"); + return 0; + } + if (e820_any_mapped(aper_base, aper_base + aper_size, E820_RAM)) { + printk(KERN_ERR "Aperture pointing to e820 RAM. Ignoring.\n"); + return 0; + } + if (aper_size < min_size) { + printk(KERN_ERR "Aperture too small (%d MB) than (%d MB)\n", + aper_size>>20, min_size>>20); + return 0; + } + + return 1; +} + #endif -- cgit v1.2.3-70-g09d2 From b1fb1f280d0969f47d4ef19334120f5c34e36080 Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Wed, 21 May 2008 18:56:16 -0700 Subject: cxgb3 - Fix dma mapping error path Take potential dma mapping errors in account. Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/sge.c | 53 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index 796eb305cdc..0741deb86ca 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c @@ -376,13 +376,16 @@ static void free_rx_bufs(struct pci_dev *pdev, struct sge_fl *q) * Add a buffer of the given length to the supplied HW and SW Rx * descriptors. */ -static inline void add_one_rx_buf(void *va, unsigned int len, - struct rx_desc *d, struct rx_sw_desc *sd, - unsigned int gen, struct pci_dev *pdev) +static inline int add_one_rx_buf(void *va, unsigned int len, + struct rx_desc *d, struct rx_sw_desc *sd, + unsigned int gen, struct pci_dev *pdev) { dma_addr_t mapping; mapping = pci_map_single(pdev, va, len, PCI_DMA_FROMDEVICE); + if (unlikely(pci_dma_mapping_error(mapping))) + return -ENOMEM; + pci_unmap_addr_set(sd, dma_addr, mapping); d->addr_lo = cpu_to_be32(mapping); @@ -390,6 +393,7 @@ static inline void add_one_rx_buf(void *va, unsigned int len, wmb(); d->len_gen = cpu_to_be32(V_FLD_GEN1(gen)); d->gen2 = cpu_to_be32(V_FLD_GEN2(gen)); + return 0; } static int alloc_pg_chunk(struct sge_fl *q, struct rx_sw_desc *sd, gfp_t gfp) @@ -424,13 +428,16 @@ static int alloc_pg_chunk(struct sge_fl *q, struct rx_sw_desc *sd, gfp_t gfp) * allocated with the supplied gfp flags. The caller must assure that * @n does not exceed the queue's capacity. */ -static void refill_fl(struct adapter *adap, struct sge_fl *q, int n, gfp_t gfp) +static int refill_fl(struct adapter *adap, struct sge_fl *q, int n, gfp_t gfp) { void *buf_start; struct rx_sw_desc *sd = &q->sdesc[q->pidx]; struct rx_desc *d = &q->desc[q->pidx]; + unsigned int count = 0; while (n--) { + int err; + if (q->use_pages) { if (unlikely(alloc_pg_chunk(q, sd, gfp))) { nomem: q->alloc_failed++; @@ -447,8 +454,16 @@ nomem: q->alloc_failed++; buf_start = skb->data; } - add_one_rx_buf(buf_start, q->buf_size, d, sd, q->gen, - adap->pdev); + err = add_one_rx_buf(buf_start, q->buf_size, d, sd, q->gen, + adap->pdev); + if (unlikely(err)) { + if (!q->use_pages) { + kfree_skb(sd->skb); + sd->skb = NULL; + } + break; + } + d++; sd++; if (++q->pidx == q->size) { @@ -458,9 +473,13 @@ nomem: q->alloc_failed++; d = q->desc; } q->credits++; + count++; } wmb(); - t3_write_reg(adap, A_SG_KDOORBELL, V_EGRCNTX(q->cntxt_id)); + if (likely(count)) + t3_write_reg(adap, A_SG_KDOORBELL, V_EGRCNTX(q->cntxt_id)); + + return count; } static inline void __refill_fl(struct adapter *adap, struct sge_fl *fl) @@ -2618,7 +2637,7 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, int irq_vec_idx, const struct qset_params *p, int ntxq, struct net_device *dev) { - int i, ret = -ENOMEM; + int i, avail, ret = -ENOMEM; struct sge_qset *q = &adapter->sge.qs[id]; init_qset_cntxt(q, id); @@ -2741,9 +2760,19 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, q->adap = adapter; q->netdev = dev; t3_update_qset_coalesce(q, p); + avail = refill_fl(adapter, &q->fl[0], q->fl[0].size, GFP_KERNEL); + if (!avail) { + CH_ALERT(adapter, "free list queue 0 initialization failed\n"); + goto err; + } + if (avail < q->fl[0].size) + CH_WARN(adapter, "free list queue 0 enabled with %d credits\n", + avail); - refill_fl(adapter, &q->fl[0], q->fl[0].size, GFP_KERNEL); - refill_fl(adapter, &q->fl[1], q->fl[1].size, GFP_KERNEL); + avail = refill_fl(adapter, &q->fl[1], q->fl[1].size, GFP_KERNEL); + if (avail < q->fl[1].size) + CH_WARN(adapter, "free list queue 1 enabled with %d credits\n", + avail); refill_rspq(adapter, &q->rspq, q->rspq.size - 1); t3_write_reg(adapter, A_SG_GTS, V_RSPQ(q->rspq.cntxt_id) | @@ -2752,9 +2781,9 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, mod_timer(&q->tx_reclaim_timer, jiffies + TX_RECLAIM_PERIOD); return 0; - err_unlock: +err_unlock: spin_unlock_irq(&adapter->sge.reg_lock); - err: +err: t3_free_qset(adapter, q); return ret; } -- cgit v1.2.3-70-g09d2 From 7385ecf339c504933a98581c2056d83b69b2a82b Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Wed, 21 May 2008 18:56:21 -0700 Subject: cxgb3 - Add page support to jumbo frame Rx queue Add page support to Jumbo frame Rx queues. Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/adapter.h | 4 ++ drivers/net/cxgb3/sge.c | 115 ++++++++++++++++++++++++++++++-------------- 2 files changed, 84 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h index acebe431d06..263e4faf45e 100644 --- a/drivers/net/cxgb3/adapter.h +++ b/drivers/net/cxgb3/adapter.h @@ -92,6 +92,7 @@ struct sge_fl { /* SGE per free-buffer list state */ unsigned int gen; /* free list generation */ struct fl_pg_chunk pg_chunk;/* page chunk cache */ unsigned int use_pages; /* whether FL uses pages or sk_buffs */ + unsigned int order; /* order of page allocations */ struct rx_desc *desc; /* address of HW Rx descriptor ring */ struct rx_sw_desc *sdesc; /* address of SW Rx descriptor ring */ dma_addr_t phys_addr; /* physical address of HW ring start */ @@ -116,12 +117,15 @@ struct sge_rspq { /* state for an SGE response queue */ unsigned int polling; /* is the queue serviced through NAPI? */ unsigned int holdoff_tmr; /* interrupt holdoff timer in 100ns */ unsigned int next_holdoff; /* holdoff time for next interrupt */ + unsigned int rx_recycle_buf; /* whether recycling occurred + within current sop-eop */ struct rsp_desc *desc; /* address of HW response ring */ dma_addr_t phys_addr; /* physical address of the ring */ unsigned int cntxt_id; /* SGE context id for the response q */ spinlock_t lock; /* guards response processing */ struct sk_buff *rx_head; /* offload packet receive queue head */ struct sk_buff *rx_tail; /* offload packet receive queue tail */ + struct sk_buff *pg_skb; /* used to build frag list in napi handler */ unsigned long offload_pkts; unsigned long offload_bundles; diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index 0741deb86ca..3e91be55e19 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c @@ -55,6 +55,9 @@ * directly. */ #define FL0_PG_CHUNK_SIZE 2048 +#define FL0_PG_ORDER 0 +#define FL1_PG_CHUNK_SIZE (PAGE_SIZE > 8192 ? 16384 : 8192) +#define FL1_PG_ORDER (PAGE_SIZE > 8192 ? 0 : 1) #define SGE_RX_DROP_THRES 16 @@ -359,7 +362,7 @@ static void free_rx_bufs(struct pci_dev *pdev, struct sge_fl *q) } if (q->pg_chunk.page) { - __free_page(q->pg_chunk.page); + __free_pages(q->pg_chunk.page, q->order); q->pg_chunk.page = NULL; } } @@ -396,10 +399,11 @@ static inline int add_one_rx_buf(void *va, unsigned int len, return 0; } -static int alloc_pg_chunk(struct sge_fl *q, struct rx_sw_desc *sd, gfp_t gfp) +static int alloc_pg_chunk(struct sge_fl *q, struct rx_sw_desc *sd, gfp_t gfp, + unsigned int order) { if (!q->pg_chunk.page) { - q->pg_chunk.page = alloc_page(gfp); + q->pg_chunk.page = alloc_pages(gfp, order); if (unlikely(!q->pg_chunk.page)) return -ENOMEM; q->pg_chunk.va = page_address(q->pg_chunk.page); @@ -408,7 +412,7 @@ static int alloc_pg_chunk(struct sge_fl *q, struct rx_sw_desc *sd, gfp_t gfp) sd->pg_chunk = q->pg_chunk; q->pg_chunk.offset += q->buf_size; - if (q->pg_chunk.offset == PAGE_SIZE) + if (q->pg_chunk.offset == (PAGE_SIZE << order)) q->pg_chunk.page = NULL; else { q->pg_chunk.va += q->buf_size; @@ -439,7 +443,7 @@ static int refill_fl(struct adapter *adap, struct sge_fl *q, int n, gfp_t gfp) int err; if (q->use_pages) { - if (unlikely(alloc_pg_chunk(q, sd, gfp))) { + if (unlikely(alloc_pg_chunk(q, sd, gfp, q->order))) { nomem: q->alloc_failed++; break; } @@ -484,7 +488,8 @@ nomem: q->alloc_failed++; static inline void __refill_fl(struct adapter *adap, struct sge_fl *fl) { - refill_fl(adap, fl, min(16U, fl->size - fl->credits), GFP_ATOMIC); + refill_fl(adap, fl, min(16U, fl->size - fl->credits), + GFP_ATOMIC | __GFP_COMP); } /** @@ -759,19 +764,22 @@ use_orig_buf: * that are page chunks rather than sk_buffs. */ static struct sk_buff *get_packet_pg(struct adapter *adap, struct sge_fl *fl, - unsigned int len, unsigned int drop_thres) + struct sge_rspq *q, unsigned int len, + unsigned int drop_thres) { - struct sk_buff *skb = NULL; + struct sk_buff *newskb, *skb; struct rx_sw_desc *sd = &fl->sdesc[fl->cidx]; - if (len <= SGE_RX_COPY_THRES) { - skb = alloc_skb(len, GFP_ATOMIC); - if (likely(skb != NULL)) { - __skb_put(skb, len); + newskb = skb = q->pg_skb; + + if (!skb && (len <= SGE_RX_COPY_THRES)) { + newskb = alloc_skb(len, GFP_ATOMIC); + if (likely(newskb != NULL)) { + __skb_put(newskb, len); pci_dma_sync_single_for_cpu(adap->pdev, pci_unmap_addr(sd, dma_addr), len, PCI_DMA_FROMDEVICE); - memcpy(skb->data, sd->pg_chunk.va, len); + memcpy(newskb->data, sd->pg_chunk.va, len); pci_dma_sync_single_for_device(adap->pdev, pci_unmap_addr(sd, dma_addr), len, PCI_DMA_FROMDEVICE); @@ -780,14 +788,16 @@ static struct sk_buff *get_packet_pg(struct adapter *adap, struct sge_fl *fl, recycle: fl->credits--; recycle_rx_buf(adap, fl, fl->cidx); - return skb; + q->rx_recycle_buf++; + return newskb; } - if (unlikely(fl->credits <= drop_thres)) + if (unlikely(q->rx_recycle_buf || (!skb && fl->credits <= drop_thres))) goto recycle; - skb = alloc_skb(SGE_RX_PULL_LEN, GFP_ATOMIC); - if (unlikely(!skb)) { + if (!skb) + newskb = alloc_skb(SGE_RX_PULL_LEN, GFP_ATOMIC); + if (unlikely(!newskb)) { if (!drop_thres) return NULL; goto recycle; @@ -795,21 +805,29 @@ recycle: pci_unmap_single(adap->pdev, pci_unmap_addr(sd, dma_addr), fl->buf_size, PCI_DMA_FROMDEVICE); - __skb_put(skb, SGE_RX_PULL_LEN); - memcpy(skb->data, sd->pg_chunk.va, SGE_RX_PULL_LEN); - skb_fill_page_desc(skb, 0, sd->pg_chunk.page, - sd->pg_chunk.offset + SGE_RX_PULL_LEN, - len - SGE_RX_PULL_LEN); - skb->len = len; - skb->data_len = len - SGE_RX_PULL_LEN; - skb->truesize += skb->data_len; + if (!skb) { + __skb_put(newskb, SGE_RX_PULL_LEN); + memcpy(newskb->data, sd->pg_chunk.va, SGE_RX_PULL_LEN); + skb_fill_page_desc(newskb, 0, sd->pg_chunk.page, + sd->pg_chunk.offset + SGE_RX_PULL_LEN, + len - SGE_RX_PULL_LEN); + newskb->len = len; + newskb->data_len = len - SGE_RX_PULL_LEN; + } else { + skb_fill_page_desc(newskb, skb_shinfo(newskb)->nr_frags, + sd->pg_chunk.page, + sd->pg_chunk.offset, len); + newskb->len += len; + newskb->data_len += len; + } + newskb->truesize += newskb->data_len; fl->credits--; /* * We do not refill FLs here, we let the caller do it to overlap a * prefetch. */ - return skb; + return newskb; } /** @@ -1966,6 +1984,12 @@ static inline int is_new_response(const struct rsp_desc *r, return (r->intr_gen & F_RSPD_GEN2) == q->gen; } +static inline void clear_rspq_bufstate(struct sge_rspq * const q) +{ + q->pg_skb = NULL; + q->rx_recycle_buf = 0; +} + #define RSPD_GTS_MASK (F_RSPD_TXQ0_GTS | F_RSPD_TXQ1_GTS) #define RSPD_CTRL_MASK (RSPD_GTS_MASK | \ V_RSPD_TXQ0_CR(M_RSPD_TXQ0_CR) | \ @@ -2003,10 +2027,11 @@ static int process_responses(struct adapter *adap, struct sge_qset *qs, q->next_holdoff = q->holdoff_tmr; while (likely(budget_left && is_new_response(r, q))) { - int eth, ethpad = 2; + int packet_complete, eth, ethpad = 2; struct sk_buff *skb = NULL; u32 len, flags = ntohl(r->flags); - __be32 rss_hi = *(const __be32 *)r, rss_lo = r->rss_hdr.rss_hash_val; + __be32 rss_hi = *(const __be32 *)r, + rss_lo = r->rss_hdr.rss_hash_val; eth = r->rss_hdr.opcode == CPL_RX_PKT; @@ -2044,8 +2069,11 @@ no_mem: #endif __refill_fl(adap, fl); - skb = get_packet_pg(adap, fl, G_RSPD_LEN(len), - eth ? SGE_RX_DROP_THRES : 0); + skb = get_packet_pg(adap, fl, q, + G_RSPD_LEN(len), + eth ? + SGE_RX_DROP_THRES : 0); + q->pg_skb = skb; } else skb = get_packet(adap, fl, G_RSPD_LEN(len), eth ? SGE_RX_DROP_THRES : 0); @@ -2079,7 +2107,11 @@ no_mem: q->credits = 0; } - if (likely(skb != NULL)) { + packet_complete = flags & + (F_RSPD_EOP | F_RSPD_IMM_DATA_VALID | + F_RSPD_ASYNC_NOTIF); + + if (skb != NULL && packet_complete) { if (eth) rx_eth(adap, q, skb, ethpad); else { @@ -2091,6 +2123,9 @@ no_mem: offload_skbs, ngathered); } + + if (flags & F_RSPD_EOP) + clear_rspq_bufstate(q); } --budget_left; } @@ -2706,10 +2741,18 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, #else q->fl[0].buf_size = SGE_RX_SM_BUF_SIZE + sizeof(struct cpl_rx_data); #endif - q->fl[0].use_pages = FL0_PG_CHUNK_SIZE > 0; +#if FL1_PG_CHUNK_SIZE > 0 + q->fl[1].buf_size = FL1_PG_CHUNK_SIZE; +#else q->fl[1].buf_size = is_offload(adapter) ? (16 * 1024) - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) : MAX_FRAME_SIZE + 2 + sizeof(struct cpl_rx_pkt); +#endif + + q->fl[0].use_pages = FL0_PG_CHUNK_SIZE > 0; + q->fl[1].use_pages = FL1_PG_CHUNK_SIZE > 0; + q->fl[0].order = FL0_PG_ORDER; + q->fl[1].order = FL1_PG_ORDER; spin_lock_irq(&adapter->sge.reg_lock); @@ -2760,7 +2803,8 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, q->adap = adapter; q->netdev = dev; t3_update_qset_coalesce(q, p); - avail = refill_fl(adapter, &q->fl[0], q->fl[0].size, GFP_KERNEL); + avail = refill_fl(adapter, &q->fl[0], q->fl[0].size, + GFP_KERNEL | __GFP_COMP); if (!avail) { CH_ALERT(adapter, "free list queue 0 initialization failed\n"); goto err; @@ -2769,7 +2813,8 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, CH_WARN(adapter, "free list queue 0 enabled with %d credits\n", avail); - avail = refill_fl(adapter, &q->fl[1], q->fl[1].size, GFP_KERNEL); + avail = refill_fl(adapter, &q->fl[1], q->fl[1].size, + GFP_KERNEL | __GFP_COMP); if (avail < q->fl[1].size) CH_WARN(adapter, "free list queue 1 enabled with %d credits\n", avail); @@ -2905,7 +2950,7 @@ void t3_sge_prep(struct adapter *adap, struct sge_params *p) q->coalesce_usecs = 5; q->rspq_size = 1024; q->fl_size = 1024; - q->jumbo_size = 512; + q->jumbo_size = 512; q->txq_size[TXQ_ETH] = 1024; q->txq_size[TXQ_OFLD] = 1024; q->txq_size[TXQ_CTRL] = 256; -- cgit v1.2.3-70-g09d2 From b47385bd4f67481a7dbfcf1b4b82e9a67ecb846c Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Wed, 21 May 2008 18:56:26 -0700 Subject: cxgb3 - Add LRO support Add LRO support. Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 1 + drivers/net/cxgb3/adapter.h | 14 +++ drivers/net/cxgb3/common.h | 1 + drivers/net/cxgb3/cxgb3_ioctl.h | 1 + drivers/net/cxgb3/cxgb3_main.c | 19 ++++ drivers/net/cxgb3/sge.c | 233 +++++++++++++++++++++++++++++++++++++--- drivers/net/cxgb3/t3_cpl.h | 11 ++ 7 files changed, 268 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 9f6cc8a5607..daeb23d7fec 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2409,6 +2409,7 @@ config CHELSIO_T3 tristate "Chelsio Communications T3 10Gb Ethernet support" depends on PCI select FW_LOADER + select INET_LRO help This driver supports Chelsio T3-based gigabit and 10Gb Ethernet adapters. diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h index 263e4faf45e..271140433b0 100644 --- a/drivers/net/cxgb3/adapter.h +++ b/drivers/net/cxgb3/adapter.h @@ -42,6 +42,7 @@ #include #include #include +#include #include "t3cdev.h" #include @@ -173,16 +174,29 @@ enum { /* per port SGE statistics */ SGE_PSTAT_TX_CSUM, /* # of TX checksum offloads */ SGE_PSTAT_VLANEX, /* # of VLAN tag extractions */ SGE_PSTAT_VLANINS, /* # of VLAN tag insertions */ + SGE_PSTAT_LRO_AGGR, /* # of page chunks added to LRO sessions */ + SGE_PSTAT_LRO_FLUSHED, /* # of flushed LRO sessions */ + SGE_PSTAT_LRO_NO_DESC, /* # of overflown LRO sessions */ SGE_PSTAT_MAX /* must be last */ }; +#define T3_MAX_LRO_SES 8 +#define T3_MAX_LRO_MAX_PKTS 64 + struct sge_qset { /* an SGE queue set */ struct adapter *adap; struct napi_struct napi; struct sge_rspq rspq; struct sge_fl fl[SGE_RXQ_PER_SET]; struct sge_txq txq[SGE_TXQ_PER_SET]; + struct net_lro_mgr lro_mgr; + struct net_lro_desc lro_desc[T3_MAX_LRO_SES]; + struct skb_frag_struct *lro_frag_tbl; + int lro_nfrags; + int lro_enabled; + int lro_frag_len; + void *lro_va; struct net_device *netdev; unsigned long txq_stopped; /* which Tx queues are stopped */ struct timer_list tx_reclaim_timer; /* reclaims TX buffers */ diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h index 579bee42a5c..d444f5881f5 100644 --- a/drivers/net/cxgb3/common.h +++ b/drivers/net/cxgb3/common.h @@ -351,6 +351,7 @@ struct tp_params { struct qset_params { /* SGE queue set parameters */ unsigned int polling; /* polling/interrupt service for rspq */ + unsigned int lro; /* large receive offload */ unsigned int coalesce_usecs; /* irq coalescing timer */ unsigned int rspq_size; /* # of entries in response queue */ unsigned int fl_size; /* # of entries in regular free list */ diff --git a/drivers/net/cxgb3/cxgb3_ioctl.h b/drivers/net/cxgb3/cxgb3_ioctl.h index 0a82fcddf2d..68200a14065 100644 --- a/drivers/net/cxgb3/cxgb3_ioctl.h +++ b/drivers/net/cxgb3/cxgb3_ioctl.h @@ -90,6 +90,7 @@ struct ch_qset_params { int32_t fl_size[2]; int32_t intr_lat; int32_t polling; + int32_t lro; int32_t cong_thres; }; diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 3a312721679..5447f3e60f0 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -1212,6 +1212,9 @@ static char stats_strings[][ETH_GSTRING_LEN] = { "VLANinsertions ", "TxCsumOffload ", "RxCsumGood ", + "LroAggregated ", + "LroFlushed ", + "LroNoDesc ", "RxDrops ", "CheckTXEnToggled ", @@ -1340,6 +1343,9 @@ static void get_stats(struct net_device *dev, struct ethtool_stats *stats, *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_VLANINS); *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_TX_CSUM); *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_RX_CSUM_GOOD); + *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_LRO_AGGR); + *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_LRO_FLUSHED); + *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_LRO_NO_DESC); *data++ = s->rx_cong_drops; *data++ = s->num_toggled; @@ -1558,6 +1564,13 @@ static int set_rx_csum(struct net_device *dev, u32 data) struct port_info *p = netdev_priv(dev); p->rx_csum_offload = data; + if (!data) { + struct adapter *adap = p->adapter; + int i; + + for (i = p->first_qset; i < p->first_qset + p->nqsets; i++) + adap->sge.qs[i].lro_enabled = 0; + } return 0; } @@ -1830,6 +1843,11 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr) } } } + if (t.lro >= 0) { + struct sge_qset *qs = &adapter->sge.qs[t.qset_idx]; + q->lro = t.lro; + qs->lro_enabled = t.lro; + } break; } case CHELSIO_GET_QSET_PARAMS:{ @@ -1849,6 +1867,7 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr) t.fl_size[0] = q->fl_size; t.fl_size[1] = q->jumbo_size; t.polling = q->polling; + t.lro = q->lro; t.intr_lat = q->coalesce_usecs; t.cong_thres = q->cong_thres; diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index 3e91be55e19..a96331c875e 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c @@ -584,6 +584,8 @@ static void t3_reset_qset(struct sge_qset *q) memset(q->txq, 0, sizeof(struct sge_txq) * SGE_TXQ_PER_SET); q->txq_stopped = 0; memset(&q->tx_reclaim_timer, 0, sizeof(q->tx_reclaim_timer)); + kfree(q->lro_frag_tbl); + q->lro_nfrags = q->lro_frag_len = 0; } @@ -796,7 +798,7 @@ recycle: goto recycle; if (!skb) - newskb = alloc_skb(SGE_RX_PULL_LEN, GFP_ATOMIC); + newskb = alloc_skb(SGE_RX_PULL_LEN, GFP_ATOMIC); if (unlikely(!newskb)) { if (!drop_thres) return NULL; @@ -1868,9 +1870,10 @@ static void restart_tx(struct sge_qset *qs) * if it was immediate data in a response. */ static void rx_eth(struct adapter *adap, struct sge_rspq *rq, - struct sk_buff *skb, int pad) + struct sk_buff *skb, int pad, int lro) { struct cpl_rx_pkt *p = (struct cpl_rx_pkt *)(skb->data + pad); + struct sge_qset *qs = rspq_to_qset(rq); struct port_info *pi; skb_pull(skb, sizeof(*p) + pad); @@ -1887,18 +1890,202 @@ static void rx_eth(struct adapter *adap, struct sge_rspq *rq, if (unlikely(p->vlan_valid)) { struct vlan_group *grp = pi->vlan_grp; - rspq_to_qset(rq)->port_stats[SGE_PSTAT_VLANEX]++; + qs->port_stats[SGE_PSTAT_VLANEX]++; if (likely(grp)) - __vlan_hwaccel_rx(skb, grp, ntohs(p->vlan), - rq->polling); + if (lro) + lro_vlan_hwaccel_receive_skb(&qs->lro_mgr, skb, + grp, + ntohs(p->vlan), + p); + else + __vlan_hwaccel_rx(skb, grp, ntohs(p->vlan), + rq->polling); else dev_kfree_skb_any(skb); - } else if (rq->polling) - netif_receive_skb(skb); - else + } else if (rq->polling) { + if (lro) + lro_receive_skb(&qs->lro_mgr, skb, p); + else + netif_receive_skb(skb); + } else netif_rx(skb); } +static inline int is_eth_tcp(u32 rss) +{ + return G_HASHTYPE(ntohl(rss)) == RSS_HASH_4_TUPLE; +} + +/** + * lro_frame_ok - check if an ingress packet is eligible for LRO + * @p: the CPL header of the packet + * + * Returns true if a received packet is eligible for LRO. + * The following conditions must be true: + * - packet is TCP/IP Ethernet II (checked elsewhere) + * - not an IP fragment + * - no IP options + * - TCP/IP checksums are correct + * - the packet is for this host + */ +static inline int lro_frame_ok(const struct cpl_rx_pkt *p) +{ + const struct ethhdr *eh = (struct ethhdr *)(p + 1); + const struct iphdr *ih = (struct iphdr *)(eh + 1); + + return (*((u8 *)p + 1) & 0x90) == 0x10 && p->csum == htons(0xffff) && + eh->h_proto == htons(ETH_P_IP) && ih->ihl == (sizeof(*ih) >> 2); +} + +#define TCP_FLAG_MASK (TCP_FLAG_CWR | TCP_FLAG_ECE | TCP_FLAG_URG |\ + TCP_FLAG_ACK | TCP_FLAG_PSH | TCP_FLAG_RST |\ + TCP_FLAG_SYN | TCP_FLAG_FIN) +#define TSTAMP_WORD ((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |\ + (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP) + +/** + * lro_segment_ok - check if a TCP segment is eligible for LRO + * @tcph: the TCP header of the packet + * + * Returns true if a TCP packet is eligible for LRO. This requires that + * the packet have only the ACK flag set and no TCP options besides + * time stamps. + */ +static inline int lro_segment_ok(const struct tcphdr *tcph) +{ + int optlen; + + if (unlikely((tcp_flag_word(tcph) & TCP_FLAG_MASK) != TCP_FLAG_ACK)) + return 0; + + optlen = (tcph->doff << 2) - sizeof(*tcph); + if (optlen) { + const u32 *opt = (const u32 *)(tcph + 1); + + if (optlen != TCPOLEN_TSTAMP_ALIGNED || + *opt != htonl(TSTAMP_WORD) || !opt[2]) + return 0; + } + return 1; +} + +static int t3_get_lro_header(void **eh, void **iph, void **tcph, + u64 *hdr_flags, void *priv) +{ + const struct cpl_rx_pkt *cpl = priv; + + if (!lro_frame_ok(cpl)) + return -1; + + *eh = (struct ethhdr *)(cpl + 1); + *iph = (struct iphdr *)((struct ethhdr *)*eh + 1); + *tcph = (struct tcphdr *)((struct iphdr *)*iph + 1); + + if (!lro_segment_ok(*tcph)) + return -1; + + *hdr_flags = LRO_IPV4 | LRO_TCP; + return 0; +} + +static int t3_get_skb_header(struct sk_buff *skb, + void **iph, void **tcph, u64 *hdr_flags, + void *priv) +{ + void *eh; + + return t3_get_lro_header(&eh, iph, tcph, hdr_flags, priv); +} + +static int t3_get_frag_header(struct skb_frag_struct *frag, void **eh, + void **iph, void **tcph, u64 *hdr_flags, + void *priv) +{ + return t3_get_lro_header(eh, iph, tcph, hdr_flags, priv); +} + +/** + * lro_add_page - add a page chunk to an LRO session + * @adap: the adapter + * @qs: the associated queue set + * @fl: the free list containing the page chunk to add + * @len: packet length + * @complete: Indicates the last fragment of a frame + * + * Add a received packet contained in a page chunk to an existing LRO + * session. + */ +static void lro_add_page(struct adapter *adap, struct sge_qset *qs, + struct sge_fl *fl, int len, int complete) +{ + struct rx_sw_desc *sd = &fl->sdesc[fl->cidx]; + struct cpl_rx_pkt *cpl; + struct skb_frag_struct *rx_frag = qs->lro_frag_tbl; + int nr_frags = qs->lro_nfrags, frag_len = qs->lro_frag_len; + int offset = 0; + + if (!nr_frags) { + offset = 2 + sizeof(struct cpl_rx_pkt); + qs->lro_va = cpl = sd->pg_chunk.va + 2; + } + + fl->credits--; + + len -= offset; + pci_unmap_single(adap->pdev, pci_unmap_addr(sd, dma_addr), + fl->buf_size, PCI_DMA_FROMDEVICE); + + rx_frag += nr_frags; + rx_frag->page = sd->pg_chunk.page; + rx_frag->page_offset = sd->pg_chunk.offset + offset; + rx_frag->size = len; + frag_len += len; + qs->lro_nfrags++; + qs->lro_frag_len = frag_len; + + if (!complete) + return; + + qs->lro_nfrags = qs->lro_frag_len = 0; + cpl = qs->lro_va; + + if (unlikely(cpl->vlan_valid)) { + struct net_device *dev = qs->netdev; + struct port_info *pi = netdev_priv(dev); + struct vlan_group *grp = pi->vlan_grp; + + if (likely(grp != NULL)) { + lro_vlan_hwaccel_receive_frags(&qs->lro_mgr, + qs->lro_frag_tbl, + frag_len, frag_len, + grp, ntohs(cpl->vlan), + cpl, 0); + return; + } + } + lro_receive_frags(&qs->lro_mgr, qs->lro_frag_tbl, + frag_len, frag_len, cpl, 0); +} + +/** + * init_lro_mgr - initialize a LRO manager object + * @lro_mgr: the LRO manager object + */ +static void init_lro_mgr(struct sge_qset *qs, struct net_lro_mgr *lro_mgr) +{ + lro_mgr->dev = qs->netdev; + lro_mgr->features = LRO_F_NAPI; + lro_mgr->ip_summed = CHECKSUM_UNNECESSARY; + lro_mgr->ip_summed_aggr = CHECKSUM_UNNECESSARY; + lro_mgr->max_desc = T3_MAX_LRO_SES; + lro_mgr->lro_arr = qs->lro_desc; + lro_mgr->get_frag_header = t3_get_frag_header; + lro_mgr->get_skb_header = t3_get_skb_header; + lro_mgr->max_aggr = T3_MAX_LRO_MAX_PKTS; + if (lro_mgr->max_aggr > MAX_SKB_FRAGS) + lro_mgr->max_aggr = MAX_SKB_FRAGS; +} + /** * handle_rsp_cntrl_info - handles control information in a response * @qs: the queue set corresponding to the response @@ -2027,7 +2214,7 @@ static int process_responses(struct adapter *adap, struct sge_qset *qs, q->next_holdoff = q->holdoff_tmr; while (likely(budget_left && is_new_response(r, q))) { - int packet_complete, eth, ethpad = 2; + int packet_complete, eth, ethpad = 2, lro = qs->lro_enabled; struct sk_buff *skb = NULL; u32 len, flags = ntohl(r->flags); __be32 rss_hi = *(const __be32 *)r, @@ -2059,6 +2246,9 @@ no_mem: } else if ((len = ntohl(r->len_cq)) != 0) { struct sge_fl *fl; + if (eth) + lro = qs->lro_enabled && is_eth_tcp(rss_hi); + fl = (len & F_RSPD_FLQ) ? &qs->fl[1] : &qs->fl[0]; if (fl->use_pages) { void *addr = fl->sdesc[fl->cidx].pg_chunk.va; @@ -2068,6 +2258,12 @@ no_mem: prefetch(addr + L1_CACHE_BYTES); #endif __refill_fl(adap, fl); + if (lro > 0) { + lro_add_page(adap, qs, fl, + G_RSPD_LEN(len), + flags & F_RSPD_EOP); + goto next_fl; + } skb = get_packet_pg(adap, fl, q, G_RSPD_LEN(len), @@ -2083,7 +2279,7 @@ no_mem: q->rx_drops++; } else if (unlikely(r->rss_hdr.opcode == CPL_TRACE_PKT)) __skb_pull(skb, 2); - +next_fl: if (++fl->cidx == fl->size) fl->cidx = 0; } else @@ -2113,7 +2309,7 @@ no_mem: if (skb != NULL && packet_complete) { if (eth) - rx_eth(adap, q, skb, ethpad); + rx_eth(adap, q, skb, ethpad, lro); else { q->offload_pkts++; /* Preserve the RSS info in csum & priority */ @@ -2125,12 +2321,17 @@ no_mem: } if (flags & F_RSPD_EOP) - clear_rspq_bufstate(q); + clear_rspq_bufstate(q); } --budget_left; } deliver_partial_bundle(&adap->tdev, q, offload_skbs, ngathered); + lro_flush_all(&qs->lro_mgr); + qs->port_stats[SGE_PSTAT_LRO_AGGR] = qs->lro_mgr.stats.aggregated; + qs->port_stats[SGE_PSTAT_LRO_FLUSHED] = qs->lro_mgr.stats.flushed; + qs->port_stats[SGE_PSTAT_LRO_NO_DESC] = qs->lro_mgr.stats.no_desc; + if (sleeping) check_ring_db(adap, qs, sleeping); @@ -2674,6 +2875,7 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, { int i, avail, ret = -ENOMEM; struct sge_qset *q = &adapter->sge.qs[id]; + struct net_lro_mgr *lro_mgr = &q->lro_mgr; init_qset_cntxt(q, id); init_timer(&q->tx_reclaim_timer); @@ -2754,6 +2956,10 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, q->fl[0].order = FL0_PG_ORDER; q->fl[1].order = FL1_PG_ORDER; + q->lro_frag_tbl = kcalloc(MAX_FRAME_SIZE / FL1_PG_CHUNK_SIZE + 1, + sizeof(struct skb_frag_struct), + GFP_KERNEL); + q->lro_nfrags = q->lro_frag_len = 0; spin_lock_irq(&adapter->sge.reg_lock); /* FL threshold comparison uses < */ @@ -2803,6 +3009,9 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, q->adap = adapter; q->netdev = dev; t3_update_qset_coalesce(q, p); + + init_lro_mgr(q, lro_mgr); + avail = refill_fl(adapter, &q->fl[0], q->fl[0].size, GFP_KERNEL | __GFP_COMP); if (!avail) { diff --git a/drivers/net/cxgb3/t3_cpl.h b/drivers/net/cxgb3/t3_cpl.h index b7a1a310dfd..a666c5d51cc 100644 --- a/drivers/net/cxgb3/t3_cpl.h +++ b/drivers/net/cxgb3/t3_cpl.h @@ -174,6 +174,13 @@ enum { /* TCP congestion control algorithms */ CONG_ALG_HIGHSPEED }; +enum { /* RSS hash type */ + RSS_HASH_NONE = 0, + RSS_HASH_2_TUPLE = 1, + RSS_HASH_4_TUPLE = 2, + RSS_HASH_TCPV6 = 3 +}; + union opcode_tid { __be32 opcode_tid; __u8 opcode; @@ -184,6 +191,10 @@ union opcode_tid { #define G_OPCODE(x) (((x) >> S_OPCODE) & 0xFF) #define G_TID(x) ((x) & 0xFFFFFF) +#define S_HASHTYPE 22 +#define M_HASHTYPE 0x3 +#define G_HASHTYPE(x) (((x) >> S_HASHTYPE) & M_HASHTYPE) + /* tid is assumed to be 24-bits */ #define MK_OPCODE_TID(opcode, tid) (V_OPCODE(opcode) | (tid)) -- cgit v1.2.3-70-g09d2 From d63ddcec20f59e78212aeaf5144e9652c0097211 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 21 May 2008 01:34:30 +0100 Subject: misc drivers/net endianness noise Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/3c509.c | 15 +++++++-------- drivers/net/atlx/atl1.c | 2 +- drivers/net/usb/catc.c | 5 ++++- drivers/net/usb/rndis_host.c | 4 ++-- drivers/net/wireless/zd1211rw/zd_mac.c | 2 +- drivers/net/wireless/zd1211rw/zd_usb.c | 2 +- 6 files changed, 16 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index e6c545fe5f5..87d8795823d 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -413,7 +413,7 @@ static int __devinit el3_pnp_probe(struct pnp_dev *pdev, { short i; int ioaddr, irq, if_port; - u16 phys_addr[3]; + __be16 phys_addr[3]; struct net_device *dev = NULL; int err; @@ -605,7 +605,7 @@ static int __init el3_mca_probe(struct device *device) short i; int ioaddr, irq, if_port; - u16 phys_addr[3]; + __be16 phys_addr[3]; struct net_device *dev = NULL; u_char pos4, pos5; struct mca_device *mdev = to_mca_device(device); @@ -635,14 +635,13 @@ static int __init el3_mca_probe(struct device *device) printk(KERN_DEBUG "3c529: irq %d ioaddr 0x%x ifport %d\n", irq, ioaddr, if_port); } EL3WINDOW(0); - for (i = 0; i < 3; i++) { - phys_addr[i] = htons(read_eeprom(ioaddr, i)); - } + for (i = 0; i < 3; i++) + phys_addr[i] = htons(read_eeprom(ioaddr, i)); dev = alloc_etherdev(sizeof (struct el3_private)); if (dev == NULL) { - release_region(ioaddr, EL3_IO_EXTENT); - return -ENOMEM; + release_region(ioaddr, EL3_IO_EXTENT); + return -ENOMEM; } netdev_boot_setup_check(dev); @@ -668,7 +667,7 @@ static int __init el3_eisa_probe (struct device *device) { short i; int ioaddr, irq, if_port; - u16 phys_addr[3]; + __be16 phys_addr[3]; struct net_device *dev = NULL; struct eisa_device *edev; int err; diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index 9c2394d4942..6e4c80d41b0 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -2135,7 +2135,7 @@ static int atl1_tso(struct atl1_adapter *adapter, struct sk_buff *skb, return -1; } - if (skb->protocol == ntohs(ETH_P_IP)) { + if (skb->protocol == htons(ETH_P_IP)) { struct iphdr *iph = ip_hdr(skb); real_len = (((unsigned char *)iph - skb->data) + diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c index 76752d84a30..22c17bbacb6 100644 --- a/drivers/net/usb/catc.c +++ b/drivers/net/usb/catc.c @@ -423,7 +423,10 @@ static int catc_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev) catc->tx_ptr = (((catc->tx_ptr - 1) >> 6) + 1) << 6; tx_buf = catc->tx_buf[catc->tx_idx] + catc->tx_ptr; - *((u16*)tx_buf) = (catc->is_f5u011) ? cpu_to_be16((u16)skb->len) : cpu_to_le16((u16)skb->len); + if (catc->is_f5u011) + *(__be16 *)tx_buf = cpu_to_be16(skb->len); + else + *(__le16 *)tx_buf = cpu_to_le16(skb->len); skb_copy_from_linear_data(skb, tx_buf + 2, skb->len); catc->tx_ptr += skb->len + 2; diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c index 21a7785cb8b..3969b7a2b8e 100644 --- a/drivers/net/usb/rndis_host.c +++ b/drivers/net/usb/rndis_host.c @@ -283,8 +283,8 @@ generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags) struct rndis_set_c *set_c; struct rndis_halt *halt; } u; - u32 tmp, phym_unspec; - __le32 *phym; + u32 tmp; + __le32 phym_unspec, *phym; int reply_len; unsigned char *bp; diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 0c736735e21..c99d4a4fde0 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -807,7 +807,7 @@ void zd_process_intr(struct work_struct *work) u16 int_status; struct zd_mac *mac = container_of(work, struct zd_mac, process_intr); - int_status = le16_to_cpu(*(u16 *)(mac->intr_buffer+4)); + int_status = le16_to_cpu(*(__le16 *)(mac->intr_buffer+4)); if (int_status & INT_CFG_NEXT_BCN) { if (net_ratelimit()) dev_dbg_f(zd_mac_dev(mac), "INT_CFG_NEXT_BCN\n"); diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 12e24f04ddd..8941f5eb96c 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -342,7 +342,7 @@ static inline void handle_regs_int(struct urb *urb) ZD_ASSERT(in_interrupt()); spin_lock(&intr->lock); - int_num = le16_to_cpu(*(u16 *)(urb->transfer_buffer+2)); + int_num = le16_to_cpu(*(__le16 *)(urb->transfer_buffer+2)); if (int_num == CR_INTERRUPT) { struct zd_mac *mac = zd_hw_mac(zd_usb_to_hw(urb->context)); memcpy(&mac->intr_buffer, urb->transfer_buffer, -- cgit v1.2.3-70-g09d2 From 5ce0da8f0386b62345312ec8fed31303732f4220 Mon Sep 17 00:00:00 2001 From: Jay Vosburgh Date: Sat, 17 May 2008 21:10:07 -0700 Subject: bonding: Use msecs_to_jiffies, eliminate panic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert bonding to use msecs_to_jiffies instead of doing the math. For the ARP monitor, there was an underflow problem that could result in an infinite loop. The miimon already had that worked around, but this is cleaner. Originally by Nicolas de Pesloüan Jay Vosburgh corrected a math error in the original; Nicolas' original commit message is: When setting arp_interval parameter to a very low value, delta_in_ticks for next arp might become 0, causing an infinite loop. See http://bugzilla.kernel.org/show_bug.cgi?id=10680 Same problem for miimon parameter already fixed, but fix might be enhanced, by using msecs_to_jiffies() function. Signed-off-by: Nicolas de Pesloüan Signed-off-by: Jay Vosburgh Signed-off-by: Jeff Garzik --- drivers/net/bonding/bond_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 50a40e43315..12c71582f4f 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2397,7 +2397,7 @@ void bond_mii_monitor(struct work_struct *work) read_lock(&bond->lock); } - delay = ((bond->params.miimon * HZ) / 1000) ? : 1; + delay = msecs_to_jiffies(bond->params.miimon); read_unlock(&bond->lock); queue_delayed_work(bond->wq, &bond->mii_work, delay); } @@ -2707,7 +2707,7 @@ void bond_loadbalance_arp_mon(struct work_struct *work) read_lock(&bond->lock); - delta_in_ticks = (bond->params.arp_interval * HZ) / 1000; + delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval); if (bond->kill_timers) { goto out; @@ -2837,7 +2837,7 @@ void bond_activebackup_arp_mon(struct work_struct *work) read_lock(&bond->lock); - delta_in_ticks = (bond->params.arp_interval * HZ) / 1000; + delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval); if (bond->kill_timers) { goto out; -- cgit v1.2.3-70-g09d2 From 4b8a9239ee708958ed72722a0e5e0cf34243ad26 Mon Sep 17 00:00:00 2001 From: Jay Vosburgh Date: Sat, 17 May 2008 21:10:08 -0700 Subject: bonding: remove test for IP in ARP monitor Remove bond_has_ip and all references to it. With this change, the ARP monitor will always send ARP probes if the master is up and has at least one slave. If the bond has an IP address, it is used in the ARP probe; if not, the probes are sent with all zeros in the sender's IP address (which is consistent with an RFC 2131 4.4.1 duplicate address probe). This is useful for cases when bonding itself is hidden underneath a layer of virtual devices, e.g., with Xen. Change suggested by Tsutomu Fujii , who included a one-line patch that only affected active-backup mode. Signed-off-by: Jay Vosburgh Signed-off-by: Jeff Garzik --- drivers/net/bonding/bond_main.c | 31 ++++--------------------------- 1 file changed, 4 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 12c71582f4f..e3da1e53b9c 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2426,25 +2426,6 @@ out: return addr; } -static int bond_has_ip(struct bonding *bond) -{ - struct vlan_entry *vlan, *vlan_next; - - if (bond->master_ip) - return 1; - - if (list_empty(&bond->vlan_list)) - return 0; - - list_for_each_entry_safe(vlan, vlan_next, &bond->vlan_list, - vlan_list) { - if (vlan->vlan_ip) - return 1; - } - - return 0; -} - static int bond_has_this_ip(struct bonding *bond, __be32 ip) { struct vlan_entry *vlan, *vlan_next; @@ -2764,8 +2745,7 @@ void bond_loadbalance_arp_mon(struct work_struct *work) * if we don't know our ip yet */ if (time_after_eq(jiffies, slave->dev->trans_start + 2*delta_in_ticks) || - (time_after_eq(jiffies, slave->dev->last_rx + 2*delta_in_ticks) && - bond_has_ip(bond))) { + (time_after_eq(jiffies, slave->dev->last_rx + 2*delta_in_ticks))) { slave->link = BOND_LINK_DOWN; slave->state = BOND_STATE_BACKUP; @@ -2900,8 +2880,7 @@ void bond_activebackup_arp_mon(struct work_struct *work) if ((slave != bond->curr_active_slave) && (!bond->current_arp_slave) && - (time_after_eq(jiffies, slave_last_rx(bond, slave) + 3*delta_in_ticks) && - bond_has_ip(bond))) { + (time_after_eq(jiffies, slave_last_rx(bond, slave) + 3*delta_in_ticks))) { /* a backup slave has gone down; three times * the delta allows the current slave to be * taken out before the backup slave. @@ -2947,8 +2926,7 @@ void bond_activebackup_arp_mon(struct work_struct *work) * if it is up and needs to take over as the curr_active_slave */ if ((time_after_eq(jiffies, slave->dev->trans_start + 2*delta_in_ticks) || - (time_after_eq(jiffies, slave_last_rx(bond, slave) + 2*delta_in_ticks) && - bond_has_ip(bond))) && + (time_after_eq(jiffies, slave_last_rx(bond, slave) + 2*delta_in_ticks))) && time_after_eq(jiffies, slave->jiffies + 2*delta_in_ticks)) { slave->link = BOND_LINK_DOWN; @@ -3000,9 +2978,8 @@ void bond_activebackup_arp_mon(struct work_struct *work) /* the current slave must tx an arp to ensure backup slaves * rx traffic */ - if (slave && bond_has_ip(bond)) { + if (slave && IS_UP(slave->dev)) bond_arp_send_all(bond, slave); - } } /* if we don't have a curr_active_slave, search for the next available -- cgit v1.2.3-70-g09d2 From 0dd646fe0549251e79d6fb03e6773bcc6ccea61f Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Sat, 17 May 2008 21:10:09 -0700 Subject: bonding: Remove redundant argument from bond_create. While we're fixing the bond_create, I hope it's OK to polish it a bit after the fixes. The third argument is NULL at the first caller and is ignored by the second one, so remove it. Signed-off-by: Pavel Emelyanov Acked-by: Jay Vosburgh Signed-off-by: Jeff Garzik --- drivers/net/bonding/bond_main.c | 7 ++----- drivers/net/bonding/bond_sysfs.c | 2 +- drivers/net/bonding/bonding.h | 2 +- 3 files changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index e3da1e53b9c..6b1216455bc 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4848,7 +4848,7 @@ static struct lock_class_key bonding_netdev_xmit_lock_key; * Caller must NOT hold rtnl_lock; we need to release it here before we * set up our sysfs entries. */ -int bond_create(char *name, struct bond_params *params, struct bonding **newbond) +int bond_create(char *name, struct bond_params *params) { struct net_device *bond_dev; struct bonding *bond, *nxt; @@ -4902,9 +4902,6 @@ int bond_create(char *name, struct bond_params *params, struct bonding **newbond lockdep_set_class(&bond_dev->_xmit_lock, &bonding_netdev_xmit_lock_key); - if (newbond) - *newbond = bond_dev->priv; - netif_carrier_off(bond_dev); up_write(&bonding_rwsem); @@ -4950,7 +4947,7 @@ static int __init bonding_init(void) init_rwsem(&bonding_rwsem); for (i = 0; i < max_bonds; i++) { - res = bond_create(NULL, &bonding_defaults, NULL); + res = bond_create(NULL, &bonding_defaults); if (res) goto err; } diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 08f3d396bcd..452a789bf2e 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -122,7 +122,7 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t if (command[0] == '+') { printk(KERN_INFO DRV_NAME ": %s is being created...\n", ifname); - rv = bond_create(ifname, &bonding_defaults, &bond); + rv = bond_create(ifname, &bonding_defaults); if (rv) { printk(KERN_INFO DRV_NAME ": Bond creation failed.\n"); res = rv; diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index a3c74e20aa5..0ce7f4ae920 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -301,7 +301,7 @@ static inline void bond_unset_master_alb_flags(struct bonding *bond) struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr); int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev); -int bond_create(char *name, struct bond_params *params, struct bonding **newbond); +int bond_create(char *name, struct bond_params *params); void bond_destroy(struct bonding *bond); int bond_release_and_destroy(struct net_device *bond_dev, struct net_device *slave_dev); int bond_create_sysfs(void); -- cgit v1.2.3-70-g09d2 From 0883beca7f39ab0c6447af35080e5caaa07418e3 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Sat, 17 May 2008 21:10:10 -0700 Subject: bonding: Relax unneeded _safe lists iterations. Many places either do not modify the list under the list_for_each_xxx, or break out of the loop as soon as the first element is removed. Thus, this _safe iteration just occupies some unneeded .text space and requires an additional variable. Signed-off-by: Pavel Emelyanov Acked-by: Jay Vosburgh Signed-off-by: Jeff Garzik --- drivers/net/bonding/bond_main.c | 31 ++++++++++++++----------------- drivers/net/bonding/bond_sysfs.c | 3 +-- 2 files changed, 15 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 6b1216455bc..5e3b942fb51 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -261,14 +261,14 @@ static int bond_add_vlan(struct bonding *bond, unsigned short vlan_id) */ static int bond_del_vlan(struct bonding *bond, unsigned short vlan_id) { - struct vlan_entry *vlan, *next; + struct vlan_entry *vlan; int res = -ENODEV; dprintk("bond: %s, vlan id %d\n", bond->dev->name, vlan_id); write_lock_bh(&bond->lock); - list_for_each_entry_safe(vlan, next, &bond->vlan_list, vlan_list) { + list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { if (vlan->vlan_id == vlan_id) { list_del(&vlan->vlan_list); @@ -2428,7 +2428,7 @@ out: static int bond_has_this_ip(struct bonding *bond, __be32 ip) { - struct vlan_entry *vlan, *vlan_next; + struct vlan_entry *vlan; if (ip == bond->master_ip) return 1; @@ -2436,8 +2436,7 @@ static int bond_has_this_ip(struct bonding *bond, __be32 ip) if (list_empty(&bond->vlan_list)) return 0; - list_for_each_entry_safe(vlan, vlan_next, &bond->vlan_list, - vlan_list) { + list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { if (ip == vlan->vlan_ip) return 1; } @@ -2479,7 +2478,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) { int i, vlan_id, rv; __be32 *targets = bond->params.arp_targets; - struct vlan_entry *vlan, *vlan_next; + struct vlan_entry *vlan; struct net_device *vlan_dev; struct flowi fl; struct rtable *rt; @@ -2526,8 +2525,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) } vlan_id = 0; - list_for_each_entry_safe(vlan, vlan_next, &bond->vlan_list, - vlan_list) { + list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { vlan_dev = vlan_group_get_device(bond->vlgrp, vlan->vlan_id); if (vlan_dev == rt->u.dst.dev) { vlan_id = vlan->vlan_id; @@ -3477,13 +3475,13 @@ static int bond_inetaddr_event(struct notifier_block *this, unsigned long event, { struct in_ifaddr *ifa = ptr; struct net_device *vlan_dev, *event_dev = ifa->ifa_dev->dev; - struct bonding *bond, *bond_next; - struct vlan_entry *vlan, *vlan_next; + struct bonding *bond; + struct vlan_entry *vlan; if (dev_net(ifa->ifa_dev->dev) != &init_net) return NOTIFY_DONE; - list_for_each_entry_safe(bond, bond_next, &bond_dev_list, bond_list) { + list_for_each_entry(bond, &bond_dev_list, bond_list) { if (bond->dev == event_dev) { switch (event) { case NETDEV_UP: @@ -3500,8 +3498,7 @@ static int bond_inetaddr_event(struct notifier_block *this, unsigned long event, if (list_empty(&bond->vlan_list)) continue; - list_for_each_entry_safe(vlan, vlan_next, &bond->vlan_list, - vlan_list) { + list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { vlan_dev = vlan_group_get_device(bond->vlgrp, vlan->vlan_id); if (vlan_dev == event_dev) { switch (event) { @@ -4851,7 +4848,7 @@ static struct lock_class_key bonding_netdev_xmit_lock_key; int bond_create(char *name, struct bond_params *params) { struct net_device *bond_dev; - struct bonding *bond, *nxt; + struct bonding *bond; int res; rtnl_lock(); @@ -4859,7 +4856,7 @@ int bond_create(char *name, struct bond_params *params) /* Check to see if the bond already exists. */ if (name) { - list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) + list_for_each_entry(bond, &bond_dev_list, bond_list) if (strnicmp(bond->dev->name, name, IFNAMSIZ) == 0) { printk(KERN_ERR DRV_NAME ": cannot add bond %s; it already exists\n", @@ -4931,7 +4928,7 @@ static int __init bonding_init(void) { int i; int res; - struct bonding *bond, *nxt; + struct bonding *bond; printk(KERN_INFO "%s", version); @@ -4961,7 +4958,7 @@ static int __init bonding_init(void) goto out; err: - list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) { + list_for_each_entry(bond, &bond_dev_list, bond_list) { bond_work_cancel_all(bond); destroy_workqueue(bond->wq); } diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 452a789bf2e..1f028579e53 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -111,7 +111,6 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t char *ifname; int rv, res = count; struct bonding *bond; - struct bonding *nxt; sscanf(buffer, "%16s", command); /* IFNAMSIZ*/ ifname = command + 1; @@ -134,7 +133,7 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t rtnl_lock(); down_write(&bonding_rwsem); - list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) + list_for_each_entry(bond, &bond_dev_list, bond_list) if (strnicmp(bond->dev->name, ifname, IFNAMSIZ) == 0) { /* check the ref count on the bond's kobject. * If it's > expected, then there's a file open, -- cgit v1.2.3-70-g09d2 From 8047637c70e4451e2ac1c17ed9a91a2f753daae7 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Sat, 17 May 2008 21:10:11 -0700 Subject: bonding: Remove unneeded list_empty checks. Some places iterate over the checked list right after the check itself, so even if the list is empty, the list_for_each_xxx iterator will make everything right by himself. Signed-off-by: Pavel Emelyanov Acked-by: Jay Vosburgh Signed-off-by: Jeff Garzik --- drivers/net/bonding/bond_main.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 5e3b942fb51..2a0039f1937 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2433,9 +2433,6 @@ static int bond_has_this_ip(struct bonding *bond, __be32 ip) if (ip == bond->master_ip) return 1; - if (list_empty(&bond->vlan_list)) - return 0; - list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { if (ip == vlan->vlan_ip) return 1; @@ -3495,9 +3492,6 @@ static int bond_inetaddr_event(struct notifier_block *this, unsigned long event, } } - if (list_empty(&bond->vlan_list)) - continue; - list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { vlan_dev = vlan_group_get_device(bond->vlgrp, vlan->vlan_id); if (vlan_dev == event_dev) { -- cgit v1.2.3-70-g09d2 From 7893b2491a2d5f716540ac5643d78d37a7f6628b Mon Sep 17 00:00:00 2001 From: Moni Shoua Date: Sat, 17 May 2008 21:10:12 -0700 Subject: bonding: Send more than one gratuitous ARP when slave takes over With IPoIB, reception of gratuitous ARP by neighboring hosts is essential for a successful change of slaves in case of failure. Otherwise, they won't learn about the HW address change and need to wait a long time until the neighboring system gives up and sends an ARP request to learn the new HW address. This patch decreases the chance for a lost of a gratuitous ARP packet by sending it more than once. The number retries is configurable and can be set with a module param. Signed-off-by: Moni Shoua Acked-by: Jay Vosburgh Signed-off-by: Jeff Garzik --- drivers/net/bonding/bond_main.c | 23 +++++++++++++++++++---- drivers/net/bonding/bond_sysfs.c | 40 ++++++++++++++++++++++++++++++++++++++++ drivers/net/bonding/bonding.h | 1 + 3 files changed, 60 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 2a0039f1937..fa3c2101fe7 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -88,6 +88,7 @@ #define BOND_LINK_ARP_INTERV 0 static int max_bonds = BOND_DEFAULT_MAX_BONDS; +static int num_grat_arp = 1; static int miimon = BOND_LINK_MON_INTERV; static int updelay = 0; static int downdelay = 0; @@ -104,6 +105,8 @@ struct bond_params bonding_defaults; module_param(max_bonds, int, 0); MODULE_PARM_DESC(max_bonds, "Max number of bonded devices"); +module_param(num_grat_arp, int, 0644); +MODULE_PARM_DESC(num_grat_arp, "Number of gratuitous ARP packets to send on failover event"); module_param(miimon, int, 0); MODULE_PARM_DESC(miimon, "Link check interval in milliseconds"); module_param(updelay, int, 0); @@ -1109,14 +1112,18 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) if (new_active && bond->params.fail_over_mac) memcpy(bond->dev->dev_addr, new_active->dev->dev_addr, new_active->dev->addr_len); + bond->send_grat_arp = bond->params.num_grat_arp; if (bond->curr_active_slave && test_bit(__LINK_STATE_LINKWATCH_PENDING, &bond->curr_active_slave->dev->state)) { dprintk("delaying gratuitous arp on %s\n", bond->curr_active_slave->dev->name); - bond->send_grat_arp = 1; - } else - bond_send_gratuitous_arp(bond); + } else { + if (bond->send_grat_arp > 0) { + bond_send_gratuitous_arp(bond); + bond->send_grat_arp--; + } + } } } @@ -2144,7 +2151,7 @@ static int __bond_mii_monitor(struct bonding *bond, int have_locks) dprintk("sending delayed gratuitous arp on on %s\n", bond->curr_active_slave->dev->name); bond_send_gratuitous_arp(bond); - bond->send_grat_arp = 0; + bond->send_grat_arp--; } } read_lock(&bond->curr_slave_lock); @@ -4626,6 +4633,13 @@ static int bond_check_params(struct bond_params *params) use_carrier = 1; } + if (num_grat_arp < 0 || num_grat_arp > 255) { + printk(KERN_WARNING DRV_NAME + ": Warning: num_grat_arp (%d) not in range 0-255 so it " + "was reset to 1 \n", num_grat_arp); + num_grat_arp = 1; + } + /* reset values for 802.3ad */ if (bond_mode == BOND_MODE_8023AD) { if (!miimon) { @@ -4813,6 +4827,7 @@ static int bond_check_params(struct bond_params *params) params->mode = bond_mode; params->xmit_policy = xmit_hashtype; params->miimon = miimon; + params->num_grat_arp = num_grat_arp; params->arp_interval = arp_interval; params->arp_validate = arp_validate_value; params->updelay = updelay; diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 1f028579e53..7a61e9a1438 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -950,6 +950,45 @@ out: } static DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, bonding_show_lacp, bonding_store_lacp); +/* + * Show and set the number of grat ARP to send after a failover event. + */ +static ssize_t bonding_show_n_grat_arp(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct bonding *bond = to_bond(d); + + return sprintf(buf, "%d\n", bond->params.num_grat_arp); +} + +static ssize_t bonding_store_n_grat_arp(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int new_value, ret = count; + struct bonding *bond = to_bond(d); + + if (sscanf(buf, "%d", &new_value) != 1) { + printk(KERN_ERR DRV_NAME + ": %s: no num_grat_arp value specified.\n", + bond->dev->name); + ret = -EINVAL; + goto out; + } + if (new_value < 0 || new_value > 255) { + printk(KERN_ERR DRV_NAME + ": %s: Invalid num_grat_arp value %d not in range 0-255; rejected.\n", + bond->dev->name, new_value); + ret = -EINVAL; + goto out; + } else { + bond->params.num_grat_arp = new_value; + } +out: + return ret; +} +static DEVICE_ATTR(num_grat_arp, S_IRUGO | S_IWUSR, bonding_show_n_grat_arp, bonding_store_n_grat_arp); /* * Show and set the MII monitor interval. There are two tricky bits * here. First, if MII monitoring is activated, then we must disable @@ -1387,6 +1426,7 @@ static struct attribute *per_bond_attrs[] = { &dev_attr_updelay.attr, &dev_attr_lacp_rate.attr, &dev_attr_xmit_hash_policy.attr, + &dev_attr_num_grat_arp.attr, &dev_attr_miimon.attr, &dev_attr_primary.attr, &dev_attr_use_carrier.attr, diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 0ce7f4ae920..46a2ed507b3 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -125,6 +125,7 @@ struct bond_params { int mode; int xmit_policy; int miimon; + int num_grat_arp; int arp_interval; int arp_validate; int use_carrier; -- cgit v1.2.3-70-g09d2 From b2220cad583c9b63e085476df448fa2aff5ea906 Mon Sep 17 00:00:00 2001 From: Jay Vosburgh Date: Sat, 17 May 2008 21:10:13 -0700 Subject: bonding: refactor ARP active-backup monitor Refactor ARP monitor for active-backup mode. The motivation for this is to take care of locking issues in a clear manner (particularly to correctly handle RTNL vs. the bonding locks). Currently, the a-b ARP monitor does not hold RTNL at all, but future changes will require RTNL during ARP monitor failovers. Rather than using conditional locking, this patch instead breaks up the ARP monitor into three discrete steps: inspection, commit changes, and probe. The inspection phase marks slaves that require link state changes. The commit phase is only called if inspection detects that changes are needed, and is called with RTNL. Lastly, the probe phase issues the ARP probes that the inspection phase uses to determine link state. Signed-off-by: Jay Vosburgh Signed-off-by: Jeff Garzik --- drivers/net/bonding/bond_main.c | 427 +++++++++++++++++++++++----------------- drivers/net/bonding/bonding.h | 6 + 2 files changed, 248 insertions(+), 185 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index fa3c2101fe7..51e0f2de42c 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1051,6 +1051,8 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) } if (new_active) { + new_active->jiffies = jiffies; + if (new_active->link == BOND_LINK_BACK) { if (USES_PRIMARY(bond->params.mode)) { printk(KERN_INFO DRV_NAME @@ -1062,7 +1064,6 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) new_active->delay = 0; new_active->link = BOND_LINK_UP; - new_active->jiffies = jiffies; if (bond->params.mode == BOND_MODE_8023AD) { bond_3ad_handle_link_change(new_active, BOND_LINK_UP); @@ -2795,243 +2796,299 @@ out: } /* - * When using arp monitoring in active-backup mode, this function is - * called to determine if any backup slaves have went down or a new - * current slave needs to be found. - * The backup slaves never generate traffic, they are considered up by merely - * receiving traffic. If the current slave goes down, each backup slave will - * be given the opportunity to tx/rx an arp before being taken down - this - * prevents all slaves from being taken down due to the current slave not - * sending any traffic for the backups to receive. The arps are not necessarily - * necessary, any tx and rx traffic will keep the current slave up. While any - * rx traffic will keep the backup slaves up, the current slave is responsible - * for generating traffic to keep them up regardless of any other traffic they - * may have received. - * see loadbalance_arp_monitor for arp monitoring in load balancing mode + * Called to inspect slaves for active-backup mode ARP monitor link state + * changes. Sets new_link in slaves to specify what action should take + * place for the slave. Returns 0 if no changes are found, >0 if changes + * to link states must be committed. + * + * Called with bond->lock held for read. */ -void bond_activebackup_arp_mon(struct work_struct *work) +static int bond_ab_arp_inspect(struct bonding *bond, int delta_in_ticks) { - struct bonding *bond = container_of(work, struct bonding, - arp_work.work); struct slave *slave; - int delta_in_ticks; - int i; + int i, commit = 0; - read_lock(&bond->lock); + bond_for_each_slave(bond, slave, i) { + slave->new_link = BOND_LINK_NOCHANGE; - delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval); + if (slave->link != BOND_LINK_UP) { + if (time_before_eq(jiffies, slave_last_rx(bond, slave) + + delta_in_ticks)) { + slave->new_link = BOND_LINK_UP; + commit++; + } - if (bond->kill_timers) { - goto out; - } + continue; + } - if (bond->slave_cnt == 0) { - goto re_arm; + /* + * Give slaves 2*delta after being enslaved or made + * active. This avoids bouncing, as the last receive + * times need a full ARP monitor cycle to be updated. + */ + if (!time_after_eq(jiffies, slave->jiffies + + 2 * delta_in_ticks)) + continue; + + /* + * Backup slave is down if: + * - No current_arp_slave AND + * - more than 3*delta since last receive AND + * - the bond has an IP address + * + * Note: a non-null current_arp_slave indicates + * the curr_active_slave went down and we are + * searching for a new one; under this condition + * we only take the curr_active_slave down - this + * gives each slave a chance to tx/rx traffic + * before being taken out + */ + if (slave->state == BOND_STATE_BACKUP && + !bond->current_arp_slave && + time_after(jiffies, slave_last_rx(bond, slave) + + 3 * delta_in_ticks)) { + slave->new_link = BOND_LINK_DOWN; + commit++; + } + + /* + * Active slave is down if: + * - more than 2*delta since transmitting OR + * - (more than 2*delta since receive AND + * the bond has an IP address) + */ + if ((slave->state == BOND_STATE_ACTIVE) && + (time_after_eq(jiffies, slave->dev->trans_start + + 2 * delta_in_ticks) || + (time_after_eq(jiffies, slave_last_rx(bond, slave) + + 2 * delta_in_ticks)))) { + slave->new_link = BOND_LINK_DOWN; + commit++; + } } - /* determine if any slave has come up or any backup slave has - * gone down - * TODO: what about up/down delay in arp mode? it wasn't here before - * so it can wait + read_lock(&bond->curr_slave_lock); + + /* + * Trigger a commit if the primary option setting has changed. */ - bond_for_each_slave(bond, slave, i) { - if (slave->link != BOND_LINK_UP) { - if (time_before_eq(jiffies, - slave_last_rx(bond, slave) + delta_in_ticks)) { + if (bond->primary_slave && + (bond->primary_slave != bond->curr_active_slave) && + (bond->primary_slave->link == BOND_LINK_UP)) + commit++; - slave->link = BOND_LINK_UP; + read_unlock(&bond->curr_slave_lock); - write_lock_bh(&bond->curr_slave_lock); + return commit; +} - if ((!bond->curr_active_slave) && - time_before_eq(jiffies, slave->dev->trans_start + delta_in_ticks)) { - bond_change_active_slave(bond, slave); - bond->current_arp_slave = NULL; - } else if (bond->curr_active_slave != slave) { - /* this slave has just come up but we - * already have a current slave; this - * can also happen if bond_enslave adds - * a new slave that is up while we are - * searching for a new slave - */ - bond_set_slave_inactive_flags(slave); - bond->current_arp_slave = NULL; - } +/* + * Called to commit link state changes noted by inspection step of + * active-backup mode ARP monitor. + * + * Called with RTNL and bond->lock for read. + */ +static void bond_ab_arp_commit(struct bonding *bond, int delta_in_ticks) +{ + struct slave *slave; + int i; - bond_set_carrier(bond); + bond_for_each_slave(bond, slave, i) { + switch (slave->new_link) { + case BOND_LINK_NOCHANGE: + continue; - if (slave == bond->curr_active_slave) { - printk(KERN_INFO DRV_NAME - ": %s: %s is up and now the " - "active interface\n", - bond->dev->name, - slave->dev->name); - netif_carrier_on(bond->dev); - } else { - printk(KERN_INFO DRV_NAME - ": %s: backup interface %s is " - "now up\n", - bond->dev->name, - slave->dev->name); - } + case BOND_LINK_UP: + write_lock_bh(&bond->curr_slave_lock); - write_unlock_bh(&bond->curr_slave_lock); - } - } else { - read_lock(&bond->curr_slave_lock); + if (!bond->curr_active_slave && + time_before_eq(jiffies, slave->dev->trans_start + + delta_in_ticks)) { + slave->link = BOND_LINK_UP; + bond_change_active_slave(bond, slave); + bond->current_arp_slave = NULL; - if ((slave != bond->curr_active_slave) && - (!bond->current_arp_slave) && - (time_after_eq(jiffies, slave_last_rx(bond, slave) + 3*delta_in_ticks))) { - /* a backup slave has gone down; three times - * the delta allows the current slave to be - * taken out before the backup slave. - * note: a non-null current_arp_slave indicates - * the curr_active_slave went down and we are - * searching for a new one; under this - * condition we only take the curr_active_slave - * down - this gives each slave a chance to - * tx/rx traffic before being taken out + printk(KERN_INFO DRV_NAME + ": %s: %s is up and now the " + "active interface\n", + bond->dev->name, slave->dev->name); + + } else if (bond->curr_active_slave != slave) { + /* this slave has just come up but we + * already have a current slave; this can + * also happen if bond_enslave adds a new + * slave that is up while we are searching + * for a new slave */ + slave->link = BOND_LINK_UP; + bond_set_slave_inactive_flags(slave); + bond->current_arp_slave = NULL; + + printk(KERN_INFO DRV_NAME + ": %s: backup interface %s is now up\n", + bond->dev->name, slave->dev->name); + } - read_unlock(&bond->curr_slave_lock); + write_unlock_bh(&bond->curr_slave_lock); - slave->link = BOND_LINK_DOWN; + break; - if (slave->link_failure_count < UINT_MAX) { - slave->link_failure_count++; - } + case BOND_LINK_DOWN: + if (slave->link_failure_count < UINT_MAX) + slave->link_failure_count++; + + slave->link = BOND_LINK_DOWN; + + if (slave == bond->curr_active_slave) { + printk(KERN_INFO DRV_NAME + ": %s: link status down for active " + "interface %s, disabling it\n", + bond->dev->name, slave->dev->name); bond_set_slave_inactive_flags(slave); + write_lock_bh(&bond->curr_slave_lock); + + bond_select_active_slave(bond); + if (bond->curr_active_slave) + bond->curr_active_slave->jiffies = + jiffies; + + write_unlock_bh(&bond->curr_slave_lock); + + bond->current_arp_slave = NULL; + + } else if (slave->state == BOND_STATE_BACKUP) { printk(KERN_INFO DRV_NAME ": %s: backup interface %s is now down\n", - bond->dev->name, - slave->dev->name); - } else { - read_unlock(&bond->curr_slave_lock); + bond->dev->name, slave->dev->name); + + bond_set_slave_inactive_flags(slave); } + break; + + default: + printk(KERN_ERR DRV_NAME + ": %s: impossible: new_link %d on slave %s\n", + bond->dev->name, slave->new_link, + slave->dev->name); } } - read_lock(&bond->curr_slave_lock); - slave = bond->curr_active_slave; - read_unlock(&bond->curr_slave_lock); - - if (slave) { - /* if we have sent traffic in the past 2*arp_intervals but - * haven't xmit and rx traffic in that time interval, select - * a different slave. slave->jiffies is only updated when - * a slave first becomes the curr_active_slave - not necessarily - * after every arp; this ensures the slave has a full 2*delta - * before being taken out. if a primary is being used, check - * if it is up and needs to take over as the curr_active_slave - */ - if ((time_after_eq(jiffies, slave->dev->trans_start + 2*delta_in_ticks) || - (time_after_eq(jiffies, slave_last_rx(bond, slave) + 2*delta_in_ticks))) && - time_after_eq(jiffies, slave->jiffies + 2*delta_in_ticks)) { + /* + * No race with changes to primary via sysfs, as we hold rtnl. + */ + if (bond->primary_slave && + (bond->primary_slave != bond->curr_active_slave) && + (bond->primary_slave->link == BOND_LINK_UP)) { + write_lock_bh(&bond->curr_slave_lock); + bond_change_active_slave(bond, bond->primary_slave); + write_unlock_bh(&bond->curr_slave_lock); + } - slave->link = BOND_LINK_DOWN; + bond_set_carrier(bond); +} - if (slave->link_failure_count < UINT_MAX) { - slave->link_failure_count++; - } +/* + * Send ARP probes for active-backup mode ARP monitor. + * + * Called with bond->lock held for read. + */ +static void bond_ab_arp_probe(struct bonding *bond) +{ + struct slave *slave; + int i; - printk(KERN_INFO DRV_NAME - ": %s: link status down for active interface " - "%s, disabling it\n", - bond->dev->name, - slave->dev->name); + read_lock(&bond->curr_slave_lock); - write_lock_bh(&bond->curr_slave_lock); + if (bond->current_arp_slave && bond->curr_active_slave) + printk("PROBE: c_arp %s && cas %s BAD\n", + bond->current_arp_slave->dev->name, + bond->curr_active_slave->dev->name); - bond_select_active_slave(bond); - slave = bond->curr_active_slave; + if (bond->curr_active_slave) { + bond_arp_send_all(bond, bond->curr_active_slave); + read_unlock(&bond->curr_slave_lock); + return; + } - write_unlock_bh(&bond->curr_slave_lock); + read_unlock(&bond->curr_slave_lock); - bond->current_arp_slave = slave; + /* if we don't have a curr_active_slave, search for the next available + * backup slave from the current_arp_slave and make it the candidate + * for becoming the curr_active_slave + */ - if (slave) { - slave->jiffies = jiffies; - } - } else if ((bond->primary_slave) && - (bond->primary_slave != slave) && - (bond->primary_slave->link == BOND_LINK_UP)) { - /* at this point, slave is the curr_active_slave */ - printk(KERN_INFO DRV_NAME - ": %s: changing from interface %s to primary " - "interface %s\n", - bond->dev->name, - slave->dev->name, - bond->primary_slave->dev->name); + if (!bond->current_arp_slave) { + bond->current_arp_slave = bond->first_slave; + if (!bond->current_arp_slave) + return; + } - /* primary is up so switch to it */ - write_lock_bh(&bond->curr_slave_lock); - bond_change_active_slave(bond, bond->primary_slave); - write_unlock_bh(&bond->curr_slave_lock); + bond_set_slave_inactive_flags(bond->current_arp_slave); - slave = bond->primary_slave; + /* search for next candidate */ + bond_for_each_slave_from(bond, slave, i, bond->current_arp_slave->next) { + if (IS_UP(slave->dev)) { + slave->link = BOND_LINK_BACK; + bond_set_slave_active_flags(slave); + bond_arp_send_all(bond, slave); slave->jiffies = jiffies; - } else { - bond->current_arp_slave = NULL; + bond->current_arp_slave = slave; + break; } - /* the current slave must tx an arp to ensure backup slaves - * rx traffic + /* if the link state is up at this point, we + * mark it down - this can happen if we have + * simultaneous link failures and + * reselect_active_interface doesn't make this + * one the current slave so it is still marked + * up when it is actually down */ - if (slave && IS_UP(slave->dev)) - bond_arp_send_all(bond, slave); - } + if (slave->link == BOND_LINK_UP) { + slave->link = BOND_LINK_DOWN; + if (slave->link_failure_count < UINT_MAX) + slave->link_failure_count++; - /* if we don't have a curr_active_slave, search for the next available - * backup slave from the current_arp_slave and make it the candidate - * for becoming the curr_active_slave - */ - if (!slave) { - if (!bond->current_arp_slave) { - bond->current_arp_slave = bond->first_slave; + bond_set_slave_inactive_flags(slave); + + printk(KERN_INFO DRV_NAME + ": %s: backup interface %s is now down.\n", + bond->dev->name, slave->dev->name); } + } +} - if (bond->current_arp_slave) { - bond_set_slave_inactive_flags(bond->current_arp_slave); +void bond_activebackup_arp_mon(struct work_struct *work) +{ + struct bonding *bond = container_of(work, struct bonding, + arp_work.work); + int delta_in_ticks; - /* search for next candidate */ - bond_for_each_slave_from(bond, slave, i, bond->current_arp_slave->next) { - if (IS_UP(slave->dev)) { - slave->link = BOND_LINK_BACK; - bond_set_slave_active_flags(slave); - bond_arp_send_all(bond, slave); - slave->jiffies = jiffies; - bond->current_arp_slave = slave; - break; - } + read_lock(&bond->lock); - /* if the link state is up at this point, we - * mark it down - this can happen if we have - * simultaneous link failures and - * reselect_active_interface doesn't make this - * one the current slave so it is still marked - * up when it is actually down - */ - if (slave->link == BOND_LINK_UP) { - slave->link = BOND_LINK_DOWN; - if (slave->link_failure_count < UINT_MAX) { - slave->link_failure_count++; - } + if (bond->kill_timers) + goto out; - bond_set_slave_inactive_flags(slave); + delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval); - printk(KERN_INFO DRV_NAME - ": %s: backup interface %s is " - "now down.\n", - bond->dev->name, - slave->dev->name); - } - } - } + if (bond->slave_cnt == 0) + goto re_arm; + + if (bond_ab_arp_inspect(bond, delta_in_ticks)) { + read_unlock(&bond->lock); + rtnl_lock(); + read_lock(&bond->lock); + + bond_ab_arp_commit(bond, delta_in_ticks); + + read_unlock(&bond->lock); + rtnl_unlock(); + read_lock(&bond->lock); } + bond_ab_arp_probe(bond); + re_arm: if (bond->params.arp_interval) { queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks); diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 46a2ed507b3..8766b121369 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -158,6 +158,7 @@ struct slave { unsigned long jiffies; unsigned long last_arp_rx; s8 link; /* one of BOND_LINK_XXXX */ + s8 new_link; s8 state; /* one of BOND_STATE_XXXX */ u32 original_flags; u32 original_mtu; @@ -169,6 +170,11 @@ struct slave { struct tlb_slave_info tlb_info; }; +/* + * Link pseudo-state only used internally by monitors + */ +#define BOND_LINK_NOCHANGE -1 + /* * Here are the locking policies for the two bonding locks: * -- cgit v1.2.3-70-g09d2 From 3915c1e8634a321d9680e5cd80a53053b642dc0c Mon Sep 17 00:00:00 2001 From: Jay Vosburgh Date: Sat, 17 May 2008 21:10:14 -0700 Subject: bonding: Add "follow" option to fail_over_mac Add a "follow" selection for fail_over_mac. This option causes the MAC address to move from slave to slave as the active slave changes. This is in addition to the existing fail_over_mac option that causes the bond's MAC address to change during failover. This new option is useful for devices that cannot tolerate multiple ports using the same MAC address simultaneously, either because it confuses them or incurs a performance penalty (as is the case with some LPAR-aware multiport devices). Because the MAC of the bond itself does not change, the "follow" option is slightly more reliable during failover and doesn't change the MAC of the bond during operation. This patch requires a previous ARP monitor change to properly handle RTNL during failovers. Signed-off-by: Jay Vosburgh Signed-off-by: Jeff Garzik --- Documentation/networking/bonding.txt | 96 ++++++++++++------ drivers/net/bonding/bond_main.c | 185 +++++++++++++++++++++++++++-------- drivers/net/bonding/bond_sysfs.c | 36 +++---- drivers/net/bonding/bonding.h | 4 + 4 files changed, 232 insertions(+), 89 deletions(-) (limited to 'drivers') diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt index a0cda062bc3..8e6b8d3c741 100644 --- a/Documentation/networking/bonding.txt +++ b/Documentation/networking/bonding.txt @@ -289,35 +289,73 @@ downdelay fail_over_mac Specifies whether active-backup mode should set all slaves to - the same MAC address (the traditional behavior), or, when - enabled, change the bond's MAC address when changing the - active interface (i.e., fail over the MAC address itself). - - Fail over MAC is useful for devices that cannot ever alter - their MAC address, or for devices that refuse incoming - broadcasts with their own source MAC (which interferes with - the ARP monitor). - - The down side of fail over MAC is that every device on the - network must be updated via gratuitous ARP, vs. just updating - a switch or set of switches (which often takes place for any - traffic, not just ARP traffic, if the switch snoops incoming - traffic to update its tables) for the traditional method. If - the gratuitous ARP is lost, communication may be disrupted. - - When fail over MAC is used in conjuction with the mii monitor, - devices which assert link up prior to being able to actually - transmit and receive are particularly susecptible to loss of - the gratuitous ARP, and an appropriate updelay setting may be - required. - - A value of 0 disables fail over MAC, and is the default. A - value of 1 enables fail over MAC. This option is enabled - automatically if the first slave added cannot change its MAC - address. This option may be modified via sysfs only when no - slaves are present in the bond. - - This option was added in bonding version 3.2.0. + the same MAC address at enslavement (the traditional + behavior), or, when enabled, perform special handling of the + bond's MAC address in accordance with the selected policy. + + Possible values are: + + none or 0 + + This setting disables fail_over_mac, and causes + bonding to set all slaves of an active-backup bond to + the same MAC address at enslavement time. This is the + default. + + active or 1 + + The "active" fail_over_mac policy indicates that the + MAC address of the bond should always be the MAC + address of the currently active slave. The MAC + address of the slaves is not changed; instead, the MAC + address of the bond changes during a failover. + + This policy is useful for devices that cannot ever + alter their MAC address, or for devices that refuse + incoming broadcasts with their own source MAC (which + interferes with the ARP monitor). + + The down side of this policy is that every device on + the network must be updated via gratuitous ARP, + vs. just updating a switch or set of switches (which + often takes place for any traffic, not just ARP + traffic, if the switch snoops incoming traffic to + update its tables) for the traditional method. If the + gratuitous ARP is lost, communication may be + disrupted. + + When this policy is used in conjuction with the mii + monitor, devices which assert link up prior to being + able to actually transmit and receive are particularly + susecptible to loss of the gratuitous ARP, and an + appropriate updelay setting may be required. + + follow or 2 + + The "follow" fail_over_mac policy causes the MAC + address of the bond to be selected normally (normally + the MAC address of the first slave added to the bond). + However, the second and subsequent slaves are not set + to this MAC address while they are in a backup role; a + slave is programmed with the bond's MAC address at + failover time (and the formerly active slave receives + the newly active slave's MAC address). + + This policy is useful for multiport devices that + either become confused or incur a performance penalty + when multiple ports are programmed with the same MAC + address. + + + The default policy is none, unless the first slave cannot + change its MAC address, in which case the active policy is + selected by default. + + This option may be modified via sysfs only when no slaves are + present in the bond. + + This option was added in bonding version 3.2.0. The "follow" + policy was added in bonding version 3.3.0. lacp_rate diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 51e0f2de42c..5b4af3cc2a4 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -100,7 +100,7 @@ static char *xmit_hash_policy = NULL; static int arp_interval = BOND_LINK_ARP_INTERV; static char *arp_ip_target[BOND_MAX_ARP_TARGETS] = { NULL, }; static char *arp_validate = NULL; -static int fail_over_mac = 0; +static char *fail_over_mac = NULL; struct bond_params bonding_defaults; module_param(max_bonds, int, 0); @@ -136,8 +136,8 @@ module_param_array(arp_ip_target, charp, NULL, 0); MODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form"); module_param(arp_validate, charp, 0); MODULE_PARM_DESC(arp_validate, "validate src/dst of ARP probes: none (default), active, backup or all"); -module_param(fail_over_mac, int, 0); -MODULE_PARM_DESC(fail_over_mac, "For active-backup, do not set all slaves to the same MAC. 0 of off (default), 1 for on."); +module_param(fail_over_mac, charp, 0); +MODULE_PARM_DESC(fail_over_mac, "For active-backup, do not set all slaves to the same MAC. none (default), active or follow"); /*----------------------------- Global variables ----------------------------*/ @@ -190,6 +190,13 @@ struct bond_parm_tbl arp_validate_tbl[] = { { NULL, -1}, }; +struct bond_parm_tbl fail_over_mac_tbl[] = { +{ "none", BOND_FOM_NONE}, +{ "active", BOND_FOM_ACTIVE}, +{ "follow", BOND_FOM_FOLLOW}, +{ NULL, -1}, +}; + /*-------------------------- Forward declarations ---------------------------*/ static void bond_send_gratuitous_arp(struct bonding *bond); @@ -973,6 +980,82 @@ static void bond_mc_swap(struct bonding *bond, struct slave *new_active, struct } } +/* + * bond_do_fail_over_mac + * + * Perform special MAC address swapping for fail_over_mac settings + * + * Called with RTNL, bond->lock for read, curr_slave_lock for write_bh. + */ +static void bond_do_fail_over_mac(struct bonding *bond, + struct slave *new_active, + struct slave *old_active) +{ + u8 tmp_mac[ETH_ALEN]; + struct sockaddr saddr; + int rv; + + switch (bond->params.fail_over_mac) { + case BOND_FOM_ACTIVE: + if (new_active) + memcpy(bond->dev->dev_addr, new_active->dev->dev_addr, + new_active->dev->addr_len); + break; + case BOND_FOM_FOLLOW: + /* + * if new_active && old_active, swap them + * if just old_active, do nothing (going to no active slave) + * if just new_active, set new_active to bond's MAC + */ + if (!new_active) + return; + + write_unlock_bh(&bond->curr_slave_lock); + read_unlock(&bond->lock); + + if (old_active) { + memcpy(tmp_mac, new_active->dev->dev_addr, ETH_ALEN); + memcpy(saddr.sa_data, old_active->dev->dev_addr, + ETH_ALEN); + saddr.sa_family = new_active->dev->type; + } else { + memcpy(saddr.sa_data, bond->dev->dev_addr, ETH_ALEN); + saddr.sa_family = bond->dev->type; + } + + rv = dev_set_mac_address(new_active->dev, &saddr); + if (rv) { + printk(KERN_ERR DRV_NAME + ": %s: Error %d setting MAC of slave %s\n", + bond->dev->name, -rv, new_active->dev->name); + goto out; + } + + if (!old_active) + goto out; + + memcpy(saddr.sa_data, tmp_mac, ETH_ALEN); + saddr.sa_family = old_active->dev->type; + + rv = dev_set_mac_address(old_active->dev, &saddr); + if (rv) + printk(KERN_ERR DRV_NAME + ": %s: Error %d setting MAC of slave %s\n", + bond->dev->name, -rv, new_active->dev->name); +out: + read_lock(&bond->lock); + write_lock_bh(&bond->curr_slave_lock); + break; + default: + printk(KERN_ERR DRV_NAME + ": %s: bond_do_fail_over_mac impossible: bad policy %d\n", + bond->dev->name, bond->params.fail_over_mac); + break; + } + +} + + /** * find_best_interface - select the best available slave to be the active one * @bond: our bonding struct @@ -1040,7 +1123,8 @@ static struct slave *bond_find_best_slave(struct bonding *bond) * because it is apparently the best available slave we have, even though its * updelay hasn't timed out yet. * - * Warning: Caller must hold curr_slave_lock for writing. + * If new_active is not NULL, caller must hold bond->lock for read and + * curr_slave_lock for write_bh. */ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) { @@ -1107,12 +1191,9 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) bond_set_slave_active_flags(new_active); } - /* when bonding does not set the slave MAC address, the bond MAC - * address is the one of the active slave. - */ if (new_active && bond->params.fail_over_mac) - memcpy(bond->dev->dev_addr, new_active->dev->dev_addr, - new_active->dev->addr_len); + bond_do_fail_over_mac(bond, new_active, old_active); + bond->send_grat_arp = bond->params.num_grat_arp; if (bond->curr_active_slave && test_bit(__LINK_STATE_LINKWATCH_PENDING, @@ -1137,7 +1218,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) * - The primary_slave has got its link back. * - A slave has got its link back and there's no old curr_active_slave. * - * Warning: Caller must hold curr_slave_lock for writing. + * Caller must hold bond->lock for read and curr_slave_lock for write_bh. */ void bond_select_active_slave(struct bonding *bond) { @@ -1384,14 +1465,14 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) printk(KERN_WARNING DRV_NAME ": %s: Warning: The first slave device " "specified does not support setting the MAC " - "address. Enabling the fail_over_mac option.", + "address. Setting fail_over_mac to active.", bond_dev->name); - bond->params.fail_over_mac = 1; - } else if (!bond->params.fail_over_mac) { + bond->params.fail_over_mac = BOND_FOM_ACTIVE; + } else if (bond->params.fail_over_mac != BOND_FOM_ACTIVE) { printk(KERN_ERR DRV_NAME ": %s: Error: The slave device specified " "does not support setting the MAC address, " - "but fail_over_mac is not enabled.\n" + "but fail_over_mac is not set to active.\n" , bond_dev->name); res = -EOPNOTSUPP; goto err_undo_flags; @@ -1498,6 +1579,10 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) bond_compute_features(bond); + write_unlock_bh(&bond->lock); + + read_lock(&bond->lock); + new_slave->last_arp_rx = jiffies; if (bond->params.miimon && !bond->params.use_carrier) { @@ -1574,6 +1659,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) } } + write_lock_bh(&bond->curr_slave_lock); + switch (bond->params.mode) { case BOND_MODE_ACTIVEBACKUP: bond_set_slave_inactive_flags(new_slave); @@ -1621,9 +1708,11 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) break; } /* switch(bond_mode) */ + write_unlock_bh(&bond->curr_slave_lock); + bond_set_carrier(bond); - write_unlock_bh(&bond->lock); + read_unlock(&bond->lock); res = bond_create_slave_symlinks(bond_dev, slave_dev); if (res) @@ -1647,6 +1736,10 @@ err_unset_master: err_restore_mac: if (!bond->params.fail_over_mac) { + /* XXX TODO - fom follow mode needs to change master's + * MAC if this slave's MAC is in use by the bond, or at + * least print a warning. + */ memcpy(addr.sa_data, new_slave->perm_hwaddr, ETH_ALEN); addr.sa_family = slave_dev->type; dev_set_mac_address(slave_dev, &addr); @@ -1701,20 +1794,18 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) return -EINVAL; } - mac_addr_differ = memcmp(bond_dev->dev_addr, - slave->perm_hwaddr, - ETH_ALEN); - if (!mac_addr_differ && (bond->slave_cnt > 1)) { - printk(KERN_WARNING DRV_NAME - ": %s: Warning: the permanent HWaddr of %s - " - "%s - is still in use by %s. " - "Set the HWaddr of %s to a different address " - "to avoid conflicts.\n", - bond_dev->name, - slave_dev->name, - print_mac(mac, slave->perm_hwaddr), - bond_dev->name, - slave_dev->name); + if (!bond->params.fail_over_mac) { + mac_addr_differ = memcmp(bond_dev->dev_addr, slave->perm_hwaddr, + ETH_ALEN); + if (!mac_addr_differ && (bond->slave_cnt > 1)) + printk(KERN_WARNING DRV_NAME + ": %s: Warning: the permanent HWaddr of %s - " + "%s - is still in use by %s. " + "Set the HWaddr of %s to a different address " + "to avoid conflicts.\n", + bond_dev->name, slave_dev->name, + print_mac(mac, slave->perm_hwaddr), + bond_dev->name, slave_dev->name); } /* Inform AD package of unbinding of slave. */ @@ -1841,7 +1932,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) /* close slave before restoring its mac address */ dev_close(slave_dev); - if (!bond->params.fail_over_mac) { + if (bond->params.fail_over_mac != BOND_FOM_ACTIVE) { /* restore original ("permanent") mac address */ memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN); addr.sa_family = slave_dev->type; @@ -3164,7 +3255,8 @@ static void bond_info_show_master(struct seq_file *seq) if (bond->params.mode == BOND_MODE_ACTIVEBACKUP && bond->params.fail_over_mac) - seq_printf(seq, " (fail_over_mac)"); + seq_printf(seq, " (fail_over_mac %s)", + fail_over_mac_tbl[bond->params.fail_over_mac].modename); seq_printf(seq, "\n"); @@ -4092,10 +4184,10 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr) dprintk("bond=%p, name=%s\n", bond, (bond_dev ? bond_dev->name : "None")); /* - * If fail_over_mac is enabled, do nothing and return success. - * Returning an error causes ifenslave to fail. + * If fail_over_mac is set to active, do nothing and return + * success. Returning an error causes ifenslave to fail. */ - if (bond->params.fail_over_mac) + if (bond->params.fail_over_mac == BOND_FOM_ACTIVE) return 0; if (!is_valid_ether_addr(sa->sa_data)) { @@ -4600,7 +4692,7 @@ int bond_parse_parm(const char *buf, struct bond_parm_tbl *tbl) static int bond_check_params(struct bond_params *params) { - int arp_validate_value; + int arp_validate_value, fail_over_mac_value; /* * Convert string parameters. @@ -4875,10 +4967,23 @@ static int bond_check_params(struct bond_params *params) primary = NULL; } - if (fail_over_mac && (bond_mode != BOND_MODE_ACTIVEBACKUP)) - printk(KERN_WARNING DRV_NAME - ": Warning: fail_over_mac only affects " - "active-backup mode.\n"); + if (fail_over_mac) { + fail_over_mac_value = bond_parse_parm(fail_over_mac, + fail_over_mac_tbl); + if (fail_over_mac_value == -1) { + printk(KERN_ERR DRV_NAME + ": Error: invalid fail_over_mac \"%s\"\n", + arp_validate == NULL ? "NULL" : arp_validate); + return -EINVAL; + } + + if (bond_mode != BOND_MODE_ACTIVEBACKUP) + printk(KERN_WARNING DRV_NAME + ": Warning: fail_over_mac only affects " + "active-backup mode.\n"); + } else { + fail_over_mac_value = BOND_FOM_NONE; + } /* fill params struct with the proper values */ params->mode = bond_mode; @@ -4892,7 +4997,7 @@ static int bond_check_params(struct bond_params *params) params->use_carrier = use_carrier; params->lacp_fast = lacp_fast; params->primary[0] = 0; - params->fail_over_mac = fail_over_mac; + params->fail_over_mac = fail_over_mac_value; if (primary) { strncpy(params->primary, primary, IFNAMSIZ); diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 7a61e9a1438..dd265c69b0d 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -50,6 +50,7 @@ extern struct bond_parm_tbl bond_mode_tbl[]; extern struct bond_parm_tbl bond_lacp_tbl[]; extern struct bond_parm_tbl xmit_hashtype_tbl[]; extern struct bond_parm_tbl arp_validate_tbl[]; +extern struct bond_parm_tbl fail_over_mac_tbl[]; static int expected_refcount = -1; static struct class *netdev_class; @@ -547,42 +548,37 @@ static ssize_t bonding_show_fail_over_mac(struct device *d, struct device_attrib { struct bonding *bond = to_bond(d); - return sprintf(buf, "%d\n", bond->params.fail_over_mac) + 1; + return sprintf(buf, "%s %d\n", + fail_over_mac_tbl[bond->params.fail_over_mac].modename, + bond->params.fail_over_mac); } static ssize_t bonding_store_fail_over_mac(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { int new_value; - int ret = count; struct bonding *bond = to_bond(d); if (bond->slave_cnt != 0) { printk(KERN_ERR DRV_NAME ": %s: Can't alter fail_over_mac with slaves in bond.\n", bond->dev->name); - ret = -EPERM; - goto out; + return -EPERM; } - if (sscanf(buf, "%d", &new_value) != 1) { + new_value = bond_parse_parm(buf, fail_over_mac_tbl); + if (new_value < 0) { printk(KERN_ERR DRV_NAME - ": %s: no fail_over_mac value specified.\n", - bond->dev->name); - ret = -EINVAL; - goto out; + ": %s: Ignoring invalid fail_over_mac value %s.\n", + bond->dev->name, buf); + return -EINVAL; } - if ((new_value == 0) || (new_value == 1)) { - bond->params.fail_over_mac = new_value; - printk(KERN_INFO DRV_NAME ": %s: Setting fail_over_mac to %d.\n", - bond->dev->name, new_value); - } else { - printk(KERN_INFO DRV_NAME - ": %s: Ignoring invalid fail_over_mac value %d.\n", - bond->dev->name, new_value); - } -out: - return ret; + bond->params.fail_over_mac = new_value; + printk(KERN_INFO DRV_NAME ": %s: Setting fail_over_mac to %s (%d).\n", + bond->dev->name, fail_over_mac_tbl[new_value].modename, + new_value); + + return count; } static DEVICE_ATTR(fail_over_mac, S_IRUGO | S_IWUSR, bonding_show_fail_over_mac, bonding_store_fail_over_mac); diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 8766b121369..89fd9963db7 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -248,6 +248,10 @@ static inline struct bonding *bond_get_bond_by_slave(struct slave *slave) return (struct bonding *)slave->dev->master->priv; } +#define BOND_FOM_NONE 0 +#define BOND_FOM_ACTIVE 1 +#define BOND_FOM_FOLLOW 2 + #define BOND_ARP_VALIDATE_NONE 0 #define BOND_ARP_VALIDATE_ACTIVE (1 << BOND_STATE_ACTIVE) #define BOND_ARP_VALIDATE_BACKUP (1 << BOND_STATE_BACKUP) -- cgit v1.2.3-70-g09d2 From cd9af3dac6d1ad001b2d5d912dbd49e184d23b9d Mon Sep 17 00:00:00 2001 From: Nate Case Date: Sat, 17 May 2008 06:40:39 +0100 Subject: PHYLIB: Add 1000Base-X support for Broadcom bcm5482 Configure the BCM5482S secondary SerDes for 1000Base-X mode when the appropriate dev_flags are passed in to phy_connect(). This is needed when the PHY is used for fiber and backplane connections. Signed-off-by: Nate Case Signed-off-by: Maciej W. Rozycki Signed-off-by: Jeff Garzik --- drivers/net/phy/broadcom.c | 201 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 199 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index 60c5cfe9691..4b4dc98ad16 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c @@ -24,6 +24,12 @@ #define MII_BCM54XX_ESR 0x11 /* BCM54xx extended status register */ #define MII_BCM54XX_ESR_IS 0x1000 /* Interrupt status */ +#define MII_BCM54XX_EXP_DATA 0x15 /* Expansion register data */ +#define MII_BCM54XX_EXP_SEL 0x17 /* Expansion register select */ +#define MII_BCM54XX_EXP_SEL_SSD 0x0e00 /* Secondary SerDes select */ +#define MII_BCM54XX_EXP_SEL_ER 0x0f00 /* Expansion register select */ + +#define MII_BCM54XX_AUX_CTL 0x18 /* Auxiliary control register */ #define MII_BCM54XX_ISR 0x1a /* BCM54xx interrupt status register */ #define MII_BCM54XX_IMR 0x1b /* BCM54xx interrupt mask register */ #define MII_BCM54XX_INT_CRCERR 0x0001 /* CRC error */ @@ -42,10 +48,120 @@ #define MII_BCM54XX_INT_MDIX 0x2000 /* MDIX status change */ #define MII_BCM54XX_INT_PSERR 0x4000 /* Pair swap error */ +#define MII_BCM54XX_SHD 0x1c /* 0x1c shadow registers */ +#define MII_BCM54XX_SHD_WRITE 0x8000 +#define MII_BCM54XX_SHD_VAL(x) ((x & 0x1f) << 10) +#define MII_BCM54XX_SHD_DATA(x) ((x & 0x3ff) << 0) + +/* + * Broadcom LED source encodings. These are used in BCM5461, BCM5481, + * BCM5482, and possibly some others. + */ +#define BCM_LED_SRC_LINKSPD1 0x0 +#define BCM_LED_SRC_LINKSPD2 0x1 +#define BCM_LED_SRC_XMITLED 0x2 +#define BCM_LED_SRC_ACTIVITYLED 0x3 +#define BCM_LED_SRC_FDXLED 0x4 +#define BCM_LED_SRC_SLAVE 0x5 +#define BCM_LED_SRC_INTR 0x6 +#define BCM_LED_SRC_QUALITY 0x7 +#define BCM_LED_SRC_RCVLED 0x8 +#define BCM_LED_SRC_MULTICOLOR1 0xa +#define BCM_LED_SRC_OPENSHORT 0xb +#define BCM_LED_SRC_OFF 0xe /* Tied high */ +#define BCM_LED_SRC_ON 0xf /* Tied low */ + +/* + * BCM5482: Shadow registers + * Shadow values go into bits [14:10] of register 0x1c to select a shadow + * register to access. + */ +#define BCM5482_SHD_LEDS1 0x0d /* 01101: LED Selector 1 */ + /* LED3 / ~LINKSPD[2] selector */ +#define BCM5482_SHD_LEDS1_LED3(src) ((src & 0xf) << 4) + /* LED1 / ~LINKSPD[1] selector */ +#define BCM5482_SHD_LEDS1_LED1(src) ((src & 0xf) << 0) +#define BCM5482_SHD_SSD 0x14 /* 10100: Secondary SerDes control */ +#define BCM5482_SHD_SSD_LEDM 0x0008 /* SSD LED Mode enable */ +#define BCM5482_SHD_SSD_EN 0x0001 /* SSD enable */ +#define BCM5482_SHD_MODE 0x1f /* 11111: Mode Control Register */ +#define BCM5482_SHD_MODE_1000BX 0x0001 /* Enable 1000BASE-X registers */ + +/* + * BCM5482: Secondary SerDes registers + */ +#define BCM5482_SSD_1000BX_CTL 0x00 /* 1000BASE-X Control */ +#define BCM5482_SSD_1000BX_CTL_PWRDOWN 0x0800 /* Power-down SSD */ +#define BCM5482_SSD_SGMII_SLAVE 0x15 /* SGMII Slave Register */ +#define BCM5482_SSD_SGMII_SLAVE_EN 0x0002 /* Slave mode enable */ +#define BCM5482_SSD_SGMII_SLAVE_AD 0x0001 /* Slave auto-detection */ + +/* + * Device flags for PHYs that can be configured for different operating + * modes. + */ +#define PHY_BCM_FLAGS_VALID 0x80000000 +#define PHY_BCM_FLAGS_INTF_XAUI 0x00000020 +#define PHY_BCM_FLAGS_INTF_SGMII 0x00000010 +#define PHY_BCM_FLAGS_MODE_1000BX 0x00000002 +#define PHY_BCM_FLAGS_MODE_COPPER 0x00000001 + MODULE_DESCRIPTION("Broadcom PHY driver"); MODULE_AUTHOR("Maciej W. Rozycki"); MODULE_LICENSE("GPL"); +/* + * Indirect register access functions for the 1000BASE-T/100BASE-TX/10BASE-T + * 0x1c shadow registers. + */ +static int bcm54xx_shadow_read(struct phy_device *phydev, u16 shadow) +{ + phy_write(phydev, MII_BCM54XX_SHD, MII_BCM54XX_SHD_VAL(shadow)); + return MII_BCM54XX_SHD_DATA(phy_read(phydev, MII_BCM54XX_SHD)); +} + +static int bcm54xx_shadow_write(struct phy_device *phydev, u16 shadow, u16 val) +{ + return phy_write(phydev, MII_BCM54XX_SHD, + MII_BCM54XX_SHD_WRITE | + MII_BCM54XX_SHD_VAL(shadow) | + MII_BCM54XX_SHD_DATA(val)); +} + +/* + * Indirect register access functions for the Expansion Registers + * and Secondary SerDes registers (when sec_serdes=1). + */ +static int bcm54xx_exp_read(struct phy_device *phydev, + int sec_serdes, u8 regnum) +{ + int val; + + phy_write(phydev, MII_BCM54XX_EXP_SEL, + (sec_serdes ? MII_BCM54XX_EXP_SEL_SSD : + MII_BCM54XX_EXP_SEL_ER) | + regnum); + val = phy_read(phydev, MII_BCM54XX_EXP_DATA); + phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum); + + return val; +} + +static int bcm54xx_exp_write(struct phy_device *phydev, + int sec_serdes, u8 regnum, u16 val) +{ + int ret; + + phy_write(phydev, MII_BCM54XX_EXP_SEL, + (sec_serdes ? MII_BCM54XX_EXP_SEL_SSD : + MII_BCM54XX_EXP_SEL_ER) | + regnum); + ret = phy_write(phydev, MII_BCM54XX_EXP_DATA, val); + phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum); + + return ret; +} + static int bcm54xx_config_init(struct phy_device *phydev) { int reg, err; @@ -70,6 +186,87 @@ static int bcm54xx_config_init(struct phy_device *phydev) return 0; } +static int bcm5482_config_init(struct phy_device *phydev) +{ + int err, reg; + + err = bcm54xx_config_init(phydev); + + if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) { + /* + * Enable secondary SerDes and its use as an LED source + */ + reg = bcm54xx_shadow_read(phydev, BCM5482_SHD_SSD); + bcm54xx_shadow_write(phydev, BCM5482_SHD_SSD, + reg | + BCM5482_SHD_SSD_LEDM | + BCM5482_SHD_SSD_EN); + + /* + * Enable SGMII slave mode and auto-detection + */ + reg = bcm54xx_exp_read(phydev, 1, BCM5482_SSD_SGMII_SLAVE); + bcm54xx_exp_write(phydev, 1, BCM5482_SSD_SGMII_SLAVE, + reg | + BCM5482_SSD_SGMII_SLAVE_EN | + BCM5482_SSD_SGMII_SLAVE_AD); + + /* + * Disable secondary SerDes powerdown + */ + reg = bcm54xx_exp_read(phydev, 1, BCM5482_SSD_1000BX_CTL); + bcm54xx_exp_write(phydev, 1, BCM5482_SSD_1000BX_CTL, + reg & ~BCM5482_SSD_1000BX_CTL_PWRDOWN); + + /* + * Select 1000BASE-X register set (primary SerDes) + */ + reg = bcm54xx_shadow_read(phydev, BCM5482_SHD_MODE); + bcm54xx_shadow_write(phydev, BCM5482_SHD_MODE, + reg | BCM5482_SHD_MODE_1000BX); + + /* + * LED1=ACTIVITYLED, LED3=LINKSPD[2] + * (Use LED1 as secondary SerDes ACTIVITY LED) + */ + bcm54xx_shadow_write(phydev, BCM5482_SHD_LEDS1, + BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_ACTIVITYLED) | + BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_LINKSPD2)); + + /* + * Auto-negotiation doesn't seem to work quite right + * in this mode, so we disable it and force it to the + * right speed/duplex setting. Only 'link status' + * is important. + */ + phydev->autoneg = AUTONEG_DISABLE; + phydev->speed = SPEED_1000; + phydev->duplex = DUPLEX_FULL; + } + + return err; +} + +static int bcm5482_read_status(struct phy_device *phydev) +{ + int err; + + err = genphy_read_status(phydev); + + if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) { + /* + * Only link status matters for 1000Base-X mode, so force + * 1000 Mbit/s full-duplex status + */ + if (phydev->link) { + phydev->speed = SPEED_1000; + phydev->duplex = DUPLEX_FULL; + } + } + + return err; +} + static int bcm54xx_ack_interrupt(struct phy_device *phydev) { int reg; @@ -210,9 +407,9 @@ static struct phy_driver bcm5482_driver = { .name = "Broadcom BCM5482", .features = PHY_GBIT_FEATURES, .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, - .config_init = bcm54xx_config_init, + .config_init = bcm5482_config_init, .config_aneg = genphy_config_aneg, - .read_status = genphy_read_status, + .read_status = bcm5482_read_status, .ack_interrupt = bcm54xx_ack_interrupt, .config_intr = bcm54xx_config_intr, .driver = { .owner = THIS_MODULE }, -- cgit v1.2.3-70-g09d2 From 1b0771ab3ea102ce77e9ca83abc500e542402e54 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Sat, 17 May 2008 06:46:19 +0100 Subject: PHYLIB: Kconfig: Complete the list of Broadcom PHYs supported Add Broadcom PHYs supported missing from the description. Signed-off-by: Maciej W. Rozycki Signed-off-by: Jeff Garzik --- drivers/net/phy/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 6bf9e76b0a0..35b431991cc 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -53,7 +53,8 @@ config SMSC_PHY config BROADCOM_PHY tristate "Drivers for Broadcom PHYs" ---help--- - Currently supports the BCM5411, BCM5421 and BCM5461 PHYs. + Currently supports the BCM5411, BCM5421, BCM5461, BCM5464, BCM5481 + and BCM5482 PHYs. config ICPLUS_PHY tristate "Drivers for ICPlus PHYs" -- cgit v1.2.3-70-g09d2 From 92fbc1c146d1d358c1ecc4e38361089ff929a02c Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 16 May 2008 10:35:24 -0700 Subject: 3c515: fix using pnp_get_resource when CONFIG_ISAPNP=n 3c515.c uses pnp_irq(), which calls pnp_get_resource(), which is not defined when CONFIG_PNP=n, so in that case, get the IRQ from a hardware register. 3c515.c:(.text+0x3adc0): undefined reference to `pnp_get_resource' Signed-off-by: Randy Dunlap Signed-off-by: Jeff Garzik --- drivers/net/3c515.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c index 105a8c7ca7e..e4e3241628d 100644 --- a/drivers/net/3c515.c +++ b/drivers/net/3c515.c @@ -572,12 +572,16 @@ static int corkscrew_setup(struct net_device *dev, int ioaddr, int irq; DECLARE_MAC_BUF(mac); +#ifdef __ISAPNP__ if (idev) { irq = pnp_irq(idev, 0); vp->dev = &idev->dev; } else { irq = inw(ioaddr + 0x2002) & 15; } +#else + irq = inw(ioaddr + 0x2002) & 15; +#endif dev->base_addr = ioaddr; dev->irq = irq; -- cgit v1.2.3-70-g09d2 From f70c5253b41444fd2779e1f76bfe25811d9b8c23 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 20 Apr 2008 12:22:36 +0100 Subject: [RTC] remove references to asm/mach/time.h asm/mach/time.h is the ARM header file for setting up kernel ticker timekeeping (be that the old jiffy interrupt or the new clocksource.) RTC drivers have no business using this header file, and in fact do not require it. Build tested on at91sam9rl, omap and s3c2410 configurations. Acked-by: Alessandro Zummo Acked-by: Andrew Victor Signed-off-by: Russell King --- drivers/rtc/rtc-at91rm9200.c | 2 -- drivers/rtc/rtc-at91sam9.c | 1 - drivers/rtc/rtc-omap.c | 1 - drivers/rtc/rtc-s3c.c | 2 -- 4 files changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index 39e64ab1ecb..2af1e6fb71c 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c @@ -31,8 +31,6 @@ #include #include -#include - #include diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index 38d8742a4bd..f0246ef413a 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -19,7 +19,6 @@ #include #include -#include #include #include diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index 58f81c77494..eb23d8423f4 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -22,7 +22,6 @@ #include #include -#include /* The OMAP1 RTC is a year/month/day/hours/minutes/seconds BCD clock diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index f26e0cad8f1..2c6e4671e38 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -28,8 +28,6 @@ #include #include -#include - #include /* I have yet to find an S3C implementation with more than one -- cgit v1.2.3-70-g09d2 From 2dba8518b7761aee3ba757b298efa15dd34eff18 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 20 Apr 2008 12:08:04 +0100 Subject: [RTC] rtc-pl031: use proper resources, use proper apis, clean up includes Clean up PL031 RTC includes, make driver use proper resource checking, and use amba bus specific accessors. Acked-by: Alessandro Zummo Signed-off-by: Russell King --- drivers/rtc/rtc-pl031.c | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c index 2fd49edcc71..08b4610ec5a 100644 --- a/drivers/rtc/rtc-pl031.c +++ b/drivers/rtc/rtc-pl031.c @@ -12,23 +12,12 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ - -#include #include #include #include -#include #include -#include -#include -#include - #include - -#include -#include -#include -#include +#include /* * Register definitions @@ -142,13 +131,12 @@ static int pl031_remove(struct amba_device *adev) { struct pl031_local *ldata = dev_get_drvdata(&adev->dev); - if (ldata) { - dev_set_drvdata(&adev->dev, NULL); - free_irq(adev->irq[0], ldata->rtc); - rtc_device_unregister(ldata->rtc); - iounmap(ldata->base); - kfree(ldata); - } + amba_set_drvdata(adev, NULL); + free_irq(adev->irq[0], ldata->rtc); + rtc_device_unregister(ldata->rtc); + iounmap(ldata->base); + kfree(ldata); + amba_release_regions(adev); return 0; } @@ -158,13 +146,15 @@ static int pl031_probe(struct amba_device *adev, void *id) int ret; struct pl031_local *ldata; + ret = amba_request_regions(adev, NULL); + if (ret) + goto err_req; ldata = kmalloc(sizeof(struct pl031_local), GFP_KERNEL); if (!ldata) { ret = -ENOMEM; goto out; } - dev_set_drvdata(&adev->dev, ldata); ldata->base = ioremap(adev->res.start, adev->res.end - adev->res.start + 1); @@ -173,6 +163,8 @@ static int pl031_probe(struct amba_device *adev, void *id) goto out_no_remap; } + amba_set_drvdata(adev, ldata); + if (request_irq(adev->irq[0], pl031_interrupt, IRQF_DISABLED, "rtc-pl031", ldata->rtc)) { ret = -EIO; @@ -192,10 +184,12 @@ out_no_rtc: free_irq(adev->irq[0], ldata->rtc); out_no_irq: iounmap(ldata->base); + amba_set_drvdata(adev, NULL); out_no_remap: - dev_set_drvdata(&adev->dev, NULL); kfree(ldata); out: + amba_release_regions(adev); +err_req: return ret; } -- cgit v1.2.3-70-g09d2 From a190901c6b5f1f4a31681e8c69d811a4f9426e2b Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 20 Apr 2008 12:08:36 +0100 Subject: [RTC] rtc-pl030: add driver, remove old non-rtc lib driver Convert Integrator PL030 RTC driver to use the RTC class interfaces. Acked-by: Alessandro Zummo Signed-off-by: Russell King --- arch/arm/mach-integrator/Makefile | 2 +- arch/arm/mach-integrator/time.c | 223 -------------------------------------- drivers/rtc/Kconfig | 10 ++ drivers/rtc/Makefile | 1 + drivers/rtc/rtc-pl030.c | 217 +++++++++++++++++++++++++++++++++++++ 5 files changed, 229 insertions(+), 224 deletions(-) delete mode 100644 arch/arm/mach-integrator/time.c create mode 100644 drivers/rtc/rtc-pl030.c (limited to 'drivers') diff --git a/arch/arm/mach-integrator/Makefile b/arch/arm/mach-integrator/Makefile index 158daaf9e3b..6a5ef8d30b1 100644 --- a/arch/arm/mach-integrator/Makefile +++ b/arch/arm/mach-integrator/Makefile @@ -4,7 +4,7 @@ # Object file lists. -obj-y := clock.o core.o lm.o time.o +obj-y := clock.o core.o lm.o obj-$(CONFIG_ARCH_INTEGRATOR_AP) += integrator_ap.o obj-$(CONFIG_ARCH_INTEGRATOR_CP) += integrator_cp.o diff --git a/arch/arm/mach-integrator/time.c b/arch/arm/mach-integrator/time.c deleted file mode 100644 index 8508a0db3ea..00000000000 --- a/arch/arm/mach-integrator/time.c +++ /dev/null @@ -1,223 +0,0 @@ -/* - * linux/arch/arm/mach-integrator/time.c - * - * Copyright (C) 2000-2001 Deep Blue Solutions Ltd. - * - * 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. - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#define RTC_DR (0) -#define RTC_MR (4) -#define RTC_STAT (8) -#define RTC_EOI (8) -#define RTC_LR (12) -#define RTC_CR (16) -#define RTC_CR_MIE (1 << 0) - -extern int (*set_rtc)(void); -static void __iomem *rtc_base; - -static int integrator_set_rtc(void) -{ - __raw_writel(xtime.tv_sec, rtc_base + RTC_LR); - return 1; -} - -static int integrator_rtc_read_alarm(struct rtc_wkalrm *alrm) -{ - rtc_time_to_tm(readl(rtc_base + RTC_MR), &alrm->time); - return 0; -} - -static inline int integrator_rtc_set_alarm(struct rtc_wkalrm *alrm) -{ - unsigned long time; - int ret; - - /* - * At the moment, we can only deal with non-wildcarded alarm times. - */ - ret = rtc_valid_tm(&alrm->time); - if (ret == 0) - ret = rtc_tm_to_time(&alrm->time, &time); - if (ret == 0) - writel(time, rtc_base + RTC_MR); - return ret; -} - -static int integrator_rtc_read_time(struct rtc_time *tm) -{ - rtc_time_to_tm(readl(rtc_base + RTC_DR), tm); - return 0; -} - -/* - * Set the RTC time. Unfortunately, we can't accurately set - * the point at which the counter updates. - * - * Also, since RTC_LR is transferred to RTC_CR on next rising - * edge of the 1Hz clock, we must write the time one second - * in advance. - */ -static inline int integrator_rtc_set_time(struct rtc_time *tm) -{ - unsigned long time; - int ret; - - ret = rtc_tm_to_time(tm, &time); - if (ret == 0) - writel(time + 1, rtc_base + RTC_LR); - - return ret; -} - -static struct rtc_ops rtc_ops = { - .owner = THIS_MODULE, - .read_time = integrator_rtc_read_time, - .set_time = integrator_rtc_set_time, - .read_alarm = integrator_rtc_read_alarm, - .set_alarm = integrator_rtc_set_alarm, -}; - -static irqreturn_t arm_rtc_interrupt(int irq, void *dev_id) -{ - writel(0, rtc_base + RTC_EOI); - return IRQ_HANDLED; -} - -static int rtc_probe(struct amba_device *dev, void *id) -{ - int ret; - - if (rtc_base) - return -EBUSY; - - ret = amba_request_regions(dev, NULL); - if (ret) - goto out; - - rtc_base = ioremap(dev->res.start, SZ_4K); - if (!rtc_base) { - ret = -ENOMEM; - goto res_out; - } - - __raw_writel(0, rtc_base + RTC_CR); - __raw_writel(0, rtc_base + RTC_EOI); - - xtime.tv_sec = __raw_readl(rtc_base + RTC_DR); - - /* note that 'dev' is merely used for irq disambiguation; - * it is not actually referenced in the irq handler - */ - ret = request_irq(dev->irq[0], arm_rtc_interrupt, IRQF_DISABLED, - "rtc-pl030", dev); - if (ret) - goto map_out; - - ret = register_rtc(&rtc_ops); - if (ret) - goto irq_out; - - set_rtc = integrator_set_rtc; - return 0; - - irq_out: - free_irq(dev->irq[0], dev); - map_out: - iounmap(rtc_base); - rtc_base = NULL; - res_out: - amba_release_regions(dev); - out: - return ret; -} - -static int rtc_remove(struct amba_device *dev) -{ - set_rtc = NULL; - - writel(0, rtc_base + RTC_CR); - - free_irq(dev->irq[0], dev); - unregister_rtc(&rtc_ops); - - iounmap(rtc_base); - rtc_base = NULL; - amba_release_regions(dev); - - return 0; -} - -static struct timespec rtc_delta; - -static int rtc_suspend(struct amba_device *dev, pm_message_t state) -{ - struct timespec rtc; - - rtc.tv_sec = readl(rtc_base + RTC_DR); - rtc.tv_nsec = 0; - save_time_delta(&rtc_delta, &rtc); - - return 0; -} - -static int rtc_resume(struct amba_device *dev) -{ - struct timespec rtc; - - rtc.tv_sec = readl(rtc_base + RTC_DR); - rtc.tv_nsec = 0; - restore_time_delta(&rtc_delta, &rtc); - - return 0; -} - -static struct amba_id rtc_ids[] = { - { - .id = 0x00041030, - .mask = 0x000fffff, - }, - { 0, 0 }, -}; - -static struct amba_driver rtc_driver = { - .drv = { - .name = "rtc-pl030", - }, - .probe = rtc_probe, - .remove = rtc_remove, - .suspend = rtc_suspend, - .resume = rtc_resume, - .id_table = rtc_ids, -}; - -static int __init integrator_rtc_init(void) -{ - return amba_driver_register(&rtc_driver); -} - -static void __exit integrator_rtc_exit(void) -{ - amba_driver_unregister(&rtc_driver); -} - -module_init(integrator_rtc_init); -module_exit(integrator_rtc_exit); diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 6cc2c033023..1b26eeb52c9 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -458,6 +458,16 @@ config RTC_DRV_VR41XX To compile this driver as a module, choose M here: the module will be called rtc-vr41xx. +config RTC_DRV_PL030 + tristate "ARM AMBA PL030 RTC" + depends on ARM_AMBA + help + If you say Y here you will get access to ARM AMBA + PrimeCell PL030 RTC found on certain ARM SOCs. + + To compile this driver as a module, choose M here: the + module will be called rtc-pl030. + config RTC_DRV_PL031 tristate "ARM AMBA PL031 RTC" depends on ARM_AMBA diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 872f1218ff9..af3ee6652ce 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -40,6 +40,7 @@ obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o +obj-$(CONFIG_RTC_DRV_PL030) += rtc-pl030.o obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o diff --git a/drivers/rtc/rtc-pl030.c b/drivers/rtc/rtc-pl030.c new file mode 100644 index 00000000000..8448eeb9d67 --- /dev/null +++ b/drivers/rtc/rtc-pl030.c @@ -0,0 +1,217 @@ +/* + * linux/drivers/rtc/rtc-pl030.c + * + * Copyright (C) 2000-2001 Deep Blue Solutions Ltd. + * + * 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. + */ +#include +#include +#include +#include +#include +#include + +#define RTC_DR (0) +#define RTC_MR (4) +#define RTC_STAT (8) +#define RTC_EOI (8) +#define RTC_LR (12) +#define RTC_CR (16) +#define RTC_CR_MIE (1 << 0) + +struct pl030_rtc { + struct rtc_device *rtc; + void __iomem *base; +}; + +static irqreturn_t pl030_interrupt(int irq, void *dev_id) +{ + struct pl030_rtc *rtc = dev_id; + writel(0, rtc->base + RTC_EOI); + return IRQ_HANDLED; +} + +static int pl030_open(struct device *dev) +{ + return 0; +} + +static void pl030_release(struct device *dev) +{ +} + +static int pl030_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) +{ + return -ENOIOCTLCMD; +} + +static int pl030_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct pl030_rtc *rtc = dev_get_drvdata(dev); + + rtc_time_to_tm(readl(rtc->base + RTC_MR), &alrm->time); + return 0; +} + +static int pl030_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct pl030_rtc *rtc = dev_get_drvdata(dev); + unsigned long time; + int ret; + + /* + * At the moment, we can only deal with non-wildcarded alarm times. + */ + ret = rtc_valid_tm(&alrm->time); + if (ret == 0) + ret = rtc_tm_to_time(&alrm->time, &time); + if (ret == 0) + writel(time, rtc->base + RTC_MR); + return ret; +} + +static int pl030_read_time(struct device *dev, struct rtc_time *tm) +{ + struct pl030_rtc *rtc = dev_get_drvdata(dev); + + rtc_time_to_tm(readl(rtc->base + RTC_DR), tm); + + return 0; +} + +/* + * Set the RTC time. Unfortunately, we can't accurately set + * the point at which the counter updates. + * + * Also, since RTC_LR is transferred to RTC_CR on next rising + * edge of the 1Hz clock, we must write the time one second + * in advance. + */ +static int pl030_set_time(struct device *dev, struct rtc_time *tm) +{ + struct pl030_rtc *rtc = dev_get_drvdata(dev); + unsigned long time; + int ret; + + ret = rtc_tm_to_time(tm, &time); + if (ret == 0) + writel(time + 1, rtc->base + RTC_LR); + + return ret; +} + +static const struct rtc_class_ops pl030_ops = { + .open = pl030_open, + .release = pl030_release, + .ioctl = pl030_ioctl, + .read_time = pl030_read_time, + .set_time = pl030_set_time, + .read_alarm = pl030_read_alarm, + .set_alarm = pl030_set_alarm, +}; + +static int pl030_probe(struct amba_device *dev, void *id) +{ + struct pl030_rtc *rtc; + int ret; + + ret = amba_request_regions(dev, NULL); + if (ret) + goto err_req; + + rtc = kmalloc(sizeof(*rtc), GFP_KERNEL); + if (!rtc) { + ret = -ENOMEM; + goto err_rtc; + } + + rtc->base = ioremap(dev->res.start, SZ_4K); + if (!rtc->base) { + ret = -ENOMEM; + goto err_map; + } + + __raw_writel(0, rtc->base + RTC_CR); + __raw_writel(0, rtc->base + RTC_EOI); + + amba_set_drvdata(dev, rtc); + + ret = request_irq(dev->irq[0], pl030_interrupt, IRQF_DISABLED, + "rtc-pl030", rtc); + if (ret) + goto err_irq; + + rtc->rtc = rtc_device_register("pl030", &dev->dev, &pl030_ops, + THIS_MODULE); + if (IS_ERR(rtc->rtc)) { + ret = PTR_ERR(rtc->rtc); + goto err_reg; + } + + return 0; + + err_reg: + free_irq(dev->irq[0], rtc); + err_irq: + iounmap(rtc->base); + err_map: + kfree(rtc); + err_rtc: + amba_release_regions(dev); + err_req: + return ret; +} + +static int pl030_remove(struct amba_device *dev) +{ + struct pl030_rtc *rtc = amba_get_drvdata(dev); + + amba_set_drvdata(dev, NULL); + + writel(0, rtc->base + RTC_CR); + + free_irq(dev->irq[0], rtc); + rtc_device_unregister(rtc->rtc); + iounmap(rtc->base); + kfree(rtc); + amba_release_regions(dev); + + return 0; +} + +static struct amba_id pl030_ids[] = { + { + .id = 0x00041030, + .mask = 0x000fffff, + }, + { 0, 0 }, +}; + +static struct amba_driver pl030_driver = { + .drv = { + .name = "rtc-pl030", + }, + .probe = pl030_probe, + .remove = pl030_remove, + .id_table = pl030_ids, +}; + +static int __init pl030_init(void) +{ + return amba_driver_register(&pl030_driver); +} + +static void __exit pl030_exit(void) +{ + amba_driver_unregister(&pl030_driver); +} + +module_init(pl030_init); +module_exit(pl030_exit); + +MODULE_AUTHOR("Russell King "); +MODULE_DESCRIPTION("ARM AMBA PL030 RTC Driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-70-g09d2 From 7da285b626860eb6d35e08ae33eba90f0e83ad58 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 20 Apr 2008 12:26:48 +0100 Subject: [RTC] remove unused asm/rtc.h includes from ARM RTC drivers On ARM, asm/rtc.h only contains definitions for the predecessor to the RTC class support. RTC class drivers should not be including this include. Build tested on at91sam9rl and s3c2410 configurations. Acked-by: Alessandro Zummo Signed-off-by: Russell King --- drivers/rtc/rtc-at91rm9200.c | 2 -- drivers/rtc/rtc-s3c.c | 2 -- 2 files changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index 2af1e6fb71c..9c3db934cc2 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c @@ -29,8 +29,6 @@ #include #include -#include - #include diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 2c6e4671e38..fed86e507fd 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -26,8 +26,6 @@ #include #include #include -#include - #include /* I have yet to find an S3C implementation with more than one -- cgit v1.2.3-70-g09d2 From 797276ec9e4d2ee210e11068a2ce815394fe8c58 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 20 Apr 2008 12:30:41 +0100 Subject: [RTC] rtc-sa1100: remove dependence on asm/rtc.h Move the two functions rtc-sa1100 wants from the old ARM RTC library into the rtc-sa1100 driver. Acked-by: Alessandro Zummo Signed-off-by: Russell King --- drivers/rtc/rtc-sa1100.c | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index 82f62d25f92..e31a687b44b 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -33,7 +33,6 @@ #include #include -#include #ifdef CONFIG_ARCH_PXA #include @@ -47,6 +46,42 @@ static unsigned long rtc_freq = 1024; static struct rtc_time rtc_alarm; static DEFINE_SPINLOCK(sa1100_rtc_lock); +static inline int rtc_periodic_alarm(struct rtc_time *tm) +{ + return (tm->tm_year == -1) || + ((unsigned)tm->tm_mon >= 12) || + ((unsigned)(tm->tm_mday - 1) >= 31) || + ((unsigned)tm->tm_hour > 23) || + ((unsigned)tm->tm_min > 59) || + ((unsigned)tm->tm_sec > 59); +} + +/* + * Calculate the next alarm time given the requested alarm time mask + * and the current time. + */ +static void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now, struct rtc_time *alrm) +{ + unsigned long next_time; + unsigned long now_time; + + next->tm_year = now->tm_year; + next->tm_mon = now->tm_mon; + next->tm_mday = now->tm_mday; + next->tm_hour = alrm->tm_hour; + next->tm_min = alrm->tm_min; + next->tm_sec = alrm->tm_sec; + + rtc_tm_to_time(now, &now_time); + rtc_tm_to_time(next, &next_time); + + if (next_time < now_time) { + /* Advance one day */ + next_time += 60 * 60 * 24; + rtc_time_to_tm(next_time, next); + } +} + static int rtc_update_alarm(struct rtc_time *alrm) { struct rtc_time alarm_tm, now_tm; -- cgit v1.2.3-70-g09d2 From 855e1111f3806905b410b745e696fec4f5dac724 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 16 Apr 2008 16:37:28 -0700 Subject: tg3: remove unneeded semicolons Remove extraneous semicolons after switch and conditional statements. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/tg3.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 07b3f77e762..ae11c672476 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -1480,7 +1480,7 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) "requested.\n", tp->dev->name, state); return -EINVAL; - }; + } power_control |= PCI_PM_CTRL_PME_ENABLE; @@ -1906,7 +1906,7 @@ static void tg3_aux_stat_to_speed_duplex(struct tg3 *tp, u32 val, u16 *speed, u8 *speed = SPEED_INVALID; *duplex = DUPLEX_INVALID; break; - }; + } } static void tg3_phy_copper_begin(struct tg3 *tp) @@ -2018,7 +2018,7 @@ static void tg3_phy_copper_begin(struct tg3 *tp) case SPEED_1000: bmcr |= TG3_BMCR_SPEED1000; break; - }; + } if (tp->link_config.duplex == DUPLEX_FULL) bmcr |= BMCR_FULLDPLX; @@ -2716,7 +2716,7 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp, default: ret = ANEG_FAILED; break; - }; + } return ret; } @@ -3558,7 +3558,7 @@ static int tg3_alloc_rx_skb(struct tg3 *tp, u32 opaque_key, default: return -EINVAL; - }; + } /* Do not overwrite any of the map or rp information * until we are sure we can commit to a new buffer. @@ -3618,7 +3618,7 @@ static void tg3_recycle_rx(struct tg3 *tp, u32 opaque_key, default: return; - }; + } dest_map->skb = src_map->skb; pci_unmap_addr_set(dest_map, mapping, @@ -4961,7 +4961,7 @@ static int tg3_stop_block(struct tg3 *tp, unsigned long ofs, u32 enable_bit, int default: break; - }; + } } val = tr32(ofs); @@ -5203,7 +5203,7 @@ static void tg3_write_sig_pre_reset(struct tg3 *tp, int kind) default: break; - }; + } } if (kind == RESET_KIND_INIT || @@ -5228,7 +5228,7 @@ static void tg3_write_sig_post_reset(struct tg3 *tp, int kind) default: break; - }; + } } if (kind == RESET_KIND_SHUTDOWN) @@ -5257,7 +5257,7 @@ static void tg3_write_sig_legacy(struct tg3 *tp, int kind) default: break; - }; + } } } @@ -7282,7 +7282,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) default: break; - }; + } if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) /* Write our heartbeat update interval to APE. */ @@ -10879,7 +10879,7 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) LED_CTRL_MODE_PHY_2); break; - }; + } if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) && @@ -12178,7 +12178,7 @@ static u32 __devinit tg3_calc_dma_bndry(struct tg3 *tp, u32 val) val |= (DMA_RWCTRL_READ_BNDRY_384_PCIX | DMA_RWCTRL_WRITE_BNDRY_384_PCIX); break; - }; + } } else if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) { switch (cacheline_size) { case 16: @@ -12195,7 +12195,7 @@ static u32 __devinit tg3_calc_dma_bndry(struct tg3 *tp, u32 val) val &= ~DMA_RWCTRL_WRITE_BNDRY_DISAB_PCIE; val |= DMA_RWCTRL_WRITE_BNDRY_128_PCIE; break; - }; + } } else { switch (cacheline_size) { case 16: @@ -12239,7 +12239,7 @@ static u32 __devinit tg3_calc_dma_bndry(struct tg3 *tp, u32 val) val |= (DMA_RWCTRL_READ_BNDRY_1024 | DMA_RWCTRL_WRITE_BNDRY_1024); break; - }; + } } out: @@ -12599,7 +12599,7 @@ static char * __devinit tg3_phy_string(struct tg3 *tp) case PHY_ID_BCM8002: return "8002/serdes"; case 0: return "serdes"; default: return "unknown"; - }; + } } static char * __devinit tg3_bus_string(struct tg3 *tp, char *str) -- cgit v1.2.3-70-g09d2 From b102df14d75753bae216f43579eebf3f9d10cd27 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 16 Apr 2008 16:37:29 -0700 Subject: atl1: use netdev_alloc_skb Use netdev_alloc_skb for rx buffer allocation. This sets skb->dev and can be overriden for NUMA machines. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/atlx/atl1.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index 6e4c80d41b0..db04bfb3460 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -1876,7 +1876,8 @@ static u16 atl1_alloc_rx_buffers(struct atl1_adapter *adapter) rfd_desc = ATL1_RFD_DESC(rfd_ring, rfd_next_to_use); - skb = dev_alloc_skb(adapter->rx_buffer_len + NET_IP_ALIGN); + skb = netdev_alloc_skb(adapter->netdev, + adapter->rx_buffer_len + NET_IP_ALIGN); if (unlikely(!skb)) { /* Better luck next round */ adapter->net_stats.rx_dropped++; -- cgit v1.2.3-70-g09d2 From 3f7a3535a6805870f265f39c92c24b136cb967f4 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Mon, 5 May 2008 13:34:31 +0100 Subject: sb1250: use netdev_alloc_skb Use netdev_alloc_skb. This sets skb->dev and allows arch specific allocation. Also simplify and cleanup the alignment code. Signed-off-by: Maciej W. Rozycki Signed-off-by: Jeff Garzik --- drivers/net/sb1250-mac.c | 67 ++++++++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index 29519902517..fe41e4ec21e 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -179,8 +179,7 @@ enum sbmac_state { #define SBMAC_MAX_TXDESCR 256 #define SBMAC_MAX_RXDESCR 256 -#define ETHER_ALIGN 2 -#define ETHER_ADDR_LEN 6 +#define ETHER_ADDR_LEN 6 #define ENET_PACKET_SIZE 1518 /*#define ENET_PACKET_SIZE 9216 */ @@ -262,8 +261,6 @@ struct sbmac_softc { spinlock_t sbm_lock; /* spin lock */ int sbm_devflags; /* current device flags */ - int sbm_buffersize; - /* * Controller-specific things */ @@ -305,10 +302,11 @@ struct sbmac_softc { static void sbdma_initctx(struct sbmacdma *d, struct sbmac_softc *s, int chan, int txrx, int maxdescr); static void sbdma_channel_start(struct sbmacdma *d, int rxtx); -static int sbdma_add_rcvbuffer(struct sbmacdma *d, struct sk_buff *m); +static int sbdma_add_rcvbuffer(struct sbmac_softc *sc, struct sbmacdma *d, + struct sk_buff *m); static int sbdma_add_txbuffer(struct sbmacdma *d, struct sk_buff *m); static void sbdma_emptyring(struct sbmacdma *d); -static void sbdma_fillring(struct sbmacdma *d); +static void sbdma_fillring(struct sbmac_softc *sc, struct sbmacdma *d); static int sbdma_rx_process(struct sbmac_softc *sc, struct sbmacdma *d, int work_to_do, int poll); static void sbdma_tx_process(struct sbmac_softc *sc, struct sbmacdma *d, @@ -777,16 +775,13 @@ static void sbdma_channel_stop(struct sbmacdma *d) d->sbdma_remptr = NULL; } -static void sbdma_align_skb(struct sk_buff *skb,int power2,int offset) +static inline void sbdma_align_skb(struct sk_buff *skb, + unsigned int power2, unsigned int offset) { - unsigned long addr; - unsigned long newaddr; - - addr = (unsigned long) skb->data; - - newaddr = (addr + power2 - 1) & ~(power2 - 1); + unsigned char *addr = skb->data; + unsigned char *newaddr = PTR_ALIGN(addr, power2); - skb_reserve(skb,newaddr-addr+offset); + skb_reserve(skb, newaddr - addr + offset); } @@ -797,7 +792,8 @@ static void sbdma_align_skb(struct sk_buff *skb,int power2,int offset) * this queues a buffer for inbound packets. * * Input parameters: - * d - DMA channel descriptor + * sc - softc structure + * d - DMA channel descriptor * sb - sk_buff to add, or NULL if we should allocate one * * Return value: @@ -806,8 +802,10 @@ static void sbdma_align_skb(struct sk_buff *skb,int power2,int offset) ********************************************************************* */ -static int sbdma_add_rcvbuffer(struct sbmacdma *d, struct sk_buff *sb) +static int sbdma_add_rcvbuffer(struct sbmac_softc *sc, struct sbmacdma *d, + struct sk_buff *sb) { + struct net_device *dev = sc->sbm_dev; struct sbdmadscr *dsc; struct sbdmadscr *nextdsc; struct sk_buff *sb_new = NULL; @@ -848,14 +846,16 @@ static int sbdma_add_rcvbuffer(struct sbmacdma *d, struct sk_buff *sb) */ if (sb == NULL) { - sb_new = dev_alloc_skb(ENET_PACKET_SIZE + SMP_CACHE_BYTES * 2 + ETHER_ALIGN); + sb_new = netdev_alloc_skb(dev, ENET_PACKET_SIZE + + SMP_CACHE_BYTES * 2 + + NET_IP_ALIGN); if (sb_new == NULL) { pr_info("%s: sk_buff allocation failed\n", d->sbdma_eth->sbm_dev->name); return -ENOBUFS; } - sbdma_align_skb(sb_new, SMP_CACHE_BYTES, ETHER_ALIGN); + sbdma_align_skb(sb_new, SMP_CACHE_BYTES, NET_IP_ALIGN); } else { sb_new = sb; @@ -874,10 +874,10 @@ static int sbdma_add_rcvbuffer(struct sbmacdma *d, struct sk_buff *sb) * Do not interrupt per DMA transfer. */ dsc->dscr_a = virt_to_phys(sb_new->data) | - V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize+ETHER_ALIGN)) | 0; + V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize + NET_IP_ALIGN)) | 0; #else dsc->dscr_a = virt_to_phys(sb_new->data) | - V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize+ETHER_ALIGN)) | + V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize + NET_IP_ALIGN)) | M_DMA_DSCRA_INTERRUPT; #endif @@ -1032,18 +1032,19 @@ static void sbdma_emptyring(struct sbmacdma *d) * with sk_buffs * * Input parameters: - * d - DMA channel + * sc - softc structure + * d - DMA channel * * Return value: * nothing ********************************************************************* */ -static void sbdma_fillring(struct sbmacdma *d) +static void sbdma_fillring(struct sbmac_softc *sc, struct sbmacdma *d) { int idx; - for (idx = 0; idx < SBMAC_MAX_RXDESCR-1; idx++) { - if (sbdma_add_rcvbuffer(d,NULL) != 0) + for (idx = 0; idx < SBMAC_MAX_RXDESCR - 1; idx++) { + if (sbdma_add_rcvbuffer(sc, d, NULL) != 0) break; } } @@ -1159,10 +1160,11 @@ again: * packet and put it right back on the receive ring. */ - if (unlikely (sbdma_add_rcvbuffer(d,NULL) == - -ENOBUFS)) { + if (unlikely(sbdma_add_rcvbuffer(sc, d, NULL) == + -ENOBUFS)) { dev->stats.rx_dropped++; - sbdma_add_rcvbuffer(d,sb); /* re-add old buffer */ + /* Re-add old buffer */ + sbdma_add_rcvbuffer(sc, d, sb); /* No point in continuing at the moment */ printk(KERN_ERR "dropped packet (1)\n"); d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr); @@ -1212,7 +1214,7 @@ again: * put it back on the receive ring. */ dev->stats.rx_errors++; - sbdma_add_rcvbuffer(d,sb); + sbdma_add_rcvbuffer(sc, d, sb); } @@ -1570,7 +1572,7 @@ static void sbmac_channel_start(struct sbmac_softc *s) * Fill the receive ring */ - sbdma_fillring(&(s->sbm_rxdma)); + sbdma_fillring(s, &(s->sbm_rxdma)); /* * Turn on the rest of the bits in the enable register @@ -2312,13 +2314,6 @@ static int sbmac_init(struct platform_device *pldev, long long base) dev->dev_addr[i] = eaddr[i]; } - - /* - * Init packet size - */ - - sc->sbm_buffersize = ENET_PACKET_SIZE + SMP_CACHE_BYTES * 2 + ETHER_ALIGN; - /* * Initialize context (get pointers to registers and stuff), then * allocate the memory for the descriptor tables. -- cgit v1.2.3-70-g09d2 From d27e7c3f6c82297611d1e1ee9476a2f31b3e89df Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 16 Apr 2008 16:37:37 -0700 Subject: ixp2000: use netdev_alloc_skb Use netdev_alloc_skb. This sets skb->dev and allows arch specific allocation. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/ixp2000/ixpdev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ixp2000/ixpdev.c b/drivers/net/ixp2000/ixpdev.c index 484cb2ba717..7111c65f0b3 100644 --- a/drivers/net/ixp2000/ixpdev.c +++ b/drivers/net/ixp2000/ixpdev.c @@ -108,14 +108,14 @@ static int ixpdev_rx(struct net_device *dev, int processed, int budget) if (unlikely(!netif_running(nds[desc->channel]))) goto err; - skb = dev_alloc_skb(desc->pkt_length + 2); + skb = netdev_alloc_skb(dev, desc->pkt_length + 2); if (likely(skb != NULL)) { skb_reserve(skb, 2); skb_copy_to_linear_data(skb, buf, desc->pkt_length); skb_put(skb, desc->pkt_length); skb->protocol = eth_type_trans(skb, nds[desc->channel]); - skb->dev->last_rx = jiffies; + dev->last_rx = jiffies; netif_receive_skb(skb); } -- cgit v1.2.3-70-g09d2 From 8eb6013189e03aa21aa53fd72c092713fdb30e44 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 16 Apr 2008 16:37:38 -0700 Subject: hamachi: use netdev_alloc_skb Use netdev_alloc_skb. This sets skb->dev and allows arch specific allocation. Remove dead code and dead comments. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/hamachi.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index e5c2380f50c..3199526bcec 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -1140,11 +1140,11 @@ static void hamachi_tx_timeout(struct net_device *dev) } /* Fill in the Rx buffers. Handle allocation failure gracefully. */ for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb = dev_alloc_skb(hmp->rx_buf_sz); + struct sk_buff *skb = netdev_alloc_skb(dev, hmp->rx_buf_sz); hmp->rx_skbuff[i] = skb; if (skb == NULL) break; - skb->dev = dev; /* Mark as being used by this device. */ + skb_reserve(skb, 2); /* 16 byte align the IP header. */ hmp->rx_ring[i].addr = cpu_to_leXX(pci_map_single(hmp->pci_dev, skb->data, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE)); @@ -1178,14 +1178,6 @@ static void hamachi_init_ring(struct net_device *dev) hmp->cur_rx = hmp->cur_tx = 0; hmp->dirty_rx = hmp->dirty_tx = 0; -#if 0 - /* This is wrong. I'm not sure what the original plan was, but this - * is wrong. An MTU of 1 gets you a buffer of 1536, while an MTU - * of 1501 gets a buffer of 1533? -KDU - */ - hmp->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); -#endif - /* My attempt at a reasonable correction */ /* +26 gets the maximum ethernet encapsulation, +7 & ~7 because the * card needs room to do 8 byte alignment, +2 so we can reserve * the first 2 bytes, and +16 gets room for the status word from the -- cgit v1.2.3-70-g09d2 From 47f98c7d4bfc08e5efffd4fe22296044ab4db21e Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 16 Apr 2008 16:37:39 -0700 Subject: dl2k: use netdev_alloc_skb Use netdev_alloc_skb. This sets skb->dev and allows arch specific allocation. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/dl2k.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index e233d04a213..8277e89e552 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -499,7 +499,7 @@ rio_timer (unsigned long data) entry = np->old_rx % RX_RING_SIZE; /* Dropped packets don't need to re-allocate */ if (np->rx_skbuff[entry] == NULL) { - skb = dev_alloc_skb (np->rx_buf_sz); + skb = netdev_alloc_skb (dev, np->rx_buf_sz); if (skb == NULL) { np->rx_ring[entry].fraginfo = 0; printk (KERN_INFO @@ -570,7 +570,7 @@ alloc_list (struct net_device *dev) /* Allocate the rx buffers */ for (i = 0; i < RX_RING_SIZE; i++) { /* Allocated fixed size of skbuff */ - struct sk_buff *skb = dev_alloc_skb (np->rx_buf_sz); + struct sk_buff *skb = netdev_alloc_skb (dev, np->rx_buf_sz); np->rx_skbuff[i] = skb; if (skb == NULL) { printk (KERN_ERR @@ -867,7 +867,7 @@ receive_packet (struct net_device *dev) PCI_DMA_FROMDEVICE); skb_put (skb = np->rx_skbuff[entry], pkt_len); np->rx_skbuff[entry] = NULL; - } else if ((skb = dev_alloc_skb (pkt_len + 2)) != NULL) { + } else if ((skb = netdev_alloc_skb(dev, pkt_len + 2))) { pci_dma_sync_single_for_cpu(np->pdev, desc_to_dma(desc), np->rx_buf_sz, @@ -904,7 +904,7 @@ receive_packet (struct net_device *dev) struct sk_buff *skb; /* Dropped packets don't need to re-allocate */ if (np->rx_skbuff[entry] == NULL) { - skb = dev_alloc_skb (np->rx_buf_sz); + skb = netdev_alloc_skb(dev, np->rx_buf_sz); if (skb == NULL) { np->rx_ring[entry].fraginfo = 0; printk (KERN_INFO -- cgit v1.2.3-70-g09d2 From c73d2589b784098b2bb6e986c1a7b04e9555fbd3 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 16 Apr 2008 16:37:31 -0700 Subject: via-velocity: use netdev_alloc_skb Use netdev_alloc_skb for rx buffer allocation. This sets skb->dev and can be overriden for NUMA machines. Change code to return new buffer rather than call by reference. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/via-velocity.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 6b8d882d197..3e94c8fff9e 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -1495,24 +1495,18 @@ static inline void velocity_rx_csum(struct rx_desc *rd, struct sk_buff *skb) * enough. This function returns a negative value if the received * packet is too big or if memory is exhausted. */ -static inline int velocity_rx_copy(struct sk_buff **rx_skb, int pkt_size, - struct velocity_info *vptr) +static int velocity_rx_copy(struct sk_buff **rx_skb, int pkt_size, + struct velocity_info *vptr) { int ret = -1; - if (pkt_size < rx_copybreak) { struct sk_buff *new_skb; - new_skb = dev_alloc_skb(pkt_size + 2); + new_skb = netdev_alloc_skb(vptr->dev, pkt_size + 2); if (new_skb) { - new_skb->dev = vptr->dev; new_skb->ip_summed = rx_skb[0]->ip_summed; - - if (vptr->flags & VELOCITY_FLAGS_IP_ALIGN) - skb_reserve(new_skb, 2); - - skb_copy_from_linear_data(rx_skb[0], new_skb->data, - pkt_size); + skb_reserve(new_skb, 2); + skb_copy_from_linear_data(*rx_skb, new_skb->data, pkt_size); *rx_skb = new_skb; ret = 0; } @@ -1629,7 +1623,7 @@ static int velocity_alloc_rx_buf(struct velocity_info *vptr, int idx) struct rx_desc *rd = &(vptr->rd_ring[idx]); struct velocity_rd_info *rd_info = &(vptr->rd_info[idx]); - rd_info->skb = dev_alloc_skb(vptr->rx_buf_sz + 64); + rd_info->skb = netdev_alloc_skb(vptr->dev, vptr->rx_buf_sz + 64); if (rd_info->skb == NULL) return -ENOMEM; @@ -1638,7 +1632,6 @@ static int velocity_alloc_rx_buf(struct velocity_info *vptr, int idx) * 64byte alignment. */ skb_reserve(rd_info->skb, (unsigned long) rd_info->skb->data & 63); - rd_info->skb->dev = vptr->dev; rd_info->skb_dma = pci_map_single(vptr->pdev, rd_info->skb->data, vptr->rx_buf_sz, PCI_DMA_FROMDEVICE); /* -- cgit v1.2.3-70-g09d2 From c03571a3e22b821e5be7bda7b166c4554770f489 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 16 Apr 2008 16:37:32 -0700 Subject: via-velocity: use memmove Use memmove to handle overlapping copy of data. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/via-velocity.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 3e94c8fff9e..bcbf2fa9b94 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -1527,12 +1527,8 @@ static int velocity_rx_copy(struct sk_buff **rx_skb, int pkt_size, static inline void velocity_iph_realign(struct velocity_info *vptr, struct sk_buff *skb, int pkt_size) { - /* FIXME - memmove ? */ if (vptr->flags & VELOCITY_FLAGS_IP_ALIGN) { - int i; - - for (i = pkt_size; i >= 0; i--) - *(skb->data + i + 2) = *(skb->data + i); + memmove(skb->data + 2, skb->data, pkt_size); skb_reserve(skb, 2); } } -- cgit v1.2.3-70-g09d2 From 21451155d8858773ee764e9218de2ca0f4d6fc38 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Wed, 30 Apr 2008 00:05:24 +1000 Subject: [POWERPC] of/gpio: Use dynamic base allocation Since the "gpiolib: dynamic gpio number allocation" patch was recently merged into Linus' tree (commit 8d0aab2f16c4fa170f32e7a74a52cd0122bbafef), we can use dynamic GPIO base allocation now. This, in turn, removes number of gpios per chip constraint. Signed-off-by: Anton Vorontsov Signed-off-by: Paul Mackerras --- drivers/of/gpio.c | 38 +------------------------------------- 1 file changed, 1 insertion(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/of/gpio.c b/drivers/of/gpio.c index 000681e98f2..1c9cab844f1 100644 --- a/drivers/of/gpio.c +++ b/drivers/of/gpio.c @@ -137,38 +137,6 @@ int of_gpio_simple_xlate(struct of_gpio_chip *of_gc, struct device_node *np, } EXPORT_SYMBOL(of_gpio_simple_xlate); -/* Should be sufficient for now, later we'll use dynamic bases. */ -#if defined(CONFIG_PPC32) || defined(CONFIG_SPARC32) -#define GPIOS_PER_CHIP 32 -#else -#define GPIOS_PER_CHIP 64 -#endif - -static int of_get_gpiochip_base(struct device_node *np) -{ - struct device_node *gc = NULL; - int gpiochip_base = 0; - - while ((gc = of_find_all_nodes(gc))) { - if (!of_get_property(gc, "gpio-controller", NULL)) - continue; - - if (gc != np) { - gpiochip_base += GPIOS_PER_CHIP; - continue; - } - - of_node_put(gc); - - if (gpiochip_base >= ARCH_NR_GPIOS) - return -ENOSPC; - - return gpiochip_base; - } - - return -ENOENT; -} - /** * of_mm_gpiochip_add - Add memory mapped GPIO chip (bank) * @np: device node of the GPIO chip @@ -205,11 +173,7 @@ int of_mm_gpiochip_add(struct device_node *np, if (!mm_gc->regs) goto err1; - gc->base = of_get_gpiochip_base(np); - if (gc->base < 0) { - ret = gc->base; - goto err1; - } + gc->base = -1; if (!of_gc->xlate) of_gc->xlate = of_gpio_simple_xlate; -- cgit v1.2.3-70-g09d2 From 63687a528c39a67c1a213cdffa09feb0e6af9dbe Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Mon, 12 May 2008 15:44:41 +0200 Subject: x86: move tracedata to RODATA .. allowing it to be write-protected just as other read-only data under CONFIG_DEBUG_RODATA. Signed-off-by: Jan Beulich Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner --- arch/x86/kernel/vmlinux_32.lds.S | 7 ------- arch/x86/kernel/vmlinux_64.lds.S | 7 ------- drivers/base/power/trace.c | 2 +- include/asm-generic/vmlinux.lds.h | 14 ++++++++++++++ include/asm-x86/resume-trace.h | 2 +- include/linux/resume-trace.h | 2 +- 6 files changed, 17 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/arch/x86/kernel/vmlinux_32.lds.S b/arch/x86/kernel/vmlinux_32.lds.S index ce5ed083a1e..2674f579627 100644 --- a/arch/x86/kernel/vmlinux_32.lds.S +++ b/arch/x86/kernel/vmlinux_32.lds.S @@ -60,13 +60,6 @@ SECTIONS BUG_TABLE :text - . = ALIGN(4); - .tracedata : AT(ADDR(.tracedata) - LOAD_OFFSET) { - __tracedata_start = .; - *(.tracedata) - __tracedata_end = .; - } - RODATA /* writeable */ diff --git a/arch/x86/kernel/vmlinux_64.lds.S b/arch/x86/kernel/vmlinux_64.lds.S index fad3674b06a..687041bfbae 100644 --- a/arch/x86/kernel/vmlinux_64.lds.S +++ b/arch/x86/kernel/vmlinux_64.lds.S @@ -53,13 +53,6 @@ SECTIONS RODATA - . = ALIGN(4); - .tracedata : AT(ADDR(.tracedata) - LOAD_OFFSET) { - __tracedata_start = .; - *(.tracedata) - __tracedata_end = .; - } - . = ALIGN(PAGE_SIZE); /* Align data segment to page size boundary */ /* Data */ .data : AT(ADDR(.data) - LOAD_OFFSET) { diff --git a/drivers/base/power/trace.c b/drivers/base/power/trace.c index 2b4b392dcbc..87a7f1d0257 100644 --- a/drivers/base/power/trace.c +++ b/drivers/base/power/trace.c @@ -153,7 +153,7 @@ EXPORT_SYMBOL(set_trace_device); * it's not any guarantee, but it's a high _likelihood_ that * the match is valid). */ -void generate_resume_trace(void *tracedata, unsigned int user) +void generate_resume_trace(const void *tracedata, unsigned int user) { unsigned short lineno = *(unsigned short *)tracedata; const char *file = *(const char **)(tracedata + 2); diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index f054778e916..f1992dc5c42 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -93,6 +93,8 @@ VMLINUX_SYMBOL(__end_rio_route_ops) = .; \ } \ \ + TRACEDATA \ + \ /* Kernel symbol table: Normal symbols */ \ __ksymtab : AT(ADDR(__ksymtab) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__start___ksymtab) = .; \ @@ -318,6 +320,18 @@ __stop___bug_table = .; \ } +#ifdef CONFIG_PM_TRACE +#define TRACEDATA \ + . = ALIGN(4); \ + .tracedata : AT(ADDR(.tracedata) - LOAD_OFFSET) { \ + __tracedata_start = .; \ + *(.tracedata) \ + __tracedata_end = .; \ + } +#else +#define TRACEDATA +#endif + #define NOTES \ .notes : AT(ADDR(.notes) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__start_notes) = .; \ diff --git a/include/asm-x86/resume-trace.h b/include/asm-x86/resume-trace.h index 2557514d7ef..8d9f0b41ee8 100644 --- a/include/asm-x86/resume-trace.h +++ b/include/asm-x86/resume-trace.h @@ -6,7 +6,7 @@ #define TRACE_RESUME(user) \ do { \ if (pm_trace_enabled) { \ - void *tracedata; \ + const void *tracedata; \ asm volatile(_ASM_MOV_UL " $1f,%0\n" \ ".section .tracedata,\"a\"\n" \ "1:\t.word %c1\n\t" \ diff --git a/include/linux/resume-trace.h b/include/linux/resume-trace.h index f3f4f28c696..c9ba2fdf807 100644 --- a/include/linux/resume-trace.h +++ b/include/linux/resume-trace.h @@ -8,7 +8,7 @@ extern int pm_trace_enabled; struct device; extern void set_trace_device(struct device *); -extern void generate_resume_trace(void *tracedata, unsigned int user); +extern void generate_resume_trace(const void *tracedata, unsigned int user); #define TRACE_DEVICE(dev) do { \ if (pm_trace_enabled) \ -- cgit v1.2.3-70-g09d2 From cb5dd7c104c64d7ba8ff4dd3eec3d9b92c378937 Mon Sep 17 00:00:00 2001 From: Paul Jackson Date: Wed, 14 May 2008 08:15:16 -0700 Subject: x86 boot: add header comment to dmi.h stating what it is The "dmi.h" file did not state anywhere in the file what "DMI" was. For those who know, it's obvious. For the rest of us, I added a brief opening comment. Signed-off-by: Paul Jackson Signed-off-by: Ingo Molnar --- drivers/firmware/dmi_scan.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index c5e3ed7e903..455575be356 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -8,6 +8,11 @@ #include #include +/* + * DMI stands for "Desktop Management Interface". It is part + * of and an antecedent to, SMBIOS, which stands for System + * Management BIOS. See further: http://www.dmtf.org/standards + */ static char dmi_empty_string[] = " "; static const char * __init dmi_string_nosave(const struct dmi_header *dm, u8 s) -- cgit v1.2.3-70-g09d2 From f3ff8a4d80e8ec867caf60b120c65db21f820e6d Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Sun, 25 May 2008 23:40:58 -0700 Subject: ppp: push BKL down into the driver I've pushed it down as far as I dare at this point. Someone familiar with the internal PPP semantics can probably push it further. Another step to eliminating the old BKL ioctl usage. Signed-off-by: Alan Cox Signed-off-by: David S. Miller --- drivers/net/ppp_generic.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 1f4ca2b54a7..c926bf0b190 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -361,7 +361,7 @@ static int ppp_open(struct inode *inode, struct file *file) return 0; } -static int ppp_release(struct inode *inode, struct file *file) +static int ppp_release(struct inode *unused, struct file *file) { struct ppp_file *pf = file->private_data; struct ppp *ppp; @@ -545,8 +545,7 @@ static int get_filter(void __user *arg, struct sock_filter **p) } #endif /* CONFIG_PPP_FILTER */ -static int ppp_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct ppp_file *pf = file->private_data; struct ppp *ppp; @@ -574,24 +573,29 @@ static int ppp_ioctl(struct inode *inode, struct file *file, * this fd and reopening /dev/ppp. */ err = -EINVAL; + lock_kernel(); if (pf->kind == INTERFACE) { ppp = PF_TO_PPP(pf); if (file == ppp->owner) ppp_shutdown_interface(ppp); } if (atomic_read(&file->f_count) <= 2) { - ppp_release(inode, file); + ppp_release(NULL, file); err = 0; } else printk(KERN_DEBUG "PPPIOCDETACH file->f_count=%d\n", atomic_read(&file->f_count)); + unlock_kernel(); return err; } if (pf->kind == CHANNEL) { - struct channel *pch = PF_TO_CHANNEL(pf); + struct channel *pch; struct ppp_channel *chan; + lock_kernel(); + pch = PF_TO_CHANNEL(pf); + switch (cmd) { case PPPIOCCONNECT: if (get_user(unit, p)) @@ -611,6 +615,7 @@ static int ppp_ioctl(struct inode *inode, struct file *file, err = chan->ops->ioctl(chan, cmd, arg); up_read(&pch->chan_sem); } + unlock_kernel(); return err; } @@ -620,6 +625,7 @@ static int ppp_ioctl(struct inode *inode, struct file *file, return -EINVAL; } + lock_kernel(); ppp = PF_TO_PPP(pf); switch (cmd) { case PPPIOCSMRU: @@ -767,7 +773,7 @@ static int ppp_ioctl(struct inode *inode, struct file *file, default: err = -ENOTTY; } - + unlock_kernel(); return err; } @@ -779,6 +785,7 @@ static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file, struct channel *chan; int __user *p = (int __user *)arg; + lock_kernel(); switch (cmd) { case PPPIOCNEWUNIT: /* Create a new ppp unit */ @@ -827,6 +834,7 @@ static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file, default: err = -ENOTTY; } + unlock_kernel(); return err; } @@ -835,7 +843,7 @@ static const struct file_operations ppp_device_fops = { .read = ppp_read, .write = ppp_write, .poll = ppp_poll, - .ioctl = ppp_ioctl, + .unlocked_ioctl = ppp_ioctl, .open = ppp_open, .release = ppp_release }; -- cgit v1.2.3-70-g09d2 From 0acf10d8fbd52926217d3933d196b33fe2468f18 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Mon, 26 May 2008 23:30:59 +0100 Subject: xen: add raw console write functions for debug Add a couple of functions which can write directly to the Xen console for debugging. This output ends up on the host's dom0 console (assuming it allows the domain to write there). Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Thomas Gleixner --- drivers/char/hvc_xen.c | 26 ++++++++++++++++++++++++++ include/xen/hvc-console.h | 3 +++ 2 files changed, 29 insertions(+) (limited to 'drivers') diff --git a/drivers/char/hvc_xen.c b/drivers/char/hvc_xen.c index dd68f8541c2..e97d9d16832 100644 --- a/drivers/char/hvc_xen.c +++ b/drivers/char/hvc_xen.c @@ -157,3 +157,29 @@ struct console xenboot_console = { .write = xenboot_write_console, .flags = CON_PRINTBUFFER | CON_BOOT, }; + +void xen_raw_console_write(const char *str) +{ + int len = strlen(str); + + while(len > 0) { + int rc = HYPERVISOR_console_io(CONSOLEIO_write, len, (char *)str); + if (rc <= 0) + break; + + str += rc; + len -= rc; + } +} + +void xen_raw_printk(const char *fmt, ...) +{ + static char buf[512]; + va_list ap; + + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + xen_raw_console_write(buf); +} diff --git a/include/xen/hvc-console.h b/include/xen/hvc-console.h index 21c0ecfd786..efc3237ab99 100644 --- a/include/xen/hvc-console.h +++ b/include/xen/hvc-console.h @@ -3,4 +3,7 @@ extern struct console xenboot_console; +void xen_raw_console_write(const char *str); +void xen_raw_printk(const char *fmt, ...); + #endif /* XEN_HVC_CONSOLE_H */ -- cgit v1.2.3-70-g09d2 From 0922abdc3982ae54cbe1b24ac5aa91a260eca1bb Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Mon, 26 May 2008 23:31:00 +0100 Subject: xen: make early console also write to debug console When using "earlyprintk=xen", also write the console output to the raw debug console. This will appear on dom0's console if the hypervisor has been compiled to allow it. Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Thomas Gleixner --- drivers/char/hvc_xen.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/char/hvc_xen.c b/drivers/char/hvc_xen.c index e97d9d16832..2413af342a8 100644 --- a/drivers/char/hvc_xen.c +++ b/drivers/char/hvc_xen.c @@ -134,12 +134,27 @@ module_init(xen_init); module_exit(xen_fini); console_initcall(xen_cons_init); +static void raw_console_write(const char *str, int len) +{ + while(len > 0) { + int rc = HYPERVISOR_console_io(CONSOLEIO_write, len, (char *)str); + if (rc <= 0) + break; + + str += rc; + len -= rc; + } +} + +#ifdef CONFIG_EARLY_PRINTK static void xenboot_write_console(struct console *console, const char *string, unsigned len) { unsigned int linelen, off = 0; const char *pos; + raw_console_write(string, len); + while (off < len && NULL != (pos = strchr(string+off, '\n'))) { linelen = pos-string+off; if (off + linelen > len) @@ -155,21 +170,13 @@ static void xenboot_write_console(struct console *console, const char *string, struct console xenboot_console = { .name = "xenboot", .write = xenboot_write_console, - .flags = CON_PRINTBUFFER | CON_BOOT, + .flags = CON_PRINTBUFFER | CON_BOOT | CON_ANYTIME, }; +#endif /* CONFIG_EARLY_PRINTK */ void xen_raw_console_write(const char *str) { - int len = strlen(str); - - while(len > 0) { - int rc = HYPERVISOR_console_io(CONSOLEIO_write, len, (char *)str); - if (rc <= 0) - break; - - str += rc; - len -= rc; - } + raw_console_write(str, strlen(str)); } void xen_raw_printk(const char *fmt, ...) -- cgit v1.2.3-70-g09d2 From a15af1c9ea2750a9ff01e51615c45950bad8221b Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Mon, 26 May 2008 23:31:06 +0100 Subject: x86/paravirt: add pte_flags to just get pte flags Add pte_flags() to extract the flags from a pte. This is a special case of pte_val() which is only guaranteed to return the pte's flags correctly; the page number may be corrupted or missing. The intent is to allow paravirt implementations to return pte flags without having to do any translation of the page number (most notably, Xen). Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Thomas Gleixner --- arch/x86/kernel/paravirt.c | 1 + arch/x86/xen/enlighten.c | 1 + drivers/lguest/lg.h | 1 - include/asm-x86/page.h | 1 + include/asm-x86/paravirt.h | 15 +++++++++++++++ include/asm-x86/pgtable.h | 16 ++++++++-------- 6 files changed, 26 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c index 74f0c5ea2a0..c98d5468818 100644 --- a/arch/x86/kernel/paravirt.c +++ b/arch/x86/kernel/paravirt.c @@ -403,6 +403,7 @@ struct pv_mmu_ops pv_mmu_ops = { #endif /* PAGETABLE_LEVELS >= 3 */ .pte_val = native_pte_val, + .pte_flags = native_pte_val, .pgd_val = native_pgd_val, .make_pte = native_make_pte, diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 4a372b71239..1b4b5fa498b 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -1101,6 +1101,7 @@ static const struct pv_mmu_ops xen_mmu_ops __initdata = { .set_pmd = xen_set_pmd, .pte_val = xen_pte_val, + .pte_flags = native_pte_val, .pgd_val = xen_pgd_val, .make_pte = xen_make_pte, diff --git a/drivers/lguest/lg.h b/drivers/lguest/lg.h index 005bd045d2e..5faefeaf679 100644 --- a/drivers/lguest/lg.h +++ b/drivers/lguest/lg.h @@ -136,7 +136,6 @@ int run_guest(struct lg_cpu *cpu, unsigned long __user *user); * first step in the migration to the kernel types. pte_pfn is already defined * in the kernel. */ #define pgd_flags(x) (pgd_val(x) & ~PAGE_MASK) -#define pte_flags(x) (pte_val(x) & ~PAGE_MASK) #define pgd_pfn(x) (pgd_val(x) >> PAGE_SHIFT) /* interrupts_and_traps.c: */ diff --git a/include/asm-x86/page.h b/include/asm-x86/page.h index dc936dddf16..a1e2b9470f2 100644 --- a/include/asm-x86/page.h +++ b/include/asm-x86/page.h @@ -160,6 +160,7 @@ static inline pteval_t native_pte_val(pte_t pte) #endif #define pte_val(x) native_pte_val(x) +#define pte_flags(x) native_pte_val(x) #define __pte(x) native_make_pte(x) #endif /* CONFIG_PARAVIRT */ diff --git a/include/asm-x86/paravirt.h b/include/asm-x86/paravirt.h index 0f13b945e24..5ea37a48eec 100644 --- a/include/asm-x86/paravirt.h +++ b/include/asm-x86/paravirt.h @@ -239,6 +239,7 @@ struct pv_mmu_ops { unsigned long addr, pte_t *ptep); pteval_t (*pte_val)(pte_t); + pteval_t (*pte_flags)(pte_t); pte_t (*make_pte)(pteval_t pte); pgdval_t (*pgd_val)(pgd_t); @@ -996,6 +997,20 @@ static inline pteval_t pte_val(pte_t pte) return ret; } +static inline pteval_t pte_flags(pte_t pte) +{ + pteval_t ret; + + if (sizeof(pteval_t) > sizeof(long)) + ret = PVOP_CALL2(pteval_t, pv_mmu_ops.pte_flags, + pte.pte, (u64)pte.pte >> 32); + else + ret = PVOP_CALL1(pteval_t, pv_mmu_ops.pte_flags, + pte.pte); + + return ret; +} + static inline pgd_t __pgd(pgdval_t val) { pgdval_t ret; diff --git a/include/asm-x86/pgtable.h b/include/asm-x86/pgtable.h index 97c271b2910..47a852cb8c9 100644 --- a/include/asm-x86/pgtable.h +++ b/include/asm-x86/pgtable.h @@ -164,37 +164,37 @@ extern struct list_head pgd_list; */ static inline int pte_dirty(pte_t pte) { - return pte_val(pte) & _PAGE_DIRTY; + return pte_flags(pte) & _PAGE_DIRTY; } static inline int pte_young(pte_t pte) { - return pte_val(pte) & _PAGE_ACCESSED; + return pte_flags(pte) & _PAGE_ACCESSED; } static inline int pte_write(pte_t pte) { - return pte_val(pte) & _PAGE_RW; + return pte_flags(pte) & _PAGE_RW; } static inline int pte_file(pte_t pte) { - return pte_val(pte) & _PAGE_FILE; + return pte_flags(pte) & _PAGE_FILE; } static inline int pte_huge(pte_t pte) { - return pte_val(pte) & _PAGE_PSE; + return pte_flags(pte) & _PAGE_PSE; } static inline int pte_global(pte_t pte) { - return pte_val(pte) & _PAGE_GLOBAL; + return pte_flags(pte) & _PAGE_GLOBAL; } static inline int pte_exec(pte_t pte) { - return !(pte_val(pte) & _PAGE_NX); + return !(pte_flags(pte) & _PAGE_NX); } static inline int pte_special(pte_t pte) @@ -305,7 +305,7 @@ static inline pgprot_t pgprot_modify(pgprot_t oldprot, pgprot_t newprot) return __pgprot(preservebits | addbits); } -#define pte_pgprot(x) __pgprot(pte_val(x) & ~PTE_MASK) +#define pte_pgprot(x) __pgprot(pte_flags(x) & ~PTE_MASK) #define canon_pgprot(p) __pgprot(pgprot_val(p) & __supported_pte_mask) -- cgit v1.2.3-70-g09d2 From 9e124fe16ff24746d6de5a2ad685266d7bce0e08 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 26 May 2008 23:31:07 +0100 Subject: xen: Enable console tty by default in domU if it's not a dummy Without console= arguments on the kernel command line, the first console to register becomes enabled and the preferred console (the one behind /dev/console). This is normally tty (assuming CONFIG_VT_CONSOLE is enabled, which it commonly is). This is okay as long tty is a useful console. But unless we have the PV framebuffer, and it is enabled for this domain, tty0 in domU is merely a dummy. In that case, we want the preferred console to be the Xen console hvc0, and we want it without having to fiddle with the kernel command line. Commit b8c2d3dfbc117dff26058fbac316b8acfc2cb5f7 did that for us. Since we now have the PV framebuffer, we want to enable and prefer tty again, but only when PVFB is enabled. But even then we still want to enable the Xen console as well. Problem: when tty registers, we can't yet know whether the PVFB is enabled. By the time we can know (xenstore is up), the console setup game is over. Solution: enable console tty by default, but keep hvc as the preferred console. Change the preferred console to tty when PVFB probes successfully, unless we've been given console kernel parameters. Signed-off-by: Markus Armbruster Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Thomas Gleixner --- arch/x86/xen/enlighten.c | 4 +++- drivers/video/xen-fbfront.c | 25 +++++++++++++++++++++++++ include/linux/console.h | 2 ++ kernel/printk.c | 3 +++ 4 files changed, 33 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 1b4b5fa498b..6cfb708408e 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -1256,8 +1256,10 @@ asmlinkage void __init xen_start_kernel(void) ? __pa(xen_start_info->mod_start) : 0; boot_params.hdr.ramdisk_size = xen_start_info->mod_len; - if (!is_initial_xendomain()) + if (!is_initial_xendomain()) { + add_preferred_console("tty", 0, NULL); add_preferred_console("hvc", 0, NULL); + } /* Start the world */ start_kernel(); diff --git a/drivers/video/xen-fbfront.c b/drivers/video/xen-fbfront.c index 619a6f8d65a..4e10876e62f 100644 --- a/drivers/video/xen-fbfront.c +++ b/drivers/video/xen-fbfront.c @@ -18,6 +18,7 @@ * frame buffer. */ +#include #include #include #include @@ -48,6 +49,7 @@ struct xenfb_info { static u32 xenfb_mem_len = XENFB_WIDTH * XENFB_HEIGHT * XENFB_DEPTH / 8; +static void xenfb_make_preferred_console(void); static int xenfb_remove(struct xenbus_device *); static void xenfb_init_shared_page(struct xenfb_info *); static int xenfb_connect_backend(struct xenbus_device *, struct xenfb_info *); @@ -348,6 +350,7 @@ static int __devinit xenfb_probe(struct xenbus_device *dev, if (ret < 0) goto error; + xenfb_make_preferred_console(); return 0; error_nomem: @@ -358,6 +361,28 @@ static int __devinit xenfb_probe(struct xenbus_device *dev, return ret; } +static __devinit void +xenfb_make_preferred_console(void) +{ + struct console *c; + + if (console_set_on_cmdline) + return; + + acquire_console_sem(); + for (c = console_drivers; c; c = c->next) { + if (!strcmp(c->name, "tty") && c->index == 0) + break; + } + release_console_sem(); + if (c) { + unregister_console(c); + c->flags |= CON_CONSDEV; + c->flags &= ~CON_PRINTBUFFER; /* don't print again */ + register_console(c); + } +} + static int xenfb_resume(struct xenbus_device *dev) { struct xenfb_info *info = dev->dev.driver_data; diff --git a/include/linux/console.h b/include/linux/console.h index a4f27fbdf54..248e6e3b9b7 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -108,6 +108,8 @@ struct console { struct console *next; }; +extern int console_set_on_cmdline; + extern int add_preferred_console(char *name, int idx, char *options); extern int update_console_cmdline(char *name, int idx, char *name_new, int idx_new, char *options); extern void register_console(struct console *); diff --git a/kernel/printk.c b/kernel/printk.c index 8fb01c32aa3..028ed75d486 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -121,6 +121,8 @@ struct console_cmdline static struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES]; static int selected_console = -1; static int preferred_console = -1; +int console_set_on_cmdline; +EXPORT_SYMBOL(console_set_on_cmdline); /* Flag: console code may call schedule() */ static int console_may_schedule; @@ -890,6 +892,7 @@ static int __init console_setup(char *str) *s = 0; __add_preferred_console(buf, idx, options, brl_options); + console_set_on_cmdline = 1; return 1; } __setup("console=", console_setup); -- cgit v1.2.3-70-g09d2 From 6ba0e7b36c7cc1745b3cbeda244d14edae3ad058 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 26 May 2008 23:31:08 +0100 Subject: xen pvfb: Pointer z-axis (mouse wheel) support Add z-axis motion to pointer events. Backward compatible, because there's space for the z-axis in union xenkbd_in_event, and old backends zero it. Derived from http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/57dfe0098000 http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/1edfea26a2a9 http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/c3ff0b26f664 Signed-off-by: Pat Campbell Signed-off-by: Markus Armbruster Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Thomas Gleixner --- drivers/input/xen-kbdfront.c | 8 +++++++- include/xen/interface/io/kbdif.h | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/xen-kbdfront.c b/drivers/input/xen-kbdfront.c index 0f47f4697cd..9da4452786f 100644 --- a/drivers/input/xen-kbdfront.c +++ b/drivers/input/xen-kbdfront.c @@ -66,6 +66,9 @@ static irqreturn_t input_handler(int rq, void *dev_id) case XENKBD_TYPE_MOTION: input_report_rel(dev, REL_X, event->motion.rel_x); input_report_rel(dev, REL_Y, event->motion.rel_y); + if (event->motion.rel_z) + input_report_rel(dev, REL_WHEEL, + -event->motion.rel_z); break; case XENKBD_TYPE_KEY: dev = NULL; @@ -84,6 +87,9 @@ static irqreturn_t input_handler(int rq, void *dev_id) case XENKBD_TYPE_POS: input_report_abs(dev, ABS_X, event->pos.abs_x); input_report_abs(dev, ABS_Y, event->pos.abs_y); + if (event->pos.rel_z) + input_report_rel(dev, REL_WHEEL, + -event->pos.rel_z); break; } if (dev) @@ -152,7 +158,7 @@ static int __devinit xenkbd_probe(struct xenbus_device *dev, ptr->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS); for (i = BTN_LEFT; i <= BTN_TASK; i++) set_bit(i, ptr->keybit); - ptr->relbit[0] = BIT(REL_X) | BIT(REL_Y); + ptr->relbit[0] = BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL); input_set_abs_params(ptr, ABS_X, 0, XENFB_WIDTH, 0, 0); input_set_abs_params(ptr, ABS_Y, 0, XENFB_HEIGHT, 0, 0); diff --git a/include/xen/interface/io/kbdif.h b/include/xen/interface/io/kbdif.h index fb97f4284ff..8066c7849fb 100644 --- a/include/xen/interface/io/kbdif.h +++ b/include/xen/interface/io/kbdif.h @@ -49,6 +49,7 @@ struct xenkbd_motion { uint8_t type; /* XENKBD_TYPE_MOTION */ int32_t rel_x; /* relative X motion */ int32_t rel_y; /* relative Y motion */ + int32_t rel_z; /* relative Z motion (wheel) */ }; struct xenkbd_key { @@ -61,6 +62,7 @@ struct xenkbd_position { uint8_t type; /* XENKBD_TYPE_POS */ int32_t abs_x; /* absolute X position (in FB pixels) */ int32_t abs_y; /* absolute Y position (in FB pixels) */ + int32_t rel_z; /* relative Z motion (wheel) */ }; #define XENKBD_IN_EVENT_SIZE 40 -- cgit v1.2.3-70-g09d2 From 1e892c959da42278e60b21f5ecfd6fba0efff313 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 26 May 2008 23:31:09 +0100 Subject: xen pvfb: Module aliases to support module autoloading These are mostly for completeness and consistency with the other frontends, as PVFB is typically compiled in rather than a module. Derived from http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/5e294e29a43e While there, add module descriptions. Signed-off-by: Markus Armbruster Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Thomas Gleixner --- drivers/input/xen-kbdfront.c | 2 ++ drivers/video/xen-fbfront.c | 2 ++ 2 files changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/input/xen-kbdfront.c b/drivers/input/xen-kbdfront.c index 9da4452786f..eaf69cf5b44 100644 --- a/drivers/input/xen-kbdfront.c +++ b/drivers/input/xen-kbdfront.c @@ -343,4 +343,6 @@ static void __exit xenkbd_cleanup(void) module_init(xenkbd_init); module_exit(xenkbd_cleanup); +MODULE_DESCRIPTION("Xen virtual keyboard/pointer device frontend"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("xen:vkbd"); diff --git a/drivers/video/xen-fbfront.c b/drivers/video/xen-fbfront.c index 4e10876e62f..5553e517563 100644 --- a/drivers/video/xen-fbfront.c +++ b/drivers/video/xen-fbfront.c @@ -572,4 +572,6 @@ static void __exit xenfb_cleanup(void) module_init(xenfb_init); module_exit(xenfb_cleanup); +MODULE_DESCRIPTION("Xen virtual framebuffer device frontend"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("xen:vfb"); -- cgit v1.2.3-70-g09d2 From f4ad1ebd7a0fae2782ef9f76c0b94b536742c3e8 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 26 May 2008 23:31:10 +0100 Subject: xen pvfb: Zero unused bytes in events sent to backend This isn't a security flaw (the backend can see all our memory anyway). But it's the right thing to do all the same. Signed-off-by: Markus Armbruster Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Thomas Gleixner --- drivers/video/xen-fbfront.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/video/xen-fbfront.c b/drivers/video/xen-fbfront.c index 5553e517563..291eef69559 100644 --- a/drivers/video/xen-fbfront.c +++ b/drivers/video/xen-fbfront.c @@ -61,6 +61,7 @@ static void xenfb_do_update(struct xenfb_info *info, union xenfb_out_event event; u32 prod; + memset(&event, 0, sizeof(event)); event.type = XENFB_TYPE_UPDATE; event.update.x = x; event.update.y = y; -- cgit v1.2.3-70-g09d2 From e4dcff1f6e7582f76c2c9990b1d9111bbc8e26ef Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 26 May 2008 23:31:11 +0100 Subject: xen pvfb: Dynamic mode support (screen resizing) The pvfb backend indicates dynamic mode support by creating node feature_resize with a non-zero value in its xenstore directory. xen-fbfront sends a resize notification event on mode change. Fully backwards compatible both ways. Framebuffer size and initial resolution can be controlled through kernel parameter xen_fbfront.video. The backend enforces a separate size limit, which it advertises in node videoram in its xenstore directory. xen-kbdfront gets the maximum screen resolution from nodes width and height in the backend's xenstore directory instead of hardcoding it. Additional goodie: support for larger framebuffers (512M on a 64-bit system with 4K pages). Changing the number of bits per pixels dynamically is not supported, yet. Ported from http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/92f7b3144f41 http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/bfc040135633 Signed-off-by: Pat Campbell Signed-off-by: Markus Armbruster Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Thomas Gleixner --- drivers/input/xen-kbdfront.c | 10 +++ drivers/video/xen-fbfront.c | 183 +++++++++++++++++++++++++++++++++------- include/xen/interface/io/fbif.h | 29 +++++-- 3 files changed, 188 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/input/xen-kbdfront.c b/drivers/input/xen-kbdfront.c index eaf69cf5b44..9ce3b3baf3a 100644 --- a/drivers/input/xen-kbdfront.c +++ b/drivers/input/xen-kbdfront.c @@ -300,6 +300,16 @@ InitWait: */ if (dev->state != XenbusStateConnected) goto InitWait; /* no InitWait seen yet, fudge it */ + + /* Set input abs params to match backend screen res */ + if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, + "width", "%d", &val) > 0) + input_set_abs_params(info->ptr, ABS_X, 0, val, 0, 0); + + if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, + "height", "%d", &val) > 0) + input_set_abs_params(info->ptr, ABS_Y, 0, val, 0, 0); + break; case XenbusStateClosing: diff --git a/drivers/video/xen-fbfront.c b/drivers/video/xen-fbfront.c index 291eef69559..47ed39b52f9 100644 --- a/drivers/video/xen-fbfront.c +++ b/drivers/video/xen-fbfront.c @@ -43,23 +43,47 @@ struct xenfb_info { struct xenfb_page *page; unsigned long *mfns; int update_wanted; /* XENFB_TYPE_UPDATE wanted */ + int feature_resize; /* XENFB_TYPE_RESIZE ok */ + struct xenfb_resize resize; /* protected by resize_lock */ + int resize_dpy; /* ditto */ + spinlock_t resize_lock; struct xenbus_device *xbdev; }; -static u32 xenfb_mem_len = XENFB_WIDTH * XENFB_HEIGHT * XENFB_DEPTH / 8; +#define XENFB_DEFAULT_FB_LEN (XENFB_WIDTH * XENFB_HEIGHT * XENFB_DEPTH / 8) + +enum { KPARAM_MEM, KPARAM_WIDTH, KPARAM_HEIGHT, KPARAM_CNT }; +static int video[KPARAM_CNT] = { 2, XENFB_WIDTH, XENFB_HEIGHT }; +module_param_array(video, int, NULL, 0); +MODULE_PARM_DESC(video, + "Video memory size in MB, width, height in pixels (default 2,800,600)"); static void xenfb_make_preferred_console(void); static int xenfb_remove(struct xenbus_device *); -static void xenfb_init_shared_page(struct xenfb_info *); +static void xenfb_init_shared_page(struct xenfb_info *, struct fb_info *); static int xenfb_connect_backend(struct xenbus_device *, struct xenfb_info *); static void xenfb_disconnect_backend(struct xenfb_info *); +static void xenfb_send_event(struct xenfb_info *info, + union xenfb_out_event *event) +{ + u32 prod; + + prod = info->page->out_prod; + /* caller ensures !xenfb_queue_full() */ + mb(); /* ensure ring space available */ + XENFB_OUT_RING_REF(info->page, prod) = *event; + wmb(); /* ensure ring contents visible */ + info->page->out_prod = prod + 1; + + notify_remote_via_irq(info->irq); +} + static void xenfb_do_update(struct xenfb_info *info, int x, int y, int w, int h) { union xenfb_out_event event; - u32 prod; memset(&event, 0, sizeof(event)); event.type = XENFB_TYPE_UPDATE; @@ -68,14 +92,19 @@ static void xenfb_do_update(struct xenfb_info *info, event.update.width = w; event.update.height = h; - prod = info->page->out_prod; /* caller ensures !xenfb_queue_full() */ - mb(); /* ensure ring space available */ - XENFB_OUT_RING_REF(info->page, prod) = event; - wmb(); /* ensure ring contents visible */ - info->page->out_prod = prod + 1; + xenfb_send_event(info, &event); +} - notify_remote_via_irq(info->irq); +static void xenfb_do_resize(struct xenfb_info *info) +{ + union xenfb_out_event event; + + memset(&event, 0, sizeof(event)); + event.resize = info->resize; + + /* caller ensures !xenfb_queue_full() */ + xenfb_send_event(info, &event); } static int xenfb_queue_full(struct xenfb_info *info) @@ -87,12 +116,28 @@ static int xenfb_queue_full(struct xenfb_info *info) return prod - cons == XENFB_OUT_RING_LEN; } +static void xenfb_handle_resize_dpy(struct xenfb_info *info) +{ + unsigned long flags; + + spin_lock_irqsave(&info->resize_lock, flags); + if (info->resize_dpy) { + if (!xenfb_queue_full(info)) { + info->resize_dpy = 0; + xenfb_do_resize(info); + } + } + spin_unlock_irqrestore(&info->resize_lock, flags); +} + static void xenfb_refresh(struct xenfb_info *info, int x1, int y1, int w, int h) { unsigned long flags; - int y2 = y1 + h - 1; int x2 = x1 + w - 1; + int y2 = y1 + h - 1; + + xenfb_handle_resize_dpy(info); if (!info->update_wanted) return; @@ -225,6 +270,57 @@ static ssize_t xenfb_write(struct fb_info *p, const char __user *buf, return res; } +static int +xenfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct xenfb_info *xenfb_info; + int required_mem_len; + + xenfb_info = info->par; + + if (!xenfb_info->feature_resize) { + if (var->xres == video[KPARAM_WIDTH] && + var->yres == video[KPARAM_HEIGHT] && + var->bits_per_pixel == xenfb_info->page->depth) { + return 0; + } + return -EINVAL; + } + + /* Can't resize past initial width and height */ + if (var->xres > video[KPARAM_WIDTH] || var->yres > video[KPARAM_HEIGHT]) + return -EINVAL; + + required_mem_len = var->xres * var->yres * xenfb_info->page->depth / 8; + if (var->bits_per_pixel == xenfb_info->page->depth && + var->xres <= info->fix.line_length / (XENFB_DEPTH / 8) && + required_mem_len <= info->fix.smem_len) { + var->xres_virtual = var->xres; + var->yres_virtual = var->yres; + return 0; + } + return -EINVAL; +} + +static int xenfb_set_par(struct fb_info *info) +{ + struct xenfb_info *xenfb_info; + unsigned long flags; + + xenfb_info = info->par; + + spin_lock_irqsave(&xenfb_info->resize_lock, flags); + xenfb_info->resize.type = XENFB_TYPE_RESIZE; + xenfb_info->resize.width = info->var.xres; + xenfb_info->resize.height = info->var.yres; + xenfb_info->resize.stride = info->fix.line_length; + xenfb_info->resize.depth = info->var.bits_per_pixel; + xenfb_info->resize.offset = 0; + xenfb_info->resize_dpy = 1; + spin_unlock_irqrestore(&xenfb_info->resize_lock, flags); + return 0; +} + static struct fb_ops xenfb_fb_ops = { .owner = THIS_MODULE, .fb_read = fb_sys_read, @@ -233,6 +329,8 @@ static struct fb_ops xenfb_fb_ops = { .fb_fillrect = xenfb_fillrect, .fb_copyarea = xenfb_copyarea, .fb_imageblit = xenfb_imageblit, + .fb_check_var = xenfb_check_var, + .fb_set_par = xenfb_set_par, }; static irqreturn_t xenfb_event_handler(int rq, void *dev_id) @@ -261,6 +359,8 @@ static int __devinit xenfb_probe(struct xenbus_device *dev, { struct xenfb_info *info; struct fb_info *fb_info; + int fb_size; + int val; int ret; info = kzalloc(sizeof(*info), GFP_KERNEL); @@ -268,18 +368,35 @@ static int __devinit xenfb_probe(struct xenbus_device *dev, xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure"); return -ENOMEM; } + + /* Limit kernel param videoram amount to what is in xenstore */ + if (xenbus_scanf(XBT_NIL, dev->otherend, "videoram", "%d", &val) == 1) { + if (val < video[KPARAM_MEM]) + video[KPARAM_MEM] = val; + } + + /* If requested res does not fit in available memory, use default */ + fb_size = video[KPARAM_MEM] * 1024 * 1024; + if (video[KPARAM_WIDTH] * video[KPARAM_HEIGHT] * XENFB_DEPTH / 8 + > fb_size) { + video[KPARAM_WIDTH] = XENFB_WIDTH; + video[KPARAM_HEIGHT] = XENFB_HEIGHT; + fb_size = XENFB_DEFAULT_FB_LEN; + } + dev->dev.driver_data = info; info->xbdev = dev; info->irq = -1; info->x1 = info->y1 = INT_MAX; spin_lock_init(&info->dirty_lock); + spin_lock_init(&info->resize_lock); - info->fb = vmalloc(xenfb_mem_len); + info->fb = vmalloc(fb_size); if (info->fb == NULL) goto error_nomem; - memset(info->fb, 0, xenfb_mem_len); + memset(info->fb, 0, fb_size); - info->nr_pages = (xenfb_mem_len + PAGE_SIZE - 1) >> PAGE_SHIFT; + info->nr_pages = (fb_size + PAGE_SIZE - 1) >> PAGE_SHIFT; info->mfns = vmalloc(sizeof(unsigned long) * info->nr_pages); if (!info->mfns) @@ -290,8 +407,6 @@ static int __devinit xenfb_probe(struct xenbus_device *dev, if (!info->page) goto error_nomem; - xenfb_init_shared_page(info); - /* abusing framebuffer_alloc() to allocate pseudo_palette */ fb_info = framebuffer_alloc(sizeof(u32) * 256, NULL); if (fb_info == NULL) @@ -304,9 +419,9 @@ static int __devinit xenfb_probe(struct xenbus_device *dev, fb_info->screen_base = info->fb; fb_info->fbops = &xenfb_fb_ops; - fb_info->var.xres_virtual = fb_info->var.xres = info->page->width; - fb_info->var.yres_virtual = fb_info->var.yres = info->page->height; - fb_info->var.bits_per_pixel = info->page->depth; + fb_info->var.xres_virtual = fb_info->var.xres = video[KPARAM_WIDTH]; + fb_info->var.yres_virtual = fb_info->var.yres = video[KPARAM_HEIGHT]; + fb_info->var.bits_per_pixel = XENFB_DEPTH; fb_info->var.red = (struct fb_bitfield){16, 8, 0}; fb_info->var.green = (struct fb_bitfield){8, 8, 0}; @@ -318,9 +433,9 @@ static int __devinit xenfb_probe(struct xenbus_device *dev, fb_info->var.vmode = FB_VMODE_NONINTERLACED; fb_info->fix.visual = FB_VISUAL_TRUECOLOR; - fb_info->fix.line_length = info->page->line_length; + fb_info->fix.line_length = fb_info->var.xres * XENFB_DEPTH / 8; fb_info->fix.smem_start = 0; - fb_info->fix.smem_len = xenfb_mem_len; + fb_info->fix.smem_len = fb_size; strcpy(fb_info->fix.id, "xen"); fb_info->fix.type = FB_TYPE_PACKED_PIXELS; fb_info->fix.accel = FB_ACCEL_NONE; @@ -337,6 +452,8 @@ static int __devinit xenfb_probe(struct xenbus_device *dev, fb_info->fbdefio = &xenfb_defio; fb_deferred_io_init(fb_info); + xenfb_init_shared_page(info, fb_info); + ret = register_framebuffer(fb_info); if (ret) { fb_deferred_io_cleanup(fb_info); @@ -389,7 +506,7 @@ static int xenfb_resume(struct xenbus_device *dev) struct xenfb_info *info = dev->dev.driver_data; xenfb_disconnect_backend(info); - xenfb_init_shared_page(info); + xenfb_init_shared_page(info, info->fb_info); return xenfb_connect_backend(dev, info); } @@ -417,20 +534,23 @@ static unsigned long vmalloc_to_mfn(void *address) return pfn_to_mfn(vmalloc_to_pfn(address)); } -static void xenfb_init_shared_page(struct xenfb_info *info) +static void xenfb_init_shared_page(struct xenfb_info *info, + struct fb_info *fb_info) { int i; + int epd = PAGE_SIZE / sizeof(info->mfns[0]); for (i = 0; i < info->nr_pages; i++) info->mfns[i] = vmalloc_to_mfn(info->fb + i * PAGE_SIZE); - info->page->pd[0] = vmalloc_to_mfn(info->mfns); - info->page->pd[1] = 0; - info->page->width = XENFB_WIDTH; - info->page->height = XENFB_HEIGHT; - info->page->depth = XENFB_DEPTH; - info->page->line_length = (info->page->depth / 8) * info->page->width; - info->page->mem_length = xenfb_mem_len; + for (i = 0; i * epd < info->nr_pages; i++) + info->page->pd[i] = vmalloc_to_mfn(&info->mfns[i * epd]); + + info->page->width = fb_info->var.xres; + info->page->height = fb_info->var.yres; + info->page->depth = fb_info->var.bits_per_pixel; + info->page->line_length = fb_info->fix.line_length; + info->page->mem_length = fb_info->fix.smem_len; info->page->in_cons = info->page->in_prod = 0; info->page->out_cons = info->page->out_prod = 0; } @@ -530,6 +650,11 @@ InitWait: val = 0; if (val) info->update_wanted = 1; + + if (xenbus_scanf(XBT_NIL, dev->otherend, + "feature-resize", "%d", &val) < 0) + val = 0; + info->feature_resize = val; break; case XenbusStateClosing: diff --git a/include/xen/interface/io/fbif.h b/include/xen/interface/io/fbif.h index 5a934dd7796..974a51ed916 100644 --- a/include/xen/interface/io/fbif.h +++ b/include/xen/interface/io/fbif.h @@ -49,11 +49,27 @@ struct xenfb_update { int32_t height; /* rect height */ }; +/* + * Framebuffer resize notification event + * Capable backend sets feature-resize in xenstore. + */ +#define XENFB_TYPE_RESIZE 3 + +struct xenfb_resize { + uint8_t type; /* XENFB_TYPE_RESIZE */ + int32_t width; /* width in pixels */ + int32_t height; /* height in pixels */ + int32_t stride; /* stride in bytes */ + int32_t depth; /* depth in bits */ + int32_t offset; /* start offset within framebuffer */ +}; + #define XENFB_OUT_EVENT_SIZE 40 union xenfb_out_event { uint8_t type; struct xenfb_update update; + struct xenfb_resize resize; char pad[XENFB_OUT_EVENT_SIZE]; }; @@ -105,15 +121,18 @@ struct xenfb_page { * Each directory page holds PAGE_SIZE / sizeof(*pd) * framebuffer pages, and can thus map up to PAGE_SIZE * * PAGE_SIZE / sizeof(*pd) bytes. With PAGE_SIZE == 4096 and - * sizeof(unsigned long) == 4, that's 4 Megs. Two directory - * pages should be enough for a while. + * sizeof(unsigned long) == 4/8, that's 4 Megs 32 bit and 2 + * Megs 64 bit. 256 directories give enough room for a 512 + * Meg framebuffer with a max resolution of 12,800x10,240. + * Should be enough for a while with room leftover for + * expansion. */ - unsigned long pd[2]; + unsigned long pd[256]; }; /* - * Wart: xenkbd needs to know resolution. Put it here until a better - * solution is found, but don't leak it to the backend. + * Wart: xenkbd needs to know default resolution. Put it here until a + * better solution is found, but don't leak it to the backend. */ #ifdef __KERNEL__ #define XENFB_WIDTH 800 -- cgit v1.2.3-70-g09d2 From 83abc70a4c6e306f4c1672e25884322f797e4fcb Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Mon, 26 May 2008 23:31:12 +0100 Subject: xen: make earlyprintk=xen work again For some perverse reason, if you call add_preferred_console() it prevents setup_early_printk() from successfully enabling the boot console - unless you make it a preferred console too... Also, make xenboot console output distinct from normal console output, since it gets repeated when the console handover happens, and the duplicated output is confusing without disambiguation. Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Thomas Gleixner Cc: Markus Armbruster Cc: Gerd Hoffmann --- arch/x86/xen/enlighten.c | 1 + drivers/char/hvc_xen.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 6cfb708408e..5c0635a8bff 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -1257,6 +1257,7 @@ asmlinkage void __init xen_start_kernel(void) boot_params.hdr.ramdisk_size = xen_start_info->mod_len; if (!is_initial_xendomain()) { + add_preferred_console("xenboot", 0, NULL); add_preferred_console("tty", 0, NULL); add_preferred_console("hvc", 0, NULL); } diff --git a/drivers/char/hvc_xen.c b/drivers/char/hvc_xen.c index 2413af342a8..d5fe0a8952f 100644 --- a/drivers/char/hvc_xen.c +++ b/drivers/char/hvc_xen.c @@ -155,6 +155,7 @@ static void xenboot_write_console(struct console *console, const char *string, raw_console_write(string, len); + write_console(0, "(early) ", 8); while (off < len && NULL != (pos = strchr(string+off, '\n'))) { linelen = pos-string+off; if (off + linelen > len) -- cgit v1.2.3-70-g09d2 From ec9b2065d4d3b797604c09a569083dd9ff951b1b Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Mon, 26 May 2008 23:31:13 +0100 Subject: xen: Move manage.c to drivers/xen for ia64/xen support move arch/x86/xen/manage.c under drivers/xen/to share codes with x86 and ia64. ia64/xen also uses manage.c Signed-off-by: Isaku Yamahata Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Thomas Gleixner --- arch/x86/xen/Makefile | 2 +- arch/x86/xen/manage.c | 143 -------------------------------------------------- drivers/xen/Makefile | 2 +- drivers/xen/manage.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 145 insertions(+), 145 deletions(-) delete mode 100644 arch/x86/xen/manage.c create mode 100644 drivers/xen/manage.c (limited to 'drivers') diff --git a/arch/x86/xen/Makefile b/arch/x86/xen/Makefile index 3d8df981d5f..40b119b6b10 100644 --- a/arch/x86/xen/Makefile +++ b/arch/x86/xen/Makefile @@ -1,4 +1,4 @@ obj-y := enlighten.o setup.o multicalls.o mmu.o \ - time.o manage.o xen-asm.o grant-table.o + time.o xen-asm.o grant-table.o obj-$(CONFIG_SMP) += smp.o diff --git a/arch/x86/xen/manage.c b/arch/x86/xen/manage.c deleted file mode 100644 index aa7af9e6abc..00000000000 --- a/arch/x86/xen/manage.c +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Handle extern requests for shutdown, reboot and sysrq - */ -#include -#include -#include -#include - -#include - -#define SHUTDOWN_INVALID -1 -#define SHUTDOWN_POWEROFF 0 -#define SHUTDOWN_SUSPEND 2 -/* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only - * report a crash, not be instructed to crash! - * HALT is the same as POWEROFF, as far as we're concerned. The tools use - * the distinction when we return the reason code to them. - */ -#define SHUTDOWN_HALT 4 - -/* Ignore multiple shutdown requests. */ -static int shutting_down = SHUTDOWN_INVALID; - -static void shutdown_handler(struct xenbus_watch *watch, - const char **vec, unsigned int len) -{ - char *str; - struct xenbus_transaction xbt; - int err; - - if (shutting_down != SHUTDOWN_INVALID) - return; - - again: - err = xenbus_transaction_start(&xbt); - if (err) - return; - - str = (char *)xenbus_read(xbt, "control", "shutdown", NULL); - /* Ignore read errors and empty reads. */ - if (XENBUS_IS_ERR_READ(str)) { - xenbus_transaction_end(xbt, 1); - return; - } - - xenbus_write(xbt, "control", "shutdown", ""); - - err = xenbus_transaction_end(xbt, 0); - if (err == -EAGAIN) { - kfree(str); - goto again; - } - - if (strcmp(str, "poweroff") == 0 || - strcmp(str, "halt") == 0) - orderly_poweroff(false); - else if (strcmp(str, "reboot") == 0) - ctrl_alt_del(); - else { - printk(KERN_INFO "Ignoring shutdown request: %s\n", str); - shutting_down = SHUTDOWN_INVALID; - } - - kfree(str); -} - -static void sysrq_handler(struct xenbus_watch *watch, const char **vec, - unsigned int len) -{ - char sysrq_key = '\0'; - struct xenbus_transaction xbt; - int err; - - again: - err = xenbus_transaction_start(&xbt); - if (err) - return; - if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) { - printk(KERN_ERR "Unable to read sysrq code in " - "control/sysrq\n"); - xenbus_transaction_end(xbt, 1); - return; - } - - if (sysrq_key != '\0') - xenbus_printf(xbt, "control", "sysrq", "%c", '\0'); - - err = xenbus_transaction_end(xbt, 0); - if (err == -EAGAIN) - goto again; - - if (sysrq_key != '\0') - handle_sysrq(sysrq_key, NULL); -} - -static struct xenbus_watch shutdown_watch = { - .node = "control/shutdown", - .callback = shutdown_handler -}; - -static struct xenbus_watch sysrq_watch = { - .node = "control/sysrq", - .callback = sysrq_handler -}; - -static int setup_shutdown_watcher(void) -{ - int err; - - err = register_xenbus_watch(&shutdown_watch); - if (err) { - printk(KERN_ERR "Failed to set shutdown watcher\n"); - return err; - } - - err = register_xenbus_watch(&sysrq_watch); - if (err) { - printk(KERN_ERR "Failed to set sysrq watcher\n"); - return err; - } - - return 0; -} - -static int shutdown_event(struct notifier_block *notifier, - unsigned long event, - void *data) -{ - setup_shutdown_watcher(); - return NOTIFY_DONE; -} - -static int __init setup_shutdown_event(void) -{ - static struct notifier_block xenstore_notifier = { - .notifier_call = shutdown_event - }; - register_xenstore_notifier(&xenstore_notifier); - - return 0; -} - -subsys_initcall(setup_shutdown_event); diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile index 37af04f1ffd..363286c5429 100644 --- a/drivers/xen/Makefile +++ b/drivers/xen/Makefile @@ -1,4 +1,4 @@ -obj-y += grant-table.o features.o events.o +obj-y += grant-table.o features.o events.o manage.o obj-y += xenbus/ obj-$(CONFIG_XEN_XENCOMM) += xencomm.o obj-$(CONFIG_XEN_BALLOON) += balloon.o diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c new file mode 100644 index 00000000000..aa7af9e6abc --- /dev/null +++ b/drivers/xen/manage.c @@ -0,0 +1,143 @@ +/* + * Handle extern requests for shutdown, reboot and sysrq + */ +#include +#include +#include +#include + +#include + +#define SHUTDOWN_INVALID -1 +#define SHUTDOWN_POWEROFF 0 +#define SHUTDOWN_SUSPEND 2 +/* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only + * report a crash, not be instructed to crash! + * HALT is the same as POWEROFF, as far as we're concerned. The tools use + * the distinction when we return the reason code to them. + */ +#define SHUTDOWN_HALT 4 + +/* Ignore multiple shutdown requests. */ +static int shutting_down = SHUTDOWN_INVALID; + +static void shutdown_handler(struct xenbus_watch *watch, + const char **vec, unsigned int len) +{ + char *str; + struct xenbus_transaction xbt; + int err; + + if (shutting_down != SHUTDOWN_INVALID) + return; + + again: + err = xenbus_transaction_start(&xbt); + if (err) + return; + + str = (char *)xenbus_read(xbt, "control", "shutdown", NULL); + /* Ignore read errors and empty reads. */ + if (XENBUS_IS_ERR_READ(str)) { + xenbus_transaction_end(xbt, 1); + return; + } + + xenbus_write(xbt, "control", "shutdown", ""); + + err = xenbus_transaction_end(xbt, 0); + if (err == -EAGAIN) { + kfree(str); + goto again; + } + + if (strcmp(str, "poweroff") == 0 || + strcmp(str, "halt") == 0) + orderly_poweroff(false); + else if (strcmp(str, "reboot") == 0) + ctrl_alt_del(); + else { + printk(KERN_INFO "Ignoring shutdown request: %s\n", str); + shutting_down = SHUTDOWN_INVALID; + } + + kfree(str); +} + +static void sysrq_handler(struct xenbus_watch *watch, const char **vec, + unsigned int len) +{ + char sysrq_key = '\0'; + struct xenbus_transaction xbt; + int err; + + again: + err = xenbus_transaction_start(&xbt); + if (err) + return; + if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) { + printk(KERN_ERR "Unable to read sysrq code in " + "control/sysrq\n"); + xenbus_transaction_end(xbt, 1); + return; + } + + if (sysrq_key != '\0') + xenbus_printf(xbt, "control", "sysrq", "%c", '\0'); + + err = xenbus_transaction_end(xbt, 0); + if (err == -EAGAIN) + goto again; + + if (sysrq_key != '\0') + handle_sysrq(sysrq_key, NULL); +} + +static struct xenbus_watch shutdown_watch = { + .node = "control/shutdown", + .callback = shutdown_handler +}; + +static struct xenbus_watch sysrq_watch = { + .node = "control/sysrq", + .callback = sysrq_handler +}; + +static int setup_shutdown_watcher(void) +{ + int err; + + err = register_xenbus_watch(&shutdown_watch); + if (err) { + printk(KERN_ERR "Failed to set shutdown watcher\n"); + return err; + } + + err = register_xenbus_watch(&sysrq_watch); + if (err) { + printk(KERN_ERR "Failed to set sysrq watcher\n"); + return err; + } + + return 0; +} + +static int shutdown_event(struct notifier_block *notifier, + unsigned long event, + void *data) +{ + setup_shutdown_watcher(); + return NOTIFY_DONE; +} + +static int __init setup_shutdown_event(void) +{ + static struct notifier_block xenstore_notifier = { + .notifier_call = shutdown_event + }; + register_xenstore_notifier(&xenstore_notifier); + + return 0; +} + +subsys_initcall(setup_shutdown_event); -- cgit v1.2.3-70-g09d2 From a90971ebddc81330f59203dee9803512aa4e2ef6 Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Mon, 26 May 2008 23:31:14 +0100 Subject: xen: compilation fix to balloon driver for ia64 support fix compilation error of ballon driver on ia64. extent_start member is pointer argument. On x86 pointer argument for xen hypercall is passed as virtual address. On the other hand, ia64 and ppc, pointer argument is passed in pseudo physical address. (guest physicall address.) So they must be passed as handle and convert right before issuing hypercall. CC drivers/xen/balloon.o linux-2.6-x86/drivers/xen/balloon.c: In function 'increase_reservation': linux-2.6-x86/drivers/xen/balloon.c:228: error: incompatible types in assignment linux-2.6-x86/drivers/xen/balloon.c: In function 'decrease_reservation': linux-2.6-x86/drivers/xen/balloon.c:324: error: incompatible types in assignment linux-2.6-x86/drivers/xen/balloon.c: In function 'dealloc_pte_fn': linux-2.6-x86/drivers/xen/balloon.c:486: error: incompatible types in assignment linux-2.6-x86/drivers/xen/balloon.c: In function 'alloc_empty_pages_and_pagevec': linux-2.6-x86/drivers/xen/balloon.c:522: error: incompatible types in assignment make[2]: *** [drivers/xen/balloon.o] Error 1 Signed-off-by: Isaku Yamahata Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Thomas Gleixner --- drivers/xen/balloon.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index ab25ba6cbbb..097ba02ac80 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c @@ -225,7 +225,7 @@ static int increase_reservation(unsigned long nr_pages) page = balloon_next_page(page); } - reservation.extent_start = (unsigned long)frame_list; + set_xen_guest_handle(reservation.extent_start, frame_list); reservation.nr_extents = nr_pages; rc = HYPERVISOR_memory_op( XENMEM_populate_physmap, &reservation); @@ -321,7 +321,7 @@ static int decrease_reservation(unsigned long nr_pages) balloon_append(pfn_to_page(pfn)); } - reservation.extent_start = (unsigned long)frame_list; + set_xen_guest_handle(reservation.extent_start, frame_list); reservation.nr_extents = nr_pages; ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation); BUG_ON(ret != nr_pages); @@ -483,7 +483,7 @@ static int dealloc_pte_fn( .extent_order = 0, .domid = DOMID_SELF }; - reservation.extent_start = (unsigned long)&mfn; + set_xen_guest_handle(reservation.extent_start, &mfn); set_pte_at(&init_mm, addr, pte, __pte_ma(0ull)); set_phys_to_machine(__pa(addr) >> PAGE_SHIFT, INVALID_P2M_ENTRY); ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation); @@ -519,7 +519,7 @@ static struct page **alloc_empty_pages_and_pagevec(int nr_pages) .extent_order = 0, .domid = DOMID_SELF }; - reservation.extent_start = (unsigned long)&gmfn; + set_xen_guest_handle(reservation.extent_start, &gmfn); ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation); if (ret == 1) -- cgit v1.2.3-70-g09d2 From 955d6f1778da5a9795f2dfb07f760006f194609a Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 26 May 2008 23:31:17 +0100 Subject: xen: drivers/xen/balloon.c: make a function static Make the needlessly global balloon_set_new_target() static. Signed-off-by: Adrian Bunk Acked-by: Chris Wright Signed-off-by: Andrew Morton Signed-off-by: Thomas Gleixner --- drivers/xen/balloon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index 097ba02ac80..591bc29b55f 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c @@ -368,7 +368,7 @@ static void balloon_process(struct work_struct *work) } /* Resets the Xen limit, sets new target, and kicks off processing. */ -void balloon_set_new_target(unsigned long target) +static void balloon_set_new_target(unsigned long target) { /* No need for lock. Not read-modify-write updates. */ balloon_stats.hard_limit = ~0UL; -- cgit v1.2.3-70-g09d2 From eb1e305f4ef201e549ffd475b7dcbcd4ec36d7dc Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Mon, 26 May 2008 23:31:23 +0100 Subject: xen: add rebind_evtchn_irq Add rebind_evtchn_irq(), which will rebind an device driver's existing irq to a new event channel on restore. Since the new event channel will be masked and bound to vcpu0, we update the state accordingly and unmask the irq once everything is set up. Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Thomas Gleixner --- drivers/xen/events.c | 27 +++++++++++++++++++++++++++ include/xen/events.h | 1 + 2 files changed, 28 insertions(+) (limited to 'drivers') diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 4f0f22b020e..f64e9798129 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -557,6 +557,33 @@ out: put_cpu(); } +/* Rebind a new event channel to an existing irq. */ +void rebind_evtchn_irq(int evtchn, int irq) +{ + /* Make sure the irq is masked, since the new event channel + will also be masked. */ + disable_irq(irq); + + spin_lock(&irq_mapping_update_lock); + + /* After resume the irq<->evtchn mappings are all cleared out */ + BUG_ON(evtchn_to_irq[evtchn] != -1); + /* Expect irq to have been bound before, + so the bindcount should be non-0 */ + BUG_ON(irq_bindcount[irq] == 0); + + evtchn_to_irq[evtchn] = irq; + irq_info[irq] = mk_irq_info(IRQT_EVTCHN, 0, evtchn); + + spin_unlock(&irq_mapping_update_lock); + + /* new event channels are always bound to cpu 0 */ + irq_set_affinity(irq, cpumask_of_cpu(0)); + + /* Unmask the event channel. */ + enable_irq(irq); +} + /* Rebind an evtchn so that it gets delivered to a specific cpu */ static void rebind_irq_to_cpu(unsigned irq, unsigned tcpu) { diff --git a/include/xen/events.h b/include/xen/events.h index acd8e062c85..a82ec0c45c3 100644 --- a/include/xen/events.h +++ b/include/xen/events.h @@ -32,6 +32,7 @@ void unbind_from_irqhandler(unsigned int irq, void *dev_id); void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector); int resend_irq_on_evtchn(unsigned int irq); +void rebind_evtchn_irq(int evtchn, int irq); static inline void notify_remote_via_evtchn(int port) { -- cgit v1.2.3-70-g09d2 From 0f2287ad7c61f10b2a22a06e2a66cdbbbfc44ad0 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Mon, 26 May 2008 23:31:24 +0100 Subject: xen: fix unbind_from_irq() Rearrange the tests in unbind_from_irq() so that we can still unbind an irq even if the underlying event channel is bad. This allows a device driver to shuffle its irqs on save/restore before the underlying event channels have been fixed up. Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Thomas Gleixner --- drivers/xen/events.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/xen/events.c b/drivers/xen/events.c index f64e9798129..70375a69076 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -355,7 +355,7 @@ static void unbind_from_irq(unsigned int irq) spin_lock(&irq_mapping_update_lock); - if (VALID_EVTCHN(evtchn) && (--irq_bindcount[irq] == 0)) { + if ((--irq_bindcount[irq] == 0) && VALID_EVTCHN(evtchn)) { close.port = evtchn; if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close) != 0) BUG(); @@ -375,7 +375,7 @@ static void unbind_from_irq(unsigned int irq) evtchn_to_irq[evtchn] = -1; irq_info[irq] = IRQ_UNBOUND; - dynamic_irq_init(irq); + dynamic_irq_cleanup(irq); } spin_unlock(&irq_mapping_update_lock); -- cgit v1.2.3-70-g09d2 From 6b9b732d0e396a3f1a95977162a8624aafce38a1 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Mon, 26 May 2008 23:31:25 +0100 Subject: xen-console: add save/restore Add code to: 1. Deal with the console page being canonicalized. During save, the console's mfn in the start_info structure is canonicalized to a pfn. In order to deal with that, we always use a copy of the pfn and indirect off that all the time. However, we fall back to using the mfn if the pfn hasn't been initialized yet. 2. Restore the console event channel, and rebind it to the existing irq. Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Thomas Gleixner --- drivers/char/hvc_xen.c | 25 +++++++++++++++++++++---- include/xen/hvc-console.h | 2 ++ 2 files changed, 23 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/char/hvc_xen.c b/drivers/char/hvc_xen.c index d5fe0a8952f..db2ae421627 100644 --- a/drivers/char/hvc_xen.c +++ b/drivers/char/hvc_xen.c @@ -39,9 +39,14 @@ static int xencons_irq; /* ------------------------------------------------------------------ */ +static unsigned long console_pfn = ~0ul; + static inline struct xencons_interface *xencons_interface(void) { - return mfn_to_virt(xen_start_info->console.domU.mfn); + if (console_pfn == ~0ul) + return mfn_to_virt(xen_start_info->console.domU.mfn); + else + return __va(console_pfn << PAGE_SHIFT); } static inline void notify_daemon(void) @@ -101,20 +106,32 @@ static int __init xen_init(void) { struct hvc_struct *hp; - if (!is_running_on_xen()) - return 0; + if (!is_running_on_xen() || + is_initial_xendomain() || + !xen_start_info->console.domU.evtchn) + return -ENODEV; xencons_irq = bind_evtchn_to_irq(xen_start_info->console.domU.evtchn); if (xencons_irq < 0) - xencons_irq = 0 /* NO_IRQ */; + xencons_irq = 0; /* NO_IRQ */ + hp = hvc_alloc(HVC_COOKIE, xencons_irq, &hvc_ops, 256); if (IS_ERR(hp)) return PTR_ERR(hp); hvc = hp; + + console_pfn = mfn_to_pfn(xen_start_info->console.domU.mfn); + return 0; } +void xen_console_resume(void) +{ + if (xencons_irq) + rebind_evtchn_irq(xen_start_info->console.domU.evtchn, xencons_irq); +} + static void __exit xen_fini(void) { if (hvc) diff --git a/include/xen/hvc-console.h b/include/xen/hvc-console.h index efc3237ab99..fd5483a059b 100644 --- a/include/xen/hvc-console.h +++ b/include/xen/hvc-console.h @@ -3,6 +3,8 @@ extern struct console xenboot_console; +void xen_console_resume(void); + void xen_raw_console_write(const char *str); void xen_raw_printk(const char *fmt, ...); -- cgit v1.2.3-70-g09d2 From 7d88d32a4670af583c896e5ecd3929b78538ca62 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Mon, 26 May 2008 23:31:26 +0100 Subject: xenbus: rebind irq on restore When restoring, rebind the existing xenbus irq to the new xenbus event channel. (It turns out in practice that this is always the same, and is never updated on restore. That's a bug, but Xeno-linux has been like this for a long time, so it can't really be fixed.) Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Thomas Gleixner --- drivers/xen/xenbus/xenbus_comms.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/xen/xenbus/xenbus_comms.c b/drivers/xen/xenbus/xenbus_comms.c index 6efbe3f29ca..090c61ee8fd 100644 --- a/drivers/xen/xenbus/xenbus_comms.c +++ b/drivers/xen/xenbus/xenbus_comms.c @@ -203,7 +203,6 @@ int xb_read(void *data, unsigned len) int xb_init_comms(void) { struct xenstore_domain_interface *intf = xen_store_interface; - int err; if (intf->req_prod != intf->req_cons) printk(KERN_ERR "XENBUS request ring is not quiescent " @@ -216,18 +215,20 @@ int xb_init_comms(void) intf->rsp_cons = intf->rsp_prod; } - if (xenbus_irq) - unbind_from_irqhandler(xenbus_irq, &xb_waitq); + if (xenbus_irq) { + /* Already have an irq; assume we're resuming */ + rebind_evtchn_irq(xen_store_evtchn, xenbus_irq); + } else { + int err; + err = bind_evtchn_to_irqhandler(xen_store_evtchn, wake_waiting, + 0, "xenbus", &xb_waitq); + if (err <= 0) { + printk(KERN_ERR "XENBUS request irq failed %i\n", err); + return err; + } - err = bind_evtchn_to_irqhandler( - xen_store_evtchn, wake_waiting, - 0, "xenbus", &xb_waitq); - if (err <= 0) { - printk(KERN_ERR "XENBUS request irq failed %i\n", err); - return err; + xenbus_irq = err; } - xenbus_irq = err; - return 0; } -- cgit v1.2.3-70-g09d2 From 0e91398f2a5d4eb6b07df8115917d0d1cf3e9b58 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Mon, 26 May 2008 23:31:27 +0100 Subject: xen: implement save/restore This patch implements Xen save/restore and migration. Saving is triggered via xenbus, which is polled in drivers/xen/manage.c. When a suspend request comes in, the kernel prepares itself for saving by: 1 - Freeze all processes. This is primarily to prevent any partially-completed pagetable updates from confusing the suspend process. If CONFIG_PREEMPT isn't defined, then this isn't necessary. 2 - Suspend xenbus and other devices 3 - Stop_machine, to make sure all the other vcpus are quiescent. The Xen tools require the domain to run its save off vcpu0. 4 - Within the stop_machine state, it pins any unpinned pgds (under construction or destruction), performs canonicalizes various other pieces of state (mostly converting mfns to pfns), and finally 5 - Suspend the domain Restore reverses the steps used to save the domain, ending when all the frozen processes are thawed. Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Thomas Gleixner --- arch/x86/xen/Makefile | 2 +- arch/x86/xen/enlighten.c | 6 +-- arch/x86/xen/mmu.c | 46 +++++++++++++++++ arch/x86/xen/smp.c | 2 +- arch/x86/xen/suspend.c | 42 +++++++++++++++ arch/x86/xen/time.c | 8 +++ arch/x86/xen/xen-ops.h | 4 ++ drivers/xen/events.c | 83 +++++++++++++++++++++++++++++ drivers/xen/grant-table.c | 4 +- drivers/xen/manage.c | 126 ++++++++++++++++++++++++++++++++++++++++----- include/linux/page-flags.h | 1 + include/xen/events.h | 3 ++ include/xen/grant_table.h | 3 ++ include/xen/xen-ops.h | 9 ++++ 14 files changed, 318 insertions(+), 21 deletions(-) create mode 100644 arch/x86/xen/suspend.c (limited to 'drivers') diff --git a/arch/x86/xen/Makefile b/arch/x86/xen/Makefile index 40b119b6b10..2ba2d164913 100644 --- a/arch/x86/xen/Makefile +++ b/arch/x86/xen/Makefile @@ -1,4 +1,4 @@ obj-y := enlighten.o setup.o multicalls.o mmu.o \ - time.o xen-asm.o grant-table.o + time.o xen-asm.o grant-table.o suspend.o obj-$(CONFIG_SMP) += smp.o diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index ce67dc8f36a..b94f63ac228 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -857,7 +857,7 @@ static __init void xen_pagetable_setup_start(pgd_t *base) PFN_DOWN(__pa(xen_start_info->pt_base))); } -static __init void setup_shared_info(void) +void xen_setup_shared_info(void) { if (!xen_feature(XENFEAT_auto_translated_physmap)) { unsigned long addr = fix_to_virt(FIX_PARAVIRT_BOOTMAP); @@ -894,7 +894,7 @@ static __init void xen_pagetable_setup_done(pgd_t *base) pv_mmu_ops.release_pmd = xen_release_pmd; pv_mmu_ops.set_pte = xen_set_pte; - setup_shared_info(); + xen_setup_shared_info(); /* Actually pin the pagetable down, but we can't set PG_pinned yet because the page structures don't exist yet. */ @@ -902,7 +902,7 @@ static __init void xen_pagetable_setup_done(pgd_t *base) } /* This is called once we have the cpu_possible_map */ -void __init xen_setup_vcpu_info_placement(void) +void xen_setup_vcpu_info_placement(void) { int cpu; diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index 4740cda3656..e95955968ba 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c @@ -560,6 +560,29 @@ void xen_pgd_pin(pgd_t *pgd) xen_mc_issue(0); } +/* + * On save, we need to pin all pagetables to make sure they get their + * mfns turned into pfns. Search the list for any unpinned pgds and pin + * them (unpinned pgds are not currently in use, probably because the + * process is under construction or destruction). + */ +void xen_mm_pin_all(void) +{ + unsigned long flags; + struct page *page; + + spin_lock_irqsave(&pgd_lock, flags); + + list_for_each_entry(page, &pgd_list, lru) { + if (!PagePinned(page)) { + xen_pgd_pin((pgd_t *)page_address(page)); + SetPageSavePinned(page); + } + } + + spin_unlock_irqrestore(&pgd_lock, flags); +} + /* The init_mm pagetable is really pinned as soon as its created, but that's before we have page structures to store the bits. So do all the book-keeping now. */ @@ -617,6 +640,29 @@ static void xen_pgd_unpin(pgd_t *pgd) xen_mc_issue(0); } +/* + * On resume, undo any pinning done at save, so that the rest of the + * kernel doesn't see any unexpected pinned pagetables. + */ +void xen_mm_unpin_all(void) +{ + unsigned long flags; + struct page *page; + + spin_lock_irqsave(&pgd_lock, flags); + + list_for_each_entry(page, &pgd_list, lru) { + if (PageSavePinned(page)) { + BUG_ON(!PagePinned(page)); + printk("unpinning pinned %p\n", page_address(page)); + xen_pgd_unpin((pgd_t *)page_address(page)); + ClearPageSavePinned(page); + } + } + + spin_unlock_irqrestore(&pgd_lock, flags); +} + void xen_activate_mm(struct mm_struct *prev, struct mm_struct *next) { spin_lock(&next->page_table_lock); diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c index 74ab8968c52..d2e3c20127d 100644 --- a/arch/x86/xen/smp.c +++ b/arch/x86/xen/smp.c @@ -35,7 +35,7 @@ #include "xen-ops.h" #include "mmu.h" -static cpumask_t xen_cpu_initialized_map; +cpumask_t xen_cpu_initialized_map; static DEFINE_PER_CPU(int, resched_irq) = -1; static DEFINE_PER_CPU(int, callfunc_irq) = -1; static DEFINE_PER_CPU(int, debug_irq) = -1; diff --git a/arch/x86/xen/suspend.c b/arch/x86/xen/suspend.c new file mode 100644 index 00000000000..7620a16fe53 --- /dev/null +++ b/arch/x86/xen/suspend.c @@ -0,0 +1,42 @@ +#include + +#include +#include +#include + +#include +#include + +#include "xen-ops.h" +#include "mmu.h" + +void xen_pre_suspend(void) +{ + xen_start_info->store_mfn = mfn_to_pfn(xen_start_info->store_mfn); + xen_start_info->console.domU.mfn = + mfn_to_pfn(xen_start_info->console.domU.mfn); + + BUG_ON(!irqs_disabled()); + + HYPERVISOR_shared_info = &xen_dummy_shared_info; + if (HYPERVISOR_update_va_mapping(fix_to_virt(FIX_PARAVIRT_BOOTMAP), + __pte_ma(0), 0)) + BUG(); +} + +void xen_post_suspend(int suspend_cancelled) +{ + if (suspend_cancelled) { + xen_start_info->store_mfn = + pfn_to_mfn(xen_start_info->store_mfn); + xen_start_info->console.domU.mfn = + pfn_to_mfn(xen_start_info->console.domU.mfn); + } else { +#ifdef CONFIG_SMP + xen_cpu_initialized_map = cpu_online_map; +#endif + } + + xen_setup_shared_info(); +} + diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c index c39e1a5aa24..0bef256e5f2 100644 --- a/arch/x86/xen/time.c +++ b/arch/x86/xen/time.c @@ -572,6 +572,14 @@ void xen_setup_cpu_clockevents(void) clockevents_register_device(&__get_cpu_var(xen_clock_events)); } +void xen_time_suspend(void) +{ +} + +void xen_time_resume(void) +{ +} + __init void xen_time_init(void) { int cpu = smp_processor_id(); diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h index a1bc89a8f16..a0503acad66 100644 --- a/arch/x86/xen/xen-ops.h +++ b/arch/x86/xen/xen-ops.h @@ -9,6 +9,7 @@ extern const char xen_hypervisor_callback[]; extern const char xen_failsafe_callback[]; +struct trap_info; void xen_copy_trap_info(struct trap_info *traps); DECLARE_PER_CPU(unsigned long, xen_cr3); @@ -19,6 +20,7 @@ extern struct shared_info xen_dummy_shared_info; extern struct shared_info *HYPERVISOR_shared_info; void xen_setup_mfn_list_list(void); +void xen_setup_shared_info(void); char * __init xen_memory_setup(void); void __init xen_arch_setup(void); @@ -59,6 +61,8 @@ int xen_smp_call_function_single(int cpu, void (*func) (void *info), void *info, int xen_smp_call_function_mask(cpumask_t mask, void (*func)(void *), void *info, int wait); +extern cpumask_t xen_cpu_initialized_map; + /* Declare an asm function, along with symbols needed to make it inlineable */ diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 70375a69076..73d78dc9b87 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -674,6 +674,89 @@ static int retrigger_dynirq(unsigned int irq) return ret; } +static void restore_cpu_virqs(unsigned int cpu) +{ + struct evtchn_bind_virq bind_virq; + int virq, irq, evtchn; + + for (virq = 0; virq < NR_VIRQS; virq++) { + if ((irq = per_cpu(virq_to_irq, cpu)[virq]) == -1) + continue; + + BUG_ON(irq_info[irq].type != IRQT_VIRQ); + BUG_ON(irq_info[irq].index != virq); + + /* Get a new binding from Xen. */ + bind_virq.virq = virq; + bind_virq.vcpu = cpu; + if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq, + &bind_virq) != 0) + BUG(); + evtchn = bind_virq.port; + + /* Record the new mapping. */ + evtchn_to_irq[evtchn] = irq; + irq_info[irq] = mk_irq_info(IRQT_VIRQ, virq, evtchn); + bind_evtchn_to_cpu(evtchn, cpu); + + /* Ready for use. */ + unmask_evtchn(evtchn); + } +} + +static void restore_cpu_ipis(unsigned int cpu) +{ + struct evtchn_bind_ipi bind_ipi; + int ipi, irq, evtchn; + + for (ipi = 0; ipi < XEN_NR_IPIS; ipi++) { + if ((irq = per_cpu(ipi_to_irq, cpu)[ipi]) == -1) + continue; + + BUG_ON(irq_info[irq].type != IRQT_IPI); + BUG_ON(irq_info[irq].index != ipi); + + /* Get a new binding from Xen. */ + bind_ipi.vcpu = cpu; + if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_ipi, + &bind_ipi) != 0) + BUG(); + evtchn = bind_ipi.port; + + /* Record the new mapping. */ + evtchn_to_irq[evtchn] = irq; + irq_info[irq] = mk_irq_info(IRQT_IPI, ipi, evtchn); + bind_evtchn_to_cpu(evtchn, cpu); + + /* Ready for use. */ + unmask_evtchn(evtchn); + + } +} + +void xen_irq_resume(void) +{ + unsigned int cpu, irq, evtchn; + + init_evtchn_cpu_bindings(); + + /* New event-channel space is not 'live' yet. */ + for (evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++) + mask_evtchn(evtchn); + + /* No IRQ <-> event-channel mappings. */ + for (irq = 0; irq < NR_IRQS; irq++) + irq_info[irq].evtchn = 0; /* zap event-channel binding */ + + for (evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++) + evtchn_to_irq[evtchn] = -1; + + for_each_possible_cpu(cpu) { + restore_cpu_virqs(cpu); + restore_cpu_ipis(cpu); + } +} + static struct irq_chip xen_dynamic_chip __read_mostly = { .name = "xen-dyn", .mask = disable_dynirq, diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c index 52b6b41b909..e9e11168616 100644 --- a/drivers/xen/grant-table.c +++ b/drivers/xen/grant-table.c @@ -471,14 +471,14 @@ static int gnttab_map(unsigned int start_idx, unsigned int end_idx) return 0; } -static int gnttab_resume(void) +int gnttab_resume(void) { if (max_nr_grant_frames() < nr_grant_frames) return -ENOSYS; return gnttab_map(0, nr_grant_frames - 1); } -static int gnttab_suspend(void) +int gnttab_suspend(void) { arch_gnttab_unmap_shared(shared, nr_grant_frames); return 0; diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c index aa7af9e6abc..ba85fa2cff3 100644 --- a/drivers/xen/manage.c +++ b/drivers/xen/manage.c @@ -5,21 +5,113 @@ #include #include #include +#include +#include #include - -#define SHUTDOWN_INVALID -1 -#define SHUTDOWN_POWEROFF 0 -#define SHUTDOWN_SUSPEND 2 -/* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only - * report a crash, not be instructed to crash! - * HALT is the same as POWEROFF, as far as we're concerned. The tools use - * the distinction when we return the reason code to them. - */ -#define SHUTDOWN_HALT 4 +#include +#include +#include +#include + +#include +#include + +enum shutdown_state { + SHUTDOWN_INVALID = -1, + SHUTDOWN_POWEROFF = 0, + SHUTDOWN_SUSPEND = 2, + /* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only + report a crash, not be instructed to crash! + HALT is the same as POWEROFF, as far as we're concerned. The tools use + the distinction when we return the reason code to them. */ + SHUTDOWN_HALT = 4, +}; /* Ignore multiple shutdown requests. */ -static int shutting_down = SHUTDOWN_INVALID; +static enum shutdown_state shutting_down = SHUTDOWN_INVALID; + +static int xen_suspend(void *data) +{ + int *cancelled = data; + + BUG_ON(!irqs_disabled()); + + load_cr3(swapper_pg_dir); + + xen_mm_pin_all(); + gnttab_suspend(); + xen_time_suspend(); + xen_pre_suspend(); + + /* + * This hypercall returns 1 if suspend was cancelled + * or the domain was merely checkpointed, and 0 if it + * is resuming in a new domain. + */ + *cancelled = HYPERVISOR_suspend(virt_to_mfn(xen_start_info)); + + xen_post_suspend(*cancelled); + xen_time_resume(); + gnttab_resume(); + xen_mm_unpin_all(); + + if (!*cancelled) { + xen_irq_resume(); + xen_console_resume(); + } + + return 0; +} + +static void do_suspend(void) +{ + int err; + int cancelled = 1; + + shutting_down = SHUTDOWN_SUSPEND; + +#ifdef CONFIG_PREEMPT + /* If the kernel is preemptible, we need to freeze all the processes + to prevent them from being in the middle of a pagetable update + during suspend. */ + err = freeze_processes(); + if (err) { + printk(KERN_ERR "xen suspend: freeze failed %d\n", err); + return; + } +#endif + + err = device_suspend(PMSG_SUSPEND); + if (err) { + printk(KERN_ERR "xen suspend: device_suspend %d\n", err); + goto out; + } + + printk("suspending xenbus...\n"); + /* XXX use normal device tree? */ + xenbus_suspend(); + + err = stop_machine_run(xen_suspend, &cancelled, 0); + if (err) { + printk(KERN_ERR "failed to start xen_suspend: %d\n", err); + goto out; + } + + if (!cancelled) + xenbus_resume(); + else + xenbus_suspend_cancel(); + + device_resume(); + + +out: +#ifdef CONFIG_PREEMPT + thaw_processes(); +#endif + shutting_down = SHUTDOWN_INVALID; +} static void shutdown_handler(struct xenbus_watch *watch, const char **vec, unsigned int len) @@ -52,11 +144,17 @@ static void shutdown_handler(struct xenbus_watch *watch, } if (strcmp(str, "poweroff") == 0 || - strcmp(str, "halt") == 0) + strcmp(str, "halt") == 0) { + shutting_down = SHUTDOWN_POWEROFF; orderly_poweroff(false); - else if (strcmp(str, "reboot") == 0) + } else if (strcmp(str, "reboot") == 0) { + shutting_down = SHUTDOWN_POWEROFF; /* ? */ ctrl_alt_del(); - else { +#ifdef CONFIG_PM_SLEEP + } else if (strcmp(str, "suspend") == 0) { + do_suspend(); +#endif + } else { printk(KERN_INFO "Ignoring shutdown request: %s\n", str); shutting_down = SHUTDOWN_INVALID; } diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h index 590cff32415..02955a1c3d7 100644 --- a/include/linux/page-flags.h +++ b/include/linux/page-flags.h @@ -157,6 +157,7 @@ PAGEFLAG(Active, active) __CLEARPAGEFLAG(Active, active) __PAGEFLAG(Slab, slab) PAGEFLAG(Checked, owner_priv_1) /* Used by some filesystems */ PAGEFLAG(Pinned, owner_priv_1) TESTSCFLAG(Pinned, owner_priv_1) /* Xen */ +PAGEFLAG(SavePinned, dirty); /* Xen */ PAGEFLAG(Reserved, reserved) __CLEARPAGEFLAG(Reserved, reserved) PAGEFLAG(Private, private) __CLEARPAGEFLAG(Private, private) __SETPAGEFLAG(Private, private) diff --git a/include/xen/events.h b/include/xen/events.h index a82ec0c45c3..67c4436554a 100644 --- a/include/xen/events.h +++ b/include/xen/events.h @@ -41,4 +41,7 @@ static inline void notify_remote_via_evtchn(int port) } extern void notify_remote_via_irq(int irq); + +extern void xen_irq_resume(void); + #endif /* _XEN_EVENTS_H */ diff --git a/include/xen/grant_table.h b/include/xen/grant_table.h index 46620484612..a40f1cd91be 100644 --- a/include/xen/grant_table.h +++ b/include/xen/grant_table.h @@ -51,6 +51,9 @@ struct gnttab_free_callback { u16 count; }; +int gnttab_suspend(void); +int gnttab_resume(void); + int gnttab_grant_foreign_access(domid_t domid, unsigned long frame, int readonly); diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h index 10ddfe0142d..5d7a6db54a8 100644 --- a/include/xen/xen-ops.h +++ b/include/xen/xen-ops.h @@ -5,4 +5,13 @@ DECLARE_PER_CPU(struct vcpu_info *, xen_vcpu); +void xen_pre_suspend(void); +void xen_post_suspend(int suspend_cancelled); + +void xen_mm_pin_all(void); +void xen_mm_unpin_all(void); + +void xen_time_suspend(void); +void xen_time_resume(void); + #endif /* INCLUDE_XEN_OPS_H */ -- cgit v1.2.3-70-g09d2 From 359cdd3f866b6219a6729e313faf2221397f3278 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Mon, 26 May 2008 23:31:28 +0100 Subject: xen: maintain clock offset over save/restore Hook into the device model to make sure that timekeeping's resume handler is called. This deals with our clocksource's non-monotonicity over the save/restore. Explicitly call clock_has_changed() to make sure that all the timers get retriggered properly. Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Thomas Gleixner --- arch/x86/xen/time.c | 8 -------- drivers/xen/manage.c | 15 ++++++++++++--- include/xen/xen-ops.h | 3 --- 3 files changed, 12 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c index 0bef256e5f2..c39e1a5aa24 100644 --- a/arch/x86/xen/time.c +++ b/arch/x86/xen/time.c @@ -572,14 +572,6 @@ void xen_setup_cpu_clockevents(void) clockevents_register_device(&__get_cpu_var(xen_clock_events)); } -void xen_time_suspend(void) -{ -} - -void xen_time_resume(void) -{ -} - __init void xen_time_init(void) { int cpu = smp_processor_id(); diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c index ba85fa2cff3..675c3dd2396 100644 --- a/drivers/xen/manage.c +++ b/drivers/xen/manage.c @@ -34,14 +34,21 @@ static enum shutdown_state shutting_down = SHUTDOWN_INVALID; static int xen_suspend(void *data) { int *cancelled = data; + int err; BUG_ON(!irqs_disabled()); load_cr3(swapper_pg_dir); + err = device_power_down(PMSG_SUSPEND); + if (err) { + printk(KERN_ERR "xen_suspend: device_power_down failed: %d\n", + err); + return err; + } + xen_mm_pin_all(); gnttab_suspend(); - xen_time_suspend(); xen_pre_suspend(); /* @@ -52,10 +59,11 @@ static int xen_suspend(void *data) *cancelled = HYPERVISOR_suspend(virt_to_mfn(xen_start_info)); xen_post_suspend(*cancelled); - xen_time_resume(); gnttab_resume(); xen_mm_unpin_all(); + device_power_up(); + if (!*cancelled) { xen_irq_resume(); xen_console_resume(); @@ -105,7 +113,8 @@ static void do_suspend(void) device_resume(); - + /* Make sure timer events get retriggered on all CPUs */ + clock_was_set(); out: #ifdef CONFIG_PREEMPT thaw_processes(); diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h index 5d7a6db54a8..a706d6a7896 100644 --- a/include/xen/xen-ops.h +++ b/include/xen/xen-ops.h @@ -11,7 +11,4 @@ void xen_post_suspend(int suspend_cancelled); void xen_mm_pin_all(void); void xen_mm_unpin_all(void); -void xen_time_suspend(void); -void xen_time_resume(void); - #endif /* INCLUDE_XEN_OPS_H */ -- cgit v1.2.3-70-g09d2 From 95e2869adc13041baf3beecb97ab8e38c01525ae Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Sun, 25 May 2008 23:44:14 -0700 Subject: tg3: Pure code movement. This patch moves some functions towards the top of the file to avoid unnecessary function prototypes. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Signed-off-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 476 +++++++++++++++++++++++++++--------------------------- 1 file changed, 237 insertions(+), 239 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 07b3f77e762..7928acc1ec7 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -804,6 +804,243 @@ static int tg3_writephy(struct tg3 *tp, int reg, u32 val) return ret; } +static int tg3_bmcr_reset(struct tg3 *tp) +{ + u32 phy_control; + int limit, err; + + /* OK, reset it, and poll the BMCR_RESET bit until it + * clears or we time out. + */ + phy_control = BMCR_RESET; + err = tg3_writephy(tp, MII_BMCR, phy_control); + if (err != 0) + return -EBUSY; + + limit = 5000; + while (limit--) { + err = tg3_readphy(tp, MII_BMCR, &phy_control); + if (err != 0) + return -EBUSY; + + if ((phy_control & BMCR_RESET) == 0) { + udelay(40); + break; + } + udelay(10); + } + if (limit <= 0) + return -EBUSY; + + return 0; +} + +/* tp->lock is held. */ +static void tg3_wait_for_event_ack(struct tg3 *tp) +{ + int i; + + /* Wait for up to 2.5 milliseconds */ + for (i = 0; i < 250000; i++) { + if (!(tr32(GRC_RX_CPU_EVENT) & GRC_RX_CPU_DRIVER_EVENT)) + break; + udelay(10); + } +} + +/* tp->lock is held. */ +static void tg3_ump_link_report(struct tg3 *tp) +{ + u32 reg; + u32 val; + + if (!(tp->tg3_flags2 & TG3_FLG2_5780_CLASS) || + !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) + return; + + tg3_wait_for_event_ack(tp); + + tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_LINK_UPDATE); + + tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 14); + + val = 0; + if (!tg3_readphy(tp, MII_BMCR, ®)) + val = reg << 16; + if (!tg3_readphy(tp, MII_BMSR, ®)) + val |= (reg & 0xffff); + tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX, val); + + val = 0; + if (!tg3_readphy(tp, MII_ADVERTISE, ®)) + val = reg << 16; + if (!tg3_readphy(tp, MII_LPA, ®)) + val |= (reg & 0xffff); + tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 4, val); + + val = 0; + if (!(tp->tg3_flags2 & TG3_FLG2_MII_SERDES)) { + if (!tg3_readphy(tp, MII_CTRL1000, ®)) + val = reg << 16; + if (!tg3_readphy(tp, MII_STAT1000, ®)) + val |= (reg & 0xffff); + } + tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 8, val); + + if (!tg3_readphy(tp, MII_PHYADDR, ®)) + val = reg << 16; + else + val = 0; + tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 12, val); + + val = tr32(GRC_RX_CPU_EVENT); + val |= GRC_RX_CPU_DRIVER_EVENT; + tw32_f(GRC_RX_CPU_EVENT, val); +} + +static void tg3_link_report(struct tg3 *tp) +{ + if (!netif_carrier_ok(tp->dev)) { + if (netif_msg_link(tp)) + printk(KERN_INFO PFX "%s: Link is down.\n", + tp->dev->name); + tg3_ump_link_report(tp); + } else if (netif_msg_link(tp)) { + printk(KERN_INFO PFX "%s: Link is up at %d Mbps, %s duplex.\n", + tp->dev->name, + (tp->link_config.active_speed == SPEED_1000 ? + 1000 : + (tp->link_config.active_speed == SPEED_100 ? + 100 : 10)), + (tp->link_config.active_duplex == DUPLEX_FULL ? + "full" : "half")); + + printk(KERN_INFO PFX + "%s: Flow control is %s for TX and %s for RX.\n", + tp->dev->name, + (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_TX) ? + "on" : "off", + (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_RX) ? + "on" : "off"); + tg3_ump_link_report(tp); + } +} + +static u16 tg3_advert_flowctrl_1000T(u8 flow_ctrl) +{ + u16 miireg; + + if ((flow_ctrl & TG3_FLOW_CTRL_TX) && (flow_ctrl & TG3_FLOW_CTRL_RX)) + miireg = ADVERTISE_PAUSE_CAP; + else if (flow_ctrl & TG3_FLOW_CTRL_TX) + miireg = ADVERTISE_PAUSE_ASYM; + else if (flow_ctrl & TG3_FLOW_CTRL_RX) + miireg = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; + else + miireg = 0; + + return miireg; +} + +static u16 tg3_advert_flowctrl_1000X(u8 flow_ctrl) +{ + u16 miireg; + + if ((flow_ctrl & TG3_FLOW_CTRL_TX) && (flow_ctrl & TG3_FLOW_CTRL_RX)) + miireg = ADVERTISE_1000XPAUSE; + else if (flow_ctrl & TG3_FLOW_CTRL_TX) + miireg = ADVERTISE_1000XPSE_ASYM; + else if (flow_ctrl & TG3_FLOW_CTRL_RX) + miireg = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM; + else + miireg = 0; + + return miireg; +} + +static u8 tg3_resolve_flowctrl_1000T(u16 lcladv, u16 rmtadv) +{ + u8 cap = 0; + + if (lcladv & ADVERTISE_PAUSE_CAP) { + if (lcladv & ADVERTISE_PAUSE_ASYM) { + if (rmtadv & LPA_PAUSE_CAP) + cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX; + else if (rmtadv & LPA_PAUSE_ASYM) + cap = TG3_FLOW_CTRL_RX; + } else { + if (rmtadv & LPA_PAUSE_CAP) + cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX; + } + } else if (lcladv & ADVERTISE_PAUSE_ASYM) { + if ((rmtadv & LPA_PAUSE_CAP) && (rmtadv & LPA_PAUSE_ASYM)) + cap = TG3_FLOW_CTRL_TX; + } + + return cap; +} + +static u8 tg3_resolve_flowctrl_1000X(u16 lcladv, u16 rmtadv) +{ + u8 cap = 0; + + if (lcladv & ADVERTISE_1000XPAUSE) { + if (lcladv & ADVERTISE_1000XPSE_ASYM) { + if (rmtadv & LPA_1000XPAUSE) + cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX; + else if (rmtadv & LPA_1000XPAUSE_ASYM) + cap = TG3_FLOW_CTRL_RX; + } else { + if (rmtadv & LPA_1000XPAUSE) + cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX; + } + } else if (lcladv & ADVERTISE_1000XPSE_ASYM) { + if ((rmtadv & LPA_1000XPAUSE) && (rmtadv & LPA_1000XPAUSE_ASYM)) + cap = TG3_FLOW_CTRL_TX; + } + + return cap; +} + +static void tg3_setup_flow_control(struct tg3 *tp, u32 local_adv, u32 remote_adv) +{ + u8 new_tg3_flags = 0; + u32 old_rx_mode = tp->rx_mode; + u32 old_tx_mode = tp->tx_mode; + + if (tp->link_config.autoneg == AUTONEG_ENABLE && + (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG)) { + if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) + new_tg3_flags = tg3_resolve_flowctrl_1000X(local_adv, + remote_adv); + else + new_tg3_flags = tg3_resolve_flowctrl_1000T(local_adv, + remote_adv); + } else { + new_tg3_flags = tp->link_config.flowctrl; + } + + tp->link_config.active_flowctrl = new_tg3_flags; + + if (new_tg3_flags & TG3_FLOW_CTRL_RX) + tp->rx_mode |= RX_MODE_FLOW_CTRL_ENABLE; + else + tp->rx_mode &= ~RX_MODE_FLOW_CTRL_ENABLE; + + if (old_rx_mode != tp->rx_mode) { + tw32_f(MAC_RX_MODE, tp->rx_mode); + } + + if (new_tg3_flags & TG3_FLOW_CTRL_TX) + tp->tx_mode |= TX_MODE_FLOW_CTRL_ENABLE; + else + tp->tx_mode &= ~TX_MODE_FLOW_CTRL_ENABLE; + + if (old_tx_mode != tp->tx_mode) { + tw32_f(MAC_TX_MODE, tp->tx_mode); + } +} + static void tg3_phydsp_write(struct tg3 *tp, u32 reg, u32 val) { tg3_writephy(tp, MII_TG3_DSP_ADDRESS, reg); @@ -861,37 +1098,6 @@ static void tg3_phy_set_wirespeed(struct tg3 *tp) (val | (1 << 15) | (1 << 4))); } -static int tg3_bmcr_reset(struct tg3 *tp) -{ - u32 phy_control; - int limit, err; - - /* OK, reset it, and poll the BMCR_RESET bit until it - * clears or we time out. - */ - phy_control = BMCR_RESET; - err = tg3_writephy(tp, MII_BMCR, phy_control); - if (err != 0) - return -EBUSY; - - limit = 5000; - while (limit--) { - err = tg3_readphy(tp, MII_BMCR, &phy_control); - if (err != 0) - return -EBUSY; - - if ((phy_control & BMCR_RESET) == 0) { - udelay(40); - break; - } - udelay(10); - } - if (limit <= 0) - return -EBUSY; - - return 0; -} - static void tg3_phy_apply_otp(struct tg3 *tp) { u32 otp, phy; @@ -1115,8 +1321,6 @@ static int tg3_phy_reset_5703_4_5(struct tg3 *tp) return err; } -static void tg3_link_report(struct tg3 *); - /* This will reset the tigon3 PHY if there is no valid * link unless the FORCE argument is non-zero. */ @@ -1656,212 +1860,6 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) return 0; } -/* tp->lock is held. */ -static void tg3_wait_for_event_ack(struct tg3 *tp) -{ - int i; - - /* Wait for up to 2.5 milliseconds */ - for (i = 0; i < 250000; i++) { - if (!(tr32(GRC_RX_CPU_EVENT) & GRC_RX_CPU_DRIVER_EVENT)) - break; - udelay(10); - } -} - -/* tp->lock is held. */ -static void tg3_ump_link_report(struct tg3 *tp) -{ - u32 reg; - u32 val; - - if (!(tp->tg3_flags2 & TG3_FLG2_5780_CLASS) || - !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) - return; - - tg3_wait_for_event_ack(tp); - - tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_LINK_UPDATE); - - tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 14); - - val = 0; - if (!tg3_readphy(tp, MII_BMCR, ®)) - val = reg << 16; - if (!tg3_readphy(tp, MII_BMSR, ®)) - val |= (reg & 0xffff); - tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX, val); - - val = 0; - if (!tg3_readphy(tp, MII_ADVERTISE, ®)) - val = reg << 16; - if (!tg3_readphy(tp, MII_LPA, ®)) - val |= (reg & 0xffff); - tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 4, val); - - val = 0; - if (!(tp->tg3_flags2 & TG3_FLG2_MII_SERDES)) { - if (!tg3_readphy(tp, MII_CTRL1000, ®)) - val = reg << 16; - if (!tg3_readphy(tp, MII_STAT1000, ®)) - val |= (reg & 0xffff); - } - tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 8, val); - - if (!tg3_readphy(tp, MII_PHYADDR, ®)) - val = reg << 16; - else - val = 0; - tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 12, val); - - val = tr32(GRC_RX_CPU_EVENT); - val |= GRC_RX_CPU_DRIVER_EVENT; - tw32_f(GRC_RX_CPU_EVENT, val); -} - -static void tg3_link_report(struct tg3 *tp) -{ - if (!netif_carrier_ok(tp->dev)) { - if (netif_msg_link(tp)) - printk(KERN_INFO PFX "%s: Link is down.\n", - tp->dev->name); - tg3_ump_link_report(tp); - } else if (netif_msg_link(tp)) { - printk(KERN_INFO PFX "%s: Link is up at %d Mbps, %s duplex.\n", - tp->dev->name, - (tp->link_config.active_speed == SPEED_1000 ? - 1000 : - (tp->link_config.active_speed == SPEED_100 ? - 100 : 10)), - (tp->link_config.active_duplex == DUPLEX_FULL ? - "full" : "half")); - - printk(KERN_INFO PFX - "%s: Flow control is %s for TX and %s for RX.\n", - tp->dev->name, - (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_TX) ? - "on" : "off", - (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_RX) ? - "on" : "off"); - tg3_ump_link_report(tp); - } -} - -static u16 tg3_advert_flowctrl_1000T(u8 flow_ctrl) -{ - u16 miireg; - - if ((flow_ctrl & TG3_FLOW_CTRL_TX) && (flow_ctrl & TG3_FLOW_CTRL_RX)) - miireg = ADVERTISE_PAUSE_CAP; - else if (flow_ctrl & TG3_FLOW_CTRL_TX) - miireg = ADVERTISE_PAUSE_ASYM; - else if (flow_ctrl & TG3_FLOW_CTRL_RX) - miireg = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; - else - miireg = 0; - - return miireg; -} - -static u16 tg3_advert_flowctrl_1000X(u8 flow_ctrl) -{ - u16 miireg; - - if ((flow_ctrl & TG3_FLOW_CTRL_TX) && (flow_ctrl & TG3_FLOW_CTRL_RX)) - miireg = ADVERTISE_1000XPAUSE; - else if (flow_ctrl & TG3_FLOW_CTRL_TX) - miireg = ADVERTISE_1000XPSE_ASYM; - else if (flow_ctrl & TG3_FLOW_CTRL_RX) - miireg = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM; - else - miireg = 0; - - return miireg; -} - -static u8 tg3_resolve_flowctrl_1000T(u16 lcladv, u16 rmtadv) -{ - u8 cap = 0; - - if (lcladv & ADVERTISE_PAUSE_CAP) { - if (lcladv & ADVERTISE_PAUSE_ASYM) { - if (rmtadv & LPA_PAUSE_CAP) - cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX; - else if (rmtadv & LPA_PAUSE_ASYM) - cap = TG3_FLOW_CTRL_RX; - } else { - if (rmtadv & LPA_PAUSE_CAP) - cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX; - } - } else if (lcladv & ADVERTISE_PAUSE_ASYM) { - if ((rmtadv & LPA_PAUSE_CAP) && (rmtadv & LPA_PAUSE_ASYM)) - cap = TG3_FLOW_CTRL_TX; - } - - return cap; -} - -static u8 tg3_resolve_flowctrl_1000X(u16 lcladv, u16 rmtadv) -{ - u8 cap = 0; - - if (lcladv & ADVERTISE_1000XPAUSE) { - if (lcladv & ADVERTISE_1000XPSE_ASYM) { - if (rmtadv & LPA_1000XPAUSE) - cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX; - else if (rmtadv & LPA_1000XPAUSE_ASYM) - cap = TG3_FLOW_CTRL_RX; - } else { - if (rmtadv & LPA_1000XPAUSE) - cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX; - } - } else if (lcladv & ADVERTISE_1000XPSE_ASYM) { - if ((rmtadv & LPA_1000XPAUSE) && (rmtadv & LPA_1000XPAUSE_ASYM)) - cap = TG3_FLOW_CTRL_TX; - } - - return cap; -} - -static void tg3_setup_flow_control(struct tg3 *tp, u32 local_adv, u32 remote_adv) -{ - u8 new_tg3_flags = 0; - u32 old_rx_mode = tp->rx_mode; - u32 old_tx_mode = tp->tx_mode; - - if (tp->link_config.autoneg == AUTONEG_ENABLE && - (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG)) { - if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) - new_tg3_flags = tg3_resolve_flowctrl_1000X(local_adv, - remote_adv); - else - new_tg3_flags = tg3_resolve_flowctrl_1000T(local_adv, - remote_adv); - } else { - new_tg3_flags = tp->link_config.flowctrl; - } - - tp->link_config.active_flowctrl = new_tg3_flags; - - if (new_tg3_flags & TG3_FLOW_CTRL_RX) - tp->rx_mode |= RX_MODE_FLOW_CTRL_ENABLE; - else - tp->rx_mode &= ~RX_MODE_FLOW_CTRL_ENABLE; - - if (old_rx_mode != tp->rx_mode) { - tw32_f(MAC_RX_MODE, tp->rx_mode); - } - - if (new_tg3_flags & TG3_FLOW_CTRL_TX) - tp->tx_mode |= TX_MODE_FLOW_CTRL_ENABLE; - else - tp->tx_mode &= ~TX_MODE_FLOW_CTRL_ENABLE; - - if (old_tx_mode != tp->tx_mode) { - tw32_f(MAC_TX_MODE, tp->tx_mode); - } -} - static void tg3_aux_stat_to_speed_duplex(struct tg3 *tp, u32 val, u16 *speed, u8 *duplex) { switch (val & MII_TG3_AUX_STAT_SPDMASK) { -- cgit v1.2.3-70-g09d2 From f51f3562d1c7df6c5a4ffee2185d713e98e76aa0 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Sun, 25 May 2008 23:45:08 -0700 Subject: tg3: Code cleanup. This patch applies cleanups that would otherwise clutter later patches. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Signed-off-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 42 +++++++++++++++--------------------------- drivers/net/tg3.h | 1 + 2 files changed, 16 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 7928acc1ec7..e402f162eb8 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -1002,43 +1002,38 @@ static u8 tg3_resolve_flowctrl_1000X(u16 lcladv, u16 rmtadv) return cap; } -static void tg3_setup_flow_control(struct tg3 *tp, u32 local_adv, u32 remote_adv) +static void tg3_setup_flow_control(struct tg3 *tp, u32 lcladv, u32 rmtadv) { - u8 new_tg3_flags = 0; + u8 flowctrl = 0; u32 old_rx_mode = tp->rx_mode; u32 old_tx_mode = tp->tx_mode; if (tp->link_config.autoneg == AUTONEG_ENABLE && (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG)) { if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) - new_tg3_flags = tg3_resolve_flowctrl_1000X(local_adv, - remote_adv); + flowctrl = tg3_resolve_flowctrl_1000X(lcladv, rmtadv); else - new_tg3_flags = tg3_resolve_flowctrl_1000T(local_adv, - remote_adv); - } else { - new_tg3_flags = tp->link_config.flowctrl; - } + flowctrl = tg3_resolve_flowctrl_1000T(lcladv, rmtadv); + } else + flowctrl = tp->link_config.flowctrl; - tp->link_config.active_flowctrl = new_tg3_flags; + tp->link_config.active_flowctrl = flowctrl; - if (new_tg3_flags & TG3_FLOW_CTRL_RX) + if (flowctrl & TG3_FLOW_CTRL_RX) tp->rx_mode |= RX_MODE_FLOW_CTRL_ENABLE; else tp->rx_mode &= ~RX_MODE_FLOW_CTRL_ENABLE; - if (old_rx_mode != tp->rx_mode) { + if (old_rx_mode != tp->rx_mode) tw32_f(MAC_RX_MODE, tp->rx_mode); - } - if (new_tg3_flags & TG3_FLOW_CTRL_TX) + if (flowctrl & TG3_FLOW_CTRL_TX) tp->tx_mode |= TX_MODE_FLOW_CTRL_ENABLE; else tp->tx_mode &= ~TX_MODE_FLOW_CTRL_ENABLE; - if (old_tx_mode != tp->tx_mode) { + if (old_tx_mode != tp->tx_mode) tw32_f(MAC_TX_MODE, tp->tx_mode); - } } static void tg3_phydsp_write(struct tg3 *tp, u32 reg, u32 val) @@ -7091,7 +7086,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) || (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) || (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)) - val |= (1 << 29); + val |= WDMAC_MODE_STATUS_TAG_FIX; tw32_f(WDMAC_MODE, val); udelay(40); @@ -11542,14 +11537,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) } } - if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5755 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906) + if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) || + (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) tp->tg3_flags2 |= TG3_FLG2_JUMBO_CAPABLE; pcie_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_EXP); @@ -11833,8 +11822,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->phy_otp = TG3_OTP_DEFAULT; } - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) + if (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) tp->mi_mode = MAC_MI_MODE_500KHZ_CONST; else tp->mi_mode = MAC_MI_MODE_BASE; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 0404f93baa2..5643be55c1d 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -1109,6 +1109,7 @@ #define WDMAC_MODE_FIFOOREAD_ENAB 0x00000100 #define WDMAC_MODE_LNGREAD_ENAB 0x00000200 #define WDMAC_MODE_RX_ACCEL 0x00000400 +#define WDMAC_MODE_STATUS_TAG_FIX 0x20000000 #define WDMAC_STATUS 0x00004c04 #define WDMAC_STATUS_TGTABORT 0x00000004 #define WDMAC_STATUS_MSTABORT 0x00000008 -- cgit v1.2.3-70-g09d2 From dd47700310ff929b439223105364c9ee3db81511 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Sun, 25 May 2008 23:45:58 -0700 Subject: tg3: Add TG3_FLG3_USE_PHYLIB This patch introduces the TG3_FLG3_USE_PHYLIB flag and applies it to some select places. This work makes later patches a little easier to read. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Signed-off-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 86 +++++++++++++++++++++++++++++++++---------------------- drivers/net/tg3.h | 1 + 2 files changed, 53 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index e402f162eb8..538232586ee 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -1605,7 +1605,7 @@ static void tg3_power_down_phy(struct tg3 *tp) tw32_f(GRC_MISC_CFG, val | GRC_MISC_CFG_EPHY_IDDQ); udelay(40); return; - } else { + } else if (!(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) { tg3_writephy(tp, MII_TG3_EXT_CTRL, MII_TG3_EXT_CTRL_FORCE_LED_OFF); tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x01b2); @@ -1687,18 +1687,22 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) tw32(TG3PCI_MISC_HOST_CTRL, misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT); - if (tp->link_config.phy_is_low_power == 0) { + if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { tp->link_config.phy_is_low_power = 1; - tp->link_config.orig_speed = tp->link_config.speed; - tp->link_config.orig_duplex = tp->link_config.duplex; - tp->link_config.orig_autoneg = tp->link_config.autoneg; - } + } else { + if (tp->link_config.phy_is_low_power == 0) { + tp->link_config.phy_is_low_power = 1; + tp->link_config.orig_speed = tp->link_config.speed; + tp->link_config.orig_duplex = tp->link_config.duplex; + tp->link_config.orig_autoneg = tp->link_config.autoneg; + } - if (!(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)) { - tp->link_config.speed = SPEED_10; - tp->link_config.duplex = DUPLEX_HALF; - tp->link_config.autoneg = AUTONEG_ENABLE; - tg3_setup_phy(tp, 0); + if (!(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)) { + tp->link_config.speed = SPEED_10; + tp->link_config.duplex = DUPLEX_HALF; + tp->link_config.autoneg = AUTONEG_ENABLE; + tg3_setup_phy(tp, 0); + } } if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { @@ -1729,8 +1733,10 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) u32 mac_mode; if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) { - tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x5a); - udelay(40); + if (!(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) { + tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x5a); + udelay(40); + } if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES) mac_mode = MAC_MODE_PORT_MODE_GMII; @@ -3821,7 +3827,15 @@ static int tg3_poll_work(struct tg3 *tp, int work_done, int budget) sblk->status = SD_STATUS_UPDATED | (sblk->status & ~SD_STATUS_LINK_CHG); spin_lock(&tp->lock); - tg3_setup_phy(tp, 0); + if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { + tw32_f(MAC_STATUS, + (MAC_STATUS_SYNC_CHANGED | + MAC_STATUS_CFG_CHANGED | + MAC_STATUS_MI_COMPLETION | + MAC_STATUS_LNKSTATE_CHANGED)); + udelay(40); + } else + tg3_setup_phy(tp, 0); spin_unlock(&tp->lock); } } @@ -6602,7 +6616,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tg3_abort_hw(tp, 1); } - if (reset_phy) + if (reset_phy && + !(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) tg3_phy_reset(tp); err = tg3_chip_reset(tp); @@ -7153,13 +7168,6 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32_f(MAC_RX_MODE, tp->rx_mode); udelay(10); - if (tp->link_config.phy_is_low_power) { - tp->link_config.phy_is_low_power = 0; - tp->link_config.speed = tp->link_config.orig_speed; - tp->link_config.duplex = tp->link_config.orig_duplex; - tp->link_config.autoneg = tp->link_config.orig_autoneg; - } - tp->mi_mode &= ~MAC_MI_MODE_AUTO_POLL; tw32_f(MAC_MI_MODE, tp->mi_mode); udelay(80); @@ -7210,19 +7218,28 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl); } - err = tg3_setup_phy(tp, 0); - if (err) - return err; + if (!(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) { + if (tp->link_config.phy_is_low_power) { + tp->link_config.phy_is_low_power = 0; + tp->link_config.speed = tp->link_config.orig_speed; + tp->link_config.duplex = tp->link_config.orig_duplex; + tp->link_config.autoneg = tp->link_config.orig_autoneg; + } - if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906) { - u32 tmp; + err = tg3_setup_phy(tp, 0); + if (err) + return err; - /* Clear CRC stats. */ - if (!tg3_readphy(tp, MII_TG3_TEST1, &tmp)) { - tg3_writephy(tp, MII_TG3_TEST1, - tmp | MII_TG3_TEST1_CRC_EN); - tg3_readphy(tp, 0x14, &tmp); + if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906) { + u32 tmp; + + /* Clear CRC stats. */ + if (!tg3_readphy(tp, MII_TG3_TEST1, &tmp)) { + tg3_writephy(tp, MII_TG3_TEST1, + tmp | MII_TG3_TEST1_CRC_EN); + tg3_readphy(tp, 0x14, &tmp); + } } } @@ -9644,7 +9661,8 @@ static int tg3_test_loopback(struct tg3 *tp) tw32(TG3_CPMU_MUTEX_GNT, CPMU_MUTEX_GNT_DRIVER); } - if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) { + if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) && + !(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) { if (tg3_run_loopback(tp, TG3_PHY_LOOPBACK)) err |= TG3_PHY_LOOPBACK_FAILED; } diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 5643be55c1d..a3598ed9f5f 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2480,6 +2480,7 @@ struct tg3 { #define TG3_FLG3_ENABLE_APE 0x00000002 #define TG3_FLG3_5761_5784_AX_FIXES 0x00000004 #define TG3_FLG3_5701_DMA_BUG 0x00000008 +#define TG3_FLG3_USE_PHYLIB 0x00000010 struct timer_list timer; u16 timer_counter; -- cgit v1.2.3-70-g09d2 From 158d7abdae85e9ac43d99780c372d79c119f7626 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Thu, 29 May 2008 01:37:54 -0700 Subject: tg3: Add mdio bus registration This patch introduces code to register and unregister the tg3 mdio bus with the system. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Signed-off-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/Kconfig | 1 + drivers/net/tg3.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++++--- drivers/net/tg3.h | 5 ++ 3 files changed, 127 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 9f6cc8a5607..78cc9495fd4 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2228,6 +2228,7 @@ config VIA_VELOCITY config TIGON3 tristate "Broadcom Tigon3 support" depends on PCI + select PHYLIB help This driver supports Broadcom Tigon3 based gigabit Ethernet cards. diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 538232586ee..ce04c64a8a6 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -835,6 +836,115 @@ static int tg3_bmcr_reset(struct tg3 *tp) return 0; } +static int tg3_mdio_read(struct mii_bus *bp, int mii_id, int reg) +{ + struct tg3 *tp = (struct tg3 *)bp->priv; + u32 val; + + if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_PAUSED) + return -EAGAIN; + + if (tg3_readphy(tp, reg, &val)) + return -EIO; + + return val; +} + +static int tg3_mdio_write(struct mii_bus *bp, int mii_id, int reg, u16 val) +{ + struct tg3 *tp = (struct tg3 *)bp->priv; + + if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_PAUSED) + return -EAGAIN; + + if (tg3_writephy(tp, reg, val)) + return -EIO; + + return 0; +} + +static int tg3_mdio_reset(struct mii_bus *bp) +{ + return 0; +} + +static void tg3_mdio_start(struct tg3 *tp) +{ + if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) { + mutex_lock(&tp->mdio_bus.mdio_lock); + tp->tg3_flags3 &= ~TG3_FLG3_MDIOBUS_PAUSED; + mutex_unlock(&tp->mdio_bus.mdio_lock); + } + + tp->mi_mode &= ~MAC_MI_MODE_AUTO_POLL; + tw32_f(MAC_MI_MODE, tp->mi_mode); + udelay(80); +} + +static void tg3_mdio_stop(struct tg3 *tp) +{ + if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) { + mutex_lock(&tp->mdio_bus.mdio_lock); + tp->tg3_flags3 |= TG3_FLG3_MDIOBUS_PAUSED; + mutex_unlock(&tp->mdio_bus.mdio_lock); + } +} + +static int tg3_mdio_init(struct tg3 *tp) +{ + int i; + u32 reg; + struct mii_bus *mdio_bus = &tp->mdio_bus; + + tg3_mdio_start(tp); + + if (!(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) || + (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED)) + return 0; + + memset(mdio_bus, 0, sizeof(*mdio_bus)); + + mdio_bus->name = "tg3 mdio bus"; + snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%x", + (tp->pdev->bus->number << 8) | tp->pdev->devfn); + mdio_bus->priv = tp; + mdio_bus->dev = &tp->pdev->dev; + mdio_bus->read = &tg3_mdio_read; + mdio_bus->write = &tg3_mdio_write; + mdio_bus->reset = &tg3_mdio_reset; + mdio_bus->phy_mask = ~(1 << PHY_ADDR); + mdio_bus->irq = &tp->mdio_irq[0]; + + for (i = 0; i < PHY_MAX_ADDR; i++) + mdio_bus->irq[i] = PHY_POLL; + + /* The bus registration will look for all the PHYs on the mdio bus. + * Unfortunately, it does not ensure the PHY is powered up before + * accessing the PHY ID registers. A chip reset is the + * quickest way to bring the device back to an operational state.. + */ + if (tg3_readphy(tp, MII_BMCR, ®) || (reg & BMCR_PDOWN)) + tg3_bmcr_reset(tp); + + i = mdiobus_register(mdio_bus); + if (!i) + tp->tg3_flags3 |= TG3_FLG3_MDIOBUS_INITED; + else + printk(KERN_WARNING "%s: mdiobus_reg failed (0x%x)\n", + tp->dev->name, i); + + return i; +} + +static void tg3_mdio_fini(struct tg3 *tp) +{ + if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) { + tp->tg3_flags3 &= ~TG3_FLG3_MDIOBUS_INITED; + mdiobus_unregister(&tp->mdio_bus); + tp->tg3_flags3 &= ~TG3_FLG3_MDIOBUS_PAUSED; + } +} + /* tp->lock is held. */ static void tg3_wait_for_event_ack(struct tg3 *tp) { @@ -5386,6 +5496,8 @@ static int tg3_chip_reset(struct tg3 *tp) tg3_nvram_lock(tp); + tg3_mdio_stop(tp); + /* No matching tg3_nvram_unlock() after this because * chip reset below will undo the nvram lock. */ @@ -5537,6 +5649,8 @@ static int tg3_chip_reset(struct tg3 *tp) tw32_f(MAC_MODE, 0); udelay(40); + tg3_mdio_start(tp); + err = tg3_poll_fw(tp); if (err) return err; @@ -7168,10 +7282,6 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32_f(MAC_RX_MODE, tp->rx_mode); udelay(10); - tp->mi_mode &= ~MAC_MI_MODE_AUTO_POLL; - tw32_f(MAC_MI_MODE, tp->mi_mode); - udelay(80); - tw32(MAC_LED_CTRL, tp->led_ctrl); tw32(MAC_MI_STAT, MAC_MI_STAT_LNKSTAT_ATTN_ENAB); @@ -11850,9 +11960,9 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_BX) tp->coalesce_mode |= HOSTCC_MODE_32BYTE; - /* Initialize MAC MI mode, polling disabled. */ - tw32_f(MAC_MI_MODE, tp->mi_mode); - udelay(80); + err = tg3_mdio_init(tp); + if (err) + return err; /* Initialize data/descriptor byte/word swapping. */ val = tr32(GRC_MODE); @@ -13052,6 +13162,10 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev) struct tg3 *tp = netdev_priv(dev); flush_scheduled_work(); + + if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) + tg3_mdio_fini(tp); + unregister_netdev(dev); if (tp->aperegs) { iounmap(tp->aperegs); diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index a3598ed9f5f..e0914fdaf27 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2481,6 +2481,8 @@ struct tg3 { #define TG3_FLG3_5761_5784_AX_FIXES 0x00000004 #define TG3_FLG3_5701_DMA_BUG 0x00000008 #define TG3_FLG3_USE_PHYLIB 0x00000010 +#define TG3_FLG3_MDIOBUS_INITED 0x00000020 +#define TG3_FLG3_MDIOBUS_PAUSED 0x00000040 struct timer_list timer; u16 timer_counter; @@ -2521,6 +2523,9 @@ struct tg3 { int msi_cap; int pcix_cap; + struct mii_bus mdio_bus; + int mdio_irq[PHY_MAX_ADDR]; + /* PHY info */ u32 phy_id; #define PHY_ID_MASK 0xfffffff0 -- cgit v1.2.3-70-g09d2 From b02fd9e3ac118037549baeb86fbe0718561db17f Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Sun, 25 May 2008 23:47:41 -0700 Subject: tg3: Add libphy support. This patch introduces the libphy support. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Signed-off-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 395 +++++++++++++++++++++++++++++++++++++++++++++++------- drivers/net/tg3.h | 2 + 2 files changed, 352 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index ce04c64a8a6..028276edd3b 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -1114,11 +1114,17 @@ static u8 tg3_resolve_flowctrl_1000X(u16 lcladv, u16 rmtadv) static void tg3_setup_flow_control(struct tg3 *tp, u32 lcladv, u32 rmtadv) { + u8 autoneg; u8 flowctrl = 0; u32 old_rx_mode = tp->rx_mode; u32 old_tx_mode = tp->tx_mode; - if (tp->link_config.autoneg == AUTONEG_ENABLE && + if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) + autoneg = tp->mdio_bus.phy_map[PHY_ADDR]->autoneg; + else + autoneg = tp->link_config.autoneg; + + if (autoneg == AUTONEG_ENABLE && (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG)) { if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) flowctrl = tg3_resolve_flowctrl_1000X(lcladv, rmtadv); @@ -1146,6 +1152,152 @@ static void tg3_setup_flow_control(struct tg3 *tp, u32 lcladv, u32 rmtadv) tw32_f(MAC_TX_MODE, tp->tx_mode); } +static void tg3_adjust_link(struct net_device *dev) +{ + u8 oldflowctrl, linkmesg = 0; + u32 mac_mode, lcl_adv, rmt_adv; + struct tg3 *tp = netdev_priv(dev); + struct phy_device *phydev = tp->mdio_bus.phy_map[PHY_ADDR]; + + spin_lock(&tp->lock); + + mac_mode = tp->mac_mode & ~(MAC_MODE_PORT_MODE_MASK | + MAC_MODE_HALF_DUPLEX); + + oldflowctrl = tp->link_config.active_flowctrl; + + if (phydev->link) { + lcl_adv = 0; + rmt_adv = 0; + + if (phydev->speed == SPEED_100 || phydev->speed == SPEED_10) + mac_mode |= MAC_MODE_PORT_MODE_MII; + else + mac_mode |= MAC_MODE_PORT_MODE_GMII; + + if (phydev->duplex == DUPLEX_HALF) + mac_mode |= MAC_MODE_HALF_DUPLEX; + else { + lcl_adv = tg3_advert_flowctrl_1000T( + tp->link_config.flowctrl); + + if (phydev->pause) + rmt_adv = LPA_PAUSE_CAP; + if (phydev->asym_pause) + rmt_adv |= LPA_PAUSE_ASYM; + } + + tg3_setup_flow_control(tp, lcl_adv, rmt_adv); + } else + mac_mode |= MAC_MODE_PORT_MODE_GMII; + + if (mac_mode != tp->mac_mode) { + tp->mac_mode = mac_mode; + tw32_f(MAC_MODE, tp->mac_mode); + udelay(40); + } + + if (phydev->speed == SPEED_1000 && phydev->duplex == DUPLEX_HALF) + tw32(MAC_TX_LENGTHS, + ((2 << TX_LENGTHS_IPG_CRS_SHIFT) | + (6 << TX_LENGTHS_IPG_SHIFT) | + (0xff << TX_LENGTHS_SLOT_TIME_SHIFT))); + else + tw32(MAC_TX_LENGTHS, + ((2 << TX_LENGTHS_IPG_CRS_SHIFT) | + (6 << TX_LENGTHS_IPG_SHIFT) | + (32 << TX_LENGTHS_SLOT_TIME_SHIFT))); + + if ((phydev->link && tp->link_config.active_speed == SPEED_INVALID) || + (!phydev->link && tp->link_config.active_speed != SPEED_INVALID) || + phydev->speed != tp->link_config.active_speed || + phydev->duplex != tp->link_config.active_duplex || + oldflowctrl != tp->link_config.active_flowctrl) + linkmesg = 1; + + tp->link_config.active_speed = phydev->speed; + tp->link_config.active_duplex = phydev->duplex; + + spin_unlock(&tp->lock); + + if (linkmesg) + tg3_link_report(tp); +} + +static int tg3_phy_init(struct tg3 *tp) +{ + struct phy_device *phydev; + + if (tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) + return 0; + + /* Bring the PHY back to a known state. */ + tg3_bmcr_reset(tp); + + phydev = tp->mdio_bus.phy_map[PHY_ADDR]; + + /* Attach the MAC to the PHY. */ + phydev = phy_connect(tp->dev, phydev->dev.bus_id, + tg3_adjust_link, 0, phydev->interface); + if (IS_ERR(phydev)) { + printk(KERN_ERR "%s: Could not attach to PHY\n", tp->dev->name); + return PTR_ERR(phydev); + } + + tp->tg3_flags3 |= TG3_FLG3_PHY_CONNECTED; + + /* Mask with MAC supported features. */ + phydev->supported &= (PHY_GBIT_FEATURES | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause); + + phydev->advertising = phydev->supported; + + printk(KERN_INFO + "%s: attached PHY driver [%s] (mii_bus:phy_addr=%s)\n", + tp->dev->name, phydev->drv->name, phydev->dev.bus_id); + + return 0; +} + +static void tg3_phy_start(struct tg3 *tp) +{ + struct phy_device *phydev; + + if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED)) + return; + + phydev = tp->mdio_bus.phy_map[PHY_ADDR]; + + if (tp->link_config.phy_is_low_power) { + tp->link_config.phy_is_low_power = 0; + phydev->speed = tp->link_config.orig_speed; + phydev->duplex = tp->link_config.orig_duplex; + phydev->autoneg = tp->link_config.orig_autoneg; + phydev->advertising = tp->link_config.orig_advertising; + } + + phy_start(phydev); + + phy_start_aneg(phydev); +} + +static void tg3_phy_stop(struct tg3 *tp) +{ + if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED)) + return; + + phy_stop(tp->mdio_bus.phy_map[PHY_ADDR]); +} + +static void tg3_phy_fini(struct tg3 *tp) +{ + if (tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) { + phy_disconnect(tp->mdio_bus.phy_map[PHY_ADDR]); + tp->tg3_flags3 &= ~TG3_FLG3_PHY_CONNECTED; + } +} + static void tg3_phydsp_write(struct tg3 *tp, u32 reg, u32 val) { tg3_writephy(tp, MII_TG3_DSP_ADDRESS, reg); @@ -1798,7 +1950,40 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT); if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { - tp->link_config.phy_is_low_power = 1; + if ((tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) && + !tp->link_config.phy_is_low_power) { + struct phy_device *phydev; + u32 advertising; + + phydev = tp->mdio_bus.phy_map[PHY_ADDR]; + + tp->link_config.phy_is_low_power = 1; + + tp->link_config.orig_speed = phydev->speed; + tp->link_config.orig_duplex = phydev->duplex; + tp->link_config.orig_autoneg = phydev->autoneg; + tp->link_config.orig_advertising = phydev->advertising; + + advertising = ADVERTISED_TP | + ADVERTISED_Pause | + ADVERTISED_Autoneg | + ADVERTISED_10baseT_Half; + + if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) || + (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)) { + if (tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB) + advertising |= + ADVERTISED_100baseT_Half | + ADVERTISED_100baseT_Full | + ADVERTISED_10baseT_Full; + else + advertising |= ADVERTISED_10baseT_Full; + } + + phydev->advertising = advertising; + + phy_start_aneg(phydev); + } } else { if (tp->link_config.phy_is_low_power == 0) { tp->link_config.phy_is_low_power = 1; @@ -4233,6 +4418,7 @@ static void tg3_poll_controller(struct net_device *dev) static void tg3_reset_task(struct work_struct *work) { struct tg3 *tp = container_of(work, struct tg3, reset_task); + int err; unsigned int restart_timer; tg3_full_lock(tp, 0); @@ -4244,6 +4430,8 @@ static void tg3_reset_task(struct work_struct *work) tg3_full_unlock(tp); + tg3_phy_stop(tp); + tg3_netif_stop(tp); tg3_full_lock(tp, 1); @@ -4259,7 +4447,8 @@ static void tg3_reset_task(struct work_struct *work) } tg3_halt(tp, RESET_KIND_SHUTDOWN, 0); - if (tg3_init_hw(tp, 1)) + err = tg3_init_hw(tp, 1); + if (err) goto out; tg3_netif_start(tp); @@ -4269,6 +4458,9 @@ static void tg3_reset_task(struct work_struct *work) out: tg3_full_unlock(tp); + + if (!err) + tg3_phy_start(tp); } static void tg3_dump_short_state(struct tg3 *tp) @@ -4772,6 +4964,8 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu) return 0; } + tg3_phy_stop(tp); + tg3_netif_stop(tp); tg3_full_lock(tp, 1); @@ -4787,6 +4981,9 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu) tg3_full_unlock(tp); + if (!err) + tg3_phy_start(tp); + return err; } @@ -7864,6 +8061,8 @@ static int tg3_open(struct net_device *dev) } } + tg3_phy_start(tp); + tg3_full_lock(tp, 0); add_timer(&tp->timer); @@ -8665,7 +8864,13 @@ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct tg3 *tp = netdev_priv(dev); + struct tg3 *tp = netdev_priv(dev); + + if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { + if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED)) + return -EAGAIN; + return phy_ethtool_gset(tp->mdio_bus.phy_map[PHY_ADDR], cmd); + } cmd->supported = (SUPPORTED_Autoneg); @@ -8702,6 +8907,12 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct tg3 *tp = netdev_priv(dev); + if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { + if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED)) + return -EAGAIN; + return phy_ethtool_sset(tp->mdio_bus.phy_map[PHY_ADDR], cmd); + } + if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) { /* These are the only valid advertisement bits allowed. */ if (cmd->autoneg == AUTONEG_ENABLE && @@ -8734,7 +8945,7 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) tp->link_config.advertising = 0; tp->link_config.speed = cmd->speed; tp->link_config.duplex = cmd->duplex; - } + } tp->link_config.orig_speed = tp->link_config.speed; tp->link_config.orig_duplex = tp->link_config.duplex; @@ -8828,7 +9039,6 @@ static int tg3_set_tso(struct net_device *dev, u32 value) static int tg3_nway_reset(struct net_device *dev) { struct tg3 *tp = netdev_priv(dev); - u32 bmcr; int r; if (!netif_running(dev)) @@ -8837,17 +9047,25 @@ static int tg3_nway_reset(struct net_device *dev) if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) return -EINVAL; - spin_lock_bh(&tp->lock); - r = -EINVAL; - tg3_readphy(tp, MII_BMCR, &bmcr); - if (!tg3_readphy(tp, MII_BMCR, &bmcr) && - ((bmcr & BMCR_ANENABLE) || - (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT))) { - tg3_writephy(tp, MII_BMCR, bmcr | BMCR_ANRESTART | - BMCR_ANENABLE); - r = 0; + if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { + if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED)) + return -EAGAIN; + r = phy_start_aneg(tp->mdio_bus.phy_map[PHY_ADDR]); + } else { + u32 bmcr; + + spin_lock_bh(&tp->lock); + r = -EINVAL; + tg3_readphy(tp, MII_BMCR, &bmcr); + if (!tg3_readphy(tp, MII_BMCR, &bmcr) && + ((bmcr & BMCR_ANENABLE) || + (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT))) { + tg3_writephy(tp, MII_BMCR, bmcr | BMCR_ANRESTART | + BMCR_ANENABLE); + r = 0; + } + spin_unlock_bh(&tp->lock); } - spin_unlock_bh(&tp->lock); return r; } @@ -8889,6 +9107,7 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e return -EINVAL; if (netif_running(dev)) { + tg3_phy_stop(tp); tg3_netif_stop(tp); irq_sync = 1; } @@ -8912,6 +9131,9 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e tg3_full_unlock(tp); + if (irq_sync && !err) + tg3_phy_start(tp); + return err; } @@ -8935,36 +9157,92 @@ static void tg3_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause) { struct tg3 *tp = netdev_priv(dev); - int irq_sync = 0, err = 0; + int err = 0; - if (netif_running(dev)) { - tg3_netif_stop(tp); - irq_sync = 1; - } + if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { + if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED)) + return -EAGAIN; - tg3_full_lock(tp, irq_sync); + if (epause->autoneg) { + u32 newadv; + struct phy_device *phydev; - if (epause->autoneg) - tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG; - else - tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG; - if (epause->rx_pause) - tp->link_config.flowctrl |= TG3_FLOW_CTRL_RX; - else - tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_RX; - if (epause->tx_pause) - tp->link_config.flowctrl |= TG3_FLOW_CTRL_TX; - else - tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_TX; + phydev = tp->mdio_bus.phy_map[PHY_ADDR]; - if (netif_running(dev)) { - tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); - err = tg3_restart_hw(tp, 1); - if (!err) - tg3_netif_start(tp); - } + if (epause->rx_pause) { + if (epause->tx_pause) + newadv = ADVERTISED_Pause; + else + newadv = ADVERTISED_Pause | + ADVERTISED_Asym_Pause; + } else if (epause->tx_pause) { + newadv = ADVERTISED_Asym_Pause; + } else + newadv = 0; + + if (tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) { + u32 oldadv = phydev->advertising & + (ADVERTISED_Pause | + ADVERTISED_Asym_Pause); + if (oldadv != newadv) { + phydev->advertising &= + ~(ADVERTISED_Pause | + ADVERTISED_Asym_Pause); + phydev->advertising |= newadv; + err = phy_start_aneg(phydev); + } + } else { + tp->link_config.advertising &= + ~(ADVERTISED_Pause | + ADVERTISED_Asym_Pause); + tp->link_config.advertising |= newadv; + } + } else { + if (epause->rx_pause) + tp->link_config.flowctrl |= TG3_FLOW_CTRL_RX; + else + tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_RX; - tg3_full_unlock(tp); + if (epause->tx_pause) + tp->link_config.flowctrl |= TG3_FLOW_CTRL_TX; + else + tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_TX; + + if (netif_running(dev)) + tg3_setup_flow_control(tp, 0, 0); + } + } else { + int irq_sync = 0; + + if (netif_running(dev)) { + tg3_netif_stop(tp); + irq_sync = 1; + } + + tg3_full_lock(tp, irq_sync); + + if (epause->autoneg) + tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG; + else + tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG; + if (epause->rx_pause) + tp->link_config.flowctrl |= TG3_FLOW_CTRL_RX; + else + tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_RX; + if (epause->tx_pause) + tp->link_config.flowctrl |= TG3_FLOW_CTRL_TX; + else + tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_TX; + + if (netif_running(dev)) { + tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); + err = tg3_restart_hw(tp, 1); + if (!err) + tg3_netif_start(tp); + } + + tg3_full_unlock(tp); + } return err; } @@ -9799,9 +10077,10 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, data[1] = 1; } if (etest->flags & ETH_TEST_FL_OFFLINE) { - int err, irq_sync = 0; + int err, err2 = 0, irq_sync = 0; if (netif_running(dev)) { + tg3_phy_stop(tp); tg3_netif_stop(tp); irq_sync = 1; } @@ -9842,11 +10121,15 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); if (netif_running(dev)) { tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE; - if (!tg3_restart_hw(tp, 1)) + err2 = tg3_restart_hw(tp, 1); + if (!err2) tg3_netif_start(tp); } tg3_full_unlock(tp); + + if (irq_sync && !err2) + tg3_phy_start(tp); } if (tp->link_config.phy_is_low_power) tg3_set_power_state(tp, PCI_D3hot); @@ -9859,6 +10142,12 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) struct tg3 *tp = netdev_priv(dev); int err; + if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { + if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED)) + return -EAGAIN; + return phy_mii_ioctl(tp->mdio_bus.phy_map[PHY_ADDR], data, cmd); + } + switch(cmd) { case SIOCGMIIPHY: data->phy_id = PHY_ADDR; @@ -11110,6 +11399,9 @@ static int __devinit tg3_phy_probe(struct tg3 *tp) u32 hw_phy_id, hw_phy_id_masked; int err; + if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) + return tg3_phy_init(tp); + /* Reading the PHY ID register can conflict with ASF * firwmare access to the PHY hardware. */ @@ -12043,6 +12335,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) printk(KERN_ERR PFX "(%s) phy probe failed, err %d\n", pci_name(tp->pdev), err); /* ... but do not return immediately ... */ + tg3_mdio_fini(tp); } tg3_read_partno(tp); @@ -13163,8 +13456,10 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev) flush_scheduled_work(); - if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) + if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { + tg3_phy_fini(tp); tg3_mdio_fini(tp); + } unregister_netdev(dev); if (tp->aperegs) { @@ -13198,6 +13493,7 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state) return 0; flush_scheduled_work(); + tg3_phy_stop(tp); tg3_netif_stop(tp); del_timer_sync(&tp->timer); @@ -13215,10 +13511,13 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state) err = tg3_set_power_state(tp, pci_choose_state(pdev, state)); if (err) { + int err2; + tg3_full_lock(tp, 0); tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE; - if (tg3_restart_hw(tp, 1)) + err2 = tg3_restart_hw(tp, 1); + if (err2) goto out; tp->timer.expires = jiffies + tp->timer_offset; @@ -13229,6 +13528,9 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state) out: tg3_full_unlock(tp); + + if (!err2) + tg3_phy_start(tp); } return err; @@ -13266,6 +13568,9 @@ static int tg3_resume(struct pci_dev *pdev) out: tg3_full_unlock(tp); + if (!err) + tg3_phy_start(tp); + return err; } diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index e0914fdaf27..48f45c17f60 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2205,6 +2205,7 @@ struct tg3_link_config { u16 orig_speed; u8 orig_duplex; u8 orig_autoneg; + u32 orig_advertising; }; struct tg3_bufmgr_config { @@ -2483,6 +2484,7 @@ struct tg3 { #define TG3_FLG3_USE_PHYLIB 0x00000010 #define TG3_FLG3_MDIOBUS_INITED 0x00000020 #define TG3_FLG3_MDIOBUS_PAUSED 0x00000040 +#define TG3_FLG3_PHY_CONNECTED 0x00000080 struct timer_list timer; u16 timer_counter; -- cgit v1.2.3-70-g09d2 From 57e6983cbde91b4569b4014b933f3a16e12b99fd Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Sun, 25 May 2008 23:48:31 -0700 Subject: tg3: Add 5785 ASIC revision This patch added the 5785 device ID and ASIC revision to the code. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Signed-off-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 58 ++++++++++++++++++++++++++++++++++++------------- drivers/net/tg3.h | 1 + include/linux/pci_ids.h | 1 + 3 files changed, 45 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 028276edd3b..69ded90cd96 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -204,6 +204,7 @@ static struct pci_device_id tg3_pci_tbl[] = { {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5723)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761E)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5785)}, {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX)}, {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX)}, {PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000)}, @@ -5710,7 +5711,8 @@ static int tg3_chip_reset(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) tw32(GRC_FASTBOOT_PC, 0); /* @@ -7004,7 +7006,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) return err; if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761) { + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785) { /* This value is determined during the probe time DMA * engine test, tg3_test_dma. */ @@ -7243,7 +7246,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) RDMAC_MODE_FIFOURUN_ENAB | RDMAC_MODE_FIFOOREAD_ENAB | RDMAC_MODE_LNGREAD_ENAB); - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) rdmac_mode |= RDMAC_MODE_BD_SBD_CRPT_ENAB | RDMAC_MODE_MBUF_RBD_CRPT_ENAB | RDMAC_MODE_MBUF_SBD_CRPT_ENAB; @@ -7411,7 +7415,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) || (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) || (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) || - (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)) + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) || + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)) val |= WDMAC_MODE_STATUS_TAG_FIX; tw32_f(WDMAC_MODE, val); @@ -7473,7 +7478,9 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tp->rx_mode = RX_MODE_ENABLE; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) tp->rx_mode |= RX_MODE_IPV6_CSUM_ENABLE; tw32_f(MAC_RX_MODE, tp->rx_mode); @@ -9028,7 +9035,10 @@ static int tg3_set_tso(struct net_device *dev, u32 value) (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)) { if (value) { dev->features |= NETIF_F_TSO6; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 && + GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) dev->features |= NETIF_F_TSO_ECN; } else dev->features &= ~(NETIF_F_TSO6 | NETIF_F_TSO_ECN); @@ -9286,7 +9296,8 @@ static int tg3_set_tx_csum(struct net_device *dev, u32 data) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) ethtool_op_set_tx_ipv6_csum(dev, data); else ethtool_op_set_tx_csum(dev, data); @@ -9807,7 +9818,8 @@ static int tg3_test_memory(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) mem_tbl = mem_tbl_5755; else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) mem_tbl = mem_tbl_5906; @@ -10014,7 +10026,8 @@ static int tg3_test_loopback(struct tg3 *tp) return TG3_LOOPBACK_FAILED; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) { + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) { int i; u32 status; @@ -10042,7 +10055,8 @@ static int tg3_test_loopback(struct tg3 *tp) err |= TG3_MAC_LOOPBACK_FAILED; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) { + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) { tw32(TG3_CPMU_CTRL, cpmuctrl); /* Release the mutex */ @@ -10690,7 +10704,8 @@ static void __devinit tg3_nvram_init(struct tg3 *tp) else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) tg3_get_5755_nvram_info(tp); else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) tg3_get_5787_nvram_info(tp); else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) tg3_get_5761_nvram_info(tp); @@ -11021,6 +11036,7 @@ static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len, (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787) && (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784) && (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761) && + (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785) && (tp->nvram_jedecnum == JEDEC_ST) && (nvram_cmd & NVRAM_CMD_FIRST)) { @@ -11924,6 +11940,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 || (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) tp->tg3_flags2 |= TG3_FLG2_5750_PLUS; @@ -11945,6 +11962,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { tp->tg3_flags2 |= TG3_FLG2_HW_TSO_2; tp->tg3_flags2 |= TG3_FLG2_1SHOT_MSI; @@ -12147,7 +12165,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) } if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) { + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) { tp->tg3_flags |= TG3_FLAG_CPMU_PRESENT; if (tp->pci_chip_rev_id == CHIPREV_ID_5784_A0 || @@ -12231,7 +12250,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->tg3_flags2 |= TG3_FLG2_PHY_JITTER_BUG; if (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5755M) tp->tg3_flags2 |= TG3_FLG2_PHY_ADJUST_TRIM; - } else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906) + } else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785) tp->tg3_flags2 |= TG3_FLG2_PHY_BER_BUG; } @@ -12252,6 +12272,9 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_BX) tp->coalesce_mode |= HOSTCC_MODE_32BYTE; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) + tp->tg3_flags3 |= TG3_FLG3_USE_PHYLIB; + err = tg3_mdio_init(tp); if (err) return err; @@ -12383,6 +12406,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) tp->dev->hard_start_xmit = tg3_start_xmit; else @@ -13307,7 +13331,10 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) && (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)) dev->features |= NETIF_F_TSO6; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 && + GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) dev->features |= NETIF_F_TSO_ECN; } @@ -13373,7 +13400,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) dev->features |= NETIF_F_IPV6_CSUM; tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 48f45c17f60..95ac4c9590a 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -128,6 +128,7 @@ #define ASIC_REV_USE_PROD_ID_REG 0x0f #define ASIC_REV_5784 0x5784 #define ASIC_REV_5761 0x5761 +#define ASIC_REV_5785 0x5785 #define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8) #define CHIPREV_5700_AX 0x70 #define CHIPREV_5700_BX 0x71 diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index cf6dbd75939..72c038560e7 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1979,6 +1979,7 @@ #define PCI_DEVICE_ID_TIGON3_5787M 0x1693 #define PCI_DEVICE_ID_TIGON3_5782 0x1696 #define PCI_DEVICE_ID_TIGON3_5784 0x1698 +#define PCI_DEVICE_ID_TIGON3_5785 0x1699 #define PCI_DEVICE_ID_TIGON3_5786 0x169a #define PCI_DEVICE_ID_TIGON3_5787 0x169b #define PCI_DEVICE_ID_TIGON3_5788 0x169c -- cgit v1.2.3-70-g09d2 From a9daf36746b1fb5c2db8d164ca70c30c63a0d7b2 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Sun, 25 May 2008 23:49:44 -0700 Subject: tg3: Add shmem options. This patch adds some options obtained through shared memory. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Signed-off-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 95 +++++++++++++++++++++++++++++++++++++++++++++---- drivers/net/tg3.h | 30 +++++++++++++++- include/linux/brcmphy.h | 6 ++++ 3 files changed, 123 insertions(+), 8 deletions(-) create mode 100644 include/linux/brcmphy.h (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 69ded90cd96..365fcffc314 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -869,6 +870,51 @@ static int tg3_mdio_reset(struct mii_bus *bp) return 0; } +static void tg3_mdio_config(struct tg3 *tp) +{ + u32 val; + + if (tp->mdio_bus.phy_map[PHY_ADDR]->interface != + PHY_INTERFACE_MODE_RGMII) + return; + + val = tr32(MAC_PHYCFG1) & ~(MAC_PHYCFG1_RGMII_EXT_RX_DEC | + MAC_PHYCFG1_RGMII_SND_STAT_EN); + if (tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE) { + if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_RX_EN) + val |= MAC_PHYCFG1_RGMII_EXT_RX_DEC; + if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_TX_EN) + val |= MAC_PHYCFG1_RGMII_SND_STAT_EN; + } + tw32(MAC_PHYCFG1, val | MAC_PHYCFG1_RGMII_INT | MAC_PHYCFG1_TXC_DRV); + + val = tr32(MAC_PHYCFG2) & ~(MAC_PHYCFG2_INBAND_ENABLE); + if (!(tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE)) + val |= MAC_PHYCFG2_INBAND_ENABLE; + tw32(MAC_PHYCFG2, val); + + val = tr32(MAC_EXT_RGMII_MODE); + val &= ~(MAC_RGMII_MODE_RX_INT_B | + MAC_RGMII_MODE_RX_QUALITY | + MAC_RGMII_MODE_RX_ACTIVITY | + MAC_RGMII_MODE_RX_ENG_DET | + MAC_RGMII_MODE_TX_ENABLE | + MAC_RGMII_MODE_TX_LOWPWR | + MAC_RGMII_MODE_TX_RESET); + if (tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE) { + if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_RX_EN) + val |= MAC_RGMII_MODE_RX_INT_B | + MAC_RGMII_MODE_RX_QUALITY | + MAC_RGMII_MODE_RX_ACTIVITY | + MAC_RGMII_MODE_RX_ENG_DET; + if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_TX_EN) + val |= MAC_RGMII_MODE_TX_ENABLE | + MAC_RGMII_MODE_TX_LOWPWR | + MAC_RGMII_MODE_TX_RESET; + } + tw32(MAC_EXT_RGMII_MODE, val); +} + static void tg3_mdio_start(struct tg3 *tp) { if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) { @@ -880,6 +926,9 @@ static void tg3_mdio_start(struct tg3 *tp) tp->mi_mode &= ~MAC_MI_MODE_AUTO_POLL; tw32_f(MAC_MI_MODE, tp->mi_mode); udelay(80); + + if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) + tg3_mdio_config(tp); } static void tg3_mdio_stop(struct tg3 *tp) @@ -895,6 +944,7 @@ static int tg3_mdio_init(struct tg3 *tp) { int i; u32 reg; + struct phy_device *phydev; struct mii_bus *mdio_bus = &tp->mdio_bus; tg3_mdio_start(tp); @@ -928,13 +978,34 @@ static int tg3_mdio_init(struct tg3 *tp) tg3_bmcr_reset(tp); i = mdiobus_register(mdio_bus); - if (!i) - tp->tg3_flags3 |= TG3_FLG3_MDIOBUS_INITED; - else + if (i) { printk(KERN_WARNING "%s: mdiobus_reg failed (0x%x)\n", tp->dev->name, i); + return i; + } - return i; + tp->tg3_flags3 |= TG3_FLG3_MDIOBUS_INITED; + + phydev = tp->mdio_bus.phy_map[PHY_ADDR]; + + switch (phydev->phy_id) { + case TG3_PHY_ID_BCM50610: + phydev->interface = PHY_INTERFACE_MODE_RGMII; + if (tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE) + phydev->dev_flags |= PHY_BRCM_STD_IBND_DISABLE; + if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_RX_EN) + phydev->dev_flags |= PHY_BRCM_EXT_IBND_RX_ENABLE; + if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_TX_EN) + phydev->dev_flags |= PHY_BRCM_EXT_IBND_TX_ENABLE; + break; + case TG3_PHY_ID_BCMAC131: + phydev->interface = PHY_INTERFACE_MODE_MII; + break; + } + + tg3_mdio_config(tp); + + return 0; } static void tg3_mdio_fini(struct tg3 *tp) @@ -1238,8 +1309,8 @@ static int tg3_phy_init(struct tg3 *tp) phydev = tp->mdio_bus.phy_map[PHY_ADDR]; /* Attach the MAC to the PHY. */ - phydev = phy_connect(tp->dev, phydev->dev.bus_id, - tg3_adjust_link, 0, phydev->interface); + phydev = phy_connect(tp->dev, phydev->dev.bus_id, tg3_adjust_link, + phydev->dev_flags, phydev->interface); if (IS_ERR(phydev)) { printk(KERN_ERR "%s: Could not attach to PHY\n", tp->dev->name); return PTR_ERR(phydev); @@ -11219,7 +11290,7 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) tg3_read_mem(tp, NIC_SRAM_DATA_SIG, &val); if (val == NIC_SRAM_DATA_SIG_MAGIC) { u32 nic_cfg, led_cfg; - u32 nic_phy_id, ver, cfg2 = 0, eeprom_phy_id; + u32 nic_phy_id, ver, cfg2 = 0, cfg4 = 0, eeprom_phy_id; int eeprom_phy_serdes = 0; tg3_read_mem(tp, NIC_SRAM_DATA_CFG, &nic_cfg); @@ -11233,6 +11304,9 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) (ver > 0) && (ver < 0x100)) tg3_read_mem(tp, NIC_SRAM_DATA_CFG_2, &cfg2); + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) + tg3_read_mem(tp, NIC_SRAM_DATA_CFG_4, &cfg4); + if ((nic_cfg & NIC_SRAM_DATA_CFG_PHY_TYPE_MASK) == NIC_SRAM_DATA_CFG_PHY_TYPE_FIBER) eeprom_phy_serdes = 1; @@ -11357,6 +11431,13 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) if (cfg3 & NIC_SRAM_ASPM_DEBOUNCE) tp->tg3_flags |= TG3_FLAG_ASPM_WORKAROUND; } + + if (cfg4 & NIC_SRAM_RGMII_STD_IBND_DISABLE) + tp->tg3_flags3 |= TG3_FLG3_RGMII_STD_IBND_DISABLE; + if (cfg4 & NIC_SRAM_RGMII_EXT_IBND_RX_EN) + tp->tg3_flags3 |= TG3_FLG3_RGMII_EXT_IBND_RX_EN; + if (cfg4 & NIC_SRAM_RGMII_EXT_IBND_TX_EN) + tp->tg3_flags3 |= TG3_FLG3_RGMII_EXT_IBND_TX_EN; } } diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 95ac4c9590a..df07842172b 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -529,7 +529,23 @@ #define MAC_SERDES_CFG 0x00000590 #define MAC_SERDES_CFG_EDGE_SELECT 0x00001000 #define MAC_SERDES_STAT 0x00000594 -/* 0x598 --> 0x5b0 unused */ +/* 0x598 --> 0x5a0 unused */ +#define MAC_PHYCFG1 0x000005a0 +#define MAC_PHYCFG1_RGMII_INT 0x00000001 +#define MAC_PHYCFG1_RGMII_EXT_RX_DEC 0x02000000 +#define MAC_PHYCFG1_RGMII_SND_STAT_EN 0x04000000 +#define MAC_PHYCFG1_TXC_DRV 0x20000000 +#define MAC_PHYCFG2 0x000005a4 +#define MAC_PHYCFG2_INBAND_ENABLE 0x00000001 +#define MAC_EXT_RGMII_MODE 0x000005a8 +#define MAC_RGMII_MODE_TX_ENABLE 0x00000001 +#define MAC_RGMII_MODE_TX_LOWPWR 0x00000002 +#define MAC_RGMII_MODE_TX_RESET 0x00000004 +#define MAC_RGMII_MODE_RX_INT_B 0x00000100 +#define MAC_RGMII_MODE_RX_QUALITY 0x00000200 +#define MAC_RGMII_MODE_RX_ACTIVITY 0x00000400 +#define MAC_RGMII_MODE_RX_ENG_DET 0x00000800 +/* 0x5ac --> 0x5b0 unused */ #define SERDES_RX_CTRL 0x000005b0 /* 5780/5714 only */ #define SERDES_RX_SIG_DETECT 0x00000400 #define SG_DIG_CTRL 0x000005b0 @@ -1715,6 +1731,12 @@ #define NIC_SRAM_DATA_CFG_3 0x00000d3c #define NIC_SRAM_ASPM_DEBOUNCE 0x00000002 +#define NIC_SRAM_DATA_CFG_4 0x00000d60 +#define NIC_SRAM_GMII_MODE 0x00000002 +#define NIC_SRAM_RGMII_STD_IBND_DISABLE 0x00000004 +#define NIC_SRAM_RGMII_EXT_IBND_RX_EN 0x00000008 +#define NIC_SRAM_RGMII_EXT_IBND_TX_EN 0x00000010 + #define NIC_SRAM_RX_MINI_BUFFER_DESC 0x00001000 #define NIC_SRAM_DMA_DESC_POOL_BASE 0x00002000 @@ -2486,6 +2508,9 @@ struct tg3 { #define TG3_FLG3_MDIOBUS_INITED 0x00000020 #define TG3_FLG3_MDIOBUS_PAUSED 0x00000040 #define TG3_FLG3_PHY_CONNECTED 0x00000080 +#define TG3_FLG3_RGMII_STD_IBND_DISABLE 0x00000100 +#define TG3_FLG3_RGMII_EXT_IBND_RX_EN 0x00000200 +#define TG3_FLG3_RGMII_EXT_IBND_TX_EN 0x00000400 struct timer_list timer; u16 timer_counter; @@ -2556,6 +2581,9 @@ struct tg3 { #define PHY_REV_BCM5401_B2 0x3 #define PHY_REV_BCM5401_C0 0x6 #define PHY_REV_BCM5411_X0 0x1 /* Found on Netgear GA302T */ +#define TG3_PHY_ID_BCM50610 0x143bd60 +#define TG3_PHY_ID_BCMAC131 0x143bc70 + u32 led_ctrl; u32 phy_otp; diff --git a/include/linux/brcmphy.h b/include/linux/brcmphy.h new file mode 100644 index 00000000000..9b64b6d6787 --- /dev/null +++ b/include/linux/brcmphy.h @@ -0,0 +1,6 @@ +#define PHY_BRCM_WIRESPEED_ENABLE 0x00000001 +#define PHY_BRCM_AUTO_PWRDWN_ENABLE 0x00000002 +#define PHY_BRCM_APD_CLK125_ENABLE 0x00000004 +#define PHY_BRCM_STD_IBND_DISABLE 0x00000008 +#define PHY_BRCM_EXT_IBND_RX_ENABLE 0x00000010 +#define PHY_BRCM_EXT_IBND_TX_ENABLE 0x00000020 -- cgit v1.2.3-70-g09d2 From bb9122b829e960f4e242c04c2b38c12efb37757b Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Sun, 25 May 2008 23:51:01 -0700 Subject: tg3: Update version to 3.93 This patch increments the version to 3.93. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Signed-off-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 365fcffc314..20a8e399640 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -66,8 +66,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.92" -#define DRV_MODULE_RELDATE "May 2, 2008" +#define DRV_MODULE_VERSION "3.93" +#define DRV_MODULE_RELDATE "May 22, 2008" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 -- cgit v1.2.3-70-g09d2 From c3a34f4390396a4bede3f8b7bcc5153f50b974bb Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Wed, 28 May 2008 01:10:52 -0400 Subject: Input: i8042 - add Intel D845PESV to nopnp list This patch introduces i8042_dmi_nopnp_table to make it possible to perform DMI matches for systems that need 'i8042.nopnp' to work correctly, and introduces such an entry for Intel D845PESV -- this system doesn't detect PS2 mouse reliably without this option, as reported by Robert Lewis. [dtor@mail.ru - make it compile if CONFIG_PNP is off - reported by Randy Dunlap] Signed-off-by: Jiri Kosina Signed-off-by: Dmitry Torokhov --- drivers/input/serio/i8042-x86ia64io.h | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 5ece9f56bab..2289e3a8f25 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -63,7 +63,7 @@ static inline void i8042_write_command(int val) outb(val, I8042_COMMAND_REG); } -#if defined(__i386__) || defined(__x86_64__) +#ifdef CONFIG_X86 #include @@ -287,14 +287,19 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { { } }; - - +#ifdef CONFIG_PNP +static struct dmi_system_id __initdata i8042_dmi_nopnp_table[] = { + { + .ident = "Intel MBO Desktop D845PESV", + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "D845PESV"), + DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"), + }, + }, + { } +}; #endif -#ifdef CONFIG_X86 - -#include - /* * Some Wistron based laptops need us to explicitly enable the 'Dritek * keyboard extension' to make their extra keys start generating scancodes. @@ -342,7 +347,6 @@ static struct dmi_system_id __initdata i8042_dmi_dritek_table[] = { #endif /* CONFIG_X86 */ - #ifdef CONFIG_PNP #include @@ -452,6 +456,11 @@ static int __init i8042_pnp_init(void) int pnp_data_busted = 0; int err; +#ifdef CONFIG_X86 + if (dmi_check_system(i8042_dmi_nopnp_table)) + i8042_nopnp = 1; +#endif + if (i8042_nopnp) { printk(KERN_INFO "i8042: PNP detection disabled\n"); return 0; @@ -577,15 +586,13 @@ static int __init i8042_platform_init(void) i8042_reset = 1; #endif -#if defined(__i386__) || defined(__x86_64__) +#ifdef CONFIG_X86 if (dmi_check_system(i8042_dmi_noloop_table)) i8042_noloop = 1; if (dmi_check_system(i8042_dmi_nomux_table)) i8042_nomux = 1; -#endif -#ifdef CONFIG_X86 if (dmi_check_system(i8042_dmi_dritek_table)) i8042_dritek = 1; #endif /* CONFIG_X86 */ -- cgit v1.2.3-70-g09d2 From 779297320d192655c2f95a870c12e9b307612429 Mon Sep 17 00:00:00 2001 From: Brice Goglin Date: Fri, 9 May 2008 02:21:10 +0200 Subject: myri10ge: add routines for multislices Add several routines that multislices support will use. Signed-off-by: Brice Goglin Signed-off-by: Andrew Gallatin Signed-off-by: Jeff Garzik --- drivers/net/myri10ge/myri10ge.c | 256 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 256 insertions(+) (limited to 'drivers') diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 36be6efc639..f3ef9e3c48c 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -1928,6 +1928,76 @@ myri10ge_get_frag_header(struct skb_frag_struct *frag, void **mac_hdr, return 0; } +#if 0 +static int myri10ge_get_txrx(struct myri10ge_priv *mgp, int slice) +{ + struct myri10ge_cmd cmd; + struct myri10ge_slice_state *ss; + int status; + + ss = &mgp->ss[slice]; + cmd.data0 = 0; /* single slice for now */ + status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SEND_OFFSET, &cmd, 0); + ss->tx.lanai = (struct mcp_kreq_ether_send __iomem *) + (mgp->sram + cmd.data0); + + cmd.data0 = slice; + status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SMALL_RX_OFFSET, + &cmd, 0); + ss->rx_small.lanai = (struct mcp_kreq_ether_recv __iomem *) + (mgp->sram + cmd.data0); + + cmd.data0 = slice; + status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_BIG_RX_OFFSET, &cmd, 0); + ss->rx_big.lanai = (struct mcp_kreq_ether_recv __iomem *) + (mgp->sram + cmd.data0); + + if (myri10ge_wcfifo && mgp->wc_enabled) { + ss->tx.wc_fifo = (u8 __iomem *) + mgp->sram + MXGEFW_ETH_SEND_4 + 64 * slice; + ss->rx_small.wc_fifo = (u8 __iomem *) + mgp->sram + MXGEFW_ETH_RECV_SMALL + 64 * slice; + ss->rx_big.wc_fifo = (u8 __iomem *) + mgp->sram + MXGEFW_ETH_RECV_BIG + 64 * slice; + } else { + ss->tx.wc_fifo = NULL; + ss->rx_small.wc_fifo = NULL; + ss->rx_big.wc_fifo = NULL; + } + return status; + +} + +static int myri10ge_set_stats(struct myri10ge_priv *mgp, int slice) +{ + struct myri10ge_cmd cmd; + struct myri10ge_slice_state *ss; + int status; + + ss = &mgp->ss[slice]; + cmd.data0 = MYRI10GE_LOWPART_TO_U32(ss->fw_stats_bus); + cmd.data1 = MYRI10GE_HIGHPART_TO_U32(ss->fw_stats_bus); + cmd.data2 = sizeof(struct mcp_irq_data); + status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_STATS_DMA_V2, &cmd, 0); + if (status == -ENOSYS) { + dma_addr_t bus = ss->fw_stats_bus; + if (slice != 0) + return -EINVAL; + bus += offsetof(struct mcp_irq_data, send_done_count); + cmd.data0 = MYRI10GE_LOWPART_TO_U32(bus); + cmd.data1 = MYRI10GE_HIGHPART_TO_U32(bus); + status = myri10ge_send_cmd(mgp, + MXGEFW_CMD_SET_STATS_DMA_OBSOLETE, + &cmd, 0); + /* Firmware cannot support multicast without STATS_DMA_V2 */ + mgp->fw_multicast_support = 0; + } else { + mgp->fw_multicast_support = 1; + } + return 0; +} +#endif + static int myri10ge_open(struct net_device *dev) { struct myri10ge_priv *mgp = netdev_priv(dev); @@ -3106,6 +3176,192 @@ static void myri10ge_watchdog_timer(unsigned long arg) mgp->watchdog_pause = rx_pause_cnt; } +#if 0 +static void myri10ge_free_slices(struct myri10ge_priv *mgp) +{ + struct myri10ge_slice_state *ss; + struct pci_dev *pdev = mgp->pdev; + size_t bytes; + int i; + + if (mgp->ss == NULL) + return; + + for (i = 0; i < mgp->num_slices; i++) { + ss = &mgp->ss[i]; + if (ss->rx_done.entry != NULL) { + bytes = mgp->max_intr_slots * + sizeof(*ss->rx_done.entry); + dma_free_coherent(&pdev->dev, bytes, + ss->rx_done.entry, ss->rx_done.bus); + ss->rx_done.entry = NULL; + } + if (ss->fw_stats != NULL) { + bytes = sizeof(*ss->fw_stats); + dma_free_coherent(&pdev->dev, bytes, + ss->fw_stats, ss->fw_stats_bus); + ss->fw_stats = NULL; + } + } + kfree(mgp->ss); + mgp->ss = NULL; +} + +static int myri10ge_alloc_slices(struct myri10ge_priv *mgp) +{ + struct myri10ge_slice_state *ss; + struct pci_dev *pdev = mgp->pdev; + size_t bytes; + int i; + + bytes = sizeof(*mgp->ss) * mgp->num_slices; + mgp->ss = kzalloc(bytes, GFP_KERNEL); + if (mgp->ss == NULL) { + return -ENOMEM; + } + + for (i = 0; i < mgp->num_slices; i++) { + ss = &mgp->ss[i]; + bytes = mgp->max_intr_slots * sizeof(*ss->rx_done.entry); + ss->rx_done.entry = dma_alloc_coherent(&pdev->dev, bytes, + &ss->rx_done.bus, + GFP_KERNEL); + if (ss->rx_done.entry == NULL) + goto abort; + memset(ss->rx_done.entry, 0, bytes); + bytes = sizeof(*ss->fw_stats); + ss->fw_stats = dma_alloc_coherent(&pdev->dev, bytes, + &ss->fw_stats_bus, + GFP_KERNEL); + if (ss->fw_stats == NULL) + goto abort; + ss->mgp = mgp; + ss->dev = mgp->dev; + netif_napi_add(ss->dev, &ss->napi, myri10ge_poll, + myri10ge_napi_weight); + } + return 0; +abort: + myri10ge_free_slices(mgp); + return -ENOMEM; +} + +/* + * This function determines the number of slices supported. + * The number slices is the minumum of the number of CPUS, + * the number of MSI-X irqs supported, the number of slices + * supported by the firmware + */ +static void myri10ge_probe_slices(struct myri10ge_priv *mgp) +{ + struct myri10ge_cmd cmd; + struct pci_dev *pdev = mgp->pdev; + char *old_fw; + int i, status, ncpus, msix_cap; + + mgp->num_slices = 1; + msix_cap = pci_find_capability(pdev, PCI_CAP_ID_MSIX); + ncpus = num_online_cpus(); + + if (myri10ge_max_slices == 1 || msix_cap == 0 || + (myri10ge_max_slices == -1 && ncpus < 2)) + return; + + /* try to load the slice aware rss firmware */ + old_fw = mgp->fw_name; + if (old_fw == myri10ge_fw_aligned) + mgp->fw_name = myri10ge_fw_rss_aligned; + else + mgp->fw_name = myri10ge_fw_rss_unaligned; + status = myri10ge_load_firmware(mgp, 0); + if (status != 0) { + dev_info(&pdev->dev, "Rss firmware not found\n"); + return; + } + + /* hit the board with a reset to ensure it is alive */ + memset(&cmd, 0, sizeof(cmd)); + status = myri10ge_send_cmd(mgp, MXGEFW_CMD_RESET, &cmd, 0); + if (status != 0) { + dev_err(&mgp->pdev->dev, "failed reset\n"); + goto abort_with_fw; + return; + } + + mgp->max_intr_slots = cmd.data0 / sizeof(struct mcp_slot); + + /* tell it the size of the interrupt queues */ + cmd.data0 = mgp->max_intr_slots * sizeof(struct mcp_slot); + status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_INTRQ_SIZE, &cmd, 0); + if (status != 0) { + dev_err(&mgp->pdev->dev, "failed MXGEFW_CMD_SET_INTRQ_SIZE\n"); + goto abort_with_fw; + } + + /* ask the maximum number of slices it supports */ + status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_MAX_RSS_QUEUES, &cmd, 0); + if (status != 0) + goto abort_with_fw; + else + mgp->num_slices = cmd.data0; + + /* Only allow multiple slices if MSI-X is usable */ + if (!myri10ge_msi) { + goto abort_with_fw; + } + + /* if the admin did not specify a limit to how many + * slices we should use, cap it automatically to the + * number of CPUs currently online */ + if (myri10ge_max_slices == -1) + myri10ge_max_slices = ncpus; + + if (mgp->num_slices > myri10ge_max_slices) + mgp->num_slices = myri10ge_max_slices; + + /* Now try to allocate as many MSI-X vectors as we have + * slices. We give up on MSI-X if we can only get a single + * vector. */ + + mgp->msix_vectors = kzalloc(mgp->num_slices * + sizeof(*mgp->msix_vectors), GFP_KERNEL); + if (mgp->msix_vectors == NULL) + goto disable_msix; + for (i = 0; i < mgp->num_slices; i++) { + mgp->msix_vectors[i].entry = i; + } + + while (mgp->num_slices > 1) { + /* make sure it is a power of two */ + while (!is_power_of_2(mgp->num_slices)) + mgp->num_slices--; + if (mgp->num_slices == 1) + goto disable_msix; + status = pci_enable_msix(pdev, mgp->msix_vectors, + mgp->num_slices); + if (status == 0) { + pci_disable_msix(pdev); + return; + } + if (status > 0) + mgp->num_slices = status; + else + goto disable_msix; + } + +disable_msix: + if (mgp->msix_vectors != NULL) { + kfree(mgp->msix_vectors); + mgp->msix_vectors = NULL; + } + +abort_with_fw: + mgp->num_slices = 1; + mgp->fw_name = old_fw; + myri10ge_load_firmware(mgp, 0); +} +#endif + static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct net_device *netdev; -- cgit v1.2.3-70-g09d2 From 0dcffac1a329be69bab0ac604bf7283737108e68 Mon Sep 17 00:00:00 2001 From: Brice Goglin Date: Fri, 9 May 2008 02:21:49 +0200 Subject: myri10ge: add multislices support Add multi-slice/MSI-X support. By default, a single slice (and the normal firmware) are used. To enable msi-x, multi-slice mode, one must load the driver with myri10ge_max_slices set to either -1, or something larger than 1. Signed-off-by: Brice Goglin Signed-off-by: Andrew Gallatin Signed-off-by: Jeff Garzik --- drivers/net/myri10ge/myri10ge.c | 684 ++++++++++++++++++++++++++-------------- 1 file changed, 442 insertions(+), 242 deletions(-) (limited to 'drivers') diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index f3ef9e3c48c..eddcee326f0 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -185,11 +185,13 @@ struct myri10ge_slice_state { dma_addr_t fw_stats_bus; int watchdog_tx_done; int watchdog_tx_req; + char irq_desc[32]; }; struct myri10ge_priv { - struct myri10ge_slice_state ss; + struct myri10ge_slice_state *ss; int tx_boundary; /* boundary transmits cannot cross */ + int num_slices; int running; /* running? */ int csum_flag; /* rx_csums? */ int small_bytes; @@ -208,6 +210,8 @@ struct myri10ge_priv { dma_addr_t cmd_bus; struct pci_dev *pdev; int msi_enabled; + int msix_enabled; + struct msix_entry *msix_vectors; u32 link_state; unsigned int rdma_tags_available; int intr_coal_delay; @@ -244,6 +248,8 @@ struct myri10ge_priv { static char *myri10ge_fw_unaligned = "myri10ge_ethp_z8e.dat"; static char *myri10ge_fw_aligned = "myri10ge_eth_z8e.dat"; +static char *myri10ge_fw_rss_unaligned = "myri10ge_rss_ethp_z8e.dat"; +static char *myri10ge_fw_rss_aligned = "myri10ge_rss_eth_z8e.dat"; static char *myri10ge_fw_name = NULL; module_param(myri10ge_fw_name, charp, S_IRUGO | S_IWUSR); @@ -321,6 +327,14 @@ static int myri10ge_wcfifo = 0; module_param(myri10ge_wcfifo, int, S_IRUGO); MODULE_PARM_DESC(myri10ge_wcfifo, "Enable WC Fifo when WC is enabled"); +static int myri10ge_max_slices = 1; +module_param(myri10ge_max_slices, int, S_IRUGO); +MODULE_PARM_DESC(myri10ge_max_slices, "Max tx/rx queues"); + +static int myri10ge_rss_hash = MXGEFW_RSS_HASH_TYPE_SRC_PORT; +module_param(myri10ge_rss_hash, int, S_IRUGO); +MODULE_PARM_DESC(myri10ge_rss_hash, "Type of RSS hashing to do"); + #define MYRI10GE_FW_OFFSET 1024*1024 #define MYRI10GE_HIGHPART_TO_U32(X) \ (sizeof (X) == 8) ? ((u32)((u64)(X) >> 32)) : (0) @@ -657,7 +671,7 @@ static int myri10ge_get_firmware_capabilities(struct myri10ge_priv *mgp) return 0; } -static int myri10ge_load_firmware(struct myri10ge_priv *mgp) +static int myri10ge_load_firmware(struct myri10ge_priv *mgp, int adopt) { char __iomem *submit; __be32 buf[16] __attribute__ ((__aligned__(8))); @@ -667,6 +681,8 @@ static int myri10ge_load_firmware(struct myri10ge_priv *mgp) size = 0; status = myri10ge_load_hotplug_firmware(mgp, &size); if (status) { + if (!adopt) + return status; dev_warn(&mgp->pdev->dev, "hotplug firmware loading failed\n"); /* Do not attempt to adopt firmware if there @@ -859,7 +875,8 @@ abort: static int myri10ge_reset(struct myri10ge_priv *mgp) { struct myri10ge_cmd cmd; - int status; + struct myri10ge_slice_state *ss; + int i, status; size_t bytes; /* try to send a reset command to the card to see if it @@ -872,20 +889,74 @@ static int myri10ge_reset(struct myri10ge_priv *mgp) } (void)myri10ge_dma_test(mgp, MXGEFW_DMA_TEST); + /* + * Use non-ndis mcp_slot (eg, 4 bytes total, + * no toeplitz hash value returned. Older firmware will + * not understand this command, but will use the correct + * sized mcp_slot, so we ignore error returns + */ + cmd.data0 = MXGEFW_RSS_MCP_SLOT_TYPE_MIN; + (void)myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_RSS_MCP_SLOT_TYPE, &cmd, 0); /* Now exchange information about interrupts */ - bytes = mgp->max_intr_slots * sizeof(*mgp->ss.rx_done.entry); - memset(mgp->ss.rx_done.entry, 0, bytes); + bytes = mgp->max_intr_slots * sizeof(*mgp->ss[0].rx_done.entry); cmd.data0 = (u32) bytes; status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_INTRQ_SIZE, &cmd, 0); - cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->ss.rx_done.bus); - cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->ss.rx_done.bus); - status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_INTRQ_DMA, &cmd, 0); + + /* + * Even though we already know how many slices are supported + * via myri10ge_probe_slices() MXGEFW_CMD_GET_MAX_RSS_QUEUES + * has magic side effects, and must be called after a reset. + * It must be called prior to calling any RSS related cmds, + * including assigning an interrupt queue for anything but + * slice 0. It must also be called *after* + * MXGEFW_CMD_SET_INTRQ_SIZE, since the intrq size is used by + * the firmware to compute offsets. + */ + + if (mgp->num_slices > 1) { + + /* ask the maximum number of slices it supports */ + status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_MAX_RSS_QUEUES, + &cmd, 0); + if (status != 0) { + dev_err(&mgp->pdev->dev, + "failed to get number of slices\n"); + } + + /* + * MXGEFW_CMD_ENABLE_RSS_QUEUES must be called prior + * to setting up the interrupt queue DMA + */ + + cmd.data0 = mgp->num_slices; + cmd.data1 = 1; /* use MSI-X */ + status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ENABLE_RSS_QUEUES, + &cmd, 0); + if (status != 0) { + dev_err(&mgp->pdev->dev, + "failed to set number of slices\n"); + + return status; + } + } + for (i = 0; i < mgp->num_slices; i++) { + ss = &mgp->ss[i]; + cmd.data0 = MYRI10GE_LOWPART_TO_U32(ss->rx_done.bus); + cmd.data1 = MYRI10GE_HIGHPART_TO_U32(ss->rx_done.bus); + cmd.data2 = i; + status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_INTRQ_DMA, + &cmd, 0); + }; status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_IRQ_ACK_OFFSET, &cmd, 0); - mgp->ss.irq_claim = (__iomem __be32 *) (mgp->sram + cmd.data0); + for (i = 0; i < mgp->num_slices; i++) { + ss = &mgp->ss[i]; + ss->irq_claim = + (__iomem __be32 *) (mgp->sram + cmd.data0 + 8 * i); + } status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_IRQ_DEASSERT_OFFSET, &cmd, 0); mgp->irq_deassert = (__iomem __be32 *) (mgp->sram + cmd.data0); @@ -899,18 +970,25 @@ static int myri10ge_reset(struct myri10ge_priv *mgp) } put_be32(htonl(mgp->intr_coal_delay), mgp->intr_coal_delay_ptr); - memset(mgp->ss.rx_done.entry, 0, bytes); - /* reset mcp/driver shared state back to 0 */ - mgp->ss.tx.req = 0; - mgp->ss.tx.done = 0; - mgp->ss.tx.pkt_start = 0; - mgp->ss.tx.pkt_done = 0; - mgp->ss.rx_big.cnt = 0; - mgp->ss.rx_small.cnt = 0; - mgp->ss.rx_done.idx = 0; - mgp->ss.rx_done.cnt = 0; + mgp->link_changes = 0; + for (i = 0; i < mgp->num_slices; i++) { + ss = &mgp->ss[i]; + + memset(ss->rx_done.entry, 0, bytes); + ss->tx.req = 0; + ss->tx.done = 0; + ss->tx.pkt_start = 0; + ss->tx.pkt_done = 0; + ss->rx_big.cnt = 0; + ss->rx_small.cnt = 0; + ss->rx_done.idx = 0; + ss->rx_done.cnt = 0; + ss->tx.wake_queue = 0; + ss->tx.stop_queue = 0; + } + status = myri10ge_update_mac_address(mgp, mgp->dev->dev_addr); myri10ge_change_pause(mgp, mgp->pause); myri10ge_set_multicast_list(mgp->dev); @@ -1095,9 +1173,10 @@ myri10ge_rx_done(struct myri10ge_slice_state *ss, struct myri10ge_rx_buf *rx, rx_frags[0].size -= MXGEFW_PAD; len -= MXGEFW_PAD; lro_receive_frags(&ss->rx_done.lro_mgr, rx_frags, - len, len, /* opaque, will come back in get_frag_header */ + len, len, (void *)(__force unsigned long)csum, csum); + return 1; } @@ -1236,7 +1315,7 @@ myri10ge_clean_rx_done(struct myri10ge_slice_state *ss, int budget) static inline void myri10ge_check_statblock(struct myri10ge_priv *mgp) { - struct mcp_irq_data *stats = mgp->ss.fw_stats; + struct mcp_irq_data *stats = mgp->ss[0].fw_stats; if (unlikely(stats->stats_updated)) { unsigned link_up = ntohl(stats->link_up); @@ -1302,6 +1381,13 @@ static irqreturn_t myri10ge_intr(int irq, void *arg) u32 send_done_count; int i; + /* an interrupt on a non-zero slice is implicitly valid + * since MSI-X irqs are not shared */ + if (ss != mgp->ss) { + netif_rx_schedule(ss->dev, &ss->napi); + return (IRQ_HANDLED); + } + /* make sure it is our IRQ, and that the DMA has finished */ if (unlikely(!stats->valid)) return (IRQ_NONE); @@ -1311,7 +1397,7 @@ static irqreturn_t myri10ge_intr(int irq, void *arg) if (stats->valid & 1) netif_rx_schedule(ss->dev, &ss->napi); - if (!mgp->msi_enabled) { + if (!mgp->msi_enabled && !mgp->msix_enabled) { put_be32(0, mgp->irq_deassert); if (!myri10ge_deassert_wait) stats->valid = 0; @@ -1446,10 +1532,10 @@ myri10ge_get_ringparam(struct net_device *netdev, { struct myri10ge_priv *mgp = netdev_priv(netdev); - ring->rx_mini_max_pending = mgp->ss.rx_small.mask + 1; - ring->rx_max_pending = mgp->ss.rx_big.mask + 1; + ring->rx_mini_max_pending = mgp->ss[0].rx_small.mask + 1; + ring->rx_max_pending = mgp->ss[0].rx_big.mask + 1; ring->rx_jumbo_max_pending = 0; - ring->tx_max_pending = mgp->ss.rx_small.mask + 1; + ring->tx_max_pending = mgp->ss[0].rx_small.mask + 1; ring->rx_mini_pending = ring->rx_mini_max_pending; ring->rx_pending = ring->rx_max_pending; ring->rx_jumbo_pending = ring->rx_jumbo_max_pending; @@ -1497,7 +1583,7 @@ static const char myri10ge_gstrings_main_stats[][ETH_GSTRING_LEN] = { "tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors", "tx_heartbeat_errors", "tx_window_errors", /* device-specific stats */ - "tx_boundary", "WC", "irq", "MSI", + "tx_boundary", "WC", "irq", "MSI", "MSIX", "read_dma_bw_MBs", "write_dma_bw_MBs", "read_write_dma_bw_MBs", "serial_number", "watchdog_resets", "link_changes", "link_up", "dropped_link_overflow", @@ -1524,23 +1610,31 @@ static const char myri10ge_gstrings_slice_stats[][ETH_GSTRING_LEN] = { static void myri10ge_get_strings(struct net_device *netdev, u32 stringset, u8 * data) { + struct myri10ge_priv *mgp = netdev_priv(netdev); + int i; + switch (stringset) { case ETH_SS_STATS: memcpy(data, *myri10ge_gstrings_main_stats, sizeof(myri10ge_gstrings_main_stats)); data += sizeof(myri10ge_gstrings_main_stats); - memcpy(data, *myri10ge_gstrings_slice_stats, - sizeof(myri10ge_gstrings_slice_stats)); - data += sizeof(myri10ge_gstrings_slice_stats); + for (i = 0; i < mgp->num_slices; i++) { + memcpy(data, *myri10ge_gstrings_slice_stats, + sizeof(myri10ge_gstrings_slice_stats)); + data += sizeof(myri10ge_gstrings_slice_stats); + } break; } } static int myri10ge_get_sset_count(struct net_device *netdev, int sset) { + struct myri10ge_priv *mgp = netdev_priv(netdev); + switch (sset) { case ETH_SS_STATS: - return MYRI10GE_MAIN_STATS_LEN + MYRI10GE_SLICE_STATS_LEN; + return MYRI10GE_MAIN_STATS_LEN + + mgp->num_slices * MYRI10GE_SLICE_STATS_LEN; default: return -EOPNOTSUPP; } @@ -1552,6 +1646,7 @@ myri10ge_get_ethtool_stats(struct net_device *netdev, { struct myri10ge_priv *mgp = netdev_priv(netdev); struct myri10ge_slice_state *ss; + int slice; int i; for (i = 0; i < MYRI10GE_NET_STATS_LEN; i++) @@ -1561,6 +1656,7 @@ myri10ge_get_ethtool_stats(struct net_device *netdev, data[i++] = (unsigned int)mgp->wc_enabled; data[i++] = (unsigned int)mgp->pdev->irq; data[i++] = (unsigned int)mgp->msi_enabled; + data[i++] = (unsigned int)mgp->msix_enabled; data[i++] = (unsigned int)mgp->read_dma; data[i++] = (unsigned int)mgp->write_dma; data[i++] = (unsigned int)mgp->read_write_dma; @@ -1569,7 +1665,7 @@ myri10ge_get_ethtool_stats(struct net_device *netdev, data[i++] = (unsigned int)mgp->link_changes; /* firmware stats are useful only in the first slice */ - ss = &mgp->ss; + ss = &mgp->ss[0]; data[i++] = (unsigned int)ntohl(ss->fw_stats->link_up); data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_link_overflow); data[i++] = @@ -1585,24 +1681,27 @@ myri10ge_get_ethtool_stats(struct net_device *netdev, data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_no_small_buffer); data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_no_big_buffer); - data[i++] = 0; - data[i++] = (unsigned int)ss->tx.pkt_start; - data[i++] = (unsigned int)ss->tx.pkt_done; - data[i++] = (unsigned int)ss->tx.req; - data[i++] = (unsigned int)ss->tx.done; - data[i++] = (unsigned int)ss->rx_small.cnt; - data[i++] = (unsigned int)ss->rx_big.cnt; - data[i++] = (unsigned int)ss->tx.wake_queue; - data[i++] = (unsigned int)ss->tx.stop_queue; - data[i++] = (unsigned int)ss->tx.linearized; - data[i++] = ss->rx_done.lro_mgr.stats.aggregated; - data[i++] = ss->rx_done.lro_mgr.stats.flushed; - if (ss->rx_done.lro_mgr.stats.flushed) - data[i++] = ss->rx_done.lro_mgr.stats.aggregated / - ss->rx_done.lro_mgr.stats.flushed; - else - data[i++] = 0; - data[i++] = ss->rx_done.lro_mgr.stats.no_desc; + for (slice = 0; slice < mgp->num_slices; slice++) { + ss = &mgp->ss[slice]; + data[i++] = slice; + data[i++] = (unsigned int)ss->tx.pkt_start; + data[i++] = (unsigned int)ss->tx.pkt_done; + data[i++] = (unsigned int)ss->tx.req; + data[i++] = (unsigned int)ss->tx.done; + data[i++] = (unsigned int)ss->rx_small.cnt; + data[i++] = (unsigned int)ss->rx_big.cnt; + data[i++] = (unsigned int)ss->tx.wake_queue; + data[i++] = (unsigned int)ss->tx.stop_queue; + data[i++] = (unsigned int)ss->tx.linearized; + data[i++] = ss->rx_done.lro_mgr.stats.aggregated; + data[i++] = ss->rx_done.lro_mgr.stats.flushed; + if (ss->rx_done.lro_mgr.stats.flushed) + data[i++] = ss->rx_done.lro_mgr.stats.aggregated / + ss->rx_done.lro_mgr.stats.flushed; + else + data[i++] = 0; + data[i++] = ss->rx_done.lro_mgr.stats.no_desc; + } } static void myri10ge_set_msglevel(struct net_device *netdev, u32 value) @@ -1645,12 +1744,15 @@ static int myri10ge_allocate_rings(struct myri10ge_slice_state *ss) struct net_device *dev = mgp->dev; int tx_ring_size, rx_ring_size; int tx_ring_entries, rx_ring_entries; - int i, status; + int i, slice, status; size_t bytes; /* get ring sizes */ + slice = ss - mgp->ss; + cmd.data0 = slice; status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SEND_RING_SIZE, &cmd, 0); tx_ring_size = cmd.data0; + cmd.data0 = slice; status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_RX_RING_SIZE, &cmd, 0); if (status != 0) return status; @@ -1715,15 +1817,17 @@ static int myri10ge_allocate_rings(struct myri10ge_slice_state *ss) mgp->small_bytes + MXGEFW_PAD, 0); if (ss->rx_small.fill_cnt < ss->rx_small.mask + 1) { - printk(KERN_ERR "myri10ge: %s: alloced only %d small bufs\n", - dev->name, ss->rx_small.fill_cnt); + printk(KERN_ERR + "myri10ge: %s:slice-%d: alloced only %d small bufs\n", + dev->name, slice, ss->rx_small.fill_cnt); goto abort_with_rx_small_ring; } myri10ge_alloc_rx_pages(mgp, &ss->rx_big, mgp->big_bytes, 0); if (ss->rx_big.fill_cnt < ss->rx_big.mask + 1) { - printk(KERN_ERR "myri10ge: %s: alloced only %d big bufs\n", - dev->name, ss->rx_big.fill_cnt); + printk(KERN_ERR + "myri10ge: %s:slice-%d: alloced only %d big bufs\n", + dev->name, slice, ss->rx_big.fill_cnt); goto abort_with_rx_big_ring; } @@ -1775,6 +1879,10 @@ static void myri10ge_free_rings(struct myri10ge_slice_state *ss) struct myri10ge_tx_buf *tx; int i, len, idx; + /* If not allocated, skip it */ + if (ss->tx.req_list == NULL) + return; + for (i = ss->rx_big.cnt; i < ss->rx_big.fill_cnt; i++) { idx = i & ss->rx_big.mask; if (i == ss->rx_big.fill_cnt - 1) @@ -1837,25 +1945,67 @@ static void myri10ge_free_rings(struct myri10ge_slice_state *ss) static int myri10ge_request_irq(struct myri10ge_priv *mgp) { struct pci_dev *pdev = mgp->pdev; + struct myri10ge_slice_state *ss; + struct net_device *netdev = mgp->dev; + int i; int status; + mgp->msi_enabled = 0; + mgp->msix_enabled = 0; + status = 0; if (myri10ge_msi) { - status = pci_enable_msi(pdev); - if (status != 0) - dev_err(&pdev->dev, - "Error %d setting up MSI; falling back to xPIC\n", - status); - else - mgp->msi_enabled = 1; - } else { - mgp->msi_enabled = 0; + if (mgp->num_slices > 1) { + status = + pci_enable_msix(pdev, mgp->msix_vectors, + mgp->num_slices); + if (status == 0) { + mgp->msix_enabled = 1; + } else { + dev_err(&pdev->dev, + "Error %d setting up MSI-X\n", status); + return status; + } + } + if (mgp->msix_enabled == 0) { + status = pci_enable_msi(pdev); + if (status != 0) { + dev_err(&pdev->dev, + "Error %d setting up MSI; falling back to xPIC\n", + status); + } else { + mgp->msi_enabled = 1; + } + } } - status = request_irq(pdev->irq, myri10ge_intr, IRQF_SHARED, - mgp->dev->name, mgp); - if (status != 0) { - dev_err(&pdev->dev, "failed to allocate IRQ\n"); - if (mgp->msi_enabled) - pci_disable_msi(pdev); + if (mgp->msix_enabled) { + for (i = 0; i < mgp->num_slices; i++) { + ss = &mgp->ss[i]; + snprintf(ss->irq_desc, sizeof(ss->irq_desc), + "%s:slice-%d", netdev->name, i); + status = request_irq(mgp->msix_vectors[i].vector, + myri10ge_intr, 0, ss->irq_desc, + ss); + if (status != 0) { + dev_err(&pdev->dev, + "slice %d failed to allocate IRQ\n", i); + i--; + while (i >= 0) { + free_irq(mgp->msix_vectors[i].vector, + &mgp->ss[i]); + i--; + } + pci_disable_msix(pdev); + return status; + } + } + } else { + status = request_irq(pdev->irq, myri10ge_intr, IRQF_SHARED, + mgp->dev->name, &mgp->ss[0]); + if (status != 0) { + dev_err(&pdev->dev, "failed to allocate IRQ\n"); + if (mgp->msi_enabled) + pci_disable_msi(pdev); + } } return status; } @@ -1863,10 +2013,18 @@ static int myri10ge_request_irq(struct myri10ge_priv *mgp) static void myri10ge_free_irq(struct myri10ge_priv *mgp) { struct pci_dev *pdev = mgp->pdev; + int i; - free_irq(pdev->irq, mgp); + if (mgp->msix_enabled) { + for (i = 0; i < mgp->num_slices; i++) + free_irq(mgp->msix_vectors[i].vector, &mgp->ss[i]); + } else { + free_irq(pdev->irq, &mgp->ss[0]); + } if (mgp->msi_enabled) pci_disable_msi(pdev); + if (mgp->msix_enabled) + pci_disable_msix(pdev); } static int @@ -1928,7 +2086,6 @@ myri10ge_get_frag_header(struct skb_frag_struct *frag, void **mac_hdr, return 0; } -#if 0 static int myri10ge_get_txrx(struct myri10ge_priv *mgp, int slice) { struct myri10ge_cmd cmd; @@ -1996,14 +2153,15 @@ static int myri10ge_set_stats(struct myri10ge_priv *mgp, int slice) } return 0; } -#endif static int myri10ge_open(struct net_device *dev) { + struct myri10ge_slice_state *ss; struct myri10ge_priv *mgp = netdev_priv(dev); struct myri10ge_cmd cmd; + int i, status, big_pow2, slice; + u8 *itable; struct net_lro_mgr *lro_mgr; - int status, big_pow2; if (mgp->running != MYRI10GE_ETH_STOPPED) return -EBUSY; @@ -2015,6 +2173,48 @@ static int myri10ge_open(struct net_device *dev) goto abort_with_nothing; } + if (mgp->num_slices > 1) { + cmd.data0 = mgp->num_slices; + cmd.data1 = 1; /* use MSI-X */ + status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ENABLE_RSS_QUEUES, + &cmd, 0); + if (status != 0) { + printk(KERN_ERR + "myri10ge: %s: failed to set number of slices\n", + dev->name); + goto abort_with_nothing; + } + /* setup the indirection table */ + cmd.data0 = mgp->num_slices; + status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_RSS_TABLE_SIZE, + &cmd, 0); + + status |= myri10ge_send_cmd(mgp, + MXGEFW_CMD_GET_RSS_TABLE_OFFSET, + &cmd, 0); + if (status != 0) { + printk(KERN_ERR + "myri10ge: %s: failed to setup rss tables\n", + dev->name); + } + + /* just enable an identity mapping */ + itable = mgp->sram + cmd.data0; + for (i = 0; i < mgp->num_slices; i++) + __raw_writeb(i, &itable[i]); + + cmd.data0 = 1; + cmd.data1 = myri10ge_rss_hash; + status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_RSS_ENABLE, + &cmd, 0); + if (status != 0) { + printk(KERN_ERR + "myri10ge: %s: failed to enable slices\n", + dev->name); + goto abort_with_nothing; + } + } + status = myri10ge_request_irq(mgp); if (status != 0) goto abort_with_nothing; @@ -2038,41 +2238,6 @@ static int myri10ge_open(struct net_device *dev) if (myri10ge_small_bytes > 0) mgp->small_bytes = myri10ge_small_bytes; - /* get the lanai pointers to the send and receive rings */ - - status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SEND_OFFSET, &cmd, 0); - mgp->ss.tx.lanai = - (struct mcp_kreq_ether_send __iomem *)(mgp->sram + cmd.data0); - - status |= - myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SMALL_RX_OFFSET, &cmd, 0); - mgp->ss.rx_small.lanai = - (struct mcp_kreq_ether_recv __iomem *)(mgp->sram + cmd.data0); - - status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_BIG_RX_OFFSET, &cmd, 0); - mgp->ss.rx_big.lanai = - (struct mcp_kreq_ether_recv __iomem *)(mgp->sram + cmd.data0); - - if (status != 0) { - printk(KERN_ERR - "myri10ge: %s: failed to get ring sizes or locations\n", - dev->name); - mgp->running = MYRI10GE_ETH_STOPPED; - goto abort_with_irq; - } - - if (myri10ge_wcfifo && mgp->wc_enabled) { - mgp->ss.tx.wc_fifo = (u8 __iomem *) mgp->sram + MXGEFW_ETH_SEND_4; - mgp->ss.rx_small.wc_fifo = - (u8 __iomem *) mgp->sram + MXGEFW_ETH_RECV_SMALL; - mgp->ss.rx_big.wc_fifo = - (u8 __iomem *) mgp->sram + MXGEFW_ETH_RECV_BIG; - } else { - mgp->ss.tx.wc_fifo = NULL; - mgp->ss.rx_small.wc_fifo = NULL; - mgp->ss.rx_big.wc_fifo = NULL; - } - /* Firmware needs the big buff size as a power of 2. Lie and * tell him the buffer is larger, because we only use 1 * buffer/pkt, and the mtu will prevent overruns. @@ -2087,9 +2252,44 @@ static int myri10ge_open(struct net_device *dev) mgp->big_bytes = big_pow2; } - status = myri10ge_allocate_rings(&mgp->ss); - if (status != 0) - goto abort_with_irq; + /* setup the per-slice data structures */ + for (slice = 0; slice < mgp->num_slices; slice++) { + ss = &mgp->ss[slice]; + + status = myri10ge_get_txrx(mgp, slice); + if (status != 0) { + printk(KERN_ERR + "myri10ge: %s: failed to get ring sizes or locations\n", + dev->name); + goto abort_with_rings; + } + status = myri10ge_allocate_rings(ss); + if (status != 0) + goto abort_with_rings; + if (slice == 0) + status = myri10ge_set_stats(mgp, slice); + if (status) { + printk(KERN_ERR + "myri10ge: %s: Couldn't set stats DMA\n", + dev->name); + goto abort_with_rings; + } + + lro_mgr = &ss->rx_done.lro_mgr; + lro_mgr->dev = dev; + lro_mgr->features = LRO_F_NAPI; + lro_mgr->ip_summed = CHECKSUM_COMPLETE; + lro_mgr->ip_summed_aggr = CHECKSUM_UNNECESSARY; + lro_mgr->max_desc = MYRI10GE_MAX_LRO_DESCRIPTORS; + lro_mgr->lro_arr = ss->rx_done.lro_desc; + lro_mgr->get_frag_header = myri10ge_get_frag_header; + lro_mgr->max_aggr = myri10ge_lro_max_pkts; + if (lro_mgr->max_aggr > MAX_SKB_FRAGS) + lro_mgr->max_aggr = MAX_SKB_FRAGS; + + /* must happen prior to any irq */ + napi_enable(&(ss)->napi); + } /* now give firmware buffers sizes, and MTU */ cmd.data0 = dev->mtu + ETH_HLEN + VLAN_HLEN; @@ -2106,25 +2306,15 @@ static int myri10ge_open(struct net_device *dev) goto abort_with_rings; } - cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->ss.fw_stats_bus); - cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->ss.fw_stats_bus); - cmd.data2 = sizeof(struct mcp_irq_data); - status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_STATS_DMA_V2, &cmd, 0); - if (status == -ENOSYS) { - dma_addr_t bus = mgp->ss.fw_stats_bus; - bus += offsetof(struct mcp_irq_data, send_done_count); - cmd.data0 = MYRI10GE_LOWPART_TO_U32(bus); - cmd.data1 = MYRI10GE_HIGHPART_TO_U32(bus); - status = myri10ge_send_cmd(mgp, - MXGEFW_CMD_SET_STATS_DMA_OBSOLETE, - &cmd, 0); - /* Firmware cannot support multicast without STATS_DMA_V2 */ - mgp->fw_multicast_support = 0; - } else { - mgp->fw_multicast_support = 1; - } - if (status) { - printk(KERN_ERR "myri10ge: %s: Couldn't set stats DMA\n", + /* + * Set Linux style TSO mode; this is needed only on newer + * firmware versions. Older versions default to Linux + * style TSO + */ + cmd.data0 = 0; + status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_TSO_MODE, &cmd, 0); + if (status && status != -ENOSYS) { + printk(KERN_ERR "myri10ge: %s: Couldn't set TSO mode\n", dev->name); goto abort_with_rings; } @@ -2132,21 +2322,6 @@ static int myri10ge_open(struct net_device *dev) mgp->link_state = ~0U; mgp->rdma_tags_available = 15; - lro_mgr = &mgp->ss.rx_done.lro_mgr; - lro_mgr->dev = dev; - lro_mgr->features = LRO_F_NAPI; - lro_mgr->ip_summed = CHECKSUM_COMPLETE; - lro_mgr->ip_summed_aggr = CHECKSUM_UNNECESSARY; - lro_mgr->max_desc = MYRI10GE_MAX_LRO_DESCRIPTORS; - lro_mgr->lro_arr = mgp->ss.rx_done.lro_desc; - lro_mgr->get_frag_header = myri10ge_get_frag_header; - lro_mgr->max_aggr = myri10ge_lro_max_pkts; - lro_mgr->frag_align_pad = 2; - if (lro_mgr->max_aggr > MAX_SKB_FRAGS) - lro_mgr->max_aggr = MAX_SKB_FRAGS; - - napi_enable(&mgp->ss.napi); /* must happen prior to any irq */ - status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ETHERNET_UP, &cmd, 0); if (status) { printk(KERN_ERR "myri10ge: %s: Couldn't bring up link\n", @@ -2154,8 +2329,6 @@ static int myri10ge_open(struct net_device *dev) goto abort_with_rings; } - mgp->ss.tx.wake_queue = 0; - mgp->ss.tx.stop_queue = 0; mgp->running = MYRI10GE_ETH_RUNNING; mgp->watchdog_timer.expires = jiffies + myri10ge_watchdog_timeout * HZ; add_timer(&mgp->watchdog_timer); @@ -2163,9 +2336,9 @@ static int myri10ge_open(struct net_device *dev) return 0; abort_with_rings: - myri10ge_free_rings(&mgp->ss); + for (i = 0; i < mgp->num_slices; i++) + myri10ge_free_rings(&mgp->ss[i]); -abort_with_irq: myri10ge_free_irq(mgp); abort_with_nothing: @@ -2178,16 +2351,19 @@ static int myri10ge_close(struct net_device *dev) struct myri10ge_priv *mgp = netdev_priv(dev); struct myri10ge_cmd cmd; int status, old_down_cnt; + int i; if (mgp->running != MYRI10GE_ETH_RUNNING) return 0; - if (mgp->ss.tx.req_bytes == NULL) + if (mgp->ss[0].tx.req_bytes == NULL) return 0; del_timer_sync(&mgp->watchdog_timer); mgp->running = MYRI10GE_ETH_STOPPING; - napi_disable(&mgp->ss.napi); + for (i = 0; i < mgp->num_slices; i++) { + napi_disable(&mgp->ss[i].napi); + } netif_carrier_off(dev); netif_stop_queue(dev); old_down_cnt = mgp->down_cnt; @@ -2203,7 +2379,8 @@ static int myri10ge_close(struct net_device *dev) netif_tx_disable(dev); myri10ge_free_irq(mgp); - myri10ge_free_rings(&mgp->ss); + for (i = 0; i < mgp->num_slices; i++) + myri10ge_free_rings(&mgp->ss[i]); mgp->running = MYRI10GE_ETH_STOPPED; return 0; @@ -2324,7 +2501,7 @@ static int myri10ge_xmit(struct sk_buff *skb, struct net_device *dev) u8 flags, odd_flag; /* always transmit through slot 0 */ - ss = &mgp->ss; + ss = mgp->ss; tx = &ss->tx; again: req = tx->req_list; @@ -2629,7 +2806,21 @@ drop: static struct net_device_stats *myri10ge_get_stats(struct net_device *dev) { struct myri10ge_priv *mgp = netdev_priv(dev); - return &mgp->stats; + struct myri10ge_slice_netstats *slice_stats; + struct net_device_stats *stats = &mgp->stats; + int i; + + memset(stats, 0, sizeof(*stats)); + for (i = 0; i < mgp->num_slices; i++) { + slice_stats = &mgp->ss[i].stats; + stats->rx_packets += slice_stats->rx_packets; + stats->tx_packets += slice_stats->tx_packets; + stats->rx_bytes += slice_stats->rx_bytes; + stats->tx_bytes += slice_stats->tx_bytes; + stats->rx_dropped += slice_stats->rx_dropped; + stats->tx_dropped += slice_stats->tx_dropped; + } + return stats; } static void myri10ge_set_multicast_list(struct net_device *dev) @@ -2840,10 +3031,10 @@ static void myri10ge_enable_ecrc(struct myri10ge_priv *mgp) * * If the driver can neither enable ECRC nor verify that it has * already been enabled, then it must use a firmware image which works - * around unaligned completion packets (myri10ge_ethp_z8e.dat), and it + * around unaligned completion packets (myri10ge_rss_ethp_z8e.dat), and it * should also ensure that it never gives the device a Read-DMA which is * larger than 2KB by setting the tx_boundary to 2KB. If ECRC is - * enabled, then the driver should use the aligned (myri10ge_eth_z8e.dat) + * enabled, then the driver should use the aligned (myri10ge_rss_eth_z8e.dat) * firmware image, and set tx_boundary to 4KB. */ @@ -2872,7 +3063,7 @@ static void myri10ge_firmware_probe(struct myri10ge_priv *mgp) * completions) in order to see if it works on this host. */ mgp->fw_name = myri10ge_fw_aligned; - status = myri10ge_load_firmware(mgp); + status = myri10ge_load_firmware(mgp, 1); if (status != 0) { goto abort; } @@ -3053,6 +3244,7 @@ static void myri10ge_watchdog(struct work_struct *work) struct myri10ge_tx_buf *tx; u32 reboot; int status; + int i; u16 cmd, vendor; mgp->watchdog_resets++; @@ -3100,20 +3292,26 @@ static void myri10ge_watchdog(struct work_struct *work) printk(KERN_ERR "myri10ge: %s: device timeout, resetting\n", mgp->dev->name); - tx = &mgp->ss.tx; - printk(KERN_INFO "myri10ge: %s: %d %d %d %d %d\n", - mgp->dev->name, tx->req, tx->done, - tx->pkt_start, tx->pkt_done, - (int)ntohl(mgp->ss.fw_stats->send_done_count)); - msleep(2000); - printk(KERN_INFO "myri10ge: %s: %d %d %d %d %d\n", - mgp->dev->name, tx->req, tx->done, - tx->pkt_start, tx->pkt_done, - (int)ntohl(mgp->ss.fw_stats->send_done_count)); + for (i = 0; i < mgp->num_slices; i++) { + tx = &mgp->ss[i].tx; + printk(KERN_INFO + "myri10ge: %s: (%d): %d %d %d %d %d\n", + mgp->dev->name, i, tx->req, tx->done, + tx->pkt_start, tx->pkt_done, + (int)ntohl(mgp->ss[i].fw_stats-> + send_done_count)); + msleep(2000); + printk(KERN_INFO + "myri10ge: %s: (%d): %d %d %d %d %d\n", + mgp->dev->name, i, tx->req, tx->done, + tx->pkt_start, tx->pkt_done, + (int)ntohl(mgp->ss[i].fw_stats-> + send_done_count)); + } } rtnl_lock(); myri10ge_close(mgp->dev); - status = myri10ge_load_firmware(mgp); + status = myri10ge_load_firmware(mgp, 1); if (status != 0) printk(KERN_ERR "myri10ge: %s: failed to load firmware\n", mgp->dev->name); @@ -3133,50 +3331,59 @@ static void myri10ge_watchdog_timer(unsigned long arg) { struct myri10ge_priv *mgp; struct myri10ge_slice_state *ss; + int i, reset_needed; u32 rx_pause_cnt; mgp = (struct myri10ge_priv *)arg; - rx_pause_cnt = ntohl(mgp->ss.fw_stats->dropped_pause); + rx_pause_cnt = ntohl(mgp->ss[0].fw_stats->dropped_pause); + for (i = 0, reset_needed = 0; + i < mgp->num_slices && reset_needed == 0; ++i) { - ss = &mgp->ss; - if (ss->rx_small.watchdog_needed) { - myri10ge_alloc_rx_pages(mgp, &ss->rx_small, - mgp->small_bytes + MXGEFW_PAD, 1); - if (ss->rx_small.fill_cnt - ss->rx_small.cnt >= - myri10ge_fill_thresh) - ss->rx_small.watchdog_needed = 0; - } - if (ss->rx_big.watchdog_needed) { - myri10ge_alloc_rx_pages(mgp, &ss->rx_big, mgp->big_bytes, 1); - if (ss->rx_big.fill_cnt - ss->rx_big.cnt >= - myri10ge_fill_thresh) - ss->rx_big.watchdog_needed = 0; - } - - if (ss->tx.req != ss->tx.done && - ss->tx.done == ss->watchdog_tx_done && - ss->watchdog_tx_req != ss->watchdog_tx_done) { - /* nic seems like it might be stuck.. */ - if (rx_pause_cnt != mgp->watchdog_pause) { - if (net_ratelimit()) - printk(KERN_WARNING "myri10ge %s:" - "TX paused, check link partner\n", - mgp->dev->name); - } else { - schedule_work(&mgp->watchdog_work); - return; + ss = &mgp->ss[i]; + if (ss->rx_small.watchdog_needed) { + myri10ge_alloc_rx_pages(mgp, &ss->rx_small, + mgp->small_bytes + MXGEFW_PAD, + 1); + if (ss->rx_small.fill_cnt - ss->rx_small.cnt >= + myri10ge_fill_thresh) + ss->rx_small.watchdog_needed = 0; + } + if (ss->rx_big.watchdog_needed) { + myri10ge_alloc_rx_pages(mgp, &ss->rx_big, + mgp->big_bytes, 1); + if (ss->rx_big.fill_cnt - ss->rx_big.cnt >= + myri10ge_fill_thresh) + ss->rx_big.watchdog_needed = 0; + } + + if (ss->tx.req != ss->tx.done && + ss->tx.done == ss->watchdog_tx_done && + ss->watchdog_tx_req != ss->watchdog_tx_done) { + /* nic seems like it might be stuck.. */ + if (rx_pause_cnt != mgp->watchdog_pause) { + if (net_ratelimit()) + printk(KERN_WARNING "myri10ge %s:" + "TX paused, check link partner\n", + mgp->dev->name); + } else { + reset_needed = 1; + } } + ss->watchdog_tx_done = ss->tx.done; + ss->watchdog_tx_req = ss->tx.req; } - /* rearm timer */ - mod_timer(&mgp->watchdog_timer, - jiffies + myri10ge_watchdog_timeout * HZ); - ss->watchdog_tx_done = ss->tx.done; - ss->watchdog_tx_req = ss->tx.req; mgp->watchdog_pause = rx_pause_cnt; + + if (reset_needed) { + schedule_work(&mgp->watchdog_work); + } else { + /* rearm timer */ + mod_timer(&mgp->watchdog_timer, + jiffies + myri10ge_watchdog_timeout * HZ); + } } -#if 0 static void myri10ge_free_slices(struct myri10ge_priv *mgp) { struct myri10ge_slice_state *ss; @@ -3360,14 +3567,12 @@ abort_with_fw: mgp->fw_name = old_fw; myri10ge_load_firmware(mgp, 0); } -#endif static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct net_device *netdev; struct myri10ge_priv *mgp; struct device *dev = &pdev->dev; - size_t bytes; int i; int status = -ENXIO; int dac_enabled; @@ -3382,7 +3587,6 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) mgp = netdev_priv(netdev); mgp->dev = netdev; - netif_napi_add(netdev, &mgp->ss.napi, myri10ge_poll, myri10ge_napi_weight); mgp->pdev = pdev; mgp->csum_flag = MXGEFW_FLAGS_CKSUM; mgp->pause = myri10ge_flow_control; @@ -3428,11 +3632,6 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (mgp->cmd == NULL) goto abort_with_netdev; - mgp->ss.fw_stats = dma_alloc_coherent(&pdev->dev, sizeof(*mgp->ss.fw_stats), - &mgp->ss.fw_stats_bus, GFP_KERNEL); - if (mgp->ss.fw_stats == NULL) - goto abort_with_cmd; - mgp->board_span = pci_resource_len(pdev, 0); mgp->iomem_base = pci_resource_start(pdev, 0); mgp->mtrr = -1; @@ -3469,26 +3668,24 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) for (i = 0; i < ETH_ALEN; i++) netdev->dev_addr[i] = mgp->mac_addr[i]; - /* allocate rx done ring */ - bytes = mgp->max_intr_slots * sizeof(*mgp->ss.rx_done.entry); - mgp->ss.rx_done.entry = dma_alloc_coherent(&pdev->dev, bytes, - &mgp->ss.rx_done.bus, GFP_KERNEL); - if (mgp->ss.rx_done.entry == NULL) - goto abort_with_ioremap; - memset(mgp->ss.rx_done.entry, 0, bytes); - myri10ge_select_firmware(mgp); - status = myri10ge_load_firmware(mgp); + status = myri10ge_load_firmware(mgp, 1); if (status != 0) { dev_err(&pdev->dev, "failed to load firmware\n"); - goto abort_with_rx_done; + goto abort_with_ioremap; + } + myri10ge_probe_slices(mgp); + status = myri10ge_alloc_slices(mgp); + if (status != 0) { + dev_err(&pdev->dev, "failed to alloc slice state\n"); + goto abort_with_firmware; } status = myri10ge_reset(mgp); if (status != 0) { dev_err(&pdev->dev, "failed reset\n"); - goto abort_with_firmware; + goto abort_with_slices; } pci_set_drvdata(pdev, mgp); @@ -3533,24 +3730,27 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dev_err(&pdev->dev, "register_netdev failed: %d\n", status); goto abort_with_state; } - dev_info(dev, "%s IRQ %d, tx bndry %d, fw %s, WC %s\n", - (mgp->msi_enabled ? "MSI" : "xPIC"), - netdev->irq, mgp->tx_boundary, mgp->fw_name, - (mgp->wc_enabled ? "Enabled" : "Disabled")); + if (mgp->msix_enabled) + dev_info(dev, "%d MSI-X IRQs, tx bndry %d, fw %s, WC %s\n", + mgp->num_slices, mgp->tx_boundary, mgp->fw_name, + (mgp->wc_enabled ? "Enabled" : "Disabled")); + else + dev_info(dev, "%s IRQ %d, tx bndry %d, fw %s, WC %s\n", + mgp->msi_enabled ? "MSI" : "xPIC", + netdev->irq, mgp->tx_boundary, mgp->fw_name, + (mgp->wc_enabled ? "Enabled" : "Disabled")); return 0; abort_with_state: pci_restore_state(pdev); +abort_with_slices: + myri10ge_free_slices(mgp); + abort_with_firmware: myri10ge_dummy_rdma(mgp, 0); -abort_with_rx_done: - bytes = mgp->max_intr_slots * sizeof(*mgp->ss.rx_done.entry); - dma_free_coherent(&pdev->dev, bytes, - mgp->ss.rx_done.entry, mgp->ss.rx_done.bus); - abort_with_ioremap: iounmap(mgp->sram); @@ -3559,10 +3759,6 @@ abort_with_wc: if (mgp->mtrr >= 0) mtrr_del(mgp->mtrr, mgp->iomem_base, mgp->board_span); #endif - dma_free_coherent(&pdev->dev, sizeof(*mgp->ss.fw_stats), - mgp->ss.fw_stats, mgp->ss.fw_stats_bus); - -abort_with_cmd: dma_free_coherent(&pdev->dev, sizeof(*mgp->cmd), mgp->cmd, mgp->cmd_bus); @@ -3583,7 +3779,6 @@ static void myri10ge_remove(struct pci_dev *pdev) { struct myri10ge_priv *mgp; struct net_device *netdev; - size_t bytes; mgp = pci_get_drvdata(pdev); if (mgp == NULL) @@ -3598,19 +3793,15 @@ static void myri10ge_remove(struct pci_dev *pdev) /* avoid a memory leak */ pci_restore_state(pdev); - bytes = mgp->max_intr_slots * sizeof(*mgp->ss.rx_done.entry); - dma_free_coherent(&pdev->dev, bytes, - mgp->ss.rx_done.entry, mgp->ss.rx_done.bus); - iounmap(mgp->sram); #ifdef CONFIG_MTRR if (mgp->mtrr >= 0) mtrr_del(mgp->mtrr, mgp->iomem_base, mgp->board_span); #endif - dma_free_coherent(&pdev->dev, sizeof(*mgp->ss.fw_stats), - mgp->ss.fw_stats, mgp->ss.fw_stats_bus); - + myri10ge_free_slices(mgp); + if (mgp->msix_vectors != NULL) + kfree(mgp->msix_vectors); dma_free_coherent(&pdev->dev, sizeof(*mgp->cmd), mgp->cmd, mgp->cmd_bus); @@ -3643,6 +3834,15 @@ static __init int myri10ge_init_module(void) { printk(KERN_INFO "%s: Version %s\n", myri10ge_driver.name, MYRI10GE_VERSION_STR); + + if (myri10ge_rss_hash > MXGEFW_RSS_HASH_TYPE_SRC_PORT || + myri10ge_rss_hash < MXGEFW_RSS_HASH_TYPE_IPV4) { + printk(KERN_ERR + "%s: Illegal rssh hash type %d, defaulting to source port\n", + myri10ge_driver.name, myri10ge_rss_hash); + myri10ge_rss_hash = MXGEFW_RSS_HASH_TYPE_SRC_PORT; + } + return pci_register_driver(&myri10ge_driver); } -- cgit v1.2.3-70-g09d2 From 981813d8e0a16946f511f4eda17bb4ee4fa2769c Mon Sep 17 00:00:00 2001 From: Brice Goglin Date: Fri, 9 May 2008 02:22:16 +0200 Subject: myri10ge: add Direct Cache Access support Add I/O AT DCA (Direct Cache Access) support. Signed-off-by: Brice Goglin Signed-off-by: Andrew Gallatin Signed-off-by: Jeff Garzik --- drivers/net/myri10ge/myri10ge.c | 146 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 145 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index eddcee326f0..93007d38df5 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -185,6 +186,11 @@ struct myri10ge_slice_state { dma_addr_t fw_stats_bus; int watchdog_tx_done; int watchdog_tx_req; +#ifdef CONFIG_DCA + int cached_dca_tag; + int cpu; + __be32 __iomem *dca_tag; +#endif char irq_desc[32]; }; @@ -212,6 +218,9 @@ struct myri10ge_priv { int msi_enabled; int msix_enabled; struct msix_entry *msix_vectors; +#ifdef CONFIG_DCA + int dca_enabled; +#endif u32 link_state; unsigned int rdma_tags_available; int intr_coal_delay; @@ -335,6 +344,10 @@ static int myri10ge_rss_hash = MXGEFW_RSS_HASH_TYPE_SRC_PORT; module_param(myri10ge_rss_hash, int, S_IRUGO); MODULE_PARM_DESC(myri10ge_rss_hash, "Type of RSS hashing to do"); +static int myri10ge_dca = 1; +module_param(myri10ge_dca, int, S_IRUGO); +MODULE_PARM_DESC(myri10ge_dca, "Enable DCA if possible"); + #define MYRI10GE_FW_OFFSET 1024*1024 #define MYRI10GE_HIGHPART_TO_U32(X) \ (sizeof (X) == 8) ? ((u32)((u64)(X) >> 32)) : (0) @@ -878,6 +891,9 @@ static int myri10ge_reset(struct myri10ge_priv *mgp) struct myri10ge_slice_state *ss; int i, status; size_t bytes; +#ifdef CONFIG_DCA + unsigned long dca_tag_off; +#endif /* try to send a reset command to the card to see if it * is alive */ @@ -970,6 +986,20 @@ static int myri10ge_reset(struct myri10ge_priv *mgp) } put_be32(htonl(mgp->intr_coal_delay), mgp->intr_coal_delay_ptr); +#ifdef CONFIG_DCA + status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_DCA_OFFSET, &cmd, 0); + dca_tag_off = cmd.data0; + for (i = 0; i < mgp->num_slices; i++) { + ss = &mgp->ss[i]; + if (status == 0) { + ss->dca_tag = (__iomem __be32 *) + (mgp->sram + dca_tag_off + 4 * i); + } else { + ss->dca_tag = NULL; + } + } +#endif /* CONFIG_DCA */ + /* reset mcp/driver shared state back to 0 */ mgp->link_changes = 0; @@ -995,6 +1025,77 @@ static int myri10ge_reset(struct myri10ge_priv *mgp) return status; } +#ifdef CONFIG_DCA +static void +myri10ge_write_dca(struct myri10ge_slice_state *ss, int cpu, int tag) +{ + ss->cpu = cpu; + ss->cached_dca_tag = tag; + put_be32(htonl(tag), ss->dca_tag); +} + +static inline void myri10ge_update_dca(struct myri10ge_slice_state *ss) +{ + int cpu = get_cpu(); + int tag; + + if (cpu != ss->cpu) { + tag = dca_get_tag(cpu); + if (ss->cached_dca_tag != tag) + myri10ge_write_dca(ss, cpu, tag); + } + put_cpu(); +} + +static void myri10ge_setup_dca(struct myri10ge_priv *mgp) +{ + int err, i; + struct pci_dev *pdev = mgp->pdev; + + if (mgp->ss[0].dca_tag == NULL || mgp->dca_enabled) + return; + if (!myri10ge_dca) { + dev_err(&pdev->dev, "dca disabled by administrator\n"); + return; + } + err = dca_add_requester(&pdev->dev); + if (err) { + dev_err(&pdev->dev, + "dca_add_requester() failed, err=%d\n", err); + return; + } + mgp->dca_enabled = 1; + for (i = 0; i < mgp->num_slices; i++) + myri10ge_write_dca(&mgp->ss[i], -1, 0); +} + +static void myri10ge_teardown_dca(struct myri10ge_priv *mgp) +{ + struct pci_dev *pdev = mgp->pdev; + int err; + + if (!mgp->dca_enabled) + return; + mgp->dca_enabled = 0; + err = dca_remove_requester(&pdev->dev); +} + +static int myri10ge_notify_dca_device(struct device *dev, void *data) +{ + struct myri10ge_priv *mgp; + unsigned long event; + + mgp = dev_get_drvdata(dev); + event = *(unsigned long *)data; + + if (event == DCA_PROVIDER_ADD) + myri10ge_setup_dca(mgp); + else if (event == DCA_PROVIDER_REMOVE) + myri10ge_teardown_dca(mgp); + return 0; +} +#endif /* CONFIG_DCA */ + static inline void myri10ge_submit_8rx(struct mcp_kreq_ether_recv __iomem * dst, struct mcp_kreq_ether_recv *src) @@ -1362,6 +1463,11 @@ static int myri10ge_poll(struct napi_struct *napi, int budget) struct net_device *netdev = ss->mgp->dev; int work_done; +#ifdef CONFIG_DCA + if (ss->mgp->dca_enabled) + myri10ge_update_dca(ss); +#endif + /* process as many rx events as NAPI will allow */ work_done = myri10ge_clean_rx_done(ss, budget); @@ -1586,6 +1692,9 @@ static const char myri10ge_gstrings_main_stats[][ETH_GSTRING_LEN] = { "tx_boundary", "WC", "irq", "MSI", "MSIX", "read_dma_bw_MBs", "write_dma_bw_MBs", "read_write_dma_bw_MBs", "serial_number", "watchdog_resets", +#ifdef CONFIG_DCA + "dca_capable", "dca_enabled", +#endif "link_changes", "link_up", "dropped_link_overflow", "dropped_link_error_or_filtered", "dropped_pause", "dropped_bad_phy", "dropped_bad_crc32", @@ -1662,6 +1771,10 @@ myri10ge_get_ethtool_stats(struct net_device *netdev, data[i++] = (unsigned int)mgp->read_write_dma; data[i++] = (unsigned int)mgp->serial_number; data[i++] = (unsigned int)mgp->watchdog_resets; +#ifdef CONFIG_DCA + data[i++] = (unsigned int)(mgp->ss[0].dca_tag != NULL); + data[i++] = (unsigned int)(mgp->dca_enabled); +#endif data[i++] = (unsigned int)mgp->link_changes; /* firmware stats are useful only in the first slice */ @@ -3687,7 +3800,9 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dev_err(&pdev->dev, "failed reset\n"); goto abort_with_slices; } - +#ifdef CONFIG_DCA + myri10ge_setup_dca(mgp); +#endif pci_set_drvdata(pdev, mgp); if ((myri10ge_initial_mtu + ETH_HLEN) > MYRI10GE_MAX_ETHER_MTU) myri10ge_initial_mtu = MYRI10GE_MAX_ETHER_MTU - ETH_HLEN; @@ -3788,6 +3903,9 @@ static void myri10ge_remove(struct pci_dev *pdev) netdev = mgp->dev; unregister_netdev(netdev); +#ifdef CONFIG_DCA + myri10ge_teardown_dca(mgp); +#endif myri10ge_dummy_rdma(mgp, 0); /* avoid a memory leak */ @@ -3830,6 +3948,26 @@ static struct pci_driver myri10ge_driver = { #endif }; +#ifdef CONFIG_DCA +static int +myri10ge_notify_dca(struct notifier_block *nb, unsigned long event, void *p) +{ + int err = driver_for_each_device(&myri10ge_driver.driver, + NULL, &event, + myri10ge_notify_dca_device); + + if (err) + return NOTIFY_BAD; + return NOTIFY_DONE; +} + +static struct notifier_block myri10ge_dca_notifier = { + .notifier_call = myri10ge_notify_dca, + .next = NULL, + .priority = 0, +}; +#endif /* CONFIG_DCA */ + static __init int myri10ge_init_module(void) { printk(KERN_INFO "%s: Version %s\n", myri10ge_driver.name, @@ -3842,6 +3980,9 @@ static __init int myri10ge_init_module(void) myri10ge_driver.name, myri10ge_rss_hash); myri10ge_rss_hash = MXGEFW_RSS_HASH_TYPE_SRC_PORT; } +#ifdef CONFIG_DCA + dca_register_notify(&myri10ge_dca_notifier); +#endif return pci_register_driver(&myri10ge_driver); } @@ -3850,6 +3991,9 @@ module_init(myri10ge_init_module); static __exit void myri10ge_cleanup_module(void) { +#ifdef CONFIG_DCA + dca_unregister_notify(&myri10ge_dca_notifier); +#endif pci_unregister_driver(&myri10ge_driver); } -- cgit v1.2.3-70-g09d2 From 41873e9aff0632d80c74380d58a89e8d420151bd Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 30 May 2008 09:49:52 -0700 Subject: tlan: get rid of padding buffer Use skb_padto to pad frames, this avoid allocation of separate buffer just for dma of the extra bytes. Compile tested only. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/tlan.c | 37 +++++++------------------------------ 1 file changed, 7 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index 0166407d706..d1633fbf46c 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -218,8 +218,6 @@ static int bbuf; module_param(bbuf, int, 0); MODULE_PARM_DESC(bbuf, "ThunderLAN use big buffer (0-1)"); -static u8 *TLanPadBuffer; -static dma_addr_t TLanPadBufferDMA; static char TLanSignature[] = "TLAN"; static const char tlan_banner[] = "ThunderLAN driver v1.15\n"; static int tlan_have_pci; @@ -469,16 +467,6 @@ static int __init tlan_probe(void) printk(KERN_INFO "%s", tlan_banner); - TLanPadBuffer = (u8 *) pci_alloc_consistent(NULL, TLAN_MIN_FRAME_SIZE, &TLanPadBufferDMA); - - if (TLanPadBuffer == NULL) { - printk(KERN_ERR "TLAN: Could not allocate memory for pad buffer.\n"); - rc = -ENOMEM; - goto err_out; - } - - memset(TLanPadBuffer, 0, TLAN_MIN_FRAME_SIZE); - TLAN_DBG(TLAN_DEBUG_PROBE, "Starting PCI Probe....\n"); /* Use new style PCI probing. Now the kernel will @@ -506,8 +494,6 @@ static int __init tlan_probe(void) err_out_pci_unreg: pci_unregister_driver(&tlan_driver); err_out_pci_free: - pci_free_consistent(NULL, TLAN_MIN_FRAME_SIZE, TLanPadBuffer, TLanPadBufferDMA); -err_out: return rc; } @@ -724,8 +710,6 @@ static void __exit tlan_exit(void) if (tlan_have_eisa) TLan_Eisa_Cleanup(); - pci_free_consistent(NULL, TLAN_MIN_FRAME_SIZE, TLanPadBuffer, TLanPadBufferDMA); - } @@ -1096,7 +1080,6 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) TLanList *tail_list; dma_addr_t tail_list_phys; u8 *tail_buffer; - int pad; unsigned long flags; if ( ! priv->phyOnline ) { @@ -1105,6 +1088,9 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) return 0; } + if (skb_padto(skb, TLAN_MIN_FRAME_SIZE)) + return 0; + tail_list = priv->txList + priv->txTail; tail_list_phys = priv->txListDMA + sizeof(TLanList) * priv->txTail; @@ -1125,19 +1111,10 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) TLan_StoreSKB(tail_list, skb); } - pad = TLAN_MIN_FRAME_SIZE - skb->len; - - if ( pad > 0 ) { - tail_list->frameSize = (u16) skb->len + pad; - tail_list->buffer[0].count = (u32) skb->len; - tail_list->buffer[1].count = TLAN_LAST_BUFFER | (u32) pad; - tail_list->buffer[1].address = TLanPadBufferDMA; - } else { - tail_list->frameSize = (u16) skb->len; - tail_list->buffer[0].count = TLAN_LAST_BUFFER | (u32) skb->len; - tail_list->buffer[1].count = 0; - tail_list->buffer[1].address = 0; - } + tail_list->frameSize = (u16) skb->len; + tail_list->buffer[0].count = TLAN_LAST_BUFFER | (u32) skb->len; + tail_list->buffer[1].count = 0; + tail_list->buffer[1].address = 0; spin_lock_irqsave(&priv->lock, flags); tail_list->cStat = TLAN_CSTAT_READY; -- cgit v1.2.3-70-g09d2 From f8f31544bf12e0934acb197889215bdc41762912 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 30 May 2008 09:49:53 -0700 Subject: tlan: use netdevice stats Use new netdevice common stats area. Compile tested only. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/tlan.c | 33 ++++++++++++++++----------------- drivers/net/tlan.h | 1 - 2 files changed, 16 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index d1633fbf46c..c14d2919c48 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -1276,7 +1276,7 @@ static struct net_device_stats *TLan_GetStats( struct net_device *dev ) TLan_PrintList( priv->txList + i, "TX", i ); } - return ( &( (TLanPrivateInfo *) netdev_priv(dev) )->stats ); + return &dev->stats; } /* TLan_GetStats */ @@ -1434,7 +1434,7 @@ static u32 TLan_HandleTxEOF( struct net_device *dev, u16 host_int ) if ( tmpCStat & TLAN_CSTAT_EOC ) eoc = 1; - priv->stats.tx_bytes += head_list->frameSize; + dev->stats.tx_bytes += head_list->frameSize; head_list->cStat = TLAN_CSTAT_UNUSED; netif_start_queue(dev); @@ -1564,7 +1564,7 @@ static u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int ) skb_reserve(skb, 2); t = (void *) skb_put(skb, frameSize); - priv->stats.rx_bytes += head_list->frameSize; + dev->stats.rx_bytes += head_list->frameSize; memcpy( t, head_buffer, frameSize ); skb->protocol = eth_type_trans( skb, dev ); @@ -1586,7 +1586,7 @@ static u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int ) pci_unmap_single(priv->pciDev, head_list->buffer[0].address, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE); skb_trim( skb, frameSize ); - priv->stats.rx_bytes += frameSize; + dev->stats.rx_bytes += frameSize; skb->protocol = eth_type_trans( skb, dev ); netif_rx( skb ); @@ -2142,7 +2142,6 @@ static void TLan_PrintList( TLanList *list, char *type, int num) static void TLan_ReadAndClearStats( struct net_device *dev, int record ) { - TLanPrivateInfo *priv = netdev_priv(dev); u32 tx_good, tx_under; u32 rx_good, rx_over; u32 def_tx, crc, code; @@ -2179,18 +2178,18 @@ static void TLan_ReadAndClearStats( struct net_device *dev, int record ) loss = inb( dev->base_addr + TLAN_DIO_DATA + 2 ); if ( record ) { - priv->stats.rx_packets += rx_good; - priv->stats.rx_errors += rx_over + crc + code; - priv->stats.tx_packets += tx_good; - priv->stats.tx_errors += tx_under + loss; - priv->stats.collisions += multi_col + single_col + excess_col + late_col; - - priv->stats.rx_over_errors += rx_over; - priv->stats.rx_crc_errors += crc; - priv->stats.rx_frame_errors += code; - - priv->stats.tx_aborted_errors += tx_under; - priv->stats.tx_carrier_errors += loss; + dev->stats.rx_packets += rx_good; + dev->stats.rx_errors += rx_over + crc + code; + dev->stats.tx_packets += tx_good; + dev->stats.tx_errors += tx_under + loss; + dev->stats.collisions += multi_col + single_col + excess_col + late_col; + + dev->stats.rx_over_errors += rx_over; + dev->stats.rx_crc_errors += crc; + dev->stats.rx_frame_errors += code; + + dev->stats.tx_aborted_errors += tx_under; + dev->stats.tx_carrier_errors += loss; } } /* TLan_ReadAndClearStats */ diff --git a/drivers/net/tlan.h b/drivers/net/tlan.h index 41ce0b66593..f2fd3167be0 100644 --- a/drivers/net/tlan.h +++ b/drivers/net/tlan.h @@ -194,7 +194,6 @@ typedef struct tlan_private_tag { u32 timerSetAt; u32 timerType; struct timer_list timer; - struct net_device_stats stats; struct board *adapter; u32 adapterRev; u32 aui; -- cgit v1.2.3-70-g09d2 From 92cee9f6804786da6b63255edce7983bebf75655 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 30 May 2008 09:49:54 -0700 Subject: tlan: remove unused devName field Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/tlan.h | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/tlan.h b/drivers/net/tlan.h index f2fd3167be0..2c0abfb0c64 100644 --- a/drivers/net/tlan.h +++ b/drivers/net/tlan.h @@ -204,7 +204,6 @@ typedef struct tlan_private_tag { u32 speed; u8 tlanRev; u8 tlanFullDuplex; - char devName[8]; spinlock_t lock; u8 link; u8 is_eisa; -- cgit v1.2.3-70-g09d2 From 93e16847c9db0093065c98063cfc639cdfccf19a Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 30 May 2008 09:49:55 -0700 Subject: tlan: 64bit conversion Make this driver compile cleanly on 64 bit platforms. Compile tested only. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 2 +- drivers/net/tlan.c | 38 +++++++++++++++++--------------------- 2 files changed, 18 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 8178a4dfd09..07a91251bca 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1670,7 +1670,7 @@ config SUNDANCE_MMIO config TLAN tristate "TI ThunderLAN support" - depends on NET_PCI && (PCI || EISA) && !64BIT + depends on NET_PCI && (PCI || EISA) ---help--- If you have a PCI Ethernet network card based on the ThunderLAN chip which is supported by this driver, say Y and read the diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index c14d2919c48..aee2a458adc 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -346,23 +346,21 @@ static void TLan_EeReceiveByte( u16, u8 *, int ); static int TLan_EeReadByte( struct net_device *, u8, u8 * ); -static void +static inline void TLan_StoreSKB( struct tlan_list_tag *tag, struct sk_buff *skb) { unsigned long addr = (unsigned long)skb; - tag->buffer[9].address = (u32)addr; - addr >>= 31; /* >>= 32 is undefined for 32bit arch, stupid C */ - addr >>= 1; - tag->buffer[8].address = (u32)addr; + tag->buffer[9].address = addr; + tag->buffer[8].address = upper_32_bits(addr); } -static struct sk_buff * -TLan_GetSKB( struct tlan_list_tag *tag) +static inline struct sk_buff * +TLan_GetSKB( const struct tlan_list_tag *tag) { - unsigned long addr = tag->buffer[8].address; - addr <<= 31; - addr <<= 1; - addr |= tag->buffer[9].address; + unsigned long addr; + + addr = tag->buffer[8].address; + addr |= (tag->buffer[9].address << 16) << 16; return (struct sk_buff *) addr; } @@ -858,7 +856,8 @@ static int TLan_Init( struct net_device *dev ) dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS ) * ( sizeof(TLanList) ); } - priv->dmaStorage = pci_alloc_consistent(priv->pciDev, dma_size, &priv->dmaStorageDMA); + priv->dmaStorage = pci_alloc_consistent(priv->pciDev, + dma_size, &priv->dmaStorageDMA); priv->dmaSize = dma_size; if ( priv->dmaStorage == NULL ) { @@ -867,11 +866,11 @@ static int TLan_Init( struct net_device *dev ) return -ENOMEM; } memset( priv->dmaStorage, 0, dma_size ); - priv->rxList = (TLanList *) - ( ( ( (u32) priv->dmaStorage ) + 7 ) & 0xFFFFFFF8 ); - priv->rxListDMA = ( ( ( (u32) priv->dmaStorageDMA ) + 7 ) & 0xFFFFFFF8 ); + priv->rxList = (TLanList *) ALIGN((unsigned long)priv->dmaStorage, 8); + priv->rxListDMA = ALIGN(priv->dmaStorageDMA, 8); priv->txList = priv->rxList + TLAN_NUM_RX_LISTS; priv->txListDMA = priv->rxListDMA + sizeof(TLanList) * TLAN_NUM_RX_LISTS; + if ( bbuf ) { priv->rxBuffer = (u8 *) ( priv->txList + TLAN_NUM_TX_LISTS ); priv->rxBufferDMA =priv->txListDMA + sizeof(TLanList) * TLAN_NUM_TX_LISTS; @@ -1584,7 +1583,7 @@ static u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int ) if ( new_skb != NULL ) { skb = TLan_GetSKB(head_list); pci_unmap_single(priv->pciDev, head_list->buffer[0].address, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE); - skb_trim( skb, frameSize ); + skb_put( skb, frameSize ); dev->stats.rx_bytes += frameSize; @@ -1592,9 +1591,8 @@ static u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int ) netif_rx( skb ); skb_reserve( new_skb, 2 ); - t = (void *) skb_put( new_skb, TLAN_MAX_FRAME_SIZE ); head_list->buffer[0].address = pci_map_single(priv->pciDev, new_skb->data, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE); - head_list->buffer[8].address = (u32) t; + TLan_StoreSKB(head_list, new_skb); } else printk(KERN_WARNING "TLAN: Couldn't allocate memory for received data.\n" ); @@ -2003,10 +2001,8 @@ static void TLan_ResetLists( struct net_device *dev ) } else { skb->dev = dev; skb_reserve( skb, 2 ); - t = (void *) skb_put( skb, TLAN_MAX_FRAME_SIZE ); } list->buffer[0].address = pci_map_single(priv->pciDev, t, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE); - list->buffer[8].address = (u32) t; TLan_StoreSKB(list, skb); } list->buffer[1].count = 0; @@ -2108,7 +2104,7 @@ static void TLan_PrintList( TLanList *list, char *type, int num) { int i; - printk( "TLAN: %s List %d at 0x%08x\n", type, num, (u32) list ); + printk( "TLAN: %s List %d at %p\n", type, num, list ); printk( "TLAN: Forward = 0x%08x\n", list->forward ); printk( "TLAN: CSTAT = 0x%04hx\n", list->cStat ); printk( "TLAN: Frame Size = 0x%04hx\n", list->frameSize ); -- cgit v1.2.3-70-g09d2 From 9ded65a1d79a2ca9aa44ee0989fd7924304c31cc Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 30 May 2008 09:49:56 -0700 Subject: tlan: manage rx allocation failure better Rx allocation failure at runtime is non-fatal. For normal Rx frame, it just reuses the buffer, and during setup it just continues with a smaller receive buffer pool. Compile tested only. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/tlan.c | 63 +++++++++++++++++++++++++----------------------------- 1 file changed, 29 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index aee2a458adc..afc831002db 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -1539,8 +1539,6 @@ static u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int ) TLanList *head_list; struct sk_buff *skb; TLanList *tail_list; - void *t; - u32 frameSize; u16 tmpCStat; dma_addr_t head_list_phys; @@ -1549,40 +1547,34 @@ static u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int ) head_list_phys = priv->rxListDMA + sizeof(TLanList) * priv->rxHead; while (((tmpCStat = head_list->cStat) & TLAN_CSTAT_FRM_CMP) && (ack < 255)) { - frameSize = head_list->frameSize; + dma_addr_t frameDma = head_list->buffer[0].address; + u32 frameSize = head_list->frameSize; ack++; if (tmpCStat & TLAN_CSTAT_EOC) eoc = 1; if (bbuf) { - skb = dev_alloc_skb(frameSize + 7); - if (skb == NULL) - printk(KERN_INFO "TLAN: Couldn't allocate memory for received data.\n"); - else { + skb = netdev_alloc_skb(dev, frameSize + 7); + if ( skb ) { head_buffer = priv->rxBuffer + (priv->rxHead * TLAN_MAX_FRAME_SIZE); skb_reserve(skb, 2); - t = (void *) skb_put(skb, frameSize); - - dev->stats.rx_bytes += head_list->frameSize; + pci_dma_sync_single_for_cpu(priv->pciDev, + frameDma, frameSize, + PCI_DMA_FROMDEVICE); + skb_copy_from_linear_data(skb, head_buffer, frameSize); + skb_put(skb, frameSize); + dev->stats.rx_bytes += frameSize; - memcpy( t, head_buffer, frameSize ); skb->protocol = eth_type_trans( skb, dev ); netif_rx( skb ); } } else { struct sk_buff *new_skb; - /* - * I changed the algorithm here. What we now do - * is allocate the new frame. If this fails we - * simply recycle the frame. - */ - - new_skb = dev_alloc_skb( TLAN_MAX_FRAME_SIZE + 7 ); - - if ( new_skb != NULL ) { + new_skb = netdev_alloc_skb(dev, TLAN_MAX_FRAME_SIZE + 7 ); + if ( new_skb ) { skb = TLan_GetSKB(head_list); - pci_unmap_single(priv->pciDev, head_list->buffer[0].address, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE); + pci_unmap_single(priv->pciDev, frameDma, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE); skb_put( skb, frameSize ); dev->stats.rx_bytes += frameSize; @@ -1590,12 +1582,12 @@ static u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int ) skb->protocol = eth_type_trans( skb, dev ); netif_rx( skb ); - skb_reserve( new_skb, 2 ); + skb_reserve( new_skb, NET_IP_ALIGN ); head_list->buffer[0].address = pci_map_single(priv->pciDev, new_skb->data, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE); TLan_StoreSKB(head_list, new_skb); - } else - printk(KERN_WARNING "TLAN: Couldn't allocate memory for received data.\n" ); + } + } head_list->forward = 0; @@ -1994,24 +1986,27 @@ static void TLan_ResetLists( struct net_device *dev ) if ( bbuf ) { list->buffer[0].address = priv->rxBufferDMA + ( i * TLAN_MAX_FRAME_SIZE ); } else { - skb = dev_alloc_skb( TLAN_MAX_FRAME_SIZE + 7 ); - if ( skb == NULL ) { + skb = netdev_alloc_skb(dev, TLAN_MAX_FRAME_SIZE + 7 ); + if ( !skb ) { printk( "TLAN: Couldn't allocate memory for received data.\n" ); - /* If this ever happened it would be a problem */ - } else { - skb->dev = dev; - skb_reserve( skb, 2 ); + break; } + + skb_reserve( skb, NET_IP_ALIGN ); list->buffer[0].address = pci_map_single(priv->pciDev, t, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE); TLan_StoreSKB(list, skb); } list->buffer[1].count = 0; list->buffer[1].address = 0; - if ( i < TLAN_NUM_RX_LISTS - 1 ) - list->forward = list_phys + sizeof(TLanList); - else - list->forward = 0; + list->forward = list_phys + sizeof(TLanList); + } + + /* in case ran out of memory early, clear bits */ + while (i < TLAN_NUM_RX_LISTS) { + TLan_StoreSKB(priv->rxList + i, NULL); + ++i; } + list->forward = 0; } /* TLan_ResetLists */ -- cgit v1.2.3-70-g09d2 From a3ccc78968f00b6589653c1cccadb7940594935a Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 30 May 2008 09:49:57 -0700 Subject: tlan: proper shared IRQ support Handle shared IRQ correctly. If IRQ is shared, it typically will show up as an IRQ with an empty status field. So check in driver and handle it without crapping out with invalid interrupt message. Compile tested only. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/tlan.c | 61 +++++++++++++++--------------------------------------- 1 file changed, 17 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index afc831002db..01aa331e183 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -218,7 +218,7 @@ static int bbuf; module_param(bbuf, int, 0); MODULE_PARM_DESC(bbuf, "ThunderLAN use big buffer (0-1)"); -static char TLanSignature[] = "TLAN"; +static const char TLanSignature[] = "TLAN"; static const char tlan_banner[] = "ThunderLAN driver v1.15\n"; static int tlan_have_pci; static int tlan_have_eisa; @@ -297,7 +297,6 @@ static void TLan_tx_timeout( struct net_device *dev); static void TLan_tx_timeout_work(struct work_struct *work); static int tlan_init_one( struct pci_dev *pdev, const struct pci_device_id *ent); -static u32 TLan_HandleInvalid( struct net_device *, u16 ); static u32 TLan_HandleTxEOF( struct net_device *, u16 ); static u32 TLan_HandleStatOverflow( struct net_device *, u16 ); static u32 TLan_HandleRxEOF( struct net_device *, u16 ); @@ -366,7 +365,7 @@ TLan_GetSKB( const struct tlan_list_tag *tag) static TLanIntVectorFunc *TLanIntVector[TLAN_INT_NUMBER_OF_INTS] = { - TLan_HandleInvalid, + NULL, TLan_HandleTxEOF, TLan_HandleStatOverflow, TLan_HandleRxEOF, @@ -935,7 +934,8 @@ static int TLan_Open( struct net_device *dev ) int err; priv->tlanRev = TLan_DioRead8( dev->base_addr, TLAN_DEF_REVISION ); - err = request_irq( dev->irq, TLan_HandleInterrupt, IRQF_SHARED, TLanSignature, dev ); + err = request_irq( dev->irq, TLan_HandleInterrupt, IRQF_SHARED, + dev->name, dev ); if ( err ) { printk(KERN_ERR "TLAN: Cannot open %s because IRQ %d is already in use.\n", dev->name, dev->irq ); @@ -1167,33 +1167,31 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) static irqreturn_t TLan_HandleInterrupt(int irq, void *dev_id) { - u32 ack; - struct net_device *dev; - u32 host_cmd; + struct net_device *dev = dev_id; + TLanPrivateInfo *priv = netdev_priv(dev); u16 host_int; - int type; - TLanPrivateInfo *priv; - - dev = dev_id; - priv = netdev_priv(dev); + u16 type; spin_lock(&priv->lock); host_int = inw( dev->base_addr + TLAN_HOST_INT ); - outw( host_int, dev->base_addr + TLAN_HOST_INT ); - type = ( host_int & TLAN_HI_IT_MASK ) >> 2; + if ( type ) { + u32 ack; + u32 host_cmd; - ack = TLanIntVector[type]( dev, host_int ); + outw( host_int, dev->base_addr + TLAN_HOST_INT ); + ack = TLanIntVector[type]( dev, host_int ); - if ( ack ) { - host_cmd = TLAN_HC_ACK | ack | ( type << 18 ); - outl( host_cmd, dev->base_addr + TLAN_HOST_CMD ); + if ( ack ) { + host_cmd = TLAN_HC_ACK | ack | ( type << 18 ); + outl( host_cmd, dev->base_addr + TLAN_HOST_CMD ); + } } spin_unlock(&priv->lock); - return IRQ_HANDLED; + return IRQ_RETVAL(type); } /* TLan_HandleInterrupts */ @@ -1359,31 +1357,6 @@ static void TLan_SetMulticastList( struct net_device *dev ) *****************************************************************************/ - /*************************************************************** - * TLan_HandleInvalid - * - * Returns: - * 0 - * Parms: - * dev Device assigned the IRQ that was - * raised. - * host_int The contents of the HOST_INT - * port. - * - * This function handles invalid interrupts. This should - * never happen unless some other adapter is trying to use - * the IRQ line assigned to the device. - * - **************************************************************/ - -static u32 TLan_HandleInvalid( struct net_device *dev, u16 host_int ) -{ - /* printk( "TLAN: Invalid interrupt on %s.\n", dev->name ); */ - return 0; - -} /* TLan_HandleInvalid */ - - /*************************************************************** -- cgit v1.2.3-70-g09d2 From dfc2c0a6db926749bd49101503644bf915f70e45 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 30 May 2008 09:49:58 -0700 Subject: tlan: wrap source lines Make driver more readable on standard 80 col windows. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/tlan.c | 294 ++++++++++++++++++++++++++++++++++------------------- drivers/net/tlan.h | 24 +++-- 2 files changed, 203 insertions(+), 115 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index 01aa331e183..85246ed7cb9 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -13,8 +13,6 @@ * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. * - ** This file is best viewed/edited with columns>=132. - * ** Useful (if not required) reading: * * Texas Instruments, ThunderLAN Programmer's Guide, @@ -236,9 +234,11 @@ static struct board { { "Compaq Netelligent 10 T PCI UTP", TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, { "Compaq Netelligent 10/100 TX PCI UTP", TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, { "Compaq Integrated NetFlex-3/P", TLAN_ADAPTER_NONE, 0x83 }, - { "Compaq NetFlex-3/P", TLAN_ADAPTER_UNMANAGED_PHY | TLAN_ADAPTER_BIT_RATE_PHY, 0x83 }, + { "Compaq NetFlex-3/P", + TLAN_ADAPTER_UNMANAGED_PHY | TLAN_ADAPTER_BIT_RATE_PHY, 0x83 }, { "Compaq NetFlex-3/P", TLAN_ADAPTER_NONE, 0x83 }, - { "Compaq Netelligent Integrated 10/100 TX UTP", TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, + { "Compaq Netelligent Integrated 10/100 TX UTP", + TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, { "Compaq Netelligent Dual 10/100 TX PCI UTP", TLAN_ADAPTER_NONE, 0x83 }, { "Compaq Netelligent 10/100 TX Embedded UTP", TLAN_ADAPTER_NONE, 0x83 }, { "Olicom OC-2183/2185", TLAN_ADAPTER_USE_INTERN_10, 0x83 }, @@ -246,8 +246,9 @@ static struct board { { "Olicom OC-2326", TLAN_ADAPTER_USE_INTERN_10, 0xF8 }, { "Compaq Netelligent 10/100 TX UTP", TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, { "Compaq Netelligent 10 T/2 PCI UTP/Coax", TLAN_ADAPTER_NONE, 0x83 }, - { "Compaq NetFlex-3/E", TLAN_ADAPTER_ACTIVITY_LED | /* EISA card */ - TLAN_ADAPTER_UNMANAGED_PHY | TLAN_ADAPTER_BIT_RATE_PHY, 0x83 }, + { "Compaq NetFlex-3/E", + TLAN_ADAPTER_ACTIVITY_LED | /* EISA card */ + TLAN_ADAPTER_UNMANAGED_PHY | TLAN_ADAPTER_BIT_RATE_PHY, 0x83 }, { "Compaq NetFlex-3/E", TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, /* EISA card */ }; @@ -292,7 +293,8 @@ static int TLan_Close( struct net_device *); static struct net_device_stats *TLan_GetStats( struct net_device *); static void TLan_SetMulticastList( struct net_device *); static int TLan_ioctl( struct net_device *dev, struct ifreq *rq, int cmd); -static int TLan_probe1( struct pci_dev *pdev, long ioaddr, int irq, int rev, const struct pci_device_id *ent); +static int TLan_probe1( struct pci_dev *pdev, long ioaddr, + int irq, int rev, const struct pci_device_id *ent); static void TLan_tx_timeout( struct net_device *dev); static void TLan_tx_timeout_work(struct work_struct *work); static int tlan_init_one( struct pci_dev *pdev, const struct pci_device_id *ent); @@ -439,7 +441,9 @@ static void __devexit tlan_remove_one( struct pci_dev *pdev) unregister_netdev( dev ); if ( priv->dmaStorage ) { - pci_free_consistent(priv->pciDev, priv->dmaSize, priv->dmaStorage, priv->dmaStorageDMA ); + pci_free_consistent(priv->pciDev, + priv->dmaSize, priv->dmaStorage, + priv->dmaStorageDMA ); } #ifdef CONFIG_PCI @@ -522,7 +526,8 @@ static int __devinit tlan_init_one( struct pci_dev *pdev, **************************************************************/ static int __devinit TLan_probe1(struct pci_dev *pdev, - long ioaddr, int irq, int rev, const struct pci_device_id *ent ) + long ioaddr, int irq, int rev, + const struct pci_device_id *ent ) { struct net_device *dev; @@ -608,8 +613,10 @@ static int __devinit TLan_probe1(struct pci_dev *pdev, /* Kernel parameters */ if (dev->mem_start) { priv->aui = dev->mem_start & 0x01; - priv->duplex = ((dev->mem_start & 0x06) == 0x06) ? 0 : (dev->mem_start & 0x06) >> 1; - priv->speed = ((dev->mem_start & 0x18) == 0x18) ? 0 : (dev->mem_start & 0x18) >> 3; + priv->duplex = ((dev->mem_start & 0x06) == 0x06) ? 0 + : (dev->mem_start & 0x06) >> 1; + priv->speed = ((dev->mem_start & 0x18) == 0x18) ? 0 + : (dev->mem_start & 0x18) >> 3; if (priv->speed == 0x1) { priv->speed = TLAN_SPEED_10; @@ -689,7 +696,8 @@ static void TLan_Eisa_Cleanup(void) dev = TLan_Eisa_Devices; priv = netdev_priv(dev); if (priv->dmaStorage) { - pci_free_consistent(priv->pciDev, priv->dmaSize, priv->dmaStorage, priv->dmaStorageDMA ); + pci_free_consistent(priv->pciDev, priv->dmaSize, + priv->dmaStorage, priv->dmaStorageDMA ); } release_region( dev->base_addr, 0x10); unregister_netdev( dev ); @@ -744,8 +752,10 @@ static void __init TLan_EisaProbe (void) /* Loop through all slots of the EISA bus */ for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) { - TLAN_DBG(TLAN_DEBUG_PROBE,"EISA_ID 0x%4x: 0x%4x\n", (int) ioaddr + 0xC80, inw(ioaddr + EISA_ID)); - TLAN_DBG(TLAN_DEBUG_PROBE,"EISA_ID 0x%4x: 0x%4x\n", (int) ioaddr + 0xC82, inw(ioaddr + EISA_ID2)); + TLAN_DBG(TLAN_DEBUG_PROBE,"EISA_ID 0x%4x: 0x%4x\n", + (int) ioaddr + 0xC80, inw(ioaddr + EISA_ID)); + TLAN_DBG(TLAN_DEBUG_PROBE,"EISA_ID 0x%4x: 0x%4x\n", + (int) ioaddr + 0xC82, inw(ioaddr + EISA_ID2)); TLAN_DBG(TLAN_DEBUG_PROBE, "Probing for EISA adapter at IO: 0x%4x : ", @@ -872,9 +882,12 @@ static int TLan_Init( struct net_device *dev ) if ( bbuf ) { priv->rxBuffer = (u8 *) ( priv->txList + TLAN_NUM_TX_LISTS ); - priv->rxBufferDMA =priv->txListDMA + sizeof(TLanList) * TLAN_NUM_TX_LISTS; - priv->txBuffer = priv->rxBuffer + ( TLAN_NUM_RX_LISTS * TLAN_MAX_FRAME_SIZE ); - priv->txBufferDMA = priv->rxBufferDMA + ( TLAN_NUM_RX_LISTS * TLAN_MAX_FRAME_SIZE ); + priv->rxBufferDMA =priv->txListDMA + + sizeof(TLanList) * TLAN_NUM_TX_LISTS; + priv->txBuffer = priv->rxBuffer + + ( TLAN_NUM_RX_LISTS * TLAN_MAX_FRAME_SIZE ); + priv->txBufferDMA = priv->rxBufferDMA + + ( TLAN_NUM_RX_LISTS * TLAN_MAX_FRAME_SIZE ); } err = 0; @@ -938,7 +951,8 @@ static int TLan_Open( struct net_device *dev ) dev->name, dev ); if ( err ) { - printk(KERN_ERR "TLAN: Cannot open %s because IRQ %d is already in use.\n", dev->name, dev->irq ); + pr_err("TLAN: Cannot open %s because IRQ %d is already in use.\n", + dev->name, dev->irq ); return err; } @@ -952,7 +966,8 @@ static int TLan_Open( struct net_device *dev ) TLan_ReadAndClearStats( dev, TLAN_IGNORE ); TLan_ResetAdapter( dev ); - TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Opened. TLAN Chip Rev: %x\n", dev->name, priv->tlanRev ); + TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Opened. TLAN Chip Rev: %x\n", + dev->name, priv->tlanRev ); return 0; @@ -990,14 +1005,16 @@ static int TLan_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) case SIOCGMIIREG: /* Read MII PHY register. */ - TLan_MiiReadReg(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, &data->val_out); + TLan_MiiReadReg(dev, data->phy_id & 0x1f, + data->reg_num & 0x1f, &data->val_out); return 0; case SIOCSMIIREG: /* Write MII PHY register. */ if (!capable(CAP_NET_ADMIN)) return -EPERM; - TLan_MiiWriteReg(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); + TLan_MiiWriteReg(dev, data->phy_id & 0x1f, + data->reg_num & 0x1f, data->val_in); return 0; default: return -EOPNOTSUPP; @@ -1082,7 +1099,8 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) unsigned long flags; if ( ! priv->phyOnline ) { - TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s PHY is not ready\n", dev->name ); + TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s PHY is not ready\n", + dev->name ); dev_kfree_skb_any(skb); return 0; } @@ -1094,7 +1112,9 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) tail_list_phys = priv->txListDMA + sizeof(TLanList) * priv->txTail; if ( tail_list->cStat != TLAN_CSTAT_UNUSED ) { - TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s is busy (Head=%d Tail=%d)\n", dev->name, priv->txHead, priv->txTail ); + TLAN_DBG( TLAN_DEBUG_TX, + "TRANSMIT: %s is busy (Head=%d Tail=%d)\n", + dev->name, priv->txHead, priv->txTail ); netif_stop_queue(dev); priv->txBusyCount++; return 1; @@ -1106,7 +1126,9 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) tail_buffer = priv->txBuffer + ( priv->txTail * TLAN_MAX_FRAME_SIZE ); skb_copy_from_linear_data(skb, tail_buffer, skb->len); } else { - tail_list->buffer[0].address = pci_map_single(priv->pciDev, skb->data, skb->len, PCI_DMA_TODEVICE); + tail_list->buffer[0].address = pci_map_single(priv->pciDev, + skb->data, skb->len, + PCI_DMA_TODEVICE); TLan_StoreSKB(tail_list, skb); } @@ -1119,15 +1141,19 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) tail_list->cStat = TLAN_CSTAT_READY; if ( ! priv->txInProgress ) { priv->txInProgress = 1; - TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Starting TX on buffer %d\n", priv->txTail ); + TLAN_DBG( TLAN_DEBUG_TX, + "TRANSMIT: Starting TX on buffer %d\n", priv->txTail ); outl( tail_list_phys, dev->base_addr + TLAN_CH_PARM ); outl( TLAN_HC_GO, dev->base_addr + TLAN_HOST_CMD ); } else { - TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Adding buffer %d to TX channel\n", priv->txTail ); + TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Adding buffer %d to TX channel\n", + priv->txTail ); if ( priv->txTail == 0 ) { - ( priv->txList + ( TLAN_NUM_TX_LISTS - 1 ) )->forward = tail_list_phys; + ( priv->txList + ( TLAN_NUM_TX_LISTS - 1 ) )->forward + = tail_list_phys; } else { - ( priv->txList + ( priv->txTail - 1 ) )->forward = tail_list_phys; + ( priv->txList + ( priv->txTail - 1 ) )->forward + = tail_list_phys; } } spin_unlock_irqrestore(&priv->lock, flags); @@ -1260,8 +1286,10 @@ static struct net_device_stats *TLan_GetStats( struct net_device *dev ) /* Should only read stats if open ? */ TLan_ReadAndClearStats( dev, TLAN_RECORD ); - TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: %s EOC count = %d\n", dev->name, priv->rxEocCount ); - TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s Busy count = %d\n", dev->name, priv->txBusyCount ); + TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: %s EOC count = %d\n", dev->name, + priv->rxEocCount ); + TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s Busy count = %d\n", dev->name, + priv->txBusyCount ); if ( debug & TLAN_DEBUG_GNRL ) { TLan_PrintDio( dev->base_addr ); TLan_PhyPrint( dev ); @@ -1311,10 +1339,12 @@ static void TLan_SetMulticastList( struct net_device *dev ) if ( dev->flags & IFF_PROMISC ) { tmp = TLan_DioRead8( dev->base_addr, TLAN_NET_CMD ); - TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, tmp | TLAN_NET_CMD_CAF ); + TLan_DioWrite8( dev->base_addr, + TLAN_NET_CMD, tmp | TLAN_NET_CMD_CAF ); } else { tmp = TLan_DioRead8( dev->base_addr, TLAN_NET_CMD ); - TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, tmp & ~TLAN_NET_CMD_CAF ); + TLan_DioWrite8( dev->base_addr, + TLAN_NET_CMD, tmp & ~TLAN_NET_CMD_CAF ); if ( dev->flags & IFF_ALLMULTI ) { for ( i = 0; i < 3; i++ ) TLan_SetMac( dev, i + 1, NULL ); @@ -1323,7 +1353,8 @@ static void TLan_SetMulticastList( struct net_device *dev ) } else { for ( i = 0; i < dev->mc_count; i++ ) { if ( i < 3 ) { - TLan_SetMac( dev, i + 1, (char *) &dmi->dmi_addr ); + TLan_SetMac( dev, i + 1, + (char *) &dmi->dmi_addr ); } else { offset = TLan_HashFunc( (u8 *) &dmi->dmi_addr ); if ( offset < 32 ) @@ -1390,14 +1421,16 @@ static u32 TLan_HandleTxEOF( struct net_device *dev, u16 host_int ) u32 ack = 0; u16 tmpCStat; - TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Handling TX EOF (Head=%d Tail=%d)\n", priv->txHead, priv->txTail ); + TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Handling TX EOF (Head=%d Tail=%d)\n", + priv->txHead, priv->txTail ); head_list = priv->txList + priv->txHead; while (((tmpCStat = head_list->cStat ) & TLAN_CSTAT_FRM_CMP) && (ack < 255)) { ack++; if ( ! bbuf ) { struct sk_buff *skb = TLan_GetSKB(head_list); - pci_unmap_single(priv->pciDev, head_list->buffer[0].address, skb->len, PCI_DMA_TODEVICE); + pci_unmap_single(priv->pciDev, head_list->buffer[0].address, + skb->len, PCI_DMA_TODEVICE); dev_kfree_skb_any(skb); head_list->buffer[8].address = 0; head_list->buffer[9].address = 0; @@ -1418,7 +1451,9 @@ static u32 TLan_HandleTxEOF( struct net_device *dev, u16 host_int ) printk(KERN_INFO "TLAN: Received interrupt for uncompleted TX frame.\n"); if ( eoc ) { - TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Handling TX EOC (Head=%d Tail=%d)\n", priv->txHead, priv->txTail ); + TLAN_DBG( TLAN_DEBUG_TX, + "TRANSMIT: Handling TX EOC (Head=%d Tail=%d)\n", + priv->txHead, priv->txTail ); head_list = priv->txList + priv->txHead; head_list_phys = priv->txListDMA + sizeof(TLanList) * priv->txHead; if ( ( head_list->cStat & TLAN_CSTAT_READY ) == TLAN_CSTAT_READY ) { @@ -1430,7 +1465,8 @@ static u32 TLan_HandleTxEOF( struct net_device *dev, u16 host_int ) } if ( priv->adapter->flags & TLAN_ADAPTER_ACTIVITY_LED ) { - TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT ); + TLan_DioWrite8( dev->base_addr, + TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT ); if ( priv->timer.function == NULL ) { priv->timer.function = &TLan_Timer; priv->timer.data = (unsigned long) dev; @@ -1515,7 +1551,8 @@ static u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int ) u16 tmpCStat; dma_addr_t head_list_phys; - TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: Handling RX EOF (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail ); + TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: Handling RX EOF (Head=%d Tail=%d)\n", + priv->rxHead, priv->rxTail ); head_list = priv->rxList + priv->rxHead; head_list_phys = priv->rxListDMA + sizeof(TLanList) * priv->rxHead; @@ -1528,41 +1565,48 @@ static u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int ) if (bbuf) { skb = netdev_alloc_skb(dev, frameSize + 7); - if ( skb ) { - head_buffer = priv->rxBuffer + (priv->rxHead * TLAN_MAX_FRAME_SIZE); - skb_reserve(skb, 2); - pci_dma_sync_single_for_cpu(priv->pciDev, - frameDma, frameSize, - PCI_DMA_FROMDEVICE); - skb_copy_from_linear_data(skb, head_buffer, frameSize); - skb_put(skb, frameSize); - dev->stats.rx_bytes += frameSize; - - skb->protocol = eth_type_trans( skb, dev ); - netif_rx( skb ); - } + if ( !skb ) + goto drop_and_reuse; + + head_buffer = priv->rxBuffer + + (priv->rxHead * TLAN_MAX_FRAME_SIZE); + skb_reserve(skb, 2); + pci_dma_sync_single_for_cpu(priv->pciDev, + frameDma, frameSize, + PCI_DMA_FROMDEVICE); + skb_copy_from_linear_data(skb, head_buffer, frameSize); + skb_put(skb, frameSize); + dev->stats.rx_bytes += frameSize; + + skb->protocol = eth_type_trans( skb, dev ); + netif_rx( skb ); } else { struct sk_buff *new_skb; new_skb = netdev_alloc_skb(dev, TLAN_MAX_FRAME_SIZE + 7 ); - if ( new_skb ) { - skb = TLan_GetSKB(head_list); - pci_unmap_single(priv->pciDev, frameDma, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE); - skb_put( skb, frameSize ); + if ( !new_skb ) + goto drop_and_reuse; - dev->stats.rx_bytes += frameSize; + skb = TLan_GetSKB(head_list); + pci_unmap_single(priv->pciDev, frameDma, + TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE); + skb_put( skb, frameSize ); - skb->protocol = eth_type_trans( skb, dev ); - netif_rx( skb ); + dev->stats.rx_bytes += frameSize; - skb_reserve( new_skb, NET_IP_ALIGN ); - head_list->buffer[0].address = pci_map_single(priv->pciDev, new_skb->data, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE); + skb->protocol = eth_type_trans( skb, dev ); + netif_rx( skb ); - TLan_StoreSKB(head_list, new_skb); - } + skb_reserve( new_skb, NET_IP_ALIGN ); + head_list->buffer[0].address = pci_map_single(priv->pciDev, + new_skb->data, + TLAN_MAX_FRAME_SIZE, + PCI_DMA_FROMDEVICE); - } + TLan_StoreSKB(head_list, new_skb); + } +drop_and_reuse: head_list->forward = 0; head_list->cStat = 0; tail_list = priv->rxList + priv->rxTail; @@ -1578,10 +1622,10 @@ static u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int ) printk(KERN_INFO "TLAN: Received interrupt for uncompleted RX frame.\n"); - - if ( eoc ) { - TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: Handling RX EOC (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail ); + TLAN_DBG( TLAN_DEBUG_RX, + "RECEIVE: Handling RX EOC (Head=%d Tail=%d)\n", + priv->rxHead, priv->rxTail ); head_list = priv->rxList + priv->rxHead; head_list_phys = priv->rxListDMA + sizeof(TLanList) * priv->rxHead; outl(head_list_phys, dev->base_addr + TLAN_CH_PARM ); @@ -1590,7 +1634,8 @@ static u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int ) } if ( priv->adapter->flags & TLAN_ADAPTER_ACTIVITY_LED ) { - TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT ); + TLan_DioWrite8( dev->base_addr, + TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT ); if ( priv->timer.function == NULL ) { priv->timer.function = &TLan_Timer; priv->timer.data = (unsigned long) dev; @@ -1668,7 +1713,9 @@ static u32 TLan_HandleTxEOC( struct net_device *dev, u16 host_int ) host_int = 0; if ( priv->tlanRev < 0x30 ) { - TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Handling TX EOC (Head=%d Tail=%d) -- IRQ\n", priv->txHead, priv->txTail ); + TLAN_DBG( TLAN_DEBUG_TX, + "TRANSMIT: Handling TX EOC (Head=%d Tail=%d) -- IRQ\n", + priv->txHead, priv->txTail ); head_list = priv->txList + priv->txHead; head_list_phys = priv->txListDMA + sizeof(TLanList) * priv->txHead; if ( ( head_list->cStat & TLAN_CSTAT_READY ) == TLAN_CSTAT_READY ) { @@ -1736,15 +1783,18 @@ static u32 TLan_HandleStatusCheck( struct net_device *dev, u16 host_int ) net_sts = TLan_DioRead8( dev->base_addr, TLAN_NET_STS ); if ( net_sts ) { TLan_DioWrite8( dev->base_addr, TLAN_NET_STS, net_sts ); - TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Net_Sts = %x\n", dev->name, (unsigned) net_sts ); + TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Net_Sts = %x\n", + dev->name, (unsigned) net_sts ); } if ( ( net_sts & TLAN_NET_STS_MIRQ ) && ( priv->phyNum == 0 ) ) { TLan_MiiReadReg( dev, phy, TLAN_TLPHY_STS, &tlphy_sts ); TLan_MiiReadReg( dev, phy, TLAN_TLPHY_CTL, &tlphy_ctl ); - if ( ! ( tlphy_sts & TLAN_TS_POLOK ) && ! ( tlphy_ctl & TLAN_TC_SWAPOL ) ) { + if ( ! ( tlphy_sts & TLAN_TS_POLOK ) && + ! ( tlphy_ctl & TLAN_TC_SWAPOL ) ) { tlphy_ctl |= TLAN_TC_SWAPOL; TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tlphy_ctl); - } else if ( ( tlphy_sts & TLAN_TS_POLOK ) && ( tlphy_ctl & TLAN_TC_SWAPOL ) ) { + } else if ( ( tlphy_sts & TLAN_TS_POLOK ) + && ( tlphy_ctl & TLAN_TC_SWAPOL ) ) { tlphy_ctl &= ~TLAN_TC_SWAPOL; TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tlphy_ctl); } @@ -1789,7 +1839,9 @@ static u32 TLan_HandleRxEOC( struct net_device *dev, u16 host_int ) u32 ack = 1; if ( priv->tlanRev < 0x30 ) { - TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: Handling RX EOC (Head=%d Tail=%d) -- IRQ\n", priv->rxHead, priv->rxTail ); + TLAN_DBG( TLAN_DEBUG_RX, + "RECEIVE: Handling RX EOC (Head=%d Tail=%d) -- IRQ\n", + priv->rxHead, priv->rxTail ); head_list_phys = priv->rxListDMA + sizeof(TLanList) * priv->rxHead; outl( head_list_phys, dev->base_addr + TLAN_CH_PARM ); ack |= TLAN_HC_GO | TLAN_HC_RT; @@ -1880,10 +1932,12 @@ static void TLan_Timer( unsigned long data ) if ( priv->timer.function == NULL ) { elapsed = jiffies - priv->timerSetAt; if ( elapsed >= TLAN_TIMER_ACT_DELAY ) { - TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK ); + TLan_DioWrite8( dev->base_addr, + TLAN_LED_REG, TLAN_LED_LINK ); } else { priv->timer.function = &TLan_Timer; - priv->timer.expires = priv->timerSetAt + TLAN_TIMER_ACT_DELAY; + priv->timer.expires = priv->timerSetAt + + TLAN_TIMER_ACT_DELAY; spin_unlock_irqrestore(&priv->lock, flags); add_timer( &priv->timer ); break; @@ -1938,7 +1992,8 @@ static void TLan_ResetLists( struct net_device *dev ) list = priv->txList + i; list->cStat = TLAN_CSTAT_UNUSED; if ( bbuf ) { - list->buffer[0].address = priv->txBufferDMA + ( i * TLAN_MAX_FRAME_SIZE ); + list->buffer[0].address = priv->txBufferDMA + + ( i * TLAN_MAX_FRAME_SIZE ); } else { list->buffer[0].address = 0; } @@ -1957,16 +2012,19 @@ static void TLan_ResetLists( struct net_device *dev ) list->frameSize = TLAN_MAX_FRAME_SIZE; list->buffer[0].count = TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER; if ( bbuf ) { - list->buffer[0].address = priv->rxBufferDMA + ( i * TLAN_MAX_FRAME_SIZE ); + list->buffer[0].address = priv->rxBufferDMA + + ( i * TLAN_MAX_FRAME_SIZE ); } else { skb = netdev_alloc_skb(dev, TLAN_MAX_FRAME_SIZE + 7 ); if ( !skb ) { - printk( "TLAN: Couldn't allocate memory for received data.\n" ); + pr_err("TLAN: out of memory for received data.\n" ); break; } skb_reserve( skb, NET_IP_ALIGN ); - list->buffer[0].address = pci_map_single(priv->pciDev, t, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE); + list->buffer[0].address = pci_map_single(priv->pciDev, t, + TLAN_MAX_FRAME_SIZE, + PCI_DMA_FROMDEVICE); TLan_StoreSKB(list, skb); } list->buffer[1].count = 0; @@ -1996,7 +2054,9 @@ static void TLan_FreeLists( struct net_device *dev ) list = priv->txList + i; skb = TLan_GetSKB(list); if ( skb ) { - pci_unmap_single(priv->pciDev, list->buffer[0].address, skb->len, PCI_DMA_TODEVICE); + pci_unmap_single(priv->pciDev, + list->buffer[0].address, skb->len, + PCI_DMA_TODEVICE); dev_kfree_skb_any( skb ); list->buffer[8].address = 0; list->buffer[9].address = 0; @@ -2007,7 +2067,10 @@ static void TLan_FreeLists( struct net_device *dev ) list = priv->rxList + i; skb = TLan_GetSKB(list); if ( skb ) { - pci_unmap_single(priv->pciDev, list->buffer[0].address, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE); + pci_unmap_single(priv->pciDev, + list->buffer[0].address, + TLAN_MAX_FRAME_SIZE, + PCI_DMA_FROMDEVICE); dev_kfree_skb_any( skb ); list->buffer[8].address = 0; list->buffer[9].address = 0; @@ -2038,7 +2101,8 @@ static void TLan_PrintDio( u16 io_base ) u32 data0, data1; int i; - printk( "TLAN: Contents of internal registers for io base 0x%04hx.\n", io_base ); + printk( "TLAN: Contents of internal registers for io base 0x%04hx.\n", + io_base ); printk( "TLAN: Off. +0 +4\n" ); for ( i = 0; i < 0x4C; i+= 8 ) { data0 = TLan_DioRead32( io_base, i ); @@ -2078,7 +2142,8 @@ static void TLan_PrintList( TLanList *list, char *type, int num) printk( "TLAN: Frame Size = 0x%04hx\n", list->frameSize ); /* for ( i = 0; i < 10; i++ ) { */ for ( i = 0; i < 2; i++ ) { - printk( "TLAN: Buffer[%d].count, addr = 0x%08x, 0x%08x\n", i, list->buffer[i].count, list->buffer[i].address ); + printk( "TLAN: Buffer[%d].count, addr = 0x%08x, 0x%08x\n", + i, list->buffer[i].count, list->buffer[i].address ); } } /* TLan_PrintList */ @@ -2294,14 +2359,16 @@ TLan_FinishReset( struct net_device *dev ) TLan_MiiReadReg( dev, phy, MII_GEN_ID_HI, &tlphy_id1 ); TLan_MiiReadReg( dev, phy, MII_GEN_ID_LO, &tlphy_id2 ); - if ( ( priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY ) || ( priv->aui ) ) { + if ( ( priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY ) || + ( priv->aui ) ) { status = MII_GS_LINK; printk( "TLAN: %s: Link forced.\n", dev->name ); } else { TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status ); udelay( 1000 ); TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status ); - if ( (status & MII_GS_LINK) && /* We only support link info on Nat.Sem. PHY's */ + if ( (status & MII_GS_LINK) && + /* We only support link info on Nat.Sem. PHY's */ (tlphy_id1 == NAT_SEM_ID1) && (tlphy_id2 == NAT_SEM_ID2) ) { TLan_MiiReadReg( dev, phy, MII_AN_LPA, &partner ); @@ -2310,12 +2377,12 @@ TLan_FinishReset( struct net_device *dev ) printk( "TLAN: %s: Link active with ", dev->name ); if (!(tlphy_par & TLAN_PHY_AN_EN_STAT)) { printk( "forced 10%sMbps %s-Duplex\n", - tlphy_par & TLAN_PHY_SPEED_100 ? "" : "0", - tlphy_par & TLAN_PHY_DUPLEX_FULL ? "Full" : "Half"); + tlphy_par & TLAN_PHY_SPEED_100 ? "" : "0", + tlphy_par & TLAN_PHY_DUPLEX_FULL ? "Full" : "Half"); } else { printk( "AutoNegotiation enabled, at 10%sMbps %s-Duplex\n", - tlphy_par & TLAN_PHY_SPEED_100 ? "" : "0", - tlphy_par & TLAN_PHY_DUPLEX_FULL ? "Full" : "Half"); + tlphy_par & TLAN_PHY_SPEED_100 ? "" : "0", + tlphy_par & TLAN_PHY_DUPLEX_FULL ? "Full" : "Half"); printk("TLAN: Partner capability: "); for (i = 5; i <= 10; i++) if (partner & (1<base_addr + TLAN_HOST_CMD ); netif_carrier_on(dev); } else { - printk( "TLAN: %s: Link inactive, will retry in 10 secs...\n", dev->name ); + printk( "TLAN: %s: Link inactive, will retry in 10 secs...\n", + dev->name ); TLan_SetTimer( dev, (10*HZ), TLAN_TIMER_FINISH_RESET ); return; } @@ -2396,10 +2464,12 @@ static void TLan_SetMac( struct net_device *dev, int areg, char *mac ) if ( mac != NULL ) { for ( i = 0; i < 6; i++ ) - TLan_DioWrite8( dev->base_addr, TLAN_AREG_0 + areg + i, mac[i] ); + TLan_DioWrite8( dev->base_addr, + TLAN_AREG_0 + areg + i, mac[i] ); } else { for ( i = 0; i < 6; i++ ) - TLan_DioWrite8( dev->base_addr, TLAN_AREG_0 + areg + i, 0 ); + TLan_DioWrite8( dev->base_addr, + TLAN_AREG_0 + areg + i, 0 ); } } /* TLan_SetMac */ @@ -2505,9 +2575,13 @@ static void TLan_PhyDetect( struct net_device *dev ) TLan_MiiReadReg( dev, phy, MII_GEN_CTL, &control ); TLan_MiiReadReg( dev, phy, MII_GEN_ID_HI, &hi ); TLan_MiiReadReg( dev, phy, MII_GEN_ID_LO, &lo ); - if ( ( control != 0xFFFF ) || ( hi != 0xFFFF ) || ( lo != 0xFFFF ) ) { - TLAN_DBG( TLAN_DEBUG_GNRL, "PHY found at %02x %04x %04x %04x\n", phy, control, hi, lo ); - if ( ( priv->phy[1] == TLAN_PHY_NONE ) && ( phy != TLAN_PHY_MAX_ADDR ) ) { + if ( ( control != 0xFFFF ) || + ( hi != 0xFFFF ) || ( lo != 0xFFFF ) ) { + TLAN_DBG( TLAN_DEBUG_GNRL, + "PHY found at %02x %04x %04x %04x\n", + phy, control, hi, lo ); + if ( ( priv->phy[1] == TLAN_PHY_NONE ) && + ( phy != TLAN_PHY_MAX_ADDR ) ) { priv->phy[1] = phy; } } @@ -2535,7 +2609,9 @@ static void TLan_PhyPowerDown( struct net_device *dev ) value = MII_GC_PDOWN | MII_GC_LOOPBK | MII_GC_ISOLATE; TLan_MiiSync( dev->base_addr ); TLan_MiiWriteReg( dev, priv->phy[priv->phyNum], MII_GEN_CTL, value ); - if ( ( priv->phyNum == 0 ) && ( priv->phy[1] != TLAN_PHY_NONE ) && ( ! ( priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10 ) ) ) { + if ( ( priv->phyNum == 0 ) && + ( priv->phy[1] != TLAN_PHY_NONE ) && + ( ! ( priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10 ) ) ) { TLan_MiiSync( dev->base_addr ); TLan_MiiWriteReg( dev, priv->phy[1], MII_GEN_CTL, value ); } @@ -2708,10 +2784,10 @@ static void TLan_PhyFinishAutoNeg( struct net_device *dev ) * more time. Perhaps we should fail after a while. */ if (!priv->neg_be_verbose++) { - printk(KERN_INFO "TLAN: Giving autonegotiation more time.\n"); - printk(KERN_INFO "TLAN: Please check that your adapter has\n"); - printk(KERN_INFO "TLAN: been properly connected to a HUB or Switch.\n"); - printk(KERN_INFO "TLAN: Trying to establish link in the background...\n"); + pr_info("TLAN: Giving autonegotiation more time.\n"); + pr_info("TLAN: Please check that your adapter has\n"); + pr_info("TLAN: been properly connected to a HUB or Switch.\n"); + pr_info("TLAN: Trying to establish link in the background...\n"); } TLan_SetTimer( dev, (8*HZ), TLAN_TIMER_PHY_FINISH_AN ); return; @@ -2727,7 +2803,9 @@ static void TLan_PhyFinishAutoNeg( struct net_device *dev ) priv->tlanFullDuplex = TRUE; } - if ( ( ! ( mode & 0x0180 ) ) && ( priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10 ) && ( priv->phyNum != 0 ) ) { + if ( ( ! ( mode & 0x0180 ) ) && + ( priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10 ) && + ( priv->phyNum != 0 ) ) { priv->phyNum = 0; data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN | TLAN_NET_CFG_PHY_EN; TLan_DioWrite16( dev->base_addr, TLAN_NET_CONFIG, data ); @@ -2736,12 +2814,14 @@ static void TLan_PhyFinishAutoNeg( struct net_device *dev ) } if ( priv->phyNum == 0 ) { - if ( ( priv->duplex == TLAN_DUPLEX_FULL ) || ( an_adv & an_lpa & 0x0040 ) ) { - TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, MII_GC_AUTOENB | MII_GC_DUPLEX ); - printk( "TLAN: Starting internal PHY with FULL-DUPLEX\n" ); + if ( ( priv->duplex == TLAN_DUPLEX_FULL ) || + ( an_adv & an_lpa & 0x0040 ) ) { + TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, + MII_GC_AUTOENB | MII_GC_DUPLEX ); + pr_info("TLAN: Starting internal PHY with FULL-DUPLEX\n" ); } else { TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, MII_GC_AUTOENB ); - printk( "TLAN: Starting internal PHY with HALF-DUPLEX\n" ); + pr_info( "TLAN: Starting internal PHY with HALF-DUPLEX\n" ); } } @@ -3149,7 +3229,8 @@ static int TLan_EeSendByte( u16 io_base, u8 data, int stop ) TLan_SetBit( TLAN_NET_SIO_ETXEN, sio ); if ( ( ! err ) && stop ) { - TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); /* STOP, raise data while clock is high */ + /* STOP, raise data while clock is high */ + TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); } @@ -3212,7 +3293,8 @@ static void TLan_EeReceiveByte( u16 io_base, u8 *data, int stop ) TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); /* No ack = 1 (?) */ TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio ); - TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); /* STOP, raise data while clock is high */ + /* STOP, raise data while clock is high */ + TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); } diff --git a/drivers/net/tlan.h b/drivers/net/tlan.h index 2c0abfb0c64..4b82f283e98 100644 --- a/drivers/net/tlan.h +++ b/drivers/net/tlan.h @@ -13,8 +13,6 @@ * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. * - ** This file is best viewed/edited with tabstop=4, colums>=132 - * * * Dec 10, 1999 Torben Mathiasen * New Maintainer @@ -45,7 +43,9 @@ #define TLAN_IGNORE 0 #define TLAN_RECORD 1 -#define TLAN_DBG(lvl, format, args...) if (debug&lvl) printk(KERN_DEBUG "TLAN: " format, ##args ); +#define TLAN_DBG(lvl, format, args...) \ + do { if (debug&lvl) printk(KERN_DEBUG "TLAN: " format, ##args ); } while(0) + #define TLAN_DEBUG_GNRL 0x0001 #define TLAN_DEBUG_TX 0x0002 #define TLAN_DEBUG_RX 0x0004 @@ -515,12 +515,18 @@ static inline void TLan_DioWrite32(u16 base_addr, u16 internal_addr, u32 data) * xor( a, xor( b, xor( c, xor( d, xor( e, xor( f, xor( g, h ) ) ) ) ) ) ) * #define DA( a, bit ) ( ( (u8) a[bit/8] ) & ( (u8) ( 1 << bit%8 ) ) ) * - * hash = XOR8( DA(a,0), DA(a, 6), DA(a,12), DA(a,18), DA(a,24), DA(a,30), DA(a,36), DA(a,42) ); - * hash |= XOR8( DA(a,1), DA(a, 7), DA(a,13), DA(a,19), DA(a,25), DA(a,31), DA(a,37), DA(a,43) ) << 1; - * hash |= XOR8( DA(a,2), DA(a, 8), DA(a,14), DA(a,20), DA(a,26), DA(a,32), DA(a,38), DA(a,44) ) << 2; - * hash |= XOR8( DA(a,3), DA(a, 9), DA(a,15), DA(a,21), DA(a,27), DA(a,33), DA(a,39), DA(a,45) ) << 3; - * hash |= XOR8( DA(a,4), DA(a,10), DA(a,16), DA(a,22), DA(a,28), DA(a,34), DA(a,40), DA(a,46) ) << 4; - * hash |= XOR8( DA(a,5), DA(a,11), DA(a,17), DA(a,23), DA(a,29), DA(a,35), DA(a,41), DA(a,47) ) << 5; + * hash = XOR8( DA(a,0), DA(a, 6), DA(a,12), DA(a,18), DA(a,24), + * DA(a,30), DA(a,36), DA(a,42) ); + * hash |= XOR8( DA(a,1), DA(a, 7), DA(a,13), DA(a,19), DA(a,25), + * DA(a,31), DA(a,37), DA(a,43) ) << 1; + * hash |= XOR8( DA(a,2), DA(a, 8), DA(a,14), DA(a,20), DA(a,26), + * DA(a,32), DA(a,38), DA(a,44) ) << 2; + * hash |= XOR8( DA(a,3), DA(a, 9), DA(a,15), DA(a,21), DA(a,27), + * DA(a,33), DA(a,39), DA(a,45) ) << 3; + * hash |= XOR8( DA(a,4), DA(a,10), DA(a,16), DA(a,22), DA(a,28), + * DA(a,34), DA(a,40), DA(a,46) ) << 4; + * hash |= XOR8( DA(a,5), DA(a,11), DA(a,17), DA(a,23), DA(a,29), + * DA(a,35), DA(a,41), DA(a,47) ) << 5; * */ static inline u32 TLan_HashFunc( const u8 *a ) -- cgit v1.2.3-70-g09d2 From 9e833be3a13aa64e1f3dc50ce0ad95278212511d Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 30 May 2008 10:29:19 -0700 Subject: cxgb3: fix build error when INET=n cxgb3 uses lro_* functions and selects INET_LRO, but this doesn't help unless INET is already enabled, so make the driver depend on INET also. sge.c:(.text+0x9f09a): undefined reference to `lro_flush_all' sge.c:(.text+0x9f62f): undefined reference to `lro_receive_skb' sge.c:(.text+0x9f8a3): undefined reference to `lro_receive_frags' sge.c:(.text+0x9fbe0): undefined reference to `lro_vlan_hwaccel_receive_skb' sge.c:(.text+0x9ffcd): undefined reference to `lro_vlan_hwaccel_receive_frags' Signed-off-by: Randy Dunlap Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 07a91251bca..d415d81b544 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2408,7 +2408,7 @@ config CHELSIO_T1_NAPI config CHELSIO_T3 tristate "Chelsio Communications T3 10Gb Ethernet support" - depends on PCI + depends on PCI && INET select FW_LOADER select INET_LRO help -- cgit v1.2.3-70-g09d2 From 37b5a60335305e46be93c2eb904c8b5be7aba5f6 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 30 May 2008 22:27:04 +0100 Subject: sfc: Use kernel I2C system and i2c-algo-bit driver Remove our own implementation of I2C bit-banging. Signed-off-by: Ben Hutchings Signed-off-by: Jeff Garzik --- drivers/net/sfc/Kconfig | 2 + drivers/net/sfc/Makefile | 2 +- drivers/net/sfc/boards.c | 2 +- drivers/net/sfc/boards.h | 3 +- drivers/net/sfc/efx.c | 2 + drivers/net/sfc/falcon.c | 72 +++++--- drivers/net/sfc/i2c-direct.c | 381 ------------------------------------------- drivers/net/sfc/i2c-direct.h | 91 ----------- drivers/net/sfc/net_driver.h | 11 +- drivers/net/sfc/sfe4001.c | 126 +++++++------- 10 files changed, 133 insertions(+), 559 deletions(-) delete mode 100644 drivers/net/sfc/i2c-direct.c delete mode 100644 drivers/net/sfc/i2c-direct.h (limited to 'drivers') diff --git a/drivers/net/sfc/Kconfig b/drivers/net/sfc/Kconfig index dbad95c295b..3be13b592b4 100644 --- a/drivers/net/sfc/Kconfig +++ b/drivers/net/sfc/Kconfig @@ -4,6 +4,8 @@ config SFC select MII select INET_LRO select CRC32 + select I2C + select I2C_ALGOBIT help This driver supports 10-gigabit Ethernet cards based on the Solarflare Communications Solarstorm SFC4000 controller. diff --git a/drivers/net/sfc/Makefile b/drivers/net/sfc/Makefile index 1d2daeec7ac..c8f5704c8fb 100644 --- a/drivers/net/sfc/Makefile +++ b/drivers/net/sfc/Makefile @@ -1,5 +1,5 @@ sfc-y += efx.o falcon.o tx.o rx.o falcon_xmac.o \ - i2c-direct.o selftest.o ethtool.o xfp_phy.o \ + selftest.o ethtool.o xfp_phy.o \ mdio_10g.o tenxpress.o boards.o sfe4001.o obj-$(CONFIG_SFC) += sfc.o diff --git a/drivers/net/sfc/boards.c b/drivers/net/sfc/boards.c index 7fc0328dc05..d3d3dd0a117 100644 --- a/drivers/net/sfc/boards.c +++ b/drivers/net/sfc/boards.c @@ -109,7 +109,7 @@ static struct efx_board_data board_data[] = { [EFX_BOARD_INVALID] = {NULL, NULL, dummy_init}, [EFX_BOARD_SFE4001] = - {"SFE4001", "10GBASE-T adapter", sfe4001_poweron}, + {"SFE4001", "10GBASE-T adapter", sfe4001_init}, [EFX_BOARD_SFE4002] = {"SFE4002", "XFP adapter", sfe4002_init}, }; diff --git a/drivers/net/sfc/boards.h b/drivers/net/sfc/boards.h index 695764dc2e6..e5e844359ce 100644 --- a/drivers/net/sfc/boards.h +++ b/drivers/net/sfc/boards.h @@ -20,8 +20,7 @@ enum efx_board_type { }; extern int efx_set_board_info(struct efx_nic *efx, u16 revision_info); -extern int sfe4001_poweron(struct efx_nic *efx); -extern void sfe4001_poweroff(struct efx_nic *efx); +extern int sfe4001_init(struct efx_nic *efx); /* Are we putting the PHY into flash config mode */ extern unsigned int sfe4001_phy_flash_cfg; diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 449760642e3..74265d8553b 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -1815,6 +1815,7 @@ static struct efx_board efx_dummy_board_info = { .init = efx_nic_dummy_op_int, .init_leds = efx_port_dummy_op_int, .set_fault_led = efx_port_dummy_op_blink, + .fini = efx_port_dummy_op_void, }; /************************************************************************** @@ -1941,6 +1942,7 @@ static void efx_pci_remove_main(struct efx_nic *efx) efx_fini_port(efx); /* Shutdown the board, then the NIC and board state */ + efx->board_info.fini(efx); falcon_fini_interrupt(efx); efx_fini_napi(efx); diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index d3f749c72d4..8acd53de5e7 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include "net_driver.h" #include "bitfield.h" #include "efx.h" @@ -36,10 +38,12 @@ * struct falcon_nic_data - Falcon NIC state * @next_buffer_table: First available buffer table id * @pci_dev2: The secondary PCI device if present + * @i2c_data: Operations and state for I2C bit-bashing algorithm */ struct falcon_nic_data { unsigned next_buffer_table; struct pci_dev *pci_dev2; + struct i2c_algo_bit_data i2c_data; }; /************************************************************************** @@ -175,39 +179,57 @@ static inline int falcon_event_present(efx_qword_t *event) * ************************************************************************** */ -static void falcon_setsdascl(struct efx_i2c_interface *i2c) +static void falcon_setsda(void *data, int state) { + struct efx_nic *efx = (struct efx_nic *)data; efx_oword_t reg; - falcon_read(i2c->efx, ®, GPIO_CTL_REG_KER); - EFX_SET_OWORD_FIELD(reg, GPIO0_OEN, (i2c->scl ? 0 : 1)); - EFX_SET_OWORD_FIELD(reg, GPIO3_OEN, (i2c->sda ? 0 : 1)); - falcon_write(i2c->efx, ®, GPIO_CTL_REG_KER); + falcon_read(efx, ®, GPIO_CTL_REG_KER); + EFX_SET_OWORD_FIELD(reg, GPIO3_OEN, !state); + falcon_write(efx, ®, GPIO_CTL_REG_KER); } -static int falcon_getsda(struct efx_i2c_interface *i2c) +static void falcon_setscl(void *data, int state) { + struct efx_nic *efx = (struct efx_nic *)data; efx_oword_t reg; - falcon_read(i2c->efx, ®, GPIO_CTL_REG_KER); + falcon_read(efx, ®, GPIO_CTL_REG_KER); + EFX_SET_OWORD_FIELD(reg, GPIO0_OEN, !state); + falcon_write(efx, ®, GPIO_CTL_REG_KER); +} + +static int falcon_getsda(void *data) +{ + struct efx_nic *efx = (struct efx_nic *)data; + efx_oword_t reg; + + falcon_read(efx, ®, GPIO_CTL_REG_KER); return EFX_OWORD_FIELD(reg, GPIO3_IN); } -static int falcon_getscl(struct efx_i2c_interface *i2c) +static int falcon_getscl(void *data) { + struct efx_nic *efx = (struct efx_nic *)data; efx_oword_t reg; - falcon_read(i2c->efx, ®, GPIO_CTL_REG_KER); - return EFX_DWORD_FIELD(reg, GPIO0_IN); + falcon_read(efx, ®, GPIO_CTL_REG_KER); + return EFX_OWORD_FIELD(reg, GPIO0_IN); } -static struct efx_i2c_bit_operations falcon_i2c_bit_operations = { - .setsda = falcon_setsdascl, - .setscl = falcon_setsdascl, +static struct i2c_algo_bit_data falcon_i2c_bit_operations = { + .setsda = falcon_setsda, + .setscl = falcon_setscl, .getsda = falcon_getsda, .getscl = falcon_getscl, .udelay = 100, - .mdelay = 10, + /* + * This is the number of system clock ticks after which + * i2c-algo-bit gives up waiting for SCL to become high. + * It must be at least 2 since the first tick can happen + * immediately after it starts waiting. + */ + .timeout = 2, }; /************************************************************************** @@ -2403,12 +2425,6 @@ int falcon_probe_nic(struct efx_nic *efx) struct falcon_nic_data *nic_data; int rc; - /* Initialise I2C interface state */ - efx->i2c.efx = efx; - efx->i2c.op = &falcon_i2c_bit_operations; - efx->i2c.sda = 1; - efx->i2c.scl = 1; - /* Allocate storage for hardware specific data */ nic_data = kzalloc(sizeof(*nic_data), GFP_KERNEL); efx->nic_data = nic_data; @@ -2459,6 +2475,18 @@ int falcon_probe_nic(struct efx_nic *efx) if (rc) goto fail5; + /* Initialise I2C adapter */ + efx->i2c_adap.owner = THIS_MODULE; + efx->i2c_adap.class = I2C_CLASS_HWMON; + nic_data->i2c_data = falcon_i2c_bit_operations; + nic_data->i2c_data.data = efx; + efx->i2c_adap.algo_data = &nic_data->i2c_data; + efx->i2c_adap.dev.parent = &efx->pci_dev->dev; + strcpy(efx->i2c_adap.name, "SFC4000 GPIO"); + rc = i2c_bit_add_bus(&efx->i2c_adap); + if (rc) + goto fail5; + return 0; fail5: @@ -2633,6 +2661,10 @@ int falcon_init_nic(struct efx_nic *efx) void falcon_remove_nic(struct efx_nic *efx) { struct falcon_nic_data *nic_data = efx->nic_data; + int rc; + + rc = i2c_del_adapter(&efx->i2c_adap); + BUG_ON(rc); falcon_free_buffer(efx, &efx->irq_status); diff --git a/drivers/net/sfc/i2c-direct.c b/drivers/net/sfc/i2c-direct.c deleted file mode 100644 index b6c62d0ed9c..00000000000 --- a/drivers/net/sfc/i2c-direct.c +++ /dev/null @@ -1,381 +0,0 @@ -/**************************************************************************** - * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2005 Fen Systems Ltd. - * Copyright 2006-2008 Solarflare Communications Inc. - * - * 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, incorporated herein by reference. - */ - -#include -#include "net_driver.h" -#include "i2c-direct.h" - -/* - * I2C data (SDA) and clock (SCL) line read/writes with appropriate - * delays. - */ - -static inline void setsda(struct efx_i2c_interface *i2c, int state) -{ - udelay(i2c->op->udelay); - i2c->sda = state; - i2c->op->setsda(i2c); - udelay(i2c->op->udelay); -} - -static inline void setscl(struct efx_i2c_interface *i2c, int state) -{ - udelay(i2c->op->udelay); - i2c->scl = state; - i2c->op->setscl(i2c); - udelay(i2c->op->udelay); -} - -static inline int getsda(struct efx_i2c_interface *i2c) -{ - int sda; - - udelay(i2c->op->udelay); - sda = i2c->op->getsda(i2c); - udelay(i2c->op->udelay); - return sda; -} - -static inline int getscl(struct efx_i2c_interface *i2c) -{ - int scl; - - udelay(i2c->op->udelay); - scl = i2c->op->getscl(i2c); - udelay(i2c->op->udelay); - return scl; -} - -/* - * I2C low-level protocol operations - * - */ - -static inline void i2c_release(struct efx_i2c_interface *i2c) -{ - EFX_WARN_ON_PARANOID(!i2c->scl); - EFX_WARN_ON_PARANOID(!i2c->sda); - /* Devices may time out if operations do not end */ - setscl(i2c, 1); - setsda(i2c, 1); - EFX_BUG_ON_PARANOID(getsda(i2c) != 1); - EFX_BUG_ON_PARANOID(getscl(i2c) != 1); -} - -static inline void i2c_start(struct efx_i2c_interface *i2c) -{ - /* We may be restarting immediately after a {send,recv}_bit, - * so SCL will not necessarily already be high. - */ - EFX_WARN_ON_PARANOID(!i2c->sda); - setscl(i2c, 1); - setsda(i2c, 0); - setscl(i2c, 0); - setsda(i2c, 1); -} - -static inline void i2c_send_bit(struct efx_i2c_interface *i2c, int bit) -{ - EFX_WARN_ON_PARANOID(i2c->scl != 0); - setsda(i2c, bit); - setscl(i2c, 1); - setscl(i2c, 0); - setsda(i2c, 1); -} - -static inline int i2c_recv_bit(struct efx_i2c_interface *i2c) -{ - int bit; - - EFX_WARN_ON_PARANOID(i2c->scl != 0); - EFX_WARN_ON_PARANOID(!i2c->sda); - setscl(i2c, 1); - bit = getsda(i2c); - setscl(i2c, 0); - return bit; -} - -static inline void i2c_stop(struct efx_i2c_interface *i2c) -{ - EFX_WARN_ON_PARANOID(i2c->scl != 0); - setsda(i2c, 0); - setscl(i2c, 1); - setsda(i2c, 1); -} - -/* - * I2C mid-level protocol operations - * - */ - -/* Sends a byte via the I2C bus and checks for an acknowledgement from - * the slave device. - */ -static int i2c_send_byte(struct efx_i2c_interface *i2c, u8 byte) -{ - int i; - - /* Send byte */ - for (i = 0; i < 8; i++) { - i2c_send_bit(i2c, !!(byte & 0x80)); - byte <<= 1; - } - - /* Check for acknowledgement from slave */ - return (i2c_recv_bit(i2c) == 0 ? 0 : -EIO); -} - -/* Receives a byte via the I2C bus and sends ACK/NACK to the slave device. */ -static u8 i2c_recv_byte(struct efx_i2c_interface *i2c, int ack) -{ - u8 value = 0; - int i; - - /* Receive byte */ - for (i = 0; i < 8; i++) - value = (value << 1) | i2c_recv_bit(i2c); - - /* Send ACK/NACK */ - i2c_send_bit(i2c, (ack ? 0 : 1)); - - return value; -} - -/* Calculate command byte for a read operation */ -static inline u8 i2c_read_cmd(u8 device_id) -{ - return ((device_id << 1) | 1); -} - -/* Calculate command byte for a write operation */ -static inline u8 i2c_write_cmd(u8 device_id) -{ - return ((device_id << 1) | 0); -} - -int efx_i2c_check_presence(struct efx_i2c_interface *i2c, u8 device_id) -{ - int rc; - - /* If someone is driving the bus low we just give up. */ - if (getsda(i2c) == 0 || getscl(i2c) == 0) { - EFX_ERR(i2c->efx, "%s someone is holding the I2C bus low." - " Giving up.\n", __func__); - return -EFAULT; - } - - /* Pretend to initiate a device write */ - i2c_start(i2c); - rc = i2c_send_byte(i2c, i2c_write_cmd(device_id)); - if (rc) - goto out; - - out: - i2c_stop(i2c); - i2c_release(i2c); - - return rc; -} - -/* This performs a fast read of one or more consecutive bytes from an - * I2C device. Not all devices support consecutive reads of more than - * one byte; for these devices use efx_i2c_read() instead. - */ -int efx_i2c_fast_read(struct efx_i2c_interface *i2c, - u8 device_id, u8 offset, u8 *data, unsigned int len) -{ - int i; - int rc; - - EFX_WARN_ON_PARANOID(getsda(i2c) != 1); - EFX_WARN_ON_PARANOID(getscl(i2c) != 1); - EFX_WARN_ON_PARANOID(data == NULL); - EFX_WARN_ON_PARANOID(len < 1); - - /* Select device and starting offset */ - i2c_start(i2c); - rc = i2c_send_byte(i2c, i2c_write_cmd(device_id)); - if (rc) - goto out; - rc = i2c_send_byte(i2c, offset); - if (rc) - goto out; - - /* Read data from device */ - i2c_start(i2c); - rc = i2c_send_byte(i2c, i2c_read_cmd(device_id)); - if (rc) - goto out; - for (i = 0; i < (len - 1); i++) - /* Read and acknowledge all but the last byte */ - data[i] = i2c_recv_byte(i2c, 1); - /* Read last byte with no acknowledgement */ - data[i] = i2c_recv_byte(i2c, 0); - - out: - i2c_stop(i2c); - i2c_release(i2c); - - return rc; -} - -/* This performs a fast write of one or more consecutive bytes to an - * I2C device. Not all devices support consecutive writes of more - * than one byte; for these devices use efx_i2c_write() instead. - */ -int efx_i2c_fast_write(struct efx_i2c_interface *i2c, - u8 device_id, u8 offset, - const u8 *data, unsigned int len) -{ - int i; - int rc; - - EFX_WARN_ON_PARANOID(getsda(i2c) != 1); - EFX_WARN_ON_PARANOID(getscl(i2c) != 1); - EFX_WARN_ON_PARANOID(len < 1); - - /* Select device and starting offset */ - i2c_start(i2c); - rc = i2c_send_byte(i2c, i2c_write_cmd(device_id)); - if (rc) - goto out; - rc = i2c_send_byte(i2c, offset); - if (rc) - goto out; - - /* Write data to device */ - for (i = 0; i < len; i++) { - rc = i2c_send_byte(i2c, data[i]); - if (rc) - goto out; - } - - out: - i2c_stop(i2c); - i2c_release(i2c); - - return rc; -} - -/* I2C byte-by-byte read */ -int efx_i2c_read(struct efx_i2c_interface *i2c, - u8 device_id, u8 offset, u8 *data, unsigned int len) -{ - int rc; - - /* i2c_fast_read with length 1 is a single byte read */ - for (; len > 0; offset++, data++, len--) { - rc = efx_i2c_fast_read(i2c, device_id, offset, data, 1); - if (rc) - return rc; - } - - return 0; -} - -/* I2C byte-by-byte write */ -int efx_i2c_write(struct efx_i2c_interface *i2c, - u8 device_id, u8 offset, const u8 *data, unsigned int len) -{ - int rc; - - /* i2c_fast_write with length 1 is a single byte write */ - for (; len > 0; offset++, data++, len--) { - rc = efx_i2c_fast_write(i2c, device_id, offset, data, 1); - if (rc) - return rc; - mdelay(i2c->op->mdelay); - } - - return 0; -} - - -/* This is just a slightly neater wrapper round efx_i2c_fast_write - * in the case where the target doesn't take an offset - */ -int efx_i2c_send_bytes(struct efx_i2c_interface *i2c, - u8 device_id, const u8 *data, unsigned int len) -{ - return efx_i2c_fast_write(i2c, device_id, data[0], data + 1, len - 1); -} - -/* I2C receiving of bytes - does not send an offset byte */ -int efx_i2c_recv_bytes(struct efx_i2c_interface *i2c, u8 device_id, - u8 *bytes, unsigned int len) -{ - int i; - int rc; - - EFX_WARN_ON_PARANOID(getsda(i2c) != 1); - EFX_WARN_ON_PARANOID(getscl(i2c) != 1); - EFX_WARN_ON_PARANOID(len < 1); - - /* Select device */ - i2c_start(i2c); - - /* Read data from device */ - rc = i2c_send_byte(i2c, i2c_read_cmd(device_id)); - if (rc) - goto out; - - for (i = 0; i < (len - 1); i++) - /* Read and acknowledge all but the last byte */ - bytes[i] = i2c_recv_byte(i2c, 1); - /* Read last byte with no acknowledgement */ - bytes[i] = i2c_recv_byte(i2c, 0); - - out: - i2c_stop(i2c); - i2c_release(i2c); - - return rc; -} - -/* SMBus and some I2C devices will time out if the I2C clock is - * held low for too long. This is most likely to happen in virtualised - * systems (when the entire domain is descheduled) but could in - * principle happen due to preemption on any busy system (and given the - * potential length of an I2C operation turning preemption off is not - * a sensible option). The following functions deal with the failure by - * retrying up to a fixed number of times. - */ - -#define I2C_MAX_RETRIES (10) - -/* The timeout problem will result in -EIO. If the wrapped function - * returns any other error, pass this up and do not retry. */ -#define RETRY_WRAPPER(_f) \ - int retries = I2C_MAX_RETRIES; \ - int rc; \ - while (retries) { \ - rc = _f; \ - if (rc != -EIO) \ - return rc; \ - retries--; \ - } \ - return rc; \ - -int efx_i2c_check_presence_retry(struct efx_i2c_interface *i2c, u8 device_id) -{ - RETRY_WRAPPER(efx_i2c_check_presence(i2c, device_id)) -} - -int efx_i2c_read_retry(struct efx_i2c_interface *i2c, - u8 device_id, u8 offset, u8 *data, unsigned int len) -{ - RETRY_WRAPPER(efx_i2c_read(i2c, device_id, offset, data, len)) -} - -int efx_i2c_write_retry(struct efx_i2c_interface *i2c, - u8 device_id, u8 offset, const u8 *data, unsigned int len) -{ - RETRY_WRAPPER(efx_i2c_write(i2c, device_id, offset, data, len)) -} diff --git a/drivers/net/sfc/i2c-direct.h b/drivers/net/sfc/i2c-direct.h deleted file mode 100644 index 291e561071f..00000000000 --- a/drivers/net/sfc/i2c-direct.h +++ /dev/null @@ -1,91 +0,0 @@ -/**************************************************************************** - * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2005 Fen Systems Ltd. - * Copyright 2006 Solarflare Communications Inc. - * - * 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, incorporated herein by reference. - */ - -#ifndef EFX_I2C_DIRECT_H -#define EFX_I2C_DIRECT_H - -#include "net_driver.h" - -/* - * Direct control of an I2C bus - */ - -struct efx_i2c_interface; - -/** - * struct efx_i2c_bit_operations - I2C bus direct control methods - * - * I2C bus direct control methods. - * - * @setsda: Set state of SDA line - * @setscl: Set state of SCL line - * @getsda: Get state of SDA line - * @getscl: Get state of SCL line - * @udelay: Delay between each bit operation - * @mdelay: Delay between each byte write - */ -struct efx_i2c_bit_operations { - void (*setsda) (struct efx_i2c_interface *i2c); - void (*setscl) (struct efx_i2c_interface *i2c); - int (*getsda) (struct efx_i2c_interface *i2c); - int (*getscl) (struct efx_i2c_interface *i2c); - unsigned int udelay; - unsigned int mdelay; -}; - -/** - * struct efx_i2c_interface - an I2C interface - * - * An I2C interface. - * - * @efx: Attached Efx NIC - * @op: I2C bus control methods - * @sda: Current output state of SDA line - * @scl: Current output state of SCL line - */ -struct efx_i2c_interface { - struct efx_nic *efx; - struct efx_i2c_bit_operations *op; - unsigned int sda:1; - unsigned int scl:1; -}; - -extern int efx_i2c_check_presence(struct efx_i2c_interface *i2c, u8 device_id); -extern int efx_i2c_fast_read(struct efx_i2c_interface *i2c, - u8 device_id, u8 offset, - u8 *data, unsigned int len); -extern int efx_i2c_fast_write(struct efx_i2c_interface *i2c, - u8 device_id, u8 offset, - const u8 *data, unsigned int len); -extern int efx_i2c_read(struct efx_i2c_interface *i2c, - u8 device_id, u8 offset, u8 *data, unsigned int len); -extern int efx_i2c_write(struct efx_i2c_interface *i2c, - u8 device_id, u8 offset, - const u8 *data, unsigned int len); - -extern int efx_i2c_send_bytes(struct efx_i2c_interface *i2c, u8 device_id, - const u8 *bytes, unsigned int len); - -extern int efx_i2c_recv_bytes(struct efx_i2c_interface *i2c, u8 device_id, - u8 *bytes, unsigned int len); - - -/* Versions of the API that retry on failure. */ -extern int efx_i2c_check_presence_retry(struct efx_i2c_interface *i2c, - u8 device_id); - -extern int efx_i2c_read_retry(struct efx_i2c_interface *i2c, - u8 device_id, u8 offset, u8 *data, unsigned int len); - -extern int efx_i2c_write_retry(struct efx_i2c_interface *i2c, - u8 device_id, u8 offset, - const u8 *data, unsigned int len); - -#endif /* EFX_I2C_DIRECT_H */ diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 5e20e7551da..d803b86c647 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -26,10 +26,10 @@ #include #include #include +#include #include "enum.h" #include "bitfield.h" -#include "i2c-direct.h" #define EFX_MAX_LRO_DESCRIPTORS 8 #define EFX_MAX_LRO_AGGR MAX_SKB_FRAGS @@ -418,7 +418,10 @@ struct efx_blinker { * @init_leds: Sets up board LEDs * @set_fault_led: Turns the fault LED on or off * @blink: Starts/stops blinking + * @fini: Cleanup function * @blinker: used to blink LEDs in software + * @hwmon_client: I2C client for hardware monitor + * @ioexp_client: I2C client for power/port control */ struct efx_board { int type; @@ -431,7 +434,9 @@ struct efx_board { int (*init_leds)(struct efx_nic *efx); void (*set_fault_led) (struct efx_nic *efx, int state); void (*blink) (struct efx_nic *efx, int start); + void (*fini) (struct efx_nic *nic); struct efx_blinker blinker; + struct i2c_client *hwmon_client, *ioexp_client; }; #define STRING_TABLE_LOOKUP(val, member) \ @@ -618,7 +623,7 @@ union efx_multicast_hash { * @membase: Memory BAR value * @biu_lock: BIU (bus interface unit) lock * @interrupt_mode: Interrupt mode - * @i2c: I2C interface + * @i2c_adap: I2C adapter * @board_info: Board-level information * @state: Device state flag. Serialised by the rtnl_lock. * @reset_pending: Pending reset method (normally RESET_TYPE_NONE) @@ -686,7 +691,7 @@ struct efx_nic { spinlock_t biu_lock; enum efx_int_mode interrupt_mode; - struct efx_i2c_interface i2c; + struct i2c_adapter i2c_adap; struct efx_board board_info; enum nic_state state; diff --git a/drivers/net/sfc/sfe4001.c b/drivers/net/sfc/sfe4001.c index 66a0d1442ab..b2784952399 100644 --- a/drivers/net/sfc/sfe4001.c +++ b/drivers/net/sfc/sfe4001.c @@ -106,28 +106,27 @@ static const u8 xgphy_max_temperature = 90; -void sfe4001_poweroff(struct efx_nic *efx) +static void sfe4001_poweroff(struct efx_nic *efx) { - struct efx_i2c_interface *i2c = &efx->i2c; + struct i2c_client *ioexp_client = efx->board_info.ioexp_client; + struct i2c_client *hwmon_client = efx->board_info.hwmon_client; - u8 cfg, out, in; + /* Turn off all power rails and disable outputs */ + i2c_smbus_write_byte_data(ioexp_client, P0_OUT, 0xff); + i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG, 0xff); + i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0xff); - EFX_INFO(efx, "%s\n", __func__); - - /* Turn off all power rails */ - out = 0xff; - efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1); - - /* Disable port 1 outputs on IO expander */ - cfg = 0xff; - efx_i2c_write(i2c, PCA9539, P1_CONFIG, &cfg, 1); + /* Clear any over-temperature alert */ + i2c_smbus_read_byte_data(hwmon_client, RSL); +} - /* Disable port 0 outputs on IO expander */ - cfg = 0xff; - efx_i2c_write(i2c, PCA9539, P0_CONFIG, &cfg, 1); +static void sfe4001_fini(struct efx_nic *efx) +{ + EFX_INFO(efx, "%s\n", __func__); - /* Clear any over-temperature alert */ - efx_i2c_read(i2c, MAX6647, RSL, &in, 1); + sfe4001_poweroff(efx); + i2c_unregister_device(efx->board_info.ioexp_client); + i2c_unregister_device(efx->board_info.hwmon_client); } /* The P0_EN_3V3X line on SFE4001 boards (from A2 onward) is connected @@ -143,14 +142,26 @@ MODULE_PARM_DESC(phy_flash_cfg, * be turned on before the PHY can be used. * Context: Process context, rtnl lock held */ -int sfe4001_poweron(struct efx_nic *efx) +int sfe4001_init(struct efx_nic *efx) { - struct efx_i2c_interface *i2c = &efx->i2c; + struct i2c_client *hwmon_client, *ioexp_client; unsigned int count; int rc; - u8 out, in, cfg; + u8 out; efx_dword_t reg; + hwmon_client = i2c_new_dummy(&efx->i2c_adap, MAX6647); + if (!hwmon_client) + return -EIO; + efx->board_info.hwmon_client = hwmon_client; + + ioexp_client = i2c_new_dummy(&efx->i2c_adap, PCA9539); + if (!ioexp_client) { + rc = -EIO; + goto fail_hwmon; + } + efx->board_info.ioexp_client = ioexp_client; + /* 10Xpress has fixed-function LED pins, so there is no board-specific * blink code. */ efx->board_info.blink = tenxpress_phy_blink; @@ -166,44 +177,45 @@ int sfe4001_poweron(struct efx_nic *efx) falcon_xmac_writel(efx, ®, XX_PWR_RST_REG_MAC); udelay(10); + efx->board_info.fini = sfe4001_fini; + /* Set DSP over-temperature alert threshold */ EFX_INFO(efx, "DSP cut-out at %dC\n", xgphy_max_temperature); - rc = efx_i2c_write(i2c, MAX6647, WLHO, - &xgphy_max_temperature, 1); + rc = i2c_smbus_write_byte_data(hwmon_client, WLHO, + xgphy_max_temperature); if (rc) - goto fail1; + goto fail_ioexp; /* Read it back and verify */ - rc = efx_i2c_read(i2c, MAX6647, RLHN, &in, 1); - if (rc) - goto fail1; - if (in != xgphy_max_temperature) { + rc = i2c_smbus_read_byte_data(hwmon_client, RLHN); + if (rc < 0) + goto fail_ioexp; + if (rc != xgphy_max_temperature) { rc = -EFAULT; - goto fail1; + goto fail_ioexp; } /* Clear any previous over-temperature alert */ - rc = efx_i2c_read(i2c, MAX6647, RSL, &in, 1); - if (rc) - goto fail1; + rc = i2c_smbus_read_byte_data(hwmon_client, RSL); + if (rc < 0) + goto fail_ioexp; /* Enable port 0 and port 1 outputs on IO expander */ - cfg = 0x00; - rc = efx_i2c_write(i2c, PCA9539, P0_CONFIG, &cfg, 1); + rc = i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0x00); if (rc) - goto fail1; - cfg = 0xff & ~(1 << P1_SPARE_LBN); - rc = efx_i2c_write(i2c, PCA9539, P1_CONFIG, &cfg, 1); + goto fail_ioexp; + rc = i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG, + 0xff & ~(1 << P1_SPARE_LBN)); if (rc) - goto fail2; + goto fail_on; /* Turn all power off then wait 1 sec. This ensures PHY is reset */ out = 0xff & ~((0 << P0_EN_1V2_LBN) | (0 << P0_EN_2V5_LBN) | (0 << P0_EN_3V3X_LBN) | (0 << P0_EN_5V_LBN) | (0 << P0_EN_1V0X_LBN)); - rc = efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1); + rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out); if (rc) - goto fail3; + goto fail_on; schedule_timeout_uninterruptible(HZ); count = 0; @@ -215,26 +227,26 @@ int sfe4001_poweron(struct efx_nic *efx) if (sfe4001_phy_flash_cfg) out |= 1 << P0_EN_3V3X_LBN; - rc = efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1); + rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out); if (rc) - goto fail3; + goto fail_on; msleep(10); /* Turn on 1V power rail */ out &= ~(1 << P0_EN_1V0X_LBN); - rc = efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1); + rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out); if (rc) - goto fail3; + goto fail_on; EFX_INFO(efx, "waiting for power (attempt %d)...\n", count); schedule_timeout_uninterruptible(HZ); /* Check DSP is powered */ - rc = efx_i2c_read(i2c, PCA9539, P1_IN, &in, 1); - if (rc) - goto fail3; - if (in & (1 << P1_AFE_PWD_LBN)) + rc = i2c_smbus_read_byte_data(ioexp_client, P1_IN); + if (rc < 0) + goto fail_on; + if (rc & (1 << P1_AFE_PWD_LBN)) goto done; /* DSP doesn't look powered in flash config mode */ @@ -244,23 +256,17 @@ int sfe4001_poweron(struct efx_nic *efx) EFX_INFO(efx, "timed out waiting for power\n"); rc = -ETIMEDOUT; - goto fail3; + goto fail_on; done: EFX_INFO(efx, "PHY is powered on\n"); return 0; -fail3: - /* Turn off all power rails */ - out = 0xff; - efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1); - /* Disable port 1 outputs on IO expander */ - out = 0xff; - efx_i2c_write(i2c, PCA9539, P1_CONFIG, &out, 1); -fail2: - /* Disable port 0 outputs on IO expander */ - out = 0xff; - efx_i2c_write(i2c, PCA9539, P0_CONFIG, &out, 1); -fail1: +fail_on: + sfe4001_poweroff(efx); +fail_ioexp: + i2c_unregister_device(ioexp_client); +fail_hwmon: + i2c_unregister_device(hwmon_client); return rc; } -- cgit v1.2.3-70-g09d2 From 62c78329581e76347e1078b8ea996b603be3efec Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 30 May 2008 22:27:46 +0100 Subject: sfc: Reduce I2C udelay to 5 resulting in a clock frequency of 100 kHz Signed-off-by: Ben Hutchings Signed-off-by: Jeff Garzik --- drivers/net/sfc/falcon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index 8acd53de5e7..8cb57987905 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -222,7 +222,7 @@ static struct i2c_algo_bit_data falcon_i2c_bit_operations = { .setscl = falcon_setscl, .getsda = falcon_getsda, .getscl = falcon_getscl, - .udelay = 100, + .udelay = 5, /* * This is the number of system clock ticks after which * i2c-algo-bit gives up waiting for SCL to become high. -- cgit v1.2.3-70-g09d2 From a5edeccb1a8432ae5d9fb9bccea5a4b64c565017 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 26 May 2008 11:53:21 +0200 Subject: net: OpenFirmware GPIO based MDIO bitbang driver This patch adds an MDIO bitbang driver that uses the GPIO library and its OF bindings to access the bus I/Os. Signed-off-by: Laurent Pinchart Signed-off-by: Jeff Garzik --- Documentation/powerpc/booting-without-of.txt | 21 +++ drivers/net/phy/Kconfig | 6 + drivers/net/phy/Makefile | 1 + drivers/net/phy/mdio-ofgpio.c | 205 +++++++++++++++++++++++++++ 4 files changed, 233 insertions(+) create mode 100644 drivers/net/phy/mdio-ofgpio.c (limited to 'drivers') diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt index 1d2a772506c..46a9dba11f2 100644 --- a/Documentation/powerpc/booting-without-of.txt +++ b/Documentation/powerpc/booting-without-of.txt @@ -58,6 +58,7 @@ Table of Contents o) Xilinx IP cores p) Freescale Synchronous Serial Interface q) USB EHCI controllers + r) MDIO on GPIOs VII - Marvell Discovery mv64[345]6x System Controller chips 1) The /system-controller node @@ -2870,6 +2871,26 @@ platforms are moved over to use the flattened-device-tree model. reg = <0xe8000000 32>; }; + r) MDIO on GPIOs + + Currently defined compatibles: + - virtual,gpio-mdio + + MDC and MDIO lines connected to GPIO controllers are listed in the + gpios property as described in section VIII.1 in the following order: + + MDC, MDIO. + + Example: + + mdio { + compatible = "virtual,mdio-gpio"; + #address-cells = <1>; + #size-cells = <0>; + gpios = <&qe_pio_a 11 + &qe_pio_c 6>; + }; + VII - Marvell Discovery mv64[345]6x System Controller chips =========================================================== diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 284217c1283..d55932acd88 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -84,4 +84,10 @@ config MDIO_BITBANG If in doubt, say N. +config MDIO_OF_GPIO + tristate "Support for GPIO lib-based bitbanged MDIO buses" + depends on MDIO_BITBANG && OF_GPIO + ---help--- + Supports GPIO lib-based MDIO busses. + endif # PHYLIB diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 5997d6ef702..eee329fa6f5 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -15,3 +15,4 @@ obj-$(CONFIG_ICPLUS_PHY) += icplus.o obj-$(CONFIG_REALTEK_PHY) += realtek.o obj-$(CONFIG_FIXED_PHY) += fixed.o obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o +obj-$(CONFIG_MDIO_OF_GPIO) += mdio-ofgpio.o diff --git a/drivers/net/phy/mdio-ofgpio.c b/drivers/net/phy/mdio-ofgpio.c new file mode 100644 index 00000000000..7edfc0c3483 --- /dev/null +++ b/drivers/net/phy/mdio-ofgpio.c @@ -0,0 +1,205 @@ +/* + * OpenFirmware GPIO based MDIO bitbang driver. + * + * Copyright (c) 2008 CSE Semaphore Belgium. + * by Laurent Pinchart + * + * Based on earlier work by + * + * Copyright (c) 2003 Intracom S.A. + * by Pantelis Antoniou + * + * 2005 (c) MontaVista Software, Inc. + * Vitaly Bordug + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include + +struct mdio_gpio_info { + struct mdiobb_ctrl ctrl; + int mdc, mdio; +}; + +static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir) +{ + struct mdio_gpio_info *bitbang = + container_of(ctrl, struct mdio_gpio_info, ctrl); + + if (dir) + gpio_direction_output(bitbang->mdio, 1); + else + gpio_direction_input(bitbang->mdio); +} + +static int mdio_read(struct mdiobb_ctrl *ctrl) +{ + struct mdio_gpio_info *bitbang = + container_of(ctrl, struct mdio_gpio_info, ctrl); + + return gpio_get_value(bitbang->mdio); +} + +static void mdio(struct mdiobb_ctrl *ctrl, int what) +{ + struct mdio_gpio_info *bitbang = + container_of(ctrl, struct mdio_gpio_info, ctrl); + + gpio_set_value(bitbang->mdio, what); +} + +static void mdc(struct mdiobb_ctrl *ctrl, int what) +{ + struct mdio_gpio_info *bitbang = + container_of(ctrl, struct mdio_gpio_info, ctrl); + + gpio_set_value(bitbang->mdc, what); +} + +static struct mdiobb_ops mdio_gpio_ops = { + .owner = THIS_MODULE, + .set_mdc = mdc, + .set_mdio_dir = mdio_dir, + .set_mdio_data = mdio, + .get_mdio_data = mdio_read, +}; + +static int __devinit mdio_ofgpio_bitbang_init(struct mii_bus *bus, + struct device_node *np) +{ + struct mdio_gpio_info *bitbang = bus->priv; + + bitbang->mdc = of_get_gpio(np, 0); + bitbang->mdio = of_get_gpio(np, 1); + + if (bitbang->mdc < 0 || bitbang->mdio < 0) + return -ENODEV; + + snprintf(bus->id, MII_BUS_ID_SIZE, "%x", bitbang->mdc); + return 0; +} + +static void __devinit add_phy(struct mii_bus *bus, struct device_node *np) +{ + const u32 *data; + int len, id, irq; + + data = of_get_property(np, "reg", &len); + if (!data || len != 4) + return; + + id = *data; + bus->phy_mask &= ~(1 << id); + + irq = of_irq_to_resource(np, 0, NULL); + if (irq != NO_IRQ) + bus->irq[id] = irq; +} + +static int __devinit mdio_ofgpio_probe(struct of_device *ofdev, + const struct of_device_id *match) +{ + struct device_node *np = NULL; + struct mii_bus *new_bus; + struct mdio_gpio_info *bitbang; + int ret = -ENOMEM; + int i; + + bitbang = kzalloc(sizeof(struct mdio_gpio_info), GFP_KERNEL); + if (!bitbang) + goto out; + + bitbang->ctrl.ops = &mdio_gpio_ops; + + new_bus = alloc_mdio_bitbang(&bitbang->ctrl); + if (!new_bus) + goto out_free_priv; + + new_bus->name = "GPIO Bitbanged MII", + + ret = mdio_ofgpio_bitbang_init(new_bus, ofdev->node); + if (ret) + goto out_free_bus; + + new_bus->phy_mask = ~0; + new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); + if (!new_bus->irq) + goto out_free_bus; + + for (i = 0; i < PHY_MAX_ADDR; i++) + new_bus->irq[i] = -1; + + while ((np = of_get_next_child(ofdev->node, np))) + if (!strcmp(np->type, "ethernet-phy")) + add_phy(new_bus, np); + + new_bus->dev = &ofdev->dev; + dev_set_drvdata(&ofdev->dev, new_bus); + + ret = mdiobus_register(new_bus); + if (ret) + goto out_free_irqs; + + return 0; + +out_free_irqs: + dev_set_drvdata(&ofdev->dev, NULL); + kfree(new_bus->irq); +out_free_bus: + kfree(new_bus); +out_free_priv: + free_mdio_bitbang(new_bus); +out: + return ret; +} + +static int mdio_ofgpio_remove(struct of_device *ofdev) +{ + struct mii_bus *bus = dev_get_drvdata(&ofdev->dev); + struct mdio_gpio_info *bitbang = bus->priv; + + mdiobus_unregister(bus); + free_mdio_bitbang(bus); + dev_set_drvdata(&ofdev->dev, NULL); + kfree(bus->irq); + kfree(bitbang); + kfree(bus); + + return 0; +} + +static struct of_device_id mdio_ofgpio_match[] = { + { + .compatible = "virtual,mdio-gpio", + }, + {}, +}; + +static struct of_platform_driver mdio_ofgpio_driver = { + .name = "mdio-gpio", + .match_table = mdio_ofgpio_match, + .probe = mdio_ofgpio_probe, + .remove = mdio_ofgpio_remove, +}; + +static int mdio_ofgpio_init(void) +{ + return of_register_platform_driver(&mdio_ofgpio_driver); +} + +static void mdio_ofgpio_exit(void) +{ + of_unregister_platform_driver(&mdio_ofgpio_driver); +} + +module_init(mdio_ofgpio_init); +module_exit(mdio_ofgpio_exit); -- cgit v1.2.3-70-g09d2 From d8b35fac8c7e1b44d873c1afcc5f88bc5ef4b361 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 26 May 2008 11:53:45 +0200 Subject: fs_enet: MDIO on GPIO support Port the fs_enet driver to support the MDIO on GPIO driver for PHY access in addition to the mii-bitbang driver. Signed-off-by: Laurent Pinchart Signed-off-by: Jeff Garzik --- drivers/net/fs_enet/fs_enet-main.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index a5baaf59ff6..fb7c47790bd 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -43,6 +43,7 @@ #include #ifdef CONFIG_PPC_CPM_NEW_BINDING +#include #include #endif @@ -1172,8 +1173,7 @@ static int __devinit find_phy(struct device_node *np, struct fs_platform_info *fpi) { struct device_node *phynode, *mdionode; - struct resource res; - int ret = 0, len; + int ret = 0, len, bus_id; const u32 *data; data = of_get_property(np, "fixed-link", NULL); @@ -1190,19 +1190,28 @@ static int __devinit find_phy(struct device_node *np, if (!phynode) return -EINVAL; - mdionode = of_get_parent(phynode); - if (!mdionode) + data = of_get_property(phynode, "reg", &len); + if (!data || len != 4) { + ret = -EINVAL; goto out_put_phy; + } - ret = of_address_to_resource(mdionode, 0, &res); - if (ret) - goto out_put_mdio; + mdionode = of_get_parent(phynode); + if (!mdionode) { + ret = -EINVAL; + goto out_put_phy; + } - data = of_get_property(phynode, "reg", &len); - if (!data || len != 4) - goto out_put_mdio; + bus_id = of_get_gpio(mdionode, 0); + if (bus_id < 0) { + struct resource res; + ret = of_address_to_resource(mdionode, 0, &res); + if (ret) + goto out_put_mdio; + bus_id = res.start; + } - snprintf(fpi->bus_id, 16, "%x:%02x", res.start, *data); + snprintf(fpi->bus_id, 16, "%x:%02x", bus_id, *data); out_put_mdio: of_node_put(mdionode); -- cgit v1.2.3-70-g09d2 From 3700b62be8c97bec3eb10198d72edb745652cb70 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Thu, 22 May 2008 00:00:01 -0700 Subject: ps3: gelic: scan_lock semaphore to mutex Signed-off-by: Daniel Walker Signed-off-by: Jeff Garzik --- drivers/net/ps3_gelic_wireless.c | 18 +++++++++--------- drivers/net/ps3_gelic_wireless.h | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c index 1dae1f2ed81..b338093a01e 100644 --- a/drivers/net/ps3_gelic_wireless.c +++ b/drivers/net/ps3_gelic_wireless.c @@ -695,7 +695,7 @@ static int gelic_wl_get_scan(struct net_device *netdev, unsigned long this_time = jiffies; pr_debug("%s: <-\n", __func__); - if (down_interruptible(&wl->scan_lock)) + if (mutex_lock_interruptible(&wl->scan_lock)) return -EAGAIN; switch (wl->scan_stat) { @@ -733,7 +733,7 @@ static int gelic_wl_get_scan(struct net_device *netdev, wrqu->data.length = ev - extra; wrqu->data.flags = 0; out: - up(&wl->scan_lock); + mutex_unlock(&wl->scan_lock); pr_debug("%s: -> %d %d\n", __func__, ret, wrqu->data.length); return ret; } @@ -1554,7 +1554,7 @@ static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan) int ret = 0; pr_debug("%s: <- always=%d\n", __func__, always_scan); - if (down_interruptible(&wl->scan_lock)) + if (mutex_lock_interruptible(&wl->scan_lock)) return -ERESTARTSYS; /* @@ -1588,7 +1588,7 @@ static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan) } kfree(cmd); out: - up(&wl->scan_lock); + mutex_unlock(&wl->scan_lock); pr_debug("%s: ->\n", __func__); return ret; } @@ -1610,7 +1610,7 @@ static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl) DECLARE_MAC_BUF(mac); pr_debug("%s:start\n", __func__); - down(&wl->scan_lock); + mutex_lock(&wl->scan_lock); if (wl->scan_stat != GELIC_WL_SCAN_STAT_SCANNING) { /* @@ -1727,7 +1727,7 @@ static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl) NULL); out: complete(&wl->scan_done); - up(&wl->scan_lock); + mutex_unlock(&wl->scan_lock); pr_debug("%s:end\n", __func__); } @@ -2282,7 +2282,7 @@ static void gelic_wl_assoc_worker(struct work_struct *work) wait_for_completion(&wl->scan_done); pr_debug("%s: scan done\n", __func__); - down(&wl->scan_lock); + mutex_lock(&wl->scan_lock); if (wl->scan_stat != GELIC_WL_SCAN_STAT_GOT_LIST) { gelic_wl_send_iwap_event(wl, NULL); pr_info("%s: no scan list. association failed\n", __func__); @@ -2302,7 +2302,7 @@ static void gelic_wl_assoc_worker(struct work_struct *work) if (ret) pr_info("%s: association failed %d\n", __func__, ret); scan_lock_out: - up(&wl->scan_lock); + mutex_unlock(&wl->scan_lock); out: up(&wl->assoc_stat_lock); } @@ -2431,7 +2431,7 @@ static struct net_device *gelic_wl_alloc(struct gelic_card *card) INIT_DELAYED_WORK(&wl->event_work, gelic_wl_event_worker); INIT_DELAYED_WORK(&wl->assoc_work, gelic_wl_assoc_worker); - init_MUTEX(&wl->scan_lock); + mutex_init(&wl->scan_lock); init_MUTEX(&wl->assoc_stat_lock); init_completion(&wl->scan_done); diff --git a/drivers/net/ps3_gelic_wireless.h b/drivers/net/ps3_gelic_wireless.h index 10369716672..fb3222e8d3b 100644 --- a/drivers/net/ps3_gelic_wireless.h +++ b/drivers/net/ps3_gelic_wireless.h @@ -241,7 +241,7 @@ enum gelic_wl_assoc_state { #define GELIC_WEP_KEYS 4 struct gelic_wl_info { /* bss list */ - struct semaphore scan_lock; + struct mutex scan_lock; struct list_head network_list; struct list_head network_free_list; struct gelic_wl_scan_info *networks; -- cgit v1.2.3-70-g09d2 From 5a2d9af2769c0b4c6ab6d88d31fa3b9a4a432b09 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Thu, 22 May 2008 00:00:02 -0700 Subject: ps3: gelic: assoc_stat_lock semaphore to mutex Signed-off-by: Daniel Walker Signed-off-by: Jeff Garzik --- drivers/net/ps3_gelic_wireless.c | 22 +++++++++++----------- drivers/net/ps3_gelic_wireless.h | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c index b338093a01e..e5e02339a5c 100644 --- a/drivers/net/ps3_gelic_wireless.c +++ b/drivers/net/ps3_gelic_wireless.c @@ -240,12 +240,12 @@ static u32 gelic_wl_get_link(struct net_device *netdev) u32 ret; pr_debug("%s: <-\n", __func__); - down(&wl->assoc_stat_lock); + mutex_lock(&wl->assoc_stat_lock); if (wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED) ret = 1; else ret = 0; - up(&wl->assoc_stat_lock); + mutex_unlock(&wl->assoc_stat_lock); pr_debug("%s: ->\n", __func__); return ret; } @@ -979,7 +979,7 @@ static int gelic_wl_get_essid(struct net_device *netdev, unsigned long irqflag; pr_debug("%s: <- \n", __func__); - down(&wl->assoc_stat_lock); + mutex_lock(&wl->assoc_stat_lock); spin_lock_irqsave(&wl->lock, irqflag); if (test_bit(GELIC_WL_STAT_ESSID_SET, &wl->stat) || wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED) { @@ -989,7 +989,7 @@ static int gelic_wl_get_essid(struct net_device *netdev, } else data->essid.flags = 0; - up(&wl->assoc_stat_lock); + mutex_unlock(&wl->assoc_stat_lock); spin_unlock_irqrestore(&wl->lock, irqflag); pr_debug("%s: -> len=%d \n", __func__, data->essid.length); @@ -1170,7 +1170,7 @@ static int gelic_wl_get_ap(struct net_device *netdev, unsigned long irqflag; pr_debug("%s: <-\n", __func__); - down(&wl->assoc_stat_lock); + mutex_lock(&wl->assoc_stat_lock); spin_lock_irqsave(&wl->lock, irqflag); if (wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED) { data->ap_addr.sa_family = ARPHRD_ETHER; @@ -1180,7 +1180,7 @@ static int gelic_wl_get_ap(struct net_device *netdev, memset(data->ap_addr.sa_data, 0, ETH_ALEN); spin_unlock_irqrestore(&wl->lock, irqflag); - up(&wl->assoc_stat_lock); + mutex_unlock(&wl->assoc_stat_lock); pr_debug("%s: ->\n", __func__); return 0; } @@ -2151,7 +2151,7 @@ static void gelic_wl_disconnect_event(struct gelic_wl_info *wl, * As it waits with timeout, just leave assoc_done * uncompleted, then it terminates with timeout */ - if (down_trylock(&wl->assoc_stat_lock)) { + if (!mutex_trylock(&wl->assoc_stat_lock)) { pr_debug("%s: already locked\n", __func__); lock = 0; } else { @@ -2170,7 +2170,7 @@ static void gelic_wl_disconnect_event(struct gelic_wl_info *wl, netif_carrier_off(port_to_netdev(wl_port(wl))); if (lock) - up(&wl->assoc_stat_lock); + mutex_unlock(&wl->assoc_stat_lock); } /* * event worker @@ -2258,7 +2258,7 @@ static void gelic_wl_assoc_worker(struct work_struct *work) wl = container_of(work, struct gelic_wl_info, assoc_work.work); - down(&wl->assoc_stat_lock); + mutex_lock(&wl->assoc_stat_lock); if (wl->assoc_stat != GELIC_WL_ASSOC_STAT_DISCONN) goto out; @@ -2304,7 +2304,7 @@ static void gelic_wl_assoc_worker(struct work_struct *work) scan_lock_out: mutex_unlock(&wl->scan_lock); out: - up(&wl->assoc_stat_lock); + mutex_unlock(&wl->assoc_stat_lock); } /* * Interrupt handler @@ -2432,7 +2432,7 @@ static struct net_device *gelic_wl_alloc(struct gelic_card *card) INIT_DELAYED_WORK(&wl->event_work, gelic_wl_event_worker); INIT_DELAYED_WORK(&wl->assoc_work, gelic_wl_assoc_worker); mutex_init(&wl->scan_lock); - init_MUTEX(&wl->assoc_stat_lock); + mutex_init(&wl->assoc_stat_lock); init_completion(&wl->scan_done); /* for the case that no scan request is issued and stop() is called */ diff --git a/drivers/net/ps3_gelic_wireless.h b/drivers/net/ps3_gelic_wireless.h index fb3222e8d3b..bc730632da5 100644 --- a/drivers/net/ps3_gelic_wireless.h +++ b/drivers/net/ps3_gelic_wireless.h @@ -266,7 +266,7 @@ struct gelic_wl_info { enum gelic_wl_wpa_level wpa_level; /* wpa/wpa2 */ /* association handling */ - struct semaphore assoc_stat_lock; + struct mutex assoc_stat_lock; struct delayed_work assoc_work; enum gelic_wl_assoc_state assoc_stat; struct completion assoc_done; -- cgit v1.2.3-70-g09d2 From 2914f3efa7ef80f12ff798cb1aa46af57838f912 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Thu, 22 May 2008 00:00:03 -0700 Subject: ps3: gelic: updown_lock semaphore to mutex Signed-off-by: Daniel Walker Signed-off-by: Jeff Garzik --- drivers/net/ps3_gelic_net.c | 10 +++++----- drivers/net/ps3_gelic_net.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c index e365efb3c62..2eb54fd7bed 100644 --- a/drivers/net/ps3_gelic_net.c +++ b/drivers/net/ps3_gelic_net.c @@ -110,7 +110,7 @@ static void gelic_card_get_ether_port_status(struct gelic_card *card, void gelic_card_up(struct gelic_card *card) { pr_debug("%s: called\n", __func__); - down(&card->updown_lock); + mutex_lock(&card->updown_lock); if (atomic_inc_return(&card->users) == 1) { pr_debug("%s: real do\n", __func__); /* enable irq */ @@ -120,7 +120,7 @@ void gelic_card_up(struct gelic_card *card) napi_enable(&card->napi); } - up(&card->updown_lock); + mutex_unlock(&card->updown_lock); pr_debug("%s: done\n", __func__); } @@ -128,7 +128,7 @@ void gelic_card_down(struct gelic_card *card) { u64 mask; pr_debug("%s: called\n", __func__); - down(&card->updown_lock); + mutex_lock(&card->updown_lock); if (atomic_dec_if_positive(&card->users) == 0) { pr_debug("%s: real do\n", __func__); napi_disable(&card->napi); @@ -146,7 +146,7 @@ void gelic_card_down(struct gelic_card *card) /* stop tx */ gelic_card_disable_txdmac(card); } - up(&card->updown_lock); + mutex_unlock(&card->updown_lock); pr_debug("%s: done\n", __func__); } @@ -1534,7 +1534,7 @@ static struct gelic_card *gelic_alloc_card_net(struct net_device **netdev) INIT_WORK(&card->tx_timeout_task, gelic_net_tx_timeout_task); init_waitqueue_head(&card->waitq); atomic_set(&card->tx_timeout_task_counter, 0); - init_MUTEX(&card->updown_lock); + mutex_init(&card->updown_lock); atomic_set(&card->users, 0); return card; diff --git a/drivers/net/ps3_gelic_net.h b/drivers/net/ps3_gelic_net.h index 520f143c2c0..8b413868bbe 100644 --- a/drivers/net/ps3_gelic_net.h +++ b/drivers/net/ps3_gelic_net.h @@ -298,7 +298,7 @@ struct gelic_card { wait_queue_head_t waitq; /* only first user should up the card */ - struct semaphore updown_lock; + struct mutex updown_lock; atomic_t users; u64 ether_port_status; -- cgit v1.2.3-70-g09d2 From f735a2a1a4f2a0f5cd823ce323e82675990469e2 Mon Sep 17 00:00:00 2001 From: Tobias Diedrich Date: Sun, 18 May 2008 15:02:37 +0200 Subject: [netdrvr] forcedeth: setup wake-on-lan before shutting down When hibernating in 'shutdown' mode, after saving the image the suspend hook is not called again. However, if the device is in promiscous mode, wake-on-lan will not work. This adds a shutdown hook to setup wake-on-lan before the final shutdown. Signed-off-by: Tobias Diedrich Signed-off-by: Jeff Garzik --- drivers/net/forcedeth.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 9eca97fb0a5..215d27bbeff 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -5827,8 +5827,23 @@ static int nv_resume(struct pci_dev *pdev) out: return rc; } + +static void nv_shutdown(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct fe_priv *np = netdev_priv(dev); + + if (netif_running(dev)) + nv_close(dev); + + pci_enable_wake(pdev, PCI_D3hot, np->wolenabled); + pci_enable_wake(pdev, PCI_D3cold, np->wolenabled); + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); +} #else #define nv_suspend NULL +#define nv_shutdown NULL #define nv_resume NULL #endif /* CONFIG_PM */ @@ -5999,6 +6014,7 @@ static struct pci_driver driver = { .remove = __devexit_p(nv_remove), .suspend = nv_suspend, .resume = nv_resume, + .shutdown = nv_shutdown, }; static int __init init_nic(void) -- cgit v1.2.3-70-g09d2 From 1a1ca86158eee303af5270338695f90bc7ae02b3 Mon Sep 17 00:00:00 2001 From: Tobias Diedrich Date: Sun, 18 May 2008 15:03:44 +0200 Subject: [netdrvr] forcedeth: save/restore device configuration space The memory mapped device configuration space is lost during hibernate. Save and restore it (fixes 'swapped mac' problem). Signed-off-by: TTobias Diedrich Signed-off-by: Jeff Garzik --- drivers/net/forcedeth.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 215d27bbeff..a5650ed4d48 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -426,6 +426,7 @@ union ring_type { #define NV_PCI_REGSZ_VER1 0x270 #define NV_PCI_REGSZ_VER2 0x2d4 #define NV_PCI_REGSZ_VER3 0x604 +#define NV_PCI_REGSZ_MAX 0x604 /* various timeout delays: all in usec */ #define NV_TXRX_RESET_DELAY 4 @@ -784,6 +785,9 @@ struct fe_priv { /* flow control */ u32 pause_flags; + + /* power saved state */ + u32 saved_config_space[NV_PCI_REGSZ_MAX/4]; }; /* @@ -5785,6 +5789,8 @@ static int nv_suspend(struct pci_dev *pdev, pm_message_t state) { struct net_device *dev = pci_get_drvdata(pdev); struct fe_priv *np = netdev_priv(dev); + u8 __iomem *base = get_hwbase(dev); + int i; if (!netif_running(dev)) goto out; @@ -5794,6 +5800,10 @@ static int nv_suspend(struct pci_dev *pdev, pm_message_t state) // Gross. nv_close(dev); + /* save non-pci configuration space */ + for (i = 0;i <= np->register_size/sizeof(u32); i++) + np->saved_config_space[i] = readl(base + i*sizeof(u32)); + pci_save_state(pdev); pci_enable_wake(pdev, pci_choose_state(pdev, state), np->wolenabled); pci_set_power_state(pdev, pci_choose_state(pdev, state)); @@ -5804,9 +5814,9 @@ out: static int nv_resume(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); - int rc = 0; - u32 txreg; + int i, rc = 0; if (!netif_running(dev)) goto out; @@ -5817,10 +5827,9 @@ static int nv_resume(struct pci_dev *pdev) pci_restore_state(pdev); pci_enable_wake(pdev, PCI_D0, 0); - /* restore mac address reverse flag */ - txreg = readl(base + NvRegTransmitPoll); - txreg |= NVREG_TRANSMITPOLL_MAC_ADDR_REV; - writel(txreg, base + NvRegTransmitPoll); + /* restore non-pci configuration space */ + for (i = 0;i <= np->register_size/sizeof(u32); i++) + writel(np->saved_config_space[i], base+i*sizeof(u32)); rc = nv_open(dev); nv_set_multicast(dev); -- cgit v1.2.3-70-g09d2 From 25d90810ff49d2a63475776f24c74c6bb49b045f Mon Sep 17 00:00:00 2001 From: Tobias Diedrich Date: Sun, 18 May 2008 15:04:29 +0200 Subject: [netdrvr] forcedeth: reorder suspend/resume code Match the suspend/resume code ordering in e100/e1000e more closely. For example the configuration space should be saved on suspend even for devices that are not up. Signed-off-by: Tobias Diedrich Signed-off-by: Jeff Garzik --- drivers/net/forcedeth.c | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index a5650ed4d48..e4d69789436 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -5792,22 +5792,20 @@ static int nv_suspend(struct pci_dev *pdev, pm_message_t state) u8 __iomem *base = get_hwbase(dev); int i; - if (!netif_running(dev)) - goto out; - + if (netif_running(dev)) { + // Gross. + nv_close(dev); + } netif_device_detach(dev); - // Gross. - nv_close(dev); - /* save non-pci configuration space */ for (i = 0;i <= np->register_size/sizeof(u32); i++) np->saved_config_space[i] = readl(base + i*sizeof(u32)); pci_save_state(pdev); pci_enable_wake(pdev, pci_choose_state(pdev, state), np->wolenabled); + pci_disable_device(pdev); pci_set_power_state(pdev, pci_choose_state(pdev, state)); -out: return 0; } @@ -5818,22 +5816,20 @@ static int nv_resume(struct pci_dev *pdev) u8 __iomem *base = get_hwbase(dev); int i, rc = 0; - if (!netif_running(dev)) - goto out; - - netif_device_attach(dev); - pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); + /* ack any pending wake events, disable PME */ pci_enable_wake(pdev, PCI_D0, 0); /* restore non-pci configuration space */ for (i = 0;i <= np->register_size/sizeof(u32); i++) writel(np->saved_config_space[i], base+i*sizeof(u32)); - rc = nv_open(dev); - nv_set_multicast(dev); -out: + netif_device_attach(dev); + if (netif_running(dev)) { + rc = nv_open(dev); + nv_set_multicast(dev); + } return rc; } -- cgit v1.2.3-70-g09d2 From b96936da7a8911cfa29225aa4dc380aba1b8a86e Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 14 May 2008 17:04:15 -0700 Subject: sky2: split phy power into two functions Later changes add more code to PHY power changes so refactor now. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 535f6cc96c8..ad35674ba83 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -619,28 +619,35 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK); } -static void sky2_phy_power(struct sky2_hw *hw, unsigned port, int onoff) +static const u32 phy_power[] = { PCI_Y2_PHY1_POWD, PCI_Y2_PHY2_POWD }; +static const u32 coma_mode[] = { PCI_Y2_PHY1_COMA, PCI_Y2_PHY2_COMA }; + +static void sky2_phy_power_up(struct sky2_hw *hw, unsigned port) { u32 reg1; - static const u32 phy_power[] = { PCI_Y2_PHY1_POWD, PCI_Y2_PHY2_POWD }; - static const u32 coma_mode[] = { PCI_Y2_PHY1_COMA, PCI_Y2_PHY2_COMA }; sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); reg1 = sky2_pci_read32(hw, PCI_DEV_REG1); - /* Turn on/off phy power saving */ - if (onoff) - reg1 &= ~phy_power[port]; - else - reg1 |= phy_power[port]; + reg1 &= ~phy_power[port]; - if (onoff && hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1) + if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1) reg1 |= coma_mode[port]; sky2_pci_write32(hw, PCI_DEV_REG1, reg1); sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); sky2_pci_read32(hw, PCI_DEV_REG1); +} + +static void sky2_phy_power_down(struct sky2_hw *hw, unsigned port) +{ + u32 reg1; + + sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); + reg1 = sky2_pci_read32(hw, PCI_DEV_REG1); + reg1 |= phy_power[port]; - udelay(100); + sky2_pci_write32(hw, PCI_DEV_REG1, reg1); + sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); } /* Force a renegotiation */ @@ -675,8 +682,11 @@ static void sky2_wol_init(struct sky2_port *sky2) sky2->advertising &= ~(ADVERTISED_1000baseT_Half|ADVERTISED_1000baseT_Full); sky2->flow_mode = FC_NONE; - sky2_phy_power(hw, port, 1); - sky2_phy_reinit(sky2); + + spin_lock_bh(&sky2->phy_lock); + sky2_phy_power_up(hw, port); + sky2_phy_init(hw, port); + spin_unlock_bh(&sky2->phy_lock); sky2->flow_mode = save_mode; sky2->advertising = ctrl; @@ -781,6 +791,7 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port) sky2_write8(hw, SK_REG(port, GMAC_IRQ_MSK), GMAC_DEF_MSK); spin_lock_bh(&sky2->phy_lock); + sky2_phy_power_up(hw, port); sky2_phy_init(hw, port); spin_unlock_bh(&sky2->phy_lock); @@ -1385,8 +1396,6 @@ static int sky2_up(struct net_device *dev) if (!sky2->rx_ring) goto err_out; - sky2_phy_power(hw, port, 1); - sky2_mac_init(hw, port); /* Register is number of 4K blocks on internal RAM buffer. */ @@ -1767,7 +1776,7 @@ static int sky2_down(struct net_device *dev) sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET); sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_SET); - sky2_phy_power(hw, port, 0); + sky2_phy_power_down(hw, port); netif_carrier_off(dev); -- cgit v1.2.3-70-g09d2 From db99b98885e717454feef1c6868b27d3f23c2e7c Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 14 May 2008 17:04:16 -0700 Subject: sky2: put PHY in sleep when down Put PHY int sleep mode (from vendor sk98lin 10.50 driver) when the network device is brought down. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 40 ++++++++++++++++++++++++++++++++++++++-- drivers/net/sky2.h | 7 +++++++ 2 files changed, 45 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index ad35674ba83..59cb9cd00ad 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -641,11 +641,47 @@ static void sky2_phy_power_up(struct sky2_hw *hw, unsigned port) static void sky2_phy_power_down(struct sky2_hw *hw, unsigned port) { u32 reg1; + u16 ctrl; + + /* release GPHY Control reset */ + sky2_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_CLR); + + /* release GMAC reset */ + sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_RST_CLR); + + if (hw->flags & SKY2_HW_NEWER_PHY) { + /* select page 2 to access MAC control register */ + gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 2); + + ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL); + /* allow GMII Power Down */ + ctrl &= ~PHY_M_MAC_GMIF_PUP; + gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl); + + /* set page register back to 0 */ + gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 0); + } + + /* setup General Purpose Control Register */ + gma_write16(hw, port, GM_GP_CTRL, + GM_GPCR_FL_PASS | GM_GPCR_SPEED_100 | GM_GPCR_AU_ALL_DIS); + + if (hw->chip_id != CHIP_ID_YUKON_EC) { + if (hw->chip_id == CHIP_ID_YUKON_EC_U) { + ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL); + + /* enable Power Down */ + ctrl |= PHY_M_PC_POW_D_ENA; + gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl); + } + + /* set IEEE compatible Power Down Mode (dev. #4.99) */ + gm_phy_write(hw, port, PHY_MARV_CTRL, PHY_CT_PDOWN); + } sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); reg1 = sky2_pci_read32(hw, PCI_DEV_REG1); - reg1 |= phy_power[port]; - + reg1 |= phy_power[port]; /* set PHY to PowerDown/COMA Mode */ sky2_pci_write32(hw, PCI_DEV_REG1, reg1); sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); } diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index c0a5eea2000..d63106cd74b 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -1143,6 +1143,12 @@ enum { PHY_M_PC_ENA_AUTO = 3, /* 11 = Enable Automatic Crossover */ }; +/* for Yukon-EC Ultra Gigabit Ethernet PHY (88E1149 only) */ +enum { + PHY_M_PC_COP_TX_DIS = 1<<3, /* Copper Transmitter Disable */ + PHY_M_PC_POW_D_ENA = 1<<2, /* Power Down Enable */ +}; + /* for 10/100 Fast Ethernet PHY (88E3082 only) */ enum { PHY_M_PC_ENA_DTE_DT = 1<<15, /* Enable Data Terminal Equ. (DTE) Detect */ @@ -1411,6 +1417,7 @@ enum { /***** PHY_MARV_PHY_CTRL (page 2) 16 bit r/w MAC Specific Ctrl *****/ enum { PHY_M_MAC_MD_MSK = 7<<7, /* Bit 9.. 7: Mode Select Mask */ + PHY_M_MAC_GMIF_PUP = 1<<3, /* GMII Power Up (88E1149 only) */ PHY_M_MAC_MD_AUTO = 3,/* Auto Copper/1000Base-X */ PHY_M_MAC_MD_COPPER = 5,/* Copper only */ PHY_M_MAC_MD_1000BX = 7,/* 1000Base-X only */ -- cgit v1.2.3-70-g09d2 From a068c0adf2fe28b324bca87f85d27af7f993cdaf Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 14 May 2008 17:04:17 -0700 Subject: sky2: pci power savings Turn on special bits to save more power when device is shutdown. Tested on a limited range of hardware, some of the bits are for hardware that probably isn't even in production (like Yukon Supreme) and was ported from the vendor driver. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++---- drivers/net/sky2.h | 16 ++++++++- 2 files changed, 107 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 59cb9cd00ad..c83406f4f2a 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -284,6 +284,86 @@ static void sky2_power_aux(struct sky2_hw *hw) PC_VAUX_ON | PC_VCC_OFF)); } +static void sky2_power_state(struct sky2_hw *hw, pci_power_t state) +{ + u16 power_control = sky2_pci_read16(hw, hw->pm_cap + PCI_PM_CTRL); + int pex = pci_find_capability(hw->pdev, PCI_CAP_ID_EXP); + u32 reg; + + sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); + + switch (state) { + case PCI_D0: + break; + + case PCI_D1: + power_control |= 1; + break; + + case PCI_D2: + power_control |= 2; + break; + + case PCI_D3hot: + case PCI_D3cold: + power_control |= 3; + if (hw->flags & SKY2_HW_ADV_POWER_CTL) { + /* additional power saving measurements */ + reg = sky2_pci_read32(hw, PCI_DEV_REG4); + + /* set gating core clock for LTSSM in L1 state */ + reg |= P_PEX_LTSSM_STAT(P_PEX_LTSSM_L1_STAT) | + /* auto clock gated scheme controlled by CLKREQ */ + P_ASPM_A1_MODE_SELECT | + /* enable Gate Root Core Clock */ + P_CLK_GATE_ROOT_COR_ENA; + + if (pex && (hw->flags & SKY2_HW_CLK_POWER)) { + /* enable Clock Power Management (CLKREQ) */ + u16 ctrl = sky2_pci_read16(hw, pex + PCI_EXP_DEVCTL); + + ctrl |= PCI_EXP_DEVCTL_AUX_PME; + sky2_pci_write16(hw, pex + PCI_EXP_DEVCTL, ctrl); + } else + /* force CLKREQ Enable in Our4 (A1b only) */ + reg |= P_ASPM_FORCE_CLKREQ_ENA; + + /* set Mask Register for Release/Gate Clock */ + sky2_pci_write32(hw, PCI_DEV_REG5, + P_REL_PCIE_EXIT_L1_ST | P_GAT_PCIE_ENTER_L1_ST | + P_REL_PCIE_RX_EX_IDLE | P_GAT_PCIE_RX_EL_IDLE | + P_REL_GPHY_LINK_UP | P_GAT_GPHY_LINK_DOWN); + } else + sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_CLK_HALT); + + /* put CPU into reset state */ + sky2_write8(hw, B28_Y2_ASF_STAT_CMD, HCU_CCSR_ASF_RESET); + if (hw->chip_id == CHIP_ID_YUKON_SUPR && hw->chip_rev == CHIP_REV_YU_SU_A0) + /* put CPU into halt state */ + sky2_write8(hw, B28_Y2_ASF_STAT_CMD, HCU_CCSR_ASF_HALTED); + + if (pex && !(hw->flags & SKY2_HW_RAM_BUFFER)) { + reg = sky2_pci_read32(hw, PCI_DEV_REG1); + /* force to PCIe L1 */ + reg |= PCI_FORCE_PEX_L1; + sky2_pci_write32(hw, PCI_DEV_REG1, reg); + } + break; + + default: + dev_warn(&hw->pdev->dev, PFX "Invalid power state (%d) ", + state); + return; + } + + power_control |= PCI_PM_CTRL_PME_ENABLE; + /* Finally, set the new power state. */ + sky2_pci_write32(hw, hw->pm_cap + PCI_PM_CTRL, power_control); + + sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); + sky2_pci_read32(hw, B0_CTST); +} + static void sky2_gmac_reset(struct sky2_hw *hw, unsigned port) { u16 reg; @@ -2786,6 +2866,10 @@ static int __devinit sky2_init(struct sky2_hw *hw) hw->flags = SKY2_HW_GIGABIT | SKY2_HW_NEWER_PHY | SKY2_HW_ADV_POWER_CTL; + + /* check for Rev. A1 dev 4200 */ + if (sky2_read16(hw, Q_ADDR(Q_XA1, Q_WM)) == 0) + hw->flags |= SKY2_HW_CLK_POWER; break; case CHIP_ID_YUKON_EX: @@ -2836,6 +2920,11 @@ static int __devinit sky2_init(struct sky2_hw *hw) if (hw->pmd_type == 'L' || hw->pmd_type == 'S' || hw->pmd_type == 'P') hw->flags |= SKY2_HW_FIBRE_PHY; + hw->pm_cap = pci_find_capability(hw->pdev, PCI_CAP_ID_PM); + if (hw->pm_cap == 0) { + dev_err(&hw->pdev->dev, "cannot find PowerManagement capability\n"); + return -EIO; + } hw->ports = 1; t8 = sky2_read8(hw, B2_Y2_HW_RES); @@ -4407,7 +4496,7 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state) pci_save_state(pdev); pci_enable_wake(pdev, pci_choose_state(pdev, state), wol); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); + sky2_power_state(hw, pci_choose_state(pdev, state)); return 0; } @@ -4420,9 +4509,7 @@ static int sky2_resume(struct pci_dev *pdev) if (!hw) return 0; - err = pci_set_power_state(pdev, PCI_D0); - if (err) - goto out; + sky2_power_state(hw, PCI_D0); err = pci_restore_state(pdev); if (err) @@ -4490,8 +4577,7 @@ static void sky2_shutdown(struct pci_dev *pdev) pci_enable_wake(pdev, PCI_D3cold, wol); pci_disable_device(pdev); - pci_set_power_state(pdev, PCI_D3hot); - + sky2_power_state(hw, PCI_D3hot); } static struct pci_driver sky2_driver = { diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index d63106cd74b..1fa82bf029d 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -28,6 +28,11 @@ enum pci_dev_reg_1 { PCI_Y2_PHY2_POWD = 1<<27, /* Set PHY 2 to Power Down (YUKON-2) */ PCI_Y2_PHY1_POWD = 1<<26, /* Set PHY 1 to Power Down (YUKON-2) */ PCI_Y2_PME_LEGACY= 1<<15, /* PCI Express legacy power management mode */ + + PCI_PHY_LNK_TIM_MSK= 3L<<8,/* Bit 9.. 8: GPHY Link Trigger Timer */ + PCI_ENA_L1_EVENT = 1<<7, /* Enable PEX L1 Event */ + PCI_ENA_GPHY_LNK = 1<<6, /* Enable PEX L1 on GPHY Link down */ + PCI_FORCE_PEX_L1 = 1<<5, /* Force to PEX L1 */ }; enum pci_dev_reg_2 { @@ -45,7 +50,11 @@ enum pci_dev_reg_2 { /* PCI_OUR_REG_4 32 bit Our Register 4 (Yukon-ECU only) */ enum pci_dev_reg_4 { - /* (Link Training & Status State Machine) */ + /* (Link Training & Status State Machine) */ + P_PEX_LTSSM_STAT_MSK = 0x7fL<<25, /* Bit 31..25: PEX LTSSM Mask */ +#define P_PEX_LTSSM_STAT(x) ((x << 25) & P_PEX_LTSSM_STAT_MSK) + P_PEX_LTSSM_L1_STAT = 0x34, + P_PEX_LTSSM_DET_STAT = 0x01, P_TIMER_VALUE_MSK = 0xffL<<16, /* Bit 23..16: Timer Value Mask */ /* (Active State Power Management) */ P_FORCE_ASPM_REQUEST = 1<<15, /* Force ASPM Request (A1 only) */ @@ -454,6 +463,9 @@ enum yukon_ex_rev { CHIP_REV_YU_EX_A0 = 1, CHIP_REV_YU_EX_B0 = 2, }; +enum yukon_supr_rev { + CHIP_REV_YU_SU_A0 = 0, +}; /* B2_Y2_CLK_GATE 8 bit Clock Gating (Yukon-2 only) */ @@ -2059,7 +2071,9 @@ struct sky2_hw { #define SKY2_HW_NEW_LE 0x00000020 /* new LSOv2 format */ #define SKY2_HW_AUTO_TX_SUM 0x00000040 /* new IP decode for Tx */ #define SKY2_HW_ADV_POWER_CTL 0x00000080 /* additional PHY power regs */ +#define SKY2_HW_CLK_POWER 0x00000100 /* clock power management */ + int pm_cap; u8 chip_id; u8 chip_rev; u8 pmd_type; -- cgit v1.2.3-70-g09d2 From 20cbe73cd52f6476f4f7122e8fc801896ea3c4b6 Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Wed, 14 May 2008 16:20:17 -0700 Subject: net/s2io: set_rxd_buffer_pointer returns -ENOMEM, not ENOMEM Signed-off-by: Marcin Slusarz Cc: Ramkrishna Vepa Cc: Rastapur Santosh Cc: Sivakumar Subramani Cc: Sreenivasa Honnur Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/s2io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 326c94122b2..dcc953e57ab 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -6997,7 +6997,7 @@ static int rxd_owner_bit_reset(struct s2io_nic *sp) &skb,(u64 *)&temp0_64, (u64 *)&temp1_64, (u64 *)&temp2_64, - size) == ENOMEM) { + size) == -ENOMEM) { return 0; } -- cgit v1.2.3-70-g09d2 From c7d6b7d20f42996b28b6a26587a081ce0fc37304 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 16 Apr 2008 16:37:30 -0700 Subject: ts108: use netdev_alloc_skb Use netdev_alloc_skb for rx buffer allocation. This sets skb->dev and can be overriden for NUMA machines. This device is PowerPC only, so not tested or compiled. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/tsi108_eth.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c index c028facd934..febfaee44fe 100644 --- a/drivers/net/tsi108_eth.c +++ b/drivers/net/tsi108_eth.c @@ -803,7 +803,8 @@ static int tsi108_refill_rx(struct net_device *dev, int budget) int rx = data->rxhead; struct sk_buff *skb; - data->rxskbs[rx] = skb = dev_alloc_skb(TSI108_RXBUF_SIZE + 2); + data->rxskbs[rx] = skb = netdev_alloc_skb(dev, + TSI108_RXBUF_SIZE + 2); if (!skb) break; @@ -1352,8 +1353,9 @@ static int tsi108_open(struct net_device *dev) data->rxhead = 0; for (i = 0; i < TSI108_RXRING_LEN; i++) { - struct sk_buff *skb = dev_alloc_skb(TSI108_RXBUF_SIZE + NET_IP_ALIGN); + struct sk_buff *skb; + skb = netdev_alloc_skb(dev, TSI108_RXBUF_SIZE + NET_IP_ALIGN); if (!skb) { /* Bah. No memory for now, but maybe we'll get * some more later. -- cgit v1.2.3-70-g09d2 From e83728c7b0ce92e57aa90eb4fc271a29d7a393d5 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 16 Apr 2008 16:37:35 -0700 Subject: ns8320: use netdev_alloc_skb Use netdev_alloc_skb. This sets skb->dev and allows arch specific allocation. Compile tested only. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/ns83820.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index b42c05f84be..ff449619f04 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -585,16 +585,13 @@ static inline int rx_refill(struct net_device *ndev, gfp_t gfp) for (i=0; idata & 0xf; - res = 0x10 - res; - res &= 0xf; - skb_reserve(skb, res); - + skb_reserve(skb, skb->data - PTR_ALIGN(skb->data, 16)); if (gfp != GFP_ATOMIC) spin_lock_irqsave(&dev->rx_info.lock, flags); res = ns83820_add_rx_skb(dev, skb); -- cgit v1.2.3-70-g09d2 From 5a18c343a6bee4b38965f14a40ccb95306641f87 Mon Sep 17 00:00:00 2001 From: Pau Oliva Fora Date: Mon, 2 Jun 2008 00:38:35 -0400 Subject: Input: add HTC Shift Touchscreen Driver Signed-off-by: Pau Oliva Fora Signed-off-by: Dmitry Torokhov --- MAINTAINERS | 6 + drivers/input/touchscreen/Kconfig | 12 ++ drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/htcpen.c | 255 +++++++++++++++++++++++++++++++++++++ 4 files changed, 274 insertions(+) create mode 100644 drivers/input/touchscreen/htcpen.c (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index bc1c0088dc4..5f12d73142a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1928,6 +1928,12 @@ M: mikulas@artax.karlin.mff.cuni.cz W: http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi S: Maintained +HTCPEN TOUCHSCREEN DRIVER +P: Pau Oliva Fora +M: pof@eslack.org +L: linux-input@vger.kernel.org +S: Maintained + HUGETLB FILESYSTEM P: William Irwin M: wli@holomorphy.com diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 2cb4df0e0a7..030a8973485 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -134,6 +134,18 @@ config TOUCHSCREEN_HP7XX To compile this driver as a module, choose M here: the module will be called jornada720_ts. +config TOUCHSCREEN_HTCPEN + tristate "HTC Shift X9500 touchscreen" + depends on ISA + help + Say Y here if you have an HTC Shift UMPC also known as HTC X9500 + Clio / Shangrila and want to support the built-in touchscreen. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called htcpen. + config TOUCHSCREEN_PENMOUNT tristate "Penmount serial touchscreen" select SERIO diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 30e86816cd4..64a11f443dc 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o obj-$(CONFIG_TOUCHSCREEN_HP7XX) += jornada720_ts.o +obj-$(CONFIG_TOUCHSCREEN_HTCPEN) += htcpen.o obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o diff --git a/drivers/input/touchscreen/htcpen.c b/drivers/input/touchscreen/htcpen.c new file mode 100644 index 00000000000..62811de6f18 --- /dev/null +++ b/drivers/input/touchscreen/htcpen.c @@ -0,0 +1,255 @@ +/* + * HTC Shift touchscreen driver + * + * Copyright (C) 2008 Pau Oliva Fora + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Pau Oliva Fora "); +MODULE_DESCRIPTION("HTC Shift touchscreen driver"); +MODULE_LICENSE("GPL"); + +#define HTCPEN_PORT_IRQ_CLEAR 0x068 +#define HTCPEN_PORT_INIT 0x06c +#define HTCPEN_PORT_INDEX 0x0250 +#define HTCPEN_PORT_DATA 0x0251 +#define HTCPEN_IRQ 3 + +#define DEVICE_ENABLE 0xa2 +#define DEVICE_DISABLE 0xa3 + +#define X_INDEX 3 +#define Y_INDEX 5 +#define TOUCH_INDEX 0xb +#define LSB_XY_INDEX 0xc +#define X_AXIS_MAX 2040 +#define Y_AXIS_MAX 2040 + +static int invert_x; +module_param(invert_x, bool, 0644); +MODULE_PARM_DESC(invert_x, "If set, X axis is inverted"); +static int invert_y; +module_param(invert_y, bool, 0644); +MODULE_PARM_DESC(invert_y, "If set, Y axis is inverted"); + +static struct pnp_device_id pnp_ids[] = { + { .id = "PNP0cc0" }, + { .id = "" } +}; +MODULE_DEVICE_TABLE(pnp, pnp_ids); + +static irqreturn_t htcpen_interrupt(int irq, void *handle) +{ + struct input_dev *htcpen_dev = handle; + unsigned short x, y, xy; + + /* 0 = press; 1 = release */ + outb_p(TOUCH_INDEX, HTCPEN_PORT_INDEX); + + if (inb_p(HTCPEN_PORT_DATA)) { + input_report_key(htcpen_dev, BTN_TOUCH, 0); + } else { + outb_p(X_INDEX, HTCPEN_PORT_INDEX); + x = inb_p(HTCPEN_PORT_DATA); + + outb_p(Y_INDEX, HTCPEN_PORT_INDEX); + y = inb_p(HTCPEN_PORT_DATA); + + outb_p(LSB_XY_INDEX, HTCPEN_PORT_INDEX); + xy = inb_p(HTCPEN_PORT_DATA); + + /* get high resolution value of X and Y using LSB */ + x = X_AXIS_MAX - ((x * 8) + ((xy >> 4) & 0xf)); + y = (y * 8) + (xy & 0xf); + if (invert_x) + x = X_AXIS_MAX - x; + if (invert_y) + y = Y_AXIS_MAX - y; + + if (x != X_AXIS_MAX && x != 0) { + input_report_key(htcpen_dev, BTN_TOUCH, 1); + input_report_abs(htcpen_dev, ABS_X, x); + input_report_abs(htcpen_dev, ABS_Y, y); + } + } + + input_sync(htcpen_dev); + + inb_p(HTCPEN_PORT_IRQ_CLEAR); + + return IRQ_HANDLED; +} + +static int htcpen_open(struct input_dev *dev) +{ + outb_p(DEVICE_ENABLE, HTCPEN_PORT_INIT); + + return 0; +} + +static void htcpen_close(struct input_dev *dev) +{ + outb_p(DEVICE_DISABLE, HTCPEN_PORT_INIT); + synchronize_irq(HTCPEN_IRQ); +} + +static int __devinit htcpen_isa_probe(struct device *dev, unsigned int id) +{ + struct input_dev *htcpen_dev; + int err = -EBUSY; + + if (!request_region(HTCPEN_PORT_IRQ_CLEAR, 1, "htcpen")) { + printk(KERN_ERR "htcpen: unable to get IO region 0x%x\n", + HTCPEN_PORT_IRQ_CLEAR); + goto request_region1_failed; + } + + if (!request_region(HTCPEN_PORT_INIT, 1, "htcpen")) { + printk(KERN_ERR "htcpen: unable to get IO region 0x%x\n", + HTCPEN_PORT_INIT); + goto request_region2_failed; + } + + if (!request_region(HTCPEN_PORT_INDEX, 2, "htcpen")) { + printk(KERN_ERR "htcpen: unable to get IO region 0x%x\n", + HTCPEN_PORT_INDEX); + goto request_region3_failed; + } + + htcpen_dev = input_allocate_device(); + if (!htcpen_dev) { + printk(KERN_ERR "htcpen: can't allocate device\n"); + err = -ENOMEM; + goto input_alloc_failed; + } + + htcpen_dev->name = "HTC Shift EC TouchScreen"; + htcpen_dev->id.bustype = BUS_ISA; + + htcpen_dev->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY); + htcpen_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + input_set_abs_params(htcpen_dev, ABS_X, 0, X_AXIS_MAX, 0, 0); + input_set_abs_params(htcpen_dev, ABS_Y, 0, Y_AXIS_MAX, 0, 0); + + htcpen_dev->open = htcpen_open; + htcpen_dev->close = htcpen_close; + + err = request_irq(HTCPEN_IRQ, htcpen_interrupt, 0, "htcpen", + htcpen_dev); + if (err) { + printk(KERN_ERR "htcpen: irq busy\n"); + goto request_irq_failed; + } + + inb_p(HTCPEN_PORT_IRQ_CLEAR); + + err = input_register_device(htcpen_dev); + if (err) + goto input_register_failed; + + dev_set_drvdata(dev, htcpen_dev); + + return 0; + + input_register_failed: + free_irq(HTCPEN_IRQ, htcpen_dev); + request_irq_failed: + input_free_device(htcpen_dev); + input_alloc_failed: + release_region(HTCPEN_PORT_INDEX, 2); + request_region3_failed: + release_region(HTCPEN_PORT_INIT, 1); + request_region2_failed: + release_region(HTCPEN_PORT_IRQ_CLEAR, 1); + request_region1_failed: + return err; +} + +static int __devexit htcpen_isa_remove(struct device *dev, unsigned int id) +{ + struct input_dev *htcpen_dev = dev_get_drvdata(dev); + + input_unregister_device(htcpen_dev); + + free_irq(HTCPEN_IRQ, htcpen_dev); + + release_region(HTCPEN_PORT_INDEX, 2); + release_region(HTCPEN_PORT_INIT, 1); + release_region(HTCPEN_PORT_IRQ_CLEAR, 1); + + dev_set_drvdata(dev, NULL); + + return 0; +} + +#ifdef CONFIG_PM +static int htcpen_isa_suspend(struct device *dev, unsigned int n, + pm_message_t state) +{ + outb_p(DEVICE_DISABLE, HTCPEN_PORT_INIT); + + return 0; +} + +static int htcpen_isa_resume(struct device *dev, unsigned int n) +{ + outb_p(DEVICE_ENABLE, HTCPEN_PORT_INIT); + + return 0; +} +#endif + +static struct isa_driver htcpen_isa_driver = { + .probe = htcpen_isa_probe, + .remove = __devexit_p(htcpen_isa_remove), +#ifdef CONFIG_PM + .suspend = htcpen_isa_suspend, + .resume = htcpen_isa_resume, +#endif + .driver = { + .owner = THIS_MODULE, + .name = "htcpen", + } +}; + +static struct dmi_system_id __initdata htcshift_dmi_table[] = { + { + .ident = "Shift", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "High Tech Computer Corp"), + DMI_MATCH(DMI_PRODUCT_NAME, "Shift"), + }, + }, + { } +}; + +static int __init htcpen_isa_init(void) +{ + if (!dmi_check_system(htcshift_dmi_table)) + return -ENODEV; + + return isa_register_driver(&htcpen_isa_driver, 1); +} + +static void __exit htcpen_isa_exit(void) +{ + isa_unregister_driver(&htcpen_isa_driver); +} + +module_init(htcpen_isa_init); +module_exit(htcpen_isa_exit); -- cgit v1.2.3-70-g09d2 From f6d65610df3bd4e7138da03aec391224219df135 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 2 Jun 2008 00:39:45 -0400 Subject: Input: atkbd - use ushort instead of uchar keymap Since some of the keycodes defined in input.h have values greater than 255 we should use unsigned shorts in keymaps. Tested-by: Carlos Corbacho Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/atkbd.c | 20 ++++++++++---------- include/linux/input.h | 2 ++ 2 files changed, 12 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index 4a95adc4cc7..56857d1e56d 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -68,7 +68,7 @@ MODULE_PARM_DESC(extra, "Enable extra LEDs and keys on IBM RapidAcces, EzKey and * are loadable via an userland utility. */ -static unsigned char atkbd_set2_keycode[512] = { +static const unsigned short atkbd_set2_keycode[512] = { #ifdef CONFIG_KEYBOARD_ATKBD_HP_KEYCODES @@ -99,7 +99,7 @@ static unsigned char atkbd_set2_keycode[512] = { #endif }; -static unsigned char atkbd_set3_keycode[512] = { +static const unsigned short atkbd_set3_keycode[512] = { 0, 0, 0, 0, 0, 0, 0, 59, 1,138,128,129,130, 15, 41, 60, 131, 29, 42, 86, 58, 16, 2, 61,133, 56, 44, 31, 30, 17, 3, 62, @@ -115,7 +115,7 @@ static unsigned char atkbd_set3_keycode[512] = { 148,149,147,140 }; -static unsigned char atkbd_unxlate_table[128] = { +static const unsigned short atkbd_unxlate_table[128] = { 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13, 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27, 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42, @@ -161,7 +161,7 @@ static unsigned char atkbd_unxlate_table[128] = { #define ATKBD_SCR_LEFT 249 #define ATKBD_SCR_RIGHT 248 -#define ATKBD_SPECIAL 248 +#define ATKBD_SPECIAL ATKBD_SCR_RIGHT #define ATKBD_LED_EVENT_BIT 0 #define ATKBD_REP_EVENT_BIT 1 @@ -173,7 +173,7 @@ static unsigned char atkbd_unxlate_table[128] = { #define ATKBD_XL_HANGEUL 0x10 #define ATKBD_XL_HANJA 0x20 -static struct { +static const struct { unsigned char keycode; unsigned char set2; } atkbd_scroll_keys[] = { @@ -200,7 +200,7 @@ struct atkbd { char phys[32]; unsigned short id; - unsigned char keycode[512]; + unsigned short keycode[512]; DECLARE_BITMAP(force_release_mask, 512); unsigned char set; unsigned char translated; @@ -357,7 +357,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, unsigned int code = data; int scroll = 0, hscroll = 0, click = -1; int value; - unsigned char keycode; + unsigned short keycode; #ifdef ATKBD_DEBUG printk(KERN_DEBUG "atkbd.c: Received %02x flags %02x\n", data, flags); @@ -959,16 +959,16 @@ static void atkbd_set_device_attrs(struct atkbd *atkbd) input_dev->evbit[0] |= BIT_MASK(EV_REL); input_dev->relbit[0] = BIT_MASK(REL_WHEEL) | BIT_MASK(REL_HWHEEL); - set_bit(BTN_MIDDLE, input_dev->keybit); + __set_bit(BTN_MIDDLE, input_dev->keybit); } input_dev->keycode = atkbd->keycode; - input_dev->keycodesize = sizeof(unsigned char); + input_dev->keycodesize = sizeof(unsigned short); input_dev->keycodemax = ARRAY_SIZE(atkbd_set2_keycode); for (i = 0; i < 512; i++) if (atkbd->keycode[i] && atkbd->keycode[i] < ATKBD_SPECIAL) - set_bit(atkbd->keycode[i], input_dev->keybit); + __set_bit(atkbd->keycode[i], input_dev->keybit); } /* diff --git a/include/linux/input.h b/include/linux/input.h index eff711d8a45..af9c6314153 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -373,6 +373,8 @@ struct input_absinfo { #define KEY_WIMAX 246 +/* Range 248 - 255 is reserved for special needs of AT keyboard driver */ + #define BTN_MISC 0x100 #define BTN_0 0x100 #define BTN_1 0x101 -- cgit v1.2.3-70-g09d2 From e8ef4347099584b49ecf74144ad2089b724292cf Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 2 Jun 2008 00:41:57 -0400 Subject: Input: serio - remove pending events when unregistering driver That fixes an opps when driver is repeatedly loaded and unloaded in a tight loop. Tested-by: Roland Kletzing Signed-off-by: Dmitry Torokhov --- drivers/input/serio/serio.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 7f5293828fb..78f2abb5c11 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -331,9 +331,10 @@ static void serio_handle_event(void) } /* - * Remove all events that have been submitted for a given serio port. + * Remove all events that have been submitted for a given + * object, be it serio port or driver. */ -static void serio_remove_pending_events(struct serio *serio) +static void serio_remove_pending_events(void *object) { struct list_head *node, *next; struct serio_event *event; @@ -343,7 +344,7 @@ static void serio_remove_pending_events(struct serio *serio) list_for_each_safe(node, next, &serio_event_list) { event = list_entry(node, struct serio_event, node); - if (event->object == serio) { + if (event->object == object) { list_del_init(node); serio_free_event(event); } @@ -837,7 +838,9 @@ void serio_unregister_driver(struct serio_driver *drv) struct serio *serio; mutex_lock(&serio_mutex); + drv->manual_bind = 1; /* so serio_find_driver ignores it */ + serio_remove_pending_events(drv); start_over: list_for_each_entry(serio, &serio_list, node) { -- cgit v1.2.3-70-g09d2 From c78277288e3d561d55fb48bc0fe8d6e2cf4d0880 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Thu, 29 May 2008 09:02:19 +0100 Subject: CONFIG_PM_SLEEP fix: xen: fix compilation when CONFIG_PM_SLEEP is disabled Xen save/restore depends on CONFIG_PM_SLEEP being set for device_power_up/down. Signed-off-by: Jeremy Fitzhardinge Acked-by: Randy Dunlap Signed-off-by: Ingo Molnar --- drivers/xen/manage.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c index 675c3dd2396..5b546e365f0 100644 --- a/drivers/xen/manage.c +++ b/drivers/xen/manage.c @@ -31,6 +31,7 @@ enum shutdown_state { /* Ignore multiple shutdown requests. */ static enum shutdown_state shutting_down = SHUTDOWN_INVALID; +#ifdef CONFIG_PM_SLEEP static int xen_suspend(void *data) { int *cancelled = data; @@ -121,6 +122,7 @@ out: #endif shutting_down = SHUTDOWN_INVALID; } +#endif /* CONFIG_PM_SLEEP */ static void shutdown_handler(struct xenbus_watch *watch, const char **vec, unsigned int len) -- cgit v1.2.3-70-g09d2 From 04ba0f656f7580d8a51a5b3441e088309141b67a Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 24 Apr 2008 15:23:25 +0100 Subject: [ARM] pxa: avoid registering multiple pxa2xx_pcmcia devices cm_x270 and mainstone both register their PCMCIA devices using the same name, resulting in a warning message from the kernel. Avoid this by making the cm_x270 and mainstone PCMCIA initialisation conditional on the machine type we're running on. Signed-off-by: Russell King --- drivers/pcmcia/pxa2xx_cm_x270.c | 4 ++++ drivers/pcmcia/pxa2xx_mainstone.c | 4 ++++ 2 files changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/pcmcia/pxa2xx_cm_x270.c b/drivers/pcmcia/pxa2xx_cm_x270.c index e7ab060ff11..4a6c020afb3 100644 --- a/drivers/pcmcia/pxa2xx_cm_x270.c +++ b/drivers/pcmcia/pxa2xx_cm_x270.c @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -147,6 +148,9 @@ static int __init cmx270_pcmcia_init(void) { int ret; + if (!machine_is_armcore()) + return -ENODEV; + cmx270_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1); if (!cmx270_pcmcia_device) diff --git a/drivers/pcmcia/pxa2xx_mainstone.c b/drivers/pcmcia/pxa2xx_mainstone.c index 145b85e0f02..36a59960b5a 100644 --- a/drivers/pcmcia/pxa2xx_mainstone.c +++ b/drivers/pcmcia/pxa2xx_mainstone.c @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -153,6 +154,9 @@ static int __init mst_pcmcia_init(void) { int ret; + if (!machine_is_mainstone()) + return -ENODEV; + mst_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1); if (!mst_pcmcia_device) return -ENOMEM; -- cgit v1.2.3-70-g09d2 From 4e5e8de0dbdeb08df2b4c15fa2b0ba2216091793 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 24 Apr 2008 15:28:11 +0100 Subject: [ARM] pxa: avoid kfreeing static data if platform device fails to register When a dynamically allocated platform device is 'put', the platform device's platform_data is kfree'd. This is bad if it's pointing at static data. Use the provided function to register platform data for these devices. This also means we can mark the pcmcia ops structures as __initdata. Signed-off-by: Russell King --- drivers/pcmcia/pxa2xx_cm_x270.c | 11 +++++++---- drivers/pcmcia/pxa2xx_mainstone.c | 9 +++++---- drivers/pcmcia/pxa2xx_sharpsl.c | 12 +++++++----- 3 files changed, 19 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/pxa2xx_cm_x270.c b/drivers/pcmcia/pxa2xx_cm_x270.c index 4a6c020afb3..f123fce65f2 100644 --- a/drivers/pcmcia/pxa2xx_cm_x270.c +++ b/drivers/pcmcia/pxa2xx_cm_x270.c @@ -131,7 +131,7 @@ static void cmx270_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) } -static struct pcmcia_low_level cmx270_pcmcia_ops = { +static struct pcmcia_low_level cmx270_pcmcia_ops __initdata = { .owner = THIS_MODULE, .hw_init = cmx270_pcmcia_hw_init, .hw_shutdown = cmx270_pcmcia_shutdown, @@ -156,10 +156,13 @@ static int __init cmx270_pcmcia_init(void) if (!cmx270_pcmcia_device) return -ENOMEM; - cmx270_pcmcia_device->dev.platform_data = &cmx270_pcmcia_ops; + ret = platform_device_add_data(cmx270_pcmcia_device, &cmx270_pcmcia_ops, + sizeof(cmx270_pcmcia_ops)); - printk(KERN_INFO "Registering cm-x270 PCMCIA interface.\n"); - ret = platform_device_add(cmx270_pcmcia_device); + if (ret == 0) { + printk(KERN_INFO "Registering cm-x270 PCMCIA interface.\n"); + ret = platform_device_add(cmx270_pcmcia_device); + } if (ret) platform_device_put(cmx270_pcmcia_device); diff --git a/drivers/pcmcia/pxa2xx_mainstone.c b/drivers/pcmcia/pxa2xx_mainstone.c index 36a59960b5a..92d1cc33808 100644 --- a/drivers/pcmcia/pxa2xx_mainstone.c +++ b/drivers/pcmcia/pxa2xx_mainstone.c @@ -137,7 +137,7 @@ static void mst_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) { } -static struct pcmcia_low_level mst_pcmcia_ops = { +static struct pcmcia_low_level mst_pcmcia_ops __initdata = { .owner = THIS_MODULE, .hw_init = mst_pcmcia_hw_init, .hw_shutdown = mst_pcmcia_hw_shutdown, @@ -161,9 +161,10 @@ static int __init mst_pcmcia_init(void) if (!mst_pcmcia_device) return -ENOMEM; - mst_pcmcia_device->dev.platform_data = &mst_pcmcia_ops; - - ret = platform_device_add(mst_pcmcia_device); + ret = platform_device_add_data(mst_pcmcia_device, &mst_pcmcia_ops, + sizeof(mst_pcmcia_ops)); + if (ret == 0) + ret = platform_device_add(mst_pcmcia_device); if (ret) platform_device_put(mst_pcmcia_device); diff --git a/drivers/pcmcia/pxa2xx_sharpsl.c b/drivers/pcmcia/pxa2xx_sharpsl.c index d5c33bd78d6..d71f93d4583 100644 --- a/drivers/pcmcia/pxa2xx_sharpsl.c +++ b/drivers/pcmcia/pxa2xx_sharpsl.c @@ -222,7 +222,7 @@ static void sharpsl_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) sharpsl_pcmcia_init_reset(skt); } -static struct pcmcia_low_level sharpsl_pcmcia_ops = { +static struct pcmcia_low_level sharpsl_pcmcia_ops __initdata = { .owner = THIS_MODULE, .hw_init = sharpsl_pcmcia_hw_init, .hw_shutdown = sharpsl_pcmcia_hw_shutdown, @@ -261,10 +261,12 @@ static int __init sharpsl_pcmcia_init(void) if (!sharpsl_pcmcia_device) return -ENOMEM; - sharpsl_pcmcia_device->dev.platform_data = &sharpsl_pcmcia_ops; - sharpsl_pcmcia_device->dev.parent = platform_scoop_config->devs[0].dev; - - ret = platform_device_add(sharpsl_pcmcia_device); + ret = platform_device_add_data(sharpsl_pcmcia_device, + &sharpsl_pcmcia_ops, sizeof(sharpsl_pcmcia_ops)); + if (ret == 0) { + sharpsl_pcmcia_device->dev.parent = platform_scoop_config->devs[0].dev; + ret = platform_device_add(sharpsl_pcmcia_device); + } if (ret) platform_device_put(sharpsl_pcmcia_device); -- cgit v1.2.3-70-g09d2 From 6b71dbf65e63c13202fb18773a5fd2d4415b6b2e Mon Sep 17 00:00:00 2001 From: Stelian Pop Date: Sat, 5 Apr 2008 21:16:15 +0100 Subject: [ARM] 4935/1: AT91CAP9: enable RTC-on-RTT in defconfig. Update the help text for RTC_DRV_AT91SAM9 to mention that the option apply to AT91CAP9 processors too, and enable it in the defconfig. Signed-off-by: Stelian Pop Signed-off-by: Andrew Victor Signed-off-by: Russell King --- arch/arm/configs/at91cap9adk_defconfig | 54 +++++++++++++++++++++++++++++++++- drivers/rtc/Kconfig | 9 +++--- 2 files changed, 58 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/arch/arm/configs/at91cap9adk_defconfig b/arch/arm/configs/at91cap9adk_defconfig index 39ca662c079..47e722511bd 100644 --- a/arch/arm/configs/at91cap9adk_defconfig +++ b/arch/arm/configs/at91cap9adk_defconfig @@ -951,7 +951,59 @@ CONFIG_MMC_AT91=y # CONFIG_MMC_SPI is not set # CONFIG_NEW_LEDS is not set CONFIG_RTC_LIB=y -# CONFIG_RTC_CLASS is not set +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RS5C348 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# +CONFIG_RTC_DRV_AT91SAM9=y +CONFIG_RTC_DRV_AT91SAM9_RTT=0 +CONFIG_RTC_DRV_AT91SAM9_GPBR=0 # # File systems diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 6cc2c033023..7fb4c48acc8 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -484,12 +484,13 @@ config RTC_DRV_AT91RM9200 this is powered by the backup power supply. config RTC_DRV_AT91SAM9 - tristate "AT91SAM9x" + tristate "AT91SAM9x/AT91CAP9" depends on ARCH_AT91 && !(ARCH_AT91RM9200 || ARCH_AT91X40) help - RTC driver for the Atmel AT91SAM9x internal RTT (Real Time Timer). - These timers are powered by the backup power supply (such as a - small coin cell battery), but do not need to be used as RTCs. + RTC driver for the Atmel AT91SAM9x and AT91CAP9 internal RTT + (Real Time Timer). These timers are powered by the backup power + supply (such as a small coin cell battery), but do not need to + be used as RTCs. (On AT91SAM9rl chips you probably want to use the dedicated RTC module and leave the RTT available for other uses.) -- cgit v1.2.3-70-g09d2 From ba45ca435060614e595a107ac323a36b52619d7d Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Tue, 8 Apr 2008 13:59:18 +0100 Subject: [ARM] 4940/1: AT91: UDPHS driver: SAM9RL board and cpu integration. Adds support for the USB High Speed Device Port on the AT91SAM9RL system on chip. The AT91SAM9RL uses the same UDPHS IP as the AVR32 and the AT91CAP9 (atmel_usba_udc driver). Signed-off-by: Nicolas Ferre Acked-by: Andrew Victor Signed-off-by: Russell King --- arch/arm/mach-at91/at91sam9rl_devices.c | 95 +++++++++++++++++++++++++++++++++ arch/arm/mach-at91/board-sam9rlek.c | 10 ++++ arch/arm/mach-at91/clock.c | 9 ++-- drivers/usb/gadget/Kconfig | 4 +- include/asm-arm/arch-at91/at91sam9rl.h | 2 +- 5 files changed, 113 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c index 450db304936..8507dd02fe9 100644 --- a/arch/arm/mach-at91/at91sam9rl_devices.c +++ b/arch/arm/mach-at91/at91sam9rl_devices.c @@ -25,6 +25,101 @@ #include "generic.h" +/* -------------------------------------------------------------------- + * USB HS Device (Gadget) + * -------------------------------------------------------------------- */ + +#if defined(CONFIG_USB_GADGET_ATMEL_USBA) || defined(CONFIG_USB_GADGET_ATMEL_USBA_MODULE) + +static struct resource usba_udc_resources[] = { + [0] = { + .start = AT91SAM9RL_UDPHS_FIFO, + .end = AT91SAM9RL_UDPHS_FIFO + SZ_512K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AT91SAM9RL_BASE_UDPHS, + .end = AT91SAM9RL_BASE_UDPHS + SZ_1K - 1, + .flags = IORESOURCE_MEM, + }, + [2] = { + .start = AT91SAM9RL_ID_UDPHS, + .end = AT91SAM9RL_ID_UDPHS, + .flags = IORESOURCE_IRQ, + }, +}; + +#define EP(nam, idx, maxpkt, maxbk, dma, isoc) \ + [idx] = { \ + .name = nam, \ + .index = idx, \ + .fifo_size = maxpkt, \ + .nr_banks = maxbk, \ + .can_dma = dma, \ + .can_isoc = isoc, \ + } + +static struct usba_ep_data usba_udc_ep[] __initdata = { + EP("ep0", 0, 64, 1, 0, 0), + EP("ep1", 1, 1024, 2, 1, 1), + EP("ep2", 2, 1024, 2, 1, 1), + EP("ep3", 3, 1024, 3, 1, 0), + EP("ep4", 4, 1024, 3, 1, 0), + EP("ep5", 5, 1024, 3, 1, 1), + EP("ep6", 6, 1024, 3, 1, 1), +}; + +#undef EP + +/* + * pdata doesn't have room for any endpoints, so we need to + * append room for the ones we need right after it. + */ +static struct { + struct usba_platform_data pdata; + struct usba_ep_data ep[7]; +} usba_udc_data; + +static struct platform_device at91_usba_udc_device = { + .name = "atmel_usba_udc", + .id = -1, + .dev = { + .platform_data = &usba_udc_data.pdata, + }, + .resource = usba_udc_resources, + .num_resources = ARRAY_SIZE(usba_udc_resources), +}; + +void __init at91_add_device_usba(struct usba_platform_data *data) +{ + /* + * Invalid pins are 0 on AT91, but the usba driver is shared + * with AVR32, which use negative values instead. Once/if + * gpio_is_valid() is ported to AT91, revisit this code. + */ + usba_udc_data.pdata.vbus_pin = -EINVAL; + usba_udc_data.pdata.num_ep = ARRAY_SIZE(usba_udc_ep); + memcpy(usba_udc_data.ep, usba_udc_ep, sizeof(usba_udc_ep));; + + if (data && data->vbus_pin > 0) { + at91_set_gpio_input(data->vbus_pin, 0); + at91_set_deglitch(data->vbus_pin, 1); + usba_udc_data.pdata.vbus_pin = data->vbus_pin; + } + + /* Pullup pin is handled internally by USB device peripheral */ + + /* Clocks */ + at91_clock_associate("utmi_clk", &at91_usba_udc_device.dev, "hclk"); + at91_clock_associate("udphs_clk", &at91_usba_udc_device.dev, "pclk"); + + platform_device_register(&at91_usba_udc_device); +} +#else +void __init at91_add_device_usba(struct usba_platform_data *data) {} +#endif + + /* -------------------------------------------------------------------- * MMC / SD * -------------------------------------------------------------------- */ diff --git a/arch/arm/mach-at91/board-sam9rlek.c b/arch/arm/mach-at91/board-sam9rlek.c index ffc0597aee8..b6a70fc735c 100644 --- a/arch/arm/mach-at91/board-sam9rlek.c +++ b/arch/arm/mach-at91/board-sam9rlek.c @@ -55,6 +55,14 @@ static void __init ek_init_irq(void) } +/* + * USB HS Device port + */ +static struct usba_platform_data __initdata ek_usba_udc_data = { + .vbus_pin = AT91_PIN_PA8, +}; + + /* * MCI (SD/MMC) */ @@ -175,6 +183,8 @@ static void __init ek_board_init(void) { /* Serial */ at91_add_device_serial(); + /* USB HS */ + at91_add_device_usba(&ek_usba_udc_data); /* I2C */ at91_add_device_i2c(NULL, 0); /* NAND */ diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c index b87772cd3d3..e8ce8f0f3ed 100644 --- a/arch/arm/mach-at91/clock.c +++ b/arch/arm/mach-at91/clock.c @@ -391,8 +391,9 @@ static int at91_clk_show(struct seq_file *s, void *unused) seq_printf(s, "MOR = %8x\n", at91_sys_read(AT91_CKGR_MOR)); seq_printf(s, "MCFR = %8x\n", at91_sys_read(AT91_CKGR_MCFR)); seq_printf(s, "PLLA = %8x\n", at91_sys_read(AT91_CKGR_PLLAR)); - seq_printf(s, "PLLB = %8x\n", at91_sys_read(AT91_CKGR_PLLBR)); - if (cpu_is_at91cap9()) + if (!cpu_is_at91sam9rl()) + seq_printf(s, "PLLB = %8x\n", at91_sys_read(AT91_CKGR_PLLBR)); + if (cpu_is_at91cap9() || cpu_is_at91sam9rl()) seq_printf(s, "UCKR = %8x\n", uckr = at91_sys_read(AT91_CKGR_UCKR)); seq_printf(s, "MCKR = %8x\n", at91_sys_read(AT91_PMC_MCKR)); seq_printf(s, "SR = %8x\n", sr = at91_sys_read(AT91_PMC_SR)); @@ -610,7 +611,7 @@ int __init at91_clock_init(unsigned long main_clock) /* * USB HS clock init */ - if (cpu_is_at91cap9()) { + if (cpu_is_at91cap9() || cpu_is_at91sam9rl()) { /* * multiplier is hard-wired to 40 * (obtain the USB High Speed 480 MHz when input is 12 MHz) @@ -635,7 +636,7 @@ int __init at91_clock_init(unsigned long main_clock) for (i = 0; i < ARRAY_SIZE(standard_pmc_clocks); i++) list_add_tail(&standard_pmc_clocks[i]->node, &clocks); - if (cpu_is_at91cap9()) + if (cpu_is_at91cap9() || cpu_is_at91sam9rl()) list_add_tail(&utmi_clk.node, &clocks); /* MCK and CPU clock are "always on" */ diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 6e784d2db42..3565d435282 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -118,10 +118,10 @@ config USB_AMD5536UDC config USB_GADGET_ATMEL_USBA boolean "Atmel USBA" select USB_GADGET_DUALSPEED - depends on AVR32 || ARCH_AT91CAP9 + depends on AVR32 || ARCH_AT91CAP9 || ARCH_AT91SAM9RL help USBA is the integrated high-speed USB Device controller on - the AT32AP700x and AT91CAP9 processors from Atmel. + the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel. config USB_ATMEL_USBA tristate diff --git a/include/asm-arm/arch-at91/at91sam9rl.h b/include/asm-arm/arch-at91/at91sam9rl.h index 16d2832f6c0..622e56f81d4 100644 --- a/include/asm-arm/arch-at91/at91sam9rl.h +++ b/include/asm-arm/arch-at91/at91sam9rl.h @@ -110,6 +110,6 @@ #define AT91SAM9RL_ROM_SIZE (2 * SZ_16K) /* Internal ROM size (32Kb) */ #define AT91SAM9RL_LCDC_BASE 0x00500000 /* LCD Controller */ -#define AT91SAM9RL_UDPHS_BASE 0x00600000 /* USB Device HS controller */ +#define AT91SAM9RL_UDPHS_FIFO 0x00600000 /* USB Device HS controller */ #endif -- cgit v1.2.3-70-g09d2 From 39ab9ddeb3e9573a1ea9a17a1431ea5c81681964 Mon Sep 17 00:00:00 2001 From: Eric Miao Date: Mon, 2 Jun 2008 11:20:55 -0400 Subject: Input: pxa27x_keypad - add wakeup support Signed-off-by: Eric Miao Acked-by: Russell King Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/pxa27x_keypad.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c index 3dea0c5077a..c7c9599b315 100644 --- a/drivers/input/keyboard/pxa27x_keypad.c +++ b/drivers/input/keyboard/pxa27x_keypad.c @@ -105,6 +105,8 @@ struct pxa27x_keypad { struct input_dev *input_dev; void __iomem *mmio_base; + int irq; + /* matrix key code map */ unsigned int matrix_keycodes[MAX_MATRIX_KEY_NUM]; @@ -385,6 +387,10 @@ static int pxa27x_keypad_suspend(struct platform_device *pdev, pm_message_t stat struct pxa27x_keypad *keypad = platform_get_drvdata(pdev); clk_disable(keypad->clk); + + if (device_may_wakeup(&pdev->dev)) + enable_irq_wake(keypad->irq); + return 0; } @@ -393,6 +399,9 @@ static int pxa27x_keypad_resume(struct platform_device *pdev) struct pxa27x_keypad *keypad = platform_get_drvdata(pdev); struct input_dev *input_dev = keypad->input_dev; + if (device_may_wakeup(&pdev->dev)) + disable_irq_wake(keypad->irq); + mutex_lock(&input_dev->mutex); if (input_dev->users) { @@ -497,6 +506,8 @@ static int __devinit pxa27x_keypad_probe(struct platform_device *pdev) goto failed_free_dev; } + keypad->irq = irq; + /* Register the input device */ error = input_register_device(input_dev); if (error) { @@ -504,6 +515,8 @@ static int __devinit pxa27x_keypad_probe(struct platform_device *pdev) goto failed_free_irq; } + device_init_wakeup(&pdev->dev, 1); + return 0; failed_free_irq: @@ -527,7 +540,7 @@ static int __devexit pxa27x_keypad_remove(struct platform_device *pdev) struct pxa27x_keypad *keypad = platform_get_drvdata(pdev); struct resource *res; - free_irq(platform_get_irq(pdev, 0), pdev); + free_irq(keypad->irq, pdev); clk_disable(keypad->clk); clk_put(keypad->clk); -- cgit v1.2.3-70-g09d2 From bc3a595988468b8a9c2526b9fb8d7bcaa27cc1a7 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Mon, 2 Jun 2008 18:49:27 +0100 Subject: [ARM] 5075/1: i2c-pxa: move i2c pin setup and PCFR_PI2CEN handling into arch/arm/mach-pxa This fixes a build error introduced when the power manager register definitions were moved into pxa2xx-regs.h. Signed-off-by: Philipp Zabel Signed-off-by: Russell King --- arch/arm/mach-pxa/devices.c | 9 +++++++++ arch/arm/mach-pxa/pxa27x.c | 3 +++ drivers/i2c/busses/i2c-pxa.c | 29 ----------------------------- 3 files changed, 12 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/arch/arm/mach-pxa/devices.c b/arch/arm/mach-pxa/devices.c index d6c05b6eab3..af6cc3dbb9a 100644 --- a/arch/arm/mach-pxa/devices.c +++ b/arch/arm/mach-pxa/devices.c @@ -10,11 +10,13 @@ #include #include #include +#include #include #include #include #include "devices.h" +#include "generic.h" void __init pxa_register_device(struct platform_device *dev, void *data) { @@ -233,8 +235,15 @@ struct platform_device pxa_device_i2c = { .num_resources = ARRAY_SIZE(pxai2c_resources), }; +static unsigned long pxa27x_i2c_mfp_cfg[] = { + GPIO117_I2C_SCL, + GPIO118_I2C_SDA, +}; + void __init pxa_set_i2c_info(struct i2c_pxa_platform_data *info) { + if (cpu_is_pxa27x()) + pxa2xx_mfp_config(ARRAY_AND_SIZE(pxa27x_i2c_mfp_cfg)); pxa_register_device(&pxa_device_i2c, info); } diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c index cdaf573e0f1..48cbdc771a8 100644 --- a/arch/arm/mach-pxa/pxa27x.c +++ b/arch/arm/mach-pxa/pxa27x.c @@ -349,6 +349,9 @@ struct platform_device pxa27x_device_i2c_power = { void __init pxa_set_i2c_power_info(struct i2c_pxa_platform_data *info) { + local_irq_disable(); + PCFR |= PCFR_PI2CEN; + local_irq_enable(); pxa27x_device_i2c_power.dev.platform_data = info; } diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index eb69fbadc9c..9f61e9b3a32 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -945,32 +945,6 @@ static const struct i2c_algorithm i2c_pxa_pio_algorithm = { .functionality = i2c_pxa_functionality, }; -static void i2c_pxa_enable(struct platform_device *dev) -{ - if (cpu_is_pxa27x()) { - switch (dev->id) { - case 0: - pxa_gpio_mode(GPIO117_I2CSCL_MD); - pxa_gpio_mode(GPIO118_I2CSDA_MD); - break; - case 1: - local_irq_disable(); - PCFR |= PCFR_PI2CEN; - local_irq_enable(); - break; - } - } -} - -static void i2c_pxa_disable(struct platform_device *dev) -{ - if (cpu_is_pxa27x() && dev->id == 1) { - local_irq_disable(); - PCFR &= ~PCFR_PI2CEN; - local_irq_enable(); - } -} - #define res_len(r) ((r)->end - (r)->start + 1) static int i2c_pxa_probe(struct platform_device *dev) { @@ -1036,7 +1010,6 @@ static int i2c_pxa_probe(struct platform_device *dev) #endif clk_enable(i2c->clk); - i2c_pxa_enable(dev); if (plat) { i2c->adap.class = plat->class; @@ -1080,7 +1053,6 @@ eadapt: free_irq(irq, i2c); ereqirq: clk_disable(i2c->clk); - i2c_pxa_disable(dev); iounmap(i2c->reg_base); eremap: clk_put(i2c->clk); @@ -1103,7 +1075,6 @@ static int __exit i2c_pxa_remove(struct platform_device *dev) clk_disable(i2c->clk); clk_put(i2c->clk); - i2c_pxa_disable(dev); iounmap(i2c->reg_base); release_mem_region(i2c->iobase, i2c->iosize); -- cgit v1.2.3-70-g09d2 From 2944e16b25e7fb8b5ee0dd9dc7197a0f9e523cfd Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Sun, 1 Jun 2008 13:17:38 -0700 Subject: x86: update mptable make mptable to be consistent with acpi routing, so we could: 1. kexec kernel with acpi=off 2. work around BIOSes where acpi routing is working, but mptable is not right, so can use kernel/kexec to start other OSes that don't have good acpi support. command line: update_mptable Signed-off-by: Yinghai Lu Signed-off-by: Ingo Molnar --- arch/x86/kernel/acpi/boot.c | 22 +++ arch/x86/kernel/e820.c | 25 +++ arch/x86/kernel/mpparse.c | 401 ++++++++++++++++++++++++++++++++++++++++++-- arch/x86/kernel/setup_64.c | 4 + drivers/acpi/pci_irq.c | 5 + include/asm-x86/e820.h | 1 + include/asm-x86/mpspec.h | 4 + 7 files changed, 445 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 2ddfabae382..f226bdc19f6 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -1154,6 +1154,28 @@ int mp_register_gsi(u32 gsi, int triggering, int polarity) return gsi; } +int mp_config_acpi_gsi(unsigned char number, unsigned int devfn, u8 pin, + u32 gsi, int triggering, int polarity) +{ + struct mpc_config_intsrc intsrc; + int ioapic; + + /* print the entry should happen on mptable identically */ + intsrc.mpc_type = MP_INTSRC; + intsrc.mpc_irqtype = mp_INT; + intsrc.mpc_irqflag = (triggering == ACPI_EDGE_SENSITIVE ? 4 : 0x0c) | + (polarity == ACPI_ACTIVE_HIGH ? 1 : 3); + intsrc.mpc_srcbus = number; + intsrc.mpc_srcbusirq = (((devfn >> 3) & 0x1f) << 2) | ((pin - 1) & 3); + ioapic = mp_find_ioapic(gsi); + intsrc.mpc_dstapic = mp_ioapic_routing[ioapic].apic_id; + intsrc.mpc_dstirq = gsi - mp_ioapic_routing[ioapic].gsi_base; + + MP_intsrc_info(&intsrc); + + return 0; +} + /* * Parse IOAPIC related entries in MADT * returns 0 on success, < 0 on error diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c index 0cd9132c945..cd2b99e27d4 100644 --- a/arch/x86/kernel/e820.c +++ b/arch/x86/kernel/e820.c @@ -739,3 +739,28 @@ u64 __init find_e820_area_size(u64 start, u64 *sizep, u64 align) return -1UL; } + +/* + * pre allocated 4k and reserved it in e820 + */ +u64 __init early_reserve_e820(u64 startt, u64 sizet, u64 align) +{ + u64 size = 0; + u64 addr; + u64 start; + + start = startt; + while (size < sizet) + start = find_e820_area_size(start, &size, align); + + if (size < sizet) + return 0; + + addr = round_down(start + size - sizet, align); + update_memory_range(addr, sizet, E820_RAM, E820_RESERVED); + printk(KERN_INFO "update e820 for early_reserve_e820\n"); + update_e820(); + + return addr; +} + diff --git a/arch/x86/kernel/mpparse.c b/arch/x86/kernel/mpparse.c index 9f3792d5504..8898aa49079 100644 --- a/arch/x86/kernel/mpparse.c +++ b/arch/x86/kernel/mpparse.c @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include #ifdef CONFIG_X86_32 @@ -161,20 +163,81 @@ static void __init MP_ioapic_info(struct mpc_config_ioapic *m) nr_ioapics++; } -static void __init MP_intsrc_info(struct mpc_config_intsrc *m) +static void print_MP_intsrc_info(struct mpc_config_intsrc *m) { - printk(KERN_INFO "Int: type %d, pol %d, trig %d, bus %02x," + printk(KERN_CONT "Int: type %d, pol %d, trig %d, bus %02x," " IRQ %02x, APIC ID %x, APIC INT %02x\n", m->mpc_irqtype, m->mpc_irqflag & 3, (m->mpc_irqflag >> 2) & 3, m->mpc_srcbus, m->mpc_srcbusirq, m->mpc_dstapic, m->mpc_dstirq); - mp_irqs[mp_irq_entries].mp_dstapic = m->mpc_dstapic; - mp_irqs[mp_irq_entries].mp_type = m->mpc_type; - mp_irqs[mp_irq_entries].mp_irqtype = m->mpc_irqtype; - mp_irqs[mp_irq_entries].mp_irqflag = m->mpc_irqflag; - mp_irqs[mp_irq_entries].mp_srcbus = m->mpc_srcbus; - mp_irqs[mp_irq_entries].mp_srcbusirq = m->mpc_srcbusirq; - mp_irqs[mp_irq_entries].mp_dstirq = m->mpc_dstirq; +} + +static void __init print_mp_irq_info(struct mp_config_intsrc *mp_irq) +{ + printk(KERN_CONT "Int: type %d, pol %d, trig %d, bus %02x," + " IRQ %02x, APIC ID %x, APIC INT %02x\n", + mp_irq->mp_irqtype, mp_irq->mp_irqflag & 3, + (mp_irq->mp_irqflag >> 2) & 3, mp_irq->mp_srcbus, + mp_irq->mp_srcbusirq, mp_irq->mp_dstapic, mp_irq->mp_dstirq); +} + +static void assign_to_mp_irq(struct mpc_config_intsrc *m, + struct mp_config_intsrc *mp_irq) +{ + mp_irq->mp_dstapic = m->mpc_dstapic; + mp_irq->mp_type = m->mpc_type; + mp_irq->mp_irqtype = m->mpc_irqtype; + mp_irq->mp_irqflag = m->mpc_irqflag; + mp_irq->mp_srcbus = m->mpc_srcbus; + mp_irq->mp_srcbusirq = m->mpc_srcbusirq; + mp_irq->mp_dstirq = m->mpc_dstirq; +} + +static void __init assign_to_mpc_intsrc(struct mp_config_intsrc *mp_irq, + struct mpc_config_intsrc *m) +{ + m->mpc_dstapic = mp_irq->mp_dstapic; + m->mpc_type = mp_irq->mp_type; + m->mpc_irqtype = mp_irq->mp_irqtype; + m->mpc_irqflag = mp_irq->mp_irqflag; + m->mpc_srcbus = mp_irq->mp_srcbus; + m->mpc_srcbusirq = mp_irq->mp_srcbusirq; + m->mpc_dstirq = mp_irq->mp_dstirq; +} + +static int mp_irq_mpc_intsrc_cmp(struct mp_config_intsrc *mp_irq, + struct mpc_config_intsrc *m) +{ + if (mp_irq->mp_dstapic != m->mpc_dstapic) + return 1; + if (mp_irq->mp_type != m->mpc_type) + return 2; + if (mp_irq->mp_irqtype != m->mpc_irqtype) + return 3; + if (mp_irq->mp_irqflag != m->mpc_irqflag) + return 4; + if (mp_irq->mp_srcbus != m->mpc_srcbus) + return 5; + if (mp_irq->mp_srcbusirq != m->mpc_srcbusirq) + return 6; + if (mp_irq->mp_dstirq != m->mpc_dstirq) + return 7; + + return 0; +} + +void MP_intsrc_info(struct mpc_config_intsrc *m) +{ + int i; + + print_MP_intsrc_info(m); + + for (i = 0; i < mp_irq_entries; i++) { + if (!mp_irq_mpc_intsrc_cmp(&mp_irqs[i], m)) + return; + } + + assign_to_mp_irq(m, &mp_irqs[mp_irq_entries]); if (++mp_irq_entries == MAX_IRQ_SOURCES) panic("Max # of irq sources exceeded!!\n"); } @@ -268,12 +331,9 @@ static inline void mps_oem_check(struct mp_config_table *mpc, char *oem, * Read/parse the MPC */ -static int __init smp_read_mpc(struct mp_config_table *mpc, unsigned early) +static int __init smp_check_mpc(struct mp_config_table *mpc, char *oem, + char *str) { - char str[16]; - char oem[10]; - int count = sizeof(*mpc); - unsigned char *mpt = ((unsigned char *)mpc) + count; if (memcmp(mpc->mpc_signature, MPC_SIGNATURE, 4)) { printk(KERN_ERR "MPTABLE: bad signature [%c%c%c%c]!\n", @@ -301,13 +361,28 @@ static int __init smp_read_mpc(struct mp_config_table *mpc, unsigned early) memcpy(str, mpc->mpc_productid, 12); str[12] = 0; -#ifdef CONFIG_X86_32 - mps_oem_check(mpc, oem, str); -#endif printk(KERN_INFO "MPTABLE: Product ID: %s\n", str); printk(KERN_INFO "MPTABLE: APIC at: 0x%X\n", mpc->mpc_lapic); + return 1; +} + +static int __init smp_read_mpc(struct mp_config_table *mpc, unsigned early) +{ + char str[16]; + char oem[10]; + + int count = sizeof(*mpc); + unsigned char *mpt = ((unsigned char *)mpc) + count; + + if (!smp_check_mpc(mpc, oem, str)) + return 0; + +#ifdef CONFIG_X86_32 + mps_oem_check(mpc, oem, str); +#endif + /* save the local APIC address, it might be non-default */ if (!acpi_lapic) mp_lapic_addr = mpc->mpc_lapic; @@ -785,3 +860,295 @@ void __init find_smp_config(void) { __find_smp_config(1); } + +#ifdef CONFIG_X86_IO_APIC +static u8 __initdata irq_used[MAX_IRQ_SOURCES]; + +static int __init get_MP_intsrc_index(struct mpc_config_intsrc *m) +{ + int i; + + if (m->mpc_irqtype != mp_INT) + return 0; + + if (m->mpc_irqflag != 0x0f) + return 0; + + /* not legacy */ + + for (i = 0; i < mp_irq_entries; i++) { + if (mp_irqs[i].mp_irqtype != mp_INT) + continue; + + if (mp_irqs[i].mp_irqflag != 0x0f) + continue; + + if (mp_irqs[i].mp_srcbus != m->mpc_srcbus) + continue; + if (mp_irqs[i].mp_srcbusirq != m->mpc_srcbusirq) + continue; + if (irq_used[i]) { + /* already claimed */ + return -2; + } + irq_used[i] = 1; + return i; + } + + /* not found */ + return -1; +} + +#define SPARE_SLOT_NUM 20 + +static struct mpc_config_intsrc __initdata *m_spare[SPARE_SLOT_NUM]; +#endif + +static int __init replace_intsrc_all(struct mp_config_table *mpc, + unsigned long mpc_new_phys, + unsigned long mpc_new_length) +{ +#ifdef CONFIG_X86_IO_APIC + int i; + int nr_m_spare = 0; +#endif + + int count = sizeof(*mpc); + unsigned char *mpt = ((unsigned char *)mpc) + count; + + printk(KERN_INFO "mpc_length %x\n", mpc->mpc_length); + while (count < mpc->mpc_length) { + switch (*mpt) { + case MP_PROCESSOR: + { + struct mpc_config_processor *m = + (struct mpc_config_processor *)mpt; + mpt += sizeof(*m); + count += sizeof(*m); + break; + } + case MP_BUS: + { + struct mpc_config_bus *m = + (struct mpc_config_bus *)mpt; + mpt += sizeof(*m); + count += sizeof(*m); + break; + } + case MP_IOAPIC: + { + mpt += sizeof(struct mpc_config_ioapic); + count += sizeof(struct mpc_config_ioapic); + break; + } + case MP_INTSRC: + { +#ifdef CONFIG_X86_IO_APIC + struct mpc_config_intsrc *m = + (struct mpc_config_intsrc *)mpt; + + printk(KERN_INFO "OLD "); + print_MP_intsrc_info(m); + i = get_MP_intsrc_index(m); + if (i > 0) { + assign_to_mpc_intsrc(&mp_irqs[i], m); + printk(KERN_INFO "NEW "); + print_mp_irq_info(&mp_irqs[i]); + } else if (!i) { + /* legacy, do nothing */ + } else if (nr_m_spare < SPARE_SLOT_NUM) { + /* + * not found (-1), or duplicated (-2) + * are invalid entries, + * we need to use the slot later + */ + m_spare[nr_m_spare] = m; + nr_m_spare++; + } +#endif + mpt += sizeof(struct mpc_config_intsrc); + count += sizeof(struct mpc_config_intsrc); + break; + } + case MP_LINTSRC: + { + struct mpc_config_lintsrc *m = + (struct mpc_config_lintsrc *)mpt; + mpt += sizeof(*m); + count += sizeof(*m); + break; + } + default: + /* wrong mptable */ + printk(KERN_ERR "Your mptable is wrong, contact your HW vendor!\n"); + printk(KERN_ERR "type %x\n", *mpt); + print_hex_dump(KERN_ERR, " ", DUMP_PREFIX_ADDRESS, 16, + 1, mpc, mpc->mpc_length, 1); + goto out; + } + } + +#ifdef CONFIG_X86_IO_APIC + for (i = 0; i < mp_irq_entries; i++) { + if (irq_used[i]) + continue; + + if (mp_irqs[i].mp_irqtype != mp_INT) + continue; + + if (mp_irqs[i].mp_irqflag != 0x0f) + continue; + + if (nr_m_spare > 0) { + printk(KERN_INFO "*NEW* found "); + nr_m_spare--; + assign_to_mpc_intsrc(&mp_irqs[i], m_spare[nr_m_spare]); + m_spare[nr_m_spare] = NULL; + } else { + struct mpc_config_intsrc *m = + (struct mpc_config_intsrc *)mpt; + count += sizeof(struct mpc_config_intsrc); + if (!mpc_new_phys) { + printk(KERN_INFO "No spare slots, try to append...take your risk, new mpc_length %x\n", count); + } else { + if (count <= mpc_new_length) + printk(KERN_INFO "No spare slots, try to append..., new mpc_length %x\n", count); + else { + printk(KERN_ERR "mpc_new_length %lx is too small\n", mpc_new_length); + goto out; + } + } + assign_to_mpc_intsrc(&mp_irqs[i], m); + mpc->mpc_length = count; + mpt += sizeof(struct mpc_config_intsrc); + } + print_mp_irq_info(&mp_irqs[i]); + } +#endif +out: + /* update checksum */ + mpc->mpc_checksum = 0; + mpc->mpc_checksum -= mpf_checksum((unsigned char *)mpc, + mpc->mpc_length); + + return 0; +} + +int __initdata enable_update_mptable; + +static int __init update_mptable_setup(char *str) +{ + enable_update_mptable = 1; + return 0; +} +early_param("update_mptable", update_mptable_setup); + +static unsigned long __initdata mpc_new_phys; +static unsigned long mpc_new_length __initdata = 4096; + +/* alloc_mptable or alloc_mptable=4k */ +static int __initdata alloc_mptable; +static int __init parse_alloc_mptable_opt(char *p) +{ + enable_update_mptable = 1; + alloc_mptable = 1; + if (!p) + return 0; + mpc_new_length = memparse(p, &p); + return 0; +} +early_param("alloc_mptable", parse_alloc_mptable_opt); + +void __init early_reserve_e820_mpc_new(void) +{ + if (enable_update_mptable && alloc_mptable) { + u64 startt = 0; +#ifdef CONFIG_X86_TRAMPOLINE + startt = TRAMPOLINE_BASE; +#endif + mpc_new_phys = early_reserve_e820(startt, mpc_new_length, 4); + } +} + +static int __init update_mp_table(void) +{ + char str[16]; + char oem[10]; + struct intel_mp_floating *mpf; + struct mp_config_table *mpc; + struct mp_config_table *mpc_new; + + if (!enable_update_mptable) + return 0; + + mpf = mpf_found; + if (!mpf) + return 0; + + /* + * Now see if we need to go further. + */ + if (mpf->mpf_feature1 != 0) + return 0; + + if (!mpf->mpf_physptr) + return 0; + + mpc = phys_to_virt(mpf->mpf_physptr); + + if (!smp_check_mpc(mpc, oem, str)) + return 0; + + printk(KERN_INFO "mpf: %lx\n", virt_to_phys(mpf)); + printk(KERN_INFO "mpf_physptr: %x\n", mpf->mpf_physptr); + + if (mpc_new_phys && mpc->mpc_length > mpc_new_length) { + mpc_new_phys = 0; + printk(KERN_INFO "mpc_new_length is %ld, please use alloc_mptable=8k\n", + mpc_new_length); + } + + if (!mpc_new_phys) { + unsigned char old, new; + /* check if we can change the postion */ + mpc->mpc_checksum = 0; + old = mpf_checksum((unsigned char *)mpc, mpc->mpc_length); + mpc->mpc_checksum = 0xff; + new = mpf_checksum((unsigned char *)mpc, mpc->mpc_length); + if (old == new) { + printk(KERN_INFO "mpc is readonly, please try alloc_mptable instead\n"); + return 0; + } + printk(KERN_INFO "use in-positon replacing\n"); + } else { + mpf->mpf_physptr = mpc_new_phys; + mpc_new = phys_to_virt(mpc_new_phys); + memcpy(mpc_new, mpc, mpc->mpc_length); + mpc = mpc_new; + /* check if we can modify that */ + if (mpc_new_phys - mpf->mpf_physptr) { + struct intel_mp_floating *mpf_new; + /* steal 16 bytes from [0, 1k) */ + printk(KERN_INFO "mpf new: %x\n", 0x400 - 16); + mpf_new = phys_to_virt(0x400 - 16); + memcpy(mpf_new, mpf, 16); + mpf = mpf_new; + mpf->mpf_physptr = mpc_new_phys; + } + mpf->mpf_checksum = 0; + mpf->mpf_checksum -= mpf_checksum((unsigned char *)mpf, 16); + printk(KERN_INFO "mpf_physptr new: %x\n", mpf->mpf_physptr); + } + + /* + * only replace the one with mp_INT and + * MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, + * already in mp_irqs , stored by ... and mp_config_acpi_gsi, + * may need pci=routeirq for all coverage + */ + replace_intsrc_all(mpc, mpc_new_phys, mpc_new_length); + + return 0; +} + +late_initcall(update_mp_table); diff --git a/arch/x86/kernel/setup_64.c b/arch/x86/kernel/setup_64.c index 89e6cca5d69..978a0d637f3 100644 --- a/arch/x86/kernel/setup_64.c +++ b/arch/x86/kernel/setup_64.c @@ -56,6 +56,7 @@ #include #include