From 203c903cbfbdf23bbb3020b9344dd1ffabcfcb53 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Mon, 25 Oct 2010 11:17:44 +0200 Subject: wl12xx: AP mode - add AP specific event Add STA-remove completion event. Unmask it during boot if operating in AP-mode. Ignore unrelated events in AP-mode. Signed-off-by: Arik Nemtsov Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/boot.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net/wireless/wl12xx/boot.c') diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c index 4df04f84d7f1..b504367f281f 100644 --- a/drivers/net/wireless/wl12xx/boot.c +++ b/drivers/net/wireless/wl12xx/boot.c @@ -431,6 +431,9 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) PSPOLL_DELIVERY_FAILURE_EVENT_ID | SOFT_GEMINI_SENSE_EVENT_ID; + if (wl->bss_type == BSS_TYPE_AP_BSS) + wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID; + ret = wl1271_event_unmask(wl); if (ret < 0) { wl1271_error("EVENT mask setting failed"); -- cgit v1.2.3 From ae113b57826b40f1962a6e2417efd757b638e6a9 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Sat, 16 Oct 2010 18:45:07 +0200 Subject: wl12xx: AP specific RX filter configuration Set filters according to the mode of operation. Signed-off-by: Arik Nemtsov Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/boot.c | 4 ++-- drivers/net/wireless/wl12xx/main.c | 7 +++---- drivers/net/wireless/wl12xx/rx.c | 11 +++++++++++ drivers/net/wireless/wl12xx/rx.h | 1 + drivers/net/wireless/wl12xx/wl12xx.h | 13 +++++++++++-- 5 files changed, 28 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless/wl12xx/boot.c') diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c index b504367f281f..2b1019f67d27 100644 --- a/drivers/net/wireless/wl12xx/boot.c +++ b/drivers/net/wireless/wl12xx/boot.c @@ -28,6 +28,7 @@ #include "boot.h" #include "io.h" #include "event.h" +#include "rx.h" static struct wl1271_partition_set part_table[PART_TABLE_LEN] = { [PART_DOWN] = { @@ -598,8 +599,7 @@ int wl1271_boot(struct wl1271 *wl) 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_set_default_filters(wl); wl1271_event_mbox_config(wl); diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 67f6db4354f0..d1075a5ac406 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1227,8 +1227,7 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw, 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; + wl1271_set_default_filters(wl); /* combine requested filters with current filter config */ filters = wl->filters | filters; @@ -2758,8 +2757,8 @@ struct ieee80211_hw *wl1271_alloc_hw(void) 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->rx_config = WL1271_DEFAULT_STA_RX_CONFIG; + wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER; wl->psm_entry_retry = 0; wl->power_level = WL1271_DEFAULT_POWER_LEVEL; wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC; diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c index c6402529eac8..b0c6ddc2a945 100644 --- a/drivers/net/wireless/wl12xx/rx.c +++ b/drivers/net/wireless/wl12xx/rx.c @@ -200,3 +200,14 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status) } wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter); } + +void wl1271_set_default_filters(struct wl1271 *wl) +{ + if (wl->bss_type == BSS_TYPE_AP_BSS) { + wl->rx_config = WL1271_DEFAULT_AP_RX_CONFIG; + wl->rx_filter = WL1271_DEFAULT_AP_RX_FILTER; + } else { + wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG; + wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER; + } +} diff --git a/drivers/net/wireless/wl12xx/rx.h b/drivers/net/wireless/wl12xx/rx.h index 3abb26fe0364..f695553f31e0 100644 --- a/drivers/net/wireless/wl12xx/rx.h +++ b/drivers/net/wireless/wl12xx/rx.h @@ -117,5 +117,6 @@ struct wl1271_rx_descriptor { void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status); u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band); +void wl1271_set_default_filters(struct wl1271 *wl); #endif diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 340153f609c7..4bbdb89f1bcb 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -103,15 +103,24 @@ extern u32 wl12xx_debug_level; true); \ } while (0) -#define WL1271_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \ +#define WL1271_DEFAULT_STA_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 | \ +#define WL1271_DEFAULT_STA_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_DEFAULT_AP_RX_CONFIG 0 + +#define WL1271_DEFAULT_AP_RX_FILTER (CFG_RX_RCTS_ACK | CFG_RX_PREQ_EN | \ + CFG_RX_MGMT_EN | CFG_RX_DATA_EN | \ + CFG_RX_CTL_EN | CFG_RX_AUTH_EN | \ + CFG_RX_ASSOC_EN) + + + #define WL1271_FW_NAME "wl1271-fw.bin" #define WL1271_NVS_NAME "wl1271-nvs.bin" -- cgit v1.2.3 From 038d925bcfed8df4d16bab57c2b5a4de6ede7847 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Sat, 16 Oct 2010 21:53:24 +0200 Subject: wl12xx: Enable AP-mode Indicate support for the NL80211_IFTYPE_AP interface mode to enable AP mode operation. Disable 11a when operating in AP-mode (unsupported for now). Signed-off-by: Arik Nemtsov Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/boot.c | 4 +++- drivers/net/wireless/wl12xx/main.c | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/wl12xx/boot.c') diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c index 2b1019f67d27..d7e036f42958 100644 --- a/drivers/net/wireless/wl12xx/boot.c +++ b/drivers/net/wireless/wl12xx/boot.c @@ -232,7 +232,9 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) */ 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) + /* for now 11a is unsupported in AP mode */ + if (wl->bss_type != BSS_TYPE_AP_BSS && + wl->nvs->general_params.dual_mode_select) wl->enable_11a = true; } diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 78d615525980..8a3549162999 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1073,6 +1073,9 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, wl->bss_type = BSS_TYPE_IBSS; wl->set_bss_type = BSS_TYPE_STA_BSS; break; + case NL80211_IFTYPE_AP: + wl->bss_type = BSS_TYPE_AP_BSS; + break; default: ret = -EOPNOTSUPP; goto out; @@ -3136,7 +3139,7 @@ int wl1271_init_ieee80211(struct wl1271 *wl) wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC); + BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP); wl->hw->wiphy->max_scan_ssids = 1; /* * Maximum length of elements in scanning probe request templates -- cgit v1.2.3 From 4b7fac77b4c1badac84df3dcbdf07199d94cb1c3 Mon Sep 17 00:00:00 2001 From: "Levi, Shahar" Date: Sun, 23 Jan 2011 07:27:22 +0100 Subject: wl12xx: BA initiator support Add 80211n BA initiator session support wl1271 driver. Include BA supported FW version auto detection mechanism. BA initiator session management included in FW independently. Signed-off-by: Shahar Levi Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/acx.c | 51 ++++++++++++++++++++++++++++++++++++ drivers/net/wireless/wl12xx/acx.h | 41 +++++++++++++++++++++++++++-- drivers/net/wireless/wl12xx/boot.c | 24 ++++++++++++++--- drivers/net/wireless/wl12xx/conf.h | 6 +++++ drivers/net/wireless/wl12xx/init.c | 42 +++++++++++++++++++++++++++++ drivers/net/wireless/wl12xx/main.c | 12 ++++++--- drivers/net/wireless/wl12xx/wl12xx.h | 17 +++++++++++- 7 files changed, 183 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless/wl12xx/boot.c') diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index 679bb37f0ca4..0b9cacc74903 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c @@ -1342,6 +1342,57 @@ out: return ret; } +/* Configure BA session initiator/receiver parameters setting in the FW. */ +int wl1271_acx_set_ba_session(struct wl1271 *wl, + enum ieee80211_back_parties direction, + u8 tid_index, u8 policy) +{ + struct wl1271_acx_ba_session_policy *acx; + int ret; + + wl1271_debug(DEBUG_ACX, "acx ba session setting"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + /* ANY role */ + acx->role_id = 0xff; + acx->tid = tid_index; + acx->enable = policy; + acx->ba_direction = direction; + + switch (direction) { + case WLAN_BACK_INITIATOR: + acx->win_size = wl->conf.ht.tx_ba_win_size; + acx->inactivity_timeout = wl->conf.ht.inactivity_timeout; + break; + case WLAN_BACK_RECIPIENT: + acx->win_size = RX_BA_WIN_SIZE; + acx->inactivity_timeout = 0; + break; + default: + wl1271_error("Incorrect acx command id=%x\n", direction); + ret = -EINVAL; + goto out; + } + + ret = wl1271_cmd_configure(wl, + ACX_BA_SESSION_POLICY_CFG, + acx, + sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx ba session 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; diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h index 62a269d84ebe..f643e60a566b 100644 --- a/drivers/net/wireless/wl12xx/acx.h +++ b/drivers/net/wireless/wl12xx/acx.h @@ -1061,6 +1061,40 @@ struct wl1271_acx_ht_information { u8 padding[3]; } __packed; +#define RX_BA_WIN_SIZE 8 + +struct wl1271_acx_ba_session_policy { + struct acx_header header; + /* + * Specifies role Id, Range 0-7, 0xFF means ANY role. + * Future use. For now this field is irrelevant + */ + u8 role_id; + /* + * Specifies Link Id, Range 0-31, 0xFF means ANY Link Id. + * Not applicable if Role Id is set to ANY. + */ + u8 link_id; + + u8 tid; + + u8 enable; + + /* Windows size in number of packets */ + u16 win_size; + + /* + * As initiator inactivity timeout in time units(TU) of 1024us. + * As receiver reserved + */ + u16 inactivity_timeout; + + /* Initiator = 1/Receiver = 0 */ + u8 ba_direction; + + u8 padding[3]; +} __packed; + struct wl1271_acx_fw_tsf_information { struct acx_header header; @@ -1134,8 +1168,8 @@ enum { 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_BA_SESSION_POLICY_CFG = 0x0055, + ACX_BA_SESSION_RX_SETUP = 0x0056, ACX_PEER_HT_CAP = 0x0057, ACX_HT_BSS_OPERATION = 0x0058, ACX_COEX_ACTIVITY = 0x0059, @@ -1209,6 +1243,9 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, bool allow_ht_operation); int wl1271_acx_set_ht_information(struct wl1271 *wl, u16 ht_operation_mode); +int wl1271_acx_set_ba_session(struct wl1271 *wl, + enum ieee80211_back_parties direction, + u8 tid_index, u8 policy); int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime); int wl1271_acx_max_tx_retry(struct wl1271 *wl); diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c index d7e036f42958..1ffbad67d2d8 100644 --- a/drivers/net/wireless/wl12xx/boot.c +++ b/drivers/net/wireless/wl12xx/boot.c @@ -101,6 +101,22 @@ static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag) wl1271_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); } +static void wl1271_parse_fw_ver(struct wl1271 *wl) +{ + int ret; + + ret = sscanf(wl->chip.fw_ver_str + 4, "%u.%u.%u.%u.%u", + &wl->chip.fw_ver[0], &wl->chip.fw_ver[1], + &wl->chip.fw_ver[2], &wl->chip.fw_ver[3], + &wl->chip.fw_ver[4]); + + if (ret != 5) { + wl1271_warning("fw version incorrect value"); + memset(wl->chip.fw_ver, 0, sizeof(wl->chip.fw_ver)); + return; + } +} + static void wl1271_boot_fw_version(struct wl1271 *wl) { struct wl1271_static_data static_data; @@ -108,11 +124,13 @@ static void wl1271_boot_fw_version(struct wl1271 *wl) 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)); + strncpy(wl->chip.fw_ver_str, static_data.fw_version, + sizeof(wl->chip.fw_ver_str)); /* make sure the string is NULL-terminated */ - wl->chip.fw_ver[sizeof(wl->chip.fw_ver) - 1] = '\0'; + wl->chip.fw_ver_str[sizeof(wl->chip.fw_ver_str) - 1] = '\0'; + + wl1271_parse_fw_ver(wl); } static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h index f5c048c9bea4..135d837cefb1 100644 --- a/drivers/net/wireless/wl12xx/conf.h +++ b/drivers/net/wireless/wl12xx/conf.h @@ -1138,6 +1138,11 @@ struct conf_rf_settings { u8 tx_per_channel_power_compensation_5[CONF_TX_PWR_COMPENSATION_LEN_5]; }; +struct conf_ht_setting { + u16 tx_ba_win_size; + u16 inactivity_timeout; +}; + struct conf_drv_settings { struct conf_sg_settings sg; struct conf_rx_settings rx; @@ -1148,6 +1153,7 @@ struct conf_drv_settings { struct conf_roam_trigger_settings roam_trigger; struct conf_scan_settings scan; struct conf_rf_settings rf; + struct conf_ht_setting ht; }; #endif diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c index bdb61232f80c..2348eadc0de1 100644 --- a/drivers/net/wireless/wl12xx/init.c +++ b/drivers/net/wireless/wl12xx/init.c @@ -455,6 +455,43 @@ static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl) return 0; } +static void wl1271_check_ba_support(struct wl1271 *wl) +{ + /* validate FW cose ver x.x.x.50-60.x */ + if ((wl->chip.fw_ver[3] >= WL12XX_BA_SUPPORT_FW_COST_VER2_START) && + (wl->chip.fw_ver[3] < WL12XX_BA_SUPPORT_FW_COST_VER2_END)) { + wl->ba_support = true; + return; + } + + wl->ba_support = false; +} + +static int wl1271_set_ba_policies(struct wl1271 *wl) +{ + u8 tid_index; + u8 ret = 0; + + /* Reset the BA RX indicators */ + wl->ba_allowed = true; + wl->ba_rx_bitmap = 0; + + /* validate that FW support BA */ + wl1271_check_ba_support(wl); + + if (wl->ba_support) + /* 802.11n initiator BA session setting */ + for (tid_index = 0; tid_index < CONF_TX_MAX_TID_COUNT; + ++tid_index) { + ret = wl1271_acx_set_ba_session(wl, WLAN_BACK_INITIATOR, + tid_index, true); + if (ret < 0) + break; + } + + return ret; +} + int wl1271_hw_init(struct wl1271 *wl) { struct conf_tx_ac_category *conf_ac; @@ -568,6 +605,11 @@ int wl1271_hw_init(struct wl1271 *wl) if (ret < 0) goto out_free_memmap; + /* Configure initiator BA sessions policies */ + ret = wl1271_set_ba_policies(wl); + if (ret < 0) + goto out_free_memmap; + return 0; out_free_memmap: diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 48194629c00b..01ca666b6c2d 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -274,7 +274,7 @@ static struct conf_drv_settings default_conf = { .avg_weight_rssi_beacon = 20, .avg_weight_rssi_data = 10, .avg_weight_snr_beacon = 20, - .avg_weight_snr_data = 10 + .avg_weight_snr_data = 10, }, .scan = { .min_dwell_time_active = 7500, @@ -293,6 +293,10 @@ static struct conf_drv_settings default_conf = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, }, + .ht = { + .tx_ba_win_size = 64, + .inactivity_timeout = 10000, + }, }; static void __wl1271_op_remove_interface(struct wl1271 *wl); @@ -890,7 +894,7 @@ int wl1271_plt_start(struct wl1271 *wl) wl->state = WL1271_STATE_PLT; wl1271_notice("firmware booted in PLT mode (%s)", - wl->chip.fw_ver); + wl->chip.fw_ver_str); goto out; irq_disable: @@ -1138,11 +1142,11 @@ power_off: wl->vif = vif; wl->state = WL1271_STATE_ON; - wl1271_info("firmware booted (%s)", wl->chip.fw_ver); + wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str); /* update hw/fw version info in wiphy struct */ wiphy->hw_version = wl->chip.id; - strncpy(wiphy->fw_version, wl->chip.fw_ver, + strncpy(wiphy->fw_version, wl->chip.fw_ver_str, sizeof(wiphy->fw_version)); /* diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index ca727e0c4ce9..e0bac79cd516 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -38,6 +38,13 @@ #define DRIVER_NAME "wl1271" #define DRIVER_PREFIX DRIVER_NAME ": " +/* + * FW versions support BA 11n + * versions marks x.x.x.50-60.x + */ +#define WL12XX_BA_SUPPORT_FW_COST_VER2_START 50 +#define WL12XX_BA_SUPPORT_FW_COST_VER2_END 60 + enum { DEBUG_NONE = 0, DEBUG_IRQ = BIT(0), @@ -182,10 +189,13 @@ struct wl1271_partition_set { struct wl1271; +#define WL12XX_NUM_FW_VER 5 + /* FIXME: I'm not sure about this structure name */ struct wl1271_chip { u32 id; - char fw_ver[21]; + char fw_ver_str[ETHTOOL_BUSINFO_LEN]; + unsigned int fw_ver[WL12XX_NUM_FW_VER]; }; struct wl1271_stats { @@ -460,6 +470,11 @@ struct wl1271 { /* bands supported by this instance of wl12xx */ struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS]; + + /* RX BA constraint value */ + bool ba_support; + u8 ba_allowed; + u8 ba_rx_bitmap; }; struct wl1271_station { -- cgit v1.2.3 From 606ea9fa0b2c01ffafb6beae92ea8e2b1473520b Mon Sep 17 00:00:00 2001 From: Ido Yariv Date: Tue, 1 Mar 2011 15:14:39 +0200 Subject: wl12xx: Do end-of-transactions transfers only if needed On newer hardware revisions, there is no need to write the host's counter at the end of a RX transaction. The same applies to writing the number of packets at the end of a TX transaction. It is generally a good idea to avoid unnecessary SDIO/SPI transfers. Throughput and CPU usage are improved when avoiding these. Send the host's RX counter and the TX packet count only if needed, based on the hardware revision. [Changed WL12XX_QUIRK_END_OF_TRANSACTION to use BIT(0) -- Luca] Signed-off-by: Ido Yariv Signed-off-by: Ohad Ben-Cohen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/boot.c | 3 +++ drivers/net/wireless/wl12xx/boot.h | 5 +++++ drivers/net/wireless/wl12xx/main.c | 1 + drivers/net/wireless/wl12xx/rx.c | 8 +++++++- drivers/net/wireless/wl12xx/tx.c | 10 ++++++++-- drivers/net/wireless/wl12xx/wl12xx.h | 8 ++++++++ 6 files changed, 32 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/wl12xx/boot.c') diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c index 1ffbad67d2d8..6934dffd5174 100644 --- a/drivers/net/wireless/wl12xx/boot.c +++ b/drivers/net/wireless/wl12xx/boot.c @@ -488,6 +488,9 @@ static void wl1271_boot_hw_version(struct wl1271 *wl) fuse = (fuse & PG_VER_MASK) >> PG_VER_OFFSET; wl->hw_pg_ver = (s8)fuse; + + if (((wl->hw_pg_ver & PG_MAJOR_VER_MASK) >> PG_MAJOR_VER_OFFSET) < 3) + wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION; } /* uploads NVS and firmware */ diff --git a/drivers/net/wireless/wl12xx/boot.h b/drivers/net/wireless/wl12xx/boot.h index d67dcffa31eb..17229b86fc71 100644 --- a/drivers/net/wireless/wl12xx/boot.h +++ b/drivers/net/wireless/wl12xx/boot.h @@ -59,6 +59,11 @@ struct wl1271_static_data { #define PG_VER_MASK 0x3c #define PG_VER_OFFSET 2 +#define PG_MAJOR_VER_MASK 0x3 +#define PG_MAJOR_VER_OFFSET 0x0 +#define PG_MINOR_VER_MASK 0xc +#define PG_MINOR_VER_OFFSET 0x2 + #define CMD_MBOX_ADDRESS 0x407B4 #define POLARITY_LOW BIT(1) diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 65e8a0cc92d0..ba34ac3a440d 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -3404,6 +3404,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void) wl->last_tx_hlid = 0; wl->ap_ps_map = 0; wl->ap_fw_ps_map = 0; + wl->quirks = 0; memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map)); for (i = 0; i < ACX_TX_DESCRIPTORS; i++) diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c index 3d13d7a83ea1..4e7a3b311321 100644 --- a/drivers/net/wireless/wl12xx/rx.c +++ b/drivers/net/wireless/wl12xx/rx.c @@ -198,7 +198,13 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status) pkt_offset += pkt_length; } } - wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter); + + /* + * Write the driver's packet counter to the FW. This is only required + * for older hardware revisions + */ + if (wl->quirks & WL12XX_QUIRK_END_OF_TRANSACTION) + wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter); } void wl1271_set_default_filters(struct wl1271 *wl) diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index 37d354ddd58e..455954edf83e 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -506,8 +506,14 @@ out_ack: sent_packets = true; } if (sent_packets) { - /* interrupt the firmware with the new packets */ - wl1271_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count); + /* + * Interrupt the firmware with the new packets. This is only + * required for older hardware revisions + */ + if (wl->quirks & WL12XX_QUIRK_END_OF_TRANSACTION) + wl1271_write32(wl, WL1271_HOST_WR_ACCESS, + wl->tx_packets_count); + wl1271_handle_tx_low_watermark(wl); } diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 7132bc7dd2cf..ea1eee7895cf 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -535,6 +535,9 @@ struct wl1271 { /* AP-mode - a bitmap of links currently in PS mode in mac80211 */ unsigned long ap_ps_map; + + /* Quirks of specific hardware revisions */ + unsigned int quirks; }; struct wl1271_station { @@ -562,4 +565,9 @@ int wl1271_plt_stop(struct wl1271 *wl); #define HW_BG_RATES_MASK 0xffff #define HW_HT_RATES_OFFSET 16 +/* Quirks */ + +/* Each RX/TX transaction requires an end-of-transaction transfer */ +#define WL12XX_QUIRK_END_OF_TRANSACTION BIT(0) + #endif -- cgit v1.2.3