From 98b2a68473ae975bc4abdeb66cd719ccfdad9d4a Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 11 Dec 2009 15:40:52 +0200 Subject: wl1271: add gpio_power file in debugfs to power the chip on and off Some debugging tools require the chip to be powered on before they can work. With these tools, we shouldn't upload the firmware nor boot the firmware ourselves, so this debufs file is provided. It always contains the gpio power setting (0 = off, 1 = on). To change the power setting, just write 0 or 1 to the file. Signed-off-by: Luciano Coelho Reviewed-by: Juuso Oikarinen Reviewed-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net/wireless/wl12xx/wl1271.h') diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 94359b1a861..3bec6f3b1c7 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -276,6 +276,7 @@ struct wl1271_debugfs { struct dentry *retry_count; struct dentry *excessive_retries; + struct dentry *gpio_power; }; #define NUM_TX_QUEUES 4 @@ -442,6 +443,8 @@ struct wl1271 { struct conf_drv_settings conf; struct list_head list; + + bool gpio_power; }; int wl1271_plt_start(struct wl1271 *wl); -- cgit v1.2.3-70-g09d2 From 8cf5e8e509950237fa0982235a703348d8b6e670 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 11 Dec 2009 15:40:53 +0200 Subject: wl1271: upload only the first 468 bytes from the NVS file We were uploading the whole NVS file, but that is wrong, because the same file also contains the initialization values. For the latest firmwares, we should upload only the initial 468 bytes from the file. Signed-off-by: Luciano Coelho Reviewed-by: Juuso Oikarinen Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271.h | 1 + drivers/net/wireless/wl12xx/wl1271_boot.c | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/wl12xx/wl1271.h') diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 3bec6f3b1c7..8dfc9ec9590 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -111,6 +111,7 @@ enum { #define WL1271_FW_NAME "wl1271-fw.bin" #define WL1271_NVS_NAME "wl1271-nvs.bin" +#define WL1271_NVS_LEN 468 /* * Enable/disable 802.11a support for WL1273 diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c index b7c96454cca..e803b876f3f 100644 --- a/drivers/net/wireless/wl12xx/wl1271_boot.c +++ b/drivers/net/wireless/wl12xx/wl1271_boot.c @@ -225,9 +225,15 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) if (nvs == NULL) return -ENODEV; + if (wl->nvs_len < WL1271_NVS_LEN) + return -EINVAL; + nvs_ptr = nvs; - nvs_len = wl->nvs_len; + /* only the first part of the NVS needs to be uploaded */ + nvs_len = WL1271_NVS_LEN; + + /* FIXME: read init settings from the remaining part of the NVS */ /* Update the device MAC address into the nvs */ nvs[11] = wl->mac_addr[0]; -- cgit v1.2.3-70-g09d2 From a6fe231361e35e3d068a63bbfd2318fa4e961ec5 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Fri, 11 Dec 2009 15:40:58 +0200 Subject: wl1271: Use slow rates for association messages While not associated, default the data rates to 1 and 2mbps, so that only those rates will be used for association related message transfer. Once associated, configure the full rate-set supported by the AP. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271.h | 2 -- drivers/net/wireless/wl12xx/wl1271_conf.h | 3 ++- drivers/net/wireless/wl12xx/wl1271_init.c | 2 +- drivers/net/wireless/wl12xx/wl1271_main.c | 8 ++++++-- 4 files changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless/wl12xx/wl1271.h') diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 8dfc9ec9590..4b5ddba96f0 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -107,8 +107,6 @@ enum { CFG_RX_CTL_EN | CFG_RX_BCN_EN | \ CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN) -#define WL1271_DEFAULT_BASIC_RATE_SET (CONF_TX_RATE_MASK_ALL) - #define WL1271_FW_NAME "wl1271-fw.bin" #define WL1271_NVS_NAME "wl1271-nvs.bin" #define WL1271_NVS_LEN 468 diff --git a/drivers/net/wireless/wl12xx/wl1271_conf.h b/drivers/net/wireless/wl12xx/wl1271_conf.h index c87ae56ce42..5d1b5b6493e 100644 --- a/drivers/net/wireless/wl12xx/wl1271_conf.h +++ b/drivers/net/wireless/wl12xx/wl1271_conf.h @@ -258,7 +258,8 @@ struct conf_rx_settings { #define CONF_TX_MAX_RATE_CLASSES 8 #define CONF_TX_RATE_MASK_UNSPECIFIED 0 -#define CONF_TX_RATE_MASK_ALL 0x1eff +#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 { diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c index 7bfd6c6a4c7..c67889dd18f 100644 --- a/drivers/net/wireless/wl12xx/wl1271_init.c +++ b/drivers/net/wireless/wl12xx/wl1271_init.c @@ -284,7 +284,7 @@ int wl1271_hw_init(struct wl1271 *wl) goto out_free_memmap; /* Configure TX rate classes */ - ret = wl1271_acx_rate_policies(wl, WL1271_DEFAULT_BASIC_RATE_SET); + ret = wl1271_acx_rate_policies(wl, CONF_TX_RATE_MASK_BASIC); if (ret < 0) goto out_free_memmap; diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 5a6e4d44696..272a8fa677e 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -1180,6 +1180,11 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) wl1271_unjoin_channel(wl); else wl1271_join_channel(wl, channel); + + if (conf->flags & IEEE80211_CONF_IDLE) { + wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC; + wl1271_acx_rate_policies(wl, CONF_TX_RATE_MASK_BASIC); + } } /* if the channel changes while joined, join again */ @@ -1568,7 +1573,6 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, } } else { /* use defaults when not associated */ - wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET; wl->aid = 0; } @@ -1897,7 +1901,7 @@ static int __devinit wl1271_probe(struct spi_device *spi) wl->psm_entry_retry = 0; wl->tx_queue_stopped = false; wl->power_level = WL1271_DEFAULT_POWER_LEVEL; - wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET; + wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC; wl->band = IEEE80211_BAND_2GHZ; wl->vif = NULL; wl->joined = false; -- cgit v1.2.3-70-g09d2 From af5e084b3200ab6e3033068a34fe16fd139be17b Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Fri, 11 Dec 2009 15:41:00 +0200 Subject: wl1271: prevent power save entry while not associated The mac80211 sometimes requests power save entry while not associated - this will cause problems, so prevent it if not associated. Go to powersave once association is complete. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271.h | 1 + drivers/net/wireless/wl12xx/wl1271_main.c | 11 ++++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/wl12xx/wl1271.h') diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 4b5ddba96f0..81e1c9531a3 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -416,6 +416,7 @@ struct wl1271 { /* PSM mode requested */ bool psm_requested; + bool associated; /* retry counter for PSM entries */ u8 psm_entry_retry; diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index d507dae19e1..d07f0356519 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -978,6 +978,7 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) wl->elp = false; wl->psm = 0; wl->psm_entry_retry = 0; + wl->associated = false; wl->tx_queue_stopped = false; wl->power_level = WL1271_DEFAULT_POWER_LEVEL; wl->tx_blocks_available = 0; @@ -1191,8 +1192,6 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) wl1271_join_channel(wl, channel); if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) { - wl1271_info("psm enabled"); - wl->psm_requested = true; /* @@ -1200,7 +1199,10 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) * If we're not, we'll enter it when joining an SSID, * through the bss_info_changed() hook. */ - ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE); + if (wl->associated) { + wl1271_info("psm enabled"); + ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE); + } } else if (!(conf->flags & IEEE80211_CONF_PS) && wl->psm_requested) { wl1271_info("psm disabled"); @@ -1548,6 +1550,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ASSOC) { if (bss_conf->assoc) { wl->aid = bss_conf->aid; + wl->associated = true; /* * with wl1271, we don't need to update the @@ -1572,6 +1575,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, } } else { /* use defaults when not associated */ + wl->associated = false; wl->aid = 0; } @@ -1898,6 +1902,7 @@ static int __devinit wl1271_probe(struct spi_device *spi) wl->psm = 0; wl->psm_requested = false; wl->psm_entry_retry = 0; + wl->associated = false; wl->tx_queue_stopped = false; wl->power_level = WL1271_DEFAULT_POWER_LEVEL; wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC; -- cgit v1.2.3-70-g09d2 From 01ac17ecb6292ceab9bfc498145491b78552b239 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Fri, 11 Dec 2009 15:41:02 +0200 Subject: wl1271: Add pre-power-on sleep This patch adds a short delay before powering on the wl1271. Normally, it is not needed, but if the wl1271 has been powered off shortly before, for reliable firmware-booting this small stabilization delay is required. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271.h | 4 +++- drivers/net/wireless/wl12xx/wl1271_main.c | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/wl12xx/wl1271.h') diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 81e1c9531a3..c965c4a718f 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -458,7 +458,9 @@ int wl1271_plt_stop(struct wl1271 *wl); #define WL1271_TX_QUEUE_MAX_LENGTH 20 -/* WL1271 needs a 200ms sleep after power on */ +/* 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 */ static inline bool wl1271_11a_enabled(void) diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 0795bf3c60d..0520b38e8e7 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -618,6 +618,7 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) struct wl1271_partition_set partition; int ret = 0; + msleep(WL1271_PRE_POWER_ON_SLEEP); wl1271_power_on(wl); msleep(WL1271_POWER_ON_SLEEP); wl1271_spi_reset(wl); -- cgit v1.2.3-70-g09d2 From 830fb67b8e37fb03cf703b4e1217fe30ce32d579 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Fri, 11 Dec 2009 15:41:06 +0200 Subject: wl1271: Fix supported rate management Previously, only basic rates were used for data transmission - resulting in reduced transfer rates. This patch takes enables the firmware to take advantage of the full set of data rates supported by the AP. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271.h | 7 +++- drivers/net/wireless/wl12xx/wl1271_acx.c | 24 +++++++++---- drivers/net/wireless/wl12xx/wl1271_acx.h | 5 ++- drivers/net/wireless/wl12xx/wl1271_init.c | 2 +- drivers/net/wireless/wl12xx/wl1271_main.c | 59 +++++++++++++------------------ drivers/net/wireless/wl12xx/wl1271_tx.c | 37 +++++++++++++++++++ 6 files changed, 90 insertions(+), 44 deletions(-) (limited to 'drivers/net/wireless/wl12xx/wl1271.h') diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index c965c4a718f..9290c92522b 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -322,6 +322,10 @@ struct wl1271 { enum wl1271_state state; struct mutex mutex; +#define WL1271_FLAG_STA_RATES_CHANGED (0) +#define WL1271_FLAG_STA_ASSOCIATED (1) + unsigned long flags; + struct wl1271_partition_set part; struct wl1271_chip chip; @@ -394,7 +398,9 @@ struct wl1271 { u16 aid; /* currently configured rate set */ + u32 sta_rate_set; u32 basic_rate_set; + u32 rate_set; /* The current band */ enum ieee80211_band band; @@ -416,7 +422,6 @@ struct wl1271 { /* PSM mode requested */ bool psm_requested; - bool associated; /* retry counter for PSM entries */ u8 psm_entry_retry; diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c index ea6427ad1bc..0ea1a48c45f 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.c +++ b/drivers/net/wireless/wl12xx/wl1271_acx.c @@ -787,10 +787,11 @@ int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats) return 0; } -int wl1271_acx_rate_policies(struct wl1271 *wl, u32 enabled_rates) +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"); @@ -802,12 +803,21 @@ int wl1271_acx_rate_policies(struct wl1271 *wl, u32 enabled_rates) goto out; } - /* configure one default (one-size-fits-all) rate class */ - acx->rate_class_cnt = cpu_to_le32(1); - acx->rate_class[0].enabled_rates = cpu_to_le32(enabled_rates); - acx->rate_class[0].short_retry_limit = c->short_retry_limit; - acx->rate_class[0].long_retry_limit = c->long_retry_limit; - acx->rate_class[0].aflags = c->aflags; + /* configure one basic rate class */ + idx = ACX_TX_BASIC_RATE; + acx->rate_class[idx].enabled_rates = cpu_to_le32(wl->basic_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; + + /* 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) { diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h index 6640ebfb616..b6a473f6065 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.h +++ b/drivers/net/wireless/wl12xx/wl1271_acx.h @@ -826,6 +826,9 @@ struct acx_rate_class { 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; @@ -1058,7 +1061,7 @@ 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, u32 enabled_rates); +int wl1271_acx_rate_policies(struct wl1271 *wl); int wl1271_acx_ac_cfg(struct wl1271 *wl); int wl1271_acx_tid_cfg(struct wl1271 *wl); int wl1271_acx_frag_threshold(struct wl1271 *wl); diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c index c67889dd18f..3b4ed070f43 100644 --- a/drivers/net/wireless/wl12xx/wl1271_init.c +++ b/drivers/net/wireless/wl12xx/wl1271_init.c @@ -284,7 +284,7 @@ int wl1271_hw_init(struct wl1271 *wl) goto out_free_memmap; /* Configure TX rate classes */ - ret = wl1271_acx_rate_policies(wl, CONF_TX_RATE_MASK_BASIC); + ret = wl1271_acx_rate_policies(wl); if (ret < 0) goto out_free_memmap; diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 7a73aaadd04..775b1e82ca8 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -777,7 +777,20 @@ out: 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 */ + spin_lock_irqsave(&wl->wl_lock, flags); + if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) { + wl->sta_rate_set = sta->supp_rates[conf->channel->band]; + set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags); + } + spin_unlock_irqrestore(&wl->wl_lock, flags); + + /* queue the packet */ skb_queue_tail(&wl->tx_queue, skb); /* @@ -1004,7 +1017,6 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) wl->elp = false; wl->psm = 0; wl->psm_entry_retry = 0; - wl->associated = false; wl->tx_queue_stopped = false; wl->power_level = WL1271_DEFAULT_POWER_LEVEL; wl->tx_blocks_available = 0; @@ -1016,6 +1028,9 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) wl->time_offset = 0; wl->session_counter = 0; wl->joined = false; + wl->rate_set = CONF_TX_RATE_MASK_BASIC; + wl->sta_rate_set = 0; + wl->flags = 0; for (i = 0; i < NUM_TX_QUEUES; i++) wl->tx_blocks_freed[i] = 0; @@ -1212,8 +1227,9 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) wl1271_join_channel(wl, channel); if (conf->flags & IEEE80211_CONF_IDLE) { - wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC; - wl1271_acx_rate_policies(wl, CONF_TX_RATE_MASK_BASIC); + wl->rate_set = CONF_TX_RATE_MASK_BASIC; + wl->sta_rate_set = 0; + wl1271_acx_rate_policies(wl); } } @@ -1229,7 +1245,7 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) * If we're not, we'll enter it when joining an SSID, * through the bss_info_changed() hook. */ - if (wl->associated) { + if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) { wl1271_info("psm enabled"); ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE); } @@ -1522,22 +1538,6 @@ out: return ret; } -static u32 wl1271_enabled_rates_get(struct wl1271 *wl, u64 basic_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 (basic_rate_set & 0x1) - enabled_rates |= band->bitrates[bit].hw_value; - basic_rate_set >>= 1; - } - - return enabled_rates; -} - static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, @@ -1616,7 +1616,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ASSOC) { if (bss_conf->assoc) { wl->aid = bss_conf->aid; - wl->associated = true; + set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags); /* * with wl1271, we don't need to update the @@ -1641,7 +1641,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, } } else { /* use defaults when not associated */ - wl->associated = false; + clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags); wl->aid = 0; } @@ -1676,17 +1676,6 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, } } - if (changed & BSS_CHANGED_BASIC_RATES) { - wl->basic_rate_set = wl1271_enabled_rates_get( - wl, bss_conf->basic_rates); - - ret = wl1271_acx_rate_policies(wl, wl->basic_rate_set); - if (ret < 0) { - wl1271_warning("Set rate policies failed %d", ret); - goto out_sleep; - } - } - out_sleep: wl1271_ps_elp_sleep(wl); @@ -1969,14 +1958,16 @@ static int __devinit wl1271_probe(struct spi_device *spi) wl->psm = 0; wl->psm_requested = false; wl->psm_entry_retry = 0; - wl->associated = false; wl->tx_queue_stopped = false; wl->power_level = WL1271_DEFAULT_POWER_LEVEL; wl->basic_rate_set = 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->joined = false; wl->gpio_power = false; + wl->flags = 0; for (i = 0; i < ACX_TX_DESCRIPTORS; i++) wl->tx_frames[i] = NULL; diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c index 00af065c77c..75f53270633 100644 --- a/drivers/net/wireless/wl12xx/wl1271_tx.c +++ b/drivers/net/wireless/wl12xx/wl1271_tx.c @@ -121,6 +121,11 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, 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); @@ -214,18 +219,50 @@ static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb) return ret; } +static 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; + } + + return enabled_rates; +} + void wl1271_tx_work(struct work_struct *work) { struct wl1271 *wl = container_of(work, struct wl1271, tx_work); struct sk_buff *skb; bool woken_up = false; + u32 sta_rates = 0; 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); + } + mutex_lock(&wl->mutex); if (unlikely(wl->state == WL1271_STATE_OFF)) goto out; + /* if rates have changed, re-configure the rate policy */ + if (unlikely(sta_rates)) { + 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); -- cgit v1.2.3-70-g09d2 From 71449f8d7059b69e6e45063997d225d8202221a2 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Fri, 11 Dec 2009 15:41:07 +0200 Subject: wl1271: Change booleans in struct wl1271 into a flags bitmask For cleaner implementation, change the bunch of booleans in the struct wl1271 structure into a flags bitmask. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271.h | 23 +++++--------- drivers/net/wireless/wl12xx/wl1271_cmd.c | 6 ++-- drivers/net/wireless/wl12xx/wl1271_debugfs.c | 13 ++++++-- drivers/net/wireless/wl12xx/wl1271_event.c | 11 +++---- drivers/net/wireless/wl12xx/wl1271_main.c | 45 +++++++++++----------------- drivers/net/wireless/wl12xx/wl1271_ps.c | 15 +++++----- drivers/net/wireless/wl12xx/wl1271_tx.c | 6 ++-- 7 files changed, 55 insertions(+), 64 deletions(-) (limited to 'drivers/net/wireless/wl12xx/wl1271.h') diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 9290c92522b..d0938db043b 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -324,6 +324,13 @@ struct wl1271 { #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_SCANNING (5) +#define WL1271_FLAG_IN_ELP (6) +#define WL1271_FLAG_PSM (7) +#define WL1271_FLAG_PSM_REQUESTED (8) unsigned long flags; struct wl1271_partition_set part; @@ -363,7 +370,6 @@ struct wl1271 { /* Frames scheduled for transmission, not handled yet */ struct sk_buff_head tx_queue; - bool tx_queue_stopped; struct work_struct tx_work; @@ -391,7 +397,6 @@ struct wl1271 { u32 mbox_ptr[2]; /* Are we currently scanning */ - bool scanning; struct wl1271_scan scan; /* Our association ID */ @@ -411,18 +416,9 @@ struct wl1271 { unsigned int rx_config; unsigned int rx_filter; - /* is firmware in elp mode */ - bool elp; - struct completion *elp_compl; struct delayed_work elp_work; - /* we can be in psm, but not in elp, we have to differentiate */ - bool psm; - - /* PSM mode requested */ - bool psm_requested; - /* retry counter for PSM entries */ u8 psm_entry_retry; @@ -441,15 +437,10 @@ struct wl1271 { struct ieee80211_vif *vif; - /* Used for a workaround to send disconnect before rejoining */ - bool joined; - /* Current chipset configuration */ struct conf_drv_settings conf; struct list_head list; - - bool gpio_power; }; int wl1271_plt_start(struct wl1271 *wl); diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index 20f3e67c8e4..b5eb9edc63a 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -655,7 +655,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, channels = wl->hw->wiphy->bands[ieee_band]->channels; n_ch = wl->hw->wiphy->bands[ieee_band]->n_channels; - if (wl->scanning) + if (test_bit(WL1271_FLAG_SCANNING, &wl->flags)) return -EINVAL; params = kzalloc(sizeof(*params), GFP_KERNEL); @@ -730,7 +730,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, wl1271_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params)); - wl->scanning = true; + set_bit(WL1271_FLAG_SCANNING, &wl->flags); if (wl1271_11a_enabled()) { wl->scan.state = band; if (band == WL1271_SCAN_BAND_DUAL) { @@ -748,7 +748,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params), 0); if (ret < 0) { wl1271_error("SCAN failed"); - wl->scanning = false; + clear_bit(WL1271_FLAG_SCANNING, &wl->flags); goto out; } diff --git a/drivers/net/wireless/wl12xx/wl1271_debugfs.c b/drivers/net/wireless/wl12xx/wl1271_debugfs.c index 4eaf40c5756..8d7588ca68f 100644 --- a/drivers/net/wireless/wl12xx/wl1271_debugfs.c +++ b/drivers/net/wireless/wl12xx/wl1271_debugfs.c @@ -241,10 +241,12 @@ 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", wl->gpio_power); + res = scnprintf(buf, sizeof(buf), "%d\n", state); return simple_read_from_buffer(user_buf, count, ppos, buf, res); } @@ -274,8 +276,13 @@ static ssize_t gpio_power_write(struct file *file, goto out; } - wl->set_power(!!value); - wl->gpio_power = !!value; + if (value) { + wl->set_power(true); + set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); + } else { + wl->set_power(false); + clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); + } out: mutex_unlock(&wl->mutex); diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c index 8d0c18dec2c..6ff535d5c7e 100644 --- a/drivers/net/wireless/wl12xx/wl1271_event.c +++ b/drivers/net/wireless/wl12xx/wl1271_event.c @@ -35,7 +35,7 @@ static int wl1271_event_scan_complete(struct wl1271 *wl, wl1271_debug(DEBUG_EVENT, "status: 0x%x", mbox->scheduled_scan_status); - if (wl->scanning) { + if (test_bit(WL1271_FLAG_SCANNING, &wl->flags)) { if (wl->scan.state == WL1271_SCAN_BAND_DUAL) { wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL, size); @@ -43,7 +43,7 @@ static int wl1271_event_scan_complete(struct wl1271 *wl, * to the wl1271_cmd_scan function that we are not * scanning as it checks that. */ - wl->scanning = false; + clear_bit(WL1271_FLAG_SCANNING, &wl->flags); wl1271_cmd_scan(wl, wl->scan.ssid, wl->scan.ssid_len, wl->scan.active, wl->scan.high_prio, @@ -62,7 +62,7 @@ static int wl1271_event_scan_complete(struct wl1271 *wl, mutex_unlock(&wl->mutex); ieee80211_scan_completed(wl->hw, false); mutex_lock(&wl->mutex); - wl->scanning = false; + clear_bit(WL1271_FLAG_SCANNING, &wl->flags); } } return 0; @@ -78,7 +78,7 @@ static int wl1271_event_ps_report(struct wl1271 *wl, switch (mbox->ps_status) { case EVENT_ENTER_POWER_SAVE_FAIL: - if (!wl->psm) { + if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) { wl->psm_entry_retry = 0; break; } @@ -135,7 +135,8 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) * filtering) is enabled. Without PSM, the stack will receive all * beacons and can detect beacon loss by itself. */ - if (vector & BSS_LOSE_EVENT_ID && wl->psm) { + if (vector & BSS_LOSE_EVENT_ID && + test_bit(WL1271_FLAG_PSM, &wl->flags)) { wl1271_debug(DEBUG_EVENT, "BSS_LOSE_EVENT"); /* indicate to the stack, that beacons have been lost */ diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 775b1e82ca8..90a60c1147a 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -378,13 +378,13 @@ static void wl1271_disable_interrupts(struct wl1271 *wl) static void wl1271_power_off(struct wl1271 *wl) { wl->set_power(false); - wl->gpio_power = false; + clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); } static void wl1271_power_on(struct wl1271 *wl) { wl->set_power(true); - wl->gpio_power = true; + set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); } static void wl1271_fw_status(struct wl1271 *wl, @@ -812,7 +812,7 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) * protected. Maybe fix this by removing the stupid * variable altogether and checking the real queue state? */ - wl->tx_queue_stopped = true; + set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags); } return NETDEV_TX_OK; @@ -985,11 +985,10 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) WARN_ON(wl->state != WL1271_STATE_ON); - if (wl->scanning) { + if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) { mutex_unlock(&wl->mutex); ieee80211_scan_completed(wl->hw, true); mutex_lock(&wl->mutex); - wl->scanning = false; } wl->state = WL1271_STATE_OFF; @@ -1014,10 +1013,7 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) wl->band = IEEE80211_BAND_2GHZ; wl->rx_counter = 0; - wl->elp = false; - wl->psm = 0; wl->psm_entry_retry = 0; - wl->tx_queue_stopped = false; wl->power_level = WL1271_DEFAULT_POWER_LEVEL; wl->tx_blocks_available = 0; wl->tx_results_count = 0; @@ -1027,7 +1023,6 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) wl->tx_security_seq_32 = 0; wl->time_offset = 0; wl->session_counter = 0; - wl->joined = false; wl->rate_set = CONF_TX_RATE_MASK_BASIC; wl->sta_rate_set = 0; wl->flags = 0; @@ -1174,7 +1169,7 @@ static int wl1271_join_channel(struct wl1271 *wl, int channel) if (ret < 0) goto out; - wl->joined = true; + set_bit(WL1271_FLAG_JOINED, &wl->flags); out: return ret; @@ -1189,7 +1184,7 @@ static int wl1271_unjoin_channel(struct wl1271 *wl) if (ret < 0) goto out; - wl->joined = false; + clear_bit(WL1271_FLAG_JOINED, &wl->flags); wl->channel = 0; memset(wl->bssid, 0, ETH_ALEN); wl->rx_config = WL1271_DEFAULT_RX_CONFIG; @@ -1221,7 +1216,8 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) goto out; if (changed & IEEE80211_CONF_CHANGE_IDLE) { - if (conf->flags & IEEE80211_CONF_IDLE && wl->joined) + if (conf->flags & IEEE80211_CONF_IDLE && + test_bit(WL1271_FLAG_JOINED, &wl->flags)) wl1271_unjoin_channel(wl); else wl1271_join_channel(wl, channel); @@ -1234,11 +1230,12 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) } /* if the channel changes while joined, join again */ - if (channel != wl->channel && wl->joined) + if (channel != wl->channel && test_bit(WL1271_FLAG_JOINED, &wl->flags)) wl1271_join_channel(wl, channel); - if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) { - wl->psm_requested = true; + 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. @@ -1250,12 +1247,12 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE); } } else if (!(conf->flags & IEEE80211_CONF_PS) && - wl->psm_requested) { + test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) { wl1271_info("psm disabled"); - wl->psm_requested = false; + clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags); - if (wl->psm) + if (test_bit(WL1271_FLAG_PSM, &wl->flags)) ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE); } @@ -1574,7 +1571,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, wl1271_warning("cmd join failed %d", ret); goto out_sleep; } - wl->joined = true; + set_bit(WL1271_FLAG_JOINED, &wl->flags); } if (wl->bss_type == BSS_TYPE_IBSS) { @@ -1633,7 +1630,8 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, goto out_sleep; /* If we want to go in PSM but we're not there yet */ - if (wl->psm_requested && !wl->psm) { + 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); if (ret < 0) @@ -1949,24 +1947,17 @@ static int __devinit wl1271_probe(struct spi_device *spi) INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work); wl->channel = WL1271_DEFAULT_CHANNEL; - wl->scanning = false; wl->default_key = 0; wl->rx_counter = 0; wl->rx_config = WL1271_DEFAULT_RX_CONFIG; wl->rx_filter = WL1271_DEFAULT_RX_FILTER; - wl->elp = false; - wl->psm = 0; - wl->psm_requested = false; wl->psm_entry_retry = 0; - wl->tx_queue_stopped = false; wl->power_level = WL1271_DEFAULT_POWER_LEVEL; wl->basic_rate_set = 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->joined = false; - wl->gpio_power = false; wl->flags = 0; for (i = 0; i < ACX_TX_DESCRIPTORS; i++) diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.c b/drivers/net/wireless/wl12xx/wl1271_ps.c index 507cd91d7ee..e407790f677 100644 --- a/drivers/net/wireless/wl12xx/wl1271_ps.c +++ b/drivers/net/wireless/wl12xx/wl1271_ps.c @@ -39,12 +39,13 @@ void wl1271_elp_work(struct work_struct *work) mutex_lock(&wl->mutex); - if (wl->elp || !wl->psm) + if (test_bit(WL1271_FLAG_IN_ELP, &wl->flags) || + !test_bit(WL1271_FLAG_PSM, &wl->flags)) goto out; wl1271_debug(DEBUG_PSM, "chip to elp"); wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); - wl->elp = true; + set_bit(WL1271_FLAG_IN_ELP, &wl->flags); out: mutex_unlock(&wl->mutex); @@ -55,7 +56,7 @@ out: /* Routines to toggle sleep mode while in ELP */ void wl1271_ps_elp_sleep(struct wl1271 *wl) { - if (wl->psm) { + if (test_bit(WL1271_FLAG_PSM, &wl->flags)) { cancel_delayed_work(&wl->elp_work); ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, msecs_to_jiffies(ELP_ENTRY_DELAY)); @@ -70,7 +71,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake) u32 start_time = jiffies; bool pending = false; - if (!wl->elp) + if (!test_bit(WL1271_FLAG_IN_ELP, &wl->flags)) return 0; wl1271_debug(DEBUG_PSM, "waking up chip from elp"); @@ -101,7 +102,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake) } } - wl->elp = false; + clear_bit(WL1271_FLAG_IN_ELP, &wl->flags); wl1271_debug(DEBUG_PSM, "wakeup time: %u ms", jiffies_to_msecs(jiffies - start_time)); @@ -143,7 +144,7 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode) if (ret < 0) return ret; - wl->psm = 1; + set_bit(WL1271_FLAG_PSM, &wl->flags); break; case STATION_ACTIVE_MODE: default: @@ -166,7 +167,7 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode) if (ret < 0) return ret; - wl->psm = 0; + clear_bit(WL1271_FLAG_PSM, &wl->flags); break; } diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c index 75f53270633..a288cc317d7 100644 --- a/drivers/net/wireless/wl12xx/wl1271_tx.c +++ b/drivers/net/wireless/wl12xx/wl1271_tx.c @@ -277,18 +277,18 @@ void wl1271_tx_work(struct work_struct *work) wl1271_debug(DEBUG_TX, "tx_work: fw buffer full, " "stop queues"); ieee80211_stop_queues(wl->hw); - wl->tx_queue_stopped = true; + set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags); skb_queue_head(&wl->tx_queue, skb); goto out; } else if (ret < 0) { dev_kfree_skb(skb); goto out; - } else if (wl->tx_queue_stopped) { + } else if (test_and_clear_bit(WL1271_FLAG_TX_QUEUE_STOPPED, + &wl->flags)) { /* firmware buffer has space, restart queues */ wl1271_debug(DEBUG_TX, "complete_packet: waking queues"); ieee80211_wake_queues(wl->hw); - wl->tx_queue_stopped = false; } } -- cgit v1.2.3-70-g09d2 From 152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Thu, 18 Feb 2010 13:25:42 +0200 Subject: wl1271: Use NVS INI file configuration Replace the hardcoded general and radio parameter configuration in the driver with configuration taken from the NVS file directly. Also remove the driver dependency to the structures with the parameter data. Signed-off-by: Juuso Oikarinen Reviewed-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271.h | 32 ++++++- drivers/net/wireless/wl12xx/wl1271_boot.c | 29 +++--- drivers/net/wireless/wl12xx/wl1271_cmd.c | 117 ++++-------------------- drivers/net/wireless/wl12xx/wl1271_cmd.h | 86 +++--------------- drivers/net/wireless/wl12xx/wl1271_conf.h | 144 +----------------------------- drivers/net/wireless/wl12xx/wl1271_main.c | 101 ++------------------- 6 files changed, 77 insertions(+), 432 deletions(-) (limited to 'drivers/net/wireless/wl12xx/wl1271.h') diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index d0938db043b..b3a3402593d 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -109,7 +109,33 @@ enum { #define WL1271_FW_NAME "wl1271-fw.bin" #define WL1271_NVS_NAME "wl1271-nvs.bin" -#define WL1271_NVS_LEN 468 + +/* NVS data structure */ +#define WL1271_NVS_SECTION_SIZE 468 + +#define WL1271_NVS_GENERAL_PARAMS_SIZE 57 +#define WL1271_NVS_GENERAL_PARAMS_SIZE_PADDED \ + (WL1271_NVS_GENERAL_PARAMS_SIZE + 1) +#define WL1271_NVS_STAT_RADIO_PARAMS_SIZE 17 +#define WL1271_NVS_STAT_RADIO_PARAMS_SIZE_PADDED \ + (WL1271_NVS_STAT_RADIO_PARAMS_SIZE + 1) +#define WL1271_NVS_DYN_RADIO_PARAMS_SIZE 65 +#define WL1271_NVS_DYN_RADIO_PARAMS_SIZE_PADDED \ + (WL1271_NVS_DYN_RADIO_PARAMS_SIZE + 1) +#define WL1271_NVS_FEM_COUNT 2 +#define WL1271_NVS_INI_SPARE_SIZE 124 + +struct wl1271_nvs_file { + /* NVS section */ + u8 nvs[WL1271_NVS_SECTION_SIZE]; + + /* INI section */ + u8 general_params[WL1271_NVS_GENERAL_PARAMS_SIZE_PADDED]; + u8 stat_radio_params[WL1271_NVS_STAT_RADIO_PARAMS_SIZE_PADDED]; + u8 dyn_radio_params[WL1271_NVS_FEM_COUNT] + [WL1271_NVS_DYN_RADIO_PARAMS_SIZE_PADDED]; + u8 ini_spare[WL1271_NVS_INI_SPARE_SIZE]; +} __attribute__ ((packed)); /* * Enable/disable 802.11a support for WL1273 @@ -342,8 +368,7 @@ struct wl1271 { u8 *fw; size_t fw_len; - u8 *nvs; - size_t nvs_len; + struct wl1271_nvs_file *nvs; u8 bssid[ETH_ALEN]; u8 mac_addr[ETH_ALEN]; @@ -461,6 +486,7 @@ int wl1271_plt_stop(struct wl1271 *wl); static inline bool wl1271_11a_enabled(void) { + /* FIXME: this could be determined based on the NVS-INI file */ #ifdef WL1271_80211A_ENABLED return true; #else diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c index e803b876f3f..bc3fe0275ca 100644 --- a/drivers/net/wireless/wl12xx/wl1271_boot.c +++ b/drivers/net/wireless/wl12xx/wl1271_boot.c @@ -219,29 +219,22 @@ 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, *nvs_aligned; + u8 *nvs_ptr, *nvs_aligned; - nvs = wl->nvs; - if (nvs == NULL) + if (wl->nvs == NULL) return -ENODEV; - if (wl->nvs_len < WL1271_NVS_LEN) - return -EINVAL; - - nvs_ptr = nvs; - /* only the first part of the NVS needs to be uploaded */ - nvs_len = WL1271_NVS_LEN; - - /* FIXME: read init settings from the remaining part of the NVS */ + nvs_len = sizeof(wl->nvs->nvs); + nvs_ptr = (u8 *)wl->nvs->nvs; /* Update the device MAC address into the nvs */ - nvs[11] = wl->mac_addr[0]; - nvs[10] = wl->mac_addr[1]; - nvs[6] = wl->mac_addr[2]; - nvs[5] = wl->mac_addr[3]; - nvs[4] = wl->mac_addr[4]; - nvs[3] = wl->mac_addr[5]; + 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: @@ -283,7 +276,7 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) * is 7 bytes further. */ nvs_ptr += 7; - nvs_len -= nvs_ptr - nvs; + nvs_len -= nvs_ptr - (u8 *)wl->nvs->nvs; nvs_len = ALIGN(nvs_len, 4); /* FIXME: The driver sets the partition here, but this is not needed, diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index dd2b5f0540a..54b5124fc0c 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -191,43 +191,19 @@ static int wl1271_cmd_cal(struct wl1271 *wl) int wl1271_cmd_general_parms(struct wl1271 *wl) { struct wl1271_general_parms_cmd *gen_parms; - struct conf_general_parms *g = &wl->conf.init.genparam; 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; - gen_parms->ref_clk = g->ref_clk; - gen_parms->settling_time = g->settling_time; - gen_parms->clk_valid_on_wakeup = g->clk_valid_on_wakeup; - gen_parms->dc2dcmode = g->dc2dcmode; - gen_parms->single_dual_band = g->single_dual_band; - gen_parms->tx_bip_fem_autodetect = g->tx_bip_fem_autodetect; - gen_parms->tx_bip_fem_manufacturer = g->tx_bip_fem_manufacturer; - gen_parms->settings = g->settings; - - gen_parms->sr_state = g->sr_state; - - memcpy(gen_parms->srf1, - g->srf1, - CONF_MAX_SMART_REFLEX_PARAMS); - memcpy(gen_parms->srf2, - g->srf2, - CONF_MAX_SMART_REFLEX_PARAMS); - memcpy(gen_parms->srf3, - g->srf3, - CONF_MAX_SMART_REFLEX_PARAMS); - memcpy(gen_parms->sr_debug_table, - g->sr_debug_table, - CONF_MAX_SMART_REFLEX_PARAMS); - - gen_parms->sr_sen_n_p = g->sr_sen_n_p; - gen_parms->sr_sen_n_p_gain = g->sr_sen_n_p_gain; - gen_parms->sr_sen_nrn = g->sr_sen_nrn; - gen_parms->sr_sen_prn = g->sr_sen_prn; + memcpy(gen_parms->params, wl->nvs->general_params, + WL1271_NVS_GENERAL_PARAMS_SIZE); ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), 0); if (ret < 0) @@ -240,8 +216,11 @@ int wl1271_cmd_general_parms(struct wl1271 *wl) int wl1271_cmd_radio_parms(struct wl1271 *wl) { struct wl1271_radio_parms_cmd *radio_parms; - struct conf_radio_parms *r = &wl->conf.init.radioparam; - int i, ret; + struct conf_radio_parms *rparam = &wl->conf.init.radioparam; + int ret; + + if (!wl->nvs) + return -ENODEV; radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL); if (!radio_parms) @@ -249,73 +228,13 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl) radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM; - /* Static radio parameters */ - radio_parms->rx_trace_loss = r->rx_trace_loss; - radio_parms->tx_trace_loss = r->tx_trace_loss; - memcpy(radio_parms->rx_rssi_and_proc_compens, - r->rx_rssi_and_proc_compens, - CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE); - - memcpy(radio_parms->rx_trace_loss_5, r->rx_trace_loss_5, - CONF_NUMBER_OF_SUB_BANDS_5); - memcpy(radio_parms->tx_trace_loss_5, r->tx_trace_loss_5, - CONF_NUMBER_OF_SUB_BANDS_5); - memcpy(radio_parms->rx_rssi_and_proc_compens_5, - r->rx_rssi_and_proc_compens_5, - CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE); - - /* Dynamic radio parameters */ - radio_parms->tx_ref_pd_voltage = cpu_to_le16(r->tx_ref_pd_voltage); - radio_parms->tx_ref_power = r->tx_ref_power; - radio_parms->tx_offset_db = r->tx_offset_db; - - memcpy(radio_parms->tx_rate_limits_normal, r->tx_rate_limits_normal, - CONF_NUMBER_OF_RATE_GROUPS); - memcpy(radio_parms->tx_rate_limits_degraded, r->tx_rate_limits_degraded, - CONF_NUMBER_OF_RATE_GROUPS); - memcpy(radio_parms->tx_rate_limits_extreme, r->tx_rate_limits_extreme, - CONF_NUMBER_OF_RATE_GROUPS); - - memcpy(radio_parms->tx_channel_limits_11b, r->tx_channel_limits_11b, - CONF_NUMBER_OF_CHANNELS_2_4); - memcpy(radio_parms->tx_channel_limits_ofdm, r->tx_channel_limits_ofdm, - CONF_NUMBER_OF_CHANNELS_2_4); - memcpy(radio_parms->tx_pdv_rate_offsets, r->tx_pdv_rate_offsets, - CONF_NUMBER_OF_RATE_GROUPS); - memcpy(radio_parms->tx_ibias, r->tx_ibias, CONF_NUMBER_OF_RATE_GROUPS); - - radio_parms->rx_fem_insertion_loss = r->rx_fem_insertion_loss; - radio_parms->degraded_low_to_normal_threshold = - r->degraded_low_to_normal_threshold; - radio_parms->degraded_normal_to_high_threshold = - r->degraded_normal_to_high_threshold; - - - for (i = 0; i < CONF_NUMBER_OF_SUB_BANDS_5; i++) - radio_parms->tx_ref_pd_voltage_5[i] = - cpu_to_le16(r->tx_ref_pd_voltage_5[i]); - memcpy(radio_parms->tx_ref_power_5, r->tx_ref_power_5, - CONF_NUMBER_OF_SUB_BANDS_5); - memcpy(radio_parms->tx_offset_db_5, r->tx_offset_db_5, - CONF_NUMBER_OF_SUB_BANDS_5); - memcpy(radio_parms->tx_rate_limits_normal_5, - r->tx_rate_limits_normal_5, CONF_NUMBER_OF_RATE_GROUPS); - memcpy(radio_parms->tx_rate_limits_degraded_5, - r->tx_rate_limits_degraded_5, CONF_NUMBER_OF_RATE_GROUPS); - memcpy(radio_parms->tx_rate_limits_extreme_5, - r->tx_rate_limits_extreme_5, CONF_NUMBER_OF_RATE_GROUPS); - memcpy(radio_parms->tx_channel_limits_ofdm_5, - r->tx_channel_limits_ofdm_5, CONF_NUMBER_OF_CHANNELS_5); - memcpy(radio_parms->tx_pdv_rate_offsets_5, r->tx_pdv_rate_offsets_5, - CONF_NUMBER_OF_RATE_GROUPS); - memcpy(radio_parms->tx_ibias_5, r->tx_ibias_5, - CONF_NUMBER_OF_RATE_GROUPS); - memcpy(radio_parms->rx_fem_insertion_loss_5, - r->rx_fem_insertion_loss_5, CONF_NUMBER_OF_SUB_BANDS_5); - radio_parms->degraded_low_to_normal_threshold_5 = - r->degraded_low_to_normal_threshold_5; - radio_parms->degraded_normal_to_high_threshold_5 = - r->degraded_normal_to_high_threshold_5; + memcpy(radio_parms->stat_radio_params, wl->nvs->stat_radio_params, + WL1271_NVS_STAT_RADIO_PARAMS_SIZE); + memcpy(radio_parms->dyn_radio_params, + wl->nvs->dyn_radio_params[rparam->fem], + WL1271_NVS_DYN_RADIO_PARAMS_SIZE); + + /* FIXME: current NVS is missing 5GHz parameters */ wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ", radio_parms, sizeof(*radio_parms)); @@ -1022,7 +941,7 @@ int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_warning("could not set keys"); - goto out; + goto out; } out: diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/wl1271_cmd.h index ba433f423c8..2dc06c73532 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h @@ -428,90 +428,24 @@ struct wl1271_general_parms_cmd { struct wl1271_cmd_test_header test; - u8 ref_clk; - u8 settling_time; - u8 clk_valid_on_wakeup; - u8 dc2dcmode; - u8 single_dual_band; - - u8 tx_bip_fem_autodetect; - u8 tx_bip_fem_manufacturer; - u8 settings; - - u8 sr_state; - - s8 srf1[CONF_MAX_SMART_REFLEX_PARAMS]; - s8 srf2[CONF_MAX_SMART_REFLEX_PARAMS]; - s8 srf3[CONF_MAX_SMART_REFLEX_PARAMS]; - - s8 sr_debug_table[CONF_MAX_SMART_REFLEX_PARAMS]; - - u8 sr_sen_n_p; - u8 sr_sen_n_p_gain; - u8 sr_sen_nrn; - u8 sr_sen_prn; - - u8 padding[3]; + u8 params[WL1271_NVS_GENERAL_PARAMS_SIZE]; + s8 reserved[23]; } __attribute__ ((packed)); +#define WL1271_STAT_RADIO_PARAMS_5_SIZE 29 +#define WL1271_DYN_RADIO_PARAMS_5_SIZE 104 + struct wl1271_radio_parms_cmd { struct wl1271_cmd_header header; struct wl1271_cmd_test_header test; - /* Static radio parameters */ - /* 2.4GHz */ - u8 rx_trace_loss; - u8 tx_trace_loss; - s8 rx_rssi_and_proc_compens[CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE]; - - /* 5GHz */ - u8 rx_trace_loss_5[CONF_NUMBER_OF_SUB_BANDS_5]; - u8 tx_trace_loss_5[CONF_NUMBER_OF_SUB_BANDS_5]; - s8 rx_rssi_and_proc_compens_5[CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE]; - - /* Dynamic radio parameters */ - /* 2.4GHz */ - __le16 tx_ref_pd_voltage; - u8 tx_ref_power; - s8 tx_offset_db; - - s8 tx_rate_limits_normal[CONF_NUMBER_OF_RATE_GROUPS]; - s8 tx_rate_limits_degraded[CONF_NUMBER_OF_RATE_GROUPS]; - s8 tx_rate_limits_extreme[CONF_NUMBER_OF_RATE_GROUPS]; + u8 stat_radio_params[WL1271_NVS_STAT_RADIO_PARAMS_SIZE]; + u8 stat_radio_params_5[WL1271_STAT_RADIO_PARAMS_5_SIZE]; - s8 tx_channel_limits_11b[CONF_NUMBER_OF_CHANNELS_2_4]; - s8 tx_channel_limits_ofdm[CONF_NUMBER_OF_CHANNELS_2_4]; - s8 tx_pdv_rate_offsets[CONF_NUMBER_OF_RATE_GROUPS]; - - u8 tx_ibias[CONF_NUMBER_OF_RATE_GROUPS]; - u8 rx_fem_insertion_loss; - - u8 degraded_low_to_normal_threshold; - u8 degraded_normal_to_high_threshold; - - u8 padding1; /* our own padding, not in ref driver */ - - /* 5GHz */ - __le16 tx_ref_pd_voltage_5[CONF_NUMBER_OF_SUB_BANDS_5]; - u8 tx_ref_power_5[CONF_NUMBER_OF_SUB_BANDS_5]; - s8 tx_offset_db_5[CONF_NUMBER_OF_SUB_BANDS_5]; - - s8 tx_rate_limits_normal_5[CONF_NUMBER_OF_RATE_GROUPS]; - s8 tx_rate_limits_degraded_5[CONF_NUMBER_OF_RATE_GROUPS]; - s8 tx_rate_limits_extreme_5[CONF_NUMBER_OF_RATE_GROUPS]; - - s8 tx_channel_limits_ofdm_5[CONF_NUMBER_OF_CHANNELS_5]; - s8 tx_pdv_rate_offsets_5[CONF_NUMBER_OF_RATE_GROUPS]; - - /* FIXME: this is inconsistent with the types for 2.4GHz */ - s8 tx_ibias_5[CONF_NUMBER_OF_RATE_GROUPS]; - s8 rx_fem_insertion_loss_5[CONF_NUMBER_OF_SUB_BANDS_5]; - - u8 degraded_low_to_normal_threshold_5; - u8 degraded_normal_to_high_threshold_5; - - u8 padding2[2]; + u8 dyn_radio_params[WL1271_NVS_DYN_RADIO_PARAMS_SIZE]; + u8 reserved; + u8 dyn_radio_params_5[WL1271_DYN_RADIO_PARAMS_5_SIZE]; } __attribute__ ((packed)); struct wl1271_cmd_cal_channel_tune { diff --git a/drivers/net/wireless/wl12xx/wl1271_conf.h b/drivers/net/wireless/wl12xx/wl1271_conf.h index 1993d63c214..6f9e75cc564 100644 --- a/drivers/net/wireless/wl12xx/wl1271_conf.h +++ b/drivers/net/wireless/wl12xx/wl1271_conf.h @@ -735,81 +735,6 @@ enum single_dual_band_enum { CONF_DUAL_BAND }; - -#define CONF_MAX_SMART_REFLEX_PARAMS 16 - -struct conf_general_parms { - /* - * RF Reference Clock type / speed - * - * Range: CONF_REF_CLK_* - */ - u8 ref_clk; - - /* - * Settling time of the reference clock after boot. - * - * Range: u8 - */ - u8 settling_time; - - /* - * Flag defining whether clock is valid on wakeup. - * - * Range: 0 - not valid on wakeup, 1 - valid on wakeup - */ - u8 clk_valid_on_wakeup; - - /* - * DC-to-DC mode. - * - * Range: Unknown - */ - u8 dc2dcmode; - - /* - * Flag defining whether used as single or dual-band. - * - * Range: CONF_SINGLE_BAND, CONF_DUAL_BAND - */ - u8 single_dual_band; - - /* - * TX bip fem autodetect flag. - * - * Range: Unknown - */ - u8 tx_bip_fem_autodetect; - - /* - * TX bip gem manufacturer. - * - * Range: Unknown - */ - u8 tx_bip_fem_manufacturer; - - /* - * Settings flags. - * - * Range: Unknown - */ - u8 settings; - - /* Smart reflex settings */ - u8 sr_state; - - s8 srf1[CONF_MAX_SMART_REFLEX_PARAMS]; - s8 srf2[CONF_MAX_SMART_REFLEX_PARAMS]; - s8 srf3[CONF_MAX_SMART_REFLEX_PARAMS]; - - s8 sr_debug_table[CONF_MAX_SMART_REFLEX_PARAMS]; - - u8 sr_sen_n_p; - u8 sr_sen_n_p_gain; - u8 sr_sen_nrn; - u8 sr_sen_prn; -}; - #define CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE 15 #define CONF_NUMBER_OF_SUB_BANDS_5 7 #define CONF_NUMBER_OF_RATE_GROUPS 6 @@ -818,77 +743,14 @@ struct conf_general_parms { struct conf_radio_parms { /* - * Static radio parameters for 2.4GHz - * - * Range: unknown - */ - u8 rx_trace_loss; - u8 tx_trace_loss; - s8 rx_rssi_and_proc_compens[CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE]; - - /* - * Static radio parameters for 5GHz - * - * Range: unknown - */ - u8 rx_trace_loss_5[CONF_NUMBER_OF_SUB_BANDS_5]; - u8 tx_trace_loss_5[CONF_NUMBER_OF_SUB_BANDS_5]; - s8 rx_rssi_and_proc_compens_5[CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE]; - - /* - * Dynamic radio parameters for 2.4GHz + * FEM parameter set to use * - * Range: unknown + * Range: 0 or 1 */ - u16 tx_ref_pd_voltage; - u8 tx_ref_power; - s8 tx_offset_db; - - s8 tx_rate_limits_normal[CONF_NUMBER_OF_RATE_GROUPS]; - s8 tx_rate_limits_degraded[CONF_NUMBER_OF_RATE_GROUPS]; - s8 tx_rate_limits_extreme[CONF_NUMBER_OF_RATE_GROUPS]; - - s8 tx_channel_limits_11b[CONF_NUMBER_OF_CHANNELS_2_4]; - s8 tx_channel_limits_ofdm[CONF_NUMBER_OF_CHANNELS_2_4]; - s8 tx_pdv_rate_offsets[CONF_NUMBER_OF_RATE_GROUPS]; - - u8 tx_ibias[CONF_NUMBER_OF_RATE_GROUPS]; - u8 rx_fem_insertion_loss; - - u8 degraded_low_to_normal_threshold; - u8 degraded_normal_to_high_threshold; - - - /* - * Dynamic radio parameters for 5GHz - * - * Range: unknown - */ - u16 tx_ref_pd_voltage_5[CONF_NUMBER_OF_SUB_BANDS_5]; - u8 tx_ref_power_5[CONF_NUMBER_OF_SUB_BANDS_5]; - s8 tx_offset_db_5[CONF_NUMBER_OF_SUB_BANDS_5]; - - s8 tx_rate_limits_normal_5[CONF_NUMBER_OF_RATE_GROUPS]; - s8 tx_rate_limits_degraded_5[CONF_NUMBER_OF_RATE_GROUPS]; - s8 tx_rate_limits_extreme_5[CONF_NUMBER_OF_RATE_GROUPS]; - - s8 tx_channel_limits_ofdm_5[CONF_NUMBER_OF_CHANNELS_5]; - s8 tx_pdv_rate_offsets_5[CONF_NUMBER_OF_RATE_GROUPS]; - - /* FIXME: this is inconsistent with the types for 2.4GHz */ - s8 tx_ibias_5[CONF_NUMBER_OF_RATE_GROUPS]; - s8 rx_fem_insertion_loss_5[CONF_NUMBER_OF_SUB_BANDS_5]; - - u8 degraded_low_to_normal_threshold_5; - u8 degraded_normal_to_high_threshold_5; + u8 fem; }; struct conf_init_settings { - /* - * Configure general parameters. - */ - struct conf_general_parms genparam; - /* * Configure radio parameters. */ diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 6f7a7d94635..282c2bbfec8 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -229,93 +229,8 @@ static struct conf_drv_settings default_conf = { .psm_entry_retries = 3 }, .init = { - .genparam = { - .ref_clk = CONF_REF_CLK_38_4_E, - .settling_time = 5, - .clk_valid_on_wakeup = 0, - .dc2dcmode = 0, - .single_dual_band = CONF_SINGLE_BAND, - .tx_bip_fem_autodetect = 1, - .tx_bip_fem_manufacturer = 1, - .settings = 1, - .sr_state = 1, - .srf1 = { 0x07, 0x03, 0x18, 0x10, 0x05, 0xfb, 0xf0, - 0xe8, 0, 0, 0, 0, 0, 0, 0, 0 }, - .srf2 = { 0x07, 0x03, 0x18, 0x10, 0x05, 0xfb, 0xf0, - 0xe8, 0, 0, 0, 0, 0, 0, 0, 0 }, - .srf3 = { 0x07, 0x03, 0x18, 0x10, 0x05, 0xfb, 0xf0, - 0xe8, 0, 0, 0, 0, 0, 0, 0, 0 }, - .sr_debug_table = { 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 }, - .sr_sen_n_p = 0, - .sr_sen_n_p_gain = 0, - .sr_sen_nrn = 0, - .sr_sen_prn = 0, - }, .radioparam = { - .rx_trace_loss = 0x24, - .tx_trace_loss = 0x0, - .rx_rssi_and_proc_compens = { - 0xec, 0xf6, 0x00, 0x0c, 0x18, 0xf8, - 0xfc, 0x00, 0x80, 0x10, 0xf0, 0xf8, - 0x00, 0x0a, 0x14 }, - .rx_trace_loss_5 = { 0, 0, 0, 0, 0, 0, 0 }, - .tx_trace_loss_5 = { 0, 0, 0, 0, 0, 0, 0 }, - .rx_rssi_and_proc_compens_5 = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00 }, - .tx_ref_pd_voltage = 0x1a9, - .tx_ref_power = 0x80, - .tx_offset_db = 0x0, - .tx_rate_limits_normal = { - 0x1d, 0x1f, 0x24, 0x28, 0x28, 0x29 }, - .tx_rate_limits_degraded = { - 0x19, 0x1f, 0x22, 0x23, 0x27, 0x28 }, - .tx_rate_limits_extreme = { - 0x19, 0x1c, 0x1e, 0x20, 0x24, 0x25 }, - .tx_channel_limits_11b = { - 0x22, 0x50, 0x50, 0x50, 0x50, 0x50, - 0x50, 0x50, 0x50, 0x50, 0x22, 0x50, - 0x22, 0x50 }, - .tx_channel_limits_ofdm = { - 0x20, 0x50, 0x50, 0x50, 0x50, 0x50, - 0x50, 0x50, 0x50, 0x50, 0x20, 0x50, - 0x20, 0x50 }, - .tx_pdv_rate_offsets = { - 0x07, 0x08, 0x04, 0x02, 0x02, 0x00 }, - .tx_ibias = { - 0x11, 0x11, 0x15, 0x11, 0x15, 0x0f }, - .rx_fem_insertion_loss = 0x0e, - .degraded_low_to_normal_threshold = 0x1e, - .degraded_normal_to_high_threshold = 0x2d, - .tx_ref_pd_voltage_5 = { - 0x0190, 0x01a4, 0x01c3, 0x01d8, - 0x020a, 0x021c }, - .tx_ref_power_5 = { - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }, - .tx_offset_db_5 = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, - .tx_rate_limits_normal_5 = { - 0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 }, - .tx_rate_limits_degraded_5 = { - 0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 }, - .tx_rate_limits_extreme_5 = { - 0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 }, - .tx_channel_limits_ofdm_5 = { - 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, - 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, - 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, - 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, - 0x50, 0x50, 0x50 }, - .tx_pdv_rate_offsets_5 = { - 0x01, 0x02, 0x02, 0x02, 0x02, 0x00 }, - .tx_ibias_5 = { - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 }, - .rx_fem_insertion_loss_5 = { - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 }, - .degraded_low_to_normal_threshold_5 = 0x00, - .degraded_normal_to_high_threshold_5 = 0x00 + .fem = 1, } }, .itrim = { @@ -345,9 +260,6 @@ static void wl1271_conf_init(struct wl1271 *wl) /* apply driver default configuration */ memcpy(&wl->conf, &default_conf, sizeof(default_conf)); - - if (wl1271_11a_enabled()) - wl->conf.init.genparam.single_dual_band = CONF_DUAL_BAND; } @@ -567,15 +479,14 @@ static int wl1271_fetch_nvs(struct wl1271 *wl) return ret; } - if (fw->size % 4) { - wl1271_error("nvs size is not multiple of 32 bits: %zu", - fw->size); + if (fw->size != sizeof(struct wl1271_nvs_file)) { + wl1271_error("nvs size is not as expected: %zu != %zu", + fw->size, sizeof(struct wl1271_nvs_file)); ret = -EILSEQ; goto out; } - wl->nvs_len = fw->size; - wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL); + wl->nvs = kmalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL); if (!wl->nvs) { wl1271_error("could not allocate memory for the nvs file"); @@ -583,7 +494,7 @@ static int wl1271_fetch_nvs(struct wl1271 *wl) goto out; } - memcpy(wl->nvs, fw->data, wl->nvs_len); + memcpy(wl->nvs, fw->data, sizeof(struct wl1271_nvs_file)); ret = 0; -- cgit v1.2.3-70-g09d2 From c8c90873520ef4c201cfd03b4892ca8bbf551e2e Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Thu, 18 Feb 2010 13:25:53 +0200 Subject: wl1271: add testmode support Testmode will be used to send PLT (Production Line Testing) commands from user space. Signed-off-by: Kalle Valo Reviewed-by: Juuso Oikarinen Signed-off-by: Juuso Oikarinen Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/Makefile | 1 + drivers/net/wireless/wl12xx/wl1271.h | 2 +- drivers/net/wireless/wl12xx/wl1271_main.c | 2 + drivers/net/wireless/wl12xx/wl1271_testmode.c | 283 ++++++++++++++++++++++++++ drivers/net/wireless/wl12xx/wl1271_testmode.h | 31 +++ 5 files changed, 318 insertions(+), 1 deletion(-) create mode 100644 drivers/net/wireless/wl12xx/wl1271_testmode.c create mode 100644 drivers/net/wireless/wl12xx/wl1271_testmode.h (limited to 'drivers/net/wireless/wl12xx/wl1271.h') diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile index 62e37ad01cc..d089b5d6a51 100644 --- a/drivers/net/wireless/wl12xx/Makefile +++ b/drivers/net/wireless/wl12xx/Makefile @@ -11,4 +11,5 @@ wl1271-objs = wl1271_main.o wl1271_spi.o wl1271_cmd.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-$(CONFIG_NL80211_TESTMODE) += wl1271_testmode.o obj-$(CONFIG_WL1271) += wl1271.o diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index b3a3402593d..97ea5096bc8 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -43,7 +43,7 @@ enum { DEBUG_SPI = BIT(1), DEBUG_BOOT = BIT(2), DEBUG_MAILBOX = BIT(3), - DEBUG_NETLINK = BIT(4), + DEBUG_TESTMODE = BIT(4), DEBUG_EVENT = BIT(5), DEBUG_TX = BIT(6), DEBUG_RX = BIT(7), diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index fb1e6a8088d..aa8f79c4c98 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -46,6 +46,7 @@ #include "wl1271_debugfs.h" #include "wl1271_cmd.h" #include "wl1271_boot.h" +#include "wl1271_testmode.h" #define WL1271_BOOT_RETRIES 3 @@ -1955,6 +1956,7 @@ static const struct ieee80211_ops wl1271_ops = { .bss_info_changed = wl1271_op_bss_info_changed, .set_rts_threshold = wl1271_op_set_rts_threshold, .conf_tx = wl1271_op_conf_tx, + CFG80211_TESTMODE_CMD(wl1271_tm_cmd) }; static int wl1271_register_hw(struct wl1271 *wl) diff --git a/drivers/net/wireless/wl12xx/wl1271_testmode.c b/drivers/net/wireless/wl12xx/wl1271_testmode.c new file mode 100644 index 00000000000..3919102e942 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_testmode.c @@ -0,0 +1,283 @@ +/* + * 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 "wl1271.h" +#include "wl1271_spi.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_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]); + + if (len != sizeof(struct wl1271_nvs_file)) { + wl1271_error("nvs size is not as expected: %zu != %zu", + len, sizeof(struct wl1271_nvs_file)); + return -EMSGSIZE; + } + + mutex_lock(&wl->mutex); + + kfree(wl->nvs); + + wl->nvs = kmalloc(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); + + 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; +} + +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); + default: + return -EOPNOTSUPP; + } +} diff --git a/drivers/net/wireless/wl12xx/wl1271_testmode.h b/drivers/net/wireless/wl12xx/wl1271_testmode.h new file mode 100644 index 00000000000..c196d28f9d9 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_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 __WL1271_TESTMODE_H__ +#define __WL1271_TESTMODE_H__ + +#include + +int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len); + +#endif /* __WL1271_TESTMODE_H__ */ -- cgit v1.2.3-70-g09d2