From 7314c2b377afaf367f2966bd9ea67bf83350e29b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Sep 2010 18:01:55 +0200 Subject: iwlagn: rename iwl_commit_rxon iwl_commit_rxon really should be named iwlagn_commit_rxon, so rename it. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 834c2f9..09db940 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2216,7 +2216,7 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv) static struct iwl_hcmd_ops iwl4965_hcmd = { .rxon_assoc = iwl4965_send_rxon_assoc, - .commit_rxon = iwl_commit_rxon, + .commit_rxon = iwlagn_commit_rxon, .set_rxon_chain = iwl_set_rxon_chain, .send_bt_config = iwl_send_bt_config, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c index 9ca6c91..901452e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c @@ -360,7 +360,7 @@ static int iwlagn_set_pan_params(struct iwl_priv *priv) struct iwl_hcmd_ops iwlagn_hcmd = { .rxon_assoc = iwlagn_send_rxon_assoc, - .commit_rxon = iwl_commit_rxon, + .commit_rxon = iwlagn_commit_rxon, .set_rxon_chain = iwl_set_rxon_chain, .set_tx_ant = iwlagn_send_tx_ant_config, .send_bt_config = iwl_send_bt_config, @@ -369,7 +369,7 @@ struct iwl_hcmd_ops iwlagn_hcmd = { struct iwl_hcmd_ops iwlagn_bt_hcmd = { .rxon_assoc = iwlagn_send_rxon_assoc, - .commit_rxon = iwl_commit_rxon, + .commit_rxon = iwlagn_commit_rxon, .set_rxon_chain = iwl_set_rxon_chain, .set_tx_ant = iwlagn_send_tx_ant_config, .send_bt_config = iwlagn_send_advance_bt_config, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index a6dce61..b59ce92 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -91,14 +91,14 @@ static int iwlagn_ant_coupling; static bool iwlagn_bt_ch_announce = 1; /** - * iwl_commit_rxon - commit staging_rxon to hardware + * iwlagn_commit_rxon - commit staging_rxon to hardware * * The RXON command in staging_rxon is committed to the hardware and * the active_rxon structure is updated with the new data. This * function correctly transitions out of the RXON_ASSOC_MSK state if * a HW tune is required based on the RXON structure changes. */ -int iwl_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) +int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) { /* cast away the const for active_rxon in this function */ struct iwl_rxon_cmd *active_rxon = (void *)&ctx->active; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index eb3812a..2a1c83b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -129,6 +129,9 @@ void iwlagn_txq_set_sched(struct iwl_priv *priv, u32 mask); void iwl_free_tfds_in_queue(struct iwl_priv *priv, int sta_id, int tid, int freed); +/* RXON */ +int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx); + /* uCode */ int iwlagn_load_ucode(struct iwl_priv *priv); void iwlagn_rx_calib_result(struct iwl_priv *priv, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 6228b1c..d6d5bb0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -432,7 +432,6 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, u32 changes); -int iwl_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx); int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif); void iwl_mac_remove_interface(struct ieee80211_hw *hw, -- cgit v0.10.2 From a77029ee3fc03a37238b73892e55b789273991aa Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Sep 2010 18:01:56 +0200 Subject: iwlwifi: introduce post_scan hook The different drivers need to do different things after a scan, so create a post_scan hook to allow them to do this. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index cfdff54..87943a8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -2713,6 +2713,7 @@ static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = { .build_addsta_hcmd = iwl3945_build_addsta_hcmd, .tx_cmd_protection = iwlcore_tx_cmd_protection, .request_scan = iwl3945_request_scan, + .post_scan = iwl3945_post_scan, }; static const struct iwl_ops iwl3945_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index 98509c5..7ad4aff 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -296,6 +296,7 @@ extern int iwl3945_rs_next_rate(struct iwl_priv *priv, int rate); /* scanning */ int iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif); +void iwl3945_post_scan(struct iwl_priv *priv); /* Requires full declaration of iwl_priv before including */ #include "iwl-io.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 09db940..e161f5d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2221,6 +2221,18 @@ static struct iwl_hcmd_ops iwl4965_hcmd = { .send_bt_config = iwl_send_bt_config, }; +static void iwl4965_post_scan(struct iwl_priv *priv) +{ + struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; + + /* + * Since setting the RXON may have been deferred while + * performing the scan, fire one off if needed + */ + if (memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging))) + iwlcore_commit_rxon(priv, ctx); +} + static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = { .get_hcmd_size = iwl4965_get_hcmd_size, .build_addsta_hcmd = iwl4965_build_addsta_hcmd, @@ -2229,6 +2241,7 @@ static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = { .tx_cmd_protection = iwlcore_tx_cmd_protection, .calc_rssi = iwl4965_calc_rssi, .request_scan = iwlagn_request_scan, + .post_scan = iwl4965_post_scan, }; static struct iwl_lib_ops iwl4965_lib = { diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c index 901452e..634177d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c @@ -384,4 +384,5 @@ struct iwl_hcmd_utils_ops iwlagn_hcmd_utils = { .tx_cmd_protection = iwlagn_tx_cmd_protection, .calc_rssi = iwlagn_calc_rssi, .request_scan = iwlagn_request_scan, + .post_scan = iwlagn_post_scan, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index f5445d5..3fa2c5c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -1565,6 +1565,22 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) return ret; } +void iwlagn_post_scan(struct iwl_priv *priv) +{ + struct iwl_rxon_context *ctx; + + /* + * Since setting the RXON may have been deferred while + * performing the scan, fire one off if needed + */ + for_each_context(priv, ctx) + if (memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging))) + iwlagn_commit_rxon(priv, ctx); + + if (priv->cfg->ops->hcmd->set_pan_params) + priv->cfg->ops->hcmd->set_pan_params(priv); +} + int iwlagn_manage_ibss_station(struct iwl_priv *priv, struct ieee80211_vif *vif, bool add) { diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index 2a1c83b..960fe2e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -227,6 +227,7 @@ void iwl_reply_statistics(struct iwl_priv *priv, /* scan */ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif); +void iwlagn_post_scan(struct iwl_priv *priv); /* station mgmt */ int iwlagn_manage_ibss_station(struct iwl_priv *priv, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index d6d5bb0..09908f6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -112,6 +112,7 @@ struct iwl_hcmd_utils_ops { int (*calc_rssi)(struct iwl_priv *priv, struct iwl_rx_phy_res *rx_resp); int (*request_scan)(struct iwl_priv *priv, struct ieee80211_vif *vif); + void (*post_scan)(struct iwl_priv *priv); }; struct iwl_apm_ops { diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index eaae49e..a7e8c7f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -559,7 +559,6 @@ static void iwl_bg_scan_completed(struct work_struct *work) struct iwl_priv *priv = container_of(work, struct iwl_priv, scan_completed); bool aborted; - struct iwl_rxon_context *ctx; IWL_DEBUG_SCAN(priv, "Completed %sscan.\n", priv->is_internal_short_scan ? "internal short " : ""); @@ -609,15 +608,7 @@ out_settings: * performing the scan, fire one off */ iwl_set_tx_power(priv, priv->tx_power_user_lmt, true); - /* - * Since setting the RXON may have been deferred while - * performing the scan, fire one off if needed - */ - for_each_context(priv, ctx) - iwlcore_commit_rxon(priv, ctx); - - if (priv->cfg->ops->hcmd->set_pan_params) - priv->cfg->ops->hcmd->set_pan_params(priv); + priv->cfg->ops->utils->post_scan(priv); out: mutex_unlock(&priv->mutex); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 43db5f3..db148d0 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2983,6 +2983,18 @@ int iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) return ret; } +void iwl3945_post_scan(struct iwl_priv *priv) +{ + struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; + + /* + * Since setting the RXON may have been deferred while + * performing the scan, fire one off if needed + */ + if (memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging))) + iwlcore_commit_rxon(priv, ctx); +} + static void iwl3945_bg_restart(struct work_struct *data) { struct iwl_priv *priv = container_of(data, struct iwl_priv, restart); -- cgit v0.10.2 From 8289e07b8a4b588e167bc84f93419458fd6efa3e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Sep 2010 18:01:57 +0200 Subject: iwl3945: use iwl3945_commit_rxon There's no need to go via the indirect function call from within the 3945 subdriver. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 87943a8..ef67087 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -1763,8 +1763,7 @@ static int iwl3945_send_rxon_assoc(struct iwl_priv *priv, * function correctly transitions out of the RXON_ASSOC_MSK state if * a HW tune is required based on the RXON structure changes. */ -static int iwl3945_commit_rxon(struct iwl_priv *priv, - struct iwl_rxon_context *ctx) +int iwl3945_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) { /* cast away the const for active_rxon in this function */ struct iwl3945_rxon_cmd *active_rxon = (void *)&ctx->active; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index 7ad4aff..77e8e19 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -271,6 +271,9 @@ extern void iwl3945_post_associate(struct iwl_priv *priv, extern void iwl3945_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif); +extern int iwl3945_commit_rxon(struct iwl_priv *priv, + struct iwl_rxon_context *ctx); + /** * iwl3945_hw_find_station - Find station id for a given BSSID * @bssid: MAC address of station ID to find diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index db148d0..64eb049 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2547,7 +2547,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv) priv->cfg->ops->hcmd->send_bt_config(priv); /* Configure the adapter for unassociated operation */ - iwlcore_commit_rxon(priv, ctx); + iwl3945_commit_rxon(priv, ctx); iwl3945_reg_txpower_periodic(priv); @@ -2992,7 +2992,7 @@ void iwl3945_post_scan(struct iwl_priv *priv) * performing the scan, fire one off if needed */ if (memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging))) - iwlcore_commit_rxon(priv, ctx); + iwl3945_commit_rxon(priv, ctx); } static void iwl3945_bg_restart(struct work_struct *data) @@ -3061,7 +3061,7 @@ void iwl3945_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif) conf = ieee80211_get_hw_conf(priv->hw); ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwlcore_commit_rxon(priv, ctx); + iwl3945_commit_rxon(priv, ctx); rc = iwl_send_rxon_timing(priv, ctx); if (rc) @@ -3087,7 +3087,7 @@ void iwl3945_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif) ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK; } - iwlcore_commit_rxon(priv, ctx); + iwl3945_commit_rxon(priv, ctx); switch (vif->type) { case NL80211_IFTYPE_STATION: @@ -3226,7 +3226,7 @@ void iwl3945_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif) /* RXON - unassoc (to set timing command) */ ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwlcore_commit_rxon(priv, ctx); + iwl3945_commit_rxon(priv, ctx); /* RXON Timing */ rc = iwl_send_rxon_timing(priv, ctx); @@ -3253,7 +3253,7 @@ void iwl3945_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif) } /* restore RXON assoc */ ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK; - iwlcore_commit_rxon(priv, ctx); + iwl3945_commit_rxon(priv, ctx); } iwl3945_send_beacon_cmd(priv); @@ -3519,7 +3519,7 @@ static ssize_t store_flags(struct device *d, IWL_DEBUG_INFO(priv, "Committing rxon.flags = 0x%04X\n", flags); ctx->staging.flags = cpu_to_le32(flags); - iwlcore_commit_rxon(priv, ctx); + iwl3945_commit_rxon(priv, ctx); } } mutex_unlock(&priv->mutex); @@ -3557,7 +3557,7 @@ static ssize_t store_filter_flags(struct device *d, "0x%04X\n", filter_flags); ctx->staging.filter_flags = cpu_to_le32(filter_flags); - iwlcore_commit_rxon(priv, ctx); + iwl3945_commit_rxon(priv, ctx); } } mutex_unlock(&priv->mutex); -- cgit v0.10.2 From 5de33068a2f841536ca8632534e3e193d5b2607f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Sep 2010 18:01:58 +0200 Subject: iwlwifi: move chain settings to agn The core module doesn't need to carry around the code for chain settings that is used for HT drivers (agn) only. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index e161f5d..20626c9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2217,7 +2217,7 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv) static struct iwl_hcmd_ops iwl4965_hcmd = { .rxon_assoc = iwl4965_send_rxon_assoc, .commit_rxon = iwlagn_commit_rxon, - .set_rxon_chain = iwl_set_rxon_chain, + .set_rxon_chain = iwlagn_set_rxon_chain, .send_bt_config = iwl_send_bt_config, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c index 634177d..ffb2f41 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c @@ -361,7 +361,7 @@ static int iwlagn_set_pan_params(struct iwl_priv *priv) struct iwl_hcmd_ops iwlagn_hcmd = { .rxon_assoc = iwlagn_send_rxon_assoc, .commit_rxon = iwlagn_commit_rxon, - .set_rxon_chain = iwl_set_rxon_chain, + .set_rxon_chain = iwlagn_set_rxon_chain, .set_tx_ant = iwlagn_send_tx_ant_config, .send_bt_config = iwl_send_bt_config, .set_pan_params = iwlagn_set_pan_params, @@ -370,7 +370,7 @@ struct iwl_hcmd_ops iwlagn_hcmd = { struct iwl_hcmd_ops iwlagn_bt_hcmd = { .rxon_assoc = iwlagn_send_rxon_assoc, .commit_rxon = iwlagn_commit_rxon, - .set_rxon_chain = iwl_set_rxon_chain, + .set_rxon_chain = iwlagn_set_rxon_chain, .set_tx_ant = iwlagn_send_tx_ant_config, .send_bt_config = iwlagn_send_advance_bt_config, .set_pan_params = iwlagn_set_pan_params, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 3fa2c5c..0b45bce 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -2065,3 +2065,143 @@ void iwlagn_bt_cancel_deferred_work(struct iwl_priv *priv) { cancel_work_sync(&priv->bt_traffic_change_work); } + +static bool is_single_rx_stream(struct iwl_priv *priv) +{ + return priv->current_ht_config.smps == IEEE80211_SMPS_STATIC || + priv->current_ht_config.single_chain_sufficient; +} + +#define IWL_NUM_RX_CHAINS_MULTIPLE 3 +#define IWL_NUM_RX_CHAINS_SINGLE 2 +#define IWL_NUM_IDLE_CHAINS_DUAL 2 +#define IWL_NUM_IDLE_CHAINS_SINGLE 1 + +/* + * Determine how many receiver/antenna chains to use. + * + * More provides better reception via diversity. Fewer saves power + * at the expense of throughput, but only when not in powersave to + * start with. + * + * 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 iwl_get_active_rx_chain_count(struct iwl_priv *priv) +{ + if (priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist && + (priv->bt_full_concurrent || + priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) { + /* + * only use chain 'A' in bt high traffic load or + * full concurrency mode + */ + return IWL_NUM_RX_CHAINS_SINGLE; + } + /* # of Rx chains to use when expecting MIMO. */ + if (is_single_rx_stream(priv)) + return IWL_NUM_RX_CHAINS_SINGLE; + else + return IWL_NUM_RX_CHAINS_MULTIPLE; +} + +/* + * When we are in power saving mode, unless device support spatial + * multiplexing power save, use the active count for rx chain count. + */ +static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt) +{ + /* # Rx chains when idling, depending on SMPS mode */ + switch (priv->current_ht_config.smps) { + case IEEE80211_SMPS_STATIC: + case IEEE80211_SMPS_DYNAMIC: + return IWL_NUM_IDLE_CHAINS_SINGLE; + case IEEE80211_SMPS_OFF: + return active_cnt; + default: + WARN(1, "invalid SMPS mode %d", + priv->current_ht_config.smps); + return active_cnt; + } +} + +/* up to 4 chains */ +static u8 iwl_count_chain_bitmap(u32 chain_bitmap) +{ + u8 res; + res = (chain_bitmap & BIT(0)) >> 0; + res += (chain_bitmap & BIT(1)) >> 1; + res += (chain_bitmap & BIT(2)) >> 2; + res += (chain_bitmap & BIT(3)) >> 3; + return res; +} + +/** + * iwlagn_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 iwlagn_set_rxon_chain(struct iwl_priv *priv, struct iwl_rxon_context *ctx) +{ + bool is_single = is_single_rx_stream(priv); + bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); + u8 idle_rx_cnt, active_rx_cnt, valid_rx_cnt; + u32 active_chains; + u16 rx_chain; + + /* 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. */ + if (priv->chain_noise_data.active_chains) + active_chains = priv->chain_noise_data.active_chains; + else + active_chains = priv->hw_params.valid_rx_ant; + + if (priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist && + (priv->bt_full_concurrent || + priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) { + /* + * only use chain 'A' in bt high traffic load or + * full concurrency mode + */ + active_chains = first_antenna(active_chains); + } + + rx_chain = active_chains << RXON_RX_CHAIN_VALID_POS; + + /* How many receivers should we use? */ + active_rx_cnt = iwl_get_active_rx_chain_count(priv); + idle_rx_cnt = iwl_get_idle_rx_chain_count(priv, active_rx_cnt); + + + /* correct rx chain count according hw settings + * and chain noise calibration + */ + valid_rx_cnt = iwl_count_chain_bitmap(active_chains); + if (valid_rx_cnt < active_rx_cnt) + active_rx_cnt = valid_rx_cnt; + + if (valid_rx_cnt < idle_rx_cnt) + idle_rx_cnt = valid_rx_cnt; + + rx_chain |= active_rx_cnt << RXON_RX_CHAIN_MIMO_CNT_POS; + rx_chain |= idle_rx_cnt << RXON_RX_CHAIN_CNT_POS; + + ctx->staging.rx_chain = cpu_to_le16(rx_chain); + + if (!is_single && (active_rx_cnt >= IWL_NUM_RX_CHAINS_SINGLE) && is_cam) + ctx->staging.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK; + else + ctx->staging.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK; + + IWL_DEBUG_ASSOC(priv, "rx_chain=0x%X active=%d idle=%d\n", + ctx->staging.rx_chain, + active_rx_cnt, idle_rx_cnt); + + WARN_ON(active_rx_cnt == 0 || idle_rx_cnt == 0 || + active_rx_cnt < idle_rx_cnt); +} diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index 960fe2e..5d5cacb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -131,6 +131,7 @@ void iwl_free_tfds_in_queue(struct iwl_priv *priv, /* RXON */ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx); +void iwlagn_set_rxon_chain(struct iwl_priv *priv, struct iwl_rxon_context *ctx); /* uCode */ int iwlagn_load_ucode(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 516c55a..dd7c3cb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -439,12 +439,6 @@ void iwlcore_tx_cmd_protection(struct iwl_priv *priv, EXPORT_SYMBOL(iwlcore_tx_cmd_protection); -static bool is_single_rx_stream(struct iwl_priv *priv) -{ - return priv->current_ht_config.smps == IEEE80211_SMPS_STATIC || - priv->current_ht_config.single_chain_sufficient; -} - static bool iwl_is_channel_extension(struct iwl_priv *priv, enum ieee80211_band band, u16 channel, u8 extension_chan_offset) @@ -834,141 +828,6 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf) } EXPORT_SYMBOL(iwl_set_rxon_ht); -#define IWL_NUM_RX_CHAINS_MULTIPLE 3 -#define IWL_NUM_RX_CHAINS_SINGLE 2 -#define IWL_NUM_IDLE_CHAINS_DUAL 2 -#define IWL_NUM_IDLE_CHAINS_SINGLE 1 - -/* - * Determine how many receiver/antenna chains to use. - * - * More provides better reception via diversity. Fewer saves power - * at the expense of throughput, but only when not in powersave to - * start with. - * - * 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 iwl_get_active_rx_chain_count(struct iwl_priv *priv) -{ - if (priv->cfg->bt_params && - priv->cfg->bt_params->advanced_bt_coexist && - (priv->bt_full_concurrent || - priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) { - /* - * only use chain 'A' in bt high traffic load or - * full concurrency mode - */ - return IWL_NUM_RX_CHAINS_SINGLE; - } - /* # of Rx chains to use when expecting MIMO. */ - if (is_single_rx_stream(priv)) - return IWL_NUM_RX_CHAINS_SINGLE; - else - return IWL_NUM_RX_CHAINS_MULTIPLE; -} - -/* - * When we are in power saving mode, unless device support spatial - * multiplexing power save, use the active count for rx chain count. - */ -static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt) -{ - /* # Rx chains when idling, depending on SMPS mode */ - switch (priv->current_ht_config.smps) { - case IEEE80211_SMPS_STATIC: - case IEEE80211_SMPS_DYNAMIC: - return IWL_NUM_IDLE_CHAINS_SINGLE; - case IEEE80211_SMPS_OFF: - return active_cnt; - default: - WARN(1, "invalid SMPS mode %d", - priv->current_ht_config.smps); - return active_cnt; - } -} - -/* up to 4 chains */ -static u8 iwl_count_chain_bitmap(u32 chain_bitmap) -{ - u8 res; - res = (chain_bitmap & BIT(0)) >> 0; - res += (chain_bitmap & BIT(1)) >> 1; - res += (chain_bitmap & BIT(2)) >> 2; - res += (chain_bitmap & BIT(3)) >> 3; - return res; -} - -/** - * 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, struct iwl_rxon_context *ctx) -{ - bool is_single = is_single_rx_stream(priv); - bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); - u8 idle_rx_cnt, active_rx_cnt, valid_rx_cnt; - u32 active_chains; - u16 rx_chain; - - /* 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. */ - if (priv->chain_noise_data.active_chains) - active_chains = priv->chain_noise_data.active_chains; - else - active_chains = priv->hw_params.valid_rx_ant; - - if (priv->cfg->bt_params && - priv->cfg->bt_params->advanced_bt_coexist && - (priv->bt_full_concurrent || - priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) { - /* - * only use chain 'A' in bt high traffic load or - * full concurrency mode - */ - active_chains = first_antenna(active_chains); - } - - rx_chain = active_chains << RXON_RX_CHAIN_VALID_POS; - - /* How many receivers should we use? */ - active_rx_cnt = iwl_get_active_rx_chain_count(priv); - idle_rx_cnt = iwl_get_idle_rx_chain_count(priv, active_rx_cnt); - - - /* correct rx chain count according hw settings - * and chain noise calibration - */ - valid_rx_cnt = iwl_count_chain_bitmap(active_chains); - if (valid_rx_cnt < active_rx_cnt) - active_rx_cnt = valid_rx_cnt; - - if (valid_rx_cnt < idle_rx_cnt) - idle_rx_cnt = valid_rx_cnt; - - rx_chain |= active_rx_cnt << RXON_RX_CHAIN_MIMO_CNT_POS; - rx_chain |= idle_rx_cnt << RXON_RX_CHAIN_CNT_POS; - - ctx->staging.rx_chain = cpu_to_le16(rx_chain); - - if (!is_single && (active_rx_cnt >= IWL_NUM_RX_CHAINS_SINGLE) && is_cam) - ctx->staging.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK; - else - ctx->staging.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK; - - IWL_DEBUG_ASSOC(priv, "rx_chain=0x%X active=%d idle=%d\n", - ctx->staging.rx_chain, - active_rx_cnt, idle_rx_cnt); - - WARN_ON(active_rx_cnt == 0 || idle_rx_cnt == 0 || - active_rx_cnt < idle_rx_cnt); -} -EXPORT_SYMBOL(iwl_set_rxon_chain); - /* Return valid, unused, channel for a passive scan to reset the RF */ u8 iwl_get_single_channel_number(struct iwl_priv *priv, enum ieee80211_band band) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 09908f6..50a3c26 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -407,7 +407,6 @@ void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, struct iwl_rxon_context *ctx, int hw_decrypt); int iwl_check_rxon_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx); int iwl_full_rxon_required(struct iwl_priv *priv, struct iwl_rxon_context *ctx); -void iwl_set_rxon_chain(struct iwl_priv *priv, struct iwl_rxon_context *ctx); int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch, struct iwl_rxon_context *ctx); void iwl_set_flags_for_band(struct iwl_priv *priv, -- cgit v0.10.2 From 575ccfd0f47e5d791246cb03c07d636190322fa1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Sep 2010 18:01:59 +0200 Subject: iwlwifi: rename iwl_mac_beacon_update Rename iwl_mac_beacon_update to iwlcore_beacon_update and make the calling convention a bit different. The old name with _mac_ indicated that it was a mac80211 callback, but that's no longer true. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index dd7c3cb..71f245f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1617,25 +1617,25 @@ static inline void iwl_set_no_assoc(struct iwl_priv *priv, iwlcore_commit_rxon(priv, ctx); } -static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) +static void iwlcore_beacon_update(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct iwl_priv *priv = hw->priv; unsigned long flags; __le64 timestamp; + struct sk_buff *skb = ieee80211_beacon_get(hw, vif); - IWL_DEBUG_MAC80211(priv, "enter\n"); + if (!skb) + return; + + IWL_DEBUG_ASSOC(priv, "enter\n"); lockdep_assert_held(&priv->mutex); if (!priv->beacon_ctx) { IWL_ERR(priv, "update beacon but no beacon context!\n"); dev_kfree_skb(skb); - return -EINVAL; - } - - if (!iwl_is_ready_rf(priv)) { - IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n"); - return -EIO; + return; } spin_lock_irqsave(&priv->lock, flags); @@ -1648,12 +1648,16 @@ static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; priv->timestamp = le64_to_cpu(timestamp); - IWL_DEBUG_MAC80211(priv, "leave\n"); + IWL_DEBUG_ASSOC(priv, "leave\n"); + spin_unlock_irqrestore(&priv->lock, flags); - priv->cfg->ops->lib->post_associate(priv, priv->beacon_ctx->vif); + if (!iwl_is_ready_rf(priv)) { + IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n"); + return; + } - return 0; + priv->cfg->ops->lib->post_associate(priv, priv->beacon_ctx->vif); } void iwl_bss_info_changed(struct ieee80211_hw *hw, @@ -1735,13 +1739,8 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw, * mac80211 decides to do both changes at once because * it will invoke post_associate. */ - if (vif->type == NL80211_IFTYPE_ADHOC && - changes & BSS_CHANGED_BEACON) { - struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); - - if (beacon) - iwl_mac_beacon_update(hw, beacon); - } + if (vif->type == NL80211_IFTYPE_ADHOC && changes & BSS_CHANGED_BEACON) + iwlcore_beacon_update(hw, vif); if (changes & BSS_CHANGED_ERP_PREAMBLE) { IWL_DEBUG_MAC80211(priv, "ERP_PREAMBLE %d\n", -- cgit v0.10.2 From d3f5ba958d6c425a87535c6fa2a69ca90eb6e930 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Sep 2010 18:02:00 +0200 Subject: iwlwifi: remove verify_signature eeprom operation All drivers share the same implementation, so there's no need to call this via a function pointer nor to export it. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 134f545..8c2db55 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -209,7 +209,6 @@ static struct iwl_lib_ops iwl1000_lib = { EEPROM_REG_BAND_24_HT40_CHANNELS, EEPROM_REG_BAND_52_HT40_CHANNELS }, - .verify_signature = iwlcore_eeprom_verify_signature, .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, .release_semaphore = iwlcore_eeprom_release_semaphore, .calib_version = iwlagn_eeprom_calib_version, diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index ef67087..a7dbb28 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -2686,7 +2686,6 @@ static struct iwl_lib_ops iwl3945_lib = { EEPROM_REGULATORY_BAND_NO_HT40, EEPROM_REGULATORY_BAND_NO_HT40, }, - .verify_signature = iwlcore_eeprom_verify_signature, .acquire_semaphore = iwl3945_eeprom_acquire_semaphore, .release_semaphore = iwl3945_eeprom_release_semaphore, .query_addr = iwlcore_eeprom_query_addr, diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 20626c9..08d2dbc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2280,7 +2280,6 @@ static struct iwl_lib_ops iwl4965_lib = { EEPROM_4965_REGULATORY_BAND_24_HT40_CHANNELS, EEPROM_4965_REGULATORY_BAND_52_HT40_CHANNELS }, - .verify_signature = iwlcore_eeprom_verify_signature, .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, .release_semaphore = iwlcore_eeprom_release_semaphore, .calib_version = iwl4965_eeprom_calib_version, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 1b25ad6..ddbbb93 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -384,7 +384,6 @@ static struct iwl_lib_ops iwl5000_lib = { EEPROM_REG_BAND_24_HT40_CHANNELS, EEPROM_REG_BAND_52_HT40_CHANNELS }, - .verify_signature = iwlcore_eeprom_verify_signature, .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, .release_semaphore = iwlcore_eeprom_release_semaphore, .calib_version = iwlagn_eeprom_calib_version, @@ -456,7 +455,6 @@ static struct iwl_lib_ops iwl5150_lib = { EEPROM_REG_BAND_24_HT40_CHANNELS, EEPROM_REG_BAND_52_HT40_CHANNELS }, - .verify_signature = iwlcore_eeprom_verify_signature, .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, .release_semaphore = iwlcore_eeprom_release_semaphore, .calib_version = iwlagn_eeprom_calib_version, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 6261aec..198cd8f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -323,7 +323,6 @@ static struct iwl_lib_ops iwl6000_lib = { EEPROM_6000_REG_BAND_24_HT40_CHANNELS, EEPROM_REG_BAND_52_HT40_CHANNELS }, - .verify_signature = iwlcore_eeprom_verify_signature, .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, .release_semaphore = iwlcore_eeprom_release_semaphore, .calib_version = iwlagn_eeprom_calib_version, @@ -398,7 +397,6 @@ static struct iwl_lib_ops iwl6000g2b_lib = { EEPROM_6000_REG_BAND_24_HT40_CHANNELS, EEPROM_REG_BAND_52_HT40_CHANNELS }, - .verify_signature = iwlcore_eeprom_verify_signature, .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, .release_semaphore = iwlcore_eeprom_release_semaphore, .calib_version = iwlagn_eeprom_calib_version, diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 88f4a80..bd51b06 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -214,7 +214,7 @@ static const struct iwl_txpwr_section enhinfo[] = { * ******************************************************************************/ -int iwlcore_eeprom_verify_signature(struct iwl_priv *priv) +static int iwl_eeprom_verify_signature(struct iwl_priv *priv) { u32 gp = iwl_read32(priv, CSR_EEPROM_GP) & CSR_EEPROM_GP_VALID_MSK; int ret = 0; @@ -246,7 +246,6 @@ int iwlcore_eeprom_verify_signature(struct iwl_priv *priv) } return ret; } -EXPORT_SYMBOL(iwlcore_eeprom_verify_signature); static void iwl_set_otp_access(struct iwl_priv *priv, enum iwl_access_mode mode) { @@ -523,7 +522,7 @@ int iwl_eeprom_init(struct iwl_priv *priv) priv->cfg->ops->lib->apm_ops.init(priv); - ret = priv->cfg->ops->lib->eeprom_ops.verify_signature(priv); + ret = iwl_eeprom_verify_signature(priv); if (ret < 0) { IWL_ERR(priv, "EEPROM not found, EEPROM_GP=0x%08x\n", gp); ret = -ENOENT; diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index a4772af..2ae0a11 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -493,7 +493,6 @@ struct iwl_eeprom_calib_info { 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); u16 (*calib_version) (struct iwl_priv *priv); -- cgit v0.10.2 From a30e3112a8bcb5bc1caa48547e597de3992e1b21 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Sep 2010 18:02:01 +0200 Subject: iwlwifi: move agn specific station code there By duplicating a little bit of code between 3945 and agn, we can move a lot of code into an agn specific station management file and thus reduce the amount of code in core that is dead to 3945. before: text data bss dec hex filename 212886 3872 96 216854 34f16 iwlcore.ko 620542 10448 304 631294 9a1fe iwlagn.ko 314013 3264 196 317473 4d821 iwl3945.ko after: text data bss dec hex filename 202857 3872 92 206821 327e5 iwlcore.ko 629102 10448 308 639858 9c372 iwlagn.ko 314240 3264 196 317700 4d904 iwl3945.ko delta: -10029 iwlcore.ko 8560 iwlagn.ko 227 iwl3945.ko so it's a net win even if you have both loaded, likely because a lot of EXPORT_SYMBOLs go away. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 4931639..b4b24b6 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -12,7 +12,7 @@ obj-$(CONFIG_IWLAGN) += iwlagn.o iwlagn-objs := iwl-agn.o iwl-agn-rs.o iwl-agn-led.o iwl-agn-ict.o iwlagn-objs += iwl-agn-ucode.o iwl-agn-hcmd.o iwl-agn-tx.o iwlagn-objs += iwl-agn-lib.o iwl-agn-rx.o iwl-agn-calib.o -iwlagn-objs += iwl-agn-tt.o +iwlagn-objs += iwl-agn-tt.o iwl-agn-sta.o iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-agn-debugfs.o iwlagn-$(CONFIG_IWL4965) += iwl-4965.o diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index a7dbb28..4b3eb78 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -2299,6 +2299,32 @@ static u16 iwl3945_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) return (u16)sizeof(struct iwl3945_addsta_cmd); } +static int iwl3945_add_bssid_station(struct iwl_priv *priv, + const u8 *addr, u8 *sta_id_r) +{ + struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; + int ret; + u8 sta_id; + unsigned long flags; + + if (sta_id_r) + *sta_id_r = IWL_INVALID_STATION; + + ret = iwl_add_station_common(priv, ctx, addr, 0, NULL, &sta_id); + if (ret) { + IWL_ERR(priv, "Unable to add station %pM\n", addr); + return ret; + } + + if (sta_id_r) + *sta_id_r = sta_id; + + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].used |= IWL_STA_LOCAL; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + return 0; +} static int iwl3945_manage_ibss_station(struct iwl_priv *priv, struct ieee80211_vif *vif, bool add) { @@ -2306,10 +2332,8 @@ static int iwl3945_manage_ibss_station(struct iwl_priv *priv, int ret; if (add) { - ret = iwl_add_bssid_station( - priv, &priv->contexts[IWL_RXON_CTX_BSS], - vif->bss_conf.bssid, false, - &vif_priv->ibss_bssid_sta_id); + ret = iwl3945_add_bssid_station(priv, vif->bss_conf.bssid, + &vif_priv->ibss_bssid_sta_id); if (ret) return ret; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 0b45bce..3eeab0a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -1587,9 +1587,9 @@ int iwlagn_manage_ibss_station(struct iwl_priv *priv, struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; if (add) - return iwl_add_bssid_station(priv, vif_priv->ctx, - vif->bss_conf.bssid, true, - &vif_priv->ibss_bssid_sta_id); + return iwlagn_add_bssid_station(priv, vif_priv->ctx, + vif->bss_conf.bssid, + &vif_priv->ibss_bssid_sta_id); return iwl_remove_station(priv, vif_priv->ibss_bssid_sta_id, vif->bss_conf.bssid); } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index f865685..7e5cf1a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -39,6 +39,7 @@ #include "iwl-dev.h" #include "iwl-sta.h" #include "iwl-core.h" +#include "iwl-agn.h" #define RS_NAME "iwl-agn-rs" diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c new file mode 100644 index 0000000..35a30d2 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c @@ -0,0 +1,716 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2010 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: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#include + +#include "iwl-dev.h" +#include "iwl-core.h" +#include "iwl-sta.h" +#include "iwl-agn.h" + +static struct iwl_link_quality_cmd * +iwl_sta_alloc_lq(struct iwl_priv *priv, u8 sta_id) +{ + int i, r; + struct iwl_link_quality_cmd *link_cmd; + u32 rate_flags = 0; + __le32 rate_n_flags; + + link_cmd = kzalloc(sizeof(struct iwl_link_quality_cmd), GFP_KERNEL); + if (!link_cmd) { + IWL_ERR(priv, "Unable to allocate memory for LQ cmd.\n"); + return NULL; + } + /* 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 (priv->band == IEEE80211_BAND_5GHZ) + r = IWL_RATE_6M_INDEX; + else + r = IWL_RATE_1M_INDEX; + + if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE) + rate_flags |= RATE_MCS_CCK_MSK; + + rate_flags |= first_antenna(priv->hw_params.valid_tx_ant) << + RATE_MCS_ANT_POS; + rate_n_flags = iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags); + for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) + link_cmd->rs_table[i].rate_n_flags = rate_n_flags; + + link_cmd->general_params.single_stream_ant_msk = + first_antenna(priv->hw_params.valid_tx_ant); + + link_cmd->general_params.dual_stream_ant_msk = + priv->hw_params.valid_tx_ant & + ~first_antenna(priv->hw_params.valid_tx_ant); + if (!link_cmd->general_params.dual_stream_ant_msk) { + link_cmd->general_params.dual_stream_ant_msk = ANT_AB; + } else if (num_of_ant(priv->hw_params.valid_tx_ant) == 2) { + link_cmd->general_params.dual_stream_ant_msk = + priv->hw_params.valid_tx_ant; + } + + link_cmd->agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF; + link_cmd->agg_params.agg_time_limit = + cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF); + + link_cmd->sta_id = sta_id; + + return link_cmd; +} + +/* + * iwlagn_add_bssid_station - Add the special IBSS BSSID station + * + * Function sleeps. + */ +int iwlagn_add_bssid_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx, + const u8 *addr, u8 *sta_id_r) +{ + int ret; + u8 sta_id; + struct iwl_link_quality_cmd *link_cmd; + unsigned long flags; + + if (sta_id_r) + *sta_id_r = IWL_INVALID_STATION; + + ret = iwl_add_station_common(priv, ctx, addr, 0, NULL, &sta_id); + if (ret) { + IWL_ERR(priv, "Unable to add station %pM\n", addr); + return ret; + } + + if (sta_id_r) + *sta_id_r = sta_id; + + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].used |= IWL_STA_LOCAL; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + /* Set up default rate scaling table in device's station table */ + link_cmd = iwl_sta_alloc_lq(priv, sta_id); + if (!link_cmd) { + IWL_ERR(priv, "Unable to initialize rate scaling for station %pM.\n", + addr); + return -ENOMEM; + } + + ret = iwl_send_lq_cmd(priv, ctx, link_cmd, CMD_SYNC, true); + if (ret) + IWL_ERR(priv, "Link quality command failed (%d)\n", ret); + + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].lq = link_cmd; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + return 0; +} + +static int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, + struct iwl_rxon_context *ctx, + bool send_if_empty) +{ + int i, not_empty = 0; + u8 buff[sizeof(struct iwl_wep_cmd) + + sizeof(struct iwl_wep_key) * WEP_KEYS_MAX]; + struct iwl_wep_cmd *wep_cmd = (struct iwl_wep_cmd *)buff; + size_t cmd_size = sizeof(struct iwl_wep_cmd); + struct iwl_host_cmd cmd = { + .id = ctx->wep_key_cmd, + .data = wep_cmd, + .flags = CMD_SYNC, + }; + + might_sleep(); + + memset(wep_cmd, 0, cmd_size + + (sizeof(struct iwl_wep_key) * WEP_KEYS_MAX)); + + for (i = 0; i < WEP_KEYS_MAX ; i++) { + wep_cmd->key[i].key_index = i; + if (ctx->wep_keys[i].key_size) { + wep_cmd->key[i].key_offset = i; + not_empty = 1; + } else { + wep_cmd->key[i].key_offset = WEP_INVALID_OFFSET; + } + + wep_cmd->key[i].key_size = ctx->wep_keys[i].key_size; + memcpy(&wep_cmd->key[i].key[3], ctx->wep_keys[i].key, + ctx->wep_keys[i].key_size); + } + + wep_cmd->global_key_type = WEP_KEY_WEP_TYPE; + wep_cmd->num_keys = WEP_KEYS_MAX; + + cmd_size += sizeof(struct iwl_wep_key) * WEP_KEYS_MAX; + + cmd.len = cmd_size; + + if (not_empty || send_if_empty) + return iwl_send_cmd(priv, &cmd); + else + return 0; +} + +int iwl_restore_default_wep_keys(struct iwl_priv *priv, + struct iwl_rxon_context *ctx) +{ + lockdep_assert_held(&priv->mutex); + + return iwl_send_static_wepkey_cmd(priv, ctx, false); +} + +int iwl_remove_default_wep_key(struct iwl_priv *priv, + struct iwl_rxon_context *ctx, + struct ieee80211_key_conf *keyconf) +{ + int ret; + + lockdep_assert_held(&priv->mutex); + + IWL_DEBUG_WEP(priv, "Removing default WEP key: idx=%d\n", + keyconf->keyidx); + + memset(&ctx->wep_keys[keyconf->keyidx], 0, sizeof(ctx->wep_keys[0])); + if (iwl_is_rfkill(priv)) { + IWL_DEBUG_WEP(priv, "Not sending REPLY_WEPKEY command due to RFKILL.\n"); + /* but keys in device are clear anyway so return success */ + return 0; + } + ret = iwl_send_static_wepkey_cmd(priv, ctx, 1); + IWL_DEBUG_WEP(priv, "Remove default WEP key: idx=%d ret=%d\n", + keyconf->keyidx, ret); + + return ret; +} + +int iwl_set_default_wep_key(struct iwl_priv *priv, + struct iwl_rxon_context *ctx, + struct ieee80211_key_conf *keyconf) +{ + int ret; + + lockdep_assert_held(&priv->mutex); + + if (keyconf->keylen != WEP_KEY_LEN_128 && + keyconf->keylen != WEP_KEY_LEN_64) { + IWL_DEBUG_WEP(priv, "Bad WEP key length %d\n", keyconf->keylen); + return -EINVAL; + } + + keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV; + keyconf->hw_key_idx = HW_KEY_DEFAULT; + priv->stations[ctx->ap_sta_id].keyinfo.cipher = keyconf->cipher; + + ctx->wep_keys[keyconf->keyidx].key_size = keyconf->keylen; + memcpy(&ctx->wep_keys[keyconf->keyidx].key, &keyconf->key, + keyconf->keylen); + + ret = iwl_send_static_wepkey_cmd(priv, ctx, false); + IWL_DEBUG_WEP(priv, "Set default WEP key: len=%d idx=%d ret=%d\n", + keyconf->keylen, keyconf->keyidx, ret); + + return ret; +} + +static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv, + struct iwl_rxon_context *ctx, + struct ieee80211_key_conf *keyconf, + u8 sta_id) +{ + unsigned long flags; + __le16 key_flags = 0; + struct iwl_addsta_cmd sta_cmd; + + lockdep_assert_held(&priv->mutex); + + keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV; + + key_flags |= (STA_KEY_FLG_WEP | STA_KEY_FLG_MAP_KEY_MSK); + key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS); + key_flags &= ~STA_KEY_FLG_INVALID; + + if (keyconf->keylen == WEP_KEY_LEN_128) + key_flags |= STA_KEY_FLG_KEY_SIZE_MSK; + + if (sta_id == ctx->bcast_sta_id) + key_flags |= STA_KEY_MULTICAST_MSK; + + spin_lock_irqsave(&priv->sta_lock, flags); + + priv->stations[sta_id].keyinfo.cipher = keyconf->cipher; + priv->stations[sta_id].keyinfo.keylen = keyconf->keylen; + priv->stations[sta_id].keyinfo.keyidx = keyconf->keyidx; + + memcpy(priv->stations[sta_id].keyinfo.key, + keyconf->key, keyconf->keylen); + + memcpy(&priv->stations[sta_id].sta.key.key[3], + keyconf->key, keyconf->keylen); + + 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. */ + + WARN(priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET, + "no space for a new key"); + + 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; + + memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd)); + spin_unlock_irqrestore(&priv->sta_lock, flags); + + return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); +} + +static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv, + struct iwl_rxon_context *ctx, + struct ieee80211_key_conf *keyconf, + u8 sta_id) +{ + unsigned long flags; + __le16 key_flags = 0; + struct iwl_addsta_cmd sta_cmd; + + lockdep_assert_held(&priv->mutex); + + key_flags |= (STA_KEY_FLG_CCMP | STA_KEY_FLG_MAP_KEY_MSK); + key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS); + key_flags &= ~STA_KEY_FLG_INVALID; + + if (sta_id == ctx->bcast_sta_id) + key_flags |= STA_KEY_MULTICAST_MSK; + + keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].keyinfo.cipher = keyconf->cipher; + priv->stations[sta_id].keyinfo.keylen = keyconf->keylen; + + memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, + keyconf->keylen); + + memcpy(priv->stations[sta_id].sta.key.key, keyconf->key, + keyconf->keylen); + + 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. */ + + WARN(priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET, + "no space for a new key"); + + 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; + + memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd)); + spin_unlock_irqrestore(&priv->sta_lock, flags); + + return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); +} + +static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv, + struct iwl_rxon_context *ctx, + struct ieee80211_key_conf *keyconf, + u8 sta_id) +{ + unsigned long flags; + int ret = 0; + __le16 key_flags = 0; + + key_flags |= (STA_KEY_FLG_TKIP | STA_KEY_FLG_MAP_KEY_MSK); + key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS); + key_flags &= ~STA_KEY_FLG_INVALID; + + if (sta_id == ctx->bcast_sta_id) + key_flags |= STA_KEY_MULTICAST_MSK; + + keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; + + spin_lock_irqsave(&priv->sta_lock, flags); + + priv->stations[sta_id].keyinfo.cipher = keyconf->cipher; + priv->stations[sta_id].keyinfo.keylen = 16; + + 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. */ + + WARN(priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET, + "no space for a new key"); + + priv->stations[sta_id].sta.key.key_flags = key_flags; + + + /* This copy is acutally not needed: we get the key with each TX */ + memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, 16); + + memcpy(priv->stations[sta_id].sta.key.key, keyconf->key, 16); + + spin_unlock_irqrestore(&priv->sta_lock, flags); + + return ret; +} + +void iwl_update_tkip_key(struct iwl_priv *priv, + struct iwl_rxon_context *ctx, + struct ieee80211_key_conf *keyconf, + struct ieee80211_sta *sta, u32 iv32, u16 *phase1key) +{ + u8 sta_id; + unsigned long flags; + int i; + + if (iwl_scan_cancel(priv)) { + /* cancel scan failed, just live w/ bad key and rely + briefly on SW decryption */ + return; + } + + sta_id = iwl_sta_id_or_broadcast(priv, ctx, sta); + if (sta_id == IWL_INVALID_STATION) + return; + + spin_lock_irqsave(&priv->sta_lock, flags); + + priv->stations[sta_id].sta.key.tkip_rx_tsc_byte2 = (u8) iv32; + + for (i = 0; i < 5; i++) + priv->stations[sta_id].sta.key.tkip_rx_ttak[i] = + cpu_to_le16(phase1key[i]); + + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + + iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); + + spin_unlock_irqrestore(&priv->sta_lock, flags); + +} + +int iwl_remove_dynamic_key(struct iwl_priv *priv, + struct iwl_rxon_context *ctx, + struct ieee80211_key_conf *keyconf, + u8 sta_id) +{ + unsigned long flags; + u16 key_flags; + u8 keyidx; + struct iwl_addsta_cmd sta_cmd; + + lockdep_assert_held(&priv->mutex); + + ctx->key_mapping_keys--; + + 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; + + IWL_DEBUG_WEP(priv, "Remove dynamic key: idx=%d sta=%d\n", + keyconf->keyidx, sta_id); + + 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 (priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET) { + IWL_WARN(priv, "Removing wrong key %d 0x%x\n", + keyconf->keyidx, key_flags); + 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_ERR(priv, "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 iwl_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 | 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; + + if (iwl_is_rfkill(priv)) { + IWL_DEBUG_WEP(priv, "Not sending REPLY_ADD_STA command because RFKILL enabled.\n"); + spin_unlock_irqrestore(&priv->sta_lock, flags); + return 0; + } + memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd)); + spin_unlock_irqrestore(&priv->sta_lock, flags); + + return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); +} + +int iwl_set_dynamic_key(struct iwl_priv *priv, struct iwl_rxon_context *ctx, + struct ieee80211_key_conf *keyconf, u8 sta_id) +{ + int ret; + + lockdep_assert_held(&priv->mutex); + + ctx->key_mapping_keys++; + keyconf->hw_key_idx = HW_KEY_DYNAMIC; + + switch (keyconf->cipher) { + case WLAN_CIPHER_SUITE_CCMP: + ret = iwl_set_ccmp_dynamic_key_info(priv, ctx, keyconf, sta_id); + break; + case WLAN_CIPHER_SUITE_TKIP: + ret = iwl_set_tkip_dynamic_key_info(priv, ctx, keyconf, sta_id); + break; + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + ret = iwl_set_wep_dynamic_key_info(priv, ctx, keyconf, sta_id); + break; + default: + IWL_ERR(priv, + "Unknown alg: %s cipher = %x\n", __func__, + keyconf->cipher); + ret = -EINVAL; + } + + IWL_DEBUG_WEP(priv, "Set dynamic key: cipher=%x len=%d idx=%d sta=%d ret=%d\n", + keyconf->cipher, keyconf->keylen, keyconf->keyidx, + sta_id, ret); + + return ret; +} + +/** + * iwlagn_alloc_bcast_station - add broadcast station into driver's station table. + * + * This adds the broadcast station into the driver's station table + * and marks it driver active, so that it will be restored to the + * device at the next best time. + */ +int iwlagn_alloc_bcast_station(struct iwl_priv *priv, + struct iwl_rxon_context *ctx) +{ + struct iwl_link_quality_cmd *link_cmd; + unsigned long flags; + u8 sta_id; + + spin_lock_irqsave(&priv->sta_lock, flags); + sta_id = iwl_prep_station(priv, ctx, iwl_bcast_addr, false, NULL); + if (sta_id == IWL_INVALID_STATION) { + IWL_ERR(priv, "Unable to prepare broadcast station\n"); + spin_unlock_irqrestore(&priv->sta_lock, flags); + + return -EINVAL; + } + + priv->stations[sta_id].used |= IWL_STA_DRIVER_ACTIVE; + priv->stations[sta_id].used |= IWL_STA_BCAST; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + link_cmd = iwl_sta_alloc_lq(priv, sta_id); + if (!link_cmd) { + IWL_ERR(priv, + "Unable to initialize rate scaling for bcast station.\n"); + return -ENOMEM; + } + + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].lq = link_cmd; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + return 0; +} + +/** + * iwl_update_bcast_station - update broadcast station's LQ command + * + * Only used by iwlagn. Placed here to have all bcast station management + * code together. + */ +static int iwl_update_bcast_station(struct iwl_priv *priv, + struct iwl_rxon_context *ctx) +{ + unsigned long flags; + struct iwl_link_quality_cmd *link_cmd; + u8 sta_id = ctx->bcast_sta_id; + + link_cmd = iwl_sta_alloc_lq(priv, sta_id); + if (!link_cmd) { + IWL_ERR(priv, "Unable to initialize rate scaling for bcast station.\n"); + return -ENOMEM; + } + + spin_lock_irqsave(&priv->sta_lock, flags); + if (priv->stations[sta_id].lq) + kfree(priv->stations[sta_id].lq); + else + IWL_DEBUG_INFO(priv, "Bcast station rate scaling has not been initialized yet.\n"); + priv->stations[sta_id].lq = link_cmd; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + return 0; +} + +int iwl_update_bcast_stations(struct iwl_priv *priv) +{ + struct iwl_rxon_context *ctx; + int ret = 0; + + for_each_context(priv, ctx) { + ret = iwl_update_bcast_station(priv, ctx); + if (ret) + break; + } + + return ret; +} + +/** + * iwl_sta_tx_modify_enable_tid - Enable Tx for this TID in station table + */ +int iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid) +{ + unsigned long flags; + struct iwl_addsta_cmd sta_cmd; + + lockdep_assert_held(&priv->mutex); + + /* Remove "disable" flag, to enable Tx for this TID */ + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_TID_DISABLE_TX; + priv->stations[sta_id].sta.tid_disable_tx &= cpu_to_le16(~(1 << tid)); + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd)); + spin_unlock_irqrestore(&priv->sta_lock, flags); + + return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); +} + +int iwl_sta_rx_agg_start(struct iwl_priv *priv, struct ieee80211_sta *sta, + int tid, u16 ssn) +{ + unsigned long flags; + int sta_id; + struct iwl_addsta_cmd sta_cmd; + + lockdep_assert_held(&priv->mutex); + + sta_id = iwl_sta_id(sta); + if (sta_id == IWL_INVALID_STATION) + return -ENXIO; + + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].sta.station_flags_msk = 0; + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_ADDBA_TID_MSK; + priv->stations[sta_id].sta.add_immediate_ba_tid = (u8)tid; + priv->stations[sta_id].sta.add_immediate_ba_ssn = cpu_to_le16(ssn); + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd)); + spin_unlock_irqrestore(&priv->sta_lock, flags); + + return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); +} + +int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta, + int tid) +{ + unsigned long flags; + int sta_id; + struct iwl_addsta_cmd sta_cmd; + + lockdep_assert_held(&priv->mutex); + + sta_id = iwl_sta_id(sta); + if (sta_id == IWL_INVALID_STATION) { + IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid); + return -ENXIO; + } + + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].sta.station_flags_msk = 0; + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK; + priv->stations[sta_id].sta.remove_immediate_ba_tid = (u8)tid; + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd)); + spin_unlock_irqrestore(&priv->sta_lock, flags); + + return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); +} + +void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK; + priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK; + priv->stations[sta_id].sta.sta.modify_mask = 0; + priv->stations[sta_id].sta.sleep_tx_count = 0; + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); + spin_unlock_irqrestore(&priv->sta_lock, flags); + +} + +void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].sta.station_flags |= STA_FLG_PWR_SAVE_MSK; + priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK; + priv->stations[sta_id].sta.sta.modify_mask = + STA_MODIFY_SLEEP_TX_COUNT_MSK; + priv->stations[sta_id].sta.sleep_tx_count = cpu_to_le16(cnt); + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); + spin_unlock_irqrestore(&priv->sta_lock, flags); + +} diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index b59ce92..8233c64 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3089,7 +3089,7 @@ static int __iwl_up(struct iwl_priv *priv) } for_each_context(priv, ctx) { - ret = iwl_alloc_bcast_station(priv, ctx, true); + ret = iwlagn_alloc_bcast_station(priv, ctx); if (ret) { iwl_dealloc_bcast_stations(priv); return ret; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index 5d5cacb..632ea4b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -252,4 +252,35 @@ const char *iwl_get_agg_tx_fail_reason(u16 status); #else static inline const char *iwl_get_agg_tx_fail_reason(u16 status) { return ""; } #endif + +/* station management */ +int iwlagn_alloc_bcast_station(struct iwl_priv *priv, + struct iwl_rxon_context *ctx); +int iwlagn_add_bssid_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx, + const u8 *addr, u8 *sta_id_r); +int iwl_remove_default_wep_key(struct iwl_priv *priv, + struct iwl_rxon_context *ctx, + struct ieee80211_key_conf *key); +int iwl_set_default_wep_key(struct iwl_priv *priv, + struct iwl_rxon_context *ctx, + struct ieee80211_key_conf *key); +int iwl_restore_default_wep_keys(struct iwl_priv *priv, + struct iwl_rxon_context *ctx); +int iwl_set_dynamic_key(struct iwl_priv *priv, struct iwl_rxon_context *ctx, + struct ieee80211_key_conf *key, u8 sta_id); +int iwl_remove_dynamic_key(struct iwl_priv *priv, struct iwl_rxon_context *ctx, + struct ieee80211_key_conf *key, u8 sta_id); +void iwl_update_tkip_key(struct iwl_priv *priv, + struct iwl_rxon_context *ctx, + struct ieee80211_key_conf *keyconf, + struct ieee80211_sta *sta, u32 iv32, u16 *phase1key); +int iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid); +int iwl_sta_rx_agg_start(struct iwl_priv *priv, struct ieee80211_sta *sta, + int tid, u16 ssn); +int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta, + int tid); +void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id); +void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt); +int iwl_update_bcast_stations(struct iwl_priv *priv); + #endif /* __iwl_agn_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 50a3c26..31ec9db 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -750,8 +750,6 @@ static inline int iwl_is_ready_rf(struct iwl_priv *priv) extern void iwl_send_bt_config(struct iwl_priv *priv); extern int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear); -extern int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx, - struct iwl_link_quality_cmd *lq, u8 flags, bool init); void iwl_apm_stop(struct iwl_priv *priv); int iwl_apm_init(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 6edd034..7c7f7dc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -228,9 +228,8 @@ static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index, * * should be called with sta_lock held */ -static u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx, - const u8 *addr, bool is_ap, - struct ieee80211_sta *sta) +u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx, + const u8 *addr, bool is_ap, struct ieee80211_sta *sta) { struct iwl_station_entry *station; int i; @@ -317,6 +316,7 @@ static u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx, return sta_id; } +EXPORT_SYMBOL_GPL(iwl_prep_station); #define STA_WAIT_TIMEOUT (HZ/2) @@ -381,108 +381,6 @@ int iwl_add_station_common(struct iwl_priv *priv, struct iwl_rxon_context *ctx, } EXPORT_SYMBOL(iwl_add_station_common); -static struct iwl_link_quality_cmd *iwl_sta_alloc_lq(struct iwl_priv *priv, - u8 sta_id) -{ - int i, r; - struct iwl_link_quality_cmd *link_cmd; - u32 rate_flags = 0; - __le32 rate_n_flags; - - link_cmd = kzalloc(sizeof(struct iwl_link_quality_cmd), GFP_KERNEL); - if (!link_cmd) { - IWL_ERR(priv, "Unable to allocate memory for LQ cmd.\n"); - return NULL; - } - /* 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 (priv->band == IEEE80211_BAND_5GHZ) - r = IWL_RATE_6M_INDEX; - else - r = IWL_RATE_1M_INDEX; - - if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE) - rate_flags |= RATE_MCS_CCK_MSK; - - rate_flags |= first_antenna(priv->hw_params.valid_tx_ant) << - RATE_MCS_ANT_POS; - rate_n_flags = iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags); - for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) - link_cmd->rs_table[i].rate_n_flags = rate_n_flags; - - link_cmd->general_params.single_stream_ant_msk = - first_antenna(priv->hw_params.valid_tx_ant); - - link_cmd->general_params.dual_stream_ant_msk = - priv->hw_params.valid_tx_ant & - ~first_antenna(priv->hw_params.valid_tx_ant); - if (!link_cmd->general_params.dual_stream_ant_msk) { - link_cmd->general_params.dual_stream_ant_msk = ANT_AB; - } else if (num_of_ant(priv->hw_params.valid_tx_ant) == 2) { - link_cmd->general_params.dual_stream_ant_msk = - priv->hw_params.valid_tx_ant; - } - - link_cmd->agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF; - link_cmd->agg_params.agg_time_limit = - cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF); - - link_cmd->sta_id = sta_id; - - return link_cmd; -} - -/* - * iwl_add_bssid_station - Add the special IBSS BSSID station - * - * Function sleeps. - */ -int iwl_add_bssid_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx, - const u8 *addr, bool init_rs, u8 *sta_id_r) -{ - int ret; - u8 sta_id; - struct iwl_link_quality_cmd *link_cmd; - unsigned long flags; - - if (sta_id_r) - *sta_id_r = IWL_INVALID_STATION; - - ret = iwl_add_station_common(priv, ctx, addr, 0, NULL, &sta_id); - if (ret) { - IWL_ERR(priv, "Unable to add station %pM\n", addr); - return ret; - } - - if (sta_id_r) - *sta_id_r = sta_id; - - spin_lock_irqsave(&priv->sta_lock, flags); - priv->stations[sta_id].used |= IWL_STA_LOCAL; - spin_unlock_irqrestore(&priv->sta_lock, flags); - - if (init_rs) { - /* Set up default rate scaling table in device's station table */ - link_cmd = iwl_sta_alloc_lq(priv, sta_id); - if (!link_cmd) { - IWL_ERR(priv, "Unable to initialize rate scaling for station %pM.\n", - addr); - return -ENOMEM; - } - - ret = iwl_send_lq_cmd(priv, ctx, link_cmd, CMD_SYNC, true); - if (ret) - IWL_ERR(priv, "Link quality command failed (%d)\n", ret); - - spin_lock_irqsave(&priv->sta_lock, flags); - priv->stations[sta_id].lq = link_cmd; - spin_unlock_irqrestore(&priv->sta_lock, flags); - } - - return 0; -} -EXPORT_SYMBOL(iwl_add_bssid_station); - /** * iwl_sta_ucode_deactivate - deactivate ucode status for a station * @@ -738,405 +636,25 @@ int iwl_get_free_ucode_key_index(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_get_free_ucode_key_index); -static int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, - struct iwl_rxon_context *ctx, - bool send_if_empty) -{ - int i, not_empty = 0; - u8 buff[sizeof(struct iwl_wep_cmd) + - sizeof(struct iwl_wep_key) * WEP_KEYS_MAX]; - struct iwl_wep_cmd *wep_cmd = (struct iwl_wep_cmd *)buff; - size_t cmd_size = sizeof(struct iwl_wep_cmd); - struct iwl_host_cmd cmd = { - .id = ctx->wep_key_cmd, - .data = wep_cmd, - .flags = CMD_SYNC, - }; - - might_sleep(); - - memset(wep_cmd, 0, cmd_size + - (sizeof(struct iwl_wep_key) * WEP_KEYS_MAX)); - - for (i = 0; i < WEP_KEYS_MAX ; i++) { - wep_cmd->key[i].key_index = i; - if (ctx->wep_keys[i].key_size) { - wep_cmd->key[i].key_offset = i; - not_empty = 1; - } else { - wep_cmd->key[i].key_offset = WEP_INVALID_OFFSET; - } - - wep_cmd->key[i].key_size = ctx->wep_keys[i].key_size; - memcpy(&wep_cmd->key[i].key[3], ctx->wep_keys[i].key, - ctx->wep_keys[i].key_size); - } - - wep_cmd->global_key_type = WEP_KEY_WEP_TYPE; - wep_cmd->num_keys = WEP_KEYS_MAX; - - cmd_size += sizeof(struct iwl_wep_key) * WEP_KEYS_MAX; - - cmd.len = cmd_size; - - if (not_empty || send_if_empty) - return iwl_send_cmd(priv, &cmd); - else - return 0; -} - -int iwl_restore_default_wep_keys(struct iwl_priv *priv, - struct iwl_rxon_context *ctx) -{ - lockdep_assert_held(&priv->mutex); - - return iwl_send_static_wepkey_cmd(priv, ctx, false); -} -EXPORT_SYMBOL(iwl_restore_default_wep_keys); - -int iwl_remove_default_wep_key(struct iwl_priv *priv, - struct iwl_rxon_context *ctx, - struct ieee80211_key_conf *keyconf) -{ - int ret; - - lockdep_assert_held(&priv->mutex); - - IWL_DEBUG_WEP(priv, "Removing default WEP key: idx=%d\n", - keyconf->keyidx); - - memset(&ctx->wep_keys[keyconf->keyidx], 0, sizeof(ctx->wep_keys[0])); - if (iwl_is_rfkill(priv)) { - IWL_DEBUG_WEP(priv, "Not sending REPLY_WEPKEY command due to RFKILL.\n"); - /* but keys in device are clear anyway so return success */ - return 0; - } - ret = iwl_send_static_wepkey_cmd(priv, ctx, 1); - IWL_DEBUG_WEP(priv, "Remove default WEP key: idx=%d ret=%d\n", - keyconf->keyidx, ret); - - return ret; -} -EXPORT_SYMBOL(iwl_remove_default_wep_key); - -int iwl_set_default_wep_key(struct iwl_priv *priv, - struct iwl_rxon_context *ctx, - struct ieee80211_key_conf *keyconf) -{ - int ret; - - lockdep_assert_held(&priv->mutex); - - if (keyconf->keylen != WEP_KEY_LEN_128 && - keyconf->keylen != WEP_KEY_LEN_64) { - IWL_DEBUG_WEP(priv, "Bad WEP key length %d\n", keyconf->keylen); - return -EINVAL; - } - - keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV; - keyconf->hw_key_idx = HW_KEY_DEFAULT; - priv->stations[ctx->ap_sta_id].keyinfo.cipher = keyconf->cipher; - - ctx->wep_keys[keyconf->keyidx].key_size = keyconf->keylen; - memcpy(&ctx->wep_keys[keyconf->keyidx].key, &keyconf->key, - keyconf->keylen); - - ret = iwl_send_static_wepkey_cmd(priv, ctx, false); - IWL_DEBUG_WEP(priv, "Set default WEP key: len=%d idx=%d ret=%d\n", - keyconf->keylen, keyconf->keyidx, ret); - - return ret; -} -EXPORT_SYMBOL(iwl_set_default_wep_key); - -static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv, - struct iwl_rxon_context *ctx, - struct ieee80211_key_conf *keyconf, - u8 sta_id) -{ - unsigned long flags; - __le16 key_flags = 0; - struct iwl_addsta_cmd sta_cmd; - - lockdep_assert_held(&priv->mutex); - - keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV; - - key_flags |= (STA_KEY_FLG_WEP | STA_KEY_FLG_MAP_KEY_MSK); - key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS); - key_flags &= ~STA_KEY_FLG_INVALID; - - if (keyconf->keylen == WEP_KEY_LEN_128) - key_flags |= STA_KEY_FLG_KEY_SIZE_MSK; - - if (sta_id == ctx->bcast_sta_id) - key_flags |= STA_KEY_MULTICAST_MSK; - - spin_lock_irqsave(&priv->sta_lock, flags); - - priv->stations[sta_id].keyinfo.cipher = keyconf->cipher; - priv->stations[sta_id].keyinfo.keylen = keyconf->keylen; - priv->stations[sta_id].keyinfo.keyidx = keyconf->keyidx; - - memcpy(priv->stations[sta_id].keyinfo.key, - keyconf->key, keyconf->keylen); - - memcpy(&priv->stations[sta_id].sta.key.key[3], - keyconf->key, keyconf->keylen); - - 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. */ - - WARN(priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET, - "no space for a new key"); - - 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; - - memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd)); - spin_unlock_irqrestore(&priv->sta_lock, flags); - - return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); -} - -static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv, - struct iwl_rxon_context *ctx, - struct ieee80211_key_conf *keyconf, - u8 sta_id) -{ - unsigned long flags; - __le16 key_flags = 0; - struct iwl_addsta_cmd sta_cmd; - - lockdep_assert_held(&priv->mutex); - - key_flags |= (STA_KEY_FLG_CCMP | STA_KEY_FLG_MAP_KEY_MSK); - key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS); - key_flags &= ~STA_KEY_FLG_INVALID; - - if (sta_id == ctx->bcast_sta_id) - key_flags |= STA_KEY_MULTICAST_MSK; - - keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; - - spin_lock_irqsave(&priv->sta_lock, flags); - priv->stations[sta_id].keyinfo.cipher = keyconf->cipher; - priv->stations[sta_id].keyinfo.keylen = keyconf->keylen; - - memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, - keyconf->keylen); - - memcpy(priv->stations[sta_id].sta.key.key, keyconf->key, - keyconf->keylen); - - 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. */ - - WARN(priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET, - "no space for a new key"); - - 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; - - memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd)); - spin_unlock_irqrestore(&priv->sta_lock, flags); - - return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); -} - -static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv, - struct iwl_rxon_context *ctx, - struct ieee80211_key_conf *keyconf, - u8 sta_id) -{ - unsigned long flags; - int ret = 0; - __le16 key_flags = 0; - - key_flags |= (STA_KEY_FLG_TKIP | STA_KEY_FLG_MAP_KEY_MSK); - key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS); - key_flags &= ~STA_KEY_FLG_INVALID; - - if (sta_id == ctx->bcast_sta_id) - key_flags |= STA_KEY_MULTICAST_MSK; - - keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; - keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; - - spin_lock_irqsave(&priv->sta_lock, flags); - - priv->stations[sta_id].keyinfo.cipher = keyconf->cipher; - priv->stations[sta_id].keyinfo.keylen = 16; - - 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. */ - - WARN(priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET, - "no space for a new key"); - - priv->stations[sta_id].sta.key.key_flags = key_flags; - - - /* This copy is acutally not needed: we get the key with each TX */ - memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, 16); - - memcpy(priv->stations[sta_id].sta.key.key, keyconf->key, 16); - - spin_unlock_irqrestore(&priv->sta_lock, flags); - - return ret; -} - -void iwl_update_tkip_key(struct iwl_priv *priv, - struct iwl_rxon_context *ctx, - struct ieee80211_key_conf *keyconf, - struct ieee80211_sta *sta, u32 iv32, u16 *phase1key) +void iwl_dealloc_bcast_stations(struct iwl_priv *priv) { - u8 sta_id; unsigned long flags; int i; - if (iwl_scan_cancel(priv)) { - /* cancel scan failed, just live w/ bad key and rely - briefly on SW decryption */ - return; - } - - sta_id = iwl_sta_id_or_broadcast(priv, ctx, sta); - if (sta_id == IWL_INVALID_STATION) - return; - - spin_lock_irqsave(&priv->sta_lock, flags); - - priv->stations[sta_id].sta.key.tkip_rx_tsc_byte2 = (u8) iv32; - - for (i = 0; i < 5; i++) - priv->stations[sta_id].sta.key.tkip_rx_ttak[i] = - cpu_to_le16(phase1key[i]); - - priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; - priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; - - iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); - - spin_unlock_irqrestore(&priv->sta_lock, flags); - -} -EXPORT_SYMBOL(iwl_update_tkip_key); - -int iwl_remove_dynamic_key(struct iwl_priv *priv, - struct iwl_rxon_context *ctx, - struct ieee80211_key_conf *keyconf, - u8 sta_id) -{ - unsigned long flags; - u16 key_flags; - u8 keyidx; - struct iwl_addsta_cmd sta_cmd; - - lockdep_assert_held(&priv->mutex); - - ctx->key_mapping_keys--; - 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; - - IWL_DEBUG_WEP(priv, "Remove dynamic key: idx=%d sta=%d\n", - keyconf->keyidx, sta_id); - - 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 (priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET) { - IWL_WARN(priv, "Removing wrong key %d 0x%x\n", - keyconf->keyidx, key_flags); - spin_unlock_irqrestore(&priv->sta_lock, flags); - return 0; - } + for (i = 0; i < priv->hw_params.max_stations; i++) { + if (!(priv->stations[i].used & IWL_STA_BCAST)) + continue; - if (!test_and_clear_bit(priv->stations[sta_id].sta.key.key_offset, - &priv->ucode_key_table)) - IWL_ERR(priv, "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 iwl_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 | 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; - - if (iwl_is_rfkill(priv)) { - IWL_DEBUG_WEP(priv, "Not sending REPLY_ADD_STA command because RFKILL enabled.\n"); - spin_unlock_irqrestore(&priv->sta_lock, flags); - return 0; + priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE; + priv->num_stations--; + BUG_ON(priv->num_stations < 0); + kfree(priv->stations[i].lq); + priv->stations[i].lq = NULL; } - memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd)); spin_unlock_irqrestore(&priv->sta_lock, flags); - - return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); -} -EXPORT_SYMBOL(iwl_remove_dynamic_key); - -int iwl_set_dynamic_key(struct iwl_priv *priv, struct iwl_rxon_context *ctx, - struct ieee80211_key_conf *keyconf, u8 sta_id) -{ - int ret; - - lockdep_assert_held(&priv->mutex); - - ctx->key_mapping_keys++; - keyconf->hw_key_idx = HW_KEY_DYNAMIC; - - switch (keyconf->cipher) { - case WLAN_CIPHER_SUITE_CCMP: - ret = iwl_set_ccmp_dynamic_key_info(priv, ctx, keyconf, sta_id); - break; - case WLAN_CIPHER_SUITE_TKIP: - ret = iwl_set_tkip_dynamic_key_info(priv, ctx, keyconf, sta_id); - break; - case WLAN_CIPHER_SUITE_WEP40: - case WLAN_CIPHER_SUITE_WEP104: - ret = iwl_set_wep_dynamic_key_info(priv, ctx, keyconf, sta_id); - break; - default: - IWL_ERR(priv, - "Unknown alg: %s cipher = %x\n", __func__, - keyconf->cipher); - ret = -EINVAL; - } - - IWL_DEBUG_WEP(priv, "Set dynamic key: cipher=%x len=%d idx=%d sta=%d ret=%d\n", - keyconf->cipher, keyconf->keylen, keyconf->keyidx, - sta_id, ret); - - return ret; } -EXPORT_SYMBOL(iwl_set_dynamic_key); +EXPORT_SYMBOL_GPL(iwl_dealloc_bcast_stations); #ifdef CONFIG_IWLWIFI_DEBUG static void iwl_dump_lq_cmd(struct iwl_priv *priv, @@ -1240,223 +758,6 @@ int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx, } EXPORT_SYMBOL(iwl_send_lq_cmd); -/** - * iwl_alloc_bcast_station - add broadcast station into driver's station table. - * - * This adds the broadcast station into the driver's station table - * and marks it driver active, so that it will be restored to the - * device at the next best time. - */ -int iwl_alloc_bcast_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx, - bool init_lq) -{ - struct iwl_link_quality_cmd *link_cmd; - unsigned long flags; - u8 sta_id; - - spin_lock_irqsave(&priv->sta_lock, flags); - sta_id = iwl_prep_station(priv, ctx, iwl_bcast_addr, false, NULL); - if (sta_id == IWL_INVALID_STATION) { - IWL_ERR(priv, "Unable to prepare broadcast station\n"); - spin_unlock_irqrestore(&priv->sta_lock, flags); - - return -EINVAL; - } - - priv->stations[sta_id].used |= IWL_STA_DRIVER_ACTIVE; - priv->stations[sta_id].used |= IWL_STA_BCAST; - spin_unlock_irqrestore(&priv->sta_lock, flags); - - if (init_lq) { - link_cmd = iwl_sta_alloc_lq(priv, sta_id); - if (!link_cmd) { - IWL_ERR(priv, - "Unable to initialize rate scaling for bcast station.\n"); - return -ENOMEM; - } - - spin_lock_irqsave(&priv->sta_lock, flags); - priv->stations[sta_id].lq = link_cmd; - spin_unlock_irqrestore(&priv->sta_lock, flags); - } - - return 0; -} -EXPORT_SYMBOL_GPL(iwl_alloc_bcast_station); - -/** - * iwl_update_bcast_station - update broadcast station's LQ command - * - * Only used by iwlagn. Placed here to have all bcast station management - * code together. - */ -static int iwl_update_bcast_station(struct iwl_priv *priv, - struct iwl_rxon_context *ctx) -{ - unsigned long flags; - struct iwl_link_quality_cmd *link_cmd; - u8 sta_id = ctx->bcast_sta_id; - - link_cmd = iwl_sta_alloc_lq(priv, sta_id); - if (!link_cmd) { - IWL_ERR(priv, "Unable to initialize rate scaling for bcast station.\n"); - return -ENOMEM; - } - - spin_lock_irqsave(&priv->sta_lock, flags); - if (priv->stations[sta_id].lq) - kfree(priv->stations[sta_id].lq); - else - IWL_DEBUG_INFO(priv, "Bcast station rate scaling has not been initialized yet.\n"); - priv->stations[sta_id].lq = link_cmd; - spin_unlock_irqrestore(&priv->sta_lock, flags); - - return 0; -} - -int iwl_update_bcast_stations(struct iwl_priv *priv) -{ - struct iwl_rxon_context *ctx; - int ret = 0; - - for_each_context(priv, ctx) { - ret = iwl_update_bcast_station(priv, ctx); - if (ret) - break; - } - - return ret; -} -EXPORT_SYMBOL_GPL(iwl_update_bcast_stations); - -void iwl_dealloc_bcast_stations(struct iwl_priv *priv) -{ - unsigned long flags; - int i; - - spin_lock_irqsave(&priv->sta_lock, flags); - for (i = 0; i < priv->hw_params.max_stations; i++) { - if (!(priv->stations[i].used & IWL_STA_BCAST)) - continue; - - priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE; - priv->num_stations--; - BUG_ON(priv->num_stations < 0); - kfree(priv->stations[i].lq); - priv->stations[i].lq = NULL; - } - spin_unlock_irqrestore(&priv->sta_lock, flags); -} -EXPORT_SYMBOL_GPL(iwl_dealloc_bcast_stations); - -/** - * iwl_sta_tx_modify_enable_tid - Enable Tx for this TID in station table - */ -int iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid) -{ - unsigned long flags; - struct iwl_addsta_cmd sta_cmd; - - lockdep_assert_held(&priv->mutex); - - /* Remove "disable" flag, to enable Tx for this TID */ - spin_lock_irqsave(&priv->sta_lock, flags); - priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_TID_DISABLE_TX; - priv->stations[sta_id].sta.tid_disable_tx &= cpu_to_le16(~(1 << tid)); - priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; - memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd)); - spin_unlock_irqrestore(&priv->sta_lock, flags); - - return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); -} -EXPORT_SYMBOL(iwl_sta_tx_modify_enable_tid); - -int iwl_sta_rx_agg_start(struct iwl_priv *priv, struct ieee80211_sta *sta, - int tid, u16 ssn) -{ - unsigned long flags; - int sta_id; - struct iwl_addsta_cmd sta_cmd; - - lockdep_assert_held(&priv->mutex); - - sta_id = iwl_sta_id(sta); - if (sta_id == IWL_INVALID_STATION) - return -ENXIO; - - spin_lock_irqsave(&priv->sta_lock, flags); - priv->stations[sta_id].sta.station_flags_msk = 0; - priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_ADDBA_TID_MSK; - priv->stations[sta_id].sta.add_immediate_ba_tid = (u8)tid; - priv->stations[sta_id].sta.add_immediate_ba_ssn = cpu_to_le16(ssn); - priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; - memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd)); - spin_unlock_irqrestore(&priv->sta_lock, flags); - - return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); -} -EXPORT_SYMBOL(iwl_sta_rx_agg_start); - -int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta, - int tid) -{ - unsigned long flags; - int sta_id; - struct iwl_addsta_cmd sta_cmd; - - lockdep_assert_held(&priv->mutex); - - sta_id = iwl_sta_id(sta); - if (sta_id == IWL_INVALID_STATION) { - IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid); - return -ENXIO; - } - - spin_lock_irqsave(&priv->sta_lock, flags); - priv->stations[sta_id].sta.station_flags_msk = 0; - priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK; - priv->stations[sta_id].sta.remove_immediate_ba_tid = (u8)tid; - priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; - memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd)); - spin_unlock_irqrestore(&priv->sta_lock, flags); - - return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); -} -EXPORT_SYMBOL(iwl_sta_rx_agg_stop); - -void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) -{ - unsigned long flags; - - spin_lock_irqsave(&priv->sta_lock, flags); - priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK; - priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK; - priv->stations[sta_id].sta.sta.modify_mask = 0; - priv->stations[sta_id].sta.sleep_tx_count = 0; - priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; - iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); - spin_unlock_irqrestore(&priv->sta_lock, flags); - -} -EXPORT_SYMBOL(iwl_sta_modify_ps_wake); - -void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt) -{ - unsigned long flags; - - spin_lock_irqsave(&priv->sta_lock, flags); - priv->stations[sta_id].sta.station_flags |= STA_FLG_PWR_SAVE_MSK; - priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK; - priv->stations[sta_id].sta.sta.modify_mask = - STA_MODIFY_SLEEP_TX_COUNT_MSK; - priv->stations[sta_id].sta.sleep_tx_count = cpu_to_le16(cnt); - priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; - iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); - spin_unlock_irqrestore(&priv->sta_lock, flags); - -} -EXPORT_SYMBOL(iwl_sta_modify_sleep_tx_count); - int iwl_mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h index 56bad3f..0647587 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.h +++ b/drivers/net/wireless/iwlwifi/iwl-sta.h @@ -43,35 +43,13 @@ #define IWL_STA_BCAST BIT(4) /* this station is the special bcast station */ -int iwl_remove_default_wep_key(struct iwl_priv *priv, - struct iwl_rxon_context *ctx, - struct ieee80211_key_conf *key); -int iwl_set_default_wep_key(struct iwl_priv *priv, - struct iwl_rxon_context *ctx, - struct ieee80211_key_conf *key); -int iwl_restore_default_wep_keys(struct iwl_priv *priv, - struct iwl_rxon_context *ctx); -int iwl_set_dynamic_key(struct iwl_priv *priv, struct iwl_rxon_context *ctx, - struct ieee80211_key_conf *key, u8 sta_id); -int iwl_remove_dynamic_key(struct iwl_priv *priv, struct iwl_rxon_context *ctx, - struct ieee80211_key_conf *key, u8 sta_id); -void iwl_update_tkip_key(struct iwl_priv *priv, - struct iwl_rxon_context *ctx, - struct ieee80211_key_conf *keyconf, - struct ieee80211_sta *sta, u32 iv32, u16 *phase1key); - void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx); void iwl_clear_ucode_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx); -int iwl_alloc_bcast_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx, - bool init_lq); void iwl_dealloc_bcast_stations(struct iwl_priv *priv); -int iwl_update_bcast_stations(struct iwl_priv *priv); int iwl_get_free_ucode_key_index(struct iwl_priv *priv); int iwl_send_add_sta(struct iwl_priv *priv, struct iwl_addsta_cmd *sta, u8 flags); -int iwl_add_bssid_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx, - const u8 *addr, bool init_rs, u8 *sta_id_r); int iwl_add_station_common(struct iwl_priv *priv, struct iwl_rxon_context *ctx, const u8 *addr, bool is_ap, struct ieee80211_sta *sta, u8 *sta_id_r); @@ -79,13 +57,12 @@ int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id, const u8 *addr); int iwl_mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta); -int iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid); -int iwl_sta_rx_agg_start(struct iwl_priv *priv, struct ieee80211_sta *sta, - int tid, u16 ssn); -int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta, - int tid); -void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id); -void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt); + +u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx, + const u8 *addr, bool is_ap, struct ieee80211_sta *sta); + +int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx, + struct iwl_link_quality_cmd *lq, u8 flags, bool init); /** * iwl_clear_driver_stations - clear knowledge of all stations from driver diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 64eb049..c06b218 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2661,12 +2661,33 @@ static void iwl3945_down(struct iwl_priv *priv) #define MAX_HW_RESTARTS 5 +static int iwl3945_alloc_bcast_station(struct iwl_priv *priv) +{ + struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; + unsigned long flags; + u8 sta_id; + + spin_lock_irqsave(&priv->sta_lock, flags); + sta_id = iwl_prep_station(priv, ctx, iwl_bcast_addr, false, NULL); + if (sta_id == IWL_INVALID_STATION) { + IWL_ERR(priv, "Unable to prepare broadcast station\n"); + spin_unlock_irqrestore(&priv->sta_lock, flags); + + return -EINVAL; + } + + priv->stations[sta_id].used |= IWL_STA_DRIVER_ACTIVE; + priv->stations[sta_id].used |= IWL_STA_BCAST; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + return 0; +} + static int __iwl3945_up(struct iwl_priv *priv) { int rc, i; - rc = iwl_alloc_bcast_station(priv, &priv->contexts[IWL_RXON_CTX_BSS], - false); + rc = iwl3945_alloc_bcast_station(priv); if (rc) return rc; -- cgit v0.10.2 From 69fdb710b29d096bc50123f7c97891e31ffe45f9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Sep 2010 18:02:02 +0200 Subject: iwlwifi: move tx fail code to agn The code to print out TX failure reasons is AGN specific, so it can be in the AGN module. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index 77753b7..db57aea 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -1391,3 +1391,43 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, spin_unlock_irqrestore(&priv->sta_lock, flags); } + +#ifdef CONFIG_IWLWIFI_DEBUG +const char *iwl_get_tx_fail_reason(u32 status) +{ +#define TX_STATUS_FAIL(x) case TX_STATUS_FAIL_ ## x: return #x +#define TX_STATUS_POSTPONE(x) case TX_STATUS_POSTPONE_ ## x: return #x + + switch (status & TX_STATUS_MSK) { + case TX_STATUS_SUCCESS: + return "SUCCESS"; + TX_STATUS_POSTPONE(DELAY); + TX_STATUS_POSTPONE(FEW_BYTES); + TX_STATUS_POSTPONE(BT_PRIO); + TX_STATUS_POSTPONE(QUIET_PERIOD); + TX_STATUS_POSTPONE(CALC_TTAK); + TX_STATUS_FAIL(INTERNAL_CROSSED_RETRY); + TX_STATUS_FAIL(SHORT_LIMIT); + TX_STATUS_FAIL(LONG_LIMIT); + TX_STATUS_FAIL(FIFO_UNDERRUN); + TX_STATUS_FAIL(DRAIN_FLOW); + TX_STATUS_FAIL(RFKILL_FLUSH); + TX_STATUS_FAIL(LIFE_EXPIRE); + TX_STATUS_FAIL(DEST_PS); + TX_STATUS_FAIL(HOST_ABORTED); + TX_STATUS_FAIL(BT_RETRY); + TX_STATUS_FAIL(STA_INVALID); + TX_STATUS_FAIL(FRAG_DROPPED); + TX_STATUS_FAIL(TID_DISABLE); + TX_STATUS_FAIL(FIFO_FLUSHED); + TX_STATUS_FAIL(INSUFFICIENT_CF_POLL); + TX_STATUS_FAIL(PASSIVE_NO_RX); + TX_STATUS_FAIL(NO_BEACON_ON_RADAR); + } + + return "UNKNOWN"; + +#undef TX_STATUS_FAIL +#undef TX_STATUS_POSTPONE +} +#endif /* CONFIG_IWLWIFI_DEBUG */ diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index 632ea4b..d6645ec 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -248,8 +248,10 @@ void iwlagn_bt_setup_deferred_work(struct iwl_priv *priv); void iwlagn_bt_cancel_deferred_work(struct iwl_priv *priv); #ifdef CONFIG_IWLWIFI_DEBUG +const char *iwl_get_tx_fail_reason(u32 status); const char *iwl_get_agg_tx_fail_reason(u16 status); #else +static inline const char *iwl_get_tx_fail_reason(u32 status) { return ""; } static inline const char *iwl_get_agg_tx_fail_reason(u16 status) { return ""; } #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 90a37a9..2b04714 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1566,7 +1566,6 @@ static inline void iwl_txq_ctx_deactivate(struct iwl_priv *priv, int txq_id) } #ifdef CONFIG_IWLWIFI_DEBUG -const char *iwl_get_tx_fail_reason(u32 status); /* * iwl_get_debug_level: Return active debug level for device * @@ -1582,8 +1581,6 @@ static inline u32 iwl_get_debug_level(struct iwl_priv *priv) return iwl_debug_level; } #else -static inline const char *iwl_get_tx_fail_reason(u32 status) { return ""; } - static inline u32 iwl_get_debug_level(struct iwl_priv *priv) { return iwl_debug_level; diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 3290b15..7261ee4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -636,41 +636,3 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) meta->flags = 0; } EXPORT_SYMBOL(iwl_tx_cmd_complete); - -#ifdef CONFIG_IWLWIFI_DEBUG -#define TX_STATUS_FAIL(x) case TX_STATUS_FAIL_ ## x: return #x -#define TX_STATUS_POSTPONE(x) case TX_STATUS_POSTPONE_ ## x: return #x - -const char *iwl_get_tx_fail_reason(u32 status) -{ - switch (status & TX_STATUS_MSK) { - case TX_STATUS_SUCCESS: - return "SUCCESS"; - TX_STATUS_POSTPONE(DELAY); - TX_STATUS_POSTPONE(FEW_BYTES); - TX_STATUS_POSTPONE(BT_PRIO); - TX_STATUS_POSTPONE(QUIET_PERIOD); - TX_STATUS_POSTPONE(CALC_TTAK); - TX_STATUS_FAIL(INTERNAL_CROSSED_RETRY); - TX_STATUS_FAIL(SHORT_LIMIT); - TX_STATUS_FAIL(LONG_LIMIT); - TX_STATUS_FAIL(FIFO_UNDERRUN); - TX_STATUS_FAIL(DRAIN_FLOW); - TX_STATUS_FAIL(RFKILL_FLUSH); - TX_STATUS_FAIL(LIFE_EXPIRE); - TX_STATUS_FAIL(DEST_PS); - TX_STATUS_FAIL(HOST_ABORTED); - TX_STATUS_FAIL(BT_RETRY); - TX_STATUS_FAIL(STA_INVALID); - TX_STATUS_FAIL(FRAG_DROPPED); - TX_STATUS_FAIL(TID_DISABLE); - TX_STATUS_FAIL(FIFO_FLUSHED); - TX_STATUS_FAIL(INSUFFICIENT_CF_POLL); - TX_STATUS_FAIL(PASSIVE_NO_RX); - TX_STATUS_FAIL(NO_BEACON_ON_RADAR); - } - - return "UNKNOWN"; -} -EXPORT_SYMBOL(iwl_get_tx_fail_reason); -#endif /* CONFIG_IWLWIFI_DEBUG */ -- cgit v0.10.2 From 57934dc1fb7ef65a8a0f5d7a1578536b36043c0a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Sep 2010 18:02:03 +0200 Subject: iwlwifi: remove spurious exports A number of exports, especially related to thermal throttling, are unnecessary because the code lives in the same module that it is used in, so remove them. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tt.c b/drivers/net/wireless/iwlwifi/iwl-agn-tt.c index 0c6c4d9..e3a8216 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tt.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tt.c @@ -571,7 +571,6 @@ void iwl_tt_enter_ct_kill(struct iwl_priv *priv) IWL_DEBUG_POWER(priv, "Queueing critical temperature enter.\n"); queue_work(priv->workqueue, &priv->ct_enter); } -EXPORT_SYMBOL(iwl_tt_enter_ct_kill); void iwl_tt_exit_ct_kill(struct iwl_priv *priv) { @@ -581,7 +580,6 @@ void iwl_tt_exit_ct_kill(struct iwl_priv *priv) IWL_DEBUG_POWER(priv, "Queueing critical temperature exit.\n"); queue_work(priv->workqueue, &priv->ct_exit); } -EXPORT_SYMBOL(iwl_tt_exit_ct_kill); static void iwl_bg_tt_work(struct work_struct *work) { @@ -608,7 +606,6 @@ void iwl_tt_handler(struct iwl_priv *priv) IWL_DEBUG_POWER(priv, "Queueing thermal throttling work.\n"); queue_work(priv->workqueue, &priv->tt_work); } -EXPORT_SYMBOL(iwl_tt_handler); /* Thermal throttling initialization * For advance thermal throttling: @@ -678,7 +675,6 @@ void iwl_tt_initialize(struct iwl_priv *priv) priv->thermal_throttle.advanced_tt = false; } } -EXPORT_SYMBOL(iwl_tt_initialize); /* cleanup thermal throttling management related memory and timer */ void iwl_tt_exit(struct iwl_priv *priv) @@ -701,4 +697,3 @@ void iwl_tt_exit(struct iwl_priv *priv) tt->transaction = NULL; } } -EXPORT_SYMBOL(iwl_tt_exit); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 71f245f..eefcb2d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2653,7 +2653,6 @@ int iwl_force_reset(struct iwl_priv *priv, int mode, bool external) } return 0; } -EXPORT_SYMBOL(iwl_force_reset); /** * iwl_bg_monitor_recover - Timer callback to check for stuck queue and recover diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index a7e8c7f..67da312 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -121,7 +121,6 @@ void iwl_force_scan_end(struct iwl_priv *priv) clear_bit(STATUS_SCAN_ABORTING, &priv->status); iwl_complete_scan(priv, true); } -EXPORT_SYMBOL(iwl_force_scan_end); static void iwl_do_scan_abort(struct iwl_priv *priv) { -- cgit v0.10.2 From 635b85b42796a6ab4e6a31cde78f1d9660c9c4a0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Sep 2010 18:02:04 +0200 Subject: iwlwifi: remove agn rates info there Code and data related to agn bitrates can be part of the agn module rather than being in the core module. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 4b3eb78..ba3ab04 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -87,6 +87,15 @@ const struct iwl3945_rate_info iwl3945_rates[IWL_RATE_COUNT_3945] = { IWL_DECLARE_RATE_INFO(54, 48, INV, 48, INV, 48, INV),/* 54mbps */ }; +static inline u8 iwl3945_get_prev_ieee_rate(u8 rate_index) +{ + u8 rate = iwl3945_rates[rate_index].prev_ieee; + + if (rate == IWL_RATE_INVALID) + rate = rate_index; + return rate; +} + /* 1 = enable the iwl3945_disable_events() function */ #define IWL_EVT_DISABLE (0) #define IWL_EVT_DISABLE_SIZE (1532/32) diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index 77e8e19..09391f0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -138,8 +138,6 @@ enum iwl3945_antenna { #define DEFAULT_SHORT_RETRY_LIMIT 7U #define DEFAULT_LONG_RETRY_LIMIT 4U -#include "iwl-agn-rs.h" - #define IWL_TX_FIFO_AC0 0 #define IWL_TX_FIFO_AC1 1 #define IWL_TX_FIFO_AC2 2 @@ -301,6 +299,9 @@ extern int iwl3945_rs_next_rate(struct iwl_priv *priv, int rate); int iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif); void iwl3945_post_scan(struct iwl_priv *priv); +/* rates */ +extern const struct iwl3945_rate_info iwl3945_rates[IWL_RATE_COUNT_3945]; + /* Requires full declaration of iwl_priv before including */ #include "iwl-io.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 7e5cf1a..5abe2e9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -77,6 +77,74 @@ static const u8 ant_toggle_lookup[] = { /*ANT_ABC -> */ ANT_ABC, }; +#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 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 */ + 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) */ +}; + +static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags) +{ + int idx = 0; + + /* HT rate format */ + if (rate_n_flags & RATE_MCS_HT_MSK) { + idx = (rate_n_flags & 0xff); + + if (idx >= IWL_RATE_MIMO3_6M_PLCP) + idx = idx - IWL_RATE_MIMO3_6M_PLCP; + else 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*/ + if (idx >= IWL_RATE_9M_INDEX) + idx += 1; + if ((idx >= IWL_FIRST_OFDM_RATE) && (idx <= IWL_LAST_OFDM_RATE)) + return idx; + + /* legacy rate format, search for match in table */ + } else { + for (idx = 0; idx < ARRAY_SIZE(iwl_rates); idx++) + if (iwl_rates[idx].plcp == (rate_n_flags & 0xFF)) + return idx; + } + + return -1; +} + static void rs_rate_scale_perform(struct iwl_priv *priv, struct sk_buff *skb, struct ieee80211_sta *sta, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h index 357cdb2..75e50d3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h @@ -299,7 +299,6 @@ enum { #define TIME_WRAP_AROUND(x, y) (((y) > (x)) ? (y) - (x) : (0-(x)) + (y)) extern const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT]; -extern const struct iwl3945_rate_info iwl3945_rates[IWL_RATE_COUNT_3945]; enum iwl_table_type { LQ_NONE, @@ -453,15 +452,6 @@ static inline u8 first_antenna(u8 mask) } -static inline u8 iwl3945_get_prev_ieee_rate(u8 rate_index) -{ - u8 rate = iwl3945_rates[rate_index].prev_ieee; - - if (rate == IWL_RATE_INVALID) - rate = rate_index; - return rate; -} - /** * iwl3945_rate_scale_init - Initialize the rate scale table based on assoc info * diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index eefcb2d..2950384 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -69,79 +69,9 @@ EXPORT_SYMBOL_GPL(bt_coex_active); module_param(bt_coex_active, bool, S_IRUGO); MODULE_PARM_DESC(bt_coex_active, "enable wifi/bluetooth co-exist"); -#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 } - u32 iwl_debug_level; EXPORT_SYMBOL(iwl_debug_level); -/* - * 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 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 */ - 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(iwl_rates); - -int iwl_hwrate_to_plcp_idx(u32 rate_n_flags) -{ - int idx = 0; - - /* HT rate format */ - if (rate_n_flags & RATE_MCS_HT_MSK) { - idx = (rate_n_flags & 0xff); - - if (idx >= IWL_RATE_MIMO3_6M_PLCP) - idx = idx - IWL_RATE_MIMO3_6M_PLCP; - else 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*/ - if (idx >= IWL_RATE_9M_INDEX) - idx += 1; - if ((idx >= IWL_FIRST_OFDM_RATE) && (idx <= IWL_LAST_OFDM_RATE)) - return idx; - - /* legacy rate format, search for match in table */ - } else { - for (idx = 0; idx < ARRAY_SIZE(iwl_rates); idx++) - if (iwl_rates[idx].plcp == (rate_n_flags & 0xFF)) - return idx; - } - - return -1; -} -EXPORT_SYMBOL(iwl_hwrate_to_plcp_idx); - u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant, u8 valid) { int i; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 31ec9db..56251de 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -547,8 +547,6 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force); * Rate ******************************************************************************/ -int iwl_hwrate_to_plcp_idx(u32 rate_n_flags); - u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv, struct iwl_rxon_context *ctx); -- cgit v0.10.2 From facd982e8246ed25a049d270a71513fb11b901ec Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Sep 2010 18:02:05 +0200 Subject: iwlwifi: move iwl_toggle_rx_ant to agn The iwl_toggle_tx_ant function is only used by agn code, so it can be moved into the agn module instead of being exported from the core. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 3eeab0a..9f1c93b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -2205,3 +2205,20 @@ void iwlagn_set_rxon_chain(struct iwl_priv *priv, struct iwl_rxon_context *ctx) WARN_ON(active_rx_cnt == 0 || idle_rx_cnt == 0 || active_rx_cnt < idle_rx_cnt); } + +u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant, u8 valid) +{ + int i; + u8 ind = ant; + + if (priv->band == IEEE80211_BAND_2GHZ && + priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH) + return 0; + + for (i = 0; i < RATE_ANT_NUM - 1; i++) { + ind = (ind + 1) < RATE_ANT_NUM ? ind + 1 : 0; + if (valid & BIT(ind)) + return ind; + } + return ant; +} diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index d6645ec..cc7a3b5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -216,6 +216,8 @@ static inline bool iwl_is_tx_success(u32 status) (status == TX_STATUS_DIRECT_DONE); } +u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant_idx, u8 valid); + /* rx */ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 2950384..88c1ed5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -72,24 +72,6 @@ MODULE_PARM_DESC(bt_coex_active, "enable wifi/bluetooth co-exist"); u32 iwl_debug_level; EXPORT_SYMBOL(iwl_debug_level); -u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant, u8 valid) -{ - int i; - u8 ind = ant; - - if (priv->band == IEEE80211_BAND_2GHZ && - priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH) - return 0; - - for (i = 0; i < RATE_ANT_NUM - 1; i++) { - ind = (ind + 1) < RATE_ANT_NUM ? ind + 1 : 0; - if (valid & BIT(ind)) - return ind; - } - return ant; -} -EXPORT_SYMBOL(iwl_toggle_tx_ant); - const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; EXPORT_SYMBOL(iwl_bcast_addr); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 56251de..0bc7b7a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -550,8 +550,6 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force); u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv, struct iwl_rxon_context *ctx); -u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant_idx, u8 valid); - static inline u32 iwl_ant_idx_to_flags(u8 ant_idx) { return BIT(ant_idx) << RATE_MCS_ANT_POS; -- cgit v0.10.2 From fed732920bf9d96a95804a499ca586ff745540cd Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Sep 2010 18:02:06 +0200 Subject: iwlwifi: move iwl_dump_csr to agn The iwl_dump_csr function is only used within the agn module, so it can be moved there instead of being exported by the core. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 9f1c93b..de91ff6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -2222,3 +2222,72 @@ u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant, u8 valid) } return ant; } + +static const char *get_csr_string(int cmd) +{ + switch (cmd) { + IWL_CMD(CSR_HW_IF_CONFIG_REG); + IWL_CMD(CSR_INT_COALESCING); + IWL_CMD(CSR_INT); + IWL_CMD(CSR_INT_MASK); + IWL_CMD(CSR_FH_INT_STATUS); + IWL_CMD(CSR_GPIO_IN); + IWL_CMD(CSR_RESET); + IWL_CMD(CSR_GP_CNTRL); + IWL_CMD(CSR_HW_REV); + IWL_CMD(CSR_EEPROM_REG); + IWL_CMD(CSR_EEPROM_GP); + IWL_CMD(CSR_OTP_GP_REG); + IWL_CMD(CSR_GIO_REG); + IWL_CMD(CSR_GP_UCODE_REG); + IWL_CMD(CSR_GP_DRIVER_REG); + IWL_CMD(CSR_UCODE_DRV_GP1); + IWL_CMD(CSR_UCODE_DRV_GP2); + IWL_CMD(CSR_LED_REG); + IWL_CMD(CSR_DRAM_INT_TBL_REG); + IWL_CMD(CSR_GIO_CHICKEN_BITS); + IWL_CMD(CSR_ANA_PLL_CFG); + IWL_CMD(CSR_HW_REV_WA_REG); + IWL_CMD(CSR_DBG_HPET_MEM_REG); + default: + return "UNKNOWN"; + } +} + +void iwl_dump_csr(struct iwl_priv *priv) +{ + int i; + u32 csr_tbl[] = { + CSR_HW_IF_CONFIG_REG, + CSR_INT_COALESCING, + CSR_INT, + CSR_INT_MASK, + CSR_FH_INT_STATUS, + CSR_GPIO_IN, + CSR_RESET, + CSR_GP_CNTRL, + CSR_HW_REV, + CSR_EEPROM_REG, + CSR_EEPROM_GP, + CSR_OTP_GP_REG, + CSR_GIO_REG, + CSR_GP_UCODE_REG, + CSR_GP_DRIVER_REG, + CSR_UCODE_DRV_GP1, + CSR_UCODE_DRV_GP2, + CSR_LED_REG, + CSR_DRAM_INT_TBL_REG, + CSR_GIO_CHICKEN_BITS, + CSR_ANA_PLL_CFG, + CSR_HW_REV_WA_REG, + CSR_DBG_HPET_MEM_REG + }; + IWL_ERR(priv, "CSR values:\n"); + IWL_ERR(priv, "(2nd byte of CSR_INT_COALESCING is " + "CSR_INT_PERIODIC_REG)\n"); + for (i = 0; i < ARRAY_SIZE(csr_tbl); i++) { + IWL_ERR(priv, " %25s: 0X%08x\n", + get_csr_string(csr_tbl[i]), + iwl_read32(priv, csr_tbl[i])); + } +} diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index cc7a3b5..5458e63 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -162,6 +162,7 @@ int iwlagn_hw_nic_init(struct iwl_priv *priv); int iwlagn_wait_tx_queue_empty(struct iwl_priv *priv); int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control); void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control); +void iwl_dump_csr(struct iwl_priv *priv); /* rx */ void iwlagn_rx_queue_restock(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 88c1ed5..c0d531c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2351,77 +2351,6 @@ void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len) EXPORT_SYMBOL(iwl_update_stats); #endif -static const char *get_csr_string(int cmd) -{ - switch (cmd) { - IWL_CMD(CSR_HW_IF_CONFIG_REG); - IWL_CMD(CSR_INT_COALESCING); - IWL_CMD(CSR_INT); - IWL_CMD(CSR_INT_MASK); - IWL_CMD(CSR_FH_INT_STATUS); - IWL_CMD(CSR_GPIO_IN); - IWL_CMD(CSR_RESET); - IWL_CMD(CSR_GP_CNTRL); - IWL_CMD(CSR_HW_REV); - IWL_CMD(CSR_EEPROM_REG); - IWL_CMD(CSR_EEPROM_GP); - IWL_CMD(CSR_OTP_GP_REG); - IWL_CMD(CSR_GIO_REG); - IWL_CMD(CSR_GP_UCODE_REG); - IWL_CMD(CSR_GP_DRIVER_REG); - IWL_CMD(CSR_UCODE_DRV_GP1); - IWL_CMD(CSR_UCODE_DRV_GP2); - IWL_CMD(CSR_LED_REG); - IWL_CMD(CSR_DRAM_INT_TBL_REG); - IWL_CMD(CSR_GIO_CHICKEN_BITS); - IWL_CMD(CSR_ANA_PLL_CFG); - IWL_CMD(CSR_HW_REV_WA_REG); - IWL_CMD(CSR_DBG_HPET_MEM_REG); - default: - return "UNKNOWN"; - - } -} - -void iwl_dump_csr(struct iwl_priv *priv) -{ - int i; - u32 csr_tbl[] = { - CSR_HW_IF_CONFIG_REG, - CSR_INT_COALESCING, - CSR_INT, - CSR_INT_MASK, - CSR_FH_INT_STATUS, - CSR_GPIO_IN, - CSR_RESET, - CSR_GP_CNTRL, - CSR_HW_REV, - CSR_EEPROM_REG, - CSR_EEPROM_GP, - CSR_OTP_GP_REG, - CSR_GIO_REG, - CSR_GP_UCODE_REG, - CSR_GP_DRIVER_REG, - CSR_UCODE_DRV_GP1, - CSR_UCODE_DRV_GP2, - CSR_LED_REG, - CSR_DRAM_INT_TBL_REG, - CSR_GIO_CHICKEN_BITS, - CSR_ANA_PLL_CFG, - CSR_HW_REV_WA_REG, - CSR_DBG_HPET_MEM_REG - }; - IWL_ERR(priv, "CSR values:\n"); - IWL_ERR(priv, "(2nd byte of CSR_INT_COALESCING is " - "CSR_INT_PERIODIC_REG)\n"); - for (i = 0; i < ARRAY_SIZE(csr_tbl); i++) { - IWL_ERR(priv, " %25s: 0X%08x\n", - get_csr_string(csr_tbl[i]), - iwl_read32(priv, csr_tbl[i])); - } -} -EXPORT_SYMBOL(iwl_dump_csr); - static const char *get_fh_string(int cmd) { switch (cmd) { diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 0bc7b7a..7e99b7d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -659,7 +659,6 @@ int iwl_pci_resume(struct pci_dev *pdev); void iwl_dump_nic_error_log(struct iwl_priv *priv); int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log, char **buf, bool display); -void iwl_dump_csr(struct iwl_priv *priv); int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display); #ifdef CONFIG_IWLWIFI_DEBUG void iwl_print_rx_config_cmd(struct iwl_priv *priv, -- cgit v0.10.2 From 84fac3d9604147db37bd8c68897f79442d7ed714 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Sep 2010 18:02:07 +0200 Subject: iwlwifi: move iwl_dump_fh to agn The iwl_dump_fh function is only used by the agn module, so it can be there instead of being exported by the core. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index de91ff6..ff5f2fc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -2291,3 +2291,64 @@ void iwl_dump_csr(struct iwl_priv *priv) iwl_read32(priv, csr_tbl[i])); } } + +static const char *get_fh_string(int cmd) +{ + switch (cmd) { + IWL_CMD(FH_RSCSR_CHNL0_STTS_WPTR_REG); + IWL_CMD(FH_RSCSR_CHNL0_RBDCB_BASE_REG); + IWL_CMD(FH_RSCSR_CHNL0_WPTR); + IWL_CMD(FH_MEM_RCSR_CHNL0_CONFIG_REG); + IWL_CMD(FH_MEM_RSSR_SHARED_CTRL_REG); + IWL_CMD(FH_MEM_RSSR_RX_STATUS_REG); + IWL_CMD(FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV); + IWL_CMD(FH_TSSR_TX_STATUS_REG); + IWL_CMD(FH_TSSR_TX_ERROR_REG); + default: + return "UNKNOWN"; + } +} + +int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display) +{ + int i; +#ifdef CONFIG_IWLWIFI_DEBUG + int pos = 0; + size_t bufsz = 0; +#endif + u32 fh_tbl[] = { + FH_RSCSR_CHNL0_STTS_WPTR_REG, + FH_RSCSR_CHNL0_RBDCB_BASE_REG, + FH_RSCSR_CHNL0_WPTR, + FH_MEM_RCSR_CHNL0_CONFIG_REG, + FH_MEM_RSSR_SHARED_CTRL_REG, + FH_MEM_RSSR_RX_STATUS_REG, + FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV, + FH_TSSR_TX_STATUS_REG, + FH_TSSR_TX_ERROR_REG + }; +#ifdef CONFIG_IWLWIFI_DEBUG + if (display) { + bufsz = ARRAY_SIZE(fh_tbl) * 48 + 40; + *buf = kmalloc(bufsz, GFP_KERNEL); + if (!*buf) + return -ENOMEM; + pos += scnprintf(*buf + pos, bufsz - pos, + "FH register values:\n"); + for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) { + pos += scnprintf(*buf + pos, bufsz - pos, + " %34s: 0X%08x\n", + get_fh_string(fh_tbl[i]), + iwl_read_direct32(priv, fh_tbl[i])); + } + return pos; + } +#endif + IWL_ERR(priv, "FH register values:\n"); + for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) { + IWL_ERR(priv, " %34s: 0X%08x\n", + get_fh_string(fh_tbl[i]), + iwl_read_direct32(priv, fh_tbl[i])); + } + return 0; +} diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index 5458e63..1fca5af 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -163,6 +163,7 @@ int iwlagn_wait_tx_queue_empty(struct iwl_priv *priv); int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control); void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control); void iwl_dump_csr(struct iwl_priv *priv); +int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display); /* rx */ void iwlagn_rx_queue_restock(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index c0d531c..5cd16a7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2351,69 +2351,6 @@ void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len) EXPORT_SYMBOL(iwl_update_stats); #endif -static const char *get_fh_string(int cmd) -{ - switch (cmd) { - IWL_CMD(FH_RSCSR_CHNL0_STTS_WPTR_REG); - IWL_CMD(FH_RSCSR_CHNL0_RBDCB_BASE_REG); - IWL_CMD(FH_RSCSR_CHNL0_WPTR); - IWL_CMD(FH_MEM_RCSR_CHNL0_CONFIG_REG); - IWL_CMD(FH_MEM_RSSR_SHARED_CTRL_REG); - IWL_CMD(FH_MEM_RSSR_RX_STATUS_REG); - IWL_CMD(FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV); - IWL_CMD(FH_TSSR_TX_STATUS_REG); - IWL_CMD(FH_TSSR_TX_ERROR_REG); - default: - return "UNKNOWN"; - - } -} - -int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display) -{ - int i; -#ifdef CONFIG_IWLWIFI_DEBUG - int pos = 0; - size_t bufsz = 0; -#endif - u32 fh_tbl[] = { - FH_RSCSR_CHNL0_STTS_WPTR_REG, - FH_RSCSR_CHNL0_RBDCB_BASE_REG, - FH_RSCSR_CHNL0_WPTR, - FH_MEM_RCSR_CHNL0_CONFIG_REG, - FH_MEM_RSSR_SHARED_CTRL_REG, - FH_MEM_RSSR_RX_STATUS_REG, - FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV, - FH_TSSR_TX_STATUS_REG, - FH_TSSR_TX_ERROR_REG - }; -#ifdef CONFIG_IWLWIFI_DEBUG - if (display) { - bufsz = ARRAY_SIZE(fh_tbl) * 48 + 40; - *buf = kmalloc(bufsz, GFP_KERNEL); - if (!*buf) - return -ENOMEM; - pos += scnprintf(*buf + pos, bufsz - pos, - "FH register values:\n"); - for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) { - pos += scnprintf(*buf + pos, bufsz - pos, - " %34s: 0X%08x\n", - get_fh_string(fh_tbl[i]), - iwl_read_direct32(priv, fh_tbl[i])); - } - return pos; - } -#endif - IWL_ERR(priv, "FH register values:\n"); - for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) { - IWL_ERR(priv, " %34s: 0X%08x\n", - get_fh_string(fh_tbl[i]), - iwl_read_direct32(priv, fh_tbl[i])); - } - return 0; -} -EXPORT_SYMBOL(iwl_dump_fh); - static void iwl_force_rf_reset(struct iwl_priv *priv) { if (test_bit(STATUS_EXIT_PENDING, &priv->status)) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 7e99b7d..b02db31 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -659,7 +659,6 @@ int iwl_pci_resume(struct pci_dev *pdev); void iwl_dump_nic_error_log(struct iwl_priv *priv); int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log, char **buf, bool display); -int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display); #ifdef CONFIG_IWLWIFI_DEBUG void iwl_print_rx_config_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx); -- cgit v0.10.2 From 0453674c90be7b39c8925ba5e1d746447905f8ee Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Sep 2010 18:02:08 +0200 Subject: iwlwifi: remove set_ct_kill operation This operation is only ever called from set_hw_params, which is also already based on the config/ops, so that there's no need to have a separate set_ct_kill op and we can just call the right ct_threshold function. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 8c2db55..8aed9ea 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -151,8 +151,7 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant; priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant; - if (priv->cfg->ops->lib->temp_ops.set_ct_kill) - priv->cfg->ops->lib->temp_ops.set_ct_kill(priv); + iwl1000_set_ct_threshold(priv); /* Set initial sensitivity parameters */ /* Set initial calibration set */ @@ -219,7 +218,6 @@ static struct iwl_lib_ops iwl1000_lib = { .config_ap = iwl_config_ap, .temp_ops = { .temperature = iwlagn_temperature, - .set_ct_kill = iwl1000_set_ct_threshold, }, .manage_ibss_station = iwlagn_manage_ibss_station, .update_bcast_stations = iwl_update_bcast_stations, diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 08d2dbc..c192856 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -669,8 +669,8 @@ static int iwl4965_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant); priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant; priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant; - if (priv->cfg->ops->lib->temp_ops.set_ct_kill) - priv->cfg->ops->lib->temp_ops.set_ct_kill(priv); + + iwl4965_set_ct_threshold(priv); priv->hw_params.sens = &iwl4965_sensitivity; priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS; @@ -2292,7 +2292,6 @@ static struct iwl_lib_ops iwl4965_lib = { .isr = iwl_isr_legacy, .temp_ops = { .temperature = iwl4965_temperature_calib, - .set_ct_kill = iwl4965_set_ct_threshold, }, .manage_ibss_station = iwlagn_manage_ibss_station, .update_bcast_stations = iwl_update_bcast_stations, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index ddbbb93..084271e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -195,8 +195,7 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant; priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant; - if (priv->cfg->ops->lib->temp_ops.set_ct_kill) - priv->cfg->ops->lib->temp_ops.set_ct_kill(priv); + iwl5000_set_ct_threshold(priv); /* Set initial sensitivity parameters */ /* Set initial calibration set */ @@ -242,8 +241,7 @@ static int iwl5150_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant; priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant; - if (priv->cfg->ops->lib->temp_ops.set_ct_kill) - priv->cfg->ops->lib->temp_ops.set_ct_kill(priv); + iwl5150_set_ct_threshold(priv); /* Set initial sensitivity parameters */ /* Set initial calibration set */ @@ -394,7 +392,6 @@ static struct iwl_lib_ops iwl5000_lib = { .config_ap = iwl_config_ap, .temp_ops = { .temperature = iwlagn_temperature, - .set_ct_kill = iwl5000_set_ct_threshold, }, .manage_ibss_station = iwlagn_manage_ibss_station, .update_bcast_stations = iwl_update_bcast_stations, @@ -465,7 +462,6 @@ static struct iwl_lib_ops iwl5150_lib = { .config_ap = iwl_config_ap, .temp_ops = { .temperature = iwl5150_temperature, - .set_ct_kill = iwl5150_set_ct_threshold, }, .manage_ibss_station = iwlagn_manage_ibss_station, .update_bcast_stations = iwl_update_bcast_stations, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 198cd8f..84f1814 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -192,8 +192,7 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant; priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant; - if (priv->cfg->ops->lib->temp_ops.set_ct_kill) - priv->cfg->ops->lib->temp_ops.set_ct_kill(priv); + iwl6000_set_ct_threshold(priv); /* Set initial sensitivity parameters */ /* Set initial calibration set */ @@ -334,7 +333,6 @@ static struct iwl_lib_ops iwl6000_lib = { .config_ap = iwl_config_ap, .temp_ops = { .temperature = iwlagn_temperature, - .set_ct_kill = iwl6000_set_ct_threshold, }, .manage_ibss_station = iwlagn_manage_ibss_station, .update_bcast_stations = iwl_update_bcast_stations, @@ -408,7 +406,6 @@ static struct iwl_lib_ops iwl6000g2b_lib = { .config_ap = iwl_config_ap, .temp_ops = { .temperature = iwlagn_temperature, - .set_ct_kill = iwl6000_set_ct_threshold, }, .manage_ibss_station = iwlagn_manage_ibss_station, .update_bcast_stations = iwl_update_bcast_stations, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index b02db31..f3c3d85 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -137,7 +137,6 @@ struct iwl_debugfs_ops { struct iwl_temp_ops { void (*temperature)(struct iwl_priv *priv); - void (*set_ct_kill)(struct iwl_priv *priv); }; struct iwl_tt_ops { -- cgit v0.10.2 From 9597ebac91e5a88f558d236a51d776508d42a237 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Sep 2010 18:02:09 +0200 Subject: iwlwifi: remove set_pwr_src operation The set_pwr_src operation is only ever used from within the same sub-driver that it is declared in, so it can just be called directly instead of being an operation. Also, it is never called to set the power source to V_aux, so change the two functions accordingly (but keep the V_aux code for documentation purposes in a comment). Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 8aed9ea..5bdfe9d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -196,7 +196,6 @@ static struct iwl_lib_ops iwl1000_lib = { .init = iwl_apm_init, .stop = iwl_apm_stop, .config = iwl1000_nic_config, - .set_pwr_src = iwl_set_pwr_src, }, .eeprom_ops = { .regulatory_bands = { diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index ba3ab04..824c942 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -816,9 +816,12 @@ static u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate) return sta_id; } -static int iwl3945_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src) +static void iwl3945_set_pwr_vmain(struct iwl_priv *priv) { - if (src == IWL_PWR_SRC_VAUX) { +/* + * (for documentation purposes) + * to set power to V_AUX, do + if (pci_pme_capable(priv->pci_dev, PCI_D3cold)) { iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_PWR_SRC_VAUX, @@ -828,16 +831,14 @@ static int iwl3945_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src) CSR_GPIO_IN_VAL_VAUX_PWR_SRC, CSR_GPIO_IN_BIT_AUX_POWER, 5000); } - } else { - iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, - APMG_PS_CTRL_VAL_PWR_SRC_VMAIN, - ~APMG_PS_CTRL_MSK_PWR_SRC); + */ - iwl_poll_bit(priv, CSR_GPIO_IN, CSR_GPIO_IN_VAL_VMAIN_PWR_SRC, - CSR_GPIO_IN_BIT_AUX_POWER, 5000); /* uS */ - } + iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_PWR_SRC_VMAIN, + ~APMG_PS_CTRL_MSK_PWR_SRC); - return 0; + iwl_poll_bit(priv, CSR_GPIO_IN, CSR_GPIO_IN_VAL_VMAIN_PWR_SRC, + CSR_GPIO_IN_BIT_AUX_POWER, 5000); /* uS */ } static int iwl3945_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) @@ -1031,9 +1032,7 @@ int iwl3945_hw_nic_init(struct iwl_priv *priv) priv->cfg->ops->lib->apm_ops.init(priv); spin_unlock_irqrestore(&priv->lock, flags); - rc = priv->cfg->ops->lib->apm_ops.set_pwr_src(priv, IWL_PWR_SRC_VMAIN); - if (rc) - return rc; + iwl3945_set_pwr_vmain(priv); priv->cfg->ops->lib->apm_ops.config(priv); @@ -2707,7 +2706,6 @@ static struct iwl_lib_ops iwl3945_lib = { .init = iwl3945_apm_init, .stop = iwl_apm_stop, .config = iwl3945_nic_config, - .set_pwr_src = iwl3945_set_pwr_src, }, .eeprom_ops = { .regulatory_bands = { diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index c192856..cda4a31 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2268,7 +2268,6 @@ static struct iwl_lib_ops iwl4965_lib = { .init = iwl_apm_init, .stop = iwl_apm_stop, .config = iwl4965_nic_config, - .set_pwr_src = iwl_set_pwr_src, }, .eeprom_ops = { .regulatory_bands = { diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 084271e..c90a16c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -370,7 +370,6 @@ static struct iwl_lib_ops iwl5000_lib = { .init = iwl_apm_init, .stop = iwl_apm_stop, .config = iwl5000_nic_config, - .set_pwr_src = iwl_set_pwr_src, }, .eeprom_ops = { .regulatory_bands = { @@ -440,7 +439,6 @@ static struct iwl_lib_ops iwl5150_lib = { .init = iwl_apm_init, .stop = iwl_apm_stop, .config = iwl5000_nic_config, - .set_pwr_src = iwl_set_pwr_src, }, .eeprom_ops = { .regulatory_bands = { diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 84f1814..02103a7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -310,7 +310,6 @@ static struct iwl_lib_ops iwl6000_lib = { .init = iwl_apm_init, .stop = iwl_apm_stop, .config = iwl6000_nic_config, - .set_pwr_src = iwl_set_pwr_src, }, .eeprom_ops = { .regulatory_bands = { @@ -383,7 +382,6 @@ static struct iwl_lib_ops iwl6000g2b_lib = { .init = iwl_apm_init, .stop = iwl_apm_stop, .config = iwl6000_nic_config, - .set_pwr_src = iwl_set_pwr_src, }, .eeprom_ops = { .regulatory_bands = { diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index ff5f2fc..0ad0d44 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -685,6 +685,23 @@ int iwlagn_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) return 0; } +static void iwlagn_set_pwr_vmain(struct iwl_priv *priv) +{ +/* + * (for documentation purposes) + * to set power to V_AUX, do: + + if (pci_pme_capable(priv->pci_dev, PCI_D3cold)) + iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_PWR_SRC_VAUX, + ~APMG_PS_CTRL_MSK_PWR_SRC); + */ + + iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_PWR_SRC_VMAIN, + ~APMG_PS_CTRL_MSK_PWR_SRC); +} + int iwlagn_hw_nic_init(struct iwl_priv *priv) { unsigned long flags; @@ -700,7 +717,7 @@ int iwlagn_hw_nic_init(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); - ret = priv->cfg->ops->lib->apm_ops.set_pwr_src(priv, IWL_PWR_SRC_VMAIN); + iwlagn_set_pwr_vmain(priv); priv->cfg->ops->lib->apm_ops.config(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 8233c64..75472a3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -935,22 +935,6 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv, wake_up_interruptible(&priv->wait_command_queue); } -int iwl_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src) -{ - if (src == IWL_PWR_SRC_VAUX) { - if (pci_pme_capable(priv->pci_dev, PCI_D3cold)) - iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, - 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); - } - - return 0; -} - static void iwl_bg_tx_flush(struct work_struct *work) { struct iwl_priv *priv = diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index f3c3d85..ae77279 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -119,7 +119,6 @@ struct iwl_apm_ops { int (*init)(struct iwl_priv *priv); void (*stop)(struct iwl_priv *priv); void (*config)(struct iwl_priv *priv); - int (*set_pwr_src)(struct iwl_priv *priv, enum iwl_pwr_src src); }; struct iwl_debugfs_ops { diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 2b04714..2c57dbd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -282,13 +282,6 @@ struct iwl_channel_info { */ #define IWL_IPAN_MCAST_QUEUE 8 -/* 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) @@ -732,7 +725,6 @@ struct iwl_hw_params { * ****************************************************************************/ extern void iwl_update_chain_flags(struct iwl_priv *priv); -extern int iwl_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src); extern const u8 iwl_bcast_addr[ETH_ALEN]; extern int iwl_rxq_stop(struct iwl_priv *priv); extern void iwl_txq_ctx_stop(struct iwl_priv *priv); -- cgit v0.10.2 From 14e8e4afeb7e90f1f2d3f2d3b54da57c27f59f38 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Sep 2010 18:02:10 +0200 Subject: iwlwifi: remove apm_ops.stop Since all devices share the same operation here, there's no need to call it indirectly. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 5bdfe9d..db54091 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -194,7 +194,6 @@ static struct iwl_lib_ops iwl1000_lib = { .update_chain_flags = iwl_update_chain_flags, .apm_ops = { .init = iwl_apm_init, - .stop = iwl_apm_stop, .config = iwl1000_nic_config, }, .eeprom_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 824c942..b06a7bd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -2704,7 +2704,6 @@ static struct iwl_lib_ops iwl3945_lib = { .dump_nic_error_log = iwl3945_dump_nic_error_log, .apm_ops = { .init = iwl3945_apm_init, - .stop = iwl_apm_stop, .config = iwl3945_nic_config, }, .eeprom_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index cda4a31..28ba563 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2266,7 +2266,6 @@ static struct iwl_lib_ops iwl4965_lib = { .set_channel_switch = iwl4965_hw_channel_switch, .apm_ops = { .init = iwl_apm_init, - .stop = iwl_apm_stop, .config = iwl4965_nic_config, }, .eeprom_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index c90a16c..fd9fbc9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -368,7 +368,6 @@ static struct iwl_lib_ops iwl5000_lib = { .set_channel_switch = iwl5000_hw_channel_switch, .apm_ops = { .init = iwl_apm_init, - .stop = iwl_apm_stop, .config = iwl5000_nic_config, }, .eeprom_ops = { @@ -437,7 +436,6 @@ static struct iwl_lib_ops iwl5150_lib = { .set_channel_switch = iwl5000_hw_channel_switch, .apm_ops = { .init = iwl_apm_init, - .stop = iwl_apm_stop, .config = iwl5000_nic_config, }, .eeprom_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 02103a7..a45929e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -308,7 +308,6 @@ static struct iwl_lib_ops iwl6000_lib = { .set_channel_switch = iwl6000_hw_channel_switch, .apm_ops = { .init = iwl_apm_init, - .stop = iwl_apm_stop, .config = iwl6000_nic_config, }, .eeprom_ops = { @@ -380,7 +379,6 @@ static struct iwl_lib_ops iwl6000g2b_lib = { .set_channel_switch = iwl6000_hw_channel_switch, .apm_ops = { .init = iwl_apm_init, - .stop = iwl_apm_stop, .config = iwl6000_nic_config, }, .eeprom_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 75472a3..b1af79e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2983,7 +2983,7 @@ static void __iwl_down(struct iwl_priv *priv) iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); /* Stop the device, and put it in low power state */ - priv->cfg->ops->lib->apm_ops.stop(priv); + iwl_apm_stop(priv); exit: memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp)); @@ -4597,7 +4597,7 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) * paths to avoid running iwl_down() at all before leaving driver. * This (inexpensive) call *makes sure* device is reset. */ - priv->cfg->ops->lib->apm_ops.stop(priv); + iwl_apm_stop(priv); iwl_tt_exit(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 5cd16a7..b3efbe0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2599,7 +2599,7 @@ int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) * it will not call apm_ops.stop() to stop the DMA operation. * Calling apm_ops.stop here to make sure we stop the DMA. */ - priv->cfg->ops->lib->apm_ops.stop(priv); + iwl_apm_stop(priv); pci_save_state(pdev); pci_disable_device(pdev); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index ae77279..c01262c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -117,7 +117,6 @@ struct iwl_hcmd_utils_ops { struct iwl_apm_ops { int (*init)(struct iwl_priv *priv); - void (*stop)(struct iwl_priv *priv); void (*config)(struct iwl_priv *priv); }; diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index bd51b06..66eccb1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -603,7 +603,7 @@ err: if (ret) iwl_eeprom_free(priv); /* Reset chip to save power until we load uCode during "up". */ - priv->cfg->ops->lib->apm_ops.stop(priv); + iwl_apm_stop(priv); alloc_err: return ret; } diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index c06b218..980c609 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2637,7 +2637,7 @@ static void __iwl3945_down(struct iwl_priv *priv) udelay(5); /* Stop the device, and put it in low power state */ - priv->cfg->ops->lib->apm_ops.stop(priv); + iwl_apm_stop(priv); exit: memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp)); @@ -4212,7 +4212,7 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) * paths to avoid running iwl_down() at all before leaving driver. * This (inexpensive) call *makes sure* device is reset. */ - priv->cfg->ops->lib->apm_ops.stop(priv); + iwl_apm_stop(priv); /* make sure we flush any pending irq or * tasklet for the driver -- cgit v0.10.2 From 0de76736552cff02cc6ee4bae41e5502d7673f8e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Sep 2010 18:02:11 +0200 Subject: iwlwifi: clean up declarations A number of declarations in iwl-core.h should be in agn specific files, and also rename the iwl-calib.h file to iwl-agn-calib.h to better reflect that it belongs to agn. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 28ba563..b207e3e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -43,7 +43,7 @@ #include "iwl-core.h" #include "iwl-io.h" #include "iwl-helpers.h" -#include "iwl-calib.h" +#include "iwl-agn-calib.h" #include "iwl-sta.h" #include "iwl-agn-led.h" #include "iwl-agn.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c index 4c5ab78..e2019e7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c @@ -65,7 +65,7 @@ #include "iwl-dev.h" #include "iwl-core.h" -#include "iwl-calib.h" +#include "iwl-agn-calib.h" /***************************************************************************** * INIT calibrations framework diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.h b/drivers/net/wireless/iwlwifi/iwl-agn-calib.h new file mode 100644 index 0000000..e37ae726 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.h @@ -0,0 +1,86 @@ +/****************************************************************************** + * + * 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 - 2010 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: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2010 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 "iwl-dev.h" +#include "iwl-core.h" +#include "iwl-commands.h" + +void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp); +void iwl_sensitivity_calibration(struct iwl_priv *priv, void *resp); + +void iwl_init_sensitivity(struct iwl_priv *priv); +void iwl_reset_run_time_calib(struct iwl_priv *priv); +static inline void iwl_chain_noise_reset(struct iwl_priv *priv) +{ + + if (!priv->disable_chain_noise_cal && + priv->cfg->ops->utils->chain_noise_reset) + priv->cfg->ops->utils->chain_noise_reset(priv); +} + +int iwl_send_calib_results(struct iwl_priv *priv); +int iwl_calib_set(struct iwl_calib_result *res, const u8 *buf, int len); +void iwl_calib_free_results(struct iwl_priv *priv); + +#endif /* __iwl_calib_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c index 1e08eb4..bbd40b7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c @@ -34,7 +34,7 @@ #include "iwl-dev.h" #include "iwl-core.h" -#include "iwl-calib.h" +#include "iwl-agn-calib.h" #include "iwl-sta.h" #include "iwl-io.h" #include "iwl-helpers.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c index e1dd762..3a95379 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c @@ -38,6 +38,7 @@ #include "iwl-helpers.h" #include "iwl-agn-hw.h" #include "iwl-agn.h" +#include "iwl-agn-calib.h" static const s8 iwlagn_default_queue_to_tx_fifo[] = { IWL_TX_FIFO_VO, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index b1af79e..763a93d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -57,7 +57,7 @@ #include "iwl-io.h" #include "iwl-helpers.h" #include "iwl-sta.h" -#include "iwl-calib.h" +#include "iwl-agn-calib.h" #include "iwl-agn.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index 1fca5af..b4deef4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -177,8 +177,15 @@ void iwlagn_rx_reply_rx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); void iwlagn_rx_reply_rx_phy(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); +void iwl_rx_handle(struct iwl_priv *priv); /* tx */ +void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq); +int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, + struct iwl_tx_queue *txq, + dma_addr_t addr, u16 len, u8 reset, u8 pad); +int iwl_hw_tx_queue_init(struct iwl_priv *priv, + struct iwl_tx_queue *txq); void iwlagn_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, struct ieee80211_tx_info *info); int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb); @@ -289,4 +296,20 @@ void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id); void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt); int iwl_update_bcast_stations(struct iwl_priv *priv); +/* rate */ +static inline u32 iwl_ant_idx_to_flags(u8 ant_idx) +{ + return BIT(ant_idx) << RATE_MCS_ANT_POS; +} + +static inline u8 iwl_hw_get_rate(__le32 rate_n_flags) +{ + return le32_to_cpu(rate_n_flags) & 0xFF; +} + +static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags) +{ + return cpu_to_le32(flags|(u32)rate); +} + #endif /* __iwl_agn_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.h b/drivers/net/wireless/iwlwifi/iwl-calib.h deleted file mode 100644 index ba9523f..0000000 --- a/drivers/net/wireless/iwlwifi/iwl-calib.h +++ /dev/null @@ -1,82 +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) 2008 - 2010 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: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2005 - 2010 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 "iwl-dev.h" -#include "iwl-core.h" -#include "iwl-commands.h" - -void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp); -void iwl_sensitivity_calibration(struct iwl_priv *priv, void *resp); - -void iwl_init_sensitivity(struct iwl_priv *priv); -void iwl_reset_run_time_calib(struct iwl_priv *priv); -static inline void iwl_chain_noise_reset(struct iwl_priv *priv) -{ - - if (!priv->disable_chain_noise_cal && - priv->cfg->ops->utils->chain_noise_reset) - priv->cfg->ops->utils->chain_noise_reset(priv); -} - -#endif /* __iwl_calib_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index c01262c..a5e12b7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -396,7 +396,6 @@ struct iwl_cfg { struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg, struct ieee80211_ops *hw_ops); -void iwl_activate_qos(struct iwl_priv *priv); int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params); int iwl_mac_tx_last_beacon(struct ieee80211_hw *hw); @@ -505,7 +504,6 @@ void iwl_rx_reply_error(struct iwl_priv *priv, ******************************************************/ void iwl_cmd_queue_free(struct iwl_priv *priv); int iwl_rx_queue_alloc(struct iwl_priv *priv); -void iwl_rx_handle(struct iwl_priv *priv); void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q); int iwl_rx_queue_space(const struct iwl_rx_queue *q); @@ -523,12 +521,6 @@ void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); /***************************************************** * TX ******************************************************/ -void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq); -int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, - struct iwl_tx_queue *txq, - dma_addr_t addr, u16 len, u8 reset, u8 pad); -int iwl_hw_tx_queue_init(struct iwl_priv *priv, - struct iwl_tx_queue *txq); void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq); int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq, int slots_num, u32 txq_id); @@ -547,24 +539,6 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force); u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv, struct iwl_rxon_context *ctx); -static inline u32 iwl_ant_idx_to_flags(u8 ant_idx) -{ - return BIT(ant_idx) << RATE_MCS_ANT_POS; -} - -static inline u8 iwl_hw_get_rate(__le32 rate_n_flags) -{ - return le32_to_cpu(rate_n_flags) & 0xFF; -} -static inline u32 iwl_hw_get_rate_n_flags(__le32 rate_n_flags) -{ - return le32_to_cpu(rate_n_flags) & 0x1FFFF; -} -static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags) -{ - return cpu_to_le32(flags|(u32)rate); -} - /******************************************************************************* * Scanning ******************************************************************************/ @@ -600,13 +574,6 @@ void iwl_cancel_scan_deferred_work(struct iwl_priv *priv); #define IWL_SCAN_CHECK_WATCHDOG (HZ * 7) -/******************************************************************************* - * Calibrations - implemented in iwl-calib.c - ******************************************************************************/ -int iwl_send_calib_results(struct iwl_priv *priv); -int iwl_calib_set(struct iwl_calib_result *res, const u8 *buf, int len); -void iwl_calib_free_results(struct iwl_priv *priv); - /***************************************************** * 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-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index fc34031..96d9085 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -39,7 +39,6 @@ #include "iwl-debug.h" #include "iwl-core.h" #include "iwl-io.h" -#include "iwl-calib.h" /* create and remove of files */ #define DEBUGFS_ADD_FILE(name, parent, mode) do { \ diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 10be197..f436270 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -36,7 +36,6 @@ #include "iwl-core.h" #include "iwl-sta.h" #include "iwl-io.h" -#include "iwl-calib.h" #include "iwl-helpers.h" /************************** RX-FUNCTIONS ****************************/ /* -- cgit v0.10.2 From a313f3839eeeebb3cbbcf1fbd2aee92bde389032 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Sep 2010 18:02:12 +0200 Subject: iwlwifi: remove iwl_check_bits The function is used exactly once, and the caller doesn't even need the special check, it can be simplified to a simple bit check. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index b06a7bd..7d74ae5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -348,7 +348,7 @@ static void iwl3945_rx_reply_tx(struct iwl_priv *priv, IWL_DEBUG_TX_REPLY(priv, "Tx queue reclaim %d\n", index); iwl3945_tx_queue_reclaim(priv, txq_id, index); - if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK)) + if (status & TX_ABORT_REQUIRED_MSK) IWL_ERR(priv, "TODO: Implement Tx ABORT REQUIRED!!!\n"); } diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h index 621abe3..1aaef70 100644 --- a/drivers/net/wireless/iwlwifi/iwl-helpers.h +++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h @@ -44,11 +44,6 @@ static inline struct ieee80211_conf *ieee80211_get_hw_conf( return &hw->conf; } -static inline int iwl_check_bits(unsigned long field, unsigned long mask) -{ - return ((field & mask) == mask) ? 1 : 0; -} - static inline unsigned long elapsed_jiffies(unsigned long start, unsigned long end) { -- cgit v0.10.2 From 1cf263736092b3712103a5290a93dd0fff376f26 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Sep 2010 07:32:13 -0700 Subject: iwlwifi: fix dual-mode scanning The recent scanning code shuffle accidentally moved the SCAN_HW bit setting _after_ the PAN parameters are modified, which means that they don't take the scan into account -- fix that. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 0ad0d44..c1a3898 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -1565,13 +1565,15 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) cmd.data = scan; scan->len = cpu_to_le16(cmd.len); + /* set scan bit here for PAN params */ + set_bit(STATUS_SCAN_HW, &priv->status); + if (priv->cfg->ops->hcmd->set_pan_params) { ret = priv->cfg->ops->hcmd->set_pan_params(priv); if (ret) return ret; } - set_bit(STATUS_SCAN_HW, &priv->status); ret = iwl_send_cmd_sync(priv, &cmd); if (ret) { clear_bit(STATUS_SCAN_HW, &priv->status); -- cgit v0.10.2 From 65cccfb03d0dc99fd213d57be5f60f8ca6a60824 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Tue, 21 Sep 2010 16:15:58 -0700 Subject: iwlagn: no version check for experimental uCode For experimental uCode, it should work with the driver if driver has experimental uCode support option enabled; remove the API version checking. Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 763a93d..1b682dd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2104,18 +2104,23 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) * firmware filename ... but we don't check for that and only rely * on the API version read from firmware header from here on forward */ - if (api_ver < api_min || api_ver > api_max) { - IWL_ERR(priv, "Driver unable to support your firmware API. " - "Driver supports v%u, firmware is v%u.\n", - api_max, api_ver); - goto try_again; - } + /* no api version check required for experimental uCode */ + if (priv->fw_index != UCODE_EXPERIMENTAL_INDEX) { + if (api_ver < api_min || api_ver > api_max) { + IWL_ERR(priv, + "Driver unable to support your firmware API. " + "Driver supports v%u, firmware is v%u.\n", + api_max, api_ver); + goto try_again; + } - if (api_ver != api_max) - IWL_ERR(priv, "Firmware has old API version. Expected v%u, " - "got v%u. New firmware can be obtained " - "from http://www.intellinuxwireless.org.\n", - api_max, api_ver); + if (api_ver != api_max) + IWL_ERR(priv, + "Firmware has old API version. Expected v%u, " + "got v%u. New firmware can be obtained " + "from http://www.intellinuxwireless.org.\n", + api_max, api_ver); + } if (build) sprintf(buildstr, " build %u%s", build, -- cgit v0.10.2 From 642454cc0774e0774bc1ccb4292d6dc0abd06d20 Mon Sep 17 00:00:00 2001 From: Shanyu Zhao Date: Tue, 21 Sep 2010 12:06:18 -0700 Subject: iwlagn: fix default calibration table size iwlagn driver uses the IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE as the chain noise reset calibration index and IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE+1 as the chain noise gain calibration index, if not specified by the TLV value in the new firmware format. However, this is broken if we need to add more calibrations like the temperature offset calibration because we increased IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE by 1. To fix this issue, define IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE and use it as the calibration index instead. We still keep the IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE as a sanity check for the TLV value given by ucode. Signed-off-by: Shanyu Zhao Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 1b682dd..c4fe3f9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2062,7 +2062,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) struct iwlagn_ucode_capabilities ucode_capa = { .max_probe_length = 200, .standard_phy_calibration_size = - IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE, + IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE, }; memset(&pieces, 0, sizeof(pieces)); diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index fe65256..74b78d8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -3784,7 +3784,8 @@ struct iwl_enhance_sensitivity_cmd { */ /* Phy calibration command for series */ - +/* The default calibrate table size if not specified by firmware */ +#define IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE 18 enum { IWL_PHY_CALIBRATE_DIFF_GAIN_CMD = 7, IWL_PHY_CALIBRATE_DC_CMD = 8, -- cgit v0.10.2 From bf53f939e02c0e818df93ab130fedc0e4ba95796 Mon Sep 17 00:00:00 2001 From: Shanyu Zhao Date: Tue, 21 Sep 2010 16:54:01 -0700 Subject: iwlagn: add temperature offset calib for 6000g2 6000g2 devices need to have temperature offset calibration. The runtime uCode needs to receive the calibration results just like BB and LO calibration. To do this, driver reads the offset value from NVM and send it to uCode after runtime uCode is alive. Signed-off-by: Shanyu Zhao Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index a45929e..4810258a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -204,6 +204,8 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) BIT(IWL_CALIB_BASE_BAND); if (priv->cfg->need_dc_calib) priv->hw_params.calib_rt_cfg |= BIT(IWL_CALIB_CFG_DC_IDX); + if (priv->cfg->need_temp_offset_calib) + priv->hw_params.calib_init_cfg |= BIT(IWL_CALIB_TEMP_OFFSET); priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS; @@ -536,6 +538,7 @@ struct iwl_cfg iwl6000g2a_2agn_cfg = { .base_params = &iwl6000_base_params, .ht_params = &iwl6000_ht_params, .need_dc_calib = true, + .need_temp_offset_calib = true, }; struct iwl_cfg iwl6000g2a_2abg_cfg = { @@ -552,6 +555,7 @@ struct iwl_cfg iwl6000g2a_2abg_cfg = { .mod_params = &iwlagn_mod_params, .base_params = &iwl6000_base_params, .need_dc_calib = true, + .need_temp_offset_calib = true, }; struct iwl_cfg iwl6000g2a_2bg_cfg = { @@ -568,6 +572,7 @@ struct iwl_cfg iwl6000g2a_2bg_cfg = { .mod_params = &iwlagn_mod_params, .base_params = &iwl6000_base_params, .need_dc_calib = true, + .need_temp_offset_calib = true, }; struct iwl_cfg iwl6000g2b_2agn_cfg = { @@ -586,6 +591,7 @@ struct iwl_cfg iwl6000g2b_2agn_cfg = { .bt_params = &iwl6000_bt_params, .ht_params = &iwl6000_ht_params, .need_dc_calib = true, + .need_temp_offset_calib = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, }; @@ -605,6 +611,7 @@ struct iwl_cfg iwl6000g2b_2abg_cfg = { .base_params = &iwl6000_base_params, .bt_params = &iwl6000_bt_params, .need_dc_calib = true, + .need_temp_offset_calib = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, }; @@ -625,6 +632,7 @@ struct iwl_cfg iwl6000g2b_2bgn_cfg = { .bt_params = &iwl6000_bt_params, .ht_params = &iwl6000_ht_params, .need_dc_calib = true, + .need_temp_offset_calib = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, }; @@ -644,6 +652,7 @@ struct iwl_cfg iwl6000g2b_2bg_cfg = { .base_params = &iwl6000_base_params, .bt_params = &iwl6000_bt_params, .need_dc_calib = true, + .need_temp_offset_calib = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, }; @@ -664,6 +673,7 @@ struct iwl_cfg iwl6000g2b_bgn_cfg = { .bt_params = &iwl6000_bt_params, .ht_params = &iwl6000_ht_params, .need_dc_calib = true, + .need_temp_offset_calib = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, }; @@ -683,6 +693,7 @@ struct iwl_cfg iwl6000g2b_bg_cfg = { .base_params = &iwl6000_base_params, .bt_params = &iwl6000_bt_params, .need_dc_calib = true, + .need_temp_offset_calib = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c index 3a95379..7036211 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c @@ -215,6 +215,25 @@ static int iwlagn_set_Xtal_calib(struct iwl_priv *priv) (u8 *)&cmd, sizeof(cmd)); } +static int iwlagn_set_temperature_offset_calib(struct iwl_priv *priv) +{ + struct iwl_calib_temperature_offset_cmd cmd; + __le16 *offset_calib = + (__le16 *)iwl_eeprom_query_addr(priv, EEPROM_5000_TEMPERATURE); + cmd.hdr.op_code = IWL_PHY_CALIBRATE_TEMP_OFFSET_CMD; + cmd.hdr.first_group = 0; + cmd.hdr.groups_num = 1; + cmd.hdr.data_valid = 1; + cmd.radio_sensor_offset = le16_to_cpu(offset_calib[1]); + if (!(cmd.radio_sensor_offset)) + cmd.radio_sensor_offset = DEFAULT_RADIO_SENSOR_OFFSET; + cmd.reserved = 0; + IWL_DEBUG_CALIB(priv, "Radio sensor offset: %d\n", + cmd.radio_sensor_offset); + return iwl_calib_set(&priv->calib_results[IWL_CALIB_TEMP_OFFSET], + (u8 *)&cmd, sizeof(cmd)); +} + static int iwlagn_send_calib_cfg(struct iwl_priv *priv) { struct iwl_calib_cfg_cmd calib_cfg_cmd; @@ -321,6 +340,14 @@ void iwlagn_init_alive_start(struct iwl_priv *priv) } iwlagn_send_calib_cfg(priv); + + /** + * temperature offset calibration is only needed for runtime ucode, + * so prepare the value now. + */ + if (priv->cfg->need_temp_offset_calib) + iwlagn_set_temperature_offset_calib(priv); + return; restart: diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 74b78d8..424801a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -3794,7 +3794,8 @@ enum { IWL_PHY_CALIBRATE_CRYSTAL_FRQ_CMD = 15, IWL_PHY_CALIBRATE_BASE_BAND_CMD = 16, IWL_PHY_CALIBRATE_TX_IQ_PERD_CMD = 17, - IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE = 18, + IWL_PHY_CALIBRATE_TEMP_OFFSET_CMD = 18, + IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE = 19, }; #define IWL_MAX_PHY_CALIBRATE_TBL_SIZE (253) @@ -3864,6 +3865,13 @@ struct iwl_calib_xtal_freq_cmd { u8 pad[2]; } __packed; +#define DEFAULT_RADIO_SENSOR_OFFSET 2700 +struct iwl_calib_temperature_offset_cmd { + struct iwl_calib_hdr hdr; + s16 radio_sensor_offset; + s16 reserved; +} __packed; + /* IWL_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD */ struct iwl_calib_chain_noise_reset_cmd { struct iwl_calib_hdr hdr; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index a5e12b7..64527de 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -342,6 +342,7 @@ struct iwl_ht_params { * @ucode_api_min: Lowest version of uCode API supported by driver. * @pa_type: used by 6000 series only to identify the type of Power Amplifier * @need_dc_calib: need to perform init dc calibration + * @need_temp_offset_calib: need to perform temperature offset calibration * @scan_antennas: available antenna for scan operation * * We enable the driver to be backward compatible wrt API version. The @@ -386,6 +387,7 @@ struct iwl_cfg { struct iwl_bt_params *bt_params; enum iwl_pa_type pa_type; /* if used set to IWL_PA_SYSTEM */ const bool need_dc_calib; /* if used set to true */ + const bool need_temp_offset_calib; /* if used set to true */ u8 scan_rx_antennas[IEEE80211_NUM_BANDS]; u8 scan_tx_antennas[IEEE80211_NUM_BANDS]; }; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 2c57dbd..de43e13 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -835,6 +835,7 @@ enum iwl_calib { IWL_CALIB_TX_IQ, IWL_CALIB_TX_IQ_PERD, IWL_CALIB_BASE_BAND, + IWL_CALIB_TEMP_OFFSET, IWL_CALIB_MAX }; -- cgit v0.10.2 From 00cbb3c5317d418c349c60876fe12fba7624f3e7 Mon Sep 17 00:00:00 2001 From: Ohad Ben-Cohen Date: Fri, 8 Oct 2010 16:16:16 +0300 Subject: wl1271: sdio: enable runtime PM Enable runtime PM for the wl1271 SDIO device. We request power whenever the WLAN interface is brought up, and release it after the WLAN interface is taken down. As a result, power is released immediately after probe returns, since at that point power has not been explicitly requested yet (i.e. the WLAN interface is still down). Signed-off-by: Ohad Ben-Cohen Acked-by: Luciano Coelho Tested-by: Luciano Coelho Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/wl1271_sdio.c b/drivers/net/wireless/wl12xx/wl1271_sdio.c index 4c250d7..f7bef32 100644 --- a/drivers/net/wireless/wl12xx/wl1271_sdio.c +++ b/drivers/net/wireless/wl12xx/wl1271_sdio.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "wl1271.h" #include "wl12xx_80211.h" @@ -160,12 +161,19 @@ static void wl1271_sdio_raw_write(struct wl1271 *wl, int addr, void *buf, static int wl1271_sdio_power_on(struct wl1271 *wl) { struct sdio_func *func = wl_to_func(wl); + int ret; + + /* Power up the card */ + ret = pm_runtime_get_sync(&func->dev); + if (ret < 0) + goto out; sdio_claim_host(func); sdio_enable_func(func); sdio_release_host(func); - return 0; +out: + return ret; } static int wl1271_sdio_power_off(struct wl1271 *wl) @@ -176,15 +184,12 @@ static int wl1271_sdio_power_off(struct wl1271 *wl) sdio_disable_func(func); sdio_release_host(func); - return 0; + /* Power down the card */ + return pm_runtime_put_sync(&func->dev); } static int wl1271_sdio_set_power(struct wl1271 *wl, bool enable) { - /* Let the SDIO stack handle wlan_enable control, so we - * keep host claimed while wlan is in use to keep wl1271 - * alive. - */ if (enable) return wl1271_sdio_power_on(wl); else @@ -256,6 +261,9 @@ static int __devinit wl1271_probe(struct sdio_func *func, sdio_set_drvdata(func, wl); + /* Tell PM core that we don't need the card to be powered now */ + pm_runtime_put_noidle(&func->dev); + wl1271_notice("initialized"); return 0; @@ -274,6 +282,9 @@ static void __devexit wl1271_remove(struct sdio_func *func) { struct wl1271 *wl = sdio_get_drvdata(func); + /* Undo decrement done above in wl1271_probe */ + pm_runtime_get_noresume(&func->dev); + wl1271_unregister_hw(wl); free_irq(wl->irq, wl); wl1271_free_hw(wl); -- cgit v0.10.2 From 674f3058c806ae2591b98f59194fa85b650aa667 Mon Sep 17 00:00:00 2001 From: Ohad Ben-Cohen Date: Fri, 8 Oct 2010 16:16:27 +0300 Subject: wl1271: sdio: add suspend/resume support Add required suspend/resume support to prevent the SDIO core from removing our card completely during system suspend. Signed-off-by: Ohad Ben-Cohen Tested-by: Luciano Coelho Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/wl1271_sdio.c b/drivers/net/wireless/wl12xx/wl1271_sdio.c index f7bef32..784ef34 100644 --- a/drivers/net/wireless/wl12xx/wl1271_sdio.c +++ b/drivers/net/wireless/wl12xx/wl1271_sdio.c @@ -290,11 +290,31 @@ static void __devexit wl1271_remove(struct sdio_func *func) wl1271_free_hw(wl); } +static int wl1271_suspend(struct device *dev) +{ + /* Tell MMC/SDIO core it's OK to power down the card + * (if it isn't already), but not to remove it completely */ + return 0; +} + +static int wl1271_resume(struct device *dev) +{ + return 0; +} + +static const struct dev_pm_ops wl1271_sdio_pm_ops = { + .suspend = wl1271_suspend, + .resume = wl1271_resume, +}; + static struct sdio_driver wl1271_sdio_driver = { .name = "wl1271_sdio", .id_table = wl1271_devices, .probe = wl1271_probe, .remove = __devexit_p(wl1271_remove), + .drv = { + .pm = &wl1271_sdio_pm_ops, + }, }; static int __init wl1271_init(void) -- cgit v0.10.2 From 7623225f905263424c7254dc6a07bff083a498dd Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 11 Oct 2010 14:46:52 -0400 Subject: Revert "wireless: Use first phyX name available when registering phy devices." This reverts commit 5a254ffe3ffdfa84fe076009bd8e88da412180d2. The commit failed to take into account that allocated wireless devices (wiphys) are not added into the device list upon allocation, but only when they are registered. Therefore, it opened up a race between allocating and registering a name, so that if two processes allocate and register concurrently ("alloc, alloc, register, register" rather than "alloc, register, alloc, register") the code will attempt to use the same name twice. Signed-off-by: Johannes Berg diff --git a/net/wireless/core.c b/net/wireless/core.c index 1684ad9..9c21ebf 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -178,10 +178,26 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, char *newname) { struct cfg80211_registered_device *rdev2; - int result; + int wiphy_idx, taken = -1, result, digits; assert_cfg80211_lock(); + /* prohibit calling the thing phy%d when %d is not its number */ + sscanf(newname, PHY_NAME "%d%n", &wiphy_idx, &taken); + if (taken == strlen(newname) && wiphy_idx != rdev->wiphy_idx) { + /* count number of places needed to print wiphy_idx */ + digits = 1; + while (wiphy_idx /= 10) + digits++; + /* + * deny the name if it is phy where is printed + * without leading zeroes. taken == strlen(newname) here + */ + if (taken == strlen(PHY_NAME) + digits) + return -EINVAL; + } + + /* Ignore nop renames */ if (strcmp(newname, dev_name(&rdev->wiphy.dev)) == 0) return 0; @@ -189,7 +205,7 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, /* Ensure another device does not already have this name. */ list_for_each_entry(rdev2, &cfg80211_rdev_list, list) if (strcmp(newname, dev_name(&rdev2->wiphy.dev)) == 0) - return -EEXIST; + return -EINVAL; result = device_rename(&rdev->wiphy.dev, newname); if (result) @@ -304,11 +320,9 @@ static void cfg80211_event_work(struct work_struct *work) struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) { static int wiphy_counter; - int i; - struct cfg80211_registered_device *rdev, *rdev2; + + struct cfg80211_registered_device *rdev; int alloc_size; - char nname[IFNAMSIZ + 1]; - bool found = false; WARN_ON(ops->add_key && (!ops->del_key || !ops->set_default_key)); WARN_ON(ops->auth && (!ops->assoc || !ops->deauth || !ops->disassoc)); @@ -332,37 +346,17 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) if (unlikely(!wiphy_idx_valid(rdev->wiphy_idx))) { wiphy_counter--; - goto too_many_devs; - } - - /* 64k wiphy devices is enough for anyone! */ - for (i = 0; i < 0xFFFF; i++) { - found = false; - snprintf(nname, sizeof(nname)-1, PHY_NAME "%d", i); - nname[sizeof(nname)-1] = 0; - list_for_each_entry(rdev2, &cfg80211_rdev_list, list) - if (strcmp(nname, dev_name(&rdev2->wiphy.dev)) == 0) { - found = true; - break; - } - - if (!found) - break; - } - - if (unlikely(found)) { -too_many_devs: mutex_unlock(&cfg80211_mutex); - /* ugh, too many devices already! */ + /* ugh, wrapped! */ kfree(rdev); return NULL; } - /* give it a proper name */ - dev_set_name(&rdev->wiphy.dev, "%s", nname); - mutex_unlock(&cfg80211_mutex); + /* give it a proper name */ + dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx); + mutex_init(&rdev->mtx); mutex_init(&rdev->devlist_mtx); INIT_LIST_HEAD(&rdev->netdev_list); -- cgit v0.10.2 From b38afa87698375179026224522c2e48dcbf17e65 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Thu, 7 Oct 2010 16:12:06 -0700 Subject: mac80211: Improve mlme probe response log messages. Old messages didn't mention the device in question. Signed-off-by: Ben Greear Signed-off-by: John W. Linville diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 5695c94..a3a9421 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1864,10 +1864,12 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) else if (ifmgd->probe_send_count < IEEE80211_MAX_PROBE_TRIES) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "No probe response from AP %pM" - " after %dms, try %d\n", bssid, - (1000 * IEEE80211_PROBE_WAIT)/HZ, - ifmgd->probe_send_count); + wiphy_debug(local->hw.wiphy, + "%s: No probe response from AP %pM" + " after %dms, try %d\n", + sdata->name, + bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ, + ifmgd->probe_send_count); #endif ieee80211_mgd_probe_ap_send(sdata); } else { @@ -1877,9 +1879,11 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) */ ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | IEEE80211_STA_BEACON_POLL); - printk(KERN_DEBUG "No probe response from AP %pM" - " after %dms, disconnecting.\n", - bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); + wiphy_debug(local->hw.wiphy, + "%s: No probe response from AP %pM" + " after %dms, disconnecting.\n", + sdata->name, + bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); ieee80211_set_disassoc(sdata, true, true); mutex_unlock(&ifmgd->mtx); mutex_lock(&local->mtx); -- cgit v0.10.2 From 5a5c731aa59cc2c44ca20f45b1a577cd4f5435e2 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Thu, 7 Oct 2010 16:39:20 -0700 Subject: wireless: Set some stats used by /proc/net/wireless (wext) Some stats for /proc/net/wireless (and wext in general) are not being set. This patch addresses a few of those with values easily obtained from mac80211 core. Signed-off-by: Ben Greear Signed-off-by: John W. Linville diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 0778d04..f920a06 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -403,6 +403,7 @@ struct station_parameters { * @STATION_INFO_TX_PACKETS: @tx_packets filled * @STATION_INFO_TX_RETRIES: @tx_retries filled * @STATION_INFO_TX_FAILED: @tx_failed filled + * @STATION_INFO_RX_DROP_MISC: @rx_dropped_misc filled */ enum station_info_flags { STATION_INFO_INACTIVE_TIME = 1<<0, @@ -417,6 +418,7 @@ enum station_info_flags { STATION_INFO_TX_PACKETS = 1<<9, STATION_INFO_TX_RETRIES = 1<<10, STATION_INFO_TX_FAILED = 1<<11, + STATION_INFO_RX_DROP_MISC = 1<<12, }; /** @@ -468,6 +470,7 @@ struct rate_info { * @tx_packets: packets transmitted to this station * @tx_retries: cumulative retry counts * @tx_failed: number of failed transmissions (retries exceeded, no ACK) + * @rx_dropped_misc: Dropped for un-specified reason. * @generation: generation number for nl80211 dumps. * This number should increase every time the list of stations * changes, i.e. when a station is added or removed, so that @@ -487,6 +490,7 @@ struct station_info { u32 tx_packets; u32 tx_retries; u32 tx_failed; + u32 rx_dropped_misc; int generation; }; diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index ecf9b71..25fb351 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -329,7 +329,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) STATION_INFO_TX_PACKETS | STATION_INFO_TX_RETRIES | STATION_INFO_TX_FAILED | - STATION_INFO_TX_BITRATE; + STATION_INFO_TX_BITRATE | + STATION_INFO_RX_DROP_MISC; sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); sinfo->rx_bytes = sta->rx_bytes; @@ -338,6 +339,7 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) sinfo->tx_packets = sta->tx_packets; sinfo->tx_retries = sta->tx_retry_count; sinfo->tx_failed = sta->tx_retry_failed; + sinfo->rx_dropped_misc = sta->rx_dropped; if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) || (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) { diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 6002265..12222ee 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -1366,6 +1366,10 @@ struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev) } wstats.qual.updated |= IW_QUAL_NOISE_INVALID; + if (sinfo.filled & STATION_INFO_RX_DROP_MISC) + wstats.discard.misc = sinfo.rx_dropped_misc; + if (sinfo.filled & STATION_INFO_TX_FAILED) + wstats.discard.retries = sinfo.tx_failed; return &wstats; } -- cgit v0.10.2 From 92c68a66a8f73c51f062ae8cae958c86a21fea78 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Fri, 8 Oct 2010 09:43:29 -0700 Subject: ath5k: Print out opmode in debugfs. Helps debug multi-VIF scenarios. Signed-off-by: Ben Greear Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c index c2d549f..a342a9d 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c @@ -60,6 +60,7 @@ #include "base.h" #include "debug.h" +#include "../debug.h" static unsigned int ath5k_debug; module_param_named(debug, ath5k_debug, uint, 0); @@ -492,6 +493,7 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf, char buf[700]; unsigned int len = 0; u32 filt = ath5k_hw_get_rx_filter(sc->ah); + const char *tmp; len += snprintf(buf+len, sizeof(buf)-len, "bssid-mask: %pM\n", sc->bssidmask); @@ -524,6 +526,14 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf, else len += snprintf(buf+len, sizeof(buf)-len, "\n"); + tmp = ath_opmode_to_string(sc->opmode); + if (tmp) + len += snprintf(buf+len, sizeof(buf)-len, "opmode: %s\n", + tmp); + else + len += snprintf(buf+len, sizeof(buf)-len, + "opmode: UNKNOWN-%i\n", sc->opmode); + if (len > sizeof(buf)) len = sizeof(buf); diff --git a/drivers/net/wireless/ath/debug.c b/drivers/net/wireless/ath/debug.c index 53e77bd..a9eb787 100644 --- a/drivers/net/wireless/ath/debug.c +++ b/drivers/net/wireless/ath/debug.c @@ -30,3 +30,32 @@ void ath_print(struct ath_common *common, int dbg_mask, const char *fmt, ...) va_end(args); } EXPORT_SYMBOL(ath_print); + +const char *ath_opmode_to_string(enum nl80211_iftype opmode) +{ + switch (opmode) { + case NL80211_IFTYPE_UNSPECIFIED: + return "UNSPEC"; + case NL80211_IFTYPE_ADHOC: + return "ADHOC"; + case NL80211_IFTYPE_STATION: + return "STATION"; + case NL80211_IFTYPE_AP: + return "AP"; + case NL80211_IFTYPE_AP_VLAN: + return "AP-VLAN"; + case NL80211_IFTYPE_WDS: + return "WDS"; + case NL80211_IFTYPE_MONITOR: + return "MONITOR"; + case NL80211_IFTYPE_MESH_POINT: + return "MESH"; + case NL80211_IFTYPE_P2P_CLIENT: + return "P2P-CLIENT"; + case NL80211_IFTYPE_P2P_GO: + return "P2P-GO"; + default: + return NULL; + } +} +EXPORT_SYMBOL(ath_opmode_to_string); diff --git a/drivers/net/wireless/ath/debug.h b/drivers/net/wireless/ath/debug.h index fd3a020..a3a5a62 100644 --- a/drivers/net/wireless/ath/debug.h +++ b/drivers/net/wireless/ath/debug.h @@ -77,4 +77,7 @@ ath_print(struct ath_common *common, int dbg_mask, const char *fmt, ...) } #endif /* CONFIG_ATH_DEBUG */ +/** Returns string describing opmode, or NULL if unknown mode. */ +const char *ath_opmode_to_string(enum nl80211_iftype opmode); + #endif /* ATH_DEBUG_H */ -- cgit v0.10.2 From 62c58fb4316905cd9c1dbf01967935ed5610b45d Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Fri, 8 Oct 2010 12:01:15 -0700 Subject: ath5k: Adjust opmode when interfaces are removed. Otherwise, if there is an AP and a STATION, and AP is removed, the NIC will not revert back to STATION mode. Reported-by: Eliad Peller Signed-off-by: Ben Greear Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index dad7265..c9732a6 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -62,6 +62,7 @@ #include "reg.h" #include "debug.h" #include "ani.h" +#include "../debug.h" static int modparam_nohwcrypt; module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); @@ -517,12 +518,14 @@ struct ath_vif_iter_data { bool need_set_hw_addr; bool found_active; bool any_assoc; + enum nl80211_iftype opmode; }; static void ath_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { struct ath_vif_iter_data *iter_data = data; int i; + struct ath5k_vif *avf = (void *)vif->drv_priv; if (iter_data->hw_macaddr) for (i = 0; i < ETH_ALEN; i++) @@ -539,13 +542,34 @@ static void ath_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) iter_data->need_set_hw_addr = false; if (!iter_data->any_assoc) { - struct ath5k_vif *avf = (void *)vif->drv_priv; if (avf->assoc) iter_data->any_assoc = true; } + + /* Calculate combined mode - when APs are active, operate in AP mode. + * Otherwise use the mode of the new interface. This can currently + * only deal with combinations of APs and STAs. Only one ad-hoc + * interfaces is allowed above. + */ + if (avf->opmode == NL80211_IFTYPE_AP) + iter_data->opmode = NL80211_IFTYPE_AP; + else + if (iter_data->opmode == NL80211_IFTYPE_UNSPECIFIED) + iter_data->opmode = avf->opmode; } -void ath5k_update_bssid_mask(struct ath5k_softc *sc, struct ieee80211_vif *vif) +static void ath_do_set_opmode(struct ath5k_softc *sc) +{ + struct ath5k_hw *ah = sc->ah; + ath5k_hw_set_opmode(ah, sc->opmode); + ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "mode setup opmode %d (%s)\n", + sc->opmode, + ath_opmode_to_string(sc->opmode) ? + ath_opmode_to_string(sc->opmode) : "UKNOWN"); +} + +void ath5k_update_bssid_mask_and_opmode(struct ath5k_softc *sc, + struct ieee80211_vif *vif) { struct ath_common *common = ath5k_hw_common(sc->ah); struct ath_vif_iter_data iter_data; @@ -558,6 +582,7 @@ void ath5k_update_bssid_mask(struct ath5k_softc *sc, struct ieee80211_vif *vif) memset(&iter_data.mask, 0xff, ETH_ALEN); iter_data.found_active = false; iter_data.need_set_hw_addr = true; + iter_data.opmode = NL80211_IFTYPE_UNSPECIFIED; if (vif) ath_vif_iter(&iter_data, vif->addr, vif); @@ -567,10 +592,18 @@ void ath5k_update_bssid_mask(struct ath5k_softc *sc, struct ieee80211_vif *vif) &iter_data); memcpy(sc->bssidmask, iter_data.mask, ETH_ALEN); + sc->opmode = iter_data.opmode; + if (sc->opmode == NL80211_IFTYPE_UNSPECIFIED) + /* Nothing active, default to station mode */ + sc->opmode = NL80211_IFTYPE_STATION; + + ath_do_set_opmode(sc); + if (iter_data.need_set_hw_addr && iter_data.found_active) ath5k_hw_set_lladdr(sc->ah, iter_data.active_mac); - ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask); + if (ath5k_hw_hasbssidmask(sc->ah)) + ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask); } static void @@ -582,15 +615,9 @@ ath5k_mode_setup(struct ath5k_softc *sc, struct ieee80211_vif *vif) /* configure rx filter */ rfilt = sc->filter_flags; ath5k_hw_set_rx_filter(ah, rfilt); - - if (ath5k_hw_hasbssidmask(ah)) - ath5k_update_bssid_mask(sc, vif); - - /* configure operational mode */ - ath5k_hw_set_opmode(ah, sc->opmode); - - ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "mode setup opmode %d\n", sc->opmode); ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "RX filter 0x%x\n", rfilt); + + ath5k_update_bssid_mask_and_opmode(sc, vif); } static inline int @@ -2688,7 +2715,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) SET_IEEE80211_PERM_ADDR(hw, mac); memcpy(&sc->lladdr, mac, ETH_ALEN); /* All MAC address bits matter for ACKs */ - ath5k_update_bssid_mask(sc, NULL); + ath5k_update_bssid_mask_and_opmode(sc, NULL); regulatory->current_rd = ah->ah_capabilities.cap_eeprom.ee_regdomain; ret = ath_regd_init(regulatory, hw->wiphy, ath5k_reg_notifier); @@ -2786,7 +2813,6 @@ static int ath5k_add_interface(struct ieee80211_hw *hw, { struct ath5k_softc *sc = hw->priv; int ret; - struct ath5k_hw *ah = sc->ah; struct ath5k_vif *avf = (void *)vif->drv_priv; mutex_lock(&sc->lock); @@ -2850,18 +2876,6 @@ static int ath5k_add_interface(struct ieee80211_hw *hw, sc->num_adhoc_vifs++; } - /* Set combined mode - when APs are configured, operate in AP mode. - * Otherwise use the mode of the new interface. This can currently - * only deal with combinations of APs and STAs. Only one ad-hoc - * interfaces is allowed above. - */ - if (sc->num_ap_vifs) - sc->opmode = NL80211_IFTYPE_AP; - else - sc->opmode = vif->type; - - ath5k_hw_set_opmode(ah, sc->opmode); - /* Any MAC address is fine, all others are included through the * filter. */ @@ -2905,7 +2919,7 @@ ath5k_remove_interface(struct ieee80211_hw *hw, else if (avf->opmode == NL80211_IFTYPE_ADHOC) sc->num_adhoc_vifs--; - ath5k_update_bssid_mask(sc, NULL); + ath5k_update_bssid_mask_and_opmode(sc, NULL); mutex_unlock(&sc->lock); } -- cgit v0.10.2 From dfdac8ac033c9ad048a5c68563bd41bda6c5e60b Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 8 Oct 2010 22:13:51 +0200 Subject: ath9k_hw: store the clock rate in common data on channel changes Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index cee0191..b36d9d7 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -145,6 +145,8 @@ struct ath_common { DECLARE_BITMAP(tkip_keymap, ATH_KEYMAX); enum ath_crypt_caps crypt_caps; + unsigned int clockrate; + struct ath_regulatory regulatory; const struct ath_ops *ops; const struct ath_bus_ops *bus_ops; diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index f2a907b..f2aa684 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -465,35 +465,13 @@ static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah) ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel - 1); } -static u8 ath9k_hw_chan_2_clockrate_mhz(struct ath_hw *ah) -{ - struct ath9k_channel *chan = ah->curchan; - struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; - u8 clockrate; /* in MHz */ - - if (!ah->curchan) /* should really check for CCK instead */ - clockrate = ATH9K_CLOCK_RATE_CCK; - else if (conf->channel->band == IEEE80211_BAND_2GHZ) - clockrate = ATH9K_CLOCK_RATE_2GHZ_OFDM; - else if (IS_CHAN_A_FAST_CLOCK(ah, chan)) - clockrate = ATH9K_CLOCK_FAST_RATE_5GHZ_OFDM; - else - clockrate = ATH9K_CLOCK_RATE_5GHZ_OFDM; - - if (conf_is_ht40(conf)) - return clockrate * 2; - - return clockrate; -} - static int32_t ath9k_hw_ani_get_listen_time(struct ath_hw *ah) { + struct ath_common *common = ath9k_hw_common(ah); int32_t listen_time; - int32_t clock_rate; ath9k_hw_update_cycle_counters(ah); - clock_rate = ath9k_hw_chan_2_clockrate_mhz(ah) * 1000; - listen_time = ah->listen_time / clock_rate; + listen_time = ah->listen_time / (common->clockrate * 1000); ah->listen_time = 0; return listen_time; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 05e9935..f5d7917 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -88,29 +88,32 @@ static void ath9k_hw_ani_cache_ini_regs(struct ath_hw *ah) /* Helper Functions */ /********************/ -static u32 ath9k_hw_mac_clks(struct ath_hw *ah, u32 usecs) +static void ath9k_hw_set_clockrate(struct ath_hw *ah) { struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; + struct ath_common *common = ath9k_hw_common(ah); + unsigned int clockrate; if (!ah->curchan) /* should really check for CCK instead */ - return usecs *ATH9K_CLOCK_RATE_CCK; - if (conf->channel->band == IEEE80211_BAND_2GHZ) - return usecs *ATH9K_CLOCK_RATE_2GHZ_OFDM; - - if (ah->caps.hw_caps & ATH9K_HW_CAP_FASTCLOCK) - return usecs * ATH9K_CLOCK_FAST_RATE_5GHZ_OFDM; + clockrate = ATH9K_CLOCK_RATE_CCK; + else if (conf->channel->band == IEEE80211_BAND_2GHZ) + clockrate = ATH9K_CLOCK_RATE_2GHZ_OFDM; + else if (ah->caps.hw_caps & ATH9K_HW_CAP_FASTCLOCK) + clockrate = ATH9K_CLOCK_FAST_RATE_5GHZ_OFDM; else - return usecs * ATH9K_CLOCK_RATE_5GHZ_OFDM; + clockrate = ATH9K_CLOCK_RATE_5GHZ_OFDM; + + if (conf_is_ht40(conf)) + clockrate *= 2; + + common->clockrate = clockrate; } static u32 ath9k_hw_mac_to_clks(struct ath_hw *ah, u32 usecs) { - struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; + struct ath_common *common = ath9k_hw_common(ah); - if (conf_is_ht40(conf)) - return ath9k_hw_mac_clks(ah, usecs) * 2; - else - return ath9k_hw_mac_clks(ah, usecs); + return usecs * common->clockrate; } bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout) @@ -1156,6 +1159,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, "Failed to set channel\n"); return false; } + ath9k_hw_set_clockrate(ah); ah->eep_ops->set_txpower(ah, chan, ath9k_regd_get_ctl(regulatory, chan), @@ -1368,6 +1372,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, if (r) return r; + ath9k_hw_set_clockrate(ah); + ENABLE_REGWRITE_BUFFER(ah); for (i = 0; i < AR_NUM_DCU; i++) -- cgit v0.10.2 From 9d119f3ebd074bde0b801f476a44ca60d222efb2 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 8 Oct 2010 22:13:52 +0200 Subject: ath5k: store the clock rate in common data on channel changes Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 0cba2e3..4a367cd 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1201,7 +1201,7 @@ void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high); /* Clock rate related functions */ unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec); unsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock); -unsigned int ath5k_hw_get_clockrate(struct ath5k_hw *ah); +void ath5k_hw_set_clockrate(struct ath5k_hw *ah); /* Queue Control Unit, DFS Control Unit Functions */ int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue, diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index 095d30b..074b4c6 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -207,7 +207,8 @@ static int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout) */ unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec) { - return usec * ath5k_hw_get_clockrate(ah); + struct ath_common *common = ath5k_hw_common(ah); + return usec * common->clockrate; } /** @@ -216,17 +217,19 @@ unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec) */ unsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock) { - return clock / ath5k_hw_get_clockrate(ah); + struct ath_common *common = ath5k_hw_common(ah); + return clock / common->clockrate; } /** - * ath5k_hw_get_clockrate - Get the clock rate for current mode + * ath5k_hw_set_clockrate - Set common->clockrate for the current channel * * @ah: The &struct ath5k_hw */ -unsigned int ath5k_hw_get_clockrate(struct ath5k_hw *ah) +void ath5k_hw_set_clockrate(struct ath5k_hw *ah) { struct ieee80211_channel *channel = ah->ah_current_channel; + struct ath_common *common = ath5k_hw_common(ah); int clock; if (channel->hw_value & CHANNEL_5GHZ) @@ -240,7 +243,7 @@ unsigned int ath5k_hw_get_clockrate(struct ath5k_hw *ah) if (channel->hw_value & CHANNEL_TURBO) clock *= 2; - return clock; + common->clockrate = clock; } /** diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 61da913..2193678 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -1093,6 +1093,7 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel) ah->ah_current_channel = channel; ah->ah_turbo = channel->hw_value == CHANNEL_T ? true : false; + ath5k_hw_set_clockrate(ah); return 0; } -- cgit v0.10.2 From b5bfc5683db44a121ad47ec0a9f4efd4aac040e0 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 8 Oct 2010 22:13:53 +0200 Subject: ath9k_hw: move the cycle counter tracking to ath Instead of keeping track of wraparound, clear the counters on every access and keep separate deltas for ANI and later survey use. Also moves the function for calculating the 'listen time' for ANI Signed-off-by: Felix Fietkau Signed-off-by: Bruno Randolf Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index b36d9d7..501050c 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -19,6 +19,7 @@ #include #include +#include #include /* @@ -42,6 +43,13 @@ struct ath_ani { struct timer_list timer; }; +struct ath_cycle_counters { + u32 cycles; + u32 rx_busy; + u32 rx_frame; + u32 tx_frame; +}; + enum ath_device_state { ATH_HW_UNAVAILABLE, ATH_HW_INITIALIZED, @@ -147,6 +155,10 @@ struct ath_common { unsigned int clockrate; + spinlock_t cc_lock; + struct ath_cycle_counters cc_ani; + struct ath_cycle_counters cc_survey; + struct ath_regulatory regulatory; const struct ath_ops *ops; const struct ath_bus_ops *bus_ops; @@ -163,5 +175,7 @@ int ath_key_config(struct ath_common *common, struct ieee80211_sta *sta, struct ieee80211_key_conf *key); bool ath_hw_keyreset(struct ath_common *common, u16 entry); +void ath_hw_cycle_counters_update(struct ath_common *common); +int32_t ath_hw_get_listen_time(struct ath_common *common); #endif /* ATH_H */ diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index f2aa684..3aa8fb1 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -465,18 +465,6 @@ static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah) ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel - 1); } -static int32_t ath9k_hw_ani_get_listen_time(struct ath_hw *ah) -{ - struct ath_common *common = ath9k_hw_common(ah); - int32_t listen_time; - - ath9k_hw_update_cycle_counters(ah); - listen_time = ah->listen_time / (common->clockrate * 1000); - ah->listen_time = 0; - - return listen_time; -} - static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning) { struct ar5416AniState *aniState; @@ -655,7 +643,9 @@ static void ath9k_hw_ani_read_counters(struct ath_hw *ah) u32 phyCnt1, phyCnt2; int32_t listenTime; - listenTime = ath9k_hw_ani_get_listen_time(ah); + ath_hw_cycle_counters_update(common); + listenTime = ath_hw_get_listen_time(common); + if (listenTime < 0) { ah->stats.ast_ani_lneg++; ath9k_ani_restart(ah); @@ -796,54 +786,6 @@ void ath9k_hw_disable_mib_counters(struct ath_hw *ah) } EXPORT_SYMBOL(ath9k_hw_disable_mib_counters); -void ath9k_hw_update_cycle_counters(struct ath_hw *ah) -{ - struct ath_cycle_counters cc; - bool clear; - - memcpy(&cc, &ah->cc, sizeof(cc)); - - /* freeze counters */ - REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC); - - ah->cc.cycles = REG_READ(ah, AR_CCCNT); - if (ah->cc.cycles < cc.cycles) { - clear = true; - goto skip; - } - - ah->cc.rx_clear = REG_READ(ah, AR_RCCNT); - ah->cc.rx_frame = REG_READ(ah, AR_RFCNT); - ah->cc.tx_frame = REG_READ(ah, AR_TFCNT); - - /* prevent wraparound */ - if (ah->cc.cycles & BIT(31)) - clear = true; - -#define CC_DELTA(_field, _reg) ah->cc_delta._field += ah->cc._field - cc._field - CC_DELTA(cycles, AR_CCCNT); - CC_DELTA(rx_frame, AR_RFCNT); - CC_DELTA(rx_clear, AR_RCCNT); - CC_DELTA(tx_frame, AR_TFCNT); -#undef CC_DELTA - - ah->listen_time += (ah->cc.cycles - cc.cycles) - - ((ah->cc.rx_frame - cc.rx_frame) + - (ah->cc.tx_frame - cc.tx_frame)); - -skip: - if (clear) { - REG_WRITE(ah, AR_CCCNT, 0); - REG_WRITE(ah, AR_RFCNT, 0); - REG_WRITE(ah, AR_RCCNT, 0); - REG_WRITE(ah, AR_TFCNT, 0); - memset(&ah->cc, 0, sizeof(ah->cc)); - } - - /* unfreeze counters */ - REG_WRITE(ah, AR_MIBC, 0); -} - /* * Process a MIB interrupt. We may potentially be invoked because * any of the MIB counters overflow/trigger so don't assume we're diff --git a/drivers/net/wireless/ath/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h index 98cfd81..0cd6783 100644 --- a/drivers/net/wireless/ath/ath9k/ani.h +++ b/drivers/net/wireless/ath/ath9k/ani.h @@ -93,13 +93,6 @@ struct ath9k_mib_stats { u32 beacons; }; -struct ath_cycle_counters { - u32 cycles; - u32 rx_frame; - u32 rx_clear; - u32 tx_frame; -}; - /* INI default values for ANI registers */ struct ath9k_ani_default { u16 m1ThreshLow; @@ -164,7 +157,6 @@ struct ar5416Stats { void ath9k_enable_mib_counters(struct ath_hw *ah); void ath9k_hw_disable_mib_counters(struct ath_hw *ah); -void ath9k_hw_update_cycle_counters(struct ath_hw *ah); void ath9k_hw_ani_setup(struct ath_hw *ah); void ath9k_hw_ani_init(struct ath_hw *ah); int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah, diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index efb0559..669b777 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -1254,13 +1254,12 @@ void ar9003_hw_bb_watchdog_dbg_info(struct ath_hw *ah) "** BB mode: BB_gen_controls=0x%08x **\n", REG_READ(ah, AR_PHY_GEN_CTRL)); - ath9k_hw_update_cycle_counters(ah); -#define PCT(_field) (ah->cc_delta._field * 100 / ah->cc_delta.cycles) - if (ah->cc_delta.cycles) +#define PCT(_field) (common->cc_survey._field * 100 / common->cc_survey.cycles) + if (common->cc_survey.cycles) ath_print(common, ATH_DBG_RESET, "** BB busy times: rx_clear=%d%%, " "rx_frame=%d%%, tx_frame=%d%% **\n", - PCT(rx_clear), PCT(rx_frame), PCT(tx_frame)); + PCT(rx_busy), PCT(rx_frame), PCT(tx_frame)); ath_print(common, ATH_DBG_RESET, "==== BB update: done ====\n\n"); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 87627dd..7f696c8 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -740,8 +740,6 @@ struct ath_hw { int coarse_low[5]; int firpwr[5]; enum ath9k_ani_cmd ani_function; - struct ath_cycle_counters cc, cc_delta; - int32_t listen_time; /* Bluetooth coexistance */ struct ath_btcoex_hw btcoex_hw; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 74c2dc8..360c6f5 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -399,6 +399,7 @@ void ath_ani_calibrate(unsigned long data) bool aniflag = false; unsigned int timestamp = jiffies_to_msecs(jiffies); u32 cal_interval, short_cal_interval, long_cal_interval; + unsigned long flags; if (ah->caldata && ah->caldata->nfcal_interference) long_cal_interval = ATH_LONG_CALINTERVAL_INT; @@ -449,8 +450,11 @@ void ath_ani_calibrate(unsigned long data) /* Skip all processing if there's nothing to do. */ if (longcal || shortcal || aniflag) { /* Call ANI routine if necessary */ - if (aniflag) + if (aniflag) { + spin_lock_irqsave(&common->cc_lock, flags); ath9k_hw_ani_monitor(ah, ah->curchan); + spin_unlock_irqrestore(&common->cc_lock, flags); + } /* Perform calibration if necessary */ if (longcal || shortcal) { @@ -635,6 +639,7 @@ irqreturn_t ath_isr(int irq, void *dev) struct ath_softc *sc = dev; struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); enum ath9k_int status; bool sched = false; @@ -684,7 +689,12 @@ irqreturn_t ath_isr(int irq, void *dev) if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) && (status & ATH9K_INT_BB_WATCHDOG)) { + + spin_lock(&common->cc_lock); + ath_hw_cycle_counters_update(common); ar9003_hw_bb_watchdog_dbg_info(ah); + spin_unlock(&common->cc_lock); + goto chip_reset; } diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 6d01e50..0176178 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -107,12 +107,6 @@ #define AR_RXCFG_DMASZ_256B 6 #define AR_RXCFG_DMASZ_512B 7 -#define AR_MIBC 0x0040 -#define AR_MIBC_COW 0x00000001 -#define AR_MIBC_FMC 0x00000002 -#define AR_MIBC_CMC 0x00000004 -#define AR_MIBC_MCS 0x00000008 - #define AR_TOPS 0x0044 #define AR_TOPS_MASK 0x0000FFFF @@ -1524,11 +1518,6 @@ enum { #define AR_TPC_CHIRP 0x003f0000 #define AR_TPC_CHIRP_S 0x16 -#define AR_TFCNT 0x80ec -#define AR_RFCNT 0x80f0 -#define AR_RCCNT 0x80f4 -#define AR_CCCNT 0x80f8 - #define AR_QUIET1 0x80fc #define AR_QUIET1_NEXT_QUIET_S 0 #define AR_QUIET1_NEXT_QUIET_M 0x0000ffff diff --git a/drivers/net/wireless/ath/hw.c b/drivers/net/wireless/ath/hw.c index a8f81ea..183c282 100644 --- a/drivers/net/wireless/ath/hw.c +++ b/drivers/net/wireless/ath/hw.c @@ -124,3 +124,62 @@ void ath_hw_setbssidmask(struct ath_common *common) REG_WRITE(ah, get_unaligned_le16(common->bssidmask + 4), AR_BSSMSKU); } EXPORT_SYMBOL(ath_hw_setbssidmask); + + +/** + * ath_hw_cycle_counters_update - common function to update cycle counters + * + * @common: the ath_common struct for the device. + * + * This function is used to update all cycle counters in one place. + * It has to be called while holding common->cc_lock! + */ +void ath_hw_cycle_counters_update(struct ath_common *common) +{ + u32 cycles, busy, rx, tx; + void *ah = common->ah; + + /* freeze */ + REG_WRITE(ah, AR_MIBC_FMC, AR_MIBC); + + /* read */ + cycles = REG_READ(ah, AR_CCCNT); + busy = REG_READ(ah, AR_RCCNT); + rx = REG_READ(ah, AR_RFCNT); + tx = REG_READ(ah, AR_TFCNT); + + /* clear */ + REG_WRITE(ah, 0, AR_CCCNT); + REG_WRITE(ah, 0, AR_RFCNT); + REG_WRITE(ah, 0, AR_RCCNT); + REG_WRITE(ah, 0, AR_TFCNT); + + /* unfreeze */ + REG_WRITE(ah, 0, AR_MIBC); + + /* update all cycle counters here */ + common->cc_ani.cycles += cycles; + common->cc_ani.rx_busy += busy; + common->cc_ani.rx_frame += rx; + common->cc_ani.tx_frame += tx; + + common->cc_survey.cycles += cycles; + common->cc_survey.rx_busy += busy; + common->cc_survey.rx_frame += rx; + common->cc_survey.tx_frame += tx; +} +EXPORT_SYMBOL(ath_hw_cycle_counters_update); + +int32_t ath_hw_get_listen_time(struct ath_common *common) +{ + struct ath_cycle_counters *cc = &common->cc_ani; + int32_t listen_time; + + listen_time = (cc->cycles - cc->rx_frame - cc->tx_frame) / + (common->clockrate * 1000); + + memset(cc, 0, sizeof(*cc)); + + return listen_time; +} +EXPORT_SYMBOL(ath_hw_get_listen_time); diff --git a/drivers/net/wireless/ath/reg.h b/drivers/net/wireless/ath/reg.h index e798ef4..298e53f 100644 --- a/drivers/net/wireless/ath/reg.h +++ b/drivers/net/wireless/ath/reg.h @@ -17,6 +17,12 @@ #ifndef ATH_REGISTERS_H #define ATH_REGISTERS_H +#define AR_MIBC 0x0040 +#define AR_MIBC_COW 0x00000001 +#define AR_MIBC_FMC 0x00000002 +#define AR_MIBC_CMC 0x00000004 +#define AR_MIBC_MCS 0x00000008 + /* * BSSID mask registers. See ath_hw_set_bssid_mask() * for detailed documentation about these registers. @@ -24,6 +30,11 @@ #define AR_BSSMSKL 0x80e0 #define AR_BSSMSKU 0x80e4 +#define AR_TFCNT 0x80ec +#define AR_RFCNT 0x80f0 +#define AR_RCCNT 0x80f4 +#define AR_CCCNT 0x80f8 + #define AR_KEYTABLE_0 0x8800 #define AR_KEYTABLE(_n) (AR_KEYTABLE_0 + ((_n)*32)) #define AR_KEY_CACHE_SIZE 128 -- cgit v0.10.2 From 7109ca5c80a0bb94378ebd7f8bb6d00edb5e6fba Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 8 Oct 2010 22:13:54 +0200 Subject: ath5k: use the common cycle counter / listen time implementation Signed-off-by: Felix Fietkau Signed-off-by: Bruno Randolf Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/ani.c b/drivers/net/wireless/ath/ath5k/ani.c index e4a5f04..f141919 100644 --- a/drivers/net/wireless/ath/ath5k/ani.c +++ b/drivers/net/wireless/ath/ath5k/ani.c @@ -355,41 +355,28 @@ ath5k_ani_lower_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as) /** - * ath5k_hw_ani_get_listen_time() - Calculate time spent listening + * ath5k_hw_ani_get_listen_time() - Update counters and return listening time * * Return an approximation of the time spent "listening" in milliseconds (ms) - * since the last call of this function by deducting the cycles spent - * transmitting and receiving from the total cycle count. - * Save profile count values for debugging/statistics and because we might want - * to use them later. - * - * We assume no one else clears these registers! + * since the last call of this function. + * Save a snapshot of the counter values for debugging/statistics. */ static int ath5k_hw_ani_get_listen_time(struct ath5k_hw *ah, struct ath5k_ani_state *as) { + struct ath_common *common = ath5k_hw_common(ah); int listen; - /* freeze */ - ath5k_hw_reg_write(ah, AR5K_MIBC_FMC, AR5K_MIBC); - /* read */ - as->pfc_cycles = ath5k_hw_reg_read(ah, AR5K_PROFCNT_CYCLE); - as->pfc_busy = ath5k_hw_reg_read(ah, AR5K_PROFCNT_RXCLR); - as->pfc_tx = ath5k_hw_reg_read(ah, AR5K_PROFCNT_TX); - as->pfc_rx = ath5k_hw_reg_read(ah, AR5K_PROFCNT_RX); - /* clear */ - ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_TX); - ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RX); - ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RXCLR); - ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_CYCLE); - /* un-freeze */ - ath5k_hw_reg_write(ah, 0, AR5K_MIBC); - - /* TODO: where does 44000 come from? (11g clock rate?) */ - listen = (as->pfc_cycles - as->pfc_rx - as->pfc_tx) / 44000; - - if (as->pfc_cycles == 0 || listen < 0) - return 0; + spin_lock_bh(&common->cc_lock); + + ath_hw_cycle_counters_update(common); + memcpy(&as->last_cc, &common->cc_ani, sizeof(as->last_cc)); + + /* clears common->cc_ani */ + listen = ath_hw_get_listen_time(common); + + spin_unlock_bh(&common->cc_lock); + return listen; } diff --git a/drivers/net/wireless/ath/ath5k/ani.h b/drivers/net/wireless/ath/ath5k/ani.h index 55cf26d..d0a6640 100644 --- a/drivers/net/wireless/ath/ath5k/ani.h +++ b/drivers/net/wireless/ath/ath5k/ani.h @@ -75,10 +75,7 @@ struct ath5k_ani_state { unsigned int cck_errors; /* debug/statistics only: numbers from last ANI calibration */ - unsigned int pfc_tx; - unsigned int pfc_rx; - unsigned int pfc_busy; - unsigned int pfc_cycles; + struct ath_cycle_counters last_cc; unsigned int last_listen; unsigned int last_ofdm_errors; unsigned int last_cck_errors; diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c index a342a9d..a3b2171 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c @@ -725,20 +725,21 @@ static ssize_t read_file_ani(struct file *file, char __user *user_buf, len += snprintf(buf+len, sizeof(buf)-len, "beacon RSSI average:\t%d\n", sc->ah->ah_beacon_rssi_avg.avg); + +#define CC_PRINT(_struct, _field) \ + _struct._field, \ + _struct.cycles > 0 ? \ + _struct._field*100/_struct.cycles : 0 + len += snprintf(buf+len, sizeof(buf)-len, "profcnt tx\t\t%u\t(%d%%)\n", - as->pfc_tx, - as->pfc_cycles > 0 ? - as->pfc_tx*100/as->pfc_cycles : 0); + CC_PRINT(as->last_cc, tx_frame)); len += snprintf(buf+len, sizeof(buf)-len, "profcnt rx\t\t%u\t(%d%%)\n", - as->pfc_rx, - as->pfc_cycles > 0 ? - as->pfc_rx*100/as->pfc_cycles : 0); + CC_PRINT(as->last_cc, rx_frame)); len += snprintf(buf+len, sizeof(buf)-len, "profcnt busy\t\t%u\t(%d%%)\n", - as->pfc_busy, - as->pfc_cycles > 0 ? - as->pfc_busy*100/as->pfc_cycles : 0); + CC_PRINT(as->last_cc, rx_busy)); +#undef CC_PRINT len += snprintf(buf+len, sizeof(buf)-len, "profcnt cycles\t\t%u\n", - as->pfc_cycles); + as->last_cc.cycles); len += snprintf(buf+len, sizeof(buf)-len, "listen time\t\t%d\tlast: %d\n", as->listen_time, as->last_listen); -- cgit v0.10.2 From d12c74528e3065c90df70fbc06ec6ffd6e804738 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Fri, 8 Oct 2010 22:27:07 +0200 Subject: mac80211: fix possible null-pointer de-reference This patch not only fixes a null-pointer de-reference that would be triggered by a PLINK_OPEN frame with mis- matching/incompatible mesh configuration, but also responds correctly to non-compatible PLINK_OPEN frames by generating a PLINK_CLOSE with the right reason code. The original bug was detected by smatch. ( http://repo.or.cz/w/smatch.git ) net/mac80211/mesh_plink.c +574 mesh_rx_plink_frame(168) error: we previously assumed 'sta' could be null. Cc: Reviewed-and-Tested-by: Steve deRosier Reviewed-and-Tested-by: Javier Cardona Acked-by: Johannes Berg Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index ea13a80..1c91f0f 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -412,7 +412,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m enum plink_event event; enum plink_frame_type ftype; size_t baselen; - bool deactivated; + bool deactivated, matches_local = true; u8 ie_len; u8 *baseaddr; __le16 plid, llid, reason; @@ -487,6 +487,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m /* Now we will figure out the appropriate event... */ event = PLINK_UNDEFINED; if (ftype != PLINK_CLOSE && (!mesh_matches_local(&elems, sdata))) { + matches_local = false; switch (ftype) { case PLINK_OPEN: event = OPN_RJCT; @@ -498,7 +499,15 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m /* avoid warning */ break; } - spin_lock_bh(&sta->lock); + } + + if (!sta && !matches_local) { + rcu_read_unlock(); + reason = cpu_to_le16(MESH_CAPABILITY_POLICY_VIOLATION); + llid = 0; + mesh_plink_frame_tx(sdata, PLINK_CLOSE, mgmt->sa, llid, + plid, reason); + return; } else if (!sta) { /* ftype == PLINK_OPEN */ u32 rates; @@ -522,7 +531,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m } event = OPN_ACPT; spin_lock_bh(&sta->lock); - } else { + } else if (matches_local) { spin_lock_bh(&sta->lock); switch (ftype) { case PLINK_OPEN: @@ -564,6 +573,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m rcu_read_unlock(); return; } + } else { + spin_lock_bh(&sta->lock); } mpl_dbg("Mesh plink (peer, state, llid, plid, event): %pM %s %d %d %d\n", -- cgit v0.10.2 From 15943a72c7d2031c9150917ca9161a9f891d455a Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Fri, 8 Oct 2010 22:35:09 +0200 Subject: mac80211: temporarily disable reorder release timer Several serve threading problems in the current release reorder timer implementation have been discovered. A lengthy discussion - which lists some of the pitfalls and possible solutions - can be found at: http://marc.info/?t=128635927000001 But due to the complicated nature of the subject and the imminent advent of a new -rc cycle, it was decided to disable the feature for the time being. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b67221d..902b03ee 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -622,6 +622,26 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw, tid_agg_rx->buf_size; } + /* + * Disable the reorder release timer for now. + * + * The current implementation lacks a proper locking scheme + * which would protect vital statistic and debug counters + * from being updated by two different but concurrent BHs. + * + * More information about the topic is available from: + * - thread: http://marc.info/?t=128635927000001 + * + * What was wrong: + * => http://marc.info/?l=linux-wireless&m=128636170811964 + * "Basically the thing is that until your patch, the data + * in the struct didn't actually need locking because it + * was accessed by the RX path only which is not concurrent." + * + * List of what needs to be fixed: + * => http://marc.info/?l=linux-wireless&m=128656352920957 + * + if (tid_agg_rx->stored_mpdu_num) { j = index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % tid_agg_rx->buf_size; @@ -640,6 +660,10 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw, } else { del_timer(&tid_agg_rx->reorder_timer); } + */ + +set_release_timer: + return; } /* -- cgit v0.10.2 From 8610c29a2c9f273886b1c31ae4d92c69d4326262 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 9 Oct 2010 02:39:29 +0200 Subject: cfg80211: add channel utilization stats to the survey command Using these, user space can calculate a relative channel utilization with arbitrary intervals by regularly taking snapshots of the survey results. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index c08709f..0edb256 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -1413,6 +1413,16 @@ enum nl80211_reg_rule_flags { * @NL80211_SURVEY_INFO_FREQUENCY: center frequency of channel * @NL80211_SURVEY_INFO_NOISE: noise level of channel (u8, dBm) * @NL80211_SURVEY_INFO_IN_USE: channel is currently being used + * @NL80211_SURVEY_INFO_CHANNEL_TIME: amount of time (in ms) that the radio + * spent on this channel + * @NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY: amount of the time the primary + * channel was sensed busy (either due to activity or energy detect) + * @NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY: amount of time the extension + * channel was sensed busy + * @NL80211_SURVEY_INFO_CHANNEL_TIME_RX: amount of time the radio spent + * receiving data + * @NL80211_SURVEY_INFO_CHANNEL_TIME_TX: amount of time the radio spent + * transmitting data * @NL80211_SURVEY_INFO_MAX: highest survey info attribute number * currently defined * @__NL80211_SURVEY_INFO_AFTER_LAST: internal use @@ -1422,6 +1432,11 @@ enum nl80211_survey_info { NL80211_SURVEY_INFO_FREQUENCY, NL80211_SURVEY_INFO_NOISE, NL80211_SURVEY_INFO_IN_USE, + NL80211_SURVEY_INFO_CHANNEL_TIME, + NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY, + NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY, + NL80211_SURVEY_INFO_CHANNEL_TIME_RX, + NL80211_SURVEY_INFO_CHANNEL_TIME_TX, /* keep last */ __NL80211_SURVEY_INFO_AFTER_LAST, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index f920a06..24d5b58 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -294,6 +294,11 @@ struct key_params { * * @SURVEY_INFO_NOISE_DBM: noise (in dBm) was filled in * @SURVEY_INFO_IN_USE: channel is currently being used + * @SURVEY_INFO_CHANNEL_TIME: channel active time (in ms) was filled in + * @SURVEY_INFO_CHANNEL_TIME_BUSY: channel busy time was filled in + * @SURVEY_INFO_CHANNEL_TIME_EXT_BUSY: extension channel busy time was filled in + * @SURVEY_INFO_CHANNEL_TIME_RX: channel receive time was filled in + * @SURVEY_INFO_CHANNEL_TIME_TX: channel transmit time was filled in * * Used by the driver to indicate which info in &struct survey_info * it has filled in during the get_survey(). @@ -301,6 +306,11 @@ struct key_params { enum survey_info_flags { SURVEY_INFO_NOISE_DBM = 1<<0, SURVEY_INFO_IN_USE = 1<<1, + SURVEY_INFO_CHANNEL_TIME = 1<<2, + SURVEY_INFO_CHANNEL_TIME_BUSY = 1<<3, + SURVEY_INFO_CHANNEL_TIME_EXT_BUSY = 1<<4, + SURVEY_INFO_CHANNEL_TIME_RX = 1<<5, + SURVEY_INFO_CHANNEL_TIME_TX = 1<<6, }; /** @@ -310,6 +320,11 @@ enum survey_info_flags { * @filled: bitflag of flags from &enum survey_info_flags * @noise: channel noise in dBm. This and all following fields are * optional + * @channel_time: amount of time in ms the radio spent on the channel + * @channel_time_busy: amount of time the primary channel was sensed busy + * @channel_time_ext_busy: amount of time the extension channel was sensed busy + * @channel_time_rx: amount of time the radio spent receiving data + * @channel_time_tx: amount of time the radio spent transmitting data * * Used by dump_survey() to report back per-channel survey information. * @@ -318,6 +333,11 @@ enum survey_info_flags { */ struct survey_info { struct ieee80211_channel *channel; + u64 channel_time; + u64 channel_time_busy; + u64 channel_time_ext_busy; + u64 channel_time_rx; + u64 channel_time_tx; u32 filled; s8 noise; }; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 882dc92..c506241 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3153,6 +3153,21 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq, survey->noise); if (survey->filled & SURVEY_INFO_IN_USE) NLA_PUT_FLAG(msg, NL80211_SURVEY_INFO_IN_USE); + if (survey->filled & SURVEY_INFO_CHANNEL_TIME) + NLA_PUT_U64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME, + survey->channel_time); + if (survey->filled & SURVEY_INFO_CHANNEL_TIME_BUSY) + NLA_PUT_U64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY, + survey->channel_time_busy); + if (survey->filled & SURVEY_INFO_CHANNEL_TIME_EXT_BUSY) + NLA_PUT_U64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY, + survey->channel_time_ext_busy); + if (survey->filled & SURVEY_INFO_CHANNEL_TIME_RX) + NLA_PUT_U64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_RX, + survey->channel_time_rx); + if (survey->filled & SURVEY_INFO_CHANNEL_TIME_TX) + NLA_PUT_U64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_TX, + survey->channel_time_tx); nla_nest_end(msg, infoattr); -- cgit v0.10.2 From cac4220b2e93e6344f987581d52d5bd71ff2cc0e Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 9 Oct 2010 02:39:30 +0200 Subject: ath9k: add compile time checking for the size of the channel list This prevents random memory corruption if the number of channels ever gets changed without an update to the internal channel array size. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 7f696c8..6b92334 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -61,6 +61,8 @@ #define ATH9K_RSSI_BAD -128 +#define ATH9K_NUM_CHANNELS 38 + /* Register read/write primitives */ #define REG_WRITE(_ah, _reg, _val) \ ath9k_hw_common(_ah)->ops->write((_ah), (_val), (_reg)) @@ -618,7 +620,7 @@ struct ath_hw { struct ath9k_hw_version hw_version; struct ath9k_ops_config config; struct ath9k_hw_capabilities caps; - struct ath9k_channel channels[38]; + struct ath9k_channel channels[ATH9K_NUM_CHANNELS]; struct ath9k_channel *curchan; union { diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index d76003c..a4c5ed4 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -481,6 +481,10 @@ static int ath9k_init_channels_rates(struct ath_softc *sc) { void *channels; + BUILD_BUG_ON(ARRAY_SIZE(ath9k_2ghz_chantable) + + ARRAY_SIZE(ath9k_5ghz_chantable) != + ATH9K_NUM_CHANNELS); + if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes)) { channels = kmemdup(ath9k_2ghz_chantable, sizeof(ath9k_2ghz_chantable), GFP_KERNEL); -- cgit v0.10.2 From 3430098ae463e31ab16926ac3eb295368a3ca5d9 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 10 Oct 2010 18:21:52 +0200 Subject: ath9k: implement channel utilization stats for survey Results for the active channel are updated whenever a new survey dump is requested, the old data is kept to allow multiple processes to make their own channel utilization averages. All other channels only contain the data for the last time that the hardware was on the channel, i.e. the last scan result or other off-channel activity. Running a background scan does not clear the data for the active channel. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index de2b18e..4e81fe3 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -593,6 +593,8 @@ struct ath_softc { struct delayed_work wiphy_work; unsigned long wiphy_scheduler_int; int wiphy_scheduler_index; + struct survey_info *cur_survey; + struct survey_info survey[ATH9K_NUM_CHANNELS]; struct tasklet_struct intr_tq; struct tasklet_struct bcon_tasklet; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 360c6f5..8656491 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -175,6 +175,44 @@ static void ath_start_ani(struct ath_common *common) msecs_to_jiffies((u32)ah->config.ani_poll_interval)); } +static void ath_update_survey_nf(struct ath_softc *sc, int channel) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath9k_channel *chan = &ah->channels[channel]; + struct survey_info *survey = &sc->survey[channel]; + + if (chan->noisefloor) { + survey->filled |= SURVEY_INFO_NOISE_DBM; + survey->noise = chan->noisefloor; + } +} + +static void ath_update_survey_stats(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + int pos = ah->curchan - &ah->channels[0]; + struct survey_info *survey = &sc->survey[pos]; + struct ath_cycle_counters *cc = &common->cc_survey; + unsigned int div = common->clockrate * 1000; + + ath_hw_cycle_counters_update(common); + + if (cc->cycles > 0) { + survey->filled |= SURVEY_INFO_CHANNEL_TIME | + SURVEY_INFO_CHANNEL_TIME_BUSY | + SURVEY_INFO_CHANNEL_TIME_RX | + SURVEY_INFO_CHANNEL_TIME_TX; + survey->channel_time += cc->cycles / div; + survey->channel_time_busy += cc->rx_busy / div; + survey->channel_time_rx += cc->rx_frame / div; + survey->channel_time_tx += cc->tx_frame / div; + } + memset(cc, 0, sizeof(*cc)); + + ath_update_survey_nf(sc, pos); +} + /* * Set/change channels. If the channel is really being changed, it's done * by reseting the chip. To accomplish this we must first cleanup any pending @@ -453,6 +491,7 @@ void ath_ani_calibrate(unsigned long data) if (aniflag) { spin_lock_irqsave(&common->cc_lock, flags); ath9k_hw_ani_monitor(ah, ah->curchan); + ath_update_survey_stats(sc); spin_unlock_irqrestore(&common->cc_lock, flags); } @@ -1532,7 +1571,8 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) { struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; - struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_conf *conf = &hw->conf; bool disable_radio; @@ -1598,6 +1638,11 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { struct ieee80211_channel *curchan = hw->conf.channel; int pos = curchan->hw_value; + int old_pos = -1; + unsigned long flags; + + if (ah->curchan) + old_pos = ah->curchan - &ah->channels[0]; aphy->chan_idx = pos; aphy->chan_is_ht = conf_is_ht(conf); @@ -1625,12 +1670,45 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) ath_update_chainmask(sc, conf_is_ht(conf)); + /* update survey stats for the old channel before switching */ + spin_lock_irqsave(&common->cc_lock, flags); + ath_update_survey_stats(sc); + spin_unlock_irqrestore(&common->cc_lock, flags); + + /* + * If the operating channel changes, change the survey in-use flags + * along with it. + * Reset the survey data for the new channel, unless we're switching + * back to the operating channel from an off-channel operation. + */ + if (!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) && + sc->cur_survey != &sc->survey[pos]) { + + if (sc->cur_survey) + sc->cur_survey->filled &= ~SURVEY_INFO_IN_USE; + + sc->cur_survey = &sc->survey[pos]; + + memset(sc->cur_survey, 0, sizeof(struct survey_info)); + sc->cur_survey->filled |= SURVEY_INFO_IN_USE; + } else if (!(sc->survey[pos].filled & SURVEY_INFO_IN_USE)) { + memset(&sc->survey[pos], 0, sizeof(struct survey_info)); + } + if (ath_set_channel(sc, hw, &sc->sc_ah->channels[pos]) < 0) { ath_print(common, ATH_DBG_FATAL, "Unable to set channel\n"); mutex_unlock(&sc->mutex); return -EINVAL; } + + /* + * The most recent snapshot of channel->noisefloor for the old + * channel is only available after the hardware reset. Copy it to + * the survey stats now. + */ + if (old_pos >= 0) + ath_update_survey_nf(sc, old_pos); } skip_chan_change: @@ -2000,9 +2078,15 @@ static int ath9k_get_survey(struct ieee80211_hw *hw, int idx, { struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; - struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ieee80211_supported_band *sband; - struct ath9k_channel *chan; + struct ieee80211_channel *chan; + unsigned long flags; + int pos; + + spin_lock_irqsave(&common->cc_lock, flags); + if (idx == 0) + ath_update_survey_stats(sc); sband = hw->wiphy->bands[IEEE80211_BAND_2GHZ]; if (sband && idx >= sband->n_channels) { @@ -2013,21 +2097,17 @@ static int ath9k_get_survey(struct ieee80211_hw *hw, int idx, if (!sband) sband = hw->wiphy->bands[IEEE80211_BAND_5GHZ]; - if (!sband || idx >= sband->n_channels) - return -ENOENT; - - survey->channel = &sband->channels[idx]; - chan = &ah->channels[survey->channel->hw_value]; - survey->filled = 0; - - if (chan == ah->curchan) - survey->filled |= SURVEY_INFO_IN_USE; - - if (chan->noisefloor) { - survey->filled |= SURVEY_INFO_NOISE_DBM; - survey->noise = chan->noisefloor; + if (!sband || idx >= sband->n_channels) { + spin_unlock_irqrestore(&common->cc_lock, flags); + return -ENOENT; } + chan = &sband->channels[idx]; + pos = chan->hw_value; + memcpy(survey, &sc->survey[pos], sizeof(*survey)); + survey->channel = chan; + spin_unlock_irqrestore(&common->cc_lock, flags); + return 0; } -- cgit v0.10.2 From cfdfa4d3a0c7aa1287c61326a7714f262466157a Mon Sep 17 00:00:00 2001 From: Steve deRosier Date: Sat, 9 Oct 2010 17:23:28 -0700 Subject: mac80211: Update mesh constants to approved IEEE ANA values This patch updates IEEE802.11 mesh constants to be consistent with newly approved values. It modifies some values, as well as adds many new constants in preparation for updating mesh code to the current 802.11s drafts. ANA numbers were taken from: https://mentor.ieee.org/802.11/dcn/09/11-09-0031-12-0000-ana-database-assigned-number-authority.xls A few notes are in order: 1. This will break backwards compatibility with existing Linux kernels as over-the-air constants have changed. 2. Some old and obsolete constants have been retained for now as the mesh code itself hasn't been updated yet to the new 802.11s draft. This was desired to keep the existing mesh scheme working until it can be updated. Adding the approved values is the first step in updating the mesh code. 3. Obsolete constants have been clearly marked. 4. All ANA approved 802.11s constants have been added. Signed-off-by: Steve deRosier Signed-off-by: John W. Linville diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 97b2eae..ed5a03c 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -986,6 +986,7 @@ struct ieee80211_ht_info { #define WLAN_AUTH_OPEN 0 #define WLAN_AUTH_SHARED_KEY 1 #define WLAN_AUTH_FT 2 +#define WLAN_AUTH_SAE 3 #define WLAN_AUTH_LEAP 128 #define WLAN_AUTH_CHALLENGE_LEN 128 @@ -1072,6 +1073,10 @@ enum ieee80211_statuscode { WLAN_STATUS_NO_DIRECT_LINK = 48, WLAN_STATUS_STA_NOT_PRESENT = 49, WLAN_STATUS_STA_NOT_QSTA = 50, + /* 802.11s */ + WLAN_STATUS_ANTI_CLOG_REQUIRED = 76, + WLAN_STATUS_FCG_NOT_SUPP = 78, + WLAN_STATUS_STA_NO_TBTT = 78, }; @@ -1112,6 +1117,22 @@ enum ieee80211_reasoncode { WLAN_REASON_QSTA_REQUIRE_SETUP = 38, WLAN_REASON_QSTA_TIMEOUT = 39, WLAN_REASON_QSTA_CIPHER_NOT_SUPP = 45, + /* 802.11s */ + WLAN_REASON_MESH_PEER_CANCELED = 52, + WLAN_REASON_MESH_MAX_PEERS = 53, + WLAN_REASON_MESH_CONFIG = 54, + WLAN_REASON_MESH_CLOSE = 55, + WLAN_REASON_MESH_MAX_RETRIES = 56, + WLAN_REASON_MESH_CONFIRM_TIMEOUT = 57, + WLAN_REASON_MESH_INVALID_GTK = 58, + WLAN_REASON_MESH_INCONSISTENT_PARAM = 59, + WLAN_REASON_MESH_INVALID_SECURITY = 60, + WLAN_REASON_MESH_PATH_ERROR = 61, + WLAN_REASON_MESH_PATH_NOFORWARD = 62, + WLAN_REASON_MESH_PATH_DEST_UNREACHABLE = 63, + WLAN_REASON_MAC_EXISTS_IN_MBSS = 64, + WLAN_REASON_MESH_CHAN_REGULATORY = 65, + WLAN_REASON_MESH_CHAN = 66, }; @@ -1139,20 +1160,33 @@ enum ieee80211_eid { WLAN_EID_TS_DELAY = 43, WLAN_EID_TCLAS_PROCESSING = 44, WLAN_EID_QOS_CAPA = 46, - /* 802.11s - * - * All mesh EID numbers are pending IEEE 802.11 ANA approval. - * The numbers have been incremented from those suggested in - * 802.11s/D2.0 so that MESH_CONFIG does not conflict with - * EXT_SUPP_RATES. + /* 802.11s */ + WLAN_EID_MESH_CONFIG = 113, + WLAN_EID_MESH_ID = 114, + WLAN_EID_LINK_METRIC_REPORT = 115, + WLAN_EID_CONGESTION_NOTIFICATION = 116, + /* Note that the Peer Link IE has been replaced with the similar + * Peer Management IE. We will keep the former definition until mesh + * code is changed to comply with latest 802.11s drafts. */ - WLAN_EID_MESH_CONFIG = 51, - WLAN_EID_MESH_ID = 52, - WLAN_EID_PEER_LINK = 55, - WLAN_EID_PREQ = 68, - WLAN_EID_PREP = 69, - WLAN_EID_PERR = 70, - WLAN_EID_RANN = 49, /* compatible with FreeBSD */ + WLAN_EID_PEER_LINK = 55, /* no longer in 802.11s drafts */ + WLAN_EID_PEER_MGMT = 117, + WLAN_EID_CHAN_SWITCH_PARAM = 118, + WLAN_EID_MESH_AWAKE_WINDOW = 119, + WLAN_EID_BEACON_TIMING = 120, + WLAN_EID_MCCAOP_SETUP_REQ = 121, + WLAN_EID_MCCAOP_SETUP_RESP = 122, + WLAN_EID_MCCAOP_ADVERT = 123, + WLAN_EID_MCCAOP_TEARDOWN = 124, + WLAN_EID_GANN = 125, + WLAN_EID_RANN = 126, + WLAN_EID_PREQ = 130, + WLAN_EID_PREP = 131, + WLAN_EID_PERR = 132, + WLAN_EID_PXU = 137, + WLAN_EID_PXUC = 138, + WLAN_EID_AUTH_MESH_PEER_EXCH = 139, + WLAN_EID_MIC = 140, WLAN_EID_PWR_CONSTRAINT = 32, WLAN_EID_PWR_CAPABILITY = 33, @@ -1211,9 +1245,14 @@ enum ieee80211_category { WLAN_CATEGORY_HT = 7, WLAN_CATEGORY_SA_QUERY = 8, WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION = 9, + WLAN_CATEGORY_MESH_ACTION = 13, + WLAN_CATEGORY_MULTIHOP_ACTION = 14, + WLAN_CATEGORY_SELF_PROTECTED = 15, WLAN_CATEGORY_WMM = 17, - WLAN_CATEGORY_MESH_PLINK = 30, /* Pending ANA approval */ - WLAN_CATEGORY_MESH_PATH_SEL = 32, /* Pending ANA approval */ + /* TODO: remove MESH_PLINK and MESH_PATH_SEL after */ + /* mesh is updated to current 802.11s draft */ + WLAN_CATEGORY_MESH_PLINK = 30, + WLAN_CATEGORY_MESH_PATH_SEL = 32, WLAN_CATEGORY_VENDOR_SPECIFIC_PROTECTED = 126, WLAN_CATEGORY_VENDOR_SPECIFIC = 127, }; @@ -1351,6 +1390,8 @@ enum ieee80211_sa_query_action { /* AKM suite selectors */ #define WLAN_AKM_SUITE_8021X 0x000FAC01 #define WLAN_AKM_SUITE_PSK 0x000FAC02 +#define WLAN_AKM_SUITE_SAE 0x000FAC08 +#define WLAN_AKM_SUITE_FT_OVER_SAE 0x000FAC09 #define WLAN_MAX_KEY_LEN 32 -- cgit v0.10.2 From a23c22080345f1748a933f32736986ff11f44d60 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Sat, 9 Oct 2010 13:33:16 +0200 Subject: rt2x00: Shortcut link state updates when not operating as STA Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c index 4d534e9..46836f8 100644 --- a/drivers/net/wireless/rt2x00/rt2x00link.c +++ b/drivers/net/wireless/rt2x00/rt2x00link.c @@ -236,6 +236,12 @@ void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev, struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; /* + * No need to update the stats for !=STA interfaces + */ + if (!rt2x00dev->intf_sta_count) + return; + + /* * Frame was received successfully since non-succesfull * frames would have been dropped by the hardware. */ -- cgit v0.10.2 From 546adf294e85ca0dcd9c052294ef35b83a6ab2f4 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Sat, 9 Oct 2010 13:33:43 +0200 Subject: rt2x00: Optimize unmapping of skbs Since no skb will be mapped for RX and TX at the same time we can simply shortcut the check for SKBDESC_DMA_MAPPED_TX. Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 6d41599..4436ff7 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -115,9 +115,7 @@ void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb) dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, skb->len, DMA_FROM_DEVICE); skbdesc->flags &= ~SKBDESC_DMA_MAPPED_RX; - } - - if (skbdesc->flags & SKBDESC_DMA_MAPPED_TX) { + } else if (skbdesc->flags & SKBDESC_DMA_MAPPED_TX) { dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, skb->len, DMA_TO_DEVICE); skbdesc->flags &= ~SKBDESC_DMA_MAPPED_TX; -- cgit v0.10.2 From ff6133becae9ae1657fcff339a160a21448fa11c Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Sat, 9 Oct 2010 13:34:11 +0200 Subject: rt2x00: Use proper type for rxwi_w2 in rt2800_agc_to_rssi Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 7f040b0..b9433fe 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -499,7 +499,7 @@ void rt2800_write_tx_data(struct queue_entry *entry, } EXPORT_SYMBOL_GPL(rt2800_write_tx_data); -static int rt2800_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxwi_w2) +static int rt2800_agc_to_rssi(struct rt2x00_dev *rt2x00dev, u32 rxwi_w2) { int rssi0 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI0); int rssi1 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI1); -- cgit v0.10.2 From c6084d5fa2e70a436ab944066146de01819f5493 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Sat, 9 Oct 2010 13:34:43 +0200 Subject: rt2x00: Use unlikely for error case in rt2x00queue_write_tx_frame This is an error condition that is not supposed to happen. Hence, it is safe to add unlikely to this check. Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 4436ff7..83630f1 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -489,7 +489,8 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, if (unlikely(rt2x00queue_full(queue))) return -ENOBUFS; - if (test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) { + if (unlikely(test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, + &entry->flags))) { ERROR(queue->rt2x00dev, "Arrived at non-free entry in the non-full queue %d.\n" "Please file bug report to %s.\n", -- cgit v0.10.2 From 74374725cdf466629fd401a81b3a04e4cdb0815f Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Sat, 9 Oct 2010 13:35:13 +0200 Subject: rt2x00: Remove superfluous initialization of qidx There is no need to initialize qidx to zero as it will ever be overwritten by the correct value. Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 85a134c..cc4e17c 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -573,7 +573,7 @@ static void rt2800pci_kick_tx_queue(struct data_queue *queue) { struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); - unsigned int qidx = 0; + unsigned int qidx; if (queue->qid == QID_MGMT) qidx = 5; -- cgit v0.10.2 From 12eec2cc0d5eacd8287646585dc88ab558d4866d Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Sat, 9 Oct 2010 13:35:48 +0200 Subject: rt2x00: Fix tx status handling in rt2800pci The patches "rt2x00: Improve TX status entry validation" and "rt2x00: rework tx status handling in rt2800pci" together were causing problems with tx status processing in rt2800pci: phy1 -> rt2800pci_txdone: Warning - Got TX status for an empty queue 3, dropping phy1 -> rt2800pci_txdone: Warning - Got TX status for an unavailable queue 7, dropping Fix this by using the correct field definition for getting the QID out of the tx status report. Reported-by: Luis Correia Signed-off-by: Helmut Schaa Tested-by: Luis Correia Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index cc4e17c..b267395 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -676,7 +676,7 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev) break; } - qid = rt2x00_get_field32(status, TX_STA_FIFO_PID_TYPE) - 1; + qid = rt2x00_get_field32(status, TX_STA_FIFO_PID_QUEUE); if (qid >= QID_RX) { /* * Unknown queue, this shouldn't happen. Just drop -- cgit v0.10.2 From c8a16c68ef4eb7817e41759c7105678ebc155377 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 9 Oct 2010 21:37:11 +0200 Subject: carl9170: common error path for bad frames This patch replaces several identical frame drop paths with a single shared rx frame error handler. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c index 671dbc4..31287e0 100644 --- a/drivers/net/wireless/ath/carl9170/rx.c +++ b/drivers/net/wireless/ath/carl9170/rx.c @@ -598,18 +598,14 @@ static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) if (!IS_STARTED(ar)) return; - if (unlikely(len < sizeof(*mac))) { - ar->rx_dropped++; - return; - } + if (unlikely(len < sizeof(*mac))) + goto drop; mpdu_len = len - sizeof(*mac); mac = (void *)(buf + mpdu_len); - if (unlikely(mac->error & AR9170_RX_ERROR_FATAL)) { - ar->rx_dropped++; - return; - } + if (unlikely(mac->error & AR9170_RX_ERROR_FATAL)) + goto drop; switch (mac->status & AR9170_RX_STATUS_MPDU) { case AR9170_RX_STATUS_MPDU_FIRST: @@ -638,8 +634,7 @@ static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) "is clipped.\n"); } - ar->rx_dropped++; - return; + goto drop; } break; @@ -659,8 +654,7 @@ static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) "is clipped.\n"); } - ar->rx_dropped++; - return; + goto drop; } case AR9170_RX_STATUS_MPDU_MIDDLE: @@ -672,8 +666,7 @@ static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) wiphy_err(ar->hw->wiphy, "rx stream does not start " "with a first_mpdu frame tag.\n"); - ar->rx_dropped++; - return; + goto drop; } head = &ar->rx_plcp; @@ -696,16 +689,12 @@ static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) } /* FC + DU + RA + FCS */ - if (unlikely(mpdu_len < (2 + 2 + 6 + FCS_LEN))) { - ar->rx_dropped++; - return; - } + if (unlikely(mpdu_len < (2 + 2 + ETH_ALEN + FCS_LEN))) + goto drop; memset(&status, 0, sizeof(status)); - if (unlikely(carl9170_rx_mac_status(ar, head, mac, &status))) { - ar->rx_dropped++; - return; - } + if (unlikely(carl9170_rx_mac_status(ar, head, mac, &status))) + goto drop; if (phy) carl9170_rx_phy_status(ar, phy, &status); @@ -713,12 +702,15 @@ static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) carl9170_ps_beacon(ar, buf, mpdu_len); skb = carl9170_rx_copy_data(buf, mpdu_len); - if (likely(skb)) { - memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); - ieee80211_rx(ar->hw, skb); - } else { - ar->rx_dropped++; - } + if (!skb) + goto drop; + + memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); + ieee80211_rx(ar->hw, skb); + return; + +drop: + ar->rx_dropped++; } static void carl9170_rx_untie_cmds(struct ar9170 *ar, const u8 *respbuf, -- cgit v0.10.2 From 9f59f3c694c184c69e0be7d0fd0829bcb61b0429 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 9 Oct 2010 22:23:37 +0200 Subject: carl9170: remove stale rx error path The total/fatal error bit was erroneously prefixed with AR9170_RX_ERROR instead of AR9170_RX_STATUS. Luckily, the hardware specification confirmed that the 0x80 flag will never be set for mac->error. So, it was always just a dead branch. This patch also imports the latest version of shared wlan.h header from the firmware git. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c index 31287e0..256dd42 100644 --- a/drivers/net/wireless/ath/carl9170/rx.c +++ b/drivers/net/wireless/ath/carl9170/rx.c @@ -604,9 +604,6 @@ static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) mpdu_len = len - sizeof(*mac); mac = (void *)(buf + mpdu_len); - if (unlikely(mac->error & AR9170_RX_ERROR_FATAL)) - goto drop; - switch (mac->status & AR9170_RX_STATUS_MPDU) { case AR9170_RX_STATUS_MPDU_FIRST: /* Aggregated MPDUs start with an PLCP header */ diff --git a/drivers/net/wireless/ath/carl9170/wlan.h b/drivers/net/wireless/ath/carl9170/wlan.h index 48ead22..24d63b5 100644 --- a/drivers/net/wireless/ath/carl9170/wlan.h +++ b/drivers/net/wireless/ath/carl9170/wlan.h @@ -74,6 +74,9 @@ #define AR9170_RX_STATUS_MPDU_MIDDLE 0x30 #define AR9170_RX_STATUS_MPDU_LAST 0x10 +#define AR9170_RX_STATUS_CONT_AGGR 0x40 +#define AR9170_RX_STATUS_TOTAL_ERROR 0x80 + #define AR9170_RX_ERROR_RXTO 0x01 #define AR9170_RX_ERROR_OVERRUN 0x02 #define AR9170_RX_ERROR_DECRYPT 0x04 @@ -81,7 +84,6 @@ #define AR9170_RX_ERROR_WRONG_RA 0x10 #define AR9170_RX_ERROR_PLCP 0x20 #define AR9170_RX_ERROR_MMIC 0x40 -#define AR9170_RX_ERROR_FATAL 0x80 /* these are either-or */ #define AR9170_TX_MAC_PROT_RTS 0x0001 @@ -329,13 +331,15 @@ struct _carl9170_tx_superframe { #define CARL9170_TX_SUPERDESC_LEN 24 #define AR9170_TX_HWDESC_LEN 8 -#define AR9170_TX_SUPERFRAME_LEN (CARL9170_TX_HWDESC_LEN + \ - AR9170_TX_SUPERDESC_LEN) +#define CARL9170_TX_SUPERFRAME_LEN (CARL9170_TX_SUPERDESC_LEN + \ + AR9170_TX_HWDESC_LEN) struct ar9170_rx_head { u8 plcp[12]; } __packed; +#define AR9170_RX_HEAD_LEN 12 + struct ar9170_rx_phystatus { union { struct { @@ -350,12 +354,16 @@ struct ar9170_rx_phystatus { u8 phy_err; } __packed; +#define AR9170_RX_PHYSTATUS_LEN 20 + struct ar9170_rx_macstatus { u8 SAidx, DAidx; u8 error; u8 status; } __packed; +#define AR9170_RX_MACSTATUS_LEN 4 + struct ar9170_rx_frame_single { struct ar9170_rx_head phy_head; struct ieee80211_hdr i3e; -- cgit v0.10.2 From 8f236d1bef659ca69c912536a69b3031e5ba3269 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 10 Oct 2010 01:15:07 +0200 Subject: carl9170: A-MPDU frame type filter In the past, carl9170 has been plagued by mysterious ghosts. e.g.: wlan4: deauthenticated from 02:04:d8:3c:ac:c1 (Reason: 0) Apparently, the AP sent us a bogus deauthentication notification. But upon closer inspection the "management frame" turned out to be a corrupted scrap of an unsuccessful A-MPDU. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c index 256dd42..939a0e9 100644 --- a/drivers/net/wireless/ath/carl9170/rx.c +++ b/drivers/net/wireless/ath/carl9170/rx.c @@ -576,6 +576,41 @@ static void carl9170_ps_beacon(struct ar9170 *ar, void *data, unsigned int len) } } +static bool carl9170_ampdu_check(struct ar9170 *ar, u8 *buf, u8 ms) +{ + __le16 fc; + + if ((ms & AR9170_RX_STATUS_MPDU) == AR9170_RX_STATUS_MPDU_SINGLE) { + /* + * This frame is not part of an aMPDU. + * Therefore it is not subjected to any + * of the following content restrictions. + */ + return true; + } + + /* + * "802.11n - 7.4a.3 A-MPDU contents" describes in which contexts + * certain frame types can be part of an aMPDU. + * + * In order to keep the processing cost down, I opted for a + * stateless filter solely based on the frame control field. + */ + + fc = ((struct ieee80211_hdr *)buf)->frame_control; + if (ieee80211_is_data_qos(fc) && ieee80211_is_data_present(fc)) + return true; + + if (ieee80211_is_ack(fc) || ieee80211_is_back(fc) || + ieee80211_is_back_req(fc)) + return true; + + if (ieee80211_is_action(fc)) + return true; + + return false; +} + /* * If the frame alignment is right (or the kernel has * CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), and there @@ -594,6 +629,7 @@ static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) struct ieee80211_rx_status status; struct sk_buff *skb; int mpdu_len; + u8 mac_status; if (!IS_STARTED(ar)) return; @@ -604,7 +640,8 @@ static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) mpdu_len = len - sizeof(*mac); mac = (void *)(buf + mpdu_len); - switch (mac->status & AR9170_RX_STATUS_MPDU) { + mac_status = mac->status; + switch (mac_status & AR9170_RX_STATUS_MPDU) { case AR9170_RX_STATUS_MPDU_FIRST: /* Aggregated MPDUs start with an PLCP header */ if (likely(mpdu_len >= sizeof(struct ar9170_rx_head))) { @@ -693,6 +730,9 @@ static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) if (unlikely(carl9170_rx_mac_status(ar, head, mac, &status))) goto drop; + if (!carl9170_ampdu_check(ar, buf, mac_status)) + goto drop; + if (phy) carl9170_rx_phy_status(ar, phy, &status); -- cgit v0.10.2 From f03ee1ec73d8cad07b0ef5ba6106a9fc4d179ecb Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Sun, 10 Oct 2010 11:28:31 +0300 Subject: wl1251: create a copy of wl12xx_80211.h for wl1251 In preparation of moving wl1251 out from drivers/net/wireless/wl12xx create a separate copy of wl12xx_80211.h. This file should not even exist, we should instead use generic ieee80211 definitions. This will be fixed in the future so that the file can be removed. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl1251/wl12xx_80211.h b/drivers/net/wireless/wl1251/wl12xx_80211.h new file mode 100644 index 0000000..1846280 --- /dev/null +++ b/drivers/net/wireless/wl1251/wl12xx_80211.h @@ -0,0 +1,156 @@ +#ifndef __WL12XX_80211_H__ +#define __WL12XX_80211_H__ + +#include /* ETH_ALEN */ + +/* RATES */ +#define IEEE80211_CCK_RATE_1MB 0x02 +#define IEEE80211_CCK_RATE_2MB 0x04 +#define IEEE80211_CCK_RATE_5MB 0x0B +#define IEEE80211_CCK_RATE_11MB 0x16 +#define IEEE80211_OFDM_RATE_6MB 0x0C +#define IEEE80211_OFDM_RATE_9MB 0x12 +#define IEEE80211_OFDM_RATE_12MB 0x18 +#define IEEE80211_OFDM_RATE_18MB 0x24 +#define IEEE80211_OFDM_RATE_24MB 0x30 +#define IEEE80211_OFDM_RATE_36MB 0x48 +#define IEEE80211_OFDM_RATE_48MB 0x60 +#define IEEE80211_OFDM_RATE_54MB 0x6C +#define IEEE80211_BASIC_RATE_MASK 0x80 + +#define IEEE80211_CCK_RATE_1MB_MASK (1<<0) +#define IEEE80211_CCK_RATE_2MB_MASK (1<<1) +#define IEEE80211_CCK_RATE_5MB_MASK (1<<2) +#define IEEE80211_CCK_RATE_11MB_MASK (1<<3) +#define IEEE80211_OFDM_RATE_6MB_MASK (1<<4) +#define IEEE80211_OFDM_RATE_9MB_MASK (1<<5) +#define IEEE80211_OFDM_RATE_12MB_MASK (1<<6) +#define IEEE80211_OFDM_RATE_18MB_MASK (1<<7) +#define IEEE80211_OFDM_RATE_24MB_MASK (1<<8) +#define IEEE80211_OFDM_RATE_36MB_MASK (1<<9) +#define IEEE80211_OFDM_RATE_48MB_MASK (1<<10) +#define IEEE80211_OFDM_RATE_54MB_MASK (1<<11) + +#define IEEE80211_CCK_RATES_MASK 0x0000000F +#define IEEE80211_CCK_BASIC_RATES_MASK (IEEE80211_CCK_RATE_1MB_MASK | \ + IEEE80211_CCK_RATE_2MB_MASK) +#define IEEE80211_CCK_DEFAULT_RATES_MASK (IEEE80211_CCK_BASIC_RATES_MASK | \ + IEEE80211_CCK_RATE_5MB_MASK | \ + IEEE80211_CCK_RATE_11MB_MASK) + +#define IEEE80211_OFDM_RATES_MASK 0x00000FF0 +#define IEEE80211_OFDM_BASIC_RATES_MASK (IEEE80211_OFDM_RATE_6MB_MASK | \ + IEEE80211_OFDM_RATE_12MB_MASK | \ + IEEE80211_OFDM_RATE_24MB_MASK) +#define IEEE80211_OFDM_DEFAULT_RATES_MASK (IEEE80211_OFDM_BASIC_RATES_MASK | \ + IEEE80211_OFDM_RATE_9MB_MASK | \ + IEEE80211_OFDM_RATE_18MB_MASK | \ + IEEE80211_OFDM_RATE_36MB_MASK | \ + IEEE80211_OFDM_RATE_48MB_MASK | \ + IEEE80211_OFDM_RATE_54MB_MASK) +#define IEEE80211_DEFAULT_RATES_MASK (IEEE80211_OFDM_DEFAULT_RATES_MASK | \ + IEEE80211_CCK_DEFAULT_RATES_MASK) + + +/* This really should be 8, but not for our firmware */ +#define MAX_SUPPORTED_RATES 32 +#define COUNTRY_STRING_LEN 3 +#define MAX_COUNTRY_TRIPLETS 32 + +/* Headers */ +struct ieee80211_header { + __le16 frame_ctl; + __le16 duration_id; + u8 da[ETH_ALEN]; + u8 sa[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + __le16 seq_ctl; + u8 payload[0]; +} __packed; + +struct wl12xx_ie_header { + u8 id; + u8 len; +} __packed; + +/* IEs */ + +struct wl12xx_ie_ssid { + struct wl12xx_ie_header header; + char ssid[IW_ESSID_MAX_SIZE]; +} __packed; + +struct wl12xx_ie_rates { + struct wl12xx_ie_header header; + u8 rates[MAX_SUPPORTED_RATES]; +} __packed; + +struct wl12xx_ie_ds_params { + struct wl12xx_ie_header header; + u8 channel; +} __packed; + +struct country_triplet { + u8 channel; + u8 num_channels; + u8 max_tx_power; +} __packed; + +struct wl12xx_ie_country { + struct wl12xx_ie_header header; + u8 country_string[COUNTRY_STRING_LEN]; + struct country_triplet triplets[MAX_COUNTRY_TRIPLETS]; +} __packed; + + +/* Templates */ + +struct wl12xx_beacon_template { + struct ieee80211_header header; + __le32 time_stamp[2]; + __le16 beacon_interval; + __le16 capability; + struct wl12xx_ie_ssid ssid; + struct wl12xx_ie_rates rates; + struct wl12xx_ie_rates ext_rates; + struct wl12xx_ie_ds_params ds_params; + struct wl12xx_ie_country country; +} __packed; + +struct wl12xx_null_data_template { + struct ieee80211_header header; +} __packed; + +struct wl12xx_ps_poll_template { + __le16 fc; + __le16 aid; + u8 bssid[ETH_ALEN]; + u8 ta[ETH_ALEN]; +} __packed; + +struct wl12xx_qos_null_data_template { + struct ieee80211_header header; + __le16 qos_ctl; +} __packed; + +struct wl12xx_probe_req_template { + struct ieee80211_header header; + struct wl12xx_ie_ssid ssid; + struct wl12xx_ie_rates rates; + struct wl12xx_ie_rates ext_rates; +} __packed; + + +struct wl12xx_probe_resp_template { + struct ieee80211_header header; + __le32 time_stamp[2]; + __le16 beacon_interval; + __le16 capability; + struct wl12xx_ie_ssid ssid; + struct wl12xx_ie_rates rates; + struct wl12xx_ie_rates ext_rates; + struct wl12xx_ie_ds_params ds_params; + struct wl12xx_ie_country country; +} __packed; + +#endif -- cgit v0.10.2 From 9bc6772e15d25f58c1be638031280e04514287d4 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Sun, 10 Oct 2010 11:28:32 +0300 Subject: wl1251: move to it's own directory wl1271 driver is under heavy development but on the other hand the older wl1251 driver is currently considered more as a legacy driver. To make it easier to develop wl1271 features move wl1251 to it's own directory, drivers/net/wireless/wl1251. There are no functional changes, only moving of files. One regression is that Kconfig won't be updated automatically and user needs to enable wl1251 manually with an older config file. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 174e344..4de4410 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -279,6 +279,7 @@ source "drivers/net/wireless/libertas/Kconfig" source "drivers/net/wireless/orinoco/Kconfig" source "drivers/net/wireless/p54/Kconfig" source "drivers/net/wireless/rt2x00/Kconfig" +source "drivers/net/wireless/wl1251/Kconfig" source "drivers/net/wireless/wl12xx/Kconfig" source "drivers/net/wireless/zd1211rw/Kconfig" diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index a13a602..06f8ca2 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -49,6 +49,7 @@ obj-$(CONFIG_ATH_COMMON) += ath/ obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o +obj-$(CONFIG_WL1251) += wl1251/ obj-$(CONFIG_WL12XX) += wl12xx/ obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx/ diff --git a/drivers/net/wireless/wl1251/Kconfig b/drivers/net/wireless/wl1251/Kconfig new file mode 100644 index 0000000..1fb6584 --- /dev/null +++ b/drivers/net/wireless/wl1251/Kconfig @@ -0,0 +1,33 @@ +menuconfig WL1251 + tristate "TI wl1251 driver support" + depends on MAC80211 && EXPERIMENTAL && GENERIC_HARDIRQS + select FW_LOADER + select CRC7 + ---help--- + This will enable TI wl1251 driver support. The drivers make + use of the mac80211 stack. + + If you choose to build a module, it'll be called wl1251. Say + N if unsure. + +config WL1251_SPI + tristate "TI wl1251 SPI support" + depends on WL1251 && SPI_MASTER + ---help--- + This module adds support for the SPI interface of adapters using + TI wl1251 chipset. Select this if your platform is using + the SPI bus. + + If you choose to build a module, it'll be called wl1251_spi. + Say N if unsure. + +config WL1251_SDIO + tristate "TI wl1251 SDIO support" + depends on WL1251 && MMC + ---help--- + This module adds support for the SDIO interface of adapters using + TI wl1251 chipset. Select this if your platform is using + the SDIO bus. + + If you choose to build a module, it'll be called + wl1251_sdio. Say N if unsure. diff --git a/drivers/net/wireless/wl1251/Makefile b/drivers/net/wireless/wl1251/Makefile new file mode 100644 index 0000000..4fe2468 --- /dev/null +++ b/drivers/net/wireless/wl1251/Makefile @@ -0,0 +1,6 @@ +wl1251-objs = main.o event.o tx.o rx.o ps.o cmd.o \ + acx.o boot.o init.o debugfs.o io.o + +obj-$(CONFIG_WL1251) += wl1251.o +obj-$(CONFIG_WL1251_SPI) += spi.o +obj-$(CONFIG_WL1251_SDIO) += sdio.o diff --git a/drivers/net/wireless/wl1251/acx.c b/drivers/net/wireless/wl1251/acx.c new file mode 100644 index 0000000..64a0214 --- /dev/null +++ b/drivers/net/wireless/wl1251/acx.c @@ -0,0 +1,1048 @@ +#include "acx.h" + +#include +#include +#include + +#include "wl1251.h" +#include "reg.h" +#include "cmd.h" +#include "ps.h" + +int wl1251_acx_frame_rates(struct wl1251 *wl, u8 ctrl_rate, u8 ctrl_mod, + u8 mgt_rate, u8 mgt_mod) +{ + struct acx_fw_gen_frame_rates *rates; + int ret; + + wl1251_debug(DEBUG_ACX, "acx frame rates"); + + rates = kzalloc(sizeof(*rates), GFP_KERNEL); + if (!rates) { + ret = -ENOMEM; + goto out; + } + + rates->tx_ctrl_frame_rate = ctrl_rate; + rates->tx_ctrl_frame_mod = ctrl_mod; + rates->tx_mgt_frame_rate = mgt_rate; + rates->tx_mgt_frame_mod = mgt_mod; + + ret = wl1251_cmd_configure(wl, ACX_FW_GEN_FRAME_RATES, + rates, sizeof(*rates)); + if (ret < 0) { + wl1251_error("Failed to set FW rates and modulation"); + goto out; + } + +out: + kfree(rates); + return ret; +} + + +int wl1251_acx_station_id(struct wl1251 *wl) +{ + struct acx_dot11_station_id *mac; + int ret, i; + + wl1251_debug(DEBUG_ACX, "acx dot11_station_id"); + + mac = kzalloc(sizeof(*mac), GFP_KERNEL); + if (!mac) { + ret = -ENOMEM; + goto out; + } + + for (i = 0; i < ETH_ALEN; i++) + mac->mac[i] = wl->mac_addr[ETH_ALEN - 1 - i]; + + ret = wl1251_cmd_configure(wl, DOT11_STATION_ID, mac, sizeof(*mac)); + if (ret < 0) + goto out; + +out: + kfree(mac); + return ret; +} + +int wl1251_acx_default_key(struct wl1251 *wl, u8 key_id) +{ + struct acx_dot11_default_key *default_key; + int ret; + + wl1251_debug(DEBUG_ACX, "acx dot11_default_key (%d)", key_id); + + default_key = kzalloc(sizeof(*default_key), GFP_KERNEL); + if (!default_key) { + ret = -ENOMEM; + goto out; + } + + default_key->id = key_id; + + ret = wl1251_cmd_configure(wl, DOT11_DEFAULT_KEY, + default_key, sizeof(*default_key)); + if (ret < 0) { + wl1251_error("Couldn't set default key"); + goto out; + } + + wl->default_key = key_id; + +out: + kfree(default_key); + return ret; +} + +int wl1251_acx_wake_up_conditions(struct wl1251 *wl, u8 wake_up_event, + u8 listen_interval) +{ + struct acx_wake_up_condition *wake_up; + int ret; + + wl1251_debug(DEBUG_ACX, "acx wake up conditions"); + + wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL); + if (!wake_up) { + ret = -ENOMEM; + goto out; + } + + wake_up->wake_up_event = wake_up_event; + wake_up->listen_interval = listen_interval; + + ret = wl1251_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS, + wake_up, sizeof(*wake_up)); + if (ret < 0) { + wl1251_warning("could not set wake up conditions: %d", ret); + goto out; + } + +out: + kfree(wake_up); + return ret; +} + +int wl1251_acx_sleep_auth(struct wl1251 *wl, u8 sleep_auth) +{ + struct acx_sleep_auth *auth; + int ret; + + wl1251_debug(DEBUG_ACX, "acx sleep auth"); + + auth = kzalloc(sizeof(*auth), GFP_KERNEL); + if (!auth) { + ret = -ENOMEM; + goto out; + } + + auth->sleep_auth = sleep_auth; + + ret = wl1251_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth)); + if (ret < 0) + return ret; + +out: + kfree(auth); + return ret; +} + +int wl1251_acx_fw_version(struct wl1251 *wl, char *buf, size_t len) +{ + struct acx_revision *rev; + int ret; + + wl1251_debug(DEBUG_ACX, "acx fw rev"); + + rev = kzalloc(sizeof(*rev), GFP_KERNEL); + if (!rev) { + ret = -ENOMEM; + goto out; + } + + ret = wl1251_cmd_interrogate(wl, ACX_FW_REV, rev, sizeof(*rev)); + if (ret < 0) { + wl1251_warning("ACX_FW_REV interrogate failed"); + goto out; + } + + /* be careful with the buffer sizes */ + strncpy(buf, rev->fw_version, min(len, sizeof(rev->fw_version))); + + /* + * if the firmware version string is exactly + * sizeof(rev->fw_version) long or fw_len is less than + * sizeof(rev->fw_version) it won't be null terminated + */ + buf[min(len, sizeof(rev->fw_version)) - 1] = '\0'; + +out: + kfree(rev); + return ret; +} + +int wl1251_acx_tx_power(struct wl1251 *wl, int power) +{ + struct acx_current_tx_power *acx; + int ret; + + wl1251_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr"); + + if (power < 0 || power > 25) + return -EINVAL; + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->current_tx_power = power * 10; + + ret = wl1251_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx)); + if (ret < 0) { + wl1251_warning("configure of tx power failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1251_acx_feature_cfg(struct wl1251 *wl) +{ + struct acx_feature_config *feature; + int ret; + + wl1251_debug(DEBUG_ACX, "acx feature cfg"); + + feature = kzalloc(sizeof(*feature), GFP_KERNEL); + if (!feature) { + ret = -ENOMEM; + goto out; + } + + /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */ + feature->data_flow_options = 0; + feature->options = 0; + + ret = wl1251_cmd_configure(wl, ACX_FEATURE_CFG, + feature, sizeof(*feature)); + if (ret < 0) { + wl1251_error("Couldn't set HW encryption"); + goto out; + } + +out: + kfree(feature); + return ret; +} + +int wl1251_acx_mem_map(struct wl1251 *wl, struct acx_header *mem_map, + size_t len) +{ + int ret; + + wl1251_debug(DEBUG_ACX, "acx mem map"); + + ret = wl1251_cmd_interrogate(wl, ACX_MEM_MAP, mem_map, len); + if (ret < 0) + return ret; + + return 0; +} + +int wl1251_acx_data_path_params(struct wl1251 *wl, + struct acx_data_path_params_resp *resp) +{ + struct acx_data_path_params *params; + int ret; + + wl1251_debug(DEBUG_ACX, "acx data path params"); + + params = kzalloc(sizeof(*params), GFP_KERNEL); + if (!params) { + ret = -ENOMEM; + goto out; + } + + params->rx_packet_ring_chunk_size = DP_RX_PACKET_RING_CHUNK_SIZE; + params->tx_packet_ring_chunk_size = DP_TX_PACKET_RING_CHUNK_SIZE; + + params->rx_packet_ring_chunk_num = DP_RX_PACKET_RING_CHUNK_NUM; + params->tx_packet_ring_chunk_num = DP_TX_PACKET_RING_CHUNK_NUM; + + params->tx_complete_threshold = 1; + + params->tx_complete_ring_depth = FW_TX_CMPLT_BLOCK_SIZE; + + params->tx_complete_timeout = DP_TX_COMPLETE_TIME_OUT; + + ret = wl1251_cmd_configure(wl, ACX_DATA_PATH_PARAMS, + params, sizeof(*params)); + if (ret < 0) + goto out; + + /* FIXME: shouldn't this be ACX_DATA_PATH_RESP_PARAMS? */ + ret = wl1251_cmd_interrogate(wl, ACX_DATA_PATH_PARAMS, + resp, sizeof(*resp)); + + if (ret < 0) { + wl1251_warning("failed to read data path parameters: %d", ret); + goto out; + } else if (resp->header.cmd.status != CMD_STATUS_SUCCESS) { + wl1251_warning("data path parameter acx status failed"); + ret = -EIO; + goto out; + } + +out: + kfree(params); + return ret; +} + +int wl1251_acx_rx_msdu_life_time(struct wl1251 *wl, u32 life_time) +{ + struct acx_rx_msdu_lifetime *acx; + int ret; + + wl1251_debug(DEBUG_ACX, "acx rx msdu life time"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->lifetime = life_time; + ret = wl1251_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME, + acx, sizeof(*acx)); + if (ret < 0) { + wl1251_warning("failed to set rx msdu life time: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1251_acx_rx_config(struct wl1251 *wl, u32 config, u32 filter) +{ + struct acx_rx_config *rx_config; + int ret; + + wl1251_debug(DEBUG_ACX, "acx rx config"); + + rx_config = kzalloc(sizeof(*rx_config), GFP_KERNEL); + if (!rx_config) { + ret = -ENOMEM; + goto out; + } + + rx_config->config_options = config; + rx_config->filter_options = filter; + + ret = wl1251_cmd_configure(wl, ACX_RX_CFG, + rx_config, sizeof(*rx_config)); + if (ret < 0) { + wl1251_warning("failed to set rx config: %d", ret); + goto out; + } + +out: + kfree(rx_config); + return ret; +} + +int wl1251_acx_pd_threshold(struct wl1251 *wl) +{ + struct acx_packet_detection *pd; + int ret; + + wl1251_debug(DEBUG_ACX, "acx data pd threshold"); + + pd = kzalloc(sizeof(*pd), GFP_KERNEL); + if (!pd) { + ret = -ENOMEM; + goto out; + } + + /* FIXME: threshold value not set */ + + ret = wl1251_cmd_configure(wl, ACX_PD_THRESHOLD, pd, sizeof(*pd)); + if (ret < 0) { + wl1251_warning("failed to set pd threshold: %d", ret); + goto out; + } + +out: + kfree(pd); + return ret; +} + +int wl1251_acx_slot(struct wl1251 *wl, enum acx_slot_type slot_time) +{ + struct acx_slot *slot; + int ret; + + wl1251_debug(DEBUG_ACX, "acx slot"); + + slot = kzalloc(sizeof(*slot), GFP_KERNEL); + if (!slot) { + ret = -ENOMEM; + goto out; + } + + slot->wone_index = STATION_WONE_INDEX; + slot->slot_time = slot_time; + + ret = wl1251_cmd_configure(wl, ACX_SLOT, slot, sizeof(*slot)); + if (ret < 0) { + wl1251_warning("failed to set slot time: %d", ret); + goto out; + } + +out: + kfree(slot); + return ret; +} + +int wl1251_acx_group_address_tbl(struct wl1251 *wl) +{ + struct acx_dot11_grp_addr_tbl *acx; + int ret; + + wl1251_debug(DEBUG_ACX, "acx group address tbl"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + /* MAC filtering */ + acx->enabled = 0; + acx->num_groups = 0; + memset(acx->mac_table, 0, ADDRESS_GROUP_MAX_LEN); + + ret = wl1251_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL, + acx, sizeof(*acx)); + if (ret < 0) { + wl1251_warning("failed to set group addr table: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1251_acx_service_period_timeout(struct wl1251 *wl) +{ + struct acx_rx_timeout *rx_timeout; + int ret; + + rx_timeout = kzalloc(sizeof(*rx_timeout), GFP_KERNEL); + if (!rx_timeout) { + ret = -ENOMEM; + goto out; + } + + wl1251_debug(DEBUG_ACX, "acx service period timeout"); + + rx_timeout->ps_poll_timeout = RX_TIMEOUT_PS_POLL_DEF; + rx_timeout->upsd_timeout = RX_TIMEOUT_UPSD_DEF; + + ret = wl1251_cmd_configure(wl, ACX_SERVICE_PERIOD_TIMEOUT, + rx_timeout, sizeof(*rx_timeout)); + if (ret < 0) { + wl1251_warning("failed to set service period timeout: %d", + ret); + goto out; + } + +out: + kfree(rx_timeout); + return ret; +} + +int wl1251_acx_rts_threshold(struct wl1251 *wl, u16 rts_threshold) +{ + struct acx_rts_threshold *rts; + int ret; + + wl1251_debug(DEBUG_ACX, "acx rts threshold"); + + rts = kzalloc(sizeof(*rts), GFP_KERNEL); + if (!rts) { + ret = -ENOMEM; + goto out; + } + + rts->threshold = rts_threshold; + + ret = wl1251_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts)); + if (ret < 0) { + wl1251_warning("failed to set rts threshold: %d", ret); + goto out; + } + +out: + kfree(rts); + return ret; +} + +int wl1251_acx_beacon_filter_opt(struct wl1251 *wl, bool enable_filter) +{ + struct acx_beacon_filter_option *beacon_filter; + int ret; + + wl1251_debug(DEBUG_ACX, "acx beacon filter opt"); + + beacon_filter = kzalloc(sizeof(*beacon_filter), GFP_KERNEL); + if (!beacon_filter) { + ret = -ENOMEM; + goto out; + } + + beacon_filter->enable = enable_filter; + beacon_filter->max_num_beacons = 0; + + ret = wl1251_cmd_configure(wl, ACX_BEACON_FILTER_OPT, + beacon_filter, sizeof(*beacon_filter)); + if (ret < 0) { + wl1251_warning("failed to set beacon filter opt: %d", ret); + goto out; + } + +out: + kfree(beacon_filter); + return ret; +} + +int wl1251_acx_beacon_filter_table(struct wl1251 *wl) +{ + struct acx_beacon_filter_ie_table *ie_table; + int idx = 0; + int ret; + + wl1251_debug(DEBUG_ACX, "acx beacon filter table"); + + ie_table = kzalloc(sizeof(*ie_table), GFP_KERNEL); + if (!ie_table) { + ret = -ENOMEM; + goto out; + } + + /* configure default beacon pass-through rules */ + ie_table->num_ie = 1; + ie_table->table[idx++] = BEACON_FILTER_IE_ID_CHANNEL_SWITCH_ANN; + ie_table->table[idx++] = BEACON_RULE_PASS_ON_APPEARANCE; + + ret = wl1251_cmd_configure(wl, ACX_BEACON_FILTER_TABLE, + ie_table, sizeof(*ie_table)); + if (ret < 0) { + wl1251_warning("failed to set beacon filter table: %d", ret); + goto out; + } + +out: + kfree(ie_table); + return ret; +} + +int wl1251_acx_conn_monit_params(struct wl1251 *wl) +{ + struct acx_conn_monit_params *acx; + int ret; + + wl1251_debug(DEBUG_ACX, "acx connection monitor parameters"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->synch_fail_thold = SYNCH_FAIL_DEFAULT_THRESHOLD; + acx->bss_lose_timeout = NO_BEACON_DEFAULT_TIMEOUT; + + ret = wl1251_cmd_configure(wl, ACX_CONN_MONIT_PARAMS, + acx, sizeof(*acx)); + if (ret < 0) { + wl1251_warning("failed to set connection monitor " + "parameters: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1251_acx_sg_enable(struct wl1251 *wl) +{ + struct acx_bt_wlan_coex *pta; + int ret; + + wl1251_debug(DEBUG_ACX, "acx sg enable"); + + pta = kzalloc(sizeof(*pta), GFP_KERNEL); + if (!pta) { + ret = -ENOMEM; + goto out; + } + + pta->enable = SG_ENABLE; + + ret = wl1251_cmd_configure(wl, ACX_SG_ENABLE, pta, sizeof(*pta)); + if (ret < 0) { + wl1251_warning("failed to set softgemini enable: %d", ret); + goto out; + } + +out: + kfree(pta); + return ret; +} + +int wl1251_acx_sg_cfg(struct wl1251 *wl) +{ + struct acx_bt_wlan_coex_param *param; + int ret; + + wl1251_debug(DEBUG_ACX, "acx sg cfg"); + + param = kzalloc(sizeof(*param), GFP_KERNEL); + if (!param) { + ret = -ENOMEM; + goto out; + } + + /* BT-WLAN coext parameters */ + param->min_rate = RATE_INDEX_24MBPS; + param->bt_hp_max_time = PTA_BT_HP_MAXTIME_DEF; + param->wlan_hp_max_time = PTA_WLAN_HP_MAX_TIME_DEF; + param->sense_disable_timer = PTA_SENSE_DISABLE_TIMER_DEF; + param->rx_time_bt_hp = PTA_PROTECTIVE_RX_TIME_DEF; + param->tx_time_bt_hp = PTA_PROTECTIVE_TX_TIME_DEF; + param->rx_time_bt_hp_fast = PTA_PROTECTIVE_RX_TIME_FAST_DEF; + param->tx_time_bt_hp_fast = PTA_PROTECTIVE_TX_TIME_FAST_DEF; + param->wlan_cycle_fast = PTA_CYCLE_TIME_FAST_DEF; + param->bt_anti_starvation_period = PTA_ANTI_STARVE_PERIOD_DEF; + param->next_bt_lp_packet = PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF; + param->wake_up_beacon = PTA_TIME_BEFORE_BEACON_DEF; + param->hp_dm_max_guard_time = PTA_HPDM_MAX_TIME_DEF; + param->next_wlan_packet = PTA_TIME_OUT_NEXT_WLAN_DEF; + param->antenna_type = PTA_ANTENNA_TYPE_DEF; + param->signal_type = PTA_SIGNALING_TYPE_DEF; + param->afh_leverage_on = PTA_AFH_LEVERAGE_ON_DEF; + param->quiet_cycle_num = PTA_NUMBER_QUIET_CYCLE_DEF; + param->max_cts = PTA_MAX_NUM_CTS_DEF; + param->wlan_packets_num = PTA_NUMBER_OF_WLAN_PACKETS_DEF; + param->bt_packets_num = PTA_NUMBER_OF_BT_PACKETS_DEF; + param->missed_rx_avalanche = PTA_RX_FOR_AVALANCHE_DEF; + param->wlan_elp_hp = PTA_ELP_HP_DEF; + param->bt_anti_starvation_cycles = PTA_ANTI_STARVE_NUM_CYCLE_DEF; + param->ack_mode_dual_ant = PTA_ACK_MODE_DEF; + param->pa_sd_enable = PTA_ALLOW_PA_SD_DEF; + param->pta_auto_mode_enable = PTA_AUTO_MODE_NO_CTS_DEF; + param->bt_hp_respected_num = PTA_BT_HP_RESPECTED_DEF; + + ret = wl1251_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param)); + if (ret < 0) { + wl1251_warning("failed to set sg config: %d", ret); + goto out; + } + +out: + kfree(param); + return ret; +} + +int wl1251_acx_cca_threshold(struct wl1251 *wl) +{ + struct acx_energy_detection *detection; + int ret; + + wl1251_debug(DEBUG_ACX, "acx cca threshold"); + + detection = kzalloc(sizeof(*detection), GFP_KERNEL); + if (!detection) { + ret = -ENOMEM; + goto out; + } + + detection->rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D; + detection->tx_energy_detection = 0; + + ret = wl1251_cmd_configure(wl, ACX_CCA_THRESHOLD, + detection, sizeof(*detection)); + if (ret < 0) { + wl1251_warning("failed to set cca threshold: %d", ret); + return ret; + } + +out: + kfree(detection); + return ret; +} + +int wl1251_acx_bcn_dtim_options(struct wl1251 *wl) +{ + struct acx_beacon_broadcast *bb; + int ret; + + wl1251_debug(DEBUG_ACX, "acx bcn dtim options"); + + bb = kzalloc(sizeof(*bb), GFP_KERNEL); + if (!bb) { + ret = -ENOMEM; + goto out; + } + + bb->beacon_rx_timeout = BCN_RX_TIMEOUT_DEF_VALUE; + bb->broadcast_timeout = BROADCAST_RX_TIMEOUT_DEF_VALUE; + bb->rx_broadcast_in_ps = RX_BROADCAST_IN_PS_DEF_VALUE; + bb->ps_poll_threshold = CONSECUTIVE_PS_POLL_FAILURE_DEF; + + ret = wl1251_cmd_configure(wl, ACX_BCN_DTIM_OPTIONS, bb, sizeof(*bb)); + if (ret < 0) { + wl1251_warning("failed to set rx config: %d", ret); + goto out; + } + +out: + kfree(bb); + return ret; +} + +int wl1251_acx_aid(struct wl1251 *wl, u16 aid) +{ + struct acx_aid *acx_aid; + int ret; + + wl1251_debug(DEBUG_ACX, "acx aid"); + + acx_aid = kzalloc(sizeof(*acx_aid), GFP_KERNEL); + if (!acx_aid) { + ret = -ENOMEM; + goto out; + } + + acx_aid->aid = aid; + + ret = wl1251_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid)); + if (ret < 0) { + wl1251_warning("failed to set aid: %d", ret); + goto out; + } + +out: + kfree(acx_aid); + return ret; +} + +int wl1251_acx_event_mbox_mask(struct wl1251 *wl, u32 event_mask) +{ + struct acx_event_mask *mask; + int ret; + + wl1251_debug(DEBUG_ACX, "acx event mbox mask"); + + mask = kzalloc(sizeof(*mask), GFP_KERNEL); + if (!mask) { + ret = -ENOMEM; + goto out; + } + + /* high event mask is unused */ + mask->high_event_mask = 0xffffffff; + + mask->event_mask = event_mask; + + ret = wl1251_cmd_configure(wl, ACX_EVENT_MBOX_MASK, + mask, sizeof(*mask)); + if (ret < 0) { + wl1251_warning("failed to set acx_event_mbox_mask: %d", ret); + goto out; + } + +out: + kfree(mask); + return ret; +} + +int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type preamble) +{ + struct acx_preamble *acx; + int ret; + + wl1251_debug(DEBUG_ACX, "acx_set_preamble"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->preamble = preamble; + + ret = wl1251_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx)); + if (ret < 0) { + wl1251_warning("Setting of preamble failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1251_acx_cts_protect(struct wl1251 *wl, + enum acx_ctsprotect_type ctsprotect) +{ + struct acx_ctsprotect *acx; + int ret; + + wl1251_debug(DEBUG_ACX, "acx_set_ctsprotect"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->ctsprotect = ctsprotect; + + ret = wl1251_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx)); + if (ret < 0) { + wl1251_warning("Setting of ctsprotect failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime) +{ + struct acx_tsf_info *tsf_info; + int ret; + + tsf_info = kzalloc(sizeof(*tsf_info), GFP_KERNEL); + if (!tsf_info) { + ret = -ENOMEM; + goto out; + } + + ret = wl1251_cmd_interrogate(wl, ACX_TSF_INFO, + tsf_info, sizeof(*tsf_info)); + if (ret < 0) { + wl1251_warning("ACX_FW_REV interrogate failed"); + goto out; + } + + *mactime = tsf_info->current_tsf_lsb | + (tsf_info->current_tsf_msb << 31); + +out: + kfree(tsf_info); + return ret; +} + +int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats) +{ + int ret; + + wl1251_debug(DEBUG_ACX, "acx statistics"); + + ret = wl1251_cmd_interrogate(wl, ACX_STATISTICS, stats, + sizeof(*stats)); + if (ret < 0) { + wl1251_warning("acx statistics failed: %d", ret); + return -ENOMEM; + } + + return 0; +} + +int wl1251_acx_rate_policies(struct wl1251 *wl) +{ + struct acx_rate_policy *acx; + int ret = 0; + + wl1251_debug(DEBUG_ACX, "acx rate policies"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + + if (!acx) { + ret = -ENOMEM; + goto out; + } + + /* configure one default (one-size-fits-all) rate class */ + acx->rate_class_cnt = 1; + acx->rate_class[0].enabled_rates = ACX_RATE_MASK_UNSPECIFIED; + acx->rate_class[0].short_retry_limit = ACX_RATE_RETRY_LIMIT; + acx->rate_class[0].long_retry_limit = ACX_RATE_RETRY_LIMIT; + acx->rate_class[0].aflags = 0; + + ret = wl1251_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); + if (ret < 0) { + wl1251_warning("Setting of rate policies failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1251_acx_mem_cfg(struct wl1251 *wl) +{ + struct wl1251_acx_config_memory *mem_conf; + int ret, i; + + wl1251_debug(DEBUG_ACX, "acx mem cfg"); + + mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); + if (!mem_conf) { + ret = -ENOMEM; + goto out; + } + + /* memory config */ + mem_conf->mem_config.num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS); + mem_conf->mem_config.rx_mem_block_num = 35; + mem_conf->mem_config.tx_min_mem_block_num = 64; + mem_conf->mem_config.num_tx_queues = MAX_TX_QUEUES; + mem_conf->mem_config.host_if_options = HOSTIF_PKT_RING; + mem_conf->mem_config.num_ssid_profiles = 1; + mem_conf->mem_config.debug_buffer_size = + cpu_to_le16(TRACE_BUFFER_MAX_SIZE); + + /* RX queue config */ + mem_conf->rx_queue_config.dma_address = 0; + mem_conf->rx_queue_config.num_descs = ACX_RX_DESC_DEF; + mem_conf->rx_queue_config.priority = DEFAULT_RXQ_PRIORITY; + mem_conf->rx_queue_config.type = DEFAULT_RXQ_TYPE; + + /* TX queue config */ + for (i = 0; i < MAX_TX_QUEUES; i++) { + mem_conf->tx_queue_config[i].num_descs = ACX_TX_DESC_DEF; + mem_conf->tx_queue_config[i].attributes = i; + } + + ret = wl1251_cmd_configure(wl, ACX_MEM_CFG, mem_conf, + sizeof(*mem_conf)); + if (ret < 0) { + wl1251_warning("wl1251 mem config failed: %d", ret); + goto out; + } + +out: + kfree(mem_conf); + return ret; +} + +int wl1251_acx_wr_tbtt_and_dtim(struct wl1251 *wl, u16 tbtt, u8 dtim) +{ + struct wl1251_acx_wr_tbtt_and_dtim *acx; + int ret; + + wl1251_debug(DEBUG_ACX, "acx tbtt and dtim"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->tbtt = tbtt; + acx->dtim = dtim; + + ret = wl1251_cmd_configure(wl, ACX_WR_TBTT_AND_DTIM, + acx, sizeof(*acx)); + if (ret < 0) { + wl1251_warning("failed to set tbtt and dtim: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max, + u8 aifs, u16 txop) +{ + struct wl1251_acx_ac_cfg *acx; + int ret = 0; + + wl1251_debug(DEBUG_ACX, "acx ac cfg %d cw_ming %d cw_max %d " + "aifs %d txop %d", ac, cw_min, cw_max, aifs, txop); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->ac = ac; + acx->cw_min = cw_min; + acx->cw_max = cw_max; + acx->aifsn = aifs; + acx->txop_limit = txop; + + ret = wl1251_cmd_configure(wl, ACX_AC_CFG, acx, sizeof(*acx)); + if (ret < 0) { + wl1251_warning("acx ac cfg failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1251_acx_tid_cfg(struct wl1251 *wl, u8 queue, + enum wl1251_acx_channel_type type, + u8 tsid, enum wl1251_acx_ps_scheme ps_scheme, + enum wl1251_acx_ack_policy ack_policy) +{ + struct wl1251_acx_tid_cfg *acx; + int ret = 0; + + wl1251_debug(DEBUG_ACX, "acx tid cfg %d type %d tsid %d " + "ps_scheme %d ack_policy %d", queue, type, tsid, + ps_scheme, ack_policy); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->queue = queue; + acx->type = type; + acx->tsid = tsid; + acx->ps_scheme = ps_scheme; + acx->ack_policy = ack_policy; + + ret = wl1251_cmd_configure(wl, ACX_TID_CFG, acx, sizeof(*acx)); + if (ret < 0) { + wl1251_warning("acx tid cfg failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} diff --git a/drivers/net/wireless/wl1251/acx.h b/drivers/net/wireless/wl1251/acx.h new file mode 100644 index 0000000..e54b21a --- /dev/null +++ b/drivers/net/wireless/wl1251/acx.h @@ -0,0 +1,1411 @@ +/* + * This file is part of wl1251 + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL1251_ACX_H__ +#define __WL1251_ACX_H__ + +#include "wl1251.h" +#include "cmd.h" + +/* Target's information element */ +struct acx_header { + struct wl1251_cmd_header cmd; + + /* acx (or information element) header */ + u16 id; + + /* payload length (not including headers */ + u16 len; +} __packed; + +struct acx_error_counter { + struct acx_header header; + + /* The number of PLCP errors since the last time this */ + /* information element was interrogated. This field is */ + /* automatically cleared when it is interrogated.*/ + u32 PLCP_error; + + /* The number of FCS errors since the last time this */ + /* information element was interrogated. This field is */ + /* automatically cleared when it is interrogated.*/ + u32 FCS_error; + + /* The number of MPDUs without PLCP header errors received*/ + /* since the last time this information element was interrogated. */ + /* This field is automatically cleared when it is interrogated.*/ + u32 valid_frame; + + /* the number of missed sequence numbers in the squentially */ + /* values of frames seq numbers */ + u32 seq_num_miss; +} __packed; + +struct acx_revision { + struct acx_header header; + + /* + * The WiLink firmware version, an ASCII string x.x.x.x, + * that uniquely identifies the current firmware. + * The left most digit is incremented each time a + * significant change is made to the firmware, such as + * code redesign or new platform support. + * The second digit is incremented when major enhancements + * are added or major fixes are made. + * The third digit is incremented for each GA release. + * The fourth digit is incremented for each build. + * The first two digits identify a firmware release version, + * in other words, a unique set of features. + * The first three digits identify a GA release. + */ + char fw_version[20]; + + /* + * This 4 byte field specifies the WiLink hardware version. + * bits 0 - 15: Reserved. + * bits 16 - 23: Version ID - The WiLink version ID + * (1 = first spin, 2 = second spin, and so on). + * bits 24 - 31: Chip ID - The WiLink chip ID. + */ + u32 hw_version; +} __packed; + +enum wl1251_psm_mode { + /* Active mode */ + WL1251_PSM_CAM = 0, + + /* Power save mode */ + WL1251_PSM_PS = 1, + + /* Extreme low power */ + WL1251_PSM_ELP = 2, +}; + +struct acx_sleep_auth { + struct acx_header header; + + /* The sleep level authorization of the device. */ + /* 0 - Always active*/ + /* 1 - Power down mode: light / fast sleep*/ + /* 2 - ELP mode: Deep / Max sleep*/ + u8 sleep_auth; + u8 padding[3]; +} __packed; + +enum { + HOSTIF_PCI_MASTER_HOST_INDIRECT, + HOSTIF_PCI_MASTER_HOST_DIRECT, + HOSTIF_SLAVE, + HOSTIF_PKT_RING, + HOSTIF_DONTCARE = 0xFF +}; + +#define DEFAULT_UCAST_PRIORITY 0 +#define DEFAULT_RX_Q_PRIORITY 0 +#define DEFAULT_NUM_STATIONS 1 +#define DEFAULT_RXQ_PRIORITY 0 /* low 0 .. 15 high */ +#define DEFAULT_RXQ_TYPE 0x07 /* All frames, Data/Ctrl/Mgmt */ +#define TRACE_BUFFER_MAX_SIZE 256 + +#define DP_RX_PACKET_RING_CHUNK_SIZE 1600 +#define DP_TX_PACKET_RING_CHUNK_SIZE 1600 +#define DP_RX_PACKET_RING_CHUNK_NUM 2 +#define DP_TX_PACKET_RING_CHUNK_NUM 2 +#define DP_TX_COMPLETE_TIME_OUT 20 +#define FW_TX_CMPLT_BLOCK_SIZE 16 + +struct acx_data_path_params { + struct acx_header header; + + u16 rx_packet_ring_chunk_size; + u16 tx_packet_ring_chunk_size; + + u8 rx_packet_ring_chunk_num; + u8 tx_packet_ring_chunk_num; + + /* + * Maximum number of packets that can be gathered + * in the TX complete ring before an interrupt + * is generated. + */ + u8 tx_complete_threshold; + + /* Number of pending TX complete entries in cyclic ring.*/ + u8 tx_complete_ring_depth; + + /* + * Max num microseconds since a packet enters the TX + * complete ring until an interrupt is generated. + */ + u32 tx_complete_timeout; +} __packed; + + +struct acx_data_path_params_resp { + struct acx_header header; + + u16 rx_packet_ring_chunk_size; + u16 tx_packet_ring_chunk_size; + + u8 rx_packet_ring_chunk_num; + u8 tx_packet_ring_chunk_num; + + u8 pad[2]; + + u32 rx_packet_ring_addr; + u32 tx_packet_ring_addr; + + u32 rx_control_addr; + u32 tx_control_addr; + + u32 tx_complete_addr; +} __packed; + +#define TX_MSDU_LIFETIME_MIN 0 +#define TX_MSDU_LIFETIME_MAX 3000 +#define TX_MSDU_LIFETIME_DEF 512 +#define RX_MSDU_LIFETIME_MIN 0 +#define RX_MSDU_LIFETIME_MAX 0xFFFFFFFF +#define RX_MSDU_LIFETIME_DEF 512000 + +struct acx_rx_msdu_lifetime { + struct acx_header header; + + /* + * The maximum amount of time, in TU, before the + * firmware discards the MSDU. + */ + u32 lifetime; +} __packed; + +/* + * RX Config Options Table + * Bit Definition + * === ========== + * 31:14 Reserved + * 13 Copy RX Status - when set, write three receive status words + * to top of rx'd MPDUs. + * When cleared, do not write three status words (added rev 1.5) + * 12 Reserved + * 11 RX Complete upon FCS error - when set, give rx complete + * interrupt for FCS errors, after the rx filtering, e.g. unicast + * frames not to us with FCS error will not generate an interrupt. + * 10 SSID Filter Enable - When set, the WiLink discards all beacon, + * probe request, and probe response frames with an SSID that does + * not match the SSID specified by the host in the START/JOIN + * command. + * When clear, the WiLink receives frames with any SSID. + * 9 Broadcast Filter Enable - When set, the WiLink discards all + * broadcast frames. When clear, the WiLink receives all received + * broadcast frames. + * 8:6 Reserved + * 5 BSSID Filter Enable - When set, the WiLink discards any frames + * with a BSSID that does not match the BSSID specified by the + * host. + * When clear, the WiLink receives frames from any BSSID. + * 4 MAC Addr Filter - When set, the WiLink discards any frames + * with a destination address that does not match the MAC address + * of the adaptor. + * When clear, the WiLink receives frames destined to any MAC + * address. + * 3 Promiscuous - When set, the WiLink receives all valid frames + * (i.e., all frames that pass the FCS check). + * When clear, only frames that pass the other filters specified + * are received. + * 2 FCS - When set, the WiLink includes the FCS with the received + * frame. + * When cleared, the FCS is discarded. + * 1 PLCP header - When set, write all data from baseband to frame + * buffer including PHY header. + * 0 Reserved - Always equal to 0. + * + * RX Filter Options Table + * Bit Definition + * === ========== + * 31:12 Reserved - Always equal to 0. + * 11 Association - When set, the WiLink receives all association + * related frames (association request/response, reassocation + * request/response, and disassociation). When clear, these frames + * are discarded. + * 10 Auth/De auth - When set, the WiLink receives all authentication + * and de-authentication frames. When clear, these frames are + * discarded. + * 9 Beacon - When set, the WiLink receives all beacon frames. + * When clear, these frames are discarded. + * 8 Contention Free - When set, the WiLink receives all contention + * free frames. + * When clear, these frames are discarded. + * 7 Control - When set, the WiLink receives all control frames. + * When clear, these frames are discarded. + * 6 Data - When set, the WiLink receives all data frames. + * When clear, these frames are discarded. + * 5 FCS Error - When set, the WiLink receives frames that have FCS + * errors. + * When clear, these frames are discarded. + * 4 Management - When set, the WiLink receives all management + * frames. + * When clear, these frames are discarded. + * 3 Probe Request - When set, the WiLink receives all probe request + * frames. + * When clear, these frames are discarded. + * 2 Probe Response - When set, the WiLink receives all probe + * response frames. + * When clear, these frames are discarded. + * 1 RTS/CTS/ACK - When set, the WiLink receives all RTS, CTS and ACK + * frames. + * When clear, these frames are discarded. + * 0 Rsvd Type/Sub Type - When set, the WiLink receives all frames + * that have reserved frame types and sub types as defined by the + * 802.11 specification. + * When clear, these frames are discarded. + */ +struct acx_rx_config { + struct acx_header header; + + u32 config_options; + u32 filter_options; +} __packed; + +enum { + QOS_AC_BE = 0, + QOS_AC_BK, + QOS_AC_VI, + QOS_AC_VO, + QOS_HIGHEST_AC_INDEX = QOS_AC_VO, +}; + +#define MAX_NUM_OF_AC (QOS_HIGHEST_AC_INDEX+1) +#define FIRST_AC_INDEX QOS_AC_BE +#define MAX_NUM_OF_802_1d_TAGS 8 +#define AC_PARAMS_MAX_TSID 15 +#define MAX_APSD_CONF 0xffff + +#define QOS_TX_HIGH_MIN (0) +#define QOS_TX_HIGH_MAX (100) + +#define QOS_TX_HIGH_BK_DEF (25) +#define QOS_TX_HIGH_BE_DEF (35) +#define QOS_TX_HIGH_VI_DEF (35) +#define QOS_TX_HIGH_VO_DEF (35) + +#define QOS_TX_LOW_BK_DEF (15) +#define QOS_TX_LOW_BE_DEF (25) +#define QOS_TX_LOW_VI_DEF (25) +#define QOS_TX_LOW_VO_DEF (25) + +struct acx_tx_queue_qos_config { + struct acx_header header; + + u8 qid; + u8 pad[3]; + + /* Max number of blocks allowd in the queue */ + u16 high_threshold; + + /* Lowest memory blocks guaranteed for this queue */ + u16 low_threshold; +} __packed; + +struct acx_packet_detection { + struct acx_header header; + + u32 threshold; +} __packed; + + +enum acx_slot_type { + SLOT_TIME_LONG = 0, + SLOT_TIME_SHORT = 1, + DEFAULT_SLOT_TIME = SLOT_TIME_SHORT, + MAX_SLOT_TIMES = 0xFF +}; + +#define STATION_WONE_INDEX 0 + +struct acx_slot { + struct acx_header header; + + u8 wone_index; /* Reserved */ + u8 slot_time; + u8 reserved[6]; +} __packed; + + +#define ADDRESS_GROUP_MAX (8) +#define ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ADDRESS_GROUP_MAX) + +struct acx_dot11_grp_addr_tbl { + struct acx_header header; + + u8 enabled; + u8 num_groups; + u8 pad[2]; + u8 mac_table[ADDRESS_GROUP_MAX_LEN]; +} __packed; + + +#define RX_TIMEOUT_PS_POLL_MIN 0 +#define RX_TIMEOUT_PS_POLL_MAX (200000) +#define RX_TIMEOUT_PS_POLL_DEF (15) +#define RX_TIMEOUT_UPSD_MIN 0 +#define RX_TIMEOUT_UPSD_MAX (200000) +#define RX_TIMEOUT_UPSD_DEF (15) + +struct acx_rx_timeout { + struct acx_header header; + + /* + * The longest time the STA will wait to receive + * traffic from the AP after a PS-poll has been + * transmitted. + */ + u16 ps_poll_timeout; + + /* + * The longest time the STA will wait to receive + * traffic from the AP after a frame has been sent + * from an UPSD enabled queue. + */ + u16 upsd_timeout; +} __packed; + +#define RTS_THRESHOLD_MIN 0 +#define RTS_THRESHOLD_MAX 4096 +#define RTS_THRESHOLD_DEF 2347 + +struct acx_rts_threshold { + struct acx_header header; + + u16 threshold; + u8 pad[2]; +} __packed; + +struct acx_beacon_filter_option { + struct acx_header header; + + u8 enable; + + /* + * The number of beacons without the unicast TIM + * bit set that the firmware buffers before + * signaling the host about ready frames. + * When set to 0 and the filter is enabled, beacons + * without the unicast TIM bit set are dropped. + */ + u8 max_num_beacons; + u8 pad[2]; +} __packed; + +/* + * ACXBeaconFilterEntry (not 221) + * Byte Offset Size (Bytes) Definition + * =========== ============ ========== + * 0 1 IE identifier + * 1 1 Treatment bit mask + * + * ACXBeaconFilterEntry (221) + * Byte Offset Size (Bytes) Definition + * =========== ============ ========== + * 0 1 IE identifier + * 1 1 Treatment bit mask + * 2 3 OUI + * 5 1 Type + * 6 2 Version + * + * + * Treatment bit mask - The information element handling: + * bit 0 - The information element is compared and transferred + * in case of change. + * bit 1 - The information element is transferred to the host + * with each appearance or disappearance. + * Note that both bits can be set at the same time. + */ +#define BEACON_FILTER_TABLE_MAX_IE_NUM (32) +#define BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM (6) +#define BEACON_FILTER_TABLE_IE_ENTRY_SIZE (2) +#define BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE (6) +#define BEACON_FILTER_TABLE_MAX_SIZE ((BEACON_FILTER_TABLE_MAX_IE_NUM * \ + BEACON_FILTER_TABLE_IE_ENTRY_SIZE) + \ + (BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM * \ + BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE)) + +#define BEACON_RULE_PASS_ON_CHANGE BIT(0) +#define BEACON_RULE_PASS_ON_APPEARANCE BIT(1) + +#define BEACON_FILTER_IE_ID_CHANNEL_SWITCH_ANN (37) + +struct acx_beacon_filter_ie_table { + struct acx_header header; + + u8 num_ie; + u8 pad[3]; + u8 table[BEACON_FILTER_TABLE_MAX_SIZE]; +} __packed; + +#define SYNCH_FAIL_DEFAULT_THRESHOLD 10 /* number of beacons */ +#define NO_BEACON_DEFAULT_TIMEOUT (500) /* in microseconds */ + +struct acx_conn_monit_params { + struct acx_header header; + + u32 synch_fail_thold; /* number of beacons missed */ + u32 bss_lose_timeout; /* number of TU's from synch fail */ +} __packed; + +enum { + SG_ENABLE = 0, + SG_DISABLE, + SG_SENSE_NO_ACTIVITY, + SG_SENSE_ACTIVE +}; + +struct acx_bt_wlan_coex { + struct acx_header header; + + /* + * 0 -> PTA enabled + * 1 -> PTA disabled + * 2 -> sense no active mode, i.e. + * an interrupt is sent upon + * BT activity. + * 3 -> PTA is switched on in response + * to the interrupt sending. + */ + u8 enable; + u8 pad[3]; +} __packed; + +#define PTA_ANTENNA_TYPE_DEF (0) +#define PTA_BT_HP_MAXTIME_DEF (2000) +#define PTA_WLAN_HP_MAX_TIME_DEF (5000) +#define PTA_SENSE_DISABLE_TIMER_DEF (1350) +#define PTA_PROTECTIVE_RX_TIME_DEF (1500) +#define PTA_PROTECTIVE_TX_TIME_DEF (1500) +#define PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF (3000) +#define PTA_SIGNALING_TYPE_DEF (1) +#define PTA_AFH_LEVERAGE_ON_DEF (0) +#define PTA_NUMBER_QUIET_CYCLE_DEF (0) +#define PTA_MAX_NUM_CTS_DEF (3) +#define PTA_NUMBER_OF_WLAN_PACKETS_DEF (2) +#define PTA_NUMBER_OF_BT_PACKETS_DEF (2) +#define PTA_PROTECTIVE_RX_TIME_FAST_DEF (1500) +#define PTA_PROTECTIVE_TX_TIME_FAST_DEF (3000) +#define PTA_CYCLE_TIME_FAST_DEF (8700) +#define PTA_RX_FOR_AVALANCHE_DEF (5) +#define PTA_ELP_HP_DEF (0) +#define PTA_ANTI_STARVE_PERIOD_DEF (500) +#define PTA_ANTI_STARVE_NUM_CYCLE_DEF (4) +#define PTA_ALLOW_PA_SD_DEF (1) +#define PTA_TIME_BEFORE_BEACON_DEF (6300) +#define PTA_HPDM_MAX_TIME_DEF (1600) +#define PTA_TIME_OUT_NEXT_WLAN_DEF (2550) +#define PTA_AUTO_MODE_NO_CTS_DEF (0) +#define PTA_BT_HP_RESPECTED_DEF (3) +#define PTA_WLAN_RX_MIN_RATE_DEF (24) +#define PTA_ACK_MODE_DEF (1) + +struct acx_bt_wlan_coex_param { + struct acx_header header; + + /* + * The minimum rate of a received WLAN packet in the STA, + * during protective mode, of which a new BT-HP request + * during this Rx will always be respected and gain the antenna. + */ + u32 min_rate; + + /* Max time the BT HP will be respected. */ + u16 bt_hp_max_time; + + /* Max time the WLAN HP will be respected. */ + u16 wlan_hp_max_time; + + /* + * The time between the last BT activity + * and the moment when the sense mode returns + * to SENSE_INACTIVE. + */ + u16 sense_disable_timer; + + /* Time before the next BT HP instance */ + u16 rx_time_bt_hp; + u16 tx_time_bt_hp; + + /* range: 10-20000 default: 1500 */ + u16 rx_time_bt_hp_fast; + u16 tx_time_bt_hp_fast; + + /* range: 2000-65535 default: 8700 */ + u16 wlan_cycle_fast; + + /* range: 0 - 15000 (Msec) default: 1000 */ + u16 bt_anti_starvation_period; + + /* range 400-10000(Usec) default: 3000 */ + u16 next_bt_lp_packet; + + /* Deafult: worst case for BT DH5 traffic */ + u16 wake_up_beacon; + + /* range: 0-50000(Usec) default: 1050 */ + u16 hp_dm_max_guard_time; + + /* + * This is to prevent both BT & WLAN antenna + * starvation. + * Range: 100-50000(Usec) default:2550 + */ + u16 next_wlan_packet; + + /* 0 -> shared antenna */ + u8 antenna_type; + + /* + * 0 -> TI legacy + * 1 -> Palau + */ + u8 signal_type; + + /* + * BT AFH status + * 0 -> no AFH + * 1 -> from dedicated GPIO + * 2 -> AFH on (from host) + */ + u8 afh_leverage_on; + + /* + * The number of cycles during which no + * TX will be sent after 1 cycle of RX + * transaction in protective mode + */ + u8 quiet_cycle_num; + + /* + * The maximum number of CTSs that will + * be sent for receiving RX packet in + * protective mode + */ + u8 max_cts; + + /* + * The number of WLAN packets + * transferred in common mode before + * switching to BT. + */ + u8 wlan_packets_num; + + /* + * The number of BT packets + * transferred in common mode before + * switching to WLAN. + */ + u8 bt_packets_num; + + /* range: 1-255 default: 5 */ + u8 missed_rx_avalanche; + + /* range: 0-1 default: 1 */ + u8 wlan_elp_hp; + + /* range: 0 - 15 default: 4 */ + u8 bt_anti_starvation_cycles; + + u8 ack_mode_dual_ant; + + /* + * Allow PA_SD assertion/de-assertion + * during enabled BT activity. + */ + u8 pa_sd_enable; + + /* + * Enable/Disable PTA in auto mode: + * Support Both Active & P.S modes + */ + u8 pta_auto_mode_enable; + + /* range: 0 - 20 default: 1 */ + u8 bt_hp_respected_num; +} __packed; + +#define CCA_THRSH_ENABLE_ENERGY_D 0x140A +#define CCA_THRSH_DISABLE_ENERGY_D 0xFFEF + +struct acx_energy_detection { + struct acx_header header; + + /* The RX Clear Channel Assessment threshold in the PHY */ + u16 rx_cca_threshold; + u8 tx_energy_detection; + u8 pad; +} __packed; + +#define BCN_RX_TIMEOUT_DEF_VALUE 10000 +#define BROADCAST_RX_TIMEOUT_DEF_VALUE 20000 +#define RX_BROADCAST_IN_PS_DEF_VALUE 1 +#define CONSECUTIVE_PS_POLL_FAILURE_DEF 4 + +struct acx_beacon_broadcast { + struct acx_header header; + + u16 beacon_rx_timeout; + u16 broadcast_timeout; + + /* Enables receiving of broadcast packets in PS mode */ + u8 rx_broadcast_in_ps; + + /* Consecutive PS Poll failures before updating the host */ + u8 ps_poll_threshold; + u8 pad[2]; +} __packed; + +struct acx_event_mask { + struct acx_header header; + + u32 event_mask; + u32 high_event_mask; /* Unused */ +} __packed; + +#define CFG_RX_FCS BIT(2) +#define CFG_RX_ALL_GOOD BIT(3) +#define CFG_UNI_FILTER_EN BIT(4) +#define CFG_BSSID_FILTER_EN BIT(5) +#define CFG_MC_FILTER_EN BIT(6) +#define CFG_MC_ADDR0_EN BIT(7) +#define CFG_MC_ADDR1_EN BIT(8) +#define CFG_BC_REJECT_EN BIT(9) +#define CFG_SSID_FILTER_EN BIT(10) +#define CFG_RX_INT_FCS_ERROR BIT(11) +#define CFG_RX_INT_ENCRYPTED BIT(12) +#define CFG_RX_WR_RX_STATUS BIT(13) +#define CFG_RX_FILTER_NULTI BIT(14) +#define CFG_RX_RESERVE BIT(15) +#define CFG_RX_TIMESTAMP_TSF BIT(16) + +#define CFG_RX_RSV_EN BIT(0) +#define CFG_RX_RCTS_ACK BIT(1) +#define CFG_RX_PRSP_EN BIT(2) +#define CFG_RX_PREQ_EN BIT(3) +#define CFG_RX_MGMT_EN BIT(4) +#define CFG_RX_FCS_ERROR BIT(5) +#define CFG_RX_DATA_EN BIT(6) +#define CFG_RX_CTL_EN BIT(7) +#define CFG_RX_CF_EN BIT(8) +#define CFG_RX_BCN_EN BIT(9) +#define CFG_RX_AUTH_EN BIT(10) +#define CFG_RX_ASSOC_EN BIT(11) + +#define SCAN_PASSIVE BIT(0) +#define SCAN_5GHZ_BAND BIT(1) +#define SCAN_TRIGGERED BIT(2) +#define SCAN_PRIORITY_HIGH BIT(3) + +struct acx_fw_gen_frame_rates { + struct acx_header header; + + u8 tx_ctrl_frame_rate; /* RATE_* */ + u8 tx_ctrl_frame_mod; /* CCK_* or PBCC_* */ + u8 tx_mgt_frame_rate; + u8 tx_mgt_frame_mod; +} __packed; + +/* STA MAC */ +struct acx_dot11_station_id { + struct acx_header header; + + u8 mac[ETH_ALEN]; + u8 pad[2]; +} __packed; + +struct acx_feature_config { + struct acx_header header; + + u32 options; + u32 data_flow_options; +} __packed; + +struct acx_current_tx_power { + struct acx_header header; + + u8 current_tx_power; + u8 padding[3]; +} __packed; + +struct acx_dot11_default_key { + struct acx_header header; + + u8 id; + u8 pad[3]; +} __packed; + +struct acx_tsf_info { + struct acx_header header; + + u32 current_tsf_msb; + u32 current_tsf_lsb; + u32 last_TBTT_msb; + u32 last_TBTT_lsb; + u8 last_dtim_count; + u8 pad[3]; +} __packed; + +enum acx_wake_up_event { + WAKE_UP_EVENT_BEACON_BITMAP = 0x01, /* Wake on every Beacon*/ + WAKE_UP_EVENT_DTIM_BITMAP = 0x02, /* Wake on every DTIM*/ + WAKE_UP_EVENT_N_DTIM_BITMAP = 0x04, /* Wake on every Nth DTIM */ + WAKE_UP_EVENT_N_BEACONS_BITMAP = 0x08, /* Wake on every Nth Beacon */ + WAKE_UP_EVENT_BITS_MASK = 0x0F +}; + +struct acx_wake_up_condition { + struct acx_header header; + + u8 wake_up_event; /* Only one bit can be set */ + u8 listen_interval; + u8 pad[2]; +} __packed; + +struct acx_aid { + struct acx_header header; + + /* + * To be set when associated with an AP. + */ + u16 aid; + u8 pad[2]; +} __packed; + +enum acx_preamble_type { + ACX_PREAMBLE_LONG = 0, + ACX_PREAMBLE_SHORT = 1 +}; + +struct acx_preamble { + struct acx_header header; + + /* + * When set, the WiLink transmits the frames with a short preamble and + * when cleared, the WiLink transmits the frames with a long preamble. + */ + u8 preamble; + u8 padding[3]; +} __packed; + +enum acx_ctsprotect_type { + CTSPROTECT_DISABLE = 0, + CTSPROTECT_ENABLE = 1 +}; + +struct acx_ctsprotect { + struct acx_header header; + u8 ctsprotect; + u8 padding[3]; +} __packed; + +struct acx_tx_statistics { + u32 internal_desc_overflow; +} __packed; + +struct acx_rx_statistics { + u32 out_of_mem; + u32 hdr_overflow; + u32 hw_stuck; + u32 dropped; + u32 fcs_err; + u32 xfr_hint_trig; + u32 path_reset; + u32 reset_counter; +} __packed; + +struct acx_dma_statistics { + u32 rx_requested; + u32 rx_errors; + u32 tx_requested; + u32 tx_errors; +} __packed; + +struct acx_isr_statistics { + /* host command complete */ + u32 cmd_cmplt; + + /* fiqisr() */ + u32 fiqs; + + /* (INT_STS_ND & INT_TRIG_RX_HEADER) */ + u32 rx_headers; + + /* (INT_STS_ND & INT_TRIG_RX_CMPLT) */ + u32 rx_completes; + + /* (INT_STS_ND & INT_TRIG_NO_RX_BUF) */ + u32 rx_mem_overflow; + + /* (INT_STS_ND & INT_TRIG_S_RX_RDY) */ + u32 rx_rdys; + + /* irqisr() */ + u32 irqs; + + /* (INT_STS_ND & INT_TRIG_TX_PROC) */ + u32 tx_procs; + + /* (INT_STS_ND & INT_TRIG_DECRYPT_DONE) */ + u32 decrypt_done; + + /* (INT_STS_ND & INT_TRIG_DMA0) */ + u32 dma0_done; + + /* (INT_STS_ND & INT_TRIG_DMA1) */ + u32 dma1_done; + + /* (INT_STS_ND & INT_TRIG_TX_EXC_CMPLT) */ + u32 tx_exch_complete; + + /* (INT_STS_ND & INT_TRIG_COMMAND) */ + u32 commands; + + /* (INT_STS_ND & INT_TRIG_RX_PROC) */ + u32 rx_procs; + + /* (INT_STS_ND & INT_TRIG_PM_802) */ + u32 hw_pm_mode_changes; + + /* (INT_STS_ND & INT_TRIG_ACKNOWLEDGE) */ + u32 host_acknowledges; + + /* (INT_STS_ND & INT_TRIG_PM_PCI) */ + u32 pci_pm; + + /* (INT_STS_ND & INT_TRIG_ACM_WAKEUP) */ + u32 wakeups; + + /* (INT_STS_ND & INT_TRIG_LOW_RSSI) */ + u32 low_rssi; +} __packed; + +struct acx_wep_statistics { + /* WEP address keys configured */ + u32 addr_key_count; + + /* default keys configured */ + u32 default_key_count; + + u32 reserved; + + /* number of times that WEP key not found on lookup */ + u32 key_not_found; + + /* number of times that WEP key decryption failed */ + u32 decrypt_fail; + + /* WEP packets decrypted */ + u32 packets; + + /* WEP decrypt interrupts */ + u32 interrupt; +} __packed; + +#define ACX_MISSED_BEACONS_SPREAD 10 + +struct acx_pwr_statistics { + /* the amount of enters into power save mode (both PD & ELP) */ + u32 ps_enter; + + /* the amount of enters into ELP mode */ + u32 elp_enter; + + /* the amount of missing beacon interrupts to the host */ + u32 missing_bcns; + + /* the amount of wake on host-access times */ + u32 wake_on_host; + + /* the amount of wake on timer-expire */ + u32 wake_on_timer_exp; + + /* the number of packets that were transmitted with PS bit set */ + u32 tx_with_ps; + + /* the number of packets that were transmitted with PS bit clear */ + u32 tx_without_ps; + + /* the number of received beacons */ + u32 rcvd_beacons; + + /* the number of entering into PowerOn (power save off) */ + u32 power_save_off; + + /* the number of entries into power save mode */ + u16 enable_ps; + + /* + * the number of exits from power save, not including failed PS + * transitions + */ + u16 disable_ps; + + /* + * the number of times the TSF counter was adjusted because + * of drift + */ + u32 fix_tsf_ps; + + /* Gives statistics about the spread continuous missed beacons. + * The 16 LSB are dedicated for the PS mode. + * The 16 MSB are dedicated for the PS mode. + * cont_miss_bcns_spread[0] - single missed beacon. + * cont_miss_bcns_spread[1] - two continuous missed beacons. + * cont_miss_bcns_spread[2] - three continuous missed beacons. + * ... + * cont_miss_bcns_spread[9] - ten and more continuous missed beacons. + */ + u32 cont_miss_bcns_spread[ACX_MISSED_BEACONS_SPREAD]; + + /* the number of beacons in awake mode */ + u32 rcvd_awake_beacons; +} __packed; + +struct acx_mic_statistics { + u32 rx_pkts; + u32 calc_failure; +} __packed; + +struct acx_aes_statistics { + u32 encrypt_fail; + u32 decrypt_fail; + u32 encrypt_packets; + u32 decrypt_packets; + u32 encrypt_interrupt; + u32 decrypt_interrupt; +} __packed; + +struct acx_event_statistics { + u32 heart_beat; + u32 calibration; + u32 rx_mismatch; + u32 rx_mem_empty; + u32 rx_pool; + u32 oom_late; + u32 phy_transmit_error; + u32 tx_stuck; +} __packed; + +struct acx_ps_statistics { + u32 pspoll_timeouts; + u32 upsd_timeouts; + u32 upsd_max_sptime; + u32 upsd_max_apturn; + u32 pspoll_max_apturn; + u32 pspoll_utilization; + u32 upsd_utilization; +} __packed; + +struct acx_rxpipe_statistics { + u32 rx_prep_beacon_drop; + u32 descr_host_int_trig_rx_data; + u32 beacon_buffer_thres_host_int_trig_rx_data; + u32 missed_beacon_host_int_trig_rx_data; + u32 tx_xfr_host_int_trig_rx_data; +} __packed; + +struct acx_statistics { + struct acx_header header; + + struct acx_tx_statistics tx; + struct acx_rx_statistics rx; + struct acx_dma_statistics dma; + struct acx_isr_statistics isr; + struct acx_wep_statistics wep; + struct acx_pwr_statistics pwr; + struct acx_aes_statistics aes; + struct acx_mic_statistics mic; + struct acx_event_statistics event; + struct acx_ps_statistics ps; + struct acx_rxpipe_statistics rxpipe; +} __packed; + +#define ACX_MAX_RATE_CLASSES 8 +#define ACX_RATE_MASK_UNSPECIFIED 0 +#define ACX_RATE_RETRY_LIMIT 10 + +struct acx_rate_class { + u32 enabled_rates; + u8 short_retry_limit; + u8 long_retry_limit; + u8 aflags; + u8 reserved; +} __packed; + +struct acx_rate_policy { + struct acx_header header; + + u32 rate_class_cnt; + struct acx_rate_class rate_class[ACX_MAX_RATE_CLASSES]; +} __packed; + +struct wl1251_acx_memory { + __le16 num_stations; /* number of STAs to be supported. */ + u16 reserved_1; + + /* + * Nmber of memory buffers for the RX mem pool. + * The actual number may be less if there are + * not enough blocks left for the minimum num + * of TX ones. + */ + u8 rx_mem_block_num; + u8 reserved_2; + u8 num_tx_queues; /* From 1 to 16 */ + u8 host_if_options; /* HOST_IF* */ + u8 tx_min_mem_block_num; + u8 num_ssid_profiles; + __le16 debug_buffer_size; +} __packed; + + +#define ACX_RX_DESC_MIN 1 +#define ACX_RX_DESC_MAX 127 +#define ACX_RX_DESC_DEF 32 +struct wl1251_acx_rx_queue_config { + u8 num_descs; + u8 pad; + u8 type; + u8 priority; + __le32 dma_address; +} __packed; + +#define ACX_TX_DESC_MIN 1 +#define ACX_TX_DESC_MAX 127 +#define ACX_TX_DESC_DEF 16 +struct wl1251_acx_tx_queue_config { + u8 num_descs; + u8 pad[2]; + u8 attributes; +} __packed; + +#define MAX_TX_QUEUE_CONFIGS 5 +#define MAX_TX_QUEUES 4 +struct wl1251_acx_config_memory { + struct acx_header header; + + struct wl1251_acx_memory mem_config; + struct wl1251_acx_rx_queue_config rx_queue_config; + struct wl1251_acx_tx_queue_config tx_queue_config[MAX_TX_QUEUE_CONFIGS]; +} __packed; + +struct wl1251_acx_mem_map { + struct acx_header header; + + void *code_start; + void *code_end; + + void *wep_defkey_start; + void *wep_defkey_end; + + void *sta_table_start; + void *sta_table_end; + + void *packet_template_start; + void *packet_template_end; + + void *queue_memory_start; + void *queue_memory_end; + + void *packet_memory_pool_start; + void *packet_memory_pool_end; + + void *debug_buffer1_start; + void *debug_buffer1_end; + + void *debug_buffer2_start; + void *debug_buffer2_end; + + /* Number of blocks FW allocated for TX packets */ + u32 num_tx_mem_blocks; + + /* Number of blocks FW allocated for RX packets */ + u32 num_rx_mem_blocks; +} __packed; + + +struct wl1251_acx_wr_tbtt_and_dtim { + + struct acx_header header; + + /* Time in TUs between two consecutive beacons */ + u16 tbtt; + + /* + * DTIM period + * For BSS: Number of TBTTs in a DTIM period (range: 1-10) + * For IBSS: value shall be set to 1 + */ + u8 dtim; + u8 padding; +} __packed; + +struct wl1251_acx_ac_cfg { + struct acx_header header; + + /* + * Access Category - The TX queue's access category + * (refer to AccessCategory_enum) + */ + u8 ac; + + /* + * The contention window minimum size (in slots) for + * the access class. + */ + u8 cw_min; + + /* + * The contention window maximum size (in slots) for + * the access class. + */ + u16 cw_max; + + /* The AIF value (in slots) for the access class. */ + u8 aifsn; + + u8 reserved; + + /* The TX Op Limit (in microseconds) for the access class. */ + u16 txop_limit; +} __packed; + + +enum wl1251_acx_channel_type { + CHANNEL_TYPE_DCF = 0, + CHANNEL_TYPE_EDCF = 1, + CHANNEL_TYPE_HCCA = 2, +}; + +enum wl1251_acx_ps_scheme { + /* regular ps: simple sending of packets */ + WL1251_ACX_PS_SCHEME_LEGACY = 0, + + /* sending a packet triggers a unscheduled apsd downstream */ + WL1251_ACX_PS_SCHEME_UPSD_TRIGGER = 1, + + /* a pspoll packet will be sent before every data packet */ + WL1251_ACX_PS_SCHEME_LEGACY_PSPOLL = 2, + + /* scheduled apsd mode */ + WL1251_ACX_PS_SCHEME_SAPSD = 3, +}; + +enum wl1251_acx_ack_policy { + WL1251_ACX_ACK_POLICY_LEGACY = 0, + WL1251_ACX_ACK_POLICY_NO_ACK = 1, + WL1251_ACX_ACK_POLICY_BLOCK = 2, +}; + +struct wl1251_acx_tid_cfg { + struct acx_header header; + + /* tx queue id number (0-7) */ + u8 queue; + + /* channel access type for the queue, enum wl1251_acx_channel_type */ + u8 type; + + /* EDCA: ac index (0-3), HCCA: traffic stream id (8-15) */ + u8 tsid; + + /* ps scheme of the specified queue, enum wl1251_acx_ps_scheme */ + u8 ps_scheme; + + /* the tx queue ack policy, enum wl1251_acx_ack_policy */ + u8 ack_policy; + + u8 padding[3]; + + /* not supported */ + u32 apsdconf[2]; +} __packed; + +/************************************************************************* + + Host Interrupt Register (WiLink -> Host) + +**************************************************************************/ + +/* RX packet is ready in Xfer buffer #0 */ +#define WL1251_ACX_INTR_RX0_DATA BIT(0) + +/* TX result(s) are in the TX complete buffer */ +#define WL1251_ACX_INTR_TX_RESULT BIT(1) + +/* OBSOLETE */ +#define WL1251_ACX_INTR_TX_XFR BIT(2) + +/* RX packet is ready in Xfer buffer #1 */ +#define WL1251_ACX_INTR_RX1_DATA BIT(3) + +/* Event was entered to Event MBOX #A */ +#define WL1251_ACX_INTR_EVENT_A BIT(4) + +/* Event was entered to Event MBOX #B */ +#define WL1251_ACX_INTR_EVENT_B BIT(5) + +/* OBSOLETE */ +#define WL1251_ACX_INTR_WAKE_ON_HOST BIT(6) + +/* Trace meassge on MBOX #A */ +#define WL1251_ACX_INTR_TRACE_A BIT(7) + +/* Trace meassge on MBOX #B */ +#define WL1251_ACX_INTR_TRACE_B BIT(8) + +/* Command processing completion */ +#define WL1251_ACX_INTR_CMD_COMPLETE BIT(9) + +/* Init sequence is done */ +#define WL1251_ACX_INTR_INIT_COMPLETE BIT(14) + +#define WL1251_ACX_INTR_ALL 0xFFFFFFFF + +enum { + ACX_WAKE_UP_CONDITIONS = 0x0002, + ACX_MEM_CFG = 0x0003, + ACX_SLOT = 0x0004, + ACX_QUEUE_HEAD = 0x0005, /* for MASTER mode only */ + ACX_AC_CFG = 0x0007, + ACX_MEM_MAP = 0x0008, + ACX_AID = 0x000A, + ACX_RADIO_PARAM = 0x000B, /* Not used */ + ACX_CFG = 0x000C, /* Not used */ + ACX_FW_REV = 0x000D, + ACX_MEDIUM_USAGE = 0x000F, + ACX_RX_CFG = 0x0010, + ACX_TX_QUEUE_CFG = 0x0011, /* FIXME: only used by wl1251 */ + ACX_BSS_IN_PS = 0x0012, /* for AP only */ + ACX_STATISTICS = 0x0013, /* Debug API */ + ACX_FEATURE_CFG = 0x0015, + ACX_MISC_CFG = 0x0017, /* Not used */ + ACX_TID_CFG = 0x001A, + ACX_BEACON_FILTER_OPT = 0x001F, + ACX_LOW_RSSI = 0x0020, + ACX_NOISE_HIST = 0x0021, + ACX_HDK_VERSION = 0x0022, /* ??? */ + ACX_PD_THRESHOLD = 0x0023, + ACX_DATA_PATH_PARAMS = 0x0024, /* WO */ + ACX_DATA_PATH_RESP_PARAMS = 0x0024, /* RO */ + ACX_CCA_THRESHOLD = 0x0025, + ACX_EVENT_MBOX_MASK = 0x0026, +#ifdef FW_RUNNING_AS_AP + ACX_DTIM_PERIOD = 0x0027, /* for AP only */ +#else + ACX_WR_TBTT_AND_DTIM = 0x0027, /* STA only */ +#endif + ACX_ACI_OPTION_CFG = 0x0029, /* OBSOLETE (for 1251)*/ + ACX_GPIO_CFG = 0x002A, /* Not used */ + ACX_GPIO_SET = 0x002B, /* Not used */ + ACX_PM_CFG = 0x002C, /* To Be Documented */ + ACX_CONN_MONIT_PARAMS = 0x002D, + ACX_AVERAGE_RSSI = 0x002E, /* Not used */ + ACX_CONS_TX_FAILURE = 0x002F, + ACX_BCN_DTIM_OPTIONS = 0x0031, + ACX_SG_ENABLE = 0x0032, + ACX_SG_CFG = 0x0033, + ACX_ANTENNA_DIVERSITY_CFG = 0x0035, /* To Be Documented */ + ACX_LOW_SNR = 0x0037, /* To Be Documented */ + ACX_BEACON_FILTER_TABLE = 0x0038, + ACX_ARP_IP_FILTER = 0x0039, + ACX_ROAMING_STATISTICS_TBL = 0x003B, + ACX_RATE_POLICY = 0x003D, + ACX_CTS_PROTECTION = 0x003E, + ACX_SLEEP_AUTH = 0x003F, + ACX_PREAMBLE_TYPE = 0x0040, + ACX_ERROR_CNT = 0x0041, + ACX_FW_GEN_FRAME_RATES = 0x0042, + ACX_IBSS_FILTER = 0x0044, + ACX_SERVICE_PERIOD_TIMEOUT = 0x0045, + ACX_TSF_INFO = 0x0046, + ACX_CONFIG_PS_WMM = 0x0049, + ACX_ENABLE_RX_DATA_FILTER = 0x004A, + ACX_SET_RX_DATA_FILTER = 0x004B, + ACX_GET_DATA_FILTER_STATISTICS = 0x004C, + ACX_POWER_LEVEL_TABLE = 0x004D, + ACX_BET_ENABLE = 0x0050, + DOT11_STATION_ID = 0x1001, + DOT11_RX_MSDU_LIFE_TIME = 0x1004, + DOT11_CUR_TX_PWR = 0x100D, + DOT11_DEFAULT_KEY = 0x1010, + DOT11_RX_DOT11_MODE = 0x1012, + DOT11_RTS_THRESHOLD = 0x1013, + DOT11_GROUP_ADDRESS_TBL = 0x1014, + + MAX_DOT11_IE = DOT11_GROUP_ADDRESS_TBL, + + MAX_IE = 0xFFFF +}; + + +int wl1251_acx_frame_rates(struct wl1251 *wl, u8 ctrl_rate, u8 ctrl_mod, + u8 mgt_rate, u8 mgt_mod); +int wl1251_acx_station_id(struct wl1251 *wl); +int wl1251_acx_default_key(struct wl1251 *wl, u8 key_id); +int wl1251_acx_wake_up_conditions(struct wl1251 *wl, u8 wake_up_event, + u8 listen_interval); +int wl1251_acx_sleep_auth(struct wl1251 *wl, u8 sleep_auth); +int wl1251_acx_fw_version(struct wl1251 *wl, char *buf, size_t len); +int wl1251_acx_tx_power(struct wl1251 *wl, int power); +int wl1251_acx_feature_cfg(struct wl1251 *wl); +int wl1251_acx_mem_map(struct wl1251 *wl, + struct acx_header *mem_map, size_t len); +int wl1251_acx_data_path_params(struct wl1251 *wl, + struct acx_data_path_params_resp *data_path); +int wl1251_acx_rx_msdu_life_time(struct wl1251 *wl, u32 life_time); +int wl1251_acx_rx_config(struct wl1251 *wl, u32 config, u32 filter); +int wl1251_acx_pd_threshold(struct wl1251 *wl); +int wl1251_acx_slot(struct wl1251 *wl, enum acx_slot_type slot_time); +int wl1251_acx_group_address_tbl(struct wl1251 *wl); +int wl1251_acx_service_period_timeout(struct wl1251 *wl); +int wl1251_acx_rts_threshold(struct wl1251 *wl, u16 rts_threshold); +int wl1251_acx_beacon_filter_opt(struct wl1251 *wl, bool enable_filter); +int wl1251_acx_beacon_filter_table(struct wl1251 *wl); +int wl1251_acx_conn_monit_params(struct wl1251 *wl); +int wl1251_acx_sg_enable(struct wl1251 *wl); +int wl1251_acx_sg_cfg(struct wl1251 *wl); +int wl1251_acx_cca_threshold(struct wl1251 *wl); +int wl1251_acx_bcn_dtim_options(struct wl1251 *wl); +int wl1251_acx_aid(struct wl1251 *wl, u16 aid); +int wl1251_acx_event_mbox_mask(struct wl1251 *wl, u32 event_mask); +int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type preamble); +int wl1251_acx_cts_protect(struct wl1251 *wl, + enum acx_ctsprotect_type ctsprotect); +int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats); +int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime); +int wl1251_acx_rate_policies(struct wl1251 *wl); +int wl1251_acx_mem_cfg(struct wl1251 *wl); +int wl1251_acx_wr_tbtt_and_dtim(struct wl1251 *wl, u16 tbtt, u8 dtim); +int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max, + u8 aifs, u16 txop); +int wl1251_acx_tid_cfg(struct wl1251 *wl, u8 queue, + enum wl1251_acx_channel_type type, + u8 tsid, enum wl1251_acx_ps_scheme ps_scheme, + enum wl1251_acx_ack_policy ack_policy); + +#endif /* __WL1251_ACX_H__ */ diff --git a/drivers/net/wireless/wl1251/boot.c b/drivers/net/wireless/wl1251/boot.c new file mode 100644 index 0000000..61572df --- /dev/null +++ b/drivers/net/wireless/wl1251/boot.c @@ -0,0 +1,557 @@ +/* + * This file is part of wl1251 + * + * Copyright (C) 2008 Nokia Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include + +#include "reg.h" +#include "boot.h" +#include "io.h" +#include "spi.h" +#include "event.h" +#include "acx.h" + +void wl1251_boot_target_enable_interrupts(struct wl1251 *wl) +{ + wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); + wl1251_reg_write32(wl, HI_CFG, HI_CFG_DEF_VAL); +} + +int wl1251_boot_soft_reset(struct wl1251 *wl) +{ + unsigned long timeout; + u32 boot_data; + + /* perform soft reset */ + wl1251_reg_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT); + + /* SOFT_RESET is self clearing */ + timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME); + while (1) { + boot_data = wl1251_reg_read32(wl, ACX_REG_SLV_SOFT_RESET); + wl1251_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data); + if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0) + break; + + if (time_after(jiffies, timeout)) { + /* 1.2 check pWhalBus->uSelfClearTime if the + * timeout was reached */ + wl1251_error("soft reset timeout"); + return -1; + } + + udelay(SOFT_RESET_STALL_TIME); + } + + /* disable Rx/Tx */ + wl1251_reg_write32(wl, ENABLE, 0x0); + + /* disable auto calibration on start*/ + wl1251_reg_write32(wl, SPARE_A2, 0xffff); + + return 0; +} + +int wl1251_boot_init_seq(struct wl1251 *wl) +{ + u32 scr_pad6, init_data, tmp, elp_cmd, ref_freq; + + /* + * col #1: INTEGER_DIVIDER + * col #2: FRACTIONAL_DIVIDER + * col #3: ATTN_BB + * col #4: ALPHA_BB + * col #5: STOP_TIME_BB + * col #6: BB_PLL_LOOP_FILTER + */ + static const u32 LUT[REF_FREQ_NUM][LUT_PARAM_NUM] = { + + { 83, 87381, 0xB, 5, 0xF00, 3}, /* REF_FREQ_19_2*/ + { 61, 141154, 0xB, 5, 0x1450, 2}, /* REF_FREQ_26_0*/ + { 41, 174763, 0xC, 6, 0x2D00, 1}, /* REF_FREQ_38_4*/ + { 40, 0, 0xC, 6, 0x2EE0, 1}, /* REF_FREQ_40_0*/ + { 47, 162280, 0xC, 6, 0x2760, 1} /* REF_FREQ_33_6 */ + }; + + /* read NVS params */ + scr_pad6 = wl1251_reg_read32(wl, SCR_PAD6); + wl1251_debug(DEBUG_BOOT, "scr_pad6 0x%x", scr_pad6); + + /* read ELP_CMD */ + elp_cmd = wl1251_reg_read32(wl, ELP_CMD); + wl1251_debug(DEBUG_BOOT, "elp_cmd 0x%x", elp_cmd); + + /* set the BB calibration time to be 300 usec (PLL_CAL_TIME) */ + ref_freq = scr_pad6 & 0x000000FF; + wl1251_debug(DEBUG_BOOT, "ref_freq 0x%x", ref_freq); + + wl1251_reg_write32(wl, PLL_CAL_TIME, 0x9); + + /* + * PG 1.2: set the clock buffer time to be 210 usec (CLK_BUF_TIME) + */ + wl1251_reg_write32(wl, CLK_BUF_TIME, 0x6); + + /* + * set the clock detect feature to work in the restart wu procedure + * (ELP_CFG_MODE[14]) and Select the clock source type + * (ELP_CFG_MODE[13:12]) + */ + tmp = ((scr_pad6 & 0x0000FF00) << 4) | 0x00004000; + wl1251_reg_write32(wl, ELP_CFG_MODE, tmp); + + /* PG 1.2: enable the BB PLL fix. Enable the PLL_LIMP_CLK_EN_CMD */ + elp_cmd |= 0x00000040; + wl1251_reg_write32(wl, ELP_CMD, elp_cmd); + + /* PG 1.2: Set the BB PLL stable time to be 1000usec + * (PLL_STABLE_TIME) */ + wl1251_reg_write32(wl, CFG_PLL_SYNC_CNT, 0x20); + + /* PG 1.2: read clock request time */ + init_data = wl1251_reg_read32(wl, CLK_REQ_TIME); + + /* + * PG 1.2: set the clock request time to be ref_clk_settling_time - + * 1ms = 4ms + */ + if (init_data > 0x21) + tmp = init_data - 0x21; + else + tmp = 0; + wl1251_reg_write32(wl, CLK_REQ_TIME, tmp); + + /* set BB PLL configurations in RF AFE */ + wl1251_reg_write32(wl, 0x003058cc, 0x4B5); + + /* set RF_AFE_REG_5 */ + wl1251_reg_write32(wl, 0x003058d4, 0x50); + + /* set RF_AFE_CTRL_REG_2 */ + wl1251_reg_write32(wl, 0x00305948, 0x11c001); + + /* + * change RF PLL and BB PLL divider for VCO clock and adjust VCO + * bais current(RF_AFE_REG_13) + */ + wl1251_reg_write32(wl, 0x003058f4, 0x1e); + + /* set BB PLL configurations */ + tmp = LUT[ref_freq][LUT_PARAM_INTEGER_DIVIDER] | 0x00017000; + wl1251_reg_write32(wl, 0x00305840, tmp); + + /* set fractional divider according to Appendix C-BB PLL + * Calculations + */ + tmp = LUT[ref_freq][LUT_PARAM_FRACTIONAL_DIVIDER]; + wl1251_reg_write32(wl, 0x00305844, tmp); + + /* set the initial data for the sigma delta */ + wl1251_reg_write32(wl, 0x00305848, 0x3039); + + /* + * set the accumulator attenuation value, calibration loop1 + * (alpha), calibration loop2 (beta), calibration loop3 (gamma) and + * the VCO gain + */ + tmp = (LUT[ref_freq][LUT_PARAM_ATTN_BB] << 16) | + (LUT[ref_freq][LUT_PARAM_ALPHA_BB] << 12) | 0x1; + wl1251_reg_write32(wl, 0x00305854, tmp); + + /* + * set the calibration stop time after holdoff time expires and set + * settling time HOLD_OFF_TIME_BB + */ + tmp = LUT[ref_freq][LUT_PARAM_STOP_TIME_BB] | 0x000A0000; + wl1251_reg_write32(wl, 0x00305858, tmp); + + /* + * set BB PLL Loop filter capacitor3- BB_C3[2:0] and set BB PLL + * constant leakage current to linearize PFD to 0uA - + * BB_ILOOPF[7:3] + */ + tmp = LUT[ref_freq][LUT_PARAM_BB_PLL_LOOP_FILTER] | 0x00000030; + wl1251_reg_write32(wl, 0x003058f8, tmp); + + /* + * set regulator output voltage for n divider to + * 1.35-BB_REFDIV[1:0], set charge pump current- BB_CPGAIN[4:2], + * set BB PLL Loop filter capacitor2- BB_C2[7:5], set gain of BB + * PLL auto-call to normal mode- BB_CALGAIN_3DB[8] + */ + wl1251_reg_write32(wl, 0x003058f0, 0x29); + + /* enable restart wakeup sequence (ELP_CMD[0]) */ + wl1251_reg_write32(wl, ELP_CMD, elp_cmd | 0x1); + + /* restart sequence completed */ + udelay(2000); + + return 0; +} + +static void wl1251_boot_set_ecpu_ctrl(struct wl1251 *wl, u32 flag) +{ + u32 cpu_ctrl; + + /* 10.5.0 run the firmware (I) */ + cpu_ctrl = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL); + + /* 10.5.1 run the firmware (II) */ + cpu_ctrl &= ~flag; + wl1251_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); +} + +int wl1251_boot_run_firmware(struct wl1251 *wl) +{ + int loop, ret; + u32 chip_id, acx_intr; + + wl1251_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); + + chip_id = wl1251_reg_read32(wl, CHIP_ID_B); + + wl1251_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); + + if (chip_id != wl->chip_id) { + wl1251_error("chip id doesn't match after firmware boot"); + return -EIO; + } + + /* wait for init to complete */ + loop = 0; + while (loop++ < INIT_LOOP) { + udelay(INIT_LOOP_DELAY); + acx_intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); + + if (acx_intr == 0xffffffff) { + wl1251_error("error reading hardware complete " + "init indication"); + return -EIO; + } + /* check that ACX_INTR_INIT_COMPLETE is enabled */ + else if (acx_intr & WL1251_ACX_INTR_INIT_COMPLETE) { + wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK, + WL1251_ACX_INTR_INIT_COMPLETE); + break; + } + } + + if (loop > INIT_LOOP) { + wl1251_error("timeout waiting for the hardware to " + "complete initialization"); + return -EIO; + } + + /* get hardware config command mail box */ + wl->cmd_box_addr = wl1251_reg_read32(wl, REG_COMMAND_MAILBOX_PTR); + + /* get hardware config event mail box */ + wl->event_box_addr = wl1251_reg_read32(wl, REG_EVENT_MAILBOX_PTR); + + /* set the working partition to its "running" mode offset */ + wl1251_set_partition(wl, WL1251_PART_WORK_MEM_START, + WL1251_PART_WORK_MEM_SIZE, + WL1251_PART_WORK_REG_START, + WL1251_PART_WORK_REG_SIZE); + + wl1251_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x", + wl->cmd_box_addr, wl->event_box_addr); + + wl1251_acx_fw_version(wl, wl->fw_ver, sizeof(wl->fw_ver)); + + /* + * in case of full asynchronous mode the firmware event must be + * ready to receive event from the command mailbox + */ + + /* enable gpio interrupts */ + wl1251_enable_interrupts(wl); + + /* Enable target's interrupts */ + wl->intr_mask = WL1251_ACX_INTR_RX0_DATA | + WL1251_ACX_INTR_RX1_DATA | + WL1251_ACX_INTR_TX_RESULT | + WL1251_ACX_INTR_EVENT_A | + WL1251_ACX_INTR_EVENT_B | + WL1251_ACX_INTR_INIT_COMPLETE; + wl1251_boot_target_enable_interrupts(wl); + + wl->event_mask = SCAN_COMPLETE_EVENT_ID | BSS_LOSE_EVENT_ID | + SYNCHRONIZATION_TIMEOUT_EVENT_ID | + ROAMING_TRIGGER_LOW_RSSI_EVENT_ID | + ROAMING_TRIGGER_REGAINED_RSSI_EVENT_ID | + REGAINED_BSS_EVENT_ID | BT_PTA_SENSE_EVENT_ID | + BT_PTA_PREDICTION_EVENT_ID | JOIN_EVENT_COMPLETE_ID; + + ret = wl1251_event_unmask(wl); + if (ret < 0) { + wl1251_error("EVENT mask setting failed"); + return ret; + } + + wl1251_event_mbox_config(wl); + + /* firmware startup completed */ + return 0; +} + +static int wl1251_boot_upload_firmware(struct wl1251 *wl) +{ + int addr, chunk_num, partition_limit; + size_t fw_data_len, len; + u8 *p, *buf; + + /* whal_FwCtrl_LoadFwImageSm() */ + + wl1251_debug(DEBUG_BOOT, "chip id before fw upload: 0x%x", + wl1251_reg_read32(wl, CHIP_ID_B)); + + /* 10.0 check firmware length and set partition */ + fw_data_len = (wl->fw[4] << 24) | (wl->fw[5] << 16) | + (wl->fw[6] << 8) | (wl->fw[7]); + + wl1251_debug(DEBUG_BOOT, "fw_data_len %zu chunk_size %d", fw_data_len, + CHUNK_SIZE); + + if ((fw_data_len % 4) != 0) { + wl1251_error("firmware length not multiple of four"); + return -EIO; + } + + buf = kmalloc(CHUNK_SIZE, GFP_KERNEL); + if (!buf) { + wl1251_error("allocation for firmware upload chunk failed"); + return -ENOMEM; + } + + wl1251_set_partition(wl, WL1251_PART_DOWN_MEM_START, + WL1251_PART_DOWN_MEM_SIZE, + WL1251_PART_DOWN_REG_START, + WL1251_PART_DOWN_REG_SIZE); + + /* 10.1 set partition limit and chunk num */ + chunk_num = 0; + partition_limit = WL1251_PART_DOWN_MEM_SIZE; + + while (chunk_num < fw_data_len / CHUNK_SIZE) { + /* 10.2 update partition, if needed */ + addr = WL1251_PART_DOWN_MEM_START + + (chunk_num + 2) * CHUNK_SIZE; + if (addr > partition_limit) { + addr = WL1251_PART_DOWN_MEM_START + + chunk_num * CHUNK_SIZE; + partition_limit = chunk_num * CHUNK_SIZE + + WL1251_PART_DOWN_MEM_SIZE; + wl1251_set_partition(wl, + addr, + WL1251_PART_DOWN_MEM_SIZE, + WL1251_PART_DOWN_REG_START, + WL1251_PART_DOWN_REG_SIZE); + } + + /* 10.3 upload the chunk */ + addr = WL1251_PART_DOWN_MEM_START + chunk_num * CHUNK_SIZE; + p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; + wl1251_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", + p, addr); + + /* need to copy the chunk for dma */ + len = CHUNK_SIZE; + memcpy(buf, p, len); + wl1251_mem_write(wl, addr, buf, len); + + chunk_num++; + } + + /* 10.4 upload the last chunk */ + addr = WL1251_PART_DOWN_MEM_START + chunk_num * CHUNK_SIZE; + p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; + + /* need to copy the chunk for dma */ + len = fw_data_len % CHUNK_SIZE; + memcpy(buf, p, len); + + wl1251_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x", + len, p, addr); + wl1251_mem_write(wl, addr, buf, len); + + kfree(buf); + + return 0; +} + +static int wl1251_boot_upload_nvs(struct wl1251 *wl) +{ + size_t nvs_len, nvs_bytes_written, burst_len; + int nvs_start, i; + u32 dest_addr, val; + u8 *nvs_ptr, *nvs; + + nvs = wl->nvs; + if (nvs == NULL) + return -ENODEV; + + nvs_ptr = nvs; + + nvs_len = wl->nvs_len; + nvs_start = wl->fw_len; + + /* + * Layout before the actual NVS tables: + * 1 byte : burst length. + * 2 bytes: destination address. + * n bytes: data to burst copy. + * + * This is ended by a 0 length, then the NVS tables. + */ + + while (nvs_ptr[0]) { + burst_len = nvs_ptr[0]; + dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8)); + + /* We move our pointer to the data */ + nvs_ptr += 3; + + for (i = 0; i < burst_len; i++) { + val = (nvs_ptr[0] | (nvs_ptr[1] << 8) + | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); + + wl1251_debug(DEBUG_BOOT, + "nvs burst write 0x%x: 0x%x", + dest_addr, val); + wl1251_mem_write32(wl, dest_addr, val); + + nvs_ptr += 4; + dest_addr += 4; + } + } + + /* + * We've reached the first zero length, the first NVS table + * is 7 bytes further. + */ + nvs_ptr += 7; + nvs_len -= nvs_ptr - nvs; + nvs_len = ALIGN(nvs_len, 4); + + /* Now we must set the partition correctly */ + wl1251_set_partition(wl, nvs_start, + WL1251_PART_DOWN_MEM_SIZE, + WL1251_PART_DOWN_REG_START, + WL1251_PART_DOWN_REG_SIZE); + + /* And finally we upload the NVS tables */ + nvs_bytes_written = 0; + while (nvs_bytes_written < nvs_len) { + val = (nvs_ptr[0] | (nvs_ptr[1] << 8) + | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); + + val = cpu_to_le32(val); + + wl1251_debug(DEBUG_BOOT, + "nvs write table 0x%x: 0x%x", + nvs_start, val); + wl1251_mem_write32(wl, nvs_start, val); + + nvs_ptr += 4; + nvs_bytes_written += 4; + nvs_start += 4; + } + + return 0; +} + +int wl1251_boot(struct wl1251 *wl) +{ + int ret = 0, minor_minor_e2_ver; + u32 tmp, boot_data; + + /* halt embedded ARM CPU while loading firmware */ + wl1251_reg_write32(wl, ACX_REG_ECPU_CONTROL, ECPU_CONTROL_HALT); + + ret = wl1251_boot_soft_reset(wl); + if (ret < 0) + goto out; + + /* 2. start processing NVS file */ + if (wl->use_eeprom) { + wl1251_reg_write32(wl, ACX_REG_EE_START, START_EEPROM_MGR); + /* Wait for EEPROM NVS burst read to complete */ + msleep(40); + wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, USE_EEPROM); + } else { + ret = wl1251_boot_upload_nvs(wl); + if (ret < 0) + goto out; + + /* write firmware's last address (ie. it's length) to + * ACX_EEPROMLESS_IND_REG */ + wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len); + } + + /* 6. read the EEPROM parameters */ + tmp = wl1251_reg_read32(wl, SCR_PAD2); + + /* 7. read bootdata */ + wl->boot_attr.radio_type = (tmp & 0x0000FF00) >> 8; + wl->boot_attr.major = (tmp & 0x00FF0000) >> 16; + tmp = wl1251_reg_read32(wl, SCR_PAD3); + + /* 8. check bootdata and call restart sequence */ + wl->boot_attr.minor = (tmp & 0x00FF0000) >> 16; + minor_minor_e2_ver = (tmp & 0xFF000000) >> 24; + + wl1251_debug(DEBUG_BOOT, "radioType 0x%x majorE2Ver 0x%x " + "minorE2Ver 0x%x minor_minor_e2_ver 0x%x", + wl->boot_attr.radio_type, wl->boot_attr.major, + wl->boot_attr.minor, minor_minor_e2_ver); + + ret = wl1251_boot_init_seq(wl); + if (ret < 0) + goto out; + + /* 9. NVS processing done */ + boot_data = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL); + + wl1251_debug(DEBUG_BOOT, "halt boot_data 0x%x", boot_data); + + /* 10. check that ECPU_CONTROL_HALT bits are set in + * pWhalBus->uBootData and start uploading firmware + */ + if ((boot_data & ECPU_CONTROL_HALT) == 0) { + wl1251_error("boot failed, ECPU_CONTROL_HALT not set"); + ret = -EIO; + goto out; + } + + ret = wl1251_boot_upload_firmware(wl); + if (ret < 0) + goto out; + + /* 10.5 start firmware */ + ret = wl1251_boot_run_firmware(wl); + if (ret < 0) + goto out; + +out: + return ret; +} diff --git a/drivers/net/wireless/wl1251/boot.h b/drivers/net/wireless/wl1251/boot.h new file mode 100644 index 0000000..7661bc5 --- /dev/null +++ b/drivers/net/wireless/wl1251/boot.h @@ -0,0 +1,39 @@ +/* + * This file is part of wl1251 + * + * Copyright (C) 2008 Nokia Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __BOOT_H__ +#define __BOOT_H__ + +#include "wl1251.h" + +int wl1251_boot_soft_reset(struct wl1251 *wl); +int wl1251_boot_init_seq(struct wl1251 *wl); +int wl1251_boot_run_firmware(struct wl1251 *wl); +void wl1251_boot_target_enable_interrupts(struct wl1251 *wl); +int wl1251_boot(struct wl1251 *wl); + +/* number of times we try to read the INIT interrupt */ +#define INIT_LOOP 20000 + +/* delay between retries */ +#define INIT_LOOP_DELAY 50 + +#endif diff --git a/drivers/net/wireless/wl1251/cmd.c b/drivers/net/wireless/wl1251/cmd.c new file mode 100644 index 0000000..0ade4bd --- /dev/null +++ b/drivers/net/wireless/wl1251/cmd.c @@ -0,0 +1,496 @@ +#include "cmd.h" + +#include +#include +#include + +#include "wl1251.h" +#include "reg.h" +#include "io.h" +#include "ps.h" +#include "acx.h" + +/** + * send command to firmware + * + * @wl: wl struct + * @id: command id + * @buf: buffer containing the command, must work with dma + * @len: length of the buffer + */ +int wl1251_cmd_send(struct wl1251 *wl, u16 id, void *buf, size_t len) +{ + struct wl1251_cmd_header *cmd; + unsigned long timeout; + u32 intr; + int ret = 0; + + cmd = buf; + cmd->id = id; + cmd->status = 0; + + WARN_ON(len % 4 != 0); + + wl1251_mem_write(wl, wl->cmd_box_addr, buf, len); + + wl1251_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); + + timeout = jiffies + msecs_to_jiffies(WL1251_COMMAND_TIMEOUT); + + intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); + while (!(intr & WL1251_ACX_INTR_CMD_COMPLETE)) { + if (time_after(jiffies, timeout)) { + wl1251_error("command complete timeout"); + ret = -ETIMEDOUT; + goto out; + } + + msleep(1); + + intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); + } + + wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK, + WL1251_ACX_INTR_CMD_COMPLETE); + +out: + return ret; +} + +/** + * send test command to firmware + * + * @wl: wl struct + * @buf: buffer containing the command, with all headers, must work with dma + * @len: length of the buffer + * @answer: is answer needed + */ +int wl1251_cmd_test(struct wl1251 *wl, void *buf, size_t buf_len, u8 answer) +{ + int ret; + + wl1251_debug(DEBUG_CMD, "cmd test"); + + ret = wl1251_cmd_send(wl, CMD_TEST, buf, buf_len); + + if (ret < 0) { + wl1251_warning("TEST command failed"); + return ret; + } + + if (answer) { + struct wl1251_command *cmd_answer; + + /* + * The test command got in, we can read the answer. + * The answer would be a wl1251_command, where the + * parameter array contains the actual answer. + */ + wl1251_mem_read(wl, wl->cmd_box_addr, buf, buf_len); + + cmd_answer = buf; + + if (cmd_answer->header.status != CMD_STATUS_SUCCESS) + wl1251_error("TEST command answer error: %d", + cmd_answer->header.status); + } + + return 0; +} + +/** + * read acx from firmware + * + * @wl: wl struct + * @id: acx id + * @buf: buffer for the response, including all headers, must work with dma + * @len: lenght of buf + */ +int wl1251_cmd_interrogate(struct wl1251 *wl, u16 id, void *buf, size_t len) +{ + struct acx_header *acx = buf; + int ret; + + wl1251_debug(DEBUG_CMD, "cmd interrogate"); + + acx->id = id; + + /* payload length, does not include any headers */ + acx->len = len - sizeof(*acx); + + ret = wl1251_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx)); + if (ret < 0) { + wl1251_error("INTERROGATE command failed"); + goto out; + } + + /* the interrogate command got in, we can read the answer */ + wl1251_mem_read(wl, wl->cmd_box_addr, buf, len); + + acx = buf; + if (acx->cmd.status != CMD_STATUS_SUCCESS) + wl1251_error("INTERROGATE command error: %d", + acx->cmd.status); + +out: + return ret; +} + +/** + * write acx value to firmware + * + * @wl: wl struct + * @id: acx id + * @buf: buffer containing acx, including all headers, must work with dma + * @len: length of buf + */ +int wl1251_cmd_configure(struct wl1251 *wl, u16 id, void *buf, size_t len) +{ + struct acx_header *acx = buf; + int ret; + + wl1251_debug(DEBUG_CMD, "cmd configure"); + + acx->id = id; + + /* payload length, does not include any headers */ + acx->len = len - sizeof(*acx); + + ret = wl1251_cmd_send(wl, CMD_CONFIGURE, acx, len); + if (ret < 0) { + wl1251_warning("CONFIGURE command NOK"); + return ret; + } + + return 0; +} + +int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity, + void *bitmap, u16 bitmap_len, u8 bitmap_control) +{ + struct wl1251_cmd_vbm_update *vbm; + int ret; + + wl1251_debug(DEBUG_CMD, "cmd vbm"); + + vbm = kzalloc(sizeof(*vbm), GFP_KERNEL); + if (!vbm) { + ret = -ENOMEM; + goto out; + } + + /* Count and period will be filled by the target */ + vbm->tim.bitmap_ctrl = bitmap_control; + if (bitmap_len > PARTIAL_VBM_MAX) { + wl1251_warning("cmd vbm len is %d B, truncating to %d", + bitmap_len, PARTIAL_VBM_MAX); + bitmap_len = PARTIAL_VBM_MAX; + } + memcpy(vbm->tim.pvb_field, bitmap, bitmap_len); + vbm->tim.identity = identity; + vbm->tim.length = bitmap_len + 3; + + vbm->len = cpu_to_le16(bitmap_len + 5); + + ret = wl1251_cmd_send(wl, CMD_VBM, vbm, sizeof(*vbm)); + if (ret < 0) { + wl1251_error("VBM command failed"); + goto out; + } + +out: + kfree(vbm); + return ret; +} + +int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable) +{ + struct cmd_enabledisable_path *cmd; + int ret; + u16 cmd_rx, cmd_tx; + + wl1251_debug(DEBUG_CMD, "cmd data path"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->channel = channel; + + if (enable) { + cmd_rx = CMD_ENABLE_RX; + cmd_tx = CMD_ENABLE_TX; + } else { + cmd_rx = CMD_DISABLE_RX; + cmd_tx = CMD_DISABLE_TX; + } + + ret = wl1251_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd)); + if (ret < 0) { + wl1251_error("rx %s cmd for channel %d failed", + enable ? "start" : "stop", channel); + goto out; + } + + wl1251_debug(DEBUG_BOOT, "rx %s cmd channel %d", + enable ? "start" : "stop", channel); + + ret = wl1251_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd)); + if (ret < 0) { + wl1251_error("tx %s cmd for channel %d failed", + enable ? "start" : "stop", channel); + return ret; + } + + wl1251_debug(DEBUG_BOOT, "tx %s cmd channel %d", + enable ? "start" : "stop", channel); + +out: + kfree(cmd); + return ret; +} + +int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel, + u16 beacon_interval, u8 dtim_interval) +{ + struct cmd_join *join; + int ret, i; + u8 *bssid; + + join = kzalloc(sizeof(*join), GFP_KERNEL); + if (!join) { + ret = -ENOMEM; + goto out; + } + + wl1251_debug(DEBUG_CMD, "cmd join%s ch %d %d/%d", + bss_type == BSS_TYPE_IBSS ? " ibss" : "", + channel, beacon_interval, dtim_interval); + + /* Reverse order BSSID */ + bssid = (u8 *) &join->bssid_lsb; + for (i = 0; i < ETH_ALEN; i++) + bssid[i] = wl->bssid[ETH_ALEN - i - 1]; + + join->rx_config_options = wl->rx_config; + join->rx_filter_options = wl->rx_filter; + + /* + * FIXME: disable temporarily all filters because after commit + * 9cef8737 "mac80211: fix managed mode BSSID handling" broke + * association. The filter logic needs to be implemented properly + * and once that is done, this hack can be removed. + */ + join->rx_config_options = 0; + join->rx_filter_options = WL1251_DEFAULT_RX_FILTER; + + join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS | + RATE_MASK_5_5MBPS | RATE_MASK_11MBPS; + + join->beacon_interval = beacon_interval; + join->dtim_interval = dtim_interval; + join->bss_type = bss_type; + join->channel = channel; + join->ctrl = JOIN_CMD_CTRL_TX_FLUSH; + + ret = wl1251_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join)); + if (ret < 0) { + wl1251_error("failed to initiate cmd join"); + goto out; + } + +out: + kfree(join); + return ret; +} + +int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode) +{ + struct wl1251_cmd_ps_params *ps_params = NULL; + int ret = 0; + + wl1251_debug(DEBUG_CMD, "cmd set ps mode"); + + ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL); + if (!ps_params) { + ret = -ENOMEM; + goto out; + } + + ps_params->ps_mode = ps_mode; + ps_params->send_null_data = 1; + ps_params->retries = 5; + ps_params->hang_over_period = 128; + ps_params->null_data_rate = 1; /* 1 Mbps */ + + ret = wl1251_cmd_send(wl, CMD_SET_PS_MODE, ps_params, + sizeof(*ps_params)); + if (ret < 0) { + wl1251_error("cmd set_ps_mode failed"); + goto out; + } + +out: + kfree(ps_params); + return ret; +} + +int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer, + size_t len) +{ + struct cmd_read_write_memory *cmd; + int ret = 0; + + wl1251_debug(DEBUG_CMD, "cmd read memory"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + WARN_ON(len > MAX_READ_SIZE); + len = min_t(size_t, len, MAX_READ_SIZE); + + cmd->addr = addr; + cmd->size = len; + + ret = wl1251_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd)); + if (ret < 0) { + wl1251_error("read memory command failed: %d", ret); + goto out; + } + + /* the read command got in, we can now read the answer */ + wl1251_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd)); + + if (cmd->header.status != CMD_STATUS_SUCCESS) + wl1251_error("error in read command result: %d", + cmd->header.status); + + memcpy(answer, cmd->value, len); + +out: + kfree(cmd); + return ret; +} + +int wl1251_cmd_template_set(struct wl1251 *wl, u16 cmd_id, + void *buf, size_t buf_len) +{ + struct wl1251_cmd_packet_template *cmd; + size_t cmd_len; + int ret = 0; + + wl1251_debug(DEBUG_CMD, "cmd template %d", cmd_id); + + WARN_ON(buf_len > WL1251_MAX_TEMPLATE_SIZE); + buf_len = min_t(size_t, buf_len, WL1251_MAX_TEMPLATE_SIZE); + cmd_len = ALIGN(sizeof(*cmd) + buf_len, 4); + + cmd = kzalloc(cmd_len, GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->size = cpu_to_le16(buf_len); + + if (buf) + memcpy(cmd->data, buf, buf_len); + + ret = wl1251_cmd_send(wl, cmd_id, cmd, cmd_len); + if (ret < 0) { + wl1251_warning("cmd set_template failed: %d", ret); + goto out; + } + +out: + kfree(cmd); + return ret; +} + +int wl1251_cmd_scan(struct wl1251 *wl, u8 *ssid, size_t ssid_len, + struct ieee80211_channel *channels[], + unsigned int n_channels, unsigned int n_probes) +{ + struct wl1251_cmd_scan *cmd; + int i, ret = 0; + + wl1251_debug(DEBUG_CMD, "cmd scan"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cmd->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD); + cmd->params.rx_filter_options = cpu_to_le32(CFG_RX_PRSP_EN | + CFG_RX_MGMT_EN | + CFG_RX_BCN_EN); + cmd->params.scan_options = 0; + cmd->params.num_channels = n_channels; + cmd->params.num_probe_requests = n_probes; + cmd->params.tx_rate = cpu_to_le16(1 << 1); /* 2 Mbps */ + cmd->params.tid_trigger = 0; + + for (i = 0; i < n_channels; i++) { + cmd->channels[i].min_duration = + cpu_to_le32(WL1251_SCAN_MIN_DURATION); + cmd->channels[i].max_duration = + cpu_to_le32(WL1251_SCAN_MAX_DURATION); + memset(&cmd->channels[i].bssid_lsb, 0xff, 4); + memset(&cmd->channels[i].bssid_msb, 0xff, 2); + cmd->channels[i].early_termination = 0; + cmd->channels[i].tx_power_att = 0; + cmd->channels[i].channel = channels[i]->hw_value; + } + + cmd->params.ssid_len = ssid_len; + if (ssid) + memcpy(cmd->params.ssid, ssid, ssid_len); + + ret = wl1251_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd)); + if (ret < 0) { + wl1251_error("cmd scan failed: %d", ret); + goto out; + } + + wl1251_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd)); + + if (cmd->header.status != CMD_STATUS_SUCCESS) { + wl1251_error("cmd scan status wasn't success: %d", + cmd->header.status); + ret = -EIO; + goto out; + } + +out: + kfree(cmd); + return ret; +} + +int wl1251_cmd_trigger_scan_to(struct wl1251 *wl, u32 timeout) +{ + struct wl1251_cmd_trigger_scan_to *cmd; + int ret; + + wl1251_debug(DEBUG_CMD, "cmd trigger scan to"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cmd->timeout = timeout; + + ret = wl1251_cmd_send(wl, CMD_TRIGGER_SCAN_TO, cmd, sizeof(*cmd)); + if (ret < 0) { + wl1251_error("cmd trigger scan to failed: %d", ret); + goto out; + } + +out: + kfree(cmd); + return ret; +} diff --git a/drivers/net/wireless/wl1251/cmd.h b/drivers/net/wireless/wl1251/cmd.h new file mode 100644 index 0000000..e5c74c6 --- /dev/null +++ b/drivers/net/wireless/wl1251/cmd.h @@ -0,0 +1,415 @@ +/* + * This file is part of wl1251 + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL1251_CMD_H__ +#define __WL1251_CMD_H__ + +#include "wl1251.h" + +#include + +struct acx_header; + +int wl1251_cmd_send(struct wl1251 *wl, u16 type, void *buf, size_t buf_len); +int wl1251_cmd_test(struct wl1251 *wl, void *buf, size_t buf_len, u8 answer); +int wl1251_cmd_interrogate(struct wl1251 *wl, u16 id, void *buf, size_t len); +int wl1251_cmd_configure(struct wl1251 *wl, u16 id, void *buf, size_t len); +int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity, + void *bitmap, u16 bitmap_len, u8 bitmap_control); +int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable); +int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel, + u16 beacon_interval, u8 dtim_interval); +int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode); +int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer, + size_t len); +int wl1251_cmd_template_set(struct wl1251 *wl, u16 cmd_id, + void *buf, size_t buf_len); +int wl1251_cmd_scan(struct wl1251 *wl, u8 *ssid, size_t ssid_len, + struct ieee80211_channel *channels[], + unsigned int n_channels, unsigned int n_probes); +int wl1251_cmd_trigger_scan_to(struct wl1251 *wl, u32 timeout); + +/* unit ms */ +#define WL1251_COMMAND_TIMEOUT 2000 + +enum wl1251_commands { + CMD_RESET = 0, + CMD_INTERROGATE = 1, /*use this to read information elements*/ + CMD_CONFIGURE = 2, /*use this to write information elements*/ + CMD_ENABLE_RX = 3, + CMD_ENABLE_TX = 4, + CMD_DISABLE_RX = 5, + CMD_DISABLE_TX = 6, + CMD_SCAN = 8, + CMD_STOP_SCAN = 9, + CMD_VBM = 10, + CMD_START_JOIN = 11, + CMD_SET_KEYS = 12, + CMD_READ_MEMORY = 13, + CMD_WRITE_MEMORY = 14, + CMD_BEACON = 19, + CMD_PROBE_RESP = 20, + CMD_NULL_DATA = 21, + CMD_PROBE_REQ = 22, + CMD_TEST = 23, + CMD_RADIO_CALIBRATE = 25, /* OBSOLETE */ + CMD_ENABLE_RX_PATH = 27, /* OBSOLETE */ + CMD_NOISE_HIST = 28, + CMD_RX_RESET = 29, + CMD_PS_POLL = 30, + CMD_QOS_NULL_DATA = 31, + CMD_LNA_CONTROL = 32, + CMD_SET_BCN_MODE = 33, + CMD_MEASUREMENT = 34, + CMD_STOP_MEASUREMENT = 35, + CMD_DISCONNECT = 36, + CMD_SET_PS_MODE = 37, + CMD_CHANNEL_SWITCH = 38, + CMD_STOP_CHANNEL_SWICTH = 39, + CMD_AP_DISCOVERY = 40, + CMD_STOP_AP_DISCOVERY = 41, + CMD_SPS_SCAN = 42, + CMD_STOP_SPS_SCAN = 43, + CMD_HEALTH_CHECK = 45, + CMD_DEBUG = 46, + CMD_TRIGGER_SCAN_TO = 47, + + NUM_COMMANDS, + MAX_COMMAND_ID = 0xFFFF, +}; + +#define MAX_CMD_PARAMS 572 + +struct wl1251_cmd_header { + u16 id; + u16 status; + /* payload */ + u8 data[0]; +} __packed; + +struct wl1251_command { + struct wl1251_cmd_header header; + u8 parameters[MAX_CMD_PARAMS]; +} __packed; + +enum { + CMD_MAILBOX_IDLE = 0, + CMD_STATUS_SUCCESS = 1, + CMD_STATUS_UNKNOWN_CMD = 2, + CMD_STATUS_UNKNOWN_IE = 3, + CMD_STATUS_REJECT_MEAS_SG_ACTIVE = 11, + CMD_STATUS_RX_BUSY = 13, + CMD_STATUS_INVALID_PARAM = 14, + CMD_STATUS_TEMPLATE_TOO_LARGE = 15, + CMD_STATUS_OUT_OF_MEMORY = 16, + CMD_STATUS_STA_TABLE_FULL = 17, + CMD_STATUS_RADIO_ERROR = 18, + CMD_STATUS_WRONG_NESTING = 19, + CMD_STATUS_TIMEOUT = 21, /* Driver internal use.*/ + CMD_STATUS_FW_RESET = 22, /* Driver internal use.*/ + MAX_COMMAND_STATUS = 0xff +}; + + +/* + * CMD_READ_MEMORY + * + * The host issues this command to read the WiLink device memory/registers. + * + * Note: The Base Band address has special handling (16 bits registers and + * addresses). For more information, see the hardware specification. + */ +/* + * CMD_WRITE_MEMORY + * + * The host issues this command to write the WiLink device memory/registers. + * + * The Base Band address has special handling (16 bits registers and + * addresses). For more information, see the hardware specification. + */ +#define MAX_READ_SIZE 256 + +struct cmd_read_write_memory { + struct wl1251_cmd_header header; + + /* The address of the memory to read from or write to.*/ + u32 addr; + + /* The amount of data in bytes to read from or write to the WiLink + * device.*/ + u32 size; + + /* The actual value read from or written to the Wilink. The source + of this field is the Host in WRITE command or the Wilink in READ + command. */ + u8 value[MAX_READ_SIZE]; +} __packed; + +#define CMDMBOX_HEADER_LEN 4 +#define CMDMBOX_INFO_ELEM_HEADER_LEN 4 + +#define WL1251_SCAN_MIN_DURATION 30000 +#define WL1251_SCAN_MAX_DURATION 60000 + +#define WL1251_SCAN_NUM_PROBES 3 + +struct wl1251_scan_parameters { + __le32 rx_config_options; + __le32 rx_filter_options; + + /* + * Scan options: + * bit 0: When this bit is set, passive scan. + * bit 1: Band, when this bit is set we scan + * in the 5Ghz band. + * bit 2: voice mode, 0 for normal scan. + * bit 3: scan priority, 1 for high priority. + */ + __le16 scan_options; + + /* Number of channels to scan */ + u8 num_channels; + + /* Number opf probe requests to send, per channel */ + u8 num_probe_requests; + + /* Rate and modulation for probe requests */ + __le16 tx_rate; + + u8 tid_trigger; + u8 ssid_len; + u8 ssid[32]; + +} __packed; + +struct wl1251_scan_ch_parameters { + __le32 min_duration; /* in TU */ + __le32 max_duration; /* in TU */ + u32 bssid_lsb; + u16 bssid_msb; + + /* + * bits 0-3: Early termination count. + * bits 4-5: Early termination condition. + */ + u8 early_termination; + + u8 tx_power_att; + u8 channel; + u8 pad[3]; +} __packed; + +/* SCAN parameters */ +#define SCAN_MAX_NUM_OF_CHANNELS 16 + +struct wl1251_cmd_scan { + struct wl1251_cmd_header header; + + struct wl1251_scan_parameters params; + struct wl1251_scan_ch_parameters channels[SCAN_MAX_NUM_OF_CHANNELS]; +} __packed; + +enum { + BSS_TYPE_IBSS = 0, + BSS_TYPE_STA_BSS = 2, + BSS_TYPE_AP_BSS = 3, + MAX_BSS_TYPE = 0xFF +}; + +#define JOIN_CMD_CTRL_TX_FLUSH 0x80 /* Firmware flushes all Tx */ +#define JOIN_CMD_CTRL_EARLY_WAKEUP_ENABLE 0x01 /* Early wakeup time */ + + +struct cmd_join { + struct wl1251_cmd_header header; + + u32 bssid_lsb; + u16 bssid_msb; + u16 beacon_interval; /* in TBTTs */ + u32 rx_config_options; + u32 rx_filter_options; + + /* + * The target uses this field to determine the rate at + * which to transmit control frame responses (such as + * ACK or CTS frames). + */ + u16 basic_rate_set; + u8 dtim_interval; + u8 tx_ctrl_frame_rate; /* OBSOLETE */ + u8 tx_ctrl_frame_mod; /* OBSOLETE */ + /* + * bits 0-2: This bitwise field specifies the type + * of BSS to start or join (BSS_TYPE_*). + * bit 4: Band - The radio band in which to join + * or start. + * 0 - 2.4GHz band + * 1 - 5GHz band + * bits 3, 5-7: Reserved + */ + u8 bss_type; + u8 channel; + u8 ssid_len; + u8 ssid[IW_ESSID_MAX_SIZE]; + u8 ctrl; /* JOIN_CMD_CTRL_* */ + u8 tx_mgt_frame_rate; /* OBSOLETE */ + u8 tx_mgt_frame_mod; /* OBSOLETE */ + u8 reserved; +} __packed; + +struct cmd_enabledisable_path { + struct wl1251_cmd_header header; + + u8 channel; + u8 padding[3]; +} __packed; + +#define WL1251_MAX_TEMPLATE_SIZE 300 + +struct wl1251_cmd_packet_template { + struct wl1251_cmd_header header; + + __le16 size; + u8 data[0]; +} __packed; + +#define TIM_ELE_ID 5 +#define PARTIAL_VBM_MAX 251 + +struct wl1251_tim { + u8 identity; + u8 length; + u8 dtim_count; + u8 dtim_period; + u8 bitmap_ctrl; + u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */ +} __packed; + +/* Virtual Bit Map update */ +struct wl1251_cmd_vbm_update { + struct wl1251_cmd_header header; + __le16 len; + u8 padding[2]; + struct wl1251_tim tim; +} __packed; + +enum wl1251_cmd_ps_mode { + STATION_ACTIVE_MODE, + STATION_POWER_SAVE_MODE +}; + +struct wl1251_cmd_ps_params { + struct wl1251_cmd_header header; + + u8 ps_mode; /* STATION_* */ + u8 send_null_data; /* Do we have to send NULL data packet ? */ + u8 retries; /* Number of retires for the initial NULL data packet */ + + /* + * TUs during which the target stays awake after switching + * to power save mode. + */ + u8 hang_over_period; + u16 null_data_rate; + u8 pad[2]; +} __packed; + +struct wl1251_cmd_trigger_scan_to { + struct wl1251_cmd_header header; + + u32 timeout; +} __packed; + +/* HW encryption keys */ +#define NUM_ACCESS_CATEGORIES_COPY 4 +#define MAX_KEY_SIZE 32 + +/* When set, disable HW encryption */ +#define DF_ENCRYPTION_DISABLE 0x01 +/* When set, disable HW decryption */ +#define DF_SNIFF_MODE_ENABLE 0x80 + +enum wl1251_cmd_key_action { + KEY_ADD_OR_REPLACE = 1, + KEY_REMOVE = 2, + KEY_SET_ID = 3, + MAX_KEY_ACTION = 0xffff, +}; + +enum wl1251_cmd_key_type { + KEY_WEP_DEFAULT = 0, + KEY_WEP_ADDR = 1, + KEY_AES_GROUP = 4, + KEY_AES_PAIRWISE = 5, + KEY_WEP_GROUP = 6, + KEY_TKIP_MIC_GROUP = 10, + KEY_TKIP_MIC_PAIRWISE = 11, +}; + +/* + * + * key_type_e key size key format + * ---------- --------- ---------- + * 0x00 5, 13, 29 Key data + * 0x01 5, 13, 29 Key data + * 0x04 16 16 bytes of key data + * 0x05 16 16 bytes of key data + * 0x0a 32 16 bytes of TKIP key data + * 8 bytes of RX MIC key data + * 8 bytes of TX MIC key data + * 0x0b 32 16 bytes of TKIP key data + * 8 bytes of RX MIC key data + * 8 bytes of TX MIC key data + * + */ + +struct wl1251_cmd_set_keys { + struct wl1251_cmd_header header; + + /* Ignored for default WEP key */ + u8 addr[ETH_ALEN]; + + /* key_action_e */ + u16 key_action; + + u16 reserved_1; + + /* key size in bytes */ + u8 key_size; + + /* key_type_e */ + u8 key_type; + u8 ssid_profile; + + /* + * TKIP, AES: frame's key id field. + * For WEP default key: key id; + */ + u8 id; + u8 reserved_2[6]; + u8 key[MAX_KEY_SIZE]; + u16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY]; + u32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY]; +} __packed; + + +#endif /* __WL1251_CMD_H__ */ diff --git a/drivers/net/wireless/wl1251/debugfs.c b/drivers/net/wireless/wl1251/debugfs.c new file mode 100644 index 0000000..6e5caaa --- /dev/null +++ b/drivers/net/wireless/wl1251/debugfs.c @@ -0,0 +1,541 @@ +/* + * This file is part of wl1251 + * + * Copyright (C) 2009 Nokia Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "debugfs.h" + +#include +#include + +#include "wl1251.h" +#include "acx.h" +#include "ps.h" + +/* ms */ +#define WL1251_DEBUGFS_STATS_LIFETIME 1000 + +/* debugfs macros idea from mac80211 */ + +#define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...) \ +static ssize_t name## _read(struct file *file, char __user *userbuf, \ + size_t count, loff_t *ppos) \ +{ \ + struct wl1251 *wl = file->private_data; \ + char buf[buflen]; \ + int res; \ + \ + res = scnprintf(buf, buflen, fmt "\n", ##value); \ + return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ +} \ + \ +static const struct file_operations name## _ops = { \ + .read = name## _read, \ + .open = wl1251_open_file_generic, \ +}; + +#define DEBUGFS_ADD(name, parent) \ + wl->debugfs.name = debugfs_create_file(#name, 0400, parent, \ + wl, &name## _ops); \ + if (IS_ERR(wl->debugfs.name)) { \ + ret = PTR_ERR(wl->debugfs.name); \ + wl->debugfs.name = NULL; \ + goto out; \ + } + +#define DEBUGFS_DEL(name) \ + do { \ + debugfs_remove(wl->debugfs.name); \ + wl->debugfs.name = NULL; \ + } while (0) + +#define DEBUGFS_FWSTATS_FILE(sub, name, buflen, fmt) \ +static ssize_t sub## _ ##name## _read(struct file *file, \ + char __user *userbuf, \ + size_t count, loff_t *ppos) \ +{ \ + struct wl1251 *wl = file->private_data; \ + char buf[buflen]; \ + int res; \ + \ + wl1251_debugfs_update_stats(wl); \ + \ + res = scnprintf(buf, buflen, fmt "\n", \ + wl->stats.fw_stats->sub.name); \ + return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ +} \ + \ +static const struct file_operations sub## _ ##name## _ops = { \ + .read = sub## _ ##name## _read, \ + .open = wl1251_open_file_generic, \ +}; + +#define DEBUGFS_FWSTATS_ADD(sub, name) \ + DEBUGFS_ADD(sub## _ ##name, wl->debugfs.fw_statistics) + +#define DEBUGFS_FWSTATS_DEL(sub, name) \ + DEBUGFS_DEL(sub## _ ##name) + +static void wl1251_debugfs_update_stats(struct wl1251 *wl) +{ + int ret; + + mutex_lock(&wl->mutex); + + ret = wl1251_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + if (wl->state == WL1251_STATE_ON && + time_after(jiffies, wl->stats.fw_stats_update + + msecs_to_jiffies(WL1251_DEBUGFS_STATS_LIFETIME))) { + wl1251_acx_statistics(wl, wl->stats.fw_stats); + wl->stats.fw_stats_update = jiffies; + } + + wl1251_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); +} + +static int wl1251_open_file_generic(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +DEBUGFS_FWSTATS_FILE(tx, internal_desc_overflow, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(rx, out_of_mem, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, hdr_overflow, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, hw_stuck, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, dropped, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, fcs_err, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, xfr_hint_trig, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, path_reset, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, reset_counter, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(dma, rx_requested, 20, "%u"); +DEBUGFS_FWSTATS_FILE(dma, rx_errors, 20, "%u"); +DEBUGFS_FWSTATS_FILE(dma, tx_requested, 20, "%u"); +DEBUGFS_FWSTATS_FILE(dma, tx_errors, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(isr, cmd_cmplt, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, fiqs, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, rx_headers, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, rx_mem_overflow, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, rx_rdys, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, irqs, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, tx_procs, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, decrypt_done, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, dma0_done, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, dma1_done, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, tx_exch_complete, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, commands, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, rx_procs, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, hw_pm_mode_changes, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, host_acknowledges, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, pci_pm, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, wakeups, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, low_rssi, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(wep, addr_key_count, 20, "%u"); +DEBUGFS_FWSTATS_FILE(wep, default_key_count, 20, "%u"); +/* skipping wep.reserved */ +DEBUGFS_FWSTATS_FILE(wep, key_not_found, 20, "%u"); +DEBUGFS_FWSTATS_FILE(wep, decrypt_fail, 20, "%u"); +DEBUGFS_FWSTATS_FILE(wep, packets, 20, "%u"); +DEBUGFS_FWSTATS_FILE(wep, interrupt, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(pwr, ps_enter, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, elp_enter, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, missing_bcns, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, wake_on_host, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, wake_on_timer_exp, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, tx_with_ps, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, tx_without_ps, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, rcvd_beacons, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, power_save_off, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, enable_ps, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, disable_ps, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, fix_tsf_ps, 20, "%u"); +/* skipping cont_miss_bcns_spread for now */ +DEBUGFS_FWSTATS_FILE(pwr, rcvd_awake_beacons, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(mic, rx_pkts, 20, "%u"); +DEBUGFS_FWSTATS_FILE(mic, calc_failure, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(aes, encrypt_fail, 20, "%u"); +DEBUGFS_FWSTATS_FILE(aes, decrypt_fail, 20, "%u"); +DEBUGFS_FWSTATS_FILE(aes, encrypt_packets, 20, "%u"); +DEBUGFS_FWSTATS_FILE(aes, decrypt_packets, 20, "%u"); +DEBUGFS_FWSTATS_FILE(aes, encrypt_interrupt, 20, "%u"); +DEBUGFS_FWSTATS_FILE(aes, decrypt_interrupt, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(event, heart_beat, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, calibration, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, rx_mismatch, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, rx_mem_empty, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, rx_pool, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, oom_late, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, phy_transmit_error, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, tx_stuck, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(ps, pspoll_timeouts, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, upsd_timeouts, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, upsd_max_sptime, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, upsd_max_apturn, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, pspoll_max_apturn, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, pspoll_utilization, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, upsd_utilization, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(rxpipe, rx_prep_beacon_drop, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rxpipe, descr_host_int_trig_rx_data, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rxpipe, beacon_buffer_thres_host_int_trig_rx_data, + 20, "%u"); +DEBUGFS_FWSTATS_FILE(rxpipe, missed_beacon_host_int_trig_rx_data, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rxpipe, tx_xfr_host_int_trig_rx_data, 20, "%u"); + +DEBUGFS_READONLY_FILE(retry_count, 20, "%u", wl->stats.retry_count); +DEBUGFS_READONLY_FILE(excessive_retries, 20, "%u", + wl->stats.excessive_retries); + +static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct wl1251 *wl = file->private_data; + u32 queue_len; + char buf[20]; + int res; + + queue_len = skb_queue_len(&wl->tx_queue); + + res = scnprintf(buf, sizeof(buf), "%u\n", queue_len); + return simple_read_from_buffer(userbuf, count, ppos, buf, res); +} + +static const struct file_operations tx_queue_len_ops = { + .read = tx_queue_len_read, + .open = wl1251_open_file_generic, +}; + +static ssize_t tx_queue_status_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct wl1251 *wl = file->private_data; + char buf[3], status; + int len; + + if (wl->tx_queue_stopped) + status = 's'; + else + status = 'r'; + + len = scnprintf(buf, sizeof(buf), "%c\n", status); + return simple_read_from_buffer(userbuf, count, ppos, buf, len); +} + +static const struct file_operations tx_queue_status_ops = { + .read = tx_queue_status_read, + .open = wl1251_open_file_generic, +}; + +static void wl1251_debugfs_delete_files(struct wl1251 *wl) +{ + DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow); + + DEBUGFS_FWSTATS_DEL(rx, out_of_mem); + DEBUGFS_FWSTATS_DEL(rx, hdr_overflow); + DEBUGFS_FWSTATS_DEL(rx, hw_stuck); + DEBUGFS_FWSTATS_DEL(rx, dropped); + DEBUGFS_FWSTATS_DEL(rx, fcs_err); + DEBUGFS_FWSTATS_DEL(rx, xfr_hint_trig); + DEBUGFS_FWSTATS_DEL(rx, path_reset); + DEBUGFS_FWSTATS_DEL(rx, reset_counter); + + DEBUGFS_FWSTATS_DEL(dma, rx_requested); + DEBUGFS_FWSTATS_DEL(dma, rx_errors); + DEBUGFS_FWSTATS_DEL(dma, tx_requested); + DEBUGFS_FWSTATS_DEL(dma, tx_errors); + + DEBUGFS_FWSTATS_DEL(isr, cmd_cmplt); + DEBUGFS_FWSTATS_DEL(isr, fiqs); + DEBUGFS_FWSTATS_DEL(isr, rx_headers); + DEBUGFS_FWSTATS_DEL(isr, rx_mem_overflow); + DEBUGFS_FWSTATS_DEL(isr, rx_rdys); + DEBUGFS_FWSTATS_DEL(isr, irqs); + DEBUGFS_FWSTATS_DEL(isr, tx_procs); + DEBUGFS_FWSTATS_DEL(isr, decrypt_done); + DEBUGFS_FWSTATS_DEL(isr, dma0_done); + DEBUGFS_FWSTATS_DEL(isr, dma1_done); + DEBUGFS_FWSTATS_DEL(isr, tx_exch_complete); + DEBUGFS_FWSTATS_DEL(isr, commands); + DEBUGFS_FWSTATS_DEL(isr, rx_procs); + DEBUGFS_FWSTATS_DEL(isr, hw_pm_mode_changes); + DEBUGFS_FWSTATS_DEL(isr, host_acknowledges); + DEBUGFS_FWSTATS_DEL(isr, pci_pm); + DEBUGFS_FWSTATS_DEL(isr, wakeups); + DEBUGFS_FWSTATS_DEL(isr, low_rssi); + + DEBUGFS_FWSTATS_DEL(wep, addr_key_count); + DEBUGFS_FWSTATS_DEL(wep, default_key_count); + /* skipping wep.reserved */ + DEBUGFS_FWSTATS_DEL(wep, key_not_found); + DEBUGFS_FWSTATS_DEL(wep, decrypt_fail); + DEBUGFS_FWSTATS_DEL(wep, packets); + DEBUGFS_FWSTATS_DEL(wep, interrupt); + + DEBUGFS_FWSTATS_DEL(pwr, ps_enter); + DEBUGFS_FWSTATS_DEL(pwr, elp_enter); + DEBUGFS_FWSTATS_DEL(pwr, missing_bcns); + DEBUGFS_FWSTATS_DEL(pwr, wake_on_host); + DEBUGFS_FWSTATS_DEL(pwr, wake_on_timer_exp); + DEBUGFS_FWSTATS_DEL(pwr, tx_with_ps); + DEBUGFS_FWSTATS_DEL(pwr, tx_without_ps); + DEBUGFS_FWSTATS_DEL(pwr, rcvd_beacons); + DEBUGFS_FWSTATS_DEL(pwr, power_save_off); + DEBUGFS_FWSTATS_DEL(pwr, enable_ps); + DEBUGFS_FWSTATS_DEL(pwr, disable_ps); + DEBUGFS_FWSTATS_DEL(pwr, fix_tsf_ps); + /* skipping cont_miss_bcns_spread for now */ + DEBUGFS_FWSTATS_DEL(pwr, rcvd_awake_beacons); + + DEBUGFS_FWSTATS_DEL(mic, rx_pkts); + DEBUGFS_FWSTATS_DEL(mic, calc_failure); + + DEBUGFS_FWSTATS_DEL(aes, encrypt_fail); + DEBUGFS_FWSTATS_DEL(aes, decrypt_fail); + DEBUGFS_FWSTATS_DEL(aes, encrypt_packets); + DEBUGFS_FWSTATS_DEL(aes, decrypt_packets); + DEBUGFS_FWSTATS_DEL(aes, encrypt_interrupt); + DEBUGFS_FWSTATS_DEL(aes, decrypt_interrupt); + + DEBUGFS_FWSTATS_DEL(event, heart_beat); + DEBUGFS_FWSTATS_DEL(event, calibration); + DEBUGFS_FWSTATS_DEL(event, rx_mismatch); + DEBUGFS_FWSTATS_DEL(event, rx_mem_empty); + DEBUGFS_FWSTATS_DEL(event, rx_pool); + DEBUGFS_FWSTATS_DEL(event, oom_late); + DEBUGFS_FWSTATS_DEL(event, phy_transmit_error); + DEBUGFS_FWSTATS_DEL(event, tx_stuck); + + DEBUGFS_FWSTATS_DEL(ps, pspoll_timeouts); + DEBUGFS_FWSTATS_DEL(ps, upsd_timeouts); + DEBUGFS_FWSTATS_DEL(ps, upsd_max_sptime); + DEBUGFS_FWSTATS_DEL(ps, upsd_max_apturn); + DEBUGFS_FWSTATS_DEL(ps, pspoll_max_apturn); + DEBUGFS_FWSTATS_DEL(ps, pspoll_utilization); + DEBUGFS_FWSTATS_DEL(ps, upsd_utilization); + + DEBUGFS_FWSTATS_DEL(rxpipe, rx_prep_beacon_drop); + DEBUGFS_FWSTATS_DEL(rxpipe, descr_host_int_trig_rx_data); + DEBUGFS_FWSTATS_DEL(rxpipe, beacon_buffer_thres_host_int_trig_rx_data); + DEBUGFS_FWSTATS_DEL(rxpipe, missed_beacon_host_int_trig_rx_data); + DEBUGFS_FWSTATS_DEL(rxpipe, tx_xfr_host_int_trig_rx_data); + + DEBUGFS_DEL(tx_queue_len); + DEBUGFS_DEL(tx_queue_status); + DEBUGFS_DEL(retry_count); + DEBUGFS_DEL(excessive_retries); +} + +static int wl1251_debugfs_add_files(struct wl1251 *wl) +{ + int ret = 0; + + DEBUGFS_FWSTATS_ADD(tx, internal_desc_overflow); + + DEBUGFS_FWSTATS_ADD(rx, out_of_mem); + DEBUGFS_FWSTATS_ADD(rx, hdr_overflow); + DEBUGFS_FWSTATS_ADD(rx, hw_stuck); + DEBUGFS_FWSTATS_ADD(rx, dropped); + DEBUGFS_FWSTATS_ADD(rx, fcs_err); + DEBUGFS_FWSTATS_ADD(rx, xfr_hint_trig); + DEBUGFS_FWSTATS_ADD(rx, path_reset); + DEBUGFS_FWSTATS_ADD(rx, reset_counter); + + DEBUGFS_FWSTATS_ADD(dma, rx_requested); + DEBUGFS_FWSTATS_ADD(dma, rx_errors); + DEBUGFS_FWSTATS_ADD(dma, tx_requested); + DEBUGFS_FWSTATS_ADD(dma, tx_errors); + + DEBUGFS_FWSTATS_ADD(isr, cmd_cmplt); + DEBUGFS_FWSTATS_ADD(isr, fiqs); + DEBUGFS_FWSTATS_ADD(isr, rx_headers); + DEBUGFS_FWSTATS_ADD(isr, rx_mem_overflow); + DEBUGFS_FWSTATS_ADD(isr, rx_rdys); + DEBUGFS_FWSTATS_ADD(isr, irqs); + DEBUGFS_FWSTATS_ADD(isr, tx_procs); + DEBUGFS_FWSTATS_ADD(isr, decrypt_done); + DEBUGFS_FWSTATS_ADD(isr, dma0_done); + DEBUGFS_FWSTATS_ADD(isr, dma1_done); + DEBUGFS_FWSTATS_ADD(isr, tx_exch_complete); + DEBUGFS_FWSTATS_ADD(isr, commands); + DEBUGFS_FWSTATS_ADD(isr, rx_procs); + DEBUGFS_FWSTATS_ADD(isr, hw_pm_mode_changes); + DEBUGFS_FWSTATS_ADD(isr, host_acknowledges); + DEBUGFS_FWSTATS_ADD(isr, pci_pm); + DEBUGFS_FWSTATS_ADD(isr, wakeups); + DEBUGFS_FWSTATS_ADD(isr, low_rssi); + + DEBUGFS_FWSTATS_ADD(wep, addr_key_count); + DEBUGFS_FWSTATS_ADD(wep, default_key_count); + /* skipping wep.reserved */ + DEBUGFS_FWSTATS_ADD(wep, key_not_found); + DEBUGFS_FWSTATS_ADD(wep, decrypt_fail); + DEBUGFS_FWSTATS_ADD(wep, packets); + DEBUGFS_FWSTATS_ADD(wep, interrupt); + + DEBUGFS_FWSTATS_ADD(pwr, ps_enter); + DEBUGFS_FWSTATS_ADD(pwr, elp_enter); + DEBUGFS_FWSTATS_ADD(pwr, missing_bcns); + DEBUGFS_FWSTATS_ADD(pwr, wake_on_host); + DEBUGFS_FWSTATS_ADD(pwr, wake_on_timer_exp); + DEBUGFS_FWSTATS_ADD(pwr, tx_with_ps); + DEBUGFS_FWSTATS_ADD(pwr, tx_without_ps); + DEBUGFS_FWSTATS_ADD(pwr, rcvd_beacons); + DEBUGFS_FWSTATS_ADD(pwr, power_save_off); + DEBUGFS_FWSTATS_ADD(pwr, enable_ps); + DEBUGFS_FWSTATS_ADD(pwr, disable_ps); + DEBUGFS_FWSTATS_ADD(pwr, fix_tsf_ps); + /* skipping cont_miss_bcns_spread for now */ + DEBUGFS_FWSTATS_ADD(pwr, rcvd_awake_beacons); + + DEBUGFS_FWSTATS_ADD(mic, rx_pkts); + DEBUGFS_FWSTATS_ADD(mic, calc_failure); + + DEBUGFS_FWSTATS_ADD(aes, encrypt_fail); + DEBUGFS_FWSTATS_ADD(aes, decrypt_fail); + DEBUGFS_FWSTATS_ADD(aes, encrypt_packets); + DEBUGFS_FWSTATS_ADD(aes, decrypt_packets); + DEBUGFS_FWSTATS_ADD(aes, encrypt_interrupt); + DEBUGFS_FWSTATS_ADD(aes, decrypt_interrupt); + + DEBUGFS_FWSTATS_ADD(event, heart_beat); + DEBUGFS_FWSTATS_ADD(event, calibration); + DEBUGFS_FWSTATS_ADD(event, rx_mismatch); + DEBUGFS_FWSTATS_ADD(event, rx_mem_empty); + DEBUGFS_FWSTATS_ADD(event, rx_pool); + DEBUGFS_FWSTATS_ADD(event, oom_late); + DEBUGFS_FWSTATS_ADD(event, phy_transmit_error); + DEBUGFS_FWSTATS_ADD(event, tx_stuck); + + DEBUGFS_FWSTATS_ADD(ps, pspoll_timeouts); + DEBUGFS_FWSTATS_ADD(ps, upsd_timeouts); + DEBUGFS_FWSTATS_ADD(ps, upsd_max_sptime); + DEBUGFS_FWSTATS_ADD(ps, upsd_max_apturn); + DEBUGFS_FWSTATS_ADD(ps, pspoll_max_apturn); + DEBUGFS_FWSTATS_ADD(ps, pspoll_utilization); + DEBUGFS_FWSTATS_ADD(ps, upsd_utilization); + + DEBUGFS_FWSTATS_ADD(rxpipe, rx_prep_beacon_drop); + DEBUGFS_FWSTATS_ADD(rxpipe, descr_host_int_trig_rx_data); + DEBUGFS_FWSTATS_ADD(rxpipe, beacon_buffer_thres_host_int_trig_rx_data); + DEBUGFS_FWSTATS_ADD(rxpipe, missed_beacon_host_int_trig_rx_data); + DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data); + + DEBUGFS_ADD(tx_queue_len, wl->debugfs.rootdir); + DEBUGFS_ADD(tx_queue_status, wl->debugfs.rootdir); + DEBUGFS_ADD(retry_count, wl->debugfs.rootdir); + DEBUGFS_ADD(excessive_retries, wl->debugfs.rootdir); + +out: + if (ret < 0) + wl1251_debugfs_delete_files(wl); + + return ret; +} + +void wl1251_debugfs_reset(struct wl1251 *wl) +{ + if (wl->stats.fw_stats != NULL) + memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats)); + wl->stats.retry_count = 0; + wl->stats.excessive_retries = 0; +} + +int wl1251_debugfs_init(struct wl1251 *wl) +{ + int ret; + + wl->debugfs.rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL); + + if (IS_ERR(wl->debugfs.rootdir)) { + ret = PTR_ERR(wl->debugfs.rootdir); + wl->debugfs.rootdir = NULL; + goto err; + } + + wl->debugfs.fw_statistics = debugfs_create_dir("fw-statistics", + wl->debugfs.rootdir); + + if (IS_ERR(wl->debugfs.fw_statistics)) { + ret = PTR_ERR(wl->debugfs.fw_statistics); + wl->debugfs.fw_statistics = NULL; + goto err_root; + } + + wl->stats.fw_stats = kzalloc(sizeof(*wl->stats.fw_stats), + GFP_KERNEL); + + if (!wl->stats.fw_stats) { + ret = -ENOMEM; + goto err_fw; + } + + wl->stats.fw_stats_update = jiffies; + + ret = wl1251_debugfs_add_files(wl); + + if (ret < 0) + goto err_file; + + return 0; + +err_file: + kfree(wl->stats.fw_stats); + wl->stats.fw_stats = NULL; + +err_fw: + debugfs_remove(wl->debugfs.fw_statistics); + wl->debugfs.fw_statistics = NULL; + +err_root: + debugfs_remove(wl->debugfs.rootdir); + wl->debugfs.rootdir = NULL; + +err: + return ret; +} + +void wl1251_debugfs_exit(struct wl1251 *wl) +{ + wl1251_debugfs_delete_files(wl); + + kfree(wl->stats.fw_stats); + wl->stats.fw_stats = NULL; + + debugfs_remove(wl->debugfs.fw_statistics); + wl->debugfs.fw_statistics = NULL; + + debugfs_remove(wl->debugfs.rootdir); + wl->debugfs.rootdir = NULL; + +} diff --git a/drivers/net/wireless/wl1251/debugfs.h b/drivers/net/wireless/wl1251/debugfs.h new file mode 100644 index 0000000..b3417c0 --- /dev/null +++ b/drivers/net/wireless/wl1251/debugfs.h @@ -0,0 +1,31 @@ +/* + * This file is part of wl1251 + * + * Copyright (C) 2009 Nokia Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef WL1251_DEBUGFS_H +#define WL1251_DEBUGFS_H + +#include "wl1251.h" + +int wl1251_debugfs_init(struct wl1251 *wl); +void wl1251_debugfs_exit(struct wl1251 *wl); +void wl1251_debugfs_reset(struct wl1251 *wl); + +#endif /* WL1251_DEBUGFS_H */ diff --git a/drivers/net/wireless/wl1251/event.c b/drivers/net/wireless/wl1251/event.c new file mode 100644 index 0000000..712372e --- /dev/null +++ b/drivers/net/wireless/wl1251/event.c @@ -0,0 +1,168 @@ +/* + * This file is part of wl1251 + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "wl1251.h" +#include "reg.h" +#include "io.h" +#include "event.h" +#include "ps.h" + +static int wl1251_event_scan_complete(struct wl1251 *wl, + struct event_mailbox *mbox) +{ + wl1251_debug(DEBUG_EVENT, "status: 0x%x, channels: %d", + mbox->scheduled_scan_status, + mbox->scheduled_scan_channels); + + if (wl->scanning) { + ieee80211_scan_completed(wl->hw, false); + wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan completed"); + wl->scanning = false; + } + + return 0; +} + +static void wl1251_event_mbox_dump(struct event_mailbox *mbox) +{ + wl1251_debug(DEBUG_EVENT, "MBOX DUMP:"); + wl1251_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector); + wl1251_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask); +} + +static int wl1251_event_process(struct wl1251 *wl, struct event_mailbox *mbox) +{ + int ret; + u32 vector; + + wl1251_event_mbox_dump(mbox); + + vector = mbox->events_vector & ~(mbox->events_mask); + wl1251_debug(DEBUG_EVENT, "vector: 0x%x", vector); + + if (vector & SCAN_COMPLETE_EVENT_ID) { + ret = wl1251_event_scan_complete(wl, mbox); + if (ret < 0) + return ret; + } + + if (vector & BSS_LOSE_EVENT_ID) { + wl1251_debug(DEBUG_EVENT, "BSS_LOSE_EVENT"); + + if (wl->psm_requested && wl->psm) { + ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE); + if (ret < 0) + return ret; + } + } + + if (vector & SYNCHRONIZATION_TIMEOUT_EVENT_ID && wl->psm) { + wl1251_debug(DEBUG_EVENT, "SYNCHRONIZATION_TIMEOUT_EVENT"); + + /* indicate to the stack, that beacons have been lost */ + ieee80211_beacon_loss(wl->vif); + } + + if (vector & REGAINED_BSS_EVENT_ID) { + if (wl->psm_requested) { + ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE); + if (ret < 0) + return ret; + } + } + + return 0; +} + +/* + * Poll the mailbox event field until any of the bits in the mask is set or a + * timeout occurs (WL1251_EVENT_TIMEOUT in msecs) + */ +int wl1251_event_wait(struct wl1251 *wl, u32 mask, int timeout_ms) +{ + u32 events_vector, event; + unsigned long timeout; + + timeout = jiffies + msecs_to_jiffies(timeout_ms); + + do { + if (time_after(jiffies, timeout)) + return -ETIMEDOUT; + + msleep(1); + + /* read from both event fields */ + wl1251_mem_read(wl, wl->mbox_ptr[0], &events_vector, + sizeof(events_vector)); + event = events_vector & mask; + wl1251_mem_read(wl, wl->mbox_ptr[1], &events_vector, + sizeof(events_vector)); + event |= events_vector & mask; + } while (!event); + + return 0; +} + +int wl1251_event_unmask(struct wl1251 *wl) +{ + int ret; + + ret = wl1251_acx_event_mbox_mask(wl, ~(wl->event_mask)); + if (ret < 0) + return ret; + + return 0; +} + +void wl1251_event_mbox_config(struct wl1251 *wl) +{ + wl->mbox_ptr[0] = wl1251_reg_read32(wl, REG_EVENT_MAILBOX_PTR); + wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox); + + wl1251_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x", + wl->mbox_ptr[0], wl->mbox_ptr[1]); +} + +int wl1251_event_handle(struct wl1251 *wl, u8 mbox_num) +{ + struct event_mailbox mbox; + int ret; + + wl1251_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num); + + if (mbox_num > 1) + return -EINVAL; + + /* first we read the mbox descriptor */ + wl1251_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox, + sizeof(struct event_mailbox)); + + /* process the descriptor */ + ret = wl1251_event_process(wl, &mbox); + if (ret < 0) + return ret; + + /* then we let the firmware know it can go on...*/ + wl1251_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK); + + return 0; +} diff --git a/drivers/net/wireless/wl1251/event.h b/drivers/net/wireless/wl1251/event.h new file mode 100644 index 0000000..30eb5d1 --- /dev/null +++ b/drivers/net/wireless/wl1251/event.h @@ -0,0 +1,120 @@ +/* + * This file is part of wl1251 + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL1251_EVENT_H__ +#define __WL1251_EVENT_H__ + +/* + * Mbox events + * + * The event mechanism is based on a pair of event buffers (buffers A and + * B) at fixed locations in the target's memory. The host processes one + * buffer while the other buffer continues to collect events. If the host + * is not processing events, an interrupt is issued to signal that a buffer + * is ready. Once the host is done with processing events from one buffer, + * it signals the target (with an ACK interrupt) that the event buffer is + * free. + */ + +enum { + RESERVED1_EVENT_ID = BIT(0), + RESERVED2_EVENT_ID = BIT(1), + MEASUREMENT_START_EVENT_ID = BIT(2), + SCAN_COMPLETE_EVENT_ID = BIT(3), + CALIBRATION_COMPLETE_EVENT_ID = BIT(4), + ROAMING_TRIGGER_LOW_RSSI_EVENT_ID = BIT(5), + PS_REPORT_EVENT_ID = BIT(6), + SYNCHRONIZATION_TIMEOUT_EVENT_ID = BIT(7), + HEALTH_REPORT_EVENT_ID = BIT(8), + ACI_DETECTION_EVENT_ID = BIT(9), + DEBUG_REPORT_EVENT_ID = BIT(10), + MAC_STATUS_EVENT_ID = BIT(11), + DISCONNECT_EVENT_COMPLETE_ID = BIT(12), + JOIN_EVENT_COMPLETE_ID = BIT(13), + CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(14), + BSS_LOSE_EVENT_ID = BIT(15), + ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID = BIT(16), + MEASUREMENT_COMPLETE_EVENT_ID = BIT(17), + AP_DISCOVERY_COMPLETE_EVENT_ID = BIT(18), + SCHEDULED_SCAN_COMPLETE_EVENT_ID = BIT(19), + PSPOLL_DELIVERY_FAILURE_EVENT_ID = BIT(20), + RESET_BSS_EVENT_ID = BIT(21), + REGAINED_BSS_EVENT_ID = BIT(22), + ROAMING_TRIGGER_REGAINED_RSSI_EVENT_ID = BIT(23), + ROAMING_TRIGGER_LOW_SNR_EVENT_ID = BIT(24), + ROAMING_TRIGGER_REGAINED_SNR_EVENT_ID = BIT(25), + + DBG_EVENT_ID = BIT(26), + BT_PTA_SENSE_EVENT_ID = BIT(27), + BT_PTA_PREDICTION_EVENT_ID = BIT(28), + BT_PTA_AVALANCHE_EVENT_ID = BIT(29), + + PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(30), + + EVENT_MBOX_ALL_EVENT_ID = 0x7fffffff, +}; + +struct event_debug_report { + u8 debug_event_id; + u8 num_params; + u16 pad; + u32 report_1; + u32 report_2; + u32 report_3; +} __packed; + +struct event_mailbox { + u32 events_vector; + u32 events_mask; + u32 reserved_1; + u32 reserved_2; + + char average_rssi_level; + u8 ps_status; + u8 channel_switch_status; + u8 scheduled_scan_status; + + /* Channels scanned by the scheduled scan */ + u16 scheduled_scan_channels; + + /* If bit 0 is set -> target's fatal error */ + u16 health_report; + u16 bad_fft_counter; + u8 bt_pta_sense_info; + u8 bt_pta_protective_info; + u32 reserved; + u32 debug_report[2]; + + /* Number of FCS errors since last event */ + u32 fcs_err_counter; + + struct event_debug_report report; + u8 average_snr_level; + u8 padding[19]; +} __packed; + +int wl1251_event_unmask(struct wl1251 *wl); +void wl1251_event_mbox_config(struct wl1251 *wl); +int wl1251_event_handle(struct wl1251 *wl, u8 mbox); +int wl1251_event_wait(struct wl1251 *wl, u32 mask, int timeout_ms); + +#endif diff --git a/drivers/net/wireless/wl1251/init.c b/drivers/net/wireless/wl1251/init.c new file mode 100644 index 0000000..89b43d3 --- /dev/null +++ b/drivers/net/wireless/wl1251/init.c @@ -0,0 +1,423 @@ +/* + * This file is part of wl1251 + * + * Copyright (C) 2009 Nokia Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include + +#include "init.h" +#include "wl12xx_80211.h" +#include "acx.h" +#include "cmd.h" +#include "reg.h" + +int wl1251_hw_init_hwenc_config(struct wl1251 *wl) +{ + int ret; + + ret = wl1251_acx_feature_cfg(wl); + if (ret < 0) { + wl1251_warning("couldn't set feature config"); + return ret; + } + + ret = wl1251_acx_default_key(wl, wl->default_key); + if (ret < 0) { + wl1251_warning("couldn't set default key"); + return ret; + } + + return 0; +} + +int wl1251_hw_init_templates_config(struct wl1251 *wl) +{ + int ret; + u8 partial_vbm[PARTIAL_VBM_MAX]; + + /* send empty templates for fw memory reservation */ + ret = wl1251_cmd_template_set(wl, CMD_PROBE_REQ, NULL, + sizeof(struct wl12xx_probe_req_template)); + if (ret < 0) + return ret; + + ret = wl1251_cmd_template_set(wl, CMD_NULL_DATA, NULL, + sizeof(struct wl12xx_null_data_template)); + if (ret < 0) + return ret; + + ret = wl1251_cmd_template_set(wl, CMD_PS_POLL, NULL, + sizeof(struct wl12xx_ps_poll_template)); + if (ret < 0) + return ret; + + ret = wl1251_cmd_template_set(wl, CMD_QOS_NULL_DATA, NULL, + sizeof + (struct wl12xx_qos_null_data_template)); + if (ret < 0) + return ret; + + ret = wl1251_cmd_template_set(wl, CMD_PROBE_RESP, NULL, + sizeof + (struct wl12xx_probe_resp_template)); + if (ret < 0) + return ret; + + ret = wl1251_cmd_template_set(wl, CMD_BEACON, NULL, + sizeof + (struct wl12xx_beacon_template)); + if (ret < 0) + return ret; + + /* tim templates, first reserve space then allocate an empty one */ + memset(partial_vbm, 0, PARTIAL_VBM_MAX); + ret = wl1251_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, PARTIAL_VBM_MAX, 0); + if (ret < 0) + return ret; + + ret = wl1251_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, 1, 0); + if (ret < 0) + return ret; + + return 0; +} + +int wl1251_hw_init_rx_config(struct wl1251 *wl, u32 config, u32 filter) +{ + int ret; + + ret = wl1251_acx_rx_msdu_life_time(wl, RX_MSDU_LIFETIME_DEF); + if (ret < 0) + return ret; + + ret = wl1251_acx_rx_config(wl, config, filter); + if (ret < 0) + return ret; + + return 0; +} + +int wl1251_hw_init_phy_config(struct wl1251 *wl) +{ + int ret; + + ret = wl1251_acx_pd_threshold(wl); + if (ret < 0) + return ret; + + ret = wl1251_acx_slot(wl, DEFAULT_SLOT_TIME); + if (ret < 0) + return ret; + + ret = wl1251_acx_group_address_tbl(wl); + if (ret < 0) + return ret; + + ret = wl1251_acx_service_period_timeout(wl); + if (ret < 0) + return ret; + + ret = wl1251_acx_rts_threshold(wl, RTS_THRESHOLD_DEF); + if (ret < 0) + return ret; + + return 0; +} + +int wl1251_hw_init_beacon_filter(struct wl1251 *wl) +{ + int ret; + + /* disable beacon filtering at this stage */ + ret = wl1251_acx_beacon_filter_opt(wl, false); + if (ret < 0) + return ret; + + ret = wl1251_acx_beacon_filter_table(wl); + if (ret < 0) + return ret; + + return 0; +} + +int wl1251_hw_init_pta(struct wl1251 *wl) +{ + int ret; + + ret = wl1251_acx_sg_enable(wl); + if (ret < 0) + return ret; + + ret = wl1251_acx_sg_cfg(wl); + if (ret < 0) + return ret; + + return 0; +} + +int wl1251_hw_init_energy_detection(struct wl1251 *wl) +{ + int ret; + + ret = wl1251_acx_cca_threshold(wl); + if (ret < 0) + return ret; + + return 0; +} + +int wl1251_hw_init_beacon_broadcast(struct wl1251 *wl) +{ + int ret; + + ret = wl1251_acx_bcn_dtim_options(wl); + if (ret < 0) + return ret; + + return 0; +} + +int wl1251_hw_init_power_auth(struct wl1251 *wl) +{ + return wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM); +} + +int wl1251_hw_init_mem_config(struct wl1251 *wl) +{ + int ret; + + ret = wl1251_acx_mem_cfg(wl); + if (ret < 0) + return ret; + + wl->target_mem_map = kzalloc(sizeof(struct wl1251_acx_mem_map), + GFP_KERNEL); + if (!wl->target_mem_map) { + wl1251_error("couldn't allocate target memory map"); + return -ENOMEM; + } + + /* we now ask for the firmware built memory map */ + ret = wl1251_acx_mem_map(wl, wl->target_mem_map, + sizeof(struct wl1251_acx_mem_map)); + if (ret < 0) { + wl1251_error("couldn't retrieve firmware memory map"); + kfree(wl->target_mem_map); + wl->target_mem_map = NULL; + return ret; + } + + return 0; +} + +static int wl1251_hw_init_txq_fill(u8 qid, + struct acx_tx_queue_qos_config *config, + u32 num_blocks) +{ + config->qid = qid; + + switch (qid) { + case QOS_AC_BE: + config->high_threshold = + (QOS_TX_HIGH_BE_DEF * num_blocks) / 100; + config->low_threshold = + (QOS_TX_LOW_BE_DEF * num_blocks) / 100; + break; + case QOS_AC_BK: + config->high_threshold = + (QOS_TX_HIGH_BK_DEF * num_blocks) / 100; + config->low_threshold = + (QOS_TX_LOW_BK_DEF * num_blocks) / 100; + break; + case QOS_AC_VI: + config->high_threshold = + (QOS_TX_HIGH_VI_DEF * num_blocks) / 100; + config->low_threshold = + (QOS_TX_LOW_VI_DEF * num_blocks) / 100; + break; + case QOS_AC_VO: + config->high_threshold = + (QOS_TX_HIGH_VO_DEF * num_blocks) / 100; + config->low_threshold = + (QOS_TX_LOW_VO_DEF * num_blocks) / 100; + break; + default: + wl1251_error("Invalid TX queue id: %d", qid); + return -EINVAL; + } + + return 0; +} + +static int wl1251_hw_init_tx_queue_config(struct wl1251 *wl) +{ + struct acx_tx_queue_qos_config *config; + struct wl1251_acx_mem_map *wl_mem_map = wl->target_mem_map; + int ret, i; + + wl1251_debug(DEBUG_ACX, "acx tx queue config"); + + config = kzalloc(sizeof(*config), GFP_KERNEL); + if (!config) { + ret = -ENOMEM; + goto out; + } + + for (i = 0; i < MAX_NUM_OF_AC; i++) { + ret = wl1251_hw_init_txq_fill(i, config, + wl_mem_map->num_tx_mem_blocks); + if (ret < 0) + goto out; + + ret = wl1251_cmd_configure(wl, ACX_TX_QUEUE_CFG, + config, sizeof(*config)); + if (ret < 0) + goto out; + } + + wl1251_acx_ac_cfg(wl, AC_BE, CWMIN_BE, CWMAX_BE, AIFS_DIFS, TXOP_BE); + wl1251_acx_ac_cfg(wl, AC_BK, CWMIN_BK, CWMAX_BK, AIFS_DIFS, TXOP_BK); + wl1251_acx_ac_cfg(wl, AC_VI, CWMIN_VI, CWMAX_VI, AIFS_DIFS, TXOP_VI); + wl1251_acx_ac_cfg(wl, AC_VO, CWMIN_VO, CWMAX_VO, AIFS_DIFS, TXOP_VO); + +out: + kfree(config); + return ret; +} + +static int wl1251_hw_init_data_path_config(struct wl1251 *wl) +{ + int ret; + + /* asking for the data path parameters */ + wl->data_path = kzalloc(sizeof(struct acx_data_path_params_resp), + GFP_KERNEL); + if (!wl->data_path) { + wl1251_error("Couldnt allocate data path parameters"); + return -ENOMEM; + } + + ret = wl1251_acx_data_path_params(wl, wl->data_path); + if (ret < 0) { + kfree(wl->data_path); + wl->data_path = NULL; + return ret; + } + + return 0; +} + + +int wl1251_hw_init(struct wl1251 *wl) +{ + struct wl1251_acx_mem_map *wl_mem_map; + int ret; + + ret = wl1251_hw_init_hwenc_config(wl); + if (ret < 0) + return ret; + + /* Template settings */ + ret = wl1251_hw_init_templates_config(wl); + if (ret < 0) + return ret; + + /* Default memory configuration */ + ret = wl1251_hw_init_mem_config(wl); + if (ret < 0) + return ret; + + /* Default data path configuration */ + ret = wl1251_hw_init_data_path_config(wl); + if (ret < 0) + goto out_free_memmap; + + /* RX config */ + ret = wl1251_hw_init_rx_config(wl, + RX_CFG_PROMISCUOUS | RX_CFG_TSF, + RX_FILTER_OPTION_DEF); + /* RX_CONFIG_OPTION_ANY_DST_ANY_BSS, + RX_FILTER_OPTION_FILTER_ALL); */ + if (ret < 0) + goto out_free_data_path; + + /* TX queues config */ + ret = wl1251_hw_init_tx_queue_config(wl); + if (ret < 0) + goto out_free_data_path; + + /* PHY layer config */ + ret = wl1251_hw_init_phy_config(wl); + if (ret < 0) + goto out_free_data_path; + + /* Initialize connection monitoring thresholds */ + ret = wl1251_acx_conn_monit_params(wl); + if (ret < 0) + goto out_free_data_path; + + /* Beacon filtering */ + ret = wl1251_hw_init_beacon_filter(wl); + if (ret < 0) + goto out_free_data_path; + + /* Bluetooth WLAN coexistence */ + ret = wl1251_hw_init_pta(wl); + if (ret < 0) + goto out_free_data_path; + + /* Energy detection */ + ret = wl1251_hw_init_energy_detection(wl); + if (ret < 0) + goto out_free_data_path; + + /* Beacons and boradcast settings */ + ret = wl1251_hw_init_beacon_broadcast(wl); + if (ret < 0) + goto out_free_data_path; + + /* Enable data path */ + ret = wl1251_cmd_data_path(wl, wl->channel, 1); + if (ret < 0) + goto out_free_data_path; + + /* Default power state */ + ret = wl1251_hw_init_power_auth(wl); + if (ret < 0) + goto out_free_data_path; + + wl_mem_map = wl->target_mem_map; + wl1251_info("%d tx blocks at 0x%x, %d rx blocks at 0x%x", + wl_mem_map->num_tx_mem_blocks, + wl->data_path->tx_control_addr, + wl_mem_map->num_rx_mem_blocks, + wl->data_path->rx_control_addr); + + return 0; + + out_free_data_path: + kfree(wl->data_path); + + out_free_memmap: + kfree(wl->target_mem_map); + + return ret; +} diff --git a/drivers/net/wireless/wl1251/init.h b/drivers/net/wireless/wl1251/init.h new file mode 100644 index 0000000..543f175 --- /dev/null +++ b/drivers/net/wireless/wl1251/init.h @@ -0,0 +1,86 @@ +/* + * This file is part of wl1251 + * + * Copyright (C) 2009 Nokia Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL1251_INIT_H__ +#define __WL1251_INIT_H__ + +#include "wl1251.h" + +enum { + /* best effort/legacy */ + AC_BE = 0, + + /* background */ + AC_BK = 1, + + /* video */ + AC_VI = 2, + + /* voice */ + AC_VO = 3, + + /* broadcast dummy access category */ + AC_BCAST = 4, + + NUM_ACCESS_CATEGORIES = 4 +}; + +/* following are defult values for the IE fields*/ +#define CWMIN_BK 15 +#define CWMIN_BE 15 +#define CWMIN_VI 7 +#define CWMIN_VO 3 +#define CWMAX_BK 1023 +#define CWMAX_BE 63 +#define CWMAX_VI 15 +#define CWMAX_VO 7 + +/* slot number setting to start transmission at PIFS interval */ +#define AIFS_PIFS 1 + +/* + * slot number setting to start transmission at DIFS interval - normal DCF + * access + */ +#define AIFS_DIFS 2 + +#define AIFSN_BK 7 +#define AIFSN_BE 3 +#define AIFSN_VI AIFS_PIFS +#define AIFSN_VO AIFS_PIFS +#define TXOP_BK 0 +#define TXOP_BE 0 +#define TXOP_VI 3008 +#define TXOP_VO 1504 + +int wl1251_hw_init_hwenc_config(struct wl1251 *wl); +int wl1251_hw_init_templates_config(struct wl1251 *wl); +int wl1251_hw_init_rx_config(struct wl1251 *wl, u32 config, u32 filter); +int wl1251_hw_init_phy_config(struct wl1251 *wl); +int wl1251_hw_init_beacon_filter(struct wl1251 *wl); +int wl1251_hw_init_pta(struct wl1251 *wl); +int wl1251_hw_init_energy_detection(struct wl1251 *wl); +int wl1251_hw_init_beacon_broadcast(struct wl1251 *wl); +int wl1251_hw_init_power_auth(struct wl1251 *wl); +int wl1251_hw_init_mem_config(struct wl1251 *wl); +int wl1251_hw_init(struct wl1251 *wl); + +#endif diff --git a/drivers/net/wireless/wl1251/io.c b/drivers/net/wireless/wl1251/io.c new file mode 100644 index 0000000..cdcadbf --- /dev/null +++ b/drivers/net/wireless/wl1251/io.c @@ -0,0 +1,194 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2008 Nokia Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "wl1251.h" +#include "reg.h" +#include "io.h" + +/* FIXME: this is static data nowadays and the table can be removed */ +static enum wl12xx_acx_int_reg wl1251_io_reg_table[ACX_REG_TABLE_LEN] = { + [ACX_REG_INTERRUPT_TRIG] = (REGISTERS_BASE + 0x0474), + [ACX_REG_INTERRUPT_TRIG_H] = (REGISTERS_BASE + 0x0478), + [ACX_REG_INTERRUPT_MASK] = (REGISTERS_BASE + 0x0494), + [ACX_REG_HINT_MASK_SET] = (REGISTERS_BASE + 0x0498), + [ACX_REG_HINT_MASK_CLR] = (REGISTERS_BASE + 0x049C), + [ACX_REG_INTERRUPT_NO_CLEAR] = (REGISTERS_BASE + 0x04B0), + [ACX_REG_INTERRUPT_CLEAR] = (REGISTERS_BASE + 0x04A4), + [ACX_REG_INTERRUPT_ACK] = (REGISTERS_BASE + 0x04A8), + [ACX_REG_SLV_SOFT_RESET] = (REGISTERS_BASE + 0x0000), + [ACX_REG_EE_START] = (REGISTERS_BASE + 0x080C), + [ACX_REG_ECPU_CONTROL] = (REGISTERS_BASE + 0x0804) +}; + +static int wl1251_translate_reg_addr(struct wl1251 *wl, int addr) +{ + /* If the address is lower than REGISTERS_BASE, it means that this is + * a chip-specific register address, so look it up in the registers + * table */ + if (addr < REGISTERS_BASE) { + /* Make sure we don't go over the table */ + if (addr >= ACX_REG_TABLE_LEN) { + wl1251_error("address out of range (%d)", addr); + return -EINVAL; + } + addr = wl1251_io_reg_table[addr]; + } + + return addr - wl->physical_reg_addr + wl->virtual_reg_addr; +} + +static int wl1251_translate_mem_addr(struct wl1251 *wl, int addr) +{ + return addr - wl->physical_mem_addr + wl->virtual_mem_addr; +} + +void wl1251_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len) +{ + int physical; + + physical = wl1251_translate_mem_addr(wl, addr); + + wl->if_ops->read(wl, physical, buf, len); +} + +void wl1251_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len) +{ + int physical; + + physical = wl1251_translate_mem_addr(wl, addr); + + wl->if_ops->write(wl, physical, buf, len); +} + +u32 wl1251_mem_read32(struct wl1251 *wl, int addr) +{ + return wl1251_read32(wl, wl1251_translate_mem_addr(wl, addr)); +} + +void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val) +{ + wl1251_write32(wl, wl1251_translate_mem_addr(wl, addr), val); +} + +u32 wl1251_reg_read32(struct wl1251 *wl, int addr) +{ + return wl1251_read32(wl, wl1251_translate_reg_addr(wl, addr)); +} + +void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val) +{ + wl1251_write32(wl, wl1251_translate_reg_addr(wl, addr), val); +} + +/* Set the partitions to access the chip addresses. + * + * There are two VIRTUAL partitions (the memory partition and the + * registers partition), which are mapped to two different areas of the + * PHYSICAL (hardware) memory. This function also makes other checks to + * ensure that the partitions are not overlapping. In the diagram below, the + * memory partition comes before the register partition, but the opposite is + * also supported. + * + * PHYSICAL address + * space + * + * | | + * ...+----+--> mem_start + * VIRTUAL address ... | | + * space ... | | [PART_0] + * ... | | + * 0x00000000 <--+----+... ...+----+--> mem_start + mem_size + * | | ... | | + * |MEM | ... | | + * | | ... | | + * part_size <--+----+... | | {unused area) + * | | ... | | + * |REG | ... | | + * part_size | | ... | | + * + <--+----+... ...+----+--> reg_start + * reg_size ... | | + * ... | | [PART_1] + * ... | | + * ...+----+--> reg_start + reg_size + * | | + * + */ +void wl1251_set_partition(struct wl1251 *wl, + u32 mem_start, u32 mem_size, + u32 reg_start, u32 reg_size) +{ + struct wl1251_partition partition[2]; + + wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + mem_start, mem_size); + wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + reg_start, reg_size); + + /* Make sure that the two partitions together don't exceed the + * address range */ + if ((mem_size + reg_size) > HW_ACCESS_MEMORY_MAX_RANGE) { + wl1251_debug(DEBUG_SPI, "Total size exceeds maximum virtual" + " address range. Truncating partition[0]."); + mem_size = HW_ACCESS_MEMORY_MAX_RANGE - reg_size; + wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + mem_start, mem_size); + wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + reg_start, reg_size); + } + + if ((mem_start < reg_start) && + ((mem_start + mem_size) > reg_start)) { + /* Guarantee that the memory partition doesn't overlap the + * registers partition */ + wl1251_debug(DEBUG_SPI, "End of partition[0] is " + "overlapping partition[1]. Adjusted."); + mem_size = reg_start - mem_start; + wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + mem_start, mem_size); + wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + reg_start, reg_size); + } else if ((reg_start < mem_start) && + ((reg_start + reg_size) > mem_start)) { + /* Guarantee that the register partition doesn't overlap the + * memory partition */ + wl1251_debug(DEBUG_SPI, "End of partition[1] is" + " overlapping partition[0]. Adjusted."); + reg_size = mem_start - reg_start; + wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + mem_start, mem_size); + wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + reg_start, reg_size); + } + + partition[0].start = mem_start; + partition[0].size = mem_size; + partition[1].start = reg_start; + partition[1].size = reg_size; + + wl->physical_mem_addr = mem_start; + wl->physical_reg_addr = reg_start; + + wl->virtual_mem_addr = 0; + wl->virtual_reg_addr = mem_size; + + wl->if_ops->write(wl, HW_ACCESS_PART0_SIZE_ADDR, partition, + sizeof(partition)); +} diff --git a/drivers/net/wireless/wl1251/io.h b/drivers/net/wireless/wl1251/io.h new file mode 100644 index 0000000..c545e9d --- /dev/null +++ b/drivers/net/wireless/wl1251/io.h @@ -0,0 +1,84 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2008 Nokia Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ +#ifndef __WL1251_IO_H__ +#define __WL1251_IO_H__ + +#include "wl1251.h" + +#define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0 + +#define HW_ACCESS_PART0_SIZE_ADDR 0x1FFC0 +#define HW_ACCESS_PART0_START_ADDR 0x1FFC4 +#define HW_ACCESS_PART1_SIZE_ADDR 0x1FFC8 +#define HW_ACCESS_PART1_START_ADDR 0x1FFCC + +#define HW_ACCESS_REGISTER_SIZE 4 + +#define HW_ACCESS_PRAM_MAX_RANGE 0x3c000 + +static inline u32 wl1251_read32(struct wl1251 *wl, int addr) +{ + u32 response; + + wl->if_ops->read(wl, addr, &response, sizeof(u32)); + + return response; +} + +static inline void wl1251_write32(struct wl1251 *wl, int addr, u32 val) +{ + wl->if_ops->write(wl, addr, &val, sizeof(u32)); +} + +static inline u32 wl1251_read_elp(struct wl1251 *wl, int addr) +{ + u32 response; + + if (wl->if_ops->read_elp) + wl->if_ops->read_elp(wl, addr, &response); + else + wl->if_ops->read(wl, addr, &response, sizeof(u32)); + + return response; +} + +static inline void wl1251_write_elp(struct wl1251 *wl, int addr, u32 val) +{ + if (wl->if_ops->write_elp) + wl->if_ops->write_elp(wl, addr, val); + else + wl->if_ops->write(wl, addr, &val, sizeof(u32)); +} + +/* Memory target IO, address is translated to partition 0 */ +void wl1251_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len); +void wl1251_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len); +u32 wl1251_mem_read32(struct wl1251 *wl, int addr); +void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val); +/* Registers IO */ +u32 wl1251_reg_read32(struct wl1251 *wl, int addr); +void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val); + +void wl1251_set_partition(struct wl1251 *wl, + u32 part_start, u32 part_size, + u32 reg_start, u32 reg_size); + +#endif diff --git a/drivers/net/wireless/wl1251/main.c b/drivers/net/wireless/wl1251/main.c new file mode 100644 index 0000000..7a87625 --- /dev/null +++ b/drivers/net/wireless/wl1251/main.c @@ -0,0 +1,1435 @@ +/* + * This file is part of wl1251 + * + * Copyright (C) 2008-2009 Nokia Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wl1251.h" +#include "wl12xx_80211.h" +#include "reg.h" +#include "io.h" +#include "cmd.h" +#include "event.h" +#include "tx.h" +#include "rx.h" +#include "ps.h" +#include "init.h" +#include "debugfs.h" +#include "boot.h" + +void wl1251_enable_interrupts(struct wl1251 *wl) +{ + wl->if_ops->enable_irq(wl); +} + +void wl1251_disable_interrupts(struct wl1251 *wl) +{ + wl->if_ops->disable_irq(wl); +} + +static void wl1251_power_off(struct wl1251 *wl) +{ + wl->set_power(false); +} + +static void wl1251_power_on(struct wl1251 *wl) +{ + wl->set_power(true); +} + +static int wl1251_fetch_firmware(struct wl1251 *wl) +{ + const struct firmware *fw; + struct device *dev = wiphy_dev(wl->hw->wiphy); + int ret; + + ret = request_firmware(&fw, WL1251_FW_NAME, dev); + + if (ret < 0) { + wl1251_error("could not get firmware: %d", ret); + return ret; + } + + if (fw->size % 4) { + wl1251_error("firmware size is not multiple of 32 bits: %zu", + fw->size); + ret = -EILSEQ; + goto out; + } + + wl->fw_len = fw->size; + wl->fw = vmalloc(wl->fw_len); + + if (!wl->fw) { + wl1251_error("could not allocate memory for the firmware"); + ret = -ENOMEM; + goto out; + } + + memcpy(wl->fw, fw->data, wl->fw_len); + + ret = 0; + +out: + release_firmware(fw); + + return ret; +} + +static int wl1251_fetch_nvs(struct wl1251 *wl) +{ + const struct firmware *fw; + struct device *dev = wiphy_dev(wl->hw->wiphy); + int ret; + + ret = request_firmware(&fw, WL1251_NVS_NAME, dev); + + if (ret < 0) { + wl1251_error("could not get nvs file: %d", ret); + return ret; + } + + if (fw->size % 4) { + wl1251_error("nvs size is not multiple of 32 bits: %zu", + fw->size); + ret = -EILSEQ; + goto out; + } + + wl->nvs_len = fw->size; + wl->nvs = kmemdup(fw->data, wl->nvs_len, GFP_KERNEL); + + if (!wl->nvs) { + wl1251_error("could not allocate memory for the nvs file"); + ret = -ENOMEM; + goto out; + } + + ret = 0; + +out: + release_firmware(fw); + + return ret; +} + +static void wl1251_fw_wakeup(struct wl1251 *wl) +{ + u32 elp_reg; + + elp_reg = ELPCTRL_WAKE_UP; + wl1251_write_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg); + elp_reg = wl1251_read_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); + + if (!(elp_reg & ELPCTRL_WLAN_READY)) + wl1251_warning("WLAN not ready"); +} + +static int wl1251_chip_wakeup(struct wl1251 *wl) +{ + int ret = 0; + + wl1251_power_on(wl); + msleep(WL1251_POWER_ON_SLEEP); + wl->if_ops->reset(wl); + + /* We don't need a real memory partition here, because we only want + * to use the registers at this point. */ + wl1251_set_partition(wl, + 0x00000000, + 0x00000000, + REGISTERS_BASE, + REGISTERS_DOWN_SIZE); + + /* ELP module wake up */ + wl1251_fw_wakeup(wl); + + /* whal_FwCtrl_BootSm() */ + + /* 0. read chip id from CHIP_ID */ + wl->chip_id = wl1251_reg_read32(wl, CHIP_ID_B); + + /* 1. check if chip id is valid */ + + switch (wl->chip_id) { + case CHIP_ID_1251_PG12: + wl1251_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG12)", + wl->chip_id); + break; + case CHIP_ID_1251_PG11: + wl1251_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG11)", + wl->chip_id); + break; + case CHIP_ID_1251_PG10: + default: + wl1251_error("unsupported chip id: 0x%x", wl->chip_id); + ret = -ENODEV; + goto out; + } + + if (wl->fw == NULL) { + ret = wl1251_fetch_firmware(wl); + if (ret < 0) + goto out; + } + + if (wl->nvs == NULL && !wl->use_eeprom) { + /* No NVS from netlink, try to get it from the filesystem */ + ret = wl1251_fetch_nvs(wl); + if (ret < 0) + goto out; + } + +out: + return ret; +} + +#define WL1251_IRQ_LOOP_COUNT 10 +static void wl1251_irq_work(struct work_struct *work) +{ + u32 intr, ctr = WL1251_IRQ_LOOP_COUNT; + struct wl1251 *wl = + container_of(work, struct wl1251, irq_work); + int ret; + + mutex_lock(&wl->mutex); + + wl1251_debug(DEBUG_IRQ, "IRQ work"); + + if (wl->state == WL1251_STATE_OFF) + goto out; + + ret = wl1251_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1251_ACX_INTR_ALL); + + intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); + wl1251_debug(DEBUG_IRQ, "intr: 0x%x", intr); + + do { + if (wl->data_path) { + wl->rx_counter = wl1251_mem_read32( + wl, wl->data_path->rx_control_addr); + + /* We handle a frmware bug here */ + switch ((wl->rx_counter - wl->rx_handled) & 0xf) { + case 0: + wl1251_debug(DEBUG_IRQ, + "RX: FW and host in sync"); + intr &= ~WL1251_ACX_INTR_RX0_DATA; + intr &= ~WL1251_ACX_INTR_RX1_DATA; + break; + case 1: + wl1251_debug(DEBUG_IRQ, "RX: FW +1"); + intr |= WL1251_ACX_INTR_RX0_DATA; + intr &= ~WL1251_ACX_INTR_RX1_DATA; + break; + case 2: + wl1251_debug(DEBUG_IRQ, "RX: FW +2"); + intr |= WL1251_ACX_INTR_RX0_DATA; + intr |= WL1251_ACX_INTR_RX1_DATA; + break; + default: + wl1251_warning( + "RX: FW and host out of sync: %d", + wl->rx_counter - wl->rx_handled); + break; + } + + wl->rx_handled = wl->rx_counter; + + wl1251_debug(DEBUG_IRQ, "RX counter: %d", + wl->rx_counter); + } + + intr &= wl->intr_mask; + + if (intr == 0) { + wl1251_debug(DEBUG_IRQ, "INTR is 0"); + goto out_sleep; + } + + if (intr & WL1251_ACX_INTR_RX0_DATA) { + wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA"); + wl1251_rx(wl); + } + + if (intr & WL1251_ACX_INTR_RX1_DATA) { + wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA"); + wl1251_rx(wl); + } + + if (intr & WL1251_ACX_INTR_TX_RESULT) { + wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT"); + wl1251_tx_complete(wl); + } + + if (intr & WL1251_ACX_INTR_EVENT_A) { + wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT_A"); + wl1251_event_handle(wl, 0); + } + + if (intr & WL1251_ACX_INTR_EVENT_B) { + wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT_B"); + wl1251_event_handle(wl, 1); + } + + if (intr & WL1251_ACX_INTR_INIT_COMPLETE) + wl1251_debug(DEBUG_IRQ, + "WL1251_ACX_INTR_INIT_COMPLETE"); + + if (--ctr == 0) + break; + + intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); + } while (intr); + +out_sleep: + wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); + wl1251_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); +} + +static int wl1251_join(struct wl1251 *wl, u8 bss_type, u8 channel, + u16 beacon_interval, u8 dtim_period) +{ + int ret; + + ret = wl1251_acx_frame_rates(wl, DEFAULT_HW_GEN_TX_RATE, + DEFAULT_HW_GEN_MODULATION_TYPE, + wl->tx_mgmt_frm_rate, + wl->tx_mgmt_frm_mod); + if (ret < 0) + goto out; + + + ret = wl1251_cmd_join(wl, bss_type, channel, beacon_interval, + dtim_period); + if (ret < 0) + goto out; + + ret = wl1251_event_wait(wl, JOIN_EVENT_COMPLETE_ID, 100); + if (ret < 0) + wl1251_warning("join timeout"); + +out: + return ret; +} + +static void wl1251_filter_work(struct work_struct *work) +{ + struct wl1251 *wl = + container_of(work, struct wl1251, filter_work); + int ret; + + mutex_lock(&wl->mutex); + + if (wl->state == WL1251_STATE_OFF) + goto out; + + ret = wl1251_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + ret = wl1251_join(wl, wl->bss_type, wl->channel, wl->beacon_int, + wl->dtim_period); + if (ret < 0) + goto out_sleep; + +out_sleep: + wl1251_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); +} + +static int wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct wl1251 *wl = hw->priv; + unsigned long flags; + + skb_queue_tail(&wl->tx_queue, skb); + + /* + * The chip specific setup must run before the first TX packet - + * before that, the tx_work will not be initialized! + */ + + ieee80211_queue_work(wl->hw, &wl->tx_work); + + /* + * The workqueue is slow to process the tx_queue and we need stop + * the queue here, otherwise the queue will get too long. + */ + if (skb_queue_len(&wl->tx_queue) >= WL1251_TX_QUEUE_HIGH_WATERMARK) { + wl1251_debug(DEBUG_TX, "op_tx: tx_queue full, stop queues"); + + spin_lock_irqsave(&wl->wl_lock, flags); + ieee80211_stop_queues(wl->hw); + wl->tx_queue_stopped = true; + spin_unlock_irqrestore(&wl->wl_lock, flags); + } + + return NETDEV_TX_OK; +} + +static int wl1251_op_start(struct ieee80211_hw *hw) +{ + struct wl1251 *wl = hw->priv; + struct wiphy *wiphy = hw->wiphy; + int ret = 0; + + wl1251_debug(DEBUG_MAC80211, "mac80211 start"); + + mutex_lock(&wl->mutex); + + if (wl->state != WL1251_STATE_OFF) { + wl1251_error("cannot start because not in off state: %d", + wl->state); + ret = -EBUSY; + goto out; + } + + ret = wl1251_chip_wakeup(wl); + if (ret < 0) + goto out; + + ret = wl1251_boot(wl); + if (ret < 0) + goto out; + + ret = wl1251_hw_init(wl); + if (ret < 0) + goto out; + + ret = wl1251_acx_station_id(wl); + if (ret < 0) + goto out; + + wl->state = WL1251_STATE_ON; + + wl1251_info("firmware booted (%s)", wl->fw_ver); + + /* update hw/fw version info in wiphy struct */ + wiphy->hw_version = wl->chip_id; + strncpy(wiphy->fw_version, wl->fw_ver, sizeof(wiphy->fw_version)); + +out: + if (ret < 0) + wl1251_power_off(wl); + + mutex_unlock(&wl->mutex); + + return ret; +} + +static void wl1251_op_stop(struct ieee80211_hw *hw) +{ + struct wl1251 *wl = hw->priv; + + wl1251_info("down"); + + wl1251_debug(DEBUG_MAC80211, "mac80211 stop"); + + mutex_lock(&wl->mutex); + + WARN_ON(wl->state != WL1251_STATE_ON); + + if (wl->scanning) { + ieee80211_scan_completed(wl->hw, true); + wl->scanning = false; + } + + wl->state = WL1251_STATE_OFF; + + wl1251_disable_interrupts(wl); + + mutex_unlock(&wl->mutex); + + cancel_work_sync(&wl->irq_work); + cancel_work_sync(&wl->tx_work); + cancel_work_sync(&wl->filter_work); + + mutex_lock(&wl->mutex); + + /* let's notify MAC80211 about the remaining pending TX frames */ + wl1251_tx_flush(wl); + wl1251_power_off(wl); + + memset(wl->bssid, 0, ETH_ALEN); + wl->listen_int = 1; + wl->bss_type = MAX_BSS_TYPE; + + wl->data_in_count = 0; + wl->rx_counter = 0; + wl->rx_handled = 0; + wl->rx_current_buffer = 0; + wl->rx_last_id = 0; + wl->next_tx_complete = 0; + wl->elp = false; + wl->psm = 0; + wl->tx_queue_stopped = false; + wl->power_level = WL1251_DEFAULT_POWER_LEVEL; + wl->channel = WL1251_DEFAULT_CHANNEL; + + wl1251_debugfs_reset(wl); + + mutex_unlock(&wl->mutex); +} + +static int wl1251_op_add_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct wl1251 *wl = hw->priv; + int ret = 0; + + wl1251_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", + vif->type, vif->addr); + + mutex_lock(&wl->mutex); + if (wl->vif) { + ret = -EBUSY; + goto out; + } + + wl->vif = vif; + + switch (vif->type) { + case NL80211_IFTYPE_STATION: + wl->bss_type = BSS_TYPE_STA_BSS; + break; + case NL80211_IFTYPE_ADHOC: + wl->bss_type = BSS_TYPE_IBSS; + break; + default: + ret = -EOPNOTSUPP; + goto out; + } + + if (memcmp(wl->mac_addr, vif->addr, ETH_ALEN)) { + memcpy(wl->mac_addr, vif->addr, ETH_ALEN); + SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); + ret = wl1251_acx_station_id(wl); + if (ret < 0) + goto out; + } + +out: + mutex_unlock(&wl->mutex); + return ret; +} + +static void wl1251_op_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct wl1251 *wl = hw->priv; + + mutex_lock(&wl->mutex); + wl1251_debug(DEBUG_MAC80211, "mac80211 remove interface"); + wl->vif = NULL; + mutex_unlock(&wl->mutex); +} + +static int wl1251_build_qos_null_data(struct wl1251 *wl) +{ + struct ieee80211_qos_hdr template; + + memset(&template, 0, sizeof(template)); + + memcpy(template.addr1, wl->bssid, ETH_ALEN); + memcpy(template.addr2, wl->mac_addr, ETH_ALEN); + memcpy(template.addr3, wl->bssid, ETH_ALEN); + + template.frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | + IEEE80211_STYPE_QOS_NULLFUNC | + IEEE80211_FCTL_TODS); + + /* FIXME: not sure what priority to use here */ + template.qos_ctrl = cpu_to_le16(0); + + return wl1251_cmd_template_set(wl, CMD_QOS_NULL_DATA, &template, + sizeof(template)); +} + +static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) +{ + struct wl1251 *wl = hw->priv; + struct ieee80211_conf *conf = &hw->conf; + int channel, ret = 0; + + channel = ieee80211_frequency_to_channel(conf->channel->center_freq); + + wl1251_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d", + channel, + conf->flags & IEEE80211_CONF_PS ? "on" : "off", + conf->power_level); + + mutex_lock(&wl->mutex); + + ret = wl1251_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + if (channel != wl->channel) { + wl->channel = channel; + + ret = wl1251_join(wl, wl->bss_type, wl->channel, + wl->beacon_int, wl->dtim_period); + if (ret < 0) + goto out_sleep; + } + + if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) { + wl1251_debug(DEBUG_PSM, "psm enabled"); + + wl->psm_requested = true; + + wl->dtim_period = conf->ps_dtim_period; + + ret = wl1251_acx_wr_tbtt_and_dtim(wl, wl->beacon_int, + wl->dtim_period); + + /* + * mac80211 enables PSM only if we're already associated. + */ + ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE); + if (ret < 0) + goto out_sleep; + } else if (!(conf->flags & IEEE80211_CONF_PS) && + wl->psm_requested) { + wl1251_debug(DEBUG_PSM, "psm disabled"); + + wl->psm_requested = false; + + if (wl->psm) { + ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE); + if (ret < 0) + goto out_sleep; + } + } + + if (conf->power_level != wl->power_level) { + ret = wl1251_acx_tx_power(wl, conf->power_level); + if (ret < 0) + goto out_sleep; + + wl->power_level = conf->power_level; + } + +out_sleep: + wl1251_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + + return ret; +} + +#define WL1251_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ + FIF_ALLMULTI | \ + FIF_FCSFAIL | \ + FIF_BCN_PRBRESP_PROMISC | \ + FIF_CONTROL | \ + FIF_OTHER_BSS) + +static void wl1251_op_configure_filter(struct ieee80211_hw *hw, + unsigned int changed, + unsigned int *total,u64 multicast) +{ + struct wl1251 *wl = hw->priv; + + wl1251_debug(DEBUG_MAC80211, "mac80211 configure filter"); + + *total &= WL1251_SUPPORTED_FILTERS; + changed &= WL1251_SUPPORTED_FILTERS; + + if (changed == 0) + /* no filters which we support changed */ + return; + + /* FIXME: wl->rx_config and wl->rx_filter are not protected */ + + wl->rx_config = WL1251_DEFAULT_RX_CONFIG; + wl->rx_filter = WL1251_DEFAULT_RX_FILTER; + + if (*total & FIF_PROMISC_IN_BSS) { + wl->rx_config |= CFG_BSSID_FILTER_EN; + wl->rx_config |= CFG_RX_ALL_GOOD; + } + if (*total & FIF_ALLMULTI) + /* + * CFG_MC_FILTER_EN in rx_config needs to be 0 to receive + * all multicast frames + */ + wl->rx_config &= ~CFG_MC_FILTER_EN; + if (*total & FIF_FCSFAIL) + wl->rx_filter |= CFG_RX_FCS_ERROR; + if (*total & FIF_BCN_PRBRESP_PROMISC) { + wl->rx_config &= ~CFG_BSSID_FILTER_EN; + wl->rx_config &= ~CFG_SSID_FILTER_EN; + } + if (*total & FIF_CONTROL) + wl->rx_filter |= CFG_RX_CTL_EN; + if (*total & FIF_OTHER_BSS) + wl->rx_filter &= ~CFG_BSSID_FILTER_EN; + + /* + * FIXME: workqueues need to be properly cancelled on stop(), for + * now let's just disable changing the filter settings. They will + * be updated any on config(). + */ + /* schedule_work(&wl->filter_work); */ +} + +/* HW encryption */ +static int wl1251_set_key_type(struct wl1251 *wl, + struct wl1251_cmd_set_keys *key, + enum set_key_cmd cmd, + struct ieee80211_key_conf *mac80211_key, + const u8 *addr) +{ + switch (mac80211_key->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + if (is_broadcast_ether_addr(addr)) + key->key_type = KEY_WEP_DEFAULT; + else + key->key_type = KEY_WEP_ADDR; + + mac80211_key->hw_key_idx = mac80211_key->keyidx; + break; + case WLAN_CIPHER_SUITE_TKIP: + if (is_broadcast_ether_addr(addr)) + key->key_type = KEY_TKIP_MIC_GROUP; + else + key->key_type = KEY_TKIP_MIC_PAIRWISE; + + mac80211_key->hw_key_idx = mac80211_key->keyidx; + break; + case WLAN_CIPHER_SUITE_CCMP: + if (is_broadcast_ether_addr(addr)) + key->key_type = KEY_AES_GROUP; + else + key->key_type = KEY_AES_PAIRWISE; + mac80211_key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + break; + default: + wl1251_error("Unknown key cipher 0x%x", mac80211_key->cipher); + return -EOPNOTSUPP; + } + + return 0; +} + +static int wl1251_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + struct wl1251 *wl = hw->priv; + struct wl1251_cmd_set_keys *wl_cmd; + const u8 *addr; + int ret; + + static const u8 bcast_addr[ETH_ALEN] = + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + wl1251_debug(DEBUG_MAC80211, "mac80211 set key"); + + wl_cmd = kzalloc(sizeof(*wl_cmd), GFP_KERNEL); + if (!wl_cmd) { + ret = -ENOMEM; + goto out; + } + + addr = sta ? sta->addr : bcast_addr; + + wl1251_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd); + wl1251_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN); + wl1251_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x", + key->cipher, key->keyidx, key->keylen, key->flags); + wl1251_dump(DEBUG_CRYPT, "KEY: ", key->key, key->keylen); + + if (is_zero_ether_addr(addr)) { + /* We dont support TX only encryption */ + ret = -EOPNOTSUPP; + goto out; + } + + mutex_lock(&wl->mutex); + + ret = wl1251_ps_elp_wakeup(wl); + if (ret < 0) + goto out_unlock; + + switch (cmd) { + case SET_KEY: + wl_cmd->key_action = KEY_ADD_OR_REPLACE; + break; + case DISABLE_KEY: + wl_cmd->key_action = KEY_REMOVE; + break; + default: + wl1251_error("Unsupported key cmd 0x%x", cmd); + break; + } + + ret = wl1251_set_key_type(wl, wl_cmd, cmd, key, addr); + if (ret < 0) { + wl1251_error("Set KEY type failed"); + goto out_sleep; + } + + if (wl_cmd->key_type != KEY_WEP_DEFAULT) + memcpy(wl_cmd->addr, addr, ETH_ALEN); + + if ((wl_cmd->key_type == KEY_TKIP_MIC_GROUP) || + (wl_cmd->key_type == KEY_TKIP_MIC_PAIRWISE)) { + /* + * We get the key in the following form: + * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes) + * but the target is expecting: + * TKIP - RX MIC - TX MIC + */ + memcpy(wl_cmd->key, key->key, 16); + memcpy(wl_cmd->key + 16, key->key + 24, 8); + memcpy(wl_cmd->key + 24, key->key + 16, 8); + + } else { + memcpy(wl_cmd->key, key->key, key->keylen); + } + wl_cmd->key_size = key->keylen; + + wl_cmd->id = key->keyidx; + wl_cmd->ssid_profile = 0; + + wl1251_dump(DEBUG_CRYPT, "TARGET KEY: ", wl_cmd, sizeof(*wl_cmd)); + + ret = wl1251_cmd_send(wl, CMD_SET_KEYS, wl_cmd, sizeof(*wl_cmd)); + if (ret < 0) { + wl1251_warning("could not set keys"); + goto out_sleep; + } + +out_sleep: + wl1251_ps_elp_sleep(wl); + +out_unlock: + mutex_unlock(&wl->mutex); + +out: + kfree(wl_cmd); + + return ret; +} + +static int wl1251_op_hw_scan(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_scan_request *req) +{ + struct wl1251 *wl = hw->priv; + struct sk_buff *skb; + size_t ssid_len = 0; + u8 *ssid = NULL; + int ret; + + wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan"); + + if (req->n_ssids) { + ssid = req->ssids[0].ssid; + ssid_len = req->ssids[0].ssid_len; + } + + mutex_lock(&wl->mutex); + + if (wl->scanning) { + wl1251_debug(DEBUG_SCAN, "scan already in progress"); + ret = -EINVAL; + goto out; + } + + ret = wl1251_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + skb = ieee80211_probereq_get(wl->hw, wl->vif, ssid, ssid_len, + req->ie, req->ie_len); + if (!skb) { + ret = -ENOMEM; + goto out; + } + + ret = wl1251_cmd_template_set(wl, CMD_PROBE_REQ, skb->data, + skb->len); + dev_kfree_skb(skb); + if (ret < 0) + goto out_sleep; + + ret = wl1251_cmd_trigger_scan_to(wl, 0); + if (ret < 0) + goto out_sleep; + + wl->scanning = true; + + ret = wl1251_cmd_scan(wl, ssid, ssid_len, req->channels, + req->n_channels, WL1251_SCAN_NUM_PROBES); + if (ret < 0) { + wl->scanning = false; + goto out_sleep; + } + +out_sleep: + wl1251_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + + return ret; +} + +static int wl1251_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +{ + struct wl1251 *wl = hw->priv; + int ret; + + mutex_lock(&wl->mutex); + + ret = wl1251_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + ret = wl1251_acx_rts_threshold(wl, (u16) value); + if (ret < 0) + wl1251_warning("wl1251_op_set_rts_threshold failed: %d", ret); + + wl1251_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + + return ret; +} + +static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changed) +{ + struct wl1251 *wl = hw->priv; + struct sk_buff *beacon, *skb; + int ret; + + wl1251_debug(DEBUG_MAC80211, "mac80211 bss info changed"); + + mutex_lock(&wl->mutex); + + ret = wl1251_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + if (changed & BSS_CHANGED_BSSID) { + memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN); + + skb = ieee80211_nullfunc_get(wl->hw, wl->vif); + if (!skb) + goto out_sleep; + + ret = wl1251_cmd_template_set(wl, CMD_NULL_DATA, + skb->data, skb->len); + dev_kfree_skb(skb); + if (ret < 0) + goto out_sleep; + + ret = wl1251_build_qos_null_data(wl); + if (ret < 0) + goto out; + + if (wl->bss_type != BSS_TYPE_IBSS) { + ret = wl1251_join(wl, wl->bss_type, wl->channel, + wl->beacon_int, wl->dtim_period); + if (ret < 0) + goto out_sleep; + } + } + + if (changed & BSS_CHANGED_ASSOC) { + if (bss_conf->assoc) { + wl->beacon_int = bss_conf->beacon_int; + + skb = ieee80211_pspoll_get(wl->hw, wl->vif); + if (!skb) + goto out_sleep; + + ret = wl1251_cmd_template_set(wl, CMD_PS_POLL, + skb->data, + skb->len); + dev_kfree_skb(skb); + if (ret < 0) + goto out_sleep; + + ret = wl1251_acx_aid(wl, bss_conf->aid); + if (ret < 0) + goto out_sleep; + } else { + /* use defaults when not associated */ + wl->beacon_int = WL1251_DEFAULT_BEACON_INT; + wl->dtim_period = WL1251_DEFAULT_DTIM_PERIOD; + } + } + if (changed & BSS_CHANGED_ERP_SLOT) { + if (bss_conf->use_short_slot) + ret = wl1251_acx_slot(wl, SLOT_TIME_SHORT); + else + ret = wl1251_acx_slot(wl, SLOT_TIME_LONG); + if (ret < 0) { + wl1251_warning("Set slot time failed %d", ret); + goto out_sleep; + } + } + + if (changed & BSS_CHANGED_ERP_PREAMBLE) { + if (bss_conf->use_short_preamble) + wl1251_acx_set_preamble(wl, ACX_PREAMBLE_SHORT); + else + wl1251_acx_set_preamble(wl, ACX_PREAMBLE_LONG); + } + + if (changed & BSS_CHANGED_ERP_CTS_PROT) { + if (bss_conf->use_cts_prot) + ret = wl1251_acx_cts_protect(wl, CTSPROTECT_ENABLE); + else + ret = wl1251_acx_cts_protect(wl, CTSPROTECT_DISABLE); + if (ret < 0) { + wl1251_warning("Set ctsprotect failed %d", ret); + goto out_sleep; + } + } + + if (changed & BSS_CHANGED_BEACON) { + beacon = ieee80211_beacon_get(hw, vif); + ret = wl1251_cmd_template_set(wl, CMD_BEACON, beacon->data, + beacon->len); + + if (ret < 0) { + dev_kfree_skb(beacon); + goto out_sleep; + } + + ret = wl1251_cmd_template_set(wl, CMD_PROBE_RESP, beacon->data, + beacon->len); + + dev_kfree_skb(beacon); + + if (ret < 0) + goto out_sleep; + + ret = wl1251_join(wl, wl->bss_type, wl->beacon_int, + wl->channel, wl->dtim_period); + + if (ret < 0) + goto out_sleep; + } + +out_sleep: + wl1251_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); +} + + +/* can't be const, mac80211 writes to this */ +static struct ieee80211_rate wl1251_rates[] = { + { .bitrate = 10, + .hw_value = 0x1, + .hw_value_short = 0x1, }, + { .bitrate = 20, + .hw_value = 0x2, + .hw_value_short = 0x2, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 55, + .hw_value = 0x4, + .hw_value_short = 0x4, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 110, + .hw_value = 0x20, + .hw_value_short = 0x20, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 60, + .hw_value = 0x8, + .hw_value_short = 0x8, }, + { .bitrate = 90, + .hw_value = 0x10, + .hw_value_short = 0x10, }, + { .bitrate = 120, + .hw_value = 0x40, + .hw_value_short = 0x40, }, + { .bitrate = 180, + .hw_value = 0x80, + .hw_value_short = 0x80, }, + { .bitrate = 240, + .hw_value = 0x200, + .hw_value_short = 0x200, }, + { .bitrate = 360, + .hw_value = 0x400, + .hw_value_short = 0x400, }, + { .bitrate = 480, + .hw_value = 0x800, + .hw_value_short = 0x800, }, + { .bitrate = 540, + .hw_value = 0x1000, + .hw_value_short = 0x1000, }, +}; + +/* can't be const, mac80211 writes to this */ +static struct ieee80211_channel wl1251_channels[] = { + { .hw_value = 1, .center_freq = 2412}, + { .hw_value = 2, .center_freq = 2417}, + { .hw_value = 3, .center_freq = 2422}, + { .hw_value = 4, .center_freq = 2427}, + { .hw_value = 5, .center_freq = 2432}, + { .hw_value = 6, .center_freq = 2437}, + { .hw_value = 7, .center_freq = 2442}, + { .hw_value = 8, .center_freq = 2447}, + { .hw_value = 9, .center_freq = 2452}, + { .hw_value = 10, .center_freq = 2457}, + { .hw_value = 11, .center_freq = 2462}, + { .hw_value = 12, .center_freq = 2467}, + { .hw_value = 13, .center_freq = 2472}, +}; + +static int wl1251_op_conf_tx(struct ieee80211_hw *hw, u16 queue, + const struct ieee80211_tx_queue_params *params) +{ + enum wl1251_acx_ps_scheme ps_scheme; + struct wl1251 *wl = hw->priv; + int ret; + + mutex_lock(&wl->mutex); + + wl1251_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue); + + ret = wl1251_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + /* mac80211 uses units of 32 usec */ + ret = wl1251_acx_ac_cfg(wl, wl1251_tx_get_queue(queue), + params->cw_min, params->cw_max, + params->aifs, params->txop * 32); + if (ret < 0) + goto out_sleep; + + if (params->uapsd) + ps_scheme = WL1251_ACX_PS_SCHEME_UPSD_TRIGGER; + else + ps_scheme = WL1251_ACX_PS_SCHEME_LEGACY; + + ret = wl1251_acx_tid_cfg(wl, wl1251_tx_get_queue(queue), + CHANNEL_TYPE_EDCF, + wl1251_tx_get_queue(queue), ps_scheme, + WL1251_ACX_ACK_POLICY_LEGACY); + if (ret < 0) + goto out_sleep; + +out_sleep: + wl1251_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + + return ret; +} + +static int wl1251_op_get_survey(struct ieee80211_hw *hw, int idx, + struct survey_info *survey) +{ + struct wl1251 *wl = hw->priv; + struct ieee80211_conf *conf = &hw->conf; + + if (idx != 0) + return -ENOENT; + + survey->channel = conf->channel; + survey->filled = SURVEY_INFO_NOISE_DBM; + survey->noise = wl->noise; + + return 0; +} + +/* can't be const, mac80211 writes to this */ +static struct ieee80211_supported_band wl1251_band_2ghz = { + .channels = wl1251_channels, + .n_channels = ARRAY_SIZE(wl1251_channels), + .bitrates = wl1251_rates, + .n_bitrates = ARRAY_SIZE(wl1251_rates), +}; + +static const struct ieee80211_ops wl1251_ops = { + .start = wl1251_op_start, + .stop = wl1251_op_stop, + .add_interface = wl1251_op_add_interface, + .remove_interface = wl1251_op_remove_interface, + .config = wl1251_op_config, + .configure_filter = wl1251_op_configure_filter, + .tx = wl1251_op_tx, + .set_key = wl1251_op_set_key, + .hw_scan = wl1251_op_hw_scan, + .bss_info_changed = wl1251_op_bss_info_changed, + .set_rts_threshold = wl1251_op_set_rts_threshold, + .conf_tx = wl1251_op_conf_tx, + .get_survey = wl1251_op_get_survey, +}; + +static int wl1251_read_eeprom_byte(struct wl1251 *wl, off_t offset, u8 *data) +{ + unsigned long timeout; + + wl1251_reg_write32(wl, EE_ADDR, offset); + wl1251_reg_write32(wl, EE_CTL, EE_CTL_READ); + + /* EE_CTL_READ clears when data is ready */ + timeout = jiffies + msecs_to_jiffies(100); + while (1) { + if (!(wl1251_reg_read32(wl, EE_CTL) & EE_CTL_READ)) + break; + + if (time_after(jiffies, timeout)) + return -ETIMEDOUT; + + msleep(1); + } + + *data = wl1251_reg_read32(wl, EE_DATA); + return 0; +} + +static int wl1251_read_eeprom(struct wl1251 *wl, off_t offset, + u8 *data, size_t len) +{ + size_t i; + int ret; + + wl1251_reg_write32(wl, EE_START, 0); + + for (i = 0; i < len; i++) { + ret = wl1251_read_eeprom_byte(wl, offset + i, &data[i]); + if (ret < 0) + return ret; + } + + return 0; +} + +static int wl1251_read_eeprom_mac(struct wl1251 *wl) +{ + u8 mac[ETH_ALEN]; + int i, ret; + + wl1251_set_partition(wl, 0, 0, REGISTERS_BASE, REGISTERS_DOWN_SIZE); + + ret = wl1251_read_eeprom(wl, 0x1c, mac, sizeof(mac)); + if (ret < 0) { + wl1251_warning("failed to read MAC address from EEPROM"); + return ret; + } + + /* MAC is stored in reverse order */ + for (i = 0; i < ETH_ALEN; i++) + wl->mac_addr[i] = mac[ETH_ALEN - i - 1]; + + return 0; +} + +static int wl1251_register_hw(struct wl1251 *wl) +{ + int ret; + + if (wl->mac80211_registered) + return 0; + + SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); + + ret = ieee80211_register_hw(wl->hw); + if (ret < 0) { + wl1251_error("unable to register mac80211 hw: %d", ret); + return ret; + } + + wl->mac80211_registered = true; + + wl1251_notice("loaded"); + + return 0; +} + +int wl1251_init_ieee80211(struct wl1251 *wl) +{ + int ret; + + /* The tx descriptor buffer and the TKIP space */ + wl->hw->extra_tx_headroom = sizeof(struct tx_double_buffer_desc) + + WL1251_TKIP_IV_SPACE; + + /* unit us */ + /* FIXME: find a proper value */ + wl->hw->channel_change_time = 10000; + + wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_SUPPORTS_PS | + IEEE80211_HW_BEACON_FILTER | + IEEE80211_HW_SUPPORTS_UAPSD; + + wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); + wl->hw->wiphy->max_scan_ssids = 1; + wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1251_band_2ghz; + + wl->hw->queues = 4; + + if (wl->use_eeprom) + wl1251_read_eeprom_mac(wl); + + ret = wl1251_register_hw(wl); + if (ret) + goto out; + + wl1251_debugfs_init(wl); + wl1251_notice("initialized"); + + ret = 0; + +out: + return ret; +} +EXPORT_SYMBOL_GPL(wl1251_init_ieee80211); + +struct ieee80211_hw *wl1251_alloc_hw(void) +{ + struct ieee80211_hw *hw; + struct wl1251 *wl; + int i; + static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf}; + + hw = ieee80211_alloc_hw(sizeof(*wl), &wl1251_ops); + if (!hw) { + wl1251_error("could not alloc ieee80211_hw"); + return ERR_PTR(-ENOMEM); + } + + wl = hw->priv; + memset(wl, 0, sizeof(*wl)); + + wl->hw = hw; + + wl->data_in_count = 0; + + skb_queue_head_init(&wl->tx_queue); + + INIT_WORK(&wl->filter_work, wl1251_filter_work); + INIT_DELAYED_WORK(&wl->elp_work, wl1251_elp_work); + wl->channel = WL1251_DEFAULT_CHANNEL; + wl->scanning = false; + wl->default_key = 0; + wl->listen_int = 1; + wl->rx_counter = 0; + wl->rx_handled = 0; + wl->rx_current_buffer = 0; + wl->rx_last_id = 0; + wl->rx_config = WL1251_DEFAULT_RX_CONFIG; + wl->rx_filter = WL1251_DEFAULT_RX_FILTER; + wl->elp = false; + wl->psm = 0; + wl->psm_requested = false; + wl->tx_queue_stopped = false; + wl->power_level = WL1251_DEFAULT_POWER_LEVEL; + wl->beacon_int = WL1251_DEFAULT_BEACON_INT; + wl->dtim_period = WL1251_DEFAULT_DTIM_PERIOD; + wl->vif = NULL; + + for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) + wl->tx_frames[i] = NULL; + + wl->next_tx_complete = 0; + + INIT_WORK(&wl->irq_work, wl1251_irq_work); + INIT_WORK(&wl->tx_work, wl1251_tx_work); + + /* + * In case our MAC address is not correctly set, + * we use a random but Nokia MAC. + */ + memcpy(wl->mac_addr, nokia_oui, 3); + get_random_bytes(wl->mac_addr + 3, 3); + + wl->state = WL1251_STATE_OFF; + mutex_init(&wl->mutex); + + wl->tx_mgmt_frm_rate = DEFAULT_HW_GEN_TX_RATE; + wl->tx_mgmt_frm_mod = DEFAULT_HW_GEN_MODULATION_TYPE; + + wl->rx_descriptor = kmalloc(sizeof(*wl->rx_descriptor), GFP_KERNEL); + if (!wl->rx_descriptor) { + wl1251_error("could not allocate memory for rx descriptor"); + ieee80211_free_hw(hw); + return ERR_PTR(-ENOMEM); + } + + return hw; +} +EXPORT_SYMBOL_GPL(wl1251_alloc_hw); + +int wl1251_free_hw(struct wl1251 *wl) +{ + ieee80211_unregister_hw(wl->hw); + + wl1251_debugfs_exit(wl); + + kfree(wl->target_mem_map); + kfree(wl->data_path); + vfree(wl->fw); + wl->fw = NULL; + kfree(wl->nvs); + wl->nvs = NULL; + + kfree(wl->rx_descriptor); + wl->rx_descriptor = NULL; + + ieee80211_free_hw(wl->hw); + + return 0; +} +EXPORT_SYMBOL_GPL(wl1251_free_hw); + +MODULE_DESCRIPTION("TI wl1251 Wireles LAN Driver Core"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kalle Valo "); +MODULE_FIRMWARE(WL1251_FW_NAME); diff --git a/drivers/net/wireless/wl1251/ps.c b/drivers/net/wireless/wl1251/ps.c new file mode 100644 index 0000000..5ed47c8 --- /dev/null +++ b/drivers/net/wireless/wl1251/ps.c @@ -0,0 +1,194 @@ +/* + * This file is part of wl1251 + * + * Copyright (C) 2008 Nokia Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "reg.h" +#include "ps.h" +#include "cmd.h" +#include "io.h" + +/* in ms */ +#define WL1251_WAKEUP_TIMEOUT 100 + +void wl1251_elp_work(struct work_struct *work) +{ + struct delayed_work *dwork; + struct wl1251 *wl; + + dwork = container_of(work, struct delayed_work, work); + wl = container_of(dwork, struct wl1251, elp_work); + + wl1251_debug(DEBUG_PSM, "elp work"); + + mutex_lock(&wl->mutex); + + if (wl->elp || !wl->psm) + goto out; + + wl1251_debug(DEBUG_PSM, "chip to elp"); + wl1251_write_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); + wl->elp = true; + +out: + mutex_unlock(&wl->mutex); +} + +#define ELP_ENTRY_DELAY 5 + +/* Routines to toggle sleep mode while in ELP */ +void wl1251_ps_elp_sleep(struct wl1251 *wl) +{ + unsigned long delay; + + if (wl->psm) { + cancel_delayed_work(&wl->elp_work); + delay = msecs_to_jiffies(ELP_ENTRY_DELAY); + ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, delay); + } +} + +int wl1251_ps_elp_wakeup(struct wl1251 *wl) +{ + unsigned long timeout, start; + u32 elp_reg; + + if (!wl->elp) + return 0; + + wl1251_debug(DEBUG_PSM, "waking up chip from elp"); + + start = jiffies; + timeout = jiffies + msecs_to_jiffies(WL1251_WAKEUP_TIMEOUT); + + wl1251_write_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP); + + elp_reg = wl1251_read_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); + + /* + * FIXME: we should wait for irq from chip but, as a temporary + * solution to simplify locking, let's poll instead + */ + while (!(elp_reg & ELPCTRL_WLAN_READY)) { + if (time_after(jiffies, timeout)) { + wl1251_error("elp wakeup timeout"); + return -ETIMEDOUT; + } + msleep(1); + elp_reg = wl1251_read_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); + } + + wl1251_debug(DEBUG_PSM, "wakeup time: %u ms", + jiffies_to_msecs(jiffies - start)); + + wl->elp = false; + + return 0; +} + +static int wl1251_ps_set_elp(struct wl1251 *wl, bool enable) +{ + int ret; + + if (enable) { + wl1251_debug(DEBUG_PSM, "sleep auth psm/elp"); + + ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_ELP); + if (ret < 0) + return ret; + + wl1251_ps_elp_sleep(wl); + } else { + wl1251_debug(DEBUG_PSM, "sleep auth cam"); + + /* + * When the target is in ELP, we can only + * access the ELP control register. Thus, + * we have to wake the target up before + * changing the power authorization. + */ + + wl1251_ps_elp_wakeup(wl); + + ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM); + if (ret < 0) + return ret; + } + + return 0; +} + +int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode) +{ + int ret; + + switch (mode) { + case STATION_POWER_SAVE_MODE: + wl1251_debug(DEBUG_PSM, "entering psm"); + + /* enable beacon filtering */ + ret = wl1251_acx_beacon_filter_opt(wl, true); + if (ret < 0) + return ret; + + ret = wl1251_acx_wake_up_conditions(wl, + WAKE_UP_EVENT_DTIM_BITMAP, + wl->listen_int); + if (ret < 0) + return ret; + + ret = wl1251_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE); + if (ret < 0) + return ret; + + ret = wl1251_ps_set_elp(wl, true); + if (ret < 0) + return ret; + + wl->psm = 1; + break; + case STATION_ACTIVE_MODE: + default: + wl1251_debug(DEBUG_PSM, "leaving psm"); + ret = wl1251_ps_set_elp(wl, false); + if (ret < 0) + return ret; + + /* disable beacon filtering */ + ret = wl1251_acx_beacon_filter_opt(wl, false); + if (ret < 0) + return ret; + + ret = wl1251_acx_wake_up_conditions(wl, + WAKE_UP_EVENT_DTIM_BITMAP, + wl->listen_int); + if (ret < 0) + return ret; + + ret = wl1251_cmd_ps_mode(wl, STATION_ACTIVE_MODE); + if (ret < 0) + return ret; + + wl->psm = 0; + break; + } + + return ret; +} + diff --git a/drivers/net/wireless/wl1251/ps.h b/drivers/net/wireless/wl1251/ps.h new file mode 100644 index 0000000..55c3dda --- /dev/null +++ b/drivers/net/wireless/wl1251/ps.h @@ -0,0 +1,35 @@ +/* + * This file is part of wl1251 + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL1251_PS_H__ +#define __WL1251_PS_H__ + +#include "wl1251.h" +#include "acx.h" + +int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode); +void wl1251_ps_elp_sleep(struct wl1251 *wl); +int wl1251_ps_elp_wakeup(struct wl1251 *wl); +void wl1251_elp_work(struct work_struct *work); + + +#endif /* __WL1251_PS_H__ */ diff --git a/drivers/net/wireless/wl1251/reg.h b/drivers/net/wireless/wl1251/reg.h new file mode 100644 index 0000000..a580901 --- /dev/null +++ b/drivers/net/wireless/wl1251/reg.h @@ -0,0 +1,655 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __REG_H__ +#define __REG_H__ + +#include + +#define REGISTERS_BASE 0x00300000 +#define DRPW_BASE 0x00310000 + +#define REGISTERS_DOWN_SIZE 0x00008800 +#define REGISTERS_WORK_SIZE 0x0000b000 + +#define HW_ACCESS_ELP_CTRL_REG_ADDR 0x1FFFC + +/* ELP register commands */ +#define ELPCTRL_WAKE_UP 0x1 +#define ELPCTRL_WAKE_UP_WLAN_READY 0x5 +#define ELPCTRL_SLEEP 0x0 +/* ELP WLAN_READY bit */ +#define ELPCTRL_WLAN_READY 0x2 + +/* Device Configuration registers*/ +#define SOR_CFG (REGISTERS_BASE + 0x0800) +#define ECPU_CTRL (REGISTERS_BASE + 0x0804) +#define HI_CFG (REGISTERS_BASE + 0x0808) + +/* EEPROM registers */ +#define EE_START (REGISTERS_BASE + 0x080C) +#define EE_CTL (REGISTERS_BASE + 0x2000) +#define EE_DATA (REGISTERS_BASE + 0x2004) +#define EE_ADDR (REGISTERS_BASE + 0x2008) + +#define EE_CTL_READ 2 + +#define CHIP_ID_B (REGISTERS_BASE + 0x5674) + +#define CHIP_ID_1251_PG10 (0x7010101) +#define CHIP_ID_1251_PG11 (0x7020101) +#define CHIP_ID_1251_PG12 (0x7030101) + +#define ENABLE (REGISTERS_BASE + 0x5450) + +/* Power Management registers */ +#define ELP_CFG_MODE (REGISTERS_BASE + 0x5804) +#define ELP_CMD (REGISTERS_BASE + 0x5808) +#define PLL_CAL_TIME (REGISTERS_BASE + 0x5810) +#define CLK_REQ_TIME (REGISTERS_BASE + 0x5814) +#define CLK_BUF_TIME (REGISTERS_BASE + 0x5818) + +#define CFG_PLL_SYNC_CNT (REGISTERS_BASE + 0x5820) + +/* Scratch Pad registers*/ +#define SCR_PAD0 (REGISTERS_BASE + 0x5608) +#define SCR_PAD1 (REGISTERS_BASE + 0x560C) +#define SCR_PAD2 (REGISTERS_BASE + 0x5610) +#define SCR_PAD3 (REGISTERS_BASE + 0x5614) +#define SCR_PAD4 (REGISTERS_BASE + 0x5618) +#define SCR_PAD4_SET (REGISTERS_BASE + 0x561C) +#define SCR_PAD4_CLR (REGISTERS_BASE + 0x5620) +#define SCR_PAD5 (REGISTERS_BASE + 0x5624) +#define SCR_PAD5_SET (REGISTERS_BASE + 0x5628) +#define SCR_PAD5_CLR (REGISTERS_BASE + 0x562C) +#define SCR_PAD6 (REGISTERS_BASE + 0x5630) +#define SCR_PAD7 (REGISTERS_BASE + 0x5634) +#define SCR_PAD8 (REGISTERS_BASE + 0x5638) +#define SCR_PAD9 (REGISTERS_BASE + 0x563C) + +/* Spare registers*/ +#define SPARE_A1 (REGISTERS_BASE + 0x0994) +#define SPARE_A2 (REGISTERS_BASE + 0x0998) +#define SPARE_A3 (REGISTERS_BASE + 0x099C) +#define SPARE_A4 (REGISTERS_BASE + 0x09A0) +#define SPARE_A5 (REGISTERS_BASE + 0x09A4) +#define SPARE_A6 (REGISTERS_BASE + 0x09A8) +#define SPARE_A7 (REGISTERS_BASE + 0x09AC) +#define SPARE_A8 (REGISTERS_BASE + 0x09B0) +#define SPARE_B1 (REGISTERS_BASE + 0x5420) +#define SPARE_B2 (REGISTERS_BASE + 0x5424) +#define SPARE_B3 (REGISTERS_BASE + 0x5428) +#define SPARE_B4 (REGISTERS_BASE + 0x542C) +#define SPARE_B5 (REGISTERS_BASE + 0x5430) +#define SPARE_B6 (REGISTERS_BASE + 0x5434) +#define SPARE_B7 (REGISTERS_BASE + 0x5438) +#define SPARE_B8 (REGISTERS_BASE + 0x543C) + +enum wl12xx_acx_int_reg { + ACX_REG_INTERRUPT_TRIG, + ACX_REG_INTERRUPT_TRIG_H, + +/*============================================= + Host Interrupt Mask Register - 32bit (RW) + ------------------------------------------ + Setting a bit in this register masks the + corresponding interrupt to the host. + 0 - RX0 - Rx first dubble buffer Data Interrupt + 1 - TXD - Tx Data Interrupt + 2 - TXXFR - Tx Transfer Interrupt + 3 - RX1 - Rx second dubble buffer Data Interrupt + 4 - RXXFR - Rx Transfer Interrupt + 5 - EVENT_A - Event Mailbox interrupt + 6 - EVENT_B - Event Mailbox interrupt + 7 - WNONHST - Wake On Host Interrupt + 8 - TRACE_A - Debug Trace interrupt + 9 - TRACE_B - Debug Trace interrupt + 10 - CDCMP - Command Complete Interrupt + 11 - + 12 - + 13 - + 14 - ICOMP - Initialization Complete Interrupt + 16 - SG SE - Soft Gemini - Sense enable interrupt + 17 - SG SD - Soft Gemini - Sense disable interrupt + 18 - - + 19 - - + 20 - - + 21- - + Default: 0x0001 +*==============================================*/ + ACX_REG_INTERRUPT_MASK, + +/*============================================= + Host Interrupt Mask Set 16bit, (Write only) + ------------------------------------------ + Setting a bit in this register sets + the corresponding bin in ACX_HINT_MASK register + without effecting the mask + state of other bits (0 = no effect). +==============================================*/ + ACX_REG_HINT_MASK_SET, + +/*============================================= + Host Interrupt Mask Clear 16bit,(Write only) + ------------------------------------------ + Setting a bit in this register clears + the corresponding bin in ACX_HINT_MASK register + without effecting the mask + state of other bits (0 = no effect). +=============================================*/ + ACX_REG_HINT_MASK_CLR, + +/*============================================= + Host Interrupt Status Nondestructive Read + 16bit,(Read only) + ------------------------------------------ + The host can read this register to determine + which interrupts are active. + Reading this register doesn't + effect its content. +=============================================*/ + ACX_REG_INTERRUPT_NO_CLEAR, + +/*============================================= + Host Interrupt Status Clear on Read Register + 16bit,(Read only) + ------------------------------------------ + The host can read this register to determine + which interrupts are active. + Reading this register clears it, + thus making all interrupts inactive. +==============================================*/ + ACX_REG_INTERRUPT_CLEAR, + +/*============================================= + Host Interrupt Acknowledge Register + 16bit,(Write only) + ------------------------------------------ + The host can set individual bits in this + register to clear (acknowledge) the corresp. + interrupt status bits in the HINT_STS_CLR and + HINT_STS_ND registers, thus making the + assotiated interrupt inactive. (0-no effect) +==============================================*/ + ACX_REG_INTERRUPT_ACK, + +/*=============================================== + Host Software Reset - 32bit RW + ------------------------------------------ + [31:1] Reserved + 0 SOFT_RESET Soft Reset - When this bit is set, + it holds the Wlan hardware in a soft reset state. + This reset disables all MAC and baseband processor + clocks except the CardBus/PCI interface clock. + It also initializes all MAC state machines except + the host interface. It does not reload the + contents of the EEPROM. When this bit is cleared + (not self-clearing), the Wlan hardware + exits the software reset state. +===============================================*/ + ACX_REG_SLV_SOFT_RESET, + +/*=============================================== + EEPROM Burst Read Start - 32bit RW + ------------------------------------------ + [31:1] Reserved + 0 ACX_EE_START - EEPROM Burst Read Start 0 + Setting this bit starts a burst read from + the external EEPROM. + If this bit is set (after reset) before an EEPROM read/write, + the burst read starts at EEPROM address 0. + Otherwise, it starts at the address + following the address of the previous access. + TheWlan hardware hardware clears this bit automatically. + + Default: 0x00000000 +*================================================*/ + ACX_REG_EE_START, + +/* Embedded ARM CPU Control */ + +/*=============================================== + Halt eCPU - 32bit RW + ------------------------------------------ + 0 HALT_ECPU Halt Embedded CPU - This bit is the + compliment of bit 1 (MDATA2) in the SOR_CFG register. + During a hardware reset, this bit holds + the inverse of MDATA2. + When downloading firmware from the host, + set this bit (pull down MDATA2). + The host clears this bit after downloading the firmware into + zero-wait-state SSRAM. + When loading firmware from Flash, clear this bit (pull up MDATA2) + so that the eCPU can run the bootloader code in Flash + HALT_ECPU eCPU State + -------------------- + 1 halt eCPU + 0 enable eCPU + ===============================================*/ + ACX_REG_ECPU_CONTROL, + + ACX_REG_TABLE_LEN +}; + +#define ACX_SLV_SOFT_RESET_BIT BIT(0) +#define ACX_REG_EEPROM_START_BIT BIT(0) + +/* Command/Information Mailbox Pointers */ + +/*=============================================== + Command Mailbox Pointer - 32bit RW + ------------------------------------------ + This register holds the start address of + the command mailbox located in the Wlan hardware memory. + The host must read this pointer after a reset to + find the location of the command mailbox. + The Wlan hardware initializes the command mailbox + pointer with the default address of the command mailbox. + The command mailbox pointer is not valid until after + the host receives the Init Complete interrupt from + the Wlan hardware. + ===============================================*/ +#define REG_COMMAND_MAILBOX_PTR (SCR_PAD0) + +/*=============================================== + Information Mailbox Pointer - 32bit RW + ------------------------------------------ + This register holds the start address of + the information mailbox located in the Wlan hardware memory. + The host must read this pointer after a reset to find + the location of the information mailbox. + The Wlan hardware initializes the information mailbox pointer + with the default address of the information mailbox. + The information mailbox pointer is not valid + until after the host receives the Init Complete interrupt from + the Wlan hardware. + ===============================================*/ +#define REG_EVENT_MAILBOX_PTR (SCR_PAD1) + + +/* Misc */ + +#define REG_ENABLE_TX_RX (ENABLE) +/* + * Rx configuration (filter) information element + * --------------------------------------------- + */ +#define REG_RX_CONFIG (RX_CFG) +#define REG_RX_FILTER (RX_FILTER_CFG) + + +#define RX_CFG_ENABLE_PHY_HEADER_PLCP 0x0002 + +/* promiscuous - receives all valid frames */ +#define RX_CFG_PROMISCUOUS 0x0008 + +/* receives frames from any BSSID */ +#define RX_CFG_BSSID 0x0020 + +/* receives frames destined to any MAC address */ +#define RX_CFG_MAC 0x0010 + +#define RX_CFG_ENABLE_ONLY_MY_DEST_MAC 0x0010 +#define RX_CFG_ENABLE_ANY_DEST_MAC 0x0000 +#define RX_CFG_ENABLE_ONLY_MY_BSSID 0x0020 +#define RX_CFG_ENABLE_ANY_BSSID 0x0000 + +/* discards all broadcast frames */ +#define RX_CFG_DISABLE_BCAST 0x0200 + +#define RX_CFG_ENABLE_ONLY_MY_SSID 0x0400 +#define RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR 0x0800 +#define RX_CFG_COPY_RX_STATUS 0x2000 +#define RX_CFG_TSF 0x10000 + +#define RX_CONFIG_OPTION_ANY_DST_MY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \ + RX_CFG_ENABLE_ONLY_MY_BSSID) + +#define RX_CONFIG_OPTION_MY_DST_ANY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\ + | RX_CFG_ENABLE_ANY_BSSID) + +#define RX_CONFIG_OPTION_ANY_DST_ANY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \ + RX_CFG_ENABLE_ANY_BSSID) + +#define RX_CONFIG_OPTION_MY_DST_MY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\ + | RX_CFG_ENABLE_ONLY_MY_BSSID) + +#define RX_CONFIG_OPTION_FOR_SCAN (RX_CFG_ENABLE_PHY_HEADER_PLCP \ + | RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR \ + | RX_CFG_COPY_RX_STATUS | RX_CFG_TSF) + +#define RX_CONFIG_OPTION_FOR_MEASUREMENT (RX_CFG_ENABLE_ANY_DEST_MAC) + +#define RX_CONFIG_OPTION_FOR_JOIN (RX_CFG_ENABLE_ONLY_MY_BSSID | \ + RX_CFG_ENABLE_ONLY_MY_DEST_MAC) + +#define RX_CONFIG_OPTION_FOR_IBSS_JOIN (RX_CFG_ENABLE_ONLY_MY_SSID | \ + RX_CFG_ENABLE_ONLY_MY_DEST_MAC) + +#define RX_FILTER_OPTION_DEF (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\ + | CFG_RX_CTL_EN | CFG_RX_BCN_EN\ + | CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN) + +#define RX_FILTER_OPTION_FILTER_ALL 0 + +#define RX_FILTER_OPTION_DEF_PRSP_BCN (CFG_RX_PRSP_EN | CFG_RX_MGMT_EN\ + | CFG_RX_RCTS_ACK | CFG_RX_BCN_EN) + +#define RX_FILTER_OPTION_JOIN (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\ + | CFG_RX_BCN_EN | CFG_RX_AUTH_EN\ + | CFG_RX_ASSOC_EN | CFG_RX_RCTS_ACK\ + | CFG_RX_PRSP_EN) + + +/*=============================================== + EEPROM Read/Write Request 32bit RW + ------------------------------------------ + 1 EE_READ - EEPROM Read Request 1 - Setting this bit + loads a single byte of data into the EE_DATA + register from the EEPROM location specified in + the EE_ADDR register. + The Wlan hardware hardware clears this bit automatically. + EE_DATA is valid when this bit is cleared. + + 0 EE_WRITE - EEPROM Write Request - Setting this bit + writes a single byte of data from the EE_DATA register into the + EEPROM location specified in the EE_ADDR register. + The Wlan hardware hardware clears this bit automatically. +*===============================================*/ +#define EE_CTL (REGISTERS_BASE + 0x2000) +#define ACX_EE_CTL_REG EE_CTL +#define EE_WRITE 0x00000001ul +#define EE_READ 0x00000002ul + +/*=============================================== + EEPROM Address - 32bit RW + ------------------------------------------ + This register specifies the address + within the EEPROM from/to which to read/write data. + ===============================================*/ +#define EE_ADDR (REGISTERS_BASE + 0x2008) +#define ACX_EE_ADDR_REG EE_ADDR + +/*=============================================== + EEPROM Data - 32bit RW + ------------------------------------------ + This register either holds the read 8 bits of + data from the EEPROM or the write data + to be written to the EEPROM. + ===============================================*/ +#define EE_DATA (REGISTERS_BASE + 0x2004) +#define ACX_EE_DATA_REG EE_DATA + +#define EEPROM_ACCESS_TO 10000 /* timeout counter */ +#define START_EEPROM_MGR 0x00000001 + +/*=============================================== + EEPROM Base Address - 32bit RW + ------------------------------------------ + This register holds the upper nine bits + [23:15] of the 24-bit Wlan hardware memory + address for burst reads from EEPROM accesses. + The EEPROM provides the lower 15 bits of this address. + The MSB of the address from the EEPROM is ignored. + ===============================================*/ +#define ACX_EE_CFG EE_CFG + +/*=============================================== + GPIO Output Values -32bit, RW + ------------------------------------------ + [31:16] Reserved + [15: 0] Specify the output values (at the output driver inputs) for + GPIO[15:0], respectively. + ===============================================*/ +#define ACX_GPIO_OUT_REG GPIO_OUT +#define ACX_MAX_GPIO_LINES 15 + +/*=============================================== + Contention window -32bit, RW + ------------------------------------------ + [31:26] Reserved + [25:16] Max (0x3ff) + [15:07] Reserved + [06:00] Current contention window value - default is 0x1F + ===============================================*/ +#define ACX_CONT_WIND_CFG_REG CONT_WIND_CFG +#define ACX_CONT_WIND_MIN_MASK 0x0000007f +#define ACX_CONT_WIND_MAX 0x03ff0000 + +/*=============================================== + HI_CFG Interface Configuration Register Values + ------------------------------------------ + ===============================================*/ +#define HI_CFG_UART_ENABLE 0x00000004 +#define HI_CFG_RST232_ENABLE 0x00000008 +#define HI_CFG_CLOCK_REQ_SELECT 0x00000010 +#define HI_CFG_HOST_INT_ENABLE 0x00000020 +#define HI_CFG_VLYNQ_OUTPUT_ENABLE 0x00000040 +#define HI_CFG_HOST_INT_ACTIVE_LOW 0x00000080 +#define HI_CFG_UART_TX_OUT_GPIO_15 0x00000100 +#define HI_CFG_UART_TX_OUT_GPIO_14 0x00000200 +#define HI_CFG_UART_TX_OUT_GPIO_7 0x00000400 + +/* + * NOTE: USE_ACTIVE_HIGH compilation flag should be defined in makefile + * for platforms using active high interrupt level + */ +#ifdef USE_ACTIVE_HIGH +#define HI_CFG_DEF_VAL \ + (HI_CFG_UART_ENABLE | \ + HI_CFG_RST232_ENABLE | \ + HI_CFG_CLOCK_REQ_SELECT | \ + HI_CFG_HOST_INT_ENABLE) +#else +#define HI_CFG_DEF_VAL \ + (HI_CFG_UART_ENABLE | \ + HI_CFG_RST232_ENABLE | \ + HI_CFG_CLOCK_REQ_SELECT | \ + HI_CFG_HOST_INT_ENABLE) + +#endif + +#define REF_FREQ_19_2 0 +#define REF_FREQ_26_0 1 +#define REF_FREQ_38_4 2 +#define REF_FREQ_40_0 3 +#define REF_FREQ_33_6 4 +#define REF_FREQ_NUM 5 + +#define LUT_PARAM_INTEGER_DIVIDER 0 +#define LUT_PARAM_FRACTIONAL_DIVIDER 1 +#define LUT_PARAM_ATTN_BB 2 +#define LUT_PARAM_ALPHA_BB 3 +#define LUT_PARAM_STOP_TIME_BB 4 +#define LUT_PARAM_BB_PLL_LOOP_FILTER 5 +#define LUT_PARAM_NUM 6 + +#define ACX_EEPROMLESS_IND_REG (SCR_PAD4) +#define USE_EEPROM 0 +#define SOFT_RESET_MAX_TIME 1000000 +#define SOFT_RESET_STALL_TIME 1000 +#define NVS_DATA_BUNDARY_ALIGNMENT 4 + + +/* Firmware image load chunk size */ +#define CHUNK_SIZE 512 + +/* Firmware image header size */ +#define FW_HDR_SIZE 8 + +#define ECPU_CONTROL_HALT 0x00000101 + + +/****************************************************************************** + + CHANNELS, BAND & REG DOMAINS definitions + +******************************************************************************/ + + +enum { + RADIO_BAND_2_4GHZ = 0, /* 2.4 Ghz band */ + RADIO_BAND_5GHZ = 1, /* 5 Ghz band */ + RADIO_BAND_JAPAN_4_9_GHZ = 2, + DEFAULT_BAND = RADIO_BAND_2_4GHZ, + INVALID_BAND = 0xFE, + MAX_RADIO_BANDS = 0xFF +}; + +enum { + NO_RATE = 0, + RATE_1MBPS = 0x0A, + RATE_2MBPS = 0x14, + RATE_5_5MBPS = 0x37, + RATE_6MBPS = 0x0B, + RATE_9MBPS = 0x0F, + RATE_11MBPS = 0x6E, + RATE_12MBPS = 0x0A, + RATE_18MBPS = 0x0E, + RATE_22MBPS = 0xDC, + RATE_24MBPS = 0x09, + RATE_36MBPS = 0x0D, + RATE_48MBPS = 0x08, + RATE_54MBPS = 0x0C +}; + +enum { + RATE_INDEX_1MBPS = 0, + RATE_INDEX_2MBPS = 1, + RATE_INDEX_5_5MBPS = 2, + RATE_INDEX_6MBPS = 3, + RATE_INDEX_9MBPS = 4, + RATE_INDEX_11MBPS = 5, + RATE_INDEX_12MBPS = 6, + RATE_INDEX_18MBPS = 7, + RATE_INDEX_22MBPS = 8, + RATE_INDEX_24MBPS = 9, + RATE_INDEX_36MBPS = 10, + RATE_INDEX_48MBPS = 11, + RATE_INDEX_54MBPS = 12, + RATE_INDEX_MAX = RATE_INDEX_54MBPS, + MAX_RATE_INDEX, + INVALID_RATE_INDEX = MAX_RATE_INDEX, + RATE_INDEX_ENUM_MAX_SIZE = 0x7FFFFFFF +}; + +enum { + RATE_MASK_1MBPS = 0x1, + RATE_MASK_2MBPS = 0x2, + RATE_MASK_5_5MBPS = 0x4, + RATE_MASK_11MBPS = 0x20, +}; + +#define SHORT_PREAMBLE_BIT BIT(0) /* CCK or Barker depending on the rate */ +#define OFDM_RATE_BIT BIT(6) +#define PBCC_RATE_BIT BIT(7) + +enum { + CCK_LONG = 0, + CCK_SHORT = SHORT_PREAMBLE_BIT, + PBCC_LONG = PBCC_RATE_BIT, + PBCC_SHORT = PBCC_RATE_BIT | SHORT_PREAMBLE_BIT, + OFDM = OFDM_RATE_BIT +}; + +/****************************************************************************** + +Transmit-Descriptor RATE-SET field definitions... + +Define a new "Rate-Set" for TX path that incorporates the +Rate & Modulation info into a single 16-bit field. + +TxdRateSet_t: +b15 - Indicates Preamble type (1=SHORT, 0=LONG). + Notes: + Must be LONG (0) for 1Mbps rate. + Does not apply (set to 0) for RevG-OFDM rates. +b14 - Indicates PBCC encoding (1=PBCC, 0=not). + Notes: + Does not apply (set to 0) for rates 1 and 2 Mbps. + Does not apply (set to 0) for RevG-OFDM rates. +b13 - Unused (set to 0). +b12-b0 - Supported Rate indicator bits as defined below. + +******************************************************************************/ + + +/************************************************************************* + + Interrupt Trigger Register (Host -> WiLink) + +**************************************************************************/ + +/* Hardware to Embedded CPU Interrupts - first 32-bit register set */ + +/* + * Host Command Interrupt. Setting this bit masks + * the interrupt that the host issues to inform + * the FW that it has sent a command + * to the Wlan hardware Command Mailbox. + */ +#define INTR_TRIG_CMD BIT(0) + +/* + * Host Event Acknowlegde Interrupt. The host + * sets this bit to acknowledge that it received + * the unsolicited information from the event + * mailbox. + */ +#define INTR_TRIG_EVENT_ACK BIT(1) + +/* + * The host sets this bit to inform the Wlan + * FW that a TX packet is in the XFER + * Buffer #0. + */ +#define INTR_TRIG_TX_PROC0 BIT(2) + +/* + * The host sets this bit to inform the FW + * that it read a packet from RX XFER + * Buffer #0. + */ +#define INTR_TRIG_RX_PROC0 BIT(3) + +#define INTR_TRIG_DEBUG_ACK BIT(4) + +#define INTR_TRIG_STATE_CHANGED BIT(5) + + +/* Hardware to Embedded CPU Interrupts - second 32-bit register set */ + +/* + * The host sets this bit to inform the FW + * that it read a packet from RX XFER + * Buffer #1. + */ +#define INTR_TRIG_RX_PROC1 BIT(17) + +/* + * The host sets this bit to inform the Wlan + * hardware that a TX packet is in the XFER + * Buffer #1. + */ +#define INTR_TRIG_TX_PROC1 BIT(18) + +#endif diff --git a/drivers/net/wireless/wl1251/rx.c b/drivers/net/wireless/wl1251/rx.c new file mode 100644 index 0000000..efa5360 --- /dev/null +++ b/drivers/net/wireless/wl1251/rx.c @@ -0,0 +1,190 @@ +/* + * This file is part of wl1251 + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include + +#include "wl1251.h" +#include "reg.h" +#include "io.h" +#include "rx.h" +#include "cmd.h" +#include "acx.h" + +static void wl1251_rx_header(struct wl1251 *wl, + struct wl1251_rx_descriptor *desc) +{ + u32 rx_packet_ring_addr; + + rx_packet_ring_addr = wl->data_path->rx_packet_ring_addr; + if (wl->rx_current_buffer) + rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size; + + wl1251_mem_read(wl, rx_packet_ring_addr, desc, sizeof(*desc)); +} + +static void wl1251_rx_status(struct wl1251 *wl, + struct wl1251_rx_descriptor *desc, + struct ieee80211_rx_status *status, + u8 beacon) +{ + u64 mactime; + int ret; + + memset(status, 0, sizeof(struct ieee80211_rx_status)); + + status->band = IEEE80211_BAND_2GHZ; + status->mactime = desc->timestamp; + + /* + * The rx status timestamp is a 32 bits value while the TSF is a + * 64 bits one. + * For IBSS merging, TSF is mandatory, so we have to get it + * somehow, so we ask for ACX_TSF_INFO. + * That could be moved to the get_tsf() hook, but unfortunately, + * this one must be atomic, while our SPI routines can sleep. + */ + if ((wl->bss_type == BSS_TYPE_IBSS) && beacon) { + ret = wl1251_acx_tsf_info(wl, &mactime); + if (ret == 0) + status->mactime = mactime; + } + + status->signal = desc->rssi; + + /* + * FIXME: guessing that snr needs to be divided by two, otherwise + * the values don't make any sense + */ + wl->noise = desc->rssi - desc->snr / 2; + + status->freq = ieee80211_channel_to_frequency(desc->channel); + + status->flag |= RX_FLAG_TSFT; + + if (desc->flags & RX_DESC_ENCRYPTION_MASK) { + status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; + + if (likely(!(desc->flags & RX_DESC_DECRYPT_FAIL))) + status->flag |= RX_FLAG_DECRYPTED; + + if (unlikely(desc->flags & RX_DESC_MIC_FAIL)) + status->flag |= RX_FLAG_MMIC_ERROR; + } + + if (unlikely(!(desc->flags & RX_DESC_VALID_FCS))) + status->flag |= RX_FLAG_FAILED_FCS_CRC; + + + /* FIXME: set status->rate_idx */ +} + +static void wl1251_rx_body(struct wl1251 *wl, + struct wl1251_rx_descriptor *desc) +{ + struct sk_buff *skb; + struct ieee80211_rx_status status; + u8 *rx_buffer, beacon = 0; + u16 length, *fc; + u32 curr_id, last_id_inc, rx_packet_ring_addr; + + length = WL1251_RX_ALIGN(desc->length - PLCP_HEADER_LENGTH); + curr_id = (desc->flags & RX_DESC_SEQNUM_MASK) >> RX_DESC_PACKETID_SHIFT; + last_id_inc = (wl->rx_last_id + 1) % (RX_MAX_PACKET_ID + 1); + + if (last_id_inc != curr_id) { + wl1251_warning("curr ID:%d, last ID inc:%d", + curr_id, last_id_inc); + wl->rx_last_id = curr_id; + } else { + wl->rx_last_id = last_id_inc; + } + + rx_packet_ring_addr = wl->data_path->rx_packet_ring_addr + + sizeof(struct wl1251_rx_descriptor) + 20; + if (wl->rx_current_buffer) + rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size; + + skb = __dev_alloc_skb(length, GFP_KERNEL); + if (!skb) { + wl1251_error("Couldn't allocate RX frame"); + return; + } + + rx_buffer = skb_put(skb, length); + wl1251_mem_read(wl, rx_packet_ring_addr, rx_buffer, length); + + /* The actual lenght doesn't include the target's alignment */ + skb->len = desc->length - PLCP_HEADER_LENGTH; + + fc = (u16 *)skb->data; + + if ((*fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) + beacon = 1; + + wl1251_rx_status(wl, desc, &status, beacon); + + wl1251_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len, + beacon ? "beacon" : ""); + + memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); + ieee80211_rx_ni(wl->hw, skb); +} + +static void wl1251_rx_ack(struct wl1251 *wl) +{ + u32 data, addr; + + if (wl->rx_current_buffer) { + addr = ACX_REG_INTERRUPT_TRIG_H; + data = INTR_TRIG_RX_PROC1; + } else { + addr = ACX_REG_INTERRUPT_TRIG; + data = INTR_TRIG_RX_PROC0; + } + + wl1251_reg_write32(wl, addr, data); + + /* Toggle buffer ring */ + wl->rx_current_buffer = !wl->rx_current_buffer; +} + + +void wl1251_rx(struct wl1251 *wl) +{ + struct wl1251_rx_descriptor *rx_desc; + + if (wl->state != WL1251_STATE_ON) + return; + + rx_desc = wl->rx_descriptor; + + /* We first read the frame's header */ + wl1251_rx_header(wl, rx_desc); + + /* Now we can read the body */ + wl1251_rx_body(wl, rx_desc); + + /* Finally, we need to ACK the RX */ + wl1251_rx_ack(wl); +} diff --git a/drivers/net/wireless/wl1251/rx.h b/drivers/net/wireless/wl1251/rx.h new file mode 100644 index 0000000..4448f63 --- /dev/null +++ b/drivers/net/wireless/wl1251/rx.h @@ -0,0 +1,122 @@ +/* + * This file is part of wl1251 + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL1251_RX_H__ +#define __WL1251_RX_H__ + +#include + +#include "wl1251.h" + +/* + * RX PATH + * + * The Rx path uses a double buffer and an rx_contro structure, each located + * at a fixed address in the device memory. The host keeps track of which + * buffer is available and alternates between them on a per packet basis. + * The size of each of the two buffers is large enough to hold the longest + * 802.3 packet. + * The RX path goes like that: + * 1) The target generates an interrupt each time a new packet is received. + * There are 2 RX interrupts, one for each buffer. + * 2) The host reads the received packet from one of the double buffers. + * 3) The host triggers a target interrupt. + * 4) The target prepares the next RX packet. + */ + +#define WL1251_RX_MAX_RSSI -30 +#define WL1251_RX_MIN_RSSI -95 + +#define WL1251_RX_ALIGN_TO 4 +#define WL1251_RX_ALIGN(len) (((len) + WL1251_RX_ALIGN_TO - 1) & \ + ~(WL1251_RX_ALIGN_TO - 1)) + +#define SHORT_PREAMBLE_BIT BIT(0) +#define OFDM_RATE_BIT BIT(6) +#define PBCC_RATE_BIT BIT(7) + +#define PLCP_HEADER_LENGTH 8 +#define RX_DESC_PACKETID_SHIFT 11 +#define RX_MAX_PACKET_ID 3 + +#define RX_DESC_VALID_FCS 0x0001 +#define RX_DESC_MATCH_RXADDR1 0x0002 +#define RX_DESC_MCAST 0x0004 +#define RX_DESC_STAINTIM 0x0008 +#define RX_DESC_VIRTUAL_BM 0x0010 +#define RX_DESC_BCAST 0x0020 +#define RX_DESC_MATCH_SSID 0x0040 +#define RX_DESC_MATCH_BSSID 0x0080 +#define RX_DESC_ENCRYPTION_MASK 0x0300 +#define RX_DESC_MEASURMENT 0x0400 +#define RX_DESC_SEQNUM_MASK 0x1800 +#define RX_DESC_MIC_FAIL 0x2000 +#define RX_DESC_DECRYPT_FAIL 0x4000 + +struct wl1251_rx_descriptor { + u32 timestamp; /* In microseconds */ + u16 length; /* Paylod length, including headers */ + u16 flags; + + /* + * 0 - 802.11 + * 1 - 802.3 + * 2 - IP + * 3 - Raw Codec + */ + u8 type; + + /* + * Received Rate: + * 0x0A - 1MBPS + * 0x14 - 2MBPS + * 0x37 - 5_5MBPS + * 0x0B - 6MBPS + * 0x0F - 9MBPS + * 0x6E - 11MBPS + * 0x0A - 12MBPS + * 0x0E - 18MBPS + * 0xDC - 22MBPS + * 0x09 - 24MBPS + * 0x0D - 36MBPS + * 0x08 - 48MBPS + * 0x0C - 54MBPS + */ + u8 rate; + + u8 mod_pre; /* Modulation and preamble */ + u8 channel; + + /* + * 0 - 2.4 Ghz + * 1 - 5 Ghz + */ + u8 band; + + s8 rssi; /* in dB */ + u8 rcpi; /* in dB */ + u8 snr; /* in dB */ +} __packed; + +void wl1251_rx(struct wl1251 *wl); + +#endif diff --git a/drivers/net/wireless/wl1251/sdio.c b/drivers/net/wireless/wl1251/sdio.c new file mode 100644 index 0000000..74ba9ce --- /dev/null +++ b/drivers/net/wireless/wl1251/sdio.c @@ -0,0 +1,342 @@ +/* + * wl12xx SDIO routines + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + * Copyright (C) 2005 Texas Instruments Incorporated + * Copyright (C) 2008 Google Inc + * Copyright (C) 2009 Bob Copeland (me@bobcopeland.com) + */ +#include +#include +#include +#include +#include +#include +#include + +#include "wl1251.h" + +#ifndef SDIO_VENDOR_ID_TI +#define SDIO_VENDOR_ID_TI 0x104c +#endif + +#ifndef SDIO_DEVICE_ID_TI_WL1251 +#define SDIO_DEVICE_ID_TI_WL1251 0x9066 +#endif + +struct wl1251_sdio { + struct sdio_func *func; + u32 elp_val; +}; + +static struct wl12xx_platform_data *wl12xx_board_data; + +static struct sdio_func *wl_to_func(struct wl1251 *wl) +{ + struct wl1251_sdio *wl_sdio = wl->if_priv; + return wl_sdio->func; +} + +static void wl1251_sdio_interrupt(struct sdio_func *func) +{ + struct wl1251 *wl = sdio_get_drvdata(func); + + wl1251_debug(DEBUG_IRQ, "IRQ"); + + /* FIXME should be synchronous for sdio */ + ieee80211_queue_work(wl->hw, &wl->irq_work); +} + +static const struct sdio_device_id wl1251_devices[] = { + { SDIO_DEVICE(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1251) }, + {} +}; +MODULE_DEVICE_TABLE(sdio, wl1251_devices); + + +static void wl1251_sdio_read(struct wl1251 *wl, int addr, + void *buf, size_t len) +{ + int ret; + struct sdio_func *func = wl_to_func(wl); + + sdio_claim_host(func); + ret = sdio_memcpy_fromio(func, buf, addr, len); + if (ret) + wl1251_error("sdio read failed (%d)", ret); + sdio_release_host(func); +} + +static void wl1251_sdio_write(struct wl1251 *wl, int addr, + void *buf, size_t len) +{ + int ret; + struct sdio_func *func = wl_to_func(wl); + + sdio_claim_host(func); + ret = sdio_memcpy_toio(func, addr, buf, len); + if (ret) + wl1251_error("sdio write failed (%d)", ret); + sdio_release_host(func); +} + +static void wl1251_sdio_read_elp(struct wl1251 *wl, int addr, u32 *val) +{ + int ret = 0; + struct wl1251_sdio *wl_sdio = wl->if_priv; + struct sdio_func *func = wl_sdio->func; + + /* + * The hardware only supports RAW (read after write) access for + * reading, regular sdio_readb won't work here (it interprets + * the unused bits of CMD52 as write data even if we send read + * request). + */ + sdio_claim_host(func); + *val = sdio_writeb_readb(func, wl_sdio->elp_val, addr, &ret); + sdio_release_host(func); + + if (ret) + wl1251_error("sdio_readb failed (%d)", ret); +} + +static void wl1251_sdio_write_elp(struct wl1251 *wl, int addr, u32 val) +{ + int ret = 0; + struct wl1251_sdio *wl_sdio = wl->if_priv; + struct sdio_func *func = wl_sdio->func; + + sdio_claim_host(func); + sdio_writeb(func, val, addr, &ret); + sdio_release_host(func); + + if (ret) + wl1251_error("sdio_writeb failed (%d)", ret); + else + wl_sdio->elp_val = val; +} + +static void wl1251_sdio_reset(struct wl1251 *wl) +{ +} + +static void wl1251_sdio_enable_irq(struct wl1251 *wl) +{ + struct sdio_func *func = wl_to_func(wl); + + sdio_claim_host(func); + sdio_claim_irq(func, wl1251_sdio_interrupt); + sdio_release_host(func); +} + +static void wl1251_sdio_disable_irq(struct wl1251 *wl) +{ + struct sdio_func *func = wl_to_func(wl); + + sdio_claim_host(func); + sdio_release_irq(func); + sdio_release_host(func); +} + +/* Interrupts when using dedicated WLAN_IRQ pin */ +static irqreturn_t wl1251_line_irq(int irq, void *cookie) +{ + struct wl1251 *wl = cookie; + + ieee80211_queue_work(wl->hw, &wl->irq_work); + + return IRQ_HANDLED; +} + +static void wl1251_enable_line_irq(struct wl1251 *wl) +{ + return enable_irq(wl->irq); +} + +static void wl1251_disable_line_irq(struct wl1251 *wl) +{ + return disable_irq(wl->irq); +} + +static void wl1251_sdio_set_power(bool enable) +{ +} + +static struct wl1251_if_operations wl1251_sdio_ops = { + .read = wl1251_sdio_read, + .write = wl1251_sdio_write, + .write_elp = wl1251_sdio_write_elp, + .read_elp = wl1251_sdio_read_elp, + .reset = wl1251_sdio_reset, +}; + +static int wl1251_platform_probe(struct platform_device *pdev) +{ + if (pdev->id != -1) { + wl1251_error("can only handle single device"); + return -ENODEV; + } + + wl12xx_board_data = pdev->dev.platform_data; + return 0; +} + +/* + * Dummy platform_driver for passing platform_data to this driver, + * until we have a way to pass this through SDIO subsystem or + * some other way. + */ +static struct platform_driver wl1251_platform_driver = { + .driver = { + .name = "wl1251_data", + .owner = THIS_MODULE, + }, + .probe = wl1251_platform_probe, +}; + +static int wl1251_sdio_probe(struct sdio_func *func, + const struct sdio_device_id *id) +{ + int ret; + struct wl1251 *wl; + struct ieee80211_hw *hw; + struct wl1251_sdio *wl_sdio; + + hw = wl1251_alloc_hw(); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + wl = hw->priv; + + wl_sdio = kzalloc(sizeof(*wl_sdio), GFP_KERNEL); + if (wl_sdio == NULL) { + ret = -ENOMEM; + goto out_free_hw; + } + + sdio_claim_host(func); + ret = sdio_enable_func(func); + if (ret) + goto release; + + sdio_set_block_size(func, 512); + sdio_release_host(func); + + SET_IEEE80211_DEV(hw, &func->dev); + wl_sdio->func = func; + wl->if_priv = wl_sdio; + wl->if_ops = &wl1251_sdio_ops; + wl->set_power = wl1251_sdio_set_power; + + if (wl12xx_board_data != NULL) { + wl->set_power = wl12xx_board_data->set_power; + wl->irq = wl12xx_board_data->irq; + wl->use_eeprom = wl12xx_board_data->use_eeprom; + } + + if (wl->irq) { + ret = request_irq(wl->irq, wl1251_line_irq, 0, "wl1251", wl); + if (ret < 0) { + wl1251_error("request_irq() failed: %d", ret); + goto disable; + } + + set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); + disable_irq(wl->irq); + + wl1251_sdio_ops.enable_irq = wl1251_enable_line_irq; + wl1251_sdio_ops.disable_irq = wl1251_disable_line_irq; + + wl1251_info("using dedicated interrupt line"); + } else { + wl1251_sdio_ops.enable_irq = wl1251_sdio_enable_irq; + wl1251_sdio_ops.disable_irq = wl1251_sdio_disable_irq; + + wl1251_info("using SDIO interrupt"); + } + + ret = wl1251_init_ieee80211(wl); + if (ret) + goto out_free_irq; + + sdio_set_drvdata(func, wl); + return ret; + +out_free_irq: + if (wl->irq) + free_irq(wl->irq, wl); +disable: + sdio_claim_host(func); + sdio_disable_func(func); +release: + sdio_release_host(func); + kfree(wl_sdio); +out_free_hw: + wl1251_free_hw(wl); + return ret; +} + +static void __devexit wl1251_sdio_remove(struct sdio_func *func) +{ + struct wl1251 *wl = sdio_get_drvdata(func); + struct wl1251_sdio *wl_sdio = wl->if_priv; + + if (wl->irq) + free_irq(wl->irq, wl); + kfree(wl_sdio); + wl1251_free_hw(wl); + + sdio_claim_host(func); + sdio_release_irq(func); + sdio_disable_func(func); + sdio_release_host(func); +} + +static struct sdio_driver wl1251_sdio_driver = { + .name = "wl1251_sdio", + .id_table = wl1251_devices, + .probe = wl1251_sdio_probe, + .remove = __devexit_p(wl1251_sdio_remove), +}; + +static int __init wl1251_sdio_init(void) +{ + int err; + + err = platform_driver_register(&wl1251_platform_driver); + if (err) { + wl1251_error("failed to register platform driver: %d", err); + return err; + } + + err = sdio_register_driver(&wl1251_sdio_driver); + if (err) + wl1251_error("failed to register sdio driver: %d", err); + return err; +} + +static void __exit wl1251_sdio_exit(void) +{ + sdio_unregister_driver(&wl1251_sdio_driver); + platform_driver_unregister(&wl1251_platform_driver); + wl1251_notice("unloaded"); +} + +module_init(wl1251_sdio_init); +module_exit(wl1251_sdio_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kalle Valo "); diff --git a/drivers/net/wireless/wl1251/spi.c b/drivers/net/wireless/wl1251/spi.c new file mode 100644 index 0000000..88fa8e6 --- /dev/null +++ b/drivers/net/wireless/wl1251/spi.c @@ -0,0 +1,346 @@ +/* + * This file is part of wl1251 + * + * Copyright (C) 2008 Nokia Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#include + +#include "wl1251.h" +#include "reg.h" +#include "spi.h" + +static irqreturn_t wl1251_irq(int irq, void *cookie) +{ + struct wl1251 *wl; + + wl1251_debug(DEBUG_IRQ, "IRQ"); + + wl = cookie; + + ieee80211_queue_work(wl->hw, &wl->irq_work); + + return IRQ_HANDLED; +} + +static struct spi_device *wl_to_spi(struct wl1251 *wl) +{ + return wl->if_priv; +} + +static void wl1251_spi_reset(struct wl1251 *wl) +{ + u8 *cmd; + struct spi_transfer t; + struct spi_message m; + + cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); + if (!cmd) { + wl1251_error("could not allocate cmd for spi reset"); + return; + } + + memset(&t, 0, sizeof(t)); + spi_message_init(&m); + + memset(cmd, 0xff, WSPI_INIT_CMD_LEN); + + t.tx_buf = cmd; + t.len = WSPI_INIT_CMD_LEN; + spi_message_add_tail(&t, &m); + + spi_sync(wl_to_spi(wl), &m); + + wl1251_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); +} + +static void wl1251_spi_wake(struct wl1251 *wl) +{ + u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd; + struct spi_transfer t; + struct spi_message m; + + cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); + if (!cmd) { + wl1251_error("could not allocate cmd for spi init"); + return; + } + + memset(crc, 0, sizeof(crc)); + memset(&t, 0, sizeof(t)); + spi_message_init(&m); + + /* + * Set WSPI_INIT_COMMAND + * the data is being send from the MSB to LSB + */ + cmd[2] = 0xff; + cmd[3] = 0xff; + cmd[1] = WSPI_INIT_CMD_START | WSPI_INIT_CMD_TX; + cmd[0] = 0; + cmd[7] = 0; + cmd[6] |= HW_ACCESS_WSPI_INIT_CMD_MASK << 3; + cmd[6] |= HW_ACCESS_WSPI_FIXED_BUSY_LEN & WSPI_INIT_CMD_FIXEDBUSY_LEN; + + if (HW_ACCESS_WSPI_FIXED_BUSY_LEN == 0) + cmd[5] |= WSPI_INIT_CMD_DIS_FIXEDBUSY; + else + cmd[5] |= WSPI_INIT_CMD_EN_FIXEDBUSY; + + cmd[5] |= WSPI_INIT_CMD_IOD | WSPI_INIT_CMD_IP | WSPI_INIT_CMD_CS + | WSPI_INIT_CMD_WSPI | WSPI_INIT_CMD_WS; + + crc[0] = cmd[1]; + crc[1] = cmd[0]; + crc[2] = cmd[7]; + crc[3] = cmd[6]; + crc[4] = cmd[5]; + + cmd[4] |= crc7(0, crc, WSPI_INIT_CMD_CRC_LEN) << 1; + cmd[4] |= WSPI_INIT_CMD_END; + + t.tx_buf = cmd; + t.len = WSPI_INIT_CMD_LEN; + spi_message_add_tail(&t, &m); + + spi_sync(wl_to_spi(wl), &m); + + wl1251_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN); +} + +static void wl1251_spi_reset_wake(struct wl1251 *wl) +{ + wl1251_spi_reset(wl); + wl1251_spi_wake(wl); +} + +static void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, + size_t len) +{ + struct spi_transfer t[3]; + struct spi_message m; + u8 *busy_buf; + u32 *cmd; + + cmd = &wl->buffer_cmd; + busy_buf = wl->buffer_busyword; + + *cmd = 0; + *cmd |= WSPI_CMD_READ; + *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; + *cmd |= addr & WSPI_CMD_BYTE_ADDR; + + spi_message_init(&m); + memset(t, 0, sizeof(t)); + + t[0].tx_buf = cmd; + t[0].len = 4; + spi_message_add_tail(&t[0], &m); + + /* Busy and non busy words read */ + t[1].rx_buf = busy_buf; + t[1].len = WL1251_BUSY_WORD_LEN; + spi_message_add_tail(&t[1], &m); + + t[2].rx_buf = buf; + t[2].len = len; + spi_message_add_tail(&t[2], &m); + + spi_sync(wl_to_spi(wl), &m); + + /* FIXME: check busy words */ + + wl1251_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd)); + wl1251_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); +} + +static void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, + size_t len) +{ + struct spi_transfer t[2]; + struct spi_message m; + u32 *cmd; + + cmd = &wl->buffer_cmd; + + *cmd = 0; + *cmd |= WSPI_CMD_WRITE; + *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; + *cmd |= addr & WSPI_CMD_BYTE_ADDR; + + spi_message_init(&m); + memset(t, 0, sizeof(t)); + + t[0].tx_buf = cmd; + t[0].len = sizeof(*cmd); + spi_message_add_tail(&t[0], &m); + + t[1].tx_buf = buf; + t[1].len = len; + spi_message_add_tail(&t[1], &m); + + spi_sync(wl_to_spi(wl), &m); + + wl1251_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); + wl1251_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); +} + +static void wl1251_spi_enable_irq(struct wl1251 *wl) +{ + return enable_irq(wl->irq); +} + +static void wl1251_spi_disable_irq(struct wl1251 *wl) +{ + return disable_irq(wl->irq); +} + +static const struct wl1251_if_operations wl1251_spi_ops = { + .read = wl1251_spi_read, + .write = wl1251_spi_write, + .reset = wl1251_spi_reset_wake, + .enable_irq = wl1251_spi_enable_irq, + .disable_irq = wl1251_spi_disable_irq, +}; + +static int __devinit wl1251_spi_probe(struct spi_device *spi) +{ + struct wl12xx_platform_data *pdata; + struct ieee80211_hw *hw; + struct wl1251 *wl; + int ret; + + pdata = spi->dev.platform_data; + if (!pdata) { + wl1251_error("no platform data"); + return -ENODEV; + } + + hw = wl1251_alloc_hw(); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + wl = hw->priv; + + SET_IEEE80211_DEV(hw, &spi->dev); + dev_set_drvdata(&spi->dev, wl); + wl->if_priv = spi; + wl->if_ops = &wl1251_spi_ops; + + /* This is the only SPI value that we need to set here, the rest + * comes from the board-peripherals file */ + spi->bits_per_word = 32; + + ret = spi_setup(spi); + if (ret < 0) { + wl1251_error("spi_setup failed"); + goto out_free; + } + + wl->set_power = pdata->set_power; + if (!wl->set_power) { + wl1251_error("set power function missing in platform data"); + return -ENODEV; + } + + wl->irq = spi->irq; + if (wl->irq < 0) { + wl1251_error("irq missing in platform data"); + return -ENODEV; + } + + wl->use_eeprom = pdata->use_eeprom; + + ret = request_irq(wl->irq, wl1251_irq, 0, DRIVER_NAME, wl); + if (ret < 0) { + wl1251_error("request_irq() failed: %d", ret); + goto out_free; + } + + set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); + + disable_irq(wl->irq); + + ret = wl1251_init_ieee80211(wl); + if (ret) + goto out_irq; + + return 0; + + out_irq: + free_irq(wl->irq, wl); + + out_free: + ieee80211_free_hw(hw); + + return ret; +} + +static int __devexit wl1251_spi_remove(struct spi_device *spi) +{ + struct wl1251 *wl = dev_get_drvdata(&spi->dev); + + free_irq(wl->irq, wl); + wl1251_free_hw(wl); + + return 0; +} + +static struct spi_driver wl1251_spi_driver = { + .driver = { + .name = DRIVER_NAME, + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + + .probe = wl1251_spi_probe, + .remove = __devexit_p(wl1251_spi_remove), +}; + +static int __init wl1251_spi_init(void) +{ + int ret; + + ret = spi_register_driver(&wl1251_spi_driver); + if (ret < 0) { + wl1251_error("failed to register spi driver: %d", ret); + goto out; + } + +out: + return ret; +} + +static void __exit wl1251_spi_exit(void) +{ + spi_unregister_driver(&wl1251_spi_driver); + + wl1251_notice("unloaded"); +} + +module_init(wl1251_spi_init); +module_exit(wl1251_spi_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kalle Valo "); +MODULE_ALIAS("spi:wl1251"); diff --git a/drivers/net/wireless/wl1251/spi.h b/drivers/net/wireless/wl1251/spi.h new file mode 100644 index 0000000..16d5069 --- /dev/null +++ b/drivers/net/wireless/wl1251/spi.h @@ -0,0 +1,59 @@ +/* + * This file is part of wl1251 + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL1251_SPI_H__ +#define __WL1251_SPI_H__ + +#include "cmd.h" +#include "acx.h" +#include "reg.h" + +#define WSPI_CMD_READ 0x40000000 +#define WSPI_CMD_WRITE 0x00000000 +#define WSPI_CMD_FIXED 0x20000000 +#define WSPI_CMD_BYTE_LENGTH 0x1FFE0000 +#define WSPI_CMD_BYTE_LENGTH_OFFSET 17 +#define WSPI_CMD_BYTE_ADDR 0x0001FFFF + +#define WSPI_INIT_CMD_CRC_LEN 5 + +#define WSPI_INIT_CMD_START 0x00 +#define WSPI_INIT_CMD_TX 0x40 +/* the extra bypass bit is sampled by the TNET as '1' */ +#define WSPI_INIT_CMD_BYPASS_BIT 0x80 +#define WSPI_INIT_CMD_FIXEDBUSY_LEN 0x07 +#define WSPI_INIT_CMD_EN_FIXEDBUSY 0x80 +#define WSPI_INIT_CMD_DIS_FIXEDBUSY 0x00 +#define WSPI_INIT_CMD_IOD 0x40 +#define WSPI_INIT_CMD_IP 0x20 +#define WSPI_INIT_CMD_CS 0x10 +#define WSPI_INIT_CMD_WS 0x08 +#define WSPI_INIT_CMD_WSPI 0x01 +#define WSPI_INIT_CMD_END 0x01 + +#define WSPI_INIT_CMD_LEN 8 + +#define HW_ACCESS_WSPI_FIXED_BUSY_LEN \ + ((WL1251_BUSY_WORD_LEN - 4) / sizeof(u32)) +#define HW_ACCESS_WSPI_INIT_CMD_MASK 0 + +#endif /* __WL1251_SPI_H__ */ diff --git a/drivers/net/wireless/wl1251/tx.c b/drivers/net/wireless/wl1251/tx.c new file mode 100644 index 0000000..554b4f9 --- /dev/null +++ b/drivers/net/wireless/wl1251/tx.c @@ -0,0 +1,570 @@ +/* + * This file is part of wl1251 + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include + +#include "wl1251.h" +#include "reg.h" +#include "tx.h" +#include "ps.h" +#include "io.h" + +static bool wl1251_tx_double_buffer_busy(struct wl1251 *wl, u32 data_out_count) +{ + int used, data_in_count; + + data_in_count = wl->data_in_count; + + if (data_in_count < data_out_count) + /* data_in_count has wrapped */ + data_in_count += TX_STATUS_DATA_OUT_COUNT_MASK + 1; + + used = data_in_count - data_out_count; + + WARN_ON(used < 0); + WARN_ON(used > DP_TX_PACKET_RING_CHUNK_NUM); + + if (used >= DP_TX_PACKET_RING_CHUNK_NUM) + return true; + else + return false; +} + +static int wl1251_tx_path_status(struct wl1251 *wl) +{ + u32 status, addr, data_out_count; + bool busy; + + addr = wl->data_path->tx_control_addr; + status = wl1251_mem_read32(wl, addr); + data_out_count = status & TX_STATUS_DATA_OUT_COUNT_MASK; + busy = wl1251_tx_double_buffer_busy(wl, data_out_count); + + if (busy) + return -EBUSY; + + return 0; +} + +static int wl1251_tx_id(struct wl1251 *wl, struct sk_buff *skb) +{ + int i; + + for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) + if (wl->tx_frames[i] == NULL) { + wl->tx_frames[i] = skb; + return i; + } + + return -EBUSY; +} + +static void wl1251_tx_control(struct tx_double_buffer_desc *tx_hdr, + struct ieee80211_tx_info *control, u16 fc) +{ + *(u16 *)&tx_hdr->control = 0; + + tx_hdr->control.rate_policy = 0; + + /* 802.11 packets */ + tx_hdr->control.packet_type = 0; + + if (control->flags & IEEE80211_TX_CTL_NO_ACK) + tx_hdr->control.ack_policy = 1; + + tx_hdr->control.tx_complete = 1; + + if ((fc & IEEE80211_FTYPE_DATA) && + ((fc & IEEE80211_STYPE_QOS_DATA) || + (fc & IEEE80211_STYPE_QOS_NULLFUNC))) + tx_hdr->control.qos = 1; +} + +/* RSN + MIC = 8 + 8 = 16 bytes (worst case - AES). */ +#define MAX_MSDU_SECURITY_LENGTH 16 +#define MAX_MPDU_SECURITY_LENGTH 16 +#define WLAN_QOS_HDR_LEN 26 +#define MAX_MPDU_HEADER_AND_SECURITY (MAX_MPDU_SECURITY_LENGTH + \ + WLAN_QOS_HDR_LEN) +#define HW_BLOCK_SIZE 252 +static void wl1251_tx_frag_block_num(struct tx_double_buffer_desc *tx_hdr) +{ + u16 payload_len, frag_threshold, mem_blocks; + u16 num_mpdus, mem_blocks_per_frag; + + frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD; + tx_hdr->frag_threshold = cpu_to_le16(frag_threshold); + + payload_len = le16_to_cpu(tx_hdr->length) + MAX_MSDU_SECURITY_LENGTH; + + if (payload_len > frag_threshold) { + mem_blocks_per_frag = + ((frag_threshold + MAX_MPDU_HEADER_AND_SECURITY) / + HW_BLOCK_SIZE) + 1; + num_mpdus = payload_len / frag_threshold; + mem_blocks = num_mpdus * mem_blocks_per_frag; + payload_len -= num_mpdus * frag_threshold; + num_mpdus++; + + } else { + mem_blocks_per_frag = 0; + mem_blocks = 0; + num_mpdus = 1; + } + + mem_blocks += (payload_len / HW_BLOCK_SIZE) + 1; + + if (num_mpdus > 1) + mem_blocks += min(num_mpdus, mem_blocks_per_frag); + + tx_hdr->num_mem_blocks = mem_blocks; +} + +static int wl1251_tx_fill_hdr(struct wl1251 *wl, struct sk_buff *skb, + struct ieee80211_tx_info *control) +{ + struct tx_double_buffer_desc *tx_hdr; + struct ieee80211_rate *rate; + int id; + u16 fc; + + if (!skb) + return -EINVAL; + + id = wl1251_tx_id(wl, skb); + if (id < 0) + return id; + + fc = *(u16 *)skb->data; + tx_hdr = (struct tx_double_buffer_desc *) skb_push(skb, + sizeof(*tx_hdr)); + + tx_hdr->length = cpu_to_le16(skb->len - sizeof(*tx_hdr)); + rate = ieee80211_get_tx_rate(wl->hw, control); + tx_hdr->rate = cpu_to_le16(rate->hw_value); + tx_hdr->expiry_time = cpu_to_le32(1 << 16); + tx_hdr->id = id; + + tx_hdr->xmit_queue = wl1251_tx_get_queue(skb_get_queue_mapping(skb)); + + wl1251_tx_control(tx_hdr, control, fc); + wl1251_tx_frag_block_num(tx_hdr); + + return 0; +} + +/* We copy the packet to the target */ +static int wl1251_tx_send_packet(struct wl1251 *wl, struct sk_buff *skb, + struct ieee80211_tx_info *control) +{ + struct tx_double_buffer_desc *tx_hdr; + int len; + u32 addr; + + if (!skb) + return -EINVAL; + + tx_hdr = (struct tx_double_buffer_desc *) skb->data; + + if (control->control.hw_key && + control->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) { + int hdrlen; + __le16 fc; + u16 length; + u8 *pos; + + fc = *(__le16 *)(skb->data + sizeof(*tx_hdr)); + length = le16_to_cpu(tx_hdr->length) + WL1251_TKIP_IV_SPACE; + tx_hdr->length = cpu_to_le16(length); + + hdrlen = ieee80211_hdrlen(fc); + + pos = skb_push(skb, WL1251_TKIP_IV_SPACE); + memmove(pos, pos + WL1251_TKIP_IV_SPACE, + sizeof(*tx_hdr) + hdrlen); + } + + /* Revisit. This is a workaround for getting non-aligned packets. + This happens at least with EAPOL packets from the user space. + Our DMA requires packets to be aligned on a 4-byte boundary. + */ + if (unlikely((long)skb->data & 0x03)) { + int offset = (4 - (long)skb->data) & 0x03; + wl1251_debug(DEBUG_TX, "skb offset %d", offset); + + /* check whether the current skb can be used */ + if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) { + unsigned char *src = skb->data; + + /* align the buffer on a 4-byte boundary */ + skb_reserve(skb, offset); + memmove(skb->data, src, skb->len); + tx_hdr = (struct tx_double_buffer_desc *) skb->data; + } else { + wl1251_info("No handler, fixme!"); + return -EINVAL; + } + } + + /* Our skb->data at this point includes the HW header */ + len = WL1251_TX_ALIGN(skb->len); + + if (wl->data_in_count & 0x1) + addr = wl->data_path->tx_packet_ring_addr + + wl->data_path->tx_packet_ring_chunk_size; + else + addr = wl->data_path->tx_packet_ring_addr; + + wl1251_mem_write(wl, addr, skb->data, len); + + wl1251_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x " + "queue %d", tx_hdr->id, skb, tx_hdr->length, + tx_hdr->rate, tx_hdr->xmit_queue); + + return 0; +} + +static void wl1251_tx_trigger(struct wl1251 *wl) +{ + u32 data, addr; + + if (wl->data_in_count & 0x1) { + addr = ACX_REG_INTERRUPT_TRIG_H; + data = INTR_TRIG_TX_PROC1; + } else { + addr = ACX_REG_INTERRUPT_TRIG; + data = INTR_TRIG_TX_PROC0; + } + + wl1251_reg_write32(wl, addr, data); + + /* Bumping data in */ + wl->data_in_count = (wl->data_in_count + 1) & + TX_STATUS_DATA_OUT_COUNT_MASK; +} + +/* caller must hold wl->mutex */ +static int wl1251_tx_frame(struct wl1251 *wl, struct sk_buff *skb) +{ + struct ieee80211_tx_info *info; + int ret = 0; + u8 idx; + + info = IEEE80211_SKB_CB(skb); + + if (info->control.hw_key) { + idx = info->control.hw_key->hw_key_idx; + if (unlikely(wl->default_key != idx)) { + ret = wl1251_acx_default_key(wl, idx); + if (ret < 0) + return ret; + } + } + + ret = wl1251_tx_path_status(wl); + if (ret < 0) + return ret; + + ret = wl1251_tx_fill_hdr(wl, skb, info); + if (ret < 0) + return ret; + + ret = wl1251_tx_send_packet(wl, skb, info); + if (ret < 0) + return ret; + + wl1251_tx_trigger(wl); + + return ret; +} + +void wl1251_tx_work(struct work_struct *work) +{ + struct wl1251 *wl = container_of(work, struct wl1251, tx_work); + struct sk_buff *skb; + bool woken_up = false; + int ret; + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state == WL1251_STATE_OFF)) + goto out; + + while ((skb = skb_dequeue(&wl->tx_queue))) { + if (!woken_up) { + ret = wl1251_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + woken_up = true; + } + + ret = wl1251_tx_frame(wl, skb); + if (ret == -EBUSY) { + skb_queue_head(&wl->tx_queue, skb); + goto out; + } else if (ret < 0) { + dev_kfree_skb(skb); + goto out; + } + } + +out: + if (woken_up) + wl1251_ps_elp_sleep(wl); + + mutex_unlock(&wl->mutex); +} + +static const char *wl1251_tx_parse_status(u8 status) +{ + /* 8 bit status field, one character per bit plus null */ + static char buf[9]; + int i = 0; + + memset(buf, 0, sizeof(buf)); + + if (status & TX_DMA_ERROR) + buf[i++] = 'm'; + if (status & TX_DISABLED) + buf[i++] = 'd'; + if (status & TX_RETRY_EXCEEDED) + buf[i++] = 'r'; + if (status & TX_TIMEOUT) + buf[i++] = 't'; + if (status & TX_KEY_NOT_FOUND) + buf[i++] = 'k'; + if (status & TX_ENCRYPT_FAIL) + buf[i++] = 'e'; + if (status & TX_UNAVAILABLE_PRIORITY) + buf[i++] = 'p'; + + /* bit 0 is unused apparently */ + + return buf; +} + +static void wl1251_tx_packet_cb(struct wl1251 *wl, + struct tx_result *result) +{ + struct ieee80211_tx_info *info; + struct sk_buff *skb; + int hdrlen, ret; + u8 *frame; + + skb = wl->tx_frames[result->id]; + if (skb == NULL) { + wl1251_error("SKB for packet %d is NULL", result->id); + return; + } + + info = IEEE80211_SKB_CB(skb); + + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && + (result->status == TX_SUCCESS)) + info->flags |= IEEE80211_TX_STAT_ACK; + + info->status.rates[0].count = result->ack_failures + 1; + wl->stats.retry_count += result->ack_failures; + + /* + * We have to remove our private TX header before pushing + * the skb back to mac80211. + */ + frame = skb_pull(skb, sizeof(struct tx_double_buffer_desc)); + if (info->control.hw_key && + info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) { + hdrlen = ieee80211_get_hdrlen_from_skb(skb); + memmove(frame + WL1251_TKIP_IV_SPACE, frame, hdrlen); + skb_pull(skb, WL1251_TKIP_IV_SPACE); + } + + wl1251_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x" + " status 0x%x (%s)", + result->id, skb, result->ack_failures, result->rate, + result->status, wl1251_tx_parse_status(result->status)); + + + ieee80211_tx_status(wl->hw, skb); + + wl->tx_frames[result->id] = NULL; + + if (wl->tx_queue_stopped) { + wl1251_debug(DEBUG_TX, "cb: queue was stopped"); + + skb = skb_dequeue(&wl->tx_queue); + + /* The skb can be NULL because tx_work might have been + scheduled before the queue was stopped making the + queue empty */ + + if (skb) { + ret = wl1251_tx_frame(wl, skb); + if (ret == -EBUSY) { + /* firmware buffer is still full */ + wl1251_debug(DEBUG_TX, "cb: fw buffer " + "still full"); + skb_queue_head(&wl->tx_queue, skb); + return; + } else if (ret < 0) { + dev_kfree_skb(skb); + return; + } + } + + wl1251_debug(DEBUG_TX, "cb: waking queues"); + ieee80211_wake_queues(wl->hw); + wl->tx_queue_stopped = false; + } +} + +/* Called upon reception of a TX complete interrupt */ +void wl1251_tx_complete(struct wl1251 *wl) +{ + int i, result_index, num_complete = 0; + struct tx_result result[FW_TX_CMPLT_BLOCK_SIZE], *result_ptr; + unsigned long flags; + + if (unlikely(wl->state != WL1251_STATE_ON)) + return; + + /* First we read the result */ + wl1251_mem_read(wl, wl->data_path->tx_complete_addr, + result, sizeof(result)); + + result_index = wl->next_tx_complete; + + for (i = 0; i < ARRAY_SIZE(result); i++) { + result_ptr = &result[result_index]; + + if (result_ptr->done_1 == 1 && + result_ptr->done_2 == 1) { + wl1251_tx_packet_cb(wl, result_ptr); + + result_ptr->done_1 = 0; + result_ptr->done_2 = 0; + + result_index = (result_index + 1) & + (FW_TX_CMPLT_BLOCK_SIZE - 1); + num_complete++; + } else { + break; + } + } + + if (wl->tx_queue_stopped + && + skb_queue_len(&wl->tx_queue) <= WL1251_TX_QUEUE_LOW_WATERMARK){ + + /* firmware buffer has space, restart queues */ + wl1251_debug(DEBUG_TX, "tx_complete: waking queues"); + spin_lock_irqsave(&wl->wl_lock, flags); + ieee80211_wake_queues(wl->hw); + wl->tx_queue_stopped = false; + spin_unlock_irqrestore(&wl->wl_lock, flags); + ieee80211_queue_work(wl->hw, &wl->tx_work); + + } + + /* Every completed frame needs to be acknowledged */ + if (num_complete) { + /* + * If we've wrapped, we have to clear + * the results in 2 steps. + */ + if (result_index > wl->next_tx_complete) { + /* Only 1 write is needed */ + wl1251_mem_write(wl, + wl->data_path->tx_complete_addr + + (wl->next_tx_complete * + sizeof(struct tx_result)), + &result[wl->next_tx_complete], + num_complete * + sizeof(struct tx_result)); + + + } else if (result_index < wl->next_tx_complete) { + /* 2 writes are needed */ + wl1251_mem_write(wl, + wl->data_path->tx_complete_addr + + (wl->next_tx_complete * + sizeof(struct tx_result)), + &result[wl->next_tx_complete], + (FW_TX_CMPLT_BLOCK_SIZE - + wl->next_tx_complete) * + sizeof(struct tx_result)); + + wl1251_mem_write(wl, + wl->data_path->tx_complete_addr, + result, + (num_complete - + FW_TX_CMPLT_BLOCK_SIZE + + wl->next_tx_complete) * + sizeof(struct tx_result)); + + } else { + /* We have to write the whole array */ + wl1251_mem_write(wl, + wl->data_path->tx_complete_addr, + result, + FW_TX_CMPLT_BLOCK_SIZE * + sizeof(struct tx_result)); + } + + } + + wl->next_tx_complete = result_index; +} + +/* caller must hold wl->mutex */ +void wl1251_tx_flush(struct wl1251 *wl) +{ + int i; + struct sk_buff *skb; + struct ieee80211_tx_info *info; + + /* TX failure */ +/* control->flags = 0; FIXME */ + + while ((skb = skb_dequeue(&wl->tx_queue))) { + info = IEEE80211_SKB_CB(skb); + + wl1251_debug(DEBUG_TX, "flushing skb 0x%p", skb); + + if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) + continue; + + ieee80211_tx_status(wl->hw, skb); + } + + for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) + if (wl->tx_frames[i] != NULL) { + skb = wl->tx_frames[i]; + info = IEEE80211_SKB_CB(skb); + + if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) + continue; + + ieee80211_tx_status(wl->hw, skb); + wl->tx_frames[i] = NULL; + } +} diff --git a/drivers/net/wireless/wl1251/tx.h b/drivers/net/wireless/wl1251/tx.h new file mode 100644 index 0000000..81338d3 --- /dev/null +++ b/drivers/net/wireless/wl1251/tx.h @@ -0,0 +1,231 @@ +/* + * This file is part of wl1251 + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL1251_TX_H__ +#define __WL1251_TX_H__ + +#include +#include "acx.h" + +/* + * + * TX PATH + * + * The Tx path uses a double buffer and a tx_control structure, each located + * at a fixed address in the device's memory. On startup, the host retrieves + * the pointers to these addresses. A double buffer allows for continuous data + * flow towards the device. The host keeps track of which buffer is available + * and alternates between these two buffers on a per packet basis. + * + * The size of each of the two buffers is large enough to hold the longest + * 802.3 packet - maximum size Ethernet packet + header + descriptor. + * TX complete indication will be received a-synchronously in a TX done cyclic + * buffer which is composed of 16 tx_result descriptors structures and is used + * in a cyclic manner. + * + * The TX (HOST) procedure is as follows: + * 1. Read the Tx path status, that will give the data_out_count. + * 2. goto 1, if not possible. + * i.e. if data_in_count - data_out_count >= HwBuffer size (2 for double + * buffer). + * 3. Copy the packet (preceded by double_buffer_desc), if possible. + * i.e. if data_in_count - data_out_count < HwBuffer size (2 for double + * buffer). + * 4. increment data_in_count. + * 5. Inform the firmware by generating a firmware internal interrupt. + * 6. FW will increment data_out_count after it reads the buffer. + * + * The TX Complete procedure: + * 1. To get a TX complete indication the host enables the tx_complete flag in + * the TX descriptor Structure. + * 2. For each packet with a Tx Complete field set, the firmware adds the + * transmit results to the cyclic buffer (txDoneRing) and sets both done_1 + * and done_2 to 1 to indicate driver ownership. + * 3. The firmware sends a Tx Complete interrupt to the host to trigger the + * host to process the new data. Note: interrupt will be send per packet if + * TX complete indication was requested in tx_control or per crossing + * aggregation threshold. + * 4. After receiving the Tx Complete interrupt, the host reads the + * TxDescriptorDone information in a cyclic manner and clears both done_1 + * and done_2 fields. + * + */ + +#define TX_COMPLETE_REQUIRED_BIT 0x80 +#define TX_STATUS_DATA_OUT_COUNT_MASK 0xf + +#define WL1251_TX_ALIGN_TO 4 +#define WL1251_TX_ALIGN(len) (((len) + WL1251_TX_ALIGN_TO - 1) & \ + ~(WL1251_TX_ALIGN_TO - 1)) +#define WL1251_TKIP_IV_SPACE 4 + +struct tx_control { + /* Rate Policy (class) index */ + unsigned rate_policy:3; + + /* When set, no ack policy is expected */ + unsigned ack_policy:1; + + /* + * Packet type: + * 0 -> 802.11 + * 1 -> 802.3 + * 2 -> IP + * 3 -> raw codec + */ + unsigned packet_type:2; + + /* If set, this is a QoS-Null or QoS-Data frame */ + unsigned qos:1; + + /* + * If set, the target triggers the tx complete INT + * upon frame sending completion. + */ + unsigned tx_complete:1; + + /* 2 bytes padding before packet header */ + unsigned xfer_pad:1; + + unsigned reserved:7; +} __packed; + + +struct tx_double_buffer_desc { + /* Length of payload, including headers. */ + __le16 length; + + /* + * A bit mask that specifies the initial rate to be used + * Possible values are: + * 0x0001 - 1Mbits + * 0x0002 - 2Mbits + * 0x0004 - 5.5Mbits + * 0x0008 - 6Mbits + * 0x0010 - 9Mbits + * 0x0020 - 11Mbits + * 0x0040 - 12Mbits + * 0x0080 - 18Mbits + * 0x0100 - 22Mbits + * 0x0200 - 24Mbits + * 0x0400 - 36Mbits + * 0x0800 - 48Mbits + * 0x1000 - 54Mbits + */ + __le16 rate; + + /* Time in us that a packet can spend in the target */ + __le32 expiry_time; + + /* index of the TX queue used for this packet */ + u8 xmit_queue; + + /* Used to identify a packet */ + u8 id; + + struct tx_control control; + + /* + * The FW should cut the packet into fragments + * of this size. + */ + __le16 frag_threshold; + + /* Numbers of HW queue blocks to be allocated */ + u8 num_mem_blocks; + + u8 reserved; +} __packed; + +enum { + TX_SUCCESS = 0, + TX_DMA_ERROR = BIT(7), + TX_DISABLED = BIT(6), + TX_RETRY_EXCEEDED = BIT(5), + TX_TIMEOUT = BIT(4), + TX_KEY_NOT_FOUND = BIT(3), + TX_ENCRYPT_FAIL = BIT(2), + TX_UNAVAILABLE_PRIORITY = BIT(1), +}; + +struct tx_result { + /* + * Ownership synchronization between the host and + * the firmware. If done_1 and done_2 are cleared, + * owned by the FW (no info ready). + */ + u8 done_1; + + /* same as double_buffer_desc->id */ + u8 id; + + /* + * Total air access duration consumed by this + * packet, including all retries and overheads. + */ + u16 medium_usage; + + /* Total media delay (from 1st EDCA AIFS counter until TX Complete). */ + u32 medium_delay; + + /* Time between host xfer and tx complete */ + u32 fw_hnadling_time; + + /* The LS-byte of the last TKIP sequence number. */ + u8 lsb_seq_num; + + /* Retry count */ + u8 ack_failures; + + /* At which rate we got a ACK */ + u16 rate; + + u16 reserved; + + /* TX_* */ + u8 status; + + /* See done_1 */ + u8 done_2; +} __packed; + +static inline int wl1251_tx_get_queue(int queue) +{ + switch (queue) { + case 0: + return QOS_AC_VO; + case 1: + return QOS_AC_VI; + case 2: + return QOS_AC_BE; + case 3: + return QOS_AC_BK; + default: + return QOS_AC_BE; + } +} + +void wl1251_tx_work(struct work_struct *work); +void wl1251_tx_complete(struct wl1251 *wl); +void wl1251_tx_flush(struct wl1251 *wl); + +#endif diff --git a/drivers/net/wireless/wl1251/wl1251.h b/drivers/net/wireless/wl1251/wl1251.h new file mode 100644 index 0000000..e113d4c --- /dev/null +++ b/drivers/net/wireless/wl1251/wl1251.h @@ -0,0 +1,433 @@ +/* + * This file is part of wl1251 + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008-2009 Nokia Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL1251_H__ +#define __WL1251_H__ + +#include +#include +#include +#include + +#define DRIVER_NAME "wl1251" +#define DRIVER_PREFIX DRIVER_NAME ": " + +enum { + DEBUG_NONE = 0, + DEBUG_IRQ = BIT(0), + DEBUG_SPI = BIT(1), + DEBUG_BOOT = BIT(2), + DEBUG_MAILBOX = BIT(3), + DEBUG_NETLINK = BIT(4), + DEBUG_EVENT = BIT(5), + DEBUG_TX = BIT(6), + DEBUG_RX = BIT(7), + DEBUG_SCAN = BIT(8), + DEBUG_CRYPT = BIT(9), + DEBUG_PSM = BIT(10), + DEBUG_MAC80211 = BIT(11), + DEBUG_CMD = BIT(12), + DEBUG_ACX = BIT(13), + DEBUG_ALL = ~0, +}; + +#define DEBUG_LEVEL (DEBUG_NONE) + +#define DEBUG_DUMP_LIMIT 1024 + +#define wl1251_error(fmt, arg...) \ + printk(KERN_ERR DRIVER_PREFIX "ERROR " fmt "\n", ##arg) + +#define wl1251_warning(fmt, arg...) \ + printk(KERN_WARNING DRIVER_PREFIX "WARNING " fmt "\n", ##arg) + +#define wl1251_notice(fmt, arg...) \ + printk(KERN_INFO DRIVER_PREFIX fmt "\n", ##arg) + +#define wl1251_info(fmt, arg...) \ + printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg) + +#define wl1251_debug(level, fmt, arg...) \ + do { \ + if (level & DEBUG_LEVEL) \ + printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg); \ + } while (0) + +#define wl1251_dump(level, prefix, buf, len) \ + do { \ + if (level & DEBUG_LEVEL) \ + print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ + DUMP_PREFIX_OFFSET, 16, 1, \ + buf, \ + min_t(size_t, len, DEBUG_DUMP_LIMIT), \ + 0); \ + } while (0) + +#define wl1251_dump_ascii(level, prefix, buf, len) \ + do { \ + if (level & DEBUG_LEVEL) \ + print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ + DUMP_PREFIX_OFFSET, 16, 1, \ + buf, \ + min_t(size_t, len, DEBUG_DUMP_LIMIT), \ + true); \ + } while (0) + +#define WL1251_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \ + CFG_BSSID_FILTER_EN) + +#define WL1251_DEFAULT_RX_FILTER (CFG_RX_PRSP_EN | \ + CFG_RX_MGMT_EN | \ + CFG_RX_DATA_EN | \ + CFG_RX_CTL_EN | \ + CFG_RX_BCN_EN | \ + CFG_RX_AUTH_EN | \ + CFG_RX_ASSOC_EN) + +#define WL1251_BUSY_WORD_LEN 8 + +struct boot_attr { + u32 radio_type; + u8 mac_clock; + u8 arm_clock; + int firmware_debug; + u32 minor; + u32 major; + u32 bugfix; +}; + +enum wl1251_state { + WL1251_STATE_OFF, + WL1251_STATE_ON, + WL1251_STATE_PLT, +}; + +enum wl1251_partition_type { + PART_DOWN, + PART_WORK, + PART_DRPW, + + PART_TABLE_LEN +}; + +struct wl1251_partition { + u32 size; + u32 start; +}; + +struct wl1251_partition_set { + struct wl1251_partition mem; + struct wl1251_partition reg; +}; + +struct wl1251; + +struct wl1251_stats { + struct acx_statistics *fw_stats; + unsigned long fw_stats_update; + + unsigned int retry_count; + unsigned int excessive_retries; +}; + +struct wl1251_debugfs { + struct dentry *rootdir; + struct dentry *fw_statistics; + + struct dentry *tx_internal_desc_overflow; + + struct dentry *rx_out_of_mem; + struct dentry *rx_hdr_overflow; + struct dentry *rx_hw_stuck; + struct dentry *rx_dropped; + struct dentry *rx_fcs_err; + struct dentry *rx_xfr_hint_trig; + struct dentry *rx_path_reset; + struct dentry *rx_reset_counter; + + struct dentry *dma_rx_requested; + struct dentry *dma_rx_errors; + struct dentry *dma_tx_requested; + struct dentry *dma_tx_errors; + + struct dentry *isr_cmd_cmplt; + struct dentry *isr_fiqs; + struct dentry *isr_rx_headers; + struct dentry *isr_rx_mem_overflow; + struct dentry *isr_rx_rdys; + struct dentry *isr_irqs; + struct dentry *isr_tx_procs; + struct dentry *isr_decrypt_done; + struct dentry *isr_dma0_done; + struct dentry *isr_dma1_done; + struct dentry *isr_tx_exch_complete; + struct dentry *isr_commands; + struct dentry *isr_rx_procs; + struct dentry *isr_hw_pm_mode_changes; + struct dentry *isr_host_acknowledges; + struct dentry *isr_pci_pm; + struct dentry *isr_wakeups; + struct dentry *isr_low_rssi; + + struct dentry *wep_addr_key_count; + struct dentry *wep_default_key_count; + /* skipping wep.reserved */ + struct dentry *wep_key_not_found; + struct dentry *wep_decrypt_fail; + struct dentry *wep_packets; + struct dentry *wep_interrupt; + + struct dentry *pwr_ps_enter; + struct dentry *pwr_elp_enter; + struct dentry *pwr_missing_bcns; + struct dentry *pwr_wake_on_host; + struct dentry *pwr_wake_on_timer_exp; + struct dentry *pwr_tx_with_ps; + struct dentry *pwr_tx_without_ps; + struct dentry *pwr_rcvd_beacons; + struct dentry *pwr_power_save_off; + struct dentry *pwr_enable_ps; + struct dentry *pwr_disable_ps; + struct dentry *pwr_fix_tsf_ps; + /* skipping cont_miss_bcns_spread for now */ + struct dentry *pwr_rcvd_awake_beacons; + + struct dentry *mic_rx_pkts; + struct dentry *mic_calc_failure; + + struct dentry *aes_encrypt_fail; + struct dentry *aes_decrypt_fail; + struct dentry *aes_encrypt_packets; + struct dentry *aes_decrypt_packets; + struct dentry *aes_encrypt_interrupt; + struct dentry *aes_decrypt_interrupt; + + struct dentry *event_heart_beat; + struct dentry *event_calibration; + struct dentry *event_rx_mismatch; + struct dentry *event_rx_mem_empty; + struct dentry *event_rx_pool; + struct dentry *event_oom_late; + struct dentry *event_phy_transmit_error; + struct dentry *event_tx_stuck; + + struct dentry *ps_pspoll_timeouts; + struct dentry *ps_upsd_timeouts; + struct dentry *ps_upsd_max_sptime; + struct dentry *ps_upsd_max_apturn; + struct dentry *ps_pspoll_max_apturn; + struct dentry *ps_pspoll_utilization; + struct dentry *ps_upsd_utilization; + + struct dentry *rxpipe_rx_prep_beacon_drop; + struct dentry *rxpipe_descr_host_int_trig_rx_data; + struct dentry *rxpipe_beacon_buffer_thres_host_int_trig_rx_data; + struct dentry *rxpipe_missed_beacon_host_int_trig_rx_data; + struct dentry *rxpipe_tx_xfr_host_int_trig_rx_data; + + struct dentry *tx_queue_len; + struct dentry *tx_queue_status; + + struct dentry *retry_count; + struct dentry *excessive_retries; +}; + +struct wl1251_if_operations { + void (*read)(struct wl1251 *wl, int addr, void *buf, size_t len); + void (*write)(struct wl1251 *wl, int addr, void *buf, size_t len); + void (*read_elp)(struct wl1251 *wl, int addr, u32 *val); + void (*write_elp)(struct wl1251 *wl, int addr, u32 val); + void (*reset)(struct wl1251 *wl); + void (*enable_irq)(struct wl1251 *wl); + void (*disable_irq)(struct wl1251 *wl); +}; + +struct wl1251 { + struct ieee80211_hw *hw; + bool mac80211_registered; + + void *if_priv; + const struct wl1251_if_operations *if_ops; + + void (*set_power)(bool enable); + int irq; + bool use_eeprom; + + spinlock_t wl_lock; + + enum wl1251_state state; + struct mutex mutex; + + int physical_mem_addr; + int physical_reg_addr; + int virtual_mem_addr; + int virtual_reg_addr; + + int cmd_box_addr; + int event_box_addr; + struct boot_attr boot_attr; + + u8 *fw; + size_t fw_len; + u8 *nvs; + size_t nvs_len; + + u8 bssid[ETH_ALEN]; + u8 mac_addr[ETH_ALEN]; + u8 bss_type; + u8 listen_int; + int channel; + + void *target_mem_map; + struct acx_data_path_params_resp *data_path; + + /* Number of TX packets transferred to the FW, modulo 16 */ + u32 data_in_count; + + /* Frames scheduled for transmission, not handled yet */ + struct sk_buff_head tx_queue; + bool tx_queue_stopped; + + struct work_struct tx_work; + struct work_struct filter_work; + + /* Pending TX frames */ + struct sk_buff *tx_frames[16]; + + /* + * Index pointing to the next TX complete entry + * in the cyclic XT complete array we get from + * the FW. + */ + u32 next_tx_complete; + + /* FW Rx counter */ + u32 rx_counter; + + /* Rx frames handled */ + u32 rx_handled; + + /* Current double buffer */ + u32 rx_current_buffer; + u32 rx_last_id; + + /* The target interrupt mask */ + u32 intr_mask; + struct work_struct irq_work; + + /* The mbox event mask */ + u32 event_mask; + + /* Mailbox pointers */ + u32 mbox_ptr[2]; + + /* Are we currently scanning */ + bool scanning; + + /* Default key (for WEP) */ + u32 default_key; + + unsigned int tx_mgmt_frm_rate; + unsigned int tx_mgmt_frm_mod; + + unsigned int rx_config; + unsigned int rx_filter; + + /* is firmware in elp mode */ + bool elp; + + struct delayed_work elp_work; + + /* we can be in psm, but not in elp, we have to differentiate */ + bool psm; + + /* PSM mode requested */ + bool psm_requested; + + u16 beacon_int; + u8 dtim_period; + + /* in dBm */ + int power_level; + + struct wl1251_stats stats; + struct wl1251_debugfs debugfs; + + u32 buffer_32; + u32 buffer_cmd; + u8 buffer_busyword[WL1251_BUSY_WORD_LEN]; + struct wl1251_rx_descriptor *rx_descriptor; + + struct ieee80211_vif *vif; + + u32 chip_id; + char fw_ver[21]; + + /* Most recently reported noise in dBm */ + s8 noise; +}; + +int wl1251_plt_start(struct wl1251 *wl); +int wl1251_plt_stop(struct wl1251 *wl); + +struct ieee80211_hw *wl1251_alloc_hw(void); +int wl1251_free_hw(struct wl1251 *wl); +int wl1251_init_ieee80211(struct wl1251 *wl); +void wl1251_enable_interrupts(struct wl1251 *wl); +void wl1251_disable_interrupts(struct wl1251 *wl); + +#define DEFAULT_HW_GEN_MODULATION_TYPE CCK_LONG /* Long Preamble */ +#define DEFAULT_HW_GEN_TX_RATE RATE_2MBPS +#define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */ + +#define WL1251_DEFAULT_POWER_LEVEL 20 + +#define WL1251_TX_QUEUE_LOW_WATERMARK 10 +#define WL1251_TX_QUEUE_HIGH_WATERMARK 25 + +#define WL1251_DEFAULT_BEACON_INT 100 +#define WL1251_DEFAULT_DTIM_PERIOD 1 + +#define WL1251_DEFAULT_CHANNEL 0 + +#define CHIP_ID_1251_PG10 (0x7010101) +#define CHIP_ID_1251_PG11 (0x7020101) +#define CHIP_ID_1251_PG12 (0x7030101) +#define CHIP_ID_1271_PG10 (0x4030101) +#define CHIP_ID_1271_PG20 (0x4030111) + +#define WL1251_FW_NAME "wl1251-fw.bin" +#define WL1251_NVS_NAME "wl1251-nvs.bin" + +#define WL1251_POWER_ON_SLEEP 10 /* in miliseconds */ + +#define WL1251_PART_DOWN_MEM_START 0x0 +#define WL1251_PART_DOWN_MEM_SIZE 0x16800 +#define WL1251_PART_DOWN_REG_START REGISTERS_BASE +#define WL1251_PART_DOWN_REG_SIZE REGISTERS_DOWN_SIZE + +#define WL1251_PART_WORK_MEM_START 0x28000 +#define WL1251_PART_WORK_MEM_SIZE 0x14000 +#define WL1251_PART_WORK_REG_START REGISTERS_BASE +#define WL1251_PART_WORK_REG_SIZE REGISTERS_WORK_SIZE + +#endif diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig index 4a8bb25..b447559 100644 --- a/drivers/net/wireless/wl12xx/Kconfig +++ b/drivers/net/wireless/wl12xx/Kconfig @@ -5,40 +5,6 @@ menuconfig WL12XX This will enable TI wl12xx driver support. The drivers make use of the mac80211 stack. -config WL1251 - tristate "TI wl1251 support" - depends on WL12XX && GENERIC_HARDIRQS - select FW_LOADER - select CRC7 - ---help--- - This module adds support for wireless adapters based on - TI wl1251 chipset. - - If you choose to build a module, it'll be called wl1251. Say - N if unsure. - -config WL1251_SPI - tristate "TI wl1251 SPI support" - depends on WL1251 && SPI_MASTER - ---help--- - This module adds support for the SPI interface of adapters using - TI wl1251 chipset. Select this if your platform is using - the SPI bus. - - If you choose to build a module, it'll be called wl1251_spi. - Say N if unsure. - -config WL1251_SDIO - tristate "TI wl1251 SDIO support" - depends on WL1251 && MMC - ---help--- - This module adds support for the SDIO interface of adapters using - TI wl1251 chipset. Select this if your platform is using - the SDIO bus. - - If you choose to build a module, it'll be called - wl1251_sdio. Say N if unsure. - config WL1271 tristate "TI wl1271 support" depends on WL12XX && GENERIC_HARDIRQS diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile index 0d334d6..3a80744 100644 --- a/drivers/net/wireless/wl12xx/Makefile +++ b/drivers/net/wireless/wl12xx/Makefile @@ -1,12 +1,3 @@ -wl1251-objs = wl1251_main.o wl1251_event.o \ - wl1251_tx.o wl1251_rx.o wl1251_ps.o wl1251_cmd.o \ - wl1251_acx.o wl1251_boot.o wl1251_init.o \ - wl1251_debugfs.o wl1251_io.o - -obj-$(CONFIG_WL1251) += wl1251.o -obj-$(CONFIG_WL1251_SPI) += wl1251_spi.o -obj-$(CONFIG_WL1251_SDIO) += wl1251_sdio.o - wl1271-objs = wl1271_main.o wl1271_cmd.o wl1271_io.o \ wl1271_event.o wl1271_tx.o wl1271_rx.o \ wl1271_ps.o wl1271_acx.o wl1271_boot.o \ diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h deleted file mode 100644 index e113d4c..0000000 --- a/drivers/net/wireless/wl12xx/wl1251.h +++ /dev/null @@ -1,433 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008-2009 Nokia Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL1251_H__ -#define __WL1251_H__ - -#include -#include -#include -#include - -#define DRIVER_NAME "wl1251" -#define DRIVER_PREFIX DRIVER_NAME ": " - -enum { - DEBUG_NONE = 0, - DEBUG_IRQ = BIT(0), - DEBUG_SPI = BIT(1), - DEBUG_BOOT = BIT(2), - DEBUG_MAILBOX = BIT(3), - DEBUG_NETLINK = BIT(4), - DEBUG_EVENT = BIT(5), - DEBUG_TX = BIT(6), - DEBUG_RX = BIT(7), - DEBUG_SCAN = BIT(8), - DEBUG_CRYPT = BIT(9), - DEBUG_PSM = BIT(10), - DEBUG_MAC80211 = BIT(11), - DEBUG_CMD = BIT(12), - DEBUG_ACX = BIT(13), - DEBUG_ALL = ~0, -}; - -#define DEBUG_LEVEL (DEBUG_NONE) - -#define DEBUG_DUMP_LIMIT 1024 - -#define wl1251_error(fmt, arg...) \ - printk(KERN_ERR DRIVER_PREFIX "ERROR " fmt "\n", ##arg) - -#define wl1251_warning(fmt, arg...) \ - printk(KERN_WARNING DRIVER_PREFIX "WARNING " fmt "\n", ##arg) - -#define wl1251_notice(fmt, arg...) \ - printk(KERN_INFO DRIVER_PREFIX fmt "\n", ##arg) - -#define wl1251_info(fmt, arg...) \ - printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg) - -#define wl1251_debug(level, fmt, arg...) \ - do { \ - if (level & DEBUG_LEVEL) \ - printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg); \ - } while (0) - -#define wl1251_dump(level, prefix, buf, len) \ - do { \ - if (level & DEBUG_LEVEL) \ - print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ - DUMP_PREFIX_OFFSET, 16, 1, \ - buf, \ - min_t(size_t, len, DEBUG_DUMP_LIMIT), \ - 0); \ - } while (0) - -#define wl1251_dump_ascii(level, prefix, buf, len) \ - do { \ - if (level & DEBUG_LEVEL) \ - print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ - DUMP_PREFIX_OFFSET, 16, 1, \ - buf, \ - min_t(size_t, len, DEBUG_DUMP_LIMIT), \ - true); \ - } while (0) - -#define WL1251_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \ - CFG_BSSID_FILTER_EN) - -#define WL1251_DEFAULT_RX_FILTER (CFG_RX_PRSP_EN | \ - CFG_RX_MGMT_EN | \ - CFG_RX_DATA_EN | \ - CFG_RX_CTL_EN | \ - CFG_RX_BCN_EN | \ - CFG_RX_AUTH_EN | \ - CFG_RX_ASSOC_EN) - -#define WL1251_BUSY_WORD_LEN 8 - -struct boot_attr { - u32 radio_type; - u8 mac_clock; - u8 arm_clock; - int firmware_debug; - u32 minor; - u32 major; - u32 bugfix; -}; - -enum wl1251_state { - WL1251_STATE_OFF, - WL1251_STATE_ON, - WL1251_STATE_PLT, -}; - -enum wl1251_partition_type { - PART_DOWN, - PART_WORK, - PART_DRPW, - - PART_TABLE_LEN -}; - -struct wl1251_partition { - u32 size; - u32 start; -}; - -struct wl1251_partition_set { - struct wl1251_partition mem; - struct wl1251_partition reg; -}; - -struct wl1251; - -struct wl1251_stats { - struct acx_statistics *fw_stats; - unsigned long fw_stats_update; - - unsigned int retry_count; - unsigned int excessive_retries; -}; - -struct wl1251_debugfs { - struct dentry *rootdir; - struct dentry *fw_statistics; - - struct dentry *tx_internal_desc_overflow; - - struct dentry *rx_out_of_mem; - struct dentry *rx_hdr_overflow; - struct dentry *rx_hw_stuck; - struct dentry *rx_dropped; - struct dentry *rx_fcs_err; - struct dentry *rx_xfr_hint_trig; - struct dentry *rx_path_reset; - struct dentry *rx_reset_counter; - - struct dentry *dma_rx_requested; - struct dentry *dma_rx_errors; - struct dentry *dma_tx_requested; - struct dentry *dma_tx_errors; - - struct dentry *isr_cmd_cmplt; - struct dentry *isr_fiqs; - struct dentry *isr_rx_headers; - struct dentry *isr_rx_mem_overflow; - struct dentry *isr_rx_rdys; - struct dentry *isr_irqs; - struct dentry *isr_tx_procs; - struct dentry *isr_decrypt_done; - struct dentry *isr_dma0_done; - struct dentry *isr_dma1_done; - struct dentry *isr_tx_exch_complete; - struct dentry *isr_commands; - struct dentry *isr_rx_procs; - struct dentry *isr_hw_pm_mode_changes; - struct dentry *isr_host_acknowledges; - struct dentry *isr_pci_pm; - struct dentry *isr_wakeups; - struct dentry *isr_low_rssi; - - struct dentry *wep_addr_key_count; - struct dentry *wep_default_key_count; - /* skipping wep.reserved */ - struct dentry *wep_key_not_found; - struct dentry *wep_decrypt_fail; - struct dentry *wep_packets; - struct dentry *wep_interrupt; - - struct dentry *pwr_ps_enter; - struct dentry *pwr_elp_enter; - struct dentry *pwr_missing_bcns; - struct dentry *pwr_wake_on_host; - struct dentry *pwr_wake_on_timer_exp; - struct dentry *pwr_tx_with_ps; - struct dentry *pwr_tx_without_ps; - struct dentry *pwr_rcvd_beacons; - struct dentry *pwr_power_save_off; - struct dentry *pwr_enable_ps; - struct dentry *pwr_disable_ps; - struct dentry *pwr_fix_tsf_ps; - /* skipping cont_miss_bcns_spread for now */ - struct dentry *pwr_rcvd_awake_beacons; - - struct dentry *mic_rx_pkts; - struct dentry *mic_calc_failure; - - struct dentry *aes_encrypt_fail; - struct dentry *aes_decrypt_fail; - struct dentry *aes_encrypt_packets; - struct dentry *aes_decrypt_packets; - struct dentry *aes_encrypt_interrupt; - struct dentry *aes_decrypt_interrupt; - - struct dentry *event_heart_beat; - struct dentry *event_calibration; - struct dentry *event_rx_mismatch; - struct dentry *event_rx_mem_empty; - struct dentry *event_rx_pool; - struct dentry *event_oom_late; - struct dentry *event_phy_transmit_error; - struct dentry *event_tx_stuck; - - struct dentry *ps_pspoll_timeouts; - struct dentry *ps_upsd_timeouts; - struct dentry *ps_upsd_max_sptime; - struct dentry *ps_upsd_max_apturn; - struct dentry *ps_pspoll_max_apturn; - struct dentry *ps_pspoll_utilization; - struct dentry *ps_upsd_utilization; - - struct dentry *rxpipe_rx_prep_beacon_drop; - struct dentry *rxpipe_descr_host_int_trig_rx_data; - struct dentry *rxpipe_beacon_buffer_thres_host_int_trig_rx_data; - struct dentry *rxpipe_missed_beacon_host_int_trig_rx_data; - struct dentry *rxpipe_tx_xfr_host_int_trig_rx_data; - - struct dentry *tx_queue_len; - struct dentry *tx_queue_status; - - struct dentry *retry_count; - struct dentry *excessive_retries; -}; - -struct wl1251_if_operations { - void (*read)(struct wl1251 *wl, int addr, void *buf, size_t len); - void (*write)(struct wl1251 *wl, int addr, void *buf, size_t len); - void (*read_elp)(struct wl1251 *wl, int addr, u32 *val); - void (*write_elp)(struct wl1251 *wl, int addr, u32 val); - void (*reset)(struct wl1251 *wl); - void (*enable_irq)(struct wl1251 *wl); - void (*disable_irq)(struct wl1251 *wl); -}; - -struct wl1251 { - struct ieee80211_hw *hw; - bool mac80211_registered; - - void *if_priv; - const struct wl1251_if_operations *if_ops; - - void (*set_power)(bool enable); - int irq; - bool use_eeprom; - - spinlock_t wl_lock; - - enum wl1251_state state; - struct mutex mutex; - - int physical_mem_addr; - int physical_reg_addr; - int virtual_mem_addr; - int virtual_reg_addr; - - int cmd_box_addr; - int event_box_addr; - struct boot_attr boot_attr; - - u8 *fw; - size_t fw_len; - u8 *nvs; - size_t nvs_len; - - u8 bssid[ETH_ALEN]; - u8 mac_addr[ETH_ALEN]; - u8 bss_type; - u8 listen_int; - int channel; - - void *target_mem_map; - struct acx_data_path_params_resp *data_path; - - /* Number of TX packets transferred to the FW, modulo 16 */ - u32 data_in_count; - - /* Frames scheduled for transmission, not handled yet */ - struct sk_buff_head tx_queue; - bool tx_queue_stopped; - - struct work_struct tx_work; - struct work_struct filter_work; - - /* Pending TX frames */ - struct sk_buff *tx_frames[16]; - - /* - * Index pointing to the next TX complete entry - * in the cyclic XT complete array we get from - * the FW. - */ - u32 next_tx_complete; - - /* FW Rx counter */ - u32 rx_counter; - - /* Rx frames handled */ - u32 rx_handled; - - /* Current double buffer */ - u32 rx_current_buffer; - u32 rx_last_id; - - /* The target interrupt mask */ - u32 intr_mask; - struct work_struct irq_work; - - /* The mbox event mask */ - u32 event_mask; - - /* Mailbox pointers */ - u32 mbox_ptr[2]; - - /* Are we currently scanning */ - bool scanning; - - /* Default key (for WEP) */ - u32 default_key; - - unsigned int tx_mgmt_frm_rate; - unsigned int tx_mgmt_frm_mod; - - unsigned int rx_config; - unsigned int rx_filter; - - /* is firmware in elp mode */ - bool elp; - - struct delayed_work elp_work; - - /* we can be in psm, but not in elp, we have to differentiate */ - bool psm; - - /* PSM mode requested */ - bool psm_requested; - - u16 beacon_int; - u8 dtim_period; - - /* in dBm */ - int power_level; - - struct wl1251_stats stats; - struct wl1251_debugfs debugfs; - - u32 buffer_32; - u32 buffer_cmd; - u8 buffer_busyword[WL1251_BUSY_WORD_LEN]; - struct wl1251_rx_descriptor *rx_descriptor; - - struct ieee80211_vif *vif; - - u32 chip_id; - char fw_ver[21]; - - /* Most recently reported noise in dBm */ - s8 noise; -}; - -int wl1251_plt_start(struct wl1251 *wl); -int wl1251_plt_stop(struct wl1251 *wl); - -struct ieee80211_hw *wl1251_alloc_hw(void); -int wl1251_free_hw(struct wl1251 *wl); -int wl1251_init_ieee80211(struct wl1251 *wl); -void wl1251_enable_interrupts(struct wl1251 *wl); -void wl1251_disable_interrupts(struct wl1251 *wl); - -#define DEFAULT_HW_GEN_MODULATION_TYPE CCK_LONG /* Long Preamble */ -#define DEFAULT_HW_GEN_TX_RATE RATE_2MBPS -#define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */ - -#define WL1251_DEFAULT_POWER_LEVEL 20 - -#define WL1251_TX_QUEUE_LOW_WATERMARK 10 -#define WL1251_TX_QUEUE_HIGH_WATERMARK 25 - -#define WL1251_DEFAULT_BEACON_INT 100 -#define WL1251_DEFAULT_DTIM_PERIOD 1 - -#define WL1251_DEFAULT_CHANNEL 0 - -#define CHIP_ID_1251_PG10 (0x7010101) -#define CHIP_ID_1251_PG11 (0x7020101) -#define CHIP_ID_1251_PG12 (0x7030101) -#define CHIP_ID_1271_PG10 (0x4030101) -#define CHIP_ID_1271_PG20 (0x4030111) - -#define WL1251_FW_NAME "wl1251-fw.bin" -#define WL1251_NVS_NAME "wl1251-nvs.bin" - -#define WL1251_POWER_ON_SLEEP 10 /* in miliseconds */ - -#define WL1251_PART_DOWN_MEM_START 0x0 -#define WL1251_PART_DOWN_MEM_SIZE 0x16800 -#define WL1251_PART_DOWN_REG_START REGISTERS_BASE -#define WL1251_PART_DOWN_REG_SIZE REGISTERS_DOWN_SIZE - -#define WL1251_PART_WORK_MEM_START 0x28000 -#define WL1251_PART_WORK_MEM_SIZE 0x14000 -#define WL1251_PART_WORK_REG_START REGISTERS_BASE -#define WL1251_PART_WORK_REG_SIZE REGISTERS_WORK_SIZE - -#endif diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.c b/drivers/net/wireless/wl12xx/wl1251_acx.c deleted file mode 100644 index 2f8a2ba..0000000 --- a/drivers/net/wireless/wl12xx/wl1251_acx.c +++ /dev/null @@ -1,1048 +0,0 @@ -#include "wl1251_acx.h" - -#include -#include -#include - -#include "wl1251.h" -#include "wl1251_reg.h" -#include "wl1251_cmd.h" -#include "wl1251_ps.h" - -int wl1251_acx_frame_rates(struct wl1251 *wl, u8 ctrl_rate, u8 ctrl_mod, - u8 mgt_rate, u8 mgt_mod) -{ - struct acx_fw_gen_frame_rates *rates; - int ret; - - wl1251_debug(DEBUG_ACX, "acx frame rates"); - - rates = kzalloc(sizeof(*rates), GFP_KERNEL); - if (!rates) { - ret = -ENOMEM; - goto out; - } - - rates->tx_ctrl_frame_rate = ctrl_rate; - rates->tx_ctrl_frame_mod = ctrl_mod; - rates->tx_mgt_frame_rate = mgt_rate; - rates->tx_mgt_frame_mod = mgt_mod; - - ret = wl1251_cmd_configure(wl, ACX_FW_GEN_FRAME_RATES, - rates, sizeof(*rates)); - if (ret < 0) { - wl1251_error("Failed to set FW rates and modulation"); - goto out; - } - -out: - kfree(rates); - return ret; -} - - -int wl1251_acx_station_id(struct wl1251 *wl) -{ - struct acx_dot11_station_id *mac; - int ret, i; - - wl1251_debug(DEBUG_ACX, "acx dot11_station_id"); - - mac = kzalloc(sizeof(*mac), GFP_KERNEL); - if (!mac) { - ret = -ENOMEM; - goto out; - } - - for (i = 0; i < ETH_ALEN; i++) - mac->mac[i] = wl->mac_addr[ETH_ALEN - 1 - i]; - - ret = wl1251_cmd_configure(wl, DOT11_STATION_ID, mac, sizeof(*mac)); - if (ret < 0) - goto out; - -out: - kfree(mac); - return ret; -} - -int wl1251_acx_default_key(struct wl1251 *wl, u8 key_id) -{ - struct acx_dot11_default_key *default_key; - int ret; - - wl1251_debug(DEBUG_ACX, "acx dot11_default_key (%d)", key_id); - - default_key = kzalloc(sizeof(*default_key), GFP_KERNEL); - if (!default_key) { - ret = -ENOMEM; - goto out; - } - - default_key->id = key_id; - - ret = wl1251_cmd_configure(wl, DOT11_DEFAULT_KEY, - default_key, sizeof(*default_key)); - if (ret < 0) { - wl1251_error("Couldn't set default key"); - goto out; - } - - wl->default_key = key_id; - -out: - kfree(default_key); - return ret; -} - -int wl1251_acx_wake_up_conditions(struct wl1251 *wl, u8 wake_up_event, - u8 listen_interval) -{ - struct acx_wake_up_condition *wake_up; - int ret; - - wl1251_debug(DEBUG_ACX, "acx wake up conditions"); - - wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL); - if (!wake_up) { - ret = -ENOMEM; - goto out; - } - - wake_up->wake_up_event = wake_up_event; - wake_up->listen_interval = listen_interval; - - ret = wl1251_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS, - wake_up, sizeof(*wake_up)); - if (ret < 0) { - wl1251_warning("could not set wake up conditions: %d", ret); - goto out; - } - -out: - kfree(wake_up); - return ret; -} - -int wl1251_acx_sleep_auth(struct wl1251 *wl, u8 sleep_auth) -{ - struct acx_sleep_auth *auth; - int ret; - - wl1251_debug(DEBUG_ACX, "acx sleep auth"); - - auth = kzalloc(sizeof(*auth), GFP_KERNEL); - if (!auth) { - ret = -ENOMEM; - goto out; - } - - auth->sleep_auth = sleep_auth; - - ret = wl1251_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth)); - if (ret < 0) - return ret; - -out: - kfree(auth); - return ret; -} - -int wl1251_acx_fw_version(struct wl1251 *wl, char *buf, size_t len) -{ - struct acx_revision *rev; - int ret; - - wl1251_debug(DEBUG_ACX, "acx fw rev"); - - rev = kzalloc(sizeof(*rev), GFP_KERNEL); - if (!rev) { - ret = -ENOMEM; - goto out; - } - - ret = wl1251_cmd_interrogate(wl, ACX_FW_REV, rev, sizeof(*rev)); - if (ret < 0) { - wl1251_warning("ACX_FW_REV interrogate failed"); - goto out; - } - - /* be careful with the buffer sizes */ - strncpy(buf, rev->fw_version, min(len, sizeof(rev->fw_version))); - - /* - * if the firmware version string is exactly - * sizeof(rev->fw_version) long or fw_len is less than - * sizeof(rev->fw_version) it won't be null terminated - */ - buf[min(len, sizeof(rev->fw_version)) - 1] = '\0'; - -out: - kfree(rev); - return ret; -} - -int wl1251_acx_tx_power(struct wl1251 *wl, int power) -{ - struct acx_current_tx_power *acx; - int ret; - - wl1251_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr"); - - if (power < 0 || power > 25) - return -EINVAL; - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->current_tx_power = power * 10; - - ret = wl1251_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx)); - if (ret < 0) { - wl1251_warning("configure of tx power failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1251_acx_feature_cfg(struct wl1251 *wl) -{ - struct acx_feature_config *feature; - int ret; - - wl1251_debug(DEBUG_ACX, "acx feature cfg"); - - feature = kzalloc(sizeof(*feature), GFP_KERNEL); - if (!feature) { - ret = -ENOMEM; - goto out; - } - - /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */ - feature->data_flow_options = 0; - feature->options = 0; - - ret = wl1251_cmd_configure(wl, ACX_FEATURE_CFG, - feature, sizeof(*feature)); - if (ret < 0) { - wl1251_error("Couldn't set HW encryption"); - goto out; - } - -out: - kfree(feature); - return ret; -} - -int wl1251_acx_mem_map(struct wl1251 *wl, struct acx_header *mem_map, - size_t len) -{ - int ret; - - wl1251_debug(DEBUG_ACX, "acx mem map"); - - ret = wl1251_cmd_interrogate(wl, ACX_MEM_MAP, mem_map, len); - if (ret < 0) - return ret; - - return 0; -} - -int wl1251_acx_data_path_params(struct wl1251 *wl, - struct acx_data_path_params_resp *resp) -{ - struct acx_data_path_params *params; - int ret; - - wl1251_debug(DEBUG_ACX, "acx data path params"); - - params = kzalloc(sizeof(*params), GFP_KERNEL); - if (!params) { - ret = -ENOMEM; - goto out; - } - - params->rx_packet_ring_chunk_size = DP_RX_PACKET_RING_CHUNK_SIZE; - params->tx_packet_ring_chunk_size = DP_TX_PACKET_RING_CHUNK_SIZE; - - params->rx_packet_ring_chunk_num = DP_RX_PACKET_RING_CHUNK_NUM; - params->tx_packet_ring_chunk_num = DP_TX_PACKET_RING_CHUNK_NUM; - - params->tx_complete_threshold = 1; - - params->tx_complete_ring_depth = FW_TX_CMPLT_BLOCK_SIZE; - - params->tx_complete_timeout = DP_TX_COMPLETE_TIME_OUT; - - ret = wl1251_cmd_configure(wl, ACX_DATA_PATH_PARAMS, - params, sizeof(*params)); - if (ret < 0) - goto out; - - /* FIXME: shouldn't this be ACX_DATA_PATH_RESP_PARAMS? */ - ret = wl1251_cmd_interrogate(wl, ACX_DATA_PATH_PARAMS, - resp, sizeof(*resp)); - - if (ret < 0) { - wl1251_warning("failed to read data path parameters: %d", ret); - goto out; - } else if (resp->header.cmd.status != CMD_STATUS_SUCCESS) { - wl1251_warning("data path parameter acx status failed"); - ret = -EIO; - goto out; - } - -out: - kfree(params); - return ret; -} - -int wl1251_acx_rx_msdu_life_time(struct wl1251 *wl, u32 life_time) -{ - struct acx_rx_msdu_lifetime *acx; - int ret; - - wl1251_debug(DEBUG_ACX, "acx rx msdu life time"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->lifetime = life_time; - ret = wl1251_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME, - acx, sizeof(*acx)); - if (ret < 0) { - wl1251_warning("failed to set rx msdu life time: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1251_acx_rx_config(struct wl1251 *wl, u32 config, u32 filter) -{ - struct acx_rx_config *rx_config; - int ret; - - wl1251_debug(DEBUG_ACX, "acx rx config"); - - rx_config = kzalloc(sizeof(*rx_config), GFP_KERNEL); - if (!rx_config) { - ret = -ENOMEM; - goto out; - } - - rx_config->config_options = config; - rx_config->filter_options = filter; - - ret = wl1251_cmd_configure(wl, ACX_RX_CFG, - rx_config, sizeof(*rx_config)); - if (ret < 0) { - wl1251_warning("failed to set rx config: %d", ret); - goto out; - } - -out: - kfree(rx_config); - return ret; -} - -int wl1251_acx_pd_threshold(struct wl1251 *wl) -{ - struct acx_packet_detection *pd; - int ret; - - wl1251_debug(DEBUG_ACX, "acx data pd threshold"); - - pd = kzalloc(sizeof(*pd), GFP_KERNEL); - if (!pd) { - ret = -ENOMEM; - goto out; - } - - /* FIXME: threshold value not set */ - - ret = wl1251_cmd_configure(wl, ACX_PD_THRESHOLD, pd, sizeof(*pd)); - if (ret < 0) { - wl1251_warning("failed to set pd threshold: %d", ret); - goto out; - } - -out: - kfree(pd); - return ret; -} - -int wl1251_acx_slot(struct wl1251 *wl, enum acx_slot_type slot_time) -{ - struct acx_slot *slot; - int ret; - - wl1251_debug(DEBUG_ACX, "acx slot"); - - slot = kzalloc(sizeof(*slot), GFP_KERNEL); - if (!slot) { - ret = -ENOMEM; - goto out; - } - - slot->wone_index = STATION_WONE_INDEX; - slot->slot_time = slot_time; - - ret = wl1251_cmd_configure(wl, ACX_SLOT, slot, sizeof(*slot)); - if (ret < 0) { - wl1251_warning("failed to set slot time: %d", ret); - goto out; - } - -out: - kfree(slot); - return ret; -} - -int wl1251_acx_group_address_tbl(struct wl1251 *wl) -{ - struct acx_dot11_grp_addr_tbl *acx; - int ret; - - wl1251_debug(DEBUG_ACX, "acx group address tbl"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - /* MAC filtering */ - acx->enabled = 0; - acx->num_groups = 0; - memset(acx->mac_table, 0, ADDRESS_GROUP_MAX_LEN); - - ret = wl1251_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL, - acx, sizeof(*acx)); - if (ret < 0) { - wl1251_warning("failed to set group addr table: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1251_acx_service_period_timeout(struct wl1251 *wl) -{ - struct acx_rx_timeout *rx_timeout; - int ret; - - rx_timeout = kzalloc(sizeof(*rx_timeout), GFP_KERNEL); - if (!rx_timeout) { - ret = -ENOMEM; - goto out; - } - - wl1251_debug(DEBUG_ACX, "acx service period timeout"); - - rx_timeout->ps_poll_timeout = RX_TIMEOUT_PS_POLL_DEF; - rx_timeout->upsd_timeout = RX_TIMEOUT_UPSD_DEF; - - ret = wl1251_cmd_configure(wl, ACX_SERVICE_PERIOD_TIMEOUT, - rx_timeout, sizeof(*rx_timeout)); - if (ret < 0) { - wl1251_warning("failed to set service period timeout: %d", - ret); - goto out; - } - -out: - kfree(rx_timeout); - return ret; -} - -int wl1251_acx_rts_threshold(struct wl1251 *wl, u16 rts_threshold) -{ - struct acx_rts_threshold *rts; - int ret; - - wl1251_debug(DEBUG_ACX, "acx rts threshold"); - - rts = kzalloc(sizeof(*rts), GFP_KERNEL); - if (!rts) { - ret = -ENOMEM; - goto out; - } - - rts->threshold = rts_threshold; - - ret = wl1251_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts)); - if (ret < 0) { - wl1251_warning("failed to set rts threshold: %d", ret); - goto out; - } - -out: - kfree(rts); - return ret; -} - -int wl1251_acx_beacon_filter_opt(struct wl1251 *wl, bool enable_filter) -{ - struct acx_beacon_filter_option *beacon_filter; - int ret; - - wl1251_debug(DEBUG_ACX, "acx beacon filter opt"); - - beacon_filter = kzalloc(sizeof(*beacon_filter), GFP_KERNEL); - if (!beacon_filter) { - ret = -ENOMEM; - goto out; - } - - beacon_filter->enable = enable_filter; - beacon_filter->max_num_beacons = 0; - - ret = wl1251_cmd_configure(wl, ACX_BEACON_FILTER_OPT, - beacon_filter, sizeof(*beacon_filter)); - if (ret < 0) { - wl1251_warning("failed to set beacon filter opt: %d", ret); - goto out; - } - -out: - kfree(beacon_filter); - return ret; -} - -int wl1251_acx_beacon_filter_table(struct wl1251 *wl) -{ - struct acx_beacon_filter_ie_table *ie_table; - int idx = 0; - int ret; - - wl1251_debug(DEBUG_ACX, "acx beacon filter table"); - - ie_table = kzalloc(sizeof(*ie_table), GFP_KERNEL); - if (!ie_table) { - ret = -ENOMEM; - goto out; - } - - /* configure default beacon pass-through rules */ - ie_table->num_ie = 1; - ie_table->table[idx++] = BEACON_FILTER_IE_ID_CHANNEL_SWITCH_ANN; - ie_table->table[idx++] = BEACON_RULE_PASS_ON_APPEARANCE; - - ret = wl1251_cmd_configure(wl, ACX_BEACON_FILTER_TABLE, - ie_table, sizeof(*ie_table)); - if (ret < 0) { - wl1251_warning("failed to set beacon filter table: %d", ret); - goto out; - } - -out: - kfree(ie_table); - return ret; -} - -int wl1251_acx_conn_monit_params(struct wl1251 *wl) -{ - struct acx_conn_monit_params *acx; - int ret; - - wl1251_debug(DEBUG_ACX, "acx connection monitor parameters"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->synch_fail_thold = SYNCH_FAIL_DEFAULT_THRESHOLD; - acx->bss_lose_timeout = NO_BEACON_DEFAULT_TIMEOUT; - - ret = wl1251_cmd_configure(wl, ACX_CONN_MONIT_PARAMS, - acx, sizeof(*acx)); - if (ret < 0) { - wl1251_warning("failed to set connection monitor " - "parameters: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1251_acx_sg_enable(struct wl1251 *wl) -{ - struct acx_bt_wlan_coex *pta; - int ret; - - wl1251_debug(DEBUG_ACX, "acx sg enable"); - - pta = kzalloc(sizeof(*pta), GFP_KERNEL); - if (!pta) { - ret = -ENOMEM; - goto out; - } - - pta->enable = SG_ENABLE; - - ret = wl1251_cmd_configure(wl, ACX_SG_ENABLE, pta, sizeof(*pta)); - if (ret < 0) { - wl1251_warning("failed to set softgemini enable: %d", ret); - goto out; - } - -out: - kfree(pta); - return ret; -} - -int wl1251_acx_sg_cfg(struct wl1251 *wl) -{ - struct acx_bt_wlan_coex_param *param; - int ret; - - wl1251_debug(DEBUG_ACX, "acx sg cfg"); - - param = kzalloc(sizeof(*param), GFP_KERNEL); - if (!param) { - ret = -ENOMEM; - goto out; - } - - /* BT-WLAN coext parameters */ - param->min_rate = RATE_INDEX_24MBPS; - param->bt_hp_max_time = PTA_BT_HP_MAXTIME_DEF; - param->wlan_hp_max_time = PTA_WLAN_HP_MAX_TIME_DEF; - param->sense_disable_timer = PTA_SENSE_DISABLE_TIMER_DEF; - param->rx_time_bt_hp = PTA_PROTECTIVE_RX_TIME_DEF; - param->tx_time_bt_hp = PTA_PROTECTIVE_TX_TIME_DEF; - param->rx_time_bt_hp_fast = PTA_PROTECTIVE_RX_TIME_FAST_DEF; - param->tx_time_bt_hp_fast = PTA_PROTECTIVE_TX_TIME_FAST_DEF; - param->wlan_cycle_fast = PTA_CYCLE_TIME_FAST_DEF; - param->bt_anti_starvation_period = PTA_ANTI_STARVE_PERIOD_DEF; - param->next_bt_lp_packet = PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF; - param->wake_up_beacon = PTA_TIME_BEFORE_BEACON_DEF; - param->hp_dm_max_guard_time = PTA_HPDM_MAX_TIME_DEF; - param->next_wlan_packet = PTA_TIME_OUT_NEXT_WLAN_DEF; - param->antenna_type = PTA_ANTENNA_TYPE_DEF; - param->signal_type = PTA_SIGNALING_TYPE_DEF; - param->afh_leverage_on = PTA_AFH_LEVERAGE_ON_DEF; - param->quiet_cycle_num = PTA_NUMBER_QUIET_CYCLE_DEF; - param->max_cts = PTA_MAX_NUM_CTS_DEF; - param->wlan_packets_num = PTA_NUMBER_OF_WLAN_PACKETS_DEF; - param->bt_packets_num = PTA_NUMBER_OF_BT_PACKETS_DEF; - param->missed_rx_avalanche = PTA_RX_FOR_AVALANCHE_DEF; - param->wlan_elp_hp = PTA_ELP_HP_DEF; - param->bt_anti_starvation_cycles = PTA_ANTI_STARVE_NUM_CYCLE_DEF; - param->ack_mode_dual_ant = PTA_ACK_MODE_DEF; - param->pa_sd_enable = PTA_ALLOW_PA_SD_DEF; - param->pta_auto_mode_enable = PTA_AUTO_MODE_NO_CTS_DEF; - param->bt_hp_respected_num = PTA_BT_HP_RESPECTED_DEF; - - ret = wl1251_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param)); - if (ret < 0) { - wl1251_warning("failed to set sg config: %d", ret); - goto out; - } - -out: - kfree(param); - return ret; -} - -int wl1251_acx_cca_threshold(struct wl1251 *wl) -{ - struct acx_energy_detection *detection; - int ret; - - wl1251_debug(DEBUG_ACX, "acx cca threshold"); - - detection = kzalloc(sizeof(*detection), GFP_KERNEL); - if (!detection) { - ret = -ENOMEM; - goto out; - } - - detection->rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D; - detection->tx_energy_detection = 0; - - ret = wl1251_cmd_configure(wl, ACX_CCA_THRESHOLD, - detection, sizeof(*detection)); - if (ret < 0) { - wl1251_warning("failed to set cca threshold: %d", ret); - return ret; - } - -out: - kfree(detection); - return ret; -} - -int wl1251_acx_bcn_dtim_options(struct wl1251 *wl) -{ - struct acx_beacon_broadcast *bb; - int ret; - - wl1251_debug(DEBUG_ACX, "acx bcn dtim options"); - - bb = kzalloc(sizeof(*bb), GFP_KERNEL); - if (!bb) { - ret = -ENOMEM; - goto out; - } - - bb->beacon_rx_timeout = BCN_RX_TIMEOUT_DEF_VALUE; - bb->broadcast_timeout = BROADCAST_RX_TIMEOUT_DEF_VALUE; - bb->rx_broadcast_in_ps = RX_BROADCAST_IN_PS_DEF_VALUE; - bb->ps_poll_threshold = CONSECUTIVE_PS_POLL_FAILURE_DEF; - - ret = wl1251_cmd_configure(wl, ACX_BCN_DTIM_OPTIONS, bb, sizeof(*bb)); - if (ret < 0) { - wl1251_warning("failed to set rx config: %d", ret); - goto out; - } - -out: - kfree(bb); - return ret; -} - -int wl1251_acx_aid(struct wl1251 *wl, u16 aid) -{ - struct acx_aid *acx_aid; - int ret; - - wl1251_debug(DEBUG_ACX, "acx aid"); - - acx_aid = kzalloc(sizeof(*acx_aid), GFP_KERNEL); - if (!acx_aid) { - ret = -ENOMEM; - goto out; - } - - acx_aid->aid = aid; - - ret = wl1251_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid)); - if (ret < 0) { - wl1251_warning("failed to set aid: %d", ret); - goto out; - } - -out: - kfree(acx_aid); - return ret; -} - -int wl1251_acx_event_mbox_mask(struct wl1251 *wl, u32 event_mask) -{ - struct acx_event_mask *mask; - int ret; - - wl1251_debug(DEBUG_ACX, "acx event mbox mask"); - - mask = kzalloc(sizeof(*mask), GFP_KERNEL); - if (!mask) { - ret = -ENOMEM; - goto out; - } - - /* high event mask is unused */ - mask->high_event_mask = 0xffffffff; - - mask->event_mask = event_mask; - - ret = wl1251_cmd_configure(wl, ACX_EVENT_MBOX_MASK, - mask, sizeof(*mask)); - if (ret < 0) { - wl1251_warning("failed to set acx_event_mbox_mask: %d", ret); - goto out; - } - -out: - kfree(mask); - return ret; -} - -int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type preamble) -{ - struct acx_preamble *acx; - int ret; - - wl1251_debug(DEBUG_ACX, "acx_set_preamble"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->preamble = preamble; - - ret = wl1251_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx)); - if (ret < 0) { - wl1251_warning("Setting of preamble failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1251_acx_cts_protect(struct wl1251 *wl, - enum acx_ctsprotect_type ctsprotect) -{ - struct acx_ctsprotect *acx; - int ret; - - wl1251_debug(DEBUG_ACX, "acx_set_ctsprotect"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->ctsprotect = ctsprotect; - - ret = wl1251_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx)); - if (ret < 0) { - wl1251_warning("Setting of ctsprotect failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime) -{ - struct acx_tsf_info *tsf_info; - int ret; - - tsf_info = kzalloc(sizeof(*tsf_info), GFP_KERNEL); - if (!tsf_info) { - ret = -ENOMEM; - goto out; - } - - ret = wl1251_cmd_interrogate(wl, ACX_TSF_INFO, - tsf_info, sizeof(*tsf_info)); - if (ret < 0) { - wl1251_warning("ACX_FW_REV interrogate failed"); - goto out; - } - - *mactime = tsf_info->current_tsf_lsb | - (tsf_info->current_tsf_msb << 31); - -out: - kfree(tsf_info); - return ret; -} - -int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats) -{ - int ret; - - wl1251_debug(DEBUG_ACX, "acx statistics"); - - ret = wl1251_cmd_interrogate(wl, ACX_STATISTICS, stats, - sizeof(*stats)); - if (ret < 0) { - wl1251_warning("acx statistics failed: %d", ret); - return -ENOMEM; - } - - return 0; -} - -int wl1251_acx_rate_policies(struct wl1251 *wl) -{ - struct acx_rate_policy *acx; - int ret = 0; - - wl1251_debug(DEBUG_ACX, "acx rate policies"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - - if (!acx) { - ret = -ENOMEM; - goto out; - } - - /* configure one default (one-size-fits-all) rate class */ - acx->rate_class_cnt = 1; - acx->rate_class[0].enabled_rates = ACX_RATE_MASK_UNSPECIFIED; - acx->rate_class[0].short_retry_limit = ACX_RATE_RETRY_LIMIT; - acx->rate_class[0].long_retry_limit = ACX_RATE_RETRY_LIMIT; - acx->rate_class[0].aflags = 0; - - ret = wl1251_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); - if (ret < 0) { - wl1251_warning("Setting of rate policies failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1251_acx_mem_cfg(struct wl1251 *wl) -{ - struct wl1251_acx_config_memory *mem_conf; - int ret, i; - - wl1251_debug(DEBUG_ACX, "acx mem cfg"); - - mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); - if (!mem_conf) { - ret = -ENOMEM; - goto out; - } - - /* memory config */ - mem_conf->mem_config.num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS); - mem_conf->mem_config.rx_mem_block_num = 35; - mem_conf->mem_config.tx_min_mem_block_num = 64; - mem_conf->mem_config.num_tx_queues = MAX_TX_QUEUES; - mem_conf->mem_config.host_if_options = HOSTIF_PKT_RING; - mem_conf->mem_config.num_ssid_profiles = 1; - mem_conf->mem_config.debug_buffer_size = - cpu_to_le16(TRACE_BUFFER_MAX_SIZE); - - /* RX queue config */ - mem_conf->rx_queue_config.dma_address = 0; - mem_conf->rx_queue_config.num_descs = ACX_RX_DESC_DEF; - mem_conf->rx_queue_config.priority = DEFAULT_RXQ_PRIORITY; - mem_conf->rx_queue_config.type = DEFAULT_RXQ_TYPE; - - /* TX queue config */ - for (i = 0; i < MAX_TX_QUEUES; i++) { - mem_conf->tx_queue_config[i].num_descs = ACX_TX_DESC_DEF; - mem_conf->tx_queue_config[i].attributes = i; - } - - ret = wl1251_cmd_configure(wl, ACX_MEM_CFG, mem_conf, - sizeof(*mem_conf)); - if (ret < 0) { - wl1251_warning("wl1251 mem config failed: %d", ret); - goto out; - } - -out: - kfree(mem_conf); - return ret; -} - -int wl1251_acx_wr_tbtt_and_dtim(struct wl1251 *wl, u16 tbtt, u8 dtim) -{ - struct wl1251_acx_wr_tbtt_and_dtim *acx; - int ret; - - wl1251_debug(DEBUG_ACX, "acx tbtt and dtim"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->tbtt = tbtt; - acx->dtim = dtim; - - ret = wl1251_cmd_configure(wl, ACX_WR_TBTT_AND_DTIM, - acx, sizeof(*acx)); - if (ret < 0) { - wl1251_warning("failed to set tbtt and dtim: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max, - u8 aifs, u16 txop) -{ - struct wl1251_acx_ac_cfg *acx; - int ret = 0; - - wl1251_debug(DEBUG_ACX, "acx ac cfg %d cw_ming %d cw_max %d " - "aifs %d txop %d", ac, cw_min, cw_max, aifs, txop); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->ac = ac; - acx->cw_min = cw_min; - acx->cw_max = cw_max; - acx->aifsn = aifs; - acx->txop_limit = txop; - - ret = wl1251_cmd_configure(wl, ACX_AC_CFG, acx, sizeof(*acx)); - if (ret < 0) { - wl1251_warning("acx ac cfg failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1251_acx_tid_cfg(struct wl1251 *wl, u8 queue, - enum wl1251_acx_channel_type type, - u8 tsid, enum wl1251_acx_ps_scheme ps_scheme, - enum wl1251_acx_ack_policy ack_policy) -{ - struct wl1251_acx_tid_cfg *acx; - int ret = 0; - - wl1251_debug(DEBUG_ACX, "acx tid cfg %d type %d tsid %d " - "ps_scheme %d ack_policy %d", queue, type, tsid, - ps_scheme, ack_policy); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->queue = queue; - acx->type = type; - acx->tsid = tsid; - acx->ps_scheme = ps_scheme; - acx->ack_policy = ack_policy; - - ret = wl1251_cmd_configure(wl, ACX_TID_CFG, acx, sizeof(*acx)); - if (ret < 0) { - wl1251_warning("acx tid cfg failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.h b/drivers/net/wireless/wl12xx/wl1251_acx.h deleted file mode 100644 index c7cc5c1..0000000 --- a/drivers/net/wireless/wl12xx/wl1251_acx.h +++ /dev/null @@ -1,1411 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL1251_ACX_H__ -#define __WL1251_ACX_H__ - -#include "wl1251.h" -#include "wl1251_cmd.h" - -/* Target's information element */ -struct acx_header { - struct wl1251_cmd_header cmd; - - /* acx (or information element) header */ - u16 id; - - /* payload length (not including headers */ - u16 len; -} __packed; - -struct acx_error_counter { - struct acx_header header; - - /* The number of PLCP errors since the last time this */ - /* information element was interrogated. This field is */ - /* automatically cleared when it is interrogated.*/ - u32 PLCP_error; - - /* The number of FCS errors since the last time this */ - /* information element was interrogated. This field is */ - /* automatically cleared when it is interrogated.*/ - u32 FCS_error; - - /* The number of MPDUs without PLCP header errors received*/ - /* since the last time this information element was interrogated. */ - /* This field is automatically cleared when it is interrogated.*/ - u32 valid_frame; - - /* the number of missed sequence numbers in the squentially */ - /* values of frames seq numbers */ - u32 seq_num_miss; -} __packed; - -struct acx_revision { - struct acx_header header; - - /* - * The WiLink firmware version, an ASCII string x.x.x.x, - * that uniquely identifies the current firmware. - * The left most digit is incremented each time a - * significant change is made to the firmware, such as - * code redesign or new platform support. - * The second digit is incremented when major enhancements - * are added or major fixes are made. - * The third digit is incremented for each GA release. - * The fourth digit is incremented for each build. - * The first two digits identify a firmware release version, - * in other words, a unique set of features. - * The first three digits identify a GA release. - */ - char fw_version[20]; - - /* - * This 4 byte field specifies the WiLink hardware version. - * bits 0 - 15: Reserved. - * bits 16 - 23: Version ID - The WiLink version ID - * (1 = first spin, 2 = second spin, and so on). - * bits 24 - 31: Chip ID - The WiLink chip ID. - */ - u32 hw_version; -} __packed; - -enum wl1251_psm_mode { - /* Active mode */ - WL1251_PSM_CAM = 0, - - /* Power save mode */ - WL1251_PSM_PS = 1, - - /* Extreme low power */ - WL1251_PSM_ELP = 2, -}; - -struct acx_sleep_auth { - struct acx_header header; - - /* The sleep level authorization of the device. */ - /* 0 - Always active*/ - /* 1 - Power down mode: light / fast sleep*/ - /* 2 - ELP mode: Deep / Max sleep*/ - u8 sleep_auth; - u8 padding[3]; -} __packed; - -enum { - HOSTIF_PCI_MASTER_HOST_INDIRECT, - HOSTIF_PCI_MASTER_HOST_DIRECT, - HOSTIF_SLAVE, - HOSTIF_PKT_RING, - HOSTIF_DONTCARE = 0xFF -}; - -#define DEFAULT_UCAST_PRIORITY 0 -#define DEFAULT_RX_Q_PRIORITY 0 -#define DEFAULT_NUM_STATIONS 1 -#define DEFAULT_RXQ_PRIORITY 0 /* low 0 .. 15 high */ -#define DEFAULT_RXQ_TYPE 0x07 /* All frames, Data/Ctrl/Mgmt */ -#define TRACE_BUFFER_MAX_SIZE 256 - -#define DP_RX_PACKET_RING_CHUNK_SIZE 1600 -#define DP_TX_PACKET_RING_CHUNK_SIZE 1600 -#define DP_RX_PACKET_RING_CHUNK_NUM 2 -#define DP_TX_PACKET_RING_CHUNK_NUM 2 -#define DP_TX_COMPLETE_TIME_OUT 20 -#define FW_TX_CMPLT_BLOCK_SIZE 16 - -struct acx_data_path_params { - struct acx_header header; - - u16 rx_packet_ring_chunk_size; - u16 tx_packet_ring_chunk_size; - - u8 rx_packet_ring_chunk_num; - u8 tx_packet_ring_chunk_num; - - /* - * Maximum number of packets that can be gathered - * in the TX complete ring before an interrupt - * is generated. - */ - u8 tx_complete_threshold; - - /* Number of pending TX complete entries in cyclic ring.*/ - u8 tx_complete_ring_depth; - - /* - * Max num microseconds since a packet enters the TX - * complete ring until an interrupt is generated. - */ - u32 tx_complete_timeout; -} __packed; - - -struct acx_data_path_params_resp { - struct acx_header header; - - u16 rx_packet_ring_chunk_size; - u16 tx_packet_ring_chunk_size; - - u8 rx_packet_ring_chunk_num; - u8 tx_packet_ring_chunk_num; - - u8 pad[2]; - - u32 rx_packet_ring_addr; - u32 tx_packet_ring_addr; - - u32 rx_control_addr; - u32 tx_control_addr; - - u32 tx_complete_addr; -} __packed; - -#define TX_MSDU_LIFETIME_MIN 0 -#define TX_MSDU_LIFETIME_MAX 3000 -#define TX_MSDU_LIFETIME_DEF 512 -#define RX_MSDU_LIFETIME_MIN 0 -#define RX_MSDU_LIFETIME_MAX 0xFFFFFFFF -#define RX_MSDU_LIFETIME_DEF 512000 - -struct acx_rx_msdu_lifetime { - struct acx_header header; - - /* - * The maximum amount of time, in TU, before the - * firmware discards the MSDU. - */ - u32 lifetime; -} __packed; - -/* - * RX Config Options Table - * Bit Definition - * === ========== - * 31:14 Reserved - * 13 Copy RX Status - when set, write three receive status words - * to top of rx'd MPDUs. - * When cleared, do not write three status words (added rev 1.5) - * 12 Reserved - * 11 RX Complete upon FCS error - when set, give rx complete - * interrupt for FCS errors, after the rx filtering, e.g. unicast - * frames not to us with FCS error will not generate an interrupt. - * 10 SSID Filter Enable - When set, the WiLink discards all beacon, - * probe request, and probe response frames with an SSID that does - * not match the SSID specified by the host in the START/JOIN - * command. - * When clear, the WiLink receives frames with any SSID. - * 9 Broadcast Filter Enable - When set, the WiLink discards all - * broadcast frames. When clear, the WiLink receives all received - * broadcast frames. - * 8:6 Reserved - * 5 BSSID Filter Enable - When set, the WiLink discards any frames - * with a BSSID that does not match the BSSID specified by the - * host. - * When clear, the WiLink receives frames from any BSSID. - * 4 MAC Addr Filter - When set, the WiLink discards any frames - * with a destination address that does not match the MAC address - * of the adaptor. - * When clear, the WiLink receives frames destined to any MAC - * address. - * 3 Promiscuous - When set, the WiLink receives all valid frames - * (i.e., all frames that pass the FCS check). - * When clear, only frames that pass the other filters specified - * are received. - * 2 FCS - When set, the WiLink includes the FCS with the received - * frame. - * When cleared, the FCS is discarded. - * 1 PLCP header - When set, write all data from baseband to frame - * buffer including PHY header. - * 0 Reserved - Always equal to 0. - * - * RX Filter Options Table - * Bit Definition - * === ========== - * 31:12 Reserved - Always equal to 0. - * 11 Association - When set, the WiLink receives all association - * related frames (association request/response, reassocation - * request/response, and disassociation). When clear, these frames - * are discarded. - * 10 Auth/De auth - When set, the WiLink receives all authentication - * and de-authentication frames. When clear, these frames are - * discarded. - * 9 Beacon - When set, the WiLink receives all beacon frames. - * When clear, these frames are discarded. - * 8 Contention Free - When set, the WiLink receives all contention - * free frames. - * When clear, these frames are discarded. - * 7 Control - When set, the WiLink receives all control frames. - * When clear, these frames are discarded. - * 6 Data - When set, the WiLink receives all data frames. - * When clear, these frames are discarded. - * 5 FCS Error - When set, the WiLink receives frames that have FCS - * errors. - * When clear, these frames are discarded. - * 4 Management - When set, the WiLink receives all management - * frames. - * When clear, these frames are discarded. - * 3 Probe Request - When set, the WiLink receives all probe request - * frames. - * When clear, these frames are discarded. - * 2 Probe Response - When set, the WiLink receives all probe - * response frames. - * When clear, these frames are discarded. - * 1 RTS/CTS/ACK - When set, the WiLink receives all RTS, CTS and ACK - * frames. - * When clear, these frames are discarded. - * 0 Rsvd Type/Sub Type - When set, the WiLink receives all frames - * that have reserved frame types and sub types as defined by the - * 802.11 specification. - * When clear, these frames are discarded. - */ -struct acx_rx_config { - struct acx_header header; - - u32 config_options; - u32 filter_options; -} __packed; - -enum { - QOS_AC_BE = 0, - QOS_AC_BK, - QOS_AC_VI, - QOS_AC_VO, - QOS_HIGHEST_AC_INDEX = QOS_AC_VO, -}; - -#define MAX_NUM_OF_AC (QOS_HIGHEST_AC_INDEX+1) -#define FIRST_AC_INDEX QOS_AC_BE -#define MAX_NUM_OF_802_1d_TAGS 8 -#define AC_PARAMS_MAX_TSID 15 -#define MAX_APSD_CONF 0xffff - -#define QOS_TX_HIGH_MIN (0) -#define QOS_TX_HIGH_MAX (100) - -#define QOS_TX_HIGH_BK_DEF (25) -#define QOS_TX_HIGH_BE_DEF (35) -#define QOS_TX_HIGH_VI_DEF (35) -#define QOS_TX_HIGH_VO_DEF (35) - -#define QOS_TX_LOW_BK_DEF (15) -#define QOS_TX_LOW_BE_DEF (25) -#define QOS_TX_LOW_VI_DEF (25) -#define QOS_TX_LOW_VO_DEF (25) - -struct acx_tx_queue_qos_config { - struct acx_header header; - - u8 qid; - u8 pad[3]; - - /* Max number of blocks allowd in the queue */ - u16 high_threshold; - - /* Lowest memory blocks guaranteed for this queue */ - u16 low_threshold; -} __packed; - -struct acx_packet_detection { - struct acx_header header; - - u32 threshold; -} __packed; - - -enum acx_slot_type { - SLOT_TIME_LONG = 0, - SLOT_TIME_SHORT = 1, - DEFAULT_SLOT_TIME = SLOT_TIME_SHORT, - MAX_SLOT_TIMES = 0xFF -}; - -#define STATION_WONE_INDEX 0 - -struct acx_slot { - struct acx_header header; - - u8 wone_index; /* Reserved */ - u8 slot_time; - u8 reserved[6]; -} __packed; - - -#define ADDRESS_GROUP_MAX (8) -#define ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ADDRESS_GROUP_MAX) - -struct acx_dot11_grp_addr_tbl { - struct acx_header header; - - u8 enabled; - u8 num_groups; - u8 pad[2]; - u8 mac_table[ADDRESS_GROUP_MAX_LEN]; -} __packed; - - -#define RX_TIMEOUT_PS_POLL_MIN 0 -#define RX_TIMEOUT_PS_POLL_MAX (200000) -#define RX_TIMEOUT_PS_POLL_DEF (15) -#define RX_TIMEOUT_UPSD_MIN 0 -#define RX_TIMEOUT_UPSD_MAX (200000) -#define RX_TIMEOUT_UPSD_DEF (15) - -struct acx_rx_timeout { - struct acx_header header; - - /* - * The longest time the STA will wait to receive - * traffic from the AP after a PS-poll has been - * transmitted. - */ - u16 ps_poll_timeout; - - /* - * The longest time the STA will wait to receive - * traffic from the AP after a frame has been sent - * from an UPSD enabled queue. - */ - u16 upsd_timeout; -} __packed; - -#define RTS_THRESHOLD_MIN 0 -#define RTS_THRESHOLD_MAX 4096 -#define RTS_THRESHOLD_DEF 2347 - -struct acx_rts_threshold { - struct acx_header header; - - u16 threshold; - u8 pad[2]; -} __packed; - -struct acx_beacon_filter_option { - struct acx_header header; - - u8 enable; - - /* - * The number of beacons without the unicast TIM - * bit set that the firmware buffers before - * signaling the host about ready frames. - * When set to 0 and the filter is enabled, beacons - * without the unicast TIM bit set are dropped. - */ - u8 max_num_beacons; - u8 pad[2]; -} __packed; - -/* - * ACXBeaconFilterEntry (not 221) - * Byte Offset Size (Bytes) Definition - * =========== ============ ========== - * 0 1 IE identifier - * 1 1 Treatment bit mask - * - * ACXBeaconFilterEntry (221) - * Byte Offset Size (Bytes) Definition - * =========== ============ ========== - * 0 1 IE identifier - * 1 1 Treatment bit mask - * 2 3 OUI - * 5 1 Type - * 6 2 Version - * - * - * Treatment bit mask - The information element handling: - * bit 0 - The information element is compared and transferred - * in case of change. - * bit 1 - The information element is transferred to the host - * with each appearance or disappearance. - * Note that both bits can be set at the same time. - */ -#define BEACON_FILTER_TABLE_MAX_IE_NUM (32) -#define BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM (6) -#define BEACON_FILTER_TABLE_IE_ENTRY_SIZE (2) -#define BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE (6) -#define BEACON_FILTER_TABLE_MAX_SIZE ((BEACON_FILTER_TABLE_MAX_IE_NUM * \ - BEACON_FILTER_TABLE_IE_ENTRY_SIZE) + \ - (BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM * \ - BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE)) - -#define BEACON_RULE_PASS_ON_CHANGE BIT(0) -#define BEACON_RULE_PASS_ON_APPEARANCE BIT(1) - -#define BEACON_FILTER_IE_ID_CHANNEL_SWITCH_ANN (37) - -struct acx_beacon_filter_ie_table { - struct acx_header header; - - u8 num_ie; - u8 pad[3]; - u8 table[BEACON_FILTER_TABLE_MAX_SIZE]; -} __packed; - -#define SYNCH_FAIL_DEFAULT_THRESHOLD 10 /* number of beacons */ -#define NO_BEACON_DEFAULT_TIMEOUT (500) /* in microseconds */ - -struct acx_conn_monit_params { - struct acx_header header; - - u32 synch_fail_thold; /* number of beacons missed */ - u32 bss_lose_timeout; /* number of TU's from synch fail */ -} __packed; - -enum { - SG_ENABLE = 0, - SG_DISABLE, - SG_SENSE_NO_ACTIVITY, - SG_SENSE_ACTIVE -}; - -struct acx_bt_wlan_coex { - struct acx_header header; - - /* - * 0 -> PTA enabled - * 1 -> PTA disabled - * 2 -> sense no active mode, i.e. - * an interrupt is sent upon - * BT activity. - * 3 -> PTA is switched on in response - * to the interrupt sending. - */ - u8 enable; - u8 pad[3]; -} __packed; - -#define PTA_ANTENNA_TYPE_DEF (0) -#define PTA_BT_HP_MAXTIME_DEF (2000) -#define PTA_WLAN_HP_MAX_TIME_DEF (5000) -#define PTA_SENSE_DISABLE_TIMER_DEF (1350) -#define PTA_PROTECTIVE_RX_TIME_DEF (1500) -#define PTA_PROTECTIVE_TX_TIME_DEF (1500) -#define PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF (3000) -#define PTA_SIGNALING_TYPE_DEF (1) -#define PTA_AFH_LEVERAGE_ON_DEF (0) -#define PTA_NUMBER_QUIET_CYCLE_DEF (0) -#define PTA_MAX_NUM_CTS_DEF (3) -#define PTA_NUMBER_OF_WLAN_PACKETS_DEF (2) -#define PTA_NUMBER_OF_BT_PACKETS_DEF (2) -#define PTA_PROTECTIVE_RX_TIME_FAST_DEF (1500) -#define PTA_PROTECTIVE_TX_TIME_FAST_DEF (3000) -#define PTA_CYCLE_TIME_FAST_DEF (8700) -#define PTA_RX_FOR_AVALANCHE_DEF (5) -#define PTA_ELP_HP_DEF (0) -#define PTA_ANTI_STARVE_PERIOD_DEF (500) -#define PTA_ANTI_STARVE_NUM_CYCLE_DEF (4) -#define PTA_ALLOW_PA_SD_DEF (1) -#define PTA_TIME_BEFORE_BEACON_DEF (6300) -#define PTA_HPDM_MAX_TIME_DEF (1600) -#define PTA_TIME_OUT_NEXT_WLAN_DEF (2550) -#define PTA_AUTO_MODE_NO_CTS_DEF (0) -#define PTA_BT_HP_RESPECTED_DEF (3) -#define PTA_WLAN_RX_MIN_RATE_DEF (24) -#define PTA_ACK_MODE_DEF (1) - -struct acx_bt_wlan_coex_param { - struct acx_header header; - - /* - * The minimum rate of a received WLAN packet in the STA, - * during protective mode, of which a new BT-HP request - * during this Rx will always be respected and gain the antenna. - */ - u32 min_rate; - - /* Max time the BT HP will be respected. */ - u16 bt_hp_max_time; - - /* Max time the WLAN HP will be respected. */ - u16 wlan_hp_max_time; - - /* - * The time between the last BT activity - * and the moment when the sense mode returns - * to SENSE_INACTIVE. - */ - u16 sense_disable_timer; - - /* Time before the next BT HP instance */ - u16 rx_time_bt_hp; - u16 tx_time_bt_hp; - - /* range: 10-20000 default: 1500 */ - u16 rx_time_bt_hp_fast; - u16 tx_time_bt_hp_fast; - - /* range: 2000-65535 default: 8700 */ - u16 wlan_cycle_fast; - - /* range: 0 - 15000 (Msec) default: 1000 */ - u16 bt_anti_starvation_period; - - /* range 400-10000(Usec) default: 3000 */ - u16 next_bt_lp_packet; - - /* Deafult: worst case for BT DH5 traffic */ - u16 wake_up_beacon; - - /* range: 0-50000(Usec) default: 1050 */ - u16 hp_dm_max_guard_time; - - /* - * This is to prevent both BT & WLAN antenna - * starvation. - * Range: 100-50000(Usec) default:2550 - */ - u16 next_wlan_packet; - - /* 0 -> shared antenna */ - u8 antenna_type; - - /* - * 0 -> TI legacy - * 1 -> Palau - */ - u8 signal_type; - - /* - * BT AFH status - * 0 -> no AFH - * 1 -> from dedicated GPIO - * 2 -> AFH on (from host) - */ - u8 afh_leverage_on; - - /* - * The number of cycles during which no - * TX will be sent after 1 cycle of RX - * transaction in protective mode - */ - u8 quiet_cycle_num; - - /* - * The maximum number of CTSs that will - * be sent for receiving RX packet in - * protective mode - */ - u8 max_cts; - - /* - * The number of WLAN packets - * transferred in common mode before - * switching to BT. - */ - u8 wlan_packets_num; - - /* - * The number of BT packets - * transferred in common mode before - * switching to WLAN. - */ - u8 bt_packets_num; - - /* range: 1-255 default: 5 */ - u8 missed_rx_avalanche; - - /* range: 0-1 default: 1 */ - u8 wlan_elp_hp; - - /* range: 0 - 15 default: 4 */ - u8 bt_anti_starvation_cycles; - - u8 ack_mode_dual_ant; - - /* - * Allow PA_SD assertion/de-assertion - * during enabled BT activity. - */ - u8 pa_sd_enable; - - /* - * Enable/Disable PTA in auto mode: - * Support Both Active & P.S modes - */ - u8 pta_auto_mode_enable; - - /* range: 0 - 20 default: 1 */ - u8 bt_hp_respected_num; -} __packed; - -#define CCA_THRSH_ENABLE_ENERGY_D 0x140A -#define CCA_THRSH_DISABLE_ENERGY_D 0xFFEF - -struct acx_energy_detection { - struct acx_header header; - - /* The RX Clear Channel Assessment threshold in the PHY */ - u16 rx_cca_threshold; - u8 tx_energy_detection; - u8 pad; -} __packed; - -#define BCN_RX_TIMEOUT_DEF_VALUE 10000 -#define BROADCAST_RX_TIMEOUT_DEF_VALUE 20000 -#define RX_BROADCAST_IN_PS_DEF_VALUE 1 -#define CONSECUTIVE_PS_POLL_FAILURE_DEF 4 - -struct acx_beacon_broadcast { - struct acx_header header; - - u16 beacon_rx_timeout; - u16 broadcast_timeout; - - /* Enables receiving of broadcast packets in PS mode */ - u8 rx_broadcast_in_ps; - - /* Consecutive PS Poll failures before updating the host */ - u8 ps_poll_threshold; - u8 pad[2]; -} __packed; - -struct acx_event_mask { - struct acx_header header; - - u32 event_mask; - u32 high_event_mask; /* Unused */ -} __packed; - -#define CFG_RX_FCS BIT(2) -#define CFG_RX_ALL_GOOD BIT(3) -#define CFG_UNI_FILTER_EN BIT(4) -#define CFG_BSSID_FILTER_EN BIT(5) -#define CFG_MC_FILTER_EN BIT(6) -#define CFG_MC_ADDR0_EN BIT(7) -#define CFG_MC_ADDR1_EN BIT(8) -#define CFG_BC_REJECT_EN BIT(9) -#define CFG_SSID_FILTER_EN BIT(10) -#define CFG_RX_INT_FCS_ERROR BIT(11) -#define CFG_RX_INT_ENCRYPTED BIT(12) -#define CFG_RX_WR_RX_STATUS BIT(13) -#define CFG_RX_FILTER_NULTI BIT(14) -#define CFG_RX_RESERVE BIT(15) -#define CFG_RX_TIMESTAMP_TSF BIT(16) - -#define CFG_RX_RSV_EN BIT(0) -#define CFG_RX_RCTS_ACK BIT(1) -#define CFG_RX_PRSP_EN BIT(2) -#define CFG_RX_PREQ_EN BIT(3) -#define CFG_RX_MGMT_EN BIT(4) -#define CFG_RX_FCS_ERROR BIT(5) -#define CFG_RX_DATA_EN BIT(6) -#define CFG_RX_CTL_EN BIT(7) -#define CFG_RX_CF_EN BIT(8) -#define CFG_RX_BCN_EN BIT(9) -#define CFG_RX_AUTH_EN BIT(10) -#define CFG_RX_ASSOC_EN BIT(11) - -#define SCAN_PASSIVE BIT(0) -#define SCAN_5GHZ_BAND BIT(1) -#define SCAN_TRIGGERED BIT(2) -#define SCAN_PRIORITY_HIGH BIT(3) - -struct acx_fw_gen_frame_rates { - struct acx_header header; - - u8 tx_ctrl_frame_rate; /* RATE_* */ - u8 tx_ctrl_frame_mod; /* CCK_* or PBCC_* */ - u8 tx_mgt_frame_rate; - u8 tx_mgt_frame_mod; -} __packed; - -/* STA MAC */ -struct acx_dot11_station_id { - struct acx_header header; - - u8 mac[ETH_ALEN]; - u8 pad[2]; -} __packed; - -struct acx_feature_config { - struct acx_header header; - - u32 options; - u32 data_flow_options; -} __packed; - -struct acx_current_tx_power { - struct acx_header header; - - u8 current_tx_power; - u8 padding[3]; -} __packed; - -struct acx_dot11_default_key { - struct acx_header header; - - u8 id; - u8 pad[3]; -} __packed; - -struct acx_tsf_info { - struct acx_header header; - - u32 current_tsf_msb; - u32 current_tsf_lsb; - u32 last_TBTT_msb; - u32 last_TBTT_lsb; - u8 last_dtim_count; - u8 pad[3]; -} __packed; - -enum acx_wake_up_event { - WAKE_UP_EVENT_BEACON_BITMAP = 0x01, /* Wake on every Beacon*/ - WAKE_UP_EVENT_DTIM_BITMAP = 0x02, /* Wake on every DTIM*/ - WAKE_UP_EVENT_N_DTIM_BITMAP = 0x04, /* Wake on every Nth DTIM */ - WAKE_UP_EVENT_N_BEACONS_BITMAP = 0x08, /* Wake on every Nth Beacon */ - WAKE_UP_EVENT_BITS_MASK = 0x0F -}; - -struct acx_wake_up_condition { - struct acx_header header; - - u8 wake_up_event; /* Only one bit can be set */ - u8 listen_interval; - u8 pad[2]; -} __packed; - -struct acx_aid { - struct acx_header header; - - /* - * To be set when associated with an AP. - */ - u16 aid; - u8 pad[2]; -} __packed; - -enum acx_preamble_type { - ACX_PREAMBLE_LONG = 0, - ACX_PREAMBLE_SHORT = 1 -}; - -struct acx_preamble { - struct acx_header header; - - /* - * When set, the WiLink transmits the frames with a short preamble and - * when cleared, the WiLink transmits the frames with a long preamble. - */ - u8 preamble; - u8 padding[3]; -} __packed; - -enum acx_ctsprotect_type { - CTSPROTECT_DISABLE = 0, - CTSPROTECT_ENABLE = 1 -}; - -struct acx_ctsprotect { - struct acx_header header; - u8 ctsprotect; - u8 padding[3]; -} __packed; - -struct acx_tx_statistics { - u32 internal_desc_overflow; -} __packed; - -struct acx_rx_statistics { - u32 out_of_mem; - u32 hdr_overflow; - u32 hw_stuck; - u32 dropped; - u32 fcs_err; - u32 xfr_hint_trig; - u32 path_reset; - u32 reset_counter; -} __packed; - -struct acx_dma_statistics { - u32 rx_requested; - u32 rx_errors; - u32 tx_requested; - u32 tx_errors; -} __packed; - -struct acx_isr_statistics { - /* host command complete */ - u32 cmd_cmplt; - - /* fiqisr() */ - u32 fiqs; - - /* (INT_STS_ND & INT_TRIG_RX_HEADER) */ - u32 rx_headers; - - /* (INT_STS_ND & INT_TRIG_RX_CMPLT) */ - u32 rx_completes; - - /* (INT_STS_ND & INT_TRIG_NO_RX_BUF) */ - u32 rx_mem_overflow; - - /* (INT_STS_ND & INT_TRIG_S_RX_RDY) */ - u32 rx_rdys; - - /* irqisr() */ - u32 irqs; - - /* (INT_STS_ND & INT_TRIG_TX_PROC) */ - u32 tx_procs; - - /* (INT_STS_ND & INT_TRIG_DECRYPT_DONE) */ - u32 decrypt_done; - - /* (INT_STS_ND & INT_TRIG_DMA0) */ - u32 dma0_done; - - /* (INT_STS_ND & INT_TRIG_DMA1) */ - u32 dma1_done; - - /* (INT_STS_ND & INT_TRIG_TX_EXC_CMPLT) */ - u32 tx_exch_complete; - - /* (INT_STS_ND & INT_TRIG_COMMAND) */ - u32 commands; - - /* (INT_STS_ND & INT_TRIG_RX_PROC) */ - u32 rx_procs; - - /* (INT_STS_ND & INT_TRIG_PM_802) */ - u32 hw_pm_mode_changes; - - /* (INT_STS_ND & INT_TRIG_ACKNOWLEDGE) */ - u32 host_acknowledges; - - /* (INT_STS_ND & INT_TRIG_PM_PCI) */ - u32 pci_pm; - - /* (INT_STS_ND & INT_TRIG_ACM_WAKEUP) */ - u32 wakeups; - - /* (INT_STS_ND & INT_TRIG_LOW_RSSI) */ - u32 low_rssi; -} __packed; - -struct acx_wep_statistics { - /* WEP address keys configured */ - u32 addr_key_count; - - /* default keys configured */ - u32 default_key_count; - - u32 reserved; - - /* number of times that WEP key not found on lookup */ - u32 key_not_found; - - /* number of times that WEP key decryption failed */ - u32 decrypt_fail; - - /* WEP packets decrypted */ - u32 packets; - - /* WEP decrypt interrupts */ - u32 interrupt; -} __packed; - -#define ACX_MISSED_BEACONS_SPREAD 10 - -struct acx_pwr_statistics { - /* the amount of enters into power save mode (both PD & ELP) */ - u32 ps_enter; - - /* the amount of enters into ELP mode */ - u32 elp_enter; - - /* the amount of missing beacon interrupts to the host */ - u32 missing_bcns; - - /* the amount of wake on host-access times */ - u32 wake_on_host; - - /* the amount of wake on timer-expire */ - u32 wake_on_timer_exp; - - /* the number of packets that were transmitted with PS bit set */ - u32 tx_with_ps; - - /* the number of packets that were transmitted with PS bit clear */ - u32 tx_without_ps; - - /* the number of received beacons */ - u32 rcvd_beacons; - - /* the number of entering into PowerOn (power save off) */ - u32 power_save_off; - - /* the number of entries into power save mode */ - u16 enable_ps; - - /* - * the number of exits from power save, not including failed PS - * transitions - */ - u16 disable_ps; - - /* - * the number of times the TSF counter was adjusted because - * of drift - */ - u32 fix_tsf_ps; - - /* Gives statistics about the spread continuous missed beacons. - * The 16 LSB are dedicated for the PS mode. - * The 16 MSB are dedicated for the PS mode. - * cont_miss_bcns_spread[0] - single missed beacon. - * cont_miss_bcns_spread[1] - two continuous missed beacons. - * cont_miss_bcns_spread[2] - three continuous missed beacons. - * ... - * cont_miss_bcns_spread[9] - ten and more continuous missed beacons. - */ - u32 cont_miss_bcns_spread[ACX_MISSED_BEACONS_SPREAD]; - - /* the number of beacons in awake mode */ - u32 rcvd_awake_beacons; -} __packed; - -struct acx_mic_statistics { - u32 rx_pkts; - u32 calc_failure; -} __packed; - -struct acx_aes_statistics { - u32 encrypt_fail; - u32 decrypt_fail; - u32 encrypt_packets; - u32 decrypt_packets; - u32 encrypt_interrupt; - u32 decrypt_interrupt; -} __packed; - -struct acx_event_statistics { - u32 heart_beat; - u32 calibration; - u32 rx_mismatch; - u32 rx_mem_empty; - u32 rx_pool; - u32 oom_late; - u32 phy_transmit_error; - u32 tx_stuck; -} __packed; - -struct acx_ps_statistics { - u32 pspoll_timeouts; - u32 upsd_timeouts; - u32 upsd_max_sptime; - u32 upsd_max_apturn; - u32 pspoll_max_apturn; - u32 pspoll_utilization; - u32 upsd_utilization; -} __packed; - -struct acx_rxpipe_statistics { - u32 rx_prep_beacon_drop; - u32 descr_host_int_trig_rx_data; - u32 beacon_buffer_thres_host_int_trig_rx_data; - u32 missed_beacon_host_int_trig_rx_data; - u32 tx_xfr_host_int_trig_rx_data; -} __packed; - -struct acx_statistics { - struct acx_header header; - - struct acx_tx_statistics tx; - struct acx_rx_statistics rx; - struct acx_dma_statistics dma; - struct acx_isr_statistics isr; - struct acx_wep_statistics wep; - struct acx_pwr_statistics pwr; - struct acx_aes_statistics aes; - struct acx_mic_statistics mic; - struct acx_event_statistics event; - struct acx_ps_statistics ps; - struct acx_rxpipe_statistics rxpipe; -} __packed; - -#define ACX_MAX_RATE_CLASSES 8 -#define ACX_RATE_MASK_UNSPECIFIED 0 -#define ACX_RATE_RETRY_LIMIT 10 - -struct acx_rate_class { - u32 enabled_rates; - u8 short_retry_limit; - u8 long_retry_limit; - u8 aflags; - u8 reserved; -} __packed; - -struct acx_rate_policy { - struct acx_header header; - - u32 rate_class_cnt; - struct acx_rate_class rate_class[ACX_MAX_RATE_CLASSES]; -} __packed; - -struct wl1251_acx_memory { - __le16 num_stations; /* number of STAs to be supported. */ - u16 reserved_1; - - /* - * Nmber of memory buffers for the RX mem pool. - * The actual number may be less if there are - * not enough blocks left for the minimum num - * of TX ones. - */ - u8 rx_mem_block_num; - u8 reserved_2; - u8 num_tx_queues; /* From 1 to 16 */ - u8 host_if_options; /* HOST_IF* */ - u8 tx_min_mem_block_num; - u8 num_ssid_profiles; - __le16 debug_buffer_size; -} __packed; - - -#define ACX_RX_DESC_MIN 1 -#define ACX_RX_DESC_MAX 127 -#define ACX_RX_DESC_DEF 32 -struct wl1251_acx_rx_queue_config { - u8 num_descs; - u8 pad; - u8 type; - u8 priority; - __le32 dma_address; -} __packed; - -#define ACX_TX_DESC_MIN 1 -#define ACX_TX_DESC_MAX 127 -#define ACX_TX_DESC_DEF 16 -struct wl1251_acx_tx_queue_config { - u8 num_descs; - u8 pad[2]; - u8 attributes; -} __packed; - -#define MAX_TX_QUEUE_CONFIGS 5 -#define MAX_TX_QUEUES 4 -struct wl1251_acx_config_memory { - struct acx_header header; - - struct wl1251_acx_memory mem_config; - struct wl1251_acx_rx_queue_config rx_queue_config; - struct wl1251_acx_tx_queue_config tx_queue_config[MAX_TX_QUEUE_CONFIGS]; -} __packed; - -struct wl1251_acx_mem_map { - struct acx_header header; - - void *code_start; - void *code_end; - - void *wep_defkey_start; - void *wep_defkey_end; - - void *sta_table_start; - void *sta_table_end; - - void *packet_template_start; - void *packet_template_end; - - void *queue_memory_start; - void *queue_memory_end; - - void *packet_memory_pool_start; - void *packet_memory_pool_end; - - void *debug_buffer1_start; - void *debug_buffer1_end; - - void *debug_buffer2_start; - void *debug_buffer2_end; - - /* Number of blocks FW allocated for TX packets */ - u32 num_tx_mem_blocks; - - /* Number of blocks FW allocated for RX packets */ - u32 num_rx_mem_blocks; -} __packed; - - -struct wl1251_acx_wr_tbtt_and_dtim { - - struct acx_header header; - - /* Time in TUs between two consecutive beacons */ - u16 tbtt; - - /* - * DTIM period - * For BSS: Number of TBTTs in a DTIM period (range: 1-10) - * For IBSS: value shall be set to 1 - */ - u8 dtim; - u8 padding; -} __packed; - -struct wl1251_acx_ac_cfg { - struct acx_header header; - - /* - * Access Category - The TX queue's access category - * (refer to AccessCategory_enum) - */ - u8 ac; - - /* - * The contention window minimum size (in slots) for - * the access class. - */ - u8 cw_min; - - /* - * The contention window maximum size (in slots) for - * the access class. - */ - u16 cw_max; - - /* The AIF value (in slots) for the access class. */ - u8 aifsn; - - u8 reserved; - - /* The TX Op Limit (in microseconds) for the access class. */ - u16 txop_limit; -} __packed; - - -enum wl1251_acx_channel_type { - CHANNEL_TYPE_DCF = 0, - CHANNEL_TYPE_EDCF = 1, - CHANNEL_TYPE_HCCA = 2, -}; - -enum wl1251_acx_ps_scheme { - /* regular ps: simple sending of packets */ - WL1251_ACX_PS_SCHEME_LEGACY = 0, - - /* sending a packet triggers a unscheduled apsd downstream */ - WL1251_ACX_PS_SCHEME_UPSD_TRIGGER = 1, - - /* a pspoll packet will be sent before every data packet */ - WL1251_ACX_PS_SCHEME_LEGACY_PSPOLL = 2, - - /* scheduled apsd mode */ - WL1251_ACX_PS_SCHEME_SAPSD = 3, -}; - -enum wl1251_acx_ack_policy { - WL1251_ACX_ACK_POLICY_LEGACY = 0, - WL1251_ACX_ACK_POLICY_NO_ACK = 1, - WL1251_ACX_ACK_POLICY_BLOCK = 2, -}; - -struct wl1251_acx_tid_cfg { - struct acx_header header; - - /* tx queue id number (0-7) */ - u8 queue; - - /* channel access type for the queue, enum wl1251_acx_channel_type */ - u8 type; - - /* EDCA: ac index (0-3), HCCA: traffic stream id (8-15) */ - u8 tsid; - - /* ps scheme of the specified queue, enum wl1251_acx_ps_scheme */ - u8 ps_scheme; - - /* the tx queue ack policy, enum wl1251_acx_ack_policy */ - u8 ack_policy; - - u8 padding[3]; - - /* not supported */ - u32 apsdconf[2]; -} __packed; - -/************************************************************************* - - Host Interrupt Register (WiLink -> Host) - -**************************************************************************/ - -/* RX packet is ready in Xfer buffer #0 */ -#define WL1251_ACX_INTR_RX0_DATA BIT(0) - -/* TX result(s) are in the TX complete buffer */ -#define WL1251_ACX_INTR_TX_RESULT BIT(1) - -/* OBSOLETE */ -#define WL1251_ACX_INTR_TX_XFR BIT(2) - -/* RX packet is ready in Xfer buffer #1 */ -#define WL1251_ACX_INTR_RX1_DATA BIT(3) - -/* Event was entered to Event MBOX #A */ -#define WL1251_ACX_INTR_EVENT_A BIT(4) - -/* Event was entered to Event MBOX #B */ -#define WL1251_ACX_INTR_EVENT_B BIT(5) - -/* OBSOLETE */ -#define WL1251_ACX_INTR_WAKE_ON_HOST BIT(6) - -/* Trace meassge on MBOX #A */ -#define WL1251_ACX_INTR_TRACE_A BIT(7) - -/* Trace meassge on MBOX #B */ -#define WL1251_ACX_INTR_TRACE_B BIT(8) - -/* Command processing completion */ -#define WL1251_ACX_INTR_CMD_COMPLETE BIT(9) - -/* Init sequence is done */ -#define WL1251_ACX_INTR_INIT_COMPLETE BIT(14) - -#define WL1251_ACX_INTR_ALL 0xFFFFFFFF - -enum { - ACX_WAKE_UP_CONDITIONS = 0x0002, - ACX_MEM_CFG = 0x0003, - ACX_SLOT = 0x0004, - ACX_QUEUE_HEAD = 0x0005, /* for MASTER mode only */ - ACX_AC_CFG = 0x0007, - ACX_MEM_MAP = 0x0008, - ACX_AID = 0x000A, - ACX_RADIO_PARAM = 0x000B, /* Not used */ - ACX_CFG = 0x000C, /* Not used */ - ACX_FW_REV = 0x000D, - ACX_MEDIUM_USAGE = 0x000F, - ACX_RX_CFG = 0x0010, - ACX_TX_QUEUE_CFG = 0x0011, /* FIXME: only used by wl1251 */ - ACX_BSS_IN_PS = 0x0012, /* for AP only */ - ACX_STATISTICS = 0x0013, /* Debug API */ - ACX_FEATURE_CFG = 0x0015, - ACX_MISC_CFG = 0x0017, /* Not used */ - ACX_TID_CFG = 0x001A, - ACX_BEACON_FILTER_OPT = 0x001F, - ACX_LOW_RSSI = 0x0020, - ACX_NOISE_HIST = 0x0021, - ACX_HDK_VERSION = 0x0022, /* ??? */ - ACX_PD_THRESHOLD = 0x0023, - ACX_DATA_PATH_PARAMS = 0x0024, /* WO */ - ACX_DATA_PATH_RESP_PARAMS = 0x0024, /* RO */ - ACX_CCA_THRESHOLD = 0x0025, - ACX_EVENT_MBOX_MASK = 0x0026, -#ifdef FW_RUNNING_AS_AP - ACX_DTIM_PERIOD = 0x0027, /* for AP only */ -#else - ACX_WR_TBTT_AND_DTIM = 0x0027, /* STA only */ -#endif - ACX_ACI_OPTION_CFG = 0x0029, /* OBSOLETE (for 1251)*/ - ACX_GPIO_CFG = 0x002A, /* Not used */ - ACX_GPIO_SET = 0x002B, /* Not used */ - ACX_PM_CFG = 0x002C, /* To Be Documented */ - ACX_CONN_MONIT_PARAMS = 0x002D, - ACX_AVERAGE_RSSI = 0x002E, /* Not used */ - ACX_CONS_TX_FAILURE = 0x002F, - ACX_BCN_DTIM_OPTIONS = 0x0031, - ACX_SG_ENABLE = 0x0032, - ACX_SG_CFG = 0x0033, - ACX_ANTENNA_DIVERSITY_CFG = 0x0035, /* To Be Documented */ - ACX_LOW_SNR = 0x0037, /* To Be Documented */ - ACX_BEACON_FILTER_TABLE = 0x0038, - ACX_ARP_IP_FILTER = 0x0039, - ACX_ROAMING_STATISTICS_TBL = 0x003B, - ACX_RATE_POLICY = 0x003D, - ACX_CTS_PROTECTION = 0x003E, - ACX_SLEEP_AUTH = 0x003F, - ACX_PREAMBLE_TYPE = 0x0040, - ACX_ERROR_CNT = 0x0041, - ACX_FW_GEN_FRAME_RATES = 0x0042, - ACX_IBSS_FILTER = 0x0044, - ACX_SERVICE_PERIOD_TIMEOUT = 0x0045, - ACX_TSF_INFO = 0x0046, - ACX_CONFIG_PS_WMM = 0x0049, - ACX_ENABLE_RX_DATA_FILTER = 0x004A, - ACX_SET_RX_DATA_FILTER = 0x004B, - ACX_GET_DATA_FILTER_STATISTICS = 0x004C, - ACX_POWER_LEVEL_TABLE = 0x004D, - ACX_BET_ENABLE = 0x0050, - DOT11_STATION_ID = 0x1001, - DOT11_RX_MSDU_LIFE_TIME = 0x1004, - DOT11_CUR_TX_PWR = 0x100D, - DOT11_DEFAULT_KEY = 0x1010, - DOT11_RX_DOT11_MODE = 0x1012, - DOT11_RTS_THRESHOLD = 0x1013, - DOT11_GROUP_ADDRESS_TBL = 0x1014, - - MAX_DOT11_IE = DOT11_GROUP_ADDRESS_TBL, - - MAX_IE = 0xFFFF -}; - - -int wl1251_acx_frame_rates(struct wl1251 *wl, u8 ctrl_rate, u8 ctrl_mod, - u8 mgt_rate, u8 mgt_mod); -int wl1251_acx_station_id(struct wl1251 *wl); -int wl1251_acx_default_key(struct wl1251 *wl, u8 key_id); -int wl1251_acx_wake_up_conditions(struct wl1251 *wl, u8 wake_up_event, - u8 listen_interval); -int wl1251_acx_sleep_auth(struct wl1251 *wl, u8 sleep_auth); -int wl1251_acx_fw_version(struct wl1251 *wl, char *buf, size_t len); -int wl1251_acx_tx_power(struct wl1251 *wl, int power); -int wl1251_acx_feature_cfg(struct wl1251 *wl); -int wl1251_acx_mem_map(struct wl1251 *wl, - struct acx_header *mem_map, size_t len); -int wl1251_acx_data_path_params(struct wl1251 *wl, - struct acx_data_path_params_resp *data_path); -int wl1251_acx_rx_msdu_life_time(struct wl1251 *wl, u32 life_time); -int wl1251_acx_rx_config(struct wl1251 *wl, u32 config, u32 filter); -int wl1251_acx_pd_threshold(struct wl1251 *wl); -int wl1251_acx_slot(struct wl1251 *wl, enum acx_slot_type slot_time); -int wl1251_acx_group_address_tbl(struct wl1251 *wl); -int wl1251_acx_service_period_timeout(struct wl1251 *wl); -int wl1251_acx_rts_threshold(struct wl1251 *wl, u16 rts_threshold); -int wl1251_acx_beacon_filter_opt(struct wl1251 *wl, bool enable_filter); -int wl1251_acx_beacon_filter_table(struct wl1251 *wl); -int wl1251_acx_conn_monit_params(struct wl1251 *wl); -int wl1251_acx_sg_enable(struct wl1251 *wl); -int wl1251_acx_sg_cfg(struct wl1251 *wl); -int wl1251_acx_cca_threshold(struct wl1251 *wl); -int wl1251_acx_bcn_dtim_options(struct wl1251 *wl); -int wl1251_acx_aid(struct wl1251 *wl, u16 aid); -int wl1251_acx_event_mbox_mask(struct wl1251 *wl, u32 event_mask); -int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type preamble); -int wl1251_acx_cts_protect(struct wl1251 *wl, - enum acx_ctsprotect_type ctsprotect); -int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats); -int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime); -int wl1251_acx_rate_policies(struct wl1251 *wl); -int wl1251_acx_mem_cfg(struct wl1251 *wl); -int wl1251_acx_wr_tbtt_and_dtim(struct wl1251 *wl, u16 tbtt, u8 dtim); -int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max, - u8 aifs, u16 txop); -int wl1251_acx_tid_cfg(struct wl1251 *wl, u8 queue, - enum wl1251_acx_channel_type type, - u8 tsid, enum wl1251_acx_ps_scheme ps_scheme, - enum wl1251_acx_ack_policy ack_policy); - -#endif /* __WL1251_ACX_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.c b/drivers/net/wireless/wl12xx/wl1251_boot.c deleted file mode 100644 index 468b47b..0000000 --- a/drivers/net/wireless/wl12xx/wl1251_boot.c +++ /dev/null @@ -1,557 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (C) 2008 Nokia Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include -#include - -#include "wl1251_reg.h" -#include "wl1251_boot.h" -#include "wl1251_io.h" -#include "wl1251_spi.h" -#include "wl1251_event.h" -#include "wl1251_acx.h" - -void wl1251_boot_target_enable_interrupts(struct wl1251 *wl) -{ - wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); - wl1251_reg_write32(wl, HI_CFG, HI_CFG_DEF_VAL); -} - -int wl1251_boot_soft_reset(struct wl1251 *wl) -{ - unsigned long timeout; - u32 boot_data; - - /* perform soft reset */ - wl1251_reg_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT); - - /* SOFT_RESET is self clearing */ - timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME); - while (1) { - boot_data = wl1251_reg_read32(wl, ACX_REG_SLV_SOFT_RESET); - wl1251_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data); - if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0) - break; - - if (time_after(jiffies, timeout)) { - /* 1.2 check pWhalBus->uSelfClearTime if the - * timeout was reached */ - wl1251_error("soft reset timeout"); - return -1; - } - - udelay(SOFT_RESET_STALL_TIME); - } - - /* disable Rx/Tx */ - wl1251_reg_write32(wl, ENABLE, 0x0); - - /* disable auto calibration on start*/ - wl1251_reg_write32(wl, SPARE_A2, 0xffff); - - return 0; -} - -int wl1251_boot_init_seq(struct wl1251 *wl) -{ - u32 scr_pad6, init_data, tmp, elp_cmd, ref_freq; - - /* - * col #1: INTEGER_DIVIDER - * col #2: FRACTIONAL_DIVIDER - * col #3: ATTN_BB - * col #4: ALPHA_BB - * col #5: STOP_TIME_BB - * col #6: BB_PLL_LOOP_FILTER - */ - static const u32 LUT[REF_FREQ_NUM][LUT_PARAM_NUM] = { - - { 83, 87381, 0xB, 5, 0xF00, 3}, /* REF_FREQ_19_2*/ - { 61, 141154, 0xB, 5, 0x1450, 2}, /* REF_FREQ_26_0*/ - { 41, 174763, 0xC, 6, 0x2D00, 1}, /* REF_FREQ_38_4*/ - { 40, 0, 0xC, 6, 0x2EE0, 1}, /* REF_FREQ_40_0*/ - { 47, 162280, 0xC, 6, 0x2760, 1} /* REF_FREQ_33_6 */ - }; - - /* read NVS params */ - scr_pad6 = wl1251_reg_read32(wl, SCR_PAD6); - wl1251_debug(DEBUG_BOOT, "scr_pad6 0x%x", scr_pad6); - - /* read ELP_CMD */ - elp_cmd = wl1251_reg_read32(wl, ELP_CMD); - wl1251_debug(DEBUG_BOOT, "elp_cmd 0x%x", elp_cmd); - - /* set the BB calibration time to be 300 usec (PLL_CAL_TIME) */ - ref_freq = scr_pad6 & 0x000000FF; - wl1251_debug(DEBUG_BOOT, "ref_freq 0x%x", ref_freq); - - wl1251_reg_write32(wl, PLL_CAL_TIME, 0x9); - - /* - * PG 1.2: set the clock buffer time to be 210 usec (CLK_BUF_TIME) - */ - wl1251_reg_write32(wl, CLK_BUF_TIME, 0x6); - - /* - * set the clock detect feature to work in the restart wu procedure - * (ELP_CFG_MODE[14]) and Select the clock source type - * (ELP_CFG_MODE[13:12]) - */ - tmp = ((scr_pad6 & 0x0000FF00) << 4) | 0x00004000; - wl1251_reg_write32(wl, ELP_CFG_MODE, tmp); - - /* PG 1.2: enable the BB PLL fix. Enable the PLL_LIMP_CLK_EN_CMD */ - elp_cmd |= 0x00000040; - wl1251_reg_write32(wl, ELP_CMD, elp_cmd); - - /* PG 1.2: Set the BB PLL stable time to be 1000usec - * (PLL_STABLE_TIME) */ - wl1251_reg_write32(wl, CFG_PLL_SYNC_CNT, 0x20); - - /* PG 1.2: read clock request time */ - init_data = wl1251_reg_read32(wl, CLK_REQ_TIME); - - /* - * PG 1.2: set the clock request time to be ref_clk_settling_time - - * 1ms = 4ms - */ - if (init_data > 0x21) - tmp = init_data - 0x21; - else - tmp = 0; - wl1251_reg_write32(wl, CLK_REQ_TIME, tmp); - - /* set BB PLL configurations in RF AFE */ - wl1251_reg_write32(wl, 0x003058cc, 0x4B5); - - /* set RF_AFE_REG_5 */ - wl1251_reg_write32(wl, 0x003058d4, 0x50); - - /* set RF_AFE_CTRL_REG_2 */ - wl1251_reg_write32(wl, 0x00305948, 0x11c001); - - /* - * change RF PLL and BB PLL divider for VCO clock and adjust VCO - * bais current(RF_AFE_REG_13) - */ - wl1251_reg_write32(wl, 0x003058f4, 0x1e); - - /* set BB PLL configurations */ - tmp = LUT[ref_freq][LUT_PARAM_INTEGER_DIVIDER] | 0x00017000; - wl1251_reg_write32(wl, 0x00305840, tmp); - - /* set fractional divider according to Appendix C-BB PLL - * Calculations - */ - tmp = LUT[ref_freq][LUT_PARAM_FRACTIONAL_DIVIDER]; - wl1251_reg_write32(wl, 0x00305844, tmp); - - /* set the initial data for the sigma delta */ - wl1251_reg_write32(wl, 0x00305848, 0x3039); - - /* - * set the accumulator attenuation value, calibration loop1 - * (alpha), calibration loop2 (beta), calibration loop3 (gamma) and - * the VCO gain - */ - tmp = (LUT[ref_freq][LUT_PARAM_ATTN_BB] << 16) | - (LUT[ref_freq][LUT_PARAM_ALPHA_BB] << 12) | 0x1; - wl1251_reg_write32(wl, 0x00305854, tmp); - - /* - * set the calibration stop time after holdoff time expires and set - * settling time HOLD_OFF_TIME_BB - */ - tmp = LUT[ref_freq][LUT_PARAM_STOP_TIME_BB] | 0x000A0000; - wl1251_reg_write32(wl, 0x00305858, tmp); - - /* - * set BB PLL Loop filter capacitor3- BB_C3[2:0] and set BB PLL - * constant leakage current to linearize PFD to 0uA - - * BB_ILOOPF[7:3] - */ - tmp = LUT[ref_freq][LUT_PARAM_BB_PLL_LOOP_FILTER] | 0x00000030; - wl1251_reg_write32(wl, 0x003058f8, tmp); - - /* - * set regulator output voltage for n divider to - * 1.35-BB_REFDIV[1:0], set charge pump current- BB_CPGAIN[4:2], - * set BB PLL Loop filter capacitor2- BB_C2[7:5], set gain of BB - * PLL auto-call to normal mode- BB_CALGAIN_3DB[8] - */ - wl1251_reg_write32(wl, 0x003058f0, 0x29); - - /* enable restart wakeup sequence (ELP_CMD[0]) */ - wl1251_reg_write32(wl, ELP_CMD, elp_cmd | 0x1); - - /* restart sequence completed */ - udelay(2000); - - return 0; -} - -static void wl1251_boot_set_ecpu_ctrl(struct wl1251 *wl, u32 flag) -{ - u32 cpu_ctrl; - - /* 10.5.0 run the firmware (I) */ - cpu_ctrl = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL); - - /* 10.5.1 run the firmware (II) */ - cpu_ctrl &= ~flag; - wl1251_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); -} - -int wl1251_boot_run_firmware(struct wl1251 *wl) -{ - int loop, ret; - u32 chip_id, acx_intr; - - wl1251_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); - - chip_id = wl1251_reg_read32(wl, CHIP_ID_B); - - wl1251_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); - - if (chip_id != wl->chip_id) { - wl1251_error("chip id doesn't match after firmware boot"); - return -EIO; - } - - /* wait for init to complete */ - loop = 0; - while (loop++ < INIT_LOOP) { - udelay(INIT_LOOP_DELAY); - acx_intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); - - if (acx_intr == 0xffffffff) { - wl1251_error("error reading hardware complete " - "init indication"); - return -EIO; - } - /* check that ACX_INTR_INIT_COMPLETE is enabled */ - else if (acx_intr & WL1251_ACX_INTR_INIT_COMPLETE) { - wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK, - WL1251_ACX_INTR_INIT_COMPLETE); - break; - } - } - - if (loop > INIT_LOOP) { - wl1251_error("timeout waiting for the hardware to " - "complete initialization"); - return -EIO; - } - - /* get hardware config command mail box */ - wl->cmd_box_addr = wl1251_reg_read32(wl, REG_COMMAND_MAILBOX_PTR); - - /* get hardware config event mail box */ - wl->event_box_addr = wl1251_reg_read32(wl, REG_EVENT_MAILBOX_PTR); - - /* set the working partition to its "running" mode offset */ - wl1251_set_partition(wl, WL1251_PART_WORK_MEM_START, - WL1251_PART_WORK_MEM_SIZE, - WL1251_PART_WORK_REG_START, - WL1251_PART_WORK_REG_SIZE); - - wl1251_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x", - wl->cmd_box_addr, wl->event_box_addr); - - wl1251_acx_fw_version(wl, wl->fw_ver, sizeof(wl->fw_ver)); - - /* - * in case of full asynchronous mode the firmware event must be - * ready to receive event from the command mailbox - */ - - /* enable gpio interrupts */ - wl1251_enable_interrupts(wl); - - /* Enable target's interrupts */ - wl->intr_mask = WL1251_ACX_INTR_RX0_DATA | - WL1251_ACX_INTR_RX1_DATA | - WL1251_ACX_INTR_TX_RESULT | - WL1251_ACX_INTR_EVENT_A | - WL1251_ACX_INTR_EVENT_B | - WL1251_ACX_INTR_INIT_COMPLETE; - wl1251_boot_target_enable_interrupts(wl); - - wl->event_mask = SCAN_COMPLETE_EVENT_ID | BSS_LOSE_EVENT_ID | - SYNCHRONIZATION_TIMEOUT_EVENT_ID | - ROAMING_TRIGGER_LOW_RSSI_EVENT_ID | - ROAMING_TRIGGER_REGAINED_RSSI_EVENT_ID | - REGAINED_BSS_EVENT_ID | BT_PTA_SENSE_EVENT_ID | - BT_PTA_PREDICTION_EVENT_ID | JOIN_EVENT_COMPLETE_ID; - - ret = wl1251_event_unmask(wl); - if (ret < 0) { - wl1251_error("EVENT mask setting failed"); - return ret; - } - - wl1251_event_mbox_config(wl); - - /* firmware startup completed */ - return 0; -} - -static int wl1251_boot_upload_firmware(struct wl1251 *wl) -{ - int addr, chunk_num, partition_limit; - size_t fw_data_len, len; - u8 *p, *buf; - - /* whal_FwCtrl_LoadFwImageSm() */ - - wl1251_debug(DEBUG_BOOT, "chip id before fw upload: 0x%x", - wl1251_reg_read32(wl, CHIP_ID_B)); - - /* 10.0 check firmware length and set partition */ - fw_data_len = (wl->fw[4] << 24) | (wl->fw[5] << 16) | - (wl->fw[6] << 8) | (wl->fw[7]); - - wl1251_debug(DEBUG_BOOT, "fw_data_len %zu chunk_size %d", fw_data_len, - CHUNK_SIZE); - - if ((fw_data_len % 4) != 0) { - wl1251_error("firmware length not multiple of four"); - return -EIO; - } - - buf = kmalloc(CHUNK_SIZE, GFP_KERNEL); - if (!buf) { - wl1251_error("allocation for firmware upload chunk failed"); - return -ENOMEM; - } - - wl1251_set_partition(wl, WL1251_PART_DOWN_MEM_START, - WL1251_PART_DOWN_MEM_SIZE, - WL1251_PART_DOWN_REG_START, - WL1251_PART_DOWN_REG_SIZE); - - /* 10.1 set partition limit and chunk num */ - chunk_num = 0; - partition_limit = WL1251_PART_DOWN_MEM_SIZE; - - while (chunk_num < fw_data_len / CHUNK_SIZE) { - /* 10.2 update partition, if needed */ - addr = WL1251_PART_DOWN_MEM_START + - (chunk_num + 2) * CHUNK_SIZE; - if (addr > partition_limit) { - addr = WL1251_PART_DOWN_MEM_START + - chunk_num * CHUNK_SIZE; - partition_limit = chunk_num * CHUNK_SIZE + - WL1251_PART_DOWN_MEM_SIZE; - wl1251_set_partition(wl, - addr, - WL1251_PART_DOWN_MEM_SIZE, - WL1251_PART_DOWN_REG_START, - WL1251_PART_DOWN_REG_SIZE); - } - - /* 10.3 upload the chunk */ - addr = WL1251_PART_DOWN_MEM_START + chunk_num * CHUNK_SIZE; - p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; - wl1251_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", - p, addr); - - /* need to copy the chunk for dma */ - len = CHUNK_SIZE; - memcpy(buf, p, len); - wl1251_mem_write(wl, addr, buf, len); - - chunk_num++; - } - - /* 10.4 upload the last chunk */ - addr = WL1251_PART_DOWN_MEM_START + chunk_num * CHUNK_SIZE; - p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; - - /* need to copy the chunk for dma */ - len = fw_data_len % CHUNK_SIZE; - memcpy(buf, p, len); - - wl1251_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x", - len, p, addr); - wl1251_mem_write(wl, addr, buf, len); - - kfree(buf); - - return 0; -} - -static int wl1251_boot_upload_nvs(struct wl1251 *wl) -{ - size_t nvs_len, nvs_bytes_written, burst_len; - int nvs_start, i; - u32 dest_addr, val; - u8 *nvs_ptr, *nvs; - - nvs = wl->nvs; - if (nvs == NULL) - return -ENODEV; - - nvs_ptr = nvs; - - nvs_len = wl->nvs_len; - nvs_start = wl->fw_len; - - /* - * Layout before the actual NVS tables: - * 1 byte : burst length. - * 2 bytes: destination address. - * n bytes: data to burst copy. - * - * This is ended by a 0 length, then the NVS tables. - */ - - while (nvs_ptr[0]) { - burst_len = nvs_ptr[0]; - dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8)); - - /* We move our pointer to the data */ - nvs_ptr += 3; - - for (i = 0; i < burst_len; i++) { - val = (nvs_ptr[0] | (nvs_ptr[1] << 8) - | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); - - wl1251_debug(DEBUG_BOOT, - "nvs burst write 0x%x: 0x%x", - dest_addr, val); - wl1251_mem_write32(wl, dest_addr, val); - - nvs_ptr += 4; - dest_addr += 4; - } - } - - /* - * We've reached the first zero length, the first NVS table - * is 7 bytes further. - */ - nvs_ptr += 7; - nvs_len -= nvs_ptr - nvs; - nvs_len = ALIGN(nvs_len, 4); - - /* Now we must set the partition correctly */ - wl1251_set_partition(wl, nvs_start, - WL1251_PART_DOWN_MEM_SIZE, - WL1251_PART_DOWN_REG_START, - WL1251_PART_DOWN_REG_SIZE); - - /* And finally we upload the NVS tables */ - nvs_bytes_written = 0; - while (nvs_bytes_written < nvs_len) { - val = (nvs_ptr[0] | (nvs_ptr[1] << 8) - | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); - - val = cpu_to_le32(val); - - wl1251_debug(DEBUG_BOOT, - "nvs write table 0x%x: 0x%x", - nvs_start, val); - wl1251_mem_write32(wl, nvs_start, val); - - nvs_ptr += 4; - nvs_bytes_written += 4; - nvs_start += 4; - } - - return 0; -} - -int wl1251_boot(struct wl1251 *wl) -{ - int ret = 0, minor_minor_e2_ver; - u32 tmp, boot_data; - - /* halt embedded ARM CPU while loading firmware */ - wl1251_reg_write32(wl, ACX_REG_ECPU_CONTROL, ECPU_CONTROL_HALT); - - ret = wl1251_boot_soft_reset(wl); - if (ret < 0) - goto out; - - /* 2. start processing NVS file */ - if (wl->use_eeprom) { - wl1251_reg_write32(wl, ACX_REG_EE_START, START_EEPROM_MGR); - /* Wait for EEPROM NVS burst read to complete */ - msleep(40); - wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, USE_EEPROM); - } else { - ret = wl1251_boot_upload_nvs(wl); - if (ret < 0) - goto out; - - /* write firmware's last address (ie. it's length) to - * ACX_EEPROMLESS_IND_REG */ - wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len); - } - - /* 6. read the EEPROM parameters */ - tmp = wl1251_reg_read32(wl, SCR_PAD2); - - /* 7. read bootdata */ - wl->boot_attr.radio_type = (tmp & 0x0000FF00) >> 8; - wl->boot_attr.major = (tmp & 0x00FF0000) >> 16; - tmp = wl1251_reg_read32(wl, SCR_PAD3); - - /* 8. check bootdata and call restart sequence */ - wl->boot_attr.minor = (tmp & 0x00FF0000) >> 16; - minor_minor_e2_ver = (tmp & 0xFF000000) >> 24; - - wl1251_debug(DEBUG_BOOT, "radioType 0x%x majorE2Ver 0x%x " - "minorE2Ver 0x%x minor_minor_e2_ver 0x%x", - wl->boot_attr.radio_type, wl->boot_attr.major, - wl->boot_attr.minor, minor_minor_e2_ver); - - ret = wl1251_boot_init_seq(wl); - if (ret < 0) - goto out; - - /* 9. NVS processing done */ - boot_data = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL); - - wl1251_debug(DEBUG_BOOT, "halt boot_data 0x%x", boot_data); - - /* 10. check that ECPU_CONTROL_HALT bits are set in - * pWhalBus->uBootData and start uploading firmware - */ - if ((boot_data & ECPU_CONTROL_HALT) == 0) { - wl1251_error("boot failed, ECPU_CONTROL_HALT not set"); - ret = -EIO; - goto out; - } - - ret = wl1251_boot_upload_firmware(wl); - if (ret < 0) - goto out; - - /* 10.5 start firmware */ - ret = wl1251_boot_run_firmware(wl); - if (ret < 0) - goto out; - -out: - return ret; -} diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.h b/drivers/net/wireless/wl12xx/wl1251_boot.h deleted file mode 100644 index 7661bc5..0000000 --- a/drivers/net/wireless/wl12xx/wl1251_boot.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (C) 2008 Nokia Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __BOOT_H__ -#define __BOOT_H__ - -#include "wl1251.h" - -int wl1251_boot_soft_reset(struct wl1251 *wl); -int wl1251_boot_init_seq(struct wl1251 *wl); -int wl1251_boot_run_firmware(struct wl1251 *wl); -void wl1251_boot_target_enable_interrupts(struct wl1251 *wl); -int wl1251_boot(struct wl1251 *wl); - -/* number of times we try to read the INIT interrupt */ -#define INIT_LOOP 20000 - -/* delay between retries */ -#define INIT_LOOP_DELAY 50 - -#endif diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c deleted file mode 100644 index 15fb68c..0000000 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.c +++ /dev/null @@ -1,496 +0,0 @@ -#include "wl1251_cmd.h" - -#include -#include -#include - -#include "wl1251.h" -#include "wl1251_reg.h" -#include "wl1251_io.h" -#include "wl1251_ps.h" -#include "wl1251_acx.h" - -/** - * send command to firmware - * - * @wl: wl struct - * @id: command id - * @buf: buffer containing the command, must work with dma - * @len: length of the buffer - */ -int wl1251_cmd_send(struct wl1251 *wl, u16 id, void *buf, size_t len) -{ - struct wl1251_cmd_header *cmd; - unsigned long timeout; - u32 intr; - int ret = 0; - - cmd = buf; - cmd->id = id; - cmd->status = 0; - - WARN_ON(len % 4 != 0); - - wl1251_mem_write(wl, wl->cmd_box_addr, buf, len); - - wl1251_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); - - timeout = jiffies + msecs_to_jiffies(WL1251_COMMAND_TIMEOUT); - - intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); - while (!(intr & WL1251_ACX_INTR_CMD_COMPLETE)) { - if (time_after(jiffies, timeout)) { - wl1251_error("command complete timeout"); - ret = -ETIMEDOUT; - goto out; - } - - msleep(1); - - intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); - } - - wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK, - WL1251_ACX_INTR_CMD_COMPLETE); - -out: - return ret; -} - -/** - * send test command to firmware - * - * @wl: wl struct - * @buf: buffer containing the command, with all headers, must work with dma - * @len: length of the buffer - * @answer: is answer needed - */ -int wl1251_cmd_test(struct wl1251 *wl, void *buf, size_t buf_len, u8 answer) -{ - int ret; - - wl1251_debug(DEBUG_CMD, "cmd test"); - - ret = wl1251_cmd_send(wl, CMD_TEST, buf, buf_len); - - if (ret < 0) { - wl1251_warning("TEST command failed"); - return ret; - } - - if (answer) { - struct wl1251_command *cmd_answer; - - /* - * The test command got in, we can read the answer. - * The answer would be a wl1251_command, where the - * parameter array contains the actual answer. - */ - wl1251_mem_read(wl, wl->cmd_box_addr, buf, buf_len); - - cmd_answer = buf; - - if (cmd_answer->header.status != CMD_STATUS_SUCCESS) - wl1251_error("TEST command answer error: %d", - cmd_answer->header.status); - } - - return 0; -} - -/** - * read acx from firmware - * - * @wl: wl struct - * @id: acx id - * @buf: buffer for the response, including all headers, must work with dma - * @len: lenght of buf - */ -int wl1251_cmd_interrogate(struct wl1251 *wl, u16 id, void *buf, size_t len) -{ - struct acx_header *acx = buf; - int ret; - - wl1251_debug(DEBUG_CMD, "cmd interrogate"); - - acx->id = id; - - /* payload length, does not include any headers */ - acx->len = len - sizeof(*acx); - - ret = wl1251_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx)); - if (ret < 0) { - wl1251_error("INTERROGATE command failed"); - goto out; - } - - /* the interrogate command got in, we can read the answer */ - wl1251_mem_read(wl, wl->cmd_box_addr, buf, len); - - acx = buf; - if (acx->cmd.status != CMD_STATUS_SUCCESS) - wl1251_error("INTERROGATE command error: %d", - acx->cmd.status); - -out: - return ret; -} - -/** - * write acx value to firmware - * - * @wl: wl struct - * @id: acx id - * @buf: buffer containing acx, including all headers, must work with dma - * @len: length of buf - */ -int wl1251_cmd_configure(struct wl1251 *wl, u16 id, void *buf, size_t len) -{ - struct acx_header *acx = buf; - int ret; - - wl1251_debug(DEBUG_CMD, "cmd configure"); - - acx->id = id; - - /* payload length, does not include any headers */ - acx->len = len - sizeof(*acx); - - ret = wl1251_cmd_send(wl, CMD_CONFIGURE, acx, len); - if (ret < 0) { - wl1251_warning("CONFIGURE command NOK"); - return ret; - } - - return 0; -} - -int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity, - void *bitmap, u16 bitmap_len, u8 bitmap_control) -{ - struct wl1251_cmd_vbm_update *vbm; - int ret; - - wl1251_debug(DEBUG_CMD, "cmd vbm"); - - vbm = kzalloc(sizeof(*vbm), GFP_KERNEL); - if (!vbm) { - ret = -ENOMEM; - goto out; - } - - /* Count and period will be filled by the target */ - vbm->tim.bitmap_ctrl = bitmap_control; - if (bitmap_len > PARTIAL_VBM_MAX) { - wl1251_warning("cmd vbm len is %d B, truncating to %d", - bitmap_len, PARTIAL_VBM_MAX); - bitmap_len = PARTIAL_VBM_MAX; - } - memcpy(vbm->tim.pvb_field, bitmap, bitmap_len); - vbm->tim.identity = identity; - vbm->tim.length = bitmap_len + 3; - - vbm->len = cpu_to_le16(bitmap_len + 5); - - ret = wl1251_cmd_send(wl, CMD_VBM, vbm, sizeof(*vbm)); - if (ret < 0) { - wl1251_error("VBM command failed"); - goto out; - } - -out: - kfree(vbm); - return ret; -} - -int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable) -{ - struct cmd_enabledisable_path *cmd; - int ret; - u16 cmd_rx, cmd_tx; - - wl1251_debug(DEBUG_CMD, "cmd data path"); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - cmd->channel = channel; - - if (enable) { - cmd_rx = CMD_ENABLE_RX; - cmd_tx = CMD_ENABLE_TX; - } else { - cmd_rx = CMD_DISABLE_RX; - cmd_tx = CMD_DISABLE_TX; - } - - ret = wl1251_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd)); - if (ret < 0) { - wl1251_error("rx %s cmd for channel %d failed", - enable ? "start" : "stop", channel); - goto out; - } - - wl1251_debug(DEBUG_BOOT, "rx %s cmd channel %d", - enable ? "start" : "stop", channel); - - ret = wl1251_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd)); - if (ret < 0) { - wl1251_error("tx %s cmd for channel %d failed", - enable ? "start" : "stop", channel); - return ret; - } - - wl1251_debug(DEBUG_BOOT, "tx %s cmd channel %d", - enable ? "start" : "stop", channel); - -out: - kfree(cmd); - return ret; -} - -int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel, - u16 beacon_interval, u8 dtim_interval) -{ - struct cmd_join *join; - int ret, i; - u8 *bssid; - - join = kzalloc(sizeof(*join), GFP_KERNEL); - if (!join) { - ret = -ENOMEM; - goto out; - } - - wl1251_debug(DEBUG_CMD, "cmd join%s ch %d %d/%d", - bss_type == BSS_TYPE_IBSS ? " ibss" : "", - channel, beacon_interval, dtim_interval); - - /* Reverse order BSSID */ - bssid = (u8 *) &join->bssid_lsb; - for (i = 0; i < ETH_ALEN; i++) - bssid[i] = wl->bssid[ETH_ALEN - i - 1]; - - join->rx_config_options = wl->rx_config; - join->rx_filter_options = wl->rx_filter; - - /* - * FIXME: disable temporarily all filters because after commit - * 9cef8737 "mac80211: fix managed mode BSSID handling" broke - * association. The filter logic needs to be implemented properly - * and once that is done, this hack can be removed. - */ - join->rx_config_options = 0; - join->rx_filter_options = WL1251_DEFAULT_RX_FILTER; - - join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS | - RATE_MASK_5_5MBPS | RATE_MASK_11MBPS; - - join->beacon_interval = beacon_interval; - join->dtim_interval = dtim_interval; - join->bss_type = bss_type; - join->channel = channel; - join->ctrl = JOIN_CMD_CTRL_TX_FLUSH; - - ret = wl1251_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join)); - if (ret < 0) { - wl1251_error("failed to initiate cmd join"); - goto out; - } - -out: - kfree(join); - return ret; -} - -int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode) -{ - struct wl1251_cmd_ps_params *ps_params = NULL; - int ret = 0; - - wl1251_debug(DEBUG_CMD, "cmd set ps mode"); - - ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL); - if (!ps_params) { - ret = -ENOMEM; - goto out; - } - - ps_params->ps_mode = ps_mode; - ps_params->send_null_data = 1; - ps_params->retries = 5; - ps_params->hang_over_period = 128; - ps_params->null_data_rate = 1; /* 1 Mbps */ - - ret = wl1251_cmd_send(wl, CMD_SET_PS_MODE, ps_params, - sizeof(*ps_params)); - if (ret < 0) { - wl1251_error("cmd set_ps_mode failed"); - goto out; - } - -out: - kfree(ps_params); - return ret; -} - -int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer, - size_t len) -{ - struct cmd_read_write_memory *cmd; - int ret = 0; - - wl1251_debug(DEBUG_CMD, "cmd read memory"); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - WARN_ON(len > MAX_READ_SIZE); - len = min_t(size_t, len, MAX_READ_SIZE); - - cmd->addr = addr; - cmd->size = len; - - ret = wl1251_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd)); - if (ret < 0) { - wl1251_error("read memory command failed: %d", ret); - goto out; - } - - /* the read command got in, we can now read the answer */ - wl1251_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd)); - - if (cmd->header.status != CMD_STATUS_SUCCESS) - wl1251_error("error in read command result: %d", - cmd->header.status); - - memcpy(answer, cmd->value, len); - -out: - kfree(cmd); - return ret; -} - -int wl1251_cmd_template_set(struct wl1251 *wl, u16 cmd_id, - void *buf, size_t buf_len) -{ - struct wl1251_cmd_packet_template *cmd; - size_t cmd_len; - int ret = 0; - - wl1251_debug(DEBUG_CMD, "cmd template %d", cmd_id); - - WARN_ON(buf_len > WL1251_MAX_TEMPLATE_SIZE); - buf_len = min_t(size_t, buf_len, WL1251_MAX_TEMPLATE_SIZE); - cmd_len = ALIGN(sizeof(*cmd) + buf_len, 4); - - cmd = kzalloc(cmd_len, GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - cmd->size = cpu_to_le16(buf_len); - - if (buf) - memcpy(cmd->data, buf, buf_len); - - ret = wl1251_cmd_send(wl, cmd_id, cmd, cmd_len); - if (ret < 0) { - wl1251_warning("cmd set_template failed: %d", ret); - goto out; - } - -out: - kfree(cmd); - return ret; -} - -int wl1251_cmd_scan(struct wl1251 *wl, u8 *ssid, size_t ssid_len, - struct ieee80211_channel *channels[], - unsigned int n_channels, unsigned int n_probes) -{ - struct wl1251_cmd_scan *cmd; - int i, ret = 0; - - wl1251_debug(DEBUG_CMD, "cmd scan"); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) - return -ENOMEM; - - cmd->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD); - cmd->params.rx_filter_options = cpu_to_le32(CFG_RX_PRSP_EN | - CFG_RX_MGMT_EN | - CFG_RX_BCN_EN); - cmd->params.scan_options = 0; - cmd->params.num_channels = n_channels; - cmd->params.num_probe_requests = n_probes; - cmd->params.tx_rate = cpu_to_le16(1 << 1); /* 2 Mbps */ - cmd->params.tid_trigger = 0; - - for (i = 0; i < n_channels; i++) { - cmd->channels[i].min_duration = - cpu_to_le32(WL1251_SCAN_MIN_DURATION); - cmd->channels[i].max_duration = - cpu_to_le32(WL1251_SCAN_MAX_DURATION); - memset(&cmd->channels[i].bssid_lsb, 0xff, 4); - memset(&cmd->channels[i].bssid_msb, 0xff, 2); - cmd->channels[i].early_termination = 0; - cmd->channels[i].tx_power_att = 0; - cmd->channels[i].channel = channels[i]->hw_value; - } - - cmd->params.ssid_len = ssid_len; - if (ssid) - memcpy(cmd->params.ssid, ssid, ssid_len); - - ret = wl1251_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd)); - if (ret < 0) { - wl1251_error("cmd scan failed: %d", ret); - goto out; - } - - wl1251_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd)); - - if (cmd->header.status != CMD_STATUS_SUCCESS) { - wl1251_error("cmd scan status wasn't success: %d", - cmd->header.status); - ret = -EIO; - goto out; - } - -out: - kfree(cmd); - return ret; -} - -int wl1251_cmd_trigger_scan_to(struct wl1251 *wl, u32 timeout) -{ - struct wl1251_cmd_trigger_scan_to *cmd; - int ret; - - wl1251_debug(DEBUG_CMD, "cmd trigger scan to"); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) - return -ENOMEM; - - cmd->timeout = timeout; - - ret = wl1251_cmd_send(wl, CMD_TRIGGER_SCAN_TO, cmd, sizeof(*cmd)); - if (ret < 0) { - wl1251_error("cmd trigger scan to failed: %d", ret); - goto out; - } - -out: - kfree(cmd); - return ret; -} diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.h b/drivers/net/wireless/wl12xx/wl1251_cmd.h deleted file mode 100644 index e5c74c6..0000000 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.h +++ /dev/null @@ -1,415 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL1251_CMD_H__ -#define __WL1251_CMD_H__ - -#include "wl1251.h" - -#include - -struct acx_header; - -int wl1251_cmd_send(struct wl1251 *wl, u16 type, void *buf, size_t buf_len); -int wl1251_cmd_test(struct wl1251 *wl, void *buf, size_t buf_len, u8 answer); -int wl1251_cmd_interrogate(struct wl1251 *wl, u16 id, void *buf, size_t len); -int wl1251_cmd_configure(struct wl1251 *wl, u16 id, void *buf, size_t len); -int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity, - void *bitmap, u16 bitmap_len, u8 bitmap_control); -int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable); -int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel, - u16 beacon_interval, u8 dtim_interval); -int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode); -int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer, - size_t len); -int wl1251_cmd_template_set(struct wl1251 *wl, u16 cmd_id, - void *buf, size_t buf_len); -int wl1251_cmd_scan(struct wl1251 *wl, u8 *ssid, size_t ssid_len, - struct ieee80211_channel *channels[], - unsigned int n_channels, unsigned int n_probes); -int wl1251_cmd_trigger_scan_to(struct wl1251 *wl, u32 timeout); - -/* unit ms */ -#define WL1251_COMMAND_TIMEOUT 2000 - -enum wl1251_commands { - CMD_RESET = 0, - CMD_INTERROGATE = 1, /*use this to read information elements*/ - CMD_CONFIGURE = 2, /*use this to write information elements*/ - CMD_ENABLE_RX = 3, - CMD_ENABLE_TX = 4, - CMD_DISABLE_RX = 5, - CMD_DISABLE_TX = 6, - CMD_SCAN = 8, - CMD_STOP_SCAN = 9, - CMD_VBM = 10, - CMD_START_JOIN = 11, - CMD_SET_KEYS = 12, - CMD_READ_MEMORY = 13, - CMD_WRITE_MEMORY = 14, - CMD_BEACON = 19, - CMD_PROBE_RESP = 20, - CMD_NULL_DATA = 21, - CMD_PROBE_REQ = 22, - CMD_TEST = 23, - CMD_RADIO_CALIBRATE = 25, /* OBSOLETE */ - CMD_ENABLE_RX_PATH = 27, /* OBSOLETE */ - CMD_NOISE_HIST = 28, - CMD_RX_RESET = 29, - CMD_PS_POLL = 30, - CMD_QOS_NULL_DATA = 31, - CMD_LNA_CONTROL = 32, - CMD_SET_BCN_MODE = 33, - CMD_MEASUREMENT = 34, - CMD_STOP_MEASUREMENT = 35, - CMD_DISCONNECT = 36, - CMD_SET_PS_MODE = 37, - CMD_CHANNEL_SWITCH = 38, - CMD_STOP_CHANNEL_SWICTH = 39, - CMD_AP_DISCOVERY = 40, - CMD_STOP_AP_DISCOVERY = 41, - CMD_SPS_SCAN = 42, - CMD_STOP_SPS_SCAN = 43, - CMD_HEALTH_CHECK = 45, - CMD_DEBUG = 46, - CMD_TRIGGER_SCAN_TO = 47, - - NUM_COMMANDS, - MAX_COMMAND_ID = 0xFFFF, -}; - -#define MAX_CMD_PARAMS 572 - -struct wl1251_cmd_header { - u16 id; - u16 status; - /* payload */ - u8 data[0]; -} __packed; - -struct wl1251_command { - struct wl1251_cmd_header header; - u8 parameters[MAX_CMD_PARAMS]; -} __packed; - -enum { - CMD_MAILBOX_IDLE = 0, - CMD_STATUS_SUCCESS = 1, - CMD_STATUS_UNKNOWN_CMD = 2, - CMD_STATUS_UNKNOWN_IE = 3, - CMD_STATUS_REJECT_MEAS_SG_ACTIVE = 11, - CMD_STATUS_RX_BUSY = 13, - CMD_STATUS_INVALID_PARAM = 14, - CMD_STATUS_TEMPLATE_TOO_LARGE = 15, - CMD_STATUS_OUT_OF_MEMORY = 16, - CMD_STATUS_STA_TABLE_FULL = 17, - CMD_STATUS_RADIO_ERROR = 18, - CMD_STATUS_WRONG_NESTING = 19, - CMD_STATUS_TIMEOUT = 21, /* Driver internal use.*/ - CMD_STATUS_FW_RESET = 22, /* Driver internal use.*/ - MAX_COMMAND_STATUS = 0xff -}; - - -/* - * CMD_READ_MEMORY - * - * The host issues this command to read the WiLink device memory/registers. - * - * Note: The Base Band address has special handling (16 bits registers and - * addresses). For more information, see the hardware specification. - */ -/* - * CMD_WRITE_MEMORY - * - * The host issues this command to write the WiLink device memory/registers. - * - * The Base Band address has special handling (16 bits registers and - * addresses). For more information, see the hardware specification. - */ -#define MAX_READ_SIZE 256 - -struct cmd_read_write_memory { - struct wl1251_cmd_header header; - - /* The address of the memory to read from or write to.*/ - u32 addr; - - /* The amount of data in bytes to read from or write to the WiLink - * device.*/ - u32 size; - - /* The actual value read from or written to the Wilink. The source - of this field is the Host in WRITE command or the Wilink in READ - command. */ - u8 value[MAX_READ_SIZE]; -} __packed; - -#define CMDMBOX_HEADER_LEN 4 -#define CMDMBOX_INFO_ELEM_HEADER_LEN 4 - -#define WL1251_SCAN_MIN_DURATION 30000 -#define WL1251_SCAN_MAX_DURATION 60000 - -#define WL1251_SCAN_NUM_PROBES 3 - -struct wl1251_scan_parameters { - __le32 rx_config_options; - __le32 rx_filter_options; - - /* - * Scan options: - * bit 0: When this bit is set, passive scan. - * bit 1: Band, when this bit is set we scan - * in the 5Ghz band. - * bit 2: voice mode, 0 for normal scan. - * bit 3: scan priority, 1 for high priority. - */ - __le16 scan_options; - - /* Number of channels to scan */ - u8 num_channels; - - /* Number opf probe requests to send, per channel */ - u8 num_probe_requests; - - /* Rate and modulation for probe requests */ - __le16 tx_rate; - - u8 tid_trigger; - u8 ssid_len; - u8 ssid[32]; - -} __packed; - -struct wl1251_scan_ch_parameters { - __le32 min_duration; /* in TU */ - __le32 max_duration; /* in TU */ - u32 bssid_lsb; - u16 bssid_msb; - - /* - * bits 0-3: Early termination count. - * bits 4-5: Early termination condition. - */ - u8 early_termination; - - u8 tx_power_att; - u8 channel; - u8 pad[3]; -} __packed; - -/* SCAN parameters */ -#define SCAN_MAX_NUM_OF_CHANNELS 16 - -struct wl1251_cmd_scan { - struct wl1251_cmd_header header; - - struct wl1251_scan_parameters params; - struct wl1251_scan_ch_parameters channels[SCAN_MAX_NUM_OF_CHANNELS]; -} __packed; - -enum { - BSS_TYPE_IBSS = 0, - BSS_TYPE_STA_BSS = 2, - BSS_TYPE_AP_BSS = 3, - MAX_BSS_TYPE = 0xFF -}; - -#define JOIN_CMD_CTRL_TX_FLUSH 0x80 /* Firmware flushes all Tx */ -#define JOIN_CMD_CTRL_EARLY_WAKEUP_ENABLE 0x01 /* Early wakeup time */ - - -struct cmd_join { - struct wl1251_cmd_header header; - - u32 bssid_lsb; - u16 bssid_msb; - u16 beacon_interval; /* in TBTTs */ - u32 rx_config_options; - u32 rx_filter_options; - - /* - * The target uses this field to determine the rate at - * which to transmit control frame responses (such as - * ACK or CTS frames). - */ - u16 basic_rate_set; - u8 dtim_interval; - u8 tx_ctrl_frame_rate; /* OBSOLETE */ - u8 tx_ctrl_frame_mod; /* OBSOLETE */ - /* - * bits 0-2: This bitwise field specifies the type - * of BSS to start or join (BSS_TYPE_*). - * bit 4: Band - The radio band in which to join - * or start. - * 0 - 2.4GHz band - * 1 - 5GHz band - * bits 3, 5-7: Reserved - */ - u8 bss_type; - u8 channel; - u8 ssid_len; - u8 ssid[IW_ESSID_MAX_SIZE]; - u8 ctrl; /* JOIN_CMD_CTRL_* */ - u8 tx_mgt_frame_rate; /* OBSOLETE */ - u8 tx_mgt_frame_mod; /* OBSOLETE */ - u8 reserved; -} __packed; - -struct cmd_enabledisable_path { - struct wl1251_cmd_header header; - - u8 channel; - u8 padding[3]; -} __packed; - -#define WL1251_MAX_TEMPLATE_SIZE 300 - -struct wl1251_cmd_packet_template { - struct wl1251_cmd_header header; - - __le16 size; - u8 data[0]; -} __packed; - -#define TIM_ELE_ID 5 -#define PARTIAL_VBM_MAX 251 - -struct wl1251_tim { - u8 identity; - u8 length; - u8 dtim_count; - u8 dtim_period; - u8 bitmap_ctrl; - u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */ -} __packed; - -/* Virtual Bit Map update */ -struct wl1251_cmd_vbm_update { - struct wl1251_cmd_header header; - __le16 len; - u8 padding[2]; - struct wl1251_tim tim; -} __packed; - -enum wl1251_cmd_ps_mode { - STATION_ACTIVE_MODE, - STATION_POWER_SAVE_MODE -}; - -struct wl1251_cmd_ps_params { - struct wl1251_cmd_header header; - - u8 ps_mode; /* STATION_* */ - u8 send_null_data; /* Do we have to send NULL data packet ? */ - u8 retries; /* Number of retires for the initial NULL data packet */ - - /* - * TUs during which the target stays awake after switching - * to power save mode. - */ - u8 hang_over_period; - u16 null_data_rate; - u8 pad[2]; -} __packed; - -struct wl1251_cmd_trigger_scan_to { - struct wl1251_cmd_header header; - - u32 timeout; -} __packed; - -/* HW encryption keys */ -#define NUM_ACCESS_CATEGORIES_COPY 4 -#define MAX_KEY_SIZE 32 - -/* When set, disable HW encryption */ -#define DF_ENCRYPTION_DISABLE 0x01 -/* When set, disable HW decryption */ -#define DF_SNIFF_MODE_ENABLE 0x80 - -enum wl1251_cmd_key_action { - KEY_ADD_OR_REPLACE = 1, - KEY_REMOVE = 2, - KEY_SET_ID = 3, - MAX_KEY_ACTION = 0xffff, -}; - -enum wl1251_cmd_key_type { - KEY_WEP_DEFAULT = 0, - KEY_WEP_ADDR = 1, - KEY_AES_GROUP = 4, - KEY_AES_PAIRWISE = 5, - KEY_WEP_GROUP = 6, - KEY_TKIP_MIC_GROUP = 10, - KEY_TKIP_MIC_PAIRWISE = 11, -}; - -/* - * - * key_type_e key size key format - * ---------- --------- ---------- - * 0x00 5, 13, 29 Key data - * 0x01 5, 13, 29 Key data - * 0x04 16 16 bytes of key data - * 0x05 16 16 bytes of key data - * 0x0a 32 16 bytes of TKIP key data - * 8 bytes of RX MIC key data - * 8 bytes of TX MIC key data - * 0x0b 32 16 bytes of TKIP key data - * 8 bytes of RX MIC key data - * 8 bytes of TX MIC key data - * - */ - -struct wl1251_cmd_set_keys { - struct wl1251_cmd_header header; - - /* Ignored for default WEP key */ - u8 addr[ETH_ALEN]; - - /* key_action_e */ - u16 key_action; - - u16 reserved_1; - - /* key size in bytes */ - u8 key_size; - - /* key_type_e */ - u8 key_type; - u8 ssid_profile; - - /* - * TKIP, AES: frame's key id field. - * For WEP default key: key id; - */ - u8 id; - u8 reserved_2[6]; - u8 key[MAX_KEY_SIZE]; - u16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY]; - u32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY]; -} __packed; - - -#endif /* __WL1251_CMD_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1251_debugfs.c b/drivers/net/wireless/wl12xx/wl1251_debugfs.c deleted file mode 100644 index 6ffe4cd..0000000 --- a/drivers/net/wireless/wl12xx/wl1251_debugfs.c +++ /dev/null @@ -1,541 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (C) 2009 Nokia Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include "wl1251_debugfs.h" - -#include -#include - -#include "wl1251.h" -#include "wl1251_acx.h" -#include "wl1251_ps.h" - -/* ms */ -#define WL1251_DEBUGFS_STATS_LIFETIME 1000 - -/* debugfs macros idea from mac80211 */ - -#define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...) \ -static ssize_t name## _read(struct file *file, char __user *userbuf, \ - size_t count, loff_t *ppos) \ -{ \ - struct wl1251 *wl = file->private_data; \ - char buf[buflen]; \ - int res; \ - \ - res = scnprintf(buf, buflen, fmt "\n", ##value); \ - return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ -} \ - \ -static const struct file_operations name## _ops = { \ - .read = name## _read, \ - .open = wl1251_open_file_generic, \ -}; - -#define DEBUGFS_ADD(name, parent) \ - wl->debugfs.name = debugfs_create_file(#name, 0400, parent, \ - wl, &name## _ops); \ - if (IS_ERR(wl->debugfs.name)) { \ - ret = PTR_ERR(wl->debugfs.name); \ - wl->debugfs.name = NULL; \ - goto out; \ - } - -#define DEBUGFS_DEL(name) \ - do { \ - debugfs_remove(wl->debugfs.name); \ - wl->debugfs.name = NULL; \ - } while (0) - -#define DEBUGFS_FWSTATS_FILE(sub, name, buflen, fmt) \ -static ssize_t sub## _ ##name## _read(struct file *file, \ - char __user *userbuf, \ - size_t count, loff_t *ppos) \ -{ \ - struct wl1251 *wl = file->private_data; \ - char buf[buflen]; \ - int res; \ - \ - wl1251_debugfs_update_stats(wl); \ - \ - res = scnprintf(buf, buflen, fmt "\n", \ - wl->stats.fw_stats->sub.name); \ - return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ -} \ - \ -static const struct file_operations sub## _ ##name## _ops = { \ - .read = sub## _ ##name## _read, \ - .open = wl1251_open_file_generic, \ -}; - -#define DEBUGFS_FWSTATS_ADD(sub, name) \ - DEBUGFS_ADD(sub## _ ##name, wl->debugfs.fw_statistics) - -#define DEBUGFS_FWSTATS_DEL(sub, name) \ - DEBUGFS_DEL(sub## _ ##name) - -static void wl1251_debugfs_update_stats(struct wl1251 *wl) -{ - int ret; - - mutex_lock(&wl->mutex); - - ret = wl1251_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - if (wl->state == WL1251_STATE_ON && - time_after(jiffies, wl->stats.fw_stats_update + - msecs_to_jiffies(WL1251_DEBUGFS_STATS_LIFETIME))) { - wl1251_acx_statistics(wl, wl->stats.fw_stats); - wl->stats.fw_stats_update = jiffies; - } - - wl1251_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); -} - -static int wl1251_open_file_generic(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - -DEBUGFS_FWSTATS_FILE(tx, internal_desc_overflow, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(rx, out_of_mem, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rx, hdr_overflow, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rx, hw_stuck, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rx, dropped, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rx, fcs_err, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rx, xfr_hint_trig, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rx, path_reset, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rx, reset_counter, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(dma, rx_requested, 20, "%u"); -DEBUGFS_FWSTATS_FILE(dma, rx_errors, 20, "%u"); -DEBUGFS_FWSTATS_FILE(dma, tx_requested, 20, "%u"); -DEBUGFS_FWSTATS_FILE(dma, tx_errors, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(isr, cmd_cmplt, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, fiqs, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, rx_headers, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, rx_mem_overflow, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, rx_rdys, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, irqs, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, tx_procs, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, decrypt_done, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, dma0_done, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, dma1_done, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, tx_exch_complete, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, commands, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, rx_procs, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, hw_pm_mode_changes, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, host_acknowledges, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, pci_pm, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, wakeups, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, low_rssi, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(wep, addr_key_count, 20, "%u"); -DEBUGFS_FWSTATS_FILE(wep, default_key_count, 20, "%u"); -/* skipping wep.reserved */ -DEBUGFS_FWSTATS_FILE(wep, key_not_found, 20, "%u"); -DEBUGFS_FWSTATS_FILE(wep, decrypt_fail, 20, "%u"); -DEBUGFS_FWSTATS_FILE(wep, packets, 20, "%u"); -DEBUGFS_FWSTATS_FILE(wep, interrupt, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(pwr, ps_enter, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, elp_enter, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, missing_bcns, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, wake_on_host, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, wake_on_timer_exp, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, tx_with_ps, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, tx_without_ps, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, rcvd_beacons, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, power_save_off, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, enable_ps, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, disable_ps, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, fix_tsf_ps, 20, "%u"); -/* skipping cont_miss_bcns_spread for now */ -DEBUGFS_FWSTATS_FILE(pwr, rcvd_awake_beacons, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(mic, rx_pkts, 20, "%u"); -DEBUGFS_FWSTATS_FILE(mic, calc_failure, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(aes, encrypt_fail, 20, "%u"); -DEBUGFS_FWSTATS_FILE(aes, decrypt_fail, 20, "%u"); -DEBUGFS_FWSTATS_FILE(aes, encrypt_packets, 20, "%u"); -DEBUGFS_FWSTATS_FILE(aes, decrypt_packets, 20, "%u"); -DEBUGFS_FWSTATS_FILE(aes, encrypt_interrupt, 20, "%u"); -DEBUGFS_FWSTATS_FILE(aes, decrypt_interrupt, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(event, heart_beat, 20, "%u"); -DEBUGFS_FWSTATS_FILE(event, calibration, 20, "%u"); -DEBUGFS_FWSTATS_FILE(event, rx_mismatch, 20, "%u"); -DEBUGFS_FWSTATS_FILE(event, rx_mem_empty, 20, "%u"); -DEBUGFS_FWSTATS_FILE(event, rx_pool, 20, "%u"); -DEBUGFS_FWSTATS_FILE(event, oom_late, 20, "%u"); -DEBUGFS_FWSTATS_FILE(event, phy_transmit_error, 20, "%u"); -DEBUGFS_FWSTATS_FILE(event, tx_stuck, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(ps, pspoll_timeouts, 20, "%u"); -DEBUGFS_FWSTATS_FILE(ps, upsd_timeouts, 20, "%u"); -DEBUGFS_FWSTATS_FILE(ps, upsd_max_sptime, 20, "%u"); -DEBUGFS_FWSTATS_FILE(ps, upsd_max_apturn, 20, "%u"); -DEBUGFS_FWSTATS_FILE(ps, pspoll_max_apturn, 20, "%u"); -DEBUGFS_FWSTATS_FILE(ps, pspoll_utilization, 20, "%u"); -DEBUGFS_FWSTATS_FILE(ps, upsd_utilization, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(rxpipe, rx_prep_beacon_drop, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rxpipe, descr_host_int_trig_rx_data, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rxpipe, beacon_buffer_thres_host_int_trig_rx_data, - 20, "%u"); -DEBUGFS_FWSTATS_FILE(rxpipe, missed_beacon_host_int_trig_rx_data, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rxpipe, tx_xfr_host_int_trig_rx_data, 20, "%u"); - -DEBUGFS_READONLY_FILE(retry_count, 20, "%u", wl->stats.retry_count); -DEBUGFS_READONLY_FILE(excessive_retries, 20, "%u", - wl->stats.excessive_retries); - -static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - struct wl1251 *wl = file->private_data; - u32 queue_len; - char buf[20]; - int res; - - queue_len = skb_queue_len(&wl->tx_queue); - - res = scnprintf(buf, sizeof(buf), "%u\n", queue_len); - return simple_read_from_buffer(userbuf, count, ppos, buf, res); -} - -static const struct file_operations tx_queue_len_ops = { - .read = tx_queue_len_read, - .open = wl1251_open_file_generic, -}; - -static ssize_t tx_queue_status_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - struct wl1251 *wl = file->private_data; - char buf[3], status; - int len; - - if (wl->tx_queue_stopped) - status = 's'; - else - status = 'r'; - - len = scnprintf(buf, sizeof(buf), "%c\n", status); - return simple_read_from_buffer(userbuf, count, ppos, buf, len); -} - -static const struct file_operations tx_queue_status_ops = { - .read = tx_queue_status_read, - .open = wl1251_open_file_generic, -}; - -static void wl1251_debugfs_delete_files(struct wl1251 *wl) -{ - DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow); - - DEBUGFS_FWSTATS_DEL(rx, out_of_mem); - DEBUGFS_FWSTATS_DEL(rx, hdr_overflow); - DEBUGFS_FWSTATS_DEL(rx, hw_stuck); - DEBUGFS_FWSTATS_DEL(rx, dropped); - DEBUGFS_FWSTATS_DEL(rx, fcs_err); - DEBUGFS_FWSTATS_DEL(rx, xfr_hint_trig); - DEBUGFS_FWSTATS_DEL(rx, path_reset); - DEBUGFS_FWSTATS_DEL(rx, reset_counter); - - DEBUGFS_FWSTATS_DEL(dma, rx_requested); - DEBUGFS_FWSTATS_DEL(dma, rx_errors); - DEBUGFS_FWSTATS_DEL(dma, tx_requested); - DEBUGFS_FWSTATS_DEL(dma, tx_errors); - - DEBUGFS_FWSTATS_DEL(isr, cmd_cmplt); - DEBUGFS_FWSTATS_DEL(isr, fiqs); - DEBUGFS_FWSTATS_DEL(isr, rx_headers); - DEBUGFS_FWSTATS_DEL(isr, rx_mem_overflow); - DEBUGFS_FWSTATS_DEL(isr, rx_rdys); - DEBUGFS_FWSTATS_DEL(isr, irqs); - DEBUGFS_FWSTATS_DEL(isr, tx_procs); - DEBUGFS_FWSTATS_DEL(isr, decrypt_done); - DEBUGFS_FWSTATS_DEL(isr, dma0_done); - DEBUGFS_FWSTATS_DEL(isr, dma1_done); - DEBUGFS_FWSTATS_DEL(isr, tx_exch_complete); - DEBUGFS_FWSTATS_DEL(isr, commands); - DEBUGFS_FWSTATS_DEL(isr, rx_procs); - DEBUGFS_FWSTATS_DEL(isr, hw_pm_mode_changes); - DEBUGFS_FWSTATS_DEL(isr, host_acknowledges); - DEBUGFS_FWSTATS_DEL(isr, pci_pm); - DEBUGFS_FWSTATS_DEL(isr, wakeups); - DEBUGFS_FWSTATS_DEL(isr, low_rssi); - - DEBUGFS_FWSTATS_DEL(wep, addr_key_count); - DEBUGFS_FWSTATS_DEL(wep, default_key_count); - /* skipping wep.reserved */ - DEBUGFS_FWSTATS_DEL(wep, key_not_found); - DEBUGFS_FWSTATS_DEL(wep, decrypt_fail); - DEBUGFS_FWSTATS_DEL(wep, packets); - DEBUGFS_FWSTATS_DEL(wep, interrupt); - - DEBUGFS_FWSTATS_DEL(pwr, ps_enter); - DEBUGFS_FWSTATS_DEL(pwr, elp_enter); - DEBUGFS_FWSTATS_DEL(pwr, missing_bcns); - DEBUGFS_FWSTATS_DEL(pwr, wake_on_host); - DEBUGFS_FWSTATS_DEL(pwr, wake_on_timer_exp); - DEBUGFS_FWSTATS_DEL(pwr, tx_with_ps); - DEBUGFS_FWSTATS_DEL(pwr, tx_without_ps); - DEBUGFS_FWSTATS_DEL(pwr, rcvd_beacons); - DEBUGFS_FWSTATS_DEL(pwr, power_save_off); - DEBUGFS_FWSTATS_DEL(pwr, enable_ps); - DEBUGFS_FWSTATS_DEL(pwr, disable_ps); - DEBUGFS_FWSTATS_DEL(pwr, fix_tsf_ps); - /* skipping cont_miss_bcns_spread for now */ - DEBUGFS_FWSTATS_DEL(pwr, rcvd_awake_beacons); - - DEBUGFS_FWSTATS_DEL(mic, rx_pkts); - DEBUGFS_FWSTATS_DEL(mic, calc_failure); - - DEBUGFS_FWSTATS_DEL(aes, encrypt_fail); - DEBUGFS_FWSTATS_DEL(aes, decrypt_fail); - DEBUGFS_FWSTATS_DEL(aes, encrypt_packets); - DEBUGFS_FWSTATS_DEL(aes, decrypt_packets); - DEBUGFS_FWSTATS_DEL(aes, encrypt_interrupt); - DEBUGFS_FWSTATS_DEL(aes, decrypt_interrupt); - - DEBUGFS_FWSTATS_DEL(event, heart_beat); - DEBUGFS_FWSTATS_DEL(event, calibration); - DEBUGFS_FWSTATS_DEL(event, rx_mismatch); - DEBUGFS_FWSTATS_DEL(event, rx_mem_empty); - DEBUGFS_FWSTATS_DEL(event, rx_pool); - DEBUGFS_FWSTATS_DEL(event, oom_late); - DEBUGFS_FWSTATS_DEL(event, phy_transmit_error); - DEBUGFS_FWSTATS_DEL(event, tx_stuck); - - DEBUGFS_FWSTATS_DEL(ps, pspoll_timeouts); - DEBUGFS_FWSTATS_DEL(ps, upsd_timeouts); - DEBUGFS_FWSTATS_DEL(ps, upsd_max_sptime); - DEBUGFS_FWSTATS_DEL(ps, upsd_max_apturn); - DEBUGFS_FWSTATS_DEL(ps, pspoll_max_apturn); - DEBUGFS_FWSTATS_DEL(ps, pspoll_utilization); - DEBUGFS_FWSTATS_DEL(ps, upsd_utilization); - - DEBUGFS_FWSTATS_DEL(rxpipe, rx_prep_beacon_drop); - DEBUGFS_FWSTATS_DEL(rxpipe, descr_host_int_trig_rx_data); - DEBUGFS_FWSTATS_DEL(rxpipe, beacon_buffer_thres_host_int_trig_rx_data); - DEBUGFS_FWSTATS_DEL(rxpipe, missed_beacon_host_int_trig_rx_data); - DEBUGFS_FWSTATS_DEL(rxpipe, tx_xfr_host_int_trig_rx_data); - - DEBUGFS_DEL(tx_queue_len); - DEBUGFS_DEL(tx_queue_status); - DEBUGFS_DEL(retry_count); - DEBUGFS_DEL(excessive_retries); -} - -static int wl1251_debugfs_add_files(struct wl1251 *wl) -{ - int ret = 0; - - DEBUGFS_FWSTATS_ADD(tx, internal_desc_overflow); - - DEBUGFS_FWSTATS_ADD(rx, out_of_mem); - DEBUGFS_FWSTATS_ADD(rx, hdr_overflow); - DEBUGFS_FWSTATS_ADD(rx, hw_stuck); - DEBUGFS_FWSTATS_ADD(rx, dropped); - DEBUGFS_FWSTATS_ADD(rx, fcs_err); - DEBUGFS_FWSTATS_ADD(rx, xfr_hint_trig); - DEBUGFS_FWSTATS_ADD(rx, path_reset); - DEBUGFS_FWSTATS_ADD(rx, reset_counter); - - DEBUGFS_FWSTATS_ADD(dma, rx_requested); - DEBUGFS_FWSTATS_ADD(dma, rx_errors); - DEBUGFS_FWSTATS_ADD(dma, tx_requested); - DEBUGFS_FWSTATS_ADD(dma, tx_errors); - - DEBUGFS_FWSTATS_ADD(isr, cmd_cmplt); - DEBUGFS_FWSTATS_ADD(isr, fiqs); - DEBUGFS_FWSTATS_ADD(isr, rx_headers); - DEBUGFS_FWSTATS_ADD(isr, rx_mem_overflow); - DEBUGFS_FWSTATS_ADD(isr, rx_rdys); - DEBUGFS_FWSTATS_ADD(isr, irqs); - DEBUGFS_FWSTATS_ADD(isr, tx_procs); - DEBUGFS_FWSTATS_ADD(isr, decrypt_done); - DEBUGFS_FWSTATS_ADD(isr, dma0_done); - DEBUGFS_FWSTATS_ADD(isr, dma1_done); - DEBUGFS_FWSTATS_ADD(isr, tx_exch_complete); - DEBUGFS_FWSTATS_ADD(isr, commands); - DEBUGFS_FWSTATS_ADD(isr, rx_procs); - DEBUGFS_FWSTATS_ADD(isr, hw_pm_mode_changes); - DEBUGFS_FWSTATS_ADD(isr, host_acknowledges); - DEBUGFS_FWSTATS_ADD(isr, pci_pm); - DEBUGFS_FWSTATS_ADD(isr, wakeups); - DEBUGFS_FWSTATS_ADD(isr, low_rssi); - - DEBUGFS_FWSTATS_ADD(wep, addr_key_count); - DEBUGFS_FWSTATS_ADD(wep, default_key_count); - /* skipping wep.reserved */ - DEBUGFS_FWSTATS_ADD(wep, key_not_found); - DEBUGFS_FWSTATS_ADD(wep, decrypt_fail); - DEBUGFS_FWSTATS_ADD(wep, packets); - DEBUGFS_FWSTATS_ADD(wep, interrupt); - - DEBUGFS_FWSTATS_ADD(pwr, ps_enter); - DEBUGFS_FWSTATS_ADD(pwr, elp_enter); - DEBUGFS_FWSTATS_ADD(pwr, missing_bcns); - DEBUGFS_FWSTATS_ADD(pwr, wake_on_host); - DEBUGFS_FWSTATS_ADD(pwr, wake_on_timer_exp); - DEBUGFS_FWSTATS_ADD(pwr, tx_with_ps); - DEBUGFS_FWSTATS_ADD(pwr, tx_without_ps); - DEBUGFS_FWSTATS_ADD(pwr, rcvd_beacons); - DEBUGFS_FWSTATS_ADD(pwr, power_save_off); - DEBUGFS_FWSTATS_ADD(pwr, enable_ps); - DEBUGFS_FWSTATS_ADD(pwr, disable_ps); - DEBUGFS_FWSTATS_ADD(pwr, fix_tsf_ps); - /* skipping cont_miss_bcns_spread for now */ - DEBUGFS_FWSTATS_ADD(pwr, rcvd_awake_beacons); - - DEBUGFS_FWSTATS_ADD(mic, rx_pkts); - DEBUGFS_FWSTATS_ADD(mic, calc_failure); - - DEBUGFS_FWSTATS_ADD(aes, encrypt_fail); - DEBUGFS_FWSTATS_ADD(aes, decrypt_fail); - DEBUGFS_FWSTATS_ADD(aes, encrypt_packets); - DEBUGFS_FWSTATS_ADD(aes, decrypt_packets); - DEBUGFS_FWSTATS_ADD(aes, encrypt_interrupt); - DEBUGFS_FWSTATS_ADD(aes, decrypt_interrupt); - - DEBUGFS_FWSTATS_ADD(event, heart_beat); - DEBUGFS_FWSTATS_ADD(event, calibration); - DEBUGFS_FWSTATS_ADD(event, rx_mismatch); - DEBUGFS_FWSTATS_ADD(event, rx_mem_empty); - DEBUGFS_FWSTATS_ADD(event, rx_pool); - DEBUGFS_FWSTATS_ADD(event, oom_late); - DEBUGFS_FWSTATS_ADD(event, phy_transmit_error); - DEBUGFS_FWSTATS_ADD(event, tx_stuck); - - DEBUGFS_FWSTATS_ADD(ps, pspoll_timeouts); - DEBUGFS_FWSTATS_ADD(ps, upsd_timeouts); - DEBUGFS_FWSTATS_ADD(ps, upsd_max_sptime); - DEBUGFS_FWSTATS_ADD(ps, upsd_max_apturn); - DEBUGFS_FWSTATS_ADD(ps, pspoll_max_apturn); - DEBUGFS_FWSTATS_ADD(ps, pspoll_utilization); - DEBUGFS_FWSTATS_ADD(ps, upsd_utilization); - - DEBUGFS_FWSTATS_ADD(rxpipe, rx_prep_beacon_drop); - DEBUGFS_FWSTATS_ADD(rxpipe, descr_host_int_trig_rx_data); - DEBUGFS_FWSTATS_ADD(rxpipe, beacon_buffer_thres_host_int_trig_rx_data); - DEBUGFS_FWSTATS_ADD(rxpipe, missed_beacon_host_int_trig_rx_data); - DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data); - - DEBUGFS_ADD(tx_queue_len, wl->debugfs.rootdir); - DEBUGFS_ADD(tx_queue_status, wl->debugfs.rootdir); - DEBUGFS_ADD(retry_count, wl->debugfs.rootdir); - DEBUGFS_ADD(excessive_retries, wl->debugfs.rootdir); - -out: - if (ret < 0) - wl1251_debugfs_delete_files(wl); - - return ret; -} - -void wl1251_debugfs_reset(struct wl1251 *wl) -{ - if (wl->stats.fw_stats != NULL) - memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats)); - wl->stats.retry_count = 0; - wl->stats.excessive_retries = 0; -} - -int wl1251_debugfs_init(struct wl1251 *wl) -{ - int ret; - - wl->debugfs.rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL); - - if (IS_ERR(wl->debugfs.rootdir)) { - ret = PTR_ERR(wl->debugfs.rootdir); - wl->debugfs.rootdir = NULL; - goto err; - } - - wl->debugfs.fw_statistics = debugfs_create_dir("fw-statistics", - wl->debugfs.rootdir); - - if (IS_ERR(wl->debugfs.fw_statistics)) { - ret = PTR_ERR(wl->debugfs.fw_statistics); - wl->debugfs.fw_statistics = NULL; - goto err_root; - } - - wl->stats.fw_stats = kzalloc(sizeof(*wl->stats.fw_stats), - GFP_KERNEL); - - if (!wl->stats.fw_stats) { - ret = -ENOMEM; - goto err_fw; - } - - wl->stats.fw_stats_update = jiffies; - - ret = wl1251_debugfs_add_files(wl); - - if (ret < 0) - goto err_file; - - return 0; - -err_file: - kfree(wl->stats.fw_stats); - wl->stats.fw_stats = NULL; - -err_fw: - debugfs_remove(wl->debugfs.fw_statistics); - wl->debugfs.fw_statistics = NULL; - -err_root: - debugfs_remove(wl->debugfs.rootdir); - wl->debugfs.rootdir = NULL; - -err: - return ret; -} - -void wl1251_debugfs_exit(struct wl1251 *wl) -{ - wl1251_debugfs_delete_files(wl); - - kfree(wl->stats.fw_stats); - wl->stats.fw_stats = NULL; - - debugfs_remove(wl->debugfs.fw_statistics); - wl->debugfs.fw_statistics = NULL; - - debugfs_remove(wl->debugfs.rootdir); - wl->debugfs.rootdir = NULL; - -} diff --git a/drivers/net/wireless/wl12xx/wl1251_debugfs.h b/drivers/net/wireless/wl12xx/wl1251_debugfs.h deleted file mode 100644 index b3417c0..0000000 --- a/drivers/net/wireless/wl12xx/wl1251_debugfs.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (C) 2009 Nokia Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef WL1251_DEBUGFS_H -#define WL1251_DEBUGFS_H - -#include "wl1251.h" - -int wl1251_debugfs_init(struct wl1251 *wl); -void wl1251_debugfs_exit(struct wl1251 *wl); -void wl1251_debugfs_reset(struct wl1251 *wl); - -#endif /* WL1251_DEBUGFS_H */ diff --git a/drivers/net/wireless/wl12xx/wl1251_event.c b/drivers/net/wireless/wl12xx/wl1251_event.c deleted file mode 100644 index 5422355..0000000 --- a/drivers/net/wireless/wl12xx/wl1251_event.c +++ /dev/null @@ -1,168 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include "wl1251.h" -#include "wl1251_reg.h" -#include "wl1251_io.h" -#include "wl1251_event.h" -#include "wl1251_ps.h" - -static int wl1251_event_scan_complete(struct wl1251 *wl, - struct event_mailbox *mbox) -{ - wl1251_debug(DEBUG_EVENT, "status: 0x%x, channels: %d", - mbox->scheduled_scan_status, - mbox->scheduled_scan_channels); - - if (wl->scanning) { - ieee80211_scan_completed(wl->hw, false); - wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan completed"); - wl->scanning = false; - } - - return 0; -} - -static void wl1251_event_mbox_dump(struct event_mailbox *mbox) -{ - wl1251_debug(DEBUG_EVENT, "MBOX DUMP:"); - wl1251_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector); - wl1251_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask); -} - -static int wl1251_event_process(struct wl1251 *wl, struct event_mailbox *mbox) -{ - int ret; - u32 vector; - - wl1251_event_mbox_dump(mbox); - - vector = mbox->events_vector & ~(mbox->events_mask); - wl1251_debug(DEBUG_EVENT, "vector: 0x%x", vector); - - if (vector & SCAN_COMPLETE_EVENT_ID) { - ret = wl1251_event_scan_complete(wl, mbox); - if (ret < 0) - return ret; - } - - if (vector & BSS_LOSE_EVENT_ID) { - wl1251_debug(DEBUG_EVENT, "BSS_LOSE_EVENT"); - - if (wl->psm_requested && wl->psm) { - ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE); - if (ret < 0) - return ret; - } - } - - if (vector & SYNCHRONIZATION_TIMEOUT_EVENT_ID && wl->psm) { - wl1251_debug(DEBUG_EVENT, "SYNCHRONIZATION_TIMEOUT_EVENT"); - - /* indicate to the stack, that beacons have been lost */ - ieee80211_beacon_loss(wl->vif); - } - - if (vector & REGAINED_BSS_EVENT_ID) { - if (wl->psm_requested) { - ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE); - if (ret < 0) - return ret; - } - } - - return 0; -} - -/* - * Poll the mailbox event field until any of the bits in the mask is set or a - * timeout occurs (WL1251_EVENT_TIMEOUT in msecs) - */ -int wl1251_event_wait(struct wl1251 *wl, u32 mask, int timeout_ms) -{ - u32 events_vector, event; - unsigned long timeout; - - timeout = jiffies + msecs_to_jiffies(timeout_ms); - - do { - if (time_after(jiffies, timeout)) - return -ETIMEDOUT; - - msleep(1); - - /* read from both event fields */ - wl1251_mem_read(wl, wl->mbox_ptr[0], &events_vector, - sizeof(events_vector)); - event = events_vector & mask; - wl1251_mem_read(wl, wl->mbox_ptr[1], &events_vector, - sizeof(events_vector)); - event |= events_vector & mask; - } while (!event); - - return 0; -} - -int wl1251_event_unmask(struct wl1251 *wl) -{ - int ret; - - ret = wl1251_acx_event_mbox_mask(wl, ~(wl->event_mask)); - if (ret < 0) - return ret; - - return 0; -} - -void wl1251_event_mbox_config(struct wl1251 *wl) -{ - wl->mbox_ptr[0] = wl1251_reg_read32(wl, REG_EVENT_MAILBOX_PTR); - wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox); - - wl1251_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x", - wl->mbox_ptr[0], wl->mbox_ptr[1]); -} - -int wl1251_event_handle(struct wl1251 *wl, u8 mbox_num) -{ - struct event_mailbox mbox; - int ret; - - wl1251_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num); - - if (mbox_num > 1) - return -EINVAL; - - /* first we read the mbox descriptor */ - wl1251_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox, - sizeof(struct event_mailbox)); - - /* process the descriptor */ - ret = wl1251_event_process(wl, &mbox); - if (ret < 0) - return ret; - - /* then we let the firmware know it can go on...*/ - wl1251_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK); - - return 0; -} diff --git a/drivers/net/wireless/wl12xx/wl1251_event.h b/drivers/net/wireless/wl12xx/wl1251_event.h deleted file mode 100644 index 30eb5d1..0000000 --- a/drivers/net/wireless/wl12xx/wl1251_event.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL1251_EVENT_H__ -#define __WL1251_EVENT_H__ - -/* - * Mbox events - * - * The event mechanism is based on a pair of event buffers (buffers A and - * B) at fixed locations in the target's memory. The host processes one - * buffer while the other buffer continues to collect events. If the host - * is not processing events, an interrupt is issued to signal that a buffer - * is ready. Once the host is done with processing events from one buffer, - * it signals the target (with an ACK interrupt) that the event buffer is - * free. - */ - -enum { - RESERVED1_EVENT_ID = BIT(0), - RESERVED2_EVENT_ID = BIT(1), - MEASUREMENT_START_EVENT_ID = BIT(2), - SCAN_COMPLETE_EVENT_ID = BIT(3), - CALIBRATION_COMPLETE_EVENT_ID = BIT(4), - ROAMING_TRIGGER_LOW_RSSI_EVENT_ID = BIT(5), - PS_REPORT_EVENT_ID = BIT(6), - SYNCHRONIZATION_TIMEOUT_EVENT_ID = BIT(7), - HEALTH_REPORT_EVENT_ID = BIT(8), - ACI_DETECTION_EVENT_ID = BIT(9), - DEBUG_REPORT_EVENT_ID = BIT(10), - MAC_STATUS_EVENT_ID = BIT(11), - DISCONNECT_EVENT_COMPLETE_ID = BIT(12), - JOIN_EVENT_COMPLETE_ID = BIT(13), - CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(14), - BSS_LOSE_EVENT_ID = BIT(15), - ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID = BIT(16), - MEASUREMENT_COMPLETE_EVENT_ID = BIT(17), - AP_DISCOVERY_COMPLETE_EVENT_ID = BIT(18), - SCHEDULED_SCAN_COMPLETE_EVENT_ID = BIT(19), - PSPOLL_DELIVERY_FAILURE_EVENT_ID = BIT(20), - RESET_BSS_EVENT_ID = BIT(21), - REGAINED_BSS_EVENT_ID = BIT(22), - ROAMING_TRIGGER_REGAINED_RSSI_EVENT_ID = BIT(23), - ROAMING_TRIGGER_LOW_SNR_EVENT_ID = BIT(24), - ROAMING_TRIGGER_REGAINED_SNR_EVENT_ID = BIT(25), - - DBG_EVENT_ID = BIT(26), - BT_PTA_SENSE_EVENT_ID = BIT(27), - BT_PTA_PREDICTION_EVENT_ID = BIT(28), - BT_PTA_AVALANCHE_EVENT_ID = BIT(29), - - PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(30), - - EVENT_MBOX_ALL_EVENT_ID = 0x7fffffff, -}; - -struct event_debug_report { - u8 debug_event_id; - u8 num_params; - u16 pad; - u32 report_1; - u32 report_2; - u32 report_3; -} __packed; - -struct event_mailbox { - u32 events_vector; - u32 events_mask; - u32 reserved_1; - u32 reserved_2; - - char average_rssi_level; - u8 ps_status; - u8 channel_switch_status; - u8 scheduled_scan_status; - - /* Channels scanned by the scheduled scan */ - u16 scheduled_scan_channels; - - /* If bit 0 is set -> target's fatal error */ - u16 health_report; - u16 bad_fft_counter; - u8 bt_pta_sense_info; - u8 bt_pta_protective_info; - u32 reserved; - u32 debug_report[2]; - - /* Number of FCS errors since last event */ - u32 fcs_err_counter; - - struct event_debug_report report; - u8 average_snr_level; - u8 padding[19]; -} __packed; - -int wl1251_event_unmask(struct wl1251 *wl); -void wl1251_event_mbox_config(struct wl1251 *wl); -int wl1251_event_handle(struct wl1251 *wl, u8 mbox); -int wl1251_event_wait(struct wl1251 *wl, u32 mask, int timeout_ms); - -#endif diff --git a/drivers/net/wireless/wl12xx/wl1251_init.c b/drivers/net/wireless/wl12xx/wl1251_init.c deleted file mode 100644 index c5daec0..0000000 --- a/drivers/net/wireless/wl12xx/wl1251_init.c +++ /dev/null @@ -1,423 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (C) 2009 Nokia Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include -#include -#include - -#include "wl1251_init.h" -#include "wl12xx_80211.h" -#include "wl1251_acx.h" -#include "wl1251_cmd.h" -#include "wl1251_reg.h" - -int wl1251_hw_init_hwenc_config(struct wl1251 *wl) -{ - int ret; - - ret = wl1251_acx_feature_cfg(wl); - if (ret < 0) { - wl1251_warning("couldn't set feature config"); - return ret; - } - - ret = wl1251_acx_default_key(wl, wl->default_key); - if (ret < 0) { - wl1251_warning("couldn't set default key"); - return ret; - } - - return 0; -} - -int wl1251_hw_init_templates_config(struct wl1251 *wl) -{ - int ret; - u8 partial_vbm[PARTIAL_VBM_MAX]; - - /* send empty templates for fw memory reservation */ - ret = wl1251_cmd_template_set(wl, CMD_PROBE_REQ, NULL, - sizeof(struct wl12xx_probe_req_template)); - if (ret < 0) - return ret; - - ret = wl1251_cmd_template_set(wl, CMD_NULL_DATA, NULL, - sizeof(struct wl12xx_null_data_template)); - if (ret < 0) - return ret; - - ret = wl1251_cmd_template_set(wl, CMD_PS_POLL, NULL, - sizeof(struct wl12xx_ps_poll_template)); - if (ret < 0) - return ret; - - ret = wl1251_cmd_template_set(wl, CMD_QOS_NULL_DATA, NULL, - sizeof - (struct wl12xx_qos_null_data_template)); - if (ret < 0) - return ret; - - ret = wl1251_cmd_template_set(wl, CMD_PROBE_RESP, NULL, - sizeof - (struct wl12xx_probe_resp_template)); - if (ret < 0) - return ret; - - ret = wl1251_cmd_template_set(wl, CMD_BEACON, NULL, - sizeof - (struct wl12xx_beacon_template)); - if (ret < 0) - return ret; - - /* tim templates, first reserve space then allocate an empty one */ - memset(partial_vbm, 0, PARTIAL_VBM_MAX); - ret = wl1251_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, PARTIAL_VBM_MAX, 0); - if (ret < 0) - return ret; - - ret = wl1251_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, 1, 0); - if (ret < 0) - return ret; - - return 0; -} - -int wl1251_hw_init_rx_config(struct wl1251 *wl, u32 config, u32 filter) -{ - int ret; - - ret = wl1251_acx_rx_msdu_life_time(wl, RX_MSDU_LIFETIME_DEF); - if (ret < 0) - return ret; - - ret = wl1251_acx_rx_config(wl, config, filter); - if (ret < 0) - return ret; - - return 0; -} - -int wl1251_hw_init_phy_config(struct wl1251 *wl) -{ - int ret; - - ret = wl1251_acx_pd_threshold(wl); - if (ret < 0) - return ret; - - ret = wl1251_acx_slot(wl, DEFAULT_SLOT_TIME); - if (ret < 0) - return ret; - - ret = wl1251_acx_group_address_tbl(wl); - if (ret < 0) - return ret; - - ret = wl1251_acx_service_period_timeout(wl); - if (ret < 0) - return ret; - - ret = wl1251_acx_rts_threshold(wl, RTS_THRESHOLD_DEF); - if (ret < 0) - return ret; - - return 0; -} - -int wl1251_hw_init_beacon_filter(struct wl1251 *wl) -{ - int ret; - - /* disable beacon filtering at this stage */ - ret = wl1251_acx_beacon_filter_opt(wl, false); - if (ret < 0) - return ret; - - ret = wl1251_acx_beacon_filter_table(wl); - if (ret < 0) - return ret; - - return 0; -} - -int wl1251_hw_init_pta(struct wl1251 *wl) -{ - int ret; - - ret = wl1251_acx_sg_enable(wl); - if (ret < 0) - return ret; - - ret = wl1251_acx_sg_cfg(wl); - if (ret < 0) - return ret; - - return 0; -} - -int wl1251_hw_init_energy_detection(struct wl1251 *wl) -{ - int ret; - - ret = wl1251_acx_cca_threshold(wl); - if (ret < 0) - return ret; - - return 0; -} - -int wl1251_hw_init_beacon_broadcast(struct wl1251 *wl) -{ - int ret; - - ret = wl1251_acx_bcn_dtim_options(wl); - if (ret < 0) - return ret; - - return 0; -} - -int wl1251_hw_init_power_auth(struct wl1251 *wl) -{ - return wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM); -} - -int wl1251_hw_init_mem_config(struct wl1251 *wl) -{ - int ret; - - ret = wl1251_acx_mem_cfg(wl); - if (ret < 0) - return ret; - - wl->target_mem_map = kzalloc(sizeof(struct wl1251_acx_mem_map), - GFP_KERNEL); - if (!wl->target_mem_map) { - wl1251_error("couldn't allocate target memory map"); - return -ENOMEM; - } - - /* we now ask for the firmware built memory map */ - ret = wl1251_acx_mem_map(wl, wl->target_mem_map, - sizeof(struct wl1251_acx_mem_map)); - if (ret < 0) { - wl1251_error("couldn't retrieve firmware memory map"); - kfree(wl->target_mem_map); - wl->target_mem_map = NULL; - return ret; - } - - return 0; -} - -static int wl1251_hw_init_txq_fill(u8 qid, - struct acx_tx_queue_qos_config *config, - u32 num_blocks) -{ - config->qid = qid; - - switch (qid) { - case QOS_AC_BE: - config->high_threshold = - (QOS_TX_HIGH_BE_DEF * num_blocks) / 100; - config->low_threshold = - (QOS_TX_LOW_BE_DEF * num_blocks) / 100; - break; - case QOS_AC_BK: - config->high_threshold = - (QOS_TX_HIGH_BK_DEF * num_blocks) / 100; - config->low_threshold = - (QOS_TX_LOW_BK_DEF * num_blocks) / 100; - break; - case QOS_AC_VI: - config->high_threshold = - (QOS_TX_HIGH_VI_DEF * num_blocks) / 100; - config->low_threshold = - (QOS_TX_LOW_VI_DEF * num_blocks) / 100; - break; - case QOS_AC_VO: - config->high_threshold = - (QOS_TX_HIGH_VO_DEF * num_blocks) / 100; - config->low_threshold = - (QOS_TX_LOW_VO_DEF * num_blocks) / 100; - break; - default: - wl1251_error("Invalid TX queue id: %d", qid); - return -EINVAL; - } - - return 0; -} - -static int wl1251_hw_init_tx_queue_config(struct wl1251 *wl) -{ - struct acx_tx_queue_qos_config *config; - struct wl1251_acx_mem_map *wl_mem_map = wl->target_mem_map; - int ret, i; - - wl1251_debug(DEBUG_ACX, "acx tx queue config"); - - config = kzalloc(sizeof(*config), GFP_KERNEL); - if (!config) { - ret = -ENOMEM; - goto out; - } - - for (i = 0; i < MAX_NUM_OF_AC; i++) { - ret = wl1251_hw_init_txq_fill(i, config, - wl_mem_map->num_tx_mem_blocks); - if (ret < 0) - goto out; - - ret = wl1251_cmd_configure(wl, ACX_TX_QUEUE_CFG, - config, sizeof(*config)); - if (ret < 0) - goto out; - } - - wl1251_acx_ac_cfg(wl, AC_BE, CWMIN_BE, CWMAX_BE, AIFS_DIFS, TXOP_BE); - wl1251_acx_ac_cfg(wl, AC_BK, CWMIN_BK, CWMAX_BK, AIFS_DIFS, TXOP_BK); - wl1251_acx_ac_cfg(wl, AC_VI, CWMIN_VI, CWMAX_VI, AIFS_DIFS, TXOP_VI); - wl1251_acx_ac_cfg(wl, AC_VO, CWMIN_VO, CWMAX_VO, AIFS_DIFS, TXOP_VO); - -out: - kfree(config); - return ret; -} - -static int wl1251_hw_init_data_path_config(struct wl1251 *wl) -{ - int ret; - - /* asking for the data path parameters */ - wl->data_path = kzalloc(sizeof(struct acx_data_path_params_resp), - GFP_KERNEL); - if (!wl->data_path) { - wl1251_error("Couldnt allocate data path parameters"); - return -ENOMEM; - } - - ret = wl1251_acx_data_path_params(wl, wl->data_path); - if (ret < 0) { - kfree(wl->data_path); - wl->data_path = NULL; - return ret; - } - - return 0; -} - - -int wl1251_hw_init(struct wl1251 *wl) -{ - struct wl1251_acx_mem_map *wl_mem_map; - int ret; - - ret = wl1251_hw_init_hwenc_config(wl); - if (ret < 0) - return ret; - - /* Template settings */ - ret = wl1251_hw_init_templates_config(wl); - if (ret < 0) - return ret; - - /* Default memory configuration */ - ret = wl1251_hw_init_mem_config(wl); - if (ret < 0) - return ret; - - /* Default data path configuration */ - ret = wl1251_hw_init_data_path_config(wl); - if (ret < 0) - goto out_free_memmap; - - /* RX config */ - ret = wl1251_hw_init_rx_config(wl, - RX_CFG_PROMISCUOUS | RX_CFG_TSF, - RX_FILTER_OPTION_DEF); - /* RX_CONFIG_OPTION_ANY_DST_ANY_BSS, - RX_FILTER_OPTION_FILTER_ALL); */ - if (ret < 0) - goto out_free_data_path; - - /* TX queues config */ - ret = wl1251_hw_init_tx_queue_config(wl); - if (ret < 0) - goto out_free_data_path; - - /* PHY layer config */ - ret = wl1251_hw_init_phy_config(wl); - if (ret < 0) - goto out_free_data_path; - - /* Initialize connection monitoring thresholds */ - ret = wl1251_acx_conn_monit_params(wl); - if (ret < 0) - goto out_free_data_path; - - /* Beacon filtering */ - ret = wl1251_hw_init_beacon_filter(wl); - if (ret < 0) - goto out_free_data_path; - - /* Bluetooth WLAN coexistence */ - ret = wl1251_hw_init_pta(wl); - if (ret < 0) - goto out_free_data_path; - - /* Energy detection */ - ret = wl1251_hw_init_energy_detection(wl); - if (ret < 0) - goto out_free_data_path; - - /* Beacons and boradcast settings */ - ret = wl1251_hw_init_beacon_broadcast(wl); - if (ret < 0) - goto out_free_data_path; - - /* Enable data path */ - ret = wl1251_cmd_data_path(wl, wl->channel, 1); - if (ret < 0) - goto out_free_data_path; - - /* Default power state */ - ret = wl1251_hw_init_power_auth(wl); - if (ret < 0) - goto out_free_data_path; - - wl_mem_map = wl->target_mem_map; - wl1251_info("%d tx blocks at 0x%x, %d rx blocks at 0x%x", - wl_mem_map->num_tx_mem_blocks, - wl->data_path->tx_control_addr, - wl_mem_map->num_rx_mem_blocks, - wl->data_path->rx_control_addr); - - return 0; - - out_free_data_path: - kfree(wl->data_path); - - out_free_memmap: - kfree(wl->target_mem_map); - - return ret; -} diff --git a/drivers/net/wireless/wl12xx/wl1251_init.h b/drivers/net/wireless/wl12xx/wl1251_init.h deleted file mode 100644 index 543f175..0000000 --- a/drivers/net/wireless/wl12xx/wl1251_init.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (C) 2009 Nokia Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL1251_INIT_H__ -#define __WL1251_INIT_H__ - -#include "wl1251.h" - -enum { - /* best effort/legacy */ - AC_BE = 0, - - /* background */ - AC_BK = 1, - - /* video */ - AC_VI = 2, - - /* voice */ - AC_VO = 3, - - /* broadcast dummy access category */ - AC_BCAST = 4, - - NUM_ACCESS_CATEGORIES = 4 -}; - -/* following are defult values for the IE fields*/ -#define CWMIN_BK 15 -#define CWMIN_BE 15 -#define CWMIN_VI 7 -#define CWMIN_VO 3 -#define CWMAX_BK 1023 -#define CWMAX_BE 63 -#define CWMAX_VI 15 -#define CWMAX_VO 7 - -/* slot number setting to start transmission at PIFS interval */ -#define AIFS_PIFS 1 - -/* - * slot number setting to start transmission at DIFS interval - normal DCF - * access - */ -#define AIFS_DIFS 2 - -#define AIFSN_BK 7 -#define AIFSN_BE 3 -#define AIFSN_VI AIFS_PIFS -#define AIFSN_VO AIFS_PIFS -#define TXOP_BK 0 -#define TXOP_BE 0 -#define TXOP_VI 3008 -#define TXOP_VO 1504 - -int wl1251_hw_init_hwenc_config(struct wl1251 *wl); -int wl1251_hw_init_templates_config(struct wl1251 *wl); -int wl1251_hw_init_rx_config(struct wl1251 *wl, u32 config, u32 filter); -int wl1251_hw_init_phy_config(struct wl1251 *wl); -int wl1251_hw_init_beacon_filter(struct wl1251 *wl); -int wl1251_hw_init_pta(struct wl1251 *wl); -int wl1251_hw_init_energy_detection(struct wl1251 *wl); -int wl1251_hw_init_beacon_broadcast(struct wl1251 *wl); -int wl1251_hw_init_power_auth(struct wl1251 *wl); -int wl1251_hw_init_mem_config(struct wl1251 *wl); -int wl1251_hw_init(struct wl1251 *wl); - -#endif diff --git a/drivers/net/wireless/wl12xx/wl1251_io.c b/drivers/net/wireless/wl12xx/wl1251_io.c deleted file mode 100644 index ad6ca68..0000000 --- a/drivers/net/wireless/wl12xx/wl1251_io.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (C) 2008 Nokia Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include "wl1251.h" -#include "wl1251_reg.h" -#include "wl1251_io.h" - -/* FIXME: this is static data nowadays and the table can be removed */ -static enum wl12xx_acx_int_reg wl1251_io_reg_table[ACX_REG_TABLE_LEN] = { - [ACX_REG_INTERRUPT_TRIG] = (REGISTERS_BASE + 0x0474), - [ACX_REG_INTERRUPT_TRIG_H] = (REGISTERS_BASE + 0x0478), - [ACX_REG_INTERRUPT_MASK] = (REGISTERS_BASE + 0x0494), - [ACX_REG_HINT_MASK_SET] = (REGISTERS_BASE + 0x0498), - [ACX_REG_HINT_MASK_CLR] = (REGISTERS_BASE + 0x049C), - [ACX_REG_INTERRUPT_NO_CLEAR] = (REGISTERS_BASE + 0x04B0), - [ACX_REG_INTERRUPT_CLEAR] = (REGISTERS_BASE + 0x04A4), - [ACX_REG_INTERRUPT_ACK] = (REGISTERS_BASE + 0x04A8), - [ACX_REG_SLV_SOFT_RESET] = (REGISTERS_BASE + 0x0000), - [ACX_REG_EE_START] = (REGISTERS_BASE + 0x080C), - [ACX_REG_ECPU_CONTROL] = (REGISTERS_BASE + 0x0804) -}; - -static int wl1251_translate_reg_addr(struct wl1251 *wl, int addr) -{ - /* If the address is lower than REGISTERS_BASE, it means that this is - * a chip-specific register address, so look it up in the registers - * table */ - if (addr < REGISTERS_BASE) { - /* Make sure we don't go over the table */ - if (addr >= ACX_REG_TABLE_LEN) { - wl1251_error("address out of range (%d)", addr); - return -EINVAL; - } - addr = wl1251_io_reg_table[addr]; - } - - return addr - wl->physical_reg_addr + wl->virtual_reg_addr; -} - -static int wl1251_translate_mem_addr(struct wl1251 *wl, int addr) -{ - return addr - wl->physical_mem_addr + wl->virtual_mem_addr; -} - -void wl1251_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len) -{ - int physical; - - physical = wl1251_translate_mem_addr(wl, addr); - - wl->if_ops->read(wl, physical, buf, len); -} - -void wl1251_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len) -{ - int physical; - - physical = wl1251_translate_mem_addr(wl, addr); - - wl->if_ops->write(wl, physical, buf, len); -} - -u32 wl1251_mem_read32(struct wl1251 *wl, int addr) -{ - return wl1251_read32(wl, wl1251_translate_mem_addr(wl, addr)); -} - -void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val) -{ - wl1251_write32(wl, wl1251_translate_mem_addr(wl, addr), val); -} - -u32 wl1251_reg_read32(struct wl1251 *wl, int addr) -{ - return wl1251_read32(wl, wl1251_translate_reg_addr(wl, addr)); -} - -void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val) -{ - wl1251_write32(wl, wl1251_translate_reg_addr(wl, addr), val); -} - -/* Set the partitions to access the chip addresses. - * - * There are two VIRTUAL partitions (the memory partition and the - * registers partition), which are mapped to two different areas of the - * PHYSICAL (hardware) memory. This function also makes other checks to - * ensure that the partitions are not overlapping. In the diagram below, the - * memory partition comes before the register partition, but the opposite is - * also supported. - * - * PHYSICAL address - * space - * - * | | - * ...+----+--> mem_start - * VIRTUAL address ... | | - * space ... | | [PART_0] - * ... | | - * 0x00000000 <--+----+... ...+----+--> mem_start + mem_size - * | | ... | | - * |MEM | ... | | - * | | ... | | - * part_size <--+----+... | | {unused area) - * | | ... | | - * |REG | ... | | - * part_size | | ... | | - * + <--+----+... ...+----+--> reg_start - * reg_size ... | | - * ... | | [PART_1] - * ... | | - * ...+----+--> reg_start + reg_size - * | | - * - */ -void wl1251_set_partition(struct wl1251 *wl, - u32 mem_start, u32 mem_size, - u32 reg_start, u32 reg_size) -{ - struct wl1251_partition partition[2]; - - wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", - mem_start, mem_size); - wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", - reg_start, reg_size); - - /* Make sure that the two partitions together don't exceed the - * address range */ - if ((mem_size + reg_size) > HW_ACCESS_MEMORY_MAX_RANGE) { - wl1251_debug(DEBUG_SPI, "Total size exceeds maximum virtual" - " address range. Truncating partition[0]."); - mem_size = HW_ACCESS_MEMORY_MAX_RANGE - reg_size; - wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", - mem_start, mem_size); - wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", - reg_start, reg_size); - } - - if ((mem_start < reg_start) && - ((mem_start + mem_size) > reg_start)) { - /* Guarantee that the memory partition doesn't overlap the - * registers partition */ - wl1251_debug(DEBUG_SPI, "End of partition[0] is " - "overlapping partition[1]. Adjusted."); - mem_size = reg_start - mem_start; - wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", - mem_start, mem_size); - wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", - reg_start, reg_size); - } else if ((reg_start < mem_start) && - ((reg_start + reg_size) > mem_start)) { - /* Guarantee that the register partition doesn't overlap the - * memory partition */ - wl1251_debug(DEBUG_SPI, "End of partition[1] is" - " overlapping partition[0]. Adjusted."); - reg_size = mem_start - reg_start; - wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", - mem_start, mem_size); - wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", - reg_start, reg_size); - } - - partition[0].start = mem_start; - partition[0].size = mem_size; - partition[1].start = reg_start; - partition[1].size = reg_size; - - wl->physical_mem_addr = mem_start; - wl->physical_reg_addr = reg_start; - - wl->virtual_mem_addr = 0; - wl->virtual_reg_addr = mem_size; - - wl->if_ops->write(wl, HW_ACCESS_PART0_SIZE_ADDR, partition, - sizeof(partition)); -} diff --git a/drivers/net/wireless/wl12xx/wl1251_io.h b/drivers/net/wireless/wl12xx/wl1251_io.h deleted file mode 100644 index c545e9d..0000000 --- a/drivers/net/wireless/wl12xx/wl1251_io.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (C) 2008 Nokia Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ -#ifndef __WL1251_IO_H__ -#define __WL1251_IO_H__ - -#include "wl1251.h" - -#define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0 - -#define HW_ACCESS_PART0_SIZE_ADDR 0x1FFC0 -#define HW_ACCESS_PART0_START_ADDR 0x1FFC4 -#define HW_ACCESS_PART1_SIZE_ADDR 0x1FFC8 -#define HW_ACCESS_PART1_START_ADDR 0x1FFCC - -#define HW_ACCESS_REGISTER_SIZE 4 - -#define HW_ACCESS_PRAM_MAX_RANGE 0x3c000 - -static inline u32 wl1251_read32(struct wl1251 *wl, int addr) -{ - u32 response; - - wl->if_ops->read(wl, addr, &response, sizeof(u32)); - - return response; -} - -static inline void wl1251_write32(struct wl1251 *wl, int addr, u32 val) -{ - wl->if_ops->write(wl, addr, &val, sizeof(u32)); -} - -static inline u32 wl1251_read_elp(struct wl1251 *wl, int addr) -{ - u32 response; - - if (wl->if_ops->read_elp) - wl->if_ops->read_elp(wl, addr, &response); - else - wl->if_ops->read(wl, addr, &response, sizeof(u32)); - - return response; -} - -static inline void wl1251_write_elp(struct wl1251 *wl, int addr, u32 val) -{ - if (wl->if_ops->write_elp) - wl->if_ops->write_elp(wl, addr, val); - else - wl->if_ops->write(wl, addr, &val, sizeof(u32)); -} - -/* Memory target IO, address is translated to partition 0 */ -void wl1251_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len); -void wl1251_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len); -u32 wl1251_mem_read32(struct wl1251 *wl, int addr); -void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val); -/* Registers IO */ -u32 wl1251_reg_read32(struct wl1251 *wl, int addr); -void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val); - -void wl1251_set_partition(struct wl1251 *wl, - u32 part_start, u32 part_size, - u32 reg_start, u32 reg_size); - -#endif diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c deleted file mode 100644 index faf221c..0000000 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ /dev/null @@ -1,1435 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (C) 2008-2009 Nokia Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "wl1251.h" -#include "wl12xx_80211.h" -#include "wl1251_reg.h" -#include "wl1251_io.h" -#include "wl1251_cmd.h" -#include "wl1251_event.h" -#include "wl1251_tx.h" -#include "wl1251_rx.h" -#include "wl1251_ps.h" -#include "wl1251_init.h" -#include "wl1251_debugfs.h" -#include "wl1251_boot.h" - -void wl1251_enable_interrupts(struct wl1251 *wl) -{ - wl->if_ops->enable_irq(wl); -} - -void wl1251_disable_interrupts(struct wl1251 *wl) -{ - wl->if_ops->disable_irq(wl); -} - -static void wl1251_power_off(struct wl1251 *wl) -{ - wl->set_power(false); -} - -static void wl1251_power_on(struct wl1251 *wl) -{ - wl->set_power(true); -} - -static int wl1251_fetch_firmware(struct wl1251 *wl) -{ - const struct firmware *fw; - struct device *dev = wiphy_dev(wl->hw->wiphy); - int ret; - - ret = request_firmware(&fw, WL1251_FW_NAME, dev); - - if (ret < 0) { - wl1251_error("could not get firmware: %d", ret); - return ret; - } - - if (fw->size % 4) { - wl1251_error("firmware size is not multiple of 32 bits: %zu", - fw->size); - ret = -EILSEQ; - goto out; - } - - wl->fw_len = fw->size; - wl->fw = vmalloc(wl->fw_len); - - if (!wl->fw) { - wl1251_error("could not allocate memory for the firmware"); - ret = -ENOMEM; - goto out; - } - - memcpy(wl->fw, fw->data, wl->fw_len); - - ret = 0; - -out: - release_firmware(fw); - - return ret; -} - -static int wl1251_fetch_nvs(struct wl1251 *wl) -{ - const struct firmware *fw; - struct device *dev = wiphy_dev(wl->hw->wiphy); - int ret; - - ret = request_firmware(&fw, WL1251_NVS_NAME, dev); - - if (ret < 0) { - wl1251_error("could not get nvs file: %d", ret); - return ret; - } - - if (fw->size % 4) { - wl1251_error("nvs size is not multiple of 32 bits: %zu", - fw->size); - ret = -EILSEQ; - goto out; - } - - wl->nvs_len = fw->size; - wl->nvs = kmemdup(fw->data, wl->nvs_len, GFP_KERNEL); - - if (!wl->nvs) { - wl1251_error("could not allocate memory for the nvs file"); - ret = -ENOMEM; - goto out; - } - - ret = 0; - -out: - release_firmware(fw); - - return ret; -} - -static void wl1251_fw_wakeup(struct wl1251 *wl) -{ - u32 elp_reg; - - elp_reg = ELPCTRL_WAKE_UP; - wl1251_write_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg); - elp_reg = wl1251_read_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); - - if (!(elp_reg & ELPCTRL_WLAN_READY)) - wl1251_warning("WLAN not ready"); -} - -static int wl1251_chip_wakeup(struct wl1251 *wl) -{ - int ret = 0; - - wl1251_power_on(wl); - msleep(WL1251_POWER_ON_SLEEP); - wl->if_ops->reset(wl); - - /* We don't need a real memory partition here, because we only want - * to use the registers at this point. */ - wl1251_set_partition(wl, - 0x00000000, - 0x00000000, - REGISTERS_BASE, - REGISTERS_DOWN_SIZE); - - /* ELP module wake up */ - wl1251_fw_wakeup(wl); - - /* whal_FwCtrl_BootSm() */ - - /* 0. read chip id from CHIP_ID */ - wl->chip_id = wl1251_reg_read32(wl, CHIP_ID_B); - - /* 1. check if chip id is valid */ - - switch (wl->chip_id) { - case CHIP_ID_1251_PG12: - wl1251_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG12)", - wl->chip_id); - break; - case CHIP_ID_1251_PG11: - wl1251_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG11)", - wl->chip_id); - break; - case CHIP_ID_1251_PG10: - default: - wl1251_error("unsupported chip id: 0x%x", wl->chip_id); - ret = -ENODEV; - goto out; - } - - if (wl->fw == NULL) { - ret = wl1251_fetch_firmware(wl); - if (ret < 0) - goto out; - } - - if (wl->nvs == NULL && !wl->use_eeprom) { - /* No NVS from netlink, try to get it from the filesystem */ - ret = wl1251_fetch_nvs(wl); - if (ret < 0) - goto out; - } - -out: - return ret; -} - -#define WL1251_IRQ_LOOP_COUNT 10 -static void wl1251_irq_work(struct work_struct *work) -{ - u32 intr, ctr = WL1251_IRQ_LOOP_COUNT; - struct wl1251 *wl = - container_of(work, struct wl1251, irq_work); - int ret; - - mutex_lock(&wl->mutex); - - wl1251_debug(DEBUG_IRQ, "IRQ work"); - - if (wl->state == WL1251_STATE_OFF) - goto out; - - ret = wl1251_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1251_ACX_INTR_ALL); - - intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); - wl1251_debug(DEBUG_IRQ, "intr: 0x%x", intr); - - do { - if (wl->data_path) { - wl->rx_counter = wl1251_mem_read32( - wl, wl->data_path->rx_control_addr); - - /* We handle a frmware bug here */ - switch ((wl->rx_counter - wl->rx_handled) & 0xf) { - case 0: - wl1251_debug(DEBUG_IRQ, - "RX: FW and host in sync"); - intr &= ~WL1251_ACX_INTR_RX0_DATA; - intr &= ~WL1251_ACX_INTR_RX1_DATA; - break; - case 1: - wl1251_debug(DEBUG_IRQ, "RX: FW +1"); - intr |= WL1251_ACX_INTR_RX0_DATA; - intr &= ~WL1251_ACX_INTR_RX1_DATA; - break; - case 2: - wl1251_debug(DEBUG_IRQ, "RX: FW +2"); - intr |= WL1251_ACX_INTR_RX0_DATA; - intr |= WL1251_ACX_INTR_RX1_DATA; - break; - default: - wl1251_warning( - "RX: FW and host out of sync: %d", - wl->rx_counter - wl->rx_handled); - break; - } - - wl->rx_handled = wl->rx_counter; - - wl1251_debug(DEBUG_IRQ, "RX counter: %d", - wl->rx_counter); - } - - intr &= wl->intr_mask; - - if (intr == 0) { - wl1251_debug(DEBUG_IRQ, "INTR is 0"); - goto out_sleep; - } - - if (intr & WL1251_ACX_INTR_RX0_DATA) { - wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA"); - wl1251_rx(wl); - } - - if (intr & WL1251_ACX_INTR_RX1_DATA) { - wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA"); - wl1251_rx(wl); - } - - if (intr & WL1251_ACX_INTR_TX_RESULT) { - wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT"); - wl1251_tx_complete(wl); - } - - if (intr & WL1251_ACX_INTR_EVENT_A) { - wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT_A"); - wl1251_event_handle(wl, 0); - } - - if (intr & WL1251_ACX_INTR_EVENT_B) { - wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT_B"); - wl1251_event_handle(wl, 1); - } - - if (intr & WL1251_ACX_INTR_INIT_COMPLETE) - wl1251_debug(DEBUG_IRQ, - "WL1251_ACX_INTR_INIT_COMPLETE"); - - if (--ctr == 0) - break; - - intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); - } while (intr); - -out_sleep: - wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); - wl1251_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); -} - -static int wl1251_join(struct wl1251 *wl, u8 bss_type, u8 channel, - u16 beacon_interval, u8 dtim_period) -{ - int ret; - - ret = wl1251_acx_frame_rates(wl, DEFAULT_HW_GEN_TX_RATE, - DEFAULT_HW_GEN_MODULATION_TYPE, - wl->tx_mgmt_frm_rate, - wl->tx_mgmt_frm_mod); - if (ret < 0) - goto out; - - - ret = wl1251_cmd_join(wl, bss_type, channel, beacon_interval, - dtim_period); - if (ret < 0) - goto out; - - ret = wl1251_event_wait(wl, JOIN_EVENT_COMPLETE_ID, 100); - if (ret < 0) - wl1251_warning("join timeout"); - -out: - return ret; -} - -static void wl1251_filter_work(struct work_struct *work) -{ - struct wl1251 *wl = - container_of(work, struct wl1251, filter_work); - int ret; - - mutex_lock(&wl->mutex); - - if (wl->state == WL1251_STATE_OFF) - goto out; - - ret = wl1251_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - ret = wl1251_join(wl, wl->bss_type, wl->channel, wl->beacon_int, - wl->dtim_period); - if (ret < 0) - goto out_sleep; - -out_sleep: - wl1251_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); -} - -static int wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) -{ - struct wl1251 *wl = hw->priv; - unsigned long flags; - - skb_queue_tail(&wl->tx_queue, skb); - - /* - * The chip specific setup must run before the first TX packet - - * before that, the tx_work will not be initialized! - */ - - ieee80211_queue_work(wl->hw, &wl->tx_work); - - /* - * The workqueue is slow to process the tx_queue and we need stop - * the queue here, otherwise the queue will get too long. - */ - if (skb_queue_len(&wl->tx_queue) >= WL1251_TX_QUEUE_HIGH_WATERMARK) { - wl1251_debug(DEBUG_TX, "op_tx: tx_queue full, stop queues"); - - spin_lock_irqsave(&wl->wl_lock, flags); - ieee80211_stop_queues(wl->hw); - wl->tx_queue_stopped = true; - spin_unlock_irqrestore(&wl->wl_lock, flags); - } - - return NETDEV_TX_OK; -} - -static int wl1251_op_start(struct ieee80211_hw *hw) -{ - struct wl1251 *wl = hw->priv; - struct wiphy *wiphy = hw->wiphy; - int ret = 0; - - wl1251_debug(DEBUG_MAC80211, "mac80211 start"); - - mutex_lock(&wl->mutex); - - if (wl->state != WL1251_STATE_OFF) { - wl1251_error("cannot start because not in off state: %d", - wl->state); - ret = -EBUSY; - goto out; - } - - ret = wl1251_chip_wakeup(wl); - if (ret < 0) - goto out; - - ret = wl1251_boot(wl); - if (ret < 0) - goto out; - - ret = wl1251_hw_init(wl); - if (ret < 0) - goto out; - - ret = wl1251_acx_station_id(wl); - if (ret < 0) - goto out; - - wl->state = WL1251_STATE_ON; - - wl1251_info("firmware booted (%s)", wl->fw_ver); - - /* update hw/fw version info in wiphy struct */ - wiphy->hw_version = wl->chip_id; - strncpy(wiphy->fw_version, wl->fw_ver, sizeof(wiphy->fw_version)); - -out: - if (ret < 0) - wl1251_power_off(wl); - - mutex_unlock(&wl->mutex); - - return ret; -} - -static void wl1251_op_stop(struct ieee80211_hw *hw) -{ - struct wl1251 *wl = hw->priv; - - wl1251_info("down"); - - wl1251_debug(DEBUG_MAC80211, "mac80211 stop"); - - mutex_lock(&wl->mutex); - - WARN_ON(wl->state != WL1251_STATE_ON); - - if (wl->scanning) { - ieee80211_scan_completed(wl->hw, true); - wl->scanning = false; - } - - wl->state = WL1251_STATE_OFF; - - wl1251_disable_interrupts(wl); - - mutex_unlock(&wl->mutex); - - cancel_work_sync(&wl->irq_work); - cancel_work_sync(&wl->tx_work); - cancel_work_sync(&wl->filter_work); - - mutex_lock(&wl->mutex); - - /* let's notify MAC80211 about the remaining pending TX frames */ - wl1251_tx_flush(wl); - wl1251_power_off(wl); - - memset(wl->bssid, 0, ETH_ALEN); - wl->listen_int = 1; - wl->bss_type = MAX_BSS_TYPE; - - wl->data_in_count = 0; - wl->rx_counter = 0; - wl->rx_handled = 0; - wl->rx_current_buffer = 0; - wl->rx_last_id = 0; - wl->next_tx_complete = 0; - wl->elp = false; - wl->psm = 0; - wl->tx_queue_stopped = false; - wl->power_level = WL1251_DEFAULT_POWER_LEVEL; - wl->channel = WL1251_DEFAULT_CHANNEL; - - wl1251_debugfs_reset(wl); - - mutex_unlock(&wl->mutex); -} - -static int wl1251_op_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct wl1251 *wl = hw->priv; - int ret = 0; - - wl1251_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", - vif->type, vif->addr); - - mutex_lock(&wl->mutex); - if (wl->vif) { - ret = -EBUSY; - goto out; - } - - wl->vif = vif; - - switch (vif->type) { - case NL80211_IFTYPE_STATION: - wl->bss_type = BSS_TYPE_STA_BSS; - break; - case NL80211_IFTYPE_ADHOC: - wl->bss_type = BSS_TYPE_IBSS; - break; - default: - ret = -EOPNOTSUPP; - goto out; - } - - if (memcmp(wl->mac_addr, vif->addr, ETH_ALEN)) { - memcpy(wl->mac_addr, vif->addr, ETH_ALEN); - SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); - ret = wl1251_acx_station_id(wl); - if (ret < 0) - goto out; - } - -out: - mutex_unlock(&wl->mutex); - return ret; -} - -static void wl1251_op_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct wl1251 *wl = hw->priv; - - mutex_lock(&wl->mutex); - wl1251_debug(DEBUG_MAC80211, "mac80211 remove interface"); - wl->vif = NULL; - mutex_unlock(&wl->mutex); -} - -static int wl1251_build_qos_null_data(struct wl1251 *wl) -{ - struct ieee80211_qos_hdr template; - - memset(&template, 0, sizeof(template)); - - memcpy(template.addr1, wl->bssid, ETH_ALEN); - memcpy(template.addr2, wl->mac_addr, ETH_ALEN); - memcpy(template.addr3, wl->bssid, ETH_ALEN); - - template.frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | - IEEE80211_STYPE_QOS_NULLFUNC | - IEEE80211_FCTL_TODS); - - /* FIXME: not sure what priority to use here */ - template.qos_ctrl = cpu_to_le16(0); - - return wl1251_cmd_template_set(wl, CMD_QOS_NULL_DATA, &template, - sizeof(template)); -} - -static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) -{ - struct wl1251 *wl = hw->priv; - struct ieee80211_conf *conf = &hw->conf; - int channel, ret = 0; - - channel = ieee80211_frequency_to_channel(conf->channel->center_freq); - - wl1251_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d", - channel, - conf->flags & IEEE80211_CONF_PS ? "on" : "off", - conf->power_level); - - mutex_lock(&wl->mutex); - - ret = wl1251_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - if (channel != wl->channel) { - wl->channel = channel; - - ret = wl1251_join(wl, wl->bss_type, wl->channel, - wl->beacon_int, wl->dtim_period); - if (ret < 0) - goto out_sleep; - } - - if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) { - wl1251_debug(DEBUG_PSM, "psm enabled"); - - wl->psm_requested = true; - - wl->dtim_period = conf->ps_dtim_period; - - ret = wl1251_acx_wr_tbtt_and_dtim(wl, wl->beacon_int, - wl->dtim_period); - - /* - * mac80211 enables PSM only if we're already associated. - */ - ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE); - if (ret < 0) - goto out_sleep; - } else if (!(conf->flags & IEEE80211_CONF_PS) && - wl->psm_requested) { - wl1251_debug(DEBUG_PSM, "psm disabled"); - - wl->psm_requested = false; - - if (wl->psm) { - ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE); - if (ret < 0) - goto out_sleep; - } - } - - if (conf->power_level != wl->power_level) { - ret = wl1251_acx_tx_power(wl, conf->power_level); - if (ret < 0) - goto out_sleep; - - wl->power_level = conf->power_level; - } - -out_sleep: - wl1251_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); - - return ret; -} - -#define WL1251_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ - FIF_ALLMULTI | \ - FIF_FCSFAIL | \ - FIF_BCN_PRBRESP_PROMISC | \ - FIF_CONTROL | \ - FIF_OTHER_BSS) - -static void wl1251_op_configure_filter(struct ieee80211_hw *hw, - unsigned int changed, - unsigned int *total,u64 multicast) -{ - struct wl1251 *wl = hw->priv; - - wl1251_debug(DEBUG_MAC80211, "mac80211 configure filter"); - - *total &= WL1251_SUPPORTED_FILTERS; - changed &= WL1251_SUPPORTED_FILTERS; - - if (changed == 0) - /* no filters which we support changed */ - return; - - /* FIXME: wl->rx_config and wl->rx_filter are not protected */ - - wl->rx_config = WL1251_DEFAULT_RX_CONFIG; - wl->rx_filter = WL1251_DEFAULT_RX_FILTER; - - if (*total & FIF_PROMISC_IN_BSS) { - wl->rx_config |= CFG_BSSID_FILTER_EN; - wl->rx_config |= CFG_RX_ALL_GOOD; - } - if (*total & FIF_ALLMULTI) - /* - * CFG_MC_FILTER_EN in rx_config needs to be 0 to receive - * all multicast frames - */ - wl->rx_config &= ~CFG_MC_FILTER_EN; - if (*total & FIF_FCSFAIL) - wl->rx_filter |= CFG_RX_FCS_ERROR; - if (*total & FIF_BCN_PRBRESP_PROMISC) { - wl->rx_config &= ~CFG_BSSID_FILTER_EN; - wl->rx_config &= ~CFG_SSID_FILTER_EN; - } - if (*total & FIF_CONTROL) - wl->rx_filter |= CFG_RX_CTL_EN; - if (*total & FIF_OTHER_BSS) - wl->rx_filter &= ~CFG_BSSID_FILTER_EN; - - /* - * FIXME: workqueues need to be properly cancelled on stop(), for - * now let's just disable changing the filter settings. They will - * be updated any on config(). - */ - /* schedule_work(&wl->filter_work); */ -} - -/* HW encryption */ -static int wl1251_set_key_type(struct wl1251 *wl, - struct wl1251_cmd_set_keys *key, - enum set_key_cmd cmd, - struct ieee80211_key_conf *mac80211_key, - const u8 *addr) -{ - switch (mac80211_key->cipher) { - case WLAN_CIPHER_SUITE_WEP40: - case WLAN_CIPHER_SUITE_WEP104: - if (is_broadcast_ether_addr(addr)) - key->key_type = KEY_WEP_DEFAULT; - else - key->key_type = KEY_WEP_ADDR; - - mac80211_key->hw_key_idx = mac80211_key->keyidx; - break; - case WLAN_CIPHER_SUITE_TKIP: - if (is_broadcast_ether_addr(addr)) - key->key_type = KEY_TKIP_MIC_GROUP; - else - key->key_type = KEY_TKIP_MIC_PAIRWISE; - - mac80211_key->hw_key_idx = mac80211_key->keyidx; - break; - case WLAN_CIPHER_SUITE_CCMP: - if (is_broadcast_ether_addr(addr)) - key->key_type = KEY_AES_GROUP; - else - key->key_type = KEY_AES_PAIRWISE; - mac80211_key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; - break; - default: - wl1251_error("Unknown key cipher 0x%x", mac80211_key->cipher); - return -EOPNOTSUPP; - } - - return 0; -} - -static int wl1251_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct ieee80211_key_conf *key) -{ - struct wl1251 *wl = hw->priv; - struct wl1251_cmd_set_keys *wl_cmd; - const u8 *addr; - int ret; - - static const u8 bcast_addr[ETH_ALEN] = - { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - - wl1251_debug(DEBUG_MAC80211, "mac80211 set key"); - - wl_cmd = kzalloc(sizeof(*wl_cmd), GFP_KERNEL); - if (!wl_cmd) { - ret = -ENOMEM; - goto out; - } - - addr = sta ? sta->addr : bcast_addr; - - wl1251_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd); - wl1251_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN); - wl1251_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x", - key->cipher, key->keyidx, key->keylen, key->flags); - wl1251_dump(DEBUG_CRYPT, "KEY: ", key->key, key->keylen); - - if (is_zero_ether_addr(addr)) { - /* We dont support TX only encryption */ - ret = -EOPNOTSUPP; - goto out; - } - - mutex_lock(&wl->mutex); - - ret = wl1251_ps_elp_wakeup(wl); - if (ret < 0) - goto out_unlock; - - switch (cmd) { - case SET_KEY: - wl_cmd->key_action = KEY_ADD_OR_REPLACE; - break; - case DISABLE_KEY: - wl_cmd->key_action = KEY_REMOVE; - break; - default: - wl1251_error("Unsupported key cmd 0x%x", cmd); - break; - } - - ret = wl1251_set_key_type(wl, wl_cmd, cmd, key, addr); - if (ret < 0) { - wl1251_error("Set KEY type failed"); - goto out_sleep; - } - - if (wl_cmd->key_type != KEY_WEP_DEFAULT) - memcpy(wl_cmd->addr, addr, ETH_ALEN); - - if ((wl_cmd->key_type == KEY_TKIP_MIC_GROUP) || - (wl_cmd->key_type == KEY_TKIP_MIC_PAIRWISE)) { - /* - * We get the key in the following form: - * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes) - * but the target is expecting: - * TKIP - RX MIC - TX MIC - */ - memcpy(wl_cmd->key, key->key, 16); - memcpy(wl_cmd->key + 16, key->key + 24, 8); - memcpy(wl_cmd->key + 24, key->key + 16, 8); - - } else { - memcpy(wl_cmd->key, key->key, key->keylen); - } - wl_cmd->key_size = key->keylen; - - wl_cmd->id = key->keyidx; - wl_cmd->ssid_profile = 0; - - wl1251_dump(DEBUG_CRYPT, "TARGET KEY: ", wl_cmd, sizeof(*wl_cmd)); - - ret = wl1251_cmd_send(wl, CMD_SET_KEYS, wl_cmd, sizeof(*wl_cmd)); - if (ret < 0) { - wl1251_warning("could not set keys"); - goto out_sleep; - } - -out_sleep: - wl1251_ps_elp_sleep(wl); - -out_unlock: - mutex_unlock(&wl->mutex); - -out: - kfree(wl_cmd); - - return ret; -} - -static int wl1251_op_hw_scan(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct cfg80211_scan_request *req) -{ - struct wl1251 *wl = hw->priv; - struct sk_buff *skb; - size_t ssid_len = 0; - u8 *ssid = NULL; - int ret; - - wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan"); - - if (req->n_ssids) { - ssid = req->ssids[0].ssid; - ssid_len = req->ssids[0].ssid_len; - } - - mutex_lock(&wl->mutex); - - if (wl->scanning) { - wl1251_debug(DEBUG_SCAN, "scan already in progress"); - ret = -EINVAL; - goto out; - } - - ret = wl1251_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - skb = ieee80211_probereq_get(wl->hw, wl->vif, ssid, ssid_len, - req->ie, req->ie_len); - if (!skb) { - ret = -ENOMEM; - goto out; - } - - ret = wl1251_cmd_template_set(wl, CMD_PROBE_REQ, skb->data, - skb->len); - dev_kfree_skb(skb); - if (ret < 0) - goto out_sleep; - - ret = wl1251_cmd_trigger_scan_to(wl, 0); - if (ret < 0) - goto out_sleep; - - wl->scanning = true; - - ret = wl1251_cmd_scan(wl, ssid, ssid_len, req->channels, - req->n_channels, WL1251_SCAN_NUM_PROBES); - if (ret < 0) { - wl->scanning = false; - goto out_sleep; - } - -out_sleep: - wl1251_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); - - return ret; -} - -static int wl1251_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) -{ - struct wl1251 *wl = hw->priv; - int ret; - - mutex_lock(&wl->mutex); - - ret = wl1251_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - ret = wl1251_acx_rts_threshold(wl, (u16) value); - if (ret < 0) - wl1251_warning("wl1251_op_set_rts_threshold failed: %d", ret); - - wl1251_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); - - return ret; -} - -static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, - u32 changed) -{ - struct wl1251 *wl = hw->priv; - struct sk_buff *beacon, *skb; - int ret; - - wl1251_debug(DEBUG_MAC80211, "mac80211 bss info changed"); - - mutex_lock(&wl->mutex); - - ret = wl1251_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - if (changed & BSS_CHANGED_BSSID) { - memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN); - - skb = ieee80211_nullfunc_get(wl->hw, wl->vif); - if (!skb) - goto out_sleep; - - ret = wl1251_cmd_template_set(wl, CMD_NULL_DATA, - skb->data, skb->len); - dev_kfree_skb(skb); - if (ret < 0) - goto out_sleep; - - ret = wl1251_build_qos_null_data(wl); - if (ret < 0) - goto out; - - if (wl->bss_type != BSS_TYPE_IBSS) { - ret = wl1251_join(wl, wl->bss_type, wl->channel, - wl->beacon_int, wl->dtim_period); - if (ret < 0) - goto out_sleep; - } - } - - if (changed & BSS_CHANGED_ASSOC) { - if (bss_conf->assoc) { - wl->beacon_int = bss_conf->beacon_int; - - skb = ieee80211_pspoll_get(wl->hw, wl->vif); - if (!skb) - goto out_sleep; - - ret = wl1251_cmd_template_set(wl, CMD_PS_POLL, - skb->data, - skb->len); - dev_kfree_skb(skb); - if (ret < 0) - goto out_sleep; - - ret = wl1251_acx_aid(wl, bss_conf->aid); - if (ret < 0) - goto out_sleep; - } else { - /* use defaults when not associated */ - wl->beacon_int = WL1251_DEFAULT_BEACON_INT; - wl->dtim_period = WL1251_DEFAULT_DTIM_PERIOD; - } - } - if (changed & BSS_CHANGED_ERP_SLOT) { - if (bss_conf->use_short_slot) - ret = wl1251_acx_slot(wl, SLOT_TIME_SHORT); - else - ret = wl1251_acx_slot(wl, SLOT_TIME_LONG); - if (ret < 0) { - wl1251_warning("Set slot time failed %d", ret); - goto out_sleep; - } - } - - if (changed & BSS_CHANGED_ERP_PREAMBLE) { - if (bss_conf->use_short_preamble) - wl1251_acx_set_preamble(wl, ACX_PREAMBLE_SHORT); - else - wl1251_acx_set_preamble(wl, ACX_PREAMBLE_LONG); - } - - if (changed & BSS_CHANGED_ERP_CTS_PROT) { - if (bss_conf->use_cts_prot) - ret = wl1251_acx_cts_protect(wl, CTSPROTECT_ENABLE); - else - ret = wl1251_acx_cts_protect(wl, CTSPROTECT_DISABLE); - if (ret < 0) { - wl1251_warning("Set ctsprotect failed %d", ret); - goto out_sleep; - } - } - - if (changed & BSS_CHANGED_BEACON) { - beacon = ieee80211_beacon_get(hw, vif); - ret = wl1251_cmd_template_set(wl, CMD_BEACON, beacon->data, - beacon->len); - - if (ret < 0) { - dev_kfree_skb(beacon); - goto out_sleep; - } - - ret = wl1251_cmd_template_set(wl, CMD_PROBE_RESP, beacon->data, - beacon->len); - - dev_kfree_skb(beacon); - - if (ret < 0) - goto out_sleep; - - ret = wl1251_join(wl, wl->bss_type, wl->beacon_int, - wl->channel, wl->dtim_period); - - if (ret < 0) - goto out_sleep; - } - -out_sleep: - wl1251_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); -} - - -/* can't be const, mac80211 writes to this */ -static struct ieee80211_rate wl1251_rates[] = { - { .bitrate = 10, - .hw_value = 0x1, - .hw_value_short = 0x1, }, - { .bitrate = 20, - .hw_value = 0x2, - .hw_value_short = 0x2, - .flags = IEEE80211_RATE_SHORT_PREAMBLE }, - { .bitrate = 55, - .hw_value = 0x4, - .hw_value_short = 0x4, - .flags = IEEE80211_RATE_SHORT_PREAMBLE }, - { .bitrate = 110, - .hw_value = 0x20, - .hw_value_short = 0x20, - .flags = IEEE80211_RATE_SHORT_PREAMBLE }, - { .bitrate = 60, - .hw_value = 0x8, - .hw_value_short = 0x8, }, - { .bitrate = 90, - .hw_value = 0x10, - .hw_value_short = 0x10, }, - { .bitrate = 120, - .hw_value = 0x40, - .hw_value_short = 0x40, }, - { .bitrate = 180, - .hw_value = 0x80, - .hw_value_short = 0x80, }, - { .bitrate = 240, - .hw_value = 0x200, - .hw_value_short = 0x200, }, - { .bitrate = 360, - .hw_value = 0x400, - .hw_value_short = 0x400, }, - { .bitrate = 480, - .hw_value = 0x800, - .hw_value_short = 0x800, }, - { .bitrate = 540, - .hw_value = 0x1000, - .hw_value_short = 0x1000, }, -}; - -/* can't be const, mac80211 writes to this */ -static struct ieee80211_channel wl1251_channels[] = { - { .hw_value = 1, .center_freq = 2412}, - { .hw_value = 2, .center_freq = 2417}, - { .hw_value = 3, .center_freq = 2422}, - { .hw_value = 4, .center_freq = 2427}, - { .hw_value = 5, .center_freq = 2432}, - { .hw_value = 6, .center_freq = 2437}, - { .hw_value = 7, .center_freq = 2442}, - { .hw_value = 8, .center_freq = 2447}, - { .hw_value = 9, .center_freq = 2452}, - { .hw_value = 10, .center_freq = 2457}, - { .hw_value = 11, .center_freq = 2462}, - { .hw_value = 12, .center_freq = 2467}, - { .hw_value = 13, .center_freq = 2472}, -}; - -static int wl1251_op_conf_tx(struct ieee80211_hw *hw, u16 queue, - const struct ieee80211_tx_queue_params *params) -{ - enum wl1251_acx_ps_scheme ps_scheme; - struct wl1251 *wl = hw->priv; - int ret; - - mutex_lock(&wl->mutex); - - wl1251_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue); - - ret = wl1251_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - /* mac80211 uses units of 32 usec */ - ret = wl1251_acx_ac_cfg(wl, wl1251_tx_get_queue(queue), - params->cw_min, params->cw_max, - params->aifs, params->txop * 32); - if (ret < 0) - goto out_sleep; - - if (params->uapsd) - ps_scheme = WL1251_ACX_PS_SCHEME_UPSD_TRIGGER; - else - ps_scheme = WL1251_ACX_PS_SCHEME_LEGACY; - - ret = wl1251_acx_tid_cfg(wl, wl1251_tx_get_queue(queue), - CHANNEL_TYPE_EDCF, - wl1251_tx_get_queue(queue), ps_scheme, - WL1251_ACX_ACK_POLICY_LEGACY); - if (ret < 0) - goto out_sleep; - -out_sleep: - wl1251_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); - - return ret; -} - -static int wl1251_op_get_survey(struct ieee80211_hw *hw, int idx, - struct survey_info *survey) -{ - struct wl1251 *wl = hw->priv; - struct ieee80211_conf *conf = &hw->conf; - - if (idx != 0) - return -ENOENT; - - survey->channel = conf->channel; - survey->filled = SURVEY_INFO_NOISE_DBM; - survey->noise = wl->noise; - - return 0; -} - -/* can't be const, mac80211 writes to this */ -static struct ieee80211_supported_band wl1251_band_2ghz = { - .channels = wl1251_channels, - .n_channels = ARRAY_SIZE(wl1251_channels), - .bitrates = wl1251_rates, - .n_bitrates = ARRAY_SIZE(wl1251_rates), -}; - -static const struct ieee80211_ops wl1251_ops = { - .start = wl1251_op_start, - .stop = wl1251_op_stop, - .add_interface = wl1251_op_add_interface, - .remove_interface = wl1251_op_remove_interface, - .config = wl1251_op_config, - .configure_filter = wl1251_op_configure_filter, - .tx = wl1251_op_tx, - .set_key = wl1251_op_set_key, - .hw_scan = wl1251_op_hw_scan, - .bss_info_changed = wl1251_op_bss_info_changed, - .set_rts_threshold = wl1251_op_set_rts_threshold, - .conf_tx = wl1251_op_conf_tx, - .get_survey = wl1251_op_get_survey, -}; - -static int wl1251_read_eeprom_byte(struct wl1251 *wl, off_t offset, u8 *data) -{ - unsigned long timeout; - - wl1251_reg_write32(wl, EE_ADDR, offset); - wl1251_reg_write32(wl, EE_CTL, EE_CTL_READ); - - /* EE_CTL_READ clears when data is ready */ - timeout = jiffies + msecs_to_jiffies(100); - while (1) { - if (!(wl1251_reg_read32(wl, EE_CTL) & EE_CTL_READ)) - break; - - if (time_after(jiffies, timeout)) - return -ETIMEDOUT; - - msleep(1); - } - - *data = wl1251_reg_read32(wl, EE_DATA); - return 0; -} - -static int wl1251_read_eeprom(struct wl1251 *wl, off_t offset, - u8 *data, size_t len) -{ - size_t i; - int ret; - - wl1251_reg_write32(wl, EE_START, 0); - - for (i = 0; i < len; i++) { - ret = wl1251_read_eeprom_byte(wl, offset + i, &data[i]); - if (ret < 0) - return ret; - } - - return 0; -} - -static int wl1251_read_eeprom_mac(struct wl1251 *wl) -{ - u8 mac[ETH_ALEN]; - int i, ret; - - wl1251_set_partition(wl, 0, 0, REGISTERS_BASE, REGISTERS_DOWN_SIZE); - - ret = wl1251_read_eeprom(wl, 0x1c, mac, sizeof(mac)); - if (ret < 0) { - wl1251_warning("failed to read MAC address from EEPROM"); - return ret; - } - - /* MAC is stored in reverse order */ - for (i = 0; i < ETH_ALEN; i++) - wl->mac_addr[i] = mac[ETH_ALEN - i - 1]; - - return 0; -} - -static int wl1251_register_hw(struct wl1251 *wl) -{ - int ret; - - if (wl->mac80211_registered) - return 0; - - SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); - - ret = ieee80211_register_hw(wl->hw); - if (ret < 0) { - wl1251_error("unable to register mac80211 hw: %d", ret); - return ret; - } - - wl->mac80211_registered = true; - - wl1251_notice("loaded"); - - return 0; -} - -int wl1251_init_ieee80211(struct wl1251 *wl) -{ - int ret; - - /* The tx descriptor buffer and the TKIP space */ - wl->hw->extra_tx_headroom = sizeof(struct tx_double_buffer_desc) - + WL1251_TKIP_IV_SPACE; - - /* unit us */ - /* FIXME: find a proper value */ - wl->hw->channel_change_time = 10000; - - wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_SUPPORTS_PS | - IEEE80211_HW_BEACON_FILTER | - IEEE80211_HW_SUPPORTS_UAPSD; - - wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); - wl->hw->wiphy->max_scan_ssids = 1; - wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1251_band_2ghz; - - wl->hw->queues = 4; - - if (wl->use_eeprom) - wl1251_read_eeprom_mac(wl); - - ret = wl1251_register_hw(wl); - if (ret) - goto out; - - wl1251_debugfs_init(wl); - wl1251_notice("initialized"); - - ret = 0; - -out: - return ret; -} -EXPORT_SYMBOL_GPL(wl1251_init_ieee80211); - -struct ieee80211_hw *wl1251_alloc_hw(void) -{ - struct ieee80211_hw *hw; - struct wl1251 *wl; - int i; - static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf}; - - hw = ieee80211_alloc_hw(sizeof(*wl), &wl1251_ops); - if (!hw) { - wl1251_error("could not alloc ieee80211_hw"); - return ERR_PTR(-ENOMEM); - } - - wl = hw->priv; - memset(wl, 0, sizeof(*wl)); - - wl->hw = hw; - - wl->data_in_count = 0; - - skb_queue_head_init(&wl->tx_queue); - - INIT_WORK(&wl->filter_work, wl1251_filter_work); - INIT_DELAYED_WORK(&wl->elp_work, wl1251_elp_work); - wl->channel = WL1251_DEFAULT_CHANNEL; - wl->scanning = false; - wl->default_key = 0; - wl->listen_int = 1; - wl->rx_counter = 0; - wl->rx_handled = 0; - wl->rx_current_buffer = 0; - wl->rx_last_id = 0; - wl->rx_config = WL1251_DEFAULT_RX_CONFIG; - wl->rx_filter = WL1251_DEFAULT_RX_FILTER; - wl->elp = false; - wl->psm = 0; - wl->psm_requested = false; - wl->tx_queue_stopped = false; - wl->power_level = WL1251_DEFAULT_POWER_LEVEL; - wl->beacon_int = WL1251_DEFAULT_BEACON_INT; - wl->dtim_period = WL1251_DEFAULT_DTIM_PERIOD; - wl->vif = NULL; - - for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) - wl->tx_frames[i] = NULL; - - wl->next_tx_complete = 0; - - INIT_WORK(&wl->irq_work, wl1251_irq_work); - INIT_WORK(&wl->tx_work, wl1251_tx_work); - - /* - * In case our MAC address is not correctly set, - * we use a random but Nokia MAC. - */ - memcpy(wl->mac_addr, nokia_oui, 3); - get_random_bytes(wl->mac_addr + 3, 3); - - wl->state = WL1251_STATE_OFF; - mutex_init(&wl->mutex); - - wl->tx_mgmt_frm_rate = DEFAULT_HW_GEN_TX_RATE; - wl->tx_mgmt_frm_mod = DEFAULT_HW_GEN_MODULATION_TYPE; - - wl->rx_descriptor = kmalloc(sizeof(*wl->rx_descriptor), GFP_KERNEL); - if (!wl->rx_descriptor) { - wl1251_error("could not allocate memory for rx descriptor"); - ieee80211_free_hw(hw); - return ERR_PTR(-ENOMEM); - } - - return hw; -} -EXPORT_SYMBOL_GPL(wl1251_alloc_hw); - -int wl1251_free_hw(struct wl1251 *wl) -{ - ieee80211_unregister_hw(wl->hw); - - wl1251_debugfs_exit(wl); - - kfree(wl->target_mem_map); - kfree(wl->data_path); - vfree(wl->fw); - wl->fw = NULL; - kfree(wl->nvs); - wl->nvs = NULL; - - kfree(wl->rx_descriptor); - wl->rx_descriptor = NULL; - - ieee80211_free_hw(wl->hw); - - return 0; -} -EXPORT_SYMBOL_GPL(wl1251_free_hw); - -MODULE_DESCRIPTION("TI wl1251 Wireles LAN Driver Core"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Kalle Valo "); -MODULE_FIRMWARE(WL1251_FW_NAME); diff --git a/drivers/net/wireless/wl12xx/wl1251_ps.c b/drivers/net/wireless/wl12xx/wl1251_ps.c deleted file mode 100644 index 0b997bd..0000000 --- a/drivers/net/wireless/wl12xx/wl1251_ps.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (C) 2008 Nokia Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include "wl1251_reg.h" -#include "wl1251_ps.h" -#include "wl1251_cmd.h" -#include "wl1251_io.h" - -/* in ms */ -#define WL1251_WAKEUP_TIMEOUT 100 - -void wl1251_elp_work(struct work_struct *work) -{ - struct delayed_work *dwork; - struct wl1251 *wl; - - dwork = container_of(work, struct delayed_work, work); - wl = container_of(dwork, struct wl1251, elp_work); - - wl1251_debug(DEBUG_PSM, "elp work"); - - mutex_lock(&wl->mutex); - - if (wl->elp || !wl->psm) - goto out; - - wl1251_debug(DEBUG_PSM, "chip to elp"); - wl1251_write_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); - wl->elp = true; - -out: - mutex_unlock(&wl->mutex); -} - -#define ELP_ENTRY_DELAY 5 - -/* Routines to toggle sleep mode while in ELP */ -void wl1251_ps_elp_sleep(struct wl1251 *wl) -{ - unsigned long delay; - - if (wl->psm) { - cancel_delayed_work(&wl->elp_work); - delay = msecs_to_jiffies(ELP_ENTRY_DELAY); - ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, delay); - } -} - -int wl1251_ps_elp_wakeup(struct wl1251 *wl) -{ - unsigned long timeout, start; - u32 elp_reg; - - if (!wl->elp) - return 0; - - wl1251_debug(DEBUG_PSM, "waking up chip from elp"); - - start = jiffies; - timeout = jiffies + msecs_to_jiffies(WL1251_WAKEUP_TIMEOUT); - - wl1251_write_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP); - - elp_reg = wl1251_read_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); - - /* - * FIXME: we should wait for irq from chip but, as a temporary - * solution to simplify locking, let's poll instead - */ - while (!(elp_reg & ELPCTRL_WLAN_READY)) { - if (time_after(jiffies, timeout)) { - wl1251_error("elp wakeup timeout"); - return -ETIMEDOUT; - } - msleep(1); - elp_reg = wl1251_read_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); - } - - wl1251_debug(DEBUG_PSM, "wakeup time: %u ms", - jiffies_to_msecs(jiffies - start)); - - wl->elp = false; - - return 0; -} - -static int wl1251_ps_set_elp(struct wl1251 *wl, bool enable) -{ - int ret; - - if (enable) { - wl1251_debug(DEBUG_PSM, "sleep auth psm/elp"); - - ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_ELP); - if (ret < 0) - return ret; - - wl1251_ps_elp_sleep(wl); - } else { - wl1251_debug(DEBUG_PSM, "sleep auth cam"); - - /* - * When the target is in ELP, we can only - * access the ELP control register. Thus, - * we have to wake the target up before - * changing the power authorization. - */ - - wl1251_ps_elp_wakeup(wl); - - ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM); - if (ret < 0) - return ret; - } - - return 0; -} - -int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode) -{ - int ret; - - switch (mode) { - case STATION_POWER_SAVE_MODE: - wl1251_debug(DEBUG_PSM, "entering psm"); - - /* enable beacon filtering */ - ret = wl1251_acx_beacon_filter_opt(wl, true); - if (ret < 0) - return ret; - - ret = wl1251_acx_wake_up_conditions(wl, - WAKE_UP_EVENT_DTIM_BITMAP, - wl->listen_int); - if (ret < 0) - return ret; - - ret = wl1251_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE); - if (ret < 0) - return ret; - - ret = wl1251_ps_set_elp(wl, true); - if (ret < 0) - return ret; - - wl->psm = 1; - break; - case STATION_ACTIVE_MODE: - default: - wl1251_debug(DEBUG_PSM, "leaving psm"); - ret = wl1251_ps_set_elp(wl, false); - if (ret < 0) - return ret; - - /* disable beacon filtering */ - ret = wl1251_acx_beacon_filter_opt(wl, false); - if (ret < 0) - return ret; - - ret = wl1251_acx_wake_up_conditions(wl, - WAKE_UP_EVENT_DTIM_BITMAP, - wl->listen_int); - if (ret < 0) - return ret; - - ret = wl1251_cmd_ps_mode(wl, STATION_ACTIVE_MODE); - if (ret < 0) - return ret; - - wl->psm = 0; - break; - } - - return ret; -} - diff --git a/drivers/net/wireless/wl12xx/wl1251_ps.h b/drivers/net/wireless/wl12xx/wl1251_ps.h deleted file mode 100644 index e5db81f..0000000 --- a/drivers/net/wireless/wl12xx/wl1251_ps.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL1251_PS_H__ -#define __WL1251_PS_H__ - -#include "wl1251.h" -#include "wl1251_acx.h" - -int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode); -void wl1251_ps_elp_sleep(struct wl1251 *wl); -int wl1251_ps_elp_wakeup(struct wl1251 *wl); -void wl1251_elp_work(struct work_struct *work); - - -#endif /* __WL1251_PS_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1251_reg.h b/drivers/net/wireless/wl12xx/wl1251_reg.h deleted file mode 100644 index a580901..0000000 --- a/drivers/net/wireless/wl12xx/wl1251_reg.h +++ /dev/null @@ -1,655 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __REG_H__ -#define __REG_H__ - -#include - -#define REGISTERS_BASE 0x00300000 -#define DRPW_BASE 0x00310000 - -#define REGISTERS_DOWN_SIZE 0x00008800 -#define REGISTERS_WORK_SIZE 0x0000b000 - -#define HW_ACCESS_ELP_CTRL_REG_ADDR 0x1FFFC - -/* ELP register commands */ -#define ELPCTRL_WAKE_UP 0x1 -#define ELPCTRL_WAKE_UP_WLAN_READY 0x5 -#define ELPCTRL_SLEEP 0x0 -/* ELP WLAN_READY bit */ -#define ELPCTRL_WLAN_READY 0x2 - -/* Device Configuration registers*/ -#define SOR_CFG (REGISTERS_BASE + 0x0800) -#define ECPU_CTRL (REGISTERS_BASE + 0x0804) -#define HI_CFG (REGISTERS_BASE + 0x0808) - -/* EEPROM registers */ -#define EE_START (REGISTERS_BASE + 0x080C) -#define EE_CTL (REGISTERS_BASE + 0x2000) -#define EE_DATA (REGISTERS_BASE + 0x2004) -#define EE_ADDR (REGISTERS_BASE + 0x2008) - -#define EE_CTL_READ 2 - -#define CHIP_ID_B (REGISTERS_BASE + 0x5674) - -#define CHIP_ID_1251_PG10 (0x7010101) -#define CHIP_ID_1251_PG11 (0x7020101) -#define CHIP_ID_1251_PG12 (0x7030101) - -#define ENABLE (REGISTERS_BASE + 0x5450) - -/* Power Management registers */ -#define ELP_CFG_MODE (REGISTERS_BASE + 0x5804) -#define ELP_CMD (REGISTERS_BASE + 0x5808) -#define PLL_CAL_TIME (REGISTERS_BASE + 0x5810) -#define CLK_REQ_TIME (REGISTERS_BASE + 0x5814) -#define CLK_BUF_TIME (REGISTERS_BASE + 0x5818) - -#define CFG_PLL_SYNC_CNT (REGISTERS_BASE + 0x5820) - -/* Scratch Pad registers*/ -#define SCR_PAD0 (REGISTERS_BASE + 0x5608) -#define SCR_PAD1 (REGISTERS_BASE + 0x560C) -#define SCR_PAD2 (REGISTERS_BASE + 0x5610) -#define SCR_PAD3 (REGISTERS_BASE + 0x5614) -#define SCR_PAD4 (REGISTERS_BASE + 0x5618) -#define SCR_PAD4_SET (REGISTERS_BASE + 0x561C) -#define SCR_PAD4_CLR (REGISTERS_BASE + 0x5620) -#define SCR_PAD5 (REGISTERS_BASE + 0x5624) -#define SCR_PAD5_SET (REGISTERS_BASE + 0x5628) -#define SCR_PAD5_CLR (REGISTERS_BASE + 0x562C) -#define SCR_PAD6 (REGISTERS_BASE + 0x5630) -#define SCR_PAD7 (REGISTERS_BASE + 0x5634) -#define SCR_PAD8 (REGISTERS_BASE + 0x5638) -#define SCR_PAD9 (REGISTERS_BASE + 0x563C) - -/* Spare registers*/ -#define SPARE_A1 (REGISTERS_BASE + 0x0994) -#define SPARE_A2 (REGISTERS_BASE + 0x0998) -#define SPARE_A3 (REGISTERS_BASE + 0x099C) -#define SPARE_A4 (REGISTERS_BASE + 0x09A0) -#define SPARE_A5 (REGISTERS_BASE + 0x09A4) -#define SPARE_A6 (REGISTERS_BASE + 0x09A8) -#define SPARE_A7 (REGISTERS_BASE + 0x09AC) -#define SPARE_A8 (REGISTERS_BASE + 0x09B0) -#define SPARE_B1 (REGISTERS_BASE + 0x5420) -#define SPARE_B2 (REGISTERS_BASE + 0x5424) -#define SPARE_B3 (REGISTERS_BASE + 0x5428) -#define SPARE_B4 (REGISTERS_BASE + 0x542C) -#define SPARE_B5 (REGISTERS_BASE + 0x5430) -#define SPARE_B6 (REGISTERS_BASE + 0x5434) -#define SPARE_B7 (REGISTERS_BASE + 0x5438) -#define SPARE_B8 (REGISTERS_BASE + 0x543C) - -enum wl12xx_acx_int_reg { - ACX_REG_INTERRUPT_TRIG, - ACX_REG_INTERRUPT_TRIG_H, - -/*============================================= - Host Interrupt Mask Register - 32bit (RW) - ------------------------------------------ - Setting a bit in this register masks the - corresponding interrupt to the host. - 0 - RX0 - Rx first dubble buffer Data Interrupt - 1 - TXD - Tx Data Interrupt - 2 - TXXFR - Tx Transfer Interrupt - 3 - RX1 - Rx second dubble buffer Data Interrupt - 4 - RXXFR - Rx Transfer Interrupt - 5 - EVENT_A - Event Mailbox interrupt - 6 - EVENT_B - Event Mailbox interrupt - 7 - WNONHST - Wake On Host Interrupt - 8 - TRACE_A - Debug Trace interrupt - 9 - TRACE_B - Debug Trace interrupt - 10 - CDCMP - Command Complete Interrupt - 11 - - 12 - - 13 - - 14 - ICOMP - Initialization Complete Interrupt - 16 - SG SE - Soft Gemini - Sense enable interrupt - 17 - SG SD - Soft Gemini - Sense disable interrupt - 18 - - - 19 - - - 20 - - - 21- - - Default: 0x0001 -*==============================================*/ - ACX_REG_INTERRUPT_MASK, - -/*============================================= - Host Interrupt Mask Set 16bit, (Write only) - ------------------------------------------ - Setting a bit in this register sets - the corresponding bin in ACX_HINT_MASK register - without effecting the mask - state of other bits (0 = no effect). -==============================================*/ - ACX_REG_HINT_MASK_SET, - -/*============================================= - Host Interrupt Mask Clear 16bit,(Write only) - ------------------------------------------ - Setting a bit in this register clears - the corresponding bin in ACX_HINT_MASK register - without effecting the mask - state of other bits (0 = no effect). -=============================================*/ - ACX_REG_HINT_MASK_CLR, - -/*============================================= - Host Interrupt Status Nondestructive Read - 16bit,(Read only) - ------------------------------------------ - The host can read this register to determine - which interrupts are active. - Reading this register doesn't - effect its content. -=============================================*/ - ACX_REG_INTERRUPT_NO_CLEAR, - -/*============================================= - Host Interrupt Status Clear on Read Register - 16bit,(Read only) - ------------------------------------------ - The host can read this register to determine - which interrupts are active. - Reading this register clears it, - thus making all interrupts inactive. -==============================================*/ - ACX_REG_INTERRUPT_CLEAR, - -/*============================================= - Host Interrupt Acknowledge Register - 16bit,(Write only) - ------------------------------------------ - The host can set individual bits in this - register to clear (acknowledge) the corresp. - interrupt status bits in the HINT_STS_CLR and - HINT_STS_ND registers, thus making the - assotiated interrupt inactive. (0-no effect) -==============================================*/ - ACX_REG_INTERRUPT_ACK, - -/*=============================================== - Host Software Reset - 32bit RW - ------------------------------------------ - [31:1] Reserved - 0 SOFT_RESET Soft Reset - When this bit is set, - it holds the Wlan hardware in a soft reset state. - This reset disables all MAC and baseband processor - clocks except the CardBus/PCI interface clock. - It also initializes all MAC state machines except - the host interface. It does not reload the - contents of the EEPROM. When this bit is cleared - (not self-clearing), the Wlan hardware - exits the software reset state. -===============================================*/ - ACX_REG_SLV_SOFT_RESET, - -/*=============================================== - EEPROM Burst Read Start - 32bit RW - ------------------------------------------ - [31:1] Reserved - 0 ACX_EE_START - EEPROM Burst Read Start 0 - Setting this bit starts a burst read from - the external EEPROM. - If this bit is set (after reset) before an EEPROM read/write, - the burst read starts at EEPROM address 0. - Otherwise, it starts at the address - following the address of the previous access. - TheWlan hardware hardware clears this bit automatically. - - Default: 0x00000000 -*================================================*/ - ACX_REG_EE_START, - -/* Embedded ARM CPU Control */ - -/*=============================================== - Halt eCPU - 32bit RW - ------------------------------------------ - 0 HALT_ECPU Halt Embedded CPU - This bit is the - compliment of bit 1 (MDATA2) in the SOR_CFG register. - During a hardware reset, this bit holds - the inverse of MDATA2. - When downloading firmware from the host, - set this bit (pull down MDATA2). - The host clears this bit after downloading the firmware into - zero-wait-state SSRAM. - When loading firmware from Flash, clear this bit (pull up MDATA2) - so that the eCPU can run the bootloader code in Flash - HALT_ECPU eCPU State - -------------------- - 1 halt eCPU - 0 enable eCPU - ===============================================*/ - ACX_REG_ECPU_CONTROL, - - ACX_REG_TABLE_LEN -}; - -#define ACX_SLV_SOFT_RESET_BIT BIT(0) -#define ACX_REG_EEPROM_START_BIT BIT(0) - -/* Command/Information Mailbox Pointers */ - -/*=============================================== - Command Mailbox Pointer - 32bit RW - ------------------------------------------ - This register holds the start address of - the command mailbox located in the Wlan hardware memory. - The host must read this pointer after a reset to - find the location of the command mailbox. - The Wlan hardware initializes the command mailbox - pointer with the default address of the command mailbox. - The command mailbox pointer is not valid until after - the host receives the Init Complete interrupt from - the Wlan hardware. - ===============================================*/ -#define REG_COMMAND_MAILBOX_PTR (SCR_PAD0) - -/*=============================================== - Information Mailbox Pointer - 32bit RW - ------------------------------------------ - This register holds the start address of - the information mailbox located in the Wlan hardware memory. - The host must read this pointer after a reset to find - the location of the information mailbox. - The Wlan hardware initializes the information mailbox pointer - with the default address of the information mailbox. - The information mailbox pointer is not valid - until after the host receives the Init Complete interrupt from - the Wlan hardware. - ===============================================*/ -#define REG_EVENT_MAILBOX_PTR (SCR_PAD1) - - -/* Misc */ - -#define REG_ENABLE_TX_RX (ENABLE) -/* - * Rx configuration (filter) information element - * --------------------------------------------- - */ -#define REG_RX_CONFIG (RX_CFG) -#define REG_RX_FILTER (RX_FILTER_CFG) - - -#define RX_CFG_ENABLE_PHY_HEADER_PLCP 0x0002 - -/* promiscuous - receives all valid frames */ -#define RX_CFG_PROMISCUOUS 0x0008 - -/* receives frames from any BSSID */ -#define RX_CFG_BSSID 0x0020 - -/* receives frames destined to any MAC address */ -#define RX_CFG_MAC 0x0010 - -#define RX_CFG_ENABLE_ONLY_MY_DEST_MAC 0x0010 -#define RX_CFG_ENABLE_ANY_DEST_MAC 0x0000 -#define RX_CFG_ENABLE_ONLY_MY_BSSID 0x0020 -#define RX_CFG_ENABLE_ANY_BSSID 0x0000 - -/* discards all broadcast frames */ -#define RX_CFG_DISABLE_BCAST 0x0200 - -#define RX_CFG_ENABLE_ONLY_MY_SSID 0x0400 -#define RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR 0x0800 -#define RX_CFG_COPY_RX_STATUS 0x2000 -#define RX_CFG_TSF 0x10000 - -#define RX_CONFIG_OPTION_ANY_DST_MY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \ - RX_CFG_ENABLE_ONLY_MY_BSSID) - -#define RX_CONFIG_OPTION_MY_DST_ANY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\ - | RX_CFG_ENABLE_ANY_BSSID) - -#define RX_CONFIG_OPTION_ANY_DST_ANY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \ - RX_CFG_ENABLE_ANY_BSSID) - -#define RX_CONFIG_OPTION_MY_DST_MY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\ - | RX_CFG_ENABLE_ONLY_MY_BSSID) - -#define RX_CONFIG_OPTION_FOR_SCAN (RX_CFG_ENABLE_PHY_HEADER_PLCP \ - | RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR \ - | RX_CFG_COPY_RX_STATUS | RX_CFG_TSF) - -#define RX_CONFIG_OPTION_FOR_MEASUREMENT (RX_CFG_ENABLE_ANY_DEST_MAC) - -#define RX_CONFIG_OPTION_FOR_JOIN (RX_CFG_ENABLE_ONLY_MY_BSSID | \ - RX_CFG_ENABLE_ONLY_MY_DEST_MAC) - -#define RX_CONFIG_OPTION_FOR_IBSS_JOIN (RX_CFG_ENABLE_ONLY_MY_SSID | \ - RX_CFG_ENABLE_ONLY_MY_DEST_MAC) - -#define RX_FILTER_OPTION_DEF (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\ - | CFG_RX_CTL_EN | CFG_RX_BCN_EN\ - | CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN) - -#define RX_FILTER_OPTION_FILTER_ALL 0 - -#define RX_FILTER_OPTION_DEF_PRSP_BCN (CFG_RX_PRSP_EN | CFG_RX_MGMT_EN\ - | CFG_RX_RCTS_ACK | CFG_RX_BCN_EN) - -#define RX_FILTER_OPTION_JOIN (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\ - | CFG_RX_BCN_EN | CFG_RX_AUTH_EN\ - | CFG_RX_ASSOC_EN | CFG_RX_RCTS_ACK\ - | CFG_RX_PRSP_EN) - - -/*=============================================== - EEPROM Read/Write Request 32bit RW - ------------------------------------------ - 1 EE_READ - EEPROM Read Request 1 - Setting this bit - loads a single byte of data into the EE_DATA - register from the EEPROM location specified in - the EE_ADDR register. - The Wlan hardware hardware clears this bit automatically. - EE_DATA is valid when this bit is cleared. - - 0 EE_WRITE - EEPROM Write Request - Setting this bit - writes a single byte of data from the EE_DATA register into the - EEPROM location specified in the EE_ADDR register. - The Wlan hardware hardware clears this bit automatically. -*===============================================*/ -#define EE_CTL (REGISTERS_BASE + 0x2000) -#define ACX_EE_CTL_REG EE_CTL -#define EE_WRITE 0x00000001ul -#define EE_READ 0x00000002ul - -/*=============================================== - EEPROM Address - 32bit RW - ------------------------------------------ - This register specifies the address - within the EEPROM from/to which to read/write data. - ===============================================*/ -#define EE_ADDR (REGISTERS_BASE + 0x2008) -#define ACX_EE_ADDR_REG EE_ADDR - -/*=============================================== - EEPROM Data - 32bit RW - ------------------------------------------ - This register either holds the read 8 bits of - data from the EEPROM or the write data - to be written to the EEPROM. - ===============================================*/ -#define EE_DATA (REGISTERS_BASE + 0x2004) -#define ACX_EE_DATA_REG EE_DATA - -#define EEPROM_ACCESS_TO 10000 /* timeout counter */ -#define START_EEPROM_MGR 0x00000001 - -/*=============================================== - EEPROM Base Address - 32bit RW - ------------------------------------------ - This register holds the upper nine bits - [23:15] of the 24-bit Wlan hardware memory - address for burst reads from EEPROM accesses. - The EEPROM provides the lower 15 bits of this address. - The MSB of the address from the EEPROM is ignored. - ===============================================*/ -#define ACX_EE_CFG EE_CFG - -/*=============================================== - GPIO Output Values -32bit, RW - ------------------------------------------ - [31:16] Reserved - [15: 0] Specify the output values (at the output driver inputs) for - GPIO[15:0], respectively. - ===============================================*/ -#define ACX_GPIO_OUT_REG GPIO_OUT -#define ACX_MAX_GPIO_LINES 15 - -/*=============================================== - Contention window -32bit, RW - ------------------------------------------ - [31:26] Reserved - [25:16] Max (0x3ff) - [15:07] Reserved - [06:00] Current contention window value - default is 0x1F - ===============================================*/ -#define ACX_CONT_WIND_CFG_REG CONT_WIND_CFG -#define ACX_CONT_WIND_MIN_MASK 0x0000007f -#define ACX_CONT_WIND_MAX 0x03ff0000 - -/*=============================================== - HI_CFG Interface Configuration Register Values - ------------------------------------------ - ===============================================*/ -#define HI_CFG_UART_ENABLE 0x00000004 -#define HI_CFG_RST232_ENABLE 0x00000008 -#define HI_CFG_CLOCK_REQ_SELECT 0x00000010 -#define HI_CFG_HOST_INT_ENABLE 0x00000020 -#define HI_CFG_VLYNQ_OUTPUT_ENABLE 0x00000040 -#define HI_CFG_HOST_INT_ACTIVE_LOW 0x00000080 -#define HI_CFG_UART_TX_OUT_GPIO_15 0x00000100 -#define HI_CFG_UART_TX_OUT_GPIO_14 0x00000200 -#define HI_CFG_UART_TX_OUT_GPIO_7 0x00000400 - -/* - * NOTE: USE_ACTIVE_HIGH compilation flag should be defined in makefile - * for platforms using active high interrupt level - */ -#ifdef USE_ACTIVE_HIGH -#define HI_CFG_DEF_VAL \ - (HI_CFG_UART_ENABLE | \ - HI_CFG_RST232_ENABLE | \ - HI_CFG_CLOCK_REQ_SELECT | \ - HI_CFG_HOST_INT_ENABLE) -#else -#define HI_CFG_DEF_VAL \ - (HI_CFG_UART_ENABLE | \ - HI_CFG_RST232_ENABLE | \ - HI_CFG_CLOCK_REQ_SELECT | \ - HI_CFG_HOST_INT_ENABLE) - -#endif - -#define REF_FREQ_19_2 0 -#define REF_FREQ_26_0 1 -#define REF_FREQ_38_4 2 -#define REF_FREQ_40_0 3 -#define REF_FREQ_33_6 4 -#define REF_FREQ_NUM 5 - -#define LUT_PARAM_INTEGER_DIVIDER 0 -#define LUT_PARAM_FRACTIONAL_DIVIDER 1 -#define LUT_PARAM_ATTN_BB 2 -#define LUT_PARAM_ALPHA_BB 3 -#define LUT_PARAM_STOP_TIME_BB 4 -#define LUT_PARAM_BB_PLL_LOOP_FILTER 5 -#define LUT_PARAM_NUM 6 - -#define ACX_EEPROMLESS_IND_REG (SCR_PAD4) -#define USE_EEPROM 0 -#define SOFT_RESET_MAX_TIME 1000000 -#define SOFT_RESET_STALL_TIME 1000 -#define NVS_DATA_BUNDARY_ALIGNMENT 4 - - -/* Firmware image load chunk size */ -#define CHUNK_SIZE 512 - -/* Firmware image header size */ -#define FW_HDR_SIZE 8 - -#define ECPU_CONTROL_HALT 0x00000101 - - -/****************************************************************************** - - CHANNELS, BAND & REG DOMAINS definitions - -******************************************************************************/ - - -enum { - RADIO_BAND_2_4GHZ = 0, /* 2.4 Ghz band */ - RADIO_BAND_5GHZ = 1, /* 5 Ghz band */ - RADIO_BAND_JAPAN_4_9_GHZ = 2, - DEFAULT_BAND = RADIO_BAND_2_4GHZ, - INVALID_BAND = 0xFE, - MAX_RADIO_BANDS = 0xFF -}; - -enum { - NO_RATE = 0, - RATE_1MBPS = 0x0A, - RATE_2MBPS = 0x14, - RATE_5_5MBPS = 0x37, - RATE_6MBPS = 0x0B, - RATE_9MBPS = 0x0F, - RATE_11MBPS = 0x6E, - RATE_12MBPS = 0x0A, - RATE_18MBPS = 0x0E, - RATE_22MBPS = 0xDC, - RATE_24MBPS = 0x09, - RATE_36MBPS = 0x0D, - RATE_48MBPS = 0x08, - RATE_54MBPS = 0x0C -}; - -enum { - RATE_INDEX_1MBPS = 0, - RATE_INDEX_2MBPS = 1, - RATE_INDEX_5_5MBPS = 2, - RATE_INDEX_6MBPS = 3, - RATE_INDEX_9MBPS = 4, - RATE_INDEX_11MBPS = 5, - RATE_INDEX_12MBPS = 6, - RATE_INDEX_18MBPS = 7, - RATE_INDEX_22MBPS = 8, - RATE_INDEX_24MBPS = 9, - RATE_INDEX_36MBPS = 10, - RATE_INDEX_48MBPS = 11, - RATE_INDEX_54MBPS = 12, - RATE_INDEX_MAX = RATE_INDEX_54MBPS, - MAX_RATE_INDEX, - INVALID_RATE_INDEX = MAX_RATE_INDEX, - RATE_INDEX_ENUM_MAX_SIZE = 0x7FFFFFFF -}; - -enum { - RATE_MASK_1MBPS = 0x1, - RATE_MASK_2MBPS = 0x2, - RATE_MASK_5_5MBPS = 0x4, - RATE_MASK_11MBPS = 0x20, -}; - -#define SHORT_PREAMBLE_BIT BIT(0) /* CCK or Barker depending on the rate */ -#define OFDM_RATE_BIT BIT(6) -#define PBCC_RATE_BIT BIT(7) - -enum { - CCK_LONG = 0, - CCK_SHORT = SHORT_PREAMBLE_BIT, - PBCC_LONG = PBCC_RATE_BIT, - PBCC_SHORT = PBCC_RATE_BIT | SHORT_PREAMBLE_BIT, - OFDM = OFDM_RATE_BIT -}; - -/****************************************************************************** - -Transmit-Descriptor RATE-SET field definitions... - -Define a new "Rate-Set" for TX path that incorporates the -Rate & Modulation info into a single 16-bit field. - -TxdRateSet_t: -b15 - Indicates Preamble type (1=SHORT, 0=LONG). - Notes: - Must be LONG (0) for 1Mbps rate. - Does not apply (set to 0) for RevG-OFDM rates. -b14 - Indicates PBCC encoding (1=PBCC, 0=not). - Notes: - Does not apply (set to 0) for rates 1 and 2 Mbps. - Does not apply (set to 0) for RevG-OFDM rates. -b13 - Unused (set to 0). -b12-b0 - Supported Rate indicator bits as defined below. - -******************************************************************************/ - - -/************************************************************************* - - Interrupt Trigger Register (Host -> WiLink) - -**************************************************************************/ - -/* Hardware to Embedded CPU Interrupts - first 32-bit register set */ - -/* - * Host Command Interrupt. Setting this bit masks - * the interrupt that the host issues to inform - * the FW that it has sent a command - * to the Wlan hardware Command Mailbox. - */ -#define INTR_TRIG_CMD BIT(0) - -/* - * Host Event Acknowlegde Interrupt. The host - * sets this bit to acknowledge that it received - * the unsolicited information from the event - * mailbox. - */ -#define INTR_TRIG_EVENT_ACK BIT(1) - -/* - * The host sets this bit to inform the Wlan - * FW that a TX packet is in the XFER - * Buffer #0. - */ -#define INTR_TRIG_TX_PROC0 BIT(2) - -/* - * The host sets this bit to inform the FW - * that it read a packet from RX XFER - * Buffer #0. - */ -#define INTR_TRIG_RX_PROC0 BIT(3) - -#define INTR_TRIG_DEBUG_ACK BIT(4) - -#define INTR_TRIG_STATE_CHANGED BIT(5) - - -/* Hardware to Embedded CPU Interrupts - second 32-bit register set */ - -/* - * The host sets this bit to inform the FW - * that it read a packet from RX XFER - * Buffer #1. - */ -#define INTR_TRIG_RX_PROC1 BIT(17) - -/* - * The host sets this bit to inform the Wlan - * hardware that a TX packet is in the XFER - * Buffer #1. - */ -#define INTR_TRIG_TX_PROC1 BIT(18) - -#endif diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.c b/drivers/net/wireless/wl12xx/wl1251_rx.c deleted file mode 100644 index 2576459..0000000 --- a/drivers/net/wireless/wl12xx/wl1251_rx.c +++ /dev/null @@ -1,190 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include -#include -#include - -#include "wl1251.h" -#include "wl1251_reg.h" -#include "wl1251_io.h" -#include "wl1251_rx.h" -#include "wl1251_cmd.h" -#include "wl1251_acx.h" - -static void wl1251_rx_header(struct wl1251 *wl, - struct wl1251_rx_descriptor *desc) -{ - u32 rx_packet_ring_addr; - - rx_packet_ring_addr = wl->data_path->rx_packet_ring_addr; - if (wl->rx_current_buffer) - rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size; - - wl1251_mem_read(wl, rx_packet_ring_addr, desc, sizeof(*desc)); -} - -static void wl1251_rx_status(struct wl1251 *wl, - struct wl1251_rx_descriptor *desc, - struct ieee80211_rx_status *status, - u8 beacon) -{ - u64 mactime; - int ret; - - memset(status, 0, sizeof(struct ieee80211_rx_status)); - - status->band = IEEE80211_BAND_2GHZ; - status->mactime = desc->timestamp; - - /* - * The rx status timestamp is a 32 bits value while the TSF is a - * 64 bits one. - * For IBSS merging, TSF is mandatory, so we have to get it - * somehow, so we ask for ACX_TSF_INFO. - * That could be moved to the get_tsf() hook, but unfortunately, - * this one must be atomic, while our SPI routines can sleep. - */ - if ((wl->bss_type == BSS_TYPE_IBSS) && beacon) { - ret = wl1251_acx_tsf_info(wl, &mactime); - if (ret == 0) - status->mactime = mactime; - } - - status->signal = desc->rssi; - - /* - * FIXME: guessing that snr needs to be divided by two, otherwise - * the values don't make any sense - */ - wl->noise = desc->rssi - desc->snr / 2; - - status->freq = ieee80211_channel_to_frequency(desc->channel); - - status->flag |= RX_FLAG_TSFT; - - if (desc->flags & RX_DESC_ENCRYPTION_MASK) { - status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; - - if (likely(!(desc->flags & RX_DESC_DECRYPT_FAIL))) - status->flag |= RX_FLAG_DECRYPTED; - - if (unlikely(desc->flags & RX_DESC_MIC_FAIL)) - status->flag |= RX_FLAG_MMIC_ERROR; - } - - if (unlikely(!(desc->flags & RX_DESC_VALID_FCS))) - status->flag |= RX_FLAG_FAILED_FCS_CRC; - - - /* FIXME: set status->rate_idx */ -} - -static void wl1251_rx_body(struct wl1251 *wl, - struct wl1251_rx_descriptor *desc) -{ - struct sk_buff *skb; - struct ieee80211_rx_status status; - u8 *rx_buffer, beacon = 0; - u16 length, *fc; - u32 curr_id, last_id_inc, rx_packet_ring_addr; - - length = WL1251_RX_ALIGN(desc->length - PLCP_HEADER_LENGTH); - curr_id = (desc->flags & RX_DESC_SEQNUM_MASK) >> RX_DESC_PACKETID_SHIFT; - last_id_inc = (wl->rx_last_id + 1) % (RX_MAX_PACKET_ID + 1); - - if (last_id_inc != curr_id) { - wl1251_warning("curr ID:%d, last ID inc:%d", - curr_id, last_id_inc); - wl->rx_last_id = curr_id; - } else { - wl->rx_last_id = last_id_inc; - } - - rx_packet_ring_addr = wl->data_path->rx_packet_ring_addr + - sizeof(struct wl1251_rx_descriptor) + 20; - if (wl->rx_current_buffer) - rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size; - - skb = __dev_alloc_skb(length, GFP_KERNEL); - if (!skb) { - wl1251_error("Couldn't allocate RX frame"); - return; - } - - rx_buffer = skb_put(skb, length); - wl1251_mem_read(wl, rx_packet_ring_addr, rx_buffer, length); - - /* The actual lenght doesn't include the target's alignment */ - skb->len = desc->length - PLCP_HEADER_LENGTH; - - fc = (u16 *)skb->data; - - if ((*fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) - beacon = 1; - - wl1251_rx_status(wl, desc, &status, beacon); - - wl1251_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len, - beacon ? "beacon" : ""); - - memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); - ieee80211_rx_ni(wl->hw, skb); -} - -static void wl1251_rx_ack(struct wl1251 *wl) -{ - u32 data, addr; - - if (wl->rx_current_buffer) { - addr = ACX_REG_INTERRUPT_TRIG_H; - data = INTR_TRIG_RX_PROC1; - } else { - addr = ACX_REG_INTERRUPT_TRIG; - data = INTR_TRIG_RX_PROC0; - } - - wl1251_reg_write32(wl, addr, data); - - /* Toggle buffer ring */ - wl->rx_current_buffer = !wl->rx_current_buffer; -} - - -void wl1251_rx(struct wl1251 *wl) -{ - struct wl1251_rx_descriptor *rx_desc; - - if (wl->state != WL1251_STATE_ON) - return; - - rx_desc = wl->rx_descriptor; - - /* We first read the frame's header */ - wl1251_rx_header(wl, rx_desc); - - /* Now we can read the body */ - wl1251_rx_body(wl, rx_desc); - - /* Finally, we need to ACK the RX */ - wl1251_rx_ack(wl); -} diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.h b/drivers/net/wireless/wl12xx/wl1251_rx.h deleted file mode 100644 index 4448f63..0000000 --- a/drivers/net/wireless/wl12xx/wl1251_rx.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL1251_RX_H__ -#define __WL1251_RX_H__ - -#include - -#include "wl1251.h" - -/* - * RX PATH - * - * The Rx path uses a double buffer and an rx_contro structure, each located - * at a fixed address in the device memory. The host keeps track of which - * buffer is available and alternates between them on a per packet basis. - * The size of each of the two buffers is large enough to hold the longest - * 802.3 packet. - * The RX path goes like that: - * 1) The target generates an interrupt each time a new packet is received. - * There are 2 RX interrupts, one for each buffer. - * 2) The host reads the received packet from one of the double buffers. - * 3) The host triggers a target interrupt. - * 4) The target prepares the next RX packet. - */ - -#define WL1251_RX_MAX_RSSI -30 -#define WL1251_RX_MIN_RSSI -95 - -#define WL1251_RX_ALIGN_TO 4 -#define WL1251_RX_ALIGN(len) (((len) + WL1251_RX_ALIGN_TO - 1) & \ - ~(WL1251_RX_ALIGN_TO - 1)) - -#define SHORT_PREAMBLE_BIT BIT(0) -#define OFDM_RATE_BIT BIT(6) -#define PBCC_RATE_BIT BIT(7) - -#define PLCP_HEADER_LENGTH 8 -#define RX_DESC_PACKETID_SHIFT 11 -#define RX_MAX_PACKET_ID 3 - -#define RX_DESC_VALID_FCS 0x0001 -#define RX_DESC_MATCH_RXADDR1 0x0002 -#define RX_DESC_MCAST 0x0004 -#define RX_DESC_STAINTIM 0x0008 -#define RX_DESC_VIRTUAL_BM 0x0010 -#define RX_DESC_BCAST 0x0020 -#define RX_DESC_MATCH_SSID 0x0040 -#define RX_DESC_MATCH_BSSID 0x0080 -#define RX_DESC_ENCRYPTION_MASK 0x0300 -#define RX_DESC_MEASURMENT 0x0400 -#define RX_DESC_SEQNUM_MASK 0x1800 -#define RX_DESC_MIC_FAIL 0x2000 -#define RX_DESC_DECRYPT_FAIL 0x4000 - -struct wl1251_rx_descriptor { - u32 timestamp; /* In microseconds */ - u16 length; /* Paylod length, including headers */ - u16 flags; - - /* - * 0 - 802.11 - * 1 - 802.3 - * 2 - IP - * 3 - Raw Codec - */ - u8 type; - - /* - * Received Rate: - * 0x0A - 1MBPS - * 0x14 - 2MBPS - * 0x37 - 5_5MBPS - * 0x0B - 6MBPS - * 0x0F - 9MBPS - * 0x6E - 11MBPS - * 0x0A - 12MBPS - * 0x0E - 18MBPS - * 0xDC - 22MBPS - * 0x09 - 24MBPS - * 0x0D - 36MBPS - * 0x08 - 48MBPS - * 0x0C - 54MBPS - */ - u8 rate; - - u8 mod_pre; /* Modulation and preamble */ - u8 channel; - - /* - * 0 - 2.4 Ghz - * 1 - 5 Ghz - */ - u8 band; - - s8 rssi; /* in dB */ - u8 rcpi; /* in dB */ - u8 snr; /* in dB */ -} __packed; - -void wl1251_rx(struct wl1251 *wl); - -#endif diff --git a/drivers/net/wireless/wl12xx/wl1251_sdio.c b/drivers/net/wireless/wl12xx/wl1251_sdio.c deleted file mode 100644 index 74ba9ce..0000000 --- a/drivers/net/wireless/wl12xx/wl1251_sdio.c +++ /dev/null @@ -1,342 +0,0 @@ -/* - * wl12xx SDIO routines - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - * Copyright (C) 2005 Texas Instruments Incorporated - * Copyright (C) 2008 Google Inc - * Copyright (C) 2009 Bob Copeland (me@bobcopeland.com) - */ -#include -#include -#include -#include -#include -#include -#include - -#include "wl1251.h" - -#ifndef SDIO_VENDOR_ID_TI -#define SDIO_VENDOR_ID_TI 0x104c -#endif - -#ifndef SDIO_DEVICE_ID_TI_WL1251 -#define SDIO_DEVICE_ID_TI_WL1251 0x9066 -#endif - -struct wl1251_sdio { - struct sdio_func *func; - u32 elp_val; -}; - -static struct wl12xx_platform_data *wl12xx_board_data; - -static struct sdio_func *wl_to_func(struct wl1251 *wl) -{ - struct wl1251_sdio *wl_sdio = wl->if_priv; - return wl_sdio->func; -} - -static void wl1251_sdio_interrupt(struct sdio_func *func) -{ - struct wl1251 *wl = sdio_get_drvdata(func); - - wl1251_debug(DEBUG_IRQ, "IRQ"); - - /* FIXME should be synchronous for sdio */ - ieee80211_queue_work(wl->hw, &wl->irq_work); -} - -static const struct sdio_device_id wl1251_devices[] = { - { SDIO_DEVICE(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1251) }, - {} -}; -MODULE_DEVICE_TABLE(sdio, wl1251_devices); - - -static void wl1251_sdio_read(struct wl1251 *wl, int addr, - void *buf, size_t len) -{ - int ret; - struct sdio_func *func = wl_to_func(wl); - - sdio_claim_host(func); - ret = sdio_memcpy_fromio(func, buf, addr, len); - if (ret) - wl1251_error("sdio read failed (%d)", ret); - sdio_release_host(func); -} - -static void wl1251_sdio_write(struct wl1251 *wl, int addr, - void *buf, size_t len) -{ - int ret; - struct sdio_func *func = wl_to_func(wl); - - sdio_claim_host(func); - ret = sdio_memcpy_toio(func, addr, buf, len); - if (ret) - wl1251_error("sdio write failed (%d)", ret); - sdio_release_host(func); -} - -static void wl1251_sdio_read_elp(struct wl1251 *wl, int addr, u32 *val) -{ - int ret = 0; - struct wl1251_sdio *wl_sdio = wl->if_priv; - struct sdio_func *func = wl_sdio->func; - - /* - * The hardware only supports RAW (read after write) access for - * reading, regular sdio_readb won't work here (it interprets - * the unused bits of CMD52 as write data even if we send read - * request). - */ - sdio_claim_host(func); - *val = sdio_writeb_readb(func, wl_sdio->elp_val, addr, &ret); - sdio_release_host(func); - - if (ret) - wl1251_error("sdio_readb failed (%d)", ret); -} - -static void wl1251_sdio_write_elp(struct wl1251 *wl, int addr, u32 val) -{ - int ret = 0; - struct wl1251_sdio *wl_sdio = wl->if_priv; - struct sdio_func *func = wl_sdio->func; - - sdio_claim_host(func); - sdio_writeb(func, val, addr, &ret); - sdio_release_host(func); - - if (ret) - wl1251_error("sdio_writeb failed (%d)", ret); - else - wl_sdio->elp_val = val; -} - -static void wl1251_sdio_reset(struct wl1251 *wl) -{ -} - -static void wl1251_sdio_enable_irq(struct wl1251 *wl) -{ - struct sdio_func *func = wl_to_func(wl); - - sdio_claim_host(func); - sdio_claim_irq(func, wl1251_sdio_interrupt); - sdio_release_host(func); -} - -static void wl1251_sdio_disable_irq(struct wl1251 *wl) -{ - struct sdio_func *func = wl_to_func(wl); - - sdio_claim_host(func); - sdio_release_irq(func); - sdio_release_host(func); -} - -/* Interrupts when using dedicated WLAN_IRQ pin */ -static irqreturn_t wl1251_line_irq(int irq, void *cookie) -{ - struct wl1251 *wl = cookie; - - ieee80211_queue_work(wl->hw, &wl->irq_work); - - return IRQ_HANDLED; -} - -static void wl1251_enable_line_irq(struct wl1251 *wl) -{ - return enable_irq(wl->irq); -} - -static void wl1251_disable_line_irq(struct wl1251 *wl) -{ - return disable_irq(wl->irq); -} - -static void wl1251_sdio_set_power(bool enable) -{ -} - -static struct wl1251_if_operations wl1251_sdio_ops = { - .read = wl1251_sdio_read, - .write = wl1251_sdio_write, - .write_elp = wl1251_sdio_write_elp, - .read_elp = wl1251_sdio_read_elp, - .reset = wl1251_sdio_reset, -}; - -static int wl1251_platform_probe(struct platform_device *pdev) -{ - if (pdev->id != -1) { - wl1251_error("can only handle single device"); - return -ENODEV; - } - - wl12xx_board_data = pdev->dev.platform_data; - return 0; -} - -/* - * Dummy platform_driver for passing platform_data to this driver, - * until we have a way to pass this through SDIO subsystem or - * some other way. - */ -static struct platform_driver wl1251_platform_driver = { - .driver = { - .name = "wl1251_data", - .owner = THIS_MODULE, - }, - .probe = wl1251_platform_probe, -}; - -static int wl1251_sdio_probe(struct sdio_func *func, - const struct sdio_device_id *id) -{ - int ret; - struct wl1251 *wl; - struct ieee80211_hw *hw; - struct wl1251_sdio *wl_sdio; - - hw = wl1251_alloc_hw(); - if (IS_ERR(hw)) - return PTR_ERR(hw); - - wl = hw->priv; - - wl_sdio = kzalloc(sizeof(*wl_sdio), GFP_KERNEL); - if (wl_sdio == NULL) { - ret = -ENOMEM; - goto out_free_hw; - } - - sdio_claim_host(func); - ret = sdio_enable_func(func); - if (ret) - goto release; - - sdio_set_block_size(func, 512); - sdio_release_host(func); - - SET_IEEE80211_DEV(hw, &func->dev); - wl_sdio->func = func; - wl->if_priv = wl_sdio; - wl->if_ops = &wl1251_sdio_ops; - wl->set_power = wl1251_sdio_set_power; - - if (wl12xx_board_data != NULL) { - wl->set_power = wl12xx_board_data->set_power; - wl->irq = wl12xx_board_data->irq; - wl->use_eeprom = wl12xx_board_data->use_eeprom; - } - - if (wl->irq) { - ret = request_irq(wl->irq, wl1251_line_irq, 0, "wl1251", wl); - if (ret < 0) { - wl1251_error("request_irq() failed: %d", ret); - goto disable; - } - - set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); - disable_irq(wl->irq); - - wl1251_sdio_ops.enable_irq = wl1251_enable_line_irq; - wl1251_sdio_ops.disable_irq = wl1251_disable_line_irq; - - wl1251_info("using dedicated interrupt line"); - } else { - wl1251_sdio_ops.enable_irq = wl1251_sdio_enable_irq; - wl1251_sdio_ops.disable_irq = wl1251_sdio_disable_irq; - - wl1251_info("using SDIO interrupt"); - } - - ret = wl1251_init_ieee80211(wl); - if (ret) - goto out_free_irq; - - sdio_set_drvdata(func, wl); - return ret; - -out_free_irq: - if (wl->irq) - free_irq(wl->irq, wl); -disable: - sdio_claim_host(func); - sdio_disable_func(func); -release: - sdio_release_host(func); - kfree(wl_sdio); -out_free_hw: - wl1251_free_hw(wl); - return ret; -} - -static void __devexit wl1251_sdio_remove(struct sdio_func *func) -{ - struct wl1251 *wl = sdio_get_drvdata(func); - struct wl1251_sdio *wl_sdio = wl->if_priv; - - if (wl->irq) - free_irq(wl->irq, wl); - kfree(wl_sdio); - wl1251_free_hw(wl); - - sdio_claim_host(func); - sdio_release_irq(func); - sdio_disable_func(func); - sdio_release_host(func); -} - -static struct sdio_driver wl1251_sdio_driver = { - .name = "wl1251_sdio", - .id_table = wl1251_devices, - .probe = wl1251_sdio_probe, - .remove = __devexit_p(wl1251_sdio_remove), -}; - -static int __init wl1251_sdio_init(void) -{ - int err; - - err = platform_driver_register(&wl1251_platform_driver); - if (err) { - wl1251_error("failed to register platform driver: %d", err); - return err; - } - - err = sdio_register_driver(&wl1251_sdio_driver); - if (err) - wl1251_error("failed to register sdio driver: %d", err); - return err; -} - -static void __exit wl1251_sdio_exit(void) -{ - sdio_unregister_driver(&wl1251_sdio_driver); - platform_driver_unregister(&wl1251_platform_driver); - wl1251_notice("unloaded"); -} - -module_init(wl1251_sdio_init); -module_exit(wl1251_sdio_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Kalle Valo "); diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c deleted file mode 100644 index 320de79..0000000 --- a/drivers/net/wireless/wl12xx/wl1251_spi.c +++ /dev/null @@ -1,346 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (C) 2008 Nokia Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include -#include -#include -#include -#include -#include - -#include "wl1251.h" -#include "wl1251_reg.h" -#include "wl1251_spi.h" - -static irqreturn_t wl1251_irq(int irq, void *cookie) -{ - struct wl1251 *wl; - - wl1251_debug(DEBUG_IRQ, "IRQ"); - - wl = cookie; - - ieee80211_queue_work(wl->hw, &wl->irq_work); - - return IRQ_HANDLED; -} - -static struct spi_device *wl_to_spi(struct wl1251 *wl) -{ - return wl->if_priv; -} - -static void wl1251_spi_reset(struct wl1251 *wl) -{ - u8 *cmd; - struct spi_transfer t; - struct spi_message m; - - cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); - if (!cmd) { - wl1251_error("could not allocate cmd for spi reset"); - return; - } - - memset(&t, 0, sizeof(t)); - spi_message_init(&m); - - memset(cmd, 0xff, WSPI_INIT_CMD_LEN); - - t.tx_buf = cmd; - t.len = WSPI_INIT_CMD_LEN; - spi_message_add_tail(&t, &m); - - spi_sync(wl_to_spi(wl), &m); - - wl1251_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); -} - -static void wl1251_spi_wake(struct wl1251 *wl) -{ - u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd; - struct spi_transfer t; - struct spi_message m; - - cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); - if (!cmd) { - wl1251_error("could not allocate cmd for spi init"); - return; - } - - memset(crc, 0, sizeof(crc)); - memset(&t, 0, sizeof(t)); - spi_message_init(&m); - - /* - * Set WSPI_INIT_COMMAND - * the data is being send from the MSB to LSB - */ - cmd[2] = 0xff; - cmd[3] = 0xff; - cmd[1] = WSPI_INIT_CMD_START | WSPI_INIT_CMD_TX; - cmd[0] = 0; - cmd[7] = 0; - cmd[6] |= HW_ACCESS_WSPI_INIT_CMD_MASK << 3; - cmd[6] |= HW_ACCESS_WSPI_FIXED_BUSY_LEN & WSPI_INIT_CMD_FIXEDBUSY_LEN; - - if (HW_ACCESS_WSPI_FIXED_BUSY_LEN == 0) - cmd[5] |= WSPI_INIT_CMD_DIS_FIXEDBUSY; - else - cmd[5] |= WSPI_INIT_CMD_EN_FIXEDBUSY; - - cmd[5] |= WSPI_INIT_CMD_IOD | WSPI_INIT_CMD_IP | WSPI_INIT_CMD_CS - | WSPI_INIT_CMD_WSPI | WSPI_INIT_CMD_WS; - - crc[0] = cmd[1]; - crc[1] = cmd[0]; - crc[2] = cmd[7]; - crc[3] = cmd[6]; - crc[4] = cmd[5]; - - cmd[4] |= crc7(0, crc, WSPI_INIT_CMD_CRC_LEN) << 1; - cmd[4] |= WSPI_INIT_CMD_END; - - t.tx_buf = cmd; - t.len = WSPI_INIT_CMD_LEN; - spi_message_add_tail(&t, &m); - - spi_sync(wl_to_spi(wl), &m); - - wl1251_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN); -} - -static void wl1251_spi_reset_wake(struct wl1251 *wl) -{ - wl1251_spi_reset(wl); - wl1251_spi_wake(wl); -} - -static void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, - size_t len) -{ - struct spi_transfer t[3]; - struct spi_message m; - u8 *busy_buf; - u32 *cmd; - - cmd = &wl->buffer_cmd; - busy_buf = wl->buffer_busyword; - - *cmd = 0; - *cmd |= WSPI_CMD_READ; - *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; - *cmd |= addr & WSPI_CMD_BYTE_ADDR; - - spi_message_init(&m); - memset(t, 0, sizeof(t)); - - t[0].tx_buf = cmd; - t[0].len = 4; - spi_message_add_tail(&t[0], &m); - - /* Busy and non busy words read */ - t[1].rx_buf = busy_buf; - t[1].len = WL1251_BUSY_WORD_LEN; - spi_message_add_tail(&t[1], &m); - - t[2].rx_buf = buf; - t[2].len = len; - spi_message_add_tail(&t[2], &m); - - spi_sync(wl_to_spi(wl), &m); - - /* FIXME: check busy words */ - - wl1251_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd)); - wl1251_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); -} - -static void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, - size_t len) -{ - struct spi_transfer t[2]; - struct spi_message m; - u32 *cmd; - - cmd = &wl->buffer_cmd; - - *cmd = 0; - *cmd |= WSPI_CMD_WRITE; - *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; - *cmd |= addr & WSPI_CMD_BYTE_ADDR; - - spi_message_init(&m); - memset(t, 0, sizeof(t)); - - t[0].tx_buf = cmd; - t[0].len = sizeof(*cmd); - spi_message_add_tail(&t[0], &m); - - t[1].tx_buf = buf; - t[1].len = len; - spi_message_add_tail(&t[1], &m); - - spi_sync(wl_to_spi(wl), &m); - - wl1251_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); - wl1251_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); -} - -static void wl1251_spi_enable_irq(struct wl1251 *wl) -{ - return enable_irq(wl->irq); -} - -static void wl1251_spi_disable_irq(struct wl1251 *wl) -{ - return disable_irq(wl->irq); -} - -static const struct wl1251_if_operations wl1251_spi_ops = { - .read = wl1251_spi_read, - .write = wl1251_spi_write, - .reset = wl1251_spi_reset_wake, - .enable_irq = wl1251_spi_enable_irq, - .disable_irq = wl1251_spi_disable_irq, -}; - -static int __devinit wl1251_spi_probe(struct spi_device *spi) -{ - struct wl12xx_platform_data *pdata; - struct ieee80211_hw *hw; - struct wl1251 *wl; - int ret; - - pdata = spi->dev.platform_data; - if (!pdata) { - wl1251_error("no platform data"); - return -ENODEV; - } - - hw = wl1251_alloc_hw(); - if (IS_ERR(hw)) - return PTR_ERR(hw); - - wl = hw->priv; - - SET_IEEE80211_DEV(hw, &spi->dev); - dev_set_drvdata(&spi->dev, wl); - wl->if_priv = spi; - wl->if_ops = &wl1251_spi_ops; - - /* This is the only SPI value that we need to set here, the rest - * comes from the board-peripherals file */ - spi->bits_per_word = 32; - - ret = spi_setup(spi); - if (ret < 0) { - wl1251_error("spi_setup failed"); - goto out_free; - } - - wl->set_power = pdata->set_power; - if (!wl->set_power) { - wl1251_error("set power function missing in platform data"); - return -ENODEV; - } - - wl->irq = spi->irq; - if (wl->irq < 0) { - wl1251_error("irq missing in platform data"); - return -ENODEV; - } - - wl->use_eeprom = pdata->use_eeprom; - - ret = request_irq(wl->irq, wl1251_irq, 0, DRIVER_NAME, wl); - if (ret < 0) { - wl1251_error("request_irq() failed: %d", ret); - goto out_free; - } - - set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); - - disable_irq(wl->irq); - - ret = wl1251_init_ieee80211(wl); - if (ret) - goto out_irq; - - return 0; - - out_irq: - free_irq(wl->irq, wl); - - out_free: - ieee80211_free_hw(hw); - - return ret; -} - -static int __devexit wl1251_spi_remove(struct spi_device *spi) -{ - struct wl1251 *wl = dev_get_drvdata(&spi->dev); - - free_irq(wl->irq, wl); - wl1251_free_hw(wl); - - return 0; -} - -static struct spi_driver wl1251_spi_driver = { - .driver = { - .name = DRIVER_NAME, - .bus = &spi_bus_type, - .owner = THIS_MODULE, - }, - - .probe = wl1251_spi_probe, - .remove = __devexit_p(wl1251_spi_remove), -}; - -static int __init wl1251_spi_init(void) -{ - int ret; - - ret = spi_register_driver(&wl1251_spi_driver); - if (ret < 0) { - wl1251_error("failed to register spi driver: %d", ret); - goto out; - } - -out: - return ret; -} - -static void __exit wl1251_spi_exit(void) -{ - spi_unregister_driver(&wl1251_spi_driver); - - wl1251_notice("unloaded"); -} - -module_init(wl1251_spi_init); -module_exit(wl1251_spi_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Kalle Valo "); -MODULE_ALIAS("spi:wl1251"); diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.h b/drivers/net/wireless/wl12xx/wl1251_spi.h deleted file mode 100644 index 7dcf3cf..0000000 --- a/drivers/net/wireless/wl12xx/wl1251_spi.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL1251_SPI_H__ -#define __WL1251_SPI_H__ - -#include "wl1251_cmd.h" -#include "wl1251_acx.h" -#include "wl1251_reg.h" - -#define WSPI_CMD_READ 0x40000000 -#define WSPI_CMD_WRITE 0x00000000 -#define WSPI_CMD_FIXED 0x20000000 -#define WSPI_CMD_BYTE_LENGTH 0x1FFE0000 -#define WSPI_CMD_BYTE_LENGTH_OFFSET 17 -#define WSPI_CMD_BYTE_ADDR 0x0001FFFF - -#define WSPI_INIT_CMD_CRC_LEN 5 - -#define WSPI_INIT_CMD_START 0x00 -#define WSPI_INIT_CMD_TX 0x40 -/* the extra bypass bit is sampled by the TNET as '1' */ -#define WSPI_INIT_CMD_BYPASS_BIT 0x80 -#define WSPI_INIT_CMD_FIXEDBUSY_LEN 0x07 -#define WSPI_INIT_CMD_EN_FIXEDBUSY 0x80 -#define WSPI_INIT_CMD_DIS_FIXEDBUSY 0x00 -#define WSPI_INIT_CMD_IOD 0x40 -#define WSPI_INIT_CMD_IP 0x20 -#define WSPI_INIT_CMD_CS 0x10 -#define WSPI_INIT_CMD_WS 0x08 -#define WSPI_INIT_CMD_WSPI 0x01 -#define WSPI_INIT_CMD_END 0x01 - -#define WSPI_INIT_CMD_LEN 8 - -#define HW_ACCESS_WSPI_FIXED_BUSY_LEN \ - ((WL1251_BUSY_WORD_LEN - 4) / sizeof(u32)) -#define HW_ACCESS_WSPI_INIT_CMD_MASK 0 - -#endif /* __WL1251_SPI_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.c b/drivers/net/wireless/wl12xx/wl1251_tx.c deleted file mode 100644 index 388492a..0000000 --- a/drivers/net/wireless/wl12xx/wl1251_tx.c +++ /dev/null @@ -1,570 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include -#include - -#include "wl1251.h" -#include "wl1251_reg.h" -#include "wl1251_tx.h" -#include "wl1251_ps.h" -#include "wl1251_io.h" - -static bool wl1251_tx_double_buffer_busy(struct wl1251 *wl, u32 data_out_count) -{ - int used, data_in_count; - - data_in_count = wl->data_in_count; - - if (data_in_count < data_out_count) - /* data_in_count has wrapped */ - data_in_count += TX_STATUS_DATA_OUT_COUNT_MASK + 1; - - used = data_in_count - data_out_count; - - WARN_ON(used < 0); - WARN_ON(used > DP_TX_PACKET_RING_CHUNK_NUM); - - if (used >= DP_TX_PACKET_RING_CHUNK_NUM) - return true; - else - return false; -} - -static int wl1251_tx_path_status(struct wl1251 *wl) -{ - u32 status, addr, data_out_count; - bool busy; - - addr = wl->data_path->tx_control_addr; - status = wl1251_mem_read32(wl, addr); - data_out_count = status & TX_STATUS_DATA_OUT_COUNT_MASK; - busy = wl1251_tx_double_buffer_busy(wl, data_out_count); - - if (busy) - return -EBUSY; - - return 0; -} - -static int wl1251_tx_id(struct wl1251 *wl, struct sk_buff *skb) -{ - int i; - - for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) - if (wl->tx_frames[i] == NULL) { - wl->tx_frames[i] = skb; - return i; - } - - return -EBUSY; -} - -static void wl1251_tx_control(struct tx_double_buffer_desc *tx_hdr, - struct ieee80211_tx_info *control, u16 fc) -{ - *(u16 *)&tx_hdr->control = 0; - - tx_hdr->control.rate_policy = 0; - - /* 802.11 packets */ - tx_hdr->control.packet_type = 0; - - if (control->flags & IEEE80211_TX_CTL_NO_ACK) - tx_hdr->control.ack_policy = 1; - - tx_hdr->control.tx_complete = 1; - - if ((fc & IEEE80211_FTYPE_DATA) && - ((fc & IEEE80211_STYPE_QOS_DATA) || - (fc & IEEE80211_STYPE_QOS_NULLFUNC))) - tx_hdr->control.qos = 1; -} - -/* RSN + MIC = 8 + 8 = 16 bytes (worst case - AES). */ -#define MAX_MSDU_SECURITY_LENGTH 16 -#define MAX_MPDU_SECURITY_LENGTH 16 -#define WLAN_QOS_HDR_LEN 26 -#define MAX_MPDU_HEADER_AND_SECURITY (MAX_MPDU_SECURITY_LENGTH + \ - WLAN_QOS_HDR_LEN) -#define HW_BLOCK_SIZE 252 -static void wl1251_tx_frag_block_num(struct tx_double_buffer_desc *tx_hdr) -{ - u16 payload_len, frag_threshold, mem_blocks; - u16 num_mpdus, mem_blocks_per_frag; - - frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD; - tx_hdr->frag_threshold = cpu_to_le16(frag_threshold); - - payload_len = le16_to_cpu(tx_hdr->length) + MAX_MSDU_SECURITY_LENGTH; - - if (payload_len > frag_threshold) { - mem_blocks_per_frag = - ((frag_threshold + MAX_MPDU_HEADER_AND_SECURITY) / - HW_BLOCK_SIZE) + 1; - num_mpdus = payload_len / frag_threshold; - mem_blocks = num_mpdus * mem_blocks_per_frag; - payload_len -= num_mpdus * frag_threshold; - num_mpdus++; - - } else { - mem_blocks_per_frag = 0; - mem_blocks = 0; - num_mpdus = 1; - } - - mem_blocks += (payload_len / HW_BLOCK_SIZE) + 1; - - if (num_mpdus > 1) - mem_blocks += min(num_mpdus, mem_blocks_per_frag); - - tx_hdr->num_mem_blocks = mem_blocks; -} - -static int wl1251_tx_fill_hdr(struct wl1251 *wl, struct sk_buff *skb, - struct ieee80211_tx_info *control) -{ - struct tx_double_buffer_desc *tx_hdr; - struct ieee80211_rate *rate; - int id; - u16 fc; - - if (!skb) - return -EINVAL; - - id = wl1251_tx_id(wl, skb); - if (id < 0) - return id; - - fc = *(u16 *)skb->data; - tx_hdr = (struct tx_double_buffer_desc *) skb_push(skb, - sizeof(*tx_hdr)); - - tx_hdr->length = cpu_to_le16(skb->len - sizeof(*tx_hdr)); - rate = ieee80211_get_tx_rate(wl->hw, control); - tx_hdr->rate = cpu_to_le16(rate->hw_value); - tx_hdr->expiry_time = cpu_to_le32(1 << 16); - tx_hdr->id = id; - - tx_hdr->xmit_queue = wl1251_tx_get_queue(skb_get_queue_mapping(skb)); - - wl1251_tx_control(tx_hdr, control, fc); - wl1251_tx_frag_block_num(tx_hdr); - - return 0; -} - -/* We copy the packet to the target */ -static int wl1251_tx_send_packet(struct wl1251 *wl, struct sk_buff *skb, - struct ieee80211_tx_info *control) -{ - struct tx_double_buffer_desc *tx_hdr; - int len; - u32 addr; - - if (!skb) - return -EINVAL; - - tx_hdr = (struct tx_double_buffer_desc *) skb->data; - - if (control->control.hw_key && - control->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) { - int hdrlen; - __le16 fc; - u16 length; - u8 *pos; - - fc = *(__le16 *)(skb->data + sizeof(*tx_hdr)); - length = le16_to_cpu(tx_hdr->length) + WL1251_TKIP_IV_SPACE; - tx_hdr->length = cpu_to_le16(length); - - hdrlen = ieee80211_hdrlen(fc); - - pos = skb_push(skb, WL1251_TKIP_IV_SPACE); - memmove(pos, pos + WL1251_TKIP_IV_SPACE, - sizeof(*tx_hdr) + hdrlen); - } - - /* Revisit. This is a workaround for getting non-aligned packets. - This happens at least with EAPOL packets from the user space. - Our DMA requires packets to be aligned on a 4-byte boundary. - */ - if (unlikely((long)skb->data & 0x03)) { - int offset = (4 - (long)skb->data) & 0x03; - wl1251_debug(DEBUG_TX, "skb offset %d", offset); - - /* check whether the current skb can be used */ - if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) { - unsigned char *src = skb->data; - - /* align the buffer on a 4-byte boundary */ - skb_reserve(skb, offset); - memmove(skb->data, src, skb->len); - tx_hdr = (struct tx_double_buffer_desc *) skb->data; - } else { - wl1251_info("No handler, fixme!"); - return -EINVAL; - } - } - - /* Our skb->data at this point includes the HW header */ - len = WL1251_TX_ALIGN(skb->len); - - if (wl->data_in_count & 0x1) - addr = wl->data_path->tx_packet_ring_addr + - wl->data_path->tx_packet_ring_chunk_size; - else - addr = wl->data_path->tx_packet_ring_addr; - - wl1251_mem_write(wl, addr, skb->data, len); - - wl1251_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x " - "queue %d", tx_hdr->id, skb, tx_hdr->length, - tx_hdr->rate, tx_hdr->xmit_queue); - - return 0; -} - -static void wl1251_tx_trigger(struct wl1251 *wl) -{ - u32 data, addr; - - if (wl->data_in_count & 0x1) { - addr = ACX_REG_INTERRUPT_TRIG_H; - data = INTR_TRIG_TX_PROC1; - } else { - addr = ACX_REG_INTERRUPT_TRIG; - data = INTR_TRIG_TX_PROC0; - } - - wl1251_reg_write32(wl, addr, data); - - /* Bumping data in */ - wl->data_in_count = (wl->data_in_count + 1) & - TX_STATUS_DATA_OUT_COUNT_MASK; -} - -/* caller must hold wl->mutex */ -static int wl1251_tx_frame(struct wl1251 *wl, struct sk_buff *skb) -{ - struct ieee80211_tx_info *info; - int ret = 0; - u8 idx; - - info = IEEE80211_SKB_CB(skb); - - if (info->control.hw_key) { - idx = info->control.hw_key->hw_key_idx; - if (unlikely(wl->default_key != idx)) { - ret = wl1251_acx_default_key(wl, idx); - if (ret < 0) - return ret; - } - } - - ret = wl1251_tx_path_status(wl); - if (ret < 0) - return ret; - - ret = wl1251_tx_fill_hdr(wl, skb, info); - if (ret < 0) - return ret; - - ret = wl1251_tx_send_packet(wl, skb, info); - if (ret < 0) - return ret; - - wl1251_tx_trigger(wl); - - return ret; -} - -void wl1251_tx_work(struct work_struct *work) -{ - struct wl1251 *wl = container_of(work, struct wl1251, tx_work); - struct sk_buff *skb; - bool woken_up = false; - int ret; - - mutex_lock(&wl->mutex); - - if (unlikely(wl->state == WL1251_STATE_OFF)) - goto out; - - while ((skb = skb_dequeue(&wl->tx_queue))) { - if (!woken_up) { - ret = wl1251_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - woken_up = true; - } - - ret = wl1251_tx_frame(wl, skb); - if (ret == -EBUSY) { - skb_queue_head(&wl->tx_queue, skb); - goto out; - } else if (ret < 0) { - dev_kfree_skb(skb); - goto out; - } - } - -out: - if (woken_up) - wl1251_ps_elp_sleep(wl); - - mutex_unlock(&wl->mutex); -} - -static const char *wl1251_tx_parse_status(u8 status) -{ - /* 8 bit status field, one character per bit plus null */ - static char buf[9]; - int i = 0; - - memset(buf, 0, sizeof(buf)); - - if (status & TX_DMA_ERROR) - buf[i++] = 'm'; - if (status & TX_DISABLED) - buf[i++] = 'd'; - if (status & TX_RETRY_EXCEEDED) - buf[i++] = 'r'; - if (status & TX_TIMEOUT) - buf[i++] = 't'; - if (status & TX_KEY_NOT_FOUND) - buf[i++] = 'k'; - if (status & TX_ENCRYPT_FAIL) - buf[i++] = 'e'; - if (status & TX_UNAVAILABLE_PRIORITY) - buf[i++] = 'p'; - - /* bit 0 is unused apparently */ - - return buf; -} - -static void wl1251_tx_packet_cb(struct wl1251 *wl, - struct tx_result *result) -{ - struct ieee80211_tx_info *info; - struct sk_buff *skb; - int hdrlen, ret; - u8 *frame; - - skb = wl->tx_frames[result->id]; - if (skb == NULL) { - wl1251_error("SKB for packet %d is NULL", result->id); - return; - } - - info = IEEE80211_SKB_CB(skb); - - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && - (result->status == TX_SUCCESS)) - info->flags |= IEEE80211_TX_STAT_ACK; - - info->status.rates[0].count = result->ack_failures + 1; - wl->stats.retry_count += result->ack_failures; - - /* - * We have to remove our private TX header before pushing - * the skb back to mac80211. - */ - frame = skb_pull(skb, sizeof(struct tx_double_buffer_desc)); - if (info->control.hw_key && - info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) { - hdrlen = ieee80211_get_hdrlen_from_skb(skb); - memmove(frame + WL1251_TKIP_IV_SPACE, frame, hdrlen); - skb_pull(skb, WL1251_TKIP_IV_SPACE); - } - - wl1251_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x" - " status 0x%x (%s)", - result->id, skb, result->ack_failures, result->rate, - result->status, wl1251_tx_parse_status(result->status)); - - - ieee80211_tx_status(wl->hw, skb); - - wl->tx_frames[result->id] = NULL; - - if (wl->tx_queue_stopped) { - wl1251_debug(DEBUG_TX, "cb: queue was stopped"); - - skb = skb_dequeue(&wl->tx_queue); - - /* The skb can be NULL because tx_work might have been - scheduled before the queue was stopped making the - queue empty */ - - if (skb) { - ret = wl1251_tx_frame(wl, skb); - if (ret == -EBUSY) { - /* firmware buffer is still full */ - wl1251_debug(DEBUG_TX, "cb: fw buffer " - "still full"); - skb_queue_head(&wl->tx_queue, skb); - return; - } else if (ret < 0) { - dev_kfree_skb(skb); - return; - } - } - - wl1251_debug(DEBUG_TX, "cb: waking queues"); - ieee80211_wake_queues(wl->hw); - wl->tx_queue_stopped = false; - } -} - -/* Called upon reception of a TX complete interrupt */ -void wl1251_tx_complete(struct wl1251 *wl) -{ - int i, result_index, num_complete = 0; - struct tx_result result[FW_TX_CMPLT_BLOCK_SIZE], *result_ptr; - unsigned long flags; - - if (unlikely(wl->state != WL1251_STATE_ON)) - return; - - /* First we read the result */ - wl1251_mem_read(wl, wl->data_path->tx_complete_addr, - result, sizeof(result)); - - result_index = wl->next_tx_complete; - - for (i = 0; i < ARRAY_SIZE(result); i++) { - result_ptr = &result[result_index]; - - if (result_ptr->done_1 == 1 && - result_ptr->done_2 == 1) { - wl1251_tx_packet_cb(wl, result_ptr); - - result_ptr->done_1 = 0; - result_ptr->done_2 = 0; - - result_index = (result_index + 1) & - (FW_TX_CMPLT_BLOCK_SIZE - 1); - num_complete++; - } else { - break; - } - } - - if (wl->tx_queue_stopped - && - skb_queue_len(&wl->tx_queue) <= WL1251_TX_QUEUE_LOW_WATERMARK){ - - /* firmware buffer has space, restart queues */ - wl1251_debug(DEBUG_TX, "tx_complete: waking queues"); - spin_lock_irqsave(&wl->wl_lock, flags); - ieee80211_wake_queues(wl->hw); - wl->tx_queue_stopped = false; - spin_unlock_irqrestore(&wl->wl_lock, flags); - ieee80211_queue_work(wl->hw, &wl->tx_work); - - } - - /* Every completed frame needs to be acknowledged */ - if (num_complete) { - /* - * If we've wrapped, we have to clear - * the results in 2 steps. - */ - if (result_index > wl->next_tx_complete) { - /* Only 1 write is needed */ - wl1251_mem_write(wl, - wl->data_path->tx_complete_addr + - (wl->next_tx_complete * - sizeof(struct tx_result)), - &result[wl->next_tx_complete], - num_complete * - sizeof(struct tx_result)); - - - } else if (result_index < wl->next_tx_complete) { - /* 2 writes are needed */ - wl1251_mem_write(wl, - wl->data_path->tx_complete_addr + - (wl->next_tx_complete * - sizeof(struct tx_result)), - &result[wl->next_tx_complete], - (FW_TX_CMPLT_BLOCK_SIZE - - wl->next_tx_complete) * - sizeof(struct tx_result)); - - wl1251_mem_write(wl, - wl->data_path->tx_complete_addr, - result, - (num_complete - - FW_TX_CMPLT_BLOCK_SIZE + - wl->next_tx_complete) * - sizeof(struct tx_result)); - - } else { - /* We have to write the whole array */ - wl1251_mem_write(wl, - wl->data_path->tx_complete_addr, - result, - FW_TX_CMPLT_BLOCK_SIZE * - sizeof(struct tx_result)); - } - - } - - wl->next_tx_complete = result_index; -} - -/* caller must hold wl->mutex */ -void wl1251_tx_flush(struct wl1251 *wl) -{ - int i; - struct sk_buff *skb; - struct ieee80211_tx_info *info; - - /* TX failure */ -/* control->flags = 0; FIXME */ - - while ((skb = skb_dequeue(&wl->tx_queue))) { - info = IEEE80211_SKB_CB(skb); - - wl1251_debug(DEBUG_TX, "flushing skb 0x%p", skb); - - if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) - continue; - - ieee80211_tx_status(wl->hw, skb); - } - - for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) - if (wl->tx_frames[i] != NULL) { - skb = wl->tx_frames[i]; - info = IEEE80211_SKB_CB(skb); - - if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) - continue; - - ieee80211_tx_status(wl->hw, skb); - wl->tx_frames[i] = NULL; - } -} diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.h b/drivers/net/wireless/wl12xx/wl1251_tx.h deleted file mode 100644 index 96011e7..0000000 --- a/drivers/net/wireless/wl12xx/wl1251_tx.h +++ /dev/null @@ -1,231 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL1251_TX_H__ -#define __WL1251_TX_H__ - -#include -#include "wl1251_acx.h" - -/* - * - * TX PATH - * - * The Tx path uses a double buffer and a tx_control structure, each located - * at a fixed address in the device's memory. On startup, the host retrieves - * the pointers to these addresses. A double buffer allows for continuous data - * flow towards the device. The host keeps track of which buffer is available - * and alternates between these two buffers on a per packet basis. - * - * The size of each of the two buffers is large enough to hold the longest - * 802.3 packet - maximum size Ethernet packet + header + descriptor. - * TX complete indication will be received a-synchronously in a TX done cyclic - * buffer which is composed of 16 tx_result descriptors structures and is used - * in a cyclic manner. - * - * The TX (HOST) procedure is as follows: - * 1. Read the Tx path status, that will give the data_out_count. - * 2. goto 1, if not possible. - * i.e. if data_in_count - data_out_count >= HwBuffer size (2 for double - * buffer). - * 3. Copy the packet (preceded by double_buffer_desc), if possible. - * i.e. if data_in_count - data_out_count < HwBuffer size (2 for double - * buffer). - * 4. increment data_in_count. - * 5. Inform the firmware by generating a firmware internal interrupt. - * 6. FW will increment data_out_count after it reads the buffer. - * - * The TX Complete procedure: - * 1. To get a TX complete indication the host enables the tx_complete flag in - * the TX descriptor Structure. - * 2. For each packet with a Tx Complete field set, the firmware adds the - * transmit results to the cyclic buffer (txDoneRing) and sets both done_1 - * and done_2 to 1 to indicate driver ownership. - * 3. The firmware sends a Tx Complete interrupt to the host to trigger the - * host to process the new data. Note: interrupt will be send per packet if - * TX complete indication was requested in tx_control or per crossing - * aggregation threshold. - * 4. After receiving the Tx Complete interrupt, the host reads the - * TxDescriptorDone information in a cyclic manner and clears both done_1 - * and done_2 fields. - * - */ - -#define TX_COMPLETE_REQUIRED_BIT 0x80 -#define TX_STATUS_DATA_OUT_COUNT_MASK 0xf - -#define WL1251_TX_ALIGN_TO 4 -#define WL1251_TX_ALIGN(len) (((len) + WL1251_TX_ALIGN_TO - 1) & \ - ~(WL1251_TX_ALIGN_TO - 1)) -#define WL1251_TKIP_IV_SPACE 4 - -struct tx_control { - /* Rate Policy (class) index */ - unsigned rate_policy:3; - - /* When set, no ack policy is expected */ - unsigned ack_policy:1; - - /* - * Packet type: - * 0 -> 802.11 - * 1 -> 802.3 - * 2 -> IP - * 3 -> raw codec - */ - unsigned packet_type:2; - - /* If set, this is a QoS-Null or QoS-Data frame */ - unsigned qos:1; - - /* - * If set, the target triggers the tx complete INT - * upon frame sending completion. - */ - unsigned tx_complete:1; - - /* 2 bytes padding before packet header */ - unsigned xfer_pad:1; - - unsigned reserved:7; -} __packed; - - -struct tx_double_buffer_desc { - /* Length of payload, including headers. */ - __le16 length; - - /* - * A bit mask that specifies the initial rate to be used - * Possible values are: - * 0x0001 - 1Mbits - * 0x0002 - 2Mbits - * 0x0004 - 5.5Mbits - * 0x0008 - 6Mbits - * 0x0010 - 9Mbits - * 0x0020 - 11Mbits - * 0x0040 - 12Mbits - * 0x0080 - 18Mbits - * 0x0100 - 22Mbits - * 0x0200 - 24Mbits - * 0x0400 - 36Mbits - * 0x0800 - 48Mbits - * 0x1000 - 54Mbits - */ - __le16 rate; - - /* Time in us that a packet can spend in the target */ - __le32 expiry_time; - - /* index of the TX queue used for this packet */ - u8 xmit_queue; - - /* Used to identify a packet */ - u8 id; - - struct tx_control control; - - /* - * The FW should cut the packet into fragments - * of this size. - */ - __le16 frag_threshold; - - /* Numbers of HW queue blocks to be allocated */ - u8 num_mem_blocks; - - u8 reserved; -} __packed; - -enum { - TX_SUCCESS = 0, - TX_DMA_ERROR = BIT(7), - TX_DISABLED = BIT(6), - TX_RETRY_EXCEEDED = BIT(5), - TX_TIMEOUT = BIT(4), - TX_KEY_NOT_FOUND = BIT(3), - TX_ENCRYPT_FAIL = BIT(2), - TX_UNAVAILABLE_PRIORITY = BIT(1), -}; - -struct tx_result { - /* - * Ownership synchronization between the host and - * the firmware. If done_1 and done_2 are cleared, - * owned by the FW (no info ready). - */ - u8 done_1; - - /* same as double_buffer_desc->id */ - u8 id; - - /* - * Total air access duration consumed by this - * packet, including all retries and overheads. - */ - u16 medium_usage; - - /* Total media delay (from 1st EDCA AIFS counter until TX Complete). */ - u32 medium_delay; - - /* Time between host xfer and tx complete */ - u32 fw_hnadling_time; - - /* The LS-byte of the last TKIP sequence number. */ - u8 lsb_seq_num; - - /* Retry count */ - u8 ack_failures; - - /* At which rate we got a ACK */ - u16 rate; - - u16 reserved; - - /* TX_* */ - u8 status; - - /* See done_1 */ - u8 done_2; -} __packed; - -static inline int wl1251_tx_get_queue(int queue) -{ - switch (queue) { - case 0: - return QOS_AC_VO; - case 1: - return QOS_AC_VI; - case 2: - return QOS_AC_BE; - case 3: - return QOS_AC_BK; - default: - return QOS_AC_BE; - } -} - -void wl1251_tx_work(struct work_struct *work); -void wl1251_tx_complete(struct wl1251 *wl); -void wl1251_tx_flush(struct wl1251 *wl); - -#endif -- cgit v0.10.2 From cc2858c987f41286e059ee777c3bc09f7b7c19f6 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Sun, 10 Oct 2010 11:28:33 +0300 Subject: wl1251: update the new location to the maintainers file wl1251 is grown up now and can have its own room^H^H^H^Hdirectory. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/MAINTAINERS b/MAINTAINERS index 529bfee..339606e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6314,8 +6314,7 @@ L: linux-wireless@vger.kernel.org W: http://wireless.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git S: Maintained -F: drivers/net/wireless/wl12xx/* -X: drivers/net/wireless/wl12xx/wl1271* +F: drivers/net/wireless/wl1251/* WL1271 WIRELESS DRIVER M: Luciano Coelho -- cgit v0.10.2 From 730bd83b036e72b0134352ca27e76ea08475fbf1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 10 Oct 2010 18:52:10 +0200 Subject: mac80211: don't kmalloc 16 bytes Since this small buffer isn't used for DMA, we can simply allocate it on the stack, it just needs to be 16 bytes of which only 8 will be used for WEP40 keys. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index f27484c..2ff6d1e 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c @@ -222,7 +222,7 @@ static int ieee80211_wep_decrypt(struct ieee80211_local *local, struct ieee80211_key *key) { u32 klen; - u8 *rc4key; + u8 rc4key[3 + WLAN_KEY_LEN_WEP104]; u8 keyidx; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; unsigned int hdrlen; @@ -245,10 +245,6 @@ static int ieee80211_wep_decrypt(struct ieee80211_local *local, klen = 3 + key->conf.keylen; - rc4key = kmalloc(klen, GFP_ATOMIC); - if (!rc4key) - return -1; - /* Prepend 24-bit IV to RC4 key */ memcpy(rc4key, skb->data + hdrlen, 3); @@ -260,8 +256,6 @@ static int ieee80211_wep_decrypt(struct ieee80211_local *local, len)) ret = -1; - kfree(rc4key); - /* Trim ICV */ skb_trim(skb, skb->len - WEP_ICV_LEN); -- cgit v0.10.2 From 15d46f38df87f89242e470f5797120fa384c1fc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Smedman?= Date: Sun, 10 Oct 2010 22:14:25 +0200 Subject: mac80211: minstrel_ht A-MPDU fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch fixes two problems with the minstrel_ht rate control algorithms handling of A-MPDU frames: 1. The ampdu_len field of the tx status is not always initialized for non-HT frames (and it would probably be unreasonable to require all drivers to do so). This could cause rate control statistics to be corrupted. We now trust the ampdu_len and ampdu_ack_len fields only when the frame is marked with the IEEE80211_TX_STAT_AMPDU flag. 2. Successful transmission attempts where only recognized when the A-MPDU subframe carrying the rate control status information was marked with the IEEE80211_TX_STAT_ACK flag. If this information happed to be carried on a frame that failed to be ACKed then the other subframes (which may have succeeded) where not correctly registered. We now update rate control statistics regardless of whether the subframe carrying the information was ACKed or not. Cc: Signed-off-by: Björn Smedman Acked-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index c5b4659..2a18d66 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -397,8 +397,9 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, !(info->flags & IEEE80211_TX_STAT_AMPDU)) return; - if (!info->status.ampdu_len) { - info->status.ampdu_ack_len = 1; + if (!(info->flags & IEEE80211_TX_STAT_AMPDU)) { + info->status.ampdu_ack_len = + (info->flags & IEEE80211_TX_STAT_ACK ? 1 : 0); info->status.ampdu_len = 1; } @@ -426,7 +427,7 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, group = minstrel_ht_get_group_idx(&ar[i]); rate = &mi->groups[group].rates[ar[i].idx % 8]; - if (last && (info->flags & IEEE80211_TX_STAT_ACK)) + if (last) rate->success += info->status.ampdu_ack_len; rate->attempts += ar[i].count * info->status.ampdu_len; -- cgit v0.10.2 From ebd022873aa61937603d2c4dfea19ce63ea1a3c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Smedman?= Date: Sun, 10 Oct 2010 22:44:39 +0200 Subject: ath9k: A-MPDU rate control info fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch fixes the following problems with the rate control feedback generated by ath9k for A-MPDU frames: 1. Rate control feedback is carried on the first frame of an aggregate that is either ACKed, or has execeeded the software retry count and is considered failed. However, ath9k would incorrectly assume the aggregate had the length 1 if one of these conditions did not apply to the first frame of the aggregate, but instead a later frame. This fix therefor copies the bf_nframes field of the buffer in the same manner as the rates field of the tx status. 2. Sometimes the ampdu_len and ampdu_ack_len fields of the tx status was left uninitialized eventhough the IEEE80211_TX_STAT_AMPDU flag was set. This is now avoid by setting flag and fields in the same place. 3. Even if a frame has been selected for aggregation by mac80211 and marked with the IEEE80211_TX_CTL_AMPDU flag it can sometimes happen that ath9k transmits the frame without aggregation. In these cases the ampdu_ack_len field could be incorrectly computed because the nbad parameter to ath_tx_rc_status was incorrect. Cc: Signed-off-by: Björn Smedman Acked-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index aa44777..9a11099 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -317,6 +317,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0; bool rc_update = true; struct ieee80211_tx_rate rates[4]; + int nframes; skb = bf->bf_mpdu; hdr = (struct ieee80211_hdr *)skb->data; @@ -325,6 +326,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, hw = bf->aphy->hw; memcpy(rates, tx_info->control.rates, sizeof(rates)); + nframes = bf->bf_nframes; rcu_read_lock(); @@ -341,7 +343,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, !bf->bf_stale || bf_next != NULL) list_move_tail(&bf->list, &bf_head); - ath_tx_rc_status(bf, ts, 0, 0, false); + ath_tx_rc_status(bf, ts, 1, 0, false); ath_tx_complete_buf(sc, bf, txq, &bf_head, ts, 0, 0); @@ -446,6 +448,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) { memcpy(tx_info->control.rates, rates, sizeof(rates)); + bf->bf_nframes = nframes; ath_tx_rc_status(bf, ts, nbad, txok, true); rc_update = false; } else { @@ -1979,9 +1982,15 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts, if (ts->ts_status & ATH9K_TXERR_FILT) tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; - if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc) + if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc) { tx_info->flags |= IEEE80211_TX_STAT_AMPDU; + BUG_ON(nbad > bf->bf_nframes); + + tx_info->status.ampdu_len = bf->bf_nframes; + tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad; + } + if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 && (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) { if (ieee80211_is_data(hdr->frame_control)) { @@ -1991,8 +2000,6 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts, if ((ts->ts_status & ATH9K_TXERR_XRETRY) || (ts->ts_status & ATH9K_TXERR_FIFO)) tx_info->pad[0] |= ATH_TX_INFO_XRETRY; - tx_info->status.ampdu_len = bf->bf_nframes; - tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad; } } @@ -2102,7 +2109,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) */ if (ts.ts_status & ATH9K_TXERR_XRETRY) bf->bf_state.bf_type |= BUF_XRETRY; - ath_tx_rc_status(bf, &ts, 0, txok, true); + ath_tx_rc_status(bf, &ts, txok ? 0 : 1, txok, true); } if (bf_isampdu(bf)) @@ -2220,7 +2227,7 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) if (!bf_isampdu(bf)) { if (txs.ts_status & ATH9K_TXERR_XRETRY) bf->bf_state.bf_type |= BUF_XRETRY; - ath_tx_rc_status(bf, &txs, 0, txok, true); + ath_tx_rc_status(bf, &txs, txok ? 0 : 1, txok, true); } if (bf_isampdu(bf)) -- cgit v0.10.2 From a8909cfb1832ac623142898df2a9374722cfe68f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Smedman?= Date: Sun, 10 Oct 2010 22:51:54 +0200 Subject: ath9k: built-in rate control A-MPDU fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch attempts to ensure that ath9k's built-in rate control algorithm does not rely on the value of the ampdu_len and ampdu_ack_len tx status fields unless the IEEE80211_TX_STAT_AMPDU flag is set. This patch has not been tested. Cc: Signed-off-by: Björn Smedman Acked-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index ce1cd6d..13f9e88 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -1375,6 +1375,12 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, if (tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) return; + if (!(tx_info->flags & IEEE80211_TX_STAT_AMPDU)) { + tx_info->status.ampdu_ack_len = + (tx_info->flags & IEEE80211_TX_STAT_ACK ? 1 : 0); + tx_info->status.ampdu_len = 1; + } + /* * If an underrun error is seen assume it as an excessive retry only * if max frame trigger level has been reached (2 KB for singel stream, -- cgit v0.10.2 From a656b6a9665dce09a8f273091f1b4aa3d5cec721 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Mon, 11 Oct 2010 03:11:01 +0200 Subject: b43: N-PHY: grab more info about new channel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 52ce438..6ca41a0 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -3323,9 +3323,9 @@ int b43_phy_initn(struct b43_wldev *dev) } /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ChanspecSetup */ -static void b43_nphy_chanspec_setup(struct b43_wldev *dev, +static void b43_nphy_channel_setup(struct b43_wldev *dev, const struct b43_phy_n_sfo_cfg *e, - struct b43_chanspec chanspec) + struct ieee80211_channel *new_channel) { struct b43_phy *phy = &dev->phy; struct b43_phy_n *nphy = dev->phy.n; @@ -3334,13 +3334,13 @@ static void b43_nphy_chanspec_setup(struct b43_wldev *dev, u32 tmp32; tmp = b43_phy_read(dev, B43_NPHY_BANDCTL) & B43_NPHY_BANDCTL_5GHZ; - if (chanspec.b_freq == 1 && tmp == 0) { + if (new_channel->band == IEEE80211_BAND_5GHZ && tmp == 0) { tmp32 = b43_read32(dev, B43_MMIO_PSM_PHY_HDR); b43_write32(dev, B43_MMIO_PSM_PHY_HDR, tmp32 | 4); b43_phy_set(dev, B43_PHY_B_BBCFG, 0xC000); b43_write32(dev, B43_MMIO_PSM_PHY_HDR, tmp32); b43_phy_set(dev, B43_NPHY_BANDCTL, B43_NPHY_BANDCTL_5GHZ); - } else if (chanspec.b_freq == 1) { + } else if (new_channel->band == IEEE80211_BAND_5GHZ) { b43_phy_mask(dev, B43_NPHY_BANDCTL, ~B43_NPHY_BANDCTL_5GHZ); tmp32 = b43_read32(dev, B43_MMIO_PSM_PHY_HDR); b43_write32(dev, B43_MMIO_PSM_PHY_HDR, tmp32 | 4); @@ -3350,13 +3350,12 @@ static void b43_nphy_chanspec_setup(struct b43_wldev *dev, b43_chantab_phy_upload(dev, e); - - if (nphy->radio_chanspec.channel == 14) { + if (new_channel->hw_value == 14) { b43_nphy_classifier(dev, 2, 0); b43_phy_set(dev, B43_PHY_B_TEST, 0x0800); } else { b43_nphy_classifier(dev, 2, 2); - if (chanspec.b_freq == 2) + if (new_channel->band == IEEE80211_BAND_2GHZ) b43_phy_mask(dev, B43_PHY_B_TEST, ~0x840); } @@ -3379,16 +3378,17 @@ static void b43_nphy_chanspec_setup(struct b43_wldev *dev, } /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SetChanspec */ -static int b43_nphy_set_chanspec(struct b43_wldev *dev, - struct b43_chanspec chanspec) +static int b43_nphy_set_channel(struct b43_wldev *dev, + struct ieee80211_channel *channel, + enum nl80211_channel_type channel_type) { + struct b43_phy *phy = &dev->phy; struct b43_phy_n *nphy = dev->phy.n; const struct b43_nphy_channeltab_entry_rev2 *tabent_r2; const struct b43_nphy_channeltab_entry_rev3 *tabent_r3; u8 tmp; - u8 channel = chanspec.channel; if (dev->phy.rev >= 3) { /* TODO */ @@ -3396,36 +3396,36 @@ static int b43_nphy_set_chanspec(struct b43_wldev *dev, if (!tabent_r3) return -ESRCH; } else { - tabent_r2 = b43_nphy_get_chantabent_rev2(dev, channel); + tabent_r2 = b43_nphy_get_chantabent_rev2(dev, + channel->hw_value); if (!tabent_r2) return -ESRCH; } - nphy->radio_chanspec = chanspec; + nphy->radio_chanspec.channel = channel->hw_value; + /* if (chanspec.b_width != nphy->b_width) - ; /* TODO: BMAC BW Set (chanspec.b_width) */ + ; TODO: BMAC BW Set (chanspec.b_width) + */ - /* TODO: use defines */ - if (chanspec.b_width == 3) { - if (chanspec.sideband == 2) - b43_phy_set(dev, B43_NPHY_RXCTL, - B43_NPHY_RXCTL_BSELU20); - else - b43_phy_mask(dev, B43_NPHY_RXCTL, - ~B43_NPHY_RXCTL_BSELU20); - } + if (channel_type == NL80211_CHAN_HT40PLUS) + b43_phy_set(dev, B43_NPHY_RXCTL, + B43_NPHY_RXCTL_BSELU20); + else if (channel_type == NL80211_CHAN_HT40MINUS) + b43_phy_mask(dev, B43_NPHY_RXCTL, + ~B43_NPHY_RXCTL_BSELU20); if (dev->phy.rev >= 3) { - tmp = (chanspec.b_freq == 1) ? 4 : 0; + tmp = (channel->band == IEEE80211_BAND_5GHZ) ? 4 : 0; b43_radio_maskset(dev, 0x08, 0xFFFB, tmp); /* TODO: PHY Radio2056 Setup (dev, tabent_r3); */ - b43_nphy_chanspec_setup(dev, &(tabent_r3->phy_regs), chanspec); + b43_nphy_channel_setup(dev, &(tabent_r3->phy_regs), channel); } else { - tmp = (chanspec.b_freq == 1) ? 0x0020 : 0x0050; + tmp = (channel->band == IEEE80211_BAND_5GHZ) ? 0x0020 : 0x0050; b43_radio_maskset(dev, B2055_MASTER1, 0xFF8F, tmp); b43_radio_2055_setup(dev, tabent_r2); - b43_nphy_chanspec_setup(dev, &(tabent_r2->phy_regs), chanspec); + b43_nphy_channel_setup(dev, &(tabent_r2->phy_regs), channel); } return 0; @@ -3567,8 +3567,8 @@ static void b43_nphy_op_switch_analog(struct b43_wldev *dev, bool on) static int b43_nphy_op_switch_channel(struct b43_wldev *dev, unsigned int new_channel) { - struct b43_phy_n *nphy = dev->phy.n; - struct b43_chanspec chanspec; + struct ieee80211_channel *channel = dev->wl->hw->conf.channel; + enum nl80211_channel_type channel_type = dev->wl->hw->conf.channel_type; if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { if ((new_channel < 1) || (new_channel > 14)) @@ -3578,10 +3578,7 @@ static int b43_nphy_op_switch_channel(struct b43_wldev *dev, return -EINVAL; } - chanspec = nphy->radio_chanspec; - chanspec.channel = new_channel; - - return b43_nphy_set_chanspec(dev, chanspec); + return b43_nphy_set_channel(dev, channel, channel_type); } static unsigned int b43_nphy_op_get_default_chan(struct b43_wldev *dev) -- cgit v0.10.2 From e5c407f970ea2977600eb54cf4cc8a67a44fefeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Mon, 11 Oct 2010 03:11:02 +0200 Subject: b43: N-PHY: store info about current channel's type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h index bd480b4..6dcd033 100644 --- a/drivers/net/wireless/b43/phy_common.h +++ b/drivers/net/wireless/b43/phy_common.h @@ -2,6 +2,7 @@ #define LINUX_B43_PHY_COMMON_H_ #include +#include struct b43_wldev; @@ -250,8 +251,9 @@ struct b43_phy { * check is needed. */ unsigned long next_txpwr_check_time; - /* current channel */ + /* Current channel */ unsigned int channel; + enum nl80211_channel_type channel_type; /* PHY TX errors counter. */ atomic_t txerr_cnt; diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 6ca41a0..789d21c 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -74,6 +74,13 @@ static void b43_nphy_rf_control_override(struct b43_wldev *dev, u16 field, static void b43_nphy_rf_control_intc_override(struct b43_wldev *dev, u8 field, u16 value, u8 core); +static inline bool b43_channel_type_is_40mhz( + enum nl80211_channel_type channel_type) +{ + return (channel_type == NL80211_CHAN_HT40MINUS || + channel_type == NL80211_CHAN_HT40PLUS); +} + static inline bool b43_empty_chanspec(struct b43_chanspec *chanspec) { return !chanspec->channel && !chanspec->sideband && @@ -3404,10 +3411,9 @@ static int b43_nphy_set_channel(struct b43_wldev *dev, nphy->radio_chanspec.channel = channel->hw_value; - /* - if (chanspec.b_width != nphy->b_width) - ; TODO: BMAC BW Set (chanspec.b_width) - */ + if (b43_channel_type_is_40mhz(phy->channel_type) != + b43_channel_type_is_40mhz(channel_type)) + ; /* TODO: BMAC BW Set (channel_type) */ if (channel_type == NL80211_CHAN_HT40PLUS) b43_phy_set(dev, B43_NPHY_RXCTL, diff --git a/drivers/net/wireless/b43/phy_n.h b/drivers/net/wireless/b43/phy_n.h index 8b6d570..e7acae2 100644 --- a/drivers/net/wireless/b43/phy_n.h +++ b/drivers/net/wireless/b43/phy_n.h @@ -984,7 +984,6 @@ struct b43_phy_n { u16 papd_epsilon_offset[2]; s32 preamble_override; u32 bb_mult_save; - u8 b_width; struct b43_chanspec radio_chanspec; bool gain_boost; -- cgit v0.10.2 From 087de74ae512fe31894c1556d5f8d5a126322de7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Mon, 11 Oct 2010 03:11:03 +0200 Subject: b43: N-PHY: fix logic in band switching MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 789d21c..19582ba 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -3337,17 +3337,18 @@ static void b43_nphy_channel_setup(struct b43_wldev *dev, struct b43_phy *phy = &dev->phy; struct b43_phy_n *nphy = dev->phy.n; - u16 tmp; + u16 old_band_5ghz; u32 tmp32; - tmp = b43_phy_read(dev, B43_NPHY_BANDCTL) & B43_NPHY_BANDCTL_5GHZ; - if (new_channel->band == IEEE80211_BAND_5GHZ && tmp == 0) { + old_band_5ghz = + b43_phy_read(dev, B43_NPHY_BANDCTL) & B43_NPHY_BANDCTL_5GHZ; + if (new_channel->band == IEEE80211_BAND_5GHZ && !old_band_5ghz) { tmp32 = b43_read32(dev, B43_MMIO_PSM_PHY_HDR); b43_write32(dev, B43_MMIO_PSM_PHY_HDR, tmp32 | 4); b43_phy_set(dev, B43_PHY_B_BBCFG, 0xC000); b43_write32(dev, B43_MMIO_PSM_PHY_HDR, tmp32); b43_phy_set(dev, B43_NPHY_BANDCTL, B43_NPHY_BANDCTL_5GHZ); - } else if (new_channel->band == IEEE80211_BAND_5GHZ) { + } else if (new_channel->band == IEEE80211_BAND_2GHZ && old_band_5ghz) { b43_phy_mask(dev, B43_NPHY_BANDCTL, ~B43_NPHY_BANDCTL_5GHZ); tmp32 = b43_read32(dev, B43_MMIO_PSM_PHY_HDR); b43_write32(dev, B43_MMIO_PSM_PHY_HDR, tmp32 | 4); -- cgit v0.10.2 From f2a6d6a08cf13f621661dd57f32bf0a5100ba26b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Mon, 11 Oct 2010 03:19:22 +0200 Subject: b43: N-PHY: prepare for rev3+ channel tables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 19582ba..e532901 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -3399,7 +3399,8 @@ static int b43_nphy_set_channel(struct b43_wldev *dev, u8 tmp; if (dev->phy.rev >= 3) { - /* TODO */ + tabent_r3 = b43_nphy_get_chantabent_rev3(dev, + channel->center_freq); tabent_r3 = NULL; if (!tabent_r3) return -ESRCH; diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c index d96e870..e74b8eb5 100644 --- a/drivers/net/wireless/b43/tables_nphy.c +++ b/drivers/net/wireless/b43/tables_nphy.c @@ -325,7 +325,7 @@ void b2055_upload_inittab(struct b43_wldev *dev, .phy_regs.phy_bw5 = r4, \ .phy_regs.phy_bw6 = r5 -static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab[] = { +static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = { { .channel = 184, .freq = 4920, /* MHz */ .unk2 = 3280, @@ -1326,8 +1326,8 @@ b43_nphy_get_chantabent_rev2(struct b43_wldev *dev, u8 channel) const struct b43_nphy_channeltab_entry_rev2 *e; unsigned int i; - for (i = 0; i < ARRAY_SIZE(b43_nphy_channeltab); i++) { - e = &(b43_nphy_channeltab[i]); + for (i = 0; i < ARRAY_SIZE(b43_nphy_channeltab_rev2); i++) { + e = &(b43_nphy_channeltab_rev2[i]); if (e->channel == channel) return e; } @@ -1335,6 +1335,24 @@ b43_nphy_get_chantabent_rev2(struct b43_wldev *dev, u8 channel) return NULL; } +static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev3[] = { +}; + +const struct b43_nphy_channeltab_entry_rev3 * +b43_nphy_get_chantabent_rev3(struct b43_wldev *dev, u16 freq) +{ + const struct b43_nphy_channeltab_entry_rev3 *e; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(b43_nphy_channeltab_rev3); i++) { + e = &(b43_nphy_channeltab_rev3[i]); + if (e->freq == freq) + return e; + } + + return NULL; +} + static const u8 b43_ntab_adjustpower0[] = { 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, diff --git a/drivers/net/wireless/b43/tables_nphy.h b/drivers/net/wireless/b43/tables_nphy.h index 8fc1da9..3eedb86 100644 --- a/drivers/net/wireless/b43/tables_nphy.h +++ b/drivers/net/wireless/b43/tables_nphy.h @@ -90,10 +90,12 @@ void b2055_upload_inittab(struct b43_wldev *dev, bool ghz5, bool ignore_uploadflag); -/* Get the NPHY Channel Switch Table entry for a channel number. +/* Get the NPHY Channel Switch Table entry for a channel. * Returns NULL on failure to find an entry. */ const struct b43_nphy_channeltab_entry_rev2 * b43_nphy_get_chantabent_rev2(struct b43_wldev *dev, u8 channel); +const struct b43_nphy_channeltab_entry_rev3 * +b43_nphy_get_chantabent_rev3(struct b43_wldev *dev, u16 freq); /* The N-PHY tables. */ -- cgit v0.10.2 From a9325199edb093a5c7311a25d15da20ee984e80b Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 11 Oct 2010 11:27:32 +0200 Subject: WIRELESS: at76c50x, remove unneeded NULL check Stanse found that urb cannot be NULL in at76_rx_tasklet because it is dereferenced earlier, so remove the unneeded check. Signed-off-by: Jiri Slaby Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index 91c5f73..1476314 100644 --- a/drivers/net/wireless/at76c50x-usb.c +++ b/drivers/net/wireless/at76c50x-usb.c @@ -1525,8 +1525,7 @@ static void at76_rx_tasklet(unsigned long param) if (priv->device_unplugged) { at76_dbg(DBG_DEVSTART, "device unplugged"); - if (urb) - at76_dbg(DBG_DEVSTART, "urb status %d", urb->status); + at76_dbg(DBG_DEVSTART, "urb status %d", urb->status); return; } -- cgit v0.10.2 From fa69560f317d961c56e29dea788b346d2b34fb87 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 11 Oct 2010 15:37:25 +0200 Subject: rt2x00: Simplify Queue function arguments A lot of functions accept a struct rt2x00_dev combined with either a struct queue_entry or struct data_queue argument. This can be simplified by only passing on the queue/entry argument. In cases where rt2x00_dev and a sk_buff are send together, we can send the queue_entry instead. rt2x00usb_alloc_urb and rt2x00usb_free_urb have a bit of vague naming. Instead they allocate all the data which belongs to a rt2x00 data queue entry. Signed-off-by: Ivo van Doorn Acked-by: Helmut Schaa Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 4b88909..095cb69 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1104,7 +1104,7 @@ static void rt2400pci_write_beacon(struct queue_entry *entry, rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); rt2x00pci_register_write(rt2x00dev, CSR14, reg); - rt2x00queue_map_txskb(rt2x00dev, entry->skb); + rt2x00queue_map_txskb(entry); /* * Write the TX descriptor for the beacon. diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 46ef692..7d85bf9 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1258,7 +1258,7 @@ static void rt2500pci_write_beacon(struct queue_entry *entry, rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); rt2x00pci_register_write(rt2x00dev, CSR14, reg); - rt2x00queue_map_txskb(rt2x00dev, entry->skb); + rt2x00queue_map_txskb(entry); /* * Write the TX descriptor for the beacon. diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 75ac662..2322c84 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -1036,17 +1036,15 @@ static inline bool rt2x00_is_soc(struct rt2x00_dev *rt2x00dev) /** * rt2x00queue_map_txskb - Map a skb into DMA for TX purposes. - * @rt2x00dev: Pointer to &struct rt2x00_dev. - * @skb: The skb to map. + * @entry: Pointer to &struct queue_entry */ -void rt2x00queue_map_txskb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb); +void rt2x00queue_map_txskb(struct queue_entry *entry); /** * rt2x00queue_unmap_skb - Unmap a skb from DMA. - * @rt2x00dev: Pointer to &struct rt2x00_dev. - * @skb: The skb to unmap. + * @entry: Pointer to &struct queue_entry */ -void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb); +void rt2x00queue_unmap_skb(struct queue_entry *entry); /** * rt2x00queue_get_queue - Convert queue index to queue pointer @@ -1093,8 +1091,7 @@ void rt2x00lib_dmadone(struct queue_entry *entry); void rt2x00lib_txdone(struct queue_entry *entry, struct txdone_entry_desc *txdesc); void rt2x00lib_txdone_noinfo(struct queue_entry *entry, u32 status); -void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry); +void rt2x00lib_rxdone(struct queue_entry *entry); /* * mac80211 handlers. diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 6f442b0..9b745fa 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -273,7 +273,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, /* * Unmap the skb. */ - rt2x00queue_unmap_skb(rt2x00dev, entry->skb); + rt2x00queue_unmap_skb(entry); /* * Remove the extra tx headroom from the skb. @@ -465,9 +465,9 @@ static int rt2x00lib_rxdone_read_signal(struct rt2x00_dev *rt2x00dev, return 0; } -void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry) +void rt2x00lib_rxdone(struct queue_entry *entry) { + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct rxdone_entry_desc rxdesc; struct sk_buff *skb; struct ieee80211_rx_status *rx_status; @@ -481,14 +481,14 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, * Allocate a new sk_buffer. If no new buffer available, drop the * received frame and reuse the existing buffer. */ - skb = rt2x00queue_alloc_rxskb(rt2x00dev, entry); + skb = rt2x00queue_alloc_rxskb(entry); if (!skb) return; /* * Unmap the skb. */ - rt2x00queue_unmap_skb(rt2x00dev, entry->skb); + rt2x00queue_unmap_skb(entry); /* * Extract the RXD details. diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 70c85ac..619da23 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -100,18 +100,15 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, /** * rt2x00queue_alloc_rxskb - allocate a skb for RX purposes. - * @rt2x00dev: Pointer to &struct rt2x00_dev. - * @queue: The queue for which the skb will be applicable. + * @entry: The entry for which the skb will be applicable. */ -struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry); +struct sk_buff *rt2x00queue_alloc_rxskb(struct queue_entry *entry); /** * rt2x00queue_free_skb - free a skb - * @rt2x00dev: Pointer to &struct rt2x00_dev. - * @skb: The skb to free. + * @entry: The entry for which the skb will be applicable. */ -void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb); +void rt2x00queue_free_skb(struct queue_entry *entry); /** * rt2x00queue_align_frame - Align 802.11 frame to 4-byte boundary diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index 63c2cc4..2449d78 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -84,7 +84,7 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) /* * Send the frame to rt2x00lib for further processing. */ - rt2x00lib_rxdone(rt2x00dev, entry); + rt2x00lib_rxdone(entry); } } EXPORT_SYMBOL_GPL(rt2x00pci_rxdone); diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 83630f1..7e30144 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -33,9 +33,9 @@ #include "rt2x00.h" #include "rt2x00lib.h" -struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry) +struct sk_buff *rt2x00queue_alloc_rxskb(struct queue_entry *entry) { + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct sk_buff *skb; struct skb_frame_desc *skbdesc; unsigned int frame_size; @@ -97,39 +97,42 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev, return skb; } -void rt2x00queue_map_txskb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb) +void rt2x00queue_map_txskb(struct queue_entry *entry) { - struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); + struct device *dev = entry->queue->rt2x00dev->dev; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); skbdesc->skb_dma = - dma_map_single(rt2x00dev->dev, skb->data, skb->len, DMA_TO_DEVICE); + dma_map_single(dev, entry->skb->data, entry->skb->len, DMA_TO_DEVICE); skbdesc->flags |= SKBDESC_DMA_MAPPED_TX; } EXPORT_SYMBOL_GPL(rt2x00queue_map_txskb); -void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb) +void rt2x00queue_unmap_skb(struct queue_entry *entry) { - struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); + struct device *dev = entry->queue->rt2x00dev->dev; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); if (skbdesc->flags & SKBDESC_DMA_MAPPED_RX) { - dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, skb->len, + dma_unmap_single(dev, skbdesc->skb_dma, entry->skb->len, DMA_FROM_DEVICE); skbdesc->flags &= ~SKBDESC_DMA_MAPPED_RX; } else if (skbdesc->flags & SKBDESC_DMA_MAPPED_TX) { - dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, skb->len, + dma_unmap_single(dev, skbdesc->skb_dma, entry->skb->len, DMA_TO_DEVICE); skbdesc->flags &= ~SKBDESC_DMA_MAPPED_TX; } } EXPORT_SYMBOL_GPL(rt2x00queue_unmap_skb); -void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb) +void rt2x00queue_free_skb(struct queue_entry *entry) { - if (!skb) + if (!entry->skb) return; - rt2x00queue_unmap_skb(rt2x00dev, skb); - dev_kfree_skb_any(skb); + rt2x00queue_unmap_skb(entry); + dev_kfree_skb_any(entry->skb); + entry->skb = NULL; } void rt2x00queue_align_frame(struct sk_buff *skb) @@ -438,7 +441,7 @@ static int rt2x00queue_write_tx_data(struct queue_entry *entry, * Map the skb to DMA. */ if (test_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags)) - rt2x00queue_map_txskb(rt2x00dev, entry->skb); + rt2x00queue_map_txskb(entry); return 0; } @@ -585,8 +588,7 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev, /* * Clean up the beacon skb. */ - rt2x00queue_free_skb(rt2x00dev, intf->beacon->skb); - intf->beacon->skb = NULL; + rt2x00queue_free_skb(intf->beacon); if (!enable_beacon) { rt2x00dev->ops->lib->kill_tx_queue(intf->beacon->queue); @@ -827,8 +829,7 @@ static int rt2x00queue_alloc_entries(struct data_queue *queue, return 0; } -static void rt2x00queue_free_skbs(struct rt2x00_dev *rt2x00dev, - struct data_queue *queue) +static void rt2x00queue_free_skbs(struct data_queue *queue) { unsigned int i; @@ -836,19 +837,17 @@ static void rt2x00queue_free_skbs(struct rt2x00_dev *rt2x00dev, return; for (i = 0; i < queue->limit; i++) { - if (queue->entries[i].skb) - rt2x00queue_free_skb(rt2x00dev, queue->entries[i].skb); + rt2x00queue_free_skb(&queue->entries[i]); } } -static int rt2x00queue_alloc_rxskbs(struct rt2x00_dev *rt2x00dev, - struct data_queue *queue) +static int rt2x00queue_alloc_rxskbs(struct data_queue *queue) { unsigned int i; struct sk_buff *skb; for (i = 0; i < queue->limit; i++) { - skb = rt2x00queue_alloc_rxskb(rt2x00dev, &queue->entries[i]); + skb = rt2x00queue_alloc_rxskb(&queue->entries[i]); if (!skb) return -ENOMEM; queue->entries[i].skb = skb; @@ -883,7 +882,7 @@ int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev) goto exit; } - status = rt2x00queue_alloc_rxskbs(rt2x00dev, rt2x00dev->rx); + status = rt2x00queue_alloc_rxskbs(rt2x00dev->rx); if (status) goto exit; @@ -901,7 +900,7 @@ void rt2x00queue_uninitialize(struct rt2x00_dev *rt2x00dev) { struct data_queue *queue; - rt2x00queue_free_skbs(rt2x00dev, rt2x00dev->rx); + rt2x00queue_free_skbs(rt2x00dev->rx); queue_for_each(rt2x00dev, queue) { kfree(queue->entries); diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 4c5ae3d..451d637 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -398,7 +398,7 @@ static void rt2x00usb_work_rxdone(struct work_struct *work) /* * Send the frame to rt2x00lib for further processing. */ - rt2x00lib_rxdone(rt2x00dev, entry); + rt2x00lib_rxdone(entry); } } @@ -542,9 +542,9 @@ static int rt2x00usb_find_endpoints(struct rt2x00_dev *rt2x00dev) return 0; } -static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev, - struct data_queue *queue) +static int rt2x00usb_alloc_entries(struct data_queue *queue) { + struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; struct queue_entry_priv_usb *entry_priv; struct queue_entry_priv_usb_bcn *bcn_priv; unsigned int i; @@ -561,7 +561,7 @@ static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev, * no guardian byte was required for the beacon, * then we are done. */ - if (rt2x00dev->bcn != queue || + if (queue->qid != QID_BEACON || !test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags)) return 0; @@ -575,9 +575,9 @@ static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev, return 0; } -static void rt2x00usb_free_urb(struct rt2x00_dev *rt2x00dev, - struct data_queue *queue) +static void rt2x00usb_free_entries(struct data_queue *queue) { + struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; struct queue_entry_priv_usb *entry_priv; struct queue_entry_priv_usb_bcn *bcn_priv; unsigned int i; @@ -596,7 +596,7 @@ static void rt2x00usb_free_urb(struct rt2x00_dev *rt2x00dev, * no guardian byte was required for the beacon, * then we are done. */ - if (rt2x00dev->bcn != queue || + if (queue->qid != QID_BEACON || !test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags)) return; @@ -623,7 +623,7 @@ int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev) * Allocate DMA */ queue_for_each(rt2x00dev, queue) { - status = rt2x00usb_alloc_urb(rt2x00dev, queue); + status = rt2x00usb_alloc_entries(queue); if (status) goto exit; } @@ -642,7 +642,7 @@ void rt2x00usb_uninitialize(struct rt2x00_dev *rt2x00dev) struct data_queue *queue; queue_for_each(rt2x00dev, queue) - rt2x00usb_free_urb(rt2x00dev, queue); + rt2x00usb_free_entries(queue); } EXPORT_SYMBOL_GPL(rt2x00usb_uninitialize); -- cgit v0.10.2 From cdfd2c5cffac2e744c855f9998212867387bb2de Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 11 Oct 2010 15:37:47 +0200 Subject: rt2x00: Move watchdog work to kernel work_queue The watchdog function must run on a work_queue which is independent of any other work inside rt2x00. The main reasons, being that a broken work on the mac80211 work_queue can otherwise prevent the watchdog to run (while in fact the watchdog could fix the issue). And on the other hand because the watchdog relies on the completion of the completion handlers for RX/TX which for the USB case, occur on the mac80211 workqueue. This fixes some "Queue %d failed to flush" errors, which were caused by the watchdog function waiting on the completion handler which was scheduled to run right after the watchdog. Signed-off-by: Ivo van Doorn Acked-by: Helmut Schaa Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 2322c84..94fe589 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -338,6 +338,11 @@ struct link { /* * Work structure for scheduling periodic watchdog monitoring. + * This work must be scheduled on the kernel workqueue, while + * all other work structures must be queued on the mac80211 + * workqueue. This guarantees that the watchdog can schedule + * other work structures and wait for their completion in order + * to bring the device/driver back into the desired state. */ struct delayed_work watchdog_work; }; diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c index 46836f8..b971d87 100644 --- a/drivers/net/wireless/rt2x00/rt2x00link.c +++ b/drivers/net/wireless/rt2x00/rt2x00link.c @@ -417,8 +417,7 @@ void rt2x00link_start_watchdog(struct rt2x00_dev *rt2x00dev) !test_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags)) return; - ieee80211_queue_delayed_work(rt2x00dev->hw, - &link->watchdog_work, WATCHDOG_INTERVAL); + schedule_delayed_work(&link->watchdog_work, WATCHDOG_INTERVAL); } void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev) @@ -442,8 +441,7 @@ static void rt2x00link_watchdog(struct work_struct *work) rt2x00dev->ops->lib->watchdog(rt2x00dev); if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) - ieee80211_queue_delayed_work(rt2x00dev->hw, - &link->watchdog_work, WATCHDOG_INTERVAL); + schedule_delayed_work(&link->watchdog_work, WATCHDOG_INTERVAL); } void rt2x00link_register(struct rt2x00_dev *rt2x00dev) -- cgit v0.10.2 From 3590eea41815679e268c90d30795a13a732b8413 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 11 Oct 2010 15:38:07 +0200 Subject: rt2x00: Validate MCS on RX path Similar to the PLCP signal and bitrates values, we should validate the MCS value from the RX descriptor before sending it to mac80211. Signed-off-by: Ivo van Doorn Acked-by: Helmut Schaa Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 9b745fa..db25209 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -432,36 +432,44 @@ static int rt2x00lib_rxdone_read_signal(struct rt2x00_dev *rt2x00dev, struct ieee80211_supported_band *sband; const struct rt2x00_rate *rate; unsigned int i; - int signal; - int type; + int signal = rxdesc->signal; + int type = (rxdesc->dev_flags & RXDONE_SIGNAL_MASK); - /* - * For non-HT rates the MCS value needs to contain the - * actually used rate modulation (CCK or OFDM). - */ - if (rxdesc->dev_flags & RXDONE_SIGNAL_MCS) - signal = RATE_MCS(rxdesc->rate_mode, rxdesc->signal); - else - signal = rxdesc->signal; - - type = (rxdesc->dev_flags & RXDONE_SIGNAL_MASK); - - sband = &rt2x00dev->bands[rt2x00dev->curr_band]; - for (i = 0; i < sband->n_bitrates; i++) { - rate = rt2x00_get_rate(sband->bitrates[i].hw_value); - - if (((type == RXDONE_SIGNAL_PLCP) && - (rate->plcp == signal)) || - ((type == RXDONE_SIGNAL_BITRATE) && - (rate->bitrate == signal)) || - ((type == RXDONE_SIGNAL_MCS) && - (rate->mcs == signal))) { - return i; + switch (rxdesc->rate_mode) { + case RATE_MODE_CCK: + case RATE_MODE_OFDM: + /* + * For non-HT rates the MCS value needs to contain the + * actually used rate modulation (CCK or OFDM). + */ + if (rxdesc->dev_flags & RXDONE_SIGNAL_MCS) + signal = RATE_MCS(rxdesc->rate_mode, signal); + + sband = &rt2x00dev->bands[rt2x00dev->curr_band]; + for (i = 0; i < sband->n_bitrates; i++) { + rate = rt2x00_get_rate(sband->bitrates[i].hw_value); + if (((type == RXDONE_SIGNAL_PLCP) && + (rate->plcp == signal)) || + ((type == RXDONE_SIGNAL_BITRATE) && + (rate->bitrate == signal)) || + ((type == RXDONE_SIGNAL_MCS) && + (rate->mcs == signal))) { + return i; + } } + break; + case RATE_MODE_HT_MIX: + case RATE_MODE_HT_GREENFIELD: + if (signal >= 0 && signal <= 76) + return signal; + break; + default: + break; } WARNING(rt2x00dev, "Frame received with unrecognized signal, " - "signal=0x%.4x, type=%d.\n", signal, type); + "mode=0x%.4x, signal=0x%.4x, type=%d.\n", + rxdesc->rate_mode, signal, type); return 0; } @@ -523,18 +531,12 @@ void rt2x00lib_rxdone(struct queue_entry *entry) skb_trim(entry->skb, rxdesc.size); /* - * Check if the frame was received using HT. In that case, - * the rate is the MCS index and should be passed to mac80211 - * directly. Otherwise we need to translate the signal to - * the correct bitrate index. + * Translate the signal to the correct bitrate index. */ - if (rxdesc.rate_mode == RATE_MODE_CCK || - rxdesc.rate_mode == RATE_MODE_OFDM) { - rate_idx = rt2x00lib_rxdone_read_signal(rt2x00dev, &rxdesc); - } else { + rate_idx = rt2x00lib_rxdone_read_signal(rt2x00dev, &rxdesc); + if (rxdesc.rate_mode == RATE_MODE_HT_MIX || + rxdesc.rate_mode == RATE_MODE_HT_GREENFIELD) rxdesc.flags |= RX_FLAG_HT; - rate_idx = rxdesc.signal; - } /* * Update extra components -- cgit v0.10.2 From 1550c8ef835af17df322045e92541561afa0f017 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 11 Oct 2010 15:38:26 +0200 Subject: rt2x00: Fix dead queue when skb allocation failed When the RX skb allocation failed, we should recycle the previously allocated skbuffer. By calling return we would kill the RX queue completely since the entry would be invalidated. Signed-off-by: Ivo van Doorn Acked-by: Helmut Schaa Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index db25209..e5e8ba3 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -491,7 +491,7 @@ void rt2x00lib_rxdone(struct queue_entry *entry) */ skb = rt2x00queue_alloc_rxskb(entry); if (!skb) - return; + goto submit_entry; /* * Unmap the skb. -- cgit v0.10.2 From a1d1eabc8c42ddf5fd3ea4184094561b3edd127b Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 11 Oct 2010 15:38:45 +0200 Subject: rt2x00: Make queue_entry flags access atomic All access to the queue_entry->flags can be done concurrently, so all flags must use the atomic operators. On most locations this was already done, so just fix the last few non-atomic versions. Signed-off-by: Ivo van Doorn Acked-by: Helmut Schaa Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 451d637..769c534 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -208,7 +208,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; - if (!__test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) + if (!test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) return; /* @@ -220,7 +220,7 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) * Check if the frame was correctly uploaded */ if (urb->status) - __set_bit(ENTRY_DATA_IO_FAILED, &entry->flags); + set_bit(ENTRY_DATA_IO_FAILED, &entry->flags); /* * Schedule the delayed work for reading the TX status @@ -407,7 +407,7 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) struct queue_entry *entry = (struct queue_entry *)urb->context; struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; - if (!__test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) + if (!test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) return; /* @@ -421,7 +421,7 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) * a problem. */ if (urb->actual_length < entry->queue->desc_size || urb->status) - __set_bit(ENTRY_DATA_IO_FAILED, &entry->flags); + set_bit(ENTRY_DATA_IO_FAILED, &entry->flags); /* * Schedule the delayed work for reading the RX status -- cgit v0.10.2 From 1a397696536e896e7d763c0c38f3ae3e588b5d52 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 11 Oct 2010 15:39:04 +0200 Subject: rt2x00: Don't perform watchdog checks on empty queue The currently used watchdog functions cannot be applied to empty queues. Signed-off-by: Ivo van Doorn Acked-by: Helmut Schaa Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 769c534..89d77f5 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -363,10 +363,12 @@ void rt2x00usb_watchdog(struct rt2x00_dev *rt2x00dev) struct data_queue *queue; tx_queue_for_each(rt2x00dev, queue) { - if (rt2x00queue_dma_timeout(queue)) - rt2x00usb_watchdog_tx_dma(queue); - if (rt2x00queue_timeout(queue)) - rt2x00usb_watchdog_tx_status(queue); + if (!rt2x00queue_empty(queue)) { + if (rt2x00queue_dma_timeout(queue)) + rt2x00usb_watchdog_tx_dma(queue); + if (rt2x00queue_timeout(queue)) + rt2x00usb_watchdog_tx_status(queue); + } } } EXPORT_SYMBOL_GPL(rt2x00usb_watchdog); -- cgit v0.10.2 From a13c8f3133b250e732c383b1c390d625e755db03 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 11 Oct 2010 15:39:48 +0200 Subject: rt2x00: Fix URB error handling kill_urb guarentees that when the function returns, the URB has been fully killed. This means we don't need the extra sleeping after the call to kill_urb. kill_urb can however also guarentee the submit_urb to fail, as a result, we must catch the return value from submit_urb an correctly mark the entry as owned by the driver, and the status as broken. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index e5e8ba3..5ba79b9 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -253,6 +253,7 @@ EXPORT_SYMBOL_GPL(rt2x00lib_pretbtt); void rt2x00lib_dmadone(struct queue_entry *entry) { + clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); rt2x00queue_index_inc(entry->queue, Q_INDEX_DMA_DONE); } EXPORT_SYMBOL_GPL(rt2x00lib_dmadone); diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 89d77f5..b3317df 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -253,7 +253,10 @@ static void rt2x00usb_kick_tx_entry(struct queue_entry *entry) entry->skb->data, length, rt2x00usb_interrupt_txdone, entry); - usb_submit_urb(entry_priv->urb, GFP_ATOMIC); + if (usb_submit_urb(entry_priv->urb, GFP_ATOMIC)) { + set_bit(ENTRY_DATA_IO_FAILED, &entry->flags); + rt2x00lib_dmadone(entry); + } } void rt2x00usb_kick_tx_queue(struct data_queue *queue) @@ -280,14 +283,6 @@ static void rt2x00usb_kill_tx_entry(struct queue_entry *entry) if ((entry->queue->qid == QID_BEACON) && (test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags))) usb_kill_urb(bcn_priv->guardian_urb); - - /* - * We need a short delay here to wait for - * the URB to be canceled - */ - do { - udelay(100); - } while (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)); } void rt2x00usb_kill_tx_queue(struct data_queue *queue) @@ -469,7 +464,10 @@ void rt2x00usb_clear_entry(struct queue_entry *entry) rt2x00usb_interrupt_rxdone, entry); set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); - usb_submit_urb(entry_priv->urb, GFP_ATOMIC); + if (usb_submit_urb(entry_priv->urb, GFP_ATOMIC)) { + set_bit(ENTRY_DATA_IO_FAILED, &entry->flags); + rt2x00lib_dmadone(entry); + } } } EXPORT_SYMBOL_GPL(rt2x00usb_clear_entry); -- cgit v0.10.2 From a5901cbb5783b25fa71536503bfa4617d8ee41bd Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Thu, 23 Sep 2010 09:56:51 -0700 Subject: iiwlagn: always download priority table For advance BT/WiFi co-exist, always download bt priority table before sending bt_config command Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index c4fe3f9..4470e8c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2835,8 +2835,7 @@ static void iwl_alive_start(struct iwl_priv *priv) priv->kill_cts_mask = IWLAGN_BT_KILL_CTS_MASK_DEFAULT; priv->cfg->ops->hcmd->send_bt_config(priv); priv->bt_valid = IWLAGN_BT_VALID_ENABLE_FLAGS; - if (bt_coex_active && priv->iw_mode != NL80211_IFTYPE_ADHOC) - iwlagn_send_prio_tbl(priv); + iwlagn_send_prio_tbl(priv); /* FIXME: w/a to force change uCode BT state machine */ iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN, -- cgit v0.10.2 From bc795df1d225415c2ec6ff2a81c07a753681d945 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Mon, 11 Oct 2010 14:24:05 -0700 Subject: iwlagn: prio_tbl need to download before calibration For WiFi/BT combo devices, priority table always need to download before perform any calibration operation. Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 4470e8c..6771c40 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2809,9 +2809,6 @@ static void iwl_alive_start(struct iwl_priv *priv) goto restart; } - if (priv->hw_params.calib_rt_cfg) - iwlagn_send_calib_cfg_rt(priv, priv->hw_params.calib_rt_cfg); - /* After the ALIVE response, we can send host commands to the uCode */ set_bit(STATUS_ALIVE, &priv->status); @@ -2827,6 +2824,7 @@ static void iwl_alive_start(struct iwl_priv *priv) if (iwl_is_rfkill(priv)) return; + /* download priority table before any calibration request */ if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist) { /* Configure Bluetooth device coexistence support */ @@ -2843,6 +2841,9 @@ static void iwl_alive_start(struct iwl_priv *priv) iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_CLOSE, BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); } + if (priv->hw_params.calib_rt_cfg) + iwlagn_send_calib_cfg_rt(priv, priv->hw_params.calib_rt_cfg); + ieee80211_wake_queues(priv->hw); priv->active_rate = IWL_RATES_MASK; -- cgit v0.10.2 From fd74d065f43f88eedc7492886d84f0accb683653 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 12 Oct 2010 02:26:13 -0700 Subject: iwl3945: fix queue allocation commit 6f98613258b966ffe0e6def18129b386514d10e0 Author: Jay Sternberg Date: Sat Sep 18 09:07:04 2010 -0700 iwlagn: reduce redundant parameter definitions broke 3945 because Jay accidentally removed the num_of_queues parameter for 3945, so that we now attempt to allocate a zero-sized queue array, which leads to SLUB returning ZERO_SIZE_PTR (0x10) which we then try to dereference thus crashing the system. Restore the necessary num_of_queues param. This fixes http://bugzilla.intellinuxwireless.org/show_bug.cgi?id=2254 Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 7d74ae5..176e525 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -2753,6 +2753,7 @@ static const struct iwl_ops iwl3945_ops = { static struct iwl_base_params iwl3945_base_params = { .eeprom_size = IWL3945_EEPROM_IMG_SIZE, + .num_of_queues = IWL39_NUM_QUEUES, .pll_cfg_val = CSR39_ANA_PLL_CFG_VAL, .set_l0s = false, .use_bsm = true, -- cgit v0.10.2 From cfd8e12f42746df396ecbdf7a1d8e92e8e4dbb97 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Mon, 11 Oct 2010 10:28:59 -0700 Subject: wireless: Print wiphy name in sysfs. The index cannot be used to reliably reconstruct a phy name, so explicitly add the phy name to sysfs so that scripts can figure out the parent phy device for a particular wireless interface. Signed-off-by: Ben Greear Signed-off-by: John W. Linville diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c index 74a9e3c..4294fa2 100644 --- a/net/wireless/sysfs.c +++ b/net/wireless/sysfs.c @@ -35,6 +35,14 @@ SHOW_FMT(index, "%d", wiphy_idx); SHOW_FMT(macaddress, "%pM", wiphy.perm_addr); SHOW_FMT(address_mask, "%pM", wiphy.addr_mask); +static ssize_t name_show(struct device *dev, + struct device_attribute *attr, + char *buf) { + struct wiphy *wiphy = &dev_to_rdev(dev)->wiphy; + return sprintf(buf, "%s\n", dev_name(&wiphy->dev)); +} + + static ssize_t addresses_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -57,6 +65,7 @@ static struct device_attribute ieee80211_dev_attrs[] = { __ATTR_RO(macaddress), __ATTR_RO(address_mask), __ATTR_RO(addresses), + __ATTR_RO(name), {} }; -- cgit v0.10.2 From 908ebfb95d16bdf7f5f37ad911ccd9b7350ba780 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 12 Oct 2010 11:07:44 -0700 Subject: ath5k: fix build break from "ath5k: Print out opmode in debugfs" Also improve ath_opmode_to_string usage by having it return UNKNOWN rather than NULL in the event of failure to map the opmode value to a representative string. Signed-off-by: Joe Perches Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index c9732a6..7baaf04 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -563,9 +563,7 @@ static void ath_do_set_opmode(struct ath5k_softc *sc) struct ath5k_hw *ah = sc->ah; ath5k_hw_set_opmode(ah, sc->opmode); ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "mode setup opmode %d (%s)\n", - sc->opmode, - ath_opmode_to_string(sc->opmode) ? - ath_opmode_to_string(sc->opmode) : "UKNOWN"); + sc->opmode, ath_opmode_to_string(sc->opmode)); } void ath5k_update_bssid_mask_and_opmode(struct ath5k_softc *sc, diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c index a3b2171..7c77e5b7 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c @@ -493,7 +493,6 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf, char buf[700]; unsigned int len = 0; u32 filt = ath5k_hw_get_rx_filter(sc->ah); - const char *tmp; len += snprintf(buf+len, sizeof(buf)-len, "bssid-mask: %pM\n", sc->bssidmask); @@ -522,17 +521,10 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf, if (filt & AR5K_RX_FILTER_PHYERR_5211) snprintf(buf+len, sizeof(buf)-len, " PHYERR-5211"); if (filt & AR5K_RX_FILTER_RADARERR_5211) - len += snprintf(buf+len, sizeof(buf)-len, " RADARERR-5211\n"); - else - len += snprintf(buf+len, sizeof(buf)-len, "\n"); - - tmp = ath_opmode_to_string(sc->opmode); - if (tmp) - len += snprintf(buf+len, sizeof(buf)-len, "opmode: %s\n", - tmp); - else - len += snprintf(buf+len, sizeof(buf)-len, - "opmode: UNKNOWN-%i\n", sc->opmode); + len += snprintf(buf+len, sizeof(buf)-len, " RADARERR-5211"); + + len += snprintf(buf+len, sizeof(buf)-len, "\nopmode: %s (%d)\n", + ath_opmode_to_string(sc->opmode), sc->opmode); if (len > sizeof(buf)) len = sizeof(buf); diff --git a/drivers/net/wireless/ath/debug.c b/drivers/net/wireless/ath/debug.c index a9eb787..dacfb23 100644 --- a/drivers/net/wireless/ath/debug.c +++ b/drivers/net/wireless/ath/debug.c @@ -55,7 +55,7 @@ const char *ath_opmode_to_string(enum nl80211_iftype opmode) case NL80211_IFTYPE_P2P_GO: return "P2P-GO"; default: - return NULL; + return "UNKNOWN"; } } EXPORT_SYMBOL(ath_opmode_to_string); diff --git a/drivers/net/wireless/ath/debug.h b/drivers/net/wireless/ath/debug.h index a3a5a62..64e4af2 100644 --- a/drivers/net/wireless/ath/debug.h +++ b/drivers/net/wireless/ath/debug.h @@ -78,6 +78,13 @@ ath_print(struct ath_common *common, int dbg_mask, const char *fmt, ...) #endif /* CONFIG_ATH_DEBUG */ /** Returns string describing opmode, or NULL if unknown mode. */ +#ifdef CONFIG_ATH_DEBUG const char *ath_opmode_to_string(enum nl80211_iftype opmode); +#else +static inline const char *ath_opmode_to_string(enum nl80211_iftype opmode) +{ + return "UNKNOWN"; +} +#endif #endif /* ATH_DEBUG_H */ -- cgit v0.10.2 From 10d8dad8453f8648a448960d7a2d3d983dfe0ed3 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Tue, 12 Oct 2010 07:07:42 +0200 Subject: wext: fix alignment problem in serializing 'struct iw_point' wext: fix alignment problem in serializing 'struct iw_point' This fixes a typo in the definition of the serialized length of struct iw_point: a) wireless.h is exported to userspace, the typo causes IW_EV_POINT_PK_LEN to be 12 on 64-bit, and 8 on 32-bit systems (causing misalignment); b) in compat-64 mode iwe_stream_add_point() memcpys overlap (see below). The second case in in compat-64 mode looks like (variable names are as in include/net/iw_handler.h:iwe_stream_add_point()): point_len = IW_EV_COMPAT_POINT_LEN = 8 lcp_len = IW_EV_COMPAT_LCP_LEN = 4 2nd memcpy: IW_EV_POINT_PK_LEN - IW_EV_LCP_PK_LEN = 12 - 4 = 8 IW_EV_LCP_PK_LEN <--------------> *---> 'extra' data area +-------+-------+-------+-------+---------------+------- ...-+ | len | cmd |length | flags | (empty) -> extra ... | +-------+-------+-------+-------+---------------+------- ...-+ 2 2 2 2 4 lcp_len <--------------> <-!! OVERLAP !!> <--1st memcpy--><------- 2nd memcpy -----------> <---- 3rd memcpy ------- ... > <--------- point_len ----------> This case could cause overrun whenever iw_point.length < 4. The other two cases are - * 32-bit systems: IW_EV_POINT_PK_LEN - IW_EV_LCP_PK_LEN = 8 - 4 = 4, the second memcpy copies exactly the 4 required bytes; * 64-bit systems: IW_EV_POINT_PK_LEN - IW_EV_LCP_PK_LEN = 12 - 4 = 8, the second memcpy copies a superfluous (but non overlapping) 4 bytes. The patch changes IW_EV_POINT_PK_LEN to be 8, so that in all 3 cases always only the requested iw_point.{length,flags} (both __u16) are copied, avoiding overrrun (compat-64) and superfluous copy (64-bit). In addition, the userspace header is sanitized (in agreement with version 30 of the wireless tools). Many thanks to Johannes Berg for help and review with this patch. Signed-off-by: Gerrit Renker Signed-off-by: John W. Linville diff --git a/include/linux/wireless.h b/include/linux/wireless.h index e6827ee..4395b28 100644 --- a/include/linux/wireless.h +++ b/include/linux/wireless.h @@ -1157,6 +1157,6 @@ struct __compat_iw_event { #define IW_EV_PARAM_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(struct iw_param)) #define IW_EV_ADDR_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(struct sockaddr)) #define IW_EV_QUAL_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(struct iw_quality)) -#define IW_EV_POINT_PK_LEN (IW_EV_LCP_LEN + 4) +#define IW_EV_POINT_PK_LEN (IW_EV_LCP_PK_LEN + 4) #endif /* _LINUX_WIRELESS_H */ -- cgit v0.10.2 From d84a35d1323bc62f9b26a707072767a60da75015 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Tue, 12 Oct 2010 10:55:38 -0700 Subject: ath5k: Move debugfs under ieee80211/[wiphy-name] This automatically keeps things proper when wiphy is renamed. Based on patch by Johannes Berg Signed-off-by: Ben Greear Acked-by: Bruno Randolf Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 7baaf04..f1ae75d 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -3541,8 +3541,6 @@ ath5k_pci_probe(struct pci_dev *pdev, sc->hw = hw; sc->pdev = pdev; - ath5k_debug_init_device(sc); - /* * Mark the device as detached to avoid processing * interrupts until setup is complete. @@ -3650,6 +3648,7 @@ ath5k_pci_probe(struct pci_dev *pdev, } } + ath5k_debug_init_device(sc); /* ready to process interrupts */ __clear_bit(ATH_STAT_INVALID, sc->status); @@ -3736,8 +3735,6 @@ init_ath5k_pci(void) { int ret; - ath5k_debug_init(); - ret = pci_register_driver(&ath5k_pci_driver); if (ret) { printk(KERN_ERR "ath5k_pci: can't register pci driver\n"); @@ -3751,8 +3748,6 @@ static void __exit exit_ath5k_pci(void) { pci_unregister_driver(&ath5k_pci_driver); - - ath5k_debug_finish(); } module_init(init_ath5k_pci); diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c index 7c77e5b7..42ea5b1 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c @@ -72,8 +72,6 @@ module_param_named(debug, ath5k_debug, uint, 0); #include "reg.h" #include "ani.h" -static struct dentry *ath5k_global_debugfs; - static int ath5k_debugfs_open(struct inode *inode, struct file *file) { file->private_data = inode->i_private; @@ -882,21 +880,13 @@ static const struct file_operations fops_queue = { }; -/* init */ - -void -ath5k_debug_init(void) -{ - ath5k_global_debugfs = debugfs_create_dir("ath5k", NULL); -} - void ath5k_debug_init_device(struct ath5k_softc *sc) { sc->debug.level = ath5k_debug; - sc->debug.debugfs_phydir = debugfs_create_dir(wiphy_name(sc->hw->wiphy), - ath5k_global_debugfs); + sc->debug.debugfs_phydir = debugfs_create_dir("ath5k", + sc->hw->wiphy->debugfsdir); sc->debug.debugfs_debug = debugfs_create_file("debug", S_IWUSR | S_IRUSR, @@ -937,12 +927,6 @@ ath5k_debug_init_device(struct ath5k_softc *sc) } void -ath5k_debug_finish(void) -{ - debugfs_remove(ath5k_global_debugfs); -} - -void ath5k_debug_finish_device(struct ath5k_softc *sc) { debugfs_remove(sc->debug.debugfs_debug); diff --git a/drivers/net/wireless/ath/ath5k/debug.h b/drivers/net/wireless/ath/ath5k/debug.h index 4f078b1..236edbd 100644 --- a/drivers/net/wireless/ath/ath5k/debug.h +++ b/drivers/net/wireless/ath/ath5k/debug.h @@ -138,15 +138,9 @@ enum ath5k_debug_level { } while (0) void -ath5k_debug_init(void); - -void ath5k_debug_init_device(struct ath5k_softc *sc); void -ath5k_debug_finish(void); - -void ath5k_debug_finish_device(struct ath5k_softc *sc); void @@ -174,15 +168,9 @@ ATH5K_DBG_UNLIMIT(struct ath5k_softc *sc, unsigned int m, const char *fmt, ...) {} static inline void -ath5k_debug_init(void) {} - -static inline void ath5k_debug_init_device(struct ath5k_softc *sc) {} static inline void -ath5k_debug_finish(void) {} - -static inline void ath5k_debug_finish_device(struct ath5k_softc *sc) {} static inline void -- cgit v0.10.2 From 7a8266524af7ec70d1b3d10f964ce911d922d466 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Wed, 13 Oct 2010 11:47:09 +0530 Subject: ath9k: Fix documentation in rate control This fix updates the documenation in Rate Control Table structure Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 13f9e88..abebf24 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -302,7 +302,7 @@ static const struct ath_rate_table ar5416_11ng_ratetable = { [64] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 243000, 205100, 20, 20, 8, 64, 65, 65 }, /* 243 Mb */ [65] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS_HGI, 270000, - 224700, 20, 20, 8, 64, 65, 65 }, /* 170 Mb */ + 224700, 20, 20, 8, 64, 65, 65 }, /* 270 Mb */ [66] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 324000, 263100, 21, 21, 8, 66, 67, 67 }, /* 324 Mb */ [67] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 360000, diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h index 268072f..fbb1d33 100644 --- a/drivers/net/wireless/ath/ath9k/rc.h +++ b/drivers/net/wireless/ath/ath9k/rc.h @@ -135,20 +135,21 @@ enum { /** * struct ath_rate_table - Rate Control table - * @valid: valid for use in rate control - * @valid_single_stream: valid for use in rate control for - * single stream operation - * @phy: CCK/OFDM + * @rate_cnt: total number of rates for the given wireless mode + * @mcs_start: MCS rate index offset + * @rate_flags: Rate Control flags + * @phy: CCK/OFDM/HT20/HT40 * @ratekbps: rate in Kbits per second * @user_ratekbps: user rate in Kbits per second * @ratecode: rate that goes into HW descriptors - * @short_preamble: Mask for enabling short preamble in ratecode for CCK * @dot11rate: value that goes into supported * rates info element of MLME * @ctrl_rate: Index of next lower basic rate, used for duration computation - * @max_4ms_framelen: maximum frame length(bytes) for tx duration + * @cw40index: Index of rates having 40MHz channel width + * @sgi_index: Index of rates having Short Guard Interval + * @ht_index: high throughput rates having 40MHz channel width and + * Short Guard Interval * @probe_interval: interval for rate control to probe for other rates - * @rssi_reduce_interval: interval for rate control to reduce rssi * @initial_ratemax: initial ratemax value */ struct ath_rate_table { -- cgit v0.10.2 From 271733cf844a2f5f186ef3b40c26d6397b71039a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 13 Oct 2010 12:06:23 +0200 Subject: cfg80211: notify drivers about frame registrations Drivers may need to adjust their filters according to frame registrations, so notify them about them. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 24d5b58..2a7936d 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1147,6 +1147,9 @@ struct cfg80211_pmksa { * allows the driver to adjust the dynamic ps timeout value. * @set_cqm_rssi_config: Configure connection quality monitor RSSI threshold. * + * @mgmt_frame_register: Notify driver that a management frame type was + * registered. Note that this callback may not sleep, and cannot run + * concurrently with itself. */ struct cfg80211_ops { int (*suspend)(struct wiphy *wiphy); @@ -1297,6 +1300,10 @@ struct cfg80211_ops { int (*set_cqm_rssi_config)(struct wiphy *wiphy, struct net_device *dev, s32 rssi_thold, u32 rssi_hyst); + + void (*mgmt_frame_register)(struct wiphy *wiphy, + struct net_device *dev, + u16 frame_type, bool reg); }; /* diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index caf11a427..26838d9 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -764,6 +764,8 @@ int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid, u16 frame_type, const u8 *match_data, int match_len) { + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); struct cfg80211_mgmt_registration *reg, *nreg; int err = 0; u16 mgmt_type; @@ -810,22 +812,37 @@ int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid, nreg->frame_type = cpu_to_le16(frame_type); list_add(&nreg->list, &wdev->mgmt_registrations); + if (rdev->ops->mgmt_frame_register) + rdev->ops->mgmt_frame_register(wiphy, wdev->netdev, + frame_type, true); + out: spin_unlock_bh(&wdev->mgmt_registrations_lock); + return err; } void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid) { + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); struct cfg80211_mgmt_registration *reg, *tmp; spin_lock_bh(&wdev->mgmt_registrations_lock); list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) { - if (reg->nlpid == nlpid) { - list_del(®->list); - kfree(reg); + if (reg->nlpid != nlpid) + continue; + + if (rdev->ops->mgmt_frame_register) { + u16 frame_type = le16_to_cpu(reg->frame_type); + + rdev->ops->mgmt_frame_register(wiphy, wdev->netdev, + frame_type, false); } + + list_del(®->list); + kfree(reg); } spin_unlock_bh(&wdev->mgmt_registrations_lock); -- cgit v0.10.2 From 7be5086d4cb7cceb71d724a9524d5e927785d04f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 13 Oct 2010 12:06:24 +0200 Subject: mac80211: add probe request filter flag Using the frame registration notification, we can see when probe requests are requested and notify the low-level driver via filtering. The flag is also set in AP and IBSS modes. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 33aa2e3..9fdf982 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1478,12 +1478,14 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw, * honour this flag if possible. * * @FIF_CONTROL: pass control frames (except for PS Poll), if PROMISC_IN_BSS - * is not set then only those addressed to this station. + * is not set then only those addressed to this station. * * @FIF_OTHER_BSS: pass frames destined to other BSSes * - * @FIF_PSPOLL: pass PS Poll frames, if PROMISC_IN_BSS is not set then only - * those addressed to this station. + * @FIF_PSPOLL: pass PS Poll frames, if PROMISC_IN_BSS is not set then only + * those addressed to this station. + * + * @FIF_PROBE_REQ: pass probe request frames */ enum ieee80211_filter_flags { FIF_PROMISC_IN_BSS = 1<<0, @@ -1494,6 +1496,7 @@ enum ieee80211_filter_flags { FIF_CONTROL = 1<<5, FIF_OTHER_BSS = 1<<6, FIF_PSPOLL = 1<<7, + FIF_PROBE_REQ = 1<<8, }; /** diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 25fb351..18bd0e5 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1604,6 +1604,23 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, return 0; } +static void ieee80211_mgmt_frame_register(struct wiphy *wiphy, + struct net_device *dev, + u16 frame_type, bool reg) +{ + struct ieee80211_local *local = wiphy_priv(wiphy); + + if (frame_type != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ)) + return; + + if (reg) + local->probe_req_reg++; + else + local->probe_req_reg--; + + ieee80211_queue_work(&local->hw, &local->reconfig_filter); +} + struct cfg80211_ops mac80211_config_ops = { .add_virtual_intf = ieee80211_add_iface, .del_virtual_intf = ieee80211_del_iface, @@ -1655,4 +1672,5 @@ struct cfg80211_ops mac80211_config_ops = { .cancel_remain_on_channel = ieee80211_cancel_remain_on_channel, .mgmt_tx = ieee80211_mgmt_tx, .set_cqm_rssi_config = ieee80211_set_cqm_rssi_config, + .mgmt_frame_register = ieee80211_mgmt_frame_register, }; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index f0610fa..b80c386 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -707,7 +707,9 @@ struct ieee80211_local { int open_count; int monitors, cooked_mntrs; /* number of interfaces with corresponding FIF_ flags */ - int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss, fif_pspoll; + int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss, fif_pspoll, + fif_probe_req; + int probe_req_reg; unsigned int filter_flags; /* FIF_* */ bool wiphy_ciphers_allocated; diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index e99d1b6..f9163b1 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -280,8 +280,11 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) ieee80211_start_mesh(sdata); } else if (sdata->vif.type == NL80211_IFTYPE_AP) { local->fif_pspoll++; + local->fif_probe_req++; ieee80211_configure_filter(local); + } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { + local->fif_probe_req++; } changed |= ieee80211_reset_erp_info(sdata); @@ -428,8 +431,12 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, if (sdata->flags & IEEE80211_SDATA_PROMISC) atomic_dec(&local->iff_promiscs); - if (sdata->vif.type == NL80211_IFTYPE_AP) + if (sdata->vif.type == NL80211_IFTYPE_AP) { local->fif_pspoll--; + local->fif_probe_req--; + } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { + local->fif_probe_req--; + } netif_addr_lock_bh(sdata->dev); spin_lock_bh(&local->filter_lock); diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 915ecf8..5162303 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -54,6 +54,9 @@ void ieee80211_configure_filter(struct ieee80211_local *local) if (local->monitors || local->scanning) new_flags |= FIF_BCN_PRBRESP_PROMISC; + if (local->fif_probe_req || local->probe_req_reg) + new_flags |= FIF_PROBE_REQ; + if (local->fif_fcsfail) new_flags |= FIF_FCSFAIL; -- cgit v0.10.2 From 9c1d8e4affe6748d884a677cf5db19ae0c20ef07 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Wed, 13 Oct 2010 17:29:31 +0300 Subject: ath9k: Set RX filter for Probe Request based on filter flag This allows mac80211 to enable receiving of Probe Request frames in station mode which is needed for P2P. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 8656491..bcd3892 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1739,6 +1739,7 @@ skip_chan_change: FIF_PSPOLL | \ FIF_OTHER_BSS | \ FIF_BCN_PRBRESP_PROMISC | \ + FIF_PROBE_REQ | \ FIF_FCSFAIL) /* FIXME: sc->sc_full_reset ? */ diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 9c166f3..7c90eaf 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -430,8 +430,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc) | ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST | ATH9K_RX_FILTER_MCAST; - /* If not a STA, enable processing of Probe Requests */ - if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION) + if (sc->rx.rxfilter & FIF_PROBE_REQ) rfilt |= ATH9K_RX_FILTER_PROBEREQ; /* -- cgit v0.10.2 From e4b55957eb695b43055b6badec026628b24fe80a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 13 Oct 2010 19:23:21 +0200 Subject: mac80211: fix SMPS request It looks like I submitted a different patch than I tested, because clearly the code in mac80211 is missing actually propagating the requested SMPS mode. Fix that! Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 4214bb6..75d679d 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -291,6 +291,8 @@ void ieee80211_request_smps(struct ieee80211_vif *vif, if (WARN_ON(smps_mode == IEEE80211_SMPS_OFF)) smps_mode = IEEE80211_SMPS_AUTOMATIC; + sdata->u.mgd.driver_smps_mode = smps_mode; + ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.request_smps_work); } -- cgit v0.10.2 From c23cc81a5e5c1d4486b662cedd0afcdf9145f154 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Wed, 13 Oct 2010 12:01:23 -0700 Subject: ath9k: Fix potential use-after-free. The ath_debug_stat_tx references bf->bf_mpdu, which is the skb consumed by ath_tx_complete. So, call the ath_debug_stat_tx method first. Signed-off-by: Ben Greear Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 9a11099..9b17108 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1924,8 +1924,8 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, else complete(&sc->paprd_complete); } else { - ath_tx_complete(sc, skb, bf->aphy, tx_flags); ath_debug_stat_tx(sc, txq, bf, ts); + ath_tx_complete(sc, skb, bf->aphy, tx_flags); } /* -- cgit v0.10.2 From de05ead8f8649788603afc470eb1c2ea2b8b1655 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Thu, 23 Sep 2010 15:24:22 -0700 Subject: iwlgn: need longer tx queue stuck timer for coex devices For BT/WiFi combo devices, need longer tx stuck queue timer, so those devices won't reload firmware too often. Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 4810258a..3eaea6f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -509,6 +509,28 @@ static struct iwl_base_params iwl6050_base_params = { .sensitivity_calib_by_driver = true, .chain_noise_calib_by_driver = true, }; +static struct iwl_base_params iwl6000_coex_base_params = { + .eeprom_size = OTP_LOW_IMAGE_SIZE, + .num_of_queues = IWLAGN_NUM_QUEUES, + .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, + .pll_cfg_val = 0, + .set_l0s = true, + .use_bsm = false, + .max_ll_items = OTP_MAX_LL_ITEMS_6x00, + .shadow_ram_support = true, + .led_compensation = 51, + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .supports_idle = true, + .adv_thermal_throttle = true, + .support_ct_kill_exit = true, + .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, + .chain_noise_scale = 1000, + .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, + .max_event_log_size = 512, + .ucode_tracing = true, + .sensitivity_calib_by_driver = true, + .chain_noise_calib_by_driver = true, +}; static struct iwl_ht_params iwl6000_ht_params = { .ht_greenfield_support = true, @@ -587,7 +609,7 @@ struct iwl_cfg iwl6000g2b_2agn_cfg = { .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION, .ops = &iwl6000g2b_ops, .mod_params = &iwlagn_mod_params, - .base_params = &iwl6000_base_params, + .base_params = &iwl6000_coex_base_params, .bt_params = &iwl6000_bt_params, .ht_params = &iwl6000_ht_params, .need_dc_calib = true, @@ -608,7 +630,7 @@ struct iwl_cfg iwl6000g2b_2abg_cfg = { .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION, .ops = &iwl6000g2b_ops, .mod_params = &iwlagn_mod_params, - .base_params = &iwl6000_base_params, + .base_params = &iwl6000_coex_base_params, .bt_params = &iwl6000_bt_params, .need_dc_calib = true, .need_temp_offset_calib = true, @@ -628,7 +650,7 @@ struct iwl_cfg iwl6000g2b_2bgn_cfg = { .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION, .ops = &iwl6000g2b_ops, .mod_params = &iwlagn_mod_params, - .base_params = &iwl6000_base_params, + .base_params = &iwl6000_coex_base_params, .bt_params = &iwl6000_bt_params, .ht_params = &iwl6000_ht_params, .need_dc_calib = true, @@ -649,7 +671,7 @@ struct iwl_cfg iwl6000g2b_2bg_cfg = { .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION, .ops = &iwl6000g2b_ops, .mod_params = &iwlagn_mod_params, - .base_params = &iwl6000_base_params, + .base_params = &iwl6000_coex_base_params, .bt_params = &iwl6000_bt_params, .need_dc_calib = true, .need_temp_offset_calib = true, @@ -669,7 +691,7 @@ struct iwl_cfg iwl6000g2b_bgn_cfg = { .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION, .ops = &iwl6000g2b_ops, .mod_params = &iwlagn_mod_params, - .base_params = &iwl6000_base_params, + .base_params = &iwl6000_coex_base_params, .bt_params = &iwl6000_bt_params, .ht_params = &iwl6000_ht_params, .need_dc_calib = true, @@ -690,7 +712,7 @@ struct iwl_cfg iwl6000g2b_bg_cfg = { .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION, .ops = &iwl6000g2b_ops, .mod_params = &iwlagn_mod_params, - .base_params = &iwl6000_base_params, + .base_params = &iwl6000_coex_base_params, .bt_params = &iwl6000_bt_params, .need_dc_calib = true, .need_temp_offset_calib = true, @@ -829,7 +851,7 @@ struct iwl_cfg iwl130_bgn_cfg = { .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION, .ops = &iwl6000g2b_ops, .mod_params = &iwlagn_mod_params, - .base_params = &iwl6000_base_params, + .base_params = &iwl6000_coex_base_params, .bt_params = &iwl6000_bt_params, .ht_params = &iwl6000_ht_params, .need_dc_calib = true, @@ -849,7 +871,7 @@ struct iwl_cfg iwl130_bg_cfg = { .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION, .ops = &iwl6000g2b_ops, .mod_params = &iwlagn_mod_params, - .base_params = &iwl6000_base_params, + .base_params = &iwl6000_coex_base_params, .bt_params = &iwl6000_bt_params, .need_dc_calib = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index b3efbe0..89b1827 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2483,13 +2483,10 @@ static int iwl_check_stuck_queue(struct iwl_priv *priv, int cnt) "queue %d, not read %d time\n", q->id, q->repeat_same_read_ptr); - if (priv->cfg->bt_params && - !priv->cfg->bt_params->advanced_bt_coexist) { - mod_timer(&priv->monitor_recover, - jiffies + msecs_to_jiffies( - IWL_ONE_HUNDRED_MSECS)); - return 1; - } + mod_timer(&priv->monitor_recover, + jiffies + msecs_to_jiffies( + IWL_ONE_HUNDRED_MSECS)); + return 1; } } else { q->last_read_ptr = q->read_ptr; -- cgit v0.10.2 From 085fbca29d7b4574c4e42189ee5789004e4beff7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 4 Oct 2010 05:47:23 -0700 Subject: iwlwifi: allow probe-after-rx on 2.4 GHz There are two passive 2.4 GHz channels: 12 and 13. If you have a hidden SSID on those, you will not be able to connect to it because we don't send out probe requests there. We can allow this by using the firmware's probe-after-rx functionality on those channels as well. This fixes https://bugzilla.kernel.org/show_bug.cgi?id=16462 Reported-by: Daniel J Blueman Tested-by: Daniel J Blueman Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index c1a3898..b555edd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -1447,35 +1447,35 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist) scan->tx_cmd.tx_flags |= TX_CMD_FLG_IGNORE_BT; - scan->good_CRC_th = IWL_GOOD_CRC_TH_DISABLED; break; case IEEE80211_BAND_5GHZ: rate = IWL_RATE_6M_PLCP; - /* - * If active scanning is requested but a certain channel is - * marked passive, we can do active scanning if we detect - * transmissions. - * - * There is an issue with some firmware versions that triggers - * a sysassert on a "good CRC threshold" of zero (== disabled), - * on a radar channel even though this means that we should NOT - * send probes. - * - * The "good CRC threshold" is the number of frames that we - * need to receive during our dwell time on a channel before - * sending out probes -- setting this to a huge value will - * mean we never reach it, but at the same time work around - * the aforementioned issue. Thus use IWL_GOOD_CRC_TH_NEVER - * here instead of IWL_GOOD_CRC_TH_DISABLED. - */ - scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT : - IWL_GOOD_CRC_TH_NEVER; break; default: IWL_WARN(priv, "Invalid scan band\n"); return -EIO; } + /* + * If active scanning is requested but a certain channel is + * marked passive, we can do active scanning if we detect + * transmissions. + * + * There is an issue with some firmware versions that triggers + * a sysassert on a "good CRC threshold" of zero (== disabled), + * on a radar channel even though this means that we should NOT + * send probes. + * + * The "good CRC threshold" is the number of frames that we + * need to receive during our dwell time on a channel before + * sending out probes -- setting this to a huge value will + * mean we never reach it, but at the same time work around + * the aforementioned issue. Thus use IWL_GOOD_CRC_TH_NEVER + * here instead of IWL_GOOD_CRC_TH_DISABLED. + */ + scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT : + IWL_GOOD_CRC_TH_NEVER; + band = priv->scan_band; if (priv->cfg->scan_rx_antennas[band]) diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 980c609..3ee3e55 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2938,18 +2938,10 @@ int iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) case IEEE80211_BAND_2GHZ: scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK; scan->tx_cmd.rate = IWL_RATE_1M_PLCP; - scan->good_CRC_th = 0; band = IEEE80211_BAND_2GHZ; break; case IEEE80211_BAND_5GHZ: scan->tx_cmd.rate = IWL_RATE_6M_PLCP; - /* - * If active scaning is requested but a certain channel - * is marked passive, we can do active scanning if we - * detect transmissions. - */ - scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT : - IWL_GOOD_CRC_TH_DISABLED; band = IEEE80211_BAND_5GHZ; break; default: @@ -2957,6 +2949,14 @@ int iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) return -EIO; } + /* + * If active scaning is requested but a certain channel + * is marked passive, we can do active scanning if we + * detect transmissions. + */ + scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT : + IWL_GOOD_CRC_TH_DISABLED; + if (!priv->is_internal_short_scan) { scan->tx_cmd.len = cpu_to_le16( iwl_fill_probe_req(priv, -- cgit v0.10.2 From 12e934dc602fafba946b33587c38077ebceb3698 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 4 Oct 2010 05:50:06 -0700 Subject: iwlwifi: rename ibss_beacon variable Since we're also going to support AP (GO) mode, the variable isn't used for just IBSS beacons any more -- rename it to not mislead readers. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 6771c40..0cc090b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -317,15 +317,15 @@ static u32 iwl_fill_beacon_frame(struct iwl_priv *priv, struct ieee80211_hdr *hdr, int left) { - if (!priv->ibss_beacon) + if (!priv->beacon_skb) return 0; - if (priv->ibss_beacon->len > left) + if (priv->beacon_skb->len > left) return 0; - memcpy(hdr, priv->ibss_beacon->data, priv->ibss_beacon->len); + memcpy(hdr, priv->beacon_skb->data, priv->beacon_skb->len); - return priv->ibss_beacon->len; + return priv->beacon_skb->len; } /* Parse the beacon frame to find the TIM element and set tim_idx & tim_size */ @@ -653,10 +653,10 @@ static void iwl_bg_beacon_update(struct work_struct *work) } /* new beacon skb is allocated every time; dispose previous.*/ - if (priv->ibss_beacon) - dev_kfree_skb(priv->ibss_beacon); + if (priv->beacon_skb) + dev_kfree_skb(priv->beacon_skb); - priv->ibss_beacon = beacon; + priv->beacon_skb = beacon; iwl_send_beacon_cmd(priv); out: @@ -2993,9 +2993,9 @@ static void __iwl_down(struct iwl_priv *priv) exit: memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp)); - if (priv->ibss_beacon) - dev_kfree_skb(priv->ibss_beacon); - priv->ibss_beacon = NULL; + if (priv->beacon_skb) + dev_kfree_skb(priv->beacon_skb); + priv->beacon_skb = NULL; /* clear out any free frames */ iwl_clear_free_frames(priv); @@ -4131,7 +4131,7 @@ static int iwl_init_drv(struct iwl_priv *priv) { int ret; - priv->ibss_beacon = NULL; + priv->beacon_skb = NULL; spin_lock_init(&priv->sta_lock); spin_lock_init(&priv->hcmd_lock); @@ -4645,8 +4645,8 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) iwl_free_isr_ict(priv); - if (priv->ibss_beacon) - dev_kfree_skb(priv->ibss_beacon); + if (priv->beacon_skb) + dev_kfree_skb(priv->beacon_skb); ieee80211_free_hw(priv->hw); } diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 89b1827..09a4d17 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1552,10 +1552,10 @@ static void iwlcore_beacon_update(struct ieee80211_hw *hw, spin_lock_irqsave(&priv->lock, flags); - if (priv->ibss_beacon) - dev_kfree_skb(priv->ibss_beacon); + if (priv->beacon_skb) + dev_kfree_skb(priv->beacon_skb); - priv->ibss_beacon = skb; + priv->beacon_skb = skb; timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; priv->timestamp = le64_to_cpu(timestamp); @@ -1610,8 +1610,8 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw, } if (changes & BSS_CHANGED_BEACON && vif->type == NL80211_IFTYPE_AP) { - dev_kfree_skb(priv->ibss_beacon); - priv->ibss_beacon = ieee80211_beacon_get(hw, vif); + dev_kfree_skb(priv->beacon_skb); + priv->beacon_skb = ieee80211_beacon_get(hw, vif); } if (changes & BSS_CHANGED_BEACON_INT && vif->type == NL80211_IFTYPE_AP) @@ -2060,10 +2060,10 @@ void iwl_mac_reset_tsf(struct ieee80211_hw *hw) spin_lock_irqsave(&priv->lock, flags); /* new association get rid of ibss beacon skb */ - if (priv->ibss_beacon) - dev_kfree_skb(priv->ibss_beacon); + if (priv->beacon_skb) + dev_kfree_skb(priv->beacon_skb); - priv->ibss_beacon = NULL; + priv->beacon_skb = NULL; priv->timestamp = 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index de43e13..70e07fa 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1383,8 +1383,6 @@ struct iwl_priv { enum nl80211_iftype iw_mode; - struct sk_buff *ibss_beacon; - /* Last Rx'd beacon timestamp */ u64 timestamp; @@ -1496,8 +1494,10 @@ struct iwl_priv { struct work_struct scan_completed; struct work_struct rx_replenish; struct work_struct abort_scan; + struct work_struct beacon_update; struct iwl_rxon_context *beacon_ctx; + struct sk_buff *beacon_skb; struct work_struct tt_work; struct work_struct ct_enter; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 3ee3e55..8f8c4b7 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -317,15 +317,15 @@ unsigned int iwl3945_fill_beacon_frame(struct iwl_priv *priv, int left) { - if (!iwl_is_associated(priv, IWL_RXON_CTX_BSS) || !priv->ibss_beacon) + if (!iwl_is_associated(priv, IWL_RXON_CTX_BSS) || !priv->beacon_skb) return 0; - if (priv->ibss_beacon->len > left) + if (priv->beacon_skb->len > left) return 0; - memcpy(hdr, priv->ibss_beacon->data, priv->ibss_beacon->len); + memcpy(hdr, priv->beacon_skb->data, priv->beacon_skb->len); - return priv->ibss_beacon->len; + return priv->beacon_skb->len; } static int iwl3945_send_beacon_cmd(struct iwl_priv *priv) @@ -813,10 +813,10 @@ static void iwl3945_bg_beacon_update(struct work_struct *work) mutex_lock(&priv->mutex); /* new beacon skb is allocated every time; dispose previous.*/ - if (priv->ibss_beacon) - dev_kfree_skb(priv->ibss_beacon); + if (priv->beacon_skb) + dev_kfree_skb(priv->beacon_skb); - priv->ibss_beacon = beacon; + priv->beacon_skb = beacon; mutex_unlock(&priv->mutex); iwl3945_send_beacon_cmd(priv); @@ -2642,9 +2642,9 @@ static void __iwl3945_down(struct iwl_priv *priv) exit: memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp)); - if (priv->ibss_beacon) - dev_kfree_skb(priv->ibss_beacon); - priv->ibss_beacon = NULL; + if (priv->beacon_skb) + dev_kfree_skb(priv->beacon_skb); + priv->beacon_skb = NULL; /* clear out any free frames */ iwl3945_clear_free_frames(priv); @@ -3848,7 +3848,7 @@ static int iwl3945_init_drv(struct iwl_priv *priv) struct iwl3945_eeprom *eeprom = (struct iwl3945_eeprom *)priv->eeprom; priv->retry_rate = 1; - priv->ibss_beacon = NULL; + priv->beacon_skb = NULL; spin_lock_init(&priv->sta_lock); spin_lock_init(&priv->hcmd_lock); @@ -4256,8 +4256,8 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) iwl_free_channel_map(priv); iwlcore_free_geos(priv); kfree(priv->scan_cmd); - if (priv->ibss_beacon) - dev_kfree_skb(priv->ibss_beacon); + if (priv->beacon_skb) + dev_kfree_skb(priv->beacon_skb); ieee80211_free_hw(priv->hw); } -- cgit v0.10.2 From 77834543a5278b55df6c2784cd5ed59970be3c44 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 4 Oct 2010 05:50:36 -0700 Subject: iwlwifi: clean up some beacon handling There's no need to check for NULL before calling dev_kfree_skb() since it is valid to call it on NULL -- it becomes a no-op. There's also no need to initialise the beacon_skb variable to NULL just after the memory it is in has been kzalloc'ed. Some minor whitespace cleanups, and a lock assertion in a function that needs the mutex (to access the beacon_skb var) complete the patch. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 0cc090b..7079efb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -314,9 +314,11 @@ static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame) } static u32 iwl_fill_beacon_frame(struct iwl_priv *priv, - struct ieee80211_hdr *hdr, - int left) + struct ieee80211_hdr *hdr, + int left) { + lockdep_assert_held(&priv->mutex); + if (!priv->beacon_skb) return 0; @@ -330,8 +332,8 @@ static u32 iwl_fill_beacon_frame(struct iwl_priv *priv, /* Parse the beacon frame to find the TIM element and set tim_idx & tim_size */ static void iwl_set_beacon_tim(struct iwl_priv *priv, - struct iwl_tx_beacon_cmd *tx_beacon_cmd, - u8 *beacon, u32 frame_size) + struct iwl_tx_beacon_cmd *tx_beacon_cmd, + u8 *beacon, u32 frame_size) { u16 tim_idx; struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)beacon; @@ -393,7 +395,7 @@ static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv, /* Set up TX beacon command fields */ iwl_set_beacon_tim(priv, tx_beacon_cmd, (u8 *)tx_beacon_cmd->frame, - frame_size); + frame_size); /* Set up packet rate and flags */ rate = iwl_rate_get_lowest_plcp(priv, priv->beacon_ctx); @@ -648,13 +650,12 @@ static void iwl_bg_beacon_update(struct work_struct *work) /* Pull updated AP beacon from mac80211. will fail if not in AP mode */ beacon = ieee80211_beacon_get(priv->hw, priv->beacon_ctx->vif); if (!beacon) { - IWL_ERR(priv, "update beacon failed\n"); + IWL_ERR(priv, "update beacon failed -- keeping old\n"); goto out; } /* new beacon skb is allocated every time; dispose previous.*/ - if (priv->beacon_skb) - dev_kfree_skb(priv->beacon_skb); + dev_kfree_skb(priv->beacon_skb); priv->beacon_skb = beacon; @@ -2993,8 +2994,7 @@ static void __iwl_down(struct iwl_priv *priv) exit: memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp)); - if (priv->beacon_skb) - dev_kfree_skb(priv->beacon_skb); + dev_kfree_skb(priv->beacon_skb); priv->beacon_skb = NULL; /* clear out any free frames */ @@ -4131,8 +4131,6 @@ static int iwl_init_drv(struct iwl_priv *priv) { int ret; - priv->beacon_skb = NULL; - spin_lock_init(&priv->sta_lock); spin_lock_init(&priv->hcmd_lock); @@ -4645,8 +4643,7 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) iwl_free_isr_ict(priv); - if (priv->beacon_skb) - dev_kfree_skb(priv->beacon_skb); + dev_kfree_skb(priv->beacon_skb); ieee80211_free_hw(priv->hw); } -- cgit v0.10.2 From 34f5a70c08530bb0b4724991a712a0ef6bbec39a Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Wed, 6 Oct 2010 13:46:11 -0700 Subject: iwlagn: 6050 ops should be used; For 6050 series of devices, 6050 ops should be used; One of the 6050 config still use 6000 ops, fix it. Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 3eaea6f..11e6532 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -780,7 +780,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, - .ops = &iwl6000_ops, + .ops = &iwl6050_ops, .eeprom_ver = EEPROM_6050_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION, .mod_params = &iwlagn_mod_params, -- cgit v0.10.2 From dacefedb34e538e9934556ffe5eaad177e7a9718 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 7 Oct 2010 04:02:03 -0700 Subject: iwlwifi: rewrite RXON checks The RXON checking is a bit magical, and prints out too much information if something goes wrong. Make it less magical and print out only the items that were actually wrong. Also remove the comment about removing it -- the driver is constantly changing so these checks are useful. Signed-off-by: Johannes Berg diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 09a4d17..ecf5c9b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -510,76 +510,74 @@ void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, struct iwl_rxon_context *ctx, } EXPORT_SYMBOL(iwl_set_rxon_hwcrypto); -/** - * iwl_check_rxon_cmd - validate RXON structure is valid - * - * NOTE: This is really only useful during development and can eventually - * be #ifdef'd out once the driver is stable and folks aren't actively - * making changes - */ +/* validate RXON structure is valid */ int iwl_check_rxon_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx) { - int error = 0; - int counter = 1; struct iwl_rxon_cmd *rxon = &ctx->staging; + bool error = false; if (rxon->flags & RXON_FLG_BAND_24G_MSK) { - error |= le32_to_cpu(rxon->flags & - (RXON_FLG_TGJ_NARROW_BAND_MSK | - RXON_FLG_RADAR_DETECT_MSK)); - if (error) - IWL_WARN(priv, "check 24G fields %d | %d\n", - counter++, error); + if (rxon->flags & RXON_FLG_TGJ_NARROW_BAND_MSK) { + IWL_WARN(priv, "check 2.4G: wrong narrow\n"); + error = true; + } + if (rxon->flags & RXON_FLG_RADAR_DETECT_MSK) { + IWL_WARN(priv, "check 2.4G: wrong radar\n"); + error = true; + } } else { - error |= (rxon->flags & RXON_FLG_SHORT_SLOT_MSK) ? - 0 : le32_to_cpu(RXON_FLG_SHORT_SLOT_MSK); - if (error) - IWL_WARN(priv, "check 52 fields %d | %d\n", - counter++, error); - error |= le32_to_cpu(rxon->flags & RXON_FLG_CCK_MSK); - if (error) - IWL_WARN(priv, "check 52 CCK %d | %d\n", - counter++, error); - } - error |= (rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1; - if (error) - IWL_WARN(priv, "check mac addr %d | %d\n", counter++, error); + if (!(rxon->flags & RXON_FLG_SHORT_SLOT_MSK)) { + IWL_WARN(priv, "check 5.2G: not short slot!\n"); + error = true; + } + if (rxon->flags & RXON_FLG_CCK_MSK) { + IWL_WARN(priv, "check 5.2G: CCK!\n"); + error = true; + } + } + if ((rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1) { + IWL_WARN(priv, "mac/bssid mcast!\n"); + error = true; + } /* make sure basic rates 6Mbps and 1Mbps are supported */ - error |= (((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0) && - ((rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0)); - if (error) - IWL_WARN(priv, "check basic rate %d | %d\n", counter++, error); + if ((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0 && + (rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0) { + IWL_WARN(priv, "neither 1 nor 6 are basic\n"); + error = true; + } - error |= (le16_to_cpu(rxon->assoc_id) > 2007); - if (error) - IWL_WARN(priv, "check assoc id %d | %d\n", counter++, error); + if (le16_to_cpu(rxon->assoc_id) > 2007) { + IWL_WARN(priv, "aid > 2007\n"); + error = true; + } - error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) - == (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)); - if (error) - IWL_WARN(priv, "check CCK and short slot %d | %d\n", - counter++, error); + if ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) + == (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) { + IWL_WARN(priv, "CCK and short slot\n"); + error = true; + } - error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) - == (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)); - if (error) - IWL_WARN(priv, "check CCK & auto detect %d | %d\n", - counter++, error); + if ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) + == (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) { + IWL_WARN(priv, "CCK and auto detect"); + error = true; + } - error |= ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK | - RXON_FLG_TGG_PROTECT_MSK)) == RXON_FLG_TGG_PROTECT_MSK); - if (error) - IWL_WARN(priv, "check TGG and auto detect %d | %d\n", - counter++, error); + if ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK | + RXON_FLG_TGG_PROTECT_MSK)) == + RXON_FLG_TGG_PROTECT_MSK) { + IWL_WARN(priv, "TGg but no auto-detect\n"); + error = true; + } if (error) IWL_WARN(priv, "Tuning to channel %d\n", le16_to_cpu(rxon->channel)); if (error) { - IWL_ERR(priv, "Not a valid iwl_rxon_assoc_cmd field values\n"); - return -1; + IWL_ERR(priv, "Invalid RXON\n"); + return -EINVAL; } return 0; } -- cgit v0.10.2 From 657e11a47dede79cae1d2f72084f6f7303aec725 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 7 Oct 2010 03:52:35 -0700 Subject: iwlwifi: blink LED in IBSS mode We recently found that contrary to expectations, the LED is not blinking in IBSS mode. Fix this. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index ecf5c9b..25fb391 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1727,6 +1727,7 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw, memcpy(ctx->staging.bssid_addr, bss_conf->bssid, ETH_ALEN); memcpy(priv->bssid, bss_conf->bssid, ETH_ALEN); + iwl_led_associate(priv); iwlcore_config_ap(priv, vif); } else iwl_set_no_assoc(priv, vif); -- cgit v0.10.2 From 40bbfd4c1b336b8841bef9933b6e09252ace56b8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 7 Oct 2010 04:00:33 -0700 Subject: iwlagn: check beacon frame size When the beacon_skb is NULL, we might still attempt to use it in this code path (if we ever get here) -- make the code a bit more defensive and check the return value of iwl_fill_beacon_frame() against zero. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 7079efb..c2636a7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -385,6 +385,8 @@ static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv, sizeof(frame->u) - sizeof(*tx_beacon_cmd)); if (WARN_ON_ONCE(frame_size > MAX_MPDU_SIZE)) return 0; + if (!frame_size) + return 0; /* Set up TX command fields */ tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size); -- cgit v0.10.2 From 3be63ff0ae196b371728ba8fc8aca12eafcae218 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 8 Oct 2010 16:05:19 -0700 Subject: iwlwifi: move agn only eeprom functions to separate file Some of the functions in iwl-eeprom.c file are for agn devices only, Those functions do not have to be part of iwlcore.ko, so move those to iwl-agn-eeprom.c file. Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index b4b24b6..63edbe2 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -12,7 +12,7 @@ obj-$(CONFIG_IWLAGN) += iwlagn.o iwlagn-objs := iwl-agn.o iwl-agn-rs.o iwl-agn-led.o iwl-agn-ict.o iwlagn-objs += iwl-agn-ucode.o iwl-agn-hcmd.o iwl-agn-tx.o iwlagn-objs += iwl-agn-lib.o iwl-agn-rx.o iwl-agn-calib.o -iwlagn-objs += iwl-agn-tt.o iwl-agn-sta.o +iwlagn-objs += iwl-agn-tt.o iwl-agn-sta.o iwl-agn-eeprom.o iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-agn-debugfs.o iwlagn-$(CONFIG_IWL4965) += iwl-4965.o diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c new file mode 100644 index 0000000..a650bab --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c @@ -0,0 +1,454 @@ +/****************************************************************************** + * + * 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 - 2010 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: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2010 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 +#include + +#include + +#include "iwl-commands.h" +#include "iwl-dev.h" +#include "iwl-core.h" +#include "iwl-debug.h" +#include "iwl-agn.h" +#include "iwl-io.h" + +/************************** EEPROM BANDS **************************** + * + * The iwl_eeprom_band definitions below provide the mapping from the + * EEPROM contents to the specific channel number supported for each + * band. + * + * For example, iwl_priv->eeprom.band_3_channels[4] from the band_3 + * definition below maps to physical channel 42 in the 5.2GHz spectrum. + * The specific geography and calibration information for that channel + * is contained in the eeprom map itself. + * + * During init, we copy the eeprom information and channel map + * information into priv->channel_info_24/52 and priv->channel_map_24/52 + * + * channel_map_24/52 provides the index in the channel_info array for a + * given channel. We have to have two separate maps as there is channel + * overlap with the 2.4GHz and 5.2GHz spectrum as seen in band_1 and + * band_2 + * + * A value of 0xff stored in the channel_map indicates that the channel + * is not supported by the hardware at all. + * + * A value of 0xfe in the channel_map indicates that the channel is not + * valid for Tx with the current hardware. This means that + * while the system can tune and receive on a given channel, it may not + * be able to associate or transmit any frames on that + * channel. There is no corresponding channel information for that + * entry. + * + *********************************************************************/ + +/** + * struct iwl_txpwr_section: eeprom section information + * @offset: indirect address into eeprom image + * @count: number of "struct iwl_eeprom_enhanced_txpwr" in this section + * @band: band type for the section + * @is_common - true: common section, false: channel section + * @is_cck - true: cck section, false: not cck section + * @is_ht_40 - true: all channel in the section are HT40 channel, + * false: legacy or HT 20 MHz + * ignore if it is common section + * @iwl_eeprom_section_channel: channel array in the section, + * ignore if common section + */ +struct iwl_txpwr_section { + u32 offset; + u8 count; + enum ieee80211_band band; + bool is_common; + bool is_cck; + bool is_ht40; + u8 iwl_eeprom_section_channel[EEPROM_MAX_TXPOWER_SECTION_ELEMENTS]; +}; + +/** + * section 1 - 3 are regulatory tx power apply to all channels based on + * modulation: CCK, OFDM + * Band: 2.4GHz, 5.2GHz + * section 4 - 10 are regulatory tx power apply to specified channels + * For example: + * 1L - Channel 1 Legacy + * 1HT - Channel 1 HT + * (1,+1) - Channel 1 HT40 "_above_" + * + * Section 1: all CCK channels + * Section 2: all 2.4 GHz OFDM (Legacy, HT and HT40) channels + * Section 3: all 5.2 GHz OFDM (Legacy, HT and HT40) channels + * Section 4: 2.4 GHz 20MHz channels: 1L, 1HT, 2L, 2HT, 10L, 10HT, 11L, 11HT + * Section 5: 2.4 GHz 40MHz channels: (1,+1) (2,+1) (6,+1) (7,+1) (9,+1) + * Section 6: 5.2 GHz 20MHz channels: 36L, 64L, 100L, 36HT, 64HT, 100HT + * Section 7: 5.2 GHz 40MHz channels: (36,+1) (60,+1) (100,+1) + * Section 8: 2.4 GHz channel: 13L, 13HT + * Section 9: 2.4 GHz channel: 140L, 140HT + * Section 10: 2.4 GHz 40MHz channels: (132,+1) (44,+1) + * + */ +static const struct iwl_txpwr_section enhinfo[] = { + { EEPROM_LB_CCK_20_COMMON, 1, IEEE80211_BAND_2GHZ, true, true, false }, + { EEPROM_LB_OFDM_COMMON, 3, IEEE80211_BAND_2GHZ, true, false, false }, + { EEPROM_HB_OFDM_COMMON, 3, IEEE80211_BAND_5GHZ, true, false, false }, + { EEPROM_LB_OFDM_20_BAND, 8, IEEE80211_BAND_2GHZ, + false, false, false, + {1, 1, 2, 2, 10, 10, 11, 11 } }, + { EEPROM_LB_OFDM_HT40_BAND, 5, IEEE80211_BAND_2GHZ, + false, false, true, + { 1, 2, 6, 7, 9 } }, + { EEPROM_HB_OFDM_20_BAND, 6, IEEE80211_BAND_5GHZ, + false, false, false, + { 36, 64, 100, 36, 64, 100 } }, + { EEPROM_HB_OFDM_HT40_BAND, 3, IEEE80211_BAND_5GHZ, + false, false, true, + { 36, 60, 100 } }, + { EEPROM_LB_OFDM_20_CHANNEL_13, 2, IEEE80211_BAND_2GHZ, + false, false, false, + { 13, 13 } }, + { EEPROM_HB_OFDM_20_CHANNEL_140, 2, IEEE80211_BAND_5GHZ, + false, false, false, + { 140, 140 } }, + { EEPROM_HB_OFDM_HT40_BAND_1, 2, IEEE80211_BAND_5GHZ, + false, false, true, + { 132, 44 } }, +}; + +/****************************************************************************** + * + * EEPROM related functions + * +******************************************************************************/ + +/* + * The device's EEPROM semaphore prevents conflicts between driver and uCode + * when accessing the EEPROM; each access is a series of pulses to/from the + * EEPROM chip, not a single event, so even reads could conflict if they + * weren't arbitrated by the semaphore. + */ +int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv) +{ + u16 count; + int ret; + + for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) { + /* Request semaphore */ + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); + + /* See if we got it */ + ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, + CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, + EEPROM_SEM_TIMEOUT); + if (ret >= 0) { + IWL_DEBUG_IO(priv, + "Acquired semaphore after %d tries.\n", + count+1); + return ret; + } + } + + return ret; +} + +void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv) +{ + iwl_clear_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); + +} + +int iwl_eeprom_check_version(struct iwl_priv *priv) +{ + u16 eeprom_ver; + u16 calib_ver; + + eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); + calib_ver = priv->cfg->ops->lib->eeprom_ops.calib_version(priv); + + if (eeprom_ver < priv->cfg->eeprom_ver || + calib_ver < priv->cfg->eeprom_calib_ver) + goto err; + + IWL_INFO(priv, "device EEPROM VER=0x%x, CALIB=0x%x\n", + eeprom_ver, calib_ver); + + return 0; +err: + IWL_ERR(priv, "Unsupported (too old) EEPROM VER=0x%x < 0x%x " + "CALIB=0x%x < 0x%x\n", + eeprom_ver, priv->cfg->eeprom_ver, + calib_ver, priv->cfg->eeprom_calib_ver); + return -EINVAL; + +} + +void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac) +{ + const u8 *addr = priv->cfg->ops->lib->eeprom_ops.query_addr(priv, + EEPROM_MAC_ADDRESS); + memcpy(mac, addr, ETH_ALEN); +} + +/** + * iwl_get_max_txpower_avg - get the highest tx power from all chains. + * find the highest tx power from all chains for the channel + */ +static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv, + struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, + int element, s8 *max_txpower_in_half_dbm) +{ + s8 max_txpower_avg = 0; /* (dBm) */ + + IWL_DEBUG_INFO(priv, "%d - " + "chain_a: %d dB chain_b: %d dB " + "chain_c: %d dB mimo2: %d dB mimo3: %d dB\n", + element, + enhanced_txpower[element].chain_a_max >> 1, + enhanced_txpower[element].chain_b_max >> 1, + enhanced_txpower[element].chain_c_max >> 1, + enhanced_txpower[element].mimo2_max >> 1, + enhanced_txpower[element].mimo3_max >> 1); + /* Take the highest tx power from any valid chains */ + if ((priv->cfg->valid_tx_ant & ANT_A) && + (enhanced_txpower[element].chain_a_max > max_txpower_avg)) + max_txpower_avg = enhanced_txpower[element].chain_a_max; + if ((priv->cfg->valid_tx_ant & ANT_B) && + (enhanced_txpower[element].chain_b_max > max_txpower_avg)) + max_txpower_avg = enhanced_txpower[element].chain_b_max; + if ((priv->cfg->valid_tx_ant & ANT_C) && + (enhanced_txpower[element].chain_c_max > max_txpower_avg)) + max_txpower_avg = enhanced_txpower[element].chain_c_max; + if (((priv->cfg->valid_tx_ant == ANT_AB) | + (priv->cfg->valid_tx_ant == ANT_BC) | + (priv->cfg->valid_tx_ant == ANT_AC)) && + (enhanced_txpower[element].mimo2_max > max_txpower_avg)) + max_txpower_avg = enhanced_txpower[element].mimo2_max; + if ((priv->cfg->valid_tx_ant == ANT_ABC) && + (enhanced_txpower[element].mimo3_max > max_txpower_avg)) + max_txpower_avg = enhanced_txpower[element].mimo3_max; + + /* + * max. tx power in EEPROM is in 1/2 dBm format + * convert from 1/2 dBm to dBm (round-up convert) + * but we also do not want to loss 1/2 dBm resolution which + * will impact performance + */ + *max_txpower_in_half_dbm = max_txpower_avg; + return (max_txpower_avg & 0x01) + (max_txpower_avg >> 1); +} + +/** + * iwl_update_common_txpower: update channel tx power + * update tx power per band based on EEPROM enhanced tx power info. + */ +static s8 iwl_update_common_txpower(struct iwl_priv *priv, + struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, + int section, int element, s8 *max_txpower_in_half_dbm) +{ + struct iwl_channel_info *ch_info; + int ch; + bool is_ht40 = false; + s8 max_txpower_avg; /* (dBm) */ + + /* it is common section, contain all type (Legacy, HT and HT40) + * based on the element in the section to determine + * is it HT 40 or not + */ + if (element == EEPROM_TXPOWER_COMMON_HT40_INDEX) + is_ht40 = true; + max_txpower_avg = + iwl_get_max_txpower_avg(priv, enhanced_txpower, + element, max_txpower_in_half_dbm); + + ch_info = priv->channel_info; + + for (ch = 0; ch < priv->channel_count; ch++) { + /* find matching band and update tx power if needed */ + if ((ch_info->band == enhinfo[section].band) && + (ch_info->max_power_avg < max_txpower_avg) && + (!is_ht40)) { + /* Update regulatory-based run-time data */ + ch_info->max_power_avg = ch_info->curr_txpow = + max_txpower_avg; + ch_info->scan_power = max_txpower_avg; + } + if ((ch_info->band == enhinfo[section].band) && is_ht40 && + (ch_info->ht40_max_power_avg < max_txpower_avg)) { + /* Update regulatory-based run-time data */ + ch_info->ht40_max_power_avg = max_txpower_avg; + } + ch_info++; + } + return max_txpower_avg; +} + +/** + * iwl_update_channel_txpower: update channel tx power + * update channel tx power based on EEPROM enhanced tx power info. + */ +static s8 iwl_update_channel_txpower(struct iwl_priv *priv, + struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, + int section, int element, s8 *max_txpower_in_half_dbm) +{ + struct iwl_channel_info *ch_info; + int ch; + u8 channel; + s8 max_txpower_avg; /* (dBm) */ + + channel = enhinfo[section].iwl_eeprom_section_channel[element]; + max_txpower_avg = + iwl_get_max_txpower_avg(priv, enhanced_txpower, + element, max_txpower_in_half_dbm); + + ch_info = priv->channel_info; + for (ch = 0; ch < priv->channel_count; ch++) { + /* find matching channel and update tx power if needed */ + if (ch_info->channel == channel) { + if ((ch_info->max_power_avg < max_txpower_avg) && + (!enhinfo[section].is_ht40)) { + /* Update regulatory-based run-time data */ + ch_info->max_power_avg = max_txpower_avg; + ch_info->curr_txpow = max_txpower_avg; + ch_info->scan_power = max_txpower_avg; + } + if ((enhinfo[section].is_ht40) && + (ch_info->ht40_max_power_avg < max_txpower_avg)) { + /* Update regulatory-based run-time data */ + ch_info->ht40_max_power_avg = max_txpower_avg; + } + break; + } + ch_info++; + } + return max_txpower_avg; +} + +/** + * iwlcore_eeprom_enhanced_txpower: process enhanced tx power info + */ +void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv) +{ + int eeprom_section_count = 0; + int section, element; + struct iwl_eeprom_enhanced_txpwr *enhanced_txpower; + u32 offset; + s8 max_txpower_avg; /* (dBm) */ + s8 max_txpower_in_half_dbm; /* (half-dBm) */ + + /* Loop through all the sections + * adjust bands and channel's max tx power + * Set the tx_power_user_lmt to the highest power + * supported by any channels and chains + */ + for (section = 0; section < ARRAY_SIZE(enhinfo); section++) { + eeprom_section_count = enhinfo[section].count; + offset = enhinfo[section].offset; + enhanced_txpower = (struct iwl_eeprom_enhanced_txpwr *) + iwl_eeprom_query_addr(priv, offset); + + /* + * check for valid entry - + * different version of EEPROM might contain different set + * of enhanced tx power table + * always check for valid entry before process + * the information + */ + if (!enhanced_txpower->common || enhanced_txpower->reserved) + continue; + + for (element = 0; element < eeprom_section_count; element++) { + if (enhinfo[section].is_common) + max_txpower_avg = + iwl_update_common_txpower(priv, + enhanced_txpower, section, + element, + &max_txpower_in_half_dbm); + else + max_txpower_avg = + iwl_update_channel_txpower(priv, + enhanced_txpower, section, + element, + &max_txpower_in_half_dbm); + + /* Update the tx_power_user_lmt to the highest power + * supported by any channel */ + if (max_txpower_avg > priv->tx_power_user_lmt) + priv->tx_power_user_lmt = max_txpower_avg; + + /* + * Update the tx_power_lmt_in_half_dbm to + * the highest power supported by any channel + */ + if (max_txpower_in_half_dbm > + priv->tx_power_lmt_in_half_dbm) + priv->tx_power_lmt_in_half_dbm = + max_txpower_in_half_dbm; + } + } +} diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index b4deef4..f525d55 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -312,4 +312,10 @@ static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags) return cpu_to_le32(flags|(u32)rate); } +/* eeprom */ +void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv); +void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac); +int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv); +void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv); + #endif /* __iwl_agn_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 66eccb1..87cd10f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -136,78 +136,6 @@ static const u8 iwl_eeprom_band_7[] = { /* 5.2 ht40 channel */ 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157 }; -/** - * struct iwl_txpwr_section: eeprom section information - * @offset: indirect address into eeprom image - * @count: number of "struct iwl_eeprom_enhanced_txpwr" in this section - * @band: band type for the section - * @is_common - true: common section, false: channel section - * @is_cck - true: cck section, false: not cck section - * @is_ht_40 - true: all channel in the section are HT40 channel, - * false: legacy or HT 20 MHz - * ignore if it is common section - * @iwl_eeprom_section_channel: channel array in the section, - * ignore if common section - */ -struct iwl_txpwr_section { - u32 offset; - u8 count; - enum ieee80211_band band; - bool is_common; - bool is_cck; - bool is_ht40; - u8 iwl_eeprom_section_channel[EEPROM_MAX_TXPOWER_SECTION_ELEMENTS]; -}; - -/** - * section 1 - 3 are regulatory tx power apply to all channels based on - * modulation: CCK, OFDM - * Band: 2.4GHz, 5.2GHz - * section 4 - 10 are regulatory tx power apply to specified channels - * For example: - * 1L - Channel 1 Legacy - * 1HT - Channel 1 HT - * (1,+1) - Channel 1 HT40 "_above_" - * - * Section 1: all CCK channels - * Section 2: all 2.4 GHz OFDM (Legacy, HT and HT40) channels - * Section 3: all 5.2 GHz OFDM (Legacy, HT and HT40) channels - * Section 4: 2.4 GHz 20MHz channels: 1L, 1HT, 2L, 2HT, 10L, 10HT, 11L, 11HT - * Section 5: 2.4 GHz 40MHz channels: (1,+1) (2,+1) (6,+1) (7,+1) (9,+1) - * Section 6: 5.2 GHz 20MHz channels: 36L, 64L, 100L, 36HT, 64HT, 100HT - * Section 7: 5.2 GHz 40MHz channels: (36,+1) (60,+1) (100,+1) - * Section 8: 2.4 GHz channel: 13L, 13HT - * Section 9: 2.4 GHz channel: 140L, 140HT - * Section 10: 2.4 GHz 40MHz channels: (132,+1) (44,+1) - * - */ -static const struct iwl_txpwr_section enhinfo[] = { - { EEPROM_LB_CCK_20_COMMON, 1, IEEE80211_BAND_2GHZ, true, true, false }, - { EEPROM_LB_OFDM_COMMON, 3, IEEE80211_BAND_2GHZ, true, false, false }, - { EEPROM_HB_OFDM_COMMON, 3, IEEE80211_BAND_5GHZ, true, false, false }, - { EEPROM_LB_OFDM_20_BAND, 8, IEEE80211_BAND_2GHZ, - false, false, false, - {1, 1, 2, 2, 10, 10, 11, 11 } }, - { EEPROM_LB_OFDM_HT40_BAND, 5, IEEE80211_BAND_2GHZ, - false, false, true, - { 1, 2, 6, 7, 9 } }, - { EEPROM_HB_OFDM_20_BAND, 6, IEEE80211_BAND_5GHZ, - false, false, false, - { 36, 64, 100, 36, 64, 100 } }, - { EEPROM_HB_OFDM_HT40_BAND, 3, IEEE80211_BAND_5GHZ, - false, false, true, - { 36, 60, 100 } }, - { EEPROM_LB_OFDM_20_CHANNEL_13, 2, IEEE80211_BAND_2GHZ, - false, false, false, - { 13, 13 } }, - { EEPROM_HB_OFDM_20_CHANNEL_140, 2, IEEE80211_BAND_5GHZ, - false, false, false, - { 140, 140 } }, - { EEPROM_HB_OFDM_HT40_BAND_1, 2, IEEE80211_BAND_5GHZ, - false, false, true, - { 132, 44 } }, -}; - /****************************************************************************** * * EEPROM related functions @@ -289,46 +217,6 @@ static int iwlcore_get_nvm_type(struct iwl_priv *priv) return nvm_type; } -/* - * The device's EEPROM semaphore prevents conflicts between driver and uCode - * when accessing the EEPROM; each access is a series of pulses to/from the - * EEPROM chip, not a single event, so even reads could conflict if they - * weren't arbitrated by the semaphore. - */ -int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv) -{ - u16 count; - int ret; - - for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) { - /* Request semaphore */ - iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); - - /* See if we got it */ - ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, - CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, - EEPROM_SEM_TIMEOUT); - if (ret >= 0) { - IWL_DEBUG_IO(priv, "Acquired semaphore after %d tries.\n", - count+1); - return ret; - } - } - - return ret; -} -EXPORT_SYMBOL(iwlcore_eeprom_acquire_semaphore); - -void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv) -{ - iwl_clear_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); - -} -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->base_params->eeprom_size); @@ -490,6 +378,20 @@ static int iwl_find_otp_image(struct iwl_priv *priv, return -EINVAL; } +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) +{ + if (!priv->eeprom) + return 0; + return (u16)priv->eeprom[offset] | ((u16)priv->eeprom[offset + 1] << 8); +} +EXPORT_SYMBOL(iwl_eeprom_query16); + /** * iwl_eeprom_init - read EEPROM contents * @@ -616,53 +518,6 @@ void iwl_eeprom_free(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_eeprom_free); -int iwl_eeprom_check_version(struct iwl_priv *priv) -{ - u16 eeprom_ver; - u16 calib_ver; - - eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); - calib_ver = priv->cfg->ops->lib->eeprom_ops.calib_version(priv); - - if (eeprom_ver < priv->cfg->eeprom_ver || - calib_ver < priv->cfg->eeprom_calib_ver) - goto err; - - IWL_INFO(priv, "device EEPROM VER=0x%x, CALIB=0x%x\n", - eeprom_ver, calib_ver); - - return 0; -err: - IWL_ERR(priv, "Unsupported (too old) EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n", - eeprom_ver, priv->cfg->eeprom_ver, - calib_ver, priv->cfg->eeprom_calib_ver); - return -EINVAL; - -} -EXPORT_SYMBOL(iwl_eeprom_check_version); - -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) -{ - if (!priv->eeprom) - return 0; - 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) -{ - 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 eep_band, int *eeprom_ch_count, const struct iwl_eeprom_channel **eeprom_ch_info, @@ -721,7 +576,6 @@ static void iwl_init_band_reference(const struct iwl_priv *priv, #define CHECK_AND_PRINT(x) ((eeprom_ch->flags & EEPROM_CHANNEL_##x) \ ? # x " " : "") - /** * iwl_mod_ht40_chan_info - Copy ht40 channel info into driver's priv. * @@ -765,205 +619,6 @@ static int iwl_mod_ht40_chan_info(struct iwl_priv *priv, return 0; } -/** - * iwl_get_max_txpower_avg - get the highest tx power from all chains. - * find the highest tx power from all chains for the channel - */ -static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv, - struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, - int element, s8 *max_txpower_in_half_dbm) -{ - s8 max_txpower_avg = 0; /* (dBm) */ - - IWL_DEBUG_INFO(priv, "%d - " - "chain_a: %d dB chain_b: %d dB " - "chain_c: %d dB mimo2: %d dB mimo3: %d dB\n", - element, - enhanced_txpower[element].chain_a_max >> 1, - enhanced_txpower[element].chain_b_max >> 1, - enhanced_txpower[element].chain_c_max >> 1, - enhanced_txpower[element].mimo2_max >> 1, - enhanced_txpower[element].mimo3_max >> 1); - /* Take the highest tx power from any valid chains */ - if ((priv->cfg->valid_tx_ant & ANT_A) && - (enhanced_txpower[element].chain_a_max > max_txpower_avg)) - max_txpower_avg = enhanced_txpower[element].chain_a_max; - if ((priv->cfg->valid_tx_ant & ANT_B) && - (enhanced_txpower[element].chain_b_max > max_txpower_avg)) - max_txpower_avg = enhanced_txpower[element].chain_b_max; - if ((priv->cfg->valid_tx_ant & ANT_C) && - (enhanced_txpower[element].chain_c_max > max_txpower_avg)) - max_txpower_avg = enhanced_txpower[element].chain_c_max; - if (((priv->cfg->valid_tx_ant == ANT_AB) | - (priv->cfg->valid_tx_ant == ANT_BC) | - (priv->cfg->valid_tx_ant == ANT_AC)) && - (enhanced_txpower[element].mimo2_max > max_txpower_avg)) - max_txpower_avg = enhanced_txpower[element].mimo2_max; - if ((priv->cfg->valid_tx_ant == ANT_ABC) && - (enhanced_txpower[element].mimo3_max > max_txpower_avg)) - max_txpower_avg = enhanced_txpower[element].mimo3_max; - - /* - * max. tx power in EEPROM is in 1/2 dBm format - * convert from 1/2 dBm to dBm (round-up convert) - * but we also do not want to loss 1/2 dBm resolution which - * will impact performance - */ - *max_txpower_in_half_dbm = max_txpower_avg; - return (max_txpower_avg & 0x01) + (max_txpower_avg >> 1); -} - -/** - * iwl_update_common_txpower: update channel tx power - * update tx power per band based on EEPROM enhanced tx power info. - */ -static s8 iwl_update_common_txpower(struct iwl_priv *priv, - struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, - int section, int element, s8 *max_txpower_in_half_dbm) -{ - struct iwl_channel_info *ch_info; - int ch; - bool is_ht40 = false; - s8 max_txpower_avg; /* (dBm) */ - - /* it is common section, contain all type (Legacy, HT and HT40) - * based on the element in the section to determine - * is it HT 40 or not - */ - if (element == EEPROM_TXPOWER_COMMON_HT40_INDEX) - is_ht40 = true; - max_txpower_avg = - iwl_get_max_txpower_avg(priv, enhanced_txpower, - element, max_txpower_in_half_dbm); - - ch_info = priv->channel_info; - - for (ch = 0; ch < priv->channel_count; ch++) { - /* find matching band and update tx power if needed */ - if ((ch_info->band == enhinfo[section].band) && - (ch_info->max_power_avg < max_txpower_avg) && - (!is_ht40)) { - /* Update regulatory-based run-time data */ - ch_info->max_power_avg = ch_info->curr_txpow = - max_txpower_avg; - ch_info->scan_power = max_txpower_avg; - } - if ((ch_info->band == enhinfo[section].band) && is_ht40 && - (ch_info->ht40_max_power_avg < max_txpower_avg)) { - /* Update regulatory-based run-time data */ - ch_info->ht40_max_power_avg = max_txpower_avg; - } - ch_info++; - } - return max_txpower_avg; -} - -/** - * iwl_update_channel_txpower: update channel tx power - * update channel tx power based on EEPROM enhanced tx power info. - */ -static s8 iwl_update_channel_txpower(struct iwl_priv *priv, - struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, - int section, int element, s8 *max_txpower_in_half_dbm) -{ - struct iwl_channel_info *ch_info; - int ch; - u8 channel; - s8 max_txpower_avg; /* (dBm) */ - - channel = enhinfo[section].iwl_eeprom_section_channel[element]; - max_txpower_avg = - iwl_get_max_txpower_avg(priv, enhanced_txpower, - element, max_txpower_in_half_dbm); - - ch_info = priv->channel_info; - for (ch = 0; ch < priv->channel_count; ch++) { - /* find matching channel and update tx power if needed */ - if (ch_info->channel == channel) { - if ((ch_info->max_power_avg < max_txpower_avg) && - (!enhinfo[section].is_ht40)) { - /* Update regulatory-based run-time data */ - ch_info->max_power_avg = max_txpower_avg; - ch_info->curr_txpow = max_txpower_avg; - ch_info->scan_power = max_txpower_avg; - } - if ((enhinfo[section].is_ht40) && - (ch_info->ht40_max_power_avg < max_txpower_avg)) { - /* Update regulatory-based run-time data */ - ch_info->ht40_max_power_avg = max_txpower_avg; - } - break; - } - ch_info++; - } - return max_txpower_avg; -} - -/** - * iwlcore_eeprom_enhanced_txpower: process enhanced tx power info - */ -void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv) -{ - int eeprom_section_count = 0; - int section, element; - struct iwl_eeprom_enhanced_txpwr *enhanced_txpower; - u32 offset; - s8 max_txpower_avg; /* (dBm) */ - s8 max_txpower_in_half_dbm; /* (half-dBm) */ - - /* Loop through all the sections - * adjust bands and channel's max tx power - * Set the tx_power_user_lmt to the highest power - * supported by any channels and chains - */ - for (section = 0; section < ARRAY_SIZE(enhinfo); section++) { - eeprom_section_count = enhinfo[section].count; - offset = enhinfo[section].offset; - enhanced_txpower = (struct iwl_eeprom_enhanced_txpwr *) - iwl_eeprom_query_addr(priv, offset); - - /* - * check for valid entry - - * different version of EEPROM might contain different set - * of enhanced tx power table - * always check for valid entry before process - * the information - */ - if (!enhanced_txpower->common || enhanced_txpower->reserved) - continue; - - for (element = 0; element < eeprom_section_count; element++) { - if (enhinfo[section].is_common) - max_txpower_avg = - iwl_update_common_txpower(priv, - enhanced_txpower, section, - element, - &max_txpower_in_half_dbm); - else - max_txpower_avg = - iwl_update_channel_txpower(priv, - enhanced_txpower, section, - element, - &max_txpower_in_half_dbm); - - /* Update the tx_power_user_lmt to the highest power - * supported by any channel */ - if (max_txpower_avg > priv->tx_power_user_lmt) - priv->tx_power_user_lmt = max_txpower_avg; - - /* - * Update the tx_power_lmt_in_half_dbm to - * the highest power supported by any channel - */ - if (max_txpower_in_half_dbm > - priv->tx_power_lmt_in_half_dbm) - priv->tx_power_lmt_in_half_dbm = - max_txpower_in_half_dbm; - } - } -} -EXPORT_SYMBOL(iwlcore_eeprom_enhanced_txpower); - #define CHECK_AND_PRINT_I(x) ((eeprom_ch_info[ch].flags & EEPROM_CHANNEL_##x) \ ? # x " " : "") @@ -1161,4 +816,3 @@ const struct iwl_channel_info *iwl_get_channel_info(const struct iwl_priv *priv, return NULL; } EXPORT_SYMBOL(iwl_get_channel_info); - diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 2ae0a11..d9b5906 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -501,18 +501,13 @@ 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); - 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); +u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset); const u8 *iwlcore_eeprom_query_addr(const struct iwl_priv *priv, size_t offset); -void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv); int iwl_init_channel_map(struct iwl_priv *priv); void iwl_free_channel_map(struct iwl_priv *priv); const struct iwl_channel_info *iwl_get_channel_info( -- cgit v0.10.2 From 898c914a0871ea7e5557b77156d4358c0f15d98a Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 12 Oct 2010 14:02:53 +0200 Subject: ath9k: do not track cycle counter updates in powersave mode While the chip is in powersave mode, the cycle counter updates do not contain useful values. While the chip is in full sleep, the rx_clear signal stays high, indicating a busy medium. To ensure sane values, update cycle counters before going into powersave, and clear them right after switching back to awake. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index bcd3892..74ff51d 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -121,6 +121,7 @@ bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode) void ath9k_ps_wakeup(struct ath_softc *sc) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); unsigned long flags; spin_lock_irqsave(&sc->sc_pm_lock, flags); @@ -129,18 +130,33 @@ void ath9k_ps_wakeup(struct ath_softc *sc) ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); + /* + * While the hardware is asleep, the cycle counters contain no + * useful data. Better clear them now so that they don't mess up + * survey data results. + */ + spin_lock(&common->cc_lock); + ath_hw_cycle_counters_update(common); + memset(&common->cc_survey, 0, sizeof(common->cc_survey)); + spin_unlock(&common->cc_lock); + unlock: spin_unlock_irqrestore(&sc->sc_pm_lock, flags); } void ath9k_ps_restore(struct ath_softc *sc) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); unsigned long flags; spin_lock_irqsave(&sc->sc_pm_lock, flags); if (--sc->ps_usecount != 0) goto unlock; + spin_lock(&common->cc_lock); + ath_hw_cycle_counters_update(common); + spin_unlock(&common->cc_lock); + if (sc->ps_idle) ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP); else if (sc->ps_enabled && @@ -196,7 +212,8 @@ static void ath_update_survey_stats(struct ath_softc *sc) struct ath_cycle_counters *cc = &common->cc_survey; unsigned int div = common->clockrate * 1000; - ath_hw_cycle_counters_update(common); + if (ah->power_mode == ATH9K_PM_AWAKE) + ath_hw_cycle_counters_update(common); if (cc->cycles > 0) { survey->filled |= SURVEY_INFO_CHANNEL_TIME | -- cgit v0.10.2 From e49f913750bb8745085cc4c547912c330cd3eacb Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 12 Oct 2010 16:08:01 +0200 Subject: ath9k_hw: fix division by zero in the ANI monitor code The commit "ath9k_hw: remove code duplication in phy error counter handling" split off some duplicate code into a separate function, but did not have a return code for aborting ANI processing based on counter values. This introduced a divide by zero issue. This patch adds the missing return code check in ath9k_hw_ani_monitor Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index 3aa8fb1..9297f57 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -633,7 +633,7 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning) REGWRITE_BUFFER_FLUSH(ah); } -static void ath9k_hw_ani_read_counters(struct ath_hw *ah) +static bool ath9k_hw_ani_read_counters(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); struct ar5416AniState *aniState = &ah->curchan->ani; @@ -646,10 +646,10 @@ static void ath9k_hw_ani_read_counters(struct ath_hw *ah) ath_hw_cycle_counters_update(common); listenTime = ath_hw_get_listen_time(common); - if (listenTime < 0) { + if (listenTime <= 0) { ah->stats.ast_ani_lneg++; ath9k_ani_restart(ah); - return; + return false; } if (!use_new_ani(ah)) { @@ -683,7 +683,7 @@ static void ath9k_hw_ani_read_counters(struct ath_hw *ah) REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); } - return; + return false; } ofdmPhyErrCnt = phyCnt1 - ofdm_base; @@ -695,7 +695,7 @@ static void ath9k_hw_ani_read_counters(struct ath_hw *ah) ah->stats.ast_ani_cckerrs += cckPhyErrCnt - aniState->cckPhyErrCount; aniState->cckPhyErrCount = cckPhyErrCnt; - + return true; } void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan) @@ -711,7 +711,8 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan) if (WARN_ON(!aniState)) return; - ath9k_hw_ani_read_counters(ah); + if (!ath9k_hw_ani_read_counters(ah)) + return; ofdmPhyErrRate = aniState->ofdmPhyErrCount * 1000 / aniState->listenTime; -- cgit v0.10.2 From 431c74821432a6078d54f08de7cd561f8ef8f1ba Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 12 Oct 2010 16:08:02 +0200 Subject: ath9k_hw: fix PHY counter overflow handling in ANI v1 PHY counter overflows need to be checked for the old ANI version, because of its use of interrupt based counter overflow reports when the counters exceed the configured thresholds. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index 9297f57..63ccb39 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -664,7 +664,7 @@ static bool ath9k_hw_ani_read_counters(struct ath_hw *ah) phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); - if (use_new_ani(ah) && (phyCnt1 < ofdm_base || phyCnt2 < cck_base)) { + if (!use_new_ani(ah) && (phyCnt1 < ofdm_base || phyCnt2 < cck_base)) { if (phyCnt1 < ofdm_base) { ath_print(common, ATH_DBG_ANI, "phyCnt1 0x%x, resetting " -- cgit v0.10.2 From 88eac2dad876a58b9c6a4c4805c3fc27b02c048f Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 12 Oct 2010 16:08:03 +0200 Subject: ath9k: add missing locking around ath9k_hw_proc_mib_event ath9k_hw_proc_mib_event updates the cycle counters, so it common->cc_lock must be acquired. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 74ff51d..2c7f28e 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -779,7 +779,9 @@ irqreturn_t ath_isr(int irq, void *dev) * it will clear whatever condition caused * the interrupt. */ + spin_lock(&common->cc_lock); ath9k_hw_proc_mib_event(ah); + spin_unlock(&common->cc_lock); ath9k_hw_set_interrupts(ah, ah->imask); } -- cgit v0.10.2 From 772d5515635fef5bc7a9d0efee785b58b0181ee5 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 13 Oct 2010 16:43:26 +0200 Subject: ath9k: make rate control debugfs stats per station Move them to the same debugfs file that the other rc modules use. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 74a4570..7f764e3 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -378,95 +378,6 @@ static const struct file_operations fops_interrupt = { .owner = THIS_MODULE }; -void ath_debug_stat_rc(struct ath_softc *sc, int final_rate) -{ - struct ath_rc_stats *stats; - - stats = &sc->debug.stats.rcstats[final_rate]; - stats->success++; -} - -void ath_debug_stat_retries(struct ath_softc *sc, int rix, - int xretries, int retries, u8 per) -{ - struct ath_rc_stats *stats = &sc->debug.stats.rcstats[rix]; - - stats->xretries += xretries; - stats->retries += retries; - stats->per = per; -} - -static ssize_t read_file_rcstat(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - char *buf; - unsigned int len = 0, max; - int i = 0; - ssize_t retval; - - if (sc->cur_rate_table == NULL) - return 0; - - max = 80 + sc->cur_rate_table->rate_cnt * 1024 + 1; - buf = kmalloc(max, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - len += sprintf(buf, "%6s %6s %6s " - "%10s %10s %10s %10s\n", - "HT", "MCS", "Rate", - "Success", "Retries", "XRetries", "PER"); - - for (i = 0; i < sc->cur_rate_table->rate_cnt; i++) { - u32 ratekbps = sc->cur_rate_table->info[i].ratekbps; - struct ath_rc_stats *stats = &sc->debug.stats.rcstats[i]; - char mcs[5]; - char htmode[5]; - int used_mcs = 0, used_htmode = 0; - - if (WLAN_RC_PHY_HT(sc->cur_rate_table->info[i].phy)) { - used_mcs = snprintf(mcs, 5, "%d", - sc->cur_rate_table->info[i].ratecode); - - if (WLAN_RC_PHY_40(sc->cur_rate_table->info[i].phy)) - used_htmode = snprintf(htmode, 5, "HT40"); - else if (WLAN_RC_PHY_20(sc->cur_rate_table->info[i].phy)) - used_htmode = snprintf(htmode, 5, "HT20"); - else - used_htmode = snprintf(htmode, 5, "????"); - } - - mcs[used_mcs] = '\0'; - htmode[used_htmode] = '\0'; - - len += snprintf(buf + len, max - len, - "%6s %6s %3u.%d: " - "%10u %10u %10u %10u\n", - htmode, - mcs, - ratekbps / 1000, - (ratekbps % 1000) / 100, - stats->success, - stats->retries, - stats->xretries, - stats->per); - } - - if (len > max) - len = max; - - retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); - kfree(buf); - return retval; -} - -static const struct file_operations fops_rcstat = { - .read = read_file_rcstat, - .open = ath9k_debugfs_open, - .owner = THIS_MODULE -}; - static const char * ath_wiphy_state_str(enum ath_wiphy_state state) { switch (state) { @@ -977,10 +888,6 @@ int ath9k_init_debug(struct ath_hw *ah) sc, &fops_interrupt)) goto err; - if (!debugfs_create_file("rcstat", S_IRUSR, sc->debug.debugfs_phy, - sc, &fops_rcstat)) - goto err; - if (!debugfs_create_file("wiphy", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_wiphy)) goto err; diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index 822b6f3..bb08232 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -80,13 +80,6 @@ struct ath_interrupt_stats { u32 bb_watchdog; }; -struct ath_rc_stats { - u32 success; - u32 retries; - u32 xretries; - u8 per; -}; - /** * struct ath_tx_stats - Statistics about TX * @tx_pkts_all: No. of total frames transmitted, including ones that @@ -160,7 +153,6 @@ struct ath_rx_stats { struct ath_stats { struct ath_interrupt_stats istats; - struct ath_rc_stats rcstats[RATE_TABLE_SIZE]; struct ath_tx_stats txstats[ATH9K_NUM_TX_QUEUES]; struct ath_rx_stats rxstats; }; @@ -177,12 +169,9 @@ void ath9k_exit_debug(struct ath_hw *ah); int ath9k_debug_create_root(void); void ath9k_debug_remove_root(void); void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status); -void ath_debug_stat_rc(struct ath_softc *sc, int final_rate); void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *bf, struct ath_tx_status *ts); void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs); -void ath_debug_stat_retries(struct ath_softc *sc, int rix, - int xretries, int retries, u8 per); #else @@ -209,11 +198,6 @@ static inline void ath_debug_stat_interrupt(struct ath_softc *sc, { } -static inline void ath_debug_stat_rc(struct ath_softc *sc, - int final_rate) -{ -} - static inline void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *bf, @@ -226,11 +210,6 @@ static inline void ath_debug_stat_rx(struct ath_softc *sc, { } -static inline void ath_debug_stat_retries(struct ath_softc *sc, int rix, - int xretries, int retries, u8 per) -{ -} - #endif /* CONFIG_ATH9K_DEBUGFS */ #endif /* DEBUG_H */ diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index abebf24..5db3a12 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -1026,6 +1026,16 @@ static bool ath_rc_update_per(struct ath_softc *sc, return state_change; } +static void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix, + int xretries, int retries, u8 per) +{ + struct ath_rc_stats *stats = &rc->rcstats[rix]; + + stats->xretries += xretries; + stats->retries += retries; + stats->per = per; +} + /* Update PER, RSSI and whatever else that the code thinks it is doing. If you can make sense of all this, you really need to go out more. */ @@ -1098,7 +1108,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, ath_rc_priv->per_down_time = now_msec; } - ath_debug_stat_retries(sc, tx_rate, xretries, retries, + ath_debug_stat_retries(ath_rc_priv, tx_rate, xretries, retries, ath_rc_priv->per[tx_rate]); } @@ -1294,6 +1304,7 @@ static void ath_rc_init(struct ath_softc *sc, ath_rc_sort_validrates(rate_table, ath_rc_priv); ath_rc_priv->rate_max_phy = ath_rc_priv->valid_rate_index[k-4]; sc->cur_rate_table = rate_table; + ath_rc_priv->rate_table = rate_table; ath_print(common, ATH_DBG_CONFIG, "RC Initialized with capabilities: 0x%x\n", @@ -1340,6 +1351,15 @@ static bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, /* mac80211 Rate Control callbacks */ /***********************************/ +static void ath_debug_stat_rc(struct ath_rate_priv *rc, int final_rate) +{ + struct ath_rc_stats *stats; + + stats = &rc->rcstats[final_rate]; + stats->success++; +} + + static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, struct ieee80211_sta *sta, void *priv_sta, struct sk_buff *skb) @@ -1419,7 +1439,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, } } - ath_debug_stat_rc(sc, ath_rc_get_rateindex(sc->cur_rate_table, + ath_debug_stat_rc(ath_rc_priv, ath_rc_get_rateindex(sc->cur_rate_table, &tx_info->status.rates[final_ts_idx])); } @@ -1521,6 +1541,94 @@ static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband, } } +#ifdef CONFIG_ATH9K_DEBUGFS + +static int ath9k_debugfs_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t read_file_rcstat(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_rate_priv *rc = file->private_data; + char *buf; + unsigned int len = 0, max; + int i = 0; + ssize_t retval; + + if (rc->rate_table == NULL) + return 0; + + max = 80 + rc->rate_table->rate_cnt * 1024 + 1; + buf = kmalloc(max, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + len += sprintf(buf, "%6s %6s %6s " + "%10s %10s %10s %10s\n", + "HT", "MCS", "Rate", + "Success", "Retries", "XRetries", "PER"); + + for (i = 0; i < rc->rate_table->rate_cnt; i++) { + u32 ratekbps = rc->rate_table->info[i].ratekbps; + struct ath_rc_stats *stats = &rc->rcstats[i]; + char mcs[5]; + char htmode[5]; + int used_mcs = 0, used_htmode = 0; + + if (WLAN_RC_PHY_HT(rc->rate_table->info[i].phy)) { + used_mcs = snprintf(mcs, 5, "%d", + rc->rate_table->info[i].ratecode); + + if (WLAN_RC_PHY_40(rc->rate_table->info[i].phy)) + used_htmode = snprintf(htmode, 5, "HT40"); + else if (WLAN_RC_PHY_20(rc->rate_table->info[i].phy)) + used_htmode = snprintf(htmode, 5, "HT20"); + else + used_htmode = snprintf(htmode, 5, "????"); + } + + mcs[used_mcs] = '\0'; + htmode[used_htmode] = '\0'; + + len += snprintf(buf + len, max - len, + "%6s %6s %3u.%d: " + "%10u %10u %10u %10u\n", + htmode, + mcs, + ratekbps / 1000, + (ratekbps % 1000) / 100, + stats->success, + stats->retries, + stats->xretries, + stats->per); + } + + if (len > max) + len = max; + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + return retval; +} + +static const struct file_operations fops_rcstat = { + .read = read_file_rcstat, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE +}; + +static void ath_rate_add_sta_debugfs(void *priv, void *priv_sta, + struct dentry *dir) +{ + struct ath_rate_priv *rc = priv_sta; + debugfs_create_file("rc_stats", S_IRUGO, dir, rc, &fops_rcstat); +} + +#endif /* CONFIG_ATH9K_DEBUGFS */ + static void *ath_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) { struct ath_wiphy *aphy = hw->priv; @@ -1567,6 +1675,9 @@ static struct rate_control_ops ath_rate_ops = { .free = ath_rate_free, .alloc_sta = ath_rate_alloc_sta, .free_sta = ath_rate_free_sta, +#ifdef CONFIG_ATH9K_DEBUGFS + .add_sta_debugfs = ath_rate_add_sta_debugfs, +#endif }; int ath_rate_control_register(void) diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h index fbb1d33..2f46a22 100644 --- a/drivers/net/wireless/ath/ath9k/rc.h +++ b/drivers/net/wireless/ath/ath9k/rc.h @@ -176,6 +176,13 @@ struct ath_rateset { u8 rs_rates[ATH_RATE_MAX]; }; +struct ath_rc_stats { + u32 success; + u32 retries; + u32 xretries; + u8 per; +}; + /** * struct ath_rate_priv - Rate Control priv data * @state: RC state @@ -212,6 +219,10 @@ struct ath_rate_priv { struct ath_rateset neg_rates; struct ath_rateset neg_ht_rates; struct ath_rate_softc *asc; + const struct ath_rate_table *rate_table; + + struct dentry *debugfs_rcstats; + struct ath_rc_stats rcstats[RATE_TABLE_SIZE]; }; #define ATH_TX_INFO_FRAME_TYPE_INTERNAL (1 << 0) -- cgit v0.10.2 From 4e9900180eb72b3b22fc9742999045b11607eb24 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 13 Oct 2010 16:43:27 +0200 Subject: ath9k: remove sc->cur_rate_table and sc->cur_rate_mode Set the rate table in the rc module properly based on band and HT capabilities instead, which was already partially done, but not for every mode. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 4e81fe3..e435c1d 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -623,8 +623,6 @@ struct ath_softc { struct ath_rx rx; struct ath_tx tx; struct ath_beacon beacon; - const struct ath_rate_table *cur_rate_table; - enum wireless_mode cur_rate_mode; struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; struct ath_led radio_led; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 2c7f28e..3ff0e47 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -18,36 +18,6 @@ #include "ath9k.h" #include "btcoex.h" -static void ath_cache_conf_rate(struct ath_softc *sc, - struct ieee80211_conf *conf) -{ - switch (conf->channel->band) { - case IEEE80211_BAND_2GHZ: - if (conf_is_ht20(conf)) - sc->cur_rate_mode = ATH9K_MODE_11NG_HT20; - else if (conf_is_ht40_minus(conf)) - sc->cur_rate_mode = ATH9K_MODE_11NG_HT40MINUS; - else if (conf_is_ht40_plus(conf)) - sc->cur_rate_mode = ATH9K_MODE_11NG_HT40PLUS; - else - sc->cur_rate_mode = ATH9K_MODE_11G; - break; - case IEEE80211_BAND_5GHZ: - if (conf_is_ht20(conf)) - sc->cur_rate_mode = ATH9K_MODE_11NA_HT20; - else if (conf_is_ht40_minus(conf)) - sc->cur_rate_mode = ATH9K_MODE_11NA_HT40MINUS; - else if (conf_is_ht40_plus(conf)) - sc->cur_rate_mode = ATH9K_MODE_11NA_HT40PLUS; - else - sc->cur_rate_mode = ATH9K_MODE_11A; - break; - default: - BUG_ON(1); - break; - } -} - static void ath_update_txpow(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; @@ -306,7 +276,6 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, goto ps_restore; } - ath_cache_conf_rate(sc, &hw->conf); ath_update_txpow(sc); ath9k_hw_set_interrupts(ah, ah->imask); @@ -1013,8 +982,6 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) * that changes the channel so update any state that * might change as a result. */ - ath_cache_conf_rate(sc, &hw->conf); - ath_update_txpow(sc); if ((sc->sc_flags & SC_OP_BEACONS) || !(sc->sc_flags & (SC_OP_OFFCHANNEL))) @@ -1221,8 +1188,6 @@ static int ath9k_start(struct ieee80211_hw *hw) if (ah->caps.hw_caps & ATH9K_HW_CAP_HT) ah->imask |= ATH9K_INT_CST; - ath_cache_conf_rate(sc, &hw->conf); - sc->sc_flags &= ~SC_OP_INVALID; /* Disable BMISS interrupt when we're not associated */ diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 5db3a12..2d3a67f 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -791,7 +791,7 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, */ try_per_rate = 4; - rate_table = sc->cur_rate_table; + rate_table = ath_rc_priv->rate_table; rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table, &is_probe); /* @@ -1048,7 +1048,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, int rate; u8 last_per; bool state_change = false; - const struct ath_rate_table *rate_table = sc->cur_rate_table; + const struct ath_rate_table *rate_table = ath_rc_priv->rate_table; int size = ath_rc_priv->rate_table_size; if ((tx_rate < 0) || (tx_rate > rate_table->rate_cnt)) @@ -1150,7 +1150,7 @@ static void ath_rc_tx_status(struct ath_softc *sc, u8 flags; u32 i = 0, rix; - rate_table = sc->cur_rate_table; + rate_table = ath_rc_priv->rate_table; /* * If the first rate is not the final index, there @@ -1231,7 +1231,6 @@ struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc, ath_print(common, ATH_DBG_CONFIG, "Choosing rate table for mode: %d\n", mode); - sc->cur_rate_mode = mode; return hw_rate_table[mode]; } @@ -1303,7 +1302,6 @@ static void ath_rc_init(struct ath_softc *sc, ath_rc_priv->max_valid_rate = k; ath_rc_sort_validrates(rate_table, ath_rc_priv); ath_rc_priv->rate_max_phy = ath_rc_priv->valid_rate_index[k-4]; - sc->cur_rate_table = rate_table; ath_rc_priv->rate_table = rate_table; ath_print(common, ATH_DBG_CONFIG, @@ -1439,8 +1437,9 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, } } - ath_debug_stat_rc(ath_rc_priv, ath_rc_get_rateindex(sc->cur_rate_table, - &tx_info->status.rates[final_ts_idx])); + ath_debug_stat_rc(ath_rc_priv, + ath_rc_get_rateindex(ath_rc_priv->rate_table, + &tx_info->status.rates[final_ts_idx])); } static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, @@ -1480,14 +1479,8 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, /* Choose rate table first */ - if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) || - (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT) || - (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC)) { - rate_table = ath_choose_rate_table(sc, sband->band, - sta->ht_cap.ht_supported, is_cw40); - } else { - rate_table = hw_rate_table[sc->cur_rate_mode]; - } + rate_table = ath_choose_rate_table(sc, sband->band, + sta->ht_cap.ht_supported, is_cw40); ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta, is_cw40, is_sgi); ath_rc_init(sc, priv_sta, sband, sta, rate_table); @@ -1536,7 +1529,6 @@ static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband, ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG, "Operating HT Bandwidth changed to: %d\n", sc->hw->conf.channel_type); - sc->cur_rate_table = hw_rate_table[sc->cur_rate_mode]; } } } -- cgit v0.10.2 From d4659912b557e9f68c0ad8be14e2cafd3210dd16 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 14 Oct 2010 16:02:39 +0200 Subject: ath9k_hw: remove enum wireless_mode and its users The wireless mode bitfield was only used to detect 2.4 and 5 GHz support, which can be simplified by using ATH9K_HW_CAP_* capabilities. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index bbb54bc..3d7b97f 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -566,7 +566,7 @@ static void ath9k_init_crypto(struct ath9k_htc_priv *priv) static void ath9k_init_channels_rates(struct ath9k_htc_priv *priv) { - if (test_bit(ATH9K_MODE_11G, priv->ah->caps.wireless_modes)) { + if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) { priv->sbands[IEEE80211_BAND_2GHZ].channels = ath9k_2ghz_channels; priv->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; @@ -577,7 +577,7 @@ static void ath9k_init_channels_rates(struct ath9k_htc_priv *priv) ARRAY_SIZE(ath9k_legacy_rates); } - if (test_bit(ATH9K_MODE_11A, priv->ah->caps.wireless_modes)) { + if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) { priv->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_channels; priv->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; priv->sbands[IEEE80211_BAND_5GHZ].n_channels = @@ -740,18 +740,18 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, hw->extra_tx_headroom = sizeof(struct tx_frame_hdr) + sizeof(struct htc_frame_hdr) + 4; - if (test_bit(ATH9K_MODE_11G, priv->ah->caps.wireless_modes)) + if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->sbands[IEEE80211_BAND_2GHZ]; - if (test_bit(ATH9K_MODE_11A, priv->ah->caps.wireless_modes)) + if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &priv->sbands[IEEE80211_BAND_5GHZ]; if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_HT) { - if (test_bit(ATH9K_MODE_11G, priv->ah->caps.wireless_modes)) + if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) setup_ht_cap(priv, &priv->sbands[IEEE80211_BAND_2GHZ].ht_cap); - if (test_bit(ATH9K_MODE_11A, priv->ah->caps.wireless_modes)) + if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) setup_ht_cap(priv, &priv->sbands[IEEE80211_BAND_5GHZ].ht_cap); } diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index f5d7917..cc13ee1 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1800,37 +1800,11 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) return -EINVAL; } - bitmap_zero(pCap->wireless_modes, ATH9K_MODE_MAX); - - if (eeval & AR5416_OPFLAGS_11A) { - set_bit(ATH9K_MODE_11A, pCap->wireless_modes); - if (ah->config.ht_enable) { - if (!(eeval & AR5416_OPFLAGS_N_5G_HT20)) - set_bit(ATH9K_MODE_11NA_HT20, - pCap->wireless_modes); - if (!(eeval & AR5416_OPFLAGS_N_5G_HT40)) { - set_bit(ATH9K_MODE_11NA_HT40PLUS, - pCap->wireless_modes); - set_bit(ATH9K_MODE_11NA_HT40MINUS, - pCap->wireless_modes); - } - } - } + if (eeval & AR5416_OPFLAGS_11A) + pCap->hw_caps |= ATH9K_HW_CAP_5GHZ; - if (eeval & AR5416_OPFLAGS_11G) { - set_bit(ATH9K_MODE_11G, pCap->wireless_modes); - if (ah->config.ht_enable) { - if (!(eeval & AR5416_OPFLAGS_N_2G_HT20)) - set_bit(ATH9K_MODE_11NG_HT20, - pCap->wireless_modes); - if (!(eeval & AR5416_OPFLAGS_N_2G_HT40)) { - set_bit(ATH9K_MODE_11NG_HT40PLUS, - pCap->wireless_modes); - set_bit(ATH9K_MODE_11NG_HT40MINUS, - pCap->wireless_modes); - } - } - } + if (eeval & AR5416_OPFLAGS_11G) + pCap->hw_caps |= ATH9K_HW_CAP_2GHZ; pCap->tx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_TX_MASK); /* diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 6b92334..d032939 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -164,18 +164,6 @@ enum ath_ini_subsys { ATH_INI_NUM_SPLIT, }; -enum wireless_mode { - ATH9K_MODE_11A = 0, - ATH9K_MODE_11G, - ATH9K_MODE_11NA_HT20, - ATH9K_MODE_11NG_HT20, - ATH9K_MODE_11NA_HT40PLUS, - ATH9K_MODE_11NA_HT40MINUS, - ATH9K_MODE_11NG_HT40PLUS, - ATH9K_MODE_11NG_HT40MINUS, - ATH9K_MODE_MAX, -}; - enum ath9k_hw_caps { ATH9K_HW_CAP_HT = BIT(0), ATH9K_HW_CAP_RFSILENT = BIT(1), @@ -190,11 +178,12 @@ enum ath9k_hw_caps { ATH9K_HW_CAP_SGI_20 = BIT(10), ATH9K_HW_CAP_PAPRD = BIT(11), ATH9K_HW_CAP_ANT_DIV_COMB = BIT(12), + ATH9K_HW_CAP_2GHZ = BIT(13), + ATH9K_HW_CAP_5GHZ = BIT(14), }; struct ath9k_hw_capabilities { u32 hw_caps; /* ATH9K_HW_CAP_* from ath9k_hw_caps */ - DECLARE_BITMAP(wireless_modes, ATH9K_MODE_MAX); /* ATH9K_MODE_* */ u16 total_queues; u16 keycache_size; u16 low_5ghz_chan, high_5ghz_chan; diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index a4c5ed4..bc6c4df 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -485,7 +485,7 @@ static int ath9k_init_channels_rates(struct ath_softc *sc) ARRAY_SIZE(ath9k_5ghz_chantable) != ATH9K_NUM_CHANNELS); - if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes)) { + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) { channels = kmemdup(ath9k_2ghz_chantable, sizeof(ath9k_2ghz_chantable), GFP_KERNEL); if (!channels) @@ -500,7 +500,7 @@ static int ath9k_init_channels_rates(struct ath_softc *sc) ARRAY_SIZE(ath9k_legacy_rates); } - if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) { + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) { channels = kmemdup(ath9k_5ghz_chantable, sizeof(ath9k_5ghz_chantable), GFP_KERNEL); if (!channels) { @@ -681,17 +681,17 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) hw->rate_control_algorithm = "ath9k_rate_control"; #endif - if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes)) + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &sc->sbands[IEEE80211_BAND_2GHZ]; - if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &sc->sbands[IEEE80211_BAND_5GHZ]; if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { - if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes)) + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); - if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap); } diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 2d3a67f..0cee90c 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -378,17 +378,6 @@ static const struct ath_rate_table ar5416_11g_ratetable = { 0, /* Phy rates allowed initially */ }; -static const struct ath_rate_table *hw_rate_table[ATH9K_MODE_MAX] = { - [ATH9K_MODE_11A] = &ar5416_11a_ratetable, - [ATH9K_MODE_11G] = &ar5416_11g_ratetable, - [ATH9K_MODE_11NA_HT20] = &ar5416_11na_ratetable, - [ATH9K_MODE_11NG_HT20] = &ar5416_11ng_ratetable, - [ATH9K_MODE_11NA_HT40PLUS] = &ar5416_11na_ratetable, - [ATH9K_MODE_11NA_HT40MINUS] = &ar5416_11na_ratetable, - [ATH9K_MODE_11NG_HT40PLUS] = &ar5416_11ng_ratetable, - [ATH9K_MODE_11NG_HT40MINUS] = &ar5416_11ng_ratetable, -}; - static int ath_rc_get_rateindex(const struct ath_rate_table *rate_table, struct ieee80211_tx_rate *rate); @@ -1200,38 +1189,23 @@ static void ath_rc_tx_status(struct ath_softc *sc, static const struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc, enum ieee80211_band band, - bool is_ht, - bool is_cw_40) + bool is_ht) { - int mode = 0; struct ath_common *common = ath9k_hw_common(sc->sc_ah); switch(band) { case IEEE80211_BAND_2GHZ: - mode = ATH9K_MODE_11G; if (is_ht) - mode = ATH9K_MODE_11NG_HT20; - if (is_cw_40) - mode = ATH9K_MODE_11NG_HT40PLUS; - break; + return &ar5416_11ng_ratetable; + return &ar5416_11g_ratetable; case IEEE80211_BAND_5GHZ: - mode = ATH9K_MODE_11A; if (is_ht) - mode = ATH9K_MODE_11NA_HT20; - if (is_cw_40) - mode = ATH9K_MODE_11NA_HT40PLUS; - break; + return &ar5416_11na_ratetable; + return &ar5416_11a_ratetable; default: ath_print(common, ATH_DBG_CONFIG, "Invalid band\n"); return NULL; } - - BUG_ON(mode >= ATH9K_MODE_MAX); - - ath_print(common, ATH_DBG_CONFIG, - "Choosing rate table for mode: %d\n", mode); - - return hw_rate_table[mode]; } static void ath_rc_init(struct ath_softc *sc, @@ -1480,7 +1454,7 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, /* Choose rate table first */ rate_table = ath_choose_rate_table(sc, sband->band, - sta->ht_cap.ht_supported, is_cw40); + sta->ht_cap.ht_supported); ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta, is_cw40, is_sgi); ath_rc_init(sc, priv_sta, sband, sta, rate_table); @@ -1520,8 +1494,7 @@ static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband, if ((local_cw40 != oper_cw40) || (local_sgi != oper_sgi)) { rate_table = ath_choose_rate_table(sc, sband->band, - sta->ht_cap.ht_supported, - oper_cw40); + sta->ht_cap.ht_supported); ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta, oper_cw40, oper_sgi); ath_rc_init(sc, priv_sta, sband, sta, rate_table); -- cgit v0.10.2 From 4f329c043ba3495f0f97ec782948cbba7bd01047 Mon Sep 17 00:00:00 2001 From: Paul Fox Date: Wed, 13 Oct 2010 20:14:56 +0100 Subject: libertas: Communicate USB transfer errors The return code was being overwritten with -1. Useful for debugging. Signed-off-by: Paul Fox Signed-off-by: Daniel Drake Acked-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index 238de10..b70f0f4 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -484,11 +484,12 @@ static int if_usb_reset_device(struct if_usb_card *cardp) */ static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, uint16_t nb) { - int ret = -1; + int ret; /* check if device is removed */ if (cardp->surprise_removed) { lbs_deb_usbd(&cardp->udev->dev, "Device removed\n"); + ret = -ENODEV; goto tx_ret; } @@ -501,7 +502,6 @@ static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, uint16_t nb if ((ret = usb_submit_urb(cardp->tx_urb, GFP_ATOMIC))) { lbs_deb_usbd(&cardp->udev->dev, "usb_submit_urb failed: %d\n", ret); - ret = -1; } else { lbs_deb_usb2(&cardp->udev->dev, "usb_submit_urb success\n"); ret = 0; -- cgit v0.10.2 From 94a40c0c6bcc47ceba12e0247c5a23fb1e6c81e4 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Thu, 14 Oct 2010 10:50:26 +0530 Subject: ath9k_htc: set probe request rx filter This patch enables to receive probe request frames on p2p client mode. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index f12591f..55c8086 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1454,6 +1454,7 @@ out: FIF_PSPOLL | \ FIF_OTHER_BSS | \ FIF_BCN_PRBRESP_PROMISC | \ + FIF_PROBE_REQ | \ FIF_FCSFAIL) static void ath9k_htc_configure_filter(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index c99600a..3d19b5b 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -369,8 +369,7 @@ u32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv) | ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST | ATH9K_RX_FILTER_MCAST; - /* If not a STA, enable processing of Probe Requests */ - if (ah->opmode != NL80211_IFTYPE_STATION) + if (priv->rxfilter & FIF_PROBE_REQ) rfilt |= ATH9K_RX_FILTER_PROBEREQ; /* -- cgit v0.10.2 From 9ebad4ab87f2ffa6eca825327721e647c7457264 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 14 Oct 2010 13:41:35 +0200 Subject: radiotap: fix vendor namespace parsing There's a bug with radiotap vendor namespace parsing if you don't register for the given namespace extensions. Fix this by passing only the unknown vendor namespaces and the registered data to frontends, but not both. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/radiotap.c b/net/wireless/radiotap.c index c774bc0..dbe35e1 100644 --- a/net/wireless/radiotap.c +++ b/net/wireless/radiotap.c @@ -201,7 +201,7 @@ int ieee80211_radiotap_iterator_next( { while (1) { int hit = 0; - int pad, align, size, subns, vnslen; + int pad, align, size, subns; uint32_t oui; /* if no more EXT bits, that's it */ @@ -261,6 +261,27 @@ int ieee80211_radiotap_iterator_next( if (pad) iterator->_arg += align - pad; + if (iterator->_arg_index % 32 == IEEE80211_RADIOTAP_VENDOR_NAMESPACE) { + int vnslen; + + if ((unsigned long)iterator->_arg + size - + (unsigned long)iterator->_rtheader > + (unsigned long)iterator->_max_length) + return -EINVAL; + + oui = (*iterator->_arg << 16) | + (*(iterator->_arg + 1) << 8) | + *(iterator->_arg + 2); + subns = *(iterator->_arg + 3); + + find_ns(iterator, oui, subns); + + vnslen = get_unaligned_le16(iterator->_arg + 4); + iterator->_next_ns_data = iterator->_arg + size + vnslen; + if (!iterator->current_namespace) + size += vnslen; + } + /* * this is what we will return to user, but we need to * move on first so next call has something fresh to test @@ -287,40 +308,25 @@ int ieee80211_radiotap_iterator_next( /* these special ones are valid in each bitmap word */ switch (iterator->_arg_index % 32) { case IEEE80211_RADIOTAP_VENDOR_NAMESPACE: - iterator->_bitmap_shifter >>= 1; - iterator->_arg_index++; - iterator->_reset_on_ext = 1; - vnslen = get_unaligned_le16(iterator->this_arg + 4); - iterator->_next_ns_data = iterator->_arg + vnslen; - oui = (*iterator->this_arg << 16) | - (*(iterator->this_arg + 1) << 8) | - *(iterator->this_arg + 2); - subns = *(iterator->this_arg + 3); - - find_ns(iterator, oui, subns); - iterator->is_radiotap_ns = 0; - /* allow parsers to show this information */ + /* + * If parser didn't register this vendor + * namespace with us, allow it to show it + * as 'raw. Do do that, set argument index + * to vendor namespace. + */ iterator->this_arg_index = IEEE80211_RADIOTAP_VENDOR_NAMESPACE; - iterator->this_arg_size += vnslen; - if ((unsigned long)iterator->this_arg + - iterator->this_arg_size - - (unsigned long)iterator->_rtheader > - (unsigned long)(unsigned long)iterator->_max_length) - return -EINVAL; - hit = 1; - break; + if (!iterator->current_namespace) + hit = 1; + goto next_entry; case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE: - iterator->_bitmap_shifter >>= 1; - iterator->_arg_index++; - iterator->_reset_on_ext = 1; iterator->current_namespace = &radiotap_ns; iterator->is_radiotap_ns = 1; - break; + goto next_entry; case IEEE80211_RADIOTAP_EXT: /* * bit 31 was set, there is more -- cgit v0.10.2 From 204a665ba390bca861ad7b1a061f3ccded0e7eab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 14 Oct 2010 19:33:34 +0200 Subject: b43: N-PHY: replace N-specific radio_chanspec with common code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h index 6dcd033..0e61942 100644 --- a/drivers/net/wireless/b43/phy_common.h +++ b/drivers/net/wireless/b43/phy_common.h @@ -253,6 +253,7 @@ struct b43_phy { /* Current channel */ unsigned int channel; + u16 channel_freq; enum nl80211_channel_type channel_type; /* PHY TX errors counter. */ diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index e532901..3ade019 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -81,21 +81,6 @@ static inline bool b43_channel_type_is_40mhz( channel_type == NL80211_CHAN_HT40PLUS); } -static inline bool b43_empty_chanspec(struct b43_chanspec *chanspec) -{ - return !chanspec->channel && !chanspec->sideband && - !chanspec->b_width && !chanspec->b_freq; -} - -static inline bool b43_eq_chanspecs(struct b43_chanspec *chanspec1, - struct b43_chanspec *chanspec2) -{ - return (chanspec1->channel == chanspec2->channel && - chanspec1->sideband == chanspec2->sideband && - chanspec1->b_width == chanspec2->b_width && - chanspec1->b_freq == chanspec2->b_freq); -} - void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna) {//TODO } @@ -788,7 +773,7 @@ static void b43_nphy_spur_workaround(struct b43_wldev *dev) { struct b43_phy_n *nphy = dev->phy.n; - u8 channel = nphy->radio_chanspec.channel; + u8 channel = dev->phy.channel; int tone[2] = { 57, 58 }; u32 noise[2] = { 0x3FF, 0x3FF }; @@ -862,9 +847,9 @@ static void b43_nphy_adjust_lna_gain_table(struct b43_wldev *dev) gain[0] = 6; gain[1] = 6; } else { - tmp = 40370 - 315 * nphy->radio_chanspec.channel; + tmp = 40370 - 315 * dev->phy.channel; gain[0] = ((tmp >> 13) + ((tmp >> 12) & 1)); - tmp = 23242 - 224 * nphy->radio_chanspec.channel; + tmp = 23242 - 224 * dev->phy.channel; gain[1] = ((tmp >> 13) + ((tmp >> 12) & 1)); } } else { @@ -2090,12 +2075,12 @@ static void b43_nphy_restore_rssi_cal(struct b43_wldev *dev) u16 *rssical_phy_regs = NULL; if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { - if (b43_empty_chanspec(&nphy->rssical_chanspec_2G)) + if (!nphy->rssical_chanspec_2G.center_freq) return; rssical_radio_regs = nphy->rssical_cache.rssical_radio_regs_2G; rssical_phy_regs = nphy->rssical_cache.rssical_phy_regs_2G; } else { - if (b43_empty_chanspec(&nphy->rssical_chanspec_5G)) + if (!nphy->rssical_chanspec_5G.center_freq) return; rssical_radio_regs = nphy->rssical_cache.rssical_radio_regs_5G; rssical_phy_regs = nphy->rssical_cache.rssical_phy_regs_5G; @@ -2551,7 +2536,8 @@ static void b43_nphy_save_cal(struct b43_wldev *dev) txcal_radio_regs[2] = b43_radio_read(dev, 0x8D); txcal_radio_regs[3] = b43_radio_read(dev, 0xBC); } - *iqcal_chanspec = nphy->radio_chanspec; + iqcal_chanspec->center_freq = dev->phy.channel_freq; + iqcal_chanspec->channel_type = dev->phy.channel_type; b43_ntab_write_bulk(dev, B43_NTAB16(15, 80), 8, table); if (nphy->hang_avoid) @@ -2572,12 +2558,12 @@ static void b43_nphy_restore_cal(struct b43_wldev *dev) struct b43_phy_n_iq_comp *rxcal_coeffs = NULL; if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { - if (b43_empty_chanspec(&nphy->iqcal_chanspec_2G)) + if (!nphy->iqcal_chanspec_2G.center_freq) return; table = nphy->cal_cache.txcal_coeffs_2G; loft = &nphy->cal_cache.txcal_coeffs_2G[5]; } else { - if (b43_empty_chanspec(&nphy->iqcal_chanspec_5G)) + if (!nphy->iqcal_chanspec_5G.center_freq) return; table = nphy->cal_cache.txcal_coeffs_5G; loft = &nphy->cal_cache.txcal_coeffs_5G[5]; @@ -2822,7 +2808,10 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, b43_ntab_read_bulk(dev, B43_NTAB16(15, 96), length, nphy->txiqlocal_bestc); nphy->txiqlocal_coeffsvalid = true; - nphy->txiqlocal_chanspec = nphy->radio_chanspec; + nphy->txiqlocal_chanspec.center_freq = + dev->phy.channel_freq; + nphy->txiqlocal_chanspec.channel_type = + dev->phy.channel_type; } else { length = 11; if (dev->phy.rev < 3) @@ -2858,7 +2847,8 @@ static void b43_nphy_reapply_tx_cal_coeffs(struct b43_wldev *dev) bool equal = true; if (!nphy->txiqlocal_coeffsvalid || - b43_eq_chanspecs(&nphy->txiqlocal_chanspec, &nphy->radio_chanspec)) + nphy->txiqlocal_chanspec.center_freq != dev->phy.channel_freq || + nphy->txiqlocal_chanspec.channel_type != dev->phy.channel_type) return; b43_ntab_read_bulk(dev, B43_NTAB16(15, 80), 7, buffer); @@ -3264,11 +3254,9 @@ int b43_phy_initn(struct b43_wldev *dev) do_rssi_cal = false; if (phy->rev >= 3) { if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) - do_rssi_cal = - b43_empty_chanspec(&nphy->rssical_chanspec_2G); + do_rssi_cal = !nphy->rssical_chanspec_2G.center_freq; else - do_rssi_cal = - b43_empty_chanspec(&nphy->rssical_chanspec_5G); + do_rssi_cal = !nphy->rssical_chanspec_5G.center_freq; if (do_rssi_cal) b43_nphy_rssi_cal(dev); @@ -3280,9 +3268,9 @@ int b43_phy_initn(struct b43_wldev *dev) if (!((nphy->measure_hold & 0x6) != 0)) { if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) - do_cal = b43_empty_chanspec(&nphy->iqcal_chanspec_2G); + do_cal = !nphy->iqcal_chanspec_2G.center_freq; else - do_cal = b43_empty_chanspec(&nphy->iqcal_chanspec_5G); + do_cal = !nphy->iqcal_chanspec_5G.center_freq; if (nphy->mute) do_cal = false; @@ -3411,7 +3399,10 @@ static int b43_nphy_set_channel(struct b43_wldev *dev, return -ESRCH; } - nphy->radio_chanspec.channel = channel->hw_value; + /* Channel is set later in common code, but we need to set it on our + own to let this function's subcalls work properly. */ + phy->channel = channel->hw_value; + phy->channel_freq = channel->center_freq; if (b43_channel_type_is_40mhz(phy->channel_type) != b43_channel_type_is_40mhz(channel_type)) diff --git a/drivers/net/wireless/b43/phy_n.h b/drivers/net/wireless/b43/phy_n.h index e7acae2..f915c83 100644 --- a/drivers/net/wireless/b43/phy_n.h +++ b/drivers/net/wireless/b43/phy_n.h @@ -927,10 +927,8 @@ struct b43_wldev; struct b43_chanspec { - u8 channel; - u8 sideband; - u8 b_width; - u8 b_freq; + u16 center_freq; + enum nl80211_channel_type channel_type; }; struct b43_phy_n_iq_comp { @@ -984,7 +982,6 @@ struct b43_phy_n { u16 papd_epsilon_offset[2]; s32 preamble_override; u32 bb_mult_save; - struct b43_chanspec radio_chanspec; bool gain_boost; bool elna_gain_config; -- cgit v0.10.2 From 5818e989360b06d249cf1d88e7d4601ca70a7322 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 14 Oct 2010 19:33:35 +0200 Subject: b43: N-PHY: fix typo: read table when caching IQ LO calibration (do not write) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 3ade019..dd9cfe5 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -2538,7 +2538,7 @@ static void b43_nphy_save_cal(struct b43_wldev *dev) } iqcal_chanspec->center_freq = dev->phy.channel_freq; iqcal_chanspec->channel_type = dev->phy.channel_type; - b43_ntab_write_bulk(dev, B43_NTAB16(15, 80), 8, table); + b43_ntab_read_bulk(dev, B43_NTAB16(15, 80), 8, table); if (nphy->hang_avoid) b43_nphy_stay_in_carrier_search(dev, 0); -- cgit v0.10.2 From 6db507ff9232cc3874306f7b25b399cb2cdc1675 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 14 Oct 2010 19:33:36 +0200 Subject: b43: N-PHY: put radio-specific code in separated file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile index 5e83b6f..0398c7c 100644 --- a/drivers/net/wireless/b43/Makefile +++ b/drivers/net/wireless/b43/Makefile @@ -1,6 +1,7 @@ b43-y += main.o b43-y += tables.o b43-$(CONFIG_B43_NPHY) += tables_nphy.o +b43-$(CONFIG_B43_NPHY) += radio_2055.o b43-y += phy_common.o b43-y += phy_g.o b43-y += phy_a.o diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index dd9cfe5..284b54f 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -29,6 +29,7 @@ #include "b43.h" #include "phy_n.h" #include "tables_nphy.h" +#include "radio_2055.h" #include "main.h" struct nphy_txgains { diff --git a/drivers/net/wireless/b43/phy_n.h b/drivers/net/wireless/b43/phy_n.h index f915c83..c144e59 100644 --- a/drivers/net/wireless/b43/phy_n.h +++ b/drivers/net/wireless/b43/phy_n.h @@ -714,216 +714,6 @@ #define B43_PHY_B_BBCFG B43_PHY_N_BMODE(0x001) /* BB config */ #define B43_PHY_B_TEST B43_PHY_N_BMODE(0x00A) - -/* Broadcom 2055 radio registers */ - -#define B2055_GEN_SPARE 0x00 /* GEN spare */ -#define B2055_SP_PINPD 0x02 /* SP PIN PD */ -#define B2055_C1_SP_RSSI 0x03 /* SP RSSI Core 1 */ -#define B2055_C1_SP_PDMISC 0x04 /* SP PD MISC Core 1 */ -#define B2055_C2_SP_RSSI 0x05 /* SP RSSI Core 2 */ -#define B2055_C2_SP_PDMISC 0x06 /* SP PD MISC Core 2 */ -#define B2055_C1_SP_RXGC1 0x07 /* SP RX GC1 Core 1 */ -#define B2055_C1_SP_RXGC2 0x08 /* SP RX GC2 Core 1 */ -#define B2055_C2_SP_RXGC1 0x09 /* SP RX GC1 Core 2 */ -#define B2055_C2_SP_RXGC2 0x0A /* SP RX GC2 Core 2 */ -#define B2055_C1_SP_LPFBWSEL 0x0B /* SP LPF BW select Core 1 */ -#define B2055_C2_SP_LPFBWSEL 0x0C /* SP LPF BW select Core 2 */ -#define B2055_C1_SP_TXGC1 0x0D /* SP TX GC1 Core 1 */ -#define B2055_C1_SP_TXGC2 0x0E /* SP TX GC2 Core 1 */ -#define B2055_C2_SP_TXGC1 0x0F /* SP TX GC1 Core 2 */ -#define B2055_C2_SP_TXGC2 0x10 /* SP TX GC2 Core 2 */ -#define B2055_MASTER1 0x11 /* Master control 1 */ -#define B2055_MASTER2 0x12 /* Master control 2 */ -#define B2055_PD_LGEN 0x13 /* PD LGEN */ -#define B2055_PD_PLLTS 0x14 /* PD PLL TS */ -#define B2055_C1_PD_LGBUF 0x15 /* PD Core 1 LGBUF */ -#define B2055_C1_PD_TX 0x16 /* PD Core 1 TX */ -#define B2055_C1_PD_RXTX 0x17 /* PD Core 1 RXTX */ -#define B2055_C1_PD_RSSIMISC 0x18 /* PD Core 1 RSSI MISC */ -#define B2055_C2_PD_LGBUF 0x19 /* PD Core 2 LGBUF */ -#define B2055_C2_PD_TX 0x1A /* PD Core 2 TX */ -#define B2055_C2_PD_RXTX 0x1B /* PD Core 2 RXTX */ -#define B2055_C2_PD_RSSIMISC 0x1C /* PD Core 2 RSSI MISC */ -#define B2055_PWRDET_LGEN 0x1D /* PWRDET LGEN */ -#define B2055_C1_PWRDET_LGBUF 0x1E /* PWRDET LGBUF Core 1 */ -#define B2055_C1_PWRDET_RXTX 0x1F /* PWRDET RXTX Core 1 */ -#define B2055_C2_PWRDET_LGBUF 0x20 /* PWRDET LGBUF Core 2 */ -#define B2055_C2_PWRDET_RXTX 0x21 /* PWRDET RXTX Core 2 */ -#define B2055_RRCCAL_CS 0x22 /* RRCCAL Control spare */ -#define B2055_RRCCAL_NOPTSEL 0x23 /* RRCCAL N OPT SEL */ -#define B2055_CAL_MISC 0x24 /* CAL MISC */ -#define B2055_CAL_COUT 0x25 /* CAL Counter out */ -#define B2055_CAL_COUT2 0x26 /* CAL Counter out 2 */ -#define B2055_CAL_CVARCTL 0x27 /* CAL CVAR Control */ -#define B2055_CAL_RVARCTL 0x28 /* CAL RVAR Control */ -#define B2055_CAL_LPOCTL 0x29 /* CAL LPO Control */ -#define B2055_CAL_TS 0x2A /* CAL TS */ -#define B2055_CAL_RCCALRTS 0x2B /* CAL RCCAL READ TS */ -#define B2055_CAL_RCALRTS 0x2C /* CAL RCAL READ TS */ -#define B2055_PADDRV 0x2D /* PAD driver */ -#define B2055_XOCTL1 0x2E /* XO Control 1 */ -#define B2055_XOCTL2 0x2F /* XO Control 2 */ -#define B2055_XOREGUL 0x30 /* XO Regulator */ -#define B2055_XOMISC 0x31 /* XO misc */ -#define B2055_PLL_LFC1 0x32 /* PLL LF C1 */ -#define B2055_PLL_CALVTH 0x33 /* PLL CAL VTH */ -#define B2055_PLL_LFC2 0x34 /* PLL LF C2 */ -#define B2055_PLL_REF 0x35 /* PLL reference */ -#define B2055_PLL_LFR1 0x36 /* PLL LF R1 */ -#define B2055_PLL_PFDCP 0x37 /* PLL PFD CP */ -#define B2055_PLL_IDAC_CPOPAMP 0x38 /* PLL IDAC CPOPAMP */ -#define B2055_PLL_CPREG 0x39 /* PLL CP Regulator */ -#define B2055_PLL_RCAL 0x3A /* PLL RCAL */ -#define B2055_RF_PLLMOD0 0x3B /* RF PLL MOD0 */ -#define B2055_RF_PLLMOD1 0x3C /* RF PLL MOD1 */ -#define B2055_RF_MMDIDAC1 0x3D /* RF MMD IDAC 1 */ -#define B2055_RF_MMDIDAC0 0x3E /* RF MMD IDAC 0 */ -#define B2055_RF_MMDSP 0x3F /* RF MMD spare */ -#define B2055_VCO_CAL1 0x40 /* VCO cal 1 */ -#define B2055_VCO_CAL2 0x41 /* VCO cal 2 */ -#define B2055_VCO_CAL3 0x42 /* VCO cal 3 */ -#define B2055_VCO_CAL4 0x43 /* VCO cal 4 */ -#define B2055_VCO_CAL5 0x44 /* VCO cal 5 */ -#define B2055_VCO_CAL6 0x45 /* VCO cal 6 */ -#define B2055_VCO_CAL7 0x46 /* VCO cal 7 */ -#define B2055_VCO_CAL8 0x47 /* VCO cal 8 */ -#define B2055_VCO_CAL9 0x48 /* VCO cal 9 */ -#define B2055_VCO_CAL10 0x49 /* VCO cal 10 */ -#define B2055_VCO_CAL11 0x4A /* VCO cal 11 */ -#define B2055_VCO_CAL12 0x4B /* VCO cal 12 */ -#define B2055_VCO_CAL13 0x4C /* VCO cal 13 */ -#define B2055_VCO_CAL14 0x4D /* VCO cal 14 */ -#define B2055_VCO_CAL15 0x4E /* VCO cal 15 */ -#define B2055_VCO_CAL16 0x4F /* VCO cal 16 */ -#define B2055_VCO_KVCO 0x50 /* VCO KVCO */ -#define B2055_VCO_CAPTAIL 0x51 /* VCO CAP TAIL */ -#define B2055_VCO_IDACVCO 0x52 /* VCO IDAC VCO */ -#define B2055_VCO_REG 0x53 /* VCO Regulator */ -#define B2055_PLL_RFVTH 0x54 /* PLL RF VTH */ -#define B2055_LGBUF_CENBUF 0x55 /* LGBUF CEN BUF */ -#define B2055_LGEN_TUNE1 0x56 /* LGEN tune 1 */ -#define B2055_LGEN_TUNE2 0x57 /* LGEN tune 2 */ -#define B2055_LGEN_IDAC1 0x58 /* LGEN IDAC 1 */ -#define B2055_LGEN_IDAC2 0x59 /* LGEN IDAC 2 */ -#define B2055_LGEN_BIASC 0x5A /* LGEN BIAS counter */ -#define B2055_LGEN_BIASIDAC 0x5B /* LGEN BIAS IDAC */ -#define B2055_LGEN_RCAL 0x5C /* LGEN RCAL */ -#define B2055_LGEN_DIV 0x5D /* LGEN div */ -#define B2055_LGEN_SPARE2 0x5E /* LGEN spare 2 */ -#define B2055_C1_LGBUF_ATUNE 0x5F /* Core 1 LGBUF A tune */ -#define B2055_C1_LGBUF_GTUNE 0x60 /* Core 1 LGBUF G tune */ -#define B2055_C1_LGBUF_DIV 0x61 /* Core 1 LGBUF div */ -#define B2055_C1_LGBUF_AIDAC 0x62 /* Core 1 LGBUF A IDAC */ -#define B2055_C1_LGBUF_GIDAC 0x63 /* Core 1 LGBUF G IDAC */ -#define B2055_C1_LGBUF_IDACFO 0x64 /* Core 1 LGBUF IDAC filter override */ -#define B2055_C1_LGBUF_SPARE 0x65 /* Core 1 LGBUF spare */ -#define B2055_C1_RX_RFSPC1 0x66 /* Core 1 RX RF SPC1 */ -#define B2055_C1_RX_RFR1 0x67 /* Core 1 RX RF reg 1 */ -#define B2055_C1_RX_RFR2 0x68 /* Core 1 RX RF reg 2 */ -#define B2055_C1_RX_RFRCAL 0x69 /* Core 1 RX RF RCAL */ -#define B2055_C1_RX_BB_BLCMP 0x6A /* Core 1 RX Baseband BUFI LPF CMP */ -#define B2055_C1_RX_BB_LPF 0x6B /* Core 1 RX Baseband LPF */ -#define B2055_C1_RX_BB_MIDACHP 0x6C /* Core 1 RX Baseband MIDAC High-pass */ -#define B2055_C1_RX_BB_VGA1IDAC 0x6D /* Core 1 RX Baseband VGA1 IDAC */ -#define B2055_C1_RX_BB_VGA2IDAC 0x6E /* Core 1 RX Baseband VGA2 IDAC */ -#define B2055_C1_RX_BB_VGA3IDAC 0x6F /* Core 1 RX Baseband VGA3 IDAC */ -#define B2055_C1_RX_BB_BUFOCTL 0x70 /* Core 1 RX Baseband BUFO Control */ -#define B2055_C1_RX_BB_RCCALCTL 0x71 /* Core 1 RX Baseband RCCAL Control */ -#define B2055_C1_RX_BB_RSSICTL1 0x72 /* Core 1 RX Baseband RSSI Control 1 */ -#define B2055_C1_RX_BB_RSSICTL2 0x73 /* Core 1 RX Baseband RSSI Control 2 */ -#define B2055_C1_RX_BB_RSSICTL3 0x74 /* Core 1 RX Baseband RSSI Control 3 */ -#define B2055_C1_RX_BB_RSSICTL4 0x75 /* Core 1 RX Baseband RSSI Control 4 */ -#define B2055_C1_RX_BB_RSSICTL5 0x76 /* Core 1 RX Baseband RSSI Control 5 */ -#define B2055_C1_RX_BB_REG 0x77 /* Core 1 RX Baseband Regulator */ -#define B2055_C1_RX_BB_SPARE1 0x78 /* Core 1 RX Baseband spare 1 */ -#define B2055_C1_RX_TXBBRCAL 0x79 /* Core 1 RX TX BB RCAL */ -#define B2055_C1_TX_RF_SPGA 0x7A /* Core 1 TX RF SGM PGA */ -#define B2055_C1_TX_RF_SPAD 0x7B /* Core 1 TX RF SGM PAD */ -#define B2055_C1_TX_RF_CNTPGA1 0x7C /* Core 1 TX RF counter PGA 1 */ -#define B2055_C1_TX_RF_CNTPAD1 0x7D /* Core 1 TX RF counter PAD 1 */ -#define B2055_C1_TX_RF_PGAIDAC 0x7E /* Core 1 TX RF PGA IDAC */ -#define B2055_C1_TX_PGAPADTN 0x7F /* Core 1 TX PGA PAD TN */ -#define B2055_C1_TX_PADIDAC1 0x80 /* Core 1 TX PAD IDAC 1 */ -#define B2055_C1_TX_PADIDAC2 0x81 /* Core 1 TX PAD IDAC 2 */ -#define B2055_C1_TX_MXBGTRIM 0x82 /* Core 1 TX MX B/G TRIM */ -#define B2055_C1_TX_RF_RCAL 0x83 /* Core 1 TX RF RCAL */ -#define B2055_C1_TX_RF_PADTSSI1 0x84 /* Core 1 TX RF PAD TSSI1 */ -#define B2055_C1_TX_RF_PADTSSI2 0x85 /* Core 1 TX RF PAD TSSI2 */ -#define B2055_C1_TX_RF_SPARE 0x86 /* Core 1 TX RF spare */ -#define B2055_C1_TX_RF_IQCAL1 0x87 /* Core 1 TX RF I/Q CAL 1 */ -#define B2055_C1_TX_RF_IQCAL2 0x88 /* Core 1 TX RF I/Q CAL 2 */ -#define B2055_C1_TXBB_RCCAL 0x89 /* Core 1 TXBB RC CAL Control */ -#define B2055_C1_TXBB_LPF1 0x8A /* Core 1 TXBB LPF 1 */ -#define B2055_C1_TX_VOSCNCL 0x8B /* Core 1 TX VOS CNCL */ -#define B2055_C1_TX_LPF_MXGMIDAC 0x8C /* Core 1 TX LPF MXGM IDAC */ -#define B2055_C1_TX_BB_MXGM 0x8D /* Core 1 TX BB MXGM */ -#define B2055_C2_LGBUF_ATUNE 0x8E /* Core 2 LGBUF A tune */ -#define B2055_C2_LGBUF_GTUNE 0x8F /* Core 2 LGBUF G tune */ -#define B2055_C2_LGBUF_DIV 0x90 /* Core 2 LGBUF div */ -#define B2055_C2_LGBUF_AIDAC 0x91 /* Core 2 LGBUF A IDAC */ -#define B2055_C2_LGBUF_GIDAC 0x92 /* Core 2 LGBUF G IDAC */ -#define B2055_C2_LGBUF_IDACFO 0x93 /* Core 2 LGBUF IDAC filter override */ -#define B2055_C2_LGBUF_SPARE 0x94 /* Core 2 LGBUF spare */ -#define B2055_C2_RX_RFSPC1 0x95 /* Core 2 RX RF SPC1 */ -#define B2055_C2_RX_RFR1 0x96 /* Core 2 RX RF reg 1 */ -#define B2055_C2_RX_RFR2 0x97 /* Core 2 RX RF reg 2 */ -#define B2055_C2_RX_RFRCAL 0x98 /* Core 2 RX RF RCAL */ -#define B2055_C2_RX_BB_BLCMP 0x99 /* Core 2 RX Baseband BUFI LPF CMP */ -#define B2055_C2_RX_BB_LPF 0x9A /* Core 2 RX Baseband LPF */ -#define B2055_C2_RX_BB_MIDACHP 0x9B /* Core 2 RX Baseband MIDAC High-pass */ -#define B2055_C2_RX_BB_VGA1IDAC 0x9C /* Core 2 RX Baseband VGA1 IDAC */ -#define B2055_C2_RX_BB_VGA2IDAC 0x9D /* Core 2 RX Baseband VGA2 IDAC */ -#define B2055_C2_RX_BB_VGA3IDAC 0x9E /* Core 2 RX Baseband VGA3 IDAC */ -#define B2055_C2_RX_BB_BUFOCTL 0x9F /* Core 2 RX Baseband BUFO Control */ -#define B2055_C2_RX_BB_RCCALCTL 0xA0 /* Core 2 RX Baseband RCCAL Control */ -#define B2055_C2_RX_BB_RSSICTL1 0xA1 /* Core 2 RX Baseband RSSI Control 1 */ -#define B2055_C2_RX_BB_RSSICTL2 0xA2 /* Core 2 RX Baseband RSSI Control 2 */ -#define B2055_C2_RX_BB_RSSICTL3 0xA3 /* Core 2 RX Baseband RSSI Control 3 */ -#define B2055_C2_RX_BB_RSSICTL4 0xA4 /* Core 2 RX Baseband RSSI Control 4 */ -#define B2055_C2_RX_BB_RSSICTL5 0xA5 /* Core 2 RX Baseband RSSI Control 5 */ -#define B2055_C2_RX_BB_REG 0xA6 /* Core 2 RX Baseband Regulator */ -#define B2055_C2_RX_BB_SPARE1 0xA7 /* Core 2 RX Baseband spare 1 */ -#define B2055_C2_RX_TXBBRCAL 0xA8 /* Core 2 RX TX BB RCAL */ -#define B2055_C2_TX_RF_SPGA 0xA9 /* Core 2 TX RF SGM PGA */ -#define B2055_C2_TX_RF_SPAD 0xAA /* Core 2 TX RF SGM PAD */ -#define B2055_C2_TX_RF_CNTPGA1 0xAB /* Core 2 TX RF counter PGA 1 */ -#define B2055_C2_TX_RF_CNTPAD1 0xAC /* Core 2 TX RF counter PAD 1 */ -#define B2055_C2_TX_RF_PGAIDAC 0xAD /* Core 2 TX RF PGA IDAC */ -#define B2055_C2_TX_PGAPADTN 0xAE /* Core 2 TX PGA PAD TN */ -#define B2055_C2_TX_PADIDAC1 0xAF /* Core 2 TX PAD IDAC 1 */ -#define B2055_C2_TX_PADIDAC2 0xB0 /* Core 2 TX PAD IDAC 2 */ -#define B2055_C2_TX_MXBGTRIM 0xB1 /* Core 2 TX MX B/G TRIM */ -#define B2055_C2_TX_RF_RCAL 0xB2 /* Core 2 TX RF RCAL */ -#define B2055_C2_TX_RF_PADTSSI1 0xB3 /* Core 2 TX RF PAD TSSI1 */ -#define B2055_C2_TX_RF_PADTSSI2 0xB4 /* Core 2 TX RF PAD TSSI2 */ -#define B2055_C2_TX_RF_SPARE 0xB5 /* Core 2 TX RF spare */ -#define B2055_C2_TX_RF_IQCAL1 0xB6 /* Core 2 TX RF I/Q CAL 1 */ -#define B2055_C2_TX_RF_IQCAL2 0xB7 /* Core 2 TX RF I/Q CAL 2 */ -#define B2055_C2_TXBB_RCCAL 0xB8 /* Core 2 TXBB RC CAL Control */ -#define B2055_C2_TXBB_LPF1 0xB9 /* Core 2 TXBB LPF 1 */ -#define B2055_C2_TX_VOSCNCL 0xBA /* Core 2 TX VOS CNCL */ -#define B2055_C2_TX_LPF_MXGMIDAC 0xBB /* Core 2 TX LPF MXGM IDAC */ -#define B2055_C2_TX_BB_MXGM 0xBC /* Core 2 TX BB MXGM */ -#define B2055_PRG_GCHP21 0xBD /* PRG GC HPVGA23 21 */ -#define B2055_PRG_GCHP22 0xBE /* PRG GC HPVGA23 22 */ -#define B2055_PRG_GCHP23 0xBF /* PRG GC HPVGA23 23 */ -#define B2055_PRG_GCHP24 0xC0 /* PRG GC HPVGA23 24 */ -#define B2055_PRG_GCHP25 0xC1 /* PRG GC HPVGA23 25 */ -#define B2055_PRG_GCHP26 0xC2 /* PRG GC HPVGA23 26 */ -#define B2055_PRG_GCHP27 0xC3 /* PRG GC HPVGA23 27 */ -#define B2055_PRG_GCHP28 0xC4 /* PRG GC HPVGA23 28 */ -#define B2055_PRG_GCHP29 0xC5 /* PRG GC HPVGA23 29 */ -#define B2055_PRG_GCHP30 0xC6 /* PRG GC HPVGA23 30 */ -#define B2055_C1_LNA_GAINBST 0xCD /* Core 1 LNA GAINBST */ -#define B2055_C1_B0NB_RSSIVCM 0xD2 /* Core 1 B0 narrow-band RSSI VCM */ -#define B2055_C1_GENSPARE2 0xD6 /* Core 1 GEN spare 2 */ -#define B2055_C2_LNA_GAINBST 0xD9 /* Core 2 LNA GAINBST */ -#define B2055_C2_B0NB_RSSIVCM 0xDE /* Core 2 B0 narrow-band RSSI VCM */ -#define B2055_C2_GENSPARE2 0xE2 /* Core 2 GEN spare 2 */ - - - struct b43_wldev; struct b43_chanspec { diff --git a/drivers/net/wireless/b43/radio_2055.c b/drivers/net/wireless/b43/radio_2055.c new file mode 100644 index 0000000..1b53165 --- /dev/null +++ b/drivers/net/wireless/b43/radio_2055.c @@ -0,0 +1,1332 @@ +/* + + Broadcom B43 wireless driver + IEEE 802.11n PHY and radio device data tables + + Copyright (c) 2008 Michael Buesch + + This program 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 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "b43.h" +#include "radio_2055.h" +#include "phy_common.h" + +struct b2055_inittab_entry { + /* Value to write if we use the 5GHz band. */ + u16 ghz5; + /* Value to write if we use the 2.4GHz band. */ + u16 ghz2; + /* Flags */ + u8 flags; +#define B2055_INITTAB_ENTRY_OK 0x01 +#define B2055_INITTAB_UPLOAD 0x02 +}; +#define UPLOAD .flags = B2055_INITTAB_ENTRY_OK | B2055_INITTAB_UPLOAD +#define NOUPLOAD .flags = B2055_INITTAB_ENTRY_OK + +static const struct b2055_inittab_entry b2055_inittab [] = { + [B2055_SP_PINPD] = { .ghz5 = 0x0080, .ghz2 = 0x0080, NOUPLOAD, }, + [B2055_C1_SP_RSSI] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C1_SP_PDMISC] = { .ghz5 = 0x0027, .ghz2 = 0x0027, NOUPLOAD, }, + [B2055_C2_SP_RSSI] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C2_SP_PDMISC] = { .ghz5 = 0x0027, .ghz2 = 0x0027, NOUPLOAD, }, + [B2055_C1_SP_RXGC1] = { .ghz5 = 0x007F, .ghz2 = 0x007F, UPLOAD, }, + [B2055_C1_SP_RXGC2] = { .ghz5 = 0x0007, .ghz2 = 0x0007, UPLOAD, }, + [B2055_C2_SP_RXGC1] = { .ghz5 = 0x007F, .ghz2 = 0x007F, UPLOAD, }, + [B2055_C2_SP_RXGC2] = { .ghz5 = 0x0007, .ghz2 = 0x0007, UPLOAD, }, + [B2055_C1_SP_LPFBWSEL] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, }, + [B2055_C2_SP_LPFBWSEL] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, }, + [B2055_C1_SP_TXGC1] = { .ghz5 = 0x004F, .ghz2 = 0x004F, UPLOAD, }, + [B2055_C1_SP_TXGC2] = { .ghz5 = 0x0005, .ghz2 = 0x0005, UPLOAD, }, + [B2055_C2_SP_TXGC1] = { .ghz5 = 0x004F, .ghz2 = 0x004F, UPLOAD, }, + [B2055_C2_SP_TXGC2] = { .ghz5 = 0x0005, .ghz2 = 0x0005, UPLOAD, }, + [B2055_MASTER1] = { .ghz5 = 0x00D0, .ghz2 = 0x00D0, NOUPLOAD, }, + [B2055_MASTER2] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, }, + [B2055_PD_LGEN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_PD_PLLTS] = { .ghz5 = 0x0040, .ghz2 = 0x0040, NOUPLOAD, }, + [B2055_C1_PD_LGBUF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C1_PD_TX] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C1_PD_RXTX] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C1_PD_RSSIMISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C2_PD_LGBUF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C2_PD_TX] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C2_PD_RXTX] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C2_PD_RSSIMISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_PWRDET_LGEN] = { .ghz5 = 0x00C0, .ghz2 = 0x00C0, NOUPLOAD, }, + [B2055_C1_PWRDET_LGBUF] = { .ghz5 = 0x00FF, .ghz2 = 0x00FF, NOUPLOAD, }, + [B2055_C1_PWRDET_RXTX] = { .ghz5 = 0x00C0, .ghz2 = 0x00C0, NOUPLOAD, }, + [B2055_C2_PWRDET_LGBUF] = { .ghz5 = 0x00FF, .ghz2 = 0x00FF, NOUPLOAD, }, + [B2055_C2_PWRDET_RXTX] = { .ghz5 = 0x00C0, .ghz2 = 0x00C0, NOUPLOAD, }, + [B2055_RRCCAL_CS] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_RRCCAL_NOPTSEL] = { .ghz5 = 0x002C, .ghz2 = 0x002C, NOUPLOAD, }, + [B2055_CAL_MISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_CAL_COUT] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_CAL_COUT2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_CAL_CVARCTL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_CAL_RVARCTL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_CAL_LPOCTL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_CAL_TS] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_CAL_RCCALRTS] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_CAL_RCALRTS] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_PADDRV] = { .ghz5 = 0x00A4, .ghz2 = 0x00A4, NOUPLOAD, }, + [B2055_XOCTL1] = { .ghz5 = 0x0038, .ghz2 = 0x0038, NOUPLOAD, }, + [B2055_XOCTL2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_XOREGUL] = { .ghz5 = 0x0004, .ghz2 = 0x0004, UPLOAD, }, + [B2055_XOMISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_PLL_LFC1] = { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, }, + [B2055_PLL_CALVTH] = { .ghz5 = 0x0087, .ghz2 = 0x0087, NOUPLOAD, }, + [B2055_PLL_LFC2] = { .ghz5 = 0x0009, .ghz2 = 0x0009, NOUPLOAD, }, + [B2055_PLL_REF] = { .ghz5 = 0x0070, .ghz2 = 0x0070, NOUPLOAD, }, + [B2055_PLL_LFR1] = { .ghz5 = 0x0011, .ghz2 = 0x0011, NOUPLOAD, }, + [B2055_PLL_PFDCP] = { .ghz5 = 0x0018, .ghz2 = 0x0018, UPLOAD, }, + [B2055_PLL_IDAC_CPOPAMP] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, + [B2055_PLL_CPREG] = { .ghz5 = 0x0004, .ghz2 = 0x0004, UPLOAD, }, + [B2055_PLL_RCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, + [B2055_RF_PLLMOD0] = { .ghz5 = 0x009E, .ghz2 = 0x009E, NOUPLOAD, }, + [B2055_RF_PLLMOD1] = { .ghz5 = 0x0009, .ghz2 = 0x0009, NOUPLOAD, }, + [B2055_RF_MMDIDAC1] = { .ghz5 = 0x00C8, .ghz2 = 0x00C8, UPLOAD, }, + [B2055_RF_MMDIDAC0] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, + [B2055_RF_MMDSP] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_VCO_CAL1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_VCO_CAL2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_VCO_CAL3] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, }, + [B2055_VCO_CAL4] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, }, + [B2055_VCO_CAL5] = { .ghz5 = 0x0096, .ghz2 = 0x0096, NOUPLOAD, }, + [B2055_VCO_CAL6] = { .ghz5 = 0x003E, .ghz2 = 0x003E, NOUPLOAD, }, + [B2055_VCO_CAL7] = { .ghz5 = 0x003E, .ghz2 = 0x003E, NOUPLOAD, }, + [B2055_VCO_CAL8] = { .ghz5 = 0x0013, .ghz2 = 0x0013, NOUPLOAD, }, + [B2055_VCO_CAL9] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, }, + [B2055_VCO_CAL10] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, }, + [B2055_VCO_CAL11] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, }, + [B2055_VCO_CAL12] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_VCO_CAL13] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_VCO_CAL14] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_VCO_CAL15] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_VCO_CAL16] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_VCO_KVCO] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, }, + [B2055_VCO_CAPTAIL] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, }, + [B2055_VCO_IDACVCO] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, + [B2055_VCO_REG] = { .ghz5 = 0x0084, .ghz2 = 0x0084, UPLOAD, }, + [B2055_PLL_RFVTH] = { .ghz5 = 0x00C3, .ghz2 = 0x00C3, NOUPLOAD, }, + [B2055_LGBUF_CENBUF] = { .ghz5 = 0x008F, .ghz2 = 0x008F, NOUPLOAD, }, + [B2055_LGEN_TUNE1] = { .ghz5 = 0x00FF, .ghz2 = 0x00FF, NOUPLOAD, }, + [B2055_LGEN_TUNE2] = { .ghz5 = 0x00FF, .ghz2 = 0x00FF, NOUPLOAD, }, + [B2055_LGEN_IDAC1] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, + [B2055_LGEN_IDAC2] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, + [B2055_LGEN_BIASC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_LGEN_BIASIDAC] = { .ghz5 = 0x00CC, .ghz2 = 0x00CC, NOUPLOAD, }, + [B2055_LGEN_RCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, + [B2055_LGEN_DIV] = { .ghz5 = 0x0080, .ghz2 = 0x0080, NOUPLOAD, }, + [B2055_LGEN_SPARE2] = { .ghz5 = 0x0080, .ghz2 = 0x0080, NOUPLOAD, }, + [B2055_C1_LGBUF_ATUNE] = { .ghz5 = 0x00F8, .ghz2 = 0x00F8, NOUPLOAD, }, + [B2055_C1_LGBUF_GTUNE] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, + [B2055_C1_LGBUF_DIV] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, + [B2055_C1_LGBUF_AIDAC] = { .ghz5 = 0x0088, .ghz2 = 0x0008, UPLOAD, }, + [B2055_C1_LGBUF_GIDAC] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, + [B2055_C1_LGBUF_IDACFO] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C1_LGBUF_SPARE] = { .ghz5 = 0x0001, .ghz2 = 0x0001, UPLOAD, }, + [B2055_C1_RX_RFSPC1] = { .ghz5 = 0x008A, .ghz2 = 0x008A, NOUPLOAD, }, + [B2055_C1_RX_RFR1] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, }, + [B2055_C1_RX_RFR2] = { .ghz5 = 0x0083, .ghz2 = 0x0083, NOUPLOAD, }, + [B2055_C1_RX_RFRCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, + [B2055_C1_RX_BB_BLCMP] = { .ghz5 = 0x00A0, .ghz2 = 0x00A0, NOUPLOAD, }, + [B2055_C1_RX_BB_LPF] = { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, }, + [B2055_C1_RX_BB_MIDACHP] = { .ghz5 = 0x0087, .ghz2 = 0x0087, UPLOAD, }, + [B2055_C1_RX_BB_VGA1IDAC] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, }, + [B2055_C1_RX_BB_VGA2IDAC] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, }, + [B2055_C1_RX_BB_VGA3IDAC] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, }, + [B2055_C1_RX_BB_BUFOCTL] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, }, + [B2055_C1_RX_BB_RCCALCTL] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, }, + [B2055_C1_RX_BB_RSSICTL1] = { .ghz5 = 0x006A, .ghz2 = 0x006A, UPLOAD, }, + [B2055_C1_RX_BB_RSSICTL2] = { .ghz5 = 0x00AB, .ghz2 = 0x00AB, UPLOAD, }, + [B2055_C1_RX_BB_RSSICTL3] = { .ghz5 = 0x0013, .ghz2 = 0x0013, UPLOAD, }, + [B2055_C1_RX_BB_RSSICTL4] = { .ghz5 = 0x00C1, .ghz2 = 0x00C1, UPLOAD, }, + [B2055_C1_RX_BB_RSSICTL5] = { .ghz5 = 0x00AA, .ghz2 = 0x00AA, UPLOAD, }, + [B2055_C1_RX_BB_REG] = { .ghz5 = 0x0087, .ghz2 = 0x0087, UPLOAD, }, + [B2055_C1_RX_BB_SPARE1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C1_RX_TXBBRCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, + [B2055_C1_TX_RF_SPGA] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, }, + [B2055_C1_TX_RF_SPAD] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, }, + [B2055_C1_TX_RF_CNTPGA1] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, }, + [B2055_C1_TX_RF_CNTPAD1] = { .ghz5 = 0x0055, .ghz2 = 0x0055, NOUPLOAD, }, + [B2055_C1_TX_RF_PGAIDAC] = { .ghz5 = 0x0097, .ghz2 = 0x0097, UPLOAD, }, + [B2055_C1_TX_PGAPADTN] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, }, + [B2055_C1_TX_PADIDAC1] = { .ghz5 = 0x0014, .ghz2 = 0x0014, UPLOAD, }, + [B2055_C1_TX_PADIDAC2] = { .ghz5 = 0x0033, .ghz2 = 0x0033, NOUPLOAD, }, + [B2055_C1_TX_MXBGTRIM] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, + [B2055_C1_TX_RF_RCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, + [B2055_C1_TX_RF_PADTSSI1] = { .ghz5 = 0x0003, .ghz2 = 0x0003, UPLOAD, }, + [B2055_C1_TX_RF_PADTSSI2] = { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, }, + [B2055_C1_TX_RF_SPARE] = { .ghz5 = 0x0003, .ghz2 = 0x0003, UPLOAD, }, + [B2055_C1_TX_RF_IQCAL1] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, }, + [B2055_C1_TX_RF_IQCAL2] = { .ghz5 = 0x00A4, .ghz2 = 0x00A4, NOUPLOAD, }, + [B2055_C1_TXBB_RCCAL] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, }, + [B2055_C1_TXBB_LPF1] = { .ghz5 = 0x0028, .ghz2 = 0x0028, NOUPLOAD, }, + [B2055_C1_TX_VOSCNCL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C1_TX_LPF_MXGMIDAC] = { .ghz5 = 0x004A, .ghz2 = 0x004A, NOUPLOAD, }, + [B2055_C1_TX_BB_MXGM] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C2_LGBUF_ATUNE] = { .ghz5 = 0x00F8, .ghz2 = 0x00F8, NOUPLOAD, }, + [B2055_C2_LGBUF_GTUNE] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, + [B2055_C2_LGBUF_DIV] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, + [B2055_C2_LGBUF_AIDAC] = { .ghz5 = 0x0088, .ghz2 = 0x0008, UPLOAD, }, + [B2055_C2_LGBUF_GIDAC] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, + [B2055_C2_LGBUF_IDACFO] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C2_LGBUF_SPARE] = { .ghz5 = 0x0001, .ghz2 = 0x0001, UPLOAD, }, + [B2055_C2_RX_RFSPC1] = { .ghz5 = 0x008A, .ghz2 = 0x008A, NOUPLOAD, }, + [B2055_C2_RX_RFR1] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, }, + [B2055_C2_RX_RFR2] = { .ghz5 = 0x0083, .ghz2 = 0x0083, NOUPLOAD, }, + [B2055_C2_RX_RFRCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, + [B2055_C2_RX_BB_BLCMP] = { .ghz5 = 0x00A0, .ghz2 = 0x00A0, NOUPLOAD, }, + [B2055_C2_RX_BB_LPF] = { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, }, + [B2055_C2_RX_BB_MIDACHP] = { .ghz5 = 0x0087, .ghz2 = 0x0087, UPLOAD, }, + [B2055_C2_RX_BB_VGA1IDAC] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, }, + [B2055_C2_RX_BB_VGA2IDAC] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, }, + [B2055_C2_RX_BB_VGA3IDAC] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, }, + [B2055_C2_RX_BB_BUFOCTL] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, }, + [B2055_C2_RX_BB_RCCALCTL] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, }, + [B2055_C2_RX_BB_RSSICTL1] = { .ghz5 = 0x006A, .ghz2 = 0x006A, UPLOAD, }, + [B2055_C2_RX_BB_RSSICTL2] = { .ghz5 = 0x00AB, .ghz2 = 0x00AB, UPLOAD, }, + [B2055_C2_RX_BB_RSSICTL3] = { .ghz5 = 0x0013, .ghz2 = 0x0013, UPLOAD, }, + [B2055_C2_RX_BB_RSSICTL4] = { .ghz5 = 0x00C1, .ghz2 = 0x00C1, UPLOAD, }, + [B2055_C2_RX_BB_RSSICTL5] = { .ghz5 = 0x00AA, .ghz2 = 0x00AA, UPLOAD, }, + [B2055_C2_RX_BB_REG] = { .ghz5 = 0x0087, .ghz2 = 0x0087, UPLOAD, }, + [B2055_C2_RX_BB_SPARE1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C2_RX_TXBBRCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, + [B2055_C2_TX_RF_SPGA] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, }, + [B2055_C2_TX_RF_SPAD] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, }, + [B2055_C2_TX_RF_CNTPGA1] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, }, + [B2055_C2_TX_RF_CNTPAD1] = { .ghz5 = 0x0055, .ghz2 = 0x0055, NOUPLOAD, }, + [B2055_C2_TX_RF_PGAIDAC] = { .ghz5 = 0x0097, .ghz2 = 0x0097, UPLOAD, }, + [B2055_C2_TX_PGAPADTN] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, }, + [B2055_C2_TX_PADIDAC1] = { .ghz5 = 0x0014, .ghz2 = 0x0014, UPLOAD, }, + [B2055_C2_TX_PADIDAC2] = { .ghz5 = 0x0033, .ghz2 = 0x0033, NOUPLOAD, }, + [B2055_C2_TX_MXBGTRIM] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, + [B2055_C2_TX_RF_RCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, + [B2055_C2_TX_RF_PADTSSI1] = { .ghz5 = 0x0003, .ghz2 = 0x0003, UPLOAD, }, + [B2055_C2_TX_RF_PADTSSI2] = { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, }, + [B2055_C2_TX_RF_SPARE] = { .ghz5 = 0x0003, .ghz2 = 0x0003, UPLOAD, }, + [B2055_C2_TX_RF_IQCAL1] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, }, + [B2055_C2_TX_RF_IQCAL2] = { .ghz5 = 0x00A4, .ghz2 = 0x00A4, NOUPLOAD, }, + [B2055_C2_TXBB_RCCAL] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, }, + [B2055_C2_TXBB_LPF1] = { .ghz5 = 0x0028, .ghz2 = 0x0028, NOUPLOAD, }, + [B2055_C2_TX_VOSCNCL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C2_TX_LPF_MXGMIDAC] = { .ghz5 = 0x004A, .ghz2 = 0x004A, NOUPLOAD, }, + [B2055_C2_TX_BB_MXGM] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_PRG_GCHP21] = { .ghz5 = 0x0071, .ghz2 = 0x0071, NOUPLOAD, }, + [B2055_PRG_GCHP22] = { .ghz5 = 0x0072, .ghz2 = 0x0072, NOUPLOAD, }, + [B2055_PRG_GCHP23] = { .ghz5 = 0x0073, .ghz2 = 0x0073, NOUPLOAD, }, + [B2055_PRG_GCHP24] = { .ghz5 = 0x0074, .ghz2 = 0x0074, NOUPLOAD, }, + [B2055_PRG_GCHP25] = { .ghz5 = 0x0075, .ghz2 = 0x0075, NOUPLOAD, }, + [B2055_PRG_GCHP26] = { .ghz5 = 0x0076, .ghz2 = 0x0076, NOUPLOAD, }, + [B2055_PRG_GCHP27] = { .ghz5 = 0x0077, .ghz2 = 0x0077, NOUPLOAD, }, + [B2055_PRG_GCHP28] = { .ghz5 = 0x0078, .ghz2 = 0x0078, NOUPLOAD, }, + [B2055_PRG_GCHP29] = { .ghz5 = 0x0079, .ghz2 = 0x0079, NOUPLOAD, }, + [B2055_PRG_GCHP30] = { .ghz5 = 0x007A, .ghz2 = 0x007A, NOUPLOAD, }, + [0xC7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xC8] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xC9] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xCA] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xCB] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xCC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C1_LNA_GAINBST] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xCE] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xCF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xD0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xD1] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, }, + [B2055_C1_B0NB_RSSIVCM] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, + [0xD3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xD4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xD5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C1_GENSPARE2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xD7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xD8] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C2_LNA_GAINBST] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xDA] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xDB] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xDC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xDD] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, }, + [B2055_C2_B0NB_RSSIVCM] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, + [0xDF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xE0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xE1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C2_GENSPARE2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, +}; + +#define RADIOREGS(r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, \ + r12, r13, r14, r15, r16, r17, r18, r19, r20, r21) \ + .radio_pll_ref = r0, \ + .radio_rf_pllmod0 = r1, \ + .radio_rf_pllmod1 = r2, \ + .radio_vco_captail = r3, \ + .radio_vco_cal1 = r4, \ + .radio_vco_cal2 = r5, \ + .radio_pll_lfc1 = r6, \ + .radio_pll_lfr1 = r7, \ + .radio_pll_lfc2 = r8, \ + .radio_lgbuf_cenbuf = r9, \ + .radio_lgen_tune1 = r10, \ + .radio_lgen_tune2 = r11, \ + .radio_c1_lgbuf_atune = r12, \ + .radio_c1_lgbuf_gtune = r13, \ + .radio_c1_rx_rfr1 = r14, \ + .radio_c1_tx_pgapadtn = r15, \ + .radio_c1_tx_mxbgtrim = r16, \ + .radio_c2_lgbuf_atune = r17, \ + .radio_c2_lgbuf_gtune = r18, \ + .radio_c2_rx_rfr1 = r19, \ + .radio_c2_tx_pgapadtn = r20, \ + .radio_c2_tx_mxbgtrim = r21 + +#define PHYREGS(r0, r1, r2, r3, r4, r5) \ + .phy_regs.phy_bw1a = r0, \ + .phy_regs.phy_bw2 = r1, \ + .phy_regs.phy_bw3 = r2, \ + .phy_regs.phy_bw4 = r3, \ + .phy_regs.phy_bw5 = r4, \ + .phy_regs.phy_bw6 = r5 + +static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = { + { .channel = 184, + .freq = 4920, /* MHz */ + .unk2 = 3280, + RADIOREGS(0x71, 0x01, 0xEC, 0x0F, 0xFF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xB407, 0xB007, 0xAC07, 0x1402, 0x1502, 0x1602), + }, + { .channel = 186, + .freq = 4930, /* MHz */ + .unk2 = 3287, + RADIOREGS(0x71, 0x01, 0xED, 0x0F, 0xFF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xB807, 0xB407, 0xB007, 0x1302, 0x1402, 0x1502), + }, + { .channel = 188, + .freq = 4940, /* MHz */ + .unk2 = 3293, + RADIOREGS(0x71, 0x01, 0xEE, 0x0F, 0xFF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xBC07, 0xB807, 0xB407, 0x1202, 0x1302, 0x1402), + }, + { .channel = 190, + .freq = 4950, /* MHz */ + .unk2 = 3300, + RADIOREGS(0x71, 0x01, 0xEF, 0x0F, 0xFF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xC007, 0xBC07, 0xB807, 0x1102, 0x1202, 0x1302), + }, + { .channel = 192, + .freq = 4960, /* MHz */ + .unk2 = 3307, + RADIOREGS(0x71, 0x01, 0xF0, 0x0F, 0xFF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xC407, 0xC007, 0xBC07, 0x0F02, 0x1102, 0x1202), + }, + { .channel = 194, + .freq = 4970, /* MHz */ + .unk2 = 3313, + RADIOREGS(0x71, 0x01, 0xF1, 0x0F, 0xFF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xC807, 0xC407, 0xC007, 0x0E02, 0x0F02, 0x1102), + }, + { .channel = 196, + .freq = 4980, /* MHz */ + .unk2 = 3320, + RADIOREGS(0x71, 0x01, 0xF2, 0x0E, 0xFF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xCC07, 0xC807, 0xC407, 0x0D02, 0x0E02, 0x0F02), + }, + { .channel = 198, + .freq = 4990, /* MHz */ + .unk2 = 3327, + RADIOREGS(0x71, 0x01, 0xF3, 0x0E, 0xFF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xD007, 0xCC07, 0xC807, 0x0C02, 0x0D02, 0x0E02), + }, + { .channel = 200, + .freq = 5000, /* MHz */ + .unk2 = 3333, + RADIOREGS(0x71, 0x01, 0xF4, 0x0E, 0xFF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xD407, 0xD007, 0xCC07, 0x0B02, 0x0C02, 0x0D02), + }, + { .channel = 202, + .freq = 5010, /* MHz */ + .unk2 = 3340, + RADIOREGS(0x71, 0x01, 0xF5, 0x0E, 0xFF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xD807, 0xD407, 0xD007, 0x0A02, 0x0B02, 0x0C02), + }, + { .channel = 204, + .freq = 5020, /* MHz */ + .unk2 = 3347, + RADIOREGS(0x71, 0x01, 0xF6, 0x0E, 0xF7, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xDC07, 0xD807, 0xD407, 0x0902, 0x0A02, 0x0B02), + }, + { .channel = 206, + .freq = 5030, /* MHz */ + .unk2 = 3353, + RADIOREGS(0x71, 0x01, 0xF7, 0x0E, 0xF7, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xE007, 0xDC07, 0xD807, 0x0802, 0x0902, 0x0A02), + }, + { .channel = 208, + .freq = 5040, /* MHz */ + .unk2 = 3360, + RADIOREGS(0x71, 0x01, 0xF8, 0x0D, 0xEF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xE407, 0xE007, 0xDC07, 0x0702, 0x0802, 0x0902), + }, + { .channel = 210, + .freq = 5050, /* MHz */ + .unk2 = 3367, + RADIOREGS(0x71, 0x01, 0xF9, 0x0D, 0xEF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xE807, 0xE407, 0xE007, 0x0602, 0x0702, 0x0802), + }, + { .channel = 212, + .freq = 5060, /* MHz */ + .unk2 = 3373, + RADIOREGS(0x71, 0x01, 0xFA, 0x0D, 0xE6, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xBB, 0xBB, 0xFF, 0x00, 0x0E, 0x0F, + 0x8E, 0xFF, 0x00, 0x0E, 0x0F, 0x8E), + PHYREGS(0xEC07, 0xE807, 0xE407, 0x0502, 0x0602, 0x0702), + }, + { .channel = 214, + .freq = 5070, /* MHz */ + .unk2 = 3380, + RADIOREGS(0x71, 0x01, 0xFB, 0x0D, 0xE6, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xBB, 0xBB, 0xFF, 0x00, 0x0E, 0x0F, + 0x8E, 0xFF, 0x00, 0x0E, 0x0F, 0x8E), + PHYREGS(0xF007, 0xEC07, 0xE807, 0x0402, 0x0502, 0x0602), + }, + { .channel = 216, + .freq = 5080, /* MHz */ + .unk2 = 3387, + RADIOREGS(0x71, 0x01, 0xFC, 0x0D, 0xDE, 0x01, 0x04, 0x0A, + 0x00, 0x8E, 0xBB, 0xBB, 0xEE, 0x00, 0x0E, 0x0F, + 0x8D, 0xEE, 0x00, 0x0E, 0x0F, 0x8D), + PHYREGS(0xF407, 0xF007, 0xEC07, 0x0302, 0x0402, 0x0502), + }, + { .channel = 218, + .freq = 5090, /* MHz */ + .unk2 = 3393, + RADIOREGS(0x71, 0x01, 0xFD, 0x0D, 0xDE, 0x01, 0x04, 0x0A, + 0x00, 0x8E, 0xBB, 0xBB, 0xEE, 0x00, 0x0E, 0x0F, + 0x8D, 0xEE, 0x00, 0x0E, 0x0F, 0x8D), + PHYREGS(0xF807, 0xF407, 0xF007, 0x0202, 0x0302, 0x0402), + }, + { .channel = 220, + .freq = 5100, /* MHz */ + .unk2 = 3400, + RADIOREGS(0x71, 0x01, 0xFE, 0x0C, 0xD6, 0x01, 0x04, 0x0A, + 0x00, 0x8E, 0xAA, 0xAA, 0xEE, 0x00, 0x0D, 0x0F, + 0x8D, 0xEE, 0x00, 0x0D, 0x0F, 0x8D), + PHYREGS(0xFC07, 0xF807, 0xF407, 0x0102, 0x0202, 0x0302), + }, + { .channel = 222, + .freq = 5110, /* MHz */ + .unk2 = 3407, + RADIOREGS(0x71, 0x01, 0xFF, 0x0C, 0xD6, 0x01, 0x04, 0x0A, + 0x00, 0x8E, 0xAA, 0xAA, 0xEE, 0x00, 0x0D, 0x0F, + 0x8D, 0xEE, 0x00, 0x0D, 0x0F, 0x8D), + PHYREGS(0x0008, 0xFC07, 0xF807, 0x0002, 0x0102, 0x0202), + }, + { .channel = 224, + .freq = 5120, /* MHz */ + .unk2 = 3413, + RADIOREGS(0x71, 0x02, 0x00, 0x0C, 0xCE, 0x01, 0x04, 0x0A, + 0x00, 0x8D, 0xAA, 0xAA, 0xDD, 0x00, 0x0D, 0x0F, + 0x8C, 0xDD, 0x00, 0x0D, 0x0F, 0x8C), + PHYREGS(0x0408, 0x0008, 0xFC07, 0xFF01, 0x0002, 0x0102), + }, + { .channel = 226, + .freq = 5130, /* MHz */ + .unk2 = 3420, + RADIOREGS(0x71, 0x02, 0x01, 0x0C, 0xCE, 0x01, 0x04, 0x0A, + 0x00, 0x8D, 0xAA, 0xAA, 0xDD, 0x00, 0x0D, 0x0F, + 0x8C, 0xDD, 0x00, 0x0D, 0x0F, 0x8C), + PHYREGS(0x0808, 0x0408, 0x0008, 0xFE01, 0xFF01, 0x0002), + }, + { .channel = 228, + .freq = 5140, /* MHz */ + .unk2 = 3427, + RADIOREGS(0x71, 0x02, 0x02, 0x0C, 0xC6, 0x01, 0x04, 0x0A, + 0x00, 0x8D, 0x99, 0x99, 0xDD, 0x00, 0x0C, 0x0E, + 0x8B, 0xDD, 0x00, 0x0C, 0x0E, 0x8B), + PHYREGS(0x0C08, 0x0808, 0x0408, 0xFD01, 0xFE01, 0xFF01), + }, + { .channel = 32, + .freq = 5160, /* MHz */ + .unk2 = 3440, + RADIOREGS(0x71, 0x02, 0x04, 0x0B, 0xBE, 0x01, 0x04, 0x0A, + 0x00, 0x8C, 0x99, 0x99, 0xCC, 0x00, 0x0B, 0x0D, + 0x8A, 0xCC, 0x00, 0x0B, 0x0D, 0x8A), + PHYREGS(0x1408, 0x1008, 0x0C08, 0xFB01, 0xFC01, 0xFD01), + }, + { .channel = 34, + .freq = 5170, /* MHz */ + .unk2 = 3447, + RADIOREGS(0x71, 0x02, 0x05, 0x0B, 0xBE, 0x01, 0x04, 0x0A, + 0x00, 0x8C, 0x99, 0x99, 0xCC, 0x00, 0x0B, 0x0D, + 0x8A, 0xCC, 0x00, 0x0B, 0x0D, 0x8A), + PHYREGS(0x1808, 0x1408, 0x1008, 0xFA01, 0xFB01, 0xFC01), + }, + { .channel = 36, + .freq = 5180, /* MHz */ + .unk2 = 3453, + RADIOREGS(0x71, 0x02, 0x06, 0x0B, 0xB6, 0x01, 0x04, 0x0A, + 0x00, 0x8C, 0x88, 0x88, 0xCC, 0x00, 0x0B, 0x0C, + 0x89, 0xCC, 0x00, 0x0B, 0x0C, 0x89), + PHYREGS(0x1C08, 0x1808, 0x1408, 0xF901, 0xFA01, 0xFB01), + }, + { .channel = 38, + .freq = 5190, /* MHz */ + .unk2 = 3460, + RADIOREGS(0x71, 0x02, 0x07, 0x0B, 0xB6, 0x01, 0x04, 0x0A, + 0x00, 0x8C, 0x88, 0x88, 0xCC, 0x00, 0x0B, 0x0C, + 0x89, 0xCC, 0x00, 0x0B, 0x0C, 0x89), + PHYREGS(0x2008, 0x1C08, 0x1808, 0xF801, 0xF901, 0xFA01), + }, + { .channel = 40, + .freq = 5200, /* MHz */ + .unk2 = 3467, + RADIOREGS(0x71, 0x02, 0x08, 0x0B, 0xAF, 0x01, 0x04, 0x0A, + 0x00, 0x8B, 0x88, 0x88, 0xBB, 0x00, 0x0A, 0x0B, + 0x89, 0xBB, 0x00, 0x0A, 0x0B, 0x89), + PHYREGS(0x2408, 0x2008, 0x1C08, 0xF701, 0xF801, 0xF901), + }, + { .channel = 42, + .freq = 5210, /* MHz */ + .unk2 = 3473, + RADIOREGS(0x71, 0x02, 0x09, 0x0B, 0xAF, 0x01, 0x04, 0x0A, + 0x00, 0x8B, 0x88, 0x88, 0xBB, 0x00, 0x0A, 0x0B, + 0x89, 0xBB, 0x00, 0x0A, 0x0B, 0x89), + PHYREGS(0x2808, 0x2408, 0x2008, 0xF601, 0xF701, 0xF801), + }, + { .channel = 44, + .freq = 5220, /* MHz */ + .unk2 = 3480, + RADIOREGS(0x71, 0x02, 0x0A, 0x0A, 0xA7, 0x01, 0x04, 0x0A, + 0x00, 0x8B, 0x77, 0x77, 0xBB, 0x00, 0x09, 0x0A, + 0x88, 0xBB, 0x00, 0x09, 0x0A, 0x88), + PHYREGS(0x2C08, 0x2808, 0x2408, 0xF501, 0xF601, 0xF701), + }, + { .channel = 46, + .freq = 5230, /* MHz */ + .unk2 = 3487, + RADIOREGS(0x71, 0x02, 0x0B, 0x0A, 0xA7, 0x01, 0x04, 0x0A, + 0x00, 0x8B, 0x77, 0x77, 0xBB, 0x00, 0x09, 0x0A, + 0x88, 0xBB, 0x00, 0x09, 0x0A, 0x88), + PHYREGS(0x3008, 0x2C08, 0x2808, 0xF401, 0xF501, 0xF601), + }, + { .channel = 48, + .freq = 5240, /* MHz */ + .unk2 = 3493, + RADIOREGS(0x71, 0x02, 0x0C, 0x0A, 0xA0, 0x01, 0x04, 0x0A, + 0x00, 0x8A, 0x77, 0x77, 0xAA, 0x00, 0x09, 0x0A, + 0x87, 0xAA, 0x00, 0x09, 0x0A, 0x87), + PHYREGS(0x3408, 0x3008, 0x2C08, 0xF301, 0xF401, 0xF501), + }, + { .channel = 50, + .freq = 5250, /* MHz */ + .unk2 = 3500, + RADIOREGS(0x71, 0x02, 0x0D, 0x0A, 0xA0, 0x01, 0x04, 0x0A, + 0x00, 0x8A, 0x77, 0x77, 0xAA, 0x00, 0x09, 0x0A, + 0x87, 0xAA, 0x00, 0x09, 0x0A, 0x87), + PHYREGS(0x3808, 0x3408, 0x3008, 0xF201, 0xF301, 0xF401), + }, + { .channel = 52, + .freq = 5260, /* MHz */ + .unk2 = 3507, + RADIOREGS(0x71, 0x02, 0x0E, 0x0A, 0x98, 0x01, 0x04, 0x0A, + 0x00, 0x8A, 0x66, 0x66, 0xAA, 0x00, 0x08, 0x09, + 0x87, 0xAA, 0x00, 0x08, 0x09, 0x87), + PHYREGS(0x3C08, 0x3808, 0x3408, 0xF101, 0xF201, 0xF301), + }, + { .channel = 54, + .freq = 5270, /* MHz */ + .unk2 = 3513, + RADIOREGS(0x71, 0x02, 0x0F, 0x0A, 0x98, 0x01, 0x04, 0x0A, + 0x00, 0x8A, 0x66, 0x66, 0xAA, 0x00, 0x08, 0x09, + 0x87, 0xAA, 0x00, 0x08, 0x09, 0x87), + PHYREGS(0x4008, 0x3C08, 0x3808, 0xF001, 0xF101, 0xF201), + }, + { .channel = 56, + .freq = 5280, /* MHz */ + .unk2 = 3520, + RADIOREGS(0x71, 0x02, 0x10, 0x09, 0x91, 0x01, 0x04, 0x0A, + 0x00, 0x89, 0x66, 0x66, 0x99, 0x00, 0x08, 0x08, + 0x86, 0x99, 0x00, 0x08, 0x08, 0x86), + PHYREGS(0x4408, 0x4008, 0x3C08, 0xF001, 0xF001, 0xF101), + }, + { .channel = 58, + .freq = 5290, /* MHz */ + .unk2 = 3527, + RADIOREGS(0x71, 0x02, 0x11, 0x09, 0x91, 0x01, 0x04, 0x0A, + 0x00, 0x89, 0x66, 0x66, 0x99, 0x00, 0x08, 0x08, + 0x86, 0x99, 0x00, 0x08, 0x08, 0x86), + PHYREGS(0x4808, 0x4408, 0x4008, 0xEF01, 0xF001, 0xF001), + }, + { .channel = 60, + .freq = 5300, /* MHz */ + .unk2 = 3533, + RADIOREGS(0x71, 0x02, 0x12, 0x09, 0x8A, 0x01, 0x04, 0x0A, + 0x00, 0x89, 0x55, 0x55, 0x99, 0x00, 0x08, 0x07, + 0x85, 0x99, 0x00, 0x08, 0x07, 0x85), + PHYREGS(0x4C08, 0x4808, 0x4408, 0xEE01, 0xEF01, 0xF001), + }, + { .channel = 62, + .freq = 5310, /* MHz */ + .unk2 = 3540, + RADIOREGS(0x71, 0x02, 0x13, 0x09, 0x8A, 0x01, 0x04, 0x0A, + 0x00, 0x89, 0x55, 0x55, 0x99, 0x00, 0x08, 0x07, + 0x85, 0x99, 0x00, 0x08, 0x07, 0x85), + PHYREGS(0x5008, 0x4C08, 0x4808, 0xED01, 0xEE01, 0xEF01), + }, + { .channel = 64, + .freq = 5320, /* MHz */ + .unk2 = 3547, + RADIOREGS(0x71, 0x02, 0x14, 0x09, 0x83, 0x01, 0x04, 0x0A, + 0x00, 0x88, 0x55, 0x55, 0x88, 0x00, 0x07, 0x07, + 0x84, 0x88, 0x00, 0x07, 0x07, 0x84), + PHYREGS(0x5408, 0x5008, 0x4C08, 0xEC01, 0xED01, 0xEE01), + }, + { .channel = 66, + .freq = 5330, /* MHz */ + .unk2 = 3553, + RADIOREGS(0x71, 0x02, 0x15, 0x09, 0x83, 0x01, 0x04, 0x0A, + 0x00, 0x88, 0x55, 0x55, 0x88, 0x00, 0x07, 0x07, + 0x84, 0x88, 0x00, 0x07, 0x07, 0x84), + PHYREGS(0x5808, 0x5408, 0x5008, 0xEB01, 0xEC01, 0xED01), + }, + { .channel = 68, + .freq = 5340, /* MHz */ + .unk2 = 3560, + RADIOREGS(0x71, 0x02, 0x16, 0x08, 0x7C, 0x01, 0x04, 0x0A, + 0x00, 0x88, 0x44, 0x44, 0x88, 0x00, 0x07, 0x06, + 0x84, 0x88, 0x00, 0x07, 0x06, 0x84), + PHYREGS(0x5C08, 0x5808, 0x5408, 0xEA01, 0xEB01, 0xEC01), + }, + { .channel = 70, + .freq = 5350, /* MHz */ + .unk2 = 3567, + RADIOREGS(0x71, 0x02, 0x17, 0x08, 0x7C, 0x01, 0x04, 0x0A, + 0x00, 0x88, 0x44, 0x44, 0x88, 0x00, 0x07, 0x06, + 0x84, 0x88, 0x00, 0x07, 0x06, 0x84), + PHYREGS(0x6008, 0x5C08, 0x5808, 0xE901, 0xEA01, 0xEB01), + }, + { .channel = 72, + .freq = 5360, /* MHz */ + .unk2 = 3573, + RADIOREGS(0x71, 0x02, 0x18, 0x08, 0x75, 0x01, 0x04, 0x0A, + 0x00, 0x87, 0x44, 0x44, 0x77, 0x00, 0x06, 0x05, + 0x83, 0x77, 0x00, 0x06, 0x05, 0x83), + PHYREGS(0x6408, 0x6008, 0x5C08, 0xE801, 0xE901, 0xEA01), + }, + { .channel = 74, + .freq = 5370, /* MHz */ + .unk2 = 3580, + RADIOREGS(0x71, 0x02, 0x19, 0x08, 0x75, 0x01, 0x04, 0x0A, + 0x00, 0x87, 0x44, 0x44, 0x77, 0x00, 0x06, 0x05, + 0x83, 0x77, 0x00, 0x06, 0x05, 0x83), + PHYREGS(0x6808, 0x6408, 0x6008, 0xE701, 0xE801, 0xE901), + }, + { .channel = 76, + .freq = 5380, /* MHz */ + .unk2 = 3587, + RADIOREGS(0x71, 0x02, 0x1A, 0x08, 0x6E, 0x01, 0x04, 0x0A, + 0x00, 0x87, 0x33, 0x33, 0x77, 0x00, 0x06, 0x04, + 0x82, 0x77, 0x00, 0x06, 0x04, 0x82), + PHYREGS(0x6C08, 0x6808, 0x6408, 0xE601, 0xE701, 0xE801), + }, + { .channel = 78, + .freq = 5390, /* MHz */ + .unk2 = 3593, + RADIOREGS(0x71, 0x02, 0x1B, 0x08, 0x6E, 0x01, 0x04, 0x0A, + 0x00, 0x87, 0x33, 0x33, 0x77, 0x00, 0x06, 0x04, + 0x82, 0x77, 0x00, 0x06, 0x04, 0x82), + PHYREGS(0x7008, 0x6C08, 0x6808, 0xE501, 0xE601, 0xE701), + }, + { .channel = 80, + .freq = 5400, /* MHz */ + .unk2 = 3600, + RADIOREGS(0x71, 0x02, 0x1C, 0x07, 0x67, 0x01, 0x04, 0x0A, + 0x00, 0x86, 0x33, 0x33, 0x66, 0x00, 0x05, 0x04, + 0x81, 0x66, 0x00, 0x05, 0x04, 0x81), + PHYREGS(0x7408, 0x7008, 0x6C08, 0xE501, 0xE501, 0xE601), + }, + { .channel = 82, + .freq = 5410, /* MHz */ + .unk2 = 3607, + RADIOREGS(0x71, 0x02, 0x1D, 0x07, 0x67, 0x01, 0x04, 0x0A, + 0x00, 0x86, 0x33, 0x33, 0x66, 0x00, 0x05, 0x04, + 0x81, 0x66, 0x00, 0x05, 0x04, 0x81), + PHYREGS(0x7808, 0x7408, 0x7008, 0xE401, 0xE501, 0xE501), + }, + { .channel = 84, + .freq = 5420, /* MHz */ + .unk2 = 3613, + RADIOREGS(0x71, 0x02, 0x1E, 0x07, 0x61, 0x01, 0x04, 0x0A, + 0x00, 0x86, 0x22, 0x22, 0x66, 0x00, 0x05, 0x03, + 0x80, 0x66, 0x00, 0x05, 0x03, 0x80), + PHYREGS(0x7C08, 0x7808, 0x7408, 0xE301, 0xE401, 0xE501), + }, + { .channel = 86, + .freq = 5430, /* MHz */ + .unk2 = 3620, + RADIOREGS(0x71, 0x02, 0x1F, 0x07, 0x61, 0x01, 0x04, 0x0A, + 0x00, 0x86, 0x22, 0x22, 0x66, 0x00, 0x05, 0x03, + 0x80, 0x66, 0x00, 0x05, 0x03, 0x80), + PHYREGS(0x8008, 0x7C08, 0x7808, 0xE201, 0xE301, 0xE401), + }, + { .channel = 88, + .freq = 5440, /* MHz */ + .unk2 = 3627, + RADIOREGS(0x71, 0x02, 0x20, 0x07, 0x5A, 0x01, 0x04, 0x0A, + 0x00, 0x85, 0x22, 0x22, 0x55, 0x00, 0x04, 0x02, + 0x80, 0x55, 0x00, 0x04, 0x02, 0x80), + PHYREGS(0x8408, 0x8008, 0x7C08, 0xE101, 0xE201, 0xE301), + }, + { .channel = 90, + .freq = 5450, /* MHz */ + .unk2 = 3633, + RADIOREGS(0x71, 0x02, 0x21, 0x07, 0x5A, 0x01, 0x04, 0x0A, + 0x00, 0x85, 0x22, 0x22, 0x55, 0x00, 0x04, 0x02, + 0x80, 0x55, 0x00, 0x04, 0x02, 0x80), + PHYREGS(0x8808, 0x8408, 0x8008, 0xE001, 0xE101, 0xE201), + }, + { .channel = 92, + .freq = 5460, /* MHz */ + .unk2 = 3640, + RADIOREGS(0x71, 0x02, 0x22, 0x06, 0x53, 0x01, 0x04, 0x0A, + 0x00, 0x85, 0x11, 0x11, 0x55, 0x00, 0x04, 0x01, + 0x80, 0x55, 0x00, 0x04, 0x01, 0x80), + PHYREGS(0x8C08, 0x8808, 0x8408, 0xDF01, 0xE001, 0xE101), + }, + { .channel = 94, + .freq = 5470, /* MHz */ + .unk2 = 3647, + RADIOREGS(0x71, 0x02, 0x23, 0x06, 0x53, 0x01, 0x04, 0x0A, + 0x00, 0x85, 0x11, 0x11, 0x55, 0x00, 0x04, 0x01, + 0x80, 0x55, 0x00, 0x04, 0x01, 0x80), + PHYREGS(0x9008, 0x8C08, 0x8808, 0xDE01, 0xDF01, 0xE001), + }, + { .channel = 96, + .freq = 5480, /* MHz */ + .unk2 = 3653, + RADIOREGS(0x71, 0x02, 0x24, 0x06, 0x4D, 0x01, 0x04, 0x0A, + 0x00, 0x84, 0x11, 0x11, 0x44, 0x00, 0x03, 0x00, + 0x80, 0x44, 0x00, 0x03, 0x00, 0x80), + PHYREGS(0x9408, 0x9008, 0x8C08, 0xDD01, 0xDE01, 0xDF01), + }, + { .channel = 98, + .freq = 5490, /* MHz */ + .unk2 = 3660, + RADIOREGS(0x71, 0x02, 0x25, 0x06, 0x4D, 0x01, 0x04, 0x0A, + 0x00, 0x84, 0x11, 0x11, 0x44, 0x00, 0x03, 0x00, + 0x80, 0x44, 0x00, 0x03, 0x00, 0x80), + PHYREGS(0x9808, 0x9408, 0x9008, 0xDD01, 0xDD01, 0xDE01), + }, + { .channel = 100, + .freq = 5500, /* MHz */ + .unk2 = 3667, + RADIOREGS(0x71, 0x02, 0x26, 0x06, 0x47, 0x01, 0x04, 0x0A, + 0x00, 0x84, 0x00, 0x00, 0x44, 0x00, 0x03, 0x00, + 0x80, 0x44, 0x00, 0x03, 0x00, 0x80), + PHYREGS(0x9C08, 0x9808, 0x9408, 0xDC01, 0xDD01, 0xDD01), + }, + { .channel = 102, + .freq = 5510, /* MHz */ + .unk2 = 3673, + RADIOREGS(0x71, 0x02, 0x27, 0x06, 0x47, 0x01, 0x04, 0x0A, + 0x00, 0x84, 0x00, 0x00, 0x44, 0x00, 0x03, 0x00, + 0x80, 0x44, 0x00, 0x03, 0x00, 0x80), + PHYREGS(0xA008, 0x9C08, 0x9808, 0xDB01, 0xDC01, 0xDD01), + }, + { .channel = 104, + .freq = 5520, /* MHz */ + .unk2 = 3680, + RADIOREGS(0x71, 0x02, 0x28, 0x05, 0x40, 0x01, 0x04, 0x0A, + 0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00, + 0x80, 0x33, 0x00, 0x02, 0x00, 0x80), + PHYREGS(0xA408, 0xA008, 0x9C08, 0xDA01, 0xDB01, 0xDC01), + }, + { .channel = 106, + .freq = 5530, /* MHz */ + .unk2 = 3687, + RADIOREGS(0x71, 0x02, 0x29, 0x05, 0x40, 0x01, 0x04, 0x0A, + 0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00, + 0x80, 0x33, 0x00, 0x02, 0x00, 0x80), + PHYREGS(0xA808, 0xA408, 0xA008, 0xD901, 0xDA01, 0xDB01), + }, + { .channel = 108, + .freq = 5540, /* MHz */ + .unk2 = 3693, + RADIOREGS(0x71, 0x02, 0x2A, 0x05, 0x3A, 0x01, 0x04, 0x0A, + 0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00, + 0x80, 0x33, 0x00, 0x02, 0x00, 0x80), + PHYREGS(0xAC08, 0xA808, 0xA408, 0xD801, 0xD901, 0xDA01), + }, + { .channel = 110, + .freq = 5550, /* MHz */ + .unk2 = 3700, + RADIOREGS(0x71, 0x02, 0x2B, 0x05, 0x3A, 0x01, 0x04, 0x0A, + 0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00, + 0x80, 0x33, 0x00, 0x02, 0x00, 0x80), + PHYREGS(0xB008, 0xAC08, 0xA808, 0xD701, 0xD801, 0xD901), + }, + { .channel = 112, + .freq = 5560, /* MHz */ + .unk2 = 3707, + RADIOREGS(0x71, 0x02, 0x2C, 0x05, 0x34, 0x01, 0x04, 0x0A, + 0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00, + 0x80, 0x22, 0x00, 0x01, 0x00, 0x80), + PHYREGS(0xB408, 0xB008, 0xAC08, 0xD701, 0xD701, 0xD801), + }, + { .channel = 114, + .freq = 5570, /* MHz */ + .unk2 = 3713, + RADIOREGS(0x71, 0x02, 0x2D, 0x05, 0x34, 0x01, 0x04, 0x0A, + 0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00, + 0x80, 0x22, 0x00, 0x01, 0x00, 0x80), + PHYREGS(0xB808, 0xB408, 0xB008, 0xD601, 0xD701, 0xD701), + }, + { .channel = 116, + .freq = 5580, /* MHz */ + .unk2 = 3720, + RADIOREGS(0x71, 0x02, 0x2E, 0x04, 0x2E, 0x01, 0x04, 0x0A, + 0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00, + 0x80, 0x22, 0x00, 0x01, 0x00, 0x80), + PHYREGS(0xBC08, 0xB808, 0xB408, 0xD501, 0xD601, 0xD701), + }, + { .channel = 118, + .freq = 5590, /* MHz */ + .unk2 = 3727, + RADIOREGS(0x71, 0x02, 0x2F, 0x04, 0x2E, 0x01, 0x04, 0x0A, + 0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00, + 0x80, 0x22, 0x00, 0x01, 0x00, 0x80), + PHYREGS(0xC008, 0xBC08, 0xB808, 0xD401, 0xD501, 0xD601), + }, + { .channel = 120, + .freq = 5600, /* MHz */ + .unk2 = 3733, + RADIOREGS(0x71, 0x02, 0x30, 0x04, 0x28, 0x01, 0x04, 0x0A, + 0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x01, 0x00, + 0x80, 0x11, 0x00, 0x01, 0x00, 0x80), + PHYREGS(0xC408, 0xC008, 0xBC08, 0xD301, 0xD401, 0xD501), + }, + { .channel = 122, + .freq = 5610, /* MHz */ + .unk2 = 3740, + RADIOREGS(0x71, 0x02, 0x31, 0x04, 0x28, 0x01, 0x04, 0x0A, + 0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x01, 0x00, + 0x80, 0x11, 0x00, 0x01, 0x00, 0x80), + PHYREGS(0xC808, 0xC408, 0xC008, 0xD201, 0xD301, 0xD401), + }, + { .channel = 124, + .freq = 5620, /* MHz */ + .unk2 = 3747, + RADIOREGS(0x71, 0x02, 0x32, 0x04, 0x21, 0x01, 0x04, 0x0A, + 0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, + 0x80, 0x11, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xCC08, 0xC808, 0xC408, 0xD201, 0xD201, 0xD301), + }, + { .channel = 126, + .freq = 5630, /* MHz */ + .unk2 = 3753, + RADIOREGS(0x71, 0x02, 0x33, 0x04, 0x21, 0x01, 0x04, 0x0A, + 0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, + 0x80, 0x11, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xD008, 0xCC08, 0xC808, 0xD101, 0xD201, 0xD201), + }, + { .channel = 128, + .freq = 5640, /* MHz */ + .unk2 = 3760, + RADIOREGS(0x71, 0x02, 0x34, 0x03, 0x1C, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xD408, 0xD008, 0xCC08, 0xD001, 0xD101, 0xD201), + }, + { .channel = 130, + .freq = 5650, /* MHz */ + .unk2 = 3767, + RADIOREGS(0x71, 0x02, 0x35, 0x03, 0x1C, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xD808, 0xD408, 0xD008, 0xCF01, 0xD001, 0xD101), + }, + { .channel = 132, + .freq = 5660, /* MHz */ + .unk2 = 3773, + RADIOREGS(0x71, 0x02, 0x36, 0x03, 0x16, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xDC08, 0xD808, 0xD408, 0xCE01, 0xCF01, 0xD001), + }, + { .channel = 134, + .freq = 5670, /* MHz */ + .unk2 = 3780, + RADIOREGS(0x71, 0x02, 0x37, 0x03, 0x16, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xE008, 0xDC08, 0xD808, 0xCE01, 0xCE01, 0xCF01), + }, + { .channel = 136, + .freq = 5680, /* MHz */ + .unk2 = 3787, + RADIOREGS(0x71, 0x02, 0x38, 0x03, 0x10, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xE408, 0xE008, 0xDC08, 0xCD01, 0xCE01, 0xCE01), + }, + { .channel = 138, + .freq = 5690, /* MHz */ + .unk2 = 3793, + RADIOREGS(0x71, 0x02, 0x39, 0x03, 0x10, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xE808, 0xE408, 0xE008, 0xCC01, 0xCD01, 0xCE01), + }, + { .channel = 140, + .freq = 5700, /* MHz */ + .unk2 = 3800, + RADIOREGS(0x71, 0x02, 0x3A, 0x02, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xEC08, 0xE808, 0xE408, 0xCB01, 0xCC01, 0xCD01), + }, + { .channel = 142, + .freq = 5710, /* MHz */ + .unk2 = 3807, + RADIOREGS(0x71, 0x02, 0x3B, 0x02, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xF008, 0xEC08, 0xE808, 0xCA01, 0xCB01, 0xCC01), + }, + { .channel = 144, + .freq = 5720, /* MHz */ + .unk2 = 3813, + RADIOREGS(0x71, 0x02, 0x3C, 0x02, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xF408, 0xF008, 0xEC08, 0xC901, 0xCA01, 0xCB01), + }, + { .channel = 145, + .freq = 5725, /* MHz */ + .unk2 = 3817, + RADIOREGS(0x72, 0x04, 0x79, 0x02, 0x03, 0x01, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xF608, 0xF208, 0xEE08, 0xC901, 0xCA01, 0xCB01), + }, + { .channel = 146, + .freq = 5730, /* MHz */ + .unk2 = 3820, + RADIOREGS(0x71, 0x02, 0x3D, 0x02, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xF808, 0xF408, 0xF008, 0xC901, 0xC901, 0xCA01), + }, + { .channel = 147, + .freq = 5735, /* MHz */ + .unk2 = 3823, + RADIOREGS(0x72, 0x04, 0x7B, 0x02, 0x03, 0x01, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xFA08, 0xF608, 0xF208, 0xC801, 0xC901, 0xCA01), + }, + { .channel = 148, + .freq = 5740, /* MHz */ + .unk2 = 3827, + RADIOREGS(0x71, 0x02, 0x3E, 0x02, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xFC08, 0xF808, 0xF408, 0xC801, 0xC901, 0xC901), + }, + { .channel = 149, + .freq = 5745, /* MHz */ + .unk2 = 3830, + RADIOREGS(0x72, 0x04, 0x7D, 0x02, 0xFE, 0x00, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xFE08, 0xFA08, 0xF608, 0xC801, 0xC801, 0xC901), + }, + { .channel = 150, + .freq = 5750, /* MHz */ + .unk2 = 3833, + RADIOREGS(0x71, 0x02, 0x3F, 0x02, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x0009, 0xFC08, 0xF808, 0xC701, 0xC801, 0xC901), + }, + { .channel = 151, + .freq = 5755, /* MHz */ + .unk2 = 3837, + RADIOREGS(0x72, 0x04, 0x7F, 0x02, 0xFE, 0x00, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x0209, 0xFE08, 0xFA08, 0xC701, 0xC801, 0xC801), + }, + { .channel = 152, + .freq = 5760, /* MHz */ + .unk2 = 3840, + RADIOREGS(0x71, 0x02, 0x40, 0x02, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x0409, 0x0009, 0xFC08, 0xC601, 0xC701, 0xC801), + }, + { .channel = 153, + .freq = 5765, /* MHz */ + .unk2 = 3843, + RADIOREGS(0x72, 0x04, 0x81, 0x02, 0xF8, 0x00, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x0609, 0x0209, 0xFE08, 0xC601, 0xC701, 0xC801), + }, + { .channel = 154, + .freq = 5770, /* MHz */ + .unk2 = 3847, + RADIOREGS(0x71, 0x02, 0x41, 0x02, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x0809, 0x0409, 0x0009, 0xC601, 0xC601, 0xC701), + }, + { .channel = 155, + .freq = 5775, /* MHz */ + .unk2 = 3850, + RADIOREGS(0x72, 0x04, 0x83, 0x02, 0xF8, 0x00, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x0A09, 0x0609, 0x0209, 0xC501, 0xC601, 0xC701), + }, + { .channel = 156, + .freq = 5780, /* MHz */ + .unk2 = 3853, + RADIOREGS(0x71, 0x02, 0x42, 0x02, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x0C09, 0x0809, 0x0409, 0xC501, 0xC601, 0xC601), + }, + { .channel = 157, + .freq = 5785, /* MHz */ + .unk2 = 3857, + RADIOREGS(0x72, 0x04, 0x85, 0x02, 0xF2, 0x00, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x0E09, 0x0A09, 0x0609, 0xC401, 0xC501, 0xC601), + }, + { .channel = 158, + .freq = 5790, /* MHz */ + .unk2 = 3860, + RADIOREGS(0x71, 0x02, 0x43, 0x02, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x1009, 0x0C09, 0x0809, 0xC401, 0xC501, 0xC601), + }, + { .channel = 159, + .freq = 5795, /* MHz */ + .unk2 = 3863, + RADIOREGS(0x72, 0x04, 0x87, 0x02, 0xF2, 0x00, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x1209, 0x0E09, 0x0A09, 0xC401, 0xC401, 0xC501), + }, + { .channel = 160, + .freq = 5800, /* MHz */ + .unk2 = 3867, + RADIOREGS(0x71, 0x02, 0x44, 0x01, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x1409, 0x1009, 0x0C09, 0xC301, 0xC401, 0xC501), + }, + { .channel = 161, + .freq = 5805, /* MHz */ + .unk2 = 3870, + RADIOREGS(0x72, 0x04, 0x89, 0x01, 0xED, 0x00, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x1609, 0x1209, 0x0E09, 0xC301, 0xC401, 0xC401), + }, + { .channel = 162, + .freq = 5810, /* MHz */ + .unk2 = 3873, + RADIOREGS(0x71, 0x02, 0x45, 0x01, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x1809, 0x1409, 0x1009, 0xC201, 0xC301, 0xC401), + }, + { .channel = 163, + .freq = 5815, /* MHz */ + .unk2 = 3877, + RADIOREGS(0x72, 0x04, 0x8B, 0x01, 0xED, 0x00, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x1A09, 0x1609, 0x1209, 0xC201, 0xC301, 0xC401), + }, + { .channel = 164, + .freq = 5820, /* MHz */ + .unk2 = 3880, + RADIOREGS(0x71, 0x02, 0x46, 0x01, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x1C09, 0x1809, 0x1409, 0xC201, 0xC201, 0xC301), + }, + { .channel = 165, + .freq = 5825, /* MHz */ + .unk2 = 3883, + RADIOREGS(0x72, 0x04, 0x8D, 0x01, 0xED, 0x00, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x1E09, 0x1A09, 0x1609, 0xC101, 0xC201, 0xC301), + }, + { .channel = 166, + .freq = 5830, /* MHz */ + .unk2 = 3887, + RADIOREGS(0x71, 0x02, 0x47, 0x01, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x2009, 0x1C09, 0x1809, 0xC101, 0xC201, 0xC201), + }, + { .channel = 168, + .freq = 5840, /* MHz */ + .unk2 = 3893, + RADIOREGS(0x71, 0x02, 0x48, 0x01, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x2409, 0x2009, 0x1C09, 0xC001, 0xC101, 0xC201), + }, + { .channel = 170, + .freq = 5850, /* MHz */ + .unk2 = 3900, + RADIOREGS(0x71, 0x02, 0x49, 0x01, 0xE0, 0x00, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x2809, 0x2409, 0x2009, 0xBF01, 0xC001, 0xC101), + }, + { .channel = 172, + .freq = 5860, /* MHz */ + .unk2 = 3907, + RADIOREGS(0x71, 0x02, 0x4A, 0x01, 0xDE, 0x00, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x2C09, 0x2809, 0x2409, 0xBF01, 0xBF01, 0xC001), + }, + { .channel = 174, + .freq = 5870, /* MHz */ + .unk2 = 3913, + RADIOREGS(0x71, 0x02, 0x4B, 0x00, 0xDB, 0x00, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x3009, 0x2C09, 0x2809, 0xBE01, 0xBF01, 0xBF01), + }, + { .channel = 176, + .freq = 5880, /* MHz */ + .unk2 = 3920, + RADIOREGS(0x71, 0x02, 0x4C, 0x00, 0xD8, 0x00, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x3409, 0x3009, 0x2C09, 0xBD01, 0xBE01, 0xBF01), + }, + { .channel = 178, + .freq = 5890, /* MHz */ + .unk2 = 3927, + RADIOREGS(0x71, 0x02, 0x4D, 0x00, 0xD6, 0x00, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x3809, 0x3409, 0x3009, 0xBC01, 0xBD01, 0xBE01), + }, + { .channel = 180, + .freq = 5900, /* MHz */ + .unk2 = 3933, + RADIOREGS(0x71, 0x02, 0x4E, 0x00, 0xD3, 0x00, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x3C09, 0x3809, 0x3409, 0xBC01, 0xBC01, 0xBD01), + }, + { .channel = 182, + .freq = 5910, /* MHz */ + .unk2 = 3940, + RADIOREGS(0x71, 0x02, 0x4F, 0x00, 0xD6, 0x00, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x4009, 0x3C09, 0x3809, 0xBB01, 0xBC01, 0xBC01), + }, + { .channel = 1, + .freq = 2412, /* MHz */ + .unk2 = 3216, + RADIOREGS(0x73, 0x09, 0x6C, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0D, 0x0C, + 0x80, 0xFF, 0x88, 0x0D, 0x0C, 0x80), + PHYREGS(0xC903, 0xC503, 0xC103, 0x3A04, 0x3F04, 0x4304), + }, + { .channel = 2, + .freq = 2417, /* MHz */ + .unk2 = 3223, + RADIOREGS(0x73, 0x09, 0x71, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0B, + 0x80, 0xFF, 0x88, 0x0C, 0x0B, 0x80), + PHYREGS(0xCB03, 0xC703, 0xC303, 0x3804, 0x3D04, 0x4104), + }, + { .channel = 3, + .freq = 2422, /* MHz */ + .unk2 = 3229, + RADIOREGS(0x73, 0x09, 0x76, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0A, + 0x80, 0xFF, 0x88, 0x0C, 0x0A, 0x80), + PHYREGS(0xCD03, 0xC903, 0xC503, 0x3604, 0x3A04, 0x3F04), + }, + { .channel = 4, + .freq = 2427, /* MHz */ + .unk2 = 3236, + RADIOREGS(0x73, 0x09, 0x7B, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0A, + 0x80, 0xFF, 0x88, 0x0C, 0x0A, 0x80), + PHYREGS(0xCF03, 0xCB03, 0xC703, 0x3404, 0x3804, 0x3D04), + }, + { .channel = 5, + .freq = 2432, /* MHz */ + .unk2 = 3243, + RADIOREGS(0x73, 0x09, 0x80, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x09, + 0x80, 0xFF, 0x88, 0x0C, 0x09, 0x80), + PHYREGS(0xD103, 0xCD03, 0xC903, 0x3104, 0x3604, 0x3A04), + }, + { .channel = 6, + .freq = 2437, /* MHz */ + .unk2 = 3249, + RADIOREGS(0x73, 0x09, 0x85, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0B, 0x08, + 0x80, 0xFF, 0x88, 0x0B, 0x08, 0x80), + PHYREGS(0xD303, 0xCF03, 0xCB03, 0x2F04, 0x3404, 0x3804), + }, + { .channel = 7, + .freq = 2442, /* MHz */ + .unk2 = 3256, + RADIOREGS(0x73, 0x09, 0x8A, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0A, 0x07, + 0x80, 0xFF, 0x88, 0x0A, 0x07, 0x80), + PHYREGS(0xD503, 0xD103, 0xCD03, 0x2D04, 0x3104, 0x3604), + }, + { .channel = 8, + .freq = 2447, /* MHz */ + .unk2 = 3263, + RADIOREGS(0x73, 0x09, 0x8F, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0A, 0x06, + 0x80, 0xFF, 0x88, 0x0A, 0x06, 0x80), + PHYREGS(0xD703, 0xD303, 0xCF03, 0x2B04, 0x2F04, 0x3404), + }, + { .channel = 9, + .freq = 2452, /* MHz */ + .unk2 = 3269, + RADIOREGS(0x73, 0x09, 0x94, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x09, 0x06, + 0x80, 0xFF, 0x88, 0x09, 0x06, 0x80), + PHYREGS(0xD903, 0xD503, 0xD103, 0x2904, 0x2D04, 0x3104), + }, + { .channel = 10, + .freq = 2457, /* MHz */ + .unk2 = 3276, + RADIOREGS(0x73, 0x09, 0x99, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x05, + 0x80, 0xFF, 0x88, 0x08, 0x05, 0x80), + PHYREGS(0xDB03, 0xD703, 0xD303, 0x2704, 0x2B04, 0x2F04), + }, + { .channel = 11, + .freq = 2462, /* MHz */ + .unk2 = 3283, + RADIOREGS(0x73, 0x09, 0x9E, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x04, + 0x80, 0xFF, 0x88, 0x08, 0x04, 0x80), + PHYREGS(0xDD03, 0xD903, 0xD503, 0x2404, 0x2904, 0x2D04), + }, + { .channel = 12, + .freq = 2467, /* MHz */ + .unk2 = 3289, + RADIOREGS(0x73, 0x09, 0xA3, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x03, + 0x80, 0xFF, 0x88, 0x08, 0x03, 0x80), + PHYREGS(0xDF03, 0xDB03, 0xD703, 0x2204, 0x2704, 0x2B04), + }, + { .channel = 13, + .freq = 2472, /* MHz */ + .unk2 = 3296, + RADIOREGS(0x73, 0x09, 0xA8, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x07, 0x03, + 0x80, 0xFF, 0x88, 0x07, 0x03, 0x80), + PHYREGS(0xE103, 0xDD03, 0xD903, 0x2004, 0x2404, 0x2904), + }, + { .channel = 14, + .freq = 2484, /* MHz */ + .unk2 = 3312, + RADIOREGS(0x73, 0x09, 0xB4, 0x0F, 0xFF, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x07, 0x01, + 0x80, 0xFF, 0x88, 0x07, 0x01, 0x80), + PHYREGS(0xE603, 0xE203, 0xDE03, 0x1B04, 0x1F04, 0x2404), + }, +}; + +void b2055_upload_inittab(struct b43_wldev *dev, + bool ghz5, bool ignore_uploadflag) +{ + const struct b2055_inittab_entry *e; + unsigned int i; + u16 value; + + for (i = 0; i < ARRAY_SIZE(b2055_inittab); i++) { + e = &(b2055_inittab[i]); + if (!(e->flags & B2055_INITTAB_ENTRY_OK)) + continue; + if ((e->flags & B2055_INITTAB_UPLOAD) || ignore_uploadflag) { + if (ghz5) + value = e->ghz5; + else + value = e->ghz2; + b43_radio_write16(dev, i, value); + } + } +} + +const struct b43_nphy_channeltab_entry_rev2 * +b43_nphy_get_chantabent_rev2(struct b43_wldev *dev, u8 channel) +{ + const struct b43_nphy_channeltab_entry_rev2 *e; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(b43_nphy_channeltab_rev2); i++) { + e = &(b43_nphy_channeltab_rev2[i]); + if (e->channel == channel) + return e; + } + + return NULL; +} diff --git a/drivers/net/wireless/b43/radio_2055.h b/drivers/net/wireless/b43/radio_2055.h new file mode 100644 index 0000000..d9bfa0f --- /dev/null +++ b/drivers/net/wireless/b43/radio_2055.h @@ -0,0 +1,254 @@ +#ifndef B43_RADIO_2055_H_ +#define B43_RADIO_2055_H_ + +#include + +#include "tables_nphy.h" + +#define B2055_GEN_SPARE 0x00 /* GEN spare */ +#define B2055_SP_PINPD 0x02 /* SP PIN PD */ +#define B2055_C1_SP_RSSI 0x03 /* SP RSSI Core 1 */ +#define B2055_C1_SP_PDMISC 0x04 /* SP PD MISC Core 1 */ +#define B2055_C2_SP_RSSI 0x05 /* SP RSSI Core 2 */ +#define B2055_C2_SP_PDMISC 0x06 /* SP PD MISC Core 2 */ +#define B2055_C1_SP_RXGC1 0x07 /* SP RX GC1 Core 1 */ +#define B2055_C1_SP_RXGC2 0x08 /* SP RX GC2 Core 1 */ +#define B2055_C2_SP_RXGC1 0x09 /* SP RX GC1 Core 2 */ +#define B2055_C2_SP_RXGC2 0x0A /* SP RX GC2 Core 2 */ +#define B2055_C1_SP_LPFBWSEL 0x0B /* SP LPF BW select Core 1 */ +#define B2055_C2_SP_LPFBWSEL 0x0C /* SP LPF BW select Core 2 */ +#define B2055_C1_SP_TXGC1 0x0D /* SP TX GC1 Core 1 */ +#define B2055_C1_SP_TXGC2 0x0E /* SP TX GC2 Core 1 */ +#define B2055_C2_SP_TXGC1 0x0F /* SP TX GC1 Core 2 */ +#define B2055_C2_SP_TXGC2 0x10 /* SP TX GC2 Core 2 */ +#define B2055_MASTER1 0x11 /* Master control 1 */ +#define B2055_MASTER2 0x12 /* Master control 2 */ +#define B2055_PD_LGEN 0x13 /* PD LGEN */ +#define B2055_PD_PLLTS 0x14 /* PD PLL TS */ +#define B2055_C1_PD_LGBUF 0x15 /* PD Core 1 LGBUF */ +#define B2055_C1_PD_TX 0x16 /* PD Core 1 TX */ +#define B2055_C1_PD_RXTX 0x17 /* PD Core 1 RXTX */ +#define B2055_C1_PD_RSSIMISC 0x18 /* PD Core 1 RSSI MISC */ +#define B2055_C2_PD_LGBUF 0x19 /* PD Core 2 LGBUF */ +#define B2055_C2_PD_TX 0x1A /* PD Core 2 TX */ +#define B2055_C2_PD_RXTX 0x1B /* PD Core 2 RXTX */ +#define B2055_C2_PD_RSSIMISC 0x1C /* PD Core 2 RSSI MISC */ +#define B2055_PWRDET_LGEN 0x1D /* PWRDET LGEN */ +#define B2055_C1_PWRDET_LGBUF 0x1E /* PWRDET LGBUF Core 1 */ +#define B2055_C1_PWRDET_RXTX 0x1F /* PWRDET RXTX Core 1 */ +#define B2055_C2_PWRDET_LGBUF 0x20 /* PWRDET LGBUF Core 2 */ +#define B2055_C2_PWRDET_RXTX 0x21 /* PWRDET RXTX Core 2 */ +#define B2055_RRCCAL_CS 0x22 /* RRCCAL Control spare */ +#define B2055_RRCCAL_NOPTSEL 0x23 /* RRCCAL N OPT SEL */ +#define B2055_CAL_MISC 0x24 /* CAL MISC */ +#define B2055_CAL_COUT 0x25 /* CAL Counter out */ +#define B2055_CAL_COUT2 0x26 /* CAL Counter out 2 */ +#define B2055_CAL_CVARCTL 0x27 /* CAL CVAR Control */ +#define B2055_CAL_RVARCTL 0x28 /* CAL RVAR Control */ +#define B2055_CAL_LPOCTL 0x29 /* CAL LPO Control */ +#define B2055_CAL_TS 0x2A /* CAL TS */ +#define B2055_CAL_RCCALRTS 0x2B /* CAL RCCAL READ TS */ +#define B2055_CAL_RCALRTS 0x2C /* CAL RCAL READ TS */ +#define B2055_PADDRV 0x2D /* PAD driver */ +#define B2055_XOCTL1 0x2E /* XO Control 1 */ +#define B2055_XOCTL2 0x2F /* XO Control 2 */ +#define B2055_XOREGUL 0x30 /* XO Regulator */ +#define B2055_XOMISC 0x31 /* XO misc */ +#define B2055_PLL_LFC1 0x32 /* PLL LF C1 */ +#define B2055_PLL_CALVTH 0x33 /* PLL CAL VTH */ +#define B2055_PLL_LFC2 0x34 /* PLL LF C2 */ +#define B2055_PLL_REF 0x35 /* PLL reference */ +#define B2055_PLL_LFR1 0x36 /* PLL LF R1 */ +#define B2055_PLL_PFDCP 0x37 /* PLL PFD CP */ +#define B2055_PLL_IDAC_CPOPAMP 0x38 /* PLL IDAC CPOPAMP */ +#define B2055_PLL_CPREG 0x39 /* PLL CP Regulator */ +#define B2055_PLL_RCAL 0x3A /* PLL RCAL */ +#define B2055_RF_PLLMOD0 0x3B /* RF PLL MOD0 */ +#define B2055_RF_PLLMOD1 0x3C /* RF PLL MOD1 */ +#define B2055_RF_MMDIDAC1 0x3D /* RF MMD IDAC 1 */ +#define B2055_RF_MMDIDAC0 0x3E /* RF MMD IDAC 0 */ +#define B2055_RF_MMDSP 0x3F /* RF MMD spare */ +#define B2055_VCO_CAL1 0x40 /* VCO cal 1 */ +#define B2055_VCO_CAL2 0x41 /* VCO cal 2 */ +#define B2055_VCO_CAL3 0x42 /* VCO cal 3 */ +#define B2055_VCO_CAL4 0x43 /* VCO cal 4 */ +#define B2055_VCO_CAL5 0x44 /* VCO cal 5 */ +#define B2055_VCO_CAL6 0x45 /* VCO cal 6 */ +#define B2055_VCO_CAL7 0x46 /* VCO cal 7 */ +#define B2055_VCO_CAL8 0x47 /* VCO cal 8 */ +#define B2055_VCO_CAL9 0x48 /* VCO cal 9 */ +#define B2055_VCO_CAL10 0x49 /* VCO cal 10 */ +#define B2055_VCO_CAL11 0x4A /* VCO cal 11 */ +#define B2055_VCO_CAL12 0x4B /* VCO cal 12 */ +#define B2055_VCO_CAL13 0x4C /* VCO cal 13 */ +#define B2055_VCO_CAL14 0x4D /* VCO cal 14 */ +#define B2055_VCO_CAL15 0x4E /* VCO cal 15 */ +#define B2055_VCO_CAL16 0x4F /* VCO cal 16 */ +#define B2055_VCO_KVCO 0x50 /* VCO KVCO */ +#define B2055_VCO_CAPTAIL 0x51 /* VCO CAP TAIL */ +#define B2055_VCO_IDACVCO 0x52 /* VCO IDAC VCO */ +#define B2055_VCO_REG 0x53 /* VCO Regulator */ +#define B2055_PLL_RFVTH 0x54 /* PLL RF VTH */ +#define B2055_LGBUF_CENBUF 0x55 /* LGBUF CEN BUF */ +#define B2055_LGEN_TUNE1 0x56 /* LGEN tune 1 */ +#define B2055_LGEN_TUNE2 0x57 /* LGEN tune 2 */ +#define B2055_LGEN_IDAC1 0x58 /* LGEN IDAC 1 */ +#define B2055_LGEN_IDAC2 0x59 /* LGEN IDAC 2 */ +#define B2055_LGEN_BIASC 0x5A /* LGEN BIAS counter */ +#define B2055_LGEN_BIASIDAC 0x5B /* LGEN BIAS IDAC */ +#define B2055_LGEN_RCAL 0x5C /* LGEN RCAL */ +#define B2055_LGEN_DIV 0x5D /* LGEN div */ +#define B2055_LGEN_SPARE2 0x5E /* LGEN spare 2 */ +#define B2055_C1_LGBUF_ATUNE 0x5F /* Core 1 LGBUF A tune */ +#define B2055_C1_LGBUF_GTUNE 0x60 /* Core 1 LGBUF G tune */ +#define B2055_C1_LGBUF_DIV 0x61 /* Core 1 LGBUF div */ +#define B2055_C1_LGBUF_AIDAC 0x62 /* Core 1 LGBUF A IDAC */ +#define B2055_C1_LGBUF_GIDAC 0x63 /* Core 1 LGBUF G IDAC */ +#define B2055_C1_LGBUF_IDACFO 0x64 /* Core 1 LGBUF IDAC filter override */ +#define B2055_C1_LGBUF_SPARE 0x65 /* Core 1 LGBUF spare */ +#define B2055_C1_RX_RFSPC1 0x66 /* Core 1 RX RF SPC1 */ +#define B2055_C1_RX_RFR1 0x67 /* Core 1 RX RF reg 1 */ +#define B2055_C1_RX_RFR2 0x68 /* Core 1 RX RF reg 2 */ +#define B2055_C1_RX_RFRCAL 0x69 /* Core 1 RX RF RCAL */ +#define B2055_C1_RX_BB_BLCMP 0x6A /* Core 1 RX Baseband BUFI LPF CMP */ +#define B2055_C1_RX_BB_LPF 0x6B /* Core 1 RX Baseband LPF */ +#define B2055_C1_RX_BB_MIDACHP 0x6C /* Core 1 RX Baseband MIDAC High-pass */ +#define B2055_C1_RX_BB_VGA1IDAC 0x6D /* Core 1 RX Baseband VGA1 IDAC */ +#define B2055_C1_RX_BB_VGA2IDAC 0x6E /* Core 1 RX Baseband VGA2 IDAC */ +#define B2055_C1_RX_BB_VGA3IDAC 0x6F /* Core 1 RX Baseband VGA3 IDAC */ +#define B2055_C1_RX_BB_BUFOCTL 0x70 /* Core 1 RX Baseband BUFO Control */ +#define B2055_C1_RX_BB_RCCALCTL 0x71 /* Core 1 RX Baseband RCCAL Control */ +#define B2055_C1_RX_BB_RSSICTL1 0x72 /* Core 1 RX Baseband RSSI Control 1 */ +#define B2055_C1_RX_BB_RSSICTL2 0x73 /* Core 1 RX Baseband RSSI Control 2 */ +#define B2055_C1_RX_BB_RSSICTL3 0x74 /* Core 1 RX Baseband RSSI Control 3 */ +#define B2055_C1_RX_BB_RSSICTL4 0x75 /* Core 1 RX Baseband RSSI Control 4 */ +#define B2055_C1_RX_BB_RSSICTL5 0x76 /* Core 1 RX Baseband RSSI Control 5 */ +#define B2055_C1_RX_BB_REG 0x77 /* Core 1 RX Baseband Regulator */ +#define B2055_C1_RX_BB_SPARE1 0x78 /* Core 1 RX Baseband spare 1 */ +#define B2055_C1_RX_TXBBRCAL 0x79 /* Core 1 RX TX BB RCAL */ +#define B2055_C1_TX_RF_SPGA 0x7A /* Core 1 TX RF SGM PGA */ +#define B2055_C1_TX_RF_SPAD 0x7B /* Core 1 TX RF SGM PAD */ +#define B2055_C1_TX_RF_CNTPGA1 0x7C /* Core 1 TX RF counter PGA 1 */ +#define B2055_C1_TX_RF_CNTPAD1 0x7D /* Core 1 TX RF counter PAD 1 */ +#define B2055_C1_TX_RF_PGAIDAC 0x7E /* Core 1 TX RF PGA IDAC */ +#define B2055_C1_TX_PGAPADTN 0x7F /* Core 1 TX PGA PAD TN */ +#define B2055_C1_TX_PADIDAC1 0x80 /* Core 1 TX PAD IDAC 1 */ +#define B2055_C1_TX_PADIDAC2 0x81 /* Core 1 TX PAD IDAC 2 */ +#define B2055_C1_TX_MXBGTRIM 0x82 /* Core 1 TX MX B/G TRIM */ +#define B2055_C1_TX_RF_RCAL 0x83 /* Core 1 TX RF RCAL */ +#define B2055_C1_TX_RF_PADTSSI1 0x84 /* Core 1 TX RF PAD TSSI1 */ +#define B2055_C1_TX_RF_PADTSSI2 0x85 /* Core 1 TX RF PAD TSSI2 */ +#define B2055_C1_TX_RF_SPARE 0x86 /* Core 1 TX RF spare */ +#define B2055_C1_TX_RF_IQCAL1 0x87 /* Core 1 TX RF I/Q CAL 1 */ +#define B2055_C1_TX_RF_IQCAL2 0x88 /* Core 1 TX RF I/Q CAL 2 */ +#define B2055_C1_TXBB_RCCAL 0x89 /* Core 1 TXBB RC CAL Control */ +#define B2055_C1_TXBB_LPF1 0x8A /* Core 1 TXBB LPF 1 */ +#define B2055_C1_TX_VOSCNCL 0x8B /* Core 1 TX VOS CNCL */ +#define B2055_C1_TX_LPF_MXGMIDAC 0x8C /* Core 1 TX LPF MXGM IDAC */ +#define B2055_C1_TX_BB_MXGM 0x8D /* Core 1 TX BB MXGM */ +#define B2055_C2_LGBUF_ATUNE 0x8E /* Core 2 LGBUF A tune */ +#define B2055_C2_LGBUF_GTUNE 0x8F /* Core 2 LGBUF G tune */ +#define B2055_C2_LGBUF_DIV 0x90 /* Core 2 LGBUF div */ +#define B2055_C2_LGBUF_AIDAC 0x91 /* Core 2 LGBUF A IDAC */ +#define B2055_C2_LGBUF_GIDAC 0x92 /* Core 2 LGBUF G IDAC */ +#define B2055_C2_LGBUF_IDACFO 0x93 /* Core 2 LGBUF IDAC filter override */ +#define B2055_C2_LGBUF_SPARE 0x94 /* Core 2 LGBUF spare */ +#define B2055_C2_RX_RFSPC1 0x95 /* Core 2 RX RF SPC1 */ +#define B2055_C2_RX_RFR1 0x96 /* Core 2 RX RF reg 1 */ +#define B2055_C2_RX_RFR2 0x97 /* Core 2 RX RF reg 2 */ +#define B2055_C2_RX_RFRCAL 0x98 /* Core 2 RX RF RCAL */ +#define B2055_C2_RX_BB_BLCMP 0x99 /* Core 2 RX Baseband BUFI LPF CMP */ +#define B2055_C2_RX_BB_LPF 0x9A /* Core 2 RX Baseband LPF */ +#define B2055_C2_RX_BB_MIDACHP 0x9B /* Core 2 RX Baseband MIDAC High-pass */ +#define B2055_C2_RX_BB_VGA1IDAC 0x9C /* Core 2 RX Baseband VGA1 IDAC */ +#define B2055_C2_RX_BB_VGA2IDAC 0x9D /* Core 2 RX Baseband VGA2 IDAC */ +#define B2055_C2_RX_BB_VGA3IDAC 0x9E /* Core 2 RX Baseband VGA3 IDAC */ +#define B2055_C2_RX_BB_BUFOCTL 0x9F /* Core 2 RX Baseband BUFO Control */ +#define B2055_C2_RX_BB_RCCALCTL 0xA0 /* Core 2 RX Baseband RCCAL Control */ +#define B2055_C2_RX_BB_RSSICTL1 0xA1 /* Core 2 RX Baseband RSSI Control 1 */ +#define B2055_C2_RX_BB_RSSICTL2 0xA2 /* Core 2 RX Baseband RSSI Control 2 */ +#define B2055_C2_RX_BB_RSSICTL3 0xA3 /* Core 2 RX Baseband RSSI Control 3 */ +#define B2055_C2_RX_BB_RSSICTL4 0xA4 /* Core 2 RX Baseband RSSI Control 4 */ +#define B2055_C2_RX_BB_RSSICTL5 0xA5 /* Core 2 RX Baseband RSSI Control 5 */ +#define B2055_C2_RX_BB_REG 0xA6 /* Core 2 RX Baseband Regulator */ +#define B2055_C2_RX_BB_SPARE1 0xA7 /* Core 2 RX Baseband spare 1 */ +#define B2055_C2_RX_TXBBRCAL 0xA8 /* Core 2 RX TX BB RCAL */ +#define B2055_C2_TX_RF_SPGA 0xA9 /* Core 2 TX RF SGM PGA */ +#define B2055_C2_TX_RF_SPAD 0xAA /* Core 2 TX RF SGM PAD */ +#define B2055_C2_TX_RF_CNTPGA1 0xAB /* Core 2 TX RF counter PGA 1 */ +#define B2055_C2_TX_RF_CNTPAD1 0xAC /* Core 2 TX RF counter PAD 1 */ +#define B2055_C2_TX_RF_PGAIDAC 0xAD /* Core 2 TX RF PGA IDAC */ +#define B2055_C2_TX_PGAPADTN 0xAE /* Core 2 TX PGA PAD TN */ +#define B2055_C2_TX_PADIDAC1 0xAF /* Core 2 TX PAD IDAC 1 */ +#define B2055_C2_TX_PADIDAC2 0xB0 /* Core 2 TX PAD IDAC 2 */ +#define B2055_C2_TX_MXBGTRIM 0xB1 /* Core 2 TX MX B/G TRIM */ +#define B2055_C2_TX_RF_RCAL 0xB2 /* Core 2 TX RF RCAL */ +#define B2055_C2_TX_RF_PADTSSI1 0xB3 /* Core 2 TX RF PAD TSSI1 */ +#define B2055_C2_TX_RF_PADTSSI2 0xB4 /* Core 2 TX RF PAD TSSI2 */ +#define B2055_C2_TX_RF_SPARE 0xB5 /* Core 2 TX RF spare */ +#define B2055_C2_TX_RF_IQCAL1 0xB6 /* Core 2 TX RF I/Q CAL 1 */ +#define B2055_C2_TX_RF_IQCAL2 0xB7 /* Core 2 TX RF I/Q CAL 2 */ +#define B2055_C2_TXBB_RCCAL 0xB8 /* Core 2 TXBB RC CAL Control */ +#define B2055_C2_TXBB_LPF1 0xB9 /* Core 2 TXBB LPF 1 */ +#define B2055_C2_TX_VOSCNCL 0xBA /* Core 2 TX VOS CNCL */ +#define B2055_C2_TX_LPF_MXGMIDAC 0xBB /* Core 2 TX LPF MXGM IDAC */ +#define B2055_C2_TX_BB_MXGM 0xBC /* Core 2 TX BB MXGM */ +#define B2055_PRG_GCHP21 0xBD /* PRG GC HPVGA23 21 */ +#define B2055_PRG_GCHP22 0xBE /* PRG GC HPVGA23 22 */ +#define B2055_PRG_GCHP23 0xBF /* PRG GC HPVGA23 23 */ +#define B2055_PRG_GCHP24 0xC0 /* PRG GC HPVGA23 24 */ +#define B2055_PRG_GCHP25 0xC1 /* PRG GC HPVGA23 25 */ +#define B2055_PRG_GCHP26 0xC2 /* PRG GC HPVGA23 26 */ +#define B2055_PRG_GCHP27 0xC3 /* PRG GC HPVGA23 27 */ +#define B2055_PRG_GCHP28 0xC4 /* PRG GC HPVGA23 28 */ +#define B2055_PRG_GCHP29 0xC5 /* PRG GC HPVGA23 29 */ +#define B2055_PRG_GCHP30 0xC6 /* PRG GC HPVGA23 30 */ +#define B2055_C1_LNA_GAINBST 0xCD /* Core 1 LNA GAINBST */ +#define B2055_C1_B0NB_RSSIVCM 0xD2 /* Core 1 B0 narrow-band RSSI VCM */ +#define B2055_C1_GENSPARE2 0xD6 /* Core 1 GEN spare 2 */ +#define B2055_C2_LNA_GAINBST 0xD9 /* Core 2 LNA GAINBST */ +#define B2055_C2_B0NB_RSSIVCM 0xDE /* Core 2 B0 narrow-band RSSI VCM */ +#define B2055_C2_GENSPARE2 0xE2 /* Core 2 GEN spare 2 */ + +struct b43_nphy_channeltab_entry_rev2 { + /* The channel number */ + u8 channel; + /* The channel frequency in MHz */ + u16 freq; + /* An unknown value */ + u16 unk2; + /* Radio register values on channelswitch */ + u8 radio_pll_ref; + u8 radio_rf_pllmod0; + u8 radio_rf_pllmod1; + u8 radio_vco_captail; + u8 radio_vco_cal1; + u8 radio_vco_cal2; + u8 radio_pll_lfc1; + u8 radio_pll_lfr1; + u8 radio_pll_lfc2; + u8 radio_lgbuf_cenbuf; + u8 radio_lgen_tune1; + u8 radio_lgen_tune2; + u8 radio_c1_lgbuf_atune; + u8 radio_c1_lgbuf_gtune; + u8 radio_c1_rx_rfr1; + u8 radio_c1_tx_pgapadtn; + u8 radio_c1_tx_mxbgtrim; + u8 radio_c2_lgbuf_atune; + u8 radio_c2_lgbuf_gtune; + u8 radio_c2_rx_rfr1; + u8 radio_c2_tx_pgapadtn; + u8 radio_c2_tx_mxbgtrim; + /* PHY register values on channelswitch */ + struct b43_phy_n_sfo_cfg phy_regs; +}; + +/* Upload the default register value table. + * If "ghz5" is true, we upload the 5Ghz table. Otherwise the 2.4Ghz + * table is uploaded. If "ignore_uploadflag" is true, we upload any value + * and ignore the "UPLOAD" flag. */ +void b2055_upload_inittab(struct b43_wldev *dev, + bool ghz5, bool ignore_uploadflag); + +#endif /* B43_RADIO_2055_H_ */ diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c index e74b8eb5..cff7bd3 100644 --- a/drivers/net/wireless/b43/tables_nphy.c +++ b/drivers/net/wireless/b43/tables_nphy.c @@ -27,1314 +27,6 @@ #include "phy_common.h" #include "phy_n.h" - -struct b2055_inittab_entry { - /* Value to write if we use the 5GHz band. */ - u16 ghz5; - /* Value to write if we use the 2.4GHz band. */ - u16 ghz2; - /* Flags */ - u8 flags; -#define B2055_INITTAB_ENTRY_OK 0x01 -#define B2055_INITTAB_UPLOAD 0x02 -}; -#define UPLOAD .flags = B2055_INITTAB_ENTRY_OK | B2055_INITTAB_UPLOAD -#define NOUPLOAD .flags = B2055_INITTAB_ENTRY_OK - -static const struct b2055_inittab_entry b2055_inittab [] = { - [B2055_SP_PINPD] = { .ghz5 = 0x0080, .ghz2 = 0x0080, NOUPLOAD, }, - [B2055_C1_SP_RSSI] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_C1_SP_PDMISC] = { .ghz5 = 0x0027, .ghz2 = 0x0027, NOUPLOAD, }, - [B2055_C2_SP_RSSI] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_C2_SP_PDMISC] = { .ghz5 = 0x0027, .ghz2 = 0x0027, NOUPLOAD, }, - [B2055_C1_SP_RXGC1] = { .ghz5 = 0x007F, .ghz2 = 0x007F, UPLOAD, }, - [B2055_C1_SP_RXGC2] = { .ghz5 = 0x0007, .ghz2 = 0x0007, UPLOAD, }, - [B2055_C2_SP_RXGC1] = { .ghz5 = 0x007F, .ghz2 = 0x007F, UPLOAD, }, - [B2055_C2_SP_RXGC2] = { .ghz5 = 0x0007, .ghz2 = 0x0007, UPLOAD, }, - [B2055_C1_SP_LPFBWSEL] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, }, - [B2055_C2_SP_LPFBWSEL] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, }, - [B2055_C1_SP_TXGC1] = { .ghz5 = 0x004F, .ghz2 = 0x004F, UPLOAD, }, - [B2055_C1_SP_TXGC2] = { .ghz5 = 0x0005, .ghz2 = 0x0005, UPLOAD, }, - [B2055_C2_SP_TXGC1] = { .ghz5 = 0x004F, .ghz2 = 0x004F, UPLOAD, }, - [B2055_C2_SP_TXGC2] = { .ghz5 = 0x0005, .ghz2 = 0x0005, UPLOAD, }, - [B2055_MASTER1] = { .ghz5 = 0x00D0, .ghz2 = 0x00D0, NOUPLOAD, }, - [B2055_MASTER2] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, }, - [B2055_PD_LGEN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_PD_PLLTS] = { .ghz5 = 0x0040, .ghz2 = 0x0040, NOUPLOAD, }, - [B2055_C1_PD_LGBUF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_C1_PD_TX] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_C1_PD_RXTX] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_C1_PD_RSSIMISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_C2_PD_LGBUF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_C2_PD_TX] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_C2_PD_RXTX] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_C2_PD_RSSIMISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_PWRDET_LGEN] = { .ghz5 = 0x00C0, .ghz2 = 0x00C0, NOUPLOAD, }, - [B2055_C1_PWRDET_LGBUF] = { .ghz5 = 0x00FF, .ghz2 = 0x00FF, NOUPLOAD, }, - [B2055_C1_PWRDET_RXTX] = { .ghz5 = 0x00C0, .ghz2 = 0x00C0, NOUPLOAD, }, - [B2055_C2_PWRDET_LGBUF] = { .ghz5 = 0x00FF, .ghz2 = 0x00FF, NOUPLOAD, }, - [B2055_C2_PWRDET_RXTX] = { .ghz5 = 0x00C0, .ghz2 = 0x00C0, NOUPLOAD, }, - [B2055_RRCCAL_CS] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_RRCCAL_NOPTSEL] = { .ghz5 = 0x002C, .ghz2 = 0x002C, NOUPLOAD, }, - [B2055_CAL_MISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_CAL_COUT] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_CAL_COUT2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_CAL_CVARCTL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_CAL_RVARCTL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_CAL_LPOCTL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_CAL_TS] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_CAL_RCCALRTS] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_CAL_RCALRTS] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_PADDRV] = { .ghz5 = 0x00A4, .ghz2 = 0x00A4, NOUPLOAD, }, - [B2055_XOCTL1] = { .ghz5 = 0x0038, .ghz2 = 0x0038, NOUPLOAD, }, - [B2055_XOCTL2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_XOREGUL] = { .ghz5 = 0x0004, .ghz2 = 0x0004, UPLOAD, }, - [B2055_XOMISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_PLL_LFC1] = { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, }, - [B2055_PLL_CALVTH] = { .ghz5 = 0x0087, .ghz2 = 0x0087, NOUPLOAD, }, - [B2055_PLL_LFC2] = { .ghz5 = 0x0009, .ghz2 = 0x0009, NOUPLOAD, }, - [B2055_PLL_REF] = { .ghz5 = 0x0070, .ghz2 = 0x0070, NOUPLOAD, }, - [B2055_PLL_LFR1] = { .ghz5 = 0x0011, .ghz2 = 0x0011, NOUPLOAD, }, - [B2055_PLL_PFDCP] = { .ghz5 = 0x0018, .ghz2 = 0x0018, UPLOAD, }, - [B2055_PLL_IDAC_CPOPAMP] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, - [B2055_PLL_CPREG] = { .ghz5 = 0x0004, .ghz2 = 0x0004, UPLOAD, }, - [B2055_PLL_RCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, - [B2055_RF_PLLMOD0] = { .ghz5 = 0x009E, .ghz2 = 0x009E, NOUPLOAD, }, - [B2055_RF_PLLMOD1] = { .ghz5 = 0x0009, .ghz2 = 0x0009, NOUPLOAD, }, - [B2055_RF_MMDIDAC1] = { .ghz5 = 0x00C8, .ghz2 = 0x00C8, UPLOAD, }, - [B2055_RF_MMDIDAC0] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, - [B2055_RF_MMDSP] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_VCO_CAL1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_VCO_CAL2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_VCO_CAL3] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, }, - [B2055_VCO_CAL4] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, }, - [B2055_VCO_CAL5] = { .ghz5 = 0x0096, .ghz2 = 0x0096, NOUPLOAD, }, - [B2055_VCO_CAL6] = { .ghz5 = 0x003E, .ghz2 = 0x003E, NOUPLOAD, }, - [B2055_VCO_CAL7] = { .ghz5 = 0x003E, .ghz2 = 0x003E, NOUPLOAD, }, - [B2055_VCO_CAL8] = { .ghz5 = 0x0013, .ghz2 = 0x0013, NOUPLOAD, }, - [B2055_VCO_CAL9] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, }, - [B2055_VCO_CAL10] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, }, - [B2055_VCO_CAL11] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, }, - [B2055_VCO_CAL12] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_VCO_CAL13] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_VCO_CAL14] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_VCO_CAL15] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_VCO_CAL16] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_VCO_KVCO] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, }, - [B2055_VCO_CAPTAIL] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, }, - [B2055_VCO_IDACVCO] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, - [B2055_VCO_REG] = { .ghz5 = 0x0084, .ghz2 = 0x0084, UPLOAD, }, - [B2055_PLL_RFVTH] = { .ghz5 = 0x00C3, .ghz2 = 0x00C3, NOUPLOAD, }, - [B2055_LGBUF_CENBUF] = { .ghz5 = 0x008F, .ghz2 = 0x008F, NOUPLOAD, }, - [B2055_LGEN_TUNE1] = { .ghz5 = 0x00FF, .ghz2 = 0x00FF, NOUPLOAD, }, - [B2055_LGEN_TUNE2] = { .ghz5 = 0x00FF, .ghz2 = 0x00FF, NOUPLOAD, }, - [B2055_LGEN_IDAC1] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, - [B2055_LGEN_IDAC2] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, - [B2055_LGEN_BIASC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_LGEN_BIASIDAC] = { .ghz5 = 0x00CC, .ghz2 = 0x00CC, NOUPLOAD, }, - [B2055_LGEN_RCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, - [B2055_LGEN_DIV] = { .ghz5 = 0x0080, .ghz2 = 0x0080, NOUPLOAD, }, - [B2055_LGEN_SPARE2] = { .ghz5 = 0x0080, .ghz2 = 0x0080, NOUPLOAD, }, - [B2055_C1_LGBUF_ATUNE] = { .ghz5 = 0x00F8, .ghz2 = 0x00F8, NOUPLOAD, }, - [B2055_C1_LGBUF_GTUNE] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, - [B2055_C1_LGBUF_DIV] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, - [B2055_C1_LGBUF_AIDAC] = { .ghz5 = 0x0088, .ghz2 = 0x0008, UPLOAD, }, - [B2055_C1_LGBUF_GIDAC] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, - [B2055_C1_LGBUF_IDACFO] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_C1_LGBUF_SPARE] = { .ghz5 = 0x0001, .ghz2 = 0x0001, UPLOAD, }, - [B2055_C1_RX_RFSPC1] = { .ghz5 = 0x008A, .ghz2 = 0x008A, NOUPLOAD, }, - [B2055_C1_RX_RFR1] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, }, - [B2055_C1_RX_RFR2] = { .ghz5 = 0x0083, .ghz2 = 0x0083, NOUPLOAD, }, - [B2055_C1_RX_RFRCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, - [B2055_C1_RX_BB_BLCMP] = { .ghz5 = 0x00A0, .ghz2 = 0x00A0, NOUPLOAD, }, - [B2055_C1_RX_BB_LPF] = { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, }, - [B2055_C1_RX_BB_MIDACHP] = { .ghz5 = 0x0087, .ghz2 = 0x0087, UPLOAD, }, - [B2055_C1_RX_BB_VGA1IDAC] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, }, - [B2055_C1_RX_BB_VGA2IDAC] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, }, - [B2055_C1_RX_BB_VGA3IDAC] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, }, - [B2055_C1_RX_BB_BUFOCTL] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, }, - [B2055_C1_RX_BB_RCCALCTL] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, }, - [B2055_C1_RX_BB_RSSICTL1] = { .ghz5 = 0x006A, .ghz2 = 0x006A, UPLOAD, }, - [B2055_C1_RX_BB_RSSICTL2] = { .ghz5 = 0x00AB, .ghz2 = 0x00AB, UPLOAD, }, - [B2055_C1_RX_BB_RSSICTL3] = { .ghz5 = 0x0013, .ghz2 = 0x0013, UPLOAD, }, - [B2055_C1_RX_BB_RSSICTL4] = { .ghz5 = 0x00C1, .ghz2 = 0x00C1, UPLOAD, }, - [B2055_C1_RX_BB_RSSICTL5] = { .ghz5 = 0x00AA, .ghz2 = 0x00AA, UPLOAD, }, - [B2055_C1_RX_BB_REG] = { .ghz5 = 0x0087, .ghz2 = 0x0087, UPLOAD, }, - [B2055_C1_RX_BB_SPARE1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_C1_RX_TXBBRCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, - [B2055_C1_TX_RF_SPGA] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, }, - [B2055_C1_TX_RF_SPAD] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, }, - [B2055_C1_TX_RF_CNTPGA1] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, }, - [B2055_C1_TX_RF_CNTPAD1] = { .ghz5 = 0x0055, .ghz2 = 0x0055, NOUPLOAD, }, - [B2055_C1_TX_RF_PGAIDAC] = { .ghz5 = 0x0097, .ghz2 = 0x0097, UPLOAD, }, - [B2055_C1_TX_PGAPADTN] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, }, - [B2055_C1_TX_PADIDAC1] = { .ghz5 = 0x0014, .ghz2 = 0x0014, UPLOAD, }, - [B2055_C1_TX_PADIDAC2] = { .ghz5 = 0x0033, .ghz2 = 0x0033, NOUPLOAD, }, - [B2055_C1_TX_MXBGTRIM] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, - [B2055_C1_TX_RF_RCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, - [B2055_C1_TX_RF_PADTSSI1] = { .ghz5 = 0x0003, .ghz2 = 0x0003, UPLOAD, }, - [B2055_C1_TX_RF_PADTSSI2] = { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, }, - [B2055_C1_TX_RF_SPARE] = { .ghz5 = 0x0003, .ghz2 = 0x0003, UPLOAD, }, - [B2055_C1_TX_RF_IQCAL1] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, }, - [B2055_C1_TX_RF_IQCAL2] = { .ghz5 = 0x00A4, .ghz2 = 0x00A4, NOUPLOAD, }, - [B2055_C1_TXBB_RCCAL] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, }, - [B2055_C1_TXBB_LPF1] = { .ghz5 = 0x0028, .ghz2 = 0x0028, NOUPLOAD, }, - [B2055_C1_TX_VOSCNCL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_C1_TX_LPF_MXGMIDAC] = { .ghz5 = 0x004A, .ghz2 = 0x004A, NOUPLOAD, }, - [B2055_C1_TX_BB_MXGM] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_C2_LGBUF_ATUNE] = { .ghz5 = 0x00F8, .ghz2 = 0x00F8, NOUPLOAD, }, - [B2055_C2_LGBUF_GTUNE] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, - [B2055_C2_LGBUF_DIV] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, - [B2055_C2_LGBUF_AIDAC] = { .ghz5 = 0x0088, .ghz2 = 0x0008, UPLOAD, }, - [B2055_C2_LGBUF_GIDAC] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, - [B2055_C2_LGBUF_IDACFO] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_C2_LGBUF_SPARE] = { .ghz5 = 0x0001, .ghz2 = 0x0001, UPLOAD, }, - [B2055_C2_RX_RFSPC1] = { .ghz5 = 0x008A, .ghz2 = 0x008A, NOUPLOAD, }, - [B2055_C2_RX_RFR1] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, }, - [B2055_C2_RX_RFR2] = { .ghz5 = 0x0083, .ghz2 = 0x0083, NOUPLOAD, }, - [B2055_C2_RX_RFRCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, - [B2055_C2_RX_BB_BLCMP] = { .ghz5 = 0x00A0, .ghz2 = 0x00A0, NOUPLOAD, }, - [B2055_C2_RX_BB_LPF] = { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, }, - [B2055_C2_RX_BB_MIDACHP] = { .ghz5 = 0x0087, .ghz2 = 0x0087, UPLOAD, }, - [B2055_C2_RX_BB_VGA1IDAC] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, }, - [B2055_C2_RX_BB_VGA2IDAC] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, }, - [B2055_C2_RX_BB_VGA3IDAC] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, }, - [B2055_C2_RX_BB_BUFOCTL] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, }, - [B2055_C2_RX_BB_RCCALCTL] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, }, - [B2055_C2_RX_BB_RSSICTL1] = { .ghz5 = 0x006A, .ghz2 = 0x006A, UPLOAD, }, - [B2055_C2_RX_BB_RSSICTL2] = { .ghz5 = 0x00AB, .ghz2 = 0x00AB, UPLOAD, }, - [B2055_C2_RX_BB_RSSICTL3] = { .ghz5 = 0x0013, .ghz2 = 0x0013, UPLOAD, }, - [B2055_C2_RX_BB_RSSICTL4] = { .ghz5 = 0x00C1, .ghz2 = 0x00C1, UPLOAD, }, - [B2055_C2_RX_BB_RSSICTL5] = { .ghz5 = 0x00AA, .ghz2 = 0x00AA, UPLOAD, }, - [B2055_C2_RX_BB_REG] = { .ghz5 = 0x0087, .ghz2 = 0x0087, UPLOAD, }, - [B2055_C2_RX_BB_SPARE1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_C2_RX_TXBBRCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, - [B2055_C2_TX_RF_SPGA] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, }, - [B2055_C2_TX_RF_SPAD] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, }, - [B2055_C2_TX_RF_CNTPGA1] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, }, - [B2055_C2_TX_RF_CNTPAD1] = { .ghz5 = 0x0055, .ghz2 = 0x0055, NOUPLOAD, }, - [B2055_C2_TX_RF_PGAIDAC] = { .ghz5 = 0x0097, .ghz2 = 0x0097, UPLOAD, }, - [B2055_C2_TX_PGAPADTN] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, }, - [B2055_C2_TX_PADIDAC1] = { .ghz5 = 0x0014, .ghz2 = 0x0014, UPLOAD, }, - [B2055_C2_TX_PADIDAC2] = { .ghz5 = 0x0033, .ghz2 = 0x0033, NOUPLOAD, }, - [B2055_C2_TX_MXBGTRIM] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, - [B2055_C2_TX_RF_RCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, - [B2055_C2_TX_RF_PADTSSI1] = { .ghz5 = 0x0003, .ghz2 = 0x0003, UPLOAD, }, - [B2055_C2_TX_RF_PADTSSI2] = { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, }, - [B2055_C2_TX_RF_SPARE] = { .ghz5 = 0x0003, .ghz2 = 0x0003, UPLOAD, }, - [B2055_C2_TX_RF_IQCAL1] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, }, - [B2055_C2_TX_RF_IQCAL2] = { .ghz5 = 0x00A4, .ghz2 = 0x00A4, NOUPLOAD, }, - [B2055_C2_TXBB_RCCAL] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, }, - [B2055_C2_TXBB_LPF1] = { .ghz5 = 0x0028, .ghz2 = 0x0028, NOUPLOAD, }, - [B2055_C2_TX_VOSCNCL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_C2_TX_LPF_MXGMIDAC] = { .ghz5 = 0x004A, .ghz2 = 0x004A, NOUPLOAD, }, - [B2055_C2_TX_BB_MXGM] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_PRG_GCHP21] = { .ghz5 = 0x0071, .ghz2 = 0x0071, NOUPLOAD, }, - [B2055_PRG_GCHP22] = { .ghz5 = 0x0072, .ghz2 = 0x0072, NOUPLOAD, }, - [B2055_PRG_GCHP23] = { .ghz5 = 0x0073, .ghz2 = 0x0073, NOUPLOAD, }, - [B2055_PRG_GCHP24] = { .ghz5 = 0x0074, .ghz2 = 0x0074, NOUPLOAD, }, - [B2055_PRG_GCHP25] = { .ghz5 = 0x0075, .ghz2 = 0x0075, NOUPLOAD, }, - [B2055_PRG_GCHP26] = { .ghz5 = 0x0076, .ghz2 = 0x0076, NOUPLOAD, }, - [B2055_PRG_GCHP27] = { .ghz5 = 0x0077, .ghz2 = 0x0077, NOUPLOAD, }, - [B2055_PRG_GCHP28] = { .ghz5 = 0x0078, .ghz2 = 0x0078, NOUPLOAD, }, - [B2055_PRG_GCHP29] = { .ghz5 = 0x0079, .ghz2 = 0x0079, NOUPLOAD, }, - [B2055_PRG_GCHP30] = { .ghz5 = 0x007A, .ghz2 = 0x007A, NOUPLOAD, }, - [0xC7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [0xC8] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [0xC9] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [0xCA] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [0xCB] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [0xCC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_C1_LNA_GAINBST] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [0xCE] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [0xCF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [0xD0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [0xD1] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, }, - [B2055_C1_B0NB_RSSIVCM] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, - [0xD3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [0xD4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [0xD5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_C1_GENSPARE2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [0xD7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [0xD8] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_C2_LNA_GAINBST] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [0xDA] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [0xDB] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [0xDC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [0xDD] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, }, - [B2055_C2_B0NB_RSSIVCM] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, - [0xDF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [0xE0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [0xE1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [B2055_C2_GENSPARE2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, -}; - - -void b2055_upload_inittab(struct b43_wldev *dev, - bool ghz5, bool ignore_uploadflag) -{ - const struct b2055_inittab_entry *e; - unsigned int i; - u16 value; - - for (i = 0; i < ARRAY_SIZE(b2055_inittab); i++) { - e = &(b2055_inittab[i]); - if (!(e->flags & B2055_INITTAB_ENTRY_OK)) - continue; - if ((e->flags & B2055_INITTAB_UPLOAD) || ignore_uploadflag) { - if (ghz5) - value = e->ghz5; - else - value = e->ghz2; - b43_radio_write16(dev, i, value); - } - } -} - - -#define RADIOREGS(r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, \ - r12, r13, r14, r15, r16, r17, r18, r19, r20, r21) \ - .radio_pll_ref = r0, \ - .radio_rf_pllmod0 = r1, \ - .radio_rf_pllmod1 = r2, \ - .radio_vco_captail = r3, \ - .radio_vco_cal1 = r4, \ - .radio_vco_cal2 = r5, \ - .radio_pll_lfc1 = r6, \ - .radio_pll_lfr1 = r7, \ - .radio_pll_lfc2 = r8, \ - .radio_lgbuf_cenbuf = r9, \ - .radio_lgen_tune1 = r10, \ - .radio_lgen_tune2 = r11, \ - .radio_c1_lgbuf_atune = r12, \ - .radio_c1_lgbuf_gtune = r13, \ - .radio_c1_rx_rfr1 = r14, \ - .radio_c1_tx_pgapadtn = r15, \ - .radio_c1_tx_mxbgtrim = r16, \ - .radio_c2_lgbuf_atune = r17, \ - .radio_c2_lgbuf_gtune = r18, \ - .radio_c2_rx_rfr1 = r19, \ - .radio_c2_tx_pgapadtn = r20, \ - .radio_c2_tx_mxbgtrim = r21 - -#define PHYREGS(r0, r1, r2, r3, r4, r5) \ - .phy_regs.phy_bw1a = r0, \ - .phy_regs.phy_bw2 = r1, \ - .phy_regs.phy_bw3 = r2, \ - .phy_regs.phy_bw4 = r3, \ - .phy_regs.phy_bw5 = r4, \ - .phy_regs.phy_bw6 = r5 - -static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = { - { .channel = 184, - .freq = 4920, /* MHz */ - .unk2 = 3280, - RADIOREGS(0x71, 0x01, 0xEC, 0x0F, 0xFF, 0x01, 0x04, 0x0A, - 0x00, 0x8F, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x0F, - 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), - PHYREGS(0xB407, 0xB007, 0xAC07, 0x1402, 0x1502, 0x1602), - }, - { .channel = 186, - .freq = 4930, /* MHz */ - .unk2 = 3287, - RADIOREGS(0x71, 0x01, 0xED, 0x0F, 0xFF, 0x01, 0x04, 0x0A, - 0x00, 0x8F, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x0F, - 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), - PHYREGS(0xB807, 0xB407, 0xB007, 0x1302, 0x1402, 0x1502), - }, - { .channel = 188, - .freq = 4940, /* MHz */ - .unk2 = 3293, - RADIOREGS(0x71, 0x01, 0xEE, 0x0F, 0xFF, 0x01, 0x04, 0x0A, - 0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F, - 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), - PHYREGS(0xBC07, 0xB807, 0xB407, 0x1202, 0x1302, 0x1402), - }, - { .channel = 190, - .freq = 4950, /* MHz */ - .unk2 = 3300, - RADIOREGS(0x71, 0x01, 0xEF, 0x0F, 0xFF, 0x01, 0x04, 0x0A, - 0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F, - 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), - PHYREGS(0xC007, 0xBC07, 0xB807, 0x1102, 0x1202, 0x1302), - }, - { .channel = 192, - .freq = 4960, /* MHz */ - .unk2 = 3307, - RADIOREGS(0x71, 0x01, 0xF0, 0x0F, 0xFF, 0x01, 0x04, 0x0A, - 0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F, - 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), - PHYREGS(0xC407, 0xC007, 0xBC07, 0x0F02, 0x1102, 0x1202), - }, - { .channel = 194, - .freq = 4970, /* MHz */ - .unk2 = 3313, - RADIOREGS(0x71, 0x01, 0xF1, 0x0F, 0xFF, 0x01, 0x04, 0x0A, - 0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F, - 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), - PHYREGS(0xC807, 0xC407, 0xC007, 0x0E02, 0x0F02, 0x1102), - }, - { .channel = 196, - .freq = 4980, /* MHz */ - .unk2 = 3320, - RADIOREGS(0x71, 0x01, 0xF2, 0x0E, 0xFF, 0x01, 0x04, 0x0A, - 0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F, - 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), - PHYREGS(0xCC07, 0xC807, 0xC407, 0x0D02, 0x0E02, 0x0F02), - }, - { .channel = 198, - .freq = 4990, /* MHz */ - .unk2 = 3327, - RADIOREGS(0x71, 0x01, 0xF3, 0x0E, 0xFF, 0x01, 0x04, 0x0A, - 0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F, - 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), - PHYREGS(0xD007, 0xCC07, 0xC807, 0x0C02, 0x0D02, 0x0E02), - }, - { .channel = 200, - .freq = 5000, /* MHz */ - .unk2 = 3333, - RADIOREGS(0x71, 0x01, 0xF4, 0x0E, 0xFF, 0x01, 0x04, 0x0A, - 0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F, - 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), - PHYREGS(0xD407, 0xD007, 0xCC07, 0x0B02, 0x0C02, 0x0D02), - }, - { .channel = 202, - .freq = 5010, /* MHz */ - .unk2 = 3340, - RADIOREGS(0x71, 0x01, 0xF5, 0x0E, 0xFF, 0x01, 0x04, 0x0A, - 0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F, - 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), - PHYREGS(0xD807, 0xD407, 0xD007, 0x0A02, 0x0B02, 0x0C02), - }, - { .channel = 204, - .freq = 5020, /* MHz */ - .unk2 = 3347, - RADIOREGS(0x71, 0x01, 0xF6, 0x0E, 0xF7, 0x01, 0x04, 0x0A, - 0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F, - 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), - PHYREGS(0xDC07, 0xD807, 0xD407, 0x0902, 0x0A02, 0x0B02), - }, - { .channel = 206, - .freq = 5030, /* MHz */ - .unk2 = 3353, - RADIOREGS(0x71, 0x01, 0xF7, 0x0E, 0xF7, 0x01, 0x04, 0x0A, - 0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F, - 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), - PHYREGS(0xE007, 0xDC07, 0xD807, 0x0802, 0x0902, 0x0A02), - }, - { .channel = 208, - .freq = 5040, /* MHz */ - .unk2 = 3360, - RADIOREGS(0x71, 0x01, 0xF8, 0x0D, 0xEF, 0x01, 0x04, 0x0A, - 0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F, - 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), - PHYREGS(0xE407, 0xE007, 0xDC07, 0x0702, 0x0802, 0x0902), - }, - { .channel = 210, - .freq = 5050, /* MHz */ - .unk2 = 3367, - RADIOREGS(0x71, 0x01, 0xF9, 0x0D, 0xEF, 0x01, 0x04, 0x0A, - 0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F, - 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), - PHYREGS(0xE807, 0xE407, 0xE007, 0x0602, 0x0702, 0x0802), - }, - { .channel = 212, - .freq = 5060, /* MHz */ - .unk2 = 3373, - RADIOREGS(0x71, 0x01, 0xFA, 0x0D, 0xE6, 0x01, 0x04, 0x0A, - 0x00, 0x8F, 0xBB, 0xBB, 0xFF, 0x00, 0x0E, 0x0F, - 0x8E, 0xFF, 0x00, 0x0E, 0x0F, 0x8E), - PHYREGS(0xEC07, 0xE807, 0xE407, 0x0502, 0x0602, 0x0702), - }, - { .channel = 214, - .freq = 5070, /* MHz */ - .unk2 = 3380, - RADIOREGS(0x71, 0x01, 0xFB, 0x0D, 0xE6, 0x01, 0x04, 0x0A, - 0x00, 0x8F, 0xBB, 0xBB, 0xFF, 0x00, 0x0E, 0x0F, - 0x8E, 0xFF, 0x00, 0x0E, 0x0F, 0x8E), - PHYREGS(0xF007, 0xEC07, 0xE807, 0x0402, 0x0502, 0x0602), - }, - { .channel = 216, - .freq = 5080, /* MHz */ - .unk2 = 3387, - RADIOREGS(0x71, 0x01, 0xFC, 0x0D, 0xDE, 0x01, 0x04, 0x0A, - 0x00, 0x8E, 0xBB, 0xBB, 0xEE, 0x00, 0x0E, 0x0F, - 0x8D, 0xEE, 0x00, 0x0E, 0x0F, 0x8D), - PHYREGS(0xF407, 0xF007, 0xEC07, 0x0302, 0x0402, 0x0502), - }, - { .channel = 218, - .freq = 5090, /* MHz */ - .unk2 = 3393, - RADIOREGS(0x71, 0x01, 0xFD, 0x0D, 0xDE, 0x01, 0x04, 0x0A, - 0x00, 0x8E, 0xBB, 0xBB, 0xEE, 0x00, 0x0E, 0x0F, - 0x8D, 0xEE, 0x00, 0x0E, 0x0F, 0x8D), - PHYREGS(0xF807, 0xF407, 0xF007, 0x0202, 0x0302, 0x0402), - }, - { .channel = 220, - .freq = 5100, /* MHz */ - .unk2 = 3400, - RADIOREGS(0x71, 0x01, 0xFE, 0x0C, 0xD6, 0x01, 0x04, 0x0A, - 0x00, 0x8E, 0xAA, 0xAA, 0xEE, 0x00, 0x0D, 0x0F, - 0x8D, 0xEE, 0x00, 0x0D, 0x0F, 0x8D), - PHYREGS(0xFC07, 0xF807, 0xF407, 0x0102, 0x0202, 0x0302), - }, - { .channel = 222, - .freq = 5110, /* MHz */ - .unk2 = 3407, - RADIOREGS(0x71, 0x01, 0xFF, 0x0C, 0xD6, 0x01, 0x04, 0x0A, - 0x00, 0x8E, 0xAA, 0xAA, 0xEE, 0x00, 0x0D, 0x0F, - 0x8D, 0xEE, 0x00, 0x0D, 0x0F, 0x8D), - PHYREGS(0x0008, 0xFC07, 0xF807, 0x0002, 0x0102, 0x0202), - }, - { .channel = 224, - .freq = 5120, /* MHz */ - .unk2 = 3413, - RADIOREGS(0x71, 0x02, 0x00, 0x0C, 0xCE, 0x01, 0x04, 0x0A, - 0x00, 0x8D, 0xAA, 0xAA, 0xDD, 0x00, 0x0D, 0x0F, - 0x8C, 0xDD, 0x00, 0x0D, 0x0F, 0x8C), - PHYREGS(0x0408, 0x0008, 0xFC07, 0xFF01, 0x0002, 0x0102), - }, - { .channel = 226, - .freq = 5130, /* MHz */ - .unk2 = 3420, - RADIOREGS(0x71, 0x02, 0x01, 0x0C, 0xCE, 0x01, 0x04, 0x0A, - 0x00, 0x8D, 0xAA, 0xAA, 0xDD, 0x00, 0x0D, 0x0F, - 0x8C, 0xDD, 0x00, 0x0D, 0x0F, 0x8C), - PHYREGS(0x0808, 0x0408, 0x0008, 0xFE01, 0xFF01, 0x0002), - }, - { .channel = 228, - .freq = 5140, /* MHz */ - .unk2 = 3427, - RADIOREGS(0x71, 0x02, 0x02, 0x0C, 0xC6, 0x01, 0x04, 0x0A, - 0x00, 0x8D, 0x99, 0x99, 0xDD, 0x00, 0x0C, 0x0E, - 0x8B, 0xDD, 0x00, 0x0C, 0x0E, 0x8B), - PHYREGS(0x0C08, 0x0808, 0x0408, 0xFD01, 0xFE01, 0xFF01), - }, - { .channel = 32, - .freq = 5160, /* MHz */ - .unk2 = 3440, - RADIOREGS(0x71, 0x02, 0x04, 0x0B, 0xBE, 0x01, 0x04, 0x0A, - 0x00, 0x8C, 0x99, 0x99, 0xCC, 0x00, 0x0B, 0x0D, - 0x8A, 0xCC, 0x00, 0x0B, 0x0D, 0x8A), - PHYREGS(0x1408, 0x1008, 0x0C08, 0xFB01, 0xFC01, 0xFD01), - }, - { .channel = 34, - .freq = 5170, /* MHz */ - .unk2 = 3447, - RADIOREGS(0x71, 0x02, 0x05, 0x0B, 0xBE, 0x01, 0x04, 0x0A, - 0x00, 0x8C, 0x99, 0x99, 0xCC, 0x00, 0x0B, 0x0D, - 0x8A, 0xCC, 0x00, 0x0B, 0x0D, 0x8A), - PHYREGS(0x1808, 0x1408, 0x1008, 0xFA01, 0xFB01, 0xFC01), - }, - { .channel = 36, - .freq = 5180, /* MHz */ - .unk2 = 3453, - RADIOREGS(0x71, 0x02, 0x06, 0x0B, 0xB6, 0x01, 0x04, 0x0A, - 0x00, 0x8C, 0x88, 0x88, 0xCC, 0x00, 0x0B, 0x0C, - 0x89, 0xCC, 0x00, 0x0B, 0x0C, 0x89), - PHYREGS(0x1C08, 0x1808, 0x1408, 0xF901, 0xFA01, 0xFB01), - }, - { .channel = 38, - .freq = 5190, /* MHz */ - .unk2 = 3460, - RADIOREGS(0x71, 0x02, 0x07, 0x0B, 0xB6, 0x01, 0x04, 0x0A, - 0x00, 0x8C, 0x88, 0x88, 0xCC, 0x00, 0x0B, 0x0C, - 0x89, 0xCC, 0x00, 0x0B, 0x0C, 0x89), - PHYREGS(0x2008, 0x1C08, 0x1808, 0xF801, 0xF901, 0xFA01), - }, - { .channel = 40, - .freq = 5200, /* MHz */ - .unk2 = 3467, - RADIOREGS(0x71, 0x02, 0x08, 0x0B, 0xAF, 0x01, 0x04, 0x0A, - 0x00, 0x8B, 0x88, 0x88, 0xBB, 0x00, 0x0A, 0x0B, - 0x89, 0xBB, 0x00, 0x0A, 0x0B, 0x89), - PHYREGS(0x2408, 0x2008, 0x1C08, 0xF701, 0xF801, 0xF901), - }, - { .channel = 42, - .freq = 5210, /* MHz */ - .unk2 = 3473, - RADIOREGS(0x71, 0x02, 0x09, 0x0B, 0xAF, 0x01, 0x04, 0x0A, - 0x00, 0x8B, 0x88, 0x88, 0xBB, 0x00, 0x0A, 0x0B, - 0x89, 0xBB, 0x00, 0x0A, 0x0B, 0x89), - PHYREGS(0x2808, 0x2408, 0x2008, 0xF601, 0xF701, 0xF801), - }, - { .channel = 44, - .freq = 5220, /* MHz */ - .unk2 = 3480, - RADIOREGS(0x71, 0x02, 0x0A, 0x0A, 0xA7, 0x01, 0x04, 0x0A, - 0x00, 0x8B, 0x77, 0x77, 0xBB, 0x00, 0x09, 0x0A, - 0x88, 0xBB, 0x00, 0x09, 0x0A, 0x88), - PHYREGS(0x2C08, 0x2808, 0x2408, 0xF501, 0xF601, 0xF701), - }, - { .channel = 46, - .freq = 5230, /* MHz */ - .unk2 = 3487, - RADIOREGS(0x71, 0x02, 0x0B, 0x0A, 0xA7, 0x01, 0x04, 0x0A, - 0x00, 0x8B, 0x77, 0x77, 0xBB, 0x00, 0x09, 0x0A, - 0x88, 0xBB, 0x00, 0x09, 0x0A, 0x88), - PHYREGS(0x3008, 0x2C08, 0x2808, 0xF401, 0xF501, 0xF601), - }, - { .channel = 48, - .freq = 5240, /* MHz */ - .unk2 = 3493, - RADIOREGS(0x71, 0x02, 0x0C, 0x0A, 0xA0, 0x01, 0x04, 0x0A, - 0x00, 0x8A, 0x77, 0x77, 0xAA, 0x00, 0x09, 0x0A, - 0x87, 0xAA, 0x00, 0x09, 0x0A, 0x87), - PHYREGS(0x3408, 0x3008, 0x2C08, 0xF301, 0xF401, 0xF501), - }, - { .channel = 50, - .freq = 5250, /* MHz */ - .unk2 = 3500, - RADIOREGS(0x71, 0x02, 0x0D, 0x0A, 0xA0, 0x01, 0x04, 0x0A, - 0x00, 0x8A, 0x77, 0x77, 0xAA, 0x00, 0x09, 0x0A, - 0x87, 0xAA, 0x00, 0x09, 0x0A, 0x87), - PHYREGS(0x3808, 0x3408, 0x3008, 0xF201, 0xF301, 0xF401), - }, - { .channel = 52, - .freq = 5260, /* MHz */ - .unk2 = 3507, - RADIOREGS(0x71, 0x02, 0x0E, 0x0A, 0x98, 0x01, 0x04, 0x0A, - 0x00, 0x8A, 0x66, 0x66, 0xAA, 0x00, 0x08, 0x09, - 0x87, 0xAA, 0x00, 0x08, 0x09, 0x87), - PHYREGS(0x3C08, 0x3808, 0x3408, 0xF101, 0xF201, 0xF301), - }, - { .channel = 54, - .freq = 5270, /* MHz */ - .unk2 = 3513, - RADIOREGS(0x71, 0x02, 0x0F, 0x0A, 0x98, 0x01, 0x04, 0x0A, - 0x00, 0x8A, 0x66, 0x66, 0xAA, 0x00, 0x08, 0x09, - 0x87, 0xAA, 0x00, 0x08, 0x09, 0x87), - PHYREGS(0x4008, 0x3C08, 0x3808, 0xF001, 0xF101, 0xF201), - }, - { .channel = 56, - .freq = 5280, /* MHz */ - .unk2 = 3520, - RADIOREGS(0x71, 0x02, 0x10, 0x09, 0x91, 0x01, 0x04, 0x0A, - 0x00, 0x89, 0x66, 0x66, 0x99, 0x00, 0x08, 0x08, - 0x86, 0x99, 0x00, 0x08, 0x08, 0x86), - PHYREGS(0x4408, 0x4008, 0x3C08, 0xF001, 0xF001, 0xF101), - }, - { .channel = 58, - .freq = 5290, /* MHz */ - .unk2 = 3527, - RADIOREGS(0x71, 0x02, 0x11, 0x09, 0x91, 0x01, 0x04, 0x0A, - 0x00, 0x89, 0x66, 0x66, 0x99, 0x00, 0x08, 0x08, - 0x86, 0x99, 0x00, 0x08, 0x08, 0x86), - PHYREGS(0x4808, 0x4408, 0x4008, 0xEF01, 0xF001, 0xF001), - }, - { .channel = 60, - .freq = 5300, /* MHz */ - .unk2 = 3533, - RADIOREGS(0x71, 0x02, 0x12, 0x09, 0x8A, 0x01, 0x04, 0x0A, - 0x00, 0x89, 0x55, 0x55, 0x99, 0x00, 0x08, 0x07, - 0x85, 0x99, 0x00, 0x08, 0x07, 0x85), - PHYREGS(0x4C08, 0x4808, 0x4408, 0xEE01, 0xEF01, 0xF001), - }, - { .channel = 62, - .freq = 5310, /* MHz */ - .unk2 = 3540, - RADIOREGS(0x71, 0x02, 0x13, 0x09, 0x8A, 0x01, 0x04, 0x0A, - 0x00, 0x89, 0x55, 0x55, 0x99, 0x00, 0x08, 0x07, - 0x85, 0x99, 0x00, 0x08, 0x07, 0x85), - PHYREGS(0x5008, 0x4C08, 0x4808, 0xED01, 0xEE01, 0xEF01), - }, - { .channel = 64, - .freq = 5320, /* MHz */ - .unk2 = 3547, - RADIOREGS(0x71, 0x02, 0x14, 0x09, 0x83, 0x01, 0x04, 0x0A, - 0x00, 0x88, 0x55, 0x55, 0x88, 0x00, 0x07, 0x07, - 0x84, 0x88, 0x00, 0x07, 0x07, 0x84), - PHYREGS(0x5408, 0x5008, 0x4C08, 0xEC01, 0xED01, 0xEE01), - }, - { .channel = 66, - .freq = 5330, /* MHz */ - .unk2 = 3553, - RADIOREGS(0x71, 0x02, 0x15, 0x09, 0x83, 0x01, 0x04, 0x0A, - 0x00, 0x88, 0x55, 0x55, 0x88, 0x00, 0x07, 0x07, - 0x84, 0x88, 0x00, 0x07, 0x07, 0x84), - PHYREGS(0x5808, 0x5408, 0x5008, 0xEB01, 0xEC01, 0xED01), - }, - { .channel = 68, - .freq = 5340, /* MHz */ - .unk2 = 3560, - RADIOREGS(0x71, 0x02, 0x16, 0x08, 0x7C, 0x01, 0x04, 0x0A, - 0x00, 0x88, 0x44, 0x44, 0x88, 0x00, 0x07, 0x06, - 0x84, 0x88, 0x00, 0x07, 0x06, 0x84), - PHYREGS(0x5C08, 0x5808, 0x5408, 0xEA01, 0xEB01, 0xEC01), - }, - { .channel = 70, - .freq = 5350, /* MHz */ - .unk2 = 3567, - RADIOREGS(0x71, 0x02, 0x17, 0x08, 0x7C, 0x01, 0x04, 0x0A, - 0x00, 0x88, 0x44, 0x44, 0x88, 0x00, 0x07, 0x06, - 0x84, 0x88, 0x00, 0x07, 0x06, 0x84), - PHYREGS(0x6008, 0x5C08, 0x5808, 0xE901, 0xEA01, 0xEB01), - }, - { .channel = 72, - .freq = 5360, /* MHz */ - .unk2 = 3573, - RADIOREGS(0x71, 0x02, 0x18, 0x08, 0x75, 0x01, 0x04, 0x0A, - 0x00, 0x87, 0x44, 0x44, 0x77, 0x00, 0x06, 0x05, - 0x83, 0x77, 0x00, 0x06, 0x05, 0x83), - PHYREGS(0x6408, 0x6008, 0x5C08, 0xE801, 0xE901, 0xEA01), - }, - { .channel = 74, - .freq = 5370, /* MHz */ - .unk2 = 3580, - RADIOREGS(0x71, 0x02, 0x19, 0x08, 0x75, 0x01, 0x04, 0x0A, - 0x00, 0x87, 0x44, 0x44, 0x77, 0x00, 0x06, 0x05, - 0x83, 0x77, 0x00, 0x06, 0x05, 0x83), - PHYREGS(0x6808, 0x6408, 0x6008, 0xE701, 0xE801, 0xE901), - }, - { .channel = 76, - .freq = 5380, /* MHz */ - .unk2 = 3587, - RADIOREGS(0x71, 0x02, 0x1A, 0x08, 0x6E, 0x01, 0x04, 0x0A, - 0x00, 0x87, 0x33, 0x33, 0x77, 0x00, 0x06, 0x04, - 0x82, 0x77, 0x00, 0x06, 0x04, 0x82), - PHYREGS(0x6C08, 0x6808, 0x6408, 0xE601, 0xE701, 0xE801), - }, - { .channel = 78, - .freq = 5390, /* MHz */ - .unk2 = 3593, - RADIOREGS(0x71, 0x02, 0x1B, 0x08, 0x6E, 0x01, 0x04, 0x0A, - 0x00, 0x87, 0x33, 0x33, 0x77, 0x00, 0x06, 0x04, - 0x82, 0x77, 0x00, 0x06, 0x04, 0x82), - PHYREGS(0x7008, 0x6C08, 0x6808, 0xE501, 0xE601, 0xE701), - }, - { .channel = 80, - .freq = 5400, /* MHz */ - .unk2 = 3600, - RADIOREGS(0x71, 0x02, 0x1C, 0x07, 0x67, 0x01, 0x04, 0x0A, - 0x00, 0x86, 0x33, 0x33, 0x66, 0x00, 0x05, 0x04, - 0x81, 0x66, 0x00, 0x05, 0x04, 0x81), - PHYREGS(0x7408, 0x7008, 0x6C08, 0xE501, 0xE501, 0xE601), - }, - { .channel = 82, - .freq = 5410, /* MHz */ - .unk2 = 3607, - RADIOREGS(0x71, 0x02, 0x1D, 0x07, 0x67, 0x01, 0x04, 0x0A, - 0x00, 0x86, 0x33, 0x33, 0x66, 0x00, 0x05, 0x04, - 0x81, 0x66, 0x00, 0x05, 0x04, 0x81), - PHYREGS(0x7808, 0x7408, 0x7008, 0xE401, 0xE501, 0xE501), - }, - { .channel = 84, - .freq = 5420, /* MHz */ - .unk2 = 3613, - RADIOREGS(0x71, 0x02, 0x1E, 0x07, 0x61, 0x01, 0x04, 0x0A, - 0x00, 0x86, 0x22, 0x22, 0x66, 0x00, 0x05, 0x03, - 0x80, 0x66, 0x00, 0x05, 0x03, 0x80), - PHYREGS(0x7C08, 0x7808, 0x7408, 0xE301, 0xE401, 0xE501), - }, - { .channel = 86, - .freq = 5430, /* MHz */ - .unk2 = 3620, - RADIOREGS(0x71, 0x02, 0x1F, 0x07, 0x61, 0x01, 0x04, 0x0A, - 0x00, 0x86, 0x22, 0x22, 0x66, 0x00, 0x05, 0x03, - 0x80, 0x66, 0x00, 0x05, 0x03, 0x80), - PHYREGS(0x8008, 0x7C08, 0x7808, 0xE201, 0xE301, 0xE401), - }, - { .channel = 88, - .freq = 5440, /* MHz */ - .unk2 = 3627, - RADIOREGS(0x71, 0x02, 0x20, 0x07, 0x5A, 0x01, 0x04, 0x0A, - 0x00, 0x85, 0x22, 0x22, 0x55, 0x00, 0x04, 0x02, - 0x80, 0x55, 0x00, 0x04, 0x02, 0x80), - PHYREGS(0x8408, 0x8008, 0x7C08, 0xE101, 0xE201, 0xE301), - }, - { .channel = 90, - .freq = 5450, /* MHz */ - .unk2 = 3633, - RADIOREGS(0x71, 0x02, 0x21, 0x07, 0x5A, 0x01, 0x04, 0x0A, - 0x00, 0x85, 0x22, 0x22, 0x55, 0x00, 0x04, 0x02, - 0x80, 0x55, 0x00, 0x04, 0x02, 0x80), - PHYREGS(0x8808, 0x8408, 0x8008, 0xE001, 0xE101, 0xE201), - }, - { .channel = 92, - .freq = 5460, /* MHz */ - .unk2 = 3640, - RADIOREGS(0x71, 0x02, 0x22, 0x06, 0x53, 0x01, 0x04, 0x0A, - 0x00, 0x85, 0x11, 0x11, 0x55, 0x00, 0x04, 0x01, - 0x80, 0x55, 0x00, 0x04, 0x01, 0x80), - PHYREGS(0x8C08, 0x8808, 0x8408, 0xDF01, 0xE001, 0xE101), - }, - { .channel = 94, - .freq = 5470, /* MHz */ - .unk2 = 3647, - RADIOREGS(0x71, 0x02, 0x23, 0x06, 0x53, 0x01, 0x04, 0x0A, - 0x00, 0x85, 0x11, 0x11, 0x55, 0x00, 0x04, 0x01, - 0x80, 0x55, 0x00, 0x04, 0x01, 0x80), - PHYREGS(0x9008, 0x8C08, 0x8808, 0xDE01, 0xDF01, 0xE001), - }, - { .channel = 96, - .freq = 5480, /* MHz */ - .unk2 = 3653, - RADIOREGS(0x71, 0x02, 0x24, 0x06, 0x4D, 0x01, 0x04, 0x0A, - 0x00, 0x84, 0x11, 0x11, 0x44, 0x00, 0x03, 0x00, - 0x80, 0x44, 0x00, 0x03, 0x00, 0x80), - PHYREGS(0x9408, 0x9008, 0x8C08, 0xDD01, 0xDE01, 0xDF01), - }, - { .channel = 98, - .freq = 5490, /* MHz */ - .unk2 = 3660, - RADIOREGS(0x71, 0x02, 0x25, 0x06, 0x4D, 0x01, 0x04, 0x0A, - 0x00, 0x84, 0x11, 0x11, 0x44, 0x00, 0x03, 0x00, - 0x80, 0x44, 0x00, 0x03, 0x00, 0x80), - PHYREGS(0x9808, 0x9408, 0x9008, 0xDD01, 0xDD01, 0xDE01), - }, - { .channel = 100, - .freq = 5500, /* MHz */ - .unk2 = 3667, - RADIOREGS(0x71, 0x02, 0x26, 0x06, 0x47, 0x01, 0x04, 0x0A, - 0x00, 0x84, 0x00, 0x00, 0x44, 0x00, 0x03, 0x00, - 0x80, 0x44, 0x00, 0x03, 0x00, 0x80), - PHYREGS(0x9C08, 0x9808, 0x9408, 0xDC01, 0xDD01, 0xDD01), - }, - { .channel = 102, - .freq = 5510, /* MHz */ - .unk2 = 3673, - RADIOREGS(0x71, 0x02, 0x27, 0x06, 0x47, 0x01, 0x04, 0x0A, - 0x00, 0x84, 0x00, 0x00, 0x44, 0x00, 0x03, 0x00, - 0x80, 0x44, 0x00, 0x03, 0x00, 0x80), - PHYREGS(0xA008, 0x9C08, 0x9808, 0xDB01, 0xDC01, 0xDD01), - }, - { .channel = 104, - .freq = 5520, /* MHz */ - .unk2 = 3680, - RADIOREGS(0x71, 0x02, 0x28, 0x05, 0x40, 0x01, 0x04, 0x0A, - 0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00, - 0x80, 0x33, 0x00, 0x02, 0x00, 0x80), - PHYREGS(0xA408, 0xA008, 0x9C08, 0xDA01, 0xDB01, 0xDC01), - }, - { .channel = 106, - .freq = 5530, /* MHz */ - .unk2 = 3687, - RADIOREGS(0x71, 0x02, 0x29, 0x05, 0x40, 0x01, 0x04, 0x0A, - 0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00, - 0x80, 0x33, 0x00, 0x02, 0x00, 0x80), - PHYREGS(0xA808, 0xA408, 0xA008, 0xD901, 0xDA01, 0xDB01), - }, - { .channel = 108, - .freq = 5540, /* MHz */ - .unk2 = 3693, - RADIOREGS(0x71, 0x02, 0x2A, 0x05, 0x3A, 0x01, 0x04, 0x0A, - 0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00, - 0x80, 0x33, 0x00, 0x02, 0x00, 0x80), - PHYREGS(0xAC08, 0xA808, 0xA408, 0xD801, 0xD901, 0xDA01), - }, - { .channel = 110, - .freq = 5550, /* MHz */ - .unk2 = 3700, - RADIOREGS(0x71, 0x02, 0x2B, 0x05, 0x3A, 0x01, 0x04, 0x0A, - 0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00, - 0x80, 0x33, 0x00, 0x02, 0x00, 0x80), - PHYREGS(0xB008, 0xAC08, 0xA808, 0xD701, 0xD801, 0xD901), - }, - { .channel = 112, - .freq = 5560, /* MHz */ - .unk2 = 3707, - RADIOREGS(0x71, 0x02, 0x2C, 0x05, 0x34, 0x01, 0x04, 0x0A, - 0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00, - 0x80, 0x22, 0x00, 0x01, 0x00, 0x80), - PHYREGS(0xB408, 0xB008, 0xAC08, 0xD701, 0xD701, 0xD801), - }, - { .channel = 114, - .freq = 5570, /* MHz */ - .unk2 = 3713, - RADIOREGS(0x71, 0x02, 0x2D, 0x05, 0x34, 0x01, 0x04, 0x0A, - 0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00, - 0x80, 0x22, 0x00, 0x01, 0x00, 0x80), - PHYREGS(0xB808, 0xB408, 0xB008, 0xD601, 0xD701, 0xD701), - }, - { .channel = 116, - .freq = 5580, /* MHz */ - .unk2 = 3720, - RADIOREGS(0x71, 0x02, 0x2E, 0x04, 0x2E, 0x01, 0x04, 0x0A, - 0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00, - 0x80, 0x22, 0x00, 0x01, 0x00, 0x80), - PHYREGS(0xBC08, 0xB808, 0xB408, 0xD501, 0xD601, 0xD701), - }, - { .channel = 118, - .freq = 5590, /* MHz */ - .unk2 = 3727, - RADIOREGS(0x71, 0x02, 0x2F, 0x04, 0x2E, 0x01, 0x04, 0x0A, - 0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00, - 0x80, 0x22, 0x00, 0x01, 0x00, 0x80), - PHYREGS(0xC008, 0xBC08, 0xB808, 0xD401, 0xD501, 0xD601), - }, - { .channel = 120, - .freq = 5600, /* MHz */ - .unk2 = 3733, - RADIOREGS(0x71, 0x02, 0x30, 0x04, 0x28, 0x01, 0x04, 0x0A, - 0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x01, 0x00, - 0x80, 0x11, 0x00, 0x01, 0x00, 0x80), - PHYREGS(0xC408, 0xC008, 0xBC08, 0xD301, 0xD401, 0xD501), - }, - { .channel = 122, - .freq = 5610, /* MHz */ - .unk2 = 3740, - RADIOREGS(0x71, 0x02, 0x31, 0x04, 0x28, 0x01, 0x04, 0x0A, - 0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x01, 0x00, - 0x80, 0x11, 0x00, 0x01, 0x00, 0x80), - PHYREGS(0xC808, 0xC408, 0xC008, 0xD201, 0xD301, 0xD401), - }, - { .channel = 124, - .freq = 5620, /* MHz */ - .unk2 = 3747, - RADIOREGS(0x71, 0x02, 0x32, 0x04, 0x21, 0x01, 0x04, 0x0A, - 0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, - 0x80, 0x11, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0xCC08, 0xC808, 0xC408, 0xD201, 0xD201, 0xD301), - }, - { .channel = 126, - .freq = 5630, /* MHz */ - .unk2 = 3753, - RADIOREGS(0x71, 0x02, 0x33, 0x04, 0x21, 0x01, 0x04, 0x0A, - 0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, - 0x80, 0x11, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0xD008, 0xCC08, 0xC808, 0xD101, 0xD201, 0xD201), - }, - { .channel = 128, - .freq = 5640, /* MHz */ - .unk2 = 3760, - RADIOREGS(0x71, 0x02, 0x34, 0x03, 0x1C, 0x01, 0x04, 0x0A, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0xD408, 0xD008, 0xCC08, 0xD001, 0xD101, 0xD201), - }, - { .channel = 130, - .freq = 5650, /* MHz */ - .unk2 = 3767, - RADIOREGS(0x71, 0x02, 0x35, 0x03, 0x1C, 0x01, 0x04, 0x0A, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0xD808, 0xD408, 0xD008, 0xCF01, 0xD001, 0xD101), - }, - { .channel = 132, - .freq = 5660, /* MHz */ - .unk2 = 3773, - RADIOREGS(0x71, 0x02, 0x36, 0x03, 0x16, 0x01, 0x04, 0x0A, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0xDC08, 0xD808, 0xD408, 0xCE01, 0xCF01, 0xD001), - }, - { .channel = 134, - .freq = 5670, /* MHz */ - .unk2 = 3780, - RADIOREGS(0x71, 0x02, 0x37, 0x03, 0x16, 0x01, 0x04, 0x0A, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0xE008, 0xDC08, 0xD808, 0xCE01, 0xCE01, 0xCF01), - }, - { .channel = 136, - .freq = 5680, /* MHz */ - .unk2 = 3787, - RADIOREGS(0x71, 0x02, 0x38, 0x03, 0x10, 0x01, 0x04, 0x0A, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0xE408, 0xE008, 0xDC08, 0xCD01, 0xCE01, 0xCE01), - }, - { .channel = 138, - .freq = 5690, /* MHz */ - .unk2 = 3793, - RADIOREGS(0x71, 0x02, 0x39, 0x03, 0x10, 0x01, 0x04, 0x0A, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0xE808, 0xE408, 0xE008, 0xCC01, 0xCD01, 0xCE01), - }, - { .channel = 140, - .freq = 5700, /* MHz */ - .unk2 = 3800, - RADIOREGS(0x71, 0x02, 0x3A, 0x02, 0x0A, 0x01, 0x04, 0x0A, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0xEC08, 0xE808, 0xE408, 0xCB01, 0xCC01, 0xCD01), - }, - { .channel = 142, - .freq = 5710, /* MHz */ - .unk2 = 3807, - RADIOREGS(0x71, 0x02, 0x3B, 0x02, 0x0A, 0x01, 0x04, 0x0A, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0xF008, 0xEC08, 0xE808, 0xCA01, 0xCB01, 0xCC01), - }, - { .channel = 144, - .freq = 5720, /* MHz */ - .unk2 = 3813, - RADIOREGS(0x71, 0x02, 0x3C, 0x02, 0x0A, 0x01, 0x04, 0x0A, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0xF408, 0xF008, 0xEC08, 0xC901, 0xCA01, 0xCB01), - }, - { .channel = 145, - .freq = 5725, /* MHz */ - .unk2 = 3817, - RADIOREGS(0x72, 0x04, 0x79, 0x02, 0x03, 0x01, 0x03, 0x14, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0xF608, 0xF208, 0xEE08, 0xC901, 0xCA01, 0xCB01), - }, - { .channel = 146, - .freq = 5730, /* MHz */ - .unk2 = 3820, - RADIOREGS(0x71, 0x02, 0x3D, 0x02, 0x0A, 0x01, 0x04, 0x0A, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0xF808, 0xF408, 0xF008, 0xC901, 0xC901, 0xCA01), - }, - { .channel = 147, - .freq = 5735, /* MHz */ - .unk2 = 3823, - RADIOREGS(0x72, 0x04, 0x7B, 0x02, 0x03, 0x01, 0x03, 0x14, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0xFA08, 0xF608, 0xF208, 0xC801, 0xC901, 0xCA01), - }, - { .channel = 148, - .freq = 5740, /* MHz */ - .unk2 = 3827, - RADIOREGS(0x71, 0x02, 0x3E, 0x02, 0x0A, 0x01, 0x04, 0x0A, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0xFC08, 0xF808, 0xF408, 0xC801, 0xC901, 0xC901), - }, - { .channel = 149, - .freq = 5745, /* MHz */ - .unk2 = 3830, - RADIOREGS(0x72, 0x04, 0x7D, 0x02, 0xFE, 0x00, 0x03, 0x14, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0xFE08, 0xFA08, 0xF608, 0xC801, 0xC801, 0xC901), - }, - { .channel = 150, - .freq = 5750, /* MHz */ - .unk2 = 3833, - RADIOREGS(0x71, 0x02, 0x3F, 0x02, 0x0A, 0x01, 0x04, 0x0A, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0x0009, 0xFC08, 0xF808, 0xC701, 0xC801, 0xC901), - }, - { .channel = 151, - .freq = 5755, /* MHz */ - .unk2 = 3837, - RADIOREGS(0x72, 0x04, 0x7F, 0x02, 0xFE, 0x00, 0x03, 0x14, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0x0209, 0xFE08, 0xFA08, 0xC701, 0xC801, 0xC801), - }, - { .channel = 152, - .freq = 5760, /* MHz */ - .unk2 = 3840, - RADIOREGS(0x71, 0x02, 0x40, 0x02, 0x0A, 0x01, 0x04, 0x0A, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0x0409, 0x0009, 0xFC08, 0xC601, 0xC701, 0xC801), - }, - { .channel = 153, - .freq = 5765, /* MHz */ - .unk2 = 3843, - RADIOREGS(0x72, 0x04, 0x81, 0x02, 0xF8, 0x00, 0x03, 0x14, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0x0609, 0x0209, 0xFE08, 0xC601, 0xC701, 0xC801), - }, - { .channel = 154, - .freq = 5770, /* MHz */ - .unk2 = 3847, - RADIOREGS(0x71, 0x02, 0x41, 0x02, 0x0A, 0x01, 0x04, 0x0A, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0x0809, 0x0409, 0x0009, 0xC601, 0xC601, 0xC701), - }, - { .channel = 155, - .freq = 5775, /* MHz */ - .unk2 = 3850, - RADIOREGS(0x72, 0x04, 0x83, 0x02, 0xF8, 0x00, 0x03, 0x14, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0x0A09, 0x0609, 0x0209, 0xC501, 0xC601, 0xC701), - }, - { .channel = 156, - .freq = 5780, /* MHz */ - .unk2 = 3853, - RADIOREGS(0x71, 0x02, 0x42, 0x02, 0x0A, 0x01, 0x04, 0x0A, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0x0C09, 0x0809, 0x0409, 0xC501, 0xC601, 0xC601), - }, - { .channel = 157, - .freq = 5785, /* MHz */ - .unk2 = 3857, - RADIOREGS(0x72, 0x04, 0x85, 0x02, 0xF2, 0x00, 0x03, 0x14, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0x0E09, 0x0A09, 0x0609, 0xC401, 0xC501, 0xC601), - }, - { .channel = 158, - .freq = 5790, /* MHz */ - .unk2 = 3860, - RADIOREGS(0x71, 0x02, 0x43, 0x02, 0x0A, 0x01, 0x04, 0x0A, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0x1009, 0x0C09, 0x0809, 0xC401, 0xC501, 0xC601), - }, - { .channel = 159, - .freq = 5795, /* MHz */ - .unk2 = 3863, - RADIOREGS(0x72, 0x04, 0x87, 0x02, 0xF2, 0x00, 0x03, 0x14, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0x1209, 0x0E09, 0x0A09, 0xC401, 0xC401, 0xC501), - }, - { .channel = 160, - .freq = 5800, /* MHz */ - .unk2 = 3867, - RADIOREGS(0x71, 0x02, 0x44, 0x01, 0x0A, 0x01, 0x04, 0x0A, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0x1409, 0x1009, 0x0C09, 0xC301, 0xC401, 0xC501), - }, - { .channel = 161, - .freq = 5805, /* MHz */ - .unk2 = 3870, - RADIOREGS(0x72, 0x04, 0x89, 0x01, 0xED, 0x00, 0x03, 0x14, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0x1609, 0x1209, 0x0E09, 0xC301, 0xC401, 0xC401), - }, - { .channel = 162, - .freq = 5810, /* MHz */ - .unk2 = 3873, - RADIOREGS(0x71, 0x02, 0x45, 0x01, 0x0A, 0x01, 0x04, 0x0A, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0x1809, 0x1409, 0x1009, 0xC201, 0xC301, 0xC401), - }, - { .channel = 163, - .freq = 5815, /* MHz */ - .unk2 = 3877, - RADIOREGS(0x72, 0x04, 0x8B, 0x01, 0xED, 0x00, 0x03, 0x14, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0x1A09, 0x1609, 0x1209, 0xC201, 0xC301, 0xC401), - }, - { .channel = 164, - .freq = 5820, /* MHz */ - .unk2 = 3880, - RADIOREGS(0x71, 0x02, 0x46, 0x01, 0x0A, 0x01, 0x04, 0x0A, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0x1C09, 0x1809, 0x1409, 0xC201, 0xC201, 0xC301), - }, - { .channel = 165, - .freq = 5825, /* MHz */ - .unk2 = 3883, - RADIOREGS(0x72, 0x04, 0x8D, 0x01, 0xED, 0x00, 0x03, 0x14, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0x1E09, 0x1A09, 0x1609, 0xC101, 0xC201, 0xC301), - }, - { .channel = 166, - .freq = 5830, /* MHz */ - .unk2 = 3887, - RADIOREGS(0x71, 0x02, 0x47, 0x01, 0x0A, 0x01, 0x04, 0x0A, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0x2009, 0x1C09, 0x1809, 0xC101, 0xC201, 0xC201), - }, - { .channel = 168, - .freq = 5840, /* MHz */ - .unk2 = 3893, - RADIOREGS(0x71, 0x02, 0x48, 0x01, 0x0A, 0x01, 0x04, 0x0A, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0x2409, 0x2009, 0x1C09, 0xC001, 0xC101, 0xC201), - }, - { .channel = 170, - .freq = 5850, /* MHz */ - .unk2 = 3900, - RADIOREGS(0x71, 0x02, 0x49, 0x01, 0xE0, 0x00, 0x04, 0x0A, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0x2809, 0x2409, 0x2009, 0xBF01, 0xC001, 0xC101), - }, - { .channel = 172, - .freq = 5860, /* MHz */ - .unk2 = 3907, - RADIOREGS(0x71, 0x02, 0x4A, 0x01, 0xDE, 0x00, 0x04, 0x0A, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0x2C09, 0x2809, 0x2409, 0xBF01, 0xBF01, 0xC001), - }, - { .channel = 174, - .freq = 5870, /* MHz */ - .unk2 = 3913, - RADIOREGS(0x71, 0x02, 0x4B, 0x00, 0xDB, 0x00, 0x04, 0x0A, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0x3009, 0x2C09, 0x2809, 0xBE01, 0xBF01, 0xBF01), - }, - { .channel = 176, - .freq = 5880, /* MHz */ - .unk2 = 3920, - RADIOREGS(0x71, 0x02, 0x4C, 0x00, 0xD8, 0x00, 0x04, 0x0A, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0x3409, 0x3009, 0x2C09, 0xBD01, 0xBE01, 0xBF01), - }, - { .channel = 178, - .freq = 5890, /* MHz */ - .unk2 = 3927, - RADIOREGS(0x71, 0x02, 0x4D, 0x00, 0xD6, 0x00, 0x04, 0x0A, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0x3809, 0x3409, 0x3009, 0xBC01, 0xBD01, 0xBE01), - }, - { .channel = 180, - .freq = 5900, /* MHz */ - .unk2 = 3933, - RADIOREGS(0x71, 0x02, 0x4E, 0x00, 0xD3, 0x00, 0x04, 0x0A, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0x3C09, 0x3809, 0x3409, 0xBC01, 0xBC01, 0xBD01), - }, - { .channel = 182, - .freq = 5910, /* MHz */ - .unk2 = 3940, - RADIOREGS(0x71, 0x02, 0x4F, 0x00, 0xD6, 0x00, 0x04, 0x0A, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), - PHYREGS(0x4009, 0x3C09, 0x3809, 0xBB01, 0xBC01, 0xBC01), - }, - { .channel = 1, - .freq = 2412, /* MHz */ - .unk2 = 3216, - RADIOREGS(0x73, 0x09, 0x6C, 0x0F, 0x00, 0x01, 0x07, 0x15, - 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0D, 0x0C, - 0x80, 0xFF, 0x88, 0x0D, 0x0C, 0x80), - PHYREGS(0xC903, 0xC503, 0xC103, 0x3A04, 0x3F04, 0x4304), - }, - { .channel = 2, - .freq = 2417, /* MHz */ - .unk2 = 3223, - RADIOREGS(0x73, 0x09, 0x71, 0x0F, 0x00, 0x01, 0x07, 0x15, - 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0B, - 0x80, 0xFF, 0x88, 0x0C, 0x0B, 0x80), - PHYREGS(0xCB03, 0xC703, 0xC303, 0x3804, 0x3D04, 0x4104), - }, - { .channel = 3, - .freq = 2422, /* MHz */ - .unk2 = 3229, - RADIOREGS(0x73, 0x09, 0x76, 0x0F, 0x00, 0x01, 0x07, 0x15, - 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0A, - 0x80, 0xFF, 0x88, 0x0C, 0x0A, 0x80), - PHYREGS(0xCD03, 0xC903, 0xC503, 0x3604, 0x3A04, 0x3F04), - }, - { .channel = 4, - .freq = 2427, /* MHz */ - .unk2 = 3236, - RADIOREGS(0x73, 0x09, 0x7B, 0x0F, 0x00, 0x01, 0x07, 0x15, - 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0A, - 0x80, 0xFF, 0x88, 0x0C, 0x0A, 0x80), - PHYREGS(0xCF03, 0xCB03, 0xC703, 0x3404, 0x3804, 0x3D04), - }, - { .channel = 5, - .freq = 2432, /* MHz */ - .unk2 = 3243, - RADIOREGS(0x73, 0x09, 0x80, 0x0F, 0x00, 0x01, 0x07, 0x15, - 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x09, - 0x80, 0xFF, 0x88, 0x0C, 0x09, 0x80), - PHYREGS(0xD103, 0xCD03, 0xC903, 0x3104, 0x3604, 0x3A04), - }, - { .channel = 6, - .freq = 2437, /* MHz */ - .unk2 = 3249, - RADIOREGS(0x73, 0x09, 0x85, 0x0F, 0x00, 0x01, 0x07, 0x15, - 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0B, 0x08, - 0x80, 0xFF, 0x88, 0x0B, 0x08, 0x80), - PHYREGS(0xD303, 0xCF03, 0xCB03, 0x2F04, 0x3404, 0x3804), - }, - { .channel = 7, - .freq = 2442, /* MHz */ - .unk2 = 3256, - RADIOREGS(0x73, 0x09, 0x8A, 0x0F, 0x00, 0x01, 0x07, 0x15, - 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0A, 0x07, - 0x80, 0xFF, 0x88, 0x0A, 0x07, 0x80), - PHYREGS(0xD503, 0xD103, 0xCD03, 0x2D04, 0x3104, 0x3604), - }, - { .channel = 8, - .freq = 2447, /* MHz */ - .unk2 = 3263, - RADIOREGS(0x73, 0x09, 0x8F, 0x0F, 0x00, 0x01, 0x07, 0x15, - 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0A, 0x06, - 0x80, 0xFF, 0x88, 0x0A, 0x06, 0x80), - PHYREGS(0xD703, 0xD303, 0xCF03, 0x2B04, 0x2F04, 0x3404), - }, - { .channel = 9, - .freq = 2452, /* MHz */ - .unk2 = 3269, - RADIOREGS(0x73, 0x09, 0x94, 0x0F, 0x00, 0x01, 0x07, 0x15, - 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x09, 0x06, - 0x80, 0xFF, 0x88, 0x09, 0x06, 0x80), - PHYREGS(0xD903, 0xD503, 0xD103, 0x2904, 0x2D04, 0x3104), - }, - { .channel = 10, - .freq = 2457, /* MHz */ - .unk2 = 3276, - RADIOREGS(0x73, 0x09, 0x99, 0x0F, 0x00, 0x01, 0x07, 0x15, - 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x05, - 0x80, 0xFF, 0x88, 0x08, 0x05, 0x80), - PHYREGS(0xDB03, 0xD703, 0xD303, 0x2704, 0x2B04, 0x2F04), - }, - { .channel = 11, - .freq = 2462, /* MHz */ - .unk2 = 3283, - RADIOREGS(0x73, 0x09, 0x9E, 0x0F, 0x00, 0x01, 0x07, 0x15, - 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x04, - 0x80, 0xFF, 0x88, 0x08, 0x04, 0x80), - PHYREGS(0xDD03, 0xD903, 0xD503, 0x2404, 0x2904, 0x2D04), - }, - { .channel = 12, - .freq = 2467, /* MHz */ - .unk2 = 3289, - RADIOREGS(0x73, 0x09, 0xA3, 0x0F, 0x00, 0x01, 0x07, 0x15, - 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x03, - 0x80, 0xFF, 0x88, 0x08, 0x03, 0x80), - PHYREGS(0xDF03, 0xDB03, 0xD703, 0x2204, 0x2704, 0x2B04), - }, - { .channel = 13, - .freq = 2472, /* MHz */ - .unk2 = 3296, - RADIOREGS(0x73, 0x09, 0xA8, 0x0F, 0x00, 0x01, 0x07, 0x15, - 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x07, 0x03, - 0x80, 0xFF, 0x88, 0x07, 0x03, 0x80), - PHYREGS(0xE103, 0xDD03, 0xD903, 0x2004, 0x2404, 0x2904), - }, - { .channel = 14, - .freq = 2484, /* MHz */ - .unk2 = 3312, - RADIOREGS(0x73, 0x09, 0xB4, 0x0F, 0xFF, 0x01, 0x07, 0x15, - 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x07, 0x01, - 0x80, 0xFF, 0x88, 0x07, 0x01, 0x80), - PHYREGS(0xE603, 0xE203, 0xDE03, 0x1B04, 0x1F04, 0x2404), - }, -}; - -const struct b43_nphy_channeltab_entry_rev2 * -b43_nphy_get_chantabent_rev2(struct b43_wldev *dev, u8 channel) -{ - const struct b43_nphy_channeltab_entry_rev2 *e; - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(b43_nphy_channeltab_rev2); i++) { - e = &(b43_nphy_channeltab_rev2[i]); - if (e->channel == channel) - return e; - } - - return NULL; -} - static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev3[] = { }; @@ -1353,7 +45,6 @@ b43_nphy_get_chantabent_rev3(struct b43_wldev *dev, u16 freq) return NULL; } - static const u8 b43_ntab_adjustpower0[] = { 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, diff --git a/drivers/net/wireless/b43/tables_nphy.h b/drivers/net/wireless/b43/tables_nphy.h index 3eedb86..cb06d39 100644 --- a/drivers/net/wireless/b43/tables_nphy.h +++ b/drivers/net/wireless/b43/tables_nphy.h @@ -3,7 +3,6 @@ #include - struct b43_phy_n_sfo_cfg { u16 phy_bw1a; u16 phy_bw2; @@ -13,40 +12,6 @@ struct b43_phy_n_sfo_cfg { u16 phy_bw6; }; -struct b43_nphy_channeltab_entry_rev2 { - /* The channel number */ - u8 channel; - /* The channel frequency in MHz */ - u16 freq; - /* An unknown value */ - u16 unk2; - /* Radio register values on channelswitch */ - u8 radio_pll_ref; - u8 radio_rf_pllmod0; - u8 radio_rf_pllmod1; - u8 radio_vco_captail; - u8 radio_vco_cal1; - u8 radio_vco_cal2; - u8 radio_pll_lfc1; - u8 radio_pll_lfr1; - u8 radio_pll_lfc2; - u8 radio_lgbuf_cenbuf; - u8 radio_lgen_tune1; - u8 radio_lgen_tune2; - u8 radio_c1_lgbuf_atune; - u8 radio_c1_lgbuf_gtune; - u8 radio_c1_rx_rfr1; - u8 radio_c1_tx_pgapadtn; - u8 radio_c1_tx_mxbgtrim; - u8 radio_c2_lgbuf_atune; - u8 radio_c2_lgbuf_gtune; - u8 radio_c2_rx_rfr1; - u8 radio_c2_tx_pgapadtn; - u8 radio_c2_tx_mxbgtrim; - /* PHY register values on channelswitch */ - struct b43_phy_n_sfo_cfg phy_regs; -}; - struct b43_nphy_channeltab_entry_rev3 { /* The channel number */ u8 channel; @@ -58,7 +23,6 @@ struct b43_nphy_channeltab_entry_rev3 { struct b43_phy_n_sfo_cfg phy_regs; }; - struct b43_wldev; struct nphy_txiqcal_ladder { @@ -82,14 +46,6 @@ struct nphy_rf_control_override_rev3 { u8 val_addr1; }; -/* Upload the default register value table. - * If "ghz5" is true, we upload the 5Ghz table. Otherwise the 2.4Ghz - * table is uploaded. If "ignore_uploadflag" is true, we upload any value - * and ignore the "UPLOAD" flag. */ -void b2055_upload_inittab(struct b43_wldev *dev, - bool ghz5, bool ignore_uploadflag); - - /* Get the NPHY Channel Switch Table entry for a channel. * Returns NULL on failure to find an entry. */ const struct b43_nphy_channeltab_entry_rev2 * -- cgit v0.10.2 From 886b42bf5e54098061c8bae3d5e292a8b6897401 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 14 Oct 2010 11:44:27 -0700 Subject: ath9k_hw: remove AR9003 2.0 support These chipsets will not hit the market, all customers will be on >= AR9003 2.2. This shaves down the ath9k_hw size by 24161 bytes (24 KB) on my system. Before: $ size drivers/net/wireless/ath/ath9k/ath9k_hw.ko text data bss dec hex filename 292328 616 1824 294768 47f70 drivers/net/wireless/ath/ath9k/ath9k_hw.ko $ du -b drivers/net/wireless/ath/ath9k/ath9k_hw.ko 5987825 drivers/net/wireless/ath/ath9k/ath9k_hw.ko After: $ size drivers/net/wireless/ath/ath9k/ath9k_hw.ko text data bss dec hex filename 277192 616 1824 279632 44450 drivers/net/wireless/ath/ath9k/ath9k_hw.ko $ du -b drivers/net/wireless/ath/ath9k/ath9k_hw.ko 5963664 drivers/net/wireless/ath/ath9k/ath9k_hw.ko Cc: Yixiang Li Cc: Don Breslin Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p0_initvals.h deleted file mode 100644 index d3375fc..0000000 --- a/drivers/net/wireless/ath/ath9k/ar9003_2p0_initvals.h +++ /dev/null @@ -1,1784 +0,0 @@ -/* - * Copyright (c) 2010 Atheros Communications Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef INITVALS_9003_2P0_H -#define INITVALS_9003_2P0_H - -/* AR9003 2.0 */ - -static const u32 ar9300_2p0_radio_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0001609c, 0x0dd08f29, 0x0dd08f29, 0x0b283f31, 0x0b283f31}, - {0x000160ac, 0xa4653c00, 0xa4653c00, 0x24652800, 0x24652800}, - {0x000160b0, 0x03284f3e, 0x03284f3e, 0x05d08f20, 0x05d08f20}, - {0x0001610c, 0x08000000, 0x00000000, 0x00000000, 0x00000000}, - {0x00016140, 0x10804008, 0x10804008, 0x50804008, 0x50804008}, - {0x0001650c, 0x08000000, 0x00000000, 0x00000000, 0x00000000}, - {0x00016540, 0x10804008, 0x10804008, 0x50804008, 0x50804008}, - {0x0001690c, 0x08000000, 0x00000000, 0x00000000, 0x00000000}, - {0x00016940, 0x10804008, 0x10804008, 0x50804008, 0x50804008}, -}; - -static const u32 ar9300Modes_lowest_ob_db_tx_gain_table_2p0[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, - {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, - {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, - {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, - {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202}, - {0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400}, - {0x0000a518, 0x21020220, 0x21020220, 0x16000402, 0x16000402}, - {0x0000a51c, 0x27020223, 0x27020223, 0x19000404, 0x19000404}, - {0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603}, - {0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02}, - {0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04}, - {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20}, - {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20}, - {0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22}, - {0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24}, - {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640}, - {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660}, - {0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861}, - {0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81}, - {0x0000a54c, 0x5c04286b, 0x5c04286b, 0x47001a83, 0x47001a83}, - {0x0000a550, 0x61042a6c, 0x61042a6c, 0x4a001c84, 0x4a001c84}, - {0x0000a554, 0x66062a6c, 0x66062a6c, 0x4e001ce3, 0x4e001ce3}, - {0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x52001ce5, 0x52001ce5}, - {0x0000a55c, 0x7006308c, 0x7006308c, 0x56001ce9, 0x56001ce9}, - {0x0000a560, 0x730a308a, 0x730a308a, 0x5a001ceb, 0x5a001ceb}, - {0x0000a564, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a568, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a56c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a570, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a574, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a578, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a57c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, - {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002}, - {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004}, - {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200}, - {0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202}, - {0x0000a594, 0x1c800223, 0x1c800223, 0x12800400, 0x12800400}, - {0x0000a598, 0x21820220, 0x21820220, 0x16800402, 0x16800402}, - {0x0000a59c, 0x27820223, 0x27820223, 0x19800404, 0x19800404}, - {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603}, - {0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02}, - {0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04}, - {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20}, - {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20}, - {0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22}, - {0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24}, - {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640}, - {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660}, - {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861}, - {0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81}, - {0x0000a5cc, 0x5c84286b, 0x5c84286b, 0x47801a83, 0x47801a83}, - {0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x4a801c84, 0x4a801c84}, - {0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x4e801ce3, 0x4e801ce3}, - {0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x52801ce5, 0x52801ce5}, - {0x0000a5dc, 0x7086308c, 0x7086308c, 0x56801ce9, 0x56801ce9}, - {0x0000a5e0, 0x738a308a, 0x738a308a, 0x5a801ceb, 0x5a801ceb}, - {0x0000a5e4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, - {0x0000a5e8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, - {0x0000a5ec, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, - {0x0000a5f0, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, - {0x0000a5f4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, - {0x0000a5f8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, - {0x0000a5fc, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, - {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, - {0x00016048, 0x62480001, 0x62480001, 0x62480001, 0x62480001}, - {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, - {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, - {0x00016448, 0x62480001, 0x62480001, 0x62480001, 0x62480001}, - {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, - {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, - {0x00016848, 0x62480001, 0x62480001, 0x62480001, 0x62480001}, - {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, -}; - -static const u32 ar9300Modes_fast_clock_2p0[][3] = { - /* Addr 5G_HT20 5G_HT40 */ - {0x00001030, 0x00000268, 0x000004d0}, - {0x00001070, 0x0000018c, 0x00000318}, - {0x000010b0, 0x00000fd0, 0x00001fa0}, - {0x00008014, 0x044c044c, 0x08980898}, - {0x0000801c, 0x148ec02b, 0x148ec057}, - {0x00008318, 0x000044c0, 0x00008980}, - {0x00009e00, 0x03721821, 0x03721821}, - {0x0000a230, 0x0000000b, 0x00000016}, - {0x0000a254, 0x00000898, 0x00001130}, -}; - -static const u32 ar9300_2p0_radio_core[][2] = { - /* Addr allmodes */ - {0x00016000, 0x36db6db6}, - {0x00016004, 0x6db6db40}, - {0x00016008, 0x73f00000}, - {0x0001600c, 0x00000000}, - {0x00016040, 0x7f80fff8}, - {0x0001604c, 0x76d005b5}, - {0x00016050, 0x556cf031}, - {0x00016054, 0x13449440}, - {0x00016058, 0x0c51c92c}, - {0x0001605c, 0x3db7fffc}, - {0x00016060, 0xfffffffc}, - {0x00016064, 0x000f0278}, - {0x0001606c, 0x6db60000}, - {0x00016080, 0x00000000}, - {0x00016084, 0x0e48048c}, - {0x00016088, 0x54214514}, - {0x0001608c, 0x119f481e}, - {0x00016090, 0x24926490}, - {0x00016098, 0xd2888888}, - {0x000160a0, 0x0a108ffe}, - {0x000160a4, 0x812fc370}, - {0x000160a8, 0x423c8000}, - {0x000160b4, 0x92480080}, - {0x000160c0, 0x00adb6d0}, - {0x000160c4, 0x6db6db60}, - {0x000160c8, 0x6db6db6c}, - {0x000160cc, 0x01e6c000}, - {0x00016100, 0x3fffbe01}, - {0x00016104, 0xfff80000}, - {0x00016108, 0x00080010}, - {0x00016144, 0x02084080}, - {0x00016148, 0x00000000}, - {0x00016280, 0x058a0001}, - {0x00016284, 0x3d840208}, - {0x00016288, 0x05a20408}, - {0x0001628c, 0x00038c07}, - {0x00016290, 0x40000004}, - {0x00016294, 0x458aa14f}, - {0x00016380, 0x00000000}, - {0x00016384, 0x00000000}, - {0x00016388, 0x00800700}, - {0x0001638c, 0x00800700}, - {0x00016390, 0x00800700}, - {0x00016394, 0x00000000}, - {0x00016398, 0x00000000}, - {0x0001639c, 0x00000000}, - {0x000163a0, 0x00000001}, - {0x000163a4, 0x00000001}, - {0x000163a8, 0x00000000}, - {0x000163ac, 0x00000000}, - {0x000163b0, 0x00000000}, - {0x000163b4, 0x00000000}, - {0x000163b8, 0x00000000}, - {0x000163bc, 0x00000000}, - {0x000163c0, 0x000000a0}, - {0x000163c4, 0x000c0000}, - {0x000163c8, 0x14021402}, - {0x000163cc, 0x00001402}, - {0x000163d0, 0x00000000}, - {0x000163d4, 0x00000000}, - {0x00016400, 0x36db6db6}, - {0x00016404, 0x6db6db40}, - {0x00016408, 0x73f00000}, - {0x0001640c, 0x00000000}, - {0x00016440, 0x7f80fff8}, - {0x0001644c, 0x76d005b5}, - {0x00016450, 0x556cf031}, - {0x00016454, 0x13449440}, - {0x00016458, 0x0c51c92c}, - {0x0001645c, 0x3db7fffc}, - {0x00016460, 0xfffffffc}, - {0x00016464, 0x000f0278}, - {0x0001646c, 0x6db60000}, - {0x00016500, 0x3fffbe01}, - {0x00016504, 0xfff80000}, - {0x00016508, 0x00080010}, - {0x00016544, 0x02084080}, - {0x00016548, 0x00000000}, - {0x00016780, 0x00000000}, - {0x00016784, 0x00000000}, - {0x00016788, 0x00800700}, - {0x0001678c, 0x00800700}, - {0x00016790, 0x00800700}, - {0x00016794, 0x00000000}, - {0x00016798, 0x00000000}, - {0x0001679c, 0x00000000}, - {0x000167a0, 0x00000001}, - {0x000167a4, 0x00000001}, - {0x000167a8, 0x00000000}, - {0x000167ac, 0x00000000}, - {0x000167b0, 0x00000000}, - {0x000167b4, 0x00000000}, - {0x000167b8, 0x00000000}, - {0x000167bc, 0x00000000}, - {0x000167c0, 0x000000a0}, - {0x000167c4, 0x000c0000}, - {0x000167c8, 0x14021402}, - {0x000167cc, 0x00001402}, - {0x000167d0, 0x00000000}, - {0x000167d4, 0x00000000}, - {0x00016800, 0x36db6db6}, - {0x00016804, 0x6db6db40}, - {0x00016808, 0x73f00000}, - {0x0001680c, 0x00000000}, - {0x00016840, 0x7f80fff8}, - {0x0001684c, 0x76d005b5}, - {0x00016850, 0x556cf031}, - {0x00016854, 0x13449440}, - {0x00016858, 0x0c51c92c}, - {0x0001685c, 0x3db7fffc}, - {0x00016860, 0xfffffffc}, - {0x00016864, 0x000f0278}, - {0x0001686c, 0x6db60000}, - {0x00016900, 0x3fffbe01}, - {0x00016904, 0xfff80000}, - {0x00016908, 0x00080010}, - {0x00016944, 0x02084080}, - {0x00016948, 0x00000000}, - {0x00016b80, 0x00000000}, - {0x00016b84, 0x00000000}, - {0x00016b88, 0x00800700}, - {0x00016b8c, 0x00800700}, - {0x00016b90, 0x00800700}, - {0x00016b94, 0x00000000}, - {0x00016b98, 0x00000000}, - {0x00016b9c, 0x00000000}, - {0x00016ba0, 0x00000001}, - {0x00016ba4, 0x00000001}, - {0x00016ba8, 0x00000000}, - {0x00016bac, 0x00000000}, - {0x00016bb0, 0x00000000}, - {0x00016bb4, 0x00000000}, - {0x00016bb8, 0x00000000}, - {0x00016bbc, 0x00000000}, - {0x00016bc0, 0x000000a0}, - {0x00016bc4, 0x000c0000}, - {0x00016bc8, 0x14021402}, - {0x00016bcc, 0x00001402}, - {0x00016bd0, 0x00000000}, - {0x00016bd4, 0x00000000}, -}; - -static const u32 ar9300Common_rx_gain_table_merlin_2p0[][2] = { - /* Addr allmodes */ - {0x0000a000, 0x02000101}, - {0x0000a004, 0x02000102}, - {0x0000a008, 0x02000103}, - {0x0000a00c, 0x02000104}, - {0x0000a010, 0x02000200}, - {0x0000a014, 0x02000201}, - {0x0000a018, 0x02000202}, - {0x0000a01c, 0x02000203}, - {0x0000a020, 0x02000204}, - {0x0000a024, 0x02000205}, - {0x0000a028, 0x02000208}, - {0x0000a02c, 0x02000302}, - {0x0000a030, 0x02000303}, - {0x0000a034, 0x02000304}, - {0x0000a038, 0x02000400}, - {0x0000a03c, 0x02010300}, - {0x0000a040, 0x02010301}, - {0x0000a044, 0x02010302}, - {0x0000a048, 0x02000500}, - {0x0000a04c, 0x02010400}, - {0x0000a050, 0x02020300}, - {0x0000a054, 0x02020301}, - {0x0000a058, 0x02020302}, - {0x0000a05c, 0x02020303}, - {0x0000a060, 0x02020400}, - {0x0000a064, 0x02030300}, - {0x0000a068, 0x02030301}, - {0x0000a06c, 0x02030302}, - {0x0000a070, 0x02030303}, - {0x0000a074, 0x02030400}, - {0x0000a078, 0x02040300}, - {0x0000a07c, 0x02040301}, - {0x0000a080, 0x02040302}, - {0x0000a084, 0x02040303}, - {0x0000a088, 0x02030500}, - {0x0000a08c, 0x02040400}, - {0x0000a090, 0x02050203}, - {0x0000a094, 0x02050204}, - {0x0000a098, 0x02050205}, - {0x0000a09c, 0x02040500}, - {0x0000a0a0, 0x02050301}, - {0x0000a0a4, 0x02050302}, - {0x0000a0a8, 0x02050303}, - {0x0000a0ac, 0x02050400}, - {0x0000a0b0, 0x02050401}, - {0x0000a0b4, 0x02050402}, - {0x0000a0b8, 0x02050403}, - {0x0000a0bc, 0x02050500}, - {0x0000a0c0, 0x02050501}, - {0x0000a0c4, 0x02050502}, - {0x0000a0c8, 0x02050503}, - {0x0000a0cc, 0x02050504}, - {0x0000a0d0, 0x02050600}, - {0x0000a0d4, 0x02050601}, - {0x0000a0d8, 0x02050602}, - {0x0000a0dc, 0x02050603}, - {0x0000a0e0, 0x02050604}, - {0x0000a0e4, 0x02050700}, - {0x0000a0e8, 0x02050701}, - {0x0000a0ec, 0x02050702}, - {0x0000a0f0, 0x02050703}, - {0x0000a0f4, 0x02050704}, - {0x0000a0f8, 0x02050705}, - {0x0000a0fc, 0x02050708}, - {0x0000a100, 0x02050709}, - {0x0000a104, 0x0205070a}, - {0x0000a108, 0x0205070b}, - {0x0000a10c, 0x0205070c}, - {0x0000a110, 0x0205070d}, - {0x0000a114, 0x02050710}, - {0x0000a118, 0x02050711}, - {0x0000a11c, 0x02050712}, - {0x0000a120, 0x02050713}, - {0x0000a124, 0x02050714}, - {0x0000a128, 0x02050715}, - {0x0000a12c, 0x02050730}, - {0x0000a130, 0x02050731}, - {0x0000a134, 0x02050732}, - {0x0000a138, 0x02050733}, - {0x0000a13c, 0x02050734}, - {0x0000a140, 0x02050735}, - {0x0000a144, 0x02050750}, - {0x0000a148, 0x02050751}, - {0x0000a14c, 0x02050752}, - {0x0000a150, 0x02050753}, - {0x0000a154, 0x02050754}, - {0x0000a158, 0x02050755}, - {0x0000a15c, 0x02050770}, - {0x0000a160, 0x02050771}, - {0x0000a164, 0x02050772}, - {0x0000a168, 0x02050773}, - {0x0000a16c, 0x02050774}, - {0x0000a170, 0x02050775}, - {0x0000a174, 0x00000776}, - {0x0000a178, 0x00000776}, - {0x0000a17c, 0x00000776}, - {0x0000a180, 0x00000776}, - {0x0000a184, 0x00000776}, - {0x0000a188, 0x00000776}, - {0x0000a18c, 0x00000776}, - {0x0000a190, 0x00000776}, - {0x0000a194, 0x00000776}, - {0x0000a198, 0x00000776}, - {0x0000a19c, 0x00000776}, - {0x0000a1a0, 0x00000776}, - {0x0000a1a4, 0x00000776}, - {0x0000a1a8, 0x00000776}, - {0x0000a1ac, 0x00000776}, - {0x0000a1b0, 0x00000776}, - {0x0000a1b4, 0x00000776}, - {0x0000a1b8, 0x00000776}, - {0x0000a1bc, 0x00000776}, - {0x0000a1c0, 0x00000776}, - {0x0000a1c4, 0x00000776}, - {0x0000a1c8, 0x00000776}, - {0x0000a1cc, 0x00000776}, - {0x0000a1d0, 0x00000776}, - {0x0000a1d4, 0x00000776}, - {0x0000a1d8, 0x00000776}, - {0x0000a1dc, 0x00000776}, - {0x0000a1e0, 0x00000776}, - {0x0000a1e4, 0x00000776}, - {0x0000a1e8, 0x00000776}, - {0x0000a1ec, 0x00000776}, - {0x0000a1f0, 0x00000776}, - {0x0000a1f4, 0x00000776}, - {0x0000a1f8, 0x00000776}, - {0x0000a1fc, 0x00000776}, - {0x0000b000, 0x02000101}, - {0x0000b004, 0x02000102}, - {0x0000b008, 0x02000103}, - {0x0000b00c, 0x02000104}, - {0x0000b010, 0x02000200}, - {0x0000b014, 0x02000201}, - {0x0000b018, 0x02000202}, - {0x0000b01c, 0x02000203}, - {0x0000b020, 0x02000204}, - {0x0000b024, 0x02000205}, - {0x0000b028, 0x02000208}, - {0x0000b02c, 0x02000302}, - {0x0000b030, 0x02000303}, - {0x0000b034, 0x02000304}, - {0x0000b038, 0x02000400}, - {0x0000b03c, 0x02010300}, - {0x0000b040, 0x02010301}, - {0x0000b044, 0x02010302}, - {0x0000b048, 0x02000500}, - {0x0000b04c, 0x02010400}, - {0x0000b050, 0x02020300}, - {0x0000b054, 0x02020301}, - {0x0000b058, 0x02020302}, - {0x0000b05c, 0x02020303}, - {0x0000b060, 0x02020400}, - {0x0000b064, 0x02030300}, - {0x0000b068, 0x02030301}, - {0x0000b06c, 0x02030302}, - {0x0000b070, 0x02030303}, - {0x0000b074, 0x02030400}, - {0x0000b078, 0x02040300}, - {0x0000b07c, 0x02040301}, - {0x0000b080, 0x02040302}, - {0x0000b084, 0x02040303}, - {0x0000b088, 0x02030500}, - {0x0000b08c, 0x02040400}, - {0x0000b090, 0x02050203}, - {0x0000b094, 0x02050204}, - {0x0000b098, 0x02050205}, - {0x0000b09c, 0x02040500}, - {0x0000b0a0, 0x02050301}, - {0x0000b0a4, 0x02050302}, - {0x0000b0a8, 0x02050303}, - {0x0000b0ac, 0x02050400}, - {0x0000b0b0, 0x02050401}, - {0x0000b0b4, 0x02050402}, - {0x0000b0b8, 0x02050403}, - {0x0000b0bc, 0x02050500}, - {0x0000b0c0, 0x02050501}, - {0x0000b0c4, 0x02050502}, - {0x0000b0c8, 0x02050503}, - {0x0000b0cc, 0x02050504}, - {0x0000b0d0, 0x02050600}, - {0x0000b0d4, 0x02050601}, - {0x0000b0d8, 0x02050602}, - {0x0000b0dc, 0x02050603}, - {0x0000b0e0, 0x02050604}, - {0x0000b0e4, 0x02050700}, - {0x0000b0e8, 0x02050701}, - {0x0000b0ec, 0x02050702}, - {0x0000b0f0, 0x02050703}, - {0x0000b0f4, 0x02050704}, - {0x0000b0f8, 0x02050705}, - {0x0000b0fc, 0x02050708}, - {0x0000b100, 0x02050709}, - {0x0000b104, 0x0205070a}, - {0x0000b108, 0x0205070b}, - {0x0000b10c, 0x0205070c}, - {0x0000b110, 0x0205070d}, - {0x0000b114, 0x02050710}, - {0x0000b118, 0x02050711}, - {0x0000b11c, 0x02050712}, - {0x0000b120, 0x02050713}, - {0x0000b124, 0x02050714}, - {0x0000b128, 0x02050715}, - {0x0000b12c, 0x02050730}, - {0x0000b130, 0x02050731}, - {0x0000b134, 0x02050732}, - {0x0000b138, 0x02050733}, - {0x0000b13c, 0x02050734}, - {0x0000b140, 0x02050735}, - {0x0000b144, 0x02050750}, - {0x0000b148, 0x02050751}, - {0x0000b14c, 0x02050752}, - {0x0000b150, 0x02050753}, - {0x0000b154, 0x02050754}, - {0x0000b158, 0x02050755}, - {0x0000b15c, 0x02050770}, - {0x0000b160, 0x02050771}, - {0x0000b164, 0x02050772}, - {0x0000b168, 0x02050773}, - {0x0000b16c, 0x02050774}, - {0x0000b170, 0x02050775}, - {0x0000b174, 0x00000776}, - {0x0000b178, 0x00000776}, - {0x0000b17c, 0x00000776}, - {0x0000b180, 0x00000776}, - {0x0000b184, 0x00000776}, - {0x0000b188, 0x00000776}, - {0x0000b18c, 0x00000776}, - {0x0000b190, 0x00000776}, - {0x0000b194, 0x00000776}, - {0x0000b198, 0x00000776}, - {0x0000b19c, 0x00000776}, - {0x0000b1a0, 0x00000776}, - {0x0000b1a4, 0x00000776}, - {0x0000b1a8, 0x00000776}, - {0x0000b1ac, 0x00000776}, - {0x0000b1b0, 0x00000776}, - {0x0000b1b4, 0x00000776}, - {0x0000b1b8, 0x00000776}, - {0x0000b1bc, 0x00000776}, - {0x0000b1c0, 0x00000776}, - {0x0000b1c4, 0x00000776}, - {0x0000b1c8, 0x00000776}, - {0x0000b1cc, 0x00000776}, - {0x0000b1d0, 0x00000776}, - {0x0000b1d4, 0x00000776}, - {0x0000b1d8, 0x00000776}, - {0x0000b1dc, 0x00000776}, - {0x0000b1e0, 0x00000776}, - {0x0000b1e4, 0x00000776}, - {0x0000b1e8, 0x00000776}, - {0x0000b1ec, 0x00000776}, - {0x0000b1f0, 0x00000776}, - {0x0000b1f4, 0x00000776}, - {0x0000b1f8, 0x00000776}, - {0x0000b1fc, 0x00000776}, -}; - -static const u32 ar9300_2p0_mac_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, - {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c}, - {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38}, - {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00}, - {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b}, - {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810}, - {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a}, - {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440}, -}; - -static const u32 ar9300_2p0_soc_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00007010, 0x00000023, 0x00000023, 0x00000023, 0x00000023}, -}; - -static const u32 ar9200_merlin_2p0_radio_core[][2] = { - /* Addr allmodes */ - {0x00007800, 0x00040000}, - {0x00007804, 0xdb005012}, - {0x00007808, 0x04924914}, - {0x0000780c, 0x21084210}, - {0x00007810, 0x6d801300}, - {0x00007814, 0x0019beff}, - {0x00007818, 0x07e41000}, - {0x0000781c, 0x00392000}, - {0x00007820, 0x92592480}, - {0x00007824, 0x00040000}, - {0x00007828, 0xdb005012}, - {0x0000782c, 0x04924914}, - {0x00007830, 0x21084210}, - {0x00007834, 0x6d801300}, - {0x00007838, 0x0019beff}, - {0x0000783c, 0x07e40000}, - {0x00007840, 0x00392000}, - {0x00007844, 0x92592480}, - {0x00007848, 0x00100000}, - {0x0000784c, 0x773f0567}, - {0x00007850, 0x54214514}, - {0x00007854, 0x12035828}, - {0x00007858, 0x92592692}, - {0x0000785c, 0x00000000}, - {0x00007860, 0x56400000}, - {0x00007864, 0x0a8e370e}, - {0x00007868, 0xc0102850}, - {0x0000786c, 0x812d4000}, - {0x00007870, 0x807ec400}, - {0x00007874, 0x001b6db0}, - {0x00007878, 0x00376b63}, - {0x0000787c, 0x06db6db6}, - {0x00007880, 0x006d8000}, - {0x00007884, 0xffeffffe}, - {0x00007888, 0xffeffffe}, - {0x0000788c, 0x00010000}, - {0x00007890, 0x02060aeb}, - {0x00007894, 0x5a108000}, -}; - -static const u32 ar9300_2p0_baseband_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011}, - {0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e}, - {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, - {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881}, - {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, - {0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c}, - {0x00009c00, 0x00000044, 0x000000c4, 0x000000c4, 0x00000044}, - {0x00009e00, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0}, - {0x00009e04, 0x00802020, 0x00802020, 0x00802020, 0x00802020}, - {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2}, - {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e}, - {0x00009e14, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e}, - {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, - {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, - {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, - {0x00009e44, 0x02321e27, 0x02321e27, 0x02291e27, 0x02291e27}, - {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, - {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, - {0x0000a204, 0x000037c0, 0x000037c4, 0x000037c4, 0x000037c0}, - {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, - {0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b}, - {0x0000a238, 0xffb81018, 0xffb81018, 0xffb81018, 0xffb81018}, - {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, - {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, - {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002}, - {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e}, - {0x0000a260, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501}, - {0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, - {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b}, - {0x0000a284, 0x00000000, 0x00000000, 0x00000150, 0x00000150}, - {0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110}, - {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222}, - {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, - {0x0000a2d0, 0x00071981, 0x00071981, 0x00071981, 0x00071982}, - {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a}, - {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, - {0x0000ae04, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, - {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, - {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce}, - {0x0000b284, 0x00000000, 0x00000000, 0x00000150, 0x00000150}, - {0x0000b830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, - {0x0000be04, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, - {0x0000be18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000be1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, - {0x0000be20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce}, - {0x0000c284, 0x00000000, 0x00000000, 0x00000150, 0x00000150}, -}; - -static const u32 ar9300_2p0_baseband_core[][2] = { - /* Addr allmodes */ - {0x00009800, 0xafe68e30}, - {0x00009804, 0xfd14e000}, - {0x00009808, 0x9c0a9f6b}, - {0x0000980c, 0x04900000}, - {0x00009814, 0x9280c00a}, - {0x00009818, 0x00000000}, - {0x0000981c, 0x00020028}, - {0x00009834, 0x5f3ca3de}, - {0x00009838, 0x0108ecff}, - {0x0000983c, 0x14750600}, - {0x00009880, 0x201fff00}, - {0x00009884, 0x00001042}, - {0x000098a4, 0x00200400}, - {0x000098b0, 0x52440bbe}, - {0x000098d0, 0x004b6a8e}, - {0x000098d4, 0x00000820}, - {0x000098dc, 0x00000000}, - {0x000098f0, 0x00000000}, - {0x000098f4, 0x00000000}, - {0x00009c04, 0xff55ff55}, - {0x00009c08, 0x0320ff55}, - {0x00009c0c, 0x00000000}, - {0x00009c10, 0x00000000}, - {0x00009c14, 0x00046384}, - {0x00009c18, 0x05b6b440}, - {0x00009c1c, 0x00b6b440}, - {0x00009d00, 0xc080a333}, - {0x00009d04, 0x40206c10}, - {0x00009d08, 0x009c4060}, - {0x00009d0c, 0x9883800a}, - {0x00009d10, 0x01834061}, - {0x00009d14, 0x00c0040b}, - {0x00009d18, 0x00000000}, - {0x00009e08, 0x0038230c}, - {0x00009e24, 0x990bb515}, - {0x00009e28, 0x0c6f0000}, - {0x00009e30, 0x06336f77}, - {0x00009e34, 0x6af6532f}, - {0x00009e38, 0x0cc80c00}, - {0x00009e3c, 0xcf946222}, - {0x00009e40, 0x0d261820}, - {0x00009e4c, 0x00001004}, - {0x00009e50, 0x00ff03f1}, - {0x00009e54, 0x00000000}, - {0x00009fc0, 0x803e4788}, - {0x00009fc4, 0x0001efb5}, - {0x00009fcc, 0x40000014}, - {0x00009fd0, 0x01193b93}, - {0x0000a20c, 0x00000000}, - {0x0000a220, 0x00000000}, - {0x0000a224, 0x00000000}, - {0x0000a228, 0x10002310}, - {0x0000a22c, 0x01036a1e}, - {0x0000a234, 0x10000fff}, - {0x0000a23c, 0x00000000}, - {0x0000a244, 0x0c000000}, - {0x0000a2a0, 0x00000001}, - {0x0000a2c0, 0x00000001}, - {0x0000a2c8, 0x00000000}, - {0x0000a2cc, 0x18c43433}, - {0x0000a2d4, 0x00000000}, - {0x0000a2dc, 0x00000000}, - {0x0000a2e0, 0x00000000}, - {0x0000a2e4, 0x00000000}, - {0x0000a2e8, 0x00000000}, - {0x0000a2ec, 0x00000000}, - {0x0000a2f0, 0x00000000}, - {0x0000a2f4, 0x00000000}, - {0x0000a2f8, 0x00000000}, - {0x0000a344, 0x00000000}, - {0x0000a34c, 0x00000000}, - {0x0000a350, 0x0000a000}, - {0x0000a364, 0x00000000}, - {0x0000a370, 0x00000000}, - {0x0000a390, 0x00000001}, - {0x0000a394, 0x00000444}, - {0x0000a398, 0x001f0e0f}, - {0x0000a39c, 0x0075393f}, - {0x0000a3a0, 0xb79f6427}, - {0x0000a3a4, 0x00000000}, - {0x0000a3a8, 0xaaaaaaaa}, - {0x0000a3ac, 0x3c466478}, - {0x0000a3c0, 0x20202020}, - {0x0000a3c4, 0x22222220}, - {0x0000a3c8, 0x20200020}, - {0x0000a3cc, 0x20202020}, - {0x0000a3d0, 0x20202020}, - {0x0000a3d4, 0x20202020}, - {0x0000a3d8, 0x20202020}, - {0x0000a3dc, 0x20202020}, - {0x0000a3e0, 0x20202020}, - {0x0000a3e4, 0x20202020}, - {0x0000a3e8, 0x20202020}, - {0x0000a3ec, 0x20202020}, - {0x0000a3f0, 0x00000000}, - {0x0000a3f4, 0x00000246}, - {0x0000a3f8, 0x0cdbd380}, - {0x0000a3fc, 0x000f0f01}, - {0x0000a400, 0x8fa91f01}, - {0x0000a404, 0x00000000}, - {0x0000a408, 0x0e79e5c6}, - {0x0000a40c, 0x00820820}, - {0x0000a414, 0x1ce739ce}, - {0x0000a418, 0x2d001dce}, - {0x0000a41c, 0x1ce739ce}, - {0x0000a420, 0x000001ce}, - {0x0000a424, 0x1ce739ce}, - {0x0000a428, 0x000001ce}, - {0x0000a42c, 0x1ce739ce}, - {0x0000a430, 0x1ce739ce}, - {0x0000a434, 0x00000000}, - {0x0000a438, 0x00001801}, - {0x0000a43c, 0x00000000}, - {0x0000a440, 0x00000000}, - {0x0000a444, 0x00000000}, - {0x0000a448, 0x04000080}, - {0x0000a44c, 0x00000001}, - {0x0000a450, 0x00010000}, - {0x0000a458, 0x00000000}, - {0x0000a600, 0x00000000}, - {0x0000a604, 0x00000000}, - {0x0000a608, 0x00000000}, - {0x0000a60c, 0x00000000}, - {0x0000a610, 0x00000000}, - {0x0000a614, 0x00000000}, - {0x0000a618, 0x00000000}, - {0x0000a61c, 0x00000000}, - {0x0000a620, 0x00000000}, - {0x0000a624, 0x00000000}, - {0x0000a628, 0x00000000}, - {0x0000a62c, 0x00000000}, - {0x0000a630, 0x00000000}, - {0x0000a634, 0x00000000}, - {0x0000a638, 0x00000000}, - {0x0000a63c, 0x00000000}, - {0x0000a640, 0x00000000}, - {0x0000a644, 0x3fad9d74}, - {0x0000a648, 0x0048060a}, - {0x0000a64c, 0x00000637}, - {0x0000a670, 0x03020100}, - {0x0000a674, 0x09080504}, - {0x0000a678, 0x0d0c0b0a}, - {0x0000a67c, 0x13121110}, - {0x0000a680, 0x31301514}, - {0x0000a684, 0x35343332}, - {0x0000a688, 0x00000036}, - {0x0000a690, 0x00000838}, - {0x0000a7c0, 0x00000000}, - {0x0000a7c4, 0xfffffffc}, - {0x0000a7c8, 0x00000000}, - {0x0000a7cc, 0x00000000}, - {0x0000a7d0, 0x00000000}, - {0x0000a7d4, 0x00000004}, - {0x0000a7dc, 0x00000001}, - {0x0000a8d0, 0x004b6a8e}, - {0x0000a8d4, 0x00000820}, - {0x0000a8dc, 0x00000000}, - {0x0000a8f0, 0x00000000}, - {0x0000a8f4, 0x00000000}, - {0x0000b2d0, 0x00000080}, - {0x0000b2d4, 0x00000000}, - {0x0000b2dc, 0x00000000}, - {0x0000b2e0, 0x00000000}, - {0x0000b2e4, 0x00000000}, - {0x0000b2e8, 0x00000000}, - {0x0000b2ec, 0x00000000}, - {0x0000b2f0, 0x00000000}, - {0x0000b2f4, 0x00000000}, - {0x0000b2f8, 0x00000000}, - {0x0000b408, 0x0e79e5c0}, - {0x0000b40c, 0x00820820}, - {0x0000b420, 0x00000000}, - {0x0000b8d0, 0x004b6a8e}, - {0x0000b8d4, 0x00000820}, - {0x0000b8dc, 0x00000000}, - {0x0000b8f0, 0x00000000}, - {0x0000b8f4, 0x00000000}, - {0x0000c2d0, 0x00000080}, - {0x0000c2d4, 0x00000000}, - {0x0000c2dc, 0x00000000}, - {0x0000c2e0, 0x00000000}, - {0x0000c2e4, 0x00000000}, - {0x0000c2e8, 0x00000000}, - {0x0000c2ec, 0x00000000}, - {0x0000c2f0, 0x00000000}, - {0x0000c2f4, 0x00000000}, - {0x0000c2f8, 0x00000000}, - {0x0000c408, 0x0e79e5c0}, - {0x0000c40c, 0x00820820}, - {0x0000c420, 0x00000000}, -}; - -static const u32 ar9300Modes_high_power_tx_gain_table_2p0[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, - {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, - {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, - {0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004}, - {0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200}, - {0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202}, - {0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400}, - {0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402}, - {0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404}, - {0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603}, - {0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02}, - {0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04}, - {0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20}, - {0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20}, - {0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22}, - {0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24}, - {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640}, - {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660}, - {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861}, - {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81}, - {0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83}, - {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84}, - {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3}, - {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5}, - {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9}, - {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb}, - {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000}, - {0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002}, - {0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004}, - {0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200}, - {0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202}, - {0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400}, - {0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402}, - {0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404}, - {0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603}, - {0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02}, - {0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04}, - {0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20}, - {0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20}, - {0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22}, - {0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24}, - {0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640}, - {0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660}, - {0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861}, - {0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81}, - {0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83}, - {0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84}, - {0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3}, - {0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5}, - {0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9}, - {0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb}, - {0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x00016044, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6}, - {0x00016048, 0xae480001, 0xae480001, 0xae480001, 0xae480001}, - {0x00016068, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c}, - {0x00016444, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6}, - {0x00016448, 0xae480001, 0xae480001, 0xae480001, 0xae480001}, - {0x00016468, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c}, - {0x00016844, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6}, - {0x00016848, 0xae480001, 0xae480001, 0xae480001, 0xae480001}, - {0x00016868, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c}, -}; - -static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p0[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, - {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, - {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, - {0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004}, - {0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200}, - {0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202}, - {0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400}, - {0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402}, - {0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404}, - {0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603}, - {0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02}, - {0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04}, - {0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20}, - {0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20}, - {0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22}, - {0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24}, - {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640}, - {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660}, - {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861}, - {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81}, - {0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83}, - {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84}, - {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3}, - {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5}, - {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9}, - {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb}, - {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000}, - {0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002}, - {0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004}, - {0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200}, - {0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202}, - {0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400}, - {0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402}, - {0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404}, - {0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603}, - {0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02}, - {0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04}, - {0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20}, - {0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20}, - {0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22}, - {0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24}, - {0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640}, - {0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660}, - {0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861}, - {0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81}, - {0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83}, - {0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84}, - {0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3}, - {0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5}, - {0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9}, - {0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb}, - {0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x00016044, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4}, - {0x00016048, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001}, - {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, - {0x00016444, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4}, - {0x00016448, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001}, - {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, - {0x00016844, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4}, - {0x00016848, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001}, - {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, -}; - -static const u32 ar9300Common_rx_gain_table_2p0[][2] = { - /* Addr allmodes */ - {0x0000a000, 0x00010000}, - {0x0000a004, 0x00030002}, - {0x0000a008, 0x00050004}, - {0x0000a00c, 0x00810080}, - {0x0000a010, 0x00830082}, - {0x0000a014, 0x01810180}, - {0x0000a018, 0x01830182}, - {0x0000a01c, 0x01850184}, - {0x0000a020, 0x01890188}, - {0x0000a024, 0x018b018a}, - {0x0000a028, 0x018d018c}, - {0x0000a02c, 0x01910190}, - {0x0000a030, 0x01930192}, - {0x0000a034, 0x01950194}, - {0x0000a038, 0x038a0196}, - {0x0000a03c, 0x038c038b}, - {0x0000a040, 0x0390038d}, - {0x0000a044, 0x03920391}, - {0x0000a048, 0x03940393}, - {0x0000a04c, 0x03960395}, - {0x0000a050, 0x00000000}, - {0x0000a054, 0x00000000}, - {0x0000a058, 0x00000000}, - {0x0000a05c, 0x00000000}, - {0x0000a060, 0x00000000}, - {0x0000a064, 0x00000000}, - {0x0000a068, 0x00000000}, - {0x0000a06c, 0x00000000}, - {0x0000a070, 0x00000000}, - {0x0000a074, 0x00000000}, - {0x0000a078, 0x00000000}, - {0x0000a07c, 0x00000000}, - {0x0000a080, 0x22222229}, - {0x0000a084, 0x1d1d1d1d}, - {0x0000a088, 0x1d1d1d1d}, - {0x0000a08c, 0x1d1d1d1d}, - {0x0000a090, 0x171d1d1d}, - {0x0000a094, 0x11111717}, - {0x0000a098, 0x00030311}, - {0x0000a09c, 0x00000000}, - {0x0000a0a0, 0x00000000}, - {0x0000a0a4, 0x00000000}, - {0x0000a0a8, 0x00000000}, - {0x0000a0ac, 0x00000000}, - {0x0000a0b0, 0x00000000}, - {0x0000a0b4, 0x00000000}, - {0x0000a0b8, 0x00000000}, - {0x0000a0bc, 0x00000000}, - {0x0000a0c0, 0x001f0000}, - {0x0000a0c4, 0x01000101}, - {0x0000a0c8, 0x011e011f}, - {0x0000a0cc, 0x011c011d}, - {0x0000a0d0, 0x02030204}, - {0x0000a0d4, 0x02010202}, - {0x0000a0d8, 0x021f0200}, - {0x0000a0dc, 0x0302021e}, - {0x0000a0e0, 0x03000301}, - {0x0000a0e4, 0x031e031f}, - {0x0000a0e8, 0x0402031d}, - {0x0000a0ec, 0x04000401}, - {0x0000a0f0, 0x041e041f}, - {0x0000a0f4, 0x0502041d}, - {0x0000a0f8, 0x05000501}, - {0x0000a0fc, 0x051e051f}, - {0x0000a100, 0x06010602}, - {0x0000a104, 0x061f0600}, - {0x0000a108, 0x061d061e}, - {0x0000a10c, 0x07020703}, - {0x0000a110, 0x07000701}, - {0x0000a114, 0x00000000}, - {0x0000a118, 0x00000000}, - {0x0000a11c, 0x00000000}, - {0x0000a120, 0x00000000}, - {0x0000a124, 0x00000000}, - {0x0000a128, 0x00000000}, - {0x0000a12c, 0x00000000}, - {0x0000a130, 0x00000000}, - {0x0000a134, 0x00000000}, - {0x0000a138, 0x00000000}, - {0x0000a13c, 0x00000000}, - {0x0000a140, 0x001f0000}, - {0x0000a144, 0x01000101}, - {0x0000a148, 0x011e011f}, - {0x0000a14c, 0x011c011d}, - {0x0000a150, 0x02030204}, - {0x0000a154, 0x02010202}, - {0x0000a158, 0x021f0200}, - {0x0000a15c, 0x0302021e}, - {0x0000a160, 0x03000301}, - {0x0000a164, 0x031e031f}, - {0x0000a168, 0x0402031d}, - {0x0000a16c, 0x04000401}, - {0x0000a170, 0x041e041f}, - {0x0000a174, 0x0502041d}, - {0x0000a178, 0x05000501}, - {0x0000a17c, 0x051e051f}, - {0x0000a180, 0x06010602}, - {0x0000a184, 0x061f0600}, - {0x0000a188, 0x061d061e}, - {0x0000a18c, 0x07020703}, - {0x0000a190, 0x07000701}, - {0x0000a194, 0x00000000}, - {0x0000a198, 0x00000000}, - {0x0000a19c, 0x00000000}, - {0x0000a1a0, 0x00000000}, - {0x0000a1a4, 0x00000000}, - {0x0000a1a8, 0x00000000}, - {0x0000a1ac, 0x00000000}, - {0x0000a1b0, 0x00000000}, - {0x0000a1b4, 0x00000000}, - {0x0000a1b8, 0x00000000}, - {0x0000a1bc, 0x00000000}, - {0x0000a1c0, 0x00000000}, - {0x0000a1c4, 0x00000000}, - {0x0000a1c8, 0x00000000}, - {0x0000a1cc, 0x00000000}, - {0x0000a1d0, 0x00000000}, - {0x0000a1d4, 0x00000000}, - {0x0000a1d8, 0x00000000}, - {0x0000a1dc, 0x00000000}, - {0x0000a1e0, 0x00000000}, - {0x0000a1e4, 0x00000000}, - {0x0000a1e8, 0x00000000}, - {0x0000a1ec, 0x00000000}, - {0x0000a1f0, 0x00000396}, - {0x0000a1f4, 0x00000396}, - {0x0000a1f8, 0x00000396}, - {0x0000a1fc, 0x00000196}, - {0x0000b000, 0x00010000}, - {0x0000b004, 0x00030002}, - {0x0000b008, 0x00050004}, - {0x0000b00c, 0x00810080}, - {0x0000b010, 0x00830082}, - {0x0000b014, 0x01810180}, - {0x0000b018, 0x01830182}, - {0x0000b01c, 0x01850184}, - {0x0000b020, 0x02810280}, - {0x0000b024, 0x02830282}, - {0x0000b028, 0x02850284}, - {0x0000b02c, 0x02890288}, - {0x0000b030, 0x028b028a}, - {0x0000b034, 0x0388028c}, - {0x0000b038, 0x038a0389}, - {0x0000b03c, 0x038c038b}, - {0x0000b040, 0x0390038d}, - {0x0000b044, 0x03920391}, - {0x0000b048, 0x03940393}, - {0x0000b04c, 0x03960395}, - {0x0000b050, 0x00000000}, - {0x0000b054, 0x00000000}, - {0x0000b058, 0x00000000}, - {0x0000b05c, 0x00000000}, - {0x0000b060, 0x00000000}, - {0x0000b064, 0x00000000}, - {0x0000b068, 0x00000000}, - {0x0000b06c, 0x00000000}, - {0x0000b070, 0x00000000}, - {0x0000b074, 0x00000000}, - {0x0000b078, 0x00000000}, - {0x0000b07c, 0x00000000}, - {0x0000b080, 0x32323232}, - {0x0000b084, 0x2f2f3232}, - {0x0000b088, 0x23282a2d}, - {0x0000b08c, 0x1c1e2123}, - {0x0000b090, 0x14171919}, - {0x0000b094, 0x0e0e1214}, - {0x0000b098, 0x03050707}, - {0x0000b09c, 0x00030303}, - {0x0000b0a0, 0x00000000}, - {0x0000b0a4, 0x00000000}, - {0x0000b0a8, 0x00000000}, - {0x0000b0ac, 0x00000000}, - {0x0000b0b0, 0x00000000}, - {0x0000b0b4, 0x00000000}, - {0x0000b0b8, 0x00000000}, - {0x0000b0bc, 0x00000000}, - {0x0000b0c0, 0x003f0020}, - {0x0000b0c4, 0x00400041}, - {0x0000b0c8, 0x0140005f}, - {0x0000b0cc, 0x0160015f}, - {0x0000b0d0, 0x017e017f}, - {0x0000b0d4, 0x02410242}, - {0x0000b0d8, 0x025f0240}, - {0x0000b0dc, 0x027f0260}, - {0x0000b0e0, 0x0341027e}, - {0x0000b0e4, 0x035f0340}, - {0x0000b0e8, 0x037f0360}, - {0x0000b0ec, 0x04400441}, - {0x0000b0f0, 0x0460045f}, - {0x0000b0f4, 0x0541047f}, - {0x0000b0f8, 0x055f0540}, - {0x0000b0fc, 0x057f0560}, - {0x0000b100, 0x06400641}, - {0x0000b104, 0x0660065f}, - {0x0000b108, 0x067e067f}, - {0x0000b10c, 0x07410742}, - {0x0000b110, 0x075f0740}, - {0x0000b114, 0x077f0760}, - {0x0000b118, 0x07800781}, - {0x0000b11c, 0x07a0079f}, - {0x0000b120, 0x07c107bf}, - {0x0000b124, 0x000007c0}, - {0x0000b128, 0x00000000}, - {0x0000b12c, 0x00000000}, - {0x0000b130, 0x00000000}, - {0x0000b134, 0x00000000}, - {0x0000b138, 0x00000000}, - {0x0000b13c, 0x00000000}, - {0x0000b140, 0x003f0020}, - {0x0000b144, 0x00400041}, - {0x0000b148, 0x0140005f}, - {0x0000b14c, 0x0160015f}, - {0x0000b150, 0x017e017f}, - {0x0000b154, 0x02410242}, - {0x0000b158, 0x025f0240}, - {0x0000b15c, 0x027f0260}, - {0x0000b160, 0x0341027e}, - {0x0000b164, 0x035f0340}, - {0x0000b168, 0x037f0360}, - {0x0000b16c, 0x04400441}, - {0x0000b170, 0x0460045f}, - {0x0000b174, 0x0541047f}, - {0x0000b178, 0x055f0540}, - {0x0000b17c, 0x057f0560}, - {0x0000b180, 0x06400641}, - {0x0000b184, 0x0660065f}, - {0x0000b188, 0x067e067f}, - {0x0000b18c, 0x07410742}, - {0x0000b190, 0x075f0740}, - {0x0000b194, 0x077f0760}, - {0x0000b198, 0x07800781}, - {0x0000b19c, 0x07a0079f}, - {0x0000b1a0, 0x07c107bf}, - {0x0000b1a4, 0x000007c0}, - {0x0000b1a8, 0x00000000}, - {0x0000b1ac, 0x00000000}, - {0x0000b1b0, 0x00000000}, - {0x0000b1b4, 0x00000000}, - {0x0000b1b8, 0x00000000}, - {0x0000b1bc, 0x00000000}, - {0x0000b1c0, 0x00000000}, - {0x0000b1c4, 0x00000000}, - {0x0000b1c8, 0x00000000}, - {0x0000b1cc, 0x00000000}, - {0x0000b1d0, 0x00000000}, - {0x0000b1d4, 0x00000000}, - {0x0000b1d8, 0x00000000}, - {0x0000b1dc, 0x00000000}, - {0x0000b1e0, 0x00000000}, - {0x0000b1e4, 0x00000000}, - {0x0000b1e8, 0x00000000}, - {0x0000b1ec, 0x00000000}, - {0x0000b1f0, 0x00000396}, - {0x0000b1f4, 0x00000396}, - {0x0000b1f8, 0x00000396}, - {0x0000b1fc, 0x00000196}, -}; - -static const u32 ar9300Modes_low_ob_db_tx_gain_table_2p0[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, - {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, - {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, - {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, - {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202}, - {0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400}, - {0x0000a518, 0x21020220, 0x21020220, 0x16000402, 0x16000402}, - {0x0000a51c, 0x27020223, 0x27020223, 0x19000404, 0x19000404}, - {0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603}, - {0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02}, - {0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04}, - {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20}, - {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20}, - {0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22}, - {0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24}, - {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640}, - {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660}, - {0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861}, - {0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81}, - {0x0000a54c, 0x5c04286b, 0x5c04286b, 0x47001a83, 0x47001a83}, - {0x0000a550, 0x61042a6c, 0x61042a6c, 0x4a001c84, 0x4a001c84}, - {0x0000a554, 0x66062a6c, 0x66062a6c, 0x4e001ce3, 0x4e001ce3}, - {0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x52001ce5, 0x52001ce5}, - {0x0000a55c, 0x7006308c, 0x7006308c, 0x56001ce9, 0x56001ce9}, - {0x0000a560, 0x730a308a, 0x730a308a, 0x5a001ceb, 0x5a001ceb}, - {0x0000a564, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a568, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a56c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a570, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a574, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a578, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a57c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, - {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002}, - {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004}, - {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200}, - {0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202}, - {0x0000a594, 0x1c800223, 0x1c800223, 0x12800400, 0x12800400}, - {0x0000a598, 0x21820220, 0x21820220, 0x16800402, 0x16800402}, - {0x0000a59c, 0x27820223, 0x27820223, 0x19800404, 0x19800404}, - {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603}, - {0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02}, - {0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04}, - {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20}, - {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20}, - {0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22}, - {0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24}, - {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640}, - {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660}, - {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861}, - {0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81}, - {0x0000a5cc, 0x5c84286b, 0x5c84286b, 0x47801a83, 0x47801a83}, - {0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x4a801c84, 0x4a801c84}, - {0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x4e801ce3, 0x4e801ce3}, - {0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x52801ce5, 0x52801ce5}, - {0x0000a5dc, 0x7086308c, 0x7086308c, 0x56801ce9, 0x56801ce9}, - {0x0000a5e0, 0x738a308a, 0x738a308a, 0x5a801ceb, 0x5a801ceb}, - {0x0000a5e4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, - {0x0000a5e8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, - {0x0000a5ec, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, - {0x0000a5f0, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, - {0x0000a5f4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, - {0x0000a5f8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, - {0x0000a5fc, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, - {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, - {0x00016048, 0x64000001, 0x64000001, 0x64000001, 0x64000001}, - {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, - {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, - {0x00016448, 0x64000001, 0x64000001, 0x64000001, 0x64000001}, - {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, - {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, - {0x00016848, 0x64000001, 0x64000001, 0x64000001, 0x64000001}, - {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, -}; - -static const u32 ar9300_2p0_mac_core[][2] = { - /* Addr allmodes */ - {0x00000008, 0x00000000}, - {0x00000030, 0x00020085}, - {0x00000034, 0x00000005}, - {0x00000040, 0x00000000}, - {0x00000044, 0x00000000}, - {0x00000048, 0x00000008}, - {0x0000004c, 0x00000010}, - {0x00000050, 0x00000000}, - {0x00001040, 0x002ffc0f}, - {0x00001044, 0x002ffc0f}, - {0x00001048, 0x002ffc0f}, - {0x0000104c, 0x002ffc0f}, - {0x00001050, 0x002ffc0f}, - {0x00001054, 0x002ffc0f}, - {0x00001058, 0x002ffc0f}, - {0x0000105c, 0x002ffc0f}, - {0x00001060, 0x002ffc0f}, - {0x00001064, 0x002ffc0f}, - {0x000010f0, 0x00000100}, - {0x00001270, 0x00000000}, - {0x000012b0, 0x00000000}, - {0x000012f0, 0x00000000}, - {0x0000143c, 0x00000000}, - {0x0000147c, 0x00000000}, - {0x00008000, 0x00000000}, - {0x00008004, 0x00000000}, - {0x00008008, 0x00000000}, - {0x0000800c, 0x00000000}, - {0x00008018, 0x00000000}, - {0x00008020, 0x00000000}, - {0x00008038, 0x00000000}, - {0x0000803c, 0x00000000}, - {0x00008040, 0x00000000}, - {0x00008044, 0x00000000}, - {0x00008048, 0x00000000}, - {0x0000804c, 0xffffffff}, - {0x00008054, 0x00000000}, - {0x00008058, 0x00000000}, - {0x0000805c, 0x000fc78f}, - {0x00008060, 0x0000000f}, - {0x00008064, 0x00000000}, - {0x00008070, 0x00000310}, - {0x00008074, 0x00000020}, - {0x00008078, 0x00000000}, - {0x0000809c, 0x0000000f}, - {0x000080a0, 0x00000000}, - {0x000080a4, 0x02ff0000}, - {0x000080a8, 0x0e070605}, - {0x000080ac, 0x0000000d}, - {0x000080b0, 0x00000000}, - {0x000080b4, 0x00000000}, - {0x000080b8, 0x00000000}, - {0x000080bc, 0x00000000}, - {0x000080c0, 0x2a800000}, - {0x000080c4, 0x06900168}, - {0x000080c8, 0x13881c20}, - {0x000080cc, 0x01f40000}, - {0x000080d0, 0x00252500}, - {0x000080d4, 0x00a00000}, - {0x000080d8, 0x00400000}, - {0x000080dc, 0x00000000}, - {0x000080e0, 0xffffffff}, - {0x000080e4, 0x0000ffff}, - {0x000080e8, 0x3f3f3f3f}, - {0x000080ec, 0x00000000}, - {0x000080f0, 0x00000000}, - {0x000080f4, 0x00000000}, - {0x000080fc, 0x00020000}, - {0x00008100, 0x00000000}, - {0x00008108, 0x00000052}, - {0x0000810c, 0x00000000}, - {0x00008110, 0x00000000}, - {0x00008114, 0x000007ff}, - {0x00008118, 0x000000aa}, - {0x0000811c, 0x00003210}, - {0x00008124, 0x00000000}, - {0x00008128, 0x00000000}, - {0x0000812c, 0x00000000}, - {0x00008130, 0x00000000}, - {0x00008134, 0x00000000}, - {0x00008138, 0x00000000}, - {0x0000813c, 0x0000ffff}, - {0x00008144, 0xffffffff}, - {0x00008168, 0x00000000}, - {0x0000816c, 0x00000000}, - {0x00008170, 0x18486200}, - {0x00008174, 0x33332210}, - {0x00008178, 0x00000000}, - {0x0000817c, 0x00020000}, - {0x000081c0, 0x00000000}, - {0x000081c4, 0x33332210}, - {0x000081c8, 0x00000000}, - {0x000081cc, 0x00000000}, - {0x000081d4, 0x00000000}, - {0x000081ec, 0x00000000}, - {0x000081f0, 0x00000000}, - {0x000081f4, 0x00000000}, - {0x000081f8, 0x00000000}, - {0x000081fc, 0x00000000}, - {0x00008240, 0x00100000}, - {0x00008244, 0x0010f424}, - {0x00008248, 0x00000800}, - {0x0000824c, 0x0001e848}, - {0x00008250, 0x00000000}, - {0x00008254, 0x00000000}, - {0x00008258, 0x00000000}, - {0x0000825c, 0x40000000}, - {0x00008260, 0x00080922}, - {0x00008264, 0x98a00010}, - {0x00008268, 0xffffffff}, - {0x0000826c, 0x0000ffff}, - {0x00008270, 0x00000000}, - {0x00008274, 0x40000000}, - {0x00008278, 0x003e4180}, - {0x0000827c, 0x00000004}, - {0x00008284, 0x0000002c}, - {0x00008288, 0x0000002c}, - {0x0000828c, 0x000000ff}, - {0x00008294, 0x00000000}, - {0x00008298, 0x00000000}, - {0x0000829c, 0x00000000}, - {0x00008300, 0x00000140}, - {0x00008314, 0x00000000}, - {0x0000831c, 0x0000010d}, - {0x00008328, 0x00000000}, - {0x0000832c, 0x00000007}, - {0x00008330, 0x00000302}, - {0x00008334, 0x00000700}, - {0x00008338, 0x00ff0000}, - {0x0000833c, 0x02400000}, - {0x00008340, 0x000107ff}, - {0x00008344, 0xaa48105b}, - {0x00008348, 0x008f0000}, - {0x0000835c, 0x00000000}, - {0x00008360, 0xffffffff}, - {0x00008364, 0xffffffff}, - {0x00008368, 0x00000000}, - {0x00008370, 0x00000000}, - {0x00008374, 0x000000ff}, - {0x00008378, 0x00000000}, - {0x0000837c, 0x00000000}, - {0x00008380, 0xffffffff}, - {0x00008384, 0xffffffff}, - {0x00008390, 0xffffffff}, - {0x00008394, 0xffffffff}, - {0x00008398, 0x00000000}, - {0x0000839c, 0x00000000}, - {0x000083a0, 0x00000000}, - {0x000083a4, 0x0000fa14}, - {0x000083a8, 0x000f0c00}, - {0x000083ac, 0x33332210}, - {0x000083b0, 0x33332210}, - {0x000083b4, 0x33332210}, - {0x000083b8, 0x33332210}, - {0x000083bc, 0x00000000}, - {0x000083c0, 0x00000000}, - {0x000083c4, 0x00000000}, - {0x000083c8, 0x00000000}, - {0x000083cc, 0x00000200}, - {0x000083d0, 0x000301ff}, -}; - -static const u32 ar9300Common_wo_xlna_rx_gain_table_2p0[][2] = { - /* Addr allmodes */ - {0x0000a000, 0x00010000}, - {0x0000a004, 0x00030002}, - {0x0000a008, 0x00050004}, - {0x0000a00c, 0x00810080}, - {0x0000a010, 0x00830082}, - {0x0000a014, 0x01810180}, - {0x0000a018, 0x01830182}, - {0x0000a01c, 0x01850184}, - {0x0000a020, 0x01890188}, - {0x0000a024, 0x018b018a}, - {0x0000a028, 0x018d018c}, - {0x0000a02c, 0x03820190}, - {0x0000a030, 0x03840383}, - {0x0000a034, 0x03880385}, - {0x0000a038, 0x038a0389}, - {0x0000a03c, 0x038c038b}, - {0x0000a040, 0x0390038d}, - {0x0000a044, 0x03920391}, - {0x0000a048, 0x03940393}, - {0x0000a04c, 0x03960395}, - {0x0000a050, 0x00000000}, - {0x0000a054, 0x00000000}, - {0x0000a058, 0x00000000}, - {0x0000a05c, 0x00000000}, - {0x0000a060, 0x00000000}, - {0x0000a064, 0x00000000}, - {0x0000a068, 0x00000000}, - {0x0000a06c, 0x00000000}, - {0x0000a070, 0x00000000}, - {0x0000a074, 0x00000000}, - {0x0000a078, 0x00000000}, - {0x0000a07c, 0x00000000}, - {0x0000a080, 0x29292929}, - {0x0000a084, 0x29292929}, - {0x0000a088, 0x29292929}, - {0x0000a08c, 0x29292929}, - {0x0000a090, 0x22292929}, - {0x0000a094, 0x1d1d2222}, - {0x0000a098, 0x0c111117}, - {0x0000a09c, 0x00030303}, - {0x0000a0a0, 0x00000000}, - {0x0000a0a4, 0x00000000}, - {0x0000a0a8, 0x00000000}, - {0x0000a0ac, 0x00000000}, - {0x0000a0b0, 0x00000000}, - {0x0000a0b4, 0x00000000}, - {0x0000a0b8, 0x00000000}, - {0x0000a0bc, 0x00000000}, - {0x0000a0c0, 0x001f0000}, - {0x0000a0c4, 0x01000101}, - {0x0000a0c8, 0x011e011f}, - {0x0000a0cc, 0x011c011d}, - {0x0000a0d0, 0x02030204}, - {0x0000a0d4, 0x02010202}, - {0x0000a0d8, 0x021f0200}, - {0x0000a0dc, 0x0302021e}, - {0x0000a0e0, 0x03000301}, - {0x0000a0e4, 0x031e031f}, - {0x0000a0e8, 0x0402031d}, - {0x0000a0ec, 0x04000401}, - {0x0000a0f0, 0x041e041f}, - {0x0000a0f4, 0x0502041d}, - {0x0000a0f8, 0x05000501}, - {0x0000a0fc, 0x051e051f}, - {0x0000a100, 0x06010602}, - {0x0000a104, 0x061f0600}, - {0x0000a108, 0x061d061e}, - {0x0000a10c, 0x07020703}, - {0x0000a110, 0x07000701}, - {0x0000a114, 0x00000000}, - {0x0000a118, 0x00000000}, - {0x0000a11c, 0x00000000}, - {0x0000a120, 0x00000000}, - {0x0000a124, 0x00000000}, - {0x0000a128, 0x00000000}, - {0x0000a12c, 0x00000000}, - {0x0000a130, 0x00000000}, - {0x0000a134, 0x00000000}, - {0x0000a138, 0x00000000}, - {0x0000a13c, 0x00000000}, - {0x0000a140, 0x001f0000}, - {0x0000a144, 0x01000101}, - {0x0000a148, 0x011e011f}, - {0x0000a14c, 0x011c011d}, - {0x0000a150, 0x02030204}, - {0x0000a154, 0x02010202}, - {0x0000a158, 0x021f0200}, - {0x0000a15c, 0x0302021e}, - {0x0000a160, 0x03000301}, - {0x0000a164, 0x031e031f}, - {0x0000a168, 0x0402031d}, - {0x0000a16c, 0x04000401}, - {0x0000a170, 0x041e041f}, - {0x0000a174, 0x0502041d}, - {0x0000a178, 0x05000501}, - {0x0000a17c, 0x051e051f}, - {0x0000a180, 0x06010602}, - {0x0000a184, 0x061f0600}, - {0x0000a188, 0x061d061e}, - {0x0000a18c, 0x07020703}, - {0x0000a190, 0x07000701}, - {0x0000a194, 0x00000000}, - {0x0000a198, 0x00000000}, - {0x0000a19c, 0x00000000}, - {0x0000a1a0, 0x00000000}, - {0x0000a1a4, 0x00000000}, - {0x0000a1a8, 0x00000000}, - {0x0000a1ac, 0x00000000}, - {0x0000a1b0, 0x00000000}, - {0x0000a1b4, 0x00000000}, - {0x0000a1b8, 0x00000000}, - {0x0000a1bc, 0x00000000}, - {0x0000a1c0, 0x00000000}, - {0x0000a1c4, 0x00000000}, - {0x0000a1c8, 0x00000000}, - {0x0000a1cc, 0x00000000}, - {0x0000a1d0, 0x00000000}, - {0x0000a1d4, 0x00000000}, - {0x0000a1d8, 0x00000000}, - {0x0000a1dc, 0x00000000}, - {0x0000a1e0, 0x00000000}, - {0x0000a1e4, 0x00000000}, - {0x0000a1e8, 0x00000000}, - {0x0000a1ec, 0x00000000}, - {0x0000a1f0, 0x00000396}, - {0x0000a1f4, 0x00000396}, - {0x0000a1f8, 0x00000396}, - {0x0000a1fc, 0x00000196}, - {0x0000b000, 0x00010000}, - {0x0000b004, 0x00030002}, - {0x0000b008, 0x00050004}, - {0x0000b00c, 0x00810080}, - {0x0000b010, 0x00830082}, - {0x0000b014, 0x01810180}, - {0x0000b018, 0x01830182}, - {0x0000b01c, 0x01850184}, - {0x0000b020, 0x02810280}, - {0x0000b024, 0x02830282}, - {0x0000b028, 0x02850284}, - {0x0000b02c, 0x02890288}, - {0x0000b030, 0x028b028a}, - {0x0000b034, 0x0388028c}, - {0x0000b038, 0x038a0389}, - {0x0000b03c, 0x038c038b}, - {0x0000b040, 0x0390038d}, - {0x0000b044, 0x03920391}, - {0x0000b048, 0x03940393}, - {0x0000b04c, 0x03960395}, - {0x0000b050, 0x00000000}, - {0x0000b054, 0x00000000}, - {0x0000b058, 0x00000000}, - {0x0000b05c, 0x00000000}, - {0x0000b060, 0x00000000}, - {0x0000b064, 0x00000000}, - {0x0000b068, 0x00000000}, - {0x0000b06c, 0x00000000}, - {0x0000b070, 0x00000000}, - {0x0000b074, 0x00000000}, - {0x0000b078, 0x00000000}, - {0x0000b07c, 0x00000000}, - {0x0000b080, 0x32323232}, - {0x0000b084, 0x2f2f3232}, - {0x0000b088, 0x23282a2d}, - {0x0000b08c, 0x1c1e2123}, - {0x0000b090, 0x14171919}, - {0x0000b094, 0x0e0e1214}, - {0x0000b098, 0x03050707}, - {0x0000b09c, 0x00030303}, - {0x0000b0a0, 0x00000000}, - {0x0000b0a4, 0x00000000}, - {0x0000b0a8, 0x00000000}, - {0x0000b0ac, 0x00000000}, - {0x0000b0b0, 0x00000000}, - {0x0000b0b4, 0x00000000}, - {0x0000b0b8, 0x00000000}, - {0x0000b0bc, 0x00000000}, - {0x0000b0c0, 0x003f0020}, - {0x0000b0c4, 0x00400041}, - {0x0000b0c8, 0x0140005f}, - {0x0000b0cc, 0x0160015f}, - {0x0000b0d0, 0x017e017f}, - {0x0000b0d4, 0x02410242}, - {0x0000b0d8, 0x025f0240}, - {0x0000b0dc, 0x027f0260}, - {0x0000b0e0, 0x0341027e}, - {0x0000b0e4, 0x035f0340}, - {0x0000b0e8, 0x037f0360}, - {0x0000b0ec, 0x04400441}, - {0x0000b0f0, 0x0460045f}, - {0x0000b0f4, 0x0541047f}, - {0x0000b0f8, 0x055f0540}, - {0x0000b0fc, 0x057f0560}, - {0x0000b100, 0x06400641}, - {0x0000b104, 0x0660065f}, - {0x0000b108, 0x067e067f}, - {0x0000b10c, 0x07410742}, - {0x0000b110, 0x075f0740}, - {0x0000b114, 0x077f0760}, - {0x0000b118, 0x07800781}, - {0x0000b11c, 0x07a0079f}, - {0x0000b120, 0x07c107bf}, - {0x0000b124, 0x000007c0}, - {0x0000b128, 0x00000000}, - {0x0000b12c, 0x00000000}, - {0x0000b130, 0x00000000}, - {0x0000b134, 0x00000000}, - {0x0000b138, 0x00000000}, - {0x0000b13c, 0x00000000}, - {0x0000b140, 0x003f0020}, - {0x0000b144, 0x00400041}, - {0x0000b148, 0x0140005f}, - {0x0000b14c, 0x0160015f}, - {0x0000b150, 0x017e017f}, - {0x0000b154, 0x02410242}, - {0x0000b158, 0x025f0240}, - {0x0000b15c, 0x027f0260}, - {0x0000b160, 0x0341027e}, - {0x0000b164, 0x035f0340}, - {0x0000b168, 0x037f0360}, - {0x0000b16c, 0x04400441}, - {0x0000b170, 0x0460045f}, - {0x0000b174, 0x0541047f}, - {0x0000b178, 0x055f0540}, - {0x0000b17c, 0x057f0560}, - {0x0000b180, 0x06400641}, - {0x0000b184, 0x0660065f}, - {0x0000b188, 0x067e067f}, - {0x0000b18c, 0x07410742}, - {0x0000b190, 0x075f0740}, - {0x0000b194, 0x077f0760}, - {0x0000b198, 0x07800781}, - {0x0000b19c, 0x07a0079f}, - {0x0000b1a0, 0x07c107bf}, - {0x0000b1a4, 0x000007c0}, - {0x0000b1a8, 0x00000000}, - {0x0000b1ac, 0x00000000}, - {0x0000b1b0, 0x00000000}, - {0x0000b1b4, 0x00000000}, - {0x0000b1b8, 0x00000000}, - {0x0000b1bc, 0x00000000}, - {0x0000b1c0, 0x00000000}, - {0x0000b1c4, 0x00000000}, - {0x0000b1c8, 0x00000000}, - {0x0000b1cc, 0x00000000}, - {0x0000b1d0, 0x00000000}, - {0x0000b1d4, 0x00000000}, - {0x0000b1d8, 0x00000000}, - {0x0000b1dc, 0x00000000}, - {0x0000b1e0, 0x00000000}, - {0x0000b1e4, 0x00000000}, - {0x0000b1e8, 0x00000000}, - {0x0000b1ec, 0x00000000}, - {0x0000b1f0, 0x00000396}, - {0x0000b1f4, 0x00000396}, - {0x0000b1f8, 0x00000396}, - {0x0000b1fc, 0x00000196}, -}; - -static const u32 ar9300_2p0_soc_preamble[][2] = { - /* Addr allmodes */ - {0x000040a4, 0x00a0c1c9}, - {0x00007008, 0x00000000}, - {0x00007020, 0x00000000}, - {0x00007034, 0x00000002}, - {0x00007038, 0x000004c2}, -}; - -static const u32 ar9300PciePhy_pll_on_clkreq_disable_L1_2p0[][2] = { - /* Addr allmodes */ - {0x00004040, 0x08212e5e}, - {0x00004040, 0x0008003b}, - {0x00004044, 0x00000000}, -}; - -static const u32 ar9300PciePhy_clkreq_enable_L1_2p0[][2] = { - /* Addr allmodes */ - {0x00004040, 0x08253e5e}, - {0x00004040, 0x0008003b}, - {0x00004044, 0x00000000}, -}; - -static const u32 ar9300PciePhy_clkreq_disable_L1_2p0[][2] = { - /* Addr allmodes */ - {0x00004040, 0x08213e5e}, - {0x00004040, 0x0008003b}, - {0x00004044, 0x00000000}, -}; - -#endif /* INITVALS_9003_2P0_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index 02c9708..c2a0571 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -16,7 +16,6 @@ #include "hw.h" #include "ar9003_mac.h" -#include "ar9003_2p0_initvals.h" #include "ar9003_2p2_initvals.h" /* General hardware code for the AR9003 hadware family */ @@ -32,79 +31,12 @@ static bool ar9003_hw_macversion_supported(u32 macversion) return false; } -/* AR9003 2.0 */ -static void ar9003_2p0_hw_init_mode_regs(struct ath_hw *ah) -{ - /* mac */ - INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); - INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], - ar9300_2p0_mac_core, - ARRAY_SIZE(ar9300_2p0_mac_core), 2); - INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], - ar9300_2p0_mac_postamble, - ARRAY_SIZE(ar9300_2p0_mac_postamble), 5); - - /* bb */ - INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0); - INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], - ar9300_2p0_baseband_core, - ARRAY_SIZE(ar9300_2p0_baseband_core), 2); - INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], - ar9300_2p0_baseband_postamble, - ARRAY_SIZE(ar9300_2p0_baseband_postamble), 5); - - /* radio */ - INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0); - INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE], - ar9300_2p0_radio_core, - ARRAY_SIZE(ar9300_2p0_radio_core), 2); - INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], - ar9300_2p0_radio_postamble, - ARRAY_SIZE(ar9300_2p0_radio_postamble), 5); - - /* soc */ - INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE], - ar9300_2p0_soc_preamble, - ARRAY_SIZE(ar9300_2p0_soc_preamble), 2); - INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0); - INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], - ar9300_2p0_soc_postamble, - ARRAY_SIZE(ar9300_2p0_soc_postamble), 5); - - /* rx/tx gain */ - INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9300Common_rx_gain_table_2p0, - ARRAY_SIZE(ar9300Common_rx_gain_table_2p0), 2); - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9300Modes_lowest_ob_db_tx_gain_table_2p0, - ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p0), - 5); - - /* Load PCIE SERDES settings from INI */ - - /* Awake Setting */ - - INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9300PciePhy_pll_on_clkreq_disable_L1_2p0, - ARRAY_SIZE(ar9300PciePhy_pll_on_clkreq_disable_L1_2p0), - 2); - - /* Sleep Setting */ - - INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, - ar9300PciePhy_clkreq_enable_L1_2p0, - ARRAY_SIZE(ar9300PciePhy_clkreq_enable_L1_2p0), - 2); - - /* Fast clock modal settings */ - INIT_INI_ARRAY(&ah->iniModesAdditional, - ar9300Modes_fast_clock_2p0, - ARRAY_SIZE(ar9300Modes_fast_clock_2p0), - 3); -} - -/* AR9003 2.2 */ -static void ar9003_2p2_hw_init_mode_regs(struct ath_hw *ah) +/* + * The AR9003 family uses a new INI format (pre, core, post + * arrays per subsystem). This provides support for the + * AR9003 2.2 chipsets. + */ +static void ar9003_hw_init_mode_regs(struct ath_hw *ah) { /* mac */ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); @@ -174,57 +106,27 @@ static void ar9003_2p2_hw_init_mode_regs(struct ath_hw *ah) 3); } -/* - * The AR9003 family uses a new INI format (pre, core, post - * arrays per subsystem). - */ -static void ar9003_hw_init_mode_regs(struct ath_hw *ah) -{ - if (AR_SREV_9300_20(ah)) - ar9003_2p0_hw_init_mode_regs(ah); - else - ar9003_2p2_hw_init_mode_regs(ah); -} - static void ar9003_tx_gain_table_apply(struct ath_hw *ah) { switch (ar9003_hw_get_tx_gain_idx(ah)) { case 0: default: - if (AR_SREV_9300_20(ah)) - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9300Modes_lowest_ob_db_tx_gain_table_2p0, - ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p0), - 5); - else - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9300Modes_lowest_ob_db_tx_gain_table_2p2, - ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p2), - 5); + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9300Modes_lowest_ob_db_tx_gain_table_2p2, + ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p2), + 5); break; case 1: - if (AR_SREV_9300_20(ah)) - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9300Modes_high_ob_db_tx_gain_table_2p0, - ARRAY_SIZE(ar9300Modes_high_ob_db_tx_gain_table_2p0), - 5); - else - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9300Modes_high_ob_db_tx_gain_table_2p2, - ARRAY_SIZE(ar9300Modes_high_ob_db_tx_gain_table_2p2), - 5); + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9300Modes_high_ob_db_tx_gain_table_2p2, + ARRAY_SIZE(ar9300Modes_high_ob_db_tx_gain_table_2p2), + 5); break; case 2: - if (AR_SREV_9300_20(ah)) - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9300Modes_low_ob_db_tx_gain_table_2p0, - ARRAY_SIZE(ar9300Modes_low_ob_db_tx_gain_table_2p0), - 5); - else - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9300Modes_low_ob_db_tx_gain_table_2p2, - ARRAY_SIZE(ar9300Modes_low_ob_db_tx_gain_table_2p2), - 5); + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9300Modes_low_ob_db_tx_gain_table_2p2, + ARRAY_SIZE(ar9300Modes_low_ob_db_tx_gain_table_2p2), + 5); break; } } @@ -234,28 +136,16 @@ static void ar9003_rx_gain_table_apply(struct ath_hw *ah) switch (ar9003_hw_get_rx_gain_idx(ah)) { case 0: default: - if (AR_SREV_9300_20(ah)) - INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9300Common_rx_gain_table_2p0, - ARRAY_SIZE(ar9300Common_rx_gain_table_2p0), - 2); - else - INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9300Common_rx_gain_table_2p2, - ARRAY_SIZE(ar9300Common_rx_gain_table_2p2), - 2); + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9300Common_rx_gain_table_2p2, + ARRAY_SIZE(ar9300Common_rx_gain_table_2p2), + 2); break; case 1: - if (AR_SREV_9300_20(ah)) - INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9300Common_wo_xlna_rx_gain_table_2p0, - ARRAY_SIZE(ar9300Common_wo_xlna_rx_gain_table_2p0), - 2); - else - INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9300Common_wo_xlna_rx_gain_table_2p2, - ARRAY_SIZE(ar9300Common_wo_xlna_rx_gain_table_2p2), - 2); + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9300Common_wo_xlna_rx_gain_table_2p2, + ARRAY_SIZE(ar9300Common_wo_xlna_rx_gain_table_2p2), + 2); break; } } diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 0176178..42976b0 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -853,9 +853,6 @@ #define AR_SREV_9300(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9300)) -#define AR_SREV_9300_20(_ah) \ - (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9300) && \ - ((_ah)->hw_version.macRev == AR_SREV_REVISION_9300_20)) #define AR_SREV_9300_20_OR_LATER(_ah) \ (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9300) || \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9300) && \ -- cgit v0.10.2 From 5161bec5a8b3509b8cf69418129a191cf90bbd87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 14 Oct 2010 21:16:33 +0200 Subject: b43: N-PHY: put 2056-radio's specific code in separated file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile index 0398c7c..69d4af0 100644 --- a/drivers/net/wireless/b43/Makefile +++ b/drivers/net/wireless/b43/Makefile @@ -2,6 +2,7 @@ b43-y += main.o b43-y += tables.o b43-$(CONFIG_B43_NPHY) += tables_nphy.o b43-$(CONFIG_B43_NPHY) += radio_2055.o +b43-$(CONFIG_B43_NPHY) += radio_2056.o b43-y += phy_common.o b43-y += phy_g.o b43-y += phy_a.o diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 284b54f..1bdf20c 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -30,6 +30,7 @@ #include "phy_n.h" #include "tables_nphy.h" #include "radio_2055.h" +#include "radio_2056.h" #include "main.h" struct nphy_txgains { diff --git a/drivers/net/wireless/b43/radio_2056.c b/drivers/net/wireless/b43/radio_2056.c new file mode 100644 index 0000000..d856319 --- /dev/null +++ b/drivers/net/wireless/b43/radio_2056.c @@ -0,0 +1,43 @@ +/* + + Broadcom B43 wireless driver + IEEE 802.11n 2056 radio device data tables + + This program 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 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "b43.h" +#include "radio_2056.h" +#include "phy_common.h" + +static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev3[] = { +}; + +const struct b43_nphy_channeltab_entry_rev3 * +b43_nphy_get_chantabent_rev3(struct b43_wldev *dev, u16 freq) +{ + const struct b43_nphy_channeltab_entry_rev3 *e; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(b43_nphy_channeltab_rev3); i++) { + e = &(b43_nphy_channeltab_rev3[i]); + if (e->freq == freq) + return e; + } + + return NULL; +} diff --git a/drivers/net/wireless/b43/radio_2056.h b/drivers/net/wireless/b43/radio_2056.h new file mode 100644 index 0000000..fda6daf --- /dev/null +++ b/drivers/net/wireless/b43/radio_2056.h @@ -0,0 +1,42 @@ +/* + + Broadcom B43 wireless driver + + Copyright (c) 2010 Rafał Miłecki + + This program 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 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#ifndef B43_RADIO_2056_H_ +#define B43_RADIO_2056_H_ + +#include + +#include "tables_nphy.h" + +struct b43_nphy_channeltab_entry_rev3 { + /* The channel number */ + u8 channel; + /* The channel frequency in MHz */ + u16 freq; + /* Radio register values on channelswitch */ + /* TODO */ + /* PHY register values on channelswitch */ + struct b43_phy_n_sfo_cfg phy_regs; +}; + +#endif /* B43_RADIO_2056_H_ */ diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c index cff7bd3..d60db07 100644 --- a/drivers/net/wireless/b43/tables_nphy.c +++ b/drivers/net/wireless/b43/tables_nphy.c @@ -1,7 +1,7 @@ /* Broadcom B43 wireless driver - IEEE 802.11n PHY and radio device data tables + IEEE 802.11n PHY data tables Copyright (c) 2008 Michael Buesch @@ -27,24 +27,6 @@ #include "phy_common.h" #include "phy_n.h" -static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev3[] = { -}; - -const struct b43_nphy_channeltab_entry_rev3 * -b43_nphy_get_chantabent_rev3(struct b43_wldev *dev, u16 freq) -{ - const struct b43_nphy_channeltab_entry_rev3 *e; - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(b43_nphy_channeltab_rev3); i++) { - e = &(b43_nphy_channeltab_rev3[i]); - if (e->freq == freq) - return e; - } - - return NULL; -} - static const u8 b43_ntab_adjustpower0[] = { 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, diff --git a/drivers/net/wireless/b43/tables_nphy.h b/drivers/net/wireless/b43/tables_nphy.h index cb06d39..4ec593b 100644 --- a/drivers/net/wireless/b43/tables_nphy.h +++ b/drivers/net/wireless/b43/tables_nphy.h @@ -12,17 +12,6 @@ struct b43_phy_n_sfo_cfg { u16 phy_bw6; }; -struct b43_nphy_channeltab_entry_rev3 { - /* The channel number */ - u8 channel; - /* The channel frequency in MHz */ - u16 freq; - /* Radio register values on channelswitch */ - /* TODO */ - /* PHY register values on channelswitch */ - struct b43_phy_n_sfo_cfg phy_regs; -}; - struct b43_wldev; struct nphy_txiqcal_ladder { -- cgit v0.10.2 From c1739eb3e61e160f124bc842c219011916f63068 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Thu, 14 Oct 2010 12:45:29 -0700 Subject: ath9k: Remove bf_dmacontext. The bf_dmacontext seems to be totally useless and duplicated by bf_buf_addr. Remove it entirely, use bf_buf_addr in its place. Signed-off-by: Ben Greear Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index e435c1d..973c919 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -239,12 +239,11 @@ struct ath_buf { struct sk_buff *bf_mpdu; /* enclosing frame structure */ void *bf_desc; /* virtual addr of desc */ dma_addr_t bf_daddr; /* physical addr of desc */ - dma_addr_t bf_buf_addr; /* physical addr of data buffer */ + dma_addr_t bf_buf_addr; /* physical addr of data buffer, for DMA */ bool bf_stale; bool bf_tx_aborted; u16 bf_flags; struct ath_buf_state bf_state; - dma_addr_t bf_dmacontext; struct ath_wiphy *aphy; }; diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 081192e..af8fedd 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -136,7 +136,7 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, bf = avp->av_bcbuf; skb = bf->bf_mpdu; if (skb) { - dma_unmap_single(sc->dev, bf->bf_dmacontext, + dma_unmap_single(sc->dev, bf->bf_buf_addr, skb->len, DMA_TO_DEVICE); dev_kfree_skb_any(skb); } @@ -162,9 +162,8 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no); } - bf->bf_buf_addr = bf->bf_dmacontext = - dma_map_single(sc->dev, skb->data, - skb->len, DMA_TO_DEVICE); + bf->bf_buf_addr = dma_map_single(sc->dev, skb->data, + skb->len, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) { dev_kfree_skb_any(skb); bf->bf_mpdu = NULL; @@ -252,7 +251,7 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) bf = avp->av_bcbuf; if (bf->bf_mpdu != NULL) { skb = bf->bf_mpdu; - dma_unmap_single(sc->dev, bf->bf_dmacontext, + dma_unmap_single(sc->dev, bf->bf_buf_addr, skb->len, DMA_TO_DEVICE); dev_kfree_skb_any(skb); bf->bf_mpdu = NULL; @@ -296,9 +295,8 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) avp->tsf_adjust = cpu_to_le64(0); bf->bf_mpdu = skb; - bf->bf_buf_addr = bf->bf_dmacontext = - dma_map_single(sc->dev, skb->data, - skb->len, DMA_TO_DEVICE); + bf->bf_buf_addr = dma_map_single(sc->dev, skb->data, + skb->len, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) { dev_kfree_skb_any(skb); bf->bf_mpdu = NULL; @@ -324,7 +322,7 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp) bf = avp->av_bcbuf; if (bf->bf_mpdu != NULL) { struct sk_buff *skb = bf->bf_mpdu; - dma_unmap_single(sc->dev, bf->bf_dmacontext, + dma_unmap_single(sc->dev, bf->bf_buf_addr, skb->len, DMA_TO_DEVICE); dev_kfree_skb_any(skb); bf->bf_mpdu = NULL; diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 7c90eaf..2e42752 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -363,7 +363,6 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) error = -ENOMEM; goto err; } - bf->bf_dmacontext = bf->bf_buf_addr; } sc->rx.rxlink = NULL; } @@ -1739,7 +1738,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) ath_rx_send_to_mac80211(hw, sc, skb, rxs); break; } - bf->bf_dmacontext = bf->bf_buf_addr; /* * change the default rx antenna if rx diversity chooses the diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 9b17108..b053058 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -294,7 +294,6 @@ static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf) tbf->bf_buf_addr = bf->bf_buf_addr; memcpy(tbf->bf_desc, bf->bf_desc, sc->sc_ah->caps.tx_desc_len); tbf->bf_state = bf->bf_state; - tbf->bf_dmacontext = bf->bf_dmacontext; return tbf; } @@ -1640,17 +1639,15 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, bf->bf_mpdu = skb; - bf->bf_dmacontext = dma_map_single(sc->dev, skb->data, - skb->len, DMA_TO_DEVICE); - if (unlikely(dma_mapping_error(sc->dev, bf->bf_dmacontext))) { + bf->bf_buf_addr = dma_map_single(sc->dev, skb->data, + skb->len, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) { bf->bf_mpdu = NULL; ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL, "dma_mapping_error() on TX\n"); return -ENOMEM; } - bf->bf_buf_addr = bf->bf_dmacontext; - bf->bf_tx_aborted = false; return 0; @@ -1914,7 +1911,7 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, tx_flags |= ATH_TX_XRETRY; } - dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE); + dma_unmap_single(sc->dev, bf->bf_buf_addr, skb->len, DMA_TO_DEVICE); if (bf->bf_state.bfs_paprd) { if (time_after(jiffies, -- cgit v0.10.2 From 6cf9e995f91e5bbffb2bef85feef490e5b67605d Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Thu, 14 Oct 2010 12:45:30 -0700 Subject: ath9k: Null out references to stale pointers. This doesn't fix any problem that I'm aware of, but should make it harder to add use-after-free type bugs in the future. Signed-off-by: Ben Greear Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index af8fedd..4ed010d 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -139,6 +139,7 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, dma_unmap_single(sc->dev, bf->bf_buf_addr, skb->len, DMA_TO_DEVICE); dev_kfree_skb_any(skb); + bf->bf_buf_addr = 0; } /* Get a new beacon from mac80211 */ @@ -167,6 +168,7 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) { dev_kfree_skb_any(skb); bf->bf_mpdu = NULL; + bf->bf_buf_addr = 0; ath_print(common, ATH_DBG_FATAL, "dma_mapping_error on beaconing\n"); return NULL; @@ -255,6 +257,7 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) skb->len, DMA_TO_DEVICE); dev_kfree_skb_any(skb); bf->bf_mpdu = NULL; + bf->bf_buf_addr = 0; } /* NB: the beacon data buffer must be 32-bit aligned. */ @@ -300,6 +303,7 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) { dev_kfree_skb_any(skb); bf->bf_mpdu = NULL; + bf->bf_buf_addr = 0; ath_print(common, ATH_DBG_FATAL, "dma_mapping_error on beacon alloc\n"); return -ENOMEM; @@ -326,6 +330,7 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp) skb->len, DMA_TO_DEVICE); dev_kfree_skb_any(skb); bf->bf_mpdu = NULL; + bf->bf_buf_addr = 0; } list_add_tail(&bf->list, &sc->beacon.bbuf); diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 2e42752..fe73fc5 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -268,6 +268,7 @@ static int ath_rx_edma_init(struct ath_softc *sc, int nbufs) bf->bf_buf_addr))) { dev_kfree_skb_any(skb); bf->bf_mpdu = NULL; + bf->bf_buf_addr = 0; ath_print(common, ATH_DBG_FATAL, "dma_mapping_error() on RX init\n"); error = -ENOMEM; @@ -358,6 +359,7 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) bf->bf_buf_addr))) { dev_kfree_skb_any(skb); bf->bf_mpdu = NULL; + bf->bf_buf_addr = 0; ath_print(common, ATH_DBG_FATAL, "dma_mapping_error() on RX init\n"); error = -ENOMEM; @@ -392,6 +394,8 @@ void ath_rx_cleanup(struct ath_softc *sc) common->rx_bufsize, DMA_FROM_DEVICE); dev_kfree_skb(skb); + bf->bf_buf_addr = 0; + bf->bf_mpdu = NULL; } } @@ -1733,6 +1737,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) bf->bf_buf_addr))) { dev_kfree_skb_any(requeue_skb); bf->bf_mpdu = NULL; + bf->bf_buf_addr = 0; ath_print(common, ATH_DBG_FATAL, "dma_mapping_error() on RX\n"); ath_rx_send_to_mac80211(hw, sc, skb, rxs); diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index b053058..d077186 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1643,6 +1643,7 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, skb->len, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) { bf->bf_mpdu = NULL; + bf->bf_buf_addr = 0; ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL, "dma_mapping_error() on TX\n"); return -ENOMEM; @@ -1912,6 +1913,7 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, } dma_unmap_single(sc->dev, bf->bf_buf_addr, skb->len, DMA_TO_DEVICE); + bf->bf_buf_addr = 0; if (bf->bf_state.bfs_paprd) { if (time_after(jiffies, @@ -1924,6 +1926,10 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, ath_debug_stat_tx(sc, txq, bf, ts); ath_tx_complete(sc, skb, bf->aphy, tx_flags); } + /* At this point, skb (bf->bf_mpdu) is consumed...make sure we don't + * accidentally reference it later. + */ + bf->bf_mpdu = NULL; /* * Return the list of ath_buf of this mpdu to free queue -- cgit v0.10.2 From 0d91f22b75347d9503b17a42b6c74d3f7750acd6 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 15 Oct 2010 15:00:06 +0200 Subject: drivers/net/wireless/p54/eeprom.c: Return -ENOMEM on memory allocation failure In this code, 0 is returned on memory allocation failure, even though other failures return -ENOMEM or other similar values. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression ret; expression x,e1,e2,e3; @@ ret = 0 ... when != ret = e1 *x = \(kmalloc\|kcalloc\|kzalloc\)(...) ... when != ret = e2 if (x == NULL) { ... when != ret = e3 return ret; } // Signed-off-by: Julia Lawall Cc: Acked-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c index 8c05266..35b09aa 100644 --- a/drivers/net/wireless/p54/eeprom.c +++ b/drivers/net/wireless/p54/eeprom.c @@ -261,8 +261,10 @@ static int p54_generate_channel_lists(struct ieee80211_hw *dev) list->max_entries = max_channel_num; list->channels = kzalloc(sizeof(struct p54_channel_entry) * max_channel_num, GFP_KERNEL); - if (!list->channels) + if (!list->channels) { + ret = -ENOMEM; goto free; + } for (i = 0; i < max_channel_num; i++) { if (i < priv->iq_autocal_len) { -- cgit v0.10.2