From 8829c9e2ec144baeb3cee599e1e653a396ad521b Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Wed, 10 Nov 2010 11:05:38 -0800 Subject: iwlagn: used frame count info in compressed ba packet For newer devices, uCode provide both "number of frames sent" and "number of frames acked" information inside the compressed_ba packet. So instead of figure the success/failure information through the bitmap, use those information which is much betrer approach. 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 4748d06..a172bd1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2620,6 +2620,7 @@ static struct iwl_base_params iwl4965_base_params = { .ucode_tracing = true, .sensitivity_calib_by_driver = true, .chain_noise_calib_by_driver = true, + .no_agg_framecnt_info = true, }; struct iwl_cfg iwl4965_agn_cfg = { diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index 2b078a9..522c77f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -1241,37 +1241,61 @@ static int iwlagn_tx_status_reply_compressed_ba(struct iwl_priv *priv, if (sh < 0) /* tbw something is wrong with indices */ sh += 0x100; - /* don't use 64-bit values for now */ - bitmap = le64_to_cpu(ba_resp->bitmap) >> sh; - if (agg->frame_count > (64 - sh)) { IWL_DEBUG_TX_REPLY(priv, "more frames than bitmap size"); return -1; } - - /* check for success or failure according to the - * transmitted bitmap and block-ack bitmap */ - sent_bitmap = bitmap & agg->bitmap; - - /* For each frame attempted in aggregation, - * update driver's record of tx frame's status. */ - i = 0; - while (sent_bitmap) { - ack = sent_bitmap & 1ULL; - successes += ack; - IWL_DEBUG_TX_REPLY(priv, "%s ON i=%d idx=%d raw=%d\n", - ack ? "ACK" : "NACK", i, (agg->start_idx + i) & 0xff, - agg->start_idx + i); - sent_bitmap >>= 1; - ++i; + if (!priv->cfg->base_params->no_agg_framecnt_info && ba_resp->txed) { + /* + * sent and ack information provided by uCode + * use it instead of figure out ourself + */ + if (ba_resp->txed_2_done > ba_resp->txed) { + IWL_DEBUG_TX_REPLY(priv, + "bogus sent(%d) and ack(%d) count\n", + ba_resp->txed, ba_resp->txed_2_done); + /* + * set txed_2_done = txed, + * so it won't impact rate scale + */ + ba_resp->txed = ba_resp->txed_2_done; + } + IWL_DEBUG_HT(priv, "agg frames sent:%d, acked:%d\n", + ba_resp->txed, ba_resp->txed_2_done); + } else { + /* don't use 64-bit values for now */ + bitmap = le64_to_cpu(ba_resp->bitmap) >> sh; + + /* check for success or failure according to the + * transmitted bitmap and block-ack bitmap */ + sent_bitmap = bitmap & agg->bitmap; + + /* For each frame attempted in aggregation, + * update driver's record of tx frame's status. */ + i = 0; + while (sent_bitmap) { + ack = sent_bitmap & 1ULL; + successes += ack; + IWL_DEBUG_TX_REPLY(priv, "%s ON i=%d idx=%d raw=%d\n", + ack ? "ACK" : "NACK", i, + (agg->start_idx + i) & 0xff, + agg->start_idx + i); + sent_bitmap >>= 1; + ++i; + } } - info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb); memset(&info->status, 0, sizeof(info->status)); info->flags |= IEEE80211_TX_STAT_ACK; info->flags |= IEEE80211_TX_STAT_AMPDU; - info->status.ampdu_ack_len = successes; - info->status.ampdu_len = agg->frame_count; + if (!priv->cfg->base_params->no_agg_framecnt_info && ba_resp->txed) { + info->status.ampdu_ack_len = ba_resp->txed_2_done; + info->status.ampdu_len = ba_resp->txed; + + } else { + info->status.ampdu_ack_len = successes; + info->status.ampdu_len = agg->frame_count; + } iwlagn_hwrate_to_tx_control(priv, agg->rate_n_flags, info); IWL_DEBUG_TX_REPLY(priv, "Bitmap %llx\n", (unsigned long long)bitmap); diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 424801a..31c29a5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -2022,6 +2022,9 @@ struct iwl_compressed_ba_resp { __le64 bitmap; __le16 scd_flow; __le16 scd_ssn; + /* following only for 5000 series and up */ + u8 txed; /* number of frames sent */ + u8 txed_2_done; /* number of frames acked */ } __packed; /* diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index ee8cf24..98b79f6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -291,7 +291,9 @@ struct iwl_mod_params { * @chain_noise_calib_by_driver: driver has the capability to perform * chain noise calibration operation * @shadow_reg_enable: HW shadhow register bit -*/ + * @no_agg_framecnt_info: uCode do not provide aggregation frame count + * information + */ struct iwl_base_params { int eeprom_size; int num_of_queues; /* def: HW dependent */ @@ -322,6 +324,7 @@ struct iwl_base_params { const bool sensitivity_calib_by_driver; const bool chain_noise_calib_by_driver; const bool shadow_reg_enable; + const bool no_agg_framecnt_info; }; /* * @advanced_bt_coexist: support advanced bt coexist -- cgit v0.10.2 From 95a5ede3ee9269e175bfe0e6f5a4a5fd2914ed6a Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Mon, 8 Nov 2010 14:55:43 -0800 Subject: iwlagn: set dynamic aggregation threshold for BT Setting the max/min/def value for BT dynamic aggregation threshold. Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 31c29a5..a3cd811 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -2410,9 +2410,9 @@ struct iwl_link_quality_cmd { #define BT_FRAG_THRESHOLD_MAX 0 #define BT_FRAG_THRESHOLD_MIN 0 -#define BT_AGG_THRESHOLD_DEF 0 -#define BT_AGG_THRESHOLD_MAX 0 -#define BT_AGG_THRESHOLD_MIN 0 +#define BT_AGG_THRESHOLD_DEF 1200 +#define BT_AGG_THRESHOLD_MAX 8000 +#define BT_AGG_THRESHOLD_MIN 400 /* * REPLY_BT_CONFIG = 0x9b (command, has simple generic response) -- cgit v0.10.2 From 66e863a527f9ed3a871797862aaf0d62b0954813 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Mon, 8 Nov 2010 14:54:37 -0800 Subject: iwlagn: support dynamic aggregation for BT coex Use dynamic aggregation threshold if bt traffic load is high to reduce the impact on aggregated frame. 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 c7ff1bd..d8f9df6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -546,6 +546,7 @@ static struct iwl_bt_params iwl6000_bt_params = { .bt_statistics = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .advanced_bt_coexist = true, + .agg_time_limit = BT_AGG_THRESHOLD_DEF, .bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE, .bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index ca3530c..c6f65fd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -2025,7 +2025,6 @@ void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv, struct iwl_bt_coex_profile_notif *coex = &pkt->u.bt_coex_profile_notif; struct iwlagn_bt_sco_cmd sco_cmd = { .flags = 0 }; struct iwl_bt_uart_msg *uart_msg = &coex->last_bt_uart_msg; - u8 last_traffic_load; IWL_DEBUG_NOTIF(priv, "BT Coex notification:\n"); IWL_DEBUG_NOTIF(priv, " status: %d\n", coex->bt_status); @@ -2034,11 +2033,10 @@ void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv, coex->bt_ci_compliance); iwlagn_print_uartmsg(priv, uart_msg); - last_traffic_load = priv->notif_bt_traffic_load; - priv->notif_bt_traffic_load = coex->bt_traffic_load; + priv->last_bt_traffic_load = priv->bt_traffic_load; if (priv->iw_mode != NL80211_IFTYPE_ADHOC) { if (priv->bt_status != coex->bt_status || - last_traffic_load != coex->bt_traffic_load) { + priv->last_bt_traffic_load != coex->bt_traffic_load) { if (coex->bt_status) { /* BT on */ if (!priv->bt_ch_announce) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 0655536..f450adc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -833,17 +833,23 @@ static void rs_bt_update_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx, struct iwl_lq_sta *lq_sta) { struct iwl_scale_tbl_info *tbl; - bool full_concurrent; + bool full_concurrent = priv->bt_full_concurrent; unsigned long flags; - spin_lock_irqsave(&priv->lock, flags); - if (priv->bt_ci_compliance && priv->bt_ant_couple_ok) - full_concurrent = true; - else - full_concurrent = false; - spin_unlock_irqrestore(&priv->lock, flags); - - if (priv->bt_full_concurrent != full_concurrent) { + if (priv->bt_ant_couple_ok) { + /* + * Is there a need to switch between + * full concurrency and 3-wire? + */ + spin_lock_irqsave(&priv->lock, flags); + if (priv->bt_ci_compliance && priv->bt_ant_couple_ok) + full_concurrent = true; + else + full_concurrent = false; + spin_unlock_irqrestore(&priv->lock, flags); + } + if ((priv->bt_traffic_load != priv->last_bt_traffic_load) || + (priv->bt_full_concurrent != full_concurrent)) { priv->bt_full_concurrent = full_concurrent; /* Update uCode's rate table. */ @@ -1040,8 +1046,7 @@ done: if (sta && sta->supp_rates[sband->band]) rs_rate_scale_perform(priv, skb, sta, lq_sta); - /* Is there a need to switch between full concurrency and 3-wire? */ - if (priv->bt_ant_couple_ok) + if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist) rs_bt_update_lq(priv, ctx, lq_sta); } @@ -3010,10 +3015,7 @@ static void rs_fill_link_cmd(struct iwl_priv *priv, */ if (priv && priv->cfg->bt_params && priv->cfg->bt_params->agg_time_limit && - priv->cfg->bt_params->agg_time_limit >= - LINK_QUAL_AGG_TIME_LIMIT_MIN && - priv->cfg->bt_params->agg_time_limit <= - LINK_QUAL_AGG_TIME_LIMIT_MAX) + priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH) lq_cmd->agg_params.agg_time_limit = cpu_to_le16(priv->cfg->bt_params->agg_time_limit); } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 007fb20..d976912 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3837,7 +3837,6 @@ static int iwl_init_drv(struct iwl_priv *priv) priv->bt_on_thresh = BT_ON_THRESHOLD_DEF; priv->bt_duration = BT_DURATION_LIMIT_DEF; priv->dynamic_frag_thresh = BT_FRAG_THRESHOLD_DEF; - priv->dynamic_agg_thresh = BT_AGG_THRESHOLD_DEF; } /* Set the tx_power_user_lmt to the lowest power level diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index c884ed3..c41f5a87 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1469,7 +1469,7 @@ static void iwl_teardown_interface(struct iwl_priv *priv, * both values are the same and zero. */ if (vif->type == NL80211_IFTYPE_ADHOC) - priv->bt_traffic_load = priv->notif_bt_traffic_load; + priv->bt_traffic_load = priv->last_bt_traffic_load; } void iwl_mac_remove_interface(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 8fdd4ef..4876e26 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -1580,7 +1580,7 @@ static ssize_t iwl_dbgfs_bt_traffic_read(struct file *file, priv->bt_full_concurrent ? "full concurrency" : "3-wire"); pos += scnprintf(buf + pos, bufsz - pos, "BT status: %s, " "last traffic notif: %d\n", - priv->bt_status ? "On" : "Off", priv->notif_bt_traffic_load); + priv->bt_status ? "On" : "Off", priv->last_bt_traffic_load); pos += scnprintf(buf + pos, bufsz - pos, "ch_announcement: %d, " "sco_active: %d, kill_ack_mask: %x, " "kill_cts_mask: %x\n", diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 9fcaaf0..ea81ced 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1471,7 +1471,7 @@ struct iwl_priv { /* bt coex */ u8 bt_status; - u8 bt_traffic_load, notif_bt_traffic_load; + u8 bt_traffic_load, last_bt_traffic_load; bool bt_ch_announce; bool bt_sco_active; bool bt_full_concurrent; @@ -1482,7 +1482,6 @@ struct iwl_priv { u16 bt_on_thresh; u16 bt_duration; u16 dynamic_frag_thresh; - u16 dynamic_agg_thresh; u8 bt_ci_compliance; struct work_struct bt_traffic_change_work; -- cgit v0.10.2 From 05433df23cf16a9ccbdd35964aba781cdf455034 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Mon, 8 Nov 2010 12:37:20 -0800 Subject: iwlagn: change default ACK/CTS MASK setting for WiFi/BT coex Change the default BT_KILL_ACK_MASK and BT_KILL_CTS_MASK for BT coex Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index a3cd811..9c1b7fb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -2450,8 +2450,8 @@ struct iwl_bt_cmd { #define IWLAGN_BT3_T7_DEFAULT 1 -#define IWLAGN_BT_KILL_ACK_MASK_DEFAULT cpu_to_le32(0xffffffff) -#define IWLAGN_BT_KILL_CTS_MASK_DEFAULT cpu_to_le32(0xffffffff) +#define IWLAGN_BT_KILL_ACK_MASK_DEFAULT cpu_to_le32(0xffff0000) +#define IWLAGN_BT_KILL_CTS_MASK_DEFAULT cpu_to_le32(0xffff0000) #define IWLAGN_BT3_PRIO_SAMPLE_DEFAULT 2 -- cgit v0.10.2 From 564b344c10b694d433cef5b89f8ff8ac5e33898d Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Tue, 9 Nov 2010 09:21:34 -0800 Subject: iwlwifi: change default led mode for different devices Set the default led mode for different devices. For the newer devices such as 6000g2a, 6000g2b and newer, the default led mode is On/Off instead of blinking. The led_mode still can be control through module parameter 0: system default 1: On/Off 2: blinking 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 068f1e1..e881b08 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -287,6 +287,7 @@ struct iwl_cfg iwl1000_bgn_cfg = { .mod_params = &iwlagn_mod_params, .base_params = &iwl1000_base_params, .ht_params = &iwl1000_ht_params, + .led_mode = IWL_LED_BLINK, }; struct iwl_cfg iwl1000_bg_cfg = { @@ -302,6 +303,7 @@ struct iwl_cfg iwl1000_bg_cfg = { .ops = &iwl1000_ops, .mod_params = &iwlagn_mod_params, .base_params = &iwl1000_base_params, + .led_mode = IWL_LED_BLINK, }; struct iwl_cfg iwl100_bgn_cfg = { @@ -318,6 +320,7 @@ struct iwl_cfg iwl100_bgn_cfg = { .mod_params = &iwlagn_mod_params, .base_params = &iwl1000_base_params, .ht_params = &iwl1000_ht_params, + .led_mode = IWL_LED_RF_STATE, }; struct iwl_cfg iwl100_bg_cfg = { @@ -333,6 +336,7 @@ struct iwl_cfg iwl100_bg_cfg = { .ops = &iwl1000_ops, .mod_params = &iwlagn_mod_params, .base_params = &iwl1000_base_params, + .led_mode = IWL_LED_RF_STATE, }; MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index ebac04b..4503245 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -2788,6 +2788,7 @@ static struct iwl_cfg iwl3945_bg_cfg = { .ops = &iwl3945_ops, .mod_params = &iwl3945_mod_params, .base_params = &iwl3945_base_params, + .led_mode = IWL_LED_BLINK, }; static struct iwl_cfg iwl3945_abg_cfg = { @@ -2800,6 +2801,7 @@ static struct iwl_cfg iwl3945_abg_cfg = { .ops = &iwl3945_ops, .mod_params = &iwl3945_mod_params, .base_params = &iwl3945_base_params, + .led_mode = IWL_LED_BLINK, }; DEFINE_PCI_DEVICE_TABLE(iwl3945_hw_card_ids) = { diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index a172bd1..19da3e5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2636,6 +2636,7 @@ struct iwl_cfg iwl4965_agn_cfg = { .ops = &iwl4965_ops, .mod_params = &iwlagn_mod_params, .base_params = &iwl4965_base_params, + .led_mode = IWL_LED_BLINK, /* * Force use of chains B and C for scan RX on 5 GHz band * because the device has off-channel reception on chain A. diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index ad43f0fd..b147580 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -536,6 +536,7 @@ struct iwl_cfg iwl5300_agn_cfg = { .mod_params = &iwlagn_mod_params, .base_params = &iwl5000_base_params, .ht_params = &iwl5000_ht_params, + .led_mode = IWL_LED_BLINK, }; struct iwl_cfg iwl5100_bgn_cfg = { @@ -552,6 +553,7 @@ struct iwl_cfg iwl5100_bgn_cfg = { .mod_params = &iwlagn_mod_params, .base_params = &iwl5000_base_params, .ht_params = &iwl5000_ht_params, + .led_mode = IWL_LED_BLINK, }; struct iwl_cfg iwl5100_abg_cfg = { @@ -567,6 +569,7 @@ struct iwl_cfg iwl5100_abg_cfg = { .ops = &iwl5000_ops, .mod_params = &iwlagn_mod_params, .base_params = &iwl5000_base_params, + .led_mode = IWL_LED_BLINK, }; struct iwl_cfg iwl5100_agn_cfg = { @@ -583,6 +586,7 @@ struct iwl_cfg iwl5100_agn_cfg = { .mod_params = &iwlagn_mod_params, .base_params = &iwl5000_base_params, .ht_params = &iwl5000_ht_params, + .led_mode = IWL_LED_BLINK, }; struct iwl_cfg iwl5350_agn_cfg = { @@ -599,6 +603,7 @@ struct iwl_cfg iwl5350_agn_cfg = { .mod_params = &iwlagn_mod_params, .base_params = &iwl5000_base_params, .ht_params = &iwl5000_ht_params, + .led_mode = IWL_LED_BLINK, }; struct iwl_cfg iwl5150_agn_cfg = { @@ -616,6 +621,7 @@ struct iwl_cfg iwl5150_agn_cfg = { .base_params = &iwl5000_base_params, .ht_params = &iwl5000_ht_params, .need_dc_calib = true, + .led_mode = IWL_LED_BLINK, }; struct iwl_cfg iwl5150_abg_cfg = { @@ -632,6 +638,7 @@ struct iwl_cfg iwl5150_abg_cfg = { .mod_params = &iwlagn_mod_params, .base_params = &iwl5000_base_params, .need_dc_calib = true, + .led_mode = IWL_LED_BLINK, }; MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index d8f9df6..9f835ac 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -567,6 +567,7 @@ struct iwl_cfg iwl6000g2a_2agn_cfg = { .ht_params = &iwl6000_ht_params, .need_dc_calib = true, .need_temp_offset_calib = true, + .led_mode = IWL_LED_RF_STATE, }; struct iwl_cfg iwl6000g2a_2abg_cfg = { @@ -584,6 +585,7 @@ struct iwl_cfg iwl6000g2a_2abg_cfg = { .base_params = &iwl6000_base_params, .need_dc_calib = true, .need_temp_offset_calib = true, + .led_mode = IWL_LED_RF_STATE, }; struct iwl_cfg iwl6000g2a_2bg_cfg = { @@ -601,6 +603,7 @@ struct iwl_cfg iwl6000g2a_2bg_cfg = { .base_params = &iwl6000_base_params, .need_dc_calib = true, .need_temp_offset_calib = true, + .led_mode = IWL_LED_RF_STATE, }; struct iwl_cfg iwl6000g2b_2agn_cfg = { @@ -620,6 +623,7 @@ struct iwl_cfg iwl6000g2b_2agn_cfg = { .ht_params = &iwl6000_ht_params, .need_dc_calib = true, .need_temp_offset_calib = true, + .led_mode = IWL_LED_RF_STATE, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, }; @@ -640,6 +644,7 @@ struct iwl_cfg iwl6000g2b_2abg_cfg = { .bt_params = &iwl6000_bt_params, .need_dc_calib = true, .need_temp_offset_calib = true, + .led_mode = IWL_LED_RF_STATE, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, }; @@ -661,6 +666,7 @@ struct iwl_cfg iwl6000g2b_2bgn_cfg = { .ht_params = &iwl6000_ht_params, .need_dc_calib = true, .need_temp_offset_calib = true, + .led_mode = IWL_LED_RF_STATE, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, }; @@ -681,6 +687,7 @@ struct iwl_cfg iwl6000g2b_2bg_cfg = { .bt_params = &iwl6000_bt_params, .need_dc_calib = true, .need_temp_offset_calib = true, + .led_mode = IWL_LED_RF_STATE, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, }; @@ -702,6 +709,7 @@ struct iwl_cfg iwl6000g2b_bgn_cfg = { .ht_params = &iwl6000_ht_params, .need_dc_calib = true, .need_temp_offset_calib = true, + .led_mode = IWL_LED_RF_STATE, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, }; @@ -722,6 +730,7 @@ struct iwl_cfg iwl6000g2b_bg_cfg = { .bt_params = &iwl6000_bt_params, .need_dc_calib = true, .need_temp_offset_calib = true, + .led_mode = IWL_LED_RF_STATE, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, }; @@ -744,6 +753,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .base_params = &iwl6000_base_params, .ht_params = &iwl6000_ht_params, .pa_type = IWL_PA_INTERNAL, + .led_mode = IWL_LED_BLINK, }; struct iwl_cfg iwl6000i_2abg_cfg = { @@ -760,6 +770,7 @@ struct iwl_cfg iwl6000i_2abg_cfg = { .mod_params = &iwlagn_mod_params, .base_params = &iwl6000_base_params, .pa_type = IWL_PA_INTERNAL, + .led_mode = IWL_LED_BLINK, }; struct iwl_cfg iwl6000i_2bg_cfg = { @@ -776,6 +787,7 @@ struct iwl_cfg iwl6000i_2bg_cfg = { .mod_params = &iwlagn_mod_params, .base_params = &iwl6000_base_params, .pa_type = IWL_PA_INTERNAL, + .led_mode = IWL_LED_BLINK, }; struct iwl_cfg iwl6050_2agn_cfg = { @@ -793,6 +805,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .base_params = &iwl6050_base_params, .ht_params = &iwl6000_ht_params, .need_dc_calib = true, + .led_mode = IWL_LED_BLINK, }; struct iwl_cfg iwl6050g2_bgn_cfg = { @@ -810,6 +823,7 @@ struct iwl_cfg iwl6050g2_bgn_cfg = { .base_params = &iwl6050_base_params, .ht_params = &iwl6000_ht_params, .need_dc_calib = true, + .led_mode = IWL_LED_RF_STATE, }; struct iwl_cfg iwl6050_2abg_cfg = { @@ -826,6 +840,7 @@ struct iwl_cfg iwl6050_2abg_cfg = { .mod_params = &iwlagn_mod_params, .base_params = &iwl6050_base_params, .need_dc_calib = true, + .led_mode = IWL_LED_BLINK, }; struct iwl_cfg iwl6000_3agn_cfg = { @@ -843,6 +858,7 @@ struct iwl_cfg iwl6000_3agn_cfg = { .base_params = &iwl6000_base_params, .ht_params = &iwl6000_ht_params, .need_dc_calib = true, + .led_mode = IWL_LED_BLINK, }; struct iwl_cfg iwl130_bgn_cfg = { @@ -861,6 +877,7 @@ struct iwl_cfg iwl130_bgn_cfg = { .bt_params = &iwl6000_bt_params, .ht_params = &iwl6000_ht_params, .need_dc_calib = true, + .led_mode = IWL_LED_RF_STATE, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, }; @@ -880,6 +897,7 @@ struct iwl_cfg iwl130_bg_cfg = { .base_params = &iwl6000_coex_base_params, .bt_params = &iwl6000_bt_params, .need_dc_calib = true, + .led_mode = IWL_LED_RF_STATE, /* 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-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 98b79f6..9035cd8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -363,6 +363,7 @@ struct iwl_ht_params { * @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 + * @led_mode: 0=blinking, 1=On(RF On)/Off(RF Off) * * We enable the driver to be backward compatible wrt API version. The * driver specifies which APIs it supports (with @ucode_api_max being the @@ -409,6 +410,7 @@ struct iwl_cfg { 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]; + enum iwl_led_mode led_mode; }; /*************************** diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 5a91292..516e557 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -45,9 +45,8 @@ /* default: IWL_LED_BLINK(0) using blinking index table */ static int led_mode; module_param(led_mode, int, S_IRUGO); -MODULE_PARM_DESC(led_mode, "led mode: 0=blinking, 1=On(RF On)/Off(RF Off), " - "(default 0)"); - +MODULE_PARM_DESC(led_mode, "led mode: 0=system default, " + "1=On(RF On)/Off(RF Off), 2=blinking"); static const struct { u16 tpt; /* Mb/s */ @@ -128,7 +127,7 @@ EXPORT_SYMBOL(iwl_led_start); int iwl_led_associate(struct iwl_priv *priv) { IWL_DEBUG_LED(priv, "Associated\n"); - if (led_mode == IWL_LED_BLINK) + if (priv->cfg->led_mode == IWL_LED_BLINK) priv->allow_blinking = 1; priv->last_blink_time = jiffies; @@ -223,5 +222,8 @@ void iwl_leds_init(struct iwl_priv *priv) priv->last_blink_rate = 0; priv->last_blink_time = 0; priv->allow_blinking = 0; + if (led_mode != IWL_LED_DEFAULT && + led_mode != priv->cfg->led_mode) + priv->cfg->led_mode = led_mode; } EXPORT_SYMBOL(iwl_leds_init); diff --git a/drivers/net/wireless/iwlwifi/iwl-led.h b/drivers/net/wireless/iwlwifi/iwl-led.h index 49a70ba..9079b33 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.h +++ b/drivers/net/wireless/iwlwifi/iwl-led.h @@ -47,14 +47,16 @@ enum led_type { /* * LED mode - * IWL_LED_BLINK: adjust led blink rate based on blink table + * IWL_LED_DEFAULT: use system default * IWL_LED_RF_STATE: turn LED on/off based on RF state * LED ON = RF ON * LED OFF = RF OFF + * IWL_LED_BLINK: adjust led blink rate based on blink table */ enum iwl_led_mode { - IWL_LED_BLINK, + IWL_LED_DEFAULT, IWL_LED_RF_STATE, + IWL_LED_BLINK, }; void iwl_leds_init(struct iwl_priv *priv); -- cgit v0.10.2 From 76f379cec6df6c9c5c9dbf7377d1bbbb0bf3fd5f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 10 Nov 2010 18:25:41 -0800 Subject: iwlagn: fix some naming regarding FIFOs Some variables are misnamed in the FIFO setup code, fix that. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c index 7036211..8b129e2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c @@ -429,7 +429,7 @@ void iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type) int iwlagn_alive_notify(struct iwl_priv *priv) { - const s8 *queues; + const s8 *queue_to_fifo; u32 a; unsigned long flags; int i, chan; @@ -492,9 +492,9 @@ int iwlagn_alive_notify(struct iwl_priv *priv) /* map queues to FIFOs */ if (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS)) - queues = iwlagn_ipan_queue_to_tx_fifo; + queue_to_fifo = iwlagn_ipan_queue_to_tx_fifo; else - queues = iwlagn_default_queue_to_tx_fifo; + queue_to_fifo = iwlagn_default_queue_to_tx_fifo; iwlagn_set_wr_ptrs(priv, priv->cmd_queue, 0); @@ -510,14 +510,14 @@ int iwlagn_alive_notify(struct iwl_priv *priv) BUILD_BUG_ON(ARRAY_SIZE(iwlagn_ipan_queue_to_tx_fifo) != 10); for (i = 0; i < 10; i++) { - int ac = queues[i]; + int fifo = queue_to_fifo[i]; iwl_txq_ctx_activate(priv, i); - if (ac == IWL_TX_FIFO_UNUSED) + if (fifo == IWL_TX_FIFO_UNUSED) continue; - iwlagn_tx_queue_set_status(priv, &priv->txq[i], ac, 0); + iwlagn_tx_queue_set_status(priv, &priv->txq[i], fifo, 0); } spin_unlock_irqrestore(&priv->lock, flags); -- cgit v0.10.2 From 8d56396ac3926412dd97dcb9dd8d0cef556b908e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 10 Nov 2010 18:25:42 -0800 Subject: iwlagn: remove unused variable swq_id Simply remove the unused variable swq_id. 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 522c77f..0fc86c9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -518,7 +518,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) struct iwl_cmd_meta *out_meta; struct iwl_tx_cmd *tx_cmd; struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - int swq_id, txq_id; + int txq_id; dma_addr_t phys_addr; dma_addr_t txcmd_phys; dma_addr_t scratch_phys; @@ -620,7 +620,6 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) } txq = &priv->txq[txq_id]; - swq_id = txq->swq_id; q = &txq->q; if (unlikely(iwl_queue_space(q) < q->high_mark)) { -- cgit v0.10.2 From 4bea9b990205e4a3d432d9d6c29687215618a306 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 10 Nov 2010 18:25:43 -0800 Subject: iwlagn: remove a bogus AGG_OFF check Even if this check were to happen, using the txq_id here (which is a HW queue) would lead to confusion in mac80211. Luckily, it doesn't seem like this can ever happen. 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 19da3e5..1940079 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2238,12 +2238,8 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, if (priv->mac80211_registered && (iwl_queue_space(&txq->q) > txq->q.low_mark) && - (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) { - if (agg->state == IWL_AGG_OFF) - iwl_wake_queue(priv, txq_id); - else - iwl_wake_queue(priv, txq->swq_id); - } + (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) + iwl_wake_queue(priv, txq->swq_id); } } else { info->status.rates[0].count = tx_resp->failure_frame + 1; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index c6f65fd..2ba83b5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -445,12 +445,8 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv, if (priv->mac80211_registered && (iwl_queue_space(&txq->q) > txq->q.low_mark) && - (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) { - if (agg->state == IWL_AGG_OFF) - iwl_wake_queue(priv, txq_id); - else - iwl_wake_queue(priv, txq->swq_id); - } + (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) + iwl_wake_queue(priv, txq->swq_id); } } else { BUG_ON(txq_id != txq->swq_id); -- cgit v0.10.2 From 549a04e092e5e043df82fd0541f3b67ab488359b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 10 Nov 2010 18:25:44 -0800 Subject: iwlwifi: pass txq to wake/stop queue Instead of passing the txq->swq_id, pass the txq struct directly to make sure that in the future nobody will pass an invalid number. Only three places actually change from using the txq_id or the skb's queue_mapping to now using txq->swq_id as well. 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 4503245..56f4ca7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -297,7 +297,7 @@ static void iwl3945_tx_queue_reclaim(struct iwl_priv *priv, if (iwl_queue_space(q) > q->low_mark && (txq_id >= 0) && (txq_id != IWL39_CMD_QUEUE_NUM) && priv->mac80211_registered) - iwl_wake_queue(priv, txq_id); + iwl_wake_queue(priv, txq); } /** diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 1940079..2ec868d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2239,7 +2239,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, if (priv->mac80211_registered && (iwl_queue_space(&txq->q) > txq->q.low_mark) && (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) - iwl_wake_queue(priv, txq->swq_id); + iwl_wake_queue(priv, txq); } } else { info->status.rates[0].count = tx_resp->failure_frame + 1; @@ -2263,7 +2263,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, if (priv->mac80211_registered && (iwl_queue_space(&txq->q) > txq->q.low_mark)) - iwl_wake_queue(priv, txq_id); + iwl_wake_queue(priv, txq); } if (qc && likely(sta_id != IWL_INVALID_STATION)) iwlagn_txq_check_empty(priv, sta_id, tid, txq_id); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 2ba83b5..eef90b5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -446,7 +446,7 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv, if (priv->mac80211_registered && (iwl_queue_space(&txq->q) > txq->q.low_mark) && (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) - iwl_wake_queue(priv, txq->swq_id); + iwl_wake_queue(priv, txq); } } else { BUG_ON(txq_id != txq->swq_id); @@ -456,7 +456,7 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv, if (priv->mac80211_registered && (iwl_queue_space(&txq->q) > txq->q.low_mark)) - iwl_wake_queue(priv, txq_id); + iwl_wake_queue(priv, txq); } iwlagn_txq_check_empty(priv, sta_id, tid, txq_id); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index 0fc86c9..179a9c8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -783,7 +783,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) iwl_txq_update_write_ptr(priv, txq); spin_unlock_irqrestore(&priv->lock, flags); } else { - iwl_stop_queue(priv, txq->swq_id); + iwl_stop_queue(priv, txq); } } @@ -1408,7 +1408,7 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, if ((iwl_queue_space(&txq->q) > txq->q.low_mark) && priv->mac80211_registered && (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) - iwl_wake_queue(priv, txq->swq_id); + iwl_wake_queue(priv, txq); iwlagn_txq_check_empty(priv, sta_id, tid, scd_flow); } diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h index 1aaef70..23fa8e8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-helpers.h +++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h @@ -116,8 +116,10 @@ static inline u8 iwl_virtual_agg_queue_num(u8 ac, u8 hwq) return 0x80 | (hwq << 2) | ac; } -static inline void iwl_wake_queue(struct iwl_priv *priv, u8 queue) +static inline void iwl_wake_queue(struct iwl_priv *priv, + struct iwl_tx_queue *txq) { + u8 queue = txq->swq_id; u8 ac = queue; u8 hwq = queue; @@ -131,8 +133,10 @@ static inline void iwl_wake_queue(struct iwl_priv *priv, u8 queue) ieee80211_wake_queue(priv->hw, ac); } -static inline void iwl_stop_queue(struct iwl_priv *priv, u8 queue) +static inline void iwl_stop_queue(struct iwl_priv *priv, + struct iwl_tx_queue *txq) { + u8 queue = txq->swq_id; u8 ac = queue; u8 hwq = queue; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index a55b462..b8c4906 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -662,7 +662,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) spin_unlock_irqrestore(&priv->lock, flags); } - iwl_stop_queue(priv, skb_get_queue_mapping(skb)); + iwl_stop_queue(priv, txq); } return 0; -- cgit v0.10.2 From ea9b307f8e859186a6791e0d508c5993448ac900 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 10 Nov 2010 18:25:45 -0800 Subject: iwlwifi: always build swq_id as virtual queue ID Previously, we used the swq_id's mechanism to have AC and HW queue different only for aggregation queues. To be able to fix a bug with iPAN simply always build the swq_id as ac | (hwq << 2) and remove the flag bit. 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 eef90b5..881475c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -449,7 +449,6 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv, iwl_wake_queue(priv, txq); } } else { - BUG_ON(txq_id != txq->swq_id); iwlagn_set_tx_status(priv, info, tx_resp, txq_id, false); freed = iwlagn_tx_queue_reclaim(priv, txq_id, index); iwl_free_tfds_in_queue(priv, sta_id, tid, freed); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index 179a9c8..330852c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -1012,7 +1012,7 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif, tid_data = &priv->stations[sta_id].tid[tid]; *ssn = SEQ_TO_SN(tid_data->seq_number); tid_data->agg.txq_id = txq_id; - priv->txq[txq_id].swq_id = iwl_virtual_agg_queue_num(get_ac_from_tid(tid), txq_id); + iwl_set_swq_id(&priv->txq[txq_id], get_ac_from_tid(tid), txq_id); spin_unlock_irqrestore(&priv->sta_lock, flags); ret = priv->cfg->ops->lib->txq_agg_enable(priv, txq_id, tx_fifo, diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 4876e26..3cc5842 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -992,11 +992,8 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file, " swq_id=%#.2x (ac %d/hwq %d)\n", cnt, q->read_ptr, q->write_ptr, !!test_bit(cnt, priv->queue_stopped), - txq->swq_id, - txq->swq_id & 0x80 ? txq->swq_id & 3 : - txq->swq_id, - txq->swq_id & 0x80 ? (txq->swq_id >> 2) & - 0x1f : txq->swq_id); + txq->swq_id, txq->swq_id & 3, + (txq->swq_id >> 2) & 0x1f); if (cnt >= 4) continue; /* for the ACs, display the stop count too */ diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h index 23fa8e8..e53cd7f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-helpers.h +++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h @@ -104,29 +104,24 @@ static inline int iwl_alloc_fw_desc(struct pci_dev *pci_dev, * | | | | | | | | * | | | | | | +-+-------- AC queue (0-3) * | | | | | | - * | +-+-+-+-+------------ HW A-MPDU queue + * | +-+-+-+-+------------ HW queue ID * | - * +---------------------- indicates agg queue + * +---------------------- unused */ -static inline u8 iwl_virtual_agg_queue_num(u8 ac, u8 hwq) +static inline void iwl_set_swq_id(struct iwl_tx_queue *txq, u8 ac, u8 hwq) { BUG_ON(ac > 3); /* only have 2 bits */ - BUG_ON(hwq > 31); /* only have 5 bits */ + BUG_ON(hwq > 31); /* only use 5 bits */ - return 0x80 | (hwq << 2) | ac; + txq->swq_id = (hwq << 2) | ac; } static inline void iwl_wake_queue(struct iwl_priv *priv, struct iwl_tx_queue *txq) { u8 queue = txq->swq_id; - u8 ac = queue; - u8 hwq = queue; - - if (queue & 0x80) { - ac = queue & 3; - hwq = (queue >> 2) & 0x1f; - } + u8 ac = queue & 3; + u8 hwq = (queue >> 2) & 0x1f; if (test_and_clear_bit(hwq, priv->queue_stopped)) if (atomic_dec_return(&priv->queue_stop_count[ac]) <= 0) @@ -137,13 +132,8 @@ static inline void iwl_stop_queue(struct iwl_priv *priv, struct iwl_tx_queue *txq) { u8 queue = txq->swq_id; - u8 ac = queue; - u8 hwq = queue; - - if (queue & 0x80) { - ac = queue & 3; - hwq = (queue >> 2) & 0x1f; - } + u8 ac = queue & 3; + u8 hwq = (queue >> 2) & 0x1f; if (!test_and_set_bit(hwq, priv->queue_stopped)) if (atomic_inc_return(&priv->queue_stop_count[ac]) > 0) diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index feaa367..90659bc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -359,13 +359,12 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq, txq->need_update = 0; /* - * Aggregation TX queues will get their ID when aggregation begins; - * they overwrite the setting done here. The command FIFO doesn't - * need an swq_id so don't set one to catch errors, all others can - * be set up to the identity mapping. + * For the default queues 0-3, set up the swq_id + * already -- all others need to get one later + * (if they need one at all). */ - if (txq_id != priv->cmd_queue) - txq->swq_id = txq_id; + if (txq_id < 4) + iwl_set_swq_id(txq, txq_id, txq_id); /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */ -- cgit v0.10.2 From cfa1da7e9133be9280990b2a64fa7696924c8d9a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 10 Nov 2010 18:25:46 -0800 Subject: iwlagn: fix PAN queues Currently, when a PAN queue needs to be stopped, we erroneously stop queue number 5 (for example) with mac80211 -- which doesn't even exist! To avoid that problem, recalculate the swq_id for all queues when setting up the queues, and don't use the default identity mapping that is acceptable for devices which don't support PAN. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c index 8b129e2..411a7a2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c @@ -40,30 +40,36 @@ #include "iwl-agn.h" #include "iwl-agn-calib.h" -static const s8 iwlagn_default_queue_to_tx_fifo[] = { - IWL_TX_FIFO_VO, - IWL_TX_FIFO_VI, - IWL_TX_FIFO_BE, - IWL_TX_FIFO_BK, - IWLAGN_CMD_FIFO_NUM, - IWL_TX_FIFO_UNUSED, - IWL_TX_FIFO_UNUSED, - IWL_TX_FIFO_UNUSED, - IWL_TX_FIFO_UNUSED, - IWL_TX_FIFO_UNUSED, +#define IWL_AC_UNSET -1 + +struct queue_to_fifo_ac { + s8 fifo, ac; +}; + +static const struct queue_to_fifo_ac iwlagn_default_queue_to_tx_fifo[] = { + { IWL_TX_FIFO_VO, 0, }, + { IWL_TX_FIFO_VI, 1, }, + { IWL_TX_FIFO_BE, 2, }, + { IWL_TX_FIFO_BK, 3, }, + { IWLAGN_CMD_FIFO_NUM, IWL_AC_UNSET, }, + { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, }, + { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, }, + { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, }, + { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, }, + { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, }, }; -static const s8 iwlagn_ipan_queue_to_tx_fifo[] = { - IWL_TX_FIFO_VO, - IWL_TX_FIFO_VI, - IWL_TX_FIFO_BE, - IWL_TX_FIFO_BK, - IWL_TX_FIFO_BK_IPAN, - IWL_TX_FIFO_BE_IPAN, - IWL_TX_FIFO_VI_IPAN, - IWL_TX_FIFO_VO_IPAN, - IWL_TX_FIFO_BE_IPAN, - IWLAGN_CMD_FIFO_NUM, +static const struct queue_to_fifo_ac iwlagn_ipan_queue_to_tx_fifo[] = { + { IWL_TX_FIFO_VO, 0, }, + { IWL_TX_FIFO_VI, 1, }, + { IWL_TX_FIFO_BE, 2, }, + { IWL_TX_FIFO_BK, 3, }, + { IWL_TX_FIFO_BK_IPAN, 3, }, + { IWL_TX_FIFO_BE_IPAN, 2, }, + { IWL_TX_FIFO_VI_IPAN, 1, }, + { IWL_TX_FIFO_VO_IPAN, 0, }, + { IWL_TX_FIFO_BE_IPAN, 2, }, + { IWLAGN_CMD_FIFO_NUM, IWL_AC_UNSET, }, }; static struct iwl_wimax_coex_event_entry cu_priorities[COEX_NUM_OF_EVENTS] = { @@ -429,7 +435,7 @@ void iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type) int iwlagn_alive_notify(struct iwl_priv *priv) { - const s8 *queue_to_fifo; + const struct queue_to_fifo_ac *queue_to_fifo; u32 a; unsigned long flags; int i, chan; @@ -510,13 +516,16 @@ int iwlagn_alive_notify(struct iwl_priv *priv) BUILD_BUG_ON(ARRAY_SIZE(iwlagn_ipan_queue_to_tx_fifo) != 10); for (i = 0; i < 10; i++) { - int fifo = queue_to_fifo[i]; + int fifo = queue_to_fifo[i].fifo; + int ac = queue_to_fifo[i].ac; iwl_txq_ctx_activate(priv, i); if (fifo == IWL_TX_FIFO_UNUSED) continue; + if (ac != IWL_AC_UNSET) + iwl_set_swq_id(&priv->txq[i], ac, i); iwlagn_tx_queue_set_status(priv, &priv->txq[i], fifo, 0); } -- cgit v0.10.2 From 893654de3ff41a4f5037397d06a3f853bbbb3484 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 10 Nov 2010 18:25:47 -0800 Subject: iwlagn: avoid crash if vif is not assigned For reasons that aren't entirely clear to me, we sometimes get here during hardware reset without the interface being set. Don't crash, but keep a warning. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index 2d927a9..fbaa8d2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -507,6 +507,11 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, mutex_lock(&priv->mutex); + if (WARN_ON(!ctx->vif)) { + mutex_unlock(&priv->mutex); + return; + } + if (changes & BSS_CHANGED_BEACON_INT) force = true; -- cgit v0.10.2 From 2b5f7a679c2ae34407f6cc9387e77b563578bfdc Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 10 Nov 2010 18:25:48 -0800 Subject: iwlagn: reprogram AP STA after assoc Instead of unconditionally sending unassoc RXON, before any assoc RXON, re-send only the AP STA entry which is required after the BSSID has been programmed into the device to set up internal filters in the microcode properly. This fixes some issues that we correlated with sending a lot of RXON commands to the device. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index fbaa8d2..9db3924 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -97,6 +97,7 @@ 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 = (void *)&ctx->active; bool new_assoc = !!(ctx->staging.filter_flags & RXON_FILTER_ASSOC_MSK); + bool old_assoc = !!(ctx->active.filter_flags & RXON_FILTER_ASSOC_MSK); int ret; lockdep_assert_held(&priv->mutex); @@ -176,25 +177,27 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) * AP station must be done after the BSSID is set to correctly * set up filters in the device. */ - if (ctx->ctxid == IWL_RXON_CTX_BSS) - ret = iwlagn_disable_bss(priv, ctx, &ctx->staging); - else - ret = iwlagn_disable_pan(priv, ctx, &ctx->staging); - if (ret) - return ret; + if ((old_assoc && new_assoc) || !new_assoc) { + if (ctx->ctxid == IWL_RXON_CTX_BSS) + ret = iwlagn_disable_bss(priv, ctx, &ctx->staging); + else + ret = iwlagn_disable_pan(priv, ctx, &ctx->staging); + if (ret) + return ret; - memcpy(active, &ctx->staging, sizeof(*active)); + memcpy(active, &ctx->staging, sizeof(*active)); - /* - * Un-assoc RXON clears the station table and WEP - * keys, so we have to restore those afterwards. - */ - iwl_clear_ucode_stations(priv, ctx); - iwl_restore_stations(priv, ctx); - ret = iwl_restore_default_wep_keys(priv, ctx); - if (ret) { - IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret); - return ret; + /* + * Un-assoc RXON clears the station table and WEP + * keys, so we have to restore those afterwards. + */ + iwl_clear_ucode_stations(priv, ctx); + iwl_restore_stations(priv, ctx); + ret = iwl_restore_default_wep_keys(priv, ctx); + if (ret) { + IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret); + return ret; + } } /* RXON timing must be before associated RXON */ @@ -235,6 +238,8 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) } memcpy(active, &ctx->staging, sizeof(*active)); + iwl_reprogram_ap_sta(priv, ctx); + /* IBSS beacon needs to be sent after setting assoc */ if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_ADHOC)) if (iwlagn_update_beacon(priv, ctx->vif)) diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 7c7f7dc..0a67b2f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -400,7 +400,8 @@ static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, u8 sta_id) } static int iwl_send_remove_station(struct iwl_priv *priv, - const u8 *addr, int sta_id) + const u8 *addr, int sta_id, + bool temporary) { struct iwl_rx_packet *pkt; int ret; @@ -436,9 +437,11 @@ static int iwl_send_remove_station(struct iwl_priv *priv, if (!ret) { switch (pkt->u.rem_sta.status) { case REM_STA_SUCCESS_MSK: - spin_lock_irqsave(&priv->sta_lock, flags_spin); - iwl_sta_ucode_deactivate(priv, sta_id); - spin_unlock_irqrestore(&priv->sta_lock, flags_spin); + if (!temporary) { + spin_lock_irqsave(&priv->sta_lock, flags_spin); + iwl_sta_ucode_deactivate(priv, sta_id); + spin_unlock_irqrestore(&priv->sta_lock, flags_spin); + } IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n"); break; default: @@ -505,7 +508,7 @@ int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id, spin_unlock_irqrestore(&priv->sta_lock, flags); - return iwl_send_remove_station(priv, addr, sta_id); + return iwl_send_remove_station(priv, addr, sta_id, false); out_err: spin_unlock_irqrestore(&priv->sta_lock, flags); return -EINVAL; @@ -624,6 +627,44 @@ void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx) } EXPORT_SYMBOL(iwl_restore_stations); +void iwl_reprogram_ap_sta(struct iwl_priv *priv, struct iwl_rxon_context *ctx) +{ + unsigned long flags; + int sta_id = ctx->ap_sta_id; + int ret; + struct iwl_addsta_cmd sta_cmd; + struct iwl_link_quality_cmd lq; + bool active; + + spin_lock_irqsave(&priv->sta_lock, flags); + if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) { + spin_unlock_irqrestore(&priv->sta_lock, flags); + return; + } + + memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(sta_cmd)); + sta_cmd.mode = 0; + memcpy(&lq, priv->stations[sta_id].lq, sizeof(lq)); + + active = priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + if (active) { + ret = iwl_send_remove_station( + priv, priv->stations[sta_id].sta.sta.addr, + sta_id, true); + if (ret) + IWL_ERR(priv, "failed to remove STA %pM (%d)\n", + priv->stations[sta_id].sta.sta.addr, ret); + } + ret = iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); + if (ret) + IWL_ERR(priv, "failed to re-add STA %pM (%d)\n", + priv->stations[sta_id].sta.sta.addr, ret); + iwl_send_lq_cmd(priv, ctx, &lq, CMD_SYNC, true); +} +EXPORT_SYMBOL(iwl_reprogram_ap_sta); + int iwl_get_free_ucode_key_index(struct iwl_priv *priv) { int i; diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h index 0647587..206f1e1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.h +++ b/drivers/net/wireless/iwlwifi/iwl-sta.h @@ -63,6 +63,7 @@ u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx, 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_reprogram_ap_sta(struct iwl_priv *priv, struct iwl_rxon_context *ctx); /** * iwl_clear_driver_stations - clear knowledge of all stations from driver -- cgit v0.10.2 From efe54db8233a4b41e68cbe67ca2e30c48532078a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 10 Nov 2010 18:25:49 -0800 Subject: iwlagn: fix PAN slot timing wrt. DTIM When the DTIM is not 1, then the slot timing is in some cases required to be calclulated based on the DTIM interval instead of the beacon interval, fix that. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c index ffb2f41..366340f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c @@ -307,6 +307,7 @@ static int iwlagn_set_pan_params(struct iwl_priv *priv) if (ctx_bss->vif && ctx_pan->vif) { int bcnint = ctx_pan->vif->bss_conf.beacon_int; + int dtim = ctx_pan->vif->bss_conf.dtim_period ?: 1; /* should be set, but seems unused?? */ cmd.flags |= cpu_to_le16(IWL_WIPAN_PARAMS_FLG_SLOTTED_MODE); @@ -329,10 +330,10 @@ static int iwlagn_set_pan_params(struct iwl_priv *priv) if (test_bit(STATUS_SCAN_HW, &priv->status) || (!ctx_bss->vif->bss_conf.idle && !ctx_bss->vif->bss_conf.assoc)) { - slot0 = bcnint * 3 - 20; + slot0 = dtim * bcnint * 3 - 20; slot1 = 20; } else if (!ctx_pan->vif->bss_conf.idle && - !ctx_pan->vif->bss_conf.assoc) { + !ctx_pan->vif->bss_conf.assoc) { slot1 = bcnint * 3 - 20; slot0 = 20; } -- cgit v0.10.2 From f4115d46599464a49a3055d33d499d97ac81fccb Mon Sep 17 00:00:00 2001 From: Shanyu Zhao Date: Wed, 10 Nov 2010 18:25:58 -0800 Subject: iwlagn: update QoS before commit associated RXON RXON command without association bit can clear the QoS info in the uCode. Therefore, before sending the associated RXON, we need to send the QoS command just in case. 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-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index 9db3924..203ee60 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -72,6 +72,34 @@ static int iwlagn_disable_pan(struct iwl_priv *priv, return ret; } +static void iwlagn_update_qos(struct iwl_priv *priv, + struct iwl_rxon_context *ctx) +{ + int ret; + + if (!ctx->is_active) + return; + + ctx->qos_data.def_qos_parm.qos_flags = 0; + + if (ctx->qos_data.qos_active) + ctx->qos_data.def_qos_parm.qos_flags |= + QOS_PARAM_FLG_UPDATE_EDCA_MSK; + + if (ctx->ht.enabled) + ctx->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK; + + IWL_DEBUG_QOS(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n", + ctx->qos_data.qos_active, + ctx->qos_data.def_qos_parm.qos_flags); + + ret = iwl_send_cmd_pdu(priv, ctx->qos_cmd, + sizeof(struct iwl_qosparam_cmd), + &ctx->qos_data.def_qos_parm); + if (ret) + IWL_ERR(priv, "Failed to update QoS\n"); +} + static int iwlagn_update_beacon(struct iwl_priv *priv, struct ieee80211_vif *vif) { @@ -208,6 +236,9 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) } if (new_assoc) { + /* QoS info may be cleared by previous un-assoc RXON */ + iwlagn_update_qos(priv, ctx); + /* * We'll run into this code path when beaconing is * enabled, but then we also need to send the beacon @@ -266,34 +297,6 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) return 0; } -static void iwlagn_update_qos(struct iwl_priv *priv, - struct iwl_rxon_context *ctx) -{ - int ret; - - if (!ctx->is_active) - return; - - ctx->qos_data.def_qos_parm.qos_flags = 0; - - if (ctx->qos_data.qos_active) - ctx->qos_data.def_qos_parm.qos_flags |= - QOS_PARAM_FLG_UPDATE_EDCA_MSK; - - if (ctx->ht.enabled) - ctx->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK; - - IWL_DEBUG_QOS(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n", - ctx->qos_data.qos_active, - ctx->qos_data.def_qos_parm.qos_flags); - - ret = iwl_send_cmd_pdu(priv, ctx->qos_cmd, - sizeof(struct iwl_qosparam_cmd), - &ctx->qos_data.def_qos_parm); - if (ret) - IWL_ERR(priv, "Failed to update QoS\n"); -} - int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) { struct iwl_priv *priv = hw->priv; -- cgit v0.10.2 From 21a5b3c6b19a8b8972ccdd55389be28a8b7c9180 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Wed, 10 Nov 2010 13:32:59 -0800 Subject: iwlagn: use SKU information in the EEPROM EEPROM contain the SKU information for the device, use it. 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 e881b08..3100a72 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -278,7 +278,6 @@ struct iwl_cfg iwl1000_bgn_cfg = { .fw_name_pre = IWL1000_FW_PRE, .ucode_api_max = IWL1000_UCODE_API_MAX, .ucode_api_min = IWL1000_UCODE_API_MIN, - .sku = IWL_SKU_G|IWL_SKU_N, .valid_tx_ant = ANT_A, .valid_rx_ant = ANT_AB, .eeprom_ver = EEPROM_1000_EEPROM_VERSION, @@ -295,7 +294,6 @@ struct iwl_cfg iwl1000_bg_cfg = { .fw_name_pre = IWL1000_FW_PRE, .ucode_api_max = IWL1000_UCODE_API_MAX, .ucode_api_min = IWL1000_UCODE_API_MIN, - .sku = IWL_SKU_G, .valid_tx_ant = ANT_A, .valid_rx_ant = ANT_AB, .eeprom_ver = EEPROM_1000_EEPROM_VERSION, @@ -311,7 +309,6 @@ struct iwl_cfg iwl100_bgn_cfg = { .fw_name_pre = IWL100_FW_PRE, .ucode_api_max = IWL100_UCODE_API_MAX, .ucode_api_min = IWL100_UCODE_API_MIN, - .sku = IWL_SKU_G|IWL_SKU_N, .valid_tx_ant = ANT_A, .valid_rx_ant = ANT_A, .eeprom_ver = EEPROM_1000_EEPROM_VERSION, @@ -328,7 +325,6 @@ struct iwl_cfg iwl100_bg_cfg = { .fw_name_pre = IWL100_FW_PRE, .ucode_api_max = IWL100_UCODE_API_MAX, .ucode_api_min = IWL100_UCODE_API_MIN, - .sku = IWL_SKU_G, .valid_tx_ant = ANT_A, .valid_rx_ant = ANT_A, .eeprom_ver = EEPROM_1000_EEPROM_VERSION, diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 2ec868d..6788ceb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2624,7 +2624,6 @@ struct iwl_cfg iwl4965_agn_cfg = { .fw_name_pre = IWL4965_FW_PRE, .ucode_api_max = IWL4965_UCODE_API_MAX, .ucode_api_min = IWL4965_UCODE_API_MIN, - .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_ABC, .eeprom_ver = EEPROM_4965_EEPROM_VERSION, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index b147580..3ee0f7c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -527,7 +527,6 @@ struct iwl_cfg iwl5300_agn_cfg = { .fw_name_pre = IWL5000_FW_PRE, .ucode_api_max = IWL5000_UCODE_API_MAX, .ucode_api_min = IWL5000_UCODE_API_MIN, - .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .valid_tx_ant = ANT_ABC, .valid_rx_ant = ANT_ABC, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, @@ -544,7 +543,6 @@ struct iwl_cfg iwl5100_bgn_cfg = { .fw_name_pre = IWL5000_FW_PRE, .ucode_api_max = IWL5000_UCODE_API_MAX, .ucode_api_min = IWL5000_UCODE_API_MIN, - .sku = IWL_SKU_G|IWL_SKU_N, .valid_tx_ant = ANT_B, .valid_rx_ant = ANT_AB, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, @@ -561,7 +559,6 @@ struct iwl_cfg iwl5100_abg_cfg = { .fw_name_pre = IWL5000_FW_PRE, .ucode_api_max = IWL5000_UCODE_API_MAX, .ucode_api_min = IWL5000_UCODE_API_MIN, - .sku = IWL_SKU_A|IWL_SKU_G, .valid_tx_ant = ANT_B, .valid_rx_ant = ANT_AB, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, @@ -577,7 +574,6 @@ struct iwl_cfg iwl5100_agn_cfg = { .fw_name_pre = IWL5000_FW_PRE, .ucode_api_max = IWL5000_UCODE_API_MAX, .ucode_api_min = IWL5000_UCODE_API_MIN, - .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .valid_tx_ant = ANT_B, .valid_rx_ant = ANT_AB, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, @@ -594,7 +590,6 @@ struct iwl_cfg iwl5350_agn_cfg = { .fw_name_pre = IWL5000_FW_PRE, .ucode_api_max = IWL5000_UCODE_API_MAX, .ucode_api_min = IWL5000_UCODE_API_MIN, - .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .valid_tx_ant = ANT_ABC, .valid_rx_ant = ANT_ABC, .eeprom_ver = EEPROM_5050_EEPROM_VERSION, @@ -611,7 +606,6 @@ struct iwl_cfg iwl5150_agn_cfg = { .fw_name_pre = IWL5150_FW_PRE, .ucode_api_max = IWL5150_UCODE_API_MAX, .ucode_api_min = IWL5150_UCODE_API_MIN, - .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .valid_tx_ant = ANT_A, .valid_rx_ant = ANT_AB, .eeprom_ver = EEPROM_5050_EEPROM_VERSION, @@ -629,7 +623,6 @@ struct iwl_cfg iwl5150_abg_cfg = { .fw_name_pre = IWL5150_FW_PRE, .ucode_api_max = IWL5150_UCODE_API_MAX, .ucode_api_min = IWL5150_UCODE_API_MIN, - .sku = IWL_SKU_A|IWL_SKU_G, .valid_tx_ant = ANT_A, .valid_rx_ant = ANT_AB, .eeprom_ver = EEPROM_5050_EEPROM_VERSION, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 9f835ac..0cc66fd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -556,7 +556,6 @@ struct iwl_cfg iwl6000g2a_2agn_cfg = { .fw_name_pre = IWL6000G2A_FW_PRE, .ucode_api_max = IWL6000G2_UCODE_API_MAX, .ucode_api_min = IWL6000G2_UCODE_API_MIN, - .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION, @@ -575,7 +574,6 @@ struct iwl_cfg iwl6000g2a_2abg_cfg = { .fw_name_pre = IWL6000G2A_FW_PRE, .ucode_api_max = IWL6000G2_UCODE_API_MAX, .ucode_api_min = IWL6000G2_UCODE_API_MIN, - .sku = IWL_SKU_A|IWL_SKU_G, .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION, @@ -593,7 +591,6 @@ struct iwl_cfg iwl6000g2a_2bg_cfg = { .fw_name_pre = IWL6000G2A_FW_PRE, .ucode_api_max = IWL6000G2_UCODE_API_MAX, .ucode_api_min = IWL6000G2_UCODE_API_MIN, - .sku = IWL_SKU_G, .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION, @@ -611,7 +608,6 @@ struct iwl_cfg iwl6000g2b_2agn_cfg = { .fw_name_pre = IWL6000G2B_FW_PRE, .ucode_api_max = IWL6000G2_UCODE_API_MAX, .ucode_api_min = IWL6000G2_UCODE_API_MIN, - .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION, @@ -633,7 +629,6 @@ struct iwl_cfg iwl6000g2b_2abg_cfg = { .fw_name_pre = IWL6000G2B_FW_PRE, .ucode_api_max = IWL6000G2_UCODE_API_MAX, .ucode_api_min = IWL6000G2_UCODE_API_MIN, - .sku = IWL_SKU_A|IWL_SKU_G, .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION, @@ -654,7 +649,6 @@ struct iwl_cfg iwl6000g2b_2bgn_cfg = { .fw_name_pre = IWL6000G2B_FW_PRE, .ucode_api_max = IWL6000G2_UCODE_API_MAX, .ucode_api_min = IWL6000G2_UCODE_API_MIN, - .sku = IWL_SKU_G|IWL_SKU_N, .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION, @@ -676,7 +670,6 @@ struct iwl_cfg iwl6000g2b_2bg_cfg = { .fw_name_pre = IWL6000G2B_FW_PRE, .ucode_api_max = IWL6000G2_UCODE_API_MAX, .ucode_api_min = IWL6000G2_UCODE_API_MIN, - .sku = IWL_SKU_G, .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION, @@ -697,7 +690,6 @@ struct iwl_cfg iwl6000g2b_bgn_cfg = { .fw_name_pre = IWL6000G2B_FW_PRE, .ucode_api_max = IWL6000G2_UCODE_API_MAX, .ucode_api_min = IWL6000G2_UCODE_API_MIN, - .sku = IWL_SKU_G|IWL_SKU_N, .valid_tx_ant = ANT_A, .valid_rx_ant = ANT_AB, .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION, @@ -719,7 +711,6 @@ struct iwl_cfg iwl6000g2b_bg_cfg = { .fw_name_pre = IWL6000G2B_FW_PRE, .ucode_api_max = IWL6000G2_UCODE_API_MAX, .ucode_api_min = IWL6000G2_UCODE_API_MIN, - .sku = IWL_SKU_G, .valid_tx_ant = ANT_A, .valid_rx_ant = ANT_AB, .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION, @@ -743,7 +734,6 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .fw_name_pre = IWL6000_FW_PRE, .ucode_api_max = IWL6000_UCODE_API_MAX, .ucode_api_min = IWL6000_UCODE_API_MIN, - .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .valid_tx_ant = ANT_BC, .valid_rx_ant = ANT_BC, .eeprom_ver = EEPROM_6000_EEPROM_VERSION, @@ -761,7 +751,6 @@ struct iwl_cfg iwl6000i_2abg_cfg = { .fw_name_pre = IWL6000_FW_PRE, .ucode_api_max = IWL6000_UCODE_API_MAX, .ucode_api_min = IWL6000_UCODE_API_MIN, - .sku = IWL_SKU_A|IWL_SKU_G, .valid_tx_ant = ANT_BC, .valid_rx_ant = ANT_BC, .eeprom_ver = EEPROM_6000_EEPROM_VERSION, @@ -778,7 +767,6 @@ struct iwl_cfg iwl6000i_2bg_cfg = { .fw_name_pre = IWL6000_FW_PRE, .ucode_api_max = IWL6000_UCODE_API_MAX, .ucode_api_min = IWL6000_UCODE_API_MIN, - .sku = IWL_SKU_G, .valid_tx_ant = ANT_BC, .valid_rx_ant = ANT_BC, .eeprom_ver = EEPROM_6000_EEPROM_VERSION, @@ -795,7 +783,6 @@ struct iwl_cfg iwl6050_2agn_cfg = { .fw_name_pre = IWL6050_FW_PRE, .ucode_api_max = IWL6050_UCODE_API_MAX, .ucode_api_min = IWL6050_UCODE_API_MIN, - .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, .ops = &iwl6050_ops, @@ -813,7 +800,6 @@ struct iwl_cfg iwl6050g2_bgn_cfg = { .fw_name_pre = IWL6050_FW_PRE, .ucode_api_max = IWL6050_UCODE_API_MAX, .ucode_api_min = IWL6050_UCODE_API_MIN, - .sku = IWL_SKU_G|IWL_SKU_N, .valid_tx_ant = ANT_A, .valid_rx_ant = ANT_AB, .eeprom_ver = EEPROM_6050G2_EEPROM_VERSION, @@ -831,7 +817,6 @@ struct iwl_cfg iwl6050_2abg_cfg = { .fw_name_pre = IWL6050_FW_PRE, .ucode_api_max = IWL6050_UCODE_API_MAX, .ucode_api_min = IWL6050_UCODE_API_MIN, - .sku = IWL_SKU_A|IWL_SKU_G, .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, .eeprom_ver = EEPROM_6050_EEPROM_VERSION, @@ -848,7 +833,6 @@ struct iwl_cfg iwl6000_3agn_cfg = { .fw_name_pre = IWL6000_FW_PRE, .ucode_api_max = IWL6000_UCODE_API_MAX, .ucode_api_min = IWL6000_UCODE_API_MIN, - .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .valid_tx_ant = ANT_ABC, .valid_rx_ant = ANT_ABC, .eeprom_ver = EEPROM_6000_EEPROM_VERSION, @@ -866,7 +850,6 @@ struct iwl_cfg iwl130_bgn_cfg = { .fw_name_pre = IWL6000G2B_FW_PRE, .ucode_api_max = IWL6000G2_UCODE_API_MAX, .ucode_api_min = IWL6000G2_UCODE_API_MIN, - .sku = IWL_SKU_G|IWL_SKU_N, .valid_tx_ant = ANT_A, .valid_rx_ant = ANT_A, .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION, @@ -887,7 +870,6 @@ struct iwl_cfg iwl130_bg_cfg = { .fw_name_pre = IWL6000G2B_FW_PRE, .ucode_api_max = IWL6000G2_UCODE_API_MAX, .ucode_api_min = IWL6000G2_UCODE_API_MIN, - .sku = IWL_SKU_G, .valid_tx_ant = ANT_A, .valid_rx_ant = ANT_A, .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c index a650bab..8a4d3ac 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c @@ -248,6 +248,27 @@ err: } +int iwl_eeprom_check_sku(struct iwl_priv *priv) +{ + u16 eeprom_sku; + + eeprom_sku = iwl_eeprom_query16(priv, EEPROM_SKU_CAP); + + priv->cfg->sku = ((eeprom_sku & EEPROM_SKU_CAP_BAND_SELECTION) >> + EEPROM_SKU_CAP_BAND_POS); + if (eeprom_sku & EEPROM_SKU_CAP_11N_ENABLE) + priv->cfg->sku |= IWL_SKU_N; + + if (!priv->cfg->sku) { + IWL_ERR(priv, "Invalid device sku\n"); + return -EINVAL; + } + + IWL_INFO(priv, "Device SKU: 0X%x\n", priv->cfg->sku); + + return 0; +} + void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac) { const u8 *addr = priv->cfg->ops->lib->eeprom_ops.query_addr(priv, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index d976912..59af06d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -4134,6 +4134,10 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (err) goto out_free_eeprom; + err = iwl_eeprom_check_sku(priv); + if (err) + goto out_free_eeprom; + /* extract MAC Address */ iwl_eeprom_get_mac(priv, priv->addresses[0].addr); IWL_DEBUG_INFO(priv, "MAC address: %pM\n", priv->addresses[0].addr); diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index d9b5906..e87be1e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -110,9 +110,18 @@ enum { }; /* SKU Capabilities */ +/* 3945 only */ #define EEPROM_SKU_CAP_SW_RF_KILL_ENABLE (1 << 0) #define EEPROM_SKU_CAP_HW_RF_KILL_ENABLE (1 << 1) +/* 5000 and up */ +#define EEPROM_SKU_CAP_BAND_POS (4) +#define EEPROM_SKU_CAP_BAND_SELECTION \ + (3 << EEPROM_SKU_CAP_BAND_POS) +#define EEPROM_SKU_CAP_11N_ENABLE (1 << 6) +#define EEPROM_SKU_CAP_AMT_ENABLE (1 << 7) +#define EEPROM_SKU_CAP_IPAN_ENABLE (1 << 8) + /* *regulatory* channel data format in eeprom, one for each channel. * There are separate entries for HT40 (40 MHz) vs. normal (20 MHz) channels. */ struct iwl_eeprom_channel { @@ -397,7 +406,7 @@ struct iwl_eeprom_calib_info { #define EEPROM_BOARD_REVISION (2*0x35) /* 2 bytes */ #define EEPROM_BOARD_PBA_NUMBER (2*0x3B+1) /* 9 bytes */ #define EEPROM_VERSION (2*0x44) /* 2 bytes */ -#define EEPROM_SKU_CAP (2*0x45) /* 1 bytes */ +#define EEPROM_SKU_CAP (2*0x45) /* 2 bytes */ #define EEPROM_OEM_MODE (2*0x46) /* 2 bytes */ #define EEPROM_WOWLAN_MODE (2*0x47) /* 2 bytes */ #define EEPROM_RADIO_CONFIG (2*0x48) /* 2 bytes */ @@ -504,6 +513,7 @@ struct iwl_eeprom_ops { 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); +int iwl_eeprom_check_sku(struct iwl_priv *priv); const u8 *iwl_eeprom_query_addr(const struct iwl_priv *priv, size_t offset); int iwlcore_eeprom_verify_signature(struct iwl_priv *priv); u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset); -- cgit v0.10.2 From 6163a3735aad19bdb8d02b3362d3a2d7d2eb78d5 Mon Sep 17 00:00:00 2001 From: Shanyu Zhao Date: Fri, 12 Nov 2010 13:48:13 -0800 Subject: iwlagn: check change before commit RXON cmd When setting rxon chain and filter, no need to commit RXON when the chain flag is not changed. This reduces the number of RXON commands we send down to uCode. Signed-off-by: Shanyu Zhao 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 59af06d..c6e455e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -97,7 +97,8 @@ void iwl_update_chain_flags(struct iwl_priv *priv) if (priv->cfg->ops->hcmd->set_rxon_chain) { for_each_context(priv, ctx) { priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx); - iwlcore_commit_rxon(priv, ctx); + if (ctx->active.rx_chain != ctx->staging.rx_chain) + iwlcore_commit_rxon(priv, ctx); } } } -- cgit v0.10.2 From 9e2e7422d059f9b98c3a0810df92a1ff660ade2f Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 12 Nov 2010 13:52:37 -0800 Subject: iwlwifi: set STATUS_READY before commit_rxon Have the STATUS_READY bit set before commit_rxon call to avoid fail to send tx power to uCode. 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 c6e455e..5b96b0d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2717,6 +2717,8 @@ static void iwl_alive_start(struct iwl_priv *priv) iwl_reset_run_time_calib(priv); + set_bit(STATUS_READY, &priv->status); + /* Configure the adapter for unassociated operation */ iwlcore_commit_rxon(priv, ctx); @@ -2726,7 +2728,6 @@ static void iwl_alive_start(struct iwl_priv *priv) iwl_leds_init(priv); IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n"); - set_bit(STATUS_READY, &priv->status); wake_up_interruptible(&priv->wait_command_queue); iwl_power_update_mode(priv, true); -- cgit v0.10.2 From cf43298864fdfd687202db8c736473522bfceb98 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Sun, 31 Oct 2010 13:40:12 +0000 Subject: libertas: don't block usb8388 suspend if no wakeup conditions are set This hunk added by commit 66fceb69b72f seems erroneous. We don't want to prevent suspend of the whole system if no wakeup params are set. In the case of the usb8388 we do want to keep the card powered up even if there are no wakeup params. This is because it will continue acting as a mesh node. If the mesh is disabled, it would indeed make more sense to power down the card during suspend, as the equivalent hunk does for the SD interface. But that's a separate task; for now just restore the previous behaviour. 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 efaf850..35931cf 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -1090,12 +1090,6 @@ static int if_usb_suspend(struct usb_interface *intf, pm_message_t message) if (priv->psstate != PS_STATE_FULL_POWER) return -1; - if (priv->wol_criteria == EHS_REMOVE_WAKEUP) { - lbs_pr_info("Suspend attempt without " - "configuring wake params!\n"); - return -ENOSYS; - } - ret = lbs_suspend(priv); if (ret) goto out; -- cgit v0.10.2 From ae63a33ec9b598b3454cf0d29077fa17b616c42a Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Sun, 31 Oct 2010 13:40:33 +0000 Subject: libertas: EHS_REMOVE_WAKEUP is not always supported Certain firmware versions, particularly the 8388 found on the XO-1, do not support the EHS_REMOVE_WAKEUP command that is used to disable WOL. Sending this command to the card will return a failure that would get propagated up the stack and cause suspend to fail. Instead, fall back to an all-zero wakeup mask. This fixes http://dev.laptop.org/ticket/9967 Signed-off-by: Deepak Saxena Signed-off-by: Daniel Drake [includes fixups by Paul Fox] Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 7074592..78c4da1 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -177,6 +177,14 @@ int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria, struct cmd_ds_host_sleep cmd_config; int ret; + /* + * Certain firmware versions do not support EHS_REMOVE_WAKEUP command + * and the card will return a failure. Since we need to be + * able to reset the mask, in those cases we set a 0 mask instead. + */ + if (criteria == EHS_REMOVE_WAKEUP && !priv->ehs_remove_supported) + criteria = 0; + cmd_config.hdr.size = cpu_to_le16(sizeof(cmd_config)); cmd_config.criteria = cpu_to_le32(criteria); cmd_config.gpio = priv->wol_gpio; diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index f062ed5..f5a9851 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -137,6 +137,7 @@ struct lbs_private { uint32_t wol_criteria; uint8_t wol_gpio; uint8_t wol_gap; + bool ehs_remove_supported; /* Transmitting */ int tx_pending_len; /* -1 while building packet */ diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index 35931cf..6524c70 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -345,6 +345,13 @@ static int if_usb_probe(struct usb_interface *intf, if (device_create_file(&priv->dev->dev, &dev_attr_lbs_flash_boot2)) lbs_pr_err("cannot register lbs_flash_boot2 attribute\n"); + /* + * EHS_REMOVE_WAKEUP is not supported on all versions of the firmware. + */ + priv->wol_criteria = EHS_REMOVE_WAKEUP; + if (lbs_host_sleep_cfg(priv, priv->wol_criteria, NULL)) + priv->ehs_remove_supported = false; + return 0; err_start_card: diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 47ce5a6..6d7af91 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -844,9 +844,10 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) priv->work_thread = create_singlethread_workqueue("lbs_worker"); INIT_WORK(&priv->mcast_work, lbs_set_mcast_worker); - priv->wol_criteria = 0xffffffff; + priv->wol_criteria = EHS_REMOVE_WAKEUP; priv->wol_gpio = 0xff; priv->wol_gap = 20; + priv->ehs_remove_supported = true; goto done; -- cgit v0.10.2 From a1fe24b0fd8bf16b4e551ae3fb785bfc574b9ffb Mon Sep 17 00:00:00 2001 From: Brian Cavagnolo Date: Fri, 12 Nov 2010 17:23:47 -0800 Subject: mwl8k: revert unnecessary modification of tx descriptor This reverts change 783391c443728febc669e40597193308460e7b4f. The stabilized AP v1 firmware uses the same tx descriptor as the STA firmware. Signed-off-by: Brian Cavagnolo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 1bbcd7c..f152a25 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1125,12 +1125,10 @@ struct mwl8k_tx_desc { __le32 reserved; __le16 rate_info; __u8 peer_id; - __u8 xmitcontrol; + __u8 tx_frag_cnt; } __packed; #define MWL8K_TX_DESCS 128 -#define MWL8K_XMITCONTROL_NON_AMPDU 0x04 - static int mwl8k_txq_init(struct ieee80211_hw *hw, int index) { @@ -1450,9 +1448,6 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) tx->peer_id = MWL8K_STA(tx_info->control.sta)->peer_id; else tx->peer_id = 0; - - if (priv->ap_fw) - tx->xmitcontrol = MWL8K_XMITCONTROL_NON_AMPDU; wmb(); tx->status = cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED | txstatus); -- cgit v0.10.2 From 41fdf0974d9eb81215cb578211a6d8f8a022a9eb Mon Sep 17 00:00:00 2001 From: Nishant Sarmukadam Date: Fri, 12 Nov 2010 17:23:48 -0800 Subject: mwl8k: rf_tx_power cmd not supported by AP firmware APIv1 APIv1 AP firmware does not support the RF_TX_POWER command. It supports the similar TX_POWER command. Signed-off-by: Pradeep Nemavat Signed-off-by: Nishant Sarmukadam Signed-off-by: Brian Cavagnolo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index f152a25..cfda87a 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -285,8 +285,9 @@ static const struct ieee80211_rate mwl8k_rates_50[] = { }; /* Set or get info from Firmware */ -#define MWL8K_CMD_SET 0x0001 #define MWL8K_CMD_GET 0x0000 +#define MWL8K_CMD_SET 0x0001 +#define MWL8K_CMD_SET_LIST 0x0002 /* Firmware command codes */ #define MWL8K_CMD_CODE_DNLD 0x0001 @@ -296,6 +297,7 @@ static const struct ieee80211_rate mwl8k_rates_50[] = { #define MWL8K_CMD_GET_STAT 0x0014 #define MWL8K_CMD_RADIO_CONTROL 0x001c #define MWL8K_CMD_RF_TX_POWER 0x001e +#define MWL8K_CMD_TX_POWER 0x001f #define MWL8K_CMD_RF_ANTENNA 0x0020 #define MWL8K_CMD_SET_BEACON 0x0100 /* per-vif */ #define MWL8K_CMD_SET_PRE_SCAN 0x0107 @@ -333,6 +335,7 @@ static const char *mwl8k_cmd_name(__le16 cmd, char *buf, int bufsize) MWL8K_CMDNAME(GET_STAT); MWL8K_CMDNAME(RADIO_CONTROL); MWL8K_CMDNAME(RF_TX_POWER); + MWL8K_CMDNAME(TX_POWER); MWL8K_CMDNAME(RF_ANTENNA); MWL8K_CMDNAME(SET_BEACON); MWL8K_CMDNAME(SET_PRE_SCAN); @@ -2084,7 +2087,7 @@ mwl8k_set_radio_preamble(struct ieee80211_hw *hw, bool short_preamble) /* * CMD_RF_TX_POWER. */ -#define MWL8K_TX_POWER_LEVEL_TOTAL 8 +#define MWL8K_RF_TX_POWER_LEVEL_TOTAL 8 struct mwl8k_cmd_rf_tx_power { struct mwl8k_cmd_pkt header; @@ -2092,7 +2095,7 @@ struct mwl8k_cmd_rf_tx_power { __le16 support_level; __le16 current_level; __le16 reserved; - __le16 power_level_list[MWL8K_TX_POWER_LEVEL_TOTAL]; + __le16 power_level_list[MWL8K_RF_TX_POWER_LEVEL_TOTAL]; } __packed; static int mwl8k_cmd_rf_tx_power(struct ieee80211_hw *hw, int dBm) @@ -2116,6 +2119,65 @@ static int mwl8k_cmd_rf_tx_power(struct ieee80211_hw *hw, int dBm) } /* + * CMD_TX_POWER. + */ +#define MWL8K_TX_POWER_LEVEL_TOTAL 12 + +struct mwl8k_cmd_tx_power { + struct mwl8k_cmd_pkt header; + __le16 action; + __le16 band; + __le16 channel; + __le16 bw; + __le16 sub_ch; + __le16 power_level_list[MWL8K_TX_POWER_LEVEL_TOTAL]; +} __attribute__((packed)); + +static int mwl8k_cmd_tx_power(struct ieee80211_hw *hw, + struct ieee80211_conf *conf, + unsigned short pwr) +{ + struct ieee80211_channel *channel = conf->channel; + struct mwl8k_cmd_tx_power *cmd; + int rc; + int i; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (cmd == NULL) + return -ENOMEM; + + cmd->header.code = cpu_to_le16(MWL8K_CMD_TX_POWER); + cmd->header.length = cpu_to_le16(sizeof(*cmd)); + cmd->action = cpu_to_le16(MWL8K_CMD_SET_LIST); + + if (channel->band == IEEE80211_BAND_2GHZ) + cmd->band = cpu_to_le16(0x1); + else if (channel->band == IEEE80211_BAND_5GHZ) + cmd->band = cpu_to_le16(0x4); + + cmd->channel = channel->hw_value; + + if (conf->channel_type == NL80211_CHAN_NO_HT || + conf->channel_type == NL80211_CHAN_HT20) { + cmd->bw = cpu_to_le16(0x2); + } else { + cmd->bw = cpu_to_le16(0x4); + if (conf->channel_type == NL80211_CHAN_HT40MINUS) + cmd->sub_ch = cpu_to_le16(0x3); + else if (conf->channel_type == NL80211_CHAN_HT40PLUS) + cmd->sub_ch = cpu_to_le16(0x1); + } + + for (i = 0; i < MWL8K_TX_POWER_LEVEL_TOTAL; i++) + cmd->power_level_list[i] = cpu_to_le16(pwr); + + rc = mwl8k_post_cmd(hw, &cmd->header); + kfree(cmd); + + return rc; +} + +/* * CMD_RF_ANTENNA. */ struct mwl8k_cmd_rf_antenna { @@ -3377,15 +3439,19 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed) if (conf->power_level > 18) conf->power_level = 18; - rc = mwl8k_cmd_rf_tx_power(hw, conf->power_level); - if (rc) - goto out; if (priv->ap_fw) { + rc = mwl8k_cmd_tx_power(hw, conf, conf->power_level); + if (rc) + goto out; + rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_RX, 0x7); if (!rc) rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_TX, 0x7); } else { + rc = mwl8k_cmd_rf_tx_power(hw, conf->power_level); + if (rc) + goto out; rc = mwl8k_cmd_mimo_config(hw, 0x7, 0x7); } -- cgit v0.10.2 From 3cc7772c0a3cc193fa9873816168bd34d4f16837 Mon Sep 17 00:00:00 2001 From: Brian Cavagnolo Date: Fri, 12 Nov 2010 17:23:49 -0800 Subject: mwl8k: factor out firmware loading and hw init code This is in preparation for supporting different fw images for different interface types, and for supporting asynchronous firmware loading. Based on a patch from Pradeep Nemavat and Yogesh Powar Signed-off-by: Brian Cavagnolo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index cfda87a..7bd8615 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -3942,73 +3942,10 @@ static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = { }; MODULE_DEVICE_TABLE(pci, mwl8k_pci_id_table); -static int __devinit mwl8k_probe(struct pci_dev *pdev, - const struct pci_device_id *id) +static int mwl8k_init_firmware(struct ieee80211_hw *hw) { - static int printed_version = 0; - struct ieee80211_hw *hw; - struct mwl8k_priv *priv; + struct mwl8k_priv *priv = hw->priv; int rc; - int i; - - if (!printed_version) { - printk(KERN_INFO "%s version %s\n", MWL8K_DESC, MWL8K_VERSION); - printed_version = 1; - } - - - rc = pci_enable_device(pdev); - if (rc) { - printk(KERN_ERR "%s: Cannot enable new PCI device\n", - MWL8K_NAME); - return rc; - } - - rc = pci_request_regions(pdev, MWL8K_NAME); - if (rc) { - printk(KERN_ERR "%s: Cannot obtain PCI resources\n", - MWL8K_NAME); - goto err_disable_device; - } - - pci_set_master(pdev); - - - hw = ieee80211_alloc_hw(sizeof(*priv), &mwl8k_ops); - if (hw == NULL) { - printk(KERN_ERR "%s: ieee80211 alloc failed\n", MWL8K_NAME); - rc = -ENOMEM; - goto err_free_reg; - } - - SET_IEEE80211_DEV(hw, &pdev->dev); - pci_set_drvdata(pdev, hw); - - priv = hw->priv; - priv->hw = hw; - priv->pdev = pdev; - priv->device_info = &mwl8k_info_tbl[id->driver_data]; - - - priv->sram = pci_iomap(pdev, 0, 0x10000); - if (priv->sram == NULL) { - wiphy_err(hw->wiphy, "Cannot map device SRAM\n"); - goto err_iounmap; - } - - /* - * If BAR0 is a 32 bit BAR, the register BAR will be BAR1. - * If BAR0 is a 64 bit BAR, the register BAR will be BAR2. - */ - priv->regs = pci_iomap(pdev, 1, 0x10000); - if (priv->regs == NULL) { - priv->regs = pci_iomap(pdev, 2, 0x10000); - if (priv->regs == NULL) { - wiphy_err(hw->wiphy, "Cannot map device registers\n"); - goto err_iounmap; - } - } - /* Reset firmware and hardware */ mwl8k_hw_reset(priv); @@ -4017,19 +3954,26 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, rc = mwl8k_request_firmware(priv); if (rc) { wiphy_err(hw->wiphy, "Firmware files not found\n"); - goto err_stop_firmware; + return rc; } /* Load firmware into hardware */ rc = mwl8k_load_firmware(hw); - if (rc) { + if (rc) wiphy_err(hw->wiphy, "Cannot start firmware\n"); - goto err_stop_firmware; - } /* Reclaim memory once firmware is successfully loaded */ mwl8k_release_firmware(priv); + return rc; +} + +/* initialize hw after successfully loading a firmware image */ +static int mwl8k_probe_hw(struct ieee80211_hw *hw) +{ + struct mwl8k_priv *priv = hw->priv; + int rc = 0; + int i; if (priv->ap_fw) { priv->rxd_ops = priv->device_info->ap_rxd_ops; @@ -4046,58 +3990,11 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, priv->wmm_enabled = false; priv->pending_tx_pkts = 0; - - /* - * Extra headroom is the size of the required DMA header - * minus the size of the smallest 802.11 frame (CTS frame). - */ - hw->extra_tx_headroom = - sizeof(struct mwl8k_dma_data) - sizeof(struct ieee80211_cts); - - hw->channel_change_time = 10; - - hw->queues = MWL8K_TX_QUEUES; - - /* Set rssi values to dBm */ - hw->flags |= IEEE80211_HW_SIGNAL_DBM; - hw->vif_data_size = sizeof(struct mwl8k_vif); - hw->sta_data_size = sizeof(struct mwl8k_sta); - - priv->macids_used = 0; - INIT_LIST_HEAD(&priv->vif_list); - - /* Set default radio state and preamble */ - priv->radio_on = 0; - priv->radio_short_preamble = 0; - - /* Finalize join worker */ - INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker); - - /* TX reclaim and RX tasklets. */ - tasklet_init(&priv->poll_tx_task, mwl8k_tx_poll, (unsigned long)hw); - tasklet_disable(&priv->poll_tx_task); - tasklet_init(&priv->poll_rx_task, mwl8k_rx_poll, (unsigned long)hw); - tasklet_disable(&priv->poll_rx_task); - - /* Power management cookie */ - priv->cookie = pci_alloc_consistent(priv->pdev, 4, &priv->cookie_dma); - if (priv->cookie == NULL) - goto err_stop_firmware; - rc = mwl8k_rxq_init(hw, 0); if (rc) - goto err_free_cookie; + goto err_stop_firmware; rxq_refill(hw, 0, INT_MAX); - mutex_init(&priv->fw_mutex); - priv->fw_mutex_owner = NULL; - priv->fw_mutex_depth = 0; - priv->hostcmd_wait = NULL; - - spin_lock_init(&priv->tx_lock); - - priv->tx_wait = NULL; - for (i = 0; i < MWL8K_TX_QUEUES; i++) { rc = mwl8k_txq_init(hw, i); if (rc) @@ -4137,13 +4034,6 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, goto err_free_irq; } - hw->wiphy->interface_modes = 0; - if (priv->ap_macids_supported) - hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP); - if (priv->sta_macids_supported) - hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_STATION); - - /* Turn radio off */ rc = mwl8k_cmd_radio_disable(hw); if (rc) { @@ -4162,12 +4052,6 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); free_irq(priv->pdev->irq, hw); - rc = ieee80211_register_hw(hw); - if (rc) { - wiphy_err(hw->wiphy, "Cannot register device\n"); - goto err_free_queues; - } - wiphy_info(hw->wiphy, "%s v%d, %pm, %s firmware %u.%u.%u.%u\n", priv->device_info->part_name, priv->hw_rev, hw->wiphy->perm_addr, @@ -4186,14 +4070,213 @@ err_free_queues: mwl8k_txq_deinit(hw, i); mwl8k_rxq_deinit(hw, 0); +err_stop_firmware: + mwl8k_hw_reset(priv); + + return rc; +} + +/* + * invoke mwl8k_reload_firmware to change the firmware image after the device + * has already been registered + */ +static int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image) +{ + int i, rc = 0; + struct mwl8k_priv *priv = hw->priv; + + mwl8k_stop(hw); + mwl8k_rxq_deinit(hw, 0); + + for (i = 0; i < MWL8K_TX_QUEUES; i++) + mwl8k_txq_deinit(hw, i); + + rc = mwl8k_init_firmware(hw, fw_image); + if (rc) + goto fail; + + rc = mwl8k_probe_hw(hw); + if (rc) + goto fail; + + rc = mwl8k_start(hw); + if (rc) + goto fail; + + rc = mwl8k_config(hw, ~0); + if (rc) + goto fail; + + for (i = 0; i < MWL8K_TX_QUEUES; i++) { + rc = mwl8k_conf_tx(hw, i, &priv->wmm_params[i]); + if (rc) + goto fail; + } + + return rc; + +fail: + printk(KERN_WARNING "mwl8k: Failed to reload firmware image.\n"); + return rc; +} + +static int mwl8k_firmware_load_success(struct mwl8k_priv *priv) +{ + struct ieee80211_hw *hw = priv->hw; + int i, rc; + + /* + * Extra headroom is the size of the required DMA header + * minus the size of the smallest 802.11 frame (CTS frame). + */ + hw->extra_tx_headroom = + sizeof(struct mwl8k_dma_data) - sizeof(struct ieee80211_cts); + + hw->channel_change_time = 10; + + hw->queues = MWL8K_TX_QUEUES; + + /* Set rssi values to dBm */ + hw->flags |= IEEE80211_HW_SIGNAL_DBM; + hw->vif_data_size = sizeof(struct mwl8k_vif); + hw->sta_data_size = sizeof(struct mwl8k_sta); + + priv->macids_used = 0; + INIT_LIST_HEAD(&priv->vif_list); + + /* Set default radio state and preamble */ + priv->radio_on = 0; + priv->radio_short_preamble = 0; + + /* Finalize join worker */ + INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker); + + /* TX reclaim and RX tasklets. */ + tasklet_init(&priv->poll_tx_task, mwl8k_tx_poll, (unsigned long)hw); + tasklet_disable(&priv->poll_tx_task); + tasklet_init(&priv->poll_rx_task, mwl8k_rx_poll, (unsigned long)hw); + tasklet_disable(&priv->poll_rx_task); + + /* Power management cookie */ + priv->cookie = pci_alloc_consistent(priv->pdev, 4, &priv->cookie_dma); + if (priv->cookie == NULL) + return -ENOMEM; + + mutex_init(&priv->fw_mutex); + priv->fw_mutex_owner = NULL; + priv->fw_mutex_depth = 0; + priv->hostcmd_wait = NULL; + + spin_lock_init(&priv->tx_lock); + + priv->tx_wait = NULL; + + rc = mwl8k_probe_hw(hw); + if (rc) + goto err_free_cookie; + + hw->wiphy->interface_modes = 0; + if (priv->ap_macids_supported || priv->device_info->fw_image_ap) + hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP); + if (priv->sta_macids_supported || priv->device_info->fw_image_sta) + hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_STATION); + + rc = ieee80211_register_hw(hw); + if (rc) { + wiphy_err(hw->wiphy, "Cannot register device\n"); + goto err_unprobe_hw; + } + + return 0; + +err_unprobe_hw: + for (i = 0; i < MWL8K_TX_QUEUES; i++) + mwl8k_txq_deinit(hw, i); + mwl8k_rxq_deinit(hw, 0); + err_free_cookie: if (priv->cookie != NULL) pci_free_consistent(priv->pdev, 4, priv->cookie, priv->cookie_dma); + return rc; +} +static int __devinit mwl8k_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + static int printed_version; + struct ieee80211_hw *hw; + struct mwl8k_priv *priv; + int rc; + + if (!printed_version) { + printk(KERN_INFO "%s version %s\n", MWL8K_DESC, MWL8K_VERSION); + printed_version = 1; + } + + + rc = pci_enable_device(pdev); + if (rc) { + printk(KERN_ERR "%s: Cannot enable new PCI device\n", + MWL8K_NAME); + return rc; + } + + rc = pci_request_regions(pdev, MWL8K_NAME); + if (rc) { + printk(KERN_ERR "%s: Cannot obtain PCI resources\n", + MWL8K_NAME); + goto err_disable_device; + } + + pci_set_master(pdev); + + + hw = ieee80211_alloc_hw(sizeof(*priv), &mwl8k_ops); + if (hw == NULL) { + printk(KERN_ERR "%s: ieee80211 alloc failed\n", MWL8K_NAME); + rc = -ENOMEM; + goto err_free_reg; + } + + SET_IEEE80211_DEV(hw, &pdev->dev); + pci_set_drvdata(pdev, hw); + + priv = hw->priv; + priv->hw = hw; + priv->pdev = pdev; + priv->device_info = &mwl8k_info_tbl[id->driver_data]; + + + priv->sram = pci_iomap(pdev, 0, 0x10000); + if (priv->sram == NULL) { + wiphy_err(hw->wiphy, "Cannot map device SRAM\n"); + goto err_iounmap; + } + + /* + * If BAR0 is a 32 bit BAR, the register BAR will be BAR1. + * If BAR0 is a 64 bit BAR, the register BAR will be BAR2. + */ + priv->regs = pci_iomap(pdev, 1, 0x10000); + if (priv->regs == NULL) { + priv->regs = pci_iomap(pdev, 2, 0x10000); + if (priv->regs == NULL) { + wiphy_err(hw->wiphy, "Cannot map device registers\n"); + goto err_iounmap; + } + } + + rc = mwl8k_init_firmware(hw); + if (rc) + goto err_stop_firmware; + + rc = mwl8k_firmware_load_success(priv); + if (!rc) + return rc; + err_stop_firmware: mwl8k_hw_reset(priv); - mwl8k_release_firmware(priv); err_iounmap: if (priv->regs != NULL) -- cgit v0.10.2 From 0863ade8d6bde1d151f75720d999ff27f9fe3533 Mon Sep 17 00:00:00 2001 From: Brian Cavagnolo Date: Fri, 12 Nov 2010 17:23:50 -0800 Subject: mwl8k: choose proper firmware image as directed by user The mwl8k can operate in AP or STA mode, depending on the firmware image that is loaded. By default, STA firmware is loaded. Allow the user to override this default mode at module load time. This saves an unnecessary firmware reload for users only interested in AP mode. Also, the firmware image can be swapped to meet the user's add_interface request. For example, suppose the STA firmware is loaded, no STA interface has been added, and the user adds an AP interface. In this case, the AP firmware will be loaded to meet the request. Based on contributions from Pradeep Nemavat , Yogesh Powar , and Lennert Buytenhek . Signed-off-by: Brian Cavagnolo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 7bd8615..cbf7271 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -29,6 +29,12 @@ #define MWL8K_NAME KBUILD_MODNAME #define MWL8K_VERSION "0.12" +/* Module parameters */ +static unsigned ap_mode_default; +module_param(ap_mode_default, bool, 0); +MODULE_PARM_DESC(ap_mode_default, + "Set to 1 to make ap mode the default instead of sta mode"); + /* Register definitions */ #define MWL8K_HIU_GEN_PTR 0x00000c10 #define MWL8K_MODE_STA 0x0000005a @@ -92,7 +98,8 @@ struct rxd_ops { struct mwl8k_device_info { char *part_name; char *helper_image; - char *fw_image; + char *fw_image_sta; + char *fw_image_ap; struct rxd_ops *ap_rxd_ops; }; @@ -210,6 +217,12 @@ struct mwl8k_priv { /* Most recently reported noise in dBm */ s8 noise; + + /* + * preserve the queue configurations so they can be restored if/when + * the firmware image is swapped. + */ + struct ieee80211_tx_queue_params wmm_params[MWL8K_TX_QUEUES]; }; /* Per interface specific private data */ @@ -401,7 +414,7 @@ static int mwl8k_request_fw(struct mwl8k_priv *priv, fname, &priv->pdev->dev); } -static int mwl8k_request_firmware(struct mwl8k_priv *priv) +static int mwl8k_request_firmware(struct mwl8k_priv *priv, char *fw_image) { struct mwl8k_device_info *di = priv->device_info; int rc; @@ -416,10 +429,10 @@ static int mwl8k_request_firmware(struct mwl8k_priv *priv) } } - rc = mwl8k_request_fw(priv, di->fw_image, &priv->fw_ucode); + rc = mwl8k_request_fw(priv, fw_image, &priv->fw_ucode); if (rc) { printk(KERN_ERR "%s: Error requesting firmware file %s\n", - pci_name(priv->pdev), di->fw_image); + pci_name(priv->pdev), fw_image); mwl8k_release_fw(&priv->fw_helper); return rc; } @@ -3345,13 +3358,16 @@ static void mwl8k_stop(struct ieee80211_hw *hw) mwl8k_txq_reclaim(hw, i, INT_MAX, 1); } +static int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image); + static int mwl8k_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mwl8k_priv *priv = hw->priv; struct mwl8k_vif *mwl8k_vif; u32 macids_supported; - int macid; + int macid, rc; + struct mwl8k_device_info *di; /* * Reject interface creation if sniffer mode is active, as @@ -3364,12 +3380,28 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, return -EINVAL; } - + di = priv->device_info; switch (vif->type) { case NL80211_IFTYPE_AP: + if (!priv->ap_fw && di->fw_image_ap) { + /* we must load the ap fw to meet this request */ + if (!list_empty(&priv->vif_list)) + return -EBUSY; + rc = mwl8k_reload_firmware(hw, di->fw_image_ap); + if (rc) + return rc; + } macids_supported = priv->ap_macids_supported; break; case NL80211_IFTYPE_STATION: + if (priv->ap_fw && di->fw_image_sta) { + /* we must load the sta fw to meet this request */ + if (!list_empty(&priv->vif_list)) + return -EBUSY; + rc = mwl8k_reload_firmware(hw, di->fw_image_sta); + if (rc) + return rc; + } macids_supported = priv->sta_macids_supported; break; default: @@ -3805,6 +3837,9 @@ static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue, rc = mwl8k_fw_lock(hw); if (!rc) { + BUG_ON(queue > MWL8K_TX_QUEUES - 1); + memcpy(&priv->wmm_params[queue], params, sizeof(*params)); + if (!priv->wmm_enabled) rc = mwl8k_cmd_set_wmm_mode(hw, 1); @@ -3908,17 +3943,18 @@ static struct mwl8k_device_info mwl8k_info_tbl[] __devinitdata = { [MWL8363] = { .part_name = "88w8363", .helper_image = "mwl8k/helper_8363.fw", - .fw_image = "mwl8k/fmimage_8363.fw", + .fw_image_sta = "mwl8k/fmimage_8363.fw", }, [MWL8687] = { .part_name = "88w8687", .helper_image = "mwl8k/helper_8687.fw", - .fw_image = "mwl8k/fmimage_8687.fw", + .fw_image_sta = "mwl8k/fmimage_8687.fw", }, [MWL8366] = { .part_name = "88w8366", .helper_image = "mwl8k/helper_8366.fw", - .fw_image = "mwl8k/fmimage_8366.fw", + .fw_image_sta = "mwl8k/fmimage_8366.fw", + .fw_image_ap = "mwl8k/fmimage_8366_ap-1.fw", .ap_rxd_ops = &rxd_8366_ap_ops, }, }; @@ -3929,6 +3965,7 @@ MODULE_FIRMWARE("mwl8k/helper_8687.fw"); MODULE_FIRMWARE("mwl8k/fmimage_8687.fw"); MODULE_FIRMWARE("mwl8k/helper_8366.fw"); MODULE_FIRMWARE("mwl8k/fmimage_8366.fw"); +MODULE_FIRMWARE("mwl8k/fmimage_8366_ap-1.fw"); static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = { { PCI_VDEVICE(MARVELL, 0x2a0a), .driver_data = MWL8363, }, @@ -3942,7 +3979,7 @@ static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = { }; MODULE_DEVICE_TABLE(pci, mwl8k_pci_id_table); -static int mwl8k_init_firmware(struct ieee80211_hw *hw) +static int mwl8k_init_firmware(struct ieee80211_hw *hw, char *fw_image) { struct mwl8k_priv *priv = hw->priv; int rc; @@ -3951,7 +3988,7 @@ static int mwl8k_init_firmware(struct ieee80211_hw *hw) mwl8k_hw_reset(priv); /* Ask userland hotplug daemon for the device firmware */ - rc = mwl8k_request_firmware(priv); + rc = mwl8k_request_firmware(priv, fw_image); if (rc) { wiphy_err(hw->wiphy, "Firmware files not found\n"); return rc; @@ -4207,6 +4244,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, static int printed_version; struct ieee80211_hw *hw; struct mwl8k_priv *priv; + struct mwl8k_device_info *di; int rc; if (!printed_version) { @@ -4267,7 +4305,23 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, } } - rc = mwl8k_init_firmware(hw); + /* + * Choose the initial fw image depending on user input and availability + * of images. + */ + di = priv->device_info; + if (ap_mode_default && di->fw_image_ap) + rc = mwl8k_init_firmware(hw, di->fw_image_ap); + else if (!ap_mode_default && di->fw_image_sta) + rc = mwl8k_init_firmware(hw, di->fw_image_sta); + else if (ap_mode_default && !di->fw_image_ap && di->fw_image_sta) { + printk(KERN_WARNING "AP fw is unavailable. Using STA fw."); + rc = mwl8k_init_firmware(hw, di->fw_image_sta); + } else if (!ap_mode_default && !di->fw_image_sta && di->fw_image_ap) { + printk(KERN_WARNING "STA fw is unavailable. Using AP fw."); + rc = mwl8k_init_firmware(hw, di->fw_image_ap); + } else + rc = mwl8k_init_firmware(hw, di->fw_image_sta); if (rc) goto err_stop_firmware; -- cgit v0.10.2 From 952a0e963fb02e50f4afbf502f7d468a8fe2b0fa Mon Sep 17 00:00:00 2001 From: Brian Cavagnolo Date: Fri, 12 Nov 2010 17:23:51 -0800 Subject: mwl8k: add API version checking for AP firmware The AP firmware specifies an API version in the GET_HW_SPEC command response. Currently, the driver only supports AP firmware for the 8366, and only supports API v1. In the future, if higher API version firmwares emerge (possibly for different chips), different ops can be selected based on the reported API version. Signed-off-by: Brian Cavagnolo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index cbf7271..e5b062c 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -101,6 +101,7 @@ struct mwl8k_device_info { char *fw_image_sta; char *fw_image_ap; struct rxd_ops *ap_rxd_ops; + u32 fw_api_ap; }; struct mwl8k_rx_queue { @@ -1827,6 +1828,7 @@ struct mwl8k_cmd_get_hw_spec_ap { __le32 wcbbase1; __le32 wcbbase2; __le32 wcbbase3; + __le32 fw_api_version; } __packed; static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw) @@ -1834,6 +1836,7 @@ static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw) struct mwl8k_priv *priv = hw->priv; struct mwl8k_cmd_get_hw_spec_ap *cmd; int rc; + u32 api_version; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (cmd == NULL) @@ -1850,6 +1853,16 @@ static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw) if (!rc) { int off; + api_version = le32_to_cpu(cmd->fw_api_version); + if (priv->device_info->fw_api_ap != api_version) { + printk(KERN_ERR "%s: Unsupported fw API version for %s." + " Expected %d got %d.\n", MWL8K_NAME, + priv->device_info->part_name, + priv->device_info->fw_api_ap, + api_version); + rc = -EINVAL; + goto done; + } SET_IEEE80211_PERM_ADDR(hw, cmd->perm_addr); priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs); priv->fw_rev = le32_to_cpu(cmd->fw_rev); @@ -1877,6 +1890,7 @@ static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw) iowrite32(priv->txq[3].txd_dma, priv->sram + off); } +done: kfree(cmd); return rc; } @@ -3939,6 +3953,10 @@ enum { MWL8366, }; +#define MWL8K_8366_AP_FW_API 1 +#define _MWL8K_8366_AP_FW(api) "mwl8k/fmimage_8366_ap-" #api ".fw" +#define MWL8K_8366_AP_FW(api) _MWL8K_8366_AP_FW(api) + static struct mwl8k_device_info mwl8k_info_tbl[] __devinitdata = { [MWL8363] = { .part_name = "88w8363", @@ -3954,7 +3972,8 @@ static struct mwl8k_device_info mwl8k_info_tbl[] __devinitdata = { .part_name = "88w8366", .helper_image = "mwl8k/helper_8366.fw", .fw_image_sta = "mwl8k/fmimage_8366.fw", - .fw_image_ap = "mwl8k/fmimage_8366_ap-1.fw", + .fw_image_ap = MWL8K_8366_AP_FW(MWL8K_8366_AP_FW_API), + .fw_api_ap = MWL8K_8366_AP_FW_API, .ap_rxd_ops = &rxd_8366_ap_ops, }, }; @@ -3965,7 +3984,7 @@ MODULE_FIRMWARE("mwl8k/helper_8687.fw"); MODULE_FIRMWARE("mwl8k/fmimage_8687.fw"); MODULE_FIRMWARE("mwl8k/helper_8366.fw"); MODULE_FIRMWARE("mwl8k/fmimage_8366.fw"); -MODULE_FIRMWARE("mwl8k/fmimage_8366_ap-1.fw"); +MODULE_FIRMWARE(MWL8K_8366_AP_FW(MWL8K_8366_AP_FW_API)); static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = { { PCI_VDEVICE(MARVELL, 0x2a0a), .driver_data = MWL8363, }, -- cgit v0.10.2 From 99020471001dbbd6edf61f105368cb6667cc683d Mon Sep 17 00:00:00 2001 From: Brian Cavagnolo Date: Fri, 12 Nov 2010 17:23:52 -0800 Subject: mwl8k: make initial firmware load asynchronous Introduce a firmware loading state machine to manage the process of loading firmware asynchronously and completing initialization upon success. The state machine attempts to load the preferred firmware image. If that fails, and if an alternative firmware image is available, it will attempt to load that one. Signed-off-by: Brian Cavagnolo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index e5b062c..081bb6c 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -224,6 +224,12 @@ struct mwl8k_priv { * the firmware image is swapped. */ struct ieee80211_tx_queue_params wmm_params[MWL8K_TX_QUEUES]; + + /* async firmware loading state */ + unsigned fw_state; + char *fw_pref; + char *fw_alt; + struct completion firmware_loading_complete; }; /* Per interface specific private data */ @@ -403,34 +409,66 @@ static void mwl8k_release_firmware(struct mwl8k_priv *priv) mwl8k_release_fw(&priv->fw_helper); } +/* states for asynchronous f/w loading */ +static void mwl8k_fw_state_machine(const struct firmware *fw, void *context); +enum { + FW_STATE_INIT = 0, + FW_STATE_LOADING_PREF, + FW_STATE_LOADING_ALT, + FW_STATE_ERROR, +}; + /* Request fw image */ static int mwl8k_request_fw(struct mwl8k_priv *priv, - const char *fname, struct firmware **fw) + const char *fname, struct firmware **fw, + bool nowait) { /* release current image */ if (*fw != NULL) mwl8k_release_fw(fw); - return request_firmware((const struct firmware **)fw, - fname, &priv->pdev->dev); + if (nowait) + return request_firmware_nowait(THIS_MODULE, 1, fname, + &priv->pdev->dev, GFP_KERNEL, + priv, mwl8k_fw_state_machine); + else + return request_firmware((const struct firmware **)fw, + fname, &priv->pdev->dev); } -static int mwl8k_request_firmware(struct mwl8k_priv *priv, char *fw_image) +static int mwl8k_request_firmware(struct mwl8k_priv *priv, char *fw_image, + bool nowait) { struct mwl8k_device_info *di = priv->device_info; int rc; if (di->helper_image != NULL) { - rc = mwl8k_request_fw(priv, di->helper_image, &priv->fw_helper); - if (rc) { - printk(KERN_ERR "%s: Error requesting helper " - "firmware file %s\n", pci_name(priv->pdev), - di->helper_image); + if (nowait) + rc = mwl8k_request_fw(priv, di->helper_image, + &priv->fw_helper, true); + else + rc = mwl8k_request_fw(priv, di->helper_image, + &priv->fw_helper, false); + if (rc) + printk(KERN_ERR "%s: Error requesting helper fw %s\n", + pci_name(priv->pdev), di->helper_image); + + if (rc || nowait) return rc; - } } - rc = mwl8k_request_fw(priv, fw_image, &priv->fw_ucode); + if (nowait) { + /* + * if we get here, no helper image is needed. Skip the + * FW_STATE_INIT state. + */ + priv->fw_state = FW_STATE_LOADING_PREF; + rc = mwl8k_request_fw(priv, fw_image, + &priv->fw_ucode, + true); + } else + rc = mwl8k_request_fw(priv, fw_image, + &priv->fw_ucode, false); if (rc) { printk(KERN_ERR "%s: Error requesting firmware file %s\n", pci_name(priv->pdev), fw_image); @@ -3998,7 +4036,99 @@ static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = { }; MODULE_DEVICE_TABLE(pci, mwl8k_pci_id_table); -static int mwl8k_init_firmware(struct ieee80211_hw *hw, char *fw_image) +static int mwl8k_request_alt_fw(struct mwl8k_priv *priv) +{ + int rc; + printk(KERN_ERR "%s: Error requesting preferred fw %s.\n" + "Trying alternative firmware %s\n", pci_name(priv->pdev), + priv->fw_pref, priv->fw_alt); + rc = mwl8k_request_fw(priv, priv->fw_alt, &priv->fw_ucode, true); + if (rc) { + printk(KERN_ERR "%s: Error requesting alt fw %s\n", + pci_name(priv->pdev), priv->fw_alt); + return rc; + } + return 0; +} + +static int mwl8k_firmware_load_success(struct mwl8k_priv *priv); +static void mwl8k_fw_state_machine(const struct firmware *fw, void *context) +{ + struct mwl8k_priv *priv = context; + struct mwl8k_device_info *di = priv->device_info; + int rc; + + switch (priv->fw_state) { + case FW_STATE_INIT: + if (!fw) { + printk(KERN_ERR "%s: Error requesting helper fw %s\n", + pci_name(priv->pdev), di->helper_image); + goto fail; + } + priv->fw_helper = fw; + rc = mwl8k_request_fw(priv, priv->fw_pref, &priv->fw_ucode, + true); + if (rc && priv->fw_alt) { + rc = mwl8k_request_alt_fw(priv); + if (rc) + goto fail; + priv->fw_state = FW_STATE_LOADING_ALT; + } else if (rc) + goto fail; + else + priv->fw_state = FW_STATE_LOADING_PREF; + break; + + case FW_STATE_LOADING_PREF: + if (!fw) { + if (priv->fw_alt) { + rc = mwl8k_request_alt_fw(priv); + if (rc) + goto fail; + priv->fw_state = FW_STATE_LOADING_ALT; + } else + goto fail; + } else { + priv->fw_ucode = fw; + rc = mwl8k_firmware_load_success(priv); + if (rc) + goto fail; + else + complete(&priv->firmware_loading_complete); + } + break; + + case FW_STATE_LOADING_ALT: + if (!fw) { + printk(KERN_ERR "%s: Error requesting alt fw %s\n", + pci_name(priv->pdev), di->helper_image); + goto fail; + } + priv->fw_ucode = fw; + rc = mwl8k_firmware_load_success(priv); + if (rc) + goto fail; + else + complete(&priv->firmware_loading_complete); + break; + + default: + printk(KERN_ERR "%s: Unexpected firmware loading state: %d\n", + MWL8K_NAME, priv->fw_state); + BUG_ON(1); + } + + return; + +fail: + priv->fw_state = FW_STATE_ERROR; + complete(&priv->firmware_loading_complete); + device_release_driver(&priv->pdev->dev); + mwl8k_release_firmware(priv); +} + +static int mwl8k_init_firmware(struct ieee80211_hw *hw, char *fw_image, + bool nowait) { struct mwl8k_priv *priv = hw->priv; int rc; @@ -4007,12 +4137,15 @@ static int mwl8k_init_firmware(struct ieee80211_hw *hw, char *fw_image) mwl8k_hw_reset(priv); /* Ask userland hotplug daemon for the device firmware */ - rc = mwl8k_request_firmware(priv, fw_image); + rc = mwl8k_request_firmware(priv, fw_image, nowait); if (rc) { wiphy_err(hw->wiphy, "Firmware files not found\n"); return rc; } + if (nowait) + return rc; + /* Load firmware into hardware */ rc = mwl8k_load_firmware(hw); if (rc) @@ -4147,7 +4280,7 @@ static int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image) for (i = 0; i < MWL8K_TX_QUEUES; i++) mwl8k_txq_deinit(hw, i); - rc = mwl8k_init_firmware(hw, fw_image); + rc = mwl8k_init_firmware(hw, fw_image, false); if (rc) goto fail; @@ -4181,6 +4314,13 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv) struct ieee80211_hw *hw = priv->hw; int i, rc; + rc = mwl8k_load_firmware(hw); + mwl8k_release_firmware(priv); + if (rc) { + wiphy_err(hw->wiphy, "Cannot start firmware\n"); + return rc; + } + /* * Extra headroom is the size of the required DMA header * minus the size of the smallest 802.11 frame (CTS frame). @@ -4325,28 +4465,29 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, } /* - * Choose the initial fw image depending on user input and availability - * of images. + * Choose the initial fw image depending on user input. If a second + * image is available, make it the alternative image that will be + * loaded if the first one fails. */ + init_completion(&priv->firmware_loading_complete); di = priv->device_info; - if (ap_mode_default && di->fw_image_ap) - rc = mwl8k_init_firmware(hw, di->fw_image_ap); - else if (!ap_mode_default && di->fw_image_sta) - rc = mwl8k_init_firmware(hw, di->fw_image_sta); - else if (ap_mode_default && !di->fw_image_ap && di->fw_image_sta) { + if (ap_mode_default && di->fw_image_ap) { + priv->fw_pref = di->fw_image_ap; + priv->fw_alt = di->fw_image_sta; + } else if (!ap_mode_default && di->fw_image_sta) { + priv->fw_pref = di->fw_image_sta; + priv->fw_alt = di->fw_image_ap; + } else if (ap_mode_default && !di->fw_image_ap && di->fw_image_sta) { printk(KERN_WARNING "AP fw is unavailable. Using STA fw."); - rc = mwl8k_init_firmware(hw, di->fw_image_sta); + priv->fw_pref = di->fw_image_sta; } else if (!ap_mode_default && !di->fw_image_sta && di->fw_image_ap) { printk(KERN_WARNING "STA fw is unavailable. Using AP fw."); - rc = mwl8k_init_firmware(hw, di->fw_image_ap); - } else - rc = mwl8k_init_firmware(hw, di->fw_image_sta); + priv->fw_pref = di->fw_image_ap; + } + rc = mwl8k_init_firmware(hw, priv->fw_pref, true); if (rc) goto err_stop_firmware; - - rc = mwl8k_firmware_load_success(priv); - if (!rc) - return rc; + return rc; err_stop_firmware: mwl8k_hw_reset(priv); @@ -4385,6 +4526,13 @@ static void __devexit mwl8k_remove(struct pci_dev *pdev) return; priv = hw->priv; + wait_for_completion(&priv->firmware_loading_complete); + + if (priv->fw_state == FW_STATE_ERROR) { + mwl8k_hw_reset(priv); + goto unmap; + } + ieee80211_stop_queues(hw); ieee80211_unregister_hw(hw); @@ -4407,6 +4555,7 @@ static void __devexit mwl8k_remove(struct pci_dev *pdev) pci_free_consistent(priv->pdev, 4, priv->cookie, priv->cookie_dma); +unmap: pci_iounmap(pdev, priv->regs); pci_iounmap(pdev, priv->sram); pci_set_drvdata(pdev, NULL); -- cgit v0.10.2 From d1f9e41d1d739cd4393840d35e7554f4a439a4f1 Mon Sep 17 00:00:00 2001 From: Brian Cavagnolo Date: Fri, 12 Nov 2010 17:23:53 -0800 Subject: mwl8k: use const struct fw pointers throughout This eliminates compiler warnings by doing things how the firmware class expects. Signed-off-by: Brian Cavagnolo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 081bb6c..9ecf840 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -144,8 +144,8 @@ struct mwl8k_priv { void __iomem *regs; /* firmware */ - struct firmware *fw_helper; - struct firmware *fw_ucode; + const struct firmware *fw_helper; + const struct firmware *fw_ucode; /* hardware/firmware parameters */ bool ap_fw; @@ -395,7 +395,7 @@ static void mwl8k_hw_reset(struct mwl8k_priv *priv) } /* Release fw image */ -static void mwl8k_release_fw(struct firmware **fw) +static void mwl8k_release_fw(const struct firmware **fw) { if (*fw == NULL) return; @@ -420,7 +420,7 @@ enum { /* Request fw image */ static int mwl8k_request_fw(struct mwl8k_priv *priv, - const char *fname, struct firmware **fw, + const char *fname, const struct firmware **fw, bool nowait) { /* release current image */ @@ -432,8 +432,7 @@ static int mwl8k_request_fw(struct mwl8k_priv *priv, &priv->pdev->dev, GFP_KERNEL, priv, mwl8k_fw_state_machine); else - return request_firmware((const struct firmware **)fw, - fname, &priv->pdev->dev); + return request_firmware(fw, fname, &priv->pdev->dev); } static int mwl8k_request_firmware(struct mwl8k_priv *priv, char *fw_image, @@ -632,12 +631,12 @@ static int mwl8k_feed_fw_image(struct mwl8k_priv *priv, static int mwl8k_load_firmware(struct ieee80211_hw *hw) { struct mwl8k_priv *priv = hw->priv; - struct firmware *fw = priv->fw_ucode; + const struct firmware *fw = priv->fw_ucode; int rc; int loops; if (!memcmp(fw->data, "\x01\x00\x00\x00", 4)) { - struct firmware *helper = priv->fw_helper; + const struct firmware *helper = priv->fw_helper; if (helper == NULL) { printk(KERN_ERR "%s: helper image needed but none " -- cgit v0.10.2 From 54435f9ec837cf0bb0ea02a2bb6362a6aaef5250 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 3 Nov 2010 22:06:26 +0100 Subject: ssb: workarounds: be verbose about hacking SPROM revision, don't duplicate 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/ssb/pci.c b/drivers/ssb/pci.c index 6e88d2b..3226832 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -573,37 +573,38 @@ static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out, ssb_dprintk(KERN_DEBUG PFX "SPROM revision %d detected.\n", out->revision); memset(out->et0mac, 0xFF, 6); /* preset et0 and et1 mac */ memset(out->et1mac, 0xFF, 6); + if ((bus->chip_id & 0xFF00) == 0x4400) { /* Workaround: The BCM44XX chip has a stupid revision * number stored in the SPROM. * Always extract r1. */ out->revision = 1; - sprom_extract_r123(out, in); + ssb_dprintk(KERN_DEBUG PFX "SPROM treated as revision %d\n", out->revision); } else if (bus->chip_id == 0x4321) { /* the BCM4328 has a chipid == 0x4321 and a rev 4 SPROM */ out->revision = 4; + ssb_dprintk(KERN_DEBUG PFX "SPROM treated as revision %d\n", out->revision); + } + + switch (out->revision) { + case 1: + case 2: + case 3: + sprom_extract_r123(out, in); + break; + case 4: + case 5: sprom_extract_r45(out, in); - } else { - switch (out->revision) { - case 1: - case 2: - case 3: - sprom_extract_r123(out, in); - break; - case 4: - case 5: - sprom_extract_r45(out, in); - break; - case 8: - sprom_extract_r8(out, in); - break; - default: - ssb_printk(KERN_WARNING PFX "Unsupported SPROM" - " revision %d detected. Will extract" - " v1\n", out->revision); - out->revision = 1; - sprom_extract_r123(out, in); - } + break; + case 8: + sprom_extract_r8(out, in); + break; + default: + ssb_printk(KERN_WARNING PFX "Unsupported SPROM" + " revision %d detected. Will extract" + " v1\n", out->revision); + out->revision = 1; + sprom_extract_r123(out, in); } if (out->boardflags_lo == 0xFFFF) -- cgit v0.10.2 From ca4a0831917d6541b45f03542257fcb20dc9cf4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 3 Nov 2010 23:28:45 +0100 Subject: ssb: return -ENOMEM on alloc fail (instead of CRC check's result) 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/ssb/pci.c b/drivers/ssb/pci.c index 3226832..b5343ac 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -619,7 +619,7 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus, struct ssb_sprom *sprom) { const struct ssb_sprom *fallback; - int err = -ENOMEM; + int err; u16 *buf; if (!ssb_is_sprom_available(bus)) { @@ -646,7 +646,7 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus, buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL); if (!buf) - goto out; + return -ENOMEM; bus->sprom_size = SSB_SPROMSIZE_WORDS_R123; sprom_do_read(bus, buf); err = sprom_check_crc(buf, bus->sprom_size); @@ -656,7 +656,7 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus, buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16), GFP_KERNEL); if (!buf) - goto out; + return -ENOMEM; bus->sprom_size = SSB_SPROMSIZE_WORDS_R4; sprom_do_read(bus, buf); err = sprom_check_crc(buf, bus->sprom_size); @@ -678,7 +678,6 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus, out_free: kfree(buf); -out: return err; } -- cgit v0.10.2 From f23a478075659db8a4fd62fa6e264a8bb052cc5b Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Mon, 8 Nov 2010 11:51:06 +0200 Subject: mac80211: support hardware TX fragmentation offload The lower driver is notified when the fragmentation threshold changes and upon a reconfig of the interface. If the driver supports hardware TX fragmentation, don't fragment packets in the stack. Signed-off-by: Arik Nemtsov Signed-off-by: John W. Linville diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 9fdf982..6122e8a 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1652,6 +1652,11 @@ enum ieee80211_ampdu_mlme_action { * and IV16) for the given key from hardware. * The callback must be atomic. * + * @set_frag_threshold: Configuration of fragmentation threshold. Assign this + * if the device does fragmentation by itself; if this callback is + * implemented then the stack will not do fragmentation. + * The callback can sleep. + * * @set_rts_threshold: Configuration of RTS threshold (if device needs it) * The callback can sleep. * @@ -1765,6 +1770,7 @@ struct ieee80211_ops { struct ieee80211_low_level_stats *stats); void (*get_tkip_seq)(struct ieee80211_hw *hw, u8 hw_key_idx, u32 *iv32, u16 *iv16); + int (*set_frag_threshold)(struct ieee80211_hw *hw, u32 value); int (*set_rts_threshold)(struct ieee80211_hw *hw, u32 value); int (*sta_add)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta); diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 18bd0e5..3df12f7 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1299,6 +1299,13 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) struct ieee80211_local *local = wiphy_priv(wiphy); int err; + if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { + err = drv_set_frag_threshold(local, wiphy->frag_threshold); + + if (err) + return err; + } + if (changed & WIPHY_PARAM_COVERAGE_CLASS) { err = drv_set_coverage_class(local, wiphy->coverage_class); diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 1698382..79019f9 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -233,6 +233,20 @@ static inline void drv_get_tkip_seq(struct ieee80211_local *local, trace_drv_get_tkip_seq(local, hw_key_idx, iv32, iv16); } +static inline int drv_set_frag_threshold(struct ieee80211_local *local, + u32 value) +{ + int ret = 0; + + might_sleep(); + + trace_drv_set_frag_threshold(local, value); + if (local->ops->set_frag_threshold) + ret = local->ops->set_frag_threshold(&local->hw, value); + trace_drv_return_int(local, ret); + return ret; +} + static inline int drv_set_rts_threshold(struct ieee80211_local *local, u32 value) { diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 6831fb1..431d655 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h @@ -531,6 +531,27 @@ TRACE_EVENT(drv_get_tkip_seq, ) ); +TRACE_EVENT(drv_set_frag_threshold, + TP_PROTO(struct ieee80211_local *local, u32 value), + + TP_ARGS(local, value), + + TP_STRUCT__entry( + LOCAL_ENTRY + __field(u32, value) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + __entry->value = value; + ), + + TP_printk( + LOCAL_PR_FMT " value:%d", + LOCAL_PR_ARG, __entry->value + ) +); + TRACE_EVENT(drv_set_rts_threshold, TP_PROTO(struct ieee80211_local *local, u32 value), diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 96c5943..b392876 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1033,6 +1033,7 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, struct ieee80211_radiotap_header *rthdr = (struct ieee80211_radiotap_header *) skb->data; struct ieee80211_supported_band *sband; + bool hw_frag; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len, NULL); @@ -1042,6 +1043,9 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; tx->flags &= ~IEEE80211_TX_FRAGMENTED; + /* packet is fragmented in HW if we have a non-NULL driver callback */ + hw_frag = (tx->local->ops->set_frag_threshold != NULL); + /* * for every radiotap entry that is present * (ieee80211_radiotap_iterator_next returns -ENOENT when no more @@ -1078,7 +1082,8 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, } if (*iterator.this_arg & IEEE80211_RADIOTAP_F_WEP) info->flags &= ~IEEE80211_TX_INTFL_DONT_ENCRYPT; - if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG) + if ((*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG) && + !hw_frag) tx->flags |= IEEE80211_TX_FRAGMENTED; break; @@ -1181,8 +1186,10 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, /* * Set this flag (used below to indicate "automatic fragmentation"), * it will be cleared/left by radiotap as desired. + * Only valid when fragmentation is done by the stack. */ - tx->flags |= IEEE80211_TX_FRAGMENTED; + if (!local->ops->set_frag_threshold) + tx->flags |= IEEE80211_TX_FRAGMENTED; /* process and remove the injection radiotap header */ if (unlikely(info->flags & IEEE80211_TX_INTFL_HAS_RADIOTAP)) { diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 0b6fc92..e486286 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1152,6 +1152,9 @@ int ieee80211_reconfig(struct ieee80211_local *local) } mutex_unlock(&local->sta_mtx); + /* setup fragmentation threshold */ + drv_set_frag_threshold(local, hw->wiphy->frag_threshold); + /* setup RTS threshold */ drv_set_rts_threshold(local, hw->wiphy->rts_threshold); -- cgit v0.10.2 From b5257c952dda24df7078c74b7b811b44c6e49206 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Tue, 9 Nov 2010 19:25:47 +0200 Subject: rndis_wlan: workaround device not returning bss for currently connected AP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BCM4320a devices do not return bss for currently connected AP in bss-list, althought this is required by NDIS specs. Missing bss leads to warning at net/wireless/sme.c:__cfg80211_connect_result(), WARN_ON(!bss). Workaround this by crafting bss manually with information we can read from device. Workaround is only used when device bss-list does not return current bss, and so is only used with BCM4320a devices and not newer BCM4320b ones. Fixes bug #20152. Reported-by: Luís Picciochi Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 71b5971..0a423c4 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -994,7 +994,8 @@ static int level_to_qual(int level) */ static int set_infra_mode(struct usbnet *usbdev, int mode); static void restore_keys(struct usbnet *usbdev); -static int rndis_check_bssid_list(struct usbnet *usbdev); +static int rndis_check_bssid_list(struct usbnet *usbdev, u8 *match_bssid, + bool *matched); static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid) { @@ -1911,7 +1912,7 @@ static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, /* Get current bssid list from device before new scan, as new scan * clears internal bssid list. */ - rndis_check_bssid_list(usbdev); + rndis_check_bssid_list(usbdev, NULL, NULL); if (!request) return -EINVAL; @@ -1981,7 +1982,8 @@ static struct cfg80211_bss *rndis_bss_info_update(struct usbnet *usbdev, GFP_KERNEL); } -static int rndis_check_bssid_list(struct usbnet *usbdev) +static int rndis_check_bssid_list(struct usbnet *usbdev, u8 *match_bssid, + bool *matched) { void *buf = NULL; struct ndis_80211_bssid_list_ex *bssid_list; @@ -2017,7 +2019,11 @@ resize_buf: count, len); while (count && ((void *)bssid + bssid_len) <= (buf + len)) { - rndis_bss_info_update(usbdev, bssid); + if (rndis_bss_info_update(usbdev, bssid) && match_bssid && + matched) { + if (compare_ether_addr(bssid->mac, match_bssid)) + *matched = true; + } bssid = (void *)bssid + bssid_len; bssid_len = le32_to_cpu(bssid->length); @@ -2041,7 +2047,7 @@ static void rndis_get_scan_results(struct work_struct *work) if (!priv->scan_request) return; - ret = rndis_check_bssid_list(usbdev); + ret = rndis_check_bssid_list(usbdev, NULL, NULL); cfg80211_scan_done(priv->scan_request, ret < 0); @@ -2495,6 +2501,91 @@ static int rndis_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev) return rndis_set_oid(usbdev, OID_802_11_PMKID, &pmkid, sizeof(pmkid)); } +static void rndis_wlan_craft_connected_bss(struct usbnet *usbdev, u8 *bssid, + struct ndis_80211_assoc_info *info) +{ + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); + struct ieee80211_channel *channel; + struct ndis_80211_conf config; + struct ndis_80211_ssid ssid; + s32 signal; + u64 timestamp; + u16 capability; + u16 beacon_interval; + __le32 rssi; + u8 ie_buf[34]; + int len, ret, ie_len; + + /* Get signal quality, in case of error use rssi=0 and ignore error. */ + len = sizeof(rssi); + rssi = 0; + rndis_query_oid(usbdev, OID_802_11_RSSI, &rssi, &len); + signal = level_to_qual(le32_to_cpu(rssi)); + + netdev_dbg(usbdev->net, "%s(): OID_802_11_RSSI -> %d, " + "rssi:%d, qual: %d\n", __func__, ret, le32_to_cpu(rssi), + level_to_qual(le32_to_cpu(rssi))); + + /* Get AP capabilities */ + if (info) { + capability = le16_to_cpu(info->resp_ie.capa); + } else { + /* Set atleast ESS/IBSS capability */ + capability = (priv->infra_mode == NDIS_80211_INFRA_INFRA) ? + WLAN_CAPABILITY_ESS : WLAN_CAPABILITY_IBSS; + } + + /* Get channel and beacon interval */ + len = sizeof(config); + ret = rndis_query_oid(usbdev, OID_802_11_CONFIGURATION, &config, &len); + netdev_dbg(usbdev->net, "%s(): OID_802_11_CONFIGURATION -> %d\n", + __func__, ret); + if (ret >= 0) { + beacon_interval = le16_to_cpu(config.beacon_period); + channel = ieee80211_get_channel(priv->wdev.wiphy, + KHZ_TO_MHZ(le32_to_cpu(config.ds_config))); + if (!channel) { + netdev_warn(usbdev->net, "%s(): could not get channel." + "\n", __func__); + return; + } + } else { + netdev_warn(usbdev->net, "%s(): could not get configuration.\n", + __func__); + return; + } + + /* Get SSID, in case of error, use zero length SSID and ignore error. */ + len = sizeof(ssid); + memset(&ssid, 0, sizeof(ssid)); + ret = rndis_query_oid(usbdev, OID_802_11_SSID, &ssid, &len); + netdev_dbg(usbdev->net, "%s(): OID_802_11_SSID -> %d, len: %d, ssid: " + "'%.32s'\n", __func__, ret, + le32_to_cpu(ssid.length), ssid.essid); + + if (le32_to_cpu(ssid.length) > 32) + ssid.length = cpu_to_le32(32); + + ie_buf[0] = WLAN_EID_SSID; + ie_buf[1] = le32_to_cpu(ssid.length); + memcpy(&ie_buf[2], ssid.essid, le32_to_cpu(ssid.length)); + + ie_len = le32_to_cpu(ssid.length) + 2; + + /* no tsf */ + timestamp = 0; + + netdev_dbg(usbdev->net, "%s(): channel:%d(freq), bssid:[%pM], tsf:%d, " + "capa:%x, beacon int:%d, resp_ie(len:%d, essid:'%.32s'), " + "signal:%d\n", __func__, (channel ? channel->center_freq : -1), + bssid, (u32)timestamp, capability, beacon_interval, ie_len, + ssid.essid, signal); + + cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid, + timestamp, capability, beacon_interval, ie_buf, ie_len, + signal, GFP_KERNEL); +} + /* * workers, indication handlers, device poller */ @@ -2507,6 +2598,7 @@ static void rndis_wlan_do_link_up_work(struct usbnet *usbdev) u8 *req_ie, *resp_ie; int ret, offset; bool roamed = false; + bool match_bss; if (priv->infra_mode == NDIS_80211_INFRA_INFRA && priv->connected) { /* received media connect indication while connected, either @@ -2558,6 +2650,13 @@ static void rndis_wlan_do_link_up_work(struct usbnet *usbdev) resp_ie_len = CONTROL_BUFFER_SIZE - offset; } + } else { + /* Since rndis_wlan_craft_connected_bss() might use info + * later and expects info to contain valid data if + * non-null, free info and set NULL here. + */ + kfree(info); + info = NULL; } } else if (WARN_ON(priv->infra_mode != NDIS_80211_INFRA_ADHOC)) return; @@ -2569,13 +2668,26 @@ static void rndis_wlan_do_link_up_work(struct usbnet *usbdev) netdev_dbg(usbdev->net, "link up work: [%pM]%s\n", bssid, roamed ? " roamed" : ""); - /* Internal bss list in device always contains at least the currently + /* Internal bss list in device should contain at least the currently * connected bss and we can get it to cfg80211 with * rndis_check_bssid_list(). - * NOTE: This is true for Broadcom chip, but not mentioned in RNDIS - * spec. + * + * NDIS spec says: "If the device is associated, but the associated + * BSSID is not in its BSSID scan list, then the driver must add an + * entry for the BSSID at the end of the data that it returns in + * response to query of OID_802_11_BSSID_LIST." + * + * NOTE: Seems to be true for BCM4320b variant, but not BCM4320a. */ - rndis_check_bssid_list(usbdev); + match_bss = false; + rndis_check_bssid_list(usbdev, bssid, &match_bss); + + if (!is_zero_ether_addr(bssid) && !match_bss) { + /* Couldn't get bss from device, we need to manually craft bss + * for cfg80211. + */ + rndis_wlan_craft_connected_bss(usbdev, bssid, info); + } if (priv->infra_mode == NDIS_80211_INFRA_INFRA) { if (!roamed) -- cgit v0.10.2 From 5cb56af29be8d12f74afcb2c1de91e51a577bd52 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Tue, 9 Nov 2010 19:25:56 +0200 Subject: rndis_wlan: workaround poor scanning with BCM4320a MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BCM4320a devices seem to sometimes do scanning pretty poorly. This can be workaround by issuing new scan every second, while not yet connected. By this new scanning method device catches beacons much faster. Fixes bug #20822. Reported-by: Luís Picciochi Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 0a423c4..8a77ff6 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -156,6 +156,12 @@ MODULE_PARM_DESC(workaround_interval, #define RNDIS_STATUS_ADAPTER_NOT_OPEN cpu_to_le32(0xc0010012) +/* Known device types */ +#define RNDIS_UNKNOWN 0 +#define RNDIS_BCM4320A 1 +#define RNDIS_BCM4320B 2 + + /* NDIS data structures. Taken from wpa_supplicant driver_ndis.c * slightly modified for datatype endianess, etc */ @@ -478,6 +484,7 @@ struct rndis_wlan_private { struct ieee80211_rate rates[ARRAY_SIZE(rndis_rates)]; u32 cipher_suites[ARRAY_SIZE(rndis_cipher_suites)]; + int device_type; int caps; int multicast_size; @@ -997,6 +1004,16 @@ static void restore_keys(struct usbnet *usbdev); static int rndis_check_bssid_list(struct usbnet *usbdev, u8 *match_bssid, bool *matched); +static int rndis_start_bssid_list_scan(struct usbnet *usbdev) +{ + __le32 tmp; + + /* Note: OID_802_11_BSSID_LIST_SCAN clears internal BSS list. */ + tmp = cpu_to_le32(1); + return rndis_set_oid(usbdev, OID_802_11_BSSID_LIST_SCAN, &tmp, + sizeof(tmp)); +} + static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); @@ -1905,7 +1922,7 @@ static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, struct usbnet *usbdev = netdev_priv(dev); struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); int ret; - __le32 tmp; + int delay = SCAN_DELAY_JIFFIES; netdev_dbg(usbdev->net, "cfg80211.scan\n"); @@ -1922,13 +1939,13 @@ static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, priv->scan_request = request; - tmp = cpu_to_le32(1); - ret = rndis_set_oid(usbdev, OID_802_11_BSSID_LIST_SCAN, &tmp, - sizeof(tmp)); + ret = rndis_start_bssid_list_scan(usbdev); if (ret == 0) { + if (priv->device_type == RNDIS_BCM4320A) + delay = HZ; + /* Wait before retrieving scan results from device */ - queue_delayed_work(priv->workqueue, &priv->scan_work, - SCAN_DELAY_JIFFIES); + queue_delayed_work(priv->workqueue, &priv->scan_work, delay); } return ret; @@ -3046,8 +3063,21 @@ static void rndis_device_poller(struct work_struct *work) * also polls device with rndis_command() and catches for media link * indications. */ - if (!is_associated(usbdev)) + if (!is_associated(usbdev)) { + /* Workaround bad scanning in BCM4320a devices with active + * background scanning when not associated. + */ + if (priv->device_type == RNDIS_BCM4320A && priv->radio_on && + !priv->scan_request) { + /* Get previous scan results */ + rndis_check_bssid_list(usbdev, NULL, NULL); + + /* Initiate new scan */ + rndis_start_bssid_list_scan(usbdev); + } + goto end; + } len = sizeof(rssi); ret = rndis_query_oid(usbdev, OID_802_11_RSSI, &rssi, &len); @@ -3104,10 +3134,12 @@ end: /* * driver/device initialization */ -static void rndis_copy_module_params(struct usbnet *usbdev) +static void rndis_copy_module_params(struct usbnet *usbdev, int device_type) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); + priv->device_type = device_type; + priv->param_country[0] = modparam_country[0]; priv->param_country[1] = modparam_country[1]; priv->param_country[2] = 0; @@ -3150,12 +3182,25 @@ static void rndis_copy_module_params(struct usbnet *usbdev) priv->param_workaround_interval = modparam_workaround_interval; } +static int unknown_early_init(struct usbnet *usbdev) +{ + /* copy module parameters for unknown so that iwconfig reports txpower + * and workaround parameter is copied to private structure correctly. + */ + rndis_copy_module_params(usbdev, RNDIS_UNKNOWN); + + /* This is unknown device, so do not try set configuration parameters. + */ + + return 0; +} + static int bcm4320a_early_init(struct usbnet *usbdev) { /* copy module parameters for bcm4320a so that iwconfig reports txpower * and workaround parameter is copied to private structure correctly. */ - rndis_copy_module_params(usbdev); + rndis_copy_module_params(usbdev, RNDIS_BCM4320A); /* bcm4320a doesn't handle configuration parameters well. Try * set any and you get partially zeroed mac and broken device. @@ -3169,7 +3214,7 @@ static int bcm4320b_early_init(struct usbnet *usbdev) struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); char buf[8]; - rndis_copy_module_params(usbdev); + rndis_copy_module_params(usbdev, RNDIS_BCM4320B); /* Early initialization settings, setting these won't have effect * if called after generic_rndis_bind(). @@ -3432,7 +3477,7 @@ static const struct driver_info rndis_wlan_info = { .tx_fixup = rndis_tx_fixup, .reset = rndis_wlan_reset, .stop = rndis_wlan_stop, - .early_init = bcm4320a_early_init, + .early_init = unknown_early_init, .indication = rndis_wlan_indication, }; -- cgit v0.10.2 From 7e559ec31c5625cf85bcb1ae0eb9f8f2a8da4a29 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 9 Nov 2010 16:35:17 -0800 Subject: drivers/net/wireless/ath/debug.c: Use printf extension %pV Using %pV reduces the number of printk calls and eliminates any possible message interleaving from other printk calls. Signed-off-by: Joe Perches Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/debug.c b/drivers/net/wireless/ath/debug.c index dacfb23..a9600ba 100644 --- a/drivers/net/wireless/ath/debug.c +++ b/drivers/net/wireless/ath/debug.c @@ -19,14 +19,19 @@ void ath_print(struct ath_common *common, int dbg_mask, const char *fmt, ...) { + struct va_format vaf; va_list args; if (likely(!(common->debug_mask & dbg_mask))) return; va_start(args, fmt); - printk(KERN_DEBUG "ath: "); - vprintk(fmt, args); + + vaf.fmt = fmt; + vaf.va = &args; + + printk(KERN_DEBUG "ath: %pV", &vaf); + va_end(args); } EXPORT_SYMBOL(ath_print); -- cgit v0.10.2 From 5b736d42bc51fe893fd7d4ceac34c727d23135e1 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 9 Nov 2010 16:35:18 -0800 Subject: drivers/net/wireless/b43/main.c: Use printf extension %pV Using %pV reduces the number of printk calls and eliminates any possible message interleaving from other printk calls. Signed-off-by: Joe Perches Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index a118652..fa48803 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -322,59 +322,83 @@ static int b43_ratelimit(struct b43_wl *wl) void b43info(struct b43_wl *wl, const char *fmt, ...) { + struct va_format vaf; va_list args; if (b43_modparam_verbose < B43_VERBOSITY_INFO) return; if (!b43_ratelimit(wl)) return; + va_start(args, fmt); - printk(KERN_INFO "b43-%s: ", - (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan"); - vprintk(fmt, args); + + vaf.fmt = fmt; + vaf.va = &args; + + printk(KERN_INFO "b43-%s: %pV", + (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan", &vaf); + va_end(args); } void b43err(struct b43_wl *wl, const char *fmt, ...) { + struct va_format vaf; va_list args; if (b43_modparam_verbose < B43_VERBOSITY_ERROR) return; if (!b43_ratelimit(wl)) return; + va_start(args, fmt); - printk(KERN_ERR "b43-%s ERROR: ", - (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan"); - vprintk(fmt, args); + + vaf.fmt = fmt; + vaf.va = &args; + + printk(KERN_ERR "b43-%s ERROR: %pV", + (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan", &vaf); + va_end(args); } void b43warn(struct b43_wl *wl, const char *fmt, ...) { + struct va_format vaf; va_list args; if (b43_modparam_verbose < B43_VERBOSITY_WARN) return; if (!b43_ratelimit(wl)) return; + va_start(args, fmt); - printk(KERN_WARNING "b43-%s warning: ", - (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan"); - vprintk(fmt, args); + + vaf.fmt = fmt; + vaf.va = &args; + + printk(KERN_WARNING "b43-%s warning: %pV", + (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan", &vaf); + va_end(args); } void b43dbg(struct b43_wl *wl, const char *fmt, ...) { + struct va_format vaf; va_list args; if (b43_modparam_verbose < B43_VERBOSITY_DEBUG) return; + va_start(args, fmt); - printk(KERN_DEBUG "b43-%s debug: ", - (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan"); - vprintk(fmt, args); + + vaf.fmt = fmt; + vaf.va = &args; + + printk(KERN_DEBUG "b43-%s debug: %pV", + (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan", &vaf); + va_end(args); } -- cgit v0.10.2 From 0e67d6cb753643fc076a90fa9309301b3fbfb8db Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 9 Nov 2010 16:35:19 -0800 Subject: drivers/net/wireless/b43legacy/main.c: Use printf extension %pV Using %pV reduces the number of printk calls and eliminates any possible message interleaving from other printk calls. Signed-off-by: Joe Perches Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 67f18ec..1f11e16 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -181,52 +181,75 @@ static int b43legacy_ratelimit(struct b43legacy_wl *wl) void b43legacyinfo(struct b43legacy_wl *wl, const char *fmt, ...) { + struct va_format vaf; va_list args; if (!b43legacy_ratelimit(wl)) return; + va_start(args, fmt); - printk(KERN_INFO "b43legacy-%s: ", - (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan"); - vprintk(fmt, args); + + vaf.fmt = fmt; + vaf.va = &args; + + printk(KERN_INFO "b43legacy-%s: %pV", + (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan", &vaf); + va_end(args); } void b43legacyerr(struct b43legacy_wl *wl, const char *fmt, ...) { + struct va_format vaf; va_list args; if (!b43legacy_ratelimit(wl)) return; + va_start(args, fmt); - printk(KERN_ERR "b43legacy-%s ERROR: ", - (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan"); - vprintk(fmt, args); + + vaf.fmt = fmt; + vaf.va = &args; + + printk(KERN_ERR "b43legacy-%s ERROR: %pV", + (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan", &vaf); + va_end(args); } void b43legacywarn(struct b43legacy_wl *wl, const char *fmt, ...) { + struct va_format vaf; va_list args; if (!b43legacy_ratelimit(wl)) return; + va_start(args, fmt); - printk(KERN_WARNING "b43legacy-%s warning: ", - (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan"); - vprintk(fmt, args); + + vaf.fmt = fmt; + vaf.va = &args; + + printk(KERN_WARNING "b43legacy-%s warning: %pV", + (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan", &vaf); + va_end(args); } #if B43legacy_DEBUG void b43legacydbg(struct b43legacy_wl *wl, const char *fmt, ...) { + struct va_format vaf; va_list args; va_start(args, fmt); - printk(KERN_DEBUG "b43legacy-%s debug: ", - (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan"); - vprintk(fmt, args); + + vaf.fmt = fmt; + vaf.va = &args; + + printk(KERN_DEBUG "b43legacy-%s debug: %pV", + (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan", &vaf); + va_end(args); } #endif /* DEBUG */ -- cgit v0.10.2 From afe0cbf87500f0585d217deb8c6fd329793a7957 Mon Sep 17 00:00:00 2001 From: Bruno Randolf Date: Wed, 10 Nov 2010 12:50:50 +0900 Subject: cfg80211: Add nl80211 antenna configuration Allow setting of TX and RX antennas configuration via nl80211. The antenna configuration is defined as a bitmap of allowed antennas to use. This API can be used to mask out antennas which are not attached or should not be used for other reasons like regulatory concerns or special setups. Separate bitmaps are used for RX and TX to allow configuring different antennas for receiving and transmitting. Each bitmap is 32 bit long, each bit representing one antenna, starting with antenna 1 at the first bit. If an antenna bit is set, this means the driver is allowed to use this antenna for RX or TX respectively; if the bit is not set the hardware is not allowed to use this antenna. Using bitmaps has the benefit of allowing for a flexible configuration interface which can support many different configurations and which can be used for 802.11n as well as non-802.11n devices. Instead of relying on some hardware specific assumptions, drivers can use this information to know which antennas are actually attached to the system and derive their capabilities based on that. 802.11n devices should enable or disable chains, based on which antennas are present (If all antennas belonging to a particular chain are disabled, the entire chain should be disabled). HT capabilities (like STBC, TX Beamforming, Antenna selection) should be calculated based on the available chains after applying the antenna masks. Should a 802.11n device have diversity antennas attached to one of their chains, diversity can be enabled or disabled based on the antenna information. Non-802.11n drivers can use the antenna masks to select RX and TX antennas and to enable or disable antenna diversity. While covering chainmasks for 802.11n and the standard "legacy" modes "fixed antenna 1", "fixed antenna 2" and "diversity" this API also allows more rare, but useful configurations as follows: 1) Send on antenna 1, receive on antenna 2 (or vice versa). This can be used to have a low gain antenna for TX in order to keep within the regulatory constraints and a high gain antenna for RX in order to receive weaker signals ("speak softly, but listen harder"). This can be useful for building long-shot outdoor links. Another usage of this setup is having a low-noise pre-amplifier on antenna 1 and a power amplifier on the other antenna. This way transmit noise is mostly kept out of the low noise receive channel. (This would be bitmaps: tx 1 rx 2). 2) Another similar setup is: Use RX diversity on both antennas, but always send on antenna 1. Again that would allow us to benefit from a higher gain RX antenna, while staying within the legal limits. (This would be: tx 0 rx 3). 3) And finally there can be special experimental setups in research and development even with pre 802.11n hardware where more than 2 antennas are available. It's good to keep the API simple, yet flexible. Signed-off-by: Bruno Randolf -- v7: Made bitmasks 32 bit wide and rebased to latest wireless-testing. Signed-off-by: John W. Linville diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index fb877b56..17c5c88 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -804,6 +804,28 @@ enum nl80211_commands { * @NL80211_ATTR_SUPPORT_IBSS_RSN: The device supports IBSS RSN, which mostly * means support for per-station GTKs. * + * @NL80211_ATTR_WIPHY_ANTENNA_TX: Bitmap of allowed antennas for transmitting. + * This can be used to mask out antennas which are not attached or should + * not be used for transmitting. If an antenna is not selected in this + * bitmap the hardware is not allowed to transmit on this antenna. + * + * Each bit represents one antenna, starting with antenna 1 at the first + * bit. Depending on which antennas are selected in the bitmap, 802.11n + * drivers can derive which chainmasks to use (if all antennas belonging to + * a particular chain are disabled this chain should be disabled) and if + * a chain has diversity antennas wether diversity should be used or not. + * HT capabilities (STBC, TX Beamforming, Antenna selection) can be + * derived from the available chains after applying the antenna mask. + * Non-802.11n drivers can derive wether to use diversity or not. + * Drivers may reject configurations or RX/TX mask combinations they cannot + * support by returning -EINVAL. + * + * @NL80211_ATTR_WIPHY_ANTENNA_RX: Bitmap of allowed antennas for receiving. + * This can be used to mask out antennas which are not attached or should + * not be used for receiving. If an antenna is not selected in this bitmap + * the hardware should not be configured to receive on this antenna. + * For a more detailed descripton see @NL80211_ATTR_WIPHY_ANTENNA_TX. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -973,6 +995,9 @@ enum nl80211_attrs { NL80211_ATTR_SUPPORT_IBSS_RSN, + NL80211_ATTR_WIPHY_ANTENNA_TX, + NL80211_ATTR_WIPHY_ANTENNA_RX, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index e5702f5..07425e6 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1304,6 +1304,9 @@ struct cfg80211_ops { void (*mgmt_frame_register)(struct wiphy *wiphy, struct net_device *dev, u16 frame_type, bool reg); + + int (*set_antenna)(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant); + int (*get_antenna)(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant); }; /* diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index c506241..5e4dda4 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -166,7 +166,11 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { [NL80211_ATTR_WIPHY_TX_POWER_SETTING] = { .type = NLA_U32 }, [NL80211_ATTR_WIPHY_TX_POWER_LEVEL] = { .type = NLA_U32 }, + [NL80211_ATTR_FRAME_TYPE] = { .type = NLA_U16 }, + + [NL80211_ATTR_WIPHY_ANTENNA_TX] = { .type = NLA_U32 }, + [NL80211_ATTR_WIPHY_ANTENNA_RX] = { .type = NLA_U32 }, }; /* policy for the key attributes */ @@ -526,7 +530,6 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, dev->wiphy.rts_threshold); NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, dev->wiphy.coverage_class); - NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS, dev->wiphy.max_scan_ssids); NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN, @@ -545,6 +548,16 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, if (dev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE); + if (dev->ops->get_antenna) { + u32 tx_ant = 0, rx_ant = 0; + int res; + res = dev->ops->get_antenna(&dev->wiphy, &tx_ant, &rx_ant); + if (!res) { + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_TX, tx_ant); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_RX, rx_ant); + } + } + nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES); if (!nl_modes) goto nla_put_failure; @@ -1024,6 +1037,22 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) goto bad_res; } + if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX] && + info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]) { + u32 tx_ant, rx_ant; + if (!rdev->ops->set_antenna) { + result = -EOPNOTSUPP; + goto bad_res; + } + + tx_ant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX]); + rx_ant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]); + + result = rdev->ops->set_antenna(&rdev->wiphy, tx_ant, rx_ant); + if (result) + goto bad_res; + } + changed = 0; if (info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]) { -- cgit v0.10.2 From 15d967532148a5fcda075282b82a271b6595a386 Mon Sep 17 00:00:00 2001 From: Bruno Randolf Date: Wed, 10 Nov 2010 12:50:56 +0900 Subject: mac80211: Add antenna configuration Allow antenna configuration by calling driver's function for it. We disallow antenna configuration if the wiphy is already running, mainly to make life easier for 802.11n drivers which need to recalculate HT capabilites. Signed-off-by: Bruno Randolf Signed-off-by: John W. Linville diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 6122e8a..a7323ec 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1799,6 +1799,8 @@ struct ieee80211_ops { void (*channel_switch)(struct ieee80211_hw *hw, struct ieee80211_channel_switch *ch_switch); int (*napi_poll)(struct ieee80211_hw *hw, int budget); + int (*set_antenna)(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant); + int (*get_antenna)(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant); }; /** diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 3df12f7..0c54407 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1628,6 +1628,23 @@ static void ieee80211_mgmt_frame_register(struct wiphy *wiphy, ieee80211_queue_work(&local->hw, &local->reconfig_filter); } +static int ieee80211_set_antenna(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant) +{ + struct ieee80211_local *local = wiphy_priv(wiphy); + + if (local->started) + return -EOPNOTSUPP; + + return drv_set_antenna(local, tx_ant, rx_ant); +} + +static int ieee80211_get_antenna(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant) +{ + struct ieee80211_local *local = wiphy_priv(wiphy); + + return drv_get_antenna(local, tx_ant, rx_ant); +} + struct cfg80211_ops mac80211_config_ops = { .add_virtual_intf = ieee80211_add_iface, .del_virtual_intf = ieee80211_del_iface, @@ -1680,4 +1697,6 @@ struct cfg80211_ops mac80211_config_ops = { .mgmt_tx = ieee80211_mgmt_tx, .set_cqm_rssi_config = ieee80211_set_cqm_rssi_config, .mgmt_frame_register = ieee80211_mgmt_frame_register, + .set_antenna = ieee80211_set_antenna, + .get_antenna = ieee80211_get_antenna, }; diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 79019f9..4244554 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -442,4 +442,27 @@ static inline void drv_channel_switch(struct ieee80211_local *local, trace_drv_return_void(local); } + +static inline int drv_set_antenna(struct ieee80211_local *local, + u32 tx_ant, u32 rx_ant) +{ + int ret = -EOPNOTSUPP; + might_sleep(); + if (local->ops->set_antenna) + ret = local->ops->set_antenna(&local->hw, tx_ant, rx_ant); + trace_drv_set_antenna(local, tx_ant, rx_ant, ret); + return ret; +} + +static inline int drv_get_antenna(struct ieee80211_local *local, + u32 *tx_ant, u32 *rx_ant) +{ + int ret = -EOPNOTSUPP; + might_sleep(); + if (local->ops->get_antenna) + ret = local->ops->get_antenna(&local->hw, tx_ant, rx_ant); + trace_drv_get_antenna(local, *tx_ant, *rx_ant, ret); + return ret; +} + #endif /* __MAC80211_DRIVER_OPS */ diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 431d655..c2772f2 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h @@ -883,6 +883,56 @@ TRACE_EVENT(drv_channel_switch, ) ); +TRACE_EVENT(drv_set_antenna, + TP_PROTO(struct ieee80211_local *local, u32 tx_ant, u32 rx_ant, int ret), + + TP_ARGS(local, tx_ant, rx_ant, ret), + + TP_STRUCT__entry( + LOCAL_ENTRY + __field(u32, tx_ant) + __field(u32, rx_ant) + __field(int, ret) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + __entry->tx_ant = tx_ant; + __entry->rx_ant = rx_ant; + __entry->ret = ret; + ), + + TP_printk( + LOCAL_PR_FMT " tx_ant:%d rx_ant:%d ret:%d", + LOCAL_PR_ARG, __entry->tx_ant, __entry->rx_ant, __entry->ret + ) +); + +TRACE_EVENT(drv_get_antenna, + TP_PROTO(struct ieee80211_local *local, u32 tx_ant, u32 rx_ant, int ret), + + TP_ARGS(local, tx_ant, rx_ant, ret), + + TP_STRUCT__entry( + LOCAL_ENTRY + __field(u32, tx_ant) + __field(u32, rx_ant) + __field(int, ret) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + __entry->tx_ant = tx_ant; + __entry->rx_ant = rx_ant; + __entry->ret = ret; + ), + + TP_printk( + LOCAL_PR_FMT " tx_ant:%d rx_ant:%d ret:%d", + LOCAL_PR_ARG, __entry->tx_ant, __entry->rx_ant, __entry->ret + ) +); + /* * Tracing for API calls that drivers call. */ -- cgit v0.10.2 From 72a801103f07182c0a4f3a761caa62b4ab8eb4e5 Mon Sep 17 00:00:00 2001 From: Bruno Randolf Date: Wed, 10 Nov 2010 12:51:01 +0900 Subject: ath5k: Add support for antenna configuration Support setting the antenna configuration via cfg/mac80211. At the moment only allow the simple pre-defined configurations we already have (fixed antenna A/B or diversity), but more advanced settings are possible to implement. Signed-off-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 b9f93fb..fe116de 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -3413,6 +3413,36 @@ static int ath5k_conf_tx(struct ieee80211_hw *hw, u16 queue, return ret; } +static int ath5k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) +{ + struct ath5k_softc *sc = hw->priv; + + if (tx_ant == 1 && rx_ant == 1) + ath5k_hw_set_antenna_mode(sc->ah, AR5K_ANTMODE_FIXED_A); + else if (tx_ant == 2 && rx_ant == 2) + ath5k_hw_set_antenna_mode(sc->ah, AR5K_ANTMODE_FIXED_B); + else if ((tx_ant & 3) == 3 && (rx_ant & 3) == 3) + ath5k_hw_set_antenna_mode(sc->ah, AR5K_ANTMODE_DEFAULT); + else + return -EINVAL; + return 0; +} + +static int ath5k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) +{ + struct ath5k_softc *sc = hw->priv; + + switch (sc->ah->ah_ant_mode) { + case AR5K_ANTMODE_FIXED_A: + *tx_ant = 1; *rx_ant = 1; break; + case AR5K_ANTMODE_FIXED_B: + *tx_ant = 2; *rx_ant = 2; break; + case AR5K_ANTMODE_DEFAULT: + *tx_ant = 3; *rx_ant = 3; break; + } + return 0; +} + static const struct ieee80211_ops ath5k_hw_ops = { .tx = ath5k_tx, .start = ath5k_start, @@ -3433,6 +3463,8 @@ static const struct ieee80211_ops ath5k_hw_ops = { .sw_scan_start = ath5k_sw_scan_start, .sw_scan_complete = ath5k_sw_scan_complete, .set_coverage_class = ath5k_set_coverage_class, + .set_antenna = ath5k_set_antenna, + .get_antenna = ath5k_get_antenna, }; /********************\ -- cgit v0.10.2 From a9d85fbd3e5f7a0679e6276953cd23ac7bb72789 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Thu, 11 Nov 2010 00:40:33 -0800 Subject: ath9k_hw: Fix a reset failure on AR9382 (2x2). AR9382 needs to be configured for the correct chain mask before running AGC/TxIQ caliberation. Otherwise reset would fail. Signed-off-by: Senthil Balasubramanian Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 9e6edff..32eed19 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -718,12 +718,19 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) { struct ath_common *common = ath9k_hw_common(ah); + int val; - /* - * 0x7 = 0b111 , AR9003 needs to be configured for 3-chain mode before - * running AGC/TxIQ cals - */ - ar9003_hw_set_chain_masks(ah, 0x7, 0x7); + val = REG_READ(ah, AR_ENT_OTP); + ath_print(common, ATH_DBG_CALIBRATE, "ath9k: AR_ENT_OTP 0x%x\n", val); + + if (val & AR_ENT_OTP_CHAIN2_DISABLE) + ar9003_hw_set_chain_masks(ah, 0x3, 0x3); + else + /* + * 0x7 = 0b111 , AR9003 needs to be configured for 3-chain + * mode before running AGC/TxIQ cals + */ + ar9003_hw_set_chain_masks(ah, 0x7, 0x7); /* Do Tx IQ Calibration */ ar9003_hw_tx_iq_cal(ah); diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 42976b0..ac6a13e 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -1065,6 +1065,8 @@ enum { #define AR_INTR_PRIO_ASYNC_MASK 0x40c8 #define AR_INTR_PRIO_SYNC_MASK 0x40cc #define AR_INTR_PRIO_ASYNC_ENABLE 0x40d4 +#define AR_ENT_OTP 0x40d8 +#define AR_ENT_OTP_CHAIN2_DISABLE 0x00020000 #define AR_RTC_9300_PLL_DIV 0x000003ff #define AR_RTC_9300_PLL_DIV_S 0 -- cgit v0.10.2 From b3dd6bc1f052ef3a754fa866743e4fda38522811 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Wed, 10 Nov 2010 05:03:07 -0800 Subject: ath9k_hw: Add new member into the eeprom structure. Add eeprom base extension structures which are needed for AR938x caliberation changes and gain calculation. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index a88fe0d..bc3f49c 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -147,10 +147,13 @@ static const struct ar9300_eeprom ar9300_default = { .papdRateMaskHt20 = LE32(0x80c080), .papdRateMaskHt40 = LE32(0x80c080), .futureModal = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, }, + .base_ext1 = { + .ant_div_control = 0, + .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + }, .calFreqPier2G = { FREQ2FBIN(2412, 1), FREQ2FBIN(2437, 1), @@ -285,8 +288,7 @@ static const struct ar9300_eeprom ar9300_default = { /* Data[11].ctlEdges[0].bChannel */ FREQ2FBIN(2422, 1), /* Data[11].ctlEdges[1].bChannel */ FREQ2FBIN(2427, 1), /* Data[11].ctlEdges[2].bChannel */ FREQ2FBIN(2447, 1), - /* Data[11].ctlEdges[3].bChannel */ - FREQ2FBIN(2462, 1), + /* Data[11].ctlEdges[3].bChannel */ FREQ2FBIN(2462, 1), } }, .ctlPowerData_2G = { @@ -346,10 +348,17 @@ static const struct ar9300_eeprom ar9300_default = { .papdRateMaskHt20 = LE32(0xf0e0e0), .papdRateMaskHt40 = LE32(0xf0e0e0), .futureModal = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, }, + .base_ext2 = { + .tempSlopeLow = 0, + .tempSlopeHigh = 0, + .xatten1DBLow = {0, 0, 0}, + .xatten1MarginLow = {0, 0, 0}, + .xatten1DBHigh = {0, 0, 0}, + .xatten1MarginHigh = {0, 0, 0} + }, .calFreqPier5G = { FREQ2FBIN(5180, 0), FREQ2FBIN(5220, 0), diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h index 3c533bb..5301df3 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h @@ -236,7 +236,7 @@ struct ar9300_modal_eep_header { u8 thresh62; __le32 papdRateMaskHt20; __le32 papdRateMaskHt40; - u8 futureModal[24]; + u8 futureModal[10]; } __packed; struct ar9300_cal_data_per_freq_op_loop { @@ -274,6 +274,20 @@ struct cal_ctl_data_5g { struct cal_ctl_edge_pwr ctlEdges[AR9300_NUM_BAND_EDGES_5G]; } __packed; +struct ar9300_BaseExtension_1 { + u8 ant_div_control; + u8 future[13]; +} __packed; + +struct ar9300_BaseExtension_2 { + int8_t tempSlopeLow; + int8_t tempSlopeHigh; + u8 xatten1DBLow[AR9300_MAX_CHAINS]; + u8 xatten1MarginLow[AR9300_MAX_CHAINS]; + u8 xatten1DBHigh[AR9300_MAX_CHAINS]; + u8 xatten1MarginHigh[AR9300_MAX_CHAINS]; +} __packed; + struct ar9300_eeprom { u8 eepromVersion; u8 templateVersion; @@ -283,6 +297,7 @@ struct ar9300_eeprom { struct ar9300_base_eep_hdr baseEepHeader; struct ar9300_modal_eep_header modalHeader2G; + struct ar9300_BaseExtension_1 base_ext1; u8 calFreqPier2G[AR9300_NUM_2G_CAL_PIERS]; struct ar9300_cal_data_per_freq_op_loop calPierData2G[AR9300_MAX_CHAINS][AR9300_NUM_2G_CAL_PIERS]; @@ -302,6 +317,7 @@ struct ar9300_eeprom { u8 ctl_freqbin_2G[AR9300_NUM_CTLS_2G][AR9300_NUM_BAND_EDGES_2G]; struct cal_ctl_data_2g ctlPowerData_2G[AR9300_NUM_CTLS_2G]; struct ar9300_modal_eep_header modalHeader5G; + struct ar9300_BaseExtension_2 base_ext2; u8 calFreqPier5G[AR9300_NUM_5G_CAL_PIERS]; struct ar9300_cal_data_per_freq_op_loop calPierData5G[AR9300_MAX_CHAINS][AR9300_NUM_5G_CAL_PIERS]; -- cgit v0.10.2 From ef5a6a7573b7a12ced67dae155be8a909bc245d6 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Wed, 10 Nov 2010 05:03:08 -0800 Subject: ath9k_hw: Initialize 2GHz CTL properly. The last 2GHz CTL was not being initialized, so power was being set to 0 instead of 30dbm. Initialize to 30 like other CTLs. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index bc3f49c..b33fb5b 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -306,6 +306,7 @@ static const struct ar9300_eeprom ar9300_default = { { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, { { {60, 0}, {60, 1}, {60, 1}, {60, 1} } }, + { { {60, 0}, {60, 1}, {60, 1}, {60, 1} } }, }, .modalHeader5G = { /* 4 idle,t1,t2,b (4 bits per setting) */ -- cgit v0.10.2 From 3ceb801bffb62bc486f9662cd4dbca2cbdc6f5c7 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Wed, 10 Nov 2010 05:03:09 -0800 Subject: ath9k_hw: Fix paprd training frame failure. paprd training frame fails in some rates. Fix the rate mask. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index b33fb5b..29a1386 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -144,8 +144,8 @@ static const struct ar9300_eeprom ar9300_default = { .txEndToRxOn = 0x2, .txFrameToXpaOn = 0xe, .thresh62 = 28, - .papdRateMaskHt20 = LE32(0x80c080), - .papdRateMaskHt40 = LE32(0x80c080), + .papdRateMaskHt20 = LE32(0x0cf0e0e0), + .papdRateMaskHt40 = LE32(0x6cf0e0e0), .futureModal = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, @@ -346,8 +346,8 @@ static const struct ar9300_eeprom ar9300_default = { .txEndToRxOn = 0x2, .txFrameToXpaOn = 0xe, .thresh62 = 28, - .papdRateMaskHt20 = LE32(0xf0e0e0), - .papdRateMaskHt40 = LE32(0xf0e0e0), + .papdRateMaskHt20 = LE32(0x0c80c080), + .papdRateMaskHt40 = LE32(0x0080c080), .futureModal = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, -- cgit v0.10.2 From 3092354970381fb8b6439fb4def0c34632277ae9 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Wed, 10 Nov 2010 05:03:10 -0800 Subject: ath9k_hw: add eeprom templates for ar9003 family chipsets We are currently using the default eeprom default and it doesn't work properly for all ar9003 family chipsets. So add eeprom templates for different versisons and select the eeprom table based on the template version programmed in the eeprom. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 29a1386..3d467fc 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -633,6 +633,2338 @@ static const struct ar9300_eeprom ar9300_default = { } }; +static const struct ar9300_eeprom ar9300_x113 = { + .eepromVersion = 2, + .templateVersion = 6, + .macAddr = {0x00, 0x03, 0x7f, 0x0, 0x0, 0x0}, + .custData = {"x113-023-f0000"}, + .baseEepHeader = { + .regDmn = { LE16(0), LE16(0x1f) }, + .txrxMask = 0x77, /* 4 bits tx and 4 bits rx */ + .opCapFlags = { + .opFlags = AR9300_OPFLAGS_11G | AR9300_OPFLAGS_11A, + .eepMisc = 0, + }, + .rfSilent = 0, + .blueToothOptions = 0, + .deviceCap = 0, + .deviceType = 5, /* takes lower byte in eeprom location */ + .pwrTableOffset = AR9300_PWR_TABLE_OFFSET, + .params_for_tuning_caps = {0, 0}, + .featureEnable = 0x0d, + /* + * bit0 - enable tx temp comp - disabled + * bit1 - enable tx volt comp - disabled + * bit2 - enable fastClock - enabled + * bit3 - enable doubling - enabled + * bit4 - enable internal regulator - disabled + * bit5 - enable pa predistortion - disabled + */ + .miscConfiguration = 0, /* bit0 - turn down drivestrength */ + .eepromWriteEnableGpio = 6, + .wlanDisableGpio = 0, + .wlanLedGpio = 8, + .rxBandSelectGpio = 0xff, + .txrxgain = 0x21, + .swreg = 0, + }, + .modalHeader2G = { + /* ar9300_modal_eep_header 2g */ + /* 4 idle,t1,t2,b(4 bits per setting) */ + .antCtrlCommon = LE32(0x110), + /* 4 ra1l1, ra2l1, ra1l2, ra2l2, ra12 */ + .antCtrlCommon2 = LE32(0x44444), + + /* + * antCtrlChain[AR9300_MAX_CHAINS]; 6 idle, t, r, + * rx1, rx12, b (2 bits each) + */ + .antCtrlChain = { LE16(0x150), LE16(0x150), LE16(0x150) }, + + /* + * xatten1DB[AR9300_MAX_CHAINS]; 3 xatten1_db + * for ar9280 (0xa20c/b20c 5:0) + */ + .xatten1DB = {0, 0, 0}, + + /* + * xatten1Margin[AR9300_MAX_CHAINS]; 3 xatten1_margin + * for ar9280 (0xa20c/b20c 16:12 + */ + .xatten1Margin = {0, 0, 0}, + .tempSlope = 25, + .voltSlope = 0, + + /* + * spurChans[OSPREY_EEPROM_MODAL_SPURS]; spur + * channels in usual fbin coding format + */ + .spurChans = {FREQ2FBIN(2464, 1), 0, 0, 0, 0}, + + /* + * noiseFloorThreshCh[AR9300_MAX_CHAINS]; 3 Check + * if the register is per chain + */ + .noiseFloorThreshCh = {-1, 0, 0}, + .ob = {1, 1, 1},/* 3 chain */ + .db_stage2 = {1, 1, 1}, /* 3 chain */ + .db_stage3 = {0, 0, 0}, + .db_stage4 = {0, 0, 0}, + .xpaBiasLvl = 0, + .txFrameToDataStart = 0x0e, + .txFrameToPaOn = 0x0e, + .txClip = 3, /* 4 bits tx_clip, 4 bits dac_scale_cck */ + .antennaGain = 0, + .switchSettling = 0x2c, + .adcDesiredSize = -30, + .txEndToXpaOff = 0, + .txEndToRxOn = 0x2, + .txFrameToXpaOn = 0xe, + .thresh62 = 28, + .papdRateMaskHt20 = LE32(0x0c80c080), + .papdRateMaskHt40 = LE32(0x0080c080), + .futureModal = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }, + }, + .base_ext1 = { + .ant_div_control = 0, + .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + }, + .calFreqPier2G = { + FREQ2FBIN(2412, 1), + FREQ2FBIN(2437, 1), + FREQ2FBIN(2472, 1), + }, + /* ar9300_cal_data_per_freq_op_loop 2g */ + .calPierData2G = { + { {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} }, + { {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} }, + { {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} }, + }, + .calTarget_freqbin_Cck = { + FREQ2FBIN(2412, 1), + FREQ2FBIN(2472, 1), + }, + .calTarget_freqbin_2G = { + FREQ2FBIN(2412, 1), + FREQ2FBIN(2437, 1), + FREQ2FBIN(2472, 1) + }, + .calTarget_freqbin_2GHT20 = { + FREQ2FBIN(2412, 1), + FREQ2FBIN(2437, 1), + FREQ2FBIN(2472, 1) + }, + .calTarget_freqbin_2GHT40 = { + FREQ2FBIN(2412, 1), + FREQ2FBIN(2437, 1), + FREQ2FBIN(2472, 1) + }, + .calTargetPowerCck = { + /* 1L-5L,5S,11L,11S */ + { {34, 34, 34, 34} }, + { {34, 34, 34, 34} }, + }, + .calTargetPower2G = { + /* 6-24,36,48,54 */ + { {34, 34, 32, 32} }, + { {34, 34, 32, 32} }, + { {34, 34, 32, 32} }, + }, + .calTargetPower2GHT20 = { + { {32, 32, 32, 32, 32, 28, 32, 32, 30, 28, 0, 0, 0, 0} }, + { {32, 32, 32, 32, 32, 28, 32, 32, 30, 28, 0, 0, 0, 0} }, + { {32, 32, 32, 32, 32, 28, 32, 32, 30, 28, 0, 0, 0, 0} }, + }, + .calTargetPower2GHT40 = { + { {30, 30, 30, 30, 30, 28, 30, 30, 28, 26, 0, 0, 0, 0} }, + { {30, 30, 30, 30, 30, 28, 30, 30, 28, 26, 0, 0, 0, 0} }, + { {30, 30, 30, 30, 30, 28, 30, 30, 28, 26, 0, 0, 0, 0} }, + }, + .ctlIndex_2G = { + 0x11, 0x12, 0x15, 0x17, 0x41, 0x42, + 0x45, 0x47, 0x31, 0x32, 0x35, 0x37, + }, + .ctl_freqbin_2G = { + { + FREQ2FBIN(2412, 1), + FREQ2FBIN(2417, 1), + FREQ2FBIN(2457, 1), + FREQ2FBIN(2462, 1) + }, + { + FREQ2FBIN(2412, 1), + FREQ2FBIN(2417, 1), + FREQ2FBIN(2462, 1), + 0xFF, + }, + + { + FREQ2FBIN(2412, 1), + FREQ2FBIN(2417, 1), + FREQ2FBIN(2462, 1), + 0xFF, + }, + { + FREQ2FBIN(2422, 1), + FREQ2FBIN(2427, 1), + FREQ2FBIN(2447, 1), + FREQ2FBIN(2452, 1) + }, + + { + /* Data[4].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1), + /* Data[4].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1), + /* Data[4].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1), + /* Data[4].ctlEdges[3].bChannel */ FREQ2FBIN(2484, 1), + }, + + { + /* Data[5].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1), + /* Data[5].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1), + /* Data[5].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1), + 0, + }, + + { + /* Data[6].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1), + /* Data[6].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1), + FREQ2FBIN(2472, 1), + 0, + }, + + { + /* Data[7].ctlEdges[0].bChannel */ FREQ2FBIN(2422, 1), + /* Data[7].ctlEdges[1].bChannel */ FREQ2FBIN(2427, 1), + /* Data[7].ctlEdges[2].bChannel */ FREQ2FBIN(2447, 1), + /* Data[7].ctlEdges[3].bChannel */ FREQ2FBIN(2462, 1), + }, + + { + /* Data[8].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1), + /* Data[8].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1), + /* Data[8].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1), + }, + + { + /* Data[9].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1), + /* Data[9].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1), + /* Data[9].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1), + 0 + }, + + { + /* Data[10].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1), + /* Data[10].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1), + /* Data[10].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1), + 0 + }, + + { + /* Data[11].ctlEdges[0].bChannel */ FREQ2FBIN(2422, 1), + /* Data[11].ctlEdges[1].bChannel */ FREQ2FBIN(2427, 1), + /* Data[11].ctlEdges[2].bChannel */ FREQ2FBIN(2447, 1), + /* Data[11].ctlEdges[3].bChannel */ FREQ2FBIN(2462, 1), + } + }, + .ctlPowerData_2G = { + { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, + { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, + { { {60, 1}, {60, 0}, {60, 0}, {60, 1} } }, + + { { {60, 1}, {60, 0}, {0, 0}, {0, 0} } }, + { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, + { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, + + { { {60, 0}, {60, 1}, {60, 1}, {60, 0} } }, + { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, + { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, + + { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, + { { {60, 0}, {60, 1}, {60, 1}, {60, 1} } }, + { { {60, 0}, {60, 1}, {60, 1}, {60, 1} } }, + }, + .modalHeader5G = { + /* 4 idle,t1,t2,b (4 bits per setting) */ + .antCtrlCommon = LE32(0x220), + /* 4 ra1l1, ra2l1, ra1l2,ra2l2,ra12 */ + .antCtrlCommon2 = LE32(0x11111), + /* antCtrlChain 6 idle, t,r,rx1,rx12,b (2 bits each) */ + .antCtrlChain = { + LE16(0x150), LE16(0x150), LE16(0x150), + }, + /* xatten1DB 3 xatten1_db for AR9280 (0xa20c/b20c 5:0) */ + .xatten1DB = {0, 0, 0}, + + /* + * xatten1Margin[AR9300_MAX_CHAINS]; 3 xatten1_margin + * for merlin (0xa20c/b20c 16:12 + */ + .xatten1Margin = {0, 0, 0}, + .tempSlope = 68, + .voltSlope = 0, + /* spurChans spur channels in usual fbin coding format */ + .spurChans = {FREQ2FBIN(5500, 0), 0, 0, 0, 0}, + /* noiseFloorThreshCh Check if the register is per chain */ + .noiseFloorThreshCh = {-1, 0, 0}, + .ob = {3, 3, 3}, /* 3 chain */ + .db_stage2 = {3, 3, 3}, /* 3 chain */ + .db_stage3 = {3, 3, 3}, /* doesn't exist for 2G */ + .db_stage4 = {3, 3, 3}, /* don't exist for 2G */ + .xpaBiasLvl = 0, + .txFrameToDataStart = 0x0e, + .txFrameToPaOn = 0x0e, + .txClip = 3, /* 4 bits tx_clip, 4 bits dac_scale_cck */ + .antennaGain = 0, + .switchSettling = 0x2d, + .adcDesiredSize = -30, + .txEndToXpaOff = 0, + .txEndToRxOn = 0x2, + .txFrameToXpaOn = 0xe, + .thresh62 = 28, + .papdRateMaskHt20 = LE32(0x0cf0e0e0), + .papdRateMaskHt40 = LE32(0x6cf0e0e0), + .futureModal = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }, + }, + .base_ext2 = { + .tempSlopeLow = 72, + .tempSlopeHigh = 105, + .xatten1DBLow = {0, 0, 0}, + .xatten1MarginLow = {0, 0, 0}, + .xatten1DBHigh = {0, 0, 0}, + .xatten1MarginHigh = {0, 0, 0} + }, + .calFreqPier5G = { + FREQ2FBIN(5180, 0), + FREQ2FBIN(5240, 0), + FREQ2FBIN(5320, 0), + FREQ2FBIN(5400, 0), + FREQ2FBIN(5500, 0), + FREQ2FBIN(5600, 0), + FREQ2FBIN(5745, 0), + FREQ2FBIN(5785, 0) + }, + .calPierData5G = { + { + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + }, + { + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + }, + { + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + }, + + }, + .calTarget_freqbin_5G = { + FREQ2FBIN(5180, 0), + FREQ2FBIN(5220, 0), + FREQ2FBIN(5320, 0), + FREQ2FBIN(5400, 0), + FREQ2FBIN(5500, 0), + FREQ2FBIN(5600, 0), + FREQ2FBIN(5745, 0), + FREQ2FBIN(5785, 0) + }, + .calTarget_freqbin_5GHT20 = { + FREQ2FBIN(5180, 0), + FREQ2FBIN(5240, 0), + FREQ2FBIN(5320, 0), + FREQ2FBIN(5400, 0), + FREQ2FBIN(5500, 0), + FREQ2FBIN(5700, 0), + FREQ2FBIN(5745, 0), + FREQ2FBIN(5825, 0) + }, + .calTarget_freqbin_5GHT40 = { + FREQ2FBIN(5190, 0), + FREQ2FBIN(5230, 0), + FREQ2FBIN(5320, 0), + FREQ2FBIN(5410, 0), + FREQ2FBIN(5510, 0), + FREQ2FBIN(5670, 0), + FREQ2FBIN(5755, 0), + FREQ2FBIN(5825, 0) + }, + .calTargetPower5G = { + /* 6-24,36,48,54 */ + { {42, 40, 40, 34} }, + { {42, 40, 40, 34} }, + { {42, 40, 40, 34} }, + { {42, 40, 40, 34} }, + { {42, 40, 40, 34} }, + { {42, 40, 40, 34} }, + { {42, 40, 40, 34} }, + { {42, 40, 40, 34} }, + }, + .calTargetPower5GHT20 = { + /* + * 0_8_16,1-3_9-11_17-19, + * 4,5,6,7,12,13,14,15,20,21,22,23 + */ + { {40, 40, 40, 40, 32, 28, 40, 40, 32, 28, 40, 40, 32, 20} }, + { {40, 40, 40, 40, 32, 28, 40, 40, 32, 28, 40, 40, 32, 20} }, + { {40, 40, 40, 40, 32, 28, 40, 40, 32, 28, 40, 40, 32, 20} }, + { {40, 40, 40, 40, 32, 28, 40, 40, 32, 28, 40, 40, 32, 20} }, + { {40, 40, 40, 40, 32, 28, 40, 40, 32, 28, 40, 40, 32, 20} }, + { {40, 40, 40, 40, 32, 28, 40, 40, 32, 28, 40, 40, 32, 20} }, + { {38, 38, 38, 38, 32, 28, 38, 38, 32, 28, 38, 38, 32, 26} }, + { {36, 36, 36, 36, 32, 28, 36, 36, 32, 28, 36, 36, 32, 26} }, + }, + .calTargetPower5GHT40 = { + /* + * 0_8_16,1-3_9-11_17-19, + * 4,5,6,7,12,13,14,15,20,21,22,23 + */ + { {40, 40, 40, 38, 30, 26, 40, 40, 30, 26, 40, 40, 30, 24} }, + { {40, 40, 40, 38, 30, 26, 40, 40, 30, 26, 40, 40, 30, 24} }, + { {40, 40, 40, 38, 30, 26, 40, 40, 30, 26, 40, 40, 30, 24} }, + { {40, 40, 40, 38, 30, 26, 40, 40, 30, 26, 40, 40, 30, 24} }, + { {40, 40, 40, 38, 30, 26, 40, 40, 30, 26, 40, 40, 30, 24} }, + { {40, 40, 40, 38, 30, 26, 40, 40, 30, 26, 40, 40, 30, 24} }, + { {36, 36, 36, 36, 30, 26, 36, 36, 30, 26, 36, 36, 30, 24} }, + { {34, 34, 34, 34, 30, 26, 34, 34, 30, 26, 34, 34, 30, 24} }, + }, + .ctlIndex_5G = { + 0x10, 0x16, 0x18, 0x40, 0x46, + 0x48, 0x30, 0x36, 0x38 + }, + .ctl_freqbin_5G = { + { + /* Data[0].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0), + /* Data[0].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0), + /* Data[0].ctlEdges[2].bChannel */ FREQ2FBIN(5280, 0), + /* Data[0].ctlEdges[3].bChannel */ FREQ2FBIN(5500, 0), + /* Data[0].ctlEdges[4].bChannel */ FREQ2FBIN(5600, 0), + /* Data[0].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0), + /* Data[0].ctlEdges[6].bChannel */ FREQ2FBIN(5745, 0), + /* Data[0].ctlEdges[7].bChannel */ FREQ2FBIN(5825, 0) + }, + { + /* Data[1].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0), + /* Data[1].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0), + /* Data[1].ctlEdges[2].bChannel */ FREQ2FBIN(5280, 0), + /* Data[1].ctlEdges[3].bChannel */ FREQ2FBIN(5500, 0), + /* Data[1].ctlEdges[4].bChannel */ FREQ2FBIN(5520, 0), + /* Data[1].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0), + /* Data[1].ctlEdges[6].bChannel */ FREQ2FBIN(5745, 0), + /* Data[1].ctlEdges[7].bChannel */ FREQ2FBIN(5825, 0) + }, + + { + /* Data[2].ctlEdges[0].bChannel */ FREQ2FBIN(5190, 0), + /* Data[2].ctlEdges[1].bChannel */ FREQ2FBIN(5230, 0), + /* Data[2].ctlEdges[2].bChannel */ FREQ2FBIN(5270, 0), + /* Data[2].ctlEdges[3].bChannel */ FREQ2FBIN(5310, 0), + /* Data[2].ctlEdges[4].bChannel */ FREQ2FBIN(5510, 0), + /* Data[2].ctlEdges[5].bChannel */ FREQ2FBIN(5550, 0), + /* Data[2].ctlEdges[6].bChannel */ FREQ2FBIN(5670, 0), + /* Data[2].ctlEdges[7].bChannel */ FREQ2FBIN(5755, 0) + }, + + { + /* Data[3].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0), + /* Data[3].ctlEdges[1].bChannel */ FREQ2FBIN(5200, 0), + /* Data[3].ctlEdges[2].bChannel */ FREQ2FBIN(5260, 0), + /* Data[3].ctlEdges[3].bChannel */ FREQ2FBIN(5320, 0), + /* Data[3].ctlEdges[4].bChannel */ FREQ2FBIN(5500, 0), + /* Data[3].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0), + /* Data[3].ctlEdges[6].bChannel */ 0xFF, + /* Data[3].ctlEdges[7].bChannel */ 0xFF, + }, + + { + /* Data[4].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0), + /* Data[4].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0), + /* Data[4].ctlEdges[2].bChannel */ FREQ2FBIN(5500, 0), + /* Data[4].ctlEdges[3].bChannel */ FREQ2FBIN(5700, 0), + /* Data[4].ctlEdges[4].bChannel */ 0xFF, + /* Data[4].ctlEdges[5].bChannel */ 0xFF, + /* Data[4].ctlEdges[6].bChannel */ 0xFF, + /* Data[4].ctlEdges[7].bChannel */ 0xFF, + }, + + { + /* Data[5].ctlEdges[0].bChannel */ FREQ2FBIN(5190, 0), + /* Data[5].ctlEdges[1].bChannel */ FREQ2FBIN(5270, 0), + /* Data[5].ctlEdges[2].bChannel */ FREQ2FBIN(5310, 0), + /* Data[5].ctlEdges[3].bChannel */ FREQ2FBIN(5510, 0), + /* Data[5].ctlEdges[4].bChannel */ FREQ2FBIN(5590, 0), + /* Data[5].ctlEdges[5].bChannel */ FREQ2FBIN(5670, 0), + /* Data[5].ctlEdges[6].bChannel */ 0xFF, + /* Data[5].ctlEdges[7].bChannel */ 0xFF + }, + + { + /* Data[6].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0), + /* Data[6].ctlEdges[1].bChannel */ FREQ2FBIN(5200, 0), + /* Data[6].ctlEdges[2].bChannel */ FREQ2FBIN(5220, 0), + /* Data[6].ctlEdges[3].bChannel */ FREQ2FBIN(5260, 0), + /* Data[6].ctlEdges[4].bChannel */ FREQ2FBIN(5500, 0), + /* Data[6].ctlEdges[5].bChannel */ FREQ2FBIN(5600, 0), + /* Data[6].ctlEdges[6].bChannel */ FREQ2FBIN(5700, 0), + /* Data[6].ctlEdges[7].bChannel */ FREQ2FBIN(5745, 0) + }, + + { + /* Data[7].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0), + /* Data[7].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0), + /* Data[7].ctlEdges[2].bChannel */ FREQ2FBIN(5320, 0), + /* Data[7].ctlEdges[3].bChannel */ FREQ2FBIN(5500, 0), + /* Data[7].ctlEdges[4].bChannel */ FREQ2FBIN(5560, 0), + /* Data[7].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0), + /* Data[7].ctlEdges[6].bChannel */ FREQ2FBIN(5745, 0), + /* Data[7].ctlEdges[7].bChannel */ FREQ2FBIN(5825, 0) + }, + + { + /* Data[8].ctlEdges[0].bChannel */ FREQ2FBIN(5190, 0), + /* Data[8].ctlEdges[1].bChannel */ FREQ2FBIN(5230, 0), + /* Data[8].ctlEdges[2].bChannel */ FREQ2FBIN(5270, 0), + /* Data[8].ctlEdges[3].bChannel */ FREQ2FBIN(5510, 0), + /* Data[8].ctlEdges[4].bChannel */ FREQ2FBIN(5550, 0), + /* Data[8].ctlEdges[5].bChannel */ FREQ2FBIN(5670, 0), + /* Data[8].ctlEdges[6].bChannel */ FREQ2FBIN(5755, 0), + /* Data[8].ctlEdges[7].bChannel */ FREQ2FBIN(5795, 0) + } + }, + .ctlPowerData_5G = { + { + { + {60, 1}, {60, 1}, {60, 1}, {60, 1}, + {60, 1}, {60, 1}, {60, 1}, {60, 0}, + } + }, + { + { + {60, 1}, {60, 1}, {60, 1}, {60, 1}, + {60, 1}, {60, 1}, {60, 1}, {60, 0}, + } + }, + { + { + {60, 0}, {60, 1}, {60, 0}, {60, 1}, + {60, 1}, {60, 1}, {60, 1}, {60, 1}, + } + }, + { + { + {60, 0}, {60, 1}, {60, 1}, {60, 0}, + {60, 1}, {60, 0}, {60, 0}, {60, 0}, + } + }, + { + { + {60, 1}, {60, 1}, {60, 1}, {60, 0}, + {60, 0}, {60, 0}, {60, 0}, {60, 0}, + } + }, + { + { + {60, 1}, {60, 1}, {60, 1}, {60, 1}, + {60, 1}, {60, 0}, {60, 0}, {60, 0}, + } + }, + { + { + {60, 1}, {60, 1}, {60, 1}, {60, 1}, + {60, 1}, {60, 1}, {60, 1}, {60, 1}, + } + }, + { + { + {60, 1}, {60, 1}, {60, 0}, {60, 1}, + {60, 1}, {60, 1}, {60, 1}, {60, 0}, + } + }, + { + { + {60, 1}, {60, 0}, {60, 1}, {60, 1}, + {60, 1}, {60, 1}, {60, 0}, {60, 1}, + } + }, + } +}; + + +static const struct ar9300_eeprom ar9300_h112 = { + .eepromVersion = 2, + .templateVersion = 3, + .macAddr = {0x00, 0x03, 0x7f, 0x0, 0x0, 0x0}, + .custData = {"h112-241-f0000"}, + .baseEepHeader = { + .regDmn = { LE16(0), LE16(0x1f) }, + .txrxMask = 0x77, /* 4 bits tx and 4 bits rx */ + .opCapFlags = { + .opFlags = AR9300_OPFLAGS_11G | AR9300_OPFLAGS_11A, + .eepMisc = 0, + }, + .rfSilent = 0, + .blueToothOptions = 0, + .deviceCap = 0, + .deviceType = 5, /* takes lower byte in eeprom location */ + .pwrTableOffset = AR9300_PWR_TABLE_OFFSET, + .params_for_tuning_caps = {0, 0}, + .featureEnable = 0x0d, + /* + * bit0 - enable tx temp comp - disabled + * bit1 - enable tx volt comp - disabled + * bit2 - enable fastClock - enabled + * bit3 - enable doubling - enabled + * bit4 - enable internal regulator - disabled + * bit5 - enable pa predistortion - disabled + */ + .miscConfiguration = 0, /* bit0 - turn down drivestrength */ + .eepromWriteEnableGpio = 6, + .wlanDisableGpio = 0, + .wlanLedGpio = 8, + .rxBandSelectGpio = 0xff, + .txrxgain = 0x10, + .swreg = 0, + }, + .modalHeader2G = { + /* ar9300_modal_eep_header 2g */ + /* 4 idle,t1,t2,b(4 bits per setting) */ + .antCtrlCommon = LE32(0x110), + /* 4 ra1l1, ra2l1, ra1l2, ra2l2, ra12 */ + .antCtrlCommon2 = LE32(0x44444), + + /* + * antCtrlChain[AR9300_MAX_CHAINS]; 6 idle, t, r, + * rx1, rx12, b (2 bits each) + */ + .antCtrlChain = { LE16(0x150), LE16(0x150), LE16(0x150) }, + + /* + * xatten1DB[AR9300_MAX_CHAINS]; 3 xatten1_db + * for ar9280 (0xa20c/b20c 5:0) + */ + .xatten1DB = {0, 0, 0}, + + /* + * xatten1Margin[AR9300_MAX_CHAINS]; 3 xatten1_margin + * for ar9280 (0xa20c/b20c 16:12 + */ + .xatten1Margin = {0, 0, 0}, + .tempSlope = 25, + .voltSlope = 0, + + /* + * spurChans[OSPREY_EEPROM_MODAL_SPURS]; spur + * channels in usual fbin coding format + */ + .spurChans = {FREQ2FBIN(2464, 1), 0, 0, 0, 0}, + + /* + * noiseFloorThreshCh[AR9300_MAX_CHAINS]; 3 Check + * if the register is per chain + */ + .noiseFloorThreshCh = {-1, 0, 0}, + .ob = {1, 1, 1},/* 3 chain */ + .db_stage2 = {1, 1, 1}, /* 3 chain */ + .db_stage3 = {0, 0, 0}, + .db_stage4 = {0, 0, 0}, + .xpaBiasLvl = 0, + .txFrameToDataStart = 0x0e, + .txFrameToPaOn = 0x0e, + .txClip = 3, /* 4 bits tx_clip, 4 bits dac_scale_cck */ + .antennaGain = 0, + .switchSettling = 0x2c, + .adcDesiredSize = -30, + .txEndToXpaOff = 0, + .txEndToRxOn = 0x2, + .txFrameToXpaOn = 0xe, + .thresh62 = 28, + .papdRateMaskHt20 = LE32(0x80c080), + .papdRateMaskHt40 = LE32(0x80c080), + .futureModal = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }, + }, + .base_ext1 = { + .ant_div_control = 0, + .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + }, + .calFreqPier2G = { + FREQ2FBIN(2412, 1), + FREQ2FBIN(2437, 1), + FREQ2FBIN(2472, 1), + }, + /* ar9300_cal_data_per_freq_op_loop 2g */ + .calPierData2G = { + { {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} }, + { {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} }, + { {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} }, + }, + .calTarget_freqbin_Cck = { + FREQ2FBIN(2412, 1), + FREQ2FBIN(2484, 1), + }, + .calTarget_freqbin_2G = { + FREQ2FBIN(2412, 1), + FREQ2FBIN(2437, 1), + FREQ2FBIN(2472, 1) + }, + .calTarget_freqbin_2GHT20 = { + FREQ2FBIN(2412, 1), + FREQ2FBIN(2437, 1), + FREQ2FBIN(2472, 1) + }, + .calTarget_freqbin_2GHT40 = { + FREQ2FBIN(2412, 1), + FREQ2FBIN(2437, 1), + FREQ2FBIN(2472, 1) + }, + .calTargetPowerCck = { + /* 1L-5L,5S,11L,11S */ + { {34, 34, 34, 34} }, + { {34, 34, 34, 34} }, + }, + .calTargetPower2G = { + /* 6-24,36,48,54 */ + { {34, 34, 32, 32} }, + { {34, 34, 32, 32} }, + { {34, 34, 32, 32} }, + }, + .calTargetPower2GHT20 = { + { {32, 32, 32, 32, 32, 30, 32, 32, 30, 28, 28, 28, 28, 24} }, + { {32, 32, 32, 32, 32, 30, 32, 32, 30, 28, 28, 28, 28, 24} }, + { {32, 32, 32, 32, 32, 30, 32, 32, 30, 28, 28, 28, 28, 24} }, + }, + .calTargetPower2GHT40 = { + { {30, 30, 30, 30, 30, 28, 30, 30, 28, 26, 26, 26, 26, 22} }, + { {30, 30, 30, 30, 30, 28, 30, 30, 28, 26, 26, 26, 26, 22} }, + { {30, 30, 30, 30, 30, 28, 30, 30, 28, 26, 26, 26, 26, 22} }, + }, + .ctlIndex_2G = { + 0x11, 0x12, 0x15, 0x17, 0x41, 0x42, + 0x45, 0x47, 0x31, 0x32, 0x35, 0x37, + }, + .ctl_freqbin_2G = { + { + FREQ2FBIN(2412, 1), + FREQ2FBIN(2417, 1), + FREQ2FBIN(2457, 1), + FREQ2FBIN(2462, 1) + }, + { + FREQ2FBIN(2412, 1), + FREQ2FBIN(2417, 1), + FREQ2FBIN(2462, 1), + 0xFF, + }, + + { + FREQ2FBIN(2412, 1), + FREQ2FBIN(2417, 1), + FREQ2FBIN(2462, 1), + 0xFF, + }, + { + FREQ2FBIN(2422, 1), + FREQ2FBIN(2427, 1), + FREQ2FBIN(2447, 1), + FREQ2FBIN(2452, 1) + }, + + { + /* Data[4].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1), + /* Data[4].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1), + /* Data[4].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1), + /* Data[4].ctlEdges[3].bChannel */ FREQ2FBIN(2484, 1), + }, + + { + /* Data[5].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1), + /* Data[5].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1), + /* Data[5].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1), + 0, + }, + + { + /* Data[6].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1), + /* Data[6].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1), + FREQ2FBIN(2472, 1), + 0, + }, + + { + /* Data[7].ctlEdges[0].bChannel */ FREQ2FBIN(2422, 1), + /* Data[7].ctlEdges[1].bChannel */ FREQ2FBIN(2427, 1), + /* Data[7].ctlEdges[2].bChannel */ FREQ2FBIN(2447, 1), + /* Data[7].ctlEdges[3].bChannel */ FREQ2FBIN(2462, 1), + }, + + { + /* Data[8].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1), + /* Data[8].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1), + /* Data[8].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1), + }, + + { + /* Data[9].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1), + /* Data[9].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1), + /* Data[9].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1), + 0 + }, + + { + /* Data[10].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1), + /* Data[10].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1), + /* Data[10].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1), + 0 + }, + + { + /* Data[11].ctlEdges[0].bChannel */ FREQ2FBIN(2422, 1), + /* Data[11].ctlEdges[1].bChannel */ FREQ2FBIN(2427, 1), + /* Data[11].ctlEdges[2].bChannel */ FREQ2FBIN(2447, 1), + /* Data[11].ctlEdges[3].bChannel */ FREQ2FBIN(2462, 1), + } + }, + .ctlPowerData_2G = { + { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, + { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, + { { {60, 1}, {60, 0}, {60, 0}, {60, 1} } }, + + { { {60, 1}, {60, 0}, {0, 0}, {0, 0} } }, + { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, + { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, + + { { {60, 0}, {60, 1}, {60, 1}, {60, 0} } }, + { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, + { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, + + { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, + { { {60, 0}, {60, 1}, {60, 1}, {60, 1} } }, + { { {60, 0}, {60, 1}, {60, 1}, {60, 1} } }, + }, + .modalHeader5G = { + /* 4 idle,t1,t2,b (4 bits per setting) */ + .antCtrlCommon = LE32(0x220), + /* 4 ra1l1, ra2l1, ra1l2,ra2l2,ra12 */ + .antCtrlCommon2 = LE32(0x44444), + /* antCtrlChain 6 idle, t,r,rx1,rx12,b (2 bits each) */ + .antCtrlChain = { + LE16(0x150), LE16(0x150), LE16(0x150), + }, + /* xatten1DB 3 xatten1_db for AR9280 (0xa20c/b20c 5:0) */ + .xatten1DB = {0, 0, 0}, + + /* + * xatten1Margin[AR9300_MAX_CHAINS]; 3 xatten1_margin + * for merlin (0xa20c/b20c 16:12 + */ + .xatten1Margin = {0, 0, 0}, + .tempSlope = 45, + .voltSlope = 0, + /* spurChans spur channels in usual fbin coding format */ + .spurChans = {0, 0, 0, 0, 0}, + /* noiseFloorThreshCh Check if the register is per chain */ + .noiseFloorThreshCh = {-1, 0, 0}, + .ob = {3, 3, 3}, /* 3 chain */ + .db_stage2 = {3, 3, 3}, /* 3 chain */ + .db_stage3 = {3, 3, 3}, /* doesn't exist for 2G */ + .db_stage4 = {3, 3, 3}, /* don't exist for 2G */ + .xpaBiasLvl = 0, + .txFrameToDataStart = 0x0e, + .txFrameToPaOn = 0x0e, + .txClip = 3, /* 4 bits tx_clip, 4 bits dac_scale_cck */ + .antennaGain = 0, + .switchSettling = 0x2d, + .adcDesiredSize = -30, + .txEndToXpaOff = 0, + .txEndToRxOn = 0x2, + .txFrameToXpaOn = 0xe, + .thresh62 = 28, + .papdRateMaskHt20 = LE32(0x0cf0e0e0), + .papdRateMaskHt40 = LE32(0x6cf0e0e0), + .futureModal = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }, + }, + .base_ext2 = { + .tempSlopeLow = 40, + .tempSlopeHigh = 50, + .xatten1DBLow = {0, 0, 0}, + .xatten1MarginLow = {0, 0, 0}, + .xatten1DBHigh = {0, 0, 0}, + .xatten1MarginHigh = {0, 0, 0} + }, + .calFreqPier5G = { + FREQ2FBIN(5180, 0), + FREQ2FBIN(5220, 0), + FREQ2FBIN(5320, 0), + FREQ2FBIN(5400, 0), + FREQ2FBIN(5500, 0), + FREQ2FBIN(5600, 0), + FREQ2FBIN(5700, 0), + FREQ2FBIN(5825, 0) + }, + .calPierData5G = { + { + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + }, + { + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + }, + { + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + }, + + }, + .calTarget_freqbin_5G = { + FREQ2FBIN(5180, 0), + FREQ2FBIN(5240, 0), + FREQ2FBIN(5320, 0), + FREQ2FBIN(5400, 0), + FREQ2FBIN(5500, 0), + FREQ2FBIN(5600, 0), + FREQ2FBIN(5700, 0), + FREQ2FBIN(5825, 0) + }, + .calTarget_freqbin_5GHT20 = { + FREQ2FBIN(5180, 0), + FREQ2FBIN(5240, 0), + FREQ2FBIN(5320, 0), + FREQ2FBIN(5400, 0), + FREQ2FBIN(5500, 0), + FREQ2FBIN(5700, 0), + FREQ2FBIN(5745, 0), + FREQ2FBIN(5825, 0) + }, + .calTarget_freqbin_5GHT40 = { + FREQ2FBIN(5180, 0), + FREQ2FBIN(5240, 0), + FREQ2FBIN(5320, 0), + FREQ2FBIN(5400, 0), + FREQ2FBIN(5500, 0), + FREQ2FBIN(5700, 0), + FREQ2FBIN(5745, 0), + FREQ2FBIN(5825, 0) + }, + .calTargetPower5G = { + /* 6-24,36,48,54 */ + { {30, 30, 28, 24} }, + { {30, 30, 28, 24} }, + { {30, 30, 28, 24} }, + { {30, 30, 28, 24} }, + { {30, 30, 28, 24} }, + { {30, 30, 28, 24} }, + { {30, 30, 28, 24} }, + { {30, 30, 28, 24} }, + }, + .calTargetPower5GHT20 = { + /* + * 0_8_16,1-3_9-11_17-19, + * 4,5,6,7,12,13,14,15,20,21,22,23 + */ + { {30, 30, 30, 28, 24, 20, 30, 28, 24, 20, 20, 20, 20, 16} }, + { {30, 30, 30, 28, 24, 20, 30, 28, 24, 20, 20, 20, 20, 16} }, + { {30, 30, 30, 26, 22, 18, 30, 26, 22, 18, 18, 18, 18, 16} }, + { {30, 30, 30, 26, 22, 18, 30, 26, 22, 18, 18, 18, 18, 16} }, + { {30, 30, 30, 24, 20, 16, 30, 24, 20, 16, 16, 16, 16, 14} }, + { {30, 30, 30, 24, 20, 16, 30, 24, 20, 16, 16, 16, 16, 14} }, + { {30, 30, 30, 22, 18, 14, 30, 22, 18, 14, 14, 14, 14, 12} }, + { {30, 30, 30, 22, 18, 14, 30, 22, 18, 14, 14, 14, 14, 12} }, + }, + .calTargetPower5GHT40 = { + /* + * 0_8_16,1-3_9-11_17-19, + * 4,5,6,7,12,13,14,15,20,21,22,23 + */ + { {28, 28, 28, 26, 22, 18, 28, 26, 22, 18, 18, 18, 18, 14} }, + { {28, 28, 28, 26, 22, 18, 28, 26, 22, 18, 18, 18, 18, 14} }, + { {28, 28, 28, 24, 20, 16, 28, 24, 20, 16, 16, 16, 16, 12} }, + { {28, 28, 28, 24, 20, 16, 28, 24, 20, 16, 16, 16, 16, 12} }, + { {28, 28, 28, 22, 18, 14, 28, 22, 18, 14, 14, 14, 14, 10} }, + { {28, 28, 28, 22, 18, 14, 28, 22, 18, 14, 14, 14, 14, 10} }, + { {28, 28, 28, 20, 16, 12, 28, 20, 16, 12, 12, 12, 12, 8} }, + { {28, 28, 28, 20, 16, 12, 28, 20, 16, 12, 12, 12, 12, 8} }, + }, + .ctlIndex_5G = { + 0x10, 0x16, 0x18, 0x40, 0x46, + 0x48, 0x30, 0x36, 0x38 + }, + .ctl_freqbin_5G = { + { + /* Data[0].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0), + /* Data[0].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0), + /* Data[0].ctlEdges[2].bChannel */ FREQ2FBIN(5280, 0), + /* Data[0].ctlEdges[3].bChannel */ FREQ2FBIN(5500, 0), + /* Data[0].ctlEdges[4].bChannel */ FREQ2FBIN(5600, 0), + /* Data[0].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0), + /* Data[0].ctlEdges[6].bChannel */ FREQ2FBIN(5745, 0), + /* Data[0].ctlEdges[7].bChannel */ FREQ2FBIN(5825, 0) + }, + { + /* Data[1].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0), + /* Data[1].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0), + /* Data[1].ctlEdges[2].bChannel */ FREQ2FBIN(5280, 0), + /* Data[1].ctlEdges[3].bChannel */ FREQ2FBIN(5500, 0), + /* Data[1].ctlEdges[4].bChannel */ FREQ2FBIN(5520, 0), + /* Data[1].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0), + /* Data[1].ctlEdges[6].bChannel */ FREQ2FBIN(5745, 0), + /* Data[1].ctlEdges[7].bChannel */ FREQ2FBIN(5825, 0) + }, + + { + /* Data[2].ctlEdges[0].bChannel */ FREQ2FBIN(5190, 0), + /* Data[2].ctlEdges[1].bChannel */ FREQ2FBIN(5230, 0), + /* Data[2].ctlEdges[2].bChannel */ FREQ2FBIN(5270, 0), + /* Data[2].ctlEdges[3].bChannel */ FREQ2FBIN(5310, 0), + /* Data[2].ctlEdges[4].bChannel */ FREQ2FBIN(5510, 0), + /* Data[2].ctlEdges[5].bChannel */ FREQ2FBIN(5550, 0), + /* Data[2].ctlEdges[6].bChannel */ FREQ2FBIN(5670, 0), + /* Data[2].ctlEdges[7].bChannel */ FREQ2FBIN(5755, 0) + }, + + { + /* Data[3].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0), + /* Data[3].ctlEdges[1].bChannel */ FREQ2FBIN(5200, 0), + /* Data[3].ctlEdges[2].bChannel */ FREQ2FBIN(5260, 0), + /* Data[3].ctlEdges[3].bChannel */ FREQ2FBIN(5320, 0), + /* Data[3].ctlEdges[4].bChannel */ FREQ2FBIN(5500, 0), + /* Data[3].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0), + /* Data[3].ctlEdges[6].bChannel */ 0xFF, + /* Data[3].ctlEdges[7].bChannel */ 0xFF, + }, + + { + /* Data[4].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0), + /* Data[4].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0), + /* Data[4].ctlEdges[2].bChannel */ FREQ2FBIN(5500, 0), + /* Data[4].ctlEdges[3].bChannel */ FREQ2FBIN(5700, 0), + /* Data[4].ctlEdges[4].bChannel */ 0xFF, + /* Data[4].ctlEdges[5].bChannel */ 0xFF, + /* Data[4].ctlEdges[6].bChannel */ 0xFF, + /* Data[4].ctlEdges[7].bChannel */ 0xFF, + }, + + { + /* Data[5].ctlEdges[0].bChannel */ FREQ2FBIN(5190, 0), + /* Data[5].ctlEdges[1].bChannel */ FREQ2FBIN(5270, 0), + /* Data[5].ctlEdges[2].bChannel */ FREQ2FBIN(5310, 0), + /* Data[5].ctlEdges[3].bChannel */ FREQ2FBIN(5510, 0), + /* Data[5].ctlEdges[4].bChannel */ FREQ2FBIN(5590, 0), + /* Data[5].ctlEdges[5].bChannel */ FREQ2FBIN(5670, 0), + /* Data[5].ctlEdges[6].bChannel */ 0xFF, + /* Data[5].ctlEdges[7].bChannel */ 0xFF + }, + + { + /* Data[6].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0), + /* Data[6].ctlEdges[1].bChannel */ FREQ2FBIN(5200, 0), + /* Data[6].ctlEdges[2].bChannel */ FREQ2FBIN(5220, 0), + /* Data[6].ctlEdges[3].bChannel */ FREQ2FBIN(5260, 0), + /* Data[6].ctlEdges[4].bChannel */ FREQ2FBIN(5500, 0), + /* Data[6].ctlEdges[5].bChannel */ FREQ2FBIN(5600, 0), + /* Data[6].ctlEdges[6].bChannel */ FREQ2FBIN(5700, 0), + /* Data[6].ctlEdges[7].bChannel */ FREQ2FBIN(5745, 0) + }, + + { + /* Data[7].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0), + /* Data[7].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0), + /* Data[7].ctlEdges[2].bChannel */ FREQ2FBIN(5320, 0), + /* Data[7].ctlEdges[3].bChannel */ FREQ2FBIN(5500, 0), + /* Data[7].ctlEdges[4].bChannel */ FREQ2FBIN(5560, 0), + /* Data[7].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0), + /* Data[7].ctlEdges[6].bChannel */ FREQ2FBIN(5745, 0), + /* Data[7].ctlEdges[7].bChannel */ FREQ2FBIN(5825, 0) + }, + + { + /* Data[8].ctlEdges[0].bChannel */ FREQ2FBIN(5190, 0), + /* Data[8].ctlEdges[1].bChannel */ FREQ2FBIN(5230, 0), + /* Data[8].ctlEdges[2].bChannel */ FREQ2FBIN(5270, 0), + /* Data[8].ctlEdges[3].bChannel */ FREQ2FBIN(5510, 0), + /* Data[8].ctlEdges[4].bChannel */ FREQ2FBIN(5550, 0), + /* Data[8].ctlEdges[5].bChannel */ FREQ2FBIN(5670, 0), + /* Data[8].ctlEdges[6].bChannel */ FREQ2FBIN(5755, 0), + /* Data[8].ctlEdges[7].bChannel */ FREQ2FBIN(5795, 0) + } + }, + .ctlPowerData_5G = { + { + { + {60, 1}, {60, 1}, {60, 1}, {60, 1}, + {60, 1}, {60, 1}, {60, 1}, {60, 0}, + } + }, + { + { + {60, 1}, {60, 1}, {60, 1}, {60, 1}, + {60, 1}, {60, 1}, {60, 1}, {60, 0}, + } + }, + { + { + {60, 0}, {60, 1}, {60, 0}, {60, 1}, + {60, 1}, {60, 1}, {60, 1}, {60, 1}, + } + }, + { + { + {60, 0}, {60, 1}, {60, 1}, {60, 0}, + {60, 1}, {60, 0}, {60, 0}, {60, 0}, + } + }, + { + { + {60, 1}, {60, 1}, {60, 1}, {60, 0}, + {60, 0}, {60, 0}, {60, 0}, {60, 0}, + } + }, + { + { + {60, 1}, {60, 1}, {60, 1}, {60, 1}, + {60, 1}, {60, 0}, {60, 0}, {60, 0}, + } + }, + { + { + {60, 1}, {60, 1}, {60, 1}, {60, 1}, + {60, 1}, {60, 1}, {60, 1}, {60, 1}, + } + }, + { + { + {60, 1}, {60, 1}, {60, 0}, {60, 1}, + {60, 1}, {60, 1}, {60, 1}, {60, 0}, + } + }, + { + { + {60, 1}, {60, 0}, {60, 1}, {60, 1}, + {60, 1}, {60, 1}, {60, 0}, {60, 1}, + } + }, + } +}; + + +static const struct ar9300_eeprom ar9300_x112 = { + .eepromVersion = 2, + .templateVersion = 5, + .macAddr = {0x00, 0x03, 0x7f, 0x0, 0x0, 0x0}, + .custData = {"x112-041-f0000"}, + .baseEepHeader = { + .regDmn = { LE16(0), LE16(0x1f) }, + .txrxMask = 0x77, /* 4 bits tx and 4 bits rx */ + .opCapFlags = { + .opFlags = AR9300_OPFLAGS_11G | AR9300_OPFLAGS_11A, + .eepMisc = 0, + }, + .rfSilent = 0, + .blueToothOptions = 0, + .deviceCap = 0, + .deviceType = 5, /* takes lower byte in eeprom location */ + .pwrTableOffset = AR9300_PWR_TABLE_OFFSET, + .params_for_tuning_caps = {0, 0}, + .featureEnable = 0x0d, + /* + * bit0 - enable tx temp comp - disabled + * bit1 - enable tx volt comp - disabled + * bit2 - enable fastclock - enabled + * bit3 - enable doubling - enabled + * bit4 - enable internal regulator - disabled + * bit5 - enable pa predistortion - disabled + */ + .miscConfiguration = 0, /* bit0 - turn down drivestrength */ + .eepromWriteEnableGpio = 6, + .wlanDisableGpio = 0, + .wlanLedGpio = 8, + .rxBandSelectGpio = 0xff, + .txrxgain = 0x0, + .swreg = 0, + }, + .modalHeader2G = { + /* ar9300_modal_eep_header 2g */ + /* 4 idle,t1,t2,b(4 bits per setting) */ + .antCtrlCommon = LE32(0x110), + /* 4 ra1l1, ra2l1, ra1l2, ra2l2, ra12 */ + .antCtrlCommon2 = LE32(0x22222), + + /* + * antCtrlChain[ar9300_max_chains]; 6 idle, t, r, + * rx1, rx12, b (2 bits each) + */ + .antCtrlChain = { LE16(0x10), LE16(0x10), LE16(0x10) }, + + /* + * xatten1DB[AR9300_max_chains]; 3 xatten1_db + * for ar9280 (0xa20c/b20c 5:0) + */ + .xatten1DB = {0x1b, 0x1b, 0x1b}, + + /* + * xatten1Margin[ar9300_max_chains]; 3 xatten1_margin + * for ar9280 (0xa20c/b20c 16:12 + */ + .xatten1Margin = {0x15, 0x15, 0x15}, + .tempSlope = 50, + .voltSlope = 0, + + /* + * spurChans[OSPrey_eeprom_modal_sPURS]; spur + * channels in usual fbin coding format + */ + .spurChans = {FREQ2FBIN(2464, 1), 0, 0, 0, 0}, + + /* + * noiseFloorThreshch[ar9300_max_cHAINS]; 3 Check + * if the register is per chain + */ + .noiseFloorThreshCh = {-1, 0, 0}, + .ob = {1, 1, 1},/* 3 chain */ + .db_stage2 = {1, 1, 1}, /* 3 chain */ + .db_stage3 = {0, 0, 0}, + .db_stage4 = {0, 0, 0}, + .xpaBiasLvl = 0, + .txFrameToDataStart = 0x0e, + .txFrameToPaOn = 0x0e, + .txClip = 3, /* 4 bits tx_clip, 4 bits dac_scale_cck */ + .antennaGain = 0, + .switchSettling = 0x2c, + .adcDesiredSize = -30, + .txEndToXpaOff = 0, + .txEndToRxOn = 0x2, + .txFrameToXpaOn = 0xe, + .thresh62 = 28, + .papdRateMaskHt20 = LE32(0x0c80c080), + .papdRateMaskHt40 = LE32(0x0080c080), + .futureModal = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }, + }, + .base_ext1 = { + .ant_div_control = 0, + .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + }, + .calFreqPier2G = { + FREQ2FBIN(2412, 1), + FREQ2FBIN(2437, 1), + FREQ2FBIN(2472, 1), + }, + /* ar9300_cal_data_per_freq_op_loop 2g */ + .calPierData2G = { + { {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} }, + { {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} }, + { {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} }, + }, + .calTarget_freqbin_Cck = { + FREQ2FBIN(2412, 1), + FREQ2FBIN(2472, 1), + }, + .calTarget_freqbin_2G = { + FREQ2FBIN(2412, 1), + FREQ2FBIN(2437, 1), + FREQ2FBIN(2472, 1) + }, + .calTarget_freqbin_2GHT20 = { + FREQ2FBIN(2412, 1), + FREQ2FBIN(2437, 1), + FREQ2FBIN(2472, 1) + }, + .calTarget_freqbin_2GHT40 = { + FREQ2FBIN(2412, 1), + FREQ2FBIN(2437, 1), + FREQ2FBIN(2472, 1) + }, + .calTargetPowerCck = { + /* 1L-5L,5S,11L,11s */ + { {38, 38, 38, 38} }, + { {38, 38, 38, 38} }, + }, + .calTargetPower2G = { + /* 6-24,36,48,54 */ + { {38, 38, 36, 34} }, + { {38, 38, 36, 34} }, + { {38, 38, 34, 32} }, + }, + .calTargetPower2GHT20 = { + { {36, 36, 36, 36, 36, 34, 34, 32, 30, 28, 28, 28, 28, 26} }, + { {36, 36, 36, 36, 36, 34, 36, 34, 32, 30, 30, 30, 28, 26} }, + { {36, 36, 36, 36, 36, 34, 34, 32, 30, 28, 28, 28, 28, 26} }, + }, + .calTargetPower2GHT40 = { + { {36, 36, 36, 36, 34, 32, 32, 30, 28, 26, 26, 26, 26, 24} }, + { {36, 36, 36, 36, 34, 32, 34, 32, 30, 28, 28, 28, 28, 24} }, + { {36, 36, 36, 36, 34, 32, 32, 30, 28, 26, 26, 26, 26, 24} }, + }, + .ctlIndex_2G = { + 0x11, 0x12, 0x15, 0x17, 0x41, 0x42, + 0x45, 0x47, 0x31, 0x32, 0x35, 0x37, + }, + .ctl_freqbin_2G = { + { + FREQ2FBIN(2412, 1), + FREQ2FBIN(2417, 1), + FREQ2FBIN(2457, 1), + FREQ2FBIN(2462, 1) + }, + { + FREQ2FBIN(2412, 1), + FREQ2FBIN(2417, 1), + FREQ2FBIN(2462, 1), + 0xFF, + }, + + { + FREQ2FBIN(2412, 1), + FREQ2FBIN(2417, 1), + FREQ2FBIN(2462, 1), + 0xFF, + }, + { + FREQ2FBIN(2422, 1), + FREQ2FBIN(2427, 1), + FREQ2FBIN(2447, 1), + FREQ2FBIN(2452, 1) + }, + + { + /* Data[4].ctledges[0].bchannel */ FREQ2FBIN(2412, 1), + /* Data[4].ctledges[1].bchannel */ FREQ2FBIN(2417, 1), + /* Data[4].ctledges[2].bchannel */ FREQ2FBIN(2472, 1), + /* Data[4].ctledges[3].bchannel */ FREQ2FBIN(2484, 1), + }, + + { + /* Data[5].ctledges[0].bchannel */ FREQ2FBIN(2412, 1), + /* Data[5].ctledges[1].bchannel */ FREQ2FBIN(2417, 1), + /* Data[5].ctledges[2].bchannel */ FREQ2FBIN(2472, 1), + 0, + }, + + { + /* Data[6].ctledges[0].bchannel */ FREQ2FBIN(2412, 1), + /* Data[6].ctledges[1].bchannel */ FREQ2FBIN(2417, 1), + FREQ2FBIN(2472, 1), + 0, + }, + + { + /* Data[7].ctledges[0].bchannel */ FREQ2FBIN(2422, 1), + /* Data[7].ctledges[1].bchannel */ FREQ2FBIN(2427, 1), + /* Data[7].ctledges[2].bchannel */ FREQ2FBIN(2447, 1), + /* Data[7].ctledges[3].bchannel */ FREQ2FBIN(2462, 1), + }, + + { + /* Data[8].ctledges[0].bchannel */ FREQ2FBIN(2412, 1), + /* Data[8].ctledges[1].bchannel */ FREQ2FBIN(2417, 1), + /* Data[8].ctledges[2].bchannel */ FREQ2FBIN(2472, 1), + }, + + { + /* Data[9].ctledges[0].bchannel */ FREQ2FBIN(2412, 1), + /* Data[9].ctledges[1].bchannel */ FREQ2FBIN(2417, 1), + /* Data[9].ctledges[2].bchannel */ FREQ2FBIN(2472, 1), + 0 + }, + + { + /* Data[10].ctledges[0].bchannel */ FREQ2FBIN(2412, 1), + /* Data[10].ctledges[1].bchannel */ FREQ2FBIN(2417, 1), + /* Data[10].ctledges[2].bchannel */ FREQ2FBIN(2472, 1), + 0 + }, + + { + /* Data[11].ctledges[0].bchannel */ FREQ2FBIN(2422, 1), + /* Data[11].ctledges[1].bchannel */ FREQ2FBIN(2427, 1), + /* Data[11].ctledges[2].bchannel */ FREQ2FBIN(2447, 1), + /* Data[11].ctledges[3].bchannel */ FREQ2FBIN(2462, 1), + } + }, + .ctlPowerData_2G = { + { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, + { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, + { { {60, 1}, {60, 0}, {60, 0}, {60, 1} } }, + + { { {60, 1}, {60, 0}, {0, 0}, {0, 0} } }, + { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, + { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, + + { { {60, 0}, {60, 1}, {60, 1}, {60, 0} } }, + { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, + { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, + + { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, + { { {60, 0}, {60, 1}, {60, 1}, {60, 1} } }, + { { {60, 0}, {60, 1}, {60, 1}, {60, 1} } }, + }, + .modalHeader5G = { + /* 4 idle,t1,t2,b (4 bits per setting) */ + .antCtrlCommon = LE32(0x110), + /* 4 ra1l1, ra2l1, ra1l2,ra2l2,ra12 */ + .antCtrlCommon2 = LE32(0x22222), + /* antCtrlChain 6 idle, t,r,rx1,rx12,b (2 bits each) */ + .antCtrlChain = { + LE16(0x0), LE16(0x0), LE16(0x0), + }, + /* xatten1DB 3 xatten1_db for ar9280 (0xa20c/b20c 5:0) */ + .xatten1DB = {0x13, 0x19, 0x17}, + + /* + * xatten1Margin[ar9300_max_chains]; 3 xatten1_margin + * for merlin (0xa20c/b20c 16:12 + */ + .xatten1Margin = {0x19, 0x19, 0x19}, + .tempSlope = 70, + .voltSlope = 15, + /* spurChans spur channels in usual fbin coding format */ + .spurChans = {0, 0, 0, 0, 0}, + /* noiseFloorThreshch check if the register is per chain */ + .noiseFloorThreshCh = {-1, 0, 0}, + .ob = {3, 3, 3}, /* 3 chain */ + .db_stage2 = {3, 3, 3}, /* 3 chain */ + .db_stage3 = {3, 3, 3}, /* doesn't exist for 2G */ + .db_stage4 = {3, 3, 3}, /* don't exist for 2G */ + .xpaBiasLvl = 0, + .txFrameToDataStart = 0x0e, + .txFrameToPaOn = 0x0e, + .txClip = 3, /* 4 bits tx_clip, 4 bits dac_scale_cck */ + .antennaGain = 0, + .switchSettling = 0x2d, + .adcDesiredSize = -30, + .txEndToXpaOff = 0, + .txEndToRxOn = 0x2, + .txFrameToXpaOn = 0xe, + .thresh62 = 28, + .papdRateMaskHt20 = LE32(0x0cf0e0e0), + .papdRateMaskHt40 = LE32(0x6cf0e0e0), + .futureModal = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }, + }, + .base_ext2 = { + .tempSlopeLow = 72, + .tempSlopeHigh = 105, + .xatten1DBLow = {0x10, 0x14, 0x10}, + .xatten1MarginLow = {0x19, 0x19 , 0x19}, + .xatten1DBHigh = {0x1d, 0x20, 0x24}, + .xatten1MarginHigh = {0x10, 0x10, 0x10} + }, + .calFreqPier5G = { + FREQ2FBIN(5180, 0), + FREQ2FBIN(5220, 0), + FREQ2FBIN(5320, 0), + FREQ2FBIN(5400, 0), + FREQ2FBIN(5500, 0), + FREQ2FBIN(5600, 0), + FREQ2FBIN(5700, 0), + FREQ2FBIN(5785, 0) + }, + .calPierData5G = { + { + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + }, + { + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + }, + { + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + }, + + }, + .calTarget_freqbin_5G = { + FREQ2FBIN(5180, 0), + FREQ2FBIN(5220, 0), + FREQ2FBIN(5320, 0), + FREQ2FBIN(5400, 0), + FREQ2FBIN(5500, 0), + FREQ2FBIN(5600, 0), + FREQ2FBIN(5725, 0), + FREQ2FBIN(5825, 0) + }, + .calTarget_freqbin_5GHT20 = { + FREQ2FBIN(5180, 0), + FREQ2FBIN(5220, 0), + FREQ2FBIN(5320, 0), + FREQ2FBIN(5400, 0), + FREQ2FBIN(5500, 0), + FREQ2FBIN(5600, 0), + FREQ2FBIN(5725, 0), + FREQ2FBIN(5825, 0) + }, + .calTarget_freqbin_5GHT40 = { + FREQ2FBIN(5180, 0), + FREQ2FBIN(5220, 0), + FREQ2FBIN(5320, 0), + FREQ2FBIN(5400, 0), + FREQ2FBIN(5500, 0), + FREQ2FBIN(5600, 0), + FREQ2FBIN(5725, 0), + FREQ2FBIN(5825, 0) + }, + .calTargetPower5G = { + /* 6-24,36,48,54 */ + { {32, 32, 28, 26} }, + { {32, 32, 28, 26} }, + { {32, 32, 28, 26} }, + { {32, 32, 26, 24} }, + { {32, 32, 26, 24} }, + { {32, 32, 24, 22} }, + { {30, 30, 24, 22} }, + { {30, 30, 24, 22} }, + }, + .calTargetPower5GHT20 = { + /* + * 0_8_16,1-3_9-11_17-19, + * 4,5,6,7,12,13,14,15,20,21,22,23 + */ + { {32, 32, 32, 32, 28, 26, 32, 28, 26, 24, 24, 24, 22, 22} }, + { {32, 32, 32, 32, 28, 26, 32, 28, 26, 24, 24, 24, 22, 22} }, + { {32, 32, 32, 32, 28, 26, 32, 28, 26, 24, 24, 24, 22, 22} }, + { {32, 32, 32, 32, 28, 26, 32, 26, 24, 22, 22, 22, 20, 20} }, + { {32, 32, 32, 32, 28, 26, 32, 26, 24, 22, 20, 18, 16, 16} }, + { {32, 32, 32, 32, 28, 26, 32, 24, 20, 16, 18, 16, 14, 14} }, + { {30, 30, 30, 30, 28, 26, 30, 24, 20, 16, 18, 16, 14, 14} }, + { {30, 30, 30, 30, 28, 26, 30, 24, 20, 16, 18, 16, 14, 14} }, + }, + .calTargetPower5GHT40 = { + /* + * 0_8_16,1-3_9-11_17-19, + * 4,5,6,7,12,13,14,15,20,21,22,23 + */ + { {32, 32, 32, 30, 28, 26, 30, 28, 26, 24, 24, 24, 22, 22} }, + { {32, 32, 32, 30, 28, 26, 30, 28, 26, 24, 24, 24, 22, 22} }, + { {32, 32, 32, 30, 28, 26, 30, 28, 26, 24, 24, 24, 22, 22} }, + { {32, 32, 32, 30, 28, 26, 30, 26, 24, 22, 22, 22, 20, 20} }, + { {32, 32, 32, 30, 28, 26, 30, 26, 24, 22, 20, 18, 16, 16} }, + { {32, 32, 32, 30, 28, 26, 30, 22, 20, 16, 18, 16, 14, 14} }, + { {30, 30, 30, 30, 28, 26, 30, 22, 20, 16, 18, 16, 14, 14} }, + { {30, 30, 30, 30, 28, 26, 30, 22, 20, 16, 18, 16, 14, 14} }, + }, + .ctlIndex_5G = { + 0x10, 0x16, 0x18, 0x40, 0x46, + 0x48, 0x30, 0x36, 0x38 + }, + .ctl_freqbin_5G = { + { + /* Data[0].ctledges[0].bchannel */ FREQ2FBIN(5180, 0), + /* Data[0].ctledges[1].bchannel */ FREQ2FBIN(5260, 0), + /* Data[0].ctledges[2].bchannel */ FREQ2FBIN(5280, 0), + /* Data[0].ctledges[3].bchannel */ FREQ2FBIN(5500, 0), + /* Data[0].ctledges[4].bchannel */ FREQ2FBIN(5600, 0), + /* Data[0].ctledges[5].bchannel */ FREQ2FBIN(5700, 0), + /* Data[0].ctledges[6].bchannel */ FREQ2FBIN(5745, 0), + /* Data[0].ctledges[7].bchannel */ FREQ2FBIN(5825, 0) + }, + { + /* Data[1].ctledges[0].bchannel */ FREQ2FBIN(5180, 0), + /* Data[1].ctledges[1].bchannel */ FREQ2FBIN(5260, 0), + /* Data[1].ctledges[2].bchannel */ FREQ2FBIN(5280, 0), + /* Data[1].ctledges[3].bchannel */ FREQ2FBIN(5500, 0), + /* Data[1].ctledges[4].bchannel */ FREQ2FBIN(5520, 0), + /* Data[1].ctledges[5].bchannel */ FREQ2FBIN(5700, 0), + /* Data[1].ctledges[6].bchannel */ FREQ2FBIN(5745, 0), + /* Data[1].ctledges[7].bchannel */ FREQ2FBIN(5825, 0) + }, + + { + /* Data[2].ctledges[0].bchannel */ FREQ2FBIN(5190, 0), + /* Data[2].ctledges[1].bchannel */ FREQ2FBIN(5230, 0), + /* Data[2].ctledges[2].bchannel */ FREQ2FBIN(5270, 0), + /* Data[2].ctledges[3].bchannel */ FREQ2FBIN(5310, 0), + /* Data[2].ctledges[4].bchannel */ FREQ2FBIN(5510, 0), + /* Data[2].ctledges[5].bchannel */ FREQ2FBIN(5550, 0), + /* Data[2].ctledges[6].bchannel */ FREQ2FBIN(5670, 0), + /* Data[2].ctledges[7].bchannel */ FREQ2FBIN(5755, 0) + }, + + { + /* Data[3].ctledges[0].bchannel */ FREQ2FBIN(5180, 0), + /* Data[3].ctledges[1].bchannel */ FREQ2FBIN(5200, 0), + /* Data[3].ctledges[2].bchannel */ FREQ2FBIN(5260, 0), + /* Data[3].ctledges[3].bchannel */ FREQ2FBIN(5320, 0), + /* Data[3].ctledges[4].bchannel */ FREQ2FBIN(5500, 0), + /* Data[3].ctledges[5].bchannel */ FREQ2FBIN(5700, 0), + /* Data[3].ctledges[6].bchannel */ 0xFF, + /* Data[3].ctledges[7].bchannel */ 0xFF, + }, + + { + /* Data[4].ctledges[0].bchannel */ FREQ2FBIN(5180, 0), + /* Data[4].ctledges[1].bchannel */ FREQ2FBIN(5260, 0), + /* Data[4].ctledges[2].bchannel */ FREQ2FBIN(5500, 0), + /* Data[4].ctledges[3].bchannel */ FREQ2FBIN(5700, 0), + /* Data[4].ctledges[4].bchannel */ 0xFF, + /* Data[4].ctledges[5].bchannel */ 0xFF, + /* Data[4].ctledges[6].bchannel */ 0xFF, + /* Data[4].ctledges[7].bchannel */ 0xFF, + }, + + { + /* Data[5].ctledges[0].bchannel */ FREQ2FBIN(5190, 0), + /* Data[5].ctledges[1].bchannel */ FREQ2FBIN(5270, 0), + /* Data[5].ctledges[2].bchannel */ FREQ2FBIN(5310, 0), + /* Data[5].ctledges[3].bchannel */ FREQ2FBIN(5510, 0), + /* Data[5].ctledges[4].bchannel */ FREQ2FBIN(5590, 0), + /* Data[5].ctledges[5].bchannel */ FREQ2FBIN(5670, 0), + /* Data[5].ctledges[6].bchannel */ 0xFF, + /* Data[5].ctledges[7].bchannel */ 0xFF + }, + + { + /* Data[6].ctledges[0].bchannel */ FREQ2FBIN(5180, 0), + /* Data[6].ctledges[1].bchannel */ FREQ2FBIN(5200, 0), + /* Data[6].ctledges[2].bchannel */ FREQ2FBIN(5220, 0), + /* Data[6].ctledges[3].bchannel */ FREQ2FBIN(5260, 0), + /* Data[6].ctledges[4].bchannel */ FREQ2FBIN(5500, 0), + /* Data[6].ctledges[5].bchannel */ FREQ2FBIN(5600, 0), + /* Data[6].ctledges[6].bchannel */ FREQ2FBIN(5700, 0), + /* Data[6].ctledges[7].bchannel */ FREQ2FBIN(5745, 0) + }, + + { + /* Data[7].ctledges[0].bchannel */ FREQ2FBIN(5180, 0), + /* Data[7].ctledges[1].bchannel */ FREQ2FBIN(5260, 0), + /* Data[7].ctledges[2].bchannel */ FREQ2FBIN(5320, 0), + /* Data[7].ctledges[3].bchannel */ FREQ2FBIN(5500, 0), + /* Data[7].ctledges[4].bchannel */ FREQ2FBIN(5560, 0), + /* Data[7].ctledges[5].bchannel */ FREQ2FBIN(5700, 0), + /* Data[7].ctledges[6].bchannel */ FREQ2FBIN(5745, 0), + /* Data[7].ctledges[7].bchannel */ FREQ2FBIN(5825, 0) + }, + + { + /* Data[8].ctledges[0].bchannel */ FREQ2FBIN(5190, 0), + /* Data[8].ctledges[1].bchannel */ FREQ2FBIN(5230, 0), + /* Data[8].ctledges[2].bchannel */ FREQ2FBIN(5270, 0), + /* Data[8].ctledges[3].bchannel */ FREQ2FBIN(5510, 0), + /* Data[8].ctledges[4].bchannel */ FREQ2FBIN(5550, 0), + /* Data[8].ctledges[5].bchannel */ FREQ2FBIN(5670, 0), + /* Data[8].ctledges[6].bchannel */ FREQ2FBIN(5755, 0), + /* Data[8].ctledges[7].bchannel */ FREQ2FBIN(5795, 0) + } + }, + .ctlPowerData_5G = { + { + { + {60, 1}, {60, 1}, {60, 1}, {60, 1}, + {60, 1}, {60, 1}, {60, 1}, {60, 0}, + } + }, + { + { + {60, 1}, {60, 1}, {60, 1}, {60, 1}, + {60, 1}, {60, 1}, {60, 1}, {60, 0}, + } + }, + { + { + {60, 0}, {60, 1}, {60, 0}, {60, 1}, + {60, 1}, {60, 1}, {60, 1}, {60, 1}, + } + }, + { + { + {60, 0}, {60, 1}, {60, 1}, {60, 0}, + {60, 1}, {60, 0}, {60, 0}, {60, 0}, + } + }, + { + { + {60, 1}, {60, 1}, {60, 1}, {60, 0}, + {60, 0}, {60, 0}, {60, 0}, {60, 0}, + } + }, + { + { + {60, 1}, {60, 1}, {60, 1}, {60, 1}, + {60, 1}, {60, 0}, {60, 0}, {60, 0}, + } + }, + { + { + {60, 1}, {60, 1}, {60, 1}, {60, 1}, + {60, 1}, {60, 1}, {60, 1}, {60, 1}, + } + }, + { + { + {60, 1}, {60, 1}, {60, 0}, {60, 1}, + {60, 1}, {60, 1}, {60, 1}, {60, 0}, + } + }, + { + { + {60, 1}, {60, 0}, {60, 1}, {60, 1}, + {60, 1}, {60, 1}, {60, 0}, {60, 1}, + } + }, + } +}; + +static const struct ar9300_eeprom ar9300_h116 = { + .eepromVersion = 2, + .templateVersion = 4, + .macAddr = {0x00, 0x03, 0x7f, 0x0, 0x0, 0x0}, + .custData = {"h116-041-f0000"}, + .baseEepHeader = { + .regDmn = { LE16(0), LE16(0x1f) }, + .txrxMask = 0x33, /* 4 bits tx and 4 bits rx */ + .opCapFlags = { + .opFlags = AR9300_OPFLAGS_11G | AR9300_OPFLAGS_11A, + .eepMisc = 0, + }, + .rfSilent = 0, + .blueToothOptions = 0, + .deviceCap = 0, + .deviceType = 5, /* takes lower byte in eeprom location */ + .pwrTableOffset = AR9300_PWR_TABLE_OFFSET, + .params_for_tuning_caps = {0, 0}, + .featureEnable = 0x0d, + /* + * bit0 - enable tx temp comp - disabled + * bit1 - enable tx volt comp - disabled + * bit2 - enable fastClock - enabled + * bit3 - enable doubling - enabled + * bit4 - enable internal regulator - disabled + * bit5 - enable pa predistortion - disabled + */ + .miscConfiguration = 0, /* bit0 - turn down drivestrength */ + .eepromWriteEnableGpio = 6, + .wlanDisableGpio = 0, + .wlanLedGpio = 8, + .rxBandSelectGpio = 0xff, + .txrxgain = 0x10, + .swreg = 0, + }, + .modalHeader2G = { + /* ar9300_modal_eep_header 2g */ + /* 4 idle,t1,t2,b(4 bits per setting) */ + .antCtrlCommon = LE32(0x110), + /* 4 ra1l1, ra2l1, ra1l2, ra2l2, ra12 */ + .antCtrlCommon2 = LE32(0x44444), + + /* + * antCtrlChain[AR9300_MAX_CHAINS]; 6 idle, t, r, + * rx1, rx12, b (2 bits each) + */ + .antCtrlChain = { LE16(0x10), LE16(0x10), LE16(0x10) }, + + /* + * xatten1DB[AR9300_MAX_CHAINS]; 3 xatten1_db + * for ar9280 (0xa20c/b20c 5:0) + */ + .xatten1DB = {0x1f, 0x1f, 0x1f}, + + /* + * xatten1Margin[AR9300_MAX_CHAINS]; 3 xatten1_margin + * for ar9280 (0xa20c/b20c 16:12 + */ + .xatten1Margin = {0x12, 0x12, 0x12}, + .tempSlope = 25, + .voltSlope = 0, + + /* + * spurChans[OSPREY_EEPROM_MODAL_SPURS]; spur + * channels in usual fbin coding format + */ + .spurChans = {FREQ2FBIN(2464, 1), 0, 0, 0, 0}, + + /* + * noiseFloorThreshCh[AR9300_MAX_CHAINS]; 3 Check + * if the register is per chain + */ + .noiseFloorThreshCh = {-1, 0, 0}, + .ob = {1, 1, 1},/* 3 chain */ + .db_stage2 = {1, 1, 1}, /* 3 chain */ + .db_stage3 = {0, 0, 0}, + .db_stage4 = {0, 0, 0}, + .xpaBiasLvl = 0, + .txFrameToDataStart = 0x0e, + .txFrameToPaOn = 0x0e, + .txClip = 3, /* 4 bits tx_clip, 4 bits dac_scale_cck */ + .antennaGain = 0, + .switchSettling = 0x2c, + .adcDesiredSize = -30, + .txEndToXpaOff = 0, + .txEndToRxOn = 0x2, + .txFrameToXpaOn = 0xe, + .thresh62 = 28, + .papdRateMaskHt20 = LE32(0x0c80C080), + .papdRateMaskHt40 = LE32(0x0080C080), + .futureModal = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }, + }, + .base_ext1 = { + .ant_div_control = 0, + .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + }, + .calFreqPier2G = { + FREQ2FBIN(2412, 1), + FREQ2FBIN(2437, 1), + FREQ2FBIN(2472, 1), + }, + /* ar9300_cal_data_per_freq_op_loop 2g */ + .calPierData2G = { + { {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} }, + { {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} }, + { {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} }, + }, + .calTarget_freqbin_Cck = { + FREQ2FBIN(2412, 1), + FREQ2FBIN(2472, 1), + }, + .calTarget_freqbin_2G = { + FREQ2FBIN(2412, 1), + FREQ2FBIN(2437, 1), + FREQ2FBIN(2472, 1) + }, + .calTarget_freqbin_2GHT20 = { + FREQ2FBIN(2412, 1), + FREQ2FBIN(2437, 1), + FREQ2FBIN(2472, 1) + }, + .calTarget_freqbin_2GHT40 = { + FREQ2FBIN(2412, 1), + FREQ2FBIN(2437, 1), + FREQ2FBIN(2472, 1) + }, + .calTargetPowerCck = { + /* 1L-5L,5S,11L,11S */ + { {34, 34, 34, 34} }, + { {34, 34, 34, 34} }, + }, + .calTargetPower2G = { + /* 6-24,36,48,54 */ + { {34, 34, 32, 32} }, + { {34, 34, 32, 32} }, + { {34, 34, 32, 32} }, + }, + .calTargetPower2GHT20 = { + { {32, 32, 32, 32, 32, 30, 32, 32, 30, 28, 0, 0, 0, 0} }, + { {32, 32, 32, 32, 32, 30, 32, 32, 30, 28, 0, 0, 0, 0} }, + { {32, 32, 32, 32, 32, 30, 32, 32, 30, 28, 0, 0, 0, 0} }, + }, + .calTargetPower2GHT40 = { + { {30, 30, 30, 30, 30, 28, 30, 30, 28, 26, 0, 0, 0, 0} }, + { {30, 30, 30, 30, 30, 28, 30, 30, 28, 26, 0, 0, 0, 0} }, + { {30, 30, 30, 30, 30, 28, 30, 30, 28, 26, 0, 0, 0, 0} }, + }, + .ctlIndex_2G = { + 0x11, 0x12, 0x15, 0x17, 0x41, 0x42, + 0x45, 0x47, 0x31, 0x32, 0x35, 0x37, + }, + .ctl_freqbin_2G = { + { + FREQ2FBIN(2412, 1), + FREQ2FBIN(2417, 1), + FREQ2FBIN(2457, 1), + FREQ2FBIN(2462, 1) + }, + { + FREQ2FBIN(2412, 1), + FREQ2FBIN(2417, 1), + FREQ2FBIN(2462, 1), + 0xFF, + }, + + { + FREQ2FBIN(2412, 1), + FREQ2FBIN(2417, 1), + FREQ2FBIN(2462, 1), + 0xFF, + }, + { + FREQ2FBIN(2422, 1), + FREQ2FBIN(2427, 1), + FREQ2FBIN(2447, 1), + FREQ2FBIN(2452, 1) + }, + + { + /* Data[4].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1), + /* Data[4].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1), + /* Data[4].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1), + /* Data[4].ctlEdges[3].bChannel */ FREQ2FBIN(2484, 1), + }, + + { + /* Data[5].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1), + /* Data[5].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1), + /* Data[5].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1), + 0, + }, + + { + /* Data[6].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1), + /* Data[6].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1), + FREQ2FBIN(2472, 1), + 0, + }, + + { + /* Data[7].ctlEdges[0].bChannel */ FREQ2FBIN(2422, 1), + /* Data[7].ctlEdges[1].bChannel */ FREQ2FBIN(2427, 1), + /* Data[7].ctlEdges[2].bChannel */ FREQ2FBIN(2447, 1), + /* Data[7].ctlEdges[3].bChannel */ FREQ2FBIN(2462, 1), + }, + + { + /* Data[8].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1), + /* Data[8].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1), + /* Data[8].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1), + }, + + { + /* Data[9].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1), + /* Data[9].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1), + /* Data[9].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1), + 0 + }, + + { + /* Data[10].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1), + /* Data[10].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1), + /* Data[10].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1), + 0 + }, + + { + /* Data[11].ctlEdges[0].bChannel */ FREQ2FBIN(2422, 1), + /* Data[11].ctlEdges[1].bChannel */ FREQ2FBIN(2427, 1), + /* Data[11].ctlEdges[2].bChannel */ FREQ2FBIN(2447, 1), + /* Data[11].ctlEdges[3].bChannel */ FREQ2FBIN(2462, 1), + } + }, + .ctlPowerData_2G = { + { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, + { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, + { { {60, 1}, {60, 0}, {60, 0}, {60, 1} } }, + + { { {60, 1}, {60, 0}, {0, 0}, {0, 0} } }, + { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, + { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, + + { { {60, 0}, {60, 1}, {60, 1}, {60, 0} } }, + { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, + { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, + + { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, + { { {60, 0}, {60, 1}, {60, 1}, {60, 1} } }, + { { {60, 0}, {60, 1}, {60, 1}, {60, 1} } }, + }, + .modalHeader5G = { + /* 4 idle,t1,t2,b (4 bits per setting) */ + .antCtrlCommon = LE32(0x220), + /* 4 ra1l1, ra2l1, ra1l2,ra2l2,ra12 */ + .antCtrlCommon2 = LE32(0x44444), + /* antCtrlChain 6 idle, t,r,rx1,rx12,b (2 bits each) */ + .antCtrlChain = { + LE16(0x150), LE16(0x150), LE16(0x150), + }, + /* xatten1DB 3 xatten1_db for AR9280 (0xa20c/b20c 5:0) */ + .xatten1DB = {0x19, 0x19, 0x19}, + + /* + * xatten1Margin[AR9300_MAX_CHAINS]; 3 xatten1_margin + * for merlin (0xa20c/b20c 16:12 + */ + .xatten1Margin = {0x14, 0x14, 0x14}, + .tempSlope = 70, + .voltSlope = 0, + /* spurChans spur channels in usual fbin coding format */ + .spurChans = {0, 0, 0, 0, 0}, + /* noiseFloorThreshCh Check if the register is per chain */ + .noiseFloorThreshCh = {-1, 0, 0}, + .ob = {3, 3, 3}, /* 3 chain */ + .db_stage2 = {3, 3, 3}, /* 3 chain */ + .db_stage3 = {3, 3, 3}, /* doesn't exist for 2G */ + .db_stage4 = {3, 3, 3}, /* don't exist for 2G */ + .xpaBiasLvl = 0, + .txFrameToDataStart = 0x0e, + .txFrameToPaOn = 0x0e, + .txClip = 3, /* 4 bits tx_clip, 4 bits dac_scale_cck */ + .antennaGain = 0, + .switchSettling = 0x2d, + .adcDesiredSize = -30, + .txEndToXpaOff = 0, + .txEndToRxOn = 0x2, + .txFrameToXpaOn = 0xe, + .thresh62 = 28, + .papdRateMaskHt20 = LE32(0x0cf0e0e0), + .papdRateMaskHt40 = LE32(0x6cf0e0e0), + .futureModal = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }, + }, + .base_ext2 = { + .tempSlopeLow = 35, + .tempSlopeHigh = 50, + .xatten1DBLow = {0, 0, 0}, + .xatten1MarginLow = {0, 0, 0}, + .xatten1DBHigh = {0, 0, 0}, + .xatten1MarginHigh = {0, 0, 0} + }, + .calFreqPier5G = { + FREQ2FBIN(5180, 0), + FREQ2FBIN(5220, 0), + FREQ2FBIN(5320, 0), + FREQ2FBIN(5400, 0), + FREQ2FBIN(5500, 0), + FREQ2FBIN(5600, 0), + FREQ2FBIN(5700, 0), + FREQ2FBIN(5785, 0) + }, + .calPierData5G = { + { + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + }, + { + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + }, + { + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + }, + + }, + .calTarget_freqbin_5G = { + FREQ2FBIN(5180, 0), + FREQ2FBIN(5240, 0), + FREQ2FBIN(5320, 0), + FREQ2FBIN(5400, 0), + FREQ2FBIN(5500, 0), + FREQ2FBIN(5600, 0), + FREQ2FBIN(5700, 0), + FREQ2FBIN(5825, 0) + }, + .calTarget_freqbin_5GHT20 = { + FREQ2FBIN(5180, 0), + FREQ2FBIN(5240, 0), + FREQ2FBIN(5320, 0), + FREQ2FBIN(5400, 0), + FREQ2FBIN(5500, 0), + FREQ2FBIN(5700, 0), + FREQ2FBIN(5745, 0), + FREQ2FBIN(5825, 0) + }, + .calTarget_freqbin_5GHT40 = { + FREQ2FBIN(5180, 0), + FREQ2FBIN(5240, 0), + FREQ2FBIN(5320, 0), + FREQ2FBIN(5400, 0), + FREQ2FBIN(5500, 0), + FREQ2FBIN(5700, 0), + FREQ2FBIN(5745, 0), + FREQ2FBIN(5825, 0) + }, + .calTargetPower5G = { + /* 6-24,36,48,54 */ + { {30, 30, 28, 24} }, + { {30, 30, 28, 24} }, + { {30, 30, 28, 24} }, + { {30, 30, 28, 24} }, + { {30, 30, 28, 24} }, + { {30, 30, 28, 24} }, + { {30, 30, 28, 24} }, + { {30, 30, 28, 24} }, + }, + .calTargetPower5GHT20 = { + /* + * 0_8_16,1-3_9-11_17-19, + * 4,5,6,7,12,13,14,15,20,21,22,23 + */ + { {30, 30, 30, 28, 24, 20, 30, 28, 24, 20, 0, 0, 0, 0} }, + { {30, 30, 30, 28, 24, 20, 30, 28, 24, 20, 0, 0, 0, 0} }, + { {30, 30, 30, 26, 22, 18, 30, 26, 22, 18, 0, 0, 0, 0} }, + { {30, 30, 30, 26, 22, 18, 30, 26, 22, 18, 0, 0, 0, 0} }, + { {30, 30, 30, 24, 20, 16, 30, 24, 20, 16, 0, 0, 0, 0} }, + { {30, 30, 30, 24, 20, 16, 30, 24, 20, 16, 0, 0, 0, 0} }, + { {30, 30, 30, 22, 18, 14, 30, 22, 18, 14, 0, 0, 0, 0} }, + { {30, 30, 30, 22, 18, 14, 30, 22, 18, 14, 0, 0, 0, 0} }, + }, + .calTargetPower5GHT40 = { + /* + * 0_8_16,1-3_9-11_17-19, + * 4,5,6,7,12,13,14,15,20,21,22,23 + */ + { {28, 28, 28, 26, 22, 18, 28, 26, 22, 18, 0, 0, 0, 0} }, + { {28, 28, 28, 26, 22, 18, 28, 26, 22, 18, 0, 0, 0, 0} }, + { {28, 28, 28, 24, 20, 16, 28, 24, 20, 16, 0, 0, 0, 0} }, + { {28, 28, 28, 24, 20, 16, 28, 24, 20, 16, 0, 0, 0, 0} }, + { {28, 28, 28, 22, 18, 14, 28, 22, 18, 14, 0, 0, 0, 0} }, + { {28, 28, 28, 22, 18, 14, 28, 22, 18, 14, 0, 0, 0, 0} }, + { {28, 28, 28, 20, 16, 12, 28, 20, 16, 12, 0, 0, 0, 0} }, + { {28, 28, 28, 20, 16, 12, 28, 20, 16, 12, 0, 0, 0, 0} }, + }, + .ctlIndex_5G = { + 0x10, 0x16, 0x18, 0x40, 0x46, + 0x48, 0x30, 0x36, 0x38 + }, + .ctl_freqbin_5G = { + { + /* Data[0].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0), + /* Data[0].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0), + /* Data[0].ctlEdges[2].bChannel */ FREQ2FBIN(5280, 0), + /* Data[0].ctlEdges[3].bChannel */ FREQ2FBIN(5500, 0), + /* Data[0].ctlEdges[4].bChannel */ FREQ2FBIN(5600, 0), + /* Data[0].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0), + /* Data[0].ctlEdges[6].bChannel */ FREQ2FBIN(5745, 0), + /* Data[0].ctlEdges[7].bChannel */ FREQ2FBIN(5825, 0) + }, + { + /* Data[1].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0), + /* Data[1].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0), + /* Data[1].ctlEdges[2].bChannel */ FREQ2FBIN(5280, 0), + /* Data[1].ctlEdges[3].bChannel */ FREQ2FBIN(5500, 0), + /* Data[1].ctlEdges[4].bChannel */ FREQ2FBIN(5520, 0), + /* Data[1].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0), + /* Data[1].ctlEdges[6].bChannel */ FREQ2FBIN(5745, 0), + /* Data[1].ctlEdges[7].bChannel */ FREQ2FBIN(5825, 0) + }, + + { + /* Data[2].ctlEdges[0].bChannel */ FREQ2FBIN(5190, 0), + /* Data[2].ctlEdges[1].bChannel */ FREQ2FBIN(5230, 0), + /* Data[2].ctlEdges[2].bChannel */ FREQ2FBIN(5270, 0), + /* Data[2].ctlEdges[3].bChannel */ FREQ2FBIN(5310, 0), + /* Data[2].ctlEdges[4].bChannel */ FREQ2FBIN(5510, 0), + /* Data[2].ctlEdges[5].bChannel */ FREQ2FBIN(5550, 0), + /* Data[2].ctlEdges[6].bChannel */ FREQ2FBIN(5670, 0), + /* Data[2].ctlEdges[7].bChannel */ FREQ2FBIN(5755, 0) + }, + + { + /* Data[3].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0), + /* Data[3].ctlEdges[1].bChannel */ FREQ2FBIN(5200, 0), + /* Data[3].ctlEdges[2].bChannel */ FREQ2FBIN(5260, 0), + /* Data[3].ctlEdges[3].bChannel */ FREQ2FBIN(5320, 0), + /* Data[3].ctlEdges[4].bChannel */ FREQ2FBIN(5500, 0), + /* Data[3].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0), + /* Data[3].ctlEdges[6].bChannel */ 0xFF, + /* Data[3].ctlEdges[7].bChannel */ 0xFF, + }, + + { + /* Data[4].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0), + /* Data[4].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0), + /* Data[4].ctlEdges[2].bChannel */ FREQ2FBIN(5500, 0), + /* Data[4].ctlEdges[3].bChannel */ FREQ2FBIN(5700, 0), + /* Data[4].ctlEdges[4].bChannel */ 0xFF, + /* Data[4].ctlEdges[5].bChannel */ 0xFF, + /* Data[4].ctlEdges[6].bChannel */ 0xFF, + /* Data[4].ctlEdges[7].bChannel */ 0xFF, + }, + + { + /* Data[5].ctlEdges[0].bChannel */ FREQ2FBIN(5190, 0), + /* Data[5].ctlEdges[1].bChannel */ FREQ2FBIN(5270, 0), + /* Data[5].ctlEdges[2].bChannel */ FREQ2FBIN(5310, 0), + /* Data[5].ctlEdges[3].bChannel */ FREQ2FBIN(5510, 0), + /* Data[5].ctlEdges[4].bChannel */ FREQ2FBIN(5590, 0), + /* Data[5].ctlEdges[5].bChannel */ FREQ2FBIN(5670, 0), + /* Data[5].ctlEdges[6].bChannel */ 0xFF, + /* Data[5].ctlEdges[7].bChannel */ 0xFF + }, + + { + /* Data[6].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0), + /* Data[6].ctlEdges[1].bChannel */ FREQ2FBIN(5200, 0), + /* Data[6].ctlEdges[2].bChannel */ FREQ2FBIN(5220, 0), + /* Data[6].ctlEdges[3].bChannel */ FREQ2FBIN(5260, 0), + /* Data[6].ctlEdges[4].bChannel */ FREQ2FBIN(5500, 0), + /* Data[6].ctlEdges[5].bChannel */ FREQ2FBIN(5600, 0), + /* Data[6].ctlEdges[6].bChannel */ FREQ2FBIN(5700, 0), + /* Data[6].ctlEdges[7].bChannel */ FREQ2FBIN(5745, 0) + }, + + { + /* Data[7].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0), + /* Data[7].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0), + /* Data[7].ctlEdges[2].bChannel */ FREQ2FBIN(5320, 0), + /* Data[7].ctlEdges[3].bChannel */ FREQ2FBIN(5500, 0), + /* Data[7].ctlEdges[4].bChannel */ FREQ2FBIN(5560, 0), + /* Data[7].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0), + /* Data[7].ctlEdges[6].bChannel */ FREQ2FBIN(5745, 0), + /* Data[7].ctlEdges[7].bChannel */ FREQ2FBIN(5825, 0) + }, + + { + /* Data[8].ctlEdges[0].bChannel */ FREQ2FBIN(5190, 0), + /* Data[8].ctlEdges[1].bChannel */ FREQ2FBIN(5230, 0), + /* Data[8].ctlEdges[2].bChannel */ FREQ2FBIN(5270, 0), + /* Data[8].ctlEdges[3].bChannel */ FREQ2FBIN(5510, 0), + /* Data[8].ctlEdges[4].bChannel */ FREQ2FBIN(5550, 0), + /* Data[8].ctlEdges[5].bChannel */ FREQ2FBIN(5670, 0), + /* Data[8].ctlEdges[6].bChannel */ FREQ2FBIN(5755, 0), + /* Data[8].ctlEdges[7].bChannel */ FREQ2FBIN(5795, 0) + } + }, + .ctlPowerData_5G = { + { + { + {60, 1}, {60, 1}, {60, 1}, {60, 1}, + {60, 1}, {60, 1}, {60, 1}, {60, 0}, + } + }, + { + { + {60, 1}, {60, 1}, {60, 1}, {60, 1}, + {60, 1}, {60, 1}, {60, 1}, {60, 0}, + } + }, + { + { + {60, 0}, {60, 1}, {60, 0}, {60, 1}, + {60, 1}, {60, 1}, {60, 1}, {60, 1}, + } + }, + { + { + {60, 0}, {60, 1}, {60, 1}, {60, 0}, + {60, 1}, {60, 0}, {60, 0}, {60, 0}, + } + }, + { + { + {60, 1}, {60, 1}, {60, 1}, {60, 0}, + {60, 0}, {60, 0}, {60, 0}, {60, 0}, + } + }, + { + { + {60, 1}, {60, 1}, {60, 1}, {60, 1}, + {60, 1}, {60, 0}, {60, 0}, {60, 0}, + } + }, + { + { + {60, 1}, {60, 1}, {60, 1}, {60, 1}, + {60, 1}, {60, 1}, {60, 1}, {60, 1}, + } + }, + { + { + {60, 1}, {60, 1}, {60, 0}, {60, 1}, + {60, 1}, {60, 1}, {60, 1}, {60, 0}, + } + }, + { + { + {60, 1}, {60, 0}, {60, 1}, {60, 1}, + {60, 1}, {60, 1}, {60, 0}, {60, 1}, + } + }, + } +}; + + +static const struct ar9300_eeprom *ar9300_eep_templates[] = { + &ar9300_default, + &ar9300_x112, + &ar9300_h116, + &ar9300_h112, + &ar9300_x113, +}; + +static const struct ar9300_eeprom *ar9003_eeprom_struct_find_by_id(int id) +{ +#define N_LOOP (sizeof(ar9300_eep_templates) / sizeof(ar9300_eep_templates[0])) + int it; + + for (it = 0; it < N_LOOP; it++) + if (ar9300_eep_templates[it]->templateVersion == id) + return ar9300_eep_templates[it]; + return NULL; +#undef N_LOOP +} + + static u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz) { if (fbin == AR9300_BCHAN_UNUSED) @@ -834,6 +3166,7 @@ static int ar9300_compress_decision(struct ath_hw *ah, { struct ath_common *common = ath9k_hw_common(ah); u8 *dptr; + const struct ar9300_eeprom *eep = NULL; switch (code) { case _CompressNone: @@ -851,13 +3184,14 @@ static int ar9300_compress_decision(struct ath_hw *ah, if (reference == 0) { dptr = mptr; } else { - if (reference != 2) { + eep = ar9003_eeprom_struct_find_by_id(reference); + if (eep == NULL) { ath_print(common, ATH_DBG_EEPROM, "cant find reference eeprom" "struct %d\n", reference); return -1; } - memcpy(mptr, &ar9300_default, mdata_size); + memcpy(mptr, eep, mdata_size); } ath_print(common, ATH_DBG_EEPROM, "restore eeprom %d: block, reference %d," -- cgit v0.10.2 From 52a0e2477dac2106bc1688cbe9615cdafc9deb7d Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 10 Nov 2010 05:03:11 -0800 Subject: ath9k_hw: Fix XPABIAS level configuration for AR9003 Improper configuration of 0x16288 and 0x16290 would affect transmission. Cc:stable@kernel.org Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 3d467fc..17f73e4 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -22,12 +22,14 @@ #define COMP_CKSUM_LEN 2 #define AR_CH0_TOP (0x00016288) -#define AR_CH0_TOP_XPABIASLVL (0x3) +#define AR_CH0_TOP_XPABIASLVL (0x300) #define AR_CH0_TOP_XPABIASLVL_S (8) #define AR_CH0_THERM (0x00016290) -#define AR_CH0_THERM_SPARE (0x3f) -#define AR_CH0_THERM_SPARE_S (0) +#define AR_CH0_THERM_XPABIASLVL_MSB 0x3 +#define AR_CH0_THERM_XPABIASLVL_MSB_S 0 +#define AR_CH0_THERM_XPASHORT2GND 0x4 +#define AR_CH0_THERM_XPASHORT2GND_S 2 #define AR_SWITCH_TABLE_COM_ALL (0xffff) #define AR_SWITCH_TABLE_COM_ALL_S (0) @@ -3336,9 +3338,9 @@ static s32 ar9003_hw_xpa_bias_level_get(struct ath_hw *ah, bool is2ghz) static void ar9003_hw_xpa_bias_level_apply(struct ath_hw *ah, bool is2ghz) { int bias = ar9003_hw_xpa_bias_level_get(ah, is2ghz); - REG_RMW_FIELD(ah, AR_CH0_TOP, AR_CH0_TOP_XPABIASLVL, (bias & 0x3)); - REG_RMW_FIELD(ah, AR_CH0_THERM, AR_CH0_THERM_SPARE, - ((bias >> 2) & 0x3)); + REG_RMW_FIELD(ah, AR_CH0_TOP, AR_CH0_TOP_XPABIASLVL, bias); + REG_RMW_FIELD(ah, AR_CH0_THERM, AR_CH0_THERM_XPABIASLVL_MSB, bias >> 2); + REG_RMW_FIELD(ah, AR_CH0_THERM, AR_CH0_THERM_XPASHORT2GND, 1); } static u32 ar9003_hw_ant_ctrl_common_get(struct ath_hw *ah, bool is2ghz) -- cgit v0.10.2 From f4475a6e52fce8d951a96c763f36b835bf89fdec Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 10 Nov 2010 05:03:12 -0800 Subject: ath9k_hw: Enable strong signal detection for AR9003 Attenuation from eeprom is configured into attenuator control register. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 17f73e4..da26d37 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -57,6 +57,8 @@ #define SUB_NUM_CTL_MODES_AT_5G_40 2 /* excluding HT40, EXT-OFDM */ #define SUB_NUM_CTL_MODES_AT_2G_40 3 /* excluding HT40, EXT-OFDM, EXT-CCK */ +static int ar9003_hw_power_interpolate(int32_t x, + int32_t *px, int32_t *py, u_int16_t np); static const struct ar9300_eeprom ar9300_default = { .eepromVersion = 2, .templateVersion = 2, @@ -3443,6 +3445,82 @@ static void ar9003_hw_drive_strength_apply(struct ath_hw *ah) REG_WRITE(ah, AR_PHY_65NM_CH0_BIAS4, reg); } +static u16 ar9003_hw_atten_chain_get(struct ath_hw *ah, int chain, + struct ath9k_channel *chan) +{ + int f[3], t[3]; + u16 value; + struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; + + if (chain >= 0 && chain < 3) { + if (IS_CHAN_2GHZ(chan)) + return eep->modalHeader2G.xatten1DB[chain]; + else if (eep->base_ext2.xatten1DBLow[chain] != 0) { + t[0] = eep->base_ext2.xatten1DBLow[chain]; + f[0] = 5180; + t[1] = eep->modalHeader5G.xatten1DB[chain]; + f[1] = 5500; + t[2] = eep->base_ext2.xatten1DBHigh[chain]; + f[2] = 5785; + value = ar9003_hw_power_interpolate((s32) chan->channel, + f, t, 3); + return value; + } else + return eep->modalHeader5G.xatten1DB[chain]; + } + + return 0; +} + + +static u16 ar9003_hw_atten_chain_get_margin(struct ath_hw *ah, int chain, + struct ath9k_channel *chan) +{ + int f[3], t[3]; + u16 value; + struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; + + if (chain >= 0 && chain < 3) { + if (IS_CHAN_2GHZ(chan)) + return eep->modalHeader2G.xatten1Margin[chain]; + else if (eep->base_ext2.xatten1MarginLow[chain] != 0) { + t[0] = eep->base_ext2.xatten1MarginLow[chain]; + f[0] = 5180; + t[1] = eep->modalHeader5G.xatten1Margin[chain]; + f[1] = 5500; + t[2] = eep->base_ext2.xatten1MarginHigh[chain]; + f[2] = 5785; + value = ar9003_hw_power_interpolate((s32) chan->channel, + f, t, 3); + return value; + } else + return eep->modalHeader5G.xatten1Margin[chain]; + } + + return 0; +} + +static void ar9003_hw_atten_apply(struct ath_hw *ah, struct ath9k_channel *chan) +{ + int i; + u16 value; + unsigned long ext_atten_reg[3] = {AR_PHY_EXT_ATTEN_CTL_0, + AR_PHY_EXT_ATTEN_CTL_1, + AR_PHY_EXT_ATTEN_CTL_2, + }; + + /* Test value. if 0 then attenuation is unused. Don't load anything. */ + for (i = 0; i < 3; i++) { + value = ar9003_hw_atten_chain_get(ah, i, chan); + REG_RMW_FIELD(ah, ext_atten_reg[i], + AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB, value); + + value = ar9003_hw_atten_chain_get_margin(ah, i, chan); + REG_RMW_FIELD(ah, ext_atten_reg[i], + AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN, value); + } +} + static void ar9003_hw_internal_regulator_apply(struct ath_hw *ah) { int internal_regulator = @@ -3474,6 +3552,7 @@ static void ath9k_hw_ar9300_set_board_values(struct ath_hw *ah, ar9003_hw_xpa_bias_level_apply(ah, IS_CHAN_2GHZ(chan)); ar9003_hw_ant_ctrl_apply(ah, IS_CHAN_2GHZ(chan)); ar9003_hw_drive_strength_apply(ah); + ar9003_hw_atten_apply(ah, chan); ar9003_hw_internal_regulator_apply(ah); } -- cgit v0.10.2 From 15cbbc44cc4abaaebc37caf0ec9410a3f83d1deb Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 10 Nov 2010 05:03:13 -0800 Subject: ath9k_hw: Improve power control accuracy for AR9003 It is done for 5Ghz by adding three temperature slopes. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index da26d37..5ffeda2 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -4062,6 +4062,7 @@ static int ar9003_hw_power_control_override(struct ath_hw *ah, { int tempSlope = 0; struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; + int f[3], t[3]; REG_RMW(ah, AR_PHY_TPC_11_B0, (correction[0] << AR_PHY_TPC_OLPC_GAIN_DELTA_S), @@ -4090,7 +4091,16 @@ static int ar9003_hw_power_control_override(struct ath_hw *ah, */ if (frequency < 4000) tempSlope = eep->modalHeader2G.tempSlope; - else + else if (eep->base_ext2.tempSlopeLow != 0) { + t[0] = eep->base_ext2.tempSlopeLow; + f[0] = 5180; + t[1] = eep->modalHeader5G.tempSlope; + f[1] = 5500; + t[2] = eep->base_ext2.tempSlopeHigh; + f[2] = 5785; + tempSlope = ar9003_hw_power_interpolate((s32) frequency, + f, t, 3); + } else tempSlope = eep->modalHeader5G.tempSlope; REG_RMW_FIELD(ah, AR_PHY_TPC_19, AR_PHY_TPC_19_ALPHA_THERM, tempSlope); -- cgit v0.10.2 From bc2068020bfa976efd425f3be590f58a012fd747 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 10 Nov 2010 05:03:14 -0800 Subject: ath9k_hw: Add helper function for interpolation Also round off interpolated values this would improve power accuracy by 0.5dB in some cases. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 5ffeda2..1b4e991 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -2982,6 +2982,16 @@ static int ath9k_hw_ar9300_check_eeprom(struct ath_hw *ah) return 0; } +static int interpolate(int x, int xa, int xb, int ya, int yb) +{ + int bf, factor, plus; + + bf = 2 * (yb - ya) * (x - xa) / (xb - xa); + factor = bf / 2; + plus = bf % 2; + return ya + factor + plus; +} + static u32 ath9k_hw_ar9300_get_eeprom(struct ath_hw *ah, enum eeprom_param param) { @@ -3614,7 +3624,7 @@ static int ar9003_hw_power_interpolate(int32_t x, if (hx == lx) y = ly; else /* interpolate */ - y = ly + (((x - lx) * (hy - ly)) / (hx - lx)); + y = interpolate(x, lx, hx, ly, hy); } else /* only low is good, use it */ y = ly; } else if (hhave) /* only high is good, use it */ @@ -4204,25 +4214,23 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency) /* so is the high frequency, interpolate */ if (hfrequency[ichain] - frequency < 1000) { - correction[ichain] = lcorrection[ichain] + - (((frequency - lfrequency[ichain]) * - (hcorrection[ichain] - - lcorrection[ichain])) / - (hfrequency[ichain] - lfrequency[ichain])); - - temperature[ichain] = ltemperature[ichain] + - (((frequency - lfrequency[ichain]) * - (htemperature[ichain] - - ltemperature[ichain])) / - (hfrequency[ichain] - lfrequency[ichain])); - - voltage[ichain] = - lvoltage[ichain] + - (((frequency - - lfrequency[ichain]) * (hvoltage[ichain] - - lvoltage[ichain])) - / (hfrequency[ichain] - - lfrequency[ichain])); + correction[ichain] = interpolate(frequency, + lfrequency[ichain], + hfrequency[ichain], + lcorrection[ichain], + hcorrection[ichain]); + + temperature[ichain] = interpolate(frequency, + lfrequency[ichain], + hfrequency[ichain], + ltemperature[ichain], + htemperature[ichain]); + + voltage[ichain] = interpolate(frequency, + lfrequency[ichain], + hfrequency[ichain], + lvoltage[ichain], + hvoltage[ichain]); } /* only low is good, use it */ else { -- cgit v0.10.2 From 39ec2997c374b528cdbf65099b6d6b8593a67f7f Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 10 Nov 2010 05:03:15 -0800 Subject: ath9k: Fix bug in delimiter padding computation There is a roundng error in delimiter padding computation which causes severe throughput drop with some of AR9003. signed-off-by: Felix Fietkau Signed-off-by: Vasanthakumar Thiagarajan Cc:stable@kernel.org 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 2143346..92670ce 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -177,8 +177,8 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd, /* returns delimiter padding required given the packet length */ #define ATH_AGGR_GET_NDELIM(_len) \ - (((((_len) + ATH_AGGR_DELIM_SZ) < ATH_AGGR_MINPLEN) ? \ - (ATH_AGGR_MINPLEN - (_len) - ATH_AGGR_DELIM_SZ) : 0) >> 2) + (((_len) >= ATH_AGGR_MINPLEN) ? 0 : \ + DIV_ROUND_UP(ATH_AGGR_MINPLEN - (_len), ATH_AGGR_DELIM_SZ)) #define BAW_WITHIN(_start, _bawsz, _seqno) \ ((((_seqno) - (_start)) & 4095) < (_bawsz)) -- cgit v0.10.2 From 6ee63f55c7754462a45315ac93027a1df60667c9 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Wed, 10 Nov 2010 05:03:16 -0800 Subject: ath9k_hw: Fix low throughput issue with AR93xx TX underruns were noticed when RTS/CTS preceded aggregates. This issue was noticed in ar93xx family of chipsets only. The workaround involves padding the RTS or CTS length up to the min packet length of 256 bytes required by the hardware by adding delimiters to the fist descriptor of the aggregate. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c index 10c812e..f5896aa 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c @@ -410,12 +410,36 @@ static void ar9003_hw_set11n_ratescenario(struct ath_hw *ah, void *ds, static void ar9003_hw_set11n_aggr_first(struct ath_hw *ah, void *ds, u32 aggrLen) { +#define FIRST_DESC_NDELIMS 60 struct ar9003_txc *ads = (struct ar9003_txc *) ds; ads->ctl12 |= (AR_IsAggr | AR_MoreAggr); - ads->ctl17 &= ~AR_AggrLen; - ads->ctl17 |= SM(aggrLen, AR_AggrLen); + if (ah->ent_mode & AR_ENT_OTP_MPSD) { + u32 ctl17, ndelim; + /* + * Add delimiter when using RTS/CTS with aggregation + * and non enterprise AR9003 card + */ + ctl17 = ads->ctl17; + ndelim = MS(ctl17, AR_PadDelim); + + if (ndelim < FIRST_DESC_NDELIMS) { + aggrLen += (FIRST_DESC_NDELIMS - ndelim) * 4; + ndelim = FIRST_DESC_NDELIMS; + } + + ctl17 &= ~AR_AggrLen; + ctl17 |= SM(aggrLen, AR_AggrLen); + + ctl17 &= ~AR_PadDelim; + ctl17 |= SM(ndelim, AR_PadDelim); + + ads->ctl17 = ctl17; + } else { + ads->ctl17 &= ~AR_AggrLen; + ads->ctl17 |= SM(aggrLen, AR_AggrLen); + } } static void ar9003_hw_set11n_aggr_middle(struct ath_hw *ah, void *ds, diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index e75d8e8..75e2363 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1952,6 +1952,9 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) if (AR_SREV_9300_20_OR_LATER(ah)) pCap->hw_caps |= ATH9K_HW_CAP_RAC_SUPPORTED; + if (AR_SREV_9300_20_OR_LATER(ah)) + ah->ent_mode = REG_READ(ah, AR_ENT_OTP); + if (AR_SREV_9287_11_OR_LATER(ah) || AR_SREV_9271(ah)) pCap->hw_caps |= ATH9K_HW_CAP_SGI_20; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index f821a28..15f51c8 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -803,6 +803,9 @@ struct ath_hw { * this register when in sleep states. */ u32 WARegVal; + + /* Enterprise mode cap */ + u32 ent_mode; }; static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah) diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index ac6a13e..60826b8 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -1067,6 +1067,7 @@ enum { #define AR_INTR_PRIO_ASYNC_ENABLE 0x40d4 #define AR_ENT_OTP 0x40d8 #define AR_ENT_OTP_CHAIN2_DISABLE 0x00020000 +#define AR_ENT_OTP_MPSD 0x00800000 #define AR_RTC_9300_PLL_DIV 0x000003ff #define AR_RTC_9300_PLL_DIV_S 0 -- cgit v0.10.2 From 7afbb2f07028183f50ae4f7ce4dab1f32b36cf48 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Wed, 10 Nov 2010 11:43:51 -0800 Subject: ath5k: Cleanup opmode setting logic. An earlier review suggested moving the code in a small method that was only called once inline. This patch accomplishes that. 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 fe116de..13735cc 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -549,7 +549,7 @@ static void ath_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) /* 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. + * interfaces is allowed. */ if (avf->opmode == NL80211_IFTYPE_AP) iter_data->opmode = NL80211_IFTYPE_AP; @@ -558,14 +558,6 @@ static void ath_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) iter_data->opmode = avf->opmode; } -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)); -} - static void ath5k_update_bssid_mask_and_opmode(struct ath5k_softc *sc, struct ieee80211_vif *vif) { @@ -595,7 +587,9 @@ static void ath5k_update_bssid_mask_and_opmode(struct ath5k_softc *sc, /* Nothing active, default to station mode */ sc->opmode = NL80211_IFTYPE_STATION; - ath_do_set_opmode(sc); + ath5k_hw_set_opmode(sc->ah, sc->opmode); + ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "mode setup opmode %d (%s)\n", + sc->opmode, ath_opmode_to_string(sc->opmode)); if (iter_data.need_set_hw_addr && iter_data.found_active) ath5k_hw_set_lladdr(sc->ah, iter_data.active_mac); -- cgit v0.10.2 From 1d666d8e05edf5891a7a4bd84a25f493f01dc71a Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 11 Nov 2010 03:18:34 +0100 Subject: ath9k: remove the unnecessary private xretry tx flag Signed-off-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 85c8e93..c052bd6 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -1370,7 +1370,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, is_underrun = 1; } - if (tx_info->pad[0] & ATH_TX_INFO_XRETRY) + if (!(tx_info->flags & IEEE80211_TX_STAT_ACK)) tx_status = 1; ath_rc_tx_status(sc, ath_rc_priv, tx_info, final_ts_idx, tx_status, diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h index 2f46a22..a1dce43 100644 --- a/drivers/net/wireless/ath/ath9k/rc.h +++ b/drivers/net/wireless/ath/ath9k/rc.h @@ -227,7 +227,6 @@ struct ath_rate_priv { #define ATH_TX_INFO_FRAME_TYPE_INTERNAL (1 << 0) #define ATH_TX_INFO_FRAME_TYPE_PAUSE (1 << 1) -#define ATH_TX_INFO_XRETRY (1 << 3) #define ATH_TX_INFO_UNDERRUN (1 << 4) enum ath9k_internal_frame_type { diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 6380bbd..eaaeb93 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1993,9 +1993,6 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts, if (ts->ts_flags & (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN)) tx_info->pad[0] |= ATH_TX_INFO_UNDERRUN; - if ((ts->ts_status & ATH9K_TXERR_XRETRY) || - (ts->ts_status & ATH9K_TXERR_FIFO)) - tx_info->pad[0] |= ATH_TX_INFO_XRETRY; } } -- cgit v0.10.2 From f0c255a07fe8a4d450cce6355a22b73ee0e9e6e0 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 11 Nov 2010 03:18:35 +0100 Subject: ath9k: handle tx underrun in the driver instead of rate control Signed-off-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 c052bd6..33bb33b 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -1354,22 +1354,6 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, 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, - * and 4 KB for dual stream). Adjust the long retry as if the frame was - * tried hw->max_rate_tries times to affect how ratectrl updates PER for - * the failed rate. In case of congestion on the bus penalizing these - * type of underruns should help hardware actually transmit new frames - * successfully by eventually preferring slower rates. This itself - * should also alleviate congestion on the bus. - */ - if ((tx_info->pad[0] & ATH_TX_INFO_UNDERRUN) && - (sc->sc_ah->tx_trig_level >= ath_rc_priv->tx_triglevel_max)) { - tx_status = 1; - is_underrun = 1; - } - if (!(tx_info->flags & IEEE80211_TX_STAT_ACK)) tx_status = 1; @@ -1596,8 +1580,6 @@ static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp return NULL; } - rate_priv->tx_triglevel_max = sc->sc_ah->caps.tx_triglevel_max; - return rate_priv; } diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h index a1dce43..a96f5eb 100644 --- a/drivers/net/wireless/ath/ath9k/rc.h +++ b/drivers/net/wireless/ath/ath9k/rc.h @@ -215,7 +215,6 @@ struct ath_rate_priv { u32 per_down_time; u32 probe_interval; u32 prev_data_rix; - u32 tx_triglevel_max; struct ath_rateset neg_rates; struct ath_rateset neg_ht_rates; struct ath_rate_softc *asc; @@ -227,7 +226,6 @@ struct ath_rate_priv { #define ATH_TX_INFO_FRAME_TYPE_INTERNAL (1 << 0) #define ATH_TX_INFO_FRAME_TYPE_PAUSE (1 << 1) -#define ATH_TX_INFO_UNDERRUN (1 << 4) enum ath9k_internal_frame_type { ATH9K_IFT_NOT_INTERNAL, diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index eaaeb93..8785ec3 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1968,6 +1968,8 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts, struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_hw *hw = bf->aphy->hw; + struct ath_softc *sc = bf->aphy->sc; + struct ath_hw *ah = sc->sc_ah; u8 i, tx_rateindex; if (txok) @@ -1989,11 +1991,24 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts, if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 && (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) { - if (ieee80211_is_data(hdr->frame_control)) { - if (ts->ts_flags & - (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN)) - tx_info->pad[0] |= ATH_TX_INFO_UNDERRUN; - } + /* + * If an underrun error is seen assume it as an excessive + * retry only if max frame trigger level has been reached + * (2 KB for single stream, and 4 KB for dual stream). + * Adjust the long retry as if the frame was tried + * hw->max_rate_tries times to affect how rate control updates + * PER for the failed rate. + * In case of congestion on the bus penalizing this type of + * underruns should help hardware actually transmit new frames + * successfully by eventually preferring slower rates. + * This itself should also alleviate congestion on the bus. + */ + if (ieee80211_is_data(hdr->frame_control) && + (ts->ts_flags & (ATH9K_TX_DATA_UNDERRUN | + ATH9K_TX_DELIM_UNDERRUN)) && + ah->tx_trig_level >= sc->sc_ah->caps.tx_triglevel_max) + tx_info->status.rates[tx_rateindex].count = + hw->max_rate_tries; } for (i = tx_rateindex + 1; i < hw->max_rates; i++) { -- cgit v0.10.2 From 61117f01e79f7c0da86c23535bed757370f5885f Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 11 Nov 2010 03:18:36 +0100 Subject: ath9k: remove the tx info padding byte abuse 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 92670ce..3e6ebe6 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -229,6 +229,7 @@ struct ath_buf_state { unsigned long bfs_paprd_timestamp; u32 bfs_keyix; enum ath9k_key_type bfs_keytype; + enum ath9k_internal_frame_type bfs_ftype; }; struct ath_buf { @@ -711,7 +712,7 @@ void ath9k_ps_restore(struct ath_softc *sc); void ath9k_set_bssid_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif); int ath9k_wiphy_add(struct ath_softc *sc); int ath9k_wiphy_del(struct ath_wiphy *aphy); -void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb); +void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, int ftype); int ath9k_wiphy_pause(struct ath_wiphy *aphy); int ath9k_wiphy_unpause(struct ath_wiphy *aphy); int ath9k_wiphy_select(struct ath_wiphy *aphy); diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h index a96f5eb..31a004c 100644 --- a/drivers/net/wireless/ath/ath9k/rc.h +++ b/drivers/net/wireless/ath/ath9k/rc.h @@ -224,9 +224,6 @@ struct ath_rate_priv { struct ath_rc_stats rcstats[RATE_TABLE_SIZE]; }; -#define ATH_TX_INFO_FRAME_TYPE_INTERNAL (1 << 0) -#define ATH_TX_INFO_FRAME_TYPE_PAUSE (1 << 1) - enum ath9k_internal_frame_type { ATH9K_IFT_NOT_INTERNAL, ATH9K_IFT_PAUSE, diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c index 4008f51..d5442c3 100644 --- a/drivers/net/wireless/ath/ath9k/virtual.c +++ b/drivers/net/wireless/ath/ath9k/virtual.c @@ -305,13 +305,12 @@ void ath9k_wiphy_chan_work(struct work_struct *work) * ath9k version of ieee80211_tx_status() for TX frames that are generated * internally in the driver. */ -void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) +void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, int ftype) { struct ath_wiphy *aphy = hw->priv; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - if ((tx_info->pad[0] & ATH_TX_INFO_FRAME_TYPE_PAUSE) && - aphy->state == ATH_WIPHY_PAUSING) { + if (ftype == ATH9K_IFT_PAUSE && aphy->state == ATH_WIPHY_PAUSING) { if (!(tx_info->flags & IEEE80211_TX_STAT_ACK)) { printk(KERN_DEBUG "ath9k: %s: no ACK for pause " "frame\n", wiphy_name(hw->wiphy)); diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 8785ec3..32e2267 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1580,17 +1580,6 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, int padpos, padsize; bool use_ldpc = false; - tx_info->pad[0] = 0; - switch (txctl->frame_type) { - case ATH9K_IFT_NOT_INTERNAL: - break; - case ATH9K_IFT_PAUSE: - tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_PAUSE; - /* fall through */ - case ATH9K_IFT_UNPAUSE: - tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_INTERNAL; - break; - } hdrlen = ieee80211_get_hdrlen_from_skb(skb); fc = hdr->frame_control; @@ -1711,6 +1700,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, tid, &bf_head); } } else { + bf->bf_state.bfs_ftype = txctl->frame_type; ath_tx_send_normal(sc, txctl->txq, &bf_head); } @@ -1828,7 +1818,7 @@ exit: /*****************/ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, - struct ath_wiphy *aphy, int tx_flags, + struct ath_wiphy *aphy, int tx_flags, int ftype, struct ath_txq *txq) { struct ieee80211_hw *hw = sc->hw; @@ -1872,8 +1862,8 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, PS_WAIT_FOR_TX_ACK)); } - if (unlikely(tx_info->pad[0] & ATH_TX_INFO_FRAME_TYPE_INTERNAL)) - ath9k_tx_status(hw, skb); + if (unlikely(ftype)) + ath9k_tx_status(hw, skb, ftype); else { q = skb_get_queue_mapping(skb); if (txq == sc->tx.txq_map[q]) { @@ -1917,7 +1907,8 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, complete(&sc->paprd_complete); } else { ath_debug_stat_tx(sc, bf, ts); - ath_tx_complete(sc, skb, bf->aphy, tx_flags, txq); + ath_tx_complete(sc, skb, bf->aphy, tx_flags, + bf->bf_state.bfs_ftype, txq); } /* At this point, skb (bf->bf_mpdu) is consumed...make sure we don't * accidentally reference it later. -- cgit v0.10.2 From 82b873afe83c81d9b1273a816bbdacb266f71a52 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 11 Nov 2010 03:18:37 +0100 Subject: ath9k: clean up tx buffer setup Merge ath_tx_send_normal and ath_tx_send_ht_normal. Move the paprd state initialization and sequence number assignment to reduce the number of redundant checks. This not only simplifies buffer allocation error handling, but also removes a small inconsistency in the buffer HT flag. This flag should only be set if the frame is also a QoS data frame. Signed-off-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 32e2267..8ba0e2d 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -48,9 +48,9 @@ static u16 bits_per_symbol[][2] = { #define IS_HT_RATE(_rate) ((_rate) & 0x80) -static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq, - struct ath_atx_tid *tid, - struct list_head *bf_head); +static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, + struct ath_atx_tid *tid, + struct list_head *bf_head); static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, struct ath_txq *txq, struct list_head *bf_q, struct ath_tx_status *ts, int txok, int sendbar); @@ -160,7 +160,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) ath_tx_update_baw(sc, tid, bf->bf_seqno); ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0); } else { - ath_tx_send_ht_normal(sc, txq, tid, &bf_head); + ath_tx_send_normal(sc, txq, tid, &bf_head); } } @@ -1322,9 +1322,9 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, ath_tx_txqaddbuf(sc, txctl->txq, bf_head); } -static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq, - struct ath_atx_tid *tid, - struct list_head *bf_head) +static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, + struct ath_atx_tid *tid, + struct list_head *bf_head) { struct ath_buf *bf; @@ -1332,7 +1332,8 @@ static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq, bf->bf_state.bf_type &= ~BUF_AMPDU; /* update starting sequence number for subsequent ADDBA request */ - INCR(tid->seq_start, IEEE80211_SEQ_MAX); + if (tid) + INCR(tid->seq_start, IEEE80211_SEQ_MAX); bf->bf_nframes = 1; bf->bf_lastbf = bf; @@ -1341,20 +1342,6 @@ static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq, TX_STAT_INC(txq->axq_qnum, queued); } -static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, - struct list_head *bf_head) -{ - struct ath_buf *bf; - - bf = list_first_entry(bf_head, struct ath_buf, list); - - bf->bf_lastbf = bf; - bf->bf_nframes = 1; - ath_buf_set_rate(sc, bf); - ath_tx_txqaddbuf(sc, txq, bf_head); - TX_STAT_INC(txq->axq_qnum, queued); -} - static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb) { struct ieee80211_hdr *hdr; @@ -1411,7 +1398,7 @@ static void assign_aggr_tid_seqno(struct sk_buff *skb, INCR(tid->seq_next, IEEE80211_SEQ_MAX); } -static int setup_tx_flags(struct sk_buff *skb, bool use_ldpc) +static int setup_tx_flags(struct sk_buff *skb) { struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); int flags = 0; @@ -1422,7 +1409,7 @@ static int setup_tx_flags(struct sk_buff *skb, bool use_ldpc) if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) flags |= ATH9K_TXDESC_NOACK; - if (use_ldpc) + if (tx_info->flags & IEEE80211_TX_CTL_LDPC) flags |= ATH9K_TXDESC_LDPC; return flags; @@ -1567,18 +1554,24 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) ath9k_hw_set11n_burstduration(sc->sc_ah, bf->bf_desc, 8192); } -static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, - struct sk_buff *skb, - struct ath_tx_control *txctl) +static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw, + struct sk_buff *skb) { struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ath_buf *bf; int hdrlen; __le16 fc; int padpos, padsize; - bool use_ldpc = false; + + bf = ath_tx_get_buffer(sc); + if (!bf) { + ath_print(common, ATH_DBG_XMIT, "TX buffers are full\n"); + return NULL; + } hdrlen = ieee80211_get_hdrlen_from_skb(skb); fc = hdr->frame_control; @@ -1594,16 +1587,13 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, bf->bf_frmlen -= padsize; } - if (!txctl->paprd && conf_is_ht(&hw->conf)) { + if (ieee80211_is_data_qos(fc) && conf_is_ht(&hw->conf)) { bf->bf_state.bf_type |= BUF_HT; - if (tx_info->flags & IEEE80211_TX_CTL_LDPC) - use_ldpc = true; + if (sc->sc_flags & SC_OP_TXAGGR) + assign_aggr_tid_seqno(skb, bf); } - bf->bf_state.bfs_paprd = txctl->paprd; - if (txctl->paprd) - bf->bf_state.bfs_paprd_timestamp = jiffies; - bf->bf_flags = setup_tx_flags(skb, use_ldpc); + bf->bf_flags = setup_tx_flags(skb); bf->bf_keytype = ath9k_cmn_get_hw_crypto_keytype(skb); if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR) { @@ -1613,10 +1603,6 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, bf->bf_keyix = ATH9K_TXKEYIX_INVALID; } - if (ieee80211_is_data_qos(fc) && bf_isht(bf) && - (sc->sc_flags & SC_OP_TXAGGR)) - assign_aggr_tid_seqno(skb, bf); - bf->bf_mpdu = skb; bf->bf_buf_addr = dma_map_single(sc->dev, skb->data, @@ -1626,12 +1612,13 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, bf->bf_buf_addr = 0; ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL, "dma_mapping_error() on TX\n"); - return -ENOMEM; + ath_tx_return_buffer(sc, bf); + return NULL; } bf->bf_tx_aborted = false; - return 0; + return bf; } /* FIXME: tx power */ @@ -1679,11 +1666,6 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, an = (struct ath_node *)tx_info->control.sta->drv_priv; tid = ATH_AN_2_TID(an, bf->bf_tidno); - if (!ieee80211_is_data_qos(fc)) { - ath_tx_send_normal(sc, txctl->txq, &bf_head); - goto tx_done; - } - WARN_ON(tid->ac->txq != txctl->txq); if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { /* @@ -1696,15 +1678,18 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, * Send this frame as regular when ADDBA * exchange is neither complete nor pending. */ - ath_tx_send_ht_normal(sc, txctl->txq, - tid, &bf_head); + ath_tx_send_normal(sc, txctl->txq, tid, &bf_head); } } else { bf->bf_state.bfs_ftype = txctl->frame_type; - ath_tx_send_normal(sc, txctl->txq, &bf_head); + bf->bf_state.bfs_paprd = txctl->paprd; + + if (txctl->paprd) + bf->bf_state.bfs_paprd_timestamp = jiffies; + + ath_tx_send_normal(sc, txctl->txq, NULL, &bf_head); } -tx_done: spin_unlock_bh(&txctl->txq->axq_lock); } @@ -1714,39 +1699,15 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, { struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; - struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_txq *txq = txctl->txq; struct ath_buf *bf; - int q, r; + int q; - bf = ath_tx_get_buffer(sc); - if (!bf) { - ath_print(common, ATH_DBG_XMIT, "TX buffers are full\n"); - return -1; - } + bf = ath_tx_setup_buffer(hw, skb); + if (unlikely(!bf)) + return -ENOMEM; q = skb_get_queue_mapping(skb); - r = ath_tx_setup_buffer(hw, bf, skb, txctl); - if (unlikely(r)) { - ath_print(common, ATH_DBG_FATAL, "TX mem alloc failure\n"); - - /* upon ath_tx_processq() this TX queue will be resumed, we - * guarantee this will happen by knowing beforehand that - * we will at least have to run TX completionon one buffer - * on the queue */ - spin_lock_bh(&txq->axq_lock); - if (txq == sc->tx.txq_map[q] && !txq->stopped && - txq->axq_depth > 1) { - ath_mac80211_stop_queue(sc, q); - txq->stopped = 1; - } - spin_unlock_bh(&txq->axq_lock); - - ath_tx_return_buffer(sc, bf); - - return r; - } - spin_lock_bh(&txq->axq_lock); if (txq == sc->tx.txq_map[q] && ++txq->pending_frames > ATH_MAX_QDEPTH && !txq->stopped) { -- cgit v0.10.2 From 4e8c14e9587c38f4cce8049c766935629fdb8d46 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 11 Nov 2010 03:18:38 +0100 Subject: ath9k_hw: add a private op for configuring radar pulse detection Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index c83a22c..3686811 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -1579,6 +1579,37 @@ static void ar5008_hw_set_nf_limits(struct ath_hw *ah) ah->nf_5g.nominal = AR_PHY_CCA_NOM_VAL_5416_5GHZ; } +static void ar5008_hw_set_radar_params(struct ath_hw *ah, + struct ath_hw_radar_conf *conf) +{ + u32 radar_0 = 0, radar_1 = 0; + + if (!conf) { + REG_CLR_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_ENA); + return; + } + + radar_0 |= AR_PHY_RADAR_0_ENA | AR_PHY_RADAR_0_FFT_ENA; + radar_0 |= SM(conf->fir_power, AR_PHY_RADAR_0_FIRPWR); + radar_0 |= SM(conf->radar_rssi, AR_PHY_RADAR_0_RRSSI); + radar_0 |= SM(conf->pulse_height, AR_PHY_RADAR_0_HEIGHT); + radar_0 |= SM(conf->pulse_rssi, AR_PHY_RADAR_0_PRSSI); + radar_0 |= SM(conf->pulse_inband, AR_PHY_RADAR_0_INBAND); + + radar_1 |= AR_PHY_RADAR_1_MAX_RRSSI; + radar_1 |= AR_PHY_RADAR_1_BLOCK_CHECK; + radar_1 |= SM(conf->pulse_maxlen, AR_PHY_RADAR_1_MAXLEN); + radar_1 |= SM(conf->pulse_inband_step, AR_PHY_RADAR_1_RELSTEP_THRESH); + radar_1 |= SM(conf->radar_inband, AR_PHY_RADAR_1_RELPWR_THRESH); + + REG_WRITE(ah, AR_PHY_RADAR_0, radar_0); + REG_WRITE(ah, AR_PHY_RADAR_1, radar_1); + if (conf->ext_channel) + REG_SET_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA); + else + REG_CLR_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA); +} + void ar5008_hw_attach_phy_ops(struct ath_hw *ah) { struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); @@ -1609,6 +1640,7 @@ void ar5008_hw_attach_phy_ops(struct ath_hw *ah) priv_ops->restore_chainmask = ar5008_restore_chainmask; priv_ops->set_diversity = ar5008_set_diversity; priv_ops->do_getnf = ar5008_hw_do_getnf; + priv_ops->set_radar_params = ar5008_hw_set_radar_params; if (modparam_force_new_ani) { priv_ops->ani_control = ar5008_hw_ani_control_new; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 44c5454..f676b21 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -1113,6 +1113,37 @@ static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah) aniState->mrcCCKOff = !ATH9K_ANI_ENABLE_MRC_CCK; } +static void ar9003_hw_set_radar_params(struct ath_hw *ah, + struct ath_hw_radar_conf *conf) +{ + u32 radar_0 = 0, radar_1 = 0; + + if (!conf) { + REG_CLR_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_ENA); + return; + } + + radar_0 |= AR_PHY_RADAR_0_ENA | AR_PHY_RADAR_0_FFT_ENA; + radar_0 |= SM(conf->fir_power, AR_PHY_RADAR_0_FIRPWR); + radar_0 |= SM(conf->radar_rssi, AR_PHY_RADAR_0_RRSSI); + radar_0 |= SM(conf->pulse_height, AR_PHY_RADAR_0_HEIGHT); + radar_0 |= SM(conf->pulse_rssi, AR_PHY_RADAR_0_PRSSI); + radar_0 |= SM(conf->pulse_inband, AR_PHY_RADAR_0_INBAND); + + radar_1 |= AR_PHY_RADAR_1_MAX_RRSSI; + radar_1 |= AR_PHY_RADAR_1_BLOCK_CHECK; + radar_1 |= SM(conf->pulse_maxlen, AR_PHY_RADAR_1_MAXLEN); + radar_1 |= SM(conf->pulse_inband_step, AR_PHY_RADAR_1_RELSTEP_THRESH); + radar_1 |= SM(conf->radar_inband, AR_PHY_RADAR_1_RELPWR_THRESH); + + REG_WRITE(ah, AR_PHY_RADAR_0, radar_0); + REG_WRITE(ah, AR_PHY_RADAR_1, radar_1); + if (conf->ext_channel) + REG_SET_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA); + else + REG_CLR_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA); +} + void ar9003_hw_attach_phy_ops(struct ath_hw *ah) { struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); @@ -1141,6 +1172,7 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah) priv_ops->ani_control = ar9003_hw_ani_control; priv_ops->do_getnf = ar9003_hw_do_getnf; priv_ops->ani_cache_ini_regs = ar9003_hw_ani_cache_ini_regs; + priv_ops->set_radar_params = ar9003_hw_set_radar_params; ar9003_hw_set_nf_limits(ah); memcpy(ah->nf_regs, ar9300_cca_regs, sizeof(ah->nf_regs)); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 15f51c8..c20a542 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -485,6 +485,40 @@ struct ath_hw_antcomb_conf { }; /** + * struct ath_hw_radar_conf - radar detection initialization parameters + * + * @pulse_inband: threshold for checking the ratio of in-band power + * to total power for short radar pulses (half dB steps) + * @pulse_inband_step: threshold for checking an in-band power to total + * power ratio increase for short radar pulses (half dB steps) + * @pulse_height: threshold for detecting the beginning of a short + * radar pulse (dB step) + * @pulse_rssi: threshold for detecting if a short radar pulse is + * gone (dB step) + * @pulse_maxlen: maximum pulse length (0.8 us steps) + * + * @radar_rssi: RSSI threshold for starting long radar detection (dB steps) + * @radar_inband: threshold for checking the ratio of in-band power + * to total power for long radar pulses (half dB steps) + * @fir_power: threshold for detecting the end of a long radar pulse (dB) + * + * @ext_channel: enable extension channel radar detection + */ +struct ath_hw_radar_conf { + unsigned int pulse_inband; + unsigned int pulse_inband_step; + unsigned int pulse_height; + unsigned int pulse_rssi; + unsigned int pulse_maxlen; + + unsigned int radar_rssi; + unsigned int radar_inband; + int fir_power; + + bool ext_channel; +}; + +/** * struct ath_hw_private_ops - callbacks used internally by hardware code * * This structure contains private callbacks designed to only be used internally @@ -549,6 +583,8 @@ struct ath_hw_private_ops { bool (*ani_control)(struct ath_hw *ah, enum ath9k_ani_cmd cmd, int param); void (*do_getnf)(struct ath_hw *ah, int16_t nfarray[NUM_NF_READINGS]); + void (*set_radar_params)(struct ath_hw *ah, + struct ath_hw_radar_conf *conf); /* ANI */ void (*ani_cache_ini_regs)(struct ath_hw *ah); -- cgit v0.10.2 From a619a4c0e1fd4e8c360c63d0df3fa0a401107d69 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Thu, 11 Nov 2010 08:50:18 +0200 Subject: mac80211: Add function to get probe request template for current AP Chipsets with hardware based connection monitoring need to autonomically send directed probe-request frames to the AP (in the event of beacon loss, for example.) For the hardware to be able to do this, it requires a template for the frame to transmit to the AP, filled in with the BSSID and SSID of the AP, but also the supported rate IE's. This patch adds a function to mac80211, which allows the hardware driver to fetch this template after association, so it can be configured to the hardware. Signed-off-by: Juuso Oikarinen Acked-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/mac80211.h b/include/net/mac80211.h index a7323ec..af7e841 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2509,6 +2509,21 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw, struct ieee80211_sta *pubsta, bool block); /** + * ieee80211_ap_probereq_get - retrieve a Probe Request template + * @hw: pointer obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * + * Creates a Probe Request template which can, for example, be uploaded to + * hardware. The template is filled with bssid, ssid and supported rate + * information. This function must only be called from within the + * .bss_info_changed callback function and only in managed mode. The function + * is only useful when the interface is associated, otherwise it will return + * NULL. + */ +struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); + +/** * ieee80211_beacon_loss - inform hardware does not receive beacons * * @vif: &struct ieee80211_vif pointer from the add_interface callback. diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index b80c386..59a1d38 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1287,6 +1287,10 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, const u8 *ie, size_t ie_len, enum ieee80211_band band, u32 rate_mask, u8 channel); +struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, + u8 *dst, + const u8 *ssid, size_t ssid_len, + const u8 *ie, size_t ie_len); void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, const u8 *ssid, size_t ssid_len, const u8 *ie, size_t ie_len); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index a3a9421..dfc4a31 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1108,6 +1108,30 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, mutex_unlock(&ifmgd->mtx); } +struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct sk_buff *skb; + const u8 *ssid; + + if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) + return NULL; + + ASSERT_MGD_MTX(ifmgd); + + if (!ifmgd->associated) + return NULL; + + ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); + skb = ieee80211_build_probe_req(sdata, ifmgd->associated->bssid, + ssid + 2, ssid[1], NULL, 0); + + return skb; +} +EXPORT_SYMBOL(ieee80211_ap_probereq_get); + static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index e486286..68d0518 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1011,9 +1011,10 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, return pos - buffer; } -void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, - const u8 *ssid, size_t ssid_len, - const u8 *ie, size_t ie_len) +struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, + u8 *dst, + const u8 *ssid, size_t ssid_len, + const u8 *ie, size_t ie_len) { struct ieee80211_local *local = sdata->local; struct sk_buff *skb; @@ -1027,7 +1028,7 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, if (!buf) { printk(KERN_DEBUG "%s: failed to allocate temporary IE " "buffer\n", sdata->name); - return; + return NULL; } chan = ieee80211_frequency_to_channel( @@ -1050,8 +1051,20 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, } IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; - ieee80211_tx_skb(sdata, skb); kfree(buf); + + return skb; +} + +void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, + const u8 *ssid, size_t ssid_len, + const u8 *ie, size_t ie_len) +{ + struct sk_buff *skb; + + skb = ieee80211_build_probe_req(sdata, dst, ssid, ssid_len, ie, ie_len); + if (skb) + ieee80211_tx_skb(sdata, skb); } u32 ieee80211_sta_get_rates(struct ieee80211_local *local, -- cgit v0.10.2 From 885a46d0f7942d76c2f3860acb45f75237d3bb42 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 11 Nov 2010 15:07:22 +0100 Subject: cfg80211: add support for setting the ad-hoc multicast rate Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 17c5c88..037b4e4 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -826,6 +826,8 @@ enum nl80211_commands { * the hardware should not be configured to receive on this antenna. * For a more detailed descripton see @NL80211_ATTR_WIPHY_ANTENNA_TX. * + * @NL80211_ATTR_MCAST_RATE: Multicast tx rate (in 100 kbps) for IBSS + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -998,6 +1000,8 @@ enum nl80211_attrs { NL80211_ATTR_WIPHY_ANTENNA_TX, NL80211_ATTR_WIPHY_ANTENNA_RX, + NL80211_ATTR_MCAST_RATE, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 07425e6..8fd9eeb 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -923,6 +923,7 @@ struct cfg80211_disassoc_request { * @privacy: this is a protected network, keys will be configured * after joining * @basic_rates: bitmap of basic rates to use when creating the IBSS + * @mcast_rate: multicast tx rate (in 100 kbps) */ struct cfg80211_ibss_params { u8 *ssid; @@ -934,6 +935,7 @@ struct cfg80211_ibss_params { u32 basic_rates; bool channel_fixed; bool privacy; + int mcast_rate; }; /** diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 5e4dda4..6055538 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -171,6 +171,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { [NL80211_ATTR_WIPHY_ANTENNA_TX] = { .type = NLA_U32 }, [NL80211_ATTR_WIPHY_ANTENNA_RX] = { .type = NLA_U32 }, + + [NL80211_ATTR_MCAST_RATE] = { .type = NLA_U32 }, }; /* policy for the key attributes */ @@ -3681,6 +3683,9 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) return -EINVAL; } } + if (info->attrs[NL80211_ATTR_MCAST_RATE]) + ibss.mcast_rate = + nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE]); if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) { connkeys = nl80211_parse_connkeys(rdev, -- cgit v0.10.2 From 8f0729b16ae354f9db89394fc1d2d65003455d56 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 11 Nov 2010 15:07:23 +0100 Subject: mac80211: add support for setting the ad-hoc multicast rate Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/include/net/mac80211.h b/include/net/mac80211.h index af7e841..1248369 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -205,6 +205,7 @@ enum ieee80211_bss_change { * @basic_rates: bitmap of basic rates, each bit stands for an * index into the rate table configured by the driver in * the current band. + * @mcast_rate: multicast rate for AP and Ad-Hoc (in 100 kbps) * @bssid: The BSSID for this BSS * @enable_beacon: whether beaconing should be enabled or not * @channel_type: Channel type for this BSS -- the hardware might be @@ -244,6 +245,7 @@ struct ieee80211_bss_conf { u16 assoc_capability; u64 timestamp; u32 basic_rates; + u32 mcast_rate; u16 ht_operation_mode; s32 cqm_rssi_thold; u32 cqm_rssi_hyst; @@ -2663,7 +2665,7 @@ enum rate_control_changed { * @rate_idx_mask: user-requested rate mask (not MCS for now) * @skb: the skb that will be transmitted, the control information in it needs * to be filled in - * @ap: whether this frame is sent out in AP mode + * @bss: whether this frame is sent out in AP or IBSS mode */ struct ieee80211_tx_rate_control { struct ieee80211_hw *hw; @@ -2674,7 +2676,7 @@ struct ieee80211_tx_rate_control { bool rts, short_preamble; u8 max_rate_idx; u32 rate_idx_mask; - bool ap; + bool bss; }; struct rate_control_ops { diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 239c483..6fe6837 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -915,6 +915,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, sdata->u.ibss.privacy = params->privacy; sdata->u.ibss.basic_rates = params->basic_rates; + sdata->vif.bss_conf.mcast_rate = params->mcast_rate; sdata->vif.bss_conf.beacon_int = params->beacon_interval; diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 33f7699..76de4f8 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -211,10 +211,20 @@ static bool rc_no_data_or_no_ack(struct ieee80211_tx_rate_control *txrc) return (info->flags & IEEE80211_TX_CTL_NO_ACK) || !ieee80211_is_data(fc); } -static void rc_send_low_broadcast(s8 *idx, u32 basic_rates, u8 max_rate_idx) +static void rc_send_low_broadcast(s8 *idx, u32 basic_rates, u32 mcast_rate, + struct ieee80211_supported_band *sband) { u8 i; + if (mcast_rate) { + for (i = 0; i < sband->n_bitrates; i++) { + if (sband->bitrates[i].bitrate == mcast_rate) { + *idx = i; + return; + } + } + } + if (basic_rates == 0) return; /* assume basic rates unknown and accept rate */ if (*idx < 0) @@ -222,7 +232,7 @@ static void rc_send_low_broadcast(s8 *idx, u32 basic_rates, u8 max_rate_idx) if (basic_rates & (1 << *idx)) return; /* selected rate is a basic rate */ - for (i = *idx + 1; i <= max_rate_idx; i++) { + for (i = *idx + 1; i <= sband->n_bitrates; i++) { if (basic_rates & (1 << i)) { *idx = i; return; @@ -243,10 +253,11 @@ bool rate_control_send_low(struct ieee80211_sta *sta, info->control.rates[0].count = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? 1 : txrc->hw->max_rate_tries; - if (!sta && txrc->ap) + if (!sta && txrc->bss) rc_send_low_broadcast(&info->control.rates[0].idx, txrc->bss_conf->basic_rates, - txrc->sband->n_bitrates); + txrc->bss_conf->mcast_rate, + txrc->sband); return true; } return false; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index b392876..e694836 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -622,7 +622,8 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) txrc.max_rate_idx = -1; else txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1; - txrc.ap = tx->sdata->vif.type == NL80211_IFTYPE_AP; + txrc.bss = (tx->sdata->vif.type == NL80211_IFTYPE_AP || + tx->sdata->vif.type == NL80211_IFTYPE_ADHOC); /* set up RTS protection if desired */ if (len > tx->local->hw.wiphy->rts_threshold) { @@ -2308,7 +2309,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, txrc.max_rate_idx = -1; else txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1; - txrc.ap = true; + txrc.bss = true; rate_control_get_rate(sdata, NULL, &txrc); info->control.vif = vif; -- cgit v0.10.2 From 2cb7865648e44647a976875428c9dfd9d5553221 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Fri, 12 Nov 2010 08:47:05 +0100 Subject: iwl3945: remove unused len_org variable Signed-off-by: Stanislaw Gruszka Acked-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index a55b462..6d09c09 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -475,7 +475,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) dma_addr_t phys_addr; dma_addr_t txcmd_phys; int txq_id = skb_get_queue_mapping(skb); - u16 len, idx, len_org, hdr_len; /* TODO: len_org is not used */ + u16 len, idx, hdr_len; u8 id; u8 unicast; u8 sta_id; @@ -612,15 +612,8 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) */ len = sizeof(struct iwl3945_tx_cmd) + sizeof(struct iwl_cmd_header) + hdr_len; - - len_org = len; len = (len + 3) & ~3; - if (len_org != len) - len_org = 1; - else - len_org = 0; - /* Physical address of this Tx command's header (not MAC header!), * within command buffer array. */ txcmd_phys = pci_map_single(priv->pci_dev, &out_cmd->hdr, -- cgit v0.10.2 From 70f3876f09ccf1f2819aee6caee9266b2c4b1622 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Fri, 12 Nov 2010 08:47:06 +0100 Subject: iwlagn: simplify iwlagn_tx_skb We can simplify length calculation in iwlagn_tx_skb, that function is enough complex, without fuzz it more than necessary. Signed-off-by: Stanislaw Gruszka Acked-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index 2b078a9..1205cec 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -522,7 +522,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) dma_addr_t phys_addr; dma_addr_t txcmd_phys; dma_addr_t scratch_phys; - u16 len, len_org, firstlen, secondlen; + u16 len, firstlen, secondlen; u16 seq_number = 0; __le16 fc; u8 hdr_len; @@ -687,30 +687,23 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) */ len = sizeof(struct iwl_tx_cmd) + sizeof(struct iwl_cmd_header) + hdr_len; - - len_org = len; - firstlen = len = (len + 3) & ~3; - - if (len_org != len) - len_org = 1; - else - len_org = 0; + firstlen = (len + 3) & ~3; /* Tell NIC about any 2-byte padding after MAC header */ - if (len_org) + if (firstlen != len) tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK; /* Physical address of this Tx command's header (not MAC header!), * within command buffer array. */ txcmd_phys = pci_map_single(priv->pci_dev, - &out_cmd->hdr, len, + &out_cmd->hdr, firstlen, PCI_DMA_BIDIRECTIONAL); dma_unmap_addr_set(out_meta, mapping, txcmd_phys); - dma_unmap_len_set(out_meta, len, len); + dma_unmap_len_set(out_meta, len, firstlen); /* Add buffer containing Tx command and MAC(!) header to TFD's * first entry */ priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq, - txcmd_phys, len, 1, 0); + txcmd_phys, firstlen, 1, 0); if (!ieee80211_has_morefrags(hdr->frame_control)) { txq->need_update = 1; @@ -721,23 +714,21 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) /* Set up TFD's 2nd entry to point directly to remainder of skb, * if any (802.11 null frames have no payload). */ - secondlen = len = skb->len - hdr_len; - if (len) { + secondlen = skb->len - hdr_len; + if (secondlen > 0) { phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len, - len, PCI_DMA_TODEVICE); + secondlen, PCI_DMA_TODEVICE); priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq, - phys_addr, len, + phys_addr, secondlen, 0, 0); } scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) + offsetof(struct iwl_tx_cmd, scratch); - len = sizeof(struct iwl_tx_cmd) + - sizeof(struct iwl_cmd_header) + hdr_len; /* take back ownership of DMA buffer to enable update */ pci_dma_sync_single_for_cpu(priv->pci_dev, txcmd_phys, - len, PCI_DMA_BIDIRECTIONAL); + firstlen, PCI_DMA_BIDIRECTIONAL); tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys); tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys); @@ -753,7 +744,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) le16_to_cpu(tx_cmd->len)); pci_dma_sync_single_for_device(priv->pci_dev, txcmd_phys, - len, PCI_DMA_BIDIRECTIONAL); + firstlen, PCI_DMA_BIDIRECTIONAL); trace_iwlwifi_dev_tx(priv, &((struct iwl_tfd *)txq->tfds)[txq->q.write_ptr], -- cgit v0.10.2 From ef1b21f7eb074a8c8ddfea70ed70e988545c8d54 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Fri, 12 Nov 2010 08:47:07 +0100 Subject: iwlwifi: kill elapsed_jiffies Subtract of jiffies is fine even if one variable overwrap. Signed-off-by: Stanislaw Gruszka Acked-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h index 1aaef70..9233683 100644 --- a/drivers/net/wireless/iwlwifi/iwl-helpers.h +++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h @@ -44,15 +44,6 @@ static inline struct ieee80211_conf *ieee80211_get_hw_conf( return &hw->conf; } -static inline unsigned long elapsed_jiffies(unsigned long start, - unsigned long end) -{ - if (end >= start) - return end - start; - - return end + (MAX_JIFFY_OFFSET - start) + 1; -} - /** * iwl_queue_inc_wrap - increment queue index, wrap back to beginning * @index -- current index diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index e1aa0e1..12d9363 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -252,8 +252,7 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv, IWL_DEBUG_SCAN(priv, "Scan on %sGHz took %dms\n", (priv->scan_band == IEEE80211_BAND_2GHZ) ? "2.4" : "5.2", - jiffies_to_msecs(elapsed_jiffies - (priv->scan_start, jiffies))); + jiffies_to_msecs(jiffies - priv->scan_start)); queue_work(priv->workqueue, &priv->scan_completed); -- cgit v0.10.2 From 28d9cc7f21da6a70fc8c1516fa0ee5588572eb92 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Sat, 13 Nov 2010 20:58:27 +0530 Subject: ath9k_htc: Use macro for caldata array size The calibration data variable size is based on the number of channels available in the ath9k driver. Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 75ecf6a..db00289 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -368,7 +368,7 @@ struct ath9k_htc_priv { u16 seq_no; u32 bmiss_cnt; - struct ath9k_hw_cal_data caldata[38]; + struct ath9k_hw_cal_data caldata[ATH9K_NUM_CHANNELS]; spinlock_t beacon_lock; -- cgit v0.10.2 From ae4ecb9f8f01eb9deffb5bd837dc90f4e646cd2d Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 13 Nov 2010 19:08:14 +0100 Subject: rt2x00: Increase REGISTER_BUSY_COUNT For some hardware the REGISTER_BUSY_COUNT isn't sufficient, increase the REGISTER_BUSY_COUNT to 100 to catch most devices which have more problems with accessing the registers. For normal operating devices nothing would change as they will exit the loop early anyway. 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 42bd3a9..0a55eef 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -915,7 +915,7 @@ struct rt2x00_dev { * in those cases REGISTER_BUSY_COUNT attempts should be * taken with a REGISTER_BUSY_DELAY interval. */ -#define REGISTER_BUSY_COUNT 5 +#define REGISTER_BUSY_COUNT 100 #define REGISTER_BUSY_DELAY 100 /* -- cgit v0.10.2 From f93bc9b3ce379800b30b3c2f4fc945ae35a80039 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Sat, 13 Nov 2010 19:09:50 +0100 Subject: rt2x00: Add initial support for RT3370/RT3390 devices. Modified from Eddy's patch by adding the RT3370 USB support as well. Signed-off-by: Gertjan van Wingerde Cc: Eddy Tsai Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index eea1ef2..f0f0152 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -96,6 +96,17 @@ config RT2800PCI_RT30XX Support for these devices is non-functional at the moment and is intended for testers and developers. +config RT2800PCI_RT33XX + bool "rt2800pci - Include support for rt33xx (PCI/PCIe/PCMCIA) devices" + default n + ---help--- + This adds support for rt33xx wireless chipset family to the + rt2800pci driver. + Supported chips: RT3390 + + Support for these devices is non-functional at the moment and is + intended for testers and developers. + config RT2800PCI_RT35XX bool "rt2800pci - Include support for rt35xx (PCI/PCIe/PCMCIA) devices" default n @@ -165,6 +176,17 @@ config RT2800USB_RT30XX Support for these devices is non-functional at the moment and is intended for testers and developers. +config RT2800USB_RT33XX + bool "rt2800usb - Include support for rt33xx (USB) devices" + default n + ---help--- + This adds support for rt33xx wireless chipset family to the + rt2800usb driver. + Supported chips: RT3370 + + Support for these devices is non-functional at the moment and is + intended for testers and developers. + config RT2800USB_RT35XX bool "rt2800usb - Include support for rt35xx (USB) devices" default n diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index 002224c..a81c437 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -47,6 +47,7 @@ * RF3021 2.4G 1T2R * RF3022 2.4G 2T2R * RF3052 2.4G 2T2R + * RF3320 2.4G 1T1R */ #define RF2820 0x0001 #define RF2850 0x0002 diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index b5d2eba..ce8df66 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1544,7 +1544,8 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, rt2x00_rf(rt2x00dev, RF3020) || rt2x00_rf(rt2x00dev, RF3021) || rt2x00_rf(rt2x00dev, RF3022) || - rt2x00_rf(rt2x00dev, RF3052)) + rt2x00_rf(rt2x00dev, RF3052) || + rt2x00_rf(rt2x00dev, RF3320)) rt2800_config_channel_rf3xxx(rt2x00dev, conf, rf, info); else rt2800_config_channel_rf2xxx(rt2x00dev, conf, rf, info); @@ -3012,7 +3013,8 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) !rt2x00_rf(rt2x00dev, RF2020) && !rt2x00_rf(rt2x00dev, RF3021) && !rt2x00_rf(rt2x00dev, RF3022) && - !rt2x00_rf(rt2x00dev, RF3052)) { + !rt2x00_rf(rt2x00dev, RF3052) && + !rt2x00_rf(rt2x00dev, RF3320)) { ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); return -ENODEV; } @@ -3276,7 +3278,8 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) } else if (rt2x00_rf(rt2x00dev, RF3020) || rt2x00_rf(rt2x00dev, RF2020) || rt2x00_rf(rt2x00dev, RF3021) || - rt2x00_rf(rt2x00dev, RF3022)) { + rt2x00_rf(rt2x00dev, RF3022) || + rt2x00_rf(rt2x00dev, RF3320)) { spec->num_channels = 14; spec->channels = rf_vals_3x; } else if (rt2x00_rf(rt2x00dev, RF3052)) { diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 5f3a018..6642f13 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -1051,6 +1051,9 @@ static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = { { PCI_DEVICE(0x1814, 0x3092), PCI_DEVICE_DATA(&rt2800pci_ops) }, { PCI_DEVICE(0x1462, 0x891a), PCI_DEVICE_DATA(&rt2800pci_ops) }, #endif +#ifdef CONFIG_RT2800PCI_RT33XX + { PCI_DEVICE(0x1814, 0x3390), PCI_DEVICE_DATA(&rt2800pci_ops) }, +#endif #ifdef CONFIG_RT2800PCI_RT35XX { PCI_DEVICE(0x1814, 0x3060), PCI_DEVICE_DATA(&rt2800pci_ops) }, { PCI_DEVICE(0x1814, 0x3062), PCI_DEVICE_DATA(&rt2800pci_ops) }, diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 389ecba..61852c5 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -839,6 +839,13 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x5a57, 0x0283), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x5a57, 0x5257), USB_DEVICE_DATA(&rt2800usb_ops) }, #endif +#ifdef CONFIG_RT2800USB_RT33XX + /* Ralink */ + { USB_DEVICE(0x148f, 0x3370), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x148f, 0x8070), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Sitecom */ + { USB_DEVICE(0x0df6, 0x0050), USB_DEVICE_DATA(&rt2800usb_ops) }, +#endif #ifdef CONFIG_RT2800USB_RT35XX /* Allwin */ { USB_DEVICE(0x8516, 0x3572), USB_DEVICE_DATA(&rt2800usb_ops) }, @@ -851,12 +858,9 @@ static struct usb_device_id rt2800usb_device_table[] = { /* I-O DATA */ { USB_DEVICE(0x04bb, 0x0944), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Ralink */ - { USB_DEVICE(0x148f, 0x3370), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x148f, 0x3572), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x148f, 0x8070), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Sitecom */ { USB_DEVICE(0x0df6, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x0050), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Zinwell */ { USB_DEVICE(0x5a57, 0x0284), USB_DEVICE_DATA(&rt2800usb_ops) }, #endif -- cgit v0.10.2 From 46af584d2ea86518c4cdf521903cd93ba6de2ec0 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Sat, 13 Nov 2010 19:10:10 +0100 Subject: rt2x00: Clean up Kconfig for RT2800 devices. General clean up of the Kconfig part for RT28XX devices. Also remove the indications of non functional support for rt27xx/rt28xx/rt30xx devices, as this is no longer true. They just work fine. Finally, remove the experimental indications for rt27xx/rt28xx/rt30xx devices as that is no longer true. Keep the experimental indications for rt33xx/rt35xx devices, though. Signed-off-by: Gertjan van Wingerde Acked-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index f0f0152..f2be1d3 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -64,8 +64,8 @@ config RT2800PCI_SOC default y config RT2800PCI - tristate "Ralink rt28xx/rt30xx/rt35xx (PCI/PCIe/PCMCIA) support (EXPERIMENTAL)" - depends on (RT2800PCI_PCI || RT2800PCI_SOC) && EXPERIMENTAL + tristate "Ralink rt27xx/rt28xx (PCI/PCIe/PCMCIA) support" + depends on RT2800PCI_PCI || RT2800PCI_SOC select RT2800_LIB select RT2X00_LIB_PCI if RT2800PCI_PCI select RT2X00_LIB_SOC if RT2800PCI_SOC @@ -75,29 +75,24 @@ config RT2800PCI select CRC_CCITT select EEPROM_93CX6 ---help--- - This adds support for rt2800/rt3000/rt3500 wireless chipset family. + This adds support for rt27xx/rt28xx wireless chipset family. Supported chips: RT2760, RT2790, RT2860, RT2880, RT2890 & RT3052 - This driver is non-functional at the moment and is intended for - developers. - When compiled as a module, this driver will be called "rt2800pci.ko". if RT2800PCI config RT2800PCI_RT30XX - bool "rt2800pci - Include support for rt30xx (PCI/PCIe/PCMCIA) devices" + bool "rt2800pci - Include support for rt30xx devices" default y ---help--- This adds support for rt30xx wireless chipset family to the rt2800pci driver. Supported chips: RT3090, RT3091 & RT3092 - Support for these devices is non-functional at the moment and is - intended for testers and developers. - config RT2800PCI_RT33XX - bool "rt2800pci - Include support for rt33xx (PCI/PCIe/PCMCIA) devices" + bool "rt2800pci - Include support for rt33xx devices (EXPERIMENTAL)" + depends on EXPERIMENTAL default n ---help--- This adds support for rt33xx wireless chipset family to the @@ -108,7 +103,8 @@ config RT2800PCI_RT33XX intended for testers and developers. config RT2800PCI_RT35XX - bool "rt2800pci - Include support for rt35xx (PCI/PCIe/PCMCIA) devices" + bool "rt2800pci - Include support for rt35xx devices (EXPERIMENTAL)" + depends on EXPERIMENTAL default n ---help--- This adds support for rt35xx wireless chipset family to the @@ -145,8 +141,8 @@ config RT73USB When compiled as a module, this driver will be called rt73usb. config RT2800USB - tristate "Ralink rt2800 (USB) support (EXPERIMENTAL)" - depends on USB && EXPERIMENTAL + tristate "Ralink rt27xx/rt28xx (USB) support" + depends on USB select RT2800_LIB select RT2X00_LIB_USB select RT2X00_LIB_HT @@ -154,30 +150,24 @@ config RT2800USB select RT2X00_LIB_CRYPTO select CRC_CCITT ---help--- - This adds experimental support for rt2800 wireless chipset family. + This adds support for rt27xx/rt28xx wireless chipset family. Supported chips: RT2770, RT2870 & RT3070. - Known issues: - - support for RT2870 chips doesn't work with 802.11n APs yet - - support for RT3070 chips is non-functional at the moment - When compiled as a module, this driver will be called "rt2800usb.ko". if RT2800USB config RT2800USB_RT30XX - bool "rt2800usb - Include support for rt30xx (USB) devices" + bool "rt2800usb - Include support for rt30xx devices" default y ---help--- This adds support for rt30xx wireless chipset family to the rt2800usb driver. Supported chips: RT3070, RT3071 & RT3072 - Support for these devices is non-functional at the moment and is - intended for testers and developers. - config RT2800USB_RT33XX - bool "rt2800usb - Include support for rt33xx (USB) devices" + bool "rt2800usb - Include support for rt33xx devices (EXPERIMENTAL)" + depends on EXPERIMENTAL default n ---help--- This adds support for rt33xx wireless chipset family to the @@ -188,7 +178,8 @@ config RT2800USB_RT33XX intended for testers and developers. config RT2800USB_RT35XX - bool "rt2800usb - Include support for rt35xx (USB) devices" + bool "rt2800usb - Include support for rt35xx devices (EXPERIMENTAL)" + depends on EXPERIMENTAL default n ---help--- This adds support for rt35xx wireless chipset family to the @@ -202,9 +193,9 @@ config RT2800USB_UNKNOWN bool "rt2800usb - Include support for unknown (USB) devices" default n ---help--- - This adds support for rt2800 family devices that are known to - have a rt2800 family chipset, but for which the exact chipset - is unknown. + This adds support for rt2800usb devices that are known to + have a rt28xx family compatible chipset, but for which the exact + chipset is unknown. Support status for these devices is unknown, and enabling these devices may or may not work. -- cgit v0.10.2 From a6a8d66ebaea1e78d779af221bd6f01c5cbe71f5 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Sat, 13 Nov 2010 19:10:31 +0100 Subject: rt2x00: Remove RT30XX Kconfig variables. Enabling of RT30xx devices via Kconfig variables was introduced when these devices weren't properly supported yet. Now that that they are properly supported and functional, we can remove these Kconfig variables for RT30xx devices and simply enable them whenever rt2800pci and/or rt2800usb is enabled. Signed-off-by: Gertjan van Wingerde Acked-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index f2be1d3..a6939cc 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -64,7 +64,7 @@ config RT2800PCI_SOC default y config RT2800PCI - tristate "Ralink rt27xx/rt28xx (PCI/PCIe/PCMCIA) support" + tristate "Ralink rt27xx/rt28xx/rt30xx (PCI/PCIe/PCMCIA) support" depends on RT2800PCI_PCI || RT2800PCI_SOC select RT2800_LIB select RT2X00_LIB_PCI if RT2800PCI_PCI @@ -75,21 +75,14 @@ config RT2800PCI select CRC_CCITT select EEPROM_93CX6 ---help--- - This adds support for rt27xx/rt28xx wireless chipset family. - Supported chips: RT2760, RT2790, RT2860, RT2880, RT2890 & RT3052 + This adds support for rt27xx/rt28xx/rt30xx wireless chipset family. + Supported chips: RT2760, RT2790, RT2860, RT2880, RT2890, RT3052, + RT3090, RT3091 & RT3092 When compiled as a module, this driver will be called "rt2800pci.ko". if RT2800PCI -config RT2800PCI_RT30XX - bool "rt2800pci - Include support for rt30xx devices" - default y - ---help--- - This adds support for rt30xx wireless chipset family to the - rt2800pci driver. - Supported chips: RT3090, RT3091 & RT3092 - config RT2800PCI_RT33XX bool "rt2800pci - Include support for rt33xx devices (EXPERIMENTAL)" depends on EXPERIMENTAL @@ -141,7 +134,7 @@ config RT73USB When compiled as a module, this driver will be called rt73usb. config RT2800USB - tristate "Ralink rt27xx/rt28xx (USB) support" + tristate "Ralink rt27xx/rt28xx/rt30xx (USB) support" depends on USB select RT2800_LIB select RT2X00_LIB_USB @@ -150,21 +143,13 @@ config RT2800USB select RT2X00_LIB_CRYPTO select CRC_CCITT ---help--- - This adds support for rt27xx/rt28xx wireless chipset family. - Supported chips: RT2770, RT2870 & RT3070. + This adds support for rt27xx/rt28xx/rt30xx wireless chipset family. + Supported chips: RT2770, RT2870 & RT3070, RT3071 & RT3072 When compiled as a module, this driver will be called "rt2800usb.ko". if RT2800USB -config RT2800USB_RT30XX - bool "rt2800usb - Include support for rt30xx devices" - default y - ---help--- - This adds support for rt30xx wireless chipset family to the - rt2800usb driver. - Supported chips: RT3070, RT3071 & RT3072 - config RT2800USB_RT33XX bool "rt2800usb - Include support for rt33xx devices (EXPERIMENTAL)" depends on EXPERIMENTAL diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 6642f13..97f4df6 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -1037,6 +1037,9 @@ static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = { { PCI_DEVICE(0x1814, 0x0681), PCI_DEVICE_DATA(&rt2800pci_ops) }, { PCI_DEVICE(0x1814, 0x0701), PCI_DEVICE_DATA(&rt2800pci_ops) }, { PCI_DEVICE(0x1814, 0x0781), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1814, 0x3090), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1814, 0x3091), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1814, 0x3092), PCI_DEVICE_DATA(&rt2800pci_ops) }, { PCI_DEVICE(0x1432, 0x7708), PCI_DEVICE_DATA(&rt2800pci_ops) }, { PCI_DEVICE(0x1432, 0x7727), PCI_DEVICE_DATA(&rt2800pci_ops) }, { PCI_DEVICE(0x1432, 0x7728), PCI_DEVICE_DATA(&rt2800pci_ops) }, @@ -1044,13 +1047,8 @@ static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = { { PCI_DEVICE(0x1432, 0x7748), PCI_DEVICE_DATA(&rt2800pci_ops) }, { PCI_DEVICE(0x1432, 0x7758), PCI_DEVICE_DATA(&rt2800pci_ops) }, { PCI_DEVICE(0x1432, 0x7768), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1a3b, 0x1059), PCI_DEVICE_DATA(&rt2800pci_ops) }, -#ifdef CONFIG_RT2800PCI_RT30XX - { PCI_DEVICE(0x1814, 0x3090), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1814, 0x3091), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1814, 0x3092), PCI_DEVICE_DATA(&rt2800pci_ops) }, { PCI_DEVICE(0x1462, 0x891a), PCI_DEVICE_DATA(&rt2800pci_ops) }, -#endif + { PCI_DEVICE(0x1a3b, 0x1059), PCI_DEVICE_DATA(&rt2800pci_ops) }, #ifdef CONFIG_RT2800PCI_RT33XX { PCI_DEVICE(0x1814, 0x3390), PCI_DEVICE_DATA(&rt2800pci_ops) }, #endif diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 61852c5..2933bf1 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -641,11 +641,19 @@ static struct usb_device_id rt2800usb_device_table[] = { /* Abocom */ { USB_DEVICE(0x07b8, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x07b8, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07b8, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07b8, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07b8, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1482, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* AirTies */ + { USB_DEVICE(0x1eda, 0x2310), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Allwin */ { USB_DEVICE(0x8516, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x8516, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x8516, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x8516, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x8516, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x8516, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Amit */ { USB_DEVICE(0x15c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Askey */ @@ -654,8 +662,13 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x0b05, 0x1731), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0b05, 0x1732), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0b05, 0x1742), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0b05, 0x1784), USB_DEVICE_DATA(&rt2800usb_ops) }, /* AzureWave */ { USB_DEVICE(0x13d3, 0x3247), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x13d3, 0x3273), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x13d3, 0x3305), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x13d3, 0x3307), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x13d3, 0x3321), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Belkin */ { USB_DEVICE(0x050d, 0x8053), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x050d, 0x805c), USB_DEVICE_DATA(&rt2800usb_ops) }, @@ -666,6 +679,7 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x14b2, 0x3c06), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x14b2, 0x3c07), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x14b2, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c12), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x14b2, 0x3c23), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x14b2, 0x3c25), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x14b2, 0x3c27), USB_DEVICE_DATA(&rt2800usb_ops) }, @@ -674,113 +688,27 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x07aa, 0x002f), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x07aa, 0x003c), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x07aa, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* D-Link */ - { USB_DEVICE(0x07d1, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07d1, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Edimax */ - { USB_DEVICE(0x7392, 0x7717), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x7392, 0x7718), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* EnGenius */ - { USB_DEVICE(0x1740, 0x9701), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1740, 0x9702), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Gigabyte */ - { USB_DEVICE(0x1044, 0x800b), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Hawking */ - { USB_DEVICE(0x0e66, 0x0001), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0e66, 0x0003), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0e66, 0x0009), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0e66, 0x000b), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0e66, 0x0013), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0e66, 0x0017), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0e66, 0x0018), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Linksys */ - { USB_DEVICE(0x1737, 0x0070), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1737, 0x0071), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Logitec */ - { USB_DEVICE(0x0789, 0x0162), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0789, 0x0163), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0789, 0x0164), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Motorola */ - { USB_DEVICE(0x100d, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* MSI */ - { USB_DEVICE(0x0db0, 0x6899), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Philips */ - { USB_DEVICE(0x0471, 0x200f), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Planex */ - { USB_DEVICE(0x2019, 0xed06), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Ralink */ - { USB_DEVICE(0x148f, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x148f, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Samsung */ - { USB_DEVICE(0x04e8, 0x2018), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Siemens */ - { USB_DEVICE(0x129b, 0x1828), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Sitecom */ - { USB_DEVICE(0x0df6, 0x0017), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x002b), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x002c), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x002d), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x0039), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x003b), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x003d), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* SMC */ - { USB_DEVICE(0x083a, 0x6618), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0x7512), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0x7522), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0x8522), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0xa618), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0xb522), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Sparklan */ - { USB_DEVICE(0x15a9, 0x0006), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Sweex */ - { USB_DEVICE(0x177f, 0x0302), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* U-Media*/ - { USB_DEVICE(0x157e, 0x300e), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* ZCOM */ - { USB_DEVICE(0x0cde, 0x0022), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0cde, 0x0025), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Zinwell */ - { USB_DEVICE(0x5a57, 0x0280), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x5a57, 0x0282), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Zyxel */ - { USB_DEVICE(0x0586, 0x3416), USB_DEVICE_DATA(&rt2800usb_ops) }, -#ifdef CONFIG_RT2800USB_RT30XX - /* Abocom */ - { USB_DEVICE(0x07b8, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07b8, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07b8, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* AirTies */ - { USB_DEVICE(0x1eda, 0x2310), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Allwin */ - { USB_DEVICE(0x8516, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x8516, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x8516, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* ASUS */ - { USB_DEVICE(0x0b05, 0x1784), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* AzureWave */ - { USB_DEVICE(0x13d3, 0x3273), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x13d3, 0x3305), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x13d3, 0x3307), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x13d3, 0x3321), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Conceptronic */ - { USB_DEVICE(0x14b2, 0x3c12), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Corega */ { USB_DEVICE(0x18c5, 0x0012), USB_DEVICE_DATA(&rt2800usb_ops) }, /* D-Link */ + { USB_DEVICE(0x07d1, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x07d1, 0x3c0a), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x07d1, 0x3c0d), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x07d1, 0x3c0e), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x07d1, 0x3c0f), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07d1, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x07d1, 0x3c16), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Draytek */ { USB_DEVICE(0x07fa, 0x7712), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Edimax */ { USB_DEVICE(0x7392, 0x7711), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x7392, 0x7717), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x7392, 0x7718), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Encore */ { USB_DEVICE(0x203d, 0x1480), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x203d, 0x14a9), USB_DEVICE_DATA(&rt2800usb_ops) }, /* EnGenius */ + { USB_DEVICE(0x1740, 0x9701), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1740, 0x9702), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1740, 0x9703), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1740, 0x9705), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1740, 0x9706), USB_DEVICE_DATA(&rt2800usb_ops) }, @@ -788,19 +716,37 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x1740, 0x9708), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1740, 0x9709), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Gigabyte */ + { USB_DEVICE(0x1044, 0x800b), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1044, 0x800d), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Hawking */ + { USB_DEVICE(0x0e66, 0x0001), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0e66, 0x0003), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0e66, 0x0009), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0e66, 0x000b), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0e66, 0x0013), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0e66, 0x0017), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0e66, 0x0018), USB_DEVICE_DATA(&rt2800usb_ops) }, /* I-O DATA */ { USB_DEVICE(0x04bb, 0x0945), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x04bb, 0x0947), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x04bb, 0x0948), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Linksys */ + { USB_DEVICE(0x1737, 0x0070), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1737, 0x0071), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Logitec */ + { USB_DEVICE(0x0789, 0x0162), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0789, 0x0163), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0789, 0x0164), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0789, 0x0166), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Motorola */ + { USB_DEVICE(0x100d, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) }, /* MSI */ { USB_DEVICE(0x0db0, 0x3820), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0db0, 0x3821), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0db0, 0x3822), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0db0, 0x3870), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0db0, 0x3871), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0db0, 0x6899), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0db0, 0x821a), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0db0, 0x822a), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0db0, 0x822b), USB_DEVICE_DATA(&rt2800usb_ops) }, @@ -815,30 +761,65 @@ static struct usb_device_id rt2800usb_device_table[] = { /* Pegatron */ { USB_DEVICE(0x1d4d, 0x000c), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1d4d, 0x000e), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Philips */ + { USB_DEVICE(0x0471, 0x200f), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Planex */ { USB_DEVICE(0x2019, 0xab25), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x2019, 0xed06), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Quanta */ { USB_DEVICE(0x1a32, 0x0304), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Ralink */ { USB_DEVICE(0x148f, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x148f, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x148f, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x148f, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x148f, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x148f, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Samsung */ + { USB_DEVICE(0x04e8, 0x2018), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Siemens */ + { USB_DEVICE(0x129b, 0x1828), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Sitecom */ + { USB_DEVICE(0x0df6, 0x0017), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x002b), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x002c), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x002d), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x0039), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x003b), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x003d), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0df6, 0x003e), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0df6, 0x0040), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0df6, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0df6, 0x0047), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0df6, 0x0048), USB_DEVICE_DATA(&rt2800usb_ops) }, /* SMC */ + { USB_DEVICE(0x083a, 0x6618), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x083a, 0x7511), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0x7512), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0x7522), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0x8522), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0xa618), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x083a, 0xa701), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x083a, 0xa702), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x083a, 0xa703), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0xb522), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Sparklan */ + { USB_DEVICE(0x15a9, 0x0006), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Sweex */ + { USB_DEVICE(0x177f, 0x0302), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* U-Media*/ + { USB_DEVICE(0x157e, 0x300e), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* ZCOM */ + { USB_DEVICE(0x0cde, 0x0022), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0cde, 0x0025), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Zinwell */ + { USB_DEVICE(0x5a57, 0x0280), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x5a57, 0x0282), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x5a57, 0x0283), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x5a57, 0x5257), USB_DEVICE_DATA(&rt2800usb_ops) }, -#endif + /* Zyxel */ + { USB_DEVICE(0x0586, 0x3416), USB_DEVICE_DATA(&rt2800usb_ops) }, #ifdef CONFIG_RT2800USB_RT33XX /* Ralink */ { USB_DEVICE(0x148f, 0x3370), USB_DEVICE_DATA(&rt2800usb_ops) }, -- cgit v0.10.2 From 72c7296e03e381b49958809915105b18b09fa7a3 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Sat, 13 Nov 2010 19:10:54 +0100 Subject: rt2x00: Remove unneccessary internal Kconfig symbols. CONFIG_RT2800PCI_PCI and CONFIG_RT2800PCI_SOC are strictly not needed as we can check the dependent symbols directly in the rest of Kconfig and the code, so clean up the Kconfig namespace a bit. Signed-off-by: Gertjan van Wingerde Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index a6939cc..ade3025 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -53,22 +53,12 @@ config RT61PCI When compiled as a module, this driver will be called rt61pci. -config RT2800PCI_PCI - boolean - depends on PCI - default y - -config RT2800PCI_SOC - boolean - depends on RALINK_RT288X || RALINK_RT305X - default y - config RT2800PCI tristate "Ralink rt27xx/rt28xx/rt30xx (PCI/PCIe/PCMCIA) support" - depends on RT2800PCI_PCI || RT2800PCI_SOC + depends on PCI || RALINK_RT288X || RALINK_RT305X select RT2800_LIB - select RT2X00_LIB_PCI if RT2800PCI_PCI - select RT2X00_LIB_SOC if RT2800PCI_SOC + select RT2X00_LIB_PCI if PCI + select RT2X00_LIB_SOC if RALINK_RT288X || RALINK_RT305X select RT2X00_LIB_HT select RT2X00_LIB_FIRMWARE select RT2X00_LIB_CRYPTO diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 97f4df6..b0946f8 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -84,7 +84,7 @@ static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token) rt2800_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0); } -#ifdef CONFIG_RT2800PCI_SOC +#if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X) static void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev) { u32 *base_addr = (u32 *) KSEG1ADDR(0x1F040000); /* XXX for RT3052 */ @@ -95,9 +95,9 @@ static void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev) static inline void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev) { } -#endif /* CONFIG_RT2800PCI_SOC */ +#endif /* CONFIG_RALINK_RT288X || CONFIG_RALINK_RT305X */ -#ifdef CONFIG_RT2800PCI_PCI +#ifdef CONFIG_PCI static void rt2800pci_eepromregister_read(struct eeprom_93cx6 *eeprom) { struct rt2x00_dev *rt2x00dev = eeprom->data; @@ -181,7 +181,7 @@ static inline int rt2800pci_efuse_detect(struct rt2x00_dev *rt2x00dev) static inline void rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev) { } -#endif /* CONFIG_RT2800PCI_PCI */ +#endif /* CONFIG_PCI */ /* * Firmware functions @@ -1031,7 +1031,7 @@ static const struct rt2x00_ops rt2800pci_ops = { /* * RT2800pci module information. */ -#ifdef CONFIG_RT2800PCI_PCI +#ifdef CONFIG_PCI static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = { { PCI_DEVICE(0x1814, 0x0601), PCI_DEVICE_DATA(&rt2800pci_ops) }, { PCI_DEVICE(0x1814, 0x0681), PCI_DEVICE_DATA(&rt2800pci_ops) }, @@ -1061,19 +1061,19 @@ static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = { #endif { 0, } }; -#endif /* CONFIG_RT2800PCI_PCI */ +#endif /* CONFIG_PCI */ MODULE_AUTHOR(DRV_PROJECT); MODULE_VERSION(DRV_VERSION); MODULE_DESCRIPTION("Ralink RT2800 PCI & PCMCIA Wireless LAN driver."); MODULE_SUPPORTED_DEVICE("Ralink RT2860 PCI & PCMCIA chipset based cards"); -#ifdef CONFIG_RT2800PCI_PCI +#ifdef CONFIG_PCI MODULE_FIRMWARE(FIRMWARE_RT2860); MODULE_DEVICE_TABLE(pci, rt2800pci_device_table); -#endif /* CONFIG_RT2800PCI_PCI */ +#endif /* CONFIG_PCI */ MODULE_LICENSE("GPL"); -#ifdef CONFIG_RT2800PCI_SOC +#if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X) static int rt2800soc_probe(struct platform_device *pdev) { return rt2x00soc_probe(pdev, &rt2800pci_ops); @@ -1090,9 +1090,9 @@ static struct platform_driver rt2800soc_driver = { .suspend = rt2x00soc_suspend, .resume = rt2x00soc_resume, }; -#endif /* CONFIG_RT2800PCI_SOC */ +#endif /* CONFIG_RALINK_RT288X || CONFIG_RALINK_RT305X */ -#ifdef CONFIG_RT2800PCI_PCI +#ifdef CONFIG_PCI static struct pci_driver rt2800pci_driver = { .name = KBUILD_MODNAME, .id_table = rt2800pci_device_table, @@ -1101,21 +1101,21 @@ static struct pci_driver rt2800pci_driver = { .suspend = rt2x00pci_suspend, .resume = rt2x00pci_resume, }; -#endif /* CONFIG_RT2800PCI_PCI */ +#endif /* CONFIG_PCI */ static int __init rt2800pci_init(void) { int ret = 0; -#ifdef CONFIG_RT2800PCI_SOC +#if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X) ret = platform_driver_register(&rt2800soc_driver); if (ret) return ret; #endif -#ifdef CONFIG_RT2800PCI_PCI +#ifdef CONFIG_PCI ret = pci_register_driver(&rt2800pci_driver); if (ret) { -#ifdef CONFIG_RT2800PCI_SOC +#if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X) platform_driver_unregister(&rt2800soc_driver); #endif return ret; @@ -1127,10 +1127,10 @@ static int __init rt2800pci_init(void) static void __exit rt2800pci_exit(void) { -#ifdef CONFIG_RT2800PCI_PCI +#ifdef CONFIG_PCI pci_unregister_driver(&rt2800pci_driver); #endif -#ifdef CONFIG_RT2800PCI_SOC +#if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X) platform_driver_unregister(&rt2800soc_driver); #endif } -- cgit v0.10.2 From ef8397cfb3a385bc57a32213d0e4a5b7903a9dc6 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Sat, 13 Nov 2010 19:11:22 +0100 Subject: rt2x00: Use ioremap for SoC devices instead of KSEG1ADDR. Make the code a bit more portable to architectures that do not support KSEG1ADDR. Signed-off-by: Gertjan van Wingerde Tested-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 b0946f8..433c7f3 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -87,9 +87,11 @@ static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token) #if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X) static void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev) { - u32 *base_addr = (u32 *) KSEG1ADDR(0x1F040000); /* XXX for RT3052 */ + void __iomem *base_addr = ioremap(0x1F040000, EEPROM_SIZE); memcpy_fromio(rt2x00dev->eeprom, base_addr, EEPROM_SIZE); + + iounmap(base_addr); } #else static inline void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev) diff --git a/drivers/net/wireless/rt2x00/rt2x00soc.c b/drivers/net/wireless/rt2x00/rt2x00soc.c index fc98063..2aa5c38 100644 --- a/drivers/net/wireless/rt2x00/rt2x00soc.c +++ b/drivers/net/wireless/rt2x00/rt2x00soc.c @@ -40,6 +40,8 @@ static void rt2x00soc_free_reg(struct rt2x00_dev *rt2x00dev) kfree(rt2x00dev->eeprom); rt2x00dev->eeprom = NULL; + + iounmap(rt2x00dev->csr.base); } static int rt2x00soc_alloc_reg(struct rt2x00_dev *rt2x00dev) @@ -51,9 +53,9 @@ static int rt2x00soc_alloc_reg(struct rt2x00_dev *rt2x00dev) if (!res) return -ENODEV; - rt2x00dev->csr.base = (void __iomem *)KSEG1ADDR(res->start); + rt2x00dev->csr.base = ioremap(res->start, resource_size(res)); if (!rt2x00dev->csr.base) - goto exit; + return -ENOMEM; rt2x00dev->eeprom = kzalloc(rt2x00dev->ops->eeprom_size, GFP_KERNEL); if (!rt2x00dev->eeprom) -- cgit v0.10.2 From b43d63bd69ae5464a52bf1796e84097607917b2f Mon Sep 17 00:00:00 2001 From: RA-Jay Hung Date: Sat, 13 Nov 2010 19:11:46 +0100 Subject: rt2x00: Fix rt2800 USB TX Path DMA issue rt2800usb chips need to add 1~3 bytes zero padding after each 802.11 header & payload, and at the end need to add 4 bytes zero padding whether doing TX bulk aggregation or not, TXINFO_W0_USB_DMA_TX_PKT_LEN in TXINFO must include 1-3 bytes padding after 802.11 header & payload but do not include 4 bytes end zero padding. In rt2800usb_get_tx_data_len do not consider multiple of the USB packet size case, sometimes this will cause USB DMA problem. Signed-off-by: RA-Jay Hung Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 2933bf1..935b76d 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -307,8 +307,14 @@ static void rt2800usb_write_tx_desc(struct queue_entry *entry, * Initialize TXINFO descriptor */ rt2x00_desc_read(txi, 0, &word); + + /* + * The size of TXINFO_W0_USB_DMA_TX_PKT_LEN is + * TXWI + 802.11 header + L2 pad + payload + pad, + * so need to decrease size of TXINFO and USB end pad. + */ rt2x00_set_field32(&word, TXINFO_W0_USB_DMA_TX_PKT_LEN, - entry->skb->len - TXINFO_DESC_SIZE); + entry->skb->len - TXINFO_DESC_SIZE - 4); rt2x00_set_field32(&word, TXINFO_W0_WIV, !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags)); rt2x00_set_field32(&word, TXINFO_W0_QSEL, 2); @@ -326,22 +332,29 @@ static void rt2800usb_write_tx_desc(struct queue_entry *entry, skbdesc->desc_len = TXINFO_DESC_SIZE + TXWI_DESC_SIZE; } -/* - * TX data initialization - */ -static int rt2800usb_get_tx_data_len(struct queue_entry *entry) +static void rt2800usb_write_tx_data(struct queue_entry *entry, + struct txentry_desc *txdesc) { - int length; + u8 padding_len; /* - * The length _must_ include 4 bytes padding, - * it should always be multiple of 4, - * but it must _not_ be a multiple of the USB packet size. + * pad(1~3 bytes) is added after each 802.11 payload. + * USB end pad(4 bytes) is added at each USB bulk out packet end. + * TX frame format is : + * | TXINFO | TXWI | 802.11 header | L2 pad | payload | pad | USB end pad | + * |<------------- tx_pkt_len ------------->| */ - length = roundup(entry->skb->len + 4, 4); - length += (4 * !(length % entry->queue->usb_maxpacket)); + rt2800_write_tx_data(entry, txdesc); + padding_len = roundup(entry->skb->len + 4, 4) - entry->skb->len; + memset(skb_put(entry->skb, padding_len), 0, padding_len); +} - return length; +/* + * TX data initialization + */ +static int rt2800usb_get_tx_data_len(struct queue_entry *entry) +{ + return entry->skb->len; } /* @@ -579,7 +592,7 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = { .link_tuner = rt2800_link_tuner, .watchdog = rt2800usb_watchdog, .write_tx_desc = rt2800usb_write_tx_desc, - .write_tx_data = rt2800_write_tx_data, + .write_tx_data = rt2800usb_write_tx_data, .write_beacon = rt2800_write_beacon, .get_tx_data_len = rt2800usb_get_tx_data_len, .kick_tx_queue = rt2x00usb_kick_tx_queue, -- cgit v0.10.2 From f8eaec659f8a7a4e0086fca7c5d5c5e0fbc76d1a Mon Sep 17 00:00:00 2001 From: RA-Jay Hung Date: Sat, 13 Nov 2010 19:12:54 +0100 Subject: rt2x00: Fix header_length in rt2x00lib_txdone Put the assignment of header_length after pull out extra tx headroom Signed-off-by: RA-Jay Hung 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 3afa2a3..c879f9a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -250,10 +250,9 @@ void rt2x00lib_txdone(struct queue_entry *entry, struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); enum data_queue_qid qid = skb_get_queue_mapping(entry->skb); - unsigned int header_length = ieee80211_get_hdrlen_from_skb(entry->skb); + unsigned int header_length, i; u8 rate_idx, rate_flags, retry_rates; u8 skbdesc_flags = skbdesc->flags; - unsigned int i; bool success; /* @@ -272,6 +271,11 @@ void rt2x00lib_txdone(struct queue_entry *entry, skbdesc->flags &= ~SKBDESC_DESC_IN_SKB; /* + * Determine the length of 802.11 header. + */ + header_length = ieee80211_get_hdrlen_from_skb(entry->skb); + + /* * Remove L2 padding which was added during */ if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags)) -- cgit v0.10.2 From 387e68846413f3dcfc5a5afca9841430057e3340 Mon Sep 17 00:00:00 2001 From: RA-Jay Hung Date: Sat, 13 Nov 2010 19:13:53 +0100 Subject: rt2x00: Modify rt2x00queue_remove_l2pad to make skb->data two-byte alignment When send out skb data to mac80211, orignal code will cause mac80211 unaligned access, so modify code to make mac80211 can natural access. Signed-off-by: RA-Jay Hung 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 dc54317..a3d79c7 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -204,8 +204,10 @@ void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length) if (!l2pad) return; - memmove(skb->data + l2pad, skb->data, header_length); - skb_pull(skb, l2pad); + memmove(skb->data + header_length, skb->data + header_length + l2pad, + skb->len - header_length - l2pad); + + skb_trim(skb, skb->len - l2pad); } static void rt2x00queue_create_tx_descriptor_seq(struct queue_entry *entry, -- cgit v0.10.2 From c5d0855acfa4d6801c4c45bc02ddddd959262050 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 13 Nov 2010 20:22:41 +0100 Subject: ath9k_hw: set default values for radar pulse detection Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index 3686811..7303d98 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -1610,6 +1610,20 @@ static void ar5008_hw_set_radar_params(struct ath_hw *ah, REG_CLR_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA); } +static void ar5008_hw_set_radar_conf(struct ath_hw *ah) +{ + struct ath_hw_radar_conf *conf = &ah->radar_conf; + + conf->fir_power = -33; + conf->radar_rssi = 20; + conf->pulse_height = 10; + conf->pulse_rssi = 24; + conf->pulse_inband = 15; + conf->pulse_maxlen = 255; + conf->pulse_inband_step = 12; + conf->radar_inband = 8; +} + void ar5008_hw_attach_phy_ops(struct ath_hw *ah) { struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); @@ -1656,5 +1670,6 @@ void ar5008_hw_attach_phy_ops(struct ath_hw *ah) priv_ops->compute_pll_control = ar5008_hw_compute_pll_control; ar5008_hw_set_nf_limits(ah); + ar5008_hw_set_radar_conf(ah); memcpy(ah->nf_regs, ar5416_cca_regs, sizeof(ah->nf_regs)); } diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index f676b21..e8d6455 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -1144,6 +1144,20 @@ static void ar9003_hw_set_radar_params(struct ath_hw *ah, REG_CLR_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA); } +static void ar9003_hw_set_radar_conf(struct ath_hw *ah) +{ + struct ath_hw_radar_conf *conf = &ah->radar_conf; + + conf->fir_power = -28; + conf->radar_rssi = 0; + conf->pulse_height = 10; + conf->pulse_rssi = 24; + conf->pulse_inband = 8; + conf->pulse_maxlen = 255; + conf->pulse_inband_step = 12; + conf->radar_inband = 8; +} + void ar9003_hw_attach_phy_ops(struct ath_hw *ah) { struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); @@ -1175,6 +1189,7 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah) priv_ops->set_radar_params = ar9003_hw_set_radar_params; ar9003_hw_set_nf_limits(ah); + ar9003_hw_set_radar_conf(ah); memcpy(ah->nf_regs, ar9300_cca_regs, sizeof(ah->nf_regs)); } diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index c20a542..d5e6834 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -782,6 +782,8 @@ struct ath_hw { u8 txchainmask; u8 rxchainmask; + struct ath_hw_radar_conf radar_conf; + u32 originalGain[22]; int initPDADC; int PDADCdelta; -- cgit v0.10.2 From 9a6b82706317333a1fab5dcafa2c33b91253a7a2 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 14 Nov 2010 00:03:01 +0100 Subject: ath9k: fix PA predistortion training frame setup Signed-off-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 8ba0e2d..dc648a5 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1656,9 +1656,6 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, bf->bf_buf_addr, txctl->txq->axq_qnum); - if (bf->bf_state.bfs_paprd) - ar9003_hw_set_paprd_txdesc(ah, ds, bf->bf_state.bfs_paprd); - spin_lock_bh(&txctl->txq->axq_lock); if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR) && @@ -1684,6 +1681,9 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, bf->bf_state.bfs_ftype = txctl->frame_type; bf->bf_state.bfs_paprd = txctl->paprd; + if (bf->bf_state.bfs_paprd) + ar9003_hw_set_paprd_txdesc(ah, ds, bf->bf_state.bfs_paprd); + if (txctl->paprd) bf->bf_state.bfs_paprd_timestamp = jiffies; -- cgit v0.10.2 From 2d3bcba0827013dfc60f727e7370dea00bc0638a Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 14 Nov 2010 15:20:01 +0100 Subject: ath9k: remove bfs_seqno from struct ath_buf_state 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 3e6ebe6..3b52577 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -105,7 +105,6 @@ enum buffer_type { #define bf_al bf_state.bfs_al #define bf_frmlen bf_state.bfs_frmlen #define bf_retries bf_state.bfs_retries -#define bf_seqno bf_state.bfs_seqno #define bf_tidno bf_state.bfs_tidno #define bf_keyix bf_state.bfs_keyix #define bf_keytype bf_state.bfs_keytype @@ -221,7 +220,6 @@ struct ath_buf_state { int bfs_nframes; u16 bfs_al; u16 bfs_frmlen; - int bfs_seqno; int bfs_tidno; int bfs_retries; u8 bf_type; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index dc648a5..e84c9c2 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -140,6 +140,12 @@ unlock: spin_unlock_bh(&txq->axq_lock); } +static u16 ath_frame_seqno(struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + return le16_to_cpu(hdr->seq_ctrl) >> IEEE80211_SEQ_SEQ_SHIFT; +} + static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) { struct ath_txq *txq = tid->ac->txq; @@ -157,7 +163,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) list_move_tail(&bf->list, &bf_head); if (bf_isretried(bf)) { - ath_tx_update_baw(sc, tid, bf->bf_seqno); + ath_tx_update_baw(sc, tid, ath_frame_seqno(bf->bf_mpdu)); ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0); } else { ath_tx_send_normal(sc, txq, tid, &bf_head); @@ -184,14 +190,11 @@ static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, } static void ath_tx_addto_baw(struct ath_softc *sc, struct ath_atx_tid *tid, - struct ath_buf *bf) + u16 seqno) { int index, cindex; - if (bf_isretried(bf)) - return; - - index = ATH_BA_INDEX(tid->seq_start, bf->bf_seqno); + index = ATH_BA_INDEX(tid->seq_start, seqno); cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1); __set_bit(cindex, tid->tx_buf); @@ -215,6 +218,7 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *bf; struct list_head bf_head; struct ath_tx_status ts; + u16 bf_seqno; memset(&ts, 0, sizeof(ts)); INIT_LIST_HEAD(&bf_head); @@ -226,8 +230,9 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, bf = list_first_entry(&tid->buf_q, struct ath_buf, list); list_move_tail(&bf->list, &bf_head); + bf_seqno = ath_frame_seqno(bf->bf_mpdu); if (bf_isretried(bf)) - ath_tx_update_baw(sc, tid, bf->bf_seqno); + ath_tx_update_baw(sc, tid, bf_seqno); spin_unlock(&txq->axq_lock); ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0); @@ -316,6 +321,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]; + u16 bf_seqno; int nframes; skb = bf->bf_mpdu; @@ -392,8 +398,9 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, skb = bf->bf_mpdu; tx_info = IEEE80211_SKB_CB(skb); + bf_seqno = ath_frame_seqno(skb); - if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, bf->bf_seqno))) { + if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, bf_seqno))) { /* transmit completion, subframe is * acked by block ack */ acked_cnt++; @@ -442,7 +449,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, * block-ack window */ spin_lock_bh(&txq->axq_lock); - ath_tx_update_baw(sc, tid, bf->bf_seqno); + ath_tx_update_baw(sc, tid, bf_seqno); spin_unlock_bh(&txq->axq_lock); if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) { @@ -471,7 +478,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, if (!tbf) { spin_lock_bh(&txq->axq_lock); ath_tx_update_baw(sc, tid, - bf->bf_seqno); + bf_seqno); spin_unlock_bh(&txq->axq_lock); bf->bf_state.bf_type |= @@ -674,14 +681,16 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, al_delta, h_baw = tid->baw_size / 2; enum ATH_AGGR_STATUS status = ATH_AGGR_DONE; struct ieee80211_tx_info *tx_info; + u16 bf_seqno; bf_first = list_first_entry(&tid->buf_q, struct ath_buf, list); do { bf = list_first_entry(&tid->buf_q, struct ath_buf, list); + bf_seqno = ath_frame_seqno(bf->bf_mpdu); /* do not step over block-ack window */ - if (!BAW_WITHIN(tid->seq_start, tid->baw_size, bf->bf_seqno)) { + if (!BAW_WITHIN(tid->seq_start, tid->baw_size, bf_seqno)) { status = ATH_AGGR_BAW_CLOSED; break; } @@ -726,7 +735,8 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, 0); /* link buffers of this frame to the aggregate */ - ath_tx_addto_baw(sc, tid, bf); + if (!bf_isretried(bf)) + ath_tx_addto_baw(sc, tid, bf_seqno); ath9k_hw_set11n_aggr_middle(sc->sc_ah, bf->bf_desc, ndelim); list_move_tail(&bf->list, bf_q); if (bf_prev) { @@ -1288,10 +1298,12 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, struct ath_tx_control *txctl) { struct ath_buf *bf; + u16 bf_seqno; bf = list_first_entry(bf_head, struct ath_buf, list); bf->bf_state.bf_type |= BUF_AMPDU; TX_STAT_INC(txctl->txq->axq_qnum, a_queued); + bf_seqno = ath_frame_seqno(bf->bf_mpdu); /* * Do not queue to h/w when any of the following conditions is true: @@ -1301,7 +1313,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, * - h/w queue depth exceeds low water mark */ if (!list_empty(&tid->buf_q) || tid->paused || - !BAW_WITHIN(tid->seq_start, tid->baw_size, bf->bf_seqno) || + !BAW_WITHIN(tid->seq_start, tid->baw_size, bf_seqno) || txctl->txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) { /* * Add this frame to software queue for scheduling later @@ -1313,7 +1325,8 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, } /* Add sub-frame to BAW */ - ath_tx_addto_baw(sc, tid, bf); + if (!bf_isretried(bf)) + ath_tx_addto_baw(sc, tid, bf_seqno); /* Queue to h/w without aggregation */ bf->bf_nframes = 1; @@ -1394,7 +1407,6 @@ static void assign_aggr_tid_seqno(struct sk_buff *skb, */ tid = ATH_AN_2_TID(an, bf->bf_tidno); hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT); - bf->bf_seqno = tid->seq_next; INCR(tid->seq_next, IEEE80211_SEQ_MAX); } @@ -1903,7 +1915,7 @@ static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf, } while (bf) { - ba_index = ATH_BA_INDEX(seq_st, bf->bf_seqno); + ba_index = ATH_BA_INDEX(seq_st, ath_frame_seqno(bf->bf_mpdu)); if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index))) nbad++; -- cgit v0.10.2 From 5daefbd061d9509644058b6886abe2b6672ee386 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 14 Nov 2010 15:20:02 +0100 Subject: ath9k: remove bfs_tidno from struct ath_buf_state 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 3b52577..905d3c4 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -105,7 +105,6 @@ enum buffer_type { #define bf_al bf_state.bfs_al #define bf_frmlen bf_state.bfs_frmlen #define bf_retries bf_state.bfs_retries -#define bf_tidno bf_state.bfs_tidno #define bf_keyix bf_state.bfs_keyix #define bf_keytype bf_state.bfs_keytype #define bf_isht(bf) (bf->bf_state.bf_type & BUF_HT) @@ -220,7 +219,6 @@ struct ath_buf_state { int bfs_nframes; u16 bfs_al; u16 bfs_frmlen; - int bfs_tidno; int bfs_retries; u8 bf_type; u8 bfs_paprd; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index e84c9c2..c7097a5 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -323,6 +323,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, struct ieee80211_tx_rate rates[4]; u16 bf_seqno; int nframes; + u8 tidno; skb = bf->bf_mpdu; hdr = (struct ieee80211_hdr *)skb->data; @@ -358,14 +359,15 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, } an = (struct ath_node *)sta->drv_priv; - tid = ATH_AN_2_TID(an, bf->bf_tidno); + tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK; + tid = ATH_AN_2_TID(an, tidno); /* * The hardware occasionally sends a tx status for the wrong TID. * In this case, the BA status cannot be considered valid and all * subframes need to be retransmitted */ - if (bf->bf_tidno != ts->tid) + if (tidno != ts->tid) txok = false; isaggr = bf_isaggr(bf); @@ -1386,7 +1388,7 @@ static void assign_aggr_tid_seqno(struct sk_buff *skb, struct ath_node *an; struct ath_atx_tid *tid; __le16 fc; - u8 *qc; + u8 tidno; if (!tx_info->control.sta) return; @@ -1394,18 +1396,13 @@ static void assign_aggr_tid_seqno(struct sk_buff *skb, an = (struct ath_node *)tx_info->control.sta->drv_priv; hdr = (struct ieee80211_hdr *)skb->data; fc = hdr->frame_control; - - if (ieee80211_is_data_qos(fc)) { - qc = ieee80211_get_qos_ctl(hdr); - bf->bf_tidno = qc[0] & 0xf; - } + tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK; /* - * For HT capable stations, we save tidno for later use. - * We also override seqno set by upper layer with the one + * Override seqno set by upper layer with the one * in tx aggregation state. */ - tid = ATH_AN_2_TID(an, bf->bf_tidno); + tid = ATH_AN_2_TID(an, tidno); hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT); INCR(tid->seq_next, IEEE80211_SEQ_MAX); } @@ -1647,6 +1644,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, struct ath_hw *ah = sc->sc_ah; int frm_type; __le16 fc; + u8 tidno; frm_type = get_hw_packet_type(skb); fc = hdr->frame_control; @@ -1673,7 +1671,10 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR) && tx_info->control.sta) { an = (struct ath_node *)tx_info->control.sta->drv_priv; - tid = ATH_AN_2_TID(an, bf->bf_tidno); + tidno = ieee80211_get_qos_ctl(hdr)[0] & + IEEE80211_QOS_CTL_TID_MASK; + tid = ATH_AN_2_TID(an, tidno); + WARN_ON(tid->ac->txq != txctl->txq); if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { -- cgit v0.10.2 From 952cd693718d8ac796d5323fe7876241cf15ecfa Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 14 Nov 2010 15:20:03 +0100 Subject: ath9k: remove bfs_keytype from struct ath_buf_state 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 905d3c4..bd988ea 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -106,7 +106,6 @@ enum buffer_type { #define bf_frmlen bf_state.bfs_frmlen #define bf_retries bf_state.bfs_retries #define bf_keyix bf_state.bfs_keyix -#define bf_keytype bf_state.bfs_keytype #define bf_isht(bf) (bf->bf_state.bf_type & BUF_HT) #define bf_isampdu(bf) (bf->bf_state.bf_type & BUF_AMPDU) #define bf_isaggr(bf) (bf->bf_state.bf_type & BUF_AGGR) @@ -224,7 +223,6 @@ struct ath_buf_state { u8 bfs_paprd; unsigned long bfs_paprd_timestamp; u32 bfs_keyix; - enum ath9k_key_type bfs_keytype; enum ath9k_internal_frame_type bfs_ftype; }; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index c7097a5..6e0467c 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -630,7 +630,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid, * TODO - this could be improved to be dependent on the rate. * The hardware can keep up at lower rates, but not higher rates */ - if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR) + if (tx_info->control.hw_key) ndelim += ATH_AGGR_ENCRYPTDELIM; /* @@ -1604,8 +1604,7 @@ static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw, bf->bf_flags = setup_tx_flags(skb); - bf->bf_keytype = ath9k_cmn_get_hw_crypto_keytype(skb); - if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR) { + if (tx_info->control.hw_key) { bf->bf_frmlen += tx_info->control.hw_key->icv_len; bf->bf_keyix = tx_info->control.hw_key->hw_key_idx; } else { @@ -1642,6 +1641,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, struct ath_desc *ds; struct ath_atx_tid *tid; struct ath_hw *ah = sc->sc_ah; + enum ath9k_key_type keytype; int frm_type; __le16 fc; u8 tidno; @@ -1655,8 +1655,9 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, ds = bf->bf_desc; ath9k_hw_set_desc_link(ah, ds, 0); + keytype = ath9k_cmn_get_hw_crypto_keytype(skb); ath9k_hw_set11n_txdesc(ah, ds, bf->bf_frmlen, frm_type, MAX_RATE_POWER, - bf->bf_keyix, bf->bf_keytype, bf->bf_flags); + bf->bf_keyix, keytype, bf->bf_flags); ath9k_hw_filltxdesc(ah, ds, skb->len, /* segment length */ -- cgit v0.10.2 From 82259b77f6e55c5b81f5f4a2852f6216c196ef30 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 14 Nov 2010 15:20:04 +0100 Subject: ath9k: remove bfs_paprd_timestamp from struct ath_buf_state 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 bd988ea..826b665 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -221,7 +221,6 @@ struct ath_buf_state { int bfs_retries; u8 bf_type; u8 bfs_paprd; - unsigned long bfs_paprd_timestamp; u32 bfs_keyix; enum ath9k_internal_frame_type bfs_ftype; }; @@ -598,6 +597,7 @@ struct ath_softc { struct work_struct paprd_work; struct work_struct hw_check_work; struct completion paprd_complete; + bool paprd_pending; u32 intrstatus; u32 sc_flags; /* SC_OP_* */ diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index df7c62d..cfec2ad 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -375,6 +375,7 @@ void ath_paprd_calibrate(struct work_struct *work) } init_completion(&sc->paprd_complete); + sc->paprd_pending = true; ar9003_paprd_setup_gain_table(ah, chain); txctl.paprd = BIT(chain); if (ath_tx_start(hw, skb, &txctl) != 0) @@ -382,6 +383,7 @@ void ath_paprd_calibrate(struct work_struct *work) time_left = wait_for_completion_timeout(&sc->paprd_complete, msecs_to_jiffies(ATH_PAPRD_TIMEOUT)); + sc->paprd_pending = false; if (!time_left) { ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE, "Timeout waiting for paprd training on " diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 6e0467c..9f3d23a 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1698,9 +1698,6 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, if (bf->bf_state.bfs_paprd) ar9003_hw_set_paprd_txdesc(ah, ds, bf->bf_state.bfs_paprd); - if (txctl->paprd) - bf->bf_state.bfs_paprd_timestamp = jiffies; - ath_tx_send_normal(sc, txctl->txq, NULL, &bf_head); } @@ -1874,9 +1871,7 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, bf->bf_buf_addr = 0; if (bf->bf_state.bfs_paprd) { - if (time_after(jiffies, - bf->bf_state.bfs_paprd_timestamp + - msecs_to_jiffies(ATH_PAPRD_TIMEOUT))) + if (!sc->paprd_pending) dev_kfree_skb_any(skb); else complete(&sc->paprd_complete); -- cgit v0.10.2 From 3017047f564d5101009c8318b94bdacd3ca3312e Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 14 Nov 2010 15:20:05 +0100 Subject: ath9k: remove bfs_keyix from struct ath_buf_state 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 826b665..e78f7f9 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -105,7 +105,6 @@ enum buffer_type { #define bf_al bf_state.bfs_al #define bf_frmlen bf_state.bfs_frmlen #define bf_retries bf_state.bfs_retries -#define bf_keyix bf_state.bfs_keyix #define bf_isht(bf) (bf->bf_state.bf_type & BUF_HT) #define bf_isampdu(bf) (bf->bf_state.bf_type & BUF_AMPDU) #define bf_isaggr(bf) (bf->bf_state.bf_type & BUF_AGGR) @@ -221,7 +220,6 @@ struct ath_buf_state { int bfs_retries; u8 bf_type; u8 bfs_paprd; - u32 bfs_keyix; enum ath9k_internal_frame_type bfs_ftype; }; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 9f3d23a..176d88c 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1604,12 +1604,8 @@ static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw, bf->bf_flags = setup_tx_flags(skb); - if (tx_info->control.hw_key) { + if (tx_info->control.hw_key) bf->bf_frmlen += tx_info->control.hw_key->icv_len; - bf->bf_keyix = tx_info->control.hw_key->hw_key_idx; - } else { - bf->bf_keyix = ATH9K_TXKEYIX_INVALID; - } bf->bf_mpdu = skb; @@ -1642,6 +1638,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, struct ath_atx_tid *tid; struct ath_hw *ah = sc->sc_ah; enum ath9k_key_type keytype; + u32 keyix; int frm_type; __le16 fc; u8 tidno; @@ -1656,8 +1653,13 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, ath9k_hw_set_desc_link(ah, ds, 0); keytype = ath9k_cmn_get_hw_crypto_keytype(skb); + if (tx_info->control.hw_key) + keyix = tx_info->control.hw_key->hw_key_idx; + else + keyix = ATH9K_TXKEYIX_INVALID; + ath9k_hw_set11n_txdesc(ah, ds, bf->bf_frmlen, frm_type, MAX_RATE_POWER, - bf->bf_keyix, keytype, bf->bf_flags); + keyix, keytype, bf->bf_flags); ath9k_hw_filltxdesc(ah, ds, skb->len, /* segment length */ -- cgit v0.10.2 From 269c44bc8415ad78fb4dc3de25e6de3420332e9f Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 14 Nov 2010 15:20:06 +0100 Subject: ath9k: remove bfs_al from struct ath_buf_state 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 e78f7f9..b70ac3a 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -102,7 +102,6 @@ enum buffer_type { }; #define bf_nframes bf_state.bfs_nframes -#define bf_al bf_state.bfs_al #define bf_frmlen bf_state.bfs_frmlen #define bf_retries bf_state.bfs_retries #define bf_isht(bf) (bf->bf_state.bf_type & BUF_HT) @@ -215,11 +214,10 @@ struct ath_atx_ac { struct ath_buf_state { int bfs_nframes; - u16 bfs_al; - u16 bfs_frmlen; int bfs_retries; u8 bf_type; u8 bfs_paprd; + u16 bfs_frmlen; enum ath9k_internal_frame_type bfs_ftype; }; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 176d88c..88efcc1 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -56,7 +56,7 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, struct ath_tx_status *ts, int txok, int sendbar); static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, struct list_head *head); -static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf); +static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len); static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf, struct ath_tx_status *ts, int txok); static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts, @@ -674,7 +674,8 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid, static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq, struct ath_atx_tid *tid, - struct list_head *bf_q) + struct list_head *bf_q, + int *aggr_len) { #define PADBYTES(_len) ((4 - ((_len) % 4)) % 4) struct ath_buf *bf, *bf_first, *bf_prev = NULL; @@ -750,7 +751,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, } while (!list_empty(&tid->buf_q)); - bf_first->bf_al = al; + *aggr_len = al; bf_first->bf_nframes = nframes; return status; @@ -763,6 +764,7 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *bf; enum ATH_AGGR_STATUS status; struct list_head bf_q; + int aggr_len; do { if (list_empty(&tid->buf_q)) @@ -770,7 +772,7 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, INIT_LIST_HEAD(&bf_q); - status = ath_tx_form_aggr(sc, txq, tid, &bf_q); + status = ath_tx_form_aggr(sc, txq, tid, &bf_q, &aggr_len); /* * no frames picked up to be aggregated; @@ -786,15 +788,15 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, if (bf->bf_nframes == 1) { bf->bf_state.bf_type &= ~BUF_AGGR; ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc); - ath_buf_set_rate(sc, bf); + ath_buf_set_rate(sc, bf, bf->bf_frmlen); ath_tx_txqaddbuf(sc, txq, &bf_q); continue; } /* setup first desc of aggregate */ bf->bf_state.bf_type |= BUF_AGGR; - ath_buf_set_rate(sc, bf); - ath9k_hw_set11n_aggr_first(sc->sc_ah, bf->bf_desc, bf->bf_al); + ath_buf_set_rate(sc, bf, aggr_len); + ath9k_hw_set11n_aggr_first(sc->sc_ah, bf->bf_desc, aggr_len); /* anchor last desc of aggregate */ ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc); @@ -1333,7 +1335,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, /* Queue to h/w without aggregation */ bf->bf_nframes = 1; bf->bf_lastbf = bf; - ath_buf_set_rate(sc, bf); + ath_buf_set_rate(sc, bf, bf->bf_frmlen); ath_tx_txqaddbuf(sc, txctl->txq, bf_head); } @@ -1352,7 +1354,7 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, bf->bf_nframes = 1; bf->bf_lastbf = bf; - ath_buf_set_rate(sc, bf); + ath_buf_set_rate(sc, bf, bf->bf_frmlen); ath_tx_txqaddbuf(sc, txq, bf_head); TX_STAT_INC(txq->axq_qnum, queued); } @@ -1430,13 +1432,11 @@ static int setup_tx_flags(struct sk_buff *skb) * width - 0 for 20 MHz, 1 for 40 MHz * half_gi - to use 4us v/s 3.6 us for symbol time */ -static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf, +static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, int pktlen, int width, int half_gi, bool shortPreamble) { u32 nbits, nsymbits, duration, nsymbols; - int streams, pktlen; - - pktlen = bf_isaggr(bf) ? bf->bf_al : bf->bf_frmlen; + int streams; /* find number of symbols: PLCP + data */ streams = HT_RC_2_STREAMS(rix); @@ -1455,7 +1455,7 @@ static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf, return duration; } -static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) +static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath9k_11n_rate_series series[4]; @@ -1518,7 +1518,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) if (rates[i].flags & IEEE80211_TX_RC_MCS) { /* MCS rates */ series[i].Rate = rix | 0x80; - series[i].PktDuration = ath_pkt_duration(sc, rix, bf, + series[i].PktDuration = ath_pkt_duration(sc, rix, len, is_40, is_sgi, is_sp); if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC)) series[i].RateFlags |= ATH9K_RATESERIES_STBC; @@ -1542,11 +1542,11 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) } series[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah, - phy, rate->bitrate * 100, bf->bf_frmlen, rix, is_sp); + phy, rate->bitrate * 100, len, rix, is_sp); } /* For AR5416 - RTS cannot be followed by a frame larger than 8K */ - if (bf_isaggr(bf) && (bf->bf_al > sc->sc_ah->caps.rts_aggr_limit)) + if (bf_isaggr(bf) && (len > sc->sc_ah->caps.rts_aggr_limit)) flags &= ~ATH9K_TXDESC_RTSENA; /* ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. */ -- cgit v0.10.2 From b572d0335fcb26e526f6ae087a9a09371b22e739 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 14 Nov 2010 15:20:07 +0100 Subject: ath9k: remove bfs_nframes from struct ath_buf_state 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 b70ac3a..b1c45b8 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -101,7 +101,6 @@ enum buffer_type { BUF_XRETRY = BIT(5), }; -#define bf_nframes bf_state.bfs_nframes #define bf_frmlen bf_state.bfs_frmlen #define bf_retries bf_state.bfs_retries #define bf_isht(bf) (bf->bf_state.bf_type & BUF_HT) @@ -213,7 +212,6 @@ struct ath_atx_ac { }; struct ath_buf_state { - int bfs_nframes; int bfs_retries; u8 bf_type; u8 bfs_paprd; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 88efcc1..87b79ef 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -57,10 +57,8 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, struct list_head *head); static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len); -static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf, - struct ath_tx_status *ts, int txok); static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts, - int nbad, int txok, bool update_rc); + int nframes, int nbad, int txok, bool update_rc); static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, int seqno); @@ -303,6 +301,39 @@ static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf) return tbf; } +static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf, + struct ath_tx_status *ts, int txok, + int *nframes, int *nbad) +{ + u16 seq_st = 0; + u32 ba[WME_BA_BMP_SIZE >> 5]; + int ba_index; + int isaggr = 0; + + *nbad = 0; + *nframes = 0; + + if (bf->bf_lastbf->bf_tx_aborted) + return; + + isaggr = bf_isaggr(bf); + if (isaggr) { + seq_st = ts->ts_seqnum; + memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3); + } + + while (bf) { + ba_index = ATH_BA_INDEX(seq_st, ath_frame_seqno(bf->bf_mpdu)); + + (*nframes)++; + if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index))) + (*nbad)++; + + bf = bf->bf_next; + } +} + + static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *bf, struct list_head *bf_q, struct ath_tx_status *ts, int txok) @@ -332,7 +363,6 @@ 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(); @@ -349,7 +379,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, 1, 0, false); + ath_tx_rc_status(bf, ts, 1, 1, 0, false); ath_tx_complete_buf(sc, bf, txq, &bf_head, ts, 0, 0); @@ -393,7 +423,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, INIT_LIST_HEAD(&bf_pending); INIT_LIST_HEAD(&bf_head); - nbad = ath_tx_num_badfrms(sc, bf, ts, txok); + ath_tx_count_frames(sc, bf, ts, txok, &nframes, &nbad); while (bf) { txfail = txpending = 0; bf_next = bf->bf_next; @@ -456,11 +486,10 @@ 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); + ath_tx_rc_status(bf, ts, nframes, nbad, txok, true); rc_update = false; } else { - ath_tx_rc_status(bf, ts, nbad, txok, false); + ath_tx_rc_status(bf, ts, nframes, nbad, txok, false); } ath_tx_complete_buf(sc, bf, txq, &bf_head, ts, @@ -485,8 +514,8 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, bf->bf_state.bf_type |= BUF_XRETRY; - ath_tx_rc_status(bf, ts, nbad, - 0, false); + ath_tx_rc_status(bf, ts, nframes, + nbad, 0, false); ath_tx_complete_buf(sc, bf, txq, &bf_head, ts, 0, 0); @@ -752,7 +781,6 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, } while (!list_empty(&tid->buf_q)); *aggr_len = al; - bf_first->bf_nframes = nframes; return status; #undef PADBYTES @@ -785,7 +813,7 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list); /* if only one frame, send as non-aggregate */ - if (bf->bf_nframes == 1) { + if (bf == bf->bf_lastbf) { bf->bf_state.bf_type &= ~BUF_AGGR; ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc); ath_buf_set_rate(sc, bf, bf->bf_frmlen); @@ -1333,7 +1361,6 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, ath_tx_addto_baw(sc, tid, bf_seqno); /* Queue to h/w without aggregation */ - bf->bf_nframes = 1; bf->bf_lastbf = bf; ath_buf_set_rate(sc, bf, bf->bf_frmlen); ath_tx_txqaddbuf(sc, txctl->txq, bf_head); @@ -1352,7 +1379,6 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, if (tid) INCR(tid->seq_start, IEEE80211_SEQ_MAX); - bf->bf_nframes = 1; bf->bf_lastbf = bf; ath_buf_set_rate(sc, bf, bf->bf_frmlen); ath_tx_txqaddbuf(sc, txq, bf_head); @@ -1895,37 +1921,8 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, spin_unlock_irqrestore(&sc->tx.txbuflock, flags); } -static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf, - struct ath_tx_status *ts, int txok) -{ - u16 seq_st = 0; - u32 ba[WME_BA_BMP_SIZE >> 5]; - int ba_index; - int nbad = 0; - int isaggr = 0; - - if (bf->bf_lastbf->bf_tx_aborted) - return 0; - - isaggr = bf_isaggr(bf); - if (isaggr) { - seq_st = ts->ts_seqnum; - memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3); - } - - while (bf) { - ba_index = ATH_BA_INDEX(seq_st, ath_frame_seqno(bf->bf_mpdu)); - if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index))) - nbad++; - - bf = bf->bf_next; - } - - return nbad; -} - static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts, - int nbad, int txok, bool update_rc) + int nframes, int nbad, int txok, bool update_rc) { struct sk_buff *skb = bf->bf_mpdu; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; @@ -1946,10 +1943,10 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts, if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc) { tx_info->flags |= IEEE80211_TX_STAT_AMPDU; - BUG_ON(nbad > bf->bf_nframes); + BUG_ON(nbad > nframes); - tx_info->status.ampdu_len = bf->bf_nframes; - tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad; + tx_info->status.ampdu_len = nframes; + tx_info->status.ampdu_ack_len = nframes - nbad; } if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 && @@ -2078,7 +2075,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, txok ? 0 : 1, txok, true); + ath_tx_rc_status(bf, &ts, 1, txok ? 0 : 1, txok, true); } qnum = skb_get_queue_mapping(bf->bf_mpdu); @@ -2200,7 +2197,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, txok ? 0 : 1, txok, true); + ath_tx_rc_status(bf, &txs, 1, txok ? 0 : 1, txok, true); } qnum = skb_get_queue_mapping(bf->bf_mpdu); -- cgit v0.10.2 From 76e4522177de81ac89ade01a394aeb3704a66f1b Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 14 Nov 2010 15:20:08 +0100 Subject: ath9k: remove bfs_frmlen from struct ath_buf_state 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 b1c45b8..84518dc 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -101,7 +101,6 @@ enum buffer_type { BUF_XRETRY = BIT(5), }; -#define bf_frmlen bf_state.bfs_frmlen #define bf_retries bf_state.bfs_retries #define bf_isht(bf) (bf->bf_state.bf_type & BUF_HT) #define bf_isampdu(bf) (bf->bf_state.bf_type & BUF_AMPDU) @@ -215,7 +214,6 @@ struct ath_buf_state { int bfs_retries; u8 bf_type; u8 bfs_paprd; - u16 bfs_frmlen; enum ath9k_internal_frame_type bfs_ftype; }; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 87b79ef..527151e 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -50,7 +50,7 @@ static u16 bits_per_symbol[][2] = { static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, struct ath_atx_tid *tid, - struct list_head *bf_head); + struct list_head *bf_head, int frmlen); static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, struct ath_txq *txq, struct list_head *bf_q, struct ath_tx_status *ts, int txok, int sendbar); @@ -144,6 +144,26 @@ static u16 ath_frame_seqno(struct sk_buff *skb) return le16_to_cpu(hdr->seq_ctrl) >> IEEE80211_SEQ_SEQ_SHIFT; } +static int ath_frame_len(struct sk_buff *skb) +{ + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + int frmlen = skb->len + FCS_LEN; + int padpos, padsize; + + /* Remove the padding size, if any */ + padpos = ath9k_cmn_padpos(hdr->frame_control); + padsize = padpos & 3; + + if (padsize && skb->len > padpos + padsize) + frmlen -= padsize; + + if (tx_info->control.hw_key) + frmlen += tx_info->control.hw_key->icv_len; + + return frmlen; +} + static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) { struct ath_txq *txq = tid->ac->txq; @@ -164,7 +184,8 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) ath_tx_update_baw(sc, tid, ath_frame_seqno(bf->bf_mpdu)); ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0); } else { - ath_tx_send_normal(sc, txq, tid, &bf_head); + ath_tx_send_normal(sc, txq, tid, &bf_head, + ath_frame_len(bf->bf_mpdu)); } } @@ -713,6 +734,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, al_delta, h_baw = tid->baw_size / 2; enum ATH_AGGR_STATUS status = ATH_AGGR_DONE; struct ieee80211_tx_info *tx_info; + int frmlen; u16 bf_seqno; bf_first = list_first_entry(&tid->buf_q, struct ath_buf, list); @@ -733,7 +755,8 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, } /* do not exceed aggregation limit */ - al_delta = ATH_AGGR_DELIM_SZ + bf->bf_frmlen; + frmlen = ath_frame_len(bf->bf_mpdu); + al_delta = ATH_AGGR_DELIM_SZ + frmlen; if (nframes && (aggr_limit < (al + bpad + al_delta + prev_al))) { @@ -760,7 +783,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, * Get the delimiters needed to meet the MPDU * density for this node. */ - ndelim = ath_compute_num_delims(sc, tid, bf_first, bf->bf_frmlen); + ndelim = ath_compute_num_delims(sc, tid, bf_first, frmlen); bpad = PADBYTES(al_delta) + (ndelim << 2); bf->bf_next = NULL; @@ -816,7 +839,7 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, if (bf == bf->bf_lastbf) { bf->bf_state.bf_type &= ~BUF_AGGR; ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc); - ath_buf_set_rate(sc, bf, bf->bf_frmlen); + ath_buf_set_rate(sc, bf, ath_frame_len(bf->bf_mpdu)); ath_tx_txqaddbuf(sc, txq, &bf_q); continue; } @@ -1327,7 +1350,7 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, struct list_head *bf_head, - struct ath_tx_control *txctl) + struct ath_tx_control *txctl, int frmlen) { struct ath_buf *bf; u16 bf_seqno; @@ -1362,13 +1385,13 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, /* Queue to h/w without aggregation */ bf->bf_lastbf = bf; - ath_buf_set_rate(sc, bf, bf->bf_frmlen); + ath_buf_set_rate(sc, bf, frmlen); ath_tx_txqaddbuf(sc, txctl->txq, bf_head); } static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, struct ath_atx_tid *tid, - struct list_head *bf_head) + struct list_head *bf_head, int frmlen) { struct ath_buf *bf; @@ -1380,7 +1403,7 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, INCR(tid->seq_start, IEEE80211_SEQ_MAX); bf->bf_lastbf = bf; - ath_buf_set_rate(sc, bf, bf->bf_frmlen); + ath_buf_set_rate(sc, bf, frmlen); ath_tx_txqaddbuf(sc, txq, bf_head); TX_STAT_INC(txq->axq_qnum, queued); } @@ -1595,12 +1618,10 @@ static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ath_buf *bf; int hdrlen; __le16 fc; - int padpos, padsize; bf = ath_tx_get_buffer(sc); if (!bf) { @@ -1614,13 +1635,6 @@ static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw, ATH_TXBUF_RESET(bf); bf->aphy = aphy; - bf->bf_frmlen = skb->len + FCS_LEN; - /* Remove the padding size from bf_frmlen, if any */ - padpos = ath9k_cmn_padpos(hdr->frame_control); - padsize = padpos & 3; - if (padsize && skb->len>padpos+padsize) { - bf->bf_frmlen -= padsize; - } if (ieee80211_is_data_qos(fc) && conf_is_ht(&hw->conf)) { bf->bf_state.bf_type |= BUF_HT; @@ -1630,9 +1644,6 @@ static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw, bf->bf_flags = setup_tx_flags(skb); - if (tx_info->control.hw_key) - bf->bf_frmlen += tx_info->control.hw_key->icv_len; - bf->bf_mpdu = skb; bf->bf_buf_addr = dma_map_single(sc->dev, skb->data, @@ -1668,6 +1679,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, int frm_type; __le16 fc; u8 tidno; + int frmlen; frm_type = get_hw_packet_type(skb); fc = hdr->frame_control; @@ -1684,7 +1696,8 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, else keyix = ATH9K_TXKEYIX_INVALID; - ath9k_hw_set11n_txdesc(ah, ds, bf->bf_frmlen, frm_type, MAX_RATE_POWER, + frmlen = ath_frame_len(bf->bf_mpdu); + ath9k_hw_set11n_txdesc(ah, ds, frmlen, frm_type, MAX_RATE_POWER, keyix, keytype, bf->bf_flags); ath9k_hw_filltxdesc(ah, ds, @@ -1711,13 +1724,13 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, * Try aggregation if it's a unicast data frame * and the destination is HT capable. */ - ath_tx_send_ampdu(sc, tid, &bf_head, txctl); + ath_tx_send_ampdu(sc, tid, &bf_head, txctl, frmlen); } else { /* * Send this frame as regular when ADDBA * exchange is neither complete nor pending. */ - ath_tx_send_normal(sc, txctl->txq, tid, &bf_head); + ath_tx_send_normal(sc, txctl->txq, tid, &bf_head, frmlen); } } else { bf->bf_state.bfs_ftype = txctl->frame_type; @@ -1726,7 +1739,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, if (bf->bf_state.bfs_paprd) ar9003_hw_set_paprd_txdesc(ah, ds, bf->bf_state.bfs_paprd); - ath_tx_send_normal(sc, txctl->txq, NULL, &bf_head); + ath_tx_send_normal(sc, txctl->txq, NULL, &bf_head, frmlen); } spin_unlock_bh(&txctl->txq->axq_lock); -- cgit v0.10.2 From c5992618259598ade82c386aa1595bf105e92d1f Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 14 Nov 2010 15:20:09 +0100 Subject: ath9k: remove bf_tx_aborted from struct ath_buf 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 84518dc..3fecd03 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -227,7 +227,6 @@ struct ath_buf { dma_addr_t bf_daddr; /* physical addr of desc */ 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; struct ath_wiphy *aphy; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 527151e..c35033f 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -334,9 +334,6 @@ static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf, *nbad = 0; *nframes = 0; - if (bf->bf_lastbf->bf_tx_aborted) - return; - isaggr = bf_isaggr(bf); if (isaggr) { seq_st = ts->ts_seqnum; @@ -357,7 +354,7 @@ static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf, static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *bf, struct list_head *bf_q, - struct ath_tx_status *ts, int txok) + struct ath_tx_status *ts, int txok, bool retry) { struct ath_node *an = NULL; struct sk_buff *skb; @@ -461,8 +458,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, /* transmit completion */ acked_cnt++; } else { - if (!(tid->state & AGGR_CLEANUP) && - !bf_last->bf_tx_aborted) { + if (!(tid->state & AGGR_CLEANUP) && retry) { if (bf->bf_retries < ATH_MAX_SW_RETRIES) { ath_tx_set_retry(sc, txq, bf); txpending = 1; @@ -1132,8 +1128,6 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx) } lastbf = bf->bf_lastbf; - if (!retry_tx) - lastbf->bf_tx_aborted = true; if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { list_cut_position(&bf_head, @@ -1150,7 +1144,8 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx) spin_unlock_bh(&txq->axq_lock); if (bf_isampdu(bf)) - ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0); + ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0, + retry_tx); else ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0); } @@ -1171,7 +1166,7 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx) if (bf_isampdu(bf)) ath_tx_complete_aggr(sc, txq, bf, &bf_head, - &ts, 0); + &ts, 0, retry_tx); else ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0); @@ -1657,8 +1652,6 @@ static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw, return NULL; } - bf->bf_tx_aborted = false; - return bf; } @@ -2094,7 +2087,8 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) qnum = skb_get_queue_mapping(bf->bf_mpdu); if (bf_isampdu(bf)) - ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok); + ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok, + true); else ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0); @@ -2216,7 +2210,8 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) qnum = skb_get_queue_mapping(bf->bf_mpdu); if (bf_isampdu(bf)) - ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs, txok); + ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs, + txok, true); else ath_tx_complete_buf(sc, bf, txq, &bf_head, &txs, txok, 0); -- cgit v0.10.2 From 28d167086227969fd6586953ee4ac682a3c394ff Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 14 Nov 2010 15:20:10 +0100 Subject: ath9k: clean up code duplication around ath_tx_start Merge initial processing for the CAB queue and regular tx. Also move ath_tx_cabq() to beacon.c and make it static. 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 3fecd03..7111007 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -323,7 +323,6 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, struct ath_tx_control *txctl); void ath_tx_tasklet(struct ath_softc *sc); void ath_tx_edma_tasklet(struct ath_softc *sc); -void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb); int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid, u16 *ssn); void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 2377376..30724a4 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -109,6 +109,25 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, series, 4, 0); } +static void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_tx_control txctl; + + memset(&txctl, 0, sizeof(struct ath_tx_control)); + txctl.txq = sc->beacon.cabq; + + ath_print(common, ATH_DBG_XMIT, + "transmitting CABQ packet, skb: %p\n", skb); + + if (ath_tx_start(hw, skb, &txctl) != 0) { + ath_print(common, ATH_DBG_XMIT, "CABQ TX failed\n"); + dev_kfree_skb_any(skb); + } +} + static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index cfec2ad..6e93a53 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1187,12 +1187,10 @@ mutex_unlock: static int ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_tx_control txctl; - int padpos, padsize; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; if (aphy->state != ATH_WIPHY_ACTIVE && aphy->state != ATH_WIPHY_SCAN) { @@ -1243,29 +1241,6 @@ static int ath9k_tx(struct ieee80211_hw *hw, } memset(&txctl, 0, sizeof(struct ath_tx_control)); - - /* - * As a temporary workaround, assign seq# here; this will likely need - * to be cleaned up to work better with Beacon transmission and virtual - * BSSes. - */ - if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { - if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) - sc->tx.seq_no += 0x10; - hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); - hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no); - } - - /* Add the padding after the header if this is not already done */ - padpos = ath9k_cmn_padpos(hdr->frame_control); - padsize = padpos & 3; - if (padsize && skb->len>padpos) { - if (skb_headroom(skb) < padsize) - return -1; - skb_push(skb, padsize); - memmove(skb->data, skb->data + padsize, padpos); - } - txctl.txq = sc->tx.txq_map[skb_get_queue_mapping(skb)]; ath_print(common, ATH_DBG_XMIT, "transmitting packet, skb: %p\n", skb); diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index c35033f..f3f0d1c 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1742,41 +1742,14 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, struct ath_tx_control *txctl) { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; struct ath_txq *txq = txctl->txq; struct ath_buf *bf; - int q; - - bf = ath_tx_setup_buffer(hw, skb); - if (unlikely(!bf)) - return -ENOMEM; - - q = skb_get_queue_mapping(skb); - spin_lock_bh(&txq->axq_lock); - if (txq == sc->tx.txq_map[q] && - ++txq->pending_frames > ATH_MAX_QDEPTH && !txq->stopped) { - ath_mac80211_stop_queue(sc, q); - txq->stopped = 1; - } - spin_unlock_bh(&txq->axq_lock); - - ath_tx_start_dma(sc, bf, txctl); - - return 0; -} - -void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb) -{ - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; int padpos, padsize; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ath_tx_control txctl; - - memset(&txctl, 0, sizeof(struct ath_tx_control)); + int q; /* * As a temporary workaround, assign seq# here; this will likely need @@ -1793,30 +1766,30 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb) /* Add the padding after the header if this is not already done */ padpos = ath9k_cmn_padpos(hdr->frame_control); padsize = padpos & 3; - if (padsize && skb->len>padpos) { - if (skb_headroom(skb) < padsize) { - ath_print(common, ATH_DBG_XMIT, - "TX CABQ padding failed\n"); - dev_kfree_skb_any(skb); - return; - } + if (padsize && skb->len > padpos) { + if (skb_headroom(skb) < padsize) + return -ENOMEM; + skb_push(skb, padsize); memmove(skb->data, skb->data + padsize, padpos); } - txctl.txq = sc->beacon.cabq; - - ath_print(common, ATH_DBG_XMIT, - "transmitting CABQ packet, skb: %p\n", skb); + bf = ath_tx_setup_buffer(hw, skb); + if (unlikely(!bf)) + return -ENOMEM; - if (ath_tx_start(hw, skb, &txctl) != 0) { - ath_print(common, ATH_DBG_XMIT, "CABQ TX failed\n"); - goto exit; + q = skb_get_queue_mapping(skb); + spin_lock_bh(&txq->axq_lock); + if (txq == sc->tx.txq_map[q] && + ++txq->pending_frames > ATH_MAX_QDEPTH && !txq->stopped) { + ath_mac80211_stop_queue(sc, q); + txq->stopped = 1; } + spin_unlock_bh(&txq->axq_lock); - return; -exit: - dev_kfree_skb_any(skb); + ath_tx_start_dma(sc, bf, txctl); + + return 0; } /*****************/ -- cgit v0.10.2 From 71a3bf3e94b745467fc4c3451a294910f0369555 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 14 Nov 2010 15:20:11 +0100 Subject: ath9k: block new AMPDU sessions if SC_OP_TXAGGR is not set This makes further tx path cleanups easier 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 6e93a53..dede9a9 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1979,6 +1979,9 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, case IEEE80211_AMPDU_RX_STOP: break; case IEEE80211_AMPDU_TX_START: + if (!(sc->sc_flags & SC_OP_TXAGGR)) + return -EOPNOTSUPP; + ath9k_ps_wakeup(sc); ret = ath_tx_aggr_start(sc, sta, tid, ssn); if (!ret) -- cgit v0.10.2 From 04caf863750bc7e042d1e8d57e5ce9d6326ab435 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 14 Nov 2010 15:20:12 +0100 Subject: ath9k: more tx setup cleanups - remove the BUF_HT flag, and instead check for IEEE80211_TX_CTL_AMPDU before calling ath_tx_send_ampdu. - remove a few unused variables - calculate frame length before adding the frame padding - merge the misnamed ath_tx_start_dma function into ath_tx_start - remove an unused argument for assign_aggr_tid_seqno 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 7111007..d12123a 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -86,7 +86,6 @@ struct ath_config { /** * enum buffer_type - Buffer type flags * - * @BUF_HT: Send this buffer using HT capabilities * @BUF_AMPDU: This buffer is an ampdu, as part of an aggregate (during TX) * @BUF_AGGR: Indicates whether the buffer can be aggregated * (used in aggregation scheduling) @@ -94,7 +93,6 @@ struct ath_config { * @BUF_XRETRY: To denote excessive retries of the buffer */ enum buffer_type { - BUF_HT = BIT(1), BUF_AMPDU = BIT(2), BUF_AGGR = BIT(3), BUF_RETRY = BIT(4), @@ -102,7 +100,6 @@ enum buffer_type { }; #define bf_retries bf_state.bfs_retries -#define bf_isht(bf) (bf->bf_state.bf_type & BUF_HT) #define bf_isampdu(bf) (bf->bf_state.bf_type & BUF_AMPDU) #define bf_isaggr(bf) (bf->bf_state.bf_type & BUF_AGGR) #define bf_isretried(bf) (bf->bf_state.bf_type & BUF_RETRY) @@ -265,6 +262,7 @@ struct ath_tx_control { struct ath_txq *txq; int if_id; enum ath9k_internal_frame_type frame_type; + int frmlen; u8 paprd; }; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index f3f0d1c..5eeffae 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1344,13 +1344,11 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, } static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, - struct list_head *bf_head, - struct ath_tx_control *txctl, int frmlen) + struct ath_buf *bf, struct ath_tx_control *txctl) { - struct ath_buf *bf; + struct list_head bf_head; u16 bf_seqno; - bf = list_first_entry(bf_head, struct ath_buf, list); bf->bf_state.bf_type |= BUF_AMPDU; TX_STAT_INC(txctl->txq->axq_qnum, a_queued); bf_seqno = ath_frame_seqno(bf->bf_mpdu); @@ -1369,19 +1367,22 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, * Add this frame to software queue for scheduling later * for aggregation. */ - list_move_tail(&bf->list, &tid->buf_q); + list_add_tail(&bf->list, &tid->buf_q); ath_tx_queue_tid(txctl->txq, tid); return; } + INIT_LIST_HEAD(&bf_head); + list_add(&bf->list, &bf_head); + /* Add sub-frame to BAW */ if (!bf_isretried(bf)) ath_tx_addto_baw(sc, tid, bf_seqno); /* Queue to h/w without aggregation */ bf->bf_lastbf = bf; - ath_buf_set_rate(sc, bf, frmlen); - ath_tx_txqaddbuf(sc, txctl->txq, bf_head); + ath_buf_set_rate(sc, bf, txctl->frmlen); + ath_tx_txqaddbuf(sc, txctl->txq, &bf_head); } static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, @@ -1426,8 +1427,7 @@ static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb) return htype; } -static void assign_aggr_tid_seqno(struct sk_buff *skb, - struct ath_buf *bf) +static void assign_aggr_tid_seqno(struct sk_buff *skb) { struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr; @@ -1608,15 +1608,20 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len) } static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw, - struct sk_buff *skb) + struct ath_txq *txq, + struct sk_buff *skb, int frmlen) { 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_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb; struct ath_buf *bf; - int hdrlen; - __le16 fc; + struct ath_desc *ds; + enum ath9k_key_type keytype; + u32 keyix; + int frm_type; bf = ath_tx_get_buffer(sc); if (!bf) { @@ -1624,21 +1629,14 @@ static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw, return NULL; } - hdrlen = ieee80211_get_hdrlen_from_skb(skb); - fc = hdr->frame_control; - ATH_TXBUF_RESET(bf); - bf->aphy = aphy; - - if (ieee80211_is_data_qos(fc) && conf_is_ht(&hw->conf)) { - bf->bf_state.bf_type |= BUF_HT; - if (sc->sc_flags & SC_OP_TXAGGR) - assign_aggr_tid_seqno(skb, bf); - } + if (ieee80211_is_data_qos(hdr->frame_control) && + conf_is_ht(&hw->conf) && (sc->sc_flags & SC_OP_TXAGGR)) + assign_aggr_tid_seqno(skb); + bf->aphy = aphy; bf->bf_flags = setup_tx_flags(skb); - bf->bf_mpdu = skb; bf->bf_buf_addr = dma_map_single(sc->dev, skb->data, @@ -1652,33 +1650,7 @@ static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw, return NULL; } - return bf; -} - -/* FIXME: tx power */ -static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, - struct ath_tx_control *txctl) -{ - struct sk_buff *skb = bf->bf_mpdu; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct ath_node *an = NULL; - struct list_head bf_head; - struct ath_desc *ds; - struct ath_atx_tid *tid; - struct ath_hw *ah = sc->sc_ah; - enum ath9k_key_type keytype; - u32 keyix; - int frm_type; - __le16 fc; - u8 tidno; - int frmlen; - frm_type = get_hw_packet_type(skb); - fc = hdr->frame_control; - - INIT_LIST_HEAD(&bf_head); - list_add_tail(&bf->list, &bf_head); ds = bf->bf_desc; ath9k_hw_set_desc_link(ah, ds, 0); @@ -1689,7 +1661,6 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, else keyix = ATH9K_TXKEYIX_INVALID; - frmlen = ath_frame_len(bf->bf_mpdu); ath9k_hw_set11n_txdesc(ah, ds, frmlen, frm_type, MAX_RATE_POWER, keyix, keytype, bf->bf_flags); @@ -1699,40 +1670,50 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, true, /* last segment */ ds, /* first descriptor */ bf->bf_buf_addr, - txctl->txq->axq_qnum); + txq->axq_qnum); + + + return bf; +} + +/* FIXME: tx power */ +static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, + struct ath_tx_control *txctl) +{ + struct sk_buff *skb = bf->bf_mpdu; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ath_node *an = NULL; + struct list_head bf_head; + struct ath_atx_tid *tid; + u8 tidno; spin_lock_bh(&txctl->txq->axq_lock); - if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR) && - tx_info->control.sta) { + if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && tx_info->control.sta) { an = (struct ath_node *)tx_info->control.sta->drv_priv; tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK; tid = ATH_AN_2_TID(an, tidno); - WARN_ON(tid->ac->txq != txctl->txq); - if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { - /* - * Try aggregation if it's a unicast data frame - * and the destination is HT capable. - */ - ath_tx_send_ampdu(sc, tid, &bf_head, txctl, frmlen); - } else { - /* - * Send this frame as regular when ADDBA - * exchange is neither complete nor pending. - */ - ath_tx_send_normal(sc, txctl->txq, tid, &bf_head, frmlen); - } + /* + * Try aggregation if it's a unicast data frame + * and the destination is HT capable. + */ + ath_tx_send_ampdu(sc, tid, bf, txctl); } else { + INIT_LIST_HEAD(&bf_head); + list_add_tail(&bf->list, &bf_head); + bf->bf_state.bfs_ftype = txctl->frame_type; bf->bf_state.bfs_paprd = txctl->paprd; if (bf->bf_state.bfs_paprd) - ar9003_hw_set_paprd_txdesc(ah, ds, bf->bf_state.bfs_paprd); + ar9003_hw_set_paprd_txdesc(sc->sc_ah, bf->bf_desc, + bf->bf_state.bfs_paprd); - ath_tx_send_normal(sc, txctl->txq, NULL, &bf_head, frmlen); + ath_tx_send_normal(sc, txctl->txq, NULL, &bf_head, txctl->frmlen); } spin_unlock_bh(&txctl->txq->axq_lock); @@ -1749,8 +1730,14 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, struct ath_txq *txq = txctl->txq; struct ath_buf *bf; int padpos, padsize; + int frmlen = skb->len + FCS_LEN; int q; + if (info->control.hw_key) + frmlen += info->control.hw_key->icv_len; + + txctl->frmlen = frmlen; + /* * As a temporary workaround, assign seq# here; this will likely need * to be cleaned up to work better with Beacon transmission and virtual @@ -1774,7 +1761,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, memmove(skb->data, skb->data + padsize, padpos); } - bf = ath_tx_setup_buffer(hw, skb); + bf = ath_tx_setup_buffer(hw, txctl->txq, skb, frmlen); if (unlikely(!bf)) return -ENOMEM; -- cgit v0.10.2 From 2d42efc44e38d3a8b2bf30e34559036bb6541672 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 14 Nov 2010 15:20:13 +0100 Subject: ath9k: store frame information used by aggregation inside the skb tx info Since the pointers after the rates in the tx info cannot be used anymore after frames have been queued, this area can be used to store information that was previously stored in the ath_buf. With these changes, we can delay the ath_buf assignment in the aggregation code until aggregates are formed. That will not only make it possible to simplify DMA descriptor setup to do less rewriting of uncached memory, but will also make it easier to move aggregation out of the core of the ath9k tx path. 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 d12123a..be9c8d3 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -89,20 +89,16 @@ struct ath_config { * @BUF_AMPDU: This buffer is an ampdu, as part of an aggregate (during TX) * @BUF_AGGR: Indicates whether the buffer can be aggregated * (used in aggregation scheduling) - * @BUF_RETRY: Indicates whether the buffer is retried * @BUF_XRETRY: To denote excessive retries of the buffer */ enum buffer_type { BUF_AMPDU = BIT(2), BUF_AGGR = BIT(3), - BUF_RETRY = BIT(4), BUF_XRETRY = BIT(5), }; -#define bf_retries bf_state.bfs_retries #define bf_isampdu(bf) (bf->bf_state.bf_type & BUF_AMPDU) #define bf_isaggr(bf) (bf->bf_state.bf_type & BUF_AGGR) -#define bf_isretried(bf) (bf->bf_state.bf_type & BUF_RETRY) #define bf_isxretried(bf) (bf->bf_state.bf_type & BUF_XRETRY) #define ATH_TXSTATUS_RING_SIZE 64 @@ -207,8 +203,15 @@ struct ath_atx_ac { struct list_head tid_q; }; +struct ath_frame_info { + int framelen; + u32 keyix; + enum ath9k_key_type keytype; + u8 retries; + u16 seqno; +}; + struct ath_buf_state { - int bfs_retries; u8 bf_type; u8 bfs_paprd; enum ath9k_internal_frame_type bfs_ftype; @@ -260,9 +263,9 @@ struct ath_node { struct ath_tx_control { struct ath_txq *txq; + struct ath_node *an; int if_id; enum ath9k_internal_frame_type frame_type; - int frmlen; u8 paprd; }; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 5eeffae..c63e283f 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -50,7 +50,7 @@ static u16 bits_per_symbol[][2] = { static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, struct ath_atx_tid *tid, - struct list_head *bf_head, int frmlen); + struct list_head *bf_head); static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, struct ath_txq *txq, struct list_head *bf_q, struct ath_tx_status *ts, int txok, int sendbar); @@ -138,30 +138,12 @@ unlock: spin_unlock_bh(&txq->axq_lock); } -static u16 ath_frame_seqno(struct sk_buff *skb) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - return le16_to_cpu(hdr->seq_ctrl) >> IEEE80211_SEQ_SEQ_SHIFT; -} - -static int ath_frame_len(struct sk_buff *skb) +static struct ath_frame_info *get_frame_info(struct sk_buff *skb) { struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - int frmlen = skb->len + FCS_LEN; - int padpos, padsize; - - /* Remove the padding size, if any */ - padpos = ath9k_cmn_padpos(hdr->frame_control); - padsize = padpos & 3; - - if (padsize && skb->len > padpos + padsize) - frmlen -= padsize; - - if (tx_info->control.hw_key) - frmlen += tx_info->control.hw_key->icv_len; - - return frmlen; + BUILD_BUG_ON(sizeof(struct ath_frame_info) > + sizeof(tx_info->rate_driver_data)); + return (struct ath_frame_info *) &tx_info->rate_driver_data[0]; } static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) @@ -170,6 +152,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) struct ath_buf *bf; struct list_head bf_head; struct ath_tx_status ts; + struct ath_frame_info *fi; INIT_LIST_HEAD(&bf_head); @@ -180,12 +163,12 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) bf = list_first_entry(&tid->buf_q, struct ath_buf, list); list_move_tail(&bf->list, &bf_head); - if (bf_isretried(bf)) { - ath_tx_update_baw(sc, tid, ath_frame_seqno(bf->bf_mpdu)); + fi = get_frame_info(bf->bf_mpdu); + if (fi->retries) { + ath_tx_update_baw(sc, tid, fi->seqno); ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0); } else { - ath_tx_send_normal(sc, txq, tid, &bf_head, - ath_frame_len(bf->bf_mpdu)); + ath_tx_send_normal(sc, txq, tid, &bf_head); } } @@ -237,7 +220,7 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *bf; struct list_head bf_head; struct ath_tx_status ts; - u16 bf_seqno; + struct ath_frame_info *fi; memset(&ts, 0, sizeof(ts)); INIT_LIST_HEAD(&bf_head); @@ -249,9 +232,9 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, bf = list_first_entry(&tid->buf_q, struct ath_buf, list); list_move_tail(&bf->list, &bf_head); - bf_seqno = ath_frame_seqno(bf->bf_mpdu); - if (bf_isretried(bf)) - ath_tx_update_baw(sc, tid, bf_seqno); + fi = get_frame_info(bf->bf_mpdu); + if (fi->retries) + ath_tx_update_baw(sc, tid, fi->seqno); spin_unlock(&txq->axq_lock); ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0); @@ -263,16 +246,15 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, } static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq, - struct ath_buf *bf) + struct sk_buff *skb) { - struct sk_buff *skb; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr; - bf->bf_state.bf_type |= BUF_RETRY; - bf->bf_retries++; TX_STAT_INC(txq->axq_qnum, a_retries); + if (tx_info->control.rates[4].count++ > 0) + return; - skb = bf->bf_mpdu; hdr = (struct ieee80211_hdr *)skb->data; hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_RETRY); } @@ -326,6 +308,7 @@ static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf, struct ath_tx_status *ts, int txok, int *nframes, int *nbad) { + struct ath_frame_info *fi; u16 seq_st = 0; u32 ba[WME_BA_BMP_SIZE >> 5]; int ba_index; @@ -341,7 +324,8 @@ static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf, } while (bf) { - ba_index = ATH_BA_INDEX(seq_st, ath_frame_seqno(bf->bf_mpdu)); + fi = get_frame_info(bf->bf_mpdu); + ba_index = ATH_BA_INDEX(seq_st, fi->seqno); (*nframes)++; if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index))) @@ -370,7 +354,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]; - u16 bf_seqno; + struct ath_frame_info *fi; int nframes; u8 tidno; @@ -448,9 +432,9 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, skb = bf->bf_mpdu; tx_info = IEEE80211_SKB_CB(skb); - bf_seqno = ath_frame_seqno(skb); + fi = get_frame_info(skb); - if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, bf_seqno))) { + if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, fi->seqno))) { /* transmit completion, subframe is * acked by block ack */ acked_cnt++; @@ -459,8 +443,8 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, acked_cnt++; } else { if (!(tid->state & AGGR_CLEANUP) && retry) { - if (bf->bf_retries < ATH_MAX_SW_RETRIES) { - ath_tx_set_retry(sc, txq, bf); + if (fi->retries < ATH_MAX_SW_RETRIES) { + ath_tx_set_retry(sc, txq, bf->bf_mpdu); txpending = 1; } else { bf->bf_state.bf_type |= BUF_XRETRY; @@ -498,7 +482,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, * block-ack window */ spin_lock_bh(&txq->axq_lock); - ath_tx_update_baw(sc, tid, bf_seqno); + ath_tx_update_baw(sc, tid, fi->seqno); spin_unlock_bh(&txq->axq_lock); if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) { @@ -525,8 +509,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, */ if (!tbf) { spin_lock_bh(&txq->axq_lock); - ath_tx_update_baw(sc, tid, - bf_seqno); + ath_tx_update_baw(sc, tid, fi->seqno); spin_unlock_bh(&txq->axq_lock); bf->bf_state.bf_type |= @@ -666,6 +649,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid, u16 minlen; u8 flags, rix; int width, streams, half_gi, ndelim, mindelim; + struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu); /* Select standard number of delimiters based on frame length alone */ ndelim = ATH_AGGR_GET_NDELIM(frmlen); @@ -676,7 +660,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid, * TODO - this could be improved to be dependent on the rate. * The hardware can keep up at lower rates, but not higher rates */ - if (tx_info->control.hw_key) + if (fi->keyix != ATH9K_TXKEYIX_INVALID) ndelim += ATH_AGGR_ENCRYPTDELIM; /* @@ -730,17 +714,16 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, al_delta, h_baw = tid->baw_size / 2; enum ATH_AGGR_STATUS status = ATH_AGGR_DONE; struct ieee80211_tx_info *tx_info; - int frmlen; - u16 bf_seqno; + struct ath_frame_info *fi; bf_first = list_first_entry(&tid->buf_q, struct ath_buf, list); do { bf = list_first_entry(&tid->buf_q, struct ath_buf, list); - bf_seqno = ath_frame_seqno(bf->bf_mpdu); + fi = get_frame_info(bf->bf_mpdu); /* do not step over block-ack window */ - if (!BAW_WITHIN(tid->seq_start, tid->baw_size, bf_seqno)) { + if (!BAW_WITHIN(tid->seq_start, tid->baw_size, fi->seqno)) { status = ATH_AGGR_BAW_CLOSED; break; } @@ -751,8 +734,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, } /* do not exceed aggregation limit */ - frmlen = ath_frame_len(bf->bf_mpdu); - al_delta = ATH_AGGR_DELIM_SZ + frmlen; + al_delta = ATH_AGGR_DELIM_SZ + fi->framelen; if (nframes && (aggr_limit < (al + bpad + al_delta + prev_al))) { @@ -779,15 +761,15 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, * Get the delimiters needed to meet the MPDU * density for this node. */ - ndelim = ath_compute_num_delims(sc, tid, bf_first, frmlen); + ndelim = ath_compute_num_delims(sc, tid, bf_first, fi->framelen); bpad = PADBYTES(al_delta) + (ndelim << 2); bf->bf_next = NULL; ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, 0); /* link buffers of this frame to the aggregate */ - if (!bf_isretried(bf)) - ath_tx_addto_baw(sc, tid, bf_seqno); + if (!fi->retries) + ath_tx_addto_baw(sc, tid, fi->seqno); ath9k_hw_set11n_aggr_middle(sc->sc_ah, bf->bf_desc, ndelim); list_move_tail(&bf->list, bf_q); if (bf_prev) { @@ -810,6 +792,7 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, { struct ath_buf *bf; enum ATH_AGGR_STATUS status; + struct ath_frame_info *fi; struct list_head bf_q; int aggr_len; @@ -833,9 +816,11 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, /* if only one frame, send as non-aggregate */ if (bf == bf->bf_lastbf) { + fi = get_frame_info(bf->bf_mpdu); + bf->bf_state.bf_type &= ~BUF_AGGR; ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc); - ath_buf_set_rate(sc, bf, ath_frame_len(bf->bf_mpdu)); + ath_buf_set_rate(sc, bf, fi->framelen); ath_tx_txqaddbuf(sc, txq, &bf_q); continue; } @@ -1346,12 +1331,11 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, struct ath_buf *bf, struct ath_tx_control *txctl) { + struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu); struct list_head bf_head; - u16 bf_seqno; bf->bf_state.bf_type |= BUF_AMPDU; TX_STAT_INC(txctl->txq->axq_qnum, a_queued); - bf_seqno = ath_frame_seqno(bf->bf_mpdu); /* * Do not queue to h/w when any of the following conditions is true: @@ -1361,7 +1345,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, * - h/w queue depth exceeds low water mark */ if (!list_empty(&tid->buf_q) || tid->paused || - !BAW_WITHIN(tid->seq_start, tid->baw_size, bf_seqno) || + !BAW_WITHIN(tid->seq_start, tid->baw_size, fi->seqno) || txctl->txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) { /* * Add this frame to software queue for scheduling later @@ -1376,19 +1360,20 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, list_add(&bf->list, &bf_head); /* Add sub-frame to BAW */ - if (!bf_isretried(bf)) - ath_tx_addto_baw(sc, tid, bf_seqno); + if (!fi->retries) + ath_tx_addto_baw(sc, tid, fi->seqno); /* Queue to h/w without aggregation */ bf->bf_lastbf = bf; - ath_buf_set_rate(sc, bf, txctl->frmlen); + ath_buf_set_rate(sc, bf, fi->framelen); ath_tx_txqaddbuf(sc, txctl->txq, &bf_head); } static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, struct ath_atx_tid *tid, - struct list_head *bf_head, int frmlen) + struct list_head *bf_head) { + struct ath_frame_info *fi; struct ath_buf *bf; bf = list_first_entry(bf_head, struct ath_buf, list); @@ -1399,7 +1384,8 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, INCR(tid->seq_start, IEEE80211_SEQ_MAX); bf->bf_lastbf = bf; - ath_buf_set_rate(sc, bf, frmlen); + fi = get_frame_info(bf->bf_mpdu); + ath_buf_set_rate(sc, bf, fi->framelen); ath_tx_txqaddbuf(sc, txq, bf_head); TX_STAT_INC(txq->axq_qnum, queued); } @@ -1427,30 +1413,49 @@ static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb) return htype; } -static void assign_aggr_tid_seqno(struct sk_buff *skb) +static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb, + int framelen) { + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_sta *sta = tx_info->control.sta; + struct ieee80211_key_conf *hw_key = tx_info->control.hw_key; struct ieee80211_hdr *hdr; + struct ath_frame_info *fi = get_frame_info(skb); struct ath_node *an; struct ath_atx_tid *tid; - __le16 fc; + enum ath9k_key_type keytype; + u16 seqno = 0; u8 tidno; - if (!tx_info->control.sta) - return; + keytype = ath9k_cmn_get_hw_crypto_keytype(skb); - an = (struct ath_node *)tx_info->control.sta->drv_priv; hdr = (struct ieee80211_hdr *)skb->data; - fc = hdr->frame_control; - tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK; + if (sta && ieee80211_is_data_qos(hdr->frame_control) && + conf_is_ht(&hw->conf) && (sc->sc_flags & SC_OP_TXAGGR)) { - /* - * Override seqno set by upper layer with the one - * in tx aggregation state. - */ - tid = ATH_AN_2_TID(an, tidno); - hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT); - INCR(tid->seq_next, IEEE80211_SEQ_MAX); + an = (struct ath_node *) sta->drv_priv; + tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK; + + /* + * Override seqno set by upper layer with the one + * in tx aggregation state. + */ + tid = ATH_AN_2_TID(an, tidno); + seqno = tid->seq_next; + hdr->seq_ctrl = cpu_to_le16(seqno << IEEE80211_SEQ_SEQ_SHIFT); + INCR(tid->seq_next, IEEE80211_SEQ_MAX); + } + + memset(fi, 0, sizeof(*fi)); + if (hw_key) + fi->keyix = hw_key->hw_key_idx; + else + fi->keyix = ATH9K_TXKEYIX_INVALID; + fi->keytype = keytype; + fi->framelen = framelen; + fi->seqno = seqno; } static int setup_tx_flags(struct sk_buff *skb) @@ -1609,18 +1614,15 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len) static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_txq *txq, - struct sk_buff *skb, int frmlen) + struct sk_buff *skb) { 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_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb; + struct ath_frame_info *fi = get_frame_info(skb); struct ath_buf *bf; struct ath_desc *ds; - enum ath9k_key_type keytype; - u32 keyix; int frm_type; bf = ath_tx_get_buffer(sc); @@ -1631,10 +1633,6 @@ static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw, ATH_TXBUF_RESET(bf); - if (ieee80211_is_data_qos(hdr->frame_control) && - conf_is_ht(&hw->conf) && (sc->sc_flags & SC_OP_TXAGGR)) - assign_aggr_tid_seqno(skb); - bf->aphy = aphy; bf->bf_flags = setup_tx_flags(skb); bf->bf_mpdu = skb; @@ -1655,14 +1653,8 @@ static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw, ds = bf->bf_desc; ath9k_hw_set_desc_link(ah, ds, 0); - keytype = ath9k_cmn_get_hw_crypto_keytype(skb); - if (tx_info->control.hw_key) - keyix = tx_info->control.hw_key->hw_key_idx; - else - keyix = ATH9K_TXKEYIX_INVALID; - - ath9k_hw_set11n_txdesc(ah, ds, frmlen, frm_type, MAX_RATE_POWER, - keyix, keytype, bf->bf_flags); + ath9k_hw_set11n_txdesc(ah, ds, fi->framelen, frm_type, MAX_RATE_POWER, + fi->keyix, fi->keytype, bf->bf_flags); ath9k_hw_filltxdesc(ah, ds, skb->len, /* segment length */ @@ -1683,18 +1675,16 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, struct sk_buff *skb = bf->bf_mpdu; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct ath_node *an = NULL; struct list_head bf_head; struct ath_atx_tid *tid; u8 tidno; spin_lock_bh(&txctl->txq->axq_lock); - if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && tx_info->control.sta) { - an = (struct ath_node *)tx_info->control.sta->drv_priv; + if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && txctl->an) { tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK; - tid = ATH_AN_2_TID(an, tidno); + tid = ATH_AN_2_TID(txctl->an, tidno); WARN_ON(tid->ac->txq != txctl->txq); /* @@ -1713,7 +1703,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, ar9003_hw_set_paprd_txdesc(sc->sc_ah, bf->bf_desc, bf->bf_state.bfs_paprd); - ath_tx_send_normal(sc, txctl->txq, NULL, &bf_head, txctl->frmlen); + ath_tx_send_normal(sc, txctl->txq, NULL, &bf_head); } spin_unlock_bh(&txctl->txq->axq_lock); @@ -1725,6 +1715,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_sta *sta = info->control.sta; struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; struct ath_txq *txq = txctl->txq; @@ -1733,11 +1724,10 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, int frmlen = skb->len + FCS_LEN; int q; + txctl->an = (struct ath_node *)sta->drv_priv; if (info->control.hw_key) frmlen += info->control.hw_key->icv_len; - txctl->frmlen = frmlen; - /* * As a temporary workaround, assign seq# here; this will likely need * to be cleaned up to work better with Beacon transmission and virtual @@ -1761,7 +1751,14 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, memmove(skb->data, skb->data + padsize, padpos); } - bf = ath_tx_setup_buffer(hw, txctl->txq, skb, frmlen); + setup_frame_info(hw, skb, frmlen); + + /* + * At this point, the vif, hw_key and sta pointers in the tx control + * info are no longer valid (overwritten by the ath_frame_info data. + */ + + bf = ath_tx_setup_buffer(hw, txctl->txq, skb); if (unlikely(!bf)) return -ENOMEM; -- cgit v0.10.2 From 488f6ba75b5deaa7e89d6cdac07e0f2120899b6f Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 16 Nov 2010 19:20:28 +0100 Subject: ath9k_hw: add support for reading EEPROM data from the internal OTP ROM Some of the new AR9003 cards do not come with an external EEPROM chip anymore. Calibration data on these cards is stored in the OTP ROM on the chip. This patch adds support for reading this data, and also adds support for different EEPROM chip sizes (512 bytes instead of 1K). Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 1b4e991..230a122 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -3104,6 +3104,36 @@ error: return false; } +static bool ar9300_otp_read_word(struct ath_hw *ah, int addr, u32 *data) +{ + REG_READ(ah, AR9300_OTP_BASE + (4 * addr)); + + if (!ath9k_hw_wait(ah, AR9300_OTP_STATUS, AR9300_OTP_STATUS_TYPE, + AR9300_OTP_STATUS_VALID, 1000)) + return false; + + *data = REG_READ(ah, AR9300_OTP_READ_DATA); + return true; +} + +static bool ar9300_read_otp(struct ath_hw *ah, int address, u8 *buffer, + int count) +{ + u32 data; + int i; + + for (i = 0; i < count; i++) { + int offset = 8 * ((address - i) % 4); + if (!ar9300_otp_read_word(ah, (address - i) / 4, &data)) + return false; + + buffer[i] = (data >> offset) & 0xff; + } + + return true; +} + + static void ar9300_comp_hdr_unpack(u8 *best, int *code, int *reference, int *length, int *major, int *minor) { @@ -3221,6 +3251,26 @@ static int ar9300_compress_decision(struct ath_hw *ah, return 0; } +typedef bool (*eeprom_read_op)(struct ath_hw *ah, int address, u8 *buffer, + int count); + +static bool ar9300_check_header(void *data) +{ + u32 *word = data; + return !(*word == 0 || *word == ~0); +} + +static bool ar9300_check_eeprom_header(struct ath_hw *ah, eeprom_read_op read, + int base_addr) +{ + u8 header[4]; + + if (!read(ah, base_addr, header, 4)) + return false; + + return ar9300_check_header(header); +} + /* * Read the configuration data from the eeprom. * The data can be put in any specified memory buffer. @@ -3241,6 +3291,7 @@ static int ar9300_eeprom_restore_internal(struct ath_hw *ah, int it; u16 checksum, mchecksum; struct ath_common *common = ath9k_hw_common(ah); + eeprom_read_op read; word = kzalloc(2048, GFP_KERNEL); if (!word) @@ -3248,14 +3299,42 @@ static int ar9300_eeprom_restore_internal(struct ath_hw *ah, memcpy(mptr, &ar9300_default, mdata_size); + read = ar9300_read_eeprom; cptr = AR9300_BASE_ADDR; + ath_print(common, ATH_DBG_EEPROM, + "Trying EEPROM accesss at Address 0x%04x\n", cptr); + if (ar9300_check_eeprom_header(ah, read, cptr)) + goto found; + + cptr = AR9300_BASE_ADDR_512; + ath_print(common, ATH_DBG_EEPROM, + "Trying EEPROM accesss at Address 0x%04x\n", cptr); + if (ar9300_check_eeprom_header(ah, read, cptr)) + goto found; + + read = ar9300_read_otp; + cptr = AR9300_BASE_ADDR; + ath_print(common, ATH_DBG_EEPROM, + "Trying OTP accesss at Address 0x%04x\n", cptr); + if (ar9300_check_eeprom_header(ah, read, cptr)) + goto found; + + cptr = AR9300_BASE_ADDR_512; + ath_print(common, ATH_DBG_EEPROM, + "Trying OTP accesss at Address 0x%04x\n", cptr); + if (ar9300_check_eeprom_header(ah, read, cptr)) + goto found; + + goto fail; + +found: + ath_print(common, ATH_DBG_EEPROM, "Found valid EEPROM data"); + for (it = 0; it < MSTATE; it++) { - if (!ar9300_read_eeprom(ah, cptr, word, COMP_HDR_LEN)) + if (!read(ah, cptr, word, COMP_HDR_LEN)) goto fail; - if ((word[0] == 0 && word[1] == 0 && word[2] == 0 && - word[3] == 0) || (word[0] == 0xff && word[1] == 0xff - && word[2] == 0xff && word[3] == 0xff)) + if (!ar9300_check_header(word)) break; ar9300_comp_hdr_unpack(word, &code, &reference, @@ -3272,8 +3351,7 @@ static int ar9300_eeprom_restore_internal(struct ath_hw *ah, } osize = length; - ar9300_read_eeprom(ah, cptr, word, - COMP_HDR_LEN + osize + COMP_CKSUM_LEN); + read(ah, cptr, word, COMP_HDR_LEN + osize + COMP_CKSUM_LEN); checksum = ar9300_comp_cksum(&word[COMP_HDR_LEN], length); mchecksum = word[COMP_HDR_LEN + osize] | (word[COMP_HDR_LEN + osize + 1] << 8); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h index 5301df3..57f64db 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h @@ -79,6 +79,15 @@ #define FIXED_CCA_THRESHOLD 15 #define AR9300_BASE_ADDR 0x3ff +#define AR9300_BASE_ADDR_512 0x1ff + +#define AR9300_OTP_BASE 0x14000 +#define AR9300_OTP_STATUS 0x15f18 +#define AR9300_OTP_STATUS_TYPE 0x7 +#define AR9300_OTP_STATUS_VALID 0x4 +#define AR9300_OTP_STATUS_ACCESS_BUSY 0x2 +#define AR9300_OTP_STATUS_SM_BUSY 0x1 +#define AR9300_OTP_READ_DATA 0x15f1c enum targetPowerHTRates { HT_TARGET_RATE_0_8_16, -- cgit v0.10.2 From 4bce22b9b84032c77c7e038b07b24fcc706dfc10 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 16 Nov 2010 11:49:58 -0800 Subject: mac80211: defines for AC numbers In many places we've just hardcoded the AC numbers -- which is a relic from the original mac80211 (d80211). Add constants for them so we know what we're talking about. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 1248369..5b0fff2 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -97,6 +97,20 @@ enum ieee80211_max_queues { }; /** + * enum ieee80211_ac_numbers - AC numbers as used in mac80211 + * @IEEE80211_AC_VO: voice + * @IEEE80211_AC_VI: video + * @IEEE80211_AC_BE: best effort + * @IEEE80211_AC_BK: background + */ +enum ieee80211_ac_numbers { + IEEE80211_AC_VO = 0, + IEEE80211_AC_VI = 1, + IEEE80211_AC_BE = 2, + IEEE80211_AC_BK = 3, +}; + +/** * struct ieee80211_tx_queue_params - transmit queue configuration * * The information provided in this structure is required for QoS diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 34e6d02..58e75bb 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -21,7 +21,16 @@ /* Default mapping in classifier to work with default * queue setup. */ -const int ieee802_1d_to_ac[8] = { 2, 3, 3, 2, 1, 1, 0, 0 }; +const int ieee802_1d_to_ac[8] = { + IEEE80211_AC_BE, + IEEE80211_AC_BK, + IEEE80211_AC_BK, + IEEE80211_AC_BE, + IEEE80211_AC_VI, + IEEE80211_AC_VI, + IEEE80211_AC_VO, + IEEE80211_AC_VO +}; static int wme_downgrade_ac(struct sk_buff *skb) { -- cgit v0.10.2 From 50a9432daeece6fc1309bef1dc0a7b8fde8204cb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 16 Nov 2010 11:50:28 -0800 Subject: mac80211: fix powersaving clients races The code to handle powersaving stations has a race: when the powersave flag is lifted from a station, we could transmit a packet that is being processed for TX at the same time right away, even if there are other frames queued for it. This would cause frame reordering. To fix this, lift the flag only under the appropriate lock that blocks TX. Additionally, the code to allow drivers to block a station while frames for it are on the HW queue is never re-enabled the station, so traffic would get stuck indefinitely. Fix this by clearing the flag for this appropriately. Finally, as an optimisation, don't do anything if the driver unblocks an already unblocked station. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 59a1d38..3598abf 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1278,6 +1278,9 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local, struct sk_buff *skb); int ieee80211_add_pending_skbs(struct ieee80211_local *local, struct sk_buff_head *skbs); +int ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, + struct sk_buff_head *skbs, + void (*fn)(void *data), void *data); void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, u16 transaction, u16 auth_alg, diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 902b03ee..d2fcd22 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1102,8 +1102,6 @@ static void ap_sta_ps_end(struct sta_info *sta) atomic_dec(&sdata->bss->num_sta_ps); - clear_sta_flags(sta, WLAN_STA_PS_STA); - #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "%s: STA %pM aid %d exits power save mode\n", sdata->name, sta->sta.addr, sta->sta.aid); diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 6d8f897..eff5857 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -199,8 +199,11 @@ static void sta_unblock(struct work_struct *wk) if (!test_sta_flags(sta, WLAN_STA_PS_STA)) ieee80211_sta_ps_deliver_wakeup(sta); - else if (test_and_clear_sta_flags(sta, WLAN_STA_PSPOLL)) + else if (test_and_clear_sta_flags(sta, WLAN_STA_PSPOLL)) { + clear_sta_flags(sta, WLAN_STA_PS_DRIVER); ieee80211_sta_ps_deliver_poll_response(sta); + } else + clear_sta_flags(sta, WLAN_STA_PS_DRIVER); } static int sta_prepare_rate_control(struct ieee80211_local *local, @@ -880,6 +883,13 @@ struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif, } EXPORT_SYMBOL(ieee80211_find_sta); +static void clear_sta_ps_flags(void *_sta) +{ + struct sta_info *sta = _sta; + + clear_sta_flags(sta, WLAN_STA_PS_DRIVER | WLAN_STA_PS_STA); +} + /* powersave support code */ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) { @@ -894,7 +904,8 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) /* Send all buffered frames to the station */ sent = ieee80211_add_pending_skbs(local, &sta->tx_filtered); - buffered = ieee80211_add_pending_skbs(local, &sta->ps_tx_buf); + buffered = ieee80211_add_pending_skbs_fn(local, &sta->ps_tx_buf, + clear_sta_ps_flags, sta); sent += buffered; local->total_ps_buffered -= buffered; @@ -973,7 +984,7 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw, if (block) set_sta_flags(sta, WLAN_STA_PS_DRIVER); - else + else if (test_sta_flags(sta, WLAN_STA_PS_DRIVER)) ieee80211_queue_work(hw, &sta->drv_unblock_wk); } EXPORT_SYMBOL(ieee80211_sta_block_awake); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 68d0518..e497476 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -368,8 +368,9 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local, spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); } -int ieee80211_add_pending_skbs(struct ieee80211_local *local, - struct sk_buff_head *skbs) +int ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, + struct sk_buff_head *skbs, + void (*fn)(void *data), void *data) { struct ieee80211_hw *hw = &local->hw; struct sk_buff *skb; @@ -394,6 +395,9 @@ int ieee80211_add_pending_skbs(struct ieee80211_local *local, __skb_queue_tail(&local->pending[queue], skb); } + if (fn) + fn(data); + for (i = 0; i < hw->queues; i++) __ieee80211_wake_queue(hw, i, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); @@ -402,6 +406,12 @@ int ieee80211_add_pending_skbs(struct ieee80211_local *local, return ret; } +int ieee80211_add_pending_skbs(struct ieee80211_local *local, + struct sk_buff_head *skbs) +{ + return ieee80211_add_pending_skbs_fn(local, skbs, NULL, NULL); +} + void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, enum queue_stop_reason reason) { -- cgit v0.10.2 From c5485a7e7569ab32eea240c850198519e2a765ef Mon Sep 17 00:00:00 2001 From: Bruno Randolf Date: Tue, 16 Nov 2010 10:58:37 +0900 Subject: lib: Add generic exponentially weighted moving average (EWMA) function This adds generic functions for calculating Exponentially Weighted Moving Averages (EWMA). This implementation makes use of a structure which keeps the EWMA parameters and a scaled up internal representation to reduce rounding errors. The original idea for this implementation came from the rt2x00 driver (rt2x00link.c). I would like to use it in several places in the mac80211 and ath5k code and I hope it can be useful in many other places in the kernel code. Signed-off-by: Bruno Randolf Reviewed-by: KOSAKI Motohiro Signed-off-by: John W. Linville diff --git a/include/linux/average.h b/include/linux/average.h new file mode 100644 index 0000000..7706e40 --- /dev/null +++ b/include/linux/average.h @@ -0,0 +1,32 @@ +#ifndef _LINUX_AVERAGE_H +#define _LINUX_AVERAGE_H + +#include + +/* Exponentially weighted moving average (EWMA) */ + +/* For more documentation see lib/average.c */ + +struct ewma { + unsigned long internal; + unsigned long factor; + unsigned long weight; +}; + +extern void ewma_init(struct ewma *avg, unsigned long factor, + unsigned long weight); + +extern struct ewma *ewma_add(struct ewma *avg, unsigned long val); + +/** + * ewma_read() - Get average value + * @avg: Average structure + * + * Returns the average value held in @avg. + */ +static inline unsigned long ewma_read(const struct ewma *avg) +{ + return DIV_ROUND_CLOSEST(avg->internal, avg->factor); +} + +#endif /* _LINUX_AVERAGE_H */ diff --git a/lib/Kconfig b/lib/Kconfig index fa9bf2c..3116aa6 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -210,4 +210,7 @@ config GENERIC_ATOMIC64 config LRU_CACHE tristate +config AVERAGE + bool + endmenu diff --git a/lib/Makefile b/lib/Makefile index e6a3763..76d3b85 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -106,6 +106,8 @@ obj-$(CONFIG_GENERIC_ATOMIC64) += atomic64.o obj-$(CONFIG_ATOMIC64_SELFTEST) += atomic64_test.o +obj-$(CONFIG_AVERAGE) += average.o + hostprogs-y := gen_crc32table clean-files := crc32table.h diff --git a/lib/average.c b/lib/average.c new file mode 100644 index 0000000..f1d1b46 --- /dev/null +++ b/lib/average.c @@ -0,0 +1,57 @@ +/* + * lib/average.c + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#include +#include +#include + +/** + * DOC: Exponentially Weighted Moving Average (EWMA) + * + * These are generic functions for calculating Exponentially Weighted Moving + * Averages (EWMA). We keep a structure with the EWMA parameters and a scaled + * up internal representation of the average value to prevent rounding errors. + * The factor for scaling up and the exponential weight (or decay rate) have to + * be specified thru the init fuction. The structure should not be accessed + * directly but only thru the helper functions. + */ + +/** + * ewma_init() - Initialize EWMA parameters + * @avg: Average structure + * @factor: Factor to use for the scaled up internal value. The maximum value + * of averages can be ULONG_MAX/(factor*weight). + * @weight: Exponential weight, or decay rate. This defines how fast the + * influence of older values decreases. Has to be bigger than 1. + * + * Initialize the EWMA parameters for a given struct ewma @avg. + */ +void ewma_init(struct ewma *avg, unsigned long factor, unsigned long weight) +{ + WARN_ON(weight <= 1 || factor == 0); + avg->internal = 0; + avg->weight = weight; + avg->factor = factor; +} +EXPORT_SYMBOL(ewma_init); + +/** + * ewma_add() - Exponentially weighted moving average (EWMA) + * @avg: Average structure + * @val: Current value + * + * Add a sample to the average. + */ +struct ewma *ewma_add(struct ewma *avg, unsigned long val) +{ + avg->internal = avg->internal ? + (((avg->internal * (avg->weight - 1)) + + (val * avg->factor)) / avg->weight) : + (val * avg->factor); + return avg; +} +EXPORT_SYMBOL(ewma_add); -- cgit v0.10.2 From eef39befaae2a1559efe197d795c376a317af2af Mon Sep 17 00:00:00 2001 From: Bruno Randolf Date: Tue, 16 Nov 2010 10:58:43 +0900 Subject: ath5k: Use generic EWMA library Remove ath5k's private moving average implementation in favour of the generic library version. Signed-off-by: Bruno Randolf Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/Kconfig b/drivers/net/wireless/ath/ath5k/Kconfig index eb83b7b..4784457 100644 --- a/drivers/net/wireless/ath/ath5k/Kconfig +++ b/drivers/net/wireless/ath/ath5k/Kconfig @@ -4,6 +4,7 @@ config ATH5K select MAC80211_LEDS select LEDS_CLASS select NEW_LEDS + select AVERAGE ---help--- This module adds support for wireless adapters based on Atheros 5xxx chipset. diff --git a/drivers/net/wireless/ath/ath5k/ani.c b/drivers/net/wireless/ath/ath5k/ani.c index f141919..db98a85 100644 --- a/drivers/net/wireless/ath/ath5k/ani.c +++ b/drivers/net/wireless/ath/ath5k/ani.c @@ -216,7 +216,7 @@ static void ath5k_ani_raise_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as, bool ofdm_trigger) { - int rssi = ah->ah_beacon_rssi_avg.avg; + int rssi = ewma_read(&ah->ah_beacon_rssi_avg); ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "raise immunity (%s)", ofdm_trigger ? "ODFM" : "CCK"); @@ -301,7 +301,7 @@ ath5k_ani_raise_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as, static void ath5k_ani_lower_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as) { - int rssi = ah->ah_beacon_rssi_avg.avg; + int rssi = ewma_read(&ah->ah_beacon_rssi_avg); ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "lower immunity"); diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 308b79e..2718136 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -25,6 +25,7 @@ #include #include +#include #include /* RX/TX descriptor hw structs @@ -1102,7 +1103,7 @@ struct ath5k_hw { struct ath5k_nfcal_hist ah_nfcal_hist; /* average beacon RSSI in our BSS (used by ANI) */ - struct ath5k_avg_val ah_beacon_rssi_avg; + struct ewma ah_beacon_rssi_avg; /* noise floor from last periodic calibration */ s32 ah_noise_floor; @@ -1315,27 +1316,4 @@ static inline u32 ath5k_hw_bitswap(u32 val, unsigned int bits) return retval; } -#define AVG_SAMPLES 8 -#define AVG_FACTOR 1000 - -/** - * ath5k_moving_average - Exponentially weighted moving average - * @avg: average structure - * @val: current value - * - * This implementation make use of a struct ath5k_avg_val to prevent rounding - * errors. - */ -static inline struct ath5k_avg_val -ath5k_moving_average(const struct ath5k_avg_val avg, const int val) -{ - struct ath5k_avg_val new; - new.avg_weight = avg.avg_weight ? - (((avg.avg_weight * ((AVG_SAMPLES) - 1)) + - (val * (AVG_FACTOR))) / (AVG_SAMPLES)) : - (val * (AVG_FACTOR)); - new.avg = new.avg_weight / (AVG_FACTOR); - return new; -} - #endif diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 13735cc..7f783d9 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1301,8 +1301,7 @@ ath5k_update_beacon_rssi(struct ath5k_softc *sc, struct sk_buff *skb, int rssi) memcmp(mgmt->bssid, common->curbssid, ETH_ALEN) != 0) return; - ah->ah_beacon_rssi_avg = ath5k_moving_average(ah->ah_beacon_rssi_avg, - rssi); + ewma_add(&ah->ah_beacon_rssi_avg, rssi); /* in IBSS mode we should keep RSSI statistics per neighbour */ /* le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS */ @@ -2556,6 +2555,7 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan) ah->ah_cal_next_full = jiffies; ah->ah_cal_next_ani = jiffies; ah->ah_cal_next_nf = jiffies; + ewma_init(&ah->ah_beacon_rssi_avg, 1000, 8); /* * Change channels and update the h/w rate map if we're switching; diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c index 54dcf77..7d785cb6 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c @@ -719,7 +719,7 @@ static ssize_t read_file_ani(struct file *file, char __user *user_buf, st->mib_intr); len += snprintf(buf+len, sizeof(buf)-len, "beacon RSSI average:\t%d\n", - sc->ah->ah_beacon_rssi_avg.avg); + (int)ewma_read(&sc->ah->ah_beacon_rssi_avg)); #define CC_PRINT(_struct, _field) \ _struct._field, \ -- cgit v0.10.2 From 86107fd170bc379869250eb7e1bd393a3a70e8ae Mon Sep 17 00:00:00 2001 From: Bruno Randolf Date: Tue, 16 Nov 2010 10:58:48 +0900 Subject: nl80211/mac80211: Report signal average Extend nl80211 to report an exponential weighted moving average (EWMA) of the signal value. Since the signal value usually fluctuates between different packets, an average can be more useful than the value of the last packet. This uses the recently added generic EWMA library function. Signed-off-by: Bruno Randolf Signed-off-by: John W. Linville diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 037b4e4..1ce3775 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -1161,6 +1161,7 @@ enum nl80211_rate_info { * @__NL80211_STA_INFO_AFTER_LAST: internal * @NL80211_STA_INFO_MAX: highest possible station info attribute * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm) + * @NL80211_STA_INFO_SIGNAL_AVG: signal strength average (u8, dBm) * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute * containing info as possible, see &enum nl80211_sta_info_txrate. * @NL80211_STA_INFO_RX_PACKETS: total received packet (u32, from this station) @@ -1178,6 +1179,7 @@ enum nl80211_sta_info { NL80211_STA_INFO_PLID, NL80211_STA_INFO_PLINK_STATE, NL80211_STA_INFO_SIGNAL, + NL80211_STA_INFO_SIGNAL_AVG, NL80211_STA_INFO_TX_BITRATE, NL80211_STA_INFO_RX_PACKETS, NL80211_STA_INFO_TX_PACKETS, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 8fd9eeb..69e2364 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -424,6 +424,7 @@ struct station_parameters { * @STATION_INFO_TX_RETRIES: @tx_retries filled * @STATION_INFO_TX_FAILED: @tx_failed filled * @STATION_INFO_RX_DROP_MISC: @rx_dropped_misc filled + * @STATION_INFO_SIGNAL_AVG: @signal_avg filled */ enum station_info_flags { STATION_INFO_INACTIVE_TIME = 1<<0, @@ -439,6 +440,7 @@ enum station_info_flags { STATION_INFO_TX_RETRIES = 1<<10, STATION_INFO_TX_FAILED = 1<<11, STATION_INFO_RX_DROP_MISC = 1<<12, + STATION_INFO_SIGNAL_AVG = 1<<13, }; /** @@ -485,6 +487,7 @@ struct rate_info { * @plid: mesh peer link id * @plink_state: mesh peer link state * @signal: signal strength of last received packet in dBm + * @signal_avg: signal strength average in dBm * @txrate: current unicast bitrate to this station * @rx_packets: packets received from this station * @tx_packets: packets transmitted to this station @@ -505,6 +508,7 @@ struct station_info { u16 plid; u8 plink_state; s8 signal; + s8 signal_avg; struct rate_info txrate; u32 rx_packets; u32 tx_packets; diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 4d6f865..798d9b9 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -6,6 +6,7 @@ config MAC80211 select CRYPTO_ARC4 select CRYPTO_AES select CRC32 + select AVERAGE ---help--- This option enables the hardware independent IEEE 802.11 networking stack. diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 0c54407..92c9cf6 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -343,8 +343,9 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) || (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) { - sinfo->filled |= STATION_INFO_SIGNAL; + sinfo->filled |= STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG; sinfo->signal = (s8)sta->last_signal; + sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal); } sinfo->txrate.flags = 0; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index d2fcd22..9dd60a7 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1156,6 +1156,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) sta->rx_fragments++; sta->rx_bytes += rx->skb->len; sta->last_signal = status->signal; + ewma_add(&sta->avg_signal, -status->signal); /* * Change STA power saving mode only at the end of a frame diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index eff5857..f43fca8 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -244,6 +244,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, sta->local = local; sta->sdata = sdata; + ewma_init(&sta->avg_signal, 1000, 8); + if (sta_prepare_rate_control(local, sta, gfp)) { kfree(sta); return NULL; diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 9265aca..84062e2 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -13,6 +13,7 @@ #include #include #include +#include #include "key.h" /** @@ -224,6 +225,7 @@ enum plink_state { * @rx_fragments: number of received MPDUs * @rx_dropped: number of dropped MPDUs from this STA * @last_signal: signal of last received frame from this STA + * @avg_signal: moving average of signal of received frames from this STA * @last_seq_ctrl: last received seq/frag number from this STA (per RX queue) * @tx_filtered_count: number of frames the hardware filtered for this STA * @tx_retry_failed: number of frames that failed retry @@ -291,6 +293,7 @@ struct sta_info { unsigned long rx_fragments; unsigned long rx_dropped; int last_signal; + struct ewma avg_signal; __le16 last_seq_ctrl[NUM_RX_DATA_QUEUES]; /* Updated from TX status path only, no locking requirements */ diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 6055538..d06a40d 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -1872,6 +1872,9 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, if (sinfo->filled & STATION_INFO_SIGNAL) NLA_PUT_U8(msg, NL80211_STA_INFO_SIGNAL, sinfo->signal); + if (sinfo->filled & STATION_INFO_SIGNAL_AVG) + NLA_PUT_U8(msg, NL80211_STA_INFO_SIGNAL_AVG, + sinfo->signal_avg); if (sinfo->filled & STATION_INFO_TX_BITRATE) { txrate = nla_nest_start(msg, NL80211_STA_INFO_TX_BITRATE); if (!txrate) -- cgit v0.10.2 From 8befba6f2262a6e31d6e3bcf7d07ff46da444ec0 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 16 Nov 2010 16:08:56 -0500 Subject: iwmc3200wifi: clarify potentially undefined operation in iwm_scan_ssids MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CC [M] drivers/net/wireless/iwmc3200wifi/commands.o drivers/net/wireless/iwmc3200wifi/commands.c: In function ‘iwm_scan_ssids’: drivers/net/wireless/iwmc3200wifi/commands.c:911:15: warning: operation on ‘iwm->scan_id’ may be undefined Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c index 330c7d9..50dee6a 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -908,7 +908,7 @@ int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids, return ret; } - iwm->scan_id = iwm->scan_id++ % IWM_SCAN_ID_MAX; + iwm->scan_id = (iwm->scan_id + 1) % IWM_SCAN_ID_MAX; return 0; } -- cgit v0.10.2 From 458fafdd579dcb58c8288c55c9cd92d6816ba094 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 16 Nov 2010 16:49:08 -0500 Subject: rndis_wlan: avoid uninitialized var warning in rndis_wlan_craft_connected_bss MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CC [M] drivers/net/wireless/rndis_wlan.o drivers/net/wireless/rndis_wlan.c: In function ‘rndis_wlan_craft_connected_bss’: drivers/net/wireless/rndis_wlan.c:2542:2: warning: ‘ret’ may be used uninitialized in this function Signed-off-by: John W. Linville Acked-by: Jussi Kivilinna diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 8a77ff6..ee08bca 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -2536,7 +2536,7 @@ static void rndis_wlan_craft_connected_bss(struct usbnet *usbdev, u8 *bssid, /* Get signal quality, in case of error use rssi=0 and ignore error. */ len = sizeof(rssi); rssi = 0; - rndis_query_oid(usbdev, OID_802_11_RSSI, &rssi, &len); + ret = rndis_query_oid(usbdev, OID_802_11_RSSI, &rssi, &len); signal = level_to_qual(le32_to_cpu(rssi)); netdev_dbg(usbdev->net, "%s(): OID_802_11_RSSI -> %d, " -- cgit v0.10.2 From a05b5d45049d60a06a1b12976150572304a51928 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 17 Nov 2010 04:25:33 +0100 Subject: ath9k: add support for reading eeprom from platform data on PCI devices Some embedded boards store platform data for connected PCIe AR92xx chips in the system flash instead of a separate EEPROM chip. Signed-off-by: Gabor Juhos Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 75e2363..5a13a76 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -419,10 +419,6 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah) ah->hw_version.magic = AR5416_MAGIC; ah->hw_version.subvendorid = 0; - ah->ah_flags = 0; - if (!AR_SREV_9100(ah)) - ah->ah_flags = AH_USE_EEPROM; - ah->atim_window = 0; ah->sta_id1_defaults = AR_STA_ID1_CRPT_MIC_ENABLE | diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 498f621..e7764ce 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -530,6 +530,9 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, ah->hw_version.subsysid = subsysid; sc->sc_ah = ah; + if (!sc->dev->platform_data) + ah->ah_flags |= AH_USE_EEPROM; + common = ath9k_hw_common(ah); common->ops = &ath9k_common_ops; common->bus_ops = bus_ops; diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 6605bc2..09f69a9 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -16,6 +16,7 @@ #include #include +#include #include "ath9k.h" static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = { @@ -53,21 +54,36 @@ static void ath_pci_read_cachesize(struct ath_common *common, int *csz) static bool ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data) { - struct ath_hw *ah = (struct ath_hw *) common->ah; - - common->ops->read(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S)); - - if (!ath9k_hw_wait(ah, - AR_EEPROM_STATUS_DATA, - AR_EEPROM_STATUS_DATA_BUSY | - AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0, - AH_WAIT_TIMEOUT)) { - return false; + struct ath_softc *sc = (struct ath_softc *) common->priv; + struct ath9k_platform_data *pdata = sc->dev->platform_data; + + if (pdata) { + if (off >= (ARRAY_SIZE(pdata->eeprom_data))) { + ath_print(common, ATH_DBG_FATAL, + "%s: eeprom read failed, offset %08x " + "is out of range\n", + __func__, off); + } + + *data = pdata->eeprom_data[off]; + } else { + struct ath_hw *ah = (struct ath_hw *) common->ah; + + common->ops->read(ah, AR5416_EEPROM_OFFSET + + (off << AR5416_EEPROM_S)); + + if (!ath9k_hw_wait(ah, + AR_EEPROM_STATUS_DATA, + AR_EEPROM_STATUS_DATA_BUSY | + AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0, + AH_WAIT_TIMEOUT)) { + return false; + } + + *data = MS(common->ops->read(ah, AR_EEPROM_STATUS_DATA), + AR_EEPROM_STATUS_DATA_VAL); } - *data = MS(common->ops->read(ah, AR_EEPROM_STATUS_DATA), - AR_EEPROM_STATUS_DATA_VAL); - return true; } -- cgit v0.10.2 From aaa13ca2428789b3c8096b5edc175d4d78b5f504 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 17 Nov 2010 04:19:47 +0100 Subject: ath9k_hw: support reading calibration data from flash on AR9003 Embedded boards do not have compressed EEPROM data, they use the struct ar9003_eeprom layout, with little endian fields, so copying the raw data to the eeprom buffer is enough. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 230a122..9a7e151 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -3271,6 +3271,18 @@ static bool ar9300_check_eeprom_header(struct ath_hw *ah, eeprom_read_op read, return ar9300_check_header(header); } +static int ar9300_eeprom_restore_flash(struct ath_hw *ah, u8 *mptr, + int mdata_size) +{ + struct ath_common *common = ath9k_hw_common(ah); + u16 *data = (u16 *) mptr; + int i; + + for (i = 0; i < mdata_size / 2; i++, data++) + ath9k_hw_nvram_read(common, i, data); + + return 0; +} /* * Read the configuration data from the eeprom. * The data can be put in any specified memory buffer. @@ -3293,6 +3305,9 @@ static int ar9300_eeprom_restore_internal(struct ath_hw *ah, struct ath_common *common = ath9k_hw_common(ah); eeprom_read_op read; + if (ath9k_hw_use_flash(ah)) + return ar9300_eeprom_restore_flash(ah, mptr, mdata_size); + word = kzalloc(2048, GFP_KERNEL); if (!word) return -1; -- cgit v0.10.2 From a76a574ca9ce7c05791cee42f000f2a42c687837 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 17 Nov 2010 19:52:13 +0100 Subject: ssb: drop BCM4328 hack for SPROM revision MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This hacks leads to incorrect SPROM parsing for me and reading for example MAC as: 00:00:00:54:00:00. Michael G. who introduced this confirmed it is not needed anymore. Signed-off-by: Rafał Miłecki Tested-by: Michael Gerdau Signed-off-by: John W. Linville diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index b5343ac..f529663 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -580,10 +580,6 @@ static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out, * Always extract r1. */ out->revision = 1; ssb_dprintk(KERN_DEBUG PFX "SPROM treated as revision %d\n", out->revision); - } else if (bus->chip_id == 0x4321) { - /* the BCM4328 has a chipid == 0x4321 and a rev 4 SPROM */ - out->revision = 4; - ssb_dprintk(KERN_DEBUG PFX "SPROM treated as revision %d\n", out->revision); } switch (out->revision) { -- cgit v0.10.2 From 00d201001bd4e8a46e3d03c970abcb72256c368b Mon Sep 17 00:00:00 2001 From: Shahar Levi Date: Mon, 8 Nov 2010 11:20:10 +0000 Subject: wl1271: Change wl12xx Files Names All files name prefix removed due to the fact that wl12xx driver supports wl1271 and wl1273. Also the definition in Kconfig and header files changed respectively. Signed-off-by: Shahar Levi Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig index 02ad4bc..d2adeb1 100644 --- a/drivers/net/wireless/wl12xx/Kconfig +++ b/drivers/net/wireless/wl12xx/Kconfig @@ -1,56 +1,58 @@ -menuconfig WL12XX +menuconfig WL12XX_MENU tristate "TI wl12xx driver support" depends on MAC80211 && EXPERIMENTAL ---help--- - This will enable TI wl12xx driver support. The drivers make - use of the mac80211 stack. + This will enable TI wl12xx driver support for the following chips: + wl1271 and wl1273. + The drivers make use of the mac80211 stack. -config WL1271 - tristate "TI wl1271 support" - depends on WL12XX && GENERIC_HARDIRQS +config WL12XX + tristate "TI wl12xx support" + depends on WL12XX_MENU && GENERIC_HARDIRQS depends on INET select FW_LOADER select CRC7 ---help--- - This module adds support for wireless adapters based on the - TI wl1271 chipset. + This module adds support for wireless adapters based on TI wl1271 and + TI wl1273 chipsets. This module does *not* include support for wl1251. + For wl1251 support, use the separate homonymous driver instead. - If you choose to build a module, it'll be called wl1271. Say N if + If you choose to build a module, it will be called wl12xx. Say N if unsure. -config WL1271_HT - bool "TI wl1271 802.11 HT support (EXPERIMENTAL)" - depends on WL1271 && EXPERIMENTAL +config WL12XX_HT + bool "TI wl12xx 802.11 HT support (EXPERIMENTAL)" + depends on WL12XX && EXPERIMENTAL default n ---help--- - This will enable 802.11 HT support for TI wl1271 chipset. + This will enable 802.11 HT support in the wl12xx module. That configuration is temporary due to the code incomplete and still in testing process. -config WL1271_SPI - tristate "TI wl1271 SPI support" - depends on WL1271 && SPI_MASTER +config WL12XX_SPI + tristate "TI wl12xx SPI support" + depends on WL12XX && SPI_MASTER ---help--- This module adds support for the SPI interface of adapters using - TI wl1271 chipset. Select this if your platform is using + TI wl12xx chipsets. Select this if your platform is using the SPI bus. - If you choose to build a module, it'll be called wl1251_spi. + If you choose to build a module, it'll be called wl12xx_spi. Say N if unsure. -config WL1271_SDIO - tristate "TI wl1271 SDIO support" - depends on WL1271 && MMC +config WL12XX_SDIO + tristate "TI wl12xx SDIO support" + depends on WL12XX && MMC ---help--- This module adds support for the SDIO interface of adapters using - TI wl1271 chipset. Select this if your platform is using + TI wl12xx chipsets. Select this if your platform is using the SDIO bus. - If you choose to build a module, it'll be called - wl1271_sdio. Say N if unsure. + If you choose to build a module, it'll be called wl12xx_sdio. + Say N if unsure. config WL12XX_PLATFORM_DATA bool - depends on WL1271_SDIO != n || WL1251_SDIO != n + depends on WL12XX_SDIO != n || WL1251_SDIO != n default y diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile index 3a80744..005a758 100644 --- a/drivers/net/wireless/wl12xx/Makefile +++ b/drivers/net/wireless/wl12xx/Makefile @@ -1,12 +1,13 @@ -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 \ - wl1271_init.o wl1271_debugfs.o wl1271_scan.o +wl12xx-objs = main.o cmd.o io.o event.o tx.o rx.o ps.o acx.o \ + boot.o init.o debugfs.o scan.o -wl1271-$(CONFIG_NL80211_TESTMODE) += wl1271_testmode.o -obj-$(CONFIG_WL1271) += wl1271.o -obj-$(CONFIG_WL1271_SPI) += wl1271_spi.o -obj-$(CONFIG_WL1271_SDIO) += wl1271_sdio.o +wl12xx_spi-objs = spi.o +wl12xx_sdio-objs = sdio.o + +wl12xx-$(CONFIG_NL80211_TESTMODE) += testmode.o +obj-$(CONFIG_WL12XX) += wl12xx.o +obj-$(CONFIG_WL12XX_SPI) += wl12xx_spi.o +obj-$(CONFIG_WL12XX_SDIO) += wl12xx_sdio.o # small builtin driver bit obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx_platform_data.o diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c new file mode 100644 index 0000000..bc1085b --- /dev/null +++ b/drivers/net/wireless/wl12xx/acx.c @@ -0,0 +1,1336 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 "acx.h" + +#include +#include +#include +#include +#include + +#include "wl12xx.h" +#include "wl12xx_80211.h" +#include "reg.h" +#include "ps.h" + +int wl1271_acx_wake_up_conditions(struct wl1271 *wl) +{ + struct acx_wake_up_condition *wake_up; + int ret; + + wl1271_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 = wl->conf.conn.wake_up_event; + wake_up->listen_interval = wl->conf.conn.listen_interval; + + ret = wl1271_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS, + wake_up, sizeof(*wake_up)); + if (ret < 0) { + wl1271_warning("could not set wake up conditions: %d", ret); + goto out; + } + +out: + kfree(wake_up); + return ret; +} + +int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth) +{ + struct acx_sleep_auth *auth; + int ret; + + wl1271_debug(DEBUG_ACX, "acx sleep auth"); + + auth = kzalloc(sizeof(*auth), GFP_KERNEL); + if (!auth) { + ret = -ENOMEM; + goto out; + } + + auth->sleep_auth = sleep_auth; + + ret = wl1271_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth)); + if (ret < 0) + return ret; + +out: + kfree(auth); + return ret; +} + +int wl1271_acx_tx_power(struct wl1271 *wl, int power) +{ + struct acx_current_tx_power *acx; + int ret; + + wl1271_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 = wl1271_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("configure of tx power failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_feature_cfg(struct wl1271 *wl) +{ + struct acx_feature_config *feature; + int ret; + + wl1271_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 = wl1271_cmd_configure(wl, ACX_FEATURE_CFG, + feature, sizeof(*feature)); + if (ret < 0) { + wl1271_error("Couldnt set HW encryption"); + goto out; + } + +out: + kfree(feature); + return ret; +} + +int wl1271_acx_mem_map(struct wl1271 *wl, struct acx_header *mem_map, + size_t len) +{ + int ret; + + wl1271_debug(DEBUG_ACX, "acx mem map"); + + ret = wl1271_cmd_interrogate(wl, ACX_MEM_MAP, mem_map, len); + if (ret < 0) + return ret; + + return 0; +} + +int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl) +{ + struct acx_rx_msdu_lifetime *acx; + int ret; + + wl1271_debug(DEBUG_ACX, "acx rx msdu life time"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->lifetime = cpu_to_le32(wl->conf.rx.rx_msdu_life_time); + ret = wl1271_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME, + acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("failed to set rx msdu life time: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_rx_config(struct wl1271 *wl, u32 config, u32 filter) +{ + struct acx_rx_config *rx_config; + int ret; + + wl1271_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 = cpu_to_le32(config); + rx_config->filter_options = cpu_to_le32(filter); + + ret = wl1271_cmd_configure(wl, ACX_RX_CFG, + rx_config, sizeof(*rx_config)); + if (ret < 0) { + wl1271_warning("failed to set rx config: %d", ret); + goto out; + } + +out: + kfree(rx_config); + return ret; +} + +int wl1271_acx_pd_threshold(struct wl1271 *wl) +{ + struct acx_packet_detection *pd; + int ret; + + wl1271_debug(DEBUG_ACX, "acx data pd threshold"); + + pd = kzalloc(sizeof(*pd), GFP_KERNEL); + if (!pd) { + ret = -ENOMEM; + goto out; + } + + pd->threshold = cpu_to_le32(wl->conf.rx.packet_detection_threshold); + + ret = wl1271_cmd_configure(wl, ACX_PD_THRESHOLD, pd, sizeof(*pd)); + if (ret < 0) { + wl1271_warning("failed to set pd threshold: %d", ret); + goto out; + } + +out: + kfree(pd); + return ret; +} + +int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time) +{ + struct acx_slot *slot; + int ret; + + wl1271_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 = wl1271_cmd_configure(wl, ACX_SLOT, slot, sizeof(*slot)); + if (ret < 0) { + wl1271_warning("failed to set slot time: %d", ret); + goto out; + } + +out: + kfree(slot); + return ret; +} + +int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable, + void *mc_list, u32 mc_list_len) +{ + struct acx_dot11_grp_addr_tbl *acx; + int ret; + + wl1271_debug(DEBUG_ACX, "acx group address tbl"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + /* MAC filtering */ + acx->enabled = enable; + acx->num_groups = mc_list_len; + memcpy(acx->mac_table, mc_list, mc_list_len * ETH_ALEN); + + ret = wl1271_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL, + acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("failed to set group addr table: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_service_period_timeout(struct wl1271 *wl) +{ + struct acx_rx_timeout *rx_timeout; + int ret; + + rx_timeout = kzalloc(sizeof(*rx_timeout), GFP_KERNEL); + if (!rx_timeout) { + ret = -ENOMEM; + goto out; + } + + wl1271_debug(DEBUG_ACX, "acx service period timeout"); + + rx_timeout->ps_poll_timeout = cpu_to_le16(wl->conf.rx.ps_poll_timeout); + rx_timeout->upsd_timeout = cpu_to_le16(wl->conf.rx.upsd_timeout); + + ret = wl1271_cmd_configure(wl, ACX_SERVICE_PERIOD_TIMEOUT, + rx_timeout, sizeof(*rx_timeout)); + if (ret < 0) { + wl1271_warning("failed to set service period timeout: %d", + ret); + goto out; + } + +out: + kfree(rx_timeout); + return ret; +} + +int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold) +{ + struct acx_rts_threshold *rts; + int ret; + + wl1271_debug(DEBUG_ACX, "acx rts threshold"); + + rts = kzalloc(sizeof(*rts), GFP_KERNEL); + if (!rts) { + ret = -ENOMEM; + goto out; + } + + rts->threshold = cpu_to_le16(rts_threshold); + + ret = wl1271_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts)); + if (ret < 0) { + wl1271_warning("failed to set rts threshold: %d", ret); + goto out; + } + +out: + kfree(rts); + return ret; +} + +int wl1271_acx_dco_itrim_params(struct wl1271 *wl) +{ + struct acx_dco_itrim_params *dco; + struct conf_itrim_settings *c = &wl->conf.itrim; + int ret; + + wl1271_debug(DEBUG_ACX, "acx dco itrim parameters"); + + dco = kzalloc(sizeof(*dco), GFP_KERNEL); + if (!dco) { + ret = -ENOMEM; + goto out; + } + + dco->enable = c->enable; + dco->timeout = cpu_to_le32(c->timeout); + + ret = wl1271_cmd_configure(wl, ACX_SET_DCO_ITRIM_PARAMS, + dco, sizeof(*dco)); + if (ret < 0) { + wl1271_warning("failed to set dco itrim parameters: %d", ret); + goto out; + } + +out: + kfree(dco); + return ret; +} + +int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter) +{ + struct acx_beacon_filter_option *beacon_filter = NULL; + int ret = 0; + + wl1271_debug(DEBUG_ACX, "acx beacon filter opt"); + + if (enable_filter && + wl->conf.conn.bcn_filt_mode == CONF_BCN_FILT_MODE_DISABLED) + goto out; + + beacon_filter = kzalloc(sizeof(*beacon_filter), GFP_KERNEL); + if (!beacon_filter) { + ret = -ENOMEM; + goto out; + } + + beacon_filter->enable = enable_filter; + + /* + * When set to zero, and the filter is enabled, beacons + * without the unicast TIM bit set are dropped. + */ + beacon_filter->max_num_beacons = 0; + + ret = wl1271_cmd_configure(wl, ACX_BEACON_FILTER_OPT, + beacon_filter, sizeof(*beacon_filter)); + if (ret < 0) { + wl1271_warning("failed to set beacon filter opt: %d", ret); + goto out; + } + +out: + kfree(beacon_filter); + return ret; +} + +int wl1271_acx_beacon_filter_table(struct wl1271 *wl) +{ + struct acx_beacon_filter_ie_table *ie_table; + int i, idx = 0; + int ret; + bool vendor_spec = false; + + wl1271_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 = 0; + for (i = 0; i < wl->conf.conn.bcn_filt_ie_count; i++) { + struct conf_bcn_filt_rule *r = &(wl->conf.conn.bcn_filt_ie[i]); + ie_table->table[idx++] = r->ie; + ie_table->table[idx++] = r->rule; + + if (r->ie == WLAN_EID_VENDOR_SPECIFIC) { + /* only one vendor specific ie allowed */ + if (vendor_spec) + continue; + + /* for vendor specific rules configure the + additional fields */ + memcpy(&(ie_table->table[idx]), r->oui, + CONF_BCN_IE_OUI_LEN); + idx += CONF_BCN_IE_OUI_LEN; + ie_table->table[idx++] = r->type; + memcpy(&(ie_table->table[idx]), r->version, + CONF_BCN_IE_VER_LEN); + idx += CONF_BCN_IE_VER_LEN; + vendor_spec = true; + } + + ie_table->num_ie++; + } + + ret = wl1271_cmd_configure(wl, ACX_BEACON_FILTER_TABLE, + ie_table, sizeof(*ie_table)); + if (ret < 0) { + wl1271_warning("failed to set beacon filter table: %d", ret); + goto out; + } + +out: + kfree(ie_table); + return ret; +} + +#define ACX_CONN_MONIT_DISABLE_VALUE 0xffffffff + +int wl1271_acx_conn_monit_params(struct wl1271 *wl, bool enable) +{ + struct acx_conn_monit_params *acx; + u32 threshold = ACX_CONN_MONIT_DISABLE_VALUE; + u32 timeout = ACX_CONN_MONIT_DISABLE_VALUE; + int ret; + + wl1271_debug(DEBUG_ACX, "acx connection monitor parameters: %s", + enable ? "enabled" : "disabled"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + if (enable) { + threshold = wl->conf.conn.synch_fail_thold; + timeout = wl->conf.conn.bss_lose_timeout; + } + + acx->synch_fail_thold = cpu_to_le32(threshold); + acx->bss_lose_timeout = cpu_to_le32(timeout); + + ret = wl1271_cmd_configure(wl, ACX_CONN_MONIT_PARAMS, + acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("failed to set connection monitor " + "parameters: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + + +int wl1271_acx_sg_enable(struct wl1271 *wl, bool enable) +{ + struct acx_bt_wlan_coex *pta; + int ret; + + wl1271_debug(DEBUG_ACX, "acx sg enable"); + + pta = kzalloc(sizeof(*pta), GFP_KERNEL); + if (!pta) { + ret = -ENOMEM; + goto out; + } + + if (enable) + pta->enable = wl->conf.sg.state; + else + pta->enable = CONF_SG_DISABLE; + + ret = wl1271_cmd_configure(wl, ACX_SG_ENABLE, pta, sizeof(*pta)); + if (ret < 0) { + wl1271_warning("failed to set softgemini enable: %d", ret); + goto out; + } + +out: + kfree(pta); + return ret; +} + +int wl1271_acx_sg_cfg(struct wl1271 *wl) +{ + struct acx_bt_wlan_coex_param *param; + struct conf_sg_settings *c = &wl->conf.sg; + int i, ret; + + wl1271_debug(DEBUG_ACX, "acx sg cfg"); + + param = kzalloc(sizeof(*param), GFP_KERNEL); + if (!param) { + ret = -ENOMEM; + goto out; + } + + /* BT-WLAN coext parameters */ + for (i = 0; i < CONF_SG_PARAMS_MAX; i++) + param->params[i] = cpu_to_le32(c->params[i]); + param->param_idx = CONF_SG_PARAMS_ALL; + + ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param)); + if (ret < 0) { + wl1271_warning("failed to set sg config: %d", ret); + goto out; + } + +out: + kfree(param); + return ret; +} + +int wl1271_acx_cca_threshold(struct wl1271 *wl) +{ + struct acx_energy_detection *detection; + int ret; + + wl1271_debug(DEBUG_ACX, "acx cca threshold"); + + detection = kzalloc(sizeof(*detection), GFP_KERNEL); + if (!detection) { + ret = -ENOMEM; + goto out; + } + + detection->rx_cca_threshold = cpu_to_le16(wl->conf.rx.rx_cca_threshold); + detection->tx_energy_detection = wl->conf.tx.tx_energy_detection; + + ret = wl1271_cmd_configure(wl, ACX_CCA_THRESHOLD, + detection, sizeof(*detection)); + if (ret < 0) { + wl1271_warning("failed to set cca threshold: %d", ret); + return ret; + } + +out: + kfree(detection); + return ret; +} + +int wl1271_acx_bcn_dtim_options(struct wl1271 *wl) +{ + struct acx_beacon_broadcast *bb; + int ret; + + wl1271_debug(DEBUG_ACX, "acx bcn dtim options"); + + bb = kzalloc(sizeof(*bb), GFP_KERNEL); + if (!bb) { + ret = -ENOMEM; + goto out; + } + + bb->beacon_rx_timeout = cpu_to_le16(wl->conf.conn.beacon_rx_timeout); + bb->broadcast_timeout = cpu_to_le16(wl->conf.conn.broadcast_timeout); + bb->rx_broadcast_in_ps = wl->conf.conn.rx_broadcast_in_ps; + bb->ps_poll_threshold = wl->conf.conn.ps_poll_threshold; + + ret = wl1271_cmd_configure(wl, ACX_BCN_DTIM_OPTIONS, bb, sizeof(*bb)); + if (ret < 0) { + wl1271_warning("failed to set rx config: %d", ret); + goto out; + } + +out: + kfree(bb); + return ret; +} + +int wl1271_acx_aid(struct wl1271 *wl, u16 aid) +{ + struct acx_aid *acx_aid; + int ret; + + wl1271_debug(DEBUG_ACX, "acx aid"); + + acx_aid = kzalloc(sizeof(*acx_aid), GFP_KERNEL); + if (!acx_aid) { + ret = -ENOMEM; + goto out; + } + + acx_aid->aid = cpu_to_le16(aid); + + ret = wl1271_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid)); + if (ret < 0) { + wl1271_warning("failed to set aid: %d", ret); + goto out; + } + +out: + kfree(acx_aid); + return ret; +} + +int wl1271_acx_event_mbox_mask(struct wl1271 *wl, u32 event_mask) +{ + struct acx_event_mask *mask; + int ret; + + wl1271_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 = cpu_to_le32(0xffffffff); + mask->event_mask = cpu_to_le32(event_mask); + + ret = wl1271_cmd_configure(wl, ACX_EVENT_MBOX_MASK, + mask, sizeof(*mask)); + if (ret < 0) { + wl1271_warning("failed to set acx_event_mbox_mask: %d", ret); + goto out; + } + +out: + kfree(mask); + return ret; +} + +int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble) +{ + struct acx_preamble *acx; + int ret; + + wl1271_debug(DEBUG_ACX, "acx_set_preamble"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->preamble = preamble; + + ret = wl1271_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("Setting of preamble failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_cts_protect(struct wl1271 *wl, + enum acx_ctsprotect_type ctsprotect) +{ + struct acx_ctsprotect *acx; + int ret; + + wl1271_debug(DEBUG_ACX, "acx_set_ctsprotect"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->ctsprotect = ctsprotect; + + ret = wl1271_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("Setting of ctsprotect failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats) +{ + int ret; + + wl1271_debug(DEBUG_ACX, "acx statistics"); + + ret = wl1271_cmd_interrogate(wl, ACX_STATISTICS, stats, + sizeof(*stats)); + if (ret < 0) { + wl1271_warning("acx statistics failed: %d", ret); + return -ENOMEM; + } + + return 0; +} + +int wl1271_acx_rate_policies(struct wl1271 *wl) +{ + struct acx_rate_policy *acx; + struct conf_tx_rate_class *c = &wl->conf.tx.rc_conf; + int idx = 0; + int ret = 0; + + wl1271_debug(DEBUG_ACX, "acx rate policies"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + + if (!acx) { + ret = -ENOMEM; + goto out; + } + + /* configure one basic rate class */ + idx = ACX_TX_BASIC_RATE; + acx->rate_class[idx].enabled_rates = cpu_to_le32(wl->basic_rate); + acx->rate_class[idx].short_retry_limit = c->short_retry_limit; + acx->rate_class[idx].long_retry_limit = c->long_retry_limit; + acx->rate_class[idx].aflags = c->aflags; + + /* configure one AP supported rate class */ + idx = ACX_TX_AP_FULL_RATE; + acx->rate_class[idx].enabled_rates = cpu_to_le32(wl->rate_set); + acx->rate_class[idx].short_retry_limit = c->short_retry_limit; + acx->rate_class[idx].long_retry_limit = c->long_retry_limit; + acx->rate_class[idx].aflags = c->aflags; + + acx->rate_class_cnt = cpu_to_le32(ACX_TX_RATE_POLICY_CNT); + + ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("Setting of rate policies failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max, + u8 aifsn, u16 txop) +{ + struct acx_ac_cfg *acx; + int ret = 0; + + wl1271_debug(DEBUG_ACX, "acx ac cfg %d cw_ming %d cw_max %d " + "aifs %d txop %d", ac, cw_min, cw_max, aifsn, txop); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->ac = ac; + acx->cw_min = cw_min; + acx->cw_max = cpu_to_le16(cw_max); + acx->aifsn = aifsn; + acx->tx_op_limit = cpu_to_le16(txop); + + ret = wl1271_cmd_configure(wl, ACX_AC_CFG, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx ac cfg failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type, + u8 tsid, u8 ps_scheme, u8 ack_policy, + u32 apsd_conf0, u32 apsd_conf1) +{ + struct acx_tid_config *acx; + int ret = 0; + + wl1271_debug(DEBUG_ACX, "acx tid config"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->queue_id = queue_id; + acx->channel_type = channel_type; + acx->tsid = tsid; + acx->ps_scheme = ps_scheme; + acx->ack_policy = ack_policy; + acx->apsd_conf[0] = cpu_to_le32(apsd_conf0); + acx->apsd_conf[1] = cpu_to_le32(apsd_conf1); + + ret = wl1271_cmd_configure(wl, ACX_TID_CFG, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("Setting of tid config failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_frag_threshold(struct wl1271 *wl) +{ + struct acx_frag_threshold *acx; + int ret = 0; + + wl1271_debug(DEBUG_ACX, "acx frag threshold"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->frag_threshold = cpu_to_le16(wl->conf.tx.frag_threshold); + ret = wl1271_cmd_configure(wl, ACX_FRAG_CFG, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("Setting of frag threshold failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_tx_config_options(struct wl1271 *wl) +{ + struct acx_tx_config_options *acx; + int ret = 0; + + wl1271_debug(DEBUG_ACX, "acx tx config options"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->tx_compl_timeout = cpu_to_le16(wl->conf.tx.tx_compl_timeout); + acx->tx_compl_threshold = cpu_to_le16(wl->conf.tx.tx_compl_threshold); + ret = wl1271_cmd_configure(wl, ACX_TX_CONFIG_OPT, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("Setting of tx options failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_mem_cfg(struct wl1271 *wl) +{ + struct wl1271_acx_config_memory *mem_conf; + int ret; + + wl1271_debug(DEBUG_ACX, "wl1271 mem cfg"); + + mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); + if (!mem_conf) { + ret = -ENOMEM; + goto out; + } + + /* memory config */ + mem_conf->num_stations = DEFAULT_NUM_STATIONS; + mem_conf->rx_mem_block_num = ACX_RX_MEM_BLOCKS; + mem_conf->tx_min_mem_block_num = ACX_TX_MIN_MEM_BLOCKS; + mem_conf->num_ssid_profiles = ACX_NUM_SSID_PROFILES; + mem_conf->total_tx_descriptors = cpu_to_le32(ACX_TX_DESCRIPTORS); + + ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf, + sizeof(*mem_conf)); + if (ret < 0) { + wl1271_warning("wl1271 mem config failed: %d", ret); + goto out; + } + +out: + kfree(mem_conf); + return ret; +} + +int wl1271_acx_init_mem_config(struct wl1271 *wl) +{ + int ret; + + ret = wl1271_acx_mem_cfg(wl); + if (ret < 0) + return ret; + + wl->target_mem_map = kzalloc(sizeof(struct wl1271_acx_mem_map), + GFP_KERNEL); + if (!wl->target_mem_map) { + wl1271_error("couldn't allocate target memory map"); + return -ENOMEM; + } + + /* we now ask for the firmware built memory map */ + ret = wl1271_acx_mem_map(wl, (void *)wl->target_mem_map, + sizeof(struct wl1271_acx_mem_map)); + if (ret < 0) { + wl1271_error("couldn't retrieve firmware memory map"); + kfree(wl->target_mem_map); + wl->target_mem_map = NULL; + return ret; + } + + /* initialize TX block book keeping */ + wl->tx_blocks_available = + le32_to_cpu(wl->target_mem_map->num_tx_mem_blocks); + wl1271_debug(DEBUG_TX, "available tx blocks: %d", + wl->tx_blocks_available); + + return 0; +} + +int wl1271_acx_init_rx_interrupt(struct wl1271 *wl) +{ + struct wl1271_acx_rx_config_opt *rx_conf; + int ret; + + wl1271_debug(DEBUG_ACX, "wl1271 rx interrupt config"); + + rx_conf = kzalloc(sizeof(*rx_conf), GFP_KERNEL); + if (!rx_conf) { + ret = -ENOMEM; + goto out; + } + + rx_conf->threshold = cpu_to_le16(wl->conf.rx.irq_pkt_threshold); + rx_conf->timeout = cpu_to_le16(wl->conf.rx.irq_timeout); + rx_conf->mblk_threshold = cpu_to_le16(wl->conf.rx.irq_blk_threshold); + rx_conf->queue_type = wl->conf.rx.queue_type; + + ret = wl1271_cmd_configure(wl, ACX_RX_CONFIG_OPT, rx_conf, + sizeof(*rx_conf)); + if (ret < 0) { + wl1271_warning("wl1271 rx config opt failed: %d", ret); + goto out; + } + +out: + kfree(rx_conf); + return ret; +} + +int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable) +{ + struct wl1271_acx_bet_enable *acx = NULL; + int ret = 0; + + wl1271_debug(DEBUG_ACX, "acx bet enable"); + + if (enable && wl->conf.conn.bet_enable == CONF_BET_MODE_DISABLE) + goto out; + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->enable = enable ? CONF_BET_MODE_ENABLE : CONF_BET_MODE_DISABLE; + acx->max_consecutive = wl->conf.conn.bet_max_consecutive; + + ret = wl1271_cmd_configure(wl, ACX_BET_ENABLE, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx bet enable failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, __be32 address) +{ + struct wl1271_acx_arp_filter *acx; + int ret; + + wl1271_debug(DEBUG_ACX, "acx arp ip filter, enable: %d", enable); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->version = ACX_IPV4_VERSION; + acx->enable = enable; + + if (enable == true) + memcpy(acx->address, &address, ACX_IPV4_ADDR_SIZE); + + ret = wl1271_cmd_configure(wl, ACX_ARP_IP_FILTER, + acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("failed to set arp ip filter: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_pm_config(struct wl1271 *wl) +{ + struct wl1271_acx_pm_config *acx = NULL; + struct conf_pm_config_settings *c = &wl->conf.pm_config; + int ret = 0; + + wl1271_debug(DEBUG_ACX, "acx pm config"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->host_clk_settling_time = cpu_to_le32(c->host_clk_settling_time); + acx->host_fast_wakeup_support = c->host_fast_wakeup_support; + + ret = wl1271_cmd_configure(wl, ACX_PM_CONFIG, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx pm config failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_keep_alive_mode(struct wl1271 *wl, bool enable) +{ + struct wl1271_acx_keep_alive_mode *acx = NULL; + int ret = 0; + + wl1271_debug(DEBUG_ACX, "acx keep alive mode: %d", enable); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->enabled = enable; + + ret = wl1271_cmd_configure(wl, ACX_KEEP_ALIVE_MODE, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx keep alive mode failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid) +{ + struct wl1271_acx_keep_alive_config *acx = NULL; + int ret = 0; + + wl1271_debug(DEBUG_ACX, "acx keep alive config"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->period = cpu_to_le32(wl->conf.conn.keep_alive_interval); + acx->index = index; + acx->tpl_validation = tpl_valid; + acx->trigger = ACX_KEEP_ALIVE_NO_TX; + + ret = wl1271_cmd_configure(wl, ACX_SET_KEEP_ALIVE_CONFIG, + acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx keep alive config failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable, + s16 thold, u8 hyst) +{ + struct wl1271_acx_rssi_snr_trigger *acx = NULL; + int ret = 0; + + wl1271_debug(DEBUG_ACX, "acx rssi snr trigger"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + wl->last_rssi_event = -1; + + acx->pacing = cpu_to_le16(wl->conf.roam_trigger.trigger_pacing); + acx->metric = WL1271_ACX_TRIG_METRIC_RSSI_BEACON; + acx->type = WL1271_ACX_TRIG_TYPE_EDGE; + if (enable) + acx->enable = WL1271_ACX_TRIG_ENABLE; + else + acx->enable = WL1271_ACX_TRIG_DISABLE; + + acx->index = WL1271_ACX_TRIG_IDX_RSSI; + acx->dir = WL1271_ACX_TRIG_DIR_BIDIR; + acx->threshold = cpu_to_le16(thold); + acx->hysteresis = hyst; + + ret = wl1271_cmd_configure(wl, ACX_RSSI_SNR_TRIGGER, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx rssi snr trigger setting failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl) +{ + struct wl1271_acx_rssi_snr_avg_weights *acx = NULL; + struct conf_roam_trigger_settings *c = &wl->conf.roam_trigger; + int ret = 0; + + wl1271_debug(DEBUG_ACX, "acx rssi snr avg weights"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->rssi_beacon = c->avg_weight_rssi_beacon; + acx->rssi_data = c->avg_weight_rssi_data; + acx->snr_beacon = c->avg_weight_snr_beacon; + acx->snr_data = c->avg_weight_snr_data; + + ret = wl1271_cmd_configure(wl, ACX_RSSI_SNR_WEIGHTS, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx rssi snr trigger weights failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, + struct ieee80211_sta_ht_cap *ht_cap, + bool allow_ht_operation) +{ + struct wl1271_acx_ht_capabilities *acx; + u8 mac_address[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + int ret = 0; + + wl1271_debug(DEBUG_ACX, "acx ht capabilities setting"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + /* Allow HT Operation ? */ + if (allow_ht_operation) { + acx->ht_capabilites = + WL1271_ACX_FW_CAP_HT_OPERATION; + if (ht_cap->cap & IEEE80211_HT_CAP_GRN_FLD) + acx->ht_capabilites |= + WL1271_ACX_FW_CAP_GREENFIELD_FRAME_FORMAT; + if (ht_cap->cap & IEEE80211_HT_CAP_SGI_20) + acx->ht_capabilites |= + WL1271_ACX_FW_CAP_SHORT_GI_FOR_20MHZ_PACKETS; + if (ht_cap->cap & IEEE80211_HT_CAP_LSIG_TXOP_PROT) + acx->ht_capabilites |= + WL1271_ACX_FW_CAP_LSIG_TXOP_PROTECTION; + + /* get data from A-MPDU parameters field */ + acx->ampdu_max_length = ht_cap->ampdu_factor; + acx->ampdu_min_spacing = ht_cap->ampdu_density; + + memcpy(acx->mac_address, mac_address, ETH_ALEN); + } else { /* HT operations are not allowed */ + acx->ht_capabilites = 0; + } + + ret = wl1271_cmd_configure(wl, ACX_PEER_HT_CAP, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx ht capabilities setting failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_set_ht_information(struct wl1271 *wl, + u16 ht_operation_mode) +{ + struct wl1271_acx_ht_information *acx; + int ret = 0; + + wl1271_debug(DEBUG_ACX, "acx ht information setting"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->ht_protection = + (u8)(ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION); + acx->rifs_mode = 0; + acx->gf_protection = 0; + acx->ht_tx_burst_limit = 0; + acx->dual_cts_protection = 0; + + ret = wl1271_cmd_configure(wl, ACX_HT_BSS_OPERATION, acx, sizeof(*acx)); + + if (ret < 0) { + wl1271_warning("acx ht information setting failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime) +{ + struct wl1271_acx_fw_tsf_information *tsf_info; + int ret; + + tsf_info = kzalloc(sizeof(*tsf_info), GFP_KERNEL); + if (!tsf_info) { + ret = -ENOMEM; + goto out; + } + + ret = wl1271_cmd_interrogate(wl, ACX_TSF_INFO, + tsf_info, sizeof(*tsf_info)); + if (ret < 0) { + wl1271_warning("acx tsf info interrogate failed"); + goto out; + } + + *mactime = le32_to_cpu(tsf_info->current_tsf_low) | + ((u64) le32_to_cpu(tsf_info->current_tsf_high) << 32); + +out: + kfree(tsf_info); + return ret; +} diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h new file mode 100644 index 0000000..f41a9c1 --- /dev/null +++ b/drivers/net/wireless/wl12xx/acx.h @@ -0,0 +1,1185 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. + * Copyright (C) 2008-2010 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 __ACX_H__ +#define __ACX_H__ + +#include "wl12xx.h" +#include "cmd.h" + +/************************************************************************* + + Host Interrupt Register (WiLink -> Host) + +**************************************************************************/ +/* HW Initiated interrupt Watchdog timer expiration */ +#define WL1271_ACX_INTR_WATCHDOG BIT(0) +/* Init sequence is done (masked interrupt, detection through polling only ) */ +#define WL1271_ACX_INTR_INIT_COMPLETE BIT(1) +/* Event was entered to Event MBOX #A*/ +#define WL1271_ACX_INTR_EVENT_A BIT(2) +/* Event was entered to Event MBOX #B*/ +#define WL1271_ACX_INTR_EVENT_B BIT(3) +/* Command processing completion*/ +#define WL1271_ACX_INTR_CMD_COMPLETE BIT(4) +/* Signaling the host on HW wakeup */ +#define WL1271_ACX_INTR_HW_AVAILABLE BIT(5) +/* The MISC bit is used for aggregation of RX, TxComplete and TX rate update */ +#define WL1271_ACX_INTR_DATA BIT(6) +/* Trace meassge on MBOX #A */ +#define WL1271_ACX_INTR_TRACE_A BIT(7) +/* Trace meassge on MBOX #B */ +#define WL1271_ACX_INTR_TRACE_B BIT(8) + +#define WL1271_ACX_INTR_ALL 0xFFFFFFFF +#define WL1271_ACX_ALL_EVENTS_VECTOR (WL1271_ACX_INTR_WATCHDOG | \ + WL1271_ACX_INTR_INIT_COMPLETE | \ + WL1271_ACX_INTR_EVENT_A | \ + WL1271_ACX_INTR_EVENT_B | \ + WL1271_ACX_INTR_CMD_COMPLETE | \ + WL1271_ACX_INTR_HW_AVAILABLE | \ + WL1271_ACX_INTR_DATA) + +#define WL1271_INTR_MASK (WL1271_ACX_INTR_WATCHDOG | \ + WL1271_ACX_INTR_EVENT_A | \ + WL1271_ACX_INTR_EVENT_B | \ + WL1271_ACX_INTR_HW_AVAILABLE | \ + WL1271_ACX_INTR_DATA) + +/* Target's information element */ +struct acx_header { + struct wl1271_cmd_header cmd; + + /* acx (or information element) header */ + __le16 id; + + /* payload length (not including headers */ + __le16 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.*/ + __le32 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.*/ + __le32 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.*/ + __le32 valid_frame; + + /* the number of missed sequence numbers in the squentially */ + /* values of frames seq numbers */ + __le32 seq_num_miss; +} __packed; + +enum wl1271_psm_mode { + /* Active mode */ + WL1271_PSM_CAM = 0, + + /* Power save mode */ + WL1271_PSM_PS = 1, + + /* Extreme low power */ + WL1271_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 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. + */ + __le32 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; + + __le32 config_options; + __le32 filter_options; +} __packed; + +struct acx_packet_detection { + struct acx_header header; + + __le32 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 ACX_MC_ADDRESS_GROUP_MAX (8) +#define ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ACX_MC_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; + +struct acx_rx_timeout { + struct acx_header header; + + __le16 ps_poll_timeout; + __le16 upsd_timeout; +} __packed; + +struct acx_rts_threshold { + struct acx_header header; + + __le16 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)) + +struct acx_beacon_filter_ie_table { + struct acx_header header; + + u8 num_ie; + u8 pad[3]; + u8 table[BEACON_FILTER_TABLE_MAX_SIZE]; +} __packed; + +struct acx_conn_monit_params { + struct acx_header header; + + __le32 synch_fail_thold; /* number of beacons missed */ + __le32 bss_lose_timeout; /* number of TU's from synch fail */ +} __packed; + +struct acx_bt_wlan_coex { + struct acx_header header; + + u8 enable; + u8 pad[3]; +} __packed; + +struct acx_bt_wlan_coex_param { + struct acx_header header; + + __le32 params[CONF_SG_PARAMS_MAX]; + u8 param_idx; + u8 padding[3]; +} __packed; + +struct acx_dco_itrim_params { + struct acx_header header; + + u8 enable; + u8 padding[3]; + __le32 timeout; +} __packed; + +struct acx_energy_detection { + struct acx_header header; + + /* The RX Clear Channel Assessment threshold in the PHY */ + __le16 rx_cca_threshold; + u8 tx_energy_detection; + u8 pad; +} __packed; + +struct acx_beacon_broadcast { + struct acx_header header; + + __le16 beacon_rx_timeout; + __le16 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; + + __le32 event_mask; + __le32 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) + +/* When set, disable HW encryption */ +#define DF_ENCRYPTION_DISABLE 0x01 +#define DF_SNIFF_MODE_ENABLE 0x80 + +struct acx_feature_config { + struct acx_header header; + + __le32 options; + __le32 data_flow_options; +} __packed; + +struct acx_current_tx_power { + struct acx_header header; + + u8 current_tx_power; + u8 padding[3]; +} __packed; + +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. + */ + __le16 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 { + __le32 internal_desc_overflow; +} __packed; + +struct acx_rx_statistics { + __le32 out_of_mem; + __le32 hdr_overflow; + __le32 hw_stuck; + __le32 dropped; + __le32 fcs_err; + __le32 xfr_hint_trig; + __le32 path_reset; + __le32 reset_counter; +} __packed; + +struct acx_dma_statistics { + __le32 rx_requested; + __le32 rx_errors; + __le32 tx_requested; + __le32 tx_errors; +} __packed; + +struct acx_isr_statistics { + /* host command complete */ + __le32 cmd_cmplt; + + /* fiqisr() */ + __le32 fiqs; + + /* (INT_STS_ND & INT_TRIG_RX_HEADER) */ + __le32 rx_headers; + + /* (INT_STS_ND & INT_TRIG_RX_CMPLT) */ + __le32 rx_completes; + + /* (INT_STS_ND & INT_TRIG_NO_RX_BUF) */ + __le32 rx_mem_overflow; + + /* (INT_STS_ND & INT_TRIG_S_RX_RDY) */ + __le32 rx_rdys; + + /* irqisr() */ + __le32 irqs; + + /* (INT_STS_ND & INT_TRIG_TX_PROC) */ + __le32 tx_procs; + + /* (INT_STS_ND & INT_TRIG_DECRYPT_DONE) */ + __le32 decrypt_done; + + /* (INT_STS_ND & INT_TRIG_DMA0) */ + __le32 dma0_done; + + /* (INT_STS_ND & INT_TRIG_DMA1) */ + __le32 dma1_done; + + /* (INT_STS_ND & INT_TRIG_TX_EXC_CMPLT) */ + __le32 tx_exch_complete; + + /* (INT_STS_ND & INT_TRIG_COMMAND) */ + __le32 commands; + + /* (INT_STS_ND & INT_TRIG_RX_PROC) */ + __le32 rx_procs; + + /* (INT_STS_ND & INT_TRIG_PM_802) */ + __le32 hw_pm_mode_changes; + + /* (INT_STS_ND & INT_TRIG_ACKNOWLEDGE) */ + __le32 host_acknowledges; + + /* (INT_STS_ND & INT_TRIG_PM_PCI) */ + __le32 pci_pm; + + /* (INT_STS_ND & INT_TRIG_ACM_WAKEUP) */ + __le32 wakeups; + + /* (INT_STS_ND & INT_TRIG_LOW_RSSI) */ + __le32 low_rssi; +} __packed; + +struct acx_wep_statistics { + /* WEP address keys configured */ + __le32 addr_key_count; + + /* default keys configured */ + __le32 default_key_count; + + __le32 reserved; + + /* number of times that WEP key not found on lookup */ + __le32 key_not_found; + + /* number of times that WEP key decryption failed */ + __le32 decrypt_fail; + + /* WEP packets decrypted */ + __le32 packets; + + /* WEP decrypt interrupts */ + __le32 interrupt; +} __packed; + +#define ACX_MISSED_BEACONS_SPREAD 10 + +struct acx_pwr_statistics { + /* the amount of enters into power save mode (both PD & ELP) */ + __le32 ps_enter; + + /* the amount of enters into ELP mode */ + __le32 elp_enter; + + /* the amount of missing beacon interrupts to the host */ + __le32 missing_bcns; + + /* the amount of wake on host-access times */ + __le32 wake_on_host; + + /* the amount of wake on timer-expire */ + __le32 wake_on_timer_exp; + + /* the number of packets that were transmitted with PS bit set */ + __le32 tx_with_ps; + + /* the number of packets that were transmitted with PS bit clear */ + __le32 tx_without_ps; + + /* the number of received beacons */ + __le32 rcvd_beacons; + + /* the number of entering into PowerOn (power save off) */ + __le32 power_save_off; + + /* the number of entries into power save mode */ + __le16 enable_ps; + + /* + * the number of exits from power save, not including failed PS + * transitions + */ + __le16 disable_ps; + + /* + * the number of times the TSF counter was adjusted because + * of drift + */ + __le32 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. + */ + __le32 cont_miss_bcns_spread[ACX_MISSED_BEACONS_SPREAD]; + + /* the number of beacons in awake mode */ + __le32 rcvd_awake_beacons; +} __packed; + +struct acx_mic_statistics { + __le32 rx_pkts; + __le32 calc_failure; +} __packed; + +struct acx_aes_statistics { + __le32 encrypt_fail; + __le32 decrypt_fail; + __le32 encrypt_packets; + __le32 decrypt_packets; + __le32 encrypt_interrupt; + __le32 decrypt_interrupt; +} __packed; + +struct acx_event_statistics { + __le32 heart_beat; + __le32 calibration; + __le32 rx_mismatch; + __le32 rx_mem_empty; + __le32 rx_pool; + __le32 oom_late; + __le32 phy_transmit_error; + __le32 tx_stuck; +} __packed; + +struct acx_ps_statistics { + __le32 pspoll_timeouts; + __le32 upsd_timeouts; + __le32 upsd_max_sptime; + __le32 upsd_max_apturn; + __le32 pspoll_max_apturn; + __le32 pspoll_utilization; + __le32 upsd_utilization; +} __packed; + +struct acx_rxpipe_statistics { + __le32 rx_prep_beacon_drop; + __le32 descr_host_int_trig_rx_data; + __le32 beacon_buffer_thres_host_int_trig_rx_data; + __le32 missed_beacon_host_int_trig_rx_data; + __le32 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; + +struct acx_rate_class { + __le32 enabled_rates; + u8 short_retry_limit; + u8 long_retry_limit; + u8 aflags; + u8 reserved; +}; + +#define ACX_TX_BASIC_RATE 0 +#define ACX_TX_AP_FULL_RATE 1 +#define ACX_TX_RATE_POLICY_CNT 2 +struct acx_rate_policy { + struct acx_header header; + + __le32 rate_class_cnt; + struct acx_rate_class rate_class[CONF_TX_MAX_RATE_CLASSES]; +} __packed; + +struct acx_ac_cfg { + struct acx_header header; + u8 ac; + u8 cw_min; + __le16 cw_max; + u8 aifsn; + u8 reserved; + __le16 tx_op_limit; +} __packed; + +struct acx_tid_config { + struct acx_header header; + u8 queue_id; + u8 channel_type; + u8 tsid; + u8 ps_scheme; + u8 ack_policy; + u8 padding[3]; + __le32 apsd_conf[2]; +} __packed; + +struct acx_frag_threshold { + struct acx_header header; + __le16 frag_threshold; + u8 padding[2]; +} __packed; + +struct acx_tx_config_options { + struct acx_header header; + __le16 tx_compl_timeout; /* msec */ + __le16 tx_compl_threshold; /* number of packets */ +} __packed; + +#define ACX_RX_MEM_BLOCKS 70 +#define ACX_TX_MIN_MEM_BLOCKS 40 +#define ACX_TX_DESCRIPTORS 32 +#define ACX_NUM_SSID_PROFILES 1 + +struct wl1271_acx_config_memory { + struct acx_header header; + + u8 rx_mem_block_num; + u8 tx_min_mem_block_num; + u8 num_stations; + u8 num_ssid_profiles; + __le32 total_tx_descriptors; +} __packed; + +struct wl1271_acx_mem_map { + struct acx_header header; + + __le32 code_start; + __le32 code_end; + + __le32 wep_defkey_start; + __le32 wep_defkey_end; + + __le32 sta_table_start; + __le32 sta_table_end; + + __le32 packet_template_start; + __le32 packet_template_end; + + /* Address of the TX result interface (control block) */ + __le32 tx_result; + __le32 tx_result_queue_start; + + __le32 queue_memory_start; + __le32 queue_memory_end; + + __le32 packet_memory_pool_start; + __le32 packet_memory_pool_end; + + __le32 debug_buffer1_start; + __le32 debug_buffer1_end; + + __le32 debug_buffer2_start; + __le32 debug_buffer2_end; + + /* Number of blocks FW allocated for TX packets */ + __le32 num_tx_mem_blocks; + + /* Number of blocks FW allocated for RX packets */ + __le32 num_rx_mem_blocks; + + /* the following 4 fields are valid in SLAVE mode only */ + u8 *tx_cbuf; + u8 *rx_cbuf; + __le32 rx_ctrl; + __le32 tx_ctrl; +} __packed; + +struct wl1271_acx_rx_config_opt { + struct acx_header header; + + __le16 mblk_threshold; + __le16 threshold; + __le16 timeout; + u8 queue_type; + u8 reserved; +} __packed; + + +struct wl1271_acx_bet_enable { + struct acx_header header; + + u8 enable; + u8 max_consecutive; + u8 padding[2]; +} __packed; + +#define ACX_IPV4_VERSION 4 +#define ACX_IPV6_VERSION 6 +#define ACX_IPV4_ADDR_SIZE 4 +struct wl1271_acx_arp_filter { + struct acx_header header; + u8 version; /* ACX_IPV4_VERSION, ACX_IPV6_VERSION */ + u8 enable; /* 1 to enable ARP filtering, 0 to disable */ + u8 padding[2]; + u8 address[16]; /* The configured device IP address - all ARP + requests directed to this IP address will pass + through. For IPv4, the first four bytes are + used. */ +} __packed; + +struct wl1271_acx_pm_config { + struct acx_header header; + + __le32 host_clk_settling_time; + u8 host_fast_wakeup_support; + u8 padding[3]; +} __packed; + +struct wl1271_acx_keep_alive_mode { + struct acx_header header; + + u8 enabled; + u8 padding[3]; +} __packed; + +enum { + ACX_KEEP_ALIVE_NO_TX = 0, + ACX_KEEP_ALIVE_PERIOD_ONLY +}; + +enum { + ACX_KEEP_ALIVE_TPL_INVALID = 0, + ACX_KEEP_ALIVE_TPL_VALID +}; + +struct wl1271_acx_keep_alive_config { + struct acx_header header; + + __le32 period; + u8 index; + u8 tpl_validation; + u8 trigger; + u8 padding; +} __packed; + +enum { + WL1271_ACX_TRIG_TYPE_LEVEL = 0, + WL1271_ACX_TRIG_TYPE_EDGE, +}; + +enum { + WL1271_ACX_TRIG_DIR_LOW = 0, + WL1271_ACX_TRIG_DIR_HIGH, + WL1271_ACX_TRIG_DIR_BIDIR, +}; + +enum { + WL1271_ACX_TRIG_ENABLE = 1, + WL1271_ACX_TRIG_DISABLE, +}; + +enum { + WL1271_ACX_TRIG_METRIC_RSSI_BEACON = 0, + WL1271_ACX_TRIG_METRIC_RSSI_DATA, + WL1271_ACX_TRIG_METRIC_SNR_BEACON, + WL1271_ACX_TRIG_METRIC_SNR_DATA, +}; + +enum { + WL1271_ACX_TRIG_IDX_RSSI = 0, + WL1271_ACX_TRIG_COUNT = 8, +}; + +struct wl1271_acx_rssi_snr_trigger { + struct acx_header header; + + __le16 threshold; + __le16 pacing; /* 0 - 60000 ms */ + u8 metric; + u8 type; + u8 dir; + u8 hysteresis; + u8 index; + u8 enable; + u8 padding[2]; +}; + +struct wl1271_acx_rssi_snr_avg_weights { + struct acx_header header; + + u8 rssi_beacon; + u8 rssi_data; + u8 snr_beacon; + u8 snr_data; +}; + +/* + * ACX_PEER_HT_CAP + * Configure HT capabilities - declare the capabilities of the peer + * we are connected to. + */ +struct wl1271_acx_ht_capabilities { + struct acx_header header; + + /* + * bit 0 - Allow HT Operation + * bit 1 - Allow Greenfield format in TX + * bit 2 - Allow Short GI in TX + * bit 3 - Allow L-SIG TXOP Protection in TX + * bit 4 - Allow HT Control fields in TX. + * Note, driver will still leave space for HT control in packets + * regardless of the value of this field. FW will be responsible + * to drop the HT field from any frame when this Bit set to 0. + * bit 5 - Allow RD initiation in TXOP. FW is allowed to initate RD. + * Exact policy setting for this feature is TBD. + * Note, this bit can only be set to 1 if bit 3 is set to 1. + */ + __le32 ht_capabilites; + + /* + * Indicates to which peer these capabilities apply. + * For infrastructure use ff:ff:ff:ff:ff:ff that indicates relevance + * for all peers. + * Only valid for IBSS/DLS operation. + */ + u8 mac_address[ETH_ALEN]; + + /* + * This the maximum A-MPDU length supported by the AP. The FW may not + * exceed this length when sending A-MPDUs + */ + u8 ampdu_max_length; + + /* This is the minimal spacing required when sending A-MPDUs to the AP*/ + u8 ampdu_min_spacing; +} __packed; + +/* HT Capabilites Fw Bit Mask Mapping */ +#define WL1271_ACX_FW_CAP_HT_OPERATION BIT(0) +#define WL1271_ACX_FW_CAP_GREENFIELD_FRAME_FORMAT BIT(1) +#define WL1271_ACX_FW_CAP_SHORT_GI_FOR_20MHZ_PACKETS BIT(2) +#define WL1271_ACX_FW_CAP_LSIG_TXOP_PROTECTION BIT(3) +#define WL1271_ACX_FW_CAP_HT_CONTROL_FIELDS BIT(4) +#define WL1271_ACX_FW_CAP_RD_INITIATION BIT(5) + + +/* + * ACX_HT_BSS_OPERATION + * Configure HT capabilities - AP rules for behavior in the BSS. + */ +struct wl1271_acx_ht_information { + struct acx_header header; + + /* Values: 0 - RIFS not allowed, 1 - RIFS allowed */ + u8 rifs_mode; + + /* Values: 0 - 3 like in spec */ + u8 ht_protection; + + /* Values: 0 - GF protection not required, 1 - GF protection required */ + u8 gf_protection; + + /*Values: 0 - TX Burst limit not required, 1 - TX Burst Limit required*/ + u8 ht_tx_burst_limit; + + /* + * Values: 0 - Dual CTS protection not required, + * 1 - Dual CTS Protection required + * Note: When this value is set to 1 FW will protect all TXOP with RTS + * frame and will not use CTS-to-self regardless of the value of the + * ACX_CTS_PROTECTION information element + */ + u8 dual_cts_protection; + + u8 padding[3]; +} __packed; + +struct wl1271_acx_fw_tsf_information { + struct acx_header header; + + __le32 current_tsf_high; + __le32 current_tsf_low; + __le32 last_bttt_high; + __le32 last_tbtt_low; + u8 last_dtim_count; + u8 padding[3]; +} __packed; + +enum { + ACX_WAKE_UP_CONDITIONS = 0x0002, + ACX_MEM_CFG = 0x0003, + ACX_SLOT = 0x0004, + ACX_AC_CFG = 0x0007, + ACX_MEM_MAP = 0x0008, + ACX_AID = 0x000A, + /* ACX_FW_REV is missing in the ref driver, but seems to work */ + ACX_FW_REV = 0x000D, + ACX_MEDIUM_USAGE = 0x000F, + ACX_RX_CFG = 0x0010, + ACX_TX_QUEUE_CFG = 0x0011, /* FIXME: only used by wl1251 */ + ACX_STATISTICS = 0x0013, /* Debug API */ + ACX_PWR_CONSUMPTION_STATISTICS = 0x0014, + ACX_FEATURE_CFG = 0x0015, + ACX_TID_CFG = 0x001A, + ACX_PS_RX_STREAMING = 0x001B, + ACX_BEACON_FILTER_OPT = 0x001F, + ACX_NOISE_HIST = 0x0021, + ACX_HDK_VERSION = 0x0022, /* ??? */ + ACX_PD_THRESHOLD = 0x0023, + ACX_TX_CONFIG_OPT = 0x0024, + ACX_CCA_THRESHOLD = 0x0025, + ACX_EVENT_MBOX_MASK = 0x0026, + ACX_CONN_MONIT_PARAMS = 0x002D, + ACX_CONS_TX_FAILURE = 0x002F, + ACX_BCN_DTIM_OPTIONS = 0x0031, + ACX_SG_ENABLE = 0x0032, + ACX_SG_CFG = 0x0033, + 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_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_RX_CONFIG_OPT = 0x004E, + ACX_FRAG_CFG = 0x004F, + ACX_BET_ENABLE = 0x0050, + ACX_RSSI_SNR_TRIGGER = 0x0051, + ACX_RSSI_SNR_WEIGHTS = 0x0052, + ACX_KEEP_ALIVE_MODE = 0x0053, + ACX_SET_KEEP_ALIVE_CONFIG = 0x0054, + ACX_BA_SESSION_RESPONDER_POLICY = 0x0055, + ACX_BA_SESSION_INITIATOR_POLICY = 0x0056, + ACX_PEER_HT_CAP = 0x0057, + ACX_HT_BSS_OPERATION = 0x0058, + ACX_COEX_ACTIVITY = 0x0059, + ACX_SET_DCO_ITRIM_PARAMS = 0x0061, + DOT11_RX_MSDU_LIFE_TIME = 0x1004, + DOT11_CUR_TX_PWR = 0x100D, + DOT11_RX_DOT11_MODE = 0x1012, + DOT11_RTS_THRESHOLD = 0x1013, + DOT11_GROUP_ADDRESS_TBL = 0x1014, + ACX_PM_CONFIG = 0x1016, + + MAX_DOT11_IE = DOT11_GROUP_ADDRESS_TBL, + + MAX_IE = 0xFFFF +}; + + +int wl1271_acx_wake_up_conditions(struct wl1271 *wl); +int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth); +int wl1271_acx_tx_power(struct wl1271 *wl, int power); +int wl1271_acx_feature_cfg(struct wl1271 *wl); +int wl1271_acx_mem_map(struct wl1271 *wl, + struct acx_header *mem_map, size_t len); +int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl); +int wl1271_acx_rx_config(struct wl1271 *wl, u32 config, u32 filter); +int wl1271_acx_pd_threshold(struct wl1271 *wl); +int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time); +int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable, + void *mc_list, u32 mc_list_len); +int wl1271_acx_service_period_timeout(struct wl1271 *wl); +int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold); +int wl1271_acx_dco_itrim_params(struct wl1271 *wl); +int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter); +int wl1271_acx_beacon_filter_table(struct wl1271 *wl); +int wl1271_acx_conn_monit_params(struct wl1271 *wl, bool enable); +int wl1271_acx_sg_enable(struct wl1271 *wl, bool enable); +int wl1271_acx_sg_cfg(struct wl1271 *wl); +int wl1271_acx_cca_threshold(struct wl1271 *wl); +int wl1271_acx_bcn_dtim_options(struct wl1271 *wl); +int wl1271_acx_aid(struct wl1271 *wl, u16 aid); +int wl1271_acx_event_mbox_mask(struct wl1271 *wl, u32 event_mask); +int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble); +int wl1271_acx_cts_protect(struct wl1271 *wl, + enum acx_ctsprotect_type ctsprotect); +int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats); +int wl1271_acx_rate_policies(struct wl1271 *wl); +int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max, + u8 aifsn, u16 txop); +int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type, + u8 tsid, u8 ps_scheme, u8 ack_policy, + u32 apsd_conf0, u32 apsd_conf1); +int wl1271_acx_frag_threshold(struct wl1271 *wl); +int wl1271_acx_tx_config_options(struct wl1271 *wl); +int wl1271_acx_mem_cfg(struct wl1271 *wl); +int wl1271_acx_init_mem_config(struct wl1271 *wl); +int wl1271_acx_init_rx_interrupt(struct wl1271 *wl); +int wl1271_acx_smart_reflex(struct wl1271 *wl); +int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable); +int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, __be32 address); +int wl1271_acx_pm_config(struct wl1271 *wl); +int wl1271_acx_keep_alive_mode(struct wl1271 *wl, bool enable); +int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid); +int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable, + s16 thold, u8 hyst); +int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl); +int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, + struct ieee80211_sta_ht_cap *ht_cap, + bool allow_ht_operation); +int wl1271_acx_set_ht_information(struct wl1271 *wl, + u16 ht_operation_mode); +int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime); + +#endif /* __WL1271_ACX_H__ */ diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c new file mode 100644 index 0000000..1eafb81 --- /dev/null +++ b/drivers/net/wireless/wl12xx/boot.c @@ -0,0 +1,591 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2008-2010 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 "acx.h" +#include "reg.h" +#include "boot.h" +#include "io.h" +#include "event.h" + +static struct wl1271_partition_set part_table[PART_TABLE_LEN] = { + [PART_DOWN] = { + .mem = { + .start = 0x00000000, + .size = 0x000177c0 + }, + .reg = { + .start = REGISTERS_BASE, + .size = 0x00008800 + }, + .mem2 = { + .start = 0x00000000, + .size = 0x00000000 + }, + .mem3 = { + .start = 0x00000000, + .size = 0x00000000 + }, + }, + + [PART_WORK] = { + .mem = { + .start = 0x00040000, + .size = 0x00014fc0 + }, + .reg = { + .start = REGISTERS_BASE, + .size = 0x0000a000 + }, + .mem2 = { + .start = 0x003004f8, + .size = 0x00000004 + }, + .mem3 = { + .start = 0x00040404, + .size = 0x00000000 + }, + }, + + [PART_DRPW] = { + .mem = { + .start = 0x00040000, + .size = 0x00014fc0 + }, + .reg = { + .start = DRPW_BASE, + .size = 0x00006000 + }, + .mem2 = { + .start = 0x00000000, + .size = 0x00000000 + }, + .mem3 = { + .start = 0x00000000, + .size = 0x00000000 + } + } +}; + +static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag) +{ + u32 cpu_ctrl; + + /* 10.5.0 run the firmware (I) */ + cpu_ctrl = wl1271_read32(wl, ACX_REG_ECPU_CONTROL); + + /* 10.5.1 run the firmware (II) */ + cpu_ctrl |= flag; + wl1271_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); +} + +static void wl1271_boot_fw_version(struct wl1271 *wl) +{ + struct wl1271_static_data static_data; + + wl1271_read(wl, wl->cmd_box_addr, &static_data, sizeof(static_data), + false); + + strncpy(wl->chip.fw_ver, static_data.fw_version, + sizeof(wl->chip.fw_ver)); + + /* make sure the string is NULL-terminated */ + wl->chip.fw_ver[sizeof(wl->chip.fw_ver) - 1] = '\0'; +} + +static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, + size_t fw_data_len, u32 dest) +{ + struct wl1271_partition_set partition; + int addr, chunk_num, partition_limit; + u8 *p, *chunk; + + /* whal_FwCtrl_LoadFwImageSm() */ + + wl1271_debug(DEBUG_BOOT, "starting firmware upload"); + + wl1271_debug(DEBUG_BOOT, "fw_data_len %zd chunk_size %d", + fw_data_len, CHUNK_SIZE); + + if ((fw_data_len % 4) != 0) { + wl1271_error("firmware length not multiple of four"); + return -EIO; + } + + chunk = kmalloc(CHUNK_SIZE, GFP_KERNEL); + if (!chunk) { + wl1271_error("allocation for firmware upload chunk failed"); + return -ENOMEM; + } + + memcpy(&partition, &part_table[PART_DOWN], sizeof(partition)); + partition.mem.start = dest; + wl1271_set_partition(wl, &partition); + + /* 10.1 set partition limit and chunk num */ + chunk_num = 0; + partition_limit = part_table[PART_DOWN].mem.size; + + while (chunk_num < fw_data_len / CHUNK_SIZE) { + /* 10.2 update partition, if needed */ + addr = dest + (chunk_num + 2) * CHUNK_SIZE; + if (addr > partition_limit) { + addr = dest + chunk_num * CHUNK_SIZE; + partition_limit = chunk_num * CHUNK_SIZE + + part_table[PART_DOWN].mem.size; + partition.mem.start = addr; + wl1271_set_partition(wl, &partition); + } + + /* 10.3 upload the chunk */ + addr = dest + chunk_num * CHUNK_SIZE; + p = buf + chunk_num * CHUNK_SIZE; + memcpy(chunk, p, CHUNK_SIZE); + wl1271_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", + p, addr); + wl1271_write(wl, addr, chunk, CHUNK_SIZE, false); + + chunk_num++; + } + + /* 10.4 upload the last chunk */ + addr = dest + chunk_num * CHUNK_SIZE; + p = buf + chunk_num * CHUNK_SIZE; + memcpy(chunk, p, fw_data_len % CHUNK_SIZE); + wl1271_debug(DEBUG_BOOT, "uploading fw last chunk (%zd B) 0x%p to 0x%x", + fw_data_len % CHUNK_SIZE, p, addr); + wl1271_write(wl, addr, chunk, fw_data_len % CHUNK_SIZE, false); + + kfree(chunk); + return 0; +} + +static int wl1271_boot_upload_firmware(struct wl1271 *wl) +{ + u32 chunks, addr, len; + int ret = 0; + u8 *fw; + + fw = wl->fw; + chunks = be32_to_cpup((__be32 *) fw); + fw += sizeof(u32); + + wl1271_debug(DEBUG_BOOT, "firmware chunks to be uploaded: %u", chunks); + + while (chunks--) { + addr = be32_to_cpup((__be32 *) fw); + fw += sizeof(u32); + len = be32_to_cpup((__be32 *) fw); + fw += sizeof(u32); + + if (len > 300000) { + wl1271_info("firmware chunk too long: %u", len); + return -EINVAL; + } + wl1271_debug(DEBUG_BOOT, "chunk %d addr 0x%x len %u", + chunks, addr, len); + ret = wl1271_boot_upload_firmware_chunk(wl, fw, len, addr); + if (ret != 0) + break; + fw += len; + } + + return ret; +} + +static int wl1271_boot_upload_nvs(struct wl1271 *wl) +{ + size_t nvs_len, burst_len; + int i; + u32 dest_addr, val; + u8 *nvs_ptr, *nvs_aligned; + + if (wl->nvs == NULL) + return -ENODEV; + + /* + * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz band + * configurations) can be removed when those NVS files stop floating + * around. + */ + if (wl->nvs_len == sizeof(struct wl1271_nvs_file) || + wl->nvs_len == WL1271_INI_LEGACY_NVS_FILE_SIZE) { + if (wl->nvs->general_params.dual_mode_select) + wl->enable_11a = true; + } + + if (wl->nvs_len != sizeof(struct wl1271_nvs_file) && + (wl->nvs_len != WL1271_INI_LEGACY_NVS_FILE_SIZE || + wl->enable_11a)) { + wl1271_error("nvs size is not as expected: %zu != %zu", + wl->nvs_len, sizeof(struct wl1271_nvs_file)); + kfree(wl->nvs); + wl->nvs = NULL; + wl->nvs_len = 0; + return -EILSEQ; + } + + /* only the first part of the NVS needs to be uploaded */ + nvs_len = sizeof(wl->nvs->nvs); + nvs_ptr = (u8 *)wl->nvs->nvs; + + /* update current MAC address to NVS */ + nvs_ptr[11] = wl->mac_addr[0]; + nvs_ptr[10] = wl->mac_addr[1]; + nvs_ptr[6] = wl->mac_addr[2]; + nvs_ptr[5] = wl->mac_addr[3]; + nvs_ptr[4] = wl->mac_addr[4]; + nvs_ptr[3] = wl->mac_addr[5]; + + /* + * 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. + */ + + /* FIXME: Do we need to check here whether the LSB is 1? */ + while (nvs_ptr[0]) { + burst_len = nvs_ptr[0]; + dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8)); + + /* + * Due to our new wl1271_translate_reg_addr function, + * we need to add the REGISTER_BASE to the destination + */ + dest_addr += REGISTERS_BASE; + + /* 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)); + + wl1271_debug(DEBUG_BOOT, + "nvs burst write 0x%x: 0x%x", + dest_addr, val); + wl1271_write32(wl, dest_addr, val); + + nvs_ptr += 4; + dest_addr += 4; + } + } + + /* + * We've reached the first zero length, the first NVS table + * is located at an aligned offset which is at least 7 bytes further. + */ + nvs_ptr = (u8 *)wl->nvs->nvs + + ALIGN(nvs_ptr - (u8 *)wl->nvs->nvs + 7, 4); + nvs_len -= nvs_ptr - (u8 *)wl->nvs->nvs; + + /* Now we must set the partition correctly */ + wl1271_set_partition(wl, &part_table[PART_WORK]); + + /* Copy the NVS tables to a new block to ensure alignment */ + nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL); + if (!nvs_aligned) + return -ENOMEM; + + /* And finally we upload the NVS tables */ + wl1271_write(wl, CMD_MBOX_ADDRESS, nvs_aligned, nvs_len, false); + + kfree(nvs_aligned); + return 0; +} + +static void wl1271_boot_enable_interrupts(struct wl1271 *wl) +{ + wl1271_enable_interrupts(wl); + wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, + WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK)); + wl1271_write32(wl, HI_CFG, HI_CFG_DEF_VAL); +} + +static int wl1271_boot_soft_reset(struct wl1271 *wl) +{ + unsigned long timeout; + u32 boot_data; + + /* perform soft reset */ + wl1271_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 = wl1271_read32(wl, ACX_REG_SLV_SOFT_RESET); + wl1271_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 */ + wl1271_error("soft reset timeout"); + return -1; + } + + udelay(SOFT_RESET_STALL_TIME); + } + + /* disable Rx/Tx */ + wl1271_write32(wl, ENABLE, 0x0); + + /* disable auto calibration on start*/ + wl1271_write32(wl, SPARE_A2, 0xffff); + + return 0; +} + +static int wl1271_boot_run_firmware(struct wl1271 *wl) +{ + int loop, ret; + u32 chip_id, intr; + + wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); + + chip_id = wl1271_read32(wl, CHIP_ID_B); + + wl1271_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); + + if (chip_id != wl->chip.id) { + wl1271_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); + intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); + + if (intr == 0xffffffff) { + wl1271_error("error reading hardware complete " + "init indication"); + return -EIO; + } + /* check that ACX_INTR_INIT_COMPLETE is enabled */ + else if (intr & WL1271_ACX_INTR_INIT_COMPLETE) { + wl1271_write32(wl, ACX_REG_INTERRUPT_ACK, + WL1271_ACX_INTR_INIT_COMPLETE); + break; + } + } + + if (loop > INIT_LOOP) { + wl1271_error("timeout waiting for the hardware to " + "complete initialization"); + return -EIO; + } + + /* get hardware config command mail box */ + wl->cmd_box_addr = wl1271_read32(wl, REG_COMMAND_MAILBOX_PTR); + + /* get hardware config event mail box */ + wl->event_box_addr = wl1271_read32(wl, REG_EVENT_MAILBOX_PTR); + + /* set the working partition to its "running" mode offset */ + wl1271_set_partition(wl, &part_table[PART_WORK]); + + wl1271_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x", + wl->cmd_box_addr, wl->event_box_addr); + + wl1271_boot_fw_version(wl); + + /* + * in case of full asynchronous mode the firmware event must be + * ready to receive event from the command mailbox + */ + + /* unmask required mbox events */ + wl->event_mask = BSS_LOSE_EVENT_ID | + SCAN_COMPLETE_EVENT_ID | + PS_REPORT_EVENT_ID | + JOIN_EVENT_COMPLETE_ID | + DISCONNECT_EVENT_COMPLETE_ID | + RSSI_SNR_TRIGGER_0_EVENT_ID | + PSPOLL_DELIVERY_FAILURE_EVENT_ID | + SOFT_GEMINI_SENSE_EVENT_ID; + + ret = wl1271_event_unmask(wl); + if (ret < 0) { + wl1271_error("EVENT mask setting failed"); + return ret; + } + + wl1271_event_mbox_config(wl); + + /* firmware startup completed */ + return 0; +} + +static int wl1271_boot_write_irq_polarity(struct wl1271 *wl) +{ + u32 polarity; + + polarity = wl1271_top_reg_read(wl, OCP_REG_POLARITY); + + /* We use HIGH polarity, so unset the LOW bit */ + polarity &= ~POLARITY_LOW; + wl1271_top_reg_write(wl, OCP_REG_POLARITY, polarity); + + return 0; +} + +static void wl1271_boot_hw_version(struct wl1271 *wl) +{ + u32 fuse; + + fuse = wl1271_top_reg_read(wl, REG_FUSE_DATA_2_1); + fuse = (fuse & PG_VER_MASK) >> PG_VER_OFFSET; + + wl->hw_pg_ver = (s8)fuse; +} + +int wl1271_boot(struct wl1271 *wl) +{ + int ret = 0; + u32 tmp, clk, pause; + + wl1271_boot_hw_version(wl); + + if (wl->ref_clock == 0 || wl->ref_clock == 2 || wl->ref_clock == 4) + /* ref clk: 19.2/38.4/38.4-XTAL */ + clk = 0x3; + else if (wl->ref_clock == 1 || wl->ref_clock == 3) + /* ref clk: 26/52 */ + clk = 0x5; + else + return -EINVAL; + + if (wl->ref_clock != 0) { + u16 val; + /* Set clock type (open drain) */ + val = wl1271_top_reg_read(wl, OCP_REG_CLK_TYPE); + val &= FREF_CLK_TYPE_BITS; + wl1271_top_reg_write(wl, OCP_REG_CLK_TYPE, val); + + /* Set clock pull mode (no pull) */ + val = wl1271_top_reg_read(wl, OCP_REG_CLK_PULL); + val |= NO_PULL; + wl1271_top_reg_write(wl, OCP_REG_CLK_PULL, val); + } else { + u16 val; + /* Set clock polarity */ + val = wl1271_top_reg_read(wl, OCP_REG_CLK_POLARITY); + val &= FREF_CLK_POLARITY_BITS; + val |= CLK_REQ_OUTN_SEL; + wl1271_top_reg_write(wl, OCP_REG_CLK_POLARITY, val); + } + + wl1271_write32(wl, PLL_PARAMETERS, clk); + + pause = wl1271_read32(wl, PLL_PARAMETERS); + + wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause); + + pause &= ~(WU_COUNTER_PAUSE_VAL); + pause |= WU_COUNTER_PAUSE_VAL; + wl1271_write32(wl, WU_COUNTER_PAUSE, pause); + + /* Continue the ELP wake up sequence */ + wl1271_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL); + udelay(500); + + wl1271_set_partition(wl, &part_table[PART_DRPW]); + + /* Read-modify-write DRPW_SCRATCH_START register (see next state) + to be used by DRPw FW. The RTRIM value will be added by the FW + before taking DRPw out of reset */ + + wl1271_debug(DEBUG_BOOT, "DRPW_SCRATCH_START %08x", DRPW_SCRATCH_START); + clk = wl1271_read32(wl, DRPW_SCRATCH_START); + + wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk); + + clk |= (wl->ref_clock << 1) << 4; + wl1271_write32(wl, DRPW_SCRATCH_START, clk); + + wl1271_set_partition(wl, &part_table[PART_WORK]); + + /* Disable interrupts */ + wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); + + ret = wl1271_boot_soft_reset(wl); + if (ret < 0) + goto out; + + /* 2. start processing NVS file */ + ret = wl1271_boot_upload_nvs(wl); + if (ret < 0) + goto out; + + /* write firmware's last address (ie. it's length) to + * ACX_EEPROMLESS_IND_REG */ + wl1271_debug(DEBUG_BOOT, "ACX_EEPROMLESS_IND_REG"); + + wl1271_write32(wl, ACX_EEPROMLESS_IND_REG, ACX_EEPROMLESS_IND_REG); + + tmp = wl1271_read32(wl, CHIP_ID_B); + + wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp); + + /* 6. read the EEPROM parameters */ + tmp = wl1271_read32(wl, SCR_PAD2); + + ret = wl1271_boot_write_irq_polarity(wl); + if (ret < 0) + goto out; + + wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, + WL1271_ACX_ALL_EVENTS_VECTOR); + + /* WL1271: The reference driver skips steps 7 to 10 (jumps directly + * to upload_fw) */ + + ret = wl1271_boot_upload_firmware(wl); + if (ret < 0) + goto out; + + /* 10.5 start firmware */ + ret = wl1271_boot_run_firmware(wl); + if (ret < 0) + goto out; + + /* Enable firmware interrupts now */ + wl1271_boot_enable_interrupts(wl); + + /* set the wl1271 default filters */ + wl->rx_config = WL1271_DEFAULT_RX_CONFIG; + wl->rx_filter = WL1271_DEFAULT_RX_FILTER; + + wl1271_event_mbox_config(wl); + +out: + return ret; +} diff --git a/drivers/net/wireless/wl12xx/boot.h b/drivers/net/wireless/wl12xx/boot.h new file mode 100644 index 0000000..c7d7719 --- /dev/null +++ b/drivers/net/wireless/wl12xx/boot.h @@ -0,0 +1,71 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 "wl12xx.h" + +int wl1271_boot(struct wl1271 *wl); + +#define WL1271_NO_SUBBANDS 8 +#define WL1271_NO_POWER_LEVELS 4 +#define WL1271_FW_VERSION_MAX_LEN 20 + +struct wl1271_static_data { + u8 mac_address[ETH_ALEN]; + u8 padding[2]; + u8 fw_version[WL1271_FW_VERSION_MAX_LEN]; + u32 hw_version; + u8 tx_power_table[WL1271_NO_SUBBANDS][WL1271_NO_POWER_LEVELS]; +}; + +/* number of times we try to read the INIT interrupt */ +#define INIT_LOOP 20000 + +/* delay between retries */ +#define INIT_LOOP_DELAY 50 + +#define WU_COUNTER_PAUSE_VAL 0x3FF +#define WELP_ARM_COMMAND_VAL 0x4 + +#define OCP_REG_POLARITY 0x0064 +#define OCP_REG_CLK_TYPE 0x0448 +#define OCP_REG_CLK_POLARITY 0x0cb2 +#define OCP_REG_CLK_PULL 0x0cb4 + +#define REG_FUSE_DATA_2_1 0x050a +#define PG_VER_MASK 0x3c +#define PG_VER_OFFSET 2 + +#define CMD_MBOX_ADDRESS 0x407B4 + +#define POLARITY_LOW BIT(1) +#define NO_PULL (BIT(14) | BIT(15)) + +#define FREF_CLK_TYPE_BITS 0xfffffe7f +#define CLK_REQ_PRCM 0x100 +#define FREF_CLK_POLARITY_BITS 0xfffff8ff +#define CLK_REQ_OUTN_SEL 0x700 + +#endif diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c new file mode 100644 index 0000000..f3d0541 --- /dev/null +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -0,0 +1,783 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2009-2010 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 "wl12xx.h" +#include "reg.h" +#include "io.h" +#include "acx.h" +#include "wl12xx_80211.h" +#include "cmd.h" +#include "event.h" + +#define WL1271_CMD_FAST_POLL_COUNT 50 + +/* + * 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 wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, + size_t res_len) +{ + struct wl1271_cmd_header *cmd; + unsigned long timeout; + u32 intr; + int ret = 0; + u16 status; + u16 poll_count = 0; + + cmd = buf; + cmd->id = cpu_to_le16(id); + cmd->status = 0; + + WARN_ON(len % 4 != 0); + + wl1271_write(wl, wl->cmd_box_addr, buf, len, false); + + wl1271_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); + + timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT); + + intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); + while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) { + if (time_after(jiffies, timeout)) { + wl1271_error("command complete timeout"); + ret = -ETIMEDOUT; + goto out; + } + + poll_count++; + if (poll_count < WL1271_CMD_FAST_POLL_COUNT) + udelay(10); + else + msleep(1); + + intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); + } + + /* read back the status code of the command */ + if (res_len == 0) + res_len = sizeof(struct wl1271_cmd_header); + wl1271_read(wl, wl->cmd_box_addr, cmd, res_len, false); + + status = le16_to_cpu(cmd->status); + if (status != CMD_STATUS_SUCCESS) { + wl1271_error("command execute failure %d", status); + ieee80211_queue_work(wl->hw, &wl->recovery_work); + ret = -EIO; + } + + wl1271_write32(wl, ACX_REG_INTERRUPT_ACK, + WL1271_ACX_INTR_CMD_COMPLETE); + +out: + return ret; +} + +int wl1271_cmd_general_parms(struct wl1271 *wl) +{ + struct wl1271_general_parms_cmd *gen_parms; + struct wl1271_ini_general_params *gp = &wl->nvs->general_params; + bool answer = false; + int ret; + + if (!wl->nvs) + return -ENODEV; + + gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL); + if (!gen_parms) + return -ENOMEM; + + gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM; + + memcpy(&gen_parms->general_params, gp, sizeof(*gp)); + + if (gp->tx_bip_fem_auto_detect) + answer = true; + + ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer); + if (ret < 0) { + wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed"); + goto out; + } + + gp->tx_bip_fem_manufacturer = + gen_parms->general_params.tx_bip_fem_manufacturer; + + wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n", + answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer); + +out: + kfree(gen_parms); + return ret; +} + +int wl1271_cmd_radio_parms(struct wl1271 *wl) +{ + struct wl1271_radio_parms_cmd *radio_parms; + struct wl1271_ini_general_params *gp = &wl->nvs->general_params; + int ret; + + if (!wl->nvs) + return -ENODEV; + + radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL); + if (!radio_parms) + return -ENOMEM; + + radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM; + + /* 2.4GHz parameters */ + memcpy(&radio_parms->static_params_2, &wl->nvs->stat_radio_params_2, + sizeof(struct wl1271_ini_band_params_2)); + memcpy(&radio_parms->dyn_params_2, + &wl->nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params, + sizeof(struct wl1271_ini_fem_params_2)); + + /* 5GHz parameters */ + memcpy(&radio_parms->static_params_5, + &wl->nvs->stat_radio_params_5, + sizeof(struct wl1271_ini_band_params_5)); + memcpy(&radio_parms->dyn_params_5, + &wl->nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params, + sizeof(struct wl1271_ini_fem_params_5)); + + wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ", + radio_parms, sizeof(*radio_parms)); + + ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0); + if (ret < 0) + wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed"); + + kfree(radio_parms); + return ret; +} + +int wl1271_cmd_ext_radio_parms(struct wl1271 *wl) +{ + struct wl1271_ext_radio_parms_cmd *ext_radio_parms; + struct conf_rf_settings *rf = &wl->conf.rf; + int ret; + + if (!wl->nvs) + return -ENODEV; + + ext_radio_parms = kzalloc(sizeof(*ext_radio_parms), GFP_KERNEL); + if (!ext_radio_parms) + return -ENOMEM; + + ext_radio_parms->test.id = TEST_CMD_INI_FILE_RF_EXTENDED_PARAM; + + memcpy(ext_radio_parms->tx_per_channel_power_compensation_2, + rf->tx_per_channel_power_compensation_2, + CONF_TX_PWR_COMPENSATION_LEN_2); + memcpy(ext_radio_parms->tx_per_channel_power_compensation_5, + rf->tx_per_channel_power_compensation_5, + CONF_TX_PWR_COMPENSATION_LEN_5); + + wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_EXT_RADIO_PARAM: ", + ext_radio_parms, sizeof(*ext_radio_parms)); + + ret = wl1271_cmd_test(wl, ext_radio_parms, sizeof(*ext_radio_parms), 0); + if (ret < 0) + wl1271_warning("TEST_CMD_INI_FILE_RF_EXTENDED_PARAM failed"); + + kfree(ext_radio_parms); + return ret; +} + +/* + * Poll the mailbox event field until any of the bits in the mask is set or a + * timeout occurs (WL1271_EVENT_TIMEOUT in msecs) + */ +static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask) +{ + u32 events_vector, event; + unsigned long timeout; + + timeout = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT); + + do { + if (time_after(jiffies, timeout)) { + ieee80211_queue_work(wl->hw, &wl->recovery_work); + return -ETIMEDOUT; + } + + msleep(1); + + /* read from both event fields */ + wl1271_read(wl, wl->mbox_ptr[0], &events_vector, + sizeof(events_vector), false); + event = events_vector & mask; + wl1271_read(wl, wl->mbox_ptr[1], &events_vector, + sizeof(events_vector), false); + event |= events_vector & mask; + } while (!event); + + return 0; +} + +int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type) +{ + struct wl1271_cmd_join *join; + int ret, i; + u8 *bssid; + + join = kzalloc(sizeof(*join), GFP_KERNEL); + if (!join) { + ret = -ENOMEM; + goto out; + } + + wl1271_debug(DEBUG_CMD, "cmd join"); + + /* 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 = cpu_to_le32(wl->rx_config); + join->rx_filter_options = cpu_to_le32(wl->rx_filter); + join->bss_type = bss_type; + join->basic_rate_set = cpu_to_le32(wl->basic_rate_set); + + if (wl->band == IEEE80211_BAND_5GHZ) + join->bss_type |= WL1271_JOIN_CMD_BSS_TYPE_5GHZ; + + join->beacon_interval = cpu_to_le16(wl->beacon_int); + join->dtim_interval = WL1271_DEFAULT_DTIM_PERIOD; + + join->channel = wl->channel; + join->ssid_len = wl->ssid_len; + memcpy(join->ssid, wl->ssid, wl->ssid_len); + + join->ctrl |= wl->session_counter << WL1271_JOIN_CMD_TX_SESSION_OFFSET; + + /* reset TX security counters */ + wl->tx_security_last_seq = 0; + wl->tx_security_seq = 0; + + ret = wl1271_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join), 0); + if (ret < 0) { + wl1271_error("failed to initiate cmd join"); + goto out_free; + } + + ret = wl1271_cmd_wait_for_event(wl, JOIN_EVENT_COMPLETE_ID); + if (ret < 0) + wl1271_error("cmd join event completion error"); + +out_free: + kfree(join); + +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 wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer) +{ + int ret; + size_t res_len = 0; + + wl1271_debug(DEBUG_CMD, "cmd test"); + + if (answer) + res_len = buf_len; + + ret = wl1271_cmd_send(wl, CMD_TEST, buf, buf_len, res_len); + + if (ret < 0) { + wl1271_warning("TEST command failed"); + return ret; + } + + return ret; +} + +/** + * 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 wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len) +{ + struct acx_header *acx = buf; + int ret; + + wl1271_debug(DEBUG_CMD, "cmd interrogate"); + + acx->id = cpu_to_le16(id); + + /* payload length, does not include any headers */ + acx->len = cpu_to_le16(len - sizeof(*acx)); + + ret = wl1271_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx), len); + if (ret < 0) + wl1271_error("INTERROGATE command failed"); + + 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 wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len) +{ + struct acx_header *acx = buf; + int ret; + + wl1271_debug(DEBUG_CMD, "cmd configure"); + + acx->id = cpu_to_le16(id); + + /* payload length, does not include any headers */ + acx->len = cpu_to_le16(len - sizeof(*acx)); + + ret = wl1271_cmd_send(wl, CMD_CONFIGURE, acx, len, 0); + if (ret < 0) { + wl1271_warning("CONFIGURE command NOK"); + return ret; + } + + return 0; +} + +int wl1271_cmd_data_path(struct wl1271 *wl, bool enable) +{ + struct cmd_enabledisable_path *cmd; + int ret; + u16 cmd_rx, cmd_tx; + + wl1271_debug(DEBUG_CMD, "cmd data path"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + /* the channel here is only used for calibration, so hardcoded to 1 */ + cmd->channel = 1; + + if (enable) { + cmd_rx = CMD_ENABLE_RX; + cmd_tx = CMD_ENABLE_TX; + } else { + cmd_rx = CMD_DISABLE_RX; + cmd_tx = CMD_DISABLE_TX; + } + + ret = wl1271_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("rx %s cmd for channel %d failed", + enable ? "start" : "stop", cmd->channel); + goto out; + } + + wl1271_debug(DEBUG_BOOT, "rx %s cmd channel %d", + enable ? "start" : "stop", cmd->channel); + + ret = wl1271_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("tx %s cmd for channel %d failed", + enable ? "start" : "stop", cmd->channel); + goto out; + } + + wl1271_debug(DEBUG_BOOT, "tx %s cmd channel %d", + enable ? "start" : "stop", cmd->channel); + +out: + kfree(cmd); + return ret; +} + +int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, u32 rates, bool send) +{ + struct wl1271_cmd_ps_params *ps_params = NULL; + int ret = 0; + + wl1271_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 = send; + ps_params->retries = wl->conf.conn.psm_entry_nullfunc_retries; + ps_params->hang_over_period = wl->conf.conn.psm_entry_hangover_period; + ps_params->null_data_rate = cpu_to_le32(rates); + + ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params, + sizeof(*ps_params), 0); + if (ret < 0) { + wl1271_error("cmd set_ps_mode failed"); + goto out; + } + +out: + kfree(ps_params); + return ret; +} + +int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, + void *buf, size_t buf_len, int index, u32 rates) +{ + struct wl1271_cmd_template_set *cmd; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd template_set %d", template_id); + + WARN_ON(buf_len > WL1271_CMD_TEMPL_MAX_SIZE); + buf_len = min_t(size_t, buf_len, WL1271_CMD_TEMPL_MAX_SIZE); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->len = cpu_to_le16(buf_len); + cmd->template_type = template_id; + cmd->enabled_rates = cpu_to_le32(rates); + cmd->short_retry_limit = wl->conf.tx.rc_conf.short_retry_limit; + cmd->long_retry_limit = wl->conf.tx.rc_conf.long_retry_limit; + cmd->index = index; + + if (buf) + memcpy(cmd->template_data, buf, buf_len); + + ret = wl1271_cmd_send(wl, CMD_SET_TEMPLATE, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_warning("cmd set_template failed: %d", ret); + goto out_free; + } + +out_free: + kfree(cmd); + +out: + return ret; +} + +int wl1271_cmd_build_null_data(struct wl1271 *wl) +{ + struct sk_buff *skb = NULL; + int size; + void *ptr; + int ret = -ENOMEM; + + + if (wl->bss_type == BSS_TYPE_IBSS) { + size = sizeof(struct wl12xx_null_data_template); + ptr = NULL; + } else { + skb = ieee80211_nullfunc_get(wl->hw, wl->vif); + if (!skb) + goto out; + size = skb->len; + ptr = skb->data; + } + + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, ptr, size, 0, + wl->basic_rate); + +out: + dev_kfree_skb(skb); + if (ret) + wl1271_warning("cmd buld null data failed %d", ret); + + return ret; + +} + +int wl1271_cmd_build_klv_null_data(struct wl1271 *wl) +{ + struct sk_buff *skb = NULL; + int ret = -ENOMEM; + + skb = ieee80211_nullfunc_get(wl->hw, wl->vif); + if (!skb) + goto out; + + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV, + skb->data, skb->len, + CMD_TEMPL_KLV_IDX_NULL_DATA, + wl->basic_rate); + +out: + dev_kfree_skb(skb); + if (ret) + wl1271_warning("cmd build klv null data failed %d", ret); + + return ret; + +} + +int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid) +{ + struct sk_buff *skb; + int ret = 0; + + skb = ieee80211_pspoll_get(wl->hw, wl->vif); + if (!skb) + goto out; + + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, skb->data, + skb->len, 0, wl->basic_rate_set); + +out: + dev_kfree_skb(skb); + return ret; +} + +int wl1271_cmd_build_probe_req(struct wl1271 *wl, + const u8 *ssid, size_t ssid_len, + const u8 *ie, size_t ie_len, u8 band) +{ + struct sk_buff *skb; + int ret; + + skb = ieee80211_probereq_get(wl->hw, wl->vif, ssid, ssid_len, + ie, ie_len); + if (!skb) { + ret = -ENOMEM; + goto out; + } + + wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len); + + if (band == IEEE80211_BAND_2GHZ) + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, + skb->data, skb->len, 0, + wl->conf.tx.basic_rate); + else + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, + skb->data, skb->len, 0, + wl->conf.tx.basic_rate_5); + +out: + dev_kfree_skb(skb); + return ret; +} + +int wl1271_build_qos_null_data(struct wl1271 *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 wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, &template, + sizeof(template), 0, + wl->basic_rate); +} + +int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id) +{ + struct wl1271_cmd_set_keys *cmd; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd set_default_wep_key %d", id); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->id = id; + cmd->key_action = cpu_to_le16(KEY_SET_ID); + cmd->key_type = KEY_WEP; + + ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_warning("cmd set_default_wep_key failed: %d", ret); + goto out; + } + +out: + kfree(cmd); + + return ret; +} + +int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, + u8 key_size, const u8 *key, const u8 *addr, + u32 tx_seq_32, u16 tx_seq_16) +{ + struct wl1271_cmd_set_keys *cmd; + int ret = 0; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + if (key_type != KEY_WEP) + memcpy(cmd->addr, addr, ETH_ALEN); + + cmd->key_action = cpu_to_le16(action); + cmd->key_size = key_size; + cmd->key_type = key_type; + + cmd->ac_seq_num16[0] = cpu_to_le16(tx_seq_16); + cmd->ac_seq_num32[0] = cpu_to_le32(tx_seq_32); + + /* we have only one SSID profile */ + cmd->ssid_profile = 0; + + cmd->id = id; + + if (key_type == KEY_TKIP) { + /* + * 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(cmd->key, key, 16); + memcpy(cmd->key + 16, key + 24, 8); + memcpy(cmd->key + 24, key + 16, 8); + + } else { + memcpy(cmd->key, key, key_size); + } + + wl1271_dump(DEBUG_CRYPT, "TARGET KEY: ", cmd, sizeof(*cmd)); + + ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_warning("could not set keys"); + goto out; + } + +out: + kfree(cmd); + + return ret; +} + +int wl1271_cmd_disconnect(struct wl1271 *wl) +{ + struct wl1271_cmd_disconnect *cmd; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd disconnect"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->rx_config_options = cpu_to_le32(wl->rx_config); + cmd->rx_filter_options = cpu_to_le32(wl->rx_filter); + /* disconnect reason is not used in immediate disconnections */ + cmd->type = DISCONNECT_IMMEDIATE; + + ret = wl1271_cmd_send(wl, CMD_DISCONNECT, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to send disconnect command"); + goto out_free; + } + + ret = wl1271_cmd_wait_for_event(wl, DISCONNECT_EVENT_COMPLETE_ID); + if (ret < 0) + wl1271_error("cmd disconnect event completion error"); + +out_free: + kfree(cmd); + +out: + return ret; +} + +int wl1271_cmd_set_sta_state(struct wl1271 *wl) +{ + struct wl1271_cmd_set_sta_state *cmd; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd set sta state"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->state = WL1271_CMD_STA_STATE_CONNECTED; + + ret = wl1271_cmd_send(wl, CMD_SET_STA_STATE, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to send set STA state command"); + goto out_free; + } + +out_free: + kfree(cmd); + +out: + return ret; +} diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h new file mode 100644 index 0000000..893dbf7 --- /dev/null +++ b/drivers/net/wireless/wl12xx/cmd.h @@ -0,0 +1,459 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 __CMD_H__ +#define __CMD_H__ + +#include "wl12xx.h" + +struct acx_header; + +int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, + size_t res_len); +int wl1271_cmd_general_parms(struct wl1271 *wl); +int wl1271_cmd_radio_parms(struct wl1271 *wl); +int wl1271_cmd_ext_radio_parms(struct wl1271 *wl); +int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type); +int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer); +int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len); +int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len); +int wl1271_cmd_data_path(struct wl1271 *wl, bool enable); +int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, u32 rates, bool send); +int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer, + size_t len); +int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, + void *buf, size_t buf_len, int index, u32 rates); +int wl1271_cmd_build_null_data(struct wl1271 *wl); +int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid); +int wl1271_cmd_build_probe_req(struct wl1271 *wl, + const u8 *ssid, size_t ssid_len, + const u8 *ie, size_t ie_len, u8 band); +int wl1271_build_qos_null_data(struct wl1271 *wl); +int wl1271_cmd_build_klv_null_data(struct wl1271 *wl); +int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id); +int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, + u8 key_size, const u8 *key, const u8 *addr, + u32 tx_seq_32, u16 tx_seq_16); +int wl1271_cmd_disconnect(struct wl1271 *wl); +int wl1271_cmd_set_sta_state(struct wl1271 *wl); + +enum wl1271_commands { + 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_START_JOIN = 11, + CMD_SET_KEYS = 12, + CMD_READ_MEMORY = 13, + CMD_WRITE_MEMORY = 14, + CMD_SET_TEMPLATE = 19, + CMD_TEST = 23, + CMD_NOISE_HIST = 28, + 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, + CMD_CONNECTION_SCAN_CFG = 48, + CMD_CONNECTION_SCAN_SSID_CFG = 49, + CMD_START_PERIODIC_SCAN = 50, + CMD_STOP_PERIODIC_SCAN = 51, + CMD_SET_STA_STATE = 52, + + NUM_COMMANDS, + MAX_COMMAND_ID = 0xFFFF, +}; + +#define MAX_CMD_PARAMS 572 + +enum { + CMD_TEMPL_KLV_IDX_NULL_DATA = 0, + CMD_TEMPL_KLV_IDX_MAX = 4 +}; + +enum cmd_templ { + CMD_TEMPL_NULL_DATA = 0, + CMD_TEMPL_BEACON, + CMD_TEMPL_CFG_PROBE_REQ_2_4, + CMD_TEMPL_CFG_PROBE_REQ_5, + CMD_TEMPL_PROBE_RESPONSE, + CMD_TEMPL_QOS_NULL_DATA, + CMD_TEMPL_PS_POLL, + CMD_TEMPL_KLV, + CMD_TEMPL_DISCONNECT, + CMD_TEMPL_PROBE_REQ_2_4, /* for firmware internal use only */ + CMD_TEMPL_PROBE_REQ_5, /* for firmware internal use only */ + CMD_TEMPL_BAR, /* for firmware internal use only */ + CMD_TEMPL_CTS, /* + * For CTS-to-self (FastCTS) mechanism + * for BT/WLAN coexistence (SoftGemini). */ + CMD_TEMPL_MAX = 0xff +}; + +/* unit ms */ +#define WL1271_COMMAND_TIMEOUT 2000 +#define WL1271_CMD_TEMPL_MAX_SIZE 252 +#define WL1271_EVENT_TIMEOUT 750 + +struct wl1271_cmd_header { + __le16 id; + __le16 status; + /* payload */ + u8 data[0]; +} __packed; + +#define WL1271_CMD_MAX_PARAMS 572 + +struct wl1271_command { + struct wl1271_cmd_header header; + u8 parameters[WL1271_CMD_MAX_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 +}; + +#define CMDMBOX_HEADER_LEN 4 +#define CMDMBOX_INFO_ELEM_HEADER_LEN 4 + +enum { + BSS_TYPE_IBSS = 0, + BSS_TYPE_STA_BSS = 2, + BSS_TYPE_AP_BSS = 3, + MAX_BSS_TYPE = 0xFF +}; + +#define WL1271_JOIN_CMD_CTRL_TX_FLUSH 0x80 /* Firmware flushes all Tx */ +#define WL1271_JOIN_CMD_TX_SESSION_OFFSET 1 +#define WL1271_JOIN_CMD_BSS_TYPE_5GHZ 0x10 + +struct wl1271_cmd_join { + struct wl1271_cmd_header header; + + __le32 bssid_lsb; + __le16 bssid_msb; + __le16 beacon_interval; /* in TBTTs */ + __le32 rx_config_options; + __le32 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). + */ + __le32 basic_rate_set; + u8 dtim_interval; + /* + * 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 reserved[3]; +} __packed; + +struct cmd_enabledisable_path { + struct wl1271_cmd_header header; + + u8 channel; + u8 padding[3]; +} __packed; + +#define WL1271_RATE_AUTOMATIC 0 + +struct wl1271_cmd_template_set { + struct wl1271_cmd_header header; + + __le16 len; + u8 template_type; + u8 index; /* relevant only for KLV_TEMPLATE type */ + __le32 enabled_rates; + u8 short_retry_limit; + u8 long_retry_limit; + u8 aflags; + u8 reserved; + u8 template_data[WL1271_CMD_TEMPL_MAX_SIZE]; +} __packed; + +#define TIM_ELE_ID 5 +#define PARTIAL_VBM_MAX 251 + +struct wl1271_tim { + u8 identity; + u8 length; + u8 dtim_count; + u8 dtim_period; + u8 bitmap_ctrl; + u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */ +} __packed; + +enum wl1271_cmd_ps_mode { + STATION_ACTIVE_MODE, + STATION_POWER_SAVE_MODE +}; + +struct wl1271_cmd_ps_params { + struct wl1271_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; + __le32 null_data_rate; +} __packed; + +/* HW encryption keys */ +#define NUM_ACCESS_CATEGORIES_COPY 4 +#define MAX_KEY_SIZE 32 + +enum wl1271_cmd_key_action { + KEY_ADD_OR_REPLACE = 1, + KEY_REMOVE = 2, + KEY_SET_ID = 3, + MAX_KEY_ACTION = 0xffff, +}; + +enum wl1271_cmd_key_type { + KEY_NONE = 0, + KEY_WEP = 1, + KEY_TKIP = 2, + KEY_AES = 3, + KEY_GEM = 4, +}; + +/* FIXME: Add description for key-types */ + +struct wl1271_cmd_set_keys { + struct wl1271_cmd_header header; + + /* Ignored for default WEP key */ + u8 addr[ETH_ALEN]; + + /* key_action_e */ + __le16 key_action; + + __le16 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]; + __le16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY]; + __le32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY]; +} __packed; + +struct wl1271_cmd_test_header { + u8 id; + u8 padding[3]; +} __packed; + +enum wl1271_channel_tune_bands { + WL1271_CHANNEL_TUNE_BAND_2_4, + WL1271_CHANNEL_TUNE_BAND_5, + WL1271_CHANNEL_TUNE_BAND_4_9 +}; + +#define WL1271_PD_REFERENCE_POINT_BAND_B_G 0 + +#define TEST_CMD_P2G_CAL 0x02 +#define TEST_CMD_CHANNEL_TUNE 0x0d +#define TEST_CMD_UPDATE_PD_REFERENCE_POINT 0x1d +#define TEST_CMD_INI_FILE_RADIO_PARAM 0x19 +#define TEST_CMD_INI_FILE_GENERAL_PARAM 0x1E +#define TEST_CMD_INI_FILE_RF_EXTENDED_PARAM 0x26 + +struct wl1271_general_parms_cmd { + struct wl1271_cmd_header header; + + struct wl1271_cmd_test_header test; + + struct wl1271_ini_general_params general_params; + + u8 sr_debug_table[WL1271_INI_MAX_SMART_REFLEX_PARAM]; + u8 sr_sen_n_p; + u8 sr_sen_n_p_gain; + u8 sr_sen_nrn; + u8 sr_sen_prn; + u8 padding[3]; +} __packed; + +struct wl1271_radio_parms_cmd { + struct wl1271_cmd_header header; + + struct wl1271_cmd_test_header test; + + /* Static radio parameters */ + struct wl1271_ini_band_params_2 static_params_2; + struct wl1271_ini_band_params_5 static_params_5; + + /* Dynamic radio parameters */ + struct wl1271_ini_fem_params_2 dyn_params_2; + u8 padding2; + struct wl1271_ini_fem_params_5 dyn_params_5; + u8 padding3[2]; +} __packed; + +struct wl1271_ext_radio_parms_cmd { + struct wl1271_cmd_header header; + + struct wl1271_cmd_test_header test; + + u8 tx_per_channel_power_compensation_2[CONF_TX_PWR_COMPENSATION_LEN_2]; + u8 tx_per_channel_power_compensation_5[CONF_TX_PWR_COMPENSATION_LEN_5]; + u8 padding[3]; +} __packed; + +struct wl1271_cmd_cal_channel_tune { + struct wl1271_cmd_header header; + + struct wl1271_cmd_test_header test; + + u8 band; + u8 channel; + + __le16 radio_status; +} __packed; + +struct wl1271_cmd_cal_update_ref_point { + struct wl1271_cmd_header header; + + struct wl1271_cmd_test_header test; + + __le32 ref_power; + __le32 ref_detector; + u8 sub_band; + u8 padding[3]; +} __packed; + +#define MAX_TLV_LENGTH 400 +#define MAX_NVS_VERSION_LENGTH 12 + +#define WL1271_CAL_P2G_BAND_B_G BIT(0) + +struct wl1271_cmd_cal_p2g { + struct wl1271_cmd_header header; + + struct wl1271_cmd_test_header test; + + __le16 len; + u8 buf[MAX_TLV_LENGTH]; + u8 type; + u8 padding; + + __le16 radio_status; + u8 nvs_version[MAX_NVS_VERSION_LENGTH]; + + u8 sub_band_mask; + u8 padding2; +} __packed; + + +/* + * There are three types of disconnections: + * + * DISCONNECT_IMMEDIATE: the fw doesn't send any frames + * DISCONNECT_DEAUTH: the fw generates a DEAUTH request with the reason + * we have passed + * DISCONNECT_DISASSOC: the fw generates a DESASSOC request with the reason + * we have passed + */ +enum wl1271_disconnect_type { + DISCONNECT_IMMEDIATE, + DISCONNECT_DEAUTH, + DISCONNECT_DISASSOC +}; + +struct wl1271_cmd_disconnect { + struct wl1271_cmd_header header; + + __le32 rx_config_options; + __le32 rx_filter_options; + + __le16 reason; + u8 type; + + u8 padding; +} __packed; + +#define WL1271_CMD_STA_STATE_CONNECTED 1 + +struct wl1271_cmd_set_sta_state { + struct wl1271_cmd_header header; + + u8 state; + u8 padding[3]; +} __packed; + +#endif /* __WL1271_CMD_H__ */ diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h new file mode 100644 index 0000000..a16b361 --- /dev/null +++ b/drivers/net/wireless/wl12xx/conf.h @@ -0,0 +1,1105 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 __CONF_H__ +#define __CONF_H__ + +enum { + CONF_HW_BIT_RATE_1MBPS = BIT(0), + CONF_HW_BIT_RATE_2MBPS = BIT(1), + CONF_HW_BIT_RATE_5_5MBPS = BIT(2), + CONF_HW_BIT_RATE_6MBPS = BIT(3), + CONF_HW_BIT_RATE_9MBPS = BIT(4), + CONF_HW_BIT_RATE_11MBPS = BIT(5), + CONF_HW_BIT_RATE_12MBPS = BIT(6), + CONF_HW_BIT_RATE_18MBPS = BIT(7), + CONF_HW_BIT_RATE_22MBPS = BIT(8), + CONF_HW_BIT_RATE_24MBPS = BIT(9), + CONF_HW_BIT_RATE_36MBPS = BIT(10), + CONF_HW_BIT_RATE_48MBPS = BIT(11), + CONF_HW_BIT_RATE_54MBPS = BIT(12), + CONF_HW_BIT_RATE_MCS_0 = BIT(13), + CONF_HW_BIT_RATE_MCS_1 = BIT(14), + CONF_HW_BIT_RATE_MCS_2 = BIT(15), + CONF_HW_BIT_RATE_MCS_3 = BIT(16), + CONF_HW_BIT_RATE_MCS_4 = BIT(17), + CONF_HW_BIT_RATE_MCS_5 = BIT(18), + CONF_HW_BIT_RATE_MCS_6 = BIT(19), + CONF_HW_BIT_RATE_MCS_7 = BIT(20) +}; + +enum { + CONF_HW_RATE_INDEX_1MBPS = 0, + CONF_HW_RATE_INDEX_2MBPS = 1, + CONF_HW_RATE_INDEX_5_5MBPS = 2, + CONF_HW_RATE_INDEX_6MBPS = 3, + CONF_HW_RATE_INDEX_9MBPS = 4, + CONF_HW_RATE_INDEX_11MBPS = 5, + CONF_HW_RATE_INDEX_12MBPS = 6, + CONF_HW_RATE_INDEX_18MBPS = 7, + CONF_HW_RATE_INDEX_22MBPS = 8, + CONF_HW_RATE_INDEX_24MBPS = 9, + CONF_HW_RATE_INDEX_36MBPS = 10, + CONF_HW_RATE_INDEX_48MBPS = 11, + CONF_HW_RATE_INDEX_54MBPS = 12, + CONF_HW_RATE_INDEX_MAX = CONF_HW_RATE_INDEX_54MBPS, +}; + +enum { + CONF_HW_RXTX_RATE_MCS7 = 0, + CONF_HW_RXTX_RATE_MCS6, + CONF_HW_RXTX_RATE_MCS5, + CONF_HW_RXTX_RATE_MCS4, + CONF_HW_RXTX_RATE_MCS3, + CONF_HW_RXTX_RATE_MCS2, + CONF_HW_RXTX_RATE_MCS1, + CONF_HW_RXTX_RATE_MCS0, + CONF_HW_RXTX_RATE_54, + CONF_HW_RXTX_RATE_48, + CONF_HW_RXTX_RATE_36, + CONF_HW_RXTX_RATE_24, + CONF_HW_RXTX_RATE_22, + CONF_HW_RXTX_RATE_18, + CONF_HW_RXTX_RATE_12, + CONF_HW_RXTX_RATE_11, + CONF_HW_RXTX_RATE_9, + CONF_HW_RXTX_RATE_6, + CONF_HW_RXTX_RATE_5_5, + CONF_HW_RXTX_RATE_2, + CONF_HW_RXTX_RATE_1, + CONF_HW_RXTX_RATE_MAX, + CONF_HW_RXTX_RATE_UNSUPPORTED = 0xff +}; + +enum { + CONF_SG_DISABLE = 0, + CONF_SG_PROTECTIVE, + CONF_SG_OPPORTUNISTIC +}; + +enum { + /* + * PER threshold in PPM of the BT voice + * + * Range: 0 - 10000000 + */ + CONF_SG_BT_PER_THRESHOLD = 0, + + /* + * Number of consequent RX_ACTIVE activities to override BT voice + * frames to ensure WLAN connection + * + * Range: 0 - 100 + */ + CONF_SG_HV3_MAX_OVERRIDE, + + /* + * Defines the PER threshold of the BT voice + * + * Range: 0 - 65000 + */ + CONF_SG_BT_NFS_SAMPLE_INTERVAL, + + /* + * Defines the load ratio of BT + * + * Range: 0 - 100 (%) + */ + CONF_SG_BT_LOAD_RATIO, + + /* + * Defines whether the SG will force WLAN host to enter/exit PSM + * + * Range: 1 - SG can force, 0 - host handles PSM + */ + CONF_SG_AUTO_PS_MODE, + + /* + * Compensation percentage of probe requests when scan initiated + * during BT voice/ACL link. + * + * Range: 0 - 255 (%) + */ + CONF_SG_AUTO_SCAN_PROBE_REQ, + + /* + * Compensation percentage of probe requests when active scan initiated + * during BT voice + * + * Range: 0 - 255 (%) + */ + CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3, + + /* + * Defines antenna configuration (single/dual antenna) + * + * Range: 0 - single antenna, 1 - dual antenna + */ + CONF_SG_ANTENNA_CONFIGURATION, + + /* + * The threshold (percent) of max consequtive beacon misses before + * increasing priority of beacon reception. + * + * Range: 0 - 100 (%) + */ + CONF_SG_BEACON_MISS_PERCENT, + + /* + * The rate threshold below which receiving a data frame from the AP + * will increase the priority of the data frame above BT traffic. + * + * Range: 0,2, 5(=5.5), 6, 9, 11, 12, 18, 24, 36, 48, 54 + */ + CONF_SG_RATE_ADAPT_THRESH, + + /* + * Not used currently. + * + * Range: 0 + */ + CONF_SG_RATE_ADAPT_SNR, + + /* + * Configure the min and max time BT gains the antenna + * in WLAN PSM / BT master basic rate + * + * Range: 0 - 255 (ms) + */ + CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR, + CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR, + + /* + * The time after it expires no new WLAN trigger frame is trasmitted + * in WLAN PSM / BT master basic rate + * + * Range: 0 - 255 (ms) + */ + CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR, + + /* + * Configure the min and max time BT gains the antenna + * in WLAN PSM / BT slave basic rate + * + * Range: 0 - 255 (ms) + */ + CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR, + CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR, + + /* + * The time after it expires no new WLAN trigger frame is trasmitted + * in WLAN PSM / BT slave basic rate + * + * Range: 0 - 255 (ms) + */ + CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR, + + /* + * Configure the min and max time BT gains the antenna + * in WLAN PSM / BT master EDR + * + * Range: 0 - 255 (ms) + */ + CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR, + CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR, + + /* + * The time after it expires no new WLAN trigger frame is trasmitted + * in WLAN PSM / BT master EDR + * + * Range: 0 - 255 (ms) + */ + CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR, + + /* + * Configure the min and max time BT gains the antenna + * in WLAN PSM / BT slave EDR + * + * Range: 0 - 255 (ms) + */ + CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR, + CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR, + + /* + * The time after it expires no new WLAN trigger frame is trasmitted + * in WLAN PSM / BT slave EDR + * + * Range: 0 - 255 (ms) + */ + CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR, + + /* + * RX guard time before the beginning of a new BT voice frame during + * which no new WLAN trigger frame is transmitted. + * + * Range: 0 - 100000 (us) + */ + CONF_SG_RXT, + + /* + * TX guard time before the beginning of a new BT voice frame during + * which no new WLAN frame is transmitted. + * + * Range: 0 - 100000 (us) + */ + + CONF_SG_TXT, + + /* + * Enable adaptive RXT/TXT algorithm. If disabled, the host values + * will be utilized. + * + * Range: 0 - disable, 1 - enable + */ + CONF_SG_ADAPTIVE_RXT_TXT, + + /* + * The used WLAN legacy service period during active BT ACL link + * + * Range: 0 - 255 (ms) + */ + CONF_SG_PS_POLL_TIMEOUT, + + /* + * The used WLAN UPSD service period during active BT ACL link + * + * Range: 0 - 255 (ms) + */ + CONF_SG_UPSD_TIMEOUT, + + /* + * Configure the min and max time BT gains the antenna + * in WLAN Active / BT master EDR + * + * Range: 0 - 255 (ms) + */ + CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR, + CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR, + + /* + * The maximum time WLAN can gain the antenna for + * in WLAN Active / BT master EDR + * + * Range: 0 - 255 (ms) + */ + CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR, + + /* + * Configure the min and max time BT gains the antenna + * in WLAN Active / BT slave EDR + * + * Range: 0 - 255 (ms) + */ + CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR, + CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR, + + /* + * The maximum time WLAN can gain the antenna for + * in WLAN Active / BT slave EDR + * + * Range: 0 - 255 (ms) + */ + CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR, + + /* + * Configure the min and max time BT gains the antenna + * in WLAN Active / BT basic rate + * + * Range: 0 - 255 (ms) + */ + CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR, + CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR, + + /* + * The maximum time WLAN can gain the antenna for + * in WLAN Active / BT basic rate + * + * Range: 0 - 255 (ms) + */ + CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR, + + /* + * Compensation percentage of WLAN passive scan window if initiated + * during BT voice + * + * Range: 0 - 1000 (%) + */ + CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3, + + /* + * Compensation percentage of WLAN passive scan window if initiated + * during BT A2DP + * + * Range: 0 - 1000 (%) + */ + CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP, + + /* + * Fixed time ensured for BT traffic to gain the antenna during WLAN + * passive scan. + * + * Range: 0 - 1000 ms + */ + CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME, + + /* + * Fixed time ensured for WLAN traffic to gain the antenna during WLAN + * passive scan. + * + * Range: 0 - 1000 ms + */ + CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME, + + /* + * Number of consequent BT voice frames not interrupted by WLAN + * + * Range: 0 - 100 + */ + CONF_SG_HV3_MAX_SERVED, + + /* + * Protection time of the DHCP procedure. + * + * Range: 0 - 100000 (ms) + */ + CONF_SG_DHCP_TIME, + + /* + * Compensation percentage of WLAN active scan window if initiated + * during BT A2DP + * + * Range: 0 - 1000 (%) + */ + CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP, + CONF_SG_TEMP_PARAM_1, + CONF_SG_TEMP_PARAM_2, + CONF_SG_TEMP_PARAM_3, + CONF_SG_TEMP_PARAM_4, + CONF_SG_TEMP_PARAM_5, + CONF_SG_PARAMS_MAX, + CONF_SG_PARAMS_ALL = 0xff +}; + +struct conf_sg_settings { + u32 params[CONF_SG_PARAMS_MAX]; + u8 state; +}; + +enum conf_rx_queue_type { + CONF_RX_QUEUE_TYPE_LOW_PRIORITY, /* All except the high priority */ + CONF_RX_QUEUE_TYPE_HIGH_PRIORITY, /* Management and voice packets */ +}; + +struct conf_rx_settings { + /* + * The maximum amount of time, in TU, before the + * firmware discards the MSDU. + * + * Range: 0 - 0xFFFFFFFF + */ + u32 rx_msdu_life_time; + + /* + * Packet detection threshold in the PHY. + * + * FIXME: details unknown. + */ + u32 packet_detection_threshold; + + /* + * The longest time the STA will wait to receive traffic from the AP + * after a PS-poll has been transmitted. + * + * Range: 0 - 200000 + */ + 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. + * + * Range: 0 - 200000 + */ + u16 upsd_timeout; + + /* + * The number of octets in an MPDU, below which an RTS/CTS + * handshake is not performed. + * + * Range: 0 - 4096 + */ + u16 rts_threshold; + + /* + * The RX Clear Channel Assessment threshold in the PHY + * (the energy threshold). + * + * Range: ENABLE_ENERGY_D == 0x140A + * DISABLE_ENERGY_D == 0xFFEF + */ + u16 rx_cca_threshold; + + /* + * Occupied Rx mem-blocks number which requires interrupting the host + * (0 = no buffering, 0xffff = disabled). + * + * Range: u16 + */ + u16 irq_blk_threshold; + + /* + * Rx packets number which requires interrupting the host + * (0 = no buffering). + * + * Range: u16 + */ + u16 irq_pkt_threshold; + + /* + * Max time in msec the FW may delay RX-Complete interrupt. + * + * Range: 1 - 100 + */ + u16 irq_timeout; + + /* + * The RX queue type. + * + * Range: RX_QUEUE_TYPE_RX_LOW_PRIORITY, RX_QUEUE_TYPE_RX_HIGH_PRIORITY, + */ + u8 queue_type; +}; + +#define CONF_TX_MAX_RATE_CLASSES 8 + +#define CONF_TX_RATE_MASK_UNSPECIFIED 0 +#define CONF_TX_RATE_MASK_BASIC (CONF_HW_BIT_RATE_1MBPS | \ + CONF_HW_BIT_RATE_2MBPS) +#define CONF_TX_RATE_RETRY_LIMIT 10 + +struct conf_tx_rate_class { + + /* + * The rates enabled for this rate class. + * + * Range: CONF_HW_BIT_RATE_* bit mask + */ + u32 enabled_rates; + + /* + * The dot11 short retry limit used for TX retries. + * + * Range: u8 + */ + u8 short_retry_limit; + + /* + * The dot11 long retry limit used for TX retries. + * + * Range: u8 + */ + u8 long_retry_limit; + + /* + * Flags controlling the attributes of TX transmission. + * + * Range: bit 0: Truncate - when set, FW attempts to send a frame stop + * when the total valid per-rate attempts have + * been exhausted; otherwise transmissions + * will continue at the lowest available rate + * until the appropriate one of the + * short_retry_limit, long_retry_limit, + * dot11_max_transmit_msdu_life_time, or + * max_tx_life_time, is exhausted. + * 1: Preamble Override - indicates if the preamble type + * should be used in TX. + * 2: Preamble Type - the type of the preamble to be used by + * the policy (0 - long preamble, 1 - short preamble. + */ + u8 aflags; +}; + +#define CONF_TX_MAX_AC_COUNT 4 + +/* Slot number setting to start transmission at PIFS interval */ +#define CONF_TX_AIFS_PIFS 1 +/* Slot number setting to start transmission at DIFS interval normal + * DCF access */ +#define CONF_TX_AIFS_DIFS 2 + + +enum conf_tx_ac { + CONF_TX_AC_BE = 0, /* best effort / legacy */ + CONF_TX_AC_BK = 1, /* background */ + CONF_TX_AC_VI = 2, /* video */ + CONF_TX_AC_VO = 3, /* voice */ + CONF_TX_AC_CTS2SELF = 4, /* fictious AC, follows AC_VO */ + CONF_TX_AC_ANY_TID = 0x1f +}; + +struct conf_tx_ac_category { + /* + * The AC class identifier. + * + * Range: enum conf_tx_ac + */ + u8 ac; + + /* + * The contention window minimum size (in slots) for the access + * class. + * + * Range: u8 + */ + u8 cw_min; + + /* + * The contention window maximum size (in slots) for the access + * class. + * + * Range: u8 + */ + u16 cw_max; + + /* + * The AIF value (in slots) for the access class. + * + * Range: u8 + */ + u8 aifsn; + + /* + * The TX Op Limit (in microseconds) for the access class. + * + * Range: u16 + */ + u16 tx_op_limit; +}; + +#define CONF_TX_MAX_TID_COUNT 8 + +enum { + CONF_CHANNEL_TYPE_DCF = 0, /* DC/LEGACY*/ + CONF_CHANNEL_TYPE_EDCF = 1, /* EDCA*/ + CONF_CHANNEL_TYPE_HCCA = 2, /* HCCA*/ +}; + +enum { + CONF_PS_SCHEME_LEGACY = 0, + CONF_PS_SCHEME_UPSD_TRIGGER = 1, + CONF_PS_SCHEME_LEGACY_PSPOLL = 2, + CONF_PS_SCHEME_SAPSD = 3, +}; + +enum { + CONF_ACK_POLICY_LEGACY = 0, + CONF_ACK_POLICY_NO_ACK = 1, + CONF_ACK_POLICY_BLOCK = 2, +}; + + +struct conf_tx_tid { + u8 queue_id; + u8 channel_type; + u8 tsid; + u8 ps_scheme; + u8 ack_policy; + u32 apsd_conf[2]; +}; + +struct conf_tx_settings { + /* + * The TX ED value for TELEC Enable/Disable. + * + * Range: 0, 1 + */ + u8 tx_energy_detection; + + /* + * Configuration for rate classes for TX (currently only one + * rate class supported.) + */ + struct conf_tx_rate_class rc_conf; + + /* + * Configuration for access categories for TX rate control. + */ + u8 ac_conf_count; + struct conf_tx_ac_category ac_conf[CONF_TX_MAX_AC_COUNT]; + + /* + * Configuration for TID parameters. + */ + u8 tid_conf_count; + struct conf_tx_tid tid_conf[CONF_TX_MAX_TID_COUNT]; + + /* + * The TX fragmentation threshold. + * + * Range: u16 + */ + u16 frag_threshold; + + /* + * Max time in msec the FW may delay frame TX-Complete interrupt. + * + * Range: u16 + */ + u16 tx_compl_timeout; + + /* + * Completed TX packet count which requires to issue the TX-Complete + * interrupt. + * + * Range: u16 + */ + u16 tx_compl_threshold; + + /* + * The rate used for control messages and scanning on the 2.4GHz band + * + * Range: CONF_HW_BIT_RATE_* bit mask + */ + u32 basic_rate; + + /* + * The rate used for control messages and scanning on the 5GHz band + * + * Range: CONF_HW_BIT_RATE_* bit mask + */ + u32 basic_rate_5; +}; + +enum { + CONF_WAKE_UP_EVENT_BEACON = 0x01, /* Wake on every Beacon*/ + CONF_WAKE_UP_EVENT_DTIM = 0x02, /* Wake on every DTIM*/ + CONF_WAKE_UP_EVENT_N_DTIM = 0x04, /* Wake every Nth DTIM */ + CONF_WAKE_UP_EVENT_N_BEACONS = 0x08, /* Wake every Nth beacon */ + CONF_WAKE_UP_EVENT_BITS_MASK = 0x0F +}; + +#define CONF_MAX_BCN_FILT_IE_COUNT 32 + +#define CONF_BCN_RULE_PASS_ON_CHANGE BIT(0) +#define CONF_BCN_RULE_PASS_ON_APPEARANCE BIT(1) + +#define CONF_BCN_IE_OUI_LEN 3 +#define CONF_BCN_IE_VER_LEN 2 + +struct conf_bcn_filt_rule { + /* + * IE number to which to associate a rule. + * + * Range: u8 + */ + u8 ie; + + /* + * Rule to associate with the specific ie. + * + * Range: CONF_BCN_RULE_PASS_ON_* + */ + u8 rule; + + /* + * OUI for the vendor specifie IE (221) + */ + u8 oui[CONF_BCN_IE_OUI_LEN]; + + /* + * Type for the vendor specifie IE (221) + */ + u8 type; + + /* + * Version for the vendor specifie IE (221) + */ + u8 version[CONF_BCN_IE_VER_LEN]; +}; + +#define CONF_MAX_RSSI_SNR_TRIGGERS 8 + +enum { + CONF_TRIG_METRIC_RSSI_BEACON = 0, + CONF_TRIG_METRIC_RSSI_DATA, + CONF_TRIG_METRIC_SNR_BEACON, + CONF_TRIG_METRIC_SNR_DATA +}; + +enum { + CONF_TRIG_EVENT_TYPE_LEVEL = 0, + CONF_TRIG_EVENT_TYPE_EDGE +}; + +enum { + CONF_TRIG_EVENT_DIR_LOW = 0, + CONF_TRIG_EVENT_DIR_HIGH, + CONF_TRIG_EVENT_DIR_BIDIR +}; + +struct conf_sig_weights { + + /* + * RSSI from beacons average weight. + * + * Range: u8 + */ + u8 rssi_bcn_avg_weight; + + /* + * RSSI from data average weight. + * + * Range: u8 + */ + u8 rssi_pkt_avg_weight; + + /* + * SNR from beacons average weight. + * + * Range: u8 + */ + u8 snr_bcn_avg_weight; + + /* + * SNR from data average weight. + * + * Range: u8 + */ + u8 snr_pkt_avg_weight; +}; + +enum conf_bcn_filt_mode { + CONF_BCN_FILT_MODE_DISABLED = 0, + CONF_BCN_FILT_MODE_ENABLED = 1 +}; + +enum conf_bet_mode { + CONF_BET_MODE_DISABLE = 0, + CONF_BET_MODE_ENABLE = 1, +}; + +struct conf_conn_settings { + /* + * Firmware wakeup conditions configuration. The host may set only + * one bit. + * + * Range: CONF_WAKE_UP_EVENT_* + */ + u8 wake_up_event; + + /* + * Listen interval for beacons or Dtims. + * + * Range: 0 for beacon and Dtim wakeup + * 1-10 for x Dtims + * 1-255 for x beacons + */ + u8 listen_interval; + + /* + * Enable or disable the beacon filtering. + * + * Range: CONF_BCN_FILT_MODE_* + */ + enum conf_bcn_filt_mode bcn_filt_mode; + + /* + * Configure Beacon filter pass-thru rules. + */ + u8 bcn_filt_ie_count; + struct conf_bcn_filt_rule bcn_filt_ie[CONF_MAX_BCN_FILT_IE_COUNT]; + + /* + * The number of consequtive beacons to lose, before the firmware + * becomes out of synch. + * + * Range: u32 + */ + u32 synch_fail_thold; + + /* + * After out-of-synch, the number of TU's to wait without a further + * received beacon (or probe response) before issuing the BSS_EVENT_LOSE + * event. + * + * Range: u32 + */ + u32 bss_lose_timeout; + + /* + * Beacon receive timeout. + * + * Range: u32 + */ + u32 beacon_rx_timeout; + + /* + * Broadcast receive timeout. + * + * Range: u32 + */ + u32 broadcast_timeout; + + /* + * Enable/disable reception of broadcast packets in power save mode + * + * Range: 1 - enable, 0 - disable + */ + u8 rx_broadcast_in_ps; + + /* + * Consequtive PS Poll failures before sending event to driver + * + * Range: u8 + */ + u8 ps_poll_threshold; + + /* + * PS Poll failure recovery ACTIVE period length + * + * Range: u32 (ms) + */ + u32 ps_poll_recovery_period; + + /* + * Configuration of signal average weights. + */ + struct conf_sig_weights sig_weights; + + /* + * Specifies if beacon early termination procedure is enabled or + * disabled. + * + * Range: CONF_BET_MODE_* + */ + u8 bet_enable; + + /* + * Specifies the maximum number of consecutive beacons that may be + * early terminated. After this number is reached at least one full + * beacon must be correctly received in FW before beacon ET + * resumes. + * + * Range 0 - 255 + */ + u8 bet_max_consecutive; + + /* + * Specifies the maximum number of times to try PSM entry if it fails + * (if sending the appropriate null-func message fails.) + * + * Range 0 - 255 + */ + u8 psm_entry_retries; + + /* + * Specifies the maximum number of times to try transmit the PSM entry + * null-func frame for each PSM entry attempt + * + * Range 0 - 255 + */ + u8 psm_entry_nullfunc_retries; + + /* + * Specifies the time to linger in active mode after successfully + * transmitting the PSM entry null-func frame. + * + * Range 0 - 255 TU's + */ + u8 psm_entry_hangover_period; + + /* + * + * Specifies the interval of the connection keep-alive null-func + * frame in ms. + * + * Range: 1000 - 3600000 + */ + u32 keep_alive_interval; + + /* + * Maximum listen interval supported by the driver in units of beacons. + * + * Range: u16 + */ + u8 max_listen_interval; +}; + +enum { + CONF_REF_CLK_19_2_E, + CONF_REF_CLK_26_E, + CONF_REF_CLK_38_4_E, + CONF_REF_CLK_52_E +}; + +enum single_dual_band_enum { + CONF_SINGLE_BAND, + CONF_DUAL_BAND +}; + +#define CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE 15 +#define CONF_NUMBER_OF_SUB_BANDS_5 7 +#define CONF_NUMBER_OF_RATE_GROUPS 6 +#define CONF_NUMBER_OF_CHANNELS_2_4 14 +#define CONF_NUMBER_OF_CHANNELS_5 35 + +struct conf_radio_parms { + /* + * FEM parameter set to use + * + * Range: 0 or 1 + */ + u8 fem; +}; + +struct conf_itrim_settings { + /* enable dco itrim */ + u8 enable; + + /* moderation timeout in microsecs from the last TX */ + u32 timeout; +}; + +struct conf_pm_config_settings { + /* + * Host clock settling time + * + * Range: 0 - 30000 us + */ + u32 host_clk_settling_time; + + /* + * Host fast wakeup support + * + * Range: true, false + */ + bool host_fast_wakeup_support; +}; + +struct conf_roam_trigger_settings { + /* + * The minimum interval between two trigger events. + * + * Range: 0 - 60000 ms + */ + u16 trigger_pacing; + + /* + * The weight for rssi/beacon average calculation + * + * Range: 0 - 255 + */ + u8 avg_weight_rssi_beacon; + + /* + * The weight for rssi/data frame average calculation + * + * Range: 0 - 255 + */ + u8 avg_weight_rssi_data; + + /* + * The weight for snr/beacon average calculation + * + * Range: 0 - 255 + */ + u8 avg_weight_snr_beacon; + + /* + * The weight for snr/data frame average calculation + * + * Range: 0 - 255 + */ + u8 avg_weight_snr_data; +}; + +struct conf_scan_settings { + /* + * The minimum time to wait on each channel for active scans + * + * Range: 0 - 65536 tu + */ + u16 min_dwell_time_active; + + /* + * The maximum time to wait on each channel for active scans + * + * Range: 0 - 65536 tu + */ + u16 max_dwell_time_active; + + /* + * The maximum time to wait on each channel for passive scans + * + * Range: 0 - 65536 tu + */ + u16 min_dwell_time_passive; + + /* + * The maximum time to wait on each channel for passive scans + * + * Range: 0 - 65536 tu + */ + u16 max_dwell_time_passive; + + /* + * Number of probe requests to transmit on each active scan channel + * + * Range: u8 + */ + u16 num_probe_reqs; + +}; + +/* these are number of channels on the band divided by two, rounded up */ +#define CONF_TX_PWR_COMPENSATION_LEN_2 7 +#define CONF_TX_PWR_COMPENSATION_LEN_5 18 + +struct conf_rf_settings { + /* + * Per channel power compensation for 2.4GHz + * + * Range: s8 + */ + u8 tx_per_channel_power_compensation_2[CONF_TX_PWR_COMPENSATION_LEN_2]; + + /* + * Per channel power compensation for 5GHz + * + * Range: s8 + */ + u8 tx_per_channel_power_compensation_5[CONF_TX_PWR_COMPENSATION_LEN_5]; +}; + +struct conf_drv_settings { + struct conf_sg_settings sg; + struct conf_rx_settings rx; + struct conf_tx_settings tx; + struct conf_conn_settings conn; + struct conf_itrim_settings itrim; + struct conf_pm_config_settings pm_config; + struct conf_roam_trigger_settings roam_trigger; + struct conf_scan_settings scan; + struct conf_rf_settings rf; +}; + +#endif diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c new file mode 100644 index 0000000..dd71b7d --- /dev/null +++ b/drivers/net/wireless/wl12xx/debugfs.c @@ -0,0 +1,590 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 "wl12xx.h" +#include "acx.h" +#include "ps.h" +#include "io.h" + +/* ms */ +#define WL1271_DEBUGFS_STATS_LIFETIME 1000 + +/* debugfs macros idea from mac80211 */ +#define DEBUGFS_FORMAT_BUFFER_SIZE 100 +static int wl1271_format_buffer(char __user *userbuf, size_t count, + loff_t *ppos, char *fmt, ...) +{ + va_list args; + char buf[DEBUGFS_FORMAT_BUFFER_SIZE]; + int res; + + va_start(args, fmt); + res = vscnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + + return simple_read_from_buffer(userbuf, count, ppos, buf, res); +} + +#define DEBUGFS_READONLY_FILE(name, fmt, value...) \ +static ssize_t name## _read(struct file *file, char __user *userbuf, \ + size_t count, loff_t *ppos) \ +{ \ + struct wl1271 *wl = file->private_data; \ + return wl1271_format_buffer(userbuf, count, ppos, \ + fmt "\n", ##value); \ +} \ + \ +static const struct file_operations name## _ops = { \ + .read = name## _read, \ + .open = wl1271_open_file_generic, \ + .llseek = generic_file_llseek, \ +}; + +#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, fmt) \ +static ssize_t sub## _ ##name## _read(struct file *file, \ + char __user *userbuf, \ + size_t count, loff_t *ppos) \ +{ \ + struct wl1271 *wl = file->private_data; \ + \ + wl1271_debugfs_update_stats(wl); \ + \ + return wl1271_format_buffer(userbuf, count, ppos, fmt "\n", \ + wl->stats.fw_stats->sub.name); \ +} \ + \ +static const struct file_operations sub## _ ##name## _ops = { \ + .read = sub## _ ##name## _read, \ + .open = wl1271_open_file_generic, \ + .llseek = generic_file_llseek, \ +}; + +#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 wl1271_debugfs_update_stats(struct wl1271 *wl) +{ + int ret; + + mutex_lock(&wl->mutex); + + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out; + + if (wl->state == WL1271_STATE_ON && + time_after(jiffies, wl->stats.fw_stats_update + + msecs_to_jiffies(WL1271_DEBUGFS_STATS_LIFETIME))) { + wl1271_acx_statistics(wl, wl->stats.fw_stats); + wl->stats.fw_stats_update = jiffies; + } + + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); +} + +static int wl1271_open_file_generic(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +DEBUGFS_FWSTATS_FILE(tx, internal_desc_overflow, "%u"); + +DEBUGFS_FWSTATS_FILE(rx, out_of_mem, "%u"); +DEBUGFS_FWSTATS_FILE(rx, hdr_overflow, "%u"); +DEBUGFS_FWSTATS_FILE(rx, hw_stuck, "%u"); +DEBUGFS_FWSTATS_FILE(rx, dropped, "%u"); +DEBUGFS_FWSTATS_FILE(rx, fcs_err, "%u"); +DEBUGFS_FWSTATS_FILE(rx, xfr_hint_trig, "%u"); +DEBUGFS_FWSTATS_FILE(rx, path_reset, "%u"); +DEBUGFS_FWSTATS_FILE(rx, reset_counter, "%u"); + +DEBUGFS_FWSTATS_FILE(dma, rx_requested, "%u"); +DEBUGFS_FWSTATS_FILE(dma, rx_errors, "%u"); +DEBUGFS_FWSTATS_FILE(dma, tx_requested, "%u"); +DEBUGFS_FWSTATS_FILE(dma, tx_errors, "%u"); + +DEBUGFS_FWSTATS_FILE(isr, cmd_cmplt, "%u"); +DEBUGFS_FWSTATS_FILE(isr, fiqs, "%u"); +DEBUGFS_FWSTATS_FILE(isr, rx_headers, "%u"); +DEBUGFS_FWSTATS_FILE(isr, rx_mem_overflow, "%u"); +DEBUGFS_FWSTATS_FILE(isr, rx_rdys, "%u"); +DEBUGFS_FWSTATS_FILE(isr, irqs, "%u"); +DEBUGFS_FWSTATS_FILE(isr, tx_procs, "%u"); +DEBUGFS_FWSTATS_FILE(isr, decrypt_done, "%u"); +DEBUGFS_FWSTATS_FILE(isr, dma0_done, "%u"); +DEBUGFS_FWSTATS_FILE(isr, dma1_done, "%u"); +DEBUGFS_FWSTATS_FILE(isr, tx_exch_complete, "%u"); +DEBUGFS_FWSTATS_FILE(isr, commands, "%u"); +DEBUGFS_FWSTATS_FILE(isr, rx_procs, "%u"); +DEBUGFS_FWSTATS_FILE(isr, hw_pm_mode_changes, "%u"); +DEBUGFS_FWSTATS_FILE(isr, host_acknowledges, "%u"); +DEBUGFS_FWSTATS_FILE(isr, pci_pm, "%u"); +DEBUGFS_FWSTATS_FILE(isr, wakeups, "%u"); +DEBUGFS_FWSTATS_FILE(isr, low_rssi, "%u"); + +DEBUGFS_FWSTATS_FILE(wep, addr_key_count, "%u"); +DEBUGFS_FWSTATS_FILE(wep, default_key_count, "%u"); +/* skipping wep.reserved */ +DEBUGFS_FWSTATS_FILE(wep, key_not_found, "%u"); +DEBUGFS_FWSTATS_FILE(wep, decrypt_fail, "%u"); +DEBUGFS_FWSTATS_FILE(wep, packets, "%u"); +DEBUGFS_FWSTATS_FILE(wep, interrupt, "%u"); + +DEBUGFS_FWSTATS_FILE(pwr, ps_enter, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, elp_enter, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, missing_bcns, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, wake_on_host, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, wake_on_timer_exp, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, tx_with_ps, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, tx_without_ps, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, rcvd_beacons, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, power_save_off, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, enable_ps, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, disable_ps, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, fix_tsf_ps, "%u"); +/* skipping cont_miss_bcns_spread for now */ +DEBUGFS_FWSTATS_FILE(pwr, rcvd_awake_beacons, "%u"); + +DEBUGFS_FWSTATS_FILE(mic, rx_pkts, "%u"); +DEBUGFS_FWSTATS_FILE(mic, calc_failure, "%u"); + +DEBUGFS_FWSTATS_FILE(aes, encrypt_fail, "%u"); +DEBUGFS_FWSTATS_FILE(aes, decrypt_fail, "%u"); +DEBUGFS_FWSTATS_FILE(aes, encrypt_packets, "%u"); +DEBUGFS_FWSTATS_FILE(aes, decrypt_packets, "%u"); +DEBUGFS_FWSTATS_FILE(aes, encrypt_interrupt, "%u"); +DEBUGFS_FWSTATS_FILE(aes, decrypt_interrupt, "%u"); + +DEBUGFS_FWSTATS_FILE(event, heart_beat, "%u"); +DEBUGFS_FWSTATS_FILE(event, calibration, "%u"); +DEBUGFS_FWSTATS_FILE(event, rx_mismatch, "%u"); +DEBUGFS_FWSTATS_FILE(event, rx_mem_empty, "%u"); +DEBUGFS_FWSTATS_FILE(event, rx_pool, "%u"); +DEBUGFS_FWSTATS_FILE(event, oom_late, "%u"); +DEBUGFS_FWSTATS_FILE(event, phy_transmit_error, "%u"); +DEBUGFS_FWSTATS_FILE(event, tx_stuck, "%u"); + +DEBUGFS_FWSTATS_FILE(ps, pspoll_timeouts, "%u"); +DEBUGFS_FWSTATS_FILE(ps, upsd_timeouts, "%u"); +DEBUGFS_FWSTATS_FILE(ps, upsd_max_sptime, "%u"); +DEBUGFS_FWSTATS_FILE(ps, upsd_max_apturn, "%u"); +DEBUGFS_FWSTATS_FILE(ps, pspoll_max_apturn, "%u"); +DEBUGFS_FWSTATS_FILE(ps, pspoll_utilization, "%u"); +DEBUGFS_FWSTATS_FILE(ps, upsd_utilization, "%u"); + +DEBUGFS_FWSTATS_FILE(rxpipe, rx_prep_beacon_drop, "%u"); +DEBUGFS_FWSTATS_FILE(rxpipe, descr_host_int_trig_rx_data, "%u"); +DEBUGFS_FWSTATS_FILE(rxpipe, beacon_buffer_thres_host_int_trig_rx_data, "%u"); +DEBUGFS_FWSTATS_FILE(rxpipe, missed_beacon_host_int_trig_rx_data, "%u"); +DEBUGFS_FWSTATS_FILE(rxpipe, tx_xfr_host_int_trig_rx_data, "%u"); + +DEBUGFS_READONLY_FILE(retry_count, "%u", wl->stats.retry_count); +DEBUGFS_READONLY_FILE(excessive_retries, "%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 wl1271 *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 = wl1271_open_file_generic, + .llseek = default_llseek, +}; + +static ssize_t gpio_power_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wl1271 *wl = file->private_data; + bool state = test_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); + + int res; + char buf[10]; + + res = scnprintf(buf, sizeof(buf), "%d\n", state); + + return simple_read_from_buffer(user_buf, count, ppos, buf, res); +} + +static ssize_t gpio_power_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wl1271 *wl = file->private_data; + char buf[10]; + size_t len; + unsigned long value; + int ret; + + mutex_lock(&wl->mutex); + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) { + ret = -EFAULT; + goto out; + } + buf[len] = '\0'; + + ret = strict_strtoul(buf, 0, &value); + if (ret < 0) { + wl1271_warning("illegal value in gpio_power"); + goto out; + } + + if (value) + wl1271_power_on(wl); + else + wl1271_power_off(wl); + +out: + mutex_unlock(&wl->mutex); + return count; +} + +static const struct file_operations gpio_power_ops = { + .read = gpio_power_read, + .write = gpio_power_write, + .open = wl1271_open_file_generic, + .llseek = default_llseek, +}; + +static void wl1271_debugfs_delete_files(struct wl1271 *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(retry_count); + DEBUGFS_DEL(excessive_retries); + + DEBUGFS_DEL(gpio_power); +} + +static int wl1271_debugfs_add_files(struct wl1271 *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(retry_count, wl->debugfs.rootdir); + DEBUGFS_ADD(excessive_retries, wl->debugfs.rootdir); + + DEBUGFS_ADD(gpio_power, wl->debugfs.rootdir); + +out: + if (ret < 0) + wl1271_debugfs_delete_files(wl); + + return ret; +} + +void wl1271_debugfs_reset(struct wl1271 *wl) +{ + memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats)); + wl->stats.retry_count = 0; + wl->stats.excessive_retries = 0; +} + +int wl1271_debugfs_init(struct wl1271 *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 = wl1271_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 wl1271_debugfs_exit(struct wl1271 *wl) +{ + wl1271_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/debugfs.h b/drivers/net/wireless/wl12xx/debugfs.h new file mode 100644 index 0000000..254c5b2 --- /dev/null +++ b/drivers/net/wireless/wl12xx/debugfs.h @@ -0,0 +1,33 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 __DEBUGFS_H__ +#define __DEBUGFS_H__ + +#include "wl12xx.h" + +int wl1271_debugfs_init(struct wl1271 *wl); +void wl1271_debugfs_exit(struct wl1271 *wl); +void wl1271_debugfs_reset(struct wl1271 *wl); + +#endif /* WL1271_DEBUGFS_H */ diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c new file mode 100644 index 0000000..f9146f5 --- /dev/null +++ b/drivers/net/wireless/wl12xx/event.c @@ -0,0 +1,293 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 "wl12xx.h" +#include "reg.h" +#include "io.h" +#include "event.h" +#include "ps.h" +#include "scan.h" +#include "wl12xx_80211.h" + +void wl1271_pspoll_work(struct work_struct *work) +{ + struct delayed_work *dwork; + struct wl1271 *wl; + + dwork = container_of(work, struct delayed_work, work); + wl = container_of(dwork, struct wl1271, pspoll_work); + + wl1271_debug(DEBUG_EVENT, "pspoll work"); + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state == WL1271_STATE_OFF)) + goto out; + + if (!test_and_clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags)) + goto out; + + if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) + goto out; + + /* + * if we end up here, then we were in powersave when the pspoll + * delivery failure occurred, and no-one changed state since, so + * we should go back to powersave. + */ + wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, wl->basic_rate, true); + +out: + mutex_unlock(&wl->mutex); +}; + +static void wl1271_event_pspoll_delivery_fail(struct wl1271 *wl) +{ + int delay = wl->conf.conn.ps_poll_recovery_period; + int ret; + + wl->ps_poll_failures++; + if (wl->ps_poll_failures == 1) + wl1271_info("AP with dysfunctional ps-poll, " + "trying to work around it."); + + /* force active mode receive data from the AP */ + if (test_bit(WL1271_FLAG_PSM, &wl->flags)) { + ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, + wl->basic_rate, true); + if (ret < 0) + return; + set_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags); + ieee80211_queue_delayed_work(wl->hw, &wl->pspoll_work, + msecs_to_jiffies(delay)); + } + + /* + * If already in active mode, lets we should be getting data from + * the AP right away. If we enter PSM too fast after this, and data + * remains on the AP, we will get another event like this, and we'll + * go into active once more. + */ +} + +static int wl1271_event_ps_report(struct wl1271 *wl, + struct event_mailbox *mbox, + bool *beacon_loss) +{ + int ret = 0; + u32 total_retries = wl->conf.conn.psm_entry_retries; + + wl1271_debug(DEBUG_EVENT, "ps_status: 0x%x", mbox->ps_status); + + switch (mbox->ps_status) { + case EVENT_ENTER_POWER_SAVE_FAIL: + wl1271_debug(DEBUG_PSM, "PSM entry failed"); + + if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) { + /* remain in active mode */ + wl->psm_entry_retry = 0; + break; + } + + if (wl->psm_entry_retry < total_retries) { + wl->psm_entry_retry++; + ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, + wl->basic_rate, true); + } else { + wl1271_info("No ack to nullfunc from AP."); + wl->psm_entry_retry = 0; + *beacon_loss = true; + } + break; + case EVENT_ENTER_POWER_SAVE_SUCCESS: + wl->psm_entry_retry = 0; + + /* enable beacon filtering */ + ret = wl1271_acx_beacon_filter_opt(wl, true); + if (ret < 0) + break; + + /* enable beacon early termination */ + ret = wl1271_acx_bet_enable(wl, true); + if (ret < 0) + break; + + /* go to extremely low power mode */ + wl1271_ps_elp_sleep(wl); + break; + case EVENT_EXIT_POWER_SAVE_FAIL: + wl1271_debug(DEBUG_PSM, "PSM exit failed"); + + if (test_bit(WL1271_FLAG_PSM, &wl->flags)) { + wl->psm_entry_retry = 0; + break; + } + + /* make sure the firmware goes to active mode - the frame to + be sent next will indicate to the AP, that we are active. */ + ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, + wl->basic_rate, false); + break; + case EVENT_EXIT_POWER_SAVE_SUCCESS: + default: + break; + } + + return ret; +} + +static void wl1271_event_rssi_trigger(struct wl1271 *wl, + struct event_mailbox *mbox) +{ + enum nl80211_cqm_rssi_threshold_event event; + s8 metric = mbox->rssi_snr_trigger_metric[0]; + + wl1271_debug(DEBUG_EVENT, "RSSI trigger metric: %d", metric); + + if (metric <= wl->rssi_thold) + event = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW; + else + event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH; + + if (event != wl->last_rssi_event) + ieee80211_cqm_rssi_notify(wl->vif, event, GFP_KERNEL); + wl->last_rssi_event = event; +} + +static void wl1271_event_mbox_dump(struct event_mailbox *mbox) +{ + wl1271_debug(DEBUG_EVENT, "MBOX DUMP:"); + wl1271_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector); + wl1271_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask); +} + +static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) +{ + int ret; + u32 vector; + bool beacon_loss = false; + + wl1271_event_mbox_dump(mbox); + + vector = le32_to_cpu(mbox->events_vector); + vector &= ~(le32_to_cpu(mbox->events_mask)); + wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector); + + if (vector & SCAN_COMPLETE_EVENT_ID) { + wl1271_debug(DEBUG_EVENT, "status: 0x%x", + mbox->scheduled_scan_status); + + wl1271_scan_stm(wl); + } + + /* disable dynamic PS when requested by the firmware */ + if (vector & SOFT_GEMINI_SENSE_EVENT_ID && + wl->bss_type == BSS_TYPE_STA_BSS) { + if (mbox->soft_gemini_sense_info) + ieee80211_disable_dyn_ps(wl->vif); + else + ieee80211_enable_dyn_ps(wl->vif); + } + + /* + * The BSS_LOSE_EVENT_ID is only needed while psm (and hence beacon + * filtering) is enabled. Without PSM, the stack will receive all + * beacons and can detect beacon loss by itself. + * + * As there's possibility that the driver disables PSM before receiving + * BSS_LOSE_EVENT, beacon loss has to be reported to the stack. + * + */ + if (vector & BSS_LOSE_EVENT_ID) { + wl1271_info("Beacon loss detected."); + + /* indicate to the stack, that beacons have been lost */ + beacon_loss = true; + } + + if (vector & PS_REPORT_EVENT_ID) { + wl1271_debug(DEBUG_EVENT, "PS_REPORT_EVENT"); + ret = wl1271_event_ps_report(wl, mbox, &beacon_loss); + if (ret < 0) + return ret; + } + + if (vector & PSPOLL_DELIVERY_FAILURE_EVENT_ID) + wl1271_event_pspoll_delivery_fail(wl); + + if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) { + wl1271_debug(DEBUG_EVENT, "RSSI_SNR_TRIGGER_0_EVENT"); + if (wl->vif) + wl1271_event_rssi_trigger(wl, mbox); + } + + if (wl->vif && beacon_loss) + ieee80211_connection_loss(wl->vif); + + return 0; +} + +int wl1271_event_unmask(struct wl1271 *wl) +{ + int ret; + + ret = wl1271_acx_event_mbox_mask(wl, ~(wl->event_mask)); + if (ret < 0) + return ret; + + return 0; +} + +void wl1271_event_mbox_config(struct wl1271 *wl) +{ + wl->mbox_ptr[0] = wl1271_read32(wl, REG_EVENT_MAILBOX_PTR); + wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox); + + wl1271_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x", + wl->mbox_ptr[0], wl->mbox_ptr[1]); +} + +int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num) +{ + struct event_mailbox mbox; + int ret; + + wl1271_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num); + + if (mbox_num > 1) + return -EINVAL; + + /* first we read the mbox descriptor */ + wl1271_read(wl, wl->mbox_ptr[mbox_num], &mbox, + sizeof(struct event_mailbox), false); + + /* process the descriptor */ + ret = wl1271_event_process(wl, &mbox); + if (ret < 0) + return ret; + + /* then we let the firmware know it can go on...*/ + wl1271_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK); + + return 0; +} diff --git a/drivers/net/wireless/wl12xx/event.h b/drivers/net/wireless/wl12xx/event.h new file mode 100644 index 0000000..6cce014 --- /dev/null +++ b/drivers/net/wireless/wl12xx/event.h @@ -0,0 +1,126 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 __EVENT_H__ +#define __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 { + RSSI_SNR_TRIGGER_0_EVENT_ID = BIT(0), + RSSI_SNR_TRIGGER_1_EVENT_ID = BIT(1), + RSSI_SNR_TRIGGER_2_EVENT_ID = BIT(2), + RSSI_SNR_TRIGGER_3_EVENT_ID = BIT(3), + RSSI_SNR_TRIGGER_4_EVENT_ID = BIT(4), + RSSI_SNR_TRIGGER_5_EVENT_ID = BIT(5), + RSSI_SNR_TRIGGER_6_EVENT_ID = BIT(6), + RSSI_SNR_TRIGGER_7_EVENT_ID = BIT(7), + MEASUREMENT_START_EVENT_ID = BIT(8), + MEASUREMENT_COMPLETE_EVENT_ID = BIT(9), + SCAN_COMPLETE_EVENT_ID = BIT(10), + SCHEDULED_SCAN_COMPLETE_EVENT_ID = BIT(11), + AP_DISCOVERY_COMPLETE_EVENT_ID = BIT(12), + PS_REPORT_EVENT_ID = BIT(13), + PSPOLL_DELIVERY_FAILURE_EVENT_ID = BIT(14), + DISCONNECT_EVENT_COMPLETE_ID = BIT(15), + JOIN_EVENT_COMPLETE_ID = BIT(16), + CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(17), + BSS_LOSE_EVENT_ID = BIT(18), + REGAINED_BSS_EVENT_ID = BIT(19), + ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID = BIT(20), + SOFT_GEMINI_SENSE_EVENT_ID = BIT(22), + SOFT_GEMINI_PREDICTION_EVENT_ID = BIT(23), + SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24), + PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(25), + DBG_EVENT_ID = BIT(26), + HEALTH_CHECK_REPLY_EVENT_ID = BIT(27), + PERIODIC_SCAN_COMPLETE_EVENT_ID = BIT(28), + PERIODIC_SCAN_REPORT_EVENT_ID = BIT(29), + BA_SESSION_TEAR_DOWN_EVENT_ID = BIT(30), + EVENT_MBOX_ALL_EVENT_ID = 0x7fffffff, +}; + +enum { + EVENT_ENTER_POWER_SAVE_FAIL = 0, + EVENT_ENTER_POWER_SAVE_SUCCESS, + EVENT_EXIT_POWER_SAVE_FAIL, + EVENT_EXIT_POWER_SAVE_SUCCESS, +}; + +struct event_debug_report { + u8 debug_event_id; + u8 num_params; + __le16 pad; + __le32 report_1; + __le32 report_2; + __le32 report_3; +} __packed; + +#define NUM_OF_RSSI_SNR_TRIGGERS 8 + +struct event_mailbox { + __le32 events_vector; + __le32 events_mask; + __le32 reserved_1; + __le32 reserved_2; + + u8 dbg_event_id; + u8 num_relevant_params; + __le16 reserved_3; + __le32 event_report_p1; + __le32 event_report_p2; + __le32 event_report_p3; + + u8 number_of_scan_results; + u8 scan_tag; + u8 reserved_4[2]; + __le32 compl_scheduled_scan_status; + + __le16 scheduled_scan_attended_channels; + u8 soft_gemini_sense_info; + u8 soft_gemini_protective_info; + s8 rssi_snr_trigger_metric[NUM_OF_RSSI_SNR_TRIGGERS]; + u8 channel_switch_status; + u8 scheduled_scan_status; + u8 ps_status; + + u8 reserved_5[29]; +} __packed; + +int wl1271_event_unmask(struct wl1271 *wl); +void wl1271_event_mbox_config(struct wl1271 *wl); +int wl1271_event_handle(struct wl1271 *wl, u8 mbox); +void wl1271_pspoll_work(struct work_struct *work); + +#endif diff --git a/drivers/net/wireless/wl12xx/ini.h b/drivers/net/wireless/wl12xx/ini.h new file mode 100644 index 0000000..c330a25 --- /dev/null +++ b/drivers/net/wireless/wl12xx/ini.h @@ -0,0 +1,123 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2010 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 __INI_H__ +#define __INI_H__ + +#define WL1271_INI_MAX_SMART_REFLEX_PARAM 16 + +struct wl1271_ini_general_params { + u8 ref_clock; + u8 settling_time; + u8 clk_valid_on_wakeup; + u8 dc2dc_mode; + u8 dual_mode_select; + u8 tx_bip_fem_auto_detect; + u8 tx_bip_fem_manufacturer; + u8 general_settings; + u8 sr_state; + u8 srf1[WL1271_INI_MAX_SMART_REFLEX_PARAM]; + u8 srf2[WL1271_INI_MAX_SMART_REFLEX_PARAM]; + u8 srf3[WL1271_INI_MAX_SMART_REFLEX_PARAM]; +} __packed; + +#define WL1271_INI_RSSI_PROCESS_COMPENS_SIZE 15 + +struct wl1271_ini_band_params_2 { + u8 rx_trace_insertion_loss; + u8 tx_trace_loss; + u8 rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE]; +} __packed; + +#define WL1271_INI_RATE_GROUP_COUNT 6 +#define WL1271_INI_CHANNEL_COUNT_2 14 + +struct wl1271_ini_fem_params_2 { + __le16 tx_bip_ref_pd_voltage; + u8 tx_bip_ref_power; + u8 tx_bip_ref_offset; + u8 tx_per_rate_pwr_limits_normal[WL1271_INI_RATE_GROUP_COUNT]; + u8 tx_per_rate_pwr_limits_degraded[WL1271_INI_RATE_GROUP_COUNT]; + u8 tx_per_rate_pwr_limits_extreme[WL1271_INI_RATE_GROUP_COUNT]; + u8 tx_per_chan_pwr_limits_11b[WL1271_INI_CHANNEL_COUNT_2]; + u8 tx_per_chan_pwr_limits_ofdm[WL1271_INI_CHANNEL_COUNT_2]; + u8 tx_pd_vs_rate_offsets[WL1271_INI_RATE_GROUP_COUNT]; + u8 tx_ibias[WL1271_INI_RATE_GROUP_COUNT]; + u8 rx_fem_insertion_loss; + u8 degraded_low_to_normal_thr; + u8 normal_to_degraded_high_thr; +} __packed; + +#define WL1271_INI_CHANNEL_COUNT_5 35 +#define WL1271_INI_SUB_BAND_COUNT_5 7 + +struct wl1271_ini_band_params_5 { + u8 rx_trace_insertion_loss[WL1271_INI_SUB_BAND_COUNT_5]; + u8 tx_trace_loss[WL1271_INI_SUB_BAND_COUNT_5]; + u8 rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE]; +} __packed; + +struct wl1271_ini_fem_params_5 { + __le16 tx_bip_ref_pd_voltage[WL1271_INI_SUB_BAND_COUNT_5]; + u8 tx_bip_ref_power[WL1271_INI_SUB_BAND_COUNT_5]; + u8 tx_bip_ref_offset[WL1271_INI_SUB_BAND_COUNT_5]; + u8 tx_per_rate_pwr_limits_normal[WL1271_INI_RATE_GROUP_COUNT]; + u8 tx_per_rate_pwr_limits_degraded[WL1271_INI_RATE_GROUP_COUNT]; + u8 tx_per_rate_pwr_limits_extreme[WL1271_INI_RATE_GROUP_COUNT]; + u8 tx_per_chan_pwr_limits_ofdm[WL1271_INI_CHANNEL_COUNT_5]; + u8 tx_pd_vs_rate_offsets[WL1271_INI_RATE_GROUP_COUNT]; + u8 tx_ibias[WL1271_INI_RATE_GROUP_COUNT]; + u8 rx_fem_insertion_loss[WL1271_INI_SUB_BAND_COUNT_5]; + u8 degraded_low_to_normal_thr; + u8 normal_to_degraded_high_thr; +} __packed; + + +/* NVS data structure */ +#define WL1271_INI_NVS_SECTION_SIZE 468 +#define WL1271_INI_FEM_MODULE_COUNT 2 + +#define WL1271_INI_LEGACY_NVS_FILE_SIZE 800 + +struct wl1271_nvs_file { + /* NVS section */ + u8 nvs[WL1271_INI_NVS_SECTION_SIZE]; + + /* INI section */ + struct wl1271_ini_general_params general_params; + u8 padding1; + struct wl1271_ini_band_params_2 stat_radio_params_2; + u8 padding2; + struct { + struct wl1271_ini_fem_params_2 params; + u8 padding; + } dyn_radio_params_2[WL1271_INI_FEM_MODULE_COUNT]; + struct wl1271_ini_band_params_5 stat_radio_params_5; + u8 padding3; + struct { + struct wl1271_ini_fem_params_5 params; + u8 padding; + } dyn_radio_params_5[WL1271_INI_FEM_MODULE_COUNT]; +} __packed; + +#endif diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c new file mode 100644 index 0000000..492edc0 --- /dev/null +++ b/drivers/net/wireless/wl12xx/init.c @@ -0,0 +1,369 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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" + +static int wl1271_init_hwenc_config(struct wl1271 *wl) +{ + int ret; + + ret = wl1271_acx_feature_cfg(wl); + if (ret < 0) { + wl1271_warning("couldn't set feature config"); + return ret; + } + + ret = wl1271_cmd_set_default_wep_key(wl, wl->default_key); + if (ret < 0) { + wl1271_warning("couldn't set default key"); + return ret; + } + + return 0; +} + +int wl1271_init_templates_config(struct wl1271 *wl) +{ + int ret, i; + size_t size; + + /* send empty templates for fw memory reservation */ + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL, + sizeof(struct wl12xx_probe_req_template), + 0, WL1271_RATE_AUTOMATIC); + if (ret < 0) + return ret; + + size = sizeof(struct wl12xx_probe_req_template); + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, + NULL, size, 0, + WL1271_RATE_AUTOMATIC); + if (ret < 0) + return ret; + + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, NULL, + sizeof(struct wl12xx_null_data_template), + 0, WL1271_RATE_AUTOMATIC); + if (ret < 0) + return ret; + + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, NULL, + sizeof(struct wl12xx_ps_poll_template), + 0, WL1271_RATE_AUTOMATIC); + if (ret < 0) + return ret; + + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, NULL, + sizeof + (struct wl12xx_qos_null_data_template), + 0, WL1271_RATE_AUTOMATIC); + if (ret < 0) + return ret; + + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE, NULL, + sizeof + (struct wl12xx_probe_resp_template), + 0, WL1271_RATE_AUTOMATIC); + if (ret < 0) + return ret; + + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, NULL, + sizeof + (struct wl12xx_beacon_template), + 0, WL1271_RATE_AUTOMATIC); + if (ret < 0) + return ret; + + for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) { + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV, NULL, + WL1271_CMD_TEMPL_MAX_SIZE, i, + WL1271_RATE_AUTOMATIC); + if (ret < 0) + return ret; + } + + return 0; +} + +static int wl1271_init_rx_config(struct wl1271 *wl, u32 config, u32 filter) +{ + int ret; + + ret = wl1271_acx_rx_msdu_life_time(wl); + if (ret < 0) + return ret; + + ret = wl1271_acx_rx_config(wl, config, filter); + if (ret < 0) + return ret; + + return 0; +} + +int wl1271_init_phy_config(struct wl1271 *wl) +{ + int ret; + + ret = wl1271_acx_pd_threshold(wl); + if (ret < 0) + return ret; + + ret = wl1271_acx_slot(wl, DEFAULT_SLOT_TIME); + if (ret < 0) + return ret; + + ret = wl1271_acx_group_address_tbl(wl, true, NULL, 0); + if (ret < 0) + return ret; + + ret = wl1271_acx_service_period_timeout(wl); + if (ret < 0) + return ret; + + ret = wl1271_acx_rts_threshold(wl, wl->conf.rx.rts_threshold); + if (ret < 0) + return ret; + + return 0; +} + +static int wl1271_init_beacon_filter(struct wl1271 *wl) +{ + int ret; + + /* disable beacon filtering at this stage */ + ret = wl1271_acx_beacon_filter_opt(wl, false); + if (ret < 0) + return ret; + + ret = wl1271_acx_beacon_filter_table(wl); + if (ret < 0) + return ret; + + return 0; +} + +int wl1271_init_pta(struct wl1271 *wl) +{ + int ret; + + ret = wl1271_acx_sg_cfg(wl); + if (ret < 0) + return ret; + + ret = wl1271_acx_sg_enable(wl, wl->sg_enabled); + if (ret < 0) + return ret; + + return 0; +} + +int wl1271_init_energy_detection(struct wl1271 *wl) +{ + int ret; + + ret = wl1271_acx_cca_threshold(wl); + if (ret < 0) + return ret; + + return 0; +} + +static int wl1271_init_beacon_broadcast(struct wl1271 *wl) +{ + int ret; + + ret = wl1271_acx_bcn_dtim_options(wl); + if (ret < 0) + return ret; + + return 0; +} + +int wl1271_hw_init(struct wl1271 *wl) +{ + struct conf_tx_ac_category *conf_ac; + struct conf_tx_tid *conf_tid; + int ret, i; + + ret = wl1271_cmd_general_parms(wl); + if (ret < 0) + return ret; + + ret = wl1271_cmd_radio_parms(wl); + if (ret < 0) + return ret; + + ret = wl1271_cmd_ext_radio_parms(wl); + if (ret < 0) + return ret; + + /* Template settings */ + ret = wl1271_init_templates_config(wl); + if (ret < 0) + return ret; + + /* Default memory configuration */ + ret = wl1271_acx_init_mem_config(wl); + if (ret < 0) + return ret; + + /* RX config */ + ret = wl1271_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_memmap; + + /* PHY layer config */ + ret = wl1271_init_phy_config(wl); + if (ret < 0) + goto out_free_memmap; + + ret = wl1271_acx_dco_itrim_params(wl); + if (ret < 0) + goto out_free_memmap; + + /* Initialize connection monitoring thresholds */ + ret = wl1271_acx_conn_monit_params(wl, false); + if (ret < 0) + goto out_free_memmap; + + /* Beacon filtering */ + ret = wl1271_init_beacon_filter(wl); + if (ret < 0) + goto out_free_memmap; + + /* Configure TX patch complete interrupt behavior */ + ret = wl1271_acx_tx_config_options(wl); + if (ret < 0) + goto out_free_memmap; + + /* RX complete interrupt pacing */ + ret = wl1271_acx_init_rx_interrupt(wl); + if (ret < 0) + goto out_free_memmap; + + /* Bluetooth WLAN coexistence */ + ret = wl1271_init_pta(wl); + if (ret < 0) + goto out_free_memmap; + + /* Energy detection */ + ret = wl1271_init_energy_detection(wl); + if (ret < 0) + goto out_free_memmap; + + /* Beacons and boradcast settings */ + ret = wl1271_init_beacon_broadcast(wl); + if (ret < 0) + goto out_free_memmap; + + /* Default fragmentation threshold */ + ret = wl1271_acx_frag_threshold(wl); + if (ret < 0) + goto out_free_memmap; + + /* Default TID/AC configuration */ + BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count); + for (i = 0; i < wl->conf.tx.tid_conf_count; i++) { + conf_ac = &wl->conf.tx.ac_conf[i]; + ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min, + conf_ac->cw_max, conf_ac->aifsn, + conf_ac->tx_op_limit); + if (ret < 0) + goto out_free_memmap; + + conf_tid = &wl->conf.tx.tid_conf[i]; + ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id, + conf_tid->channel_type, + conf_tid->tsid, + conf_tid->ps_scheme, + conf_tid->ack_policy, + conf_tid->apsd_conf[0], + conf_tid->apsd_conf[1]); + if (ret < 0) + goto out_free_memmap; + } + + /* Configure TX rate classes */ + ret = wl1271_acx_rate_policies(wl); + if (ret < 0) + goto out_free_memmap; + + /* Enable data path */ + ret = wl1271_cmd_data_path(wl, 1); + if (ret < 0) + goto out_free_memmap; + + /* Configure for ELP power saving */ + ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP); + if (ret < 0) + goto out_free_memmap; + + /* Configure HW encryption */ + ret = wl1271_init_hwenc_config(wl); + if (ret < 0) + goto out_free_memmap; + + /* configure PM */ + ret = wl1271_acx_pm_config(wl); + if (ret < 0) + goto out_free_memmap; + + /* disable all keep-alive templates */ + for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) { + ret = wl1271_acx_keep_alive_config(wl, i, + ACX_KEEP_ALIVE_TPL_INVALID); + if (ret < 0) + goto out_free_memmap; + } + + /* disable the keep-alive feature */ + ret = wl1271_acx_keep_alive_mode(wl, false); + if (ret < 0) + goto out_free_memmap; + + /* Configure rssi/snr averaging weights */ + ret = wl1271_acx_rssi_snr_avg_weights(wl); + if (ret < 0) + goto out_free_memmap; + + return 0; + + out_free_memmap: + kfree(wl->target_mem_map); + wl->target_mem_map = NULL; + + return ret; +} diff --git a/drivers/net/wireless/wl12xx/init.h b/drivers/net/wireless/wl12xx/init.h new file mode 100644 index 0000000..7762421 --- /dev/null +++ b/drivers/net/wireless/wl12xx/init.h @@ -0,0 +1,36 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 __INIT_H__ +#define __INIT_H__ + +#include "wl12xx.h" + +int wl1271_hw_init_power_auth(struct wl1271 *wl); +int wl1271_init_templates_config(struct wl1271 *wl); +int wl1271_init_phy_config(struct wl1271 *wl); +int wl1271_init_pta(struct wl1271 *wl); +int wl1271_init_energy_detection(struct wl1271 *wl); +int wl1271_hw_init(struct wl1271 *wl); + +#endif diff --git a/drivers/net/wireless/wl12xx/io.c b/drivers/net/wireless/wl12xx/io.c new file mode 100644 index 0000000..35c2f1a --- /dev/null +++ b/drivers/net/wireless/wl12xx/io.c @@ -0,0 +1,170 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2008-2010 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 "wl12xx.h" +#include "wl12xx_80211.h" +#include "io.h" + +#define OCP_CMD_LOOP 32 + +#define OCP_CMD_WRITE 0x1 +#define OCP_CMD_READ 0x2 + +#define OCP_READY_MASK BIT(18) +#define OCP_STATUS_MASK (BIT(16) | BIT(17)) + +#define OCP_STATUS_NO_RESP 0x00000 +#define OCP_STATUS_OK 0x10000 +#define OCP_STATUS_REQ_FAILED 0x20000 +#define OCP_STATUS_RESP_ERROR 0x30000 + +void wl1271_disable_interrupts(struct wl1271 *wl) +{ + wl->if_ops->disable_irq(wl); +} + +void wl1271_enable_interrupts(struct wl1271 *wl) +{ + wl->if_ops->enable_irq(wl); +} + +/* Set the SPI partitions to access the chip addresses + * + * To simplify driver code, a fixed (virtual) memory map is defined for + * register and memory addresses. Because in the chipset, in different stages + * of operation, those addresses will move around, an address translation + * mechanism is required. + * + * There are four partitions (three memory and one register partition), + * which are mapped to two different areas of the hardware memory. + * + * Virtual address + * space + * + * | | + * ...+----+--> mem.start + * Physical address ... | | + * space ... | | [PART_0] + * ... | | + * 00000000 <--+----+... ...+----+--> mem.start + mem.size + * | | ... | | + * |MEM | ... | | + * | | ... | | + * mem.size <--+----+... | | {unused area) + * | | ... | | + * |REG | ... | | + * mem.size | | ... | | + * + <--+----+... ...+----+--> reg.start + * reg.size | | ... | | + * |MEM2| ... | | [PART_1] + * | | ... | | + * ...+----+--> reg.start + reg.size + * | | + * + */ +int wl1271_set_partition(struct wl1271 *wl, + struct wl1271_partition_set *p) +{ + /* copy partition info */ + memcpy(&wl->part, p, sizeof(*p)); + + wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + p->mem.start, p->mem.size); + wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + p->reg.start, p->reg.size); + wl1271_debug(DEBUG_SPI, "mem2_start %08X mem2_size %08X", + p->mem2.start, p->mem2.size); + wl1271_debug(DEBUG_SPI, "mem3_start %08X mem3_size %08X", + p->mem3.start, p->mem3.size); + + /* write partition info to the chipset */ + wl1271_raw_write32(wl, HW_PART0_START_ADDR, p->mem.start); + wl1271_raw_write32(wl, HW_PART0_SIZE_ADDR, p->mem.size); + wl1271_raw_write32(wl, HW_PART1_START_ADDR, p->reg.start); + wl1271_raw_write32(wl, HW_PART1_SIZE_ADDR, p->reg.size); + wl1271_raw_write32(wl, HW_PART2_START_ADDR, p->mem2.start); + wl1271_raw_write32(wl, HW_PART2_SIZE_ADDR, p->mem2.size); + wl1271_raw_write32(wl, HW_PART3_START_ADDR, p->mem3.start); + + return 0; +} + +void wl1271_io_reset(struct wl1271 *wl) +{ + wl->if_ops->reset(wl); +} + +void wl1271_io_init(struct wl1271 *wl) +{ + wl->if_ops->init(wl); +} + +void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val) +{ + /* write address >> 1 + 0x30000 to OCP_POR_CTR */ + addr = (addr >> 1) + 0x30000; + wl1271_write32(wl, OCP_POR_CTR, addr); + + /* write value to OCP_POR_WDATA */ + wl1271_write32(wl, OCP_DATA_WRITE, val); + + /* write 1 to OCP_CMD */ + wl1271_write32(wl, OCP_CMD, OCP_CMD_WRITE); +} + +u16 wl1271_top_reg_read(struct wl1271 *wl, int addr) +{ + u32 val; + int timeout = OCP_CMD_LOOP; + + /* write address >> 1 + 0x30000 to OCP_POR_CTR */ + addr = (addr >> 1) + 0x30000; + wl1271_write32(wl, OCP_POR_CTR, addr); + + /* write 2 to OCP_CMD */ + wl1271_write32(wl, OCP_CMD, OCP_CMD_READ); + + /* poll for data ready */ + do { + val = wl1271_read32(wl, OCP_DATA_READ); + } while (!(val & OCP_READY_MASK) && --timeout); + + if (!timeout) { + wl1271_warning("Top register access timed out."); + return 0xffff; + } + + /* check data status and return if OK */ + if ((val & OCP_STATUS_MASK) == OCP_STATUS_OK) + return val & 0xffff; + else { + wl1271_warning("Top register access returned error."); + return 0xffff; + } +} + diff --git a/drivers/net/wireless/wl12xx/io.h b/drivers/net/wireless/wl12xx/io.h new file mode 100644 index 0000000..844b32b --- /dev/null +++ b/drivers/net/wireless/wl12xx/io.h @@ -0,0 +1,172 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. + * Copyright (C) 2008-2010 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 __IO_H__ +#define __IO_H__ + +#include "reg.h" + +#define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0 + +#define HW_PARTITION_REGISTERS_ADDR 0x1FFC0 +#define HW_PART0_SIZE_ADDR (HW_PARTITION_REGISTERS_ADDR) +#define HW_PART0_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 4) +#define HW_PART1_SIZE_ADDR (HW_PARTITION_REGISTERS_ADDR + 8) +#define HW_PART1_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 12) +#define HW_PART2_SIZE_ADDR (HW_PARTITION_REGISTERS_ADDR + 16) +#define HW_PART2_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 20) +#define HW_PART3_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 24) + +#define HW_ACCESS_REGISTER_SIZE 4 + +#define HW_ACCESS_PRAM_MAX_RANGE 0x3c000 + +struct wl1271; + +void wl1271_disable_interrupts(struct wl1271 *wl); +void wl1271_enable_interrupts(struct wl1271 *wl); + +void wl1271_io_reset(struct wl1271 *wl); +void wl1271_io_init(struct wl1271 *wl); + +static inline struct device *wl1271_wl_to_dev(struct wl1271 *wl) +{ + return wl->if_ops->dev(wl); +} + + +/* Raw target IO, address is not translated */ +static inline void wl1271_raw_write(struct wl1271 *wl, int addr, void *buf, + size_t len, bool fixed) +{ + wl->if_ops->write(wl, addr, buf, len, fixed); +} + +static inline void wl1271_raw_read(struct wl1271 *wl, int addr, void *buf, + size_t len, bool fixed) +{ + wl->if_ops->read(wl, addr, buf, len, fixed); +} + +static inline u32 wl1271_raw_read32(struct wl1271 *wl, int addr) +{ + wl1271_raw_read(wl, addr, &wl->buffer_32, + sizeof(wl->buffer_32), false); + + return le32_to_cpu(wl->buffer_32); +} + +static inline void wl1271_raw_write32(struct wl1271 *wl, int addr, u32 val) +{ + wl->buffer_32 = cpu_to_le32(val); + wl1271_raw_write(wl, addr, &wl->buffer_32, + sizeof(wl->buffer_32), false); +} + +/* Translated target IO */ +static inline int wl1271_translate_addr(struct wl1271 *wl, int addr) +{ + /* + * To translate, first check to which window of addresses the + * particular address belongs. Then subtract the starting address + * of that window from the address. Then, add offset of the + * translated region. + * + * The translated regions occur next to each other in physical device + * memory, so just add the sizes of the preceeding address regions to + * get the offset to the new region. + * + * Currently, only the two first regions are addressed, and the + * assumption is that all addresses will fall into either of those + * two. + */ + if ((addr >= wl->part.reg.start) && + (addr < wl->part.reg.start + wl->part.reg.size)) + return addr - wl->part.reg.start + wl->part.mem.size; + else + return addr - wl->part.mem.start; +} + +static inline void wl1271_read(struct wl1271 *wl, int addr, void *buf, + size_t len, bool fixed) +{ + int physical; + + physical = wl1271_translate_addr(wl, addr); + + wl1271_raw_read(wl, physical, buf, len, fixed); +} + +static inline void wl1271_write(struct wl1271 *wl, int addr, void *buf, + size_t len, bool fixed) +{ + int physical; + + physical = wl1271_translate_addr(wl, addr); + + wl1271_raw_write(wl, physical, buf, len, fixed); +} + +static inline u32 wl1271_read32(struct wl1271 *wl, int addr) +{ + return wl1271_raw_read32(wl, wl1271_translate_addr(wl, addr)); +} + +static inline void wl1271_write32(struct wl1271 *wl, int addr, u32 val) +{ + wl1271_raw_write32(wl, wl1271_translate_addr(wl, addr), val); +} + +static inline void wl1271_power_off(struct wl1271 *wl) +{ + wl->if_ops->power(wl, false); + clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); +} + +static inline int wl1271_power_on(struct wl1271 *wl) +{ + int ret = wl->if_ops->power(wl, true); + if (ret == 0) + set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); + + return ret; +} + + +/* Top Register IO */ +void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val); +u16 wl1271_top_reg_read(struct wl1271 *wl, int addr); + +int wl1271_set_partition(struct wl1271 *wl, + struct wl1271_partition_set *p); + +/* Functions from wl1271_main.c */ + +int wl1271_register_hw(struct wl1271 *wl); +void wl1271_unregister_hw(struct wl1271 *wl); +int wl1271_init_ieee80211(struct wl1271 *wl); +struct ieee80211_hw *wl1271_alloc_hw(void); +int wl1271_free_hw(struct wl1271 *wl); + +#endif diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c new file mode 100644 index 0000000..c005230 --- /dev/null +++ b/drivers/net/wireless/wl12xx/main.c @@ -0,0 +1,2749 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2008-2010 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 "wl12xx.h" +#include "wl12xx_80211.h" +#include "reg.h" +#include "io.h" +#include "event.h" +#include "tx.h" +#include "rx.h" +#include "ps.h" +#include "init.h" +#include "debugfs.h" +#include "cmd.h" +#include "boot.h" +#include "testmode.h" +#include "scan.h" + +#define WL1271_BOOT_RETRIES 3 + +static struct conf_drv_settings default_conf = { + .sg = { + .params = { + [CONF_SG_BT_PER_THRESHOLD] = 7500, + [CONF_SG_HV3_MAX_OVERRIDE] = 0, + [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400, + [CONF_SG_BT_LOAD_RATIO] = 50, + [CONF_SG_AUTO_PS_MODE] = 1, + [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170, + [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50, + [CONF_SG_ANTENNA_CONFIGURATION] = 0, + [CONF_SG_BEACON_MISS_PERCENT] = 60, + [CONF_SG_RATE_ADAPT_THRESH] = 12, + [CONF_SG_RATE_ADAPT_SNR] = 0, + [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10, + [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 30, + [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 8, + [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20, + [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 50, + /* Note: with UPSD, this should be 4 */ + [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 8, + [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7, + [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25, + [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 20, + /* Note: with UPDS, this should be 15 */ + [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8, + /* Note: with UPDS, this should be 50 */ + [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 40, + /* Note: with UPDS, this should be 10 */ + [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 20, + [CONF_SG_RXT] = 1200, + [CONF_SG_TXT] = 1000, + [CONF_SG_ADAPTIVE_RXT_TXT] = 1, + [CONF_SG_PS_POLL_TIMEOUT] = 10, + [CONF_SG_UPSD_TIMEOUT] = 10, + [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7, + [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15, + [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15, + [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8, + [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20, + [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15, + [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20, + [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50, + [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10, + [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200, + [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800, + [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75, + [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15, + [CONF_SG_HV3_MAX_SERVED] = 6, + [CONF_SG_DHCP_TIME] = 5000, + [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100, + }, + .state = CONF_SG_PROTECTIVE, + }, + .rx = { + .rx_msdu_life_time = 512000, + .packet_detection_threshold = 0, + .ps_poll_timeout = 15, + .upsd_timeout = 15, + .rts_threshold = 2347, + .rx_cca_threshold = 0, + .irq_blk_threshold = 0xFFFF, + .irq_pkt_threshold = 0, + .irq_timeout = 600, + .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY, + }, + .tx = { + .tx_energy_detection = 0, + .rc_conf = { + .enabled_rates = 0, + .short_retry_limit = 10, + .long_retry_limit = 10, + .aflags = 0 + }, + .ac_conf_count = 4, + .ac_conf = { + [CONF_TX_AC_BE] = { + .ac = CONF_TX_AC_BE, + .cw_min = 15, + .cw_max = 63, + .aifsn = 3, + .tx_op_limit = 0, + }, + [CONF_TX_AC_BK] = { + .ac = CONF_TX_AC_BK, + .cw_min = 15, + .cw_max = 63, + .aifsn = 7, + .tx_op_limit = 0, + }, + [CONF_TX_AC_VI] = { + .ac = CONF_TX_AC_VI, + .cw_min = 15, + .cw_max = 63, + .aifsn = CONF_TX_AIFS_PIFS, + .tx_op_limit = 3008, + }, + [CONF_TX_AC_VO] = { + .ac = CONF_TX_AC_VO, + .cw_min = 15, + .cw_max = 63, + .aifsn = CONF_TX_AIFS_PIFS, + .tx_op_limit = 1504, + }, + }, + .tid_conf_count = 4, + .tid_conf = { + [CONF_TX_AC_BE] = { + .queue_id = CONF_TX_AC_BE, + .channel_type = CONF_CHANNEL_TYPE_EDCF, + .tsid = CONF_TX_AC_BE, + .ps_scheme = CONF_PS_SCHEME_LEGACY, + .ack_policy = CONF_ACK_POLICY_LEGACY, + .apsd_conf = {0, 0}, + }, + [CONF_TX_AC_BK] = { + .queue_id = CONF_TX_AC_BK, + .channel_type = CONF_CHANNEL_TYPE_EDCF, + .tsid = CONF_TX_AC_BK, + .ps_scheme = CONF_PS_SCHEME_LEGACY, + .ack_policy = CONF_ACK_POLICY_LEGACY, + .apsd_conf = {0, 0}, + }, + [CONF_TX_AC_VI] = { + .queue_id = CONF_TX_AC_VI, + .channel_type = CONF_CHANNEL_TYPE_EDCF, + .tsid = CONF_TX_AC_VI, + .ps_scheme = CONF_PS_SCHEME_LEGACY, + .ack_policy = CONF_ACK_POLICY_LEGACY, + .apsd_conf = {0, 0}, + }, + [CONF_TX_AC_VO] = { + .queue_id = CONF_TX_AC_VO, + .channel_type = CONF_CHANNEL_TYPE_EDCF, + .tsid = CONF_TX_AC_VO, + .ps_scheme = CONF_PS_SCHEME_LEGACY, + .ack_policy = CONF_ACK_POLICY_LEGACY, + .apsd_conf = {0, 0}, + }, + }, + .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD, + .tx_compl_timeout = 700, + .tx_compl_threshold = 4, + .basic_rate = CONF_HW_BIT_RATE_1MBPS, + .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS, + }, + .conn = { + .wake_up_event = CONF_WAKE_UP_EVENT_DTIM, + .listen_interval = 1, + .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED, + .bcn_filt_ie_count = 1, + .bcn_filt_ie = { + [0] = { + .ie = WLAN_EID_CHANNEL_SWITCH, + .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE, + } + }, + .synch_fail_thold = 10, + .bss_lose_timeout = 100, + .beacon_rx_timeout = 10000, + .broadcast_timeout = 20000, + .rx_broadcast_in_ps = 1, + .ps_poll_threshold = 10, + .ps_poll_recovery_period = 700, + .bet_enable = CONF_BET_MODE_ENABLE, + .bet_max_consecutive = 10, + .psm_entry_retries = 5, + .psm_entry_nullfunc_retries = 3, + .psm_entry_hangover_period = 1, + .keep_alive_interval = 55000, + .max_listen_interval = 20, + }, + .itrim = { + .enable = false, + .timeout = 50000, + }, + .pm_config = { + .host_clk_settling_time = 5000, + .host_fast_wakeup_support = false + }, + .roam_trigger = { + .trigger_pacing = 1, + .avg_weight_rssi_beacon = 20, + .avg_weight_rssi_data = 10, + .avg_weight_snr_beacon = 20, + .avg_weight_snr_data = 10 + }, + .scan = { + .min_dwell_time_active = 7500, + .max_dwell_time_active = 30000, + .min_dwell_time_passive = 30000, + .max_dwell_time_passive = 60000, + .num_probe_reqs = 2, + }, + .rf = { + .tx_per_channel_power_compensation_2 = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .tx_per_channel_power_compensation_5 = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + }, +}; + +static void __wl1271_op_remove_interface(struct wl1271 *wl); + + +static void wl1271_device_release(struct device *dev) +{ + +} + +static struct platform_device wl1271_device = { + .name = "wl1271", + .id = -1, + + /* device model insists to have a release function */ + .dev = { + .release = wl1271_device_release, + }, +}; + +static LIST_HEAD(wl_list); + +static int wl1271_dev_notify(struct notifier_block *me, unsigned long what, + void *arg) +{ + struct net_device *dev = arg; + struct wireless_dev *wdev; + struct wiphy *wiphy; + struct ieee80211_hw *hw; + struct wl1271 *wl; + struct wl1271 *wl_temp; + int ret = 0; + + /* Check that this notification is for us. */ + if (what != NETDEV_CHANGE) + return NOTIFY_DONE; + + wdev = dev->ieee80211_ptr; + if (wdev == NULL) + return NOTIFY_DONE; + + wiphy = wdev->wiphy; + if (wiphy == NULL) + return NOTIFY_DONE; + + hw = wiphy_priv(wiphy); + if (hw == NULL) + return NOTIFY_DONE; + + wl_temp = hw->priv; + list_for_each_entry(wl, &wl_list, list) { + if (wl == wl_temp) + break; + } + if (wl != wl_temp) + return NOTIFY_DONE; + + mutex_lock(&wl->mutex); + + if (wl->state == WL1271_STATE_OFF) + goto out; + + if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) + goto out; + + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out; + + if ((dev->operstate == IF_OPER_UP) && + !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) { + wl1271_cmd_set_sta_state(wl); + wl1271_info("Association completed."); + } + + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + + return NOTIFY_OK; +} + +static void wl1271_conf_init(struct wl1271 *wl) +{ + + /* + * This function applies the default configuration to the driver. This + * function is invoked upon driver load (spi probe.) + * + * The configuration is stored in a run-time structure in order to + * facilitate for run-time adjustment of any of the parameters. Making + * changes to the configuration structure will apply the new values on + * the next interface up (wl1271_op_start.) + */ + + /* apply driver default configuration */ + memcpy(&wl->conf, &default_conf, sizeof(default_conf)); +} + + +static int wl1271_plt_init(struct wl1271 *wl) +{ + struct conf_tx_ac_category *conf_ac; + struct conf_tx_tid *conf_tid; + int ret, i; + + ret = wl1271_cmd_general_parms(wl); + if (ret < 0) + return ret; + + ret = wl1271_cmd_radio_parms(wl); + if (ret < 0) + return ret; + + ret = wl1271_cmd_ext_radio_parms(wl); + if (ret < 0) + return ret; + + ret = wl1271_init_templates_config(wl); + if (ret < 0) + return ret; + + ret = wl1271_acx_init_mem_config(wl); + if (ret < 0) + return ret; + + /* PHY layer config */ + ret = wl1271_init_phy_config(wl); + if (ret < 0) + goto out_free_memmap; + + ret = wl1271_acx_dco_itrim_params(wl); + if (ret < 0) + goto out_free_memmap; + + /* Initialize connection monitoring thresholds */ + ret = wl1271_acx_conn_monit_params(wl, false); + if (ret < 0) + goto out_free_memmap; + + /* Bluetooth WLAN coexistence */ + ret = wl1271_init_pta(wl); + if (ret < 0) + goto out_free_memmap; + + /* Energy detection */ + ret = wl1271_init_energy_detection(wl); + if (ret < 0) + goto out_free_memmap; + + /* Default fragmentation threshold */ + ret = wl1271_acx_frag_threshold(wl); + if (ret < 0) + goto out_free_memmap; + + /* Default TID/AC configuration */ + BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count); + for (i = 0; i < wl->conf.tx.tid_conf_count; i++) { + conf_ac = &wl->conf.tx.ac_conf[i]; + ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min, + conf_ac->cw_max, conf_ac->aifsn, + conf_ac->tx_op_limit); + if (ret < 0) + goto out_free_memmap; + + conf_tid = &wl->conf.tx.tid_conf[i]; + ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id, + conf_tid->channel_type, + conf_tid->tsid, + conf_tid->ps_scheme, + conf_tid->ack_policy, + conf_tid->apsd_conf[0], + conf_tid->apsd_conf[1]); + if (ret < 0) + goto out_free_memmap; + } + + /* Enable data path */ + ret = wl1271_cmd_data_path(wl, 1); + if (ret < 0) + goto out_free_memmap; + + /* Configure for CAM power saving (ie. always active) */ + ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM); + if (ret < 0) + goto out_free_memmap; + + /* configure PM */ + ret = wl1271_acx_pm_config(wl); + if (ret < 0) + goto out_free_memmap; + + return 0; + + out_free_memmap: + kfree(wl->target_mem_map); + wl->target_mem_map = NULL; + + return ret; +} + +static void wl1271_fw_status(struct wl1271 *wl, + struct wl1271_fw_status *status) +{ + struct timespec ts; + u32 total = 0; + int i; + + wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false); + + wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, " + "drv_rx_counter = %d, tx_results_counter = %d)", + status->intr, + status->fw_rx_counter, + status->drv_rx_counter, + status->tx_results_counter); + + /* update number of available TX blocks */ + for (i = 0; i < NUM_TX_QUEUES; i++) { + u32 cnt = le32_to_cpu(status->tx_released_blks[i]) - + wl->tx_blocks_freed[i]; + + wl->tx_blocks_freed[i] = + le32_to_cpu(status->tx_released_blks[i]); + wl->tx_blocks_available += cnt; + total += cnt; + } + + /* if more blocks are available now, tx work can be scheduled */ + if (total) + clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); + + /* update the host-chipset time offset */ + getnstimeofday(&ts); + wl->time_offset = (timespec_to_ns(&ts) >> 10) - + (s64)le32_to_cpu(status->fw_localtime); +} + +#define WL1271_IRQ_MAX_LOOPS 10 + +static void wl1271_irq_work(struct work_struct *work) +{ + int ret; + u32 intr; + int loopcount = WL1271_IRQ_MAX_LOOPS; + unsigned long flags; + struct wl1271 *wl = + container_of(work, struct wl1271, irq_work); + + mutex_lock(&wl->mutex); + + wl1271_debug(DEBUG_IRQ, "IRQ work"); + + if (unlikely(wl->state == WL1271_STATE_OFF)) + goto out; + + ret = wl1271_ps_elp_wakeup(wl, true); + if (ret < 0) + goto out; + + spin_lock_irqsave(&wl->wl_lock, flags); + while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) { + clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags); + spin_unlock_irqrestore(&wl->wl_lock, flags); + loopcount--; + + wl1271_fw_status(wl, wl->fw_status); + intr = le32_to_cpu(wl->fw_status->intr); + if (!intr) { + wl1271_debug(DEBUG_IRQ, "Zero interrupt received."); + spin_lock_irqsave(&wl->wl_lock, flags); + continue; + } + + intr &= WL1271_INTR_MASK; + + if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) { + wl1271_error("watchdog interrupt received! " + "starting recovery."); + ieee80211_queue_work(wl->hw, &wl->recovery_work); + + /* restarting the chip. ignore any other interrupt. */ + goto out; + } + + if (intr & WL1271_ACX_INTR_DATA) { + wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA"); + + /* check for tx results */ + if (wl->fw_status->tx_results_counter != + (wl->tx_results_count & 0xff)) + wl1271_tx_complete(wl); + + /* Check if any tx blocks were freed */ + if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) && + !skb_queue_empty(&wl->tx_queue)) { + /* + * In order to avoid starvation of the TX path, + * call the work function directly. + */ + wl1271_tx_work_locked(wl); + } + + wl1271_rx(wl, wl->fw_status); + } + + if (intr & WL1271_ACX_INTR_EVENT_A) { + wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A"); + wl1271_event_handle(wl, 0); + } + + if (intr & WL1271_ACX_INTR_EVENT_B) { + wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B"); + wl1271_event_handle(wl, 1); + } + + if (intr & WL1271_ACX_INTR_INIT_COMPLETE) + wl1271_debug(DEBUG_IRQ, + "WL1271_ACX_INTR_INIT_COMPLETE"); + + if (intr & WL1271_ACX_INTR_HW_AVAILABLE) + wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE"); + + spin_lock_irqsave(&wl->wl_lock, flags); + } + + if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags)) + ieee80211_queue_work(wl->hw, &wl->irq_work); + else + clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags); + spin_unlock_irqrestore(&wl->wl_lock, flags); + + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); +} + +static int wl1271_fetch_firmware(struct wl1271 *wl) +{ + const struct firmware *fw; + int ret; + + ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl)); + + if (ret < 0) { + wl1271_error("could not get firmware: %d", ret); + return ret; + } + + if (fw->size % 4) { + wl1271_error("firmware size is not multiple of 32 bits: %zu", + fw->size); + ret = -EILSEQ; + goto out; + } + + wl->fw_len = fw->size; + wl->fw = vmalloc(wl->fw_len); + + if (!wl->fw) { + wl1271_error("could not allocate memory for the firmware"); + ret = -ENOMEM; + goto out; + } + + memcpy(wl->fw, fw->data, wl->fw_len); + + ret = 0; + +out: + release_firmware(fw); + + return ret; +} + +static int wl1271_fetch_nvs(struct wl1271 *wl) +{ + const struct firmware *fw; + int ret; + + ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl)); + + if (ret < 0) { + wl1271_error("could not get nvs file: %d", ret); + return ret; + } + + wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL); + + if (!wl->nvs) { + wl1271_error("could not allocate memory for the nvs file"); + ret = -ENOMEM; + goto out; + } + + wl->nvs_len = fw->size; + +out: + release_firmware(fw); + + return ret; +} + +static void wl1271_recovery_work(struct work_struct *work) +{ + struct wl1271 *wl = + container_of(work, struct wl1271, recovery_work); + + mutex_lock(&wl->mutex); + + if (wl->state != WL1271_STATE_ON) + goto out; + + wl1271_info("Hardware recovery in progress."); + + if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) + ieee80211_connection_loss(wl->vif); + + /* reboot the chipset */ + __wl1271_op_remove_interface(wl); + ieee80211_restart_hw(wl->hw); + +out: + mutex_unlock(&wl->mutex); +} + +static void wl1271_fw_wakeup(struct wl1271 *wl) +{ + u32 elp_reg; + + elp_reg = ELPCTRL_WAKE_UP; + wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg); +} + +static int wl1271_setup(struct wl1271 *wl) +{ + wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL); + if (!wl->fw_status) + return -ENOMEM; + + wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL); + if (!wl->tx_res_if) { + kfree(wl->fw_status); + return -ENOMEM; + } + + return 0; +} + +static int wl1271_chip_wakeup(struct wl1271 *wl) +{ + struct wl1271_partition_set partition; + int ret = 0; + + msleep(WL1271_PRE_POWER_ON_SLEEP); + ret = wl1271_power_on(wl); + if (ret < 0) + goto out; + msleep(WL1271_POWER_ON_SLEEP); + wl1271_io_reset(wl); + wl1271_io_init(wl); + + /* We don't need a real memory partition here, because we only want + * to use the registers at this point. */ + memset(&partition, 0, sizeof(partition)); + partition.reg.start = REGISTERS_BASE; + partition.reg.size = REGISTERS_DOWN_SIZE; + wl1271_set_partition(wl, &partition); + + /* ELP module wake up */ + wl1271_fw_wakeup(wl); + + /* whal_FwCtrl_BootSm() */ + + /* 0. read chip id from CHIP_ID */ + wl->chip.id = wl1271_read32(wl, CHIP_ID_B); + + /* 1. check if chip id is valid */ + + switch (wl->chip.id) { + case CHIP_ID_1271_PG10: + wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete", + wl->chip.id); + + ret = wl1271_setup(wl); + if (ret < 0) + goto out; + break; + case CHIP_ID_1271_PG20: + wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)", + wl->chip.id); + + ret = wl1271_setup(wl); + if (ret < 0) + goto out; + break; + default: + wl1271_warning("unsupported chip id: 0x%x", wl->chip.id); + ret = -ENODEV; + goto out; + } + + if (wl->fw == NULL) { + ret = wl1271_fetch_firmware(wl); + if (ret < 0) + goto out; + } + + /* No NVS from netlink, try to get it from the filesystem */ + if (wl->nvs == NULL) { + ret = wl1271_fetch_nvs(wl); + if (ret < 0) + goto out; + } + +out: + return ret; +} + +int wl1271_plt_start(struct wl1271 *wl) +{ + int retries = WL1271_BOOT_RETRIES; + int ret; + + mutex_lock(&wl->mutex); + + wl1271_notice("power up"); + + if (wl->state != WL1271_STATE_OFF) { + wl1271_error("cannot go into PLT state because not " + "in off state: %d", wl->state); + ret = -EBUSY; + goto out; + } + + while (retries) { + retries--; + ret = wl1271_chip_wakeup(wl); + if (ret < 0) + goto power_off; + + ret = wl1271_boot(wl); + if (ret < 0) + goto power_off; + + ret = wl1271_plt_init(wl); + if (ret < 0) + goto irq_disable; + + wl->state = WL1271_STATE_PLT; + wl1271_notice("firmware booted in PLT mode (%s)", + wl->chip.fw_ver); + goto out; + +irq_disable: + wl1271_disable_interrupts(wl); + mutex_unlock(&wl->mutex); + /* Unlocking the mutex in the middle of handling is + inherently unsafe. In this case we deem it safe to do, + because we need to let any possibly pending IRQ out of + the system (and while we are WL1271_STATE_OFF the IRQ + work function will not do anything.) Also, any other + possible concurrent operations will fail due to the + current state, hence the wl1271 struct should be safe. */ + cancel_work_sync(&wl->irq_work); + mutex_lock(&wl->mutex); +power_off: + wl1271_power_off(wl); + } + + wl1271_error("firmware boot in PLT mode failed despite %d retries", + WL1271_BOOT_RETRIES); +out: + mutex_unlock(&wl->mutex); + + return ret; +} + +int wl1271_plt_stop(struct wl1271 *wl) +{ + int ret = 0; + + mutex_lock(&wl->mutex); + + wl1271_notice("power down"); + + if (wl->state != WL1271_STATE_PLT) { + wl1271_error("cannot power down because not in PLT " + "state: %d", wl->state); + ret = -EBUSY; + goto out; + } + + wl1271_disable_interrupts(wl); + wl1271_power_off(wl); + + wl->state = WL1271_STATE_OFF; + wl->rx_counter = 0; + +out: + mutex_unlock(&wl->mutex); + + cancel_work_sync(&wl->irq_work); + cancel_work_sync(&wl->recovery_work); + + return ret; +} + +static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct wl1271 *wl = hw->priv; + struct ieee80211_conf *conf = &hw->conf; + struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb); + struct ieee80211_sta *sta = txinfo->control.sta; + unsigned long flags; + + /* + * peek into the rates configured in the STA entry. + * The rates set after connection stage, The first block only BG sets: + * the compare is for bit 0-16 of sta_rate_set. The second block add + * HT rates in case of HT supported. + */ + spin_lock_irqsave(&wl->wl_lock, flags); + if (sta && + (sta->supp_rates[conf->channel->band] != + (wl->sta_rate_set & HW_BG_RATES_MASK))) { + wl->sta_rate_set = sta->supp_rates[conf->channel->band]; + set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags); + } + +#ifdef CONFIG_WL12XX_HT + if (sta && + sta->ht_cap.ht_supported && + ((wl->sta_rate_set >> HW_HT_RATES_OFFSET) != + sta->ht_cap.mcs.rx_mask[0])) { + /* Clean MCS bits before setting them */ + wl->sta_rate_set &= HW_BG_RATES_MASK; + wl->sta_rate_set |= + (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET); + set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags); + } +#endif + spin_unlock_irqrestore(&wl->wl_lock, flags); + + /* queue the packet */ + 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! + */ + + if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags)) + 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) >= WL1271_TX_QUEUE_HIGH_WATERMARK) { + wl1271_debug(DEBUG_TX, "op_tx: stopping queues"); + + spin_lock_irqsave(&wl->wl_lock, flags); + ieee80211_stop_queues(wl->hw); + set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags); + spin_unlock_irqrestore(&wl->wl_lock, flags); + } + + return NETDEV_TX_OK; +} + +static struct notifier_block wl1271_dev_notifier = { + .notifier_call = wl1271_dev_notify, +}; + +static int wl1271_op_start(struct ieee80211_hw *hw) +{ + wl1271_debug(DEBUG_MAC80211, "mac80211 start"); + + /* + * We have to delay the booting of the hardware because + * we need to know the local MAC address before downloading and + * initializing the firmware. The MAC address cannot be changed + * after boot, and without the proper MAC address, the firmware + * will not function properly. + * + * The MAC address is first known when the corresponding interface + * is added. That is where we will initialize the hardware. + */ + + return 0; +} + +static void wl1271_op_stop(struct ieee80211_hw *hw) +{ + wl1271_debug(DEBUG_MAC80211, "mac80211 stop"); +} + +static int wl1271_op_add_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct wl1271 *wl = hw->priv; + struct wiphy *wiphy = hw->wiphy; + int retries = WL1271_BOOT_RETRIES; + int ret = 0; + bool booted = false; + + wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", + vif->type, vif->addr); + + mutex_lock(&wl->mutex); + if (wl->vif) { + wl1271_debug(DEBUG_MAC80211, + "multiple vifs are not supported yet"); + ret = -EBUSY; + goto out; + } + + switch (vif->type) { + case NL80211_IFTYPE_STATION: + wl->bss_type = BSS_TYPE_STA_BSS; + wl->set_bss_type = BSS_TYPE_STA_BSS; + break; + case NL80211_IFTYPE_ADHOC: + wl->bss_type = BSS_TYPE_IBSS; + wl->set_bss_type = BSS_TYPE_STA_BSS; + break; + default: + ret = -EOPNOTSUPP; + goto out; + } + + memcpy(wl->mac_addr, vif->addr, ETH_ALEN); + + if (wl->state != WL1271_STATE_OFF) { + wl1271_error("cannot start because not in off state: %d", + wl->state); + ret = -EBUSY; + goto out; + } + + while (retries) { + retries--; + ret = wl1271_chip_wakeup(wl); + if (ret < 0) + goto power_off; + + ret = wl1271_boot(wl); + if (ret < 0) + goto power_off; + + ret = wl1271_hw_init(wl); + if (ret < 0) + goto irq_disable; + + booted = true; + break; + +irq_disable: + wl1271_disable_interrupts(wl); + mutex_unlock(&wl->mutex); + /* Unlocking the mutex in the middle of handling is + inherently unsafe. In this case we deem it safe to do, + because we need to let any possibly pending IRQ out of + the system (and while we are WL1271_STATE_OFF the IRQ + work function will not do anything.) Also, any other + possible concurrent operations will fail due to the + current state, hence the wl1271 struct should be safe. */ + cancel_work_sync(&wl->irq_work); + mutex_lock(&wl->mutex); +power_off: + wl1271_power_off(wl); + } + + if (!booted) { + wl1271_error("firmware boot failed despite %d retries", + WL1271_BOOT_RETRIES); + goto out; + } + + wl->vif = vif; + wl->state = WL1271_STATE_ON; + wl1271_info("firmware booted (%s)", wl->chip.fw_ver); + + /* update hw/fw version info in wiphy struct */ + wiphy->hw_version = wl->chip.id; + strncpy(wiphy->fw_version, wl->chip.fw_ver, + sizeof(wiphy->fw_version)); + +out: + mutex_unlock(&wl->mutex); + + if (!ret) + list_add(&wl->list, &wl_list); + + return ret; +} + +static void __wl1271_op_remove_interface(struct wl1271 *wl) +{ + int i; + + wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface"); + + wl1271_info("down"); + + list_del(&wl->list); + + WARN_ON(wl->state != WL1271_STATE_ON); + + /* enable dyn ps just in case (if left on due to fw crash etc) */ + if (wl->bss_type == BSS_TYPE_STA_BSS) + ieee80211_enable_dyn_ps(wl->vif); + + if (wl->scan.state != WL1271_SCAN_STATE_IDLE) { + wl->scan.state = WL1271_SCAN_STATE_IDLE; + kfree(wl->scan.scanned_ch); + wl->scan.scanned_ch = NULL; + wl->scan.req = NULL; + ieee80211_scan_completed(wl->hw, true); + } + + wl->state = WL1271_STATE_OFF; + + wl1271_disable_interrupts(wl); + + mutex_unlock(&wl->mutex); + + cancel_delayed_work_sync(&wl->scan_complete_work); + cancel_work_sync(&wl->irq_work); + cancel_work_sync(&wl->tx_work); + cancel_delayed_work_sync(&wl->pspoll_work); + cancel_delayed_work_sync(&wl->elp_work); + + mutex_lock(&wl->mutex); + + /* let's notify MAC80211 about the remaining pending TX frames */ + wl1271_tx_reset(wl); + wl1271_power_off(wl); + + memset(wl->bssid, 0, ETH_ALEN); + memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1); + wl->ssid_len = 0; + wl->bss_type = MAX_BSS_TYPE; + wl->set_bss_type = MAX_BSS_TYPE; + wl->band = IEEE80211_BAND_2GHZ; + + wl->rx_counter = 0; + wl->psm_entry_retry = 0; + wl->power_level = WL1271_DEFAULT_POWER_LEVEL; + wl->tx_blocks_available = 0; + wl->tx_results_count = 0; + wl->tx_packets_count = 0; + wl->tx_security_last_seq = 0; + wl->tx_security_seq = 0; + wl->time_offset = 0; + wl->session_counter = 0; + wl->rate_set = CONF_TX_RATE_MASK_BASIC; + wl->sta_rate_set = 0; + wl->flags = 0; + wl->vif = NULL; + wl->filters = 0; + + for (i = 0; i < NUM_TX_QUEUES; i++) + wl->tx_blocks_freed[i] = 0; + + wl1271_debugfs_reset(wl); + + kfree(wl->fw_status); + wl->fw_status = NULL; + kfree(wl->tx_res_if); + wl->tx_res_if = NULL; + kfree(wl->target_mem_map); + wl->target_mem_map = NULL; +} + +static void wl1271_op_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct wl1271 *wl = hw->priv; + + mutex_lock(&wl->mutex); + WARN_ON(wl->vif != vif); + __wl1271_op_remove_interface(wl); + mutex_unlock(&wl->mutex); + + cancel_work_sync(&wl->recovery_work); +} + +static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters) +{ + wl->rx_config = WL1271_DEFAULT_RX_CONFIG; + wl->rx_filter = WL1271_DEFAULT_RX_FILTER; + + /* combine requested filters with current filter config */ + filters = wl->filters | filters; + + wl1271_debug(DEBUG_FILTERS, "RX filters set: "); + + if (filters & FIF_PROMISC_IN_BSS) { + wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS"); + wl->rx_config &= ~CFG_UNI_FILTER_EN; + wl->rx_config |= CFG_BSSID_FILTER_EN; + } + if (filters & FIF_BCN_PRBRESP_PROMISC) { + wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC"); + wl->rx_config &= ~CFG_BSSID_FILTER_EN; + wl->rx_config &= ~CFG_SSID_FILTER_EN; + } + if (filters & FIF_OTHER_BSS) { + wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS"); + wl->rx_config &= ~CFG_BSSID_FILTER_EN; + } + if (filters & FIF_CONTROL) { + wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL"); + wl->rx_filter |= CFG_RX_CTL_EN; + } + if (filters & FIF_FCSFAIL) { + wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL"); + wl->rx_filter |= CFG_RX_FCS_ERROR; + } +} + +static int wl1271_dummy_join(struct wl1271 *wl) +{ + int ret = 0; + /* we need to use a dummy BSSID for now */ + static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde, + 0xad, 0xbe, 0xef }; + + memcpy(wl->bssid, dummy_bssid, ETH_ALEN); + + /* pass through frames from all BSS */ + wl1271_configure_filters(wl, FIF_OTHER_BSS); + + ret = wl1271_cmd_join(wl, wl->set_bss_type); + if (ret < 0) + goto out; + + set_bit(WL1271_FLAG_JOINED, &wl->flags); + +out: + return ret; +} + +static int wl1271_join(struct wl1271 *wl, bool set_assoc) +{ + int ret; + + /* + * One of the side effects of the JOIN command is that is clears + * WPA/WPA2 keys from the chipset. Performing a JOIN while associated + * to a WPA/WPA2 access point will therefore kill the data-path. + * Currently there is no supported scenario for JOIN during + * association - if it becomes a supported scenario, the WPA/WPA2 keys + * must be handled somehow. + * + */ + if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) + wl1271_info("JOIN while associated."); + + if (set_assoc) + set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags); + + ret = wl1271_cmd_join(wl, wl->set_bss_type); + if (ret < 0) + goto out; + + set_bit(WL1271_FLAG_JOINED, &wl->flags); + + if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) + goto out; + + /* + * The join command disable the keep-alive mode, shut down its process, + * and also clear the template config, so we need to reset it all after + * the join. The acx_aid starts the keep-alive process, and the order + * of the commands below is relevant. + */ + ret = wl1271_acx_keep_alive_mode(wl, true); + if (ret < 0) + goto out; + + ret = wl1271_acx_aid(wl, wl->aid); + if (ret < 0) + goto out; + + ret = wl1271_cmd_build_klv_null_data(wl); + if (ret < 0) + goto out; + + ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA, + ACX_KEEP_ALIVE_TPL_VALID); + if (ret < 0) + goto out; + +out: + return ret; +} + +static int wl1271_unjoin(struct wl1271 *wl) +{ + int ret; + + /* to stop listening to a channel, we disconnect */ + ret = wl1271_cmd_disconnect(wl); + if (ret < 0) + goto out; + + clear_bit(WL1271_FLAG_JOINED, &wl->flags); + memset(wl->bssid, 0, ETH_ALEN); + + /* stop filterting packets based on bssid */ + wl1271_configure_filters(wl, FIF_OTHER_BSS); + +out: + return ret; +} + +static void wl1271_set_band_rate(struct wl1271 *wl) +{ + if (wl->band == IEEE80211_BAND_2GHZ) + wl->basic_rate_set = wl->conf.tx.basic_rate; + else + wl->basic_rate_set = wl->conf.tx.basic_rate_5; +} + +static u32 wl1271_min_rate_get(struct wl1271 *wl) +{ + int i; + u32 rate = 0; + + if (!wl->basic_rate_set) { + WARN_ON(1); + wl->basic_rate_set = wl->conf.tx.basic_rate; + } + + for (i = 0; !rate; i++) { + if ((wl->basic_rate_set >> i) & 0x1) + rate = 1 << i; + } + + return rate; +} + +static int wl1271_handle_idle(struct wl1271 *wl, bool idle) +{ + int ret; + + if (idle) { + if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) { + ret = wl1271_unjoin(wl); + if (ret < 0) + goto out; + } + wl->rate_set = wl1271_min_rate_get(wl); + wl->sta_rate_set = 0; + ret = wl1271_acx_rate_policies(wl); + if (ret < 0) + goto out; + ret = wl1271_acx_keep_alive_config( + wl, CMD_TEMPL_KLV_IDX_NULL_DATA, + ACX_KEEP_ALIVE_TPL_INVALID); + if (ret < 0) + goto out; + set_bit(WL1271_FLAG_IDLE, &wl->flags); + } else { + /* increment the session counter */ + wl->session_counter++; + if (wl->session_counter >= SESSION_COUNTER_MAX) + wl->session_counter = 0; + ret = wl1271_dummy_join(wl); + if (ret < 0) + goto out; + clear_bit(WL1271_FLAG_IDLE, &wl->flags); + } + +out: + return ret; +} + +static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) +{ + struct wl1271 *wl = hw->priv; + struct ieee80211_conf *conf = &hw->conf; + int channel, ret = 0; + + channel = ieee80211_frequency_to_channel(conf->channel->center_freq); + + wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s", + channel, + conf->flags & IEEE80211_CONF_PS ? "on" : "off", + conf->power_level, + conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use"); + + /* + * mac80211 will go to idle nearly immediately after transmitting some + * frames, such as the deauth. To make sure those frames reach the air, + * wait here until the TX queue is fully flushed. + */ + if ((changed & IEEE80211_CONF_CHANGE_IDLE) && + (conf->flags & IEEE80211_CONF_IDLE)) + wl1271_tx_flush(wl); + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state == WL1271_STATE_OFF)) { + ret = -EAGAIN; + goto out; + } + + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out; + + /* if the channel changes while joined, join again */ + if (changed & IEEE80211_CONF_CHANGE_CHANNEL && + ((wl->band != conf->channel->band) || + (wl->channel != channel))) { + wl->band = conf->channel->band; + wl->channel = channel; + + /* + * FIXME: the mac80211 should really provide a fixed rate + * to use here. for now, just use the smallest possible rate + * for the band as a fixed rate for association frames and + * other control messages. + */ + if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) + wl1271_set_band_rate(wl); + + wl->basic_rate = wl1271_min_rate_get(wl); + ret = wl1271_acx_rate_policies(wl); + if (ret < 0) + wl1271_warning("rate policy for update channel " + "failed %d", ret); + + if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) { + ret = wl1271_join(wl, false); + if (ret < 0) + wl1271_warning("cmd join to update channel " + "failed %d", ret); + } + } + + if (changed & IEEE80211_CONF_CHANGE_IDLE) { + ret = wl1271_handle_idle(wl, conf->flags & IEEE80211_CONF_IDLE); + if (ret < 0) + wl1271_warning("idle mode change failed %d", ret); + } + + /* + * if mac80211 changes the PSM mode, make sure the mode is not + * incorrectly changed after the pspoll failure active window. + */ + if (changed & IEEE80211_CONF_CHANGE_PS) + clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags); + + if (conf->flags & IEEE80211_CONF_PS && + !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) { + set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags); + + /* + * We enter PSM only if we're already associated. + * If we're not, we'll enter it when joining an SSID, + * through the bss_info_changed() hook. + */ + if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) { + wl1271_debug(DEBUG_PSM, "psm enabled"); + ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, + wl->basic_rate, true); + } + } else if (!(conf->flags & IEEE80211_CONF_PS) && + test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) { + wl1271_debug(DEBUG_PSM, "psm disabled"); + + clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags); + + if (test_bit(WL1271_FLAG_PSM, &wl->flags)) + ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, + wl->basic_rate, true); + } + + if (conf->power_level != wl->power_level) { + ret = wl1271_acx_tx_power(wl, conf->power_level); + if (ret < 0) + goto out_sleep; + + wl->power_level = conf->power_level; + } + +out_sleep: + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + + return ret; +} + +struct wl1271_filter_params { + bool enabled; + int mc_list_length; + u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN]; +}; + +static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, + struct netdev_hw_addr_list *mc_list) +{ + struct wl1271_filter_params *fp; + struct netdev_hw_addr *ha; + struct wl1271 *wl = hw->priv; + + if (unlikely(wl->state == WL1271_STATE_OFF)) + return 0; + + fp = kzalloc(sizeof(*fp), GFP_ATOMIC); + if (!fp) { + wl1271_error("Out of memory setting filters."); + return 0; + } + + /* update multicast filtering parameters */ + fp->mc_list_length = 0; + if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) { + fp->enabled = false; + } else { + fp->enabled = true; + netdev_hw_addr_list_for_each(ha, mc_list) { + memcpy(fp->mc_list[fp->mc_list_length], + ha->addr, ETH_ALEN); + fp->mc_list_length++; + } + } + + return (u64)(unsigned long)fp; +} + +#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ + FIF_ALLMULTI | \ + FIF_FCSFAIL | \ + FIF_BCN_PRBRESP_PROMISC | \ + FIF_CONTROL | \ + FIF_OTHER_BSS) + +static void wl1271_op_configure_filter(struct ieee80211_hw *hw, + unsigned int changed, + unsigned int *total, u64 multicast) +{ + struct wl1271_filter_params *fp = (void *)(unsigned long)multicast; + struct wl1271 *wl = hw->priv; + int ret; + + wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter"); + + mutex_lock(&wl->mutex); + + *total &= WL1271_SUPPORTED_FILTERS; + changed &= WL1271_SUPPORTED_FILTERS; + + if (unlikely(wl->state == WL1271_STATE_OFF)) + goto out; + + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out; + + + if (*total & FIF_ALLMULTI) + ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0); + else if (fp) + ret = wl1271_acx_group_address_tbl(wl, fp->enabled, + fp->mc_list, + fp->mc_list_length); + if (ret < 0) + goto out_sleep; + + /* determine, whether supported filter values have changed */ + if (changed == 0) + goto out_sleep; + + /* configure filters */ + wl->filters = *total; + wl1271_configure_filters(wl, 0); + + /* apply configured filters */ + ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter); + if (ret < 0) + goto out_sleep; + +out_sleep: + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + kfree(fp); +} + +static int wl1271_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_conf) +{ + struct wl1271 *wl = hw->priv; + const u8 *addr; + int ret; + u32 tx_seq_32 = 0; + u16 tx_seq_16 = 0; + u8 key_type; + + static const u8 bcast_addr[ETH_ALEN] = + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + wl1271_debug(DEBUG_MAC80211, "mac80211 set key"); + + addr = sta ? sta->addr : bcast_addr; + + wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd); + wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN); + wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x", + key_conf->cipher, key_conf->keyidx, + key_conf->keylen, key_conf->flags); + wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen); + + if (is_zero_ether_addr(addr)) { + /* We dont support TX only encryption */ + ret = -EOPNOTSUPP; + goto out; + } + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state == WL1271_STATE_OFF)) { + ret = -EAGAIN; + goto out_unlock; + } + + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out_unlock; + + switch (key_conf->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + key_type = KEY_WEP; + + key_conf->hw_key_idx = key_conf->keyidx; + break; + case WLAN_CIPHER_SUITE_TKIP: + key_type = KEY_TKIP; + + key_conf->hw_key_idx = key_conf->keyidx; + tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq); + tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq); + break; + case WLAN_CIPHER_SUITE_CCMP: + key_type = KEY_AES; + + key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq); + tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq); + break; + case WL1271_CIPHER_SUITE_GEM: + key_type = KEY_GEM; + tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq); + tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq); + break; + default: + wl1271_error("Unknown key algo 0x%x", key_conf->cipher); + + ret = -EOPNOTSUPP; + goto out_sleep; + } + + switch (cmd) { + case SET_KEY: + ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE, + key_conf->keyidx, key_type, + key_conf->keylen, key_conf->key, + addr, tx_seq_32, tx_seq_16); + if (ret < 0) { + wl1271_error("Could not add or replace key"); + goto out_sleep; + } + + /* the default WEP key needs to be configured at least once */ + if (key_type == KEY_WEP) { + ret = wl1271_cmd_set_default_wep_key(wl, + wl->default_key); + if (ret < 0) + goto out_sleep; + } + break; + + case DISABLE_KEY: + /* The wl1271 does not allow to remove unicast keys - they + will be cleared automatically on next CMD_JOIN. Ignore the + request silently, as we dont want the mac80211 to emit + an error message. */ + if (!is_broadcast_ether_addr(addr)) + break; + + ret = wl1271_cmd_set_key(wl, KEY_REMOVE, + key_conf->keyidx, key_type, + key_conf->keylen, key_conf->key, + addr, 0, 0); + if (ret < 0) { + wl1271_error("Could not remove key"); + goto out_sleep; + } + break; + + default: + wl1271_error("Unsupported key cmd 0x%x", cmd); + ret = -EOPNOTSUPP; + break; + } + +out_sleep: + wl1271_ps_elp_sleep(wl); + +out_unlock: + mutex_unlock(&wl->mutex); + +out: + return ret; +} + +static int wl1271_op_hw_scan(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_scan_request *req) +{ + struct wl1271 *wl = hw->priv; + int ret; + u8 *ssid = NULL; + size_t len = 0; + + wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan"); + + if (req->n_ssids) { + ssid = req->ssids[0].ssid; + len = req->ssids[0].ssid_len; + } + + mutex_lock(&wl->mutex); + + if (wl->state == WL1271_STATE_OFF) { + /* + * We cannot return -EBUSY here because cfg80211 will expect + * a call to ieee80211_scan_completed if we do - in this case + * there won't be any call. + */ + ret = -EAGAIN; + goto out; + } + + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out; + + ret = wl1271_scan(hw->priv, ssid, len, req); + + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + + return ret; +} + +static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +{ + struct wl1271 *wl = hw->priv; + int ret = 0; + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state == WL1271_STATE_OFF)) { + ret = -EAGAIN; + goto out; + } + + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out; + + ret = wl1271_acx_rts_threshold(wl, (u16) value); + if (ret < 0) + wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret); + + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + + return ret; +} + +static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon) +{ + u8 *ptr = beacon->data + + offsetof(struct ieee80211_mgmt, u.beacon.variable); + + /* find the location of the ssid in the beacon */ + while (ptr < beacon->data + beacon->len) { + if (ptr[0] == WLAN_EID_SSID) { + wl->ssid_len = ptr[1]; + memcpy(wl->ssid, ptr+2, wl->ssid_len); + return; + } + ptr += ptr[1]; + } + wl1271_error("ad-hoc beacon template has no SSID!\n"); +} + +static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changed) +{ + enum wl1271_cmd_ps_mode mode; + struct wl1271 *wl = hw->priv; + struct ieee80211_sta *sta = ieee80211_find_sta(vif, bss_conf->bssid); + bool do_join = false; + bool set_assoc = false; + int ret; + + wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed"); + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state == WL1271_STATE_OFF)) + goto out; + + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out; + + if ((changed & BSS_CHANGED_BEACON_INT) && + (wl->bss_type == BSS_TYPE_IBSS)) { + wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d", + bss_conf->beacon_int); + + wl->beacon_int = bss_conf->beacon_int; + do_join = true; + } + + if ((changed & BSS_CHANGED_BEACON) && + (wl->bss_type == BSS_TYPE_IBSS)) { + struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); + + wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon updated"); + + if (beacon) { + struct ieee80211_hdr *hdr; + + wl1271_ssid_set(wl, beacon); + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, + beacon->data, + beacon->len, 0, + wl1271_min_rate_get(wl)); + + if (ret < 0) { + dev_kfree_skb(beacon); + goto out_sleep; + } + + hdr = (struct ieee80211_hdr *) beacon->data; + hdr->frame_control = cpu_to_le16( + IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_PROBE_RESP); + + ret = wl1271_cmd_template_set(wl, + CMD_TEMPL_PROBE_RESPONSE, + beacon->data, + beacon->len, 0, + wl1271_min_rate_get(wl)); + dev_kfree_skb(beacon); + if (ret < 0) + goto out_sleep; + + /* Need to update the SSID (for filtering etc) */ + do_join = true; + } + } + + if ((changed & BSS_CHANGED_BEACON_ENABLED) && + (wl->bss_type == BSS_TYPE_IBSS)) { + wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s", + bss_conf->enable_beacon ? "enabled" : "disabled"); + + if (bss_conf->enable_beacon) + wl->set_bss_type = BSS_TYPE_IBSS; + else + wl->set_bss_type = BSS_TYPE_STA_BSS; + do_join = true; + } + + if (changed & BSS_CHANGED_CQM) { + bool enable = false; + if (bss_conf->cqm_rssi_thold) + enable = true; + ret = wl1271_acx_rssi_snr_trigger(wl, enable, + bss_conf->cqm_rssi_thold, + bss_conf->cqm_rssi_hyst); + if (ret < 0) + goto out; + wl->rssi_thold = bss_conf->cqm_rssi_thold; + } + + if ((changed & BSS_CHANGED_BSSID) && + /* + * Now we know the correct bssid, so we send a new join command + * and enable the BSSID filter + */ + memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) { + memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN); + + ret = wl1271_cmd_build_null_data(wl); + if (ret < 0) + goto out_sleep; + + ret = wl1271_build_qos_null_data(wl); + if (ret < 0) + goto out_sleep; + + /* filter out all packets not from this BSSID */ + wl1271_configure_filters(wl, 0); + + /* Need to update the BSSID (for filtering etc) */ + do_join = true; + } + + if (changed & BSS_CHANGED_ASSOC) { + if (bss_conf->assoc) { + u32 rates; + wl->aid = bss_conf->aid; + set_assoc = true; + + wl->ps_poll_failures = 0; + + /* + * use basic rates from AP, and determine lowest rate + * to use with control frames. + */ + rates = bss_conf->basic_rates; + wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, + rates); + wl->basic_rate = wl1271_min_rate_get(wl); + ret = wl1271_acx_rate_policies(wl); + if (ret < 0) + goto out_sleep; + + /* + * with wl1271, we don't need to update the + * beacon_int and dtim_period, because the firmware + * updates it by itself when the first beacon is + * received after a join. + */ + ret = wl1271_cmd_build_ps_poll(wl, wl->aid); + if (ret < 0) + goto out_sleep; + + /* + * The SSID is intentionally set to NULL here - the + * firmware will set the probe request with a + * broadcast SSID regardless of what we set in the + * template. + */ + ret = wl1271_cmd_build_probe_req(wl, NULL, 0, + NULL, 0, wl->band); + + /* enable the connection monitoring feature */ + ret = wl1271_acx_conn_monit_params(wl, true); + if (ret < 0) + goto out_sleep; + + /* If we want to go in PSM but we're not there yet */ + if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) && + !test_bit(WL1271_FLAG_PSM, &wl->flags)) { + mode = STATION_POWER_SAVE_MODE; + ret = wl1271_ps_set_mode(wl, mode, + wl->basic_rate, + true); + if (ret < 0) + goto out_sleep; + } + } else { + /* use defaults when not associated */ + clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags); + clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags); + wl->aid = 0; + + /* re-enable dynamic ps - just in case */ + ieee80211_enable_dyn_ps(wl->vif); + + /* revert back to minimum rates for the current band */ + wl1271_set_band_rate(wl); + wl->basic_rate = wl1271_min_rate_get(wl); + ret = wl1271_acx_rate_policies(wl); + if (ret < 0) + goto out_sleep; + + /* disable connection monitor features */ + ret = wl1271_acx_conn_monit_params(wl, false); + + /* Disable the keep-alive feature */ + ret = wl1271_acx_keep_alive_mode(wl, false); + + if (ret < 0) + goto out_sleep; + } + + } + + if (changed & BSS_CHANGED_ERP_SLOT) { + if (bss_conf->use_short_slot) + ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT); + else + ret = wl1271_acx_slot(wl, SLOT_TIME_LONG); + if (ret < 0) { + wl1271_warning("Set slot time failed %d", ret); + goto out_sleep; + } + } + + if (changed & BSS_CHANGED_ERP_PREAMBLE) { + if (bss_conf->use_short_preamble) + wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT); + else + wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG); + } + + if (changed & BSS_CHANGED_ERP_CTS_PROT) { + if (bss_conf->use_cts_prot) + ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE); + else + ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE); + if (ret < 0) { + wl1271_warning("Set ctsprotect failed %d", ret); + goto out_sleep; + } + } + + /* + * Takes care of: New association with HT enable, + * HT information change in beacon. + */ + if (sta && + (changed & BSS_CHANGED_HT) && + (bss_conf->channel_type != NL80211_CHAN_NO_HT)) { + ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true); + if (ret < 0) { + wl1271_warning("Set ht cap true failed %d", ret); + goto out_sleep; + } + ret = wl1271_acx_set_ht_information(wl, + bss_conf->ht_operation_mode); + if (ret < 0) { + wl1271_warning("Set ht information failed %d", ret); + goto out_sleep; + } + } + /* + * Takes care of: New association without HT, + * Disassociation. + */ + else if (sta && (changed & BSS_CHANGED_ASSOC)) { + ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, false); + if (ret < 0) { + wl1271_warning("Set ht cap false failed %d", ret); + goto out_sleep; + } + } + + if (changed & BSS_CHANGED_ARP_FILTER) { + __be32 addr = bss_conf->arp_addr_list[0]; + WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS); + + if (bss_conf->arp_addr_cnt == 1 && bss_conf->arp_filter_enabled) + ret = wl1271_acx_arp_ip_filter(wl, true, addr); + else + ret = wl1271_acx_arp_ip_filter(wl, false, addr); + + if (ret < 0) + goto out_sleep; + } + + if (do_join) { + ret = wl1271_join(wl, set_assoc); + if (ret < 0) { + wl1271_warning("cmd join failed %d", ret); + goto out_sleep; + } + } + +out_sleep: + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); +} + +static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue, + const struct ieee80211_tx_queue_params *params) +{ + struct wl1271 *wl = hw->priv; + u8 ps_scheme; + int ret; + + mutex_lock(&wl->mutex); + + wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue); + + if (unlikely(wl->state == WL1271_STATE_OFF)) { + ret = -EAGAIN; + goto out; + } + + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out; + + /* the txop is confed in units of 32us by the mac80211, we need us */ + ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue), + params->cw_min, params->cw_max, + params->aifs, params->txop << 5); + if (ret < 0) + goto out_sleep; + + if (params->uapsd) + ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER; + else + ps_scheme = CONF_PS_SCHEME_LEGACY; + + ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue), + CONF_CHANNEL_TYPE_EDCF, + wl1271_tx_get_queue(queue), + ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0); + if (ret < 0) + goto out_sleep; + +out_sleep: + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + + return ret; +} + +static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw) +{ + + struct wl1271 *wl = hw->priv; + u64 mactime = ULLONG_MAX; + int ret; + + wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf"); + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state == WL1271_STATE_OFF)) + goto out; + + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out; + + ret = wl1271_acx_tsf_info(wl, &mactime); + if (ret < 0) + goto out_sleep; + +out_sleep: + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + return mactime; +} + +static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx, + struct survey_info *survey) +{ + struct wl1271 *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_rate wl1271_rates[] = { + { .bitrate = 10, + .hw_value = CONF_HW_BIT_RATE_1MBPS, + .hw_value_short = CONF_HW_BIT_RATE_1MBPS, }, + { .bitrate = 20, + .hw_value = CONF_HW_BIT_RATE_2MBPS, + .hw_value_short = CONF_HW_BIT_RATE_2MBPS, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 55, + .hw_value = CONF_HW_BIT_RATE_5_5MBPS, + .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 110, + .hw_value = CONF_HW_BIT_RATE_11MBPS, + .hw_value_short = CONF_HW_BIT_RATE_11MBPS, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 60, + .hw_value = CONF_HW_BIT_RATE_6MBPS, + .hw_value_short = CONF_HW_BIT_RATE_6MBPS, }, + { .bitrate = 90, + .hw_value = CONF_HW_BIT_RATE_9MBPS, + .hw_value_short = CONF_HW_BIT_RATE_9MBPS, }, + { .bitrate = 120, + .hw_value = CONF_HW_BIT_RATE_12MBPS, + .hw_value_short = CONF_HW_BIT_RATE_12MBPS, }, + { .bitrate = 180, + .hw_value = CONF_HW_BIT_RATE_18MBPS, + .hw_value_short = CONF_HW_BIT_RATE_18MBPS, }, + { .bitrate = 240, + .hw_value = CONF_HW_BIT_RATE_24MBPS, + .hw_value_short = CONF_HW_BIT_RATE_24MBPS, }, + { .bitrate = 360, + .hw_value = CONF_HW_BIT_RATE_36MBPS, + .hw_value_short = CONF_HW_BIT_RATE_36MBPS, }, + { .bitrate = 480, + .hw_value = CONF_HW_BIT_RATE_48MBPS, + .hw_value_short = CONF_HW_BIT_RATE_48MBPS, }, + { .bitrate = 540, + .hw_value = CONF_HW_BIT_RATE_54MBPS, + .hw_value_short = CONF_HW_BIT_RATE_54MBPS, }, +}; + +/* + * Can't be const, mac80211 writes to this. The order of the channels here + * is designed to improve scanning. + */ +static struct ieee80211_channel wl1271_channels[] = { + { .hw_value = 1, .center_freq = 2412, .max_power = 25 }, + { .hw_value = 5, .center_freq = 2432, .max_power = 25 }, + { .hw_value = 9, .center_freq = 2452, .max_power = 25 }, + { .hw_value = 13, .center_freq = 2472, .max_power = 25 }, + { .hw_value = 4, .center_freq = 2427, .max_power = 25 }, + { .hw_value = 8, .center_freq = 2447, .max_power = 25 }, + { .hw_value = 12, .center_freq = 2467, .max_power = 25 }, + { .hw_value = 3, .center_freq = 2422, .max_power = 25 }, + { .hw_value = 7, .center_freq = 2442, .max_power = 25 }, + { .hw_value = 11, .center_freq = 2462, .max_power = 25 }, + { .hw_value = 2, .center_freq = 2417, .max_power = 25 }, + { .hw_value = 6, .center_freq = 2437, .max_power = 25 }, + { .hw_value = 10, .center_freq = 2457, .max_power = 25 }, +}; + +/* mapping to indexes for wl1271_rates */ +static const u8 wl1271_rate_to_idx_2ghz[] = { + /* MCS rates are used only with 11n */ + 7, /* CONF_HW_RXTX_RATE_MCS7 */ + 6, /* CONF_HW_RXTX_RATE_MCS6 */ + 5, /* CONF_HW_RXTX_RATE_MCS5 */ + 4, /* CONF_HW_RXTX_RATE_MCS4 */ + 3, /* CONF_HW_RXTX_RATE_MCS3 */ + 2, /* CONF_HW_RXTX_RATE_MCS2 */ + 1, /* CONF_HW_RXTX_RATE_MCS1 */ + 0, /* CONF_HW_RXTX_RATE_MCS0 */ + + 11, /* CONF_HW_RXTX_RATE_54 */ + 10, /* CONF_HW_RXTX_RATE_48 */ + 9, /* CONF_HW_RXTX_RATE_36 */ + 8, /* CONF_HW_RXTX_RATE_24 */ + + /* TI-specific rate */ + CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */ + + 7, /* CONF_HW_RXTX_RATE_18 */ + 6, /* CONF_HW_RXTX_RATE_12 */ + 3, /* CONF_HW_RXTX_RATE_11 */ + 5, /* CONF_HW_RXTX_RATE_9 */ + 4, /* CONF_HW_RXTX_RATE_6 */ + 2, /* CONF_HW_RXTX_RATE_5_5 */ + 1, /* CONF_HW_RXTX_RATE_2 */ + 0 /* CONF_HW_RXTX_RATE_1 */ +}; + +/* 11n STA capabilities */ +#define HW_RX_HIGHEST_RATE 72 + +#ifdef CONFIG_WL12XX_HT +#define WL12XX_HT_CAP { \ + .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \ + .ht_supported = true, \ + .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \ + .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \ + .mcs = { \ + .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \ + .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \ + .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \ + }, \ +} +#else +#define WL12XX_HT_CAP { \ + .ht_supported = false, \ +} +#endif + +/* can't be const, mac80211 writes to this */ +static struct ieee80211_supported_band wl1271_band_2ghz = { + .channels = wl1271_channels, + .n_channels = ARRAY_SIZE(wl1271_channels), + .bitrates = wl1271_rates, + .n_bitrates = ARRAY_SIZE(wl1271_rates), + .ht_cap = WL12XX_HT_CAP, +}; + +/* 5 GHz data rates for WL1273 */ +static struct ieee80211_rate wl1271_rates_5ghz[] = { + { .bitrate = 60, + .hw_value = CONF_HW_BIT_RATE_6MBPS, + .hw_value_short = CONF_HW_BIT_RATE_6MBPS, }, + { .bitrate = 90, + .hw_value = CONF_HW_BIT_RATE_9MBPS, + .hw_value_short = CONF_HW_BIT_RATE_9MBPS, }, + { .bitrate = 120, + .hw_value = CONF_HW_BIT_RATE_12MBPS, + .hw_value_short = CONF_HW_BIT_RATE_12MBPS, }, + { .bitrate = 180, + .hw_value = CONF_HW_BIT_RATE_18MBPS, + .hw_value_short = CONF_HW_BIT_RATE_18MBPS, }, + { .bitrate = 240, + .hw_value = CONF_HW_BIT_RATE_24MBPS, + .hw_value_short = CONF_HW_BIT_RATE_24MBPS, }, + { .bitrate = 360, + .hw_value = CONF_HW_BIT_RATE_36MBPS, + .hw_value_short = CONF_HW_BIT_RATE_36MBPS, }, + { .bitrate = 480, + .hw_value = CONF_HW_BIT_RATE_48MBPS, + .hw_value_short = CONF_HW_BIT_RATE_48MBPS, }, + { .bitrate = 540, + .hw_value = CONF_HW_BIT_RATE_54MBPS, + .hw_value_short = CONF_HW_BIT_RATE_54MBPS, }, +}; + +/* + * 5 GHz band channels for WL1273 - can't be const, mac80211 writes to this. + * The order of the channels here is designed to improve scanning. + */ +static struct ieee80211_channel wl1271_channels_5ghz[] = { + { .hw_value = 183, .center_freq = 4915}, + { .hw_value = 188, .center_freq = 4940}, + { .hw_value = 8, .center_freq = 5040}, + { .hw_value = 34, .center_freq = 5170}, + { .hw_value = 44, .center_freq = 5220}, + { .hw_value = 60, .center_freq = 5300}, + { .hw_value = 112, .center_freq = 5560}, + { .hw_value = 132, .center_freq = 5660}, + { .hw_value = 157, .center_freq = 5785}, + { .hw_value = 184, .center_freq = 4920}, + { .hw_value = 189, .center_freq = 4945}, + { .hw_value = 9, .center_freq = 5045}, + { .hw_value = 36, .center_freq = 5180}, + { .hw_value = 46, .center_freq = 5230}, + { .hw_value = 64, .center_freq = 5320}, + { .hw_value = 116, .center_freq = 5580}, + { .hw_value = 136, .center_freq = 5680}, + { .hw_value = 192, .center_freq = 4960}, + { .hw_value = 11, .center_freq = 5055}, + { .hw_value = 38, .center_freq = 5190}, + { .hw_value = 48, .center_freq = 5240}, + { .hw_value = 100, .center_freq = 5500}, + { .hw_value = 120, .center_freq = 5600}, + { .hw_value = 140, .center_freq = 5700}, + { .hw_value = 185, .center_freq = 4925}, + { .hw_value = 196, .center_freq = 4980}, + { .hw_value = 12, .center_freq = 5060}, + { .hw_value = 40, .center_freq = 5200}, + { .hw_value = 52, .center_freq = 5260}, + { .hw_value = 104, .center_freq = 5520}, + { .hw_value = 124, .center_freq = 5620}, + { .hw_value = 149, .center_freq = 5745}, + { .hw_value = 161, .center_freq = 5805}, + { .hw_value = 187, .center_freq = 4935}, + { .hw_value = 7, .center_freq = 5035}, + { .hw_value = 16, .center_freq = 5080}, + { .hw_value = 42, .center_freq = 5210}, + { .hw_value = 56, .center_freq = 5280}, + { .hw_value = 108, .center_freq = 5540}, + { .hw_value = 128, .center_freq = 5640}, + { .hw_value = 153, .center_freq = 5765}, + { .hw_value = 165, .center_freq = 5825}, +}; + +/* mapping to indexes for wl1271_rates_5ghz */ +static const u8 wl1271_rate_to_idx_5ghz[] = { + /* MCS rates are used only with 11n */ + 7, /* CONF_HW_RXTX_RATE_MCS7 */ + 6, /* CONF_HW_RXTX_RATE_MCS6 */ + 5, /* CONF_HW_RXTX_RATE_MCS5 */ + 4, /* CONF_HW_RXTX_RATE_MCS4 */ + 3, /* CONF_HW_RXTX_RATE_MCS3 */ + 2, /* CONF_HW_RXTX_RATE_MCS2 */ + 1, /* CONF_HW_RXTX_RATE_MCS1 */ + 0, /* CONF_HW_RXTX_RATE_MCS0 */ + + 7, /* CONF_HW_RXTX_RATE_54 */ + 6, /* CONF_HW_RXTX_RATE_48 */ + 5, /* CONF_HW_RXTX_RATE_36 */ + 4, /* CONF_HW_RXTX_RATE_24 */ + + /* TI-specific rate */ + CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */ + + 3, /* CONF_HW_RXTX_RATE_18 */ + 2, /* CONF_HW_RXTX_RATE_12 */ + CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */ + 1, /* CONF_HW_RXTX_RATE_9 */ + 0, /* CONF_HW_RXTX_RATE_6 */ + CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */ + CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */ + CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */ +}; + +static struct ieee80211_supported_band wl1271_band_5ghz = { + .channels = wl1271_channels_5ghz, + .n_channels = ARRAY_SIZE(wl1271_channels_5ghz), + .bitrates = wl1271_rates_5ghz, + .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz), + .ht_cap = WL12XX_HT_CAP, +}; + +static const u8 *wl1271_band_rate_to_idx[] = { + [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz, + [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz +}; + +static const struct ieee80211_ops wl1271_ops = { + .start = wl1271_op_start, + .stop = wl1271_op_stop, + .add_interface = wl1271_op_add_interface, + .remove_interface = wl1271_op_remove_interface, + .config = wl1271_op_config, + .prepare_multicast = wl1271_op_prepare_multicast, + .configure_filter = wl1271_op_configure_filter, + .tx = wl1271_op_tx, + .set_key = wl1271_op_set_key, + .hw_scan = wl1271_op_hw_scan, + .bss_info_changed = wl1271_op_bss_info_changed, + .set_rts_threshold = wl1271_op_set_rts_threshold, + .conf_tx = wl1271_op_conf_tx, + .get_tsf = wl1271_op_get_tsf, + .get_survey = wl1271_op_get_survey, + CFG80211_TESTMODE_CMD(wl1271_tm_cmd) +}; + + +u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band) +{ + u8 idx; + + BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *)); + + if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) { + wl1271_error("Illegal RX rate from HW: %d", rate); + return 0; + } + + idx = wl1271_band_rate_to_idx[band][rate]; + if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) { + wl1271_error("Unsupported RX rate from HW: %d", rate); + return 0; + } + + return idx; +} + +static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct wl1271 *wl = dev_get_drvdata(dev); + ssize_t len; + + len = PAGE_SIZE; + + mutex_lock(&wl->mutex); + len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n", + wl->sg_enabled); + mutex_unlock(&wl->mutex); + + return len; + +} + +static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct wl1271 *wl = dev_get_drvdata(dev); + unsigned long res; + int ret; + + ret = strict_strtoul(buf, 10, &res); + + if (ret < 0) { + wl1271_warning("incorrect value written to bt_coex_mode"); + return count; + } + + mutex_lock(&wl->mutex); + + res = !!res; + + if (res == wl->sg_enabled) + goto out; + + wl->sg_enabled = res; + + if (wl->state == WL1271_STATE_OFF) + goto out; + + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out; + + wl1271_acx_sg_enable(wl, wl->sg_enabled); + wl1271_ps_elp_sleep(wl); + + out: + mutex_unlock(&wl->mutex); + return count; +} + +static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR, + wl1271_sysfs_show_bt_coex_state, + wl1271_sysfs_store_bt_coex_state); + +static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct wl1271 *wl = dev_get_drvdata(dev); + ssize_t len; + + len = PAGE_SIZE; + + mutex_lock(&wl->mutex); + if (wl->hw_pg_ver >= 0) + len = snprintf(buf, len, "%d\n", wl->hw_pg_ver); + else + len = snprintf(buf, len, "n/a\n"); + mutex_unlock(&wl->mutex); + + return len; +} + +static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR, + wl1271_sysfs_show_hw_pg_ver, NULL); + +int wl1271_register_hw(struct wl1271 *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) { + wl1271_error("unable to register mac80211 hw: %d", ret); + return ret; + } + + wl->mac80211_registered = true; + + register_netdevice_notifier(&wl1271_dev_notifier); + + wl1271_notice("loaded"); + + return 0; +} +EXPORT_SYMBOL_GPL(wl1271_register_hw); + +void wl1271_unregister_hw(struct wl1271 *wl) +{ + unregister_netdevice_notifier(&wl1271_dev_notifier); + ieee80211_unregister_hw(wl->hw); + wl->mac80211_registered = false; + +} +EXPORT_SYMBOL_GPL(wl1271_unregister_hw); + +int wl1271_init_ieee80211(struct wl1271 *wl) +{ + static const u32 cipher_suites[] = { + WLAN_CIPHER_SUITE_WEP40, + WLAN_CIPHER_SUITE_WEP104, + WLAN_CIPHER_SUITE_TKIP, + WLAN_CIPHER_SUITE_CCMP, + WL1271_CIPHER_SUITE_GEM, + }; + + /* The tx descriptor buffer and the TKIP space. */ + wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE + + sizeof(struct wl1271_tx_hw_descr); + + /* unit us */ + /* FIXME: find a proper value */ + wl->hw->channel_change_time = 10000; + wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval; + + wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_BEACON_FILTER | + IEEE80211_HW_SUPPORTS_PS | + IEEE80211_HW_SUPPORTS_UAPSD | + IEEE80211_HW_HAS_RATE_CONTROL | + IEEE80211_HW_CONNECTION_MONITOR | + IEEE80211_HW_SUPPORTS_CQM_RSSI; + + wl->hw->wiphy->cipher_suites = cipher_suites; + wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); + + wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC); + wl->hw->wiphy->max_scan_ssids = 1; + wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz; + wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz; + + wl->hw->queues = 4; + wl->hw->max_rates = 1; + + SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl)); + + return 0; +} +EXPORT_SYMBOL_GPL(wl1271_init_ieee80211); + +#define WL1271_DEFAULT_CHANNEL 0 + +struct ieee80211_hw *wl1271_alloc_hw(void) +{ + struct ieee80211_hw *hw; + struct platform_device *plat_dev = NULL; + struct wl1271 *wl; + int i, ret; + unsigned int order; + + hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops); + if (!hw) { + wl1271_error("could not alloc ieee80211_hw"); + ret = -ENOMEM; + goto err_hw_alloc; + } + + plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL); + if (!plat_dev) { + wl1271_error("could not allocate platform_device"); + ret = -ENOMEM; + goto err_plat_alloc; + } + + wl = hw->priv; + memset(wl, 0, sizeof(*wl)); + + INIT_LIST_HEAD(&wl->list); + + wl->hw = hw; + wl->plat_dev = plat_dev; + + skb_queue_head_init(&wl->tx_queue); + + INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work); + INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work); + INIT_WORK(&wl->irq_work, wl1271_irq_work); + INIT_WORK(&wl->tx_work, wl1271_tx_work); + INIT_WORK(&wl->recovery_work, wl1271_recovery_work); + INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work); + wl->channel = WL1271_DEFAULT_CHANNEL; + wl->beacon_int = WL1271_DEFAULT_BEACON_INT; + wl->default_key = 0; + wl->rx_counter = 0; + wl->rx_config = WL1271_DEFAULT_RX_CONFIG; + wl->rx_filter = WL1271_DEFAULT_RX_FILTER; + wl->psm_entry_retry = 0; + wl->power_level = WL1271_DEFAULT_POWER_LEVEL; + wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC; + wl->basic_rate = CONF_TX_RATE_MASK_BASIC; + wl->rate_set = CONF_TX_RATE_MASK_BASIC; + wl->sta_rate_set = 0; + wl->band = IEEE80211_BAND_2GHZ; + wl->vif = NULL; + wl->flags = 0; + wl->sg_enabled = true; + wl->hw_pg_ver = -1; + + memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map)); + for (i = 0; i < ACX_TX_DESCRIPTORS; i++) + wl->tx_frames[i] = NULL; + + spin_lock_init(&wl->wl_lock); + + wl->state = WL1271_STATE_OFF; + mutex_init(&wl->mutex); + + /* Apply default driver configuration. */ + wl1271_conf_init(wl); + + wl1271_debugfs_init(wl); + + order = get_order(WL1271_AGGR_BUFFER_SIZE); + wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order); + if (!wl->aggr_buf) { + ret = -ENOMEM; + goto err_hw; + } + + /* Register platform device */ + ret = platform_device_register(wl->plat_dev); + if (ret) { + wl1271_error("couldn't register platform device"); + goto err_aggr; + } + dev_set_drvdata(&wl->plat_dev->dev, wl); + + /* Create sysfs file to control bt coex state */ + ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state); + if (ret < 0) { + wl1271_error("failed to create sysfs file bt_coex_state"); + goto err_platform; + } + + /* Create sysfs file to get HW PG version */ + ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver); + if (ret < 0) { + wl1271_error("failed to create sysfs file hw_pg_ver"); + goto err_bt_coex_state; + } + + return hw; + +err_bt_coex_state: + device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state); + +err_platform: + platform_device_unregister(wl->plat_dev); + +err_aggr: + free_pages((unsigned long)wl->aggr_buf, order); + +err_hw: + wl1271_debugfs_exit(wl); + kfree(plat_dev); + +err_plat_alloc: + ieee80211_free_hw(hw); + +err_hw_alloc: + + return ERR_PTR(ret); +} +EXPORT_SYMBOL_GPL(wl1271_alloc_hw); + +int wl1271_free_hw(struct wl1271 *wl) +{ + platform_device_unregister(wl->plat_dev); + free_pages((unsigned long)wl->aggr_buf, + get_order(WL1271_AGGR_BUFFER_SIZE)); + kfree(wl->plat_dev); + + wl1271_debugfs_exit(wl); + + vfree(wl->fw); + wl->fw = NULL; + kfree(wl->nvs); + wl->nvs = NULL; + + kfree(wl->fw_status); + kfree(wl->tx_res_if); + + ieee80211_free_hw(wl->hw); + + return 0; +} +EXPORT_SYMBOL_GPL(wl1271_free_hw); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Luciano Coelho "); +MODULE_AUTHOR("Juuso Oikarinen "); diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c new file mode 100644 index 0000000..60a3738 --- /dev/null +++ b/drivers/net/wireless/wl12xx/ps.c @@ -0,0 +1,178 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 "io.h" + +#define WL1271_WAKEUP_TIMEOUT 500 + +void wl1271_elp_work(struct work_struct *work) +{ + struct delayed_work *dwork; + struct wl1271 *wl; + + dwork = container_of(work, struct delayed_work, work); + wl = container_of(dwork, struct wl1271, elp_work); + + wl1271_debug(DEBUG_PSM, "elp work"); + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state == WL1271_STATE_OFF)) + goto out; + + if (test_bit(WL1271_FLAG_IN_ELP, &wl->flags) || + (!test_bit(WL1271_FLAG_PSM, &wl->flags) && + !test_bit(WL1271_FLAG_IDLE, &wl->flags))) + goto out; + + wl1271_debug(DEBUG_PSM, "chip to elp"); + wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); + set_bit(WL1271_FLAG_IN_ELP, &wl->flags); + +out: + mutex_unlock(&wl->mutex); +} + +#define ELP_ENTRY_DELAY 5 + +/* Routines to toggle sleep mode while in ELP */ +void wl1271_ps_elp_sleep(struct wl1271 *wl) +{ + if (test_bit(WL1271_FLAG_PSM, &wl->flags) || + test_bit(WL1271_FLAG_IDLE, &wl->flags)) { + cancel_delayed_work(&wl->elp_work); + ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, + msecs_to_jiffies(ELP_ENTRY_DELAY)); + } +} + +int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake) +{ + DECLARE_COMPLETION_ONSTACK(compl); + unsigned long flags; + int ret; + u32 start_time = jiffies; + bool pending = false; + + if (!test_bit(WL1271_FLAG_IN_ELP, &wl->flags)) + return 0; + + wl1271_debug(DEBUG_PSM, "waking up chip from elp"); + + /* + * The spinlock is required here to synchronize both the work and + * the completion variable in one entity. + */ + spin_lock_irqsave(&wl->wl_lock, flags); + if (work_pending(&wl->irq_work) || chip_awake) + pending = true; + else + wl->elp_compl = &compl; + spin_unlock_irqrestore(&wl->wl_lock, flags); + + wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP); + + if (!pending) { + ret = wait_for_completion_timeout( + &compl, msecs_to_jiffies(WL1271_WAKEUP_TIMEOUT)); + if (ret == 0) { + wl1271_error("ELP wakeup timeout!"); + ieee80211_queue_work(wl->hw, &wl->recovery_work); + ret = -ETIMEDOUT; + goto err; + } else if (ret < 0) { + wl1271_error("ELP wakeup completion error."); + goto err; + } + } + + clear_bit(WL1271_FLAG_IN_ELP, &wl->flags); + + wl1271_debug(DEBUG_PSM, "wakeup time: %u ms", + jiffies_to_msecs(jiffies - start_time)); + goto out; + +err: + spin_lock_irqsave(&wl->wl_lock, flags); + wl->elp_compl = NULL; + spin_unlock_irqrestore(&wl->wl_lock, flags); + return ret; + +out: + return 0; +} + +int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode, + u32 rates, bool send) +{ + int ret; + + switch (mode) { + case STATION_POWER_SAVE_MODE: + wl1271_debug(DEBUG_PSM, "entering psm"); + + ret = wl1271_acx_wake_up_conditions(wl); + if (ret < 0) { + wl1271_error("couldn't set wake up conditions"); + return ret; + } + + ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE, + rates, send); + if (ret < 0) + return ret; + + set_bit(WL1271_FLAG_PSM, &wl->flags); + break; + case STATION_ACTIVE_MODE: + default: + wl1271_debug(DEBUG_PSM, "leaving psm"); + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + return ret; + + /* disable beacon early termination */ + ret = wl1271_acx_bet_enable(wl, false); + if (ret < 0) + return ret; + + /* disable beacon filtering */ + ret = wl1271_acx_beacon_filter_opt(wl, false); + if (ret < 0) + return ret; + + ret = wl1271_cmd_ps_mode(wl, STATION_ACTIVE_MODE, + rates, send); + if (ret < 0) + return ret; + + clear_bit(WL1271_FLAG_PSM, &wl->flags); + break; + } + + return ret; +} + + diff --git a/drivers/net/wireless/wl12xx/ps.h b/drivers/net/wireless/wl12xx/ps.h new file mode 100644 index 0000000..8415060 --- /dev/null +++ b/drivers/net/wireless/wl12xx/ps.h @@ -0,0 +1,36 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 __PS_H__ +#define __PS_H__ + +#include "wl12xx.h" +#include "acx.h" + +int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode, + u32 rates, bool send); +void wl1271_ps_elp_sleep(struct wl1271 *wl); +int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake); +void wl1271_elp_work(struct work_struct *work); + +#endif /* __WL1271_PS_H__ */ diff --git a/drivers/net/wireless/wl12xx/reg.h b/drivers/net/wireless/wl12xx/reg.h new file mode 100644 index 0000000..9909607 --- /dev/null +++ b/drivers/net/wireless/wl12xx/reg.h @@ -0,0 +1,614 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 +#define FW_STATUS_ADDR (0x14FC0 + 0xA000) + +/* 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 + +/*=============================================== + 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. +===============================================*/ +#define ACX_REG_SLV_SOFT_RESET (REGISTERS_BASE + 0x0000) + +#define WL1271_SLV_REG_DATA (REGISTERS_BASE + 0x0008) +#define WL1271_SLV_REG_ADATA (REGISTERS_BASE + 0x000c) +#define WL1271_SLV_MEM_DATA (REGISTERS_BASE + 0x0018) + +#define ACX_REG_INTERRUPT_TRIG (REGISTERS_BASE + 0x0474) +#define ACX_REG_INTERRUPT_TRIG_H (REGISTERS_BASE + 0x0478) + +/*============================================= + 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 +*==============================================*/ +#define ACX_REG_INTERRUPT_MASK (REGISTERS_BASE + 0x04DC) + +/*============================================= + 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). +==============================================*/ +#define ACX_REG_HINT_MASK_SET (REGISTERS_BASE + 0x04E0) + +/*============================================= + 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). +=============================================*/ +#define ACX_REG_HINT_MASK_CLR (REGISTERS_BASE + 0x04E4) + +/*============================================= + 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. +=============================================*/ +#define ACX_REG_INTERRUPT_NO_CLEAR (REGISTERS_BASE + 0x04E8) + +/*============================================= + 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. +==============================================*/ +#define ACX_REG_INTERRUPT_CLEAR (REGISTERS_BASE + 0x04F8) + +/*============================================= + 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) +==============================================*/ +#define ACX_REG_INTERRUPT_ACK (REGISTERS_BASE + 0x04F0) + +#define RX_DRIVER_COUNTER_ADDRESS (REGISTERS_BASE + 0x0538) + +/* Device Configuration registers*/ +#define SOR_CFG (REGISTERS_BASE + 0x0800) + +/* 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 + ===============================================*/ +#define ACX_REG_ECPU_CONTROL (REGISTERS_BASE + 0x0804) + +#define HI_CFG (REGISTERS_BASE + 0x0808) + +/*=============================================== + 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 +*================================================*/ +#define ACX_REG_EE_START (REGISTERS_BASE + 0x080C) + +#define OCP_POR_CTR (REGISTERS_BASE + 0x09B4) +#define OCP_DATA_WRITE (REGISTERS_BASE + 0x09B8) +#define OCP_DATA_READ (REGISTERS_BASE + 0x09BC) +#define OCP_CMD (REGISTERS_BASE + 0x09C0) + +#define WL1271_HOST_WR_ACCESS (REGISTERS_BASE + 0x09F8) + +#define CHIP_ID_B (REGISTERS_BASE + 0x5674) + +#define CHIP_ID_1271_PG10 (0x4030101) +#define CHIP_ID_1271_PG20 (0x4030111) + +#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) + +#define PLL_PARAMETERS (REGISTERS_BASE + 0x6040) +#define WU_COUNTER_PAUSE (REGISTERS_BASE + 0x6008) +#define WELP_ARM_COMMAND (REGISTERS_BASE + 0x6100) +#define DRPW_SCRATCH_START (DRPW_BASE + 0x002C) + + +#define ACX_SLV_SOFT_RESET_BIT BIT(1) +#define ACX_REG_EEPROM_START_BIT BIT(1) + +/* 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 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 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 ACX_EE_DATA_REG EE_DATA + +/*=============================================== + 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 +}; + +#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/rx.c b/drivers/net/wireless/wl12xx/rx.c new file mode 100644 index 0000000..682304c --- /dev/null +++ b/drivers/net/wireless/wl12xx/rx.c @@ -0,0 +1,203 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 "wl12xx.h" +#include "acx.h" +#include "reg.h" +#include "rx.h" +#include "io.h" + +static u8 wl1271_rx_get_mem_block(struct wl1271_fw_status *status, + u32 drv_rx_counter) +{ + return le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) & + RX_MEM_BLOCK_MASK; +} + +static u32 wl1271_rx_get_buf_size(struct wl1271_fw_status *status, + u32 drv_rx_counter) +{ + return (le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) & + RX_BUF_SIZE_MASK) >> RX_BUF_SIZE_SHIFT_DIV; +} + +static void wl1271_rx_status(struct wl1271 *wl, + struct wl1271_rx_descriptor *desc, + struct ieee80211_rx_status *status, + u8 beacon) +{ + enum ieee80211_band desc_band; + + memset(status, 0, sizeof(struct ieee80211_rx_status)); + + status->band = wl->band; + + if ((desc->flags & WL1271_RX_DESC_BAND_MASK) == WL1271_RX_DESC_BAND_BG) + desc_band = IEEE80211_BAND_2GHZ; + else + desc_band = IEEE80211_BAND_5GHZ; + + status->rate_idx = wl1271_rate_to_idx(desc->rate, desc_band); + +#ifdef CONFIG_WL12XX_HT + /* 11n support */ + if (desc->rate <= CONF_HW_RXTX_RATE_MCS0) + status->flag |= RX_FLAG_HT; +#endif + + status->signal = desc->rssi; + + /* + * FIXME: In wl1251, the SNR should be divided by two. In wl1271 we + * need to divide by two for now, but TI has been discussing about + * changing it. This needs to be rechecked. + */ + wl->noise = desc->rssi - (desc->snr >> 1); + + status->freq = ieee80211_channel_to_frequency(desc->channel); + + if (desc->flags & WL1271_RX_DESC_ENCRYPT_MASK) { + status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; + + if (likely(!(desc->status & WL1271_RX_DESC_DECRYPT_FAIL))) + status->flag |= RX_FLAG_DECRYPTED; + if (unlikely(desc->status & WL1271_RX_DESC_MIC_FAIL)) + status->flag |= RX_FLAG_MMIC_ERROR; + } +} + +static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length) +{ + struct wl1271_rx_descriptor *desc; + struct sk_buff *skb; + u16 *fc; + u8 *buf; + u8 beacon = 0; + + /* + * In PLT mode we seem to get frames and mac80211 warns about them, + * workaround this by not retrieving them at all. + */ + if (unlikely(wl->state == WL1271_STATE_PLT)) + return -EINVAL; + + skb = __dev_alloc_skb(length, GFP_KERNEL); + if (!skb) { + wl1271_error("Couldn't allocate RX frame"); + return -ENOMEM; + } + + buf = skb_put(skb, length); + memcpy(buf, data, length); + + /* the data read starts with the descriptor */ + desc = (struct wl1271_rx_descriptor *) buf; + + /* now we pull the descriptor out of the buffer */ + skb_pull(skb, sizeof(*desc)); + + fc = (u16 *)skb->data; + if ((*fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) + beacon = 1; + + wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon); + + wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len, + beacon ? "beacon" : ""); + + skb_trim(skb, skb->len - desc->pad_len); + + ieee80211_rx_ni(wl->hw, skb); + + return 0; +} + +void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status) +{ + struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map; + u32 buf_size; + u32 fw_rx_counter = status->fw_rx_counter & NUM_RX_PKT_DESC_MOD_MASK; + u32 drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK; + u32 rx_counter; + u32 mem_block; + u32 pkt_length; + u32 pkt_offset; + + while (drv_rx_counter != fw_rx_counter) { + buf_size = 0; + rx_counter = drv_rx_counter; + while (rx_counter != fw_rx_counter) { + pkt_length = wl1271_rx_get_buf_size(status, rx_counter); + if (buf_size + pkt_length > WL1271_AGGR_BUFFER_SIZE) + break; + buf_size += pkt_length; + rx_counter++; + rx_counter &= NUM_RX_PKT_DESC_MOD_MASK; + } + + if (buf_size == 0) { + wl1271_warning("received empty data"); + break; + } + + /* + * Choose the block we want to read + * For aggregated packets, only the first memory block should + * be retrieved. The FW takes care of the rest. + */ + mem_block = wl1271_rx_get_mem_block(status, drv_rx_counter); + wl->rx_mem_pool_addr.addr = (mem_block << 8) + + le32_to_cpu(wl_mem_map->packet_memory_pool_start); + wl->rx_mem_pool_addr.addr_extra = + wl->rx_mem_pool_addr.addr + 4; + wl1271_write(wl, WL1271_SLV_REG_DATA, &wl->rx_mem_pool_addr, + sizeof(wl->rx_mem_pool_addr), false); + + /* Read all available packets at once */ + wl1271_read(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, + buf_size, true); + + /* Split data into separate packets */ + pkt_offset = 0; + while (pkt_offset < buf_size) { + pkt_length = wl1271_rx_get_buf_size(status, + drv_rx_counter); + /* + * the handle data call can only fail in memory-outage + * conditions, in that case the received frame will just + * be dropped. + */ + wl1271_rx_handle_data(wl, + wl->aggr_buf + pkt_offset, + pkt_length); + wl->rx_counter++; + drv_rx_counter++; + drv_rx_counter &= NUM_RX_PKT_DESC_MOD_MASK; + pkt_offset += pkt_length; + } + } + wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, + cpu_to_le32(wl->rx_counter)); +} diff --git a/drivers/net/wireless/wl12xx/rx.h b/drivers/net/wireless/wl12xx/rx.h new file mode 100644 index 0000000..3abb26f --- /dev/null +++ b/drivers/net/wireless/wl12xx/rx.h @@ -0,0 +1,121 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 __RX_H__ +#define __RX_H__ + +#include + +#define WL1271_RX_MAX_RSSI -30 +#define WL1271_RX_MIN_RSSI -95 + +#define WL1271_RX_ALIGN_TO 4 +#define WL1271_RX_ALIGN(len) (((len) + WL1271_RX_ALIGN_TO - 1) & \ + ~(WL1271_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 NUM_RX_PKT_DESC_MOD_MASK 7 + +#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 + +/* + * RX Descriptor flags: + * + * Bits 0-1 - band + * Bit 2 - STBC + * Bit 3 - A-MPDU + * Bit 4 - HT + * Bits 5-7 - encryption + */ +#define WL1271_RX_DESC_BAND_MASK 0x03 +#define WL1271_RX_DESC_ENCRYPT_MASK 0xE0 + +#define WL1271_RX_DESC_BAND_BG 0x00 +#define WL1271_RX_DESC_BAND_J 0x01 +#define WL1271_RX_DESC_BAND_A 0x02 + +#define WL1271_RX_DESC_STBC BIT(2) +#define WL1271_RX_DESC_A_MPDU BIT(3) +#define WL1271_RX_DESC_HT BIT(4) + +#define WL1271_RX_DESC_ENCRYPT_WEP 0x20 +#define WL1271_RX_DESC_ENCRYPT_TKIP 0x40 +#define WL1271_RX_DESC_ENCRYPT_AES 0x60 +#define WL1271_RX_DESC_ENCRYPT_GEM 0x80 + +/* + * RX Descriptor status + * + * Bits 0-2 - status + * Bits 3-7 - reserved + */ +#define WL1271_RX_DESC_STATUS_MASK 0x07 + +#define WL1271_RX_DESC_SUCCESS 0x00 +#define WL1271_RX_DESC_DECRYPT_FAIL 0x01 +#define WL1271_RX_DESC_MIC_FAIL 0x02 +#define WL1271_RX_DESC_DRIVER_RX_Q_FAIL 0x03 + +#define RX_MEM_BLOCK_MASK 0xFF +#define RX_BUF_SIZE_MASK 0xFFF00 +#define RX_BUF_SIZE_SHIFT_DIV 6 + +struct wl1271_rx_descriptor { + __le16 length; + u8 status; + u8 flags; + u8 rate; + u8 channel; + s8 rssi; + u8 snr; + __le32 timestamp; + u8 packet_class; + u8 process_id; + u8 pad_len; + u8 reserved; +} __packed; + +void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status); +u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band); + +#endif diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c new file mode 100644 index 0000000..f3f2c5b --- /dev/null +++ b/drivers/net/wireless/wl12xx/scan.c @@ -0,0 +1,307 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2009-2010 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 "wl12xx.h" +#include "cmd.h" +#include "scan.h" +#include "acx.h" + +void wl1271_scan_complete_work(struct work_struct *work) +{ + struct delayed_work *dwork; + struct wl1271 *wl; + + dwork = container_of(work, struct delayed_work, work); + wl = container_of(dwork, struct wl1271, scan_complete_work); + + wl1271_debug(DEBUG_SCAN, "Scanning complete"); + + mutex_lock(&wl->mutex); + + if (wl->scan.state == WL1271_SCAN_STATE_IDLE) { + mutex_unlock(&wl->mutex); + return; + } + + wl->scan.state = WL1271_SCAN_STATE_IDLE; + kfree(wl->scan.scanned_ch); + wl->scan.scanned_ch = NULL; + wl->scan.req = NULL; + ieee80211_scan_completed(wl->hw, false); + + if (wl->scan.failed) { + wl1271_info("Scan completed due to error."); + ieee80211_queue_work(wl->hw, &wl->recovery_work); + } + mutex_unlock(&wl->mutex); + +} + + +static int wl1271_get_scan_channels(struct wl1271 *wl, + struct cfg80211_scan_request *req, + struct basic_scan_channel_params *channels, + enum ieee80211_band band, bool passive) +{ + struct conf_scan_settings *c = &wl->conf.scan; + int i, j; + u32 flags; + + for (i = 0, j = 0; + i < req->n_channels && j < WL1271_SCAN_MAX_CHANNELS; + i++) { + + flags = req->channels[i]->flags; + + if (!wl->scan.scanned_ch[i] && + !(flags & IEEE80211_CHAN_DISABLED) && + ((!!(flags & IEEE80211_CHAN_PASSIVE_SCAN)) == passive) && + (req->channels[i]->band == band)) { + + wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ", + req->channels[i]->band, + req->channels[i]->center_freq); + wl1271_debug(DEBUG_SCAN, "hw_value %d, flags %X", + req->channels[i]->hw_value, + req->channels[i]->flags); + wl1271_debug(DEBUG_SCAN, + "max_antenna_gain %d, max_power %d", + req->channels[i]->max_antenna_gain, + req->channels[i]->max_power); + wl1271_debug(DEBUG_SCAN, "beacon_found %d", + req->channels[i]->beacon_found); + + if (!passive) { + channels[j].min_duration = + cpu_to_le32(c->min_dwell_time_active); + channels[j].max_duration = + cpu_to_le32(c->max_dwell_time_active); + } else { + channels[j].min_duration = + cpu_to_le32(c->min_dwell_time_passive); + channels[j].max_duration = + cpu_to_le32(c->max_dwell_time_passive); + } + channels[j].early_termination = 0; + channels[j].tx_power_att = req->channels[i]->max_power; + channels[j].channel = req->channels[i]->hw_value; + + memset(&channels[j].bssid_lsb, 0xff, 4); + memset(&channels[j].bssid_msb, 0xff, 2); + + /* Mark the channels we already used */ + wl->scan.scanned_ch[i] = true; + + j++; + } + } + + return j; +} + +#define WL1271_NOTHING_TO_SCAN 1 + +static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band, + bool passive, u32 basic_rate) +{ + struct wl1271_cmd_scan *cmd; + struct wl1271_cmd_trigger_scan_to *trigger; + int ret; + u16 scan_options = 0; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + trigger = kzalloc(sizeof(*trigger), GFP_KERNEL); + if (!cmd || !trigger) { + ret = -ENOMEM; + goto out; + } + + /* We always use high priority scans */ + scan_options = WL1271_SCAN_OPT_PRIORITY_HIGH; + + /* No SSIDs means that we have a forced passive scan */ + if (passive || wl->scan.req->n_ssids == 0) + scan_options |= WL1271_SCAN_OPT_PASSIVE; + + cmd->params.scan_options = cpu_to_le16(scan_options); + + cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req, + cmd->channels, + band, passive); + if (cmd->params.n_ch == 0) { + ret = WL1271_NOTHING_TO_SCAN; + goto out; + } + + cmd->params.tx_rate = cpu_to_le32(basic_rate); + 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.n_probe_reqs = wl->conf.scan.num_probe_reqs; + cmd->params.tx_rate = cpu_to_le32(basic_rate); + cmd->params.tid_trigger = 0; + cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG; + + if (band == IEEE80211_BAND_2GHZ) + cmd->params.band = WL1271_SCAN_BAND_2_4_GHZ; + else + cmd->params.band = WL1271_SCAN_BAND_5_GHZ; + + if (wl->scan.ssid_len && wl->scan.ssid) { + cmd->params.ssid_len = wl->scan.ssid_len; + memcpy(cmd->params.ssid, wl->scan.ssid, wl->scan.ssid_len); + } + + ret = wl1271_cmd_build_probe_req(wl, wl->scan.ssid, wl->scan.ssid_len, + wl->scan.req->ie, wl->scan.req->ie_len, + band); + if (ret < 0) { + wl1271_error("PROBE request template failed"); + goto out; + } + + /* disable the timeout */ + trigger->timeout = 0; + ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, + sizeof(*trigger), 0); + if (ret < 0) { + wl1271_error("trigger scan to failed for hw scan"); + goto out; + } + + wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd)); + + ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("SCAN failed"); + goto out; + } + +out: + kfree(cmd); + kfree(trigger); + return ret; +} + +void wl1271_scan_stm(struct wl1271 *wl) +{ + int ret = 0; + + switch (wl->scan.state) { + case WL1271_SCAN_STATE_IDLE: + break; + + case WL1271_SCAN_STATE_2GHZ_ACTIVE: + ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, false, + wl->conf.tx.basic_rate); + if (ret == WL1271_NOTHING_TO_SCAN) { + wl->scan.state = WL1271_SCAN_STATE_2GHZ_PASSIVE; + wl1271_scan_stm(wl); + } + + break; + + case WL1271_SCAN_STATE_2GHZ_PASSIVE: + ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, true, + wl->conf.tx.basic_rate); + if (ret == WL1271_NOTHING_TO_SCAN) { + if (wl->enable_11a) + wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE; + else + wl->scan.state = WL1271_SCAN_STATE_DONE; + wl1271_scan_stm(wl); + } + + break; + + case WL1271_SCAN_STATE_5GHZ_ACTIVE: + ret = wl1271_scan_send(wl, IEEE80211_BAND_5GHZ, false, + wl->conf.tx.basic_rate_5); + if (ret == WL1271_NOTHING_TO_SCAN) { + wl->scan.state = WL1271_SCAN_STATE_5GHZ_PASSIVE; + wl1271_scan_stm(wl); + } + + break; + + case WL1271_SCAN_STATE_5GHZ_PASSIVE: + ret = wl1271_scan_send(wl, IEEE80211_BAND_5GHZ, true, + wl->conf.tx.basic_rate_5); + if (ret == WL1271_NOTHING_TO_SCAN) { + wl->scan.state = WL1271_SCAN_STATE_DONE; + wl1271_scan_stm(wl); + } + + break; + + case WL1271_SCAN_STATE_DONE: + wl->scan.failed = false; + cancel_delayed_work(&wl->scan_complete_work); + ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, + msecs_to_jiffies(0)); + break; + + default: + wl1271_error("invalid scan state"); + break; + } + + if (ret < 0) { + cancel_delayed_work(&wl->scan_complete_work); + ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, + msecs_to_jiffies(0)); + } +} + +int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, + struct cfg80211_scan_request *req) +{ + if (wl->scan.state != WL1271_SCAN_STATE_IDLE) + return -EBUSY; + + wl->scan.state = WL1271_SCAN_STATE_2GHZ_ACTIVE; + + if (ssid_len && ssid) { + wl->scan.ssid_len = ssid_len; + memcpy(wl->scan.ssid, ssid, ssid_len); + } else { + wl->scan.ssid_len = 0; + } + + wl->scan.req = req; + + wl->scan.scanned_ch = kcalloc(req->n_channels, + sizeof(*wl->scan.scanned_ch), + GFP_KERNEL); + /* we assume failure so that timeout scenarios are handled correctly */ + wl->scan.failed = true; + ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, + msecs_to_jiffies(WL1271_SCAN_TIMEOUT)); + + wl1271_scan_stm(wl); + + return 0; +} diff --git a/drivers/net/wireless/wl12xx/scan.h b/drivers/net/wireless/wl12xx/scan.h new file mode 100644 index 0000000..421a750 --- /dev/null +++ b/drivers/net/wireless/wl12xx/scan.h @@ -0,0 +1,109 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2009-2010 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 __SCAN_H__ +#define __SCAN_H__ + +#include "wl12xx.h" + +int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, + struct cfg80211_scan_request *req); +int wl1271_scan_build_probe_req(struct wl1271 *wl, + const u8 *ssid, size_t ssid_len, + const u8 *ie, size_t ie_len, u8 band); +void wl1271_scan_stm(struct wl1271 *wl); +void wl1271_scan_complete_work(struct work_struct *work); + +#define WL1271_SCAN_MAX_CHANNELS 24 +#define WL1271_SCAN_DEFAULT_TAG 1 +#define WL1271_SCAN_CURRENT_TX_PWR 0 +#define WL1271_SCAN_OPT_ACTIVE 0 +#define WL1271_SCAN_OPT_PASSIVE 1 +#define WL1271_SCAN_OPT_PRIORITY_HIGH 4 +#define WL1271_SCAN_BAND_2_4_GHZ 0 +#define WL1271_SCAN_BAND_5_GHZ 1 + +#define WL1271_SCAN_TIMEOUT 10000 /* msec */ + +enum { + WL1271_SCAN_STATE_IDLE, + WL1271_SCAN_STATE_2GHZ_ACTIVE, + WL1271_SCAN_STATE_2GHZ_PASSIVE, + WL1271_SCAN_STATE_5GHZ_ACTIVE, + WL1271_SCAN_STATE_5GHZ_PASSIVE, + WL1271_SCAN_STATE_DONE +}; + +struct basic_scan_params { + __le32 rx_config_options; + __le32 rx_filter_options; + /* Scan option flags (WL1271_SCAN_OPT_*) */ + __le16 scan_options; + /* Number of scan channels in the list (maximum 30) */ + u8 n_ch; + /* This field indicates the number of probe requests to send + per channel for an active scan */ + u8 n_probe_reqs; + /* Rate bit field for sending the probes */ + __le32 tx_rate; + u8 tid_trigger; + u8 ssid_len; + /* in order to align */ + u8 padding1[2]; + u8 ssid[IW_ESSID_MAX_SIZE]; + /* Band to scan */ + u8 band; + u8 use_ssid_list; + u8 scan_tag; + u8 padding2; +} __packed; + +struct basic_scan_channel_params { + /* Duration in TU to wait for frames on a channel for active scan */ + __le32 min_duration; + __le32 max_duration; + __le32 bssid_lsb; + __le16 bssid_msb; + u8 early_termination; + u8 tx_power_att; + u8 channel; + /* FW internal use only! */ + u8 dfs_candidate; + u8 activity_detected; + u8 pad; +} __packed; + +struct wl1271_cmd_scan { + struct wl1271_cmd_header header; + + struct basic_scan_params params; + struct basic_scan_channel_params channels[WL1271_SCAN_MAX_CHANNELS]; +} __packed; + +struct wl1271_cmd_trigger_scan_to { + struct wl1271_cmd_header header; + + __le32 timeout; +} __packed; + +#endif /* __WL1271_SCAN_H__ */ diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c new file mode 100644 index 0000000..93cbb8d --- /dev/null +++ b/drivers/net/wireless/wl12xx/sdio.c @@ -0,0 +1,347 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2009-2010 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 + +#include "wl12xx.h" +#include "wl12xx_80211.h" +#include "io.h" + +#ifndef SDIO_VENDOR_ID_TI +#define SDIO_VENDOR_ID_TI 0x0097 +#endif + +#ifndef SDIO_DEVICE_ID_TI_WL1271 +#define SDIO_DEVICE_ID_TI_WL1271 0x4076 +#endif + +static const struct sdio_device_id wl1271_devices[] = { + { SDIO_DEVICE(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271) }, + {} +}; +MODULE_DEVICE_TABLE(sdio, wl1271_devices); + +static inline struct sdio_func *wl_to_func(struct wl1271 *wl) +{ + return wl->if_priv; +} + +static struct device *wl1271_sdio_wl_to_dev(struct wl1271 *wl) +{ + return &(wl_to_func(wl)->dev); +} + +static irqreturn_t wl1271_irq(int irq, void *cookie) +{ + struct wl1271 *wl = cookie; + unsigned long flags; + + wl1271_debug(DEBUG_IRQ, "IRQ"); + + /* complete the ELP completion */ + spin_lock_irqsave(&wl->wl_lock, flags); + if (wl->elp_compl) { + complete(wl->elp_compl); + wl->elp_compl = NULL; + } + + if (!test_and_set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags)) + ieee80211_queue_work(wl->hw, &wl->irq_work); + set_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags); + spin_unlock_irqrestore(&wl->wl_lock, flags); + + return IRQ_HANDLED; +} + +static void wl1271_sdio_disable_interrupts(struct wl1271 *wl) +{ + disable_irq(wl->irq); +} + +static void wl1271_sdio_enable_interrupts(struct wl1271 *wl) +{ + enable_irq(wl->irq); +} + +static void wl1271_sdio_reset(struct wl1271 *wl) +{ +} + +static void wl1271_sdio_init(struct wl1271 *wl) +{ +} + +static void wl1271_sdio_raw_read(struct wl1271 *wl, int addr, void *buf, + size_t len, bool fixed) +{ + int ret; + struct sdio_func *func = wl_to_func(wl); + + sdio_claim_host(func); + + if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) { + ((u8 *)buf)[0] = sdio_f0_readb(func, addr, &ret); + wl1271_debug(DEBUG_SDIO, "sdio read 52 addr 0x%x, byte 0x%02x", + addr, ((u8 *)buf)[0]); + } else { + if (fixed) + ret = sdio_readsb(func, buf, addr, len); + else + ret = sdio_memcpy_fromio(func, buf, addr, len); + + wl1271_debug(DEBUG_SDIO, "sdio read 53 addr 0x%x, %zu bytes", + addr, len); + wl1271_dump_ascii(DEBUG_SDIO, "data: ", buf, len); + } + + sdio_release_host(func); + + if (ret) + wl1271_error("sdio read failed (%d)", ret); +} + +static void wl1271_sdio_raw_write(struct wl1271 *wl, int addr, void *buf, + size_t len, bool fixed) +{ + int ret; + struct sdio_func *func = wl_to_func(wl); + + sdio_claim_host(func); + + if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) { + sdio_f0_writeb(func, ((u8 *)buf)[0], addr, &ret); + wl1271_debug(DEBUG_SDIO, "sdio write 52 addr 0x%x, byte 0x%02x", + addr, ((u8 *)buf)[0]); + } else { + wl1271_debug(DEBUG_SDIO, "sdio write 53 addr 0x%x, %zu bytes", + addr, len); + wl1271_dump_ascii(DEBUG_SDIO, "data: ", buf, len); + + if (fixed) + ret = sdio_writesb(func, addr, buf, len); + else + ret = sdio_memcpy_toio(func, addr, buf, len); + } + + sdio_release_host(func); + + if (ret) + wl1271_error("sdio write failed (%d)", ret); +} + +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); + +out: + return ret; +} + +static int wl1271_sdio_power_off(struct wl1271 *wl) +{ + struct sdio_func *func = wl_to_func(wl); + + sdio_claim_host(func); + sdio_disable_func(func); + sdio_release_host(func); + + /* Power down the card */ + return pm_runtime_put_sync(&func->dev); +} + +static int wl1271_sdio_set_power(struct wl1271 *wl, bool enable) +{ + if (enable) + return wl1271_sdio_power_on(wl); + else + return wl1271_sdio_power_off(wl); +} + +static struct wl1271_if_operations sdio_ops = { + .read = wl1271_sdio_raw_read, + .write = wl1271_sdio_raw_write, + .reset = wl1271_sdio_reset, + .init = wl1271_sdio_init, + .power = wl1271_sdio_set_power, + .dev = wl1271_sdio_wl_to_dev, + .enable_irq = wl1271_sdio_enable_interrupts, + .disable_irq = wl1271_sdio_disable_interrupts +}; + +static int __devinit wl1271_probe(struct sdio_func *func, + const struct sdio_device_id *id) +{ + struct ieee80211_hw *hw; + const struct wl12xx_platform_data *wlan_data; + struct wl1271 *wl; + int ret; + + /* We are only able to handle the wlan function */ + if (func->num != 0x02) + return -ENODEV; + + hw = wl1271_alloc_hw(); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + wl = hw->priv; + + wl->if_priv = func; + wl->if_ops = &sdio_ops; + + /* Grab access to FN0 for ELP reg. */ + func->card->quirks |= MMC_QUIRK_LENIENT_FN0; + + wlan_data = wl12xx_get_platform_data(); + if (IS_ERR(wlan_data)) { + ret = PTR_ERR(wlan_data); + wl1271_error("missing wlan platform data: %d", ret); + goto out_free; + } + + wl->irq = wlan_data->irq; + wl->ref_clock = wlan_data->board_ref_clock; + + ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl); + if (ret < 0) { + wl1271_error("request_irq() failed: %d", ret); + goto out_free; + } + + set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); + + disable_irq(wl->irq); + + ret = wl1271_init_ieee80211(wl); + if (ret) + goto out_irq; + + ret = wl1271_register_hw(wl); + if (ret) + goto out_irq; + + 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; + + out_irq: + free_irq(wl->irq, wl); + + + out_free: + wl1271_free_hw(wl); + + return ret; +} + +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); +} + +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) +{ + int ret; + + ret = sdio_register_driver(&wl1271_sdio_driver); + if (ret < 0) { + wl1271_error("failed to register sdio driver: %d", ret); + goto out; + } + +out: + return ret; +} + +static void __exit wl1271_exit(void) +{ + sdio_unregister_driver(&wl1271_sdio_driver); + + wl1271_notice("unloaded"); +} + +module_init(wl1271_init); +module_exit(wl1271_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Luciano Coelho "); +MODULE_AUTHOR("Juuso Oikarinen "); +MODULE_FIRMWARE(WL1271_FW_NAME); diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c new file mode 100644 index 0000000..4671491 --- /dev/null +++ b/drivers/net/wireless/wl12xx/spi.c @@ -0,0 +1,498 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 "wl12xx.h" +#include "wl12xx_80211.h" +#include "io.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 \ + ((WL1271_BUSY_WORD_LEN - 4) / sizeof(u32)) +#define HW_ACCESS_WSPI_INIT_CMD_MASK 0 + +/* HW limitation: maximum possible chunk size is 4095 bytes */ +#define WSPI_MAX_CHUNK_SIZE 4092 + +#define WSPI_MAX_NUM_OF_CHUNKS (WL1271_AGGR_BUFFER_SIZE / WSPI_MAX_CHUNK_SIZE) + +static inline struct spi_device *wl_to_spi(struct wl1271 *wl) +{ + return wl->if_priv; +} + +static struct device *wl1271_spi_wl_to_dev(struct wl1271 *wl) +{ + return &(wl_to_spi(wl)->dev); +} + +static void wl1271_spi_disable_interrupts(struct wl1271 *wl) +{ + disable_irq(wl->irq); +} + +static void wl1271_spi_enable_interrupts(struct wl1271 *wl) +{ + enable_irq(wl->irq); +} + +static void wl1271_spi_reset(struct wl1271 *wl) +{ + u8 *cmd; + struct spi_transfer t; + struct spi_message m; + + cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); + if (!cmd) { + wl1271_error("could not allocate cmd for spi reset"); + 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); + kfree(cmd); + + wl1271_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); +} + +static void wl1271_spi_init(struct wl1271 *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) { + wl1271_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); + wl1271_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN); + kfree(cmd); +} + +#define WL1271_BUSY_WORD_TIMEOUT 1000 + +static int wl1271_spi_read_busy(struct wl1271 *wl) +{ + struct spi_transfer t[1]; + struct spi_message m; + u32 *busy_buf; + int num_busy_bytes = 0; + + /* + * Read further busy words from SPI until a non-busy word is + * encountered, then read the data itself into the buffer. + */ + + num_busy_bytes = WL1271_BUSY_WORD_TIMEOUT; + busy_buf = wl->buffer_busyword; + while (num_busy_bytes) { + num_busy_bytes--; + spi_message_init(&m); + memset(t, 0, sizeof(t)); + t[0].rx_buf = busy_buf; + t[0].len = sizeof(u32); + t[0].cs_change = true; + spi_message_add_tail(&t[0], &m); + spi_sync(wl_to_spi(wl), &m); + + if (*busy_buf & 0x1) + return 0; + } + + /* The SPI bus is unresponsive, the read failed. */ + wl1271_error("SPI read busy-word timeout!\n"); + return -ETIMEDOUT; +} + +static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf, + size_t len, bool fixed) +{ + struct spi_transfer t[2]; + struct spi_message m; + u32 *busy_buf; + u32 *cmd; + u32 chunk_len; + + while (len > 0) { + chunk_len = min((size_t)WSPI_MAX_CHUNK_SIZE, len); + + cmd = &wl->buffer_cmd; + busy_buf = wl->buffer_busyword; + + *cmd = 0; + *cmd |= WSPI_CMD_READ; + *cmd |= (chunk_len << WSPI_CMD_BYTE_LENGTH_OFFSET) & + WSPI_CMD_BYTE_LENGTH; + *cmd |= addr & WSPI_CMD_BYTE_ADDR; + + if (fixed) + *cmd |= WSPI_CMD_FIXED; + + spi_message_init(&m); + memset(t, 0, sizeof(t)); + + t[0].tx_buf = cmd; + t[0].len = 4; + t[0].cs_change = true; + spi_message_add_tail(&t[0], &m); + + /* Busy and non busy words read */ + t[1].rx_buf = busy_buf; + t[1].len = WL1271_BUSY_WORD_LEN; + t[1].cs_change = true; + spi_message_add_tail(&t[1], &m); + + spi_sync(wl_to_spi(wl), &m); + + if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1) && + wl1271_spi_read_busy(wl)) { + memset(buf, 0, chunk_len); + return; + } + + spi_message_init(&m); + memset(t, 0, sizeof(t)); + + t[0].rx_buf = buf; + t[0].len = chunk_len; + t[0].cs_change = true; + spi_message_add_tail(&t[0], &m); + + spi_sync(wl_to_spi(wl), &m); + + wl1271_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd)); + wl1271_dump(DEBUG_SPI, "spi_read buf <- ", buf, chunk_len); + + if (!fixed) + addr += chunk_len; + buf += chunk_len; + len -= chunk_len; + } +} + +static void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf, + size_t len, bool fixed) +{ + struct spi_transfer t[2 * WSPI_MAX_NUM_OF_CHUNKS]; + struct spi_message m; + u32 commands[WSPI_MAX_NUM_OF_CHUNKS]; + u32 *cmd; + u32 chunk_len; + int i; + + WARN_ON(len > WL1271_AGGR_BUFFER_SIZE); + + spi_message_init(&m); + memset(t, 0, sizeof(t)); + + cmd = &commands[0]; + i = 0; + while (len > 0) { + chunk_len = min((size_t)WSPI_MAX_CHUNK_SIZE, len); + + *cmd = 0; + *cmd |= WSPI_CMD_WRITE; + *cmd |= (chunk_len << WSPI_CMD_BYTE_LENGTH_OFFSET) & + WSPI_CMD_BYTE_LENGTH; + *cmd |= addr & WSPI_CMD_BYTE_ADDR; + + if (fixed) + *cmd |= WSPI_CMD_FIXED; + + t[i].tx_buf = cmd; + t[i].len = sizeof(*cmd); + spi_message_add_tail(&t[i++], &m); + + t[i].tx_buf = buf; + t[i].len = chunk_len; + spi_message_add_tail(&t[i++], &m); + + wl1271_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); + wl1271_dump(DEBUG_SPI, "spi_write buf -> ", buf, chunk_len); + + if (!fixed) + addr += chunk_len; + buf += chunk_len; + len -= chunk_len; + cmd++; + } + + spi_sync(wl_to_spi(wl), &m); +} + +static irqreturn_t wl1271_irq(int irq, void *cookie) +{ + struct wl1271 *wl; + unsigned long flags; + + wl1271_debug(DEBUG_IRQ, "IRQ"); + + wl = cookie; + + /* complete the ELP completion */ + spin_lock_irqsave(&wl->wl_lock, flags); + if (wl->elp_compl) { + complete(wl->elp_compl); + wl->elp_compl = NULL; + } + + if (!test_and_set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags)) + ieee80211_queue_work(wl->hw, &wl->irq_work); + set_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags); + spin_unlock_irqrestore(&wl->wl_lock, flags); + + return IRQ_HANDLED; +} + +static int wl1271_spi_set_power(struct wl1271 *wl, bool enable) +{ + if (wl->set_power) + wl->set_power(enable); + + return 0; +} + +static struct wl1271_if_operations spi_ops = { + .read = wl1271_spi_raw_read, + .write = wl1271_spi_raw_write, + .reset = wl1271_spi_reset, + .init = wl1271_spi_init, + .power = wl1271_spi_set_power, + .dev = wl1271_spi_wl_to_dev, + .enable_irq = wl1271_spi_enable_interrupts, + .disable_irq = wl1271_spi_disable_interrupts +}; + +static int __devinit wl1271_probe(struct spi_device *spi) +{ + struct wl12xx_platform_data *pdata; + struct ieee80211_hw *hw; + struct wl1271 *wl; + int ret; + + pdata = spi->dev.platform_data; + if (!pdata) { + wl1271_error("no platform data"); + return -ENODEV; + } + + hw = wl1271_alloc_hw(); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + wl = hw->priv; + + dev_set_drvdata(&spi->dev, wl); + wl->if_priv = spi; + + wl->if_ops = &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) { + wl1271_error("spi_setup failed"); + goto out_free; + } + + wl->set_power = pdata->set_power; + if (!wl->set_power) { + wl1271_error("set power function missing in platform data"); + ret = -ENODEV; + goto out_free; + } + + wl->ref_clock = pdata->board_ref_clock; + + wl->irq = spi->irq; + if (wl->irq < 0) { + wl1271_error("irq missing in platform data"); + ret = -ENODEV; + goto out_free; + } + + ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl); + if (ret < 0) { + wl1271_error("request_irq() failed: %d", ret); + goto out_free; + } + + set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); + + disable_irq(wl->irq); + + ret = wl1271_init_ieee80211(wl); + if (ret) + goto out_irq; + + ret = wl1271_register_hw(wl); + if (ret) + goto out_irq; + + wl1271_notice("initialized"); + + return 0; + + out_irq: + free_irq(wl->irq, wl); + + out_free: + wl1271_free_hw(wl); + + return ret; +} + +static int __devexit wl1271_remove(struct spi_device *spi) +{ + struct wl1271 *wl = dev_get_drvdata(&spi->dev); + + wl1271_unregister_hw(wl); + free_irq(wl->irq, wl); + wl1271_free_hw(wl); + + return 0; +} + + +static struct spi_driver wl1271_spi_driver = { + .driver = { + .name = "wl1271_spi", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + + .probe = wl1271_probe, + .remove = __devexit_p(wl1271_remove), +}; + +static int __init wl1271_init(void) +{ + int ret; + + ret = spi_register_driver(&wl1271_spi_driver); + if (ret < 0) { + wl1271_error("failed to register spi driver: %d", ret); + goto out; + } + +out: + return ret; +} + +static void __exit wl1271_exit(void) +{ + spi_unregister_driver(&wl1271_spi_driver); + + wl1271_notice("unloaded"); +} + +module_init(wl1271_init); +module_exit(wl1271_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Luciano Coelho "); +MODULE_AUTHOR("Juuso Oikarinen "); +MODULE_FIRMWARE(WL1271_FW_NAME); +MODULE_ALIAS("spi:wl1271"); diff --git a/drivers/net/wireless/wl12xx/testmode.c b/drivers/net/wireless/wl12xx/testmode.c new file mode 100644 index 0000000..e64403b --- /dev/null +++ b/drivers/net/wireless/wl12xx/testmode.c @@ -0,0 +1,290 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2010 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 "testmode.h" + +#include +#include + +#include "wl12xx.h" +#include "acx.h" + +#define WL1271_TM_MAX_DATA_LENGTH 1024 + +enum wl1271_tm_commands { + WL1271_TM_CMD_UNSPEC, + WL1271_TM_CMD_TEST, + WL1271_TM_CMD_INTERROGATE, + WL1271_TM_CMD_CONFIGURE, + WL1271_TM_CMD_NVS_PUSH, + WL1271_TM_CMD_SET_PLT_MODE, + WL1271_TM_CMD_RECOVER, + + __WL1271_TM_CMD_AFTER_LAST +}; +#define WL1271_TM_CMD_MAX (__WL1271_TM_CMD_AFTER_LAST - 1) + +enum wl1271_tm_attrs { + WL1271_TM_ATTR_UNSPEC, + WL1271_TM_ATTR_CMD_ID, + WL1271_TM_ATTR_ANSWER, + WL1271_TM_ATTR_DATA, + WL1271_TM_ATTR_IE_ID, + WL1271_TM_ATTR_PLT_MODE, + + __WL1271_TM_ATTR_AFTER_LAST +}; +#define WL1271_TM_ATTR_MAX (__WL1271_TM_ATTR_AFTER_LAST - 1) + +static struct nla_policy wl1271_tm_policy[WL1271_TM_ATTR_MAX + 1] = { + [WL1271_TM_ATTR_CMD_ID] = { .type = NLA_U32 }, + [WL1271_TM_ATTR_ANSWER] = { .type = NLA_U8 }, + [WL1271_TM_ATTR_DATA] = { .type = NLA_BINARY, + .len = WL1271_TM_MAX_DATA_LENGTH }, + [WL1271_TM_ATTR_IE_ID] = { .type = NLA_U32 }, + [WL1271_TM_ATTR_PLT_MODE] = { .type = NLA_U32 }, +}; + + +static int wl1271_tm_cmd_test(struct wl1271 *wl, struct nlattr *tb[]) +{ + int buf_len, ret, len; + struct sk_buff *skb; + void *buf; + u8 answer = 0; + + wl1271_debug(DEBUG_TESTMODE, "testmode cmd test"); + + if (!tb[WL1271_TM_ATTR_DATA]) + return -EINVAL; + + buf = nla_data(tb[WL1271_TM_ATTR_DATA]); + buf_len = nla_len(tb[WL1271_TM_ATTR_DATA]); + + if (tb[WL1271_TM_ATTR_ANSWER]) + answer = nla_get_u8(tb[WL1271_TM_ATTR_ANSWER]); + + if (buf_len > sizeof(struct wl1271_command)) + return -EMSGSIZE; + + mutex_lock(&wl->mutex); + ret = wl1271_cmd_test(wl, buf, buf_len, answer); + mutex_unlock(&wl->mutex); + + if (ret < 0) { + wl1271_warning("testmode cmd test failed: %d", ret); + return ret; + } + + if (answer) { + len = nla_total_size(buf_len); + skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, len); + if (!skb) + return -ENOMEM; + + NLA_PUT(skb, WL1271_TM_ATTR_DATA, buf_len, buf); + ret = cfg80211_testmode_reply(skb); + if (ret < 0) + return ret; + } + + return 0; + +nla_put_failure: + kfree_skb(skb); + return -EMSGSIZE; +} + +static int wl1271_tm_cmd_interrogate(struct wl1271 *wl, struct nlattr *tb[]) +{ + int ret; + struct wl1271_command *cmd; + struct sk_buff *skb; + u8 ie_id; + + wl1271_debug(DEBUG_TESTMODE, "testmode cmd interrogate"); + + if (!tb[WL1271_TM_ATTR_IE_ID]) + return -EINVAL; + + ie_id = nla_get_u8(tb[WL1271_TM_ATTR_IE_ID]); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + mutex_lock(&wl->mutex); + ret = wl1271_cmd_interrogate(wl, ie_id, cmd, sizeof(*cmd)); + mutex_unlock(&wl->mutex); + + if (ret < 0) { + wl1271_warning("testmode cmd interrogate failed: %d", ret); + return ret; + } + + skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + NLA_PUT(skb, WL1271_TM_ATTR_DATA, sizeof(*cmd), cmd); + + return 0; + +nla_put_failure: + kfree_skb(skb); + return -EMSGSIZE; +} + +static int wl1271_tm_cmd_configure(struct wl1271 *wl, struct nlattr *tb[]) +{ + int buf_len, ret; + void *buf; + u8 ie_id; + + wl1271_debug(DEBUG_TESTMODE, "testmode cmd configure"); + + if (!tb[WL1271_TM_ATTR_DATA]) + return -EINVAL; + if (!tb[WL1271_TM_ATTR_IE_ID]) + return -EINVAL; + + ie_id = nla_get_u8(tb[WL1271_TM_ATTR_IE_ID]); + buf = nla_data(tb[WL1271_TM_ATTR_DATA]); + buf_len = nla_len(tb[WL1271_TM_ATTR_DATA]); + + if (buf_len > sizeof(struct wl1271_command)) + return -EMSGSIZE; + + mutex_lock(&wl->mutex); + ret = wl1271_cmd_configure(wl, ie_id, buf, buf_len); + mutex_unlock(&wl->mutex); + + if (ret < 0) { + wl1271_warning("testmode cmd configure failed: %d", ret); + return ret; + } + + return 0; +} + +static int wl1271_tm_cmd_nvs_push(struct wl1271 *wl, struct nlattr *tb[]) +{ + int ret = 0; + size_t len; + void *buf; + + wl1271_debug(DEBUG_TESTMODE, "testmode cmd nvs push"); + + if (!tb[WL1271_TM_ATTR_DATA]) + return -EINVAL; + + buf = nla_data(tb[WL1271_TM_ATTR_DATA]); + len = nla_len(tb[WL1271_TM_ATTR_DATA]); + + mutex_lock(&wl->mutex); + + kfree(wl->nvs); + + wl->nvs = kzalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL); + if (!wl->nvs) { + wl1271_error("could not allocate memory for the nvs file"); + ret = -ENOMEM; + goto out; + } + + memcpy(wl->nvs, buf, len); + wl->nvs_len = len; + + wl1271_debug(DEBUG_TESTMODE, "testmode pushed nvs"); + +out: + mutex_unlock(&wl->mutex); + + return ret; +} + +static int wl1271_tm_cmd_set_plt_mode(struct wl1271 *wl, struct nlattr *tb[]) +{ + u32 val; + int ret; + + wl1271_debug(DEBUG_TESTMODE, "testmode cmd set plt mode"); + + if (!tb[WL1271_TM_ATTR_PLT_MODE]) + return -EINVAL; + + val = nla_get_u32(tb[WL1271_TM_ATTR_PLT_MODE]); + + switch (val) { + case 0: + ret = wl1271_plt_stop(wl); + break; + case 1: + ret = wl1271_plt_start(wl); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int wl1271_tm_cmd_recover(struct wl1271 *wl, struct nlattr *tb[]) +{ + wl1271_debug(DEBUG_TESTMODE, "testmode cmd recover"); + + ieee80211_queue_work(wl->hw, &wl->recovery_work); + + return 0; +} + +int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len) +{ + struct wl1271 *wl = hw->priv; + struct nlattr *tb[WL1271_TM_ATTR_MAX + 1]; + int err; + + err = nla_parse(tb, WL1271_TM_ATTR_MAX, data, len, wl1271_tm_policy); + if (err) + return err; + + if (!tb[WL1271_TM_ATTR_CMD_ID]) + return -EINVAL; + + switch (nla_get_u32(tb[WL1271_TM_ATTR_CMD_ID])) { + case WL1271_TM_CMD_TEST: + return wl1271_tm_cmd_test(wl, tb); + case WL1271_TM_CMD_INTERROGATE: + return wl1271_tm_cmd_interrogate(wl, tb); + case WL1271_TM_CMD_CONFIGURE: + return wl1271_tm_cmd_configure(wl, tb); + case WL1271_TM_CMD_NVS_PUSH: + return wl1271_tm_cmd_nvs_push(wl, tb); + case WL1271_TM_CMD_SET_PLT_MODE: + return wl1271_tm_cmd_set_plt_mode(wl, tb); + case WL1271_TM_CMD_RECOVER: + return wl1271_tm_cmd_recover(wl, tb); + default: + return -EOPNOTSUPP; + } +} diff --git a/drivers/net/wireless/wl12xx/testmode.h b/drivers/net/wireless/wl12xx/testmode.h new file mode 100644 index 0000000..8071654 --- /dev/null +++ b/drivers/net/wireless/wl12xx/testmode.h @@ -0,0 +1,31 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2010 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 __TESTMODE_H__ +#define __TESTMODE_H__ + +#include + +int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len); + +#endif /* __WL1271_TESTMODE_H__ */ diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c new file mode 100644 index 0000000..d332b3f --- /dev/null +++ b/drivers/net/wireless/wl12xx/tx.c @@ -0,0 +1,485 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 "wl12xx.h" +#include "io.h" +#include "reg.h" +#include "ps.h" +#include "tx.h" + +static int wl1271_alloc_tx_id(struct wl1271 *wl, struct sk_buff *skb) +{ + int id; + + id = find_first_zero_bit(wl->tx_frames_map, ACX_TX_DESCRIPTORS); + if (id >= ACX_TX_DESCRIPTORS) + return -EBUSY; + + __set_bit(id, wl->tx_frames_map); + wl->tx_frames[id] = skb; + wl->tx_frames_cnt++; + return id; +} + +static void wl1271_free_tx_id(struct wl1271 *wl, int id) +{ + if (__test_and_clear_bit(id, wl->tx_frames_map)) { + wl->tx_frames[id] = NULL; + wl->tx_frames_cnt--; + } +} + +static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, + u32 buf_offset) +{ + struct wl1271_tx_hw_descr *desc; + u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra; + u32 total_blocks; + int id, ret = -EBUSY; + + if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE) + return -EAGAIN; + + /* allocate free identifier for the packet */ + id = wl1271_alloc_tx_id(wl, skb); + if (id < 0) + return id; + + /* approximate the number of blocks required for this packet + in the firmware */ + total_blocks = total_len + TX_HW_BLOCK_SIZE - 1; + total_blocks = total_blocks / TX_HW_BLOCK_SIZE + TX_HW_BLOCK_SPARE; + if (total_blocks <= wl->tx_blocks_available) { + desc = (struct wl1271_tx_hw_descr *)skb_push( + skb, total_len - skb->len); + + desc->extra_mem_blocks = TX_HW_BLOCK_SPARE; + desc->total_mem_blocks = total_blocks; + desc->id = id; + + wl->tx_blocks_available -= total_blocks; + + ret = 0; + + wl1271_debug(DEBUG_TX, + "tx_allocate: size: %d, blocks: %d, id: %d", + total_len, total_blocks, id); + } else { + wl1271_free_tx_id(wl, id); + } + + return ret; +} + +static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, + u32 extra, struct ieee80211_tx_info *control) +{ + struct timespec ts; + struct wl1271_tx_hw_descr *desc; + int pad, ac; + s64 hosttime; + u16 tx_attr; + + desc = (struct wl1271_tx_hw_descr *) skb->data; + + /* relocate space for security header */ + if (extra) { + void *framestart = skb->data + sizeof(*desc); + u16 fc = *(u16 *)(framestart + extra); + int hdrlen = ieee80211_hdrlen(cpu_to_le16(fc)); + memmove(framestart, framestart + extra, hdrlen); + } + + /* configure packet life time */ + getnstimeofday(&ts); + hosttime = (timespec_to_ns(&ts) >> 10); + desc->start_time = cpu_to_le32(hosttime - wl->time_offset); + desc->life_time = cpu_to_le16(TX_HW_MGMT_PKT_LIFETIME_TU); + + /* configure the tx attributes */ + tx_attr = wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER; + + /* queue (we use same identifiers for tid's and ac's */ + ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); + desc->tid = ac; + + desc->aid = TX_HW_DEFAULT_AID; + desc->reserved = 0; + + /* align the length (and store in terms of words) */ + pad = WL1271_TX_ALIGN(skb->len); + desc->length = cpu_to_le16(pad >> 2); + + /* calculate number of padding bytes */ + pad = pad - skb->len; + tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD; + + /* if the packets are destined for AP (have a STA entry) send them + with AP rate policies, otherwise use default basic rates */ + if (control->control.sta) + tx_attr |= ACX_TX_AP_FULL_RATE << TX_HW_ATTR_OFST_RATE_POLICY; + + desc->tx_attr = cpu_to_le16(tx_attr); + + wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d", pad); +} + +/* caller must hold wl->mutex */ +static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, + u32 buf_offset) +{ + struct ieee80211_tx_info *info; + u32 extra = 0; + int ret = 0; + u8 idx; + u32 total_len; + + if (!skb) + return -EINVAL; + + info = IEEE80211_SKB_CB(skb); + + if (info->control.hw_key && + info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) + extra = WL1271_TKIP_IV_SPACE; + + if (info->control.hw_key) { + idx = info->control.hw_key->hw_key_idx; + + /* FIXME: do we have to do this if we're not using WEP? */ + if (unlikely(wl->default_key != idx)) { + ret = wl1271_cmd_set_default_wep_key(wl, idx); + if (ret < 0) + return ret; + wl->default_key = idx; + } + } + + ret = wl1271_tx_allocate(wl, skb, extra, buf_offset); + if (ret < 0) + return ret; + + wl1271_tx_fill_hdr(wl, skb, extra, info); + + /* + * The length of each packet is stored in terms of words. Thus, we must + * pad the skb data to make sure its length is aligned. + * The number of padding bytes is computed and set in wl1271_tx_fill_hdr + */ + total_len = WL1271_TX_ALIGN(skb->len); + memcpy(wl->aggr_buf + buf_offset, skb->data, skb->len); + memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len); + + return total_len; +} + +u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set) +{ + struct ieee80211_supported_band *band; + u32 enabled_rates = 0; + int bit; + + band = wl->hw->wiphy->bands[wl->band]; + for (bit = 0; bit < band->n_bitrates; bit++) { + if (rate_set & 0x1) + enabled_rates |= band->bitrates[bit].hw_value; + rate_set >>= 1; + } + +#ifdef CONFIG_WL12XX_HT + /* MCS rates indication are on bits 16 - 23 */ + rate_set >>= HW_HT_RATES_OFFSET - band->n_bitrates; + + for (bit = 0; bit < 8; bit++) { + if (rate_set & 0x1) + enabled_rates |= (CONF_HW_BIT_RATE_MCS_0 << bit); + rate_set >>= 1; + } +#endif + + return enabled_rates; +} + +static void handle_tx_low_watermark(struct wl1271 *wl) +{ + unsigned long flags; + + if (test_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags) && + skb_queue_len(&wl->tx_queue) <= WL1271_TX_QUEUE_LOW_WATERMARK) { + /* firmware buffer has space, restart queues */ + spin_lock_irqsave(&wl->wl_lock, flags); + ieee80211_wake_queues(wl->hw); + clear_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags); + spin_unlock_irqrestore(&wl->wl_lock, flags); + } +} + +void wl1271_tx_work_locked(struct wl1271 *wl) +{ + struct sk_buff *skb; + bool woken_up = false; + u32 sta_rates = 0; + u32 buf_offset = 0; + bool sent_packets = false; + int ret; + + /* check if the rates supported by the AP have changed */ + if (unlikely(test_and_clear_bit(WL1271_FLAG_STA_RATES_CHANGED, + &wl->flags))) { + unsigned long flags; + + spin_lock_irqsave(&wl->wl_lock, flags); + sta_rates = wl->sta_rate_set; + spin_unlock_irqrestore(&wl->wl_lock, flags); + } + + if (unlikely(wl->state == WL1271_STATE_OFF)) + goto out; + + /* if rates have changed, re-configure the rate policy */ + if (unlikely(sta_rates)) { + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out; + woken_up = true; + + wl->rate_set = wl1271_tx_enabled_rates_get(wl, sta_rates); + wl1271_acx_rate_policies(wl); + } + + while ((skb = skb_dequeue(&wl->tx_queue))) { + if (!woken_up) { + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out_ack; + woken_up = true; + } + + ret = wl1271_prepare_tx_frame(wl, skb, buf_offset); + if (ret == -EAGAIN) { + /* + * Aggregation buffer is full. + * Flush buffer and try again. + */ + skb_queue_head(&wl->tx_queue, skb); + wl1271_write(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, + buf_offset, true); + sent_packets = true; + buf_offset = 0; + continue; + } else if (ret == -EBUSY) { + /* + * Firmware buffer is full. + * Queue back last skb, and stop aggregating. + */ + skb_queue_head(&wl->tx_queue, skb); + /* No work left, avoid scheduling redundant tx work */ + set_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); + goto out_ack; + } else if (ret < 0) { + dev_kfree_skb(skb); + goto out_ack; + } + buf_offset += ret; + wl->tx_packets_count++; + } + +out_ack: + if (buf_offset) { + wl1271_write(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, + buf_offset, true); + sent_packets = true; + } + if (sent_packets) { + /* interrupt the firmware with the new packets */ + wl1271_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count); + handle_tx_low_watermark(wl); + } + +out: + if (woken_up) + wl1271_ps_elp_sleep(wl); +} + +void wl1271_tx_work(struct work_struct *work) +{ + struct wl1271 *wl = container_of(work, struct wl1271, tx_work); + + mutex_lock(&wl->mutex); + wl1271_tx_work_locked(wl); + mutex_unlock(&wl->mutex); +} + +static void wl1271_tx_complete_packet(struct wl1271 *wl, + struct wl1271_tx_hw_res_descr *result) +{ + struct ieee80211_tx_info *info; + struct sk_buff *skb; + int id = result->id; + int rate = -1; + u8 retries = 0; + + /* check for id legality */ + if (unlikely(id >= ACX_TX_DESCRIPTORS || wl->tx_frames[id] == NULL)) { + wl1271_warning("TX result illegal id: %d", id); + return; + } + + skb = wl->tx_frames[id]; + info = IEEE80211_SKB_CB(skb); + + /* update the TX status info */ + if (result->status == TX_SUCCESS) { + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) + info->flags |= IEEE80211_TX_STAT_ACK; + rate = wl1271_rate_to_idx(result->rate_class_index, wl->band); + retries = result->ack_failures; + } else if (result->status == TX_RETRY_EXCEEDED) { + wl->stats.excessive_retries++; + retries = result->ack_failures; + } + + info->status.rates[0].idx = rate; + info->status.rates[0].count = retries; + info->status.rates[0].flags = 0; + info->status.ack_signal = -1; + + wl->stats.retry_count += result->ack_failures; + + /* update security sequence number */ + wl->tx_security_seq += (result->lsb_security_sequence_number - + wl->tx_security_last_seq); + wl->tx_security_last_seq = result->lsb_security_sequence_number; + + /* remove private header from packet */ + skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); + + /* remove TKIP header space if present */ + if (info->control.hw_key && + info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) { + int hdrlen = ieee80211_get_hdrlen_from_skb(skb); + memmove(skb->data + WL1271_TKIP_IV_SPACE, skb->data, hdrlen); + skb_pull(skb, WL1271_TKIP_IV_SPACE); + } + + wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x" + " status 0x%x", + result->id, skb, result->ack_failures, + result->rate_class_index, result->status); + + /* return the packet to the stack */ + ieee80211_tx_status(wl->hw, skb); + wl1271_free_tx_id(wl, result->id); +} + +/* Called upon reception of a TX complete interrupt */ +void wl1271_tx_complete(struct wl1271 *wl) +{ + struct wl1271_acx_mem_map *memmap = + (struct wl1271_acx_mem_map *)wl->target_mem_map; + u32 count, fw_counter; + u32 i; + + /* read the tx results from the chipset */ + wl1271_read(wl, le32_to_cpu(memmap->tx_result), + wl->tx_res_if, sizeof(*wl->tx_res_if), false); + fw_counter = le32_to_cpu(wl->tx_res_if->tx_result_fw_counter); + + /* write host counter to chipset (to ack) */ + wl1271_write32(wl, le32_to_cpu(memmap->tx_result) + + offsetof(struct wl1271_tx_hw_res_if, + tx_result_host_counter), fw_counter); + + count = fw_counter - wl->tx_results_count; + wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count); + + /* verify that the result buffer is not getting overrun */ + if (unlikely(count > TX_HW_RESULT_QUEUE_LEN)) + wl1271_warning("TX result overflow from chipset: %d", count); + + /* process the results */ + for (i = 0; i < count; i++) { + struct wl1271_tx_hw_res_descr *result; + u8 offset = wl->tx_results_count & TX_HW_RESULT_QUEUE_LEN_MASK; + + /* process the packet */ + result = &(wl->tx_res_if->tx_results_queue[offset]); + wl1271_tx_complete_packet(wl, result); + + wl->tx_results_count++; + } +} + +/* caller must hold wl->mutex */ +void wl1271_tx_reset(struct wl1271 *wl) +{ + int i; + struct sk_buff *skb; + + /* TX failure */ + while ((skb = skb_dequeue(&wl->tx_queue))) { + wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb); + ieee80211_tx_status(wl->hw, skb); + } + + /* + * Make sure the driver is at a consistent state, in case this + * function is called from a context other than interface removal. + */ + handle_tx_low_watermark(wl); + + for (i = 0; i < ACX_TX_DESCRIPTORS; i++) + if (wl->tx_frames[i] != NULL) { + skb = wl->tx_frames[i]; + wl1271_free_tx_id(wl, i); + wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb); + ieee80211_tx_status(wl->hw, skb); + } +} + +#define WL1271_TX_FLUSH_TIMEOUT 500000 + +/* caller must *NOT* hold wl->mutex */ +void wl1271_tx_flush(struct wl1271 *wl) +{ + unsigned long timeout; + timeout = jiffies + usecs_to_jiffies(WL1271_TX_FLUSH_TIMEOUT); + + while (!time_after(jiffies, timeout)) { + mutex_lock(&wl->mutex); + wl1271_debug(DEBUG_TX, "flushing tx buffer: %d", + wl->tx_frames_cnt); + if ((wl->tx_frames_cnt == 0) && + skb_queue_empty(&wl->tx_queue)) { + mutex_unlock(&wl->mutex); + return; + } + mutex_unlock(&wl->mutex); + msleep(1); + } + + wl1271_warning("Unable to flush all TX buffers, timed out."); +} diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h new file mode 100644 index 0000000..903e5dc --- /dev/null +++ b/drivers/net/wireless/wl12xx/tx.h @@ -0,0 +1,150 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 __TX_H__ +#define __TX_H__ + +#define TX_HW_BLOCK_SPARE 2 +#define TX_HW_BLOCK_SIZE 252 + +#define TX_HW_MGMT_PKT_LIFETIME_TU 2000 +/* The chipset reference driver states, that the "aid" value 1 + * is for infra-BSS, but is still always used */ +#define TX_HW_DEFAULT_AID 1 + +#define TX_HW_ATTR_SAVE_RETRIES BIT(0) +#define TX_HW_ATTR_HEADER_PAD BIT(1) +#define TX_HW_ATTR_SESSION_COUNTER (BIT(2) | BIT(3) | BIT(4)) +#define TX_HW_ATTR_RATE_POLICY (BIT(5) | BIT(6) | BIT(7) | \ + BIT(8) | BIT(9)) +#define TX_HW_ATTR_LAST_WORD_PAD (BIT(10) | BIT(11)) +#define TX_HW_ATTR_TX_CMPLT_REQ BIT(12) + +#define TX_HW_ATTR_OFST_SAVE_RETRIES 0 +#define TX_HW_ATTR_OFST_HEADER_PAD 1 +#define TX_HW_ATTR_OFST_SESSION_COUNTER 2 +#define TX_HW_ATTR_OFST_RATE_POLICY 5 +#define TX_HW_ATTR_OFST_LAST_WORD_PAD 10 +#define TX_HW_ATTR_OFST_TX_CMPLT_REQ 12 + +#define TX_HW_RESULT_QUEUE_LEN 16 +#define TX_HW_RESULT_QUEUE_LEN_MASK 0xf + +#define WL1271_TX_ALIGN_TO 4 +#define WL1271_TX_ALIGN(len) (((len) + WL1271_TX_ALIGN_TO - 1) & \ + ~(WL1271_TX_ALIGN_TO - 1)) +#define WL1271_TKIP_IV_SPACE 4 + +struct wl1271_tx_hw_descr { + /* Length of packet in words, including descriptor+header+data */ + __le16 length; + /* Number of extra memory blocks to allocate for this packet in + addition to the number of blocks derived from the packet length */ + u8 extra_mem_blocks; + /* Total number of memory blocks allocated by the host for this packet. + Must be equal or greater than the actual blocks number allocated by + HW!! */ + u8 total_mem_blocks; + /* Device time (in us) when the packet arrived to the driver */ + __le32 start_time; + /* Max delay in TUs until transmission. The last device time the + packet can be transmitted is: startTime+(1024*LifeTime) */ + __le16 life_time; + /* Bitwise fields - see TX_ATTR... definitions above. */ + __le16 tx_attr; + /* Packet identifier used also in the Tx-Result. */ + u8 id; + /* The packet TID value (as User-Priority) */ + u8 tid; + /* Identifier of the remote STA in IBSS, 1 in infra-BSS */ + u8 aid; + u8 reserved; +} __packed; + +enum wl1271_tx_hw_res_status { + TX_SUCCESS = 0, + TX_HW_ERROR = 1, + TX_DISABLED = 2, + TX_RETRY_EXCEEDED = 3, + TX_TIMEOUT = 4, + TX_KEY_NOT_FOUND = 5, + TX_PEER_NOT_FOUND = 6, + TX_SESSION_MISMATCH = 7 +}; + +struct wl1271_tx_hw_res_descr { + /* Packet Identifier - same value used in the Tx descriptor.*/ + u8 id; + /* The status of the transmission, indicating success or one of + several possible reasons for failure. */ + u8 status; + /* Total air access duration including all retrys and overheads.*/ + __le16 medium_usage; + /* The time passed from host xfer to Tx-complete.*/ + __le32 fw_handling_time; + /* Total media delay + (from 1st EDCA AIFS counter until TX Complete). */ + __le32 medium_delay; + /* LS-byte of last TKIP seq-num (saved per AC for recovery). */ + u8 lsb_security_sequence_number; + /* Retry count - number of transmissions without successful ACK.*/ + u8 ack_failures; + /* The rate that succeeded getting ACK + (Valid only if status=SUCCESS). */ + u8 rate_class_index; + /* for 4-byte alignment. */ + u8 spare; +} __packed; + +struct wl1271_tx_hw_res_if { + __le32 tx_result_fw_counter; + __le32 tx_result_host_counter; + struct wl1271_tx_hw_res_descr tx_results_queue[TX_HW_RESULT_QUEUE_LEN]; +} __packed; + +static inline int wl1271_tx_get_queue(int queue) +{ + switch (queue) { + case 0: + return CONF_TX_AC_VO; + case 1: + return CONF_TX_AC_VI; + case 2: + return CONF_TX_AC_BE; + case 3: + return CONF_TX_AC_BK; + default: + return CONF_TX_AC_BE; + } +} + +void wl1271_tx_work(struct work_struct *work); +void wl1271_tx_work_locked(struct wl1271 *wl); +void wl1271_tx_complete(struct wl1271 *wl); +void wl1271_tx_reset(struct wl1271 *wl); +void wl1271_tx_flush(struct wl1271 *wl); +u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band); +u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set); + +#endif diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h deleted file mode 100644 index ab53162..0000000 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ /dev/null @@ -1,523 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. - * Copyright (C) 2008-2009 Nokia Corporation - * - * Contact: Luciano Coelho - * - * 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 __WL1271_H__ -#define __WL1271_H__ - -#include -#include -#include -#include -#include -#include - -#include "wl1271_conf.h" -#include "wl1271_ini.h" - -#define DRIVER_NAME "wl1271" -#define DRIVER_PREFIX DRIVER_NAME ": " - -enum { - DEBUG_NONE = 0, - DEBUG_IRQ = BIT(0), - DEBUG_SPI = BIT(1), - DEBUG_BOOT = BIT(2), - DEBUG_MAILBOX = BIT(3), - DEBUG_TESTMODE = BIT(4), - DEBUG_EVENT = BIT(5), - DEBUG_TX = BIT(6), - DEBUG_RX = BIT(7), - DEBUG_SCAN = BIT(8), - DEBUG_CRYPT = BIT(9), - DEBUG_PSM = BIT(10), - DEBUG_MAC80211 = BIT(11), - DEBUG_CMD = BIT(12), - DEBUG_ACX = BIT(13), - DEBUG_SDIO = BIT(14), - DEBUG_FILTERS = BIT(15), - DEBUG_ADHOC = BIT(16), - DEBUG_ALL = ~0, -}; - -#define DEBUG_LEVEL (DEBUG_NONE) - -#define DEBUG_DUMP_LIMIT 1024 - -#define wl1271_error(fmt, arg...) \ - printk(KERN_ERR DRIVER_PREFIX "ERROR " fmt "\n", ##arg) - -#define wl1271_warning(fmt, arg...) \ - printk(KERN_WARNING DRIVER_PREFIX "WARNING " fmt "\n", ##arg) - -#define wl1271_notice(fmt, arg...) \ - printk(KERN_INFO DRIVER_PREFIX fmt "\n", ##arg) - -#define wl1271_info(fmt, arg...) \ - printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg) - -#define wl1271_debug(level, fmt, arg...) \ - do { \ - if (level & DEBUG_LEVEL) \ - printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg); \ - } while (0) - -#define wl1271_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 wl1271_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 WL1271_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \ - CFG_BSSID_FILTER_EN | \ - CFG_MC_FILTER_EN) - -#define WL1271_DEFAULT_RX_FILTER (CFG_RX_RCTS_ACK | 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 WL1271_FW_NAME "wl1271-fw.bin" -#define WL1271_NVS_NAME "wl1271-nvs.bin" - -#define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff)) -#define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff)) - -#define WL1271_CIPHER_SUITE_GEM 0x00147201 - -#define WL1271_BUSY_WORD_CNT 1 -#define WL1271_BUSY_WORD_LEN (WL1271_BUSY_WORD_CNT * sizeof(u32)) - -#define WL1271_ELP_HW_STATE_ASLEEP 0 -#define WL1271_ELP_HW_STATE_IRQ 1 - -#define WL1271_DEFAULT_BEACON_INT 100 -#define WL1271_DEFAULT_DTIM_PERIOD 1 - -#define ACX_TX_DESCRIPTORS 32 - -#define WL1271_AGGR_BUFFER_SIZE (4 * PAGE_SIZE) - -enum wl1271_state { - WL1271_STATE_OFF, - WL1271_STATE_ON, - WL1271_STATE_PLT, -}; - -enum wl1271_partition_type { - PART_DOWN, - PART_WORK, - PART_DRPW, - - PART_TABLE_LEN -}; - -struct wl1271_partition { - u32 size; - u32 start; -}; - -struct wl1271_partition_set { - struct wl1271_partition mem; - struct wl1271_partition reg; - struct wl1271_partition mem2; - struct wl1271_partition mem3; -}; - -struct wl1271; - -/* FIXME: I'm not sure about this structure name */ -struct wl1271_chip { - u32 id; - char fw_ver[21]; -}; - -struct wl1271_stats { - struct acx_statistics *fw_stats; - unsigned long fw_stats_update; - - unsigned int retry_count; - unsigned int excessive_retries; -}; - -struct wl1271_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 *retry_count; - struct dentry *excessive_retries; - struct dentry *gpio_power; -}; - -#define NUM_TX_QUEUES 4 -#define NUM_RX_PKT_DESC 8 - -/* FW status registers */ -struct wl1271_fw_status { - __le32 intr; - u8 fw_rx_counter; - u8 drv_rx_counter; - u8 reserved; - u8 tx_results_counter; - __le32 rx_pkt_descs[NUM_RX_PKT_DESC]; - __le32 tx_released_blks[NUM_TX_QUEUES]; - __le32 fw_localtime; - __le32 padding[2]; -} __packed; - -struct wl1271_rx_mem_pool_addr { - u32 addr; - u32 addr_extra; -}; - -struct wl1271_scan { - struct cfg80211_scan_request *req; - bool *scanned_ch; - bool failed; - u8 state; - u8 ssid[IW_ESSID_MAX_SIZE+1]; - size_t ssid_len; -}; - -struct wl1271_if_operations { - void (*read)(struct wl1271 *wl, int addr, void *buf, size_t len, - bool fixed); - void (*write)(struct wl1271 *wl, int addr, void *buf, size_t len, - bool fixed); - void (*reset)(struct wl1271 *wl); - void (*init)(struct wl1271 *wl); - int (*power)(struct wl1271 *wl, bool enable); - struct device* (*dev)(struct wl1271 *wl); - void (*enable_irq)(struct wl1271 *wl); - void (*disable_irq)(struct wl1271 *wl); -}; - -struct wl1271 { - struct platform_device *plat_dev; - struct ieee80211_hw *hw; - bool mac80211_registered; - - void *if_priv; - - struct wl1271_if_operations *if_ops; - - void (*set_power)(bool enable); - int irq; - int ref_clock; - - spinlock_t wl_lock; - - enum wl1271_state state; - struct mutex mutex; - -#define WL1271_FLAG_STA_RATES_CHANGED (0) -#define WL1271_FLAG_STA_ASSOCIATED (1) -#define WL1271_FLAG_JOINED (2) -#define WL1271_FLAG_GPIO_POWER (3) -#define WL1271_FLAG_TX_QUEUE_STOPPED (4) -#define WL1271_FLAG_IN_ELP (5) -#define WL1271_FLAG_PSM (6) -#define WL1271_FLAG_PSM_REQUESTED (7) -#define WL1271_FLAG_IRQ_PENDING (8) -#define WL1271_FLAG_IRQ_RUNNING (9) -#define WL1271_FLAG_IDLE (10) -#define WL1271_FLAG_IDLE_REQUESTED (11) -#define WL1271_FLAG_PSPOLL_FAILURE (12) -#define WL1271_FLAG_STA_STATE_SENT (13) -#define WL1271_FLAG_FW_TX_BUSY (14) - unsigned long flags; - - struct wl1271_partition_set part; - - struct wl1271_chip chip; - - int cmd_box_addr; - int event_box_addr; - - u8 *fw; - size_t fw_len; - struct wl1271_nvs_file *nvs; - size_t nvs_len; - - s8 hw_pg_ver; - - u8 bssid[ETH_ALEN]; - u8 mac_addr[ETH_ALEN]; - u8 bss_type; - u8 set_bss_type; - u8 ssid[IW_ESSID_MAX_SIZE + 1]; - u8 ssid_len; - int channel; - - struct wl1271_acx_mem_map *target_mem_map; - - /* Accounting for allocated / available TX blocks on HW */ - u32 tx_blocks_freed[NUM_TX_QUEUES]; - u32 tx_blocks_available; - u32 tx_results_count; - - /* Transmitted TX packets counter for chipset interface */ - u32 tx_packets_count; - - /* Time-offset between host and chipset clocks */ - s64 time_offset; - - /* Session counter for the chipset */ - int session_counter; - - /* Frames scheduled for transmission, not handled yet */ - struct sk_buff_head tx_queue; - - struct work_struct tx_work; - - /* Pending TX frames */ - unsigned long tx_frames_map[BITS_TO_LONGS(ACX_TX_DESCRIPTORS)]; - struct sk_buff *tx_frames[ACX_TX_DESCRIPTORS]; - int tx_frames_cnt; - - /* Security sequence number counters */ - u8 tx_security_last_seq; - s64 tx_security_seq; - - /* FW Rx counter */ - u32 rx_counter; - - /* Rx memory pool address */ - struct wl1271_rx_mem_pool_addr rx_mem_pool_addr; - - /* Intermediate buffer, used for packet aggregation */ - u8 *aggr_buf; - - /* The target interrupt mask */ - struct work_struct irq_work; - - /* Hardware recovery work */ - struct work_struct recovery_work; - - /* The mbox event mask */ - u32 event_mask; - - /* Mailbox pointers */ - u32 mbox_ptr[2]; - - /* Are we currently scanning */ - struct wl1271_scan scan; - struct delayed_work scan_complete_work; - - /* Our association ID */ - u16 aid; - - /* - * currently configured rate set: - * bits 0-15 - 802.11abg rates - * bits 16-23 - 802.11n MCS index mask - * support only 1 stream, thus only 8 bits for the MCS rates (0-7). - */ - u32 sta_rate_set; - u32 basic_rate_set; - u32 basic_rate; - u32 rate_set; - - /* The current band */ - enum ieee80211_band band; - - /* Beaconing interval (needed for ad-hoc) */ - u32 beacon_int; - - /* Default key (for WEP) */ - u32 default_key; - - unsigned int filters; - unsigned int rx_config; - unsigned int rx_filter; - - struct completion *elp_compl; - struct delayed_work elp_work; - struct delayed_work pspoll_work; - - /* counter for ps-poll delivery failures */ - int ps_poll_failures; - - /* retry counter for PSM entries */ - u8 psm_entry_retry; - - /* in dBm */ - int power_level; - - int rssi_thold; - int last_rssi_event; - - struct wl1271_stats stats; - struct wl1271_debugfs debugfs; - - __le32 buffer_32; - u32 buffer_cmd; - u32 buffer_busyword[WL1271_BUSY_WORD_CNT]; - - struct wl1271_fw_status *fw_status; - struct wl1271_tx_hw_res_if *tx_res_if; - - struct ieee80211_vif *vif; - - /* Current chipset configuration */ - struct conf_drv_settings conf; - - bool sg_enabled; - - bool enable_11a; - - struct list_head list; - - /* Most recently reported noise in dBm */ - s8 noise; -}; - -int wl1271_plt_start(struct wl1271 *wl); -int wl1271_plt_stop(struct wl1271 *wl); - -#define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */ - -#define SESSION_COUNTER_MAX 7 /* maximum value for the session counter */ - -#define WL1271_DEFAULT_POWER_LEVEL 0 - -#define WL1271_TX_QUEUE_LOW_WATERMARK 10 -#define WL1271_TX_QUEUE_HIGH_WATERMARK 25 - -/* WL1271 needs a 200ms sleep after power on, and a 20ms sleep before power - on in case is has been shut down shortly before */ -#define WL1271_PRE_POWER_ON_SLEEP 20 /* in miliseconds */ -#define WL1271_POWER_ON_SLEEP 200 /* in miliseconds */ - -/* Macros to handle wl1271.sta_rate_set */ -#define HW_BG_RATES_MASK 0xffff -#define HW_HT_RATES_OFFSET 16 - -#endif diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c deleted file mode 100644 index bd7f95f..0000000 --- a/drivers/net/wireless/wl12xx/wl1271_acx.c +++ /dev/null @@ -1,1336 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 2008-2009 Nokia Corporation - * - * Contact: Luciano Coelho - * - * 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 "wl1271_acx.h" - -#include -#include -#include -#include -#include - -#include "wl1271.h" -#include "wl12xx_80211.h" -#include "wl1271_reg.h" -#include "wl1271_ps.h" - -int wl1271_acx_wake_up_conditions(struct wl1271 *wl) -{ - struct acx_wake_up_condition *wake_up; - int ret; - - wl1271_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 = wl->conf.conn.wake_up_event; - wake_up->listen_interval = wl->conf.conn.listen_interval; - - ret = wl1271_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS, - wake_up, sizeof(*wake_up)); - if (ret < 0) { - wl1271_warning("could not set wake up conditions: %d", ret); - goto out; - } - -out: - kfree(wake_up); - return ret; -} - -int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth) -{ - struct acx_sleep_auth *auth; - int ret; - - wl1271_debug(DEBUG_ACX, "acx sleep auth"); - - auth = kzalloc(sizeof(*auth), GFP_KERNEL); - if (!auth) { - ret = -ENOMEM; - goto out; - } - - auth->sleep_auth = sleep_auth; - - ret = wl1271_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth)); - if (ret < 0) - return ret; - -out: - kfree(auth); - return ret; -} - -int wl1271_acx_tx_power(struct wl1271 *wl, int power) -{ - struct acx_current_tx_power *acx; - int ret; - - wl1271_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 = wl1271_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("configure of tx power failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1271_acx_feature_cfg(struct wl1271 *wl) -{ - struct acx_feature_config *feature; - int ret; - - wl1271_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 = wl1271_cmd_configure(wl, ACX_FEATURE_CFG, - feature, sizeof(*feature)); - if (ret < 0) { - wl1271_error("Couldnt set HW encryption"); - goto out; - } - -out: - kfree(feature); - return ret; -} - -int wl1271_acx_mem_map(struct wl1271 *wl, struct acx_header *mem_map, - size_t len) -{ - int ret; - - wl1271_debug(DEBUG_ACX, "acx mem map"); - - ret = wl1271_cmd_interrogate(wl, ACX_MEM_MAP, mem_map, len); - if (ret < 0) - return ret; - - return 0; -} - -int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl) -{ - struct acx_rx_msdu_lifetime *acx; - int ret; - - wl1271_debug(DEBUG_ACX, "acx rx msdu life time"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->lifetime = cpu_to_le32(wl->conf.rx.rx_msdu_life_time); - ret = wl1271_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME, - acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("failed to set rx msdu life time: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1271_acx_rx_config(struct wl1271 *wl, u32 config, u32 filter) -{ - struct acx_rx_config *rx_config; - int ret; - - wl1271_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 = cpu_to_le32(config); - rx_config->filter_options = cpu_to_le32(filter); - - ret = wl1271_cmd_configure(wl, ACX_RX_CFG, - rx_config, sizeof(*rx_config)); - if (ret < 0) { - wl1271_warning("failed to set rx config: %d", ret); - goto out; - } - -out: - kfree(rx_config); - return ret; -} - -int wl1271_acx_pd_threshold(struct wl1271 *wl) -{ - struct acx_packet_detection *pd; - int ret; - - wl1271_debug(DEBUG_ACX, "acx data pd threshold"); - - pd = kzalloc(sizeof(*pd), GFP_KERNEL); - if (!pd) { - ret = -ENOMEM; - goto out; - } - - pd->threshold = cpu_to_le32(wl->conf.rx.packet_detection_threshold); - - ret = wl1271_cmd_configure(wl, ACX_PD_THRESHOLD, pd, sizeof(*pd)); - if (ret < 0) { - wl1271_warning("failed to set pd threshold: %d", ret); - goto out; - } - -out: - kfree(pd); - return ret; -} - -int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time) -{ - struct acx_slot *slot; - int ret; - - wl1271_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 = wl1271_cmd_configure(wl, ACX_SLOT, slot, sizeof(*slot)); - if (ret < 0) { - wl1271_warning("failed to set slot time: %d", ret); - goto out; - } - -out: - kfree(slot); - return ret; -} - -int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable, - void *mc_list, u32 mc_list_len) -{ - struct acx_dot11_grp_addr_tbl *acx; - int ret; - - wl1271_debug(DEBUG_ACX, "acx group address tbl"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - /* MAC filtering */ - acx->enabled = enable; - acx->num_groups = mc_list_len; - memcpy(acx->mac_table, mc_list, mc_list_len * ETH_ALEN); - - ret = wl1271_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL, - acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("failed to set group addr table: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1271_acx_service_period_timeout(struct wl1271 *wl) -{ - struct acx_rx_timeout *rx_timeout; - int ret; - - rx_timeout = kzalloc(sizeof(*rx_timeout), GFP_KERNEL); - if (!rx_timeout) { - ret = -ENOMEM; - goto out; - } - - wl1271_debug(DEBUG_ACX, "acx service period timeout"); - - rx_timeout->ps_poll_timeout = cpu_to_le16(wl->conf.rx.ps_poll_timeout); - rx_timeout->upsd_timeout = cpu_to_le16(wl->conf.rx.upsd_timeout); - - ret = wl1271_cmd_configure(wl, ACX_SERVICE_PERIOD_TIMEOUT, - rx_timeout, sizeof(*rx_timeout)); - if (ret < 0) { - wl1271_warning("failed to set service period timeout: %d", - ret); - goto out; - } - -out: - kfree(rx_timeout); - return ret; -} - -int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold) -{ - struct acx_rts_threshold *rts; - int ret; - - wl1271_debug(DEBUG_ACX, "acx rts threshold"); - - rts = kzalloc(sizeof(*rts), GFP_KERNEL); - if (!rts) { - ret = -ENOMEM; - goto out; - } - - rts->threshold = cpu_to_le16(rts_threshold); - - ret = wl1271_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts)); - if (ret < 0) { - wl1271_warning("failed to set rts threshold: %d", ret); - goto out; - } - -out: - kfree(rts); - return ret; -} - -int wl1271_acx_dco_itrim_params(struct wl1271 *wl) -{ - struct acx_dco_itrim_params *dco; - struct conf_itrim_settings *c = &wl->conf.itrim; - int ret; - - wl1271_debug(DEBUG_ACX, "acx dco itrim parameters"); - - dco = kzalloc(sizeof(*dco), GFP_KERNEL); - if (!dco) { - ret = -ENOMEM; - goto out; - } - - dco->enable = c->enable; - dco->timeout = cpu_to_le32(c->timeout); - - ret = wl1271_cmd_configure(wl, ACX_SET_DCO_ITRIM_PARAMS, - dco, sizeof(*dco)); - if (ret < 0) { - wl1271_warning("failed to set dco itrim parameters: %d", ret); - goto out; - } - -out: - kfree(dco); - return ret; -} - -int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter) -{ - struct acx_beacon_filter_option *beacon_filter = NULL; - int ret = 0; - - wl1271_debug(DEBUG_ACX, "acx beacon filter opt"); - - if (enable_filter && - wl->conf.conn.bcn_filt_mode == CONF_BCN_FILT_MODE_DISABLED) - goto out; - - beacon_filter = kzalloc(sizeof(*beacon_filter), GFP_KERNEL); - if (!beacon_filter) { - ret = -ENOMEM; - goto out; - } - - beacon_filter->enable = enable_filter; - - /* - * When set to zero, and the filter is enabled, beacons - * without the unicast TIM bit set are dropped. - */ - beacon_filter->max_num_beacons = 0; - - ret = wl1271_cmd_configure(wl, ACX_BEACON_FILTER_OPT, - beacon_filter, sizeof(*beacon_filter)); - if (ret < 0) { - wl1271_warning("failed to set beacon filter opt: %d", ret); - goto out; - } - -out: - kfree(beacon_filter); - return ret; -} - -int wl1271_acx_beacon_filter_table(struct wl1271 *wl) -{ - struct acx_beacon_filter_ie_table *ie_table; - int i, idx = 0; - int ret; - bool vendor_spec = false; - - wl1271_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 = 0; - for (i = 0; i < wl->conf.conn.bcn_filt_ie_count; i++) { - struct conf_bcn_filt_rule *r = &(wl->conf.conn.bcn_filt_ie[i]); - ie_table->table[idx++] = r->ie; - ie_table->table[idx++] = r->rule; - - if (r->ie == WLAN_EID_VENDOR_SPECIFIC) { - /* only one vendor specific ie allowed */ - if (vendor_spec) - continue; - - /* for vendor specific rules configure the - additional fields */ - memcpy(&(ie_table->table[idx]), r->oui, - CONF_BCN_IE_OUI_LEN); - idx += CONF_BCN_IE_OUI_LEN; - ie_table->table[idx++] = r->type; - memcpy(&(ie_table->table[idx]), r->version, - CONF_BCN_IE_VER_LEN); - idx += CONF_BCN_IE_VER_LEN; - vendor_spec = true; - } - - ie_table->num_ie++; - } - - ret = wl1271_cmd_configure(wl, ACX_BEACON_FILTER_TABLE, - ie_table, sizeof(*ie_table)); - if (ret < 0) { - wl1271_warning("failed to set beacon filter table: %d", ret); - goto out; - } - -out: - kfree(ie_table); - return ret; -} - -#define ACX_CONN_MONIT_DISABLE_VALUE 0xffffffff - -int wl1271_acx_conn_monit_params(struct wl1271 *wl, bool enable) -{ - struct acx_conn_monit_params *acx; - u32 threshold = ACX_CONN_MONIT_DISABLE_VALUE; - u32 timeout = ACX_CONN_MONIT_DISABLE_VALUE; - int ret; - - wl1271_debug(DEBUG_ACX, "acx connection monitor parameters: %s", - enable ? "enabled" : "disabled"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - if (enable) { - threshold = wl->conf.conn.synch_fail_thold; - timeout = wl->conf.conn.bss_lose_timeout; - } - - acx->synch_fail_thold = cpu_to_le32(threshold); - acx->bss_lose_timeout = cpu_to_le32(timeout); - - ret = wl1271_cmd_configure(wl, ACX_CONN_MONIT_PARAMS, - acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("failed to set connection monitor " - "parameters: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - - -int wl1271_acx_sg_enable(struct wl1271 *wl, bool enable) -{ - struct acx_bt_wlan_coex *pta; - int ret; - - wl1271_debug(DEBUG_ACX, "acx sg enable"); - - pta = kzalloc(sizeof(*pta), GFP_KERNEL); - if (!pta) { - ret = -ENOMEM; - goto out; - } - - if (enable) - pta->enable = wl->conf.sg.state; - else - pta->enable = CONF_SG_DISABLE; - - ret = wl1271_cmd_configure(wl, ACX_SG_ENABLE, pta, sizeof(*pta)); - if (ret < 0) { - wl1271_warning("failed to set softgemini enable: %d", ret); - goto out; - } - -out: - kfree(pta); - return ret; -} - -int wl1271_acx_sg_cfg(struct wl1271 *wl) -{ - struct acx_bt_wlan_coex_param *param; - struct conf_sg_settings *c = &wl->conf.sg; - int i, ret; - - wl1271_debug(DEBUG_ACX, "acx sg cfg"); - - param = kzalloc(sizeof(*param), GFP_KERNEL); - if (!param) { - ret = -ENOMEM; - goto out; - } - - /* BT-WLAN coext parameters */ - for (i = 0; i < CONF_SG_PARAMS_MAX; i++) - param->params[i] = cpu_to_le32(c->params[i]); - param->param_idx = CONF_SG_PARAMS_ALL; - - ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param)); - if (ret < 0) { - wl1271_warning("failed to set sg config: %d", ret); - goto out; - } - -out: - kfree(param); - return ret; -} - -int wl1271_acx_cca_threshold(struct wl1271 *wl) -{ - struct acx_energy_detection *detection; - int ret; - - wl1271_debug(DEBUG_ACX, "acx cca threshold"); - - detection = kzalloc(sizeof(*detection), GFP_KERNEL); - if (!detection) { - ret = -ENOMEM; - goto out; - } - - detection->rx_cca_threshold = cpu_to_le16(wl->conf.rx.rx_cca_threshold); - detection->tx_energy_detection = wl->conf.tx.tx_energy_detection; - - ret = wl1271_cmd_configure(wl, ACX_CCA_THRESHOLD, - detection, sizeof(*detection)); - if (ret < 0) { - wl1271_warning("failed to set cca threshold: %d", ret); - return ret; - } - -out: - kfree(detection); - return ret; -} - -int wl1271_acx_bcn_dtim_options(struct wl1271 *wl) -{ - struct acx_beacon_broadcast *bb; - int ret; - - wl1271_debug(DEBUG_ACX, "acx bcn dtim options"); - - bb = kzalloc(sizeof(*bb), GFP_KERNEL); - if (!bb) { - ret = -ENOMEM; - goto out; - } - - bb->beacon_rx_timeout = cpu_to_le16(wl->conf.conn.beacon_rx_timeout); - bb->broadcast_timeout = cpu_to_le16(wl->conf.conn.broadcast_timeout); - bb->rx_broadcast_in_ps = wl->conf.conn.rx_broadcast_in_ps; - bb->ps_poll_threshold = wl->conf.conn.ps_poll_threshold; - - ret = wl1271_cmd_configure(wl, ACX_BCN_DTIM_OPTIONS, bb, sizeof(*bb)); - if (ret < 0) { - wl1271_warning("failed to set rx config: %d", ret); - goto out; - } - -out: - kfree(bb); - return ret; -} - -int wl1271_acx_aid(struct wl1271 *wl, u16 aid) -{ - struct acx_aid *acx_aid; - int ret; - - wl1271_debug(DEBUG_ACX, "acx aid"); - - acx_aid = kzalloc(sizeof(*acx_aid), GFP_KERNEL); - if (!acx_aid) { - ret = -ENOMEM; - goto out; - } - - acx_aid->aid = cpu_to_le16(aid); - - ret = wl1271_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid)); - if (ret < 0) { - wl1271_warning("failed to set aid: %d", ret); - goto out; - } - -out: - kfree(acx_aid); - return ret; -} - -int wl1271_acx_event_mbox_mask(struct wl1271 *wl, u32 event_mask) -{ - struct acx_event_mask *mask; - int ret; - - wl1271_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 = cpu_to_le32(0xffffffff); - mask->event_mask = cpu_to_le32(event_mask); - - ret = wl1271_cmd_configure(wl, ACX_EVENT_MBOX_MASK, - mask, sizeof(*mask)); - if (ret < 0) { - wl1271_warning("failed to set acx_event_mbox_mask: %d", ret); - goto out; - } - -out: - kfree(mask); - return ret; -} - -int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble) -{ - struct acx_preamble *acx; - int ret; - - wl1271_debug(DEBUG_ACX, "acx_set_preamble"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->preamble = preamble; - - ret = wl1271_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("Setting of preamble failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1271_acx_cts_protect(struct wl1271 *wl, - enum acx_ctsprotect_type ctsprotect) -{ - struct acx_ctsprotect *acx; - int ret; - - wl1271_debug(DEBUG_ACX, "acx_set_ctsprotect"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->ctsprotect = ctsprotect; - - ret = wl1271_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("Setting of ctsprotect failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats) -{ - int ret; - - wl1271_debug(DEBUG_ACX, "acx statistics"); - - ret = wl1271_cmd_interrogate(wl, ACX_STATISTICS, stats, - sizeof(*stats)); - if (ret < 0) { - wl1271_warning("acx statistics failed: %d", ret); - return -ENOMEM; - } - - return 0; -} - -int wl1271_acx_rate_policies(struct wl1271 *wl) -{ - struct acx_rate_policy *acx; - struct conf_tx_rate_class *c = &wl->conf.tx.rc_conf; - int idx = 0; - int ret = 0; - - wl1271_debug(DEBUG_ACX, "acx rate policies"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - - if (!acx) { - ret = -ENOMEM; - goto out; - } - - /* configure one basic rate class */ - idx = ACX_TX_BASIC_RATE; - acx->rate_class[idx].enabled_rates = cpu_to_le32(wl->basic_rate); - acx->rate_class[idx].short_retry_limit = c->short_retry_limit; - acx->rate_class[idx].long_retry_limit = c->long_retry_limit; - acx->rate_class[idx].aflags = c->aflags; - - /* configure one AP supported rate class */ - idx = ACX_TX_AP_FULL_RATE; - acx->rate_class[idx].enabled_rates = cpu_to_le32(wl->rate_set); - acx->rate_class[idx].short_retry_limit = c->short_retry_limit; - acx->rate_class[idx].long_retry_limit = c->long_retry_limit; - acx->rate_class[idx].aflags = c->aflags; - - acx->rate_class_cnt = cpu_to_le32(ACX_TX_RATE_POLICY_CNT); - - ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("Setting of rate policies failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max, - u8 aifsn, u16 txop) -{ - struct acx_ac_cfg *acx; - int ret = 0; - - wl1271_debug(DEBUG_ACX, "acx ac cfg %d cw_ming %d cw_max %d " - "aifs %d txop %d", ac, cw_min, cw_max, aifsn, txop); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->ac = ac; - acx->cw_min = cw_min; - acx->cw_max = cpu_to_le16(cw_max); - acx->aifsn = aifsn; - acx->tx_op_limit = cpu_to_le16(txop); - - ret = wl1271_cmd_configure(wl, ACX_AC_CFG, acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("acx ac cfg failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type, - u8 tsid, u8 ps_scheme, u8 ack_policy, - u32 apsd_conf0, u32 apsd_conf1) -{ - struct acx_tid_config *acx; - int ret = 0; - - wl1271_debug(DEBUG_ACX, "acx tid config"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->queue_id = queue_id; - acx->channel_type = channel_type; - acx->tsid = tsid; - acx->ps_scheme = ps_scheme; - acx->ack_policy = ack_policy; - acx->apsd_conf[0] = cpu_to_le32(apsd_conf0); - acx->apsd_conf[1] = cpu_to_le32(apsd_conf1); - - ret = wl1271_cmd_configure(wl, ACX_TID_CFG, acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("Setting of tid config failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1271_acx_frag_threshold(struct wl1271 *wl) -{ - struct acx_frag_threshold *acx; - int ret = 0; - - wl1271_debug(DEBUG_ACX, "acx frag threshold"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->frag_threshold = cpu_to_le16(wl->conf.tx.frag_threshold); - ret = wl1271_cmd_configure(wl, ACX_FRAG_CFG, acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("Setting of frag threshold failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1271_acx_tx_config_options(struct wl1271 *wl) -{ - struct acx_tx_config_options *acx; - int ret = 0; - - wl1271_debug(DEBUG_ACX, "acx tx config options"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->tx_compl_timeout = cpu_to_le16(wl->conf.tx.tx_compl_timeout); - acx->tx_compl_threshold = cpu_to_le16(wl->conf.tx.tx_compl_threshold); - ret = wl1271_cmd_configure(wl, ACX_TX_CONFIG_OPT, acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("Setting of tx options failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1271_acx_mem_cfg(struct wl1271 *wl) -{ - struct wl1271_acx_config_memory *mem_conf; - int ret; - - wl1271_debug(DEBUG_ACX, "wl1271 mem cfg"); - - mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); - if (!mem_conf) { - ret = -ENOMEM; - goto out; - } - - /* memory config */ - mem_conf->num_stations = DEFAULT_NUM_STATIONS; - mem_conf->rx_mem_block_num = ACX_RX_MEM_BLOCKS; - mem_conf->tx_min_mem_block_num = ACX_TX_MIN_MEM_BLOCKS; - mem_conf->num_ssid_profiles = ACX_NUM_SSID_PROFILES; - mem_conf->total_tx_descriptors = cpu_to_le32(ACX_TX_DESCRIPTORS); - - ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf, - sizeof(*mem_conf)); - if (ret < 0) { - wl1271_warning("wl1271 mem config failed: %d", ret); - goto out; - } - -out: - kfree(mem_conf); - return ret; -} - -int wl1271_acx_init_mem_config(struct wl1271 *wl) -{ - int ret; - - ret = wl1271_acx_mem_cfg(wl); - if (ret < 0) - return ret; - - wl->target_mem_map = kzalloc(sizeof(struct wl1271_acx_mem_map), - GFP_KERNEL); - if (!wl->target_mem_map) { - wl1271_error("couldn't allocate target memory map"); - return -ENOMEM; - } - - /* we now ask for the firmware built memory map */ - ret = wl1271_acx_mem_map(wl, (void *)wl->target_mem_map, - sizeof(struct wl1271_acx_mem_map)); - if (ret < 0) { - wl1271_error("couldn't retrieve firmware memory map"); - kfree(wl->target_mem_map); - wl->target_mem_map = NULL; - return ret; - } - - /* initialize TX block book keeping */ - wl->tx_blocks_available = - le32_to_cpu(wl->target_mem_map->num_tx_mem_blocks); - wl1271_debug(DEBUG_TX, "available tx blocks: %d", - wl->tx_blocks_available); - - return 0; -} - -int wl1271_acx_init_rx_interrupt(struct wl1271 *wl) -{ - struct wl1271_acx_rx_config_opt *rx_conf; - int ret; - - wl1271_debug(DEBUG_ACX, "wl1271 rx interrupt config"); - - rx_conf = kzalloc(sizeof(*rx_conf), GFP_KERNEL); - if (!rx_conf) { - ret = -ENOMEM; - goto out; - } - - rx_conf->threshold = cpu_to_le16(wl->conf.rx.irq_pkt_threshold); - rx_conf->timeout = cpu_to_le16(wl->conf.rx.irq_timeout); - rx_conf->mblk_threshold = cpu_to_le16(wl->conf.rx.irq_blk_threshold); - rx_conf->queue_type = wl->conf.rx.queue_type; - - ret = wl1271_cmd_configure(wl, ACX_RX_CONFIG_OPT, rx_conf, - sizeof(*rx_conf)); - if (ret < 0) { - wl1271_warning("wl1271 rx config opt failed: %d", ret); - goto out; - } - -out: - kfree(rx_conf); - return ret; -} - -int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable) -{ - struct wl1271_acx_bet_enable *acx = NULL; - int ret = 0; - - wl1271_debug(DEBUG_ACX, "acx bet enable"); - - if (enable && wl->conf.conn.bet_enable == CONF_BET_MODE_DISABLE) - goto out; - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->enable = enable ? CONF_BET_MODE_ENABLE : CONF_BET_MODE_DISABLE; - acx->max_consecutive = wl->conf.conn.bet_max_consecutive; - - ret = wl1271_cmd_configure(wl, ACX_BET_ENABLE, acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("acx bet enable failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, __be32 address) -{ - struct wl1271_acx_arp_filter *acx; - int ret; - - wl1271_debug(DEBUG_ACX, "acx arp ip filter, enable: %d", enable); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->version = ACX_IPV4_VERSION; - acx->enable = enable; - - if (enable == true) - memcpy(acx->address, &address, ACX_IPV4_ADDR_SIZE); - - ret = wl1271_cmd_configure(wl, ACX_ARP_IP_FILTER, - acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("failed to set arp ip filter: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1271_acx_pm_config(struct wl1271 *wl) -{ - struct wl1271_acx_pm_config *acx = NULL; - struct conf_pm_config_settings *c = &wl->conf.pm_config; - int ret = 0; - - wl1271_debug(DEBUG_ACX, "acx pm config"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->host_clk_settling_time = cpu_to_le32(c->host_clk_settling_time); - acx->host_fast_wakeup_support = c->host_fast_wakeup_support; - - ret = wl1271_cmd_configure(wl, ACX_PM_CONFIG, acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("acx pm config failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1271_acx_keep_alive_mode(struct wl1271 *wl, bool enable) -{ - struct wl1271_acx_keep_alive_mode *acx = NULL; - int ret = 0; - - wl1271_debug(DEBUG_ACX, "acx keep alive mode: %d", enable); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->enabled = enable; - - ret = wl1271_cmd_configure(wl, ACX_KEEP_ALIVE_MODE, acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("acx keep alive mode failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid) -{ - struct wl1271_acx_keep_alive_config *acx = NULL; - int ret = 0; - - wl1271_debug(DEBUG_ACX, "acx keep alive config"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->period = cpu_to_le32(wl->conf.conn.keep_alive_interval); - acx->index = index; - acx->tpl_validation = tpl_valid; - acx->trigger = ACX_KEEP_ALIVE_NO_TX; - - ret = wl1271_cmd_configure(wl, ACX_SET_KEEP_ALIVE_CONFIG, - acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("acx keep alive config failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable, - s16 thold, u8 hyst) -{ - struct wl1271_acx_rssi_snr_trigger *acx = NULL; - int ret = 0; - - wl1271_debug(DEBUG_ACX, "acx rssi snr trigger"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - wl->last_rssi_event = -1; - - acx->pacing = cpu_to_le16(wl->conf.roam_trigger.trigger_pacing); - acx->metric = WL1271_ACX_TRIG_METRIC_RSSI_BEACON; - acx->type = WL1271_ACX_TRIG_TYPE_EDGE; - if (enable) - acx->enable = WL1271_ACX_TRIG_ENABLE; - else - acx->enable = WL1271_ACX_TRIG_DISABLE; - - acx->index = WL1271_ACX_TRIG_IDX_RSSI; - acx->dir = WL1271_ACX_TRIG_DIR_BIDIR; - acx->threshold = cpu_to_le16(thold); - acx->hysteresis = hyst; - - ret = wl1271_cmd_configure(wl, ACX_RSSI_SNR_TRIGGER, acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("acx rssi snr trigger setting failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl) -{ - struct wl1271_acx_rssi_snr_avg_weights *acx = NULL; - struct conf_roam_trigger_settings *c = &wl->conf.roam_trigger; - int ret = 0; - - wl1271_debug(DEBUG_ACX, "acx rssi snr avg weights"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->rssi_beacon = c->avg_weight_rssi_beacon; - acx->rssi_data = c->avg_weight_rssi_data; - acx->snr_beacon = c->avg_weight_snr_beacon; - acx->snr_data = c->avg_weight_snr_data; - - ret = wl1271_cmd_configure(wl, ACX_RSSI_SNR_WEIGHTS, acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("acx rssi snr trigger weights failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, - struct ieee80211_sta_ht_cap *ht_cap, - bool allow_ht_operation) -{ - struct wl1271_acx_ht_capabilities *acx; - u8 mac_address[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - int ret = 0; - - wl1271_debug(DEBUG_ACX, "acx ht capabilities setting"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - /* Allow HT Operation ? */ - if (allow_ht_operation) { - acx->ht_capabilites = - WL1271_ACX_FW_CAP_HT_OPERATION; - if (ht_cap->cap & IEEE80211_HT_CAP_GRN_FLD) - acx->ht_capabilites |= - WL1271_ACX_FW_CAP_GREENFIELD_FRAME_FORMAT; - if (ht_cap->cap & IEEE80211_HT_CAP_SGI_20) - acx->ht_capabilites |= - WL1271_ACX_FW_CAP_SHORT_GI_FOR_20MHZ_PACKETS; - if (ht_cap->cap & IEEE80211_HT_CAP_LSIG_TXOP_PROT) - acx->ht_capabilites |= - WL1271_ACX_FW_CAP_LSIG_TXOP_PROTECTION; - - /* get data from A-MPDU parameters field */ - acx->ampdu_max_length = ht_cap->ampdu_factor; - acx->ampdu_min_spacing = ht_cap->ampdu_density; - - memcpy(acx->mac_address, mac_address, ETH_ALEN); - } else { /* HT operations are not allowed */ - acx->ht_capabilites = 0; - } - - ret = wl1271_cmd_configure(wl, ACX_PEER_HT_CAP, acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("acx ht capabilities setting failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1271_acx_set_ht_information(struct wl1271 *wl, - u16 ht_operation_mode) -{ - struct wl1271_acx_ht_information *acx; - int ret = 0; - - wl1271_debug(DEBUG_ACX, "acx ht information setting"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->ht_protection = - (u8)(ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION); - acx->rifs_mode = 0; - acx->gf_protection = 0; - acx->ht_tx_burst_limit = 0; - acx->dual_cts_protection = 0; - - ret = wl1271_cmd_configure(wl, ACX_HT_BSS_OPERATION, acx, sizeof(*acx)); - - if (ret < 0) { - wl1271_warning("acx ht information setting failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime) -{ - struct wl1271_acx_fw_tsf_information *tsf_info; - int ret; - - tsf_info = kzalloc(sizeof(*tsf_info), GFP_KERNEL); - if (!tsf_info) { - ret = -ENOMEM; - goto out; - } - - ret = wl1271_cmd_interrogate(wl, ACX_TSF_INFO, - tsf_info, sizeof(*tsf_info)); - if (ret < 0) { - wl1271_warning("acx tsf info interrogate failed"); - goto out; - } - - *mactime = le32_to_cpu(tsf_info->current_tsf_low) | - ((u64) le32_to_cpu(tsf_info->current_tsf_high) << 32); - -out: - kfree(tsf_info); - return ret; -} diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h deleted file mode 100644 index b7c4908..0000000 --- a/drivers/net/wireless/wl12xx/wl1271_acx.h +++ /dev/null @@ -1,1185 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. - * Copyright (C) 2008-2010 Nokia Corporation - * - * Contact: Luciano Coelho - * - * 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 __WL1271_ACX_H__ -#define __WL1271_ACX_H__ - -#include "wl1271.h" -#include "wl1271_cmd.h" - -/************************************************************************* - - Host Interrupt Register (WiLink -> Host) - -**************************************************************************/ -/* HW Initiated interrupt Watchdog timer expiration */ -#define WL1271_ACX_INTR_WATCHDOG BIT(0) -/* Init sequence is done (masked interrupt, detection through polling only ) */ -#define WL1271_ACX_INTR_INIT_COMPLETE BIT(1) -/* Event was entered to Event MBOX #A*/ -#define WL1271_ACX_INTR_EVENT_A BIT(2) -/* Event was entered to Event MBOX #B*/ -#define WL1271_ACX_INTR_EVENT_B BIT(3) -/* Command processing completion*/ -#define WL1271_ACX_INTR_CMD_COMPLETE BIT(4) -/* Signaling the host on HW wakeup */ -#define WL1271_ACX_INTR_HW_AVAILABLE BIT(5) -/* The MISC bit is used for aggregation of RX, TxComplete and TX rate update */ -#define WL1271_ACX_INTR_DATA BIT(6) -/* Trace meassge on MBOX #A */ -#define WL1271_ACX_INTR_TRACE_A BIT(7) -/* Trace meassge on MBOX #B */ -#define WL1271_ACX_INTR_TRACE_B BIT(8) - -#define WL1271_ACX_INTR_ALL 0xFFFFFFFF -#define WL1271_ACX_ALL_EVENTS_VECTOR (WL1271_ACX_INTR_WATCHDOG | \ - WL1271_ACX_INTR_INIT_COMPLETE | \ - WL1271_ACX_INTR_EVENT_A | \ - WL1271_ACX_INTR_EVENT_B | \ - WL1271_ACX_INTR_CMD_COMPLETE | \ - WL1271_ACX_INTR_HW_AVAILABLE | \ - WL1271_ACX_INTR_DATA) - -#define WL1271_INTR_MASK (WL1271_ACX_INTR_WATCHDOG | \ - WL1271_ACX_INTR_EVENT_A | \ - WL1271_ACX_INTR_EVENT_B | \ - WL1271_ACX_INTR_HW_AVAILABLE | \ - WL1271_ACX_INTR_DATA) - -/* Target's information element */ -struct acx_header { - struct wl1271_cmd_header cmd; - - /* acx (or information element) header */ - __le16 id; - - /* payload length (not including headers */ - __le16 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.*/ - __le32 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.*/ - __le32 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.*/ - __le32 valid_frame; - - /* the number of missed sequence numbers in the squentially */ - /* values of frames seq numbers */ - __le32 seq_num_miss; -} __packed; - -enum wl1271_psm_mode { - /* Active mode */ - WL1271_PSM_CAM = 0, - - /* Power save mode */ - WL1271_PSM_PS = 1, - - /* Extreme low power */ - WL1271_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 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. - */ - __le32 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; - - __le32 config_options; - __le32 filter_options; -} __packed; - -struct acx_packet_detection { - struct acx_header header; - - __le32 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 ACX_MC_ADDRESS_GROUP_MAX (8) -#define ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ACX_MC_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; - -struct acx_rx_timeout { - struct acx_header header; - - __le16 ps_poll_timeout; - __le16 upsd_timeout; -} __packed; - -struct acx_rts_threshold { - struct acx_header header; - - __le16 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)) - -struct acx_beacon_filter_ie_table { - struct acx_header header; - - u8 num_ie; - u8 pad[3]; - u8 table[BEACON_FILTER_TABLE_MAX_SIZE]; -} __packed; - -struct acx_conn_monit_params { - struct acx_header header; - - __le32 synch_fail_thold; /* number of beacons missed */ - __le32 bss_lose_timeout; /* number of TU's from synch fail */ -} __packed; - -struct acx_bt_wlan_coex { - struct acx_header header; - - u8 enable; - u8 pad[3]; -} __packed; - -struct acx_bt_wlan_coex_param { - struct acx_header header; - - __le32 params[CONF_SG_PARAMS_MAX]; - u8 param_idx; - u8 padding[3]; -} __packed; - -struct acx_dco_itrim_params { - struct acx_header header; - - u8 enable; - u8 padding[3]; - __le32 timeout; -} __packed; - -struct acx_energy_detection { - struct acx_header header; - - /* The RX Clear Channel Assessment threshold in the PHY */ - __le16 rx_cca_threshold; - u8 tx_energy_detection; - u8 pad; -} __packed; - -struct acx_beacon_broadcast { - struct acx_header header; - - __le16 beacon_rx_timeout; - __le16 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; - - __le32 event_mask; - __le32 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) - -/* When set, disable HW encryption */ -#define DF_ENCRYPTION_DISABLE 0x01 -#define DF_SNIFF_MODE_ENABLE 0x80 - -struct acx_feature_config { - struct acx_header header; - - __le32 options; - __le32 data_flow_options; -} __packed; - -struct acx_current_tx_power { - struct acx_header header; - - u8 current_tx_power; - u8 padding[3]; -} __packed; - -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. - */ - __le16 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 { - __le32 internal_desc_overflow; -} __packed; - -struct acx_rx_statistics { - __le32 out_of_mem; - __le32 hdr_overflow; - __le32 hw_stuck; - __le32 dropped; - __le32 fcs_err; - __le32 xfr_hint_trig; - __le32 path_reset; - __le32 reset_counter; -} __packed; - -struct acx_dma_statistics { - __le32 rx_requested; - __le32 rx_errors; - __le32 tx_requested; - __le32 tx_errors; -} __packed; - -struct acx_isr_statistics { - /* host command complete */ - __le32 cmd_cmplt; - - /* fiqisr() */ - __le32 fiqs; - - /* (INT_STS_ND & INT_TRIG_RX_HEADER) */ - __le32 rx_headers; - - /* (INT_STS_ND & INT_TRIG_RX_CMPLT) */ - __le32 rx_completes; - - /* (INT_STS_ND & INT_TRIG_NO_RX_BUF) */ - __le32 rx_mem_overflow; - - /* (INT_STS_ND & INT_TRIG_S_RX_RDY) */ - __le32 rx_rdys; - - /* irqisr() */ - __le32 irqs; - - /* (INT_STS_ND & INT_TRIG_TX_PROC) */ - __le32 tx_procs; - - /* (INT_STS_ND & INT_TRIG_DECRYPT_DONE) */ - __le32 decrypt_done; - - /* (INT_STS_ND & INT_TRIG_DMA0) */ - __le32 dma0_done; - - /* (INT_STS_ND & INT_TRIG_DMA1) */ - __le32 dma1_done; - - /* (INT_STS_ND & INT_TRIG_TX_EXC_CMPLT) */ - __le32 tx_exch_complete; - - /* (INT_STS_ND & INT_TRIG_COMMAND) */ - __le32 commands; - - /* (INT_STS_ND & INT_TRIG_RX_PROC) */ - __le32 rx_procs; - - /* (INT_STS_ND & INT_TRIG_PM_802) */ - __le32 hw_pm_mode_changes; - - /* (INT_STS_ND & INT_TRIG_ACKNOWLEDGE) */ - __le32 host_acknowledges; - - /* (INT_STS_ND & INT_TRIG_PM_PCI) */ - __le32 pci_pm; - - /* (INT_STS_ND & INT_TRIG_ACM_WAKEUP) */ - __le32 wakeups; - - /* (INT_STS_ND & INT_TRIG_LOW_RSSI) */ - __le32 low_rssi; -} __packed; - -struct acx_wep_statistics { - /* WEP address keys configured */ - __le32 addr_key_count; - - /* default keys configured */ - __le32 default_key_count; - - __le32 reserved; - - /* number of times that WEP key not found on lookup */ - __le32 key_not_found; - - /* number of times that WEP key decryption failed */ - __le32 decrypt_fail; - - /* WEP packets decrypted */ - __le32 packets; - - /* WEP decrypt interrupts */ - __le32 interrupt; -} __packed; - -#define ACX_MISSED_BEACONS_SPREAD 10 - -struct acx_pwr_statistics { - /* the amount of enters into power save mode (both PD & ELP) */ - __le32 ps_enter; - - /* the amount of enters into ELP mode */ - __le32 elp_enter; - - /* the amount of missing beacon interrupts to the host */ - __le32 missing_bcns; - - /* the amount of wake on host-access times */ - __le32 wake_on_host; - - /* the amount of wake on timer-expire */ - __le32 wake_on_timer_exp; - - /* the number of packets that were transmitted with PS bit set */ - __le32 tx_with_ps; - - /* the number of packets that were transmitted with PS bit clear */ - __le32 tx_without_ps; - - /* the number of received beacons */ - __le32 rcvd_beacons; - - /* the number of entering into PowerOn (power save off) */ - __le32 power_save_off; - - /* the number of entries into power save mode */ - __le16 enable_ps; - - /* - * the number of exits from power save, not including failed PS - * transitions - */ - __le16 disable_ps; - - /* - * the number of times the TSF counter was adjusted because - * of drift - */ - __le32 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. - */ - __le32 cont_miss_bcns_spread[ACX_MISSED_BEACONS_SPREAD]; - - /* the number of beacons in awake mode */ - __le32 rcvd_awake_beacons; -} __packed; - -struct acx_mic_statistics { - __le32 rx_pkts; - __le32 calc_failure; -} __packed; - -struct acx_aes_statistics { - __le32 encrypt_fail; - __le32 decrypt_fail; - __le32 encrypt_packets; - __le32 decrypt_packets; - __le32 encrypt_interrupt; - __le32 decrypt_interrupt; -} __packed; - -struct acx_event_statistics { - __le32 heart_beat; - __le32 calibration; - __le32 rx_mismatch; - __le32 rx_mem_empty; - __le32 rx_pool; - __le32 oom_late; - __le32 phy_transmit_error; - __le32 tx_stuck; -} __packed; - -struct acx_ps_statistics { - __le32 pspoll_timeouts; - __le32 upsd_timeouts; - __le32 upsd_max_sptime; - __le32 upsd_max_apturn; - __le32 pspoll_max_apturn; - __le32 pspoll_utilization; - __le32 upsd_utilization; -} __packed; - -struct acx_rxpipe_statistics { - __le32 rx_prep_beacon_drop; - __le32 descr_host_int_trig_rx_data; - __le32 beacon_buffer_thres_host_int_trig_rx_data; - __le32 missed_beacon_host_int_trig_rx_data; - __le32 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; - -struct acx_rate_class { - __le32 enabled_rates; - u8 short_retry_limit; - u8 long_retry_limit; - u8 aflags; - u8 reserved; -}; - -#define ACX_TX_BASIC_RATE 0 -#define ACX_TX_AP_FULL_RATE 1 -#define ACX_TX_RATE_POLICY_CNT 2 -struct acx_rate_policy { - struct acx_header header; - - __le32 rate_class_cnt; - struct acx_rate_class rate_class[CONF_TX_MAX_RATE_CLASSES]; -} __packed; - -struct acx_ac_cfg { - struct acx_header header; - u8 ac; - u8 cw_min; - __le16 cw_max; - u8 aifsn; - u8 reserved; - __le16 tx_op_limit; -} __packed; - -struct acx_tid_config { - struct acx_header header; - u8 queue_id; - u8 channel_type; - u8 tsid; - u8 ps_scheme; - u8 ack_policy; - u8 padding[3]; - __le32 apsd_conf[2]; -} __packed; - -struct acx_frag_threshold { - struct acx_header header; - __le16 frag_threshold; - u8 padding[2]; -} __packed; - -struct acx_tx_config_options { - struct acx_header header; - __le16 tx_compl_timeout; /* msec */ - __le16 tx_compl_threshold; /* number of packets */ -} __packed; - -#define ACX_RX_MEM_BLOCKS 70 -#define ACX_TX_MIN_MEM_BLOCKS 40 -#define ACX_TX_DESCRIPTORS 32 -#define ACX_NUM_SSID_PROFILES 1 - -struct wl1271_acx_config_memory { - struct acx_header header; - - u8 rx_mem_block_num; - u8 tx_min_mem_block_num; - u8 num_stations; - u8 num_ssid_profiles; - __le32 total_tx_descriptors; -} __packed; - -struct wl1271_acx_mem_map { - struct acx_header header; - - __le32 code_start; - __le32 code_end; - - __le32 wep_defkey_start; - __le32 wep_defkey_end; - - __le32 sta_table_start; - __le32 sta_table_end; - - __le32 packet_template_start; - __le32 packet_template_end; - - /* Address of the TX result interface (control block) */ - __le32 tx_result; - __le32 tx_result_queue_start; - - __le32 queue_memory_start; - __le32 queue_memory_end; - - __le32 packet_memory_pool_start; - __le32 packet_memory_pool_end; - - __le32 debug_buffer1_start; - __le32 debug_buffer1_end; - - __le32 debug_buffer2_start; - __le32 debug_buffer2_end; - - /* Number of blocks FW allocated for TX packets */ - __le32 num_tx_mem_blocks; - - /* Number of blocks FW allocated for RX packets */ - __le32 num_rx_mem_blocks; - - /* the following 4 fields are valid in SLAVE mode only */ - u8 *tx_cbuf; - u8 *rx_cbuf; - __le32 rx_ctrl; - __le32 tx_ctrl; -} __packed; - -struct wl1271_acx_rx_config_opt { - struct acx_header header; - - __le16 mblk_threshold; - __le16 threshold; - __le16 timeout; - u8 queue_type; - u8 reserved; -} __packed; - - -struct wl1271_acx_bet_enable { - struct acx_header header; - - u8 enable; - u8 max_consecutive; - u8 padding[2]; -} __packed; - -#define ACX_IPV4_VERSION 4 -#define ACX_IPV6_VERSION 6 -#define ACX_IPV4_ADDR_SIZE 4 -struct wl1271_acx_arp_filter { - struct acx_header header; - u8 version; /* ACX_IPV4_VERSION, ACX_IPV6_VERSION */ - u8 enable; /* 1 to enable ARP filtering, 0 to disable */ - u8 padding[2]; - u8 address[16]; /* The configured device IP address - all ARP - requests directed to this IP address will pass - through. For IPv4, the first four bytes are - used. */ -} __packed; - -struct wl1271_acx_pm_config { - struct acx_header header; - - __le32 host_clk_settling_time; - u8 host_fast_wakeup_support; - u8 padding[3]; -} __packed; - -struct wl1271_acx_keep_alive_mode { - struct acx_header header; - - u8 enabled; - u8 padding[3]; -} __packed; - -enum { - ACX_KEEP_ALIVE_NO_TX = 0, - ACX_KEEP_ALIVE_PERIOD_ONLY -}; - -enum { - ACX_KEEP_ALIVE_TPL_INVALID = 0, - ACX_KEEP_ALIVE_TPL_VALID -}; - -struct wl1271_acx_keep_alive_config { - struct acx_header header; - - __le32 period; - u8 index; - u8 tpl_validation; - u8 trigger; - u8 padding; -} __packed; - -enum { - WL1271_ACX_TRIG_TYPE_LEVEL = 0, - WL1271_ACX_TRIG_TYPE_EDGE, -}; - -enum { - WL1271_ACX_TRIG_DIR_LOW = 0, - WL1271_ACX_TRIG_DIR_HIGH, - WL1271_ACX_TRIG_DIR_BIDIR, -}; - -enum { - WL1271_ACX_TRIG_ENABLE = 1, - WL1271_ACX_TRIG_DISABLE, -}; - -enum { - WL1271_ACX_TRIG_METRIC_RSSI_BEACON = 0, - WL1271_ACX_TRIG_METRIC_RSSI_DATA, - WL1271_ACX_TRIG_METRIC_SNR_BEACON, - WL1271_ACX_TRIG_METRIC_SNR_DATA, -}; - -enum { - WL1271_ACX_TRIG_IDX_RSSI = 0, - WL1271_ACX_TRIG_COUNT = 8, -}; - -struct wl1271_acx_rssi_snr_trigger { - struct acx_header header; - - __le16 threshold; - __le16 pacing; /* 0 - 60000 ms */ - u8 metric; - u8 type; - u8 dir; - u8 hysteresis; - u8 index; - u8 enable; - u8 padding[2]; -}; - -struct wl1271_acx_rssi_snr_avg_weights { - struct acx_header header; - - u8 rssi_beacon; - u8 rssi_data; - u8 snr_beacon; - u8 snr_data; -}; - -/* - * ACX_PEER_HT_CAP - * Configure HT capabilities - declare the capabilities of the peer - * we are connected to. - */ -struct wl1271_acx_ht_capabilities { - struct acx_header header; - - /* - * bit 0 - Allow HT Operation - * bit 1 - Allow Greenfield format in TX - * bit 2 - Allow Short GI in TX - * bit 3 - Allow L-SIG TXOP Protection in TX - * bit 4 - Allow HT Control fields in TX. - * Note, driver will still leave space for HT control in packets - * regardless of the value of this field. FW will be responsible - * to drop the HT field from any frame when this Bit set to 0. - * bit 5 - Allow RD initiation in TXOP. FW is allowed to initate RD. - * Exact policy setting for this feature is TBD. - * Note, this bit can only be set to 1 if bit 3 is set to 1. - */ - __le32 ht_capabilites; - - /* - * Indicates to which peer these capabilities apply. - * For infrastructure use ff:ff:ff:ff:ff:ff that indicates relevance - * for all peers. - * Only valid for IBSS/DLS operation. - */ - u8 mac_address[ETH_ALEN]; - - /* - * This the maximum A-MPDU length supported by the AP. The FW may not - * exceed this length when sending A-MPDUs - */ - u8 ampdu_max_length; - - /* This is the minimal spacing required when sending A-MPDUs to the AP*/ - u8 ampdu_min_spacing; -} __packed; - -/* HT Capabilites Fw Bit Mask Mapping */ -#define WL1271_ACX_FW_CAP_HT_OPERATION BIT(0) -#define WL1271_ACX_FW_CAP_GREENFIELD_FRAME_FORMAT BIT(1) -#define WL1271_ACX_FW_CAP_SHORT_GI_FOR_20MHZ_PACKETS BIT(2) -#define WL1271_ACX_FW_CAP_LSIG_TXOP_PROTECTION BIT(3) -#define WL1271_ACX_FW_CAP_HT_CONTROL_FIELDS BIT(4) -#define WL1271_ACX_FW_CAP_RD_INITIATION BIT(5) - - -/* - * ACX_HT_BSS_OPERATION - * Configure HT capabilities - AP rules for behavior in the BSS. - */ -struct wl1271_acx_ht_information { - struct acx_header header; - - /* Values: 0 - RIFS not allowed, 1 - RIFS allowed */ - u8 rifs_mode; - - /* Values: 0 - 3 like in spec */ - u8 ht_protection; - - /* Values: 0 - GF protection not required, 1 - GF protection required */ - u8 gf_protection; - - /*Values: 0 - TX Burst limit not required, 1 - TX Burst Limit required*/ - u8 ht_tx_burst_limit; - - /* - * Values: 0 - Dual CTS protection not required, - * 1 - Dual CTS Protection required - * Note: When this value is set to 1 FW will protect all TXOP with RTS - * frame and will not use CTS-to-self regardless of the value of the - * ACX_CTS_PROTECTION information element - */ - u8 dual_cts_protection; - - u8 padding[3]; -} __packed; - -struct wl1271_acx_fw_tsf_information { - struct acx_header header; - - __le32 current_tsf_high; - __le32 current_tsf_low; - __le32 last_bttt_high; - __le32 last_tbtt_low; - u8 last_dtim_count; - u8 padding[3]; -} __packed; - -enum { - ACX_WAKE_UP_CONDITIONS = 0x0002, - ACX_MEM_CFG = 0x0003, - ACX_SLOT = 0x0004, - ACX_AC_CFG = 0x0007, - ACX_MEM_MAP = 0x0008, - ACX_AID = 0x000A, - /* ACX_FW_REV is missing in the ref driver, but seems to work */ - ACX_FW_REV = 0x000D, - ACX_MEDIUM_USAGE = 0x000F, - ACX_RX_CFG = 0x0010, - ACX_TX_QUEUE_CFG = 0x0011, /* FIXME: only used by wl1251 */ - ACX_STATISTICS = 0x0013, /* Debug API */ - ACX_PWR_CONSUMPTION_STATISTICS = 0x0014, - ACX_FEATURE_CFG = 0x0015, - ACX_TID_CFG = 0x001A, - ACX_PS_RX_STREAMING = 0x001B, - ACX_BEACON_FILTER_OPT = 0x001F, - ACX_NOISE_HIST = 0x0021, - ACX_HDK_VERSION = 0x0022, /* ??? */ - ACX_PD_THRESHOLD = 0x0023, - ACX_TX_CONFIG_OPT = 0x0024, - ACX_CCA_THRESHOLD = 0x0025, - ACX_EVENT_MBOX_MASK = 0x0026, - ACX_CONN_MONIT_PARAMS = 0x002D, - ACX_CONS_TX_FAILURE = 0x002F, - ACX_BCN_DTIM_OPTIONS = 0x0031, - ACX_SG_ENABLE = 0x0032, - ACX_SG_CFG = 0x0033, - 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_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_RX_CONFIG_OPT = 0x004E, - ACX_FRAG_CFG = 0x004F, - ACX_BET_ENABLE = 0x0050, - ACX_RSSI_SNR_TRIGGER = 0x0051, - ACX_RSSI_SNR_WEIGHTS = 0x0052, - ACX_KEEP_ALIVE_MODE = 0x0053, - ACX_SET_KEEP_ALIVE_CONFIG = 0x0054, - ACX_BA_SESSION_RESPONDER_POLICY = 0x0055, - ACX_BA_SESSION_INITIATOR_POLICY = 0x0056, - ACX_PEER_HT_CAP = 0x0057, - ACX_HT_BSS_OPERATION = 0x0058, - ACX_COEX_ACTIVITY = 0x0059, - ACX_SET_DCO_ITRIM_PARAMS = 0x0061, - DOT11_RX_MSDU_LIFE_TIME = 0x1004, - DOT11_CUR_TX_PWR = 0x100D, - DOT11_RX_DOT11_MODE = 0x1012, - DOT11_RTS_THRESHOLD = 0x1013, - DOT11_GROUP_ADDRESS_TBL = 0x1014, - ACX_PM_CONFIG = 0x1016, - - MAX_DOT11_IE = DOT11_GROUP_ADDRESS_TBL, - - MAX_IE = 0xFFFF -}; - - -int wl1271_acx_wake_up_conditions(struct wl1271 *wl); -int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth); -int wl1271_acx_tx_power(struct wl1271 *wl, int power); -int wl1271_acx_feature_cfg(struct wl1271 *wl); -int wl1271_acx_mem_map(struct wl1271 *wl, - struct acx_header *mem_map, size_t len); -int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl); -int wl1271_acx_rx_config(struct wl1271 *wl, u32 config, u32 filter); -int wl1271_acx_pd_threshold(struct wl1271 *wl); -int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time); -int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable, - void *mc_list, u32 mc_list_len); -int wl1271_acx_service_period_timeout(struct wl1271 *wl); -int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold); -int wl1271_acx_dco_itrim_params(struct wl1271 *wl); -int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter); -int wl1271_acx_beacon_filter_table(struct wl1271 *wl); -int wl1271_acx_conn_monit_params(struct wl1271 *wl, bool enable); -int wl1271_acx_sg_enable(struct wl1271 *wl, bool enable); -int wl1271_acx_sg_cfg(struct wl1271 *wl); -int wl1271_acx_cca_threshold(struct wl1271 *wl); -int wl1271_acx_bcn_dtim_options(struct wl1271 *wl); -int wl1271_acx_aid(struct wl1271 *wl, u16 aid); -int wl1271_acx_event_mbox_mask(struct wl1271 *wl, u32 event_mask); -int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble); -int wl1271_acx_cts_protect(struct wl1271 *wl, - enum acx_ctsprotect_type ctsprotect); -int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats); -int wl1271_acx_rate_policies(struct wl1271 *wl); -int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max, - u8 aifsn, u16 txop); -int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type, - u8 tsid, u8 ps_scheme, u8 ack_policy, - u32 apsd_conf0, u32 apsd_conf1); -int wl1271_acx_frag_threshold(struct wl1271 *wl); -int wl1271_acx_tx_config_options(struct wl1271 *wl); -int wl1271_acx_mem_cfg(struct wl1271 *wl); -int wl1271_acx_init_mem_config(struct wl1271 *wl); -int wl1271_acx_init_rx_interrupt(struct wl1271 *wl); -int wl1271_acx_smart_reflex(struct wl1271 *wl); -int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable); -int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, __be32 address); -int wl1271_acx_pm_config(struct wl1271 *wl); -int wl1271_acx_keep_alive_mode(struct wl1271 *wl, bool enable); -int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid); -int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable, - s16 thold, u8 hyst); -int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl); -int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, - struct ieee80211_sta_ht_cap *ht_cap, - bool allow_ht_operation); -int wl1271_acx_set_ht_information(struct wl1271 *wl, - u16 ht_operation_mode); -int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime); - -#endif /* __WL1271_ACX_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c deleted file mode 100644 index 5b19072..0000000 --- a/drivers/net/wireless/wl12xx/wl1271_boot.c +++ /dev/null @@ -1,591 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 2008-2010 Nokia Corporation - * - * Contact: Luciano Coelho - * - * 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 "wl1271_acx.h" -#include "wl1271_reg.h" -#include "wl1271_boot.h" -#include "wl1271_io.h" -#include "wl1271_event.h" - -static struct wl1271_partition_set part_table[PART_TABLE_LEN] = { - [PART_DOWN] = { - .mem = { - .start = 0x00000000, - .size = 0x000177c0 - }, - .reg = { - .start = REGISTERS_BASE, - .size = 0x00008800 - }, - .mem2 = { - .start = 0x00000000, - .size = 0x00000000 - }, - .mem3 = { - .start = 0x00000000, - .size = 0x00000000 - }, - }, - - [PART_WORK] = { - .mem = { - .start = 0x00040000, - .size = 0x00014fc0 - }, - .reg = { - .start = REGISTERS_BASE, - .size = 0x0000a000 - }, - .mem2 = { - .start = 0x003004f8, - .size = 0x00000004 - }, - .mem3 = { - .start = 0x00040404, - .size = 0x00000000 - }, - }, - - [PART_DRPW] = { - .mem = { - .start = 0x00040000, - .size = 0x00014fc0 - }, - .reg = { - .start = DRPW_BASE, - .size = 0x00006000 - }, - .mem2 = { - .start = 0x00000000, - .size = 0x00000000 - }, - .mem3 = { - .start = 0x00000000, - .size = 0x00000000 - } - } -}; - -static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag) -{ - u32 cpu_ctrl; - - /* 10.5.0 run the firmware (I) */ - cpu_ctrl = wl1271_read32(wl, ACX_REG_ECPU_CONTROL); - - /* 10.5.1 run the firmware (II) */ - cpu_ctrl |= flag; - wl1271_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); -} - -static void wl1271_boot_fw_version(struct wl1271 *wl) -{ - struct wl1271_static_data static_data; - - wl1271_read(wl, wl->cmd_box_addr, &static_data, sizeof(static_data), - false); - - strncpy(wl->chip.fw_ver, static_data.fw_version, - sizeof(wl->chip.fw_ver)); - - /* make sure the string is NULL-terminated */ - wl->chip.fw_ver[sizeof(wl->chip.fw_ver) - 1] = '\0'; -} - -static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, - size_t fw_data_len, u32 dest) -{ - struct wl1271_partition_set partition; - int addr, chunk_num, partition_limit; - u8 *p, *chunk; - - /* whal_FwCtrl_LoadFwImageSm() */ - - wl1271_debug(DEBUG_BOOT, "starting firmware upload"); - - wl1271_debug(DEBUG_BOOT, "fw_data_len %zd chunk_size %d", - fw_data_len, CHUNK_SIZE); - - if ((fw_data_len % 4) != 0) { - wl1271_error("firmware length not multiple of four"); - return -EIO; - } - - chunk = kmalloc(CHUNK_SIZE, GFP_KERNEL); - if (!chunk) { - wl1271_error("allocation for firmware upload chunk failed"); - return -ENOMEM; - } - - memcpy(&partition, &part_table[PART_DOWN], sizeof(partition)); - partition.mem.start = dest; - wl1271_set_partition(wl, &partition); - - /* 10.1 set partition limit and chunk num */ - chunk_num = 0; - partition_limit = part_table[PART_DOWN].mem.size; - - while (chunk_num < fw_data_len / CHUNK_SIZE) { - /* 10.2 update partition, if needed */ - addr = dest + (chunk_num + 2) * CHUNK_SIZE; - if (addr > partition_limit) { - addr = dest + chunk_num * CHUNK_SIZE; - partition_limit = chunk_num * CHUNK_SIZE + - part_table[PART_DOWN].mem.size; - partition.mem.start = addr; - wl1271_set_partition(wl, &partition); - } - - /* 10.3 upload the chunk */ - addr = dest + chunk_num * CHUNK_SIZE; - p = buf + chunk_num * CHUNK_SIZE; - memcpy(chunk, p, CHUNK_SIZE); - wl1271_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", - p, addr); - wl1271_write(wl, addr, chunk, CHUNK_SIZE, false); - - chunk_num++; - } - - /* 10.4 upload the last chunk */ - addr = dest + chunk_num * CHUNK_SIZE; - p = buf + chunk_num * CHUNK_SIZE; - memcpy(chunk, p, fw_data_len % CHUNK_SIZE); - wl1271_debug(DEBUG_BOOT, "uploading fw last chunk (%zd B) 0x%p to 0x%x", - fw_data_len % CHUNK_SIZE, p, addr); - wl1271_write(wl, addr, chunk, fw_data_len % CHUNK_SIZE, false); - - kfree(chunk); - return 0; -} - -static int wl1271_boot_upload_firmware(struct wl1271 *wl) -{ - u32 chunks, addr, len; - int ret = 0; - u8 *fw; - - fw = wl->fw; - chunks = be32_to_cpup((__be32 *) fw); - fw += sizeof(u32); - - wl1271_debug(DEBUG_BOOT, "firmware chunks to be uploaded: %u", chunks); - - while (chunks--) { - addr = be32_to_cpup((__be32 *) fw); - fw += sizeof(u32); - len = be32_to_cpup((__be32 *) fw); - fw += sizeof(u32); - - if (len > 300000) { - wl1271_info("firmware chunk too long: %u", len); - return -EINVAL; - } - wl1271_debug(DEBUG_BOOT, "chunk %d addr 0x%x len %u", - chunks, addr, len); - ret = wl1271_boot_upload_firmware_chunk(wl, fw, len, addr); - if (ret != 0) - break; - fw += len; - } - - return ret; -} - -static int wl1271_boot_upload_nvs(struct wl1271 *wl) -{ - size_t nvs_len, burst_len; - int i; - u32 dest_addr, val; - u8 *nvs_ptr, *nvs_aligned; - - if (wl->nvs == NULL) - return -ENODEV; - - /* - * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz band - * configurations) can be removed when those NVS files stop floating - * around. - */ - if (wl->nvs_len == sizeof(struct wl1271_nvs_file) || - wl->nvs_len == WL1271_INI_LEGACY_NVS_FILE_SIZE) { - if (wl->nvs->general_params.dual_mode_select) - wl->enable_11a = true; - } - - if (wl->nvs_len != sizeof(struct wl1271_nvs_file) && - (wl->nvs_len != WL1271_INI_LEGACY_NVS_FILE_SIZE || - wl->enable_11a)) { - wl1271_error("nvs size is not as expected: %zu != %zu", - wl->nvs_len, sizeof(struct wl1271_nvs_file)); - kfree(wl->nvs); - wl->nvs = NULL; - wl->nvs_len = 0; - return -EILSEQ; - } - - /* only the first part of the NVS needs to be uploaded */ - nvs_len = sizeof(wl->nvs->nvs); - nvs_ptr = (u8 *)wl->nvs->nvs; - - /* update current MAC address to NVS */ - nvs_ptr[11] = wl->mac_addr[0]; - nvs_ptr[10] = wl->mac_addr[1]; - nvs_ptr[6] = wl->mac_addr[2]; - nvs_ptr[5] = wl->mac_addr[3]; - nvs_ptr[4] = wl->mac_addr[4]; - nvs_ptr[3] = wl->mac_addr[5]; - - /* - * 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. - */ - - /* FIXME: Do we need to check here whether the LSB is 1? */ - while (nvs_ptr[0]) { - burst_len = nvs_ptr[0]; - dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8)); - - /* - * Due to our new wl1271_translate_reg_addr function, - * we need to add the REGISTER_BASE to the destination - */ - dest_addr += REGISTERS_BASE; - - /* 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)); - - wl1271_debug(DEBUG_BOOT, - "nvs burst write 0x%x: 0x%x", - dest_addr, val); - wl1271_write32(wl, dest_addr, val); - - nvs_ptr += 4; - dest_addr += 4; - } - } - - /* - * We've reached the first zero length, the first NVS table - * is located at an aligned offset which is at least 7 bytes further. - */ - nvs_ptr = (u8 *)wl->nvs->nvs + - ALIGN(nvs_ptr - (u8 *)wl->nvs->nvs + 7, 4); - nvs_len -= nvs_ptr - (u8 *)wl->nvs->nvs; - - /* Now we must set the partition correctly */ - wl1271_set_partition(wl, &part_table[PART_WORK]); - - /* Copy the NVS tables to a new block to ensure alignment */ - nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL); - if (!nvs_aligned) - return -ENOMEM; - - /* And finally we upload the NVS tables */ - wl1271_write(wl, CMD_MBOX_ADDRESS, nvs_aligned, nvs_len, false); - - kfree(nvs_aligned); - return 0; -} - -static void wl1271_boot_enable_interrupts(struct wl1271 *wl) -{ - wl1271_enable_interrupts(wl); - wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, - WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK)); - wl1271_write32(wl, HI_CFG, HI_CFG_DEF_VAL); -} - -static int wl1271_boot_soft_reset(struct wl1271 *wl) -{ - unsigned long timeout; - u32 boot_data; - - /* perform soft reset */ - wl1271_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 = wl1271_read32(wl, ACX_REG_SLV_SOFT_RESET); - wl1271_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 */ - wl1271_error("soft reset timeout"); - return -1; - } - - udelay(SOFT_RESET_STALL_TIME); - } - - /* disable Rx/Tx */ - wl1271_write32(wl, ENABLE, 0x0); - - /* disable auto calibration on start*/ - wl1271_write32(wl, SPARE_A2, 0xffff); - - return 0; -} - -static int wl1271_boot_run_firmware(struct wl1271 *wl) -{ - int loop, ret; - u32 chip_id, intr; - - wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); - - chip_id = wl1271_read32(wl, CHIP_ID_B); - - wl1271_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); - - if (chip_id != wl->chip.id) { - wl1271_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); - intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); - - if (intr == 0xffffffff) { - wl1271_error("error reading hardware complete " - "init indication"); - return -EIO; - } - /* check that ACX_INTR_INIT_COMPLETE is enabled */ - else if (intr & WL1271_ACX_INTR_INIT_COMPLETE) { - wl1271_write32(wl, ACX_REG_INTERRUPT_ACK, - WL1271_ACX_INTR_INIT_COMPLETE); - break; - } - } - - if (loop > INIT_LOOP) { - wl1271_error("timeout waiting for the hardware to " - "complete initialization"); - return -EIO; - } - - /* get hardware config command mail box */ - wl->cmd_box_addr = wl1271_read32(wl, REG_COMMAND_MAILBOX_PTR); - - /* get hardware config event mail box */ - wl->event_box_addr = wl1271_read32(wl, REG_EVENT_MAILBOX_PTR); - - /* set the working partition to its "running" mode offset */ - wl1271_set_partition(wl, &part_table[PART_WORK]); - - wl1271_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x", - wl->cmd_box_addr, wl->event_box_addr); - - wl1271_boot_fw_version(wl); - - /* - * in case of full asynchronous mode the firmware event must be - * ready to receive event from the command mailbox - */ - - /* unmask required mbox events */ - wl->event_mask = BSS_LOSE_EVENT_ID | - SCAN_COMPLETE_EVENT_ID | - PS_REPORT_EVENT_ID | - JOIN_EVENT_COMPLETE_ID | - DISCONNECT_EVENT_COMPLETE_ID | - RSSI_SNR_TRIGGER_0_EVENT_ID | - PSPOLL_DELIVERY_FAILURE_EVENT_ID | - SOFT_GEMINI_SENSE_EVENT_ID; - - ret = wl1271_event_unmask(wl); - if (ret < 0) { - wl1271_error("EVENT mask setting failed"); - return ret; - } - - wl1271_event_mbox_config(wl); - - /* firmware startup completed */ - return 0; -} - -static int wl1271_boot_write_irq_polarity(struct wl1271 *wl) -{ - u32 polarity; - - polarity = wl1271_top_reg_read(wl, OCP_REG_POLARITY); - - /* We use HIGH polarity, so unset the LOW bit */ - polarity &= ~POLARITY_LOW; - wl1271_top_reg_write(wl, OCP_REG_POLARITY, polarity); - - return 0; -} - -static void wl1271_boot_hw_version(struct wl1271 *wl) -{ - u32 fuse; - - fuse = wl1271_top_reg_read(wl, REG_FUSE_DATA_2_1); - fuse = (fuse & PG_VER_MASK) >> PG_VER_OFFSET; - - wl->hw_pg_ver = (s8)fuse; -} - -int wl1271_boot(struct wl1271 *wl) -{ - int ret = 0; - u32 tmp, clk, pause; - - wl1271_boot_hw_version(wl); - - if (wl->ref_clock == 0 || wl->ref_clock == 2 || wl->ref_clock == 4) - /* ref clk: 19.2/38.4/38.4-XTAL */ - clk = 0x3; - else if (wl->ref_clock == 1 || wl->ref_clock == 3) - /* ref clk: 26/52 */ - clk = 0x5; - else - return -EINVAL; - - if (wl->ref_clock != 0) { - u16 val; - /* Set clock type (open drain) */ - val = wl1271_top_reg_read(wl, OCP_REG_CLK_TYPE); - val &= FREF_CLK_TYPE_BITS; - wl1271_top_reg_write(wl, OCP_REG_CLK_TYPE, val); - - /* Set clock pull mode (no pull) */ - val = wl1271_top_reg_read(wl, OCP_REG_CLK_PULL); - val |= NO_PULL; - wl1271_top_reg_write(wl, OCP_REG_CLK_PULL, val); - } else { - u16 val; - /* Set clock polarity */ - val = wl1271_top_reg_read(wl, OCP_REG_CLK_POLARITY); - val &= FREF_CLK_POLARITY_BITS; - val |= CLK_REQ_OUTN_SEL; - wl1271_top_reg_write(wl, OCP_REG_CLK_POLARITY, val); - } - - wl1271_write32(wl, PLL_PARAMETERS, clk); - - pause = wl1271_read32(wl, PLL_PARAMETERS); - - wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause); - - pause &= ~(WU_COUNTER_PAUSE_VAL); - pause |= WU_COUNTER_PAUSE_VAL; - wl1271_write32(wl, WU_COUNTER_PAUSE, pause); - - /* Continue the ELP wake up sequence */ - wl1271_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL); - udelay(500); - - wl1271_set_partition(wl, &part_table[PART_DRPW]); - - /* Read-modify-write DRPW_SCRATCH_START register (see next state) - to be used by DRPw FW. The RTRIM value will be added by the FW - before taking DRPw out of reset */ - - wl1271_debug(DEBUG_BOOT, "DRPW_SCRATCH_START %08x", DRPW_SCRATCH_START); - clk = wl1271_read32(wl, DRPW_SCRATCH_START); - - wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk); - - clk |= (wl->ref_clock << 1) << 4; - wl1271_write32(wl, DRPW_SCRATCH_START, clk); - - wl1271_set_partition(wl, &part_table[PART_WORK]); - - /* Disable interrupts */ - wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); - - ret = wl1271_boot_soft_reset(wl); - if (ret < 0) - goto out; - - /* 2. start processing NVS file */ - ret = wl1271_boot_upload_nvs(wl); - if (ret < 0) - goto out; - - /* write firmware's last address (ie. it's length) to - * ACX_EEPROMLESS_IND_REG */ - wl1271_debug(DEBUG_BOOT, "ACX_EEPROMLESS_IND_REG"); - - wl1271_write32(wl, ACX_EEPROMLESS_IND_REG, ACX_EEPROMLESS_IND_REG); - - tmp = wl1271_read32(wl, CHIP_ID_B); - - wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp); - - /* 6. read the EEPROM parameters */ - tmp = wl1271_read32(wl, SCR_PAD2); - - ret = wl1271_boot_write_irq_polarity(wl); - if (ret < 0) - goto out; - - wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, - WL1271_ACX_ALL_EVENTS_VECTOR); - - /* WL1271: The reference driver skips steps 7 to 10 (jumps directly - * to upload_fw) */ - - ret = wl1271_boot_upload_firmware(wl); - if (ret < 0) - goto out; - - /* 10.5 start firmware */ - ret = wl1271_boot_run_firmware(wl); - if (ret < 0) - goto out; - - /* Enable firmware interrupts now */ - wl1271_boot_enable_interrupts(wl); - - /* set the wl1271 default filters */ - wl->rx_config = WL1271_DEFAULT_RX_CONFIG; - wl->rx_filter = WL1271_DEFAULT_RX_FILTER; - - wl1271_event_mbox_config(wl); - -out: - return ret; -} diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.h b/drivers/net/wireless/wl12xx/wl1271_boot.h deleted file mode 100644 index f73b0b1..0000000 --- a/drivers/net/wireless/wl12xx/wl1271_boot.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 2008-2009 Nokia Corporation - * - * Contact: Luciano Coelho - * - * 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 "wl1271.h" - -int wl1271_boot(struct wl1271 *wl); - -#define WL1271_NO_SUBBANDS 8 -#define WL1271_NO_POWER_LEVELS 4 -#define WL1271_FW_VERSION_MAX_LEN 20 - -struct wl1271_static_data { - u8 mac_address[ETH_ALEN]; - u8 padding[2]; - u8 fw_version[WL1271_FW_VERSION_MAX_LEN]; - u32 hw_version; - u8 tx_power_table[WL1271_NO_SUBBANDS][WL1271_NO_POWER_LEVELS]; -}; - -/* number of times we try to read the INIT interrupt */ -#define INIT_LOOP 20000 - -/* delay between retries */ -#define INIT_LOOP_DELAY 50 - -#define WU_COUNTER_PAUSE_VAL 0x3FF -#define WELP_ARM_COMMAND_VAL 0x4 - -#define OCP_REG_POLARITY 0x0064 -#define OCP_REG_CLK_TYPE 0x0448 -#define OCP_REG_CLK_POLARITY 0x0cb2 -#define OCP_REG_CLK_PULL 0x0cb4 - -#define REG_FUSE_DATA_2_1 0x050a -#define PG_VER_MASK 0x3c -#define PG_VER_OFFSET 2 - -#define CMD_MBOX_ADDRESS 0x407B4 - -#define POLARITY_LOW BIT(1) -#define NO_PULL (BIT(14) | BIT(15)) - -#define FREF_CLK_TYPE_BITS 0xfffffe7f -#define CLK_REQ_PRCM 0x100 -#define FREF_CLK_POLARITY_BITS 0xfffff8ff -#define CLK_REQ_OUTN_SEL 0x700 - -#endif diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c deleted file mode 100644 index 5d3e848..0000000 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ /dev/null @@ -1,783 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 2009-2010 Nokia Corporation - * - * Contact: Luciano Coelho - * - * 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 "wl1271.h" -#include "wl1271_reg.h" -#include "wl1271_io.h" -#include "wl1271_acx.h" -#include "wl12xx_80211.h" -#include "wl1271_cmd.h" -#include "wl1271_event.h" - -#define WL1271_CMD_FAST_POLL_COUNT 50 - -/* - * 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 wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, - size_t res_len) -{ - struct wl1271_cmd_header *cmd; - unsigned long timeout; - u32 intr; - int ret = 0; - u16 status; - u16 poll_count = 0; - - cmd = buf; - cmd->id = cpu_to_le16(id); - cmd->status = 0; - - WARN_ON(len % 4 != 0); - - wl1271_write(wl, wl->cmd_box_addr, buf, len, false); - - wl1271_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); - - timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT); - - intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); - while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) { - if (time_after(jiffies, timeout)) { - wl1271_error("command complete timeout"); - ret = -ETIMEDOUT; - goto out; - } - - poll_count++; - if (poll_count < WL1271_CMD_FAST_POLL_COUNT) - udelay(10); - else - msleep(1); - - intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); - } - - /* read back the status code of the command */ - if (res_len == 0) - res_len = sizeof(struct wl1271_cmd_header); - wl1271_read(wl, wl->cmd_box_addr, cmd, res_len, false); - - status = le16_to_cpu(cmd->status); - if (status != CMD_STATUS_SUCCESS) { - wl1271_error("command execute failure %d", status); - ieee80211_queue_work(wl->hw, &wl->recovery_work); - ret = -EIO; - } - - wl1271_write32(wl, ACX_REG_INTERRUPT_ACK, - WL1271_ACX_INTR_CMD_COMPLETE); - -out: - return ret; -} - -int wl1271_cmd_general_parms(struct wl1271 *wl) -{ - struct wl1271_general_parms_cmd *gen_parms; - struct wl1271_ini_general_params *gp = &wl->nvs->general_params; - bool answer = false; - int ret; - - if (!wl->nvs) - return -ENODEV; - - gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL); - if (!gen_parms) - return -ENOMEM; - - gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM; - - memcpy(&gen_parms->general_params, gp, sizeof(*gp)); - - if (gp->tx_bip_fem_auto_detect) - answer = true; - - ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer); - if (ret < 0) { - wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed"); - goto out; - } - - gp->tx_bip_fem_manufacturer = - gen_parms->general_params.tx_bip_fem_manufacturer; - - wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n", - answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer); - -out: - kfree(gen_parms); - return ret; -} - -int wl1271_cmd_radio_parms(struct wl1271 *wl) -{ - struct wl1271_radio_parms_cmd *radio_parms; - struct wl1271_ini_general_params *gp = &wl->nvs->general_params; - int ret; - - if (!wl->nvs) - return -ENODEV; - - radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL); - if (!radio_parms) - return -ENOMEM; - - radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM; - - /* 2.4GHz parameters */ - memcpy(&radio_parms->static_params_2, &wl->nvs->stat_radio_params_2, - sizeof(struct wl1271_ini_band_params_2)); - memcpy(&radio_parms->dyn_params_2, - &wl->nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params, - sizeof(struct wl1271_ini_fem_params_2)); - - /* 5GHz parameters */ - memcpy(&radio_parms->static_params_5, - &wl->nvs->stat_radio_params_5, - sizeof(struct wl1271_ini_band_params_5)); - memcpy(&radio_parms->dyn_params_5, - &wl->nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params, - sizeof(struct wl1271_ini_fem_params_5)); - - wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ", - radio_parms, sizeof(*radio_parms)); - - ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0); - if (ret < 0) - wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed"); - - kfree(radio_parms); - return ret; -} - -int wl1271_cmd_ext_radio_parms(struct wl1271 *wl) -{ - struct wl1271_ext_radio_parms_cmd *ext_radio_parms; - struct conf_rf_settings *rf = &wl->conf.rf; - int ret; - - if (!wl->nvs) - return -ENODEV; - - ext_radio_parms = kzalloc(sizeof(*ext_radio_parms), GFP_KERNEL); - if (!ext_radio_parms) - return -ENOMEM; - - ext_radio_parms->test.id = TEST_CMD_INI_FILE_RF_EXTENDED_PARAM; - - memcpy(ext_radio_parms->tx_per_channel_power_compensation_2, - rf->tx_per_channel_power_compensation_2, - CONF_TX_PWR_COMPENSATION_LEN_2); - memcpy(ext_radio_parms->tx_per_channel_power_compensation_5, - rf->tx_per_channel_power_compensation_5, - CONF_TX_PWR_COMPENSATION_LEN_5); - - wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_EXT_RADIO_PARAM: ", - ext_radio_parms, sizeof(*ext_radio_parms)); - - ret = wl1271_cmd_test(wl, ext_radio_parms, sizeof(*ext_radio_parms), 0); - if (ret < 0) - wl1271_warning("TEST_CMD_INI_FILE_RF_EXTENDED_PARAM failed"); - - kfree(ext_radio_parms); - return ret; -} - -/* - * Poll the mailbox event field until any of the bits in the mask is set or a - * timeout occurs (WL1271_EVENT_TIMEOUT in msecs) - */ -static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask) -{ - u32 events_vector, event; - unsigned long timeout; - - timeout = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT); - - do { - if (time_after(jiffies, timeout)) { - ieee80211_queue_work(wl->hw, &wl->recovery_work); - return -ETIMEDOUT; - } - - msleep(1); - - /* read from both event fields */ - wl1271_read(wl, wl->mbox_ptr[0], &events_vector, - sizeof(events_vector), false); - event = events_vector & mask; - wl1271_read(wl, wl->mbox_ptr[1], &events_vector, - sizeof(events_vector), false); - event |= events_vector & mask; - } while (!event); - - return 0; -} - -int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type) -{ - struct wl1271_cmd_join *join; - int ret, i; - u8 *bssid; - - join = kzalloc(sizeof(*join), GFP_KERNEL); - if (!join) { - ret = -ENOMEM; - goto out; - } - - wl1271_debug(DEBUG_CMD, "cmd join"); - - /* 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 = cpu_to_le32(wl->rx_config); - join->rx_filter_options = cpu_to_le32(wl->rx_filter); - join->bss_type = bss_type; - join->basic_rate_set = cpu_to_le32(wl->basic_rate_set); - - if (wl->band == IEEE80211_BAND_5GHZ) - join->bss_type |= WL1271_JOIN_CMD_BSS_TYPE_5GHZ; - - join->beacon_interval = cpu_to_le16(wl->beacon_int); - join->dtim_interval = WL1271_DEFAULT_DTIM_PERIOD; - - join->channel = wl->channel; - join->ssid_len = wl->ssid_len; - memcpy(join->ssid, wl->ssid, wl->ssid_len); - - join->ctrl |= wl->session_counter << WL1271_JOIN_CMD_TX_SESSION_OFFSET; - - /* reset TX security counters */ - wl->tx_security_last_seq = 0; - wl->tx_security_seq = 0; - - ret = wl1271_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join), 0); - if (ret < 0) { - wl1271_error("failed to initiate cmd join"); - goto out_free; - } - - ret = wl1271_cmd_wait_for_event(wl, JOIN_EVENT_COMPLETE_ID); - if (ret < 0) - wl1271_error("cmd join event completion error"); - -out_free: - kfree(join); - -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 wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer) -{ - int ret; - size_t res_len = 0; - - wl1271_debug(DEBUG_CMD, "cmd test"); - - if (answer) - res_len = buf_len; - - ret = wl1271_cmd_send(wl, CMD_TEST, buf, buf_len, res_len); - - if (ret < 0) { - wl1271_warning("TEST command failed"); - return ret; - } - - return ret; -} - -/** - * 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 wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len) -{ - struct acx_header *acx = buf; - int ret; - - wl1271_debug(DEBUG_CMD, "cmd interrogate"); - - acx->id = cpu_to_le16(id); - - /* payload length, does not include any headers */ - acx->len = cpu_to_le16(len - sizeof(*acx)); - - ret = wl1271_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx), len); - if (ret < 0) - wl1271_error("INTERROGATE command failed"); - - 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 wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len) -{ - struct acx_header *acx = buf; - int ret; - - wl1271_debug(DEBUG_CMD, "cmd configure"); - - acx->id = cpu_to_le16(id); - - /* payload length, does not include any headers */ - acx->len = cpu_to_le16(len - sizeof(*acx)); - - ret = wl1271_cmd_send(wl, CMD_CONFIGURE, acx, len, 0); - if (ret < 0) { - wl1271_warning("CONFIGURE command NOK"); - return ret; - } - - return 0; -} - -int wl1271_cmd_data_path(struct wl1271 *wl, bool enable) -{ - struct cmd_enabledisable_path *cmd; - int ret; - u16 cmd_rx, cmd_tx; - - wl1271_debug(DEBUG_CMD, "cmd data path"); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - /* the channel here is only used for calibration, so hardcoded to 1 */ - cmd->channel = 1; - - if (enable) { - cmd_rx = CMD_ENABLE_RX; - cmd_tx = CMD_ENABLE_TX; - } else { - cmd_rx = CMD_DISABLE_RX; - cmd_tx = CMD_DISABLE_TX; - } - - ret = wl1271_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_error("rx %s cmd for channel %d failed", - enable ? "start" : "stop", cmd->channel); - goto out; - } - - wl1271_debug(DEBUG_BOOT, "rx %s cmd channel %d", - enable ? "start" : "stop", cmd->channel); - - ret = wl1271_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_error("tx %s cmd for channel %d failed", - enable ? "start" : "stop", cmd->channel); - goto out; - } - - wl1271_debug(DEBUG_BOOT, "tx %s cmd channel %d", - enable ? "start" : "stop", cmd->channel); - -out: - kfree(cmd); - return ret; -} - -int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, u32 rates, bool send) -{ - struct wl1271_cmd_ps_params *ps_params = NULL; - int ret = 0; - - wl1271_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 = send; - ps_params->retries = wl->conf.conn.psm_entry_nullfunc_retries; - ps_params->hang_over_period = wl->conf.conn.psm_entry_hangover_period; - ps_params->null_data_rate = cpu_to_le32(rates); - - ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params, - sizeof(*ps_params), 0); - if (ret < 0) { - wl1271_error("cmd set_ps_mode failed"); - goto out; - } - -out: - kfree(ps_params); - return ret; -} - -int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, - void *buf, size_t buf_len, int index, u32 rates) -{ - struct wl1271_cmd_template_set *cmd; - int ret = 0; - - wl1271_debug(DEBUG_CMD, "cmd template_set %d", template_id); - - WARN_ON(buf_len > WL1271_CMD_TEMPL_MAX_SIZE); - buf_len = min_t(size_t, buf_len, WL1271_CMD_TEMPL_MAX_SIZE); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - cmd->len = cpu_to_le16(buf_len); - cmd->template_type = template_id; - cmd->enabled_rates = cpu_to_le32(rates); - cmd->short_retry_limit = wl->conf.tx.rc_conf.short_retry_limit; - cmd->long_retry_limit = wl->conf.tx.rc_conf.long_retry_limit; - cmd->index = index; - - if (buf) - memcpy(cmd->template_data, buf, buf_len); - - ret = wl1271_cmd_send(wl, CMD_SET_TEMPLATE, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_warning("cmd set_template failed: %d", ret); - goto out_free; - } - -out_free: - kfree(cmd); - -out: - return ret; -} - -int wl1271_cmd_build_null_data(struct wl1271 *wl) -{ - struct sk_buff *skb = NULL; - int size; - void *ptr; - int ret = -ENOMEM; - - - if (wl->bss_type == BSS_TYPE_IBSS) { - size = sizeof(struct wl12xx_null_data_template); - ptr = NULL; - } else { - skb = ieee80211_nullfunc_get(wl->hw, wl->vif); - if (!skb) - goto out; - size = skb->len; - ptr = skb->data; - } - - ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, ptr, size, 0, - wl->basic_rate); - -out: - dev_kfree_skb(skb); - if (ret) - wl1271_warning("cmd buld null data failed %d", ret); - - return ret; - -} - -int wl1271_cmd_build_klv_null_data(struct wl1271 *wl) -{ - struct sk_buff *skb = NULL; - int ret = -ENOMEM; - - skb = ieee80211_nullfunc_get(wl->hw, wl->vif); - if (!skb) - goto out; - - ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV, - skb->data, skb->len, - CMD_TEMPL_KLV_IDX_NULL_DATA, - wl->basic_rate); - -out: - dev_kfree_skb(skb); - if (ret) - wl1271_warning("cmd build klv null data failed %d", ret); - - return ret; - -} - -int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid) -{ - struct sk_buff *skb; - int ret = 0; - - skb = ieee80211_pspoll_get(wl->hw, wl->vif); - if (!skb) - goto out; - - ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, skb->data, - skb->len, 0, wl->basic_rate_set); - -out: - dev_kfree_skb(skb); - return ret; -} - -int wl1271_cmd_build_probe_req(struct wl1271 *wl, - const u8 *ssid, size_t ssid_len, - const u8 *ie, size_t ie_len, u8 band) -{ - struct sk_buff *skb; - int ret; - - skb = ieee80211_probereq_get(wl->hw, wl->vif, ssid, ssid_len, - ie, ie_len); - if (!skb) { - ret = -ENOMEM; - goto out; - } - - wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len); - - if (band == IEEE80211_BAND_2GHZ) - ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, - skb->data, skb->len, 0, - wl->conf.tx.basic_rate); - else - ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, - skb->data, skb->len, 0, - wl->conf.tx.basic_rate_5); - -out: - dev_kfree_skb(skb); - return ret; -} - -int wl1271_build_qos_null_data(struct wl1271 *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 wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, &template, - sizeof(template), 0, - wl->basic_rate); -} - -int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id) -{ - struct wl1271_cmd_set_keys *cmd; - int ret = 0; - - wl1271_debug(DEBUG_CMD, "cmd set_default_wep_key %d", id); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - cmd->id = id; - cmd->key_action = cpu_to_le16(KEY_SET_ID); - cmd->key_type = KEY_WEP; - - ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_warning("cmd set_default_wep_key failed: %d", ret); - goto out; - } - -out: - kfree(cmd); - - return ret; -} - -int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, - u8 key_size, const u8 *key, const u8 *addr, - u32 tx_seq_32, u16 tx_seq_16) -{ - struct wl1271_cmd_set_keys *cmd; - int ret = 0; - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - if (key_type != KEY_WEP) - memcpy(cmd->addr, addr, ETH_ALEN); - - cmd->key_action = cpu_to_le16(action); - cmd->key_size = key_size; - cmd->key_type = key_type; - - cmd->ac_seq_num16[0] = cpu_to_le16(tx_seq_16); - cmd->ac_seq_num32[0] = cpu_to_le32(tx_seq_32); - - /* we have only one SSID profile */ - cmd->ssid_profile = 0; - - cmd->id = id; - - if (key_type == KEY_TKIP) { - /* - * 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(cmd->key, key, 16); - memcpy(cmd->key + 16, key + 24, 8); - memcpy(cmd->key + 24, key + 16, 8); - - } else { - memcpy(cmd->key, key, key_size); - } - - wl1271_dump(DEBUG_CRYPT, "TARGET KEY: ", cmd, sizeof(*cmd)); - - ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_warning("could not set keys"); - goto out; - } - -out: - kfree(cmd); - - return ret; -} - -int wl1271_cmd_disconnect(struct wl1271 *wl) -{ - struct wl1271_cmd_disconnect *cmd; - int ret = 0; - - wl1271_debug(DEBUG_CMD, "cmd disconnect"); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - cmd->rx_config_options = cpu_to_le32(wl->rx_config); - cmd->rx_filter_options = cpu_to_le32(wl->rx_filter); - /* disconnect reason is not used in immediate disconnections */ - cmd->type = DISCONNECT_IMMEDIATE; - - ret = wl1271_cmd_send(wl, CMD_DISCONNECT, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_error("failed to send disconnect command"); - goto out_free; - } - - ret = wl1271_cmd_wait_for_event(wl, DISCONNECT_EVENT_COMPLETE_ID); - if (ret < 0) - wl1271_error("cmd disconnect event completion error"); - -out_free: - kfree(cmd); - -out: - return ret; -} - -int wl1271_cmd_set_sta_state(struct wl1271 *wl) -{ - struct wl1271_cmd_set_sta_state *cmd; - int ret = 0; - - wl1271_debug(DEBUG_CMD, "cmd set sta state"); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - cmd->state = WL1271_CMD_STA_STATE_CONNECTED; - - ret = wl1271_cmd_send(wl, CMD_SET_STA_STATE, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_error("failed to send set STA state command"); - goto out_free; - } - -out_free: - kfree(cmd); - -out: - return ret; -} diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/wl1271_cmd.h deleted file mode 100644 index a0caf4f..0000000 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.h +++ /dev/null @@ -1,459 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. - * Copyright (C) 2009 Nokia Corporation - * - * Contact: Luciano Coelho - * - * 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 __WL1271_CMD_H__ -#define __WL1271_CMD_H__ - -#include "wl1271.h" - -struct acx_header; - -int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, - size_t res_len); -int wl1271_cmd_general_parms(struct wl1271 *wl); -int wl1271_cmd_radio_parms(struct wl1271 *wl); -int wl1271_cmd_ext_radio_parms(struct wl1271 *wl); -int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type); -int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer); -int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len); -int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len); -int wl1271_cmd_data_path(struct wl1271 *wl, bool enable); -int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, u32 rates, bool send); -int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer, - size_t len); -int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, - void *buf, size_t buf_len, int index, u32 rates); -int wl1271_cmd_build_null_data(struct wl1271 *wl); -int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid); -int wl1271_cmd_build_probe_req(struct wl1271 *wl, - const u8 *ssid, size_t ssid_len, - const u8 *ie, size_t ie_len, u8 band); -int wl1271_build_qos_null_data(struct wl1271 *wl); -int wl1271_cmd_build_klv_null_data(struct wl1271 *wl); -int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id); -int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, - u8 key_size, const u8 *key, const u8 *addr, - u32 tx_seq_32, u16 tx_seq_16); -int wl1271_cmd_disconnect(struct wl1271 *wl); -int wl1271_cmd_set_sta_state(struct wl1271 *wl); - -enum wl1271_commands { - 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_START_JOIN = 11, - CMD_SET_KEYS = 12, - CMD_READ_MEMORY = 13, - CMD_WRITE_MEMORY = 14, - CMD_SET_TEMPLATE = 19, - CMD_TEST = 23, - CMD_NOISE_HIST = 28, - 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, - CMD_CONNECTION_SCAN_CFG = 48, - CMD_CONNECTION_SCAN_SSID_CFG = 49, - CMD_START_PERIODIC_SCAN = 50, - CMD_STOP_PERIODIC_SCAN = 51, - CMD_SET_STA_STATE = 52, - - NUM_COMMANDS, - MAX_COMMAND_ID = 0xFFFF, -}; - -#define MAX_CMD_PARAMS 572 - -enum { - CMD_TEMPL_KLV_IDX_NULL_DATA = 0, - CMD_TEMPL_KLV_IDX_MAX = 4 -}; - -enum cmd_templ { - CMD_TEMPL_NULL_DATA = 0, - CMD_TEMPL_BEACON, - CMD_TEMPL_CFG_PROBE_REQ_2_4, - CMD_TEMPL_CFG_PROBE_REQ_5, - CMD_TEMPL_PROBE_RESPONSE, - CMD_TEMPL_QOS_NULL_DATA, - CMD_TEMPL_PS_POLL, - CMD_TEMPL_KLV, - CMD_TEMPL_DISCONNECT, - CMD_TEMPL_PROBE_REQ_2_4, /* for firmware internal use only */ - CMD_TEMPL_PROBE_REQ_5, /* for firmware internal use only */ - CMD_TEMPL_BAR, /* for firmware internal use only */ - CMD_TEMPL_CTS, /* - * For CTS-to-self (FastCTS) mechanism - * for BT/WLAN coexistence (SoftGemini). */ - CMD_TEMPL_MAX = 0xff -}; - -/* unit ms */ -#define WL1271_COMMAND_TIMEOUT 2000 -#define WL1271_CMD_TEMPL_MAX_SIZE 252 -#define WL1271_EVENT_TIMEOUT 750 - -struct wl1271_cmd_header { - __le16 id; - __le16 status; - /* payload */ - u8 data[0]; -} __packed; - -#define WL1271_CMD_MAX_PARAMS 572 - -struct wl1271_command { - struct wl1271_cmd_header header; - u8 parameters[WL1271_CMD_MAX_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 -}; - -#define CMDMBOX_HEADER_LEN 4 -#define CMDMBOX_INFO_ELEM_HEADER_LEN 4 - -enum { - BSS_TYPE_IBSS = 0, - BSS_TYPE_STA_BSS = 2, - BSS_TYPE_AP_BSS = 3, - MAX_BSS_TYPE = 0xFF -}; - -#define WL1271_JOIN_CMD_CTRL_TX_FLUSH 0x80 /* Firmware flushes all Tx */ -#define WL1271_JOIN_CMD_TX_SESSION_OFFSET 1 -#define WL1271_JOIN_CMD_BSS_TYPE_5GHZ 0x10 - -struct wl1271_cmd_join { - struct wl1271_cmd_header header; - - __le32 bssid_lsb; - __le16 bssid_msb; - __le16 beacon_interval; /* in TBTTs */ - __le32 rx_config_options; - __le32 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). - */ - __le32 basic_rate_set; - u8 dtim_interval; - /* - * 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 reserved[3]; -} __packed; - -struct cmd_enabledisable_path { - struct wl1271_cmd_header header; - - u8 channel; - u8 padding[3]; -} __packed; - -#define WL1271_RATE_AUTOMATIC 0 - -struct wl1271_cmd_template_set { - struct wl1271_cmd_header header; - - __le16 len; - u8 template_type; - u8 index; /* relevant only for KLV_TEMPLATE type */ - __le32 enabled_rates; - u8 short_retry_limit; - u8 long_retry_limit; - u8 aflags; - u8 reserved; - u8 template_data[WL1271_CMD_TEMPL_MAX_SIZE]; -} __packed; - -#define TIM_ELE_ID 5 -#define PARTIAL_VBM_MAX 251 - -struct wl1271_tim { - u8 identity; - u8 length; - u8 dtim_count; - u8 dtim_period; - u8 bitmap_ctrl; - u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */ -} __packed; - -enum wl1271_cmd_ps_mode { - STATION_ACTIVE_MODE, - STATION_POWER_SAVE_MODE -}; - -struct wl1271_cmd_ps_params { - struct wl1271_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; - __le32 null_data_rate; -} __packed; - -/* HW encryption keys */ -#define NUM_ACCESS_CATEGORIES_COPY 4 -#define MAX_KEY_SIZE 32 - -enum wl1271_cmd_key_action { - KEY_ADD_OR_REPLACE = 1, - KEY_REMOVE = 2, - KEY_SET_ID = 3, - MAX_KEY_ACTION = 0xffff, -}; - -enum wl1271_cmd_key_type { - KEY_NONE = 0, - KEY_WEP = 1, - KEY_TKIP = 2, - KEY_AES = 3, - KEY_GEM = 4, -}; - -/* FIXME: Add description for key-types */ - -struct wl1271_cmd_set_keys { - struct wl1271_cmd_header header; - - /* Ignored for default WEP key */ - u8 addr[ETH_ALEN]; - - /* key_action_e */ - __le16 key_action; - - __le16 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]; - __le16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY]; - __le32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY]; -} __packed; - -struct wl1271_cmd_test_header { - u8 id; - u8 padding[3]; -} __packed; - -enum wl1271_channel_tune_bands { - WL1271_CHANNEL_TUNE_BAND_2_4, - WL1271_CHANNEL_TUNE_BAND_5, - WL1271_CHANNEL_TUNE_BAND_4_9 -}; - -#define WL1271_PD_REFERENCE_POINT_BAND_B_G 0 - -#define TEST_CMD_P2G_CAL 0x02 -#define TEST_CMD_CHANNEL_TUNE 0x0d -#define TEST_CMD_UPDATE_PD_REFERENCE_POINT 0x1d -#define TEST_CMD_INI_FILE_RADIO_PARAM 0x19 -#define TEST_CMD_INI_FILE_GENERAL_PARAM 0x1E -#define TEST_CMD_INI_FILE_RF_EXTENDED_PARAM 0x26 - -struct wl1271_general_parms_cmd { - struct wl1271_cmd_header header; - - struct wl1271_cmd_test_header test; - - struct wl1271_ini_general_params general_params; - - u8 sr_debug_table[WL1271_INI_MAX_SMART_REFLEX_PARAM]; - u8 sr_sen_n_p; - u8 sr_sen_n_p_gain; - u8 sr_sen_nrn; - u8 sr_sen_prn; - u8 padding[3]; -} __packed; - -struct wl1271_radio_parms_cmd { - struct wl1271_cmd_header header; - - struct wl1271_cmd_test_header test; - - /* Static radio parameters */ - struct wl1271_ini_band_params_2 static_params_2; - struct wl1271_ini_band_params_5 static_params_5; - - /* Dynamic radio parameters */ - struct wl1271_ini_fem_params_2 dyn_params_2; - u8 padding2; - struct wl1271_ini_fem_params_5 dyn_params_5; - u8 padding3[2]; -} __packed; - -struct wl1271_ext_radio_parms_cmd { - struct wl1271_cmd_header header; - - struct wl1271_cmd_test_header test; - - u8 tx_per_channel_power_compensation_2[CONF_TX_PWR_COMPENSATION_LEN_2]; - u8 tx_per_channel_power_compensation_5[CONF_TX_PWR_COMPENSATION_LEN_5]; - u8 padding[3]; -} __packed; - -struct wl1271_cmd_cal_channel_tune { - struct wl1271_cmd_header header; - - struct wl1271_cmd_test_header test; - - u8 band; - u8 channel; - - __le16 radio_status; -} __packed; - -struct wl1271_cmd_cal_update_ref_point { - struct wl1271_cmd_header header; - - struct wl1271_cmd_test_header test; - - __le32 ref_power; - __le32 ref_detector; - u8 sub_band; - u8 padding[3]; -} __packed; - -#define MAX_TLV_LENGTH 400 -#define MAX_NVS_VERSION_LENGTH 12 - -#define WL1271_CAL_P2G_BAND_B_G BIT(0) - -struct wl1271_cmd_cal_p2g { - struct wl1271_cmd_header header; - - struct wl1271_cmd_test_header test; - - __le16 len; - u8 buf[MAX_TLV_LENGTH]; - u8 type; - u8 padding; - - __le16 radio_status; - u8 nvs_version[MAX_NVS_VERSION_LENGTH]; - - u8 sub_band_mask; - u8 padding2; -} __packed; - - -/* - * There are three types of disconnections: - * - * DISCONNECT_IMMEDIATE: the fw doesn't send any frames - * DISCONNECT_DEAUTH: the fw generates a DEAUTH request with the reason - * we have passed - * DISCONNECT_DISASSOC: the fw generates a DESASSOC request with the reason - * we have passed - */ -enum wl1271_disconnect_type { - DISCONNECT_IMMEDIATE, - DISCONNECT_DEAUTH, - DISCONNECT_DISASSOC -}; - -struct wl1271_cmd_disconnect { - struct wl1271_cmd_header header; - - __le32 rx_config_options; - __le32 rx_filter_options; - - __le16 reason; - u8 type; - - u8 padding; -} __packed; - -#define WL1271_CMD_STA_STATE_CONNECTED 1 - -struct wl1271_cmd_set_sta_state { - struct wl1271_cmd_header header; - - u8 state; - u8 padding[3]; -} __packed; - -#endif /* __WL1271_CMD_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1271_conf.h b/drivers/net/wireless/wl12xx/wl1271_conf.h deleted file mode 100644 index 5f78a6c..0000000 --- a/drivers/net/wireless/wl12xx/wl1271_conf.h +++ /dev/null @@ -1,1105 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 2009 Nokia Corporation - * - * Contact: Luciano Coelho - * - * 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 __WL1271_CONF_H__ -#define __WL1271_CONF_H__ - -enum { - CONF_HW_BIT_RATE_1MBPS = BIT(0), - CONF_HW_BIT_RATE_2MBPS = BIT(1), - CONF_HW_BIT_RATE_5_5MBPS = BIT(2), - CONF_HW_BIT_RATE_6MBPS = BIT(3), - CONF_HW_BIT_RATE_9MBPS = BIT(4), - CONF_HW_BIT_RATE_11MBPS = BIT(5), - CONF_HW_BIT_RATE_12MBPS = BIT(6), - CONF_HW_BIT_RATE_18MBPS = BIT(7), - CONF_HW_BIT_RATE_22MBPS = BIT(8), - CONF_HW_BIT_RATE_24MBPS = BIT(9), - CONF_HW_BIT_RATE_36MBPS = BIT(10), - CONF_HW_BIT_RATE_48MBPS = BIT(11), - CONF_HW_BIT_RATE_54MBPS = BIT(12), - CONF_HW_BIT_RATE_MCS_0 = BIT(13), - CONF_HW_BIT_RATE_MCS_1 = BIT(14), - CONF_HW_BIT_RATE_MCS_2 = BIT(15), - CONF_HW_BIT_RATE_MCS_3 = BIT(16), - CONF_HW_BIT_RATE_MCS_4 = BIT(17), - CONF_HW_BIT_RATE_MCS_5 = BIT(18), - CONF_HW_BIT_RATE_MCS_6 = BIT(19), - CONF_HW_BIT_RATE_MCS_7 = BIT(20) -}; - -enum { - CONF_HW_RATE_INDEX_1MBPS = 0, - CONF_HW_RATE_INDEX_2MBPS = 1, - CONF_HW_RATE_INDEX_5_5MBPS = 2, - CONF_HW_RATE_INDEX_6MBPS = 3, - CONF_HW_RATE_INDEX_9MBPS = 4, - CONF_HW_RATE_INDEX_11MBPS = 5, - CONF_HW_RATE_INDEX_12MBPS = 6, - CONF_HW_RATE_INDEX_18MBPS = 7, - CONF_HW_RATE_INDEX_22MBPS = 8, - CONF_HW_RATE_INDEX_24MBPS = 9, - CONF_HW_RATE_INDEX_36MBPS = 10, - CONF_HW_RATE_INDEX_48MBPS = 11, - CONF_HW_RATE_INDEX_54MBPS = 12, - CONF_HW_RATE_INDEX_MAX = CONF_HW_RATE_INDEX_54MBPS, -}; - -enum { - CONF_HW_RXTX_RATE_MCS7 = 0, - CONF_HW_RXTX_RATE_MCS6, - CONF_HW_RXTX_RATE_MCS5, - CONF_HW_RXTX_RATE_MCS4, - CONF_HW_RXTX_RATE_MCS3, - CONF_HW_RXTX_RATE_MCS2, - CONF_HW_RXTX_RATE_MCS1, - CONF_HW_RXTX_RATE_MCS0, - CONF_HW_RXTX_RATE_54, - CONF_HW_RXTX_RATE_48, - CONF_HW_RXTX_RATE_36, - CONF_HW_RXTX_RATE_24, - CONF_HW_RXTX_RATE_22, - CONF_HW_RXTX_RATE_18, - CONF_HW_RXTX_RATE_12, - CONF_HW_RXTX_RATE_11, - CONF_HW_RXTX_RATE_9, - CONF_HW_RXTX_RATE_6, - CONF_HW_RXTX_RATE_5_5, - CONF_HW_RXTX_RATE_2, - CONF_HW_RXTX_RATE_1, - CONF_HW_RXTX_RATE_MAX, - CONF_HW_RXTX_RATE_UNSUPPORTED = 0xff -}; - -enum { - CONF_SG_DISABLE = 0, - CONF_SG_PROTECTIVE, - CONF_SG_OPPORTUNISTIC -}; - -enum { - /* - * PER threshold in PPM of the BT voice - * - * Range: 0 - 10000000 - */ - CONF_SG_BT_PER_THRESHOLD = 0, - - /* - * Number of consequent RX_ACTIVE activities to override BT voice - * frames to ensure WLAN connection - * - * Range: 0 - 100 - */ - CONF_SG_HV3_MAX_OVERRIDE, - - /* - * Defines the PER threshold of the BT voice - * - * Range: 0 - 65000 - */ - CONF_SG_BT_NFS_SAMPLE_INTERVAL, - - /* - * Defines the load ratio of BT - * - * Range: 0 - 100 (%) - */ - CONF_SG_BT_LOAD_RATIO, - - /* - * Defines whether the SG will force WLAN host to enter/exit PSM - * - * Range: 1 - SG can force, 0 - host handles PSM - */ - CONF_SG_AUTO_PS_MODE, - - /* - * Compensation percentage of probe requests when scan initiated - * during BT voice/ACL link. - * - * Range: 0 - 255 (%) - */ - CONF_SG_AUTO_SCAN_PROBE_REQ, - - /* - * Compensation percentage of probe requests when active scan initiated - * during BT voice - * - * Range: 0 - 255 (%) - */ - CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3, - - /* - * Defines antenna configuration (single/dual antenna) - * - * Range: 0 - single antenna, 1 - dual antenna - */ - CONF_SG_ANTENNA_CONFIGURATION, - - /* - * The threshold (percent) of max consequtive beacon misses before - * increasing priority of beacon reception. - * - * Range: 0 - 100 (%) - */ - CONF_SG_BEACON_MISS_PERCENT, - - /* - * The rate threshold below which receiving a data frame from the AP - * will increase the priority of the data frame above BT traffic. - * - * Range: 0,2, 5(=5.5), 6, 9, 11, 12, 18, 24, 36, 48, 54 - */ - CONF_SG_RATE_ADAPT_THRESH, - - /* - * Not used currently. - * - * Range: 0 - */ - CONF_SG_RATE_ADAPT_SNR, - - /* - * Configure the min and max time BT gains the antenna - * in WLAN PSM / BT master basic rate - * - * Range: 0 - 255 (ms) - */ - CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR, - CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR, - - /* - * The time after it expires no new WLAN trigger frame is trasmitted - * in WLAN PSM / BT master basic rate - * - * Range: 0 - 255 (ms) - */ - CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR, - - /* - * Configure the min and max time BT gains the antenna - * in WLAN PSM / BT slave basic rate - * - * Range: 0 - 255 (ms) - */ - CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR, - CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR, - - /* - * The time after it expires no new WLAN trigger frame is trasmitted - * in WLAN PSM / BT slave basic rate - * - * Range: 0 - 255 (ms) - */ - CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR, - - /* - * Configure the min and max time BT gains the antenna - * in WLAN PSM / BT master EDR - * - * Range: 0 - 255 (ms) - */ - CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR, - CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR, - - /* - * The time after it expires no new WLAN trigger frame is trasmitted - * in WLAN PSM / BT master EDR - * - * Range: 0 - 255 (ms) - */ - CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR, - - /* - * Configure the min and max time BT gains the antenna - * in WLAN PSM / BT slave EDR - * - * Range: 0 - 255 (ms) - */ - CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR, - CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR, - - /* - * The time after it expires no new WLAN trigger frame is trasmitted - * in WLAN PSM / BT slave EDR - * - * Range: 0 - 255 (ms) - */ - CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR, - - /* - * RX guard time before the beginning of a new BT voice frame during - * which no new WLAN trigger frame is transmitted. - * - * Range: 0 - 100000 (us) - */ - CONF_SG_RXT, - - /* - * TX guard time before the beginning of a new BT voice frame during - * which no new WLAN frame is transmitted. - * - * Range: 0 - 100000 (us) - */ - - CONF_SG_TXT, - - /* - * Enable adaptive RXT/TXT algorithm. If disabled, the host values - * will be utilized. - * - * Range: 0 - disable, 1 - enable - */ - CONF_SG_ADAPTIVE_RXT_TXT, - - /* - * The used WLAN legacy service period during active BT ACL link - * - * Range: 0 - 255 (ms) - */ - CONF_SG_PS_POLL_TIMEOUT, - - /* - * The used WLAN UPSD service period during active BT ACL link - * - * Range: 0 - 255 (ms) - */ - CONF_SG_UPSD_TIMEOUT, - - /* - * Configure the min and max time BT gains the antenna - * in WLAN Active / BT master EDR - * - * Range: 0 - 255 (ms) - */ - CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR, - CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR, - - /* - * The maximum time WLAN can gain the antenna for - * in WLAN Active / BT master EDR - * - * Range: 0 - 255 (ms) - */ - CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR, - - /* - * Configure the min and max time BT gains the antenna - * in WLAN Active / BT slave EDR - * - * Range: 0 - 255 (ms) - */ - CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR, - CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR, - - /* - * The maximum time WLAN can gain the antenna for - * in WLAN Active / BT slave EDR - * - * Range: 0 - 255 (ms) - */ - CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR, - - /* - * Configure the min and max time BT gains the antenna - * in WLAN Active / BT basic rate - * - * Range: 0 - 255 (ms) - */ - CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR, - CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR, - - /* - * The maximum time WLAN can gain the antenna for - * in WLAN Active / BT basic rate - * - * Range: 0 - 255 (ms) - */ - CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR, - - /* - * Compensation percentage of WLAN passive scan window if initiated - * during BT voice - * - * Range: 0 - 1000 (%) - */ - CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3, - - /* - * Compensation percentage of WLAN passive scan window if initiated - * during BT A2DP - * - * Range: 0 - 1000 (%) - */ - CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP, - - /* - * Fixed time ensured for BT traffic to gain the antenna during WLAN - * passive scan. - * - * Range: 0 - 1000 ms - */ - CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME, - - /* - * Fixed time ensured for WLAN traffic to gain the antenna during WLAN - * passive scan. - * - * Range: 0 - 1000 ms - */ - CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME, - - /* - * Number of consequent BT voice frames not interrupted by WLAN - * - * Range: 0 - 100 - */ - CONF_SG_HV3_MAX_SERVED, - - /* - * Protection time of the DHCP procedure. - * - * Range: 0 - 100000 (ms) - */ - CONF_SG_DHCP_TIME, - - /* - * Compensation percentage of WLAN active scan window if initiated - * during BT A2DP - * - * Range: 0 - 1000 (%) - */ - CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP, - CONF_SG_TEMP_PARAM_1, - CONF_SG_TEMP_PARAM_2, - CONF_SG_TEMP_PARAM_3, - CONF_SG_TEMP_PARAM_4, - CONF_SG_TEMP_PARAM_5, - CONF_SG_PARAMS_MAX, - CONF_SG_PARAMS_ALL = 0xff -}; - -struct conf_sg_settings { - u32 params[CONF_SG_PARAMS_MAX]; - u8 state; -}; - -enum conf_rx_queue_type { - CONF_RX_QUEUE_TYPE_LOW_PRIORITY, /* All except the high priority */ - CONF_RX_QUEUE_TYPE_HIGH_PRIORITY, /* Management and voice packets */ -}; - -struct conf_rx_settings { - /* - * The maximum amount of time, in TU, before the - * firmware discards the MSDU. - * - * Range: 0 - 0xFFFFFFFF - */ - u32 rx_msdu_life_time; - - /* - * Packet detection threshold in the PHY. - * - * FIXME: details unknown. - */ - u32 packet_detection_threshold; - - /* - * The longest time the STA will wait to receive traffic from the AP - * after a PS-poll has been transmitted. - * - * Range: 0 - 200000 - */ - 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. - * - * Range: 0 - 200000 - */ - u16 upsd_timeout; - - /* - * The number of octets in an MPDU, below which an RTS/CTS - * handshake is not performed. - * - * Range: 0 - 4096 - */ - u16 rts_threshold; - - /* - * The RX Clear Channel Assessment threshold in the PHY - * (the energy threshold). - * - * Range: ENABLE_ENERGY_D == 0x140A - * DISABLE_ENERGY_D == 0xFFEF - */ - u16 rx_cca_threshold; - - /* - * Occupied Rx mem-blocks number which requires interrupting the host - * (0 = no buffering, 0xffff = disabled). - * - * Range: u16 - */ - u16 irq_blk_threshold; - - /* - * Rx packets number which requires interrupting the host - * (0 = no buffering). - * - * Range: u16 - */ - u16 irq_pkt_threshold; - - /* - * Max time in msec the FW may delay RX-Complete interrupt. - * - * Range: 1 - 100 - */ - u16 irq_timeout; - - /* - * The RX queue type. - * - * Range: RX_QUEUE_TYPE_RX_LOW_PRIORITY, RX_QUEUE_TYPE_RX_HIGH_PRIORITY, - */ - u8 queue_type; -}; - -#define CONF_TX_MAX_RATE_CLASSES 8 - -#define CONF_TX_RATE_MASK_UNSPECIFIED 0 -#define CONF_TX_RATE_MASK_BASIC (CONF_HW_BIT_RATE_1MBPS | \ - CONF_HW_BIT_RATE_2MBPS) -#define CONF_TX_RATE_RETRY_LIMIT 10 - -struct conf_tx_rate_class { - - /* - * The rates enabled for this rate class. - * - * Range: CONF_HW_BIT_RATE_* bit mask - */ - u32 enabled_rates; - - /* - * The dot11 short retry limit used for TX retries. - * - * Range: u8 - */ - u8 short_retry_limit; - - /* - * The dot11 long retry limit used for TX retries. - * - * Range: u8 - */ - u8 long_retry_limit; - - /* - * Flags controlling the attributes of TX transmission. - * - * Range: bit 0: Truncate - when set, FW attempts to send a frame stop - * when the total valid per-rate attempts have - * been exhausted; otherwise transmissions - * will continue at the lowest available rate - * until the appropriate one of the - * short_retry_limit, long_retry_limit, - * dot11_max_transmit_msdu_life_time, or - * max_tx_life_time, is exhausted. - * 1: Preamble Override - indicates if the preamble type - * should be used in TX. - * 2: Preamble Type - the type of the preamble to be used by - * the policy (0 - long preamble, 1 - short preamble. - */ - u8 aflags; -}; - -#define CONF_TX_MAX_AC_COUNT 4 - -/* Slot number setting to start transmission at PIFS interval */ -#define CONF_TX_AIFS_PIFS 1 -/* Slot number setting to start transmission at DIFS interval normal - * DCF access */ -#define CONF_TX_AIFS_DIFS 2 - - -enum conf_tx_ac { - CONF_TX_AC_BE = 0, /* best effort / legacy */ - CONF_TX_AC_BK = 1, /* background */ - CONF_TX_AC_VI = 2, /* video */ - CONF_TX_AC_VO = 3, /* voice */ - CONF_TX_AC_CTS2SELF = 4, /* fictious AC, follows AC_VO */ - CONF_TX_AC_ANY_TID = 0x1f -}; - -struct conf_tx_ac_category { - /* - * The AC class identifier. - * - * Range: enum conf_tx_ac - */ - u8 ac; - - /* - * The contention window minimum size (in slots) for the access - * class. - * - * Range: u8 - */ - u8 cw_min; - - /* - * The contention window maximum size (in slots) for the access - * class. - * - * Range: u8 - */ - u16 cw_max; - - /* - * The AIF value (in slots) for the access class. - * - * Range: u8 - */ - u8 aifsn; - - /* - * The TX Op Limit (in microseconds) for the access class. - * - * Range: u16 - */ - u16 tx_op_limit; -}; - -#define CONF_TX_MAX_TID_COUNT 8 - -enum { - CONF_CHANNEL_TYPE_DCF = 0, /* DC/LEGACY*/ - CONF_CHANNEL_TYPE_EDCF = 1, /* EDCA*/ - CONF_CHANNEL_TYPE_HCCA = 2, /* HCCA*/ -}; - -enum { - CONF_PS_SCHEME_LEGACY = 0, - CONF_PS_SCHEME_UPSD_TRIGGER = 1, - CONF_PS_SCHEME_LEGACY_PSPOLL = 2, - CONF_PS_SCHEME_SAPSD = 3, -}; - -enum { - CONF_ACK_POLICY_LEGACY = 0, - CONF_ACK_POLICY_NO_ACK = 1, - CONF_ACK_POLICY_BLOCK = 2, -}; - - -struct conf_tx_tid { - u8 queue_id; - u8 channel_type; - u8 tsid; - u8 ps_scheme; - u8 ack_policy; - u32 apsd_conf[2]; -}; - -struct conf_tx_settings { - /* - * The TX ED value for TELEC Enable/Disable. - * - * Range: 0, 1 - */ - u8 tx_energy_detection; - - /* - * Configuration for rate classes for TX (currently only one - * rate class supported.) - */ - struct conf_tx_rate_class rc_conf; - - /* - * Configuration for access categories for TX rate control. - */ - u8 ac_conf_count; - struct conf_tx_ac_category ac_conf[CONF_TX_MAX_AC_COUNT]; - - /* - * Configuration for TID parameters. - */ - u8 tid_conf_count; - struct conf_tx_tid tid_conf[CONF_TX_MAX_TID_COUNT]; - - /* - * The TX fragmentation threshold. - * - * Range: u16 - */ - u16 frag_threshold; - - /* - * Max time in msec the FW may delay frame TX-Complete interrupt. - * - * Range: u16 - */ - u16 tx_compl_timeout; - - /* - * Completed TX packet count which requires to issue the TX-Complete - * interrupt. - * - * Range: u16 - */ - u16 tx_compl_threshold; - - /* - * The rate used for control messages and scanning on the 2.4GHz band - * - * Range: CONF_HW_BIT_RATE_* bit mask - */ - u32 basic_rate; - - /* - * The rate used for control messages and scanning on the 5GHz band - * - * Range: CONF_HW_BIT_RATE_* bit mask - */ - u32 basic_rate_5; -}; - -enum { - CONF_WAKE_UP_EVENT_BEACON = 0x01, /* Wake on every Beacon*/ - CONF_WAKE_UP_EVENT_DTIM = 0x02, /* Wake on every DTIM*/ - CONF_WAKE_UP_EVENT_N_DTIM = 0x04, /* Wake every Nth DTIM */ - CONF_WAKE_UP_EVENT_N_BEACONS = 0x08, /* Wake every Nth beacon */ - CONF_WAKE_UP_EVENT_BITS_MASK = 0x0F -}; - -#define CONF_MAX_BCN_FILT_IE_COUNT 32 - -#define CONF_BCN_RULE_PASS_ON_CHANGE BIT(0) -#define CONF_BCN_RULE_PASS_ON_APPEARANCE BIT(1) - -#define CONF_BCN_IE_OUI_LEN 3 -#define CONF_BCN_IE_VER_LEN 2 - -struct conf_bcn_filt_rule { - /* - * IE number to which to associate a rule. - * - * Range: u8 - */ - u8 ie; - - /* - * Rule to associate with the specific ie. - * - * Range: CONF_BCN_RULE_PASS_ON_* - */ - u8 rule; - - /* - * OUI for the vendor specifie IE (221) - */ - u8 oui[CONF_BCN_IE_OUI_LEN]; - - /* - * Type for the vendor specifie IE (221) - */ - u8 type; - - /* - * Version for the vendor specifie IE (221) - */ - u8 version[CONF_BCN_IE_VER_LEN]; -}; - -#define CONF_MAX_RSSI_SNR_TRIGGERS 8 - -enum { - CONF_TRIG_METRIC_RSSI_BEACON = 0, - CONF_TRIG_METRIC_RSSI_DATA, - CONF_TRIG_METRIC_SNR_BEACON, - CONF_TRIG_METRIC_SNR_DATA -}; - -enum { - CONF_TRIG_EVENT_TYPE_LEVEL = 0, - CONF_TRIG_EVENT_TYPE_EDGE -}; - -enum { - CONF_TRIG_EVENT_DIR_LOW = 0, - CONF_TRIG_EVENT_DIR_HIGH, - CONF_TRIG_EVENT_DIR_BIDIR -}; - -struct conf_sig_weights { - - /* - * RSSI from beacons average weight. - * - * Range: u8 - */ - u8 rssi_bcn_avg_weight; - - /* - * RSSI from data average weight. - * - * Range: u8 - */ - u8 rssi_pkt_avg_weight; - - /* - * SNR from beacons average weight. - * - * Range: u8 - */ - u8 snr_bcn_avg_weight; - - /* - * SNR from data average weight. - * - * Range: u8 - */ - u8 snr_pkt_avg_weight; -}; - -enum conf_bcn_filt_mode { - CONF_BCN_FILT_MODE_DISABLED = 0, - CONF_BCN_FILT_MODE_ENABLED = 1 -}; - -enum conf_bet_mode { - CONF_BET_MODE_DISABLE = 0, - CONF_BET_MODE_ENABLE = 1, -}; - -struct conf_conn_settings { - /* - * Firmware wakeup conditions configuration. The host may set only - * one bit. - * - * Range: CONF_WAKE_UP_EVENT_* - */ - u8 wake_up_event; - - /* - * Listen interval for beacons or Dtims. - * - * Range: 0 for beacon and Dtim wakeup - * 1-10 for x Dtims - * 1-255 for x beacons - */ - u8 listen_interval; - - /* - * Enable or disable the beacon filtering. - * - * Range: CONF_BCN_FILT_MODE_* - */ - enum conf_bcn_filt_mode bcn_filt_mode; - - /* - * Configure Beacon filter pass-thru rules. - */ - u8 bcn_filt_ie_count; - struct conf_bcn_filt_rule bcn_filt_ie[CONF_MAX_BCN_FILT_IE_COUNT]; - - /* - * The number of consequtive beacons to lose, before the firmware - * becomes out of synch. - * - * Range: u32 - */ - u32 synch_fail_thold; - - /* - * After out-of-synch, the number of TU's to wait without a further - * received beacon (or probe response) before issuing the BSS_EVENT_LOSE - * event. - * - * Range: u32 - */ - u32 bss_lose_timeout; - - /* - * Beacon receive timeout. - * - * Range: u32 - */ - u32 beacon_rx_timeout; - - /* - * Broadcast receive timeout. - * - * Range: u32 - */ - u32 broadcast_timeout; - - /* - * Enable/disable reception of broadcast packets in power save mode - * - * Range: 1 - enable, 0 - disable - */ - u8 rx_broadcast_in_ps; - - /* - * Consequtive PS Poll failures before sending event to driver - * - * Range: u8 - */ - u8 ps_poll_threshold; - - /* - * PS Poll failure recovery ACTIVE period length - * - * Range: u32 (ms) - */ - u32 ps_poll_recovery_period; - - /* - * Configuration of signal average weights. - */ - struct conf_sig_weights sig_weights; - - /* - * Specifies if beacon early termination procedure is enabled or - * disabled. - * - * Range: CONF_BET_MODE_* - */ - u8 bet_enable; - - /* - * Specifies the maximum number of consecutive beacons that may be - * early terminated. After this number is reached at least one full - * beacon must be correctly received in FW before beacon ET - * resumes. - * - * Range 0 - 255 - */ - u8 bet_max_consecutive; - - /* - * Specifies the maximum number of times to try PSM entry if it fails - * (if sending the appropriate null-func message fails.) - * - * Range 0 - 255 - */ - u8 psm_entry_retries; - - /* - * Specifies the maximum number of times to try transmit the PSM entry - * null-func frame for each PSM entry attempt - * - * Range 0 - 255 - */ - u8 psm_entry_nullfunc_retries; - - /* - * Specifies the time to linger in active mode after successfully - * transmitting the PSM entry null-func frame. - * - * Range 0 - 255 TU's - */ - u8 psm_entry_hangover_period; - - /* - * - * Specifies the interval of the connection keep-alive null-func - * frame in ms. - * - * Range: 1000 - 3600000 - */ - u32 keep_alive_interval; - - /* - * Maximum listen interval supported by the driver in units of beacons. - * - * Range: u16 - */ - u8 max_listen_interval; -}; - -enum { - CONF_REF_CLK_19_2_E, - CONF_REF_CLK_26_E, - CONF_REF_CLK_38_4_E, - CONF_REF_CLK_52_E -}; - -enum single_dual_band_enum { - CONF_SINGLE_BAND, - CONF_DUAL_BAND -}; - -#define CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE 15 -#define CONF_NUMBER_OF_SUB_BANDS_5 7 -#define CONF_NUMBER_OF_RATE_GROUPS 6 -#define CONF_NUMBER_OF_CHANNELS_2_4 14 -#define CONF_NUMBER_OF_CHANNELS_5 35 - -struct conf_radio_parms { - /* - * FEM parameter set to use - * - * Range: 0 or 1 - */ - u8 fem; -}; - -struct conf_itrim_settings { - /* enable dco itrim */ - u8 enable; - - /* moderation timeout in microsecs from the last TX */ - u32 timeout; -}; - -struct conf_pm_config_settings { - /* - * Host clock settling time - * - * Range: 0 - 30000 us - */ - u32 host_clk_settling_time; - - /* - * Host fast wakeup support - * - * Range: true, false - */ - bool host_fast_wakeup_support; -}; - -struct conf_roam_trigger_settings { - /* - * The minimum interval between two trigger events. - * - * Range: 0 - 60000 ms - */ - u16 trigger_pacing; - - /* - * The weight for rssi/beacon average calculation - * - * Range: 0 - 255 - */ - u8 avg_weight_rssi_beacon; - - /* - * The weight for rssi/data frame average calculation - * - * Range: 0 - 255 - */ - u8 avg_weight_rssi_data; - - /* - * The weight for snr/beacon average calculation - * - * Range: 0 - 255 - */ - u8 avg_weight_snr_beacon; - - /* - * The weight for snr/data frame average calculation - * - * Range: 0 - 255 - */ - u8 avg_weight_snr_data; -}; - -struct conf_scan_settings { - /* - * The minimum time to wait on each channel for active scans - * - * Range: 0 - 65536 tu - */ - u16 min_dwell_time_active; - - /* - * The maximum time to wait on each channel for active scans - * - * Range: 0 - 65536 tu - */ - u16 max_dwell_time_active; - - /* - * The maximum time to wait on each channel for passive scans - * - * Range: 0 - 65536 tu - */ - u16 min_dwell_time_passive; - - /* - * The maximum time to wait on each channel for passive scans - * - * Range: 0 - 65536 tu - */ - u16 max_dwell_time_passive; - - /* - * Number of probe requests to transmit on each active scan channel - * - * Range: u8 - */ - u16 num_probe_reqs; - -}; - -/* these are number of channels on the band divided by two, rounded up */ -#define CONF_TX_PWR_COMPENSATION_LEN_2 7 -#define CONF_TX_PWR_COMPENSATION_LEN_5 18 - -struct conf_rf_settings { - /* - * Per channel power compensation for 2.4GHz - * - * Range: s8 - */ - u8 tx_per_channel_power_compensation_2[CONF_TX_PWR_COMPENSATION_LEN_2]; - - /* - * Per channel power compensation for 5GHz - * - * Range: s8 - */ - u8 tx_per_channel_power_compensation_5[CONF_TX_PWR_COMPENSATION_LEN_5]; -}; - -struct conf_drv_settings { - struct conf_sg_settings sg; - struct conf_rx_settings rx; - struct conf_tx_settings tx; - struct conf_conn_settings conn; - struct conf_itrim_settings itrim; - struct conf_pm_config_settings pm_config; - struct conf_roam_trigger_settings roam_trigger; - struct conf_scan_settings scan; - struct conf_rf_settings rf; -}; - -#endif diff --git a/drivers/net/wireless/wl12xx/wl1271_debugfs.c b/drivers/net/wireless/wl12xx/wl1271_debugfs.c deleted file mode 100644 index 3468b84..0000000 --- a/drivers/net/wireless/wl12xx/wl1271_debugfs.c +++ /dev/null @@ -1,590 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 2009 Nokia Corporation - * - * Contact: Luciano Coelho - * - * 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 "wl1271_debugfs.h" - -#include -#include - -#include "wl1271.h" -#include "wl1271_acx.h" -#include "wl1271_ps.h" -#include "wl1271_io.h" - -/* ms */ -#define WL1271_DEBUGFS_STATS_LIFETIME 1000 - -/* debugfs macros idea from mac80211 */ -#define DEBUGFS_FORMAT_BUFFER_SIZE 100 -static int wl1271_format_buffer(char __user *userbuf, size_t count, - loff_t *ppos, char *fmt, ...) -{ - va_list args; - char buf[DEBUGFS_FORMAT_BUFFER_SIZE]; - int res; - - va_start(args, fmt); - res = vscnprintf(buf, sizeof(buf), fmt, args); - va_end(args); - - return simple_read_from_buffer(userbuf, count, ppos, buf, res); -} - -#define DEBUGFS_READONLY_FILE(name, fmt, value...) \ -static ssize_t name## _read(struct file *file, char __user *userbuf, \ - size_t count, loff_t *ppos) \ -{ \ - struct wl1271 *wl = file->private_data; \ - return wl1271_format_buffer(userbuf, count, ppos, \ - fmt "\n", ##value); \ -} \ - \ -static const struct file_operations name## _ops = { \ - .read = name## _read, \ - .open = wl1271_open_file_generic, \ - .llseek = generic_file_llseek, \ -}; - -#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, fmt) \ -static ssize_t sub## _ ##name## _read(struct file *file, \ - char __user *userbuf, \ - size_t count, loff_t *ppos) \ -{ \ - struct wl1271 *wl = file->private_data; \ - \ - wl1271_debugfs_update_stats(wl); \ - \ - return wl1271_format_buffer(userbuf, count, ppos, fmt "\n", \ - wl->stats.fw_stats->sub.name); \ -} \ - \ -static const struct file_operations sub## _ ##name## _ops = { \ - .read = sub## _ ##name## _read, \ - .open = wl1271_open_file_generic, \ - .llseek = generic_file_llseek, \ -}; - -#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 wl1271_debugfs_update_stats(struct wl1271 *wl) -{ - int ret; - - mutex_lock(&wl->mutex); - - ret = wl1271_ps_elp_wakeup(wl, false); - if (ret < 0) - goto out; - - if (wl->state == WL1271_STATE_ON && - time_after(jiffies, wl->stats.fw_stats_update + - msecs_to_jiffies(WL1271_DEBUGFS_STATS_LIFETIME))) { - wl1271_acx_statistics(wl, wl->stats.fw_stats); - wl->stats.fw_stats_update = jiffies; - } - - wl1271_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); -} - -static int wl1271_open_file_generic(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - -DEBUGFS_FWSTATS_FILE(tx, internal_desc_overflow, "%u"); - -DEBUGFS_FWSTATS_FILE(rx, out_of_mem, "%u"); -DEBUGFS_FWSTATS_FILE(rx, hdr_overflow, "%u"); -DEBUGFS_FWSTATS_FILE(rx, hw_stuck, "%u"); -DEBUGFS_FWSTATS_FILE(rx, dropped, "%u"); -DEBUGFS_FWSTATS_FILE(rx, fcs_err, "%u"); -DEBUGFS_FWSTATS_FILE(rx, xfr_hint_trig, "%u"); -DEBUGFS_FWSTATS_FILE(rx, path_reset, "%u"); -DEBUGFS_FWSTATS_FILE(rx, reset_counter, "%u"); - -DEBUGFS_FWSTATS_FILE(dma, rx_requested, "%u"); -DEBUGFS_FWSTATS_FILE(dma, rx_errors, "%u"); -DEBUGFS_FWSTATS_FILE(dma, tx_requested, "%u"); -DEBUGFS_FWSTATS_FILE(dma, tx_errors, "%u"); - -DEBUGFS_FWSTATS_FILE(isr, cmd_cmplt, "%u"); -DEBUGFS_FWSTATS_FILE(isr, fiqs, "%u"); -DEBUGFS_FWSTATS_FILE(isr, rx_headers, "%u"); -DEBUGFS_FWSTATS_FILE(isr, rx_mem_overflow, "%u"); -DEBUGFS_FWSTATS_FILE(isr, rx_rdys, "%u"); -DEBUGFS_FWSTATS_FILE(isr, irqs, "%u"); -DEBUGFS_FWSTATS_FILE(isr, tx_procs, "%u"); -DEBUGFS_FWSTATS_FILE(isr, decrypt_done, "%u"); -DEBUGFS_FWSTATS_FILE(isr, dma0_done, "%u"); -DEBUGFS_FWSTATS_FILE(isr, dma1_done, "%u"); -DEBUGFS_FWSTATS_FILE(isr, tx_exch_complete, "%u"); -DEBUGFS_FWSTATS_FILE(isr, commands, "%u"); -DEBUGFS_FWSTATS_FILE(isr, rx_procs, "%u"); -DEBUGFS_FWSTATS_FILE(isr, hw_pm_mode_changes, "%u"); -DEBUGFS_FWSTATS_FILE(isr, host_acknowledges, "%u"); -DEBUGFS_FWSTATS_FILE(isr, pci_pm, "%u"); -DEBUGFS_FWSTATS_FILE(isr, wakeups, "%u"); -DEBUGFS_FWSTATS_FILE(isr, low_rssi, "%u"); - -DEBUGFS_FWSTATS_FILE(wep, addr_key_count, "%u"); -DEBUGFS_FWSTATS_FILE(wep, default_key_count, "%u"); -/* skipping wep.reserved */ -DEBUGFS_FWSTATS_FILE(wep, key_not_found, "%u"); -DEBUGFS_FWSTATS_FILE(wep, decrypt_fail, "%u"); -DEBUGFS_FWSTATS_FILE(wep, packets, "%u"); -DEBUGFS_FWSTATS_FILE(wep, interrupt, "%u"); - -DEBUGFS_FWSTATS_FILE(pwr, ps_enter, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, elp_enter, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, missing_bcns, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, wake_on_host, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, wake_on_timer_exp, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, tx_with_ps, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, tx_without_ps, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, rcvd_beacons, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, power_save_off, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, enable_ps, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, disable_ps, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, fix_tsf_ps, "%u"); -/* skipping cont_miss_bcns_spread for now */ -DEBUGFS_FWSTATS_FILE(pwr, rcvd_awake_beacons, "%u"); - -DEBUGFS_FWSTATS_FILE(mic, rx_pkts, "%u"); -DEBUGFS_FWSTATS_FILE(mic, calc_failure, "%u"); - -DEBUGFS_FWSTATS_FILE(aes, encrypt_fail, "%u"); -DEBUGFS_FWSTATS_FILE(aes, decrypt_fail, "%u"); -DEBUGFS_FWSTATS_FILE(aes, encrypt_packets, "%u"); -DEBUGFS_FWSTATS_FILE(aes, decrypt_packets, "%u"); -DEBUGFS_FWSTATS_FILE(aes, encrypt_interrupt, "%u"); -DEBUGFS_FWSTATS_FILE(aes, decrypt_interrupt, "%u"); - -DEBUGFS_FWSTATS_FILE(event, heart_beat, "%u"); -DEBUGFS_FWSTATS_FILE(event, calibration, "%u"); -DEBUGFS_FWSTATS_FILE(event, rx_mismatch, "%u"); -DEBUGFS_FWSTATS_FILE(event, rx_mem_empty, "%u"); -DEBUGFS_FWSTATS_FILE(event, rx_pool, "%u"); -DEBUGFS_FWSTATS_FILE(event, oom_late, "%u"); -DEBUGFS_FWSTATS_FILE(event, phy_transmit_error, "%u"); -DEBUGFS_FWSTATS_FILE(event, tx_stuck, "%u"); - -DEBUGFS_FWSTATS_FILE(ps, pspoll_timeouts, "%u"); -DEBUGFS_FWSTATS_FILE(ps, upsd_timeouts, "%u"); -DEBUGFS_FWSTATS_FILE(ps, upsd_max_sptime, "%u"); -DEBUGFS_FWSTATS_FILE(ps, upsd_max_apturn, "%u"); -DEBUGFS_FWSTATS_FILE(ps, pspoll_max_apturn, "%u"); -DEBUGFS_FWSTATS_FILE(ps, pspoll_utilization, "%u"); -DEBUGFS_FWSTATS_FILE(ps, upsd_utilization, "%u"); - -DEBUGFS_FWSTATS_FILE(rxpipe, rx_prep_beacon_drop, "%u"); -DEBUGFS_FWSTATS_FILE(rxpipe, descr_host_int_trig_rx_data, "%u"); -DEBUGFS_FWSTATS_FILE(rxpipe, beacon_buffer_thres_host_int_trig_rx_data, "%u"); -DEBUGFS_FWSTATS_FILE(rxpipe, missed_beacon_host_int_trig_rx_data, "%u"); -DEBUGFS_FWSTATS_FILE(rxpipe, tx_xfr_host_int_trig_rx_data, "%u"); - -DEBUGFS_READONLY_FILE(retry_count, "%u", wl->stats.retry_count); -DEBUGFS_READONLY_FILE(excessive_retries, "%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 wl1271 *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 = wl1271_open_file_generic, - .llseek = default_llseek, -}; - -static ssize_t gpio_power_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct wl1271 *wl = file->private_data; - bool state = test_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); - - int res; - char buf[10]; - - res = scnprintf(buf, sizeof(buf), "%d\n", state); - - return simple_read_from_buffer(user_buf, count, ppos, buf, res); -} - -static ssize_t gpio_power_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct wl1271 *wl = file->private_data; - char buf[10]; - size_t len; - unsigned long value; - int ret; - - mutex_lock(&wl->mutex); - - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) { - ret = -EFAULT; - goto out; - } - buf[len] = '\0'; - - ret = strict_strtoul(buf, 0, &value); - if (ret < 0) { - wl1271_warning("illegal value in gpio_power"); - goto out; - } - - if (value) - wl1271_power_on(wl); - else - wl1271_power_off(wl); - -out: - mutex_unlock(&wl->mutex); - return count; -} - -static const struct file_operations gpio_power_ops = { - .read = gpio_power_read, - .write = gpio_power_write, - .open = wl1271_open_file_generic, - .llseek = default_llseek, -}; - -static void wl1271_debugfs_delete_files(struct wl1271 *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(retry_count); - DEBUGFS_DEL(excessive_retries); - - DEBUGFS_DEL(gpio_power); -} - -static int wl1271_debugfs_add_files(struct wl1271 *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(retry_count, wl->debugfs.rootdir); - DEBUGFS_ADD(excessive_retries, wl->debugfs.rootdir); - - DEBUGFS_ADD(gpio_power, wl->debugfs.rootdir); - -out: - if (ret < 0) - wl1271_debugfs_delete_files(wl); - - return ret; -} - -void wl1271_debugfs_reset(struct wl1271 *wl) -{ - memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats)); - wl->stats.retry_count = 0; - wl->stats.excessive_retries = 0; -} - -int wl1271_debugfs_init(struct wl1271 *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 = wl1271_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 wl1271_debugfs_exit(struct wl1271 *wl) -{ - wl1271_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/wl1271_debugfs.h b/drivers/net/wireless/wl12xx/wl1271_debugfs.h deleted file mode 100644 index 00a45b2..0000000 --- a/drivers/net/wireless/wl12xx/wl1271_debugfs.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 2009 Nokia Corporation - * - * Contact: Luciano Coelho - * - * 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 WL1271_DEBUGFS_H -#define WL1271_DEBUGFS_H - -#include "wl1271.h" - -int wl1271_debugfs_init(struct wl1271 *wl); -void wl1271_debugfs_exit(struct wl1271 *wl); -void wl1271_debugfs_reset(struct wl1271 *wl); - -#endif /* WL1271_DEBUGFS_H */ diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c deleted file mode 100644 index 38ccef7..0000000 --- a/drivers/net/wireless/wl12xx/wl1271_event.c +++ /dev/null @@ -1,293 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 2008-2009 Nokia Corporation - * - * Contact: Luciano Coelho - * - * 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 "wl1271.h" -#include "wl1271_reg.h" -#include "wl1271_io.h" -#include "wl1271_event.h" -#include "wl1271_ps.h" -#include "wl1271_scan.h" -#include "wl12xx_80211.h" - -void wl1271_pspoll_work(struct work_struct *work) -{ - struct delayed_work *dwork; - struct wl1271 *wl; - - dwork = container_of(work, struct delayed_work, work); - wl = container_of(dwork, struct wl1271, pspoll_work); - - wl1271_debug(DEBUG_EVENT, "pspoll work"); - - mutex_lock(&wl->mutex); - - if (unlikely(wl->state == WL1271_STATE_OFF)) - goto out; - - if (!test_and_clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags)) - goto out; - - if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) - goto out; - - /* - * if we end up here, then we were in powersave when the pspoll - * delivery failure occurred, and no-one changed state since, so - * we should go back to powersave. - */ - wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, wl->basic_rate, true); - -out: - mutex_unlock(&wl->mutex); -}; - -static void wl1271_event_pspoll_delivery_fail(struct wl1271 *wl) -{ - int delay = wl->conf.conn.ps_poll_recovery_period; - int ret; - - wl->ps_poll_failures++; - if (wl->ps_poll_failures == 1) - wl1271_info("AP with dysfunctional ps-poll, " - "trying to work around it."); - - /* force active mode receive data from the AP */ - if (test_bit(WL1271_FLAG_PSM, &wl->flags)) { - ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, - wl->basic_rate, true); - if (ret < 0) - return; - set_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags); - ieee80211_queue_delayed_work(wl->hw, &wl->pspoll_work, - msecs_to_jiffies(delay)); - } - - /* - * If already in active mode, lets we should be getting data from - * the AP right away. If we enter PSM too fast after this, and data - * remains on the AP, we will get another event like this, and we'll - * go into active once more. - */ -} - -static int wl1271_event_ps_report(struct wl1271 *wl, - struct event_mailbox *mbox, - bool *beacon_loss) -{ - int ret = 0; - u32 total_retries = wl->conf.conn.psm_entry_retries; - - wl1271_debug(DEBUG_EVENT, "ps_status: 0x%x", mbox->ps_status); - - switch (mbox->ps_status) { - case EVENT_ENTER_POWER_SAVE_FAIL: - wl1271_debug(DEBUG_PSM, "PSM entry failed"); - - if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) { - /* remain in active mode */ - wl->psm_entry_retry = 0; - break; - } - - if (wl->psm_entry_retry < total_retries) { - wl->psm_entry_retry++; - ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, - wl->basic_rate, true); - } else { - wl1271_info("No ack to nullfunc from AP."); - wl->psm_entry_retry = 0; - *beacon_loss = true; - } - break; - case EVENT_ENTER_POWER_SAVE_SUCCESS: - wl->psm_entry_retry = 0; - - /* enable beacon filtering */ - ret = wl1271_acx_beacon_filter_opt(wl, true); - if (ret < 0) - break; - - /* enable beacon early termination */ - ret = wl1271_acx_bet_enable(wl, true); - if (ret < 0) - break; - - /* go to extremely low power mode */ - wl1271_ps_elp_sleep(wl); - break; - case EVENT_EXIT_POWER_SAVE_FAIL: - wl1271_debug(DEBUG_PSM, "PSM exit failed"); - - if (test_bit(WL1271_FLAG_PSM, &wl->flags)) { - wl->psm_entry_retry = 0; - break; - } - - /* make sure the firmware goes to active mode - the frame to - be sent next will indicate to the AP, that we are active. */ - ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, - wl->basic_rate, false); - break; - case EVENT_EXIT_POWER_SAVE_SUCCESS: - default: - break; - } - - return ret; -} - -static void wl1271_event_rssi_trigger(struct wl1271 *wl, - struct event_mailbox *mbox) -{ - enum nl80211_cqm_rssi_threshold_event event; - s8 metric = mbox->rssi_snr_trigger_metric[0]; - - wl1271_debug(DEBUG_EVENT, "RSSI trigger metric: %d", metric); - - if (metric <= wl->rssi_thold) - event = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW; - else - event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH; - - if (event != wl->last_rssi_event) - ieee80211_cqm_rssi_notify(wl->vif, event, GFP_KERNEL); - wl->last_rssi_event = event; -} - -static void wl1271_event_mbox_dump(struct event_mailbox *mbox) -{ - wl1271_debug(DEBUG_EVENT, "MBOX DUMP:"); - wl1271_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector); - wl1271_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask); -} - -static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) -{ - int ret; - u32 vector; - bool beacon_loss = false; - - wl1271_event_mbox_dump(mbox); - - vector = le32_to_cpu(mbox->events_vector); - vector &= ~(le32_to_cpu(mbox->events_mask)); - wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector); - - if (vector & SCAN_COMPLETE_EVENT_ID) { - wl1271_debug(DEBUG_EVENT, "status: 0x%x", - mbox->scheduled_scan_status); - - wl1271_scan_stm(wl); - } - - /* disable dynamic PS when requested by the firmware */ - if (vector & SOFT_GEMINI_SENSE_EVENT_ID && - wl->bss_type == BSS_TYPE_STA_BSS) { - if (mbox->soft_gemini_sense_info) - ieee80211_disable_dyn_ps(wl->vif); - else - ieee80211_enable_dyn_ps(wl->vif); - } - - /* - * The BSS_LOSE_EVENT_ID is only needed while psm (and hence beacon - * filtering) is enabled. Without PSM, the stack will receive all - * beacons and can detect beacon loss by itself. - * - * As there's possibility that the driver disables PSM before receiving - * BSS_LOSE_EVENT, beacon loss has to be reported to the stack. - * - */ - if (vector & BSS_LOSE_EVENT_ID) { - wl1271_info("Beacon loss detected."); - - /* indicate to the stack, that beacons have been lost */ - beacon_loss = true; - } - - if (vector & PS_REPORT_EVENT_ID) { - wl1271_debug(DEBUG_EVENT, "PS_REPORT_EVENT"); - ret = wl1271_event_ps_report(wl, mbox, &beacon_loss); - if (ret < 0) - return ret; - } - - if (vector & PSPOLL_DELIVERY_FAILURE_EVENT_ID) - wl1271_event_pspoll_delivery_fail(wl); - - if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) { - wl1271_debug(DEBUG_EVENT, "RSSI_SNR_TRIGGER_0_EVENT"); - if (wl->vif) - wl1271_event_rssi_trigger(wl, mbox); - } - - if (wl->vif && beacon_loss) - ieee80211_connection_loss(wl->vif); - - return 0; -} - -int wl1271_event_unmask(struct wl1271 *wl) -{ - int ret; - - ret = wl1271_acx_event_mbox_mask(wl, ~(wl->event_mask)); - if (ret < 0) - return ret; - - return 0; -} - -void wl1271_event_mbox_config(struct wl1271 *wl) -{ - wl->mbox_ptr[0] = wl1271_read32(wl, REG_EVENT_MAILBOX_PTR); - wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox); - - wl1271_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x", - wl->mbox_ptr[0], wl->mbox_ptr[1]); -} - -int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num) -{ - struct event_mailbox mbox; - int ret; - - wl1271_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num); - - if (mbox_num > 1) - return -EINVAL; - - /* first we read the mbox descriptor */ - wl1271_read(wl, wl->mbox_ptr[mbox_num], &mbox, - sizeof(struct event_mailbox), false); - - /* process the descriptor */ - ret = wl1271_event_process(wl, &mbox); - if (ret < 0) - return ret; - - /* then we let the firmware know it can go on...*/ - wl1271_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK); - - return 0; -} diff --git a/drivers/net/wireless/wl12xx/wl1271_event.h b/drivers/net/wireless/wl12xx/wl1271_event.h deleted file mode 100644 index e475166..0000000 --- a/drivers/net/wireless/wl12xx/wl1271_event.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. - * Copyright (C) 2008-2009 Nokia Corporation - * - * Contact: Luciano Coelho - * - * 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 __WL1271_EVENT_H__ -#define __WL1271_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 { - RSSI_SNR_TRIGGER_0_EVENT_ID = BIT(0), - RSSI_SNR_TRIGGER_1_EVENT_ID = BIT(1), - RSSI_SNR_TRIGGER_2_EVENT_ID = BIT(2), - RSSI_SNR_TRIGGER_3_EVENT_ID = BIT(3), - RSSI_SNR_TRIGGER_4_EVENT_ID = BIT(4), - RSSI_SNR_TRIGGER_5_EVENT_ID = BIT(5), - RSSI_SNR_TRIGGER_6_EVENT_ID = BIT(6), - RSSI_SNR_TRIGGER_7_EVENT_ID = BIT(7), - MEASUREMENT_START_EVENT_ID = BIT(8), - MEASUREMENT_COMPLETE_EVENT_ID = BIT(9), - SCAN_COMPLETE_EVENT_ID = BIT(10), - SCHEDULED_SCAN_COMPLETE_EVENT_ID = BIT(11), - AP_DISCOVERY_COMPLETE_EVENT_ID = BIT(12), - PS_REPORT_EVENT_ID = BIT(13), - PSPOLL_DELIVERY_FAILURE_EVENT_ID = BIT(14), - DISCONNECT_EVENT_COMPLETE_ID = BIT(15), - JOIN_EVENT_COMPLETE_ID = BIT(16), - CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(17), - BSS_LOSE_EVENT_ID = BIT(18), - REGAINED_BSS_EVENT_ID = BIT(19), - ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID = BIT(20), - SOFT_GEMINI_SENSE_EVENT_ID = BIT(22), - SOFT_GEMINI_PREDICTION_EVENT_ID = BIT(23), - SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24), - PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(25), - DBG_EVENT_ID = BIT(26), - HEALTH_CHECK_REPLY_EVENT_ID = BIT(27), - PERIODIC_SCAN_COMPLETE_EVENT_ID = BIT(28), - PERIODIC_SCAN_REPORT_EVENT_ID = BIT(29), - BA_SESSION_TEAR_DOWN_EVENT_ID = BIT(30), - EVENT_MBOX_ALL_EVENT_ID = 0x7fffffff, -}; - -enum { - EVENT_ENTER_POWER_SAVE_FAIL = 0, - EVENT_ENTER_POWER_SAVE_SUCCESS, - EVENT_EXIT_POWER_SAVE_FAIL, - EVENT_EXIT_POWER_SAVE_SUCCESS, -}; - -struct event_debug_report { - u8 debug_event_id; - u8 num_params; - __le16 pad; - __le32 report_1; - __le32 report_2; - __le32 report_3; -} __packed; - -#define NUM_OF_RSSI_SNR_TRIGGERS 8 - -struct event_mailbox { - __le32 events_vector; - __le32 events_mask; - __le32 reserved_1; - __le32 reserved_2; - - u8 dbg_event_id; - u8 num_relevant_params; - __le16 reserved_3; - __le32 event_report_p1; - __le32 event_report_p2; - __le32 event_report_p3; - - u8 number_of_scan_results; - u8 scan_tag; - u8 reserved_4[2]; - __le32 compl_scheduled_scan_status; - - __le16 scheduled_scan_attended_channels; - u8 soft_gemini_sense_info; - u8 soft_gemini_protective_info; - s8 rssi_snr_trigger_metric[NUM_OF_RSSI_SNR_TRIGGERS]; - u8 channel_switch_status; - u8 scheduled_scan_status; - u8 ps_status; - - u8 reserved_5[29]; -} __packed; - -int wl1271_event_unmask(struct wl1271 *wl); -void wl1271_event_mbox_config(struct wl1271 *wl); -int wl1271_event_handle(struct wl1271 *wl, u8 mbox); -void wl1271_pspoll_work(struct work_struct *work); - -#endif diff --git a/drivers/net/wireless/wl12xx/wl1271_ini.h b/drivers/net/wireless/wl12xx/wl1271_ini.h deleted file mode 100644 index 2313047..0000000 --- a/drivers/net/wireless/wl12xx/wl1271_ini.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 2010 Nokia Corporation - * - * Contact: Luciano Coelho - * - * 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 __WL1271_INI_H__ -#define __WL1271_INI_H__ - -#define WL1271_INI_MAX_SMART_REFLEX_PARAM 16 - -struct wl1271_ini_general_params { - u8 ref_clock; - u8 settling_time; - u8 clk_valid_on_wakeup; - u8 dc2dc_mode; - u8 dual_mode_select; - u8 tx_bip_fem_auto_detect; - u8 tx_bip_fem_manufacturer; - u8 general_settings; - u8 sr_state; - u8 srf1[WL1271_INI_MAX_SMART_REFLEX_PARAM]; - u8 srf2[WL1271_INI_MAX_SMART_REFLEX_PARAM]; - u8 srf3[WL1271_INI_MAX_SMART_REFLEX_PARAM]; -} __packed; - -#define WL1271_INI_RSSI_PROCESS_COMPENS_SIZE 15 - -struct wl1271_ini_band_params_2 { - u8 rx_trace_insertion_loss; - u8 tx_trace_loss; - u8 rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE]; -} __packed; - -#define WL1271_INI_RATE_GROUP_COUNT 6 -#define WL1271_INI_CHANNEL_COUNT_2 14 - -struct wl1271_ini_fem_params_2 { - __le16 tx_bip_ref_pd_voltage; - u8 tx_bip_ref_power; - u8 tx_bip_ref_offset; - u8 tx_per_rate_pwr_limits_normal[WL1271_INI_RATE_GROUP_COUNT]; - u8 tx_per_rate_pwr_limits_degraded[WL1271_INI_RATE_GROUP_COUNT]; - u8 tx_per_rate_pwr_limits_extreme[WL1271_INI_RATE_GROUP_COUNT]; - u8 tx_per_chan_pwr_limits_11b[WL1271_INI_CHANNEL_COUNT_2]; - u8 tx_per_chan_pwr_limits_ofdm[WL1271_INI_CHANNEL_COUNT_2]; - u8 tx_pd_vs_rate_offsets[WL1271_INI_RATE_GROUP_COUNT]; - u8 tx_ibias[WL1271_INI_RATE_GROUP_COUNT]; - u8 rx_fem_insertion_loss; - u8 degraded_low_to_normal_thr; - u8 normal_to_degraded_high_thr; -} __packed; - -#define WL1271_INI_CHANNEL_COUNT_5 35 -#define WL1271_INI_SUB_BAND_COUNT_5 7 - -struct wl1271_ini_band_params_5 { - u8 rx_trace_insertion_loss[WL1271_INI_SUB_BAND_COUNT_5]; - u8 tx_trace_loss[WL1271_INI_SUB_BAND_COUNT_5]; - u8 rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE]; -} __packed; - -struct wl1271_ini_fem_params_5 { - __le16 tx_bip_ref_pd_voltage[WL1271_INI_SUB_BAND_COUNT_5]; - u8 tx_bip_ref_power[WL1271_INI_SUB_BAND_COUNT_5]; - u8 tx_bip_ref_offset[WL1271_INI_SUB_BAND_COUNT_5]; - u8 tx_per_rate_pwr_limits_normal[WL1271_INI_RATE_GROUP_COUNT]; - u8 tx_per_rate_pwr_limits_degraded[WL1271_INI_RATE_GROUP_COUNT]; - u8 tx_per_rate_pwr_limits_extreme[WL1271_INI_RATE_GROUP_COUNT]; - u8 tx_per_chan_pwr_limits_ofdm[WL1271_INI_CHANNEL_COUNT_5]; - u8 tx_pd_vs_rate_offsets[WL1271_INI_RATE_GROUP_COUNT]; - u8 tx_ibias[WL1271_INI_RATE_GROUP_COUNT]; - u8 rx_fem_insertion_loss[WL1271_INI_SUB_BAND_COUNT_5]; - u8 degraded_low_to_normal_thr; - u8 normal_to_degraded_high_thr; -} __packed; - - -/* NVS data structure */ -#define WL1271_INI_NVS_SECTION_SIZE 468 -#define WL1271_INI_FEM_MODULE_COUNT 2 - -#define WL1271_INI_LEGACY_NVS_FILE_SIZE 800 - -struct wl1271_nvs_file { - /* NVS section */ - u8 nvs[WL1271_INI_NVS_SECTION_SIZE]; - - /* INI section */ - struct wl1271_ini_general_params general_params; - u8 padding1; - struct wl1271_ini_band_params_2 stat_radio_params_2; - u8 padding2; - struct { - struct wl1271_ini_fem_params_2 params; - u8 padding; - } dyn_radio_params_2[WL1271_INI_FEM_MODULE_COUNT]; - struct wl1271_ini_band_params_5 stat_radio_params_5; - u8 padding3; - struct { - struct wl1271_ini_fem_params_5 params; - u8 padding; - } dyn_radio_params_5[WL1271_INI_FEM_MODULE_COUNT]; -} __packed; - -#endif diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c deleted file mode 100644 index 8044bba..0000000 --- a/drivers/net/wireless/wl12xx/wl1271_init.c +++ /dev/null @@ -1,369 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 2009 Nokia Corporation - * - * Contact: Luciano Coelho - * - * 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 "wl1271_init.h" -#include "wl12xx_80211.h" -#include "wl1271_acx.h" -#include "wl1271_cmd.h" -#include "wl1271_reg.h" - -static int wl1271_init_hwenc_config(struct wl1271 *wl) -{ - int ret; - - ret = wl1271_acx_feature_cfg(wl); - if (ret < 0) { - wl1271_warning("couldn't set feature config"); - return ret; - } - - ret = wl1271_cmd_set_default_wep_key(wl, wl->default_key); - if (ret < 0) { - wl1271_warning("couldn't set default key"); - return ret; - } - - return 0; -} - -int wl1271_init_templates_config(struct wl1271 *wl) -{ - int ret, i; - size_t size; - - /* send empty templates for fw memory reservation */ - ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL, - sizeof(struct wl12xx_probe_req_template), - 0, WL1271_RATE_AUTOMATIC); - if (ret < 0) - return ret; - - size = sizeof(struct wl12xx_probe_req_template); - ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, - NULL, size, 0, - WL1271_RATE_AUTOMATIC); - if (ret < 0) - return ret; - - ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, NULL, - sizeof(struct wl12xx_null_data_template), - 0, WL1271_RATE_AUTOMATIC); - if (ret < 0) - return ret; - - ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, NULL, - sizeof(struct wl12xx_ps_poll_template), - 0, WL1271_RATE_AUTOMATIC); - if (ret < 0) - return ret; - - ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, NULL, - sizeof - (struct wl12xx_qos_null_data_template), - 0, WL1271_RATE_AUTOMATIC); - if (ret < 0) - return ret; - - ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE, NULL, - sizeof - (struct wl12xx_probe_resp_template), - 0, WL1271_RATE_AUTOMATIC); - if (ret < 0) - return ret; - - ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, NULL, - sizeof - (struct wl12xx_beacon_template), - 0, WL1271_RATE_AUTOMATIC); - if (ret < 0) - return ret; - - for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) { - ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV, NULL, - WL1271_CMD_TEMPL_MAX_SIZE, i, - WL1271_RATE_AUTOMATIC); - if (ret < 0) - return ret; - } - - return 0; -} - -static int wl1271_init_rx_config(struct wl1271 *wl, u32 config, u32 filter) -{ - int ret; - - ret = wl1271_acx_rx_msdu_life_time(wl); - if (ret < 0) - return ret; - - ret = wl1271_acx_rx_config(wl, config, filter); - if (ret < 0) - return ret; - - return 0; -} - -int wl1271_init_phy_config(struct wl1271 *wl) -{ - int ret; - - ret = wl1271_acx_pd_threshold(wl); - if (ret < 0) - return ret; - - ret = wl1271_acx_slot(wl, DEFAULT_SLOT_TIME); - if (ret < 0) - return ret; - - ret = wl1271_acx_group_address_tbl(wl, true, NULL, 0); - if (ret < 0) - return ret; - - ret = wl1271_acx_service_period_timeout(wl); - if (ret < 0) - return ret; - - ret = wl1271_acx_rts_threshold(wl, wl->conf.rx.rts_threshold); - if (ret < 0) - return ret; - - return 0; -} - -static int wl1271_init_beacon_filter(struct wl1271 *wl) -{ - int ret; - - /* disable beacon filtering at this stage */ - ret = wl1271_acx_beacon_filter_opt(wl, false); - if (ret < 0) - return ret; - - ret = wl1271_acx_beacon_filter_table(wl); - if (ret < 0) - return ret; - - return 0; -} - -int wl1271_init_pta(struct wl1271 *wl) -{ - int ret; - - ret = wl1271_acx_sg_cfg(wl); - if (ret < 0) - return ret; - - ret = wl1271_acx_sg_enable(wl, wl->sg_enabled); - if (ret < 0) - return ret; - - return 0; -} - -int wl1271_init_energy_detection(struct wl1271 *wl) -{ - int ret; - - ret = wl1271_acx_cca_threshold(wl); - if (ret < 0) - return ret; - - return 0; -} - -static int wl1271_init_beacon_broadcast(struct wl1271 *wl) -{ - int ret; - - ret = wl1271_acx_bcn_dtim_options(wl); - if (ret < 0) - return ret; - - return 0; -} - -int wl1271_hw_init(struct wl1271 *wl) -{ - struct conf_tx_ac_category *conf_ac; - struct conf_tx_tid *conf_tid; - int ret, i; - - ret = wl1271_cmd_general_parms(wl); - if (ret < 0) - return ret; - - ret = wl1271_cmd_radio_parms(wl); - if (ret < 0) - return ret; - - ret = wl1271_cmd_ext_radio_parms(wl); - if (ret < 0) - return ret; - - /* Template settings */ - ret = wl1271_init_templates_config(wl); - if (ret < 0) - return ret; - - /* Default memory configuration */ - ret = wl1271_acx_init_mem_config(wl); - if (ret < 0) - return ret; - - /* RX config */ - ret = wl1271_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_memmap; - - /* PHY layer config */ - ret = wl1271_init_phy_config(wl); - if (ret < 0) - goto out_free_memmap; - - ret = wl1271_acx_dco_itrim_params(wl); - if (ret < 0) - goto out_free_memmap; - - /* Initialize connection monitoring thresholds */ - ret = wl1271_acx_conn_monit_params(wl, false); - if (ret < 0) - goto out_free_memmap; - - /* Beacon filtering */ - ret = wl1271_init_beacon_filter(wl); - if (ret < 0) - goto out_free_memmap; - - /* Configure TX patch complete interrupt behavior */ - ret = wl1271_acx_tx_config_options(wl); - if (ret < 0) - goto out_free_memmap; - - /* RX complete interrupt pacing */ - ret = wl1271_acx_init_rx_interrupt(wl); - if (ret < 0) - goto out_free_memmap; - - /* Bluetooth WLAN coexistence */ - ret = wl1271_init_pta(wl); - if (ret < 0) - goto out_free_memmap; - - /* Energy detection */ - ret = wl1271_init_energy_detection(wl); - if (ret < 0) - goto out_free_memmap; - - /* Beacons and boradcast settings */ - ret = wl1271_init_beacon_broadcast(wl); - if (ret < 0) - goto out_free_memmap; - - /* Default fragmentation threshold */ - ret = wl1271_acx_frag_threshold(wl); - if (ret < 0) - goto out_free_memmap; - - /* Default TID/AC configuration */ - BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count); - for (i = 0; i < wl->conf.tx.tid_conf_count; i++) { - conf_ac = &wl->conf.tx.ac_conf[i]; - ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min, - conf_ac->cw_max, conf_ac->aifsn, - conf_ac->tx_op_limit); - if (ret < 0) - goto out_free_memmap; - - conf_tid = &wl->conf.tx.tid_conf[i]; - ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id, - conf_tid->channel_type, - conf_tid->tsid, - conf_tid->ps_scheme, - conf_tid->ack_policy, - conf_tid->apsd_conf[0], - conf_tid->apsd_conf[1]); - if (ret < 0) - goto out_free_memmap; - } - - /* Configure TX rate classes */ - ret = wl1271_acx_rate_policies(wl); - if (ret < 0) - goto out_free_memmap; - - /* Enable data path */ - ret = wl1271_cmd_data_path(wl, 1); - if (ret < 0) - goto out_free_memmap; - - /* Configure for ELP power saving */ - ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP); - if (ret < 0) - goto out_free_memmap; - - /* Configure HW encryption */ - ret = wl1271_init_hwenc_config(wl); - if (ret < 0) - goto out_free_memmap; - - /* configure PM */ - ret = wl1271_acx_pm_config(wl); - if (ret < 0) - goto out_free_memmap; - - /* disable all keep-alive templates */ - for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) { - ret = wl1271_acx_keep_alive_config(wl, i, - ACX_KEEP_ALIVE_TPL_INVALID); - if (ret < 0) - goto out_free_memmap; - } - - /* disable the keep-alive feature */ - ret = wl1271_acx_keep_alive_mode(wl, false); - if (ret < 0) - goto out_free_memmap; - - /* Configure rssi/snr averaging weights */ - ret = wl1271_acx_rssi_snr_avg_weights(wl); - if (ret < 0) - goto out_free_memmap; - - return 0; - - out_free_memmap: - kfree(wl->target_mem_map); - wl->target_mem_map = NULL; - - return ret; -} diff --git a/drivers/net/wireless/wl12xx/wl1271_init.h b/drivers/net/wireless/wl12xx/wl1271_init.h deleted file mode 100644 index bc26f8c..0000000 --- a/drivers/net/wireless/wl12xx/wl1271_init.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 2009 Nokia Corporation - * - * Contact: Luciano Coelho - * - * 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 __WL1271_INIT_H__ -#define __WL1271_INIT_H__ - -#include "wl1271.h" - -int wl1271_hw_init_power_auth(struct wl1271 *wl); -int wl1271_init_templates_config(struct wl1271 *wl); -int wl1271_init_phy_config(struct wl1271 *wl); -int wl1271_init_pta(struct wl1271 *wl); -int wl1271_init_energy_detection(struct wl1271 *wl); -int wl1271_hw_init(struct wl1271 *wl); - -#endif diff --git a/drivers/net/wireless/wl12xx/wl1271_io.c b/drivers/net/wireless/wl12xx/wl1271_io.c deleted file mode 100644 index c8759ac..0000000 --- a/drivers/net/wireless/wl12xx/wl1271_io.c +++ /dev/null @@ -1,170 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 2008-2010 Nokia Corporation - * - * Contact: Luciano Coelho - * - * 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 "wl1271.h" -#include "wl12xx_80211.h" -#include "wl1271_io.h" - -#define OCP_CMD_LOOP 32 - -#define OCP_CMD_WRITE 0x1 -#define OCP_CMD_READ 0x2 - -#define OCP_READY_MASK BIT(18) -#define OCP_STATUS_MASK (BIT(16) | BIT(17)) - -#define OCP_STATUS_NO_RESP 0x00000 -#define OCP_STATUS_OK 0x10000 -#define OCP_STATUS_REQ_FAILED 0x20000 -#define OCP_STATUS_RESP_ERROR 0x30000 - -void wl1271_disable_interrupts(struct wl1271 *wl) -{ - wl->if_ops->disable_irq(wl); -} - -void wl1271_enable_interrupts(struct wl1271 *wl) -{ - wl->if_ops->enable_irq(wl); -} - -/* Set the SPI partitions to access the chip addresses - * - * To simplify driver code, a fixed (virtual) memory map is defined for - * register and memory addresses. Because in the chipset, in different stages - * of operation, those addresses will move around, an address translation - * mechanism is required. - * - * There are four partitions (three memory and one register partition), - * which are mapped to two different areas of the hardware memory. - * - * Virtual address - * space - * - * | | - * ...+----+--> mem.start - * Physical address ... | | - * space ... | | [PART_0] - * ... | | - * 00000000 <--+----+... ...+----+--> mem.start + mem.size - * | | ... | | - * |MEM | ... | | - * | | ... | | - * mem.size <--+----+... | | {unused area) - * | | ... | | - * |REG | ... | | - * mem.size | | ... | | - * + <--+----+... ...+----+--> reg.start - * reg.size | | ... | | - * |MEM2| ... | | [PART_1] - * | | ... | | - * ...+----+--> reg.start + reg.size - * | | - * - */ -int wl1271_set_partition(struct wl1271 *wl, - struct wl1271_partition_set *p) -{ - /* copy partition info */ - memcpy(&wl->part, p, sizeof(*p)); - - wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", - p->mem.start, p->mem.size); - wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", - p->reg.start, p->reg.size); - wl1271_debug(DEBUG_SPI, "mem2_start %08X mem2_size %08X", - p->mem2.start, p->mem2.size); - wl1271_debug(DEBUG_SPI, "mem3_start %08X mem3_size %08X", - p->mem3.start, p->mem3.size); - - /* write partition info to the chipset */ - wl1271_raw_write32(wl, HW_PART0_START_ADDR, p->mem.start); - wl1271_raw_write32(wl, HW_PART0_SIZE_ADDR, p->mem.size); - wl1271_raw_write32(wl, HW_PART1_START_ADDR, p->reg.start); - wl1271_raw_write32(wl, HW_PART1_SIZE_ADDR, p->reg.size); - wl1271_raw_write32(wl, HW_PART2_START_ADDR, p->mem2.start); - wl1271_raw_write32(wl, HW_PART2_SIZE_ADDR, p->mem2.size); - wl1271_raw_write32(wl, HW_PART3_START_ADDR, p->mem3.start); - - return 0; -} - -void wl1271_io_reset(struct wl1271 *wl) -{ - wl->if_ops->reset(wl); -} - -void wl1271_io_init(struct wl1271 *wl) -{ - wl->if_ops->init(wl); -} - -void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val) -{ - /* write address >> 1 + 0x30000 to OCP_POR_CTR */ - addr = (addr >> 1) + 0x30000; - wl1271_write32(wl, OCP_POR_CTR, addr); - - /* write value to OCP_POR_WDATA */ - wl1271_write32(wl, OCP_DATA_WRITE, val); - - /* write 1 to OCP_CMD */ - wl1271_write32(wl, OCP_CMD, OCP_CMD_WRITE); -} - -u16 wl1271_top_reg_read(struct wl1271 *wl, int addr) -{ - u32 val; - int timeout = OCP_CMD_LOOP; - - /* write address >> 1 + 0x30000 to OCP_POR_CTR */ - addr = (addr >> 1) + 0x30000; - wl1271_write32(wl, OCP_POR_CTR, addr); - - /* write 2 to OCP_CMD */ - wl1271_write32(wl, OCP_CMD, OCP_CMD_READ); - - /* poll for data ready */ - do { - val = wl1271_read32(wl, OCP_DATA_READ); - } while (!(val & OCP_READY_MASK) && --timeout); - - if (!timeout) { - wl1271_warning("Top register access timed out."); - return 0xffff; - } - - /* check data status and return if OK */ - if ((val & OCP_STATUS_MASK) == OCP_STATUS_OK) - return val & 0xffff; - else { - wl1271_warning("Top register access returned error."); - return 0xffff; - } -} - diff --git a/drivers/net/wireless/wl12xx/wl1271_io.h b/drivers/net/wireless/wl12xx/wl1271_io.h deleted file mode 100644 index c1f92e6..0000000 --- a/drivers/net/wireless/wl12xx/wl1271_io.h +++ /dev/null @@ -1,172 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. - * Copyright (C) 2008-2010 Nokia Corporation - * - * Contact: Luciano Coelho - * - * 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 __WL1271_IO_H__ -#define __WL1271_IO_H__ - -#include "wl1271_reg.h" - -#define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0 - -#define HW_PARTITION_REGISTERS_ADDR 0x1FFC0 -#define HW_PART0_SIZE_ADDR (HW_PARTITION_REGISTERS_ADDR) -#define HW_PART0_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 4) -#define HW_PART1_SIZE_ADDR (HW_PARTITION_REGISTERS_ADDR + 8) -#define HW_PART1_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 12) -#define HW_PART2_SIZE_ADDR (HW_PARTITION_REGISTERS_ADDR + 16) -#define HW_PART2_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 20) -#define HW_PART3_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 24) - -#define HW_ACCESS_REGISTER_SIZE 4 - -#define HW_ACCESS_PRAM_MAX_RANGE 0x3c000 - -struct wl1271; - -void wl1271_disable_interrupts(struct wl1271 *wl); -void wl1271_enable_interrupts(struct wl1271 *wl); - -void wl1271_io_reset(struct wl1271 *wl); -void wl1271_io_init(struct wl1271 *wl); - -static inline struct device *wl1271_wl_to_dev(struct wl1271 *wl) -{ - return wl->if_ops->dev(wl); -} - - -/* Raw target IO, address is not translated */ -static inline void wl1271_raw_write(struct wl1271 *wl, int addr, void *buf, - size_t len, bool fixed) -{ - wl->if_ops->write(wl, addr, buf, len, fixed); -} - -static inline void wl1271_raw_read(struct wl1271 *wl, int addr, void *buf, - size_t len, bool fixed) -{ - wl->if_ops->read(wl, addr, buf, len, fixed); -} - -static inline u32 wl1271_raw_read32(struct wl1271 *wl, int addr) -{ - wl1271_raw_read(wl, addr, &wl->buffer_32, - sizeof(wl->buffer_32), false); - - return le32_to_cpu(wl->buffer_32); -} - -static inline void wl1271_raw_write32(struct wl1271 *wl, int addr, u32 val) -{ - wl->buffer_32 = cpu_to_le32(val); - wl1271_raw_write(wl, addr, &wl->buffer_32, - sizeof(wl->buffer_32), false); -} - -/* Translated target IO */ -static inline int wl1271_translate_addr(struct wl1271 *wl, int addr) -{ - /* - * To translate, first check to which window of addresses the - * particular address belongs. Then subtract the starting address - * of that window from the address. Then, add offset of the - * translated region. - * - * The translated regions occur next to each other in physical device - * memory, so just add the sizes of the preceeding address regions to - * get the offset to the new region. - * - * Currently, only the two first regions are addressed, and the - * assumption is that all addresses will fall into either of those - * two. - */ - if ((addr >= wl->part.reg.start) && - (addr < wl->part.reg.start + wl->part.reg.size)) - return addr - wl->part.reg.start + wl->part.mem.size; - else - return addr - wl->part.mem.start; -} - -static inline void wl1271_read(struct wl1271 *wl, int addr, void *buf, - size_t len, bool fixed) -{ - int physical; - - physical = wl1271_translate_addr(wl, addr); - - wl1271_raw_read(wl, physical, buf, len, fixed); -} - -static inline void wl1271_write(struct wl1271 *wl, int addr, void *buf, - size_t len, bool fixed) -{ - int physical; - - physical = wl1271_translate_addr(wl, addr); - - wl1271_raw_write(wl, physical, buf, len, fixed); -} - -static inline u32 wl1271_read32(struct wl1271 *wl, int addr) -{ - return wl1271_raw_read32(wl, wl1271_translate_addr(wl, addr)); -} - -static inline void wl1271_write32(struct wl1271 *wl, int addr, u32 val) -{ - wl1271_raw_write32(wl, wl1271_translate_addr(wl, addr), val); -} - -static inline void wl1271_power_off(struct wl1271 *wl) -{ - wl->if_ops->power(wl, false); - clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); -} - -static inline int wl1271_power_on(struct wl1271 *wl) -{ - int ret = wl->if_ops->power(wl, true); - if (ret == 0) - set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); - - return ret; -} - - -/* Top Register IO */ -void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val); -u16 wl1271_top_reg_read(struct wl1271 *wl, int addr); - -int wl1271_set_partition(struct wl1271 *wl, - struct wl1271_partition_set *p); - -/* Functions from wl1271_main.c */ - -int wl1271_register_hw(struct wl1271 *wl); -void wl1271_unregister_hw(struct wl1271 *wl); -int wl1271_init_ieee80211(struct wl1271 *wl); -struct ieee80211_hw *wl1271_alloc_hw(void); -int wl1271_free_hw(struct wl1271 *wl); - -#endif diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c deleted file mode 100644 index f5b1d19..0000000 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ /dev/null @@ -1,2749 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 2008-2010 Nokia Corporation - * - * Contact: Luciano Coelho - * - * 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 "wl1271.h" -#include "wl12xx_80211.h" -#include "wl1271_reg.h" -#include "wl1271_io.h" -#include "wl1271_event.h" -#include "wl1271_tx.h" -#include "wl1271_rx.h" -#include "wl1271_ps.h" -#include "wl1271_init.h" -#include "wl1271_debugfs.h" -#include "wl1271_cmd.h" -#include "wl1271_boot.h" -#include "wl1271_testmode.h" -#include "wl1271_scan.h" - -#define WL1271_BOOT_RETRIES 3 - -static struct conf_drv_settings default_conf = { - .sg = { - .params = { - [CONF_SG_BT_PER_THRESHOLD] = 7500, - [CONF_SG_HV3_MAX_OVERRIDE] = 0, - [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400, - [CONF_SG_BT_LOAD_RATIO] = 50, - [CONF_SG_AUTO_PS_MODE] = 1, - [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170, - [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50, - [CONF_SG_ANTENNA_CONFIGURATION] = 0, - [CONF_SG_BEACON_MISS_PERCENT] = 60, - [CONF_SG_RATE_ADAPT_THRESH] = 12, - [CONF_SG_RATE_ADAPT_SNR] = 0, - [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10, - [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 30, - [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 8, - [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20, - [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 50, - /* Note: with UPSD, this should be 4 */ - [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 8, - [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7, - [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25, - [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 20, - /* Note: with UPDS, this should be 15 */ - [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8, - /* Note: with UPDS, this should be 50 */ - [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 40, - /* Note: with UPDS, this should be 10 */ - [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 20, - [CONF_SG_RXT] = 1200, - [CONF_SG_TXT] = 1000, - [CONF_SG_ADAPTIVE_RXT_TXT] = 1, - [CONF_SG_PS_POLL_TIMEOUT] = 10, - [CONF_SG_UPSD_TIMEOUT] = 10, - [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7, - [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15, - [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15, - [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8, - [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20, - [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15, - [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20, - [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50, - [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10, - [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200, - [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800, - [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75, - [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15, - [CONF_SG_HV3_MAX_SERVED] = 6, - [CONF_SG_DHCP_TIME] = 5000, - [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100, - }, - .state = CONF_SG_PROTECTIVE, - }, - .rx = { - .rx_msdu_life_time = 512000, - .packet_detection_threshold = 0, - .ps_poll_timeout = 15, - .upsd_timeout = 15, - .rts_threshold = 2347, - .rx_cca_threshold = 0, - .irq_blk_threshold = 0xFFFF, - .irq_pkt_threshold = 0, - .irq_timeout = 600, - .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY, - }, - .tx = { - .tx_energy_detection = 0, - .rc_conf = { - .enabled_rates = 0, - .short_retry_limit = 10, - .long_retry_limit = 10, - .aflags = 0 - }, - .ac_conf_count = 4, - .ac_conf = { - [CONF_TX_AC_BE] = { - .ac = CONF_TX_AC_BE, - .cw_min = 15, - .cw_max = 63, - .aifsn = 3, - .tx_op_limit = 0, - }, - [CONF_TX_AC_BK] = { - .ac = CONF_TX_AC_BK, - .cw_min = 15, - .cw_max = 63, - .aifsn = 7, - .tx_op_limit = 0, - }, - [CONF_TX_AC_VI] = { - .ac = CONF_TX_AC_VI, - .cw_min = 15, - .cw_max = 63, - .aifsn = CONF_TX_AIFS_PIFS, - .tx_op_limit = 3008, - }, - [CONF_TX_AC_VO] = { - .ac = CONF_TX_AC_VO, - .cw_min = 15, - .cw_max = 63, - .aifsn = CONF_TX_AIFS_PIFS, - .tx_op_limit = 1504, - }, - }, - .tid_conf_count = 4, - .tid_conf = { - [CONF_TX_AC_BE] = { - .queue_id = CONF_TX_AC_BE, - .channel_type = CONF_CHANNEL_TYPE_EDCF, - .tsid = CONF_TX_AC_BE, - .ps_scheme = CONF_PS_SCHEME_LEGACY, - .ack_policy = CONF_ACK_POLICY_LEGACY, - .apsd_conf = {0, 0}, - }, - [CONF_TX_AC_BK] = { - .queue_id = CONF_TX_AC_BK, - .channel_type = CONF_CHANNEL_TYPE_EDCF, - .tsid = CONF_TX_AC_BK, - .ps_scheme = CONF_PS_SCHEME_LEGACY, - .ack_policy = CONF_ACK_POLICY_LEGACY, - .apsd_conf = {0, 0}, - }, - [CONF_TX_AC_VI] = { - .queue_id = CONF_TX_AC_VI, - .channel_type = CONF_CHANNEL_TYPE_EDCF, - .tsid = CONF_TX_AC_VI, - .ps_scheme = CONF_PS_SCHEME_LEGACY, - .ack_policy = CONF_ACK_POLICY_LEGACY, - .apsd_conf = {0, 0}, - }, - [CONF_TX_AC_VO] = { - .queue_id = CONF_TX_AC_VO, - .channel_type = CONF_CHANNEL_TYPE_EDCF, - .tsid = CONF_TX_AC_VO, - .ps_scheme = CONF_PS_SCHEME_LEGACY, - .ack_policy = CONF_ACK_POLICY_LEGACY, - .apsd_conf = {0, 0}, - }, - }, - .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD, - .tx_compl_timeout = 700, - .tx_compl_threshold = 4, - .basic_rate = CONF_HW_BIT_RATE_1MBPS, - .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS, - }, - .conn = { - .wake_up_event = CONF_WAKE_UP_EVENT_DTIM, - .listen_interval = 1, - .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED, - .bcn_filt_ie_count = 1, - .bcn_filt_ie = { - [0] = { - .ie = WLAN_EID_CHANNEL_SWITCH, - .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE, - } - }, - .synch_fail_thold = 10, - .bss_lose_timeout = 100, - .beacon_rx_timeout = 10000, - .broadcast_timeout = 20000, - .rx_broadcast_in_ps = 1, - .ps_poll_threshold = 10, - .ps_poll_recovery_period = 700, - .bet_enable = CONF_BET_MODE_ENABLE, - .bet_max_consecutive = 10, - .psm_entry_retries = 5, - .psm_entry_nullfunc_retries = 3, - .psm_entry_hangover_period = 1, - .keep_alive_interval = 55000, - .max_listen_interval = 20, - }, - .itrim = { - .enable = false, - .timeout = 50000, - }, - .pm_config = { - .host_clk_settling_time = 5000, - .host_fast_wakeup_support = false - }, - .roam_trigger = { - .trigger_pacing = 1, - .avg_weight_rssi_beacon = 20, - .avg_weight_rssi_data = 10, - .avg_weight_snr_beacon = 20, - .avg_weight_snr_data = 10 - }, - .scan = { - .min_dwell_time_active = 7500, - .max_dwell_time_active = 30000, - .min_dwell_time_passive = 30000, - .max_dwell_time_passive = 60000, - .num_probe_reqs = 2, - }, - .rf = { - .tx_per_channel_power_compensation_2 = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, - .tx_per_channel_power_compensation_5 = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, - }, -}; - -static void __wl1271_op_remove_interface(struct wl1271 *wl); - - -static void wl1271_device_release(struct device *dev) -{ - -} - -static struct platform_device wl1271_device = { - .name = "wl1271", - .id = -1, - - /* device model insists to have a release function */ - .dev = { - .release = wl1271_device_release, - }, -}; - -static LIST_HEAD(wl_list); - -static int wl1271_dev_notify(struct notifier_block *me, unsigned long what, - void *arg) -{ - struct net_device *dev = arg; - struct wireless_dev *wdev; - struct wiphy *wiphy; - struct ieee80211_hw *hw; - struct wl1271 *wl; - struct wl1271 *wl_temp; - int ret = 0; - - /* Check that this notification is for us. */ - if (what != NETDEV_CHANGE) - return NOTIFY_DONE; - - wdev = dev->ieee80211_ptr; - if (wdev == NULL) - return NOTIFY_DONE; - - wiphy = wdev->wiphy; - if (wiphy == NULL) - return NOTIFY_DONE; - - hw = wiphy_priv(wiphy); - if (hw == NULL) - return NOTIFY_DONE; - - wl_temp = hw->priv; - list_for_each_entry(wl, &wl_list, list) { - if (wl == wl_temp) - break; - } - if (wl != wl_temp) - return NOTIFY_DONE; - - mutex_lock(&wl->mutex); - - if (wl->state == WL1271_STATE_OFF) - goto out; - - if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) - goto out; - - ret = wl1271_ps_elp_wakeup(wl, false); - if (ret < 0) - goto out; - - if ((dev->operstate == IF_OPER_UP) && - !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) { - wl1271_cmd_set_sta_state(wl); - wl1271_info("Association completed."); - } - - wl1271_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); - - return NOTIFY_OK; -} - -static void wl1271_conf_init(struct wl1271 *wl) -{ - - /* - * This function applies the default configuration to the driver. This - * function is invoked upon driver load (spi probe.) - * - * The configuration is stored in a run-time structure in order to - * facilitate for run-time adjustment of any of the parameters. Making - * changes to the configuration structure will apply the new values on - * the next interface up (wl1271_op_start.) - */ - - /* apply driver default configuration */ - memcpy(&wl->conf, &default_conf, sizeof(default_conf)); -} - - -static int wl1271_plt_init(struct wl1271 *wl) -{ - struct conf_tx_ac_category *conf_ac; - struct conf_tx_tid *conf_tid; - int ret, i; - - ret = wl1271_cmd_general_parms(wl); - if (ret < 0) - return ret; - - ret = wl1271_cmd_radio_parms(wl); - if (ret < 0) - return ret; - - ret = wl1271_cmd_ext_radio_parms(wl); - if (ret < 0) - return ret; - - ret = wl1271_init_templates_config(wl); - if (ret < 0) - return ret; - - ret = wl1271_acx_init_mem_config(wl); - if (ret < 0) - return ret; - - /* PHY layer config */ - ret = wl1271_init_phy_config(wl); - if (ret < 0) - goto out_free_memmap; - - ret = wl1271_acx_dco_itrim_params(wl); - if (ret < 0) - goto out_free_memmap; - - /* Initialize connection monitoring thresholds */ - ret = wl1271_acx_conn_monit_params(wl, false); - if (ret < 0) - goto out_free_memmap; - - /* Bluetooth WLAN coexistence */ - ret = wl1271_init_pta(wl); - if (ret < 0) - goto out_free_memmap; - - /* Energy detection */ - ret = wl1271_init_energy_detection(wl); - if (ret < 0) - goto out_free_memmap; - - /* Default fragmentation threshold */ - ret = wl1271_acx_frag_threshold(wl); - if (ret < 0) - goto out_free_memmap; - - /* Default TID/AC configuration */ - BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count); - for (i = 0; i < wl->conf.tx.tid_conf_count; i++) { - conf_ac = &wl->conf.tx.ac_conf[i]; - ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min, - conf_ac->cw_max, conf_ac->aifsn, - conf_ac->tx_op_limit); - if (ret < 0) - goto out_free_memmap; - - conf_tid = &wl->conf.tx.tid_conf[i]; - ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id, - conf_tid->channel_type, - conf_tid->tsid, - conf_tid->ps_scheme, - conf_tid->ack_policy, - conf_tid->apsd_conf[0], - conf_tid->apsd_conf[1]); - if (ret < 0) - goto out_free_memmap; - } - - /* Enable data path */ - ret = wl1271_cmd_data_path(wl, 1); - if (ret < 0) - goto out_free_memmap; - - /* Configure for CAM power saving (ie. always active) */ - ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM); - if (ret < 0) - goto out_free_memmap; - - /* configure PM */ - ret = wl1271_acx_pm_config(wl); - if (ret < 0) - goto out_free_memmap; - - return 0; - - out_free_memmap: - kfree(wl->target_mem_map); - wl->target_mem_map = NULL; - - return ret; -} - -static void wl1271_fw_status(struct wl1271 *wl, - struct wl1271_fw_status *status) -{ - struct timespec ts; - u32 total = 0; - int i; - - wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false); - - wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, " - "drv_rx_counter = %d, tx_results_counter = %d)", - status->intr, - status->fw_rx_counter, - status->drv_rx_counter, - status->tx_results_counter); - - /* update number of available TX blocks */ - for (i = 0; i < NUM_TX_QUEUES; i++) { - u32 cnt = le32_to_cpu(status->tx_released_blks[i]) - - wl->tx_blocks_freed[i]; - - wl->tx_blocks_freed[i] = - le32_to_cpu(status->tx_released_blks[i]); - wl->tx_blocks_available += cnt; - total += cnt; - } - - /* if more blocks are available now, tx work can be scheduled */ - if (total) - clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); - - /* update the host-chipset time offset */ - getnstimeofday(&ts); - wl->time_offset = (timespec_to_ns(&ts) >> 10) - - (s64)le32_to_cpu(status->fw_localtime); -} - -#define WL1271_IRQ_MAX_LOOPS 10 - -static void wl1271_irq_work(struct work_struct *work) -{ - int ret; - u32 intr; - int loopcount = WL1271_IRQ_MAX_LOOPS; - unsigned long flags; - struct wl1271 *wl = - container_of(work, struct wl1271, irq_work); - - mutex_lock(&wl->mutex); - - wl1271_debug(DEBUG_IRQ, "IRQ work"); - - if (unlikely(wl->state == WL1271_STATE_OFF)) - goto out; - - ret = wl1271_ps_elp_wakeup(wl, true); - if (ret < 0) - goto out; - - spin_lock_irqsave(&wl->wl_lock, flags); - while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) { - clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags); - spin_unlock_irqrestore(&wl->wl_lock, flags); - loopcount--; - - wl1271_fw_status(wl, wl->fw_status); - intr = le32_to_cpu(wl->fw_status->intr); - if (!intr) { - wl1271_debug(DEBUG_IRQ, "Zero interrupt received."); - spin_lock_irqsave(&wl->wl_lock, flags); - continue; - } - - intr &= WL1271_INTR_MASK; - - if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) { - wl1271_error("watchdog interrupt received! " - "starting recovery."); - ieee80211_queue_work(wl->hw, &wl->recovery_work); - - /* restarting the chip. ignore any other interrupt. */ - goto out; - } - - if (intr & WL1271_ACX_INTR_DATA) { - wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA"); - - /* check for tx results */ - if (wl->fw_status->tx_results_counter != - (wl->tx_results_count & 0xff)) - wl1271_tx_complete(wl); - - /* Check if any tx blocks were freed */ - if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) && - !skb_queue_empty(&wl->tx_queue)) { - /* - * In order to avoid starvation of the TX path, - * call the work function directly. - */ - wl1271_tx_work_locked(wl); - } - - wl1271_rx(wl, wl->fw_status); - } - - if (intr & WL1271_ACX_INTR_EVENT_A) { - wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A"); - wl1271_event_handle(wl, 0); - } - - if (intr & WL1271_ACX_INTR_EVENT_B) { - wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B"); - wl1271_event_handle(wl, 1); - } - - if (intr & WL1271_ACX_INTR_INIT_COMPLETE) - wl1271_debug(DEBUG_IRQ, - "WL1271_ACX_INTR_INIT_COMPLETE"); - - if (intr & WL1271_ACX_INTR_HW_AVAILABLE) - wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE"); - - spin_lock_irqsave(&wl->wl_lock, flags); - } - - if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags)) - ieee80211_queue_work(wl->hw, &wl->irq_work); - else - clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags); - spin_unlock_irqrestore(&wl->wl_lock, flags); - - wl1271_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); -} - -static int wl1271_fetch_firmware(struct wl1271 *wl) -{ - const struct firmware *fw; - int ret; - - ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl)); - - if (ret < 0) { - wl1271_error("could not get firmware: %d", ret); - return ret; - } - - if (fw->size % 4) { - wl1271_error("firmware size is not multiple of 32 bits: %zu", - fw->size); - ret = -EILSEQ; - goto out; - } - - wl->fw_len = fw->size; - wl->fw = vmalloc(wl->fw_len); - - if (!wl->fw) { - wl1271_error("could not allocate memory for the firmware"); - ret = -ENOMEM; - goto out; - } - - memcpy(wl->fw, fw->data, wl->fw_len); - - ret = 0; - -out: - release_firmware(fw); - - return ret; -} - -static int wl1271_fetch_nvs(struct wl1271 *wl) -{ - const struct firmware *fw; - int ret; - - ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl)); - - if (ret < 0) { - wl1271_error("could not get nvs file: %d", ret); - return ret; - } - - wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL); - - if (!wl->nvs) { - wl1271_error("could not allocate memory for the nvs file"); - ret = -ENOMEM; - goto out; - } - - wl->nvs_len = fw->size; - -out: - release_firmware(fw); - - return ret; -} - -static void wl1271_recovery_work(struct work_struct *work) -{ - struct wl1271 *wl = - container_of(work, struct wl1271, recovery_work); - - mutex_lock(&wl->mutex); - - if (wl->state != WL1271_STATE_ON) - goto out; - - wl1271_info("Hardware recovery in progress."); - - if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) - ieee80211_connection_loss(wl->vif); - - /* reboot the chipset */ - __wl1271_op_remove_interface(wl); - ieee80211_restart_hw(wl->hw); - -out: - mutex_unlock(&wl->mutex); -} - -static void wl1271_fw_wakeup(struct wl1271 *wl) -{ - u32 elp_reg; - - elp_reg = ELPCTRL_WAKE_UP; - wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg); -} - -static int wl1271_setup(struct wl1271 *wl) -{ - wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL); - if (!wl->fw_status) - return -ENOMEM; - - wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL); - if (!wl->tx_res_if) { - kfree(wl->fw_status); - return -ENOMEM; - } - - return 0; -} - -static int wl1271_chip_wakeup(struct wl1271 *wl) -{ - struct wl1271_partition_set partition; - int ret = 0; - - msleep(WL1271_PRE_POWER_ON_SLEEP); - ret = wl1271_power_on(wl); - if (ret < 0) - goto out; - msleep(WL1271_POWER_ON_SLEEP); - wl1271_io_reset(wl); - wl1271_io_init(wl); - - /* We don't need a real memory partition here, because we only want - * to use the registers at this point. */ - memset(&partition, 0, sizeof(partition)); - partition.reg.start = REGISTERS_BASE; - partition.reg.size = REGISTERS_DOWN_SIZE; - wl1271_set_partition(wl, &partition); - - /* ELP module wake up */ - wl1271_fw_wakeup(wl); - - /* whal_FwCtrl_BootSm() */ - - /* 0. read chip id from CHIP_ID */ - wl->chip.id = wl1271_read32(wl, CHIP_ID_B); - - /* 1. check if chip id is valid */ - - switch (wl->chip.id) { - case CHIP_ID_1271_PG10: - wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete", - wl->chip.id); - - ret = wl1271_setup(wl); - if (ret < 0) - goto out; - break; - case CHIP_ID_1271_PG20: - wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)", - wl->chip.id); - - ret = wl1271_setup(wl); - if (ret < 0) - goto out; - break; - default: - wl1271_warning("unsupported chip id: 0x%x", wl->chip.id); - ret = -ENODEV; - goto out; - } - - if (wl->fw == NULL) { - ret = wl1271_fetch_firmware(wl); - if (ret < 0) - goto out; - } - - /* No NVS from netlink, try to get it from the filesystem */ - if (wl->nvs == NULL) { - ret = wl1271_fetch_nvs(wl); - if (ret < 0) - goto out; - } - -out: - return ret; -} - -int wl1271_plt_start(struct wl1271 *wl) -{ - int retries = WL1271_BOOT_RETRIES; - int ret; - - mutex_lock(&wl->mutex); - - wl1271_notice("power up"); - - if (wl->state != WL1271_STATE_OFF) { - wl1271_error("cannot go into PLT state because not " - "in off state: %d", wl->state); - ret = -EBUSY; - goto out; - } - - while (retries) { - retries--; - ret = wl1271_chip_wakeup(wl); - if (ret < 0) - goto power_off; - - ret = wl1271_boot(wl); - if (ret < 0) - goto power_off; - - ret = wl1271_plt_init(wl); - if (ret < 0) - goto irq_disable; - - wl->state = WL1271_STATE_PLT; - wl1271_notice("firmware booted in PLT mode (%s)", - wl->chip.fw_ver); - goto out; - -irq_disable: - wl1271_disable_interrupts(wl); - mutex_unlock(&wl->mutex); - /* Unlocking the mutex in the middle of handling is - inherently unsafe. In this case we deem it safe to do, - because we need to let any possibly pending IRQ out of - the system (and while we are WL1271_STATE_OFF the IRQ - work function will not do anything.) Also, any other - possible concurrent operations will fail due to the - current state, hence the wl1271 struct should be safe. */ - cancel_work_sync(&wl->irq_work); - mutex_lock(&wl->mutex); -power_off: - wl1271_power_off(wl); - } - - wl1271_error("firmware boot in PLT mode failed despite %d retries", - WL1271_BOOT_RETRIES); -out: - mutex_unlock(&wl->mutex); - - return ret; -} - -int wl1271_plt_stop(struct wl1271 *wl) -{ - int ret = 0; - - mutex_lock(&wl->mutex); - - wl1271_notice("power down"); - - if (wl->state != WL1271_STATE_PLT) { - wl1271_error("cannot power down because not in PLT " - "state: %d", wl->state); - ret = -EBUSY; - goto out; - } - - wl1271_disable_interrupts(wl); - wl1271_power_off(wl); - - wl->state = WL1271_STATE_OFF; - wl->rx_counter = 0; - -out: - mutex_unlock(&wl->mutex); - - cancel_work_sync(&wl->irq_work); - cancel_work_sync(&wl->recovery_work); - - return ret; -} - -static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) -{ - struct wl1271 *wl = hw->priv; - struct ieee80211_conf *conf = &hw->conf; - struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb); - struct ieee80211_sta *sta = txinfo->control.sta; - unsigned long flags; - - /* - * peek into the rates configured in the STA entry. - * The rates set after connection stage, The first block only BG sets: - * the compare is for bit 0-16 of sta_rate_set. The second block add - * HT rates in case of HT supported. - */ - spin_lock_irqsave(&wl->wl_lock, flags); - if (sta && - (sta->supp_rates[conf->channel->band] != - (wl->sta_rate_set & HW_BG_RATES_MASK))) { - wl->sta_rate_set = sta->supp_rates[conf->channel->band]; - set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags); - } - -#ifdef CONFIG_WL1271_HT - if (sta && - sta->ht_cap.ht_supported && - ((wl->sta_rate_set >> HW_HT_RATES_OFFSET) != - sta->ht_cap.mcs.rx_mask[0])) { - /* Clean MCS bits before setting them */ - wl->sta_rate_set &= HW_BG_RATES_MASK; - wl->sta_rate_set |= - (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET); - set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags); - } -#endif - spin_unlock_irqrestore(&wl->wl_lock, flags); - - /* queue the packet */ - 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! - */ - - if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags)) - 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) >= WL1271_TX_QUEUE_HIGH_WATERMARK) { - wl1271_debug(DEBUG_TX, "op_tx: stopping queues"); - - spin_lock_irqsave(&wl->wl_lock, flags); - ieee80211_stop_queues(wl->hw); - set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags); - spin_unlock_irqrestore(&wl->wl_lock, flags); - } - - return NETDEV_TX_OK; -} - -static struct notifier_block wl1271_dev_notifier = { - .notifier_call = wl1271_dev_notify, -}; - -static int wl1271_op_start(struct ieee80211_hw *hw) -{ - wl1271_debug(DEBUG_MAC80211, "mac80211 start"); - - /* - * We have to delay the booting of the hardware because - * we need to know the local MAC address before downloading and - * initializing the firmware. The MAC address cannot be changed - * after boot, and without the proper MAC address, the firmware - * will not function properly. - * - * The MAC address is first known when the corresponding interface - * is added. That is where we will initialize the hardware. - */ - - return 0; -} - -static void wl1271_op_stop(struct ieee80211_hw *hw) -{ - wl1271_debug(DEBUG_MAC80211, "mac80211 stop"); -} - -static int wl1271_op_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct wl1271 *wl = hw->priv; - struct wiphy *wiphy = hw->wiphy; - int retries = WL1271_BOOT_RETRIES; - int ret = 0; - bool booted = false; - - wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", - vif->type, vif->addr); - - mutex_lock(&wl->mutex); - if (wl->vif) { - wl1271_debug(DEBUG_MAC80211, - "multiple vifs are not supported yet"); - ret = -EBUSY; - goto out; - } - - switch (vif->type) { - case NL80211_IFTYPE_STATION: - wl->bss_type = BSS_TYPE_STA_BSS; - wl->set_bss_type = BSS_TYPE_STA_BSS; - break; - case NL80211_IFTYPE_ADHOC: - wl->bss_type = BSS_TYPE_IBSS; - wl->set_bss_type = BSS_TYPE_STA_BSS; - break; - default: - ret = -EOPNOTSUPP; - goto out; - } - - memcpy(wl->mac_addr, vif->addr, ETH_ALEN); - - if (wl->state != WL1271_STATE_OFF) { - wl1271_error("cannot start because not in off state: %d", - wl->state); - ret = -EBUSY; - goto out; - } - - while (retries) { - retries--; - ret = wl1271_chip_wakeup(wl); - if (ret < 0) - goto power_off; - - ret = wl1271_boot(wl); - if (ret < 0) - goto power_off; - - ret = wl1271_hw_init(wl); - if (ret < 0) - goto irq_disable; - - booted = true; - break; - -irq_disable: - wl1271_disable_interrupts(wl); - mutex_unlock(&wl->mutex); - /* Unlocking the mutex in the middle of handling is - inherently unsafe. In this case we deem it safe to do, - because we need to let any possibly pending IRQ out of - the system (and while we are WL1271_STATE_OFF the IRQ - work function will not do anything.) Also, any other - possible concurrent operations will fail due to the - current state, hence the wl1271 struct should be safe. */ - cancel_work_sync(&wl->irq_work); - mutex_lock(&wl->mutex); -power_off: - wl1271_power_off(wl); - } - - if (!booted) { - wl1271_error("firmware boot failed despite %d retries", - WL1271_BOOT_RETRIES); - goto out; - } - - wl->vif = vif; - wl->state = WL1271_STATE_ON; - wl1271_info("firmware booted (%s)", wl->chip.fw_ver); - - /* update hw/fw version info in wiphy struct */ - wiphy->hw_version = wl->chip.id; - strncpy(wiphy->fw_version, wl->chip.fw_ver, - sizeof(wiphy->fw_version)); - -out: - mutex_unlock(&wl->mutex); - - if (!ret) - list_add(&wl->list, &wl_list); - - return ret; -} - -static void __wl1271_op_remove_interface(struct wl1271 *wl) -{ - int i; - - wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface"); - - wl1271_info("down"); - - list_del(&wl->list); - - WARN_ON(wl->state != WL1271_STATE_ON); - - /* enable dyn ps just in case (if left on due to fw crash etc) */ - if (wl->bss_type == BSS_TYPE_STA_BSS) - ieee80211_enable_dyn_ps(wl->vif); - - if (wl->scan.state != WL1271_SCAN_STATE_IDLE) { - wl->scan.state = WL1271_SCAN_STATE_IDLE; - kfree(wl->scan.scanned_ch); - wl->scan.scanned_ch = NULL; - wl->scan.req = NULL; - ieee80211_scan_completed(wl->hw, true); - } - - wl->state = WL1271_STATE_OFF; - - wl1271_disable_interrupts(wl); - - mutex_unlock(&wl->mutex); - - cancel_delayed_work_sync(&wl->scan_complete_work); - cancel_work_sync(&wl->irq_work); - cancel_work_sync(&wl->tx_work); - cancel_delayed_work_sync(&wl->pspoll_work); - cancel_delayed_work_sync(&wl->elp_work); - - mutex_lock(&wl->mutex); - - /* let's notify MAC80211 about the remaining pending TX frames */ - wl1271_tx_reset(wl); - wl1271_power_off(wl); - - memset(wl->bssid, 0, ETH_ALEN); - memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1); - wl->ssid_len = 0; - wl->bss_type = MAX_BSS_TYPE; - wl->set_bss_type = MAX_BSS_TYPE; - wl->band = IEEE80211_BAND_2GHZ; - - wl->rx_counter = 0; - wl->psm_entry_retry = 0; - wl->power_level = WL1271_DEFAULT_POWER_LEVEL; - wl->tx_blocks_available = 0; - wl->tx_results_count = 0; - wl->tx_packets_count = 0; - wl->tx_security_last_seq = 0; - wl->tx_security_seq = 0; - wl->time_offset = 0; - wl->session_counter = 0; - wl->rate_set = CONF_TX_RATE_MASK_BASIC; - wl->sta_rate_set = 0; - wl->flags = 0; - wl->vif = NULL; - wl->filters = 0; - - for (i = 0; i < NUM_TX_QUEUES; i++) - wl->tx_blocks_freed[i] = 0; - - wl1271_debugfs_reset(wl); - - kfree(wl->fw_status); - wl->fw_status = NULL; - kfree(wl->tx_res_if); - wl->tx_res_if = NULL; - kfree(wl->target_mem_map); - wl->target_mem_map = NULL; -} - -static void wl1271_op_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct wl1271 *wl = hw->priv; - - mutex_lock(&wl->mutex); - WARN_ON(wl->vif != vif); - __wl1271_op_remove_interface(wl); - mutex_unlock(&wl->mutex); - - cancel_work_sync(&wl->recovery_work); -} - -static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters) -{ - wl->rx_config = WL1271_DEFAULT_RX_CONFIG; - wl->rx_filter = WL1271_DEFAULT_RX_FILTER; - - /* combine requested filters with current filter config */ - filters = wl->filters | filters; - - wl1271_debug(DEBUG_FILTERS, "RX filters set: "); - - if (filters & FIF_PROMISC_IN_BSS) { - wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS"); - wl->rx_config &= ~CFG_UNI_FILTER_EN; - wl->rx_config |= CFG_BSSID_FILTER_EN; - } - if (filters & FIF_BCN_PRBRESP_PROMISC) { - wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC"); - wl->rx_config &= ~CFG_BSSID_FILTER_EN; - wl->rx_config &= ~CFG_SSID_FILTER_EN; - } - if (filters & FIF_OTHER_BSS) { - wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS"); - wl->rx_config &= ~CFG_BSSID_FILTER_EN; - } - if (filters & FIF_CONTROL) { - wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL"); - wl->rx_filter |= CFG_RX_CTL_EN; - } - if (filters & FIF_FCSFAIL) { - wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL"); - wl->rx_filter |= CFG_RX_FCS_ERROR; - } -} - -static int wl1271_dummy_join(struct wl1271 *wl) -{ - int ret = 0; - /* we need to use a dummy BSSID for now */ - static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde, - 0xad, 0xbe, 0xef }; - - memcpy(wl->bssid, dummy_bssid, ETH_ALEN); - - /* pass through frames from all BSS */ - wl1271_configure_filters(wl, FIF_OTHER_BSS); - - ret = wl1271_cmd_join(wl, wl->set_bss_type); - if (ret < 0) - goto out; - - set_bit(WL1271_FLAG_JOINED, &wl->flags); - -out: - return ret; -} - -static int wl1271_join(struct wl1271 *wl, bool set_assoc) -{ - int ret; - - /* - * One of the side effects of the JOIN command is that is clears - * WPA/WPA2 keys from the chipset. Performing a JOIN while associated - * to a WPA/WPA2 access point will therefore kill the data-path. - * Currently there is no supported scenario for JOIN during - * association - if it becomes a supported scenario, the WPA/WPA2 keys - * must be handled somehow. - * - */ - if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) - wl1271_info("JOIN while associated."); - - if (set_assoc) - set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags); - - ret = wl1271_cmd_join(wl, wl->set_bss_type); - if (ret < 0) - goto out; - - set_bit(WL1271_FLAG_JOINED, &wl->flags); - - if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) - goto out; - - /* - * The join command disable the keep-alive mode, shut down its process, - * and also clear the template config, so we need to reset it all after - * the join. The acx_aid starts the keep-alive process, and the order - * of the commands below is relevant. - */ - ret = wl1271_acx_keep_alive_mode(wl, true); - if (ret < 0) - goto out; - - ret = wl1271_acx_aid(wl, wl->aid); - if (ret < 0) - goto out; - - ret = wl1271_cmd_build_klv_null_data(wl); - if (ret < 0) - goto out; - - ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA, - ACX_KEEP_ALIVE_TPL_VALID); - if (ret < 0) - goto out; - -out: - return ret; -} - -static int wl1271_unjoin(struct wl1271 *wl) -{ - int ret; - - /* to stop listening to a channel, we disconnect */ - ret = wl1271_cmd_disconnect(wl); - if (ret < 0) - goto out; - - clear_bit(WL1271_FLAG_JOINED, &wl->flags); - memset(wl->bssid, 0, ETH_ALEN); - - /* stop filterting packets based on bssid */ - wl1271_configure_filters(wl, FIF_OTHER_BSS); - -out: - return ret; -} - -static void wl1271_set_band_rate(struct wl1271 *wl) -{ - if (wl->band == IEEE80211_BAND_2GHZ) - wl->basic_rate_set = wl->conf.tx.basic_rate; - else - wl->basic_rate_set = wl->conf.tx.basic_rate_5; -} - -static u32 wl1271_min_rate_get(struct wl1271 *wl) -{ - int i; - u32 rate = 0; - - if (!wl->basic_rate_set) { - WARN_ON(1); - wl->basic_rate_set = wl->conf.tx.basic_rate; - } - - for (i = 0; !rate; i++) { - if ((wl->basic_rate_set >> i) & 0x1) - rate = 1 << i; - } - - return rate; -} - -static int wl1271_handle_idle(struct wl1271 *wl, bool idle) -{ - int ret; - - if (idle) { - if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) { - ret = wl1271_unjoin(wl); - if (ret < 0) - goto out; - } - wl->rate_set = wl1271_min_rate_get(wl); - wl->sta_rate_set = 0; - ret = wl1271_acx_rate_policies(wl); - if (ret < 0) - goto out; - ret = wl1271_acx_keep_alive_config( - wl, CMD_TEMPL_KLV_IDX_NULL_DATA, - ACX_KEEP_ALIVE_TPL_INVALID); - if (ret < 0) - goto out; - set_bit(WL1271_FLAG_IDLE, &wl->flags); - } else { - /* increment the session counter */ - wl->session_counter++; - if (wl->session_counter >= SESSION_COUNTER_MAX) - wl->session_counter = 0; - ret = wl1271_dummy_join(wl); - if (ret < 0) - goto out; - clear_bit(WL1271_FLAG_IDLE, &wl->flags); - } - -out: - return ret; -} - -static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) -{ - struct wl1271 *wl = hw->priv; - struct ieee80211_conf *conf = &hw->conf; - int channel, ret = 0; - - channel = ieee80211_frequency_to_channel(conf->channel->center_freq); - - wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s", - channel, - conf->flags & IEEE80211_CONF_PS ? "on" : "off", - conf->power_level, - conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use"); - - /* - * mac80211 will go to idle nearly immediately after transmitting some - * frames, such as the deauth. To make sure those frames reach the air, - * wait here until the TX queue is fully flushed. - */ - if ((changed & IEEE80211_CONF_CHANGE_IDLE) && - (conf->flags & IEEE80211_CONF_IDLE)) - wl1271_tx_flush(wl); - - mutex_lock(&wl->mutex); - - if (unlikely(wl->state == WL1271_STATE_OFF)) { - ret = -EAGAIN; - goto out; - } - - ret = wl1271_ps_elp_wakeup(wl, false); - if (ret < 0) - goto out; - - /* if the channel changes while joined, join again */ - if (changed & IEEE80211_CONF_CHANGE_CHANNEL && - ((wl->band != conf->channel->band) || - (wl->channel != channel))) { - wl->band = conf->channel->band; - wl->channel = channel; - - /* - * FIXME: the mac80211 should really provide a fixed rate - * to use here. for now, just use the smallest possible rate - * for the band as a fixed rate for association frames and - * other control messages. - */ - if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) - wl1271_set_band_rate(wl); - - wl->basic_rate = wl1271_min_rate_get(wl); - ret = wl1271_acx_rate_policies(wl); - if (ret < 0) - wl1271_warning("rate policy for update channel " - "failed %d", ret); - - if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) { - ret = wl1271_join(wl, false); - if (ret < 0) - wl1271_warning("cmd join to update channel " - "failed %d", ret); - } - } - - if (changed & IEEE80211_CONF_CHANGE_IDLE) { - ret = wl1271_handle_idle(wl, conf->flags & IEEE80211_CONF_IDLE); - if (ret < 0) - wl1271_warning("idle mode change failed %d", ret); - } - - /* - * if mac80211 changes the PSM mode, make sure the mode is not - * incorrectly changed after the pspoll failure active window. - */ - if (changed & IEEE80211_CONF_CHANGE_PS) - clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags); - - if (conf->flags & IEEE80211_CONF_PS && - !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) { - set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags); - - /* - * We enter PSM only if we're already associated. - * If we're not, we'll enter it when joining an SSID, - * through the bss_info_changed() hook. - */ - if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) { - wl1271_debug(DEBUG_PSM, "psm enabled"); - ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, - wl->basic_rate, true); - } - } else if (!(conf->flags & IEEE80211_CONF_PS) && - test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) { - wl1271_debug(DEBUG_PSM, "psm disabled"); - - clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags); - - if (test_bit(WL1271_FLAG_PSM, &wl->flags)) - ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, - wl->basic_rate, true); - } - - if (conf->power_level != wl->power_level) { - ret = wl1271_acx_tx_power(wl, conf->power_level); - if (ret < 0) - goto out_sleep; - - wl->power_level = conf->power_level; - } - -out_sleep: - wl1271_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); - - return ret; -} - -struct wl1271_filter_params { - bool enabled; - int mc_list_length; - u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN]; -}; - -static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, - struct netdev_hw_addr_list *mc_list) -{ - struct wl1271_filter_params *fp; - struct netdev_hw_addr *ha; - struct wl1271 *wl = hw->priv; - - if (unlikely(wl->state == WL1271_STATE_OFF)) - return 0; - - fp = kzalloc(sizeof(*fp), GFP_ATOMIC); - if (!fp) { - wl1271_error("Out of memory setting filters."); - return 0; - } - - /* update multicast filtering parameters */ - fp->mc_list_length = 0; - if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) { - fp->enabled = false; - } else { - fp->enabled = true; - netdev_hw_addr_list_for_each(ha, mc_list) { - memcpy(fp->mc_list[fp->mc_list_length], - ha->addr, ETH_ALEN); - fp->mc_list_length++; - } - } - - return (u64)(unsigned long)fp; -} - -#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ - FIF_ALLMULTI | \ - FIF_FCSFAIL | \ - FIF_BCN_PRBRESP_PROMISC | \ - FIF_CONTROL | \ - FIF_OTHER_BSS) - -static void wl1271_op_configure_filter(struct ieee80211_hw *hw, - unsigned int changed, - unsigned int *total, u64 multicast) -{ - struct wl1271_filter_params *fp = (void *)(unsigned long)multicast; - struct wl1271 *wl = hw->priv; - int ret; - - wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter"); - - mutex_lock(&wl->mutex); - - *total &= WL1271_SUPPORTED_FILTERS; - changed &= WL1271_SUPPORTED_FILTERS; - - if (unlikely(wl->state == WL1271_STATE_OFF)) - goto out; - - ret = wl1271_ps_elp_wakeup(wl, false); - if (ret < 0) - goto out; - - - if (*total & FIF_ALLMULTI) - ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0); - else if (fp) - ret = wl1271_acx_group_address_tbl(wl, fp->enabled, - fp->mc_list, - fp->mc_list_length); - if (ret < 0) - goto out_sleep; - - /* determine, whether supported filter values have changed */ - if (changed == 0) - goto out_sleep; - - /* configure filters */ - wl->filters = *total; - wl1271_configure_filters(wl, 0); - - /* apply configured filters */ - ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter); - if (ret < 0) - goto out_sleep; - -out_sleep: - wl1271_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); - kfree(fp); -} - -static int wl1271_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_conf) -{ - struct wl1271 *wl = hw->priv; - const u8 *addr; - int ret; - u32 tx_seq_32 = 0; - u16 tx_seq_16 = 0; - u8 key_type; - - static const u8 bcast_addr[ETH_ALEN] = - { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - - wl1271_debug(DEBUG_MAC80211, "mac80211 set key"); - - addr = sta ? sta->addr : bcast_addr; - - wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd); - wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN); - wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x", - key_conf->cipher, key_conf->keyidx, - key_conf->keylen, key_conf->flags); - wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen); - - if (is_zero_ether_addr(addr)) { - /* We dont support TX only encryption */ - ret = -EOPNOTSUPP; - goto out; - } - - mutex_lock(&wl->mutex); - - if (unlikely(wl->state == WL1271_STATE_OFF)) { - ret = -EAGAIN; - goto out_unlock; - } - - ret = wl1271_ps_elp_wakeup(wl, false); - if (ret < 0) - goto out_unlock; - - switch (key_conf->cipher) { - case WLAN_CIPHER_SUITE_WEP40: - case WLAN_CIPHER_SUITE_WEP104: - key_type = KEY_WEP; - - key_conf->hw_key_idx = key_conf->keyidx; - break; - case WLAN_CIPHER_SUITE_TKIP: - key_type = KEY_TKIP; - - key_conf->hw_key_idx = key_conf->keyidx; - tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq); - tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq); - break; - case WLAN_CIPHER_SUITE_CCMP: - key_type = KEY_AES; - - key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; - tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq); - tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq); - break; - case WL1271_CIPHER_SUITE_GEM: - key_type = KEY_GEM; - tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq); - tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq); - break; - default: - wl1271_error("Unknown key algo 0x%x", key_conf->cipher); - - ret = -EOPNOTSUPP; - goto out_sleep; - } - - switch (cmd) { - case SET_KEY: - ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE, - key_conf->keyidx, key_type, - key_conf->keylen, key_conf->key, - addr, tx_seq_32, tx_seq_16); - if (ret < 0) { - wl1271_error("Could not add or replace key"); - goto out_sleep; - } - - /* the default WEP key needs to be configured at least once */ - if (key_type == KEY_WEP) { - ret = wl1271_cmd_set_default_wep_key(wl, - wl->default_key); - if (ret < 0) - goto out_sleep; - } - break; - - case DISABLE_KEY: - /* The wl1271 does not allow to remove unicast keys - they - will be cleared automatically on next CMD_JOIN. Ignore the - request silently, as we dont want the mac80211 to emit - an error message. */ - if (!is_broadcast_ether_addr(addr)) - break; - - ret = wl1271_cmd_set_key(wl, KEY_REMOVE, - key_conf->keyidx, key_type, - key_conf->keylen, key_conf->key, - addr, 0, 0); - if (ret < 0) { - wl1271_error("Could not remove key"); - goto out_sleep; - } - break; - - default: - wl1271_error("Unsupported key cmd 0x%x", cmd); - ret = -EOPNOTSUPP; - break; - } - -out_sleep: - wl1271_ps_elp_sleep(wl); - -out_unlock: - mutex_unlock(&wl->mutex); - -out: - return ret; -} - -static int wl1271_op_hw_scan(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct cfg80211_scan_request *req) -{ - struct wl1271 *wl = hw->priv; - int ret; - u8 *ssid = NULL; - size_t len = 0; - - wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan"); - - if (req->n_ssids) { - ssid = req->ssids[0].ssid; - len = req->ssids[0].ssid_len; - } - - mutex_lock(&wl->mutex); - - if (wl->state == WL1271_STATE_OFF) { - /* - * We cannot return -EBUSY here because cfg80211 will expect - * a call to ieee80211_scan_completed if we do - in this case - * there won't be any call. - */ - ret = -EAGAIN; - goto out; - } - - ret = wl1271_ps_elp_wakeup(wl, false); - if (ret < 0) - goto out; - - ret = wl1271_scan(hw->priv, ssid, len, req); - - wl1271_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); - - return ret; -} - -static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) -{ - struct wl1271 *wl = hw->priv; - int ret = 0; - - mutex_lock(&wl->mutex); - - if (unlikely(wl->state == WL1271_STATE_OFF)) { - ret = -EAGAIN; - goto out; - } - - ret = wl1271_ps_elp_wakeup(wl, false); - if (ret < 0) - goto out; - - ret = wl1271_acx_rts_threshold(wl, (u16) value); - if (ret < 0) - wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret); - - wl1271_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); - - return ret; -} - -static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon) -{ - u8 *ptr = beacon->data + - offsetof(struct ieee80211_mgmt, u.beacon.variable); - - /* find the location of the ssid in the beacon */ - while (ptr < beacon->data + beacon->len) { - if (ptr[0] == WLAN_EID_SSID) { - wl->ssid_len = ptr[1]; - memcpy(wl->ssid, ptr+2, wl->ssid_len); - return; - } - ptr += ptr[1]; - } - wl1271_error("ad-hoc beacon template has no SSID!\n"); -} - -static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, - u32 changed) -{ - enum wl1271_cmd_ps_mode mode; - struct wl1271 *wl = hw->priv; - struct ieee80211_sta *sta = ieee80211_find_sta(vif, bss_conf->bssid); - bool do_join = false; - bool set_assoc = false; - int ret; - - wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed"); - - mutex_lock(&wl->mutex); - - if (unlikely(wl->state == WL1271_STATE_OFF)) - goto out; - - ret = wl1271_ps_elp_wakeup(wl, false); - if (ret < 0) - goto out; - - if ((changed & BSS_CHANGED_BEACON_INT) && - (wl->bss_type == BSS_TYPE_IBSS)) { - wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d", - bss_conf->beacon_int); - - wl->beacon_int = bss_conf->beacon_int; - do_join = true; - } - - if ((changed & BSS_CHANGED_BEACON) && - (wl->bss_type == BSS_TYPE_IBSS)) { - struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); - - wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon updated"); - - if (beacon) { - struct ieee80211_hdr *hdr; - - wl1271_ssid_set(wl, beacon); - ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, - beacon->data, - beacon->len, 0, - wl1271_min_rate_get(wl)); - - if (ret < 0) { - dev_kfree_skb(beacon); - goto out_sleep; - } - - hdr = (struct ieee80211_hdr *) beacon->data; - hdr->frame_control = cpu_to_le16( - IEEE80211_FTYPE_MGMT | - IEEE80211_STYPE_PROBE_RESP); - - ret = wl1271_cmd_template_set(wl, - CMD_TEMPL_PROBE_RESPONSE, - beacon->data, - beacon->len, 0, - wl1271_min_rate_get(wl)); - dev_kfree_skb(beacon); - if (ret < 0) - goto out_sleep; - - /* Need to update the SSID (for filtering etc) */ - do_join = true; - } - } - - if ((changed & BSS_CHANGED_BEACON_ENABLED) && - (wl->bss_type == BSS_TYPE_IBSS)) { - wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s", - bss_conf->enable_beacon ? "enabled" : "disabled"); - - if (bss_conf->enable_beacon) - wl->set_bss_type = BSS_TYPE_IBSS; - else - wl->set_bss_type = BSS_TYPE_STA_BSS; - do_join = true; - } - - if (changed & BSS_CHANGED_CQM) { - bool enable = false; - if (bss_conf->cqm_rssi_thold) - enable = true; - ret = wl1271_acx_rssi_snr_trigger(wl, enable, - bss_conf->cqm_rssi_thold, - bss_conf->cqm_rssi_hyst); - if (ret < 0) - goto out; - wl->rssi_thold = bss_conf->cqm_rssi_thold; - } - - if ((changed & BSS_CHANGED_BSSID) && - /* - * Now we know the correct bssid, so we send a new join command - * and enable the BSSID filter - */ - memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) { - memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN); - - ret = wl1271_cmd_build_null_data(wl); - if (ret < 0) - goto out_sleep; - - ret = wl1271_build_qos_null_data(wl); - if (ret < 0) - goto out_sleep; - - /* filter out all packets not from this BSSID */ - wl1271_configure_filters(wl, 0); - - /* Need to update the BSSID (for filtering etc) */ - do_join = true; - } - - if (changed & BSS_CHANGED_ASSOC) { - if (bss_conf->assoc) { - u32 rates; - wl->aid = bss_conf->aid; - set_assoc = true; - - wl->ps_poll_failures = 0; - - /* - * use basic rates from AP, and determine lowest rate - * to use with control frames. - */ - rates = bss_conf->basic_rates; - wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, - rates); - wl->basic_rate = wl1271_min_rate_get(wl); - ret = wl1271_acx_rate_policies(wl); - if (ret < 0) - goto out_sleep; - - /* - * with wl1271, we don't need to update the - * beacon_int and dtim_period, because the firmware - * updates it by itself when the first beacon is - * received after a join. - */ - ret = wl1271_cmd_build_ps_poll(wl, wl->aid); - if (ret < 0) - goto out_sleep; - - /* - * The SSID is intentionally set to NULL here - the - * firmware will set the probe request with a - * broadcast SSID regardless of what we set in the - * template. - */ - ret = wl1271_cmd_build_probe_req(wl, NULL, 0, - NULL, 0, wl->band); - - /* enable the connection monitoring feature */ - ret = wl1271_acx_conn_monit_params(wl, true); - if (ret < 0) - goto out_sleep; - - /* If we want to go in PSM but we're not there yet */ - if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) && - !test_bit(WL1271_FLAG_PSM, &wl->flags)) { - mode = STATION_POWER_SAVE_MODE; - ret = wl1271_ps_set_mode(wl, mode, - wl->basic_rate, - true); - if (ret < 0) - goto out_sleep; - } - } else { - /* use defaults when not associated */ - clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags); - clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags); - wl->aid = 0; - - /* re-enable dynamic ps - just in case */ - ieee80211_enable_dyn_ps(wl->vif); - - /* revert back to minimum rates for the current band */ - wl1271_set_band_rate(wl); - wl->basic_rate = wl1271_min_rate_get(wl); - ret = wl1271_acx_rate_policies(wl); - if (ret < 0) - goto out_sleep; - - /* disable connection monitor features */ - ret = wl1271_acx_conn_monit_params(wl, false); - - /* Disable the keep-alive feature */ - ret = wl1271_acx_keep_alive_mode(wl, false); - - if (ret < 0) - goto out_sleep; - } - - } - - if (changed & BSS_CHANGED_ERP_SLOT) { - if (bss_conf->use_short_slot) - ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT); - else - ret = wl1271_acx_slot(wl, SLOT_TIME_LONG); - if (ret < 0) { - wl1271_warning("Set slot time failed %d", ret); - goto out_sleep; - } - } - - if (changed & BSS_CHANGED_ERP_PREAMBLE) { - if (bss_conf->use_short_preamble) - wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT); - else - wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG); - } - - if (changed & BSS_CHANGED_ERP_CTS_PROT) { - if (bss_conf->use_cts_prot) - ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE); - else - ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE); - if (ret < 0) { - wl1271_warning("Set ctsprotect failed %d", ret); - goto out_sleep; - } - } - - /* - * Takes care of: New association with HT enable, - * HT information change in beacon. - */ - if (sta && - (changed & BSS_CHANGED_HT) && - (bss_conf->channel_type != NL80211_CHAN_NO_HT)) { - ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true); - if (ret < 0) { - wl1271_warning("Set ht cap true failed %d", ret); - goto out_sleep; - } - ret = wl1271_acx_set_ht_information(wl, - bss_conf->ht_operation_mode); - if (ret < 0) { - wl1271_warning("Set ht information failed %d", ret); - goto out_sleep; - } - } - /* - * Takes care of: New association without HT, - * Disassociation. - */ - else if (sta && (changed & BSS_CHANGED_ASSOC)) { - ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, false); - if (ret < 0) { - wl1271_warning("Set ht cap false failed %d", ret); - goto out_sleep; - } - } - - if (changed & BSS_CHANGED_ARP_FILTER) { - __be32 addr = bss_conf->arp_addr_list[0]; - WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS); - - if (bss_conf->arp_addr_cnt == 1 && bss_conf->arp_filter_enabled) - ret = wl1271_acx_arp_ip_filter(wl, true, addr); - else - ret = wl1271_acx_arp_ip_filter(wl, false, addr); - - if (ret < 0) - goto out_sleep; - } - - if (do_join) { - ret = wl1271_join(wl, set_assoc); - if (ret < 0) { - wl1271_warning("cmd join failed %d", ret); - goto out_sleep; - } - } - -out_sleep: - wl1271_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); -} - -static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue, - const struct ieee80211_tx_queue_params *params) -{ - struct wl1271 *wl = hw->priv; - u8 ps_scheme; - int ret; - - mutex_lock(&wl->mutex); - - wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue); - - if (unlikely(wl->state == WL1271_STATE_OFF)) { - ret = -EAGAIN; - goto out; - } - - ret = wl1271_ps_elp_wakeup(wl, false); - if (ret < 0) - goto out; - - /* the txop is confed in units of 32us by the mac80211, we need us */ - ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue), - params->cw_min, params->cw_max, - params->aifs, params->txop << 5); - if (ret < 0) - goto out_sleep; - - if (params->uapsd) - ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER; - else - ps_scheme = CONF_PS_SCHEME_LEGACY; - - ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue), - CONF_CHANNEL_TYPE_EDCF, - wl1271_tx_get_queue(queue), - ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0); - if (ret < 0) - goto out_sleep; - -out_sleep: - wl1271_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); - - return ret; -} - -static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw) -{ - - struct wl1271 *wl = hw->priv; - u64 mactime = ULLONG_MAX; - int ret; - - wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf"); - - mutex_lock(&wl->mutex); - - if (unlikely(wl->state == WL1271_STATE_OFF)) - goto out; - - ret = wl1271_ps_elp_wakeup(wl, false); - if (ret < 0) - goto out; - - ret = wl1271_acx_tsf_info(wl, &mactime); - if (ret < 0) - goto out_sleep; - -out_sleep: - wl1271_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); - return mactime; -} - -static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx, - struct survey_info *survey) -{ - struct wl1271 *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_rate wl1271_rates[] = { - { .bitrate = 10, - .hw_value = CONF_HW_BIT_RATE_1MBPS, - .hw_value_short = CONF_HW_BIT_RATE_1MBPS, }, - { .bitrate = 20, - .hw_value = CONF_HW_BIT_RATE_2MBPS, - .hw_value_short = CONF_HW_BIT_RATE_2MBPS, - .flags = IEEE80211_RATE_SHORT_PREAMBLE }, - { .bitrate = 55, - .hw_value = CONF_HW_BIT_RATE_5_5MBPS, - .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS, - .flags = IEEE80211_RATE_SHORT_PREAMBLE }, - { .bitrate = 110, - .hw_value = CONF_HW_BIT_RATE_11MBPS, - .hw_value_short = CONF_HW_BIT_RATE_11MBPS, - .flags = IEEE80211_RATE_SHORT_PREAMBLE }, - { .bitrate = 60, - .hw_value = CONF_HW_BIT_RATE_6MBPS, - .hw_value_short = CONF_HW_BIT_RATE_6MBPS, }, - { .bitrate = 90, - .hw_value = CONF_HW_BIT_RATE_9MBPS, - .hw_value_short = CONF_HW_BIT_RATE_9MBPS, }, - { .bitrate = 120, - .hw_value = CONF_HW_BIT_RATE_12MBPS, - .hw_value_short = CONF_HW_BIT_RATE_12MBPS, }, - { .bitrate = 180, - .hw_value = CONF_HW_BIT_RATE_18MBPS, - .hw_value_short = CONF_HW_BIT_RATE_18MBPS, }, - { .bitrate = 240, - .hw_value = CONF_HW_BIT_RATE_24MBPS, - .hw_value_short = CONF_HW_BIT_RATE_24MBPS, }, - { .bitrate = 360, - .hw_value = CONF_HW_BIT_RATE_36MBPS, - .hw_value_short = CONF_HW_BIT_RATE_36MBPS, }, - { .bitrate = 480, - .hw_value = CONF_HW_BIT_RATE_48MBPS, - .hw_value_short = CONF_HW_BIT_RATE_48MBPS, }, - { .bitrate = 540, - .hw_value = CONF_HW_BIT_RATE_54MBPS, - .hw_value_short = CONF_HW_BIT_RATE_54MBPS, }, -}; - -/* - * Can't be const, mac80211 writes to this. The order of the channels here - * is designed to improve scanning. - */ -static struct ieee80211_channel wl1271_channels[] = { - { .hw_value = 1, .center_freq = 2412, .max_power = 25 }, - { .hw_value = 5, .center_freq = 2432, .max_power = 25 }, - { .hw_value = 9, .center_freq = 2452, .max_power = 25 }, - { .hw_value = 13, .center_freq = 2472, .max_power = 25 }, - { .hw_value = 4, .center_freq = 2427, .max_power = 25 }, - { .hw_value = 8, .center_freq = 2447, .max_power = 25 }, - { .hw_value = 12, .center_freq = 2467, .max_power = 25 }, - { .hw_value = 3, .center_freq = 2422, .max_power = 25 }, - { .hw_value = 7, .center_freq = 2442, .max_power = 25 }, - { .hw_value = 11, .center_freq = 2462, .max_power = 25 }, - { .hw_value = 2, .center_freq = 2417, .max_power = 25 }, - { .hw_value = 6, .center_freq = 2437, .max_power = 25 }, - { .hw_value = 10, .center_freq = 2457, .max_power = 25 }, -}; - -/* mapping to indexes for wl1271_rates */ -static const u8 wl1271_rate_to_idx_2ghz[] = { - /* MCS rates are used only with 11n */ - 7, /* CONF_HW_RXTX_RATE_MCS7 */ - 6, /* CONF_HW_RXTX_RATE_MCS6 */ - 5, /* CONF_HW_RXTX_RATE_MCS5 */ - 4, /* CONF_HW_RXTX_RATE_MCS4 */ - 3, /* CONF_HW_RXTX_RATE_MCS3 */ - 2, /* CONF_HW_RXTX_RATE_MCS2 */ - 1, /* CONF_HW_RXTX_RATE_MCS1 */ - 0, /* CONF_HW_RXTX_RATE_MCS0 */ - - 11, /* CONF_HW_RXTX_RATE_54 */ - 10, /* CONF_HW_RXTX_RATE_48 */ - 9, /* CONF_HW_RXTX_RATE_36 */ - 8, /* CONF_HW_RXTX_RATE_24 */ - - /* TI-specific rate */ - CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */ - - 7, /* CONF_HW_RXTX_RATE_18 */ - 6, /* CONF_HW_RXTX_RATE_12 */ - 3, /* CONF_HW_RXTX_RATE_11 */ - 5, /* CONF_HW_RXTX_RATE_9 */ - 4, /* CONF_HW_RXTX_RATE_6 */ - 2, /* CONF_HW_RXTX_RATE_5_5 */ - 1, /* CONF_HW_RXTX_RATE_2 */ - 0 /* CONF_HW_RXTX_RATE_1 */ -}; - -/* 11n STA capabilities */ -#define HW_RX_HIGHEST_RATE 72 - -#ifdef CONFIG_WL1271_HT -#define WL1271_HT_CAP { \ - .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \ - .ht_supported = true, \ - .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \ - .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \ - .mcs = { \ - .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \ - .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \ - .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \ - }, \ -} -#else -#define WL1271_HT_CAP { \ - .ht_supported = false, \ -} -#endif - -/* can't be const, mac80211 writes to this */ -static struct ieee80211_supported_band wl1271_band_2ghz = { - .channels = wl1271_channels, - .n_channels = ARRAY_SIZE(wl1271_channels), - .bitrates = wl1271_rates, - .n_bitrates = ARRAY_SIZE(wl1271_rates), - .ht_cap = WL1271_HT_CAP, -}; - -/* 5 GHz data rates for WL1273 */ -static struct ieee80211_rate wl1271_rates_5ghz[] = { - { .bitrate = 60, - .hw_value = CONF_HW_BIT_RATE_6MBPS, - .hw_value_short = CONF_HW_BIT_RATE_6MBPS, }, - { .bitrate = 90, - .hw_value = CONF_HW_BIT_RATE_9MBPS, - .hw_value_short = CONF_HW_BIT_RATE_9MBPS, }, - { .bitrate = 120, - .hw_value = CONF_HW_BIT_RATE_12MBPS, - .hw_value_short = CONF_HW_BIT_RATE_12MBPS, }, - { .bitrate = 180, - .hw_value = CONF_HW_BIT_RATE_18MBPS, - .hw_value_short = CONF_HW_BIT_RATE_18MBPS, }, - { .bitrate = 240, - .hw_value = CONF_HW_BIT_RATE_24MBPS, - .hw_value_short = CONF_HW_BIT_RATE_24MBPS, }, - { .bitrate = 360, - .hw_value = CONF_HW_BIT_RATE_36MBPS, - .hw_value_short = CONF_HW_BIT_RATE_36MBPS, }, - { .bitrate = 480, - .hw_value = CONF_HW_BIT_RATE_48MBPS, - .hw_value_short = CONF_HW_BIT_RATE_48MBPS, }, - { .bitrate = 540, - .hw_value = CONF_HW_BIT_RATE_54MBPS, - .hw_value_short = CONF_HW_BIT_RATE_54MBPS, }, -}; - -/* - * 5 GHz band channels for WL1273 - can't be const, mac80211 writes to this. - * The order of the channels here is designed to improve scanning. - */ -static struct ieee80211_channel wl1271_channels_5ghz[] = { - { .hw_value = 183, .center_freq = 4915}, - { .hw_value = 188, .center_freq = 4940}, - { .hw_value = 8, .center_freq = 5040}, - { .hw_value = 34, .center_freq = 5170}, - { .hw_value = 44, .center_freq = 5220}, - { .hw_value = 60, .center_freq = 5300}, - { .hw_value = 112, .center_freq = 5560}, - { .hw_value = 132, .center_freq = 5660}, - { .hw_value = 157, .center_freq = 5785}, - { .hw_value = 184, .center_freq = 4920}, - { .hw_value = 189, .center_freq = 4945}, - { .hw_value = 9, .center_freq = 5045}, - { .hw_value = 36, .center_freq = 5180}, - { .hw_value = 46, .center_freq = 5230}, - { .hw_value = 64, .center_freq = 5320}, - { .hw_value = 116, .center_freq = 5580}, - { .hw_value = 136, .center_freq = 5680}, - { .hw_value = 192, .center_freq = 4960}, - { .hw_value = 11, .center_freq = 5055}, - { .hw_value = 38, .center_freq = 5190}, - { .hw_value = 48, .center_freq = 5240}, - { .hw_value = 100, .center_freq = 5500}, - { .hw_value = 120, .center_freq = 5600}, - { .hw_value = 140, .center_freq = 5700}, - { .hw_value = 185, .center_freq = 4925}, - { .hw_value = 196, .center_freq = 4980}, - { .hw_value = 12, .center_freq = 5060}, - { .hw_value = 40, .center_freq = 5200}, - { .hw_value = 52, .center_freq = 5260}, - { .hw_value = 104, .center_freq = 5520}, - { .hw_value = 124, .center_freq = 5620}, - { .hw_value = 149, .center_freq = 5745}, - { .hw_value = 161, .center_freq = 5805}, - { .hw_value = 187, .center_freq = 4935}, - { .hw_value = 7, .center_freq = 5035}, - { .hw_value = 16, .center_freq = 5080}, - { .hw_value = 42, .center_freq = 5210}, - { .hw_value = 56, .center_freq = 5280}, - { .hw_value = 108, .center_freq = 5540}, - { .hw_value = 128, .center_freq = 5640}, - { .hw_value = 153, .center_freq = 5765}, - { .hw_value = 165, .center_freq = 5825}, -}; - -/* mapping to indexes for wl1271_rates_5ghz */ -static const u8 wl1271_rate_to_idx_5ghz[] = { - /* MCS rates are used only with 11n */ - 7, /* CONF_HW_RXTX_RATE_MCS7 */ - 6, /* CONF_HW_RXTX_RATE_MCS6 */ - 5, /* CONF_HW_RXTX_RATE_MCS5 */ - 4, /* CONF_HW_RXTX_RATE_MCS4 */ - 3, /* CONF_HW_RXTX_RATE_MCS3 */ - 2, /* CONF_HW_RXTX_RATE_MCS2 */ - 1, /* CONF_HW_RXTX_RATE_MCS1 */ - 0, /* CONF_HW_RXTX_RATE_MCS0 */ - - 7, /* CONF_HW_RXTX_RATE_54 */ - 6, /* CONF_HW_RXTX_RATE_48 */ - 5, /* CONF_HW_RXTX_RATE_36 */ - 4, /* CONF_HW_RXTX_RATE_24 */ - - /* TI-specific rate */ - CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */ - - 3, /* CONF_HW_RXTX_RATE_18 */ - 2, /* CONF_HW_RXTX_RATE_12 */ - CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */ - 1, /* CONF_HW_RXTX_RATE_9 */ - 0, /* CONF_HW_RXTX_RATE_6 */ - CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */ - CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */ - CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */ -}; - -static struct ieee80211_supported_band wl1271_band_5ghz = { - .channels = wl1271_channels_5ghz, - .n_channels = ARRAY_SIZE(wl1271_channels_5ghz), - .bitrates = wl1271_rates_5ghz, - .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz), - .ht_cap = WL1271_HT_CAP, -}; - -static const u8 *wl1271_band_rate_to_idx[] = { - [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz, - [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz -}; - -static const struct ieee80211_ops wl1271_ops = { - .start = wl1271_op_start, - .stop = wl1271_op_stop, - .add_interface = wl1271_op_add_interface, - .remove_interface = wl1271_op_remove_interface, - .config = wl1271_op_config, - .prepare_multicast = wl1271_op_prepare_multicast, - .configure_filter = wl1271_op_configure_filter, - .tx = wl1271_op_tx, - .set_key = wl1271_op_set_key, - .hw_scan = wl1271_op_hw_scan, - .bss_info_changed = wl1271_op_bss_info_changed, - .set_rts_threshold = wl1271_op_set_rts_threshold, - .conf_tx = wl1271_op_conf_tx, - .get_tsf = wl1271_op_get_tsf, - .get_survey = wl1271_op_get_survey, - CFG80211_TESTMODE_CMD(wl1271_tm_cmd) -}; - - -u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band) -{ - u8 idx; - - BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *)); - - if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) { - wl1271_error("Illegal RX rate from HW: %d", rate); - return 0; - } - - idx = wl1271_band_rate_to_idx[band][rate]; - if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) { - wl1271_error("Unsupported RX rate from HW: %d", rate); - return 0; - } - - return idx; -} - -static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct wl1271 *wl = dev_get_drvdata(dev); - ssize_t len; - - len = PAGE_SIZE; - - mutex_lock(&wl->mutex); - len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n", - wl->sg_enabled); - mutex_unlock(&wl->mutex); - - return len; - -} - -static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct wl1271 *wl = dev_get_drvdata(dev); - unsigned long res; - int ret; - - ret = strict_strtoul(buf, 10, &res); - - if (ret < 0) { - wl1271_warning("incorrect value written to bt_coex_mode"); - return count; - } - - mutex_lock(&wl->mutex); - - res = !!res; - - if (res == wl->sg_enabled) - goto out; - - wl->sg_enabled = res; - - if (wl->state == WL1271_STATE_OFF) - goto out; - - ret = wl1271_ps_elp_wakeup(wl, false); - if (ret < 0) - goto out; - - wl1271_acx_sg_enable(wl, wl->sg_enabled); - wl1271_ps_elp_sleep(wl); - - out: - mutex_unlock(&wl->mutex); - return count; -} - -static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR, - wl1271_sysfs_show_bt_coex_state, - wl1271_sysfs_store_bt_coex_state); - -static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct wl1271 *wl = dev_get_drvdata(dev); - ssize_t len; - - len = PAGE_SIZE; - - mutex_lock(&wl->mutex); - if (wl->hw_pg_ver >= 0) - len = snprintf(buf, len, "%d\n", wl->hw_pg_ver); - else - len = snprintf(buf, len, "n/a\n"); - mutex_unlock(&wl->mutex); - - return len; -} - -static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR, - wl1271_sysfs_show_hw_pg_ver, NULL); - -int wl1271_register_hw(struct wl1271 *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) { - wl1271_error("unable to register mac80211 hw: %d", ret); - return ret; - } - - wl->mac80211_registered = true; - - register_netdevice_notifier(&wl1271_dev_notifier); - - wl1271_notice("loaded"); - - return 0; -} -EXPORT_SYMBOL_GPL(wl1271_register_hw); - -void wl1271_unregister_hw(struct wl1271 *wl) -{ - unregister_netdevice_notifier(&wl1271_dev_notifier); - ieee80211_unregister_hw(wl->hw); - wl->mac80211_registered = false; - -} -EXPORT_SYMBOL_GPL(wl1271_unregister_hw); - -int wl1271_init_ieee80211(struct wl1271 *wl) -{ - static const u32 cipher_suites[] = { - WLAN_CIPHER_SUITE_WEP40, - WLAN_CIPHER_SUITE_WEP104, - WLAN_CIPHER_SUITE_TKIP, - WLAN_CIPHER_SUITE_CCMP, - WL1271_CIPHER_SUITE_GEM, - }; - - /* The tx descriptor buffer and the TKIP space. */ - wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE + - sizeof(struct wl1271_tx_hw_descr); - - /* unit us */ - /* FIXME: find a proper value */ - wl->hw->channel_change_time = 10000; - wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval; - - wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_BEACON_FILTER | - IEEE80211_HW_SUPPORTS_PS | - IEEE80211_HW_SUPPORTS_UAPSD | - IEEE80211_HW_HAS_RATE_CONTROL | - IEEE80211_HW_CONNECTION_MONITOR | - IEEE80211_HW_SUPPORTS_CQM_RSSI; - - wl->hw->wiphy->cipher_suites = cipher_suites; - wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); - - wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC); - wl->hw->wiphy->max_scan_ssids = 1; - wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz; - wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz; - - wl->hw->queues = 4; - wl->hw->max_rates = 1; - - SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl)); - - return 0; -} -EXPORT_SYMBOL_GPL(wl1271_init_ieee80211); - -#define WL1271_DEFAULT_CHANNEL 0 - -struct ieee80211_hw *wl1271_alloc_hw(void) -{ - struct ieee80211_hw *hw; - struct platform_device *plat_dev = NULL; - struct wl1271 *wl; - int i, ret; - unsigned int order; - - hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops); - if (!hw) { - wl1271_error("could not alloc ieee80211_hw"); - ret = -ENOMEM; - goto err_hw_alloc; - } - - plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL); - if (!plat_dev) { - wl1271_error("could not allocate platform_device"); - ret = -ENOMEM; - goto err_plat_alloc; - } - - wl = hw->priv; - memset(wl, 0, sizeof(*wl)); - - INIT_LIST_HEAD(&wl->list); - - wl->hw = hw; - wl->plat_dev = plat_dev; - - skb_queue_head_init(&wl->tx_queue); - - INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work); - INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work); - INIT_WORK(&wl->irq_work, wl1271_irq_work); - INIT_WORK(&wl->tx_work, wl1271_tx_work); - INIT_WORK(&wl->recovery_work, wl1271_recovery_work); - INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work); - wl->channel = WL1271_DEFAULT_CHANNEL; - wl->beacon_int = WL1271_DEFAULT_BEACON_INT; - wl->default_key = 0; - wl->rx_counter = 0; - wl->rx_config = WL1271_DEFAULT_RX_CONFIG; - wl->rx_filter = WL1271_DEFAULT_RX_FILTER; - wl->psm_entry_retry = 0; - wl->power_level = WL1271_DEFAULT_POWER_LEVEL; - wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC; - wl->basic_rate = CONF_TX_RATE_MASK_BASIC; - wl->rate_set = CONF_TX_RATE_MASK_BASIC; - wl->sta_rate_set = 0; - wl->band = IEEE80211_BAND_2GHZ; - wl->vif = NULL; - wl->flags = 0; - wl->sg_enabled = true; - wl->hw_pg_ver = -1; - - memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map)); - for (i = 0; i < ACX_TX_DESCRIPTORS; i++) - wl->tx_frames[i] = NULL; - - spin_lock_init(&wl->wl_lock); - - wl->state = WL1271_STATE_OFF; - mutex_init(&wl->mutex); - - /* Apply default driver configuration. */ - wl1271_conf_init(wl); - - wl1271_debugfs_init(wl); - - order = get_order(WL1271_AGGR_BUFFER_SIZE); - wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order); - if (!wl->aggr_buf) { - ret = -ENOMEM; - goto err_hw; - } - - /* Register platform device */ - ret = platform_device_register(wl->plat_dev); - if (ret) { - wl1271_error("couldn't register platform device"); - goto err_aggr; - } - dev_set_drvdata(&wl->plat_dev->dev, wl); - - /* Create sysfs file to control bt coex state */ - ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state); - if (ret < 0) { - wl1271_error("failed to create sysfs file bt_coex_state"); - goto err_platform; - } - - /* Create sysfs file to get HW PG version */ - ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver); - if (ret < 0) { - wl1271_error("failed to create sysfs file hw_pg_ver"); - goto err_bt_coex_state; - } - - return hw; - -err_bt_coex_state: - device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state); - -err_platform: - platform_device_unregister(wl->plat_dev); - -err_aggr: - free_pages((unsigned long)wl->aggr_buf, order); - -err_hw: - wl1271_debugfs_exit(wl); - kfree(plat_dev); - -err_plat_alloc: - ieee80211_free_hw(hw); - -err_hw_alloc: - - return ERR_PTR(ret); -} -EXPORT_SYMBOL_GPL(wl1271_alloc_hw); - -int wl1271_free_hw(struct wl1271 *wl) -{ - platform_device_unregister(wl->plat_dev); - free_pages((unsigned long)wl->aggr_buf, - get_order(WL1271_AGGR_BUFFER_SIZE)); - kfree(wl->plat_dev); - - wl1271_debugfs_exit(wl); - - vfree(wl->fw); - wl->fw = NULL; - kfree(wl->nvs); - wl->nvs = NULL; - - kfree(wl->fw_status); - kfree(wl->tx_res_if); - - ieee80211_free_hw(wl->hw); - - return 0; -} -EXPORT_SYMBOL_GPL(wl1271_free_hw); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Luciano Coelho "); -MODULE_AUTHOR("Juuso Oikarinen "); diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.c b/drivers/net/wireless/wl12xx/wl1271_ps.c deleted file mode 100644 index e3c332e..0000000 --- a/drivers/net/wireless/wl12xx/wl1271_ps.c +++ /dev/null @@ -1,178 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 2008-2009 Nokia Corporation - * - * Contact: Luciano Coelho - * - * 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 "wl1271_reg.h" -#include "wl1271_ps.h" -#include "wl1271_io.h" - -#define WL1271_WAKEUP_TIMEOUT 500 - -void wl1271_elp_work(struct work_struct *work) -{ - struct delayed_work *dwork; - struct wl1271 *wl; - - dwork = container_of(work, struct delayed_work, work); - wl = container_of(dwork, struct wl1271, elp_work); - - wl1271_debug(DEBUG_PSM, "elp work"); - - mutex_lock(&wl->mutex); - - if (unlikely(wl->state == WL1271_STATE_OFF)) - goto out; - - if (test_bit(WL1271_FLAG_IN_ELP, &wl->flags) || - (!test_bit(WL1271_FLAG_PSM, &wl->flags) && - !test_bit(WL1271_FLAG_IDLE, &wl->flags))) - goto out; - - wl1271_debug(DEBUG_PSM, "chip to elp"); - wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); - set_bit(WL1271_FLAG_IN_ELP, &wl->flags); - -out: - mutex_unlock(&wl->mutex); -} - -#define ELP_ENTRY_DELAY 5 - -/* Routines to toggle sleep mode while in ELP */ -void wl1271_ps_elp_sleep(struct wl1271 *wl) -{ - if (test_bit(WL1271_FLAG_PSM, &wl->flags) || - test_bit(WL1271_FLAG_IDLE, &wl->flags)) { - cancel_delayed_work(&wl->elp_work); - ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, - msecs_to_jiffies(ELP_ENTRY_DELAY)); - } -} - -int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake) -{ - DECLARE_COMPLETION_ONSTACK(compl); - unsigned long flags; - int ret; - u32 start_time = jiffies; - bool pending = false; - - if (!test_bit(WL1271_FLAG_IN_ELP, &wl->flags)) - return 0; - - wl1271_debug(DEBUG_PSM, "waking up chip from elp"); - - /* - * The spinlock is required here to synchronize both the work and - * the completion variable in one entity. - */ - spin_lock_irqsave(&wl->wl_lock, flags); - if (work_pending(&wl->irq_work) || chip_awake) - pending = true; - else - wl->elp_compl = &compl; - spin_unlock_irqrestore(&wl->wl_lock, flags); - - wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP); - - if (!pending) { - ret = wait_for_completion_timeout( - &compl, msecs_to_jiffies(WL1271_WAKEUP_TIMEOUT)); - if (ret == 0) { - wl1271_error("ELP wakeup timeout!"); - ieee80211_queue_work(wl->hw, &wl->recovery_work); - ret = -ETIMEDOUT; - goto err; - } else if (ret < 0) { - wl1271_error("ELP wakeup completion error."); - goto err; - } - } - - clear_bit(WL1271_FLAG_IN_ELP, &wl->flags); - - wl1271_debug(DEBUG_PSM, "wakeup time: %u ms", - jiffies_to_msecs(jiffies - start_time)); - goto out; - -err: - spin_lock_irqsave(&wl->wl_lock, flags); - wl->elp_compl = NULL; - spin_unlock_irqrestore(&wl->wl_lock, flags); - return ret; - -out: - return 0; -} - -int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode, - u32 rates, bool send) -{ - int ret; - - switch (mode) { - case STATION_POWER_SAVE_MODE: - wl1271_debug(DEBUG_PSM, "entering psm"); - - ret = wl1271_acx_wake_up_conditions(wl); - if (ret < 0) { - wl1271_error("couldn't set wake up conditions"); - return ret; - } - - ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE, - rates, send); - if (ret < 0) - return ret; - - set_bit(WL1271_FLAG_PSM, &wl->flags); - break; - case STATION_ACTIVE_MODE: - default: - wl1271_debug(DEBUG_PSM, "leaving psm"); - ret = wl1271_ps_elp_wakeup(wl, false); - if (ret < 0) - return ret; - - /* disable beacon early termination */ - ret = wl1271_acx_bet_enable(wl, false); - if (ret < 0) - return ret; - - /* disable beacon filtering */ - ret = wl1271_acx_beacon_filter_opt(wl, false); - if (ret < 0) - return ret; - - ret = wl1271_cmd_ps_mode(wl, STATION_ACTIVE_MODE, - rates, send); - if (ret < 0) - return ret; - - clear_bit(WL1271_FLAG_PSM, &wl->flags); - break; - } - - return ret; -} - - diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.h b/drivers/net/wireless/wl12xx/wl1271_ps.h deleted file mode 100644 index 6ba7b03..0000000 --- a/drivers/net/wireless/wl12xx/wl1271_ps.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 2008-2009 Nokia Corporation - * - * Contact: Luciano Coelho - * - * 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 __WL1271_PS_H__ -#define __WL1271_PS_H__ - -#include "wl1271.h" -#include "wl1271_acx.h" - -int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode, - u32 rates, bool send); -void wl1271_ps_elp_sleep(struct wl1271 *wl); -int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake); -void wl1271_elp_work(struct work_struct *work); - -#endif /* __WL1271_PS_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1271_reg.h b/drivers/net/wireless/wl12xx/wl1271_reg.h deleted file mode 100644 index 9909607..0000000 --- a/drivers/net/wireless/wl12xx/wl1271_reg.h +++ /dev/null @@ -1,614 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. - * Copyright (C) 2009 Nokia Corporation - * - * Contact: Luciano Coelho - * - * 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 -#define FW_STATUS_ADDR (0x14FC0 + 0xA000) - -/* 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 - -/*=============================================== - 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. -===============================================*/ -#define ACX_REG_SLV_SOFT_RESET (REGISTERS_BASE + 0x0000) - -#define WL1271_SLV_REG_DATA (REGISTERS_BASE + 0x0008) -#define WL1271_SLV_REG_ADATA (REGISTERS_BASE + 0x000c) -#define WL1271_SLV_MEM_DATA (REGISTERS_BASE + 0x0018) - -#define ACX_REG_INTERRUPT_TRIG (REGISTERS_BASE + 0x0474) -#define ACX_REG_INTERRUPT_TRIG_H (REGISTERS_BASE + 0x0478) - -/*============================================= - 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 -*==============================================*/ -#define ACX_REG_INTERRUPT_MASK (REGISTERS_BASE + 0x04DC) - -/*============================================= - 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). -==============================================*/ -#define ACX_REG_HINT_MASK_SET (REGISTERS_BASE + 0x04E0) - -/*============================================= - 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). -=============================================*/ -#define ACX_REG_HINT_MASK_CLR (REGISTERS_BASE + 0x04E4) - -/*============================================= - 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. -=============================================*/ -#define ACX_REG_INTERRUPT_NO_CLEAR (REGISTERS_BASE + 0x04E8) - -/*============================================= - 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. -==============================================*/ -#define ACX_REG_INTERRUPT_CLEAR (REGISTERS_BASE + 0x04F8) - -/*============================================= - 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) -==============================================*/ -#define ACX_REG_INTERRUPT_ACK (REGISTERS_BASE + 0x04F0) - -#define RX_DRIVER_COUNTER_ADDRESS (REGISTERS_BASE + 0x0538) - -/* Device Configuration registers*/ -#define SOR_CFG (REGISTERS_BASE + 0x0800) - -/* 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 - ===============================================*/ -#define ACX_REG_ECPU_CONTROL (REGISTERS_BASE + 0x0804) - -#define HI_CFG (REGISTERS_BASE + 0x0808) - -/*=============================================== - 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 -*================================================*/ -#define ACX_REG_EE_START (REGISTERS_BASE + 0x080C) - -#define OCP_POR_CTR (REGISTERS_BASE + 0x09B4) -#define OCP_DATA_WRITE (REGISTERS_BASE + 0x09B8) -#define OCP_DATA_READ (REGISTERS_BASE + 0x09BC) -#define OCP_CMD (REGISTERS_BASE + 0x09C0) - -#define WL1271_HOST_WR_ACCESS (REGISTERS_BASE + 0x09F8) - -#define CHIP_ID_B (REGISTERS_BASE + 0x5674) - -#define CHIP_ID_1271_PG10 (0x4030101) -#define CHIP_ID_1271_PG20 (0x4030111) - -#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) - -#define PLL_PARAMETERS (REGISTERS_BASE + 0x6040) -#define WU_COUNTER_PAUSE (REGISTERS_BASE + 0x6008) -#define WELP_ARM_COMMAND (REGISTERS_BASE + 0x6100) -#define DRPW_SCRATCH_START (DRPW_BASE + 0x002C) - - -#define ACX_SLV_SOFT_RESET_BIT BIT(1) -#define ACX_REG_EEPROM_START_BIT BIT(1) - -/* 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 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 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 ACX_EE_DATA_REG EE_DATA - -/*=============================================== - 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 -}; - -#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/wl1271_rx.c b/drivers/net/wireless/wl12xx/wl1271_rx.c deleted file mode 100644 index cacfee5..0000000 --- a/drivers/net/wireless/wl12xx/wl1271_rx.c +++ /dev/null @@ -1,203 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 2009 Nokia Corporation - * - * Contact: Luciano Coelho - * - * 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 "wl1271.h" -#include "wl1271_acx.h" -#include "wl1271_reg.h" -#include "wl1271_rx.h" -#include "wl1271_io.h" - -static u8 wl1271_rx_get_mem_block(struct wl1271_fw_status *status, - u32 drv_rx_counter) -{ - return le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) & - RX_MEM_BLOCK_MASK; -} - -static u32 wl1271_rx_get_buf_size(struct wl1271_fw_status *status, - u32 drv_rx_counter) -{ - return (le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) & - RX_BUF_SIZE_MASK) >> RX_BUF_SIZE_SHIFT_DIV; -} - -static void wl1271_rx_status(struct wl1271 *wl, - struct wl1271_rx_descriptor *desc, - struct ieee80211_rx_status *status, - u8 beacon) -{ - enum ieee80211_band desc_band; - - memset(status, 0, sizeof(struct ieee80211_rx_status)); - - status->band = wl->band; - - if ((desc->flags & WL1271_RX_DESC_BAND_MASK) == WL1271_RX_DESC_BAND_BG) - desc_band = IEEE80211_BAND_2GHZ; - else - desc_band = IEEE80211_BAND_5GHZ; - - status->rate_idx = wl1271_rate_to_idx(desc->rate, desc_band); - -#ifdef CONFIG_WL1271_HT - /* 11n support */ - if (desc->rate <= CONF_HW_RXTX_RATE_MCS0) - status->flag |= RX_FLAG_HT; -#endif - - status->signal = desc->rssi; - - /* - * FIXME: In wl1251, the SNR should be divided by two. In wl1271 we - * need to divide by two for now, but TI has been discussing about - * changing it. This needs to be rechecked. - */ - wl->noise = desc->rssi - (desc->snr >> 1); - - status->freq = ieee80211_channel_to_frequency(desc->channel); - - if (desc->flags & WL1271_RX_DESC_ENCRYPT_MASK) { - status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; - - if (likely(!(desc->status & WL1271_RX_DESC_DECRYPT_FAIL))) - status->flag |= RX_FLAG_DECRYPTED; - if (unlikely(desc->status & WL1271_RX_DESC_MIC_FAIL)) - status->flag |= RX_FLAG_MMIC_ERROR; - } -} - -static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length) -{ - struct wl1271_rx_descriptor *desc; - struct sk_buff *skb; - u16 *fc; - u8 *buf; - u8 beacon = 0; - - /* - * In PLT mode we seem to get frames and mac80211 warns about them, - * workaround this by not retrieving them at all. - */ - if (unlikely(wl->state == WL1271_STATE_PLT)) - return -EINVAL; - - skb = __dev_alloc_skb(length, GFP_KERNEL); - if (!skb) { - wl1271_error("Couldn't allocate RX frame"); - return -ENOMEM; - } - - buf = skb_put(skb, length); - memcpy(buf, data, length); - - /* the data read starts with the descriptor */ - desc = (struct wl1271_rx_descriptor *) buf; - - /* now we pull the descriptor out of the buffer */ - skb_pull(skb, sizeof(*desc)); - - fc = (u16 *)skb->data; - if ((*fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) - beacon = 1; - - wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon); - - wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len, - beacon ? "beacon" : ""); - - skb_trim(skb, skb->len - desc->pad_len); - - ieee80211_rx_ni(wl->hw, skb); - - return 0; -} - -void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status) -{ - struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map; - u32 buf_size; - u32 fw_rx_counter = status->fw_rx_counter & NUM_RX_PKT_DESC_MOD_MASK; - u32 drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK; - u32 rx_counter; - u32 mem_block; - u32 pkt_length; - u32 pkt_offset; - - while (drv_rx_counter != fw_rx_counter) { - buf_size = 0; - rx_counter = drv_rx_counter; - while (rx_counter != fw_rx_counter) { - pkt_length = wl1271_rx_get_buf_size(status, rx_counter); - if (buf_size + pkt_length > WL1271_AGGR_BUFFER_SIZE) - break; - buf_size += pkt_length; - rx_counter++; - rx_counter &= NUM_RX_PKT_DESC_MOD_MASK; - } - - if (buf_size == 0) { - wl1271_warning("received empty data"); - break; - } - - /* - * Choose the block we want to read - * For aggregated packets, only the first memory block should - * be retrieved. The FW takes care of the rest. - */ - mem_block = wl1271_rx_get_mem_block(status, drv_rx_counter); - wl->rx_mem_pool_addr.addr = (mem_block << 8) + - le32_to_cpu(wl_mem_map->packet_memory_pool_start); - wl->rx_mem_pool_addr.addr_extra = - wl->rx_mem_pool_addr.addr + 4; - wl1271_write(wl, WL1271_SLV_REG_DATA, &wl->rx_mem_pool_addr, - sizeof(wl->rx_mem_pool_addr), false); - - /* Read all available packets at once */ - wl1271_read(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, - buf_size, true); - - /* Split data into separate packets */ - pkt_offset = 0; - while (pkt_offset < buf_size) { - pkt_length = wl1271_rx_get_buf_size(status, - drv_rx_counter); - /* - * the handle data call can only fail in memory-outage - * conditions, in that case the received frame will just - * be dropped. - */ - wl1271_rx_handle_data(wl, - wl->aggr_buf + pkt_offset, - pkt_length); - wl->rx_counter++; - drv_rx_counter++; - drv_rx_counter &= NUM_RX_PKT_DESC_MOD_MASK; - pkt_offset += pkt_length; - } - } - wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, - cpu_to_le32(wl->rx_counter)); -} diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.h b/drivers/net/wireless/wl12xx/wl1271_rx.h deleted file mode 100644 index 6d41981..0000000 --- a/drivers/net/wireless/wl12xx/wl1271_rx.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. - * Copyright (C) 2008-2009 Nokia Corporation - * - * Contact: Luciano Coelho - * - * 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 __WL1271_RX_H__ -#define __WL1271_RX_H__ - -#include - -#define WL1271_RX_MAX_RSSI -30 -#define WL1271_RX_MIN_RSSI -95 - -#define WL1271_RX_ALIGN_TO 4 -#define WL1271_RX_ALIGN(len) (((len) + WL1271_RX_ALIGN_TO - 1) & \ - ~(WL1271_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 NUM_RX_PKT_DESC_MOD_MASK 7 - -#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 - -/* - * RX Descriptor flags: - * - * Bits 0-1 - band - * Bit 2 - STBC - * Bit 3 - A-MPDU - * Bit 4 - HT - * Bits 5-7 - encryption - */ -#define WL1271_RX_DESC_BAND_MASK 0x03 -#define WL1271_RX_DESC_ENCRYPT_MASK 0xE0 - -#define WL1271_RX_DESC_BAND_BG 0x00 -#define WL1271_RX_DESC_BAND_J 0x01 -#define WL1271_RX_DESC_BAND_A 0x02 - -#define WL1271_RX_DESC_STBC BIT(2) -#define WL1271_RX_DESC_A_MPDU BIT(3) -#define WL1271_RX_DESC_HT BIT(4) - -#define WL1271_RX_DESC_ENCRYPT_WEP 0x20 -#define WL1271_RX_DESC_ENCRYPT_TKIP 0x40 -#define WL1271_RX_DESC_ENCRYPT_AES 0x60 -#define WL1271_RX_DESC_ENCRYPT_GEM 0x80 - -/* - * RX Descriptor status - * - * Bits 0-2 - status - * Bits 3-7 - reserved - */ -#define WL1271_RX_DESC_STATUS_MASK 0x07 - -#define WL1271_RX_DESC_SUCCESS 0x00 -#define WL1271_RX_DESC_DECRYPT_FAIL 0x01 -#define WL1271_RX_DESC_MIC_FAIL 0x02 -#define WL1271_RX_DESC_DRIVER_RX_Q_FAIL 0x03 - -#define RX_MEM_BLOCK_MASK 0xFF -#define RX_BUF_SIZE_MASK 0xFFF00 -#define RX_BUF_SIZE_SHIFT_DIV 6 - -struct wl1271_rx_descriptor { - __le16 length; - u8 status; - u8 flags; - u8 rate; - u8 channel; - s8 rssi; - u8 snr; - __le32 timestamp; - u8 packet_class; - u8 process_id; - u8 pad_len; - u8 reserved; -} __packed; - -void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status); -u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band); - -#endif diff --git a/drivers/net/wireless/wl12xx/wl1271_scan.c b/drivers/net/wireless/wl12xx/wl1271_scan.c deleted file mode 100644 index e0661a5..0000000 --- a/drivers/net/wireless/wl12xx/wl1271_scan.c +++ /dev/null @@ -1,307 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 2009-2010 Nokia Corporation - * - * Contact: Luciano Coelho - * - * 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 "wl1271.h" -#include "wl1271_cmd.h" -#include "wl1271_scan.h" -#include "wl1271_acx.h" - -void wl1271_scan_complete_work(struct work_struct *work) -{ - struct delayed_work *dwork; - struct wl1271 *wl; - - dwork = container_of(work, struct delayed_work, work); - wl = container_of(dwork, struct wl1271, scan_complete_work); - - wl1271_debug(DEBUG_SCAN, "Scanning complete"); - - mutex_lock(&wl->mutex); - - if (wl->scan.state == WL1271_SCAN_STATE_IDLE) { - mutex_unlock(&wl->mutex); - return; - } - - wl->scan.state = WL1271_SCAN_STATE_IDLE; - kfree(wl->scan.scanned_ch); - wl->scan.scanned_ch = NULL; - wl->scan.req = NULL; - ieee80211_scan_completed(wl->hw, false); - - if (wl->scan.failed) { - wl1271_info("Scan completed due to error."); - ieee80211_queue_work(wl->hw, &wl->recovery_work); - } - mutex_unlock(&wl->mutex); - -} - - -static int wl1271_get_scan_channels(struct wl1271 *wl, - struct cfg80211_scan_request *req, - struct basic_scan_channel_params *channels, - enum ieee80211_band band, bool passive) -{ - struct conf_scan_settings *c = &wl->conf.scan; - int i, j; - u32 flags; - - for (i = 0, j = 0; - i < req->n_channels && j < WL1271_SCAN_MAX_CHANNELS; - i++) { - - flags = req->channels[i]->flags; - - if (!wl->scan.scanned_ch[i] && - !(flags & IEEE80211_CHAN_DISABLED) && - ((!!(flags & IEEE80211_CHAN_PASSIVE_SCAN)) == passive) && - (req->channels[i]->band == band)) { - - wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ", - req->channels[i]->band, - req->channels[i]->center_freq); - wl1271_debug(DEBUG_SCAN, "hw_value %d, flags %X", - req->channels[i]->hw_value, - req->channels[i]->flags); - wl1271_debug(DEBUG_SCAN, - "max_antenna_gain %d, max_power %d", - req->channels[i]->max_antenna_gain, - req->channels[i]->max_power); - wl1271_debug(DEBUG_SCAN, "beacon_found %d", - req->channels[i]->beacon_found); - - if (!passive) { - channels[j].min_duration = - cpu_to_le32(c->min_dwell_time_active); - channels[j].max_duration = - cpu_to_le32(c->max_dwell_time_active); - } else { - channels[j].min_duration = - cpu_to_le32(c->min_dwell_time_passive); - channels[j].max_duration = - cpu_to_le32(c->max_dwell_time_passive); - } - channels[j].early_termination = 0; - channels[j].tx_power_att = req->channels[i]->max_power; - channels[j].channel = req->channels[i]->hw_value; - - memset(&channels[j].bssid_lsb, 0xff, 4); - memset(&channels[j].bssid_msb, 0xff, 2); - - /* Mark the channels we already used */ - wl->scan.scanned_ch[i] = true; - - j++; - } - } - - return j; -} - -#define WL1271_NOTHING_TO_SCAN 1 - -static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band, - bool passive, u32 basic_rate) -{ - struct wl1271_cmd_scan *cmd; - struct wl1271_cmd_trigger_scan_to *trigger; - int ret; - u16 scan_options = 0; - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - trigger = kzalloc(sizeof(*trigger), GFP_KERNEL); - if (!cmd || !trigger) { - ret = -ENOMEM; - goto out; - } - - /* We always use high priority scans */ - scan_options = WL1271_SCAN_OPT_PRIORITY_HIGH; - - /* No SSIDs means that we have a forced passive scan */ - if (passive || wl->scan.req->n_ssids == 0) - scan_options |= WL1271_SCAN_OPT_PASSIVE; - - cmd->params.scan_options = cpu_to_le16(scan_options); - - cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req, - cmd->channels, - band, passive); - if (cmd->params.n_ch == 0) { - ret = WL1271_NOTHING_TO_SCAN; - goto out; - } - - cmd->params.tx_rate = cpu_to_le32(basic_rate); - 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.n_probe_reqs = wl->conf.scan.num_probe_reqs; - cmd->params.tx_rate = cpu_to_le32(basic_rate); - cmd->params.tid_trigger = 0; - cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG; - - if (band == IEEE80211_BAND_2GHZ) - cmd->params.band = WL1271_SCAN_BAND_2_4_GHZ; - else - cmd->params.band = WL1271_SCAN_BAND_5_GHZ; - - if (wl->scan.ssid_len && wl->scan.ssid) { - cmd->params.ssid_len = wl->scan.ssid_len; - memcpy(cmd->params.ssid, wl->scan.ssid, wl->scan.ssid_len); - } - - ret = wl1271_cmd_build_probe_req(wl, wl->scan.ssid, wl->scan.ssid_len, - wl->scan.req->ie, wl->scan.req->ie_len, - band); - if (ret < 0) { - wl1271_error("PROBE request template failed"); - goto out; - } - - /* disable the timeout */ - trigger->timeout = 0; - ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, - sizeof(*trigger), 0); - if (ret < 0) { - wl1271_error("trigger scan to failed for hw scan"); - goto out; - } - - wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd)); - - ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_error("SCAN failed"); - goto out; - } - -out: - kfree(cmd); - kfree(trigger); - return ret; -} - -void wl1271_scan_stm(struct wl1271 *wl) -{ - int ret = 0; - - switch (wl->scan.state) { - case WL1271_SCAN_STATE_IDLE: - break; - - case WL1271_SCAN_STATE_2GHZ_ACTIVE: - ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, false, - wl->conf.tx.basic_rate); - if (ret == WL1271_NOTHING_TO_SCAN) { - wl->scan.state = WL1271_SCAN_STATE_2GHZ_PASSIVE; - wl1271_scan_stm(wl); - } - - break; - - case WL1271_SCAN_STATE_2GHZ_PASSIVE: - ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, true, - wl->conf.tx.basic_rate); - if (ret == WL1271_NOTHING_TO_SCAN) { - if (wl->enable_11a) - wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE; - else - wl->scan.state = WL1271_SCAN_STATE_DONE; - wl1271_scan_stm(wl); - } - - break; - - case WL1271_SCAN_STATE_5GHZ_ACTIVE: - ret = wl1271_scan_send(wl, IEEE80211_BAND_5GHZ, false, - wl->conf.tx.basic_rate_5); - if (ret == WL1271_NOTHING_TO_SCAN) { - wl->scan.state = WL1271_SCAN_STATE_5GHZ_PASSIVE; - wl1271_scan_stm(wl); - } - - break; - - case WL1271_SCAN_STATE_5GHZ_PASSIVE: - ret = wl1271_scan_send(wl, IEEE80211_BAND_5GHZ, true, - wl->conf.tx.basic_rate_5); - if (ret == WL1271_NOTHING_TO_SCAN) { - wl->scan.state = WL1271_SCAN_STATE_DONE; - wl1271_scan_stm(wl); - } - - break; - - case WL1271_SCAN_STATE_DONE: - wl->scan.failed = false; - cancel_delayed_work(&wl->scan_complete_work); - ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, - msecs_to_jiffies(0)); - break; - - default: - wl1271_error("invalid scan state"); - break; - } - - if (ret < 0) { - cancel_delayed_work(&wl->scan_complete_work); - ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, - msecs_to_jiffies(0)); - } -} - -int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, - struct cfg80211_scan_request *req) -{ - if (wl->scan.state != WL1271_SCAN_STATE_IDLE) - return -EBUSY; - - wl->scan.state = WL1271_SCAN_STATE_2GHZ_ACTIVE; - - if (ssid_len && ssid) { - wl->scan.ssid_len = ssid_len; - memcpy(wl->scan.ssid, ssid, ssid_len); - } else { - wl->scan.ssid_len = 0; - } - - wl->scan.req = req; - - wl->scan.scanned_ch = kcalloc(req->n_channels, - sizeof(*wl->scan.scanned_ch), - GFP_KERNEL); - /* we assume failure so that timeout scenarios are handled correctly */ - wl->scan.failed = true; - ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, - msecs_to_jiffies(WL1271_SCAN_TIMEOUT)); - - wl1271_scan_stm(wl); - - return 0; -} diff --git a/drivers/net/wireless/wl12xx/wl1271_scan.h b/drivers/net/wireless/wl12xx/wl1271_scan.h deleted file mode 100644 index 6d57127..0000000 --- a/drivers/net/wireless/wl12xx/wl1271_scan.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 2009-2010 Nokia Corporation - * - * Contact: Luciano Coelho - * - * 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 __WL1271_SCAN_H__ -#define __WL1271_SCAN_H__ - -#include "wl1271.h" - -int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, - struct cfg80211_scan_request *req); -int wl1271_scan_build_probe_req(struct wl1271 *wl, - const u8 *ssid, size_t ssid_len, - const u8 *ie, size_t ie_len, u8 band); -void wl1271_scan_stm(struct wl1271 *wl); -void wl1271_scan_complete_work(struct work_struct *work); - -#define WL1271_SCAN_MAX_CHANNELS 24 -#define WL1271_SCAN_DEFAULT_TAG 1 -#define WL1271_SCAN_CURRENT_TX_PWR 0 -#define WL1271_SCAN_OPT_ACTIVE 0 -#define WL1271_SCAN_OPT_PASSIVE 1 -#define WL1271_SCAN_OPT_PRIORITY_HIGH 4 -#define WL1271_SCAN_BAND_2_4_GHZ 0 -#define WL1271_SCAN_BAND_5_GHZ 1 - -#define WL1271_SCAN_TIMEOUT 10000 /* msec */ - -enum { - WL1271_SCAN_STATE_IDLE, - WL1271_SCAN_STATE_2GHZ_ACTIVE, - WL1271_SCAN_STATE_2GHZ_PASSIVE, - WL1271_SCAN_STATE_5GHZ_ACTIVE, - WL1271_SCAN_STATE_5GHZ_PASSIVE, - WL1271_SCAN_STATE_DONE -}; - -struct basic_scan_params { - __le32 rx_config_options; - __le32 rx_filter_options; - /* Scan option flags (WL1271_SCAN_OPT_*) */ - __le16 scan_options; - /* Number of scan channels in the list (maximum 30) */ - u8 n_ch; - /* This field indicates the number of probe requests to send - per channel for an active scan */ - u8 n_probe_reqs; - /* Rate bit field for sending the probes */ - __le32 tx_rate; - u8 tid_trigger; - u8 ssid_len; - /* in order to align */ - u8 padding1[2]; - u8 ssid[IW_ESSID_MAX_SIZE]; - /* Band to scan */ - u8 band; - u8 use_ssid_list; - u8 scan_tag; - u8 padding2; -} __packed; - -struct basic_scan_channel_params { - /* Duration in TU to wait for frames on a channel for active scan */ - __le32 min_duration; - __le32 max_duration; - __le32 bssid_lsb; - __le16 bssid_msb; - u8 early_termination; - u8 tx_power_att; - u8 channel; - /* FW internal use only! */ - u8 dfs_candidate; - u8 activity_detected; - u8 pad; -} __packed; - -struct wl1271_cmd_scan { - struct wl1271_cmd_header header; - - struct basic_scan_params params; - struct basic_scan_channel_params channels[WL1271_SCAN_MAX_CHANNELS]; -} __packed; - -struct wl1271_cmd_trigger_scan_to { - struct wl1271_cmd_header header; - - __le32 timeout; -} __packed; - -#endif /* __WL1271_SCAN_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1271_sdio.c b/drivers/net/wireless/wl12xx/wl1271_sdio.c deleted file mode 100644 index 784ef34..0000000 --- a/drivers/net/wireless/wl12xx/wl1271_sdio.c +++ /dev/null @@ -1,347 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 2009-2010 Nokia Corporation - * - * Contact: Luciano Coelho - * - * 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 - -#include "wl1271.h" -#include "wl12xx_80211.h" -#include "wl1271_io.h" - -#ifndef SDIO_VENDOR_ID_TI -#define SDIO_VENDOR_ID_TI 0x0097 -#endif - -#ifndef SDIO_DEVICE_ID_TI_WL1271 -#define SDIO_DEVICE_ID_TI_WL1271 0x4076 -#endif - -static const struct sdio_device_id wl1271_devices[] = { - { SDIO_DEVICE(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271) }, - {} -}; -MODULE_DEVICE_TABLE(sdio, wl1271_devices); - -static inline struct sdio_func *wl_to_func(struct wl1271 *wl) -{ - return wl->if_priv; -} - -static struct device *wl1271_sdio_wl_to_dev(struct wl1271 *wl) -{ - return &(wl_to_func(wl)->dev); -} - -static irqreturn_t wl1271_irq(int irq, void *cookie) -{ - struct wl1271 *wl = cookie; - unsigned long flags; - - wl1271_debug(DEBUG_IRQ, "IRQ"); - - /* complete the ELP completion */ - spin_lock_irqsave(&wl->wl_lock, flags); - if (wl->elp_compl) { - complete(wl->elp_compl); - wl->elp_compl = NULL; - } - - if (!test_and_set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags)) - ieee80211_queue_work(wl->hw, &wl->irq_work); - set_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags); - spin_unlock_irqrestore(&wl->wl_lock, flags); - - return IRQ_HANDLED; -} - -static void wl1271_sdio_disable_interrupts(struct wl1271 *wl) -{ - disable_irq(wl->irq); -} - -static void wl1271_sdio_enable_interrupts(struct wl1271 *wl) -{ - enable_irq(wl->irq); -} - -static void wl1271_sdio_reset(struct wl1271 *wl) -{ -} - -static void wl1271_sdio_init(struct wl1271 *wl) -{ -} - -static void wl1271_sdio_raw_read(struct wl1271 *wl, int addr, void *buf, - size_t len, bool fixed) -{ - int ret; - struct sdio_func *func = wl_to_func(wl); - - sdio_claim_host(func); - - if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) { - ((u8 *)buf)[0] = sdio_f0_readb(func, addr, &ret); - wl1271_debug(DEBUG_SDIO, "sdio read 52 addr 0x%x, byte 0x%02x", - addr, ((u8 *)buf)[0]); - } else { - if (fixed) - ret = sdio_readsb(func, buf, addr, len); - else - ret = sdio_memcpy_fromio(func, buf, addr, len); - - wl1271_debug(DEBUG_SDIO, "sdio read 53 addr 0x%x, %zu bytes", - addr, len); - wl1271_dump_ascii(DEBUG_SDIO, "data: ", buf, len); - } - - sdio_release_host(func); - - if (ret) - wl1271_error("sdio read failed (%d)", ret); -} - -static void wl1271_sdio_raw_write(struct wl1271 *wl, int addr, void *buf, - size_t len, bool fixed) -{ - int ret; - struct sdio_func *func = wl_to_func(wl); - - sdio_claim_host(func); - - if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) { - sdio_f0_writeb(func, ((u8 *)buf)[0], addr, &ret); - wl1271_debug(DEBUG_SDIO, "sdio write 52 addr 0x%x, byte 0x%02x", - addr, ((u8 *)buf)[0]); - } else { - wl1271_debug(DEBUG_SDIO, "sdio write 53 addr 0x%x, %zu bytes", - addr, len); - wl1271_dump_ascii(DEBUG_SDIO, "data: ", buf, len); - - if (fixed) - ret = sdio_writesb(func, addr, buf, len); - else - ret = sdio_memcpy_toio(func, addr, buf, len); - } - - sdio_release_host(func); - - if (ret) - wl1271_error("sdio write failed (%d)", ret); -} - -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); - -out: - return ret; -} - -static int wl1271_sdio_power_off(struct wl1271 *wl) -{ - struct sdio_func *func = wl_to_func(wl); - - sdio_claim_host(func); - sdio_disable_func(func); - sdio_release_host(func); - - /* Power down the card */ - return pm_runtime_put_sync(&func->dev); -} - -static int wl1271_sdio_set_power(struct wl1271 *wl, bool enable) -{ - if (enable) - return wl1271_sdio_power_on(wl); - else - return wl1271_sdio_power_off(wl); -} - -static struct wl1271_if_operations sdio_ops = { - .read = wl1271_sdio_raw_read, - .write = wl1271_sdio_raw_write, - .reset = wl1271_sdio_reset, - .init = wl1271_sdio_init, - .power = wl1271_sdio_set_power, - .dev = wl1271_sdio_wl_to_dev, - .enable_irq = wl1271_sdio_enable_interrupts, - .disable_irq = wl1271_sdio_disable_interrupts -}; - -static int __devinit wl1271_probe(struct sdio_func *func, - const struct sdio_device_id *id) -{ - struct ieee80211_hw *hw; - const struct wl12xx_platform_data *wlan_data; - struct wl1271 *wl; - int ret; - - /* We are only able to handle the wlan function */ - if (func->num != 0x02) - return -ENODEV; - - hw = wl1271_alloc_hw(); - if (IS_ERR(hw)) - return PTR_ERR(hw); - - wl = hw->priv; - - wl->if_priv = func; - wl->if_ops = &sdio_ops; - - /* Grab access to FN0 for ELP reg. */ - func->card->quirks |= MMC_QUIRK_LENIENT_FN0; - - wlan_data = wl12xx_get_platform_data(); - if (IS_ERR(wlan_data)) { - ret = PTR_ERR(wlan_data); - wl1271_error("missing wlan platform data: %d", ret); - goto out_free; - } - - wl->irq = wlan_data->irq; - wl->ref_clock = wlan_data->board_ref_clock; - - ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl); - if (ret < 0) { - wl1271_error("request_irq() failed: %d", ret); - goto out_free; - } - - set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); - - disable_irq(wl->irq); - - ret = wl1271_init_ieee80211(wl); - if (ret) - goto out_irq; - - ret = wl1271_register_hw(wl); - if (ret) - goto out_irq; - - 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; - - out_irq: - free_irq(wl->irq, wl); - - - out_free: - wl1271_free_hw(wl); - - return ret; -} - -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); -} - -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) -{ - int ret; - - ret = sdio_register_driver(&wl1271_sdio_driver); - if (ret < 0) { - wl1271_error("failed to register sdio driver: %d", ret); - goto out; - } - -out: - return ret; -} - -static void __exit wl1271_exit(void) -{ - sdio_unregister_driver(&wl1271_sdio_driver); - - wl1271_notice("unloaded"); -} - -module_init(wl1271_init); -module_exit(wl1271_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Luciano Coelho "); -MODULE_AUTHOR("Juuso Oikarinen "); -MODULE_FIRMWARE(WL1271_FW_NAME); diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.c b/drivers/net/wireless/wl12xx/wl1271_spi.c deleted file mode 100644 index ef80168..0000000 --- a/drivers/net/wireless/wl12xx/wl1271_spi.c +++ /dev/null @@ -1,498 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 2008-2009 Nokia Corporation - * - * Contact: Luciano Coelho - * - * 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 "wl1271.h" -#include "wl12xx_80211.h" -#include "wl1271_io.h" - -#include "wl1271_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 \ - ((WL1271_BUSY_WORD_LEN - 4) / sizeof(u32)) -#define HW_ACCESS_WSPI_INIT_CMD_MASK 0 - -/* HW limitation: maximum possible chunk size is 4095 bytes */ -#define WSPI_MAX_CHUNK_SIZE 4092 - -#define WSPI_MAX_NUM_OF_CHUNKS (WL1271_AGGR_BUFFER_SIZE / WSPI_MAX_CHUNK_SIZE) - -static inline struct spi_device *wl_to_spi(struct wl1271 *wl) -{ - return wl->if_priv; -} - -static struct device *wl1271_spi_wl_to_dev(struct wl1271 *wl) -{ - return &(wl_to_spi(wl)->dev); -} - -static void wl1271_spi_disable_interrupts(struct wl1271 *wl) -{ - disable_irq(wl->irq); -} - -static void wl1271_spi_enable_interrupts(struct wl1271 *wl) -{ - enable_irq(wl->irq); -} - -static void wl1271_spi_reset(struct wl1271 *wl) -{ - u8 *cmd; - struct spi_transfer t; - struct spi_message m; - - cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); - if (!cmd) { - wl1271_error("could not allocate cmd for spi reset"); - 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); - kfree(cmd); - - wl1271_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); -} - -static void wl1271_spi_init(struct wl1271 *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) { - wl1271_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); - wl1271_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN); - kfree(cmd); -} - -#define WL1271_BUSY_WORD_TIMEOUT 1000 - -static int wl1271_spi_read_busy(struct wl1271 *wl) -{ - struct spi_transfer t[1]; - struct spi_message m; - u32 *busy_buf; - int num_busy_bytes = 0; - - /* - * Read further busy words from SPI until a non-busy word is - * encountered, then read the data itself into the buffer. - */ - - num_busy_bytes = WL1271_BUSY_WORD_TIMEOUT; - busy_buf = wl->buffer_busyword; - while (num_busy_bytes) { - num_busy_bytes--; - spi_message_init(&m); - memset(t, 0, sizeof(t)); - t[0].rx_buf = busy_buf; - t[0].len = sizeof(u32); - t[0].cs_change = true; - spi_message_add_tail(&t[0], &m); - spi_sync(wl_to_spi(wl), &m); - - if (*busy_buf & 0x1) - return 0; - } - - /* The SPI bus is unresponsive, the read failed. */ - wl1271_error("SPI read busy-word timeout!\n"); - return -ETIMEDOUT; -} - -static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf, - size_t len, bool fixed) -{ - struct spi_transfer t[2]; - struct spi_message m; - u32 *busy_buf; - u32 *cmd; - u32 chunk_len; - - while (len > 0) { - chunk_len = min((size_t)WSPI_MAX_CHUNK_SIZE, len); - - cmd = &wl->buffer_cmd; - busy_buf = wl->buffer_busyword; - - *cmd = 0; - *cmd |= WSPI_CMD_READ; - *cmd |= (chunk_len << WSPI_CMD_BYTE_LENGTH_OFFSET) & - WSPI_CMD_BYTE_LENGTH; - *cmd |= addr & WSPI_CMD_BYTE_ADDR; - - if (fixed) - *cmd |= WSPI_CMD_FIXED; - - spi_message_init(&m); - memset(t, 0, sizeof(t)); - - t[0].tx_buf = cmd; - t[0].len = 4; - t[0].cs_change = true; - spi_message_add_tail(&t[0], &m); - - /* Busy and non busy words read */ - t[1].rx_buf = busy_buf; - t[1].len = WL1271_BUSY_WORD_LEN; - t[1].cs_change = true; - spi_message_add_tail(&t[1], &m); - - spi_sync(wl_to_spi(wl), &m); - - if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1) && - wl1271_spi_read_busy(wl)) { - memset(buf, 0, chunk_len); - return; - } - - spi_message_init(&m); - memset(t, 0, sizeof(t)); - - t[0].rx_buf = buf; - t[0].len = chunk_len; - t[0].cs_change = true; - spi_message_add_tail(&t[0], &m); - - spi_sync(wl_to_spi(wl), &m); - - wl1271_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd)); - wl1271_dump(DEBUG_SPI, "spi_read buf <- ", buf, chunk_len); - - if (!fixed) - addr += chunk_len; - buf += chunk_len; - len -= chunk_len; - } -} - -static void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf, - size_t len, bool fixed) -{ - struct spi_transfer t[2 * WSPI_MAX_NUM_OF_CHUNKS]; - struct spi_message m; - u32 commands[WSPI_MAX_NUM_OF_CHUNKS]; - u32 *cmd; - u32 chunk_len; - int i; - - WARN_ON(len > WL1271_AGGR_BUFFER_SIZE); - - spi_message_init(&m); - memset(t, 0, sizeof(t)); - - cmd = &commands[0]; - i = 0; - while (len > 0) { - chunk_len = min((size_t)WSPI_MAX_CHUNK_SIZE, len); - - *cmd = 0; - *cmd |= WSPI_CMD_WRITE; - *cmd |= (chunk_len << WSPI_CMD_BYTE_LENGTH_OFFSET) & - WSPI_CMD_BYTE_LENGTH; - *cmd |= addr & WSPI_CMD_BYTE_ADDR; - - if (fixed) - *cmd |= WSPI_CMD_FIXED; - - t[i].tx_buf = cmd; - t[i].len = sizeof(*cmd); - spi_message_add_tail(&t[i++], &m); - - t[i].tx_buf = buf; - t[i].len = chunk_len; - spi_message_add_tail(&t[i++], &m); - - wl1271_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); - wl1271_dump(DEBUG_SPI, "spi_write buf -> ", buf, chunk_len); - - if (!fixed) - addr += chunk_len; - buf += chunk_len; - len -= chunk_len; - cmd++; - } - - spi_sync(wl_to_spi(wl), &m); -} - -static irqreturn_t wl1271_irq(int irq, void *cookie) -{ - struct wl1271 *wl; - unsigned long flags; - - wl1271_debug(DEBUG_IRQ, "IRQ"); - - wl = cookie; - - /* complete the ELP completion */ - spin_lock_irqsave(&wl->wl_lock, flags); - if (wl->elp_compl) { - complete(wl->elp_compl); - wl->elp_compl = NULL; - } - - if (!test_and_set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags)) - ieee80211_queue_work(wl->hw, &wl->irq_work); - set_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags); - spin_unlock_irqrestore(&wl->wl_lock, flags); - - return IRQ_HANDLED; -} - -static int wl1271_spi_set_power(struct wl1271 *wl, bool enable) -{ - if (wl->set_power) - wl->set_power(enable); - - return 0; -} - -static struct wl1271_if_operations spi_ops = { - .read = wl1271_spi_raw_read, - .write = wl1271_spi_raw_write, - .reset = wl1271_spi_reset, - .init = wl1271_spi_init, - .power = wl1271_spi_set_power, - .dev = wl1271_spi_wl_to_dev, - .enable_irq = wl1271_spi_enable_interrupts, - .disable_irq = wl1271_spi_disable_interrupts -}; - -static int __devinit wl1271_probe(struct spi_device *spi) -{ - struct wl12xx_platform_data *pdata; - struct ieee80211_hw *hw; - struct wl1271 *wl; - int ret; - - pdata = spi->dev.platform_data; - if (!pdata) { - wl1271_error("no platform data"); - return -ENODEV; - } - - hw = wl1271_alloc_hw(); - if (IS_ERR(hw)) - return PTR_ERR(hw); - - wl = hw->priv; - - dev_set_drvdata(&spi->dev, wl); - wl->if_priv = spi; - - wl->if_ops = &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) { - wl1271_error("spi_setup failed"); - goto out_free; - } - - wl->set_power = pdata->set_power; - if (!wl->set_power) { - wl1271_error("set power function missing in platform data"); - ret = -ENODEV; - goto out_free; - } - - wl->ref_clock = pdata->board_ref_clock; - - wl->irq = spi->irq; - if (wl->irq < 0) { - wl1271_error("irq missing in platform data"); - ret = -ENODEV; - goto out_free; - } - - ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl); - if (ret < 0) { - wl1271_error("request_irq() failed: %d", ret); - goto out_free; - } - - set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); - - disable_irq(wl->irq); - - ret = wl1271_init_ieee80211(wl); - if (ret) - goto out_irq; - - ret = wl1271_register_hw(wl); - if (ret) - goto out_irq; - - wl1271_notice("initialized"); - - return 0; - - out_irq: - free_irq(wl->irq, wl); - - out_free: - wl1271_free_hw(wl); - - return ret; -} - -static int __devexit wl1271_remove(struct spi_device *spi) -{ - struct wl1271 *wl = dev_get_drvdata(&spi->dev); - - wl1271_unregister_hw(wl); - free_irq(wl->irq, wl); - wl1271_free_hw(wl); - - return 0; -} - - -static struct spi_driver wl1271_spi_driver = { - .driver = { - .name = "wl1271_spi", - .bus = &spi_bus_type, - .owner = THIS_MODULE, - }, - - .probe = wl1271_probe, - .remove = __devexit_p(wl1271_remove), -}; - -static int __init wl1271_init(void) -{ - int ret; - - ret = spi_register_driver(&wl1271_spi_driver); - if (ret < 0) { - wl1271_error("failed to register spi driver: %d", ret); - goto out; - } - -out: - return ret; -} - -static void __exit wl1271_exit(void) -{ - spi_unregister_driver(&wl1271_spi_driver); - - wl1271_notice("unloaded"); -} - -module_init(wl1271_init); -module_exit(wl1271_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Luciano Coelho "); -MODULE_AUTHOR("Juuso Oikarinen "); -MODULE_FIRMWARE(WL1271_FW_NAME); -MODULE_ALIAS("spi:wl1271"); diff --git a/drivers/net/wireless/wl12xx/wl1271_testmode.c b/drivers/net/wireless/wl12xx/wl1271_testmode.c deleted file mode 100644 index 55ec442..0000000 --- a/drivers/net/wireless/wl12xx/wl1271_testmode.c +++ /dev/null @@ -1,290 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 2010 Nokia Corporation - * - * Contact: Luciano Coelho - * - * 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 "wl1271_testmode.h" - -#include -#include - -#include "wl1271.h" -#include "wl1271_acx.h" - -#define WL1271_TM_MAX_DATA_LENGTH 1024 - -enum wl1271_tm_commands { - WL1271_TM_CMD_UNSPEC, - WL1271_TM_CMD_TEST, - WL1271_TM_CMD_INTERROGATE, - WL1271_TM_CMD_CONFIGURE, - WL1271_TM_CMD_NVS_PUSH, - WL1271_TM_CMD_SET_PLT_MODE, - WL1271_TM_CMD_RECOVER, - - __WL1271_TM_CMD_AFTER_LAST -}; -#define WL1271_TM_CMD_MAX (__WL1271_TM_CMD_AFTER_LAST - 1) - -enum wl1271_tm_attrs { - WL1271_TM_ATTR_UNSPEC, - WL1271_TM_ATTR_CMD_ID, - WL1271_TM_ATTR_ANSWER, - WL1271_TM_ATTR_DATA, - WL1271_TM_ATTR_IE_ID, - WL1271_TM_ATTR_PLT_MODE, - - __WL1271_TM_ATTR_AFTER_LAST -}; -#define WL1271_TM_ATTR_MAX (__WL1271_TM_ATTR_AFTER_LAST - 1) - -static struct nla_policy wl1271_tm_policy[WL1271_TM_ATTR_MAX + 1] = { - [WL1271_TM_ATTR_CMD_ID] = { .type = NLA_U32 }, - [WL1271_TM_ATTR_ANSWER] = { .type = NLA_U8 }, - [WL1271_TM_ATTR_DATA] = { .type = NLA_BINARY, - .len = WL1271_TM_MAX_DATA_LENGTH }, - [WL1271_TM_ATTR_IE_ID] = { .type = NLA_U32 }, - [WL1271_TM_ATTR_PLT_MODE] = { .type = NLA_U32 }, -}; - - -static int wl1271_tm_cmd_test(struct wl1271 *wl, struct nlattr *tb[]) -{ - int buf_len, ret, len; - struct sk_buff *skb; - void *buf; - u8 answer = 0; - - wl1271_debug(DEBUG_TESTMODE, "testmode cmd test"); - - if (!tb[WL1271_TM_ATTR_DATA]) - return -EINVAL; - - buf = nla_data(tb[WL1271_TM_ATTR_DATA]); - buf_len = nla_len(tb[WL1271_TM_ATTR_DATA]); - - if (tb[WL1271_TM_ATTR_ANSWER]) - answer = nla_get_u8(tb[WL1271_TM_ATTR_ANSWER]); - - if (buf_len > sizeof(struct wl1271_command)) - return -EMSGSIZE; - - mutex_lock(&wl->mutex); - ret = wl1271_cmd_test(wl, buf, buf_len, answer); - mutex_unlock(&wl->mutex); - - if (ret < 0) { - wl1271_warning("testmode cmd test failed: %d", ret); - return ret; - } - - if (answer) { - len = nla_total_size(buf_len); - skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, len); - if (!skb) - return -ENOMEM; - - NLA_PUT(skb, WL1271_TM_ATTR_DATA, buf_len, buf); - ret = cfg80211_testmode_reply(skb); - if (ret < 0) - return ret; - } - - return 0; - -nla_put_failure: - kfree_skb(skb); - return -EMSGSIZE; -} - -static int wl1271_tm_cmd_interrogate(struct wl1271 *wl, struct nlattr *tb[]) -{ - int ret; - struct wl1271_command *cmd; - struct sk_buff *skb; - u8 ie_id; - - wl1271_debug(DEBUG_TESTMODE, "testmode cmd interrogate"); - - if (!tb[WL1271_TM_ATTR_IE_ID]) - return -EINVAL; - - ie_id = nla_get_u8(tb[WL1271_TM_ATTR_IE_ID]); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) - return -ENOMEM; - - mutex_lock(&wl->mutex); - ret = wl1271_cmd_interrogate(wl, ie_id, cmd, sizeof(*cmd)); - mutex_unlock(&wl->mutex); - - if (ret < 0) { - wl1271_warning("testmode cmd interrogate failed: %d", ret); - return ret; - } - - skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, sizeof(*cmd)); - if (!skb) - return -ENOMEM; - - NLA_PUT(skb, WL1271_TM_ATTR_DATA, sizeof(*cmd), cmd); - - return 0; - -nla_put_failure: - kfree_skb(skb); - return -EMSGSIZE; -} - -static int wl1271_tm_cmd_configure(struct wl1271 *wl, struct nlattr *tb[]) -{ - int buf_len, ret; - void *buf; - u8 ie_id; - - wl1271_debug(DEBUG_TESTMODE, "testmode cmd configure"); - - if (!tb[WL1271_TM_ATTR_DATA]) - return -EINVAL; - if (!tb[WL1271_TM_ATTR_IE_ID]) - return -EINVAL; - - ie_id = nla_get_u8(tb[WL1271_TM_ATTR_IE_ID]); - buf = nla_data(tb[WL1271_TM_ATTR_DATA]); - buf_len = nla_len(tb[WL1271_TM_ATTR_DATA]); - - if (buf_len > sizeof(struct wl1271_command)) - return -EMSGSIZE; - - mutex_lock(&wl->mutex); - ret = wl1271_cmd_configure(wl, ie_id, buf, buf_len); - mutex_unlock(&wl->mutex); - - if (ret < 0) { - wl1271_warning("testmode cmd configure failed: %d", ret); - return ret; - } - - return 0; -} - -static int wl1271_tm_cmd_nvs_push(struct wl1271 *wl, struct nlattr *tb[]) -{ - int ret = 0; - size_t len; - void *buf; - - wl1271_debug(DEBUG_TESTMODE, "testmode cmd nvs push"); - - if (!tb[WL1271_TM_ATTR_DATA]) - return -EINVAL; - - buf = nla_data(tb[WL1271_TM_ATTR_DATA]); - len = nla_len(tb[WL1271_TM_ATTR_DATA]); - - mutex_lock(&wl->mutex); - - kfree(wl->nvs); - - wl->nvs = kzalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL); - if (!wl->nvs) { - wl1271_error("could not allocate memory for the nvs file"); - ret = -ENOMEM; - goto out; - } - - memcpy(wl->nvs, buf, len); - wl->nvs_len = len; - - wl1271_debug(DEBUG_TESTMODE, "testmode pushed nvs"); - -out: - mutex_unlock(&wl->mutex); - - return ret; -} - -static int wl1271_tm_cmd_set_plt_mode(struct wl1271 *wl, struct nlattr *tb[]) -{ - u32 val; - int ret; - - wl1271_debug(DEBUG_TESTMODE, "testmode cmd set plt mode"); - - if (!tb[WL1271_TM_ATTR_PLT_MODE]) - return -EINVAL; - - val = nla_get_u32(tb[WL1271_TM_ATTR_PLT_MODE]); - - switch (val) { - case 0: - ret = wl1271_plt_stop(wl); - break; - case 1: - ret = wl1271_plt_start(wl); - break; - default: - ret = -EINVAL; - break; - } - - return ret; -} - -static int wl1271_tm_cmd_recover(struct wl1271 *wl, struct nlattr *tb[]) -{ - wl1271_debug(DEBUG_TESTMODE, "testmode cmd recover"); - - ieee80211_queue_work(wl->hw, &wl->recovery_work); - - return 0; -} - -int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len) -{ - struct wl1271 *wl = hw->priv; - struct nlattr *tb[WL1271_TM_ATTR_MAX + 1]; - int err; - - err = nla_parse(tb, WL1271_TM_ATTR_MAX, data, len, wl1271_tm_policy); - if (err) - return err; - - if (!tb[WL1271_TM_ATTR_CMD_ID]) - return -EINVAL; - - switch (nla_get_u32(tb[WL1271_TM_ATTR_CMD_ID])) { - case WL1271_TM_CMD_TEST: - return wl1271_tm_cmd_test(wl, tb); - case WL1271_TM_CMD_INTERROGATE: - return wl1271_tm_cmd_interrogate(wl, tb); - case WL1271_TM_CMD_CONFIGURE: - return wl1271_tm_cmd_configure(wl, tb); - case WL1271_TM_CMD_NVS_PUSH: - return wl1271_tm_cmd_nvs_push(wl, tb); - case WL1271_TM_CMD_SET_PLT_MODE: - return wl1271_tm_cmd_set_plt_mode(wl, tb); - case WL1271_TM_CMD_RECOVER: - return wl1271_tm_cmd_recover(wl, tb); - default: - return -EOPNOTSUPP; - } -} diff --git a/drivers/net/wireless/wl12xx/wl1271_testmode.h b/drivers/net/wireless/wl12xx/wl1271_testmode.h deleted file mode 100644 index c196d28..0000000 --- a/drivers/net/wireless/wl12xx/wl1271_testmode.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 2010 Nokia Corporation - * - * Contact: Luciano Coelho - * - * 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 __WL1271_TESTMODE_H__ -#define __WL1271_TESTMODE_H__ - -#include - -int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len); - -#endif /* __WL1271_TESTMODE_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c deleted file mode 100644 index 279be5b..0000000 --- a/drivers/net/wireless/wl12xx/wl1271_tx.c +++ /dev/null @@ -1,485 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 2009 Nokia Corporation - * - * Contact: Luciano Coelho - * - * 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 "wl1271.h" -#include "wl1271_io.h" -#include "wl1271_reg.h" -#include "wl1271_ps.h" -#include "wl1271_tx.h" - -static int wl1271_alloc_tx_id(struct wl1271 *wl, struct sk_buff *skb) -{ - int id; - - id = find_first_zero_bit(wl->tx_frames_map, ACX_TX_DESCRIPTORS); - if (id >= ACX_TX_DESCRIPTORS) - return -EBUSY; - - __set_bit(id, wl->tx_frames_map); - wl->tx_frames[id] = skb; - wl->tx_frames_cnt++; - return id; -} - -static void wl1271_free_tx_id(struct wl1271 *wl, int id) -{ - if (__test_and_clear_bit(id, wl->tx_frames_map)) { - wl->tx_frames[id] = NULL; - wl->tx_frames_cnt--; - } -} - -static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, - u32 buf_offset) -{ - struct wl1271_tx_hw_descr *desc; - u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra; - u32 total_blocks; - int id, ret = -EBUSY; - - if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE) - return -EAGAIN; - - /* allocate free identifier for the packet */ - id = wl1271_alloc_tx_id(wl, skb); - if (id < 0) - return id; - - /* approximate the number of blocks required for this packet - in the firmware */ - total_blocks = total_len + TX_HW_BLOCK_SIZE - 1; - total_blocks = total_blocks / TX_HW_BLOCK_SIZE + TX_HW_BLOCK_SPARE; - if (total_blocks <= wl->tx_blocks_available) { - desc = (struct wl1271_tx_hw_descr *)skb_push( - skb, total_len - skb->len); - - desc->extra_mem_blocks = TX_HW_BLOCK_SPARE; - desc->total_mem_blocks = total_blocks; - desc->id = id; - - wl->tx_blocks_available -= total_blocks; - - ret = 0; - - wl1271_debug(DEBUG_TX, - "tx_allocate: size: %d, blocks: %d, id: %d", - total_len, total_blocks, id); - } else { - wl1271_free_tx_id(wl, id); - } - - return ret; -} - -static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, - u32 extra, struct ieee80211_tx_info *control) -{ - struct timespec ts; - struct wl1271_tx_hw_descr *desc; - int pad, ac; - s64 hosttime; - u16 tx_attr; - - desc = (struct wl1271_tx_hw_descr *) skb->data; - - /* relocate space for security header */ - if (extra) { - void *framestart = skb->data + sizeof(*desc); - u16 fc = *(u16 *)(framestart + extra); - int hdrlen = ieee80211_hdrlen(cpu_to_le16(fc)); - memmove(framestart, framestart + extra, hdrlen); - } - - /* configure packet life time */ - getnstimeofday(&ts); - hosttime = (timespec_to_ns(&ts) >> 10); - desc->start_time = cpu_to_le32(hosttime - wl->time_offset); - desc->life_time = cpu_to_le16(TX_HW_MGMT_PKT_LIFETIME_TU); - - /* configure the tx attributes */ - tx_attr = wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER; - - /* queue (we use same identifiers for tid's and ac's */ - ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); - desc->tid = ac; - - desc->aid = TX_HW_DEFAULT_AID; - desc->reserved = 0; - - /* align the length (and store in terms of words) */ - pad = WL1271_TX_ALIGN(skb->len); - desc->length = cpu_to_le16(pad >> 2); - - /* calculate number of padding bytes */ - pad = pad - skb->len; - tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD; - - /* if the packets are destined for AP (have a STA entry) send them - with AP rate policies, otherwise use default basic rates */ - if (control->control.sta) - tx_attr |= ACX_TX_AP_FULL_RATE << TX_HW_ATTR_OFST_RATE_POLICY; - - desc->tx_attr = cpu_to_le16(tx_attr); - - wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d", pad); -} - -/* caller must hold wl->mutex */ -static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, - u32 buf_offset) -{ - struct ieee80211_tx_info *info; - u32 extra = 0; - int ret = 0; - u8 idx; - u32 total_len; - - if (!skb) - return -EINVAL; - - info = IEEE80211_SKB_CB(skb); - - if (info->control.hw_key && - info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) - extra = WL1271_TKIP_IV_SPACE; - - if (info->control.hw_key) { - idx = info->control.hw_key->hw_key_idx; - - /* FIXME: do we have to do this if we're not using WEP? */ - if (unlikely(wl->default_key != idx)) { - ret = wl1271_cmd_set_default_wep_key(wl, idx); - if (ret < 0) - return ret; - wl->default_key = idx; - } - } - - ret = wl1271_tx_allocate(wl, skb, extra, buf_offset); - if (ret < 0) - return ret; - - wl1271_tx_fill_hdr(wl, skb, extra, info); - - /* - * The length of each packet is stored in terms of words. Thus, we must - * pad the skb data to make sure its length is aligned. - * The number of padding bytes is computed and set in wl1271_tx_fill_hdr - */ - total_len = WL1271_TX_ALIGN(skb->len); - memcpy(wl->aggr_buf + buf_offset, skb->data, skb->len); - memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len); - - return total_len; -} - -u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set) -{ - struct ieee80211_supported_band *band; - u32 enabled_rates = 0; - int bit; - - band = wl->hw->wiphy->bands[wl->band]; - for (bit = 0; bit < band->n_bitrates; bit++) { - if (rate_set & 0x1) - enabled_rates |= band->bitrates[bit].hw_value; - rate_set >>= 1; - } - -#ifdef CONFIG_WL1271_HT - /* MCS rates indication are on bits 16 - 23 */ - rate_set >>= HW_HT_RATES_OFFSET - band->n_bitrates; - - for (bit = 0; bit < 8; bit++) { - if (rate_set & 0x1) - enabled_rates |= (CONF_HW_BIT_RATE_MCS_0 << bit); - rate_set >>= 1; - } -#endif - - return enabled_rates; -} - -static void handle_tx_low_watermark(struct wl1271 *wl) -{ - unsigned long flags; - - if (test_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags) && - skb_queue_len(&wl->tx_queue) <= WL1271_TX_QUEUE_LOW_WATERMARK) { - /* firmware buffer has space, restart queues */ - spin_lock_irqsave(&wl->wl_lock, flags); - ieee80211_wake_queues(wl->hw); - clear_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags); - spin_unlock_irqrestore(&wl->wl_lock, flags); - } -} - -void wl1271_tx_work_locked(struct wl1271 *wl) -{ - struct sk_buff *skb; - bool woken_up = false; - u32 sta_rates = 0; - u32 buf_offset = 0; - bool sent_packets = false; - int ret; - - /* check if the rates supported by the AP have changed */ - if (unlikely(test_and_clear_bit(WL1271_FLAG_STA_RATES_CHANGED, - &wl->flags))) { - unsigned long flags; - - spin_lock_irqsave(&wl->wl_lock, flags); - sta_rates = wl->sta_rate_set; - spin_unlock_irqrestore(&wl->wl_lock, flags); - } - - if (unlikely(wl->state == WL1271_STATE_OFF)) - goto out; - - /* if rates have changed, re-configure the rate policy */ - if (unlikely(sta_rates)) { - ret = wl1271_ps_elp_wakeup(wl, false); - if (ret < 0) - goto out; - woken_up = true; - - wl->rate_set = wl1271_tx_enabled_rates_get(wl, sta_rates); - wl1271_acx_rate_policies(wl); - } - - while ((skb = skb_dequeue(&wl->tx_queue))) { - if (!woken_up) { - ret = wl1271_ps_elp_wakeup(wl, false); - if (ret < 0) - goto out_ack; - woken_up = true; - } - - ret = wl1271_prepare_tx_frame(wl, skb, buf_offset); - if (ret == -EAGAIN) { - /* - * Aggregation buffer is full. - * Flush buffer and try again. - */ - skb_queue_head(&wl->tx_queue, skb); - wl1271_write(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, - buf_offset, true); - sent_packets = true; - buf_offset = 0; - continue; - } else if (ret == -EBUSY) { - /* - * Firmware buffer is full. - * Queue back last skb, and stop aggregating. - */ - skb_queue_head(&wl->tx_queue, skb); - /* No work left, avoid scheduling redundant tx work */ - set_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); - goto out_ack; - } else if (ret < 0) { - dev_kfree_skb(skb); - goto out_ack; - } - buf_offset += ret; - wl->tx_packets_count++; - } - -out_ack: - if (buf_offset) { - wl1271_write(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, - buf_offset, true); - sent_packets = true; - } - if (sent_packets) { - /* interrupt the firmware with the new packets */ - wl1271_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count); - handle_tx_low_watermark(wl); - } - -out: - if (woken_up) - wl1271_ps_elp_sleep(wl); -} - -void wl1271_tx_work(struct work_struct *work) -{ - struct wl1271 *wl = container_of(work, struct wl1271, tx_work); - - mutex_lock(&wl->mutex); - wl1271_tx_work_locked(wl); - mutex_unlock(&wl->mutex); -} - -static void wl1271_tx_complete_packet(struct wl1271 *wl, - struct wl1271_tx_hw_res_descr *result) -{ - struct ieee80211_tx_info *info; - struct sk_buff *skb; - int id = result->id; - int rate = -1; - u8 retries = 0; - - /* check for id legality */ - if (unlikely(id >= ACX_TX_DESCRIPTORS || wl->tx_frames[id] == NULL)) { - wl1271_warning("TX result illegal id: %d", id); - return; - } - - skb = wl->tx_frames[id]; - info = IEEE80211_SKB_CB(skb); - - /* update the TX status info */ - if (result->status == TX_SUCCESS) { - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) - info->flags |= IEEE80211_TX_STAT_ACK; - rate = wl1271_rate_to_idx(result->rate_class_index, wl->band); - retries = result->ack_failures; - } else if (result->status == TX_RETRY_EXCEEDED) { - wl->stats.excessive_retries++; - retries = result->ack_failures; - } - - info->status.rates[0].idx = rate; - info->status.rates[0].count = retries; - info->status.rates[0].flags = 0; - info->status.ack_signal = -1; - - wl->stats.retry_count += result->ack_failures; - - /* update security sequence number */ - wl->tx_security_seq += (result->lsb_security_sequence_number - - wl->tx_security_last_seq); - wl->tx_security_last_seq = result->lsb_security_sequence_number; - - /* remove private header from packet */ - skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); - - /* remove TKIP header space if present */ - if (info->control.hw_key && - info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) { - int hdrlen = ieee80211_get_hdrlen_from_skb(skb); - memmove(skb->data + WL1271_TKIP_IV_SPACE, skb->data, hdrlen); - skb_pull(skb, WL1271_TKIP_IV_SPACE); - } - - wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x" - " status 0x%x", - result->id, skb, result->ack_failures, - result->rate_class_index, result->status); - - /* return the packet to the stack */ - ieee80211_tx_status(wl->hw, skb); - wl1271_free_tx_id(wl, result->id); -} - -/* Called upon reception of a TX complete interrupt */ -void wl1271_tx_complete(struct wl1271 *wl) -{ - struct wl1271_acx_mem_map *memmap = - (struct wl1271_acx_mem_map *)wl->target_mem_map; - u32 count, fw_counter; - u32 i; - - /* read the tx results from the chipset */ - wl1271_read(wl, le32_to_cpu(memmap->tx_result), - wl->tx_res_if, sizeof(*wl->tx_res_if), false); - fw_counter = le32_to_cpu(wl->tx_res_if->tx_result_fw_counter); - - /* write host counter to chipset (to ack) */ - wl1271_write32(wl, le32_to_cpu(memmap->tx_result) + - offsetof(struct wl1271_tx_hw_res_if, - tx_result_host_counter), fw_counter); - - count = fw_counter - wl->tx_results_count; - wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count); - - /* verify that the result buffer is not getting overrun */ - if (unlikely(count > TX_HW_RESULT_QUEUE_LEN)) - wl1271_warning("TX result overflow from chipset: %d", count); - - /* process the results */ - for (i = 0; i < count; i++) { - struct wl1271_tx_hw_res_descr *result; - u8 offset = wl->tx_results_count & TX_HW_RESULT_QUEUE_LEN_MASK; - - /* process the packet */ - result = &(wl->tx_res_if->tx_results_queue[offset]); - wl1271_tx_complete_packet(wl, result); - - wl->tx_results_count++; - } -} - -/* caller must hold wl->mutex */ -void wl1271_tx_reset(struct wl1271 *wl) -{ - int i; - struct sk_buff *skb; - - /* TX failure */ - while ((skb = skb_dequeue(&wl->tx_queue))) { - wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb); - ieee80211_tx_status(wl->hw, skb); - } - - /* - * Make sure the driver is at a consistent state, in case this - * function is called from a context other than interface removal. - */ - handle_tx_low_watermark(wl); - - for (i = 0; i < ACX_TX_DESCRIPTORS; i++) - if (wl->tx_frames[i] != NULL) { - skb = wl->tx_frames[i]; - wl1271_free_tx_id(wl, i); - wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb); - ieee80211_tx_status(wl->hw, skb); - } -} - -#define WL1271_TX_FLUSH_TIMEOUT 500000 - -/* caller must *NOT* hold wl->mutex */ -void wl1271_tx_flush(struct wl1271 *wl) -{ - unsigned long timeout; - timeout = jiffies + usecs_to_jiffies(WL1271_TX_FLUSH_TIMEOUT); - - while (!time_after(jiffies, timeout)) { - mutex_lock(&wl->mutex); - wl1271_debug(DEBUG_TX, "flushing tx buffer: %d", - wl->tx_frames_cnt); - if ((wl->tx_frames_cnt == 0) && - skb_queue_empty(&wl->tx_queue)) { - mutex_unlock(&wl->mutex); - return; - } - mutex_unlock(&wl->mutex); - msleep(1); - } - - wl1271_warning("Unable to flush all TX buffers, timed out."); -} diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.h b/drivers/net/wireless/wl12xx/wl1271_tx.h deleted file mode 100644 index 9dc6f22..0000000 --- a/drivers/net/wireless/wl12xx/wl1271_tx.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. - * Copyright (C) 2009 Nokia Corporation - * - * Contact: Luciano Coelho - * - * 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 __WL1271_TX_H__ -#define __WL1271_TX_H__ - -#define TX_HW_BLOCK_SPARE 2 -#define TX_HW_BLOCK_SIZE 252 - -#define TX_HW_MGMT_PKT_LIFETIME_TU 2000 -/* The chipset reference driver states, that the "aid" value 1 - * is for infra-BSS, but is still always used */ -#define TX_HW_DEFAULT_AID 1 - -#define TX_HW_ATTR_SAVE_RETRIES BIT(0) -#define TX_HW_ATTR_HEADER_PAD BIT(1) -#define TX_HW_ATTR_SESSION_COUNTER (BIT(2) | BIT(3) | BIT(4)) -#define TX_HW_ATTR_RATE_POLICY (BIT(5) | BIT(6) | BIT(7) | \ - BIT(8) | BIT(9)) -#define TX_HW_ATTR_LAST_WORD_PAD (BIT(10) | BIT(11)) -#define TX_HW_ATTR_TX_CMPLT_REQ BIT(12) - -#define TX_HW_ATTR_OFST_SAVE_RETRIES 0 -#define TX_HW_ATTR_OFST_HEADER_PAD 1 -#define TX_HW_ATTR_OFST_SESSION_COUNTER 2 -#define TX_HW_ATTR_OFST_RATE_POLICY 5 -#define TX_HW_ATTR_OFST_LAST_WORD_PAD 10 -#define TX_HW_ATTR_OFST_TX_CMPLT_REQ 12 - -#define TX_HW_RESULT_QUEUE_LEN 16 -#define TX_HW_RESULT_QUEUE_LEN_MASK 0xf - -#define WL1271_TX_ALIGN_TO 4 -#define WL1271_TX_ALIGN(len) (((len) + WL1271_TX_ALIGN_TO - 1) & \ - ~(WL1271_TX_ALIGN_TO - 1)) -#define WL1271_TKIP_IV_SPACE 4 - -struct wl1271_tx_hw_descr { - /* Length of packet in words, including descriptor+header+data */ - __le16 length; - /* Number of extra memory blocks to allocate for this packet in - addition to the number of blocks derived from the packet length */ - u8 extra_mem_blocks; - /* Total number of memory blocks allocated by the host for this packet. - Must be equal or greater than the actual blocks number allocated by - HW!! */ - u8 total_mem_blocks; - /* Device time (in us) when the packet arrived to the driver */ - __le32 start_time; - /* Max delay in TUs until transmission. The last device time the - packet can be transmitted is: startTime+(1024*LifeTime) */ - __le16 life_time; - /* Bitwise fields - see TX_ATTR... definitions above. */ - __le16 tx_attr; - /* Packet identifier used also in the Tx-Result. */ - u8 id; - /* The packet TID value (as User-Priority) */ - u8 tid; - /* Identifier of the remote STA in IBSS, 1 in infra-BSS */ - u8 aid; - u8 reserved; -} __packed; - -enum wl1271_tx_hw_res_status { - TX_SUCCESS = 0, - TX_HW_ERROR = 1, - TX_DISABLED = 2, - TX_RETRY_EXCEEDED = 3, - TX_TIMEOUT = 4, - TX_KEY_NOT_FOUND = 5, - TX_PEER_NOT_FOUND = 6, - TX_SESSION_MISMATCH = 7 -}; - -struct wl1271_tx_hw_res_descr { - /* Packet Identifier - same value used in the Tx descriptor.*/ - u8 id; - /* The status of the transmission, indicating success or one of - several possible reasons for failure. */ - u8 status; - /* Total air access duration including all retrys and overheads.*/ - __le16 medium_usage; - /* The time passed from host xfer to Tx-complete.*/ - __le32 fw_handling_time; - /* Total media delay - (from 1st EDCA AIFS counter until TX Complete). */ - __le32 medium_delay; - /* LS-byte of last TKIP seq-num (saved per AC for recovery). */ - u8 lsb_security_sequence_number; - /* Retry count - number of transmissions without successful ACK.*/ - u8 ack_failures; - /* The rate that succeeded getting ACK - (Valid only if status=SUCCESS). */ - u8 rate_class_index; - /* for 4-byte alignment. */ - u8 spare; -} __packed; - -struct wl1271_tx_hw_res_if { - __le32 tx_result_fw_counter; - __le32 tx_result_host_counter; - struct wl1271_tx_hw_res_descr tx_results_queue[TX_HW_RESULT_QUEUE_LEN]; -} __packed; - -static inline int wl1271_tx_get_queue(int queue) -{ - switch (queue) { - case 0: - return CONF_TX_AC_VO; - case 1: - return CONF_TX_AC_VI; - case 2: - return CONF_TX_AC_BE; - case 3: - return CONF_TX_AC_BK; - default: - return CONF_TX_AC_BE; - } -} - -void wl1271_tx_work(struct work_struct *work); -void wl1271_tx_work_locked(struct wl1271 *wl); -void wl1271_tx_complete(struct wl1271 *wl); -void wl1271_tx_reset(struct wl1271 *wl); -void wl1271_tx_flush(struct wl1271 *wl); -u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band); -u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set); - -#endif diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h new file mode 100644 index 0000000..3c836e6 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -0,0 +1,523 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 __WL12XX_H__ +#define __WL12XX_H__ + +#include +#include +#include +#include +#include +#include + +#include "conf.h" +#include "ini.h" + +#define DRIVER_NAME "wl1271" +#define DRIVER_PREFIX DRIVER_NAME ": " + +enum { + DEBUG_NONE = 0, + DEBUG_IRQ = BIT(0), + DEBUG_SPI = BIT(1), + DEBUG_BOOT = BIT(2), + DEBUG_MAILBOX = BIT(3), + DEBUG_TESTMODE = BIT(4), + DEBUG_EVENT = BIT(5), + DEBUG_TX = BIT(6), + DEBUG_RX = BIT(7), + DEBUG_SCAN = BIT(8), + DEBUG_CRYPT = BIT(9), + DEBUG_PSM = BIT(10), + DEBUG_MAC80211 = BIT(11), + DEBUG_CMD = BIT(12), + DEBUG_ACX = BIT(13), + DEBUG_SDIO = BIT(14), + DEBUG_FILTERS = BIT(15), + DEBUG_ADHOC = BIT(16), + DEBUG_ALL = ~0, +}; + +#define DEBUG_LEVEL (DEBUG_NONE) + +#define DEBUG_DUMP_LIMIT 1024 + +#define wl1271_error(fmt, arg...) \ + printk(KERN_ERR DRIVER_PREFIX "ERROR " fmt "\n", ##arg) + +#define wl1271_warning(fmt, arg...) \ + printk(KERN_WARNING DRIVER_PREFIX "WARNING " fmt "\n", ##arg) + +#define wl1271_notice(fmt, arg...) \ + printk(KERN_INFO DRIVER_PREFIX fmt "\n", ##arg) + +#define wl1271_info(fmt, arg...) \ + printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg) + +#define wl1271_debug(level, fmt, arg...) \ + do { \ + if (level & DEBUG_LEVEL) \ + printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg); \ + } while (0) + +#define wl1271_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 wl1271_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 WL1271_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \ + CFG_BSSID_FILTER_EN | \ + CFG_MC_FILTER_EN) + +#define WL1271_DEFAULT_RX_FILTER (CFG_RX_RCTS_ACK | 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 WL1271_FW_NAME "wl1271-fw.bin" +#define WL1271_NVS_NAME "wl1271-nvs.bin" + +#define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff)) +#define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff)) + +#define WL1271_CIPHER_SUITE_GEM 0x00147201 + +#define WL1271_BUSY_WORD_CNT 1 +#define WL1271_BUSY_WORD_LEN (WL1271_BUSY_WORD_CNT * sizeof(u32)) + +#define WL1271_ELP_HW_STATE_ASLEEP 0 +#define WL1271_ELP_HW_STATE_IRQ 1 + +#define WL1271_DEFAULT_BEACON_INT 100 +#define WL1271_DEFAULT_DTIM_PERIOD 1 + +#define ACX_TX_DESCRIPTORS 32 + +#define WL1271_AGGR_BUFFER_SIZE (4 * PAGE_SIZE) + +enum wl1271_state { + WL1271_STATE_OFF, + WL1271_STATE_ON, + WL1271_STATE_PLT, +}; + +enum wl1271_partition_type { + PART_DOWN, + PART_WORK, + PART_DRPW, + + PART_TABLE_LEN +}; + +struct wl1271_partition { + u32 size; + u32 start; +}; + +struct wl1271_partition_set { + struct wl1271_partition mem; + struct wl1271_partition reg; + struct wl1271_partition mem2; + struct wl1271_partition mem3; +}; + +struct wl1271; + +/* FIXME: I'm not sure about this structure name */ +struct wl1271_chip { + u32 id; + char fw_ver[21]; +}; + +struct wl1271_stats { + struct acx_statistics *fw_stats; + unsigned long fw_stats_update; + + unsigned int retry_count; + unsigned int excessive_retries; +}; + +struct wl1271_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 *retry_count; + struct dentry *excessive_retries; + struct dentry *gpio_power; +}; + +#define NUM_TX_QUEUES 4 +#define NUM_RX_PKT_DESC 8 + +/* FW status registers */ +struct wl1271_fw_status { + __le32 intr; + u8 fw_rx_counter; + u8 drv_rx_counter; + u8 reserved; + u8 tx_results_counter; + __le32 rx_pkt_descs[NUM_RX_PKT_DESC]; + __le32 tx_released_blks[NUM_TX_QUEUES]; + __le32 fw_localtime; + __le32 padding[2]; +} __packed; + +struct wl1271_rx_mem_pool_addr { + u32 addr; + u32 addr_extra; +}; + +struct wl1271_scan { + struct cfg80211_scan_request *req; + bool *scanned_ch; + bool failed; + u8 state; + u8 ssid[IW_ESSID_MAX_SIZE+1]; + size_t ssid_len; +}; + +struct wl1271_if_operations { + void (*read)(struct wl1271 *wl, int addr, void *buf, size_t len, + bool fixed); + void (*write)(struct wl1271 *wl, int addr, void *buf, size_t len, + bool fixed); + void (*reset)(struct wl1271 *wl); + void (*init)(struct wl1271 *wl); + int (*power)(struct wl1271 *wl, bool enable); + struct device* (*dev)(struct wl1271 *wl); + void (*enable_irq)(struct wl1271 *wl); + void (*disable_irq)(struct wl1271 *wl); +}; + +struct wl1271 { + struct platform_device *plat_dev; + struct ieee80211_hw *hw; + bool mac80211_registered; + + void *if_priv; + + struct wl1271_if_operations *if_ops; + + void (*set_power)(bool enable); + int irq; + int ref_clock; + + spinlock_t wl_lock; + + enum wl1271_state state; + struct mutex mutex; + +#define WL1271_FLAG_STA_RATES_CHANGED (0) +#define WL1271_FLAG_STA_ASSOCIATED (1) +#define WL1271_FLAG_JOINED (2) +#define WL1271_FLAG_GPIO_POWER (3) +#define WL1271_FLAG_TX_QUEUE_STOPPED (4) +#define WL1271_FLAG_IN_ELP (5) +#define WL1271_FLAG_PSM (6) +#define WL1271_FLAG_PSM_REQUESTED (7) +#define WL1271_FLAG_IRQ_PENDING (8) +#define WL1271_FLAG_IRQ_RUNNING (9) +#define WL1271_FLAG_IDLE (10) +#define WL1271_FLAG_IDLE_REQUESTED (11) +#define WL1271_FLAG_PSPOLL_FAILURE (12) +#define WL1271_FLAG_STA_STATE_SENT (13) +#define WL1271_FLAG_FW_TX_BUSY (14) + unsigned long flags; + + struct wl1271_partition_set part; + + struct wl1271_chip chip; + + int cmd_box_addr; + int event_box_addr; + + u8 *fw; + size_t fw_len; + struct wl1271_nvs_file *nvs; + size_t nvs_len; + + s8 hw_pg_ver; + + u8 bssid[ETH_ALEN]; + u8 mac_addr[ETH_ALEN]; + u8 bss_type; + u8 set_bss_type; + u8 ssid[IW_ESSID_MAX_SIZE + 1]; + u8 ssid_len; + int channel; + + struct wl1271_acx_mem_map *target_mem_map; + + /* Accounting for allocated / available TX blocks on HW */ + u32 tx_blocks_freed[NUM_TX_QUEUES]; + u32 tx_blocks_available; + u32 tx_results_count; + + /* Transmitted TX packets counter for chipset interface */ + u32 tx_packets_count; + + /* Time-offset between host and chipset clocks */ + s64 time_offset; + + /* Session counter for the chipset */ + int session_counter; + + /* Frames scheduled for transmission, not handled yet */ + struct sk_buff_head tx_queue; + + struct work_struct tx_work; + + /* Pending TX frames */ + unsigned long tx_frames_map[BITS_TO_LONGS(ACX_TX_DESCRIPTORS)]; + struct sk_buff *tx_frames[ACX_TX_DESCRIPTORS]; + int tx_frames_cnt; + + /* Security sequence number counters */ + u8 tx_security_last_seq; + s64 tx_security_seq; + + /* FW Rx counter */ + u32 rx_counter; + + /* Rx memory pool address */ + struct wl1271_rx_mem_pool_addr rx_mem_pool_addr; + + /* Intermediate buffer, used for packet aggregation */ + u8 *aggr_buf; + + /* The target interrupt mask */ + struct work_struct irq_work; + + /* Hardware recovery work */ + struct work_struct recovery_work; + + /* The mbox event mask */ + u32 event_mask; + + /* Mailbox pointers */ + u32 mbox_ptr[2]; + + /* Are we currently scanning */ + struct wl1271_scan scan; + struct delayed_work scan_complete_work; + + /* Our association ID */ + u16 aid; + + /* + * currently configured rate set: + * bits 0-15 - 802.11abg rates + * bits 16-23 - 802.11n MCS index mask + * support only 1 stream, thus only 8 bits for the MCS rates (0-7). + */ + u32 sta_rate_set; + u32 basic_rate_set; + u32 basic_rate; + u32 rate_set; + + /* The current band */ + enum ieee80211_band band; + + /* Beaconing interval (needed for ad-hoc) */ + u32 beacon_int; + + /* Default key (for WEP) */ + u32 default_key; + + unsigned int filters; + unsigned int rx_config; + unsigned int rx_filter; + + struct completion *elp_compl; + struct delayed_work elp_work; + struct delayed_work pspoll_work; + + /* counter for ps-poll delivery failures */ + int ps_poll_failures; + + /* retry counter for PSM entries */ + u8 psm_entry_retry; + + /* in dBm */ + int power_level; + + int rssi_thold; + int last_rssi_event; + + struct wl1271_stats stats; + struct wl1271_debugfs debugfs; + + __le32 buffer_32; + u32 buffer_cmd; + u32 buffer_busyword[WL1271_BUSY_WORD_CNT]; + + struct wl1271_fw_status *fw_status; + struct wl1271_tx_hw_res_if *tx_res_if; + + struct ieee80211_vif *vif; + + /* Current chipset configuration */ + struct conf_drv_settings conf; + + bool sg_enabled; + + bool enable_11a; + + struct list_head list; + + /* Most recently reported noise in dBm */ + s8 noise; +}; + +int wl1271_plt_start(struct wl1271 *wl); +int wl1271_plt_stop(struct wl1271 *wl); + +#define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */ + +#define SESSION_COUNTER_MAX 7 /* maximum value for the session counter */ + +#define WL1271_DEFAULT_POWER_LEVEL 0 + +#define WL1271_TX_QUEUE_LOW_WATERMARK 10 +#define WL1271_TX_QUEUE_HIGH_WATERMARK 25 + +/* WL1271 needs a 200ms sleep after power on, and a 20ms sleep before power + on in case is has been shut down shortly before */ +#define WL1271_PRE_POWER_ON_SLEEP 20 /* in miliseconds */ +#define WL1271_POWER_ON_SLEEP 200 /* in miliseconds */ + +/* Macros to handle wl1271.sta_rate_set */ +#define HW_BG_RATES_MASK 0xffff +#define HW_HT_RATES_OFFSET 16 + +#endif -- cgit v0.10.2 From 91433029e42e58d8536299f32fa55cf589adff35 Mon Sep 17 00:00:00 2001 From: Gery Kahn Date: Sun, 7 Nov 2010 10:04:20 +0100 Subject: wl1271: cleanup unused code of calibration structures The cleanup unused code for calibration procedures. Signed-off-by: Gery Kahn Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h index 893dbf7..16d1bf8 100644 --- a/drivers/net/wireless/wl12xx/cmd.h +++ b/drivers/net/wireless/wl12xx/cmd.h @@ -327,9 +327,6 @@ enum wl1271_channel_tune_bands { #define WL1271_PD_REFERENCE_POINT_BAND_B_G 0 -#define TEST_CMD_P2G_CAL 0x02 -#define TEST_CMD_CHANNEL_TUNE 0x0d -#define TEST_CMD_UPDATE_PD_REFERENCE_POINT 0x1d #define TEST_CMD_INI_FILE_RADIO_PARAM 0x19 #define TEST_CMD_INI_FILE_GENERAL_PARAM 0x1E #define TEST_CMD_INI_FILE_RF_EXTENDED_PARAM 0x26 @@ -375,51 +372,6 @@ struct wl1271_ext_radio_parms_cmd { u8 padding[3]; } __packed; -struct wl1271_cmd_cal_channel_tune { - struct wl1271_cmd_header header; - - struct wl1271_cmd_test_header test; - - u8 band; - u8 channel; - - __le16 radio_status; -} __packed; - -struct wl1271_cmd_cal_update_ref_point { - struct wl1271_cmd_header header; - - struct wl1271_cmd_test_header test; - - __le32 ref_power; - __le32 ref_detector; - u8 sub_band; - u8 padding[3]; -} __packed; - -#define MAX_TLV_LENGTH 400 -#define MAX_NVS_VERSION_LENGTH 12 - -#define WL1271_CAL_P2G_BAND_B_G BIT(0) - -struct wl1271_cmd_cal_p2g { - struct wl1271_cmd_header header; - - struct wl1271_cmd_test_header test; - - __le16 len; - u8 buf[MAX_TLV_LENGTH]; - u8 type; - u8 padding; - - __le16 radio_status; - u8 nvs_version[MAX_NVS_VERSION_LENGTH]; - - u8 sub_band_mask; - u8 padding2; -} __packed; - - /* * There are three types of disconnections: * -- cgit v0.10.2 From b7417d930afdc214daa24299912d984e7f4f390a Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Wed, 10 Nov 2010 11:27:19 +0100 Subject: wl1271: Prevent ad-hoc and active scanning on 11a DFS frequencies The wl1271 does not support radar detection. Hence, prevent ad-hoc and active scanning on frequencies requiring DFS. Signed-off-by: Juuso Oikarinen Tested-by: Tuomas Katila Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index c005230..0724328 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -335,6 +335,27 @@ out: return NOTIFY_OK; } +static int wl1271_reg_notify(struct wiphy *wiphy, + struct regulatory_request *request) { + struct ieee80211_supported_band *band; + struct ieee80211_channel *ch; + int i; + + band = wiphy->bands[IEEE80211_BAND_5GHZ]; + for (i = 0; i < band->n_channels; i++) { + ch = &band->channels[i]; + if (ch->flags & IEEE80211_CHAN_DISABLED) + continue; + + if (ch->flags & IEEE80211_CHAN_RADAR) + ch->flags |= IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_PASSIVE_SCAN; + + } + + return 0; +} + static void wl1271_conf_init(struct wl1271 *wl) { @@ -2590,6 +2611,8 @@ int wl1271_init_ieee80211(struct wl1271 *wl) wl->hw->queues = 4; wl->hw->max_rates = 1; + wl->hw->wiphy->reg_notifier = wl1271_reg_notify; + SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl)); return 0; -- cgit v0.10.2 From fa97f46b30357a50f3ee193e6f82864f95bc55ec Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Wed, 10 Nov 2010 11:27:20 +0100 Subject: Revert "wl1271: Change supported channel order for a more optimal scan" This reverts commit fa21c7a9e4be439e217fe72edbd39b643b643791. The reverted patch caused more harm than benefit. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Tested-by: Tuomas Katila Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 0724328..6af270d 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -2215,24 +2215,21 @@ static struct ieee80211_rate wl1271_rates[] = { .hw_value_short = CONF_HW_BIT_RATE_54MBPS, }, }; -/* - * Can't be const, mac80211 writes to this. The order of the channels here - * is designed to improve scanning. - */ +/* can't be const, mac80211 writes to this */ static struct ieee80211_channel wl1271_channels[] = { { .hw_value = 1, .center_freq = 2412, .max_power = 25 }, - { .hw_value = 5, .center_freq = 2432, .max_power = 25 }, - { .hw_value = 9, .center_freq = 2452, .max_power = 25 }, - { .hw_value = 13, .center_freq = 2472, .max_power = 25 }, - { .hw_value = 4, .center_freq = 2427, .max_power = 25 }, - { .hw_value = 8, .center_freq = 2447, .max_power = 25 }, - { .hw_value = 12, .center_freq = 2467, .max_power = 25 }, - { .hw_value = 3, .center_freq = 2422, .max_power = 25 }, - { .hw_value = 7, .center_freq = 2442, .max_power = 25 }, - { .hw_value = 11, .center_freq = 2462, .max_power = 25 }, { .hw_value = 2, .center_freq = 2417, .max_power = 25 }, + { .hw_value = 3, .center_freq = 2422, .max_power = 25 }, + { .hw_value = 4, .center_freq = 2427, .max_power = 25 }, + { .hw_value = 5, .center_freq = 2432, .max_power = 25 }, { .hw_value = 6, .center_freq = 2437, .max_power = 25 }, + { .hw_value = 7, .center_freq = 2442, .max_power = 25 }, + { .hw_value = 8, .center_freq = 2447, .max_power = 25 }, + { .hw_value = 9, .center_freq = 2452, .max_power = 25 }, { .hw_value = 10, .center_freq = 2457, .max_power = 25 }, + { .hw_value = 11, .center_freq = 2462, .max_power = 25 }, + { .hw_value = 12, .center_freq = 2467, .max_power = 25 }, + { .hw_value = 13, .center_freq = 2472, .max_power = 25 }, }; /* mapping to indexes for wl1271_rates */ @@ -2323,52 +2320,49 @@ static struct ieee80211_rate wl1271_rates_5ghz[] = { .hw_value_short = CONF_HW_BIT_RATE_54MBPS, }, }; -/* - * 5 GHz band channels for WL1273 - can't be const, mac80211 writes to this. - * The order of the channels here is designed to improve scanning. - */ +/* 5 GHz band channels for WL1273 */ static struct ieee80211_channel wl1271_channels_5ghz[] = { { .hw_value = 183, .center_freq = 4915}, - { .hw_value = 188, .center_freq = 4940}, - { .hw_value = 8, .center_freq = 5040}, - { .hw_value = 34, .center_freq = 5170}, - { .hw_value = 44, .center_freq = 5220}, - { .hw_value = 60, .center_freq = 5300}, - { .hw_value = 112, .center_freq = 5560}, - { .hw_value = 132, .center_freq = 5660}, - { .hw_value = 157, .center_freq = 5785}, { .hw_value = 184, .center_freq = 4920}, + { .hw_value = 185, .center_freq = 4925}, + { .hw_value = 187, .center_freq = 4935}, + { .hw_value = 188, .center_freq = 4940}, { .hw_value = 189, .center_freq = 4945}, - { .hw_value = 9, .center_freq = 5045}, - { .hw_value = 36, .center_freq = 5180}, - { .hw_value = 46, .center_freq = 5230}, - { .hw_value = 64, .center_freq = 5320}, - { .hw_value = 116, .center_freq = 5580}, - { .hw_value = 136, .center_freq = 5680}, { .hw_value = 192, .center_freq = 4960}, - { .hw_value = 11, .center_freq = 5055}, - { .hw_value = 38, .center_freq = 5190}, - { .hw_value = 48, .center_freq = 5240}, - { .hw_value = 100, .center_freq = 5500}, - { .hw_value = 120, .center_freq = 5600}, - { .hw_value = 140, .center_freq = 5700}, - { .hw_value = 185, .center_freq = 4925}, { .hw_value = 196, .center_freq = 4980}, - { .hw_value = 12, .center_freq = 5060}, - { .hw_value = 40, .center_freq = 5200}, - { .hw_value = 52, .center_freq = 5260}, - { .hw_value = 104, .center_freq = 5520}, - { .hw_value = 124, .center_freq = 5620}, - { .hw_value = 149, .center_freq = 5745}, - { .hw_value = 161, .center_freq = 5805}, - { .hw_value = 187, .center_freq = 4935}, { .hw_value = 7, .center_freq = 5035}, + { .hw_value = 8, .center_freq = 5040}, + { .hw_value = 9, .center_freq = 5045}, + { .hw_value = 11, .center_freq = 5055}, + { .hw_value = 12, .center_freq = 5060}, { .hw_value = 16, .center_freq = 5080}, + { .hw_value = 34, .center_freq = 5170}, + { .hw_value = 36, .center_freq = 5180}, + { .hw_value = 38, .center_freq = 5190}, + { .hw_value = 40, .center_freq = 5200}, { .hw_value = 42, .center_freq = 5210}, + { .hw_value = 44, .center_freq = 5220}, + { .hw_value = 46, .center_freq = 5230}, + { .hw_value = 48, .center_freq = 5240}, + { .hw_value = 52, .center_freq = 5260}, { .hw_value = 56, .center_freq = 5280}, + { .hw_value = 60, .center_freq = 5300}, + { .hw_value = 64, .center_freq = 5320}, + { .hw_value = 100, .center_freq = 5500}, + { .hw_value = 104, .center_freq = 5520}, { .hw_value = 108, .center_freq = 5540}, + { .hw_value = 112, .center_freq = 5560}, + { .hw_value = 116, .center_freq = 5580}, + { .hw_value = 120, .center_freq = 5600}, + { .hw_value = 124, .center_freq = 5620}, { .hw_value = 128, .center_freq = 5640}, + { .hw_value = 132, .center_freq = 5660}, + { .hw_value = 136, .center_freq = 5680}, + { .hw_value = 140, .center_freq = 5700}, + { .hw_value = 149, .center_freq = 5745}, { .hw_value = 153, .center_freq = 5765}, + { .hw_value = 157, .center_freq = 5785}, + { .hw_value = 161, .center_freq = 5805}, { .hw_value = 165, .center_freq = 5825}, }; -- cgit v0.10.2 From 68d069c45f73e8aeda0249891daec1f7e2f0e067 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Mon, 8 Nov 2010 10:51:07 +0100 Subject: wl1271: add support for HW TX fragmentation Indicate to mac80211 we support HW fragmentation. Support updates of the fragmentation threshold via the set_frag_threshold callback. Signed-off-by: Arik Nemtsov Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index bc1085b..7cbaeb6 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c @@ -862,7 +862,7 @@ out: return ret; } -int wl1271_acx_frag_threshold(struct wl1271 *wl) +int wl1271_acx_frag_threshold(struct wl1271 *wl, u16 frag_threshold) { struct acx_frag_threshold *acx; int ret = 0; @@ -876,7 +876,7 @@ int wl1271_acx_frag_threshold(struct wl1271 *wl) goto out; } - acx->frag_threshold = cpu_to_le16(wl->conf.tx.frag_threshold); + acx->frag_threshold = cpu_to_le16(frag_threshold); ret = wl1271_cmd_configure(wl, ACX_FRAG_CFG, acx, sizeof(*acx)); if (ret < 0) { wl1271_warning("Setting of frag threshold failed: %d", ret); diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h index f41a9c1..75a6306 100644 --- a/drivers/net/wireless/wl12xx/acx.h +++ b/drivers/net/wireless/wl12xx/acx.h @@ -1161,7 +1161,7 @@ int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max, int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type, u8 tsid, u8 ps_scheme, u8 ack_policy, u32 apsd_conf0, u32 apsd_conf1); -int wl1271_acx_frag_threshold(struct wl1271 *wl); +int wl1271_acx_frag_threshold(struct wl1271 *wl, u16 frag_threshold); int wl1271_acx_tx_config_options(struct wl1271 *wl); int wl1271_acx_mem_cfg(struct wl1271 *wl); int wl1271_acx_init_mem_config(struct wl1271 *wl); diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c index 492edc0..7949d34 100644 --- a/drivers/net/wireless/wl12xx/init.c +++ b/drivers/net/wireless/wl12xx/init.c @@ -290,7 +290,7 @@ int wl1271_hw_init(struct wl1271 *wl) goto out_free_memmap; /* Default fragmentation threshold */ - ret = wl1271_acx_frag_threshold(wl); + ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold); if (ret < 0) goto out_free_memmap; diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 6af270d..31f0e2f 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -425,7 +425,7 @@ static int wl1271_plt_init(struct wl1271 *wl) goto out_free_memmap; /* Default fragmentation threshold */ - ret = wl1271_acx_frag_threshold(wl); + ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold); if (ret < 0) goto out_free_memmap; @@ -1745,6 +1745,34 @@ out: return ret; } +static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value) +{ + struct wl1271 *wl = hw->priv; + int ret = 0; + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state == WL1271_STATE_OFF)) { + ret = -EAGAIN; + goto out; + } + + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out; + + ret = wl1271_acx_frag_threshold(wl, (u16)value); + if (ret < 0) + wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret); + + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + + return ret; +} + static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) { struct wl1271 *wl = hw->priv; @@ -2421,6 +2449,7 @@ static const struct ieee80211_ops wl1271_ops = { .set_key = wl1271_op_set_key, .hw_scan = wl1271_op_hw_scan, .bss_info_changed = wl1271_op_bss_info_changed, + .set_frag_threshold = wl1271_op_set_frag_threshold, .set_rts_threshold = wl1271_op_set_rts_threshold, .conf_tx = wl1271_op_conf_tx, .get_tsf = wl1271_op_get_tsf, -- cgit v0.10.2 From b84a7d3d9e7cd5a25f4fd32142cebdf4481a74a4 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Mon, 22 Nov 2010 12:59:08 +0200 Subject: wl12xx: Unset bssid filter, ssid and bssid from firmware on disassoc On the disassociation event from the mac80211, the wl12xx driver does not clear the chipset configuration related to the AP - i.e. it does not perform a DISCONNECT and then a JOIN with zero SSID and dummy BSSID. Also, it does not unset the BSSID filter. Often this is not a problem, as the above is performed upon entering idle state. But if a scenario arises where a new association is attempted without cycling through idle state, the new association will fail. Fix this by resetting the firmware state on disassociation. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 31f0e2f..708ffe3 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -2011,9 +2011,12 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, /* Disable the keep-alive feature */ ret = wl1271_acx_keep_alive_mode(wl, false); - if (ret < 0) goto out_sleep; + + /* restore the bssid filter and go to dummy bssid */ + wl1271_unjoin(wl); + wl1271_dummy_join(wl); } } -- cgit v0.10.2 From d47844a014fada1a788719f6426bc7044f2a0fd8 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 20 Nov 2010 03:08:47 +0100 Subject: ath9k: fix timeout on stopping rx dma It seems that using ath9k_hw_stoppcurecv to stop rx dma is not enough. When it's time to stop DMA, the PCU is still busy, so the rx enable bit never clears. Using ath9k_hw_abortpcurecv helps with getting rx stopped much faster, with this change, I cannot reproduce the rx stop related WARN_ON anymore. Signed-off-by: Felix Fietkau Cc: stable@kernel.org Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index c76ea53..1a62e35 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -518,7 +518,7 @@ bool ath_stoprecv(struct ath_softc *sc) bool stopped; spin_lock_bh(&sc->rx.rxbuflock); - ath9k_hw_stoppcurecv(ah); + ath9k_hw_abortpcurecv(ah); ath9k_hw_setrxfilter(ah, 0); stopped = ath9k_hw_stopdmarecv(ah); -- cgit v0.10.2 From 1d8638d4038eb8709edc80e37a0bbb77253d86e9 Mon Sep 17 00:00:00 2001 From: Daniel Klaffenbach Date: Fri, 19 Nov 2010 21:25:21 -0600 Subject: ssb: b43-pci-bridge: Add new vendor for BCM4318 Add new vendor for Broadcom 4318. Signed-off-by: Daniel Klaffenbach Signed-off-by: Larry Finger Cc: Stable Signed-off-by: John W. Linville diff --git a/drivers/ssb/b43_pci_bridge.c b/drivers/ssb/b43_pci_bridge.c index ef9c6a0..744d3f6 100644 --- a/drivers/ssb/b43_pci_bridge.c +++ b/drivers/ssb/b43_pci_bridge.c @@ -24,6 +24,7 @@ static const struct pci_device_id b43_pci_bridge_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4312) }, { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4315) }, { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4318) }, + { PCI_DEVICE(PCI_VENDOR_ID_BCM_GVC, 0x4318) }, { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4319) }, { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4320) }, { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4321) }, diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index d278dd9..f29c25e 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2043,6 +2043,7 @@ #define PCI_DEVICE_ID_AFAVLAB_P030 0x2182 #define PCI_SUBDEVICE_ID_AFAVLAB_P061 0x2150 +#define PCI_VENDOR_ID_BCM_GVC 0x14a4 #define PCI_VENDOR_ID_BROADCOM 0x14e4 #define PCI_DEVICE_ID_TIGON3_5752 0x1600 #define PCI_DEVICE_ID_TIGON3_5752M 0x1601 -- cgit v0.10.2 From b397492a8c1022887a9b2fb925fe92e69ce0ad4d Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 20 Nov 2010 13:15:27 +0100 Subject: carl9170: fix virtual interface setup crash This patch fixes a faulty bound check which caused a crash when too many virtual interface were brought up. BUG: unable to handle kernel NULL pointer dereference at 00000004 IP: [] carl9170_op_add_interface+0x1d7/0x2c0 [carl9170] *pde = 00000000 Oops: 0002 [#1] PREEMPT Modules linked in: carl9170 [...] Pid: 4720, comm: wpa_supplicant Not tainted 2.6.37-rc2-wl+ EIP: 0060:[] EFLAGS: 00210206 CPU: 0 EIP is at carl9170_op_add_interface+0x1d7/0x2c0 [carl9170] EAX: 00000000 ... Process wpa_supplicant Stack: f4f88f34 fffffff4 .. Call Trace: [] ? ieee80211_do_open+0x406/0x5c0 [mac80211] [...] Code: <89> 42 04 ... EIP: [] carl9170_op_add_interface+0x1d7/0x2c0 [carl9170] CR2: 0000000000000004 Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 980ae70..a314c2c 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -647,7 +647,7 @@ init: } unlock: - if (err && (vif_id != -1)) { + if (err && (vif_id >= 0)) { vif_priv->active = false; bitmap_release_region(&ar->vif_bitmap, vif_id, 0); ar->vifs--; -- cgit v0.10.2 From 8933f90c777c5728822206a2313c9c1361f5274f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 14 Oct 2010 22:58:58 +0200 Subject: b43: N-PHY: add 2056 radio channels 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/radio_2056.c b/drivers/net/wireless/b43/radio_2056.c index f710c01..0cdf6a4 100644 --- a/drivers/net/wireless/b43/radio_2056.c +++ b/drivers/net/wireless/b43/radio_2056.c @@ -74,7 +74,5975 @@ .phy_regs.phy_bw5 = r4, \ .phy_regs.phy_bw6 = r5 +/* http://bcm-v4.sipsolutions.net/802.11/Radio/2056/ChannelTable */ static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev3[] = { + { .freq = 4920, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x08, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xff, 0x00), + PHYREGS(0x07b4, 0x07b0, 0x07ac, 0x0214, 0x0215, 0x0216), + }, + { .freq = 4930, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xed, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x08, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xff, 0x00), + PHYREGS(0x07b8, 0x07b4, 0x07b0, 0x0213, 0x0214, 0x0215), + }, + { .freq = 4940, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xee, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x08, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xff, 0x00), + PHYREGS(0x07bc, 0x07b8, 0x07b4, 0x0212, 0x0213, 0x0214), + }, + { .freq = 4950, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xef, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x08, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xff, 0x00), + PHYREGS(0x07c0, 0x07bc, 0x07b8, 0x0211, 0x0212, 0x0213), + }, + { .freq = 4960, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf0, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x08, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xff, 0x00), + PHYREGS(0x07c4, 0x07c0, 0x07bc, 0x020f, 0x0211, 0x0212), + }, + { .freq = 4970, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf1, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x08, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xff, 0x00), + PHYREGS(0x07c8, 0x07c4, 0x07c0, 0x020e, 0x020f, 0x0211), + }, + { .freq = 4980, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf2, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x08, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xff, 0x00), + PHYREGS(0x07cc, 0x07c8, 0x07c4, 0x020d, 0x020e, 0x020f), + }, + { .freq = 4990, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf3, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x08, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xff, 0x00), + PHYREGS(0x07d0, 0x07cc, 0x07c8, 0x020c, 0x020d, 0x020e), + }, + { .freq = 5000, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf4, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xff, 0x00), + PHYREGS(0x07d4, 0x07d0, 0x07cc, 0x020b, 0x020c, 0x020d), + }, + { .freq = 5010, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf5, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xff, 0x00), + PHYREGS(0x07d8, 0x07d4, 0x07d0, 0x020a, 0x020b, 0x020c), + }, + { .freq = 5020, + RADIOREGS3(0xf7, 0x01, 0x01, 0x01, 0xf6, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xff, 0x00), + PHYREGS(0x07dc, 0x07d8, 0x07d4, 0x0209, 0x020a, 0x020b), + }, + { .freq = 5030, + RADIOREGS3(0xf7, 0x01, 0x01, 0x01, 0xf7, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xff, 0x00), + PHYREGS(0x07e0, 0x07dc, 0x07d8, 0x0208, 0x0209, 0x020a), + }, + { .freq = 5040, + RADIOREGS3(0xef, 0x01, 0x01, 0x01, 0xf8, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xff, 0x00), + PHYREGS(0x07e4, 0x07e0, 0x07dc, 0x0207, 0x0208, 0x0209), + }, + { .freq = 5050, + RADIOREGS3(0xef, 0x01, 0x01, 0x01, 0xf9, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xff, 0x00), + PHYREGS(0x07e8, 0x07e4, 0x07e0, 0x0206, 0x0207, 0x0208), + }, + { .freq = 5060, + RADIOREGS3(0xe6, 0x01, 0x01, 0x01, 0xfa, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xff, 0x00), + PHYREGS(0x07ec, 0x07e8, 0x07e4, 0x0205, 0x0206, 0x0207), + }, + { .freq = 5070, + RADIOREGS3(0xe6, 0x01, 0x01, 0x01, 0xfb, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xff, 0x00), + PHYREGS(0x07f0, 0x07ec, 0x07e8, 0x0204, 0x0205, 0x0206), + }, + { .freq = 5080, + RADIOREGS3(0xde, 0x01, 0x01, 0x01, 0xfc, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xff, 0x00), + PHYREGS(0x07f4, 0x07f0, 0x07ec, 0x0203, 0x0204, 0x0205), + }, + { .freq = 5090, + RADIOREGS3(0xde, 0x01, 0x01, 0x01, 0xfd, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xff, 0x00), + PHYREGS(0x07f8, 0x07f4, 0x07f0, 0x0202, 0x0203, 0x0204), + }, + { .freq = 5100, + RADIOREGS3(0xd6, 0x01, 0x01, 0x01, 0xfe, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xff, 0x00), + PHYREGS(0x07fc, 0x07f8, 0x07f4, 0x0201, 0x0202, 0x0203), + }, + { .freq = 5110, + RADIOREGS3(0xd6, 0x01, 0x01, 0x01, 0xff, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xfc, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xfc, 0x00), + PHYREGS(0x0800, 0x07fc, 0x07f8, 0x0200, 0x0201, 0x0202), + }, + { .freq = 5120, + RADIOREGS3(0xce, 0x01, 0x01, 0x02, 0x00, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xfc, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xfc, 0x00), + PHYREGS(0x0804, 0x0800, 0x07fc, 0x01ff, 0x0200, 0x0201), + }, + { .freq = 5130, + RADIOREGS3(0xce, 0x01, 0x01, 0x02, 0x01, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xfc, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xfc, 0x00), + PHYREGS(0x0808, 0x0804, 0x0800, 0x01fe, 0x01ff, 0x0200), + }, + { .freq = 5140, + RADIOREGS3(0xc6, 0x01, 0x01, 0x02, 0x02, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xfc, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xfc, 0x00), + PHYREGS(0x080c, 0x0808, 0x0804, 0x01fd, 0x01fe, 0x01ff), + }, + { .freq = 5160, + RADIOREGS3(0xbe, 0x01, 0x01, 0x02, 0x04, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xfc, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xfc, 0x00), + PHYREGS(0x0814, 0x0810, 0x080c, 0x01fb, 0x01fc, 0x01fd), + }, + { .freq = 5170, + RADIOREGS3(0xbe, 0x01, 0x01, 0x02, 0x05, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xfc, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xfc, 0x00), + PHYREGS(0x0818, 0x0814, 0x0810, 0x01fa, 0x01fb, 0x01fc), + }, + { .freq = 5180, + RADIOREGS3(0xb6, 0x01, 0x01, 0x02, 0x06, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xef, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xfc, 0x00, 0xef, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xfc, 0x00), + PHYREGS(0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb), + }, + { .freq = 5190, + RADIOREGS3(0xb6, 0x01, 0x01, 0x02, 0x07, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xef, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xfc, 0x00, 0xef, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xfc, 0x00), + PHYREGS(0x0820, 0x081c, 0x0818, 0x01f8, 0x01f9, 0x01fa), + }, + { .freq = 5200, + RADIOREGS3(0xaf, 0x01, 0x01, 0x02, 0x08, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xef, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xfc, 0x00, 0xef, 0x00, 0x06, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xfc, 0x00), + PHYREGS(0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9), + }, + { .freq = 5210, + RADIOREGS3(0xaf, 0x01, 0x01, 0x02, 0x09, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xdf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xfc, 0x00, 0xdf, 0x00, 0x06, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xfc, 0x00), + PHYREGS(0x0828, 0x0824, 0x0820, 0x01f6, 0x01f7, 0x01f8), + }, + { .freq = 5220, + RADIOREGS3(0xa7, 0x01, 0x01, 0x02, 0x0a, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xdf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xfc, 0x00, 0xdf, 0x00, 0x06, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xfc, 0x00), + PHYREGS(0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7), + }, + { .freq = 5230, + RADIOREGS3(0xa7, 0x01, 0x01, 0x02, 0x0b, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xdf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xfc, 0x00, 0xdf, 0x00, 0x06, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xfc, 0x00), + PHYREGS(0x0830, 0x082c, 0x0828, 0x01f4, 0x01f5, 0x01f6), + }, + { .freq = 5240, + RADIOREGS3(0xa0, 0x01, 0x01, 0x02, 0x0c, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xcf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xfc, 0x00, 0xcf, 0x00, 0x06, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xfc, 0x00), + PHYREGS(0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5), + }, + { .freq = 5250, + RADIOREGS3(0xa0, 0x01, 0x01, 0x02, 0x0d, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xcf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xfc, 0x00, 0xcf, 0x00, 0x06, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xfc, 0x00), + PHYREGS(0x0838, 0x0834, 0x0830, 0x01f2, 0x01f3, 0x01f4), + }, + { .freq = 5260, + RADIOREGS3(0x98, 0x01, 0x01, 0x02, 0x0e, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xcf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xfc, 0x00, 0xcf, 0x00, 0x06, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xfc, 0x00), + PHYREGS(0x083c, 0x0838, 0x0834, 0x01f1, 0x01f2, 0x01f3), + }, + { .freq = 5270, + RADIOREGS3(0x98, 0x01, 0x01, 0x02, 0x0f, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00, + 0xff, 0xcf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xfc, 0x00, 0xcf, 0x00, 0x06, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xfc, 0x00), + PHYREGS(0x0840, 0x083c, 0x0838, 0x01f0, 0x01f1, 0x01f2), + }, + { .freq = 5280, + RADIOREGS3(0x91, 0x01, 0x01, 0x02, 0x10, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00, + 0xff, 0xbf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xfc, 0x00, 0xbf, 0x00, 0x06, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xfc, 0x00), + PHYREGS(0x0844, 0x0840, 0x083c, 0x01f0, 0x01f0, 0x01f1), + }, + { .freq = 5290, + RADIOREGS3(0x91, 0x01, 0x01, 0x02, 0x11, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00, + 0xff, 0xbf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xfc, 0x00, 0xbf, 0x00, 0x06, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xfc, 0x00), + PHYREGS(0x0848, 0x0844, 0x0840, 0x01ef, 0x01f0, 0x01f0), + }, + { .freq = 5300, + RADIOREGS3(0x8a, 0x01, 0x01, 0x02, 0x12, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, + 0xff, 0xbf, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xfc, 0x00, 0xbf, 0x00, 0x05, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xfc, 0x00), + PHYREGS(0x084c, 0x0848, 0x0844, 0x01ee, 0x01ef, 0x01f0), + }, + { .freq = 5310, + RADIOREGS3(0x8a, 0x01, 0x01, 0x02, 0x13, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, + 0xff, 0xbf, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xfa, 0x00, 0xbf, 0x00, 0x05, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xfa, 0x00), + PHYREGS(0x0850, 0x084c, 0x0848, 0x01ed, 0x01ee, 0x01ef), + }, + { .freq = 5320, + RADIOREGS3(0x83, 0x01, 0x01, 0x02, 0x14, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, + 0xff, 0xbf, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xfa, 0x00, 0xbf, 0x00, 0x05, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xfa, 0x00), + PHYREGS(0x0854, 0x0850, 0x084c, 0x01ec, 0x01ed, 0x01ee), + }, + { .freq = 5330, + RADIOREGS3(0x83, 0x01, 0x01, 0x02, 0x15, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, + 0xff, 0xaf, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xfa, 0x00, 0xaf, 0x00, 0x05, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xfa, 0x00), + PHYREGS(0x0858, 0x0854, 0x0850, 0x01eb, 0x01ec, 0x01ed), + }, + { .freq = 5340, + RADIOREGS3(0x7c, 0x01, 0x01, 0x02, 0x16, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, + 0xff, 0xaf, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xfa, 0x00, 0xaf, 0x00, 0x05, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xfa, 0x00), + PHYREGS(0x085c, 0x0858, 0x0854, 0x01ea, 0x01eb, 0x01ec), + }, + { .freq = 5350, + RADIOREGS3(0x7c, 0x01, 0x01, 0x02, 0x17, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, + 0xff, 0x9f, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xfa, 0x00, 0x9f, 0x00, 0x05, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xfa, 0x00), + PHYREGS(0x0860, 0x085c, 0x0858, 0x01e9, 0x01ea, 0x01eb), + }, + { .freq = 5360, + RADIOREGS3(0x75, 0x01, 0x01, 0x02, 0x18, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, + 0xff, 0x9f, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xfa, 0x00, 0x9f, 0x00, 0x05, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xfa, 0x00), + PHYREGS(0x0864, 0x0860, 0x085c, 0x01e8, 0x01e9, 0x01ea), + }, + { .freq = 5370, + RADIOREGS3(0x75, 0x01, 0x01, 0x02, 0x19, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, + 0xff, 0x9f, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xfa, 0x00, 0x9f, 0x00, 0x05, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xfa, 0x00), + PHYREGS(0x0868, 0x0864, 0x0860, 0x01e7, 0x01e8, 0x01e9), + }, + { .freq = 5380, + RADIOREGS3(0x6e, 0x01, 0x01, 0x02, 0x1a, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, + 0xff, 0x9f, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xfa, 0x00, 0x9f, 0x00, 0x05, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xfa, 0x00), + PHYREGS(0x086c, 0x0868, 0x0864, 0x01e6, 0x01e7, 0x01e8), + }, + { .freq = 5390, + RADIOREGS3(0x6e, 0x01, 0x01, 0x02, 0x1b, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, + 0xff, 0x8f, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xfa, 0x00, 0x8f, 0x00, 0x05, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xfa, 0x00), + PHYREGS(0x0870, 0x086c, 0x0868, 0x01e5, 0x01e6, 0x01e7), + }, + { .freq = 5400, + RADIOREGS3(0x67, 0x01, 0x01, 0x02, 0x1c, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, + 0xc8, 0x8f, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08, + 0x00, 0xfa, 0x00, 0x8f, 0x00, 0x04, 0x00, 0x7f, + 0x00, 0x08, 0x00, 0xfa, 0x00), + PHYREGS(0x0874, 0x0870, 0x086c, 0x01e5, 0x01e5, 0x01e6), + }, + { .freq = 5410, + RADIOREGS3(0x67, 0x01, 0x01, 0x02, 0x1d, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, + 0xc8, 0x8f, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08, + 0x00, 0xfa, 0x00, 0x8f, 0x00, 0x04, 0x00, 0x7f, + 0x00, 0x08, 0x00, 0xfa, 0x00), + PHYREGS(0x0878, 0x0874, 0x0870, 0x01e4, 0x01e5, 0x01e5), + }, + { .freq = 5420, + RADIOREGS3(0x61, 0x01, 0x01, 0x02, 0x1e, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, + 0xc8, 0x8e, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08, + 0x00, 0xfa, 0x00, 0x8e, 0x00, 0x04, 0x00, 0x7f, + 0x00, 0x08, 0x00, 0xfa, 0x00), + PHYREGS(0x087c, 0x0878, 0x0874, 0x01e3, 0x01e4, 0x01e5), + }, + { .freq = 5430, + RADIOREGS3(0x61, 0x01, 0x01, 0x02, 0x1f, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, + 0xc8, 0x8e, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08, + 0x00, 0xfa, 0x00, 0x8e, 0x00, 0x04, 0x00, 0x7f, + 0x00, 0x08, 0x00, 0xfa, 0x00), + PHYREGS(0x0880, 0x087c, 0x0878, 0x01e2, 0x01e3, 0x01e4), + }, + { .freq = 5440, + RADIOREGS3(0x5a, 0x01, 0x01, 0x02, 0x20, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, + 0xc8, 0x7e, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08, + 0x00, 0xfa, 0x00, 0x7e, 0x00, 0x04, 0x00, 0x7f, + 0x00, 0x08, 0x00, 0xfa, 0x00), + PHYREGS(0x0884, 0x0880, 0x087c, 0x01e1, 0x01e2, 0x01e3), + }, + { .freq = 5450, + RADIOREGS3(0x5a, 0x01, 0x01, 0x02, 0x21, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, + 0xc8, 0x7d, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08, + 0x00, 0xfa, 0x00, 0x7d, 0x00, 0x04, 0x00, 0x7f, + 0x00, 0x08, 0x00, 0xfa, 0x00), + PHYREGS(0x0888, 0x0884, 0x0880, 0x01e0, 0x01e1, 0x01e2), + }, + { .freq = 5460, + RADIOREGS3(0x53, 0x01, 0x01, 0x02, 0x22, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, + 0xc8, 0x6d, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08, + 0x00, 0xf8, 0x00, 0x6d, 0x00, 0x04, 0x00, 0x7f, + 0x00, 0x08, 0x00, 0xf8, 0x00), + PHYREGS(0x088c, 0x0888, 0x0884, 0x01df, 0x01e0, 0x01e1), + }, + { .freq = 5470, + RADIOREGS3(0x53, 0x01, 0x01, 0x02, 0x23, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, + 0xc8, 0x6d, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08, + 0x00, 0xf8, 0x00, 0x6d, 0x00, 0x04, 0x00, 0x7f, + 0x00, 0x08, 0x00, 0xf8, 0x00), + PHYREGS(0x0890, 0x088c, 0x0888, 0x01de, 0x01df, 0x01e0), + }, + { .freq = 5480, + RADIOREGS3(0x4d, 0x01, 0x01, 0x02, 0x24, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, + 0xc8, 0x5d, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08, + 0x00, 0xf8, 0x00, 0x5d, 0x00, 0x04, 0x00, 0x7f, + 0x00, 0x08, 0x00, 0xf8, 0x00), + PHYREGS(0x0894, 0x0890, 0x088c, 0x01dd, 0x01de, 0x01df), + }, + { .freq = 5490, + RADIOREGS3(0x4d, 0x01, 0x01, 0x02, 0x25, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, + 0xc8, 0x5c, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08, + 0x00, 0xf8, 0x00, 0x5c, 0x00, 0x04, 0x00, 0x7f, + 0x00, 0x08, 0x00, 0xf8, 0x00), + PHYREGS(0x0898, 0x0894, 0x0890, 0x01dd, 0x01dd, 0x01de), + }, + { .freq = 5500, + RADIOREGS3(0x47, 0x01, 0x01, 0x02, 0x26, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, + 0x84, 0x5c, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf8, 0x00, 0x5c, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf8, 0x00), + PHYREGS(0x089c, 0x0898, 0x0894, 0x01dc, 0x01dd, 0x01dd), + }, + { .freq = 5510, + RADIOREGS3(0x47, 0x01, 0x01, 0x02, 0x27, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, + 0x84, 0x4c, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf8, 0x00, 0x4c, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf8, 0x00), + PHYREGS(0x08a0, 0x089c, 0x0898, 0x01db, 0x01dc, 0x01dd), + }, + { .freq = 5520, + RADIOREGS3(0x40, 0x01, 0x01, 0x02, 0x28, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, + 0x84, 0x4c, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf8, 0x00, 0x4c, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf8, 0x00), + PHYREGS(0x08a4, 0x08a0, 0x089c, 0x01da, 0x01db, 0x01dc), + }, + { .freq = 5530, + RADIOREGS3(0x40, 0x01, 0x01, 0x02, 0x29, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, + 0x84, 0x3b, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf8, 0x00, 0x3b, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf8, 0x00), + PHYREGS(0x08a8, 0x08a4, 0x08a0, 0x01d9, 0x01da, 0x01db), + }, + { .freq = 5540, + RADIOREGS3(0x3a, 0x01, 0x01, 0x02, 0x2a, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, + 0x84, 0x3b, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf8, 0x00, 0x3b, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf8, 0x00), + PHYREGS(0x08ac, 0x08a8, 0x08a4, 0x01d8, 0x01d9, 0x01da), + }, + { .freq = 5550, + RADIOREGS3(0x3a, 0x01, 0x01, 0x02, 0x2b, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, + 0x84, 0x3b, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf8, 0x00, 0x3b, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf8, 0x00), + PHYREGS(0x08b0, 0x08ac, 0x08a8, 0x01d7, 0x01d8, 0x01d9), + }, + { .freq = 5560, + RADIOREGS3(0x34, 0x01, 0x01, 0x02, 0x2c, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, + 0x84, 0x2b, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf8, 0x00, 0x2b, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf8, 0x00), + PHYREGS(0x08b4, 0x08b0, 0x08ac, 0x01d7, 0x01d7, 0x01d8), + }, + { .freq = 5570, + RADIOREGS3(0x34, 0x01, 0x01, 0x02, 0x2d, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, + 0x84, 0x2a, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf8, 0x00, 0x2a, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf8, 0x00), + PHYREGS(0x08b8, 0x08b4, 0x08b0, 0x01d6, 0x01d7, 0x01d7), + }, + { .freq = 5580, + RADIOREGS3(0x2e, 0x01, 0x01, 0x02, 0x2e, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, + 0x84, 0x1a, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf8, 0x00, 0x1a, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf8, 0x00), + PHYREGS(0x08bc, 0x08b8, 0x08b4, 0x01d5, 0x01d6, 0x01d7), + }, + { .freq = 5590, + RADIOREGS3(0x2e, 0x01, 0x01, 0x02, 0x2f, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, + 0x84, 0x1a, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf8, 0x00, 0x1a, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf8, 0x00), + PHYREGS(0x08c0, 0x08bc, 0x08b8, 0x01d4, 0x01d5, 0x01d6), + }, + { .freq = 5600, + RADIOREGS3(0x28, 0x01, 0x01, 0x02, 0x30, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, + 0x70, 0x1a, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf8, 0x00, 0x1a, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf8, 0x00), + PHYREGS(0x08c4, 0x08c0, 0x08bc, 0x01d3, 0x01d4, 0x01d5), + }, + { .freq = 5610, + RADIOREGS3(0x28, 0x01, 0x01, 0x02, 0x31, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, + 0x70, 0x19, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf8, 0x00, 0x19, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf8, 0x00), + PHYREGS(0x08c8, 0x08c4, 0x08c0, 0x01d2, 0x01d3, 0x01d4), + }, + { .freq = 5620, + RADIOREGS3(0x21, 0x01, 0x01, 0x02, 0x32, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, + 0x70, 0x19, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf8, 0x00, 0x19, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf8, 0x00), + PHYREGS(0x08cc, 0x08c8, 0x08c4, 0x01d2, 0x01d2, 0x01d3), + }, + { .freq = 5630, + RADIOREGS3(0x21, 0x01, 0x01, 0x02, 0x33, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, + 0x70, 0x09, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf8, 0x00, 0x09, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf8, 0x00), + PHYREGS(0x08d0, 0x08cc, 0x08c8, 0x01d1, 0x01d2, 0x01d2), + }, + { .freq = 5640, + RADIOREGS3(0x1c, 0x01, 0x01, 0x02, 0x34, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, + 0x70, 0x09, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf8, 0x00, 0x09, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf8, 0x00), + PHYREGS(0x08d4, 0x08d0, 0x08cc, 0x01d0, 0x01d1, 0x01d2), + }, + { .freq = 5650, + RADIOREGS3(0x1c, 0x01, 0x01, 0x02, 0x35, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, + 0x70, 0x08, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf8, 0x00, 0x08, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf8, 0x00), + PHYREGS(0x08d8, 0x08d4, 0x08d0, 0x01cf, 0x01d0, 0x01d1), + }, + { .freq = 5660, + RADIOREGS3(0x16, 0x01, 0x01, 0x02, 0x36, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, + 0x70, 0x08, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf6, 0x00, 0x08, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf6, 0x00), + PHYREGS(0x08dc, 0x08d8, 0x08d4, 0x01ce, 0x01cf, 0x01d0), + }, + { .freq = 5670, + RADIOREGS3(0x16, 0x01, 0x01, 0x02, 0x37, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, + 0x70, 0x08, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf6, 0x00, 0x08, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf6, 0x00), + PHYREGS(0x08e0, 0x08dc, 0x08d8, 0x01ce, 0x01ce, 0x01cf), + }, + { .freq = 5680, + RADIOREGS3(0x10, 0x01, 0x01, 0x02, 0x38, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, + 0x70, 0x08, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf6, 0x00, 0x08, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf6, 0x00), + PHYREGS(0x08e4, 0x08e0, 0x08dc, 0x01cd, 0x01ce, 0x01ce), + }, + { .freq = 5690, + RADIOREGS3(0x10, 0x01, 0x01, 0x02, 0x39, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, + 0x70, 0x07, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf6, 0x00, 0x07, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf6, 0x00), + PHYREGS(0x08e8, 0x08e4, 0x08e0, 0x01cc, 0x01cd, 0x01ce), + }, + { .freq = 5700, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3a, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x07, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf6, 0x00, 0x07, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf6, 0x00), + PHYREGS(0x08ec, 0x08e8, 0x08e4, 0x01cb, 0x01cc, 0x01cd), + }, + { .freq = 5710, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3b, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x07, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x07, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00), + PHYREGS(0x08f0, 0x08ec, 0x08e8, 0x01ca, 0x01cb, 0x01cc), + }, + { .freq = 5720, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3c, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x07, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x07, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00), + PHYREGS(0x08f4, 0x08f0, 0x08ec, 0x01c9, 0x01ca, 0x01cb), + }, + { .freq = 5725, + RADIOREGS3(0x03, 0x01, 0x02, 0x04, 0x79, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x06, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x06, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00), + PHYREGS(0x08f6, 0x08f2, 0x08ee, 0x01c9, 0x01ca, 0x01cb), + }, + { .freq = 5730, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3d, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x06, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x06, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00), + PHYREGS(0x08f8, 0x08f4, 0x08f0, 0x01c9, 0x01c9, 0x01ca), + }, + { .freq = 5735, + RADIOREGS3(0x03, 0x01, 0x02, 0x04, 0x7b, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x06, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x06, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00), + PHYREGS(0x08fa, 0x08f6, 0x08f2, 0x01c8, 0x01c9, 0x01ca), + }, + { .freq = 5740, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3e, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x06, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x06, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00), + PHYREGS(0x08fc, 0x08f8, 0x08f4, 0x01c8, 0x01c9, 0x01c9), + }, + { .freq = 5745, + RADIOREGS3(0xfe, 0x00, 0x02, 0x04, 0x7d, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x06, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x06, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00), + PHYREGS(0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9), + }, + { .freq = 5750, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3f, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x06, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x06, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00), + PHYREGS(0x0900, 0x08fc, 0x08f8, 0x01c7, 0x01c8, 0x01c9), + }, + { .freq = 5755, + RADIOREGS3(0xfe, 0x00, 0x02, 0x04, 0x7f, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x05, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x05, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00), + PHYREGS(0x0902, 0x08fe, 0x08fa, 0x01c7, 0x01c8, 0x01c8), + }, + { .freq = 5760, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x40, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x05, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x05, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00), + PHYREGS(0x0904, 0x0900, 0x08fc, 0x01c6, 0x01c7, 0x01c8), + }, + { .freq = 5765, + RADIOREGS3(0xf8, 0x00, 0x02, 0x04, 0x81, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x05, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x05, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00), + PHYREGS(0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8), + }, + { .freq = 5770, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x41, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x05, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x05, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00), + PHYREGS(0x0908, 0x0904, 0x0900, 0x01c6, 0x01c6, 0x01c7), + }, + { .freq = 5775, + RADIOREGS3(0xf8, 0x00, 0x02, 0x04, 0x83, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x05, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x05, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00), + PHYREGS(0x090a, 0x0906, 0x0902, 0x01c5, 0x01c6, 0x01c7), + }, + { .freq = 5780, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x42, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x05, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x05, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00), + PHYREGS(0x090c, 0x0908, 0x0904, 0x01c5, 0x01c6, 0x01c6), + }, + { .freq = 5785, + RADIOREGS3(0xf2, 0x00, 0x02, 0x04, 0x85, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00, + 0x40, 0x04, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x04, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00), + PHYREGS(0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6), + }, + { .freq = 5790, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x43, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00, + 0x40, 0x04, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x04, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00), + PHYREGS(0x0910, 0x090c, 0x0908, 0x01c4, 0x01c5, 0x01c6), + }, + { .freq = 5795, + RADIOREGS3(0xf2, 0x00, 0x02, 0x04, 0x87, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00, + 0x40, 0x04, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x04, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00), + PHYREGS(0x0912, 0x090e, 0x090a, 0x01c4, 0x01c4, 0x01c5), + }, + { .freq = 5800, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x44, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, + 0x20, 0x04, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00), + PHYREGS(0x0914, 0x0910, 0x090c, 0x01c3, 0x01c4, 0x01c5), + }, + { .freq = 5805, + RADIOREGS3(0xed, 0x00, 0x02, 0x04, 0x89, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, + 0x20, 0x04, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00), + PHYREGS(0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4), + }, + { .freq = 5810, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x45, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, + 0x20, 0x04, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00), + PHYREGS(0x0918, 0x0914, 0x0910, 0x01c2, 0x01c3, 0x01c4), + }, + { .freq = 5815, + RADIOREGS3(0xed, 0x00, 0x02, 0x04, 0x8b, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, + 0x20, 0x04, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00), + PHYREGS(0x091a, 0x0916, 0x0912, 0x01c2, 0x01c3, 0x01c4), + }, + { .freq = 5820, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x46, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, + 0x20, 0x03, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x03, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00), + PHYREGS(0x091c, 0x0918, 0x0914, 0x01c2, 0x01c2, 0x01c3), + }, + { .freq = 5825, + RADIOREGS3(0xed, 0x00, 0x02, 0x04, 0x8d, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, + 0x20, 0x03, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x03, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00), + PHYREGS(0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3), + }, + { .freq = 5830, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x47, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, + 0x20, 0x03, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x03, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00), + PHYREGS(0x0920, 0x091c, 0x0918, 0x01c1, 0x01c2, 0x01c2), + }, + { .freq = 5840, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x48, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, + 0x20, 0x03, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x03, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00), + PHYREGS(0x0924, 0x0920, 0x091c, 0x01c0, 0x01c1, 0x01c2), + }, + { .freq = 5850, + RADIOREGS3(0xe0, 0x00, 0x01, 0x02, 0x49, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, + 0x20, 0x03, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x03, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00), + PHYREGS(0x0928, 0x0924, 0x0920, 0x01bf, 0x01c0, 0x01c1), + }, + { .freq = 5860, + RADIOREGS3(0xde, 0x00, 0x01, 0x02, 0x4a, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, + 0x20, 0x03, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf2, 0x00, 0x03, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf2, 0x00), + PHYREGS(0x092c, 0x0928, 0x0924, 0x01bf, 0x01bf, 0x01c0), + }, + { .freq = 5870, + RADIOREGS3(0xdb, 0x00, 0x01, 0x02, 0x4b, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, + 0x20, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf2, 0x00, 0x02, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf2, 0x00), + PHYREGS(0x0930, 0x092c, 0x0928, 0x01be, 0x01bf, 0x01bf), + }, + { .freq = 5880, + RADIOREGS3(0xd8, 0x00, 0x01, 0x02, 0x4c, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, + 0x20, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf2, 0x00, 0x02, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf2, 0x00), + PHYREGS(0x0934, 0x0930, 0x092c, 0x01bd, 0x01be, 0x01bf), + }, + { .freq = 5890, + RADIOREGS3(0xd6, 0x00, 0x01, 0x02, 0x4d, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, + 0x20, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf2, 0x00, 0x02, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf2, 0x00), + PHYREGS(0x0938, 0x0934, 0x0930, 0x01bc, 0x01bd, 0x01be), + }, + { .freq = 5900, + RADIOREGS3(0xd3, 0x00, 0x01, 0x02, 0x4e, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x87, 0x03, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x05, + 0x00, 0xf2, 0x00, 0x02, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0x05, 0x00, 0xf2, 0x00), + PHYREGS(0x093c, 0x0938, 0x0934, 0x01bc, 0x01bc, 0x01bd), + }, + { .freq = 5910, + RADIOREGS3(0xd6, 0x00, 0x01, 0x02, 0x4f, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x87, 0x03, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x05, + 0x00, 0xf2, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0x05, 0x00, 0xf2, 0x00), + PHYREGS(0x0940, 0x093c, 0x0938, 0x01bb, 0x01bc, 0x01bc), + }, + { .freq = 2412, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x6c, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x04, 0x04, 0x04, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x05, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0f, 0x00, 0xff, 0x00, 0x05, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0f), + PHYREGS(0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443), + }, + { .freq = 2417, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x71, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x05, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0f, 0x00, 0xff, 0x00, 0x05, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0f), + PHYREGS(0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441), + }, + { .freq = 2422, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x76, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x05, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0f, 0x00, 0xff, 0x00, 0x05, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0f), + PHYREGS(0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f), + }, + { .freq = 2427, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x7b, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0xfd, 0x00, 0x05, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0f, 0x00, 0xfd, 0x00, 0x05, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0f), + PHYREGS(0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d), + }, + { .freq = 2432, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x80, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0xfb, 0x00, 0x05, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0f, 0x00, 0xfb, 0x00, 0x05, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0f), + PHYREGS(0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a), + }, + { .freq = 2437, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x85, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0xfa, 0x00, 0x05, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0f, 0x00, 0xfa, 0x00, 0x05, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0f), + PHYREGS(0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438), + }, + { .freq = 2442, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x8a, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0xf8, 0x00, 0x05, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0f, 0x00, 0xf8, 0x00, 0x05, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0f), + PHYREGS(0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436), + }, + { .freq = 2447, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x8f, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0xf7, 0x00, 0x05, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0f, 0x00, 0xf7, 0x00, 0x05, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0f), + PHYREGS(0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434), + }, + { .freq = 2452, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x94, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0xf6, 0x00, 0x05, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0f, 0x00, 0xf6, 0x00, 0x05, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0f), + PHYREGS(0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431), + }, + { .freq = 2457, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x99, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0xf5, 0x00, 0x05, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0d, 0x00, 0xf5, 0x00, 0x05, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0d), + PHYREGS(0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f), + }, + { .freq = 2462, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x9e, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0xf4, 0x00, 0x05, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0d, 0x00, 0xf4, 0x00, 0x05, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0d), + PHYREGS(0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d), + }, + { .freq = 2467, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0xa3, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0xf3, 0x00, 0x05, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0d, 0x00, 0xf3, 0x00, 0x05, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0d), + PHYREGS(0x03df, 0x03db, 0x03d7, 0x0422, 0x0427, 0x042b), + }, + { .freq = 2472, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0xa8, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0xf2, 0x00, 0x05, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0d, 0x00, 0xf2, 0x00, 0x05, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0d), + PHYREGS(0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429), + }, + { .freq = 2484, + RADIOREGS3(0xff, 0x01, 0x03, 0x09, 0xb4, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0xf0, 0x00, 0x05, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0d, 0x00, 0xf0, 0x00, 0x05, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0d), + PHYREGS(0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424), + }, +}; + +static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev4[] = { + { .freq = 4920, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x0e, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xff, 0x00), + PHYREGS(0x07b4, 0x07b0, 0x07ac, 0x0214, 0x0215, 0x0216), + }, + { .freq = 4930, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xed, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x0e, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xff, 0x00), + PHYREGS(0x07b8, 0x07b4, 0x07b0, 0x0213, 0x0214, 0x0215), + }, + { .freq = 4940, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xee, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x0e, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xff, 0x00), + PHYREGS(0x07bc, 0x07b8, 0x07b4, 0x0212, 0x0213, 0x0214), + }, + { .freq = 4950, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xef, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x0e, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xff, 0x00), + PHYREGS(0x07c0, 0x07bc, 0x07b8, 0x0211, 0x0212, 0x0213), + }, + { .freq = 4960, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf0, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x0e, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xff, 0x00), + PHYREGS(0x07c4, 0x07c0, 0x07bc, 0x020f, 0x0211, 0x0212), + }, + { .freq = 4970, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf1, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x0e, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xff, 0x00), + PHYREGS(0x07c8, 0x07c4, 0x07c0, 0x020e, 0x020f, 0x0211), + }, + { .freq = 4980, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf2, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x0e, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xff, 0x00), + PHYREGS(0x07cc, 0x07c8, 0x07c4, 0x020d, 0x020e, 0x020f), + }, + { .freq = 4990, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf3, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x0e, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xff, 0x00), + PHYREGS(0x07d0, 0x07cc, 0x07c8, 0x020c, 0x020d, 0x020e), + }, + { .freq = 5000, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf4, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xff, 0x00), + PHYREGS(0x07d4, 0x07d0, 0x07cc, 0x020b, 0x020c, 0x020d), + }, + { .freq = 5010, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf5, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xff, 0x00), + PHYREGS(0x07d8, 0x07d4, 0x07d0, 0x020a, 0x020b, 0x020c), + }, + { .freq = 5020, + RADIOREGS3(0xf7, 0x01, 0x01, 0x01, 0xf6, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xff, 0x00), + PHYREGS(0x07dc, 0x07d8, 0x07d4, 0x0209, 0x020a, 0x020b), + }, + { .freq = 5030, + RADIOREGS3(0xf7, 0x01, 0x01, 0x01, 0xf7, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xff, 0x00), + PHYREGS(0x07e0, 0x07dc, 0x07d8, 0x0208, 0x0209, 0x020a), + }, + { .freq = 5040, + RADIOREGS3(0xef, 0x01, 0x01, 0x01, 0xf8, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xff, 0x00), + PHYREGS(0x07e4, 0x07e0, 0x07dc, 0x0207, 0x0208, 0x0209), + }, + { .freq = 5050, + RADIOREGS3(0xef, 0x01, 0x01, 0x01, 0xf9, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xff, 0x00), + PHYREGS(0x07e8, 0x07e4, 0x07e0, 0x0206, 0x0207, 0x0208), + }, + { .freq = 5060, + RADIOREGS3(0xe6, 0x01, 0x01, 0x01, 0xfa, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xff, 0x00), + PHYREGS(0x07ec, 0x07e8, 0x07e4, 0x0205, 0x0206, 0x0207), + }, + { .freq = 5070, + RADIOREGS3(0xe6, 0x01, 0x01, 0x01, 0xfb, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xff, 0x00), + PHYREGS(0x07f0, 0x07ec, 0x07e8, 0x0204, 0x0205, 0x0206), + }, + { .freq = 5080, + RADIOREGS3(0xde, 0x01, 0x01, 0x01, 0xfc, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xff, 0x00), + PHYREGS(0x07f4, 0x07f0, 0x07ec, 0x0203, 0x0204, 0x0205), + }, + { .freq = 5090, + RADIOREGS3(0xde, 0x01, 0x01, 0x01, 0xfd, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xff, 0x00), + PHYREGS(0x07f8, 0x07f4, 0x07f0, 0x0202, 0x0203, 0x0204), + }, + { .freq = 5100, + RADIOREGS3(0xd6, 0x01, 0x01, 0x01, 0xfe, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfe, 0x00, 0xff, 0x00, 0x0c, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfe, 0x00), + PHYREGS(0x07fc, 0x07f8, 0x07f4, 0x0201, 0x0202, 0x0203), + }, + { .freq = 5110, + RADIOREGS3(0xd6, 0x01, 0x01, 0x01, 0xff, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfe, 0x00, 0xff, 0x00, 0x0c, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfe, 0x00), + PHYREGS(0x0800, 0x07fc, 0x07f8, 0x0200, 0x0201, 0x0202), + }, + { .freq = 5120, + RADIOREGS3(0xce, 0x01, 0x01, 0x02, 0x00, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfe, 0x00, 0xff, 0x00, 0x0c, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfe, 0x00), + PHYREGS(0x0804, 0x0800, 0x07fc, 0x01ff, 0x0200, 0x0201), + }, + { .freq = 5130, + RADIOREGS3(0xce, 0x01, 0x01, 0x02, 0x01, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfe, 0x00, 0xff, 0x00, 0x0c, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfe, 0x00), + PHYREGS(0x0808, 0x0804, 0x0800, 0x01fe, 0x01ff, 0x0200), + }, + { .freq = 5140, + RADIOREGS3(0xc6, 0x01, 0x01, 0x02, 0x02, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfe, 0x00, 0xff, 0x00, 0x0c, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfe, 0x00), + PHYREGS(0x080c, 0x0808, 0x0804, 0x01fd, 0x01fe, 0x01ff), + }, + { .freq = 5160, + RADIOREGS3(0xbe, 0x01, 0x01, 0x02, 0x04, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfe, 0x00, 0xff, 0x00, 0x0c, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfe, 0x00), + PHYREGS(0x0814, 0x0810, 0x080c, 0x01fb, 0x01fc, 0x01fd), + }, + { .freq = 5170, + RADIOREGS3(0xbe, 0x01, 0x01, 0x02, 0x05, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfe, 0x00, 0xff, 0x00, 0x0c, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfe, 0x00), + PHYREGS(0x0818, 0x0814, 0x0810, 0x01fa, 0x01fb, 0x01fc), + }, + { .freq = 5180, + RADIOREGS3(0xb6, 0x01, 0x01, 0x02, 0x06, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xef, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfe, 0x00, 0xef, 0x00, 0x0c, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfe, 0x00), + PHYREGS(0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb), + }, + { .freq = 5190, + RADIOREGS3(0xb6, 0x01, 0x01, 0x02, 0x07, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xef, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfe, 0x00, 0xef, 0x00, 0x0c, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfe, 0x00), + PHYREGS(0x0820, 0x081c, 0x0818, 0x01f8, 0x01f9, 0x01fa), + }, + { .freq = 5200, + RADIOREGS3(0xaf, 0x01, 0x01, 0x02, 0x08, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xef, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfc, 0x00, 0xef, 0x00, 0x0a, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfc, 0x00), + PHYREGS(0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9), + }, + { .freq = 5210, + RADIOREGS3(0xaf, 0x01, 0x01, 0x02, 0x09, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xdf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfc, 0x00, 0xdf, 0x00, 0x0a, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfc, 0x00), + PHYREGS(0x0828, 0x0824, 0x0820, 0x01f6, 0x01f7, 0x01f8), + }, + { .freq = 5220, + RADIOREGS3(0xa7, 0x01, 0x01, 0x02, 0x0a, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xdf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfc, 0x00, 0xdf, 0x00, 0x0a, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfc, 0x00), + PHYREGS(0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7), + }, + { .freq = 5230, + RADIOREGS3(0xa7, 0x01, 0x01, 0x02, 0x0b, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xdf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfc, 0x00, 0xdf, 0x00, 0x0a, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfc, 0x00), + PHYREGS(0x0830, 0x082c, 0x0828, 0x01f4, 0x01f5, 0x01f6), + }, + { .freq = 5240, + RADIOREGS3(0xa0, 0x01, 0x01, 0x02, 0x0c, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xcf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfc, 0x00, 0xcf, 0x00, 0x0a, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfc, 0x00), + PHYREGS(0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5), + }, + { .freq = 5250, + RADIOREGS3(0xa0, 0x01, 0x01, 0x02, 0x0d, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xcf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfc, 0x00, 0xcf, 0x00, 0x0a, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfc, 0x00), + PHYREGS(0x0838, 0x0834, 0x0830, 0x01f2, 0x01f3, 0x01f4), + }, + { .freq = 5260, + RADIOREGS3(0x98, 0x01, 0x01, 0x02, 0x0e, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xcf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfc, 0x00, 0xcf, 0x00, 0x0a, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfc, 0x00), + PHYREGS(0x083c, 0x0838, 0x0834, 0x01f1, 0x01f2, 0x01f3), + }, + { .freq = 5270, + RADIOREGS3(0x98, 0x01, 0x01, 0x02, 0x0f, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00, + 0xff, 0xcf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfc, 0x00, 0xcf, 0x00, 0x0a, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfc, 0x00), + PHYREGS(0x0840, 0x083c, 0x0838, 0x01f0, 0x01f1, 0x01f2), + }, + { .freq = 5280, + RADIOREGS3(0x91, 0x01, 0x01, 0x02, 0x10, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00, + 0xff, 0xbf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfc, 0x00, 0xbf, 0x00, 0x0a, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfc, 0x00), + PHYREGS(0x0844, 0x0840, 0x083c, 0x01f0, 0x01f0, 0x01f1), + }, + { .freq = 5290, + RADIOREGS3(0x91, 0x01, 0x01, 0x02, 0x11, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00, + 0xff, 0xbf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfc, 0x00, 0xbf, 0x00, 0x0a, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfc, 0x00), + PHYREGS(0x0848, 0x0844, 0x0840, 0x01ef, 0x01f0, 0x01f0), + }, + { .freq = 5300, + RADIOREGS3(0x8a, 0x01, 0x01, 0x02, 0x12, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, + 0xff, 0xbf, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfa, 0x00, 0xbf, 0x00, 0x08, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfa, 0x00), + PHYREGS(0x084c, 0x0848, 0x0844, 0x01ee, 0x01ef, 0x01f0), + }, + { .freq = 5310, + RADIOREGS3(0x8a, 0x01, 0x01, 0x02, 0x13, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, + 0xff, 0xbf, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfa, 0x00, 0xbf, 0x00, 0x08, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfa, 0x00), + PHYREGS(0x0850, 0x084c, 0x0848, 0x01ed, 0x01ee, 0x01ef), + }, + { .freq = 5320, + RADIOREGS3(0x83, 0x01, 0x01, 0x02, 0x14, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, + 0xff, 0xbf, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfa, 0x00, 0xbf, 0x00, 0x08, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfa, 0x00), + PHYREGS(0x0854, 0x0850, 0x084c, 0x01ec, 0x01ed, 0x01ee), + }, + { .freq = 5330, + RADIOREGS3(0x83, 0x01, 0x01, 0x02, 0x15, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, + 0xff, 0xaf, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfa, 0x00, 0xaf, 0x00, 0x08, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfa, 0x00), + PHYREGS(0x0858, 0x0854, 0x0850, 0x01eb, 0x01ec, 0x01ed), + }, + { .freq = 5340, + RADIOREGS3(0x7c, 0x01, 0x01, 0x02, 0x16, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, + 0xff, 0xaf, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfa, 0x00, 0xaf, 0x00, 0x08, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfa, 0x00), + PHYREGS(0x085c, 0x0858, 0x0854, 0x01ea, 0x01eb, 0x01ec), + }, + { .freq = 5350, + RADIOREGS3(0x7c, 0x01, 0x01, 0x02, 0x17, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, + 0xff, 0x9f, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfa, 0x00, 0x9f, 0x00, 0x08, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfa, 0x00), + PHYREGS(0x0860, 0x085c, 0x0858, 0x01e9, 0x01ea, 0x01eb), + }, + { .freq = 5360, + RADIOREGS3(0x75, 0x01, 0x01, 0x02, 0x18, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, + 0xff, 0x9f, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfa, 0x00, 0x9f, 0x00, 0x08, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfa, 0x00), + PHYREGS(0x0864, 0x0860, 0x085c, 0x01e8, 0x01e9, 0x01ea), + }, + { .freq = 5370, + RADIOREGS3(0x75, 0x01, 0x01, 0x02, 0x19, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, + 0xff, 0x9f, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfa, 0x00, 0x9f, 0x00, 0x08, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfa, 0x00), + PHYREGS(0x0868, 0x0864, 0x0860, 0x01e7, 0x01e8, 0x01e9), + }, + { .freq = 5380, + RADIOREGS3(0x6e, 0x01, 0x01, 0x02, 0x1a, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, + 0xff, 0x9f, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfa, 0x00, 0x9f, 0x00, 0x08, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfa, 0x00), + PHYREGS(0x086c, 0x0868, 0x0864, 0x01e6, 0x01e7, 0x01e8), + }, + { .freq = 5390, + RADIOREGS3(0x6e, 0x01, 0x01, 0x02, 0x1b, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, + 0xff, 0x8f, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfa, 0x00, 0x8f, 0x00, 0x08, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfa, 0x00), + PHYREGS(0x0870, 0x086c, 0x0868, 0x01e5, 0x01e6, 0x01e7), + }, + { .freq = 5400, + RADIOREGS3(0x67, 0x01, 0x01, 0x02, 0x1c, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, + 0xc8, 0x8f, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xf8, 0x00, 0x8f, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xf8, 0x00), + PHYREGS(0x0874, 0x0870, 0x086c, 0x01e5, 0x01e5, 0x01e6), + }, + { .freq = 5410, + RADIOREGS3(0x67, 0x01, 0x01, 0x02, 0x1d, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, + 0xc8, 0x8f, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xf8, 0x00, 0x8f, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xf8, 0x00), + PHYREGS(0x0878, 0x0874, 0x0870, 0x01e4, 0x01e5, 0x01e5), + }, + { .freq = 5420, + RADIOREGS3(0x61, 0x01, 0x01, 0x02, 0x1e, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, + 0xc8, 0x8e, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xf8, 0x00, 0x8e, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xf8, 0x00), + PHYREGS(0x087c, 0x0878, 0x0874, 0x01e3, 0x01e4, 0x01e5), + }, + { .freq = 5430, + RADIOREGS3(0x61, 0x01, 0x01, 0x02, 0x1f, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, + 0xc8, 0x8e, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xf8, 0x00, 0x8e, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xf8, 0x00), + PHYREGS(0x0880, 0x087c, 0x0878, 0x01e2, 0x01e3, 0x01e4), + }, + { .freq = 5440, + RADIOREGS3(0x5a, 0x01, 0x01, 0x02, 0x20, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, + 0xc8, 0x7e, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xf8, 0x00, 0x7e, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xf8, 0x00), + PHYREGS(0x0884, 0x0880, 0x087c, 0x01e1, 0x01e2, 0x01e3), + }, + { .freq = 5450, + RADIOREGS3(0x5a, 0x01, 0x01, 0x02, 0x21, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, + 0xc8, 0x7d, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xf8, 0x00, 0x7d, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xf8, 0x00), + PHYREGS(0x0888, 0x0884, 0x0880, 0x01e0, 0x01e1, 0x01e2), + }, + { .freq = 5460, + RADIOREGS3(0x53, 0x01, 0x01, 0x02, 0x22, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, + 0xc8, 0x6d, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xf8, 0x00, 0x6d, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xf8, 0x00), + PHYREGS(0x088c, 0x0888, 0x0884, 0x01df, 0x01e0, 0x01e1), + }, + { .freq = 5470, + RADIOREGS3(0x53, 0x01, 0x01, 0x02, 0x23, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, + 0xc8, 0x6d, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xf8, 0x00, 0x6d, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xf8, 0x00), + PHYREGS(0x0890, 0x088c, 0x0888, 0x01de, 0x01df, 0x01e0), + }, + { .freq = 5480, + RADIOREGS3(0x4d, 0x01, 0x01, 0x02, 0x24, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, + 0xc8, 0x5d, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xf8, 0x00, 0x5d, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xf8, 0x00), + PHYREGS(0x0894, 0x0890, 0x088c, 0x01dd, 0x01de, 0x01df), + }, + { .freq = 5490, + RADIOREGS3(0x4d, 0x01, 0x01, 0x02, 0x25, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, + 0xc8, 0x5c, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xf8, 0x00, 0x5c, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xf8, 0x00), + PHYREGS(0x0898, 0x0894, 0x0890, 0x01dd, 0x01dd, 0x01de), + }, + { .freq = 5500, + RADIOREGS3(0x47, 0x01, 0x01, 0x02, 0x26, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, + 0x84, 0x5c, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d, + 0x00, 0xf6, 0x00, 0x5c, 0x00, 0x06, 0x00, 0x7f, + 0x00, 0x0d, 0x00, 0xf6, 0x00), + PHYREGS(0x089c, 0x0898, 0x0894, 0x01dc, 0x01dd, 0x01dd), + }, + { .freq = 5510, + RADIOREGS3(0x47, 0x01, 0x01, 0x02, 0x27, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, + 0x84, 0x4c, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d, + 0x00, 0xf6, 0x00, 0x4c, 0x00, 0x06, 0x00, 0x7f, + 0x00, 0x0d, 0x00, 0xf6, 0x00), + PHYREGS(0x08a0, 0x089c, 0x0898, 0x01db, 0x01dc, 0x01dd), + }, + { .freq = 5520, + RADIOREGS3(0x40, 0x01, 0x01, 0x02, 0x28, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, + 0x84, 0x4c, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d, + 0x00, 0xf6, 0x00, 0x4c, 0x00, 0x06, 0x00, 0x7f, + 0x00, 0x0d, 0x00, 0xf6, 0x00), + PHYREGS(0x08a4, 0x08a0, 0x089c, 0x01da, 0x01db, 0x01dc), + }, + { .freq = 5530, + RADIOREGS3(0x40, 0x01, 0x01, 0x02, 0x29, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, + 0x84, 0x3b, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d, + 0x00, 0xf6, 0x00, 0x3b, 0x00, 0x06, 0x00, 0x7f, + 0x00, 0x0d, 0x00, 0xf6, 0x00), + PHYREGS(0x08a8, 0x08a4, 0x08a0, 0x01d9, 0x01da, 0x01db), + }, + { .freq = 5540, + RADIOREGS3(0x3a, 0x01, 0x01, 0x02, 0x2a, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, + 0x84, 0x3b, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d, + 0x00, 0xf6, 0x00, 0x3b, 0x00, 0x06, 0x00, 0x7f, + 0x00, 0x0d, 0x00, 0xf6, 0x00), + PHYREGS(0x08ac, 0x08a8, 0x08a4, 0x01d8, 0x01d9, 0x01da), + }, + { .freq = 5550, + RADIOREGS3(0x3a, 0x01, 0x01, 0x02, 0x2b, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, + 0x84, 0x3b, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d, + 0x00, 0xf6, 0x00, 0x3b, 0x00, 0x06, 0x00, 0x7f, + 0x00, 0x0d, 0x00, 0xf6, 0x00), + PHYREGS(0x08b0, 0x08ac, 0x08a8, 0x01d7, 0x01d8, 0x01d9), + }, + { .freq = 5560, + RADIOREGS3(0x34, 0x01, 0x01, 0x02, 0x2c, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, + 0x84, 0x2b, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d, + 0x00, 0xf6, 0x00, 0x2b, 0x00, 0x06, 0x00, 0x7f, + 0x00, 0x0d, 0x00, 0xf6, 0x00), + PHYREGS(0x08b4, 0x08b0, 0x08ac, 0x01d7, 0x01d7, 0x01d8), + }, + { .freq = 5570, + RADIOREGS3(0x34, 0x01, 0x01, 0x02, 0x2d, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, + 0x84, 0x2a, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d, + 0x00, 0xf6, 0x00, 0x2a, 0x00, 0x06, 0x00, 0x7f, + 0x00, 0x0d, 0x00, 0xf6, 0x00), + PHYREGS(0x08b8, 0x08b4, 0x08b0, 0x01d6, 0x01d7, 0x01d7), + }, + { .freq = 5580, + RADIOREGS3(0x2e, 0x01, 0x01, 0x02, 0x2e, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, + 0x84, 0x1a, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d, + 0x00, 0xf6, 0x00, 0x1a, 0x00, 0x06, 0x00, 0x7f, + 0x00, 0x0d, 0x00, 0xf6, 0x00), + PHYREGS(0x08bc, 0x08b8, 0x08b4, 0x01d5, 0x01d6, 0x01d7), + }, + { .freq = 5590, + RADIOREGS3(0x2e, 0x01, 0x01, 0x02, 0x2f, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, + 0x84, 0x1a, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d, + 0x00, 0xf6, 0x00, 0x1a, 0x00, 0x06, 0x00, 0x7f, + 0x00, 0x0d, 0x00, 0xf6, 0x00), + PHYREGS(0x08c0, 0x08bc, 0x08b8, 0x01d4, 0x01d5, 0x01d6), + }, + { .freq = 5600, + RADIOREGS3(0x28, 0x01, 0x01, 0x02, 0x30, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, + 0x70, 0x1a, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xf4, 0x00, 0x1a, 0x00, 0x04, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xf4, 0x00), + PHYREGS(0x08c4, 0x08c0, 0x08bc, 0x01d3, 0x01d4, 0x01d5), + }, + { .freq = 5610, + RADIOREGS3(0x28, 0x01, 0x01, 0x02, 0x31, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, + 0x70, 0x19, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xf4, 0x00, 0x19, 0x00, 0x04, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xf4, 0x00), + PHYREGS(0x08c8, 0x08c4, 0x08c0, 0x01d2, 0x01d3, 0x01d4), + }, + { .freq = 5620, + RADIOREGS3(0x21, 0x01, 0x01, 0x02, 0x32, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, + 0x70, 0x19, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xf4, 0x00, 0x19, 0x00, 0x04, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xf4, 0x00), + PHYREGS(0x08cc, 0x08c8, 0x08c4, 0x01d2, 0x01d2, 0x01d3), + }, + { .freq = 5630, + RADIOREGS3(0x21, 0x01, 0x01, 0x02, 0x33, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, + 0x70, 0x09, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xf4, 0x00, 0x09, 0x00, 0x04, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xf4, 0x00), + PHYREGS(0x08d0, 0x08cc, 0x08c8, 0x01d1, 0x01d2, 0x01d2), + }, + { .freq = 5640, + RADIOREGS3(0x1c, 0x01, 0x01, 0x02, 0x34, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, + 0x70, 0x09, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xf4, 0x00, 0x09, 0x00, 0x04, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xf4, 0x00), + PHYREGS(0x08d4, 0x08d0, 0x08cc, 0x01d0, 0x01d1, 0x01d2), + }, + { .freq = 5650, + RADIOREGS3(0x1c, 0x01, 0x01, 0x02, 0x35, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, + 0x70, 0x08, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xf4, 0x00, 0x08, 0x00, 0x04, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xf4, 0x00), + PHYREGS(0x08d8, 0x08d4, 0x08d0, 0x01cf, 0x01d0, 0x01d1), + }, + { .freq = 5660, + RADIOREGS3(0x16, 0x01, 0x01, 0x02, 0x36, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, + 0x70, 0x08, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xf4, 0x00, 0x08, 0x00, 0x04, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xf4, 0x00), + PHYREGS(0x08dc, 0x08d8, 0x08d4, 0x01ce, 0x01cf, 0x01d0), + }, + { .freq = 5670, + RADIOREGS3(0x16, 0x01, 0x01, 0x02, 0x37, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, + 0x70, 0x08, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xf4, 0x00, 0x08, 0x00, 0x04, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xf4, 0x00), + PHYREGS(0x08e0, 0x08dc, 0x08d8, 0x01ce, 0x01ce, 0x01cf), + }, + { .freq = 5680, + RADIOREGS3(0x10, 0x01, 0x01, 0x02, 0x38, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, + 0x70, 0x08, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xf4, 0x00, 0x08, 0x00, 0x04, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xf4, 0x00), + PHYREGS(0x08e4, 0x08e0, 0x08dc, 0x01cd, 0x01ce, 0x01ce), + }, + { .freq = 5690, + RADIOREGS3(0x10, 0x01, 0x01, 0x02, 0x39, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, + 0x70, 0x07, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xf4, 0x00, 0x07, 0x00, 0x04, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xf4, 0x00), + PHYREGS(0x08e8, 0x08e4, 0x08e0, 0x01cc, 0x01cd, 0x01ce), + }, + { .freq = 5700, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3a, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x07, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xf2, 0x00, 0x07, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xf2, 0x00), + PHYREGS(0x08ec, 0x08e8, 0x08e4, 0x01cb, 0x01cc, 0x01cd), + }, + { .freq = 5710, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3b, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x07, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xf2, 0x00, 0x07, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xf2, 0x00), + PHYREGS(0x08f0, 0x08ec, 0x08e8, 0x01ca, 0x01cb, 0x01cc), + }, + { .freq = 5720, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3c, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x07, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xf2, 0x00, 0x07, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xf2, 0x00), + PHYREGS(0x08f4, 0x08f0, 0x08ec, 0x01c9, 0x01ca, 0x01cb), + }, + { .freq = 5725, + RADIOREGS3(0x03, 0x01, 0x02, 0x04, 0x79, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x06, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xf2, 0x00, 0x06, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xf2, 0x00), + PHYREGS(0x08f6, 0x08f2, 0x08ee, 0x01c9, 0x01ca, 0x01cb), + }, + { .freq = 5730, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3d, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x06, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xf2, 0x00, 0x06, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xf2, 0x00), + PHYREGS(0x08f8, 0x08f4, 0x08f0, 0x01c9, 0x01c9, 0x01ca), + }, + { .freq = 5735, + RADIOREGS3(0x03, 0x01, 0x02, 0x04, 0x7b, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x06, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xf2, 0x00, 0x06, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xf2, 0x00), + PHYREGS(0x08fa, 0x08f6, 0x08f2, 0x01c8, 0x01c9, 0x01ca), + }, + { .freq = 5740, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3e, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x06, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xf2, 0x00, 0x06, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xf2, 0x00), + PHYREGS(0x08fc, 0x08f8, 0x08f4, 0x01c8, 0x01c9, 0x01c9), + }, + { .freq = 5745, + RADIOREGS3(0xfe, 0x00, 0x02, 0x04, 0x7d, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x06, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xf2, 0x00, 0x06, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xf2, 0x00), + PHYREGS(0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9), + }, + { .freq = 5750, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3f, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x06, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xf2, 0x00, 0x06, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xf2, 0x00), + PHYREGS(0x0900, 0x08fc, 0x08f8, 0x01c7, 0x01c8, 0x01c9), + }, + { .freq = 5755, + RADIOREGS3(0xfe, 0x00, 0x02, 0x04, 0x7f, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x05, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xf2, 0x00, 0x05, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xf2, 0x00), + PHYREGS(0x0902, 0x08fe, 0x08fa, 0x01c7, 0x01c8, 0x01c8), + }, + { .freq = 5760, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x40, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x05, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xf2, 0x00, 0x05, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xf2, 0x00), + PHYREGS(0x0904, 0x0900, 0x08fc, 0x01c6, 0x01c7, 0x01c8), + }, + { .freq = 5765, + RADIOREGS3(0xf8, 0x00, 0x02, 0x04, 0x81, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x05, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xf2, 0x00, 0x05, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xf2, 0x00), + PHYREGS(0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8), + }, + { .freq = 5770, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x41, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x05, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xf2, 0x00, 0x05, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xf2, 0x00), + PHYREGS(0x0908, 0x0904, 0x0900, 0x01c6, 0x01c6, 0x01c7), + }, + { .freq = 5775, + RADIOREGS3(0xf8, 0x00, 0x02, 0x04, 0x83, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x05, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xf2, 0x00, 0x05, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xf2, 0x00), + PHYREGS(0x090a, 0x0906, 0x0902, 0x01c5, 0x01c6, 0x01c7), + }, + { .freq = 5780, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x42, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x05, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xf2, 0x00, 0x05, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xf2, 0x00), + PHYREGS(0x090c, 0x0908, 0x0904, 0x01c5, 0x01c6, 0x01c6), + }, + { .freq = 5785, + RADIOREGS3(0xf2, 0x00, 0x02, 0x04, 0x85, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00, + 0x40, 0x04, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xf2, 0x00, 0x04, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xf2, 0x00), + PHYREGS(0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6), + }, + { .freq = 5790, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x43, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00, + 0x40, 0x04, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xf2, 0x00, 0x04, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xf2, 0x00), + PHYREGS(0x0910, 0x090c, 0x0908, 0x01c4, 0x01c5, 0x01c6), + }, + { .freq = 5795, + RADIOREGS3(0xf2, 0x00, 0x02, 0x04, 0x87, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00, + 0x40, 0x04, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xf2, 0x00, 0x04, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xf2, 0x00), + PHYREGS(0x0912, 0x090e, 0x090a, 0x01c4, 0x01c4, 0x01c5), + }, + { .freq = 5800, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x44, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, + 0x20, 0x04, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xf0, 0x00, 0x04, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xf0, 0x00), + PHYREGS(0x0914, 0x0910, 0x090c, 0x01c3, 0x01c4, 0x01c5), + }, + { .freq = 5805, + RADIOREGS3(0xed, 0x00, 0x02, 0x04, 0x89, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, + 0x20, 0x04, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xf0, 0x00, 0x04, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xf0, 0x00), + PHYREGS(0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4), + }, + { .freq = 5810, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x45, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, + 0x20, 0x04, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xf0, 0x00, 0x04, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xf0, 0x00), + PHYREGS(0x0918, 0x0914, 0x0910, 0x01c2, 0x01c3, 0x01c4), + }, + { .freq = 5815, + RADIOREGS3(0xed, 0x00, 0x02, 0x04, 0x8b, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, + 0x20, 0x04, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xf0, 0x00, 0x04, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xf0, 0x00), + PHYREGS(0x091a, 0x0916, 0x0912, 0x01c2, 0x01c3, 0x01c4), + }, + { .freq = 5820, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x46, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, + 0x20, 0x03, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xf0, 0x00, 0x03, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xf0, 0x00), + PHYREGS(0x091c, 0x0918, 0x0914, 0x01c2, 0x01c2, 0x01c3), + }, + { .freq = 5825, + RADIOREGS3(0xed, 0x00, 0x02, 0x04, 0x8d, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, + 0x20, 0x03, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xf0, 0x00, 0x03, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xf0, 0x00), + PHYREGS(0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3), + }, + { .freq = 5830, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x47, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, + 0x20, 0x03, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xf0, 0x00, 0x03, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xf0, 0x00), + PHYREGS(0x0920, 0x091c, 0x0918, 0x01c1, 0x01c2, 0x01c2), + }, + { .freq = 5840, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x48, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, + 0x20, 0x03, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xf0, 0x00, 0x03, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xf0, 0x00), + PHYREGS(0x0924, 0x0920, 0x091c, 0x01c0, 0x01c1, 0x01c2), + }, + { .freq = 5850, + RADIOREGS3(0xe0, 0x00, 0x01, 0x02, 0x49, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, + 0x20, 0x03, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xf0, 0x00, 0x03, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xf0, 0x00), + PHYREGS(0x0928, 0x0924, 0x0920, 0x01bf, 0x01c0, 0x01c1), + }, + { .freq = 5860, + RADIOREGS3(0xde, 0x00, 0x01, 0x02, 0x4a, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, + 0x20, 0x03, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xf0, 0x00, 0x03, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xf0, 0x00), + PHYREGS(0x092c, 0x0928, 0x0924, 0x01bf, 0x01bf, 0x01c0), + }, + { .freq = 5870, + RADIOREGS3(0xdb, 0x00, 0x01, 0x02, 0x4b, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, + 0x20, 0x02, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xf0, 0x00, 0x02, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xf0, 0x00), + PHYREGS(0x0930, 0x092c, 0x0928, 0x01be, 0x01bf, 0x01bf), + }, + { .freq = 5880, + RADIOREGS3(0xd8, 0x00, 0x01, 0x02, 0x4c, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, + 0x20, 0x02, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xf0, 0x00, 0x02, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xf0, 0x00), + PHYREGS(0x0934, 0x0930, 0x092c, 0x01bd, 0x01be, 0x01bf), + }, + { .freq = 5890, + RADIOREGS3(0xd6, 0x00, 0x01, 0x02, 0x4d, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, + 0x20, 0x02, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xf0, 0x00, 0x02, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xf0, 0x00), + PHYREGS(0x0938, 0x0934, 0x0930, 0x01bc, 0x01bd, 0x01be), + }, + { .freq = 5900, + RADIOREGS3(0xd3, 0x00, 0x01, 0x02, 0x4e, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x87, 0x03, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf0, 0x00, 0x02, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf0, 0x00), + PHYREGS(0x093c, 0x0938, 0x0934, 0x01bc, 0x01bc, 0x01bd), + }, + { .freq = 5910, + RADIOREGS3(0xd6, 0x00, 0x01, 0x02, 0x4f, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x87, 0x03, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf0, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf0, 0x00), + PHYREGS(0x0940, 0x093c, 0x0938, 0x01bb, 0x01bc, 0x01bc), + }, + { .freq = 2412, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x6c, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x04, 0x04, 0x04, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x04, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0e, 0x00, 0xff, 0x00, 0x04, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0e), + PHYREGS(0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443), + }, + { .freq = 2417, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x71, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x04, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0e, 0x00, 0xff, 0x00, 0x04, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0e), + PHYREGS(0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441), + }, + { .freq = 2422, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x76, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x04, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0e, 0x00, 0xff, 0x00, 0x04, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0e), + PHYREGS(0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f), + }, + { .freq = 2427, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x7b, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0xfd, 0x00, 0x04, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0e, 0x00, 0xfd, 0x00, 0x04, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0e), + PHYREGS(0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d), + }, + { .freq = 2432, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x80, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0xfb, 0x00, 0x04, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0e, 0x00, 0xfb, 0x00, 0x04, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0e), + PHYREGS(0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a), + }, + { .freq = 2437, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x85, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0e, 0x00, 0xfa, 0x00, 0x04, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0e), + PHYREGS(0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438), + }, + { .freq = 2442, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x8a, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0xf8, 0x00, 0x04, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0e, 0x00, 0xf8, 0x00, 0x04, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0e), + PHYREGS(0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436), + }, + { .freq = 2447, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x8f, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0xf7, 0x00, 0x04, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0e, 0x00, 0xf7, 0x00, 0x04, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0e), + PHYREGS(0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434), + }, + { .freq = 2452, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x94, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0xf6, 0x00, 0x04, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0e, 0x00, 0xf6, 0x00, 0x04, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0e), + PHYREGS(0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431), + }, + { .freq = 2457, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x99, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0xf5, 0x00, 0x04, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0e, 0x00, 0xf5, 0x00, 0x04, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0e), + PHYREGS(0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f), + }, + { .freq = 2462, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x9e, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0xf4, 0x00, 0x04, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0e, 0x00, 0xf4, 0x00, 0x04, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0e), + PHYREGS(0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d), + }, + { .freq = 2467, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0xa3, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0xf3, 0x00, 0x04, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0e, 0x00, 0xf3, 0x00, 0x04, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0e), + PHYREGS(0x03df, 0x03db, 0x03d7, 0x0422, 0x0427, 0x042b), + }, + { .freq = 2472, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0xa8, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0xf2, 0x00, 0x04, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0e, 0x00, 0xf2, 0x00, 0x04, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0e), + PHYREGS(0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429), + }, + { .freq = 2484, + RADIOREGS3(0xff, 0x01, 0x03, 0x09, 0xb4, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0xf0, 0x00, 0x04, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0e, 0x00, 0xf0, 0x00, 0x04, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0e), + PHYREGS(0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424), + }, +}; + +static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev5[] = { + { .freq = 4920, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70, 0x00, 0x0f, + 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0b, 0x00, 0x70, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x07b4, 0x07b0, 0x07ac, 0x0214, 0x0215, 0x0216), + }, + { .freq = 4930, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xed, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70, 0x00, 0x0e, + 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0b, 0x00, 0x70, + 0x00, 0x0e, 0x00, 0x6f, 0x00), + PHYREGS(0x07b8, 0x07b4, 0x07b0, 0x0213, 0x0214, 0x0215), + }, + { .freq = 4940, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xee, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70, 0x00, 0x0e, + 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0b, 0x00, 0x70, + 0x00, 0x0e, 0x00, 0x6f, 0x00), + PHYREGS(0x07bc, 0x07b8, 0x07b4, 0x0212, 0x0213, 0x0214), + }, + { .freq = 4950, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xef, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70, 0x00, 0x0e, + 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0b, 0x00, 0x70, + 0x00, 0x0e, 0x00, 0x6f, 0x00), + PHYREGS(0x07c0, 0x07bc, 0x07b8, 0x0211, 0x0212, 0x0213), + }, + { .freq = 4960, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf0, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0e, + 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, + 0x00, 0x0e, 0x00, 0x6f, 0x00), + PHYREGS(0x07c4, 0x07c0, 0x07bc, 0x020f, 0x0211, 0x0212), + }, + { .freq = 4970, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf1, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d, + 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, + 0x00, 0x0d, 0x00, 0x6f, 0x00), + PHYREGS(0x07c8, 0x07c4, 0x07c0, 0x020e, 0x020f, 0x0211), + }, + { .freq = 4980, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf2, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d, + 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, + 0x00, 0x0d, 0x00, 0x6f, 0x00), + PHYREGS(0x07cc, 0x07c8, 0x07c4, 0x020d, 0x020e, 0x020f), + }, + { .freq = 4990, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf3, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d, + 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, + 0x00, 0x0d, 0x00, 0x6f, 0x00), + PHYREGS(0x07d0, 0x07cc, 0x07c8, 0x020c, 0x020d, 0x020e), + }, + { .freq = 5000, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf4, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d, + 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, + 0x00, 0x0d, 0x00, 0x6f, 0x00), + PHYREGS(0x07d4, 0x07d0, 0x07cc, 0x020b, 0x020c, 0x020d), + }, + { .freq = 5010, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf5, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d, + 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, + 0x00, 0x0d, 0x00, 0x6f, 0x00), + PHYREGS(0x07d8, 0x07d4, 0x07d0, 0x020a, 0x020b, 0x020c), + }, + { .freq = 5020, + RADIOREGS3(0xf7, 0x01, 0x01, 0x01, 0xf6, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0d, + 0x00, 0x9f, 0x00, 0xff, 0x00, 0x09, 0x00, 0x70, + 0x00, 0x0d, 0x00, 0x6f, 0x00), + PHYREGS(0x07dc, 0x07d8, 0x07d4, 0x0209, 0x020a, 0x020b), + }, + { .freq = 5030, + RADIOREGS3(0xf7, 0x01, 0x01, 0x01, 0xf7, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0c, + 0x00, 0x9f, 0x00, 0xff, 0x00, 0x09, 0x00, 0x70, + 0x00, 0x0c, 0x00, 0x6f, 0x00), + PHYREGS(0x07e0, 0x07dc, 0x07d8, 0x0208, 0x0209, 0x020a), + }, + { .freq = 5040, + RADIOREGS3(0xef, 0x01, 0x01, 0x01, 0xf8, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xfe, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0c, + 0x00, 0x9f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x70, + 0x00, 0x0c, 0x00, 0x6f, 0x00), + PHYREGS(0x07e4, 0x07e0, 0x07dc, 0x0207, 0x0208, 0x0209), + }, + { .freq = 5050, + RADIOREGS3(0xef, 0x01, 0x01, 0x01, 0xf9, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xfe, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0c, + 0x00, 0x9f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x70, + 0x00, 0x0c, 0x00, 0x6f, 0x00), + PHYREGS(0x07e8, 0x07e4, 0x07e0, 0x0206, 0x0207, 0x0208), + }, + { .freq = 5060, + RADIOREGS3(0xe6, 0x01, 0x01, 0x01, 0xfa, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xfd, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0c, + 0x00, 0x9f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x70, + 0x00, 0x0c, 0x00, 0x6f, 0x00), + PHYREGS(0x07ec, 0x07e8, 0x07e4, 0x0205, 0x0206, 0x0207), + }, + { .freq = 5070, + RADIOREGS3(0xe6, 0x01, 0x01, 0x01, 0xfb, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xfd, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b, + 0x00, 0x9f, 0x00, 0xfd, 0x00, 0x08, 0x00, 0x70, + 0x00, 0x0b, 0x00, 0x6f, 0x00), + PHYREGS(0x07f0, 0x07ec, 0x07e8, 0x0204, 0x0205, 0x0206), + }, + { .freq = 5080, + RADIOREGS3(0xde, 0x01, 0x01, 0x01, 0xfc, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b, + 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70, + 0x00, 0x0b, 0x00, 0x6f, 0x00), + PHYREGS(0x07f4, 0x07f0, 0x07ec, 0x0203, 0x0204, 0x0205), + }, + { .freq = 5090, + RADIOREGS3(0xde, 0x01, 0x01, 0x01, 0xfd, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b, + 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70, + 0x00, 0x0b, 0x00, 0x6f, 0x00), + PHYREGS(0x07f8, 0x07f4, 0x07f0, 0x0202, 0x0203, 0x0204), + }, + { .freq = 5100, + RADIOREGS3(0xd6, 0x01, 0x01, 0x01, 0xfe, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b, + 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70, + 0x00, 0x0b, 0x00, 0x6f, 0x00), + PHYREGS(0x07fc, 0x07f8, 0x07f4, 0x0201, 0x0202, 0x0203), + }, + { .freq = 5110, + RADIOREGS3(0xd6, 0x01, 0x01, 0x01, 0xff, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b, + 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70, + 0x00, 0x0b, 0x00, 0x6f, 0x00), + PHYREGS(0x0800, 0x07fc, 0x07f8, 0x0200, 0x0201, 0x0202), + }, + { .freq = 5120, + RADIOREGS3(0xce, 0x01, 0x01, 0x02, 0x00, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b, + 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70, + 0x00, 0x0b, 0x00, 0x6f, 0x00), + PHYREGS(0x0804, 0x0800, 0x07fc, 0x01ff, 0x0200, 0x0201), + }, + { .freq = 5130, + RADIOREGS3(0xce, 0x01, 0x01, 0x02, 0x01, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xfb, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0a, + 0x00, 0x9f, 0x00, 0xfb, 0x00, 0x08, 0x00, 0x70, + 0x00, 0x0a, 0x00, 0x6f, 0x00), + PHYREGS(0x0808, 0x0804, 0x0800, 0x01fe, 0x01ff, 0x0200), + }, + { .freq = 5140, + RADIOREGS3(0xc6, 0x01, 0x01, 0x02, 0x02, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xfb, 0x00, 0x07, 0x00, 0x70, 0x00, 0x0a, + 0x00, 0x9f, 0x00, 0xfb, 0x00, 0x07, 0x00, 0x70, + 0x00, 0x0a, 0x00, 0x6f, 0x00), + PHYREGS(0x080c, 0x0808, 0x0804, 0x01fd, 0x01fe, 0x01ff), + }, + { .freq = 5160, + RADIOREGS3(0xbe, 0x01, 0x01, 0x02, 0x04, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xfb, 0x00, 0x07, 0x00, 0x70, 0x00, 0x09, + 0x00, 0x9e, 0x00, 0xfb, 0x00, 0x07, 0x00, 0x70, + 0x00, 0x09, 0x00, 0x6e, 0x00), + PHYREGS(0x0814, 0x0810, 0x080c, 0x01fb, 0x01fc, 0x01fd), + }, + { .freq = 5170, + RADIOREGS3(0xbe, 0x01, 0x01, 0x02, 0x05, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xfb, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09, + 0x00, 0x9e, 0x00, 0xfb, 0x00, 0x06, 0x00, 0x70, + 0x00, 0x09, 0x00, 0x6e, 0x00), + PHYREGS(0x0818, 0x0814, 0x0810, 0x01fa, 0x01fb, 0x01fc), + }, + { .freq = 5180, + RADIOREGS3(0xb6, 0x01, 0x01, 0x02, 0x06, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09, + 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70, + 0x00, 0x09, 0x00, 0x6e, 0x00), + PHYREGS(0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb), + }, + { .freq = 5190, + RADIOREGS3(0xb6, 0x01, 0x01, 0x02, 0x07, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09, + 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70, + 0x00, 0x09, 0x00, 0x6e, 0x00), + PHYREGS(0x0820, 0x081c, 0x0818, 0x01f8, 0x01f9, 0x01fa), + }, + { .freq = 5200, + RADIOREGS3(0xaf, 0x01, 0x01, 0x02, 0x08, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09, + 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70, + 0x00, 0x09, 0x00, 0x6e, 0x00), + PHYREGS(0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9), + }, + { .freq = 5210, + RADIOREGS3(0xaf, 0x01, 0x01, 0x02, 0x09, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09, + 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70, + 0x00, 0x09, 0x00, 0x6e, 0x00), + PHYREGS(0x0828, 0x0824, 0x0820, 0x01f6, 0x01f7, 0x01f8), + }, + { .freq = 5220, + RADIOREGS3(0xa7, 0x01, 0x01, 0x02, 0x0a, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09, + 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70, + 0x00, 0x09, 0x00, 0x6e, 0x00), + PHYREGS(0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7), + }, + { .freq = 5230, + RADIOREGS3(0xa7, 0x01, 0x01, 0x02, 0x0b, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xea, 0x00, 0x06, 0x00, 0x70, 0x00, 0x08, + 0x00, 0x9e, 0x00, 0xea, 0x00, 0x06, 0x00, 0x70, + 0x00, 0x08, 0x00, 0x6e, 0x00), + PHYREGS(0x0830, 0x082c, 0x0828, 0x01f4, 0x01f5, 0x01f6), + }, + { .freq = 5240, + RADIOREGS3(0xa0, 0x01, 0x01, 0x02, 0x0c, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xe9, 0x00, 0x05, 0x00, 0x70, 0x00, 0x08, + 0x00, 0x9d, 0x00, 0xe9, 0x00, 0x05, 0x00, 0x70, + 0x00, 0x08, 0x00, 0x6d, 0x00), + PHYREGS(0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5), + }, + { .freq = 5250, + RADIOREGS3(0xa0, 0x01, 0x01, 0x02, 0x0d, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xe9, 0x00, 0x05, 0x00, 0x70, 0x00, 0x08, + 0x00, 0x9d, 0x00, 0xe9, 0x00, 0x05, 0x00, 0x70, + 0x00, 0x08, 0x00, 0x6d, 0x00), + PHYREGS(0x0838, 0x0834, 0x0830, 0x01f2, 0x01f3, 0x01f4), + }, + { .freq = 5260, + RADIOREGS3(0x98, 0x01, 0x01, 0x02, 0x0e, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xd9, 0x00, 0x05, 0x00, 0x70, 0x00, 0x08, + 0x00, 0x9d, 0x00, 0xd9, 0x00, 0x05, 0x00, 0x70, + 0x00, 0x08, 0x00, 0x6d, 0x00), + PHYREGS(0x083c, 0x0838, 0x0834, 0x01f1, 0x01f2, 0x01f3), + }, + { .freq = 5270, + RADIOREGS3(0x98, 0x01, 0x01, 0x02, 0x0f, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00, + 0xff, 0xd8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, + 0x00, 0x9c, 0x00, 0xd8, 0x00, 0x04, 0x00, 0x70, + 0x00, 0x07, 0x00, 0x6c, 0x00), + PHYREGS(0x0840, 0x083c, 0x0838, 0x01f0, 0x01f1, 0x01f2), + }, + { .freq = 5280, + RADIOREGS3(0x91, 0x01, 0x01, 0x02, 0x10, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00, + 0xff, 0xc8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, + 0x00, 0x9c, 0x00, 0xc8, 0x00, 0x04, 0x00, 0x70, + 0x00, 0x07, 0x00, 0x6c, 0x00), + PHYREGS(0x0844, 0x0840, 0x083c, 0x01f0, 0x01f0, 0x01f1), + }, + { .freq = 5290, + RADIOREGS3(0x91, 0x01, 0x01, 0x02, 0x11, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00, + 0xff, 0xc8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, + 0x00, 0x9c, 0x00, 0xc8, 0x00, 0x04, 0x00, 0x70, + 0x00, 0x07, 0x00, 0x6c, 0x00), + PHYREGS(0x0848, 0x0844, 0x0840, 0x01ef, 0x01f0, 0x01f0), + }, + { .freq = 5300, + RADIOREGS3(0x8a, 0x01, 0x01, 0x02, 0x12, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, + 0xff, 0xc8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, + 0x00, 0x9c, 0x00, 0xc8, 0x00, 0x04, 0x00, 0x70, + 0x00, 0x07, 0x00, 0x6c, 0x00), + PHYREGS(0x084c, 0x0848, 0x0844, 0x01ee, 0x01ef, 0x01f0), + }, + { .freq = 5310, + RADIOREGS3(0x8a, 0x01, 0x01, 0x02, 0x13, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, + 0xff, 0xc8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, + 0x00, 0x9c, 0x00, 0xc8, 0x00, 0x04, 0x00, 0x70, + 0x00, 0x07, 0x00, 0x6c, 0x00), + PHYREGS(0x0850, 0x084c, 0x0848, 0x01ed, 0x01ee, 0x01ef), + }, + { .freq = 5320, + RADIOREGS3(0x83, 0x01, 0x01, 0x02, 0x14, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, + 0xff, 0xb8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, + 0x00, 0x9c, 0x00, 0xb8, 0x00, 0x04, 0x00, 0x70, + 0x00, 0x07, 0x00, 0x6c, 0x00), + PHYREGS(0x0854, 0x0850, 0x084c, 0x01ec, 0x01ed, 0x01ee), + }, + { .freq = 5330, + RADIOREGS3(0x83, 0x01, 0x01, 0x02, 0x15, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, + 0xff, 0xb7, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, + 0x00, 0x9b, 0x00, 0xb7, 0x00, 0x04, 0x00, 0x70, + 0x00, 0x07, 0x00, 0x6b, 0x00), + PHYREGS(0x0858, 0x0854, 0x0850, 0x01eb, 0x01ec, 0x01ed), + }, + { .freq = 5340, + RADIOREGS3(0x7c, 0x01, 0x01, 0x02, 0x16, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, + 0xff, 0xb7, 0x00, 0x03, 0x00, 0x70, 0x00, 0x07, + 0x00, 0x9b, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x70, + 0x00, 0x07, 0x00, 0x6b, 0x00), + PHYREGS(0x085c, 0x0858, 0x0854, 0x01ea, 0x01eb, 0x01ec), + }, + { .freq = 5350, + RADIOREGS3(0x7c, 0x01, 0x01, 0x02, 0x17, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, + 0xff, 0xa7, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06, + 0x00, 0x9b, 0x00, 0xa7, 0x00, 0x03, 0x00, 0x70, + 0x00, 0x06, 0x00, 0x6b, 0x00), + PHYREGS(0x0860, 0x085c, 0x0858, 0x01e9, 0x01ea, 0x01eb), + }, + { .freq = 5360, + RADIOREGS3(0x75, 0x01, 0x01, 0x02, 0x18, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, + 0xff, 0xa6, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06, + 0x00, 0x9b, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x70, + 0x00, 0x06, 0x00, 0x6b, 0x00), + PHYREGS(0x0864, 0x0860, 0x085c, 0x01e8, 0x01e9, 0x01ea), + }, + { .freq = 5370, + RADIOREGS3(0x75, 0x01, 0x01, 0x02, 0x19, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, + 0xff, 0xa6, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06, + 0x00, 0x9b, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x70, + 0x00, 0x06, 0x00, 0x5b, 0x00), + PHYREGS(0x0868, 0x0864, 0x0860, 0x01e7, 0x01e8, 0x01e9), + }, + { .freq = 5380, + RADIOREGS3(0x6e, 0x01, 0x01, 0x02, 0x1a, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, + 0xff, 0x96, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06, + 0x00, 0x9a, 0x00, 0x96, 0x00, 0x03, 0x00, 0x70, + 0x00, 0x06, 0x00, 0x5a, 0x00), + PHYREGS(0x086c, 0x0868, 0x0864, 0x01e6, 0x01e7, 0x01e8), + }, + { .freq = 5390, + RADIOREGS3(0x6e, 0x01, 0x01, 0x02, 0x1b, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, + 0xff, 0x95, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06, + 0x00, 0x9a, 0x00, 0x95, 0x00, 0x03, 0x00, 0x70, + 0x00, 0x06, 0x00, 0x5a, 0x00), + PHYREGS(0x0870, 0x086c, 0x0868, 0x01e5, 0x01e6, 0x01e7), + }, + { .freq = 5400, + RADIOREGS3(0x67, 0x01, 0x01, 0x02, 0x1c, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, + 0xc8, 0x95, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06, + 0x00, 0x9a, 0x00, 0x95, 0x00, 0x03, 0x00, 0x70, + 0x00, 0x06, 0x00, 0x5a, 0x00), + PHYREGS(0x0874, 0x0870, 0x086c, 0x01e5, 0x01e5, 0x01e6), + }, + { .freq = 5410, + RADIOREGS3(0x67, 0x01, 0x01, 0x02, 0x1d, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, + 0xc8, 0x95, 0x00, 0x03, 0x00, 0x70, 0x00, 0x05, + 0x00, 0x9a, 0x00, 0x95, 0x00, 0x03, 0x00, 0x70, + 0x00, 0x05, 0x00, 0x5a, 0x00), + PHYREGS(0x0878, 0x0874, 0x0870, 0x01e4, 0x01e5, 0x01e5), + }, + { .freq = 5420, + RADIOREGS3(0x61, 0x01, 0x01, 0x02, 0x1e, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, + 0xc8, 0x95, 0x00, 0x03, 0x00, 0x70, 0x00, 0x05, + 0x00, 0x9a, 0x00, 0x95, 0x00, 0x03, 0x00, 0x70, + 0x00, 0x05, 0x00, 0x5a, 0x00), + PHYREGS(0x087c, 0x0878, 0x0874, 0x01e3, 0x01e4, 0x01e5), + }, + { .freq = 5430, + RADIOREGS3(0x61, 0x01, 0x01, 0x02, 0x1f, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, + 0xc8, 0x85, 0x00, 0x02, 0x00, 0x70, 0x00, 0x05, + 0x00, 0x99, 0x00, 0x85, 0x00, 0x02, 0x00, 0x70, + 0x00, 0x05, 0x00, 0x59, 0x00), + PHYREGS(0x0880, 0x087c, 0x0878, 0x01e2, 0x01e3, 0x01e4), + }, + { .freq = 5440, + RADIOREGS3(0x5a, 0x01, 0x01, 0x02, 0x20, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, + 0xc8, 0x84, 0x00, 0x02, 0x00, 0x70, 0x00, 0x05, + 0x00, 0x99, 0x00, 0x84, 0x00, 0x02, 0x00, 0x70, + 0x00, 0x05, 0x00, 0x59, 0x00), + PHYREGS(0x0884, 0x0880, 0x087c, 0x01e1, 0x01e2, 0x01e3), + }, + { .freq = 5450, + RADIOREGS3(0x5a, 0x01, 0x01, 0x02, 0x21, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, + 0xc8, 0x84, 0x00, 0x02, 0x00, 0x70, 0x00, 0x05, + 0x00, 0x99, 0x00, 0x84, 0x00, 0x02, 0x00, 0x70, + 0x00, 0x05, 0x00, 0x59, 0x00), + PHYREGS(0x0888, 0x0884, 0x0880, 0x01e0, 0x01e1, 0x01e2), + }, + { .freq = 5460, + RADIOREGS3(0x53, 0x01, 0x01, 0x02, 0x22, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, + 0xc8, 0x84, 0x00, 0x02, 0x00, 0x70, 0x00, 0x04, + 0x00, 0x99, 0x00, 0x84, 0x00, 0x02, 0x00, 0x70, + 0x00, 0x04, 0x00, 0x69, 0x00), + PHYREGS(0x088c, 0x0888, 0x0884, 0x01df, 0x01e0, 0x01e1), + }, + { .freq = 5470, + RADIOREGS3(0x53, 0x01, 0x01, 0x02, 0x23, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, + 0xc8, 0x74, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04, + 0x00, 0x99, 0x00, 0x74, 0x00, 0x01, 0x00, 0x70, + 0x00, 0x04, 0x00, 0x69, 0x00), + PHYREGS(0x0890, 0x088c, 0x0888, 0x01de, 0x01df, 0x01e0), + }, + { .freq = 5480, + RADIOREGS3(0x4d, 0x01, 0x01, 0x02, 0x24, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, + 0xc8, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04, + 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70, + 0x00, 0x04, 0x00, 0x68, 0x00), + PHYREGS(0x0894, 0x0890, 0x088c, 0x01dd, 0x01de, 0x01df), + }, + { .freq = 5490, + RADIOREGS3(0x4d, 0x01, 0x01, 0x02, 0x25, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, + 0xc8, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04, + 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70, + 0x00, 0x04, 0x00, 0x68, 0x00), + PHYREGS(0x0898, 0x0894, 0x0890, 0x01dd, 0x01dd, 0x01de), + }, + { .freq = 5500, + RADIOREGS3(0x47, 0x01, 0x01, 0x02, 0x26, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, + 0x84, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04, + 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70, + 0x00, 0x04, 0x00, 0x78, 0x00), + PHYREGS(0x089c, 0x0898, 0x0894, 0x01dc, 0x01dd, 0x01dd), + }, + { .freq = 5510, + RADIOREGS3(0x47, 0x01, 0x01, 0x02, 0x27, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, + 0x84, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04, + 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70, + 0x00, 0x04, 0x00, 0x78, 0x00), + PHYREGS(0x08a0, 0x089c, 0x0898, 0x01db, 0x01dc, 0x01dd), + }, + { .freq = 5520, + RADIOREGS3(0x40, 0x01, 0x01, 0x02, 0x28, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, + 0x84, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04, + 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70, + 0x00, 0x04, 0x00, 0x78, 0x00), + PHYREGS(0x08a4, 0x08a0, 0x089c, 0x01da, 0x01db, 0x01dc), + }, + { .freq = 5530, + RADIOREGS3(0x40, 0x01, 0x01, 0x02, 0x29, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, + 0x84, 0x63, 0x00, 0x01, 0x00, 0x70, 0x00, 0x03, + 0x00, 0x98, 0x00, 0x63, 0x00, 0x01, 0x00, 0x70, + 0x00, 0x03, 0x00, 0x78, 0x00), + PHYREGS(0x08a8, 0x08a4, 0x08a0, 0x01d9, 0x01da, 0x01db), + }, + { .freq = 5540, + RADIOREGS3(0x3a, 0x01, 0x01, 0x02, 0x2a, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, + 0x84, 0x62, 0x00, 0x00, 0x00, 0x70, 0x00, 0x03, + 0x00, 0x97, 0x00, 0x62, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x03, 0x00, 0x77, 0x00), + PHYREGS(0x08ac, 0x08a8, 0x08a4, 0x01d8, 0x01d9, 0x01da), + }, + { .freq = 5550, + RADIOREGS3(0x3a, 0x01, 0x01, 0x02, 0x2b, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, + 0x84, 0x62, 0x00, 0x00, 0x00, 0x70, 0x00, 0x03, + 0x00, 0x97, 0x00, 0x62, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x03, 0x00, 0x77, 0x00), + PHYREGS(0x08b0, 0x08ac, 0x08a8, 0x01d7, 0x01d8, 0x01d9), + }, + { .freq = 5560, + RADIOREGS3(0x34, 0x01, 0x01, 0x02, 0x2c, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, + 0x84, 0x62, 0x00, 0x00, 0x00, 0x70, 0x00, 0x03, + 0x00, 0x97, 0x00, 0x62, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x03, 0x00, 0x77, 0x00), + PHYREGS(0x08b4, 0x08b0, 0x08ac, 0x01d7, 0x01d7, 0x01d8), + }, + { .freq = 5570, + RADIOREGS3(0x34, 0x01, 0x01, 0x02, 0x2d, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, + 0x84, 0x52, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, + 0x00, 0x96, 0x00, 0x52, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x02, 0x00, 0x76, 0x00), + PHYREGS(0x08b8, 0x08b4, 0x08b0, 0x01d6, 0x01d7, 0x01d7), + }, + { .freq = 5580, + RADIOREGS3(0x2e, 0x01, 0x01, 0x02, 0x2e, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, + 0x84, 0x52, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, + 0x00, 0x96, 0x00, 0x52, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x02, 0x00, 0x76, 0x00), + PHYREGS(0x08bc, 0x08b8, 0x08b4, 0x01d5, 0x01d6, 0x01d7), + }, + { .freq = 5590, + RADIOREGS3(0x2e, 0x01, 0x01, 0x02, 0x2f, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, + 0x84, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, + 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x02, 0x00, 0x76, 0x00), + PHYREGS(0x08c0, 0x08bc, 0x08b8, 0x01d4, 0x01d5, 0x01d6), + }, + { .freq = 5600, + RADIOREGS3(0x28, 0x01, 0x01, 0x02, 0x30, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, + 0x70, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, + 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x02, 0x00, 0x76, 0x00), + PHYREGS(0x08c4, 0x08c0, 0x08bc, 0x01d3, 0x01d4, 0x01d5), + }, + { .freq = 5610, + RADIOREGS3(0x28, 0x01, 0x01, 0x02, 0x31, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, + 0x70, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, + 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x02, 0x00, 0x76, 0x00), + PHYREGS(0x08c8, 0x08c4, 0x08c0, 0x01d2, 0x01d3, 0x01d4), + }, + { .freq = 5620, + RADIOREGS3(0x21, 0x01, 0x01, 0x02, 0x32, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, + 0x70, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, + 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x02, 0x00, 0x76, 0x00), + PHYREGS(0x08cc, 0x08c8, 0x08c4, 0x01d2, 0x01d2, 0x01d3), + }, + { .freq = 5630, + RADIOREGS3(0x21, 0x01, 0x01, 0x02, 0x33, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, + 0x70, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, + 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x02, 0x00, 0x76, 0x00), + PHYREGS(0x08d0, 0x08cc, 0x08c8, 0x01d1, 0x01d2, 0x01d2), + }, + { .freq = 5640, + RADIOREGS3(0x1c, 0x01, 0x01, 0x02, 0x34, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, + 0x70, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, + 0x00, 0x95, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x02, 0x00, 0x75, 0x00), + PHYREGS(0x08d4, 0x08d0, 0x08cc, 0x01d0, 0x01d1, 0x01d2), + }, + { .freq = 5650, + RADIOREGS3(0x1c, 0x01, 0x01, 0x02, 0x35, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, + 0x70, 0x50, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, + 0x00, 0x95, 0x00, 0x50, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x01, 0x00, 0x75, 0x00), + PHYREGS(0x08d8, 0x08d4, 0x08d0, 0x01cf, 0x01d0, 0x01d1), + }, + { .freq = 5660, + RADIOREGS3(0x16, 0x01, 0x01, 0x02, 0x36, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, + 0x70, 0x50, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, + 0x00, 0x95, 0x00, 0x50, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x01, 0x00, 0x75, 0x00), + PHYREGS(0x08dc, 0x08d8, 0x08d4, 0x01ce, 0x01cf, 0x01d0), + }, + { .freq = 5670, + RADIOREGS3(0x16, 0x01, 0x01, 0x02, 0x37, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, + 0x70, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, + 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x01, 0x00, 0x74, 0x00), + PHYREGS(0x08e0, 0x08dc, 0x08d8, 0x01ce, 0x01ce, 0x01cf), + }, + { .freq = 5680, + RADIOREGS3(0x10, 0x01, 0x01, 0x02, 0x38, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, + 0x70, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, + 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x01, 0x00, 0x74, 0x00), + PHYREGS(0x08e4, 0x08e0, 0x08dc, 0x01cd, 0x01ce, 0x01ce), + }, + { .freq = 5690, + RADIOREGS3(0x10, 0x01, 0x01, 0x02, 0x39, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, + 0x70, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, + 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x01, 0x00, 0x74, 0x00), + PHYREGS(0x08e8, 0x08e4, 0x08e0, 0x01cc, 0x01cd, 0x01ce), + }, + { .freq = 5700, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3a, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, + 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x01, 0x00, 0x74, 0x00), + PHYREGS(0x08ec, 0x08e8, 0x08e4, 0x01cb, 0x01cc, 0x01cd), + }, + { .freq = 5710, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3b, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, + 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x01, 0x00, 0x74, 0x00), + PHYREGS(0x08f0, 0x08ec, 0x08e8, 0x01ca, 0x01cb, 0x01cc), + }, + { .freq = 5720, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3c, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, + 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x01, 0x00, 0x74, 0x00), + PHYREGS(0x08f4, 0x08f0, 0x08ec, 0x01c9, 0x01ca, 0x01cb), + }, + { .freq = 5725, + RADIOREGS3(0x03, 0x01, 0x02, 0x04, 0x79, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, + 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x01, 0x00, 0x74, 0x00), + PHYREGS(0x08f6, 0x08f2, 0x08ee, 0x01c9, 0x01ca, 0x01cb), + }, + { .freq = 5730, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3d, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, + 0x00, 0x94, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x01, 0x00, 0x84, 0x00), + PHYREGS(0x08f8, 0x08f4, 0x08f0, 0x01c9, 0x01c9, 0x01ca), + }, + { .freq = 5735, + RADIOREGS3(0x03, 0x01, 0x02, 0x04, 0x7b, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x83, 0x00), + PHYREGS(0x08fa, 0x08f6, 0x08f2, 0x01c8, 0x01c9, 0x01ca), + }, + { .freq = 5740, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3e, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x83, 0x00), + PHYREGS(0x08fc, 0x08f8, 0x08f4, 0x01c8, 0x01c9, 0x01c9), + }, + { .freq = 5745, + RADIOREGS3(0xfe, 0x00, 0x02, 0x04, 0x7d, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x83, 0x00), + PHYREGS(0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9), + }, + { .freq = 5750, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3f, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x83, 0x00), + PHYREGS(0x0900, 0x08fc, 0x08f8, 0x01c7, 0x01c8, 0x01c9), + }, + { .freq = 5755, + RADIOREGS3(0xfe, 0x00, 0x02, 0x04, 0x7f, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x83, 0x00), + PHYREGS(0x0902, 0x08fe, 0x08fa, 0x01c7, 0x01c8, 0x01c8), + }, + { .freq = 5760, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x40, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x93, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x83, 0x00), + PHYREGS(0x0904, 0x0900, 0x08fc, 0x01c6, 0x01c7, 0x01c8), + }, + { .freq = 5765, + RADIOREGS3(0xf8, 0x00, 0x02, 0x04, 0x81, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x82, 0x00), + PHYREGS(0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8), + }, + { .freq = 5770, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x41, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x82, 0x00), + PHYREGS(0x0908, 0x0904, 0x0900, 0x01c6, 0x01c6, 0x01c7), + }, + { .freq = 5775, + RADIOREGS3(0xf8, 0x00, 0x02, 0x04, 0x83, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x82, 0x00), + PHYREGS(0x090a, 0x0906, 0x0902, 0x01c5, 0x01c6, 0x01c7), + }, + { .freq = 5780, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x42, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, + 0x40, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x82, 0x00), + PHYREGS(0x090c, 0x0908, 0x0904, 0x01c5, 0x01c6, 0x01c6), + }, + { .freq = 5785, + RADIOREGS3(0xf2, 0x00, 0x02, 0x04, 0x85, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00, + 0x40, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x82, 0x00), + PHYREGS(0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6), + }, + { .freq = 5790, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x43, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00, + 0x40, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x82, 0x00), + PHYREGS(0x0910, 0x090c, 0x0908, 0x01c4, 0x01c5, 0x01c6), + }, + { .freq = 5795, + RADIOREGS3(0xf2, 0x00, 0x02, 0x04, 0x87, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00, + 0x40, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x82, 0x00), + PHYREGS(0x0912, 0x090e, 0x090a, 0x01c4, 0x01c4, 0x01c5), + }, + { .freq = 5800, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x44, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, + 0x20, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x82, 0x00), + PHYREGS(0x0914, 0x0910, 0x090c, 0x01c3, 0x01c4, 0x01c5), + }, + { .freq = 5805, + RADIOREGS3(0xed, 0x00, 0x02, 0x04, 0x89, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, + 0x20, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x82, 0x00), + PHYREGS(0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4), + }, + { .freq = 5810, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x45, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, + 0x20, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x82, 0x00), + PHYREGS(0x0918, 0x0914, 0x0910, 0x01c2, 0x01c3, 0x01c4), + }, + { .freq = 5815, + RADIOREGS3(0xed, 0x00, 0x02, 0x04, 0x8b, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, + 0x20, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x82, 0x00), + PHYREGS(0x091a, 0x0916, 0x0912, 0x01c2, 0x01c3, 0x01c4), + }, + { .freq = 5820, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x46, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, + 0x20, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x82, 0x00), + PHYREGS(0x091c, 0x0918, 0x0914, 0x01c2, 0x01c2, 0x01c3), + }, + { .freq = 5825, + RADIOREGS3(0xed, 0x00, 0x02, 0x04, 0x8d, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, + 0x20, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x82, 0x00), + PHYREGS(0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3), + }, + { .freq = 5830, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x47, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, + 0x20, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x72, 0x00), + PHYREGS(0x0920, 0x091c, 0x0918, 0x01c1, 0x01c2, 0x01c2), + }, + { .freq = 5840, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x48, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, + 0x20, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x72, 0x00), + PHYREGS(0x0924, 0x0920, 0x091c, 0x01c0, 0x01c1, 0x01c2), + }, + { .freq = 5850, + RADIOREGS3(0xe0, 0x00, 0x01, 0x02, 0x49, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x72, 0x00), + PHYREGS(0x0928, 0x0924, 0x0920, 0x01bf, 0x01c0, 0x01c1), + }, + { .freq = 5860, + RADIOREGS3(0xde, 0x00, 0x01, 0x02, 0x4a, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x72, 0x00), + PHYREGS(0x092c, 0x0928, 0x0924, 0x01bf, 0x01bf, 0x01c0), + }, + { .freq = 5870, + RADIOREGS3(0xdb, 0x00, 0x01, 0x02, 0x4b, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x71, 0x00), + PHYREGS(0x0930, 0x092c, 0x0928, 0x01be, 0x01bf, 0x01bf), + }, + { .freq = 5880, + RADIOREGS3(0xd8, 0x00, 0x01, 0x02, 0x4c, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x71, 0x00), + PHYREGS(0x0934, 0x0930, 0x092c, 0x01bd, 0x01be, 0x01bf), + }, + { .freq = 5890, + RADIOREGS3(0xd6, 0x00, 0x01, 0x02, 0x4d, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x71, 0x00), + PHYREGS(0x0938, 0x0934, 0x0930, 0x01bc, 0x01bd, 0x01be), + }, + { .freq = 5900, + RADIOREGS3(0xd3, 0x00, 0x01, 0x02, 0x4e, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x87, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x71, 0x00), + PHYREGS(0x093c, 0x0938, 0x0934, 0x01bc, 0x01bc, 0x01bd), + }, + { .freq = 5910, + RADIOREGS3(0xd6, 0x00, 0x01, 0x02, 0x4f, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x87, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x71, 0x00), + PHYREGS(0x0940, 0x093c, 0x0938, 0x01bb, 0x01bc, 0x01bc), + }, + { .freq = 2412, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x6c, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x04, 0x04, 0x04, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x1f, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0b, 0x00, 0x1f, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0b), + PHYREGS(0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443), + }, + { .freq = 2417, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x71, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x1f, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0a, 0x00, 0x1f, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0a), + PHYREGS(0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441), + }, + { .freq = 2422, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x76, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0a, 0x00, 0x0e, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0a), + PHYREGS(0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f), + }, + { .freq = 2427, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x7b, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x0d, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0e, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0e, 0x00, 0x0a), + PHYREGS(0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d), + }, + { .freq = 2432, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x80, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x0c, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0e, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0e, 0x00, 0x0a), + PHYREGS(0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a), + }, + { .freq = 2437, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x85, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x0b, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0e, 0x00, 0x0a, 0x00, 0x0b, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0e, 0x00, 0x0a), + PHYREGS(0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438), + }, + { .freq = 2442, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x8a, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x09, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0e, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0e, 0x00, 0x0a), + PHYREGS(0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436), + }, + { .freq = 2447, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x8f, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0e, 0x00, 0x09, 0x00, 0x08, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0e, 0x00, 0x09), + PHYREGS(0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434), + }, + { .freq = 2452, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x94, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x07, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0e, 0x00, 0x09, 0x00, 0x07, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0e, 0x00, 0x09), + PHYREGS(0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431), + }, + { .freq = 2457, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x99, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0d, 0x00, 0x09, 0x00, 0x06, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0d, 0x00, 0x09), + PHYREGS(0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f), + }, + { .freq = 2462, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x9e, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x05, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0d, 0x00, 0x09, 0x00, 0x05, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0d, 0x00, 0x09), + PHYREGS(0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d), + }, + { .freq = 2467, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0xa3, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0d, 0x00, 0x08, 0x00, 0x04, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0d, 0x00, 0x08), + PHYREGS(0x03df, 0x03db, 0x03d7, 0x0422, 0x0427, 0x042b), + }, + { .freq = 2472, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0xa8, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0d, 0x00, 0x08, 0x00, 0x03, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0d, 0x00, 0x08), + PHYREGS(0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429), + }, + { .freq = 2484, + RADIOREGS3(0xff, 0x01, 0x03, 0x09, 0xb4, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0d, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0d, 0x00, 0x08), + PHYREGS(0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424), + }, +}; + +static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev6[] = { + { .freq = 4920, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, + 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x07b4, 0x07b0, 0x07ac, 0x0214, 0x0215, 0x0216), + }, + { .freq = 4930, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xed, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, + 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x07b8, 0x07b4, 0x07b0, 0x0213, 0x0214, 0x0215), + }, + { .freq = 4940, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xee, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, + 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x07bc, 0x07b8, 0x07b4, 0x0212, 0x0213, 0x0214), + }, + { .freq = 4950, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xef, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, + 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x07c0, 0x07bc, 0x07b8, 0x0211, 0x0212, 0x0213), + }, + { .freq = 4960, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf0, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x07c4, 0x07c0, 0x07bc, 0x020f, 0x0211, 0x0212), + }, + { .freq = 4970, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf1, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x07c8, 0x07c4, 0x07c0, 0x020e, 0x020f, 0x0211), + }, + { .freq = 4980, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf2, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x07cc, 0x07c8, 0x07c4, 0x020d, 0x020e, 0x020f), + }, + { .freq = 4990, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf3, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x07d0, 0x07cc, 0x07c8, 0x020c, 0x020d, 0x020e), + }, + { .freq = 5000, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf4, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x07d4, 0x07d0, 0x07cc, 0x020b, 0x020c, 0x020d), + }, + { .freq = 5010, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf5, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x07d8, 0x07d4, 0x07d0, 0x020a, 0x020b, 0x020c), + }, + { .freq = 5020, + RADIOREGS3(0xf7, 0x01, 0x01, 0x01, 0xf6, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x07dc, 0x07d8, 0x07d4, 0x0209, 0x020a, 0x020b), + }, + { .freq = 5030, + RADIOREGS3(0xf7, 0x01, 0x01, 0x01, 0xf7, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x07e0, 0x07dc, 0x07d8, 0x0208, 0x0209, 0x020a), + }, + { .freq = 5040, + RADIOREGS3(0xef, 0x01, 0x01, 0x01, 0xf8, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x07e4, 0x07e0, 0x07dc, 0x0207, 0x0208, 0x0209), + }, + { .freq = 5050, + RADIOREGS3(0xef, 0x01, 0x01, 0x01, 0xf9, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x07e8, 0x07e4, 0x07e0, 0x0206, 0x0207, 0x0208), + }, + { .freq = 5060, + RADIOREGS3(0xe6, 0x01, 0x01, 0x01, 0xfa, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x07ec, 0x07e8, 0x07e4, 0x0205, 0x0206, 0x0207), + }, + { .freq = 5070, + RADIOREGS3(0xe6, 0x01, 0x01, 0x01, 0xfb, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xfd, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x07f0, 0x07ec, 0x07e8, 0x0204, 0x0205, 0x0206), + }, + { .freq = 5080, + RADIOREGS3(0xde, 0x01, 0x01, 0x01, 0xfc, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xfd, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x07f4, 0x07f0, 0x07ec, 0x0203, 0x0204, 0x0205), + }, + { .freq = 5090, + RADIOREGS3(0xde, 0x01, 0x01, 0x01, 0xfd, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xfd, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x07f8, 0x07f4, 0x07f0, 0x0202, 0x0203, 0x0204), + }, + { .freq = 5100, + RADIOREGS3(0xd6, 0x01, 0x01, 0x01, 0xfe, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xfd, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x08, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x07fc, 0x07f8, 0x07f4, 0x0201, 0x0202, 0x0203), + }, + { .freq = 5110, + RADIOREGS3(0xd6, 0x01, 0x01, 0x01, 0xff, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xfc, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x0800, 0x07fc, 0x07f8, 0x0200, 0x0201, 0x0202), + }, + { .freq = 5120, + RADIOREGS3(0xce, 0x01, 0x01, 0x02, 0x00, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xfc, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x0804, 0x0800, 0x07fc, 0x01ff, 0x0200, 0x0201), + }, + { .freq = 5130, + RADIOREGS3(0xce, 0x01, 0x01, 0x02, 0x01, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xfc, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x0808, 0x0804, 0x0800, 0x01fe, 0x01ff, 0x0200), + }, + { .freq = 5140, + RADIOREGS3(0xc6, 0x01, 0x01, 0x02, 0x02, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xfb, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfb, 0x00, 0x08, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x080c, 0x0808, 0x0804, 0x01fd, 0x01fe, 0x01ff), + }, + { .freq = 5160, + RADIOREGS3(0xbe, 0x01, 0x01, 0x02, 0x04, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xfa, 0x00, 0x07, 0x00, 0x77, 0x00, 0x0e, + 0x00, 0x6f, 0x00, 0xfa, 0x00, 0x07, 0x00, 0x77, + 0x00, 0x0e, 0x00, 0x6f, 0x00), + PHYREGS(0x0814, 0x0810, 0x080c, 0x01fb, 0x01fc, 0x01fd), + }, + { .freq = 5170, + RADIOREGS3(0xbe, 0x01, 0x01, 0x02, 0x05, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xfa, 0x00, 0x07, 0x00, 0x77, 0x00, 0x0e, + 0x00, 0x6f, 0x00, 0xfa, 0x00, 0x07, 0x00, 0x77, + 0x00, 0x0e, 0x00, 0x6f, 0x00), + PHYREGS(0x0818, 0x0814, 0x0810, 0x01fa, 0x01fb, 0x01fc), + }, + { .freq = 5180, + RADIOREGS3(0xb6, 0x01, 0x01, 0x02, 0x06, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xf9, 0x00, 0x06, 0x00, 0x77, 0x00, 0x0e, + 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x06, 0x00, 0x77, + 0x00, 0x0e, 0x00, 0x6f, 0x00), + PHYREGS(0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb), + }, + { .freq = 5190, + RADIOREGS3(0xb6, 0x01, 0x01, 0x02, 0x07, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xf9, 0x00, 0x06, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x06, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00), + PHYREGS(0x0820, 0x081c, 0x0818, 0x01f8, 0x01f9, 0x01fa), + }, + { .freq = 5200, + RADIOREGS3(0xaf, 0x01, 0x01, 0x02, 0x08, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xf9, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x05, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00), + PHYREGS(0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9), + }, + { .freq = 5210, + RADIOREGS3(0xaf, 0x01, 0x01, 0x02, 0x09, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xf9, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x05, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00), + PHYREGS(0x0828, 0x0824, 0x0820, 0x01f6, 0x01f7, 0x01f8), + }, + { .freq = 5220, + RADIOREGS3(0xa7, 0x01, 0x01, 0x02, 0x0a, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, + 0xfe, 0xd8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0xd8, 0x00, 0x05, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00), + PHYREGS(0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7), + }, + { .freq = 5230, + RADIOREGS3(0xa7, 0x01, 0x01, 0x02, 0x0b, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, + 0xee, 0xd8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0xd8, 0x00, 0x05, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00), + PHYREGS(0x0830, 0x082c, 0x0828, 0x01f4, 0x01f5, 0x01f6), + }, + { .freq = 5240, + RADIOREGS3(0xa0, 0x01, 0x01, 0x02, 0x0c, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, + 0xee, 0xc8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0xc8, 0x00, 0x05, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00), + PHYREGS(0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5), + }, + { .freq = 5250, + RADIOREGS3(0xa0, 0x01, 0x01, 0x02, 0x0d, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, + 0xed, 0xc7, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0xc7, 0x00, 0x05, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00), + PHYREGS(0x0838, 0x0834, 0x0830, 0x01f2, 0x01f3, 0x01f4), + }, + { .freq = 5260, + RADIOREGS3(0x98, 0x01, 0x01, 0x02, 0x0e, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8e, 0x0e, 0x00, + 0xed, 0xc7, 0x00, 0x04, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0xc7, 0x00, 0x04, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00), + PHYREGS(0x083c, 0x0838, 0x0834, 0x01f1, 0x01f2, 0x01f3), + }, + { .freq = 5270, + RADIOREGS3(0x98, 0x01, 0x01, 0x02, 0x0f, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8e, 0x0e, 0x00, + 0xed, 0xc7, 0x00, 0x04, 0x00, 0x77, 0x00, 0x0c, + 0x00, 0x6f, 0x00, 0xc7, 0x00, 0x04, 0x00, 0x77, + 0x00, 0x0c, 0x00, 0x6f, 0x00), + PHYREGS(0x0840, 0x083c, 0x0838, 0x01f0, 0x01f1, 0x01f2), + }, + { .freq = 5280, + RADIOREGS3(0x91, 0x01, 0x01, 0x02, 0x10, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, + 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c, + 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0c, 0x00, 0x6f, 0x00), + PHYREGS(0x0844, 0x0840, 0x083c, 0x01f0, 0x01f0, 0x01f1), + }, + { .freq = 5290, + RADIOREGS3(0x91, 0x01, 0x01, 0x02, 0x11, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, + 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c, + 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0c, 0x00, 0x6f, 0x00), + PHYREGS(0x0848, 0x0844, 0x0840, 0x01ef, 0x01f0, 0x01f0), + }, + { .freq = 5300, + RADIOREGS3(0x8a, 0x01, 0x01, 0x02, 0x12, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, + 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c, + 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0c, 0x00, 0x6f, 0x00), + PHYREGS(0x084c, 0x0848, 0x0844, 0x01ee, 0x01ef, 0x01f0), + }, + { .freq = 5310, + RADIOREGS3(0x8a, 0x01, 0x01, 0x02, 0x13, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, + 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c, + 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0c, 0x00, 0x6f, 0x00), + PHYREGS(0x0850, 0x084c, 0x0848, 0x01ed, 0x01ee, 0x01ef), + }, + { .freq = 5320, + RADIOREGS3(0x83, 0x01, 0x01, 0x02, 0x14, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, + 0xdb, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c, + 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0c, 0x00, 0x6f, 0x00), + PHYREGS(0x0854, 0x0850, 0x084c, 0x01ec, 0x01ed, 0x01ee), + }, + { .freq = 5330, + RADIOREGS3(0x83, 0x01, 0x01, 0x02, 0x15, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, + 0xcb, 0xa6, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0b, + 0x00, 0x6f, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0b, 0x00, 0x6f, 0x00), + PHYREGS(0x0858, 0x0854, 0x0850, 0x01eb, 0x01ec, 0x01ed), + }, + { .freq = 5340, + RADIOREGS3(0x7c, 0x01, 0x01, 0x02, 0x16, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, + 0xca, 0xa6, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0b, + 0x00, 0x6f, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0b, 0x00, 0x6f, 0x00), + PHYREGS(0x085c, 0x0858, 0x0854, 0x01ea, 0x01eb, 0x01ec), + }, + { .freq = 5350, + RADIOREGS3(0x7c, 0x01, 0x01, 0x02, 0x17, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, + 0xca, 0xa6, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0b, + 0x00, 0x6f, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0b, 0x00, 0x6f, 0x00), + PHYREGS(0x0860, 0x085c, 0x0858, 0x01e9, 0x01ea, 0x01eb), + }, + { .freq = 5360, + RADIOREGS3(0x75, 0x01, 0x01, 0x02, 0x18, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, + 0xc9, 0x95, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x95, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0a, 0x00, 0x6f, 0x00), + PHYREGS(0x0864, 0x0860, 0x085c, 0x01e8, 0x01e9, 0x01ea), + }, + { .freq = 5370, + RADIOREGS3(0x75, 0x01, 0x01, 0x02, 0x19, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, + 0xc9, 0x95, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x95, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0a, 0x00, 0x6f, 0x00), + PHYREGS(0x0868, 0x0864, 0x0860, 0x01e7, 0x01e8, 0x01e9), + }, + { .freq = 5380, + RADIOREGS3(0x6e, 0x01, 0x01, 0x02, 0x1a, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, + 0xb8, 0x95, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x95, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0a, 0x00, 0x6f, 0x00), + PHYREGS(0x086c, 0x0868, 0x0864, 0x01e6, 0x01e7, 0x01e8), + }, + { .freq = 5390, + RADIOREGS3(0x6e, 0x01, 0x01, 0x02, 0x1b, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, + 0xb8, 0x84, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x84, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0a, 0x00, 0x6f, 0x00), + PHYREGS(0x0870, 0x086c, 0x0868, 0x01e5, 0x01e6, 0x01e7), + }, + { .freq = 5400, + RADIOREGS3(0x67, 0x01, 0x01, 0x02, 0x1c, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, + 0xb8, 0x84, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x84, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0a, 0x00, 0x6f, 0x00), + PHYREGS(0x0874, 0x0870, 0x086c, 0x01e5, 0x01e5, 0x01e6), + }, + { .freq = 5410, + RADIOREGS3(0x67, 0x01, 0x01, 0x02, 0x1d, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, + 0xb7, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, + 0x00, 0x0a, 0x00, 0x6f, 0x00), + PHYREGS(0x0878, 0x0874, 0x0870, 0x01e4, 0x01e5, 0x01e5), + }, + { .freq = 5420, + RADIOREGS3(0x61, 0x01, 0x01, 0x02, 0x1e, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, + 0xa7, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, + 0x00, 0x0a, 0x00, 0x6f, 0x00), + PHYREGS(0x087c, 0x0878, 0x0874, 0x01e3, 0x01e4, 0x01e5), + }, + { .freq = 5430, + RADIOREGS3(0x61, 0x01, 0x01, 0x02, 0x1f, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0b, 0x00, + 0xa6, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, + 0x00, 0x0a, 0x00, 0x6f, 0x00), + PHYREGS(0x0880, 0x087c, 0x0878, 0x01e2, 0x01e3, 0x01e4), + }, + { .freq = 5440, + RADIOREGS3(0x5a, 0x01, 0x01, 0x02, 0x20, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, + 0xa6, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00), + PHYREGS(0x0884, 0x0880, 0x087c, 0x01e1, 0x01e2, 0x01e3), + }, + { .freq = 5450, + RADIOREGS3(0x5a, 0x01, 0x01, 0x02, 0x21, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, + 0x95, 0x84, 0x00, 0x01, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x84, 0x00, 0x01, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00), + PHYREGS(0x0888, 0x0884, 0x0880, 0x01e0, 0x01e1, 0x01e2), + }, + { .freq = 5460, + RADIOREGS3(0x53, 0x01, 0x01, 0x02, 0x22, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, + 0x95, 0x84, 0x00, 0x01, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x84, 0x00, 0x01, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00), + PHYREGS(0x088c, 0x0888, 0x0884, 0x01df, 0x01e0, 0x01e1), + }, + { .freq = 5470, + RADIOREGS3(0x53, 0x01, 0x01, 0x02, 0x23, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, + 0x94, 0x73, 0x00, 0x01, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x73, 0x00, 0x01, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00), + PHYREGS(0x0890, 0x088c, 0x0888, 0x01de, 0x01df, 0x01e0), + }, + { .freq = 5480, + RADIOREGS3(0x4d, 0x01, 0x01, 0x02, 0x24, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, + 0x84, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00), + PHYREGS(0x0894, 0x0890, 0x088c, 0x01dd, 0x01de, 0x01df), + }, + { .freq = 5490, + RADIOREGS3(0x4d, 0x01, 0x01, 0x02, 0x25, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, + 0x83, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00), + PHYREGS(0x0898, 0x0894, 0x0890, 0x01dd, 0x01dd, 0x01de), + }, + { .freq = 5500, + RADIOREGS3(0x47, 0x01, 0x01, 0x02, 0x26, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, + 0x82, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00), + PHYREGS(0x089c, 0x0898, 0x0894, 0x01dc, 0x01dd, 0x01dd), + }, + { .freq = 5510, + RADIOREGS3(0x47, 0x01, 0x01, 0x02, 0x27, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, + 0x82, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00), + PHYREGS(0x08a0, 0x089c, 0x0898, 0x01db, 0x01dc, 0x01dd), + }, + { .freq = 5520, + RADIOREGS3(0x40, 0x01, 0x01, 0x02, 0x28, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, + 0x72, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00), + PHYREGS(0x08a4, 0x08a0, 0x089c, 0x01da, 0x01db, 0x01dc), + }, + { .freq = 5530, + RADIOREGS3(0x40, 0x01, 0x01, 0x02, 0x29, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x09, 0x00, + 0x72, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00), + PHYREGS(0x08a8, 0x08a4, 0x08a0, 0x01d9, 0x01da, 0x01db), + }, + { .freq = 5540, + RADIOREGS3(0x3a, 0x01, 0x01, 0x02, 0x2a, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x09, 0x00, + 0x71, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00), + PHYREGS(0x08ac, 0x08a8, 0x08a4, 0x01d8, 0x01d9, 0x01da), + }, + { .freq = 5550, + RADIOREGS3(0x3a, 0x01, 0x01, 0x02, 0x2b, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, + 0x61, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00), + PHYREGS(0x08b0, 0x08ac, 0x08a8, 0x01d7, 0x01d8, 0x01d9), + }, + { .freq = 5560, + RADIOREGS3(0x34, 0x01, 0x01, 0x02, 0x2c, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, + 0x61, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00), + PHYREGS(0x08b4, 0x08b0, 0x08ac, 0x01d7, 0x01d7, 0x01d8), + }, + { .freq = 5570, + RADIOREGS3(0x34, 0x01, 0x01, 0x02, 0x2d, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, + 0x61, 0x62, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x62, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00), + PHYREGS(0x08b8, 0x08b4, 0x08b0, 0x01d6, 0x01d7, 0x01d7), + }, + { .freq = 5580, + RADIOREGS3(0x2e, 0x01, 0x01, 0x02, 0x2e, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x89, 0x08, 0x00, + 0x60, 0x62, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08, + 0x00, 0x6f, 0x00, 0x62, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x08, 0x00, 0x6f, 0x00), + PHYREGS(0x08bc, 0x08b8, 0x08b4, 0x01d5, 0x01d6, 0x01d7), + }, + { .freq = 5590, + RADIOREGS3(0x2e, 0x01, 0x01, 0x02, 0x2f, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x89, 0x08, 0x00, + 0x50, 0x61, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08, + 0x00, 0x6f, 0x00, 0x61, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x08, 0x00, 0x6f, 0x00), + PHYREGS(0x08c0, 0x08bc, 0x08b8, 0x01d4, 0x01d5, 0x01d6), + }, + { .freq = 5600, + RADIOREGS3(0x28, 0x01, 0x01, 0x02, 0x30, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, + 0x50, 0x51, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08, + 0x00, 0x6f, 0x00, 0x51, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x08, 0x00, 0x6f, 0x00), + PHYREGS(0x08c4, 0x08c0, 0x08bc, 0x01d3, 0x01d4, 0x01d5), + }, + { .freq = 5610, + RADIOREGS3(0x28, 0x01, 0x01, 0x02, 0x31, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, + 0x50, 0x51, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08, + 0x00, 0x6f, 0x00, 0x51, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x08, 0x00, 0x6f, 0x00), + PHYREGS(0x08c8, 0x08c4, 0x08c0, 0x01d2, 0x01d3, 0x01d4), + }, + { .freq = 5620, + RADIOREGS3(0x21, 0x01, 0x01, 0x02, 0x32, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, + 0x50, 0x50, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07, + 0x00, 0x6f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x07, 0x00, 0x6f, 0x00), + PHYREGS(0x08cc, 0x08c8, 0x08c4, 0x01d2, 0x01d2, 0x01d3), + }, + { .freq = 5630, + RADIOREGS3(0x21, 0x01, 0x01, 0x02, 0x33, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, + 0x50, 0x50, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07, + 0x00, 0x6f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x07, 0x00, 0x6f, 0x00), + PHYREGS(0x08d0, 0x08cc, 0x08c8, 0x01d1, 0x01d2, 0x01d2), + }, + { .freq = 5640, + RADIOREGS3(0x1c, 0x01, 0x01, 0x02, 0x34, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, + 0x40, 0x50, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07, + 0x00, 0x6f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x07, 0x00, 0x6f, 0x00), + PHYREGS(0x08d4, 0x08d0, 0x08cc, 0x01d0, 0x01d1, 0x01d2), + }, + { .freq = 5650, + RADIOREGS3(0x1c, 0x01, 0x01, 0x02, 0x35, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, + 0x40, 0x40, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07, + 0x00, 0x6f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x07, 0x00, 0x6f, 0x00), + PHYREGS(0x08d8, 0x08d4, 0x08d0, 0x01cf, 0x01d0, 0x01d1), + }, + { .freq = 5660, + RADIOREGS3(0x16, 0x01, 0x01, 0x02, 0x36, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, + 0x40, 0x40, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6f, 0x00), + PHYREGS(0x08dc, 0x08d8, 0x08d4, 0x01ce, 0x01cf, 0x01d0), + }, + { .freq = 5670, + RADIOREGS3(0x16, 0x01, 0x01, 0x02, 0x37, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, + 0x40, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6f, 0x00), + PHYREGS(0x08e0, 0x08dc, 0x08d8, 0x01ce, 0x01ce, 0x01cf), + }, + { .freq = 5680, + RADIOREGS3(0x10, 0x01, 0x01, 0x02, 0x38, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, + 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6f, 0x00), + PHYREGS(0x08e4, 0x08e0, 0x08dc, 0x01cd, 0x01ce, 0x01ce), + }, + { .freq = 5690, + RADIOREGS3(0x10, 0x01, 0x01, 0x02, 0x39, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, + 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6f, 0x00), + PHYREGS(0x08e8, 0x08e4, 0x08e0, 0x01cc, 0x01cd, 0x01ce), + }, + { .freq = 5700, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3a, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, + 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6e, 0x00), + PHYREGS(0x08ec, 0x08e8, 0x08e4, 0x01cb, 0x01cc, 0x01cd), + }, + { .freq = 5710, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3b, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, + 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6e, 0x00), + PHYREGS(0x08f0, 0x08ec, 0x08e8, 0x01ca, 0x01cb, 0x01cc), + }, + { .freq = 5720, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3c, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, + 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6e, 0x00), + PHYREGS(0x08f4, 0x08f0, 0x08ec, 0x01c9, 0x01ca, 0x01cb), + }, + { .freq = 5725, + RADIOREGS3(0x03, 0x01, 0x02, 0x04, 0x79, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, + 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6e, 0x00), + PHYREGS(0x08f6, 0x08f2, 0x08ee, 0x01c9, 0x01ca, 0x01cb), + }, + { .freq = 5730, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3d, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, + 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6e, 0x00), + PHYREGS(0x08f8, 0x08f4, 0x08f0, 0x01c9, 0x01c9, 0x01ca), + }, + { .freq = 5735, + RADIOREGS3(0x03, 0x01, 0x02, 0x04, 0x7b, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, + 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6d, 0x00), + PHYREGS(0x08fa, 0x08f6, 0x08f2, 0x01c8, 0x01c9, 0x01ca), + }, + { .freq = 5740, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3e, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, + 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6d, 0x00), + PHYREGS(0x08fc, 0x08f8, 0x08f4, 0x01c8, 0x01c9, 0x01c9), + }, + { .freq = 5745, + RADIOREGS3(0xfe, 0x00, 0x02, 0x04, 0x7d, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, + 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6d, 0x00), + PHYREGS(0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9), + }, + { .freq = 5750, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3f, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, + 0x20, 0x20, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6d, 0x00, 0x20, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6d, 0x00), + PHYREGS(0x0900, 0x08fc, 0x08f8, 0x01c7, 0x01c8, 0x01c9), + }, + { .freq = 5755, + RADIOREGS3(0xfe, 0x00, 0x02, 0x04, 0x7f, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, + 0x10, 0x20, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6c, 0x00, 0x20, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6c, 0x00), + PHYREGS(0x0902, 0x08fe, 0x08fa, 0x01c7, 0x01c8, 0x01c8), + }, + { .freq = 5760, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x40, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x86, 0x05, 0x00, + 0x10, 0x20, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6c, 0x00, 0x20, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6c, 0x00), + PHYREGS(0x0904, 0x0900, 0x08fc, 0x01c6, 0x01c7, 0x01c8), + }, + { .freq = 5765, + RADIOREGS3(0xf8, 0x00, 0x02, 0x04, 0x81, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x05, 0x05, 0x05, 0x86, 0x05, 0x00, + 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6c, 0x00), + PHYREGS(0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8), + }, + { .freq = 5770, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x41, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, + 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6b, 0x00), + PHYREGS(0x0908, 0x0904, 0x0900, 0x01c6, 0x01c6, 0x01c7), + }, + { .freq = 5775, + RADIOREGS3(0xf8, 0x00, 0x02, 0x04, 0x83, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, + 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6b, 0x00), + PHYREGS(0x090a, 0x0906, 0x0902, 0x01c5, 0x01c6, 0x01c7), + }, + { .freq = 5780, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x42, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, + 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6b, 0x00), + PHYREGS(0x090c, 0x0908, 0x0904, 0x01c5, 0x01c6, 0x01c6), + }, + { .freq = 5785, + RADIOREGS3(0xf2, 0x00, 0x02, 0x04, 0x85, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6b, 0x00), + PHYREGS(0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6), + }, + { .freq = 5790, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x43, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6b, 0x00), + PHYREGS(0x0910, 0x090c, 0x0908, 0x01c4, 0x01c5, 0x01c6), + }, + { .freq = 5795, + RADIOREGS3(0xf2, 0x00, 0x02, 0x04, 0x87, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6b, 0x00), + PHYREGS(0x0912, 0x090e, 0x090a, 0x01c4, 0x01c4, 0x01c5), + }, + { .freq = 5800, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x44, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6b, 0x00), + PHYREGS(0x0914, 0x0910, 0x090c, 0x01c3, 0x01c4, 0x01c5), + }, + { .freq = 5805, + RADIOREGS3(0xed, 0x00, 0x02, 0x04, 0x89, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6a, 0x00), + PHYREGS(0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4), + }, + { .freq = 5810, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x45, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6a, 0x00), + PHYREGS(0x0918, 0x0914, 0x0910, 0x01c2, 0x01c3, 0x01c4), + }, + { .freq = 5815, + RADIOREGS3(0xed, 0x00, 0x02, 0x04, 0x8b, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6a, 0x00), + PHYREGS(0x091a, 0x0916, 0x0912, 0x01c2, 0x01c3, 0x01c4), + }, + { .freq = 5820, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x46, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6a, 0x00), + PHYREGS(0x091c, 0x0918, 0x0914, 0x01c2, 0x01c2, 0x01c3), + }, + { .freq = 5825, + RADIOREGS3(0xed, 0x00, 0x02, 0x04, 0x8d, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x69, 0x00), + PHYREGS(0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3), + }, + { .freq = 5830, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x47, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x69, 0x00), + PHYREGS(0x0920, 0x091c, 0x0918, 0x01c1, 0x01c2, 0x01c2), + }, + { .freq = 5840, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x48, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, + 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x04, 0x00, 0x69, 0x00), + PHYREGS(0x0924, 0x0920, 0x091c, 0x01c0, 0x01c1, 0x01c2), + }, + { .freq = 5850, + RADIOREGS3(0xe0, 0x00, 0x01, 0x02, 0x49, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, + 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x04, 0x00, 0x69, 0x00), + PHYREGS(0x0928, 0x0924, 0x0920, 0x01bf, 0x01c0, 0x01c1), + }, + { .freq = 5860, + RADIOREGS3(0xde, 0x00, 0x01, 0x02, 0x4a, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, + 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x04, 0x00, 0x69, 0x00), + PHYREGS(0x092c, 0x0928, 0x0924, 0x01bf, 0x01bf, 0x01c0), + }, + { .freq = 5870, + RADIOREGS3(0xdb, 0x00, 0x01, 0x02, 0x4b, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, + 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x04, 0x00, 0x68, 0x00), + PHYREGS(0x0930, 0x092c, 0x0928, 0x01be, 0x01bf, 0x01bf), + }, + { .freq = 5880, + RADIOREGS3(0xd8, 0x00, 0x01, 0x02, 0x4c, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, + 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x04, 0x00, 0x68, 0x00), + PHYREGS(0x0934, 0x0930, 0x092c, 0x01bd, 0x01be, 0x01bf), + }, + { .freq = 5890, + RADIOREGS3(0xd6, 0x00, 0x01, 0x02, 0x4d, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, + 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x04, 0x00, 0x68, 0x00), + PHYREGS(0x0938, 0x0934, 0x0930, 0x01bc, 0x01bd, 0x01be), + }, + { .freq = 5900, + RADIOREGS3(0xd3, 0x00, 0x01, 0x02, 0x4e, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, + 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x04, 0x00, 0x68, 0x00), + PHYREGS(0x093c, 0x0938, 0x0934, 0x01bc, 0x01bc, 0x01bd), + }, + { .freq = 5910, + RADIOREGS3(0xd6, 0x00, 0x01, 0x02, 0x4f, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, + 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x04, 0x00, 0x68, 0x00), + PHYREGS(0x0940, 0x093c, 0x0938, 0x01bb, 0x01bc, 0x01bc), + }, + { .freq = 2412, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x6c, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x04, 0x04, 0x04, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x78, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0b, 0x00, 0x0a, 0x00, 0x78, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0b, 0x00, 0x0a), + PHYREGS(0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443), + }, + { .freq = 2417, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x71, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x78, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0b, 0x00, 0x0a, 0x00, 0x78, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0b, 0x00, 0x0a), + PHYREGS(0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441), + }, + { .freq = 2422, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x76, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x67, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0b, 0x00, 0x0a, 0x00, 0x67, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0b, 0x00, 0x0a), + PHYREGS(0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f), + }, + { .freq = 2427, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x7b, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x57, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x0a, 0x00, 0x57, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x0a), + PHYREGS(0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d), + }, + { .freq = 2432, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x80, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x56, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x0a, 0x00, 0x56, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x0a), + PHYREGS(0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a), + }, + { .freq = 2437, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x85, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x46, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x0a, 0x00, 0x46, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x0a), + PHYREGS(0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438), + }, + { .freq = 2442, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x8a, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x45, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x0a, 0x00, 0x45, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x0a), + PHYREGS(0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436), + }, + { .freq = 2447, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x8f, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x34, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x09, 0x00, 0x34, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x09), + PHYREGS(0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434), + }, + { .freq = 2452, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x94, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x23, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x09, 0x00, 0x23, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x09), + PHYREGS(0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431), + }, + { .freq = 2457, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x99, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x12, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x09, 0x00, 0x12, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x09), + PHYREGS(0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f), + }, + { .freq = 2462, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x9e, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x09, 0x00, 0x09, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x09, 0x00, 0x09), + PHYREGS(0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d), + }, + { .freq = 2467, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0xa3, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x09, 0x00, 0x09, 0x00, 0x01, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x09, 0x00, 0x09), + PHYREGS(0x03df, 0x03db, 0x03d7, 0x0422, 0x0427, 0x042b), + }, + { .freq = 2472, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0xa8, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x09, 0x00, 0x09, 0x00, 0x01, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x09, 0x00, 0x09), + PHYREGS(0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429), + }, + { .freq = 2484, + RADIOREGS3(0xff, 0x01, 0x03, 0x09, 0xb4, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x07, 0x07, 0x07, 0x8f, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x09, 0x00, 0x09, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x09, 0x00, 0x09), + PHYREGS(0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424), + }, +}; + +static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev7_9[] = { + { .freq = 4920, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70, 0x00, 0x0f, + 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0b, 0x00, 0x70, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x07b4, 0x07b0, 0x07ac, 0x0214, 0x0215, 0x0216), + }, + { .freq = 4930, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xed, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70, 0x00, 0x0e, + 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0b, 0x00, 0x70, + 0x00, 0x0e, 0x00, 0x6f, 0x00), + PHYREGS(0x07b8, 0x07b4, 0x07b0, 0x0213, 0x0214, 0x0215), + }, + { .freq = 4940, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xee, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70, 0x00, 0x0e, + 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0b, 0x00, 0x70, + 0x00, 0x0e, 0x00, 0x6f, 0x00), + PHYREGS(0x07bc, 0x07b8, 0x07b4, 0x0212, 0x0213, 0x0214), + }, + { .freq = 4950, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xef, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70, 0x00, 0x0e, + 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0b, 0x00, 0x70, + 0x00, 0x0e, 0x00, 0x6f, 0x00), + PHYREGS(0x07c0, 0x07bc, 0x07b8, 0x0211, 0x0212, 0x0213), + }, + { .freq = 4960, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf0, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0e, + 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, + 0x00, 0x0e, 0x00, 0x6f, 0x00), + PHYREGS(0x07c4, 0x07c0, 0x07bc, 0x020f, 0x0211, 0x0212), + }, + { .freq = 4970, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf1, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d, + 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, + 0x00, 0x0d, 0x00, 0x6f, 0x00), + PHYREGS(0x07c8, 0x07c4, 0x07c0, 0x020e, 0x020f, 0x0211), + }, + { .freq = 4980, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf2, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d, + 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, + 0x00, 0x0d, 0x00, 0x6f, 0x00), + PHYREGS(0x07cc, 0x07c8, 0x07c4, 0x020d, 0x020e, 0x020f), + }, + { .freq = 4990, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf3, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d, + 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, + 0x00, 0x0d, 0x00, 0x6f, 0x00), + PHYREGS(0x07d0, 0x07cc, 0x07c8, 0x020c, 0x020d, 0x020e), + }, + { .freq = 5000, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf4, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d, + 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, + 0x00, 0x0d, 0x00, 0x6f, 0x00), + PHYREGS(0x07d4, 0x07d0, 0x07cc, 0x020b, 0x020c, 0x020d), + }, + { .freq = 5010, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf5, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d, + 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, + 0x00, 0x0d, 0x00, 0x6f, 0x00), + PHYREGS(0x07d8, 0x07d4, 0x07d0, 0x020a, 0x020b, 0x020c), + }, + { .freq = 5020, + RADIOREGS3(0xf7, 0x01, 0x01, 0x01, 0xf6, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0d, + 0x00, 0x9f, 0x00, 0xff, 0x00, 0x09, 0x00, 0x70, + 0x00, 0x0d, 0x00, 0x6f, 0x00), + PHYREGS(0x07dc, 0x07d8, 0x07d4, 0x0209, 0x020a, 0x020b), + }, + { .freq = 5030, + RADIOREGS3(0xf7, 0x01, 0x01, 0x01, 0xf7, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xff, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0c, + 0x00, 0x9f, 0x00, 0xff, 0x00, 0x09, 0x00, 0x70, + 0x00, 0x0c, 0x00, 0x6f, 0x00), + PHYREGS(0x07e0, 0x07dc, 0x07d8, 0x0208, 0x0209, 0x020a), + }, + { .freq = 5040, + RADIOREGS3(0xef, 0x01, 0x01, 0x01, 0xf8, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xfe, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0c, + 0x00, 0x9f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x70, + 0x00, 0x0c, 0x00, 0x6f, 0x00), + PHYREGS(0x07e4, 0x07e0, 0x07dc, 0x0207, 0x0208, 0x0209), + }, + { .freq = 5050, + RADIOREGS3(0xef, 0x01, 0x01, 0x01, 0xf9, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xfe, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0c, + 0x00, 0x9f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x70, + 0x00, 0x0c, 0x00, 0x6f, 0x00), + PHYREGS(0x07e8, 0x07e4, 0x07e0, 0x0206, 0x0207, 0x0208), + }, + { .freq = 5060, + RADIOREGS3(0xe6, 0x01, 0x01, 0x01, 0xfa, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xfd, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0c, + 0x00, 0x9f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x70, + 0x00, 0x0c, 0x00, 0x6f, 0x00), + PHYREGS(0x07ec, 0x07e8, 0x07e4, 0x0205, 0x0206, 0x0207), + }, + { .freq = 5070, + RADIOREGS3(0xe6, 0x01, 0x01, 0x01, 0xfb, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xfd, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b, + 0x00, 0x9f, 0x00, 0xfd, 0x00, 0x08, 0x00, 0x70, + 0x00, 0x0b, 0x00, 0x6f, 0x00), + PHYREGS(0x07f0, 0x07ec, 0x07e8, 0x0204, 0x0205, 0x0206), + }, + { .freq = 5080, + RADIOREGS3(0xde, 0x01, 0x01, 0x01, 0xfc, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b, + 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70, + 0x00, 0x0b, 0x00, 0x6f, 0x00), + PHYREGS(0x07f4, 0x07f0, 0x07ec, 0x0203, 0x0204, 0x0205), + }, + { .freq = 5090, + RADIOREGS3(0xde, 0x01, 0x01, 0x01, 0xfd, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b, + 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70, + 0x00, 0x0b, 0x00, 0x6f, 0x00), + PHYREGS(0x07f8, 0x07f4, 0x07f0, 0x0202, 0x0203, 0x0204), + }, + { .freq = 5100, + RADIOREGS3(0xd6, 0x01, 0x01, 0x01, 0xfe, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b, + 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70, + 0x00, 0x0b, 0x00, 0x6f, 0x00), + PHYREGS(0x07fc, 0x07f8, 0x07f4, 0x0201, 0x0202, 0x0203), + }, + { .freq = 5110, + RADIOREGS3(0xd6, 0x01, 0x01, 0x01, 0xff, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b, + 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70, + 0x00, 0x0b, 0x00, 0x6f, 0x00), + PHYREGS(0x0800, 0x07fc, 0x07f8, 0x0200, 0x0201, 0x0202), + }, + { .freq = 5120, + RADIOREGS3(0xce, 0x01, 0x01, 0x02, 0x00, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b, + 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70, + 0x00, 0x0b, 0x00, 0x6f, 0x00), + PHYREGS(0x0804, 0x0800, 0x07fc, 0x01ff, 0x0200, 0x0201), + }, + { .freq = 5130, + RADIOREGS3(0xce, 0x01, 0x01, 0x02, 0x01, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xfb, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0a, + 0x00, 0x9f, 0x00, 0xfb, 0x00, 0x08, 0x00, 0x70, + 0x00, 0x0a, 0x00, 0x6f, 0x00), + PHYREGS(0x0808, 0x0804, 0x0800, 0x01fe, 0x01ff, 0x0200), + }, + { .freq = 5140, + RADIOREGS3(0xc6, 0x01, 0x01, 0x02, 0x02, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xfb, 0x00, 0x07, 0x00, 0x70, 0x00, 0x0a, + 0x00, 0x9f, 0x00, 0xfb, 0x00, 0x07, 0x00, 0x70, + 0x00, 0x0a, 0x00, 0x6f, 0x00), + PHYREGS(0x080c, 0x0808, 0x0804, 0x01fd, 0x01fe, 0x01ff), + }, + { .freq = 5160, + RADIOREGS3(0xbe, 0x01, 0x01, 0x02, 0x04, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xfb, 0x00, 0x07, 0x00, 0x70, 0x00, 0x09, + 0x00, 0x9e, 0x00, 0xfb, 0x00, 0x07, 0x00, 0x70, + 0x00, 0x09, 0x00, 0x6e, 0x00), + PHYREGS(0x0814, 0x0810, 0x080c, 0x01fb, 0x01fc, 0x01fd), + }, + { .freq = 5170, + RADIOREGS3(0xbe, 0x01, 0x01, 0x02, 0x05, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xfb, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09, + 0x00, 0x9e, 0x00, 0xfb, 0x00, 0x06, 0x00, 0x70, + 0x00, 0x09, 0x00, 0x6e, 0x00), + PHYREGS(0x0818, 0x0814, 0x0810, 0x01fa, 0x01fb, 0x01fc), + }, + { .freq = 5180, + RADIOREGS3(0xb6, 0x01, 0x01, 0x02, 0x06, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09, + 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70, + 0x00, 0x09, 0x00, 0x6e, 0x00), + PHYREGS(0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb), + }, + { .freq = 5190, + RADIOREGS3(0xb6, 0x01, 0x01, 0x02, 0x07, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09, + 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70, + 0x00, 0x09, 0x00, 0x6e, 0x00), + PHYREGS(0x0820, 0x081c, 0x0818, 0x01f8, 0x01f9, 0x01fa), + }, + { .freq = 5200, + RADIOREGS3(0xaf, 0x01, 0x01, 0x02, 0x08, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09, + 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70, + 0x00, 0x09, 0x00, 0x6e, 0x00), + PHYREGS(0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9), + }, + { .freq = 5210, + RADIOREGS3(0xaf, 0x01, 0x01, 0x02, 0x09, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09, + 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70, + 0x00, 0x09, 0x00, 0x6e, 0x00), + PHYREGS(0x0828, 0x0824, 0x0820, 0x01f6, 0x01f7, 0x01f8), + }, + { .freq = 5220, + RADIOREGS3(0xa7, 0x01, 0x01, 0x02, 0x0a, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, + 0xfe, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09, + 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70, + 0x00, 0x09, 0x00, 0x6e, 0x00), + PHYREGS(0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7), + }, + { .freq = 5230, + RADIOREGS3(0xa7, 0x01, 0x01, 0x02, 0x0b, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, + 0xee, 0xea, 0x00, 0x06, 0x00, 0x70, 0x00, 0x08, + 0x00, 0x9e, 0x00, 0xea, 0x00, 0x06, 0x00, 0x70, + 0x00, 0x08, 0x00, 0x6e, 0x00), + PHYREGS(0x0830, 0x082c, 0x0828, 0x01f4, 0x01f5, 0x01f6), + }, + { .freq = 5240, + RADIOREGS3(0xa0, 0x01, 0x01, 0x02, 0x0c, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, + 0xee, 0xe9, 0x00, 0x05, 0x00, 0x70, 0x00, 0x08, + 0x00, 0x9d, 0x00, 0xe9, 0x00, 0x05, 0x00, 0x70, + 0x00, 0x08, 0x00, 0x6d, 0x00), + PHYREGS(0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5), + }, + { .freq = 5250, + RADIOREGS3(0xa0, 0x01, 0x01, 0x02, 0x0d, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, + 0xed, 0xe9, 0x00, 0x05, 0x00, 0x70, 0x00, 0x08, + 0x00, 0x9d, 0x00, 0xe9, 0x00, 0x05, 0x00, 0x70, + 0x00, 0x08, 0x00, 0x6d, 0x00), + PHYREGS(0x0838, 0x0834, 0x0830, 0x01f2, 0x01f3, 0x01f4), + }, + { .freq = 5260, + RADIOREGS3(0x98, 0x01, 0x01, 0x02, 0x0e, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8e, 0x0e, 0x00, + 0xed, 0xd9, 0x00, 0x05, 0x00, 0x70, 0x00, 0x08, + 0x00, 0x9d, 0x00, 0xd9, 0x00, 0x05, 0x00, 0x70, + 0x00, 0x08, 0x00, 0x6d, 0x00), + PHYREGS(0x083c, 0x0838, 0x0834, 0x01f1, 0x01f2, 0x01f3), + }, + { .freq = 5270, + RADIOREGS3(0x98, 0x01, 0x01, 0x02, 0x0f, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8e, 0x0e, 0x00, + 0xed, 0xd8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, + 0x00, 0x9c, 0x00, 0xd8, 0x00, 0x04, 0x00, 0x70, + 0x00, 0x07, 0x00, 0x6c, 0x00), + PHYREGS(0x0840, 0x083c, 0x0838, 0x01f0, 0x01f1, 0x01f2), + }, + { .freq = 5280, + RADIOREGS3(0x91, 0x01, 0x01, 0x02, 0x10, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, + 0xdc, 0xc8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, + 0x00, 0x9c, 0x00, 0xc8, 0x00, 0x04, 0x00, 0x70, + 0x00, 0x07, 0x00, 0x6c, 0x00), + PHYREGS(0x0844, 0x0840, 0x083c, 0x01f0, 0x01f0, 0x01f1), + }, + { .freq = 5290, + RADIOREGS3(0x91, 0x01, 0x01, 0x02, 0x11, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, + 0xdc, 0xc8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, + 0x00, 0x9c, 0x00, 0xc8, 0x00, 0x04, 0x00, 0x70, + 0x00, 0x07, 0x00, 0x6c, 0x00), + PHYREGS(0x0848, 0x0844, 0x0840, 0x01ef, 0x01f0, 0x01f0), + }, + { .freq = 5300, + RADIOREGS3(0x8a, 0x01, 0x01, 0x02, 0x12, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, + 0xdc, 0xc8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, + 0x00, 0x9c, 0x00, 0xc8, 0x00, 0x04, 0x00, 0x70, + 0x00, 0x07, 0x00, 0x6c, 0x00), + PHYREGS(0x084c, 0x0848, 0x0844, 0x01ee, 0x01ef, 0x01f0), + }, + { .freq = 5310, + RADIOREGS3(0x8a, 0x01, 0x01, 0x02, 0x13, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, + 0xdc, 0xc8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, + 0x00, 0x9c, 0x00, 0xc8, 0x00, 0x04, 0x00, 0x70, + 0x00, 0x07, 0x00, 0x6c, 0x00), + PHYREGS(0x0850, 0x084c, 0x0848, 0x01ed, 0x01ee, 0x01ef), + }, + { .freq = 5320, + RADIOREGS3(0x83, 0x01, 0x01, 0x02, 0x14, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, + 0xdb, 0xb8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, + 0x00, 0x9c, 0x00, 0xb8, 0x00, 0x04, 0x00, 0x70, + 0x00, 0x07, 0x00, 0x6c, 0x00), + PHYREGS(0x0854, 0x0850, 0x084c, 0x01ec, 0x01ed, 0x01ee), + }, + { .freq = 5330, + RADIOREGS3(0x83, 0x01, 0x01, 0x02, 0x15, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, + 0xcb, 0xb7, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, + 0x00, 0x9b, 0x00, 0xb7, 0x00, 0x04, 0x00, 0x70, + 0x00, 0x07, 0x00, 0x6b, 0x00), + PHYREGS(0x0858, 0x0854, 0x0850, 0x01eb, 0x01ec, 0x01ed), + }, + { .freq = 5340, + RADIOREGS3(0x7c, 0x01, 0x01, 0x02, 0x16, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, + 0xca, 0xb7, 0x00, 0x03, 0x00, 0x70, 0x00, 0x07, + 0x00, 0x9b, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x70, + 0x00, 0x07, 0x00, 0x6b, 0x00), + PHYREGS(0x085c, 0x0858, 0x0854, 0x01ea, 0x01eb, 0x01ec), + }, + { .freq = 5350, + RADIOREGS3(0x7c, 0x01, 0x01, 0x02, 0x17, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, + 0xca, 0xa7, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06, + 0x00, 0x9b, 0x00, 0xa7, 0x00, 0x03, 0x00, 0x70, + 0x00, 0x06, 0x00, 0x6b, 0x00), + PHYREGS(0x0860, 0x085c, 0x0858, 0x01e9, 0x01ea, 0x01eb), + }, + { .freq = 5360, + RADIOREGS3(0x75, 0x01, 0x01, 0x02, 0x18, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, + 0xc9, 0xa6, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06, + 0x00, 0x9b, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x70, + 0x00, 0x06, 0x00, 0x6b, 0x00), + PHYREGS(0x0864, 0x0860, 0x085c, 0x01e8, 0x01e9, 0x01ea), + }, + { .freq = 5370, + RADIOREGS3(0x75, 0x01, 0x01, 0x02, 0x19, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, + 0xc9, 0xa6, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06, + 0x00, 0x9b, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x70, + 0x00, 0x06, 0x00, 0x7b, 0x00), + PHYREGS(0x0868, 0x0864, 0x0860, 0x01e7, 0x01e8, 0x01e9), + }, + { .freq = 5380, + RADIOREGS3(0x6e, 0x01, 0x01, 0x02, 0x1a, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, + 0xb8, 0x96, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06, + 0x00, 0x9a, 0x00, 0x96, 0x00, 0x03, 0x00, 0x70, + 0x00, 0x06, 0x00, 0x7a, 0x00), + PHYREGS(0x086c, 0x0868, 0x0864, 0x01e6, 0x01e7, 0x01e8), + }, + { .freq = 5390, + RADIOREGS3(0x6e, 0x01, 0x01, 0x02, 0x1b, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, + 0xb8, 0x95, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06, + 0x00, 0x9a, 0x00, 0x95, 0x00, 0x03, 0x00, 0x70, + 0x00, 0x06, 0x00, 0x7a, 0x00), + PHYREGS(0x0870, 0x086c, 0x0868, 0x01e5, 0x01e6, 0x01e7), + }, + { .freq = 5400, + RADIOREGS3(0x67, 0x01, 0x01, 0x02, 0x1c, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, + 0xb8, 0x95, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06, + 0x00, 0x9a, 0x00, 0x95, 0x00, 0x03, 0x00, 0x70, + 0x00, 0x06, 0x00, 0x7a, 0x00), + PHYREGS(0x0874, 0x0870, 0x086c, 0x01e5, 0x01e5, 0x01e6), + }, + { .freq = 5410, + RADIOREGS3(0x67, 0x01, 0x01, 0x02, 0x1d, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, + 0xb7, 0x95, 0x00, 0x03, 0x00, 0x70, 0x00, 0x05, + 0x00, 0x9a, 0x00, 0x95, 0x00, 0x03, 0x00, 0x70, + 0x00, 0x05, 0x00, 0x7a, 0x00), + PHYREGS(0x0878, 0x0874, 0x0870, 0x01e4, 0x01e5, 0x01e5), + }, + { .freq = 5420, + RADIOREGS3(0x61, 0x01, 0x01, 0x02, 0x1e, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, + 0xa7, 0x95, 0x00, 0x03, 0x00, 0x70, 0x00, 0x05, + 0x00, 0x9a, 0x00, 0x95, 0x00, 0x03, 0x00, 0x70, + 0x00, 0x05, 0x00, 0x7a, 0x00), + PHYREGS(0x087c, 0x0878, 0x0874, 0x01e3, 0x01e4, 0x01e5), + }, + { .freq = 5430, + RADIOREGS3(0x61, 0x01, 0x01, 0x02, 0x1f, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0b, 0x00, + 0xa6, 0x85, 0x00, 0x02, 0x00, 0x70, 0x00, 0x05, + 0x00, 0x99, 0x00, 0x85, 0x00, 0x02, 0x00, 0x70, + 0x00, 0x05, 0x00, 0x79, 0x00), + PHYREGS(0x0880, 0x087c, 0x0878, 0x01e2, 0x01e3, 0x01e4), + }, + { .freq = 5440, + RADIOREGS3(0x5a, 0x01, 0x01, 0x02, 0x20, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, + 0xa6, 0x84, 0x00, 0x02, 0x00, 0x70, 0x00, 0x05, + 0x00, 0x99, 0x00, 0x84, 0x00, 0x02, 0x00, 0x70, + 0x00, 0x05, 0x00, 0x79, 0x00), + PHYREGS(0x0884, 0x0880, 0x087c, 0x01e1, 0x01e2, 0x01e3), + }, + { .freq = 5450, + RADIOREGS3(0x5a, 0x01, 0x01, 0x02, 0x21, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, + 0x95, 0x84, 0x00, 0x02, 0x00, 0x70, 0x00, 0x05, + 0x00, 0x99, 0x00, 0x84, 0x00, 0x02, 0x00, 0x70, + 0x00, 0x05, 0x00, 0x79, 0x00), + PHYREGS(0x0888, 0x0884, 0x0880, 0x01e0, 0x01e1, 0x01e2), + }, + { .freq = 5460, + RADIOREGS3(0x53, 0x01, 0x01, 0x02, 0x22, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, + 0x95, 0x84, 0x00, 0x02, 0x00, 0x70, 0x00, 0x04, + 0x00, 0x99, 0x00, 0x84, 0x00, 0x02, 0x00, 0x70, + 0x00, 0x04, 0x00, 0x79, 0x00), + PHYREGS(0x088c, 0x0888, 0x0884, 0x01df, 0x01e0, 0x01e1), + }, + { .freq = 5470, + RADIOREGS3(0x53, 0x01, 0x01, 0x02, 0x23, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, + 0x94, 0x74, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04, + 0x00, 0x99, 0x00, 0x74, 0x00, 0x01, 0x00, 0x70, + 0x00, 0x04, 0x00, 0x79, 0x00), + PHYREGS(0x0890, 0x088c, 0x0888, 0x01de, 0x01df, 0x01e0), + }, + { .freq = 5480, + RADIOREGS3(0x4d, 0x01, 0x01, 0x02, 0x24, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, + 0x84, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04, + 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70, + 0x00, 0x04, 0x00, 0x78, 0x00), + PHYREGS(0x0894, 0x0890, 0x088c, 0x01dd, 0x01de, 0x01df), + }, + { .freq = 5490, + RADIOREGS3(0x4d, 0x01, 0x01, 0x02, 0x25, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, + 0x83, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04, + 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70, + 0x00, 0x04, 0x00, 0x78, 0x00), + PHYREGS(0x0898, 0x0894, 0x0890, 0x01dd, 0x01dd, 0x01de), + }, + { .freq = 5500, + RADIOREGS3(0x47, 0x01, 0x01, 0x02, 0x26, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, + 0x82, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04, + 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70, + 0x00, 0x04, 0x00, 0x78, 0x00), + PHYREGS(0x089c, 0x0898, 0x0894, 0x01dc, 0x01dd, 0x01dd), + }, + { .freq = 5510, + RADIOREGS3(0x47, 0x01, 0x01, 0x02, 0x27, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, + 0x82, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04, + 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70, + 0x00, 0x04, 0x00, 0x78, 0x00), + PHYREGS(0x08a0, 0x089c, 0x0898, 0x01db, 0x01dc, 0x01dd), + }, + { .freq = 5520, + RADIOREGS3(0x40, 0x01, 0x01, 0x02, 0x28, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, + 0x72, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04, + 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70, + 0x00, 0x04, 0x00, 0x78, 0x00), + PHYREGS(0x08a4, 0x08a0, 0x089c, 0x01da, 0x01db, 0x01dc), + }, + { .freq = 5530, + RADIOREGS3(0x40, 0x01, 0x01, 0x02, 0x29, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x09, 0x00, + 0x72, 0x63, 0x00, 0x01, 0x00, 0x70, 0x00, 0x03, + 0x00, 0x98, 0x00, 0x63, 0x00, 0x01, 0x00, 0x70, + 0x00, 0x03, 0x00, 0x78, 0x00), + PHYREGS(0x08a8, 0x08a4, 0x08a0, 0x01d9, 0x01da, 0x01db), + }, + { .freq = 5540, + RADIOREGS3(0x3a, 0x01, 0x01, 0x02, 0x2a, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x09, 0x00, + 0x71, 0x62, 0x00, 0x00, 0x00, 0x70, 0x00, 0x03, + 0x00, 0x97, 0x00, 0x62, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x03, 0x00, 0x77, 0x00), + PHYREGS(0x08ac, 0x08a8, 0x08a4, 0x01d8, 0x01d9, 0x01da), + }, + { .freq = 5550, + RADIOREGS3(0x3a, 0x01, 0x01, 0x02, 0x2b, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, + 0x61, 0x62, 0x00, 0x00, 0x00, 0x70, 0x00, 0x03, + 0x00, 0x97, 0x00, 0x62, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x03, 0x00, 0x77, 0x00), + PHYREGS(0x08b0, 0x08ac, 0x08a8, 0x01d7, 0x01d8, 0x01d9), + }, + { .freq = 5560, + RADIOREGS3(0x34, 0x01, 0x01, 0x02, 0x2c, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, + 0x61, 0x62, 0x00, 0x00, 0x00, 0x70, 0x00, 0x03, + 0x00, 0x97, 0x00, 0x62, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x03, 0x00, 0x77, 0x00), + PHYREGS(0x08b4, 0x08b0, 0x08ac, 0x01d7, 0x01d7, 0x01d8), + }, + { .freq = 5570, + RADIOREGS3(0x34, 0x01, 0x01, 0x02, 0x2d, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, + 0x61, 0x52, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, + 0x00, 0x96, 0x00, 0x52, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x02, 0x00, 0x76, 0x00), + PHYREGS(0x08b8, 0x08b4, 0x08b0, 0x01d6, 0x01d7, 0x01d7), + }, + { .freq = 5580, + RADIOREGS3(0x2e, 0x01, 0x01, 0x02, 0x2e, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x89, 0x08, 0x00, + 0x60, 0x52, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, + 0x00, 0x96, 0x00, 0x52, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x02, 0x00, 0x86, 0x00), + PHYREGS(0x08bc, 0x08b8, 0x08b4, 0x01d5, 0x01d6, 0x01d7), + }, + { .freq = 5590, + RADIOREGS3(0x2e, 0x01, 0x01, 0x02, 0x2f, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x89, 0x08, 0x00, + 0x50, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, + 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x02, 0x00, 0x86, 0x00), + PHYREGS(0x08c0, 0x08bc, 0x08b8, 0x01d4, 0x01d5, 0x01d6), + }, + { .freq = 5600, + RADIOREGS3(0x28, 0x01, 0x01, 0x02, 0x30, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, + 0x50, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, + 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x02, 0x00, 0x86, 0x00), + PHYREGS(0x08c4, 0x08c0, 0x08bc, 0x01d3, 0x01d4, 0x01d5), + }, + { .freq = 5610, + RADIOREGS3(0x28, 0x01, 0x01, 0x02, 0x31, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, + 0x50, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, + 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x02, 0x00, 0x86, 0x00), + PHYREGS(0x08c8, 0x08c4, 0x08c0, 0x01d2, 0x01d3, 0x01d4), + }, + { .freq = 5620, + RADIOREGS3(0x21, 0x01, 0x01, 0x02, 0x32, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, + 0x50, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, + 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x02, 0x00, 0x86, 0x00), + PHYREGS(0x08cc, 0x08c8, 0x08c4, 0x01d2, 0x01d2, 0x01d3), + }, + { .freq = 5630, + RADIOREGS3(0x21, 0x01, 0x01, 0x02, 0x33, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, + 0x50, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, + 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x02, 0x00, 0x86, 0x00), + PHYREGS(0x08d0, 0x08cc, 0x08c8, 0x01d1, 0x01d2, 0x01d2), + }, + { .freq = 5640, + RADIOREGS3(0x1c, 0x01, 0x01, 0x02, 0x34, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, + 0x40, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, + 0x00, 0x95, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x02, 0x00, 0x85, 0x00), + PHYREGS(0x08d4, 0x08d0, 0x08cc, 0x01d0, 0x01d1, 0x01d2), + }, + { .freq = 5650, + RADIOREGS3(0x1c, 0x01, 0x01, 0x02, 0x35, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, + 0x40, 0x50, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, + 0x00, 0x95, 0x00, 0x50, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x01, 0x00, 0x85, 0x00), + PHYREGS(0x08d8, 0x08d4, 0x08d0, 0x01cf, 0x01d0, 0x01d1), + }, + { .freq = 5660, + RADIOREGS3(0x16, 0x01, 0x01, 0x02, 0x36, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, + 0x40, 0x50, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, + 0x00, 0x95, 0x00, 0x50, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x01, 0x00, 0x85, 0x00), + PHYREGS(0x08dc, 0x08d8, 0x08d4, 0x01ce, 0x01cf, 0x01d0), + }, + { .freq = 5670, + RADIOREGS3(0x16, 0x01, 0x01, 0x02, 0x37, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, + 0x40, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, + 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x01, 0x00, 0x84, 0x00), + PHYREGS(0x08e0, 0x08dc, 0x08d8, 0x01ce, 0x01ce, 0x01cf), + }, + { .freq = 5680, + RADIOREGS3(0x10, 0x01, 0x01, 0x02, 0x38, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, + 0x30, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, + 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x01, 0x00, 0x84, 0x00), + PHYREGS(0x08e4, 0x08e0, 0x08dc, 0x01cd, 0x01ce, 0x01ce), + }, + { .freq = 5690, + RADIOREGS3(0x10, 0x01, 0x01, 0x02, 0x39, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, + 0x30, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, + 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x01, 0x00, 0x94, 0x00), + PHYREGS(0x08e8, 0x08e4, 0x08e0, 0x01cc, 0x01cd, 0x01ce), + }, + { .freq = 5700, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3a, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, + 0x30, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, + 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x01, 0x00, 0x94, 0x00), + PHYREGS(0x08ec, 0x08e8, 0x08e4, 0x01cb, 0x01cc, 0x01cd), + }, + { .freq = 5710, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3b, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, + 0x30, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, + 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x01, 0x00, 0x94, 0x00), + PHYREGS(0x08f0, 0x08ec, 0x08e8, 0x01ca, 0x01cb, 0x01cc), + }, + { .freq = 5720, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3c, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, + 0x30, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, + 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x01, 0x00, 0x94, 0x00), + PHYREGS(0x08f4, 0x08f0, 0x08ec, 0x01c9, 0x01ca, 0x01cb), + }, + { .freq = 5725, + RADIOREGS3(0x03, 0x01, 0x02, 0x04, 0x79, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, + 0x30, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, + 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x01, 0x00, 0x94, 0x00), + PHYREGS(0x08f6, 0x08f2, 0x08ee, 0x01c9, 0x01ca, 0x01cb), + }, + { .freq = 5730, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3d, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, + 0x20, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, + 0x00, 0x94, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x01, 0x00, 0x94, 0x00), + PHYREGS(0x08f8, 0x08f4, 0x08f0, 0x01c9, 0x01c9, 0x01ca), + }, + { .freq = 5735, + RADIOREGS3(0x03, 0x01, 0x02, 0x04, 0x7b, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, + 0x20, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x93, 0x00), + PHYREGS(0x08fa, 0x08f6, 0x08f2, 0x01c8, 0x01c9, 0x01ca), + }, + { .freq = 5740, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3e, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, + 0x20, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x93, 0x00), + PHYREGS(0x08fc, 0x08f8, 0x08f4, 0x01c8, 0x01c9, 0x01c9), + }, + { .freq = 5745, + RADIOREGS3(0xfe, 0x00, 0x02, 0x04, 0x7d, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, + 0x20, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x93, 0x00), + PHYREGS(0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9), + }, + { .freq = 5750, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3f, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, + 0x20, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x93, 0x00), + PHYREGS(0x0900, 0x08fc, 0x08f8, 0x01c7, 0x01c8, 0x01c9), + }, + { .freq = 5755, + RADIOREGS3(0xfe, 0x00, 0x02, 0x04, 0x7f, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, + 0x10, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x93, 0x00), + PHYREGS(0x0902, 0x08fe, 0x08fa, 0x01c7, 0x01c8, 0x01c8), + }, + { .freq = 5760, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x40, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x86, 0x05, 0x00, + 0x10, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x93, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x93, 0x00), + PHYREGS(0x0904, 0x0900, 0x08fc, 0x01c6, 0x01c7, 0x01c8), + }, + { .freq = 5765, + RADIOREGS3(0xf8, 0x00, 0x02, 0x04, 0x81, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x05, 0x05, 0x05, 0x86, 0x05, 0x00, + 0x10, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00), + PHYREGS(0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8), + }, + { .freq = 5770, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x41, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, + 0x10, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00), + PHYREGS(0x0908, 0x0904, 0x0900, 0x01c6, 0x01c6, 0x01c7), + }, + { .freq = 5775, + RADIOREGS3(0xf8, 0x00, 0x02, 0x04, 0x83, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, + 0x10, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00), + PHYREGS(0x090a, 0x0906, 0x0902, 0x01c5, 0x01c6, 0x01c7), + }, + { .freq = 5780, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x42, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, + 0x10, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00), + PHYREGS(0x090c, 0x0908, 0x0904, 0x01c5, 0x01c6, 0x01c6), + }, + { .freq = 5785, + RADIOREGS3(0xf2, 0x00, 0x02, 0x04, 0x85, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00), + PHYREGS(0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6), + }, + { .freq = 5790, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x43, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00), + PHYREGS(0x0910, 0x090c, 0x0908, 0x01c4, 0x01c5, 0x01c6), + }, + { .freq = 5795, + RADIOREGS3(0xf2, 0x00, 0x02, 0x04, 0x87, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00), + PHYREGS(0x0912, 0x090e, 0x090a, 0x01c4, 0x01c4, 0x01c5), + }, + { .freq = 5800, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x44, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00), + PHYREGS(0x0914, 0x0910, 0x090c, 0x01c3, 0x01c4, 0x01c5), + }, + { .freq = 5805, + RADIOREGS3(0xed, 0x00, 0x02, 0x04, 0x89, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00), + PHYREGS(0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4), + }, + { .freq = 5810, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x45, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00), + PHYREGS(0x0918, 0x0914, 0x0910, 0x01c2, 0x01c3, 0x01c4), + }, + { .freq = 5815, + RADIOREGS3(0xed, 0x00, 0x02, 0x04, 0x8b, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00), + PHYREGS(0x091a, 0x0916, 0x0912, 0x01c2, 0x01c3, 0x01c4), + }, + { .freq = 5820, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x46, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00), + PHYREGS(0x091c, 0x0918, 0x0914, 0x01c2, 0x01c2, 0x01c3), + }, + { .freq = 5825, + RADIOREGS3(0xed, 0x00, 0x02, 0x04, 0x8d, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00), + PHYREGS(0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3), + }, + { .freq = 5830, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x47, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00), + PHYREGS(0x0920, 0x091c, 0x0918, 0x01c1, 0x01c2, 0x01c2), + }, + { .freq = 5840, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x48, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00), + PHYREGS(0x0924, 0x0920, 0x091c, 0x01c0, 0x01c1, 0x01c2), + }, + { .freq = 5850, + RADIOREGS3(0xe0, 0x00, 0x01, 0x02, 0x49, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00), + PHYREGS(0x0928, 0x0924, 0x0920, 0x01bf, 0x01c0, 0x01c1), + }, + { .freq = 5860, + RADIOREGS3(0xde, 0x00, 0x01, 0x02, 0x4a, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00), + PHYREGS(0x092c, 0x0928, 0x0924, 0x01bf, 0x01bf, 0x01c0), + }, + { .freq = 5870, + RADIOREGS3(0xdb, 0x00, 0x01, 0x02, 0x4b, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x91, 0x00), + PHYREGS(0x0930, 0x092c, 0x0928, 0x01be, 0x01bf, 0x01bf), + }, + { .freq = 5880, + RADIOREGS3(0xd8, 0x00, 0x01, 0x02, 0x4c, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x91, 0x00), + PHYREGS(0x0934, 0x0930, 0x092c, 0x01bd, 0x01be, 0x01bf), + }, + { .freq = 5890, + RADIOREGS3(0xd6, 0x00, 0x01, 0x02, 0x4d, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x91, 0x00), + PHYREGS(0x0938, 0x0934, 0x0930, 0x01bc, 0x01bd, 0x01be), + }, + { .freq = 5900, + RADIOREGS3(0xd3, 0x00, 0x01, 0x02, 0x4e, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x91, 0x00), + PHYREGS(0x093c, 0x0938, 0x0934, 0x01bc, 0x01bc, 0x01bd), + }, + { .freq = 5910, + RADIOREGS3(0xd6, 0x00, 0x01, 0x02, 0x4f, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x91, 0x00), + PHYREGS(0x0940, 0x093c, 0x0938, 0x01bb, 0x01bc, 0x01bc), + }, + { .freq = 2412, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x6c, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x04, 0x04, 0x04, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x89, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0b, 0x00, 0x89, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0b), + PHYREGS(0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443), + }, + { .freq = 2417, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x71, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x89, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0a, 0x00, 0x89, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0a), + PHYREGS(0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441), + }, + { .freq = 2422, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x76, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x89, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0a, 0x00, 0x89, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0a), + PHYREGS(0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f), + }, + { .freq = 2427, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x7b, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x78, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0e, 0x00, 0x0a, 0x00, 0x78, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0e, 0x00, 0x0a), + PHYREGS(0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d), + }, + { .freq = 2432, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x80, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x77, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0e, 0x00, 0x0a, 0x00, 0x77, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0e, 0x00, 0x0a), + PHYREGS(0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a), + }, + { .freq = 2437, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x85, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x76, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0e, 0x00, 0x0a, 0x00, 0x76, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0e, 0x00, 0x0a), + PHYREGS(0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438), + }, + { .freq = 2442, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x8a, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x66, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0e, 0x00, 0x0a, 0x00, 0x66, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0e, 0x00, 0x0a), + PHYREGS(0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436), + }, + { .freq = 2447, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x8f, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x55, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0e, 0x00, 0x09, 0x00, 0x55, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0e, 0x00, 0x09), + PHYREGS(0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434), + }, + { .freq = 2452, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x94, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x45, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0e, 0x00, 0x09, 0x00, 0x45, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0e, 0x00, 0x09), + PHYREGS(0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431), + }, + { .freq = 2457, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x99, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x34, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0d, 0x00, 0x09, 0x00, 0x34, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0d, 0x00, 0x09), + PHYREGS(0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f), + }, + { .freq = 2462, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x9e, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x33, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0d, 0x00, 0x09, 0x00, 0x33, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0d, 0x00, 0x09), + PHYREGS(0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d), + }, + { .freq = 2467, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0xa3, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x22, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0d, 0x00, 0x08, 0x00, 0x22, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0d, 0x00, 0x08), + PHYREGS(0x03df, 0x03db, 0x03d7, 0x0422, 0x0427, 0x042b), + }, + { .freq = 2472, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0xa8, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0d, 0x00, 0x08, 0x00, 0x11, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0d, 0x00, 0x08), + PHYREGS(0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429), + }, + { .freq = 2484, + RADIOREGS3(0xff, 0x01, 0x03, 0x09, 0xb4, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x07, 0x07, 0x07, 0x8f, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0d, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0d, 0x00, 0x08), + PHYREGS(0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424), + }, +}; + +static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev8[] = { + { .freq = 4920, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, + 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x07b4, 0x07b0, 0x07ac, 0x0214, 0x0215, 0x0216), + }, + { .freq = 4930, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xed, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, + 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x07b8, 0x07b4, 0x07b0, 0x0213, 0x0214, 0x0215), + }, + { .freq = 4940, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xee, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, + 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x07bc, 0x07b8, 0x07b4, 0x0212, 0x0213, 0x0214), + }, + { .freq = 4950, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xef, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, + 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x07c0, 0x07bc, 0x07b8, 0x0211, 0x0212, 0x0213), + }, + { .freq = 4960, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf0, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x07c4, 0x07c0, 0x07bc, 0x020f, 0x0211, 0x0212), + }, + { .freq = 4970, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf1, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x07c8, 0x07c4, 0x07c0, 0x020e, 0x020f, 0x0211), + }, + { .freq = 4980, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf2, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x07cc, 0x07c8, 0x07c4, 0x020d, 0x020e, 0x020f), + }, + { .freq = 4990, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf3, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x07d0, 0x07cc, 0x07c8, 0x020c, 0x020d, 0x020e), + }, + { .freq = 5000, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf4, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x07d4, 0x07d0, 0x07cc, 0x020b, 0x020c, 0x020d), + }, + { .freq = 5010, + RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf5, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x07d8, 0x07d4, 0x07d0, 0x020a, 0x020b, 0x020c), + }, + { .freq = 5020, + RADIOREGS3(0xf7, 0x01, 0x01, 0x01, 0xf6, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x07dc, 0x07d8, 0x07d4, 0x0209, 0x020a, 0x020b), + }, + { .freq = 5030, + RADIOREGS3(0xf7, 0x01, 0x01, 0x01, 0xf7, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x07e0, 0x07dc, 0x07d8, 0x0208, 0x0209, 0x020a), + }, + { .freq = 5040, + RADIOREGS3(0xef, 0x01, 0x01, 0x01, 0xf8, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x07e4, 0x07e0, 0x07dc, 0x0207, 0x0208, 0x0209), + }, + { .freq = 5050, + RADIOREGS3(0xef, 0x01, 0x01, 0x01, 0xf9, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x07e8, 0x07e4, 0x07e0, 0x0206, 0x0207, 0x0208), + }, + { .freq = 5060, + RADIOREGS3(0xe6, 0x01, 0x01, 0x01, 0xfa, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x07ec, 0x07e8, 0x07e4, 0x0205, 0x0206, 0x0207), + }, + { .freq = 5070, + RADIOREGS3(0xe6, 0x01, 0x01, 0x01, 0xfb, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xfd, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x07f0, 0x07ec, 0x07e8, 0x0204, 0x0205, 0x0206), + }, + { .freq = 5080, + RADIOREGS3(0xde, 0x01, 0x01, 0x01, 0xfc, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xfd, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x07f4, 0x07f0, 0x07ec, 0x0203, 0x0204, 0x0205), + }, + { .freq = 5090, + RADIOREGS3(0xde, 0x01, 0x01, 0x01, 0xfd, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, + 0xff, 0xfd, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x07f8, 0x07f4, 0x07f0, 0x0202, 0x0203, 0x0204), + }, + { .freq = 5100, + RADIOREGS3(0xd6, 0x01, 0x01, 0x01, 0xfe, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xfd, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x08, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x07fc, 0x07f8, 0x07f4, 0x0201, 0x0202, 0x0203), + }, + { .freq = 5110, + RADIOREGS3(0xd6, 0x01, 0x01, 0x01, 0xff, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xfc, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x0800, 0x07fc, 0x07f8, 0x0200, 0x0201, 0x0202), + }, + { .freq = 5120, + RADIOREGS3(0xce, 0x01, 0x01, 0x02, 0x00, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xfc, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x0804, 0x0800, 0x07fc, 0x01ff, 0x0200, 0x0201), + }, + { .freq = 5130, + RADIOREGS3(0xce, 0x01, 0x01, 0x02, 0x01, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xfc, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x0808, 0x0804, 0x0800, 0x01fe, 0x01ff, 0x0200), + }, + { .freq = 5140, + RADIOREGS3(0xc6, 0x01, 0x01, 0x02, 0x02, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xfb, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0xfb, 0x00, 0x08, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00), + PHYREGS(0x080c, 0x0808, 0x0804, 0x01fd, 0x01fe, 0x01ff), + }, + { .freq = 5160, + RADIOREGS3(0xbe, 0x01, 0x01, 0x02, 0x04, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xfa, 0x00, 0x07, 0x00, 0x77, 0x00, 0x0e, + 0x00, 0x6f, 0x00, 0xfa, 0x00, 0x07, 0x00, 0x77, + 0x00, 0x0e, 0x00, 0x6f, 0x00), + PHYREGS(0x0814, 0x0810, 0x080c, 0x01fb, 0x01fc, 0x01fd), + }, + { .freq = 5170, + RADIOREGS3(0xbe, 0x01, 0x01, 0x02, 0x05, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xfa, 0x00, 0x07, 0x00, 0x77, 0x00, 0x0e, + 0x00, 0x6f, 0x00, 0xfa, 0x00, 0x07, 0x00, 0x77, + 0x00, 0x0e, 0x00, 0x6f, 0x00), + PHYREGS(0x0818, 0x0814, 0x0810, 0x01fa, 0x01fb, 0x01fc), + }, + { .freq = 5180, + RADIOREGS3(0xb6, 0x01, 0x01, 0x02, 0x06, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xf9, 0x00, 0x06, 0x00, 0x77, 0x00, 0x0e, + 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x06, 0x00, 0x77, + 0x00, 0x0e, 0x00, 0x6f, 0x00), + PHYREGS(0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb), + }, + { .freq = 5190, + RADIOREGS3(0xb6, 0x01, 0x01, 0x02, 0x07, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xf9, 0x00, 0x06, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x06, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00), + PHYREGS(0x0820, 0x081c, 0x0818, 0x01f8, 0x01f9, 0x01fa), + }, + { .freq = 5200, + RADIOREGS3(0xaf, 0x01, 0x01, 0x02, 0x08, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xf9, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x05, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00), + PHYREGS(0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9), + }, + { .freq = 5210, + RADIOREGS3(0xaf, 0x01, 0x01, 0x02, 0x09, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xf9, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x05, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00), + PHYREGS(0x0828, 0x0824, 0x0820, 0x01f6, 0x01f7, 0x01f8), + }, + { .freq = 5220, + RADIOREGS3(0xa7, 0x01, 0x01, 0x02, 0x0a, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, + 0xfe, 0xd8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0xd8, 0x00, 0x05, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00), + PHYREGS(0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7), + }, + { .freq = 5230, + RADIOREGS3(0xa7, 0x01, 0x01, 0x02, 0x0b, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, + 0xee, 0xd8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0xd8, 0x00, 0x05, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00), + PHYREGS(0x0830, 0x082c, 0x0828, 0x01f4, 0x01f5, 0x01f6), + }, + { .freq = 5240, + RADIOREGS3(0xa0, 0x01, 0x01, 0x02, 0x0c, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, + 0xee, 0xc8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0xc8, 0x00, 0x05, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00), + PHYREGS(0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5), + }, + { .freq = 5250, + RADIOREGS3(0xa0, 0x01, 0x01, 0x02, 0x0d, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, + 0xed, 0xc7, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0xc7, 0x00, 0x05, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00), + PHYREGS(0x0838, 0x0834, 0x0830, 0x01f2, 0x01f3, 0x01f4), + }, + { .freq = 5260, + RADIOREGS3(0x98, 0x01, 0x01, 0x02, 0x0e, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8e, 0x0e, 0x00, + 0xed, 0xc7, 0x00, 0x04, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0xc7, 0x00, 0x04, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00), + PHYREGS(0x083c, 0x0838, 0x0834, 0x01f1, 0x01f2, 0x01f3), + }, + { .freq = 5270, + RADIOREGS3(0x98, 0x01, 0x01, 0x02, 0x0f, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8e, 0x0e, 0x00, + 0xed, 0xc7, 0x00, 0x04, 0x00, 0x77, 0x00, 0x0c, + 0x00, 0x6f, 0x00, 0xc7, 0x00, 0x04, 0x00, 0x77, + 0x00, 0x0c, 0x00, 0x6f, 0x00), + PHYREGS(0x0840, 0x083c, 0x0838, 0x01f0, 0x01f1, 0x01f2), + }, + { .freq = 5280, + RADIOREGS3(0x91, 0x01, 0x01, 0x02, 0x10, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, + 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c, + 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0c, 0x00, 0x6f, 0x00), + PHYREGS(0x0844, 0x0840, 0x083c, 0x01f0, 0x01f0, 0x01f1), + }, + { .freq = 5290, + RADIOREGS3(0x91, 0x01, 0x01, 0x02, 0x11, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, + 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c, + 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0c, 0x00, 0x6f, 0x00), + PHYREGS(0x0848, 0x0844, 0x0840, 0x01ef, 0x01f0, 0x01f0), + }, + { .freq = 5300, + RADIOREGS3(0x8a, 0x01, 0x01, 0x02, 0x12, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, + 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c, + 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0c, 0x00, 0x6f, 0x00), + PHYREGS(0x084c, 0x0848, 0x0844, 0x01ee, 0x01ef, 0x01f0), + }, + { .freq = 5310, + RADIOREGS3(0x8a, 0x01, 0x01, 0x02, 0x13, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, + 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c, + 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0c, 0x00, 0x6f, 0x00), + PHYREGS(0x0850, 0x084c, 0x0848, 0x01ed, 0x01ee, 0x01ef), + }, + { .freq = 5320, + RADIOREGS3(0x83, 0x01, 0x01, 0x02, 0x14, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, + 0xdb, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c, + 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0c, 0x00, 0x6f, 0x00), + PHYREGS(0x0854, 0x0850, 0x084c, 0x01ec, 0x01ed, 0x01ee), + }, + { .freq = 5330, + RADIOREGS3(0x83, 0x01, 0x01, 0x02, 0x15, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, + 0xcb, 0xa6, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0b, + 0x00, 0x6f, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0b, 0x00, 0x6f, 0x00), + PHYREGS(0x0858, 0x0854, 0x0850, 0x01eb, 0x01ec, 0x01ed), + }, + { .freq = 5340, + RADIOREGS3(0x7c, 0x01, 0x01, 0x02, 0x16, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, + 0xca, 0xa6, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0b, + 0x00, 0x6f, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0b, 0x00, 0x6f, 0x00), + PHYREGS(0x085c, 0x0858, 0x0854, 0x01ea, 0x01eb, 0x01ec), + }, + { .freq = 5350, + RADIOREGS3(0x7c, 0x01, 0x01, 0x02, 0x17, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, + 0xca, 0xa6, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0b, + 0x00, 0x6f, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0b, 0x00, 0x6f, 0x00), + PHYREGS(0x0860, 0x085c, 0x0858, 0x01e9, 0x01ea, 0x01eb), + }, + { .freq = 5360, + RADIOREGS3(0x75, 0x01, 0x01, 0x02, 0x18, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, + 0xc9, 0x95, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x95, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0a, 0x00, 0x6f, 0x00), + PHYREGS(0x0864, 0x0860, 0x085c, 0x01e8, 0x01e9, 0x01ea), + }, + { .freq = 5370, + RADIOREGS3(0x75, 0x01, 0x01, 0x02, 0x19, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, + 0xc9, 0x95, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x95, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0a, 0x00, 0x6f, 0x00), + PHYREGS(0x0868, 0x0864, 0x0860, 0x01e7, 0x01e8, 0x01e9), + }, + { .freq = 5380, + RADIOREGS3(0x6e, 0x01, 0x01, 0x02, 0x1a, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, + 0xb8, 0x95, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x95, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0a, 0x00, 0x6f, 0x00), + PHYREGS(0x086c, 0x0868, 0x0864, 0x01e6, 0x01e7, 0x01e8), + }, + { .freq = 5390, + RADIOREGS3(0x6e, 0x01, 0x01, 0x02, 0x1b, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, + 0xb8, 0x84, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x84, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0a, 0x00, 0x6f, 0x00), + PHYREGS(0x0870, 0x086c, 0x0868, 0x01e5, 0x01e6, 0x01e7), + }, + { .freq = 5400, + RADIOREGS3(0x67, 0x01, 0x01, 0x02, 0x1c, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, + 0xb8, 0x84, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x84, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0a, 0x00, 0x6f, 0x00), + PHYREGS(0x0874, 0x0870, 0x086c, 0x01e5, 0x01e5, 0x01e6), + }, + { .freq = 5410, + RADIOREGS3(0x67, 0x01, 0x01, 0x02, 0x1d, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, + 0xb7, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, + 0x00, 0x0a, 0x00, 0x6f, 0x00), + PHYREGS(0x0878, 0x0874, 0x0870, 0x01e4, 0x01e5, 0x01e5), + }, + { .freq = 5420, + RADIOREGS3(0x61, 0x01, 0x01, 0x02, 0x1e, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, + 0xa7, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, + 0x00, 0x0a, 0x00, 0x6f, 0x00), + PHYREGS(0x087c, 0x0878, 0x0874, 0x01e3, 0x01e4, 0x01e5), + }, + { .freq = 5430, + RADIOREGS3(0x61, 0x01, 0x01, 0x02, 0x1f, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0b, 0x00, + 0xa6, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, + 0x00, 0x0a, 0x00, 0x6f, 0x00), + PHYREGS(0x0880, 0x087c, 0x0878, 0x01e2, 0x01e3, 0x01e4), + }, + { .freq = 5440, + RADIOREGS3(0x5a, 0x01, 0x01, 0x02, 0x20, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, + 0xa6, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00), + PHYREGS(0x0884, 0x0880, 0x087c, 0x01e1, 0x01e2, 0x01e3), + }, + { .freq = 5450, + RADIOREGS3(0x5a, 0x01, 0x01, 0x02, 0x21, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, + 0x95, 0x84, 0x00, 0x01, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x84, 0x00, 0x01, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00), + PHYREGS(0x0888, 0x0884, 0x0880, 0x01e0, 0x01e1, 0x01e2), + }, + { .freq = 5460, + RADIOREGS3(0x53, 0x01, 0x01, 0x02, 0x22, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, + 0x95, 0x84, 0x00, 0x01, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x84, 0x00, 0x01, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00), + PHYREGS(0x088c, 0x0888, 0x0884, 0x01df, 0x01e0, 0x01e1), + }, + { .freq = 5470, + RADIOREGS3(0x53, 0x01, 0x01, 0x02, 0x23, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, + 0x94, 0x73, 0x00, 0x01, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x73, 0x00, 0x01, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00), + PHYREGS(0x0890, 0x088c, 0x0888, 0x01de, 0x01df, 0x01e0), + }, + { .freq = 5480, + RADIOREGS3(0x4d, 0x01, 0x01, 0x02, 0x24, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, + 0x84, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00), + PHYREGS(0x0894, 0x0890, 0x088c, 0x01dd, 0x01de, 0x01df), + }, + { .freq = 5490, + RADIOREGS3(0x4d, 0x01, 0x01, 0x02, 0x25, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, + 0x83, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00), + PHYREGS(0x0898, 0x0894, 0x0890, 0x01dd, 0x01dd, 0x01de), + }, + { .freq = 5500, + RADIOREGS3(0x47, 0x01, 0x01, 0x02, 0x26, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, + 0x82, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00), + PHYREGS(0x089c, 0x0898, 0x0894, 0x01dc, 0x01dd, 0x01dd), + }, + { .freq = 5510, + RADIOREGS3(0x47, 0x01, 0x01, 0x02, 0x27, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, + 0x82, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00), + PHYREGS(0x08a0, 0x089c, 0x0898, 0x01db, 0x01dc, 0x01dd), + }, + { .freq = 5520, + RADIOREGS3(0x40, 0x01, 0x01, 0x02, 0x28, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, + 0x72, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00), + PHYREGS(0x08a4, 0x08a0, 0x089c, 0x01da, 0x01db, 0x01dc), + }, + { .freq = 5530, + RADIOREGS3(0x40, 0x01, 0x01, 0x02, 0x29, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x09, 0x00, + 0x72, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00), + PHYREGS(0x08a8, 0x08a4, 0x08a0, 0x01d9, 0x01da, 0x01db), + }, + { .freq = 5540, + RADIOREGS3(0x3a, 0x01, 0x01, 0x02, 0x2a, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x09, 0x00, + 0x71, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00), + PHYREGS(0x08ac, 0x08a8, 0x08a4, 0x01d8, 0x01d9, 0x01da), + }, + { .freq = 5550, + RADIOREGS3(0x3a, 0x01, 0x01, 0x02, 0x2b, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, + 0x61, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00), + PHYREGS(0x08b0, 0x08ac, 0x08a8, 0x01d7, 0x01d8, 0x01d9), + }, + { .freq = 5560, + RADIOREGS3(0x34, 0x01, 0x01, 0x02, 0x2c, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, + 0x61, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00), + PHYREGS(0x08b4, 0x08b0, 0x08ac, 0x01d7, 0x01d7, 0x01d8), + }, + { .freq = 5570, + RADIOREGS3(0x34, 0x01, 0x01, 0x02, 0x2d, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, + 0x61, 0x62, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x62, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00), + PHYREGS(0x08b8, 0x08b4, 0x08b0, 0x01d6, 0x01d7, 0x01d7), + }, + { .freq = 5580, + RADIOREGS3(0x2e, 0x01, 0x01, 0x02, 0x2e, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x89, 0x08, 0x00, + 0x60, 0x62, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08, + 0x00, 0x6f, 0x00, 0x62, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x08, 0x00, 0x6f, 0x00), + PHYREGS(0x08bc, 0x08b8, 0x08b4, 0x01d5, 0x01d6, 0x01d7), + }, + { .freq = 5590, + RADIOREGS3(0x2e, 0x01, 0x01, 0x02, 0x2f, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x04, 0x04, 0x04, 0x89, 0x08, 0x00, + 0x50, 0x61, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08, + 0x00, 0x6f, 0x00, 0x61, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x08, 0x00, 0x6f, 0x00), + PHYREGS(0x08c0, 0x08bc, 0x08b8, 0x01d4, 0x01d5, 0x01d6), + }, + { .freq = 5600, + RADIOREGS3(0x28, 0x01, 0x01, 0x02, 0x30, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, + 0x50, 0x51, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08, + 0x00, 0x6f, 0x00, 0x51, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x08, 0x00, 0x6f, 0x00), + PHYREGS(0x08c4, 0x08c0, 0x08bc, 0x01d3, 0x01d4, 0x01d5), + }, + { .freq = 5610, + RADIOREGS3(0x28, 0x01, 0x01, 0x02, 0x31, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, + 0x50, 0x51, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08, + 0x00, 0x6f, 0x00, 0x51, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x08, 0x00, 0x6f, 0x00), + PHYREGS(0x08c8, 0x08c4, 0x08c0, 0x01d2, 0x01d3, 0x01d4), + }, + { .freq = 5620, + RADIOREGS3(0x21, 0x01, 0x01, 0x02, 0x32, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, + 0x50, 0x50, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07, + 0x00, 0x6f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x07, 0x00, 0x6f, 0x00), + PHYREGS(0x08cc, 0x08c8, 0x08c4, 0x01d2, 0x01d2, 0x01d3), + }, + { .freq = 5630, + RADIOREGS3(0x21, 0x01, 0x01, 0x02, 0x33, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, + 0x50, 0x50, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07, + 0x00, 0x6f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x07, 0x00, 0x6f, 0x00), + PHYREGS(0x08d0, 0x08cc, 0x08c8, 0x01d1, 0x01d2, 0x01d2), + }, + { .freq = 5640, + RADIOREGS3(0x1c, 0x01, 0x01, 0x02, 0x34, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, + 0x40, 0x50, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07, + 0x00, 0x6f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x07, 0x00, 0x6f, 0x00), + PHYREGS(0x08d4, 0x08d0, 0x08cc, 0x01d0, 0x01d1, 0x01d2), + }, + { .freq = 5650, + RADIOREGS3(0x1c, 0x01, 0x01, 0x02, 0x35, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, + 0x40, 0x40, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07, + 0x00, 0x6f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x07, 0x00, 0x6f, 0x00), + PHYREGS(0x08d8, 0x08d4, 0x08d0, 0x01cf, 0x01d0, 0x01d1), + }, + { .freq = 5660, + RADIOREGS3(0x16, 0x01, 0x01, 0x02, 0x36, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, + 0x40, 0x40, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6f, 0x00), + PHYREGS(0x08dc, 0x08d8, 0x08d4, 0x01ce, 0x01cf, 0x01d0), + }, + { .freq = 5670, + RADIOREGS3(0x16, 0x01, 0x01, 0x02, 0x37, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, + 0x40, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6f, 0x00), + PHYREGS(0x08e0, 0x08dc, 0x08d8, 0x01ce, 0x01ce, 0x01cf), + }, + { .freq = 5680, + RADIOREGS3(0x10, 0x01, 0x01, 0x02, 0x38, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, + 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6f, 0x00), + PHYREGS(0x08e4, 0x08e0, 0x08dc, 0x01cd, 0x01ce, 0x01ce), + }, + { .freq = 5690, + RADIOREGS3(0x10, 0x01, 0x01, 0x02, 0x39, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, + 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6f, 0x00), + PHYREGS(0x08e8, 0x08e4, 0x08e0, 0x01cc, 0x01cd, 0x01ce), + }, + { .freq = 5700, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3a, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, + 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6e, 0x00), + PHYREGS(0x08ec, 0x08e8, 0x08e4, 0x01cb, 0x01cc, 0x01cd), + }, + { .freq = 5710, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3b, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, + 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6e, 0x00), + PHYREGS(0x08f0, 0x08ec, 0x08e8, 0x01ca, 0x01cb, 0x01cc), + }, + { .freq = 5720, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3c, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, + 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6e, 0x00), + PHYREGS(0x08f4, 0x08f0, 0x08ec, 0x01c9, 0x01ca, 0x01cb), + }, + { .freq = 5725, + RADIOREGS3(0x03, 0x01, 0x02, 0x04, 0x79, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, + 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6e, 0x00), + PHYREGS(0x08f6, 0x08f2, 0x08ee, 0x01c9, 0x01ca, 0x01cb), + }, + { .freq = 5730, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3d, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, + 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6e, 0x00), + PHYREGS(0x08f8, 0x08f4, 0x08f0, 0x01c9, 0x01c9, 0x01ca), + }, + { .freq = 5735, + RADIOREGS3(0x03, 0x01, 0x02, 0x04, 0x7b, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, + 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6d, 0x00), + PHYREGS(0x08fa, 0x08f6, 0x08f2, 0x01c8, 0x01c9, 0x01ca), + }, + { .freq = 5740, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3e, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, + 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6d, 0x00), + PHYREGS(0x08fc, 0x08f8, 0x08f4, 0x01c8, 0x01c9, 0x01c9), + }, + { .freq = 5745, + RADIOREGS3(0xfe, 0x00, 0x02, 0x04, 0x7d, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, + 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6d, 0x00), + PHYREGS(0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9), + }, + { .freq = 5750, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3f, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, + 0x20, 0x20, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6d, 0x00, 0x20, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6d, 0x00), + PHYREGS(0x0900, 0x08fc, 0x08f8, 0x01c7, 0x01c8, 0x01c9), + }, + { .freq = 5755, + RADIOREGS3(0xfe, 0x00, 0x02, 0x04, 0x7f, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, + 0x10, 0x20, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6c, 0x00, 0x20, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6c, 0x00), + PHYREGS(0x0902, 0x08fe, 0x08fa, 0x01c7, 0x01c8, 0x01c8), + }, + { .freq = 5760, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x40, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x86, 0x05, 0x00, + 0x10, 0x20, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6c, 0x00, 0x20, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6c, 0x00), + PHYREGS(0x0904, 0x0900, 0x08fc, 0x01c6, 0x01c7, 0x01c8), + }, + { .freq = 5765, + RADIOREGS3(0xf8, 0x00, 0x02, 0x04, 0x81, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x05, 0x05, 0x05, 0x86, 0x05, 0x00, + 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6c, 0x00), + PHYREGS(0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8), + }, + { .freq = 5770, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x41, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, + 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6b, 0x00), + PHYREGS(0x0908, 0x0904, 0x0900, 0x01c6, 0x01c6, 0x01c7), + }, + { .freq = 5775, + RADIOREGS3(0xf8, 0x00, 0x02, 0x04, 0x83, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, + 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6b, 0x00), + PHYREGS(0x090a, 0x0906, 0x0902, 0x01c5, 0x01c6, 0x01c7), + }, + { .freq = 5780, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x42, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, + 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6b, 0x00), + PHYREGS(0x090c, 0x0908, 0x0904, 0x01c5, 0x01c6, 0x01c6), + }, + { .freq = 5785, + RADIOREGS3(0xf2, 0x00, 0x02, 0x04, 0x85, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6b, 0x00), + PHYREGS(0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6), + }, + { .freq = 5790, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x43, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6b, 0x00), + PHYREGS(0x0910, 0x090c, 0x0908, 0x01c4, 0x01c5, 0x01c6), + }, + { .freq = 5795, + RADIOREGS3(0xf2, 0x00, 0x02, 0x04, 0x87, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6b, 0x00), + PHYREGS(0x0912, 0x090e, 0x090a, 0x01c4, 0x01c4, 0x01c5), + }, + { .freq = 5800, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x44, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6b, 0x00), + PHYREGS(0x0914, 0x0910, 0x090c, 0x01c3, 0x01c4, 0x01c5), + }, + { .freq = 5805, + RADIOREGS3(0xed, 0x00, 0x02, 0x04, 0x89, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6a, 0x00), + PHYREGS(0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4), + }, + { .freq = 5810, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x45, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6a, 0x00), + PHYREGS(0x0918, 0x0914, 0x0910, 0x01c2, 0x01c3, 0x01c4), + }, + { .freq = 5815, + RADIOREGS3(0xed, 0x00, 0x02, 0x04, 0x8b, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6a, 0x00), + PHYREGS(0x091a, 0x0916, 0x0912, 0x01c2, 0x01c3, 0x01c4), + }, + { .freq = 5820, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x46, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6a, 0x00), + PHYREGS(0x091c, 0x0918, 0x0914, 0x01c2, 0x01c2, 0x01c3), + }, + { .freq = 5825, + RADIOREGS3(0xed, 0x00, 0x02, 0x04, 0x8d, 0x07, 0x07, 0x04, + 0x10, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x69, 0x00), + PHYREGS(0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3), + }, + { .freq = 5830, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x47, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x69, 0x00), + PHYREGS(0x0920, 0x091c, 0x0918, 0x01c1, 0x01c2, 0x01c2), + }, + { .freq = 5840, + RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x48, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, + 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x04, 0x00, 0x69, 0x00), + PHYREGS(0x0924, 0x0920, 0x091c, 0x01c0, 0x01c1, 0x01c2), + }, + { .freq = 5850, + RADIOREGS3(0xe0, 0x00, 0x01, 0x02, 0x49, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, + 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x04, 0x00, 0x69, 0x00), + PHYREGS(0x0928, 0x0924, 0x0920, 0x01bf, 0x01c0, 0x01c1), + }, + { .freq = 5860, + RADIOREGS3(0xde, 0x00, 0x01, 0x02, 0x4a, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, + 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x04, 0x00, 0x69, 0x00), + PHYREGS(0x092c, 0x0928, 0x0924, 0x01bf, 0x01bf, 0x01c0), + }, + { .freq = 5870, + RADIOREGS3(0xdb, 0x00, 0x01, 0x02, 0x4b, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, + 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x04, 0x00, 0x68, 0x00), + PHYREGS(0x0930, 0x092c, 0x0928, 0x01be, 0x01bf, 0x01bf), + }, + { .freq = 5880, + RADIOREGS3(0xd8, 0x00, 0x01, 0x02, 0x4c, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, + 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x04, 0x00, 0x68, 0x00), + PHYREGS(0x0934, 0x0930, 0x092c, 0x01bd, 0x01be, 0x01bf), + }, + { .freq = 5890, + RADIOREGS3(0xd6, 0x00, 0x01, 0x02, 0x4d, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, + 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x04, 0x00, 0x68, 0x00), + PHYREGS(0x0938, 0x0934, 0x0930, 0x01bc, 0x01bd, 0x01be), + }, + { .freq = 5900, + RADIOREGS3(0xd3, 0x00, 0x01, 0x02, 0x4e, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, + 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x04, 0x00, 0x68, 0x00), + PHYREGS(0x093c, 0x0938, 0x0934, 0x01bc, 0x01bc, 0x01bd), + }, + { .freq = 5910, + RADIOREGS3(0xd6, 0x00, 0x01, 0x02, 0x4f, 0x05, 0x05, 0x04, + 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, + 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x04, 0x00, 0x68, 0x00), + PHYREGS(0x0940, 0x093c, 0x0938, 0x01bb, 0x01bc, 0x01bc), + }, + { .freq = 2412, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x6c, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x04, 0x04, 0x04, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x78, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0b, 0x00, 0x0a, 0x00, 0x89, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0b, 0x00, 0x0a), + PHYREGS(0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443), + }, + { .freq = 2417, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x71, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x78, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0b, 0x00, 0x0a, 0x00, 0x89, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0b, 0x00, 0x0a), + PHYREGS(0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441), + }, + { .freq = 2422, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x76, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x67, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0b, 0x00, 0x0a, 0x00, 0x89, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0b, 0x00, 0x0a), + PHYREGS(0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f), + }, + { .freq = 2427, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x7b, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x57, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x0a, 0x00, 0x78, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x0a), + PHYREGS(0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d), + }, + { .freq = 2432, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x80, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x56, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x0a, 0x00, 0x77, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x0a), + PHYREGS(0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a), + }, + { .freq = 2437, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x85, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x46, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x0a, 0x00, 0x76, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x0a), + PHYREGS(0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438), + }, + { .freq = 2442, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x8a, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x45, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x0a, 0x00, 0x66, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x0a), + PHYREGS(0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436), + }, + { .freq = 2447, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x8f, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x34, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x09, 0x00, 0x55, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x09), + PHYREGS(0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434), + }, + { .freq = 2452, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x94, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x23, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x09, 0x00, 0x45, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x09), + PHYREGS(0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431), + }, + { .freq = 2457, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x99, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x12, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x09, 0x00, 0x34, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x09), + PHYREGS(0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f), + }, + { .freq = 2462, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x9e, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x09, 0x00, 0x09, 0x00, 0x33, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x09, 0x00, 0x09), + PHYREGS(0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d), + }, + { .freq = 2467, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0xa3, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x09, 0x00, 0x09, 0x00, 0x22, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x09, 0x00, 0x09), + PHYREGS(0x03df, 0x03db, 0x03d7, 0x0422, 0x0427, 0x042b), + }, + { .freq = 2472, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0xa8, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x09, 0x00, 0x09, 0x00, 0x11, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x09, 0x00, 0x09), + PHYREGS(0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429), + }, + { .freq = 2484, + RADIOREGS3(0xff, 0x01, 0x03, 0x09, 0xb4, 0x08, 0x08, 0x04, + 0x16, 0x01, 0x07, 0x07, 0x07, 0x8f, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x09, 0x00, 0x09, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x09, 0x00, 0x09), + PHYREGS(0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424), + }, }; /* TODO: add support for rev4+ devices by searching in rev4+ tables */ -- cgit v0.10.2 From 8ce469999552b0c3325350cd9b4be417f2bbfc23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 17 Nov 2010 22:14:37 +0100 Subject: b43: rfkill: use HI enabled bit for all devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Devices which use LO enabled bit are covered by b43legacy Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c index 78016ae..86bc0a0 100644 --- a/drivers/net/wireless/b43/rfkill.c +++ b/drivers/net/wireless/b43/rfkill.c @@ -28,23 +28,8 @@ /* Returns TRUE, if the radio is enabled in hardware. */ bool b43_is_hw_radio_enabled(struct b43_wldev *dev) { - if (dev->phy.rev >= 3 || dev->phy.type == B43_PHYTYPE_LP) { - if (!(b43_read32(dev, B43_MMIO_RADIO_HWENABLED_HI) - & B43_MMIO_RADIO_HWENABLED_HI_MASK)) - return 1; - } else { - /* To prevent CPU fault on PPC, do not read a register - * unless the interface is started; however, on resume - * for hibernation, this routine is entered early. When - * that happens, unconditionally return TRUE. - */ - if (b43_status(dev) < B43_STAT_STARTED) - return 1; - if (b43_read16(dev, B43_MMIO_RADIO_HWENABLED_LO) - & B43_MMIO_RADIO_HWENABLED_LO_MASK) - return 1; - } - return 0; + return !(b43_read32(dev, B43_MMIO_RADIO_HWENABLED_HI) + & B43_MMIO_RADIO_HWENABLED_HI_MASK); } /* The poll callback for the hardware button. */ -- cgit v0.10.2 From 31e99729ae66d8b74316547c40eed15172f14ea8 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 17 Nov 2010 21:46:06 -0800 Subject: cfg80211: put core regulatory request into queue This will simplify the synchronization for pending requests. Without this we have a race between the core and when we restore regulatory settings, although this is unlikely its best to just avoid that race altogether. Signed-off-by: Luis R. Rodriguez Tested-by: Mark Mentovai Tested-by: Bruno Randolf Signed-off-by: John W. Linville diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 3be18d9..9830db6 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1530,12 +1530,7 @@ static int regulatory_hint_core(const char *alpha2) request->alpha2[1] = alpha2[1]; request->initiator = NL80211_REGDOM_SET_BY_CORE; - /* - * This ensures last_request is populated once modules - * come swinging in and calling regulatory hints and - * wiphy_apply_custom_regulatory(). - */ - reg_process_hint(request); + queue_regulatory_request(request); return 0; } -- cgit v0.10.2 From f333a7a2f49e2a9b46f8d18962bd750b18beeecd Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 17 Nov 2010 21:46:07 -0800 Subject: cfg80211: move reg_work and reg_todo above These will be used earlier in the next few patches. Signed-off-by: Luis R. Rodriguez Tested-by: Mark Mentovai Tested-by: Bruno Randolf Signed-off-by: John W. Linville diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 9830db6..3fa2474 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -96,6 +96,9 @@ struct reg_beacon { struct ieee80211_channel chan; }; +static void reg_todo(struct work_struct *work); +static DECLARE_WORK(reg_work, reg_todo); + /* We keep a static world regulatory domain in case of the absence of CRDA */ static const struct ieee80211_regdomain world_regdom = { .n_reg_rules = 5, @@ -1494,8 +1497,6 @@ static void reg_todo(struct work_struct *work) reg_process_pending_beacon_hints(); } -static DECLARE_WORK(reg_work, reg_todo); - static void queue_regulatory_request(struct regulatory_request *request) { if (isalpha(request->alpha2[0])) -- cgit v0.10.2 From b0e2880b0518ad11af20c7c93ec5cac93f9f03b0 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 17 Nov 2010 21:46:08 -0800 Subject: cfg80211: move mutex locking to reg_process_pending_hints() This will be required in the next patch and it makes the next patch easier to review. Signed-off-by: Luis R. Rodriguez Tested-by: Mark Mentovai Tested-by: Bruno Randolf Signed-off-by: John W. Linville diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 3fa2474..b522c46 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1412,16 +1412,13 @@ static void reg_process_hint(struct regulatory_request *reg_request) BUG_ON(!reg_request->alpha2); - mutex_lock(&cfg80211_mutex); - mutex_lock(®_mutex); - if (wiphy_idx_valid(reg_request->wiphy_idx)) wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx); if (reg_request->initiator == NL80211_REGDOM_SET_BY_DRIVER && !wiphy) { kfree(reg_request); - goto out; + return; } r = __regulatory_hint(wiphy, reg_request); @@ -1429,16 +1426,16 @@ static void reg_process_hint(struct regulatory_request *reg_request) if (r == -EALREADY && wiphy && wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) wiphy_update_regulatory(wiphy, initiator); -out: - mutex_unlock(®_mutex); - mutex_unlock(&cfg80211_mutex); } /* Processes regulatory hints, this is all the NL80211_REGDOM_SET_BY_* */ static void reg_process_pending_hints(void) - { +{ struct regulatory_request *reg_request; + mutex_lock(&cfg80211_mutex); + mutex_lock(®_mutex); + spin_lock(®_requests_lock); while (!list_empty(®_requests_list)) { reg_request = list_first_entry(®_requests_list, @@ -1451,6 +1448,9 @@ static void reg_process_pending_hints(void) spin_lock(®_requests_lock); } spin_unlock(®_requests_lock); + + mutex_unlock(®_mutex); + mutex_unlock(&cfg80211_mutex); } /* Processes beacon hints -- this has nothing to do with country IEs */ -- cgit v0.10.2 From b2e253cf300c5e33f49b7dd8b593bfc722177401 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 17 Nov 2010 21:46:09 -0800 Subject: cfg80211: Fix regulatory bug with multiple cards and delays When two cards are connected with the same regulatory domain if CRDA had a delayed response then cfg80211's own set regulatory domain would still be the world regulatory domain. There was a bug on cfg80211's logic such that it assumed that once you pegged a request as the last request it was already the currently set regulatory domain. This would mean we would race setting a stale regulatory domain to secondary cards which had the same regulatory domain since the alpha2 would match. We fix this by processing each regulatory request atomically, and only move on to the next one once we get it fully processed. In the case CRDA is not present we will simply world roam. This issue is only present when you have a slow system and the CRDA processing is delayed. Because of this it is not a known regression. Without this fix when a delay is present with CRDA the second card would end up with an intersected regulatory domain and not allow it to use the channels it really is designed for. When two cards with two different regulatory domains were inserted you'd end up rejecting the second card's regulatory domain request. This fails with mac80211_hswim's regtest=2 (two requests, same alpha2) and regtest=3 (two requests, different alpha2) module parameter options. This was reproduced and tested against mac80211_hwsim using this CRDA delayer: #!/bin/bash echo $COUNTRY >> /tmp/log sleep 2 /sbin/crda.orig And these regulatory tests: modprobe mac80211_hwsim regtest=2 modprobe mac80211_hwsim regtest=3 Reported-by: Mark Mentovai Signed-off-by: Luis R. Rodriguez Tested-by: Mark Mentovai Tested-by: Bruno Randolf Signed-off-by: John W. Linville diff --git a/include/net/regulatory.h b/include/net/regulatory.h index 9e103a4..356d6e3 100644 --- a/include/net/regulatory.h +++ b/include/net/regulatory.h @@ -43,6 +43,12 @@ enum environment_cap { * @intersect: indicates whether the wireless core should intersect * the requested regulatory domain with the presently set regulatory * domain. + * @processed: indicates whether or not this requests has already been + * processed. When the last request is processed it means that the + * currently regulatory domain set on cfg80211 is updated from + * CRDA and can be used by other regulatory requests. When a + * the last request is not yet processed we must yield until it + * is processed before processing any new requests. * @country_ie_checksum: checksum of the last processed and accepted * country IE * @country_ie_env: lets us know if the AP is telling us we are outdoor, @@ -54,6 +60,7 @@ struct regulatory_request { enum nl80211_reg_initiator initiator; char alpha2[2]; bool intersect; + bool processed; enum environment_cap country_ie_env; struct list_head list; }; diff --git a/net/wireless/reg.c b/net/wireless/reg.c index b522c46..bc14caa 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1320,6 +1320,21 @@ static int ignore_request(struct wiphy *wiphy, return -EINVAL; } +static void reg_set_request_processed(void) +{ + bool need_more_processing = false; + + last_request->processed = true; + + spin_lock(®_requests_lock); + if (!list_empty(®_requests_list)) + need_more_processing = true; + spin_unlock(®_requests_lock); + + if (need_more_processing) + schedule_work(®_work); +} + /** * __regulatory_hint - hint to the wireless core a regulatory domain * @wiphy: if the hint comes from country information from an AP, this @@ -1395,8 +1410,10 @@ new_request: * have applied the requested regulatory domain before we just * inform userspace we have processed the request */ - if (r == -EALREADY) + if (r == -EALREADY) { nl80211_send_reg_change_event(last_request); + reg_set_request_processed(); + } return r; } @@ -1428,7 +1445,11 @@ static void reg_process_hint(struct regulatory_request *reg_request) wiphy_update_regulatory(wiphy, initiator); } -/* Processes regulatory hints, this is all the NL80211_REGDOM_SET_BY_* */ +/* + * Processes regulatory hints, this is all the NL80211_REGDOM_SET_BY_* + * Regulatory hints come on a first come first serve basis and we + * must process each one atomically. + */ static void reg_process_pending_hints(void) { struct regulatory_request *reg_request; @@ -1436,19 +1457,30 @@ static void reg_process_pending_hints(void) mutex_lock(&cfg80211_mutex); mutex_lock(®_mutex); + /* When last_request->processed becomes true this will be rescheduled */ + if (last_request && !last_request->processed) { + REG_DBG_PRINT("Pending regulatory request, waiting " + "for it to be processed..."); + goto out; + } + spin_lock(®_requests_lock); - while (!list_empty(®_requests_list)) { - reg_request = list_first_entry(®_requests_list, - struct regulatory_request, - list); - list_del_init(®_request->list); + if (list_empty(®_requests_list)) { spin_unlock(®_requests_lock); - reg_process_hint(reg_request); - spin_lock(®_requests_lock); + goto out; } + + reg_request = list_first_entry(®_requests_list, + struct regulatory_request, + list); + list_del_init(®_request->list); + spin_unlock(®_requests_lock); + reg_process_hint(reg_request); + +out: mutex_unlock(®_mutex); mutex_unlock(&cfg80211_mutex); } @@ -2057,6 +2089,8 @@ int set_regdom(const struct ieee80211_regdomain *rd) nl80211_send_reg_change_event(last_request); + reg_set_request_processed(); + mutex_unlock(®_mutex); return r; -- cgit v0.10.2 From 18890d4b89d8507ad09289f6f57a71591c7e9e83 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Fri, 19 Nov 2010 08:11:01 +0100 Subject: mac80211: Disable hw crypto for GTKs on AP VLAN interfaces When using AP VLAN interfaces, each VLAN interface should be in its own broadcast domain. Hostapd achieves this by assigning different GTKs to different AP VLAN interfaces. However, mac80211 drivers are not aware of AP VLAN interfaces and as such mac80211 sends the GTK to the driver in the context of the base AP mode interface. This causes problems when multiple AP VLAN interfaces are used since the driver will use the same key slot for the different GTKs (there's no way for the driver to distinguish the different GTKs from different AP VLAN interfaces). Thus, only the clients associated to one AP VLAN interface (the one that was created last) can actually use broadcast traffic. Fix this by not programming any GTKs for AP VLAN interfaces into the hw but fall back to using software crypto. The GTK for the underlying AP interface is still sent to the driver. That means, broadcast traffic to stations associated to an AP VLAN interface is encrypted in software whereas broadcast traffic to stations associated to the non-VLAN AP interface is encrypted in hardware. Cc: Johannes Berg Signed-off-by: Helmut Schaa Signed-off-by: John W. Linville diff --git a/net/mac80211/key.c b/net/mac80211/key.c index ccd676b..72df1ca 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -84,10 +84,17 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) goto out_unsupported; sdata = key->sdata; - if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { + /* + * The driver doesn't know anything about VLAN interfaces. + * Hence, don't send GTKs for VLAN interfaces to the driver. + */ + if (!(key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE)) + goto out_unsupported; sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap); + } ret = drv_set_key(key->local, SET_KEY, sdata, sta, &key->conf); -- cgit v0.10.2 From b5bb2f2beb4d54597fd54075480fc4874a9c08dc Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 18 Nov 2010 12:08:10 -0800 Subject: iwlwifi: fix modular 3945 only build If only 3945 is selected, and is a module, build fails because iwl-legacy.c won't be compiled. Fix this by adding it to the build correctly. This doesn't happen for 4965 because it is a bool option, not tristate, since it's built into the AGN module. Reported-by: Randy Dunlap Tested-by: Randy Dunlap Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 01aa246..93380f9 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -7,6 +7,10 @@ iwlcore-$(CONFIG_IWL4965) += iwl-legacy.o iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o iwlcore-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o +# If 3945 is selected only, iwl-legacy.o will be added +# to iwlcore-m above, but it needs to be built in. +iwlcore-objs += $(iwlcore-m) + CFLAGS_iwl-devtrace.o := -I$(src) # AGN -- cgit v0.10.2 From e1566d1f322b41b1ac3acf33407a0cfe2a311b75 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 20 Nov 2010 03:08:46 +0100 Subject: ath9k: fix recursive locking in the tx flush path Signed-off-by: Felix Fietkau Tested-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 c63e283f..495432e 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -163,6 +163,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) bf = list_first_entry(&tid->buf_q, struct ath_buf, list); list_move_tail(&bf->list, &bf_head); + spin_unlock_bh(&txq->axq_lock); fi = get_frame_info(bf->bf_mpdu); if (fi->retries) { ath_tx_update_baw(sc, tid, fi->seqno); @@ -170,6 +171,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) } else { ath_tx_send_normal(sc, txq, tid, &bf_head); } + spin_lock_bh(&txq->axq_lock); } spin_unlock_bh(&txq->axq_lock); -- cgit v0.10.2 From 3b1d6dfaaf89694c2aa56fe9a6b0f0221b98a209 Mon Sep 17 00:00:00 2001 From: Huang Weiyi Date: Sat, 20 Nov 2010 20:06:02 +0800 Subject: libertas: remove duplicated #include Remove duplicated #include('s) in drivers/net/wireless/libertas/cfg.c Signed-off-by: Huang Weiyi Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c index 5046a00..73b2bee 100644 --- a/drivers/net/wireless/libertas/cfg.c +++ b/drivers/net/wireless/libertas/cfg.c @@ -9,8 +9,6 @@ #include #include #include -#include -#include #include #include #include -- cgit v0.10.2 From a9ab21133581580f6907abbc33fd3870e75dc935 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 20 Nov 2010 16:53:26 +0100 Subject: carl9170: fix init-self regression MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The commit: "carl9170: tx path review" introduced a regression. gcc (with -Winit-self): tx.c:1264: warning: ‘super’ is used uninitialized in this function Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c index 688eede..aee5c9d 100644 --- a/drivers/net/wireless/ath/carl9170/tx.c +++ b/drivers/net/wireless/ath/carl9170/tx.c @@ -1261,7 +1261,7 @@ static void carl9170_tx(struct ar9170 *ar) static bool carl9170_tx_ampdu_queue(struct ar9170 *ar, struct ieee80211_sta *sta, struct sk_buff *skb) { - struct _carl9170_tx_superframe *super = (void *) super; + struct _carl9170_tx_superframe *super = (void *) skb->data; struct carl9170_sta_info *sta_info; struct carl9170_sta_tid *agg; struct sk_buff *iter; -- cgit v0.10.2 From 85be3d98dbc8d9cff9411c52c619c3752737b7b4 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sat, 20 Nov 2010 18:38:51 -0800 Subject: ar9170: Use const Mark an array const. Signed-off-by: Joe Perches Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ar9170/cmd.c b/drivers/net/wireless/ath/ar9170/cmd.c index 4604de0..6452c50 100644 --- a/drivers/net/wireless/ath/ar9170/cmd.c +++ b/drivers/net/wireless/ath/ar9170/cmd.c @@ -54,7 +54,7 @@ int ar9170_write_mem(struct ar9170 *ar, const __le32 *data, size_t len) int ar9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val) { - __le32 buf[2] = { + const __le32 buf[2] = { cpu_to_le32(reg), cpu_to_le32(val), }; -- cgit v0.10.2 From 8b22523b045858042c6700f556f840853de163ea Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sat, 20 Nov 2010 18:38:52 -0800 Subject: ath5k: Use static const Using static const generally increases object text and decreases data size. It also generally decreases overall object size. text data bss dec hex filename 11266 56 2464 13786 35da drivers/net/wireless/ath/ath5k/ani.o.old 11181 56 2464 13701 3585 drivers/net/wireless/ath/ath5k/ani.o.new Signed-off-by: Joe Perches 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 db98a85..6b75b22 100644 --- a/drivers/net/wireless/ath/ath5k/ani.c +++ b/drivers/net/wireless/ath/ath5k/ani.c @@ -63,15 +63,15 @@ ath5k_ani_set_noise_immunity_level(struct ath5k_hw *ah, int level) * so i stick with the HAL version for now... */ #if 0 - const s8 hi[] = { -18, -18, -16, -14, -12 }; - const s8 lo[] = { -52, -56, -60, -64, -70 }; - const s8 sz[] = { -34, -41, -48, -55, -62 }; - const s8 fr[] = { -70, -72, -75, -78, -80 }; + static const s8 hi[] = { -18, -18, -16, -14, -12 }; + static const s8 lo[] = { -52, -56, -60, -64, -70 }; + static const s8 sz[] = { -34, -41, -48, -55, -62 }; + static const s8 fr[] = { -70, -72, -75, -78, -80 }; #else - const s8 sz[] = { -55, -62 }; - const s8 lo[] = { -64, -70 }; - const s8 hi[] = { -14, -12 }; - const s8 fr[] = { -78, -80 }; + static const s8 sz[] = { -55, -62 }; + static const s8 lo[] = { -64, -70 }; + static const s8 hi[] = { -14, -12 }; + static const s8 fr[] = { -78, -80 }; #endif if (level < 0 || level >= ARRAY_SIZE(sz)) { ATH5K_ERR(ah->ah_sc, "noise immuniy level %d out of range", @@ -102,7 +102,7 @@ ath5k_ani_set_noise_immunity_level(struct ath5k_hw *ah, int level) void ath5k_ani_set_spur_immunity_level(struct ath5k_hw *ah, int level) { - const int val[] = { 2, 4, 6, 8, 10, 12, 14, 16 }; + static const int val[] = { 2, 4, 6, 8, 10, 12, 14, 16 }; if (level < 0 || level >= ARRAY_SIZE(val) || level > ah->ah_sc->ani_state.max_spur_level) { @@ -127,7 +127,7 @@ ath5k_ani_set_spur_immunity_level(struct ath5k_hw *ah, int level) void ath5k_ani_set_firstep_level(struct ath5k_hw *ah, int level) { - const int val[] = { 0, 4, 8 }; + static const int val[] = { 0, 4, 8 }; if (level < 0 || level >= ARRAY_SIZE(val)) { ATH5K_ERR(ah->ah_sc, "firstep level %d out of range", level); @@ -151,12 +151,12 @@ ath5k_ani_set_firstep_level(struct ath5k_hw *ah, int level) void ath5k_ani_set_ofdm_weak_signal_detection(struct ath5k_hw *ah, bool on) { - const int m1l[] = { 127, 50 }; - const int m2l[] = { 127, 40 }; - const int m1[] = { 127, 0x4d }; - const int m2[] = { 127, 0x40 }; - const int m2cnt[] = { 31, 16 }; - const int m2lcnt[] = { 63, 48 }; + static const int m1l[] = { 127, 50 }; + static const int m2l[] = { 127, 40 }; + static const int m1[] = { 127, 0x4d }; + static const int m2[] = { 127, 0x40 }; + static const int m2cnt[] = { 31, 16 }; + static const int m2lcnt[] = { 63, 48 }; AR5K_REG_WRITE_BITS(ah, AR5K_PHY_WEAK_OFDM_LOW_THR, AR5K_PHY_WEAK_OFDM_LOW_THR_M1, m1l[on]); @@ -192,7 +192,7 @@ ath5k_ani_set_ofdm_weak_signal_detection(struct ath5k_hw *ah, bool on) void ath5k_ani_set_cck_weak_signal_detection(struct ath5k_hw *ah, bool on) { - const int val[] = { 8, 6 }; + static const int val[] = { 8, 6 }; AR5K_REG_WRITE_BITS(ah, AR5K_PHY_CCK_CROSSCORR, AR5K_PHY_CCK_CROSSCORR_WEAK_SIG_THR, val[on]); ah->ah_sc->ani_state.cck_weak_sig = on; -- cgit v0.10.2 From 07b2fa5a2368accf0fe6cb16e7eca6d1150554ed Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sat, 20 Nov 2010 18:38:53 -0800 Subject: ath9k: Use static const Using static const generally increases object text and decreases data size. It also generally decreases overall object size. text data bss dec hex filename 11161 56 2136 13353 3429 drivers/net/wireless/ath/ath9k/ar9003_paprd.o.new 11167 56 2136 13359 342f drivers/net/wireless/ath/ath9k/ar9003_paprd.o.old 15428 56 3056 18540 486c drivers/net/wireless/ath/ath9k/eeprom_4k.o.old 15451 56 3056 18563 4883 drivers/net/wireless/ath/ath9k/eeprom_4k.o.new 14087 56 2560 16703 413f drivers/net/wireless/ath/ath9k/eeprom_9287.o.old 14036 56 2560 16652 410c drivers/net/wireless/ath/ath9k/eeprom_9287.o.new 10041 56 2384 12481 30c1 drivers/net/wireless/ath/ath9k/ani.o.new 10088 56 2384 12528 30f0 drivers/net/wireless/ath/ath9k/ani.o.old 9316 1580 2304 13200 3390 drivers/net/wireless/ath/ath9k/htc_drv_init.o.new 9316 1580 2304 13200 3390 drivers/net/wireless/ath/ath9k/htc_drv_init.o.old 16483 56 3432 19971 4e03 drivers/net/wireless/ath/ath9k/ar9003_phy.o.new 16517 56 3432 20005 4e25 drivers/net/wireless/ath/ath9k/ar9003_phy.o.old 18221 104 2960 21285 5325 drivers/net/wireless/ath/ath9k/rc.o.old 18203 104 2960 21267 5313 drivers/net/wireless/ath/ath9k/rc.o.new 19985 56 4288 24329 5f09 drivers/net/wireless/ath/ath9k/eeprom_def.o.new 20040 56 4288 24384 5f40 drivers/net/wireless/ath/ath9k/eeprom_def.o.old 23997 56 4984 29037 716d drivers/net/wireless/ath/ath9k/ar5008_phy.o.old 23846 56 4984 28886 70d6 drivers/net/wireless/ath/ath9k/ar5008_phy.o.new 24285 56 3184 27525 6b85 drivers/net/wireless/ath/ath9k/ar9003_eeprom.o.old 24101 56 3184 27341 6acd drivers/net/wireless/ath/ath9k/ar9003_eeprom.o.new 6834 56 1032 7922 1ef2 drivers/net/wireless/ath/ath9k/ar9002_phy.o.old 6780 56 1032 7868 1ebc drivers/net/wireless/ath/ath9k/ar9002_phy.o.new 36211 64 8624 44899 af63 drivers/net/wireless/ath/ath9k/hw.o.new 36401 64 8624 45089 b021 drivers/net/wireless/ath/ath9k/hw.o.old 9281 56 1496 10833 2a51 drivers/net/wireless/ath/ath9k/ar9003_calib.o.old 9150 56 1496 10702 29ce drivers/net/wireless/ath/ath9k/ar9003_calib.o.new Use ARRAY_SIZE instead of a magic number. Signed-off-by: Joe Perches 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 63ccb39..29a045d 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -834,10 +834,10 @@ void ath9k_hw_ani_setup(struct ath_hw *ah) { int i; - const int totalSizeDesired[] = { -55, -55, -55, -55, -62 }; - const int coarseHigh[] = { -14, -14, -14, -14, -12 }; - const int coarseLow[] = { -64, -64, -64, -64, -70 }; - const int firpwr[] = { -78, -78, -78, -78, -80 }; + static const int totalSizeDesired[] = { -55, -55, -55, -55, -62 }; + static const int coarseHigh[] = { -14, -14, -14, -14, -12 }; + static const int coarseLow[] = { -64, -64, -64, -64, -70 }; + static const int firpwr[] = { -78, -78, -78, -78, -80 }; for (i = 0; i < 5; i++) { ah->totalSizeDesired[i] = totalSizeDesired[i]; diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index 7303d98..06e34d2 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -244,13 +244,15 @@ static void ar5008_hw_spur_mitigate(struct ath_hw *ah, int upper, lower, cur_vit_mask; int tmp, new; int i; - int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8, - AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 + static int pilot_mask_reg[4] = { + AR_PHY_TIMING7, AR_PHY_TIMING8, + AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 }; - int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10, - AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 + static int chan_mask_reg[4] = { + AR_PHY_TIMING9, AR_PHY_TIMING10, + AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 }; - int inc[4] = { 0, 100, 0, 0 }; + static int inc[4] = { 0, 100, 0, 0 }; int8_t mask_m[123]; int8_t mask_p[123]; @@ -1084,12 +1086,12 @@ static bool ar5008_hw_ani_control_old(struct ath_hw *ah, break; } case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{ - const int m1ThreshLow[] = { 127, 50 }; - const int m2ThreshLow[] = { 127, 40 }; - const int m1Thresh[] = { 127, 0x4d }; - const int m2Thresh[] = { 127, 0x40 }; - const int m2CountThr[] = { 31, 16 }; - const int m2CountThrLow[] = { 63, 48 }; + static const int m1ThreshLow[] = { 127, 50 }; + static const int m2ThreshLow[] = { 127, 40 }; + static const int m1Thresh[] = { 127, 0x4d }; + static const int m2Thresh[] = { 127, 0x40 }; + static const int m2CountThr[] = { 31, 16 }; + static const int m2CountThrLow[] = { 63, 48 }; u32 on = param ? 1 : 0; REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, @@ -1141,7 +1143,7 @@ static bool ar5008_hw_ani_control_old(struct ath_hw *ah, break; } case ATH9K_ANI_CCK_WEAK_SIGNAL_THR:{ - const int weakSigThrCck[] = { 8, 6 }; + static const int weakSigThrCck[] = { 8, 6 }; u32 high = param ? 1 : 0; REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT, @@ -1157,7 +1159,7 @@ static bool ar5008_hw_ani_control_old(struct ath_hw *ah, break; } case ATH9K_ANI_FIRSTEP_LEVEL:{ - const int firstep[] = { 0, 4, 8 }; + static const int firstep[] = { 0, 4, 8 }; u32 level = param; if (level >= ARRAY_SIZE(firstep)) { @@ -1178,7 +1180,7 @@ static bool ar5008_hw_ani_control_old(struct ath_hw *ah, break; } case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{ - const int cycpwrThr1[] = { 2, 4, 6, 8, 10, 12, 14, 16 }; + static const int cycpwrThr1[] = { 2, 4, 6, 8, 10, 12, 14, 16 }; u32 level = param; if (level >= ARRAY_SIZE(cycpwrThr1)) { @@ -1627,7 +1629,7 @@ static void ar5008_hw_set_radar_conf(struct ath_hw *ah) void ar5008_hw_attach_phy_ops(struct ath_hw *ah) { struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); - const u32 ar5416_cca_regs[6] = { + static const u32 ar5416_cca_regs[6] = { AR_PHY_CCA, AR_PHY_CH1_CCA, AR_PHY_CH2_CCA, diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/drivers/net/wireless/ath/ath9k/ar9002_phy.c index 3fb97fd..7ae66a8 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c @@ -175,13 +175,15 @@ static void ar9002_hw_spur_mitigate(struct ath_hw *ah, int upper, lower, cur_vit_mask; int tmp, newVal; int i; - int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8, - AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 + static const int pilot_mask_reg[4] = { + AR_PHY_TIMING7, AR_PHY_TIMING8, + AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 }; - int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10, - AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 + static const int chan_mask_reg[4] = { + AR_PHY_TIMING9, AR_PHY_TIMING10, + AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 }; - int inc[4] = { 0, 100, 0, 0 }; + static const int inc[4] = { 0, 100, 0, 0 }; struct chan_centers centers; int8_t mask_m[123]; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 32eed19..4c94c9e 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -196,7 +196,7 @@ static void ar9003_hw_iqcalibrate(struct ath_hw *ah, u8 numChains) u32 qCoffDenom, iCoffDenom; int32_t qCoff, iCoff; int iqCorrNeg, i; - const u_int32_t offset_array[3] = { + static const u_int32_t offset_array[3] = { AR_PHY_RX_IQCAL_CORR_B0, AR_PHY_RX_IQCAL_CORR_B1, AR_PHY_RX_IQCAL_CORR_B2, @@ -603,22 +603,22 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah, static void ar9003_hw_tx_iq_cal(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); - const u32 txiqcal_status[AR9300_MAX_CHAINS] = { + static const u32 txiqcal_status[AR9300_MAX_CHAINS] = { AR_PHY_TX_IQCAL_STATUS_B0, AR_PHY_TX_IQCAL_STATUS_B1, AR_PHY_TX_IQCAL_STATUS_B2, }; - const u32 tx_corr_coeff[AR9300_MAX_CHAINS] = { + static const u32 tx_corr_coeff[AR9300_MAX_CHAINS] = { AR_PHY_TX_IQCAL_CORR_COEFF_01_B0, AR_PHY_TX_IQCAL_CORR_COEFF_01_B1, AR_PHY_TX_IQCAL_CORR_COEFF_01_B2, }; - const u32 rx_corr[AR9300_MAX_CHAINS] = { + static const u32 rx_corr[AR9300_MAX_CHAINS] = { AR_PHY_RX_IQCAL_CORR_B0, AR_PHY_RX_IQCAL_CORR_B1, AR_PHY_RX_IQCAL_CORR_B2, }; - const u_int32_t chan_info_tab[] = { + static const u_int32_t chan_info_tab[] = { AR_PHY_CHAN_INFO_TAB_0, AR_PHY_CHAN_INFO_TAB_1, AR_PHY_CHAN_INFO_TAB_2, diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 9a7e151..3161a59 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -4455,14 +4455,16 @@ static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah, int i; int16_t twiceLargestAntenna; u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; - u16 ctlModesFor11a[] = { + static const u16 ctlModesFor11a[] = { CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 }; - u16 ctlModesFor11g[] = { + static const u16 ctlModesFor11g[] = { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40 }; - u16 numCtlModes, *pCtlMode, ctlMode, freq; + u16 numCtlModes; + const u16 *pCtlMode; + u16 ctlMode, freq; struct chan_centers centers; u8 *ctlIndex; u8 ctlNum; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c index 716db41..850bc98 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c @@ -32,12 +32,12 @@ static void ar9003_paprd_setup_single_table(struct ath_hw *ah) { struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; struct ar9300_modal_eep_header *hdr; - const u32 ctrl0[3] = { + static const u32 ctrl0[3] = { AR_PHY_PAPRD_CTRL0_B0, AR_PHY_PAPRD_CTRL0_B1, AR_PHY_PAPRD_CTRL0_B2 }; - const u32 ctrl1[3] = { + static const u32 ctrl1[3] = { AR_PHY_PAPRD_CTRL1_B0, AR_PHY_PAPRD_CTRL1_B1, AR_PHY_PAPRD_CTRL1_B2 diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index e8d6455..656d8ce 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -128,7 +128,7 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah, struct ath9k_channel *chan) { - u32 spur_freq[4] = { 2420, 2440, 2464, 2480 }; + static const u32 spur_freq[4] = { 2420, 2440, 2464, 2480 }; int cur_bb_spur, negative = 0, cck_spur_freq; int i; @@ -1161,7 +1161,7 @@ static void ar9003_hw_set_radar_conf(struct ath_hw *ah) void ar9003_hw_attach_phy_ops(struct ath_hw *ah) { struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); - const u32 ar9300_cca_regs[6] = { + static const u32 ar9300_cca_regs[6] = { AR_PHY_CCA_0, AR_PHY_CCA_1, AR_PHY_CCA_2, diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index c40c534..c2481b3 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -534,7 +534,9 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, u16 twiceMinEdgePower; u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; - u16 numCtlModes, *pCtlMode, ctlMode, freq; + u16 numCtlModes; + const u16 *pCtlMode; + u16 ctlMode, freq; struct chan_centers centers; struct cal_ctl_data_4k *rep; struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; @@ -550,10 +552,10 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = { 0, {0, 0, 0, 0} }; - u16 ctlModesFor11g[] = - { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, - CTL_2GHT40 - }; + static const u16 ctlModesFor11g[] = { + CTL_11B, CTL_11G, CTL_2GHT20, + CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40 + }; ath9k_hw_get_channel_centers(ah, chan, ¢ers); diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c index ebf7a89..34a5888 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -626,13 +626,13 @@ static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah, struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = {0, {0, 0, 0, 0} }; u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; - u16 ctlModesFor11g[] = {CTL_11B, - CTL_11G, - CTL_2GHT20, - CTL_11B_EXT, - CTL_11G_EXT, - CTL_2GHT40}; - u16 numCtlModes = 0, *pCtlMode = NULL, ctlMode, freq; + static const u16 ctlModesFor11g[] = { + CTL_11B, CTL_11G, CTL_2GHT20, + CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40 + }; + u16 numCtlModes = 0; + const u16 *pCtlMode = NULL; + u16 ctlMode, freq; struct chan_centers centers; int tx_chainmask; u16 twiceMinEdgePower; diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c index a819ddc..e94216e 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_def.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c @@ -1021,13 +1021,16 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, 0, {0, 0, 0, 0} }; u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; - u16 ctlModesFor11a[] = - { CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 }; - u16 ctlModesFor11g[] = - { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, - CTL_2GHT40 - }; - u16 numCtlModes, *pCtlMode, ctlMode, freq; + static const u16 ctlModesFor11a[] = { + CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 + }; + static const u16 ctlModesFor11g[] = { + CTL_11B, CTL_11G, CTL_2GHT20, + CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40 + }; + u16 numCtlModes; + const u16 *pCtlMode; + u16 ctlMode, freq; struct chan_centers centers; int tx_chainmask; u16 twiceMinEdgePower; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 3d7b97f..8f05fc9 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -306,7 +306,7 @@ static void ath9k_regwrite_single(void *hw_priv, u32 val, u32 reg_offset) struct ath_hw *ah = (struct ath_hw *) hw_priv; struct ath_common *common = ath9k_hw_common(ah); struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; - __be32 buf[2] = { + const __be32 buf[2] = { cpu_to_be32(reg_offset), cpu_to_be32(val), }; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 5a13a76..fd4fdb5 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -310,10 +310,9 @@ static bool ath9k_hw_chip_test(struct ath_hw *ah) struct ath_common *common = ath9k_hw_common(ah); u32 regAddr[2] = { AR_STA_ID0 }; u32 regHold[2]; - u32 patternData[4] = { 0x55555555, - 0xaaaaaaaa, - 0x66666666, - 0x99999999 }; + static const u32 patternData[4] = { + 0x55555555, 0xaaaaaaaa, 0x66666666, 0x99999999 + }; int i, j, loop_max; if (!AR_SREV_9300_20_OR_LATER(ah)) { @@ -436,7 +435,7 @@ static int ath9k_hw_init_macaddr(struct ath_hw *ah) u32 sum; int i; u16 eeval; - u32 EEP_MAC[] = { EEP_MAC_LSW, EEP_MAC_MID, EEP_MAC_MSW }; + static const u32 EEP_MAC[] = { EEP_MAC_LSW, EEP_MAC_MID, EEP_MAC_MSW }; sum = 0; for (i = 0; i < 3; i++) { diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 33bb33b..ee4566d 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -864,7 +864,7 @@ static bool ath_rc_update_per(struct ath_softc *sc, bool state_change = false; int count, n_bad_frames; u8 last_per; - static u32 nretry_to_per_lookup[10] = { + static const u32 nretry_to_per_lookup[10] = { 100 * 0 / 1, 100 * 1 / 4, 100 * 1 / 2, @@ -1087,13 +1087,13 @@ static int ath_rc_get_rateindex(const struct ath_rate_table *rate_table, struct ieee80211_tx_rate *rate) { int rix = 0, i = 0; - int mcs_rix_off[] = { 7, 15, 20, 21, 22, 23 }; + static const int mcs_rix_off[] = { 7, 15, 20, 21, 22, 23 }; if (!(rate->flags & IEEE80211_TX_RC_MCS)) return rate->idx; while (rate->idx > mcs_rix_off[i] && - i < sizeof(mcs_rix_off)/sizeof(int)) { + i < ARRAY_SIZE(mcs_rix_off)) { rix++; i++; } -- cgit v0.10.2 From 5653a63d85300dbed71b76ab7ada03808bdfb170 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sat, 20 Nov 2010 18:38:54 -0800 Subject: carl9170: Use static const Using static const generally increases object text and decreases data size. It also generally decreases overall object size. text data bss dec hex filename 1897 56 672 2625 a41 drivers/net/wireless/ath/carl9170/cmd.o.new 1897 56 672 2625 a41 drivers/net/wireless/ath/carl9170/cmd.o.old Signed-off-by: Joe Perches Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/carl9170/cmd.c b/drivers/net/wireless/ath/carl9170/cmd.c index c21f336..cdfc94c 100644 --- a/drivers/net/wireless/ath/carl9170/cmd.c +++ b/drivers/net/wireless/ath/carl9170/cmd.c @@ -41,7 +41,7 @@ int carl9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val) { - __le32 buf[2] = { + const __le32 buf[2] = { cpu_to_le32(reg), cpu_to_le32(val), }; -- cgit v0.10.2 From 3370a895454ad814d0fb5f50352cea4e51d7392f Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sat, 20 Nov 2010 18:38:55 -0800 Subject: atmel: Use static const Using static const generally increases object text and decreases data size. It also generally decreases overall object size. text data bss dec hex filename 42578 720 8528 51826 ca72 drivers/net/wireless/atmel.o.old 42578 720 8528 51826 ca72 drivers/net/wireless/atmel.o.new Signed-off-by: Joe Perches Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index c8f7090..46e382e 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -1161,7 +1161,7 @@ static irqreturn_t service_interrupt(int irq, void *dev_id) struct atmel_private *priv = netdev_priv(dev); u8 isr; int i = -1; - static u8 irq_order[] = { + static const u8 irq_order[] = { ISR_OUT_OF_RANGE, ISR_RxCOMPLETE, ISR_TxCOMPLETE, @@ -3771,7 +3771,9 @@ static int probe_atmel_card(struct net_device *dev) if (rc) { if (dev->dev_addr[0] == 0xFF) { - u8 default_mac[] = {0x00, 0x04, 0x25, 0x00, 0x00, 0x00}; + static const u8 default_mac[] = { + 0x00, 0x04, 0x25, 0x00, 0x00, 0x00 + }; printk(KERN_ALERT "%s: *** Invalid MAC address. UPGRADE Firmware ****\n", dev->name); memcpy(dev->dev_addr, default_mac, 6); } -- cgit v0.10.2 From 5b4bc649e18539a5d5a5482670d77f3f72de0eea Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sat, 20 Nov 2010 18:38:56 -0800 Subject: b43: Use static const Using static const generally increases object text and decreases data size. It also generally decreases overall object size. text data bss dec hex filename 5502 56 1336 6894 1aee drivers/net/wireless/b43/phy_common.o.new 5511 56 1336 6903 1af7 drivers/net/wireless/b43/phy_common.o.old Signed-off-by: Joe Perches Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index 7b2ea67..fa7f83f 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -427,9 +427,11 @@ void b43_phyop_switch_analog_generic(struct b43_wldev *dev, bool on) /* http://bcm-v4.sipsolutions.net/802.11/PHY/Cordic */ struct b43_c32 b43_cordic(int theta) { - u32 arctg[] = { 2949120, 1740967, 919879, 466945, 234379, 117304, - 58666, 29335, 14668, 7334, 3667, 1833, 917, 458, - 229, 115, 57, 29, }; + static const u32 arctg[] = { + 2949120, 1740967, 919879, 466945, 234379, 117304, + 58666, 29335, 14668, 7334, 3667, 1833, + 917, 458, 229, 115, 57, 29, + }; u8 i; s32 tmp; s8 signx = 1; -- cgit v0.10.2 From 20407ed8a5bb271dd8e8bd4678e1d3dadeb318bd Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sat, 20 Nov 2010 18:38:57 -0800 Subject: iwlwifi: Use static const Using static const generally increases object text and decreases data size. It also generally decreases overall object size. text data bss dec hex filename 48644 57 12120 60821 ed95 drivers/net/wireless/b43/phy_n.o.new 48661 57 12120 60838 eda6 drivers/net/wireless/b43/phy_n.o.old 37906 86 7904 45896 b348 drivers/net/wireless/iwlwifi/iwl-agn-lib.o.new 37937 86 7904 45927 b367 drivers/net/wireless/iwlwifi/iwl-agn-lib.o.old 37781 523 6752 45056 b000 drivers/net/wireless/iwlwifi/iwl-3945.o.new 37781 523 6752 45056 b000 drivers/net/wireless/iwlwifi/iwl-3945.o.old Changed b43_nphy_write_clip_detection to take a const u16 * Signed-off-by: Joe Perches 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 6facb8a..afbfdf0 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -655,7 +655,8 @@ static void b43_nphy_tx_iq_workaround(struct b43_wldev *dev) } /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/clip-detection */ -static void b43_nphy_write_clip_detection(struct b43_wldev *dev, u16 *clip_st) +static void b43_nphy_write_clip_detection(struct b43_wldev *dev, + const u16 *clip_st) { b43_phy_write(dev, B43_NPHY_C1_CLIP1THRES, clip_st[0]); b43_phy_write(dev, B43_NPHY_C2_CLIP1THRES, clip_st[1]); @@ -731,7 +732,7 @@ static void b43_nphy_stay_in_carrier_search(struct b43_wldev *dev, bool enable) struct b43_phy_n *nphy = phy->n; if (enable) { - u16 clip[] = { 0xFFFF, 0xFFFF }; + static const u16 clip[] = { 0xFFFF, 0xFFFF }; if (nphy->deaf_count++ == 0) { nphy->classifier_state = b43_nphy_classifier(dev, 0, 0); b43_nphy_classifier(dev, 0x7, 0); @@ -843,7 +844,7 @@ static void b43_nphy_adjust_lna_gain_table(struct b43_wldev *dev) u16 data[4]; s16 gain[2]; u16 minmax[2]; - u16 lna_gain[4] = { -2, 10, 19, 25 }; + static const u16 lna_gain[4] = { -2, 10, 19, 25 }; if (nphy->hang_avoid) b43_nphy_stay_in_carrier_search(dev, 1); @@ -2299,7 +2300,7 @@ static void b43_nphy_int_pa_set_tx_dig_filters(struct b43_wldev *dev) { int i, j; /* B43_NPHY_TXF_20CO_S0A1, B43_NPHY_TXF_40CO_S0A1, unknown */ - u16 offset[] = { 0x186, 0x195, 0x2C5 }; + static const u16 offset[] = { 0x186, 0x195, 0x2C5 }; for (i = 0; i < 3; i++) for (j = 0; j < 15; j++) diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 56f4ca7..d39f449 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -116,7 +116,7 @@ void iwl3945_disable_events(struct iwl_priv *priv) u32 base; /* SRAM address of event log header */ u32 disable_ptr; /* SRAM address of event-disable bitmap array */ u32 array_size; /* # of u32 entries in array */ - u32 evt_disable[IWL_EVT_DISABLE_SIZE] = { + static const u32 evt_disable[IWL_EVT_DISABLE_SIZE] = { 0x00000000, /* 31 - 0 Event id numbers */ 0x00000000, /* 63 - 32 */ 0x00000000, /* 95 - 64 */ diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 881475c..c4491f7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -1996,7 +1996,7 @@ static void iwlagn_set_kill_ack_msk(struct iwl_priv *priv, struct iwl_bt_uart_msg *uart_msg) { u8 kill_ack_msk; - __le32 bt_kill_ack_msg[2] = { + static const __le32 bt_kill_ack_msg[2] = { cpu_to_le32(0xFFFFFFF), cpu_to_le32(0xFFFFFC00) }; kill_ack_msk = (((BT_UART_MSG_FRAME3A2DP_MSK | @@ -2280,7 +2280,7 @@ static const char *get_csr_string(int cmd) void iwl_dump_csr(struct iwl_priv *priv) { int i; - u32 csr_tbl[] = { + static const u32 csr_tbl[] = { CSR_HW_IF_CONFIG_REG, CSR_INT_COALESCING, CSR_INT, @@ -2339,7 +2339,7 @@ int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display) int pos = 0; size_t bufsz = 0; #endif - u32 fh_tbl[] = { + static const u32 fh_tbl[] = { FH_RSCSR_CHNL0_STTS_WPTR_REG, FH_RSCSR_CHNL0_RBDCB_BASE_REG, FH_RSCSR_CHNL0_WPTR, -- cgit v0.10.2 From 482e039f2a6546ee2ecf718ae6c02e84d1a7f00b Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sat, 20 Nov 2010 18:38:58 -0800 Subject: libertas: Use static const Using static const generally increases object text and decreases data size. It also generally decreases overall object size. text data bss dec hex filename 3650 56 704 4410 113a drivers/net/wireless/libertas/rx.o.new 3695 56 704 4455 1167 drivers/net/wireless/libertas/rx.o.old 27328 964 5240 33532 82fc drivers/net/wireless/libertas/cfg.o.new 27328 964 5240 33532 82fc drivers/net/wireless/libertas/cfg.o.old Signed-off-by: Joe Perches Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c index 73b2bee..a909536 100644 --- a/drivers/net/wireless/libertas/cfg.c +++ b/drivers/net/wireless/libertas/cfg.c @@ -2059,7 +2059,7 @@ static void lbs_cfg_set_regulatory_hint(struct lbs_private *priv) }; /* Section 5.17.2 */ - static struct region_code_mapping regmap[] = { + static const struct region_code_mapping regmap[] = { {"US ", 0x10}, /* US FCC */ {"CA ", 0x20}, /* Canada */ {"EU ", 0x30}, /* ETSI */ diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c index a4d0bca..a2b1df2 100644 --- a/drivers/net/wireless/libertas/rx.c +++ b/drivers/net/wireless/libertas/rx.c @@ -55,7 +55,9 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb) struct rxpd *p_rx_pd; int hdrchop; struct ethhdr *p_ethhdr; - const u8 rfc1042_eth_hdr[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; + static const u8 rfc1042_eth_hdr[] = { + 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 + }; lbs_deb_enter(LBS_DEB_RX); -- cgit v0.10.2 From ff273b91ff04e6f232234b70c45101074a0daa27 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sat, 20 Nov 2010 18:38:59 -0800 Subject: ray_cs: Use static const Using static const generally increases object text and decreases data size. It also generally decreases overall object size. text data bss dec hex filename 42607 3581 8536 54724 d5c4 drivers/net/wireless/ray_cs.o.new 42603 3585 8536 54724 d5c4 drivers/net/wireless/ray_cs.o.old Signed-off-by: Joe Perches Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 97007d9..2b1cbba 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -2286,8 +2286,8 @@ static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len) struct ethhdr *peth; UCHAR srcaddr[ADDRLEN]; UCHAR destaddr[ADDRLEN]; - static UCHAR org_bridge[3] = { 0, 0, 0xf8 }; - static UCHAR org_1042[3] = { 0, 0, 0 }; + static const UCHAR org_bridge[3] = { 0, 0, 0xf8 }; + static const UCHAR org_1042[3] = { 0, 0, 0 }; memcpy(destaddr, ieee80211_get_DA(pmac), ADDRLEN); memcpy(srcaddr, ieee80211_get_SA(pmac), ADDRLEN); -- cgit v0.10.2 From 22288a5847df30fb8ba298914f144c3b1d6e1fbe Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sat, 20 Nov 2010 18:39:00 -0800 Subject: rndis_wlan: Use static const Using static const generally increases object text and decreases data size. It also generally decreases overall object size. text data bss dec hex filename 41757 2205 9896 53858 d262 drivers/net/wireless/rndis_wlan.o.old 41653 2205 9880 53738 d1ea drivers/net/wireless/rndis_wlan.o.new Changed functions rndis_set_oid and set_bssid to take const *'s. Signed-off-by: Joe Perches Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index ee08bca..19f3d56 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -817,7 +817,8 @@ exit_unlock: return ret; } -static int rndis_set_oid(struct usbnet *dev, __le32 oid, void *data, int len) +static int rndis_set_oid(struct usbnet *dev, __le32 oid, const void *data, + int len) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(dev); union { @@ -1033,7 +1034,7 @@ static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid) return ret; } -static int set_bssid(struct usbnet *usbdev, u8 bssid[ETH_ALEN]) +static int set_bssid(struct usbnet *usbdev, const u8 *bssid) { int ret; @@ -1049,7 +1050,9 @@ static int set_bssid(struct usbnet *usbdev, u8 bssid[ETH_ALEN]) static int clear_bssid(struct usbnet *usbdev) { - u8 broadcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + static const u8 broadcast_mac[ETH_ALEN] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }; return set_bssid(usbdev, broadcast_mac); } -- cgit v0.10.2 From f4e16e41d62ddc75704a0344567a807ebb41a929 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sat, 20 Nov 2010 18:39:01 -0800 Subject: rt2x00: Use static const Using static const generally increases object text and decreases data size. It also generally decreases overall object size. text data bss dec hex filename 40197 56 8336 48589 bdcd drivers/net/wireless/rt2x00/rt2800lib.o.new 40205 56 8336 48597 bdd5 drivers/net/wireless/rt2x00/rt2800lib.o.old Signed-off-by: Joe Perches Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index ce8df66..7563161 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -2166,7 +2166,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) SHARED_KEY_MODE_ENTRY(i), 0); for (i = 0; i < 256; i++) { - u32 wcid[2] = { 0xffffffff, 0x00ffffff }; + static const u32 wcid[2] = { 0xffffffff, 0x00ffffff }; rt2800_register_multiwrite(rt2x00dev, MAC_WCID_ENTRY(i), wcid, sizeof(wcid)); -- cgit v0.10.2 From 7253965a1cfbd22dd20f92b7a054e831777e284e Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sat, 20 Nov 2010 18:39:03 -0800 Subject: zd1211rw: Use const Mark arrays const that are unmodified after initializations. text data bss dec hex filename 19291 56 4136 23483 5bbb drivers/net/wireless/zd1211rw/zd_chip.o.old 19291 56 4136 23483 5bbb drivers/net/wireless/zd1211rw/zd_chip.o.new Signed-off-by: Joe Perches Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index 87a95bc..30f8d40 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c @@ -1448,7 +1448,7 @@ int zd_rfwritev_locked(struct zd_chip *chip, */ int zd_rfwrite_cr_locked(struct zd_chip *chip, u32 value) { - struct zd_ioreq16 ioreqs[] = { + const struct zd_ioreq16 ioreqs[] = { { CR244, (value >> 16) & 0xff }, { CR243, (value >> 8) & 0xff }, { CR242, value & 0xff }, @@ -1475,7 +1475,7 @@ int zd_rfwritev_cr_locked(struct zd_chip *chip, int zd_chip_set_multicast_hash(struct zd_chip *chip, struct zd_mc_hash *hash) { - struct zd_ioreq32 ioreqs[] = { + const struct zd_ioreq32 ioreqs[] = { { CR_GROUP_HASH_P1, hash->low }, { CR_GROUP_HASH_P2, hash->high }, }; -- cgit v0.10.2 From 02d2ebb2a0aa2cae0446289c8f927067aec06079 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 22 Nov 2010 15:39:39 +0100 Subject: ath9k_hw: fix A-MPDU key search issues on AR9003 Under load, a large number of frames can produce decryption errors, even when no key cache update is being done. Performing a key search for every single frame in an A-MPDU improves reliability. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index fd4fdb5..c686987 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1817,6 +1817,10 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) ah->misc_mode |= AR_PCU_MIC_NEW_LOC_ENA; + /* enable key search for every frame in an aggregate */ + if (AR_SREV_9300_20_OR_LATER(ah)) + ah->misc_mode |= AR_PCU_ALWAYS_PERFORM_KEYSEARCH; + pCap->low_2ghz_chan = 2312; pCap->high_2ghz_chan = 2732; diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 60826b8..f6058b4 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -1568,6 +1568,7 @@ enum { #define AR_PCU_TBTT_PROTECT 0x00200000 #define AR_PCU_CLEAR_VMF 0x01000000 #define AR_PCU_CLEAR_BA_VALID 0x04000000 +#define AR_PCU_ALWAYS_PERFORM_KEYSEARCH 0x10000000 #define AR_PCU_BT_ANT_PREVENT_RX 0x00100000 #define AR_PCU_BT_ANT_PREVENT_RX_S 20 -- cgit v0.10.2 From f8afa42b01c7a9f45b7cbaadb0481a0eeb96f18d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 22 Nov 2010 18:26:51 +0100 Subject: ath9k_htc: fix eeprom access wireless-testing commit a05b5d45049d60a06a1b12976150572304a51928 ath9k: add support for reading eeprom from platform data on PCI devices This change moved the initialization of the AH_USE_EEPROM flag from ath9k_hw to ath9k. This needs to be added to ath9k_htc as well 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 8f05fc9..f214e8e 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -639,6 +639,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, ah->hw_version.devid = devid; ah->hw_version.subsysid = 0; /* FIXME */ + ah->ah_flags |= AH_USE_EEPROM; priv->ah = ah; common = ath9k_hw_common(ah); -- cgit v0.10.2 From e476a5a41ad67d0e2b4a652820c49a3923eb936b Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 23 Nov 2010 17:10:24 +0100 Subject: wireless: b43: fix error path in SDIO Fix unbalanced call to sdio_release_host() on the error path. Signed-off-by: Guennadi Liakhovetski Acked-by: Larry Finger Cc: stable@kernel.org Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/sdio.c b/drivers/net/wireless/b43/sdio.c index 9a55338..09e2dfd 100644 --- a/drivers/net/wireless/b43/sdio.c +++ b/drivers/net/wireless/b43/sdio.c @@ -163,6 +163,7 @@ static int b43_sdio_probe(struct sdio_func *func, err_free_ssb: kfree(sdio); err_disable_func: + sdio_claim_host(func); sdio_disable_func(func); err_release_host: sdio_release_host(func); -- cgit v0.10.2 From ccb14354017272ddac002e859a2711610b6af174 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 24 Nov 2010 16:18:36 -0500 Subject: Revert "nl80211/mac80211: Report signal average" This reverts commit 86107fd170bc379869250eb7e1bd393a3a70e8ae. This patch inadvertantly changed the userland ABI. Signed-off-by: John W. Linville diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 1ce3775..037b4e4 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -1161,7 +1161,6 @@ enum nl80211_rate_info { * @__NL80211_STA_INFO_AFTER_LAST: internal * @NL80211_STA_INFO_MAX: highest possible station info attribute * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm) - * @NL80211_STA_INFO_SIGNAL_AVG: signal strength average (u8, dBm) * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute * containing info as possible, see &enum nl80211_sta_info_txrate. * @NL80211_STA_INFO_RX_PACKETS: total received packet (u32, from this station) @@ -1179,7 +1178,6 @@ enum nl80211_sta_info { NL80211_STA_INFO_PLID, NL80211_STA_INFO_PLINK_STATE, NL80211_STA_INFO_SIGNAL, - NL80211_STA_INFO_SIGNAL_AVG, NL80211_STA_INFO_TX_BITRATE, NL80211_STA_INFO_RX_PACKETS, NL80211_STA_INFO_TX_PACKETS, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 69e2364..8fd9eeb 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -424,7 +424,6 @@ struct station_parameters { * @STATION_INFO_TX_RETRIES: @tx_retries filled * @STATION_INFO_TX_FAILED: @tx_failed filled * @STATION_INFO_RX_DROP_MISC: @rx_dropped_misc filled - * @STATION_INFO_SIGNAL_AVG: @signal_avg filled */ enum station_info_flags { STATION_INFO_INACTIVE_TIME = 1<<0, @@ -440,7 +439,6 @@ enum station_info_flags { STATION_INFO_TX_RETRIES = 1<<10, STATION_INFO_TX_FAILED = 1<<11, STATION_INFO_RX_DROP_MISC = 1<<12, - STATION_INFO_SIGNAL_AVG = 1<<13, }; /** @@ -487,7 +485,6 @@ struct rate_info { * @plid: mesh peer link id * @plink_state: mesh peer link state * @signal: signal strength of last received packet in dBm - * @signal_avg: signal strength average in dBm * @txrate: current unicast bitrate to this station * @rx_packets: packets received from this station * @tx_packets: packets transmitted to this station @@ -508,7 +505,6 @@ struct station_info { u16 plid; u8 plink_state; s8 signal; - s8 signal_avg; struct rate_info txrate; u32 rx_packets; u32 tx_packets; diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 798d9b9..4d6f865 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -6,7 +6,6 @@ config MAC80211 select CRYPTO_ARC4 select CRYPTO_AES select CRC32 - select AVERAGE ---help--- This option enables the hardware independent IEEE 802.11 networking stack. diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 92c9cf6..0c54407 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -343,9 +343,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) || (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) { - sinfo->filled |= STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG; + sinfo->filled |= STATION_INFO_SIGNAL; sinfo->signal = (s8)sta->last_signal; - sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal); } sinfo->txrate.flags = 0; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 9dd60a7..d2fcd22 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1156,7 +1156,6 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) sta->rx_fragments++; sta->rx_bytes += rx->skb->len; sta->last_signal = status->signal; - ewma_add(&sta->avg_signal, -status->signal); /* * Change STA power saving mode only at the end of a frame diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index f43fca8..eff5857 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -244,8 +244,6 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, sta->local = local; sta->sdata = sdata; - ewma_init(&sta->avg_signal, 1000, 8); - if (sta_prepare_rate_control(local, sta, gfp)) { kfree(sta); return NULL; diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 84062e2..9265aca 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -13,7 +13,6 @@ #include #include #include -#include #include "key.h" /** @@ -225,7 +224,6 @@ enum plink_state { * @rx_fragments: number of received MPDUs * @rx_dropped: number of dropped MPDUs from this STA * @last_signal: signal of last received frame from this STA - * @avg_signal: moving average of signal of received frames from this STA * @last_seq_ctrl: last received seq/frag number from this STA (per RX queue) * @tx_filtered_count: number of frames the hardware filtered for this STA * @tx_retry_failed: number of frames that failed retry @@ -293,7 +291,6 @@ struct sta_info { unsigned long rx_fragments; unsigned long rx_dropped; int last_signal; - struct ewma avg_signal; __le16 last_seq_ctrl[NUM_RX_DATA_QUEUES]; /* Updated from TX status path only, no locking requirements */ diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index d06a40d..6055538 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -1872,9 +1872,6 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, if (sinfo->filled & STATION_INFO_SIGNAL) NLA_PUT_U8(msg, NL80211_STA_INFO_SIGNAL, sinfo->signal); - if (sinfo->filled & STATION_INFO_SIGNAL_AVG) - NLA_PUT_U8(msg, NL80211_STA_INFO_SIGNAL_AVG, - sinfo->signal_avg); if (sinfo->filled & STATION_INFO_TX_BITRATE) { txrate = nla_nest_start(msg, NL80211_STA_INFO_TX_BITRATE); if (!txrate) -- cgit v0.10.2 From e9c0268f02f8970149158a9b7ea1e5c1c45c819d Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 16 Nov 2010 19:56:49 -0800 Subject: net/wireless: Use pr_ and netdev_ No change in output for pr_ prefixes. netdev_ output is different, arguably improved. Signed-off-by: Joe Perches Signed-off-by: John W. Linville diff --git a/net/wireless/core.c b/net/wireless/core.c index 9c21ebf..630bcf0 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -4,6 +4,8 @@ * Copyright 2006-2010 Johannes Berg */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -216,8 +218,7 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, rdev->wiphy.debugfsdir, rdev->wiphy.debugfsdir->d_parent, newname)) - printk(KERN_ERR "cfg80211: failed to rename debugfs dir to %s!\n", - newname); + pr_err("failed to rename debugfs dir to %s!\n", newname); nl80211_notify_dev_rename(rdev); @@ -699,8 +700,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, if (sysfs_create_link(&dev->dev.kobj, &rdev->wiphy.dev.kobj, "phy80211")) { - printk(KERN_ERR "wireless: failed to add phy80211 " - "symlink to netdev!\n"); + pr_err("failed to add phy80211 symlink to netdev!\n"); } wdev->netdev = dev; wdev->sme_state = CFG80211_SME_IDLE; diff --git a/net/wireless/lib80211.c b/net/wireless/lib80211.c index 97d411f..3268fac 100644 --- a/net/wireless/lib80211.c +++ b/net/wireless/lib80211.c @@ -13,6 +13,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -224,8 +226,8 @@ int lib80211_unregister_crypto_ops(struct lib80211_crypto_ops *ops) return -EINVAL; found: - printk(KERN_DEBUG "lib80211_crypt: unregistered algorithm " - "'%s'\n", ops->name); + printk(KERN_DEBUG "lib80211_crypt: unregistered algorithm '%s'\n", + ops->name); list_del(&alg->list); spin_unlock_irqrestore(&lib80211_crypto_lock, flags); kfree(alg); @@ -270,7 +272,7 @@ static struct lib80211_crypto_ops lib80211_crypt_null = { static int __init lib80211_init(void) { - printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION "\n"); + pr_info(DRV_DESCRIPTION "\n"); return lib80211_register_crypto_ops(&lib80211_crypt_null); } diff --git a/net/wireless/lib80211_crypt_tkip.c b/net/wireless/lib80211_crypt_tkip.c index 0fe4051..7ea4f2b 100644 --- a/net/wireless/lib80211_crypt_tkip.c +++ b/net/wireless/lib80211_crypt_tkip.c @@ -10,6 +10,8 @@ * more details. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -99,8 +101,7 @@ static void *lib80211_tkip_init(int key_idx) priv->tx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(priv->tx_tfm_arc4)) { - printk(KERN_DEBUG "lib80211_crypt_tkip: could not allocate " - "crypto API arc4\n"); + printk(KERN_DEBUG pr_fmt("could not allocate crypto API arc4\n")); priv->tx_tfm_arc4 = NULL; goto fail; } @@ -108,8 +109,7 @@ static void *lib80211_tkip_init(int key_idx) priv->tx_tfm_michael = crypto_alloc_hash("michael_mic", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(priv->tx_tfm_michael)) { - printk(KERN_DEBUG "lib80211_crypt_tkip: could not allocate " - "crypto API michael_mic\n"); + printk(KERN_DEBUG pr_fmt("could not allocate crypto API michael_mic\n")); priv->tx_tfm_michael = NULL; goto fail; } @@ -117,8 +117,7 @@ static void *lib80211_tkip_init(int key_idx) priv->rx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(priv->rx_tfm_arc4)) { - printk(KERN_DEBUG "lib80211_crypt_tkip: could not allocate " - "crypto API arc4\n"); + printk(KERN_DEBUG pr_fmt("could not allocate crypto API arc4\n")); priv->rx_tfm_arc4 = NULL; goto fail; } @@ -126,8 +125,7 @@ static void *lib80211_tkip_init(int key_idx) priv->rx_tfm_michael = crypto_alloc_hash("michael_mic", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(priv->rx_tfm_michael)) { - printk(KERN_DEBUG "lib80211_crypt_tkip: could not allocate " - "crypto API michael_mic\n"); + printk(KERN_DEBUG pr_fmt("could not allocate crypto API michael_mic\n")); priv->rx_tfm_michael = NULL; goto fail; } @@ -536,7 +534,7 @@ static int michael_mic(struct crypto_hash *tfm_michael, u8 * key, u8 * hdr, struct scatterlist sg[2]; if (tfm_michael == NULL) { - printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n"); + pr_warn("%s(): tfm_michael == NULL\n", __func__); return -1; } sg_init_table(sg, 2); diff --git a/net/wireless/reg.c b/net/wireless/reg.c index bc14caa..5ed615f 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -32,6 +32,9 @@ * rely on some SHA1 checksum of the regdomain for example. * */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -48,7 +51,7 @@ #ifdef CONFIG_CFG80211_REG_DEBUG #define REG_DBG_PRINT(format, args...) \ do { \ - printk(KERN_DEBUG "cfg80211: " format , ## args); \ + printk(KERN_DEBUG pr_fmt(format), ##args); \ } while (0) #else #define REG_DBG_PRINT(args...) @@ -370,11 +373,10 @@ static int call_crda(const char *alpha2) }; if (!is_world_regdom((char *) alpha2)) - printk(KERN_INFO "cfg80211: Calling CRDA for country: %c%c\n", + pr_info("Calling CRDA for country: %c%c\n", alpha2[0], alpha2[1]); else - printk(KERN_INFO "cfg80211: Calling CRDA to update world " - "regulatory domain\n"); + pr_info("Calling CRDA to update world regulatory domain\n"); /* query internal regulatory database (if it exists) */ reg_regdb_query(alpha2); @@ -1851,8 +1853,7 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd) const struct ieee80211_freq_range *freq_range = NULL; const struct ieee80211_power_rule *power_rule = NULL; - printk(KERN_INFO " (start_freq - end_freq @ bandwidth), " - "(max_antenna_gain, max_eirp)\n"); + pr_info(" (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp)\n"); for (i = 0; i < rd->n_reg_rules; i++) { reg_rule = &rd->reg_rules[i]; @@ -1864,16 +1865,14 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd) * in certain regions */ if (power_rule->max_antenna_gain) - printk(KERN_INFO " (%d KHz - %d KHz @ %d KHz), " - "(%d mBi, %d mBm)\n", + pr_info(" (%d KHz - %d KHz @ %d KHz), (%d mBi, %d mBm)\n", freq_range->start_freq_khz, freq_range->end_freq_khz, freq_range->max_bandwidth_khz, power_rule->max_antenna_gain, power_rule->max_eirp); else - printk(KERN_INFO " (%d KHz - %d KHz @ %d KHz), " - "(N/A, %d mBm)\n", + pr_info(" (%d KHz - %d KHz @ %d KHz), (N/A, %d mBm)\n", freq_range->start_freq_khz, freq_range->end_freq_khz, freq_range->max_bandwidth_khz, @@ -1892,27 +1891,20 @@ static void print_regdomain(const struct ieee80211_regdomain *rd) rdev = cfg80211_rdev_by_wiphy_idx( last_request->wiphy_idx); if (rdev) { - printk(KERN_INFO "cfg80211: Current regulatory " - "domain updated by AP to: %c%c\n", + pr_info("Current regulatory domain updated by AP to: %c%c\n", rdev->country_ie_alpha2[0], rdev->country_ie_alpha2[1]); } else - printk(KERN_INFO "cfg80211: Current regulatory " - "domain intersected:\n"); + pr_info("Current regulatory domain intersected:\n"); } else - printk(KERN_INFO "cfg80211: Current regulatory " - "domain intersected:\n"); + pr_info("Current regulatory domain intersected:\n"); } else if (is_world_regdom(rd->alpha2)) - printk(KERN_INFO "cfg80211: World regulatory " - "domain updated:\n"); + pr_info("World regulatory domain updated:\n"); else { if (is_unknown_alpha2(rd->alpha2)) - printk(KERN_INFO "cfg80211: Regulatory domain " - "changed to driver built-in settings " - "(unknown country)\n"); + pr_info("Regulatory domain changed to driver built-in settings (unknown country)\n"); else - printk(KERN_INFO "cfg80211: Regulatory domain " - "changed to country: %c%c\n", + pr_info("Regulatory domain changed to country: %c%c\n", rd->alpha2[0], rd->alpha2[1]); } print_rd_rules(rd); @@ -1920,8 +1912,7 @@ static void print_regdomain(const struct ieee80211_regdomain *rd) static void print_regdomain_info(const struct ieee80211_regdomain *rd) { - printk(KERN_INFO "cfg80211: Regulatory domain: %c%c\n", - rd->alpha2[0], rd->alpha2[1]); + pr_info("Regulatory domain: %c%c\n", rd->alpha2[0], rd->alpha2[1]); print_rd_rules(rd); } @@ -1972,8 +1963,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) return -EINVAL; if (!is_valid_rd(rd)) { - printk(KERN_ERR "cfg80211: Invalid " - "regulatory domain detected:\n"); + pr_err("Invalid regulatory domain detected:\n"); print_regdomain_info(rd); return -EINVAL; } @@ -2147,8 +2137,7 @@ int __init regulatory_init(void) * early boot for call_usermodehelper(). For now treat these * errors as non-fatal. */ - printk(KERN_ERR "cfg80211: kobject_uevent_env() was unable " - "to call CRDA during init"); + pr_err("kobject_uevent_env() was unable to call CRDA during init\n"); #ifdef CONFIG_CFG80211_REG_DEBUG /* We want to find out exactly why when debugging */ WARN_ON(err); diff --git a/net/wireless/util.c b/net/wireless/util.c index 76120ae..fee020b 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -502,7 +502,7 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, skb_orphan(skb); if (pskb_expand_head(skb, head_need, 0, GFP_ATOMIC)) { - printk(KERN_ERR "failed to reallocate Tx buffer\n"); + pr_err("failed to reallocate Tx buffer\n"); return -ENOMEM; } skb->truesize += head_need; @@ -685,20 +685,17 @@ void cfg80211_upload_connect_keys(struct wireless_dev *wdev) continue; if (rdev->ops->add_key(wdev->wiphy, dev, i, false, NULL, &wdev->connect_keys->params[i])) { - printk(KERN_ERR "%s: failed to set key %d\n", - dev->name, i); + netdev_err(dev, "failed to set key %d\n", i); continue; } if (wdev->connect_keys->def == i) if (rdev->ops->set_default_key(wdev->wiphy, dev, i)) { - printk(KERN_ERR "%s: failed to set defkey %d\n", - dev->name, i); + netdev_err(dev, "failed to set defkey %d\n", i); continue; } if (wdev->connect_keys->defmgmt == i) if (rdev->ops->set_default_mgmt_key(wdev->wiphy, dev, i)) - printk(KERN_ERR "%s: failed to set mgtdef %d\n", - dev->name, i); + netdev_err(dev, "failed to set mgtdef %d\n", i); } kfree(wdev->connect_keys); diff --git a/net/wireless/wext-core.c b/net/wireless/wext-core.c index dc675a3..fdbc23c 100644 --- a/net/wireless/wext-core.c +++ b/net/wireless/wext-core.c @@ -467,8 +467,8 @@ void wireless_send_event(struct net_device * dev, * The best the driver could do is to log an error message. * We will do it ourselves instead... */ - printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n", - dev->name, cmd); + netdev_err(dev, "(WE) : Invalid/Unknown Wireless Event (0x%04X)\n", + cmd); return; } @@ -476,11 +476,13 @@ void wireless_send_event(struct net_device * dev, if (descr->header_type == IW_HEADER_TYPE_POINT) { /* Check if number of token fits within bounds */ if (wrqu->data.length > descr->max_tokens) { - printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)\n", dev->name, wrqu->data.length); + netdev_err(dev, "(WE) : Wireless Event too big (%d)\n", + wrqu->data.length); return; } if (wrqu->data.length < descr->min_tokens) { - printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)\n", dev->name, wrqu->data.length); + netdev_err(dev, "(WE) : Wireless Event too small (%d)\n", + wrqu->data.length); return; } /* Calculate extra_len - extra is NULL for restricted events */ -- cgit v0.10.2 From 69a3229edcf0c354e1cd93a811843fba7b6e1472 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 18 Nov 2010 13:27:57 +0100 Subject: b43: N-PHY: fix values for PHY regs in channel tables of 2055 radio MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Additional comment by Larry Finger : This change deserves a bit more explanation. You might include something like "These tables came from reverse engineering the 5.10.56.46 version of the Broadcom driver. Trace comparisons between b43 and the current Broadcom driver (5.10.120.0) show byte reversals for the PHY register writes." Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/radio_2055.c b/drivers/net/wireless/b43/radio_2055.c index 0d67715..10910dc 100644 --- a/drivers/net/wireless/b43/radio_2055.c +++ b/drivers/net/wireless/b43/radio_2055.c @@ -307,7 +307,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x07B4, 0x07B0, 0x07AC, 0x0214, 0x0215, 0x0216), }, { .channel = 186, .freq = 4930, /* MHz */ @@ -315,7 +315,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x07B8, 0x07B4, 0x07B0, 0x0213, 0x0214, 0x0215), }, { .channel = 188, .freq = 4940, /* MHz */ @@ -323,7 +323,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x07BC, 0x07B8, 0x07B4, 0x0212, 0x0213, 0x0214), }, { .channel = 190, .freq = 4950, /* MHz */ @@ -331,7 +331,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x07C0, 0x07BC, 0x07B8, 0x0211, 0x0212, 0x0213), }, { .channel = 192, .freq = 4960, /* MHz */ @@ -339,7 +339,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x07C4, 0x07C0, 0x07BC, 0x020F, 0x0211, 0x0212), }, { .channel = 194, .freq = 4970, /* MHz */ @@ -347,7 +347,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x07C8, 0x07C4, 0x07C0, 0x020E, 0x020F, 0x0211), }, { .channel = 196, .freq = 4980, /* MHz */ @@ -355,7 +355,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x07CC, 0x07C8, 0x07C4, 0x020D, 0x020E, 0x020F), }, { .channel = 198, .freq = 4990, /* MHz */ @@ -363,7 +363,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x07D0, 0x07CC, 0x07C8, 0x020C, 0x020D, 0x020E), }, { .channel = 200, .freq = 5000, /* MHz */ @@ -371,7 +371,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x07D4, 0x07D0, 0x07CC, 0x020B, 0x020C, 0x020D), }, { .channel = 202, .freq = 5010, /* MHz */ @@ -379,7 +379,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x07D8, 0x07D4, 0x07D0, 0x020A, 0x020B, 0x020C), }, { .channel = 204, .freq = 5020, /* MHz */ @@ -387,7 +387,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x07DC, 0x07D8, 0x07D4, 0x0209, 0x020A, 0x020B), }, { .channel = 206, .freq = 5030, /* MHz */ @@ -395,7 +395,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x07E0, 0x07DC, 0x07D8, 0x0208, 0x0209, 0x020A), }, { .channel = 208, .freq = 5040, /* MHz */ @@ -403,7 +403,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x07E4, 0x07E0, 0x07DC, 0x0207, 0x0208, 0x0209), }, { .channel = 210, .freq = 5050, /* MHz */ @@ -411,7 +411,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x07E8, 0x07E4, 0x07E0, 0x0206, 0x0207, 0x0208), }, { .channel = 212, .freq = 5060, /* MHz */ @@ -419,7 +419,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x07EC, 0x07E8, 0x07E4, 0x0205, 0x0206, 0x0207), }, { .channel = 214, .freq = 5070, /* MHz */ @@ -427,7 +427,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x07F0, 0x07EC, 0x07E8, 0x0204, 0x0205, 0x0206), }, { .channel = 216, .freq = 5080, /* MHz */ @@ -435,7 +435,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x07F4, 0x07F0, 0x07EC, 0x0203, 0x0204, 0x0205), }, { .channel = 218, .freq = 5090, /* MHz */ @@ -443,7 +443,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x07F8, 0x07F4, 0x07F0, 0x0202, 0x0203, 0x0204), }, { .channel = 220, .freq = 5100, /* MHz */ @@ -451,7 +451,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x07FC, 0x07F8, 0x07F4, 0x0201, 0x0202, 0x0203), }, { .channel = 222, .freq = 5110, /* MHz */ @@ -459,7 +459,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0800, 0x07FC, 0x07F8, 0x0200, 0x0201, 0x0202), }, { .channel = 224, .freq = 5120, /* MHz */ @@ -467,7 +467,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0804, 0x0800, 0x07FC, 0x01FF, 0x0200, 0x0201), }, { .channel = 226, .freq = 5130, /* MHz */ @@ -475,7 +475,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0808, 0x0804, 0x0800, 0x01FE, 0x01FF, 0x0200), }, { .channel = 228, .freq = 5140, /* MHz */ @@ -483,7 +483,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x080C, 0x0808, 0x0804, 0x01FD, 0x01FE, 0x01FF), }, { .channel = 32, .freq = 5160, /* MHz */ @@ -491,7 +491,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0814, 0x0810, 0x080C, 0x01FB, 0x01FC, 0x01FD), }, { .channel = 34, .freq = 5170, /* MHz */ @@ -499,7 +499,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0818, 0x0814, 0x0810, 0x01FA, 0x01FB, 0x01FC), }, { .channel = 36, .freq = 5180, /* MHz */ @@ -507,7 +507,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x081C, 0x0818, 0x0814, 0x01F9, 0x01FA, 0x01FB), }, { .channel = 38, .freq = 5190, /* MHz */ @@ -515,7 +515,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0820, 0x081C, 0x0818, 0x01F8, 0x01F9, 0x01FA), }, { .channel = 40, .freq = 5200, /* MHz */ @@ -523,7 +523,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0824, 0x0820, 0x081C, 0x01F7, 0x01F8, 0x01F9), }, { .channel = 42, .freq = 5210, /* MHz */ @@ -531,7 +531,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0828, 0x0824, 0x0820, 0x01F6, 0x01F7, 0x01F8), }, { .channel = 44, .freq = 5220, /* MHz */ @@ -539,7 +539,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x082C, 0x0828, 0x0824, 0x01F5, 0x01F6, 0x01F7), }, { .channel = 46, .freq = 5230, /* MHz */ @@ -547,7 +547,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0830, 0x082C, 0x0828, 0x01F4, 0x01F5, 0x01F6), }, { .channel = 48, .freq = 5240, /* MHz */ @@ -555,7 +555,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0834, 0x0830, 0x082C, 0x01F3, 0x01F4, 0x01F5), }, { .channel = 50, .freq = 5250, /* MHz */ @@ -563,7 +563,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0838, 0x0834, 0x0830, 0x01F2, 0x01F3, 0x01F4), }, { .channel = 52, .freq = 5260, /* MHz */ @@ -571,7 +571,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x083C, 0x0838, 0x0834, 0x01F1, 0x01F2, 0x01F3), }, { .channel = 54, .freq = 5270, /* MHz */ @@ -579,7 +579,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0840, 0x083C, 0x0838, 0x01F0, 0x01F1, 0x01F2), }, { .channel = 56, .freq = 5280, /* MHz */ @@ -587,7 +587,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0844, 0x0840, 0x083C, 0x01F0, 0x01F0, 0x01F1), }, { .channel = 58, .freq = 5290, /* MHz */ @@ -595,7 +595,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0848, 0x0844, 0x0840, 0x01EF, 0x01F0, 0x01F0), }, { .channel = 60, .freq = 5300, /* MHz */ @@ -603,7 +603,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x084C, 0x0848, 0x0844, 0x01EE, 0x01EF, 0x01F0), }, { .channel = 62, .freq = 5310, /* MHz */ @@ -611,7 +611,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0850, 0x084C, 0x0848, 0x01ED, 0x01EE, 0x01EF), }, { .channel = 64, .freq = 5320, /* MHz */ @@ -619,7 +619,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0854, 0x0850, 0x084C, 0x01EC, 0x01ED, 0x01EE), }, { .channel = 66, .freq = 5330, /* MHz */ @@ -627,7 +627,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0858, 0x0854, 0x0850, 0x01EB, 0x01EC, 0x01ED), }, { .channel = 68, .freq = 5340, /* MHz */ @@ -635,7 +635,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x085C, 0x0858, 0x0854, 0x01EA, 0x01EB, 0x01EC), }, { .channel = 70, .freq = 5350, /* MHz */ @@ -643,7 +643,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0860, 0x085C, 0x0858, 0x01E9, 0x01EA, 0x01EB), }, { .channel = 72, .freq = 5360, /* MHz */ @@ -651,7 +651,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0864, 0x0860, 0x085C, 0x01E8, 0x01E9, 0x01EA), }, { .channel = 74, .freq = 5370, /* MHz */ @@ -659,7 +659,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0868, 0x0864, 0x0860, 0x01E7, 0x01E8, 0x01E9), }, { .channel = 76, .freq = 5380, /* MHz */ @@ -667,7 +667,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x086C, 0x0868, 0x0864, 0x01E6, 0x01E7, 0x01E8), }, { .channel = 78, .freq = 5390, /* MHz */ @@ -675,7 +675,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0870, 0x086C, 0x0868, 0x01E5, 0x01E6, 0x01E7), }, { .channel = 80, .freq = 5400, /* MHz */ @@ -683,7 +683,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0874, 0x0870, 0x086C, 0x01E5, 0x01E5, 0x01E6), }, { .channel = 82, .freq = 5410, /* MHz */ @@ -691,7 +691,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0878, 0x0874, 0x0870, 0x01E4, 0x01E5, 0x01E5), }, { .channel = 84, .freq = 5420, /* MHz */ @@ -699,7 +699,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x087C, 0x0878, 0x0874, 0x01E3, 0x01E4, 0x01E5), }, { .channel = 86, .freq = 5430, /* MHz */ @@ -707,7 +707,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0880, 0x087C, 0x0878, 0x01E2, 0x01E3, 0x01E4), }, { .channel = 88, .freq = 5440, /* MHz */ @@ -715,7 +715,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0884, 0x0880, 0x087C, 0x01E1, 0x01E2, 0x01E3), }, { .channel = 90, .freq = 5450, /* MHz */ @@ -723,7 +723,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0888, 0x0884, 0x0880, 0x01E0, 0x01E1, 0x01E2), }, { .channel = 92, .freq = 5460, /* MHz */ @@ -731,7 +731,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x088C, 0x0888, 0x0884, 0x01DF, 0x01E0, 0x01E1), }, { .channel = 94, .freq = 5470, /* MHz */ @@ -739,7 +739,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0890, 0x088C, 0x0888, 0x01DE, 0x01DF, 0x01E0), }, { .channel = 96, .freq = 5480, /* MHz */ @@ -747,7 +747,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0894, 0x0890, 0x088C, 0x01DD, 0x01DE, 0x01DF), }, { .channel = 98, .freq = 5490, /* MHz */ @@ -755,7 +755,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0898, 0x0894, 0x0890, 0x01DD, 0x01DD, 0x01DE), }, { .channel = 100, .freq = 5500, /* MHz */ @@ -763,7 +763,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x089C, 0x0898, 0x0894, 0x01DC, 0x01DD, 0x01DD), }, { .channel = 102, .freq = 5510, /* MHz */ @@ -771,7 +771,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x08A0, 0x089C, 0x0898, 0x01DB, 0x01DC, 0x01DD), }, { .channel = 104, .freq = 5520, /* MHz */ @@ -779,7 +779,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x08A4, 0x08A0, 0x089C, 0x01DA, 0x01DB, 0x01DC), }, { .channel = 106, .freq = 5530, /* MHz */ @@ -787,7 +787,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x08A8, 0x08A4, 0x08A0, 0x01D9, 0x01DA, 0x01DB), }, { .channel = 108, .freq = 5540, /* MHz */ @@ -795,7 +795,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x08AC, 0x08A8, 0x08A4, 0x01D8, 0x01D9, 0x01DA), }, { .channel = 110, .freq = 5550, /* MHz */ @@ -803,7 +803,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x08B0, 0x08AC, 0x08A8, 0x01D7, 0x01D8, 0x01D9), }, { .channel = 112, .freq = 5560, /* MHz */ @@ -811,7 +811,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x08B4, 0x08B0, 0x08AC, 0x01D7, 0x01D7, 0x01D8), }, { .channel = 114, .freq = 5570, /* MHz */ @@ -819,7 +819,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x08B8, 0x08B4, 0x08B0, 0x01D6, 0x01D7, 0x01D7), }, { .channel = 116, .freq = 5580, /* MHz */ @@ -827,7 +827,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x08BC, 0x08B8, 0x08B4, 0x01D5, 0x01D6, 0x01D7), }, { .channel = 118, .freq = 5590, /* MHz */ @@ -835,7 +835,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x08C0, 0x08BC, 0x08B8, 0x01D4, 0x01D5, 0x01D6), }, { .channel = 120, .freq = 5600, /* MHz */ @@ -843,7 +843,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x08C4, 0x08C0, 0x08BC, 0x01D3, 0x01D4, 0x01D5), }, { .channel = 122, .freq = 5610, /* MHz */ @@ -851,7 +851,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x08C8, 0x08C4, 0x08C0, 0x01D2, 0x01D3, 0x01D4), }, { .channel = 124, .freq = 5620, /* MHz */ @@ -859,7 +859,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x08CC, 0x08C8, 0x08C4, 0x01D2, 0x01D2, 0x01D3), }, { .channel = 126, .freq = 5630, /* MHz */ @@ -867,7 +867,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x08D0, 0x08CC, 0x08C8, 0x01D1, 0x01D2, 0x01D2), }, { .channel = 128, .freq = 5640, /* MHz */ @@ -875,7 +875,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x08D4, 0x08D0, 0x08CC, 0x01D0, 0x01D1, 0x01D2), }, { .channel = 130, .freq = 5650, /* MHz */ @@ -883,7 +883,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x08D8, 0x08D4, 0x08D0, 0x01CF, 0x01D0, 0x01D1), }, { .channel = 132, .freq = 5660, /* MHz */ @@ -891,7 +891,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x08DC, 0x08D8, 0x08D4, 0x01CE, 0x01CF, 0x01D0), }, { .channel = 134, .freq = 5670, /* MHz */ @@ -899,7 +899,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x08E0, 0x08DC, 0x08D8, 0x01CE, 0x01CE, 0x01CF), }, { .channel = 136, .freq = 5680, /* MHz */ @@ -907,7 +907,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x08E4, 0x08E0, 0x08DC, 0x01CD, 0x01CE, 0x01CE), }, { .channel = 138, .freq = 5690, /* MHz */ @@ -915,7 +915,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x08E8, 0x08E4, 0x08E0, 0x01CC, 0x01CD, 0x01CE), }, { .channel = 140, .freq = 5700, /* MHz */ @@ -923,7 +923,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x08EC, 0x08E8, 0x08E4, 0x01CB, 0x01CC, 0x01CD), }, { .channel = 142, .freq = 5710, /* MHz */ @@ -931,7 +931,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x08F0, 0x08EC, 0x08E8, 0x01CA, 0x01CB, 0x01CC), }, { .channel = 144, .freq = 5720, /* MHz */ @@ -939,7 +939,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x08F4, 0x08F0, 0x08EC, 0x01C9, 0x01CA, 0x01CB), }, { .channel = 145, .freq = 5725, /* MHz */ @@ -947,7 +947,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x08F6, 0x08F2, 0x08EE, 0x01C9, 0x01CA, 0x01CB), }, { .channel = 146, .freq = 5730, /* MHz */ @@ -955,7 +955,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x08F8, 0x08F4, 0x08F0, 0x01C9, 0x01C9, 0x01CA), }, { .channel = 147, .freq = 5735, /* MHz */ @@ -963,7 +963,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x08FA, 0x08F6, 0x08F2, 0x01C8, 0x01C9, 0x01CA), }, { .channel = 148, .freq = 5740, /* MHz */ @@ -971,7 +971,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x08FC, 0x08F8, 0x08F4, 0x01C8, 0x01C9, 0x01C9), }, { .channel = 149, .freq = 5745, /* MHz */ @@ -979,7 +979,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x08FE, 0x08FA, 0x08F6, 0x01C8, 0x01C8, 0x01C9), }, { .channel = 150, .freq = 5750, /* MHz */ @@ -987,7 +987,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0900, 0x08FC, 0x08F8, 0x01C7, 0x01C8, 0x01C9), }, { .channel = 151, .freq = 5755, /* MHz */ @@ -995,7 +995,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0902, 0x08FE, 0x08FA, 0x01C7, 0x01C8, 0x01C8), }, { .channel = 152, .freq = 5760, /* MHz */ @@ -1003,7 +1003,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0904, 0x0900, 0x08FC, 0x01C6, 0x01C7, 0x01C8), }, { .channel = 153, .freq = 5765, /* MHz */ @@ -1011,7 +1011,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0906, 0x0902, 0x08FE, 0x01C6, 0x01C7, 0x01C8), }, { .channel = 154, .freq = 5770, /* MHz */ @@ -1019,7 +1019,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0908, 0x0904, 0x0900, 0x01C6, 0x01C6, 0x01C7), }, { .channel = 155, .freq = 5775, /* MHz */ @@ -1027,7 +1027,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x090A, 0x0906, 0x0902, 0x01C5, 0x01C6, 0x01C7), }, { .channel = 156, .freq = 5780, /* MHz */ @@ -1035,7 +1035,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x090C, 0x0908, 0x0904, 0x01C5, 0x01C6, 0x01C6), }, { .channel = 157, .freq = 5785, /* MHz */ @@ -1043,7 +1043,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x090E, 0x090A, 0x0906, 0x01C4, 0x01C5, 0x01C6), }, { .channel = 158, .freq = 5790, /* MHz */ @@ -1051,7 +1051,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0910, 0x090C, 0x0908, 0x01C4, 0x01C5, 0x01C6), }, { .channel = 159, .freq = 5795, /* MHz */ @@ -1059,7 +1059,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0912, 0x090E, 0x090A, 0x01C4, 0x01C4, 0x01C5), }, { .channel = 160, .freq = 5800, /* MHz */ @@ -1067,7 +1067,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0914, 0x0910, 0x090C, 0x01C3, 0x01C4, 0x01C5), }, { .channel = 161, .freq = 5805, /* MHz */ @@ -1075,7 +1075,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0916, 0x0912, 0x090E, 0x01C3, 0x01C4, 0x01C4), }, { .channel = 162, .freq = 5810, /* MHz */ @@ -1083,7 +1083,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0918, 0x0914, 0x0910, 0x01C2, 0x01C3, 0x01C4), }, { .channel = 163, .freq = 5815, /* MHz */ @@ -1091,7 +1091,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x091A, 0x0916, 0x0912, 0x01C2, 0x01C3, 0x01C4), }, { .channel = 164, .freq = 5820, /* MHz */ @@ -1099,7 +1099,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x091C, 0x0918, 0x0914, 0x01C2, 0x01C2, 0x01C3), }, { .channel = 165, .freq = 5825, /* MHz */ @@ -1107,7 +1107,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x091E, 0x091A, 0x0916, 0x01C1, 0x01C2, 0x01C3), }, { .channel = 166, .freq = 5830, /* MHz */ @@ -1115,7 +1115,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0920, 0x091C, 0x0918, 0x01C1, 0x01C2, 0x01C2), }, { .channel = 168, .freq = 5840, /* MHz */ @@ -1123,7 +1123,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0924, 0x0920, 0x091C, 0x01C0, 0x01C1, 0x01C2), }, { .channel = 170, .freq = 5850, /* MHz */ @@ -1131,7 +1131,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0928, 0x0924, 0x0920, 0x01BF, 0x01C0, 0x01C1), }, { .channel = 172, .freq = 5860, /* MHz */ @@ -1139,7 +1139,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x092C, 0x0928, 0x0924, 0x01BF, 0x01BF, 0x01C0), }, { .channel = 174, .freq = 5870, /* MHz */ @@ -1147,7 +1147,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0930, 0x092C, 0x0928, 0x01BE, 0x01BF, 0x01BF), }, { .channel = 176, .freq = 5880, /* MHz */ @@ -1155,7 +1155,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0934, 0x0930, 0x092C, 0x01BD, 0x01BE, 0x01BF), }, { .channel = 178, .freq = 5890, /* MHz */ @@ -1163,7 +1163,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0938, 0x0934, 0x0930, 0x01BC, 0x01BD, 0x01BE), }, { .channel = 180, .freq = 5900, /* MHz */ @@ -1171,7 +1171,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x093C, 0x0938, 0x0934, 0x01BC, 0x01BC, 0x01BD), }, { .channel = 182, .freq = 5910, /* MHz */ @@ -1179,7 +1179,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x0940, 0x093C, 0x0938, 0x01BB, 0x01BC, 0x01BC), }, { .channel = 1, .freq = 2412, /* MHz */ @@ -1187,7 +1187,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x03C9, 0x03C5, 0x03C1, 0x043A, 0x043F, 0x0443), }, { .channel = 2, .freq = 2417, /* MHz */ @@ -1195,7 +1195,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x03CB, 0x03C7, 0x03C3, 0x0438, 0x043D, 0x0441), }, { .channel = 3, .freq = 2422, /* MHz */ @@ -1203,7 +1203,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x03CD, 0x03C9, 0x03C5, 0x0436, 0x043A, 0x043F), }, { .channel = 4, .freq = 2427, /* MHz */ @@ -1211,7 +1211,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x03CF, 0x03CB, 0x03C7, 0x0434, 0x0438, 0x043D), }, { .channel = 5, .freq = 2432, /* MHz */ @@ -1219,7 +1219,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x03D1, 0x03CD, 0x03C9, 0x0431, 0x0436, 0x043A), }, { .channel = 6, .freq = 2437, /* MHz */ @@ -1227,7 +1227,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x03D3, 0x03CF, 0x03CB, 0x042F, 0x0434, 0x0438), }, { .channel = 7, .freq = 2442, /* MHz */ @@ -1235,7 +1235,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x03D5, 0x03D1, 0x03CD, 0x042D, 0x0431, 0x0436), }, { .channel = 8, .freq = 2447, /* MHz */ @@ -1243,7 +1243,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x03D7, 0x03D3, 0x03CF, 0x042B, 0x042F, 0x0434), }, { .channel = 9, .freq = 2452, /* MHz */ @@ -1251,7 +1251,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x03D9, 0x03D5, 0x03D1, 0x0429, 0x042D, 0x0431), }, { .channel = 10, .freq = 2457, /* MHz */ @@ -1259,7 +1259,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x03DB, 0x03D7, 0x03D3, 0x0427, 0x042B, 0x042F), }, { .channel = 11, .freq = 2462, /* MHz */ @@ -1267,7 +1267,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x03DD, 0x03D9, 0x03D5, 0x0424, 0x0429, 0x042D), }, { .channel = 12, .freq = 2467, /* MHz */ @@ -1275,7 +1275,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x03DF, 0x03DB, 0x03D7, 0x0422, 0x0427, 0x042B), }, { .channel = 13, .freq = 2472, /* MHz */ @@ -1283,7 +1283,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x03E1, 0x03DD, 0x03D9, 0x0420, 0x0424, 0x0429), }, { .channel = 14, .freq = 2484, /* MHz */ @@ -1291,7 +1291,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = 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), + PHYREGS(0x03E6, 0x03E2, 0x03DE, 0x041B, 0x041F, 0x0424), }, }; -- cgit v0.10.2 From c0f05b9879a324937f14270e4a14d661d2beca63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 18 Nov 2010 13:27:58 +0100 Subject: b43: N-PHY: minor fixes to match specs 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 afbfdf0..fce5232 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -876,7 +876,7 @@ static void b43_nphy_adjust_lna_gain_table(struct b43_wldev *dev) data[2] = lna_gain[2] + gain[i]; data[3] = lna_gain[3] + gain[i]; } - b43_ntab_write_bulk(dev, B43_NTAB16(10, 8), 4, data); + b43_ntab_write_bulk(dev, B43_NTAB16(i, 8), 4, data); minmax[i] = 23 + gain[i]; } @@ -896,6 +896,7 @@ static void b43_nphy_gain_ctrl_workarounds(struct b43_wldev *dev) struct b43_phy_n *nphy = dev->phy.n; u8 i, j; u8 code; + u16 tmp; /* TODO: for PHY >= 3 s8 *lna1_gain, *lna2_gain; @@ -1000,9 +1001,11 @@ static void b43_nphy_gain_ctrl_workarounds(struct b43_wldev *dev) for (i = 0; i < 4; i++) { b43_phy_write(dev, B43_NPHY_TABLE_ADDR, (0x0400 * i) + 0x0020); - for (j = 0; j < 21; j++) + for (j = 0; j < 21; j++) { + tmp = j * (i < 2 ? 3 : 1); b43_phy_write(dev, - B43_NPHY_TABLE_DATALO, 3 * j); + B43_NPHY_TABLE_DATALO, tmp); + } } b43_nphy_set_rf_sequence(dev, 5, -- cgit v0.10.2 From a5d3598de086cd38f71fe2fec43ac3ca97bb24bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 18 Nov 2010 13:27:59 +0100 Subject: b43: N-PHY: fix some typos, conditions, set gain_boost 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 fce5232..cbdee30 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -919,15 +919,15 @@ static void b43_nphy_gain_ctrl_workarounds(struct b43_wldev *dev) B43_NPHY_C2_CGAINI_CL2DETECT); /* Set narrowband clip threshold */ - b43_phy_set(dev, B43_NPHY_C1_NBCLIPTHRES, 0x84); - b43_phy_set(dev, B43_NPHY_C2_NBCLIPTHRES, 0x84); + b43_phy_write(dev, B43_NPHY_C1_NBCLIPTHRES, 0x84); + b43_phy_write(dev, B43_NPHY_C2_NBCLIPTHRES, 0x84); if (!dev->phy.is_40mhz) { /* Set dwell lengths */ - b43_phy_set(dev, B43_NPHY_CLIP1_NBDWELL_LEN, 0x002B); - b43_phy_set(dev, B43_NPHY_CLIP2_NBDWELL_LEN, 0x002B); - b43_phy_set(dev, B43_NPHY_W1CLIP1_DWELL_LEN, 0x0009); - b43_phy_set(dev, B43_NPHY_W1CLIP2_DWELL_LEN, 0x0009); + b43_phy_write(dev, B43_NPHY_CLIP1_NBDWELL_LEN, 0x002B); + b43_phy_write(dev, B43_NPHY_CLIP2_NBDWELL_LEN, 0x002B); + b43_phy_write(dev, B43_NPHY_W1CLIP1_DWELL_LEN, 0x0009); + b43_phy_write(dev, B43_NPHY_W1CLIP2_DWELL_LEN, 0x0009); } /* Set wideband clip 2 threshold */ @@ -949,7 +949,7 @@ static void b43_nphy_gain_ctrl_workarounds(struct b43_wldev *dev) ~B43_NPHY_C2_CCK_CGAINI_GAINBKOFF, 0x1); } - b43_phy_set(dev, B43_NPHY_CCK_SHIFTB_REF, 0x809C); + b43_phy_write(dev, B43_NPHY_CCK_SHIFTB_REF, 0x809C); if (nphy->gain_boost) { if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ && @@ -970,10 +970,10 @@ static void b43_nphy_gain_ctrl_workarounds(struct b43_wldev *dev) code << B43_NPHY_C2_INITGAIN_HPVGA2_SHIFT); b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x1D06); - b43_phy_write(dev, B43_NPHY_TABLE_DATALO, - (code << 8 | 0x7C)); - b43_phy_write(dev, B43_NPHY_TABLE_DATALO, - (code << 8 | 0x7C)); + /* specs say about 2 loops, but wl does 4 */ + for (i = 0; i < 4; i++) + b43_phy_write(dev, B43_NPHY_TABLE_DATALO, + (code << 8 | 0x7C)); b43_nphy_adjust_lna_gain_table(dev); @@ -991,10 +991,10 @@ static void b43_nphy_gain_ctrl_workarounds(struct b43_wldev *dev) b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1); b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x1D06); - b43_phy_write(dev, B43_NPHY_TABLE_DATALO, - (code << 8 | 0x74)); - b43_phy_write(dev, B43_NPHY_TABLE_DATALO, - (code << 8 | 0x74)); + /* specs say about 2 loops, but wl does 4 */ + for (i = 0; i < 4; i++) + b43_phy_write(dev, B43_NPHY_TABLE_DATALO, + (code << 8 | 0x74)); } if (dev->phy.rev == 2) { @@ -1034,7 +1034,7 @@ static void b43_nphy_workarounds(struct b43_wldev *dev) u8 events2[7] = { 0x0, 0x3, 0x5, 0x4, 0x2, 0x1, 0x8 }; u8 delays2[7] = { 0x8, 0x6, 0x2, 0x4, 0x4, 0x6, 0x1 }; - if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) b43_nphy_classifier(dev, 1, 0); else b43_nphy_classifier(dev, 1, 1); @@ -3459,7 +3459,8 @@ static void b43_nphy_op_prepare_structs(struct b43_wldev *dev) memset(nphy, 0, sizeof(*nphy)); - //TODO init struct b43_phy_n + /* wl goes path which is executed for gain_boost, assume it is true */ + nphy->gain_boost = true; } static void b43_nphy_op_free(struct b43_wldev *dev) -- cgit v0.10.2 From bec186452b4cfecff9e2c579bfd4016119d39614 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 18 Nov 2010 13:28:00 +0100 Subject: b43: N-PHY: init BPHY when needed 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 cbdee30..d52d514 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -1573,6 +1573,7 @@ static void b43_nphy_rf_control_intc_override(struct b43_wldev *dev, u8 field, } } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/BPHYInit */ static void b43_nphy_bphy_init(struct b43_wldev *dev) { unsigned int i; @@ -3240,6 +3241,9 @@ int b43_phy_initn(struct b43_wldev *dev) b43_nphy_classifier(dev, 0, 0); b43_nphy_read_clip_detection(dev, clip); + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + b43_nphy_bphy_init(dev); + tx_pwr_state = nphy->txpwrctrl; /* TODO N PHY TX power control with argument 0 (turning off power control) */ -- cgit v0.10.2 From fee613b77df721781b9794945f0f1a8f535456ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 18 Nov 2010 21:11:41 +0100 Subject: b43: N-PHY: fix BPHY init 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 d52d514..bf0d63d 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -1580,13 +1580,13 @@ static void b43_nphy_bphy_init(struct b43_wldev *dev) u16 val; val = 0x1E1F; - for (i = 0; i < 14; i++) { + for (i = 0; i < 16; i++) { b43_phy_write(dev, B43_PHY_N_BMODE(0x88 + i), val); val -= 0x202; } val = 0x3E3F; for (i = 0; i < 16; i++) { - b43_phy_write(dev, B43_PHY_N_BMODE(0x97 + i), val); + b43_phy_write(dev, B43_PHY_N_BMODE(0x98 + i), val); val -= 0x202; } b43_phy_write(dev, B43_PHY_N_BMODE(0x38), 0x668); -- cgit v0.10.2 From a529cecd29ecf1e5416316ae06ce515bf67b5d5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 18 Nov 2010 21:11:42 +0100 Subject: b43: N-PHY: rev2: save and restore PHY regs on RSSI poll 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 bf0d63d..dc4045d 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -1846,6 +1846,14 @@ static int b43_nphy_poll_rssi(struct b43_wldev *dev, u8 type, s32 *buf, save_regs_phy[5] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER); save_regs_phy[6] = b43_phy_read(dev, B43_NPHY_TXF_40CO_B1S0); save_regs_phy[7] = b43_phy_read(dev, B43_NPHY_TXF_40CO_B32S1); + } else if (dev->phy.rev == 2) { + save_regs_phy[0] = b43_phy_read(dev, B43_NPHY_AFECTL_C1); + save_regs_phy[1] = b43_phy_read(dev, B43_NPHY_AFECTL_C2); + save_regs_phy[2] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER); + save_regs_phy[3] = b43_phy_read(dev, B43_NPHY_RFCTL_CMD); + save_regs_phy[4] = b43_phy_read(dev, B43_NPHY_RFCTL_OVER); + save_regs_phy[5] = b43_phy_read(dev, B43_NPHY_RFCTL_RSSIO1); + save_regs_phy[6] = b43_phy_read(dev, B43_NPHY_RFCTL_RSSIO2); } b43_nphy_rssi_select(dev, 5, type); @@ -1889,6 +1897,14 @@ static int b43_nphy_poll_rssi(struct b43_wldev *dev, u8 type, s32 *buf, b43_phy_write(dev, B43_NPHY_AFECTL_OVER, save_regs_phy[5]); b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S0, save_regs_phy[6]); b43_phy_write(dev, B43_NPHY_TXF_40CO_B32S1, save_regs_phy[7]); + } else if (dev->phy.rev == 2) { + b43_phy_write(dev, B43_NPHY_AFECTL_C1, save_regs_phy[0]); + b43_phy_write(dev, B43_NPHY_AFECTL_C2, save_regs_phy[1]); + b43_phy_write(dev, B43_NPHY_AFECTL_OVER, save_regs_phy[2]); + b43_phy_write(dev, B43_NPHY_RFCTL_CMD, save_regs_phy[3]); + b43_phy_write(dev, B43_NPHY_RFCTL_OVER, save_regs_phy[4]); + b43_phy_write(dev, B43_NPHY_RFCTL_RSSIO1, save_regs_phy[5]); + b43_phy_write(dev, B43_NPHY_RFCTL_RSSIO2, save_regs_phy[6]); } return out; -- cgit v0.10.2 From 0b81c23d2e3a8589514fa69b2f153f006a4ad773 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 18 Nov 2010 21:11:43 +0100 Subject: b43: N-PHY: little cleanups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove some typos, warnings, initialize some values to follow wl's code path. 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 dc4045d..9769483 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -573,7 +573,6 @@ static void b43_nphy_calc_rx_iq_comp(struct b43_wldev *dev, u8 mask) ii = est.i1_pwr; qq = est.q1_pwr; } else { - B43_WARN_ON(1); continue; } @@ -2029,7 +2028,7 @@ static void b43_nphy_rev2_rssi_cal(struct b43_wldev *dev, u8 type) } b43_radio_maskset(dev, B2055_C1_PD_RSSIMISC, 0xF8, state[0]); - b43_radio_maskset(dev, B2055_C1_PD_RSSIMISC, 0xF8, state[1]); + b43_radio_maskset(dev, B2055_C2_PD_RSSIMISC, 0xF8, state[1]); switch (state[2]) { case 1: @@ -3113,7 +3112,7 @@ static void b43_nphy_set_rx_core_state(struct b43_wldev *dev, u8 mask) { struct b43_phy *phy = &dev->phy; struct b43_phy_n *nphy = phy->n; - u16 buf[16]; + /* u16 buf[16]; it's rev3+ */ nphy->phyrxchain = mask; @@ -3409,7 +3408,6 @@ static int b43_nphy_set_channel(struct b43_wldev *dev, 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; @@ -3479,8 +3477,9 @@ static void b43_nphy_op_prepare_structs(struct b43_wldev *dev) memset(nphy, 0, sizeof(*nphy)); - /* wl goes path which is executed for gain_boost, assume it is true */ - nphy->gain_boost = true; + nphy->gain_boost = true; /* this way we follow wl, assume it is true */ + nphy->txrx_chain = 2; /* sth different than 0 and 1 for now */ + nphy->phyrxchain = 3; /* to avoid b43_nphy_set_rx_core_state like wl */ } static void b43_nphy_op_free(struct b43_wldev *dev) @@ -3553,8 +3552,6 @@ static void b43_nphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value) static void b43_nphy_op_software_rfkill(struct b43_wldev *dev, bool blocked) { - struct b43_phy_n *nphy = dev->phy.n; - if (b43_read32(dev, B43_MMIO_MACCTL) & B43_MACCTL_ENABLED) b43err(dev->wl, "MAC not suspended\n"); -- cgit v0.10.2 From c8a7972c3b3633bf90daf50b135665d8ca4838c4 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 19 Nov 2010 22:55:37 +0100 Subject: mac80211: restart beacon miss timer on system resume from suspend Signed-off-by: Paul Stewart Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index dfc4a31..84e24df 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2012,6 +2012,7 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata) add_timer(&ifmgd->timer); if (test_and_clear_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running)) add_timer(&ifmgd->chswitch_timer); + ieee80211_sta_reset_beacon_monitor(sdata); } #endif -- cgit v0.10.2 From 7ccc8bd7593634d827e8bc55898a5038e29848b5 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 19 Nov 2010 22:55:38 +0100 Subject: mac80211: calculate beacon loss time accurately Instead of using a fixed 2 second timeout, calculate beacon loss interval from the advertised beacon interval and a frame count. With this beacon loss happens after N (default 7) consecutive frames are missed which for a typical setup (100TU beacon interval) is ~700ms (or ~1/3 previous). Signed-off-by: Sam Leffler Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 3598abf..ff7bc30 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -349,6 +349,7 @@ struct ieee80211_if_managed { struct work_struct chswitch_work; struct work_struct beacon_connection_loss_work; + unsigned long beacon_timeout; unsigned long probe_timeout; int probe_send_count; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 84e24df..729aba4 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -31,10 +31,15 @@ #define IEEE80211_MAX_PROBE_TRIES 5 /* - * beacon loss detection timeout - * XXX: should depend on beacon interval + * Beacon loss timeout is calculated as N frames times the + * advertised beacon interval. This may need to be somewhat + * higher than what hardware might detect to account for + * delays in the host processing frames. But since we also + * probe on beacon miss before declaring the connection lost + * default to what we want. */ -#define IEEE80211_BEACON_LOSS_TIME (2 * HZ) +#define IEEE80211_BEACON_LOSS_COUNT 7 + /* * Time the connection can be idle before we probe * it to see if we can still talk to the AP. @@ -121,7 +126,7 @@ void ieee80211_sta_reset_beacon_monitor(struct ieee80211_sub_if_data *sdata) return; mod_timer(&sdata->u.mgd.bcn_mon_timer, - round_jiffies_up(jiffies + IEEE80211_BEACON_LOSS_TIME)); + round_jiffies_up(jiffies + sdata->u.mgd.beacon_timeout)); } void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata) @@ -871,6 +876,9 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, bss_info_changed |= ieee80211_handle_bss_capability(sdata, cbss->capability, bss->has_erp_value, bss->erp_value); + sdata->u.mgd.beacon_timeout = usecs_to_jiffies(ieee80211_tu_to_usec( + IEEE80211_BEACON_LOSS_COUNT * bss_conf->beacon_int)); + sdata->u.mgd.associated = cbss; memcpy(sdata->u.mgd.bssid, cbss->bssid, ETH_ALEN); -- cgit v0.10.2 From 46090979a55a0dc2cdb3d939f94fa47742108194 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 23 Nov 2010 20:28:03 +0100 Subject: mac80211: probe the AP when resuming Check the connection by probing the AP (either using nullfunc or a probe request). If nullfunc probing is supported and the assoc is no longer valid, the AP will send a disassoc/deauth immediately. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 729aba4..849d9c6 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2021,6 +2021,7 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata) if (test_and_clear_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running)) add_timer(&ifmgd->chswitch_timer); ieee80211_sta_reset_beacon_monitor(sdata); + ieee80211_restart_sta_timer(sdata); } #endif -- cgit v0.10.2 From dd5b4cc71cd09c33e1579cc6d5720656e94e52de Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 22 Nov 2010 20:58:24 +0100 Subject: cfg80211/mac80211: improve ad-hoc multicast rate handling - store the multicast rate as an index instead of the rate value (reduces cpu overhead in a hotpath) - validate the rate values (must match a bitrate in at least one sband) Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 91f0995..dd4c43f 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -923,7 +923,7 @@ struct cfg80211_disassoc_request { * @privacy: this is a protected network, keys will be configured * after joining * @basic_rates: bitmap of basic rates to use when creating the IBSS - * @mcast_rate: multicast tx rate (in 100 kbps) + * @mcast_rate: per-band multicast rate index + 1 (0: disabled) */ struct cfg80211_ibss_params { u8 *ssid; @@ -935,7 +935,7 @@ struct cfg80211_ibss_params { u32 basic_rates; bool channel_fixed; bool privacy; - int mcast_rate; + int mcast_rate[IEEE80211_NUM_BANDS]; }; /** diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 5b0fff2..08e97e5 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -219,7 +219,7 @@ enum ieee80211_bss_change { * @basic_rates: bitmap of basic rates, each bit stands for an * index into the rate table configured by the driver in * the current band. - * @mcast_rate: multicast rate for AP and Ad-Hoc (in 100 kbps) + * @mcast_rate: per-band multicast rate index + 1 (0: disabled) * @bssid: The BSSID for this BSS * @enable_beacon: whether beaconing should be enabled or not * @channel_type: Channel type for this BSS -- the hardware might be @@ -259,7 +259,7 @@ struct ieee80211_bss_conf { u16 assoc_capability; u64 timestamp; u32 basic_rates; - u32 mcast_rate; + int mcast_rate[IEEE80211_NUM_BANDS]; u16 ht_operation_mode; s32 cqm_rssi_thold; u32 cqm_rssi_hyst; diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 6fe6837..410d104 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -915,7 +915,8 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, sdata->u.ibss.privacy = params->privacy; sdata->u.ibss.basic_rates = params->basic_rates; - sdata->vif.bss_conf.mcast_rate = params->mcast_rate; + memcpy(sdata->vif.bss_conf.mcast_rate, params->mcast_rate, + sizeof(params->mcast_rate)); sdata->vif.bss_conf.beacon_int = params->beacon_interval; diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 76de4f8..3d5a2cb 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -211,20 +211,11 @@ static bool rc_no_data_or_no_ack(struct ieee80211_tx_rate_control *txrc) return (info->flags & IEEE80211_TX_CTL_NO_ACK) || !ieee80211_is_data(fc); } -static void rc_send_low_broadcast(s8 *idx, u32 basic_rates, u32 mcast_rate, +static void rc_send_low_broadcast(s8 *idx, u32 basic_rates, struct ieee80211_supported_band *sband) { u8 i; - if (mcast_rate) { - for (i = 0; i < sband->n_bitrates; i++) { - if (sband->bitrates[i].bitrate == mcast_rate) { - *idx = i; - return; - } - } - } - if (basic_rates == 0) return; /* assume basic rates unknown and accept rate */ if (*idx < 0) @@ -247,17 +238,25 @@ bool rate_control_send_low(struct ieee80211_sta *sta, struct ieee80211_tx_rate_control *txrc) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb); + struct ieee80211_supported_band *sband = txrc->sband; + int mcast_rate; if (!sta || !priv_sta || rc_no_data_or_no_ack(txrc)) { info->control.rates[0].idx = rate_lowest_index(txrc->sband, sta); info->control.rates[0].count = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? 1 : txrc->hw->max_rate_tries; - if (!sta && txrc->bss) + if (!sta && txrc->bss) { + mcast_rate = txrc->bss_conf->mcast_rate[sband->band]; + if (mcast_rate > 0) { + info->control.rates[0].idx = mcast_rate - 1; + return true; + } + rc_send_low_broadcast(&info->control.rates[0].idx, txrc->bss_conf->basic_rates, - txrc->bss_conf->mcast_rate, - txrc->sband); + sband); + } return true; } return false; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index b15eb77..8734efa 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3600,6 +3600,34 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) local_state_change); } +static bool +nl80211_parse_mcast_rate(struct cfg80211_registered_device *rdev, + int mcast_rate[IEEE80211_NUM_BANDS], + int rateval) +{ + struct wiphy *wiphy = &rdev->wiphy; + bool found = false; + int band, i; + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + struct ieee80211_supported_band *sband; + + sband = wiphy->bands[band]; + if (!sband) + continue; + + for (i = 0; i < sband->n_bitrates; i++) { + if (sband->bitrates[i].bitrate == rateval) { + mcast_rate[band] = i + 1; + found = true; + break; + } + } + } + + return found; +} + static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; @@ -3683,9 +3711,11 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) return -EINVAL; } } - if (info->attrs[NL80211_ATTR_MCAST_RATE]) - ibss.mcast_rate = - nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE]); + + if (info->attrs[NL80211_ATTR_MCAST_RATE] && + !nl80211_parse_mcast_rate(rdev, ibss.mcast_rate, + nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE]))) + return -EINVAL; if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) { connkeys = nl80211_parse_connkeys(rdev, -- cgit v0.10.2 From 4e5ff37692df35c8826f1291204841b174d3c3ce Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 23 Nov 2010 03:10:31 +0100 Subject: mac80211: use nullfunc instead of probe request for connection monitoring nullfunc frames are better for connection monitoring, because probe requests are answered even if the AP has already dropped the connection, whereas nullfunc frames from an unassociated station will trigger a disassoc/deauth frame from the AP (WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA), which allows the station to reconnect immediately instead of waiting until it attempts to transmit the next unicast frame. This only works on hardware with reliable tx ACK reporting, any other hardware needs to fall back to the probe request method. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index ff7bc30..5bc0745 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1265,6 +1265,8 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local, int powersave); void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, struct ieee80211_hdr *hdr); +void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, + struct ieee80211_hdr *hdr); void ieee80211_beacon_connection_loss_work(struct work_struct *work); void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 849d9c6..33ffce3 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1034,6 +1034,51 @@ void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, ieee80211_sta_reset_conn_monitor(sdata); } +static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + + if (!(ifmgd->flags & (IEEE80211_STA_BEACON_POLL | + IEEE80211_STA_CONNECTION_POLL))) + return; + + ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | + IEEE80211_STA_BEACON_POLL); + mutex_lock(&sdata->local->iflist_mtx); + ieee80211_recalc_ps(sdata->local, -1); + mutex_unlock(&sdata->local->iflist_mtx); + + if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) + return; + + /* + * We've received a probe response, but are not sure whether + * we have or will be receiving any beacons or data, so let's + * schedule the timers again, just in case. + */ + ieee80211_sta_reset_beacon_monitor(sdata); + + mod_timer(&ifmgd->conn_mon_timer, + round_jiffies_up(jiffies + + IEEE80211_CONNECTION_IDLE_TIME)); +} + +void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, + struct ieee80211_hdr *hdr) +{ + if (!ieee80211_is_data(hdr->frame_control) && + !ieee80211_is_nullfunc(hdr->frame_control)) + return; + + ieee80211_sta_reset_conn_monitor(sdata); + + if (ieee80211_is_nullfunc(hdr->frame_control) && + sdata->u.mgd.probe_send_count > 0) { + sdata->u.mgd.probe_send_count = 0; + ieee80211_queue_work(&sdata->local->hw, &sdata->work); + } +} + static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; @@ -1049,8 +1094,19 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) if (ifmgd->probe_send_count >= unicast_limit) dst = NULL; - ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); - ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid[1], NULL, 0); + /* + * When the hardware reports an accurate Tx ACK status, it's + * better to send a nullfunc frame instead of a probe request, + * as it will kick us off the AP quickly if we aren't associated + * anymore. The timeout will be reset if the frame is ACKed by + * the AP. + */ + if (sdata->local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) + ieee80211_send_nullfunc(sdata->local, sdata, 0); + else { + ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); + ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid[1], NULL, 0); + } ifmgd->probe_send_count++; ifmgd->probe_timeout = jiffies + IEEE80211_PROBE_WAIT; @@ -1517,29 +1573,8 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false); if (ifmgd->associated && - memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN) == 0 && - ifmgd->flags & (IEEE80211_STA_BEACON_POLL | - IEEE80211_STA_CONNECTION_POLL)) { - ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | - IEEE80211_STA_BEACON_POLL); - mutex_lock(&sdata->local->iflist_mtx); - ieee80211_recalc_ps(sdata->local, -1); - mutex_unlock(&sdata->local->iflist_mtx); - - if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) - return; - - /* - * We've received a probe response, but are not sure whether - * we have or will be receiving any beacons or data, so let's - * schedule the timers again, just in case. - */ - ieee80211_sta_reset_beacon_monitor(sdata); - - mod_timer(&ifmgd->conn_mon_timer, - round_jiffies_up(jiffies + - IEEE80211_CONNECTION_IDLE_TIME)); - } + memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN) == 0) + ieee80211_reset_ap_probe(sdata); } /* @@ -1891,7 +1926,12 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) u8 bssid[ETH_ALEN]; memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); - if (time_is_after_jiffies(ifmgd->probe_timeout)) + + /* ACK received for nullfunc probing frame */ + if (!ifmgd->probe_send_count) + ieee80211_reset_ap_probe(sdata); + + else if (time_is_after_jiffies(ifmgd->probe_timeout)) run_again(ifmgd, ifmgd->probe_timeout); else if (ifmgd->probe_send_count < IEEE80211_MAX_PROBE_TRIES) { diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 3153c19..8695cd1 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -155,6 +155,10 @@ static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb) ieee80211_queue_work(&local->hw, &local->recalc_smps); } + + if ((sdata->vif.type == NL80211_IFTYPE_STATION) && + (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)) + ieee80211_sta_tx_notify(sdata, (void *) skb->data); } void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) -- cgit v0.10.2 From 72a8a3edd630995662bdc85957206685f376f9c4 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 23 Nov 2010 03:10:32 +0100 Subject: mac80211: reduce the number of retries for nullfunc probing Since nullfunc frames are transmitted as unicast frames, they're more reliable than the broadcast probe requests, so we need fewer retries to figure out whether the AP is really gone. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 33ffce3..7948079 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -28,6 +28,7 @@ #include "rate.h" #include "led.h" +#define IEEE80211_MAX_NULLFUNC_TRIES 2 #define IEEE80211_MAX_PROBE_TRIES 5 /* @@ -1924,9 +1925,15 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) IEEE80211_STA_CONNECTION_POLL) && ifmgd->associated) { u8 bssid[ETH_ALEN]; + int max_tries; memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); + if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) + max_tries = IEEE80211_MAX_NULLFUNC_TRIES; + else + max_tries = IEEE80211_MAX_PROBE_TRIES; + /* ACK received for nullfunc probing frame */ if (!ifmgd->probe_send_count) ieee80211_reset_ap_probe(sdata); @@ -1934,7 +1941,7 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) else if (time_is_after_jiffies(ifmgd->probe_timeout)) run_again(ifmgd, ifmgd->probe_timeout); - else if (ifmgd->probe_send_count < IEEE80211_MAX_PROBE_TRIES) { + else if (ifmgd->probe_send_count < max_tries) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG wiphy_debug(local->hw.wiphy, "%s: No probe response from AP %pM" -- cgit v0.10.2 From c8b576061d87e2a4fb100e70c6a6dae189b3a310 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 23 Nov 2010 15:05:01 -0800 Subject: ath9k: avoid aggregation for VO traffic This should help with latency issues which can happen when using aggregation. Cc: Matt Smith Cc: Senthil Balasubramanian Signed-off-by: Luis R. Rodriguez 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 ee4566d..3e6ea3b 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -1363,7 +1363,8 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, /* Check if aggregation has to be enabled for this tid */ if (conf_is_ht(&sc->hw->conf) && !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { - if (ieee80211_is_data_qos(fc)) { + if (ieee80211_is_data_qos(fc) && + skb_get_queue_mapping(skb) != IEEE80211_AC_VO) { u8 *qc, tid; struct ath_node *an; -- cgit v0.10.2 From 48124d1a91fb77defc9734b4556350d59671fb2c Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 23 Nov 2010 15:05:02 -0800 Subject: mac80211: avoid aggregation for VO traffic This should help with latency issues which can happen when using aggregation. Cc: Felix Fietkau Cc: Matt Smith Cc: Senthil Balasubramanian Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 2d6f025..4ad7a36 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -371,6 +371,9 @@ minstrel_aggr_check(struct minstrel_priv *mp, struct ieee80211_sta *pubsta, stru if (likely(sta->ampdu_mlme.tid_tx[tid])) return; + if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO) + return; + ieee80211_start_tx_ba_session(pubsta, tid); } -- cgit v0.10.2 From 79b1c460a0b55e55981c25c56597c4d5d2872de3 Mon Sep 17 00:00:00 2001 From: Bruno Randolf Date: Wed, 24 Nov 2010 14:34:41 +0900 Subject: cfg80211: Add documentation for antenna ops Signed-off-by: Bruno Randolf Signed-off-by: John W. Linville diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 08e97e5..eaa4aff 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1745,6 +1745,13 @@ enum ieee80211_ampdu_mlme_action { * completion of the channel switch. * * @napi_poll: Poll Rx queue for incoming data frames. + * + * @set_antenna: Set antenna configuration (tx_ant, rx_ant) on the device. + * Parameters are bitmaps of allowed antennas to use for TX/RX. Drivers may + * reject TX/RX mask combinations they cannot support by returning -EINVAL + * (also see nl80211.h @NL80211_ATTR_WIPHY_ANTENNA_TX). + * + * @get_antenna: Get current antenna configuration from device (tx_ant, rx_ant). */ struct ieee80211_ops { int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb); -- cgit v0.10.2 From c063dbf52b998b852122dff07a8b8dd430b38437 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 24 Nov 2010 08:10:05 +0100 Subject: cfg80211: allow using CQM event to notify packet loss This adds the ability for drivers to use CQM events to notify about packet loss for specific stations (which could be the AP for the managed mode case). Since the threshold might be determined by the driver (it isn't passed in right now) it will be passed out of the driver to userspace in the event. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 037b4e4..d706bf3 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -1819,6 +1819,8 @@ enum nl80211_ps_state { * the minimum amount the RSSI level must change after an event before a * new event may be issued (to reduce effects of RSSI oscillation). * @NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT: RSSI threshold event + * @NL80211_ATTR_CQM_PKT_LOSS_EVENT: a u32 value indicating that this many + * consecutive packets were not acknowledged by the peer * @__NL80211_ATTR_CQM_AFTER_LAST: internal * @NL80211_ATTR_CQM_MAX: highest key attribute */ @@ -1827,6 +1829,7 @@ enum nl80211_attr_cqm { NL80211_ATTR_CQM_RSSI_THOLD, NL80211_ATTR_CQM_RSSI_HYST, NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT, + NL80211_ATTR_CQM_PKT_LOSS_EVENT, /* keep last */ __NL80211_ATTR_CQM_AFTER_LAST, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index dd4c43f..0663945 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2601,6 +2601,18 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev, enum nl80211_cqm_rssi_threshold_event rssi_event, gfp_t gfp); +/** + * cfg80211_cqm_pktloss_notify - notify userspace about packetloss to peer + * @dev: network device + * @peer: peer's MAC address + * @num_packets: how many packets were lost -- should be a fixed threshold + * but probably no less than maybe 50, or maybe a throughput dependent + * threshold (to account for temporary interference) + * @gfp: context flags + */ +void cfg80211_cqm_pktloss_notify(struct net_device *dev, + const u8 *peer, u32 num_packets, gfp_t gfp); + /* Logging, debugging and troubleshooting/diagnostic helpers. */ /* wiphy_printk helpers, similar to dev_printk */ diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 26838d9..6980a0c 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -1028,3 +1028,15 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev, nl80211_send_cqm_rssi_notify(rdev, dev, rssi_event, gfp); } EXPORT_SYMBOL(cfg80211_cqm_rssi_notify); + +void cfg80211_cqm_pktloss_notify(struct net_device *dev, + const u8 *peer, u32 num_packets, gfp_t gfp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + + /* Indicate roaming trigger event to user space */ + nl80211_send_cqm_pktloss_notify(rdev, dev, peer, num_packets, gfp); +} +EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 8734efa..67ff7e9 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -5715,6 +5715,51 @@ nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev, nlmsg_free(msg); } +void +nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *peer, + u32 num_packets, gfp_t gfp) +{ + struct sk_buff *msg; + struct nlattr *pinfoattr; + void *hdr; + + msg = nlmsg_new(NLMSG_GOODSIZE, gfp); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM); + if (!hdr) { + nlmsg_free(msg); + return; + } + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, peer); + + pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM); + if (!pinfoattr) + goto nla_put_failure; + + NLA_PUT_U32(msg, NL80211_ATTR_CQM_PKT_LOSS_EVENT, num_packets); + + nla_nest_end(msg, pinfoattr); + + if (genlmsg_end(msg, hdr) < 0) { + nlmsg_free(msg); + return; + } + + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); + return; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); +} + static int nl80211_netlink_notify(struct notifier_block * nb, unsigned long state, void *_notify) diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 30d2f93..16c2f71 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h @@ -87,5 +87,9 @@ nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev, struct net_device *netdev, enum nl80211_cqm_rssi_threshold_event rssi_event, gfp_t gfp); +void +nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *peer, + u32 num_packets, gfp_t gfp); #endif /* __NET_WIRELESS_NL80211_H */ -- cgit v0.10.2 From 99ba2a14283be96a682e04455061c08a46bbf4ec Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 24 Nov 2010 08:10:06 +0100 Subject: mac80211: implement packet loss notification For drivers that have accurate TX status reporting we can report the number of consecutive lost packets to userspace using the new cfg80211 CQM event. The threshold is fixed right now, this may need to be improved in the future. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 9265aca..b562d9b 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -248,6 +248,7 @@ enum plink_state { * @sta: station information we share with the driver * @dead: set to true when sta is unlinked * @uploaded: set to true when sta is uploaded to the driver + * @lost_packets: number of consecutive lost packets */ struct sta_info { /* General information, mostly static */ @@ -335,6 +336,8 @@ struct sta_info { } debugfs; #endif + unsigned int lost_packets; + /* keep last! */ struct ieee80211_sta sta; }; diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 8695cd1..bed7e32 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -161,6 +161,15 @@ static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb) ieee80211_sta_tx_notify(sdata, (void *) skb->data); } +/* + * Use a static threshold for now, best value to be determined + * by testing ... + * Should it depend on: + * - on # of retransmissions + * - current throughput (higher value for higher tpt)? + */ +#define STA_LOST_PKT_THRESHOLD 50 + void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) { struct sk_buff *skb2; @@ -247,6 +256,19 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) if (!(info->flags & IEEE80211_TX_CTL_INJECTED) && (info->flags & IEEE80211_TX_STAT_ACK)) ieee80211_frame_acked(sta, skb); + + if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) { + if (info->flags & IEEE80211_TX_STAT_ACK) { + if (sta->lost_packets) + sta->lost_packets = 0; + } else if (++sta->lost_packets >= STA_LOST_PKT_THRESHOLD) { + cfg80211_cqm_pktloss_notify(sta->sdata->dev, + sta->sta.addr, + sta->lost_packets, + GFP_ATOMIC); + sta->lost_packets = 0; + } + } } rcu_read_unlock(); -- cgit v0.10.2 From eeb1f83fa8f96501331cc17b73c57999e3a1ec5d Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Tue, 23 Nov 2010 10:58:52 -0800 Subject: iwlagn: name change for BT config flag Bit 7 of BT config flag is used to enable/disable PSPoll sync. Make the name to match it. Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 9c1b7fb..4028ed3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -2439,8 +2439,9 @@ struct iwl_bt_cmd { #define IWLAGN_BT_FLAG_COEX_MODE_3W 2 #define IWLAGN_BT_FLAG_COEX_MODE_4W 3 -#define IWLAGN_BT_FLAG_UCODE_DEFAULT BIT(6) -#define IWLAGN_BT_FLAG_NOCOEX_NOTIF BIT(7) +#define IWLAGN_BT_FLAG_UCODE_DEFAULT BIT(6) +/* Disable Sync PSPoll on SCO/eSCO */ +#define IWLAGN_BT_FLAG_SYNC_2_BT_DISABLE BIT(7) #define IWLAGN_BT_PRIO_BOOST_MAX 0xFF #define IWLAGN_BT_PRIO_BOOST_MIN 0x00 -- cgit v0.10.2 From 97badb0eefc9b6f23f864c5348b695be35f05882 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Tue, 23 Nov 2010 10:58:53 -0800 Subject: iwlwifi: add more power management flags Adding additional power management option available for the device. Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 4028ed3..f9e7fa4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -2671,6 +2671,11 @@ struct iwl_spectrum_notification { #define IWL_POWER_SLEEP_OVER_DTIM_MSK cpu_to_le16(BIT(2)) #define IWL_POWER_PCI_PM_MSK cpu_to_le16(BIT(3)) #define IWL_POWER_FAST_PD cpu_to_le16(BIT(4)) +#define IWL_POWER_BEACON_FILTERING cpu_to_le16(BIT(5)) +#define IWL_POWER_SHADOW_REG_ENA cpu_to_le16(BIT(6)) +#define IWL_POWER_CT_KILL_SET cpu_to_le16(BIT(7)) +#define IWL_POWER_BT_SCO_ENA cpu_to_le16(BIT(8)) +#define IWL_POWER_ADVANCE_PM_ENA cpu_to_le16(BIT(9)) struct iwl3945_powertable_cmd { __le16 flags; -- cgit v0.10.2 From e366176e5c7f37d2d4cd0708e63b939e3fa3b5c6 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Tue, 23 Nov 2010 10:58:54 -0800 Subject: iwlwifi: consider BT for power management Check the BT PSPoll flag when fill PM command to uCode Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 0cc66fd..f650282 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -549,6 +549,7 @@ static struct iwl_bt_params iwl6000_bt_params = { .agg_time_limit = BT_AGG_THRESHOLD_DEF, .bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE, .bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT, + .bt_sco_disable = true, }; struct iwl_cfg iwl6000g2a_2agn_cfg = { diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index c4491f7..f8fe5f4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -1829,6 +1829,10 @@ void iwlagn_send_advance_bt_config(struct iwl_priv *priv) } else { bt_cmd.flags = IWLAGN_BT_FLAG_COEX_MODE_3W << IWLAGN_BT_FLAG_COEX_MODE_SHIFT; + if (priv->cfg->bt_params && + priv->cfg->bt_params->bt_sco_disable) + bt_cmd.flags |= IWLAGN_BT_FLAG_SYNC_2_BT_DISABLE; + if (priv->bt_ch_announce) bt_cmd.flags |= IWLAGN_BT_FLAG_CHANNEL_INHIBITION; IWL_DEBUG_INFO(priv, "BT coex flag: 0X%x\n", bt_cmd.flags); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 9035cd8..3f7bd40 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -334,6 +334,7 @@ struct iwl_base_params { * @agg_time_limit: maximum number of uSec in aggregation * @ampdu_factor: Maximum A-MPDU length factor * @ampdu_density: Minimum A-MPDU spacing + * @bt_sco_disable: uCode should not response to BT in SCO/ESCO mode */ struct iwl_bt_params { bool advanced_bt_coexist; @@ -343,6 +344,7 @@ struct iwl_bt_params { u16 agg_time_limit; u8 ampdu_factor; u8 ampdu_density; + bool bt_sco_disable; }; /* * @use_rts_for_aggregation: use rts/cts protection for HT traffic diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index b7abd86..306c852 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -163,6 +163,15 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv, else cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK; + if (priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist) { + if (!priv->cfg->bt_params->bt_sco_disable) + cmd->flags |= IWL_POWER_BT_SCO_ENA; + else + cmd->flags &= ~IWL_POWER_BT_SCO_ENA; + } + + slp_itrvl = le32_to_cpu(cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]); if (slp_itrvl > IWL_CONN_MAX_LISTEN_INTERVAL) cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1] = @@ -236,6 +245,14 @@ static void iwl_power_fill_sleep_cmd(struct iwl_priv *priv, if (priv->power_data.pci_pm) cmd->flags |= IWL_POWER_PCI_PM_MSK; + if (priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist) { + if (!priv->cfg->bt_params->bt_sco_disable) + cmd->flags |= IWL_POWER_BT_SCO_ENA; + else + cmd->flags &= ~IWL_POWER_BT_SCO_ENA; + } + cmd->rx_data_timeout = cpu_to_le32(1000 * dynps_ms); cmd->tx_data_timeout = cpu_to_le32(1000 * dynps_ms); -- cgit v0.10.2 From 1f37daf3233ccda5072f715d6c322d84833cdd92 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Tue, 23 Nov 2010 10:58:55 -0800 Subject: iwlwifi: power management checking for shadow register If shadow register is enable, modify the power management command to inform uCode Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 306c852..21c5e6a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -163,6 +163,11 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv, else cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK; + if (priv->cfg->base_params->shadow_reg_enable) + cmd->flags |= IWL_POWER_SHADOW_REG_ENA; + else + cmd->flags &= ~IWL_POWER_SHADOW_REG_ENA; + if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist) { if (!priv->cfg->bt_params->bt_sco_disable) @@ -245,6 +250,11 @@ static void iwl_power_fill_sleep_cmd(struct iwl_priv *priv, if (priv->power_data.pci_pm) cmd->flags |= IWL_POWER_PCI_PM_MSK; + if (priv->cfg->base_params->shadow_reg_enable) + cmd->flags |= IWL_POWER_SHADOW_REG_ENA; + else + cmd->flags &= ~IWL_POWER_SHADOW_REG_ENA; + if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist) { if (!priv->cfg->bt_params->bt_sco_disable) -- cgit v0.10.2 From 35162ba75900209755628ccf7357763797037ba6 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Tue, 23 Nov 2010 10:58:56 -0800 Subject: iwlwifi: advance power management support For 6000g2b and up, adding advance power management support for better power consumption Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index f650282..93e3fe9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -621,6 +621,7 @@ struct iwl_cfg iwl6000g2b_2agn_cfg = { .need_dc_calib = true, .need_temp_offset_calib = true, .led_mode = IWL_LED_RF_STATE, + .adv_pm = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, }; @@ -641,6 +642,7 @@ struct iwl_cfg iwl6000g2b_2abg_cfg = { .need_dc_calib = true, .need_temp_offset_calib = true, .led_mode = IWL_LED_RF_STATE, + .adv_pm = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, }; @@ -662,6 +664,7 @@ struct iwl_cfg iwl6000g2b_2bgn_cfg = { .need_dc_calib = true, .need_temp_offset_calib = true, .led_mode = IWL_LED_RF_STATE, + .adv_pm = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, }; @@ -682,6 +685,7 @@ struct iwl_cfg iwl6000g2b_2bg_cfg = { .need_dc_calib = true, .need_temp_offset_calib = true, .led_mode = IWL_LED_RF_STATE, + .adv_pm = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, }; @@ -703,6 +707,7 @@ struct iwl_cfg iwl6000g2b_bgn_cfg = { .need_dc_calib = true, .need_temp_offset_calib = true, .led_mode = IWL_LED_RF_STATE, + .adv_pm = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, }; @@ -723,6 +728,7 @@ struct iwl_cfg iwl6000g2b_bg_cfg = { .need_dc_calib = true, .need_temp_offset_calib = true, .led_mode = IWL_LED_RF_STATE, + .adv_pm = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, }; @@ -862,6 +868,7 @@ struct iwl_cfg iwl130_bgn_cfg = { .ht_params = &iwl6000_ht_params, .need_dc_calib = true, .led_mode = IWL_LED_RF_STATE, + .adv_pm = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, }; @@ -881,6 +888,7 @@ struct iwl_cfg iwl130_bg_cfg = { .bt_params = &iwl6000_bt_params, .need_dc_calib = true, .led_mode = IWL_LED_RF_STATE, + .adv_pm = 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-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index f9e7fa4..c9448cb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -2668,6 +2668,8 @@ struct iwl_spectrum_notification { #define IWL_POWER_VEC_SIZE 5 #define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK cpu_to_le16(BIT(0)) +#define IWL_POWER_POWER_SAVE_ENA_MSK cpu_to_le16(BIT(0)) +#define IWL_POWER_POWER_MANAGEMENT_ENA_MSK cpu_to_le16(BIT(1)) #define IWL_POWER_SLEEP_OVER_DTIM_MSK cpu_to_le16(BIT(2)) #define IWL_POWER_PCI_PM_MSK cpu_to_le16(BIT(3)) #define IWL_POWER_FAST_PD cpu_to_le16(BIT(4)) @@ -2675,7 +2677,7 @@ struct iwl_spectrum_notification { #define IWL_POWER_SHADOW_REG_ENA cpu_to_le16(BIT(6)) #define IWL_POWER_CT_KILL_SET cpu_to_le16(BIT(7)) #define IWL_POWER_BT_SCO_ENA cpu_to_le16(BIT(8)) -#define IWL_POWER_ADVANCE_PM_ENA cpu_to_le16(BIT(9)) +#define IWL_POWER_ADVANCE_PM_ENA_MSK cpu_to_le16(BIT(9)) struct iwl3945_powertable_cmd { __le16 flags; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 3f7bd40..808be73 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -366,6 +366,7 @@ struct iwl_ht_params { * @need_temp_offset_calib: need to perform temperature offset calibration * @scan_antennas: available antenna for scan operation * @led_mode: 0=blinking, 1=On(RF On)/Off(RF Off) + * @adv_pm: advance power management * * We enable the driver to be backward compatible wrt API version. The * driver specifies which APIs it supports (with @ucode_api_max being the @@ -413,6 +414,7 @@ struct iwl_cfg { u8 scan_rx_antennas[IEEE80211_NUM_BANDS]; u8 scan_tx_antennas[IEEE80211_NUM_BANDS]; enum iwl_led_mode led_mode; + const bool adv_pm; }; /*************************** diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 21c5e6a..1eec18d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -75,6 +75,10 @@ struct iwl_power_vec_entry { #define NOSLP cpu_to_le16(0), 0, 0 #define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0 +#define ASLP (IWL_POWER_POWER_SAVE_ENA_MSK | \ + IWL_POWER_POWER_MANAGEMENT_ENA_MSK | \ + IWL_POWER_ADVANCE_PM_ENA_MSK) +#define ASLP_TOUT(T) cpu_to_le32(T) #define TU_TO_USEC 1024 #define SLP_TOUT(T) cpu_to_le32((T) * TU_TO_USEC) #define SLP_VEC(X0, X1, X2, X3, X4) {cpu_to_le32(X0), \ @@ -114,6 +118,52 @@ static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = { {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(4, 7, 10, 10, 0xFF)}, 0} }; +/* advance power management */ +/* DTIM 0 - 2 */ +static const struct iwl_power_vec_entry apm_range_0[IWL_POWER_NUM] = { + {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50), + SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0}, + {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50), + SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0}, + {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50), + SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0}, + {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50), + SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0}, + {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50), + SLP_VEC(1, 2, 6, 8, 0xFF), ASLP_TOUT(2)}, 2} +}; + + +/* for DTIM period IWL_DTIM_RANGE_0_MAX + 1 through IWL_DTIM_RANGE_1_MAX */ +/* DTIM 3 - 10 */ +static const struct iwl_power_vec_entry apm_range_1[IWL_POWER_NUM] = { + {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50), + SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0}, + {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50), + SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0}, + {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50), + SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0}, + {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50), + SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0}, + {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50), + SLP_VEC(1, 2, 6, 8, 0xFF), 0}, 2} +}; + +/* for DTIM period > IWL_DTIM_RANGE_1_MAX */ +/* DTIM 11 - */ +static const struct iwl_power_vec_entry apm_range_2[IWL_POWER_NUM] = { + {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50), + SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0}, + {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50), + SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0}, + {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50), + SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0}, + {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50), + SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0}, + {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50), + SLP_VEC(1, 2, 6, 8, 0xFF), ASLP_TOUT(2)}, 2} +}; + static void iwl_static_sleep_cmd(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd, enum iwl_power_level lvl, int period) @@ -124,11 +174,19 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv, u8 skip; u32 slp_itrvl; - table = range_2; - if (period <= IWL_DTIM_RANGE_1_MAX) - table = range_1; - if (period <= IWL_DTIM_RANGE_0_MAX) - table = range_0; + if (priv->cfg->adv_pm) { + table = apm_range_2; + if (period <= IWL_DTIM_RANGE_1_MAX) + table = apm_range_1; + if (period <= IWL_DTIM_RANGE_0_MAX) + table = apm_range_0; + } else { + table = range_2; + if (period <= IWL_DTIM_RANGE_1_MAX) + table = range_1; + if (period <= IWL_DTIM_RANGE_0_MAX) + table = range_0; + } BUG_ON(lvl < 0 || lvl >= IWL_POWER_NUM); -- cgit v0.10.2 From bedbbb959d2c1d1dbb4c2215f5b7074b1da3030a Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Fri, 19 Nov 2010 16:53:19 +0530 Subject: ath: Add a driver_info bitmask field The driver_info stores the device category information which is used to load appropriate device firmware, select firmware offset and eeprom starting location. The driver_info is accessed across ath9k_htc and ath9k_hw. Hence placed under common structure. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index 501050c..20ea68c 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -104,6 +104,11 @@ enum ath_cipher { ATH_CIPHER_MIC = 127 }; +enum ath_drv_info { + AR7010_DEVICE = BIT(0), + AR9287_DEVICE = BIT(1), +}; + /** * struct ath_ops - Register read/write operations * @@ -147,6 +152,7 @@ struct ath_common { u8 rx_chainmask; u32 rx_bufsize; + u32 driver_info; u32 keymax; DECLARE_BITMAP(keymap, ATH_KEYMAX); -- cgit v0.10.2 From 64f121708342afec306ce52920cc9982f4f1008f Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Fri, 19 Nov 2010 16:53:20 +0530 Subject: ath9k_htc: Add driver_info in usb device list Added driver_info to identify AR7010, R9287 HTC devices. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index dfb6560..6a0dbd1 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -28,10 +28,16 @@ MODULE_FIRMWARE(FIRMWARE_AR9271); static struct usb_device_id ath9k_hif_usb_ids[] = { { USB_DEVICE(0x0cf3, 0x9271) }, /* Atheros */ { USB_DEVICE(0x0cf3, 0x1006) }, /* Atheros */ - { USB_DEVICE(0x0cf3, 0x7010) }, /* Atheros */ - { USB_DEVICE(0x0cf3, 0x7015) }, /* Atheros */ + { USB_DEVICE(0x0cf3, 0x7010), + .driver_info = AR7010_DEVICE }, + /* Atheros */ + { USB_DEVICE(0x0cf3, 0x7015), + .driver_info = AR7010_DEVICE | AR9287_DEVICE }, + /* Atheros */ { USB_DEVICE(0x0846, 0x9030) }, /* Netgear N150 */ - { USB_DEVICE(0x0846, 0x9018) }, /* Netgear WNDA3200 */ + { USB_DEVICE(0x0846, 0x9018), + .driver_info = AR7010_DEVICE }, + /* Netgear WNDA3200 */ { USB_DEVICE(0x07D1, 0x3A10) }, /* Dlink Wireless 150 */ { USB_DEVICE(0x13D3, 0x3327) }, /* Azurewave */ { USB_DEVICE(0x13D3, 0x3328) }, /* Azurewave */ @@ -40,9 +46,13 @@ static struct usb_device_id ath9k_hif_usb_ids[] = { { USB_DEVICE(0x13D3, 0x3349) }, /* Azurewave */ { USB_DEVICE(0x13D3, 0x3350) }, /* Azurewave */ { USB_DEVICE(0x04CA, 0x4605) }, /* Liteon */ - { USB_DEVICE(0x083A, 0xA704) }, /* SMC Networks */ + { USB_DEVICE(0x083A, 0xA704), + .driver_info = AR7010_DEVICE }, + /* SMC Networks */ { USB_DEVICE(0x040D, 0x3801) }, /* VIA */ - { USB_DEVICE(0x1668, 0x1200) }, /* Verizon */ + { USB_DEVICE(0x1668, 0x1200), + .driver_info = AR7010_DEVICE | AR9287_DEVICE }, + /* Verizon */ { }, }; -- cgit v0.10.2 From f7ec8fb4d6f8f3ecb8b11e9e46ece95aa66139cc Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Fri, 19 Nov 2010 16:53:21 +0530 Subject: ath9k_hw: Fix eeprom offset for AR9287 devices (PCI/USB) AR9287 devices (PCI/USB) use different eeprom start location to read nvram. New devices might endup with same devid. So use driver_info to set offset, instead of devid. driver_info is valid for HTC devices alone which is filled in usb_device_id. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c index e756978..bcb9ed3 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -37,10 +37,10 @@ static bool ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah) int addr, eep_start_loc; eep_data = (u16 *)eep; - if (AR9287_HTC_DEVID(ah)) - eep_start_loc = AR9287_HTC_EEP_START_LOC; - else + if (!common->driver_info) eep_start_loc = AR9287_EEP_START_LOC; + else + eep_start_loc = AR9287_HTC_EEP_START_LOC; if (!ath9k_hw_use_flash(ah)) { ath_print(common, ATH_DBG_EEPROM, diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index f1bbc75..9d68237 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -870,10 +870,6 @@ ((_ah)->hw_version.devid == 0xA704) || \ ((_ah)->hw_version.devid == 0x1200)) -#define AR9287_HTC_DEVID(_ah) \ - (((_ah)->hw_version.devid == 0x7015) || \ - ((_ah)->hw_version.devid == 0x1200)) - #define AR_RADIO_SREV_MAJOR 0xf0 #define AR_RAD5133_SREV_MAJOR 0xc0 #define AR_RAD2133_SREV_MAJOR 0xd0 -- cgit v0.10.2 From fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18df Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Fri, 19 Nov 2010 16:53:22 +0530 Subject: ath9k_htc: Identify devices using driver_info Categorize AR7010 & AR9287 devices based on driver_info of usb_device_id, instead of PIDs. This avoids per-device cases and minimize code changes for new device addition. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 6a0dbd1..ae842db 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -786,7 +786,8 @@ static void ath9k_hif_usb_dealloc_urbs(struct hif_device_usb *hif_dev) ath9k_hif_usb_dealloc_rx_urbs(hif_dev); } -static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev) +static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev, + u32 drv_info) { int transfer, err; const void *data = hif_dev->firmware->data; @@ -817,18 +818,10 @@ static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev) } kfree(buf); - switch (hif_dev->device_id) { - case 0x7010: - case 0x7015: - case 0x9018: - case 0xA704: - case 0x1200: + if (drv_info & AR7010_DEVICE) firm_offset = AR7010_FIRMWARE_TEXT; - break; - default: + else firm_offset = AR9271_FIRMWARE_TEXT; - break; - } /* * Issue FW download complete command to firmware. @@ -846,7 +839,7 @@ static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev) return 0; } -static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev) +static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev, u32 drv_info) { int ret, idx; struct usb_host_interface *alt = &hif_dev->interface->altsetting[0]; @@ -862,7 +855,7 @@ static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev) } /* Download firmware */ - ret = ath9k_hif_usb_download_fw(hif_dev); + ret = ath9k_hif_usb_download_fw(hif_dev, drv_info); if (ret) { dev_err(&hif_dev->udev->dev, "ath9k_htc: Firmware - %s download failed\n", @@ -941,23 +934,15 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface, /* Find out which firmware to load */ - switch(hif_dev->device_id) { - case 0x7010: - case 0x7015: - case 0x9018: - case 0xA704: - case 0x1200: + if (id->driver_info & AR7010_DEVICE) if (le16_to_cpu(udev->descriptor.bcdDevice) == 0x0202) hif_dev->fw_name = FIRMWARE_AR7010_1_1; else hif_dev->fw_name = FIRMWARE_AR7010; - break; - default: + else hif_dev->fw_name = FIRMWARE_AR9271; - break; - } - ret = ath9k_hif_usb_dev_init(hif_dev); + ret = ath9k_hif_usb_dev_init(hif_dev, id->driver_info); if (ret) { ret = -EINVAL; goto err_hif_init_usb; @@ -965,7 +950,7 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface, ret = ath9k_htc_hw_init(hif_dev->htc_handle, &hif_dev->udev->dev, hif_dev->device_id, - hif_dev->udev->product); + hif_dev->udev->product, id->driver_info); if (ret) { ret = -EINVAL; goto err_htc_hw_init; @@ -1043,6 +1028,7 @@ static int ath9k_hif_usb_resume(struct usb_interface *interface) { struct hif_device_usb *hif_dev = (struct hif_device_usb *) usb_get_intfdata(interface); + struct htc_target *htc_handle = hif_dev->htc_handle; int ret; ret = ath9k_hif_usb_alloc_urbs(hif_dev); @@ -1050,7 +1036,8 @@ static int ath9k_hif_usb_resume(struct usb_interface *interface) return ret; if (hif_dev->firmware) { - ret = ath9k_hif_usb_download_fw(hif_dev); + ret = ath9k_hif_usb_download_fw(hif_dev, + htc_handle->drv_priv->ah->common.driver_info); if (ret) goto fail_resume; } else { @@ -1060,7 +1047,7 @@ static int ath9k_hif_usb_resume(struct usb_interface *interface) mdelay(100); - ret = ath9k_htc_resume(hif_dev->htc_handle); + ret = ath9k_htc_resume(htc_handle); if (ret) goto fail_resume; diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index db00289..afe39a9 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -461,7 +461,7 @@ void ath9k_init_leds(struct ath9k_htc_priv *priv); void ath9k_deinit_leds(struct ath9k_htc_priv *priv); int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev, - u16 devid, char *product); + u16 devid, char *product, u32 drv_info); void ath9k_htc_disconnect_device(struct htc_target *htc_handle, bool hotunplug); #ifdef CONFIG_PM int ath9k_htc_resume(struct htc_target *htc_handle); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index cba904a..071d0c9 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -181,7 +181,8 @@ static inline int ath9k_htc_connect_svc(struct ath9k_htc_priv *priv, return htc_connect_service(priv->htc, &req, ep_id); } -static int ath9k_init_htc_services(struct ath9k_htc_priv *priv, u16 devid) +static int ath9k_init_htc_services(struct ath9k_htc_priv *priv, u16 devid, + u32 drv_info) { int ret; @@ -245,17 +246,10 @@ static int ath9k_init_htc_services(struct ath9k_htc_priv *priv, u16 devid) * the HIF layer, shouldn't matter much. */ - switch(devid) { - case 0x7010: - case 0x7015: - case 0x9018: - case 0xA704: - case 0x1200: + if (drv_info & AR7010_DEVICE) priv->htc->credits = 45; - break; - default: + else priv->htc->credits = 33; - } ret = htc_init(priv->htc); if (ret) @@ -627,7 +621,8 @@ static void ath9k_init_btcoex(struct ath9k_htc_priv *priv) } static int ath9k_init_priv(struct ath9k_htc_priv *priv, - u16 devid, char *product) + u16 devid, char *product, + u32 drv_info) { struct ath_hw *ah = NULL; struct ath_common *common; @@ -651,6 +646,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, common->hw = priv->hw; common->priv = priv; common->debug_mask = ath9k_debug; + common->driver_info = drv_info; spin_lock_init(&priv->wmi->wmi_lock); spin_lock_init(&priv->beacon_lock); @@ -763,7 +759,7 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, } static int ath9k_init_device(struct ath9k_htc_priv *priv, - u16 devid, char *product) + u16 devid, char *product, u32 drv_info) { struct ieee80211_hw *hw = priv->hw; struct ath_common *common; @@ -772,7 +768,7 @@ static int ath9k_init_device(struct ath9k_htc_priv *priv, struct ath_regulatory *reg; /* Bring up device */ - error = ath9k_init_priv(priv, devid, product); + error = ath9k_init_priv(priv, devid, product, drv_info); if (error != 0) goto err_init; @@ -830,7 +826,7 @@ err_init: } int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev, - u16 devid, char *product) + u16 devid, char *product, u32 drv_info) { struct ieee80211_hw *hw; struct ath9k_htc_priv *priv; @@ -857,14 +853,14 @@ int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev, goto err_free; } - ret = ath9k_init_htc_services(priv, devid); + ret = ath9k_init_htc_services(priv, devid, drv_info); if (ret) goto err_init; /* The device may have been unplugged earlier. */ priv->op_flags &= ~OP_UNPLUGGED; - ret = ath9k_init_device(priv, devid, product); + ret = ath9k_init_device(priv, devid, product, drv_info); if (ret) goto err_init; @@ -894,14 +890,15 @@ void ath9k_htc_disconnect_device(struct htc_target *htc_handle, bool hotunplug) #ifdef CONFIG_PM int ath9k_htc_resume(struct htc_target *htc_handle) { + struct ath9k_htc_priv *priv = htc_handle->drv_priv; int ret; - ret = ath9k_htc_wait_for_target(htc_handle->drv_priv); + ret = ath9k_htc_wait_for_target(priv); if (ret) return ret; - ret = ath9k_init_htc_services(htc_handle->drv_priv, - htc_handle->drv_priv->ah->hw_version.devid); + ret = ath9k_init_htc_services(priv, priv->ah->hw_version.devid, + priv->ah->common.driver_info); return ret; } #endif diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c index 861ec92..c41ab8c 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.c +++ b/drivers/net/wireless/ath/ath9k/htc_hst.c @@ -462,9 +462,10 @@ void ath9k_htc_hw_free(struct htc_target *htc) } int ath9k_htc_hw_init(struct htc_target *target, - struct device *dev, u16 devid, char *product) + struct device *dev, u16 devid, + char *product, u32 drv_info) { - if (ath9k_htc_probe_device(target, dev, devid, product)) { + if (ath9k_htc_probe_device(target, dev, devid, product, drv_info)) { printk(KERN_ERR "Failed to initialize the device\n"); return -ENODEV; } diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.h b/drivers/net/wireless/ath/ath9k/htc_hst.h index 07b6509..6fc1b21 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.h +++ b/drivers/net/wireless/ath/ath9k/htc_hst.h @@ -239,7 +239,8 @@ struct htc_target *ath9k_htc_hw_alloc(void *hif_handle, struct device *dev); void ath9k_htc_hw_free(struct htc_target *htc); int ath9k_htc_hw_init(struct htc_target *target, - struct device *dev, u16 devid, char *product); + struct device *dev, u16 devid, char *product, + u32 drv_info); void ath9k_htc_hw_deinit(struct htc_target *target, bool hot_unplug); #endif /* HTC_HST_H */ diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 9d68237..a597cc8d 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -864,11 +864,7 @@ ((REG_READ(_ah, AR_AN_SYNTH9) & 0x7) == 0x1)) #define AR_DEVID_7010(_ah) \ - (((_ah)->hw_version.devid == 0x7010) || \ - ((_ah)->hw_version.devid == 0x7015) || \ - ((_ah)->hw_version.devid == 0x9018) || \ - ((_ah)->hw_version.devid == 0xA704) || \ - ((_ah)->hw_version.devid == 0x1200)) + ((_ah)->common.driver_info & AR7010_DEVICE) #define AR_RADIO_SREV_MAJOR 0xf0 #define AR_RAD5133_SREV_MAJOR 0xc0 -- cgit v0.10.2 From 4f8559383c41262b50dc758e2e310f257ce6a14d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 20 Nov 2010 03:08:48 +0100 Subject: ath9k_hw: remove ath9k_hw_stoppcurecv It is no longer used anywhere Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 65b1ee2..b04b37b 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -766,14 +766,6 @@ void ath9k_hw_startpcureceive(struct ath_hw *ah, bool is_scanning) } EXPORT_SYMBOL(ath9k_hw_startpcureceive); -void ath9k_hw_stoppcurecv(struct ath_hw *ah) -{ - REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS); - - ath9k_hw_disable_mib_counters(ah); -} -EXPORT_SYMBOL(ath9k_hw_stoppcurecv); - void ath9k_hw_abortpcurecv(struct ath_hw *ah) { REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_ABORT | AR_DIAG_RX_DIS); diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index 22907e2..7512f97 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -691,7 +691,6 @@ void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set); void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp); void ath9k_hw_startpcureceive(struct ath_hw *ah, bool is_scanning); -void ath9k_hw_stoppcurecv(struct ath_hw *ah); void ath9k_hw_abortpcurecv(struct ath_hw *ah); bool ath9k_hw_stopdmarecv(struct ath_hw *ah); int ath9k_hw_beaconq_setup(struct ath_hw *ah); -- cgit v0.10.2